Skip to content
Open
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
15 changes: 12 additions & 3 deletions src/dhcp_device.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -448,6 +448,10 @@ int initialize_intf_mac_and_ip_addr(dhcp_device_context_t *context)
generate_addr_string(context->mac, ETHER_ADDR_LEN).c_str());
close(fd);

memset(&context->ip, 0, sizeof(context->ip));
memset(&context->ipv6_gua, 0, sizeof(context->ipv6_gua));
memset(&context->ipv6_lla, 0, sizeof(context->ipv6_lla));

// Get ip address
struct ifaddrs *ifaddr;
int num_ip_addr = 0, num_ipv6_gua = 0, num_ipv6_lla = 0;
Expand Down Expand Up @@ -499,9 +503,14 @@ int initialize_intf_mac_and_ip_addr(dhcp_device_context_t *context)
}
freeifaddrs(ifaddr);

if (num_ip_addr != 1 || (num_ipv6_gua != 1 && num_ipv6_lla != 1)) {
syslog(LOG_ALERT, "Unable to find exactly 1 ip addr, 1 ipv6 GUA and 1 ipv6 LLA on physical interface "
"and 1 ipv6 loopback addr on loopback interface: %s", context->intf);
if (num_ip_addr > 1) {
syslog(LOG_ALERT, "Interface %s has %d primary IPv4 addresses, expected at most 1",
context->intf, num_ip_addr);
break;
}
if (num_ipv6_gua > 1 || num_ipv6_lla > 1) {
syslog(LOG_ALERT, "Interface %s has IPv6 GUA=%d and LLA=%d, expected at most 1 each",
context->intf, num_ipv6_gua, num_ipv6_lla);
break;
}

Expand Down
8 changes: 4 additions & 4 deletions src/dhcp_device.h
Original file line number Diff line number Diff line change
Expand Up @@ -176,15 +176,15 @@ typedef struct
uint8_t mac[ETHER_ADDR_LEN]; /** hardware address of this device (interface) */
dhcp_device_intf_t intf_type; /** interface type: uplink, downlink, or mgmt */
char intf[IF_NAMESIZE]; /** device (interface) name */
struct in_addr ip; /** network address of this device (interface) */
struct in6_addr ipv6_gua; /** network address of this device (interface) */
struct in6_addr ipv6_lla; /** link local address of this device (interface) */
struct in_addr ip; /** network address of this device (interface), zero if unavailable */
struct in6_addr ipv6_gua; /** network address of this device (interface), zero if unavailable */
struct in6_addr ipv6_lla; /** link local address of this device (interface), zero if unavailable */
} dhcp_device_context_t;

/**
* @code initialize_intf_mac_and_ip_addr(context);
*
* @brief initializes device (interface) mac/ip addresses
* @brief initializes device (interface) mac/ip addresses that are available
*
* @param context pointer to device (interface) context
*
Expand Down
43 changes: 43 additions & 0 deletions src/dhcp_devman.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
#include <swss/subscriberstatetable.h>

bool dual_tor_mode = false;
bool dhcpv4_enabled = false;
bool dhcpv6_enabled = false;

in_addr vlan_ip = {0};
in6_addr vlan_ipv6_gua = {0};
Expand Down Expand Up @@ -274,6 +276,45 @@ int dhcp_devman_init()
return -1;
}

// IPv4: VLAN IPv4 && (!DualToR || Loopback0 IPv4)
// IPv6: VLAN GUA && VLAN LLA && (!DualToR || Loopback0 GUA)
bool vlan_has_ipv4 = vlan_ip.s_addr != INADDR_ANY;
bool vlan_has_ipv6_gua = !IN6_IS_ADDR_UNSPECIFIED(&vlan_ipv6_gua);
bool vlan_has_ipv6_lla = !IN6_IS_ADDR_UNSPECIFIED(&vlan_ipv6_lla);
bool loopback_has_ipv4 = loopback_ip.s_addr != INADDR_ANY;
bool loopback_has_ipv6_gua = !IN6_IS_ADDR_UNSPECIFIED(&loopback_ipv6_gua);

dhcpv4_enabled = vlan_has_ipv4 &&
(!dual_tor_mode || loopback_has_ipv4);
dhcpv6_enabled = vlan_has_ipv6_gua &&
vlan_has_ipv6_lla &&
(!dual_tor_mode || loopback_has_ipv6_gua);

if (!vlan_has_ipv4) {
syslog(LOG_WARNING, "DHCPv4 monitoring disabled for %s: downstream IPv4 address is unavailable",
downstream_ifname.c_str());
}
if (!vlan_has_ipv6_gua || !vlan_has_ipv6_lla) {
syslog(LOG_WARNING, "DHCPv6 monitoring disabled for %s: downstream IPv6 GUA and LLA are required "
"(GUA=%s, LLA=%s)", downstream_ifname.c_str(),
vlan_has_ipv6_gua ? "available" : "missing",
vlan_has_ipv6_lla ? "available" : "missing");
}
if (dual_tor_mode && !loopback_has_ipv4) {
syslog(LOG_WARNING, "DHCPv4 monitoring disabled for %s: Dual-ToR loopback IPv4 address is unavailable",
downstream_ifname.c_str());
}
if (dual_tor_mode && !loopback_has_ipv6_gua) {
syslog(LOG_WARNING, "DHCPv6 monitoring disabled for %s: Dual-ToR loopback IPv6 GUA is unavailable",
downstream_ifname.c_str());
}
if (!dhcpv4_enabled && !dhcpv6_enabled) {
syslog(LOG_ALERT, "No address family satisfies monitoring requirements for %s", downstream_ifname.c_str());
return -1;
}
syslog(LOG_INFO, "Enabled DHCP monitoring families for %s: IPv4=%s, IPv6=%s",
downstream_ifname.c_str(), dhcpv4_enabled ? "true" : "false", dhcpv6_enabled ? "true" : "false");

giaddr_ip = dual_tor_mode ? loopback_ip : vlan_ip;
giaddr_ipv6_gua = dual_tor_mode ? loopback_ipv6_gua : vlan_ipv6_gua;
giaddr_ipv6_lla = dual_tor_mode ? loopback_ipv6_lla : vlan_ipv6_lla;
Expand Down Expand Up @@ -307,6 +348,8 @@ int dhcp_devman_init()

void dhcp_devman_free()
{
dhcpv4_enabled = false;
dhcpv6_enabled = false;
vlan_map.clear();
portchan_map.clear();
for (const auto &[ifname, context] : intfs) {
Expand Down
7 changes: 5 additions & 2 deletions src/dhcp_devman.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@
/** if we are in dual tor mode */
extern bool dual_tor_mode;

