Skip to content

Commit c950a55

Browse files
authored
Validate input of config mirror_session add (sonic-net#1825)
* Validate input of add mirror session Signed-off-by: bingwang <[email protected]>
1 parent 9ab20fd commit c950a55

File tree

2 files changed

+181
-13
lines changed

2 files changed

+181
-13
lines changed

config/main.py

+31-13
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,11 @@
9292

9393
asic_type = None
9494

95+
DSCP_RANGE = click.IntRange(min=0, max=63)
96+
TTL_RANGE = click.IntRange(min=0, max=255)
97+
QUEUE_RANGE = click.IntRange(min=0, max=255)
98+
GRE_TYPE_RANGE = click.IntRange(min=0, max=65535)
99+
95100
#
96101
# Helper functions
97102
#
@@ -953,6 +958,19 @@ def cache_arp_entries():
953958
open(restore_flag_file, 'w').close()
954959
return success
955960

961+
962+
def validate_ipv4_address(ctx, param, ip_addr):
963+
"""Helper function to validate ipv4 address
964+
"""
965+
try:
966+
ip_n = ipaddress.ip_network(ip_addr, False)
967+
if ip_n.version != 4:
968+
raise click.UsageError("{} is not a valid IPv4 address".format(ip_addr))
969+
return ip_addr
970+
except ValueError as e:
971+
raise click.UsageError(str(e))
972+
973+
956974
# This is our main entrypoint - the main 'config' command
957975
@click.group(cls=clicommon.AbbreviationGroup, context_settings=CONTEXT_SETTINGS)
958976
@click.pass_context
@@ -1775,12 +1793,12 @@ def mirror_session():
17751793

17761794
@mirror_session.command('add')
17771795
@click.argument('session_name', metavar='<session_name>', required=True)
1778-
@click.argument('src_ip', metavar='<src_ip>', required=True)
1779-
@click.argument('dst_ip', metavar='<dst_ip>', required=True)
1780-
@click.argument('dscp', metavar='<dscp>', required=True)
1781-
@click.argument('ttl', metavar='<ttl>', required=True)
1782-
@click.argument('gre_type', metavar='[gre_type]', required=False)
1783-
@click.argument('queue', metavar='[queue]', required=False)
1796+
@click.argument('src_ip', metavar='<src_ip>', callback=validate_ipv4_address, required=True)
1797+
@click.argument('dst_ip', metavar='<dst_ip>', callback=validate_ipv4_address, required=True)
1798+
@click.argument('dscp', metavar='<dscp>', type=DSCP_RANGE, required=True)
1799+
@click.argument('ttl', metavar='<ttl>', type=TTL_RANGE, required=True)
1800+
@click.argument('gre_type', metavar='[gre_type]', type=GRE_TYPE_RANGE, required=False)
1801+
@click.argument('queue', metavar='[queue]', type=QUEUE_RANGE, required=False)
17841802
@click.option('--policer')
17851803
def add(session_name, src_ip, dst_ip, dscp, ttl, gre_type, queue, policer):
17861804
""" Add ERSPAN mirror session.(Legacy support) """
@@ -1799,12 +1817,12 @@ def erspan(ctx):
17991817

18001818
@erspan.command('add')
18011819
@click.argument('session_name', metavar='<session_name>', required=True)
1802-
@click.argument('src_ip', metavar='<src_ip>', required=True)
1803-
@click.argument('dst_ip', metavar='<dst_ip>', required=True)
1804-
@click.argument('dscp', metavar='<dscp>', required=True)
1805-
@click.argument('ttl', metavar='<ttl>', required=True)
1806-
@click.argument('gre_type', metavar='[gre_type]', required=False)
1807-
@click.argument('queue', metavar='[queue]', required=False)
1820+
@click.argument('src_ip', metavar='<src_ip>', callback=validate_ipv4_address, required=True)
1821+
@click.argument('dst_ip', metavar='<dst_ip>', callback=validate_ipv4_address,required=True)
1822+
@click.argument('dscp', metavar='<dscp>', type=DSCP_RANGE, required=True)
1823+
@click.argument('ttl', metavar='<ttl>', type=TTL_RANGE, required=True)
1824+
@click.argument('gre_type', metavar='[gre_type]', type=GRE_TYPE_RANGE, required=False)
1825+
@click.argument('queue', metavar='[queue]', type=QUEUE_RANGE, required=False)
18081826
@click.argument('src_port', metavar='[src_port]', required=False)
18091827
@click.argument('direction', metavar='[direction]', required=False)
18101828
@click.option('--policer')
@@ -1877,7 +1895,7 @@ def span(ctx):
18771895
@click.argument('dst_port', metavar='<dst_port>', required=True)
18781896
@click.argument('src_port', metavar='[src_port]', required=False)
18791897
@click.argument('direction', metavar='[direction]', required=False)
1880-
@click.argument('queue', metavar='[queue]', required=False)
1898+
@click.argument('queue', metavar='[queue]', type=QUEUE_RANGE, required=False)
18811899
@click.option('--policer')
18821900
def add(session_name, dst_port, src_port, direction, queue, policer):
18831901
""" Add SPAN mirror session """

tests/config_mirror_session_test.py

+150
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
import pytest
2+
import config.main as config
3+
from unittest import mock
4+
from click.testing import CliRunner
5+
6+
ERR_MSG_IP_FAILURE = "does not appear to be an IPv4 or IPv6 network"
7+
ERR_MSG_IP_VERSION_FAILURE = "not a valid IPv4 address"
8+
ERR_MSG_VALUE_FAILURE = "Invalid value for"
9+
10+
def test_mirror_session_add():
11+
runner = CliRunner()
12+
13+
# Verify invalid src_ip
14+
result = runner.invoke(
15+
config.config.commands["mirror_session"].commands["add"],
16+
["test_session", "400.1.1.1", "2.2.2.2", "8", "63", "10", "100"])
17+
assert result.exit_code != 0
18+
assert ERR_MSG_IP_FAILURE in result.stdout
19+
20+
# Verify invalid dst_ip
21+
result = runner.invoke(
22+
config.config.commands["mirror_session"].commands["add"],
23+
["test_session", "1.1.1.1", "256.2.2.2", "8", "63", "10", "100"])
24+
assert result.exit_code != 0
25+
assert ERR_MSG_IP_FAILURE in result.stdout
26+
27+
# Verify invalid ip version
28+
result = runner.invoke(
29+
config.config.commands["mirror_session"].commands["add"],
30+
["test_session", "1::1", "2::2", "8", "63", "10", "100"])
31+
assert result.exit_code != 0
32+
assert ERR_MSG_IP_VERSION_FAILURE in result.stdout
33+
34+
# Verify invalid dscp
35+
result = runner.invoke(
36+
config.config.commands["mirror_session"].commands["add"],
37+
["test_session", "1.1.1.1", "2.2.2.2", "65536", "63", "10", "100"])
38+
assert result.exit_code != 0
39+
assert ERR_MSG_VALUE_FAILURE in result.stdout
40+
41+
# Verify invalid ttl
42+
result = runner.invoke(
43+
config.config.commands["mirror_session"].commands["add"],
44+
["test_session", "1.1.1.1", "2.2.2.2", "6", "256", "10", "100"])
45+
assert result.exit_code != 0
46+
assert ERR_MSG_VALUE_FAILURE in result.stdout
47+
48+
# Verify invalid gre
49+
result = runner.invoke(
50+
config.config.commands["mirror_session"].commands["add"],
51+
["test_session", "1.1.1.1", "2.2.2.2", "6", "63", "65536", "100"])
52+
assert result.exit_code != 0
53+
assert ERR_MSG_VALUE_FAILURE in result.stdout
54+
55+
# Verify invalid queue
56+
result = runner.invoke(
57+
config.config.commands["mirror_session"].commands["add"],
58+
["test_session", "1.1.1.1", "2.2.2.2", "6", "63", "65", "65536"])
59+
assert result.exit_code != 0
60+
assert ERR_MSG_VALUE_FAILURE in result.stdout
61+
62+
# Positive case
63+
with mock.patch('config.main.add_erspan') as mocked:
64+
result = runner.invoke(
65+
config.config.commands["mirror_session"].commands["add"],
66+
["test_session", "100.1.1.1", "2.2.2.2", "8", "63", "10", "100"])
67+
68+
mocked.assert_called_with("test_session", "100.1.1.1", "2.2.2.2", 8, 63, 10, 100, None)
69+
70+
71+
72+
def test_mirror_session_erspan_add():
73+
runner = CliRunner()
74+
75+
# Verify invalid src_ip
76+
result = runner.invoke(
77+
config.config.commands["mirror_session"].commands["erspan"].commands["add"],
78+
["test_session", "400.1.1.1", "2.2.2.2", "8", "63", "10", "100"])
79+
assert result.exit_code != 0
80+
assert ERR_MSG_IP_FAILURE in result.stdout
81+
82+
# Verify invalid dst_ip
83+
result = runner.invoke(
84+
config.config.commands["mirror_session"].commands["erspan"].commands["add"],
85+
["test_session", "1.1.1.1", "256.2.2.2", "8", "63", "10", "100"])
86+
assert result.exit_code != 0
87+
assert ERR_MSG_IP_FAILURE in result.stdout
88+
89+
# Verify invalid ip version
90+
result = runner.invoke(
91+
config.config.commands["mirror_session"].commands["erspan"].commands["add"],
92+
["test_session", "1::1", "2::2", "8", "63", "10", "100"])
93+
assert result.exit_code != 0
94+
assert ERR_MSG_IP_VERSION_FAILURE in result.stdout
95+
96+
# Verify invalid dscp
97+
result = runner.invoke(
98+
config.config.commands["mirror_session"].commands["erspan"].commands["add"],
99+
["test_session", "1.1.1.1", "2.2.2.2", "65536", "63", "10", "100"])
100+
assert result.exit_code != 0
101+
assert ERR_MSG_VALUE_FAILURE in result.stdout
102+
103+
# Verify invalid ttl
104+
result = runner.invoke(
105+
config.config.commands["mirror_session"].commands["erspan"].commands["add"],
106+
["test_session", "1.1.1.1", "2.2.2.2", "6", "256", "10", "100"])
107+
assert result.exit_code != 0
108+
assert ERR_MSG_VALUE_FAILURE in result.stdout
109+
110+
# Verify invalid gre
111+
result = runner.invoke(
112+
config.config.commands["mirror_session"].commands["erspan"].commands["add"],
113+
["test_session", "1.1.1.1", "2.2.2.2", "6", "63", "65536", "100"])
114+
assert result.exit_code != 0
115+
assert ERR_MSG_VALUE_FAILURE in result.stdout
116+
117+
# Verify invalid queue
118+
result = runner.invoke(
119+
config.config.commands["mirror_session"].commands["erspan"].commands["add"],
120+
["test_session", "1.1.1.1", "2.2.2.2", "6", "63", "65", "65536"])
121+
assert result.exit_code != 0
122+
assert ERR_MSG_VALUE_FAILURE in result.stdout
123+
124+
# Positive case
125+
with mock.patch('config.main.add_erspan') as mocked:
126+
result = runner.invoke(
127+
config.config.commands["mirror_session"].commands["erspan"].commands["add"],
128+
["test_session", "100.1.1.1", "2.2.2.2", "8", "63", "10", "100"])
129+
130+
mocked.assert_called_with("test_session", "100.1.1.1", "2.2.2.2", 8, 63, 10, 100, None, None, None)
131+
132+
133+
def test_mirror_session_span_add():
134+
runner = CliRunner()
135+
136+
# Verify invalid queue
137+
result = runner.invoke(
138+
config.config.commands["mirror_session"].commands["span"].commands["add"],
139+
["test_session", "Ethernet0", "Ethernet4", "rx", "65536"])
140+
assert result.exit_code != 0
141+
assert ERR_MSG_VALUE_FAILURE in result.stdout
142+
143+
# Positive case
144+
with mock.patch('config.main.add_span') as mocked:
145+
result = runner.invoke(
146+
config.config.commands["mirror_session"].commands["span"].commands["add"],
147+
["test_session", "Ethernet0", "Ethernet4", "rx", "100"])
148+
149+
mocked.assert_called_with("test_session", "Ethernet0", "Ethernet4", "rx", 100, None)
150+

0 commit comments

Comments
 (0)