Skip to content

Commit d1ba80c

Browse files
jcaiMRmssonicbld
authored andcommitted
[dhcp-relay]: dhcp/dhcpv6 per interface counter support (#16377)
Why I did it Support DHCP/DHCPv6 per-interface counter, code change in sonic-build image. Work item tracking Microsoft ADO (17271822): How I did it - Introduce libjsoncpp-dev in dhcpmon and dhcprelay repo - Show CLI changes after counter format change How to verify it - Manually run show command - dhcpmon, dhcprelay integration tests
1 parent 1239ef1 commit d1ba80c

File tree

4 files changed

+131
-38
lines changed

4 files changed

+131
-38
lines changed

dockers/docker-dhcp-relay/Dockerfile.j2

+2
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ ENV IMAGE_VERSION=$image_version
1414
# Update apt's cache of available packages
1515
RUN apt-get update
1616

17+
RUN apt-get install -y libjsoncpp-dev
18+
1719
{% if docker_dhcp_relay_debs.strip() -%}
1820
# Copy built Debian packages
1921
{{ copy_files("debs/", docker_dhcp_relay_debs.split(' '), "/debs/") }}

dockers/docker-dhcp-relay/cli-plugin-tests/test_show_dhcp6relay_counters.py

+25-19
Original file line numberDiff line numberDiff line change
@@ -17,24 +17,21 @@
1717
except KeyError:
1818
pass
1919

20-
expected_counts = """\
21-
Message Type Vlan1000
22-
------------------- -----------
23-
Unknown
24-
Solicit
25-
Advertise
26-
Request
27-
Confirm
28-
Renew
29-
Rebind
30-
Reply
31-
Release
32-
Decline
33-
Reconfigure
34-
Information-Request
35-
Relay-Forward
36-
Relay-Reply
37-
Malformed
20+
expected_counts_v6 = """\
21+
Message Type Vlan1000(RX)
22+
-------------- ---------------
23+
24+
Message Type Vlan1000(TX)
25+
-------------- ---------------
26+
27+
"""
28+
29+
expected_counts_v4 = """\
30+
Message Type Vlan1000(RX)
31+
-------------- ---------------
32+
33+
Message Type Vlan1000(TX)
34+
-------------- ---------------
3835
3936
"""
4037

@@ -43,5 +40,14 @@ class TestDhcp6RelayCounters(object):
4340
def test_show_counts(self):
4441
runner = CliRunner()
4542
result = runner.invoke(show.dhcp6relay_counters.commands["counts"], ["-i Vlan1000"])
46-
assert result.output == expected_counts
43+
print(result.output)
44+
assert result.output == expected_counts_v6
45+
46+
class TestDhcpRelayCounters(object):
47+
48+
def test_show_counts(self):
49+
runner = CliRunner()
50+
result = runner.invoke(show.dhcp4relay_counters.commands["counts"], ["-i Vlan1000"])
51+
print(result.output)
52+
assert result.output == expected_counts_v4
4753

dockers/docker-dhcp-relay/cli/show/plugins/show_dhcp_relay.py

+103-19
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import click
2+
import ast
23
from natsort import natsorted
34
from tabulate import tabulate
45
import show.vlan as show_vlan
@@ -7,13 +8,20 @@
78
from swsscommon.swsscommon import ConfigDBConnector
89
from swsscommon.swsscommon import SonicV2Connector
910

10-
1111
# STATE_DB Table
12+
DHCPv4_COUNTER_TABLE = 'DHCP_COUNTER_TABLE'
1213
DHCPv6_COUNTER_TABLE = 'DHCPv6_COUNTER_TABLE'
1314

15+
# DHCPv4 Counter Messages
16+
dhcpv4_messages = [
17+
"Unknown", "Discover", "Offer", "Request", "Decline", "Ack", "Nack", "Release", "Inform"
18+
]
19+
1420
# DHCPv6 Counter Messages
15-
messages = ["Unknown", "Solicit", "Advertise", "Request", "Confirm", "Renew", "Rebind", "Reply", "Release", "Decline",
16-
"Reconfigure", "Information-Request", "Relay-Forward", "Relay-Reply", "Malformed"]
21+
dhcpv6_messages = [
22+
"Unknown", "Solicit", "Advertise", "Request", "Confirm", "Renew", "Rebind", "Reply", "Release",
23+
"Decline", "Reconfigure", "Information-Request", "Relay-Forward", "Relay-Reply", "Malformed"
24+
]
1725

1826
# DHCP_RELAY Config Table
1927
DHCP_RELAY = 'DHCP_RELAY'
@@ -37,6 +45,75 @@ def get_dhcp_helper_address(ctx, vlan):
3745

3846
show_vlan.VlanBrief.register_column('DHCP Helper Address', get_dhcp_helper_address)
3947

48+
class DHCPv4_Counter(object):
49+
def __init__(self):
50+
self.db = SonicV2Connector(use_unix_socket_path=False)
51+
self.db.connect(self.db.STATE_DB)
52+
self.table_name = DHCPv4_COUNTER_TABLE + self.db.get_db_separator(self.db.STATE_DB)
53+
54+
def get_interface(self):
55+
""" Get all names of all interfaces in DHCPv4_COUNTER_TABLE """
56+
interfaces = []
57+
for key in self.db.keys(self.db.STATE_DB):
58+
if DHCPv4_COUNTER_TABLE in key:
59+
interfaces.append(key[21:])
60+
return interfaces
61+
62+
def get_dhcp4relay_msg_count(self, interface, dir):
63+
""" Get count of a dhcprelay message """
64+
value = self.db.get(self.db.STATE_DB, self.table_name + str(interface), str(dir))
65+
cnts = ast.literal_eval(str(value))
66+
data = []
67+
if cnts is not None:
68+
for k, v in cnts.items():
69+
data.append([k, v])
70+
return data
71+
72+
def clear_table(self, interface):
73+
""" Reset all message counts to 0 """
74+
v4_cnts = {}
75+
for msg in dhcpv4_messages:
76+
v4_cnts[msg] = '0'
77+
self.db.set(self.db.STATE_DB, self.table_name + str(interface), str("RX"), str(v4_cnts))
78+
self.db.set(self.db.STATE_DB, self.table_name + str(interface), str("TX"), str(v4_cnts))
79+
80+
def print_dhcpv4_count(counter, intf):
81+
"""Print count of each message"""
82+
rx_data = counter.get_dhcp4relay_msg_count(intf, "RX")
83+
print(tabulate(rx_data, headers=["Message Type", intf+"(RX)"], tablefmt='simple', stralign='right') + "\n")
84+
tx_data = counter.get_dhcp4relay_msg_count(intf, "TX")
85+
print(tabulate(tx_data, headers=["Message Type", intf+"(TX)"], tablefmt='simple', stralign='right') + "\n")
86+
87+
#
88+
# 'dhcp4relay_counters' group ###
89+
#
90+
91+
92+
@click.group(cls=clicommon.AliasedGroup, name="dhcp4relay_counters")
93+
def dhcp4relay_counters():
94+
"""Show DHCPv4 counter"""
95+
pass
96+
97+
98+
def ipv4_counters(interface):
99+
counter = DHCPv4_Counter()
100+
counter_intf = counter.get_interface()
101+
102+
if interface:
103+
print_dhcpv4_count(counter, interface)
104+
else:
105+
for intf in counter_intf:
106+
print_dhcpv4_count(counter, intf)
107+
108+
109+
# 'counts' subcommand ("show dhcp4relay_counters counts")
110+
@dhcp4relay_counters.command('counts')
111+
@click.option('-i', '--interface', required=False)
112+
@click.option('--verbose', is_flag=True, help="Enable verbose output")
113+
def counts(interface, verbose):
114+
"""Show dhcp4relay message counts"""
115+
ipv4_counters(interface)
116+
40117

41118
class DHCPv6_Counter(object):
42119
def __init__(self):
@@ -46,30 +123,37 @@ def __init__(self):
46123

47124
def get_interface(self):
48125
""" Get all names of all interfaces in DHCPv6_COUNTER_TABLE """
49-
vlans = []
126+
interfaces = []
50127
for key in self.db.keys(self.db.STATE_DB):
51128
if DHCPv6_COUNTER_TABLE in key:
52-
vlans.append(key[21:])
53-
return vlans
129+
interfaces.append(key[21:])
130+
return interfaces
54131

55-
def get_dhcp6relay_msg_count(self, interface, msg):
132+
def get_dhcp6relay_msg_count(self, interface, dir):
56133
""" Get count of a dhcp6relay message """
57-
count = self.db.get(self.db.STATE_DB, self.table_name + str(interface), str(msg))
58-
data = [str(msg), count]
134+
value = self.db.get(self.db.STATE_DB, self.table_name + str(interface), str(dir))
135+
cnts = ast.literal_eval(str(value))
136+
data = []
137+
if cnts is not None:
138+
for k, v in cnts.items():
139+
data.append([k, v])
59140
return data
60141

61142
def clear_table(self, interface):
62143
""" Reset all message counts to 0 """
63-
for msg in messages:
64-
self.db.set(self.db.STATE_DB, self.table_name + str(interface), str(msg), '0')
144+
v6_cnts = {}
145+
for msg in dhcpv6_messages:
146+
v6_cnts[msg] = '0'
147+
self.db.set(self.db.STATE_DB, self.table_name + str(interface), str("RX"), str(v6_cnts))
148+
self.db.set(self.db.STATE_DB, self.table_name + str(interface), str("TX"), str(v6_cnts))
65149

66150

67-
def print_count(counter, intf):
151+
def print_dhcpv6_count(counter, intf):
68152
"""Print count of each message"""
69-
data = []
70-
for i in messages:
71-
data.append(counter.get_dhcp6relay_msg_count(intf, i))
72-
print(tabulate(data, headers=["Message Type", intf], tablefmt='simple', stralign='right') + "\n")
153+
rx_data = counter.get_dhcp6relay_msg_count(intf, "RX")
154+
print(tabulate(rx_data, headers=["Message Type", intf+"(RX)"], tablefmt='simple', stralign='right') + "\n")
155+
tx_data = counter.get_dhcp6relay_msg_count(intf, "TX")
156+
print(tabulate(tx_data, headers=["Message Type", intf+"(TX)"], tablefmt='simple', stralign='right') + "\n")
73157

74158

75159
#
@@ -88,10 +172,10 @@ def ipv6_counters(interface):
88172
counter_intf = counter.get_interface()
89173

90174
if interface:
91-
print_count(counter, interface)
175+
print_dhcpv6_count(counter, interface)
92176
else:
93177
for intf in counter_intf:
94-
print_count(counter, intf)
178+
print_dhcpv6_count(counter, intf)
95179

96180

97181
# 'counts' subcommand ("show dhcp6relay_counters counts")
@@ -100,7 +184,6 @@ def ipv6_counters(interface):
100184
@click.option('--verbose', is_flag=True, help="Enable verbose output")
101185
def counts(interface, verbose):
102186
"""Show dhcp6relay message counts"""
103-
104187
ipv6_counters(interface)
105188

106189

@@ -199,6 +282,7 @@ def dhcp_relay_ip6counters(interface):
199282

200283

201284
def register(cli):
285+
cli.add_command(dhcp4relay_counters)
202286
cli.add_command(dhcp6relay_counters)
203287
cli.add_command(dhcp_relay_helper)
204288
cli.add_command(dhcp_relay)

sonic-slave-bullseye/Dockerfile.j2

+1
Original file line numberDiff line numberDiff line change
@@ -279,6 +279,7 @@ RUN apt-get update && apt-get install -y \
279279
# For DHCP Monitor tool
280280
libexplain-dev \
281281
libevent-dev \
282+
libjsoncpp-dev \
282283
# For libyang
283284
swig \
284285
# For build dtb

0 commit comments

Comments
 (0)