diff --git a/src/bgp/bgp_route.cc b/src/bgp/bgp_route.cc index 6a08acf89c4..38125013eb8 100644 --- a/src/bgp/bgp_route.cc +++ b/src/bgp/bgp_route.cc @@ -12,6 +12,7 @@ #include "bgp/extended-community/esi_label.h" #include "bgp/extended-community/load_balance.h" #include "bgp/extended-community/mac_mobility.h" +#include "bgp/extended-community/router_mac.h" #include "bgp/extended-community/site_of_origin.h" #include "bgp/origin-vn/origin_vn.h" #include "bgp/routing-instance/routepath_replicator.h" @@ -356,6 +357,9 @@ static void FillRoutePathExtCommunityInfo(const BgpTable *table, MacMobility mm(*it); communities.push_back(mm.ToString()); show_path->set_sequence_no(mm.ToString()); + } else if (ExtCommunity::is_router_mac(*it)) { + RouterMac router_mac(*it); + communities.push_back(router_mac.ToString()); } else if (ExtCommunity::is_origin_vn(*it)) { OriginVn origin_vn(*it); communities.push_back(origin_vn.ToString()); diff --git a/src/bgp/bgp_xmpp_channel.cc b/src/bgp/bgp_xmpp_channel.cc index 7ea32e231dc..8c3a126e527 100644 --- a/src/bgp/bgp_xmpp_channel.cc +++ b/src/bgp/bgp_xmpp_channel.cc @@ -4,6 +4,7 @@ #include "bgp/bgp_xmpp_channel.h" +#include #include #include @@ -23,6 +24,7 @@ #include "bgp/inet6/inet6_table.h" #include "bgp/extended-community/load_balance.h" #include "bgp/extended-community/mac_mobility.h" +#include "bgp/extended-community/router_mac.h" #include "bgp/ermvpn/ermvpn_table.h" #include "bgp/evpn/evpn_table.h" #include "bgp/peer_close_manager.h" @@ -55,6 +57,7 @@ using autogen::SecurityGroupListType; using autogen::CommunityTagListType; using autogen::TunnelEncapsulationListType; +using boost::assign::list_of; using boost::regex; using boost::regex_search; using boost::smatch; @@ -909,179 +912,251 @@ bool BgpXmppChannel::ProcessItem(string vrf_name, } error_code error; - Ip4Prefix rt_prefix = Ip4Prefix::FromString(item.entry.nlri.address, - &error); + Ip4Prefix inet_prefix = + Ip4Prefix::FromString(item.entry.nlri.address, &error); if (error) { BGP_LOG_PEER_INSTANCE_WARNING(Peer(), vrf_name, BGP_LOG_FLAG_ALL, "Bad inet route " << item.entry.nlri.address); return false; } - bool subscribe_pending; - int instance_id; - uint64_t subscription_gen_id; - BgpTable *table; - if (!VerifyMembership(vrf_name, Address::INET, &table, &instance_id, - &subscription_gen_id, &subscribe_pending, add_change)) { - channel_->Close(); + if (add_change && item.entry.next_hops.next_hop.empty()) { + BGP_LOG_PEER_INSTANCE_WARNING(Peer(), vrf_name, BGP_LOG_FLAG_ALL, + "Missing next-hops for inet route " << inet_prefix.ToString()); return false; } - InetTable::RequestData::NextHops nexthops; - DBRequest req; - req.key.reset(new InetTable::RequestKey(rt_prefix, peer_.get())); - - IpAddress nh_address(Ip4Address(0)); - uint32_t label = 0; - uint32_t flags = 0; - ExtCommunitySpec ext; - CommunitySpec comm; - - if (add_change) { - req.oper = DBRequest::DB_ENTRY_ADD_CHANGE; - BgpAttrSpec attrs; - const NextHopListType &inh_list = item.entry.next_hops; - - if (inh_list.next_hop.empty()) { - BGP_LOG_PEER_INSTANCE_WARNING(Peer(), vrf_name, BGP_LOG_FLAG_ALL, - "Missing next-hops for inet route " << rt_prefix.ToString()); + // vector family_list = list_of(Address::INET)(Address::EVPN); + vector family_list = list_of(Address::INET); + BOOST_FOREACH(Address::Family family, family_list) { + bool subscribe_pending; + int instance_id; + uint64_t subscription_gen_id; + BgpTable *table; + if (!VerifyMembership(vrf_name, family, &table, &instance_id, + &subscription_gen_id, &subscribe_pending, add_change)) { + channel_->Close(); return false; } - bool first_nh = true; - for (NextHopListType::const_iterator nit = inh_list.begin(); - nit != inh_list.end(); ++nit, first_nh = false) { - InetTable::RequestData::NextHop nexthop; + DBRequest req; + if (family == Address::INET) { + req.key.reset(new InetTable::RequestKey(inet_prefix, peer_.get())); + } else { + EvpnPrefix evpn_prefix(RouteDistinguisher::kZeroRd, 0, + inet_prefix.addr(), inet_prefix.prefixlen()); + req.key.reset(new EvpnTable::RequestKey(evpn_prefix, peer_.get())); + } - IpAddress nhop_address(Ip4Address(0)); - if (!XmppDecodeAddress(nit->af, nit->address, &nhop_address)) { - BGP_LOG_PEER_INSTANCE_WARNING(Peer(), vrf_name, - BGP_LOG_FLAG_ALL, "Bad nexthop address " << nit->address << - " for inet route " << rt_prefix.ToString()); - return false; - } + IpAddress nh_address(Ip4Address(0)); + uint32_t label = 0; + uint32_t flags = 0; + ExtCommunitySpec ext; + CommunitySpec comm; - if (first_nh) { - nh_address = nhop_address; - label = nit->label; - } + if (add_change) { + req.oper = DBRequest::DB_ENTRY_ADD_CHANGE; + BgpAttrSpec attrs; + + bool first_nh = true; + BgpTable::RequestData::NextHops nexthops; + const NextHopListType &inh_list = item.entry.next_hops; + for (NextHopListType::const_iterator nit = inh_list.begin(); + nit != inh_list.end(); ++nit, first_nh = false) { + BgpTable::RequestData::NextHop nexthop; + + IpAddress nhop_address(Ip4Address(0)); + if (!XmppDecodeAddress(nit->af, nit->address, &nhop_address)) { + BGP_LOG_PEER_INSTANCE_WARNING(Peer(), vrf_name, + BGP_LOG_FLAG_ALL, + "Bad nexthop address " << nit->address << + " for inet route " << inet_prefix.ToString()); + return false; + } + + if (family == Address::EVPN) { + if (nit->vni > 0xFFFFFF) { + BGP_LOG_PEER_INSTANCE_WARNING(Peer(), vrf_name, + BGP_LOG_FLAG_ALL, + "Bad label " << nit->vni << + " for inet route " << inet_prefix.ToString()); + return false; + } + if (!nit->vni) + continue; + if (nit->mac.empty()) + continue; + if (nexthops.empty()) { + MacAddress mac_addr = + MacAddress::FromString(nit->mac, &error); + if (error) { + BGP_LOG_PEER_INSTANCE_WARNING(Peer(), vrf_name, + BGP_LOG_FLAG_ALL, + "Bad next-hop mac address " << nit->mac); + return false; + } + RouterMac router_mac(mac_addr); + ext.communities.push_back( + router_mac.GetExtCommunityValue()); + } + } else { + if (nit->label > 0xFFFFF) { + BGP_LOG_PEER_INSTANCE_WARNING(Peer(), vrf_name, + BGP_LOG_FLAG_ALL, + "Bad label " << nit->vni << + " for inet route " << inet_prefix.ToString()); + return false; + } + if (!nit->label) + continue; + } - // Process tunnel encapsulation list. - bool no_tunnel_encap = true; - bool no_valid_tunnel_encap = true; - for (TunnelEncapsulationListType::const_iterator eit = - nit->tunnel_encapsulation_list.begin(); - eit != nit->tunnel_encapsulation_list.end(); ++eit) { - no_tunnel_encap = false; - TunnelEncap tun_encap(*eit); - if (tun_encap.tunnel_encap() == TunnelEncapType::UNSPEC) - continue; - no_valid_tunnel_encap = false; if (first_nh) { - ext.communities.push_back( - tun_encap.GetExtCommunityValue()); + nh_address = nhop_address; + if (family == Address::INET) { + label = nit->label; + } else { + label = nit->vni; + } } - nexthop.tunnel_encapsulations_.push_back( - tun_encap.GetExtCommunity()); - } - // Mark the path as infeasible if all tunnel encaps published - // by agent are invalid. - if (!no_tunnel_encap && no_valid_tunnel_encap) { - flags = BgpPath::NoTunnelEncap; - } - nexthop.flags_ = flags; - nexthop.address_ = nhop_address; - nexthop.label_ = nit->label; - nexthop.source_rd_ = RouteDistinguisher( - nhop_address.to_v4().to_ulong(), instance_id); - nexthops.push_back(nexthop); - } + // Process tunnel encapsulation list. + bool no_tunnel_encap = true; + bool no_valid_tunnel_encap = true; + for (TunnelEncapsulationListType::const_iterator eit = + nit->tunnel_encapsulation_list.begin(); + eit != nit->tunnel_encapsulation_list.end(); ++eit) { + no_tunnel_encap = false; + TunnelEncap tun_encap(*eit); + if (tun_encap.tunnel_encap() == TunnelEncapType::UNSPEC) + continue; + if (family == Address::INET && + tun_encap.tunnel_encap() == TunnelEncapType::VXLAN) { + continue; + } + if (family == Address::EVPN && + tun_encap.tunnel_encap() != TunnelEncapType::VXLAN) { + continue; + } + no_valid_tunnel_encap = false; + if (first_nh) { + ext.communities.push_back( + tun_encap.GetExtCommunityValue()); + } + nexthop.tunnel_encapsulations_.push_back( + tun_encap.GetExtCommunity()); + } - BgpAttrLocalPref local_pref(item.entry.local_preference); - if (local_pref.local_pref != 0) - attrs.push_back(&local_pref); + // Mark the path as infeasible if all tunnel encaps published + // by agent are invalid. + if (!no_tunnel_encap && no_valid_tunnel_encap) { + flags = BgpPath::NoTunnelEncap; + } - // If there's no explicit med, calculate it automatically from the - // local pref. - uint32_t med_value = item.entry.med; - if (!med_value) - med_value = GetMedFromLocalPref(local_pref.local_pref); - BgpAttrMultiExitDisc med(med_value); - if (med.med != 0) - attrs.push_back(&med); + nexthop.flags_ = flags; + nexthop.address_ = nhop_address; + nexthop.label_ = + family == Address::INET ? nit->label : nit->vni; + nexthop.source_rd_ = RouteDistinguisher( + nhop_address.to_v4().to_ulong(), instance_id); + nexthops.push_back(nexthop); + } - // Process community tags - const CommunityTagListType &ict_list = item.entry.community_tag_list; - for (CommunityTagListType::const_iterator cit = ict_list.begin(); - cit != ict_list.end(); ++cit) { - error_code error; - uint32_t rt_community = - CommunityType::CommunityFromString(*cit, &error); - if (error) + // Skip if there are no valid next hops for the inet/evpn route. + if (nexthops.empty()) continue; - comm.communities.push_back(rt_community); - } - BgpAttrNextHop nexthop(nh_address.to_v4().to_ulong()); - attrs.push_back(&nexthop); + BgpAttrLocalPref local_pref(item.entry.local_preference); + if (local_pref.local_pref != 0) + attrs.push_back(&local_pref); + + // If there's no explicit med, calculate it automatically from the + // local pref. + uint32_t med_value = item.entry.med; + if (!med_value) + med_value = GetMedFromLocalPref(local_pref.local_pref); + BgpAttrMultiExitDisc med(med_value); + if (med.med != 0) + attrs.push_back(&med); + + // Process community tags + const CommunityTagListType &ict_list = + item.entry.community_tag_list; + for (CommunityTagListType::const_iterator cit = ict_list.begin(); + cit != ict_list.end(); ++cit) { + error_code error; + uint32_t rt_community = + CommunityType::CommunityFromString(*cit, &error); + if (error) + continue; + comm.communities.push_back(rt_community); + } - BgpAttrSourceRd source_rd( - RouteDistinguisher(nh_address.to_v4().to_ulong(), instance_id)); - attrs.push_back(&source_rd); + BgpAttrNextHop nexthop(nh_address.to_v4().to_ulong()); + attrs.push_back(&nexthop); - // Process security group list. - const SecurityGroupListType &isg_list = item.entry.security_group_list; - for (SecurityGroupListType::const_iterator sit = isg_list.begin(); - sit != isg_list.end(); ++sit) { - SecurityGroup sg(bgp_server_->autonomous_system(), *sit); - ext.communities.push_back(sg.GetExtCommunityValue()); - } + BgpAttrSourceRd source_rd( + RouteDistinguisher(nh_address.to_v4().to_ulong(), instance_id)); + attrs.push_back(&source_rd); - if (item.entry.sequence_number) { - MacMobility mm(item.entry.sequence_number); - ext.communities.push_back(mm.GetExtCommunityValue()); - } + // Process security group list. + const SecurityGroupListType &isg_list = + item.entry.security_group_list; + for (SecurityGroupListType::const_iterator sit = isg_list.begin(); + sit != isg_list.end(); ++sit) { + SecurityGroup sg(bgp_server_->autonomous_system(), *sit); + ext.communities.push_back(sg.GetExtCommunityValue()); + } - // Process load-balance extended community - LoadBalance load_balance(item.entry.load_balance); - if (!load_balance.IsDefault()) - ext.communities.push_back(load_balance.GetExtCommunityValue()); + if (item.entry.sequence_number) { + MacMobility mm(item.entry.sequence_number); + ext.communities.push_back(mm.GetExtCommunityValue()); + } - if (!comm.communities.empty()) - attrs.push_back(&comm); + // Process load-balance extended community. + LoadBalance load_balance(item.entry.load_balance); + if (!load_balance.IsDefault()) + ext.communities.push_back(load_balance.GetExtCommunityValue()); - if (!ext.communities.empty()) - attrs.push_back(&ext); + if (!comm.communities.empty()) + attrs.push_back(&comm); + if (!ext.communities.empty()) + attrs.push_back(&ext); - BgpAttrPtr attr = bgp_server_->attr_db()->Locate(attrs); + BgpAttrPtr attr = bgp_server_->attr_db()->Locate(attrs); + req.data.reset(new BgpTable::RequestData(attr, nexthops, + subscription_gen_id)); + } else { + req.oper = DBRequest::DB_ENTRY_DELETE; + } - req.data.reset(new InetTable::RequestData(attr, nexthops, - subscription_gen_id)); + // Defer all requests till subscribe is processed. + if (subscribe_pending) { + DBRequest *request_entry = new DBRequest(); + request_entry->Swap(&req); + string table_name = + RoutingInstance::GetTableName(vrf_name, family); + defer_q_.insert(make_pair( + make_pair(vrf_name, table_name), request_entry)); + continue; + } + + assert(table); + BGP_LOG_PEER_INSTANCE(Peer(), vrf_name, + SandeshLevel::SYS_DEBUG, BGP_LOG_FLAG_TRACE, + "Inet route " << item.entry.nlri.address << + " with next-hop " << nh_address << " and label " << label << + " enqueued for " << (add_change ? "add/change" : "delete") << + " to table " << table->name()); + table->Enqueue(&req); + } + + if (add_change) { stats_[RX].reach++; } else { - req.oper = DBRequest::DB_ENTRY_DELETE; stats_[RX].unreach++; } - // Defer all requests till subscribe is processed. - if (subscribe_pending) { - DBRequest *request_entry = new DBRequest(); - request_entry->Swap(&req); - string table_name = - RoutingInstance::GetTableName(vrf_name, Address::INET); - defer_q_.insert(make_pair( - make_pair(vrf_name, table_name), request_entry)); - return true; - } - - assert(table); - BGP_LOG_PEER_INSTANCE(Peer(), vrf_name, - SandeshLevel::SYS_DEBUG, BGP_LOG_FLAG_TRACE, - "Inet route " << item.entry.nlri.address << - " with next-hop " << nh_address << " and label " << label << - " enqueued for " << (add_change ? "add/change" : "delete")); - table->Enqueue(&req); return true; } @@ -1114,7 +1189,7 @@ bool BgpXmppChannel::ProcessInet6Item(string vrf_name, } error_code error; - Inet6Prefix rt_prefix = + Inet6Prefix inet6_prefix = Inet6Prefix::FromString(item.entry.nlri.address, &error); if (error) { error_stats().incr_inet6_rx_bad_prefix_count(); @@ -1123,175 +1198,244 @@ bool BgpXmppChannel::ProcessInet6Item(string vrf_name, return false; } - bool subscribe_pending; - int instance_id; - uint64_t subscription_gen_id; - BgpTable *table; - if (!VerifyMembership(vrf_name, Address::INET6, &table, &instance_id, - &subscription_gen_id, &subscribe_pending, add_change)) { - channel_->Close(); + if (add_change && item.entry.next_hops.next_hop.empty()) { + BGP_LOG_PEER_INSTANCE_WARNING(Peer(), vrf_name, BGP_LOG_FLAG_ALL, + "Missing next-hops for inet6 route " << inet6_prefix.ToString()); return false; } - Inet6Table::RequestData::NextHops nexthops; - DBRequest req; - req.key.reset(new Inet6Table::RequestKey(rt_prefix, peer_.get())); - - IpAddress nh_address(Ip4Address(0)); - uint32_t label = 0; - uint32_t flags = 0; - ExtCommunitySpec ext; - CommunitySpec comm; - - if (add_change) { - req.oper = DBRequest::DB_ENTRY_ADD_CHANGE; - BgpAttrSpec attrs; - const NextHopListType &inh_list = item.entry.next_hops; - - if (inh_list.next_hop.empty()) { - BGP_LOG_PEER_INSTANCE_WARNING(Peer(), vrf_name, BGP_LOG_FLAG_ALL, - "Missing next-hops for inet6 route " << rt_prefix.ToString()); + // vector family_list = list_of(Address::INET6)(Address::EVPN); + vector family_list = list_of(Address::INET6); + BOOST_FOREACH(Address::Family family, family_list) { + bool subscribe_pending; + int instance_id; + uint64_t subscription_gen_id; + BgpTable *table; + if (!VerifyMembership(vrf_name, family, &table, &instance_id, + &subscription_gen_id, &subscribe_pending, add_change)) { + channel_->Close(); return false; } - bool first_nh = true; - for (NextHopListType::const_iterator nit = inh_list.begin(); - nit != inh_list.end(); ++nit, first_nh = false) { - Inet6Table::RequestData::NextHop nexthop; + DBRequest req; + if (family == Address::INET6) { + req.key.reset(new Inet6Table::RequestKey(inet6_prefix, peer_.get())); + } else { + EvpnPrefix evpn_prefix(RouteDistinguisher::kZeroRd, 0, + inet6_prefix.addr(), inet6_prefix.prefixlen()); + req.key.reset(new EvpnTable::RequestKey(evpn_prefix, peer_.get())); + } - IpAddress nhop_address(Ip4Address(0)); - if (!XmppDecodeAddress(nit->af, nit->address, &nhop_address)) { - error_stats().incr_inet6_rx_bad_nexthop_count(); - BGP_LOG_PEER_INSTANCE_WARNING(Peer(), vrf_name, - BGP_LOG_FLAG_ALL, "Bad nexthop address " << nit->address << - " for inet6 route " << rt_prefix.ToString()); - return false; - } + IpAddress nh_address(Ip4Address(0)); + uint32_t label = 0; + uint32_t flags = 0; + ExtCommunitySpec ext; + CommunitySpec comm; - if (first_nh) { - nh_address = nhop_address; - label = nit->label; - } + if (add_change) { + req.oper = DBRequest::DB_ENTRY_ADD_CHANGE; + BgpAttrSpec attrs; + + bool first_nh = true; + BgpTable::RequestData::NextHops nexthops; + const NextHopListType &inh_list = item.entry.next_hops; + for (NextHopListType::const_iterator nit = inh_list.begin(); + nit != inh_list.end(); ++nit, first_nh = false) { + BgpTable::RequestData::NextHop nexthop; + + IpAddress nhop_address(Ip4Address(0)); + if (!XmppDecodeAddress(nit->af, nit->address, &nhop_address)) { + error_stats().incr_inet6_rx_bad_nexthop_count(); + BGP_LOG_PEER_INSTANCE_WARNING(Peer(), vrf_name, + BGP_LOG_FLAG_ALL, + "Bad nexthop address " << nit->address << + " for inet6 route " << inet6_prefix.ToString()); + return false; + } - // Process tunnel encapsulation list. - bool no_tunnel_encap = true; - bool no_valid_tunnel_encap = true; - for (TunnelEncapsulationListType::const_iterator eit = - nit->tunnel_encapsulation_list.begin(); - eit != nit->tunnel_encapsulation_list.end(); ++eit) { - no_tunnel_encap = false; - TunnelEncap tun_encap(*eit); - if (tun_encap.tunnel_encap() == TunnelEncapType::UNSPEC) - continue; - no_valid_tunnel_encap = false; - if (first_nh) { - ext.communities.push_back( - tun_encap.GetExtCommunityValue()); + if (family == Address::EVPN) { + if (nit->vni > 0xFFFFFF) { + BGP_LOG_PEER_INSTANCE_WARNING(Peer(), vrf_name, + BGP_LOG_FLAG_ALL, + "Bad label " << nit->vni << + " for inet6 route " << inet6_prefix.ToString()); + return false; + } + if (!nit->vni) + continue; + if (nit->mac.empty()) + continue; + if (nexthops.empty()) { + MacAddress mac_addr = + MacAddress::FromString(nit->mac, &error); + if (error) { + BGP_LOG_PEER_INSTANCE_WARNING(Peer(), vrf_name, + BGP_LOG_FLAG_ALL, + "Bad next-hop mac address " << nit->mac); + return false; + } + RouterMac router_mac(mac_addr); + ext.communities.push_back( + router_mac.GetExtCommunityValue()); + } + } else { + if (nit->label > 0xFFFFF) { + BGP_LOG_PEER_INSTANCE_WARNING(Peer(), vrf_name, + BGP_LOG_FLAG_ALL, + "Bad label " << nit->vni << + " for inet6 route " << inet6_prefix.ToString()); + return false; + } + if (!nit->label) + continue; } - nexthop.tunnel_encapsulations_.push_back( - tun_encap.GetExtCommunity()); - } - // Mark the path as infeasible if all tunnel encaps published - // by agent are invalid. - if (!no_tunnel_encap && no_valid_tunnel_encap) { - flags = BgpPath::NoTunnelEncap; - } + if (first_nh) { + nh_address = nhop_address; + if (family == Address::INET6) { + label = nit->label; + } else { + label = nit->vni; + } + } - nexthop.flags_ = flags; - nexthop.address_ = nhop_address; - nexthop.label_ = nit->label; - nexthop.source_rd_ = RouteDistinguisher( - nhop_address.to_v4().to_ulong(), instance_id); - nexthops.push_back(nexthop); - } + // Process tunnel encapsulation list. + bool no_tunnel_encap = true; + bool no_valid_tunnel_encap = true; + for (TunnelEncapsulationListType::const_iterator eit = + nit->tunnel_encapsulation_list.begin(); + eit != nit->tunnel_encapsulation_list.end(); ++eit) { + no_tunnel_encap = false; + TunnelEncap tun_encap(*eit); + if (tun_encap.tunnel_encap() == TunnelEncapType::UNSPEC) + continue; + if (family == Address::INET6 && + tun_encap.tunnel_encap() == TunnelEncapType::VXLAN) { + continue; + } + if (family == Address::EVPN && + tun_encap.tunnel_encap() != TunnelEncapType::VXLAN) { + continue; + } + no_valid_tunnel_encap = false; + if (first_nh) { + ext.communities.push_back( + tun_encap.GetExtCommunityValue()); + } + nexthop.tunnel_encapsulations_.push_back( + tun_encap.GetExtCommunity()); + } - BgpAttrLocalPref local_pref(item.entry.local_preference); - if (local_pref.local_pref != 0) { - attrs.push_back(&local_pref); - } + // Mark the path as infeasible if all tunnel encaps published + // by agent are invalid. + if (!no_tunnel_encap && no_valid_tunnel_encap) { + flags = BgpPath::NoTunnelEncap; + } - // If there's no explicit med, calculate it automatically from the - // local pref. - uint32_t med_value = item.entry.med; - if (!med_value) - med_value = GetMedFromLocalPref(local_pref.local_pref); - BgpAttrMultiExitDisc med(med_value); - if (med.med != 0) - attrs.push_back(&med); + nexthop.flags_ = flags; + nexthop.address_ = nhop_address; + nexthop.label_ = + family == Address::INET6 ? nit->label : nit->vni; + nexthop.source_rd_ = RouteDistinguisher( + nhop_address.to_v4().to_ulong(), instance_id); + nexthops.push_back(nexthop); + } - // Process community tags - const CommunityTagListType &ict_list = item.entry.community_tag_list; - for (CommunityTagListType::const_iterator cit = ict_list.begin(); - cit != ict_list.end(); ++cit) { - error_code error; - uint32_t rt_community = - CommunityType::CommunityFromString(*cit, &error); - if (error) + // Skip if there are no valid next hops for the inet6/evpn route. + if (nexthops.empty()) continue; - comm.communities.push_back(rt_community); - } - BgpAttrNextHop nexthop(nh_address.to_v4().to_ulong()); - attrs.push_back(&nexthop); + BgpAttrLocalPref local_pref(item.entry.local_preference); + if (local_pref.local_pref != 0) + attrs.push_back(&local_pref); + + // If there's no explicit med, calculate it automatically from the + // local pref. + uint32_t med_value = item.entry.med; + if (!med_value) + med_value = GetMedFromLocalPref(local_pref.local_pref); + BgpAttrMultiExitDisc med(med_value); + if (med.med != 0) + attrs.push_back(&med); + + // Process community tags + const CommunityTagListType &ict_list = + item.entry.community_tag_list; + for (CommunityTagListType::const_iterator cit = ict_list.begin(); + cit != ict_list.end(); ++cit) { + error_code error; + uint32_t rt_community = + CommunityType::CommunityFromString(*cit, &error); + if (error) + continue; + comm.communities.push_back(rt_community); + } - BgpAttrSourceRd source_rd( - RouteDistinguisher(nh_address.to_v4().to_ulong(), instance_id)); - attrs.push_back(&source_rd); + BgpAttrNextHop nexthop(nh_address.to_v4().to_ulong()); + attrs.push_back(&nexthop); - // Process security group list. - const SecurityGroupListType &isg_list = item.entry.security_group_list; - for (SecurityGroupListType::const_iterator sit = isg_list.begin(); - sit != isg_list.end(); ++sit) { - SecurityGroup sg(bgp_server_->autonomous_system(), *sit); - ext.communities.push_back(sg.GetExtCommunityValue()); - } + BgpAttrSourceRd source_rd( + RouteDistinguisher(nh_address.to_v4().to_ulong(), instance_id)); + attrs.push_back(&source_rd); - if (item.entry.sequence_number) { - MacMobility mm(item.entry.sequence_number); - ext.communities.push_back(mm.GetExtCommunityValue()); - } + // Process security group list. + const SecurityGroupListType &isg_list = + item.entry.security_group_list; + for (SecurityGroupListType::const_iterator sit = isg_list.begin(); + sit != isg_list.end(); ++sit) { + SecurityGroup sg(bgp_server_->autonomous_system(), *sit); + ext.communities.push_back(sg.GetExtCommunityValue()); + } - // Process load-balance extended community - LoadBalance load_balance(item.entry.load_balance); - if (!load_balance.IsDefault()) - ext.communities.push_back(load_balance.GetExtCommunityValue()); + if (item.entry.sequence_number) { + MacMobility mm(item.entry.sequence_number); + ext.communities.push_back(mm.GetExtCommunityValue()); + } - if (!comm.communities.empty()) - attrs.push_back(&comm); + // Process load-balance extended community. + LoadBalance load_balance(item.entry.load_balance); + if (!load_balance.IsDefault()) + ext.communities.push_back(load_balance.GetExtCommunityValue()); - if (!ext.communities.empty()) { - attrs.push_back(&ext); + if (!comm.communities.empty()) + attrs.push_back(&comm); + if (!ext.communities.empty()) + attrs.push_back(&ext); + + BgpAttrPtr attr = bgp_server_->attr_db()->Locate(attrs); + req.data.reset(new BgpTable::RequestData(attr, nexthops, + subscription_gen_id)); + } else { + req.oper = DBRequest::DB_ENTRY_DELETE; } - BgpAttrPtr attr = bgp_server_->attr_db()->Locate(attrs); + // Defer all requests till subscribe is processed. + if (subscribe_pending) { + DBRequest *request_entry = new DBRequest(); + request_entry->Swap(&req); + string table_name = + RoutingInstance::GetTableName(vrf_name, family); + defer_q_.insert(make_pair( + make_pair(vrf_name, table_name), request_entry)); + continue; + } - req.data.reset(new Inet6Table::RequestData(attr, nexthops, - subscription_gen_id)); + assert(table); + BGP_LOG_PEER_INSTANCE(Peer(), vrf_name, + SandeshLevel::SYS_DEBUG, BGP_LOG_FLAG_TRACE, + "Inet6 route " << item.entry.nlri.address << + " with next-hop " << nh_address << " and label " << label << + " enqueued for " << (add_change ? "add/change" : "delete") << + " to table " << table->name()); + table->Enqueue(&req); + } + + if (add_change) { stats_[RX].reach++; } else { - req.oper = DBRequest::DB_ENTRY_DELETE; stats_[RX].unreach++; } - // Defer all requests till subscribe is processed. - if (subscribe_pending) { - DBRequest *request_entry = new DBRequest(); - request_entry->Swap(&req); - string table_name = - RoutingInstance::GetTableName(vrf_name, Address::INET6); - defer_q_.insert(make_pair( - make_pair(vrf_name, table_name), request_entry)); - return true; - } - - assert(table); - BGP_LOG_PEER_INSTANCE(Peer(), vrf_name, - SandeshLevel::SYS_DEBUG, BGP_LOG_FLAG_TRACE, - "Inet6 route " << item.entry.nlri.address << - " with next-hop " << nh_address << " and label " << label << - " enqueued for " << (add_change ? "add/change" : "delete")); - table->Enqueue(&req); return true; } @@ -2195,7 +2339,7 @@ bool BgpXmppChannel::EndOfRibReceiveTimerExpired() { BGP_LOG_PEER(Message, Peer(), SandeshLevel::SYS_INFO, BGP_LOG_FLAG_ALL, BGP_PEER_DIR_IN, "EndOfRib Receive timer rescheduled to fire after " << - kEndOfRibSendRetryTimeMsecs << "milliseconds "); + kEndOfRibSendRetryTimeMsecs << " milliseconds "); return true; } } diff --git a/src/bgp/evpn/evpn_table.cc b/src/bgp/evpn/evpn_table.cc index e79b6ede8e5..648aa85cd0e 100644 --- a/src/bgp/evpn/evpn_table.cc +++ b/src/bgp/evpn/evpn_table.cc @@ -9,6 +9,8 @@ #include "bgp/bgp_evpn.h" #include "bgp/bgp_server.h" #include "bgp/bgp_update.h" +#include "bgp/inet/inet_table.h" +#include "bgp/inet6/inet6_table.h" #include "bgp/origin-vn/origin_vn.h" #include "bgp/routing-instance/routing_instance.h" @@ -16,14 +18,21 @@ using std::auto_ptr; using std::string; size_t EvpnTable::HashFunction(const EvpnPrefix &prefix) { - if (prefix.type() != EvpnPrefix::MacAdvertisementRoute) - return 0; - if (prefix.mac_addr().IsBroadcast()) - return 0; - - const uint8_t *data = prefix.mac_addr().GetData(); - uint32_t value = get_value(data + 2, 4); - return boost::hash_value(value); + if (prefix.type() == EvpnPrefix::MacAdvertisementRoute) { + if (prefix.mac_addr().IsBroadcast()) + return 0; + const uint8_t *data = prefix.mac_addr().GetData(); + uint32_t value = get_value(data + 2, 4); + return boost::hash_value(value); + } + if (prefix.type() == EvpnPrefix::IpPrefixRoute) { + if (prefix.ip_address().is_v4()) { + return InetTable::HashFunction(prefix.inet_prefix()); + } else { + return Inet6Table::HashFunction(prefix.inet6_prefix()); + } + } + return 0; } EvpnTable::EvpnTable(DB *db, const string &name) @@ -115,8 +124,11 @@ BgpRoute *EvpnTable::RouteReplicate(BgpServer *server, BgpTable *src_table, BgpRoute *src_rt, const BgpPath *src_path, ExtCommunityPtr community) { assert(src_table->family() == Address::EVPN); + EvpnRoute *evpn_rt = dynamic_cast(src_rt); + assert(evpn_rt); + EvpnPrefix evpn_prefix(evpn_rt->GetPrefix()); - if (!IsMaster()) { + if (!IsMaster() && evpn_prefix.type() != EvpnPrefix::IpPrefixRoute) { // Don't replicate to a VRF from other VRF tables. EvpnTable *src_evpn_table = dynamic_cast(src_table); if (!src_evpn_table->IsMaster()) @@ -129,15 +141,10 @@ BgpRoute *EvpnTable::RouteReplicate(BgpServer *server, return NULL; } - EvpnRoute *evpn_rt = dynamic_cast(src_rt); - assert(evpn_rt); - EvpnPrefix evpn_prefix(evpn_rt->GetPrefix()); if (evpn_prefix.type() == EvpnPrefix::AutoDiscoveryRoute) return NULL; if (evpn_prefix.type() == EvpnPrefix::SegmentRoute) return NULL; - if (evpn_prefix.type() == EvpnPrefix::IpPrefixRoute) - return NULL; if (evpn_prefix.type() == EvpnPrefix::MacAdvertisementRoute && evpn_prefix.mac_addr().IsBroadcast()) return NULL; @@ -150,12 +157,16 @@ BgpRoute *EvpnTable::RouteReplicate(BgpServer *server, evpn_prefix.set_route_distinguisher(new_attr->source_rd()); } - Ip4Address originator_id = new_attr->nexthop().to_v4(); - new_attr = attr_db->ReplaceOriginatorIdAndLocate( - new_attr.get(), originator_id); + if (evpn_prefix.type() != EvpnPrefix::IpPrefixRoute) { + Ip4Address originator_id = new_attr->nexthop().to_v4(); + new_attr = attr_db->ReplaceOriginatorIdAndLocate( + new_attr.get(), originator_id); + } } else { - if (evpn_prefix.type() == EvpnPrefix::MacAdvertisementRoute) + if (evpn_prefix.type() == EvpnPrefix::MacAdvertisementRoute || + evpn_prefix.type() == EvpnPrefix::IpPrefixRoute) { evpn_prefix.set_route_distinguisher(RouteDistinguisher::kZeroRd); + } } EvpnRoute rt_key(evpn_prefix); diff --git a/src/bgp/evpn/test/evpn_table_test.cc b/src/bgp/evpn/test/evpn_table_test.cc index c27b7b83c5e..e0fa695e11e 100644 --- a/src/bgp/evpn/test/evpn_table_test.cc +++ b/src/bgp/evpn/test/evpn_table_test.cc @@ -1381,6 +1381,576 @@ TEST_F(EvpnTableSegmentTest, ReplicateRouteToVPN) { TASK_UTIL_EXPECT_EQ(0, master_->Size()); } +class EvpnTableIpPrefixTest : public EvpnTableTest { +}; + +TEST_F(EvpnTableIpPrefixTest, AllocEntryStr1) { + string prefix_str("5-10.1.1.1:65535-0-192.168.1.1/32"); + auto_ptr route = master_->AllocEntryStr(prefix_str); + EXPECT_EQ(prefix_str, route->ToString()); +} + +TEST_F(EvpnTableIpPrefixTest, AllocEntryStr2) { + string prefix_str("5-10.1.1.1:65535-0-192.168.1.0/24"); + auto_ptr route = master_->AllocEntryStr(prefix_str); + EXPECT_EQ(prefix_str, route->ToString()); +} + +TEST_F(EvpnTableIpPrefixTest, AllocEntryStr3) { + string prefix_str("5-10.1.1.1:65535-0-2001:db8:0:9::1/128"); + auto_ptr route = master_->AllocEntryStr(prefix_str); + EXPECT_EQ(prefix_str, route->ToString()); +} + +TEST_F(EvpnTableIpPrefixTest, AllocEntryStr4) { + string prefix_str("5-10.1.1.1:65535-0-2001:db8:0:9::/120"); + auto_ptr route = master_->AllocEntryStr(prefix_str); + EXPECT_EQ(prefix_str, route->ToString()); +} + +TEST_F(EvpnTableIpPrefixTest, AddDeleteSingleRoute1) { + ostringstream repr; + repr << "5-10.1.1.1:65535-0-192.168.1.1/32"; + AddRoute(master_, repr.str()); + task_util::WaitForIdle(); + VerifyRouteExists(master_, repr.str()); + TASK_UTIL_EXPECT_EQ(adc_notification_, 1); + + DelRoute(master_, repr.str()); + task_util::WaitForIdle(); + TASK_UTIL_EXPECT_EQ(del_notification_, 1); + VerifyRouteNoExists(master_, repr.str()); +} + +TEST_F(EvpnTableIpPrefixTest, AddDeleteSingleRoute2) { + ostringstream repr; + repr << "5-10.1.1.1:65535-0-2001:db8:0:9::1/128"; + AddRoute(master_, repr.str()); + task_util::WaitForIdle(); + VerifyRouteExists(master_, repr.str()); + TASK_UTIL_EXPECT_EQ(adc_notification_, 1); + + DelRoute(master_, repr.str()); + task_util::WaitForIdle(); + TASK_UTIL_EXPECT_EQ(del_notification_, 1); + VerifyRouteNoExists(master_, repr.str()); +} + +// Prefixes differ only in the IP address field of the RD. +TEST_F(EvpnTableIpPrefixTest, AddDeleteMultipleRoute1) { + for (int idx = 1; idx <= kRouteCount; idx++) { + ostringstream repr; + repr << "5-10.1.1." << idx << ":65535-"; + repr << "0-192.168.1.1/32"; + AddRoute(master_, repr.str()); + } + task_util::WaitForIdle(); + + for (int idx = 1; idx <= kRouteCount; idx++) { + ostringstream repr; + repr << "5-10.1.1." << idx << ":65535-"; + repr << "0-192.168.1.1/32"; + VerifyRouteExists(master_, repr.str()); + } + TASK_UTIL_EXPECT_EQ(adc_notification_, kRouteCount); + + for (int idx = 1; idx <= kRouteCount; idx++) { + ostringstream repr; + repr << "5-10.1.1." << idx << ":65535-"; + repr << "0-192.168.1.1/32"; + DelRoute(master_, repr.str()); + } + task_util::WaitForIdle(); + + for (int idx = 1; idx <= kRouteCount; idx++) { + ostringstream repr; + repr << "5-10.1.1." << idx << ":65535-"; + repr << "0-192.168.1.1/32"; + VerifyRouteNoExists(master_, repr.str()); + } + TASK_UTIL_EXPECT_EQ(del_notification_, kRouteCount); +} + +// Prefixes differ only in the address field (ipv4) of the prefix. +TEST_F(EvpnTableIpPrefixTest, AddDeleteMultipleRoute2) { + for (int idx = 1; idx <= kRouteCount; idx++) { + ostringstream repr; + repr << "5-10.1.1.1:65535-"; + repr << "0-192.168.1." << idx << "/32"; + AddRoute(master_, repr.str()); + } + task_util::WaitForIdle(); + + for (int idx = 1; idx <= kRouteCount; idx++) { + ostringstream repr; + repr << "5-10.1.1.1:65535-"; + repr << "0-192.168.1." << idx << "/32"; + VerifyRouteExists(master_, repr.str()); + } + TASK_UTIL_EXPECT_EQ(adc_notification_, kRouteCount); + + for (int idx = 1; idx <= kRouteCount; idx++) { + ostringstream repr; + repr << "5-10.1.1.1:65535-"; + repr << "0-192.168.1." << idx << "/32"; + DelRoute(master_, repr.str()); + } + task_util::WaitForIdle(); + + for (int idx = 1; idx <= kRouteCount; idx++) { + ostringstream repr; + repr << "5-10.1.1.1:65535-"; + repr << "0-192.168.1." << idx << "/32"; + VerifyRouteNoExists(master_, repr.str()); + } + TASK_UTIL_EXPECT_EQ(del_notification_, kRouteCount); +} + +// Prefixes differ only in the address field (ipv6) of the prefix. +TEST_F(EvpnTableIpPrefixTest, AddDeleteMultipleRoute3) { + for (int idx = 1; idx <= kRouteCount; idx++) { + ostringstream repr; + repr << "5-10.1.1.1:65535-"; + repr << "0-2001:db8:0:9::" << idx << "/128"; + AddRoute(master_, repr.str()); + } + task_util::WaitForIdle(); + + for (int idx = 1; idx <= kRouteCount; idx++) { + ostringstream repr; + repr << "5-10.1.1.1:65535-"; + repr << "0-2001:db8:0:9::" << idx << "/128"; + VerifyRouteExists(master_, repr.str()); + } + TASK_UTIL_EXPECT_EQ(adc_notification_, kRouteCount); + + for (int idx = 1; idx <= kRouteCount; idx++) { + ostringstream repr; + repr << "5-10.1.1.1:65535-"; + repr << "0-2001:db8:0:9::" << idx << "/128"; + DelRoute(master_, repr.str()); + } + task_util::WaitForIdle(); + + for (int idx = 1; idx <= kRouteCount; idx++) { + ostringstream repr; + repr << "5-10.1.1.1:65535-"; + repr << "0-2001:db8:0:9::" << idx << "/128"; + VerifyRouteNoExists(master_, repr.str()); + } + TASK_UTIL_EXPECT_EQ(del_notification_, kRouteCount); +} + +TEST_F(EvpnTableIpPrefixTest, Hashing1) { + for (int idx = 1; idx <= kRouteCount; idx++) { + ostringstream repr; + repr << "5-10.1.1.1:65535-"; + repr << "0-192.168.1." << idx << "/32"; + AddRoute(master_, repr.str()); + } + task_util::WaitForIdle(); + + VerifyTablePartitionNonEmpty(master_, 0, DB::PartitionCount()); + + for (int idx = 1; idx <= kRouteCount; idx++) { + ostringstream repr; + repr << "5-10.1.1.1:65535-"; + repr << "0-192.168.1." << idx << "/32"; + DelRoute(master_, repr.str()); + } + task_util::WaitForIdle(); +} + +TEST_F(EvpnTableIpPrefixTest, Hashing2) { + for (int idx = 1; idx <= kRouteCount; idx++) { + ostringstream repr; + repr << "5-10.1.1.1:65535-"; + repr << "0-2001:db8:0:9::" << hex << idx << "/128"; + AddRoute(master_, repr.str()); + } + task_util::WaitForIdle(); + + VerifyTablePartitionNonEmpty(master_, 0, DB::PartitionCount()); + + for (int idx = 1; idx <= kRouteCount; idx++) { + ostringstream repr; + repr << "5-10.1.1.1:65535-"; + repr << "0-2001:db8:0:9::" << hex << idx << "/128"; + DelRoute(master_, repr.str()); + } + task_util::WaitForIdle(); +} + +// +// Basic - RD in VRF is zero w/ inet prefix. +// +TEST_F(EvpnTableIpPrefixTest, ReplicateRouteFromVPN1) { + ostringstream repr1, repr2; + repr1 << "5-10.1.1.1:65535-0-192.168.1.1/32"; + repr2 << "5-0:0-0-192.168.1.1/32"; + AddRoute(master_, repr1.str(), "target:64512:1"); + task_util::WaitForIdle(); + VerifyRouteExists(master_, repr1.str()); + TASK_UTIL_EXPECT_EQ(1, master_->Size()); + VerifyRouteExists(blue_, repr2.str()); + TASK_UTIL_EXPECT_EQ(1, blue_->Size()); + + DelRoute(master_, repr1.str()); + task_util::WaitForIdle(); + VerifyRouteNoExists(master_, repr1.str()); + TASK_UTIL_EXPECT_EQ(0, master_->Size()); + VerifyRouteNoExists(blue_, repr2.str()); + TASK_UTIL_EXPECT_EQ(0, blue_->Size()); +} + +// +// Basic - RD in VRF is zero w/ inet6 prefix. +// +TEST_F(EvpnTableIpPrefixTest, ReplicateRouteFromVPN2) { + ostringstream repr1, repr2; + repr1 << "5-10.1.1.1:65535-0-2001:db8:0:9::1/32"; + repr2 << "5-0:0-0-2001:db8:0:9::1/32"; + AddRoute(master_, repr1.str(), "target:64512:1"); + task_util::WaitForIdle(); + VerifyRouteExists(master_, repr1.str()); + TASK_UTIL_EXPECT_EQ(1, master_->Size()); + VerifyRouteExists(blue_, repr2.str()); + TASK_UTIL_EXPECT_EQ(1, blue_->Size()); + + DelRoute(master_, repr1.str()); + task_util::WaitForIdle(); + VerifyRouteNoExists(master_, repr1.str()); + TASK_UTIL_EXPECT_EQ(0, master_->Size()); + VerifyRouteNoExists(blue_, repr2.str()); + TASK_UTIL_EXPECT_EQ(0, blue_->Size()); +} + +// +// Different RDs result in different paths for same route in VRF w/ v4 prefix. +// +TEST_F(EvpnTableIpPrefixTest, ReplicateRouteFromVPN3) { + ostringstream repr2; + repr2 << "5-0:0-0-192.168.1.1/32"; + + for (int idx = 1; idx <= kRouteCount; idx++) { + ostringstream repr1; + repr1 << "5-10.1.1." << idx << ":65535-0-192.168.1.1/32"; + AddRoute(master_, repr1.str(), "target:64512:1"); + task_util::WaitForIdle(); + VerifyRouteExists(master_, repr1.str()); + VerifyRouteExists(blue_, repr2.str(), idx); + } + TASK_UTIL_EXPECT_EQ(kRouteCount, master_->Size()); + TASK_UTIL_EXPECT_EQ(1, blue_->Size()); + + for (int idx = 1; idx <= kRouteCount; idx++) { + ostringstream repr1; + repr1 << "5-10.1.1." << idx << ":65535-0-192.168.1.1/32"; + DelRoute(master_, repr1.str()); + task_util::WaitForIdle(); + VerifyRouteNoExists(master_, repr1.str()); + if (idx == kRouteCount) { + VerifyRouteNoExists(blue_, repr2.str()); + } else { + VerifyRouteExists(blue_, repr2.str(), kRouteCount - idx); + } + } + + TASK_UTIL_EXPECT_EQ(0, blue_->Size()); + TASK_UTIL_EXPECT_EQ(0, master_->Size()); +} + +// +// Different RDs result in different paths for same route in VRF w/ v6 prefix. +// +TEST_F(EvpnTableIpPrefixTest, ReplicateRouteFromVPN4) { + ostringstream repr2; + repr2 << "5-0:0-0-2001:db8:0:9::1/32"; + + for (int idx = 1; idx <= kRouteCount; idx++) { + ostringstream repr1; + repr1 << "5-10.1.1." << idx << ":65535-0-2001:db8:0:9::1/32"; + AddRoute(master_, repr1.str(), "target:64512:1"); + task_util::WaitForIdle(); + VerifyRouteExists(master_, repr1.str()); + VerifyRouteExists(blue_, repr2.str(), idx); + } + TASK_UTIL_EXPECT_EQ(kRouteCount, master_->Size()); + TASK_UTIL_EXPECT_EQ(1, blue_->Size()); + + for (int idx = 1; idx <= kRouteCount; idx++) { + ostringstream repr1; + repr1 << "5-10.1.1." << idx << ":65535-0-2001:db8:0:9::1/32"; + DelRoute(master_, repr1.str()); + task_util::WaitForIdle(); + VerifyRouteNoExists(master_, repr1.str()); + if (idx == kRouteCount) { + VerifyRouteNoExists(blue_, repr2.str()); + } else { + VerifyRouteExists(blue_, repr2.str(), kRouteCount - idx); + } + } + + TASK_UTIL_EXPECT_EQ(0, blue_->Size()); + TASK_UTIL_EXPECT_EQ(0, master_->Size()); +} + +// +// Different IP addresses (v4) result in different routes in VRF. +// +TEST_F(EvpnTableIpPrefixTest, ReplicateRouteFromVPN5) { + for (int idx = 1; idx <= kRouteCount; idx++) { + ostringstream repr1; + repr1 << "5-10.1.1.1:65535-0-192.168.1." << idx << "/32"; + AddRoute(master_, repr1.str(), "target:64512:1"); + } + task_util::WaitForIdle(); + + for (int idx = 1; idx <= kRouteCount; idx++) { + ostringstream repr1, repr2; + repr1 << "5-10.1.1.1:65535-0-192.168.1." << idx << "/32"; + repr2 << "5-0:0-0-192.168.1." << idx << "/32"; + VerifyRouteExists(master_, repr1.str()); + VerifyRouteExists(blue_, repr2.str()); + } + TASK_UTIL_EXPECT_EQ(kRouteCount, master_->Size()); + TASK_UTIL_EXPECT_EQ(kRouteCount, blue_->Size()); + + for (int idx = 1; idx <= kRouteCount; idx++) { + ostringstream repr1; + repr1 << "5-10.1.1.1:65535-0-192.168.1." << idx << "/32"; + DelRoute(master_, repr1.str()); + } + task_util::WaitForIdle(); + + for (int idx = 1; idx <= kRouteCount; idx++) { + ostringstream repr1, repr2; + repr1 << "5-10.1.1.1:65535-0-192.168.1." << idx << "/32"; + repr2 << "5-0:0-0-192.168.1." << idx << "/32"; + VerifyRouteNoExists(master_, repr1.str()); + VerifyRouteNoExists(blue_, repr2.str()); + } + TASK_UTIL_EXPECT_EQ(0, blue_->Size()); + TASK_UTIL_EXPECT_EQ(0, master_->Size()); +} + +// +// Different IP addresses (v6) result in different routes in VRF. +// +TEST_F(EvpnTableIpPrefixTest, ReplicateRouteFromVPN6) { + for (int idx = 1; idx <= kRouteCount; idx++) { + ostringstream repr1; + repr1 << "5-10.1.1.1:65535-0-2001:db8:0:9::" << hex << idx << "/128"; + AddRoute(master_, repr1.str(), "target:64512:1"); + } + task_util::WaitForIdle(); + + for (int idx = 1; idx <= kRouteCount; idx++) { + ostringstream repr1, repr2; + repr1 << "5-10.1.1.1:65535-0-2001:db8:0:9::" << hex << idx << "/128"; + repr2 << "5-0:0-0-2001:db8:0:9::" << hex << idx << "/128"; + VerifyRouteExists(master_, repr1.str()); + VerifyRouteExists(blue_, repr2.str()); + } + TASK_UTIL_EXPECT_EQ(kRouteCount, master_->Size()); + TASK_UTIL_EXPECT_EQ(kRouteCount, blue_->Size()); + + for (int idx = 1; idx <= kRouteCount; idx++) { + ostringstream repr1; + repr1 << "5-10.1.1.1:65535-0-2001:db8:0:9::" << hex << idx << "/128"; + DelRoute(master_, repr1.str()); + } + task_util::WaitForIdle(); + + for (int idx = 1; idx <= kRouteCount; idx++) { + ostringstream repr1, repr2; + repr1 << "5-10.1.1.1:65535-0-2001:db8:0:9::" << hex << idx << "/128"; + repr2 << "5-0:0-0-2001:db8:0:9::" << hex << idx << "/128"; + VerifyRouteNoExists(master_, repr1.str()); + VerifyRouteNoExists(blue_, repr2.str()); + } + TASK_UTIL_EXPECT_EQ(0, blue_->Size()); + TASK_UTIL_EXPECT_EQ(0, master_->Size()); +} + +// +// Basic - RD of VPN route (v4) is set to provided source RD. +// +TEST_F(EvpnTableIpPrefixTest, ReplicateRouteToVPN1) { + ostringstream repr1, repr2; + repr1 << "5-0:0-0-192.168.1.1/32"; + repr2 << "5-10.1.1.1:65535-0-192.168.1.1/32"; + AddRoute(blue_, repr1.str(), "", "10.1.1.1:65535"); + task_util::WaitForIdle(); + VerifyRouteExists(blue_, repr1.str()); + TASK_UTIL_EXPECT_EQ(1, blue_->Size()); + VerifyRouteExists(master_, repr2.str()); + TASK_UTIL_EXPECT_EQ(1, master_->Size()); + + DelRoute(blue_, repr1.str()); + task_util::WaitForIdle(); + VerifyRouteNoExists(blue_, repr1.str()); + TASK_UTIL_EXPECT_EQ(0, blue_->Size()); + VerifyRouteNoExists(master_, repr2.str()); + TASK_UTIL_EXPECT_EQ(0, master_->Size()); +} + +// +// Basic - RD of VPN route (v6) is set to provided source RD. +// +TEST_F(EvpnTableIpPrefixTest, ReplicateRouteToVPN2) { + ostringstream repr1, repr2; + repr1 << "5-0:0-0-2001:db8:0:9::1/32"; + repr2 << "5-10.1.1.1:65535-0-2001:db8:0:9::1/32"; + AddRoute(blue_, repr1.str(), "", "10.1.1.1:65535"); + task_util::WaitForIdle(); + VerifyRouteExists(blue_, repr1.str()); + TASK_UTIL_EXPECT_EQ(1, blue_->Size()); + VerifyRouteExists(master_, repr2.str()); + TASK_UTIL_EXPECT_EQ(1, master_->Size()); + + DelRoute(blue_, repr1.str()); + task_util::WaitForIdle(); + VerifyRouteNoExists(blue_, repr1.str()); + TASK_UTIL_EXPECT_EQ(0, blue_->Size()); + VerifyRouteNoExists(master_, repr2.str()); + TASK_UTIL_EXPECT_EQ(0, master_->Size()); +} + +// +// Different IP addresses (v4) result in different routes in VPN. +// +TEST_F(EvpnTableIpPrefixTest, ReplicateRouteToVPN3) { + for (int idx = 1; idx <= kRouteCount; idx++) { + ostringstream repr1; + repr1 << "5-0:0-0-192.168.1." << idx << "/32"; + AddRoute(blue_, repr1.str(), "", "10.1.1.1:65535"); + } + task_util::WaitForIdle(); + + for (int idx = 1; idx <= kRouteCount; idx++) { + ostringstream repr1, repr2; + repr1 << "5-0:0-0-192.168.1." << idx << "/32"; + repr2 << "5-10.1.1.1:65535-0-192.168.1." << idx << "/32"; + VerifyRouteExists(blue_, repr1.str()); + VerifyRouteExists(master_, repr2.str()); + } + TASK_UTIL_EXPECT_EQ(kRouteCount, master_->Size()); + TASK_UTIL_EXPECT_EQ(kRouteCount, blue_->Size()); + + for (int idx = 1; idx <= kRouteCount; idx++) { + ostringstream repr1; + repr1 << "5-0:0-0-192.168.1." << idx << "/32"; + DelRoute(blue_, repr1.str()); + } + task_util::WaitForIdle(); + + for (int idx = 1; idx <= kRouteCount; idx++) { + ostringstream repr1, repr2; + repr1 << "5-0:0-0-192.168.1." << idx << "/32"; + repr2 << "5-10.1.1.1:65535-0-192.168.1." << idx << "/32"; + VerifyRouteNoExists(blue_, repr1.str()); + VerifyRouteNoExists(master_, repr2.str()); + } + TASK_UTIL_EXPECT_EQ(0, blue_->Size()); + TASK_UTIL_EXPECT_EQ(0, master_->Size()); +} + +// +// Different IP addresses (v6) result in different routes in VPN. +// +TEST_F(EvpnTableIpPrefixTest, ReplicateRouteToVPN4) { + for (int idx = 1; idx <= kRouteCount; idx++) { + ostringstream repr1; + repr1 << "5-0:0-0-2001:db8:0:9::" << hex << idx << "/128"; + AddRoute(blue_, repr1.str(), "", "10.1.1.1:65535"); + } + task_util::WaitForIdle(); + + for (int idx = 1; idx <= kRouteCount; idx++) { + ostringstream repr1, repr2; + repr1 << "5-0:0-0-2001:db8:0:9::" << hex << idx << "/128"; + repr2 << "5-10.1.1.1:65535-0-2001:db8:0:9::" << hex << idx << "/128"; + VerifyRouteExists(blue_, repr1.str()); + VerifyRouteExists(master_, repr2.str()); + } + TASK_UTIL_EXPECT_EQ(kRouteCount, master_->Size()); + TASK_UTIL_EXPECT_EQ(kRouteCount, blue_->Size()); + + for (int idx = 1; idx <= kRouteCount; idx++) { + ostringstream repr1; + repr1 << "5-0:0-0-2001:db8:0:9::" << hex << idx << "/128"; + DelRoute(blue_, repr1.str()); + } + task_util::WaitForIdle(); + + for (int idx = 1; idx <= kRouteCount; idx++) { + ostringstream repr1, repr2; + repr1 << "5-0:0-0-2001:db8:0:9::" << hex << idx << "/128"; + repr2 << "5-10.1.1.1:65535-0-2001:db8:0:9::" << hex << idx << "/128"; + VerifyRouteNoExists(blue_, repr1.str()); + VerifyRouteNoExists(master_, repr2.str()); + } + TASK_UTIL_EXPECT_EQ(0, blue_->Size()); + TASK_UTIL_EXPECT_EQ(0, master_->Size()); +} + +// +// Route (v4) is replicated from one VRF to another. +// +TEST_F(EvpnTableIpPrefixTest, ReplicateRouteVRFToVRF1) { + ostringstream repr1, repr2; + repr1 << "5-0:0-0-192.168.1.1/32"; + repr2 << "5-10.1.1.1:65535-0-192.168.1.1/32"; + AddRoute(blue_, repr1.str(), "", "10.1.1.1:65535"); + task_util::WaitForIdle(); + VerifyRouteExists(blue_, repr1.str()); + TASK_UTIL_EXPECT_EQ(1, blue_->Size()); + VerifyRouteExists(master_, repr2.str()); + TASK_UTIL_EXPECT_EQ(1, master_->Size()); + VerifyRouteExists(blue_si_, repr1.str()); + VerifyRouteNoExists(blue_si_, repr2.str()); + TASK_UTIL_EXPECT_EQ(1, blue_si_->Size()); + + DelRoute(blue_, repr1.str()); + task_util::WaitForIdle(); + VerifyRouteNoExists(blue_, repr1.str()); + TASK_UTIL_EXPECT_EQ(0, blue_->Size()); + VerifyRouteNoExists(master_, repr2.str()); + TASK_UTIL_EXPECT_EQ(0, master_->Size()); + VerifyRouteNoExists(blue_si_, repr1.str()); + VerifyRouteNoExists(blue_si_, repr2.str()); + TASK_UTIL_EXPECT_EQ(0, blue_si_->Size()); +} + +// +// Route (v6) is replicated from one VRF to another. +// +TEST_F(EvpnTableIpPrefixTest, ReplicateRouteVRFToVRF2) { + ostringstream repr1, repr2; + repr1 << "5-0:0-0-2001:db8:0:9::1/32"; + repr2 << "5-10.1.1.1:65535-0-2001:db8:0:9::1/32"; + AddRoute(blue_, repr1.str(), "", "10.1.1.1:65535"); + task_util::WaitForIdle(); + VerifyRouteExists(blue_, repr1.str()); + TASK_UTIL_EXPECT_EQ(1, blue_->Size()); + VerifyRouteExists(master_, repr2.str()); + TASK_UTIL_EXPECT_EQ(1, master_->Size()); + VerifyRouteExists(blue_si_, repr1.str()); + VerifyRouteNoExists(blue_si_, repr2.str()); + TASK_UTIL_EXPECT_EQ(1, blue_si_->Size()); + + DelRoute(blue_, repr1.str()); + task_util::WaitForIdle(); + VerifyRouteNoExists(blue_, repr1.str()); + TASK_UTIL_EXPECT_EQ(0, blue_->Size()); + VerifyRouteNoExists(master_, repr2.str()); + TASK_UTIL_EXPECT_EQ(0, master_->Size()); + VerifyRouteNoExists(blue_si_, repr1.str()); + VerifyRouteNoExists(blue_si_, repr2.str()); + TASK_UTIL_EXPECT_EQ(0, blue_si_->Size()); +} + int main(int argc, char **argv) { bgp_log_test::init(); ::testing::InitGoogleTest(&argc, argv); diff --git a/src/control-node/test/network_agent_mock.h b/src/control-node/test/network_agent_mock.h index d05926346bf..67174cf58c0 100644 --- a/src/control-node/test/network_agent_mock.h +++ b/src/control-node/test/network_agent_mock.h @@ -154,7 +154,6 @@ struct NextHop { if (tun1 == "all") { tunnel_encapsulations_.push_back("gre"); tunnel_encapsulations_.push_back("udp"); - tunnel_encapsulations_.push_back("vxlan"); } else if (tun1 == "all_ipv6") { tunnel_encapsulations_.push_back("gre"); tunnel_encapsulations_.push_back("udp"); diff --git a/src/schema/xmpp_unicast.xsd b/src/schema/xmpp_unicast.xsd index 4442c7bad84..5ec36e44d8a 100644 --- a/src/schema/xmpp_unicast.xsd +++ b/src/schema/xmpp_unicast.xsd @@ -15,12 +15,14 @@ xsd:targetNamespace="http://www.contrailsystems.com/bgp-l3vpn-unicast-cfg.xsd"> - + + +