Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[dhcp_relay] Enhance DHCP monitor application to support DHCPv6 #8060

Merged
merged 3 commits into from
Jul 26, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
564 changes: 434 additions & 130 deletions src/dhcpmon/src/dhcp_device.c

Large diffs are not rendered by default.

112 changes: 88 additions & 24 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,26 +82,42 @@ 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 giaddr_ip; /** Gateway 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;

/**
Expand All @@ -94,16 +132,28 @@ typedef struct
int initialize_intf_mac_and_ip_addr(dhcp_device_context_t *context);

/**
* @code dhcp_device_get_ip(context, ip);
* @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 @@ -130,21 +180,23 @@ 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(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 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 giaddr_ip);
in_addr_t giaddr_ip,
struct in6_addr v6_vlan_ip);

/**
* @code dhcp_device_shutdown(context);
Expand All @@ -158,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 @@ -185,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_ */
34 changes: 25 additions & 9 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,8 @@ 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;
Expand Down Expand Up @@ -136,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 Down Expand Up @@ -174,7 +178,7 @@ int dhcp_devman_setup_dual_tor_mode(const char *name)
}

if (initialize_intf_mac_and_ip_addr(&loopback_intf_context) == 0 &&
dhcp_device_get_ip(&loopback_intf_context, &loopback_ip) == 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);
Expand All @@ -197,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, dual_tor_mode ? loopback_ip : 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 @@ -219,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 @@ -267,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 @@ -87,16 +87,17 @@ int dhcp_devman_setup_dual_tor_mode(const char *name);
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 @@ -119,4 +120,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