Skip to content

Commit

Permalink
Add support to configure routed subinterface in short name and long name
Browse files Browse the repository at this point in the history
format
Update "show subniterface status" to reflect subinterface in user
configured long name and short name format.
  • Loading branch information
preetham-singh committed Sep 15, 2021
1 parent 2b12aad commit 88bae6d
Show file tree
Hide file tree
Showing 2 changed files with 123 additions and 2 deletions.
121 changes: 120 additions & 1 deletion config/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
from portconfig import get_child_ports
from socket import AF_INET, AF_INET6
from sonic_py_common import device_info, multi_asic
from sonic_py_common.interface import get_interface_table_name, get_port_table_name
from sonic_py_common.interface import get_interface_table_name, get_port_table_name, intf_get_longname
from utilities_common import util_base
from swsscommon.swsscommon import SonicV2Connector, ConfigDBConnector
from utilities_common.db import Db
Expand Down Expand Up @@ -5846,6 +5846,125 @@ def smoothing_interval(interval, rates_type):
for plugin in helper.load_plugins(plugins):
helper.register_plugin(plugin, config)

#
# 'subinterface' group ('config subinterface ...')
#
@config.group()
@click.pass_context
@click.option('-s', '--redis-unix-socket-path', help='unix socket path for redis connection')
def subinterface(ctx, redis_unix_socket_path):
"""subinterface-related configuration tasks"""
kwargs = {}
if redis_unix_socket_path:
kwargs['unix_socket_path'] = redis_unix_socket_path
config_db = ConfigDBConnector(**kwargs)
config_db.connect(wait_for_init=False)
ctx.obj = {'db': config_db}
pass

def subintf_vlan_check(config_db, parent_intf, vlan):
subintf_db = config_db.get_table('VLAN_SUB_INTERFACE')
subintf_names = [k for k in subintf_db if type(k) != tuple]
for subintf in subintf_names:
sub_intf_sep_idx = subintf.find(VLAN_SUB_INTERFACE_SEPARATOR)
if sub_intf_sep_idx == -1:
continue
if parent_intf == subintf[:sub_intf_sep_idx]:
if 'vlan' in subintf_db[subintf]:
if str(vlan) == subintf_db[subintf]['vlan']:
return True
else:
vlan_id = subintf[sub_intf_sep_idx + 1:]
if str(vlan) == vlan_id:
return True
return False

@subinterface.command('add')
@click.argument('subinterface_name', metavar='<subinterface_name>', required=True)
@click.argument('vid', metavar='<vid>', required=False, type=click.IntRange(1,4094))
@click.pass_context
def add_subinterface(ctx, subinterface_name, vid):
sub_intf_sep_idx = subinterface_name.find(VLAN_SUB_INTERFACE_SEPARATOR)
if sub_intf_sep_idx == -1:
ctx.fail("{} is invalid vlan subinterface".format(subinterface_name))

interface_alias = subinterface_name[:sub_intf_sep_idx]
vlan_id = subinterface_name[sub_intf_sep_idx + 1:]
if interface_alias is None:
ctx.fail("{} invalid subinterface".format(interface_alias))

if interface_alias.startswith("Po") is True:
intf_table_name = CFG_PORTCHANNEL_PREFIX
elif interface_alias.startswith("Eth") is True:
intf_table_name = 'PORT'

config_db = ctx.obj['db']
port_dict = config_db.get_table(intf_table_name)
if interface_alias is not None:
if not port_dict:
ctx.fail("{} parent interface not found. {} table none".format(interface_alias, intf_table_name))
if intf_get_longname(interface_alias) not in port_dict.keys():
ctx.fail("{} parent interface not found".format(subinterface_name))

# Validate if parent is portchannel member
portchannel_member_table = config_db.get_table('PORTCHANNEL_MEMBER')
if interface_is_in_portchannel(portchannel_member_table, interface_alias):
ctx.fail("{} is configured as a member of portchannel. Cannot configure subinterface"
.format(interface_alias))

