Line data Source code
1 : /* 2 : * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved. 3 : * Copyright Contributors to the OpenSDN project 4 : */ 5 : 6 : #include <boost/uuid/uuid_io.hpp> 7 : 8 : #include <cmn/agent_cmn.h> 9 : #include <oper/route_common.h> 10 : #include <oper/agent_route_walker.h> 11 : #include <oper/vrf.h> 12 : #include <oper/mirror_table.h> 13 : 14 : #include <controller/controller_export.h> 15 : #include <controller/controller_vrf_export.h> 16 : #include <controller/controller_route_walker.h> 17 : #include <controller/controller_peer.h> 18 : #include <controller/controller_init.h> 19 : #include <controller/controller_types.h> 20 : 21 32 : VrfExport::State::State() : DBState(), exported_(false), 22 128 : force_chg_(false), rt_export_(), last_sequence_number_(0) { 23 16 : }; 24 : 25 32 : VrfExport::State::~State() { 26 32 : }; 27 : 28 716 : bool VrfExport::State::IsExportable(uint64_t sequence_number) { 29 : // Sequence number passed in argument is of channel to which this state 30 : // belongs. Once channel sends the vrf subscription after flap/fresh 31 : // connection, state's sequence number will be updated to that of channel. 32 : // After this all routes in this VRF become eligible for export. 33 : // This is needed as control-node mandates that VRF is subscribed before any 34 : // route is seen in same else it will again flap the 35 : // connection(intentionally). 36 : // Note: In case of flaps etc CN removes VRF subscription. 37 : // This sequence number macthing helps in making sure that VRF sub is 38 : // sent before any route is published. 39 716 : return (last_sequence_number_ != sequence_number); 40 : } 41 : 42 1222 : void VrfExport::Notify(const Agent *agent, AgentXmppChannel *bgp_xmpp_peer, 43 : DBTablePartBase *partition, DBEntryBase *e) { 44 : 45 1222 : BgpPeer *bgp_peer = static_cast<BgpPeer *>(bgp_xmpp_peer->bgp_peer_id()); 46 1222 : VrfEntry *vrf = static_cast<VrfEntry *>(e); 47 : //PBB VRF is implictly created, agent is not supposed to send RI 48 : //subscription message since control-node will not be aware of this RI 49 : //We still want to set a state and subscribe for bridge table for 50 : //building ingress replication tree 51 1222 : bool send_subscribe = vrf->ShouldExportRoute(); 52 : 53 1222 : uint32_t instance_id = vrf->rd(); 54 : //Instance ID being zero is possible because of VN unavailability and VRF 55 : //ending up with NULL VRF. Reason being config sequence. 56 : //So seeing 0 instance_id delete the state so that resubscribe can be done 57 : //with new id and then re-export all route. 58 : //Note: Assumption is that instance id will never change from non zero to 59 : //some other non zero value. 60 : //Also Instance ID check is for TSN and TA only. 61 1222 : bool deleted = (vrf->IsDeleted()) || (instance_id == VrfEntry::kInvalidIndex); 62 : 63 1222 : if (deleted) { 64 1050 : bgp_peer->DeleteVrfState(partition, e); 65 1050 : if (!AgentXmppChannel::IsXmppChannelActive(agent, bgp_xmpp_peer)) { 66 0 : return; 67 : } 68 1050 : if (bgp_peer) { 69 1050 : CONTROLLER_TRACE(Trace, bgp_peer->GetName(), vrf->GetName(), 70 : "VRF deleted, remove state"); 71 1050 : bgp_peer->DeleteVrfState(partition, e); 72 : } 73 1050 : return; 74 : } 75 : 76 172 : if (!AgentXmppChannel::IsBgpPeerActive(agent, bgp_xmpp_peer)) 77 142 : return; 78 : 79 30 : DBTableBase::ListenerId id = bgp_peer->GetVrfExportListenerId(); 80 30 : State *state = static_cast<State *>(vrf->GetState(partition->parent(), id)); 81 : uint8_t table_type; 82 30 : if (state == NULL) { 83 16 : state = new State(); 84 16 : state->exported_ = false; 85 16 : state->mcast_exported_ = false; 86 16 : state->force_chg_ = true; 87 16 : vrf->SetState(partition->parent(), id, state); 88 : 89 : // Dont export routes belonging to Fabric VRF table 90 16 : for (table_type = (Agent::INVALID + 1); 91 112 : table_type < Agent::ROUTE_TABLE_MAX; table_type++) { 92 192 : state->rt_export_[table_type] = 93 96 : RouteExport::Init( 94 : static_cast<AgentRouteTable *> 95 : (vrf->GetRouteTable(table_type)), 96 : bgp_xmpp_peer); 97 : } 98 : } 99 : 100 30 : if (state->last_sequence_number_ == bgp_xmpp_peer->sequence_number()) { 101 14 : state->force_chg_ = false; 102 : } else { 103 16 : state->last_sequence_number_ = bgp_xmpp_peer->sequence_number(); 104 : } 105 : 106 30 : if (send_subscribe == false) { 107 0 : state->force_chg_ = false; 108 : } 109 : 110 30 : if (send_subscribe && ((state->exported_ == false) || 111 14 : (state->force_chg_ == true))) { 112 16 : if (AgentXmppChannel::ControllerSendSubscribe(bgp_xmpp_peer, vrf, 113 : true)) { 114 16 : CONTROLLER_TRACE(Trace, bgp_peer->GetName(), vrf->GetName(), 115 : "Subscribe"); 116 : 117 16 : state->exported_ = true; 118 16 : if (state->force_chg_ == true) { 119 16 : bgp_peer->route_walker()->StartRouteWalk(vrf, true, 120 : ControllerRouteWalker::NOTIFYALL); 121 16 : state->force_chg_ = false; 122 : 123 16 : if (Agent::GetInstance()->mulitcast_builder() == bgp_xmpp_peer) { 124 16 : state->mcast_exported_ = true; 125 : } else { 126 0 : state->mcast_exported_ = false; 127 : } 128 : } 129 16 : return; 130 : } 131 : } else { 132 14 : if (send_subscribe && 133 28 : (Agent::GetInstance()->mulitcast_builder() == bgp_xmpp_peer) && 134 14 : !state->mcast_exported_) { 135 : // When Agent switches to a new multicast builder, we have to 136 : // send multicast subscribe to the new multicast builder. Otherwise, 137 : // Agent can get stuck with old multicast tree affecting BUM 138 : // traffic. 139 0 : bgp_peer->route_walker()->StartRouteWalk(vrf, true, 140 : ControllerRouteWalker::NOTIFYMULTICAST); 141 0 : state->mcast_exported_ = true; 142 28 : } else if (send_subscribe && 143 14 : Agent::GetInstance()->mulitcast_builder() != bgp_xmpp_peer) { 144 : // If it is not the multicast builder, mark the flag false so that 145 : // if it becomes multicast builder we notify mutlcast routes 146 0 : state->mcast_exported_ = false; 147 : } else { 148 14 : CONTROLLER_TRACE(Trace, bgp_peer->GetName(), vrf->GetName(), 149 : "Already subscribed"); 150 : } 151 : } 152 : }