Skip to content

Commit cf2203f

Browse files
Updating Config vrf bind/unbind CLIs to skip deletion of subinterface
instead update existing subinterface. Updating unit testcases for subinterfaces.
1 parent 5f2d923 commit cf2203f

File tree

7 files changed

+183
-3
lines changed

7 files changed

+183
-3
lines changed

config/main.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4814,13 +4814,21 @@ def unbind(ctx, interface_name):
48144814
table_name = get_interface_table_name(interface_name)
48154815
if table_name == "":
48164816
ctx.fail("'interface_name' is not valid. Valid names [Ethernet/PortChannel/Vlan/Loopback]")
4817+
48174818
if is_interface_bind_to_vrf(config_db, interface_name) is False:
48184819
return
4820+
if table_name == "VLAN_SUB_INTERFACE":
4821+
subintf_entry = config_db.get_entry(table_name, interface_name)
4822+
if 'vrf_name' in subintf_entry:
4823+
subintf_entry.pop('vrf_name')
4824+
48194825
interface_ipaddresses = get_interface_ipaddresses(config_db, interface_name)
48204826
for ipaddress in interface_ipaddresses:
48214827
remove_router_interface_ip_address(config_db, interface_name, ipaddress)
4822-
config_db.set_entry(table_name, interface_name, None)
4823-
4828+
if table_name == "VLAN_SUB_INTERFACE":
4829+
config_db.set_entry(table_name, interface_name, subintf_entry)
4830+
else:
4831+
config_db.set_entry(table_name, interface_name, None)
48244832

48254833
#
48264834
# 'ipv6' subgroup ('config interface ipv6 ...')

tests/intfutil_test.py

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -210,7 +210,8 @@ def test_subintf_status(self):
210210
"Sub port interface Speed MTU Vlan Admin Type\n"
211211
"-------------------- ------- ----- ------ ------- --------------------\n"
212212
" Eth32.10 40G 9100 100 up 802.1q-encapsulation\n"
213-
" Ethernet0.10 25G 9100 10 up 802.1q-encapsulation"
213+
" Ethernet0.10 25G 9100 10 up 802.1q-encapsulation\n"
214+
" Po0001.10 40G 9100 100 up 802.1q-encapsulation"
214215
)
215216
self.assertEqual(result.output.strip(), expected_output)
216217

@@ -254,6 +255,16 @@ def test_single_subintf_status(self):
254255
print(output, file=sys.stderr)
255256
self.assertEqual(output.strip(), expected_output)
256257

258+
expected_output = (
259+
"Sub port interface Speed MTU Vlan Admin Type\n"
260+
"-------------------- ------- ----- ------ ------- --------------------\n"
261+
" Po0001.10 40G 9100 100 up 802.1q-encapsulation"
262+
)
263+
# Test 'intfutil status Po0001.10'
264+
output = subprocess.check_output('intfutil -c status -i Po0001.10', stderr=subprocess.STDOUT, shell=True, text=True)
265+
print(output, file=sys.stderr)
266+
self.assertEqual(output.strip(), expected_output)
267+
257268
# Test '--verbose' status of single sub interface
258269
def test_single_subintf_status_verbose(self):
259270
result = self.runner.invoke(show.cli.commands["subinterfaces"].commands["status"], ["Ethernet0.10", "--verbose"])
@@ -266,6 +277,11 @@ def test_single_subintf_status_verbose(self):
266277
expected_output = "Command: intfutil -c status -i Eth32.10"
267278
self.assertEqual(result.output.split('\n')[0], expected_output)
268279

280+
result = self.runner.invoke(show.cli.commands["subinterfaces"].commands["status"], ["Po0001.10", "--verbose"])
281+
print(result.output, file=sys.stderr)
282+
expected_output = "Command: intfutil -c status -i Po0001.10"
283+
self.assertEqual(result.output.split('\n')[0], expected_output)
284+
269285
# Test status of single sub interface in alias naming mode
270286
def test_single_subintf_status_alias_mode(self):
271287
os.environ["SONIC_CLI_IFACE_MODE"] = "alias"

