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

Reply via email to