@@ -71,7 +71,7 @@ OXM_CLASSES = {"NXM_OF_": (0, 0x0000, 'extension'),
"OXM_OF_": (0, 0x8000, 'standard'),
"OXM_OF_PKT_REG": (0, 0x8001, 'standard'),
"ONFOXM_ET_": (0x4f4e4600, 0xffff, 'standard'),
-
+ "ERICOXM_OF_": (0, 0x1000, 'extension'),
# This is the experimenter OXM class for Nicira, which is the
# one that OVS would be using instead of NXM_OF_ and NXM_NX_
# if OVS didn't have those grandfathered in. It is currently
@@ -484,9 +484,13 @@ struct ovs_key_arp {
};
struct ovs_key_nd {
- __be32 nd_target[4];
- __u8 nd_sll[ETH_ALEN];
- __u8 nd_tll[ETH_ALEN];
+ __be32 nd_reserved;
+ __be32 nd_target[4];
+ __u8 nd_options_type;
+ struct {
+ __u8 nd_sll[ETH_ALEN];
+ __u8 nd_tll[ETH_ALEN];
+ };
};
#define OVS_CT_LABELS_LEN_32 4
@@ -68,6 +68,8 @@ void match_zero_wildcarded_fields(struct match *);
void match_set_dp_hash(struct match *, uint32_t value);
void match_set_dp_hash_masked(struct match *, uint32_t value, uint32_t mask);
+void match_set_nd_reserved(struct match *, uint32_t value);
+
void match_set_recirc_id(struct match *, uint32_t value);
void match_set_conj_id(struct match *, uint32_t value);
@@ -199,6 +201,7 @@ void match_set_nw_frag(struct match *, uint8_t nw_frag);
void match_set_nw_frag_masked(struct match *, uint8_t nw_frag, uint8_t mask);
void match_set_icmp_type(struct match *, uint8_t);
void match_set_icmp_code(struct match *, uint8_t);
+void match_set_nd_options_type(struct match *, uint8_t);
void match_set_arp_sha(struct match *, const struct eth_addr);
void match_set_arp_sha_masked(struct match *,
const struct eth_addr arp_sha,
@@ -1796,6 +1796,34 @@ enum OVS_PACKED_ENUM mf_field_id {
*/
MFF_ND_TLL,
+ /* "nd_reserved".
+ *
+ * The reserved field in IPv6 Neighbor Discovery message.
+ *
+ * Type: be32.
+ * Maskable: no.
+ * Formatting: decimal.
+ * Prerequisites: ND.
+ * Access: read/write.
+ * NXM: none.
+ * OXM: ERICOXM_OF_ICMPV6_ND_RESERVED(1) since v2.11.
+ */
+ MFF_ND_RESERVED,
+
+ /* "nd_options_type".
+ *
+ * The type of the option in IPv6 Neighbor Discovery message.
+ *
+ * Type: u8.
+ * Maskable: no.
+ * Formatting: decimal.
+ * Prerequisites: ND.
+ * Access: read/write.
+ * NXM: none.
+ * OXM: ERICOXM_OF_ICMPV6_ND_OPTIONS_TYPE(2) since v2.11.
+ */
+ MFF_ND_OPTIONS_TYPE,
+
/* ## ---- ## */
/* ## NSH ## */
/* ## ---- ## */
@@ -41,6 +41,10 @@
#include "unaligned.h"
#include "util.h"
#include "openvswitch/nsh.h"
+#include "openvswitch/vlog.h"
+
+VLOG_DEFINE_THIS_MODULE(flow);
+static struct vlog_rate_limit minirl = VLOG_RATE_LIMIT_INIT(1, 5);
COVERAGE_DEFINE(flow_extract);
COVERAGE_DEFINE(miniflow_malloc);
@@ -398,7 +402,7 @@ parse_ethertype(const void **datap, size_t *sizep)
static inline bool
parse_icmpv6(const void **datap, size_t *sizep, const struct icmp6_hdr *icmp,
const struct in6_addr **nd_target,
- struct eth_addr arp_buf[2])
+ struct eth_addr arp_buf[2], uint8_t *opt_type)
{
if (icmp->icmp6_code != 0 ||
(icmp->icmp6_type != ND_NEIGHBOR_SOLICIT &&
@@ -408,6 +412,9 @@ parse_icmpv6(const void **datap, size_t *sizep, const struct icmp6_hdr *icmp,
arp_buf[0] = eth_addr_zero;
arp_buf[1] = eth_addr_zero;
+ opt_type[0] = 0;
+ opt_type[1] = 0;
+
*nd_target = data_try_pull(datap, sizep, sizeof **nd_target);
if (OVS_UNLIKELY(!*nd_target)) {
return true;
@@ -429,12 +436,14 @@ parse_icmpv6(const void **datap, size_t *sizep, const struct icmp6_hdr *icmp,
if (lla_opt->type == ND_OPT_SOURCE_LINKADDR && opt_len == 8) {
if (OVS_LIKELY(eth_addr_is_zero(arp_buf[0]))) {
arp_buf[0] = lla_opt->mac;
+ opt_type[0] = lla_opt->type;
} else {
goto invalid;
}
} else if (lla_opt->type == ND_OPT_TARGET_LINKADDR && opt_len == 8) {
if (OVS_LIKELY(eth_addr_is_zero(arp_buf[1]))) {
arp_buf[1] = lla_opt->mac;
+ opt_type[1] = lla_opt->type;
} else {
goto invalid;
}
@@ -982,18 +991,46 @@ miniflow_extract(struct dp_packet *packet, struct miniflow *dst)
if (OVS_LIKELY(size >= sizeof(struct icmp6_hdr))) {
const struct in6_addr *nd_target;
struct eth_addr arp_buf[2];
- const struct icmp6_hdr *icmp = data_pull(&data, &size,
- sizeof *icmp);
- if (parse_icmpv6(&data, &size, icmp, &nd_target, arp_buf)) {
+ /* This will populate whether we received Option 1
+ * or Option 2. */
+ uint8_t opt_type[2];
+ /* This holds the ND Reserved field. */
+ uint32_t *rso_flags;
+ const struct icmp6_hdr *icmp = data_pull(&data,
+ &size,ICMP6_HEADER_LEN);
+ rso_flags = (uint32_t *) data_pull(&data,
+ &size, sizeof(uint32_t));
+ if (parse_icmpv6(&data, &size, icmp,
+ &nd_target, arp_buf, opt_type)) {
if (nd_target) {
miniflow_push_words(mf, nd_target, nd_target,
sizeof *nd_target / sizeof(uint64_t));
}
miniflow_push_macs(mf, arp_sha, arp_buf);
- miniflow_pad_to_64(mf, arp_tha);
+ /* Populate options field and set the padding
+ * accordingly. */
+ if (opt_type[0] != 0) {
+ miniflow_push_be16(mf, tcp_flags, htons(opt_type[0]));
+ /* Pad to align with 64 bits.
+ * This will zero out the pad3 field. */
+ miniflow_pad_to_64(mf, tcp_flags);
+ } else if (opt_type[1] != 0) {
+ miniflow_push_be16(mf, tcp_flags, htons(opt_type[1]));
+ /* Pad to align with 64 bits.
+ * This will zero out the pad3 field. */
+ miniflow_pad_to_64(mf, tcp_flags);
+ } else {
+ /* Pad to align with 64 bits.
+ * This will zero out the tcp_flags & pad3 field. */
+ miniflow_pad_to_64(mf, arp_tha);
+ }
+
miniflow_push_be16(mf, tp_src, htons(icmp->icmp6_type));
miniflow_push_be16(mf, tp_dst, htons(icmp->icmp6_code));
miniflow_pad_to_64(mf, tp_dst);
+ /* Fill ND reserved field. */
+ miniflow_push_be32(mf, igmp_group_ip4, htonl(*rso_flags));
+ miniflow_pad_to_64(mf, igmp_group_ip4);
} else {
/* ICMPv6 but not ND. */
miniflow_push_be16(mf, tp_src, htons(icmp->icmp6_type));
@@ -1840,6 +1877,9 @@ flow_wildcards_init_for_packet(struct flow_wildcards *wc,
WC_MASK_FIELD(wc, tcp_flags);
} else if (flow->nw_proto == IPPROTO_IGMP) {
WC_MASK_FIELD(wc, igmp_group_ip4);
+ } else if (flow->nw_proto == IPPROTO_ICMPV6) {
+ WC_MASK_FIELD(wc, tcp_flags);
+ WC_MASK_FIELD(wc, igmp_group_ip4);
}
}
}
@@ -1922,6 +1962,8 @@ flow_wc_map(const struct flow *flow, struct flowmap *map)
FLOWMAP_SET(map, nd_target);
FLOWMAP_SET(map, arp_sha);
FLOWMAP_SET(map, arp_tha);
+ FLOWMAP_SET(map, tcp_flags);
+ FLOWMAP_SET(map, igmp_group_ip4);
} else {
FLOWMAP_SET(map, ct_nw_proto);
FLOWMAP_SET(map, ct_ipv6_src);
@@ -2918,6 +2960,8 @@ flow_compose_l4(struct dp_packet *p, const struct flow *flow,
struct icmp6_hdr *icmp = dp_packet_put_zeros(p, sizeof *icmp);
icmp->icmp6_type = ntohs(flow->tp_src);
icmp->icmp6_code = ntohs(flow->tp_dst);
+ uint32_t *reserved = &icmp->icmp6_dataun.icmp6_un_data32[0];
+ *reserved = ntohl(flow->igmp_group_ip4);
if (icmp->icmp6_code == 0 &&
(icmp->icmp6_type == ND_NEIGHBOR_SOLICIT ||
@@ -517,6 +517,18 @@ match_set_ct_tp_dst_masked(struct match *match, ovs_be16 port, ovs_be16 mask)
}
void
+match_set_nd_reserved (struct match *match, ovs_be32 value) {
+ match->flow.igmp_group_ip4 = value;
+ match->wc.masks.igmp_group_ip4 = OVS_BE32_MAX;
+}
+
+void
+match_set_nd_options_type(struct match *match, uint8_t option)
+{
+ match_set_tcp_flags(match, htons(option));
+}
+
+void
match_set_ct_ipv6_src(struct match *match, const struct in6_addr *src)
{
match->flow.ct_ipv6_src = *src;
@@ -1688,6 +1700,10 @@ match_format(const struct match *match,
&wc->masks.nd_target);
format_eth_masked(s, "nd_sll", f->arp_sha, wc->masks.arp_sha);
format_eth_masked(s, "nd_tll", f->arp_tha, wc->masks.arp_tha);
+ format_be32_masked(s,"nd_reserved", f->igmp_group_ip4,
+ wc->masks.igmp_group_ip4);
+ format_be16_masked(s,"nd_options_type", f->tcp_flags,
+ wc->masks.tcp_flags);
} else {
format_be16_masked(s, "tp_src", f->tp_src, wc->masks.tp_src);
format_be16_masked(s, "tp_dst", f->tp_dst, wc->masks.tp_dst);
@@ -366,6 +366,11 @@ mf_is_all_wild(const struct mf_field *mf, const struct flow_wildcards *wc)
case MFF_ICMPV4_CODE:
case MFF_ICMPV6_CODE:
return !wc->masks.tp_dst;
+ case MFF_ND_RESERVED:
+ return !wc->masks.igmp_group_ip4;
+ case MFF_ND_OPTIONS_TYPE:
+ return !wc->masks.tcp_flags;
+
case MFF_TCP_FLAGS:
return !wc->masks.tcp_flags;
@@ -571,6 +576,8 @@ mf_is_value_valid(const struct mf_field *mf, const union mf_value *value)
case MFF_ND_TARGET:
case MFF_ND_SLL:
case MFF_ND_TLL:
+ case MFF_ND_RESERVED:
+ case MFF_ND_OPTIONS_TYPE:
return true;
case MFF_IN_PORT_OXM:
@@ -922,6 +929,12 @@ mf_get_value(const struct mf_field *mf, const struct flow *flow,
value->u8 = ntohs(flow->tp_dst);
break;
+ case MFF_ND_RESERVED:
+ value->be32 = ntohl(flow->igmp_group_ip4);
+ break;
+ case MFF_ND_OPTIONS_TYPE:
+ value->u8 = ntohs(flow->tcp_flags);
+ break;
case MFF_ND_TARGET:
value->ipv6 = flow->nd_target;
break;
@@ -1255,6 +1268,12 @@ mf_set_value(const struct mf_field *mf,
match_set_icmp_code(match, value->u8);
break;
+ case MFF_ND_RESERVED:
+ match_set_nd_reserved(match, value->be32);
+ break;
+ case MFF_ND_OPTIONS_TYPE:
+ match_set_nd_options_type(match, value->u8);
+ break;
case MFF_ND_TARGET:
match_set_nd_target(match, &value->ipv6);
break;
@@ -1664,6 +1683,12 @@ mf_set_flow_value(const struct mf_field *mf,
flow->tp_dst = htons(value->u8);
break;
+ case MFF_ND_RESERVED:
+ flow->igmp_group_ip4 = htonl(value->be32);
+ break;
+ case MFF_ND_OPTIONS_TYPE:
+ flow->tcp_flags = htons(value->u8);
+ break;
case MFF_ND_TARGET:
flow->nd_target = value->ipv6;
break;
@@ -1823,6 +1848,8 @@ mf_is_pipeline_field(const struct mf_field *mf)
case MFF_ND_TARGET:
case MFF_ND_SLL:
case MFF_ND_TLL:
+ case MFF_ND_RESERVED:
+ case MFF_ND_OPTIONS_TYPE:
case MFF_NSH_FLAGS:
case MFF_NSH_TTL:
case MFF_NSH_MDTYPE:
@@ -2167,6 +2194,14 @@ mf_set_wild(const struct mf_field *mf, struct match *match, char **err_str)
match->wc.masks.tp_dst = htons(0);
match->flow.tp_dst = htons(0);
break;
+ case MFF_ND_RESERVED:
+ match->wc.masks.igmp_group_ip4 = htonl(0);
+ match->flow.igmp_group_ip4 = htonl(0);
+ break;
+ case MFF_ND_OPTIONS_TYPE:
+ match->wc.masks.tcp_flags = htons(0);
+ match->flow.tcp_flags = htons(0);
+ break;
case MFF_TCP_FLAGS:
match->wc.masks.tcp_flags = htons(0);
@@ -2285,6 +2320,8 @@ mf_set(const struct mf_field *mf,
case MFF_ICMPV4_CODE:
case MFF_ICMPV6_TYPE:
case MFF_ICMPV6_CODE:
+ case MFF_ND_RESERVED:
+ case MFF_ND_OPTIONS_TYPE:
return OFPUTIL_P_NONE;
case MFF_DP_HASH:
@@ -4586,6 +4586,19 @@ r r c c c.
title="ICMPv6 Neighbor Discovery Source Ethernet Address"/>
<field id="MFF_ND_TLL"
title="ICMPv6 Neighbor Discovery Target Ethernet Address"/>
+ <field id="MFF_ND_RESERVED"
+ title="ICMPv6 Neighbor Discovery Reserved Field"/>
+ <p>
+ This is used to set the R,S,O bits in Neighbor Advertisement Messages
+ </p>
+ <field id="MFF_ND_OPTIONS_TYPE"
+ title="ICMPv6 Neighbor Discovery Options Type Field"/>
+ <p>
+ A value of 1 indicates that the option is Source Link Layer.
+ A value of 2 indicates that the options is Target Link Layer.
+ See RFC 4861 for further details.
+ </p>
+
</group>
<h1>References</h1>
@@ -990,8 +990,16 @@ nxm_put_ip(struct nxm_put_ctx *ctx,
ntohs(flow->tp_dst));
}
if (is_nd(flow, NULL)) {
+ if (match->wc.masks.igmp_group_ip4) {
+ nxm_put_32(ctx, MFF_ND_RESERVED, oxm,
+ ntohl(flow->igmp_group_ip4));
+ }
nxm_put_ipv6(ctx, MFF_ND_TARGET, oxm,
&flow->nd_target, &match->wc.masks.nd_target);
+ if (match->wc.masks.tcp_flags) {
+ nxm_put_8(ctx, MFF_ND_OPTIONS_TYPE, oxm,
+ ntohs(flow->tcp_flags));
+ }
if (flow->tp_src == htons(ND_NEIGHBOR_SOLICIT)) {
nxm_put_eth_masked(ctx, MFF_ND_SLL, oxm,
flow->arp_sha, match->wc.masks.arp_sha);
@@ -239,16 +239,25 @@ odp_set_nd(struct dp_packet *packet, const struct ovs_key_nd *key,
struct in6_addr tgt_buf;
struct eth_addr sll_buf = eth_addr_zero;
struct eth_addr tll_buf = eth_addr_zero;
+ uint32_t reserved = get_16aligned_be32(&ns->rso_flags);
+ uint8_t nd_options_type = lla_opt->type;
+
+ if (mask->nd_reserved) {
+ reserved = key->nd_reserved;
+ }
+ if (mask->nd_options_type) {
+ nd_options_type = key->nd_options_type;
+ }
while (bytes_remain >= ND_LLA_OPT_LEN && lla_opt->len != 0) {
- if (lla_opt->type == ND_OPT_SOURCE_LINKADDR
+ if (nd_options_type == ND_OPT_SOURCE_LINKADDR
&& lla_opt->len == 1) {
sll_buf = lla_opt->mac;
ether_addr_copy_masked(&sll_buf, key->nd_sll, mask->nd_sll);
/* A packet can only contain one SLL or TLL option */
break;
- } else if (lla_opt->type == ND_OPT_TARGET_LINKADDR
+ } else if (nd_options_type == ND_OPT_TARGET_LINKADDR
&& lla_opt->len == 1) {
tll_buf = lla_opt->mac;
ether_addr_copy_masked(&tll_buf, key->nd_tll, mask->nd_tll);
@@ -265,7 +274,9 @@ odp_set_nd(struct dp_packet *packet, const struct ovs_key_nd *key,
mask_ipv6_addr(ns->target.be32, &key->nd_target,
&mask->nd_target, &tgt_buf),
sll_buf,
- tll_buf);
+ tll_buf,
+ reserved,
+ nd_options_type);
}
}
@@ -434,7 +445,9 @@ odp_execute_set_action(struct dp_packet *packet, const struct nlattr *a)
const struct ovs_key_nd *nd_key
= nl_attr_get_unspec(a, sizeof(struct ovs_key_nd));
packet_set_nd(packet, &nd_key->nd_target, nd_key->nd_sll,
- nd_key->nd_tll);
+ nd_key->nd_tll, nd_key->nd_reserved,
+ nd_key->nd_options_type);
+
}
break;
@@ -2484,7 +2484,7 @@ const struct attr_len_tbl ovs_flow_key_attr_lens[OVS_KEY_ATTR_MAX + 1] = {
[OVS_KEY_ATTR_ICMP] = { .len = sizeof(struct ovs_key_icmp) },
[OVS_KEY_ATTR_ICMPV6] = { .len = sizeof(struct ovs_key_icmpv6) },
[OVS_KEY_ATTR_ARP] = { .len = sizeof(struct ovs_key_arp) },
- [OVS_KEY_ATTR_ND] = { .len = sizeof(struct ovs_key_nd) },
+ [OVS_KEY_ATTR_ND] = { .len = ATTR_LEN_VARIABLE },
[OVS_KEY_ATTR_CT_STATE] = { .len = 4 },
[OVS_KEY_ATTR_CT_ZONE] = { .len = 2 },
[OVS_KEY_ATTR_CT_MARK] = { .len = 4 },
@@ -4018,9 +4018,14 @@ format_odp_key_attr__(const struct nlattr *a, const struct nlattr *ma,
case OVS_KEY_ATTR_ND: {
const struct ovs_key_nd *mask = ma ? nl_attr_get(ma) : NULL;
const struct ovs_key_nd *key = nl_attr_get(a);
-
+ bool first = true;
+ format_be32_masked(ds, &first, "nd_reserved", htonl(key->nd_reserved),
+ htonl(OVS_BE32_MAX));
+ ds_put_char(ds, ',');
format_in6_addr(ds, "target", &key->nd_target, MASK(mask, nd_target),
verbose);
+ format_u8u(ds,"nd_options_type", key->nd_options_type,
+ MASK(mask,nd_options_type), verbose);
format_eth(ds, "sll", key->nd_sll, MASK(mask, nd_sll), verbose);
format_eth(ds, "tll", key->nd_tll, MASK(mask, nd_tll), verbose);
@@ -5493,7 +5498,9 @@ parse_odp_key_mask_attr(const char *s, const struct simap *port_names,
} SCAN_END(OVS_KEY_ATTR_ARP);
SCAN_BEGIN("nd(", struct ovs_key_nd) {
+ SCAN_FIELD("nd_reserved=",be32,nd_reserved);
SCAN_FIELD("target=", in6_addr, nd_target);
+ SCAN_FIELD("nd_options_type=",u8,nd_options_type);
SCAN_FIELD("sll=", eth, nd_sll);
SCAN_FIELD("tll=", eth, nd_tll);
} SCAN_END(OVS_KEY_ATTR_ND);
@@ -5858,7 +5865,9 @@ odp_flow_key_from_flow__(const struct odp_flow_key_parms *parms,
nd_key = nl_msg_put_unspec_uninit(buf, OVS_KEY_ATTR_ND,
sizeof *nd_key);
+ nd_key->nd_reserved = ntohl(data->igmp_group_ip4);
nd_key->nd_target = data->nd_target;
+ nd_key->nd_options_type = ntohs(data->tcp_flags);
nd_key->nd_sll = data->arp_sha;
nd_key->nd_tll = data->arp_tha;
}
@@ -6465,7 +6474,9 @@ parse_l2_5_onward(const struct nlattr *attrs[OVS_KEY_ATTR_MAX + 1],
const struct ovs_key_nd *nd_key;
nd_key = nl_attr_get(attrs[OVS_KEY_ATTR_ND]);
+ flow->igmp_group_ip4 = htonl(nd_key->nd_reserved);
flow->nd_target = nd_key->nd_target;
+ flow->tcp_flags = htons(nd_key->nd_options_type);
flow->arp_sha = nd_key->nd_sll;
flow->arp_tha = nd_key->nd_tll;
if (is_mask) {
@@ -7364,7 +7375,9 @@ commit_set_icmp_action(const struct flow *flow, struct flow *base_flow,
static void
get_nd_key(const struct flow *flow, struct ovs_key_nd *nd)
{
+ nd->nd_reserved = ntohl(flow->igmp_group_ip4);
nd->nd_target = flow->nd_target;
+ nd->nd_options_type = ntohs(flow->tcp_flags);
/* nd_sll and nd_tll are stored in arp_sha and arp_tha, respectively */
nd->nd_sll = flow->arp_sha;
nd->nd_tll = flow->arp_tha;
@@ -7373,8 +7386,10 @@ get_nd_key(const struct flow *flow, struct ovs_key_nd *nd)
static void
put_nd_key(const struct ovs_key_nd *nd, struct flow *flow)
{
+ flow->igmp_group_ip4 =htonl(nd->nd_reserved);
flow->nd_target = nd->nd_target;
/* nd_sll and nd_tll are stored in arp_sha and arp_tha, respectively */
+ flow->tcp_flags = htons(nd->nd_options_type);
flow->arp_sha = nd->nd_sll;
flow->arp_tha = nd->nd_tll;
}
@@ -1283,11 +1283,19 @@ packet_set_icmp(struct dp_packet *packet, uint8_t type, uint8_t code)
void
packet_set_nd(struct dp_packet *packet, const struct in6_addr *target,
- const struct eth_addr sll, const struct eth_addr tll)
+ const struct eth_addr sll, const struct eth_addr tll,
+ uint32_t reserved, uint8_t nd_options_type)
{
struct ovs_nd_msg *ns;
struct ovs_nd_lla_opt *opt;
int bytes_remain = dp_packet_l4_size(packet);
+ int msg_size = bytes_remain;
+ struct ovs_16aligned_ip6_hdr * nh = dp_packet_l3(packet);
+ uint32_t pseudo_hdr_csum = 0;
+
+ if (nh) {
+ pseudo_hdr_csum = packet_csum_pseudoheader6(nh);
+ }
if (OVS_UNLIKELY(bytes_remain < sizeof(*ns))) {
return;
@@ -1296,6 +1304,7 @@ packet_set_nd(struct dp_packet *packet, const struct in6_addr *target,
ns = dp_packet_l4(packet);
opt = &ns->options[0];
bytes_remain -= sizeof(*ns);
+ put_16aligned_be32(&(ns->rso_flags),reserved);
if (memcmp(&ns->target, target, sizeof(ovs_be32[4]))) {
packet_set_ipv6_addr(packet, IPPROTO_ICMPV6, ns->target.be32, target,
@@ -1303,21 +1312,17 @@ packet_set_nd(struct dp_packet *packet, const struct in6_addr *target,
}
while (bytes_remain >= ND_LLA_OPT_LEN && opt->len != 0) {
- if (opt->type == ND_OPT_SOURCE_LINKADDR && opt->len == 1) {
+ if (nd_options_type == ND_OPT_SOURCE_LINKADDR && opt->len == 1) {
if (!eth_addr_equals(opt->mac, sll)) {
- ovs_be16 *csum = &(ns->icmph.icmp6_cksum);
-
- *csum = recalc_csum48(*csum, opt->mac, sll);
+ opt->type = 1;
opt->mac = sll;
}
-
/* A packet can only contain one SLL or TLL option */
break;
- } else if (opt->type == ND_OPT_TARGET_LINKADDR && opt->len == 1) {
+ } else if (nd_options_type == ND_OPT_TARGET_LINKADDR
+ && opt->len == 1) {
if (!eth_addr_equals(opt->mac, tll)) {
- ovs_be16 *csum = &(ns->icmph.icmp6_cksum);
-
- *csum = recalc_csum48(*csum, opt->mac, tll);
+ opt->type = 2;
opt->mac = tll;
}
@@ -1328,6 +1333,11 @@ packet_set_nd(struct dp_packet *packet, const struct in6_addr *target,
opt += opt->len;
bytes_remain -= opt->len * ND_LLA_OPT_LEN;
}
+
+ ovs_be16 *csum_value = &(ns->icmph.icmp6_cksum);
+ *csum_value = 0;
+ *csum_value = csum_finish(csum_continue(pseudo_hdr_csum,
+ &(ns->icmph), msg_size));
}
const char *
@@ -1505,13 +1515,12 @@ compose_nd_ns(struct dp_packet *b, const struct eth_addr eth_src,
ns->icmph.icmp6_type = ND_NEIGHBOR_SOLICIT;
ns->icmph.icmp6_code = 0;
- put_16aligned_be32(&ns->rso_flags, htonl(0));
lla_opt = &ns->options[0];
lla_opt->type = ND_OPT_SOURCE_LINKADDR;
lla_opt->len = 1;
- packet_set_nd(b, ipv6_dst, eth_src, eth_addr_zero);
+ packet_set_nd(b, ipv6_dst, eth_src, eth_addr_zero, 0, 1);
ns->icmph.icmp6_cksum = 0;
icmp_csum = packet_csum_pseudoheader6(dp_packet_l3(b));
@@ -1536,13 +1545,12 @@ compose_nd_na(struct dp_packet *b,
na->icmph.icmp6_type = ND_NEIGHBOR_ADVERT;
na->icmph.icmp6_code = 0;
- put_16aligned_be32(&na->rso_flags, rso_flags);
lla_opt = &na->options[0];
lla_opt->type = ND_OPT_TARGET_LINKADDR;
lla_opt->len = 1;
- packet_set_nd(b, ipv6_src, eth_addr_zero, eth_src);
+ packet_set_nd(b, ipv6_src, eth_addr_zero, eth_src, rso_flags, 2);
na->icmph.icmp6_cksum = 0;
icmp_csum = packet_csum_pseudoheader6(dp_packet_l3(b));
@@ -1542,7 +1542,8 @@ void packet_set_udp_port(struct dp_packet *, ovs_be16 src, ovs_be16 dst);
void packet_set_sctp_port(struct dp_packet *, ovs_be16 src, ovs_be16 dst);
void packet_set_icmp(struct dp_packet *, uint8_t type, uint8_t code);
void packet_set_nd(struct dp_packet *, const struct in6_addr *target,
- const struct eth_addr sll, const struct eth_addr tll);
+ const struct eth_addr sll, const struct eth_addr tll,
+ const ovs_be32 reserved, const uint8_t nd_options_type);
void packet_format_tcp_flags(struct ds *, uint16_t);
const char *packet_tcp_flag_to_string(uint32_t flag);
@@ -19,9 +19,9 @@ in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x86dd),ipv
in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x86dd),ipv6(src=::1,dst=::2,label=0,proto=6,tclass=0,hlimit=128,frag=no),tcp(src=80,dst=8080)
in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x86dd),ipv6(src=::1,dst=::2,label=0,proto=17,tclass=0,hlimit=128,frag=no),udp(src=6630,dst=22)
in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x86dd),ipv6(src=::1,dst=::2,label=0,proto=58,tclass=0,hlimit=128,frag=no),icmpv6(type=1,code=2)
-in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x86dd),ipv6(src=::1,dst=::2,label=0,proto=58,tclass=0,hlimit=128,frag=no),icmpv6(type=136,code=0),nd(target=::3,sll=00:05:06:07:08:09,tll=00:0a:0b:0c:0d:0e)
+in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x86dd),ipv6(src=::1,dst=::2,label=0,proto=58,tclass=0,hlimit=128,frag=no),icmpv6(type=136,code=0),nd(nd_reserved=0x0,target=::3,nd_options_type=0,sll=00:05:06:07:08:09,tll=00:0a:0b:0c:0d:0e)
in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x0806),arp(sip=1.2.3.4,tip=5.6.7.8,op=1,sha=00:0f:10:11:12:13,tha=00:14:15:16:17:18)
-in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x86dd),ipv6(src=::1,dst=::2,label=0,proto=58,tclass=0,hlimit=128,frag=no),icmpv6(type=136,code=0),nd(target=::3,sll=00:05:06:07:08:09,tll=00:0a:0b:0c:0d:0e)
+in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x86dd),ipv6(src=::1,dst=::2,label=0,proto=58,tclass=0,hlimit=128,frag=no),icmpv6(type=136,code=0),nd(nd_reserved=0x0,target=::3,nd_options_type=0,sll=00:05:06:07:08:09,tll=00:0a:0b:0c:0d:0e)
in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x8847),mpls(label=100,tc=3,ttl=64,bos=1)
in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x8847),mpls(label=100,tc=7,ttl=100,bos=1)
in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x8847),mpls(label=100,tc=7,ttl=100,bos=0)
@@ -124,12 +124,12 @@ in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x86dd),ipv
in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x86dd),ipv6(src=::1,dst=::2,label=0,proto=6,tclass=0,hlimit=128,frag=no),tcp(src=80/0xff00,dst=8080/0xff)
in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x86dd),ipv6(src=::1,dst=::2,label=0,proto=17,tclass=0,hlimit=128,frag=no),udp(src=6630/0xff00,dst=22/0xff)
in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x86dd),ipv6(src=::1,dst=::2,label=0,proto=58,tclass=0,hlimit=128,frag=no),icmpv6(type=1/0xf0,code=2)
-in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x86dd),ipv6(src=::1,dst=::2,label=0,proto=58,tclass=0,hlimit=128,frag=no),icmpv6(type=135,code=0),nd(target=::3/::250)
-in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x86dd),ipv6(src=::1,dst=::2,label=0,proto=58,tclass=0,hlimit=128,frag=no),icmpv6(type=135,code=0),nd(target=::3/::250,sll=00:05:06:07:08:09/ff:ff:ff:ff:ff:00)
-in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x86dd),ipv6(src=::1,dst=::2,label=0,proto=58,tclass=0,hlimit=128,frag=no),icmpv6(type=136,code=0),nd(target=::3/::250,tll=00:0a:0b:0c:0d:0e/ff:ff:ff:ff:ff:00)
-in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x86dd),ipv6(src=::1,dst=::2,label=0,proto=58,tclass=0,hlimit=128,frag=no),icmpv6(type=136,code=0),nd(target=::3/::250,sll=00:05:06:07:08:09/ff:ff:ff:ff:ff:00,tll=00:0a:0b:0c:0d:0e/ff:ff:ff:ff:ff:00)
+in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x86dd),ipv6(src=::1,dst=::2,label=0,proto=58,tclass=0,hlimit=128,frag=no),icmpv6(type=135,code=0),nd(nd_reserved=0x0,target=::3/::250,nd_options_type=0)
+in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x86dd),ipv6(src=::1,dst=::2,label=0,proto=58,tclass=0,hlimit=128,frag=no),icmpv6(type=135,code=0),nd(nd_reserved=0x0,target=::3/::250,nd_options_type=0,sll=00:05:06:07:08:09/ff:ff:ff:ff:ff:00)
+in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x86dd),ipv6(src=::1,dst=::2,label=0,proto=58,tclass=0,hlimit=128,frag=no),icmpv6(type=136,code=0),nd(nd_reserved=0x0,target=::3/::250,nd_options_type=0,tll=00:0a:0b:0c:0d:0e/ff:ff:ff:ff:ff:00)
+in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x86dd),ipv6(src=::1,dst=::2,label=0,proto=58,tclass=0,hlimit=128,frag=no),icmpv6(type=136,code=0),nd(nd_reserved=0x0,target=::3/::250,nd_options_type=0,sll=00:05:06:07:08:09/ff:ff:ff:ff:ff:00,tll=00:0a:0b:0c:0d:0e/ff:ff:ff:ff:ff:00)
in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x0806),arp(sip=1.2.3.4/255.255.255.250,tip=5.6.7.8/255.255.255.250,op=1/0xf0,sha=00:0f:10:11:12:13/ff:ff:ff:ff:ff:00,tha=00:14:15:16:17:18/ff:ff:ff:ff:ff:00)
-skb_mark(0x1234/0xfff0),in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x86dd),ipv6(src=::1,dst=::2,label=0,proto=58,tclass=0,hlimit=128,frag=no),icmpv6(type=136,code=0),nd(target=::3,sll=00:05:06:07:08:09,tll=00:0a:0b:0c:0d:0e)
+skb_mark(0x1234/0xfff0),in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x86dd),ipv6(src=::1,dst=::2,label=0,proto=58,tclass=0,hlimit=128,frag=no),icmpv6(type=136,code=0),nd(nd_reserved=0x0,target=::3,nd_options_type=0,sll=00:05:06:07:08:09,tll=00:0a:0b:0c:0d:0e)
])
(echo '# Valid forms without tun_id or VLAN header.'
@@ -269,7 +269,7 @@ AT_CHECK([ovs-ofctl -O OpenFlow12 add-flows br0 flows.txt])
AT_CHECK([ovs-appctl ofproto/trace br0 'in_port=1,dl_src=50:54:00:00:00:05,dl_dst=50:54:00:00:00:07,icmp6,ipv6_src=fe80::1,ipv6_dst=fe80::2,nw_tos=0,nw_ttl=128,icmpv6_type=135,nd_target=fe80::2020,nd_sll=66:55:44:33:22:11'], [0], [stdout])
AT_CHECK([tail -4 stdout], [0],
[Megaflow: recirc_id=0,eth,icmp6,in_port=1,nw_frag=no,icmp_type=0x87/0xff,icmp_code=0x0/0xff,nd_target=fe80::2020,nd_sll=66:55:44:33:22:11
-Datapath actions: 10,set(nd(target=fe80::4,sll=cc:cc:cc:cc:cc:cc)),11,set(nd(target=fe80::3,sll=aa:aa:aa:aa:aa:aa)),13
+Datapath actions: 10,set(nd(nd_reserved=0x0,target=fe80::4,sll=cc:cc:cc:cc:cc:cc)),11,set(nd(nd_reserved=0x0,target=fe80::3,sll=aa:aa:aa:aa:aa:aa)),13
This flow is handled by the userspace slow path because it:
- Uses action(s) not supported by datapath.
])
@@ -9152,7 +9152,7 @@ OVS_APP_EXIT_AND_WAIT([ovs-ofctl])
AT_CHECK([cat ofctl_monitor.log], [0], [dnl
NXT_PACKET_IN (xid=0x0): cookie=0x0 total_len=86 in_port=1 (via no_match) data_len=86 (unbuffered)
-icmp6,vlan_tci=0x0000,dl_src=00:00:86:05:80:da,dl_dst=00:60:97:07:69:ea,ipv6_src=fe80::200:86ff:fe05:80da,ipv6_dst=fe80::260:97ff:fe07:69ea,ipv6_label=0x00000,nw_tos=0,nw_ecn=0,nw_ttl=255,icmp_type=135,icmp_code=0,nd_target=fe80::260:97ff:fe07:69ea,nd_sll=00:00:86:05:80:da,nd_tll=00:00:00:00:00:00 icmp6_csum:68bd
+icmp6,vlan_tci=0x0000,dl_src=00:00:86:05:80:da,dl_dst=00:60:97:07:69:ea,ipv6_src=fe80::200:86ff:fe05:80da,ipv6_dst=fe80::260:97ff:fe07:69ea,ipv6_label=0x00000,nw_tos=0,nw_ecn=0,nw_ttl=255,icmp_type=135,icmp_code=0,nd_target=fe80::260:97ff:fe07:69ea,nd_sll=00:00:86:05:80:da,nd_tll=00:00:00:00:00:00,nd_reserved=0,nd_options_type=1 icmp6_csum:68bd
])
OVS_VSWITCHD_STOP
@@ -9203,7 +9203,7 @@ OVS_APP_EXIT_AND_WAIT([ovs-ofctl])
AT_CHECK([cat ofctl_monitor.log], [0], [dnl
NXT_PACKET_IN (xid=0x0): cookie=0x0 total_len=86 in_port=1 (via action) data_len=86 (unbuffered)
-icmp6,vlan_tci=0x0000,dl_src=00:00:86:05:80:da,dl_dst=00:60:97:07:69:ea,ipv6_src=fe80::200:86ff:fe05:80da,ipv6_dst=fe80::260:97ff:fe07:69ea,ipv6_label=0x00000,nw_tos=0,nw_ecn=0,nw_ttl=255,icmp_type=135,icmp_code=0,nd_target=fe80::1,nd_sll=32:21:14:86:11:74,nd_tll=00:00:00:00:00:00 icmp6_csum:19d3
+icmp6,vlan_tci=0x0000,dl_src=00:00:86:05:80:da,dl_dst=00:60:97:07:69:ea,ipv6_src=fe80::200:86ff:fe05:80da,ipv6_dst=fe80::260:97ff:fe07:69ea,ipv6_label=0x00000,nw_tos=0,nw_ecn=0,nw_ttl=255,icmp_type=135,icmp_code=0,nd_target=fe80::1,nd_sll=32:21:14:86:11:74,nd_tll=00:00:00:00:00:00,nd_reserved=0,nd_options_type=1 icmp6_csum:19d3
])
OVS_VSWITCHD_STOP
@@ -9764,7 +9764,7 @@ OVS_WAIT_UNTIL([ovs-appctl -t ovs-ofctl exit])
AT_CHECK([cat ofctl_monitor.log], [0], [dnl
NXT_PACKET_IN (xid=0x0): cookie=0x0 total_len=86 ct_state=inv|trk,ipv6,in_port=2 (via action) data_len=86 (unbuffered)
-icmp6,vlan_tci=0x0000,dl_src=00:00:86:05:80:da,dl_dst=00:60:97:07:69:ea,ipv6_src=fe80::200:86ff:fe05:80da,ipv6_dst=fe80::260:97ff:fe07:69ea,ipv6_label=0x00000,nw_tos=0,nw_ecn=0,nw_ttl=255,icmp_type=135,icmp_code=0,nd_target=fe80::260:97ff:fe07:69ea,nd_sll=00:00:86:05:80:da,nd_tll=00:00:00:00:00:00 icmp6_csum:68bd
+icmp6,vlan_tci=0x0000,dl_src=00:00:86:05:80:da,dl_dst=00:60:97:07:69:ea,ipv6_src=fe80::200:86ff:fe05:80da,ipv6_dst=fe80::260:97ff:fe07:69ea,ipv6_label=0x00000,nw_tos=0,nw_ecn=0,nw_ttl=255,icmp_type=135,icmp_code=0,nd_target=fe80::260:97ff:fe07:69ea,nd_sll=00:00:86:05:80:da,nd_tll=00:00:00:00:00:00,nd_reserved=0,nd_options_type=1 icmp6_csum:68bd
])
OVS_VSWITCHD_STOP
@@ -2456,7 +2456,7 @@ head_table () {
actions: output group set_field strip_vlan push_vlan mod_nw_ttl dec_ttl set_mpls_ttl dec_mpls_ttl push_mpls pop_mpls set_queue
supported on Set-Field: tun_id tun_src tun_dst tun_ipv6_src tun_ipv6_dst tun_flags tun_gbp_id tun_gbp_flags tun_erspan_idx tun_erspan_ver tun_erspan_dir tun_erspan_hwid tun_metadata0 dnl
tun_metadata1 tun_metadata2 tun_metadata3 tun_metadata4 tun_metadata5 tun_metadata6 tun_metadata7 tun_metadata8 tun_metadata9 tun_metadata10 tun_metadata11 tun_metadata12 tun_metadata13 tun_metadata14 tun_metadata15 tun_metadata16 tun_metadata17 tun_metadata18 tun_metadata19 tun_metadata20 tun_metadata21 tun_metadata22 tun_metadata23 tun_metadata24 tun_metadata25 tun_metadata26 tun_metadata27 tun_metadata28 tun_metadata29 tun_metadata30 tun_metadata31 tun_metadata32 tun_metadata33 tun_metadata34 tun_metadata35 tun_metadata36 tun_metadata37 tun_metadata38 tun_metadata39 tun_metadata40 tun_metadata41 tun_metadata42 tun_metadata43 tun_metadata44 tun_metadata45 tun_metadata46 tun_metadata47 tun_metadata48 tun_metadata49 tun_metadata50 tun_metadata51 tun_metadata52 tun_metadata53 tun_metadata54 tun_metadata55 tun_metadata56 tun_metadata57 tun_metadata58 tun_metadata59 tun_metadata60 tun_metadata61 tun_metadata62 tun_metadata63 dnl
-metadata in_port in_port_oxm pkt_mark ct_mark ct_label reg0 reg1 reg2 reg3 reg4 reg5 reg6 reg7 reg8 reg9 reg10 reg11 reg12 reg13 reg14 reg15 xreg0 xreg1 xreg2 xreg3 xreg4 xreg5 xreg6 xreg7 xxreg0 xxreg1 xxreg2 xxreg3 eth_src eth_dst vlan_tci vlan_vid vlan_pcp mpls_label mpls_tc mpls_ttl ip_src ip_dst ipv6_src ipv6_dst ipv6_label nw_tos ip_dscp nw_ecn nw_ttl arp_op arp_spa arp_tpa arp_sha arp_tha tcp_src tcp_dst udp_src udp_dst sctp_src sctp_dst icmp_type icmp_code icmpv6_type icmpv6_code nd_target nd_sll nd_tll nsh_flags nsh_spi nsh_si nsh_c1 nsh_c2 nsh_c3 nsh_c4 nsh_ttl
+metadata in_port in_port_oxm pkt_mark ct_mark ct_label reg0 reg1 reg2 reg3 reg4 reg5 reg6 reg7 reg8 reg9 reg10 reg11 reg12 reg13 reg14 reg15 xreg0 xreg1 xreg2 xreg3 xreg4 xreg5 xreg6 xreg7 xxreg0 xxreg1 xxreg2 xxreg3 eth_src eth_dst vlan_tci vlan_vid vlan_pcp mpls_label mpls_tc mpls_ttl ip_src ip_dst ipv6_src ipv6_dst ipv6_label nw_tos ip_dscp nw_ecn nw_ttl arp_op arp_spa arp_tpa arp_sha arp_tha tcp_src tcp_dst udp_src udp_dst sctp_src sctp_dst icmp_type icmp_code icmpv6_type icmpv6_code nd_target nd_sll nd_tll nd_reserved nd_options_type nsh_flags nsh_spi nsh_si nsh_c1 nsh_c2 nsh_c3 nsh_c4 nsh_ttl
matching:
dp_hash: arbitrary mask
recirc_id: exact match or wildcard
@@ -2622,6 +2622,8 @@ metadata in_port in_port_oxm pkt_mark ct_mark ct_label reg0 reg1 reg2 reg3 reg4
nd_target: arbitrary mask
nd_sll: arbitrary mask
nd_tll: arbitrary mask
+ nd_reserved: exact match or wildcard
+ nd_options_type: exact match or wildcard
nsh_flags: arbitrary mask
nsh_mdtype: exact match or wildcard
nsh_np: exact match or wildcard