Skip to content

Add DHCPv6 Relay Agent #8251

New issue

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

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

Already on GitHub? Sign in to your account

Merged
merged 16 commits into from
Aug 20, 2021
Merged
Show file tree
Hide file tree
Changes from 2 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
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 <[email protected]>
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 <[email protected]>
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
7 changes: 7 additions & 0 deletions src/dhcp6relay/debian/rules
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#!/usr/bin/make -f

DEB_CFLAGS_APPEND=-std=gnu11
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 add this flag to CFLAGS in Makefile above.

export DEB_CFLAGS_APPEND

%:
dh $@ --parallel
137 changes: 137 additions & 0 deletions src/dhcp6relay/src/configInterface.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
#include <sstream>
#include <syslog.h>
#include <algorithm>
#include "configInterface.h"

constexpr auto DEFAULT_TIMEOUT_MSEC = 1000;

bool mPollSwssNotifcation = true;
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 drop the letter m as it is normally used to indicate class member.

std::shared_ptr<boost::thread> mSwssThreadPtr;

//
// ---> initialize();
//
// initialize DB tables and start SWSS listening thread
//
void initialize_swss(arg_config *context)
{
try {
mSwssThreadPtr = std::make_shared<boost::thread> (&handleSwssNotification, context);
}
catch (const std::bad_alloc &e) {
syslog(LOG_ERR, "Failed allocate memory. Exception details: %s", e.what());
}
}

//
// ---> deinitialize();
//
// deinitialize DB interface and join SWSS listening thread
//
void deinitialize_swss()
{
stopSwssNotificationPoll();
mSwssThreadPtr->interrupt();
}

/**
* @code void handleSwssNotification(arg_config *context)
*
* @brief main thread for handling SWSS notification
*
* @param context argument config that contains strings of server and option
*
* @return none
*/
void handleSwssNotification(arg_config *context)
{
std::shared_ptr<swss::DBConnector> configDbPtr = std::make_shared<swss::DBConnector> ("CONFIG_DB", 0);
swss::SubscriberStateTable ipHelpersTable(configDbPtr.get(), "DHCP");
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 add DHCP as a table name in schema.h file.


swss::Select swssSelect;
swssSelect.addSelectable(&ipHelpersTable);
while (mPollSwssNotifcation) {
swss::Selectable *selectable;
int ret = swssSelect.select(&selectable, DEFAULT_TIMEOUT_MSEC);
if (ret == swss::Select::ERROR) {
syslog(LOG_WARNING, "Select: returned ERROR");
continue;
} else if (ret == swss::Select::TIMEOUT) {
continue;
}
if (selectable == static_cast<swss::Selectable *> (&ipHelpersTable)) {
handleRelayNotification(ipHelpersTable, context);
}
}
}

/**
* @code void handleRelayNotification(swss::SubscriberStateTable &ipHelpersTable, arg_config context)
*
* @brief handles DHCPv6 relay configuration change notification
*
* @param ipHelpersTable DHCP table
* @param context argument config that contains strings of server and option
*
* @return none
*/
void handleRelayNotification(swss::SubscriberStateTable &ipHelpersTable, arg_config *context)
{
std::deque<swss::KeyOpFieldsValuesTuple> entries;

ipHelpersTable.pops(entries);
processRelayNotification(entries, context);
}

/**
* @code void processRelayNotification(std::deque<swss::KeyOpFieldsValuesTuple> &entries, arg_config context)
*
* @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 argument config that contains strings of server and option
*
* @return none
*/
void processRelayNotification(std::deque<swss::KeyOpFieldsValuesTuple> &entries, arg_config *context)
{
std::vector<std::string> servers;

for (auto &entry: entries) {
std::string vlan = kfvKey(entry);
std::vector<swss::FieldValueTuple> fieldValues = kfvFieldsValues(entry);

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, ',');
context->servers.push_back(substr);
}
}
if(f == "options") {
std::stringstream ss(v);
while (ss.good()) {
std::string substr;
getline(ss, substr, ',');
if(substr == "79")
Copy link
Contributor

Choose a reason for hiding this comment

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

is the option 79 name up-to-date?

context->is_option_79 = true;
}
}
}
}
}

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

void initialize_swss(arg_config *context);
Copy link
Contributor

Choose a reason for hiding this comment

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

please add doxygen comments to functions in this file.


void deinitialize_swss();

void handleSwssNotification(arg_config *context);

void handleRelayNotification(swss::SubscriberStateTable &configMuxTable, arg_config *context);

void processRelayNotification(std::deque<swss::KeyOpFieldsValuesTuple> &entries, arg_config *context);

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 "configInterface.h"

int main(int argc, char *argv[]) {
try {
auto parser = ArgumentParser();
parser.parse_args(argc, argv);
auto context = parser.get_arg();
initialize_swss(&context);
loop_relay(&context);
}
catch (std::exception &e)
{
printf("Usage: -i <interface> -o <option>\n");
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: we are not using cli args anymore.

return 1;
}
return 0;
}
Loading