From 482f0d3c0b8ed68ce54745645bf5f90c7035b54b Mon Sep 17 00:00:00 2001
From: kellyyeh <42761586+kellyyeh@users.noreply.github.com>
Date: Wed, 29 Sep 2021 18:20:39 -0700
Subject: [PATCH 1/7] Add DHCPv6 minigraph parsing support (#8870)
---
src/sonic-config-engine/minigraph.py | 13 +++++++++++--
src/sonic-config-engine/tests/t0-sample-graph.xml | 1 +
2 files changed, 12 insertions(+), 2 deletions(-)
diff --git a/src/sonic-config-engine/minigraph.py b/src/sonic-config-engine/minigraph.py
index 67356d0b1c5a..983da9de7d0e 100644
--- a/src/sonic-config-engine/minigraph.py
+++ b/src/sonic-config-engine/minigraph.py
@@ -385,6 +385,12 @@ def parse_dpg(dpg, hname):
vdhcpserver_list = vintfdhcpservers.split(';')
vlan_attributes['dhcp_servers'] = vdhcpserver_list
+ vintf_node = vintf.find(str(QName(ns, "Dhcpv6Relays")))
+ if vintf_node is not None and vintf_node.text is not None:
+ vintfdhcpservers = vintf_node.text
+ vdhcpserver_list = vintfdhcpservers.split(';')
+ vlan_attributes['dhcpv6_servers'] = vdhcpserver_list
+
sonic_vlan_name = "Vlan%s" % vlanid
if sonic_vlan_name != vintfname:
vlan_attributes['alias'] = vintfname
@@ -606,6 +612,7 @@ def parse_cpg(cpg, hname, local_devices=[]):
def parse_meta(meta, hname):
syslog_servers = []
dhcp_servers = []
+ dhcpv6_servers = []
ntp_servers = []
tacacs_servers = []
mgmt_routes = []
@@ -648,7 +655,7 @@ def parse_meta(meta, hname):
qos_profile = value
elif name == "ResourceType":
resource_type = value
- return syslog_servers, dhcp_servers, ntp_servers, tacacs_servers, mgmt_routes, erspan_dst, deployment_id, region, cloudtype, downstream_subrole, qos_profile, resource_type
+ return syslog_servers, dhcp_servers, dhcpv6_servers, ntp_servers, tacacs_servers, mgmt_routes, erspan_dst, deployment_id, region, cloudtype, downstream_subrole, qos_profile, resource_type
def parse_linkmeta(meta, hname):
@@ -935,6 +942,7 @@ def parse_xml(filename, platform=None, port_config_file=None, asic_name=None):
console_ports = {}
syslog_servers = []
dhcp_servers = []
+ dhcpv6_servers = []
ntp_servers = []
tacacs_servers = []
mgmt_routes = []
@@ -985,7 +993,7 @@ def parse_xml(filename, platform=None, port_config_file=None, asic_name=None):
elif child.tag == str(QName(ns, "UngDec")):
(u_neighbors, u_devices, _, _, _, _, _, _) = parse_png(child, hostname)
elif child.tag == str(QName(ns, "MetadataDeclaration")):
- (syslog_servers, dhcp_servers, ntp_servers, tacacs_servers, mgmt_routes, erspan_dst, deployment_id, region, cloudtype, downstream_subrole, qos_profile, resource_type) = parse_meta(child, hostname)
+ (syslog_servers, dhcp_servers, dhcppv6_servers, ntp_servers, tacacs_servers, mgmt_routes, erspan_dst, deployment_id, region, cloudtype, downstream_subrole, qos_profile, resource_type) = parse_meta(child, hostname)
elif child.tag == str(QName(ns, "LinkMetadataDeclaration")):
linkmetas = parse_linkmeta(child, hostname)
elif child.tag == str(QName(ns, "DeviceInfos")):
@@ -1245,6 +1253,7 @@ def parse_xml(filename, platform=None, port_config_file=None, asic_name=None):
results['DEVICE_NEIGHBOR_METADATA'] = { key:devices[key] for key in devices if key in {device['name'] for device in neighbors.values()} }
results['SYSLOG_SERVER'] = dict((item, {}) for item in syslog_servers)
results['DHCP_SERVER'] = dict((item, {}) for item in dhcp_servers)
+ results['DHCPv6_SERVER'] = dict((item, {}) for item in dhcpv6_servers)
results['NTP_SERVER'] = dict((item, {}) for item in ntp_servers)
results['TACPLUS_SERVER'] = dict((item, {'priority': '1', 'tcp_port': '49'}) for item in tacacs_servers)
results['ACL_TABLE'] = filter_acl_table_bindings(acls, neighbors, pcs, sub_role)
diff --git a/src/sonic-config-engine/tests/t0-sample-graph.xml b/src/sonic-config-engine/tests/t0-sample-graph.xml
index f847af1f90cf..4c584cd4c7c2 100644
--- a/src/sonic-config-engine/tests/t0-sample-graph.xml
+++ b/src/sonic-config-engine/tests/t0-sample-graph.xml
@@ -240,6 +240,7 @@
192.0.0.1;192.0.0.2
+ fc02:2000::1;fc02:2000::2
1000
1000
192.168.0.0/27
From 35b5578d58212d49511f2c95b15b842351e28af5 Mon Sep 17 00:00:00 2001
From: kellyyeh
Date: Tue, 6 Sep 2022 23:39:56 +0000
Subject: [PATCH 2/7] Parse DHCP Table (#8988)
---
src/sonic-config-engine/minigraph.py | 30 +++++++++++++++++--
.../tests/simple-sample-graph-case.xml | 12 ++++++++
src/sonic-config-engine/tests/test_cfggen.py | 8 +++++
.../tests/test_minigraph_case.py | 24 +++++++++++++++
4 files changed, 71 insertions(+), 3 deletions(-)
diff --git a/src/sonic-config-engine/minigraph.py b/src/sonic-config-engine/minigraph.py
index 983da9de7d0e..836149bcbfd0 100644
--- a/src/sonic-config-engine/minigraph.py
+++ b/src/sonic-config-engine/minigraph.py
@@ -396,6 +396,29 @@ def parse_dpg(dpg, hname):
vlan_attributes['alias'] = vintfname
vlans[sonic_vlan_name] = vlan_attributes
+ dhcp = child.find(str(QName(ns, "Dhcp")))
+ dhcp_table = {}
+
+ if dhcp is not None:
+ for vintf in dhcp.findall(str(QName(ns, "VlanInterface"))):
+ vintfname = vintf.find(str(QName(ns, "Name"))).text
+
+ dhcp_attributes = {}
+
+ dhcp_node = vintf.find(str(QName(ns, "Dhcpv6Relays")))
+ if dhcp_node is not None and dhcp_node.text is not None:
+ dhcpservers = dhcp_node.text
+ vdhcpserver_list = dhcpservers.split(';')
+ dhcp_attributes['dhcpv6_servers'] = vdhcpserver_list
+
+ option_linklayer_addr = vintf.find(str(QName(ns, "Dhcpv6OptionRfc6939")))
+ if option_linklayer_addr is not None and option_linklayer_addr.text == "true":
+ dhcp_attributes['dhcpv6_option|rfc6939_support'] = "true"
+ elif option_linklayer_addr is not None and option_linklayer_addr.text == "false":
+ dhcp_attributes['dhcpv6_option|rfc6939_support'] = "false"
+
+ dhcp_table[vintfname] = dhcp_attributes
+
acls = {}
for aclintf in aclintfs.findall(str(QName(ns, "AclInterface"))):
if aclintf.find(str(QName(ns, "InAcl"))) is not None:
@@ -496,7 +519,7 @@ def parse_dpg(dpg, hname):
except:
print >> sys.stderr, "Warning: Ignoring Control Plane ACL %s without type" % aclname
- return intfs, lo_intfs, mvrf, mgmt_intf, vlans, vlan_members, pcs, pc_members, acls, vni
+ return intfs, lo_intfs, mvrf, mgmt_intf, vlans, vlan_members, dhcp_table, pcs, pc_members, acls, vni
return None, None, None, None, None, None, None, None, None, None
def parse_host_loopback(dpg, hname):
@@ -985,7 +1008,7 @@ def parse_xml(filename, platform=None, port_config_file=None, asic_name=None):
for child in root:
if asic_name is None:
if child.tag == str(QName(ns, "DpgDec")):
- (intfs, lo_intfs, mvrf, mgmt_intf, vlans, vlan_members, pcs, pc_members, acls, vni) = parse_dpg(child, hostname)
+ (intfs, lo_intfs, mvrf, mgmt_intf, vlans, vlan_members, dhcp_table, pcs, pc_members, acls, vni) = parse_dpg(child, hostname)
elif child.tag == str(QName(ns, "CpgDec")):
(bgp_sessions, bgp_internal_sessions, bgp_asn, bgp_peers_with_range, bgp_monitors) = parse_cpg(child, hostname)
elif child.tag == str(QName(ns, "PngDec")):
@@ -1000,7 +1023,7 @@ def parse_xml(filename, platform=None, port_config_file=None, asic_name=None):
(port_speeds_default, port_descriptions) = parse_deviceinfo(child, hwsku)
else:
if child.tag == str(QName(ns, "DpgDec")):
- (intfs, lo_intfs, mvrf, mgmt_intf, vlans, vlan_members, pcs, pc_members, acls, vni) = parse_dpg(child, asic_name)
+ (intfs, lo_intfs, mvrf, mgmt_intf, vlans, vlan_members, dhcp_table, pcs, pc_members, acls, vni) = parse_dpg(child, asic_name)
host_lo_intfs = parse_host_loopback(child, hostname)
elif child.tag == str(QName(ns, "CpgDec")):
(bgp_sessions, bgp_internal_sessions, bgp_asn, bgp_peers_with_range, bgp_monitors) = parse_cpg(child, asic_name, local_devices)
@@ -1254,6 +1277,7 @@ def parse_xml(filename, platform=None, port_config_file=None, asic_name=None):
results['SYSLOG_SERVER'] = dict((item, {}) for item in syslog_servers)
results['DHCP_SERVER'] = dict((item, {}) for item in dhcp_servers)
results['DHCPv6_SERVER'] = dict((item, {}) for item in dhcpv6_servers)
+ results['DHCP'] = dhcp_table
results['NTP_SERVER'] = dict((item, {}) for item in ntp_servers)
results['TACPLUS_SERVER'] = dict((item, {'priority': '1', 'tcp_port': '49'}) for item in tacacs_servers)
results['ACL_TABLE'] = filter_acl_table_bindings(acls, neighbors, pcs, sub_role)
diff --git a/src/sonic-config-engine/tests/simple-sample-graph-case.xml b/src/sonic-config-engine/tests/simple-sample-graph-case.xml
index add1964c5243..48460e2c6da8 100644
--- a/src/sonic-config-engine/tests/simple-sample-graph-case.xml
+++ b/src/sonic-config-engine/tests/simple-sample-graph-case.xml
@@ -136,6 +136,18 @@
192.168.0.0/27
+
+
+ Vlan1000
+ fc02:2000::1;fc02:2000::2
+ true
+
+
+ Vlan2000
+ fc02:2000::3;fc02:2000::4
+ false
+
+
diff --git a/src/sonic-config-engine/tests/test_cfggen.py b/src/sonic-config-engine/tests/test_cfggen.py
index da8c88fd7042..4782c7fc2814 100644
--- a/src/sonic-config-engine/tests/test_cfggen.py
+++ b/src/sonic-config-engine/tests/test_cfggen.py
@@ -617,3 +617,11 @@ def test_show_run_interfaces(self):
argument = '-a \'{"key1":"value"}\' --var-json INTERFACE'
output = self.run_script(argument)
self.assertEqual(output, '')
+
+ def test_minigraph_dhcp(self):
+ argument = '-m "' + self.sample_graph_simple_case + '" -p "' + self.port_config + '" -v DHCP'
+ output = self.run_script(argument)
+ self.assertEqual(
+ output.strip(),
+ "{'Vlan1000': {'dhcpv6_option|rfc6939_support': 'true', 'dhcpv6_servers': ['fc02:2000::1', 'fc02:2000::2']}, 'Vlan2000': {'dhcpv6_option|rfc6939_support': 'false', 'dhcpv6_servers': ['fc02:2000::3', 'fc02:2000::4']}}"
+ )
\ No newline at end of file
diff --git a/src/sonic-config-engine/tests/test_minigraph_case.py b/src/sonic-config-engine/tests/test_minigraph_case.py
index 3d0552fc235c..85114396fce7 100644
--- a/src/sonic-config-engine/tests/test_minigraph_case.py
+++ b/src/sonic-config-engine/tests/test_minigraph_case.py
@@ -190,3 +190,27 @@ def test_parse_device_desc_xml_mgmt_interface(self):
self.assertEqual(len(mgmt_intf.keys()), 1)
self.assertTrue(('eth0', 'FC00:1::32/64') in mgmt_intf.keys())
self.assertTrue(ipaddress.IPAddress('fc00:1::1') == mgmt_intf[('eth0', 'FC00:1::32/64')]['gwaddr'])
+
+ def test_dhcp_table(self):
+ argument = '-m "' + self.sample_graph + '" -p "' + self.port_config + '" -v "DHCP"'
+ expected = {
+ 'Vlan1000': {
+ 'dhcpv6_servers': [
+ "fc02:2000::1",
+ "fc02:2000::2"
+ ],
+ 'dhcpv6_option|rfc6939_support': 'true'
+ },
+ 'Vlan2000': {
+ 'dhcpv6_servers': [
+ "fc02:2000::3",
+ "fc02:2000::4"
+ ],
+ 'dhcpv6_option|rfc6939_support': 'false'
+ }
+ }
+ output = self.run_script(argument)
+ self.assertEqual(
+ output.strip(),
+ "{'Vlan1000': {'dhcpv6_option|rfc6939_support': 'true', 'dhcpv6_servers': ['fc02:2000::1', 'fc02:2000::2']}, 'Vlan2000': {'dhcpv6_option|rfc6939_support': 'false', 'dhcpv6_servers': ['fc02:2000::3', 'fc02:2000::4']}}"
+ )
\ No newline at end of file
From 01a8af14aa94d2f61aef80cb6fefbe1f3307c9ed Mon Sep 17 00:00:00 2001
From: kellyyeh
Date: Tue, 13 Sep 2022 00:35:12 +0000
Subject: [PATCH 3/7] Replace isc-dhcp with DHCPv6 Relay in dhcp_relay docker
(#8884)
---
dockers/docker-dhcp-relay/Dockerfile.j2 | 1 +
dockers/docker-dhcp-relay/critical_processes | 2 +-
.../docker-dhcp-relay/dhcp-relay.monitors.j2 | 76 ++
.../docker-dhcp-relay/dhcp-relay.programs.j2 | 22 +
.../docker-dhcp-relay/dhcpv4-relay.agents.j2 | 41 +
.../docker-dhcp-relay/dhcpv6-relay.agents.j2 | 23 +
.../docker-dhcp-relay.supervisord.conf.j2 | 119 +--
dockers/docker-dhcp-relay/start.sh | 2 +-
dockers/docker-dhcp-relay/wait_for_intf.sh.j2 | 5 +
rules/dhcp6relay.mk | 12 +
rules/docker-dhcp-relay.mk | 4 +-
sonic-dhcp-relay | 1 +
src/dhcp6relay/.gitignore | 5 +
src/dhcp6relay/Makefile | 42 +
src/dhcp6relay/debian/changelog | 5 +
src/dhcp6relay/debian/compat | 1 +
src/dhcp6relay/debian/control | 27 +
src/dhcp6relay/debian/rules | 12 +
src/dhcp6relay/src/configInterface.cpp | 151 ++++
src/dhcp6relay/src/configInterface.d | 44 +
src/dhcp6relay/src/configInterface.h | 75 ++
src/dhcp6relay/src/main.cpp | 17 +
src/dhcp6relay/src/main.d | 44 +
src/dhcp6relay/src/relay.cpp | 816 ++++++++++++++++++
src/dhcp6relay/src/relay.d | 51 ++
src/dhcp6relay/src/relay.h | 349 ++++++++
src/dhcp6relay/src/subdir.mk | 23 +
src/sonic-config-engine/minigraph.py | 18 +-
.../docker-dhcp-relay.supervisord.conf | 19 +-
.../tests/sample_output/wait_for_intf.sh | 4 +
.../tests/simple-sample-graph-case.xml | 18 +-
src/sonic-config-engine/tests/test_cfggen.py | 4 +-
.../tests/test_minigraph_case.py | 60 +-
src/sonic-dhcp-relay | 1 +
34 files changed, 1941 insertions(+), 153 deletions(-)
create mode 100644 dockers/docker-dhcp-relay/dhcp-relay.monitors.j2
create mode 100644 dockers/docker-dhcp-relay/dhcp-relay.programs.j2
create mode 100644 dockers/docker-dhcp-relay/dhcpv4-relay.agents.j2
create mode 100644 dockers/docker-dhcp-relay/dhcpv6-relay.agents.j2
create mode 100644 rules/dhcp6relay.mk
create mode 160000 sonic-dhcp-relay
create mode 100644 src/dhcp6relay/.gitignore
create mode 100644 src/dhcp6relay/Makefile
create mode 100644 src/dhcp6relay/debian/changelog
create mode 100644 src/dhcp6relay/debian/compat
create mode 100644 src/dhcp6relay/debian/control
create mode 100755 src/dhcp6relay/debian/rules
create mode 100644 src/dhcp6relay/src/configInterface.cpp
create mode 100644 src/dhcp6relay/src/configInterface.d
create mode 100644 src/dhcp6relay/src/configInterface.h
create mode 100644 src/dhcp6relay/src/main.cpp
create mode 100644 src/dhcp6relay/src/main.d
create mode 100644 src/dhcp6relay/src/relay.cpp
create mode 100644 src/dhcp6relay/src/relay.d
create mode 100644 src/dhcp6relay/src/relay.h
create mode 100644 src/dhcp6relay/src/subdir.mk
create mode 160000 src/sonic-dhcp-relay
diff --git a/dockers/docker-dhcp-relay/Dockerfile.j2 b/dockers/docker-dhcp-relay/Dockerfile.j2
index e909c6a70040..22662fbb7f73 100644
--- a/dockers/docker-dhcp-relay/Dockerfile.j2
+++ b/dockers/docker-dhcp-relay/Dockerfile.j2
@@ -26,6 +26,7 @@ RUN apt-get clean -y && \
COPY ["docker_init.sh", "start.sh", "/usr/bin/"]
COPY ["docker-dhcp-relay.supervisord.conf.j2", "port-name-alias-map.txt.j2", "wait_for_intf.sh.j2", "/usr/share/sonic/templates/"]
+COPY ["dhcp-relay.programs.j2", "dhcpv4-relay.agents.j2", "dhcpv6-relay.agents.j2", "dhcp-relay.monitors.j2", "/usr/share/sonic/templates/"]
COPY ["files/supervisor-proc-exit-listener", "/usr/bin"]
COPY ["critical_processes", "/etc/supervisor"]
diff --git a/dockers/docker-dhcp-relay/critical_processes b/dockers/docker-dhcp-relay/critical_processes
index 855851bf2d68..43bf6af2794f 100644
--- a/dockers/docker-dhcp-relay/critical_processes
+++ b/dockers/docker-dhcp-relay/critical_processes
@@ -1 +1 @@
-group:isc-dhcp-relay
+group:dhcp-relay
diff --git a/dockers/docker-dhcp-relay/dhcp-relay.monitors.j2 b/dockers/docker-dhcp-relay/dhcp-relay.monitors.j2
new file mode 100644
index 000000000000..0928bac22d4d
--- /dev/null
+++ b/dockers/docker-dhcp-relay/dhcp-relay.monitors.j2
@@ -0,0 +1,76 @@
+[group:dhcpmon]
+programs=
+{%- set add_preceding_comma = { 'flag': False } %}
+{% set monitor_instance = { 'flag': False } %}
+{% for vlan_name in VLAN_INTERFACE %}
+{% if VLAN and vlan_name in VLAN and 'dhcp_servers' in VLAN[vlan_name] and VLAN[vlan_name]['dhcp_servers']|length > 0 %}
+{% set _dummy = monitor_instance.update({'flag': True}) %}
+{%- endif %}
+{% if DHCP_RELAY and vlan_name in DHCP_RELAY and DHCP_RELAY[vlan_name]['dhcpv6_servers']|length > 0 %}
+{% set _dummy = monitor_instance.update({'flag': True}) %}
+{%- endif %}
+{% if monitor_instance.flag %}
+{% if add_preceding_comma.flag %},{% endif %}
+{% set _dummy = add_preceding_comma.update({'flag': True}) %}
+dhcpmon-{{ vlan_name }}
+{%- set _dummy = monitor_instance.update({'flag': False}) %}
+{%- endif %}
+{% endfor %}
+
+
+{# Create a program entry for each DHCP MONitor instance #}
+{% set relay_for_ipv4 = { 'flag': False } %}
+{% set relay_for_ipv6 = { 'flag': False } %}
+{% for vlan_name in VLAN_INTERFACE %}
+{# Check DHCPv4 agents #}
+{% if VLAN and vlan_name in VLAN and 'dhcp_servers' in VLAN[vlan_name] and VLAN[vlan_name]['dhcp_servers']|length > 0 %}
+{% for dhcp_server in VLAN[vlan_name]['dhcp_servers'] %}
+{% if dhcp_server | ipv4 %}
+{% set _dummy = relay_for_ipv4.update({'flag': True}) %}
+{% endif %}
+{% endfor %}
+{% endif %}
+{# Check DHCPv6 agents #}
+{% if DHCP_RELAY and vlan_name in DHCP_RELAY and DHCP_RELAY[vlan_name]['dhcpv6_servers']|length > 0 %}
+{% for dhcpv6_server in VLAN[vlan_name]['dhcpv6_servers'] %}
+{% if dhcpv6_server | ipv6 %}
+{% set _dummy = relay_for_ipv6.update({'flag': True}) %}
+{% endif %}
+{% endfor %}
+{% endif %}
+{% if relay_for_ipv4.flag or relay_for_ipv6.flag %}
+[program:dhcpmon-{{ vlan_name }}]
+{# We treat this VLAN as a downstream interface (-id), as we only want to listen for requests #}
+command=/usr/sbin/dhcpmon -id {{ vlan_name }}
+{#- Dual ToR Option #}
+{% if 'subtype' in DEVICE_METADATA['localhost'] and DEVICE_METADATA['localhost']['subtype'] == 'DualToR' %} -u Loopback0{% endif -%}
+{#- We treat all other interfaces as upstream interfaces (-iu), as we only want to listen for replies #}
+{% for (name, prefix) in VLAN_INTERFACE|pfx_filter %}
+{% if prefix | ipv4 and name != vlan_name %} -iu {{ name }}{% endif -%}
+{% endfor %}
+{% for (name, prefix) in INTERFACE|pfx_filter %}
+{% if prefix | ipv4 %} -iu {{ name }}{% endif -%}
+{% endfor %}
+{% for (name, prefix) in PORTCHANNEL_INTERFACE|pfx_filter %}
+{% if prefix | ipv4 %} -iu {{ name }}{% endif -%}
+{% endfor %}
+{% if MGMT_INTERFACE %}
+{% for (name, prefix) in MGMT_INTERFACE|pfx_filter %}
+{% if prefix | ipv4 %} -im {{ name }}{% endif -%}
+{% endfor %}
+{% endif %}
+
+priority=4
+autostart=false
+autorestart=false
+stdout_logfile=syslog
+stderr_logfile=syslog
+dependent_startup=true
+dependent_startup_wait_for=
+{%- if relay_for_ipv4.flag %}isc-dhcpv4-relay-{{ vlan_name }}:running {% endif %}
+
+
+{% set _dummy = relay_for_ipv4.update({'flag': False}) %}
+{% set _dummy = relay_for_ipv6.update({'flag': False}) %}
+{% endif %}
+{% endfor %}
diff --git a/dockers/docker-dhcp-relay/dhcp-relay.programs.j2 b/dockers/docker-dhcp-relay/dhcp-relay.programs.j2
new file mode 100644
index 000000000000..9d5b62c6b236
--- /dev/null
+++ b/dockers/docker-dhcp-relay/dhcp-relay.programs.j2
@@ -0,0 +1,22 @@
+[group:dhcp-relay]
+programs=
+{%- set relay_for_ipv6 = { 'flag': False } %}
+{%- set add_preceding_comma = { 'flag': False } %}
+{% for vlan_name in VLAN_INTERFACE %}
+{# Append DHCPv4 agents #}
+{% if VLAN and vlan_name in VLAN and 'dhcp_servers' in VLAN[vlan_name] and VLAN[vlan_name]['dhcp_servers']|length > 0 %}
+{% if add_preceding_comma.flag %},{% endif %}
+{% set _dummy = add_preceding_comma.update({'flag': True}) %}
+isc-dhcpv4-relay-{{ vlan_name }}
+{%- endif %}
+{% if DHCP_RELAY and vlan_name in DHCP_RELAY and DHCP_RELAY[vlan_name]['dhcpv6_servers']|length > 0 %}
+{% set _dummy = relay_for_ipv6.update({'flag': True}) %}
+{%- endif %}
+{% endfor %}
+{# Append DHCPv6 agents #}
+{% if relay_for_ipv6.flag %}
+{% if add_preceding_comma.flag %},{% endif %}
+{% set _dummy = add_preceding_comma.update({'flag': True}) %}
+dhcp6relay
+{% endif %}
+
diff --git a/dockers/docker-dhcp-relay/dhcpv4-relay.agents.j2 b/dockers/docker-dhcp-relay/dhcpv4-relay.agents.j2
new file mode 100644
index 000000000000..499afed54ef9
--- /dev/null
+++ b/dockers/docker-dhcp-relay/dhcpv4-relay.agents.j2
@@ -0,0 +1,41 @@
+{# Append DHCPv4 agents #}
+{% if VLAN and vlan_name in VLAN and 'dhcp_servers' in VLAN[vlan_name] and VLAN[vlan_name]['dhcp_servers']|length > 0 %}
+{% for dhcp_server in VLAN[vlan_name]['dhcp_servers'] %}
+{% if dhcp_server | ipv4 %}
+{% set _dummy = relay_for_ipv4.update({'flag': True}) %}
+{% endif %}
+{% endfor %}
+{% if relay_for_ipv4.flag %}
+{% set _dummy = relay_for_ipv4.update({'flag': False}) %}
+
+[program:isc-dhcpv4-relay-{{ vlan_name }}]
+{# We treat this VLAN as a downstream interface (-id), as we only want to listen for requests #}
+command=/usr/sbin/dhcrelay -d -m discard -a %%h:%%p %%P --name-alias-map-file /tmp/port-name-alias-map.txt -id {{ vlan_name }}
+{#- Dual ToR Option #}
+{% if 'subtype' in DEVICE_METADATA['localhost'] and DEVICE_METADATA['localhost']['subtype'] == 'DualToR' %} -U Loopback0 -dt{% endif -%}
+{#- si option to use intf addr in relay #}
+{% if DEVICE_METADATA['localhost']['deployment_id'] == '8' %} -si{% endif -%}
+{#- We treat all other interfaces as upstream interfaces (-iu), as we only want to listen for replies #}
+{% for (name, prefix) in VLAN_INTERFACE|pfx_filter %}
+{% if prefix | ipv4 and name != vlan_name %} -iu {{ name }}{% endif -%}
+{% endfor %}
+{% for (name, prefix) in INTERFACE|pfx_filter %}
+{% if prefix | ipv4 %} -iu {{ name }}{% endif -%}
+{% endfor %}
+{% for (name, prefix) in PORTCHANNEL_INTERFACE|pfx_filter %}
+{% if prefix | ipv4 %} -iu {{ name }}{% endif -%}
+{% endfor %}
+{% for dhcp_server in VLAN[vlan_name]['dhcp_servers'] %}
+{%- if dhcp_server | ipv4 %} {{ dhcp_server }}{% endif -%}
+{% endfor %}
+
+priority=3
+autostart=false
+autorestart=false
+stdout_logfile=syslog
+stderr_logfile=syslog
+dependent_startup=true
+dependent_startup_wait_for=start:exited
+
+{% endif %}
+{% endif %}
diff --git a/dockers/docker-dhcp-relay/dhcpv6-relay.agents.j2 b/dockers/docker-dhcp-relay/dhcpv6-relay.agents.j2
new file mode 100644
index 000000000000..3b14d11e3bcd
--- /dev/null
+++ b/dockers/docker-dhcp-relay/dhcpv6-relay.agents.j2
@@ -0,0 +1,23 @@
+{# Append DHCPv6 agents #}
+{# Create a program entry for each DHCPv6 relay agent instance #}
+{% for vlan_name in VLAN_INTERFACE %}
+{% if DHCP_RELAY and vlan_name in DHCP_RELAY and 'dhcpv6_servers' in DHCP_RELAY[vlan_name] %}
+{% for dhcpv6_server in DHCP_RELAY[vlan_name]['dhcpv6_servers'] %}
+{% if dhcpv6_server | ipv6 %}
+{% set _dummy = relay_for_ipv6.update({'flag': True}) %}
+{% endif %}
+{% endfor %}
+{% if relay_for_ipv6.flag %}
+{% set _dummy = relay_for_ipv6.update({'flag': False}) %}
+[program:dhcp6relay]
+command=/usr/sbin/dhcp6relay
+
+priority=3
+autostart=false
+autorestart=false
+stdout_logfile=syslog
+stderr_logfile=syslog
+
+{% endif %}
+{% endif %}
+{% endfor %}
diff --git a/dockers/docker-dhcp-relay/docker-dhcp-relay.supervisord.conf.j2 b/dockers/docker-dhcp-relay/docker-dhcp-relay.supervisord.conf.j2
index 6a12693efc64..e9c043dc2600 100644
--- a/dockers/docker-dhcp-relay/docker-dhcp-relay.supervisord.conf.j2
+++ b/dockers/docker-dhcp-relay/docker-dhcp-relay.supervisord.conf.j2
@@ -41,122 +41,27 @@ dependent_startup_wait_for=rsyslogd:running
{# If our configuration has VLANs... #}
{% if VLAN_INTERFACE %}
-{# Count how many VLANs require a DHCP relay agent... #}
-{% set num_relays = { 'count': 0 } %}
+{% set ipv4_num_relays = { 'count': 0 } %}
+{% set ipv6_num_relays = { 'count': 0 } %}
{% for vlan_name in VLAN_INTERFACE %}
{% if VLAN and vlan_name in VLAN and 'dhcp_servers' in VLAN[vlan_name] and VLAN[vlan_name]['dhcp_servers']|length > 0 %}
-{% set _dummy = num_relays.update({'count': num_relays.count + 1}) %}
-{% endif %}
-{% endfor %}
-{# If one or more of the VLANs require a DHCP relay agent... #}
-{% if num_relays.count > 0 %}
-[group:isc-dhcp-relay]
-programs=
-{%- set add_preceding_comma = { 'flag': False } %}
-{% for vlan_name in VLAN_INTERFACE %}
-{% if VLAN and vlan_name in VLAN and 'dhcp_servers' in VLAN[vlan_name] and VLAN[vlan_name]['dhcp_servers']|length > 0 %}
-{% if add_preceding_comma.flag %},{% endif %}
-{% set _dummy = add_preceding_comma.update({'flag': True}) %}
-isc-dhcp-relay-{{ vlan_name }}
-{%- endif %}
-{% endfor %}
-
-
-{# Create a program entry for each DHCP relay agent instance #}
-{% set relay_for_ipv4 = { 'flag': False } %}
-{% for vlan_name in VLAN_INTERFACE %}
-{% if VLAN and vlan_name in VLAN and 'dhcp_servers' in VLAN[vlan_name] and VLAN[vlan_name]['dhcp_servers']|length > 0 %}
-{% for dhcp_server in VLAN[vlan_name]['dhcp_servers'] %}
-{% if dhcp_server | ipv4 %}
-{% set _dummy = relay_for_ipv4.update({'flag': True}) %}
-{% endif %}
-{% endfor %}
-{% if relay_for_ipv4.flag %}
-{% set _dummy = relay_for_ipv4.update({'flag': False}) %}
-[program:isc-dhcp-relay-{{ vlan_name }}]
-{# We treat this VLAN as a downstream interface (-id), as we only want to listen for requests #}
-command=/usr/sbin/dhcrelay -d -m discard -a %%h:%%p %%P --name-alias-map-file /tmp/port-name-alias-map.txt -id {{ vlan_name }}
-{#- si option to use intf addr in relay #}
-{% if DEVICE_METADATA['localhost']['deployment_id'] == '8' %} -si{% endif -%}
-{#- We treat all other interfaces as upstream interfaces (-iu), as we only want to listen for replies #}
-{% for (name, prefix) in VLAN_INTERFACE|pfx_filter %}
-{% if prefix | ipv4 and name != vlan_name %} -iu {{ name }}{% endif -%}
-{% endfor %}
-{% for (name, prefix) in INTERFACE|pfx_filter %}
-{% if prefix | ipv4 %} -iu {{ name }}{% endif -%}
-{% endfor %}
-{% for (name, prefix) in PORTCHANNEL_INTERFACE|pfx_filter %}
-{% if prefix | ipv4 %} -iu {{ name }}{% endif -%}
-{% endfor %}
-{% for dhcp_server in VLAN[vlan_name]['dhcp_servers'] %}
-{%- if dhcp_server | ipv4 %} {{ dhcp_server }}{% endif -%}
-{% endfor %}
-
-priority=3
-autostart=false
-autorestart=false
-stdout_logfile=syslog
-stderr_logfile=syslog
-dependent_startup=true
-dependent_startup_wait_for=start:exited
-
+{% set _dummy = ipv4_num_relays.update({'count': ipv4_num_relays.count + 1}) %}
{% endif %}
+{% if DHCP_RELAY and vlan_name in DHCP_RELAY and 'dhcpv6_servers' in DHCP_RELAY[vlan_name] %}
+{% set _dummy = ipv6_num_relays.update({'count': ipv6_num_relays.count + 1}) %}
{% endif %}
{% endfor %}
+{# If one or more of the VLANs require a DHCP relay agent... #}
+{% if ipv4_num_relays.count > 0 or ipv6_num_relays.count > 0 %}
+{% include 'dhcp-relay.programs.j2' %}
-[group:dhcpmon]
-programs=
-{%- set add_preceding_comma = { 'flag': False } %}
-{% for vlan_name in VLAN_INTERFACE %}
-{% if VLAN and vlan_name in VLAN and 'dhcp_servers' in VLAN[vlan_name] and VLAN[vlan_name]['dhcp_servers']|length > 0 %}
-{% if add_preceding_comma.flag %},{% endif %}
-{% set _dummy = add_preceding_comma.update({'flag': True}) %}
-dhcpmon-{{ vlan_name }}
-{%- endif %}
-{% endfor %}
-
-
-{# Create a program entry for each DHCP MONitor instance #}
{% set relay_for_ipv4 = { 'flag': False } %}
+{% set relay_for_ipv6 = { 'flag': False } %}
{% for vlan_name in VLAN_INTERFACE %}
-{% if VLAN and vlan_name in VLAN and 'dhcp_servers' in VLAN[vlan_name] and VLAN[vlan_name]['dhcp_servers']|length > 0 %}
-{% for dhcp_server in VLAN[vlan_name]['dhcp_servers'] %}
-{% if dhcp_server | ipv4 %}
-{% set _dummy = relay_for_ipv4.update({'flag': True}) %}
-{% endif %}
-{% endfor %}
-{% if relay_for_ipv4.flag %}
-{% set _dummy = relay_for_ipv4.update({'flag': False}) %}
-[program:dhcpmon-{{ vlan_name }}]
-{# We treat this VLAN as a downstream interface (-id), as we only want to listen for requests #}
-command=/usr/sbin/dhcpmon -id {{ vlan_name }}
-{#- We treat all other interfaces as upstream interfaces (-iu), as we only want to listen for replies #}
-{% for (name, prefix) in VLAN_INTERFACE|pfx_filter %}
-{% if prefix | ipv4 and name != vlan_name %} -iu {{ name }}{% endif -%}
-{% endfor %}
-{% for (name, prefix) in INTERFACE|pfx_filter %}
-{% if prefix | ipv4 %} -iu {{ name }}{% endif -%}
-{% endfor %}
-{% for (name, prefix) in PORTCHANNEL_INTERFACE|pfx_filter %}
-{% if prefix | ipv4 %} -iu {{ name }}{% endif -%}
-{% endfor %}
-{% if MGMT_INTERFACE %}
-{% for (name, prefix) in MGMT_INTERFACE|pfx_filter %}
-{% if prefix | ipv4 %} -im {{ name }}{% endif -%}
-{% endfor %}
-{% endif %}
-
-priority=4
-autostart=false
-autorestart=false
-stdout_logfile=syslog
-stderr_logfile=syslog
-dependent_startup=true
-dependent_startup_wait_for=isc-dhcp-relay-{{ vlan_name }}:running
-
-{% endif %}
-{% endif %}
+{% include 'dhcpv4-relay.agents.j2' %}
{% endfor %}
+{% include 'dhcpv6-relay.agents.j2' %}
+{% include 'dhcp-relay.monitors.j2' %}
{% endif %}
{% endif %}
diff --git a/dockers/docker-dhcp-relay/start.sh b/dockers/docker-dhcp-relay/start.sh
index 86ba91147ef5..2488137378a9 100755
--- a/dockers/docker-dhcp-relay/start.sh
+++ b/dockers/docker-dhcp-relay/start.sh
@@ -1,7 +1,7 @@
#!/usr/bin/env bash
# If our supervisor config has entries in the "isc-dhcp-relay" group...
-if [ $(supervisorctl status | grep -c "^isc-dhcp-relay:") -gt 0 ]; then
+if [ $(supervisorctl status | grep -c "^dhcp-relay:") -gt 0 ]; then
# Wait for all interfaces to come up and be assigned IPv4 addresses before
# starting the DHCP relay agent(s). If an interface the relay should listen
# on is down, the relay agent will not start. If an interface the relay
diff --git a/dockers/docker-dhcp-relay/wait_for_intf.sh.j2 b/dockers/docker-dhcp-relay/wait_for_intf.sh.j2
index 568f128b3772..b224a697b5ba 100644
--- a/dockers/docker-dhcp-relay/wait_for_intf.sh.j2
+++ b/dockers/docker-dhcp-relay/wait_for_intf.sh.j2
@@ -38,3 +38,8 @@ wait_until_iface_ready {{ name }} {{ prefix }}
wait_until_iface_ready {{ name }} {{ prefix }}
{% endif %}
{% endfor %}
+
+# Wait 10 seconds for the rest of interfaces to get added/populated.
+# dhcrelay listens on each of the interfaces (in addition to the port
+# channels and vlan interfaces)
+sleep 10
diff --git a/rules/dhcp6relay.mk b/rules/dhcp6relay.mk
new file mode 100644
index 000000000000..7f1ab3a1e354
--- /dev/null
+++ b/rules/dhcp6relay.mk
@@ -0,0 +1,12 @@
+# SONiC DHCPV6 RELAY Package
+
+SONIC_DHCP6RELAY_VERSION = 1.0.0-0
+SONIC_DHCP6RELAY_PKG_NAME = dhcp6relay
+
+SONIC_DHCP6RELAY = sonic-$(SONIC_DHCP6RELAY_PKG_NAME)_$(SONIC_DHCP6RELAY_VERSION)_$(CONFIGURED_ARCH).deb
+$(SONIC_DHCP6RELAY)_DEPENDS = $(LIBSWSSCOMMON) $(LIBHIREDIS) $(LIBSWSSCOMMON_DEV) $(LIBHIREDIS_DEV)
+$(SONIC_DHCP6RELAY)_SRC_PATH = $(SRC_PATH)/$(SONIC_DHCP6RELAY_PKG_NAME)
+SONIC_DPKG_DEBS += $(SONIC_DHCP6RELAY)
+
+SONIC_DHCP6RELAY_DBG = sonic-$(SONIC_DHCP6RELAY_PKG_NAME)-dbg_$(SONIC_DHCP6RELAY_VERSION)_amd64.deb
+$(eval $(call add_derived_package,$(SONIC_DHCP6RELAY),$(SONIC_DHCP6RELAY_DBG)))
diff --git a/rules/docker-dhcp-relay.mk b/rules/docker-dhcp-relay.mk
index 520e243d6266..4a724443fb88 100644
--- a/rules/docker-dhcp-relay.mk
+++ b/rules/docker-dhcp-relay.mk
@@ -6,9 +6,9 @@ DOCKER_DHCP_RELAY_DBG = $(DOCKER_DHCP_RELAY_STEM)-$(DBG_IMAGE_MARK).gz
$(DOCKER_DHCP_RELAY)_PATH = $(DOCKERS_PATH)/$(DOCKER_DHCP_RELAY_STEM)
-$(DOCKER_DHCP_RELAY)_DEPENDS += $(ISC_DHCP_RELAY) $(REDIS_TOOLS) $(SONIC_DHCPMON)
+$(DOCKER_DHCP_RELAY)_DEPENDS += $(ISC_DHCP_RELAY) $(REDIS_TOOLS) $(SONIC_DHCPMON) $(SONIC_DHCP6RELAY) $(LIBSWSSCOMMON)
$(DOCKER_DHCP_RELAY)_DBG_DEPENDS = $($(DOCKER_CONFIG_ENGINE_STRETCH)_DBG_DEPENDS)
-$(DOCKER_DHCP_RELAY)_DBG_DEPENDS += $(ISC_DHCP_RELAY_DBG)
+$(DOCKER_DHCP_RELAY)_DBG_DEPENDS += $(ISC_DHCP_RELAY_DBG) $(SONIC_DHCP6RELAY_DBG)
$(DOCKER_DHCP_RELAY)_DBG_IMAGE_PACKAGES = $($(DOCKER_CONFIG_ENGINE_STRETCH)_DBG_IMAGE_PACKAGES)
diff --git a/sonic-dhcp-relay b/sonic-dhcp-relay
new file mode 160000
index 000000000000..e2cd5851ddd9
--- /dev/null
+++ b/sonic-dhcp-relay
@@ -0,0 +1 @@
+Subproject commit e2cd5851ddd9b6496b59b72e75aaba8e4d7f284d
diff --git a/src/dhcp6relay/.gitignore b/src/dhcp6relay/.gitignore
new file mode 100644
index 000000000000..9d09ae6b3f1a
--- /dev/null
+++ b/src/dhcp6relay/.gitignore
@@ -0,0 +1,5 @@
+debian/*
+!debian/changelog
+!debian/compat
+!debian/control
+!debian/rules
diff --git a/src/dhcp6relay/Makefile b/src/dhcp6relay/Makefile
new file mode 100644
index 000000000000..8b5740fd787e
--- /dev/null
+++ b/src/dhcp6relay/Makefile
@@ -0,0 +1,42 @@
+RM := rm -rf
+DHCP6RELAY_TARGET := dhcp6relay
+CP := cp
+MKDIR := mkdir
+CC := g++
+MV := mv
+LIBS := -levent -lhiredis -lswsscommon -pthread -lboost_thread -lboost_system
+CFLAGS += -Wall -std=c++14 -fPIE -I$(PWD)/../sonic-swss-common/common
+PWD := $(shell pwd)
+
+ifneq ($(MAKECMDGOALS),clean)
+ifneq ($(strip $(C_DEPS)),)
+-include $(C_DEPS) $(OBJS)
+endif
+endif
+
+-include src/subdir.mk
+
+all: sonic-dhcp6relay
+
+sonic-dhcp6relay: $(OBJS)
+ @echo 'Building target: $@'
+ @echo 'Invoking: G++ Linker'
+ $(CC) $(LDFLAGS) -o $(DHCP6RELAY_TARGET) $(OBJS) $(LIBS)
+ @echo 'Finished building target: $@'
+ @echo ' '
+
+install:
+ $(MKDIR) -p $(DESTDIR)/usr/sbin
+ $(MV) $(DHCP6RELAY_TARGET) $(DESTDIR)/usr/sbin
+
+deinstall:
+ $(RM) $(DESTDIR)/usr/sbin/$(DHCP6RELAY_TARGET)
+ $(RM) -rf $(DESTDIR)/usr/sbin
+
+clean:
+ -$(RM) $(EXECUTABLES) $(C_DEPS) $(OBJS) $(DHCP6RELAY_TARGET)
+ -@echo ' '
+
+.PHONY: all clean dependents
+
+
diff --git a/src/dhcp6relay/debian/changelog b/src/dhcp6relay/debian/changelog
new file mode 100644
index 000000000000..aec73a095801
--- /dev/null
+++ b/src/dhcp6relay/debian/changelog
@@ -0,0 +1,5 @@
+sonic-dhcp6relay (1.0.0-0) UNRELEASED; urgency=medium
+
+ * Initial release.
+
+ -- Kelly Yeh Fri, 15 Oct 2021 00:00:00 +1000
diff --git a/src/dhcp6relay/debian/compat b/src/dhcp6relay/debian/compat
new file mode 100644
index 000000000000..ec635144f600
--- /dev/null
+++ b/src/dhcp6relay/debian/compat
@@ -0,0 +1 @@
+9
diff --git a/src/dhcp6relay/debian/control b/src/dhcp6relay/debian/control
new file mode 100644
index 000000000000..fb82be7c911f
--- /dev/null
+++ b/src/dhcp6relay/debian/control
@@ -0,0 +1,27 @@
+Source: sonic-dhcp6relay
+Section: devel
+Priority: optional
+Maintainer: Kelly Yeh
+Build-Depends: debhelper (>= 8.0.0),
+ dh-systemd
+Standards-Version: 3.9.3
+Homepage: https://github.com/Azure/sonic-buildimage
+XS-Go-Import-Path: github.com/Azure/sonic-buildimage
+
+Package: sonic-dhcp6relay
+Architecture: any
+Built-Using: ${misc:Built-Using}
+Depends: libevent-2.0-5,
+ libboost-thread1.55.0,
+ libboost-system1.55.0
+Description: SONiC DHCPv6 Relay
+
+Package: sonic-dhcp6relay-dbg
+Architecture: any
+Section: debug
+Priority: extra
+Built-Using: ${misc:Built-Using}
+Depends: libevent-2.0-5,
+ libboost-thread1.55.0,
+ libboost-system1.55.0
+Description: SONiC DHCPv6 Relay debug symbols
diff --git a/src/dhcp6relay/debian/rules b/src/dhcp6relay/debian/rules
new file mode 100755
index 000000000000..ed8a2397a6d4
--- /dev/null
+++ b/src/dhcp6relay/debian/rules
@@ -0,0 +1,12 @@
+#!/usr/bin/make -f
+
+export DEB_BUILD_MAINT_OPTIONS=hardening=+all
+
+%:
+ dh $@ --parallel
+
+override_dh_strip:
+ dh_strip --dbg-package=sonic-dhcp6relay-dbg
+
+override_dh_auto_install:
+ dh_auto_install --destdir=debian/sonic-dhcp6relay
diff --git a/src/dhcp6relay/src/configInterface.cpp b/src/dhcp6relay/src/configInterface.cpp
new file mode 100644
index 000000000000..dfe6031e0468
--- /dev/null
+++ b/src/dhcp6relay/src/configInterface.cpp
@@ -0,0 +1,151 @@
+#include
+#include
+#include
+#include "configInterface.h"
+
+constexpr auto DEFAULT_TIMEOUT_MSEC = 1000;
+
+bool pollSwssNotifcation = true;
+std::shared_ptr mSwssThreadPtr;
+
+std::shared_ptr configDbPtr = std::make_shared (4, "localhost", 6379, 0);
+swss::SubscriberStateTable ipHelpersTable(configDbPtr.get(), "DHCP_RELAY");
+swss::Select swssSelect;
+
+/**
+ * @code void initialize_swss()
+ *
+ * @brief initialize DB tables and start SWSS listening thread
+ *
+ * @return none
+ */
+void initialize_swss(std::vector *vlans)
+{
+ try {
+ swssSelect.addSelectable(&ipHelpersTable);
+ get_dhcp(vlans);
+ mSwssThreadPtr = std::make_shared (&handleSwssNotification, vlans);
+ }
+ catch (const std::bad_alloc &e) {
+ syslog(LOG_ERR, "Failed allocate memory. Exception details: %s", e.what());
+ }
+}
+
+/**
+ * @code void deinitialize_swss()
+ *
+ * @brief deinitialize DB interface and join SWSS listening thread
+ *
+ * @return none
+ */
+void deinitialize_swss()
+{
+ stopSwssNotificationPoll();
+ mSwssThreadPtr->interrupt();
+}
+
+
+/**
+ * @code void get_dhcp(std::vector *vlans)
+ *
+ * @brief initialize and get vlan table information from DHCP_RELAY
+ *
+ * @return none
+ */
+void get_dhcp(std::vector *vlans) {
+ swss::Selectable *selectable;
+ int ret = swssSelect.select(&selectable, DEFAULT_TIMEOUT_MSEC);
+ if (ret == swss::Select::ERROR) {
+ syslog(LOG_WARNING, "Select: returned ERROR");
+ } else if (ret == swss::Select::TIMEOUT) {
+ }
+ if (selectable == static_cast (&ipHelpersTable)) {
+ handleRelayNotification(ipHelpersTable, vlans);
+ }
+}
+/**
+ * @code void handleSwssNotification(std::vector *vlans)
+ *
+ * @brief main thread for handling SWSS notification
+ *
+ * @param context list of vlans/argument config that contains strings of server and option
+ *
+ * @return none
+ */
+void handleSwssNotification(std::vector *vlans)
+{
+ while (pollSwssNotifcation) {
+ get_dhcp(vlans);
+ }
+}
+
+/**
+ * @code void handleRelayNotification(swss::SubscriberStateTable &ipHelpersTable, std::vector *vlans)
+ *
+ * @brief handles DHCPv6 relay configuration change notification
+ *
+ * @param ipHelpersTable DHCP table
+ * @param vlans list of vlans/argument config that contains strings of server and option
+ *
+ * @return none
+ */
+void handleRelayNotification(swss::SubscriberStateTable &ipHelpersTable, std::vector *vlans)
+{
+ std::deque entries;
+
+ ipHelpersTable.pops(entries);
+ processRelayNotification(entries, vlans);
+}
+
+/**
+ * @code void processRelayNotification(std::deque &entries, std::vector *vlans)
+ *
+ * @brief process DHCPv6 relay servers and options configuration change notification
+ *
+ * @param entries queue of std::tuple> entries in DHCP table
+ * @param vlans list of vlans/argument config that contains strings of server and option
+ *
+ * @return none
+ */
+void processRelayNotification(std::deque &entries, std::vector *vlans)
+{
+ std::vector servers;
+
+ for (auto &entry: entries) {
+ std::string vlan = kfvKey(entry);
+ std::string operation = kfvOp(entry);
+ std::vector fieldValues = kfvFieldsValues(entry);
+
+ relay_config intf;
+ intf.is_option_79 = true;
+ intf.interface = vlan;
+ for (auto &fieldValue: fieldValues) {
+ std::string f = fvField(fieldValue);
+ std::string v = fvValue(fieldValue);
+ if(f == "dhcpv6_servers") {
+ std::stringstream ss(v);
+ while (ss.good()) {
+ std::string substr;
+ getline(ss, substr, ',');
+ intf.servers.push_back(substr);
+ }
+ syslog(LOG_DEBUG, "key: %s, Operation: %s, f: %s, v: %s", vlan.c_str(), operation.c_str(), f.c_str(), v.c_str());
+ }
+ if(f == "dhcpv6_option|rfc6939_support" && v == "false") {
+ intf.is_option_79 = false;
+ }
+ }
+ vlans->push_back(intf);
+ }
+}
+
+/**
+*@code stopSwssNotificationPoll
+*
+*@brief stop SWSS listening thread
+*
+*@return none
+*/
+void stopSwssNotificationPoll() {
+ pollSwssNotifcation = false;
+};
diff --git a/src/dhcp6relay/src/configInterface.d b/src/dhcp6relay/src/configInterface.d
new file mode 100644
index 000000000000..d803bf1a54de
--- /dev/null
+++ b/src/dhcp6relay/src/configInterface.d
@@ -0,0 +1,44 @@
+src/configInterface.o: src/configInterface.cpp src/configInterface.h \
+ /sonic/src/dhcp6relay/../sonic-swss-common/common/subscriberstatetable.h \
+ /sonic/src/dhcp6relay/../sonic-swss-common/common/dbconnector.h \
+ /sonic/src/dhcp6relay/../sonic-swss-common/common/consumertablebase.h \
+ /sonic/src/dhcp6relay/../sonic-swss-common/common/table.h \
+ /sonic/src/dhcp6relay/../sonic-swss-common/common/redisreply.h \
+ /sonic/src/dhcp6relay/../sonic-swss-common/common/rediscommand.h \
+ /sonic/src/dhcp6relay/../sonic-swss-common/common/redisselect.h \
+ /sonic/src/dhcp6relay/../sonic-swss-common/common/selectable.h \
+ /sonic/src/dhcp6relay/../sonic-swss-common/common/redispipeline.h \
+ /sonic/src/dhcp6relay/../sonic-swss-common/common/schema.h \
+ /sonic/src/dhcp6relay/../sonic-swss-common/common/redistran.h \
+ /sonic/src/dhcp6relay/../sonic-swss-common/common/logger.h \
+ /sonic/src/dhcp6relay/../sonic-swss-common/common/select.h src/relay.h
+
+src/configInterface.h:
+
+/sonic/src/dhcp6relay/../sonic-swss-common/common/subscriberstatetable.h:
+
+/sonic/src/dhcp6relay/../sonic-swss-common/common/dbconnector.h:
+
+/sonic/src/dhcp6relay/../sonic-swss-common/common/consumertablebase.h:
+
+/sonic/src/dhcp6relay/../sonic-swss-common/common/table.h:
+
+/sonic/src/dhcp6relay/../sonic-swss-common/common/redisreply.h:
+
+/sonic/src/dhcp6relay/../sonic-swss-common/common/rediscommand.h:
+
+/sonic/src/dhcp6relay/../sonic-swss-common/common/redisselect.h:
+
+/sonic/src/dhcp6relay/../sonic-swss-common/common/selectable.h:
+
+/sonic/src/dhcp6relay/../sonic-swss-common/common/redispipeline.h:
+
+/sonic/src/dhcp6relay/../sonic-swss-common/common/schema.h:
+
+/sonic/src/dhcp6relay/../sonic-swss-common/common/redistran.h:
+
+/sonic/src/dhcp6relay/../sonic-swss-common/common/logger.h:
+
+/sonic/src/dhcp6relay/../sonic-swss-common/common/select.h:
+
+src/relay.h:
diff --git a/src/dhcp6relay/src/configInterface.h b/src/dhcp6relay/src/configInterface.h
new file mode 100644
index 000000000000..20b0912c5cef
--- /dev/null
+++ b/src/dhcp6relay/src/configInterface.h
@@ -0,0 +1,75 @@
+#include
+#include "subscriberstatetable.h"
+#include "select.h"
+#include "relay.h"
+
+/**
+ * @code void initialize_swss()
+ *
+ * @brief initialize DB tables and start SWSS listening thread
+ *
+ * @return none
+ */
+void initialize_swss(std::vector *vlans);
+
+/**
+ * @code void deinitialize_swss()
+ *
+ * @brief deinitialize DB interface and join SWSS listening thread
+ *
+ * @return none
+ */
+void deinitialize_swss();
+
+/**
+ * @code void get_dhcp(std::vector *vlans)
+ *
+ * @brief initialize and get vlan information from DHCP_RELAY
+ *
+ * @return none
+ */
+void get_dhcp(std::vector *vlans);
+
+/**
+ * @code void handleSwssNotification(std::vector *vlans)
+ *
+ * @brief main thread for handling SWSS notification
+ *
+ * @param vlans list of vlans/argument config that contains strings of server and option
+ *
+ * @return none
+ */
+void handleSwssNotification(std::vector *vlans);
+
+/**
+ * @code void handleRelayNotification(swss::SubscriberStateTable &ipHelpersTable, std::vector *vlans)
+ *
+ * @brief handles DHCPv6 relay configuration change notification
+ *
+ * @param ipHelpersTable DHCP table
+ * @param vlans list of vlans/argument config that contains strings of server and option
+ *
+ * @return none
+ */
+void handleRelayNotification(swss::SubscriberStateTable &configMuxTable, std::vector *vlans);
+
+/**
+ * @code void processRelayNotification(std::deque &entries, std::vector *vlans)
+ *
+ * @brief process DHCPv6 relay servers and options configuration change notification
+ *
+ * @param entries queue of std::tuple> entries in DHCP table
+ * @param context list of vlans/argument config that contains strings of server and option
+ *
+ * @return none
+ */
+void processRelayNotification(std::deque &entries, std::vector *vlans);
+
+/**
+*@code stopSwssNotificationPoll
+*
+*@brief stop SWSS listening thread
+*
+*@return none
+*/
+void stopSwssNotificationPoll();
diff --git a/src/dhcp6relay/src/main.cpp b/src/dhcp6relay/src/main.cpp
new file mode 100644
index 000000000000..6d0fb29c050f
--- /dev/null
+++ b/src/dhcp6relay/src/main.cpp
@@ -0,0 +1,17 @@
+#include
+#include
+#include "configInterface.h"
+
+int main(int argc, char *argv[]) {
+ try {
+ std::vector vlans;
+ initialize_swss(&vlans);
+ loop_relay(&vlans);
+ }
+ catch (std::exception &e)
+ {
+ syslog(LOG_ERR, "An exception occurred.\n");
+ return 1;
+ }
+ return 0;
+}
diff --git a/src/dhcp6relay/src/main.d b/src/dhcp6relay/src/main.d
new file mode 100644
index 000000000000..05e7fd2367f0
--- /dev/null
+++ b/src/dhcp6relay/src/main.d
@@ -0,0 +1,44 @@
+src/main.o: src/main.cpp src/configInterface.h \
+ /sonic/src/dhcp6relay/../sonic-swss-common/common/subscriberstatetable.h \
+ /sonic/src/dhcp6relay/../sonic-swss-common/common/dbconnector.h \
+ /sonic/src/dhcp6relay/../sonic-swss-common/common/consumertablebase.h \
+ /sonic/src/dhcp6relay/../sonic-swss-common/common/table.h \
+ /sonic/src/dhcp6relay/../sonic-swss-common/common/redisreply.h \
+ /sonic/src/dhcp6relay/../sonic-swss-common/common/rediscommand.h \
+ /sonic/src/dhcp6relay/../sonic-swss-common/common/redisselect.h \
+ /sonic/src/dhcp6relay/../sonic-swss-common/common/selectable.h \
+ /sonic/src/dhcp6relay/../sonic-swss-common/common/redispipeline.h \
+ /sonic/src/dhcp6relay/../sonic-swss-common/common/schema.h \
+ /sonic/src/dhcp6relay/../sonic-swss-common/common/redistran.h \
+ /sonic/src/dhcp6relay/../sonic-swss-common/common/logger.h \
+ /sonic/src/dhcp6relay/../sonic-swss-common/common/select.h src/relay.h
+
+src/configInterface.h:
+
+/sonic/src/dhcp6relay/../sonic-swss-common/common/subscriberstatetable.h:
+
+/sonic/src/dhcp6relay/../sonic-swss-common/common/dbconnector.h:
+
+/sonic/src/dhcp6relay/../sonic-swss-common/common/consumertablebase.h:
+
+/sonic/src/dhcp6relay/../sonic-swss-common/common/table.h:
+
+/sonic/src/dhcp6relay/../sonic-swss-common/common/redisreply.h:
+
+/sonic/src/dhcp6relay/../sonic-swss-common/common/rediscommand.h:
+
+/sonic/src/dhcp6relay/../sonic-swss-common/common/redisselect.h:
+
+/sonic/src/dhcp6relay/../sonic-swss-common/common/selectable.h:
+
+/sonic/src/dhcp6relay/../sonic-swss-common/common/redispipeline.h:
+
+/sonic/src/dhcp6relay/../sonic-swss-common/common/schema.h:
+
+/sonic/src/dhcp6relay/../sonic-swss-common/common/redistran.h:
+
+/sonic/src/dhcp6relay/../sonic-swss-common/common/logger.h:
+
+/sonic/src/dhcp6relay/../sonic-swss-common/common/select.h:
+
+src/relay.h:
diff --git a/src/dhcp6relay/src/relay.cpp b/src/dhcp6relay/src/relay.cpp
new file mode 100644
index 000000000000..c4589774bfa9
--- /dev/null
+++ b/src/dhcp6relay/src/relay.cpp
@@ -0,0 +1,816 @@
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "dbconnector.h"
+#include "configInterface.h"
+#include "redisclient.h"
+
+
+struct event *listen_event;
+struct event *server_listen_event;
+struct event_base *base;
+struct event *ev_sigint;
+struct event *ev_sigterm;
+static std::string counter_table = "DHCPv6_COUNTER_TABLE|";
+swss::DBConnector state_db(6, "localhost", 6379, 0);
+swss::RedisClient m_stateDbRedisClient(&state_db);
+
+/* DHCPv6 filter */
+/* sudo tcpdump -dd "ip6 dst ff02::1:2 && udp dst port 547" */
+
+static struct sock_filter ether_relay_filter[] = {
+
+ { 0x28, 0, 0, 0x0000000c },
+ { 0x15, 0, 13, 0x000086dd },
+ { 0x20, 0, 0, 0x00000026 },
+ { 0x15, 0, 11, 0xff020000 },
+ { 0x20, 0, 0, 0x0000002a },
+ { 0x15, 0, 9, 0x00000000 },
+ { 0x20, 0, 0, 0x0000002e },
+ { 0x15, 0, 7, 0x00000000 },
+ { 0x20, 0, 0, 0x00000032 },
+ { 0x15, 0, 5, 0x00010002 },
+ { 0x30, 0, 0, 0x00000014 },
+ { 0x15, 0, 3, 0x00000011 },
+ { 0x28, 0, 0, 0x00000038 },
+ { 0x15, 0, 1, 0x00000223 },
+ { 0x6, 0, 0, 0x00040000 },
+ { 0x6, 0, 0, 0x00000000 },
+};
+const struct sock_fprog ether_relay_fprog = {
+ lengthof(ether_relay_filter),
+ ether_relay_filter
+};
+
+/* DHCPv6 Counter */
+uint64_t counters[DHCPv6_MESSAGE_TYPE_COUNT];
+std::map counterMap = {{0, "Unknown"},
+ {1, "Solicit"},
+ {2, "Advertise"},
+ {3, "Request"},
+ {4, "Confirm"},
+ {5, "Renew"},
+ {6, "Rebind"},
+ {7, "Reply"},
+ {8, "Release"},
+ {9, "Decline"},
+ {12, "Relay-Forward"},
+ {13, "Relay-Reply"}};
+
+/**
+ * @code void initialize_counter(std::string counterVlan);
+ *
+ * @brief initialize the counter by each Vlan
+ *
+ * @param counterVlan counter table with interface name
+ *
+ * @return none
+ */
+void initialize_counter(std::string counterVlan) {
+ m_stateDbRedisClient.hset(counterVlan, "Unknown", toString(counters[DHCPv6_MESSAGE_TYPE_UNKNOWN]));
+ m_stateDbRedisClient.hset(counterVlan, "Solicit", toString(counters[DHCPv6_MESSAGE_TYPE_SOLICIT]));
+ m_stateDbRedisClient.hset(counterVlan, "Advertise", toString(counters[DHCPv6_MESSAGE_TYPE_ADVERTISE]));
+ m_stateDbRedisClient.hset(counterVlan, "Request", toString(counters[DHCPv6_MESSAGE_TYPE_REQUEST]));
+ m_stateDbRedisClient.hset(counterVlan, "Confirm", toString(counters[DHCPv6_MESSAGE_TYPE_CONFIRM]));
+ m_stateDbRedisClient.hset(counterVlan, "Renew", toString(counters[DHCPv6_MESSAGE_TYPE_RENEW]));
+ m_stateDbRedisClient.hset(counterVlan, "Rebind", toString(counters[DHCPv6_MESSAGE_TYPE_REBIND]));
+ m_stateDbRedisClient.hset(counterVlan, "Reply", toString(counters[DHCPv6_MESSAGE_TYPE_REPLY]));
+ m_stateDbRedisClient.hset(counterVlan, "Release", toString(counters[DHCPv6_MESSAGE_TYPE_RELEASE]));
+ m_stateDbRedisClient.hset(counterVlan, "Decline", toString(counters[DHCPv6_MESSAGE_TYPE_DECLINE]));
+ m_stateDbRedisClient.hset(counterVlan, "Relay-Forward", toString(counters[DHCPv6_MESSAGE_TYPE_RELAY_FORW]));
+ m_stateDbRedisClient.hset(counterVlan, "Relay-Reply", toString(counters[DHCPv6_MESSAGE_TYPE_RELAY_REPL]));
+}
+
+/**
+ * @code void update_counter(std::string CounterVlan, uint8_t msg_type);
+ *
+ * @brief update the counter in state_db with count of each DHCPv6 message type
+ *
+ * @param counterVlan counter table with interface name
+ * @param msg_type dhcpv6 message type to be updated in counter
+ *
+ * @return none
+ */
+void update_counter(std::string counterVlan, uint8_t msg_type) {
+ m_stateDbRedisClient.hset(counterVlan, counterMap.find(msg_type)->second, toString(counters[msg_type]));
+}
+
+/**
+ * @code std::string toString(uint16_t count);
+ *
+ * @brief convert uint16_t to string
+ *
+ * @param count count of messages in counter
+ *
+ * @return count in string
+ */
+std::string toString(uint16_t count) {
+ std::stringstream ss;
+ ss << count;
+ std::string countValue = ss.str();
+ return countValue;
+}
+
+/**
+ * @code const struct ether_header *parse_ether_frame(const uint8_t *buffer, const uint8_t **out_end);
+ *
+ * @brief parse through ethernet frame
+ *
+ * @param *buffer message buffer
+ * @param **out_end pointer
+ *
+ * @return ether_header end of ethernet header position
+ */
+const struct ether_header *parse_ether_frame(const uint8_t *buffer, const uint8_t **out_end) {
+ (*out_end) = buffer + sizeof(struct ether_header);
+ return (const struct ether_header *)buffer;
+}
+
+/**
+ * @code const struct ip6_hdr *parse_ip6_hdr(const uint8_t *buffer, const uint8_t **out_end);
+ *
+ * @brief parse through ipv6 header
+ *
+ * @param *buffer message buffer
+ * @param **out_end pointer
+ *
+ * @return ip6_hdr end of ipv6 header position
+ */
+const struct ip6_hdr *parse_ip6_hdr(const uint8_t *buffer, const uint8_t **out_end) {
+ (*out_end) = buffer + sizeof(struct ip6_hdr);
+ return (struct ip6_hdr *)buffer;
+}
+
+/**
+ * @code const struct udphdr *parse_udp(const uint8_t *buffer, const uint8_t **out_end);
+ *
+ * @brief parse through udp header
+ *
+ * @param *buffer message buffer
+ * @param **out_end pointer
+ *
+ * @return udphdr end of udp header position
+ */
+const struct udphdr *parse_udp(const uint8_t *buffer, const uint8_t **out_end) {
+ (*out_end) = buffer + sizeof(struct udphdr);
+ return (const struct udphdr *)buffer;
+}
+
+/**
+ * @code const struct dhcpv6_msg *parse_dhcpv6_hdr(const uint8_t *buffer);
+ *
+ * @brief parse through dhcpv6 header
+ *
+ * @param *buffer message buffer
+ * @param **out_end pointer
+ *
+ * @return dhcpv6_msg end of dhcpv6 header position
+ */
+const struct dhcpv6_msg *parse_dhcpv6_hdr(const uint8_t *buffer) {
+ return (const struct dhcpv6_msg *)buffer;
+}
+
+/**
+ * @code const struct dhcpv6_relay_msg *parse_dhcpv6_relay(const uint8_t *buffer);
+ *
+ * @brief parse through dhcpv6 relay message
+ *
+ * @param *buffer message buffer
+ * @param **out_end pointer
+ *
+ * @return dhcpv6_relay_msg start of dhcpv6 relay message or end of dhcpv6 message type position
+ */
+const struct dhcpv6_relay_msg *parse_dhcpv6_relay(const uint8_t *buffer) {
+ return (const struct dhcpv6_relay_msg *)buffer;
+}
+
+/**
+ * @code const struct dhcpv6_option *parse_dhcpv6_opt(const uint8_t *buffer, const uint8_t **out_end);
+ *
+ * @brief parse through dhcpv6 option
+ *
+ * @param *buffer message buffer
+ * @param **out_end pointer
+ *
+ * @return dhcpv6_option end of dhcpv6 message option
+ */
+const struct dhcpv6_option *parse_dhcpv6_opt(const uint8_t *buffer, const uint8_t **out_end) {
+ uint32_t size = 4; // option-code + option-len
+ size += ntohs(*(uint16_t *)(buffer + 2));
+ (*out_end) = buffer + size;
+
+ return (const struct dhcpv6_option *)buffer;
+}
+
+/**
+ * @code void send_udp(int sock, uint8_t *buffer, struct sockaddr_in6 target, uint32_t n, relay_config *config, uint8_t msg_type);
+ *
+ * @brief send udp packet
+ *
+ * @param *buffer message buffer
+ * @param sockaddr_in6 target target socket
+ * @param n length of message
+ * @param relay_config *config pointer to relay_config
+ * @param uint8_t msg_type message type of dhcpv6 option of relayed message
+ *
+ * @return dhcpv6_option end of dhcpv6 message option
+ */
+void send_udp(int sock, uint8_t *buffer, struct sockaddr_in6 target, uint32_t n, relay_config *config, uint8_t msg_type) {
+ std::string counterVlan = counter_table;
+ if(sendto(sock, buffer, n, 0, (const struct sockaddr *)&target, sizeof(target)) == -1)
+ syslog(LOG_ERR, "sendto: Failed to send to target address\n");
+ else if (counterMap.find(msg_type) != counterMap.end()) {
+ counters[msg_type]++;
+ update_counter(counterVlan.append(config->interface), msg_type);
+ } else {
+ syslog(LOG_WARNING, "unexpected message type %d(0x%x)\n", msg_type, msg_type);
+ }
+}
+
+/**
+ * @code relay_forward(uint8_t *buffer, const struct dhcpv6_msg *msg, uint16_t msg_length);
+ *
+ * @brief embed the DHCPv6 message received into DHCPv6 relay forward message
+ *
+ * @param buffer pointer to buffer
+ * @param msg pointer to parsed DHCPv6 message
+ * @param msg_length length of DHCPv6 message
+ *
+ * @return none
+ */
+void relay_forward(uint8_t *buffer, const struct dhcpv6_msg *msg, uint16_t msg_length) {
+ struct dhcpv6_option option;
+ option.option_code = htons(OPTION_RELAY_MSG);
+ option.option_length = htons(msg_length);
+ memcpy(buffer, &option, sizeof(struct dhcpv6_option));
+ memcpy(buffer + sizeof(struct dhcpv6_option), msg, msg_length);
+}
+
+/**
+ * @code sock_open(int ifindex, const struct sock_fprog *fprog);
+ *
+ * @brief prepare L2 socket to attach to "udp and port 547" filter
+ *
+ * @param ifindex interface index
+ * @param fprog bpf filter "udp and port 547"
+ *
+ * @return socket descriptor
+ */
+int sock_open(int ifindex, const struct sock_fprog *fprog)
+{
+ if (!ifindex) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ int s = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
+ if (s == -1) {
+ syslog(LOG_ERR, "socket: Failed to create socket\n");
+ return -1;
+ }
+
+ struct sockaddr_ll sll = {
+ .sll_family = AF_PACKET,
+ .sll_protocol = htons(ETH_P_ALL),
+ .sll_ifindex = ifindex
+ };
+
+ if (bind(s, (struct sockaddr *)&sll, sizeof sll) == -1) {
+ syslog(LOG_ERR, "bind: Failed to bind to specified interface\n");
+ (void) close(s);
+ return -1;
+ }
+
+ if (fprog && setsockopt(s, SOL_SOCKET, SO_ATTACH_FILTER, fprog, sizeof *fprog) == -1)
+ {
+ syslog(LOG_ERR, "setsockopt: Failed to attach filter\n");
+ (void) close(s);
+ return -1;
+ }
+
+ return s;
+}
+
+/**
+ * @code prepare_relay_config(relay_config *interface_config, int local_sock, int filter);
+ *
+ * @brief prepare for specified relay interface config: server and link address
+ *
+ * @param interface_config pointer to relay config to be prepared
+ * @param local_sock L3 socket used for relaying messages
+ * @param filter socket attached with filter
+ *
+ * @return none
+ */
+void prepare_relay_config(relay_config *interface_config, int *local_sock, int filter) {
+ struct ifaddrs *ifa, *ifa_tmp;
+ sockaddr_in6 non_link_local;
+ sockaddr_in6 link_local;
+
+ interface_config->local_sock = *local_sock;
+ interface_config->filter = filter;
+
+ for(auto server: interface_config->servers) {
+ sockaddr_in6 tmp;
+ if(inet_pton(AF_INET6, server.c_str(), &tmp.sin6_addr) != 1)
+ {
+ syslog(LOG_WARNING, "inet_pton: Failed to convert IPv6 address\n");
+ }
+ tmp.sin6_family = AF_INET6;
+ tmp.sin6_flowinfo = 0;
+ tmp.sin6_port = htons(RELAY_PORT);
+ tmp.sin6_scope_id = 0;
+ interface_config->servers_sock.push_back(tmp);
+ }
+
+ if (getifaddrs(&ifa) == -1) {
+ syslog(LOG_WARNING, "getifaddrs: Unable to get network interfaces\n");
+ exit(1);
+ }
+
+ ifa_tmp = ifa;
+ while (ifa_tmp) {
+ if (ifa_tmp->ifa_addr->sa_family == AF_INET6) {
+ struct sockaddr_in6 *in6 = (struct sockaddr_in6*) ifa_tmp->ifa_addr;
+ if((strcmp(ifa_tmp->ifa_name, interface_config->interface.c_str()) == 0) && !IN6_IS_ADDR_LINKLOCAL(&in6->sin6_addr)) {
+ non_link_local = *in6;
+ break;
+ }
+ if((strcmp(ifa_tmp->ifa_name, interface_config->interface.c_str()) == 0) && IN6_IS_ADDR_LINKLOCAL(&in6->sin6_addr)) {
+ link_local = *in6;
+ }
+ }
+ ifa_tmp = ifa_tmp->ifa_next;
+ }
+ freeifaddrs(ifa);
+
+ if(!IN6_IS_ADDR_LINKLOCAL(&non_link_local.sin6_addr)) {
+ interface_config->link_address = non_link_local;
+ }
+ else {
+ interface_config->link_address = link_local;
+ }
+}
+
+/**
+ * @code prepare_socket(int *local_sock, int *server_sock, relay_config *config, int index);
+ *
+ * @brief prepare L3 socket for sending
+ *
+ * @param local_sock pointer to socket binded to global address for relaying client message to server and listening for server message
+ * @param server_sock pointer to socket binded to link_local address for relaying server message to client
+ * @param index scope id of interface
+ *
+ * @return none
+ */
+void prepare_socket(int *local_sock, int *server_sock, relay_config *config, int index) {
+ struct ifaddrs *ifa, *ifa_tmp;
+ sockaddr_in6 addr;
+ sockaddr_in6 ll_addr;
+ memset(&addr, 0, sizeof(addr));
+ memset(&ll_addr, 0, sizeof(ll_addr));
+
+ if ((*local_sock = socket(AF_INET6, SOCK_DGRAM, 0)) == -1) {
+ syslog(LOG_ERR, "socket: Failed to create socket\n");
+ }
+
+ if ((*server_sock= socket(AF_INET6, SOCK_DGRAM, 0)) == -1) {
+ syslog(LOG_ERR, "socket: Failed to create socket\n");
+ }
+
+
+ if (getifaddrs(&ifa) == -1) {
+ syslog(LOG_WARNING, "getifaddrs: Unable to get network interfaces\n");
+ exit(1);
+ }
+
+ ifa_tmp = ifa;
+ while (ifa_tmp) {
+ if (ifa_tmp->ifa_addr->sa_family == AF_INET6) {
+ struct sockaddr_in6 *in6 = (struct sockaddr_in6*) ifa_tmp->ifa_addr;
+ if((strcmp(ifa_tmp->ifa_name, config->interface.c_str()) == 0) && !IN6_IS_ADDR_LINKLOCAL(&in6->sin6_addr)) {
+ in6->sin6_family = AF_INET6;
+ in6->sin6_port = htons(RELAY_PORT);
+ addr = *in6;
+ }
+ if((strcmp(ifa_tmp->ifa_name, config->interface.c_str()) == 0) && IN6_IS_ADDR_LINKLOCAL(&in6->sin6_addr)) {
+ in6->sin6_family = AF_INET6;
+ in6->sin6_port = htons(RELAY_PORT);
+ ll_addr = *in6;
+ }
+ }
+ ifa_tmp = ifa_tmp->ifa_next;
+ }
+ freeifaddrs(ifa);
+
+ if (bind(*local_sock, (sockaddr *)&addr, sizeof(addr)) == -1) {
+ syslog(LOG_ERR, "bind: Failed to bind to socket\n");
+ }
+
+ if (bind(*server_sock, (sockaddr *)&ll_addr, sizeof(addr)) == -1) {
+ syslog(LOG_ERR, "bind: Failed to bind to socket\n");
+ }
+}
+
+
+/**
+ * @code relay_client(int sock, const uint8_t *msg, int32_t len, ip6_hdr *ip_hdr, const ether_header *ether_hdr, relay_config *config);
+ *
+ * @brief construct relay-forward message
+ *
+ * @param sock L3 socket for sending data to servers
+ * @param msg pointer to dhcpv6 message header position
+ * @param len size of data received
+ * @param ip_hdr pointer to IPv6 header
+ * @param ether_hdr pointer to Ethernet header
+ * @param config pointer to the relay interface config
+ *
+ * @return none
+ */
+void relay_client(int sock, const uint8_t *msg, int32_t len, const ip6_hdr *ip_hdr, const ether_header *ether_hdr, relay_config *config) {
+ static uint8_t buffer[4096];
+ auto current_buffer_position = buffer;
+ dhcpv6_relay_msg new_message;
+ new_message.msg_type = DHCPv6_MESSAGE_TYPE_RELAY_FORW;
+ memcpy(&new_message.peer_address, &ip_hdr->ip6_src, sizeof(in6_addr));
+ new_message.hop_count = 0;
+
+ memcpy(&new_message.link_address, &config->link_address.sin6_addr, sizeof(in6_addr));
+ memcpy(current_buffer_position, &new_message, sizeof(dhcpv6_relay_msg));
+ current_buffer_position += sizeof(dhcpv6_relay_msg);
+
+ if(config->is_option_79) {
+ linklayer_addr_option option79;
+ option79.link_layer_type = htons(1);
+ option79.option_code = htons(OPTION_CLIENT_LINKLAYER_ADDR);
+ option79.option_length = htons(2 + 6); // link_layer_type field + address
+
+ memcpy(current_buffer_position, &option79, sizeof(linklayer_addr_option));
+ current_buffer_position += sizeof(linklayer_addr_option);
+
+ memcpy(current_buffer_position, ðer_hdr->ether_shost, sizeof(ether_hdr->ether_shost));
+ current_buffer_position += sizeof(ether_hdr->ether_shost);
+ }
+
+ auto dhcp_message_length = len;
+ relay_forward(current_buffer_position, parse_dhcpv6_hdr(msg), dhcp_message_length);
+ current_buffer_position += dhcp_message_length + sizeof(dhcpv6_option);
+
+ for(auto server: config->servers_sock) {
+ send_udp(sock, buffer, server, current_buffer_position - buffer, config, new_message.msg_type);
+ }
+}
+
+/**
+ * @code relay_relay_forw(int sock, const uint8_t *msg, int32_t len, const ip6_hdr *ip_hdr, relay_config *config)
+ *
+ * @brief construct a relay-forward message encapsulated relay-forward message
+ *
+ * @param sock L3 socket for sending data to servers
+ * @param msg pointer to dhcpv6 message header position
+ * @param len size of data received
+ * @param ip_hdr pointer to IPv6 header
+ * @param config pointer to the relay interface config
+ *
+ * @return none
+ */
+void relay_relay_forw(int sock, const uint8_t *msg, int32_t len, const ip6_hdr *ip_hdr, relay_config *config) {
+ static uint8_t buffer[4096];
+ dhcpv6_relay_msg new_message;
+ auto current_buffer_position = buffer;
+ auto dhcp_relay_header = parse_dhcpv6_relay(msg);
+
+ if (dhcp_relay_header->hop_count >= HOP_LIMIT)
+ return;
+
+ new_message.msg_type = DHCPv6_MESSAGE_TYPE_RELAY_FORW;
+ memcpy(&new_message.peer_address, &ip_hdr->ip6_src, sizeof(in6_addr));
+ new_message.hop_count = dhcp_relay_header->hop_count + 1;
+
+ memset(&new_message.link_address, 0, sizeof(in6_addr));
+
+ memcpy(current_buffer_position, &new_message, sizeof(dhcpv6_relay_msg));
+ current_buffer_position += sizeof(dhcpv6_relay_msg);
+
+ auto dhcp_message_length = len;
+ relay_forward(current_buffer_position, parse_dhcpv6_hdr(msg), dhcp_message_length);
+ current_buffer_position += dhcp_message_length + sizeof(dhcpv6_option);
+
+ for(auto server: config->servers_sock) {
+ send_udp(sock, buffer, server, current_buffer_position - buffer, config, new_message.msg_type);
+ }
+}
+
+/**
+ * @code relay_relay_reply(int sock, const uint8_t *msg, int32_t len, relay_config *configs);
+ *
+ * @brief relay and unwrap a relay-reply message
+ *
+ * @param sock L3 socket for sending data to servers
+ * @param msg pointer to dhcpv6 message header position
+ * @param len size of data received
+ * @param config relay interface config
+ *
+ * @return none
+ */
+ void relay_relay_reply(int sock, const uint8_t *msg, int32_t len, relay_config *config) {
+ static uint8_t buffer[4096];
+ uint8_t type = 0;
+ struct sockaddr_in6 target_addr;
+ auto current_buffer_position = buffer;
+ auto current_position = msg;
+ const uint8_t *tmp = NULL;
+ auto dhcp_relay_header = parse_dhcpv6_relay(msg);
+ current_position += sizeof(struct dhcpv6_relay_msg);
+
+ auto position = current_position + sizeof(struct dhcpv6_option);
+ auto dhcpv6msg = parse_dhcpv6_hdr(position);
+
+ while ((current_position - msg) < len) {
+ auto option = parse_dhcpv6_opt(current_position, &tmp);
+ current_position = tmp;
+ if (current_position - msg > len || ntohs(option->option_length) > sizeof(buffer) - (current_buffer_position - buffer)) {
+ break;
+ }
+ switch (ntohs(option->option_code)) {
+ case OPTION_RELAY_MSG:
+ memcpy(current_buffer_position, ((uint8_t *)option) + sizeof(struct dhcpv6_option), ntohs(option->option_length));
+ current_buffer_position += ntohs(option->option_length);
+ type = dhcpv6msg->msg_type;
+ break;
+ default:
+ break;
+ }
+ }
+
+ memcpy(&target_addr.sin6_addr, &dhcp_relay_header->peer_address, sizeof(struct in6_addr));
+ target_addr.sin6_family = AF_INET6;
+ target_addr.sin6_flowinfo = 0;
+ target_addr.sin6_port = htons(CLIENT_PORT);
+ target_addr.sin6_scope_id = if_nametoindex(config->interface.c_str());
+
+ send_udp(sock, buffer, target_addr, current_buffer_position - buffer, config, type);
+}
+
+
+/**
+ * @code callback(evutil_socket_t fd, short event, void *arg);
+ *
+ * @brief callback for libevent that is called everytime data is received at the filter socket
+ *
+ * @param fd filter socket
+ * @param event libevent triggered event
+ * @param arg callback argument provided by user
+ *
+ * @return none
+ */
+void callback(evutil_socket_t fd, short event, void *arg) {
+ struct relay_config *config = (struct relay_config *)(arg);
+ static uint8_t message_buffer[4096];
+ int32_t len = recv(config->filter, message_buffer, 4096, 0);
+ if (len <= 0) {
+ syslog(LOG_WARNING, "recv: Failed to receive data at filter socket: %s\n", strerror(errno));
+ return;
+ }
+
+ char* ptr = (char *)message_buffer;
+ const uint8_t *current_position = (uint8_t *)ptr;
+ const uint8_t *tmp = NULL;
+ const uint8_t *prev = NULL;
+
+ auto ether_header = parse_ether_frame(current_position, &tmp);
+ current_position = tmp;
+
+ auto ip_header = parse_ip6_hdr(current_position, &tmp);
+ current_position = tmp;
+
+ prev = current_position;
+ if (ip_header->ip6_ctlun.ip6_un1.ip6_un1_nxt != IPPROTO_UDP) {
+ const struct ip6_ext *ext_header;
+ do {
+ ext_header = (const struct ip6_ext *)current_position;
+ current_position += ext_header->ip6e_len;
+ if((current_position == prev) || (current_position >= (uint8_t *)ptr + sizeof(message_buffer))) {
+ return;
+ }
+ prev = current_position;
+ }
+ while (ext_header->ip6e_nxt != IPPROTO_UDP);
+ }
+
+ auto udp_header = parse_udp(current_position, &tmp);
+ current_position = tmp;
+
+ auto msg = parse_dhcpv6_hdr(current_position);
+ counters[msg->msg_type]++;
+ std::string counterVlan = counter_table;
+ update_counter(counterVlan.append(config->interface), msg->msg_type);
+
+ switch (msg->msg_type) {
+ case DHCPv6_MESSAGE_TYPE_RELAY_FORW:
+ {
+ relay_relay_forw(config->local_sock, current_position, ntohs(udp_header->len) - sizeof(udphdr), ip_header, config);
+ break;
+ }
+ default:
+ {
+ relay_client(config->local_sock, current_position, ntohs(udp_header->len) - sizeof(udphdr), ip_header, ether_header, config);
+ break;
+ }
+ }
+}
+
+/**
+ * @code void server_callback(evutil_socket_t fd, short event, void *arg);
+ *
+ * @brief callback for libevent that is called everytime data is received at the server socket
+ *
+ * @param fd filter socket
+ * @param event libevent triggered event
+ * @param arg callback argument provided by user
+ *
+ * @return none
+ */
+void server_callback(evutil_socket_t fd, short event, void *arg) {
+ struct relay_config *config = (struct relay_config *)arg;
+ sockaddr_in6 from;
+ socklen_t len = sizeof(from);
+ int32_t data = 0;
+ static uint8_t message_buffer[4096];
+
+ if ((data = recvfrom(config->local_sock, message_buffer, 4096, 0, (sockaddr *)&from, &len)) == -1) {
+ syslog(LOG_WARNING, "recv: Failed to receive data from server\n");
+ }
+
+ auto msg = parse_dhcpv6_hdr(message_buffer);
+
+ counters[msg->msg_type]++;
+ std::string counterVlan = counter_table;
+ update_counter(counterVlan.append(config->interface), msg->msg_type);
+ if (msg->msg_type == DHCPv6_MESSAGE_TYPE_RELAY_REPL) {
+ relay_relay_reply(config->server_sock, message_buffer, data, config);
+ }
+}
+
+/**
+ * @code signal_init();
+ *
+ * @brief initialize DHCPv6 Relay libevent signals
+ */
+int signal_init() {
+ int rv = -1;
+ do {
+ ev_sigint = evsignal_new(base, SIGINT, signal_callback, base);
+ if (ev_sigint == NULL) {
+ syslog(LOG_ERR, "Could not create SIGINT libevent signal\n");
+ break;
+ }
+
+ ev_sigterm = evsignal_new(base, SIGTERM, signal_callback, base);
+ if (ev_sigterm == NULL) {
+ syslog(LOG_ERR, "Could not create SIGTERM libevent signal\n");
+ break;
+ }
+ rv = 0;
+ } while(0);
+ return rv;
+}
+
+/**
+ * @code signal_start();
+ *
+ * @brief start DHCPv6 Relay libevent base and add signals
+ */
+int signal_start()
+{
+ int rv = -1;
+ do
+ {
+ if (evsignal_add(ev_sigint, NULL) != 0) {
+ syslog(LOG_ERR, "Could not add SIGINT libevent signal\n");
+ break;
+ }
+
+ if (evsignal_add(ev_sigterm, NULL) != 0) {
+ syslog(LOG_ERR, "Could not add SIGTERM libevent signal\n");
+ break;
+ }
+
+ if (event_base_dispatch(base) != 0) {
+ syslog(LOG_ERR, "Could not start libevent dispatching loop\n");
+ }
+
+ rv = 0;
+ } while (0);
+
+ return rv;
+}
+
+/**
+ * @code signal_callback(fd, event, arg);
+ *
+ * @brief signal handler for dhcp6relay. Initiate shutdown when signal is caught
+ *
+ * @param fd libevent socket
+ * @param event event triggered
+ * @param arg pointer to libevent base
+ *
+ * @return none
+ */
+void signal_callback(evutil_socket_t fd, short event, void *arg)
+{
+ syslog(LOG_ALERT, "Received signal: '%s'\n", strsignal(fd));
+ if ((fd == SIGTERM) || (fd == SIGINT)) {
+ dhcp6relay_stop();
+ }
+}
+
+/**
+ * @code dhcp6relay_stop();
+ *
+ * @brief stop DHCPv6 Relay libevent loop upon signal
+ */
+void dhcp6relay_stop()
+{
+ event_base_loopexit(base, NULL);
+}
+
+/**
+ * @code loop_relay(std::vector *vlans);
+ *
+ * @brief main loop: configure sockets, create libevent base, start server listener thread
+ *
+ * @param vlans list of vlans retrieved from config_db
+ */
+void loop_relay(std::vector *vlans) {
+ std::vector sockets;
+ base = event_base_new();
+ if(base == NULL) {
+ syslog(LOG_ERR, "libevent: Failed to create base\n");
+ }
+
+ for(relay_config &vlan : *vlans) {
+ relay_config *config = &vlan;
+ int filter = 0;
+ int local_sock = 0;
+ int server_sock = 0;
+ int index = if_nametoindex(config->interface.c_str());
+
+ std::string counterVlan = counter_table;
+ initialize_counter(counterVlan.append(config->interface));
+
+ filter = sock_open(index, ðer_relay_fprog);
+ prepare_socket(&local_sock, &server_sock, config, index);
+
+ config->local_sock = local_sock;
+ config->server_sock = server_sock;
+
+ sockets.push_back(filter);
+ sockets.push_back(local_sock);
+ sockets.push_back(server_sock);
+
+ prepare_relay_config(config, &local_sock, filter);
+
+ evutil_make_listen_socket_reuseable(filter);
+ evutil_make_socket_nonblocking(filter);
+
+ evutil_make_listen_socket_reuseable(local_sock);
+ evutil_make_socket_nonblocking(local_sock);
+
+ listen_event = event_new(base, filter, EV_READ|EV_PERSIST, callback, config);
+ server_listen_event = event_new(base, local_sock, EV_READ|EV_PERSIST, server_callback, config);
+ if (listen_event == NULL || server_listen_event == NULL) {
+ syslog(LOG_ERR, "libevent: Failed to create libevent\n");
+ }
+
+ event_add(listen_event, NULL);
+ event_add(server_listen_event, NULL);
+ }
+
+ if((signal_init() == 0) && signal_start() == 0) {
+ shutdown();
+ for(std::size_t i = 0; i
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+
+#define PACKED __attribute__ ((packed))
+
+#define RELAY_PORT 547
+#define CLIENT_PORT 546
+#define HOP_LIMIT 8 //HOP_LIMIT reduced from 32 to 8 as stated in RFC8415
+
+#define lengthof(A) (sizeof (A) / sizeof (A)[0])
+
+#define OPTION_RELAY_MSG 9
+#define OPTION_CLIENT_LINKLAYER_ADDR 79
+
+/* DHCPv6 message types */
+typedef enum
+{
+ DHCPv6_MESSAGE_TYPE_UNKNOWN = 0,
+ DHCPv6_MESSAGE_TYPE_SOLICIT = 1,
+ DHCPv6_MESSAGE_TYPE_ADVERTISE = 2,
+ DHCPv6_MESSAGE_TYPE_REQUEST = 3,
+ DHCPv6_MESSAGE_TYPE_CONFIRM = 4,
+ DHCPv6_MESSAGE_TYPE_RENEW = 5,
+ DHCPv6_MESSAGE_TYPE_REBIND = 6,
+ DHCPv6_MESSAGE_TYPE_REPLY = 7,
+ DHCPv6_MESSAGE_TYPE_RELEASE = 8,
+ DHCPv6_MESSAGE_TYPE_DECLINE = 9,
+ DHCPv6_MESSAGE_TYPE_RELAY_FORW = 12,
+ DHCPv6_MESSAGE_TYPE_RELAY_REPL = 13,
+
+ DHCPv6_MESSAGE_TYPE_COUNT
+} dhcp_message_type_t;
+
+struct relay_config {
+ int local_sock;
+ int server_sock;
+ int filter;
+ sockaddr_in6 link_address;
+ std::string interface;
+ std::vector servers;
+ std::vector servers_sock;
+ bool is_option_79;
+};
+
+
+/* DHCPv6 messages and options */
+
+struct dhcpv6_msg {
+ uint8_t msg_type;
+};
+
+struct PACKED dhcpv6_relay_msg {
+ uint8_t msg_type;
+ uint8_t hop_count;
+ struct in6_addr link_address;
+ struct in6_addr peer_address;
+};
+
+
+struct dhcpv6_option {
+ uint16_t option_code;
+ uint16_t option_length;
+};
+
+struct linklayer_addr_option {
+ uint16_t option_code;
+ uint16_t option_length;
+ uint16_t link_layer_type;
+};
+
+/**
+ * @code sock_open(int ifindex, const struct sock_fprog *fprog);
+ *
+ * @brief prepare L2 socket to attach to "udp and port 547" filter
+ *
+ * @param ifindex interface index
+ * @param fprog bpf filter "udp and port 547"
+ *
+ * @return socket descriptor
+ */
+int sock_open(int ifindex, const struct sock_fprog *fprog);
+
+/**
+ * @code prepare_socket(int *local_sock, int *server_sock, relay_config *config, int index);
+ *
+ * @brief prepare L3 socket for sending
+ *
+ * @param local_sock pointer to socket binded to global address for relaying client message to server and listening for server message
+ * @param server_sock pointer to socket binded to link_local address for relaying server message to client
+ * @param index scope id of interface
+ *
+ * @return none
+ */
+void prepare_socket(int *local_sock, int *server_sock, relay_config *config, int index);
+
+/**
+ * @code prepare_relay_config(relay_config *interface_config, int *local_sock, int filter);
+ *
+ * @brief prepare for specified relay interface config: server and link address
+ *
+ * @param interface_config pointer to relay config to be prepared
+ * @param local_sock L3 socket used for relaying messages
+ * @param filter socket attached with filter
+ *
+ * @return none
+ */
+void prepare_relay_config(relay_config *interface_config, int *local_sock, int filter);
+
+/**
+ * @code relay_forward(uint8_t *buffer, const struct dhcpv6_msg *msg, uint16_t msg_length);
+ *
+ * @brief embed the DHCPv6 message received into DHCPv6 relay forward message
+ *
+ * @param buffer pointer to buffer
+ * @param msg pointer to parsed DHCPv6 message
+ * @param msg_length length of DHCPv6 message
+ *
+ * @return none
+ */
+void relay_forward(uint8_t *buffer, const struct dhcpv6_msg *msg, uint16_t msg_length);
+
+/**
+ * @code relay_client(int sock, const uint8_t *msg, int32_t len, ip6_hdr *ip_hdr, const ether_header *ether_hdr, relay_config *config);
+ *
+ * @brief construct relay-forward message
+ *
+ * @param sock L3 socket for sending data to servers
+ * @param msg pointer to dhcpv6 message header position
+ * @param len size of data received
+ * @param ip_hdr pointer to IPv6 header
+ * @param ether_hdr pointer to Ethernet header
+ * @param config pointer to the relay interface config
+ *
+ * @return none
+ */
+void relay_client(int sock, const uint8_t *msg, int32_t len, const ip6_hdr *ip_hdr, const ether_header *ether_hdr, relay_config *config);
+
+/**
+ * @code relay_relay_forw(int sock, const uint8_t *msg, int32_t len, const ip6_hdr *ip_hdr, relay_config *config)
+ *
+ * @brief construct a relay-forward message encapsulated relay-forward message
+ *
+ * @param sock L3 socket for sending data to servers
+ * @param msg pointer to dhcpv6 message header position
+ * @param len size of data received
+ * @param ip_hdr pointer to IPv6 header
+ * @param config pointer to the relay interface config
+ *
+ * @return none
+ */
+void relay_relay_forw(int sock, const uint8_t *msg, int32_t len, const ip6_hdr *ip_hdr, relay_config *config);
+
+/**
+ * @code relay_relay_reply(int sock, const uint8_t *msg, int32_t len, relay_config *configs);
+ *
+ * @brief relay and unwrap a relay-reply message
+ *
+ * @param sock L3 socket for sending data to servers
+ * @param msg pointer to dhcpv6 message header position
+ * @param len size of data received
+ * @param config relay interface config
+ *
+ * @return none
+ */
+void relay_relay_reply(int sock, const uint8_t *msg, int32_t len, relay_config *configs);
+
+/**
+ * @code loop_relay(std::vector *vlans);
+ *
+ * @brief main loop: configure sockets, create libevent base, start server listener thread
+ *
+ * @param vlans list of vlans retrieved from config_db
+ */
+void loop_relay(std::vector *vlans);
+
+/**
+ * @code signal_init();
+ *
+ * @brief initialize DHCPv6 Relay libevent signals
+ */
+int signal_init();
+
+/**
+ * @code signal_start();
+ *
+ * @brief start DHCPv6 Relay libevent base and add signals
+ */
+int signal_start();
+
+/**
+ * @code dhcp6relay_stop();
+ *
+ * @brief stop DHCPv6 Relay libevent loop upon signal
+ */
+void dhcp6relay_stop();
+
+/**
+ * @code signal_callback(fd, event, arg);
+ *
+ * @brief signal handler for dhcp6relay. Initiate shutdown when signal is caught
+ *
+ * @param fd libevent socket
+ * @param event event triggered
+ * @param arg pointer to libevent base
+ *
+ * @return none
+ */
+void signal_callback(evutil_socket_t fd, short event, void *arg);
+
+/**
+ * @code shutdown();
+ *
+ * @brief free signals and terminate threads
+ */
+void shutdown();
+
+/**
+ * @code void initialize_counter(std::string counterVlan)
+ *
+ * @brief initialize the counter by each Vlan
+ *
+ * @param counterVlan counter table with interface name
+ *
+ * @return none
+ */
+void initialize_counter(std::string counterVlan);
+
+/**
+ * @code void update_counter(std::string CounterVlan, uint8_t msg_type);
+ *
+ * @brief update the counter in state_db with count of each DHCPv6 message type
+ *
+ * @param counterVlan counter table with interface name
+ * @param msg_type dhcpv6 message type to be updated in counter
+ *
+ * @return none
+ */
+void update_counter(std::string counterVlan, uint8_t msg_type);
+
+/* Helper functions */
+
+/**
+ * @code std::string toString(uint16_t count);
+ *
+ * @brief convert uint16_t to string
+ *
+ * @param count count of messages in counter
+ *
+ * @return count in string
+ */
+std::string toString(uint16_t count);
+
+/**
+ * @code const struct ether_header *parse_ether_frame(const uint8_t *buffer, const uint8_t **out_end);
+ *
+ * @brief parse through ethernet frame
+ *
+ * @param *buffer message buffer
+ * @param **out_end pointer
+ *
+ * @return ether_header end of ethernet header position
+ */
+const struct ether_header *parse_ether_frame(const uint8_t *buffer, const uint8_t **out_end);
+
+/**
+ * @code const struct ip6_hdr *parse_ip6_hdr(const uint8_t *buffer, const uint8_t **out_end);
+ *
+ * @brief parse through ipv6 header
+ *
+ * @param *buffer message buffer
+ * @param **out_end pointer
+ *
+ * @return ip6_hdr end of ipv6 header position
+ */
+const struct ip6_hdr *parse_ip6_hdr(const uint8_t *buffer, const uint8_t **out_end);
+
+/**
+ * @code const struct udphdr *parse_udp(const uint8_t *buffer, const uint8_t **out_end);
+ *
+ * @brief parse through udp header
+ *
+ * @param *buffer message buffer
+ * @param **out_end pointer
+ *
+ * @return udphdr end of udp header position
+ */
+const struct udphdr *parse_udp(const uint8_t *buffer, const uint8_t **out_end);
+
+/**
+ * @code const struct dhcpv6_msg *parse_dhcpv6_hdr(const uint8_t *buffer);
+ *
+ * @brief parse through dhcpv6 header
+ *
+ * @param *buffer message buffer
+ * @param **out_end pointer
+ *
+ * @return dhcpv6_msg end of dhcpv6 header position
+ */
+const struct dhcpv6_msg *parse_dhcpv6_hdr(const uint8_t *buffer);
+
+/**
+ * @code const struct dhcpv6_relay_msg *parse_dhcpv6_relay(const uint8_t *buffer);
+ *
+ * @brief parse through dhcpv6 relay message
+ *
+ * @param *buffer message buffer
+ * @param **out_end pointer
+ *
+ * @return dhcpv6_relay_msg start of dhcpv6 relay message or end of dhcpv6 message type position
+ */
+const struct dhcpv6_relay_msg *parse_dhcpv6_relay(const uint8_t *buffer);
+
+/**
+ * @code const struct dhcpv6_option *parse_dhcpv6_opt(const uint8_t *buffer, const uint8_t **out_end);
+ *
+ * @brief parse through dhcpv6 option
+ *
+ * @param *buffer message buffer
+ * @param **out_end pointer
+ *
+ * @return dhcpv6_option end of dhcpv6 message option
+ */
+const struct dhcpv6_option *parse_dhcpv6_opt(const uint8_t *buffer, const uint8_t **out_end);
+
+/**
+ * @code void send_udp(int sock, uint8_t *buffer, struct sockaddr_in6 target, uint32_t n, relay_config *config, uint8_t msg_type);
+ *
+ * @brief send udp packet
+ *
+ * @param *buffer message buffer
+ * @param sockaddr_in6 target target socket
+ * @param n length of message
+ * @param relay_config *config pointer to relay_config
+ * @param uint8_t msg_type message type of dhcpv6 option of relayed message
+ *
+ * @return dhcpv6_option end of dhcpv6 message option
+ */
+void send_udp(int sock, uint8_t *buffer, struct sockaddr_in6 target, uint32_t n, relay_config *config, uint8_t msg_type);
+
diff --git a/src/dhcp6relay/src/subdir.mk b/src/dhcp6relay/src/subdir.mk
new file mode 100644
index 000000000000..c6e784ef5504
--- /dev/null
+++ b/src/dhcp6relay/src/subdir.mk
@@ -0,0 +1,23 @@
+CC := g++
+
+C_SRCS += \
+../src/relay.c \
+../src/configInterface.c \
+../src/main.c
+
+OBJS += \
+./src/relay.o \
+./src/configInterface.o \
+./src/main.o
+
+C_DEPS += \
+./src/relay.d \
+./src/configInterface.d \
+./src/main.d
+
+src/%.o: src/%.cpp
+ @echo 'Building file: $<'
+ @echo 'Invoking: GCC C++ Compiler'
+ $(CC) -D__FILENAME__="$(subst src/,,$<)" $(CFLAGS) -c -fmessage-length=0 -MMD -MP -MF"$(@:%.o=%.d)" -MT"$(@)" -o "$@" "$<"
+\ @echo 'Finished building: $<'
+ @echo ' '
diff --git a/src/sonic-config-engine/minigraph.py b/src/sonic-config-engine/minigraph.py
index 836149bcbfd0..9ad536ad7cae 100644
--- a/src/sonic-config-engine/minigraph.py
+++ b/src/sonic-config-engine/minigraph.py
@@ -355,6 +355,7 @@ def parse_dpg(dpg, hname):
vlanintfs = child.find(str(QName(ns, "VlanInterfaces")))
vlans = {}
vlan_members = {}
+ dhcp_relay_table = {}
intf_vlan_mbr = defaultdict(list)
for vintf in vlanintfs.findall(str(QName(ns, "VlanInterface"))):
vlanid = vintf.find(str(QName(ns, "VlanID"))).text
@@ -376,6 +377,7 @@ def parse_dpg(dpg, hname):
vlan_members[(sonic_vlan_member_name, vmbr_list[i])] = {'tagging_mode': 'untagged'}
vlan_attributes = {'vlanid': vlanid, 'members': vmbr_list }
+ dhcp_attributes = {}
# If this VLAN requires a DHCP relay agent, it will contain a element
# containing a list of DHCP server IPs
@@ -390,14 +392,17 @@ def parse_dpg(dpg, hname):
vintfdhcpservers = vintf_node.text
vdhcpserver_list = vintfdhcpservers.split(';')
vlan_attributes['dhcpv6_servers'] = vdhcpserver_list
+ dhcp_attributes['dhcpv6_servers'] = vdhcpserver_list
sonic_vlan_name = "Vlan%s" % vlanid
if sonic_vlan_name != vintfname:
vlan_attributes['alias'] = vintfname
vlans[sonic_vlan_name] = vlan_attributes
+ dhcp_relay_table[sonic_vlan_name] = dhcp_attributes
+ '''
dhcp = child.find(str(QName(ns, "Dhcp")))
- dhcp_table = {}
+ dhcp_relay_table = {}
if dhcp is not None:
for vintf in dhcp.findall(str(QName(ns, "VlanInterface"))):
@@ -417,7 +422,8 @@ def parse_dpg(dpg, hname):
elif option_linklayer_addr is not None and option_linklayer_addr.text == "false":
dhcp_attributes['dhcpv6_option|rfc6939_support'] = "false"
- dhcp_table[vintfname] = dhcp_attributes
+ dhcp_relay_table[vintfname] = dhcp_attributes
+ '''
acls = {}
for aclintf in aclintfs.findall(str(QName(ns, "AclInterface"))):
@@ -519,7 +525,7 @@ def parse_dpg(dpg, hname):
except:
print >> sys.stderr, "Warning: Ignoring Control Plane ACL %s without type" % aclname
- return intfs, lo_intfs, mvrf, mgmt_intf, vlans, vlan_members, dhcp_table, pcs, pc_members, acls, vni
+ return intfs, lo_intfs, mvrf, mgmt_intf, vlans, vlan_members, dhcp_relay_table, pcs, pc_members, acls, vni
return None, None, None, None, None, None, None, None, None, None
def parse_host_loopback(dpg, hname):
@@ -1008,7 +1014,7 @@ def parse_xml(filename, platform=None, port_config_file=None, asic_name=None):
for child in root:
if asic_name is None:
if child.tag == str(QName(ns, "DpgDec")):
- (intfs, lo_intfs, mvrf, mgmt_intf, vlans, vlan_members, dhcp_table, pcs, pc_members, acls, vni) = parse_dpg(child, hostname)
+ (intfs, lo_intfs, mvrf, mgmt_intf, vlans, vlan_members, dhcp_relay_table, pcs, pc_members, acls, vni) = parse_dpg(child, hostname)
elif child.tag == str(QName(ns, "CpgDec")):
(bgp_sessions, bgp_internal_sessions, bgp_asn, bgp_peers_with_range, bgp_monitors) = parse_cpg(child, hostname)
elif child.tag == str(QName(ns, "PngDec")):
@@ -1023,7 +1029,7 @@ def parse_xml(filename, platform=None, port_config_file=None, asic_name=None):
(port_speeds_default, port_descriptions) = parse_deviceinfo(child, hwsku)
else:
if child.tag == str(QName(ns, "DpgDec")):
- (intfs, lo_intfs, mvrf, mgmt_intf, vlans, vlan_members, dhcp_table, pcs, pc_members, acls, vni) = parse_dpg(child, asic_name)
+ (intfs, lo_intfs, mvrf, mgmt_intf, vlans, vlan_members, dhcp_relay_table, pcs, pc_members, acls, vni) = parse_dpg(child, asic_name)
host_lo_intfs = parse_host_loopback(child, hostname)
elif child.tag == str(QName(ns, "CpgDec")):
(bgp_sessions, bgp_internal_sessions, bgp_asn, bgp_peers_with_range, bgp_monitors) = parse_cpg(child, asic_name, local_devices)
@@ -1277,7 +1283,7 @@ def parse_xml(filename, platform=None, port_config_file=None, asic_name=None):
results['SYSLOG_SERVER'] = dict((item, {}) for item in syslog_servers)
results['DHCP_SERVER'] = dict((item, {}) for item in dhcp_servers)
results['DHCPv6_SERVER'] = dict((item, {}) for item in dhcpv6_servers)
- results['DHCP'] = dhcp_table
+ results['DHCP_RELAY'] = dhcp_relay_table
results['NTP_SERVER'] = dict((item, {}) for item in ntp_servers)
results['TACPLUS_SERVER'] = dict((item, {'priority': '1', 'tcp_port': '49'}) for item in tacacs_servers)
results['ACL_TABLE'] = filter_acl_table_bindings(acls, neighbors, pcs, sub_role)
diff --git a/src/sonic-config-engine/tests/sample_output/docker-dhcp-relay.supervisord.conf b/src/sonic-config-engine/tests/sample_output/docker-dhcp-relay.supervisord.conf
index 47bdee4b00bc..27c409f45c14 100644
--- a/src/sonic-config-engine/tests/sample_output/docker-dhcp-relay.supervisord.conf
+++ b/src/sonic-config-engine/tests/sample_output/docker-dhcp-relay.supervisord.conf
@@ -39,10 +39,11 @@ stderr_logfile=syslog
dependent_startup=true
dependent_startup_wait_for=rsyslogd:running
-[group:isc-dhcp-relay]
-programs=isc-dhcp-relay-Vlan1000
+[group:dhcp-relay]
+programs=isc-dhcpv4-relay-Vlan1000,dhcp6relay
-[program:isc-dhcp-relay-Vlan1000]
+
+[program:isc-dhcpv4-relay-Vlan1000]
command=/usr/sbin/dhcrelay -d -m discard -a %%h:%%p %%P --name-alias-map-file /tmp/port-name-alias-map.txt -id Vlan1000 -iu Vlan2000 -iu PortChannel02 -iu PortChannel03 -iu PortChannel04 -iu PortChannel01 192.0.0.1 192.0.0.2
priority=3
autostart=false
@@ -53,6 +54,15 @@ dependent_startup=true
dependent_startup_wait_for=start:exited
+[program:dhcp6relay]
+command=/usr/sbin/dhcp6relay
+
+priority=3
+autostart=false
+autorestart=false
+stdout_logfile=syslog
+stderr_logfile=syslog
+
[group:dhcpmon]
programs=dhcpmon-Vlan1000
@@ -64,7 +74,6 @@ autorestart=false
stdout_logfile=syslog
stderr_logfile=syslog
dependent_startup=true
-dependent_startup_wait_for=isc-dhcp-relay-Vlan1000:running
-
+dependent_startup_wait_for=isc-dhcpv4-relay-Vlan1000:running
diff --git a/src/sonic-config-engine/tests/sample_output/wait_for_intf.sh b/src/sonic-config-engine/tests/sample_output/wait_for_intf.sh
index 4852f6167bad..8ba15b1c8355 100644
--- a/src/sonic-config-engine/tests/sample_output/wait_for_intf.sh
+++ b/src/sonic-config-engine/tests/sample_output/wait_for_intf.sh
@@ -30,3 +30,7 @@ wait_until_iface_ready PortChannel03 10.0.0.60/31
wait_until_iface_ready PortChannel04 10.0.0.62/31
wait_until_iface_ready PortChannel01 10.0.0.56/31
+# Wait 10 seconds for the rest of interfaces to get added/populated.
+# dhcrelay listens on each of the interfaces (in addition to the port
+# channels and vlan interfaces)
+sleep 10
diff --git a/src/sonic-config-engine/tests/simple-sample-graph-case.xml b/src/sonic-config-engine/tests/simple-sample-graph-case.xml
index 48460e2c6da8..b4e58ddaf724 100644
--- a/src/sonic-config-engine/tests/simple-sample-graph-case.xml
+++ b/src/sonic-config-engine/tests/simple-sample-graph-case.xml
@@ -131,23 +131,21 @@
ab1
fortyGigE0/8
192.0.0.1;192.0.0.2
+ fc02:2000::1;fc02:2000::2
1000
1000
192.168.0.0/27
-
-
-
- Vlan1000
- fc02:2000::1;fc02:2000::2
- true
-
- Vlan2000
+ ab2
+ fortyGigE0/4
+ 192.0.0.3;192.0.0.4
fc02:2000::3;fc02:2000::4
- false
+ 2000
+ 2000
+ 192.168.0.0/27
-
+
diff --git a/src/sonic-config-engine/tests/test_cfggen.py b/src/sonic-config-engine/tests/test_cfggen.py
index 4782c7fc2814..5bbcb4cafa03 100644
--- a/src/sonic-config-engine/tests/test_cfggen.py
+++ b/src/sonic-config-engine/tests/test_cfggen.py
@@ -619,9 +619,9 @@ def test_show_run_interfaces(self):
self.assertEqual(output, '')
def test_minigraph_dhcp(self):
- argument = '-m "' + self.sample_graph_simple_case + '" -p "' + self.port_config + '" -v DHCP'
+ argument = '-m "' + self.sample_graph_simple_case + '" -p "' + self.port_config + '" -v DHCP_RELAY'
output = self.run_script(argument)
self.assertEqual(
output.strip(),
- "{'Vlan1000': {'dhcpv6_option|rfc6939_support': 'true', 'dhcpv6_servers': ['fc02:2000::1', 'fc02:2000::2']}, 'Vlan2000': {'dhcpv6_option|rfc6939_support': 'false', 'dhcpv6_servers': ['fc02:2000::3', 'fc02:2000::4']}}"
+ "{'Vlan1000': {'dhcpv6_servers': ['fc02:2000::1', 'fc02:2000::2']}, 'Vlan2000': {'dhcpv6_servers': ['fc02:2000::3', 'fc02:2000::4']}}"
)
\ No newline at end of file
diff --git a/src/sonic-config-engine/tests/test_minigraph_case.py b/src/sonic-config-engine/tests/test_minigraph_case.py
index 85114396fce7..8c4d638fa711 100644
--- a/src/sonic-config-engine/tests/test_minigraph_case.py
+++ b/src/sonic-config-engine/tests/test_minigraph_case.py
@@ -82,15 +82,39 @@ def test_minigraph_interfaces(self):
def test_minigraph_vlans(self):
argument = '-m "' + self.sample_graph + '" -p "' + self.port_config + '" -v VLAN'
output = self.run_script(argument)
+ expected = {
+ u'Vlan1000': {
+ u'alias': 'ab1',
+ u'dhcp_servers': [u'192.0.0.1', u'192.0.0.2'],
+ u'dhcpv6_servers': [u'fc02:2000::1', u'fc02:2000::2'],
+ u'vlanid': u'1000',
+ u'members': [u'Ethernet8']
+ },
+ 'Vlan2000': {
+ u'alias': 'ab2',
+ u'dhcp_servers': ['192.0.0.3', '192.0.0.4'],
+ u'members': ['Ethernet4'],
+ u'dhcpv6_servers': [u'fc02:2000::3', u'fc02:2000::4'],
+ u'vlanid': '2000'
+ }
+ }
+
self.assertEqual(
utils.to_dict(output.strip()),
- utils.to_dict("{'Vlan1000': {'alias': 'ab1', 'dhcp_servers': ['192.0.0.1', '192.0.0.2'], 'vlanid': '1000', 'members': ['Ethernet8'] }}")
+ expected
)
def test_minigraph_vlan_members(self):
argument = '-m "' + self.sample_graph + '" -p "' + self.port_config + '" -v VLAN_MEMBER'
output = self.run_script(argument)
- self.assertEqual(output.strip(), "{('Vlan1000', 'Ethernet8'): {'tagging_mode': 'untagged'}}")
+ expected = {
+ 'Vlan1000|Ethernet8': {'tagging_mode': 'untagged'},
+ 'Vlan2000|Ethernet4': {'tagging_mode': 'untagged'}
+ }
+ self.assertEqual(
+ utils.to_dict(output.strip()),
+ expected
+ )
def test_minigraph_vlan_interfaces(self):
argument = '-m "' + self.sample_graph + '" -p "' + self.port_config + '" -v "VLAN_INTERFACE.keys()"'
@@ -192,25 +216,23 @@ def test_parse_device_desc_xml_mgmt_interface(self):
self.assertTrue(ipaddress.IPAddress('fc00:1::1') == mgmt_intf[('eth0', 'FC00:1::32/64')]['gwaddr'])
def test_dhcp_table(self):
- argument = '-m "' + self.sample_graph + '" -p "' + self.port_config + '" -v "DHCP"'
+ argument = '-m "' + self.sample_graph + '" -p "' + self.port_config + '" -v "DHCP_RELAY"'
expected = {
- 'Vlan1000': {
- 'dhcpv6_servers': [
- "fc02:2000::1",
- "fc02:2000::2"
- ],
- 'dhcpv6_option|rfc6939_support': 'true'
- },
- 'Vlan2000': {
- 'dhcpv6_servers': [
- "fc02:2000::3",
- "fc02:2000::4"
- ],
- 'dhcpv6_option|rfc6939_support': 'false'
- }
+ 'Vlan1000': {
+ 'dhcpv6_servers': [
+ "fc02:2000::1",
+ "fc02:2000::2"
+ ]
+ },
+ 'Vlan2000': {
+ 'dhcpv6_servers': [
+ "fc02:2000::3",
+ "fc02:2000::4"
+ ]
+ }
}
output = self.run_script(argument)
self.assertEqual(
- output.strip(),
- "{'Vlan1000': {'dhcpv6_option|rfc6939_support': 'true', 'dhcpv6_servers': ['fc02:2000::1', 'fc02:2000::2']}, 'Vlan2000': {'dhcpv6_option|rfc6939_support': 'false', 'dhcpv6_servers': ['fc02:2000::3', 'fc02:2000::4']}}"
+ utils.to_dict(output.strip()),
+ expected
)
\ No newline at end of file
diff --git a/src/sonic-dhcp-relay b/src/sonic-dhcp-relay
new file mode 160000
index 000000000000..e2cd5851ddd9
--- /dev/null
+++ b/src/sonic-dhcp-relay
@@ -0,0 +1 @@
+Subproject commit e2cd5851ddd9b6496b59b72e75aaba8e4d7f284d
From a6c00c9417a37e7013c5fda2bae26abefe5aaecc Mon Sep 17 00:00:00 2001
From: kellyyeh
Date: Fri, 16 Sep 2022 22:52:11 +0000
Subject: [PATCH 4/7] Add dhcprelay submodule
---
.gitmodules | 4 +
.../docker-dhcp-relay/dhcp-relay.monitors.j2 | 15 +-
rules/dhcp6relay.mk | 12 -
rules/dhcprelay.mk | 12 +
rules/docker-dhcp-relay.mk | 4 +-
sonic-dhcp-relay | 1 -
src/dhcp6relay/.gitignore | 5 -
src/dhcp6relay/Makefile | 42 -
src/dhcp6relay/debian/changelog | 5 -
src/dhcp6relay/debian/compat | 1 -
src/dhcp6relay/debian/control | 27 -
src/dhcp6relay/debian/rules | 12 -
src/dhcp6relay/src/configInterface.cpp | 151 ----
src/dhcp6relay/src/configInterface.d | 44 -
src/dhcp6relay/src/configInterface.h | 75 --
src/dhcp6relay/src/main.cpp | 17 -
src/dhcp6relay/src/main.d | 44 -
src/dhcp6relay/src/relay.cpp | 816 ------------------
src/dhcp6relay/src/relay.d | 51 --
src/dhcp6relay/src/relay.h | 349 --------
src/dhcp6relay/src/subdir.mk | 23 -
src/dhcprelay | 1 +
src/sonic-config-engine/minigraph.py | 27 +-
.../tests/test_minigraph_case.py | 40 +-
src/sonic-dhcp-relay | 1 -
25 files changed, 46 insertions(+), 1733 deletions(-)
delete mode 100644 rules/dhcp6relay.mk
create mode 100644 rules/dhcprelay.mk
delete mode 160000 sonic-dhcp-relay
delete mode 100644 src/dhcp6relay/.gitignore
delete mode 100644 src/dhcp6relay/Makefile
delete mode 100644 src/dhcp6relay/debian/changelog
delete mode 100644 src/dhcp6relay/debian/compat
delete mode 100644 src/dhcp6relay/debian/control
delete mode 100755 src/dhcp6relay/debian/rules
delete mode 100644 src/dhcp6relay/src/configInterface.cpp
delete mode 100644 src/dhcp6relay/src/configInterface.d
delete mode 100644 src/dhcp6relay/src/configInterface.h
delete mode 100644 src/dhcp6relay/src/main.cpp
delete mode 100644 src/dhcp6relay/src/main.d
delete mode 100644 src/dhcp6relay/src/relay.cpp
delete mode 100644 src/dhcp6relay/src/relay.d
delete mode 100644 src/dhcp6relay/src/relay.h
delete mode 100644 src/dhcp6relay/src/subdir.mk
create mode 160000 src/dhcprelay
delete mode 160000 src/sonic-dhcp-relay
diff --git a/.gitmodules b/.gitmodules
index 82e364085a88..0ade5f29a954 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -83,3 +83,7 @@
[submodule "src/sonic-ztp"]
path = src/sonic-ztp
url = https://github.com/Azure/sonic-ztp
+[submodule "src/dhcprelay"]
+ path = src/dhcprelay
+ url = https://github.com/sonic-net/sonic-dhcp-relay.git
+ branch = 201911
diff --git a/dockers/docker-dhcp-relay/dhcp-relay.monitors.j2 b/dockers/docker-dhcp-relay/dhcp-relay.monitors.j2
index 0928bac22d4d..4c6438fc99f2 100644
--- a/dockers/docker-dhcp-relay/dhcp-relay.monitors.j2
+++ b/dockers/docker-dhcp-relay/dhcp-relay.monitors.j2
@@ -6,9 +6,6 @@ programs=
{% if VLAN and vlan_name in VLAN and 'dhcp_servers' in VLAN[vlan_name] and VLAN[vlan_name]['dhcp_servers']|length > 0 %}
{% set _dummy = monitor_instance.update({'flag': True}) %}
{%- endif %}
-{% if DHCP_RELAY and vlan_name in DHCP_RELAY and DHCP_RELAY[vlan_name]['dhcpv6_servers']|length > 0 %}
-{% set _dummy = monitor_instance.update({'flag': True}) %}
-{%- endif %}
{% if monitor_instance.flag %}
{% if add_preceding_comma.flag %},{% endif %}
{% set _dummy = add_preceding_comma.update({'flag': True}) %}
@@ -20,7 +17,6 @@ dhcpmon-{{ vlan_name }}
{# Create a program entry for each DHCP MONitor instance #}
{% set relay_for_ipv4 = { 'flag': False } %}
-{% set relay_for_ipv6 = { 'flag': False } %}
{% for vlan_name in VLAN_INTERFACE %}
{# Check DHCPv4 agents #}
{% if VLAN and vlan_name in VLAN and 'dhcp_servers' in VLAN[vlan_name] and VLAN[vlan_name]['dhcp_servers']|length > 0 %}
@@ -30,15 +26,7 @@ dhcpmon-{{ vlan_name }}
{% endif %}
{% endfor %}
{% endif %}
-{# Check DHCPv6 agents #}
-{% if DHCP_RELAY and vlan_name in DHCP_RELAY and DHCP_RELAY[vlan_name]['dhcpv6_servers']|length > 0 %}
-{% for dhcpv6_server in VLAN[vlan_name]['dhcpv6_servers'] %}
-{% if dhcpv6_server | ipv6 %}
-{% set _dummy = relay_for_ipv6.update({'flag': True}) %}
-{% endif %}
-{% endfor %}
-{% endif %}
-{% if relay_for_ipv4.flag or relay_for_ipv6.flag %}
+{% if relay_for_ipv4.flag %}
[program:dhcpmon-{{ vlan_name }}]
{# We treat this VLAN as a downstream interface (-id), as we only want to listen for requests #}
command=/usr/sbin/dhcpmon -id {{ vlan_name }}
@@ -71,6 +59,5 @@ dependent_startup_wait_for=
{% set _dummy = relay_for_ipv4.update({'flag': False}) %}
-{% set _dummy = relay_for_ipv6.update({'flag': False}) %}
{% endif %}
{% endfor %}
diff --git a/rules/dhcp6relay.mk b/rules/dhcp6relay.mk
deleted file mode 100644
index 7f1ab3a1e354..000000000000
--- a/rules/dhcp6relay.mk
+++ /dev/null
@@ -1,12 +0,0 @@
-# SONiC DHCPV6 RELAY Package
-
-SONIC_DHCP6RELAY_VERSION = 1.0.0-0
-SONIC_DHCP6RELAY_PKG_NAME = dhcp6relay
-
-SONIC_DHCP6RELAY = sonic-$(SONIC_DHCP6RELAY_PKG_NAME)_$(SONIC_DHCP6RELAY_VERSION)_$(CONFIGURED_ARCH).deb
-$(SONIC_DHCP6RELAY)_DEPENDS = $(LIBSWSSCOMMON) $(LIBHIREDIS) $(LIBSWSSCOMMON_DEV) $(LIBHIREDIS_DEV)
-$(SONIC_DHCP6RELAY)_SRC_PATH = $(SRC_PATH)/$(SONIC_DHCP6RELAY_PKG_NAME)
-SONIC_DPKG_DEBS += $(SONIC_DHCP6RELAY)
-
-SONIC_DHCP6RELAY_DBG = sonic-$(SONIC_DHCP6RELAY_PKG_NAME)-dbg_$(SONIC_DHCP6RELAY_VERSION)_amd64.deb
-$(eval $(call add_derived_package,$(SONIC_DHCP6RELAY),$(SONIC_DHCP6RELAY_DBG)))
diff --git a/rules/dhcprelay.mk b/rules/dhcprelay.mk
new file mode 100644
index 000000000000..5129c3bcbe31
--- /dev/null
+++ b/rules/dhcprelay.mk
@@ -0,0 +1,12 @@
+# SONiC DHCPV6 RELAY Package
+
+SONIC_DHCPRELAY_VERSION = 1.0.0-0
+SONIC_DHCPRELAY_PKG_NAME = dhcp6relay
+
+SONIC_DHCPRELAY = sonic-$(SONIC_DHCPRELAY_PKG_NAME)_$(SONIC_DHCPRELAY_VERSION)_$(CONFIGURED_ARCH).deb
+$(SONIC_DHCPRELAY)_DEPENDS = $(LIBSWSSCOMMON) $(LIBHIREDIS) $(LIBSWSSCOMMON_DEV) $(LIBHIREDIS_DEV)
+$(SONIC_DHCPRELAY)_SRC_PATH = $(SRC_PATH)/dhcprelay
+SONIC_DPKG_DEBS += $(SONIC_DHCPRELAY)
+
+SONIC_DHCPRELAY_DBG = sonic-$(SONIC_DHCPRELAY_PKG_NAME)-dbgsym_$(SONIC_DHCPRELAY_VERSION)_amd64.deb
+$(eval $(call add_derived_package,$(SONIC_DHCPRELAY),$(SONIC_DHCPRELAY_DBG)))
diff --git a/rules/docker-dhcp-relay.mk b/rules/docker-dhcp-relay.mk
index 4a724443fb88..4182d3ec137f 100644
--- a/rules/docker-dhcp-relay.mk
+++ b/rules/docker-dhcp-relay.mk
@@ -6,9 +6,9 @@ DOCKER_DHCP_RELAY_DBG = $(DOCKER_DHCP_RELAY_STEM)-$(DBG_IMAGE_MARK).gz
$(DOCKER_DHCP_RELAY)_PATH = $(DOCKERS_PATH)/$(DOCKER_DHCP_RELAY_STEM)
-$(DOCKER_DHCP_RELAY)_DEPENDS += $(ISC_DHCP_RELAY) $(REDIS_TOOLS) $(SONIC_DHCPMON) $(SONIC_DHCP6RELAY) $(LIBSWSSCOMMON)
+$(DOCKER_DHCP_RELAY)_DEPENDS += $(ISC_DHCP_RELAY) $(REDIS_TOOLS) $(SONIC_DHCPMON) $(SONIC_DHCPRELAY) $(LIBSWSSCOMMON)
$(DOCKER_DHCP_RELAY)_DBG_DEPENDS = $($(DOCKER_CONFIG_ENGINE_STRETCH)_DBG_DEPENDS)
-$(DOCKER_DHCP_RELAY)_DBG_DEPENDS += $(ISC_DHCP_RELAY_DBG) $(SONIC_DHCP6RELAY_DBG)
+$(DOCKER_DHCP_RELAY)_DBG_DEPENDS += $(ISC_DHCP_RELAY_DBG) $(SONIC_DHCPRELAY_DBG)
$(DOCKER_DHCP_RELAY)_DBG_IMAGE_PACKAGES = $($(DOCKER_CONFIG_ENGINE_STRETCH)_DBG_IMAGE_PACKAGES)
diff --git a/sonic-dhcp-relay b/sonic-dhcp-relay
deleted file mode 160000
index e2cd5851ddd9..000000000000
--- a/sonic-dhcp-relay
+++ /dev/null
@@ -1 +0,0 @@
-Subproject commit e2cd5851ddd9b6496b59b72e75aaba8e4d7f284d
diff --git a/src/dhcp6relay/.gitignore b/src/dhcp6relay/.gitignore
deleted file mode 100644
index 9d09ae6b3f1a..000000000000
--- a/src/dhcp6relay/.gitignore
+++ /dev/null
@@ -1,5 +0,0 @@
-debian/*
-!debian/changelog
-!debian/compat
-!debian/control
-!debian/rules
diff --git a/src/dhcp6relay/Makefile b/src/dhcp6relay/Makefile
deleted file mode 100644
index 8b5740fd787e..000000000000
--- a/src/dhcp6relay/Makefile
+++ /dev/null
@@ -1,42 +0,0 @@
-RM := rm -rf
-DHCP6RELAY_TARGET := dhcp6relay
-CP := cp
-MKDIR := mkdir
-CC := g++
-MV := mv
-LIBS := -levent -lhiredis -lswsscommon -pthread -lboost_thread -lboost_system
-CFLAGS += -Wall -std=c++14 -fPIE -I$(PWD)/../sonic-swss-common/common
-PWD := $(shell pwd)
-
-ifneq ($(MAKECMDGOALS),clean)
-ifneq ($(strip $(C_DEPS)),)
--include $(C_DEPS) $(OBJS)
-endif
-endif
-
--include src/subdir.mk
-
-all: sonic-dhcp6relay
-
-sonic-dhcp6relay: $(OBJS)
- @echo 'Building target: $@'
- @echo 'Invoking: G++ Linker'
- $(CC) $(LDFLAGS) -o $(DHCP6RELAY_TARGET) $(OBJS) $(LIBS)
- @echo 'Finished building target: $@'
- @echo ' '
-
-install:
- $(MKDIR) -p $(DESTDIR)/usr/sbin
- $(MV) $(DHCP6RELAY_TARGET) $(DESTDIR)/usr/sbin
-
-deinstall:
- $(RM) $(DESTDIR)/usr/sbin/$(DHCP6RELAY_TARGET)
- $(RM) -rf $(DESTDIR)/usr/sbin
-
-clean:
- -$(RM) $(EXECUTABLES) $(C_DEPS) $(OBJS) $(DHCP6RELAY_TARGET)
- -@echo ' '
-
-.PHONY: all clean dependents
-
-
diff --git a/src/dhcp6relay/debian/changelog b/src/dhcp6relay/debian/changelog
deleted file mode 100644
index aec73a095801..000000000000
--- a/src/dhcp6relay/debian/changelog
+++ /dev/null
@@ -1,5 +0,0 @@
-sonic-dhcp6relay (1.0.0-0) UNRELEASED; urgency=medium
-
- * Initial release.
-
- -- Kelly Yeh Fri, 15 Oct 2021 00:00:00 +1000
diff --git a/src/dhcp6relay/debian/compat b/src/dhcp6relay/debian/compat
deleted file mode 100644
index ec635144f600..000000000000
--- a/src/dhcp6relay/debian/compat
+++ /dev/null
@@ -1 +0,0 @@
-9
diff --git a/src/dhcp6relay/debian/control b/src/dhcp6relay/debian/control
deleted file mode 100644
index fb82be7c911f..000000000000
--- a/src/dhcp6relay/debian/control
+++ /dev/null
@@ -1,27 +0,0 @@
-Source: sonic-dhcp6relay
-Section: devel
-Priority: optional
-Maintainer: Kelly Yeh
-Build-Depends: debhelper (>= 8.0.0),
- dh-systemd
-Standards-Version: 3.9.3
-Homepage: https://github.com/Azure/sonic-buildimage
-XS-Go-Import-Path: github.com/Azure/sonic-buildimage
-
-Package: sonic-dhcp6relay
-Architecture: any
-Built-Using: ${misc:Built-Using}
-Depends: libevent-2.0-5,
- libboost-thread1.55.0,
- libboost-system1.55.0
-Description: SONiC DHCPv6 Relay
-
-Package: sonic-dhcp6relay-dbg
-Architecture: any
-Section: debug
-Priority: extra
-Built-Using: ${misc:Built-Using}
-Depends: libevent-2.0-5,
- libboost-thread1.55.0,
- libboost-system1.55.0
-Description: SONiC DHCPv6 Relay debug symbols
diff --git a/src/dhcp6relay/debian/rules b/src/dhcp6relay/debian/rules
deleted file mode 100755
index ed8a2397a6d4..000000000000
--- a/src/dhcp6relay/debian/rules
+++ /dev/null
@@ -1,12 +0,0 @@
-#!/usr/bin/make -f
-
-export DEB_BUILD_MAINT_OPTIONS=hardening=+all
-
-%:
- dh $@ --parallel
-
-override_dh_strip:
- dh_strip --dbg-package=sonic-dhcp6relay-dbg
-
-override_dh_auto_install:
- dh_auto_install --destdir=debian/sonic-dhcp6relay
diff --git a/src/dhcp6relay/src/configInterface.cpp b/src/dhcp6relay/src/configInterface.cpp
deleted file mode 100644
index dfe6031e0468..000000000000
--- a/src/dhcp6relay/src/configInterface.cpp
+++ /dev/null
@@ -1,151 +0,0 @@
-#include
-#include
-#include
-#include "configInterface.h"
-
-constexpr auto DEFAULT_TIMEOUT_MSEC = 1000;
-
-bool pollSwssNotifcation = true;
-std::shared_ptr mSwssThreadPtr;
-
-std::shared_ptr configDbPtr = std::make_shared (4, "localhost", 6379, 0);
-swss::SubscriberStateTable ipHelpersTable(configDbPtr.get(), "DHCP_RELAY");
-swss::Select swssSelect;
-
-/**
- * @code void initialize_swss()
- *
- * @brief initialize DB tables and start SWSS listening thread
- *
- * @return none
- */
-void initialize_swss(std::vector *vlans)
-{
- try {
- swssSelect.addSelectable(&ipHelpersTable);
- get_dhcp(vlans);
- mSwssThreadPtr = std::make_shared (&handleSwssNotification, vlans);
- }
- catch (const std::bad_alloc &e) {
- syslog(LOG_ERR, "Failed allocate memory. Exception details: %s", e.what());
- }
-}
-
-/**
- * @code void deinitialize_swss()
- *
- * @brief deinitialize DB interface and join SWSS listening thread
- *
- * @return none
- */
-void deinitialize_swss()
-{
- stopSwssNotificationPoll();
- mSwssThreadPtr->interrupt();
-}
-
-
-/**
- * @code void get_dhcp(std::vector *vlans)
- *
- * @brief initialize and get vlan table information from DHCP_RELAY
- *
- * @return none
- */
-void get_dhcp(std::vector *vlans) {
- swss::Selectable *selectable;
- int ret = swssSelect.select(&selectable, DEFAULT_TIMEOUT_MSEC);
- if (ret == swss::Select::ERROR) {
- syslog(LOG_WARNING, "Select: returned ERROR");
- } else if (ret == swss::Select::TIMEOUT) {
- }
- if (selectable == static_cast (&ipHelpersTable)) {
- handleRelayNotification(ipHelpersTable, vlans);
- }
-}
-/**
- * @code void handleSwssNotification(std::vector *vlans)
- *
- * @brief main thread for handling SWSS notification
- *
- * @param context list of vlans/argument config that contains strings of server and option
- *
- * @return none
- */
-void handleSwssNotification(std::vector *vlans)
-{
- while (pollSwssNotifcation) {
- get_dhcp(vlans);
- }
-}
-
-/**
- * @code void handleRelayNotification(swss::SubscriberStateTable &ipHelpersTable, std::vector *vlans)
- *
- * @brief handles DHCPv6 relay configuration change notification
- *
- * @param ipHelpersTable DHCP table
- * @param vlans list of vlans/argument config that contains strings of server and option
- *
- * @return none
- */
-void handleRelayNotification(swss::SubscriberStateTable &ipHelpersTable, std::vector *vlans)
-{
- std::deque entries;
-
- ipHelpersTable.pops(entries);
- processRelayNotification(entries, vlans);
-}
-
-/**
- * @code void processRelayNotification(std::deque &entries, std::vector *vlans)
- *
- * @brief process DHCPv6 relay servers and options configuration change notification
- *
- * @param entries queue of std::tuple> entries in DHCP table
- * @param vlans list of vlans/argument config that contains strings of server and option
- *
- * @return none
- */
-void processRelayNotification(std::deque &entries, std::vector *vlans)
-{
- std::vector servers;
-
- for (auto &entry: entries) {
- std::string vlan = kfvKey(entry);
- std::string operation = kfvOp(entry);
- std::vector fieldValues = kfvFieldsValues(entry);
-
- relay_config intf;
- intf.is_option_79 = true;
- intf.interface = vlan;
- for (auto &fieldValue: fieldValues) {
- std::string f = fvField(fieldValue);
- std::string v = fvValue(fieldValue);
- if(f == "dhcpv6_servers") {
- std::stringstream ss(v);
- while (ss.good()) {
- std::string substr;
- getline(ss, substr, ',');
- intf.servers.push_back(substr);
- }
- syslog(LOG_DEBUG, "key: %s, Operation: %s, f: %s, v: %s", vlan.c_str(), operation.c_str(), f.c_str(), v.c_str());
- }
- if(f == "dhcpv6_option|rfc6939_support" && v == "false") {
- intf.is_option_79 = false;
- }
- }
- vlans->push_back(intf);
- }
-}
-
-/**
-*@code stopSwssNotificationPoll
-*
-*@brief stop SWSS listening thread
-*
-*@return none
-*/
-void stopSwssNotificationPoll() {
- pollSwssNotifcation = false;
-};
diff --git a/src/dhcp6relay/src/configInterface.d b/src/dhcp6relay/src/configInterface.d
deleted file mode 100644
index d803bf1a54de..000000000000
--- a/src/dhcp6relay/src/configInterface.d
+++ /dev/null
@@ -1,44 +0,0 @@
-src/configInterface.o: src/configInterface.cpp src/configInterface.h \
- /sonic/src/dhcp6relay/../sonic-swss-common/common/subscriberstatetable.h \
- /sonic/src/dhcp6relay/../sonic-swss-common/common/dbconnector.h \
- /sonic/src/dhcp6relay/../sonic-swss-common/common/consumertablebase.h \
- /sonic/src/dhcp6relay/../sonic-swss-common/common/table.h \
- /sonic/src/dhcp6relay/../sonic-swss-common/common/redisreply.h \
- /sonic/src/dhcp6relay/../sonic-swss-common/common/rediscommand.h \
- /sonic/src/dhcp6relay/../sonic-swss-common/common/redisselect.h \
- /sonic/src/dhcp6relay/../sonic-swss-common/common/selectable.h \
- /sonic/src/dhcp6relay/../sonic-swss-common/common/redispipeline.h \
- /sonic/src/dhcp6relay/../sonic-swss-common/common/schema.h \
- /sonic/src/dhcp6relay/../sonic-swss-common/common/redistran.h \
- /sonic/src/dhcp6relay/../sonic-swss-common/common/logger.h \
- /sonic/src/dhcp6relay/../sonic-swss-common/common/select.h src/relay.h
-
-src/configInterface.h:
-
-/sonic/src/dhcp6relay/../sonic-swss-common/common/subscriberstatetable.h:
-
-/sonic/src/dhcp6relay/../sonic-swss-common/common/dbconnector.h:
-
-/sonic/src/dhcp6relay/../sonic-swss-common/common/consumertablebase.h:
-
-/sonic/src/dhcp6relay/../sonic-swss-common/common/table.h:
-
-/sonic/src/dhcp6relay/../sonic-swss-common/common/redisreply.h:
-
-/sonic/src/dhcp6relay/../sonic-swss-common/common/rediscommand.h:
-
-/sonic/src/dhcp6relay/../sonic-swss-common/common/redisselect.h:
-
-/sonic/src/dhcp6relay/../sonic-swss-common/common/selectable.h:
-
-/sonic/src/dhcp6relay/../sonic-swss-common/common/redispipeline.h:
-
-/sonic/src/dhcp6relay/../sonic-swss-common/common/schema.h:
-
-/sonic/src/dhcp6relay/../sonic-swss-common/common/redistran.h:
-
-/sonic/src/dhcp6relay/../sonic-swss-common/common/logger.h:
-
-/sonic/src/dhcp6relay/../sonic-swss-common/common/select.h:
-
-src/relay.h:
diff --git a/src/dhcp6relay/src/configInterface.h b/src/dhcp6relay/src/configInterface.h
deleted file mode 100644
index 20b0912c5cef..000000000000
--- a/src/dhcp6relay/src/configInterface.h
+++ /dev/null
@@ -1,75 +0,0 @@
-#include
-#include "subscriberstatetable.h"
-#include "select.h"
-#include "relay.h"
-
-/**
- * @code void initialize_swss()
- *
- * @brief initialize DB tables and start SWSS listening thread
- *
- * @return none
- */
-void initialize_swss(std::vector *vlans);
-
-/**
- * @code void deinitialize_swss()
- *
- * @brief deinitialize DB interface and join SWSS listening thread
- *
- * @return none
- */
-void deinitialize_swss();
-
-/**
- * @code void get_dhcp(std::vector *vlans)
- *
- * @brief initialize and get vlan information from DHCP_RELAY
- *
- * @return none
- */
-void get_dhcp(std::vector *vlans);
-
-/**
- * @code void handleSwssNotification(std::vector *vlans)
- *
- * @brief main thread for handling SWSS notification
- *
- * @param vlans list of vlans/argument config that contains strings of server and option
- *
- * @return none
- */
-void handleSwssNotification(std::vector *vlans);
-
-/**
- * @code void handleRelayNotification(swss::SubscriberStateTable &ipHelpersTable, std::vector *vlans)
- *
- * @brief handles DHCPv6 relay configuration change notification
- *
- * @param ipHelpersTable DHCP table
- * @param vlans list of vlans/argument config that contains strings of server and option
- *
- * @return none
- */
-void handleRelayNotification(swss::SubscriberStateTable &configMuxTable, std::vector *vlans);
-
-/**
- * @code void processRelayNotification(std::deque &entries, std::vector *vlans)
- *
- * @brief process DHCPv6 relay servers and options configuration change notification
- *
- * @param entries queue of std::tuple> entries in DHCP table
- * @param context list of vlans/argument config that contains strings of server and option
- *
- * @return none
- */
-void processRelayNotification(std::deque &entries, std::vector *vlans);
-
-/**
-*@code stopSwssNotificationPoll
-*
-*@brief stop SWSS listening thread
-*
-*@return none
-*/
-void stopSwssNotificationPoll();
diff --git a/src/dhcp6relay/src/main.cpp b/src/dhcp6relay/src/main.cpp
deleted file mode 100644
index 6d0fb29c050f..000000000000
--- a/src/dhcp6relay/src/main.cpp
+++ /dev/null
@@ -1,17 +0,0 @@
-#include
-#include
-#include "configInterface.h"
-
-int main(int argc, char *argv[]) {
- try {
- std::vector vlans;
- initialize_swss(&vlans);
- loop_relay(&vlans);
- }
- catch (std::exception &e)
- {
- syslog(LOG_ERR, "An exception occurred.\n");
- return 1;
- }
- return 0;
-}
diff --git a/src/dhcp6relay/src/main.d b/src/dhcp6relay/src/main.d
deleted file mode 100644
index 05e7fd2367f0..000000000000
--- a/src/dhcp6relay/src/main.d
+++ /dev/null
@@ -1,44 +0,0 @@
-src/main.o: src/main.cpp src/configInterface.h \
- /sonic/src/dhcp6relay/../sonic-swss-common/common/subscriberstatetable.h \
- /sonic/src/dhcp6relay/../sonic-swss-common/common/dbconnector.h \
- /sonic/src/dhcp6relay/../sonic-swss-common/common/consumertablebase.h \
- /sonic/src/dhcp6relay/../sonic-swss-common/common/table.h \
- /sonic/src/dhcp6relay/../sonic-swss-common/common/redisreply.h \
- /sonic/src/dhcp6relay/../sonic-swss-common/common/rediscommand.h \
- /sonic/src/dhcp6relay/../sonic-swss-common/common/redisselect.h \
- /sonic/src/dhcp6relay/../sonic-swss-common/common/selectable.h \
- /sonic/src/dhcp6relay/../sonic-swss-common/common/redispipeline.h \
- /sonic/src/dhcp6relay/../sonic-swss-common/common/schema.h \
- /sonic/src/dhcp6relay/../sonic-swss-common/common/redistran.h \
- /sonic/src/dhcp6relay/../sonic-swss-common/common/logger.h \
- /sonic/src/dhcp6relay/../sonic-swss-common/common/select.h src/relay.h
-
-src/configInterface.h:
-
-/sonic/src/dhcp6relay/../sonic-swss-common/common/subscriberstatetable.h:
-
-/sonic/src/dhcp6relay/../sonic-swss-common/common/dbconnector.h:
-
-/sonic/src/dhcp6relay/../sonic-swss-common/common/consumertablebase.h:
-
-/sonic/src/dhcp6relay/../sonic-swss-common/common/table.h:
-
-/sonic/src/dhcp6relay/../sonic-swss-common/common/redisreply.h:
-
-/sonic/src/dhcp6relay/../sonic-swss-common/common/rediscommand.h:
-
-/sonic/src/dhcp6relay/../sonic-swss-common/common/redisselect.h:
-
-/sonic/src/dhcp6relay/../sonic-swss-common/common/selectable.h:
-
-/sonic/src/dhcp6relay/../sonic-swss-common/common/redispipeline.h:
-
-/sonic/src/dhcp6relay/../sonic-swss-common/common/schema.h:
-
-/sonic/src/dhcp6relay/../sonic-swss-common/common/redistran.h:
-
-/sonic/src/dhcp6relay/../sonic-swss-common/common/logger.h:
-
-/sonic/src/dhcp6relay/../sonic-swss-common/common/select.h:
-
-src/relay.h:
diff --git a/src/dhcp6relay/src/relay.cpp b/src/dhcp6relay/src/relay.cpp
deleted file mode 100644
index c4589774bfa9..000000000000
--- a/src/dhcp6relay/src/relay.cpp
+++ /dev/null
@@ -1,816 +0,0 @@
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-
-#include "dbconnector.h"
-#include "configInterface.h"
-#include "redisclient.h"
-
-
-struct event *listen_event;
-struct event *server_listen_event;
-struct event_base *base;
-struct event *ev_sigint;
-struct event *ev_sigterm;
-static std::string counter_table = "DHCPv6_COUNTER_TABLE|";
-swss::DBConnector state_db(6, "localhost", 6379, 0);
-swss::RedisClient m_stateDbRedisClient(&state_db);
-
-/* DHCPv6 filter */
-/* sudo tcpdump -dd "ip6 dst ff02::1:2 && udp dst port 547" */
-
-static struct sock_filter ether_relay_filter[] = {
-
- { 0x28, 0, 0, 0x0000000c },
- { 0x15, 0, 13, 0x000086dd },
- { 0x20, 0, 0, 0x00000026 },
- { 0x15, 0, 11, 0xff020000 },
- { 0x20, 0, 0, 0x0000002a },
- { 0x15, 0, 9, 0x00000000 },
- { 0x20, 0, 0, 0x0000002e },
- { 0x15, 0, 7, 0x00000000 },
- { 0x20, 0, 0, 0x00000032 },
- { 0x15, 0, 5, 0x00010002 },
- { 0x30, 0, 0, 0x00000014 },
- { 0x15, 0, 3, 0x00000011 },
- { 0x28, 0, 0, 0x00000038 },
- { 0x15, 0, 1, 0x00000223 },
- { 0x6, 0, 0, 0x00040000 },
- { 0x6, 0, 0, 0x00000000 },
-};
-const struct sock_fprog ether_relay_fprog = {
- lengthof(ether_relay_filter),
- ether_relay_filter
-};
-
-/* DHCPv6 Counter */
-uint64_t counters[DHCPv6_MESSAGE_TYPE_COUNT];
-std::map counterMap = {{0, "Unknown"},
- {1, "Solicit"},
- {2, "Advertise"},
- {3, "Request"},
- {4, "Confirm"},
- {5, "Renew"},
- {6, "Rebind"},
- {7, "Reply"},
- {8, "Release"},
- {9, "Decline"},
- {12, "Relay-Forward"},
- {13, "Relay-Reply"}};
-
-/**
- * @code void initialize_counter(std::string counterVlan);
- *
- * @brief initialize the counter by each Vlan
- *
- * @param counterVlan counter table with interface name
- *
- * @return none
- */
-void initialize_counter(std::string counterVlan) {
- m_stateDbRedisClient.hset(counterVlan, "Unknown", toString(counters[DHCPv6_MESSAGE_TYPE_UNKNOWN]));
- m_stateDbRedisClient.hset(counterVlan, "Solicit", toString(counters[DHCPv6_MESSAGE_TYPE_SOLICIT]));
- m_stateDbRedisClient.hset(counterVlan, "Advertise", toString(counters[DHCPv6_MESSAGE_TYPE_ADVERTISE]));
- m_stateDbRedisClient.hset(counterVlan, "Request", toString(counters[DHCPv6_MESSAGE_TYPE_REQUEST]));
- m_stateDbRedisClient.hset(counterVlan, "Confirm", toString(counters[DHCPv6_MESSAGE_TYPE_CONFIRM]));
- m_stateDbRedisClient.hset(counterVlan, "Renew", toString(counters[DHCPv6_MESSAGE_TYPE_RENEW]));
- m_stateDbRedisClient.hset(counterVlan, "Rebind", toString(counters[DHCPv6_MESSAGE_TYPE_REBIND]));
- m_stateDbRedisClient.hset(counterVlan, "Reply", toString(counters[DHCPv6_MESSAGE_TYPE_REPLY]));
- m_stateDbRedisClient.hset(counterVlan, "Release", toString(counters[DHCPv6_MESSAGE_TYPE_RELEASE]));
- m_stateDbRedisClient.hset(counterVlan, "Decline", toString(counters[DHCPv6_MESSAGE_TYPE_DECLINE]));
- m_stateDbRedisClient.hset(counterVlan, "Relay-Forward", toString(counters[DHCPv6_MESSAGE_TYPE_RELAY_FORW]));
- m_stateDbRedisClient.hset(counterVlan, "Relay-Reply", toString(counters[DHCPv6_MESSAGE_TYPE_RELAY_REPL]));
-}
-
-/**
- * @code void update_counter(std::string CounterVlan, uint8_t msg_type);
- *
- * @brief update the counter in state_db with count of each DHCPv6 message type
- *
- * @param counterVlan counter table with interface name
- * @param msg_type dhcpv6 message type to be updated in counter
- *
- * @return none
- */
-void update_counter(std::string counterVlan, uint8_t msg_type) {
- m_stateDbRedisClient.hset(counterVlan, counterMap.find(msg_type)->second, toString(counters[msg_type]));
-}
-
-/**
- * @code std::string toString(uint16_t count);
- *
- * @brief convert uint16_t to string
- *
- * @param count count of messages in counter
- *
- * @return count in string
- */
-std::string toString(uint16_t count) {
- std::stringstream ss;
- ss << count;
- std::string countValue = ss.str();
- return countValue;
-}
-
-/**
- * @code const struct ether_header *parse_ether_frame(const uint8_t *buffer, const uint8_t **out_end);
- *
- * @brief parse through ethernet frame
- *
- * @param *buffer message buffer
- * @param **out_end pointer
- *
- * @return ether_header end of ethernet header position
- */
-const struct ether_header *parse_ether_frame(const uint8_t *buffer, const uint8_t **out_end) {
- (*out_end) = buffer + sizeof(struct ether_header);
- return (const struct ether_header *)buffer;
-}
-
-/**
- * @code const struct ip6_hdr *parse_ip6_hdr(const uint8_t *buffer, const uint8_t **out_end);
- *
- * @brief parse through ipv6 header
- *
- * @param *buffer message buffer
- * @param **out_end pointer
- *
- * @return ip6_hdr end of ipv6 header position
- */
-const struct ip6_hdr *parse_ip6_hdr(const uint8_t *buffer, const uint8_t **out_end) {
- (*out_end) = buffer + sizeof(struct ip6_hdr);
- return (struct ip6_hdr *)buffer;
-}
-
-/**
- * @code const struct udphdr *parse_udp(const uint8_t *buffer, const uint8_t **out_end);
- *
- * @brief parse through udp header
- *
- * @param *buffer message buffer
- * @param **out_end pointer
- *
- * @return udphdr end of udp header position
- */
-const struct udphdr *parse_udp(const uint8_t *buffer, const uint8_t **out_end) {
- (*out_end) = buffer + sizeof(struct udphdr);
- return (const struct udphdr *)buffer;
-}
-
-/**
- * @code const struct dhcpv6_msg *parse_dhcpv6_hdr(const uint8_t *buffer);
- *
- * @brief parse through dhcpv6 header
- *
- * @param *buffer message buffer
- * @param **out_end pointer
- *
- * @return dhcpv6_msg end of dhcpv6 header position
- */
-const struct dhcpv6_msg *parse_dhcpv6_hdr(const uint8_t *buffer) {
- return (const struct dhcpv6_msg *)buffer;
-}
-
-/**
- * @code const struct dhcpv6_relay_msg *parse_dhcpv6_relay(const uint8_t *buffer);
- *
- * @brief parse through dhcpv6 relay message
- *
- * @param *buffer message buffer
- * @param **out_end pointer
- *
- * @return dhcpv6_relay_msg start of dhcpv6 relay message or end of dhcpv6 message type position
- */
-const struct dhcpv6_relay_msg *parse_dhcpv6_relay(const uint8_t *buffer) {
- return (const struct dhcpv6_relay_msg *)buffer;
-}
-
-/**
- * @code const struct dhcpv6_option *parse_dhcpv6_opt(const uint8_t *buffer, const uint8_t **out_end);
- *
- * @brief parse through dhcpv6 option
- *
- * @param *buffer message buffer
- * @param **out_end pointer
- *
- * @return dhcpv6_option end of dhcpv6 message option
- */
-const struct dhcpv6_option *parse_dhcpv6_opt(const uint8_t *buffer, const uint8_t **out_end) {
- uint32_t size = 4; // option-code + option-len
- size += ntohs(*(uint16_t *)(buffer + 2));
- (*out_end) = buffer + size;
-
- return (const struct dhcpv6_option *)buffer;
-}
-
-/**
- * @code void send_udp(int sock, uint8_t *buffer, struct sockaddr_in6 target, uint32_t n, relay_config *config, uint8_t msg_type);
- *
- * @brief send udp packet
- *
- * @param *buffer message buffer
- * @param sockaddr_in6 target target socket
- * @param n length of message
- * @param relay_config *config pointer to relay_config
- * @param uint8_t msg_type message type of dhcpv6 option of relayed message
- *
- * @return dhcpv6_option end of dhcpv6 message option
- */
-void send_udp(int sock, uint8_t *buffer, struct sockaddr_in6 target, uint32_t n, relay_config *config, uint8_t msg_type) {
- std::string counterVlan = counter_table;
- if(sendto(sock, buffer, n, 0, (const struct sockaddr *)&target, sizeof(target)) == -1)
- syslog(LOG_ERR, "sendto: Failed to send to target address\n");
- else if (counterMap.find(msg_type) != counterMap.end()) {
- counters[msg_type]++;
- update_counter(counterVlan.append(config->interface), msg_type);
- } else {
- syslog(LOG_WARNING, "unexpected message type %d(0x%x)\n", msg_type, msg_type);
- }
-}
-
-/**
- * @code relay_forward(uint8_t *buffer, const struct dhcpv6_msg *msg, uint16_t msg_length);
- *
- * @brief embed the DHCPv6 message received into DHCPv6 relay forward message
- *
- * @param buffer pointer to buffer
- * @param msg pointer to parsed DHCPv6 message
- * @param msg_length length of DHCPv6 message
- *
- * @return none
- */
-void relay_forward(uint8_t *buffer, const struct dhcpv6_msg *msg, uint16_t msg_length) {
- struct dhcpv6_option option;
- option.option_code = htons(OPTION_RELAY_MSG);
- option.option_length = htons(msg_length);
- memcpy(buffer, &option, sizeof(struct dhcpv6_option));
- memcpy(buffer + sizeof(struct dhcpv6_option), msg, msg_length);
-}
-
-/**
- * @code sock_open(int ifindex, const struct sock_fprog *fprog);
- *
- * @brief prepare L2 socket to attach to "udp and port 547" filter
- *
- * @param ifindex interface index
- * @param fprog bpf filter "udp and port 547"
- *
- * @return socket descriptor
- */
-int sock_open(int ifindex, const struct sock_fprog *fprog)
-{
- if (!ifindex) {
- errno = EINVAL;
- return -1;
- }
-
- int s = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
- if (s == -1) {
- syslog(LOG_ERR, "socket: Failed to create socket\n");
- return -1;
- }
-
- struct sockaddr_ll sll = {
- .sll_family = AF_PACKET,
- .sll_protocol = htons(ETH_P_ALL),
- .sll_ifindex = ifindex
- };
-
- if (bind(s, (struct sockaddr *)&sll, sizeof sll) == -1) {
- syslog(LOG_ERR, "bind: Failed to bind to specified interface\n");
- (void) close(s);
- return -1;
- }
-
- if (fprog && setsockopt(s, SOL_SOCKET, SO_ATTACH_FILTER, fprog, sizeof *fprog) == -1)
- {
- syslog(LOG_ERR, "setsockopt: Failed to attach filter\n");
- (void) close(s);
- return -1;
- }
-
- return s;
-}
-
-/**
- * @code prepare_relay_config(relay_config *interface_config, int local_sock, int filter);
- *
- * @brief prepare for specified relay interface config: server and link address
- *
- * @param interface_config pointer to relay config to be prepared
- * @param local_sock L3 socket used for relaying messages
- * @param filter socket attached with filter
- *
- * @return none
- */
-void prepare_relay_config(relay_config *interface_config, int *local_sock, int filter) {
- struct ifaddrs *ifa, *ifa_tmp;
- sockaddr_in6 non_link_local;
- sockaddr_in6 link_local;
-
- interface_config->local_sock = *local_sock;
- interface_config->filter = filter;
-
- for(auto server: interface_config->servers) {
- sockaddr_in6 tmp;
- if(inet_pton(AF_INET6, server.c_str(), &tmp.sin6_addr) != 1)
- {
- syslog(LOG_WARNING, "inet_pton: Failed to convert IPv6 address\n");
- }
- tmp.sin6_family = AF_INET6;
- tmp.sin6_flowinfo = 0;
- tmp.sin6_port = htons(RELAY_PORT);
- tmp.sin6_scope_id = 0;
- interface_config->servers_sock.push_back(tmp);
- }
-
- if (getifaddrs(&ifa) == -1) {
- syslog(LOG_WARNING, "getifaddrs: Unable to get network interfaces\n");
- exit(1);
- }
-
- ifa_tmp = ifa;
- while (ifa_tmp) {
- if (ifa_tmp->ifa_addr->sa_family == AF_INET6) {
- struct sockaddr_in6 *in6 = (struct sockaddr_in6*) ifa_tmp->ifa_addr;
- if((strcmp(ifa_tmp->ifa_name, interface_config->interface.c_str()) == 0) && !IN6_IS_ADDR_LINKLOCAL(&in6->sin6_addr)) {
- non_link_local = *in6;
- break;
- }
- if((strcmp(ifa_tmp->ifa_name, interface_config->interface.c_str()) == 0) && IN6_IS_ADDR_LINKLOCAL(&in6->sin6_addr)) {
- link_local = *in6;
- }
- }
- ifa_tmp = ifa_tmp->ifa_next;
- }
- freeifaddrs(ifa);
-
- if(!IN6_IS_ADDR_LINKLOCAL(&non_link_local.sin6_addr)) {
- interface_config->link_address = non_link_local;
- }
- else {
- interface_config->link_address = link_local;
- }
-}
-
-/**
- * @code prepare_socket(int *local_sock, int *server_sock, relay_config *config, int index);
- *
- * @brief prepare L3 socket for sending
- *
- * @param local_sock pointer to socket binded to global address for relaying client message to server and listening for server message
- * @param server_sock pointer to socket binded to link_local address for relaying server message to client
- * @param index scope id of interface
- *
- * @return none
- */
-void prepare_socket(int *local_sock, int *server_sock, relay_config *config, int index) {
- struct ifaddrs *ifa, *ifa_tmp;
- sockaddr_in6 addr;
- sockaddr_in6 ll_addr;
- memset(&addr, 0, sizeof(addr));
- memset(&ll_addr, 0, sizeof(ll_addr));
-
- if ((*local_sock = socket(AF_INET6, SOCK_DGRAM, 0)) == -1) {
- syslog(LOG_ERR, "socket: Failed to create socket\n");
- }
-
- if ((*server_sock= socket(AF_INET6, SOCK_DGRAM, 0)) == -1) {
- syslog(LOG_ERR, "socket: Failed to create socket\n");
- }
-
-
- if (getifaddrs(&ifa) == -1) {
- syslog(LOG_WARNING, "getifaddrs: Unable to get network interfaces\n");
- exit(1);
- }
-
- ifa_tmp = ifa;
- while (ifa_tmp) {
- if (ifa_tmp->ifa_addr->sa_family == AF_INET6) {
- struct sockaddr_in6 *in6 = (struct sockaddr_in6*) ifa_tmp->ifa_addr;
- if((strcmp(ifa_tmp->ifa_name, config->interface.c_str()) == 0) && !IN6_IS_ADDR_LINKLOCAL(&in6->sin6_addr)) {
- in6->sin6_family = AF_INET6;
- in6->sin6_port = htons(RELAY_PORT);
- addr = *in6;
- }
- if((strcmp(ifa_tmp->ifa_name, config->interface.c_str()) == 0) && IN6_IS_ADDR_LINKLOCAL(&in6->sin6_addr)) {
- in6->sin6_family = AF_INET6;
- in6->sin6_port = htons(RELAY_PORT);
- ll_addr = *in6;
- }
- }
- ifa_tmp = ifa_tmp->ifa_next;
- }
- freeifaddrs(ifa);
-
- if (bind(*local_sock, (sockaddr *)&addr, sizeof(addr)) == -1) {
- syslog(LOG_ERR, "bind: Failed to bind to socket\n");
- }
-
- if (bind(*server_sock, (sockaddr *)&ll_addr, sizeof(addr)) == -1) {
- syslog(LOG_ERR, "bind: Failed to bind to socket\n");
- }
-}
-
-
-/**
- * @code relay_client(int sock, const uint8_t *msg, int32_t len, ip6_hdr *ip_hdr, const ether_header *ether_hdr, relay_config *config);
- *
- * @brief construct relay-forward message
- *
- * @param sock L3 socket for sending data to servers
- * @param msg pointer to dhcpv6 message header position
- * @param len size of data received
- * @param ip_hdr pointer to IPv6 header
- * @param ether_hdr pointer to Ethernet header
- * @param config pointer to the relay interface config
- *
- * @return none
- */
-void relay_client(int sock, const uint8_t *msg, int32_t len, const ip6_hdr *ip_hdr, const ether_header *ether_hdr, relay_config *config) {
- static uint8_t buffer[4096];
- auto current_buffer_position = buffer;
- dhcpv6_relay_msg new_message;
- new_message.msg_type = DHCPv6_MESSAGE_TYPE_RELAY_FORW;
- memcpy(&new_message.peer_address, &ip_hdr->ip6_src, sizeof(in6_addr));
- new_message.hop_count = 0;
-
- memcpy(&new_message.link_address, &config->link_address.sin6_addr, sizeof(in6_addr));
- memcpy(current_buffer_position, &new_message, sizeof(dhcpv6_relay_msg));
- current_buffer_position += sizeof(dhcpv6_relay_msg);
-
- if(config->is_option_79) {
- linklayer_addr_option option79;
- option79.link_layer_type = htons(1);
- option79.option_code = htons(OPTION_CLIENT_LINKLAYER_ADDR);
- option79.option_length = htons(2 + 6); // link_layer_type field + address
-
- memcpy(current_buffer_position, &option79, sizeof(linklayer_addr_option));
- current_buffer_position += sizeof(linklayer_addr_option);
-
- memcpy(current_buffer_position, ðer_hdr->ether_shost, sizeof(ether_hdr->ether_shost));
- current_buffer_position += sizeof(ether_hdr->ether_shost);
- }
-
- auto dhcp_message_length = len;
- relay_forward(current_buffer_position, parse_dhcpv6_hdr(msg), dhcp_message_length);
- current_buffer_position += dhcp_message_length + sizeof(dhcpv6_option);
-
- for(auto server: config->servers_sock) {
- send_udp(sock, buffer, server, current_buffer_position - buffer, config, new_message.msg_type);
- }
-}
-
-/**
- * @code relay_relay_forw(int sock, const uint8_t *msg, int32_t len, const ip6_hdr *ip_hdr, relay_config *config)
- *
- * @brief construct a relay-forward message encapsulated relay-forward message
- *
- * @param sock L3 socket for sending data to servers
- * @param msg pointer to dhcpv6 message header position
- * @param len size of data received
- * @param ip_hdr pointer to IPv6 header
- * @param config pointer to the relay interface config
- *
- * @return none
- */
-void relay_relay_forw(int sock, const uint8_t *msg, int32_t len, const ip6_hdr *ip_hdr, relay_config *config) {
- static uint8_t buffer[4096];
- dhcpv6_relay_msg new_message;
- auto current_buffer_position = buffer;
- auto dhcp_relay_header = parse_dhcpv6_relay(msg);
-
- if (dhcp_relay_header->hop_count >= HOP_LIMIT)
- return;
-
- new_message.msg_type = DHCPv6_MESSAGE_TYPE_RELAY_FORW;
- memcpy(&new_message.peer_address, &ip_hdr->ip6_src, sizeof(in6_addr));
- new_message.hop_count = dhcp_relay_header->hop_count + 1;
-
- memset(&new_message.link_address, 0, sizeof(in6_addr));
-
- memcpy(current_buffer_position, &new_message, sizeof(dhcpv6_relay_msg));
- current_buffer_position += sizeof(dhcpv6_relay_msg);
-
- auto dhcp_message_length = len;
- relay_forward(current_buffer_position, parse_dhcpv6_hdr(msg), dhcp_message_length);
- current_buffer_position += dhcp_message_length + sizeof(dhcpv6_option);
-
- for(auto server: config->servers_sock) {
- send_udp(sock, buffer, server, current_buffer_position - buffer, config, new_message.msg_type);
- }
-}
-
-/**
- * @code relay_relay_reply(int sock, const uint8_t *msg, int32_t len, relay_config *configs);
- *
- * @brief relay and unwrap a relay-reply message
- *
- * @param sock L3 socket for sending data to servers
- * @param msg pointer to dhcpv6 message header position
- * @param len size of data received
- * @param config relay interface config
- *
- * @return none
- */
- void relay_relay_reply(int sock, const uint8_t *msg, int32_t len, relay_config *config) {
- static uint8_t buffer[4096];
- uint8_t type = 0;
- struct sockaddr_in6 target_addr;
- auto current_buffer_position = buffer;
- auto current_position = msg;
- const uint8_t *tmp = NULL;
- auto dhcp_relay_header = parse_dhcpv6_relay(msg);
- current_position += sizeof(struct dhcpv6_relay_msg);
-
- auto position = current_position + sizeof(struct dhcpv6_option);
- auto dhcpv6msg = parse_dhcpv6_hdr(position);
-
- while ((current_position - msg) < len) {
- auto option = parse_dhcpv6_opt(current_position, &tmp);
- current_position = tmp;
- if (current_position - msg > len || ntohs(option->option_length) > sizeof(buffer) - (current_buffer_position - buffer)) {
- break;
- }
- switch (ntohs(option->option_code)) {
- case OPTION_RELAY_MSG:
- memcpy(current_buffer_position, ((uint8_t *)option) + sizeof(struct dhcpv6_option), ntohs(option->option_length));
- current_buffer_position += ntohs(option->option_length);
- type = dhcpv6msg->msg_type;
- break;
- default:
- break;
- }
- }
-
- memcpy(&target_addr.sin6_addr, &dhcp_relay_header->peer_address, sizeof(struct in6_addr));
- target_addr.sin6_family = AF_INET6;
- target_addr.sin6_flowinfo = 0;
- target_addr.sin6_port = htons(CLIENT_PORT);
- target_addr.sin6_scope_id = if_nametoindex(config->interface.c_str());
-
- send_udp(sock, buffer, target_addr, current_buffer_position - buffer, config, type);
-}
-
-
-/**
- * @code callback(evutil_socket_t fd, short event, void *arg);
- *
- * @brief callback for libevent that is called everytime data is received at the filter socket
- *
- * @param fd filter socket
- * @param event libevent triggered event
- * @param arg callback argument provided by user
- *
- * @return none
- */
-void callback(evutil_socket_t fd, short event, void *arg) {
- struct relay_config *config = (struct relay_config *)(arg);
- static uint8_t message_buffer[4096];
- int32_t len = recv(config->filter, message_buffer, 4096, 0);
- if (len <= 0) {
- syslog(LOG_WARNING, "recv: Failed to receive data at filter socket: %s\n", strerror(errno));
- return;
- }
-
- char* ptr = (char *)message_buffer;
- const uint8_t *current_position = (uint8_t *)ptr;
- const uint8_t *tmp = NULL;
- const uint8_t *prev = NULL;
-
- auto ether_header = parse_ether_frame(current_position, &tmp);
- current_position = tmp;
-
- auto ip_header = parse_ip6_hdr(current_position, &tmp);
- current_position = tmp;
-
- prev = current_position;
- if (ip_header->ip6_ctlun.ip6_un1.ip6_un1_nxt != IPPROTO_UDP) {
- const struct ip6_ext *ext_header;
- do {
- ext_header = (const struct ip6_ext *)current_position;
- current_position += ext_header->ip6e_len;
- if((current_position == prev) || (current_position >= (uint8_t *)ptr + sizeof(message_buffer))) {
- return;
- }
- prev = current_position;
- }
- while (ext_header->ip6e_nxt != IPPROTO_UDP);
- }
-
- auto udp_header = parse_udp(current_position, &tmp);
- current_position = tmp;
-
- auto msg = parse_dhcpv6_hdr(current_position);
- counters[msg->msg_type]++;
- std::string counterVlan = counter_table;
- update_counter(counterVlan.append(config->interface), msg->msg_type);
-
- switch (msg->msg_type) {
- case DHCPv6_MESSAGE_TYPE_RELAY_FORW:
- {
- relay_relay_forw(config->local_sock, current_position, ntohs(udp_header->len) - sizeof(udphdr), ip_header, config);
- break;
- }
- default:
- {
- relay_client(config->local_sock, current_position, ntohs(udp_header->len) - sizeof(udphdr), ip_header, ether_header, config);
- break;
- }
- }
-}
-
-/**
- * @code void server_callback(evutil_socket_t fd, short event, void *arg);
- *
- * @brief callback for libevent that is called everytime data is received at the server socket
- *
- * @param fd filter socket
- * @param event libevent triggered event
- * @param arg callback argument provided by user
- *
- * @return none
- */
-void server_callback(evutil_socket_t fd, short event, void *arg) {
- struct relay_config *config = (struct relay_config *)arg;
- sockaddr_in6 from;
- socklen_t len = sizeof(from);
- int32_t data = 0;
- static uint8_t message_buffer[4096];
-
- if ((data = recvfrom(config->local_sock, message_buffer, 4096, 0, (sockaddr *)&from, &len)) == -1) {
- syslog(LOG_WARNING, "recv: Failed to receive data from server\n");
- }
-
- auto msg = parse_dhcpv6_hdr(message_buffer);
-
- counters[msg->msg_type]++;
- std::string counterVlan = counter_table;
- update_counter(counterVlan.append(config->interface), msg->msg_type);
- if (msg->msg_type == DHCPv6_MESSAGE_TYPE_RELAY_REPL) {
- relay_relay_reply(config->server_sock, message_buffer, data, config);
- }
-}
-
-/**
- * @code signal_init();
- *
- * @brief initialize DHCPv6 Relay libevent signals
- */
-int signal_init() {
- int rv = -1;
- do {
- ev_sigint = evsignal_new(base, SIGINT, signal_callback, base);
- if (ev_sigint == NULL) {
- syslog(LOG_ERR, "Could not create SIGINT libevent signal\n");
- break;
- }
-
- ev_sigterm = evsignal_new(base, SIGTERM, signal_callback, base);
- if (ev_sigterm == NULL) {
- syslog(LOG_ERR, "Could not create SIGTERM libevent signal\n");
- break;
- }
- rv = 0;
- } while(0);
- return rv;
-}
-
-/**
- * @code signal_start();
- *
- * @brief start DHCPv6 Relay libevent base and add signals
- */
-int signal_start()
-{
- int rv = -1;
- do
- {
- if (evsignal_add(ev_sigint, NULL) != 0) {
- syslog(LOG_ERR, "Could not add SIGINT libevent signal\n");
- break;
- }
-
- if (evsignal_add(ev_sigterm, NULL) != 0) {
- syslog(LOG_ERR, "Could not add SIGTERM libevent signal\n");
- break;
- }
-
- if (event_base_dispatch(base) != 0) {
- syslog(LOG_ERR, "Could not start libevent dispatching loop\n");
- }
-
- rv = 0;
- } while (0);
-
- return rv;
-}
-
-/**
- * @code signal_callback(fd, event, arg);
- *
- * @brief signal handler for dhcp6relay. Initiate shutdown when signal is caught
- *
- * @param fd libevent socket
- * @param event event triggered
- * @param arg pointer to libevent base
- *
- * @return none
- */
-void signal_callback(evutil_socket_t fd, short event, void *arg)
-{
- syslog(LOG_ALERT, "Received signal: '%s'\n", strsignal(fd));
- if ((fd == SIGTERM) || (fd == SIGINT)) {
- dhcp6relay_stop();
- }
-}
-
-/**
- * @code dhcp6relay_stop();
- *
- * @brief stop DHCPv6 Relay libevent loop upon signal
- */
-void dhcp6relay_stop()
-{
- event_base_loopexit(base, NULL);
-}
-
-/**
- * @code loop_relay(std::vector *vlans);
- *
- * @brief main loop: configure sockets, create libevent base, start server listener thread
- *
- * @param vlans list of vlans retrieved from config_db
- */
-void loop_relay(std::vector *vlans) {
- std::vector sockets;
- base = event_base_new();
- if(base == NULL) {
- syslog(LOG_ERR, "libevent: Failed to create base\n");
- }
-
- for(relay_config &vlan : *vlans) {
- relay_config *config = &vlan;
- int filter = 0;
- int local_sock = 0;
- int server_sock = 0;
- int index = if_nametoindex(config->interface.c_str());
-
- std::string counterVlan = counter_table;
- initialize_counter(counterVlan.append(config->interface));
-
- filter = sock_open(index, ðer_relay_fprog);
- prepare_socket(&local_sock, &server_sock, config, index);
-
- config->local_sock = local_sock;
- config->server_sock = server_sock;
-
- sockets.push_back(filter);
- sockets.push_back(local_sock);
- sockets.push_back(server_sock);
-
- prepare_relay_config(config, &local_sock, filter);
-
- evutil_make_listen_socket_reuseable(filter);
- evutil_make_socket_nonblocking(filter);
-
- evutil_make_listen_socket_reuseable(local_sock);
- evutil_make_socket_nonblocking(local_sock);
-
- listen_event = event_new(base, filter, EV_READ|EV_PERSIST, callback, config);
- server_listen_event = event_new(base, local_sock, EV_READ|EV_PERSIST, server_callback, config);
- if (listen_event == NULL || server_listen_event == NULL) {
- syslog(LOG_ERR, "libevent: Failed to create libevent\n");
- }
-
- event_add(listen_event, NULL);
- event_add(server_listen_event, NULL);
- }
-
- if((signal_init() == 0) && signal_start() == 0) {
- shutdown();
- for(std::size_t i = 0; i
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-
-
-#define PACKED __attribute__ ((packed))
-
-#define RELAY_PORT 547
-#define CLIENT_PORT 546
-#define HOP_LIMIT 8 //HOP_LIMIT reduced from 32 to 8 as stated in RFC8415
-
-#define lengthof(A) (sizeof (A) / sizeof (A)[0])
-
-#define OPTION_RELAY_MSG 9
-#define OPTION_CLIENT_LINKLAYER_ADDR 79
-
-/* DHCPv6 message types */
-typedef enum
-{
- DHCPv6_MESSAGE_TYPE_UNKNOWN = 0,
- DHCPv6_MESSAGE_TYPE_SOLICIT = 1,
- DHCPv6_MESSAGE_TYPE_ADVERTISE = 2,
- DHCPv6_MESSAGE_TYPE_REQUEST = 3,
- DHCPv6_MESSAGE_TYPE_CONFIRM = 4,
- DHCPv6_MESSAGE_TYPE_RENEW = 5,
- DHCPv6_MESSAGE_TYPE_REBIND = 6,
- DHCPv6_MESSAGE_TYPE_REPLY = 7,
- DHCPv6_MESSAGE_TYPE_RELEASE = 8,
- DHCPv6_MESSAGE_TYPE_DECLINE = 9,
- DHCPv6_MESSAGE_TYPE_RELAY_FORW = 12,
- DHCPv6_MESSAGE_TYPE_RELAY_REPL = 13,
-
- DHCPv6_MESSAGE_TYPE_COUNT
-} dhcp_message_type_t;
-
-struct relay_config {
- int local_sock;
- int server_sock;
- int filter;
- sockaddr_in6 link_address;
- std::string interface;
- std::vector servers;
- std::vector servers_sock;
- bool is_option_79;
-};
-
-
-/* DHCPv6 messages and options */
-
-struct dhcpv6_msg {
- uint8_t msg_type;
-};
-
-struct PACKED dhcpv6_relay_msg {
- uint8_t msg_type;
- uint8_t hop_count;
- struct in6_addr link_address;
- struct in6_addr peer_address;
-};
-
-
-struct dhcpv6_option {
- uint16_t option_code;
- uint16_t option_length;
-};
-
-struct linklayer_addr_option {
- uint16_t option_code;
- uint16_t option_length;
- uint16_t link_layer_type;
-};
-
-/**
- * @code sock_open(int ifindex, const struct sock_fprog *fprog);
- *
- * @brief prepare L2 socket to attach to "udp and port 547" filter
- *
- * @param ifindex interface index
- * @param fprog bpf filter "udp and port 547"
- *
- * @return socket descriptor
- */
-int sock_open(int ifindex, const struct sock_fprog *fprog);
-
-/**
- * @code prepare_socket(int *local_sock, int *server_sock, relay_config *config, int index);
- *
- * @brief prepare L3 socket for sending
- *
- * @param local_sock pointer to socket binded to global address for relaying client message to server and listening for server message
- * @param server_sock pointer to socket binded to link_local address for relaying server message to client
- * @param index scope id of interface
- *
- * @return none
- */
-void prepare_socket(int *local_sock, int *server_sock, relay_config *config, int index);
-
-/**
- * @code prepare_relay_config(relay_config *interface_config, int *local_sock, int filter);
- *
- * @brief prepare for specified relay interface config: server and link address
- *
- * @param interface_config pointer to relay config to be prepared
- * @param local_sock L3 socket used for relaying messages
- * @param filter socket attached with filter
- *
- * @return none
- */
-void prepare_relay_config(relay_config *interface_config, int *local_sock, int filter);
-
-/**
- * @code relay_forward(uint8_t *buffer, const struct dhcpv6_msg *msg, uint16_t msg_length);
- *
- * @brief embed the DHCPv6 message received into DHCPv6 relay forward message
- *
- * @param buffer pointer to buffer
- * @param msg pointer to parsed DHCPv6 message
- * @param msg_length length of DHCPv6 message
- *
- * @return none
- */
-void relay_forward(uint8_t *buffer, const struct dhcpv6_msg *msg, uint16_t msg_length);
-
-/**
- * @code relay_client(int sock, const uint8_t *msg, int32_t len, ip6_hdr *ip_hdr, const ether_header *ether_hdr, relay_config *config);
- *
- * @brief construct relay-forward message
- *
- * @param sock L3 socket for sending data to servers
- * @param msg pointer to dhcpv6 message header position
- * @param len size of data received
- * @param ip_hdr pointer to IPv6 header
- * @param ether_hdr pointer to Ethernet header
- * @param config pointer to the relay interface config
- *
- * @return none
- */
-void relay_client(int sock, const uint8_t *msg, int32_t len, const ip6_hdr *ip_hdr, const ether_header *ether_hdr, relay_config *config);
-
-/**
- * @code relay_relay_forw(int sock, const uint8_t *msg, int32_t len, const ip6_hdr *ip_hdr, relay_config *config)
- *
- * @brief construct a relay-forward message encapsulated relay-forward message
- *
- * @param sock L3 socket for sending data to servers
- * @param msg pointer to dhcpv6 message header position
- * @param len size of data received
- * @param ip_hdr pointer to IPv6 header
- * @param config pointer to the relay interface config
- *
- * @return none
- */
-void relay_relay_forw(int sock, const uint8_t *msg, int32_t len, const ip6_hdr *ip_hdr, relay_config *config);
-
-/**
- * @code relay_relay_reply(int sock, const uint8_t *msg, int32_t len, relay_config *configs);
- *
- * @brief relay and unwrap a relay-reply message
- *
- * @param sock L3 socket for sending data to servers
- * @param msg pointer to dhcpv6 message header position
- * @param len size of data received
- * @param config relay interface config
- *
- * @return none
- */
-void relay_relay_reply(int sock, const uint8_t *msg, int32_t len, relay_config *configs);
-
-/**
- * @code loop_relay(std::vector *vlans);
- *
- * @brief main loop: configure sockets, create libevent base, start server listener thread
- *
- * @param vlans list of vlans retrieved from config_db
- */
-void loop_relay(std::vector *vlans);
-
-/**
- * @code signal_init();
- *
- * @brief initialize DHCPv6 Relay libevent signals
- */
-int signal_init();
-
-/**
- * @code signal_start();
- *
- * @brief start DHCPv6 Relay libevent base and add signals
- */
-int signal_start();
-
-/**
- * @code dhcp6relay_stop();
- *
- * @brief stop DHCPv6 Relay libevent loop upon signal
- */
-void dhcp6relay_stop();
-
-/**
- * @code signal_callback(fd, event, arg);
- *
- * @brief signal handler for dhcp6relay. Initiate shutdown when signal is caught
- *
- * @param fd libevent socket
- * @param event event triggered
- * @param arg pointer to libevent base
- *
- * @return none
- */
-void signal_callback(evutil_socket_t fd, short event, void *arg);
-
-/**
- * @code shutdown();
- *
- * @brief free signals and terminate threads
- */
-void shutdown();
-
-/**
- * @code void initialize_counter(std::string counterVlan)
- *
- * @brief initialize the counter by each Vlan
- *
- * @param counterVlan counter table with interface name
- *
- * @return none
- */
-void initialize_counter(std::string counterVlan);
-
-/**
- * @code void update_counter(std::string CounterVlan, uint8_t msg_type);
- *
- * @brief update the counter in state_db with count of each DHCPv6 message type
- *
- * @param counterVlan counter table with interface name
- * @param msg_type dhcpv6 message type to be updated in counter
- *
- * @return none
- */
-void update_counter(std::string counterVlan, uint8_t msg_type);
-
-/* Helper functions */
-
-/**
- * @code std::string toString(uint16_t count);
- *
- * @brief convert uint16_t to string
- *
- * @param count count of messages in counter
- *
- * @return count in string
- */
-std::string toString(uint16_t count);
-
-/**
- * @code const struct ether_header *parse_ether_frame(const uint8_t *buffer, const uint8_t **out_end);
- *
- * @brief parse through ethernet frame
- *
- * @param *buffer message buffer
- * @param **out_end pointer
- *
- * @return ether_header end of ethernet header position
- */
-const struct ether_header *parse_ether_frame(const uint8_t *buffer, const uint8_t **out_end);
-
-/**
- * @code const struct ip6_hdr *parse_ip6_hdr(const uint8_t *buffer, const uint8_t **out_end);
- *
- * @brief parse through ipv6 header
- *
- * @param *buffer message buffer
- * @param **out_end pointer
- *
- * @return ip6_hdr end of ipv6 header position
- */
-const struct ip6_hdr *parse_ip6_hdr(const uint8_t *buffer, const uint8_t **out_end);
-
-/**
- * @code const struct udphdr *parse_udp(const uint8_t *buffer, const uint8_t **out_end);
- *
- * @brief parse through udp header
- *
- * @param *buffer message buffer
- * @param **out_end pointer
- *
- * @return udphdr end of udp header position
- */
-const struct udphdr *parse_udp(const uint8_t *buffer, const uint8_t **out_end);
-
-/**
- * @code const struct dhcpv6_msg *parse_dhcpv6_hdr(const uint8_t *buffer);
- *
- * @brief parse through dhcpv6 header
- *
- * @param *buffer message buffer
- * @param **out_end pointer
- *
- * @return dhcpv6_msg end of dhcpv6 header position
- */
-const struct dhcpv6_msg *parse_dhcpv6_hdr(const uint8_t *buffer);
-
-/**
- * @code const struct dhcpv6_relay_msg *parse_dhcpv6_relay(const uint8_t *buffer);
- *
- * @brief parse through dhcpv6 relay message
- *
- * @param *buffer message buffer
- * @param **out_end pointer
- *
- * @return dhcpv6_relay_msg start of dhcpv6 relay message or end of dhcpv6 message type position
- */
-const struct dhcpv6_relay_msg *parse_dhcpv6_relay(const uint8_t *buffer);
-
-/**
- * @code const struct dhcpv6_option *parse_dhcpv6_opt(const uint8_t *buffer, const uint8_t **out_end);
- *
- * @brief parse through dhcpv6 option
- *
- * @param *buffer message buffer
- * @param **out_end pointer
- *
- * @return dhcpv6_option end of dhcpv6 message option
- */
-const struct dhcpv6_option *parse_dhcpv6_opt(const uint8_t *buffer, const uint8_t **out_end);
-
-/**
- * @code void send_udp(int sock, uint8_t *buffer, struct sockaddr_in6 target, uint32_t n, relay_config *config, uint8_t msg_type);
- *
- * @brief send udp packet
- *
- * @param *buffer message buffer
- * @param sockaddr_in6 target target socket
- * @param n length of message
- * @param relay_config *config pointer to relay_config
- * @param uint8_t msg_type message type of dhcpv6 option of relayed message
- *
- * @return dhcpv6_option end of dhcpv6 message option
- */
-void send_udp(int sock, uint8_t *buffer, struct sockaddr_in6 target, uint32_t n, relay_config *config, uint8_t msg_type);
-
diff --git a/src/dhcp6relay/src/subdir.mk b/src/dhcp6relay/src/subdir.mk
deleted file mode 100644
index c6e784ef5504..000000000000
--- a/src/dhcp6relay/src/subdir.mk
+++ /dev/null
@@ -1,23 +0,0 @@
-CC := g++
-
-C_SRCS += \
-../src/relay.c \
-../src/configInterface.c \
-../src/main.c
-
-OBJS += \
-./src/relay.o \
-./src/configInterface.o \
-./src/main.o
-
-C_DEPS += \
-./src/relay.d \
-./src/configInterface.d \
-./src/main.d
-
-src/%.o: src/%.cpp
- @echo 'Building file: $<'
- @echo 'Invoking: GCC C++ Compiler'
- $(CC) -D__FILENAME__="$(subst src/,,$<)" $(CFLAGS) -c -fmessage-length=0 -MMD -MP -MF"$(@:%.o=%.d)" -MT"$(@)" -o "$@" "$<"
-\ @echo 'Finished building: $<'
- @echo ' '
diff --git a/src/dhcprelay b/src/dhcprelay
new file mode 160000
index 000000000000..04a2d4163940
--- /dev/null
+++ b/src/dhcprelay
@@ -0,0 +1 @@
+Subproject commit 04a2d4163940d3f70b2f2af5c69681edd4a1b0e1
diff --git a/src/sonic-config-engine/minigraph.py b/src/sonic-config-engine/minigraph.py
index 9ad536ad7cae..feaf3df76e2b 100644
--- a/src/sonic-config-engine/minigraph.py
+++ b/src/sonic-config-engine/minigraph.py
@@ -400,31 +400,6 @@ def parse_dpg(dpg, hname):
vlans[sonic_vlan_name] = vlan_attributes
dhcp_relay_table[sonic_vlan_name] = dhcp_attributes
- '''
- dhcp = child.find(str(QName(ns, "Dhcp")))
- dhcp_relay_table = {}
-
- if dhcp is not None:
- for vintf in dhcp.findall(str(QName(ns, "VlanInterface"))):
- vintfname = vintf.find(str(QName(ns, "Name"))).text
-
- dhcp_attributes = {}
-
- dhcp_node = vintf.find(str(QName(ns, "Dhcpv6Relays")))
- if dhcp_node is not None and dhcp_node.text is not None:
- dhcpservers = dhcp_node.text
- vdhcpserver_list = dhcpservers.split(';')
- dhcp_attributes['dhcpv6_servers'] = vdhcpserver_list
-
- option_linklayer_addr = vintf.find(str(QName(ns, "Dhcpv6OptionRfc6939")))
- if option_linklayer_addr is not None and option_linklayer_addr.text == "true":
- dhcp_attributes['dhcpv6_option|rfc6939_support'] = "true"
- elif option_linklayer_addr is not None and option_linklayer_addr.text == "false":
- dhcp_attributes['dhcpv6_option|rfc6939_support'] = "false"
-
- dhcp_relay_table[vintfname] = dhcp_attributes
- '''
-
acls = {}
for aclintf in aclintfs.findall(str(QName(ns, "AclInterface"))):
if aclintf.find(str(QName(ns, "InAcl"))) is not None:
@@ -1022,7 +997,7 @@ def parse_xml(filename, platform=None, port_config_file=None, asic_name=None):
elif child.tag == str(QName(ns, "UngDec")):
(u_neighbors, u_devices, _, _, _, _, _, _) = parse_png(child, hostname)
elif child.tag == str(QName(ns, "MetadataDeclaration")):
- (syslog_servers, dhcp_servers, dhcppv6_servers, ntp_servers, tacacs_servers, mgmt_routes, erspan_dst, deployment_id, region, cloudtype, downstream_subrole, qos_profile, resource_type) = parse_meta(child, hostname)
+ (syslog_servers, dhcp_servers, dhcpv6_servers, ntp_servers, tacacs_servers, mgmt_routes, erspan_dst, deployment_id, region, cloudtype, downstream_subrole, qos_profile, resource_type) = parse_meta(child, hostname)
elif child.tag == str(QName(ns, "LinkMetadataDeclaration")):
linkmetas = parse_linkmeta(child, hostname)
elif child.tag == str(QName(ns, "DeviceInfos")):
diff --git a/src/sonic-config-engine/tests/test_minigraph_case.py b/src/sonic-config-engine/tests/test_minigraph_case.py
index 8c4d638fa711..3ab949fbb0bb 100644
--- a/src/sonic-config-engine/tests/test_minigraph_case.py
+++ b/src/sonic-config-engine/tests/test_minigraph_case.py
@@ -83,21 +83,31 @@ def test_minigraph_vlans(self):
argument = '-m "' + self.sample_graph + '" -p "' + self.port_config + '" -v VLAN'
output = self.run_script(argument)
expected = {
- u'Vlan1000': {
- u'alias': 'ab1',
- u'dhcp_servers': [u'192.0.0.1', u'192.0.0.2'],
- u'dhcpv6_servers': [u'fc02:2000::1', u'fc02:2000::2'],
- u'vlanid': u'1000',
- u'members': [u'Ethernet8']
- },
- 'Vlan2000': {
- u'alias': 'ab2',
- u'dhcp_servers': ['192.0.0.3', '192.0.0.4'],
- u'members': ['Ethernet4'],
- u'dhcpv6_servers': [u'fc02:2000::3', u'fc02:2000::4'],
- u'vlanid': '2000'
- }
- }
+ 'Vlan1000': {
+ 'alias': 'ab1',
+ 'dhcp_servers': [
+ '192.0.0.1',
+ '192.0.0.2'
+ ],
+ 'dhcpv6_servers': [
+ 'fc02:2000::1',
+ 'fc02:2000::2'
+ ],
+ 'vlanid': '1000',
+ 'members': ['Ethernet8']
+ },
+ 'Vlan2000': {
+ 'alias': 'ab2',
+ 'dhcp_servers': [
+ '192.0.0.3',
+ '192.0.0.4'],
+ 'members': ['Ethernet4'],
+ 'dhcpv6_servers': [
+ 'fc02:2000::3',
+ 'fc02:2000::4'],
+ 'vlanid': '2000'
+ }
+ }
self.assertEqual(
utils.to_dict(output.strip()),
diff --git a/src/sonic-dhcp-relay b/src/sonic-dhcp-relay
deleted file mode 160000
index e2cd5851ddd9..000000000000
--- a/src/sonic-dhcp-relay
+++ /dev/null
@@ -1 +0,0 @@
-Subproject commit e2cd5851ddd9b6496b59b72e75aaba8e4d7f284d
From 81ff36a057c9f75ef760a75b5be179b5cd19d792 Mon Sep 17 00:00:00 2001
From: kellyyeh <42761586+kellyyeh@users.noreply.github.com>
Date: Tue, 11 Oct 2022 06:15:36 -0700
Subject: [PATCH 5/7] Add package dependency
---
rules/docker-dhcp-relay.mk | 2 +-
sonic-slave-stretch/Dockerfile.j2 | 9 ++++++++-
2 files changed, 9 insertions(+), 2 deletions(-)
diff --git a/rules/docker-dhcp-relay.mk b/rules/docker-dhcp-relay.mk
index 4182d3ec137f..8d44ee2a432b 100644
--- a/rules/docker-dhcp-relay.mk
+++ b/rules/docker-dhcp-relay.mk
@@ -6,7 +6,7 @@ DOCKER_DHCP_RELAY_DBG = $(DOCKER_DHCP_RELAY_STEM)-$(DBG_IMAGE_MARK).gz
$(DOCKER_DHCP_RELAY)_PATH = $(DOCKERS_PATH)/$(DOCKER_DHCP_RELAY_STEM)
-$(DOCKER_DHCP_RELAY)_DEPENDS += $(ISC_DHCP_RELAY) $(REDIS_TOOLS) $(SONIC_DHCPMON) $(SONIC_DHCPRELAY) $(LIBSWSSCOMMON)
+$(DOCKER_DHCP_RELAY)_DEPENDS += $(ISC_DHCP_RELAY) $(REDIS_TOOLS) $(LIBSWSSCOMMON) $(SONIC_DHCPMON) $(SONIC_DHCPRELAY)
$(DOCKER_DHCP_RELAY)_DBG_DEPENDS = $($(DOCKER_CONFIG_ENGINE_STRETCH)_DBG_DEPENDS)
$(DOCKER_DHCP_RELAY)_DBG_DEPENDS += $(ISC_DHCP_RELAY_DBG) $(SONIC_DHCPRELAY_DBG)
diff --git a/sonic-slave-stretch/Dockerfile.j2 b/sonic-slave-stretch/Dockerfile.j2
index a39f21be63aa..991eae773d6f 100644
--- a/sonic-slave-stretch/Dockerfile.j2
+++ b/sonic-slave-stretch/Dockerfile.j2
@@ -301,7 +301,14 @@ RUN apt-get update && apt-get install -y \
xxd \
# For DHCP Monitor tool
libexplain-dev \
- libevent-dev
+ libevent-dev \
+# For dhcp6relay
+ libboost-dev \
+ libboost-system-dev \
+ libboost-thread-dev \
+ libboost-atomic-dev \
+ libboost-chrono-dev \
+ libboost-date-time-dev
## Config dpkg
## install the configuration file if it’s currently missing
From 3f996df1c7827a465bf45f3c7f48fc78eac24c9c Mon Sep 17 00:00:00 2001
From: kellyyeh
Date: Sat, 22 Oct 2022 00:30:52 +0000
Subject: [PATCH 6/7] Clean Up
---
dockers/docker-dhcp-relay/dhcpv6-relay.agents.j2 | 3 ++-
.../tests/sample_output/docker-dhcp-relay.supervisord.conf | 1 -
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/dockers/docker-dhcp-relay/dhcpv6-relay.agents.j2 b/dockers/docker-dhcp-relay/dhcpv6-relay.agents.j2
index 3b14d11e3bcd..134280e52313 100644
--- a/dockers/docker-dhcp-relay/dhcpv6-relay.agents.j2
+++ b/dockers/docker-dhcp-relay/dhcpv6-relay.agents.j2
@@ -11,12 +11,13 @@
{% set _dummy = relay_for_ipv6.update({'flag': False}) %}
[program:dhcp6relay]
command=/usr/sbin/dhcp6relay
-
priority=3
autostart=false
autorestart=false
stdout_logfile=syslog
stderr_logfile=syslog
+dependent_startup=true
+dependent_startup_wait_for=start:exited
{% endif %}
{% endif %}
diff --git a/src/sonic-config-engine/tests/sample_output/docker-dhcp-relay.supervisord.conf b/src/sonic-config-engine/tests/sample_output/docker-dhcp-relay.supervisord.conf
index 27c409f45c14..4756773d05ec 100644
--- a/src/sonic-config-engine/tests/sample_output/docker-dhcp-relay.supervisord.conf
+++ b/src/sonic-config-engine/tests/sample_output/docker-dhcp-relay.supervisord.conf
@@ -56,7 +56,6 @@ dependent_startup_wait_for=start:exited
[program:dhcp6relay]
command=/usr/sbin/dhcp6relay
-
priority=3
autostart=false
autorestart=false
From 5bab10c0d6dc58b981544c5275635b4f858166e9 Mon Sep 17 00:00:00 2001
From: kellyyeh <42761586+kellyyeh@users.noreply.github.com>
Date: Fri, 21 Oct 2022 22:22:48 -0700
Subject: [PATCH 7/7] Update docker-dhcp-relay.supervisord.conf
---
.../tests/sample_output/docker-dhcp-relay.supervisord.conf | 2 ++
1 file changed, 2 insertions(+)
diff --git a/src/sonic-config-engine/tests/sample_output/docker-dhcp-relay.supervisord.conf b/src/sonic-config-engine/tests/sample_output/docker-dhcp-relay.supervisord.conf
index 4756773d05ec..3ade01edee2c 100644
--- a/src/sonic-config-engine/tests/sample_output/docker-dhcp-relay.supervisord.conf
+++ b/src/sonic-config-engine/tests/sample_output/docker-dhcp-relay.supervisord.conf
@@ -61,6 +61,8 @@ autostart=false
autorestart=false
stdout_logfile=syslog
stderr_logfile=syslog
+dependent_startup=true
+dependent_startup_wait_for=start:exited
[group:dhcpmon]
programs=dhcpmon-Vlan1000