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 378 : InetVpnTable::InetVpnTable(DB *db, const string &name) 19 378 : : BgpTable(db, name) { 20 378 : } 21 : 22 0 : unique_ptr<DBEntry> InetVpnTable::AllocEntry(const DBRequestKey *key) const { 23 0 : const RequestKey *pfxkey = static_cast<const RequestKey *>(key); 24 0 : 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 0 : size_t InetVpnTable::Hash(const DBEntry *entry) const { 34 0 : const InetVpnRoute *rt_entry = static_cast<const InetVpnRoute *>(entry); 35 0 : const InetVpnPrefix &inetvpnprefix = rt_entry->GetPrefix(); 36 0 : Ip4Prefix prefix(inetvpnprefix.addr(), inetvpnprefix.prefixlen()); 37 0 : size_t value = InetTable::HashFunction(prefix); 38 0 : return value % DB::PartitionCount(); 39 : } 40 : 41 0 : size_t InetVpnTable::Hash(const DBRequestKey *key) const { 42 0 : const RequestKey *rkey = static_cast<const RequestKey *>(key); 43 0 : Ip4Prefix prefix(rkey->prefix.addr(), rkey->prefix.prefixlen()); 44 0 : size_t value = InetTable::HashFunction(prefix); 45 0 : return value % DB::PartitionCount(); 46 : } 47 : 48 0 : BgpRoute *InetVpnTable::TableFind(DBTablePartition *rtp, 49 : const DBRequestKey *prefix) { 50 0 : const RequestKey *pfxkey = static_cast<const RequestKey *>(prefix); 51 0 : InetVpnRoute rt_key(pfxkey->prefix); 52 0 : return static_cast<BgpRoute *>(rtp->Find(&rt_key)); 53 0 : } 54 : 55 378 : DBTableBase *InetVpnTable::CreateTable(DB *db, const string &name) { 56 378 : InetVpnTable *table = new InetVpnTable(db, name); 57 378 : table->Init(); 58 378 : return table; 59 : } 60 : 61 0 : static RouteDistinguisher GenerateDistinguisher( 62 : const BgpTable *src_table, const BgpPath *src_path) { 63 0 : const RouteDistinguisher &source_rd = src_path->GetAttr()->source_rd(); 64 0 : if (!src_path->GetPeer() || !(src_path->GetPeer()->IsRouterTypeBGPaaS())){ 65 0 : if (!source_rd.IsZero()) 66 0 : 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 0 : BgpRoute *InetVpnTable::RouteReplicate(BgpServer *server, 89 : BgpTable *src_table, BgpRoute *src_rt, const BgpPath *src_path, 90 : ExtCommunityPtr community) { 91 0 : assert(src_table->family() == Address::INET); 92 : 93 0 : InetRoute *inet = dynamic_cast<InetRoute *> (src_rt); 94 0 : assert(inet); 95 : 96 0 : const RouteDistinguisher &rd = GenerateDistinguisher(src_table, src_path); 97 : 98 0 : InetVpnPrefix vpn(rd, inet->GetPrefix().ip4_addr(), 99 0 : inet->GetPrefix().prefixlen()); 100 : 101 0 : InetVpnRoute rt_key(vpn); 102 : 103 : DBTablePartition *rtp = 104 0 : static_cast<DBTablePartition *>(GetTablePartition(&rt_key)); 105 0 : BgpRoute *dest_route = static_cast<BgpRoute *>(rtp->Find(&rt_key)); 106 0 : if (dest_route == NULL) { 107 0 : dest_route = new InetVpnRoute(vpn); 108 0 : rtp->Add(dest_route); 109 : } else { 110 0 : dest_route->ClearDelete(); 111 : } 112 : 113 0 : BgpAttrDB *attr_db = server->attr_db(); 114 : 115 : BgpAttrPtr new_attr = 116 : server->attr_db()->ReplaceExtCommunityAndLocate(src_path->GetAttr(), 117 0 : community); 118 0 : 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 0 : dest_route->FindSecondaryPath(src_rt, src_path->GetSource(), 122 : src_path->GetPeer(), 123 : src_path->GetPathId()); 124 0 : if (dest_path != NULL) { 125 0 : if ((new_attr != dest_path->GetOriginalAttr()) || 126 0 : (src_path->GetFlags() != dest_path->GetFlags()) || 127 0 : (src_path->GetLabel() != dest_path->GetLabel())) { 128 : // Update Attributes and notify (if needed) 129 0 : 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 0 : new BgpSecondaryPath(src_path->GetPeer(), src_path->GetPathId(), 140 0 : src_path->GetSource(), new_attr, 141 0 : src_path->GetFlags(), src_path->GetLabel()); 142 0 : replicated_path->SetReplicateInfo(src_table, src_rt); 143 0 : dest_route->InsertPath(replicated_path); 144 : 145 : // Always trigger notification. 146 0 : rtp->Notify(dest_route); 147 : 148 : // Update corresponding route's extended communities in inet.0 table. 149 : InetTable *inet_table = 150 0 : dynamic_cast<InetTable *>(routing_instance()->GetTable(Address::INET)); 151 0 : InetVpnRoute *inetvpn_route = dynamic_cast<InetVpnRoute *>(dest_route); 152 0 : inet_table->UpdateRoute(inetvpn_route->GetPrefix(), src_path->GetPeer(), 153 : new_attr); 154 0 : return dest_route; 155 0 : } 156 : 157 0 : bool InetVpnTable::Export(RibOut *ribout, Route *route, 158 : const RibPeerSet &peerset, UpdateInfoSList &uinfo_slist) { 159 0 : BgpRoute *bgp_route = static_cast<BgpRoute *> (route); 160 0 : UpdateInfo *uinfo = GetUpdateInfo(ribout, bgp_route, peerset); 161 0 : if (!uinfo) return false; 162 0 : uinfo_slist->push_front(*uinfo); 163 : 164 0 : return true; 165 : } 166 : 167 1 : static void RegisterFactory() { 168 1 : DB::RegisterFactory("bgp.l3vpn.0", &InetVpnTable::CreateTable); 169 1 : } 170 : MODULE_INITIALIZER(RegisterFactory);