From 0e4b32a11b7df5547668a5f7cd1db5997e8b2463 Mon Sep 17 00:00:00 2001 From: Ann Pokora <44511240+qbdwlr@users.noreply.github.com> Date: Thu, 26 Aug 2021 14:37:23 -0400 Subject: [PATCH] [fpmsyncd][MPLS] updates for MPLS plus AZP libnl3 install (#1871) * "fpmsyncd support" for routes with AF_MPLS and NHs with MPLS attributes. * AZP changes to install libnl3 from sonic-buildimage --- .azure-pipelines/build-template.yml | 30 +++- azure-pipelines.yml | 6 + fpmsyncd/routesync.cpp | 248 ++++++++++++++++++++++++++-- fpmsyncd/routesync.h | 9 + lgtm.yml | 22 ++- 5 files changed, 291 insertions(+), 24 deletions(-) diff --git a/.azure-pipelines/build-template.yml b/.azure-pipelines/build-template.yml index 63723dcbb18..2dbec2ffc79 100644 --- a/.azure-pipelines/build-template.yml +++ b/.azure-pipelines/build-template.yml @@ -21,6 +21,13 @@ parameters: - name: sonic_slave type: string +- name: buildimage_artifact_name + type: string + +- name: buildimage_pipeline + type: number + default: 1 + - name: sairedis_artifact_name type: string @@ -54,10 +61,6 @@ jobs: sudo apt-get install -y libzmq5 libzmq3-dev sudo apt-get install -qq -y \ libhiredis-dev \ - libnl-3-dev \ - libnl-genl-3-dev \ - libnl-route-3-dev \ - libnl-nf-3-dev \ swig3.0 sudo apt-get install -y libdbus-1-3 sudo apt-get install -y libteam-dev \ @@ -82,7 +85,24 @@ jobs: runVersion: 'latestFromBranch' runBranch: 'refs/heads/master' displayName: "Download sonic sairedis deb packages" + - task: DownloadPipelineArtifact@2 + inputs: + source: specific + project: build + pipeline: ${{ parameters.buildimage_pipeline }} + artifact: ${{ parameters.buildimage_artifact_name }} + runVersion: 'latestFromBranch' + runBranch: 'refs/heads/master' + displayName: "Download sonic buildimage deb packages" - script: | + sudo dpkg -i target/debs/buster/libnl-3-200_*.deb + sudo dpkg -i target/debs/buster/libnl-3-dev_*.deb + sudo dpkg -i target/debs/buster/libnl-genl-3-200_*.deb + sudo dpkg -i target/debs/buster/libnl-genl-3-dev_*.deb + sudo dpkg -i target/debs/buster/libnl-route-3-200_*.deb + sudo dpkg -i target/debs/buster/libnl-route-3-dev_*.deb + sudo dpkg -i target/debs/buster/libnl-nf-3-200_*.deb + sudo dpkg -i target/debs/buster/libnl-nf-3-dev_*.deb sudo dpkg -i libswsscommon_1.0.0_${{ parameters.arch }}.deb sudo dpkg -i libswsscommon-dev_1.0.0_${{ parameters.arch }}.deb sudo dpkg -i libsaivs_*.deb @@ -93,7 +113,7 @@ jobs: sudo dpkg -i libsaimetadata-dev_*.deb sudo dpkg -i syncd-vs_*.deb workingDirectory: $(Pipeline.Workspace) - displayName: "Install sonic swss common and sairedis" + displayName: "Install libnl3, sonic swss common and sairedis" - checkout: self submodules: true - script: | diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 5f34d4b045b..d43520b2a7c 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -16,6 +16,8 @@ stages: parameters: arch: amd64 sonic_slave: sonic-slave-buster + buildimage_artifact_name: sonic-buildimage.vs + buildimage_pipeline: 1 swss_common_artifact_name: sonic-swss-common sairedis_artifact_name: sonic-sairedis artifact_name: sonic-swss @@ -31,6 +33,8 @@ stages: timeout: 240 pool: sonicbld sonic_slave: sonic-slave-buster-armhf + buildimage_artifact_name: sonic-buildimage.marvell-armhf + buildimage_pipeline: 141 swss_common_artifact_name: sonic-swss-common.armhf sairedis_artifact_name: sonic-sairedis.armhf artifact_name: sonic-swss.armhf @@ -42,6 +46,8 @@ stages: pool: sonicbld sonic_slave: sonic-slave-buster-arm64 swss_common_artifact_name: sonic-swss-common.arm64 + buildimage_artifact_name: sonic-buildimage.centec-arm64 + buildimage_pipeline: 140 sairedis_artifact_name: sonic-sairedis.arm64 artifact_name: sonic-swss.arm64 diff --git a/fpmsyncd/routesync.cpp b/fpmsyncd/routesync.cpp index 00cb7cdd2b7..6a128a07847 100644 --- a/fpmsyncd/routesync.cpp +++ b/fpmsyncd/routesync.cpp @@ -21,6 +21,8 @@ using namespace swss; #define VRF_PREFIX "Vrf" #define MGMT_VRF_PREFIX "mgmt" +#define NHG_DELIMITER ',' + #ifndef ETH_ALEN #define ETH_ALEN 6 #endif @@ -44,6 +46,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"), @@ -113,10 +116,10 @@ void RouteSync::parseEncap(struct rtattr *tb, uint32_t &encap_value, string &rma void RouteSync::getEvpnNextHopSep(string& nexthops, string& vni_list, string& mac_list, string& intf_list) { - nexthops += string(","); - vni_list += string(","); - mac_list += string(","); - intf_list += string(","); + nexthops += NHG_DELIMITER; + vni_list += NHG_DELIMITER; + mac_list += NHG_DELIMITER; + intf_list += NHG_DELIMITER; return; } @@ -571,6 +574,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)); @@ -708,11 +717,13 @@ void RouteSync::onRouteMsg(int nlmsg_type, struct nl_object *obj, char *vrf) } /* Get nexthop lists */ - string nexthops = getNextHopGw(route_obj); - string ifnames = getNextHopIf(route_obj); + string gw_list; + string intf_list; + string mpls_list; + getNextHopList(route_obj, gw_list, mpls_list, intf_list); string weights = getNextHopWt(route_obj); - vector alsv = tokenize(ifnames, ','); + vector alsv = tokenize(intf_list, NHG_DELIMITER); for (auto alias : alsv) { /* @@ -722,17 +733,22 @@ void RouteSync::onRouteMsg(int nlmsg_type, struct nl_object *obj, char *vrf) if (alias == "eth0" || alias == "docker0") { SWSS_LOG_DEBUG("Skip routes to eth0 or docker0: %s %s %s", - destipprefix, nexthops.c_str(), ifnames.c_str()); + destipprefix, gw_list.c_str(), intf_list.c_str()); return; } } vector fvVector; - FieldValueTuple nh("nexthop", nexthops); - FieldValueTuple idx("ifname", ifnames); + FieldValueTuple gw("nexthop", gw_list); + FieldValueTuple intf("ifname", intf_list); - fvVector.push_back(nh); - fvVector.push_back(idx); + fvVector.push_back(gw); + fvVector.push_back(intf); + if (!mpls_list.empty()) + { + FieldValueTuple mpls_nh("mpls_nh", mpls_list); + fvVector.push_back(mpls_nh); + } if (!weights.empty()) { FieldValueTuple wt("weight", weights); @@ -742,8 +758,8 @@ void RouteSync::onRouteMsg(int nlmsg_type, struct nl_object *obj, char *vrf) if (!warmRestartInProgress) { m_routeTable.set(destipprefix, fvVector); - SWSS_LOG_DEBUG("RouteTable set msg: %s %s %s", - destipprefix, nexthops.c_str(), ifnames.c_str()); + SWSS_LOG_DEBUG("RouteTable set msg: %s %s %s %s", destipprefix, + gw_list.c_str(), intf_list.c_str(), mpls_list.c_str()); } /* @@ -752,8 +768,8 @@ void RouteSync::onRouteMsg(int nlmsg_type, struct nl_object *obj, char *vrf) */ else { - SWSS_LOG_INFO("Warm-Restart mode: RouteTable set msg: %s %s %s", - destipprefix, nexthops.c_str(), ifnames.c_str()); + SWSS_LOG_INFO("Warm-Restart mode: RouteTable set msg: %s %s %s %s", destipprefix, + gw_list.c_str(), intf_list.c_str(), mpls_list.c_str()); const KeyOpFieldsValuesTuple kfv = std::make_tuple(destipprefix, SET_COMMAND, @@ -763,6 +779,98 @@ 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 LabelRoute 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 LabelRoute %s", nlmsg_type, destaddr); + return; + } + + /* Get the index of the master device */ + uint32_t master_index = rtnl_route_get_table(route_obj); + /* if the table_id is not set in the route obj then route is for default vrf. */ + if (master_index) + { + SWSS_LOG_INFO("Unsupported Non-default VRF: %d for LabelRoute %s", + master_index, 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 LabelRoute %s", destaddr); + return; + } + + /* Get nexthop lists */ + string gw_list; + string intf_list; + string mpls_list; + getNextHopList(route_obj, gw_list, mpls_list, intf_list); + + vector fvVector; + FieldValueTuple gw("nexthop", gw_list); + FieldValueTuple intf("ifname", intf_list); + FieldValueTuple mpls_pop("mpls_pop", "1"); + + fvVector.push_back(gw); + fvVector.push_back(intf); + if (!mpls_list.empty()) + { + FieldValueTuple mpls_nh("mpls_nh", mpls_list); + fvVector.push_back(mpls_nh); + } + fvVector.push_back(mpls_pop); + + m_label_routeTable.set(destaddr, fvVector); + SWSS_LOG_INFO("LabelRouteTable set msg: %s %s %s %s", destaddr, + gw_list.c_str(), intf_list.c_str(), mpls_list.c_str()); +} + +/* * Handle vnet route * @arg nlmsg_type Netlink message type * @arg obj Netlink object @@ -902,6 +1010,110 @@ bool RouteSync::getIfName(int if_index, char *if_name, size_t name_len) return true; } +/* + * getNextHopList() - parses next hop list attached to route_obj + * @arg route_obj (input) Netlink route object + * @arg gw_list (output) comma-separated list of NH IP gateways + * @arg mpls_list (output) comma-separated list of NH MPLS info + * @arg intf_list (output) comma-separated list of NH interfaces + * + * Return void + */ +void RouteSync::getNextHopList(struct rtnl_route *route_obj, string& gw_list, + string& mpls_list, string& intf_list) +{ + bool mpls_found = false; + + 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; + + /* RTA_GATEWAY is NH gateway info for IP routes only */ + if ((addr = rtnl_route_nh_get_gateway(nexthop))) + { + char gw_ip[MAX_ADDR_SIZE + 1] = {0}; + nl_addr2str(addr, gw_ip, MAX_ADDR_SIZE); + gw_list += gw_ip; + + /* LWTUNNEL_ENCAP_MPLS RTA_DST is MPLS NH label stack for IP routes only */ + if ((addr = rtnl_route_nh_get_encap_mpls_dst(nexthop))) + { + char labelstack[MAX_ADDR_SIZE + 1] = {0}; + nl_addr2str(addr, labelstack, MAX_ADDR_SIZE); + mpls_list += string("push"); + mpls_list += labelstack; + mpls_found = true; + } + /* Filler for proper parsing in routeorch */ + else + { + mpls_list += string("na"); + } + } + /* RTA_VIA is NH gateway info for MPLS routes only */ + else if ((addr = rtnl_route_nh_get_via(nexthop))) + { + char gw_ip[MAX_ADDR_SIZE + 1] = {0}; + nl_addr2str(addr, gw_ip, MAX_ADDR_SIZE); + gw_list += gw_ip; + + /* RTA_NEWDST is MPLS NH label stack for MPLS routes only */ + if ((addr = rtnl_route_nh_get_newdst(nexthop))) + { + char labelstack[MAX_ADDR_SIZE + 1] = {0}; + nl_addr2str(addr, labelstack, MAX_ADDR_SIZE); + mpls_list += string("swap"); + mpls_list += labelstack; + mpls_found = true; + } + /* Filler for proper parsing in routeorch */ + else + { + mpls_list += string("na"); + } + } + else + { + if (rtnl_route_get_family(route_obj) == AF_INET6) + { + gw_list += "::"; + } + /* for MPLS route, use IPv4 as default gateway. */ + else + { + gw_list += "0.0.0.0"; + } + mpls_list += string("na"); + } + + /* Get the ID of next hop interface */ + unsigned if_index = rtnl_route_nh_get_ifindex(nexthop); + char if_name[IFNAMSIZ] = "0"; + if (getIfName(if_index, if_name, IFNAMSIZ)) + { + intf_list += if_name; + } + /* If we cannot get the interface name */ + else + { + intf_list += "unknown"; + } + + if (i + 1 < rtnl_route_get_nnexthops(route_obj)) + { + gw_list += NHG_DELIMITER; + mpls_list += NHG_DELIMITER; + intf_list += NHG_DELIMITER; + } + } + + if (!mpls_found) + { + mpls_list.clear(); + } +} + /* * Get next hop gateway IP addresses * @arg route_obj route object @@ -938,7 +1150,7 @@ string RouteSync::getNextHopGw(struct rtnl_route *route_obj) if (i + 1 < rtnl_route_get_nnexthops(route_obj)) { - result += string(","); + result += NHG_DELIMITER; } } @@ -972,7 +1184,7 @@ string RouteSync::getNextHopIf(struct rtnl_route *route_obj) if (i + 1 < rtnl_route_get_nnexthops(route_obj)) { - result += string(","); + result += NHG_DELIMITER; } } diff --git a/fpmsyncd/routesync.h b/fpmsyncd/routesync.h index 968072c428e..2e53bb8d17d 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,10 @@ class RouteSync : public NetMsg string& nexthops, string& vni_list, string& mac_list, string& intf_list); + /* Get next hop list */ + void getNextHopList(struct rtnl_route *route_obj, string& gw_list, + string& mpls_list, string& intf_list); + /* Get next hop gateway IP addresses */ string getNextHopGw(struct rtnl_route *route_obj); diff --git a/lgtm.yml b/lgtm.yml index 724b9cb3892..68a2fc75865 100644 --- a/lgtm.yml +++ b/lgtm.yml @@ -23,13 +23,33 @@ extraction: - libgtest-dev - dh-exec - doxygen + - cdbs + - bison + - flex - graphviz - autoconf-archive after_prepare: + - git clone https://github.com/Azure/sonic-buildimage; pushd sonic-buildimage/src/libnl3 + - git clone https://github.com/thom311/libnl libnl3-3.5.0; pushd libnl3-3.5.0; git checkout tags/libnl3_5_0 + - git apply ../patch/0001-mpls-encap-accessors.patch + - git apply ../patch/0002-mpls-remove-nl_addr_valid.patch + - ln -s ../debian debian + - fakeroot dpkg-buildpackage -us -uc -b + - popd; popd - git clone https://github.com/Azure/sonic-swss-common; pushd sonic-swss-common; ./autogen.sh; fakeroot dpkg-buildpackage -us -uc -b; popd - dpkg-deb -x libswsscommon_1.0.0_amd64.deb $LGTM_WORKSPACE - dpkg-deb -x libswsscommon-dev_1.0.0_amd64.deb $LGTM_WORKSPACE - git clone --recursive https://github.com/Azure/sonic-sairedis; pushd sonic-sairedis; ./autogen.sh; DEB_BUILD_OPTIONS=nocheck SWSS_COMMON_INC="$LGTM_WORKSPACE/usr/include" SWSS_COMMON_LIB="$LGTM_WORKSPACE/usr/lib/x86_64-linux-gnu" fakeroot debian/rules binary-syncd-vs; popd + - pushd sonic-buildimage/src/libnl3/ + - dpkg-deb -x libnl-3-200_3.5.0-1_amd64.deb $LGTM_WORKSPACE + - dpkg-deb -x libnl-3-dev_3.5.0-1_amd64.deb $LGTM_WORKSPACE + - dpkg-deb -x libnl-genl-3-200_3.5.0-1_amd64.deb $LGTM_WORKSPACE + - dpkg-deb -x libnl-genl-3-dev_3.5.0-1_amd64.deb $LGTM_WORKSPACE + - dpkg-deb -x libnl-route-3-200_3.5.0-1_amd64.deb $LGTM_WORKSPACE + - dpkg-deb -x libnl-route-3-dev_3.5.0-1_amd64.deb $LGTM_WORKSPACE + - dpkg-deb -x libnl-nf-3-200_3.5.0-1_amd64.deb $LGTM_WORKSPACE + - dpkg-deb -x libnl-nf-3-dev_3.5.0-1_amd64.deb $LGTM_WORKSPACE + - popd - dpkg-deb -x libsairedis_1.0.0_amd64.deb $LGTM_WORKSPACE - dpkg-deb -x libsairedis-dev_1.0.0_amd64.deb $LGTM_WORKSPACE - dpkg-deb -x libsaimetadata_1.0.0_amd64.deb $LGTM_WORKSPACE @@ -39,4 +59,4 @@ extraction: configure: command: - ./autogen.sh - - ./configure --prefix=/usr --with-extra-inc=$LGTM_WORKSPACE/usr/include --with-extra-lib=$LGTM_WORKSPACE/usr/lib/x86_64-linux-gnu + - ./configure --prefix=/usr --with-extra-inc=$LGTM_WORKSPACE/usr/include --with-extra-lib=$LGTM_WORKSPACE/lib/x86_64-linux-gnu --with-extra-usr-lib=$LGTM_WORKSPACE/usr/lib/x86_64-linux-gnu --with-libnl-3.0-inc=$LGTM_WORKSPACE/usr/include/libnl3