Line data Source code
1 : /* 2 : * Copyright (c) 2014 Juniper Networks, Inc. All rights reserved. 3 : */ 4 : 5 : #include "bgp/inet6/inet6_table.h" 6 : 7 : #include "bgp/bgp_server.h" 8 : #include "bgp/bgp_update.h" 9 : #include "bgp/inet6vpn/inet6vpn_route.h" 10 : #include "bgp/routing-instance/path_resolver.h" 11 : #include "bgp/routing-instance/routing_instance.h" 12 : 13 51133 : Inet6Table::Inet6Table(DB *db, const std::string &name) 14 51133 : : BgpTable(db, name) { 15 51134 : } 16 : 17 5014945 : size_t Inet6Table::HashFunction(const Inet6Prefix &prefix) { 18 5014945 : const Ip6Address::bytes_type &addr_bytes = prefix.ToBytes(); 19 10023246 : return boost::hash_range(addr_bytes.begin(), addr_bytes.end()); 20 : } 21 : 22 196848 : std::unique_ptr<DBEntry> Inet6Table::AllocEntry(const DBRequestKey *key) const { 23 196848 : const RequestKey *rkey = static_cast<const RequestKey *>(key); 24 196848 : return std::unique_ptr<DBEntry> (new Inet6Route(rkey->prefix)); 25 : } 26 : 27 12 : std::unique_ptr<DBEntry> Inet6Table::AllocEntryStr( 28 : const std::string &key_str) const { 29 12 : Inet6Prefix prefix = Inet6Prefix::FromString(key_str); 30 24 : return std::unique_ptr<DBEntry> (new Inet6Route(prefix)); 31 : } 32 : 33 3495072 : size_t Inet6Table::Hash(const DBEntry *entry) const { 34 3495072 : const Inet6Route *route = static_cast<const Inet6Route *>(entry); 35 3495072 : size_t value = HashFunction(route->GetPrefix()); 36 3492098 : return value % DB::PartitionCount(); 37 : } 38 : 39 37993 : size_t Inet6Table::Hash(const DBRequestKey *key) const { 40 37993 : const RequestKey *rkey = static_cast<const RequestKey *>(key); 41 37993 : size_t value = HashFunction(rkey->prefix); 42 37993 : return value % DB::PartitionCount(); 43 : } 44 : 45 26996 : BgpRoute *Inet6Table::TableFind(DBTablePartition *partition, 46 : const DBRequestKey *key) { 47 26996 : const RequestKey *rkey = static_cast<const RequestKey *>(key); 48 26996 : Inet6Route route(rkey->prefix); 49 54013 : return static_cast<BgpRoute *>(partition->Find(&route)); 50 27008 : } 51 : 52 51133 : DBTableBase *Inet6Table::CreateTable(DB *db, const std::string &name) { 53 51133 : Inet6Table *table = new Inet6Table(db, name); 54 51134 : table->Init(); 55 51132 : return table; 56 : } 57 : 58 286376 : BgpRoute *Inet6Table::RouteReplicate(BgpServer *server, BgpTable *src_table, 59 : BgpRoute *src_rt, const BgpPath *path, ExtCommunityPtr community) { 60 286376 : assert((src_table->family() == Address::INET6) || 61 : (src_table->family() == Address::INET6VPN)); 62 : 63 286368 : Inet6Route *source = dynamic_cast<Inet6Route *>(src_rt); 64 : 65 286368 : RouteDistinguisher rd; 66 : 67 286374 : boost::scoped_ptr<Inet6Prefix> prefix; 68 286374 : if (source) { 69 56601 : prefix.reset(new Inet6Prefix(source->GetPrefix().ip6_addr(), 70 28299 : source->GetPrefix().prefixlen())); 71 : } else { 72 258072 : Inet6VpnRoute *vpn_route = dynamic_cast<Inet6VpnRoute *> (src_rt); 73 258072 : assert(vpn_route); 74 258072 : rd = vpn_route->GetPrefix().route_distinguisher(); 75 516128 : prefix.reset(new Inet6Prefix(vpn_route->GetPrefix().addr(), 76 258065 : vpn_route->GetPrefix().prefixlen())); 77 : } 78 : 79 286353 : Inet6Route route(*prefix); 80 : DBTablePartition *partition = 81 286367 : static_cast<DBTablePartition *>(GetTablePartition(&route)); 82 286325 : BgpRoute *dest_route = static_cast<BgpRoute *>(partition->Find(&route)); 83 286364 : if (dest_route == NULL) { 84 167753 : dest_route = new Inet6Route(route.GetPrefix()); 85 167757 : partition->Add(dest_route); 86 : } else { 87 118611 : dest_route->ClearDelete(); 88 : } 89 : 90 : // Replace the extended community with the one provided. 91 286349 : BgpAttrDB *attr_db = server->attr_db(); 92 : BgpAttrPtr new_attr = attr_db->ReplaceExtCommunityAndLocate(path->GetAttr(), 93 286348 : community); 94 : 95 286377 : if (!source) { 96 258078 : new_attr = attr_db->ReplaceSourceRdAndLocate(new_attr.get(), rd); 97 : } 98 : 99 : // Check whether there's already a path with the given peer and path id. 100 : BgpPath *dest_path = 101 286376 : dest_route->FindSecondaryPath(src_rt, path->GetSource(), 102 : path->GetPeer(), path->GetPathId()); 103 286368 : if (dest_path != NULL) { 104 227254 : if ((new_attr != dest_path->GetOriginalAttr()) || 105 227252 : (path->GetFlags() != dest_path->GetFlags()) || 106 97654 : (path->GetLabel() != dest_path->GetLabel())) { 107 : // Update Attributes and notify (if needed) 108 18994 : if (dest_path->NeedsResolution()) { 109 0 : path_resolver()->StopPathResolution(partition->index(), 110 : dest_path); 111 : } 112 18994 : assert(dest_route->RemoveSecondaryPath(src_rt, path->GetSource(), 113 : path->GetPeer(), path->GetPathId())); 114 : } else { 115 97633 : return dest_route; 116 : } 117 : } 118 : 119 : BgpSecondaryPath *replicated_path = 120 188732 : new BgpSecondaryPath(path->GetPeer(), path->GetPathId(), 121 188732 : path->GetSource(), new_attr, path->GetFlags(), path->GetLabel()); 122 188736 : replicated_path->SetReplicateInfo(src_table, src_rt); 123 : 124 : // For VPN to VRF replication, start path resolution if fast convergence is 125 : // enabled and update path flag to indicate need for resolution. 126 188734 : if (!source && (server->IsNextHopCheckEnabled()) && 127 0 : (replicated_path->GetSource() == BgpPath::BGP_XMPP)) { 128 0 : Address::Family family = replicated_path->GetAttr()->nexthop_family(); 129 0 : RoutingInstanceMgr *mgr = server->routing_instance_mgr(); 130 0 : RoutingInstance *master_ri = mgr->GetDefaultRoutingInstance(); 131 0 : BgpTable *table = master_ri->GetTable(family); 132 0 : replicated_path->SetResolveNextHop(); 133 0 : path_resolver()->StartPathResolution(dest_route, replicated_path, 134 : table); 135 : } 136 : 137 188731 : dest_route->InsertPath(replicated_path); 138 : 139 : // Notify the route even if the best path may not have changed. For XMPP 140 : // peers, we support sending multiple ECMP next-hops for a single route. 141 : // 142 : // TODO(ananth): Can be optimized for changes that does not result in 143 : // any change to ECMP list 144 188731 : partition->Notify(dest_route); 145 : 146 188732 : return dest_route; 147 286365 : } 148 : 149 217753 : bool Inet6Table::Export(RibOut *ribout, Route *route, const RibPeerSet &peerset, 150 : UpdateInfoSList &uinfo_slist) { 151 217753 : BgpRoute *bgp_route = static_cast<BgpRoute *> (route); 152 217753 : UpdateInfo *uinfo = GetUpdateInfo(ribout, bgp_route, peerset); 153 217790 : if (!uinfo) { 154 4532 : return false; 155 : } 156 : 157 213258 : if (ribout->ExportPolicy().encoding == RibExportPolicy::BGP) { 158 4510 : BgpAttrDB *attr_db = routing_instance()->server()->attr_db(); 159 : // Strip ExtCommunity. 160 4510 : if (uinfo->roattr.attr()->ext_community()) { 161 : BgpAttrPtr new_attr = attr_db->ReplaceExtCommunityAndLocate( 162 1656 : uinfo->roattr.attr(), NULL); 163 1656 : uinfo->roattr.set_attr(this, new_attr); 164 1656 : } 165 : 166 : // Strip OriginVnPath. 167 4510 : if (uinfo->roattr.attr()->origin_vn_path()) { 168 : BgpAttrPtr new_attr = attr_db->ReplaceOriginVnPathAndLocate( 169 0 : uinfo->roattr.attr(), NULL); 170 0 : uinfo->roattr.set_attr(this, new_attr); 171 0 : } 172 : } 173 213272 : uinfo_slist->push_front(*uinfo); 174 : 175 213271 : return true; 176 : } 177 : 178 42907 : PathResolver *Inet6Table::CreatePathResolver() { 179 42907 : if (routing_instance()->IsMasterRoutingInstance()) 180 0 : return NULL; 181 42907 : return (new PathResolver(this)); 182 : } 183 : 184 159 : static void RegisterFactory() { 185 159 : DB::RegisterFactory("inet6.0", &Inet6Table::CreateTable); 186 159 : } 187 : MODULE_INITIALIZER(RegisterFactory);