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