[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
This commit is contained in:
parent
b5e8c16134
commit
a522a63e25
@ -13,6 +13,8 @@ ENV IMAGE_VERSION=$image_version
|
|||||||
# Update apt's cache of available packages
|
# Update apt's cache of available packages
|
||||||
RUN apt-get update
|
RUN apt-get update
|
||||||
|
|
||||||
|
RUN apt-get install -y libjsoncpp-dev
|
||||||
|
|
||||||
{% if docker_dhcp_relay_debs.strip() -%}
|
{% if docker_dhcp_relay_debs.strip() -%}
|
||||||
# Copy built Debian packages
|
# Copy built Debian packages
|
||||||
{{ copy_files("debs/", docker_dhcp_relay_debs.split(' '), "/debs/") }}
|
{{ copy_files("debs/", docker_dhcp_relay_debs.split(' '), "/debs/") }}
|
||||||
|
@ -17,24 +17,21 @@ try:
|
|||||||
except KeyError:
|
except KeyError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
expected_counts = """\
|
expected_counts_v6 = """\
|
||||||
Message Type Vlan1000
|
Message Type Vlan1000(RX)
|
||||||
------------------- -----------
|
-------------- ---------------
|
||||||
Unknown
|
|
||||||
Solicit
|
Message Type Vlan1000(TX)
|
||||||
Advertise
|
-------------- ---------------
|
||||||
Request
|
|
||||||
Confirm
|
"""
|
||||||
Renew
|
|
||||||
Rebind
|
expected_counts_v4 = """\
|
||||||
Reply
|
Message Type Vlan1000(RX)
|
||||||
Release
|
-------------- ---------------
|
||||||
Decline
|
|
||||||
Reconfigure
|
Message Type Vlan1000(TX)
|
||||||
Information-Request
|
-------------- ---------------
|
||||||
Relay-Forward
|
|
||||||
Relay-Reply
|
|
||||||
Malformed
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@ -43,5 +40,14 @@ class TestDhcp6RelayCounters(object):
|
|||||||
def test_show_counts(self):
|
def test_show_counts(self):
|
||||||
runner = CliRunner()
|
runner = CliRunner()
|
||||||
result = runner.invoke(show.dhcp6relay_counters.commands["counts"], ["-i Vlan1000"])
|
result = runner.invoke(show.dhcp6relay_counters.commands["counts"], ["-i Vlan1000"])
|
||||||
assert result.output == expected_counts
|
print(result.output)
|
||||||
|
assert result.output == expected_counts_v6
|
||||||
|
|
||||||
|
class TestDhcpRelayCounters(object):
|
||||||
|
|
||||||
|
def test_show_counts(self):
|
||||||
|
runner = CliRunner()
|
||||||
|
result = runner.invoke(show.dhcp4relay_counters.commands["counts"], ["-i Vlan1000"])
|
||||||
|
print(result.output)
|
||||||
|
assert result.output == expected_counts_v4
|
||||||
|
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import click
|
import click
|
||||||
|
import ast
|
||||||
from natsort import natsorted
|
from natsort import natsorted
|
||||||
from tabulate import tabulate
|
from tabulate import tabulate
|
||||||
import show.vlan as show_vlan
|
import show.vlan as show_vlan
|
||||||
@ -7,13 +8,20 @@ import utilities_common.cli as clicommon
|
|||||||
from swsscommon.swsscommon import ConfigDBConnector
|
from swsscommon.swsscommon import ConfigDBConnector
|
||||||
from swsscommon.swsscommon import SonicV2Connector
|
from swsscommon.swsscommon import SonicV2Connector
|
||||||
|
|
||||||
|
|
||||||
# STATE_DB Table
|
# STATE_DB Table
|
||||||
|
DHCPv4_COUNTER_TABLE = 'DHCP_COUNTER_TABLE'
|
||||||
DHCPv6_COUNTER_TABLE = 'DHCPv6_COUNTER_TABLE'
|
DHCPv6_COUNTER_TABLE = 'DHCPv6_COUNTER_TABLE'
|
||||||
|
|
||||||
|
# DHCPv4 Counter Messages
|
||||||
|
dhcpv4_messages = [
|
||||||
|
"Unknown", "Discover", "Offer", "Request", "Decline", "Ack", "Nack", "Release", "Inform"
|
||||||
|
]
|
||||||
|
|
||||||
# DHCPv6 Counter Messages
|
# DHCPv6 Counter Messages
|
||||||
messages = ["Unknown", "Solicit", "Advertise", "Request", "Confirm", "Renew", "Rebind", "Reply", "Release", "Decline",
|
dhcpv6_messages = [
|
||||||
"Reconfigure", "Information-Request", "Relay-Forward", "Relay-Reply", "Malformed"]
|
"Unknown", "Solicit", "Advertise", "Request", "Confirm", "Renew", "Rebind", "Reply", "Release",
|
||||||
|
"Decline", "Reconfigure", "Information-Request", "Relay-Forward", "Relay-Reply", "Malformed"
|
||||||
|
]
|
||||||
|
|
||||||
# DHCP_RELAY Config Table
|
# DHCP_RELAY Config Table
|
||||||
DHCP_RELAY = 'DHCP_RELAY'
|
DHCP_RELAY = 'DHCP_RELAY'
|
||||||
@ -37,6 +45,75 @@ def get_dhcp_helper_address(ctx, vlan):
|
|||||||
|
|
||||||
show_vlan.VlanBrief.register_column('DHCP Helper Address', get_dhcp_helper_address)
|
show_vlan.VlanBrief.register_column('DHCP Helper Address', get_dhcp_helper_address)
|
||||||
|
|
||||||
|
class DHCPv4_Counter(object):
|
||||||
|
def __init__(self):
|
||||||
|
self.db = SonicV2Connector(use_unix_socket_path=False)
|
||||||
|
self.db.connect(self.db.STATE_DB)
|
||||||
|
self.table_name = DHCPv4_COUNTER_TABLE + self.db.get_db_separator(self.db.STATE_DB)
|
||||||
|
|
||||||
|
def get_interface(self):
|
||||||
|
""" Get all names of all interfaces in DHCPv4_COUNTER_TABLE """
|
||||||
|
interfaces = []
|
||||||
|
for key in self.db.keys(self.db.STATE_DB):
|
||||||
|
if DHCPv4_COUNTER_TABLE in key:
|
||||||
|
interfaces.append(key[21:])
|
||||||
|
return interfaces
|
||||||
|
|
||||||
|
def get_dhcp4relay_msg_count(self, interface, dir):
|
||||||
|
""" Get count of a dhcprelay message """
|
||||||
|
value = self.db.get(self.db.STATE_DB, self.table_name + str(interface), str(dir))
|
||||||
|
cnts = ast.literal_eval(str(value))
|
||||||
|
data = []
|
||||||
|
if cnts is not None:
|
||||||
|
for k, v in cnts.items():
|
||||||
|
data.append([k, v])
|
||||||
|
return data
|
||||||
|
|
||||||
|
def clear_table(self, interface):
|
||||||
|
""" Reset all message counts to 0 """
|
||||||
|
v4_cnts = {}
|
||||||
|
for msg in dhcpv4_messages:
|
||||||
|
v4_cnts[msg] = '0'
|
||||||
|
self.db.set(self.db.STATE_DB, self.table_name + str(interface), str("RX"), str(v4_cnts))
|
||||||
|
self.db.set(self.db.STATE_DB, self.table_name + str(interface), str("TX"), str(v4_cnts))
|
||||||
|
|
||||||
|
def print_dhcpv4_count(counter, intf):
|
||||||
|
"""Print count of each message"""
|
||||||
|
rx_data = counter.get_dhcp4relay_msg_count(intf, "RX")
|
||||||
|
print(tabulate(rx_data, headers=["Message Type", intf+"(RX)"], tablefmt='simple', stralign='right') + "\n")
|
||||||
|
tx_data = counter.get_dhcp4relay_msg_count(intf, "TX")
|
||||||
|
print(tabulate(tx_data, headers=["Message Type", intf+"(TX)"], tablefmt='simple', stralign='right') + "\n")
|
||||||
|
|
||||||
|
#
|
||||||
|
# 'dhcp4relay_counters' group ###
|
||||||
|
#
|
||||||
|
|
||||||
|
|
||||||
|
@click.group(cls=clicommon.AliasedGroup, name="dhcp4relay_counters")
|
||||||
|
def dhcp4relay_counters():
|
||||||
|
"""Show DHCPv4 counter"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def ipv4_counters(interface):
|
||||||
|
counter = DHCPv4_Counter()
|
||||||
|
counter_intf = counter.get_interface()
|
||||||
|
|
||||||
|
if interface:
|
||||||
|
print_dhcpv4_count(counter, interface)
|
||||||
|
else:
|
||||||
|
for intf in counter_intf:
|
||||||
|
print_dhcpv4_count(counter, intf)
|
||||||
|
|
||||||
|
|
||||||
|
# 'counts' subcommand ("show dhcp4relay_counters counts")
|
||||||
|
@dhcp4relay_counters.command('counts')
|
||||||
|
@click.option('-i', '--interface', required=False)
|
||||||
|
@click.option('--verbose', is_flag=True, help="Enable verbose output")
|
||||||
|
def counts(interface, verbose):
|
||||||
|
"""Show dhcp4relay message counts"""
|
||||||
|
ipv4_counters(interface)
|
||||||
|
|
||||||
|
|
||||||
class DHCPv6_Counter(object):
|
class DHCPv6_Counter(object):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
@ -46,30 +123,37 @@ class DHCPv6_Counter(object):
|
|||||||
|
|
||||||
def get_interface(self):
|
def get_interface(self):
|
||||||
""" Get all names of all interfaces in DHCPv6_COUNTER_TABLE """
|
""" Get all names of all interfaces in DHCPv6_COUNTER_TABLE """
|
||||||
vlans = []
|
interfaces = []
|
||||||
for key in self.db.keys(self.db.STATE_DB):
|
for key in self.db.keys(self.db.STATE_DB):
|
||||||
if DHCPv6_COUNTER_TABLE in key:
|
if DHCPv6_COUNTER_TABLE in key:
|
||||||
vlans.append(key[21:])
|
interfaces.append(key[21:])
|
||||||
return vlans
|
return interfaces
|
||||||
|
|
||||||
def get_dhcp6relay_msg_count(self, interface, msg):
|
def get_dhcp6relay_msg_count(self, interface, dir):
|
||||||
""" Get count of a dhcp6relay message """
|
""" Get count of a dhcp6relay message """
|
||||||
count = self.db.get(self.db.STATE_DB, self.table_name + str(interface), str(msg))
|
value = self.db.get(self.db.STATE_DB, self.table_name + str(interface), str(dir))
|
||||||
data = [str(msg), count]
|
cnts = ast.literal_eval(str(value))
|
||||||
|
data = []
|
||||||
|
if cnts is not None:
|
||||||
|
for k, v in cnts.items():
|
||||||
|
data.append([k, v])
|
||||||
return data
|
return data
|
||||||
|
|
||||||
def clear_table(self, interface):
|
def clear_table(self, interface):
|
||||||
""" Reset all message counts to 0 """
|
""" Reset all message counts to 0 """
|
||||||
for msg in messages:
|
v6_cnts = {}
|
||||||
self.db.set(self.db.STATE_DB, self.table_name + str(interface), str(msg), '0')
|
for msg in dhcpv6_messages:
|
||||||
|
v6_cnts[msg] = '0'
|
||||||
|
self.db.set(self.db.STATE_DB, self.table_name + str(interface), str("RX"), str(v6_cnts))
|
||||||
|
self.db.set(self.db.STATE_DB, self.table_name + str(interface), str("TX"), str(v6_cnts))
|
||||||
|
|
||||||
|
|
||||||
def print_count(counter, intf):
|
def print_dhcpv6_count(counter, intf):
|
||||||
"""Print count of each message"""
|
"""Print count of each message"""
|
||||||
data = []
|
rx_data = counter.get_dhcp6relay_msg_count(intf, "RX")
|
||||||
for i in messages:
|
print(tabulate(rx_data, headers=["Message Type", intf+"(RX)"], tablefmt='simple', stralign='right') + "\n")
|
||||||
data.append(counter.get_dhcp6relay_msg_count(intf, i))
|
tx_data = counter.get_dhcp6relay_msg_count(intf, "TX")
|
||||||
print(tabulate(data, headers=["Message Type", intf], tablefmt='simple', stralign='right') + "\n")
|
print(tabulate(tx_data, headers=["Message Type", intf+"(TX)"], tablefmt='simple', stralign='right') + "\n")
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
@ -88,10 +172,10 @@ def ipv6_counters(interface):
|
|||||||
counter_intf = counter.get_interface()
|
counter_intf = counter.get_interface()
|
||||||
|
|
||||||
if interface:
|
if interface:
|
||||||
print_count(counter, interface)
|
print_dhcpv6_count(counter, interface)
|
||||||
else:
|
else:
|
||||||
for intf in counter_intf:
|
for intf in counter_intf:
|
||||||
print_count(counter, intf)
|
print_dhcpv6_count(counter, intf)
|
||||||
|
|
||||||
|
|
||||||
# 'counts' subcommand ("show dhcp6relay_counters counts")
|
# 'counts' subcommand ("show dhcp6relay_counters counts")
|
||||||
@ -100,7 +184,6 @@ def ipv6_counters(interface):
|
|||||||
@click.option('--verbose', is_flag=True, help="Enable verbose output")
|
@click.option('--verbose', is_flag=True, help="Enable verbose output")
|
||||||
def counts(interface, verbose):
|
def counts(interface, verbose):
|
||||||
"""Show dhcp6relay message counts"""
|
"""Show dhcp6relay message counts"""
|
||||||
|
|
||||||
ipv6_counters(interface)
|
ipv6_counters(interface)
|
||||||
|
|
||||||
|
|
||||||
@ -199,6 +282,7 @@ def dhcp_relay_ip6counters(interface):
|
|||||||
|
|
||||||
|
|
||||||
def register(cli):
|
def register(cli):
|
||||||
|
cli.add_command(dhcp4relay_counters)
|
||||||
cli.add_command(dhcp6relay_counters)
|
cli.add_command(dhcp6relay_counters)
|
||||||
cli.add_command(dhcp_relay_helper)
|
cli.add_command(dhcp_relay_helper)
|
||||||
cli.add_command(dhcp_relay)
|
cli.add_command(dhcp_relay)
|
||||||
|
@ -348,6 +348,7 @@ RUN apt-get update && apt-get install -y \
|
|||||||
# For DHCP Monitor tool
|
# For DHCP Monitor tool
|
||||||
libexplain-dev \
|
libexplain-dev \
|
||||||
libevent-dev \
|
libevent-dev \
|
||||||
|
libjsoncpp-dev \
|
||||||
# For libyang
|
# For libyang
|
||||||
swig \
|
swig \
|
||||||
# For build dtb
|
# For build dtb
|
||||||
|
Loading…
Reference in New Issue
Block a user