Skip to content
Merged
Show file tree
Hide file tree
Changes from 18 commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
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
28 changes: 25 additions & 3 deletions .azure-pipelines/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,10 @@ jobs:
libnl-route-3-dev \
libnl-genl-3-dev \
libnl-nf-3-dev \
redis-server
redis-server \
stgit \
cmake \
libpcap-dev
sudo sed -ri 's/^# unixsocket/unixsocket/' /etc/redis/redis.conf
sudo sed -ri 's/^unixsocketperm .../unixsocketperm 777/' /etc/redis/redis.conf
sudo sed -ri 's/redis-server.sock/redis.sock/' /etc/redis/redis.conf
Expand Down Expand Up @@ -103,17 +106,36 @@ jobs:
dpkg-buildpackage -us -uc -b -j$(nproc)
cp ../*.deb $(Build.ArtifactStagingDirectory)
workingDirectory: dhcp6relay
displayName: "Compile sonic dhcp-relay"
displayName: "Compile sonic dhcp6relay"
- script: |
rm ../*.deb || true
# Configure git identity for patch application
git config --global user.email "build@sonic.net"
git config --global user.name "SONiC Build"
dpkg-buildpackage -us -uc -b -j$(nproc)
cp ../*.deb $(Build.ArtifactStagingDirectory)
workingDirectory: dhcp4relay
displayName: "Compile sonic dhcp4relay"
- publish: $(Build.ArtifactStagingDirectory)
artifact: sonic-dhcp-relay.${{ parameters.arch }}
displayName: "Archive dhcp-relay debian packages"
- task: PublishTestResults@2
inputs:
testResultsFiles: build-test/dhcp6relay-test-test-result.xml
testResultsFiles: |
build-test/dhcp6relay-test-test-result.xml
build-test/dhcp4relay-test-test-result.xml
- ${{ if and(eq(parameters.arch, 'amd64'), parameters.codeCoverage) }}:
- task: PublishCodeCoverageResults@1
inputs:
summaryFileLocation: build-test/dhcp6relay-test-code-coverage.xml
pathToSources: $(Build.SourcesDirectory)
reportDirectory: $(Build.SourcesDirectory)/build-test
codeCoverageTool: 'Cobertura'
displayName: "Publish dhcp6relay code coverage"
- task: PublishCodeCoverageResults@1
inputs:
summaryFileLocation: build-test/dhcp4relay-test-code-coverage.xml
pathToSources: $(Build.SourcesDirectory)
reportDirectory: $(Build.SourcesDirectory)/build-test
codeCoverageTool: 'Cobertura'
displayName: "Publish dhcp4relay code coverage"
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,8 @@ dhcp6relay/debian/*
!dhcp6relay/debian/compat
!dhcp6relay/debian/control
!dhcp6relay/debian/rules
dhcp4relay/debian/*
!dhcp4relay/debian/changelog
!dhcp4relay/debian/compat
!dhcp4relay/debian/control
!dhcp4relay/debian/rules
106 changes: 106 additions & 0 deletions dhcp4relay/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
.ONESHELL:
SHELL = /bin/bash

RM := rm -rf
WORKING_DIR := $(abspath .)
BUILD_DIR := build
BUILD_TEST_DIR := build-test
DHCP4RELAY_TARGET := $(BUILD_DIR)/dhcp4relay
DHCP4RELAY_TEST_TARGET := $(BUILD_TEST_DIR)/dhcp4relay-test
CP := cp
MKDIR := mkdir
MV := mv
FIND := find
GCOVR := gcovr

LD_PCAPPLUSPLUS_LIB := -lPcap++ -lPacket++ -lCommon++

#pcap plus plus zip file pcappp_v24.09.zip
PCAPPPVAR := 24.09
PCAPPPZIP_FILE := pcappp_v${PCAPPPVAR}.zip
PCAPPLUSPLUS_DIR := $(WORKING_DIR)/PcapPlusPlus-$(PCAPPPVAR)
PCAPPP_DONE = $(WORKING_DIR)/pcappp.stamp
INCLUDE_DIR = $(PCAPPLUSPLUS_DIR)/include
LIB_DIR = $(PCAPPLUSPLUS_DIR)/lib

override LDLIBS += -levent -lhiredis -lswsscommon -pthread -lboost_thread -lboost_system $(LD_PCAPPLUSPLUS_LIB) -lpcap
override CPPFLAGS += -Wall -std=c++17 -fPIE -I/usr/include/swss -I$(INCLUDE_DIR)
override CPPFLAGS += -MMD -MP -MF"$(@:%.o=%.d)" -MT"$(@)"
override LDFLAGS += -L$(LIB_DIR) -Wl,-rpath=$(abspath $(LIB_DIR))
CPPFLAGS_TEST := --coverage -fprofile-arcs -ftest-coverage -fprofile-generate -fsanitize=address -DUNIT_TEST
LDLIBS_TEST := --coverage -lgtest -lgmock -pthread -lstdc++fs -fsanitize=address
PWD := $(shell pwd)

.PHONY: $(PCAPPP_DONE)
$(PCAPPP_DONE):

# Remove stale files
rm -rf $(PCAPPLUSPLUS_DIR)

unzip ${PCAPPPZIP_FILE}
pushd $(PCAPPLUSPLUS_DIR)

# Create a git repository here for stg to apply patches
git init
git add -f *
git commit -qm "initial commit"

# Apply patches
stg init
stg import -s ../patch/series
popd

cd $(PCAPPLUSPLUS_DIR) && cmake -S . -B build && cmake --build build
cd build && make && sudo cmake --install .

touch $@

all: $(DHCP4RELAY_TARGET) $(DHCP4RELAY_TEST_TARGET)

-include src/subdir.mk
-include test/subdir.mk

# Use different build directories based on whether it's a regular build or a
# test build. This is because in the test build, code coverage is enabled,
# which means the object files that get built will be different
OBJS = $(SRCS:%.cpp=$(BUILD_DIR)/%.o)
TEST_OBJS = $(TEST_SRCS:%.cpp=$(BUILD_TEST_DIR)/%.o)

ifneq ($(MAKECMDGOALS),clean)
-include $(OBJS:%.o=%.d)
-include $(TEST_OBJS:%.o=%.d)
endif

$(BUILD_DIR)/%.o: %.cpp
@mkdir -p $(@D)
$(CXX) $(CXXFLAGS) $(CPPFLAGS) -c -o $@ $<

$(DHCP4RELAY_TARGET): $(PCAPPP_DONE) $(OBJS)
$(CXX) $(LDFLAGS) $^ $(LDLIBS) -o $@

$(BUILD_TEST_DIR)/%.o: %.cpp
@mkdir -p $(@D)
$(CXX) $(CXXFLAGS) $(CPPFLAGS) $(CPPFLAGS_TEST) $(LDLIBS) -c -o $@ $<

$(DHCP4RELAY_TEST_TARGET): $(TEST_OBJS)
$(CXX) $(LDFLAGS) $^ $(LDLIBS) $(LDLIBS_TEST) -o $@

test: $(DHCP4RELAY_TEST_TARGET)
sudo ASAN_OPTIONS=detect_leaks=0 ./$(DHCP4RELAY_TEST_TARGET) --gtest_output=xml:$(DHCP4RELAY_TEST_TARGET)-test-result.xml || true
$(GCOVR) -r ./ --html --html-details -o $(DHCP4RELAY_TEST_TARGET)-code-coverage.html
$(GCOVR) -r ./ --xml-pretty -o $(DHCP4RELAY_TEST_TARGET)-code-coverage.xml

install: $(DHCP4RELAY_TARGET)
install -D $(DHCP4RELAY_TARGET) $(DESTDIR)/usr/sbin/$(notdir $(DHCP4RELAY_TARGET))

uninstall:
$(RM) $(DESTDIR)/usr/sbin/$(notdir $(DHCP4RELAY_TARGET))

clean:
-$(RM) $(BUILD_DIR) $(BUILD_TEST_DIR) *.html *.xml
$(FIND) . -name *.gcda -exec rm -f {} \;
$(FIND) . -name *.gcno -exec rm -f {} \;
$(FIND) . -name *.gcov -exec rm -f {} \;
-@echo ' '

.PHONY: all clean test install uninstall
5 changes: 5 additions & 0 deletions dhcp4relay/debian/changelog
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
sonic-dhcp4relay (1.0.0-0) UNRELEASED; urgency=medium

* Initial release.

-- Ashutosh Agrawal <ashu@cisco.com> Thu, 16 Jan 2025 09:11:40 -0700
1 change: 1 addition & 0 deletions dhcp4relay/debian/compat
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
12
14 changes: 14 additions & 0 deletions dhcp4relay/debian/control
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
Source: sonic-dhcp4relay
Section: devel
Priority: optional
Maintainer: Ashutosh Agrawal <ashu@cisco.com>
Build-Depends: debhelper (>= 12.0.0), libevent-dev, libboost-thread-dev, libboost-system-dev, libswsscommon-dev
Standards-Version: 3.9.3
Homepage: https://github.com/Azure/sonic-buildimage
XS-Go-Import-Path: github.com/Azure/sonic-buildimage

Package: sonic-dhcp4relay
Architecture: any
Built-Using: ${misc:Built-Using}
Depends: ${shlibs:Depends}
Description: SONiC DHCPv4 Relay
6 changes: 6 additions & 0 deletions dhcp4relay/debian/rules
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#!/usr/bin/make -f

export DEB_BUILD_MAINT_OPTIONS=hardening=+all

%:
dh $@ --parallel
15 changes: 15 additions & 0 deletions dhcp4relay/patch/0001-dhcpv4-relay-accept-random-src-port.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
diff --git a/PcapPlusPlus-24.09/Packet++/header/DhcpLayer.h b/PcapPlusPlus-24.09/Packet++/header/DhcpLayer.h
index 435becb..282d739 100644
--- a/PcapPlusPlus-24.09/Packet++/header/DhcpLayer.h
+++ b/PcapPlusPlus-24.09/Packet++/header/DhcpLayer.h
@@ -881,8 +881,8 @@ namespace pcpp

bool DhcpLayer::isDhcpPorts(uint16_t portSrc, uint16_t portDst)
{
- return ((portSrc == 68 && portDst == 67) || (portSrc == 67 && portDst == 68) ||
- (portSrc == 67 && portDst == 67));
+ // src port can be any ephemeral port so removing the check
+ return ((portDst == 67) || (portDst == 68));
}

} // namespace pcpp
1 change: 1 addition & 0 deletions dhcp4relay/patch/series
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
0001-dhcpv4-relay-accept-random-src-port.patch
Binary file added dhcp4relay/pcappp_v24.09.zip

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Why is there a random zip file added here? If this is actually needed as a build dependency, compile it as a separate application or add it into the slave container.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

@saiarcot895 Since, we are applying a minor patch on top of the downloaded PCAP++ source code, we didn't include it in the slave container. But I've modified the build process to now download the file instead of including it in the code. Please review the changes in this PR

Binary file not shown.
78 changes: 78 additions & 0 deletions dhcp4relay/src/dhcp4_sender.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
#include "dhcp4_sender.h"

#include <arpa/inet.h>
#include <errno.h>
#include <syslog.h>

#include <cstring>

/**
* @code bool send_udp(int sock, uint8_t *buffer, struct sockaddr_in target, uint32_t len, const char* src_ip, bool use_src_ip);
*
* @brief send udp packet and return true if successful
*
* @param *buffer message buffer
* @param sockaddr_in target target socket
* @param len length of message
* @param src_ip source IP address as string (optional)
* @param use_src_ip if true, use src_ip as source address
*
* @return boolean True if packet successfully sent
*/
#ifndef UNIT_TEST
bool send_udp(int sock, uint8_t *buffer, struct sockaddr_in target, uint32_t len, in_addr src_ip, bool use_src_ip) {
/* Pad additional bytes if length is lesser than 300
* to make DHCP packet length to minimum of 300 bytes */
if (len < BOOTP_MIN_LEN) {
auto pad_len = BOOTP_MIN_LEN - len;
memset(buffer+len, 0, pad_len);
len = BOOTP_MIN_LEN;
}

if (use_src_ip && src_ip.s_addr != 0) {
// Enable IP_PKTINFO on the socket
int on = 1;
setsockopt(sock, IPPROTO_IP, IP_PKTINFO, &on, sizeof(on));

struct msghdr msg = {};
struct iovec iov = {};
char cmsgbuf[CMSG_SPACE(sizeof(struct in_pktinfo))];

iov.iov_base = buffer;
iov.iov_len = len;

msg.msg_name = &target;
msg.msg_namelen = sizeof(target);
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
msg.msg_control = cmsgbuf;
msg.msg_controllen = sizeof(cmsgbuf);

struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg);
cmsg->cmsg_level = IPPROTO_IP;
cmsg->cmsg_type = IP_PKTINFO;
cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));

