[dhcpmon] Fix dhcpmon socket filter and tx count issue (#13065) (#13441)

Why I did it
Fix issue caused by dualtor support PR [dhcpmon] Open different socket for dual tor to enable interface filtering #11201
Improve code
How I did it
On single ToR, packets received count was duplicated due to socket filter set to "inbound"
Tx count not increasing due to filter set to "inbound". Added an outbound socket to count tx packets
Added vlan member interface mapping for Ethernet interface to vlan interface lookup in reference to PR Fix multiple vlan issue sonic-dhcp-relay#27
Exit when socket fails to initialize to allow dhcp_relay docker to restart
How to verify it
Tested on vstestbed single tor and dual tor, sent packets and verify printed out dhcpmon rx and tx counters is correct

Correct number of tx increases
Tx does not increase when ToR is on standby
This commit is contained in:
kellyyeh 2023-01-30 09:51:06 -08:00 committed by GitHub
parent 7448f7bc2d
commit 1354033f90
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 186 additions and 142 deletions

View File

@ -41,6 +41,7 @@
#define DHCP_OPTIONS_HEADER_SIZE 240 #define DHCP_OPTIONS_HEADER_SIZE 240
/** Offset of DHCP GIADDR */ /** Offset of DHCP GIADDR */
#define DHCP_GIADDR_OFFSET 24 #define DHCP_GIADDR_OFFSET 24
#define CLIENT_IF_PREFIX "Ethernet"
#define OP_LDHA (BPF_LD | BPF_H | BPF_ABS) /** bpf ldh Abs */ #define OP_LDHA (BPF_LD | BPF_H | BPF_ABS) /** bpf ldh Abs */
#define OP_LDHI (BPF_LD | BPF_H | BPF_IND) /** bpf ldh Ind */ #define OP_LDHI (BPF_LD | BPF_H | BPF_IND) /** bpf ldh Ind */
@ -51,19 +52,54 @@
#define OP_JSET (BPF_JMP | BPF_JSET | BPF_K) /** bpf jset */ #define OP_JSET (BPF_JMP | BPF_JSET | BPF_K) /** bpf jset */
#define OP_LDXB (BPF_LDX | BPF_B | BPF_MSH) /** bpf ldxb */ #define OP_LDXB (BPF_LDX | BPF_B | BPF_MSH) /** bpf ldxb */
std::shared_ptr<swss::DBConnector> mConfigDbPtr = std::make_shared<swss::DBConnector> ("CONFIG_DB", 0);
std::shared_ptr<swss::DBConnector> mStateDbPtr = std::make_shared<swss::DBConnector> ("STATE_DB", 0); std::shared_ptr<swss::DBConnector> mStateDbPtr = std::make_shared<swss::DBConnector> ("STATE_DB", 0);
std::shared_ptr<swss::Table> mStateDbMuxTablePtr = std::make_shared<swss::Table> ( std::shared_ptr<swss::Table> mStateDbMuxTablePtr = std::make_shared<swss::Table> (
mStateDbPtr.get(), "HW_MUX_CABLE_TABLE" mStateDbPtr.get(), "HW_MUX_CABLE_TABLE"
); );
swss::DBConnector configDb("CONFIG_DB", 0);
/* interface to vlan mapping */
std::unordered_map<std::string, std::string> vlan_map;
/** Berkeley Packet Filter program for "udp and (port 67 or port 68)".
* This program is obtained using the following command tcpdump:
* `tcpdump -dd "outbound and udp and (port 67 or port 68)"`
*/
static struct sock_filter dhcp_outbound_bpf_code[] = {
{.code = OP_LDHA, .jt = 0, .jf = 0, .k = 0xfffff004}, // (000) ldh #fffff004
{.code = OP_JEQ, .jt = 0, .jf = 22, .k = 0x00000004}, // (001) jeq #0x04 jt 0 jf 22
{.code = OP_LDHA, .jt = 0, .jf = 0, .k = 0x0000000c}, // (002) ldh [12]
{.code = OP_JEQ, .jt = 0, .jf = 7, .k = 0x000086dd}, // (003) jeq #0x86dd jt 2 jf 9
{.code = OP_LDB, .jt = 0, .jf = 0, .k = 0x00000014}, // (004) ldb [20]
{.code = OP_JEQ, .jt = 0, .jf = 18, .k = 0x00000011}, // (005) jeq #0x11 jt 4 jf 22
{.code = OP_LDHA, .jt = 0, .jf = 0, .k = 0x00000036}, // (006) ldh [54]
{.code = OP_JEQ, .jt = 15, .jf = 0, .k = 0x00000043}, // (007) jeq #0x43 jt 21 jf 6
{.code = OP_JEQ, .jt = 14, .jf = 0, .k = 0x00000044}, // (008) jeq #0x44 jt 21 jf 7
{.code = OP_LDHA, .jt = 0, .jf = 0, .k = 0x00000038}, // (009) ldh [56]
{.code = OP_JEQ, .jt = 12, .jf = 11, .k = 0x00000043}, // (010) jeq #0x43 jt 21 jf 20
{.code = OP_JEQ, .jt = 0, .jf = 12, .k = 0x00000800}, // (011) jeq #0x800 jt 10 jf 22
{.code = OP_LDB, .jt = 0, .jf = 0, .k = 0x00000017}, // (012) ldb [23]
{.code = OP_JEQ, .jt = 0, .jf = 10, .k = 0x00000011}, // (013) jeq #0x11 jt 12 jf 22
{.code = OP_LDHA, .jt = 0, .jf = 0, .k = 0x00000014}, // (014) ldh [20]
{.code = OP_JSET, .jt = 8, .jf = 0, .k = 0x00001fff}, // (015) jset #0x1fff jt 22 jf 14
{.code = OP_LDXB, .jt = 0, .jf = 0, .k = 0x0000000e}, // (016) ldxb 4*([14]&0xf)
{.code = OP_LDHI, .jt = 0, .jf = 0, .k = 0x0000000e}, // (017) ldh [x + 14]
{.code = OP_JEQ, .jt = 4, .jf = 0, .k = 0x00000043}, // (018) jeq #0x43 jt 21 jf 17
{.code = OP_JEQ, .jt = 3, .jf = 0, .k = 0x00000044}, // (019) jeq #0x44 jt 21 jf 18
{.code = OP_LDHI, .jt = 0, .jf = 0, .k = 0x00000010}, // (020) ldh [x + 16]
{.code = OP_JEQ, .jt = 1, .jf = 0, .k = 0x00000043}, // (021) jeq #0x43 jt 21 jf 20
{.code = OP_JEQ, .jt = 0, .jf = 1, .k = 0x00000044}, // (022) jeq #0x44 jt 21 jf 22
{.code = OP_RET, .jt = 0, .jf = 0, .k = 0x00040000}, // (023) ret #262144
{.code = OP_RET, .jt = 0, .jf = 0, .k = 0x00000000}, // (024) ret #0
};
/** Berkeley Packet Filter program for "udp and (port 67 or port 68)". /** Berkeley Packet Filter program for "udp and (port 67 or port 68)".
* This program is obtained using the following command tcpdump: * This program is obtained using the following command tcpdump:
* `tcpdump -dd "inbound and udp and (port 67 or port 68)"` * `tcpdump -dd "inbound and udp and (port 67 or port 68)"`
*/ */
static struct sock_filter dhcp_bpf_code[] = { static struct sock_filter dhcp_inbound_bpf_code[] = {
{.code = OP_LDHA, .jt = 0, .jf = 0, .k = 0xfffff004}, // (000) ldh #fffff004 {.code = OP_LDHA, .jt = 0, .jf = 0, .k = 0xfffff004}, // (000) ldh #fffff004
{.code = OP_JEQ, .jt = 22, .jf = 0, .k = 0x00000004}, // (001) jeq #0x04 jt 22 jf 0 {.code = OP_JEQ, .jt = 22, .jf = 0, .k = 0x00000004}, // (001) jeq #0x04 jt 22 jf 0
{.code = OP_LDHA, .jt = 0, .jf = 0, .k = 0x0000000c}, // (002) ldh [12] {.code = OP_LDHA, .jt = 0, .jf = 0, .k = 0x0000000c}, // (002) ldh [12]
{.code = OP_JEQ, .jt = 0, .jf = 7, .k = 0x000086dd}, // (003) jeq #0x86dd jt 2 jf 9 {.code = OP_JEQ, .jt = 0, .jf = 7, .k = 0x000086dd}, // (003) jeq #0x86dd jt 2 jf 9
{.code = OP_LDB, .jt = 0, .jf = 0, .k = 0x00000014}, // (004) ldb [20] {.code = OP_LDB, .jt = 0, .jf = 0, .k = 0x00000014}, // (004) ldb [20]
@ -90,8 +126,11 @@ static struct sock_filter dhcp_bpf_code[] = {
}; };
/** Filter program socket struct */ /** Filter program socket struct */
static struct sock_fprog dhcp_sock_bfp = { static struct sock_fprog dhcp_outbound_sock_bfp = {
.len = sizeof(dhcp_bpf_code) / sizeof(*dhcp_bpf_code), .filter = dhcp_bpf_code .len = sizeof(dhcp_outbound_bpf_code) / sizeof(*dhcp_outbound_bpf_code), .filter = dhcp_outbound_bpf_code
};
static struct sock_fprog dhcp_inbound_sock_bfp = {
.len = sizeof(dhcp_inbound_bpf_code) / sizeof(*dhcp_inbound_bpf_code), .filter = dhcp_inbound_bpf_code
}; };
/** Aggregate device of DHCP interfaces. It contains aggregate counters from /** Aggregate device of DHCP interfaces. It contains aggregate counters from
@ -107,6 +146,17 @@ static dhcp_message_type_t monitored_msgs[] = {
DHCP_MESSAGE_TYPE_ACK DHCP_MESSAGE_TYPE_ACK
}; };
void update_vlan_mapping(std::string vlan, std::shared_ptr<swss::DBConnector> mConfigDbPtr) {
auto match_pattern = std::string("VLAN_MEMBER|") + vlan + std::string("|*");
auto keys = mConfigDbPtr->keys(match_pattern);
for (auto &itr : keys) {
auto found = itr.find_last_of('|');
auto interface = itr.substr(found + 1);
vlan_map[interface] = vlan;
syslog(LOG_INFO, "add <%s, %s> into interface vlan map\n", interface.c_str(), vlan.c_str());
}
}
/** Number of monitored DHCP message type */ /** Number of monitored DHCP message type */
static uint8_t monitored_msg_sz = sizeof(monitored_msgs) / sizeof(*monitored_msgs); static uint8_t monitored_msg_sz = sizeof(monitored_msgs) / sizeof(*monitored_msgs);
@ -163,78 +213,62 @@ static void handle_dhcp_option_53(dhcp_device_context_t *context,
} }
/** /**
* @code read_callback(fd, event, arg); * @code client_packet_handler(dhcp_device_context_t *context, ssize_t buffer_sz);
* *
* @brief callback for libevent which is called every time out in order to read queued packet capture * @brief packet handler to process received rx and tx packets
* *
* @param fd socket to read from * @param context pointer to device (interface) context
* @param event libevent triggered event * @param buffer_sz buffer that stores received packet data
* @param arg user provided argument for callback (interface context)
* *
* @return none * @return none
*/ */
static void read_callback(int fd, short event, void *arg) static void client_packet_handler(dhcp_device_context_t *context, ssize_t buffer_sz)
{ {
dhcp_device_context_t *context = (dhcp_device_context_t*) arg; struct ether_header *ethhdr = (struct ether_header*) context->buffer;
ssize_t buffer_sz; struct ip *iphdr = (struct ip*) (context->buffer + IP_START_OFFSET);
struct udphdr *udp = (struct udphdr*) (context->buffer + UDP_START_OFFSET);
uint8_t *dhcphdr = context->buffer + DHCP_START_OFFSET;
int dhcp_option_offset = DHCP_START_OFFSET + DHCP_OPTIONS_HEADER_SIZE;
while ((event == EV_READ) && if (((unsigned)buffer_sz > UDP_START_OFFSET + sizeof(struct udphdr) + DHCP_OPTIONS_HEADER_SIZE) &&
((buffer_sz = recv(fd, context->buffer, context->snaplen, MSG_DONTWAIT)) > 0)) { (ntohs(udp->len) > DHCP_OPTIONS_HEADER_SIZE))
struct ether_header *ethhdr = (struct ether_header*) context->buffer; {
struct ip *iphdr = (struct ip*) (context->buffer + IP_START_OFFSET); int dhcp_sz = ntohs(udp->len) < buffer_sz - UDP_START_OFFSET - sizeof(struct udphdr) ?
struct udphdr *udp = (struct udphdr*) (context->buffer + UDP_START_OFFSET); ntohs(udp->len) : buffer_sz - UDP_START_OFFSET - sizeof(struct udphdr);
uint8_t *dhcphdr = context->buffer + DHCP_START_OFFSET; int dhcp_option_sz = dhcp_sz - DHCP_OPTIONS_HEADER_SIZE;
int dhcp_option_offset = DHCP_START_OFFSET + DHCP_OPTIONS_HEADER_SIZE; const u_char *dhcp_option = context->buffer + dhcp_option_offset;
dhcp_packet_direction_t dir = (ethhdr->ether_shost[0] == context->mac[0] &&
if (((unsigned)buffer_sz > UDP_START_OFFSET + sizeof(struct udphdr) + DHCP_OPTIONS_HEADER_SIZE) && ethhdr->ether_shost[1] == context->mac[1] &&
(ntohs(udp->len) > DHCP_OPTIONS_HEADER_SIZE)) { ethhdr->ether_shost[2] == context->mac[2] &&
int dhcp_sz = ntohs(udp->len) < buffer_sz - UDP_START_OFFSET - sizeof(struct udphdr) ? ethhdr->ether_shost[3] == context->mac[3] &&
ntohs(udp->len) : buffer_sz - UDP_START_OFFSET - sizeof(struct udphdr); ethhdr->ether_shost[4] == context->mac[4] &&
int dhcp_option_sz = dhcp_sz - DHCP_OPTIONS_HEADER_SIZE; ethhdr->ether_shost[5] == context->mac[5]) ?
const u_char *dhcp_option = context->buffer + dhcp_option_offset; DHCP_TX : DHCP_RX;
dhcp_packet_direction_t dir = (ethhdr->ether_shost[0] == context->mac[0] && int offset = 0;
ethhdr->ether_shost[1] == context->mac[1] && while ((offset < (dhcp_option_sz + 1)) && dhcp_option[offset] != 255) {
ethhdr->ether_shost[2] == context->mac[2] && if (dhcp_option[offset] == OPTION_DHCP_MESSAGE_TYPE) {
ethhdr->ether_shost[3] == context->mac[3] && if (offset < (dhcp_option_sz + 2)) {
ethhdr->ether_shost[4] == context->mac[4] && handle_dhcp_option_53(context, &dhcp_option[offset], dir, iphdr, dhcphdr);
ethhdr->ether_shost[5] == context->mac[5]) ?
DHCP_TX : DHCP_RX;
int offset = 0;
int stop_dhcp_processing = 0;
while ((offset < (dhcp_option_sz + 1)) && dhcp_option[offset] != 255) {
switch (dhcp_option[offset])
{
case 53:
if (offset < (dhcp_option_sz + 2)) {
handle_dhcp_option_53(context, &dhcp_option[offset], dir, iphdr, dhcphdr);
}
stop_dhcp_processing = 1; // break while loop since we are only interested in Option 53
break;
default:
break;
}
if (stop_dhcp_processing == 1) {
break;
}
if (dhcp_option[offset] == 0) { // DHCP Option Padding
offset++;
} else {
offset += dhcp_option[offset + 1] + 2;
} }
break; // break while loop since we are only interested in Option 53
}
if (dhcp_option[offset] == 0) { // DHCP Option Padding
offset++;
} else {
offset += dhcp_option[offset + 1] + 2;
} }
} else {
syslog(LOG_WARNING, "read_callback(%s): read length (%ld) is too small to capture DHCP options",
context->intf, buffer_sz);
} }
} else {
syslog(LOG_WARNING, "read_callback(%s): read length (%ld) is too small to capture DHCP options",
context->intf, buffer_sz);
} }
} }
/** /**
* @code read_callback_dual_tor(fd, event, arg); * @code read_tx_callback(fd, event, arg);
* *
* @brief callback for libevent which is called every time out in order to read queued packet capture when dual tor mode is enabled * @brief callback for libevent which is called every time out in order to read queued outgoing packet capture
* *
* @param fd socket to read from * @param fd socket to read from
* @param event libevent triggered event * @param event libevent triggered event
@ -242,72 +276,58 @@ static void read_callback(int fd, short event, void *arg)
* *
* @return none * @return none
*/ */
static void read_callback_dual_tor(int fd, short event, void *arg) static void read_tx_callback(int fd, short event, void *arg)
{
dhcp_device_context_t *context = (dhcp_device_context_t*) arg;
ssize_t buffer_sz;
while ((buffer_sz = recv(fd, context->buffer, context->snaplen, MSG_DONTWAIT)) > 0) {
client_packet_handler(context, buffer_sz);
}
}
/**
* @code read_rx_callback(fd, event, arg);
*
* @brief callback for libevent which is called every time out in order to read queued incoming packet capture
*
* @param fd socket to read from
* @param event libevent triggered event
* @param arg user provided argument for callback (interface context)
*
* @return none
*/
static void read_rx_callback(int fd, short event, void *arg)
{ {
dhcp_device_context_t *context = (dhcp_device_context_t*) arg; dhcp_device_context_t *context = (dhcp_device_context_t*) arg;
ssize_t buffer_sz; ssize_t buffer_sz;
struct sockaddr_ll sll; struct sockaddr_ll sll;
socklen_t slen = sizeof sll; socklen_t slen = sizeof sll;
while ((event == EV_READ) && while ((buffer_sz = recvfrom(fd, context->buffer, context->snaplen, MSG_DONTWAIT, (struct sockaddr *)&sll, &slen)) > 0)
((buffer_sz = recvfrom(fd, context->buffer, context->snaplen, MSG_DONTWAIT, (struct sockaddr *)&sll, &slen)) > 0))
{ {
std::string member_table = std::string("VLAN_MEMBER|") + context->intf + "|";
char interfaceName[IF_NAMESIZE]; char interfaceName[IF_NAMESIZE];
char *interface = if_indextoname(sll.sll_ifindex, interfaceName); if (if_indextoname(sll.sll_ifindex, interfaceName) == NULL) {
std::string state; syslog(LOG_WARNING, "invalid input interface index %d\n", sll.sll_ifindex);
std::string intf(interface); continue;
mStateDbMuxTablePtr->hget(intf, "state", state); }
if (state != "standby" && configDb.exists(member_table.append(interface))) { std::string intf(interfaceName);
struct ether_header *ethhdr = (struct ether_header*) context->buffer; auto vlan = vlan_map.find(intf);
struct ip *iphdr = (struct ip*) (context->buffer + IP_START_OFFSET); if (vlan == vlan_map.end()) {
struct udphdr *udp = (struct udphdr*) (context->buffer + UDP_START_OFFSET); if (intf.find(CLIENT_IF_PREFIX) != std::string::npos) {
uint8_t *dhcphdr = context->buffer + DHCP_START_OFFSET; syslog(LOG_WARNING, "invalid input interface %s\n", interfaceName);
int dhcp_option_offset = DHCP_START_OFFSET + DHCP_OPTIONS_HEADER_SIZE;
if (((unsigned)buffer_sz > UDP_START_OFFSET + sizeof(struct udphdr) + DHCP_OPTIONS_HEADER_SIZE) &&
(ntohs(udp->len) > DHCP_OPTIONS_HEADER_SIZE))
{
int dhcp_sz = ntohs(udp->len) < buffer_sz - UDP_START_OFFSET - sizeof(struct udphdr) ?
ntohs(udp->len) : buffer_sz - UDP_START_OFFSET - sizeof(struct udphdr);
int dhcp_option_sz = dhcp_sz - DHCP_OPTIONS_HEADER_SIZE;
const u_char *dhcp_option = context->buffer + dhcp_option_offset;
dhcp_packet_direction_t dir = (ethhdr->ether_shost[0] == context->mac[0] &&
ethhdr->ether_shost[1] == context->mac[1] &&
ethhdr->ether_shost[2] == context->mac[2] &&
ethhdr->ether_shost[3] == context->mac[3] &&
ethhdr->ether_shost[4] == context->mac[4] &&
ethhdr->ether_shost[5] == context->mac[5]) ?
DHCP_TX : DHCP_RX;
int offset = 0;
int stop_dhcp_processing = 0;
while ((offset < (dhcp_option_sz + 1)) && dhcp_option[offset] != 255) {
switch (dhcp_option[offset])
{
case 53:
if (offset < (dhcp_option_sz + 2)) {
handle_dhcp_option_53(context, &dhcp_option[offset], dir, iphdr, dhcphdr);
}
stop_dhcp_processing = 1; // break while loop since we are only interested in Option 53
break;
default:
break;
}
if (stop_dhcp_processing == 1) {
break;
}
if (dhcp_option[offset] == 0) { // DHCP Option Padding
offset++;
} else {
offset += dhcp_option[offset + 1] + 2;
}
}
} else {
syslog(LOG_WARNING, "read_callback(%s): read length (%ld) is too small to capture DHCP options",
context->intf, buffer_sz);
} }
continue;
}
if (dual_tor_sock) {
std::string state;
mStateDbMuxTablePtr->hget(intf, "state", state);
if (state != "standby") {
client_packet_handler(context, buffer_sz);
}
} else {
client_packet_handler(context, buffer_sz);
} }
} }
} }
@ -495,20 +515,31 @@ static int init_socket(dhcp_device_context_t *context, const char *intf)
int rv = -1; int rv = -1;
do { do {
context->sock = socket(AF_PACKET, SOCK_RAW | SOCK_NONBLOCK, htons(ETH_P_ALL)); context->rx_sock = socket(AF_PACKET, SOCK_RAW | SOCK_NONBLOCK, htons(ETH_P_ALL));
if (context->sock < 0) { context->tx_sock = socket(AF_PACKET, SOCK_RAW | SOCK_NONBLOCK, htons(ETH_P_ALL));
if (context->rx_sock < 0 || context->tx_sock < 0) {
syslog(LOG_ALERT, "socket: failed to open socket with '%s'\n", strerror(errno)); syslog(LOG_ALERT, "socket: failed to open socket with '%s'\n", strerror(errno));
exit(1);
}
struct sockaddr_ll rx_addr;
memset(&rx_addr, 0, sizeof(rx_addr));
rx_addr.sll_ifindex = 0; // any interface
rx_addr.sll_family = AF_PACKET;
rx_addr.sll_protocol = htons(ETH_P_ALL);
if (bind(context->rx_sock, (struct sockaddr *) &rx_addr, sizeof(rx_addr))) {
syslog(LOG_ALERT, "bind: failed to bind to interface '%s' with '%s'\n", intf, strerror(errno));
break; break;
} }
struct sockaddr_ll addr; struct sockaddr_ll tx_addr;
memset(&addr, 0, sizeof(addr)); memset(&tx_addr, 0, sizeof(tx_addr));
addr.sll_ifindex = 0; // any interface tx_addr.sll_ifindex = if_nametoindex(intf);
addr.sll_family = AF_PACKET; tx_addr.sll_family = AF_PACKET;
addr.sll_protocol = htons(ETH_P_ALL); tx_addr.sll_protocol = htons(ETH_P_ALL);
if (bind(context->sock, (struct sockaddr *) &addr, sizeof(addr))) { if (bind(context->tx_sock, (struct sockaddr *) &tx_addr, sizeof(tx_addr))) {
syslog(LOG_ALERT, "bind: failed to bind to interface '%s' with '%s'\n", intf, strerror(errno)); syslog(LOG_ALERT, "bind: failed to bind to interface '%s' with '%s'\n", intf, strerror(errno));
break; exit(1);
} }
strncpy(context->intf, intf, sizeof(context->intf) - 1); strncpy(context->intf, intf, sizeof(context->intf) - 1);
@ -644,17 +675,18 @@ int dhcp_device_start_capture(dhcp_device_context_t *context,
in_addr_t giaddr_ip) in_addr_t giaddr_ip)
{ {
int rv = -1; int rv = -1;
struct event *ev; struct event *rx_ev;
struct event *tx_ev;
do { do {
if (context == NULL) { if (context == NULL) {
syslog(LOG_ALERT, "NULL interface context pointer'\n"); syslog(LOG_ALERT, "NULL interface context pointer'\n");
break; exit(1);
} }
if (snaplen < UDP_START_OFFSET + sizeof(struct udphdr) + DHCP_OPTIONS_HEADER_SIZE) { if (snaplen < UDP_START_OFFSET + sizeof(struct udphdr) + DHCP_OPTIONS_HEADER_SIZE) {
syslog(LOG_ALERT, "dhcp_device_start_capture(%s): snap length is too low to capture DHCP options", context->intf); syslog(LOG_ALERT, "dhcp_device_start_capture(%s): snap length is too low to capture DHCP options", context->intf);
break; exit(1);
} }
context->giaddr_ip = giaddr_ip; context->giaddr_ip = giaddr_ip;
@ -662,25 +694,31 @@ int dhcp_device_start_capture(dhcp_device_context_t *context,
context->buffer = (uint8_t *) malloc(snaplen); context->buffer = (uint8_t *) malloc(snaplen);
if (context->buffer == NULL) { if (context->buffer == NULL) {
syslog(LOG_ALERT, "malloc: failed to allocate memory for socket buffer '%s'\n", strerror(errno)); syslog(LOG_ALERT, "malloc: failed to allocate memory for socket buffer '%s'\n", strerror(errno));
break; exit(1);
} }
context->snaplen = snaplen; context->snaplen = snaplen;
if (setsockopt(context->sock, SOL_SOCKET, SO_ATTACH_FILTER, &dhcp_sock_bfp, sizeof(dhcp_sock_bfp)) != 0) { if (setsockopt(context->rx_sock, SOL_SOCKET, SO_ATTACH_FILTER, &dhcp_inbound_sock_bfp, sizeof(dhcp_inbound_sock_bfp)) != 0) {
syslog(LOG_ALERT, "setsockopt: failed to attach filter with '%s'\n", strerror(errno)); syslog(LOG_ALERT, "setsockopt: failed to attach filter with '%s'\n", strerror(errno));
break; exit(1);
} }
if (dual_tor_sock) if (setsockopt(context->tx_sock, SOL_SOCKET, SO_ATTACH_FILTER, &dhcp_outbound_sock_bfp, sizeof(dhcp_outbound_sock_bfp)) != 0) {
ev = event_new(base, context->sock, EV_READ | EV_PERSIST, read_callback_dual_tor, context); syslog(LOG_ALERT, "setsockopt: failed to attach filter with '%s'\n", strerror(errno));
else exit(1);
ev = event_new(base, context->sock, EV_READ | EV_PERSIST, read_callback, context); }
if (ev == NULL) { update_vlan_mapping(context->intf, mConfigDbPtr);
rx_ev = event_new(base, context->rx_sock, EV_READ | EV_PERSIST, read_rx_callback, context);
tx_ev = event_new(base, context->tx_sock, EV_READ | EV_PERSIST, read_tx_callback, context);
if (rx_ev == NULL || tx_ev == NULL) {
syslog(LOG_ALERT, "event_new: failed to allocate memory for libevent event '%s'\n", strerror(errno)); syslog(LOG_ALERT, "event_new: failed to allocate memory for libevent event '%s'\n", strerror(errno));
break; exit(1);
} }
event_add(ev, NULL); event_add(rx_ev, NULL);
event_add(tx_ev, NULL);
rv = 0; rv = 0;
} while (0); } while (0);

View File

@ -35,6 +35,11 @@ typedef enum
DHCP_MESSAGE_TYPE_COUNT DHCP_MESSAGE_TYPE_COUNT
} dhcp_message_type_t; } dhcp_message_type_t;
enum
{
OPTION_DHCP_MESSAGE_TYPE = 53,
};
/** packet direction */ /** packet direction */
typedef enum typedef enum
{ {
@ -71,7 +76,8 @@ typedef enum
/** DHCP device (interface) context */ /** DHCP device (interface) context */
typedef struct typedef struct
{ {
int sock; /** Raw socket associated with this device/interface */ int rx_sock; /** Raw socket associated with this device/interface to count rx packets */
int tx_sock; /** Raw socket associated with this device/interface to count tx packets*/
in_addr_t ip; /** network address of this device (interface) */ in_addr_t ip; /** network address of this device (interface) */
uint8_t mac[ETHER_ADDR_LEN]; /** hardware address of this device (interface) */ uint8_t mac[ETHER_ADDR_LEN]; /** hardware address of this device (interface) */
in_addr_t giaddr_ip; /** Gateway IP address */ in_addr_t giaddr_ip; /** Gateway IP address */