/** address families monitored for the downstream VLAN */
extern bool dhcpv4_enabled;
extern bool dhcpv6_enabled;

/** ip information for downstream vlan interface */
extern in_addr vlan_ip;
extern in6_addr vlan_ipv6_gua;
Expand Down Expand Up @@ -109,8 +113,7 @@ bool dhcp_devman_is_tracked_interface(const std::string &ifname);
/**
* @code dhcp_devman_init(snaplen);
*
* @brief initializes device (interface) manager that keeps track of interfaces and assert that there is one south
* interface and as many north interfaces
* @brief initializes the device manager, validates interface counts, and enables the downstream VLAN address families
*
* @return 0 on success, negative otherwise
*/
Expand Down
59 changes: 48 additions & 11 deletions src/dhcp_mon.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ static void initialize_db_counters(const std::string &ifname)
init_value = generate_json_string(NULL, DHCP_MESSAGE_TYPE_COUNT, db_counter_name);
mCountersDbPtr->hset(table_name, "RX", init_value);
mCountersDbPtr->hset(table_name, "TX", init_value);

table_name = construct_counter_db_table_key(ifname, true);
init_value = generate_json_string(NULL, DHCPV6_MESSAGE_TYPE_COUNT, db_counter_name_v6);
mCountersDbPtr->hset(table_name, "RX", init_value);
Expand Down Expand Up @@ -152,7 +152,7 @@ static bool db_counters_initialized(const std::string &ifname)

/**
* @code initialize_all_counters(ifname, init_db);
* @brief Initialize both db counters (we do not for agg device) and cache counters for given interface name
* @brief Initialize both-family db counters and enabled-family cache counters for the given interface
* @param ifname interface name
* @param init_db whether to initialize db counters
* @return none
Expand All @@ -177,8 +177,7 @@ static bool all_counters_initialized(const std::string &ifname)

/**
* @code cleanup_stale_db_counters();
* @brief Clean up stale counter entries in counters_db for interfaces that are no longer present
* (not in intfs map)
* @brief Clean up stale counter entries for interfaces that are no longer present
* @param none
* @return none
*/
Expand All @@ -202,6 +201,35 @@ static void cleanup_stale_db_counters()
}
}

/**
* @code update_disabled_cache_counter();
*
* @brief complete cache update synchronization for disabled address families
*
* A disabled family has no socket cache to update. This function assumes the
* completion role of update_cache_counter_callback by marking both directions
* done in STATE_DB for each disabled family without modifying cache counters.
*
* @return none
*/
static void update_disabled_cache_counter()
Comment thread
Xichen96 marked this conversation as resolved.
{
std::lock_guard<std::mutex> lock(db_sync_mutex);

if (!dhcpv4_enabled) {
std::string state_key = STATE_DB_COUNTER_UPDATE_PREFIX + downstream_ifname;
mStateDbPtr->hset(state_key, "rx_cache_update", "done");
mStateDbPtr->hset(state_key, "tx_cache_update", "done");
syslog(LOG_INFO, "Set DHCPv4 cache update done in STATE_DB; monitoring is disabled");
}
if (!dhcpv6_enabled) {
std::string state_key = STATE_DB_COUNTER_UPDATE_V6_PREFIX + downstream_ifname;
mStateDbPtr->hset(state_key, "rx_cache_update", "done");
mStateDbPtr->hset(state_key, "tx_cache_update", "done");
syslog(LOG_INFO, "Set DHCPv6 cache update done in STATE_DB; monitoring is disabled");
}
}

