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