Line data Source code
1 : /* 2 : * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved. 3 : */ 4 : 5 : #include "bgp/ermvpn/ermvpn_table.h" 6 : 7 : #include "bgp/ipeer.h" 8 : #include "bgp/bgp_factory.h" 9 : #include "bgp/bgp_multicast.h" 10 : #include "bgp/bgp_mvpn.h" 11 : #include "bgp/bgp_server.h" 12 : #include "bgp/bgp_update.h" 13 : #include "bgp/inet/inet_table.h" 14 : #include "bgp/origin-vn/origin_vn.h" 15 : #include "bgp/routing-instance/routing_instance.h" 16 : 17 : using std::unique_ptr; 18 : using std::string; 19 : 20 255903 : size_t ErmVpnTable::HashFunction(const ErmVpnPrefix &prefix) const { 21 255903 : return boost::hash_value(prefix.group().to_ulong()); 22 : } 23 : 24 51134 : ErmVpnTable::ErmVpnTable(DB *db, const string &name) 25 51134 : : BgpTable(db, name), tree_manager_(NULL), mvpn_project_manager_(NULL) { 26 51134 : } 27 : 28 7212 : unique_ptr<DBEntry> ErmVpnTable::AllocEntry( 29 : const DBRequestKey *key) const { 30 7212 : const RequestKey *pfxkey = static_cast<const RequestKey *>(key); 31 7212 : return unique_ptr<DBEntry> (new ErmVpnRoute(pfxkey->prefix)); 32 : } 33 : 34 : 35 103 : unique_ptr<DBEntry> ErmVpnTable::AllocEntryStr( 36 : const string &key_str) const { 37 103 : ErmVpnPrefix prefix = ErmVpnPrefix::FromString(key_str); 38 206 : return unique_ptr<DBEntry> (new ErmVpnRoute(prefix)); 39 : } 40 : 41 255904 : size_t ErmVpnTable::Hash(const DBEntry *entry) const { 42 255904 : const ErmVpnRoute *rt_entry = static_cast<const ErmVpnRoute *>(entry); 43 255904 : const ErmVpnPrefix &ermvpnprefix = rt_entry->GetPrefix(); 44 255903 : size_t value = ErmVpnTable::HashFunction(ermvpnprefix); 45 255898 : return value % kPartitionCount; 46 : } 47 : 48 3353 : size_t ErmVpnTable::Hash(const Ip4Address &group) const { 49 3353 : return boost::hash_value(group.to_ulong()) % kPartitionCount; 50 : } 51 : 52 14745 : size_t ErmVpnTable::Hash(const DBRequestKey *key) const { 53 14745 : const RequestKey *rkey = static_cast<const RequestKey *>(key); 54 14745 : Ip4Prefix prefix(rkey->prefix.group(), 32); 55 14745 : size_t value = InetTable::HashFunction(prefix); 56 14744 : return value % kPartitionCount; 57 : } 58 : 59 13998 : BgpRoute *ErmVpnTable::TableFind(DBTablePartition *rtp, 60 : const DBRequestKey *prefix) { 61 13998 : const RequestKey *pfxkey = static_cast<const RequestKey *>(prefix); 62 13998 : ErmVpnRoute rt_key(pfxkey->prefix); 63 27996 : return static_cast<BgpRoute *>(rtp->Find(&rt_key)); 64 13998 : } 65 : 66 51134 : DBTableBase *ErmVpnTable::CreateTable(DB *db, const string &name) { 67 51134 : ErmVpnTable *table = new ErmVpnTable(db, name); 68 51134 : table->Init(); 69 51134 : return table; 70 : } 71 : 72 14393 : BgpRoute *ErmVpnTable::RouteReplicate(BgpServer *server, 73 : BgpTable *src_table, BgpRoute *src_rt, const BgpPath *src_path, 74 : ExtCommunityPtr community) { 75 14393 : assert(src_table->family() == Address::ERMVPN); 76 : 77 14393 : ErmVpnRoute *mroute = dynamic_cast<ErmVpnRoute *>(src_rt); 78 14393 : assert(mroute); 79 : 80 : // Native routes are not replicated to other VRFs or to the VPN table. 81 14393 : if (mroute->GetPrefix().type() == ErmVpnPrefix::NativeRoute) 82 3674 : return NULL; 83 : 84 10719 : if (!IsMaster()) { 85 : // Don't replicate to a VRF from other VRF tables. 86 3634 : ErmVpnTable *src_ermvpn_table = dynamic_cast<ErmVpnTable *>(src_table); 87 3634 : if (!src_ermvpn_table->IsMaster()) 88 173 : return NULL; 89 : 90 : // Don't replicate to VRF from the VPN table if OriginVn doesn't match. 91 6922 : if (!community->ContainsOriginVn(server->autonomous_system(), 92 3461 : routing_instance()->virtual_network_index())) 93 98 : return NULL; 94 : } 95 : 96 : // RD is always zero in the VRF. When replicating to the VPN table, we 97 : // pick up the RD from the SourceRD attribute. The SourceRD is always set 98 : // for Local and Global routes that the multicast code adds to a VRF. 99 10448 : ErmVpnPrefix mprefix(mroute->GetPrefix()); 100 10448 : if (IsMaster()) { 101 7085 : mprefix.set_route_distinguisher(src_path->GetAttr()->source_rd()); 102 : } else { 103 3363 : mprefix.set_route_distinguisher(RouteDistinguisher::kZeroRd); 104 : } 105 10448 : ErmVpnRoute rt_key(mprefix); 106 : 107 : // Find or create the route. 108 : DBTablePartition *rtp = 109 10448 : static_cast<DBTablePartition *>(GetTablePartition(&rt_key)); 110 10448 : BgpRoute *dest_route = static_cast<BgpRoute *>(rtp->Find(&rt_key)); 111 10448 : if (dest_route == NULL) { 112 3468 : dest_route = new ErmVpnRoute(mprefix); 113 3468 : rtp->Add(dest_route); 114 : } else { 115 6980 : dest_route->ClearDelete(); 116 : } 117 : 118 : BgpAttrPtr new_attr = 119 : server->attr_db()->ReplaceExtCommunityAndLocate(src_path->GetAttr(), 120 10448 : community); 121 : 122 : // Check whether peer already has a path. 123 10448 : BgpPath *dest_path = dest_route->FindSecondaryPath(src_rt, 124 : src_path->GetSource(), src_path->GetPeer(), 125 : src_path->GetPathId()); 126 10448 : if (dest_path != NULL) { 127 7661 : if (new_attr != dest_path->GetOriginalAttr() || 128 2723 : src_path->GetFlags() != dest_path->GetFlags()) { 129 2215 : bool success = dest_route->RemoveSecondaryPath(src_rt, 130 : src_path->GetSource(), src_path->GetPeer(), 131 : src_path->GetPathId()); 132 2215 : assert(success); 133 : } else { 134 2723 : return dest_route; 135 : } 136 : } 137 : 138 : // Create replicated path and insert it on the route. 139 : BgpSecondaryPath *replicated_path = 140 7725 : new BgpSecondaryPath(src_path->GetPeer(), src_path->GetPathId(), 141 7725 : src_path->GetSource(), new_attr, 142 7725 : src_path->GetFlags(), src_path->GetLabel()); 143 7725 : replicated_path->SetReplicateInfo(src_table, src_rt); 144 7725 : dest_route->InsertPath(replicated_path); 145 7725 : rtp->Notify(dest_route); 146 : 147 7725 : return dest_route; 148 10448 : } 149 : 150 18565 : bool ErmVpnTable::Export(RibOut *ribout, Route *route, 151 : const RibPeerSet &peerset, UpdateInfoSList &uinfo_slist) { 152 18565 : if (ribout->IsEncodingBgp()) { 153 7350 : BgpRoute *bgp_route = static_cast<BgpRoute *> (route); 154 7350 : UpdateInfo *uinfo = GetUpdateInfo(ribout, bgp_route, peerset); 155 7350 : if (!uinfo) 156 3843 : return false; 157 3507 : uinfo_slist->push_front(*uinfo); 158 3507 : return true; 159 : } 160 : 161 11215 : ErmVpnRoute *ermvpn_route = dynamic_cast<ErmVpnRoute *>(route); 162 19071 : if (ermvpn_route->GetPrefix().type() != ErmVpnPrefix::NativeRoute && 163 7856 : ermvpn_route->GetPrefix().type() != ErmVpnPrefix::GlobalTreeRoute) 164 4833 : return false; 165 : 166 6382 : if (!tree_manager_ || tree_manager_->deleter()->IsDeleted()) 167 0 : return false; 168 : 169 6382 : const IPeer *peer = ermvpn_route->BestPath()->GetPeer(); 170 6382 : if (!peer || !ribout->IsRegistered(const_cast<IPeer *>(peer))) 171 3023 : return false; 172 : 173 3359 : size_t peerbit = ribout->GetPeerIndex(const_cast<IPeer *>(peer)); 174 3359 : if (!peerset.test(peerbit)) 175 114 : return false; 176 : 177 3245 : UpdateInfo *uinfo = tree_manager_->GetUpdateInfo(ermvpn_route); 178 3245 : if (!uinfo) 179 648 : return false; 180 : 181 2597 : uinfo->target.set(peerbit); 182 2597 : uinfo_slist->push_front(*uinfo); 183 2597 : return true; 184 : } 185 : 186 51134 : void ErmVpnTable::CreateTreeManager() { 187 : // Don't create the McastTreeManager for the VPN table. 188 51134 : if (IsMaster() && !server()->mvpn_ipv4_enable()) 189 8227 : return; 190 42907 : assert(!tree_manager_); 191 42907 : tree_manager_ = BgpStaticObjectFactory::Create<McastTreeManager>(this); 192 42907 : tree_manager_->Initialize(); 193 : } 194 : 195 42907 : void ErmVpnTable::DestroyTreeManager() { 196 42907 : assert(tree_manager_); 197 42907 : tree_manager_->Terminate(); 198 42907 : delete tree_manager_; 199 42907 : tree_manager_ = NULL; 200 42907 : } 201 : 202 4 : McastTreeManager *ErmVpnTable::GetTreeManager() { 203 4 : return tree_manager_; 204 : } 205 : 206 210 : const McastTreeManager *ErmVpnTable::GetTreeManager() const { 207 210 : return tree_manager_; 208 : } 209 : 210 51133 : void ErmVpnTable::set_routing_instance(RoutingInstance *rtinstance) { 211 51133 : BgpTable::set_routing_instance(rtinstance); 212 51134 : CreateTreeManager(); 213 51134 : CreateMvpnProjectManager(); 214 51134 : } 215 : 216 51134 : void ErmVpnTable::CreateMvpnProjectManager() { 217 : // Don't create the MvpnProjectManager for the master table. 218 51134 : if (!server()->mvpn_ipv4_enable() || IsMaster()) 219 28571 : return; 220 22563 : assert(!mvpn_project_manager_); 221 22563 : mvpn_project_manager_ = BgpStaticObjectFactory::Create<MvpnProjectManager>(this); 222 22563 : mvpn_project_manager_->Initialize(); 223 : } 224 : 225 22563 : void ErmVpnTable::DestroyMvpnProjectManager() { 226 22563 : assert(mvpn_project_manager_); 227 22563 : mvpn_project_manager_->Terminate(); 228 22563 : delete mvpn_project_manager_; 229 22563 : mvpn_project_manager_ = NULL; 230 22563 : } 231 : 232 764115 : bool ErmVpnTable::IsMaster() const { 233 764115 : return routing_instance()->IsMasterRoutingInstance(); 234 : } 235 : 236 : // Find or create the route. 237 31498 : ErmVpnRoute *ErmVpnTable::FindRoute(const ErmVpnPrefix &prefix) { 238 31498 : ErmVpnRoute rt_key(prefix); 239 : DBTablePartition *rtp = static_cast<DBTablePartition *>( 240 31498 : GetTablePartition(&rt_key)); 241 62996 : return static_cast<ErmVpnRoute *>(rtp->Find(&rt_key)); 242 31498 : } 243 : 244 0 : const ErmVpnRoute *ErmVpnTable::FindRoute(const ErmVpnPrefix &prefix) const { 245 : return const_cast<ErmVpnRoute *>( 246 0 : static_cast<const ErmVpnTable *>(this)->FindRoute(prefix)); 247 : } 248 : 249 1300 : void ErmVpnTable::GetMvpnSourceAddress(ErmVpnRoute *ermvpn_rt, 250 : Ip4Address *address) const { 251 1300 : if (mvpn_project_manager_) 252 381 : mvpn_project_manager_->GetMvpnSourceAddress(ermvpn_rt, address); 253 1300 : } 254 : 255 159 : static void RegisterFactory() { 256 159 : DB::RegisterFactory("ermvpn.0", &ErmVpnTable::CreateTable); 257 159 : } 258 : 259 : MODULE_INITIALIZER(RegisterFactory);