On Fri, Aug 05, 2016 at 09:36:07AM +0530, Numan Siddique wrote: > This patch adds a new OVN action 'put_dhcpv6_opts' to support native > DHCPv6 in OVN. > > ovn-controller parses this action and adds a NXT_PACKET_IN2 > OF flow with 'pause' flag set and the DHCPv6 options stored in > 'userdata' field. > > When the valid DHCPv6 packet is received by ovn-controller, it frames a > new DHCPv6 reply packet with the DHCPv6 options present in the > 'userdata' field and resumes the packet and stores 1 in the 1-bit subfield. > If the packet is invalid, it resumes the packet without any modifying and > stores 0 in the 1-bit subfield. > > Eg. reg0[3] = put_dhcpv6_opts(ia_addr = aef0::4, server_id = > 00:00:00:00:10:02, > dns_server = {ae70::1,ae70::2}....) > > A new 'DHCPv6_Options' table is added in SB DB which stores > the supported DHCPv6 options with DHCPv6 code and type. ovn-northd is > expected to popule this table. > > Upcoming patch will add logical flows using this action. > > Signed-off-by: Numan Siddique <nusid...@redhat.com>
Thanks for the patch! I folded in the following incremental, mostly for style and documentation reasons, but also the following because I was nervous about properly validating the internal UDP length: @@ -543,7 +540,9 @@ pinctrl_handle_put_dhcpv6_opts( * response. */ ovs_be32 iaid = 0; struct dhcpv6_opt_header const *in_opt_client_id = NULL; - uint8_t *end = (uint8_t *)in_udp + ntohs(in_udp->udp_len); + size_t udp_len = ntohs(in_udp->udp_len); + size_t l4_len = dp_packet_l4_size(pkt_in); + uint8_t *end = (uint8_t *)in_udp + MIN(udp_len, l4_len); while (in_dhcpv6_data < end) { struct dhcpv6_opt_header const *in_opt = (struct dhcpv6_opt_header *)in_dhcpv6_data; I'll apply this in a minute along with patch 2/2. --8<--------------------------cut here-------------------------->8-- diff --git a/include/ovn/actions.h b/include/ovn/actions.h index e94891b..f1f38c6 100644 --- a/include/ovn/actions.h +++ b/include/ovn/actions.h @@ -90,6 +90,7 @@ enum action_opcode { * MFF_ETH_SRC = mac */ ACTION_OPCODE_PUT_ND, + /* "result = put_dhcpv6_opts(option, ...)". * * Arguments follow the action_header, in this format: diff --git a/ovn/controller/pinctrl.c b/ovn/controller/pinctrl.c index 1eeceee..8a759cd 100644 --- a/ovn/controller/pinctrl.c +++ b/ovn/controller/pinctrl.c @@ -384,14 +384,14 @@ compose_out_dhcpv6_opts(struct ofpbuf *userdata, return false; } - switch(userdata_opt->code) { + switch (userdata_opt->code) { case DHCPV6_OPT_SERVER_ID_CODE: { - /* The Server Identifier option is used to carry a DUID + /* The Server Identifier option carries a DUID * identifying a server between a client and a server. - * See RFC 3315 Sec 9 and Sec 22.3 + * See RFC 3315 Sec 9 and Sec 22.3. * - * We will use DUID Based on Link-layer Address [DUID-LL] + * We use DUID Based on Link-layer Address [DUID-LL]. */ struct dhcpv6_opt_server_id *opt_server_id = ofpbuf_put_zeros( @@ -431,8 +431,8 @@ compose_out_dhcpv6_opts(struct ofpbuf *userdata, opt_ia_na->opt.len = htons(12 + sizeof(struct dhcpv6_opt_ia_addr)); opt_ia_na->iaid = iaid; /* Set the lifetime of the address(es) to infinity */ - opt_ia_na->t1 = htonl(UINT32_MAX); - opt_ia_na->t2 = htonl(UINT32_MAX); + opt_ia_na->t1 = OVS_BE32_MAX; + opt_ia_na->t2 = OVS_BE32_MAX; struct dhcpv6_opt_ia_addr *opt_ia_addr = ofpbuf_put_zeros( out_dhcpv6_opts, sizeof *opt_ia_addr); @@ -440,8 +440,8 @@ compose_out_dhcpv6_opts(struct ofpbuf *userdata, opt_ia_addr->opt.len = htons(userdata_opt->len + 8); memcpy(opt_ia_addr->ipv6.s6_addr, userdata_opt_data, userdata_opt->len); - opt_ia_addr->t1 = htonl(UINT32_MAX); - opt_ia_addr->t2 = htonl(UINT32_MAX); + opt_ia_addr->t1 = OVS_BE32_MAX; + opt_ia_addr->t2 = OVS_BE32_MAX; break; } @@ -480,6 +480,7 @@ pinctrl_handle_put_dhcpv6_opts( struct dp_packet *pkt_in, struct ofputil_packet_in *pin, struct ofpbuf *userdata, struct ofpbuf *continuation OVS_UNUSED) { + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); 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; @@ -489,7 +490,6 @@ pinctrl_handle_put_dhcpv6_opts( const struct mf_field *f; enum ofperr ofperr = nx_pull_header(userdata, &f, NULL); if (ofperr) { - static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); VLOG_WARN_RL(&rl, "bad result OXM (%s)", ofperr_to_string(ofperr)); goto exit; } @@ -497,7 +497,6 @@ pinctrl_handle_put_dhcpv6_opts( /* Parse result offset. */ ovs_be32 *ofsp = ofpbuf_try_pull(userdata, sizeof *ofsp); if (!ofsp) { - static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); VLOG_WARN_RL(&rl, "offset not present in the userdata"); goto exit; } @@ -506,13 +505,11 @@ pinctrl_handle_put_dhcpv6_opts( 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, "bad result bit (%s)", ofperr_to_string(ofperr)); goto exit; } if (!userdata->size) { - static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); VLOG_WARN_RL(&rl, "DHCPv6 options not present in the userdata"); goto exit; } @@ -543,7 +540,9 @@ pinctrl_handle_put_dhcpv6_opts( * response. */ ovs_be32 iaid = 0; struct dhcpv6_opt_header const *in_opt_client_id = NULL; - uint8_t *end = (uint8_t *)in_udp + ntohs(in_udp->udp_len); + size_t udp_len = ntohs(in_udp->udp_len); + size_t l4_len = dp_packet_l4_size(pkt_in); + uint8_t *end = (uint8_t *)in_udp + MIN(udp_len, l4_len); while (in_dhcpv6_data < end) { struct dhcpv6_opt_header const *in_opt = (struct dhcpv6_opt_header *)in_dhcpv6_data; @@ -563,18 +562,16 @@ pinctrl_handle_put_dhcpv6_opts( default: break; } - in_dhcpv6_data += ((sizeof *in_opt) + ntohs(in_opt->len)); + in_dhcpv6_data += sizeof *in_opt + ntohs(in_opt->len); } if (!in_opt_client_id) { - static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); VLOG_WARN_RL(&rl, "DHCPv6 option - Client id not present in the " " DHCPv6 packet"); goto exit; } if (!iaid) { - static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); VLOG_WARN_RL(&rl, "DHCPv6 option - IA NA not present in the " " DHCPv6 packet"); goto exit; @@ -585,13 +582,13 @@ pinctrl_handle_put_dhcpv6_opts( OFPBUF_STUB_INITIALIZER(out_ofpacts_dhcpv6_opts_stub); if (!compose_out_dhcpv6_opts(userdata, &out_dhcpv6_opts, iaid)) { - static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5); VLOG_WARN_RL(&rl, "Invalid userdata"); goto exit; } - uint16_t new_l4_size = UDP_HEADER_LEN + 4 + sizeof(*in_opt_client_id) + \ - ntohs(in_opt_client_id->len) + out_dhcpv6_opts.size; + uint16_t new_l4_size + = (UDP_HEADER_LEN + 4 + sizeof *in_opt_client_id + + ntohs(in_opt_client_id->len) + out_dhcpv6_opts.size); size_t new_packet_size = pkt_in->l4_ofs + new_l4_size; struct dp_packet pkt_out; @@ -600,29 +597,29 @@ pinctrl_handle_put_dhcpv6_opts( 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); + /* Copy L2 and L3 headers from pkt_in. */ + 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; - /* Pull the dhcpv6 message type and transaction id from the pkt_in. - * Need to preserve the transaction id in the DHCPv6 reply packet*/ + /* Pull the DHCPv6 message type and transaction id from the pkt_in. + * Need to preserve the transaction id in the DHCPv6 reply packet. */ struct udp_header *out_udp = dp_packet_put( &pkt_out, dp_packet_pull(pkt_in, UDP_HEADER_LEN), UDP_HEADER_LEN); uint8_t *out_dhcpv6 = dp_packet_put(&pkt_out, dp_packet_pull(pkt_in, 4), 4); - /* Set the proper dhcpv6 message type */ + /* Set the proper DHCPv6 message type. */ *out_dhcpv6 = out_dhcpv6_msg_type; - /* Copy the Client Identifier */ + /* Copy the Client Identifier. */ dp_packet_put(&pkt_out, in_opt_client_id, - sizeof(*in_opt_client_id) + ntohs(in_opt_client_id->len)); + sizeof *in_opt_client_id + ntohs(in_opt_client_id->len)); - /* Copy the DHCPv6 Options */ + /* Copy the DHCPv6 Options. */ dp_packet_put(&pkt_out, out_dhcpv6_opts.data, out_dhcpv6_opts.size); out_udp->udp_len = htons(new_l4_size); out_udp->udp_csum = 0; @@ -651,9 +648,7 @@ exit: mf_write_subfield(&dst, &sv, &pin->flow_metadata); } queue_msg(ofputil_encode_resume(pin, continuation, proto)); - if (pkt_out_ptr) { - dp_packet_uninit(pkt_out_ptr); - } + dp_packet_uninit(pkt_out_ptr); } static void diff --git a/ovn/ovn-sb.xml b/ovn/ovn-sb.xml index 3f27e5e..1314e9e 100644 --- a/ovn/ovn-sb.xml +++ b/ovn/ovn-sb.xml @@ -1328,7 +1328,7 @@ <b>Example:</b> <code> reg0[3] = put_dhcpv6_opts(ia_addr = aef0::4, server_id = 00:00:00:00:10:02, - dns_server={ae70::1,ae70::2}....); + dns_server={ae70::1,ae70::2}); </code> </p> </dd> @@ -2122,10 +2122,10 @@ tcp.flags = RST; <p> Each row in this table stores the DHCPv6 Options supported by native OVN DHCPv6. <code>ovn-northd</code> populates this table with the supported - DHCPv6 options. <code>ovn-controller</code> looks up this table to get the - DHCPv6 codes of the DHCPv6 options defined in the "put_dhcpv6_opts" - action. Please refer to the RFC 3315 and RFC 3646 for the possible list - of DHCPv6 options that can be defined here. + DHCPv6 options. <code>ovn-controller</code> looks up this table to get + the DHCPv6 codes of the DHCPv6 options defined in the + <code>put_dhcpv6_opts</code> action. Please refer to RFC 3315 and RFC + 3646 for the list of DHCPv6 options that can be defined here. </p> <column name="name"> _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev