@@ -1086,8 +1086,9 @@ def validate_mirror_session_config(config_db, session_name, dst_port, src_port,
1086
1086
return True
1087
1087
1088
1088
def cli_sroute_to_config (ctx , command_str , strict_nh = True ):
1089
- if len (command_str ) < 2 or len (command_str ) > 9 :
1090
- ctx .fail ("argument is not in pattern prefix [vrf <vrf_name>] <A.B.C.D/M> nexthop <[vrf <vrf_name>] <A.B.C.D>>|<dev <dev_name>>!" )
1089
+ if len (command_str ) < 2 or len (command_str ) > 10 :
1090
+ ctx .fail ("argument is not in pattern prefix [vrf <vrf_name>] <A.B.C.D/M> nexthop [vrf <vrf_name>] \
1091
+ <A.B.C.D>|<dev <dev_name>>|<A.B.C.D dev <dev_name>>!" )
1091
1092
if "prefix" not in command_str :
1092
1093
ctx .fail ("argument is incomplete, prefix not found!" )
1093
1094
if "nexthop" not in command_str and strict_nh :
@@ -1120,36 +1121,51 @@ def cli_sroute_to_config(ctx, command_str, strict_nh = True):
1120
1121
ctx .fail ("prefix is not in pattern!" )
1121
1122
1122
1123
if nexthop_str :
1123
- if 'nexthop' in nexthop_str and 'vrf' in nexthop_str :
1124
- # nexthop_str: ['nexthop', 'vrf', Vrf-name, ip]
1125
- config_entry ["nexthop" ] = nexthop_str [3 ]
1126
- if not is_vrf_exists (config_db , nexthop_str [2 ]):
1127
- ctx .fail ("VRF %s does not exist!" % (nexthop_str [2 ]))
1124
+ idx = 1
1125
+ if 'vrf' in nexthop_str :
1126
+ # extract nexthop vrf
1127
+ for vrf in nexthop_str [2 ].split (',' ):
1128
+ if not is_vrf_exists (config_db , vrf ):
1129
+ ctx .fail ("Nexthop VRF %s does not exist!" % (vrf ))
1128
1130
config_entry ["nexthop-vrf" ] = nexthop_str [2 ]
1129
- elif 'nexthop' in nexthop_str and 'dev' in nexthop_str :
1130
- # nexthop_str: ['nexthop', 'dev', ifname]
1131
- config_entry ["ifname" ] = nexthop_str [2 ]
1132
- elif 'nexthop' in nexthop_str :
1133
- # nexthop_str: ['nexthop', ip]
1134
- config_entry ["nexthop" ] = nexthop_str [1 ]
1131
+ idx = 3
1132
+
1133
+ if nexthop_str [idx ] == 'dev' :
1134
+ # no nexthop IPs but interface name
1135
+ config_entry ["ifname" ] = nexthop_str [idx + 1 ]
1135
1136
else :
1136
- ctx .fail ("nexthop is not in pattern!" )
1137
+ # nexthop IPs present, extract them first
1138
+ config_entry ["nexthop" ] = nexthop_str [idx ]
1139
+ if len (nexthop_str ) > idx + 1 :
1140
+ if nexthop_str [idx + 1 ] == 'dev' and len (nexthop_str ) > idx + 2 :
1141
+ # extract interface name
1142
+ config_entry ["ifname" ] = nexthop_str [idx + 2 ]
1143
+ else :
1144
+ ctx .fail ("nexthop is not in pattern!" )
1137
1145
1138
1146
try :
1139
1147
ipaddress .ip_network (ip_prefix )
1140
1148
if 'nexthop' in config_entry :
1141
1149
nh_list = config_entry ['nexthop' ].split (',' )
1142
1150
for nh in nh_list :
1143
- # Nexthop to portchannel
1144
- if nh .startswith ('PortChannel' ):
1145
- config_db = ctx .obj ['config_db' ]
1146
- if not nh in config_db .get_keys ('PORTCHANNEL' ):
1147
- ctx .fail ("portchannel does not exist." )
1148
- else :
1149
- ipaddress .ip_address (nh )
1151
+ ipaddress .ip_address (nh )
1150
1152
except ValueError :
1151
1153
ctx .fail ("ip address is not valid." )
1152
1154
1155
+ if 'ifname' in config_entry :
1156
+ ifname_list = config_entry ['ifname' ].split (',' )
1157
+ for ifname in ifname_list :
1158
+ if ifname .startswith ('PortChannel' ):
1159
+ if ifname not in config_db .get_keys ('PORTCHANNEL' ):
1160
+ ctx .fail ("portchannel does not exist." )
1161
+ elif ifname .startswith ("Vlan" ):
1162
+ if ifname not in config_db .get_keys ('VLAN_INTERFACE' ):
1163
+ ctx .fail ("vlan interface does not exist." )
1164
+ elif ifname not in config_db .get_keys ('INTERFACE' ) and \
1165
+ ifname not in config_db .get_keys ('VLAN_SUB_INTERFACE' ) and \
1166
+ ifname != 'null' :
1167
+ ctx .fail ("interface {} does not exist." .format (ifname ))
1168
+
1153
1169
if not vrf_name == "" :
1154
1170
key = vrf_name + "|" + ip_prefix
1155
1171
else :
@@ -1865,11 +1881,7 @@ def reload(db, filename, yes, load_sysinfo, no_service_restart, force, file_form
1865
1881
return
1866
1882
1867
1883
if filename is not None and filename != "/dev/stdin" :
1868
- if multi_asic .is_multi_asic ():
1869
- # Multiasic has not 100% fully validated. Thus pass here.
1870
- pass
1871
- else :
1872
- config_file_yang_validation (filename )
1884
+ config_file_yang_validation (filename )
1873
1885
1874
1886
#Stop services before config push
1875
1887
if not no_service_restart :
@@ -4624,6 +4636,11 @@ def startup(ctx, interface_name):
4624
4636
if sp_name in intf_fs :
4625
4637
config_db .mod_entry ("VLAN_SUB_INTERFACE" , sp_name , {"admin_status" : "up" })
4626
4638
4639
+ lo_list = config_db .get_table ("LOOPBACK_INTERFACE" )
4640
+ for lo in lo_list :
4641
+ if lo in intf_fs :
4642
+ config_db .mod_entry ("LOOPBACK_INTERFACE" , lo , {"admin_status" : "up" })
4643
+
4627
4644
#
4628
4645
# 'shutdown' subcommand
4629
4646
#
@@ -4664,6 +4681,11 @@ def shutdown(ctx, interface_name):
4664
4681
if sp_name in intf_fs :
4665
4682
config_db .mod_entry ("VLAN_SUB_INTERFACE" , sp_name , {"admin_status" : "down" })
4666
4683
4684
+ lo_list = config_db .get_table ("LOOPBACK_INTERFACE" )
4685
+ for lo in lo_list :
4686
+ if lo in intf_fs :
4687
+ config_db .mod_entry ("LOOPBACK_INTERFACE" , lo , {"admin_status" : "down" })
4688
+
4667
4689
#
4668
4690
# 'speed' subcommand
4669
4691
#
@@ -7139,53 +7161,60 @@ def route(ctx):
7139
7161
ctx .obj = {}
7140
7162
ctx .obj ['config_db' ] = config_db
7141
7163
7164
+
7142
7165
@route .command ('add' , context_settings = {"ignore_unknown_options" : True })
7143
- @click .argument ('command_str' , metavar = 'prefix [vrf <vrf_name>] <A.B.C.D/M> nexthop <[vrf <vrf_name>] <A.B.C.D>>|<dev <dev_name>>' , nargs = - 1 , type = click .Path ())
7166
+ @click .argument ('command_str' , metavar = 'prefix [vrf <vrf_name>] <A.B.C.D/M> nexthop [vrf <vrf_name>] \
7167
+ <A.B.C.D>|<dev <dev_name>>|<A.B.C.D dev <dev_name>>' , nargs = - 1 , type = click .Path ())
7144
7168
@click .pass_context
7145
7169
def add_route (ctx , command_str ):
7146
7170
"""Add route command"""
7147
7171
config_db = ctx .obj ['config_db' ]
7148
7172
key , route = cli_sroute_to_config (ctx , command_str )
7149
7173
7150
- # If defined intf name, check if it belongs to interface
7151
- if 'ifname' in route :
7152
- if (not route ['ifname' ] in config_db .get_keys ('VLAN_INTERFACE' ) and
7153
- not route ['ifname' ] in config_db .get_keys ('INTERFACE' ) and
7154
- not route ['ifname' ] in config_db .get_keys ('PORTCHANNEL_INTERFACE' ) and
7155
- not route ['ifname' ] in config_db .get_keys ('VLAN_SUB_INTERFACE' ) and
7156
- not route ['ifname' ] == 'null' ):
7157
- ctx .fail ('interface {} doesn`t exist' .format (route ['ifname' ]))
7158
-
7159
7174
entry_counter = 1
7160
7175
if 'nexthop' in route :
7161
7176
entry_counter = len (route ['nexthop' ].split (',' ))
7177
+ if 'ifname' in route and len (route ['ifname' ].split (',' )) > entry_counter :
7178
+ entry_counter = len (route ['ifname' ].split (',' ))
7162
7179
7163
7180
# Alignment in case the command contains several nexthop ip
7164
7181
for i in range (entry_counter ):
7182
+ # Set vrf to empty string if not defined
7165
7183
if 'nexthop-vrf' in route :
7166
- if i > 0 :
7184
+ if i >= len ( route [ 'nexthop-vrf' ]. split ( ',' )) :
7167
7185
vrf = route ['nexthop-vrf' ].split (',' )[0 ]
7168
7186
route ['nexthop-vrf' ] += ',' + vrf
7169
7187
else :
7170
7188
route ['nexthop-vrf' ] = ''
7171
7189
7172
- if not 'nexthop' in route :
7190
+ # Set nexthop to empty string if not defined
7191
+ if 'nexthop' in route :
7192
+ if i >= len (route ['nexthop' ].split (',' )):
7193
+ route ['nexthop' ] += ','
7194
+ else :
7173
7195
route ['nexthop' ] = ''
7174
7196
7197
+ # Set ifname to empty string if not defined
7175
7198
if 'ifname' in route :
7176
- if i > 0 :
7199
+ if i >= len ( route [ 'ifname' ]. split ( ',' )) :
7177
7200
route ['ifname' ] += ','
7178
7201
else :
7179
7202
route ['ifname' ] = ''
7180
7203
7181
7204
# Set default values for distance and blackhole because the command doesn't have such an option
7182
7205
if 'distance' in route :
7183
- route ['distance' ] += ',0'
7206
+ if i >= len (route ['distance' ].split (',' )):
7207
+ route ['distance' ] += ',0'
7184
7208
else :
7185
7209
route ['distance' ] = '0'
7186
7210
7187
7211
if 'blackhole' in route :
7188
- route ['blackhole' ] += ',false'
7212
+ if i >= len (route ['blackhole' ].split (',' )):
7213
+ # If the user configure with "ifname" as "null", set 'blackhole' attribute as true.
7214
+ if route ['ifname' ].split (',' )[i ] == 'null' :
7215
+ route ['blackhole' ] += ',true'
7216
+ else :
7217
+ route ['blackhole' ] += ',false'
7189
7218
else :
7190
7219
# If the user configure with "ifname" as "null", set 'blackhole' attribute as true.
7191
7220
if 'ifname' in route and route ['ifname' ] == 'null' :
@@ -7199,28 +7228,30 @@ def add_route(ctx, command_str):
7199
7228
# If exist update current entry
7200
7229
current_entry = config_db .get_entry ('STATIC_ROUTE' , key )
7201
7230
7202
- for entry in ['nexthop' , 'nexthop-vrf' , 'ifname' , 'distance' , 'blackhole' ]:
7203
- if not entry in current_entry :
7204
- current_entry [entry ] = ''
7205
- if entry in route :
7206
- current_entry [entry ] += ',' + route [entry ]
7231
+ for item in ['nexthop' , 'nexthop-vrf' , 'ifname' , 'distance' , 'blackhole' ]:
7232
+ if item not in current_entry :
7233
+ current_entry [item ] = ''
7234
+ if item in route :
7235
+ current_entry [item ] += ',' + route [item ]
7207
7236
else :
7208
- current_entry [entry ] += ','
7237
+ current_entry [item ] += ','
7209
7238
7210
7239
config_db .set_entry ("STATIC_ROUTE" , key , current_entry )
7211
7240
else :
7212
7241
config_db .set_entry ("STATIC_ROUTE" , key , route )
7213
7242
7243
+
7214
7244
@route .command ('del' , context_settings = {"ignore_unknown_options" : True })
7215
- @click .argument ('command_str' , metavar = 'prefix [vrf <vrf_name>] <A.B.C.D/M> nexthop <[vrf <vrf_name>] <A.B.C.D>>|<dev <dev_name>>' , nargs = - 1 , type = click .Path ())
7245
+ @click .argument ('command_str' , metavar = 'prefix [vrf <vrf_name>] <A.B.C.D/M> nexthop [vrf <vrf_name>] \
7246
+ <A.B.C.D>|<dev <dev_name>>|<A.B.C.D dev <dev_name>>' , nargs = - 1 , type = click .Path ())
7216
7247
@click .pass_context
7217
7248
def del_route (ctx , command_str ):
7218
7249
"""Del route command"""
7219
7250
config_db = ctx .obj ['config_db' ]
7220
7251
key , route = cli_sroute_to_config (ctx , command_str , strict_nh = False )
7221
7252
keys = config_db .get_keys ('STATIC_ROUTE' )
7222
- prefix_tuple = tuple ( key . split ( '|' ))
7223
- if not tuple (key .split ("|" )) in keys and not prefix_tuple in keys :
7253
+
7254
+ if not tuple (key .split ("|" )) in keys :
7224
7255
ctx .fail ('Route {} doesnt exist' .format (key ))
7225
7256
else :
7226
7257
# If not defined nexthop or intf name remove entire route
@@ -7255,9 +7286,11 @@ def del_route(ctx, command_str):
7255
7286
# Create tuple from CLI argument
7256
7287
# config route add prefix 1.4.3.4/32 nexthop vrf Vrf-RED 20.0.0.2
7257
7288
# ('20.0.0.2', 'Vrf-RED', '')
7258
- for entry in ['nexthop' , 'nexthop-vrf' , 'ifname' ]:
7259
- if entry in route :
7260
- cli_tuple += (route [entry ],)
7289
+ for item in ['nexthop' , 'nexthop-vrf' , 'ifname' ]:
7290
+ if item in route :
7291
+ if ',' in route [item ]:
7292
+ ctx .fail ('Only one nexthop can be deleted at a time' )
7293
+ cli_tuple += (route [item ],)
7261
7294
else :
7262
7295
cli_tuple += ('' ,)
7263
7296
0 commit comments