Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Add DHCPv6 Relay Agent #8251

Merged
merged 16 commits into from
Aug 20, 2021
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions src/dhcp6relay/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
debian/*
!debian/changelog
!debian/compat
!debian/control
!debian/rules
42 changes: 42 additions & 0 deletions src/dhcp6relay/Makefile
Original file line number Diff line number Diff line change
@@ -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 -I $(PWD)/../sonic-swss-common/common
CFLAGS = -g -Wall -std=gnu11
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) -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 changes: 5 additions & 0 deletions src/dhcp6relay/debian/changelog
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
sonic-dhcp6relay (1.0.0-0) UNRELEASED; urgency=medium

* Initial release.

-- Kelly Yeh <kellyyeh@microsoft.com>
1 change: 1 addition & 0 deletions src/dhcp6relay/debian/compat
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
9
17 changes: 17 additions & 0 deletions src/dhcp6relay/debian/control
Original file line number Diff line number Diff line change
@@ -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
4 changes: 4 additions & 0 deletions src/dhcp6relay/debian/rules
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#!/usr/bin/make -f

%:
dh $@ --parallel
156 changes: 156 additions & 0 deletions src/dhcp6relay/src/configInterface.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
#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 deinitialize_swss()
*
* @brief initialize DB tables and start SWSS listening thread
*
* @return none
*/
void initialize_swss(std::vector<relay_config> *vlans, swss::DBConnector *db)
{
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 context 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 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)
{
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.interface = vlan;
for (auto &fieldValue: fieldValues) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we need to check the operation here if it is ADD/DEL

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The dhcpv6 server address are type string value. e.g.: "fc02:2000::1,fc02:2000::2"
HDEL would delete the entire string of addresses. HSET updates the list of server addresses.
When config_db updates the list of server addresses, all addresses are properly fetched and processed regardless new addresses are added/deleted. Therefore, I don't think there is a need to check for add/del

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can get the operation using std::string operation = kfvOp(entry);. This way we can tell the type of the record updates. I think they are SET/DEL operation.

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 == "options") {
std::stringstream ss(v);
while (ss.good()) {
std::string substr;
getline(ss, substr, ',');
if(substr == "dhcpv6_option|rfc6939_support")
intf.is_option_79 = true;
}
}
}
vlans->push_back(intf);
}
}

/**
*@code stopSwssNotificationPoll
*
*@brief stop SWSS listening thread
*
*@return none
*/
void stopSwssNotificationPoll() {
pollSwssNotifcation = false;
};
75 changes: 75 additions & 0 deletions src/dhcp6relay/src/configInterface.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
#include <boost/thread.hpp>
#include "subscriberstatetable.h"
#include "select.h"
#include "relay.h"

/**
* @code void deinitialize_swss()
*
* @brief initialize DB tables and start SWSS listening thread
*
* @return none
*/
void initialize_swss(std::vector<relay_config> *vlans, swss::DBConnector *db);

/**
* @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 context 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 context 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 changes: 18 additions & 0 deletions src/dhcp6relay/src/main.cpp
Original file line number Diff line number Diff line change
@@ -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, &state_db);
loop_relay(&vlans, &state_db);
}
catch (std::exception &e)
{
syslog(LOG_ERR, "An exception occurred.\n");
return 1;
}
return 0;
}
Loading