/*
- * 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.
IP_ARGS(get_16aligned_be32(&ip->ip_dst)),
ip->ip_proto, ip->ip_tos,
ip->ip_ttl,
- ip->ip_frag_off);
+ ntohs(ip->ip_frag_off));
l4 = (ip + 1);
} else {
const struct ip6_hdr *ip6;
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
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->ip_frag_off)) {
+ &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];
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;
}
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(); \
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;
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. */
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);