Line data Source code
1 : /* 2 : * Copyright (c) 2014 Juniper Networks, Inc. All rights reserved. 3 : * Copyright Contributors to the OpenSDN project 4 : */ 5 : 6 : #include "bgp/inet6vpn/inet6vpn_table.h" 7 : 8 : #include "bgp/ipeer.h" 9 : #include "bgp/bgp_server.h" 10 : #include "bgp/bgp_peer.h" 11 : #include "bgp/bgp_update.h" 12 : #include "bgp/inet6/inet6_table.h" 13 : #include "bgp/routing-instance/routing_instance.h" 14 : #include "net/rd.h" 15 : 16 8228 : Inet6VpnTable::Inet6VpnTable(DB *db, const std::string &name) 17 8228 : : BgpTable(db, name) { 18 8228 : } 19 : 20 : std::unique_ptr<DBEntry> 21 100589 : Inet6VpnTable::AllocEntry(const DBRequestKey *key) const { 22 100589 : const RequestKey *pfxkey = static_cast<const RequestKey *>(key); 23 100589 : return std::unique_ptr<DBEntry>(new Inet6VpnRoute(pfxkey->prefix)); 24 : } 25 : 26 : std::unique_ptr<DBEntry> 27 20 : Inet6VpnTable::AllocEntryStr(const std::string &key_str) const { 28 20 : Inet6VpnPrefix vpn_prefix = Inet6VpnPrefix::FromString(key_str); 29 40 : return std::unique_ptr<DBEntry> (new Inet6VpnRoute(vpn_prefix)); 30 : } 31 : 32 1293471 : size_t Inet6VpnTable::Hash(const DBEntry *entry) const { 33 1293471 : const Inet6VpnRoute *vpn_route = static_cast<const Inet6VpnRoute *>(entry); 34 1293471 : const Inet6VpnPrefix &vpn_prefix = vpn_route->GetPrefix(); 35 1293400 : Inet6Prefix prefix(vpn_prefix.addr(), vpn_prefix.prefixlen()); 36 1293078 : size_t value = Inet6Table::HashFunction(prefix); 37 1292541 : return value % DB::PartitionCount(); 38 : } 39 : 40 64870 : size_t Inet6VpnTable::Hash(const DBRequestKey *key) const { 41 64870 : const RequestKey *rkey = static_cast<const RequestKey *>(key); 42 64870 : Inet6Prefix prefix(rkey->prefix.addr(), rkey->prefix.prefixlen()); 43 64870 : size_t value = Inet6Table::HashFunction(prefix); 44 64870 : return value % DB::PartitionCount(); 45 : } 46 : 47 63141 : BgpRoute *Inet6VpnTable::TableFind(DBTablePartition *rtp, 48 : const DBRequestKey *prefix) { 49 63141 : const RequestKey *pfxkey = static_cast<const RequestKey *>(prefix); 50 63141 : Inet6VpnRoute vpn_route(pfxkey->prefix); 51 126286 : return static_cast<BgpRoute *>(rtp->Find(&vpn_route)); 52 63160 : } 53 : 54 8228 : DBTableBase *Inet6VpnTable::CreateTable(DB *db, const std::string &name) { 55 8228 : Inet6VpnTable *table = new Inet6VpnTable(db, name); 56 8228 : table->Init(); 57 8228 : return table; 58 : } 59 : 60 20393 : static RouteDistinguisher GenerateDistinguisher( 61 : const BgpTable *src_table, const BgpPath *src_path) { 62 20393 : const RouteDistinguisher &source_rd = src_path->GetAttr()->source_rd(); 63 20392 : if (!src_path->GetPeer() || !(src_path->GetPeer()->IsRouterTypeBGPaaS())){ 64 19145 : if (!source_rd.IsZero()) 65 11484 : return source_rd; 66 : 67 7659 : assert(!src_path->GetPeer() || !src_path->GetPeer()->IsXmppPeer()); 68 7659 : const RoutingInstance *src_instance = src_table->routing_instance(); 69 7659 : return *src_instance->GetRD(); 70 : } 71 1247 : uint16_t peer_port_id = 0; 72 1247 : as_t asn_num = src_path->GetAttr()->neighbor_as(); 73 : 74 1247 : std::string ri_name = src_table->routing_instance()->name(); 75 2494 : for (const BgpPeer *peer = src_path->GetPeer()->server()->FindNextPeer(); peer != NULL; 76 1247 : peer = src_path->GetPeer()->server()->FindNextPeer(peer->peer_name())) { 77 3741 : if ((peer->peer_name().find(ri_name)!= std::string::npos)&& 78 3741 : (peer->peer_address_string().find(src_path->GetPeer()->ToString())!= std::string::npos)){ 79 1247 : peer_port_id = peer->peer_port(); 80 1247 : asn_num = peer->peer_as(); 81 1247 : break; 82 : } 83 : } 84 1247 : RouteDistinguisher new_source_rd = RouteDistinguisher(true, asn_num, peer_port_id); 85 1247 : return new_source_rd; 86 1247 : } 87 : 88 20393 : BgpRoute *Inet6VpnTable::RouteReplicate(BgpServer *server, BgpTable *src_table, 89 : BgpRoute *source_rt, const BgpPath *src_path, 90 : ExtCommunityPtr community) { 91 20393 : assert(src_table->family() == Address::INET6); 92 : 93 20393 : Inet6Route *src_rt = dynamic_cast<Inet6Route *>(source_rt); 94 20393 : assert(src_rt); 95 : 96 20393 : const RouteDistinguisher &rd = GenerateDistinguisher(src_table, src_path); 97 20390 : Inet6VpnPrefix vpn_prefix(rd, src_rt->GetPrefix().ip6_addr(), 98 40780 : src_rt->GetPrefix().prefixlen()); 99 : 100 20390 : Inet6VpnRoute vpn_route(vpn_prefix); 101 : DBTablePartition *partition = 102 20393 : static_cast<DBTablePartition *>(GetTablePartition(&vpn_route)); 103 20390 : BgpRoute *dest_route = static_cast<BgpRoute *>(partition->Find(&vpn_route)); 104 20393 : if (dest_route == NULL) { 105 12218 : dest_route = new Inet6VpnRoute(vpn_prefix); 106 12218 : partition->Add(dest_route); 107 : } else { 108 8175 : dest_route->ClearDelete(); 109 : } 110 : 111 20393 : BgpAttrDB *attr_db = server->attr_db(); 112 : 113 : BgpAttrPtr new_attr = 114 : server->attr_db()->ReplaceExtCommunityAndLocate(src_path->GetAttr(), 115 20392 : community); 116 20393 : new_attr = attr_db->ReplaceSourceRdAndLocate(new_attr.get(), rd); 117 : 118 : // Check whether there's already a path with the given peer and path id. 119 : BgpPath *dest_path = 120 20393 : dest_route->FindSecondaryPath(source_rt, src_path->GetSource(), 121 : src_path->GetPeer(), 122 : src_path->GetPathId()); 123 20393 : if (dest_path != NULL) { 124 14218 : if ((new_attr != dest_path->GetOriginalAttr()) || 125 14218 : (src_path->GetFlags() != dest_path->GetFlags()) || 126 3849 : (src_path->GetLabel() != dest_path->GetLabel())) { 127 : // Update Attributes and notify (if needed) 128 4045 : assert(dest_route->RemoveSecondaryPath(source_rt, 129 : src_path->GetSource(), src_path->GetPeer(), 130 : src_path->GetPathId())); 131 : } else { 132 3790 : return dest_route; 133 : } 134 : } 135 : 136 : // Create replicated path and insert it on the route 137 : BgpSecondaryPath *replicated_path = 138 16603 : new BgpSecondaryPath(src_path->GetPeer(), src_path->GetPathId(), 139 16603 : src_path->GetSource(), new_attr, 140 16603 : src_path->GetFlags(), src_path->GetLabel()); 141 16603 : replicated_path->SetReplicateInfo(src_table, source_rt); 142 16603 : dest_route->InsertPath(replicated_path); 143 : 144 : // Always trigger notification. 145 16603 : partition->Notify(dest_route); 146 : 147 16603 : return dest_route; 148 20393 : } 149 : 150 119436 : bool Inet6VpnTable::Export(RibOut *ribout, Route *route, 151 : const RibPeerSet &peerset, UpdateInfoSList &uinfo_slist) { 152 119436 : BgpRoute *bgp_route = static_cast<BgpRoute *> (route); 153 119436 : UpdateInfo *uinfo = GetUpdateInfo(ribout, bgp_route, peerset); 154 119494 : if (!uinfo) { 155 53467 : return false; 156 : } 157 66027 : uinfo_slist->push_front(*uinfo); 158 : 159 66030 : return true; 160 : } 161 : 162 159 : static void RegisterFactory() { 163 159 : DB::RegisterFactory("bgp.l3vpn-inet6.0", &Inet6VpnTable::CreateTable); 164 159 : } 165 : MODULE_INITIALIZER(RegisterFactory);