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