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