Skip to content

Commit 03ae3b0

Browse files
committed
[config/load_mgmt_config] Support load IPv6 mgmt IP (sonic-net#2206)
* [config/load_mgmt_config] Support load IPv6 mgmt IP Signed-off-by: Jing Kan [email protected]
1 parent 5a54bd7 commit 03ae3b0

File tree

3 files changed

+143
-11
lines changed

3 files changed

+143
-11
lines changed

config/main.py

+19-10
Original file line numberDiff line numberDiff line change
@@ -1283,16 +1283,25 @@ def load_mgmt_config(filename):
12831283
config_data = parse_device_desc_xml(filename)
12841284
hostname = config_data['DEVICE_METADATA']['localhost']['hostname']
12851285
_change_hostname(hostname)
1286-
mgmt_conf = netaddr.IPNetwork(list(config_data['MGMT_INTERFACE'].keys())[0][1])
1287-
gw_addr = list(config_data['MGMT_INTERFACE'].values())[0]['gwaddr']
1288-
command = "ifconfig eth0 {} netmask {}".format(str(mgmt_conf.ip), str(mgmt_conf.netmask))
1289-
clicommon.run_command(command, display_cmd=True)
1290-
command = "ip route add default via {} dev eth0 table default".format(gw_addr)
1291-
clicommon.run_command(command, display_cmd=True, ignore_error=True)
1292-
command = "ip rule add from {} table default".format(str(mgmt_conf.ip))
1293-
clicommon.run_command(command, display_cmd=True, ignore_error=True)
1294-
command = "[ -f /var/run/dhclient.eth0.pid ] && kill `cat /var/run/dhclient.eth0.pid` && rm -f /var/run/dhclient.eth0.pid"
1295-
clicommon.run_command(command, display_cmd=True, ignore_error=True)
1286+
for key in list(config_data['MGMT_INTERFACE'].keys()):
1287+
# key: (eth0, ipprefix)
1288+
# value: { gwaddr: ip }
1289+
mgmt_conf = netaddr.IPNetwork(key[1])
1290+
gw_addr = config_data['MGMT_INTERFACE'][key]['gwaddr']
1291+
if mgmt_conf.version == 4:
1292+
command = "ifconfig eth0 {} netmask {}".format(str(mgmt_conf.ip), str(mgmt_conf.netmask))
1293+
clicommon.run_command(command, display_cmd=True)
1294+
else:
1295+
command = "ifconfig eth0 add {}".format(str(mgmt_conf))
1296+
# Ignore error for IPv6 configuration command due to it not allows config the same IP twice
1297+
clicommon.run_command(command, display_cmd=True, ignore_error=True)
1298+
command = "ip{} route add default via {} dev eth0 table default".format(" -6" if mgmt_conf.version == 6 else "", gw_addr)
1299+
clicommon.run_command(command, display_cmd=True, ignore_error=True)
1300+
command = "ip{} rule add from {} table default".format(" -6" if mgmt_conf.version == 6 else "", str(mgmt_conf.ip))
1301+
clicommon.run_command(command, display_cmd=True, ignore_error=True)
1302+
if len(config_data['MGMT_INTERFACE'].keys()) > 0:
1303+
command = "[ -f /var/run/dhclient.eth0.pid ] && kill `cat /var/run/dhclient.eth0.pid` && rm -f /var/run/dhclient.eth0.pid"
1304+
clicommon.run_command(command, display_cmd=True, ignore_error=True)
12961305
click.echo("Please note loaded setting will be lost after system reboot. To preserve setting, run `config save`.")
12971306

12981307
@config.command("load_minigraph")

doc/Command-Reference.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -4635,7 +4635,7 @@ running on the device.
46354635
46364636
This command is used to reconfigure hostname and mgmt interface based on device description file.
46374637
This command either uses the optional file specified as arguement or looks for the file "/etc/sonic/device_desc.xml".
4638-
If the file does not exist or if the file does not have valid fields for "hostname" and "ManagementAddress", it fails.
4638+
If the file does not exist or if the file does not have valid fields for "hostname" and "ManagementAddress" (or "ManagementAddressV6"), it fails.
46394639
46404640
When user specifies the optional argument "-y" or "--yes", this command forces the loading without prompting the user for confirmation.
46414641
If the argument is not specified, it prompts the user to confirm whether user really wants to load this configuration file.

tests/config_test.py

+123
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,10 @@
33
import os
44
import traceback
55
import json
6+
import jsonpatch
7+
import sys
8+
import unittest
9+
import ipaddress
610
from unittest import mock
711

812
import click
@@ -21,6 +25,42 @@
2125
Please note setting loaded from minigraph will be lost after system reboot. To preserve setting, run `config save`.
2226
"""
2327

28+
load_mgmt_config_command_ipv4_only_output="""\
29+
Running command: /usr/local/bin/sonic-cfggen -M device_desc.xml --write-to-db
30+
parse dummy device_desc.xml
31+
change hostname to dummy
32+
Running command: ifconfig eth0 10.0.0.100 netmask 255.255.255.0
33+
Running command: ip route add default via 10.0.0.1 dev eth0 table default
34+
Running command: ip rule add from 10.0.0.100 table default
35+
Running command: [ -f /var/run/dhclient.eth0.pid ] && kill `cat /var/run/dhclient.eth0.pid` && rm -f /var/run/dhclient.eth0.pid
36+
Please note loaded setting will be lost after system reboot. To preserve setting, run `config save`.
37+
"""
38+
39+
load_mgmt_config_command_ipv6_only_output="""\
40+
Running command: /usr/local/bin/sonic-cfggen -M device_desc.xml --write-to-db
41+
parse dummy device_desc.xml
42+
change hostname to dummy
43+
Running command: ifconfig eth0 add fc00:1::32/64
44+
Running command: ip -6 route add default via fc00:1::1 dev eth0 table default
45+
Running command: ip -6 rule add from fc00:1::32 table default
46+
Running command: [ -f /var/run/dhclient.eth0.pid ] && kill `cat /var/run/dhclient.eth0.pid` && rm -f /var/run/dhclient.eth0.pid
47+
Please note loaded setting will be lost after system reboot. To preserve setting, run `config save`.
48+
"""
49+
50+
load_mgmt_config_command_ipv4_ipv6_output="""\
51+
Running command: /usr/local/bin/sonic-cfggen -M device_desc.xml --write-to-db
52+
parse dummy device_desc.xml
53+
change hostname to dummy
54+
Running command: ifconfig eth0 10.0.0.100 netmask 255.255.255.0
55+
Running command: ip route add default via 10.0.0.1 dev eth0 table default
56+
Running command: ip rule add from 10.0.0.100 table default
57+
Running command: ifconfig eth0 add fc00:1::32/64
58+
Running command: ip -6 route add default via fc00:1::1 dev eth0 table default
59+
Running command: ip -6 rule add from fc00:1::32 table default
60+
Running command: [ -f /var/run/dhclient.eth0.pid ] && kill `cat /var/run/dhclient.eth0.pid` && rm -f /var/run/dhclient.eth0.pid
61+
Please note loaded setting will be lost after system reboot. To preserve setting, run `config save`.
62+
"""
63+
2464
def mock_run_command_side_effect(*args, **kwargs):
2565
command = args[0]
2666

@@ -238,3 +278,86 @@ def teardown_class(cls):
238278
from .mock_tables import mock_single_asic
239279
imp.reload(mock_single_asic)
240280
dbconnector.load_namespace_config()
281+
282+
class TestConfigLoadMgmtConfig(object):
283+
@classmethod
284+
def setup_class(cls):
285+
os.environ['UTILITIES_UNIT_TESTING'] = "1"
286+
print("SETUP")
287+
import config.main
288+
imp.reload(config.main)
289+
290+
def test_config_load_mgmt_config_ipv4_only(self, get_cmd_module, setup_single_broadcom_asic):
291+
device_desc_result = {
292+
'DEVICE_METADATA': {
293+
'localhost': {
294+
'hostname': 'dummy'
295+
}
296+
},
297+
'MGMT_INTERFACE': {
298+
('eth0', '10.0.0.100/24') : {
299+
'gwaddr': ipaddress.ip_address(u'10.0.0.1')
300+
}
301+
}
302+
}
303+
self.check_output(get_cmd_module, device_desc_result, load_mgmt_config_command_ipv4_only_output, 5)
304+
305+
def test_config_load_mgmt_config_ipv6_only(self, get_cmd_module, setup_single_broadcom_asic):
306+
device_desc_result = {
307+
'DEVICE_METADATA': {
308+
'localhost': {
309+
'hostname': 'dummy'
310+
}
311+
},
312+
'MGMT_INTERFACE': {
313+
('eth0', 'FC00:1::32/64') : {
314+
'gwaddr': ipaddress.ip_address(u'fc00:1::1')
315+
}
316+
}
317+
}
318+
self.check_output(get_cmd_module, device_desc_result, load_mgmt_config_command_ipv6_only_output, 5)
319+
320+
def test_config_load_mgmt_config_ipv4_ipv6(self, get_cmd_module, setup_single_broadcom_asic):
321+
device_desc_result = {
322+
'DEVICE_METADATA': {
323+
'localhost': {
324+
'hostname': 'dummy'
325+
}
326+
},
327+
'MGMT_INTERFACE': {
328+
('eth0', '10.0.0.100/24') : {
329+
'gwaddr': ipaddress.ip_address(u'10.0.0.1')
330+
},
331+
('eth0', 'FC00:1::32/64') : {
332+
'gwaddr': ipaddress.ip_address(u'fc00:1::1')
333+
}
334+
}
335+
}
336+
self.check_output(get_cmd_module, device_desc_result, load_mgmt_config_command_ipv4_ipv6_output, 8)
337+
338+
def check_output(self, get_cmd_module, parse_device_desc_xml_result, expected_output, expected_command_call_count):
339+
def parse_device_desc_xml_side_effect(filename):
340+
print("parse dummy device_desc.xml")
341+
return parse_device_desc_xml_result
342+
def change_hostname_side_effect(hostname):
343+
print("change hostname to {}".format(hostname))
344+
with mock.patch("utilities_common.cli.run_command", mock.MagicMock(side_effect=mock_run_command_side_effect)) as mock_run_command:
345+
with mock.patch('config.main.parse_device_desc_xml', mock.MagicMock(side_effect=parse_device_desc_xml_side_effect)):
346+
with mock.patch('config.main._change_hostname', mock.MagicMock(side_effect=change_hostname_side_effect)):
347+
(config, show) = get_cmd_module
348+
runner = CliRunner()
349+
with runner.isolated_filesystem():
350+
with open('device_desc.xml', 'w') as f:
351+
f.write('dummy')
352+
result = runner.invoke(config.config.commands["load_mgmt_config"], ["-y", "device_desc.xml"])
353+
print(result.exit_code)
354+
print(result.output)
355+
traceback.print_tb(result.exc_info[2])
356+
assert result.exit_code == 0
357+
assert "\n".join([l.rstrip() for l in result.output.split('\n')]) == expected_output
358+
assert mock_run_command.call_count == expected_command_call_count
359+
360+
@classmethod
361+
def teardown_class(cls):
362+
os.environ['UTILITIES_UNIT_TESTING'] = "0"
363+
print("TEARDOWN")

0 commit comments

Comments
 (0)