tests/ip_config_test.py

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,12 +29,36 @@ def test_add_del_interface_valid_ipv4(self):
2929
assert result.exit_code == 0
3030
assert ('Ethernet64', '10.10.10.1/24') in db.cfgdb.get_table('INTERFACE')
3131

32+
# config int ip add Ethernet0.10 10.11.10.1/24
33+
result = runner.invoke(config.config.commands["interface"].commands["ip"].commands["add"], ["Ethernet0.10", "10.11.10.1/24"], obj=obj)
34+
print(result.exit_code, result.output)
35+
assert result.exit_code == 0
36+
assert ('Ethernet0.10', '10.11.10.1/24') in db.cfgdb.get_table('VLAN_SUB_INTERFACE')
37+
38+
# config int ip add Eth32.10 32.11.10.1/24
39+
result = runner.invoke(config.config.commands["interface"].commands["ip"].commands["add"], ["Eth32.10", "32.11.10.1/24"], obj=obj)
40+
print(result.exit_code, result.output)
41+
assert result.exit_code == 0
42+
assert ('Eth32.10', '32.11.10.1/24') in db.cfgdb.get_table('VLAN_SUB_INTERFACE')
43+
3244
# config int ip remove Ethernet64 10.10.10.1/24
3345
result = runner.invoke(config.config.commands["interface"].commands["ip"].commands["remove"], ["Ethernet64", "10.10.10.1/24"], obj=obj)
3446
print(result.exit_code, result.output)
3547
assert result.exit_code != 0
3648
assert ('Ethernet64', '10.10.10.1/24') not in db.cfgdb.get_table('INTERFACE')
3749

50+
# config int ip remove Ethernet0.10 10.11.10.1/24
51+
result = runner.invoke(config.config.commands["interface"].commands["ip"].commands["remove"], ["Ethernet0.10", "10.11.10.1/24"], obj=obj)
52+
print(result.exit_code, result.output)
53+
assert result.exit_code != 0
54+
assert ('Ethernet0.10', '10.11.10.1/24') not in db.cfgdb.get_table('VLAN_SUB_INTERFACE')
55+
56+
# config int ip remove Eth32.10 32.11.10.1/24
57+
result = runner.invoke(config.config.commands["interface"].commands["ip"].commands["remove"], ["Eth32.10", "32.11.10.1/24"], obj=obj)
58+
print(result.exit_code, result.output)
59+
assert result.exit_code != 0
60+
assert ('Eth32.10', '32.11.10.1/24') not in db.cfgdb.get_table('VLAN_SUB_INTERFACE')
61+
3862
def test_add_interface_invalid_ipv4(self):
3963
db = Db()
4064
runner = CliRunner()
@@ -81,12 +105,32 @@ def test_add_del_interface_valid_ipv6(self):
81105
assert result.exit_code == 0
82106
assert ('Ethernet72', '2001:1db8:11a3:19d7:1f34:8a2e:17a0:765d/34') in db.cfgdb.get_table('INTERFACE')
83107

108+
result = runner.invoke(config.config.commands["interface"].commands["ip"].commands["add"], ["Ethernet0.10", "1010:1db8:11a3:19d7:1f34:8a2e:17a0:765d/34"], obj=obj)
109+
print(result.exit_code, result.output)
110+
assert result.exit_code == 0
111+
assert ('Ethernet0.10', '1010:1db8:11a3:19d7:1f34:8a2e:17a0:765d/34') in db.cfgdb.get_table('VLAN_SUB_INTERFACE')
112+
113+
result = runner.invoke(config.config.commands["interface"].commands["ip"].commands["add"], ["Eth32.10", "3210:1db8:11a3:19d7:1f34:8a2e:17a0:765d/34"], obj=obj)
114+
print(result.exit_code, result.output)
115+
assert result.exit_code == 0
116+
assert ('Eth32.10', '3210:1db8:11a3:19d7:1f34:8a2e:17a0:765d/34') in db.cfgdb.get_table('VLAN_SUB_INTERFACE')
117+
84118
# config int ip remove Ethernet72 2001:1db8:11a3:19d7:1f34:8a2e:17a0:765d/34
85119
result = runner.invoke(config.config.commands["interface"].commands["ip"].commands["remove"], ["Ethernet72", "2001:1db8:11a3:19d7:1f34:8a2e:17a0:765d/34"], obj=obj)
86120
print(result.exit_code, result.output)
87121
assert result.exit_code != 0
88122
assert ('Ethernet72', '2001:1db8:11a3:19d7:1f34:8a2e:17a0:765d/34') not in db.cfgdb.get_table('INTERFACE')
89123

