@@ -140,11 +140,11 @@ def delete_vnet_local_routes(dvs, prefix, vnet_name):
140140 time .sleep (2 )
141141
142142
143- def create_vnet_routes (dvs , prefix , vnet_name , endpoint , mac = "" , vni = 0 , ep_monitor = "" , profile = "" , primary = "" , monitoring = "" , rx_monitor_timer = - 1 , tx_monitor_timer = - 1 , adv_prefix = "" , check_directly_connected = False ):
144- set_vnet_routes (dvs , prefix , vnet_name , endpoint , mac = mac , vni = vni , ep_monitor = ep_monitor , profile = profile , primary = primary , monitoring = monitoring , rx_monitor_timer = rx_monitor_timer , tx_monitor_timer = tx_monitor_timer , adv_prefix = adv_prefix , check_directly_connected = check_directly_connected )
143+ def create_vnet_routes (dvs , prefix , vnet_name , endpoint , mac = "" , vni = 0 , ep_monitor = "" , profile = "" , primary = "" , monitoring = "" , rx_monitor_timer = - 1 , tx_monitor_timer = - 1 , adv_prefix = "" , check_directly_connected = False , consistent_hashing_buckets = 0 ):
144+ set_vnet_routes (dvs , prefix , vnet_name , endpoint , mac = mac , vni = vni , ep_monitor = ep_monitor , profile = profile , primary = primary , monitoring = monitoring , rx_monitor_timer = rx_monitor_timer , tx_monitor_timer = tx_monitor_timer , adv_prefix = adv_prefix , check_directly_connected = check_directly_connected , consistent_hashing_buckets = consistent_hashing_buckets )
145145
146146
147- def set_vnet_routes (dvs , prefix , vnet_name , endpoint , mac = "" , vni = 0 , ep_monitor = "" , profile = "" , primary = "" , monitoring = "" , rx_monitor_timer = - 1 , tx_monitor_timer = - 1 , adv_prefix = "" , check_directly_connected = False ):
147+ def set_vnet_routes (dvs , prefix , vnet_name , endpoint , mac = "" , vni = 0 , ep_monitor = "" , profile = "" , primary = "" , monitoring = "" , rx_monitor_timer = - 1 , tx_monitor_timer = - 1 , adv_prefix = "" , check_directly_connected = False , consistent_hashing_buckets = 0 ):
148148 conf_db = swsscommon .DBConnector (swsscommon .CONFIG_DB , dvs .redis_sock , 0 )
149149
150150 attrs = [
@@ -181,6 +181,9 @@ def set_vnet_routes(dvs, prefix, vnet_name, endpoint, mac="", vni=0, ep_monitor=
181181 if tx_monitor_timer != - 1 :
182182 attrs .append (('tx_monitor_timer' , str (tx_monitor_timer )))
183183
184+ if consistent_hashing_buckets > 0 :
185+ attrs .append (('consistent_hashing_buckets' , str (consistent_hashing_buckets )))
186+
184187 tbl = swsscommon .Table (conf_db , "VNET_ROUTE_TUNNEL" )
185188 fvs = swsscommon .FieldValuePairs (attrs )
186189 tbl .set ("%s|%s" % (vnet_name , prefix ), fvs )
@@ -1222,6 +1225,71 @@ def check_vnet_ecmp_routes(self, dvs, name, endpoints, tunnel, mac=[], vni=[], r
12221225
12231226 return new_route , new_nhg
12241227
1228+ def check_vnet_fine_grained_ecmp_routes (self , dvs , name , endpoints , tunnel , bucket_size , route_ids = [], mac = [], vni = []):
1229+ asic_db = swsscommon .DBConnector (swsscommon .ASIC_DB , dvs .redis_sock , 0 )
1230+
1231+ vr_ids = self .vnet_route_ids (dvs , name )
1232+ count = len (vr_ids )
1233+
1234+ # Validate that next hop group is of type FINE_GRAIN_ECMP
1235+ if route_ids :
1236+ new_route = route_ids
1237+ else :
1238+ new_route = get_created_entries (asic_db , self .ASIC_ROUTE_ENTRY , self .routes , count )
1239+
1240+ # Get the next hop group ID from the route
1241+ fvs = asic_db .get_entry (self .ASIC_ROUTE_ENTRY , new_route [0 ])
1242+ nhgid = fvs .get ("SAI_ROUTE_ENTRY_ATTR_NEXT_HOP_ID" )
1243+ assert nhgid , "Next hop group ID not found"
1244+
1245+ # Check that the next hop group is of type FINE_GRAIN_ECMP
1246+ nhg_fvs = asic_db .get_entry (self .ASIC_NEXT_HOP_GROUP , nhgid )
1247+ nhg_type = nhg_fvs .get ("SAI_NEXT_HOP_GROUP_ATTR_TYPE" )
1248+ assert nhg_type == "SAI_NEXT_HOP_GROUP_TYPE_FINE_GRAIN_ECMP" , f"Expected FINE_GRAIN_ECMP, got { nhg_type } "
1249+
1250+ # Check that configured size matches bucket_size
1251+ nhg_cfg_size = nhg_fvs .get ("SAI_NEXT_HOP_GROUP_ATTR_CONFIGURED_SIZE" )
1252+ assert int (nhg_cfg_size ) == bucket_size , f"Expected bucket size { bucket_size } , got { nhg_cfg_size } "
1253+
1254+ # Check that next hop group members exist and match bucket size
1255+ nhg_members = asic_db .get_keys (self .ASIC_NEXT_HOP_GROUP_MEMBER )
1256+ member_count = 0
1257+ for member in nhg_members :
1258+ fvs = asic_db .get_entry (self .ASIC_NEXT_HOP_GROUP_MEMBER , member )
1259+ if fvs .get ("SAI_NEXT_HOP_GROUP_MEMBER_ATTR_NEXT_HOP_GROUP_ID" ) == nhgid :
1260+ member_count += 1
1261+
1262+ assert member_count == bucket_size , f"Expected { bucket_size } members, found { member_count } "
1263+
1264+ # Verify endpoints are properly configured
1265+ expected_attrs = {}
1266+ for idx , endpoint in enumerate (endpoints ):
1267+ expected_attr = {
1268+ "SAI_NEXT_HOP_ATTR_TYPE" : "SAI_NEXT_HOP_TYPE_TUNNEL_ENCAP" ,
1269+ "SAI_NEXT_HOP_ATTR_IP" : endpoint ,
1270+ "SAI_NEXT_HOP_ATTR_TUNNEL_ID" : self .tunnel [tunnel ],
1271+ }
1272+ if vni and vni [idx ]:
1273+ expected_attr .update ({'SAI_NEXT_HOP_ATTR_TUNNEL_VNI' : vni [idx ]})
1274+ if mac and mac [idx ]:
1275+ expected_attr .update ({'SAI_NEXT_HOP_ATTR_TUNNEL_MAC' : mac [idx ]})
1276+ expected_attrs [endpoint ] = expected_attr
1277+
1278+ # Verify routes are in correct VRF
1279+ asic_vrs = set ()
1280+ for idx in range (count ):
1281+ check_object (asic_db , self .ASIC_ROUTE_ENTRY , new_route [idx ],
1282+ {
1283+ "SAI_ROUTE_ENTRY_ATTR_NEXT_HOP_ID" : nhgid ,
1284+ })
1285+ rt_key = json .loads (new_route [idx ])
1286+ asic_vrs .add (rt_key ['vr' ])
1287+
1288+ assert asic_vrs == vr_ids
1289+ self .routes .update (new_route )
1290+
1291+ return new_route , nhgid
1292+
12251293 def check_priority_vnet_ecmp_routes (self , dvs , name , endpoints_primary , tunnel , mac = [], vni = [], route_ids = [], count = 1 , prefix = "" ):
12261294 asic_db = swsscommon .DBConnector (swsscommon .ASIC_DB , dvs .redis_sock , 0 )
12271295 endpoint_str_primary = name + "|" + self .serialize_endpoint_group (endpoints_primary )
0 commit comments