struct in_pktinfo *pktinfo = (struct in_pktinfo *)CMSG_DATA(cmsg);
memset(pktinfo, 0, sizeof(struct in_pktinfo));
pktinfo->ipi_spec_dst = src_ip;

msg.msg_controllen = cmsg->cmsg_len;

if (sendmsg(sock, &msg, 0) == -1) {
char server_addr[INET_ADDRSTRLEN];
inet_ntop(AF_INET, &(target.sin_addr), server_addr, INET_ADDRSTRLEN);
syslog(LOG_ERR, "sendmsg: Failed to send to target address: %s, error: %s\n", server_addr, strerror(errno));
return false;
}
} else {
if (sendto(sock, buffer, len, 0, (const struct sockaddr *)&target, sizeof(target)) == -1) {
char server_addr[INET_ADDRSTRLEN];
inet_ntop(AF_INET, &(target.sin_addr), server_addr, INET_ADDRSTRLEN);
syslog(LOG_ERR, "sendto: Failed to send to target address: %s, error: %s\n", server_addr, strerror(errno));
return false;
}
}
return true;
}
#endif
22 changes: 22 additions & 0 deletions dhcp4relay/src/dhcp4_sender.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#pragma once

#include <netinet/in.h>
#include <sys/socket.h>

#include <string>

#define BOOTP_MIN_LEN 300
/**
* @code bool send_udp(int sock, uint8_t *buffer, struct sockaddr_in target, uint32_t len, const char* src_ip, bool use_src_ip);
*
* @brief send udp packet and return true if successful
*
* @param *buffer message buffer
* @param sockaddr_in target target socket
* @param len length of message
* @param src_ip source IP address as string (optional)
* @param use_src_ip if true, use src_ip as source address
*
* @return boolean True if packet successfully sent
*/
bool send_udp(int sock, uint8_t *buffer, struct sockaddr_in target, uint32_t len, in_addr src_ip, bool use_src_ip);
Loading
Loading