This reverts commit 9db2e21c69
.
This commit is contained in:
parent
a668ccf6df
commit
d892214209
7
.gitmodules
vendored
7
.gitmodules
vendored
@ -90,10 +90,3 @@
|
||||
path = src/linkmgrd
|
||||
url = https://github.com/Azure/sonic-linkmgrd.git
|
||||
branch = 202012
|
||||
[submodule "src/dhcprelay"]
|
||||
path = src/dhcprelay
|
||||
url = https://github.com/sonic-net/sonic-dhcp-relay.git
|
||||
branch = 202012
|
||||
[submodule "sonic-dhcp-relay"]
|
||||
path = sonic-dhcp-relay
|
||||
url = https://github.com/kellyyeh/sonic-dhcp-relay.git
|
||||
|
9
rules/dhcp6relay.dep
Normal file
9
rules/dhcp6relay.dep
Normal file
@ -0,0 +1,9 @@
|
||||
|
||||
SPATH := $($(SONIC_DHCP6RELAY)_SRC_PATH)
|
||||
DEP_FILES := $(SONIC_COMMON_FILES_LIST) rules/dhcp6relay.mk rules/dhcp6relay.dep
|
||||
DEP_FILES += $(SONIC_COMMON_BASE_FILES_LIST)
|
||||
DEP_FILES += $(shell git ls-files $(SPATH))
|
||||
|
||||
$(SONIC_DHCP6RELAY)_CACHE_MODE := GIT_CONTENT_SHA
|
||||
$(SONIC_DHCP6RELAY)_DEP_FLAGS := $(SONIC_COMMON_FLAGS_LIST)
|
||||
$(SONIC_DHCP6RELAY)_DEP_FILES := $(DEP_FILES)
|
12
rules/dhcp6relay.mk
Normal file
12
rules/dhcp6relay.mk
Normal file
@ -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)-dbgsym_$(SONIC_DHCP6RELAY_VERSION)_$(CONFIGURED_ARCH).deb
|
||||
$(eval $(call add_derived_package,$(SONIC_DHCP6RELAY),$(SONIC_DHCP6RELAY_DBG)))
|
@ -1,11 +0,0 @@
|
||||
|
||||
SPATH := $($(SONIC_DHCPRELAY)_SRC_PATH)
|
||||
DEP_FILES := $(SONIC_COMMON_FILES_LIST) rules/dhcprelay.mk rules/dhcprelay.dep
|
||||
DEP_FILES += $(SONIC_COMMON_BASE_FILES_LIST)
|
||||
SMDEP_FILES := $(addprefix $(SPATH)/,$(shell cd $(SPATH) && git ls-files))
|
||||
|
||||
$(SONIC_DHCPRELAY)_CACHE_MODE := GIT_CONTENT_SHA
|
||||
$(SONIC_DHCPRELAY)_DEP_FLAGS := $(SONIC_COMMON_FLAGS_LIST)
|
||||
$(SONIC_DHCPRELAY)_DEP_FILES := $(DEP_FILES)
|
||||
$(SONIC_DHCPRELAY)_SMDEP_FILES := $(SMDEP_FILES)
|
||||
$(SONIC_DHCPRELAY)_SMDEP_PATHS := $(SPATH)
|
@ -1,12 +0,0 @@
|
||||
# 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)_$(CONFIGURED_ARCH).deb
|
||||
$(eval $(call add_derived_package,$(SONIC_DHCPRELAY),$(SONIC_DHCPRELAY_DBG)))
|
@ -6,10 +6,10 @@ 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) $(SONIC_DHCPMON) $(SONIC_DHCPRELAY) $(LIBSWSSCOMMON)
|
||||
$(DOCKER_DHCP_RELAY)_DEPENDS += $(ISC_DHCP_RELAY) $(SONIC_DHCPMON) $(SONIC_DHCP6RELAY) $(LIBSWSSCOMMON)
|
||||
|
||||
$(DOCKER_DHCP_RELAY)_DBG_DEPENDS = $($(DOCKER_CONFIG_ENGINE_BUSTER)_DBG_DEPENDS)
|
||||
$(DOCKER_DHCP_RELAY)_DBG_DEPENDS += $(ISC_DHCP_RELAY_DBG) $(SONIC_DHCPRELAY_DBG) $(SONIC_DHCPMON_DBG)
|
||||
$(DOCKER_DHCP_RELAY)_DBG_DEPENDS += $(ISC_DHCP_RELAY_DBG) $(SONIC_DHCP6RELAY_DBG) $(SONIC_DHCPMON_DBG)
|
||||
|
||||
$(DOCKER_DHCP_RELAY)_DBG_IMAGE_PACKAGES = $($(DOCKER_CONFIG_ENGINE_BUSTER)_DBG_IMAGE_PACKAGES)
|
||||
|
||||
|
5
src/dhcp6relay/.gitignore
vendored
Normal file
5
src/dhcp6relay/.gitignore
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
debian/*
|
||||
!debian/changelog
|
||||
!debian/compat
|
||||
!debian/control
|
||||
!debian/rules
|
42
src/dhcp6relay/Makefile
Normal file
42
src/dhcp6relay/Makefile
Normal file
@ -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++17 -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
|
||||
|
||||
|
5
src/dhcp6relay/debian/changelog
Normal file
5
src/dhcp6relay/debian/changelog
Normal file
@ -0,0 +1,5 @@
|
||||
sonic-dhcp6relay (1.0.0-0) UNRELEASED; urgency=medium
|
||||
|
||||
* Initial release.
|
||||
|
||||
-- Kelly Yeh <kellyyeh@microsoft.com>
|
1
src/dhcp6relay/debian/compat
Normal file
1
src/dhcp6relay/debian/compat
Normal file
@ -0,0 +1 @@
|
||||
9
|
17
src/dhcp6relay/debian/control
Normal file
17
src/dhcp6relay/debian/control
Normal file
@ -0,0 +1,17 @@
|
||||
Source: sonic-dhcp6relay
|
||||
Section: devel
|
||||
Priority: optional
|
||||
Maintainer: Kelly Yeh <kellyyeh@microsoft.com>
|
||||
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.1-6,
|
||||
libboost-thread1.71.0,
|
||||
libboost-system1.71.0
|
||||
Description: SONiC DHCPv6 Relay
|
6
src/dhcp6relay/debian/rules
Executable file
6
src/dhcp6relay/debian/rules
Executable file
@ -0,0 +1,6 @@
|
||||
#!/usr/bin/make -f
|
||||
|
||||
export DEB_BUILD_MAINT_OPTIONS=hardening=+all
|
||||
|
||||
%:
|
||||
dh $@ --parallel
|
152
src/dhcp6relay/src/configInterface.cpp
Normal file
152
src/dhcp6relay/src/configInterface.cpp
Normal file
@ -0,0 +1,152 @@
|
||||
#include <sstream>
|
||||
#include <syslog.h>
|
||||
#include <algorithm>
|
||||
#include "configInterface.h"
|
||||
|
||||
constexpr auto DEFAULT_TIMEOUT_MSEC = 1000;
|
||||
|
||||
bool pollSwssNotifcation = true;
|
||||
std::shared_ptr<boost::thread> mSwssThreadPtr;
|
||||
|
||||
std::shared_ptr<swss::DBConnector> configDbPtr = std::make_shared<swss::DBConnector> ("CONFIG_DB", 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<relay_config> *vlans)
|
||||
{
|
||||
try {
|
||||
swssSelect.addSelectable(&ipHelpersTable);
|
||||
get_dhcp(vlans);
|
||||
mSwssThreadPtr = std::make_shared<boost::thread> (&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<relay_config> *vlans)
|
||||
*
|
||||
* @brief initialize and get vlan table information from DHCP_RELAY
|
||||
*
|
||||
* @return none
|
||||
*/
|
||||
void get_dhcp(std::vector<relay_config> *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<swss::Selectable *> (&ipHelpersTable)) {
|
||||
handleRelayNotification(ipHelpersTable, vlans);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @code void handleSwssNotification(std::vector<relay_config> *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<relay_config> *vlans)
|
||||
{
|
||||
while (pollSwssNotifcation) {
|
||||
get_dhcp(vlans);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @code void handleRelayNotification(swss::SubscriberStateTable &ipHelpersTable, std::vector<relay_config> *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<relay_config> *vlans)
|
||||
{
|
||||
std::deque<swss::KeyOpFieldsValuesTuple> entries;
|
||||
|
||||
ipHelpersTable.pops(entries);
|
||||
processRelayNotification(entries, vlans);
|
||||
}
|
||||
|
||||
/**
|
||||
* @code void processRelayNotification(std::deque<swss::KeyOpFieldsValuesTuple> &entries, std::vector<relay_config> *vlans)
|
||||
*
|
||||
* @brief process DHCPv6 relay servers and options configuration change notification
|
||||
*
|
||||
* @param entries queue of std::tuple<std::string, std::string, std::vector<FieldValueTuple>> entries in DHCP table
|
||||
* @param vlans list of vlans/argument config that contains strings of server and option
|
||||
*
|
||||
* @return none
|
||||
*/
|
||||
void processRelayNotification(std::deque<swss::KeyOpFieldsValuesTuple> &entries, std::vector<relay_config> *vlans)
|
||||
{
|
||||
std::vector<std::string> servers;
|
||||
|
||||
for (auto &entry: entries) {
|
||||
std::string vlan = kfvKey(entry);
|
||||
std::string operation = kfvOp(entry);
|
||||
std::vector<swss::FieldValueTuple> fieldValues = kfvFieldsValues(entry);
|
||||
|
||||
relay_config intf;
|
||||
intf.is_option_79 = true;
|
||||
intf.interface = vlan;
|
||||
intf.db = nullptr;
|
||||
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;
|
||||
};
|
75
src/dhcp6relay/src/configInterface.h
Normal file
75
src/dhcp6relay/src/configInterface.h
Normal file
@ -0,0 +1,75 @@
|
||||
#include <boost/thread.hpp>
|
||||
#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<relay_config> *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<relay_config> *vlans)
|
||||
*
|
||||
* @brief initialize and get vlan information from DHCP_RELAY
|
||||
*
|
||||
* @return none
|
||||
*/
|
||||
void get_dhcp(std::vector<relay_config> *vlans);
|
||||
|
||||
/**
|
||||
* @code void handleSwssNotification(std::vector<relay_config> *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<relay_config> *vlans);
|
||||
|
||||
/**
|
||||
* @code void handleRelayNotification(swss::SubscriberStateTable &ipHelpersTable, std::vector<relay_config> *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<relay_config> *vlans);
|
||||
|
||||
/**
|
||||
* @code void processRelayNotification(std::deque<swss::KeyOpFieldsValuesTuple> &entries, std::vector<relay_config> *vlans)
|
||||
*
|
||||
* @brief process DHCPv6 relay servers and options configuration change notification
|
||||
*
|
||||
* @param entries queue of std::tuple<std::string, std::string, std::vector<FieldValueTuple>> entries in DHCP table
|
||||
* @param context list of vlans/argument config that contains strings of server and option
|
||||
*
|
||||
* @return none
|
||||
*/
|
||||
void processRelayNotification(std::deque<swss::KeyOpFieldsValuesTuple> &entries, std::vector<relay_config> *vlans);
|
||||
|
||||
/**
|
||||
*@code stopSwssNotificationPoll
|
||||
*
|
||||
*@brief stop SWSS listening thread
|
||||
*
|
||||
*@return none
|
||||
*/
|
||||
void stopSwssNotificationPoll();
|
18
src/dhcp6relay/src/main.cpp
Normal file
18
src/dhcp6relay/src/main.cpp
Normal file
@ -0,0 +1,18 @@
|
||||
#include <stdlib.h>
|
||||
#include <syslog.h>
|
||||
#include "configInterface.h"
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
try {
|
||||
std::vector<relay_config> vlans;
|
||||
swss::DBConnector state_db("STATE_DB", 0);
|
||||
initialize_swss(&vlans);
|
||||
loop_relay(&vlans, &state_db);
|
||||
}
|
||||
catch (std::exception &e)
|
||||
{
|
||||
syslog(LOG_ERR, "An exception occurred.\n");
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
861
src/dhcp6relay/src/relay.cpp
Normal file
861
src/dhcp6relay/src/relay.cpp
Normal file
@ -0,0 +1,861 @@
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <event.h>
|
||||
#include <sstream>
|
||||
#include <event2/event.h>
|
||||
#include <event2/bufferevent.h>
|
||||
#include <syslog.h>
|
||||
#include <signal.h>
|
||||
|
||||
#include "configdb.h"
|
||||
#include "sonicv2connector.h"
|
||||
#include "dbconnector.h"
|
||||
#include "configInterface.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|";
|
||||
|
||||
/* 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<int, std::string> counterMap = {{DHCPv6_MESSAGE_TYPE_UNKNOWN, "Unknown"},
|
||||
{DHCPv6_MESSAGE_TYPE_SOLICIT, "Solicit"},
|
||||
{DHCPv6_MESSAGE_TYPE_ADVERTISE, "Advertise"},
|
||||
{DHCPv6_MESSAGE_TYPE_REQUEST, "Request"},
|
||||
{DHCPv6_MESSAGE_TYPE_CONFIRM, "Confirm"},
|
||||
{DHCPv6_MESSAGE_TYPE_RENEW, "Renew"},
|
||||
{DHCPv6_MESSAGE_TYPE_REBIND, "Rebind"},
|
||||
{DHCPv6_MESSAGE_TYPE_REPLY, "Reply"},
|
||||
{DHCPv6_MESSAGE_TYPE_RELEASE, "Release"},
|
||||
{DHCPv6_MESSAGE_TYPE_DECLINE, "Decline"},
|
||||
{DHCPv6_MESSAGE_TYPE_RECONFIGURE, "Reconfigure"},
|
||||
{DHCPv6_MESSAGE_TYPE_INFORMATION_REQUEST, "Information-Request"},
|
||||
{DHCPv6_MESSAGE_TYPE_RELAY_FORW, "Relay-Forward"},
|
||||
{DHCPv6_MESSAGE_TYPE_RELAY_REPL, "Relay-Reply"},
|
||||
{DHCPv6_MESSAGE_TYPE_MALFORMED, "Malformed"}};
|
||||
|
||||
/**
|
||||
* @code void initialize_counter(swss::DBConnector *db, std::string counterVlan);
|
||||
*
|
||||
* @brief initialize the counter by each Vlan
|
||||
*
|
||||
* @param swss::DBConnector *db state_db connector
|
||||
* @param counterVlan counter table with interface name
|
||||
*
|
||||
* @return none
|
||||
*/
|
||||
void initialize_counter(swss::DBConnector *db, std::string counterVlan) {
|
||||
db->hset(counterVlan, "Unknown", toString(counters[DHCPv6_MESSAGE_TYPE_UNKNOWN]));
|
||||
db->hset(counterVlan, "Solicit", toString(counters[DHCPv6_MESSAGE_TYPE_SOLICIT]));
|
||||
db->hset(counterVlan, "Advertise", toString(counters[DHCPv6_MESSAGE_TYPE_ADVERTISE]));
|
||||
db->hset(counterVlan, "Request", toString(counters[DHCPv6_MESSAGE_TYPE_REQUEST]));
|
||||
db->hset(counterVlan, "Confirm", toString(counters[DHCPv6_MESSAGE_TYPE_CONFIRM]));
|
||||
db->hset(counterVlan, "Renew", toString(counters[DHCPv6_MESSAGE_TYPE_RENEW]));
|
||||
db->hset(counterVlan, "Rebind", toString(counters[DHCPv6_MESSAGE_TYPE_REBIND]));
|
||||
db->hset(counterVlan, "Reply", toString(counters[DHCPv6_MESSAGE_TYPE_REPLY]));
|
||||
db->hset(counterVlan, "Release", toString(counters[DHCPv6_MESSAGE_TYPE_RELEASE]));
|
||||
db->hset(counterVlan, "Decline", toString(counters[DHCPv6_MESSAGE_TYPE_DECLINE]));
|
||||
db->hset(counterVlan, "Reconfigure", toString(counters[DHCPv6_MESSAGE_TYPE_RECONFIGURE]));
|
||||
db->hset(counterVlan, "Information-Request", toString(counters[DHCPv6_MESSAGE_TYPE_INFORMATION_REQUEST]));
|
||||
db->hset(counterVlan, "Relay-Forward", toString(counters[DHCPv6_MESSAGE_TYPE_RELAY_FORW]));
|
||||
db->hset(counterVlan, "Relay-Reply", toString(counters[DHCPv6_MESSAGE_TYPE_RELAY_REPL]));
|
||||
db->hset(counterVlan, "Malformed", toString(counters[DHCPv6_MESSAGE_TYPE_MALFORMED]));
|
||||
}
|
||||
|
||||
/**
|
||||
* @code void update_counter(swss::DBConnector *db, std::string CounterVlan, uint8_t msg_type);
|
||||
*
|
||||
* @brief update the counter in state_db with count of each DHCPv6 message type
|
||||
*
|
||||
* @param swss::DBConnector *db state_db connector
|
||||
* @param counterVlan counter table with interface name
|
||||
* @param msg_type dhcpv6 message type to be updated in counter
|
||||
*
|
||||
* @return none
|
||||
*/
|
||||
void update_counter(swss::DBConnector *db, std::string counterVlan, uint8_t msg_type) {
|
||||
db->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) {
|
||||
auto option = (const struct dhcpv6_option *)buffer;
|
||||
uint8_t size = 4; // option-code + option-len
|
||||
size += *(uint16_t *)(buffer);
|
||||
(*out_end) = buffer + size + ntohs(option->option_length);
|
||||
|
||||
return option;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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(config->db, 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 && 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 on interface %s\n", config->interface.c_str());
|
||||
}
|
||||
|
||||
if ((*server_sock= socket(AF_INET6, SOCK_DGRAM, 0)) == -1) {
|
||||
syslog(LOG_ERR, "socket: Failed to create socket on interface %s\n", config->interface.c_str());
|
||||
}
|
||||
|
||||
int retry = 0;
|
||||
bool bind_addr = false;
|
||||
bool bind_ll_addr = false;
|
||||
do {
|
||||
if (getifaddrs(&ifa) == -1) {
|
||||
syslog(LOG_WARNING, "getifaddrs: Unable to get network interfaces with %s\n", strerror(errno));
|
||||
}
|
||||
else {
|
||||
ifa_tmp = ifa;
|
||||
while (ifa_tmp) {
|
||||
if (ifa_tmp->ifa_addr && (ifa_tmp->ifa_addr->sa_family == AF_INET6) && (strcmp(ifa_tmp->ifa_name, config->interface.c_str()) == 0)) {
|
||||
struct sockaddr_in6 *in6 = (struct sockaddr_in6*) ifa_tmp->ifa_addr;
|
||||
if(!IN6_IS_ADDR_LINKLOCAL(&in6->sin6_addr)) {
|
||||
bind_addr = true;
|
||||
in6->sin6_family = AF_INET6;
|
||||
in6->sin6_port = htons(RELAY_PORT);
|
||||
addr = *in6;
|
||||
}
|
||||
if(IN6_IS_ADDR_LINKLOCAL(&in6->sin6_addr)) {
|
||||
bind_ll_addr = true;
|
||||
in6->sin6_family = AF_INET6;
|
||||
in6->sin6_port = htons(RELAY_PORT);
|
||||
ll_addr = *in6;
|
||||
}
|
||||
}
|
||||
ifa_tmp = ifa_tmp->ifa_next;
|
||||
}
|
||||
freeifaddrs(ifa);
|
||||
}
|
||||
|
||||
if (bind_addr && bind_ll_addr) {
|
||||
break;
|
||||
}
|
||||
|
||||
syslog(LOG_WARNING, "Retry #%d to bind to sockets on interface %s\n", ++retry, config->interface.c_str());
|
||||
sleep(5);
|
||||
} while (retry < 6);
|
||||
|
||||
if ((!bind_addr) || (bind(*local_sock, (sockaddr *)&addr, sizeof(addr)) == -1)) {
|
||||
syslog(LOG_ERR, "bind: Failed to bind socket to global ipv6 address on interface %s after %d retries with %s\n", config->interface.c_str(), retry, strerror(errno));
|
||||
}
|
||||
|
||||
if ((!bind_ll_addr) || (bind(*server_sock, (sockaddr *)&ll_addr, sizeof(addr)) == -1)) {
|
||||
syslog(LOG_ERR, "bind: Failed to bind socket to link local ipv6 address on interface %s after %d retries with %s\n", config->interface.c_str(), retry, strerror(errno));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @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];
|
||||
std::string counterVlan = counter_table;
|
||||
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);
|
||||
auto option_position = current_position + sizeof(struct dhcpv6_msg);
|
||||
|
||||
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;
|
||||
}
|
||||
case DHCPv6_MESSAGE_TYPE_SOLICIT:
|
||||
case DHCPv6_MESSAGE_TYPE_REQUEST:
|
||||
case DHCPv6_MESSAGE_TYPE_CONFIRM:
|
||||
case DHCPv6_MESSAGE_TYPE_RENEW:
|
||||
case DHCPv6_MESSAGE_TYPE_REBIND:
|
||||
case DHCPv6_MESSAGE_TYPE_RELEASE:
|
||||
case DHCPv6_MESSAGE_TYPE_DECLINE:
|
||||
case DHCPv6_MESSAGE_TYPE_INFORMATION_REQUEST:
|
||||
{
|
||||
while (option_position - message_buffer < len) {
|
||||
auto option = parse_dhcpv6_opt(option_position, &tmp);
|
||||
option_position = tmp;
|
||||
if (ntohs(option->option_code) > DHCPv6_OPTION_LIMIT) {
|
||||
counters[DHCPv6_MESSAGE_TYPE_MALFORMED]++;
|
||||
update_counter(config->db, counterVlan.append(config->interface), DHCPv6_MESSAGE_TYPE_MALFORMED);
|
||||
syslog(LOG_WARNING, "DHCPv6 option is invalid or contains malformed payload\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
counters[msg->msg_type]++;
|
||||
update_counter(config->db, counterVlan.append(config->interface), msg->msg_type);
|
||||
relay_client(config->local_sock, current_position, ntohs(udp_header->len) - sizeof(udphdr), ip_header, ether_header, config);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
syslog(LOG_WARNING, "DHCPv6 client message received was not relayed\n");
|
||||
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(config->db, 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<relay_config> *vlans, swss::DBConnector *db);
|
||||
*
|
||||
* @brief main loop: configure sockets, create libevent base, start server listener thread
|
||||
*
|
||||
* @param vlans list of vlans retrieved from config_db
|
||||
* @param db state_db connector
|
||||
*/
|
||||
void loop_relay(std::vector<relay_config> *vlans, swss::DBConnector *db) {
|
||||
std::vector<int> 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());
|
||||
config->db = db;
|
||||
|
||||
std::string counterVlan = counter_table;
|
||||
initialize_counter(config->db, 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<sockets.size(); i++) {
|
||||
close(sockets.at(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @code shutdown();
|
||||
*
|
||||
* @brief free signals and terminate threads
|
||||
*/
|
||||
void shutdown() {
|
||||
event_del(ev_sigint);
|
||||
event_del(ev_sigterm);
|
||||
event_free(ev_sigint);
|
||||
event_free(ev_sigterm);
|
||||
event_base_free(base);
|
||||
deinitialize_swss();
|
||||
}
|
358
src/dhcp6relay/src/relay.h
Normal file
358
src/dhcp6relay/src/relay.h
Normal file
@ -0,0 +1,358 @@
|
||||
#include <arpa/inet.h>
|
||||
#include <net/if.h>
|
||||
#include <linux/if_packet.h>
|
||||
#include <netinet/if_ether.h>
|
||||
#include <netinet/ip6.h>
|
||||
#include <netinet/udp.h>
|
||||
#include <ifaddrs.h>
|
||||
#include <linux/filter.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <event2/util.h>
|
||||
|
||||
|
||||
#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 DHCPv6_OPTION_LIMIT 56 // DHCPv6 option code greater than 56 are currently unassigned
|
||||
|
||||
#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_RECONFIGURE = 10,
|
||||
DHCPv6_MESSAGE_TYPE_INFORMATION_REQUEST = 11,
|
||||
DHCPv6_MESSAGE_TYPE_RELAY_FORW = 12,
|
||||
DHCPv6_MESSAGE_TYPE_RELAY_REPL = 13,
|
||||
DHCPv6_MESSAGE_TYPE_MALFORMED = 14,
|
||||
|
||||
DHCPv6_MESSAGE_TYPE_COUNT
|
||||
} dhcp_message_type_t;
|
||||
|
||||
struct relay_config {
|
||||
int local_sock;
|
||||
int server_sock;
|
||||
int filter;
|
||||
sockaddr_in6 link_address;
|
||||
swss::DBConnector *db;
|
||||
std::string interface;
|
||||
std::vector<std::string> servers;
|
||||
std::vector<sockaddr_in6> servers_sock;
|
||||
bool is_option_79;
|
||||
};
|
||||
|
||||
|
||||
/* DHCPv6 messages and options */
|
||||
|
||||
struct dhcpv6_msg {
|
||||
uint8_t msg_type;
|
||||
uint8_t xid[3];
|
||||
};
|
||||
|
||||
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<arg_config> *vlans, swss::DBConnector *db);
|
||||
*
|
||||
* @brief main loop: configure sockets, create libevent base, start server listener thread
|
||||
*
|
||||
* @param vlans list of vlans retrieved from config_db
|
||||
* @param db state_db connector
|
||||
*/
|
||||
void loop_relay(std::vector<relay_config> *vlans, swss::DBConnector *db);
|
||||
|
||||
/**
|
||||
* @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(swss::DBConnector *db, std::string counterVlan);
|
||||
*
|
||||
* @brief initialize the counter by each Vlan
|
||||
*
|
||||
* @param swss::DBConnector *db state_db connector
|
||||
* @param counterVlan counter table with interface name
|
||||
*
|
||||
* @return none
|
||||
*/
|
||||
void initialize_counter(swss::DBConnector *db, std::string counterVlan);
|
||||
|
||||
/**
|
||||
* @code void update_counter(swss::DBConnector *db, std::string CounterVlan, uint8_t msg_type);
|
||||
*
|
||||
* @brief update the counter in state_db with count of each DHCPv6 message type
|
||||
*
|
||||
* @param swss::DBConnector *db state_db connector
|
||||
* @param counterVlan counter table with interface name
|
||||
* @param msg_type dhcpv6 message type to be updated in counter
|
||||
*
|
||||
* @return none
|
||||
*/
|
||||
void update_counter(swss::DBConnector *db, 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);
|
||||
|
23
src/dhcp6relay/src/subdir.mk
Normal file
23
src/dhcp6relay/src/subdir.mk
Normal file
@ -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 ' '
|
@ -1 +0,0 @@
|
||||
Subproject commit 40ad1676e4d07c3eec2153017997bb04b33a94c8
|
Loading…
Reference in New Issue
Block a user