@@ -343,18 +343,22 @@ def interface_name_to_alias(config_db, interface_name):
343
343
344
344
return None
345
345
346
- def interface_ipaddr_dependent_on_interface (config_db , interface_name ):
347
- """Get table keys including ipaddress
346
+ def get_interface_ipaddresses (config_db , interface_name ):
347
+ """Get IP addresses attached to interface
348
348
"""
349
- data = []
349
+ ipaddresses = set ()
350
350
table_name = get_interface_table_name (interface_name )
351
- if table_name == "" :
352
- return data
351
+ if not table_name :
352
+ return ipaddresses
353
+
353
354
keys = config_db .get_keys (table_name )
354
355
for key in keys :
355
- if interface_name in key and len (key ) == 2 :
356
- data .append (key )
357
- return data
356
+ if isinstance (key , tuple ) and len (key ) == 2 :
357
+ iface , interface_ip = key
358
+ if iface == interface_name :
359
+ ipaddresses .add (ipaddress .ip_interface (interface_ip ))
360
+
361
+ return ipaddresses
358
362
359
363
def is_interface_bind_to_vrf (config_db , interface_name ):
360
364
"""Get interface if bind to vrf or not
@@ -448,9 +452,9 @@ def del_interface_bind_to_vrf(config_db, vrf_name):
448
452
if interface_dict :
449
453
for interface_name in interface_dict :
450
454
if 'vrf_name' in interface_dict [interface_name ] and vrf_name == interface_dict [interface_name ]['vrf_name' ]:
451
- interface_dependent = interface_ipaddr_dependent_on_interface (config_db , interface_name )
452
- for interface_del in interface_dependent :
453
- config_db . set_entry ( table_name , interface_del , None )
455
+ interface_ipaddresses = get_interface_ipaddresses (config_db , interface_name )
456
+ for ipaddress in interface_ipaddresses :
457
+ remove_router_interface_ip_address ( config_db , interface_name , ipaddress )
454
458
config_db .set_entry (table_name , interface_name , None )
455
459
456
460
def set_interface_naming_mode (mode ):
@@ -854,27 +858,6 @@ def validate_mirror_session_config(config_db, session_name, dst_port, src_port,
854
858
855
859
return True
856
860
857
- def is_valid_ip_interface (ctx , ip_addr ):
858
- split_ip_mask = ip_addr .split ("/" )
859
- if len (split_ip_mask ) < 2 :
860
- return False
861
-
862
- # Check if the IP address is correct or if there are leading zeros.
863
- ip_obj = ipaddress .ip_address (split_ip_mask [0 ])
864
-
865
- if isinstance (ip_obj , ipaddress .IPv4Address ):
866
- # Since the IP address is used as a part of a key in Redis DB,
867
- # do not tolerate extra zeros in IPv4.
868
- if str (ip_obj ) != split_ip_mask [0 ]:
869
- return False
870
-
871
- # Check if the mask is correct
872
- net = ipaddress .ip_network (ip_addr , strict = False )
873
- if str (net .prefixlen ) != split_ip_mask [1 ] or net .prefixlen == 0 :
874
- return False
875
-
876
- return True
877
-
878
861
def cli_sroute_to_config (ctx , command_str , strict_nh = True ):
879
862
if len (command_str ) < 2 or len (command_str ) > 9 :
880
863
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>>!" )
@@ -985,6 +968,20 @@ def cache_arp_entries():
985
968
open (restore_flag_file , 'w' ).close ()
986
969
return success
987
970
971
+ def remove_router_interface_ip_address (config_db , interface_name , ipaddress_to_remove ):
972
+ table_name = get_interface_table_name (interface_name )
973
+ keys = config_db .get_keys (table_name )
974
+
975
+ for key in keys :
976
+ if not isinstance (key , tuple ) or len (key ) != 2 :
977
+ continue
978
+
979
+ iface , ipaddress_string = key
980
+ if iface != interface_name :
981
+ continue
982
+
983
+ if ipaddress .ip_interface (ipaddress_string ) == ipaddress_to_remove :
984
+ config_db .set_entry (table_name , (interface_name , ipaddress_string ), None )
988
985
989
986
def validate_ipv4_address (ctx , param , ip_addr ):
990
987
"""Helper function to validate ipv4 address
@@ -3749,50 +3746,44 @@ def add(ctx, interface_name, ip_addr, gw):
3749
3746
return
3750
3747
3751
3748
try :
3752
- net = ipaddress .ip_network (ip_addr , strict = False )
3753
- if '/' not in ip_addr :
3754
- ip_addr += '/' + str (net .prefixlen )
3755
-
3756
- if not is_valid_ip_interface (ctx , ip_addr ):
3757
- raise ValueError ('' )
3758
-
3759
- if interface_name == 'eth0' :
3760
-
3761
- # Configuring more than 1 IPv4 or more than 1 IPv6 address fails.
3762
- # Allow only one IPv4 and only one IPv6 address to be configured for IPv6.
3763
- # If a row already exist, overwrite it (by doing delete and add).
3764
- mgmtintf_key_list = _get_all_mgmtinterface_keys ()
3765
-
3766
- for key in mgmtintf_key_list :
3767
- # For loop runs for max 2 rows, once for IPv4 and once for IPv6.
3768
- # No need to capture the exception since the ip_addr is already validated earlier
3769
- ip_input = ipaddress .ip_interface (ip_addr )
3770
- current_ip = ipaddress .ip_interface (key [1 ])
3771
- if (ip_input .version == current_ip .version ):
3772
- # If user has configured IPv4/v6 address and the already available row is also IPv4/v6, delete it here.
3773
- config_db .set_entry ("MGMT_INTERFACE" , ("eth0" , key [1 ]), None )
3774
-
3775
- # Set the new row with new value
3776
- if not gw :
3777
- config_db .set_entry ("MGMT_INTERFACE" , (interface_name , ip_addr ), {"NULL" : "NULL" })
3778
- else :
3779
- config_db .set_entry ("MGMT_INTERFACE" , (interface_name , ip_addr ), {"gwaddr" : gw })
3780
- mgmt_ip_restart_services ()
3749
+ ip_address = ipaddress .ip_interface (ip_addr )
3750
+ except ValueError as err :
3751
+ ctx .fail ("IP address is not valid: {}" .format (err ))
3752
+
3753
+ if interface_name == 'eth0' :
3754
+
3755
+ # Configuring more than 1 IPv4 or more than 1 IPv6 address fails.
3756
+ # Allow only one IPv4 and only one IPv6 address to be configured for IPv6.
3757
+ # If a row already exist, overwrite it (by doing delete and add).
3758
+ mgmtintf_key_list = _get_all_mgmtinterface_keys ()
3759
+
3760
+ for key in mgmtintf_key_list :
3761
+ # For loop runs for max 2 rows, once for IPv4 and once for IPv6.
3762
+ # No need to capture the exception since the ip_addr is already validated earlier
3763
+ current_ip = ipaddress .ip_interface (key [1 ])
3764
+ if (ip_address .version == current_ip .version ):
3765
+ # If user has configured IPv4/v6 address and the already available row is also IPv4/v6, delete it here.
3766
+ config_db .set_entry ("MGMT_INTERFACE" , ("eth0" , key [1 ]), None )
3767
+
3768
+ # Set the new row with new value
3769
+ if not gw :
3770
+ config_db .set_entry ("MGMT_INTERFACE" , (interface_name , str (ip_address )), {"NULL" : "NULL" })
3771
+ else :
3772
+ config_db .set_entry ("MGMT_INTERFACE" , (interface_name , str (ip_address )), {"gwaddr" : gw })
3773
+ mgmt_ip_restart_services ()
3781
3774
3782
- return
3775
+ return
3783
3776
3784
- table_name = get_interface_table_name (interface_name )
3785
- if table_name == "" :
3786
- ctx .fail ("'interface_name' is not valid. Valid names [Ethernet/PortChannel/Vlan/Loopback]" )
3787
- interface_entry = config_db .get_entry (table_name , interface_name )
3788
- if len (interface_entry ) == 0 :
3789
- if table_name == "VLAN_SUB_INTERFACE" :
3790
- config_db .set_entry (table_name , interface_name , {"admin_status" : "up" })
3791
- else :
3792
- config_db .set_entry (table_name , interface_name , {"NULL" : "NULL" })
3793
- config_db .set_entry (table_name , (interface_name , ip_addr ), {"NULL" : "NULL" })
3794
- except ValueError :
3795
- ctx .fail ("ip address or mask is not valid." )
3777
+ table_name = get_interface_table_name (interface_name )
3778
+ if table_name == "" :
3779
+ ctx .fail ("'interface_name' is not valid. Valid names [Ethernet/PortChannel/Vlan/Loopback]" )
3780
+ interface_entry = config_db .get_entry (table_name , interface_name )
3781
+ if len (interface_entry ) == 0 :
3782
+ if table_name == "VLAN_SUB_INTERFACE" :
3783
+ config_db .set_entry (table_name , interface_name , {"admin_status" : "up" })
3784
+ else :
3785
+ config_db .set_entry (table_name , interface_name , {"NULL" : "NULL" })
3786
+ config_db .set_entry (table_name , (interface_name , str (ip_address )), {"NULL" : "NULL" })
3796
3787
3797
3788
#
3798
3789
# 'del' subcommand
@@ -3813,52 +3804,47 @@ def remove(ctx, interface_name, ip_addr):
3813
3804
ctx .fail ("'interface_name' is None!" )
3814
3805
3815
3806
try :
3816
- net = ipaddress .ip_network (ip_addr , strict = False )
3817
- if '/' not in ip_addr :
3818
- ip_addr += '/' + str ( net . prefixlen )
3807
+ ip_address = ipaddress .ip_interface (ip_addr )
3808
+ except ValueError as err :
3809
+ ctx . fail ( "IP address is not valid: {}" . format ( err ) )
3819
3810
3820
- if not is_valid_ip_interface (ctx , ip_addr ):
3821
- raise ValueError ('' )
3811
+ if interface_name == 'eth0' :
3812
+ config_db .set_entry ("MGMT_INTERFACE" , (interface_name , str (ip_address )), None )
3813
+ mgmt_ip_restart_services ()
3814
+ return
3822
3815
3823
- if interface_name == 'eth0' :
3824
- config_db .set_entry ("MGMT_INTERFACE" , (interface_name , ip_addr ), None )
3825
- mgmt_ip_restart_services ()
3826
- return
3816
+ table_name = get_interface_table_name (interface_name )
3817
+ if table_name == "" :
3818
+ ctx .fail ("'interface_name' is not valid. Valid names [Ethernet/PortChannel/Vlan/Loopback]" )
3819
+ interface_addresses = get_interface_ipaddresses (config_db , interface_name )
3820
+ # If we deleting the last IP entry of the interface, check whether a static route present for the RIF
3821
+ # before deleting the entry and also the RIF.
3822
+ if interface_addresses == {ip_address }:
3823
+ # Check both IPv4 and IPv6 routes.
3824
+ ip_versions = [ "ip" , "ipv6" ]
3825
+ for ip_ver in ip_versions :
3826
+ # Compete the command and ask Zebra to return the routes.
3827
+ # Scopes of all VRFs will be checked.
3828
+ cmd = "show {} route vrf all static" .format (ip_ver )
3829
+ if multi_asic .is_multi_asic ():
3830
+ output = bgp_util .run_bgp_command (cmd , ctx .obj ['namespace' ])
3831
+ else :
3832
+ output = bgp_util .run_bgp_command (cmd )
3833
+ # If there is output data, check is there a static route,
3834
+ # bound to the interface.
3835
+ if output != "" :
3836
+ if any (interface_name in output_line for output_line in output .splitlines ()):
3837
+ ctx .fail ("Cannot remove the last IP entry of interface {}. A static {} route is still bound to the RIF." .format (interface_name , ip_ver ))
3838
+ remove_router_interface_ip_address (config_db , interface_name , ip_address )
3839
+ interface_addresses = get_interface_ipaddresses (config_db , interface_name )
3840
+ if len (interface_addresses ) == 0 and is_interface_bind_to_vrf (config_db , interface_name ) is False and get_intf_ipv6_link_local_mode (ctx , interface_name , table_name ) != "enable" :
3841
+ config_db .set_entry (table_name , interface_name , None )
3827
3842
3828
- table_name = get_interface_table_name (interface_name )
3829
- if table_name == "" :
3830
- ctx .fail ("'interface_name' is not valid. Valid names [Ethernet/PortChannel/Vlan/Loopback]" )
3831
- interface_dependent = interface_ipaddr_dependent_on_interface (config_db , interface_name )
3832
- # If we deleting the last IP entry of the interface, check whether a static route present for the RIF
3833
- # before deleting the entry and also the RIF.
3834
- if len (interface_dependent ) == 1 and interface_dependent [0 ][1 ] == ip_addr :
3835
- # Check both IPv4 and IPv6 routes.
3836
- ip_versions = [ "ip" , "ipv6" ]
3837
- for ip_ver in ip_versions :
3838
- # Compete the command and ask Zebra to return the routes.
3839
- # Scopes of all VRFs will be checked.
3840
- cmd = "show {} route vrf all static" .format (ip_ver )
3841
- if multi_asic .is_multi_asic ():
3842
- output = bgp_util .run_bgp_command (cmd , ctx .obj ['namespace' ])
3843
- else :
3844
- output = bgp_util .run_bgp_command (cmd )
3845
- # If there is output data, check is there a static route,
3846
- # bound to the interface.
3847
- if output != "" :
3848
- if any (interface_name in output_line for output_line in output .splitlines ()):
3849
- ctx .fail ("Cannot remove the last IP entry of interface {}. A static {} route is still bound to the RIF." .format (interface_name , ip_ver ))
3850
- config_db .set_entry (table_name , (interface_name , ip_addr ), None )
3851
- interface_dependent = interface_ipaddr_dependent_on_interface (config_db , interface_name )
3852
- if len (interface_dependent ) == 0 and is_interface_bind_to_vrf (config_db , interface_name ) is False and get_intf_ipv6_link_local_mode (ctx , interface_name , table_name ) != "enable" :
3853
- config_db .set_entry (table_name , interface_name , None )
3854
-
3855
- if multi_asic .is_multi_asic ():
3856
- command = "sudo ip netns exec {} ip neigh flush dev {} {}" .format (ctx .obj ['namespace' ], interface_name , ip_addr )
3857
- else :
3858
- command = "ip neigh flush dev {} {}" .format (interface_name , ip_addr )
3859
- clicommon .run_command (command )
3860
- except ValueError :
3861
- ctx .fail ("ip address or mask is not valid." )
3843
+ if multi_asic .is_multi_asic ():
3844
+ command = "sudo ip netns exec {} ip neigh flush dev {} {}" .format (ctx .obj ['namespace' ], interface_name , str (ip_address ))
3845
+ else :
3846
+ command = "ip neigh flush dev {} {}" .format (interface_name , str (ip_address ))
3847
+ clicommon .run_command (command )
3862
3848
3863
3849
3864
3850
#
@@ -4243,9 +4229,9 @@ def bind(ctx, interface_name, vrf_name):
4243
4229
config_db .get_entry (table_name , interface_name ).get ('vrf_name' ) == vrf_name :
4244
4230
return
4245
4231
# Clean ip addresses if interface configured
4246
- interface_dependent = interface_ipaddr_dependent_on_interface (config_db , interface_name )
4247
- for interface_del in interface_dependent :
4248
- config_db . set_entry ( table_name , interface_del , None )
4232
+ interface_addresses = get_interface_ipaddresses (config_db , interface_name )
4233
+ for ipaddress in interface_addresses :
4234
+ remove_router_interface_ip_address ( config_db , interface_name , ipaddress )
4249
4235
config_db .set_entry (table_name , interface_name , None )
4250
4236
# When config_db del entry and then add entry with same key, the DEL will lost.
4251
4237
if ctx .obj ['namespace' ] is DEFAULT_NAMESPACE :
@@ -4281,9 +4267,9 @@ def unbind(ctx, interface_name):
4281
4267
ctx .fail ("'interface_name' is not valid. Valid names [Ethernet/PortChannel/Vlan/Loopback]" )
4282
4268
if is_interface_bind_to_vrf (config_db , interface_name ) is False :
4283
4269
return
4284
- interface_dependent = interface_ipaddr_dependent_on_interface (config_db , interface_name )
4285
- for interface_del in interface_dependent :
4286
- config_db . set_entry ( table_name , interface_del , None )
4270
+ interface_ipaddresses = get_interface_ipaddresses (config_db , interface_name )
4271
+ for ipaddress in interface_ipaddresses :
4272
+ remove_router_interface_ip_address ( config_db , interface_name , ipaddress )
4287
4273
config_db .set_entry (table_name , interface_name , None )
4288
4274
4289
4275
0 commit comments