# Validate if parent is vlan member
vlan_member_table = config_db.get_table('VLAN_MEMBER')
if interface_is_in_vlan(vlan_member_table, interface_alias):
ctx.fail("{} is configured as a member of vlan. Cannot configure subinterface"
.format(interface_alias))

sub_intfs = [k for k,v in config_db.get_table('VLAN_SUB_INTERFACE').items() if type(k) != tuple]
if subinterface_name in sub_intfs:
ctx.fail("{} already exists".format(subinterface_name))

subintf_dict = {}
if vid is not None:
subintf_dict.update({"vlan" : vid})

if subintf_vlan_check(config_db, intf_get_longname(interface_alias), vid) is True:
ctx.fail("Vlan {} encap already configured on other subinterface on {}".format(vid, interface_alias))

subintf_dict.update({"admin_status" : "up"})
config_db.set_entry('VLAN_SUB_INTERFACE', subinterface_name, subintf_dict)

@subinterface.command('del')
@click.argument('subinterface_name', metavar='<subinterface_name>', required=True)
@click.pass_context
def del_subinterface(ctx, subinterface_name):
sub_intf_sep_idx = subinterface_name.find(VLAN_SUB_INTERFACE_SEPARATOR)
if sub_intf_sep_idx == -1:
ctx.fail("{} is invalid vlan subinterface".format(subinterface_name))

config_db = ctx.obj['db']
#subinterface_name = subintf_get_shortname(subinterface_name)
if interface_name_is_valid(config_db, subinterface_name) is False:
ctx.fail("{} is invalid ".format(subinterface_name))

subintf_config_db = config_db.get_table('VLAN_SUB_INTERFACE')
sub_intfs = [k for k,v in subintf_config_db.items() if type(k) != tuple]
if subinterface_name not in sub_intfs:
ctx.fail("{} does not exists".format(subinterface_name))

ips = {}
ips = [ k[1] for k in config_db.get_table('VLAN_SUB_INTERFACE') if type(k) == tuple and k[0] == subinterface_name ]
for ip in ips:
try:
ipaddress.ip_network(ip, strict=False)
config_db.set_entry('VLAN_SUB_INTERFACE', (subinterface_name, ip), None)
except ValueError:
ctx.fail("Invalid ip {} found on interface {}".format(ip, subinterface_name))

subintf_config_db = config_db.get_table('INTERFACE')
ips = [ k[1] for k in subintf_config_db if type(k) == tuple and k[0] == subinterface_name ]
for ip in ips:
config_db.set_entry('INTERFACE', (subinterface_name, ip), None)

config_db.set_entry('VLAN_SUB_INTERFACE', subinterface_name, None)

if __name__ == '__main__':
config()
4 changes: 3 additions & 1 deletion scripts/intfutil
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ from tabulate import tabulate
from utilities_common import constants
from utilities_common import multi_asic as multi_asic_util
from utilities_common.intf_filter import parse_interface_in_filter
from sonic_py_common.interface import intf_get_longname

# mock the redis for unit test purposes #
try:
Expand Down Expand Up @@ -313,12 +314,13 @@ def appl_db_portchannel_status_get(appl_db, config_db, po_name, status_type, por
def appl_db_sub_intf_status_get(appl_db, config_db, front_panel_ports_list, portchannel_speed_dict, sub_intf_name, status_type):
sub_intf_sep_idx = sub_intf_name.find(VLAN_SUB_INTERFACE_SEPARATOR)
if sub_intf_sep_idx != -1:
parent_port_name = sub_intf_name[:sub_intf_sep_idx]
parent_port_name = intf_get_longname(sub_intf_name[:sub_intf_sep_idx])
vlan_id = sub_intf_name[sub_intf_sep_idx + 1:]

full_intf_table_name = "INTF_TABLE" + ":" + sub_intf_name

if status_type == "vlan":
vlan_id = appl_db.get(appl_db.APPL_DB, full_intf_table_name, status_type)
return vlan_id

if status_type == "admin_status":
Expand Down

0 comments on commit 88bae6d

Please sign in to comment.