From 3a20d442c31eed697b9eb48645586498eb889d6a Mon Sep 17 00:00:00 2001 From: Ann Pokora Date: Wed, 31 Mar 2021 12:06:29 -0700 Subject: [PATCH] sonic-swss changes for MPLS --- cfgmgr/intfmgr.cpp | 11 + fpmsyncd/routesync.cpp | 139 +++++- fpmsyncd/routesync.h | 8 + orchagent/bulker.h | 40 ++ orchagent/crmorch.cpp | 37 +- orchagent/crmorch.h | 1 + orchagent/intfsorch.cpp | 39 ++ orchagent/intfsorch.h | 1 + orchagent/neighorch.cpp | 154 +++--- orchagent/neighorch.h | 5 +- orchagent/nexthopkey.h | 48 +- orchagent/orchdaemon.cpp | 8 +- orchagent/port.h | 1 + orchagent/routeorch.cpp | 832 +++++++++++++++++++++++++++++++- orchagent/routeorch.h | 46 +- orchagent/saihelper.cpp | 3 + tests/mock_tests/aclorch_ut.cpp | 10 +- 17 files changed, 1290 insertions(+), 93 deletions(-) diff --git a/cfgmgr/intfmgr.cpp b/cfgmgr/intfmgr.cpp index a5bc092df9b..01528d91ba0 100644 --- a/cfgmgr/intfmgr.cpp +++ b/cfgmgr/intfmgr.cpp @@ -447,6 +447,7 @@ bool IntfMgr::doIntfGeneralTask(const vector& keys, string nat_zone = ""; string proxy_arp = ""; string grat_arp = ""; + string mpls = ""; for (auto idx : data) { @@ -473,6 +474,10 @@ bool IntfMgr::doIntfGeneralTask(const vector& keys, { grat_arp = value; } + else if (field == "mpls") + { + mpls = value; + } if (field == "nat_zone") { @@ -518,6 +523,12 @@ bool IntfMgr::doIntfGeneralTask(const vector& keys, FieldValueTuple fvTuple("nat_zone", nat_zone); data.push_back(fvTuple); } + /* Set mpls */ + if (!mpls.empty()) + { + FieldValueTuple fvTuple("mpls", mpls); + data.push_back(fvTuple); + } } if (!vrf_name.empty()) diff --git a/fpmsyncd/routesync.cpp b/fpmsyncd/routesync.cpp index 7fae01eb3d7..891d281fc28 100644 --- a/fpmsyncd/routesync.cpp +++ b/fpmsyncd/routesync.cpp @@ -43,6 +43,7 @@ using namespace swss; RouteSync::RouteSync(RedisPipeline *pipeline) : m_routeTable(pipeline, APP_ROUTE_TABLE_NAME, true), + m_label_routeTable(pipeline, APP_LABEL_ROUTE_TABLE_NAME, true), m_vnet_routeTable(pipeline, APP_VNET_RT_TABLE_NAME, true), m_vnet_tunnelTable(pipeline, APP_VNET_RT_TUNNEL_TABLE_NAME, true), m_warmStartHelper(pipeline, &m_routeTable, APP_ROUTE_TABLE_NAME, "bgp", "bgp"), @@ -570,6 +571,12 @@ void RouteSync::onMsg(int nlmsg_type, struct nl_object *obj) /* Supports IPv4 or IPv6 address, otherwise return immediately */ auto family = rtnl_route_get_family(route_obj); + /* Check for Label route. */ + if (family == AF_MPLS) + { + onLabelRouteMsg(nlmsg_type, obj); + return; + } if (family != AF_INET && family != AF_INET6) { SWSS_LOG_INFO("Unknown route family support (object: %s)", nl_object_get_type(obj)); @@ -698,7 +705,7 @@ void RouteSync::onRouteMsg(int nlmsg_type, struct nl_object *obj, char *vrf) } /* Get nexthop lists */ - string nexthops = getNextHopGw(route_obj); + string nexthops = getNextHopList(route_obj); string ifnames = getNextHopIf(route_obj); vector alsv = tokenize(ifnames, ','); @@ -747,6 +754,80 @@ void RouteSync::onRouteMsg(int nlmsg_type, struct nl_object *obj, char *vrf) } /* + * Handle label route + * @arg nlmsg_type Netlink message type + * @arg obj Netlink object + */ +void RouteSync::onLabelRouteMsg(int nlmsg_type, struct nl_object *obj) +{ + struct rtnl_route *route_obj = (struct rtnl_route *)obj; + struct nl_addr *daddr; + char destaddr[MAX_ADDR_SIZE + 1] = {0}; + + daddr = rtnl_route_get_dst(route_obj); + nl_addr2str(daddr, destaddr, MAX_ADDR_SIZE); + SWSS_LOG_INFO("Receive new route message dest addr: %s", destaddr); + if (nl_addr_iszero(daddr)) return; + + if (nlmsg_type == RTM_DELROUTE) + { + m_label_routeTable.del(destaddr); + return; + } + else if (nlmsg_type != RTM_NEWROUTE) + { + SWSS_LOG_INFO("Unknown message-type: %d for %s", nlmsg_type, destaddr); + return; + } + + switch (rtnl_route_get_type(route_obj)) + { + case RTN_BLACKHOLE: + { + vector fvVector; + FieldValueTuple fv("blackhole", "true"); + fvVector.push_back(fv); + m_label_routeTable.set(destaddr, fvVector); + return; + } + case RTN_UNICAST: + break; + + case RTN_MULTICAST: + case RTN_BROADCAST: + case RTN_LOCAL: + SWSS_LOG_INFO("BUM routes aren't supported yet (%s)", destaddr); + return; + + default: + return; + } + + struct nl_list_head *nhs = rtnl_route_get_nexthops(route_obj); + if (!nhs) + { + SWSS_LOG_INFO("Nexthop list is empty for %s", destaddr); + return; + } + + /* Get nexthop lists */ + string nexthops = getNextHopList(route_obj); + string ifnames = getNextHopIf(route_obj); + + vector fvVector; + FieldValueTuple nh("nexthop", nexthops); + FieldValueTuple idx("ifname", ifnames); + + fvVector.push_back(nh); + fvVector.push_back(idx); + fvVector.push_back(wt); + + m_label_routeTable.set(destaddr, fvVector); + SWSS_LOG_INFO("LabelRouteTable set msg: %s %s %s", + destaddr, nexthops.c_str(), ifnames.c_str()); +} + +/* * Handle vnet route * @arg nlmsg_type Netlink message type * @arg obj Netlink object @@ -886,6 +967,62 @@ bool RouteSync::getIfName(int if_index, char *if_name, size_t name_len) return true; } +/* + * Get next hop List + * @arg route_obj route object + * + * Return concatenation of NHs: nh0 + "," + nh1 + .... + "," + nhN + */ +string RouteSync::getNextHopList(struct rtnl_route *route_obj) +{ + string result = ""; + + for (int i = 0; i < rtnl_route_get_nnexthops(route_obj); i++) + { + struct rtnl_nexthop *nexthop = rtnl_route_nexthop_n(route_obj, i); + struct nl_addr *addr = NULL; + + if ((addr = rtnl_route_nh_get_newdst(nexthop))) + { + /* Next hop label is not empty */ + char label[MAX_ADDR_SIZE + 1] = {0}; + nl_addr2str(addr, label, MAX_ADDR_SIZE); + result += label; + result += string("+"); + } + else if ((addr = rtnl_route_nh_get_encap_mpls_dst(nexthop))) + { + /* Next hop encap is not empty */ + char label[MAX_ADDR_SIZE + 1] = {0}; + nl_addr2str(addr, label, MAX_ADDR_SIZE); + result += label; + result += string("+"); + } + + if ((addr = rtnl_route_nh_get_gateway(nexthop))) + { + /* Next hop gateway is not empty */ + char gw_ip[MAX_ADDR_SIZE + 1] = {0}; + nl_addr2str(addr, gw_ip, MAX_ADDR_SIZE); + result += gw_ip; + } + else if ((addr = rtnl_route_nh_get_via(nexthop))) + { + /* Next hop via is not empty */ + char via_ip[MAX_ADDR_SIZE + 1] = {0}; + nl_addr2str(addr, via_ip, MAX_ADDR_SIZE); + result += via_ip; + } + + if (i + 1 < rtnl_route_get_nnexthops(route_obj)) + { + result += string(","); + } + } + + return result; +} + /* * Get next hop gateway IP addresses * @arg route_obj route object diff --git a/fpmsyncd/routesync.h b/fpmsyncd/routesync.h index 71a20f9d666..e402e23f577 100644 --- a/fpmsyncd/routesync.h +++ b/fpmsyncd/routesync.h @@ -31,6 +31,8 @@ class RouteSync : public NetMsg private: /* regular route table */ ProducerStateTable m_routeTable; + /* label route table */ + ProducerStateTable m_label_routeTable; /* vnet route table */ ProducerStateTable m_vnet_routeTable; /* vnet vxlan tunnel table */ @@ -41,6 +43,9 @@ class RouteSync : public NetMsg /* Handle regular route (include VRF route) */ void onRouteMsg(int nlmsg_type, struct nl_object *obj, char *vrf); + /* Handle label route */ + void onLabelRouteMsg(int nlmsg_type, struct nl_object *obj); + void parseEncap(struct rtattr *tb, uint32_t &encap_value, string &rmac); void parseRtAttrNested(struct rtattr **tb, int max, @@ -70,6 +75,9 @@ class RouteSync : public NetMsg string& nexthops, string& vni_list, string& mac_list, string& intf_list); + /* Get next hop list */ + string getNextHopList(struct rtnl_route *route_obj); + /* Get next hop gateway IP addresses */ string getNextHopGw(struct rtnl_route *route_obj); diff --git a/orchagent/bulker.h b/orchagent/bulker.h index 4f6e9cc5cb2..19b7b14cf4c 100644 --- a/orchagent/bulker.h +++ b/orchagent/bulker.h @@ -40,6 +40,13 @@ static inline bool operator==(const sai_route_entry_t& a, const sai_route_entry_ ; } +static inline bool operator==(const sai_inseg_entry_t& a, const sai_inseg_entry_t& b) +{ + return a.switch_id == b.switch_id + && a.label == b.label + ; +} + static inline std::size_t hash_value(const sai_ip_prefix_t& a) { size_t seed = 0; @@ -84,6 +91,18 @@ namespace std return seed; } }; + + template <> + struct hash + { + size_t operator()(const sai_inseg_entry_t& a) const noexcept + { + size_t seed = 0; + boost::hash_combine(seed, a.switch_id); + boost::hash_combine(seed, a.label); + return seed; + } + }; } // SAI typedef which is not available in SAI 1.5 @@ -150,6 +169,19 @@ struct SaiBulkerTraits //using bulk_set_entry_attribute_fn = sai_bulk_object_set_attribute_fn; }; +template<> +struct SaiBulkerTraits +{ + using entry_t = sai_inseg_entry_t; + using api_t = sai_mpls_api_t; + using create_entry_fn = sai_create_inseg_entry_fn; + using remove_entry_fn = sai_remove_inseg_entry_fn; + using set_entry_attribute_fn = sai_set_inseg_entry_attribute_fn; + using bulk_create_entry_fn = sai_bulk_create_inseg_entry_fn; + using bulk_remove_entry_fn = sai_bulk_remove_inseg_entry_fn; + using bulk_set_entry_attribute_fn = sai_bulk_set_inseg_entry_attribute_fn; +}; + template class EntityBulker { @@ -452,6 +484,14 @@ inline EntityBulker::EntityBulker(sai_fdb_api_t *api) */ } +template <> +inline EntityBulker::EntityBulker(sai_mpls_api_t *api) +{ + create_entries = api->create_inseg_entries; + remove_entries = api->remove_inseg_entries; + set_entries_attribute = api->set_inseg_entries_attribute; +} + template class ObjectBulker { diff --git a/orchagent/crmorch.cpp b/orchagent/crmorch.cpp index 14b0cab4d15..6d779f2c042 100644 --- a/orchagent/crmorch.cpp +++ b/orchagent/crmorch.cpp @@ -40,7 +40,8 @@ const map crmResTypeNameMap = { CrmResourceType::CRM_FDB_ENTRY, "FDB_ENTRY" }, { CrmResourceType::CRM_IPMC_ENTRY, "IPMC_ENTRY" }, { CrmResourceType::CRM_SNAT_ENTRY, "SNAT_ENTRY" }, - { CrmResourceType::CRM_DNAT_ENTRY, "DNAT_ENTRY" } + { CrmResourceType::CRM_DNAT_ENTRY, "DNAT_ENTRY" }, + { CrmResourceType::CRM_MPLS_INSEG, "MPLS_INSEG" }, }; const map crmResSaiAvailAttrMap = @@ -60,7 +61,8 @@ const map crmResSaiAvailAttrMap = { CrmResourceType::CRM_FDB_ENTRY, SAI_SWITCH_ATTR_AVAILABLE_FDB_ENTRY }, { CrmResourceType::CRM_IPMC_ENTRY, SAI_SWITCH_ATTR_AVAILABLE_IPMC_ENTRY}, { CrmResourceType::CRM_SNAT_ENTRY, SAI_SWITCH_ATTR_AVAILABLE_SNAT_ENTRY }, - { CrmResourceType::CRM_DNAT_ENTRY, SAI_SWITCH_ATTR_AVAILABLE_DNAT_ENTRY } + { CrmResourceType::CRM_DNAT_ENTRY, SAI_SWITCH_ATTR_AVAILABLE_DNAT_ENTRY }, + { CrmResourceType::CRM_MPLS_INSEG, SAI_OBJECT_TYPE_INSEG_ENTRY }, }; const map crmThreshTypeResMap = @@ -80,7 +82,8 @@ const map crmThreshTypeResMap = { "fdb_entry_threshold_type", CrmResourceType::CRM_FDB_ENTRY }, { "ipmc_entry_threshold_type", CrmResourceType::CRM_IPMC_ENTRY }, { "snat_entry_threshold_type", CrmResourceType::CRM_SNAT_ENTRY }, - { "dnat_entry_threshold_type", CrmResourceType::CRM_DNAT_ENTRY } + { "dnat_entry_threshold_type", CrmResourceType::CRM_DNAT_ENTRY }, + { "mpls_inseg_threshold_type", CrmResourceType::CRM_MPLS_INSEG }, }; const map crmThreshLowResMap = @@ -100,7 +103,8 @@ const map crmThreshLowResMap = {"fdb_entry_low_threshold", CrmResourceType::CRM_FDB_ENTRY }, {"ipmc_entry_low_threshold", CrmResourceType::CRM_IPMC_ENTRY }, {"snat_entry_low_threshold", CrmResourceType::CRM_SNAT_ENTRY }, - {"dnat_entry_low_threshold", CrmResourceType::CRM_DNAT_ENTRY } + {"dnat_entry_low_threshold", CrmResourceType::CRM_DNAT_ENTRY }, + {"mpls_inseg_low_threshold", CrmResourceType::CRM_MPLS_INSEG }, }; const map crmThreshHighResMap = @@ -120,7 +124,8 @@ const map crmThreshHighResMap = {"fdb_entry_high_threshold", CrmResourceType::CRM_FDB_ENTRY }, {"ipmc_entry_high_threshold", CrmResourceType::CRM_IPMC_ENTRY }, {"snat_entry_high_threshold", CrmResourceType::CRM_SNAT_ENTRY }, - {"dnat_entry_high_threshold", CrmResourceType::CRM_DNAT_ENTRY } + {"dnat_entry_high_threshold", CrmResourceType::CRM_DNAT_ENTRY }, + {"mpls_inseg_high_threshold", CrmResourceType::CRM_MPLS_INSEG }, }; const map crmThreshTypeMap = @@ -147,7 +152,8 @@ const map crmAvailCntsTableMap = { "crm_stats_fdb_entry_available", CrmResourceType::CRM_FDB_ENTRY }, { "crm_stats_ipmc_entry_available", CrmResourceType::CRM_IPMC_ENTRY }, { "crm_stats_snat_entry_available", CrmResourceType::CRM_SNAT_ENTRY }, - { "crm_stats_dnat_entry_available", CrmResourceType::CRM_DNAT_ENTRY } + { "crm_stats_dnat_entry_available", CrmResourceType::CRM_DNAT_ENTRY }, + { "crm_stats_mpls_inseg_available", CrmResourceType::CRM_MPLS_INSEG }, }; const map crmUsedCntsTableMap = @@ -167,7 +173,8 @@ const map crmUsedCntsTableMap = { "crm_stats_fdb_entry_used", CrmResourceType::CRM_FDB_ENTRY }, { "crm_stats_ipmc_entry_used", CrmResourceType::CRM_IPMC_ENTRY }, { "crm_stats_snat_entry_used", CrmResourceType::CRM_SNAT_ENTRY }, - { "crm_stats_dnat_entry_used", CrmResourceType::CRM_DNAT_ENTRY } + { "crm_stats_dnat_entry_used", CrmResourceType::CRM_DNAT_ENTRY }, + { "crm_stats_mpls_inseg_used", CrmResourceType::CRM_MPLS_INSEG }, }; CrmOrch::CrmOrch(DBConnector *db, string tableName): @@ -536,6 +543,22 @@ void CrmOrch::getResAvailableCounters() break; } + case CrmResourceType::CRM_MPLS_INSEG: + { + sai_object_type_t objType = static_cast(crmResSaiAvailAttrMap.at(res.first)); + uint64_t availCount = 0; + sai_status_t status = sai_object_type_get_availability(gSwitchId, objType, 0, nullptr, &availCount); + if (status != SAI_STATUS_SUCCESS) + { + SWSS_LOG_ERROR("Failed to get availability for object_type %u , rv:%d", objType, status); + break; + } + + res.second.countersMap[CRM_COUNTERS_TABLE_KEY].availableCounter = (uint32_t)availCount; + + break; + } + default: SWSS_LOG_ERROR("Failed to get CRM resource type %u. Unknown resource type.\n", (uint32_t)res.first); return; diff --git a/orchagent/crmorch.h b/orchagent/crmorch.h index 7c093ffb24a..58089d687c2 100644 --- a/orchagent/crmorch.h +++ b/orchagent/crmorch.h @@ -28,6 +28,7 @@ enum class CrmResourceType CRM_IPMC_ENTRY, CRM_SNAT_ENTRY, CRM_DNAT_ENTRY, + CRM_MPLS_INSEG, }; enum class CrmThresholdType diff --git a/orchagent/intfsorch.cpp b/orchagent/intfsorch.cpp index ffae3decacd..8b3a51f828f 100644 --- a/orchagent/intfsorch.cpp +++ b/orchagent/intfsorch.cpp @@ -177,6 +177,27 @@ void IntfsOrch::decreaseRouterIntfsRefCount(const string &alias) alias.c_str(), m_syncdIntfses[alias].ref_count); } +bool IntfsOrch::setRouterIntfsMpls(Port &port) +{ + SWSS_LOG_ENTER(); + + sai_attribute_t attr; + attr.id = SAI_ROUTER_INTERFACE_ATTR_ADMIN_MPLS_STATE; + attr.value.booldata = port.m_mpls; + + sai_status_t status = + sai_router_intfs_api->set_router_interface_attribute(port.m_rif_id, &attr); + if (status != SAI_STATUS_SUCCESS) + { + SWSS_LOG_ERROR("Failed to set router interface %s MPLS to %s, rv:%d", + port.m_alias.c_str(), (port.m_mpls ? "enable" : "disable"), status); + return false; + } + SWSS_LOG_NOTICE("Set router interface %s MPLS to %s", port.m_alias.c_str(), + (port.m_mpls ? "enable" : "disable")); + return true; +} + bool IntfsOrch::setRouterIntfsMtu(const Port &port) { SWSS_LOG_ENTER(); @@ -618,6 +639,7 @@ void IntfsOrch::doTask(Consumer &consumer) uint32_t nat_zone_id = 0; string proxy_arp = ""; string inband_type = ""; + bool mpls = false; for (auto idx : data) { @@ -643,6 +665,10 @@ void IntfsOrch::doTask(Consumer &consumer) continue; } } + else if (field == "mpls") + { + mpls = (value == "enable" ? true : false); + } else if (field == "nat_zone") { try @@ -833,6 +859,14 @@ void IntfsOrch::doTask(Consumer &consumer) } gPortsOrch->setPort(alias, port); } + /* Set MPLS */ + if ((!ip_prefix_in_key) && (port.m_mpls != mpls)) + { + port.m_mpls = mpls; + + setRouterIntfsMpls(port); + gPortsOrch->setPort(alias, port); + } } } @@ -1072,6 +1106,10 @@ bool IntfsOrch::addRouterIntfs(sai_object_id_t vrf_id, Port &port) attr.value.u32 = port.m_mtu; attrs.push_back(attr); + attr.id = SAI_ROUTER_INTERFACE_ATTR_ADMIN_MPLS_STATE; + attr.value.booldata = port.m_mpls; + attrs.push_back(attr); + if (gIsNatSupported) { attr.id = SAI_ROUTER_INTERFACE_ATTR_NAT_ZONE_ID; @@ -1134,6 +1172,7 @@ bool IntfsOrch::removeRouterIntfs(Port &port) port.m_rif_id = 0; port.m_vr_id = 0; port.m_nat_zone_id = 0; + port.m_mpls = false; gPortsOrch->setPort(port.m_alias, port); SWSS_LOG_NOTICE("Remove router interface for port %s", port.m_alias.c_str()); diff --git a/orchagent/intfsorch.h b/orchagent/intfsorch.h index 11b947ec298..67ebd218c90 100644 --- a/orchagent/intfsorch.h +++ b/orchagent/intfsorch.h @@ -45,6 +45,7 @@ class IntfsOrch : public Orch bool setRouterIntfsMac(const Port &port); bool setRouterIntfsNatZoneId(Port &port); bool setRouterIntfsAdminStatus(const Port &port); + bool setRouterIntfsMpls(Port &port); std::set getSubnetRoutes(); diff --git a/orchagent/neighorch.cpp b/orchagent/neighorch.cpp index 5e978bd039c..ac4707427b2 100644 --- a/orchagent/neighorch.cpp +++ b/orchagent/neighorch.cpp @@ -150,15 +150,15 @@ bool NeighOrch::hasNextHop(const NextHopKey &nexthop) return m_syncdNextHops.find(nexthop) != m_syncdNextHops.end(); } -bool NeighOrch::addNextHop(const IpAddress &ipAddress, const string &alias) +bool NeighOrch::addNextHop(const NextHopKey &nexthop) { SWSS_LOG_ENTER(); Port p; - if (!gPortsOrch->getPort(alias, p)) + if (!gPortsOrch->getPort(nexthop.alias, p)) { SWSS_LOG_ERROR("Neighbor %s seen on port %s which doesn't exist", - ipAddress.to_string().c_str(), alias.c_str()); + nexthop.ip_address.to_string().c_str(), nexthop.alias.c_str()); return false; } if (p.m_type == Port::SUBPORT) @@ -166,13 +166,12 @@ bool NeighOrch::addNextHop(const IpAddress &ipAddress, const string &alias) if (!gPortsOrch->getPort(p.m_parent_port_id, p)) { SWSS_LOG_ERROR("Neighbor %s seen on sub interface %s whose parent port doesn't exist", - ipAddress.to_string().c_str(), alias.c_str()); + nexthop.ip_address.to_string().c_str(), nexthop.alias.c_str()); return false; } } - NextHopKey nexthop = { ipAddress, alias }; - if(m_intfsOrch->isRemoteSystemPortIntf(alias)) + if(m_intfsOrch->isRemoteSystemPortIntf(nexthop.alias)) { //For remote system ports kernel nexthops are always on inband. Change the key Port inbp; @@ -182,17 +181,38 @@ bool NeighOrch::addNextHop(const IpAddress &ipAddress, const string &alias) nexthop.alias = inbp.m_alias; } assert(!hasNextHop(nexthop)); - sai_object_id_t rif_id = m_intfsOrch->getRouterIntfsId(alias); + sai_object_id_t rif_id = m_intfsOrch->getRouterIntfsId(nexthop.alias); vector next_hop_attrs; sai_attribute_t next_hop_attr; - next_hop_attr.id = SAI_NEXT_HOP_ATTR_TYPE; - next_hop_attr.value.s32 = SAI_NEXT_HOP_TYPE_IP; - next_hop_attrs.push_back(next_hop_attr); + uint32_t lstack[10]; + if (nexthop.label_stack.getSize()) + { + next_hop_attr.id = SAI_NEXT_HOP_ATTR_TYPE; + next_hop_attr.value.s32 = SAI_NEXT_HOP_TYPE_MPLS; + next_hop_attrs.push_back(next_hop_attr); + + next_hop_attr.id = SAI_NEXT_HOP_ATTR_LABELSTACK; + set