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