@@ -21,6 +21,8 @@ using namespace swss;
2121#define VRF_PREFIX " Vrf"
2222#define MGMT_VRF_PREFIX " mgmt"
2323
24+ #define NHG_DELIMITER ' ,'
25+
2426#ifndef ETH_ALEN
2527#define ETH_ALEN 6
2628#endif
@@ -44,6 +46,7 @@ using namespace swss;
4446
4547RouteSync::RouteSync (RedisPipeline *pipeline) :
4648 m_routeTable(pipeline, APP_ROUTE_TABLE_NAME, true ),
49+ m_label_routeTable(pipeline, APP_LABEL_ROUTE_TABLE_NAME, true ),
4750 m_vnet_routeTable(pipeline, APP_VNET_RT_TABLE_NAME, true ),
4851 m_vnet_tunnelTable(pipeline, APP_VNET_RT_TUNNEL_TABLE_NAME, true ),
4952 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
113116void RouteSync::getEvpnNextHopSep (string& nexthops, string& vni_list,
114117 string& mac_list, string& intf_list)
115118{
116- nexthops += string ( " , " ) ;
117- vni_list += string ( " , " ) ;
118- mac_list += string ( " , " ) ;
119- intf_list += string ( " , " ) ;
119+ nexthops += NHG_DELIMITER ;
120+ vni_list += NHG_DELIMITER ;
121+ mac_list += NHG_DELIMITER ;
122+ intf_list += NHG_DELIMITER ;
120123
121124 return ;
122125}
@@ -571,6 +574,12 @@ void RouteSync::onMsg(int nlmsg_type, struct nl_object *obj)
571574
572575 /* Supports IPv4 or IPv6 address, otherwise return immediately */
573576 auto family = rtnl_route_get_family (route_obj);
577+ /* Check for Label route. */
578+ if (family == AF_MPLS)
579+ {
580+ onLabelRouteMsg (nlmsg_type, obj);
581+ return ;
582+ }
574583 if (family != AF_INET && family != AF_INET6)
575584 {
576585 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)
708717 }
709718
710719 /* Get nexthop lists */
711- string nexthops = getNextHopGw (route_obj);
712- string ifnames = getNextHopIf (route_obj);
720+ string gw_list;
721+ string intf_list;
722+ string mpls_list;
723+ getNextHopList (route_obj, gw_list, mpls_list, intf_list);
713724 string weights = getNextHopWt (route_obj);
714725
715- vector<string> alsv = tokenize (ifnames, ' , ' );
726+ vector<string> alsv = tokenize (intf_list, NHG_DELIMITER );
716727 for (auto alias : alsv)
717728 {
718729 /*
@@ -722,17 +733,22 @@ void RouteSync::onRouteMsg(int nlmsg_type, struct nl_object *obj, char *vrf)
722733 if (alias == " eth0" || alias == " docker0" )
723734 {
724735 SWSS_LOG_DEBUG (" Skip routes to eth0 or docker0: %s %s %s" ,
725- destipprefix, nexthops .c_str (), ifnames .c_str ());
736+ destipprefix, gw_list .c_str (), intf_list .c_str ());
726737 return ;
727738 }
728739 }
729740
730741 vector<FieldValueTuple> fvVector;
731- FieldValueTuple nh (" nexthop" , nexthops );
732- FieldValueTuple idx (" ifname" , ifnames );
742+ FieldValueTuple gw (" nexthop" , gw_list );
743+ FieldValueTuple intf (" ifname" , intf_list );
733744
734- fvVector.push_back (nh);
735- fvVector.push_back (idx);
745+ fvVector.push_back (gw);
746+ fvVector.push_back (intf);
747+ if (!mpls_list.empty ())
748+ {
749+ FieldValueTuple mpls_nh (" mpls_nh" , mpls_list);
750+ fvVector.push_back (mpls_nh);
751+ }
736752 if (!weights.empty ())
737753 {
738754 FieldValueTuple wt (" weight" , weights);
@@ -742,8 +758,8 @@ void RouteSync::onRouteMsg(int nlmsg_type, struct nl_object *obj, char *vrf)
742758 if (!warmRestartInProgress)
743759 {
744760 m_routeTable.set (destipprefix, fvVector);
745- SWSS_LOG_DEBUG (" RouteTable set msg: %s %s %s" ,
746- destipprefix, nexthops .c_str (), ifnames .c_str ());
761+ SWSS_LOG_DEBUG (" RouteTable set msg: %s %s %s %s " , destipprefix ,
762+ gw_list. c_str (), intf_list .c_str (), mpls_list .c_str ());
747763 }
748764
749765 /*
@@ -752,8 +768,8 @@ void RouteSync::onRouteMsg(int nlmsg_type, struct nl_object *obj, char *vrf)
752768 */
753769 else
754770 {
755- SWSS_LOG_INFO (" Warm-Restart mode: RouteTable set msg: %s %s %s" ,
756- destipprefix, nexthops .c_str (), ifnames .c_str ());
771+ SWSS_LOG_INFO (" Warm-Restart mode: RouteTable set msg: %s %s %s %s " , destipprefix ,
772+ gw_list. c_str (), intf_list .c_str (), mpls_list .c_str ());
757773
758774 const KeyOpFieldsValuesTuple kfv = std::make_tuple (destipprefix,
759775 SET_COMMAND,
@@ -763,6 +779,98 @@ void RouteSync::onRouteMsg(int nlmsg_type, struct nl_object *obj, char *vrf)
763779}
764780
765781/*
782+ * Handle label route
783+ * @arg nlmsg_type Netlink message type
784+ * @arg obj Netlink object
785+ */
786+ void RouteSync::onLabelRouteMsg (int nlmsg_type, struct nl_object *obj)
787+ {
788+ struct rtnl_route *route_obj = (struct rtnl_route *)obj;
789+ struct nl_addr *daddr;
790+ char destaddr[MAX_ADDR_SIZE + 1 ] = {0 };
791+
792+ daddr = rtnl_route_get_dst (route_obj);
793+ nl_addr2str (daddr, destaddr, MAX_ADDR_SIZE);
794+ SWSS_LOG_INFO (" Receive new LabelRoute message dest addr: %s" , destaddr);
795+ if (nl_addr_iszero (daddr)) return ;
796+
797+ if (nlmsg_type == RTM_DELROUTE)
798+ {
799+ m_label_routeTable.del (destaddr);
800+ return ;
801+ }
802+ else if (nlmsg_type != RTM_NEWROUTE)
803+ {
804+ SWSS_LOG_INFO (" Unknown message-type: %d for LabelRoute %s" , nlmsg_type, destaddr);
805+ return ;
806+ }
807+
808+ /* Get the index of the master device */
809+ uint32_t master_index = rtnl_route_get_table (route_obj);
810+ /* if the table_id is not set in the route obj then route is for default vrf. */
811+ if (master_index)
812+ {
813+ SWSS_LOG_INFO (" Unsupported Non-default VRF: %d for LabelRoute %s" ,
814+ master_index, destaddr);
815+ return ;
816+ }
817+
818+ switch (rtnl_route_get_type (route_obj))
819+ {
820+ case RTN_BLACKHOLE:
821+ {
822+ vector<FieldValueTuple> fvVector;
823+ FieldValueTuple fv (" blackhole" , " true" );
824+ fvVector.push_back (fv);
825+ m_label_routeTable.set (destaddr, fvVector);
826+ return ;
827+ }
828+ case RTN_UNICAST:
829+ break ;
830+
831+ case RTN_MULTICAST:
832+ case RTN_BROADCAST:
833+ case RTN_LOCAL:
834+ SWSS_LOG_INFO (" BUM routes aren't supported yet (%s)" , destaddr);
835+ return ;
836+
837+ default :
838+ return ;
839+ }
840+
841+ struct nl_list_head *nhs = rtnl_route_get_nexthops (route_obj);
842+ if (!nhs)
843+ {
844+ SWSS_LOG_INFO (" Nexthop list is empty for LabelRoute %s" , destaddr);
845+ return ;
846+ }
847+
848+ /* Get nexthop lists */
849+ string gw_list;
850+ string intf_list;
851+ string mpls_list;
852+ getNextHopList (route_obj, gw_list, mpls_list, intf_list);
853+
854+ vector<FieldValueTuple> fvVector;
855+ FieldValueTuple gw (" nexthop" , gw_list);
856+ FieldValueTuple intf (" ifname" , intf_list);
857+ FieldValueTuple mpls_pop (" mpls_pop" , " 1" );
858+
859+ fvVector.push_back (gw);
860+ fvVector.push_back (intf);
861+ if (!mpls_list.empty ())
862+ {
863+ FieldValueTuple mpls_nh (" mpls_nh" , mpls_list);
864+ fvVector.push_back (mpls_nh);
865+ }
866+ fvVector.push_back (mpls_pop);
867+
868+ m_label_routeTable.set (destaddr, fvVector);
869+ SWSS_LOG_INFO (" LabelRouteTable set msg: %s %s %s %s" , destaddr,
870+ gw_list.c_str (), intf_list.c_str (), mpls_list.c_str ());
871+ }
872+
873+ /*
766874 * Handle vnet route
767875 * @arg nlmsg_type Netlink message type
768876 * @arg obj Netlink object
@@ -902,6 +1010,110 @@ bool RouteSync::getIfName(int if_index, char *if_name, size_t name_len)
9021010 return true ;
9031011}
9041012
1013+ /*
1014+ * getNextHopList() - parses next hop list attached to route_obj
1015+ * @arg route_obj (input) Netlink route object
1016+ * @arg gw_list (output) comma-separated list of NH IP gateways
1017+ * @arg mpls_list (output) comma-separated list of NH MPLS info
1018+ * @arg intf_list (output) comma-separated list of NH interfaces
1019+ *
1020+ * Return void
1021+ */
1022+ void RouteSync::getNextHopList (struct rtnl_route *route_obj, string& gw_list,
1023+ string& mpls_list, string& intf_list)
1024+ {
1025+ bool mpls_found = false ;
1026+
1027+ for (int i = 0 ; i < rtnl_route_get_nnexthops (route_obj); i++)
1028+ {
1029+ struct rtnl_nexthop *nexthop = rtnl_route_nexthop_n (route_obj, i);
1030+ struct nl_addr *addr = NULL ;
1031+
1032+ /* RTA_GATEWAY is NH gateway info for IP routes only */
1033+ if ((addr = rtnl_route_nh_get_gateway (nexthop)))
1034+ {
1035+ char gw_ip[MAX_ADDR_SIZE + 1 ] = {0 };
1036+ nl_addr2str (addr, gw_ip, MAX_ADDR_SIZE);
1037+ gw_list += gw_ip;
1038+
1039+ /* LWTUNNEL_ENCAP_MPLS RTA_DST is MPLS NH label stack for IP routes only */
1040+ if ((addr = rtnl_route_nh_get_encap_mpls_dst (nexthop)))
1041+ {
1042+ char labelstack[MAX_ADDR_SIZE + 1 ] = {0 };
1043+ nl_addr2str (addr, labelstack, MAX_ADDR_SIZE);
1044+ mpls_list += string (" push" );
1045+ mpls_list += labelstack;
1046+ mpls_found = true ;
1047+ }
1048+ /* Filler for proper parsing in routeorch */
1049+ else
1050+ {
1051+ mpls_list += string (" na" );
1052+ }
1053+ }
1054+ /* RTA_VIA is NH gateway info for MPLS routes only */
1055+ else if ((addr = rtnl_route_nh_get_via (nexthop)))
1056+ {
1057+ char gw_ip[MAX_ADDR_SIZE + 1 ] = {0 };
1058+ nl_addr2str (addr, gw_ip, MAX_ADDR_SIZE);
1059+ gw_list += gw_ip;
1060+
1061+ /* RTA_NEWDST is MPLS NH label stack for MPLS routes only */
1062+ if ((addr = rtnl_route_nh_get_newdst (nexthop)))
1063+ {
1064+ char labelstack[MAX_ADDR_SIZE + 1 ] = {0 };
1065+ nl_addr2str (addr, labelstack, MAX_ADDR_SIZE);
1066+ mpls_list += string (" swap" );
1067+ mpls_list += labelstack;
1068+ mpls_found = true ;
1069+ }
1070+ /* Filler for proper parsing in routeorch */
1071+ else
1072+ {
1073+ mpls_list += string (" na" );
1074+ }
1075+ }
1076+ else
1077+ {
1078+ if (rtnl_route_get_family (route_obj) == AF_INET6)
1079+ {
1080+ gw_list += " ::" ;
1081+ }
1082+ /* for MPLS route, use IPv4 as default gateway. */
1083+ else
1084+ {
1085+ gw_list += " 0.0.0.0" ;
1086+ }
1087+ mpls_list += string (" na" );
1088+ }
1089+
1090+ /* Get the ID of next hop interface */
1091+ unsigned if_index = rtnl_route_nh_get_ifindex (nexthop);
1092+ char if_name[IFNAMSIZ] = " 0" ;
1093+ if (getIfName (if_index, if_name, IFNAMSIZ))
1094+ {
1095+ intf_list += if_name;
1096+ }
1097+ /* If we cannot get the interface name */
1098+ else
1099+ {
1100+ intf_list += " unknown" ;
1101+ }
1102+
1103+ if (i + 1 < rtnl_route_get_nnexthops (route_obj))
1104+ {
1105+ gw_list += NHG_DELIMITER;
1106+ mpls_list += NHG_DELIMITER;
1107+ intf_list += NHG_DELIMITER;
1108+ }
1109+ }
1110+
1111+ if (!mpls_found)
1112+ {
1113+ mpls_list.clear ();
1114+ }
1115+ }
1116+
9051117/*
9061118 * Get next hop gateway IP addresses
9071119 * @arg route_obj route object
@@ -938,7 +1150,7 @@ string RouteSync::getNextHopGw(struct rtnl_route *route_obj)
9381150
9391151 if (i + 1 < rtnl_route_get_nnexthops (route_obj))
9401152 {
941- result += string ( " , " ) ;
1153+ result += NHG_DELIMITER ;
9421154 }
9431155 }
9441156
@@ -972,7 +1184,7 @@ string RouteSync::getNextHopIf(struct rtnl_route *route_obj)
9721184
9731185 if (i + 1 < rtnl_route_get_nnexthops (route_obj))
9741186 {
975- result += string ( " , " ) ;
1187+ result += NHG_DELIMITER ;
9761188 }
9771189 }
9781190
0 commit comments