diff --git a/fpmsyncd/routesync.cpp b/fpmsyncd/routesync.cpp index 7fae01eb3d71..dbc08bda89c7 100644 --- a/fpmsyncd/routesync.cpp +++ b/fpmsyncd/routesync.cpp @@ -700,6 +700,7 @@ 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 weights = getNextHopWt(route_obj); vector alsv = tokenize(ifnames, ','); for (auto alias : alsv) @@ -722,6 +723,11 @@ void RouteSync::onRouteMsg(int nlmsg_type, struct nl_object *obj, char *vrf) fvVector.push_back(nh); fvVector.push_back(idx); + if (!weights.empty()) + { + FieldValueTuple wt("weight", weights); + fvVector.push_back(wt); + } if (!warmRestartInProgress) { @@ -962,3 +968,36 @@ string RouteSync::getNextHopIf(struct rtnl_route *route_obj) return result; } + +/* + * Get next hop weights + * @arg route_obj route object + * + * Return concatenation of interface names: wt0 + "," + wt1 + .... + "," + wtN + */ +string RouteSync::getNextHopWt(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); + /* Get the weight of next hop */ + uint8_t weight = rtnl_route_nh_get_weight(nexthop); + if (weight) + { + result += to_string(weight + 1); + } + else + { + return ""; + } + + if (i + 1 < rtnl_route_get_nnexthops(route_obj)) + { + result += string(","); + } + } + + return result; +} diff --git a/fpmsyncd/routesync.h b/fpmsyncd/routesync.h index 71a20f9d6662..968072c428e5 100644 --- a/fpmsyncd/routesync.h +++ b/fpmsyncd/routesync.h @@ -75,6 +75,9 @@ class RouteSync : public NetMsg /* Get next hop interfaces */ string getNextHopIf(struct rtnl_route *route_obj); + + /* Get next hop weights*/ + string getNextHopWt(struct rtnl_route *route_obj); }; } diff --git a/orchagent/nexthopgroupkey.h b/orchagent/nexthopgroupkey.h index 22e75de55148..ec977f8a2d7b 100644 --- a/orchagent/nexthopgroupkey.h +++ b/orchagent/nexthopgroupkey.h @@ -31,6 +31,21 @@ class NextHopGroupKey } } + NextHopGroupKey(const std::string &nexthops, const std::string &weights) + { + std::vector nhv = tokenize(nexthops, NHG_DELIMITER); + std::vector wtv = tokenize(weights, NHG_DELIMITER); + for (uint32_t i = 0; i < nhv.size(); i++) + { + NextHopKey nh(nhv[i]); + if (i < wtv.size()) + { + nh.weight = (uint32_t)std::stoi(wtv[i]); + } + m_nexthops.insert(nh); + } + } + inline const std::set &getNextHops() const { return m_nexthops; diff --git a/orchagent/nexthopkey.h b/orchagent/nexthopkey.h index 69a94505aeac..b5e876bbe9d5 100644 --- a/orchagent/nexthopkey.h +++ b/orchagent/nexthopkey.h @@ -15,10 +15,12 @@ struct NextHopKey string alias; // incoming interface alias uint32_t vni; // Encap VNI overlay nexthop MacAddress mac_address; // Overlay Nexthop MAC. + uint32_t weight; // NH weight for NHGs - NextHopKey() = default; - NextHopKey(const std::string &ipstr, const std::string &alias) : ip_address(ipstr), alias(alias), vni(0), mac_address() {} - NextHopKey(const IpAddress &ip, const std::string &alias) : ip_address(ip), alias(alias), vni(0), mac_address() {} + + NextHopKey() : weight(0) {} + NextHopKey(const std::string &ipstr, const std::string &alias) : ip_address(ipstr), alias(alias), vni(0), mac_address(), weight(0) {} + NextHopKey(const IpAddress &ip, const std::string &alias) : ip_address(ip), alias(alias), vni(0), mac_address(), weight(0) {} NextHopKey(const std::string &str) { if (str.find(NHG_DELIMITER) != string::npos) diff --git a/orchagent/routeorch.cpp b/orchagent/routeorch.cpp index 28f6eaef4d3a..511e387eafd1 100644 --- a/orchagent/routeorch.cpp +++ b/orchagent/routeorch.cpp @@ -325,6 +325,13 @@ bool RouteOrch::validnexthopinNextHopGroup(const NextHopKey &nexthop, uint32_t& nhgm_attr.value.oid = m_neighOrch->getNextHopId(nexthop); nhgm_attrs.push_back(nhgm_attr); + if (nexthop.weight) + { + nhgm_attr.id = SAI_NEXT_HOP_GROUP_MEMBER_ATTR_WEIGHT; + nhgm_attr.value.s32 = nexthop.weight; + nhgm_attrs.push_back(nhgm_attr); + } + status = sai_next_hop_group_api->create_next_hop_group_member(&nexthop_id, gSwitchId, (uint32_t)nhgm_attrs.size(), nhgm_attrs.data()); @@ -513,6 +520,7 @@ void RouteOrch::doTask(Consumer& consumer) string aliases; string vni_labels; string remote_macs; + string weights; bool& excp_intfs_flag = ctx.excp_intfs_flag; bool overlay_nh = false; bool blackhole = false; @@ -535,6 +543,9 @@ void RouteOrch::doTask(Consumer& consumer) if (fvField(i) == "blackhole") blackhole = fvValue(i) == "true"; + + if (fvField(i) == "weight") + weights = fvValue(i); } vector& ipv = ctx.ipv; @@ -624,7 +635,7 @@ void RouteOrch::doTask(Consumer& consumer) nhg_str += NHG_DELIMITER + ipv[i] + NH_DELIMITER + alsv[i]; } - nhg = NextHopGroupKey(nhg_str); + nhg = NextHopGroupKey(nhg_str, weights); } else @@ -1102,6 +1113,7 @@ bool RouteOrch::addNextHopGroup(const NextHopGroupKey &nexthops) for (size_t i = 0; i < npid_count; i++) { auto nhid = next_hop_ids[i]; + auto weight = nhopgroup_members_set[nhid].weight; // Create a next hop group member vector nhgm_attrs; @@ -1115,6 +1127,13 @@ bool RouteOrch::addNextHopGroup(const NextHopGroupKey &nexthops) nhgm_attr.value.oid = nhid; nhgm_attrs.push_back(nhgm_attr); + if (weight) + { + nhgm_attr.id = SAI_NEXT_HOP_GROUP_MEMBER_ATTR_WEIGHT; + nhgm_attr.value.s32 = weight; + nhgm_attrs.push_back(nhgm_attr); + } + gNextHopGroupMemberBulker.create_entry(&nhgm_ids[i], (uint32_t)nhgm_attrs.size(), nhgm_attrs.data()); diff --git a/tests/test_nhg.py b/tests/test_nhg.py index 485fc7661c1e..f1d11112e262 100644 --- a/tests/test_nhg.py +++ b/tests/test_nhg.py @@ -44,7 +44,9 @@ def test_route_nhg(self, dvs, dvs_route, testlog): dvs_route.check_asicdb_deleted_route_entries([rtprefix]) - fvs = swsscommon.FieldValuePairs([("nexthop","10.0.0.1,10.0.0.3,10.0.0.5"), ("ifname", "Ethernet0,Ethernet4,Ethernet8")]) + fvs = swsscommon.FieldValuePairs([("nexthop","10.0.0.1,10.0.0.3,10.0.0.5"), + ("ifname", "Ethernet0,Ethernet4,Ethernet8"), + ("weight", "10,30,50")]) ps.set(rtprefix, fvs) # check if route was propagated to ASIC DB @@ -68,6 +70,16 @@ def test_route_nhg(self, dvs, dvs_route, testlog): assert fvs["SAI_NEXT_HOP_GROUP_MEMBER_ATTR_NEXT_HOP_GROUP_ID"] == nhgid + # verify weight attributes in asic db + nhid = fvs["SAI_NEXT_HOP_GROUP_MEMBER_ATTR_NEXT_HOP_ID"] + weight = fvs["SAI_NEXT_HOP_GROUP_MEMBER_ATTR_WEIGHT"] + + fvs = asic_db.get_entry("ASIC_STATE:SAI_OBJECT_TYPE_NEXT_HOP", nhid) + nhip = fvs["SAI_NEXT_HOP_ATTR_IP"].split('.') + expected_weight = int(nhip[3]) * 10 + + assert int(weight) == expected_weight + # bring links down one-by-one for i in [0, 1, 2]: dvs.servers[i].runcmd("ip link set down dev eth0") == 0