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 105269 : unique_ptr<DBEntry> InetVpnTable::AllocEntry(const DBRequestKey *key) const { 23 105269 : const RequestKey *pfxkey = static_cast<const RequestKey *>(key); 24 105269 : 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 1572697 : size_t InetVpnTable::Hash(const DBEntry *entry) const { 34 1572697 : const InetVpnRoute *rt_entry = static_cast<const InetVpnRoute *>(entry); 35 1572697 : const InetVpnPrefix &inetvpnprefix = rt_entry->GetPrefix(); 36 1572677 : Ip4Prefix prefix(inetvpnprefix.addr(), inetvpnprefix.prefixlen()); 37 1572314 : size_t value = InetTable::HashFunction(prefix); 38 1572071 : 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 108949 : size_t value = InetTable::HashFunction(prefix); 45 108948 : return value % DB::PartitionCount(); 46 : } 47 : 48 78657 : BgpRoute *InetVpnTable::TableFind(DBTablePartition *rtp, 49 : const DBRequestKey *prefix) { 50 78657 : const RequestKey *pfxkey = static_cast<const RequestKey *>(prefix); 51 78657 : InetVpnRoute rt_key(pfxkey->prefix); 52 157264 : return static_cast<BgpRoute *>(rtp->Find(&rt_key)); 53 78673 : } 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 33807 : static RouteDistinguisher GenerateDistinguisher( 62 : const BgpTable *src_table, const BgpPath *src_path) { 63 33807 : const RouteDistinguisher &source_rd = src_path->GetAttr()->source_rd(); 64 33807 : if (!src_path->GetPeer() || !(src_path->GetPeer()->IsRouterTypeBGPaaS())){ 65 32617 : if (!source_rd.IsZero()) 66 22656 : return source_rd; 67 : 68 9961 : assert(!src_path->GetPeer() || !src_path->GetPeer()->IsXmppPeer()); 69 9961 : const RoutingInstance *src_instance = src_table->routing_instance(); 70 9961 : return *src_instance->GetRD(); 71 : } 72 1190 : boost::system::error_code ec; 73 1190 : Ip4Address addr = Ip4Address::from_string(src_path->GetPeer()->ToString(), ec); 74 1192 : 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 1192 : int vrf_id = 0; 83 1192 : RouteDistinguisher new_source_rd = RouteDistinguisher(addr.to_ulong(), vrf_id); 84 1192 : return new_source_rd; 85 : } 86 : } 87 : 88 33807 : BgpRoute *InetVpnTable::RouteReplicate(BgpServer *server, 89 : BgpTable *src_table, BgpRoute *src_rt, const BgpPath *src_path, 90 : ExtCommunityPtr community) { 91 33807 : assert(src_table->family() == Address::INET); 92 : 93 33807 : InetRoute *inet = dynamic_cast<InetRoute *> (src_rt); 94 33807 : assert(inet); 95 : 96 33807 : const RouteDistinguisher &rd = GenerateDistinguisher(src_table, src_path); 97 : 98 33808 : InetVpnPrefix vpn(rd, inet->GetPrefix().ip4_addr(), 99 67617 : inet->GetPrefix().prefixlen()); 100 : 101 33808 : InetVpnRoute rt_key(vpn); 102 : 103 : DBTablePartition *rtp = 104 33811 : static_cast<DBTablePartition *>(GetTablePartition(&rt_key)); 105 33809 : BgpRoute *dest_route = static_cast<BgpRoute *>(rtp->Find(&rt_key)); 106 33811 : if (dest_route == NULL) { 107 23240 : dest_route = new InetVpnRoute(vpn); 108 23238 : rtp->Add(dest_route); 109 : } else { 110 10571 : dest_route->ClearDelete(); 111 : } 112 : 113 33811 : BgpAttrDB *attr_db = server->attr_db(); 114 : 115 : BgpAttrPtr new_attr = 116 : server->attr_db()->ReplaceExtCommunityAndLocate(src_path->GetAttr(), 117 33810 : community); 118 33811 : 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 33811 : dest_route->FindSecondaryPath(src_rt, src_path->GetSource(), 122 : src_path->GetPeer(), 123 : src_path->GetPathId()); 124 33809 : if (dest_path != NULL) { 125 16889 : if ((new_attr != dest_path->GetOriginalAttr()) || 126 16889 : (src_path->GetFlags() != dest_path->GetFlags()) || 127 4134 : (src_path->GetLabel() != dest_path->GetLabel())) { 128 : // Update Attributes and notify (if needed) 129 6256 : assert(dest_route->RemoveSecondaryPath(src_rt, 130 : src_path->GetSource(), src_path->GetPeer(), 131 : src_path->GetPathId())); 132 : } else { 133 3979 : return dest_route; 134 : } 135 : } 136 : 137 : // Create replicated path and insert it on the route 138 : BgpSecondaryPath *replicated_path = 139 29830 : new BgpSecondaryPath(src_path->GetPeer(), src_path->GetPathId(), 140 29830 : src_path->GetSource(), new_attr, 141 29830 : src_path->GetFlags(), src_path->GetLabel()); 142 29832 : replicated_path->SetReplicateInfo(src_table, src_rt); 143 29831 : dest_route->InsertPath(replicated_path); 144 : 145 : // Always trigger notification. 146 29832 : rtp->Notify(dest_route); 147 : 148 : // Update corresponding route's extended communities in inet.0 table. 149 : InetTable *inet_table = 150 29832 : dynamic_cast<InetTable *>(routing_instance()->GetTable(Address::INET)); 151 29831 : InetVpnRoute *inetvpn_route = dynamic_cast<InetVpnRoute *>(dest_route); 152 29831 : inet_table->UpdateRoute(inetvpn_route->GetPrefix(), src_path->GetPeer(), 153 : new_attr); 154 29832 : return dest_route; 155 33811 : } 156 : 157 143030 : bool InetVpnTable::Export(RibOut *ribout, Route *route, 158 : const RibPeerSet &peerset, UpdateInfoSList &uinfo_slist) { 159 143030 : BgpRoute *bgp_route = static_cast<BgpRoute *> (route); 160 143030 : UpdateInfo *uinfo = GetUpdateInfo(ribout, bgp_route, peerset); 161 143082 : if (!uinfo) return false; 162 77650 : uinfo_slist->push_front(*uinfo); 163 : 164 77651 : return true; 165 : } 166 : 167 159 : static void RegisterFactory() { 168 159 : DB::RegisterFactory("bgp.l3vpn.0", &InetVpnTable::CreateTable); 169 159 : } 170 : MODULE_INITIALIZER(RegisterFactory);