[ovs-dev] [PATCH v5 4/6] ovn-controller: add 'nd_ra' action
nusiddiq at redhat.com
nusiddiq at redhat.com
Thu May 4 15:13:42 UTC 2017
From: Zong Kai LI <zealokii at gmail.com>
This patchs add a new action 'nd_ra' against current 'nd_na' action, to work as
a Router Solicitation packet responder. The inner actions to set fields, flags,
options in RA packet will be introduced in the following patch.
Signed-off-by: Zongkai LI <zealokii at gmail.com>
Signed-off-by: Numan Siddique <nusiddiq at redhat.com>
---
include/ovn/actions.h | 7 +++++
ovn/controller/pinctrl.c | 65 ++++++++++++++++++++++++++++++++---------------
ovn/lib/actions.c | 23 +++++++++++++++++
ovn/ovn-sb.xml | 41 ++++++++++++++++++++++++++++++
ovn/utilities/ovn-trace.c | 14 ++++++----
tests/ovn.at | 6 +++++
6 files changed, 131 insertions(+), 25 deletions(-)
diff --git a/include/ovn/actions.h b/include/ovn/actions.h
index 9e4a5c5..c1bfda5 100644
--- a/include/ovn/actions.h
+++ b/include/ovn/actions.h
@@ -64,6 +64,7 @@ struct simap;
OVNACT(CLONE, ovnact_nest) \
OVNACT(ARP, ovnact_nest) \
OVNACT(ND_NA, ovnact_nest) \
+ OVNACT(ND_RA, ovnact_nest) \
OVNACT(GET_ARP, ovnact_get_mac_bind) \
OVNACT(PUT_ARP, ovnact_put_mac_bind) \
OVNACT(GET_ND, ovnact_get_mac_bind) \
@@ -400,6 +401,12 @@ enum action_opcode {
*
*/
ACTION_OPCODE_DNS_LOOKUP,
+
+ /* "nd_ra { ...actions... }".
+ *
+ * The actions, in OpenFlow 1.3 format, follow the action_header.
+ */
+ ACTION_OPCODE_ND_RA,
};
/* Header. */
diff --git a/ovn/controller/pinctrl.c b/ovn/controller/pinctrl.c
index 4b44359..9656675 100644
--- a/ovn/controller/pinctrl.c
+++ b/ovn/controller/pinctrl.c
@@ -73,9 +73,9 @@ static void send_garp_run(const struct ovsrec_bridge *,
const struct sbrec_chassis *,
const struct lport_index *lports,
struct hmap *local_datapaths);
-static void pinctrl_handle_nd_na(const struct flow *ip_flow,
- const struct match *md,
- struct ofpbuf *userdata);
+static void pinctrl_handle_nd(const struct flow *ip_flow,
+ const struct match *md,
+ struct ofpbuf *userdata);
static void reload_metadata(struct ofpbuf *ofpacts,
const struct match *md);
@@ -952,7 +952,8 @@ process_packet_in(const struct ofp_header *msg, struct controller_ctx *ctx)
break;
case ACTION_OPCODE_ND_NA:
- pinctrl_handle_nd_na(&headers, &pin.flow_metadata, &userdata);
+ case ACTION_OPCODE_ND_RA:
+ pinctrl_handle_nd(&headers, &pin.flow_metadata, &userdata);
break;
case ACTION_OPCODE_PUT_ND:
@@ -1736,31 +1737,55 @@ reload_metadata(struct ofpbuf *ofpacts, const struct match *md)
}
static void
-pinctrl_handle_nd_na(const struct flow *ip_flow, const struct match *md,
- struct ofpbuf *userdata)
+pinctrl_handle_nd(const struct flow *ip_flow, const struct match *md,
+ struct ofpbuf *userdata)
{
- /* This action only works for IPv6 ND packets, and the switch should only
- * send us ND packets this way, but check here just to be sure. */
- if (!is_nd(ip_flow, NULL)) {
- static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
- VLOG_WARN_RL(&rl, "NA action on non-ND packet");
+ static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
+ /* This action only works for IPv6 ND packets, and only Neighbor
+ * Solicitation and Router Solicitation packets are supported.
+ * The switch should only send us ND packets this way, but check
+ * here just to be sure. */
+ if (!is_icmpv6(ip_flow, NULL)
+ || ip_flow->tp_dst != htons(0)
+ || (ip_flow->tp_src != htons(ND_NEIGHBOR_SOLICIT)
+ && ip_flow->tp_src != htons(ND_ROUTER_SOLICIT))) {
+ VLOG_WARN_RL(&rl, "ND action on invalid or unsupported packet");
return;
}
enum ofp_version version = rconn_get_version(swconn);
enum ofputil_protocol proto = ofputil_protocol_from_ofp_version(version);
- uint64_t packet_stub[128 / 8];
+ bool as_nd_na = ip_flow->tp_src == htons(ND_NEIGHBOR_SOLICIT);
+ int packet_stub_size = as_nd_na ? 128 : 256;
+ uint64_t packet_stub[packet_stub_size / 8];
struct dp_packet packet;
dp_packet_use_stub(&packet, packet_stub, sizeof packet_stub);
- /* xxx These flags are not exactly correct. Look at section 7.2.4
- * xxx of RFC 4861. For example, we need to set ND_RSO_ROUTER for
- * xxx router's interfaces and ND_RSO_SOLICITED only if it was
- * xxx requested. */
- compose_nd_na(&packet, ip_flow->dl_dst, ip_flow->dl_src,
- &ip_flow->nd_target, &ip_flow->ipv6_src,
- htonl(ND_RSO_SOLICITED | ND_RSO_OVERRIDE));
+ if (as_nd_na) {
+ /* xxx These flags are not exactly correct. Look at section 7.2.4
+ * xxx of RFC 4861. For example, we need to set ND_RSO_ROUTER for
+ * xxx router's interfaces and ND_RSO_SOLICITED only if it was
+ * xxx requested. */
+ compose_nd_na(&packet, ip_flow->dl_dst, ip_flow->dl_src,
+ &ip_flow->nd_target, &ip_flow->ipv6_src,
+ htonl(ND_RSO_SOLICITED | ND_RSO_OVERRIDE));
+ } else {
+ /* xxx Using hardcode data to compose RA packet.
+ * xxx The following patch should fix this. */
+ uint8_t cur_hop_limit = 64;
+ uint8_t mo_flags = 0;
+ ovs_be16 router_lifetime = 0xffff;
+ ovs_be32 reachable_time = 0;
+ ovs_be32 retrans_timer = 0;
+ ovs_be32 mtu = 0;
+
+ compose_nd_ra_with_sll_mtu_opts(
+ &packet, ip_flow->dl_dst, ip_flow->dl_src,
+ &ip_flow->ipv6_dst, &ip_flow->ipv6_src,
+ cur_hop_limit, mo_flags, router_lifetime, reachable_time,
+ retrans_timer, mtu);
+ }
/* Reload previous packet metadata. */
uint64_t ofpacts_stub[4096 / 8];
@@ -1772,7 +1797,7 @@ pinctrl_handle_nd_na(const struct flow *ip_flow, const struct match *md,
&ofpacts);
if (error) {
static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
- VLOG_WARN_RL(&rl, "failed to parse actions for 'na' (%s)",
+ VLOG_WARN_RL(&rl, "failed to parse actions for 'nd' (%s)",
ofperr_to_string(error));
goto exit;
}
diff --git a/ovn/lib/actions.c b/ovn/lib/actions.c
index 71f49c1..d361c0e 100644
--- a/ovn/lib/actions.c
+++ b/ovn/lib/actions.c
@@ -1137,6 +1137,12 @@ parse_CLONE(struct action_context *ctx)
}
static void
+parse_ND_RA(struct action_context *ctx)
+{
+ parse_nested_action(ctx, OVNACT_ND_RA, "nd_rs");
+}
+
+static void
format_nested_action(const struct ovnact_nest *on, const char *name,
struct ds *s)
{
@@ -1164,6 +1170,12 @@ format_CLONE(const struct ovnact_nest *nest, struct ds *s)
}
static void
+format_ND_RA(const struct ovnact_nest *nest, struct ds *s)
+{
+ format_nested_action(nest, "nd_ra", s);
+}
+
+static void
encode_nested_neighbor_actions(const struct ovnact_nest *on,
const struct ovnact_encode_params *ep,
enum action_opcode opcode,
@@ -1218,11 +1230,20 @@ encode_CLONE(const struct ovnact_nest *on,
}
static void
+encode_ND_RA(const struct ovnact_nest *on,
+ const struct ovnact_encode_params *ep,
+ struct ofpbuf *ofpacts)
+{
+ encode_nested_neighbor_actions(on, ep, ACTION_OPCODE_ND_RA, ofpacts);
+}
+
+static void
ovnact_nest_free(struct ovnact_nest *on)
{
ovnacts_free(on->nested, on->nested_len);
free(on->nested);
}
+
static void
parse_get_mac_bind(struct action_context *ctx, int width,
@@ -1827,6 +1848,8 @@ parse_action(struct action_context *ctx)
parse_ARP(ctx);
} else if (lexer_match_id(ctx->lexer, "nd_na")) {
parse_ND_NA(ctx);
+ } else if (lexer_match_id(ctx->lexer, "nd_ra")) {
+ parse_ND_RA(ctx);
} else if (lexer_match_id(ctx->lexer, "get_arp")) {
parse_get_mac_bind(ctx, 32, ovnact_put_GET_ARP(ctx->ovnacts));
} else if (lexer_match_id(ctx->lexer, "put_arp")) {
diff --git a/ovn/ovn-sb.xml b/ovn/ovn-sb.xml
index 87b3e99..8b2e9a8 100644
--- a/ovn/ovn-sb.xml
+++ b/ovn/ovn-sb.xml
@@ -1292,6 +1292,47 @@
</p>
</dd>
+ <dt>
+ <code>nd_ra { <var>action</var>; </code>...<code> };</code>
+ </dt>
+
+ <dd>
+ <p>
+ Temporarily replaces the IPv6 router solicitation (RS) packet
+ being processed by an IPv6 router advertisement (RA)
+ packet and executes each nested <var>action</var> on the RA
+ packet. Actions following the <code>nd_ra</code> action,
+ if any, apply to the original, unmodified packet.
+ </p>
+
+ <p>
+ The RA packet that this action operates on is initialized based on
+ the IPv6 packet being processed, as follows. These are default
+ values that the nested actions will probably want to change:
+ </p>
+
+ <ul>
+ <li><code>eth.dst</code> copied from <code>eth.src</code></li>
+ <li><code>eth.src</code> replaced by new value</li>
+ <li><code>eth.type = 0x86dd</code></li>
+ <li><code>ip6.dst</code> copied from <code>ip6.src</code></li>
+ <li><code>ip6.src</code> replaced by new value</li>
+ <li><code>icmp6.type = 134</code> (Router Advertisement)</li>
+ <li><code>nd.target</code> unchanged</li>
+ <li><code>nd.tll = 00:00:00:00:00:00</code></li>
+ <li><code>nd.sll</code> replaced by new value</li>
+ </ul>
+
+ <p>
+ The ND packet has the same VLAN header, if any, as the IPv6 packet
+ it replaces.
+ </p>
+
+ <p>
+ <b>Prerequisite:</b> <code>nd_rs</code>
+ </p>
+ </dd>
+
<dt><code>get_nd(<var>P</var>, <var>A</var>);</code></dt>
<dd>
diff --git a/ovn/utilities/ovn-trace.c b/ovn/utilities/ovn-trace.c
index 5bb29e6..dd0eaea 100644
--- a/ovn/utilities/ovn-trace.c
+++ b/ovn/utilities/ovn-trace.c
@@ -1364,21 +1364,24 @@ execute_arp(const struct ovnact_nest *on, const struct ovntrace_datapath *dp,
static void
execute_nd_na(const struct ovnact_nest *on, const struct ovntrace_datapath *dp,
const struct flow *uflow, uint8_t table_id,
- enum ovnact_pipeline pipeline, struct ovs_list *super)
+ enum ovnact_pipeline pipeline, struct ovs_list *super,
+ bool is_neighbor_adv)
+
{
struct flow na_flow = *uflow;
- /* Update fields for NA. */
+ /* Update fields for ND Router/Neighbor Advertisement. */
na_flow.dl_src = uflow->dl_dst;
na_flow.dl_dst = uflow->dl_src;
na_flow.ipv6_dst = uflow->ipv6_src;
na_flow.ipv6_src = uflow->nd_target;
- na_flow.tp_src = htons(136);
+ na_flow.tp_src = is_neighbor_adv ? htons(136) : htons(134);
na_flow.arp_sha = eth_addr_zero;
na_flow.arp_tha = uflow->dl_dst;
struct ovntrace_node *node = ovntrace_node_append(
- super, OVNTRACE_NODE_TRANSFORMATION, "nd_na");
+ super, OVNTRACE_NODE_TRANSFORMATION,
+ (is_neighbor_adv ? "nd_na" : "nd_ra"));
trace_actions(on->nested, on->nested_len, dp, &na_flow,
table_id, pipeline, &node->subs);
@@ -1611,8 +1614,9 @@ trace_actions(const struct ovnact *ovnacts, size_t ovnacts_len,
break;
case OVNACT_ND_NA:
+ case OVNACT_ND_RA:
execute_nd_na(ovnact_get_ND_NA(a), dp, uflow, table_id, pipeline,
- super);
+ super, (a->type == OVNACT_ND_NA));
break;
case OVNACT_GET_ARP:
diff --git a/tests/ovn.at b/tests/ovn.at
index 7b9243a..807161a 100644
--- a/tests/ovn.at
+++ b/tests/ovn.at
@@ -967,6 +967,12 @@ nd_na { eth.src = 12:34:56:78:9a:bc; nd.tll = 12:34:56:78:9a:bc; outport = inpor
encodes as controller(userdata=00.00.00.03.00.00.00.00.00.19.00.10.80.00.08.06.12.34.56.78.9a.bc.00.00.00.19.00.10.80.00.42.06.12.34.56.78.9a.bc.00.00.ff.ff.00.18.00.00.23.20.00.06.00.20.00.00.00.00.00.01.1c.04.00.01.1e.04.00.19.00.10.00.01.1c.04.00.00.00.00.00.00.00.00.ff.ff.00.10.00.00.23.20.00.0e.ff.f8.40.00.00.00)
has prereqs nd_ns
+# nd_ra
+nd_ra{eth.src = 12:34:56:78:9a:bc; ip6.src = fdad:1234:5678::1; outport = inport; flags.loopback = 1; output;};
+ formats as nd_ra { eth.src = 12:34:56:78:9a:bc; ip6.src = fdad:1234:5678::1; outport = inport; flags.loopback = 1; output; };
+ encodes as controller(userdata=00.00.00.06.00.00.00.00.00.19.00.10.80.00.08.06.12.34.56.78.9a.bc.00.00.00.19.00.18.80.00.34.10.fd.ad.12.34.56.78.00.00.00.00.00.00.00.00.00.01.ff.ff.00.18.00.00.23.20.00.06.00.20.00.00.00.00.00.01.1c.04.00.01.1e.04.ff.ff.00.18.00.00.23.20.00.07.00.00.00.01.14.04.00.00.00.00.00.00.00.01.ff.ff.00.10.00.00.23.20.00.0e.ff.f8.40.00.00.00)
+ has prereqs nd_rs
+
# get_nd
get_nd(outport, ip6.dst);
encodes as push:NXM_NX_XXREG0[],push:NXM_NX_IPV6_DST[],pop:NXM_NX_XXREG0[],set_field:00:00:00:00:00:00->eth_dst,resubmit(,65),pop:NXM_NX_XXREG0[]
--
2.9.3
More information about the dev
mailing list