&& (!export_mask || (data->tp_src == htons(0xff)
&& data->tp_dst == htons(0xff)))) {
struct ovs_key_nd *nd_key;
- struct ovs_key_nd_extensions *nd_ext_key;
nd_key = nl_msg_put_unspec_uninit(buf, OVS_KEY_ATTR_ND,
sizeof *nd_key);
nd_key->nd_target = data->nd_target;
nd_key->nd_sll = data->arp_sha;
nd_key->nd_tll = data->arp_tha;
- /* Add ND Extensions Attr only if reserved field
+ /* Add ND Extensions Attr only if supported and reserved field
* or options type is set. */
- if (data->igmp_group_ip4 != 0 ||
- data->tcp_flags != 0) {
- nd_ext_key =
- nl_msg_put_unspec_uninit(buf,
+ if (parms->support.nd_ext) {
+ struct ovs_key_nd_extensions *nd_ext_key;
+
+ if (data->igmp_group_ip4 != 0 || data->tcp_flags != 0) {
+ nd_ext_key = nl_msg_put_unspec_uninit(buf,
OVS_KEY_ATTR_ND_EXTENSIONS,
sizeof *nd_ext_key);
- nd_ext_key->nd_reserved = data->igmp_group_ip4;
- nd_ext_key->nd_options_type = ntohs(data->tcp_flags);
+ nd_ext_key->nd_reserved = data->igmp_group_ip4;
+ nd_ext_key->nd_options_type = ntohs(data->tcp_flags);
+ }
}
}
}
\
/* Conntrack original direction tuple matching * supported. */ \
ODP_SUPPORT_FIELD(bool, ct_orig_tuple, "CT orig tuple") \
- ODP_SUPPORT_FIELD(bool, ct_orig_tuple6, "CT orig tuple for IPv6")
+ ODP_SUPPORT_FIELD(bool, ct_orig_tuple6, "CT orig tuple for IPv6") \
+ \
+ /* If true, it means that the datapath supports the IPv6 Neigh \
+ * Discovery Extension bits. */ \
+ ODP_SUPPORT_FIELD(bool, nd_ext, "IPv6 ND Extension")
/* Indicates support for various fields. This defines how flows will be
* serialised. */
return max_alg;
}
+/* Tests whether 'backer''s datapath supports IPv6 ND extensions.
+ * Only userspace datapath support OVS_KEY_ATTR_ND_EXTENSIONS in keys.
+ *
+ * Returns false if 'backer' definitely does not support matching and
+ * setting reserved and options type, true if it seems to support. */
+static bool
+check_nd_extensions(struct dpif_backer *backer)
+{
+ struct eth_header *eth;
+ struct ofpbuf actions;
+ struct dpif_execute execute;
+ struct dp_packet packet;
+ struct flow flow;
+ int error;
+ struct ovs_key_nd_extensions key, mask;
+
+ ofpbuf_init(&actions, 64);
+ memset(&key, 0x53, sizeof key);
+ memset(&mask, 0x7f, sizeof mask);
+ commit_masked_set_action(&actions, OVS_KEY_ATTR_ND_EXTENSIONS, &key, &mask,
+ sizeof key);
+
+ /* Compose a dummy ethernet packet. */
+ dp_packet_init(&packet, ETH_HEADER_LEN);
+ eth = dp_packet_put_zeros(&packet, ETH_HEADER_LEN);
+ eth->eth_type = htons(0x1234);
+
+ flow_extract(&packet, &flow);
+
+ /* Execute the actions. On datapaths without support fails with EINVAL. */
+ execute.actions = actions.data;
+ execute.actions_len = actions.size;
+ execute.packet = &packet;
+ execute.flow = &flow;
+ execute.needs_help = false;
+ execute.probe = true;
+ execute.mtu = 0;
+
+ error = dpif_execute(backer->dpif, &execute);
+
+ dp_packet_uninit(&packet);
+ ofpbuf_uninit(&actions);
+
+ VLOG_INFO("%s: Datapath %s IPv6 ND Extensions", dpif_name(backer->dpif),
+ error ? "does not support" : "supports");
+
+ return !error;
+}
+
#define CHECK_FEATURE__(NAME, SUPPORT, FIELD, VALUE, ETHTYPE) \
static bool \
check_##NAME(struct dpif_backer *backer) \
backer->rt_support.odp.ct_zone = check_ct_zone(backer);
backer->rt_support.odp.ct_mark = check_ct_mark(backer);
backer->rt_support.odp.ct_label = check_ct_label(backer);
-
backer->rt_support.odp.ct_state_nat = check_ct_state_nat(backer);
backer->rt_support.odp.ct_orig_tuple = check_ct_orig_tuple(backer);
backer->rt_support.odp.ct_orig_tuple6 = check_ct_orig_tuple6(backer);
+ backer->rt_support.odp.nd_ext = check_nd_extensions(backer);
}
static int
"ct original direction tuple");
return OFPERR_NXBAC_CT_DATAPATH_SUPPORT;
}
+ } else if (!support->nd_ext && ofpact->type == OFPACT_SET_FIELD) {
+ const struct mf_field *dst = ofpact_get_mf_dst(ofpact);
+
+ if (dst->id == MFF_ND_RESERVED || dst->id == MFF_ND_OPTIONS_TYPE) {
+ report_unsupported_act("set field",
+ "setting IPv6 ND Extensions fields");
+ return OFPERR_OFPBAC_BAD_SET_ARGUMENT;
+ }
}
}