This patch adds support for skb mark matching and set action.
Signed-off-by: Ansis Atteka <[email protected]>
---
datapath/actions.c | 4 ++++
datapath/compat.h | 33 +++++++++++++++++++++++++++++++++
datapath/datapath.c | 8 ++++++++
datapath/flow.c | 24 ++++++++++++++++++++++++
datapath/flow.h | 6 ++++--
include/linux/openvswitch.h | 1 +
lib/dpif-netdev.c | 1 +
lib/flow.c | 1 +
lib/flow.h | 3 ++-
lib/match.c | 1 +
lib/odp-util.c | 38 ++++++++++++++++++++++++++++++++++++++
lib/odp-util.h | 5 +++--
tests/odp.at | 1 +
13 files changed, 121 insertions(+), 5 deletions(-)
diff --git a/datapath/actions.c b/datapath/actions.c
index 76c9823..faa6a00 100644
--- a/datapath/actions.c
+++ b/datapath/actions.c
@@ -435,6 +435,10 @@ static int execute_set_action(struct sk_buff *skb,
skb->priority = nla_get_u32(nested_attr);
break;
+ case OVS_KEY_ATTR_SKB_MARK:
+ skb_set_mark(skb, nla_get_u32(nested_attr));
+ break;
+
case OVS_KEY_ATTR_TUN_ID:
/* If we're only using the TUN_ID action, store the value in a
* temporary instance of struct ovs_key_ipv4_tunnel on the
stack.
diff --git a/datapath/compat.h b/datapath/compat.h
index 3113b96..3b8d577 100644
--- a/datapath/compat.h
+++ b/datapath/compat.h
@@ -81,4 +81,37 @@ static inline void skb_clear_rxhash(struct sk_buff *skb)
#define SET_NETNSOK .netnsok = true,
#endif
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
+#ifdef CONFIG_NETFILTER
+static inline u32 skb_get_mark(struct sk_buff *skb)
+{
+ return skb->nfmark;
+}
+
+static inline void skb_set_mark(struct sk_buff *skb, u32 mark)
+{
+ skb->nfmark = mark;
+}
+#else /* CONFIG_NETFILTER */
+static inline u32 skb_get_mark(struct sk_buff *skb)
+{
+ return 0;
+}
+
+static inline void skb_set_mark(struct sk_buff *skb, u32 mark)
+{
+}
+#endif
+#else /* before 2.6.20 */
+static inline u32 skb_get_mark(struct sk_buff *skb)
+{
+ return skb->mark;
+}
+
+static inline void skb_set_mark(struct sk_buff *skb, u32 mark)
+{
+ skb->mark = mark;
+}
+#endif /* after 2.6.20 */
+
#endif /* compat.h */
diff --git a/datapath/datapath.c b/datapath/datapath.c
index e359ac0..c9485ca 100644
--- a/datapath/datapath.c
+++ b/datapath/datapath.c
@@ -595,6 +595,13 @@ static int validate_set(const struct nlattr *a,
case OVS_KEY_ATTR_ETHERNET:
break;
+ case OVS_KEY_ATTR_SKB_MARK:
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) && !defined(CONFIG_NETFILTER)
+ if (nla_get_u32(ovs_key) != 0)
+ return -EINVAL;
+#endif
+ break;
+
case OVS_KEY_ATTR_IPV4_TUNNEL:
tun_key = nla_data(ovs_key);
if (!tun_key->ipv4_dst)
@@ -826,6 +833,7 @@ static int ovs_packet_cmd_execute(struct sk_buff *skb,
struct genl_info *info)
OVS_CB(packet)->flow = flow;
packet->priority = flow->key.phy.priority;
+ skb_set_mark(packet, flow->key.phy.skb_mark);
rcu_read_lock();
dp = get_dp(sock_net(skb->sk), ovs_header->dp_ifindex);
diff --git a/datapath/flow.c b/datapath/flow.c
index 41c624e..0c3d75f 100644
--- a/datapath/flow.c
+++ b/datapath/flow.c
@@ -624,6 +624,7 @@ int ovs_flow_extract(struct sk_buff *skb, u16 in_port,
struct sw_flow_key *key,
if (OVS_CB(skb)->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);
@@ -835,6 +836,7 @@ const int ovs_key_lens[OVS_KEY_ATTR_MAX + 1] = {
[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),
@@ -1024,6 +1026,15 @@ int ovs_flow_from_nlattrs(struct sw_flow_key *swkey, int
*key_lenp,
} 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)) {
@@ -1203,6 +1214,7 @@ int ovs_flow_metadata_from_nlattrs(struct sw_flow *flow,
int key_len, const stru
flow->key.phy.in_port = DP_MAX_PORTS;
flow->key.phy.priority = 0;
+ flow->key.phy.skb_mark = 0;
memset(tun_key, 0, sizeof(flow->key.tun_key));
nla_for_each_nested(nla, attr, rem) {
@@ -1254,6 +1266,14 @@ int ovs_flow_metadata_from_nlattrs(struct sw_flow *flow,
int key_len, const stru
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;
}
}
}
@@ -1291,6 +1311,10 @@ int ovs_flow_to_nlattrs(const struct sw_flow_key *swkey,
struct sk_buff *skb)
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;
diff --git a/datapath/flow.h b/datapath/flow.h
index 54f0fcd..3f3624f 100644
--- a/datapath/flow.h
+++ b/datapath/flow.h
@@ -44,6 +44,7 @@ struct sw_flow_key {
struct ovs_key_ipv4_tunnel tun_key; /* Encapsulating tunnel key. */
struct {
u32 priority; /* Packet QoS priority. */
+ u32 skb_mark; /* SKB mark. */
u16 in_port; /* Input switch port (or DP_MAX_PORTS).
*/
} phy;
struct {
@@ -147,6 +148,7 @@ u64 ovs_flow_used_time(unsigned long flow_jiffies);
* OVS_KEY_ATTR_TUN_ID 8 -- 4 12
* OVS_KEY_ATTR_IPV4_TUNNEL 24 -- 4 28
* OVS_KEY_ATTR_IN_PORT 4 -- 4 8
+ * OVS_KEY_ATTR_SKB_MARK 4 -- 4 8
* OVS_KEY_ATTR_ETHERNET 12 -- 4 16
* OVS_KEY_ATTR_ETHERTYPE 2 2 4 8 (outer VLAN ethertype)
* OVS_KEY_ATTR_8021Q 4 -- 4 8
@@ -156,9 +158,9 @@ u64 ovs_flow_used_time(unsigned long flow_jiffies);
* OVS_KEY_ATTR_ICMPV6 2 2 4 8
* OVS_KEY_ATTR_ND 28 -- 4 32
* -------------------------------------------------
- * total 184
+ * total 192
*/
-#define FLOW_BUFSIZE 184
+#define FLOW_BUFSIZE 192
int ovs_flow_to_nlattrs(const struct sw_flow_key *, struct sk_buff *);
int ovs_flow_from_nlattrs(struct sw_flow_key *swkey, int *key_lenp,
diff --git a/include/linux/openvswitch.h b/include/linux/openvswitch.h
index c4823d9..e7d4b49 100644
--- a/include/linux/openvswitch.h
+++ b/include/linux/openvswitch.h
@@ -280,6 +280,7 @@ enum ovs_key_attr {
OVS_KEY_ATTR_ICMPV6, /* struct ovs_key_icmpv6 */
OVS_KEY_ATTR_ARP, /* struct ovs_key_arp */
OVS_KEY_ATTR_ND, /* struct ovs_key_nd */
+ OVS_KEY_ATTR_SKB_MARK, /* u32 skb mark */
OVS_KEY_ATTR_IPV4_TUNNEL, /* struct ovs_key_ipv4_tunnel */
OVS_KEY_ATTR_TUN_ID = 63, /* be64 tunnel ID */
__OVS_KEY_ATTR_MAX
diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c
index 4ce4147..f920371 100644
--- a/lib/dpif-netdev.c
+++ b/lib/dpif-netdev.c
@@ -1188,6 +1188,7 @@ execute_set_action(struct ofpbuf *packet, const struct
nlattr *a)
switch (type) {
case OVS_KEY_ATTR_TUN_ID:
case OVS_KEY_ATTR_PRIORITY:
+ case OVS_KEY_ATTR_SKB_MARK:
case OVS_KEY_ATTR_IPV4_TUNNEL:
/* not implemented */
break;
diff --git a/lib/flow.c b/lib/flow.c
index 7084079..816d561 100644
--- a/lib/flow.c
+++ b/lib/flow.c
@@ -352,6 +352,7 @@ flow_extract(struct ofpbuf *packet, uint32_t skb_priority,
}
flow->in_port = ofp_in_port;
flow->skb_priority = skb_priority;
+ flow->skb_mark = 0;
packet->l2 = b.data;
packet->l3 = NULL;
diff --git a/lib/flow.h b/lib/flow.h
index 5f4b8cb..40a6a98 100644
--- a/lib/flow.h
+++ b/lib/flow.h
@@ -87,6 +87,7 @@ struct flow {
uint32_t in_port; /* Input port. OpenFlow port number
unless in DPIF code, in which case it
is the datapath port number. */
+ uint32_t skb_mark; /* Packet mark. */
ovs_be16 vlan_tci; /* If 802.1Q, TCI | VLAN_CFI; otherwise 0. */
ovs_be16 dl_type; /* Ethernet frame type. */
ovs_be16 tp_src; /* TCP/UDP source port. */
@@ -105,7 +106,7 @@ BUILD_ASSERT_DECL(sizeof(struct flow) % 4 == 0);
#define FLOW_U32S (sizeof(struct flow) / 4)
/* Remember to update FLOW_WC_SEQ when changing 'struct flow'. */
-BUILD_ASSERT_DECL(sizeof(struct flow) == sizeof(struct flow_tnl) + 144 &&
+BUILD_ASSERT_DECL(sizeof(struct flow) == sizeof(struct flow_tnl) + 152 &&
FLOW_WC_SEQ == 17);
/* Represents the metadata fields of struct flow. */
diff --git a/lib/match.c b/lib/match.c
index 81b7173..6943df2 100644
--- a/lib/match.c
+++ b/lib/match.c
@@ -125,6 +125,7 @@ match_init_exact(struct match *match, const struct flow
*flow)
match->flow = *flow;
match->flow.skb_priority = 0;
+ match->flow.skb_mark = 0;
memset(&match->flow.tunnel, 0, sizeof match->flow.tunnel);
match->flow.tunnel.tun_id = tun_id;
flow_wildcards_init_exact(&match->wc);
diff --git a/lib/odp-util.c b/lib/odp-util.c
index 08823e2..b3cad6c 100644
--- a/lib/odp-util.c
+++ b/lib/odp-util.c
@@ -93,6 +93,7 @@ ovs_key_attr_to_string(enum ovs_key_attr attr)
case OVS_KEY_ATTR_UNSPEC: return "unspec";
case OVS_KEY_ATTR_ENCAP: return "encap";
case OVS_KEY_ATTR_PRIORITY: return "priority";
+ case OVS_KEY_ATTR_SKB_MARK: return "skb_mark";
case OVS_KEY_ATTR_TUN_ID: return "tun_id";
case OVS_KEY_ATTR_IPV4_TUNNEL: return "ipv4_tunnel";
case OVS_KEY_ATTR_IN_PORT: return "in_port";
@@ -602,6 +603,7 @@ odp_flow_key_attr_len(uint16_t type)
switch ((enum ovs_key_attr) type) {
case OVS_KEY_ATTR_ENCAP: return -2;
case OVS_KEY_ATTR_PRIORITY: return 4;
+ case OVS_KEY_ATTR_SKB_MARK: return 4;
case OVS_KEY_ATTR_TUN_ID: return 8;
case OVS_KEY_ATTR_IPV4_TUNNEL: return sizeof(struct ovs_key_ipv4_tunnel);
case OVS_KEY_ATTR_IN_PORT: return 4;
@@ -697,6 +699,10 @@ format_odp_key_attr(const struct nlattr *a, struct ds *ds)
ds_put_format(ds, "(%"PRIu32")", nl_attr_get_u32(a));
break;
+ case OVS_KEY_ATTR_SKB_MARK:
+ ds_put_format(ds, "(%"PRIu32")", nl_attr_get_u32(a));
+ break;
+
case OVS_KEY_ATTR_TUN_ID:
ds_put_format(ds, "(%#"PRIx64")", ntohll(nl_attr_get_be64(a)));
break;
@@ -913,6 +919,16 @@ parse_odp_key_attr(const char *s, const struct simap
*port_names,
}
{
+ unsigned long long int mark;
+ int n = -1;
+
+ if (sscanf(s, "skb_mark(%lli)%n", &mark, &n) > 0 && n > 0) {
+ nl_msg_put_u32(key, OVS_KEY_ATTR_SKB_MARK, mark);
+ return n;
+ }
+ }
+
+ {
char tun_id_s[32];
int n = -1;
@@ -1306,6 +1322,10 @@ odp_flow_key_from_flow(struct ofpbuf *buf, const struct
flow *flow,
nl_msg_put_be64(buf, OVS_KEY_ATTR_TUN_ID, flow->tunnel.tun_id);
}
+ if (flow->skb_mark) {
+ nl_msg_put_u32(buf, OVS_KEY_ATTR_SKB_MARK, flow->skb_mark);
+ }
+
if (odp_in_port != OVSP_NONE) {
nl_msg_put_u32(buf, OVS_KEY_ATTR_IN_PORT, odp_in_port);
}
@@ -1798,6 +1818,11 @@ odp_flow_key_to_flow(const struct nlattr *key, size_t
key_len,
expected_attrs |= UINT64_C(1) << OVS_KEY_ATTR_PRIORITY;
}
+ if (present_attrs & (UINT64_C(1) << OVS_KEY_ATTR_SKB_MARK)) {
+ flow->skb_mark = nl_attr_get_u32(attrs[OVS_KEY_ATTR_SKB_MARK]);
+ expected_attrs |= UINT64_C(1) << OVS_KEY_ATTR_SKB_MARK;
+ }
+
if (present_attrs & (UINT64_C(1) << OVS_KEY_ATTR_TUN_ID)) {
flow->tunnel.tun_id = nl_attr_get_be64(attrs[OVS_KEY_ATTR_TUN_ID]);
expected_attrs |= UINT64_C(1) << OVS_KEY_ATTR_TUN_ID;
@@ -2058,6 +2083,18 @@ commit_set_priority_action(const struct flow *flow,
struct flow *base,
&base->skb_priority, sizeof(base->skb_priority));
}
+static void
+commit_set_skb_mark_action(const struct flow *flow, struct flow *base,
+ struct ofpbuf *odp_actions)
+{
+ if (base->skb_mark == flow->skb_mark) {
+ return;
+ }
+ base->skb_mark = flow->skb_mark;
+
+ commit_set_action(odp_actions, OVS_KEY_ATTR_SKB_MARK,
+ &base->skb_mark, sizeof(base->skb_mark));
+}
/* If any of the flow key data that ODP actions can modify are different in
* 'base' and 'flow', appends ODP actions to 'odp_actions' that change the flow
* key from 'base' into 'flow', and then changes 'base' the same way. */
@@ -2071,4 +2108,5 @@ commit_odp_actions(const struct flow *flow, struct flow
*base,
commit_set_nw_action(flow, base, odp_actions);
commit_set_port_action(flow, base, odp_actions);
commit_set_priority_action(flow, base, odp_actions);
+ commit_set_skb_mark_action(flow, base, odp_actions);
}
diff --git a/lib/odp-util.h b/lib/odp-util.h
index 5cdb204..0214a8b 100644
--- a/lib/odp-util.h
+++ b/lib/odp-util.h
@@ -56,6 +56,7 @@ int odp_actions_from_string(const char *, const struct simap
*port_names,
* OVS_KEY_ATTR_TUN_ID 8 -- 4 12
* OVS_KEY_ATTR_IPV4_TUNNEL 24 -- 4 28
* OVS_KEY_ATTR_IN_PORT 4 -- 4 8
+ * OVS_KEY_ATTR_SKB_MARK 4 -- 4 8
* OVS_KEY_ATTR_ETHERNET 12 -- 4 16
* OVS_KEY_ATTR_ETHERTYPE 2 2 4 8 (outer VLAN ethertype)
* OVS_KEY_ATTR_8021Q 4 -- 4 8
@@ -65,12 +66,12 @@ int odp_actions_from_string(const char *, const struct
simap *port_names,
* OVS_KEY_ATTR_ICMPV6 2 2 4 8
* OVS_KEY_ATTR_ND 28 -- 4 32
* -------------------------------------------------
- * total 184
+ * total 192
*
* We include some slack space in case the calculation isn't quite right or we
* add another field and forget to adjust this value.
*/
-#define ODPUTIL_FLOW_KEY_BYTES 200
+#define ODPUTIL_FLOW_KEY_BYTES 208
/* A buffer with sufficient size and alignment to hold an nlattr-formatted flow
* key. An array of "struct nlattr" might not, in theory, be sufficiently
diff --git a/tests/odp.at b/tests/odp.at
index 505e4c8..fa4224a 100644
--- a/tests/odp.at
+++ b/tests/odp.at
@@ -24,6 +24,7 @@
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=58,tclass=0,hlimit=128,frag=no),icmpv6(type=136,code=0),nd(target=::3,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(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(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)
+skb_mark(17185),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)
])
(echo '# Valid forms without tun_id or VLAN header.'
--
1.7.9.5
_______________________________________________
dev mailing list
[email protected]
http://openvswitch.org/mailman/listinfo/dev