Line data Source code
1 : /* 2 : * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved. 3 : */ 4 : 5 : #include "bgp/l3vpn/inetvpn_table.h" 6 : 7 : #include "bgp/ipeer.h" 8 : #include "bgp/bgp_server.h" 9 : #include "bgp/bgp_update.h" 10 : #include "bgp/inet/inet_table.h" 11 : #include "bgp/bgp_peer.h" 12 : #include "bgp/routing-instance/routing_instance.h" 13 : #include "net/rd.h" 14 : 15 : using std::unique_ptr; 16 : using std::string; 17 : 18 8235 : InetVpnTable::InetVpnTable(DB *db, const string &name) 19 8235 : : BgpTable(db, name) { 20 8235 : } 21 : 22 105146 : unique_ptr<DBEntry> InetVpnTable::AllocEntry(const DBRequestKey *key) const { 23 105146 : const RequestKey *pfxkey = static_cast<const RequestKey *>(key); 24 105146 : return unique_ptr<DBEntry> (new InetVpnRoute(pfxkey->prefix)); 25 : } 26 : 27 : 28 61 : unique_ptr<DBEntry> InetVpnTable::AllocEntryStr(const string &key_str) const { 29 61 : InetVpnPrefix prefix = InetVpnPrefix::FromString(key_str); 30 122 : return unique_ptr<DBEntry> (new InetVpnRoute(prefix)); 31 : } 32 : 33 1560930 : size_t InetVpnTable::Hash(const DBEntry *entry) const { 34 1560930 : const InetVpnRoute *rt_entry = static_cast<const InetVpnRoute *>(entry); 35 1560930 : const InetVpnPrefix &inetvpnprefix = rt_entry->GetPrefix(); 36 1560890 : Ip4Prefix prefix(inetvpnprefix.addr(), inetvpnprefix.prefixlen()); 37 1560521 : size_t value = InetTable::HashFunction(prefix); 38 1560335 : return value % DB::PartitionCount(); 39 : } 40 : 41 108951 : size_t InetVpnTable::Hash(const DBRequestKey *key) const { 42 108951 : const RequestKey *rkey = static_cast<const RequestKey *>(key); 43 108951 : Ip4Prefix prefix(rkey->prefix.addr(), rkey->prefix.prefixlen()); 44 108951 : size_t value = InetTable::HashFunction(prefix); 45 108951 : return value % DB::PartitionCount(); 46 : } 47 : 48 78652 : BgpRoute *InetVpnTable::TableFind(DBTablePartition *rtp, 49 : const DBRequestKey *prefix) { 50 78652 : const RequestKey *pfxkey = static_cast<const RequestKey *>(prefix); 51 78652 : InetVpnRoute rt_key(pfxkey->prefix); 52 157267 : return static_cast<BgpRoute *>(rtp->Find(&rt_key)); 53 78656 : } 54 : 55 8233 : DBTableBase *InetVpnTable::CreateTable(DB *db, const string &name) { 56 8233 : InetVpnTable *table = new InetVpnTable(db, name); 57 8233 : table->Init(); 58 8233 : return table; 59 : } 60 : 61 33854 : static RouteDistinguisher GenerateDistinguisher( 62 : const BgpTable *src_table, const BgpPath *src_path) { 63 33854 : const RouteDistinguisher &source_rd = src_path->GetAttr()->source_rd(); 64 33855 : if (!src_path->GetPeer() || !(src_path->GetPeer()->IsRouterTypeBGPaaS())){ 65 32641 : if (!source_rd.IsZero()) 66 22679 : return source_rd; 67 : 68 9962 : assert(!src_path->GetPeer() || !src_path->GetPeer()->IsXmppPeer()); 69 9962 : const RoutingInstance *src_instance = src_table->routing_instance(); 70 9962 : return *src_instance->GetRD(); 71 : } 72 1214 : boost::system::error_code ec; 73 1214 : Ip4Address addr = Ip4Address::from_string(src_path->GetPeer()->ToString(), ec); 74 1215 : if ((ec.value() != 0)) { 75 0 : if (!source_rd.IsZero()) 76 0 : return source_rd; 77 : 78 0 : assert(!src_path->GetPeer() || !src_path->GetPeer()->IsXmppPeer()); 79 0 : const RoutingInstance *src_instance = src_table->routing_instance(); 80 0 : return *src_instance->GetRD(); 81 : } else { 82 1214 : int vrf_id = 0; 83 1214 : RouteDistinguisher new_source_rd = RouteDistinguisher(addr.to_ulong(), vrf_id); 84 1215 : return new_source_rd; 85 : } 86 : } 87 : 88 33854 : BgpRoute *InetVpnTable::RouteReplicate(BgpServer *server, 89 : BgpTable *src_table, BgpRoute *src_rt, const BgpPath *src_path, 90 : ExtCommunityPtr community) { 91 33854 : assert(src_table->family() == Address::INET); 92 : 93 33854 : InetRoute *inet = dynamic_cast<InetRoute *> (src_rt); 94 33854 : assert(inet); 95 : 96 33854 : const RouteDistinguisher &rd = GenerateDistinguisher(src_table, src_path); 97 : 98 33855 : InetVpnPrefix vpn(rd, inet->GetPrefix().ip4_addr(), 99 67710 : inet->GetPrefix().prefixlen()); 100 : 101 33855 : InetVpnRoute rt_key(vpn); 102 : 103 : DBTablePartition *rtp = 104 33854 : static_cast<DBTablePartition *>(GetTablePartition(&rt_key)); 105 33853 : BgpRoute *dest_route = static_cast<BgpRoute *>(rtp->Find(&rt_key)); 106 33856 : if (dest_route == NULL) { 107 23218 : dest_route = new InetVpnRoute(vpn); 108 23217 : rtp->Add(dest_route); 109 : } else { 110 10638 : dest_route->ClearDelete(); 111 : } 112 : 113 33855 : BgpAttrDB *attr_db = server->attr_db(); 114 : 115 : BgpAttrPtr new_attr = 116 : server->attr_db()->ReplaceExtCommunityAndLocate(src_path->GetAttr(), 117 33854 : community); 118 33856 : new_attr = attr_db->ReplaceSourceRdAndLocate(new_attr.get(), rd); 119 : // Check whether there's already a path with the given peer and path id. 120 : BgpPath *dest_path = 121 33856 : dest_route->FindSecondaryPath(src_rt, src_path->GetSource(), 122 : src_path->GetPeer(), 123 : src_path->GetPathId()); 124 33856 : if (dest_path != NULL) { 125 17001 : if ((new_attr != dest_path->GetOriginalAttr()) || 126 17001 : (src_path->GetFlags() != dest_path->GetFlags()) || 127 4201 : (src_path->GetLabel() != dest_path->GetLabel())) { 128 : // Update Attributes and notify (if needed) 129 6258 : assert(dest_route->RemoveSecondaryPath(src_rt, 130 : src_path->GetSource(), src_path->GetPeer(), 131 : src_path->GetPathId())); 132 : } else { 133 4030 : return dest_route; 134 : } 135 : } 136 : 137 : // Create replicated path and insert it on the route 138 : BgpSecondaryPath *replicated_path = 139 29826 : new BgpSecondaryPath(src_path->GetPeer(), src_path->GetPathId(), 140 29826 : src_path->GetSource(), new_attr, 141 29826 : src_path->GetFlags(), src_path->GetLabel()); 142 29826 : replicated_path->SetReplicateInfo(src_table, src_rt); 143 29826 : dest_route->InsertPath(replicated_path); 144 : 145 : // Always trigger notification. 146 29826 : rtp->Notify(dest_route); 147 : 148 : // Update corresponding route's extended communities in inet.0 table. 149 : InetTable *inet_table = 150 29826 : dynamic_cast<InetTable *>(routing_instance()->GetTable(Address::INET)); 151 29826 : InetVpnRoute *inetvpn_route = dynamic_cast<InetVpnRoute *>(dest_route); 152 29826 : inet_table->UpdateRoute(inetvpn_route->GetPrefix(), src_path->GetPeer(), 153 : new_attr); 154 29826 : return dest_route; 155 33856 : } 156 : 157 142889 : bool InetVpnTable::Export(RibOut *ribout, Route *route, 158 : const RibPeerSet &peerset, UpdateInfoSList &uinfo_slist) { 159 142889 : BgpRoute *bgp_route = static_cast<BgpRoute *> (route); 160 142889 : UpdateInfo *uinfo = GetUpdateInfo(ribout, bgp_route, peerset); 161 142940 : if (!uinfo) return false; 162 77419 : uinfo_slist->push_front(*uinfo); 163 : 164 77420 : return true; 165 : } 166 : 167 159 : static void RegisterFactory() { 168 159 : DB::RegisterFactory("bgp.l3vpn.0", &InetVpnTable::CreateTable); 169 159 : } 170 : MODULE_INITIALIZER(RegisterFactory);