Line data Source code
1 : /* 2 : * Copyright (c) 2017 Juniper Networks, Inc. All rights reserved. 3 : */ 4 : 5 : #include <boost/uuid/uuid_io.hpp> 6 : #include <cmn/agent_cmn.h> 7 : 8 : #include <base/logging.h> 9 : #include <init/agent_param.h> 10 : #include <oper/operdb_init.h> 11 : #include <oper/route_common.h> 12 : #include <oper/vrf.h> 13 : #include <oper/tsn_elector.h> 14 : #include <oper/bridge_route.h> 15 : #include <oper/inet_unicast_route.h> 16 : #include <oper/agent_route_walker.h> 17 : #include <oper/nexthop.h> 18 : #include <oper/multicast.h> 19 : 20 : using namespace std; 21 : 22 0 : TsnElectorState::TsnElectorState(AgentRouteTable *inet4_table, 23 0 : TsnElector *elector) : 24 0 : inet4_table_(inet4_table) { 25 0 : inet4_id_ = inet4_table->Register(boost::bind(&TsnElector::RouteNotify, 26 : elector, _1, _2)); 27 0 : } 28 : 29 0 : TsnElectorState::~TsnElectorState() { 30 0 : inet4_table_->Unregister(inet4_id_); 31 0 : } 32 : 33 0 : TsnElectorWalker::TsnElectorWalker(const std::string &name, Agent *agent) : 34 0 : AgentRouteWalker(name, agent) { 35 0 : } 36 : 37 0 : TsnElectorWalker::~TsnElectorWalker() { 38 0 : } 39 : 40 0 : bool TsnElectorWalker::RouteWalkNotify(DBTablePartBase *partition, 41 : DBEntryBase *e) { 42 : BridgeRouteEntry *bridge_entry = 43 0 : dynamic_cast<BridgeRouteEntry*>(e); 44 0 : if (!bridge_entry || !bridge_entry->is_multicast()) 45 0 : return true; 46 : 47 0 : AgentPath *evpn_path = NULL; 48 0 : for (Route::PathList::iterator it = bridge_entry->GetPathList().begin(); 49 0 : it != bridge_entry->GetPathList().end(); it++) { 50 0 : AgentPath *path = static_cast<AgentPath *>(it.operator->()); 51 0 : if (path->peer()->GetType() != Peer::BGP_PEER) 52 0 : continue; 53 0 : const CompositeNH *cnh = dynamic_cast<const CompositeNH *>(path->nexthop()); 54 0 : if (!cnh) 55 0 : continue; 56 : 57 0 : if (cnh->composite_nh_type() != Composite::EVPN) 58 0 : continue; 59 : 60 0 : if (!evpn_path) 61 0 : evpn_path = path; 62 0 : path->set_inactive(!master_); 63 : } 64 : 65 0 : if (evpn_path && bridge_entry->ReComputePathAdd(evpn_path)) 66 0 : partition->Notify(bridge_entry); 67 0 : return true; 68 : } 69 : 70 0 : void TsnElectorWalker::LeaveTsnMastership() { 71 0 : master_ = false; 72 0 : StartVrfWalk(); 73 0 : } 74 : 75 0 : void TsnElectorWalker::AcquireTsnMastership() { 76 0 : master_ = true; 77 0 : StartVrfWalk(); 78 0 : } 79 : 80 3 : TsnElector::TsnElector(Agent *agent) : agent_(agent), 81 3 : vrf_listener_id_(), active_tsn_servers_() { 82 3 : if (IsTsnNoForwardingEnabled()) { 83 0 : walker_.reset(new TsnElectorWalker("TsnElectorWalker", agent)); 84 : } 85 3 : } 86 : 87 6 : TsnElector::~TsnElector() { 88 6 : } 89 : 90 9 : bool TsnElector::IsTsnNoForwardingEnabled() const { 91 9 : return (agent_->params()->agent_mode() == 92 9 : AgentParam::TSN_NO_FORWARDING_AGENT); 93 : } 94 : 95 3 : void TsnElector::Register() { 96 3 : if (!IsTsnNoForwardingEnabled()) 97 3 : return; 98 0 : vrf_listener_id_ = agent_->vrf_table()->Register( 99 : boost::bind(&TsnElector::Notify, this, _1, _2)); 100 0 : agent_->oper_db()->agent_route_walk_manager()-> 101 0 : RegisterWalker(static_cast<AgentRouteWalker *>(walker_.get())); 102 : } 103 : 104 0 : void TsnElector::Notify(DBTablePartBase *partition, DBEntryBase *e) { 105 0 : VrfEntry *vrf = dynamic_cast<VrfEntry *>(e); 106 0 : TsnElectorState *state = dynamic_cast<TsnElectorState *>(vrf-> 107 0 : GetState(partition->parent(), vrf_listener_id_)); 108 0 : if (vrf->GetName().compare(agent_->fabric_policy_vrf_name()) != 0) 109 0 : return; 110 : 111 0 : if (vrf->IsDeleted()) { 112 0 : if (state) { 113 0 : vrf->ClearState(partition->parent(), vrf_listener_id_); 114 0 : delete state; 115 : } 116 0 : return; 117 : } 118 : 119 0 : if (!state) { 120 0 : state = new TsnElectorState(vrf->GetInet4UnicastRouteTable(), this); 121 0 : vrf->SetState(partition->parent(), vrf_listener_id_, state); 122 : } 123 0 : return; 124 : } 125 : 126 0 : void TsnElector::RouteNotify(DBTablePartBase *partition, DBEntryBase *e) { 127 0 : const InetUnicastRouteEntry *rt = 128 : static_cast<const InetUnicastRouteEntry*>(e); 129 : 130 0 : if (!agent_->params()->IsConfiguredTsnHostRoute(rt->prefix_address().to_string())) 131 0 : return; 132 : 133 0 : const string rt_addr_str = rt->GetAddressString(); 134 : std::vector<std::string>::iterator it = 135 0 : std::find(active_tsn_servers_.begin(), active_tsn_servers_.end(), 136 : rt_addr_str); 137 0 : std::string master = ""; 138 0 : if (!active_tsn_servers_.empty()) { 139 0 : master = active_tsn_servers_.front(); 140 : } 141 0 : if (rt->IsDeleted()) { 142 0 : if (it == active_tsn_servers_.end()) 143 0 : return; 144 0 : active_tsn_servers_.erase(it); 145 : } else { 146 0 : if (it != active_tsn_servers_.end()) 147 0 : return; 148 0 : active_tsn_servers_.push_back(rt_addr_str); 149 : } 150 0 : std::sort(active_tsn_servers_.begin(), active_tsn_servers_.end()); 151 0 : std::string new_master = ""; 152 0 : if (!active_tsn_servers_.empty()) { 153 0 : new_master = active_tsn_servers_.front(); 154 : } 155 0 : if (master == new_master) 156 0 : return; 157 : 158 0 : std::string vhost_addr = agent_->params()->vhost_addr().to_string(); 159 0 : if (master == vhost_addr) { 160 0 : walker()->LeaveTsnMastership(); 161 : } 162 0 : if (new_master == vhost_addr) { 163 0 : walker()->AcquireTsnMastership(); 164 : } 165 0 : } 166 : 167 3 : void TsnElector::Shutdown() { 168 3 : if (!IsTsnNoForwardingEnabled()) 169 3 : return; 170 0 : agent_->vrf_table()->Unregister(vrf_listener_id_); 171 0 : agent_->oper_db()->agent_route_walk_manager()-> 172 0 : ReleaseWalker(walker_.get()); 173 0 : walker_.reset(NULL); 174 : } 175 : 176 0 : bool TsnElector::IsMaster() const { 177 0 : if (active_tsn_servers_.empty()) 178 0 : return false; 179 0 : return (active_tsn_servers_.front().compare( 180 0 : agent_->params()->vhost_addr().to_string()) == 0); 181 : } 182 : 183 0 : const TsnElector::ManagedPhysicalDevicesList &TsnElector::ManagedPhysicalDevices() 184 : const { 185 0 : return agent_->oper_db()->multicast()->physical_devices(); 186 : }