spin_unlock(&flow->lock);
}
-struct sw_flow_actions *ovs_flow_actions_alloc(const struct nlattr *actions)
+struct sw_flow_actions *ovs_flow_actions_alloc(int size)
{
- int actions_len = nla_len(actions);
struct sw_flow_actions *sfa;
- if (actions_len > MAX_ACTIONS_BUFSIZE)
+ if (size > MAX_ACTIONS_BUFSIZE)
return ERR_PTR(-EINVAL);
- sfa = kmalloc(sizeof(*sfa) + actions_len, GFP_KERNEL);
+ sfa = kmalloc(sizeof(*sfa) + size, GFP_KERNEL);
if (!sfa)
return ERR_PTR(-ENOMEM);
- sfa->actions_len = actions_len;
- memcpy(sfa->actions, nla_data(actions), actions_len);
+ sfa->actions_len = 0;
return sfa;
}
key->phy.priority = skb->priority;
if (OVS_CB(skb)->tun_key)
- memcpy(&key->phy.tun.tun_key, OVS_CB(skb)->tun_key, sizeof(key->phy.tun.tun_key));
+ memcpy(&key->tun_key, OVS_CB(skb)->tun_key, sizeof(key->tun_key));
key->phy.in_port = in_port;
+ key->phy.skb_mark = skb_get_mark(skb);
skb_reset_mac_header(skb);
static int flow_key_start(struct sw_flow_key *key)
{
- if (key->phy.tun.tun_key.ipv4_dst)
+ if (key->tun_key.ipv4_dst)
return 0;
else
- return offsetof(struct sw_flow_key, phy.priority);
+ return offsetof(struct sw_flow_key, phy);
}
struct sw_flow *ovs_flow_tbl_lookup(struct flow_table *table,
[OVS_KEY_ATTR_ENCAP] = -1,
[OVS_KEY_ATTR_PRIORITY] = sizeof(u32),
[OVS_KEY_ATTR_IN_PORT] = sizeof(u32),
+ [OVS_KEY_ATTR_SKB_MARK] = sizeof(u32),
[OVS_KEY_ATTR_ETHERNET] = sizeof(struct ovs_key_ethernet),
[OVS_KEY_ATTR_VLAN] = sizeof(__be16),
[OVS_KEY_ATTR_ETHERTYPE] = sizeof(__be16),
[OVS_KEY_ATTR_ICMPV6] = sizeof(struct ovs_key_icmpv6),
[OVS_KEY_ATTR_ARP] = sizeof(struct ovs_key_arp),
[OVS_KEY_ATTR_ND] = sizeof(struct ovs_key_nd),
+ [OVS_KEY_ATTR_TUNNEL] = -1,
/* Not upstream. */
[OVS_KEY_ATTR_TUN_ID] = sizeof(__be64),
- [OVS_KEY_ATTR_IPV4_TUNNEL] = sizeof(struct ovs_key_ipv4_tunnel),
};
static int ipv4_flow_from_nlattrs(struct sw_flow_key *swkey, int *key_len,
return 0;
}
+int ipv4_tun_from_nlattr(const struct nlattr *attr,
+ struct ovs_key_ipv4_tunnel *tun_key)
+{
+ struct nlattr *a;
+ int rem;
+ bool ttl = false;
+
+ memset(tun_key, 0, sizeof(*tun_key));
+
+ nla_for_each_nested(a, attr, rem) {
+ int type = nla_type(a);
+ static const u32 ovs_tunnel_key_lens[OVS_TUNNEL_KEY_ATTR_MAX + 1] = {
+ [OVS_TUNNEL_KEY_ATTR_ID] = sizeof(u64),
+ [OVS_TUNNEL_KEY_ATTR_IPV4_SRC] = sizeof(u32),
+ [OVS_TUNNEL_KEY_ATTR_IPV4_DST] = sizeof(u32),
+ [OVS_TUNNEL_KEY_ATTR_TOS] = 1,
+ [OVS_TUNNEL_KEY_ATTR_TTL] = 1,
+ [OVS_TUNNEL_KEY_ATTR_DONT_FRAGMENT] = 0,
+ [OVS_TUNNEL_KEY_ATTR_CSUM] = 0,
+ };
+
+ if (type > OVS_TUNNEL_KEY_ATTR_MAX ||
+ ovs_tunnel_key_lens[type] != nla_len(a))
+ return -EINVAL;
+
+ switch (type) {
+ case OVS_TUNNEL_KEY_ATTR_ID:
+ tun_key->tun_id = nla_get_be64(a);
+ tun_key->tun_flags |= OVS_TNL_F_KEY;
+ break;
+ case OVS_TUNNEL_KEY_ATTR_IPV4_SRC:
+ tun_key->ipv4_src = nla_get_be32(a);
+ break;
+ case OVS_TUNNEL_KEY_ATTR_IPV4_DST:
+ tun_key->ipv4_dst = nla_get_be32(a);
+ break;
+ case OVS_TUNNEL_KEY_ATTR_TOS:
+ tun_key->ipv4_tos = nla_get_u8(a);
+ break;
+ case OVS_TUNNEL_KEY_ATTR_TTL:
+ tun_key->ipv4_ttl = nla_get_u8(a);
+ ttl = true;
+ break;
+ case OVS_TUNNEL_KEY_ATTR_DONT_FRAGMENT:
+ tun_key->tun_flags |= OVS_TNL_F_DONT_FRAGMENT;
+ break;
+ case OVS_TUNNEL_KEY_ATTR_CSUM:
+ tun_key->tun_flags |= OVS_TNL_F_CSUM;
+ break;
+ default:
+ return -EINVAL;
+
+ }
+ }
+ if (rem > 0)
+ return -EINVAL;
+
+ if (!tun_key->ipv4_dst)
+ return -EINVAL;
+
+ if (!ttl)
+ return -EINVAL;
+
+ return 0;
+}
+
+int ipv4_tun_to_nlattr(struct sk_buff *skb,
+ const struct ovs_key_ipv4_tunnel *tun_key)
+{
+ struct nlattr *nla;
+
+ nla = nla_nest_start(skb, OVS_KEY_ATTR_TUNNEL);
+ if (!nla)
+ return -EMSGSIZE;
+
+ if (tun_key->tun_flags & OVS_TNL_F_KEY &&
+ nla_put_be64(skb, OVS_TUNNEL_KEY_ATTR_ID, tun_key->tun_id))
+ return -EMSGSIZE;
+ if (tun_key->ipv4_src &&
+ nla_put_be32(skb, OVS_TUNNEL_KEY_ATTR_IPV4_SRC, tun_key->ipv4_src))
+ return -EMSGSIZE;
+ if (nla_put_be32(skb, OVS_TUNNEL_KEY_ATTR_IPV4_DST, tun_key->ipv4_dst))
+ return -EMSGSIZE;
+ if (tun_key->ipv4_tos &&
+ nla_put_u8(skb, OVS_TUNNEL_KEY_ATTR_TOS, tun_key->ipv4_tos))
+ return -EMSGSIZE;
+ if (nla_put_u8(skb, OVS_TUNNEL_KEY_ATTR_TTL, tun_key->ipv4_ttl))
+ return -EMSGSIZE;
+ if ((tun_key->tun_flags & OVS_TNL_F_DONT_FRAGMENT) &&
+ nla_put_flag(skb, OVS_TUNNEL_KEY_ATTR_DONT_FRAGMENT))
+ return -EMSGSIZE;
+ if ((tun_key->tun_flags & OVS_TNL_F_CSUM) &&
+ nla_put_flag(skb, OVS_TUNNEL_KEY_ATTR_CSUM))
+ return -EMSGSIZE;
+
+ nla_nest_end(skb, nla);
+ return 0;
+}
+
/**
* ovs_flow_from_nlattrs - parses Netlink attributes into a flow key.
* @swkey: receives the extracted flow key.
} else {
swkey->phy.in_port = DP_MAX_PORTS;
}
+ if (attrs & (1 << OVS_KEY_ATTR_SKB_MARK)) {
+ uint32_t mark = nla_get_u32(a[OVS_KEY_ATTR_SKB_MARK]);
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) && !defined(CONFIG_NETFILTER)
+ if (mark != 0)
+ return -EINVAL;
+#endif
+ swkey->phy.skb_mark = mark;
+ attrs &= ~(1 << OVS_KEY_ATTR_SKB_MARK);
+ }
if (attrs & (1ULL << OVS_KEY_ATTR_TUN_ID) &&
- attrs & (1ULL << OVS_KEY_ATTR_IPV4_TUNNEL)) {
- struct ovs_key_ipv4_tunnel *tun_key;
+ attrs & (1ULL << OVS_KEY_ATTR_TUNNEL)) {
__be64 tun_id;
- tun_key = nla_data(a[OVS_KEY_ATTR_IPV4_TUNNEL]);
+ err = ipv4_tun_from_nlattr(a[OVS_KEY_ATTR_TUNNEL], &swkey->tun_key);
+ if (err)
+ return err;
- if (!tun_key->ipv4_dst)
- return -EINVAL;
- if (!(tun_key->tun_flags & OVS_FLOW_TNL_F_KEY))
+ if (!(swkey->tun_key.tun_flags & OVS_TNL_F_KEY))
return -EINVAL;
tun_id = nla_get_be64(a[OVS_KEY_ATTR_TUN_ID]);
- if (tun_id != tun_key->tun_id)
+ if (tun_id != swkey->tun_key.tun_id)
return -EINVAL;
- memcpy(&swkey->phy.tun.tun_key, tun_key, sizeof(swkey->phy.tun.tun_key));
attrs &= ~(1ULL << OVS_KEY_ATTR_TUN_ID);
- attrs &= ~(1ULL << OVS_KEY_ATTR_IPV4_TUNNEL);
- } else if (attrs & (1ULL << OVS_KEY_ATTR_TUN_ID)) {
- swkey->phy.tun.tun_key.tun_id = nla_get_be64(a[OVS_KEY_ATTR_TUN_ID]);
- swkey->phy.tun.tun_key.tun_flags |= OVS_FLOW_TNL_F_KEY;
+ attrs &= ~(1ULL << OVS_KEY_ATTR_TUNNEL);
+ } else if (attrs & (1ULL << OVS_KEY_ATTR_TUNNEL)) {
- attrs &= ~(1ULL << OVS_KEY_ATTR_TUN_ID);
- } else if (attrs & (1ULL << OVS_KEY_ATTR_IPV4_TUNNEL)) {
- struct ovs_key_ipv4_tunnel *tun_key;
- tun_key = nla_data(a[OVS_KEY_ATTR_IPV4_TUNNEL]);
+ err = ipv4_tun_from_nlattr(a[OVS_KEY_ATTR_TUNNEL], &swkey->tun_key);
+ if (err)
+ return err;
- if (!tun_key->ipv4_dst)
- return -EINVAL;
-
- memcpy(&swkey->phy.tun.tun_key, tun_key, sizeof(swkey->phy.tun.tun_key));
- attrs &= ~(1ULL << OVS_KEY_ATTR_IPV4_TUNNEL);
+ attrs &= ~(1ULL << OVS_KEY_ATTR_TUNNEL);
}
/* Data attributes. */
int ovs_flow_metadata_from_nlattrs(struct sw_flow *flow, int key_len, const struct nlattr *attr)
{
- struct ovs_key_ipv4_tunnel *tun_key = &flow->key.phy.tun.tun_key;
+ struct ovs_key_ipv4_tunnel *tun_key = &flow->key.tun_key;
const struct nlattr *nla;
int rem;
__be64 tun_id = 0;
flow->key.phy.in_port = DP_MAX_PORTS;
flow->key.phy.priority = 0;
- memset(tun_key, 0, sizeof(flow->key.phy.tun.tun_key));
+ flow->key.phy.skb_mark = 0;
+ memset(tun_key, 0, sizeof(flow->key.tun_key));
nla_for_each_nested(nla, attr, rem) {
int type = nla_type(nla);
if (type <= OVS_KEY_ATTR_MAX && ovs_key_lens[type] > 0) {
+ int err;
+
if (nla_len(nla) != ovs_key_lens[type])
return -EINVAL;
tun_id = nla_get_be64(nla);
if (tun_key->ipv4_dst) {
- if (!(tun_key->tun_flags & OVS_FLOW_TNL_F_KEY))
+ if (!(tun_key->tun_flags & OVS_TNL_F_KEY))
return -EINVAL;
if (tun_key->tun_id != tun_id)
return -EINVAL;
break;
}
tun_key->tun_id = tun_id;
- tun_key->tun_flags |= OVS_FLOW_TNL_F_KEY;
+ tun_key->tun_flags |= OVS_TNL_F_KEY;
break;
- case OVS_KEY_ATTR_IPV4_TUNNEL:
- if (tun_key->tun_flags & OVS_FLOW_TNL_F_KEY) {
+ case OVS_KEY_ATTR_TUNNEL:
+ if (tun_key->tun_flags & OVS_TNL_F_KEY) {
tun_id = tun_key->tun_id;
+ err = ipv4_tun_from_nlattr(nla, tun_key);
+ if (err)
+ return err;
- memcpy(tun_key, nla_data(nla), sizeof(*tun_key));
- if (!(tun_key->tun_flags & OVS_FLOW_TNL_F_KEY))
+ if (!(tun_key->tun_flags & OVS_TNL_F_KEY))
return -EINVAL;
if (tun_key->tun_id != tun_id)
return -EINVAL;
- } else
- memcpy(tun_key, nla_data(nla), sizeof(*tun_key));
-
- if (!tun_key->ipv4_dst)
- return -EINVAL;
+ } else {
+ err = ipv4_tun_from_nlattr(nla, tun_key);
+ if (err)
+ return err;
+ }
break;
case OVS_KEY_ATTR_IN_PORT:
return -EINVAL;
flow->key.phy.in_port = nla_get_u32(nla);
break;
+
+ case OVS_KEY_ATTR_SKB_MARK:
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) && !defined(CONFIG_NETFILTER)
+ if (nla_get_u32(nla) != 0)
+ return -EINVAL;
+#endif
+ flow->key.phy.skb_mark = nla_get_u32(nla);
+ break;
}
}
}
nla_put_u32(skb, OVS_KEY_ATTR_PRIORITY, swkey->phy.priority))
goto nla_put_failure;
- if (swkey->phy.tun.tun_key.ipv4_dst) {
- struct ovs_key_ipv4_tunnel *tun_key;
- nla = nla_reserve(skb, OVS_KEY_ATTR_IPV4_TUNNEL, sizeof(*tun_key));
- if (!nla)
- goto nla_put_failure;
- tun_key = nla_data(nla);
- memcpy(tun_key, &swkey->phy.tun.tun_key, sizeof(*tun_key));
- }
- if ((swkey->phy.tun.tun_key.tun_flags & OVS_FLOW_TNL_F_KEY) &&
- nla_put_be64(skb, OVS_KEY_ATTR_TUN_ID, swkey->phy.tun.tun_key.tun_id))
+ if (swkey->tun_key.ipv4_dst &&
+ ipv4_tun_to_nlattr(skb, &swkey->tun_key))
+ goto nla_put_failure;
+
+ if ((swkey->tun_key.tun_flags & OVS_TNL_F_KEY) &&
+ nla_put_be64(skb, OVS_KEY_ATTR_TUN_ID, swkey->tun_key.tun_id))
goto nla_put_failure;
if (swkey->phy.in_port != DP_MAX_PORTS &&
nla_put_u32(skb, OVS_KEY_ATTR_IN_PORT, swkey->phy.in_port))
goto nla_put_failure;
+ if (swkey->phy.skb_mark &&
+ nla_put_u32(skb, OVS_KEY_ATTR_SKB_MARK, swkey->phy.skb_mark))
+ goto nla_put_failure;
+
nla = nla_reserve(skb, OVS_KEY_ATTR_ETHERNET, sizeof(*eth_key));
if (!nla)
goto nla_put_failure;