Skip to content

Commit

Permalink
Added DHCPv6 Monitor
Browse files Browse the repository at this point in the history
  • Loading branch information
shlomibitton authored and yxieca committed Oct 26, 2021
1 parent 6483bf4 commit 5737c22
Show file tree
Hide file tree
Showing 7 changed files with 738 additions and 191 deletions.
577 changes: 441 additions & 136 deletions src/dhcpmon/src/dhcp_device.c

Large diffs are not rendered by default.

125 changes: 100 additions & 25 deletions src/dhcpmon/src/dhcp_device.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,21 +18,43 @@


/**
* DHCP message types
* DHCPv4 message types
**/
typedef enum
{
DHCP_MESSAGE_TYPE_DISCOVER = 1,
DHCP_MESSAGE_TYPE_OFFER = 2,
DHCP_MESSAGE_TYPE_REQUEST = 3,
DHCP_MESSAGE_TYPE_DECLINE = 4,
DHCP_MESSAGE_TYPE_ACK = 5,
DHCP_MESSAGE_TYPE_NAK = 6,
DHCP_MESSAGE_TYPE_RELEASE = 7,
DHCP_MESSAGE_TYPE_INFORM = 8,

DHCP_MESSAGE_TYPE_COUNT
} dhcp_message_type_t;
DHCPv4_MESSAGE_TYPE_DISCOVER = 1,
DHCPv4_MESSAGE_TYPE_OFFER = 2,
DHCPv4_MESSAGE_TYPE_REQUEST = 3,
DHCPv4_MESSAGE_TYPE_DECLINE = 4,
DHCPv4_MESSAGE_TYPE_ACK = 5,
DHCPv4_MESSAGE_TYPE_NAK = 6,
DHCPv4_MESSAGE_TYPE_RELEASE = 7,
DHCPv4_MESSAGE_TYPE_INFORM = 8,

DHCPv4_MESSAGE_TYPE_COUNT
} dhcpv4_message_type_t;

/**
* DHCPv6 message types
**/
typedef enum
{
DHCPv6_MESSAGE_TYPE_SOLICIT = 1,
DHCPv6_MESSAGE_TYPE_ADVERTISE = 2,
DHCPv6_MESSAGE_TYPE_REQUEST = 3,
DHCPv6_MESSAGE_TYPE_CONFIRM = 4,
DHCPv6_MESSAGE_TYPE_RENEW = 5,
DHCPv6_MESSAGE_TYPE_REBIND = 6,
DHCPv6_MESSAGE_TYPE_REPLY = 7,
DHCPv6_MESSAGE_TYPE_RELEASE = 8,
DHCPv6_MESSAGE_TYPE_DECLINE = 9,
DHCPv6_MESSAGE_TYPE_RECONFIGURE = 10,
DHCPv6_MESSAGE_TYPE_INFORMATION_REQUEST = 11,
DHCPv6_MESSAGE_TYPE_RELAY_FORWARD = 12,
DHCPv6_MESSAGE_TYPE_RELAY_REPLY = 13,

DHCPv6_MESSAGE_TYPE_COUNT
} dhcpv6_message_type_t;

/** packet direction */
typedef enum
Expand Down Expand Up @@ -60,39 +82,78 @@ typedef enum
DHCP_MON_STATUS_INDETERMINATE, /** DHCP relay health could not be determined */
} dhcp_mon_status_t;

/** dhcp type */
typedef enum
{
DHCPv4_TYPE,
DHCPv6_TYPE,
} dhcp_type_t;

/** dhcp check type */
typedef enum
{
DHCP_MON_CHECK_NEGATIVE, /** Presence of relayed DHCP packets activity is flagged as unhealthy state */
DHCP_MON_CHECK_POSITIVE, /** Validate that received DORA packets are relayed */
} dhcp_mon_check_t;

typedef struct
{
uint64_t v4counters[DHCP_COUNTERS_COUNT][DHCP_DIR_COUNT][DHCPv4_MESSAGE_TYPE_COUNT];
/** current/snapshot counters of DHCPv4 packets */
uint64_t v6counters[DHCP_COUNTERS_COUNT][DHCP_DIR_COUNT][DHCPv6_MESSAGE_TYPE_COUNT];
/** current/snapshot counters of DHCPv6 packets */
} counters_t;

