Skip to content

Add CLI Support for IPv6 Helpers and DHCPv6 Relay Counters #8593

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 14 commits into from
Sep 24, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions dockers/docker-dhcp-relay/cli-plugin-tests/mock_config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
TEST_DATA = [
[
"DHCPv6_Helpers",
{
"config_db": {
"DHCP_RELAY": {
"Vlan1000": {
"dhcpv6_servers": [
"fc02:2000::1",
"fc02:2000::2"
],
"dhcpv6_option|rfc6939_support": "true"
}
}
},
},
],
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import sys
import os
from unittest import mock
sys.path.append('../cli/show/plugins/')
import show_dhcp_relay as show

from click.testing import CliRunner

try:
modules_path = os.path.join(os.path.dirname(__file__), "../../../src/sonic-utilities")
test_path = os.path.join(modules_path, "tests")
mock_table_path = os.path.join(test_path, "mock_tables")
sys.path.insert(0, modules_path)
sys.path.insert(0, test_path)
sys.path.insert(0, mock_table_path)
import dbconnector
except KeyError:
pass

expected_counts = """\
Message Type Vlan1000
-------------- -----------
Solicit
Advertise
Request
Confirm
Renew
Rebind
Reply
Release
Decline
Relay-Forward
Relay-Reply

"""

class TestDhcp6RelayCounters(object):

def test_show_counts(self):
runner = CliRunner()
result = runner.invoke(show.dhcp6relay_counters.commands["counts"], ["-i Vlan1000"])
assert result.output == expected_counts

Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import pytest
import sys
import os
sys.path.append('../cli/show/plugins/')
import show_dhcp_relay as show
from click.testing import CliRunner
from swsscommon import swsscommon
from mock_config import TEST_DATA
from parameterized import parameterized
from pyfakefs.fake_filesystem_unittest import patchfs

try:
sys.path.insert(0, '../../../src/sonic-host-services/tests/common')
from mock_configdb import MockConfigDb
swsscommon.ConfigDBConnector = MockConfigDb
except KeyError:
pass

expected_table = """\
-------- ------------
Vlan1000 fc02:2000::1
fc02:2000::2
-------- ------------
"""

DBCONFIG_PATH = '/var/run/redis/sonic-db/database_config.json'

class TestDhcpRelayHelper(object):

@parameterized.expand(TEST_DATA)
@patchfs
def test_show_dhcpv6_helper(self, test_name, test_data, fs):
if not os.path.exists(DBCONFIG_PATH):
fs.create_file(DBCONFIG_PATH)
MockConfigDb.set_config_db(test_data["config_db"])
runner = CliRunner()
table = MockConfigDb.get_table(self, "DHCP_RELAY")
result = show.get_data(table, "Vlan1000")
assert result == expected_table

Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import sys
import click
sys.path.insert(0, '../../show/plugins/')
from show_dhcp6relay_counters import DHCPv6_Counter

import utilities_common.cli as clicommon


# sonic-clear dhcp6relay_counters
@click.group(cls=clicommon.AliasedGroup)
def dhcp6relay_clear():
pass

@dhcp6relay_clear.command('dhcp6relay_counters')
@click.option('-i', '--interface', required=False)
def dhcp6relay_clear_counters(interface):
""" Clear dhcp6relay message counts """

counter = DHCPv6_Counter()
counter_intf = counter.get_interface()

if interface:
counter.clear_table(interface)
else:
for intf in counter_intf:
counter.clear_table(intf)

def register(cli):
cli.add_command(dhcp6relay_clear_counters)

if __name__ == '__main__':
dhcp6relay_clear_counters()
113 changes: 112 additions & 1 deletion dockers/docker-dhcp-relay/cli/show/plugins/show_dhcp_relay.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,22 @@
import click
from natsort import natsorted
from tabulate import tabulate
import show.vlan as vlan
import utilities_common.cli as clicommon

from swsscommon.swsscommon import ConfigDBConnector
from swsscommon.swsscommon import SonicV2Connector


# STATE_DB Table
DHCPv6_COUNTER_TABLE = 'DHCPv6_COUNTER_TABLE'

# DHCPv6 Counter Messages
messages = ["Solicit", "Advertise", "Request", "Confirm", "Renew", "Rebind", "Reply", "Release", "Decline", "Relay-Forward", "Relay-Reply"]

# DHCP_RELAY Config Table
DHCP_RELAY = 'DHCP_RELAY'
config_db = ConfigDBConnector()

def get_dhcp_helper_address(ctx, vlan):
cfg, _ = ctx
Expand All @@ -16,5 +33,99 @@ def get_dhcp_helper_address(ctx, vlan):
vlan.VlanBrief.register_column('DHCP Helper Address', get_dhcp_helper_address)


def register(cli):
class DHCPv6_Counter(object):
def __init__(self):
self.db = SonicV2Connector(use_unix_socket_path=False)
self.db.connect(self.db.STATE_DB)
self.table_name = DHCPv6_COUNTER_TABLE + self.db.get_db_separator(self.db.STATE_DB)


def get_interface(self):
""" Get all names of all interfaces in DHCPv6_COUNTER_TABLE """
vlans = []
for key in self.db.keys(self.db.STATE_DB):
if DHCPv6_COUNTER_TABLE in key:
vlans.append(key[21:])
return vlans


def get_dhcp6relay_msg_count(self, interface, msg):
""" Get count of a dhcp6relay message """
count = self.db.get(self.db.STATE_DB, self.table_name + str(interface), str(msg))
data = [str(msg), count]
return data


def clear_table(self, interface):
""" Reset all message counts to 0 """
for msg in messages:
self.db.set(self.db.STATE_DB, self.table_name + str(interface), str(msg), '0')

def print_count(counter, intf):
"""Print count of each message"""
data = []
for i in messages:
data.append(counter.get_dhcp6relay_msg_count(intf, i))
print(tabulate(data, headers = ["Message Type", intf], tablefmt='simple', stralign='right') + "\n")


#
# 'dhcp6relay_counters' group ###
#


@click.group(cls=clicommon.AliasedGroup, name="dhcp6relay_counters")
def dhcp6relay_counters():
"""Show DHCPv6 counter"""
pass


# 'counts' subcommand ("show dhcp6relay_counters counts")
@dhcp6relay_counters.command('counts')
@click.option('-i', '--interface', required=False)
@click.option('--verbose', is_flag=True, help="Enable verbose output")
def counts(interface, verbose):
"""Show dhcp6relay message counts"""

counter = DHCPv6_Counter()
counter_intf = counter.get_interface()

if interface:
print_count(counter, interface)
else:
for intf in counter_intf:
print_count(counter, intf)



@click.group(cls=clicommon.AliasedGroup, name="dhcprelay_helper")
def dhcp_relay_helper():
"""Show DHCP_Relay helper information"""
pass

@dhcp_relay_helper.command('ipv6')
def get_dhcpv6_helper_address():
"""Parse through DHCP_RELAY table for each interface in config_db.json and print dhcpv6 helpers in table format"""
if config_db is not None:
config_db.connect()
table_data = config_db.get_table(DHCP_RELAY)
if table_data is not None:
vlans = config_db.get_keys(DHCP_RELAY)
for vlan in vlans:
output = get_data(table_data, vlan)
print(output)


def get_data(table_data, vlan):
vlan_data = table_data.get(vlan)
helpers_data = vlan_data.get('dhcpv6_servers')
if helpers_data is not None:
addr = {vlan:[]}
for ip in helpers_data:
addr[vlan].append(ip)
output = tabulate({'Interface':[vlan], vlan:addr.get(vlan)}, tablefmt='simple', stralign='right') + '\n'
return output

def register(cli):
cli.add_command(dhcp6relay_counters)
cli.add_command(dhcp_relay_helper)
3 changes: 2 additions & 1 deletion files/build_templates/manifest.json.j2
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
},
"cli": {
"config": "{{ config_cli_plugin|default('') }}",
"show": "{{ show_cli_plugin|default('') }}"
"show": "{{ show_cli_plugin|default('') }}",
"clear": "{{ clear_cli_plugin|default('') }}"
}
}
1 change: 1 addition & 0 deletions rules/docker-dhcp-relay.mk
Original file line number Diff line number Diff line change
Expand Up @@ -53,5 +53,6 @@ $(DOCKER_DHCP_RELAY)_CONTAINER_TMPFS += /var/tmp/

