From 99cb1e1fbe4ddfa218b6d02485d87cdaf01e2ea6 Mon Sep 17 00:00:00 2001 From: kellyyeh <42761586+kellyyeh@users.noreply.github.com> Date: Thu, 9 Mar 2023 15:52:57 -0800 Subject: [PATCH] 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. --- src/dhcpmon/src/dhcp_device.cpp | 267 +++++++++++++++++++++----------- src/dhcpmon/src/dhcp_device.h | 10 +- src/dhcpmon/src/dhcp_devman.cpp | 85 +++------- src/dhcpmon/src/dhcp_devman.h | 10 ++ src/dhcpmon/src/dhcp_mon.cpp | 13 +- src/dhcpmon/src/dhcp_mon.h | 5 +- src/dhcpmon/src/main.cpp | 12 +- 7 files changed, 233 insertions(+), 169 deletions(-) diff --git a/src/dhcpmon/src/dhcp_device.cpp b/src/dhcpmon/src/dhcp_device.cpp index f4f23526e136..12c0e1544903 100644 --- a/src/dhcpmon/src/dhcp_device.cpp +++ b/src/dhcpmon/src/dhcp_device.cpp @@ -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 mStateDbMuxTablePtr = std::make_shared /* interface to vlan mapping */ std::unordered_map vlan_map; +/* interface to port-channel mapping */ +std::unordered_map portchan_map; + +/* interface to mgmt port mapping */ +std::unordered_map 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 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 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 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 *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 *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 *)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 *)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)); - exit(1); + 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; } - context->snaplen = snaplen; - if (setsockopt(context->rx_sock, SOL_SOCKET, SO_ATTACH_FILTER, &dhcp_inbound_sock_bfp, sizeof(dhcp_inbound_sock_bfp)) != 0) { + if (rx_sock == -1 || tx_sock == -1) { + syslog(LOG_ALERT, "dhcp_device_start_capture: invalid rx_sock or tx_sock"); + exit(1); + } + 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)); diff --git a/src/dhcpmon/src/dhcp_device.h b/src/dhcpmon/src/dhcp_device.h index 2e376ac77e6f..cd8eab1ee7eb 100644 --- a/src/dhcpmon/src/dhcp_device.h +++ b/src/dhcpmon/src/dhcp_device.h @@ -17,6 +17,7 @@ #include extern bool dual_tor_sock; +extern std::unordered_map 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); diff --git a/src/dhcpmon/src/dhcp_devman.cpp b/src/dhcpmon/src/dhcp_devman.cpp index b215f978a7c4..0fa490d138bd 100644 --- a/src/dhcpmon/src/dhcp_devman.cpp +++ b/src/dhcpmon/src/dhcp_devman.cpp @@ -7,7 +7,6 @@ #include #include #include -#include #include #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 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); diff --git a/src/dhcpmon/src/dhcp_devman.h b/src/dhcpmon/src/dhcp_devman.h index 948e79cde4f4..d1c80cf30e9f 100644 --- a/src/dhcpmon/src/dhcp_devman.h +++ b/src/dhcpmon/src/dhcp_devman.h @@ -8,9 +8,19 @@ #define DHCP_DEVMAN_H_ #include +#include +#include #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(); * diff --git a/src/dhcpmon/src/dhcp_mon.cpp b/src/dhcpmon/src/dhcp_mon.cpp index 74d9869741d1..21b0a363d874 100644 --- a/src/dhcpmon/src/dhcp_mon.cpp +++ b/src/dhcpmon/src/dhcp_mon.cpp @@ -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); diff --git a/src/dhcpmon/src/dhcp_mon.h b/src/dhcpmon/src/dhcp_mon.h index ae8911ab51fc..5bae01f5962b 100644 --- a/src/dhcpmon/src/dhcp_mon.h +++ b/src/dhcpmon/src/dhcp_mon.h @@ -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(); diff --git a/src/dhcpmon/src/main.cpp b/src/dhcpmon/src/main.cpp index aefaea2d01dd..e660bbd908a9 100644 --- a/src/dhcpmon/src/main.cpp +++ b/src/dhcpmon/src/main.cpp @@ -46,7 +46,7 @@ bool dual_tor_sock = false; static void usage(const char *prog) { printf("Usage: %s -id {-iu }+ -im [-u ]" - "[-w ] [-c ] [-s ] [-d]\n", prog); + "[-w ] [-c ] [-s ] [-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;