/** DHCP device (interface) context */
typedef struct
{
int sock; /** Raw socket associated with this device/interface */
in_addr_t ip; /** network address of this device (interface) */
in_addr_t ipv4; /** ipv4 network address of this device (interface) */
struct in6_addr ipv6; /** ipv6 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 IPv4 address */
struct in6_addr v6_vlan_ip; /** Vlan IPv6 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 */
counters_t counters; /** counters for DHCPv4/6 packets */
} dhcp_device_context_t;

/**
* @code dhcp_device_get_ip(context, ip);
* @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_ipv4(context, ip);
*
* @brief Accessor method
*
* @param context pointer to device (interface) context
* @param ip(out) pointer to device IPv4
*
* @return 0 on success, otherwise for failure
*/
int dhcp_device_get_ipv4(dhcp_device_context_t *context, in_addr_t *ip);

/**
* @code dhcp_device_get_ipv6(context, ip);
*
* @brief Accessor method
*
* @param context pointer to device (interface) context
* @param ip(out) pointer to device IP
* @param ip(out) pointer to device IPv6
*
* @return 0 on success, otherwise for failure
*/
int dhcp_device_get_ip(dhcp_device_context_t *context, in_addr_t *ip);
int dhcp_device_get_ipv6(dhcp_device_context_t *context, struct in6_addr *ip);

/**
* @code dhcp_device_get_aggregate_context();
Expand All @@ -119,21 +180,23 @@ 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, v6_vlan_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
* @param v6_vlan_ip vlan IPv6 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,
struct in6_addr v6_vlan_ip);

/**
* @code dhcp_device_shutdown(context);
Expand All @@ -147,17 +210,18 @@ int dhcp_device_start_capture(dhcp_device_context_t *context,
void dhcp_device_shutdown(dhcp_device_context_t *context);

/**
* @code dhcp_device_get_status(check_type, context);
* @code dhcp_device_get_status(check_type, context, type);
*
* @brief collects DHCP relay status info for a given interface. If context is null, it will report aggregate
* status
*
* @param check_type Type of validation
* @param context Device (interface) context
* @param type DHCP type
*
* @return DHCP_MON_STATUS_HEALTHY, DHCP_MON_STATUS_UNHEALTHY, or DHCP_MON_STATUS_INDETERMINATE
*/
dhcp_mon_status_t dhcp_device_get_status(dhcp_mon_check_t check_type, dhcp_device_context_t *context);
dhcp_mon_status_t dhcp_device_get_status(dhcp_mon_check_t check_type, dhcp_device_context_t *context, dhcp_type_t type);

/**
* @code dhcp_device_update_snapshot(context);
Expand All @@ -174,10 +238,21 @@ void dhcp_device_update_snapshot(dhcp_device_context_t *context);
* @brief prints status counters to syslog. If context is null, it will print aggregate status
*
* @param context Device (interface) context
* @param counters_type Counter type to be printed
* @param type Counter type to be printed
*
* @return none
*/
void dhcp_device_print_status(dhcp_device_context_t *context, dhcp_counters_type_t type);

/**
* @code dhcp_device_active_types(dhcpv4, dhcpv6);
*
* @brief update local variables with active protocols
*
* @param dhcpv4 DHCPv4 enable flag
* @param dhcpv6 DHCPv6 enable flag
*
* @return none
*/
void dhcp_device_active_types(bool dhcpv4, bool dhcpv6);
#endif /* DHCP_DEVICE_H_ */
69 changes: 61 additions & 8 deletions src/dhcpmon/src/dhcp_devman.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
#include <syslog.h>
#include <sys/queue.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <stdbool.h>

#include "dhcp_devman.h"

Expand All @@ -35,7 +37,14 @@ static uint32_t dhcp_num_mgmt_intf = 0;

/** On Device vlan interface IP address corresponding vlan downlink IP
* This IP is used to filter Offer/Ack packet coming from DHCP server */
static in_addr_t vlan_ip = 0;
static in_addr_t v4_vlan_ip = 0;
static struct in6_addr v6_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;
Expand Down Expand Up @@ -130,7 +139,8 @@ int dhcp_devman_add_intf(const char *name, char intf_type)

