/*
- * Copyright (c) 2009, 2010, 2011, 2012, 2013, 2014, 2015 Nicira, Inc.
+ * Copyright (c) 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016 Nicira, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
#include <math.h>
#include <netinet/in.h>
#include <netinet/icmp6.h>
+#include <netinet/ip6.h>
#include <stdlib.h>
#include <string.h>
}
static const void *
-format_udp_tnl_push_header(struct ds *ds, const struct ip_header *ip)
+format_udp_tnl_push_header(struct ds *ds, const struct udp_header *udp)
{
- const struct udp_header *udp;
-
- udp = (const struct udp_header *) (ip + 1);
ds_put_format(ds, "udp(src=%"PRIu16",dst=%"PRIu16",csum=0x%"PRIx16"),",
ntohs(udp->udp_src), ntohs(udp->udp_dst),
ntohs(udp->udp_csum));
format_odp_tnl_push_header(struct ds *ds, struct ovs_action_push_tnl *data)
{
const struct eth_header *eth;
- const struct ip_header *ip;
const void *l3;
+ const void *l4;
+ const struct udp_header *udp;
eth = (const struct eth_header *)data->header;
l3 = eth + 1;
- ip = (const struct ip_header *)l3;
/* Ethernet */
ds_put_format(ds, "header(size=%"PRIu8",type=%"PRIu8",eth(dst=",
ds_put_format(ds, ETH_ADDR_FMT, ETH_ADDR_ARGS(eth->eth_src));
ds_put_format(ds, ",dl_type=0x%04"PRIx16"),", ntohs(eth->eth_type));
- /* IPv4 */
- ds_put_format(ds, "ipv4(src="IP_FMT",dst="IP_FMT",proto=%"PRIu8
- ",tos=%#"PRIx8",ttl=%"PRIu8",frag=0x%"PRIx16"),",
- IP_ARGS(get_16aligned_be32(&ip->ip_src)),
- IP_ARGS(get_16aligned_be32(&ip->ip_dst)),
- ip->ip_proto, ip->ip_tos,
- ip->ip_ttl,
- ip->ip_frag_off);
+ if (eth->eth_type == htons(ETH_TYPE_IP)) {
+ /* IPv4 */
+ const struct ip_header *ip;
+ ip = (const struct ip_header *) l3;
+ ds_put_format(ds, "ipv4(src="IP_FMT",dst="IP_FMT",proto=%"PRIu8
+ ",tos=%#"PRIx8",ttl=%"PRIu8",frag=0x%"PRIx16"),",
+ IP_ARGS(get_16aligned_be32(&ip->ip_src)),
+ IP_ARGS(get_16aligned_be32(&ip->ip_dst)),
+ ip->ip_proto, ip->ip_tos,
+ ip->ip_ttl,
+ ntohs(ip->ip_frag_off));
+ l4 = (ip + 1);
+ } else {
+ const struct ip6_hdr *ip6;
+ ip6 = (const struct ip6_hdr *) l3;
+ ds_put_format(ds, "ipv6(src=");
+ ipv6_format_addr(&ip6->ip6_src, ds);
+ ds_put_format(ds, ",dst=");
+ ipv6_format_addr(&ip6->ip6_dst, ds);
+ ds_put_format(ds, ",label=%i,proto=%"PRIu8",tclass=0x%"PRIx8
+ ",hlimit=%"PRIu8"),",
+ ntohl(ip6->ip6_flow) & IPV6_LABEL_MASK, ip6->ip6_nxt,
+ (ntohl(ip6->ip6_flow) >> 20) & 0xff, ip6->ip6_hlim);
+ l4 = (ip6 + 1);
+ }
+
+ udp = (const struct udp_header *) l4;
if (data->tnl_type == OVS_VPORT_TYPE_VXLAN) {
const struct vxlanhdr *vxh;
- vxh = format_udp_tnl_push_header(ds, ip);
+ vxh = format_udp_tnl_push_header(ds, udp);
ds_put_format(ds, "vxlan(flags=0x%"PRIx32",vni=0x%"PRIx32")",
ntohl(get_16aligned_be32(&vxh->vx_flags)),
} else if (data->tnl_type == OVS_VPORT_TYPE_GENEVE) {
const struct genevehdr *gnh;
- gnh = format_udp_tnl_push_header(ds, ip);
+ gnh = format_udp_tnl_push_header(ds, udp);
ds_put_format(ds, "geneve(%s%svni=0x%"PRIx32,
gnh->oam ? "oam," : "",
} else if (data->tnl_type == OVS_VPORT_TYPE_GRE) {
const struct gre_base_hdr *greh;
ovs_16aligned_be32 *options;
- void *l4;
- l4 = ((uint8_t *)l3 + sizeof(struct ip_header));
greh = (const struct gre_base_hdr *) l4;
ds_put_format(ds, "gre((flags=0x%"PRIx16",proto=0x%"PRIx16")",
{
int expected_len;
enum ovs_action_attr type = nl_attr_type(a);
- const struct ovs_action_push_vlan *vlan;
size_t size;
expected_len = odp_action_len(nl_attr_type(a));
format_odp_key_attr(nl_attr_get(a), NULL, NULL, ds, true);
ds_put_cstr(ds, ")");
break;
- case OVS_ACTION_ATTR_PUSH_VLAN:
- vlan = nl_attr_get(a);
+ case OVS_ACTION_ATTR_PUSH_VLAN: {
+ const struct ovs_action_push_vlan *vlan = nl_attr_get(a);
ds_put_cstr(ds, "push_vlan(");
if (vlan->vlan_tpid != htons(ETH_TYPE_VLAN)) {
ds_put_format(ds, "tpid=0x%04"PRIx16",", ntohs(vlan->vlan_tpid));
format_vlan_tci(ds, vlan->vlan_tci, OVS_BE16_MAX, false);
ds_put_char(ds, ')');
break;
+ }
case OVS_ACTION_ATTR_POP_VLAN:
ds_put_cstr(ds, "pop_vlan");
break;
void *user_data = NULL;
size_t user_data_size = 0;
bool include_actions = false;
+ int res;
if (!ovs_scan(s, "userspace(pid=%"SCNi32"%n", &pid, &n)) {
return -EINVAL;
}
+ ofpbuf_init(&buf, 16);
+
{
uint32_t output;
uint32_t probability;
user_data_size = sizeof cookie.sflow;
} else if (ovs_scan(&s[n], ",slow_path(%n",
&n1)) {
- int res;
-
n += n1;
cookie.type = USER_ACTION_COOKIE_SLOW_PATH;
cookie.slow_path.unused = 0;
&cookie.slow_path.reason,
SLOW_PATH_REASON_MASK, NULL);
if (res < 0 || s[n + res] != ')') {
- return res;
+ goto out;
}
n += res + 1;
char *end;
n += n1;
- ofpbuf_init(&buf, 16);
end = ofpbuf_put_hex(&buf, &s[n], NULL);
if (end[0] != ')') {
- return -EINVAL;
+ res = -EINVAL;
+ goto out;
}
user_data = buf.data;
user_data_size = buf.size;
&tunnel_out_port, &n1)) {
odp_put_userspace_action(pid, user_data, user_data_size,
tunnel_out_port, include_actions, actions);
- return n + n1;
+ res = n + n1;
} else if (s[n] == ')') {
odp_put_userspace_action(pid, user_data, user_data_size,
ODPP_NONE, include_actions, actions);
- return n + 1;
+ res = n + 1;
+ } else {
+ res = -EINVAL;
}
}
-
- return -EINVAL;
+out:
+ ofpbuf_uninit(&buf);
+ return res;
}
static int
{
struct eth_header *eth;
struct ip_header *ip;
+ struct ovs_16aligned_ip6_hdr *ip6;
struct udp_header *udp;
struct gre_base_hdr *greh;
uint16_t gre_proto, gre_flags, dl_type, udp_src, udp_dst, csum;
ovs_be32 sip, dip;
- uint32_t tnl_type = 0, header_len = 0;
+ uint32_t tnl_type = 0, header_len = 0, ip_len = 0;
void *l3, *l4;
int n = 0;
}
eth = (struct eth_header *) data->header;
l3 = (data->header + sizeof *eth);
- l4 = ((uint8_t *) l3 + sizeof (struct ip_header));
ip = (struct ip_header *) l3;
+ ip6 = (struct ovs_16aligned_ip6_hdr *) l3;
if (!ovs_scan_len(s, &n, "header(size=%"SCNi32",type=%"SCNi32","
"eth(dst="ETH_ADDR_SCAN_FMT",",
&data->header_len,
}
eth->eth_type = htons(dl_type);
- /* IPv4 */
- if (!ovs_scan_len(s, &n, "ipv4(src="IP_SCAN_FMT",dst="IP_SCAN_FMT",proto=%"SCNi8
- ",tos=%"SCNi8",ttl=%"SCNi8",frag=0x%"SCNx16"),",
- IP_SCAN_ARGS(&sip),
- IP_SCAN_ARGS(&dip),
- &ip->ip_proto, &ip->ip_tos,
- &ip->ip_ttl, &ip->ip_frag_off)) {
- return -EINVAL;
+ if (eth->eth_type == htons(ETH_TYPE_IP)) {
+ /* IPv4 */
+ uint16_t ip_frag_off;
+ if (!ovs_scan_len(s, &n, "ipv4(src="IP_SCAN_FMT",dst="IP_SCAN_FMT",proto=%"SCNi8
+ ",tos=%"SCNi8",ttl=%"SCNi8",frag=0x%"SCNx16"),",
+ IP_SCAN_ARGS(&sip),
+ IP_SCAN_ARGS(&dip),
+ &ip->ip_proto, &ip->ip_tos,
+ &ip->ip_ttl, &ip_frag_off)) {
+ return -EINVAL;
+ }
+ put_16aligned_be32(&ip->ip_src, sip);
+ put_16aligned_be32(&ip->ip_dst, dip);
+ ip->ip_frag_off = htons(ip_frag_off);
+ ip_len = sizeof *ip;
+ } else {
+ char sip6_s[IPV6_SCAN_LEN + 1];
+ char dip6_s[IPV6_SCAN_LEN + 1];
+ struct in6_addr sip6, dip6;
+ uint8_t tclass;
+ uint32_t label;
+ if (!ovs_scan_len(s, &n, "ipv6(src="IPV6_SCAN_FMT",dst="IPV6_SCAN_FMT
+ ",label=%i,proto=%"SCNi8",tclass=0x%"SCNx8
+ ",hlimit=%"SCNi8"),",
+ sip6_s, dip6_s, &label, &ip6->ip6_nxt,
+ &tclass, &ip6->ip6_hlim)
+ || (label & ~IPV6_LABEL_MASK) != 0
+ || inet_pton(AF_INET6, sip6_s, &sip6) != 1
+ || inet_pton(AF_INET6, dip6_s, &dip6) != 1) {
+ return -EINVAL;
+ }
+ put_16aligned_be32(&ip6->ip6_flow, htonl(6 << 28) |
+ htonl(tclass << 20) | htonl(label));
+ memcpy(&ip6->ip6_src, &sip6, sizeof(ip6->ip6_src));
+ memcpy(&ip6->ip6_dst, &dip6, sizeof(ip6->ip6_dst));
+ ip_len = sizeof *ip6;
}
- put_16aligned_be32(&ip->ip_src, sip);
- put_16aligned_be32(&ip->ip_dst, dip);
/* Tunnel header */
+ l4 = ((uint8_t *) l3 + ip_len);
udp = (struct udp_header *) l4;
greh = (struct gre_base_hdr *) l4;
if (ovs_scan_len(s, &n, "udp(src=%"SCNi16",dst=%"SCNi16",csum=0x%"SCNx16"),",
put_16aligned_be32(&vxh->vx_flags, htonl(vx_flags));
put_16aligned_be32(&vxh->vx_vni, htonl(vni << 8));
tnl_type = OVS_VPORT_TYPE_VXLAN;
- header_len = sizeof *eth + sizeof *ip +
+ header_len = sizeof *eth + ip_len +
sizeof *udp + sizeof *vxh;
} else if (ovs_scan_len(s, &n, "geneve(")) {
struct genevehdr *gnh = (struct genevehdr *) (udp + 1);
memset(gnh, 0, sizeof *gnh);
- header_len = sizeof *eth + sizeof *ip +
+ header_len = sizeof *eth + ip_len +
sizeof *udp + sizeof *gnh;
if (ovs_scan_len(s, &n, "oam,")) {
return -EINVAL;
}
- header_len = sizeof *eth + sizeof *ip +
+ header_len = sizeof *eth + ip_len +
((uint8_t *) options - (uint8_t *) greh);
} else {
return -EINVAL;
[OVS_TUNNEL_KEY_ATTR_VXLAN_OPTS] = { .len = ATTR_LEN_NESTED,
.next = ovs_vxlan_ext_attr_lens ,
.next_max = OVS_VXLAN_EXT_MAX},
+ [OVS_TUNNEL_KEY_ATTR_IPV6_SRC] = { .len = 16 },
+ [OVS_TUNNEL_KEY_ATTR_IPV6_DST] = { .len = 16 },
};
static const struct attr_len_tbl ovs_flow_key_attr_lens[OVS_KEY_ATTR_MAX + 1] = {
case OVS_TUNNEL_KEY_ATTR_IPV4_DST:
tun->ip_dst = nl_attr_get_be32(a);
break;
+ case OVS_TUNNEL_KEY_ATTR_IPV6_SRC:
+ tun->ipv6_src = nl_attr_get_in6_addr(a);
+ break;
+ case OVS_TUNNEL_KEY_ATTR_IPV6_DST:
+ tun->ipv6_dst = nl_attr_get_in6_addr(a);
+ break;
case OVS_TUNNEL_KEY_ATTR_TOS:
tun->ip_tos = nl_attr_get_u8(a);
break;
if (tun_key->ip_dst) {
nl_msg_put_be32(a, OVS_TUNNEL_KEY_ATTR_IPV4_DST, tun_key->ip_dst);
}
+ if (ipv6_addr_is_set(&tun_key->ipv6_src)) {
+ nl_msg_put_in6_addr(a, OVS_TUNNEL_KEY_ATTR_IPV6_SRC, &tun_key->ipv6_src);
+ }
+ if (ipv6_addr_is_set(&tun_key->ipv6_dst)) {
+ nl_msg_put_in6_addr(a, OVS_TUNNEL_KEY_ATTR_IPV6_DST, &tun_key->ipv6_dst);
+ }
if (tun_key->ip_tos) {
nl_msg_put_u8(a, OVS_TUNNEL_KEY_ATTR_TOS, tun_key->ip_tos);
}
}
static void
-format_ipv6(struct ds *ds, const char *name, const ovs_be32 key_[4],
- const ovs_be32 (*mask_)[4], bool verbose)
+format_in6_addr(struct ds *ds, const char *name,
+ const struct in6_addr *key,
+ const struct in6_addr *mask,
+ bool verbose)
{
char buf[INET6_ADDRSTRLEN];
- const struct in6_addr *key = (const struct in6_addr *)key_;
- const struct in6_addr *mask = mask_ ? (const struct in6_addr *)*mask_
- : NULL;
bool mask_empty = mask && ipv6_mask_is_any(mask);
if (verbose || !mask_empty) {
}
}
+static void
+format_ipv6(struct ds *ds, const char *name, const ovs_be32 key_[4],
+ const ovs_be32 (*mask_)[4], bool verbose)
+{
+ format_in6_addr(ds, name,
+ (const struct in6_addr *)key_,
+ mask_ ? (const struct in6_addr *)*mask_ : NULL,
+ verbose);
+}
+
static void
format_ipv6_label(struct ds *ds, const char *name, ovs_be32 key,
const ovs_be32 *mask, bool verbose)
format_ipv4(ds, "dst", nl_attr_get_be32(a),
ma ? nl_attr_get(ma) : NULL, verbose);
break;
+ case OVS_TUNNEL_KEY_ATTR_IPV6_SRC: {
+ struct in6_addr ipv6_src;
+ ipv6_src = nl_attr_get_in6_addr(a);
+ format_in6_addr(ds, "ipv6_src", &ipv6_src,
+ ma ? nl_attr_get(ma) : NULL, verbose);
+ break;
+ }
+ case OVS_TUNNEL_KEY_ATTR_IPV6_DST: {
+ struct in6_addr ipv6_dst;
+ ipv6_dst = nl_attr_get_in6_addr(a);
+ format_in6_addr(ds, "ipv6_dst", &ipv6_dst,
+ ma ? nl_attr_get(ma) : NULL, verbose);
+ break;
+ }
case OVS_TUNNEL_KEY_ATTR_TOS:
format_u8x(ds, "tos", nl_attr_get_u8(a),
ma ? nl_attr_get(ma) : NULL, verbose);
return "rel";
case OVS_CS_F_INVALID:
return "inv";
+ case OVS_CS_F_SRC_NAT:
+ return "snat";
+ case OVS_CS_F_DST_NAT:
+ return "dnat";
default:
return NULL;
}
}
static int
-scan_ipv6(const char *s, ovs_be32 (*key)[4], ovs_be32 (*mask)[4])
+scan_in6_addr(const char *s, struct in6_addr *key, struct in6_addr *mask)
{
int n;
char ipv6_s[IPV6_SCAN_LEN + 1];
return 0;
}
+static int
+scan_ipv6(const char *s, ovs_be32 (*key)[4], ovs_be32 (*mask)[4])
+{
+ return scan_in6_addr(s, key ? (struct in6_addr *) *key : NULL,
+ mask ? (struct in6_addr *) *mask : NULL);
+}
+
static int
scan_ipv6_label(const char *s, ovs_be32 *key, ovs_be32 *mask)
{
if (state & CS_TRACKED) {
odp |= OVS_CS_F_TRACKED;
}
+ if (state & CS_SRC_NAT) {
+ odp |= OVS_CS_F_SRC_NAT;
+ }
+ if (state & CS_DST_NAT) {
+ odp |= OVS_CS_F_DST_NAT;
+ }
return odp;
}
if (flags & OVS_CS_F_TRACKED) {
state |= CS_TRACKED;
}
+ if (flags & OVS_CS_F_SRC_NAT) {
+ state |= CS_SRC_NAT;
+ }
+ if (flags & OVS_CS_F_DST_NAT) {
+ state |= CS_DST_NAT;
+ }
return state;
}
SCAN_FIELD_NESTED__(NAME, TYPE, SCAN_AS, 0, FUNC)
#define SCAN_PUT(ATTR, FUNC) \
- if (!mask || !is_all_zeros(&smask, sizeof smask)) { \
- SCAN_PUT_ATTR(key, ATTR, skey, FUNC); \
- if (mask) { \
- SCAN_PUT_ATTR(mask, ATTR, smask, FUNC); \
- } \
- }
+ SCAN_PUT_ATTR(key, ATTR, skey, FUNC); \
+ if (mask) \
+ SCAN_PUT_ATTR(mask, ATTR, smask, FUNC); \
#define SCAN_END(ATTR) \
SCAN_FINISH(); \
SCAN_FIELD_NESTED("tun_id=", ovs_be64, be64, OVS_TUNNEL_KEY_ATTR_ID);
SCAN_FIELD_NESTED("src=", ovs_be32, ipv4, OVS_TUNNEL_KEY_ATTR_IPV4_SRC);
SCAN_FIELD_NESTED("dst=", ovs_be32, ipv4, OVS_TUNNEL_KEY_ATTR_IPV4_DST);
+ SCAN_FIELD_NESTED("ipv6_src=", struct in6_addr, in6_addr, OVS_TUNNEL_KEY_ATTR_IPV6_SRC);
+ SCAN_FIELD_NESTED("ipv6_dst=", struct in6_addr, in6_addr, OVS_TUNNEL_KEY_ATTR_IPV6_DST);
SCAN_FIELD_NESTED("tos=", uint8_t, u8, OVS_TUNNEL_KEY_ATTR_TOS);
SCAN_FIELD_NESTED("ttl=", uint8_t, u8, OVS_TUNNEL_KEY_ATTR_TTL);
SCAN_FIELD_NESTED("tp_src=", ovs_be16, be16, OVS_TUNNEL_KEY_ATTR_TP_SRC);
nl_msg_put_u32(buf, OVS_KEY_ATTR_PRIORITY, data->skb_priority);
- if (flow->tunnel.ip_dst || export_mask) {
+ if (flow_tnl_dst_is_set(&flow->tunnel) || export_mask) {
tun_key_to_attr(buf, &data->tunnel, &parms->flow->tunnel,
parms->key_buf);
}
if (flow->tp_dst == htons(0)
&& (flow->tp_src == htons(ND_NEIGHBOR_SOLICIT)
|| flow->tp_src == htons(ND_NEIGHBOR_ADVERT))
- && (!export_mask || (data->tp_src == htons(0xffff)
- && data->tp_dst == htons(0xffff)))) {
+ /* Even though 'tp_src' and 'tp_dst' are 16 bits wide, ICMP
+ * type and code are 8 bits wide. Therefore, an exact match
+ * looks like htons(0xff), not htons(0xffff). See
+ * xlate_wc_finish() for details. */
+ && (!export_mask || (data->tp_src == htons(0xff)
+ && data->tp_dst == htons(0xff)))) {
struct ovs_key_nd *nd_key;
{
nl_msg_put_u32(buf, OVS_KEY_ATTR_PRIORITY, md->skb_priority);
- if (md->tunnel.ip_dst) {
+ if (flow_tnl_dst_is_set(&md->tunnel)) {
tun_key_to_attr(buf, &md->tunnel, &md->tunnel, NULL);
}
odp_flow_key_hash(const struct nlattr *key, size_t key_len)
{
BUILD_ASSERT_DECL(!(NLA_ALIGNTO % sizeof(uint32_t)));
- return hash_words(ALIGNED_CAST(const uint32_t *, key),
- key_len / sizeof(uint32_t), 0);
+ return hash_bytes32(ALIGNED_CAST(const uint32_t *, key), key_len, 0);
}
static void
flow->arp_sha = nd_key->nd_sll;
flow->arp_tha = nd_key->nd_tll;
if (is_mask) {
+ /* Even though 'tp_src' and 'tp_dst' are 16 bits wide,
+ * ICMP type and code are 8 bits wide. Therefore, an
+ * exact match looks like htons(0xff), not
+ * htons(0xffff). See xlate_wc_finish() for details.
+ * */
if (!is_all_zeros(nd_key, sizeof *nd_key) &&
- (flow->tp_src != htons(0xffff) ||
- flow->tp_dst != htons(0xffff))) {
+ (flow->tp_src != htons(0xff) ||
+ flow->tp_dst != htons(0xff))) {
return ODP_FIT_ERROR;
} else {
expected_attrs |= UINT64_C(1) << OVS_KEY_ATTR_ND;
return odp_flow_key_to_flow__(key, key_len, NULL, 0, flow, flow, false);
}
+static enum odp_key_fitness
+odp_flow_key_to_mask__(const struct nlattr *mask_key, size_t mask_key_len,
+ const struct nlattr *flow_key, size_t flow_key_len,
+ struct flow_wildcards *mask,
+ const struct flow *src_flow,
+ bool udpif)
+{
+ if (mask_key_len) {
+ return odp_flow_key_to_flow__(mask_key, mask_key_len,
+ flow_key, flow_key_len,
+ &mask->masks, src_flow, udpif);
+
+ } else {
+ /* A missing mask means that the flow should be exact matched.
+ * Generate an appropriate exact wildcard for the flow. */
+ flow_wildcards_init_for_packet(mask, src_flow);
+
+ return ODP_FIT_PERFECT;
+ }
+}
/* Converts the 'mask_key_len' bytes of OVS_KEY_ATTR_* attributes in 'mask_key'
* to a mask structure in 'mask'. 'flow' must be a previously translated flow
* corresponding to 'mask' and similarly flow_key/flow_key_len must be the
enum odp_key_fitness
odp_flow_key_to_mask(const struct nlattr *mask_key, size_t mask_key_len,
const struct nlattr *flow_key, size_t flow_key_len,
- struct flow *mask, const struct flow *flow)
+ struct flow_wildcards *mask, const struct flow *flow)
{
- return odp_flow_key_to_flow__(mask_key, mask_key_len, flow_key, flow_key_len,
- mask, flow, false);
+ return odp_flow_key_to_mask__(mask_key, mask_key_len,
+ flow_key, flow_key_len,
+ mask, flow, false);
}
/* These functions are similar to their non-"_udpif" variants but output a
enum odp_key_fitness
odp_flow_key_to_mask_udpif(const struct nlattr *mask_key, size_t mask_key_len,
const struct nlattr *flow_key, size_t flow_key_len,
- struct flow *mask, const struct flow *flow)
+ struct flow_wildcards *mask,
+ const struct flow *flow)
{
- return odp_flow_key_to_flow__(mask_key, mask_key_len, flow_key, flow_key_len,
- mask, flow, true);
+ return odp_flow_key_to_mask__(mask_key, mask_key_len,
+ flow_key, flow_key_len,
+ mask, flow, true);
}
/* Returns 'fitness' as a string, for use in debug messages. */
commit_odp_tunnel_action(const struct flow *flow, struct flow *base,
struct ofpbuf *odp_actions)
{
- /* A valid IPV4_TUNNEL must have non-zero ip_dst. */
- if (flow->tunnel.ip_dst) {
+ /* A valid IPV4_TUNNEL must have non-zero ip_dst; a valid IPv6 tunnel
+ * must have non-zero ipv6_dst. */
+ if (flow_tnl_dst_is_set(&flow->tunnel)) {
if (!memcmp(&base->tunnel, &flow->tunnel, sizeof base->tunnel)) {
return;
}
struct ovs_key_icmp key, mask, base;
enum ovs_key_attr attr;
+ if (is_icmpv4(flow)) {
+ attr = OVS_KEY_ATTR_ICMP;
+ } else if (is_icmpv6(flow)) {
+ attr = OVS_KEY_ATTR_ICMPV6;
+ } else {
+ return 0;
+ }
+
get_icmp_key(flow, &key);
get_icmp_key(base_flow, &base);
get_icmp_key(&wc->masks, &mask);
- attr = flow->dl_type == htons(ETH_TYPE_IP) ? OVS_KEY_ATTR_ICMP
- : OVS_KEY_ATTR_ICMPV6;
if (commit(attr, false, &key, &base, &mask, sizeof key, odp_actions)) {
put_icmp_key(&base, base_flow);
put_icmp_key(&mask, &wc->masks);