From 76eeb230b09e2a0bd72e5cec76a7dd4cdf2da55e Mon Sep 17 00:00:00 2001 From: trzhang-msft Date: Mon, 3 May 2021 10:51:26 -0700 Subject: [PATCH] dhcpmon: support dual tor scenario (#7471) --- src/dhcp_device.c | 12 ++++++------ src/dhcp_device.h | 19 +++++++++++++++---- src/dhcp_devman.c | 39 ++++++++++++++++++++++++++++++++++++++- src/dhcp_devman.h | 11 +++++++++++ src/main.c | 11 +++++++++-- 5 files changed, 79 insertions(+), 13 deletions(-) diff --git a/src/dhcp_device.c b/src/dhcp_device.c index f5cb705ee..f45483f85 100644 --- a/src/dhcp_device.c +++ b/src/dhcp_device.c @@ -130,7 +130,7 @@ static void handle_dhcp_option_53(dhcp_device_context_t *context, case DHCP_MESSAGE_TYPE_INFORM: giaddr = ntohl(dhcphdr[DHCP_GIADDR_OFFSET] << 24 | dhcphdr[DHCP_GIADDR_OFFSET + 1] << 16 | dhcphdr[DHCP_GIADDR_OFFSET + 2] << 8 | dhcphdr[DHCP_GIADDR_OFFSET + 3]); - if ((context->vlan_ip == giaddr && context->is_uplink && dir == DHCP_TX) || + if ((context->giaddr_ip == giaddr && context->is_uplink && dir == DHCP_TX) || (!context->is_uplink && dir == DHCP_RX && iphdr->ip_dst.s_addr == INADDR_BROADCAST)) { context->counters[DHCP_COUNTERS_CURRENT][dir][dhcp_option[2]]++; aggregate_dev.counters[DHCP_COUNTERS_CURRENT][dir][dhcp_option[2]]++; @@ -140,7 +140,7 @@ static void handle_dhcp_option_53(dhcp_device_context_t *context, case DHCP_MESSAGE_TYPE_OFFER: case DHCP_MESSAGE_TYPE_ACK: case DHCP_MESSAGE_TYPE_NAK: - if ((context->vlan_ip == iphdr->ip_dst.s_addr && context->is_uplink && dir == DHCP_RX) || + if ((context->giaddr_ip == iphdr->ip_dst.s_addr && context->is_uplink && dir == DHCP_RX) || (!context->is_uplink && dir == DHCP_TX)) { context->counters[DHCP_COUNTERS_CURRENT][dir][dhcp_option[2]]++; aggregate_dev.counters[DHCP_COUNTERS_CURRENT][dir][dhcp_option[2]]++; @@ -438,7 +438,7 @@ static int init_socket(dhcp_device_context_t *context, const char *intf) * * @return 0 on success, otherwise for failure */ -static int initialize_intf_mac_and_ip_addr(dhcp_device_context_t *context) +int initialize_intf_mac_and_ip_addr(dhcp_device_context_t *context) { int rv = -1; @@ -543,14 +543,14 @@ int dhcp_device_init(dhcp_device_context_t **context, const char *intf, uint8_t } /** - * @code dhcp_device_start_capture(context, snaplen, base, vlan_ip); + * @code dhcp_device_start_capture(context, 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 vlan_ip) + in_addr_t giaddr_ip) { int rv = -1; @@ -565,7 +565,7 @@ int dhcp_device_start_capture(dhcp_device_context_t *context, break; } - context->vlan_ip = vlan_ip; + context->giaddr_ip = giaddr_ip; context->buffer = (uint8_t *) malloc(snaplen); if (context->buffer == NULL) { diff --git a/src/dhcp_device.h b/src/dhcp_device.h index 133b9265a..aa686f4e2 100644 --- a/src/dhcp_device.h +++ b/src/dhcp_device.h @@ -73,7 +73,7 @@ typedef struct int sock; /** Raw socket associated with 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) */ - in_addr_t vlan_ip; /** Vlan IP address */ + 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 */ @@ -82,6 +82,17 @@ typedef struct /** current/snapshot counters of DHCP packets */ } dhcp_device_context_t; +/** + * @code initialize_intf_mac_and_ip_addr(context); + * + * @brief initializes device (interface) mac/ip addresses + * + * @param context pointer to device (interface) context + * + * @return 0 on success, otherwise for failure + */ +int initialize_intf_mac_and_ip_addr(dhcp_device_context_t *context); + /** * @code dhcp_device_get_ip(context, ip); * @@ -119,21 +130,21 @@ int dhcp_device_init(dhcp_device_context_t **context, uint8_t is_uplink); /** - * @code dhcp_device_start_capture(context, snaplen, base, vlan_ip); + * @code dhcp_device_start_capture(context, 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 vlan_ip vlan IP address + * @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 vlan_ip); + in_addr_t giaddr_ip); /** * @code dhcp_device_shutdown(context); diff --git a/src/dhcp_devman.c b/src/dhcp_devman.c index 35378a631..65484798d 100644 --- a/src/dhcp_devman.c +++ b/src/dhcp_devman.c @@ -37,6 +37,12 @@ static uint32_t dhcp_num_mgmt_intf = 0; * This IP is used to filter Offer/Ack packet coming from DHCP server */ static in_addr_t vlan_ip = 0; +/* Device loopback interface ip, which will be used as the giaddr in dual tor setup. */ +static in_addr_t loopback_ip = 0; + +/* Whether the device is in dual tor mode, 0 as default for single tor mode. */ +static int dual_tor_mode = 0; + /** mgmt interface */ static struct intf *mgmt_intf = NULL; @@ -148,6 +154,37 @@ int dhcp_devman_add_intf(const char *name, char intf_type) return rv; } +/** + * @code dhcp_devman_setup_dual_tor_mode(name); + * + * @brief set up dual tor mode: 1) set dual_tor_mode flag and 2) retrieve loopback_ip. + */ +int dhcp_devman_setup_dual_tor_mode(const char *name) +{ + int rv = -1; + + dhcp_device_context_t loopback_intf_context; + + if (strlen(name) < sizeof(loopback_intf_context.intf)) { + strncpy(loopback_intf_context.intf, name, sizeof(loopback_intf_context.intf) - 1); + loopback_intf_context.intf[sizeof(loopback_intf_context.intf) - 1] = '\0'; + } else { + syslog(LOG_ALERT, "loopback interface name (%s) is too long", name); + return rv; + } + + if (initialize_intf_mac_and_ip_addr(&loopback_intf_context) == 0 && + dhcp_device_get_ip(&loopback_intf_context, &loopback_ip) == 0) { + dual_tor_mode = 1; + } else { + syslog(LOG_ALERT, "failed to retrieve ip addr for loopback interface (%s)", name); + return rv; + } + + rv = 0; + return rv; +} + /** * @code dhcp_devman_start_capture(snaplen, base); * @@ -160,7 +197,7 @@ int dhcp_devman_start_capture(size_t snaplen, struct event_base *base) 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, vlan_ip); + 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", diff --git a/src/dhcp_devman.h b/src/dhcp_devman.h index bba707690..948e79cde 100644 --- a/src/dhcp_devman.h +++ b/src/dhcp_devman.h @@ -63,6 +63,17 @@ dhcp_device_context_t* dhcp_devman_get_mgmt_dev(); */ int dhcp_devman_add_intf(const char *name, char intf_type); +/** + * @code dhcp_devman_setup_dual_tor_mode(name); + * + * @brief set up dual tor mode: 1) set dual_tor_mode flag and 2) retrieve loopback_ip. + * + * @param name interface name + * + * @return 0 on success, nonzero otherwise + */ +int dhcp_devman_setup_dual_tor_mode(const char *name); + /** * @code dhcp_devman_start_capture(snaplen, base); * diff --git a/src/main.c b/src/main.c index bb8c45867..29bc534ac 100644 --- a/src/main.c +++ b/src/main.c @@ -40,11 +40,12 @@ static const uint32_t dhcpmon_default_unhealthy_max_count = 10; */ static void usage(const char *prog) { - printf("Usage: %s -id {-iu }+ -im [-w ]" - "[-c ] [-s ] [-d]\n", prog); + printf("Usage: %s -id {-iu }+ -im [-u ]" + "[-w ] [-c ] [-s ] [-d]\n", prog); printf("where\n"); printf("\tsouth interface: is a vlan interface,\n"); printf("\tnorth interface: is a TOR-T1 interface,\n"); + printf("\tloopback interface: is the loopback interface for dual tor setup,\n"); printf("\tsnapshot window: during which DHCP counters are gathered and DHCP status is validated (default %d),\n", dhcpmon_default_health_check_window); printf("\tunhealthy status count: count of consecutive unhealthy status before writing an alert to syslog " @@ -132,6 +133,12 @@ int main(int argc, char **argv) } i += 2; break; + case 'u': + if (dhcp_devman_setup_dual_tor_mode(argv[i + 1]) != 0) { + usage(basename(argv[0])); + } + i += 2; + break; case 'd': make_daemon = 1; i++;