@@ -604,6 +604,99 @@ def is_ipaddress(val):
604
604
return False
605
605
return True
606
606
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
607
700
608
701
# This is our main entrypoint - the main 'config' command
609
702
@click .group (cls = AbbreviationGroup , context_settings = CONTEXT_SETTINGS )
@@ -1030,6 +1123,8 @@ def portchannel_member(ctx):
1030
1123
def add_portchannel_member (ctx , portchannel_name , port_name ):
1031
1124
"""Add member to port channel"""
1032
1125
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 ))
1033
1128
db .set_entry ('PORTCHANNEL_MEMBER' , (portchannel_name , port_name ),
1034
1129
{'NULL' : 'NULL' })
1035
1130
@@ -1051,7 +1146,11 @@ def del_portchannel_member(ctx, portchannel_name, port_name):
1051
1146
def mirror_session ():
1052
1147
pass
1053
1148
1054
- @mirror_session .command ()
1149
+ #
1150
+ # 'add' subgroup ('config mirror_session add ...')
1151
+ #
1152
+
1153
+ @mirror_session .command ('add' )
1055
1154
@click .argument ('session_name' , metavar = '<session_name>' , required = True )
1056
1155
@click .argument ('src_ip' , metavar = '<src_ip>' , required = True )
1057
1156
@click .argument ('dst_ip' , metavar = '<dst_ip>' , required = True )
@@ -1061,46 +1160,144 @@ def mirror_session():
1061
1160
@click .argument ('queue' , metavar = '[queue]' , required = False )
1062
1161
@click .option ('--policer' )
1063
1162
def 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 ):
1067
1214
session_info = {
1215
+ "type" : "ERSPAN" ,
1068
1216
"src_ip" : src_ip ,
1069
1217
"dst_ip" : dst_ip ,
1070
1218
"dscp" : dscp ,
1071
1219
"ttl" : ttl
1072
1220
}
1073
1221
1074
- if policer is not None :
1075
- session_info ['policer' ] = policer
1076
-
1077
- if gre_type is not None :
1222
+ if gre_type :
1078
1223
session_info ['gre_type' ] = gre_type
1079
1224
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
+
1083
1227
"""
1084
1228
For multi-npu platforms we need to program all front asic namespaces
1085
1229
"""
1086
1230
namespaces = sonic_device_util .get_all_namespaces ()
1087
1231
if not namespaces ['front_ns' ]:
1088
1232
config_db = ConfigDBConnector ()
1089
1233
config_db .connect ()
1234
+ if validate_mirror_session_config (config_db , session_name , None , src_port , direction ) is False :
1235
+ return
1090
1236
config_db .set_entry ("MIRROR_SESSION" , session_name , session_info )
1091
1237
else :
1092
1238
per_npu_configdb = {}
1093
1239
for front_asic_namespaces in namespaces ['front_ns' ]:
1094
1240
per_npu_configdb [front_asic_namespaces ] = ConfigDBConnector (use_unix_socket_path = True , namespace = front_asic_namespaces )
1095
1241
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
1096
1244
per_npu_configdb [front_asic_namespaces ].set_entry ("MIRROR_SESSION" , session_name , session_info )
1097
1245
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' )
1099
1253
@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
+
1101
1277
"""
1102
- Delete mirror session
1278
+ For multi-npu platforms we need to program all front asic namespaces
1103
1279
"""
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 """
1104
1301
1105
1302
"""
1106
1303
For multi-npu platforms we need to program all front asic namespaces
@@ -1116,6 +1313,7 @@ def remove(session_name):
1116
1313
per_npu_configdb [front_asic_namespaces ] = ConfigDBConnector (use_unix_socket_path = True , namespace = front_asic_namespaces )
1117
1314
per_npu_configdb [front_asic_namespaces ].connect ()
1118
1315
per_npu_configdb [front_asic_namespaces ].set_entry ("MIRROR_SESSION" , session_name , None )
1316
+
1119
1317
#
1120
1318
# 'pfcwd' group ('config pfcwd ...')
1121
1319
#
@@ -1390,6 +1588,9 @@ def add_vlan_member(ctx, vid, interface_name, untagged):
1390
1588
1391
1589
if len (vlan ) == 0 :
1392
1590
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
+
1393
1594
members = vlan .get ('members' , [])
1394
1595
if interface_name in members :
1395
1596
if get_interface_naming_mode () == "alias" :
@@ -1404,7 +1605,7 @@ def add_vlan_member(ctx, vid, interface_name, untagged):
1404
1605
for entry in interface_table :
1405
1606
if (interface_name == entry [0 ]):
1406
1607
ctx .fail ("{} is a L3 interface!" .format (interface_name ))
1407
-
1608
+
1408
1609
members .append (interface_name )
1409
1610
vlan ['members' ] = members
1410
1611
db .set_entry ('VLAN' , vlan_name , vlan )
0 commit comments