Skip to content

Commit a2e0542

Browse files
kellyyehqiluo-msft
authored andcommitted
[dhcpmon] Open different socket for dual tor to enable interface filtering (#11201)
1 parent 6c2f99a commit a2e0542

File tree

9 files changed

+143
-38
lines changed

9 files changed

+143
-38
lines changed

rules/dhcpmon.mk

+1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ SONIC_DHCPMON_VERSION = 1.0.0-0
44
SONIC_DHCPMON_PKG_NAME = dhcpmon
55

66
SONIC_DHCPMON = sonic-$(SONIC_DHCPMON_PKG_NAME)_$(SONIC_DHCPMON_VERSION)_$(CONFIGURED_ARCH).deb
7+
$(SONIC_DHCPMON)_DEPENDS = $(LIBSWSSCOMMON) $(LIBHIREDIS) $(LIBSWSSCOMMON_DEV) $(LIBHIREDIS_DEV)
78
$(SONIC_DHCPMON)_SRC_PATH = $(SRC_PATH)/$(SONIC_DHCPMON_PKG_NAME)
89
SONIC_DPKG_DEBS += $(SONIC_DHCPMON)
910

src/dhcpmon/Makefile

+3-2
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,9 @@ RM := rm -rf
22
DHCPMON_TARGET := dhcpmon
33
CP := cp
44
MKDIR := mkdir
5-
CC := gcc
5+
CC := g++
66
MV := mv
7+
PWD := $(shell pwd)
78

89
# All of the sources participating in the build are defined here
910
-include src/subdir.mk
@@ -23,7 +24,7 @@ all: sonic-dhcpmon
2324
# Tool invocations
2425
sonic-dhcpmon: $(OBJS) $(USER_OBJS)
2526
@echo 'Building target: $@'
26-
@echo 'Invoking: GCC C Linker'
27+
@echo 'Invoking: G++ C Linker'
2728
$(CC) -o "$(DHCPMON_TARGET)" $(OBJS) $(USER_OBJS) $(LIBS)
2829
@echo 'Finished building target: $@'
2930
@echo ' '

src/dhcpmon/objects.mk

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
USER_OBJS :=
22

3-
LIBS := -levent -lexplain
3+
LIBS := -levent -lexplain -lswsscommon -pthread -lboost_thread -lboost_system -lhiredis
44

src/dhcpmon/src/dhcp_device.c renamed to src/dhcpmon/src/dhcp_device.cpp

+123-27
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@
2121
#include <libexplain/ioctl.h>
2222
#include <linux/filter.h>
2323
#include <netpacket/packet.h>
24+
#include "subscriberstatetable.h"
25+
#include "select.h"
2426

2527
#include "dhcp_device.h"
2628

@@ -49,34 +51,42 @@
4951
#define OP_JSET (BPF_JMP | BPF_JSET | BPF_K) /** bpf jset */
5052
#define OP_LDXB (BPF_LDX | BPF_B | BPF_MSH) /** bpf ldxb */
5153

54+
std::shared_ptr<swss::DBConnector> mStateDbPtr = std::make_shared<swss::DBConnector> ("STATE_DB", 0);
55+
std::shared_ptr<swss::Table> mStateDbMuxTablePtr = std::make_shared<swss::Table> (
56+
mStateDbPtr.get(), "HW_MUX_CABLE_TABLE"
57+
);
58+
swss::DBConnector configDb("CONFIG_DB", 0);
59+
5260
/** Berkeley Packet Filter program for "udp and (port 67 or port 68)".
5361
* This program is obtained using the following command tcpdump:
54-
* `tcpdump -dd "udp and (port 67 or port 68)"`
62+
* `tcpdump -dd "inbound and udp and (port 67 or port 68)"`
5563
*/
5664
static struct sock_filter dhcp_bpf_code[] = {
57-
{.code = OP_LDHA, .jt = 0, .jf = 0, .k = 0x0000000c}, // (000) ldh [12]
58-
{.code = OP_JEQ, .jt = 0, .jf = 7, .k = 0x000086dd}, // (001) jeq #0x86dd jt 2 jf 9
59-
{.code = OP_LDB, .jt = 0, .jf = 0, .k = 0x00000014}, // (002) ldb [20]
60-
{.code = OP_JEQ, .jt = 0, .jf = 18, .k = 0x00000011}, // (003) jeq #0x11 jt 4 jf 22
61-
{.code = OP_LDHA, .jt = 0, .jf = 0, .k = 0x00000036}, // (004) ldh [54]
62-
{.code = OP_JEQ, .jt = 15, .jf = 0, .k = 0x00000043}, // (005) jeq #0x43 jt 21 jf 6
63-
{.code = OP_JEQ, .jt = 14, .jf = 0, .k = 0x00000044}, // (006) jeq #0x44 jt 21 jf 7
64-
{.code = OP_LDHA, .jt = 0, .jf = 0, .k = 0x00000038}, // (007) ldh [56]
65-
{.code = OP_JEQ, .jt = 12, .jf = 11, .k = 0x00000043}, // (008) jeq #0x43 jt 21 jf 20
66-
{.code = OP_JEQ, .jt = 0, .jf = 12, .k = 0x00000800}, // (009) jeq #0x800 jt 10 jf 22
67-
{.code = OP_LDB, .jt = 0, .jf = 0, .k = 0x00000017}, // (010) ldb [23]
68-
{.code = OP_JEQ, .jt = 0, .jf = 10, .k = 0x00000011}, // (011) jeq #0x11 jt 12 jf 22
69-
{.code = OP_LDHA, .jt = 0, .jf = 0, .k = 0x00000014}, // (012) ldh [20]
70-
{.code = OP_JSET, .jt = 8, .jf = 0, .k = 0x00001fff}, // (013) jset #0x1fff jt 22 jf 14
71-
{.code = OP_LDXB, .jt = 0, .jf = 0, .k = 0x0000000e}, // (014) ldxb 4*([14]&0xf)
72-
{.code = OP_LDHI, .jt = 0, .jf = 0, .k = 0x0000000e}, // (015) ldh [x + 14]
73-
{.code = OP_JEQ, .jt = 4, .jf = 0, .k = 0x00000043}, // (016) jeq #0x43 jt 21 jf 17
74-
{.code = OP_JEQ, .jt = 3, .jf = 0, .k = 0x00000044}, // (017) jeq #0x44 jt 21 jf 18
75-
{.code = OP_LDHI, .jt = 0, .jf = 0, .k = 0x00000010}, // (018) ldh [x + 16]
76-
{.code = OP_JEQ, .jt = 1, .jf = 0, .k = 0x00000043}, // (019) jeq #0x43 jt 21 jf 20
77-
{.code = OP_JEQ, .jt = 0, .jf = 1, .k = 0x00000044}, // (020) jeq #0x44 jt 21 jf 22
78-
{.code = OP_RET, .jt = 0, .jf = 0, .k = 0x00040000}, // (021) ret #262144
79-
{.code = OP_RET, .jt = 0, .jf = 0, .k = 0x00000000}, // (022) ret #0
65+
{.code = OP_LDHA, .jt = 0, .jf = 0, .k = 0xfffff004}, // (000) ldh #fffff004
66+
{.code = OP_JEQ, .jt = 22, .jf = 0, .k = 0x00000004}, // (001) jeq #0x04 jt 22 jf 0
67+
{.code = OP_LDHA, .jt = 0, .jf = 0, .k = 0x0000000c}, // (002) ldh [12]
68+
{.code = OP_JEQ, .jt = 0, .jf = 7, .k = 0x000086dd}, // (003) jeq #0x86dd jt 2 jf 9
69+
{.code = OP_LDB, .jt = 0, .jf = 0, .k = 0x00000014}, // (004) ldb [20]
70+
{.code = OP_JEQ, .jt = 0, .jf = 18, .k = 0x00000011}, // (005) jeq #0x11 jt 4 jf 22
71+
{.code = OP_LDHA, .jt = 0, .jf = 0, .k = 0x00000036}, // (006) ldh [54]
72+
{.code = OP_JEQ, .jt = 15, .jf = 0, .k = 0x00000043}, // (007) jeq #0x43 jt 21 jf 6
73+
{.code = OP_JEQ, .jt = 14, .jf = 0, .k = 0x00000044}, // (008) jeq #0x44 jt 21 jf 7
74+
{.code = OP_LDHA, .jt = 0, .jf = 0, .k = 0x00000038}, // (009) ldh [56]
75+
{.code = OP_JEQ, .jt = 12, .jf = 11, .k = 0x00000043}, // (010) jeq #0x43 jt 21 jf 20
76+
{.code = OP_JEQ, .jt = 0, .jf = 12, .k = 0x00000800}, // (011) jeq #0x800 jt 10 jf 22
77+
{.code = OP_LDB, .jt = 0, .jf = 0, .k = 0x00000017}, // (012) ldb [23]
78+
{.code = OP_JEQ, .jt = 0, .jf = 10, .k = 0x00000011}, // (013) jeq #0x11 jt 12 jf 22
79+
{.code = OP_LDHA, .jt = 0, .jf = 0, .k = 0x00000014}, // (014) ldh [20]
80+
{.code = OP_JSET, .jt = 8, .jf = 0, .k = 0x00001fff}, // (015) jset #0x1fff jt 22 jf 14
81+
{.code = OP_LDXB, .jt = 0, .jf = 0, .k = 0x0000000e}, // (016) ldxb 4*([14]&0xf)
82+
{.code = OP_LDHI, .jt = 0, .jf = 0, .k = 0x0000000e}, // (017) ldh [x + 14]
83+
{.code = OP_JEQ, .jt = 4, .jf = 0, .k = 0x00000043}, // (018) jeq #0x43 jt 21 jf 17
84+
{.code = OP_JEQ, .jt = 3, .jf = 0, .k = 0x00000044}, // (019) jeq #0x44 jt 21 jf 18
85+
{.code = OP_LDHI, .jt = 0, .jf = 0, .k = 0x00000010}, // (020) ldh [x + 16]
86+
{.code = OP_JEQ, .jt = 1, .jf = 0, .k = 0x00000043}, // (021) jeq #0x43 jt 21 jf 20
87+
{.code = OP_JEQ, .jt = 0, .jf = 1, .k = 0x00000044}, // (022) jeq #0x44 jt 21 jf 22
88+
{.code = OP_RET, .jt = 0, .jf = 0, .k = 0x00040000}, // (023) ret #262144
89+
{.code = OP_RET, .jt = 0, .jf = 0, .k = 0x00000000}, // (024) ret #0
8090
};
8191

8292
/** Filter program socket struct */
@@ -176,7 +186,7 @@ static void read_callback(int fd, short event, void *arg)
176186
uint8_t *dhcphdr = context->buffer + DHCP_START_OFFSET;
177187
int dhcp_option_offset = DHCP_START_OFFSET + DHCP_OPTIONS_HEADER_SIZE;
178188

179-
if ((buffer_sz > UDP_START_OFFSET + sizeof(struct udphdr) + DHCP_OPTIONS_HEADER_SIZE) &&
189+
if (((unsigned)buffer_sz > UDP_START_OFFSET + sizeof(struct udphdr) + DHCP_OPTIONS_HEADER_SIZE) &&
180190
(ntohs(udp->len) > DHCP_OPTIONS_HEADER_SIZE)) {
181191
int dhcp_sz = ntohs(udp->len) < buffer_sz - UDP_START_OFFSET - sizeof(struct udphdr) ?
182192
ntohs(udp->len) : buffer_sz - UDP_START_OFFSET - sizeof(struct udphdr);
@@ -221,6 +231,87 @@ static void read_callback(int fd, short event, void *arg)
221231
}
222232
}
223233

234+
/**
235+
* @code read_callback_dual_tor(fd, event, arg);
236+
*
237+
* @brief callback for libevent which is called every time out in order to read queued packet capture when dual tor mode is enabled
238+
*
239+
* @param fd socket to read from
240+
* @param event libevent triggered event
241+
* @param arg user provided argument for callback (interface context)
242+
*
243+
* @return none
244+
*/
245+
static void read_callback_dual_tor(int fd, short event, void *arg)
246+
{
247+
dhcp_device_context_t *context = (dhcp_device_context_t*) arg;
248+
ssize_t buffer_sz;
249+
struct sockaddr_ll sll;
250+
socklen_t slen = sizeof sll;
251+
252+
while ((event == EV_READ) &&
253+
((buffer_sz = recvfrom(fd, context->buffer, context->snaplen, MSG_DONTWAIT, (struct sockaddr *)&sll, &slen)) > 0))
254+
{
255+
std::string member_table = std::string("VLAN_MEMBER|") + context->intf + "|";
256+
char interfaceName[IF_NAMESIZE];
257+
char *interface = if_indextoname(sll.sll_ifindex, interfaceName);
258+
std::string state;
259+
std::string intf(interface);
260+
mStateDbMuxTablePtr->hget(intf, "state", state);
261+
if (state != "standby" && configDb.exists(member_table.append(interface))) {
262+
struct ether_header *ethhdr = (struct ether_header*) context->buffer;
263+
struct ip *iphdr = (struct ip*) (context->buffer + IP_START_OFFSET);
264+
struct udphdr *udp = (struct udphdr*) (context->buffer + UDP_START_OFFSET);
265+
uint8_t *dhcphdr = context->buffer + DHCP_START_OFFSET;
266+
int dhcp_option_offset = DHCP_START_OFFSET + DHCP_OPTIONS_HEADER_SIZE;
267+
268+
if (((unsigned)buffer_sz > UDP_START_OFFSET + sizeof(struct udphdr) + DHCP_OPTIONS_HEADER_SIZE) &&
269+
(ntohs(udp->len) > DHCP_OPTIONS_HEADER_SIZE))
270+
{
271+
int dhcp_sz = ntohs(udp->len) < buffer_sz - UDP_START_OFFSET - sizeof(struct udphdr) ?
272+
ntohs(udp->len) : buffer_sz - UDP_START_OFFSET - sizeof(struct udphdr);
273+
int dhcp_option_sz = dhcp_sz - DHCP_OPTIONS_HEADER_SIZE;
274+
const u_char *dhcp_option = context->buffer + dhcp_option_offset;
275+
dhcp_packet_direction_t dir = (ethhdr->ether_shost[0] == context->mac[0] &&
276+
ethhdr->ether_shost[1] == context->mac[1] &&
277+
ethhdr->ether_shost[2] == context->mac[2] &&
278+
ethhdr->ether_shost[3] == context->mac[3] &&
279+
ethhdr->ether_shost[4] == context->mac[4] &&
280+
ethhdr->ether_shost[5] == context->mac[5]) ?
281+
DHCP_TX : DHCP_RX;
282+
int offset = 0;
283+
int stop_dhcp_processing = 0;
284+
while ((offset < (dhcp_option_sz + 1)) && dhcp_option[offset] != 255) {
285+
switch (dhcp_option[offset])
286+
{
287+
case 53:
288+
if (offset < (dhcp_option_sz + 2)) {
289+
handle_dhcp_option_53(context, &dhcp_option[offset], dir, iphdr, dhcphdr);
290+
}
291+
stop_dhcp_processing = 1; // break while loop since we are only interested in Option 53
292+
break;
293+
default:
294+
break;
295+
}
296+
297+
if (stop_dhcp_processing == 1) {
298+
break;
299+
}
300+
301+
if (dhcp_option[offset] == 0) { // DHCP Option Padding
302+
offset++;
303+
} else {
304+
offset += dhcp_option[offset + 1] + 2;
305+
}
306+
}
307+
} else {
308+
syslog(LOG_WARNING, "read_callback(%s): read length (%ld) is too small to capture DHCP options",
309+
context->intf, buffer_sz);
310+
}
311+
}
312+
}
313+
}
314+
224315
/**
225316
* @code dhcp_device_is_dhcp_inactive(counters);
226317
*
@@ -412,7 +503,7 @@ static int init_socket(dhcp_device_context_t *context, const char *intf)
412503

413504
struct sockaddr_ll addr;
414505
memset(&addr, 0, sizeof(addr));
415-
addr.sll_ifindex = if_nametoindex(intf);
506+
addr.sll_ifindex = 0; // any interface
416507
addr.sll_family = AF_PACKET;
417508
addr.sll_protocol = htons(ETH_P_ALL);
418509
if (bind(context->sock, (struct sockaddr *) &addr, sizeof(addr))) {
@@ -553,6 +644,7 @@ int dhcp_device_start_capture(dhcp_device_context_t *context,
553644
in_addr_t giaddr_ip)
554645
{
555646
int rv = -1;
647+
struct event *ev;
556648

557649
do {
558650
if (context == NULL) {
@@ -579,7 +671,11 @@ int dhcp_device_start_capture(dhcp_device_context_t *context,
579671
break;
580672
}
581673

582-
struct event *ev = event_new(base, context->sock, EV_READ | EV_PERSIST, read_callback, context);
674+
if (dual_tor_sock)
675+
ev = event_new(base, context->sock, EV_READ | EV_PERSIST, read_callback_dual_tor, context);
676+
else
677+
ev = event_new(base, context->sock, EV_READ | EV_PERSIST, read_callback, context);
678+
583679
if (ev == NULL) {
584680
syslog(LOG_ALERT, "event_new: failed to allocate memory for libevent event '%s'\n", strerror(errno));
585681
break;

src/dhcpmon/src/dhcp_device.h

+1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include <event2/bufferevent.h>
1717
#include <event2/buffer.h>
1818

19+
extern bool dual_tor_sock;
1920

2021
/**
2122
* DHCP message types

src/dhcpmon/src/dhcp_devman.c renamed to src/dhcpmon/src/dhcp_devman.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ void dhcp_devman_shutdown()
110110
int dhcp_devman_add_intf(const char *name, char intf_type)
111111
{
112112
int rv = -1;
113-
struct intf *dev = malloc(sizeof(struct intf));
113+
struct intf *dev = (struct intf*) malloc(sizeof(struct intf));
114114

115115
if (dev != NULL) {
116116
dev->name = name;
File renamed without changes.

src/dhcpmon/src/main.c renamed to src/dhcpmon/src/main.cpp

+6
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,12 @@
1616
#include <sys/types.h>
1717
#include <sys/stat.h>
1818
#include <unistd.h>
19+
#include "subscriberstatetable.h"
20+
#include "select.h"
1921

2022
#include "dhcp_mon.h"
2123
#include "dhcp_devman.h"
24+
#include "dhcp_device.h"
2225

2326
/** dhcpmon_default_snaplen: default snap length of packet being captured */
2427
static const size_t dhcpmon_default_snaplen = 65535;
@@ -29,6 +32,8 @@ static const uint32_t dhcpmon_default_health_check_window = 18;
2932
* with DHCP relay */
3033
static const uint32_t dhcpmon_default_unhealthy_max_count = 10;
3134

35+
bool dual_tor_sock = false;
36+
3237
/**
3338
* @code usage(prog);
3439
*
@@ -134,6 +139,7 @@ int main(int argc, char **argv)
134139
i += 2;
135140
break;
136141
case 'u':
142+
dual_tor_sock = true;
137143
if (dhcp_devman_setup_dual_tor_mode(argv[i + 1]) != 0) {
138144
usage(basename(argv[0]));
139145
}

src/dhcpmon/src/subdir.mk

+7-7
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
# Add inputs and outputs from these tool invocations to the build variables
2-
CC := gcc
2+
CC := g++
33

44
C_SRCS += \
5-
../src/dhcp_device.c \
6-
../src/dhcp_devman.c \
7-
../src/dhcp_mon.c \
8-
../src/main.c
5+
../src/dhcp_device.cpp \
6+
../src/dhcp_devman.cpp \
7+
../src/dhcp_mon.cpp \
8+
../src/main.cpp
99

1010
OBJS += \
1111
./src/dhcp_device.o \
@@ -21,9 +21,9 @@ C_DEPS += \
2121

2222

2323
# Each subdirectory must supply rules for building sources it contributes
24-
src/%.o: ../src/%.c
24+
src/%.o: src/%.cpp
2525
@echo 'Building file: $<'
2626
@echo 'Invoking: GCC C Compiler'
27-
$(CC) -O3 -g3 -Wall -c -fmessage-length=0 -MMD -MP -MF"$(@:%.o=%.d)" -MT"$(@)" -o "$@" "$<"
27+
$(CC) -O3 -g3 -Wall -I$(PWD)/../sonic-swss-common/common -c -fmessage-length=0 -MMD -MP -MF"$(@:%.o=%.d)" -MT"$(@)" -o "$@" "$<"
2828
@echo 'Finished building: $<'
2929
@echo ' '

0 commit comments

Comments
 (0)