124+
result = runner.invoke(config.config.commands["interface"].commands["ip"].commands["remove"], ["Ethernet0.10", "1010:1db8:11a3:19d7:1f34:8a2e:17a0:765d/34"], obj=obj)
125+
print(result.exit_code, result.output)
126+
assert result.exit_code != 0
127+
assert ('Ethernet0.10', '1010:1db8:11a3:19d7:1f34:8a2e:17a0:765d/34') not in db.cfgdb.get_table('VLAN_SUB_INTERFACE')
128+
129+
result = runner.invoke(config.config.commands["interface"].commands["ip"].commands["remove"], ["Eth32.10", "3210:1db8:11a3:19d7:1f34:8a2e:17a0:765d/34"], obj=obj)
130+
print(result.exit_code, result.output)
131+
assert result.exit_code != 0
132+
assert ('Eth32.10', '3210:1db8:11a3:19d7:1f34:8a2e:17a0:765d/34') not in db.cfgdb.get_table('VLAN_SUB_INTERFACE')
133+
90134
def test_del_interface_case_sensitive_ipv6(self):
91135
db = Db()
92136
runner = CliRunner()

tests/mock_tables/appl_db.json

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,8 +190,34 @@
190190
},
191191
"INTF_TABLE:Eth32.10": {
192192
"admin_status": "up",
193+
"vrf_name": "Vrf1",
193194
"vlan": "100"
194195
},
196+
"INTF_TABLE:Po0001.10": {
197+
"admin_status": "up",
198+
"vrf_name": "Vrf1",
199+
"vlan": "100"
200+
},
201+
"INTF_TABLE:Ethernet0.10|10.11.12.13/24": {
202+
"family": "IPv4",
203+
"scope": "global"
204+
},
205+
"INTF_TABLE:Eth32.10|32.10.11.12/24": {
206+
"family": "IPv4",
207+
"scope": "global"
208+
},
209+
"INTF_TABLE:Po0001.10|10.10.11.12/24": {
210+
"family": "IPv4",
211+
"scope": "global"
212+
},
213+
"INTF_TABLE:Eth32.10|3210::12/126": {
214+
"family": "IPv6",
215+
"scope": "global"
216+
},
217+
"INTF_TABLE:Po0001.10|1010::12/126": {
218+
"family": "IPv6",
219+
"scope": "global"
220+
},
195221
"_GEARBOX_TABLE:phy:1": {
196222
"name": "sesto-1",
197223
"phy_id": "1",

tests/mock_tables/config_db.json

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -378,11 +378,26 @@
378378
},
379379
"VLAN_SUB_INTERFACE|Eth32.10": {
380380
"admin_status": "up",
381+
"vrf_name": "Vrf1",
381382
"vlan": "100"
382383
},
383384
"VLAN_SUB_INTERFACE|Eth32.10|32.10.11.12/24": {
384385
"NULL" : "NULL"
385386
},
387+
"VLAN_SUB_INTERFACE|Eth32.10|3210::12/126": {
388+
"NULL" : "NULL"
389+
},
390+
"VLAN_SUB_INTERFACE|Po0001.10": {
391+
"admin_status": "up",
392+
"vrf_name": "Vrf1",
393+
"vlan": "100"
394+
},
395+
"VLAN_SUB_INTERFACE|Po0001.10|10.10.11.12/24": {
396+
"NULL" : "NULL"
397+
},
398+
"VLAN_SUB_INTERFACE|Po0001.10|1010::12/126": {
399+
"NULL" : "NULL"
400+
},
386401
"ACL_RULE|NULL_ROUTE_V4|DEFAULT_RULE": {
387402
"PACKET_ACTION": "DROP",
388403
"PRIORITY": "1"

tests/show_vrf_test.py

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
from swsscommon.swsscommon import SonicV2Connector
55
from utilities_common.db import Db
66

7+
import config.main as config
78
import show.main as show
89

910
test_path = os.path.dirname(os.path.abspath(__file__))
@@ -31,6 +32,71 @@ def test_vrf_show(self):
3132
Eth32.10
3233
Vrf103 Ethernet4
3334
Loopback0
35+
Po0002.101
36+
"""
37+
38+
result = runner.invoke(show.cli.commands['vrf'], [], obj=db)
39+
dbconnector.dedicated_dbs = {}
40+
assert result.exit_code == 0
41+
assert result.output == expected_output
42+
43+
def test_vrf_bind_unbind(self):
44+
from .mock_tables import dbconnector
45+
jsonfile_config = os.path.join(mock_db_path, "config_db")
46+
dbconnector.dedicated_dbs['CONFIG_DB'] = jsonfile_config
47+
runner = CliRunner()
48+
db = Db()
49+
expected_output = """\
50+
VRF Interfaces
51+
------ ---------------
52+
Vrf1
53+
Vrf101 Ethernet0.10
54+
Vrf102 PortChannel0002
55+
Vlan40
56+
Eth32.10
57+
Vrf103 Ethernet4
58+
Loopback0
59+
Po0002.101
60+
"""
61+
62+
result = runner.invoke(show.cli.commands['vrf'], [], obj=db)
63+
dbconnector.dedicated_dbs = {}
64+
assert result.exit_code == 0
65+
assert result.output == expected_output
66+
67+
obj = {'config_db':db.cfgdb}
68+
result = runner.invoke(config.config.commands["interface"].commands["vrf"].commands["unbind"], ["Eth32.10"], obj=obj)
69+
print(result.exit_code, result.output)
70+
assert result.exit_code == 0
71+
assert ('vrf_name', 'Vrf102') not in db.cfgdb.get_table('VLAN_SUB_INTERFACE')['Eth32.10']
72+
73+
result = runner.invoke(config.config.commands["interface"].commands["vrf"].commands["unbind"], ["Ethernet0.10"], obj=obj)
74+
print(result.exit_code, result.output)
75+
assert result.exit_code == 0
76+
assert ('vrf_name', 'Vrf101') not in db.cfgdb.get_table('VLAN_SUB_INTERFACE')['Ethernet0.10']
77+
78+
result = runner.invoke(config.config.commands["interface"].commands["vrf"].commands["unbind"], ["Po0002.101"], obj=obj)
79+
print(result.exit_code, result.output)
80+
assert result.exit_code == 0
81+
assert ('vrf_name', 'Vrf103') not in db.cfgdb.get_table('VLAN_SUB_INTERFACE')['Po0002.101']
82+
83+
84+
#Bind click CLI cannot be tested as it tries to connecte to statedb
85+
#for verification of all IP address delete before applying new vrf configuration
86+
jsonfile_config = os.path.join(mock_db_path, "config_db")
87+
dbconnector.dedicated_dbs['CONFIG_DB'] = jsonfile_config
88+
89+
expected_output = """\
90+
VRF Interfaces
91+
------ ---------------
92+
Vrf1
93+
Vrf101 Ethernet0.10
94+
Vrf102 PortChannel0002
95+
Vlan40
96+
Eth32.10
97+
Vrf103 Ethernet4
98+
Loopback0
99+
Po0002.101
34100
"""
35101

36102
result = runner.invoke(show.cli.commands['vrf'], [], obj=db)

tests/vrf_input/config_db.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,11 @@
88
"admin_status": "up",
99
"vlan": "100"
1010
},
11+
"VLAN_SUB_INTERFACE|Po0002.101": {
12+
"vrf_name": "Vrf103",
13+
"admin_status": "up",
14+
"vlan": "1001"
15+
},
1116
"VLAN_INTERFACE|Vlan40": {
1217
"vrf_name": "Vrf102"
1318
},

0 commit comments

Comments
 (0)