Update dhcpmon rx/tx packet filtering and fix server rx count (#13898)
Why I did it Dhcpmon had incorrect RX count for server side packets. It does not raise any false alarms, but could miss catching server side packet count mismatch between snapshot and current counter. Add debug mode which prints counter to syslog How I did it Due to dualtor inbound filter requirement, there are currently two filters, each for listening to rx / tx packets. Originally, we opened up an rx/tx socket for each interface specified, which causes duplicate socket. Now we initialize the sockets only once. Both sockets are not binded to an interface, and we use vlan to interface mapping to filter packets. For inbound uplinks, we use a portchannel to interface mapping. Previous dhcpmon counter before dual tor change: [ Agg-Vlan1000- Current rx/tx] Discover: 1/ 4, Offer: 1/ 1, Request: 3/ 12, ACK: 1/ 1 [ eth0- Current rx/tx] Discover: 0/ 0, Offer: 0/ 0, Request: 0/ 0, ACK: 0/ 0 [ eth0- Current rx/tx] Discover: 0/ 0, Offer: 0/ 0, Request: 0/ 0, ACK: 0/ 0 [ PortChannel104- Current rx/tx] Discover: 0/ 1, Offer: 0/ 0, Request: 0/ 3, ACK: 0/ 0 [ PortChannel103- Current rx/tx] Discover: 0/ 1, Offer: 0/ 0, Request: 0/ 3, ACK: 0/ 0 [ PortChannel102- Current rx/tx] Discover: 0/ 2, Offer: 1/ 0, Request: 0/ 6, ACK: 1/ 0 [ PortChannel101- Current rx/tx] Discover: 0/ 0, Offer: 0/ 0, Request: 0/ 0, ACK: 0/ 0 [ Vlan1000- Current rx/tx] Discover: 1/ 0, Offer: 0/ 1, Request: 3/ 0, ACK: 0/ 1 [ Agg-Vlan1000- Current rx/tx] Discover: 1/ 4, Offer: 1/ 1, Request: 3/ 12, ACK: 1/ 1 Dhcpmon counter after this PR: [ PortChannel104- Current rx/tx] Discover: 0/ 1, Offer: 0/ 0, Request: 0/ 3, ACK: 0/ 0 [ PortChannel103- Current rx/tx] Discover: 0/ 1, Offer: 0/ 0, Request: 0/ 3, ACK: 0/ 0 [ PortChannel102- Current rx/tx] Discover: 0/ 2, Offer: 1/ 0, Request: 0/ 6, ACK: 1/ 0 [ PortChannel101- Current rx/tx] Discover: 0/ 0, Offer: 0/ 0, Request: 0/ 0, ACK: 0/ 0 [ Vlan1000- Current rx/tx] Discover: 1/ 0, Offer: 0/ 1, Request: 3/ 0, ACK: 0/ 1 [ Agg-Vlan1000- Current rx/tx] Discover: 1/ 4, Offer: 1/ 1, Request: 3/ 12, ACK: 1/ 1 How to verify it Ran dhcp relay test to send all four packets in singles and batches on both single ToR and dual ToR. Counter was as expected.
This commit is contained in:
parent
5df167b346
commit
99cb1e1fbe
@ -24,6 +24,7 @@
|
||||
#include "subscriberstatetable.h"
|
||||
#include "select.h"
|
||||
|
||||
#include "dhcp_devman.h"
|
||||
#include "dhcp_device.h"
|
||||
|
||||
/** Counter print width */
|
||||
@ -61,6 +62,12 @@ std::shared_ptr<swss::Table> mStateDbMuxTablePtr = std::make_shared<swss::Table>
|
||||
/* interface to vlan mapping */
|
||||
std::unordered_map<std::string, std::string> vlan_map;
|
||||
|
||||
/* interface to port-channel mapping */
|
||||
std::unordered_map<std::string, std::string> portchan_map;
|
||||
|
||||
/* interface to mgmt port mapping */
|
||||
std::unordered_map<std::string, std::string> mgmt_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)"`
|
||||
@ -133,6 +140,10 @@ static struct sock_fprog dhcp_inbound_sock_bfp = {
|
||||
.len = sizeof(dhcp_inbound_bpf_code) / sizeof(*dhcp_inbound_bpf_code), .filter = dhcp_inbound_bpf_code
|
||||
};
|
||||
|
||||
static uint8_t *rx_recv_buffer = NULL;
|
||||
static uint8_t *tx_recv_buffer = NULL;
|
||||
static uint32_t snap_length;
|
||||
|
||||
/** Aggregate device of DHCP interfaces. It contains aggregate counters from
|
||||
all interfaces
|
||||
*/
|
||||
@ -146,17 +157,56 @@ static dhcp_message_type_t monitored_msgs[] = {
|
||||
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);
|
||||
/** update ethernet interface to vlan map
|
||||
* VLAN_MEMBER|Vlan1000|Ethernet48
|
||||
*/
|
||||
void update_vlan_mapping(std::shared_ptr<swss::DBConnector> db_conn) {
|
||||
auto match_pattern = std::string("VLAN_MEMBER|*");
|
||||
auto keys = db_conn->keys(match_pattern);
|
||||
for (auto &itr : keys) {
|
||||
auto found = itr.find_last_of('|');
|
||||
auto interface = itr.substr(found + 1);
|
||||
auto first = itr.find_first_of('|');
|
||||
auto second = itr.find_last_of('|');
|
||||
auto vlan = itr.substr(first + 1, second - first - 1);
|
||||
auto interface = itr.substr(second + 1);
|
||||
vlan_map[interface] = vlan;
|
||||
syslog(LOG_INFO, "add <%s, %s> into interface vlan map\n", interface.c_str(), vlan.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
/** update ethernet interface to port-channel map
|
||||
* PORTCHANNEL_MEMBER|PortChannel101|Ethernet112
|
||||
*/
|
||||
void update_portchannel_mapping(std::shared_ptr<swss::DBConnector> db_conn) {
|
||||
auto match_pattern = std::string("PORTCHANNEL_MEMBER|*");
|
||||
auto keys = db_conn->keys(match_pattern);
|
||||
for (auto &itr : keys) {
|
||||
auto first = itr.find_first_of('|');
|
||||
auto second = itr.find_last_of('|');
|
||||
auto portchannel = itr.substr(first + 1, second - first - 1);
|
||||
auto interface = itr.substr(second + 1);
|
||||
portchan_map[interface] = portchannel;
|
||||
syslog(LOG_INFO, "add <%s, %s> into interface port-channel map\n", interface.c_str(), portchannel.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
/** update interface to mgmt map
|
||||
*/
|
||||
void update_mgmt_mapping() {
|
||||
auto mgmt = dhcp_devman_get_mgmt_dev();
|
||||
if (mgmt) {
|
||||
auto name = std::string(mgmt->intf);
|
||||
mgmt_map[name] = name;
|
||||
}
|
||||
}
|
||||
|
||||
dhcp_device_context_t *find_device_context(std::unordered_map<std::string, struct intf*> *intfs, std::string if_name) {
|
||||
auto intf = intfs->find(if_name);
|
||||
if (intf == intfs->end()) {
|
||||
return NULL;
|
||||
}
|
||||
return intf->second->dev_context;
|
||||
}
|
||||
|
||||
/** Number of monitored DHCP message type */
|
||||
static uint8_t monitored_msg_sz = sizeof(monitored_msgs) / sizeof(*monitored_msgs);
|
||||
|
||||
@ -222,12 +272,12 @@ static void handle_dhcp_option_53(dhcp_device_context_t *context,
|
||||
*
|
||||
* @return none
|
||||
*/
|
||||
static void client_packet_handler(dhcp_device_context_t *context, ssize_t buffer_sz)
|
||||
static void client_packet_handler(dhcp_device_context_t *context, uint8_t *buffer,
|
||||
ssize_t buffer_sz, dhcp_packet_direction_t dir)
|
||||
{
|
||||
struct ether_header *ethhdr = (struct ether_header*) context->buffer;
|
||||
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;
|
||||
struct ip *iphdr = (struct ip*) (buffer + IP_START_OFFSET);
|
||||
struct udphdr *udp = (struct udphdr*) (buffer + UDP_START_OFFSET);
|
||||
uint8_t *dhcphdr = buffer + DHCP_START_OFFSET;
|
||||
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) &&
|
||||
@ -236,14 +286,8 @@ static void client_packet_handler(dhcp_device_context_t *context, ssize_t buffer
|
||||
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;
|
||||
const u_char *dhcp_option = buffer + dhcp_option_offset;
|
||||
|
||||
int offset = 0;
|
||||
while ((offset < (dhcp_option_sz + 1)) && dhcp_option[offset] != 255) {
|
||||
if (dhcp_option[offset] == OPTION_DHCP_MESSAGE_TYPE) {
|
||||
@ -260,11 +304,41 @@ static void client_packet_handler(dhcp_device_context_t *context, ssize_t buffer
|
||||
}
|
||||
}
|
||||
} else {
|
||||
syslog(LOG_WARNING, "read_callback(%s): read length (%ld) is too small to capture DHCP options",
|
||||
context->intf, buffer_sz);
|
||||
syslog(LOG_WARNING, "read_callback(%s %s): read length (%ld) is too small to capture DHCP options",
|
||||
context->intf, dir == DHCP_TX ? "TX" : "RX", buffer_sz);
|
||||
}
|
||||
}
|
||||
|
||||
static dhcp_device_context_t *interface_to_dev_context(std::unordered_map<std::string, struct intf*> *devices,
|
||||
std::string ifname)
|
||||
{
|
||||
auto vlan = vlan_map.find(ifname);
|
||||
if (vlan != vlan_map.end()) {
|
||||
if (dual_tor_sock) {
|
||||
std::string state;
|
||||
mStateDbMuxTablePtr->hget(ifname, "state", state);
|
||||
if (state == "standby") {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
return find_device_context(devices, vlan->second);
|
||||
} else {
|
||||
auto port_channel = portchan_map.find(ifname);
|
||||
if (port_channel != portchan_map.end()) {
|
||||
return find_device_context(devices, port_channel->second);
|
||||
}
|
||||
else {
|
||||
// mgmt interface check
|
||||
auto mgmt = mgmt_map.find(ifname);
|
||||
if (mgmt != mgmt_map.end()) {
|
||||
return find_device_context(devices, mgmt->second);
|
||||
}
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @code read_tx_callback(fd, event, arg);
|
||||
*
|
||||
@ -278,11 +352,24 @@ static void client_packet_handler(dhcp_device_context_t *context, ssize_t buffer
|
||||
*/
|
||||
static void read_tx_callback(int fd, short event, void *arg)
|
||||
{
|
||||
dhcp_device_context_t *context = (dhcp_device_context_t*) arg;
|
||||
auto devices = (std::unordered_map<std::string, struct intf*> *)arg;
|
||||
ssize_t buffer_sz;
|
||||
struct sockaddr_ll sll;
|
||||
socklen_t slen = sizeof sll;
|
||||
dhcp_device_context_t *context = NULL;
|
||||
|
||||
while ((buffer_sz = recv(fd, context->buffer, context->snaplen, MSG_DONTWAIT)) > 0) {
|
||||
client_packet_handler(context, buffer_sz);
|
||||
while ((buffer_sz = recvfrom(fd, tx_recv_buffer, snap_length, MSG_DONTWAIT, (struct sockaddr *)&sll, &slen)) > 0)
|
||||
{
|
||||
char interfaceName[IF_NAMESIZE];
|
||||
if (if_indextoname(sll.sll_ifindex, interfaceName) == NULL) {
|
||||
syslog(LOG_WARNING, "invalid output interface index %d\n", sll.sll_ifindex);
|
||||
continue;
|
||||
}
|
||||
std::string intf(interfaceName);
|
||||
context = find_device_context(devices, intf);
|
||||
if (context) {
|
||||
client_packet_handler(context, tx_recv_buffer, buffer_sz, DHCP_TX);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -299,12 +386,13 @@ static void read_tx_callback(int fd, short event, void *arg)
|
||||
*/
|
||||
static void read_rx_callback(int fd, short event, void *arg)
|
||||
{
|
||||
dhcp_device_context_t *context = (dhcp_device_context_t*) arg;
|
||||
auto devices = (std::unordered_map<std::string, struct intf*> *)arg;
|
||||
ssize_t buffer_sz;
|
||||
struct sockaddr_ll sll;
|
||||
socklen_t slen = sizeof sll;
|
||||
socklen_t slen = sizeof(sll);
|
||||
dhcp_device_context_t *context = NULL;
|
||||
|
||||
while ((buffer_sz = recvfrom(fd, context->buffer, context->snaplen, MSG_DONTWAIT, (struct sockaddr *)&sll, &slen)) > 0)
|
||||
while ((buffer_sz = recvfrom(fd, rx_recv_buffer, snap_length, MSG_DONTWAIT, (struct sockaddr *)&sll, &slen)) > 0)
|
||||
{
|
||||
char interfaceName[IF_NAMESIZE];
|
||||
if (if_indextoname(sll.sll_ifindex, interfaceName) == NULL) {
|
||||
@ -312,22 +400,9 @@ static void read_rx_callback(int fd, short event, void *arg)
|
||||
continue;
|
||||
}
|
||||
std::string intf(interfaceName);
|
||||
auto vlan = vlan_map.find(intf);
|
||||
if (vlan == vlan_map.end()) {
|
||||
if (intf.find(CLIENT_IF_PREFIX) != std::string::npos) {
|
||||
syslog(LOG_WARNING, "invalid input interface %s\n", interfaceName);
|
||||
}
|
||||
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);
|
||||
context = interface_to_dev_context(devices, intf);
|
||||
if (context) {
|
||||
client_packet_handler(context, rx_recv_buffer, buffer_sz, DHCP_RX);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -500,24 +575,20 @@ static void dhcp_print_counters(const char *vlan_intf,
|
||||
}
|
||||
|
||||
/**
|
||||
* @code init_socket(context, intf);
|
||||
* @code init_socket();
|
||||
*
|
||||
* @brief initializes socket, bind it to interface and bpf program, and
|
||||
* associate with libevent base
|
||||
*
|
||||
* @param context pointer to device (interface) context
|
||||
* @param intf interface name
|
||||
* @brief initializes rx/tx sockets, bind it to interface and bpf program
|
||||
*
|
||||
* @return 0 on success, otherwise for failure
|
||||
*/
|
||||
static int init_socket(dhcp_device_context_t *context, const char *intf)
|
||||
static int init_socket()
|
||||
{
|
||||
int rv = -1;
|
||||
|
||||
do {
|
||||
context->rx_sock = socket(AF_PACKET, SOCK_RAW | SOCK_NONBLOCK, htons(ETH_P_ALL));
|
||||
context->tx_sock = socket(AF_PACKET, SOCK_RAW | SOCK_NONBLOCK, htons(ETH_P_ALL));
|
||||
if (context->rx_sock < 0 || context->tx_sock < 0) {
|
||||
auto rx_sock = socket(AF_PACKET, SOCK_RAW | SOCK_NONBLOCK, htons(ETH_P_ALL));
|
||||
auto tx_sock = socket(AF_PACKET, SOCK_RAW | SOCK_NONBLOCK, htons(ETH_P_ALL));
|
||||
if (rx_sock < 0 || tx_sock < 0) {
|
||||
syslog(LOG_ALERT, "socket: failed to open socket with '%s'\n", strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
@ -527,30 +598,47 @@ static int init_socket(dhcp_device_context_t *context, const char *intf)
|
||||
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));
|
||||
if (bind(rx_sock, (struct sockaddr *) &rx_addr, sizeof(rx_addr))) {
|
||||
syslog(LOG_ALERT, "bind: failed to bind to all interface with '%s'\n", strerror(errno));
|
||||
break;
|
||||
}
|
||||
|
||||
struct sockaddr_ll tx_addr;
|
||||
memset(&tx_addr, 0, sizeof(tx_addr));
|
||||
tx_addr.sll_ifindex = if_nametoindex(intf);
|
||||
tx_addr.sll_ifindex = 0; // any interface
|
||||
tx_addr.sll_family = AF_PACKET;
|
||||
tx_addr.sll_protocol = htons(ETH_P_ALL);
|
||||
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));
|
||||
if (bind(tx_sock, (struct sockaddr *) &tx_addr, sizeof(tx_addr))) {
|
||||
syslog(LOG_ALERT, "bind: failed to bind to interface with '%s'\n", strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
strncpy(context->intf, intf, sizeof(context->intf) - 1);
|
||||
context->intf[sizeof(context->intf) - 1] = '\0';
|
||||
|
||||
for (auto &itr : intfs) {
|
||||
itr.second->dev_context->rx_sock = rx_sock;
|
||||
itr.second->dev_context->tx_sock = tx_sock;
|
||||
}
|
||||
rv = 0;
|
||||
} while (0);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
static void init_recv_buffers(int snaplen)
|
||||
{
|
||||
snap_length = snaplen;
|
||||
rx_recv_buffer = (uint8_t *) malloc(snaplen);
|
||||
if (rx_recv_buffer == NULL) {
|
||||
syslog(LOG_ALERT, "malloc: failed to allocate memory for socket rx buffer '%s'\n", strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
tx_recv_buffer = (uint8_t *) malloc(snaplen);
|
||||
if (tx_recv_buffer == NULL) {
|
||||
syslog(LOG_ALERT, "malloc: failed to allocate memory for socket tx buffer '%s'\n", strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @code initialize_intf_mac_and_ip_addr(context);
|
||||
*
|
||||
@ -642,16 +730,15 @@ int dhcp_device_init(dhcp_device_context_t **context, const char *intf, uint8_t
|
||||
dhcp_device_context_t *dev_context = NULL;
|
||||
|
||||
if ((context != NULL) && (strlen(intf) < sizeof(dev_context->intf))) {
|
||||
|
||||
dev_context = (dhcp_device_context_t *) malloc(sizeof(dhcp_device_context_t));
|
||||
if (dev_context != NULL) {
|
||||
if ((init_socket(dev_context, intf) == 0) &&
|
||||
(initialize_intf_mac_and_ip_addr(dev_context) == 0)) {
|
||||
|
||||
// set device name
|
||||
strncpy(dev_context->intf, intf, sizeof(dev_context->intf) - 1);
|
||||
dev_context->intf[sizeof(dev_context->intf) - 1] = '\0';
|
||||
// set device meta data
|
||||
if (initialize_intf_mac_and_ip_addr(dev_context) == 0) {
|
||||
dev_context->is_uplink = is_uplink;
|
||||
|
||||
memset(dev_context->counters, 0, sizeof(dev_context->counters));
|
||||
|
||||
*context = dev_context;
|
||||
rv = 0;
|
||||
}
|
||||
@ -665,53 +752,55 @@ int dhcp_device_init(dhcp_device_context_t **context, const char *intf, uint8_t
|
||||
}
|
||||
|
||||
/**
|
||||
* @code dhcp_device_start_capture(context, snaplen, base, giaddr_ip);
|
||||
* @code dhcp_device_start_capture(snaplen, base, giaddr_ip);
|
||||
*
|
||||
* @brief starts packet capture on this interface
|
||||
*/
|
||||
int dhcp_device_start_capture(dhcp_device_context_t *context,
|
||||
size_t snaplen,
|
||||
struct event_base *base,
|
||||
in_addr_t giaddr_ip)
|
||||
int dhcp_device_start_capture(size_t snaplen, struct event_base *base, in_addr_t giaddr_ip)
|
||||
{
|
||||
int rv = -1;
|
||||
struct event *rx_ev;
|
||||
struct event *tx_ev;
|
||||
int rx_sock = -1, tx_sock = -1;
|
||||
|
||||
do {
|
||||
if (context == NULL) {
|
||||
syslog(LOG_ALERT, "NULL interface context pointer'\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
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: snap length is too low to capture DHCP options");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
context->giaddr_ip = giaddr_ip;
|
||||
init_socket();
|
||||
|
||||
context->buffer = (uint8_t *) malloc(snaplen);
|
||||
if (context->buffer == NULL) {
|
||||
syslog(LOG_ALERT, "malloc: failed to allocate memory for socket buffer '%s'\n", strerror(errno));
|
||||
init_recv_buffers(snaplen);
|
||||
|
||||
update_vlan_mapping(mConfigDbPtr);
|
||||
update_portchannel_mapping(mConfigDbPtr);
|
||||
update_mgmt_mapping();
|
||||
|
||||
for (auto &itr : intfs) {
|
||||
itr.second->dev_context->snaplen = snaplen;
|
||||
itr.second->dev_context->giaddr_ip = giaddr_ip;
|
||||
// all interface dev context has same rx/tx socket
|
||||
rx_sock = itr.second->dev_context->rx_sock;
|
||||
tx_sock = itr.second->dev_context->tx_sock;
|
||||
}
|
||||
|
||||
if (rx_sock == -1 || tx_sock == -1) {
|
||||
syslog(LOG_ALERT, "dhcp_device_start_capture: invalid rx_sock or tx_sock");
|
||||
exit(1);
|
||||
}
|
||||
context->snaplen = snaplen;
|
||||
|
||||
if (setsockopt(context->rx_sock, SOL_SOCKET, SO_ATTACH_FILTER, &dhcp_inbound_sock_bfp, sizeof(dhcp_inbound_sock_bfp)) != 0) {
|
||||
if (setsockopt(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));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (setsockopt(context->tx_sock, SOL_SOCKET, SO_ATTACH_FILTER, &dhcp_outbound_sock_bfp, sizeof(dhcp_outbound_sock_bfp)) != 0) {
|
||||
if (setsockopt(tx_sock, SOL_SOCKET, SO_ATTACH_FILTER, &dhcp_outbound_sock_bfp, sizeof(dhcp_outbound_sock_bfp)) != 0) {
|
||||
syslog(LOG_ALERT, "setsockopt: failed to attach filter with '%s'\n", strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
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);
|
||||
rx_ev = event_new(base, rx_sock, EV_READ | EV_PERSIST, read_rx_callback, &intfs);
|
||||
tx_ev = event_new(base, tx_sock, EV_READ | EV_PERSIST, read_tx_callback, &intfs);
|
||||
|
||||
if (rx_ev == NULL || tx_ev == NULL) {
|
||||
syslog(LOG_ALERT, "event_new: failed to allocate memory for libevent event '%s'\n", strerror(errno));
|
||||
|
@ -17,6 +17,7 @@
|
||||
#include <event2/buffer.h>
|
||||
|
||||
extern bool dual_tor_sock;
|
||||
extern std::unordered_map<std::string, struct intf*> intfs;
|
||||
|
||||
/**
|
||||
* DHCP message types
|
||||
@ -83,7 +84,6 @@ typedef struct
|
||||
in_addr_t giaddr_ip; /** Gateway IP address */
|
||||
uint8_t is_uplink; /** north interface? */
|
||||
char intf[IF_NAMESIZE]; /** device (interface) name */
|
||||
uint8_t *buffer; /** buffer used to read socket data */
|
||||
size_t snaplen; /** snap length or buffer size */
|
||||
uint64_t counters[DHCP_COUNTERS_COUNT][DHCP_DIR_COUNT][DHCP_MESSAGE_TYPE_COUNT];
|
||||
/** current/snapshot counters of DHCP packets */
|
||||
@ -137,21 +137,17 @@ int dhcp_device_init(dhcp_device_context_t **context,
|
||||
uint8_t is_uplink);
|
||||
|
||||
/**
|
||||
* @code dhcp_device_start_capture(context, snaplen, base, giaddr_ip);
|
||||
* @code dhcp_device_start_capture(snaplen, base, giaddr_ip);
|
||||
*
|
||||
* @brief starts packet capture on this interface
|
||||
*
|
||||
* @param context pointer to device (interface) context
|
||||
* @param snaplen length of packet capture
|
||||
* @param base pointer to libevent base
|
||||
* @param giaddr_ip gateway IP address
|
||||
*
|
||||
* @return 0 on success, otherwise for failure
|
||||
*/
|
||||
int dhcp_device_start_capture(dhcp_device_context_t *context,
|
||||
size_t snaplen,
|
||||
struct event_base *base,
|
||||
in_addr_t giaddr_ip);
|
||||
int dhcp_device_start_capture(size_t snaplen, struct event_base *base, in_addr_t giaddr_ip);
|
||||
|
||||
/**
|
||||
* @code dhcp_device_shutdown(context);
|
||||
|
@ -7,7 +7,6 @@
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <syslog.h>
|
||||
#include <sys/queue.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "dhcp_devman.h"
|
||||
@ -15,17 +14,8 @@
|
||||
/** Prefix appended to Aggregation device */
|
||||
#define AGG_DEV_PREFIX "Agg-"
|
||||
|
||||
/** struct for interface information */
|
||||
struct intf
|
||||
{
|
||||
const char *name; /** interface name */
|
||||
uint8_t is_uplink; /** is uplink (north) interface */
|
||||
dhcp_device_context_t *dev_context; /** device (interface_ context */
|
||||
LIST_ENTRY(intf) entry; /** list link/pointers entries */
|
||||
};
|
||||
|
||||
/** intfs list of interfaces */
|
||||
static LIST_HEAD(intf_list, intf) intfs;
|
||||
/** intfs map of interfaces */
|
||||
std::unordered_map<std::string, struct intf*> intfs;
|
||||
/** dhcp_num_south_intf number of south interfaces */
|
||||
static uint32_t dhcp_num_south_intf = 0;
|
||||
/** dhcp_num_north_intf number of north interfaces */
|
||||
@ -66,17 +56,6 @@ dhcp_device_context_t* dhcp_devman_get_mgmt_dev()
|
||||
return mgmt_intf ? mgmt_intf->dev_context : NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* @code dhcp_devman_init();
|
||||
*
|
||||
* initializes device (interface) manager that keeps track of interfaces and assert that there is one south
|
||||
* interface and as many north interfaces
|
||||
*/
|
||||
void dhcp_devman_init()
|
||||
{
|
||||
LIST_INIT(&intfs);
|
||||
}
|
||||
|
||||
/**
|
||||
* @code dhcp_devman_shutdown();
|
||||
*
|
||||
@ -85,20 +64,11 @@ void dhcp_devman_init()
|
||||
*/
|
||||
void dhcp_devman_shutdown()
|
||||
{
|
||||
struct intf *int_ptr, *prev_intf = NULL;
|
||||
|
||||
LIST_FOREACH(int_ptr, &intfs, entry) {
|
||||
dhcp_device_shutdown(int_ptr->dev_context);
|
||||
if (prev_intf) {
|
||||
LIST_REMOVE(prev_intf, entry);
|
||||
free(prev_intf);
|
||||
prev_intf = int_ptr;
|
||||
}
|
||||
}
|
||||
|
||||
if (prev_intf) {
|
||||
LIST_REMOVE(prev_intf, entry);
|
||||
free(prev_intf);
|
||||
for (auto it = intfs.begin(); it != intfs.end();) {
|
||||
auto inf = it->second;
|
||||
dhcp_device_shutdown(inf->dev_context);
|
||||
it = intfs.erase(it);
|
||||
free(inf);
|
||||
}
|
||||
}
|
||||
|
||||
@ -140,12 +110,14 @@ int dhcp_devman_add_intf(const char *name, char intf_type)
|
||||
|
||||
dhcp_device_context_t *agg_dev = dhcp_device_get_aggregate_context();
|
||||
|
||||
strncpy(agg_dev->intf, AGG_DEV_PREFIX, sizeof(AGG_DEV_PREFIX));
|
||||
strncpy(agg_dev->intf + sizeof(AGG_DEV_PREFIX) - 1, name, sizeof(agg_dev->intf) - sizeof(AGG_DEV_PREFIX));
|
||||
strncpy(agg_dev->intf, AGG_DEV_PREFIX, strlen(AGG_DEV_PREFIX) + 1);
|
||||
strncpy(agg_dev->intf + strlen(AGG_DEV_PREFIX), name, sizeof(agg_dev->intf) - strlen(AGG_DEV_PREFIX) - 1);
|
||||
agg_dev->intf[sizeof(agg_dev->intf) - 1] = '\0';
|
||||
syslog(LOG_INFO, "dhcpmon add aggregate interface '%s'\n", agg_dev->intf);
|
||||
}
|
||||
|
||||
LIST_INSERT_HEAD(&intfs, dev, entry);
|
||||
std::string if_name;
|
||||
if_name.assign(dev->name);
|
||||
intfs[if_name] = dev;
|
||||
}
|
||||
else {
|
||||
syslog(LOG_ALERT, "malloc: failed to allocate memory for intf '%s'\n", name);
|
||||
@ -193,21 +165,12 @@ int dhcp_devman_setup_dual_tor_mode(const char *name)
|
||||
int dhcp_devman_start_capture(size_t snaplen, struct event_base *base)
|
||||
{
|
||||
int rv = -1;
|
||||
struct intf *int_ptr;
|
||||
|
||||
if ((dhcp_num_south_intf == 1) && (dhcp_num_north_intf >= 1)) {
|
||||
LIST_FOREACH(int_ptr, &intfs, entry) {
|
||||
rv = dhcp_device_start_capture(int_ptr->dev_context, snaplen, base, dual_tor_mode ? loopback_ip : vlan_ip);
|
||||
if (rv == 0) {
|
||||
syslog(LOG_INFO,
|
||||
"Capturing DHCP packets on interface %s, ip: 0x%08x, mac [%02x:%02x:%02x:%02x:%02x:%02x] \n",
|
||||
int_ptr->name, int_ptr->dev_context->ip, int_ptr->dev_context->mac[0],
|
||||
int_ptr->dev_context->mac[1], int_ptr->dev_context->mac[2], int_ptr->dev_context->mac[3],
|
||||
int_ptr->dev_context->mac[4], int_ptr->dev_context->mac[5]);
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
rv = dhcp_device_start_capture(snaplen, base, dual_tor_mode ? loopback_ip : vlan_ip);
|
||||
if (rv != 0) {
|
||||
syslog(LOG_ALERT, "Capturing DHCP packets on interface failed");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
else {
|
||||
@ -236,12 +199,9 @@ dhcp_mon_status_t dhcp_devman_get_status(dhcp_mon_check_t check_type, dhcp_devic
|
||||
void dhcp_devman_update_snapshot(dhcp_device_context_t *context)
|
||||
{
|
||||
if (context == NULL) {
|
||||
struct intf *int_ptr;
|
||||
|
||||
LIST_FOREACH(int_ptr, &intfs, entry) {
|
||||
dhcp_device_update_snapshot(int_ptr->dev_context);
|
||||
for (auto &itr : intfs) {
|
||||
dhcp_device_update_snapshot(itr.second->dev_context);
|
||||
}
|
||||
|
||||
dhcp_device_update_snapshot(dhcp_devman_get_agg_dev());
|
||||
} else {
|
||||
dhcp_device_update_snapshot(context);
|
||||
@ -256,12 +216,9 @@ void dhcp_devman_update_snapshot(dhcp_device_context_t *context)
|
||||
void dhcp_devman_print_status(dhcp_device_context_t *context, dhcp_counters_type_t type)
|
||||
{
|
||||
if (context == NULL) {
|
||||
struct intf *int_ptr;
|
||||
|
||||
LIST_FOREACH(int_ptr, &intfs, entry) {
|
||||
dhcp_device_print_status(int_ptr->dev_context, type);
|
||||
for (auto &itr : intfs) {
|
||||
dhcp_device_print_status(itr.second->dev_context, type);
|
||||
}
|
||||
|
||||
dhcp_device_print_status(dhcp_devman_get_agg_dev(), type);
|
||||
} else {
|
||||
dhcp_device_print_status(context, type);
|
||||
|
@ -8,9 +8,19 @@
|
||||
#define DHCP_DEVMAN_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
#include "dhcp_device.h"
|
||||
|
||||
/** struct for interface information */
|
||||
struct intf
|
||||
{
|
||||
const char *name; /** interface name */
|
||||
uint8_t is_uplink; /** is uplink (north) interface */
|
||||
dhcp_device_context_t *dev_context; /** device (interface_ context */
|
||||
};
|
||||
|
||||
/**
|
||||
* @code dhcp_devman_init();
|
||||
*
|
||||
|
@ -29,6 +29,8 @@ typedef struct
|
||||
static int window_interval_sec = 18;
|
||||
/** dhcp_unhealthy_max_count max count of consecutive unhealthy statuses before reporting to syslog */
|
||||
static int dhcp_unhealthy_max_count = 10;
|
||||
/** dhcpmon debug mode control flag */
|
||||
static bool debug_on = false;
|
||||
/** libevent base struct */
|
||||
static struct event_base *base;
|
||||
/** libevent timeout event struct */
|
||||
@ -132,6 +134,11 @@ static void timeout_callback(evutil_socket_t fd, short event, void *arg)
|
||||
}
|
||||
|
||||
dhcp_devman_update_snapshot(NULL);
|
||||
|
||||
if (debug_on) {
|
||||
dhcp_devman_print_status(NULL, DHCP_COUNTERS_SNAPSHOT);
|
||||
dhcp_devman_print_status(NULL, DHCP_COUNTERS_CURRENT);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -206,13 +213,14 @@ void dhcp_mon_shutdown()
|
||||
}
|
||||
|
||||
/**
|
||||
* @code dhcp_mon_start(snaplen);
|
||||
* @code dhcp_mon_start(snaplen, debug_mode);
|
||||
*
|
||||
* @brief start monitoring DHCP Relay
|
||||
*/
|
||||
int dhcp_mon_start(size_t snaplen)
|
||||
int dhcp_mon_start(size_t snaplen, bool debug_mode)
|
||||
{
|
||||
int rv = -1;
|
||||
debug_on = debug_mode;
|
||||
|
||||
do
|
||||
{
|
||||
@ -245,7 +253,6 @@ int dhcp_mon_start(size_t snaplen)
|
||||
syslog(LOG_ERR, "Could not start libevent dispatching loop!\n");
|
||||
break;
|
||||
}
|
||||
|
||||
rv = 0;
|
||||
} while (0);
|
||||
|
||||
|
@ -32,15 +32,16 @@ int dhcp_mon_init(int window_sec, int max_count);
|
||||
void dhcp_mon_shutdown();
|
||||
|
||||
/**
|
||||
* @code dhcp_mon_start(snaplen);
|
||||
* @code dhcp_mon_start(snaplen, debug);
|
||||
*
|
||||
* @brief start monitoring DHCP Relay
|
||||
*
|
||||
* @param snaplen packet capture length
|
||||
* @param debug turn on debug or not
|
||||
*
|
||||
* @return 0 upon success, otherwise upon failure
|
||||
*/
|
||||
int dhcp_mon_start(size_t snaplen);
|
||||
int dhcp_mon_start(size_t snaplen, bool debug);
|
||||
|
||||
/**
|
||||
* @code dhcp_mon_stop();
|
||||
|
@ -46,7 +46,7 @@ bool dual_tor_sock = false;
|
||||
static void usage(const char *prog)
|
||||
{
|
||||
printf("Usage: %s -id <south interface> {-iu <north interface>}+ -im <mgmt interface> [-u <loopback interface>]"
|
||||
"[-w <snapshot window in sec>] [-c <unhealthy status count>] [-s <snap length>] [-d]\n", prog);
|
||||
"[-w <snapshot window in sec>] [-c <unhealthy status count>] [-s <snap length>] [-D] [-d]\n", prog);
|
||||
printf("where\n");
|
||||
printf("\tsouth interface: is a vlan interface,\n");
|
||||
printf("\tnorth interface: is a TOR-T1 interface,\n");
|
||||
@ -57,6 +57,7 @@ static void usage(const char *prog)
|
||||
"(default %d),\n",
|
||||
dhcpmon_default_unhealthy_max_count);
|
||||
printf("\tsnap length: snap length of packet capture (default %ld),\n", dhcpmon_default_snaplen);
|
||||
printf("\t-D: debug mode: print counter to syslog\n");
|
||||
printf("\t-d: daemonize %s.\n", prog);
|
||||
|
||||
exit(EXIT_SUCCESS);
|
||||
@ -117,12 +118,11 @@ int main(int argc, char **argv)
|
||||
int max_unhealthy_count = dhcpmon_default_unhealthy_max_count;
|
||||
size_t snaplen = dhcpmon_default_snaplen;
|
||||
int make_daemon = 0;
|
||||
bool debug_mode = false;
|
||||
|
||||
setlogmask(LOG_UPTO(LOG_INFO));
|
||||
openlog(basename(argv[0]), LOG_CONS | LOG_PID | LOG_NDELAY, LOG_DAEMON);
|
||||
|
||||
dhcp_devman_init();
|
||||
|
||||
for (i = 1; i < argc;) {
|
||||
if ((argv[i] == NULL) || (argv[i][0] != '-')) {
|
||||
break;
|
||||
@ -161,6 +161,10 @@ int main(int argc, char **argv)
|
||||
max_unhealthy_count = atoi(argv[i + 1]);
|
||||
i += 2;
|
||||
break;
|
||||
case 'D':
|
||||
debug_mode = true;
|
||||
i += 1;
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "%s: %c: Unknown option\n", basename(argv[0]), argv[i][1]);
|
||||
usage(basename(argv[0]));
|
||||
@ -172,7 +176,7 @@ int main(int argc, char **argv)
|
||||
}
|
||||
|
||||
if ((dhcp_mon_init(window_interval, max_unhealthy_count) == 0) &&
|
||||
(dhcp_mon_start(snaplen) == 0)) {
|
||||
(dhcp_mon_start(snaplen, debug_mode) == 0)) {
|
||||
|
||||
rv = EXIT_SUCCESS;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user