rv = dhcp_device_init(&dev->dev_context, dev->name, dev->is_uplink);
if (rv == 0 && intf_type == 'd') {
rv = dhcp_device_get_ip(dev->dev_context, &vlan_ip);
rv = dhcp_device_get_ipv4(dev->dev_context, &v4_vlan_ip);
rv = dhcp_device_get_ipv6(dev->dev_context, &v6_vlan_ip);

dhcp_device_context_t *agg_dev = dhcp_device_get_aggregate_context();

Expand All @@ -148,6 +158,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_ipv4(&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);
*
Expand All @@ -160,11 +201,13 @@ 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 : v4_vlan_ip, v6_vlan_ip);
if (rv == 0) {
char ipv6_addr[INET6_ADDRSTRLEN];
inet_ntop(AF_INET6, &int_ptr->dev_context->ipv6, ipv6_addr, sizeof(ipv6_addr));
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],
"Capturing DHCP packets on interface %s, ipv4: 0x%08x, ipv6: %s, mac [%02x:%02x:%02x:%02x:%02x:%02x] \n",
int_ptr->name, int_ptr->dev_context->ipv4, ipv6_addr, 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]);
}
Expand All @@ -182,13 +225,13 @@ int dhcp_devman_start_capture(size_t snaplen, struct event_base *base)
}

/**
* @code dhcp_devman_get_status(check_type, context);
* @code dhcp_devman_get_status(check_type, context, type);
*
* @brief collects DHCP relay status info.
*/
dhcp_mon_status_t dhcp_devman_get_status(dhcp_mon_check_t check_type, dhcp_device_context_t *context)
dhcp_mon_status_t dhcp_devman_get_status(dhcp_mon_check_t check_type, dhcp_device_context_t *context, dhcp_type_t type)
{
return dhcp_device_get_status(check_type, context);
return dhcp_device_get_status(check_type, context, type);
}

/**
Expand Down Expand Up @@ -230,3 +273,13 @@ void dhcp_devman_print_status(dhcp_device_context_t *context, dhcp_counters_type
dhcp_device_print_status(context, type);
}
}

/**
* @code dhcp_devman_active_types(dhcpv4, dhcpv6);
*
* @brief update local variables with active protocols
*/
void dhcp_devman_active_types(bool dhcpv4, bool dhcpv6)
{
dhcp_device_active_types(dhcpv4, dhcpv6);
}
17 changes: 15 additions & 2 deletions src/dhcpmon/src/dhcp_devman.h
Original file line number Diff line number Diff line change
Expand Up @@ -76,16 +76,17 @@ int dhcp_devman_add_intf(const char *name, char intf_type);
int dhcp_devman_start_capture(size_t snaplen, struct event_base *base);

/**
* @code dhcp_devman_get_status(check_type, context);
* @code dhcp_devman_get_status(check_type, context, type);
*
* @brief collects DHCP relay status info.
*
* @param check_type Type of validation
* @param context pointer to device (interface) context
* @param type DHCP type
*
* @return DHCP_MON_STATUS_HEALTHY, DHCP_MON_STATUS_UNHEALTHY, or DHCP_MON_STATUS_INDETERMINATE
*/
dhcp_mon_status_t dhcp_devman_get_status(dhcp_mon_check_t check_type, dhcp_device_context_t *context);
dhcp_mon_status_t dhcp_devman_get_status(dhcp_mon_check_t check_type, dhcp_device_context_t *context, dhcp_type_t type);

/**
* @code dhcp_devman_update_snapshot(context);
Expand All @@ -108,4 +109,16 @@ 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);

/**
* @code dhcp_devman_active_types(dhcpv4, dhcpv6);
*
* @brief update local variables with active protocols
*
* @param dhcpv4 flag indicating dhcpv4 is enabled
* @param dhcpv6 flag indicating dhcpv6 is enabled
*
* @return none
*/
void dhcp_devman_active_types(bool dhcpv4, bool dhcpv6);

#endif /* DHCP_DEVMAN_H_ */
Loading

0 comments on commit 5737c22

Please sign in to comment.