@@ -1051,7 +1051,42 @@ static struct zebra_vrf *vrf_lookup_by_table_id(uint32_t table_id)
10511051 }
10521052
10531053 return NULL ;
1054- }
1054+ }
1055+
1056+ static bool has_srv6_nexthop (struct zebra_dplane_ctx * ctx )
1057+ {
1058+ struct nexthop * nexthop ;
1059+
1060+ for (ALL_NEXTHOPS_PTR (dplane_ctx_get_ng (ctx ), nexthop ))
1061+ if (nexthop -> nh_srv6 )
1062+ return true ;
1063+
1064+ return false ;
1065+ }
1066+
1067+ static bool has_srv6_sidlist_nexthop (struct zebra_dplane_ctx * ctx )
1068+ {
1069+ struct nexthop * nexthop ;
1070+
1071+ for (ALL_NEXTHOPS_PTR (dplane_ctx_get_ng (ctx ), nexthop ))
1072+ if (nexthop -> nh_srv6 && nexthop -> nh_srv6 -> seg6_segs &&
1073+ !sid_zero (nexthop -> nh_srv6 -> seg6_segs ))
1074+ return true;
1075+
1076+ return false ;
1077+ }
1078+
1079+ static bool has_srv6_localsid_nexthop (struct zebra_dplane_ctx * ctx )
1080+ {
1081+ struct nexthop * nexthop ;
1082+
1083+ for (ALL_NEXTHOPS_PTR (dplane_ctx_get_ng (ctx ), nexthop ))
1084+ if (nexthop -> nh_srv6 &&
1085+ nexthop -> nh_srv6 -> seg6local_action != ZEBRA_SEG6_LOCAL_ACTION_UNSPEC )
1086+ return true;
1087+
1088+ return false ;
1089+ }
10551090
10561091/**
10571092 * Resets the SRv6 routes FPM flags so we send all SRv6 routes again.
@@ -1474,6 +1509,70 @@ static ssize_t netlink_vpn_route_msg_encode(int cmd,
14741509 return NLMSG_ALIGN (req -> n .nlmsg_len );
14751510}
14761511
1512+ static bool netlink_srv6_vpn_route_msg_encode_multipath (int cmd , struct zebra_dplane_ctx * ctx ,
1513+ uint8_t * data , size_t datalen ,
1514+ const struct nexthop * nexthop ,
1515+ struct nlmsghdr * nlmsg , size_t req_size ,
1516+ bool fpm , bool force_nhg )
1517+ {
1518+ struct rtattr * nest ;
1519+ struct rtnexthop * rtnh ;
1520+ struct interface * ifp ;
1521+ struct in6_addr encap_src_addr = {};
1522+ struct connected * connected ;
1523+ struct vrf * vrf ;
1524+ struct prefix * cp ;
1525+
1526+ rtnh = nl_attr_rtnh (nlmsg , req_size );
1527+ if (rtnh == NULL )
1528+ return false;
1529+
1530+ if (!nl_attr_put16 (nlmsg , req_size , RTA_ENCAP_TYPE , FPM_ROUTE_ENCAP_SRV6 ))
1531+ return false ;
1532+
1533+ nest = nl_attr_nest (nlmsg , req_size , RTA_ENCAP );
1534+ if (!nest )
1535+ return false;
1536+
1537+ /*
1538+ * by default, we use the loopback address as encap source address,
1539+ * if it is valid
1540+ */
1541+ ifp = if_lookup_by_name ("lo" , VRF_DEFAULT );
1542+
1543+ if (ifp ) {
1544+ vrf = vrf_lookup_by_name (VRF_DEFAULT_NAME );
1545+ if (!vrf )
1546+ return false;
1547+
1548+ FOR_ALL_INTERFACES (vrf , ifp ) {
1549+ frr_each (if_connected , ifp -> connected , connected ) {
1550+ cp = connected -> address ;
1551+ if (cp -> family == AF_INET6 &&
1552+ !IN6_IS_ADDR_LOOPBACK (& cp -> u .prefix6 ) &&
1553+ !IN6_IS_ADDR_LINKLOCAL (& cp -> u .prefix6 )) {
1554+ encap_src_addr = cp -> u .prefix6 ;
1555+ break ;
1556+ }
1557+ }
1558+ }
1559+ }
1560+
1561+ if (!nl_attr_put (nlmsg , req_size , FPM_ROUTE_ENCAP_SRV6_ENCAP_SRC_ADDR , & encap_src_addr ,
1562+ IPV6_MAX_BYTELEN ))
1563+ return false;
1564+
1565+ if (!nl_attr_put (nlmsg , req_size , FPM_ROUTE_ENCAP_SRV6_VPN_SID ,
1566+ & nexthop -> nh_srv6 -> seg6_segs -> seg [0 ], IPV6_MAX_BYTELEN ))
1567+ return false;
1568+
1569+ nl_attr_nest_end (nlmsg , nest );
1570+
1571+ nl_attr_rtnh_end (nlmsg , rtnh );
1572+
1573+ return true;
1574+ }
1575+
14771576/*
14781577 * SRv6 VPN route change via netlink interface, using a dataplane context object
14791578 *
@@ -1497,17 +1596,14 @@ static ssize_t netlink_srv6_vpn_route_msg_encode(int cmd,
14971596 struct connected * connected ;
14981597 struct vrf * vrf ;
14991598 struct prefix * cp ;
1599+ unsigned int nexthop_num ;
15001600
15011601 struct {
15021602 struct nlmsghdr n ;
15031603 struct rtmsg r ;
15041604 char buf [];
15051605 } * req = (void * )data ;
15061606
1507- nexthop = dplane_ctx_get_ng (ctx )-> nexthop ;
1508- if (!nexthop || !nexthop -> nh_srv6 || sid_zero ((const struct seg6_seg_stack * )nexthop -> nh_srv6 -> seg6_segs ))
1509- return -1 ;
1510-
15111607 p = dplane_ctx_get_dest (ctx );
15121608
15131609 if (datalen < sizeof (* req ))
@@ -1572,6 +1668,79 @@ static ssize_t netlink_srv6_vpn_route_msg_encode(int cmd,
15721668 nl_msg_type_to_str (cmd ), p , dplane_ctx_get_vrf (ctx ),
15731669 table_id );
15741670
1671+ /*
1672+ * Counts the number of nexthops to determine if the route is singlepath
1673+ * (single nexthop) or multipath (multiple nexthops)
1674+ */
1675+ nexthop_num = 0 ;
1676+ for (ALL_NEXTHOPS_PTR (dplane_ctx_get_ng (ctx ), nexthop )) {
1677+ if (CHECK_FLAG (nexthop -> flags , NEXTHOP_FLAG_RECURSIVE ))
1678+ continue ;
1679+ if (!NEXTHOP_IS_ACTIVE (nexthop -> flags ))
1680+ continue ;
1681+
1682+ nexthop_num ++ ;
1683+ }
1684+
1685+ /* Multipath case */
1686+ if (nexthop_num > 1 ) {
1687+ struct rtattr * nest ;
1688+
1689+ nest = nl_attr_nest (& req -> n , datalen , RTA_MULTIPATH );
1690+ if (nest == NULL )
1691+ return 0 ;
1692+
1693+ nexthop_num = 0 ;
1694+ for (ALL_NEXTHOPS_PTR (dplane_ctx_get_ng (ctx ), nexthop )) {
1695+ if (CHECK_FLAG (nexthop -> flags , NEXTHOP_FLAG_RECURSIVE ))
1696+ continue ;
1697+
1698+ /* Skip non-SRv6 nexthops */
1699+ if (!nexthop -> nh_srv6 || sid_zero (nexthop -> nh_srv6 -> seg6_segs ))
1700+ continue ;
1701+
1702+ if (NEXTHOP_IS_ACTIVE (nexthop -> flags )) {
1703+ nexthop_num ++ ;
1704+
1705+ if (!netlink_srv6_vpn_route_msg_encode_multipath (cmd , ctx , data ,
1706+ datalen , nexthop ,
1707+ & req -> n , datalen ,
1708+ fpm , force_nhg ))
1709+ return 0 ;
1710+ }
1711+ }
1712+
1713+ nl_attr_nest_end (& req -> n , nest );
1714+
1715+ if (nexthop_num == 0 ) {
1716+ if (IS_ZEBRA_DEBUG_FPM )
1717+ zlog_debug ("%s: No useful nexthop." , __func__ );
1718+ }
1719+
1720+ return NLMSG_ALIGN (req -> n .nlmsg_len );
1721+ }
1722+
1723+ /* Singlepath case */
1724+ nexthop_num = 0 ;
1725+ for (ALL_NEXTHOPS_PTR (dplane_ctx_get_ng (ctx ), nexthop )) {
1726+ if (CHECK_FLAG (nexthop -> flags , NEXTHOP_FLAG_RECURSIVE ))
1727+ continue ;
1728+ if (!NEXTHOP_IS_ACTIVE (nexthop -> flags ))
1729+ continue ;
1730+ if (!nexthop -> nh_srv6 || sid_zero (nexthop -> nh_srv6 -> seg6_segs ))
1731+ continue ;
1732+
1733+ nexthop_num ++ ;
1734+ break ;
1735+ }
1736+
1737+ if (nexthop_num == 0 ) {
1738+ if (IS_ZEBRA_DEBUG_FPM )
1739+ zlog_debug ("%s: No useful nexthop." , __func__ );
1740+
1741+ return NLMSG_ALIGN (req -> n .nlmsg_len );
1742+ }
1743+
15751744 if (!nl_attr_put16 (& req -> n , datalen , RTA_ENCAP_TYPE ,
15761745 FPM_ROUTE_ENCAP_SRV6 ))
15771746 return false;
@@ -1625,20 +1794,16 @@ static ssize_t netlink_srv6_msg_encode(int cmd,
16251794 uint8_t * data , size_t datalen ,
16261795 bool fpm , bool force_nhg )
16271796{
1628- struct nexthop * nexthop = NULL ;
1629-
16301797 struct {
16311798 struct nlmsghdr n ;
16321799 struct rtmsg r ;
16331800 char buf [];
16341801 } * req = (void * )data ;
16351802
1636- nexthop = dplane_ctx_get_ng (ctx )-> nexthop ;
1637- if (!nexthop || !nexthop -> nh_srv6 )
1803+ if (!has_srv6_nexthop (ctx ))
16381804 return - 1 ;
16391805
1640- if (nexthop -> nh_srv6 -> seg6local_action !=
1641- ZEBRA_SEG6_LOCAL_ACTION_UNSPEC ) {
1806+ if (has_srv6_localsid_nexthop (ctx )) {
16421807 if (cmd == RTM_NEWROUTE )
16431808 cmd = RTM_NEWSRV6LOCALSID ;
16441809 else if (cmd == RTM_DELROUTE )
@@ -1647,7 +1812,7 @@ static ssize_t netlink_srv6_msg_encode(int cmd,
16471812 if (!netlink_srv6_localsid_msg_encode (
16481813 cmd , ctx , data , datalen , fpm , force_nhg ))
16491814 return 0 ;
1650- } else if (! sid_zero ( nexthop -> nh_srv6 -> seg6_segs )) {
1815+ } else if (has_srv6_sidlist_nexthop ( ctx )) {
16511816 if (force_nhg ){
16521817 if (!netlink_vpn_route_msg_encode (
16531818 cmd , ctx , data , datalen , force_nhg ))
@@ -2280,7 +2445,6 @@ static int fpm_nl_enqueue(struct fpm_nl_ctx *fnc, struct zebra_dplane_ctx *ctx)
22802445 ssize_t rv ;
22812446 uint64_t obytes , obytes_peak ;
22822447 enum dplane_op_e op = dplane_ctx_get_op (ctx );
2283- struct nexthop * nexthop ;
22842448
22852449 /*
22862450 * If we were configured to not use next hop groups, then quit as soon
@@ -2321,8 +2485,7 @@ static int fpm_nl_enqueue(struct fpm_nl_ctx *fnc, struct zebra_dplane_ctx *ctx)
23212485 switch (op ) {
23222486 case DPLANE_OP_ROUTE_UPDATE :
23232487 case DPLANE_OP_ROUTE_DELETE :
2324- nexthop = dplane_ctx_get_ng (ctx )-> nexthop ;
2325- if (nexthop && nexthop -> nh_srv6 ) {
2488+ if (has_srv6_nexthop (ctx )) {
23262489 rv = netlink_srv6_msg_encode (RTM_DELROUTE , ctx ,
23272490 nl_buf , sizeof (nl_buf ),
23282491 true, fnc -> use_nhg );
@@ -2352,8 +2515,7 @@ static int fpm_nl_enqueue(struct fpm_nl_ctx *fnc, struct zebra_dplane_ctx *ctx)
23522515
23532516 /* FALL THROUGH */
23542517 case DPLANE_OP_ROUTE_INSTALL :
2355- nexthop = dplane_ctx_get_ng (ctx )-> nexthop ;
2356- if (nexthop && nexthop -> nh_srv6 ) {
2518+ if (has_srv6_nexthop (ctx )) {
23572519 rv = netlink_srv6_msg_encode (
23582520 RTM_NEWROUTE , ctx , & nl_buf [nl_buf_len ],
23592521 sizeof (nl_buf ) - nl_buf_len , true, fnc -> use_nhg );
0 commit comments