@@ -604,6 +604,99 @@ def is_ipaddress(val):
604604 return False
605605 return True
606606
607+ def interface_is_in_vlan (vlan_member_table , interface_name ):
608+ """ Check if an interface is in a vlan """
609+ for _ ,intf in vlan_member_table .keys ():
610+ if intf == interface_name :
611+ return True
612+
613+ return False
614+
615+ def interface_is_in_portchannel (portchannel_member_table , interface_name ):
616+ """ Check if an interface is part of portchannel """
617+ for _ ,intf in portchannel_member_table .keys ():
618+ if intf == interface_name :
619+ return True
620+
621+ return False
622+
623+ def interface_is_router_port (interface_table , interface_name ):
624+ """ Check if an interface has router config """
625+ for intf in interface_table .keys ():
626+ if (interface_name == intf [0 ]):
627+ return True
628+
629+ return False
630+
631+ def interface_is_mirror_dst_port (config_db , interface_name ):
632+ """ Check if port is already configured as mirror destination port """
633+ mirror_table = config_db .get_table ('MIRROR_SESSION' )
634+ for _ ,v in mirror_table .items ():
635+ if 'dst_port' in v and v ['dst_port' ] == interface_name :
636+ return True
637+
638+ return False
639+
640+ def interface_has_mirror_config (mirror_table , interface_name ):
641+ """ Check if port is already configured with mirror config """
642+ for _ ,v in mirror_table .items ():
643+ if 'src_port' in v and v ['src_port' ] == interface_name :
644+ return True
645+ if 'dst_port' in v and v ['dst_port' ] == interface_name :
646+ return True
647+
648+ return False
649+
650+ def validate_mirror_session_config (config_db , session_name , dst_port , src_port , direction ):
651+ """ Check if SPAN mirror-session config is valid """
652+ if len (config_db .get_entry ('MIRROR_SESSION' , session_name )) != 0 :
653+ click .echo ("Error: {} already exists" .format (session_name ))
654+ return False
655+
656+ vlan_member_table = config_db .get_table ('VLAN_MEMBER' )
657+ mirror_table = config_db .get_table ('MIRROR_SESSION' )
658+ portchannel_member_table = config_db .get_table ('PORTCHANNEL_MEMBER' )
659+ interface_table = config_db .get_table ('INTERFACE' )
660+
661+ if dst_port :
662+ if not interface_name_is_valid (dst_port ):
663+ click .echo ("Error: Destination Interface {} is invalid" .format (dst_port ))
664+ return False
665+
666+ if interface_is_in_vlan (vlan_member_table , dst_port ):
667+ click .echo ("Error: Destination Interface {} has vlan config" .format (dst_port ))
668+ return False
669+
670+ if interface_has_mirror_config (mirror_table , dst_port ):
671+ click .echo ("Error: Destination Interface {} already has mirror config" .format (dst_port ))
672+ return False
673+
674+ if interface_is_in_portchannel (portchannel_member_table , dst_port ):
675+ click .echo ("Error: Destination Interface {} has portchannel config" .format (dst_port ))
676+ return False
677+
678+ if interface_is_router_port (interface_table , dst_port ):
679+ click .echo ("Error: Destination Interface {} is a L3 interface" .format (dst_port ))
680+ return False
681+
682+ if src_port :
683+ for port in src_port .split ("," ):
684+ if not interface_name_is_valid (port ):
685+ click .echo ("Error: Source Interface {} is invalid" .format (port ))
686+ return False
687+ if dst_port and dst_port == port :
688+ click .echo ("Error: Destination Interface cant be same as Source Interface" )
689+ return False
690+ if interface_has_mirror_config (mirror_table , port ):
691+ click .echo ("Error: Source Interface {} already has mirror config" .format (port ))
692+ return False
693+
694+ if direction :
695+ if direction not in ['rx' , 'tx' , 'both' ]:
696+ click .echo ("Error: Direction {} is invalid" .format (direction ))
697+ return False
698+
699+ return True
607700
608701# This is our main entrypoint - the main 'config' command
609702@click .group (cls = AbbreviationGroup , context_settings = CONTEXT_SETTINGS )
@@ -1030,6 +1123,8 @@ def portchannel_member(ctx):
10301123def add_portchannel_member (ctx , portchannel_name , port_name ):
10311124 """Add member to port channel"""
10321125 db = ctx .obj ['db' ]
1126+ if interface_is_mirror_dst_port (db , port_name ):
1127+ ctx .fail ("{} is configured as mirror destination port" .format (port_name ))
10331128 db .set_entry ('PORTCHANNEL_MEMBER' , (portchannel_name , port_name ),
10341129 {'NULL' : 'NULL' })
10351130
@@ -1051,7 +1146,11 @@ def del_portchannel_member(ctx, portchannel_name, port_name):
10511146def mirror_session ():
10521147 pass
10531148
1054- @mirror_session .command ()
1149+ #
1150+ # 'add' subgroup ('config mirror_session add ...')
1151+ #
1152+
1153+ @mirror_session .command ('add' )
10551154@click .argument ('session_name' , metavar = '<session_name>' , required = True )
10561155@click .argument ('src_ip' , metavar = '<src_ip>' , required = True )
10571156@click .argument ('dst_ip' , metavar = '<dst_ip>' , required = True )
@@ -1061,46 +1160,144 @@ def mirror_session():
10611160@click .argument ('queue' , metavar = '[queue]' , required = False )
10621161@click .option ('--policer' )
10631162def add (session_name , src_ip , dst_ip , dscp , ttl , gre_type , queue , policer ):
1064- """
1065- Add mirror session
1066- """
1163+ """ Add ERSPAN mirror session.(Legacy support) """
1164+ add_erspan (session_name , src_ip , dst_ip , dscp , ttl , gre_type , queue , policer )
1165+
1166+ @mirror_session .group (cls = AbbreviationGroup , name = 'erspan' )
1167+ @click .pass_context
1168+ def erspan (ctx ):
1169+ """ ERSPAN mirror_session """
1170+ pass
1171+
1172+
1173+ #
1174+ # 'add' subcommand
1175+ #
1176+
1177+ @erspan .command ('add' )
1178+ @click .argument ('session_name' , metavar = '<session_name>' , required = True )
1179+ @click .argument ('src_ip' , metavar = '<src_ip>' , required = True )
1180+ @click .argument ('dst_ip' , metavar = '<dst_ip>' , required = True )
1181+ @click .argument ('dscp' , metavar = '<dscp>' , required = True )
1182+ @click .argument ('ttl' , metavar = '<ttl>' , required = True )
1183+ @click .argument ('gre_type' , metavar = '[gre_type]' , required = False )
1184+ @click .argument ('queue' , metavar = '[queue]' , required = False )
1185+ @click .argument ('src_port' , metavar = '[src_port]' , required = False )
1186+ @click .argument ('direction' , metavar = '[direction]' , required = False )
1187+ @click .option ('--policer' )
1188+ def add (session_name , src_ip , dst_ip , dscp , ttl , gre_type , queue , policer , src_port , direction ):
1189+ """ Add ERSPAN mirror session """
1190+ add_erspan (session_name , src_ip , dst_ip , dscp , ttl , gre_type , queue , policer , src_port , direction )
1191+
1192+ def gather_session_info (session_info , policer , queue , src_port , direction ):
1193+ if policer :
1194+ session_info ['policer' ] = policer
1195+
1196+ if queue :
1197+ session_info ['queue' ] = queue
1198+
1199+ if src_port :
1200+ if get_interface_naming_mode () == "alias" :
1201+ src_port_list = []
1202+ for port in src_port .split ("," ):
1203+ src_port_list .append (interface_alias_to_name (port ))
1204+ src_port = "," .join (src_port_list )
1205+
1206+ session_info ['src_port' ] = src_port
1207+ if not direction :
1208+ direction = "both"
1209+ session_info ['direction' ] = direction .upper ()
1210+
1211+ return session_info
1212+
1213+ def add_erspan (session_name , src_ip , dst_ip , dscp , ttl , gre_type , queue , policer , src_port = None , direction = None ):
10671214 session_info = {
1215+ "type" : "ERSPAN" ,
10681216 "src_ip" : src_ip ,
10691217 "dst_ip" : dst_ip ,
10701218 "dscp" : dscp ,
10711219 "ttl" : ttl
10721220 }
10731221
1074- if policer is not None :
1075- session_info ['policer' ] = policer
1076-
1077- if gre_type is not None :
1222+ if gre_type :
10781223 session_info ['gre_type' ] = gre_type
10791224
1080- if queue is not None :
1081- session_info ['queue' ] = queue
1082-
1225+ session_info = gather_session_info (session_info , policer , queue , src_port , direction )
1226+
10831227 """
10841228 For multi-npu platforms we need to program all front asic namespaces
10851229 """
10861230 namespaces = sonic_device_util .get_all_namespaces ()
10871231 if not namespaces ['front_ns' ]:
10881232 config_db = ConfigDBConnector ()
10891233 config_db .connect ()
1234+ if validate_mirror_session_config (config_db , session_name , None , src_port , direction ) is False :
1235+ return
10901236 config_db .set_entry ("MIRROR_SESSION" , session_name , session_info )
10911237 else :
10921238 per_npu_configdb = {}
10931239 for front_asic_namespaces in namespaces ['front_ns' ]:
10941240 per_npu_configdb [front_asic_namespaces ] = ConfigDBConnector (use_unix_socket_path = True , namespace = front_asic_namespaces )
10951241 per_npu_configdb [front_asic_namespaces ].connect ()
1242+ if validate_mirror_session_config (per_npu_configdb [front_asic_namespaces ], session_name , None , src_port , direction ) is False :
1243+ return
10961244 per_npu_configdb [front_asic_namespaces ].set_entry ("MIRROR_SESSION" , session_name , session_info )
10971245
1098- @mirror_session .command ()
1246+ @mirror_session .group (cls = AbbreviationGroup , name = 'span' )
1247+ @click .pass_context
1248+ def span (ctx ):
1249+ """ SPAN mirror session """
1250+ pass
1251+
1252+ @span .command ('add' )
10991253@click .argument ('session_name' , metavar = '<session_name>' , required = True )
1100- def remove (session_name ):
1254+ @click .argument ('dst_port' , metavar = '<dst_port>' , required = True )
1255+ @click .argument ('src_port' , metavar = '[src_port]' , required = False )
1256+ @click .argument ('direction' , metavar = '[direction]' , required = False )
1257+ @click .argument ('queue' , metavar = '[queue]' , required = False )
1258+ @click .option ('--policer' )
1259+ def add (session_name , dst_port , src_port , direction , queue , policer ):
1260+ """ Add SPAN mirror session """
1261+ add_span (session_name , dst_port , src_port , direction , queue , policer )
1262+
1263+ def add_span (session_name , dst_port , src_port , direction , queue , policer ):
1264+ if get_interface_naming_mode () == "alias" :
1265+ dst_port = interface_alias_to_name (dst_port )
1266+ if dst_port is None :
1267+ click .echo ("Error: Destination Interface {} is invalid" .format (dst_port ))
1268+ return
1269+
1270+ session_info = {
1271+ "type" : "SPAN" ,
1272+ "dst_port" : dst_port ,
1273+ }
1274+
1275+ session_info = gather_session_info (session_info , policer , queue , src_port , direction )
1276+
11011277 """
1102- Delete mirror session
1278+ For multi-npu platforms we need to program all front asic namespaces
11031279 """
1280+ namespaces = sonic_device_util .get_all_namespaces ()
1281+ if not namespaces ['front_ns' ]:
1282+ config_db = ConfigDBConnector ()
1283+ config_db .connect ()
1284+ if validate_mirror_session_config (config_db , session_name , dst_port , src_port , direction ) is False :
1285+ return
1286+ config_db .set_entry ("MIRROR_SESSION" , session_name , session_info )
1287+ else :
1288+ per_npu_configdb = {}
1289+ for front_asic_namespaces in namespaces ['front_ns' ]:
1290+ per_npu_configdb [front_asic_namespaces ] = ConfigDBConnector (use_unix_socket_path = True , namespace = front_asic_namespaces )
1291+ per_npu_configdb [front_asic_namespaces ].connect ()
1292+ if validate_mirror_session_config (per_npu_configdb [front_asic_namespaces ], session_name , dst_port , src_port , direction ) is False :
1293+ return
1294+ per_npu_configdb [front_asic_namespaces ].set_entry ("MIRROR_SESSION" , session_name , session_info )
1295+
1296+
1297+ @mirror_session .command ()
1298+ @click .argument ('session_name' , metavar = '<session_name>' , required = True )
1299+ def remove (session_name ):
1300+ """ Delete mirror session """
11041301
11051302 """
11061303 For multi-npu platforms we need to program all front asic namespaces
@@ -1116,6 +1313,7 @@ def remove(session_name):
11161313 per_npu_configdb [front_asic_namespaces ] = ConfigDBConnector (use_unix_socket_path = True , namespace = front_asic_namespaces )
11171314 per_npu_configdb [front_asic_namespaces ].connect ()
11181315 per_npu_configdb [front_asic_namespaces ].set_entry ("MIRROR_SESSION" , session_name , None )
1316+
11191317#
11201318# 'pfcwd' group ('config pfcwd ...')
11211319#
@@ -1390,6 +1588,9 @@ def add_vlan_member(ctx, vid, interface_name, untagged):
13901588
13911589 if len (vlan ) == 0 :
13921590 ctx .fail ("{} doesn't exist" .format (vlan_name ))
1591+ if interface_is_mirror_dst_port (db , interface_name ):
1592+ ctx .fail ("{} is configured as mirror destination port" .format (interface_name ))
1593+
13931594 members = vlan .get ('members' , [])
13941595 if interface_name in members :
13951596 if get_interface_naming_mode () == "alias" :
@@ -1404,7 +1605,7 @@ def add_vlan_member(ctx, vid, interface_name, untagged):
14041605 for entry in interface_table :
14051606 if (interface_name == entry [0 ]):
14061607 ctx .fail ("{} is a L3 interface!" .format (interface_name ))
1407-
1608+
14081609 members .append (interface_name )
14091610 vlan ['members' ] = members
14101611 db .set_entry ('VLAN' , vlan_name , vlan )
0 commit comments