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 <[email protected]>
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
[email protected]
http://openvswitch.org/mailman/listinfo/dev