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 418 : InetVpnTable::InetVpnTable(DB *db, const string &name) 19 418 : : BgpTable(db, name) { 20 418 : } 21 : 22 17620 : unique_ptr<DBEntry> InetVpnTable::AllocEntry(const DBRequestKey *key) const { 23 17620 : const RequestKey *pfxkey = static_cast<const RequestKey *>(key); 24 17620 : return unique_ptr<DBEntry> (new InetVpnRoute(pfxkey->prefix)); 25 : } 26 : 27 : 28 0 : unique_ptr<DBEntry> InetVpnTable::AllocEntryStr(const string &key_str) const { 29 0 : InetVpnPrefix prefix = InetVpnPrefix::FromString(key_str); 30 0 : return unique_ptr<DBEntry> (new InetVpnRoute(prefix)); 31 : } 32 : 33 180233 : size_t InetVpnTable::Hash(const DBEntry *entry) const { 34 180233 : const InetVpnRoute *rt_entry = static_cast<const InetVpnRoute *>(entry); 35 180233 : const InetVpnPrefix &inetvpnprefix = rt_entry->GetPrefix(); 36 180219 : Ip4Prefix prefix(inetvpnprefix.addr(), inetvpnprefix.prefixlen()); 37 180114 : size_t value = InetTable::HashFunction(prefix); 38 180035 : return value % DB::PartitionCount(); 39 : } 40 : 41 9088 : size_t InetVpnTable::Hash(const DBRequestKey *key) const { 42 9088 : const RequestKey *rkey = static_cast<const RequestKey *>(key); 43 9088 : Ip4Prefix prefix(rkey->prefix.addr(), rkey->prefix.prefixlen()); 44 9088 : size_t value = InetTable::HashFunction(prefix); 45 9088 : return value % DB::PartitionCount(); 46 : } 47 : 48 8062 : BgpRoute *InetVpnTable::TableFind(DBTablePartition *rtp, 49 : const DBRequestKey *prefix) { 50 8062 : const RequestKey *pfxkey = static_cast<const RequestKey *>(prefix); 51 8062 : InetVpnRoute rt_key(pfxkey->prefix); 52 16119 : return static_cast<BgpRoute *>(rtp->Find(&rt_key)); 53 8062 : } 54 : 55 418 : DBTableBase *InetVpnTable::CreateTable(DB *db, const string &name) { 56 418 : InetVpnTable *table = new InetVpnTable(db, name); 57 418 : table->Init(); 58 418 : return table; 59 : } 60 : 61 1024 : static RouteDistinguisher GenerateDistinguisher( 62 : const BgpTable *src_table, const BgpPath *src_path) { 63 1024 : const RouteDistinguisher &source_rd = src_path->GetAttr()->source_rd(); 64 1024 : if (!src_path->GetPeer() || !(src_path->GetPeer()->IsRouterTypeBGPaaS())){ 65 1024 : if (!source_rd.IsZero()) 66 1024 : return source_rd; 67 : 68 0 : assert(!src_path->GetPeer() || !src_path->GetPeer()->IsXmppPeer()); 69 0 : const RoutingInstance *src_instance = src_table->routing_instance(); 70 0 : return *src_instance->GetRD(); 71 : } 72 0 : boost::system::error_code ec; 73 0 : Ip4Address addr = Ip4Address::from_string(src_path->GetPeer()->ToString(), ec); 74 0 : 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 0 : int vrf_id = 0; 83 0 : RouteDistinguisher new_source_rd = RouteDistinguisher(addr.to_ulong(), vrf_id); 84 0 : return new_source_rd; 85 : } 86 : } 87 : 88 1024 : BgpRoute *InetVpnTable::RouteReplicate(BgpServer *server, 89 : BgpTable *src_table, BgpRoute *src_rt, const BgpPath *src_path, 90 : ExtCommunityPtr community) { 91 1024 : assert(src_table->family() == Address::INET); 92 : 93 1024 : InetRoute *inet = dynamic_cast<InetRoute *> (src_rt); 94 1024 : assert(inet); 95 : 96 1024 : const RouteDistinguisher &rd = GenerateDistinguisher(src_table, src_path); 97 : 98 1024 : InetVpnPrefix vpn(rd, inet->GetPrefix().ip4_addr(), 99 2048 : inet->GetPrefix().prefixlen()); 100 : 101 1024 : InetVpnRoute rt_key(vpn); 102 : 103 : DBTablePartition *rtp = 104 1024 : static_cast<DBTablePartition *>(GetTablePartition(&rt_key)); 105 1024 : BgpRoute *dest_route = static_cast<BgpRoute *>(rtp->Find(&rt_key)); 106 1024 : if (dest_route == NULL) { 107 512 : dest_route = new InetVpnRoute(vpn); 108 512 : rtp->Add(dest_route); 109 : } else { 110 512 : dest_route->ClearDelete(); 111 : } 112 : 113 1024 : BgpAttrDB *attr_db = server->attr_db(); 114 : 115 : BgpAttrPtr new_attr = 116 : server->attr_db()->ReplaceExtCommunityAndLocate(src_path->GetAttr(), 117 1024 : community); 118 1024 : 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 1024 : dest_route->FindSecondaryPath(src_rt, src_path->GetSource(), 122 : src_path->GetPeer(), 123 : src_path->GetPathId()); 124 1024 : if (dest_path != NULL) { 125 1024 : if ((new_attr != dest_path->GetOriginalAttr()) || 126 1024 : (src_path->GetFlags() != dest_path->GetFlags()) || 127 0 : (src_path->GetLabel() != dest_path->GetLabel())) { 128 : // Update Attributes and notify (if needed) 129 512 : assert(dest_route->RemoveSecondaryPath(src_rt, 130 : src_path->GetSource(), src_path->GetPeer(), 131 : src_path->GetPathId())); 132 : } else { 133 0 : return dest_route; 134 : } 135 : } 136 : 137 : // Create replicated path and insert it on the route 138 : BgpSecondaryPath *replicated_path = 139 1024 : new BgpSecondaryPath(src_path->GetPeer(), src_path->GetPathId(), 140 1024 : src_path->GetSource(), new_attr, 141 1024 : src_path->GetFlags(), src_path->GetLabel()); 142 1024 : replicated_path->SetReplicateInfo(src_table, src_rt); 143 1024 : dest_route->InsertPath(replicated_path); 144 : 145 : // Always trigger notification. 146 1024 : rtp->Notify(dest_route); 147 : 148 : // Update corresponding route's extended communities in inet.0 table. 149 : InetTable *inet_table = 150 1024 : dynamic_cast<InetTable *>(routing_instance()->GetTable(Address::INET)); 151 1023 : InetVpnRoute *inetvpn_route = dynamic_cast<InetVpnRoute *>(dest_route); 152 1023 : inet_table->UpdateRoute(inetvpn_route->GetPrefix(), src_path->GetPeer(), 153 : new_attr); 154 1024 : return dest_route; 155 1024 : } 156 : 157 13461 : bool InetVpnTable::Export(RibOut *ribout, Route *route, 158 : const RibPeerSet &peerset, UpdateInfoSList &uinfo_slist) { 159 13461 : BgpRoute *bgp_route = static_cast<BgpRoute *> (route); 160 13461 : UpdateInfo *uinfo = GetUpdateInfo(ribout, bgp_route, peerset); 161 13479 : if (!uinfo) return false; 162 7172 : uinfo_slist->push_front(*uinfo); 163 : 164 7172 : return true; 165 : } 166 : 167 3 : static void RegisterFactory() { 168 3 : DB::RegisterFactory("bgp.l3vpn.0", &InetVpnTable::CreateTable); 169 3 : } 170 : MODULE_INITIALIZER(RegisterFactory);