Skip to content

Commit 29f4a16

Browse files
Global and Interface commands for IPv6 Link local address enhancements (#1159)
* Global and Interface commands for IPv6 Link local feature * SONiC CLI per interface configuration command to enable and disable the IPv6 link-local address mode when addresses are not configured manually. Signed-off-by: Akhilesh Samineni <[email protected]>
1 parent a99d56d commit 29f4a16

File tree

5 files changed

+529
-3
lines changed

5 files changed

+529
-3
lines changed

config/main.py

+252-1
Original file line numberDiff line numberDiff line change
@@ -498,6 +498,16 @@ def set_interface_naming_mode(mode):
498498
f.close()
499499
click.echo("Please logout and log back in for changes take effect.")
500500

501+
def get_intf_ipv6_link_local_mode(ctx, interface_name, table_name):
502+
config_db = ctx.obj["config_db"]
503+
intf = config_db.get_table(table_name)
504+
if interface_name in intf:
505+
if 'ipv6_use_link_local_only' in intf[interface_name]:
506+
return intf[interface_name]['ipv6_use_link_local_only']
507+
else:
508+
return "disable"
509+
else:
510+
return ""
501511

502512
def _is_neighbor_ipaddress(config_db, ipaddress):
503513
"""Returns True if a neighbor has the IP address <ipaddress>, False if not
@@ -3698,7 +3708,7 @@ def remove(ctx, interface_name, ip_addr):
36983708
ctx.fail("Cannot remove the last IP entry of interface {}. A static {} route is still bound to the RIF.".format(interface_name, ip_ver))
36993709
config_db.set_entry(table_name, (interface_name, ip_addr), None)
37003710
interface_dependent = interface_ipaddr_dependent_on_interface(config_db, interface_name)
3701-
if len(interface_dependent) == 0 and is_interface_bind_to_vrf(config_db, interface_name) is False:
3711+
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":
37023712
config_db.set_entry(table_name, interface_name, None)
37033713

37043714
if multi_asic.is_multi_asic():
@@ -4133,6 +4143,130 @@ def unbind(ctx, interface_name):
41334143
config_db.set_entry(table_name, interface_name, None)
41344144

41354145

4146+
#
4147+
# 'ipv6' subgroup ('config interface ipv6 ...')
4148+
#
4149+
4150+
@interface.group()
4151+
@click.pass_context
4152+
def ipv6(ctx):
4153+
"""Enable or Disable IPv6 processing on interface"""
4154+
pass
4155+
4156+
@ipv6.group('enable')
4157+
def enable():
4158+
"""Enable IPv6 processing on interface"""
4159+
pass
4160+
4161+
@ipv6.group('disable')
4162+
def disable():
4163+
"""Disble IPv6 processing on interface"""
4164+
pass
4165+
4166+
#
4167+
# 'config interface ipv6 enable use-link-local-only <interface-name>'
4168+
#
4169+
4170+
@enable.command('use-link-local-only')
4171+
@click.pass_context
4172+
@click.argument('interface_name', metavar='<interface_name>', required=True)
4173+
def enable_use_link_local_only(ctx, interface_name):
4174+
"""Enable IPv6 link local address on interface"""
4175+
config_db = ConfigDBConnector()
4176+
config_db.connect()
4177+
ctx.obj = {}
4178+
ctx.obj['config_db'] = config_db
4179+
db = ctx.obj["config_db"]
4180+
4181+
if clicommon.get_interface_naming_mode() == "alias":
4182+
interface_name = interface_alias_to_name(db, interface_name)
4183+
if interface_name is None:
4184+
ctx.fail("'interface_name' is None!")
4185+
4186+
if interface_name.startswith("Ethernet"):
4187+
interface_type = "INTERFACE"
4188+
elif interface_name.startswith("PortChannel"):
4189+
interface_type = "PORTCHANNEL_INTERFACE"
4190+
elif interface_name.startswith("Vlan"):
4191+
interface_type = "VLAN_INTERFACE"
4192+
else:
4193+
ctx.fail("'interface_name' is not valid. Valid names [Ethernet/PortChannel/Vlan]")
4194+
4195+
if (interface_type == "INTERFACE" ) or (interface_type == "PORTCHANNEL_INTERFACE"):
4196+
if interface_name_is_valid(db, interface_name) is False:
4197+
ctx.fail("Interface name %s is invalid. Please enter a valid interface name!!" %(interface_name))
4198+
4199+
if (interface_type == "VLAN_INTERFACE"):
4200+
if not clicommon.is_valid_vlan_interface(db, interface_name):
4201+
ctx.fail("Interface name %s is invalid. Please enter a valid interface name!!" %(interface_name))
4202+
4203+
portchannel_member_table = db.get_table('PORTCHANNEL_MEMBER')
4204+
4205+
if interface_is_in_portchannel(portchannel_member_table, interface_name):
4206+
ctx.fail("{} is configured as a member of portchannel. Cannot configure the IPv6 link local mode!"
4207+
.format(interface_name))
4208+
4209+
vlan_member_table = db.get_table('VLAN_MEMBER')
4210+
4211+
if interface_is_in_vlan(vlan_member_table, interface_name):
4212+
ctx.fail("{} is configured as a member of vlan. Cannot configure the IPv6 link local mode!"
4213+
.format(interface_name))
4214+
4215+
interface_dict = db.get_table(interface_type)
4216+
set_ipv6_link_local_only_on_interface(db, interface_dict, interface_type, interface_name, "enable")
4217+
4218+
#
4219+
# 'config interface ipv6 disable use-link-local-only <interface-name>'
4220+
#
4221+
4222+
@disable.command('use-link-local-only')
4223+
@click.pass_context
4224+
@click.argument('interface_name', metavar='<interface_name>', required=True)
4225+
def disable_use_link_local_only(ctx, interface_name):
4226+
"""Disable IPv6 link local address on interface"""
4227+
config_db = ConfigDBConnector()
4228+
config_db.connect()
4229+
ctx.obj = {}
4230+
ctx.obj['config_db'] = config_db
4231+
db = ctx.obj["config_db"]
4232+
4233+
if clicommon.get_interface_naming_mode() == "alias":
4234+
interface_name = interface_alias_to_name(db, interface_name)
4235+
if interface_name is None:
4236+
ctx.fail("'interface_name' is None!")
4237+
4238+
interface_type = ""
4239+
if interface_name.startswith("Ethernet"):
4240+
interface_type = "INTERFACE"
4241+
elif interface_name.startswith("PortChannel"):
4242+
interface_type = "PORTCHANNEL_INTERFACE"
4243+
elif interface_name.startswith("Vlan"):
4244+
interface_type = "VLAN_INTERFACE"
4245+
else:
4246+
ctx.fail("'interface_name' is not valid. Valid names [Ethernet/PortChannel/Vlan]")
4247+
4248+
if (interface_type == "INTERFACE" ) or (interface_type == "PORTCHANNEL_INTERFACE"):
4249+
if interface_name_is_valid(db, interface_name) is False:
4250+
ctx.fail("Interface name %s is invalid. Please enter a valid interface name!!" %(interface_name))
4251+
4252+
if (interface_type == "VLAN_INTERFACE"):
4253+
if not clicommon.is_valid_vlan_interface(db, interface_name):
4254+
ctx.fail("Interface name %s is invalid. Please enter a valid interface name!!" %(interface_name))
4255+
4256+
portchannel_member_table = db.get_table('PORTCHANNEL_MEMBER')
4257+
4258+
if interface_is_in_portchannel(portchannel_member_table, interface_name):
4259+
ctx.fail("{} is configured as a member of portchannel. Cannot configure the IPv6 link local mode!"
4260+
.format(interface_name))
4261+
4262+
vlan_member_table = db.get_table('VLAN_MEMBER')
4263+
if interface_is_in_vlan(vlan_member_table, interface_name):
4264+
ctx.fail("{} is configured as a member of vlan. Cannot configure the IPv6 link local mode!"
4265+
.format(interface_name))
4266+
4267+
interface_dict = db.get_table(interface_type)
4268+
set_ipv6_link_local_only_on_interface(db, interface_dict, interface_type, interface_name, "disable")
4269+
41364270
#
41374271
# 'vrf' group ('config vrf ...')
41384272
#
@@ -5554,6 +5688,123 @@ def delete(ctx):
55545688
sflow_tbl['global'].pop('agent_id')
55555689
config_db.set_entry('SFLOW', 'global', sflow_tbl['global'])
55565690

5691+
#
5692+
# set ipv6 link local mode on a given interface
5693+
#
5694+
def set_ipv6_link_local_only_on_interface(config_db, interface_dict, interface_type, interface_name, mode):
5695+
5696+
curr_mode = config_db.get_entry(interface_type, interface_name).get('ipv6_use_link_local_only')
5697+
if curr_mode is not None:
5698+
if curr_mode == mode:
5699+
return
5700+
else:
5701+
if mode == "disable":
5702+
return
5703+
5704+
if mode == "enable":
5705+
config_db.mod_entry(interface_type, interface_name, {"ipv6_use_link_local_only": mode})
5706+
return
5707+
5708+
# If we are disabling the ipv6 link local on an interface, and if no other interface
5709+
# attributes/ip addresses are configured on the interface, delete the interface from the interface table
5710+
exists = False
5711+
for key in interface_dict.keys():
5712+
if not isinstance(key, tuple):
5713+
if interface_name == key:
5714+
#Interface bound to non-default-vrf do not delete the entry
5715+
if 'vrf_name' in interface_dict[key]:
5716+
if len(interface_dict[key]['vrf_name']) > 0:
5717+
exists = True
5718+
break
5719+
continue
5720+
if interface_name in key:
5721+
exists = True
5722+
break
5723+
5724+
if exists:
5725+
config_db.mod_entry(interface_type, interface_name, {"ipv6_use_link_local_only": mode})
5726+
else:
5727+
config_db.set_entry(interface_type, interface_name, None)
5728+
5729+
#
5730+
# 'ipv6' group ('config ipv6 ...')
5731+
#
5732+
5733+
@config.group()
5734+
@click.pass_context
5735+
def ipv6(ctx):
5736+
"""IPv6 configuration"""
5737+
5738+
#
5739+
# 'enable' command ('config ipv6 enable ...')
5740+
#
5741+
@ipv6.group()
5742+
@click.pass_context
5743+
def enable(ctx):
5744+
"""Enable IPv6 on all interfaces """
5745+
5746+
#
5747+
# 'link-local' command ('config ipv6 enable link-local')
5748+
#
5749+
@enable.command('link-local')
5750+
@click.pass_context
5751+
def enable_link_local(ctx):
5752+
"""Enable IPv6 link-local on all interfaces """
5753+
config_db = ConfigDBConnector()
5754+
config_db.connect()
5755+
vlan_member_table = config_db.get_table('VLAN_MEMBER')
5756+
portchannel_member_table = config_db.get_table('PORTCHANNEL_MEMBER')
5757+
5758+
mode = "enable"
5759+
5760+
# Enable ipv6 link local on VLANs
5761+
vlan_dict = config_db.get_table('VLAN')
5762+
for key in vlan_dict.keys():
5763+
set_ipv6_link_local_only_on_interface(config_db, vlan_dict, 'VLAN_INTERFACE', key, mode)
5764+
5765+
# Enable ipv6 link local on PortChannels
5766+
portchannel_dict = config_db.get_table('PORTCHANNEL')
5767+
for key in portchannel_dict.keys():
5768+
if interface_is_in_vlan(vlan_member_table, key):
5769+
continue
5770+
set_ipv6_link_local_only_on_interface(config_db, portchannel_dict, 'PORTCHANNEL_INTERFACE', key, mode)
5771+
5772+
port_dict = config_db.get_table('PORT')
5773+
for key in port_dict.keys():
5774+
if interface_is_in_portchannel(portchannel_member_table, key) or interface_is_in_vlan(vlan_member_table, key):
5775+
continue
5776+
set_ipv6_link_local_only_on_interface(config_db, port_dict, 'INTERFACE', key, mode)
5777+
5778+
#
5779+
# 'disable' command ('config ipv6 disable ...')
5780+
#
5781+
@ipv6.group()
5782+
@click.pass_context
5783+
def disable(ctx):
5784+
"""Disable IPv6 on all interfaces """
5785+
5786+
#
5787+
# 'link-local' command ('config ipv6 disable link-local')
5788+
#
5789+
@disable.command('link-local')
5790+
@click.pass_context
5791+
def disable_link_local(ctx):
5792+
"""Disable IPv6 link local on all interfaces """
5793+
config_db = ConfigDBConnector()
5794+
config_db.connect()
5795+
5796+
mode = "disable"
5797+
5798+
tables = ['INTERFACE', 'VLAN_INTERFACE', 'PORTCHANNEL_INTERFACE']
5799+
5800+
for table_type in tables:
5801+
table_dict = config_db.get_table(table_type)
5802+
if table_dict:
5803+
for key in table_dict.keys():
5804+
if isinstance(key, str) is False:
5805+
continue
5806+
set_ipv6_link_local_only_on_interface(config_db, table_dict, table_type, key, mode)
5807+
55575808

55585809
# Load plugins and register them
55595810
helper = util_base.UtilHelper()

doc/Command-Reference.md

+93
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,9 @@
6565
* [IP / IPv6](#ip--ipv6)
6666
* [IP show commands](#ip-show-commands)
6767
* [IPv6 show commands](#ipv6-show-commands)
68+
* [IPv6 Link Local](#ipv6-link-local)
69+
* [IPv6 Link Local config commands](#ipv6-link-local-config-commands)
70+
* [IPv6 Link Local show commands](#ipv6-link-local-show-commands)
6871
* [Kubernetes](#Kubernetes)
6972
* [Kubernetes show commands](#Kubernetes-show-commands)
7073
* [Kubernetes config commands](#Kubernetes-config-commands)
@@ -4407,6 +4410,96 @@ Refer the routing stack [Quagga Command Reference](https://www.quagga.net/docs/q
44074410
44084411
Go Back To [Beginning of the document](#) or [Beginning of this section](#ip--ipv6)
44094412
4413+
## IPv6 Link Local
4414+
4415+
### IPv6 Link Local config commands
4416+
4417+
This section explains all the commands that are supported in SONiC to configure IPv6 Link-local.
4418+
4419+
**config interface ipv6 enable use-link-local-only <interface_name>**
4420+
4421+
This command enables user to enable an interface to forward L3 traffic with out configuring an address. This command creates the routing interface based on the auto generated IPv6 link-local address. This command can be used even if an address is configured on the interface.
4422+
4423+
- Usage:
4424+
```
4425+
config interface ipv6 enable use-link-local-only <interface_name>
4426+
```
4427+
4428+
- Example:
4429+
```
4430+
admin@sonic:~$ sudo config interface ipv6 enable use-link-local-only Vlan206
4431+
admin@sonic:~$ sudo config interface ipv6 enable use-link-local-only PortChannel007
4432+
admin@sonic:~$ sudo config interface ipv6 enable use-link-local-only Ethernet52
4433+
```
4434+
4435+
**config interface ipv6 disable use-link-local-only <interface_name>**
4436+
4437+
This command enables user to disable use-link-local-only configuration on an interface.
4438+
4439+
- Usage:
4440+
```
4441+
config interface ipv6 disable use-link-local-only <interface_name>
4442+
```
4443+
4444+
- Example:
4445+
```
4446+
admin@sonic:~$ sudo config interface ipv6 disable use-link-local-only Vlan206
4447+
admin@sonic:~$ sudo config interface ipv6 disable use-link-local-only PortChannel007
4448+
admin@sonic:~$ sudo config interface ipv6 disable use-link-local-only Ethernet52
4449+
```
4450+
4451+
**config ipv6 enable link-local**
4452+
4453+
This command enables user to enable use-link-local-only command on all the interfaces globally.
4454+
4455+
- Usage:
4456+
```
4457+
sudo config ipv6 enable link-local
4458+
```
4459+
4460+
- Example:
4461+
```
4462+
admin@sonic:~$ sudo config ipv6 enable link-local
4463+
```
4464+
4465+
**config ipv6 disable link-local**
4466+
4467+
This command enables user to disable use-link-local-only command on all the interfaces globally.
4468+
4469+
- Usage:
4470+
```
4471+
sudo config ipv6 disable link-local
4472+
```
4473+
4474+
- Example:
4475+
```
4476+
admin@sonic:~$ sudo config ipv6 disable link-local
4477+
```
4478+
4479+
### IPv6 Link Local show commands
4480+
4481+
**show ipv6 link-local-mode**
4482+
4483+
This command displays the link local mode of all the interfaces.
4484+
4485+
- Usage:
4486+
```
4487+
show ipv6 link-local-mode
4488+
```
4489+
4490+
- Example:
4491+
```
4492+
root@sonic:/home/admin# show ipv6 link-local-mode
4493+
+------------------+----------+
4494+
| Interface Name | Mode |
4495+
+==================+==========+
4496+
| Ethernet16 | Disabled |
4497+
+------------------+----------+
4498+
| Ethernet18 | Enabled |
4499+
+------------------+----------+
4500+
```
4501+
4502+
Go Back To [Beginning of the document](#) or [Beginning of this section](#ipv6-link-local)
44104503
44114504
## Kubernetes
44124505

0 commit comments

Comments
 (0)