/**
* @code signal_callback(fd, event, arg);
*
Expand All @@ -216,9 +244,13 @@ static void cleanup_stale_db_counters()
static void signal_callback(evutil_socket_t fd, short event, void *arg)
{
syslog(LOG_INFO, "Received signal: %s", strsignal(fd));

dhcp_devman_print_all_status(DHCP_COUNTERS_CURRENT);
dhcp_devman_print_all_status(DHCP_COUNTERS_CURRENT_V6);

if (dhcpv4_enabled) {
dhcp_devman_print_all_status(DHCP_COUNTERS_CURRENT);
}
if (dhcpv6_enabled) {
dhcp_devman_print_all_status(DHCP_COUNTERS_CURRENT_V6);
}

if ((fd == SIGTERM) || (fd == SIGINT)) {
syslog(LOG_INFO, "Received signal to stop dhcpmon");
Expand All @@ -237,6 +269,7 @@ static void signal_callback(evutil_socket_t fd, short event, void *arg)
if (fd == SIGUSR2) {
syslog(LOG_INFO, "Received signal to sync DB counter to cache counter");
sock_mgr_trigger_cache_counter_updater();
update_disabled_cache_counter();
}
}

Expand Down Expand Up @@ -397,10 +430,14 @@ static void timeout_callback(evutil_socket_t fd, short event, void *arg)
{
syslog_debug(LOG_INFO, "Received timeout signal for DHCP relay health check");

dhcp_devman_print_all_status_debug(DHCP_COUNTERS_CURRENT);
dhcp_devman_print_all_status_debug(DHCP_COUNTERS_SNAPSHOT);
dhcp_devman_print_all_status_debug(DHCP_COUNTERS_CURRENT_V6);
dhcp_devman_print_all_status_debug(DHCP_COUNTERS_SNAPSHOT_V6);
if (dhcpv4_enabled) {
dhcp_devman_print_all_status_debug(DHCP_COUNTERS_CURRENT);
dhcp_devman_print_all_status_debug(DHCP_COUNTERS_SNAPSHOT);
}
if (dhcpv6_enabled) {
dhcp_devman_print_all_status_debug(DHCP_COUNTERS_CURRENT_V6);
dhcp_devman_print_all_status_debug(DHCP_COUNTERS_SNAPSHOT_V6);
}

check_dhcp_relay_health();

Expand Down
15 changes: 15 additions & 0 deletions src/health_check.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ extern std::string mgmt_ifname;
extern std::string agg_dev_all;
extern std::string agg_dev_prefix;

extern bool dhcpv4_enabled;
extern bool dhcpv6_enabled;

extern std::unordered_map<std::string, std::unordered_set<std::string>> rev_vlan_map;
extern std::unordered_map<std::string, std::unordered_set<std::string>> rev_portchan_map;

Expand Down Expand Up @@ -152,42 +155,50 @@ static dhcp_mon_state_t state_data[] = {
.alert = alert_dhcp_relay_disparity,
.log = log_agg_error,
.count = 0,
.is_v6 = false,
},
[1] = {
.check_health = check_mgmt_health,
.log = log_mgmt_error,
.count = 0,
.is_v6 = false,
},
[2] = {
.check_health = check_agg_health_v6,
.alert = alert_dhcp_relay_disparity,
.log = log_agg_error,
.count = 0,
.is_v6 = true,
},
[3] = {
.check_health = check_mgmt_health_v6,
.log = log_mgmt_error,
.count = 0,
.is_v6 = true,
},
[4] = {
.check_health = check_per_interface_rx_health,
.log = log_agg_per_interface_rx_error,
.count = 0,
.is_v6 = false,
},
[5] = {
.check_health = check_per_interface_tx_health,
.log = log_agg_per_interface_tx_error,
.count = 0,
.is_v6 = false,
},
[6] = {
.check_health = check_per_interface_rx_health_v6,
.log = log_agg_per_interface_rx_error,
.count = 0,
.is_v6 = true,
},
[7] = {
.check_health = check_per_interface_tx_health_v6,
.log = log_agg_per_interface_tx_error,
.count = 0,
.is_v6 = true,
},
};

Expand All @@ -198,6 +209,10 @@ void check_dhcp_relay_health()
syslog_debug(LOG_INFO, "Checking DHCP relay health");

for (uint8_t i = 0; i < state_data_sz; i++) {
if ((state_data[i].is_v6 && !dhcpv6_enabled) ||
(!state_data[i].is_v6 && !dhcpv4_enabled)) {
continue;
}
dhcp_mon_status_t dhcp_mon_status = state_data[i].check_health();
switch (dhcp_mon_status) {
case DHCP_MON_STATUS_UNHEALTHY:
Expand Down
1 change: 1 addition & 0 deletions src/health_check.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ typedef struct
void (*alert)(int duration); /** alert function when check failed */
void (*log)(int duration); /** log function when check passed */
int count; /** count in the number of unhealthy checks */
bool is_v6; /** whether this state monitors DHCPv6 */
} dhcp_mon_state_t;

extern event_handle_t g_events_handle;
Expand Down
Loading