Skip to content

Commit aee2d04

Browse files
sabakramarfeigin
authored andcommitted
Switchport Mode & CLI Modified Fix (sonic-net#3247)
This PR is Fixture for sonic-net#3108 The PR was reverted due to backward compatibility issues. As per new suggestions, removed db migrator changes from this new change along with vlan.py & switchport.py changes To Fix issues as per suggestions removed default mode from YANG model and removed minigraph changes: 1. Removed Db migrator changes from code. 2. Modified Vlan.py & Switchport.py changes New commands have been added in Command-Reference.md All the syntax and examples have been added there and they can be verified by running the specific command
1 parent bbce555 commit aee2d04

File tree

13 files changed

+2021
-403
lines changed

13 files changed

+2021
-403
lines changed

config/main.py

Lines changed: 32 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -57,8 +57,10 @@
5757
from .config_mgmt import ConfigMgmtDPB, ConfigMgmt
5858
from . import mclag
5959
from . import syslog
60+
from . import switchport
6061
from . import dns
6162

63+
6264
# mock masic APIs for unit test
6365
try:
6466
if os.environ["UTILITIES_UNIT_TESTING"] == "1" or os.environ["UTILITIES_UNIT_TESTING"] == "2":
@@ -104,6 +106,7 @@
104106
PORT_SPEED = "speed"
105107
PORT_TPID = "tpid"
106108
DEFAULT_TPID = "0x8100"
109+
PORT_MODE = "switchport_mode"
107110

108111
DOM_CONFIG_SUPPORTED_SUBPORTS = ['0', '1']
109112

@@ -1230,6 +1233,9 @@ def config(ctx):
12301233
# DNS module
12311234
config.add_command(dns.dns)
12321235

1236+
# Switchport module
1237+
config.add_command(switchport.switchport)
1238+
12331239
@config.command()
12341240
@click.option('-y', '--yes', is_flag=True, callback=_abort_if_false,
12351241
expose_value=False, prompt='Existing files will be overwritten, continue?')
@@ -4638,19 +4644,38 @@ def add(ctx, interface_name, ip_addr, gw):
46384644
if interface_name is None:
46394645
ctx.fail("'interface_name' is None!")
46404646

4641-
# Add a validation to check this interface is not a member in vlan before
4642-
# changing it to a router port
4643-
vlan_member_table = config_db.get_table('VLAN_MEMBER')
4644-
if (interface_is_in_vlan(vlan_member_table, interface_name)):
4645-
click.echo("Interface {} is a member of vlan\nAborting!".format(interface_name))
4646-
return
4647-
46484647
portchannel_member_table = config_db.get_table('PORTCHANNEL_MEMBER')
46494648

46504649
if interface_is_in_portchannel(portchannel_member_table, interface_name):
46514650
ctx.fail("{} is configured as a member of portchannel."
46524651
.format(interface_name))
46534652

4653+
# Add a validation to check this interface is in routed mode before
4654+
# assigning an IP address to it
4655+
4656+
sub_intf = False
4657+
4658+
if clicommon.is_valid_port(config_db, interface_name):
4659+
is_port = True
4660+
elif clicommon.is_valid_portchannel(config_db, interface_name):
4661+
is_port = False
4662+
else:
4663+
sub_intf = True
4664+
4665+
if not sub_intf:
4666+
interface_mode = None
4667+
if is_port:
4668+
interface_data = config_db.get_entry('PORT', interface_name)
4669+
else:
4670+
interface_data = config_db.get_entry('PORTCHANNEL', interface_name)
4671+
4672+
if "mode" in interface_data:
4673+
interface_mode = interface_data["mode"]
4674+
4675+
if interface_mode == "trunk" or interface_mode == "access":
4676+
click.echo("Interface {} is in {} mode and needs to be in routed mode!".format(
4677+
interface_name, interface_mode))
4678+
return
46544679
try:
46554680
ip_address = ipaddress.ip_interface(ip_addr)
46564681
except ValueError as err:

config/switchport.py

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
import click
2+
from .utils import log
3+
import utilities_common.cli as clicommon
4+
5+
#
6+
# 'switchport' mode ('config switchport ...')
7+
#
8+
9+
10+
@click.group(cls=clicommon.AbbreviationGroup, name='switchport', invoke_without_command=False)
11+
def switchport():
12+
"""Switchport mode configuration tasks"""
13+
pass
14+
15+
16+
@switchport.command("mode")
17+
@click.argument("type", metavar="<mode_type>", required=True, type=click.Choice(["access", "trunk", "routed"]))
18+
@click.argument("port", metavar="port", required=True)
19+
@clicommon.pass_db
20+
def switchport_mode(db, type, port):
21+
"""switchport mode help commands.Mode_type can be access or trunk or routed"""
22+
23+
ctx = click.get_current_context()
24+
25+
log.log_info("'switchport mode {} {}' executing...".format(type, port))
26+
mode_exists_status = True
27+
28+
# checking if port name with alias exists
29+
if clicommon.get_interface_naming_mode() == "alias":
30+
alias = port
31+
iface_alias_converter = clicommon.InterfaceAliasConverter(db)
32+
port = iface_alias_converter.alias_to_name(alias)
33+
34+
if clicommon.is_port_mirror_dst_port(db.cfgdb, port):
35+
ctx.fail("{} is configured as mirror destination port".format(port))
36+
37+
if clicommon.is_valid_port(db.cfgdb, port):
38+
is_port = True
39+
elif clicommon.is_valid_portchannel(db.cfgdb, port):
40+
is_port = False
41+
else:
42+
ctx.fail("{} does not exist".format(port))
43+
44+
portchannel_member_table = db.cfgdb.get_table('PORTCHANNEL_MEMBER')
45+
46+
if (is_port and clicommon.interface_is_in_portchannel(portchannel_member_table, port)):
47+
ctx.fail("{} is part of portchannel!".format(port))
48+
49+
if is_port:
50+
port_data = db.cfgdb.get_entry('PORT', port)
51+
else:
52+
port_data = db.cfgdb.get_entry('PORTCHANNEL', port)
53+
54+
# mode type is either access or trunk
55+
if type != "routed":
56+
57+
if "mode" in port_data:
58+
existing_mode = port_data["mode"]
59+
else:
60+
mode_exists_status = False
61+
62+
if (is_port and clicommon.is_port_router_interface(db.cfgdb, port)) or \
63+
(not is_port and clicommon.is_pc_router_interface(db.cfgdb, port)):
64+
ctx.fail("Remove IP from {} to change mode!".format(port))
65+
66+
if not mode_exists_status:
67+
port_data["mode"] = type
68+
if is_port:
69+
db.cfgdb.set_entry("PORT", port, port_data)
70+
# if not port then is a port channel
71+
elif not is_port:
72+
db.cfgdb.set_entry("PORTCHANNEL", port, port_data)
73+
74+
if mode_exists_status:
75+
if existing_mode == "routed":
76+
# if the port in an interface
77+
if is_port:
78+
db.cfgdb.mod_entry("PORT", port, {"mode": "{}".format(type)})
79+
# if not port then is a port channel
80+
elif not is_port:
81+
db.cfgdb.mod_entry("PORTCHANNEL", port, {"mode": "{}".format(type)})
82+
83+
if existing_mode == type:
84+
ctx.fail("{} is already in {} mode".format(port, type))
85+
else:
86+
if existing_mode == "access" and type == "trunk":
87+
pass
88+
if existing_mode == "trunk" and type == "access":
89+
if clicommon.interface_is_tagged_member(db.cfgdb, port):
90+
ctx.fail(
91+
"{} is in {} mode and have tagged member(s).\nRemove "
92+
"tagged member(s) from {} to switch to {} mode".format(port, existing_mode, port, type))
93+
if is_port:
94+
db.cfgdb.mod_entry("PORT", port, {"mode": "{}".format(type)})
95+
# if not port then is a port channel
96+
elif not is_port:
97+
db.cfgdb.mod_entry("PORTCHANNEL", port, {"mode": "{}".format(type)})
98+
99+
click.echo("{} switched to {} mode".format(port, type))
100+
101+
# if mode type is routed
102+
else:
103+
104+
if clicommon.interface_is_tagged_member(db.cfgdb, port):
105+
ctx.fail("{} has tagged member(s). \nRemove them to change mode to {}".format(port, type))
106+
107+
if clicommon.interface_is_untagged_member(db.cfgdb, port):
108+
ctx.fail("{} has untagged member. \nRemove it to change mode to {}".format(port, type))
109+
110+
if "mode" in port_data:
111+
existing_mode = port_data["mode"]
112+
else:
113+
mode_exists_status = False
114+
115+
if not mode_exists_status:
116+
port_data["mode"] = type
117+
if is_port:
118+
db.cfgdb.set_entry("PORT", port, port_data)
119+
120+
# if not port then is a port channel
121+
elif not is_port:
122+
db.cfgdb.set_entry("PORTCHANNEL", port, port_data)
123+
pass
124+
125+
if mode_exists_status:
126+
if existing_mode == type:
127+
ctx.fail("{} is already in {} mode".format(port, type))
128+
else:
129+
if is_port:
130+
db.cfgdb.mod_entry("PORT", port, {"mode": "{}".format(type)})
131+
# if not port then is a port channel
132+
elif not is_port:
133+
db.cfgdb.mod_entry("PORTCHANNEL", port, {"mode": "{}".format(type)})
134+
135+
click.echo("{} switched to {} mode".format(port, type))

0 commit comments

Comments
 (0)