$(DOCKER_DHCP_RELAY)_CLI_CONFIG_PLUGIN = /cli/config/plugins/dhcp_relay.py
$(DOCKER_DHCP_RELAY)_CLI_SHOW_PLUGIN = /cli/show/plugins/show_dhcp_relay.py
$(DOCKER_DHCP_RELAY)_CLI_CLEAR_PLUGIN = /cli/clear/plugins/clear_dhcp6relay_counter.py

$(DOCKER_DHCP_RELAY)_FILES += $(SUPERVISOR_PROC_EXIT_LISTENER_SCRIPT)
1 change: 1 addition & 0 deletions rules/functions
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,7 @@ define generate_manifest
$(eval export tmpfs=$($(1).gz_CONTAINER_TMPFS))
$(eval export config_cli_plugin=$($(1).gz_CLI_CONFIG_PLUGIN))
$(eval export show_cli_plugin=$($(1).gz_CLI_SHOW_PLUGIN))
$(eval export clear_cli_plugin=$($(1).gz_CLI_CLEAR_PLUGIN))
j2 $($*.gz_PATH)/Dockerfile$(2).j2 > $($(1).gz_PATH)/Dockerfile$(2)
j2 --customize scripts/j2cli/json_filter.py files/build_templates/manifest.json.j2 > $($(1).gz_PATH)/manifest.common.json
if [ -f $($*.gz_PATH)/manifest.part.json.j2 ]; then
Expand Down
4 changes: 4 additions & 0 deletions sonic-slave-buster/Dockerfile.j2
Original file line number Diff line number Diff line change
Expand Up @@ -486,6 +486,10 @@ EXPOSE 22
RUN git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git /usr/share/depot_tools
ENV PATH /usr/share/depot_tools:$PATH

# Install dependencies for dhcp relay test
RUN pip3 install parameterized==0.8.1
RUN pip3 install pyfakefs

# Install docker engine 17.03.2~ce-0 inside docker and enable experimental feature
RUN apt-get update
RUN apt-get install -y \
Expand Down
4 changes: 4 additions & 0 deletions sonic-slave-stretch/Dockerfile.j2
Original file line number Diff line number Diff line change
Expand Up @@ -291,6 +291,10 @@ RUN apt-get update && apt-get install -y \
python-lxml \
libexpat1-dev

# Install dependencies for dhcp relay test
RUN pip3 install parameterized==0.8.1
RUN pip3 install pyfakefs

## Config dpkg
## install the configuration file if it’s currently missing
RUN sudo augtool --autosave "set /files/etc/dpkg/dpkg.cfg/force-confmiss"
Expand Down