Message ID | 20240424095607.129155-3-naveen.yerramneni@nutanix.com |
---|---|
State | Accepted |
Headers | show |
Series | DHCP Relay Agent support for overlay subnets. | expand |
Context | Check | Description |
---|---|---|
ovsrobot/apply-robot | success | apply and check: success |
ovsrobot/github-robot-_ovn-kubernetes | success | github build: passed |
ovsrobot/github-robot-_Build_and_Test | fail | github build: failed |
On Wed, Apr 24, 2024 at 5:57 AM Naveen Yerramneni < naveen.yerramneni@nutanix.com> wrote: > Added changes in pinctrl to process DHCP Relay opcodes: > - ACTION_OPCODE_DHCP_RELAY_REQ_CHK: For request packets > - ACTION_OPCODE_DHCP_RELAY_RESP_CHK: For response packet > > Signed-off-by: Naveen Yerramneni <naveen.yerramneni@nutanix.com> > Thanks. I applied this patch to main with the below changes. I did some changes to the way dhcp options are returned in the function dhcp_parse_options() ---------------------------------------------------------------------------- diff --git a/controller/pinctrl.c b/controller/pinctrl.c index 50e090cd25..0ee6d8fa85 100644 --- a/controller/pinctrl.c +++ b/controller/pinctrl.c @@ -2023,7 +2023,7 @@ static const char *dhcp_msg_str_get(uint8_t msg_type) static const struct dhcp_header * dhcp_get_hdr_from_pkt(struct dp_packet *pkt_in, const char **in_dhcp_pptr, - const char *end) + const char *end) { /* Validate the DHCP request packet. * Format of the DHCP packet is @@ -2079,13 +2079,20 @@ dhcp_get_hdr_from_pkt(struct dp_packet *pkt_in, const char **in_dhcp_pptr, return dhcp_hdr; } -static void -dhcp_parse_options(const char **in_dhcp_pptr, const char *end, - const uint8_t **dhcp_msg_type_pptr, - ovs_be32 *request_ip_ptr, - bool *ipxe_req_ptr, ovs_be32 *server_id_ptr, - ovs_be32 *netmask_ptr, ovs_be32 *router_ip_ptr) +/* Parsed DHCP option values which we are interested in. */ +struct parsed_dhcp_options { + uint8_t dhcp_msg_type; + ovs_be32 request_ip; + ovs_be32 server_id; + ovs_be32 netmask; + ovs_be32 router_ip; + bool ipxe_req; +}; + +static struct parsed_dhcp_options +dhcp_parse_options(const char **in_dhcp_pptr, const char *end) { + struct parsed_dhcp_options parsed_dhcp_opts = {0}; while ((*in_dhcp_pptr) < end) { const struct dhcp_opt_header *in_dhcp_opt = (const struct dhcp_opt_header *) *in_dhcp_pptr; @@ -2107,52 +2114,53 @@ dhcp_parse_options(const char **in_dhcp_pptr, const char *end, switch (in_dhcp_opt->code) { case DHCP_OPT_MSG_TYPE: - if (dhcp_msg_type_pptr && in_dhcp_opt->len == 1) { - *dhcp_msg_type_pptr = DHCP_OPT_PAYLOAD(in_dhcp_opt); + if (in_dhcp_opt->len == 1) { + const uint8_t *dhcp_msg_type = DHCP_OPT_PAYLOAD(in_dhcp_opt); + parsed_dhcp_opts.dhcp_msg_type = *dhcp_msg_type; } break; case DHCP_OPT_REQ_IP: - if (request_ip_ptr && in_dhcp_opt->len == 4) { - *request_ip_ptr = get_unaligned_be32( - DHCP_OPT_PAYLOAD(in_dhcp_opt)); + if (in_dhcp_opt->len == 4) { + parsed_dhcp_opts.request_ip = get_unaligned_be32( + DHCP_OPT_PAYLOAD(in_dhcp_opt)); } break; case OVN_DHCP_OPT_CODE_SERVER_ID: - if (server_id_ptr && in_dhcp_opt->len == 4) { - *server_id_ptr = get_unaligned_be32( - DHCP_OPT_PAYLOAD(in_dhcp_opt)); + if (in_dhcp_opt->len == 4) { + parsed_dhcp_opts.server_id = get_unaligned_be32( + DHCP_OPT_PAYLOAD(in_dhcp_opt)); } break; case OVN_DHCP_OPT_CODE_NETMASK: - if (netmask_ptr && in_dhcp_opt->len == 4) { - *netmask_ptr = get_unaligned_be32( - DHCP_OPT_PAYLOAD(in_dhcp_opt)); + if (in_dhcp_opt->len == 4) { + parsed_dhcp_opts.netmask = get_unaligned_be32( + DHCP_OPT_PAYLOAD(in_dhcp_opt)); } break; case OVN_DHCP_OPT_CODE_ROUTER_IP: - if (router_ip_ptr && in_dhcp_opt->len == 4) { - *router_ip_ptr = get_unaligned_be32( - DHCP_OPT_PAYLOAD(in_dhcp_opt)); + if (in_dhcp_opt->len == 4) { + parsed_dhcp_opts.router_ip = get_unaligned_be32( + DHCP_OPT_PAYLOAD(in_dhcp_opt)); } break; case DHCP_OPT_ETHERBOOT: - if (ipxe_req_ptr) { - *ipxe_req_ptr = true; - } + parsed_dhcp_opts.ipxe_req = true; break; default: break; } } + + return parsed_dhcp_opts; } /* Called with in the pinctrl_handler thread context. */ static void -pinctrl_handle_dhcp_relay_req_chk( - struct rconn *swconn, - struct dp_packet *pkt_in, struct ofputil_packet_in *pin, - struct ofpbuf *userdata, - struct ofpbuf *continuation) +pinctrl_handle_dhcp_relay_req_chk(struct rconn *swconn, + struct dp_packet *pkt_in, + struct ofputil_packet_in *pin, + struct ofpbuf *userdata, + struct ofpbuf *continuation) { enum ofp_version version = rconn_get_version(swconn); enum ofputil_protocol proto = ofputil_protocol_from_ofp_version(version); @@ -2192,8 +2200,8 @@ pinctrl_handle_dhcp_relay_req_chk( size_t in_l4_size = dp_packet_l4_size(pkt_in); const char *end = (char *) dp_packet_l4(pkt_in) + in_l4_size; const char *in_dhcp_ptr = NULL; - const struct dhcp_header *in_dhcp_data - = dhcp_get_hdr_from_pkt(pkt_in, &in_dhcp_ptr, end); + const struct dhcp_header *in_dhcp_data = + dhcp_get_hdr_from_pkt(pkt_in, &in_dhcp_ptr, end); if (!in_dhcp_data) { goto exit; @@ -2213,14 +2221,14 @@ pinctrl_handle_dhcp_relay_req_chk( goto exit; } - const uint8_t *in_dhcp_msg_type = NULL; - ovs_be32 request_ip = in_dhcp_data->ciaddr; - - dhcp_parse_options(&in_dhcp_ptr, end, - &in_dhcp_msg_type, &request_ip, NULL, NULL, NULL, NULL); + struct parsed_dhcp_options dhcp_opts = dhcp_parse_options(&in_dhcp_ptr, + end); + if (!dhcp_opts.request_ip) { + dhcp_opts.request_ip = in_dhcp_data->ciaddr; + } /* Check whether the DHCP Message Type (opt 53) is present or not */ - if (!in_dhcp_msg_type) { + if (!dhcp_opts.dhcp_msg_type) { static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); VLOG_WARN_RL(&rl, "DHCP_RELAY_REQ_CHK: missing message type"); goto exit; @@ -2274,9 +2282,9 @@ pinctrl_handle_dhcp_relay_req_chk( " REQ_IP:"IP_FMT " GIADDR:"IP_FMT " SERVER_ADDR:"IP_FMT, - dhcp_msg_str_get(*in_dhcp_msg_type), + dhcp_msg_str_get(dhcp_opts.dhcp_msg_type), ETH_ADDR_BYTES_ARGS(dhcp_data->chaddr), ntohl(dhcp_data->xid), - IP_ARGS(request_ip), IP_ARGS(dhcp_data->giaddr), + IP_ARGS(dhcp_opts.request_ip), IP_ARGS(dhcp_data->giaddr), IP_ARGS(*server_ip)); success = 1; exit: @@ -2337,8 +2345,8 @@ pinctrl_handle_dhcp_relay_resp_chk( size_t in_l4_size = dp_packet_l4_size(pkt_in); const char *end = (char *) dp_packet_l4(pkt_in) + in_l4_size; const char *in_dhcp_ptr = NULL; - const struct dhcp_header *in_dhcp_data - = dhcp_get_hdr_from_pkt(pkt_in, &in_dhcp_ptr, end); + const struct dhcp_header *in_dhcp_data = dhcp_get_hdr_from_pkt( + pkt_in, &in_dhcp_ptr, end); if (!in_dhcp_data) { goto exit; @@ -2360,60 +2368,63 @@ pinctrl_handle_dhcp_relay_resp_chk( } ovs_be32 giaddr = in_dhcp_data->giaddr; + if (giaddr != *relay_ip) { + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); + VLOG_WARN_RL(&rl, "DHCP_RELAY_RESP: giaddr mismatch"); + goto exit; + } + ovs_be32 yiaddr = in_dhcp_data->yiaddr; - ovs_be32 server_id = 0, netmask = 0, router_ip = 0; - const uint8_t *in_dhcp_msg_type = NULL; - dhcp_parse_options(&in_dhcp_ptr, end, - &in_dhcp_msg_type, NULL, NULL, &server_id, &netmask, &router_ip); + struct parsed_dhcp_options dhcp_opts = dhcp_parse_options(&in_dhcp_ptr, + end); + if (!dhcp_opts.request_ip) { + dhcp_opts.request_ip = in_dhcp_data->ciaddr; + } /* Check whether the DHCP Message Type (opt 53) is present or not */ - if (!in_dhcp_msg_type) { + if (!dhcp_opts.dhcp_msg_type) { static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); VLOG_WARN_RL(&rl, "DHCP_RELAY_RESP: missing message type"); goto exit; } - if (!server_id) { + if (!dhcp_opts.server_id) { static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); VLOG_WARN_RL(&rl, "DHCP_RELAY_RESP: missing server identifier"); goto exit; } - if (server_id != *server_ip) { + if (dhcp_opts.server_id != *server_ip) { static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); VLOG_WARN_RL(&rl, "DHCP_RELAY_RESP: server identifier mismatch"); goto exit; } - if (giaddr != *relay_ip) { - static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); - VLOG_WARN_RL(&rl, "DHCP_RELAY_RESP: giaddr mismatch"); - goto exit; - } - - if (*in_dhcp_msg_type == DHCP_MSG_OFFER || - *in_dhcp_msg_type == DHCP_MSG_ACK) { - if ((yiaddr & netmask) != (giaddr & netmask)) { + if (dhcp_opts.dhcp_msg_type == DHCP_MSG_OFFER || + dhcp_opts.dhcp_msg_type == DHCP_MSG_ACK) { + if ((yiaddr & dhcp_opts.netmask) != ( + giaddr & dhcp_opts.netmask)) { static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); - VLOG_INFO_RL(&rl, "DHCP_RELAY_RESP_CHK:: Allocated ip adress and" - " giaddr are not in same subnet." - " MSG_TYPE:%s MAC:"ETH_ADDR_FMT + VLOG_INFO_RL(&rl, "DHCP_RELAY_RESP_CHK:: " + "Allocated ip adress and giaddr are not in " + "same subnet. MSG_TYPE:%s MAC:"ETH_ADDR_FMT " XID:%u" " YIADDR:"IP_FMT " GIADDR:"IP_FMT " SERVER_ADDR:"IP_FMT, - dhcp_msg_str_get(*in_dhcp_msg_type), + dhcp_msg_str_get(dhcp_opts.dhcp_msg_type), ETH_ADDR_BYTES_ARGS(in_dhcp_data->chaddr), ntohl(in_dhcp_data->xid), - IP_ARGS(yiaddr), - IP_ARGS(giaddr), IP_ARGS(server_id)); + IP_ARGS(yiaddr), IP_ARGS(giaddr), + IP_ARGS(dhcp_opts.server_id)); goto exit; } - if (router_ip && router_ip != giaddr) { - /* Log the default gateway mismatch and - * continue with rest of the processing */ + if (dhcp_opts.router_ip && + dhcp_opts.router_ip != giaddr) { + /* Log the default gateway mismatch and continue with rest of the + * processing. */ static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); VLOG_INFO_RL(&rl, "DHCP_RELAY_RESP_CHK::" " Router ip adress and giaddr are not same." @@ -2422,11 +2433,11 @@ pinctrl_handle_dhcp_relay_resp_chk( " YIADDR:"IP_FMT " GIADDR:"IP_FMT " SERVER_ADDR:"IP_FMT, - dhcp_msg_str_get(*in_dhcp_msg_type), + dhcp_msg_str_get(dhcp_opts.dhcp_msg_type), ETH_ADDR_BYTES_ARGS(in_dhcp_data->chaddr), ntohl(in_dhcp_data->xid), - IP_ARGS(yiaddr), - IP_ARGS(giaddr), IP_ARGS(server_id)); + IP_ARGS(yiaddr), IP_ARGS(giaddr), + IP_ARGS(dhcp_opts.server_id)); } } @@ -2469,11 +2480,9 @@ pinctrl_handle_dhcp_relay_resp_chk( ip_dst = htonl(0xffffffff); } put_16aligned_be32(&out_ip->ip_dst, ip_dst); - out_ip->ip_csum = recalc_csum32(out_ip->ip_csum, - ip_dst_orig, ip_dst); + out_ip->ip_csum = recalc_csum32(out_ip->ip_csum, ip_dst_orig, ip_dst); if (udp->udp_csum) { - udp->udp_csum = recalc_csum32(udp->udp_csum, - ip_dst_orig, ip_dst); + udp->udp_csum = recalc_csum32(udp->udp_csum, ip_dst_orig, ip_dst); } pin->packet = dp_packet_data(&pkt_out); pin->packet_len = dp_packet_size(&pkt_out); @@ -2485,10 +2494,10 @@ pinctrl_handle_dhcp_relay_resp_chk( " YIADDR:"IP_FMT " GIADDR:"IP_FMT " SERVER_ADDR:"IP_FMT, - dhcp_msg_str_get(*in_dhcp_msg_type), + dhcp_msg_str_get(dhcp_opts.dhcp_msg_type), ETH_ADDR_BYTES_ARGS(dhcp_data->chaddr), ntohl(dhcp_data->xid), IP_ARGS(yiaddr), - IP_ARGS(giaddr), IP_ARGS(server_id)); + IP_ARGS(giaddr), IP_ARGS(dhcp_opts.server_id)); success = 1; exit: if (!ofperr) { @@ -2551,8 +2560,8 @@ pinctrl_handle_put_dhcp_opts( const char *end = (char *)dp_packet_l4(pkt_in) + dp_packet_l4_size(pkt_in); const char *in_dhcp_ptr = NULL; - const struct dhcp_header *in_dhcp_data - = dhcp_get_hdr_from_pkt(pkt_in, &in_dhcp_ptr, end); + const struct dhcp_header *in_dhcp_data = + dhcp_get_hdr_from_pkt(pkt_in, &in_dhcp_ptr, end); if (!in_dhcp_data) { goto exit; @@ -2566,16 +2575,16 @@ pinctrl_handle_put_dhcp_opts( goto exit; } - bool ipxe_req = false; - const uint8_t *in_dhcp_msg_type = NULL; - ovs_be32 request_ip = in_dhcp_data->ciaddr; - dhcp_parse_options(&in_dhcp_ptr, end, - &in_dhcp_msg_type, &request_ip, &ipxe_req, NULL, NULL, NULL); + struct parsed_dhcp_options dhcp_opts = dhcp_parse_options(&in_dhcp_ptr, + end); + if (!dhcp_opts.request_ip) { + dhcp_opts.request_ip = in_dhcp_data->ciaddr; + } /* Check that the DHCP Message Type (opt 53) is present or not with * valid values - DHCP_MSG_DISCOVER or DHCP_MSG_REQUEST. */ - if (!in_dhcp_msg_type) { + if (!dhcp_opts.dhcp_msg_type) { static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); VLOG_WARN_RL(&rl, "Missing DHCP message type"); goto exit; @@ -2584,7 +2593,7 @@ pinctrl_handle_put_dhcp_opts( struct ofpbuf *reply_dhcp_opts_ptr = userdata; uint8_t msg_type = 0; - switch (*in_dhcp_msg_type) { + switch (dhcp_opts.dhcp_msg_type) { case DHCP_MSG_DISCOVER: msg_type = DHCP_MSG_OFFER; if (in_flow->nw_dst != htonl(INADDR_BROADCAST)) { @@ -2595,10 +2604,11 @@ pinctrl_handle_put_dhcp_opts( break; case DHCP_MSG_REQUEST: { msg_type = DHCP_MSG_ACK; - if (request_ip != *offer_ip) { + if (dhcp_opts.request_ip != *offer_ip) { static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); VLOG_WARN_RL(&rl, "DHCPREQUEST requested IP "IP_FMT" does not " - "match offer "IP_FMT, IP_ARGS(request_ip), + "match offer "IP_FMT, + IP_ARGS(dhcp_opts.request_ip), IP_ARGS(*offer_ip)); msg_type = DHCP_MSG_NAK; } @@ -2663,14 +2673,15 @@ pinctrl_handle_put_dhcp_opts( break; } case OVN_DHCP_MSG_DECLINE: - if (request_ip == *offer_ip) { + if (dhcp_opts.request_ip == *offer_ip) { VLOG_INFO("DHCPDECLINE from "ETH_ADDR_FMT ", "IP_FMT" duplicated", ETH_ADDR_ARGS(in_flow->dl_src), IP_ARGS(*offer_ip)); } goto exit; default: { static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); - VLOG_WARN_RL(&rl, "Invalid DHCP message type: %d", *in_dhcp_msg_type); + VLOG_WARN_RL(&rl, "Invalid DHCP message type: %d", + dhcp_opts.dhcp_msg_type); goto exit; } } @@ -2710,7 +2721,7 @@ pinctrl_handle_put_dhcp_opts( (struct dhcp_opt_header *)(ptr + len); if (next_dhcp_opt->code == DHCP_OPT_BOOTFILE_ALT_CODE) { - if (!ipxe_req) { + if (!dhcp_opts.ipxe_req) { ofpbuf_pull(reply_dhcp_opts_ptr, len); next_dhcp_opt->code = DHCP_OPT_BOOTFILE_CODE; } else { @@ -2770,7 +2781,7 @@ pinctrl_handle_put_dhcp_opts( &pkt_out, dp_packet_pull(pkt_in, DHCP_HEADER_LEN), DHCP_HEADER_LEN); dhcp_data->op = DHCP_OP_REPLY; - if (*in_dhcp_msg_type != OVN_DHCP_MSG_INFORM) { + if (dhcp_opts.dhcp_msg_type != OVN_DHCP_MSG_INFORM) { dhcp_data->yiaddr = (msg_type == DHCP_MSG_NAK) ? 0 : *offer_ip; dhcp_data->siaddr = (msg_type == DHCP_MSG_NAK) ? 0 : next_server; } else { ---------------------------------------------------------------------------- Numan --- > controller/pinctrl.c | 597 ++++++++++++++++++++++++++++++++++++++----- > lib/ovn-l7.h | 2 + > 2 files changed, 530 insertions(+), 69 deletions(-) > > diff --git a/controller/pinctrl.c b/controller/pinctrl.c > index aa73facbf..50e090cd2 100644 > --- a/controller/pinctrl.c > +++ b/controller/pinctrl.c > @@ -1993,6 +1993,515 @@ is_dhcp_flags_broadcast(ovs_be16 flags) > return flags & htons(DHCP_BROADCAST_FLAG); > } > > +static const char *dhcp_msg_str[] = { > + [0] = "INVALID", > + [DHCP_MSG_DISCOVER] = "DISCOVER", > + [DHCP_MSG_OFFER] = "OFFER", > + [DHCP_MSG_REQUEST] = "REQUEST", > + [OVN_DHCP_MSG_DECLINE] = "DECLINE", > + [DHCP_MSG_ACK] = "ACK", > + [DHCP_MSG_NAK] = "NAK", > + [OVN_DHCP_MSG_RELEASE] = "RELEASE", > + [OVN_DHCP_MSG_INFORM] = "INFORM" > +}; > + > +static bool > +dhcp_relay_is_msg_type_supported(uint8_t msg_type) > +{ > + return (msg_type >= DHCP_MSG_DISCOVER && msg_type <= > OVN_DHCP_MSG_RELEASE); > +} > + > +static const char *dhcp_msg_str_get(uint8_t msg_type) > +{ > + if (!dhcp_relay_is_msg_type_supported(msg_type)) { > + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); > + VLOG_WARN_RL(&rl, "Unknown DHCP msg type: %u", msg_type); > + return "UNKNOWN"; > + } > + return dhcp_msg_str[msg_type]; > +} > + > +static const struct dhcp_header * > +dhcp_get_hdr_from_pkt(struct dp_packet *pkt_in, const char **in_dhcp_pptr, > + const char *end) > +{ > + /* Validate the DHCP request packet. > + * Format of the DHCP packet is > + * > ----------------------------------------------------------------------- > + *| UDP HEADER | DHCP HEADER | 4 Byte DHCP Cookie | DHCP OPTIONS(var > len) | > + * > ----------------------------------------------------------------------- > + */ > + > + *in_dhcp_pptr = dp_packet_get_udp_payload(pkt_in); > + if (*in_dhcp_pptr == NULL) { > + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); > + VLOG_WARN_RL(&rl, "DHCP: Invalid or incomplete DHCP packet > received"); > + return NULL; > + } > + > + const struct dhcp_header *dhcp_hdr > + = (const struct dhcp_header *) *in_dhcp_pptr; > + (*in_dhcp_pptr) += sizeof *dhcp_hdr; > + if (*in_dhcp_pptr > end) { > + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); > + VLOG_WARN_RL(&rl, "DHCP: Invalid or incomplete DHCP packet > received, " > + "bad data length"); > + return NULL; > + } > + > + if (dhcp_hdr->htype != 0x1) { > + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); > + VLOG_WARN_RL(&rl, "DHCP: Packet is recieved with " > + "unsupported hardware type"); > + return NULL; > + } > + > + if (dhcp_hdr->hlen != 0x6) { > + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); > + VLOG_WARN_RL(&rl, "DHCP: Packet is recieved with " > + "unsupported hardware length"); > + return NULL; > + } > + > + /* DHCP options follow the DHCP header. The first 4 bytes of the DHCP > + * options is the DHCP magic cookie followed by the actual DHCP > options. > + */ > + ovs_be32 magic_cookie = htonl(DHCP_MAGIC_COOKIE); > + if ((*in_dhcp_pptr) + sizeof magic_cookie > end || > + get_unaligned_be32((const void *) (*in_dhcp_pptr)) != > magic_cookie) { > + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); > + VLOG_WARN_RL(&rl, "DHCP: Magic cookie not present in the DHCP > packet"); > + return NULL; > + } > + > + (*in_dhcp_pptr) += sizeof magic_cookie; > + > + return dhcp_hdr; > +} > + > +static void > +dhcp_parse_options(const char **in_dhcp_pptr, const char *end, > + const uint8_t **dhcp_msg_type_pptr, > + ovs_be32 *request_ip_ptr, > + bool *ipxe_req_ptr, ovs_be32 *server_id_ptr, > + ovs_be32 *netmask_ptr, ovs_be32 *router_ip_ptr) > +{ > + while ((*in_dhcp_pptr) < end) { > + const struct dhcp_opt_header *in_dhcp_opt = > + (const struct dhcp_opt_header *) *in_dhcp_pptr; > + if (in_dhcp_opt->code == DHCP_OPT_END) { > + break; > + } > + if (in_dhcp_opt->code == DHCP_OPT_PAD) { > + (*in_dhcp_pptr) += 1; > + continue; > + } > + (*in_dhcp_pptr) += sizeof *in_dhcp_opt; > + if ((*in_dhcp_pptr) > end) { > + break; > + } > + (*in_dhcp_pptr) += in_dhcp_opt->len; > + if ((*in_dhcp_pptr) > end) { > + break; > + } > + > + switch (in_dhcp_opt->code) { > + case DHCP_OPT_MSG_TYPE: > + if (dhcp_msg_type_pptr && in_dhcp_opt->len == 1) { > + *dhcp_msg_type_pptr = DHCP_OPT_PAYLOAD(in_dhcp_opt); > + } > + break; > + case DHCP_OPT_REQ_IP: > + if (request_ip_ptr && in_dhcp_opt->len == 4) { > + *request_ip_ptr = get_unaligned_be32( > + DHCP_OPT_PAYLOAD(in_dhcp_opt)); > + } > + break; > + case OVN_DHCP_OPT_CODE_SERVER_ID: > + if (server_id_ptr && in_dhcp_opt->len == 4) { > + *server_id_ptr = get_unaligned_be32( > + DHCP_OPT_PAYLOAD(in_dhcp_opt)); > + } > + break; > + case OVN_DHCP_OPT_CODE_NETMASK: > + if (netmask_ptr && in_dhcp_opt->len == 4) { > + *netmask_ptr = get_unaligned_be32( > + DHCP_OPT_PAYLOAD(in_dhcp_opt)); > + } > + break; > + case OVN_DHCP_OPT_CODE_ROUTER_IP: > + if (router_ip_ptr && in_dhcp_opt->len == 4) { > + *router_ip_ptr = get_unaligned_be32( > + DHCP_OPT_PAYLOAD(in_dhcp_opt)); > + } > + break; > + case DHCP_OPT_ETHERBOOT: > + if (ipxe_req_ptr) { > + *ipxe_req_ptr = true; > + } > + break; > + default: > + break; > + } > + } > +} > + > +/* Called with in the pinctrl_handler thread context. */ > +static void > +pinctrl_handle_dhcp_relay_req_chk( > + struct rconn *swconn, > + struct dp_packet *pkt_in, struct ofputil_packet_in *pin, > + struct ofpbuf *userdata, > + struct ofpbuf *continuation) > +{ > + enum ofp_version version = rconn_get_version(swconn); > + enum ofputil_protocol proto = > ofputil_protocol_from_ofp_version(version); > + struct dp_packet *pkt_out_ptr = NULL; > + uint32_t success = 0; > + > + /* Parse result field. */ > + const struct mf_field *f; > + enum ofperr ofperr = nx_pull_header(userdata, NULL, &f, NULL); > + if (ofperr) { > + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); > + VLOG_WARN_RL(&rl, "DHCP_RELAY_REQ_CHK: bad result OXM (%s)", > + ofperr_to_string(ofperr)); > + goto exit; > + } > + ovs_be32 *ofsp = ofpbuf_try_pull(userdata, sizeof *ofsp); > + /* Check that the result is valid and writable. */ > + struct mf_subfield dst = { .field = f, .ofs = ntohl(*ofsp), .n_bits = > 1 }; > + ofperr = mf_check_dst(&dst, NULL); > + if (ofperr) { > + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); > + VLOG_WARN_RL(&rl, "DHCP_RELAY_REQ_CHK: bad result bit (%s)", > + ofperr_to_string(ofperr)); > + goto exit; > + } > + > + /* Parse relay IP and server IP. */ > + ovs_be32 *relay_ip = ofpbuf_try_pull(userdata, sizeof *relay_ip); > + ovs_be32 *server_ip = ofpbuf_try_pull(userdata, sizeof *server_ip); > + if (!relay_ip || !server_ip) { > + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); > + VLOG_WARN_RL(&rl, "DHCP_RELAY_REQ_CHK: relay ip or server ip " > + "not present in the userdata"); > + goto exit; > + } > + > + size_t in_l4_size = dp_packet_l4_size(pkt_in); > + const char *end = (char *) dp_packet_l4(pkt_in) + in_l4_size; > + const char *in_dhcp_ptr = NULL; > + const struct dhcp_header *in_dhcp_data > + = dhcp_get_hdr_from_pkt(pkt_in, &in_dhcp_ptr, end); > + > + if (!in_dhcp_data) { > + goto exit; > + } > + ovs_assert(in_dhcp_ptr); > + > + if (in_dhcp_data->op != DHCP_OP_REQUEST) { > + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); > + VLOG_WARN_RL(&rl, "DHCP_RELAY_REQ_CHK: invalid opcode in the " > + "DHCP packet: %d", in_dhcp_data->op); > + goto exit; > + } > + > + if (in_dhcp_data->giaddr) { > + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); > + VLOG_WARN_RL(&rl, "DHCP_RELAY_REQ_CHK: giaddr is already set"); > + goto exit; > + } > + > + const uint8_t *in_dhcp_msg_type = NULL; > + ovs_be32 request_ip = in_dhcp_data->ciaddr; > + > + dhcp_parse_options(&in_dhcp_ptr, end, > + &in_dhcp_msg_type, &request_ip, NULL, NULL, NULL, NULL); > + > + /* Check whether the DHCP Message Type (opt 53) is present or not */ > + if (!in_dhcp_msg_type) { > + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); > + VLOG_WARN_RL(&rl, "DHCP_RELAY_REQ_CHK: missing message type"); > + goto exit; > + } > + > + /* Relay the DHCP request packet */ > + uint16_t new_l4_size = in_l4_size; > + size_t new_packet_size = pkt_in->l4_ofs + new_l4_size; > + > + struct dp_packet pkt_out; > + dp_packet_init(&pkt_out, new_packet_size); > + dp_packet_clear(&pkt_out); > + dp_packet_prealloc_tailroom(&pkt_out, new_packet_size); > + pkt_out_ptr = &pkt_out; > + > + /* Copy the L2 and L3 headers from the pkt_in as they would remain > same*/ > + dp_packet_put( > + &pkt_out, dp_packet_pull(pkt_in, pkt_in->l4_ofs), pkt_in->l4_ofs); > + > + pkt_out.l2_5_ofs = pkt_in->l2_5_ofs; > + pkt_out.l2_pad_size = pkt_in->l2_pad_size; > + pkt_out.l3_ofs = pkt_in->l3_ofs; > + pkt_out.l4_ofs = pkt_in->l4_ofs; > + > + struct udp_header *udp = dp_packet_put( > + &pkt_out, dp_packet_pull(pkt_in, UDP_HEADER_LEN), UDP_HEADER_LEN); > + > + struct dhcp_header *dhcp_data = dp_packet_put(&pkt_out, > + dp_packet_pull(pkt_in, new_l4_size - UDP_HEADER_LEN), > + new_l4_size - UDP_HEADER_LEN); > + > + uint8_t hops = dhcp_data->hops + 1; > + if (udp->udp_csum) { > + udp->udp_csum = recalc_csum16(udp->udp_csum, > + htons((uint16_t) dhcp_data->hops), htons((uint16_t) hops)); > + } > + dhcp_data->hops = hops; > + > + dhcp_data->giaddr = *relay_ip; > + if (udp->udp_csum) { > + udp->udp_csum = recalc_csum32(udp->udp_csum, > + 0, dhcp_data->giaddr); > + } > + pin->packet = dp_packet_data(&pkt_out); > + pin->packet_len = dp_packet_size(&pkt_out); > + > + /* Log the DHCP message. */ > + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(20, 40); > + VLOG_INFO_RL(&rl, "DHCP_RELAY_REQ_CHK:: MSG_TYPE:%s MAC:"ETH_ADDR_FMT > + " XID:%u" > + " REQ_IP:"IP_FMT > + " GIADDR:"IP_FMT > + " SERVER_ADDR:"IP_FMT, > + dhcp_msg_str_get(*in_dhcp_msg_type), > + ETH_ADDR_BYTES_ARGS(dhcp_data->chaddr), > ntohl(dhcp_data->xid), > + IP_ARGS(request_ip), IP_ARGS(dhcp_data->giaddr), > + IP_ARGS(*server_ip)); > + success = 1; > +exit: > + if (!ofperr) { > + union mf_subvalue sv; > + sv.u8_val = success; > + mf_write_subfield(&dst, &sv, &pin->flow_metadata); > + } > + queue_msg(swconn, ofputil_encode_resume(pin, continuation, proto)); > + if (pkt_out_ptr) { > + dp_packet_uninit(pkt_out_ptr); > + } > +} > + > +/* Called with in the pinctrl_handler thread context. */ > +static void > +pinctrl_handle_dhcp_relay_resp_chk( > + struct rconn *swconn, > + struct dp_packet *pkt_in, struct ofputil_packet_in *pin, > + struct ofpbuf *userdata, > + struct ofpbuf *continuation) > +{ > + enum ofp_version version = rconn_get_version(swconn); > + enum ofputil_protocol proto = > ofputil_protocol_from_ofp_version(version); > + struct dp_packet *pkt_out_ptr = NULL; > + uint32_t success = 0; > + > + /* Parse result field. */ > + const struct mf_field *f; > + enum ofperr ofperr = nx_pull_header(userdata, NULL, &f, NULL); > + if (ofperr) { > + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); > + VLOG_WARN_RL(&rl, "DHCP_RELAY_RESP_CHK: bad result OXM (%s)", > + ofperr_to_string(ofperr)); > + goto exit; > + } > + ovs_be32 *ofsp = ofpbuf_try_pull(userdata, sizeof *ofsp); > + /* Check that the result is valid and writable. */ > + struct mf_subfield dst = { .field = f, .ofs = ntohl(*ofsp), .n_bits = > 1 }; > + ofperr = mf_check_dst(&dst, NULL); > + if (ofperr) { > + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); > + VLOG_WARN_RL(&rl, "DHCP_RELAY_RESP_CHK: bad result bit (%s)", > + ofperr_to_string(ofperr)); > + goto exit; > + } > + > + /* Parse relay IP and server IP. */ > + ovs_be32 *relay_ip = ofpbuf_try_pull(userdata, sizeof *relay_ip); > + ovs_be32 *server_ip = ofpbuf_try_pull(userdata, sizeof *server_ip); > + if (!relay_ip || !server_ip) { > + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); > + VLOG_WARN_RL(&rl, "DHCP_RELAY_RESP_CHK: relay ip or server ip " > + "not present in the userdata"); > + goto exit; > + } > + > + size_t in_l4_size = dp_packet_l4_size(pkt_in); > + const char *end = (char *) dp_packet_l4(pkt_in) + in_l4_size; > + const char *in_dhcp_ptr = NULL; > + const struct dhcp_header *in_dhcp_data > + = dhcp_get_hdr_from_pkt(pkt_in, &in_dhcp_ptr, end); > + > + if (!in_dhcp_data) { > + goto exit; > + } > + ovs_assert(in_dhcp_ptr); > + > + if (in_dhcp_data->op != DHCP_OP_REPLY) { > + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); > + VLOG_WARN_RL(&rl, "DHCP_RELAY_RESP_CHK: invalid opcode " > + "in the packet: %d", in_dhcp_data->op); > + goto exit; > + } > + > + if (!in_dhcp_data->giaddr) { > + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); > + VLOG_WARN_RL(&rl, "DHCP_RELAY_RESP_CHK: giaddr is " > + "not set in request"); > + goto exit; > + } > + > + ovs_be32 giaddr = in_dhcp_data->giaddr; > + ovs_be32 yiaddr = in_dhcp_data->yiaddr; > + ovs_be32 server_id = 0, netmask = 0, router_ip = 0; > + const uint8_t *in_dhcp_msg_type = NULL; > + > + dhcp_parse_options(&in_dhcp_ptr, end, > + &in_dhcp_msg_type, NULL, NULL, &server_id, &netmask, &router_ip); > + > + /* Check whether the DHCP Message Type (opt 53) is present or not */ > + if (!in_dhcp_msg_type) { > + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); > + VLOG_WARN_RL(&rl, "DHCP_RELAY_RESP: missing message type"); > + goto exit; > + } > + > + if (!server_id) { > + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); > + VLOG_WARN_RL(&rl, "DHCP_RELAY_RESP: missing server identifier"); > + goto exit; > + } > + > + if (server_id != *server_ip) { > + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); > + VLOG_WARN_RL(&rl, "DHCP_RELAY_RESP: server identifier mismatch"); > + goto exit; > + } > + > + if (giaddr != *relay_ip) { > + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); > + VLOG_WARN_RL(&rl, "DHCP_RELAY_RESP: giaddr mismatch"); > + goto exit; > + } > + > + if (*in_dhcp_msg_type == DHCP_MSG_OFFER || > + *in_dhcp_msg_type == DHCP_MSG_ACK) { > + if ((yiaddr & netmask) != (giaddr & netmask)) { > + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); > + VLOG_INFO_RL(&rl, "DHCP_RELAY_RESP_CHK:: Allocated ip adress > and" > + " giaddr are not in same subnet." > + " MSG_TYPE:%s MAC:"ETH_ADDR_FMT > + " XID:%u" > + " YIADDR:"IP_FMT > + " GIADDR:"IP_FMT > + " SERVER_ADDR:"IP_FMT, > + dhcp_msg_str_get(*in_dhcp_msg_type), > + ETH_ADDR_BYTES_ARGS(in_dhcp_data->chaddr), > + ntohl(in_dhcp_data->xid), > + IP_ARGS(yiaddr), > + IP_ARGS(giaddr), IP_ARGS(server_id)); > + goto exit; > + } > + > + if (router_ip && router_ip != giaddr) { > + /* Log the default gateway mismatch and > + * continue with rest of the processing */ > + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); > + VLOG_INFO_RL(&rl, "DHCP_RELAY_RESP_CHK::" > + " Router ip adress and giaddr are not same." > + " MSG_TYPE:%s MAC:"ETH_ADDR_FMT > + " XID:%u" > + " YIADDR:"IP_FMT > + " GIADDR:"IP_FMT > + " SERVER_ADDR:"IP_FMT, > + dhcp_msg_str_get(*in_dhcp_msg_type), > + ETH_ADDR_BYTES_ARGS(in_dhcp_data->chaddr), > + ntohl(in_dhcp_data->xid), > + IP_ARGS(yiaddr), > + IP_ARGS(giaddr), IP_ARGS(server_id)); > + } > + } > + > + /* Update destination MAC & IP so that the packet is forward to the > + * right destination node. > + */ > + uint16_t new_l4_size = in_l4_size; > + size_t new_packet_size = pkt_in->l4_ofs + new_l4_size; > + > + struct dp_packet pkt_out; > + dp_packet_init(&pkt_out, new_packet_size); > + dp_packet_clear(&pkt_out); > + dp_packet_prealloc_tailroom(&pkt_out, new_packet_size); > + pkt_out_ptr = &pkt_out; > + > + /* Copy the L2 and L3 headers from the pkt_in as they would remain > same*/ > + struct eth_header *eth = dp_packet_put( > + &pkt_out, dp_packet_pull(pkt_in, pkt_in->l4_ofs), pkt_in->l4_ofs); > + > + pkt_out.l2_5_ofs = pkt_in->l2_5_ofs; > + pkt_out.l2_pad_size = pkt_in->l2_pad_size; > + pkt_out.l3_ofs = pkt_in->l3_ofs; > + pkt_out.l4_ofs = pkt_in->l4_ofs; > + > + struct udp_header *udp = dp_packet_put( > + &pkt_out, dp_packet_pull(pkt_in, UDP_HEADER_LEN), UDP_HEADER_LEN); > + > + struct dhcp_header *dhcp_data = dp_packet_put( > + &pkt_out, dp_packet_pull(pkt_in, new_l4_size - UDP_HEADER_LEN), > + new_l4_size - UDP_HEADER_LEN); > + memcpy(ð->eth_dst, dhcp_data->chaddr, sizeof(eth->eth_dst)); > + > + /* Send a broadcast IP frame when BROADCAST flag is set. */ > + struct ip_header *out_ip = dp_packet_l3(&pkt_out); > + ovs_be32 ip_dst; > + ovs_be32 ip_dst_orig = get_16aligned_be32(&out_ip->ip_dst); > + if (!is_dhcp_flags_broadcast(dhcp_data->flags)) { > + ip_dst = dhcp_data->yiaddr; > + } else { > + ip_dst = htonl(0xffffffff); > + } > + put_16aligned_be32(&out_ip->ip_dst, ip_dst); > + out_ip->ip_csum = recalc_csum32(out_ip->ip_csum, > + ip_dst_orig, ip_dst); > + if (udp->udp_csum) { > + udp->udp_csum = recalc_csum32(udp->udp_csum, > + ip_dst_orig, ip_dst); > + } > + pin->packet = dp_packet_data(&pkt_out); > + pin->packet_len = dp_packet_size(&pkt_out); > + > + /* Log the DHCP message. */ > + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(20, 40); > + VLOG_INFO_RL(&rl, "DHCP_RELAY_RESP_CHK:: MSG_TYPE:%s MAC:"ETH_ADDR_FMT > + " XID:%u" > + " YIADDR:"IP_FMT > + " GIADDR:"IP_FMT > + " SERVER_ADDR:"IP_FMT, > + dhcp_msg_str_get(*in_dhcp_msg_type), > + ETH_ADDR_BYTES_ARGS(dhcp_data->chaddr), > ntohl(dhcp_data->xid), > + IP_ARGS(yiaddr), > + IP_ARGS(giaddr), IP_ARGS(server_id)); > + success = 1; > +exit: > + if (!ofperr) { > + union mf_subvalue sv; > + sv.u8_val = success; > + mf_write_subfield(&dst, &sv, &pin->flow_metadata); > + } > + queue_msg(swconn, ofputil_encode_resume(pin, continuation, proto)); > + if (pkt_out_ptr) { > + dp_packet_uninit(pkt_out_ptr); > + } > +} > + > /* Called with in the pinctrl_handler thread context. */ > static void > pinctrl_handle_put_dhcp_opts( > @@ -2040,30 +2549,16 @@ pinctrl_handle_put_dhcp_opts( > goto exit; > } > > - /* Validate the DHCP request packet. > - * Format of the DHCP packet is > - * > ------------------------------------------------------------------------ > - *| UDP HEADER | DHCP HEADER | 4 Byte DHCP Cookie | DHCP > OPTIONS(var len)| > - * > ------------------------------------------------------------------------ > - */ > - > const char *end = (char *)dp_packet_l4(pkt_in) + > dp_packet_l4_size(pkt_in); > - const char *in_dhcp_ptr = dp_packet_get_udp_payload(pkt_in); > - if (!in_dhcp_ptr) { > - static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); > - VLOG_WARN_RL(&rl, "Invalid or incomplete DHCP packet received"); > - goto exit; > - } > - > + const char *in_dhcp_ptr = NULL; > const struct dhcp_header *in_dhcp_data > - = (const struct dhcp_header *) in_dhcp_ptr; > - in_dhcp_ptr += sizeof *in_dhcp_data; > - if (in_dhcp_ptr > end) { > - static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); > - VLOG_WARN_RL(&rl, "Invalid or incomplete DHCP packet received, " > - "bad data length"); > + = dhcp_get_hdr_from_pkt(pkt_in, &in_dhcp_ptr, end); > + > + if (!in_dhcp_data) { > goto exit; > } > + ovs_assert(in_dhcp_ptr); > + > if (in_dhcp_data->op != DHCP_OP_REQUEST) { > static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); > VLOG_WARN_RL(&rl, "Invalid opcode in the DHCP packet: %d", > @@ -2071,58 +2566,11 @@ pinctrl_handle_put_dhcp_opts( > goto exit; > } > > - /* DHCP options follow the DHCP header. The first 4 bytes of the DHCP > - * options is the DHCP magic cookie followed by the actual DHCP > options. > - */ > - ovs_be32 magic_cookie = htonl(DHCP_MAGIC_COOKIE); > - if (in_dhcp_ptr + sizeof magic_cookie > end || > - get_unaligned_be32((const void *) in_dhcp_ptr) != magic_cookie) { > - static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); > - VLOG_WARN_RL(&rl, "DHCP magic cookie not present in the DHCP > packet"); > - goto exit; > - } > - in_dhcp_ptr += sizeof magic_cookie; > - > bool ipxe_req = false; > const uint8_t *in_dhcp_msg_type = NULL; > ovs_be32 request_ip = in_dhcp_data->ciaddr; > - while (in_dhcp_ptr < end) { > - const struct dhcp_opt_header *in_dhcp_opt = > - (const struct dhcp_opt_header *)in_dhcp_ptr; > - if (in_dhcp_opt->code == DHCP_OPT_END) { > - break; > - } > - if (in_dhcp_opt->code == DHCP_OPT_PAD) { > - in_dhcp_ptr += 1; > - continue; > - } > - in_dhcp_ptr += sizeof *in_dhcp_opt; > - if (in_dhcp_ptr > end) { > - break; > - } > - in_dhcp_ptr += in_dhcp_opt->len; > - if (in_dhcp_ptr > end) { > - break; > - } > - > - switch (in_dhcp_opt->code) { > - case DHCP_OPT_MSG_TYPE: > - if (in_dhcp_opt->len == 1) { > - in_dhcp_msg_type = DHCP_OPT_PAYLOAD(in_dhcp_opt); > - } > - break; > - case DHCP_OPT_REQ_IP: > - if (in_dhcp_opt->len == 4) { > - request_ip = > get_unaligned_be32(DHCP_OPT_PAYLOAD(in_dhcp_opt)); > - } > - break; > - case DHCP_OPT_ETHERBOOT: > - ipxe_req = true; > - break; > - default: > - break; > - } > - } > + dhcp_parse_options(&in_dhcp_ptr, end, > + &in_dhcp_msg_type, &request_ip, &ipxe_req, NULL, NULL, NULL); > > /* Check that the DHCP Message Type (opt 53) is present or not with > * valid values - DHCP_MSG_DISCOVER or DHCP_MSG_REQUEST. > @@ -2329,6 +2777,7 @@ pinctrl_handle_put_dhcp_opts( > dhcp_data->yiaddr = 0; > } > > + ovs_be32 magic_cookie = htonl(DHCP_MAGIC_COOKIE); > dp_packet_put(&pkt_out, &magic_cookie, sizeof(ovs_be32)); > > uint16_t out_dhcp_opts_size = 12; > @@ -3298,6 +3747,16 @@ process_packet_in(struct rconn *swconn, const > struct ofp_header *msg) > ovs_mutex_unlock(&pinctrl_mutex); > break; > > + case ACTION_OPCODE_DHCP_RELAY_REQ_CHK: > + pinctrl_handle_dhcp_relay_req_chk(swconn, &packet, &pin, > + &userdata, &continuation); > + break; > + > + case ACTION_OPCODE_DHCP_RELAY_RESP_CHK: > + pinctrl_handle_dhcp_relay_resp_chk(swconn, &packet, &pin, > + &userdata, &continuation); > + break; > + > case ACTION_OPCODE_PUT_DHCP_OPTS: > pinctrl_handle_put_dhcp_opts(swconn, &packet, &pin, &headers, > &userdata, &continuation); > diff --git a/lib/ovn-l7.h b/lib/ovn-l7.h > index f4a30cc00..7f5673b12 100644 > --- a/lib/ovn-l7.h > +++ b/lib/ovn-l7.h > @@ -68,7 +68,9 @@ struct gen_opts_map { > * OVN_DHCP_OPT_CODE_<opt_name>. > */ > #define OVN_DHCP_OPT_CODE_NETMASK 1 > +#define OVN_DHCP_OPT_CODE_ROUTER_IP 3 > #define OVN_DHCP_OPT_CODE_LEASE_TIME 51 > +#define OVN_DHCP_OPT_CODE_SERVER_ID 54 > #define OVN_DHCP_OPT_CODE_T1 58 > #define OVN_DHCP_OPT_CODE_T2 59 > > -- > 2.36.6 > > _______________________________________________ > dev mailing list > dev@openvswitch.org > https://mail.openvswitch.org/mailman/listinfo/ovs-dev > >
diff --git a/controller/pinctrl.c b/controller/pinctrl.c index aa73facbf..50e090cd2 100644 --- a/controller/pinctrl.c +++ b/controller/pinctrl.c @@ -1993,6 +1993,515 @@ is_dhcp_flags_broadcast(ovs_be16 flags) return flags & htons(DHCP_BROADCAST_FLAG); } +static const char *dhcp_msg_str[] = { + [0] = "INVALID", + [DHCP_MSG_DISCOVER] = "DISCOVER", + [DHCP_MSG_OFFER] = "OFFER", + [DHCP_MSG_REQUEST] = "REQUEST", + [OVN_DHCP_MSG_DECLINE] = "DECLINE", + [DHCP_MSG_ACK] = "ACK", + [DHCP_MSG_NAK] = "NAK", + [OVN_DHCP_MSG_RELEASE] = "RELEASE", + [OVN_DHCP_MSG_INFORM] = "INFORM" +}; + +static bool +dhcp_relay_is_msg_type_supported(uint8_t msg_type) +{ + return (msg_type >= DHCP_MSG_DISCOVER && msg_type <= OVN_DHCP_MSG_RELEASE); +} + +static const char *dhcp_msg_str_get(uint8_t msg_type) +{ + if (!dhcp_relay_is_msg_type_supported(msg_type)) { + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); + VLOG_WARN_RL(&rl, "Unknown DHCP msg type: %u", msg_type); + return "UNKNOWN"; + } + return dhcp_msg_str[msg_type]; +} + +static const struct dhcp_header * +dhcp_get_hdr_from_pkt(struct dp_packet *pkt_in, const char **in_dhcp_pptr, + const char *end) +{ + /* Validate the DHCP request packet. + * Format of the DHCP packet is + * ----------------------------------------------------------------------- + *| UDP HEADER | DHCP HEADER | 4 Byte DHCP Cookie | DHCP OPTIONS(var len) | + * ----------------------------------------------------------------------- + */ + + *in_dhcp_pptr = dp_packet_get_udp_payload(pkt_in); + if (*in_dhcp_pptr == NULL) { + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); + VLOG_WARN_RL(&rl, "DHCP: Invalid or incomplete DHCP packet received"); + return NULL; + } + + const struct dhcp_header *dhcp_hdr + = (const struct dhcp_header *) *in_dhcp_pptr; + (*in_dhcp_pptr) += sizeof *dhcp_hdr; + if (*in_dhcp_pptr > end) { + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); + VLOG_WARN_RL(&rl, "DHCP: Invalid or incomplete DHCP packet received, " + "bad data length"); + return NULL; + } + + if (dhcp_hdr->htype != 0x1) { + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); + VLOG_WARN_RL(&rl, "DHCP: Packet is recieved with " + "unsupported hardware type"); + return NULL; + } + + if (dhcp_hdr->hlen != 0x6) { + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); + VLOG_WARN_RL(&rl, "DHCP: Packet is recieved with " + "unsupported hardware length"); + return NULL; + } + + /* DHCP options follow the DHCP header. The first 4 bytes of the DHCP + * options is the DHCP magic cookie followed by the actual DHCP options. + */ + ovs_be32 magic_cookie = htonl(DHCP_MAGIC_COOKIE); + if ((*in_dhcp_pptr) + sizeof magic_cookie > end || + get_unaligned_be32((const void *) (*in_dhcp_pptr)) != magic_cookie) { + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); + VLOG_WARN_RL(&rl, "DHCP: Magic cookie not present in the DHCP packet"); + return NULL; + } + + (*in_dhcp_pptr) += sizeof magic_cookie; + + return dhcp_hdr; +} + +static void +dhcp_parse_options(const char **in_dhcp_pptr, const char *end, + const uint8_t **dhcp_msg_type_pptr, + ovs_be32 *request_ip_ptr, + bool *ipxe_req_ptr, ovs_be32 *server_id_ptr, + ovs_be32 *netmask_ptr, ovs_be32 *router_ip_ptr) +{ + while ((*in_dhcp_pptr) < end) { + const struct dhcp_opt_header *in_dhcp_opt = + (const struct dhcp_opt_header *) *in_dhcp_pptr; + if (in_dhcp_opt->code == DHCP_OPT_END) { + break; + } + if (in_dhcp_opt->code == DHCP_OPT_PAD) { + (*in_dhcp_pptr) += 1; + continue; + } + (*in_dhcp_pptr) += sizeof *in_dhcp_opt; + if ((*in_dhcp_pptr) > end) { + break; + } + (*in_dhcp_pptr) += in_dhcp_opt->len; + if ((*in_dhcp_pptr) > end) { + break; + } + + switch (in_dhcp_opt->code) { + case DHCP_OPT_MSG_TYPE: + if (dhcp_msg_type_pptr && in_dhcp_opt->len == 1) { + *dhcp_msg_type_pptr = DHCP_OPT_PAYLOAD(in_dhcp_opt); + } + break; + case DHCP_OPT_REQ_IP: + if (request_ip_ptr && in_dhcp_opt->len == 4) { + *request_ip_ptr = get_unaligned_be32( + DHCP_OPT_PAYLOAD(in_dhcp_opt)); + } + break; + case OVN_DHCP_OPT_CODE_SERVER_ID: + if (server_id_ptr && in_dhcp_opt->len == 4) { + *server_id_ptr = get_unaligned_be32( + DHCP_OPT_PAYLOAD(in_dhcp_opt)); + } + break; + case OVN_DHCP_OPT_CODE_NETMASK: + if (netmask_ptr && in_dhcp_opt->len == 4) { + *netmask_ptr = get_unaligned_be32( + DHCP_OPT_PAYLOAD(in_dhcp_opt)); + } + break; + case OVN_DHCP_OPT_CODE_ROUTER_IP: + if (router_ip_ptr && in_dhcp_opt->len == 4) { + *router_ip_ptr = get_unaligned_be32( + DHCP_OPT_PAYLOAD(in_dhcp_opt)); + } + break; + case DHCP_OPT_ETHERBOOT: + if (ipxe_req_ptr) { + *ipxe_req_ptr = true; + } + break; + default: + break; + } + } +} + +/* Called with in the pinctrl_handler thread context. */ +static void +pinctrl_handle_dhcp_relay_req_chk( + struct rconn *swconn, + struct dp_packet *pkt_in, struct ofputil_packet_in *pin, + struct ofpbuf *userdata, + struct ofpbuf *continuation) +{ + enum ofp_version version = rconn_get_version(swconn); + enum ofputil_protocol proto = ofputil_protocol_from_ofp_version(version); + struct dp_packet *pkt_out_ptr = NULL; + uint32_t success = 0; + + /* Parse result field. */ + const struct mf_field *f; + enum ofperr ofperr = nx_pull_header(userdata, NULL, &f, NULL); + if (ofperr) { + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); + VLOG_WARN_RL(&rl, "DHCP_RELAY_REQ_CHK: bad result OXM (%s)", + ofperr_to_string(ofperr)); + goto exit; + } + ovs_be32 *ofsp = ofpbuf_try_pull(userdata, sizeof *ofsp); + /* Check that the result is valid and writable. */ + struct mf_subfield dst = { .field = f, .ofs = ntohl(*ofsp), .n_bits = 1 }; + ofperr = mf_check_dst(&dst, NULL); + if (ofperr) { + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); + VLOG_WARN_RL(&rl, "DHCP_RELAY_REQ_CHK: bad result bit (%s)", + ofperr_to_string(ofperr)); + goto exit; + } + + /* Parse relay IP and server IP. */ + ovs_be32 *relay_ip = ofpbuf_try_pull(userdata, sizeof *relay_ip); + ovs_be32 *server_ip = ofpbuf_try_pull(userdata, sizeof *server_ip); + if (!relay_ip || !server_ip) { + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); + VLOG_WARN_RL(&rl, "DHCP_RELAY_REQ_CHK: relay ip or server ip " + "not present in the userdata"); + goto exit; + } + + size_t in_l4_size = dp_packet_l4_size(pkt_in); + const char *end = (char *) dp_packet_l4(pkt_in) + in_l4_size; + const char *in_dhcp_ptr = NULL; + const struct dhcp_header *in_dhcp_data + = dhcp_get_hdr_from_pkt(pkt_in, &in_dhcp_ptr, end); + + if (!in_dhcp_data) { + goto exit; + } + ovs_assert(in_dhcp_ptr); + + if (in_dhcp_data->op != DHCP_OP_REQUEST) { + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); + VLOG_WARN_RL(&rl, "DHCP_RELAY_REQ_CHK: invalid opcode in the " + "DHCP packet: %d", in_dhcp_data->op); + goto exit; + } + + if (in_dhcp_data->giaddr) { + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); + VLOG_WARN_RL(&rl, "DHCP_RELAY_REQ_CHK: giaddr is already set"); + goto exit; + } + + const uint8_t *in_dhcp_msg_type = NULL; + ovs_be32 request_ip = in_dhcp_data->ciaddr; + + dhcp_parse_options(&in_dhcp_ptr, end, + &in_dhcp_msg_type, &request_ip, NULL, NULL, NULL, NULL); + + /* Check whether the DHCP Message Type (opt 53) is present or not */ + if (!in_dhcp_msg_type) { + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); + VLOG_WARN_RL(&rl, "DHCP_RELAY_REQ_CHK: missing message type"); + goto exit; + } + + /* Relay the DHCP request packet */ + uint16_t new_l4_size = in_l4_size; + size_t new_packet_size = pkt_in->l4_ofs + new_l4_size; + + struct dp_packet pkt_out; + dp_packet_init(&pkt_out, new_packet_size); + dp_packet_clear(&pkt_out); + dp_packet_prealloc_tailroom(&pkt_out, new_packet_size); + pkt_out_ptr = &pkt_out; + + /* Copy the L2 and L3 headers from the pkt_in as they would remain same*/ + dp_packet_put( + &pkt_out, dp_packet_pull(pkt_in, pkt_in->l4_ofs), pkt_in->l4_ofs); + + pkt_out.l2_5_ofs = pkt_in->l2_5_ofs; + pkt_out.l2_pad_size = pkt_in->l2_pad_size; + pkt_out.l3_ofs = pkt_in->l3_ofs; + pkt_out.l4_ofs = pkt_in->l4_ofs; + + struct udp_header *udp = dp_packet_put( + &pkt_out, dp_packet_pull(pkt_in, UDP_HEADER_LEN), UDP_HEADER_LEN); + + struct dhcp_header *dhcp_data = dp_packet_put(&pkt_out, + dp_packet_pull(pkt_in, new_l4_size - UDP_HEADER_LEN), + new_l4_size - UDP_HEADER_LEN); + + uint8_t hops = dhcp_data->hops + 1; + if (udp->udp_csum) { + udp->udp_csum = recalc_csum16(udp->udp_csum, + htons((uint16_t) dhcp_data->hops), htons((uint16_t) hops)); + } + dhcp_data->hops = hops; + + dhcp_data->giaddr = *relay_ip; + if (udp->udp_csum) { + udp->udp_csum = recalc_csum32(udp->udp_csum, + 0, dhcp_data->giaddr); + } + pin->packet = dp_packet_data(&pkt_out); + pin->packet_len = dp_packet_size(&pkt_out); + + /* Log the DHCP message. */ + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(20, 40); + VLOG_INFO_RL(&rl, "DHCP_RELAY_REQ_CHK:: MSG_TYPE:%s MAC:"ETH_ADDR_FMT + " XID:%u" + " REQ_IP:"IP_FMT + " GIADDR:"IP_FMT + " SERVER_ADDR:"IP_FMT, + dhcp_msg_str_get(*in_dhcp_msg_type), + ETH_ADDR_BYTES_ARGS(dhcp_data->chaddr), ntohl(dhcp_data->xid), + IP_ARGS(request_ip), IP_ARGS(dhcp_data->giaddr), + IP_ARGS(*server_ip)); + success = 1; +exit: + if (!ofperr) { + union mf_subvalue sv; + sv.u8_val = success; + mf_write_subfield(&dst, &sv, &pin->flow_metadata); + } + queue_msg(swconn, ofputil_encode_resume(pin, continuation, proto)); + if (pkt_out_ptr) { + dp_packet_uninit(pkt_out_ptr); + } +} + +/* Called with in the pinctrl_handler thread context. */ +static void +pinctrl_handle_dhcp_relay_resp_chk( + struct rconn *swconn, + struct dp_packet *pkt_in, struct ofputil_packet_in *pin, + struct ofpbuf *userdata, + struct ofpbuf *continuation) +{ + enum ofp_version version = rconn_get_version(swconn); + enum ofputil_protocol proto = ofputil_protocol_from_ofp_version(version); + struct dp_packet *pkt_out_ptr = NULL; + uint32_t success = 0; + + /* Parse result field. */ + const struct mf_field *f; + enum ofperr ofperr = nx_pull_header(userdata, NULL, &f, NULL); + if (ofperr) { + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); + VLOG_WARN_RL(&rl, "DHCP_RELAY_RESP_CHK: bad result OXM (%s)", + ofperr_to_string(ofperr)); + goto exit; + } + ovs_be32 *ofsp = ofpbuf_try_pull(userdata, sizeof *ofsp); + /* Check that the result is valid and writable. */ + struct mf_subfield dst = { .field = f, .ofs = ntohl(*ofsp), .n_bits = 1 }; + ofperr = mf_check_dst(&dst, NULL); + if (ofperr) { + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); + VLOG_WARN_RL(&rl, "DHCP_RELAY_RESP_CHK: bad result bit (%s)", + ofperr_to_string(ofperr)); + goto exit; + } + + /* Parse relay IP and server IP. */ + ovs_be32 *relay_ip = ofpbuf_try_pull(userdata, sizeof *relay_ip); + ovs_be32 *server_ip = ofpbuf_try_pull(userdata, sizeof *server_ip); + if (!relay_ip || !server_ip) { + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); + VLOG_WARN_RL(&rl, "DHCP_RELAY_RESP_CHK: relay ip or server ip " + "not present in the userdata"); + goto exit; + } + + size_t in_l4_size = dp_packet_l4_size(pkt_in); + const char *end = (char *) dp_packet_l4(pkt_in) + in_l4_size; + const char *in_dhcp_ptr = NULL; + const struct dhcp_header *in_dhcp_data + = dhcp_get_hdr_from_pkt(pkt_in, &in_dhcp_ptr, end); + + if (!in_dhcp_data) { + goto exit; + } + ovs_assert(in_dhcp_ptr); + + if (in_dhcp_data->op != DHCP_OP_REPLY) { + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); + VLOG_WARN_RL(&rl, "DHCP_RELAY_RESP_CHK: invalid opcode " + "in the packet: %d", in_dhcp_data->op); + goto exit; + } + + if (!in_dhcp_data->giaddr) { + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); + VLOG_WARN_RL(&rl, "DHCP_RELAY_RESP_CHK: giaddr is " + "not set in request"); + goto exit; + } + + ovs_be32 giaddr = in_dhcp_data->giaddr; + ovs_be32 yiaddr = in_dhcp_data->yiaddr; + ovs_be32 server_id = 0, netmask = 0, router_ip = 0; + const uint8_t *in_dhcp_msg_type = NULL; + + dhcp_parse_options(&in_dhcp_ptr, end, + &in_dhcp_msg_type, NULL, NULL, &server_id, &netmask, &router_ip); + + /* Check whether the DHCP Message Type (opt 53) is present or not */ + if (!in_dhcp_msg_type) { + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); + VLOG_WARN_RL(&rl, "DHCP_RELAY_RESP: missing message type"); + goto exit; + } + + if (!server_id) { + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); + VLOG_WARN_RL(&rl, "DHCP_RELAY_RESP: missing server identifier"); + goto exit; + } + + if (server_id != *server_ip) { + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); + VLOG_WARN_RL(&rl, "DHCP_RELAY_RESP: server identifier mismatch"); + goto exit; + } + + if (giaddr != *relay_ip) { + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); + VLOG_WARN_RL(&rl, "DHCP_RELAY_RESP: giaddr mismatch"); + goto exit; + } + + if (*in_dhcp_msg_type == DHCP_MSG_OFFER || + *in_dhcp_msg_type == DHCP_MSG_ACK) { + if ((yiaddr & netmask) != (giaddr & netmask)) { + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); + VLOG_INFO_RL(&rl, "DHCP_RELAY_RESP_CHK:: Allocated ip adress and" + " giaddr are not in same subnet." + " MSG_TYPE:%s MAC:"ETH_ADDR_FMT + " XID:%u" + " YIADDR:"IP_FMT + " GIADDR:"IP_FMT + " SERVER_ADDR:"IP_FMT, + dhcp_msg_str_get(*in_dhcp_msg_type), + ETH_ADDR_BYTES_ARGS(in_dhcp_data->chaddr), + ntohl(in_dhcp_data->xid), + IP_ARGS(yiaddr), + IP_ARGS(giaddr), IP_ARGS(server_id)); + goto exit; + } + + if (router_ip && router_ip != giaddr) { + /* Log the default gateway mismatch and + * continue with rest of the processing */ + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); + VLOG_INFO_RL(&rl, "DHCP_RELAY_RESP_CHK::" + " Router ip adress and giaddr are not same." + " MSG_TYPE:%s MAC:"ETH_ADDR_FMT + " XID:%u" + " YIADDR:"IP_FMT + " GIADDR:"IP_FMT + " SERVER_ADDR:"IP_FMT, + dhcp_msg_str_get(*in_dhcp_msg_type), + ETH_ADDR_BYTES_ARGS(in_dhcp_data->chaddr), + ntohl(in_dhcp_data->xid), + IP_ARGS(yiaddr), + IP_ARGS(giaddr), IP_ARGS(server_id)); + } + } + + /* Update destination MAC & IP so that the packet is forward to the + * right destination node. + */ + uint16_t new_l4_size = in_l4_size; + size_t new_packet_size = pkt_in->l4_ofs + new_l4_size; + + struct dp_packet pkt_out; + dp_packet_init(&pkt_out, new_packet_size); + dp_packet_clear(&pkt_out); + dp_packet_prealloc_tailroom(&pkt_out, new_packet_size); + pkt_out_ptr = &pkt_out; + + /* Copy the L2 and L3 headers from the pkt_in as they would remain same*/ + struct eth_header *eth = dp_packet_put( + &pkt_out, dp_packet_pull(pkt_in, pkt_in->l4_ofs), pkt_in->l4_ofs); + + pkt_out.l2_5_ofs = pkt_in->l2_5_ofs; + pkt_out.l2_pad_size = pkt_in->l2_pad_size; + pkt_out.l3_ofs = pkt_in->l3_ofs; + pkt_out.l4_ofs = pkt_in->l4_ofs; + + struct udp_header *udp = dp_packet_put( + &pkt_out, dp_packet_pull(pkt_in, UDP_HEADER_LEN), UDP_HEADER_LEN); + + struct dhcp_header *dhcp_data = dp_packet_put( + &pkt_out, dp_packet_pull(pkt_in, new_l4_size - UDP_HEADER_LEN), + new_l4_size - UDP_HEADER_LEN); + memcpy(ð->eth_dst, dhcp_data->chaddr, sizeof(eth->eth_dst)); + + /* Send a broadcast IP frame when BROADCAST flag is set. */ + struct ip_header *out_ip = dp_packet_l3(&pkt_out); + ovs_be32 ip_dst; + ovs_be32 ip_dst_orig = get_16aligned_be32(&out_ip->ip_dst); + if (!is_dhcp_flags_broadcast(dhcp_data->flags)) { + ip_dst = dhcp_data->yiaddr; + } else { + ip_dst = htonl(0xffffffff); + } + put_16aligned_be32(&out_ip->ip_dst, ip_dst); + out_ip->ip_csum = recalc_csum32(out_ip->ip_csum, + ip_dst_orig, ip_dst); + if (udp->udp_csum) { + udp->udp_csum = recalc_csum32(udp->udp_csum, + ip_dst_orig, ip_dst); + } + pin->packet = dp_packet_data(&pkt_out); + pin->packet_len = dp_packet_size(&pkt_out); + + /* Log the DHCP message. */ + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(20, 40); + VLOG_INFO_RL(&rl, "DHCP_RELAY_RESP_CHK:: MSG_TYPE:%s MAC:"ETH_ADDR_FMT + " XID:%u" + " YIADDR:"IP_FMT + " GIADDR:"IP_FMT + " SERVER_ADDR:"IP_FMT, + dhcp_msg_str_get(*in_dhcp_msg_type), + ETH_ADDR_BYTES_ARGS(dhcp_data->chaddr), ntohl(dhcp_data->xid), + IP_ARGS(yiaddr), + IP_ARGS(giaddr), IP_ARGS(server_id)); + success = 1; +exit: + if (!ofperr) { + union mf_subvalue sv; + sv.u8_val = success; + mf_write_subfield(&dst, &sv, &pin->flow_metadata); + } + queue_msg(swconn, ofputil_encode_resume(pin, continuation, proto)); + if (pkt_out_ptr) { + dp_packet_uninit(pkt_out_ptr); + } +} + /* Called with in the pinctrl_handler thread context. */ static void pinctrl_handle_put_dhcp_opts( @@ -2040,30 +2549,16 @@ pinctrl_handle_put_dhcp_opts( goto exit; } - /* Validate the DHCP request packet. - * Format of the DHCP packet is - * ------------------------------------------------------------------------ - *| UDP HEADER | DHCP HEADER | 4 Byte DHCP Cookie | DHCP OPTIONS(var len)| - * ------------------------------------------------------------------------ - */ - const char *end = (char *)dp_packet_l4(pkt_in) + dp_packet_l4_size(pkt_in); - const char *in_dhcp_ptr = dp_packet_get_udp_payload(pkt_in); - if (!in_dhcp_ptr) { - static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); - VLOG_WARN_RL(&rl, "Invalid or incomplete DHCP packet received"); - goto exit; - } - + const char *in_dhcp_ptr = NULL; const struct dhcp_header *in_dhcp_data - = (const struct dhcp_header *) in_dhcp_ptr; - in_dhcp_ptr += sizeof *in_dhcp_data; - if (in_dhcp_ptr > end) { - static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); - VLOG_WARN_RL(&rl, "Invalid or incomplete DHCP packet received, " - "bad data length"); + = dhcp_get_hdr_from_pkt(pkt_in, &in_dhcp_ptr, end); + + if (!in_dhcp_data) { goto exit; } + ovs_assert(in_dhcp_ptr); + if (in_dhcp_data->op != DHCP_OP_REQUEST) { static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); VLOG_WARN_RL(&rl, "Invalid opcode in the DHCP packet: %d", @@ -2071,58 +2566,11 @@ pinctrl_handle_put_dhcp_opts( goto exit; } - /* DHCP options follow the DHCP header. The first 4 bytes of the DHCP - * options is the DHCP magic cookie followed by the actual DHCP options. - */ - ovs_be32 magic_cookie = htonl(DHCP_MAGIC_COOKIE); - if (in_dhcp_ptr + sizeof magic_cookie > end || - get_unaligned_be32((const void *) in_dhcp_ptr) != magic_cookie) { - static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); - VLOG_WARN_RL(&rl, "DHCP magic cookie not present in the DHCP packet"); - goto exit; - } - in_dhcp_ptr += sizeof magic_cookie; - bool ipxe_req = false; const uint8_t *in_dhcp_msg_type = NULL; ovs_be32 request_ip = in_dhcp_data->ciaddr; - while (in_dhcp_ptr < end) { - const struct dhcp_opt_header *in_dhcp_opt = - (const struct dhcp_opt_header *)in_dhcp_ptr; - if (in_dhcp_opt->code == DHCP_OPT_END) { - break; - } - if (in_dhcp_opt->code == DHCP_OPT_PAD) { - in_dhcp_ptr += 1; - continue; - } - in_dhcp_ptr += sizeof *in_dhcp_opt; - if (in_dhcp_ptr > end) { - break; - } - in_dhcp_ptr += in_dhcp_opt->len; - if (in_dhcp_ptr > end) { - break; - } - - switch (in_dhcp_opt->code) { - case DHCP_OPT_MSG_TYPE: - if (in_dhcp_opt->len == 1) { - in_dhcp_msg_type = DHCP_OPT_PAYLOAD(in_dhcp_opt); - } - break; - case DHCP_OPT_REQ_IP: - if (in_dhcp_opt->len == 4) { - request_ip = get_unaligned_be32(DHCP_OPT_PAYLOAD(in_dhcp_opt)); - } - break; - case DHCP_OPT_ETHERBOOT: - ipxe_req = true; - break; - default: - break; - } - } + dhcp_parse_options(&in_dhcp_ptr, end, + &in_dhcp_msg_type, &request_ip, &ipxe_req, NULL, NULL, NULL); /* Check that the DHCP Message Type (opt 53) is present or not with * valid values - DHCP_MSG_DISCOVER or DHCP_MSG_REQUEST. @@ -2329,6 +2777,7 @@ pinctrl_handle_put_dhcp_opts( dhcp_data->yiaddr = 0; } + ovs_be32 magic_cookie = htonl(DHCP_MAGIC_COOKIE); dp_packet_put(&pkt_out, &magic_cookie, sizeof(ovs_be32)); uint16_t out_dhcp_opts_size = 12; @@ -3298,6 +3747,16 @@ process_packet_in(struct rconn *swconn, const struct ofp_header *msg) ovs_mutex_unlock(&pinctrl_mutex); break; + case ACTION_OPCODE_DHCP_RELAY_REQ_CHK: + pinctrl_handle_dhcp_relay_req_chk(swconn, &packet, &pin, + &userdata, &continuation); + break; + + case ACTION_OPCODE_DHCP_RELAY_RESP_CHK: + pinctrl_handle_dhcp_relay_resp_chk(swconn, &packet, &pin, + &userdata, &continuation); + break; + case ACTION_OPCODE_PUT_DHCP_OPTS: pinctrl_handle_put_dhcp_opts(swconn, &packet, &pin, &headers, &userdata, &continuation); diff --git a/lib/ovn-l7.h b/lib/ovn-l7.h index f4a30cc00..7f5673b12 100644 --- a/lib/ovn-l7.h +++ b/lib/ovn-l7.h @@ -68,7 +68,9 @@ struct gen_opts_map { * OVN_DHCP_OPT_CODE_<opt_name>. */ #define OVN_DHCP_OPT_CODE_NETMASK 1 +#define OVN_DHCP_OPT_CODE_ROUTER_IP 3 #define OVN_DHCP_OPT_CODE_LEASE_TIME 51 +#define OVN_DHCP_OPT_CODE_SERVER_ID 54 #define OVN_DHCP_OPT_CODE_T1 58 #define OVN_DHCP_OPT_CODE_T2 59
Added changes in pinctrl to process DHCP Relay opcodes: - ACTION_OPCODE_DHCP_RELAY_REQ_CHK: For request packets - ACTION_OPCODE_DHCP_RELAY_RESP_CHK: For response packet Signed-off-by: Naveen Yerramneni <naveen.yerramneni@nutanix.com> --- controller/pinctrl.c | 597 ++++++++++++++++++++++++++++++++++++++----- lib/ovn-l7.h | 2 + 2 files changed, 530 insertions(+), 69 deletions(-)