From 6fc8002b4e542f3138753b76dc849881b343fcc5 Mon Sep 17 00:00:00 2001 From: Shlomi Bitton Date: Wed, 13 Oct 2021 10:30:33 +0000 Subject: [PATCH 1/4] Fix for DHCPv6 relay daemon 'setsockopt: IPV6_JOIN_GROUP: Cannot allocate memory' issue Signed-off-by: Shlomi Bitton --- files/dhcp/90-dhcp6-systcl.conf.j2 | 2 ++ 1 file changed, 2 insertions(+) diff --git a/files/dhcp/90-dhcp6-systcl.conf.j2 b/files/dhcp/90-dhcp6-systcl.conf.j2 index addb94675258..446c2631e8d8 100644 --- a/files/dhcp/90-dhcp6-systcl.conf.j2 +++ b/files/dhcp/90-dhcp6-systcl.conf.j2 @@ -5,3 +5,5 @@ net.ipv6.conf.eth0.accept_ra = 0 net.ipv6.conf.eth0.accept_ra_defrtr = 1 net.ipv6.conf.eth0.accept_ra = 1 {% endif %} +{# socket memory allocation size = (default value)20480 * 2 #} +net.core.optmem_max=40960 From 4e9fff3e48887b7eb8136b63ce6374c9892a5697 Mon Sep 17 00:00:00 2001 From: Shlomi Bitton Date: Wed, 13 Oct 2021 10:32:08 +0000 Subject: [PATCH 2/4] Add a new patch for ISC-DHCPv6 relay. Change the verbosity level from ERROR to INFO for returned code of 'Network is unreachable' when sending packets. This is because by design, the relay will try to relay packets to all DHCP servers even if there is no route to it and then the error message will print out. Signed-off-by: Shlomi Bitton --- ...-level-for-unreachable-network-error.patch | 20 +++++++++++++++++++ src/isc-dhcp/patch/series | 1 + 2 files changed, 21 insertions(+) create mode 100644 src/isc-dhcp/patch/0013-Change-verbosity-level-for-unreachable-network-error.patch diff --git a/src/isc-dhcp/patch/0013-Change-verbosity-level-for-unreachable-network-error.patch b/src/isc-dhcp/patch/0013-Change-verbosity-level-for-unreachable-network-error.patch new file mode 100644 index 000000000000..721b96185e6b --- /dev/null +++ b/src/isc-dhcp/patch/0013-Change-verbosity-level-for-unreachable-network-error.patch @@ -0,0 +1,20 @@ +diff --git a/common/socket.c b/common/socket.c +index da9f501..fa2a49c 100644 +--- a/common/socket.c ++++ b/common/socket.c +@@ -975,7 +975,14 @@ ssize_t send_packet6(struct interface_info *interface, + + result = sendmsg(interface->wfdesc, &m, 0); + if (result < 0) { +- log_error("send_packet6: %m"); ++ /* 'Network is unreachable' should log as INFO, ++ since not all up link interfaces have routes to the DHCP servers. */ ++ if (errno == 101) { ++ log_info("send_packet6: %m"); ++ } ++ else { ++ log_error("send_packet6: %m"); ++ } + } + return result; + } diff --git a/src/isc-dhcp/patch/series b/src/isc-dhcp/patch/series index 5397aa0c6e06..e68fb021339e 100644 --- a/src/isc-dhcp/patch/series +++ b/src/isc-dhcp/patch/series @@ -11,3 +11,4 @@ 0010-Bugfix-correctly-set-interface-netmask.patch 0011-dhcp-relay-Prevent-Buffer-Overrun.patch 0012-add-option-si-to-support-using-src-intf-ip-in-relay.patch +0013-Change-verbosity-level-for-unreachable-network-error.patch From 6b32fcf66e2c7910172ea26cb4b9932a604d7b85 Mon Sep 17 00:00:00 2001 From: Shlomi Bitton Date: Fri, 15 Oct 2021 10:40:43 +0000 Subject: [PATCH 3/4] Exclude incrementing the aggregate device if packets recieved on the MGMT interface. The MGMT is incremented to check if DHCP packets are traveling through mgmt interface, it is not part of the aggregate device counters. To allow checking the MGMT interface health as well, we need to check the counters of MGMT interface also, so on function 'dhcp_device_check_health' we need to check the current device counters, not only the aggregate device. Signed-off-by: Shlomi Bitton --- src/dhcpmon/src/dhcp_device.c | 29 ++++++++++++++++++++++++++++- src/dhcpmon/src/dhcp_device.h | 11 +++++++++++ src/dhcpmon/src/dhcp_devman.c | 3 +++ 3 files changed, 42 insertions(+), 1 deletion(-) diff --git a/src/dhcpmon/src/dhcp_device.c b/src/dhcpmon/src/dhcp_device.c index 3078295e49a4..8c2faee354b7 100644 --- a/src/dhcpmon/src/dhcp_device.c +++ b/src/dhcpmon/src/dhcp_device.c @@ -121,6 +121,8 @@ static struct sock_fprog dhcp_sock_bfp = { */ static dhcp_device_context_t aggregate_dev = {0}; +static dhcp_device_context_t *mgmt_intf = NULL; + /** Monitored DHCPv4 message type */ static dhcpv4_message_type_t v4_monitored_msgs[] = { DHCPv4_MESSAGE_TYPE_DISCOVER, @@ -176,6 +178,11 @@ static void handle_dhcp_option_53(dhcp_device_context_t *context, 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.v4counters[DHCP_COUNTERS_CURRENT][dir][dhcp_option[2]]++; + // If the packet recieved on the mgmt interface, we don't want to increment the aggregate device + if (context == mgmt_intf) + { + break; + } aggregate_dev.counters.v4counters[DHCP_COUNTERS_CURRENT][dir][dhcp_option[2]]++; } break; @@ -186,6 +193,11 @@ static void handle_dhcp_option_53(dhcp_device_context_t *context, if ((context->giaddr_ip == iphdr->ip_dst.s_addr && context->is_uplink && dir == DHCP_RX) || (!context->is_uplink && dir == DHCP_TX)) { context->counters.v4counters[DHCP_COUNTERS_CURRENT][dir][dhcp_option[2]]++; + // If the packet recieved on the mgmt interface, we don't want to increment the aggregate device + if (context == mgmt_intf) + { + break; + } aggregate_dev.counters.v4counters[DHCP_COUNTERS_CURRENT][dir][dhcp_option[2]]++; } break; @@ -224,6 +236,11 @@ static void handle_dhcpv6_option(dhcp_device_context_t *context, case DHCPv6_MESSAGE_TYPE_RECONFIGURE: case DHCPv6_MESSAGE_TYPE_INFORMATION_REQUEST: context->counters.v6counters[DHCP_COUNTERS_CURRENT][dir][dhcp_option]++; + // If the packet recieved on the mgmt interface, we don't want to increment the aggregate device + if (context == mgmt_intf) + { + break; + } aggregate_dev.counters.v6counters[DHCP_COUNTERS_CURRENT][dir][dhcp_option]++; break; default: @@ -554,7 +571,7 @@ static dhcp_mon_status_t dhcp_device_check_health(dhcp_mon_check_t check_type, { dhcp_mon_status_t rv = DHCP_MON_STATUS_HEALTHY; - if (dhcp_device_is_dhcp_inactive(aggregate_dev.counters.v4counters, aggregate_dev.counters.v6counters, type)) { + if (dhcp_device_is_dhcp_inactive(v4counters, v6counters, type)) { rv = DHCP_MON_STATUS_INDETERMINATE; } else if (check_type == DHCP_MON_CHECK_POSITIVE) { rv = dhcp_device_check_positive_health(v4counters, v6counters, type); @@ -948,3 +965,13 @@ void dhcp_device_active_types(bool dhcpv4, bool dhcpv6) dhcpv4_enabled = dhcpv4; dhcpv6_enabled = dhcpv6; } + +/** + * @code dhcp_device_init_mgmt_intf(mgmt_intf_context); + * + * @brief assign context address of mgmt interface + */ +void dhcp_device_init_mgmt_intf(dhcp_device_context_t *mgmt_intf_context) +{ + mgmt_intf = mgmt_intf_context; +} diff --git a/src/dhcpmon/src/dhcp_device.h b/src/dhcpmon/src/dhcp_device.h index f8aa874bfcce..433eb0907626 100644 --- a/src/dhcpmon/src/dhcp_device.h +++ b/src/dhcpmon/src/dhcp_device.h @@ -255,4 +255,15 @@ void dhcp_device_print_status(dhcp_device_context_t *context, dhcp_counters_type * @return none */ void dhcp_device_active_types(bool dhcpv4, bool dhcpv6); + +/** + * @code dhcp_device_init_mgmt_intf(mgmt_intf_context); + * + * @brief assign context address of mgmt interface + * + * @param mgmt_intf_context MGMT interface context struct address + * + * @return none + */ +void dhcp_device_init_mgmt_intf(dhcp_device_context_t *mgmt_intf_context); #endif /* DHCP_DEVICE_H_ */ diff --git a/src/dhcpmon/src/dhcp_devman.c b/src/dhcpmon/src/dhcp_devman.c index e7a25322207f..b36d926c1d5b 100644 --- a/src/dhcpmon/src/dhcp_devman.c +++ b/src/dhcpmon/src/dhcp_devman.c @@ -148,6 +148,9 @@ int dhcp_devman_add_intf(const char *name, char intf_type) strncpy(agg_dev->intf + sizeof(AGG_DEV_PREFIX) - 1, name, sizeof(agg_dev->intf) - sizeof(AGG_DEV_PREFIX)); agg_dev->intf[sizeof(agg_dev->intf) - 1] = '\0'; } + else if (rv == 0 && intf_type == 'm') { + dhcp_device_init_mgmt_intf(dev->dev_context); + } LIST_INSERT_HEAD(&intfs, dev, entry); } From 4cdfb9e71c2d1acc4fb51ee624e402bded5d6d11 Mon Sep 17 00:00:00 2001 From: Shlomi Bitton Date: Sun, 17 Oct 2021 14:08:18 +0000 Subject: [PATCH 4/4] Fix DHCP header offset calculation. Get the correct option ID in order to get the inner DHCP message Signed-off-by: Shlomi Bitton --- src/dhcpmon/src/dhcp_device.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/dhcpmon/src/dhcp_device.c b/src/dhcpmon/src/dhcp_device.c index 8c2faee354b7..e4fbc7f56909 100644 --- a/src/dhcpmon/src/dhcp_device.c +++ b/src/dhcpmon/src/dhcp_device.c @@ -326,7 +326,7 @@ static void read_callback(int fd, short event, void *arg) } } else if (!is_ipv4 && dhcpv6_enabled && (buffer_sz > UDPv6_START_OFFSET + sizeof(struct udphdr) + DHCPv6_TYPE_LENGTH)) { - const u_char* dhcp_option = context->buffer + dhcp_option_offset; + const u_char* dhcp_header = 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] && @@ -336,23 +336,25 @@ static void read_callback(int fd, short event, void *arg) DHCP_TX : DHCP_RX; int offset = 0; uint16_t option = 0; + uint16_t current_option_len = 0; // Get to inner DHCP header from encapsulated RELAY_FORWARD or RELAY_REPLY header - while (dhcp_option[offset] == DHCPv6_MESSAGE_TYPE_RELAY_FORWARD || dhcp_option[offset] == DHCPv6_MESSAGE_TYPE_RELAY_REPLY) + while (dhcp_header[offset] == DHCPv6_MESSAGE_TYPE_RELAY_FORWARD || dhcp_header[offset] == DHCPv6_MESSAGE_TYPE_RELAY_REPLY) { // Get to DHCPv6_OPTION_RELAY_MSG from all options offset += DHCPv6_RELAY_MSG_OPTIONS_OFFSET; - option = htons(*((uint16_t*)(&(dhcp_option[offset])))); + option = htons(*((uint16_t*)(&(dhcp_header[offset])))); while (option != DHCPv6_OPTION_RELAY_MSG) { - offset += DHCPv6_OPTION_LENGTH; // Add to offset the option length and get the next option ID - offset += htons(*((uint16_t*)(&(dhcp_option[offset])))); - option = htons(*((uint16_t*)(&(dhcp_option[offset])))); + current_option_len = htons(*((uint16_t*)(&(dhcp_header[offset + DHCPv6_OPTION_LENGTH])))); + offset += DHCPv6_OPTION_LENGTH + DHCPv6_OPTION_LEN_LENGTH + current_option_len; + option = htons(*((uint16_t*)(&(dhcp_header[offset])))); } + // Set the offset to DHCP-relay-message data offset += DHCPv6_OPTION_LENGTH + DHCPv6_OPTION_LEN_LENGTH; } - handle_dhcpv6_option(context, dhcp_option[offset], dir); + handle_dhcpv6_option(context, dhcp_header[offset], dir); } else { syslog(LOG_WARNING, "read_callback(%s): read length (%ld) is too small to capture DHCP options", context->intf, buffer_sz);