[ovs-dev] [PATCHv2] datapath: add skb mark matching and set action

Ansis Atteka aatteka at nicira.com
Thu Nov 15 19:07:52 UTC 2012


This patch adds support for skb mark matching and set action.

Signed-off-by: Ansis Atteka <aatteka at nicira.com>
---
 datapath/actions.c          |    4 ++++
 datapath/compat.h           |   33 +++++++++++++++++++++++++++++++++
 datapath/datapath.c         |    7 +++++++
 datapath/flow.c             |   15 +++++++++++++++
 datapath/flow.h             |    6 ++++--
 include/linux/openvswitch.h |    1 +
 lib/dpif-netdev.c           |    1 +
 lib/flow.h                  |    3 ++-
 lib/odp-util.c              |   38 ++++++++++++++++++++++++++++++++++++++
 9 files changed, 105 insertions(+), 3 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..778f8e3 100644
--- a/datapath/datapath.c
+++ b/datapath/datapath.c
@@ -595,6 +595,12 @@ 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)
+		return -EINVAL;
+#endif
+		break;
+
 	case OVS_KEY_ATTR_IPV4_TUNNEL:
 		tun_key = nla_data(ovs_key);
 		if (!tun_key->ipv4_dst)
@@ -826,6 +832,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..d82fa9c 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,10 @@ 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)) {
+		swkey->phy.skb_mark = nla_get_u32(a[OVS_KEY_ATTR_SKB_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 +1209,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 +1261,10 @@ 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:
+				flow->key.phy.skb_mark = nla_get_u32(nla);
+				break;
 			}
 		}
 	}
@@ -1291,6 +1302,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.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/odp-util.c b/lib/odp-util.c
index 08823e2..6aedbc2 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, "(skb_mark=%"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;
 
@@ -1302,6 +1318,10 @@ odp_flow_key_from_flow(struct ofpbuf *buf, const struct flow *flow,
         nl_msg_put_u32(buf, OVS_KEY_ATTR_PRIORITY, flow->skb_priority);
     }
 
+    if (flow->skb_mark) {
+        nl_msg_put_u32(buf, OVS_KEY_ATTR_SKB_MARK, flow->skb_mark);
+    }
+
     if (flow->tunnel.tun_id != htonll(0)) {
         nl_msg_put_be64(buf, OVS_KEY_ATTR_TUN_ID, flow->tunnel.tun_id);
     }
@@ -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);
 }
-- 
1.7.9.5




More information about the dev mailing list