aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnsis Atteka <aatteka@nicira.com>2012-11-13 19:19:36 +0200
committerAnsis Atteka <aatteka@nicira.com>2012-11-21 16:19:59 -0800
commiteabbb4b74c5ae1f2828e54473be04d576fdf6d9f (patch)
treef1d2d606a72aa19d432e159b6c7b67f8aaeec343
parentf6ce12891513c082972f91a80b17d63dfae115b6 (diff)
datapath: add skb mark matching and set action
This patch adds support for skb mark matching and set action. Acked-by: Jesse Gross <jesse@nicira.com> Signed-off-by: Ansis Atteka <aatteka@nicira.com> Conflicts: datapath/flow.c lib/dpif-netdev.c lib/flow.h lib/odp-util.c ofproto/ofproto-dpif.c
-rw-r--r--NEWS4
-rw-r--r--datapath/actions.c4
-rw-r--r--datapath/compat.h33
-rw-r--r--datapath/datapath.c8
-rw-r--r--datapath/flow.c24
-rw-r--r--datapath/flow.h6
-rw-r--r--debian/changelog4
-rw-r--r--include/linux/openvswitch.h1
-rw-r--r--lib/dpif-linux.c2
-rw-r--r--lib/dpif-netdev.c5
-rw-r--r--lib/flow.c5
-rw-r--r--lib/flow.h11
-rw-r--r--lib/learning-switch.c2
-rw-r--r--lib/match.c3
-rw-r--r--lib/nx-match.c2
-rw-r--r--lib/odp-util.c38
-rw-r--r--lib/odp-util.h5
-rw-r--r--lib/ofp-print.c2
-rw-r--r--lib/ofp-util.c4
-rw-r--r--ofproto/ofproto-dpif.c18
-rw-r--r--ofproto/ofproto-unixctl.man4
-rw-r--r--ofproto/ofproto.c4
-rw-r--r--tests/odp.at1
-rw-r--r--tests/test-flows.c2
24 files changed, 158 insertions, 34 deletions
diff --git a/NEWS b/NEWS
index 293ef506..15ab54ff 100644
--- a/NEWS
+++ b/NEWS
@@ -3,7 +3,9 @@ v1.9.0 - xx xxx xxxx
- The tunneling code no longer assumes input and output keys are symmetric.
If they are not, PMTUD needs to be disabled for tunneling to work. Note
this only applies to flow-based keys.
- - Datapath: Support for ipv6 set action.
+ - Datapath:
+ - Support for ipv6 set action.
+ - SKB mark matching and setting.
- FreeBSD is now a supported platform, thanks to code contributions from
Gaetano Catalli, Ed Maste, and Giuseppe Lettieri.
- ovs-bugtool: New --ovs option to report only OVS related information.
diff --git a/datapath/actions.c b/datapath/actions.c
index 76c9823a..faa6a002 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 3113b961..3b8d577e 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 e359ac03..c9485ca7 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 fdfe3e94..65d6cce9 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->phy.tun.tun_key, OVS_CB(skb)->tun_key, sizeof(key->phy.tun.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)) {
@@ -1205,6 +1216,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.phy.tun.tun_key));
nla_for_each_nested(nla, attr, rem) {
@@ -1256,6 +1268,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;
}
}
}
@@ -1293,6 +1313,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 8bc6db6f..f97ec086 100644
--- a/datapath/flow.h
+++ b/datapath/flow.h
@@ -46,6 +46,7 @@ struct sw_flow_key {
struct ovs_key_ipv4_tunnel tun_key; /* Encapsulating tunnel key. */
} tun;
u32 priority; /* Packet QoS priority. */
+ u32 skb_mark; /* SKB mark. */
u16 in_port; /* Input switch port (or DP_MAX_PORTS). */
} phy;
struct {
@@ -149,6 +150,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
@@ -158,9 +160,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/debian/changelog b/debian/changelog
index 51915c8f..736411d9 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -4,7 +4,9 @@ openvswitch (1.9.0-1) unstable; urgency=low
- The tunneling code no longer assumes input and output keys are symmetric.
If they are not, PMTUD needs to be disabled for tunneling to work. Note
this only applies to flow-based keys.
- - Datapath: Support for ipv6 set action.
+ - Datapath:
+ - Support for ipv6 set action.
+ - SKB mark matching and setting.
- FreeBSD is now a supported platform, thanks to code contributions from
Gaetano Catalli, Ed Maste, and Giuseppe Lettieri.
- ovs-bugtool: New --ovs option to report only OVS related information.
diff --git a/include/linux/openvswitch.h b/include/linux/openvswitch.h
index c4823d9f..e7d4b495 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-linux.c b/lib/dpif-linux.c
index 3a4a4e6d..a058ee7f 100644
--- a/lib/dpif-linux.c
+++ b/lib/dpif-linux.c
@@ -1399,7 +1399,7 @@ dpif_linux_vport_send(int dp_ifindex, uint32_t port_no,
uint64_t action;
ofpbuf_use_const(&packet, data, size);
- flow_extract(&packet, 0, NULL, 0, &flow);
+ flow_extract(&packet, 0, 0, NULL, 0, &flow);
ofpbuf_use_stack(&key, &keybuf, sizeof keybuf);
odp_flow_key_from_flow(&key, &flow);
diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c
index 43839769..ff5e1872 100644
--- a/lib/dpif-netdev.c
+++ b/lib/dpif-netdev.c
@@ -916,7 +916,7 @@ dpif_netdev_execute(struct dpif *dpif, const struct dpif_execute *execute)
ofpbuf_reserve(&copy, DP_NETDEV_HEADROOM);
ofpbuf_put(&copy, execute->packet->data, execute->packet->size);
- flow_extract(&copy, 0, NULL, -1, &key);
+ flow_extract(&copy, 0, 0, NULL, -1, &key);
error = dpif_netdev_flow_from_nlattrs(execute->key, execute->key_len,
&key);
if (!error) {
@@ -1014,7 +1014,7 @@ dp_netdev_port_input(struct dp_netdev *dp, struct dp_netdev_port *port,
if (packet->size < ETH_HEADER_LEN) {
return;
}
- flow_extract(packet, 0, NULL, odp_port_to_ofp_port(port->port_no), &key);
+ flow_extract(packet, 0, 0, NULL, odp_port_to_ofp_port(port->port_no), &key);
flow = dp_netdev_lookup_flow(dp, &key);
if (flow) {
dp_netdev_flow_used(flow, packet);
@@ -1179,6 +1179,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 5f520048..f886ff21 100644
--- a/lib/flow.c
+++ b/lib/flow.c
@@ -335,7 +335,7 @@ invalid:
* present and has a correct length, and otherwise NULL.
*/
void
-flow_extract(struct ofpbuf *packet, uint32_t skb_priority,
+flow_extract(struct ofpbuf *packet, uint32_t skb_priority, uint32_t skb_mark,
const struct flow_tnl *tnl, uint16_t ofp_in_port,
struct flow *flow)
{
@@ -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 = skb_mark;
packet->l2 = b.data;
packet->l3 = NULL;
@@ -462,7 +463,7 @@ flow_zero_wildcards(struct flow *flow, const struct flow_wildcards *wildcards)
void
flow_get_metadata(const struct flow *flow, struct flow_metadata *fmd)
{
- BUILD_ASSERT_DECL(FLOW_WC_SEQ == 17);
+ BUILD_ASSERT_DECL(FLOW_WC_SEQ == 18);
fmd->tun_id = flow->tunnel.tun_id;
fmd->metadata = flow->metadata;
diff --git a/lib/flow.h b/lib/flow.h
index 9388f20a..e4c648d7 100644
--- a/lib/flow.h
+++ b/lib/flow.h
@@ -36,7 +36,7 @@ struct ofpbuf;
/* This sequence number should be incremented whenever anything involving flows
* or the wildcarding of flows changes. This will cause build assertion
* failures in places which likely need to be updated. */
-#define FLOW_WC_SEQ 17
+#define FLOW_WC_SEQ 18
#define FLOW_N_REGS 8
BUILD_ASSERT_DECL(FLOW_N_REGS <= NXM_NX_MAX_REGS);
@@ -77,6 +77,7 @@ struct flow {
ovs_be32 nw_dst; /* IPv4 destination address. */
ovs_be32 ipv6_label; /* IPv6 flow label. */
uint16_t in_port; /* OpenFlow port number of input port. */
+ 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. */
@@ -96,8 +97,8 @@ 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 &&
- FLOW_WC_SEQ == 17);
+BUILD_ASSERT_DECL(sizeof(struct flow) == sizeof(struct flow_tnl) + 152 &&
+ FLOW_WC_SEQ == 18);
/* Represents the metadata fields of struct flow. */
struct flow_metadata {
@@ -107,8 +108,8 @@ struct flow_metadata {
uint16_t in_port; /* OpenFlow port or zero. */
};
-void flow_extract(struct ofpbuf *, uint32_t priority, const struct flow_tnl *,
- uint16_t in_port, struct flow *);
+void flow_extract(struct ofpbuf *, uint32_t priority, uint32_t mark,
+ const struct flow_tnl *, uint16_t in_port, struct flow *);
void flow_zero_wildcards(struct flow *, const struct flow_wildcards *);
void flow_get_metadata(const struct flow *, struct flow_metadata *);
diff --git a/lib/learning-switch.c b/lib/learning-switch.c
index 7a60f3c3..9f08da55 100644
--- a/lib/learning-switch.c
+++ b/lib/learning-switch.c
@@ -535,7 +535,7 @@ process_packet_in(struct lswitch *sw, const struct ofp_header *oh)
/* Extract flow data from 'opi' into 'flow'. */
ofpbuf_use_const(&pkt, pi.packet, pi.packet_len);
- flow_extract(&pkt, 0, NULL, pi.fmd.in_port, &flow);
+ flow_extract(&pkt, 0, 0, NULL, pi.fmd.in_port, &flow);
flow.tunnel.tun_id = pi.fmd.tun_id;
/* Choose output port. */
diff --git a/lib/match.c b/lib/match.c
index 81b71734..29ee1535 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);
@@ -655,7 +656,7 @@ match_format(const struct match *match, struct ds *s, unsigned int priority)
int i;
- BUILD_ASSERT_DECL(FLOW_WC_SEQ == 17);
+ BUILD_ASSERT_DECL(FLOW_WC_SEQ == 18);
if (priority != OFP_DEFAULT_PRIORITY) {
ds_put_format(s, "priority=%u,", priority);
diff --git a/lib/nx-match.c b/lib/nx-match.c
index 9c4088f1..837db8d3 100644
--- a/lib/nx-match.c
+++ b/lib/nx-match.c
@@ -547,7 +547,7 @@ nx_put_raw(struct ofpbuf *b, bool oxm, const struct match *match,
int match_len;
int i;
- BUILD_ASSERT_DECL(FLOW_WC_SEQ == 17);
+ BUILD_ASSERT_DECL(FLOW_WC_SEQ == 18);
/* Metadata. */
if (match->wc.masks.in_port) {
diff --git a/lib/odp-util.c b/lib/odp-util.c
index 28944a00..39d4e34d 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";
@@ -644,6 +645,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;
@@ -754,6 +756,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;
@@ -973,6 +979,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;
@@ -1372,6 +1388,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 (flow->in_port != OFPP_NONE && flow->in_port != OFPP_CONTROLLER) {
nl_msg_put_u32(buf, OVS_KEY_ATTR_IN_PORT,
ofp_port_to_odp_port(flow->in_port));
@@ -1862,6 +1882,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;
@@ -2128,6 +2153,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. */
@@ -2141,4 +2178,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 57073bad..6bc37f21 100644
--- a/lib/odp-util.h
+++ b/lib/odp-util.h
@@ -82,6 +82,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
@@ -91,12 +92,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 256
/* 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/lib/ofp-print.c b/lib/ofp-print.c
index cafc665d..39a041f8 100644
--- a/lib/ofp-print.c
+++ b/lib/ofp-print.c
@@ -63,7 +63,7 @@ ofp_packet_to_string(const void *data, size_t len)
struct flow flow;
ofpbuf_use_const(&buf, data, len);
- flow_extract(&buf, 0, NULL, 0, &flow);
+ flow_extract(&buf, 0, 0, NULL, 0, &flow);
flow_format(&ds, &flow);
if (buf.l7) {
diff --git a/lib/ofp-util.c b/lib/ofp-util.c
index b8147686..f828fcac 100644
--- a/lib/ofp-util.c
+++ b/lib/ofp-util.c
@@ -84,7 +84,7 @@ ofputil_netmask_to_wcbits(ovs_be32 netmask)
void
ofputil_wildcard_from_ofpfw10(uint32_t ofpfw, struct flow_wildcards *wc)
{
- BUILD_ASSERT_DECL(FLOW_WC_SEQ == 17);
+ BUILD_ASSERT_DECL(FLOW_WC_SEQ == 18);
/* Initialize most of wc. */
flow_wildcards_init_catchall(wc);
@@ -901,7 +901,7 @@ ofputil_usable_protocols(const struct match *match)
{
const struct flow_wildcards *wc = &match->wc;
- BUILD_ASSERT_DECL(FLOW_WC_SEQ == 17);
+ BUILD_ASSERT_DECL(FLOW_WC_SEQ == 18);
/* NXM and OF1.1+ supports bitwise matching on ethernet addresses. */
if (!eth_mask_is_exact(wc->masks.dl_src)
diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c
index 30147b4c..ef4f5002 100644
--- a/ofproto/ofproto-dpif.c
+++ b/ofproto/ofproto-dpif.c
@@ -3117,7 +3117,7 @@ handle_miss_upcalls(struct ofproto_dpif *ofproto, struct dpif_upcall *upcalls,
if (miss->key_fitness == ODP_FIT_ERROR) {
continue;
}
- flow_extract(upcall->packet, flow.skb_priority,
+ flow_extract(upcall->packet, flow.skb_priority, flow.skb_mark,
&flow.tunnel, flow.in_port, &miss->flow);
/* Add other packets to a to-do list. */
@@ -4764,7 +4764,7 @@ send_packet(const struct ofport_dpif *ofport, struct ofpbuf *packet)
struct flow flow;
int error;
- flow_extract(packet, 0, NULL, 0, &flow);
+ flow_extract(packet, 0, 0, NULL, 0, &flow);
odp_port = vsp_realdev_to_vlandev(ofproto, ofport->odp_port,
flow.vlan_tci);
if (odp_port != ofport->odp_port) {
@@ -6784,15 +6784,17 @@ ofproto_unixctl_trace(struct unixctl_conn *conn, int argc, const char *argv[],
packet = ofpbuf_new(0);
flow_compose(packet, &flow);
}
- } else if (argc == 6) {
- /* ofproto/trace dpname priority tun_id in_port packet */
+ } else if (argc == 7) {
+ /* ofproto/trace dpname priority tun_id in_port mark packet */
const char *priority_s = argv[2];
const char *tun_id_s = argv[3];
const char *in_port_s = argv[4];
- const char *packet_s = argv[5];
+ const char *mark_s = argv[5];
+ const char *packet_s = argv[6];
uint16_t in_port = ofp_port_to_odp_port(atoi(in_port_s));
ovs_be64 tun_id = htonll(strtoull(tun_id_s, NULL, 0));
uint32_t priority = atoi(priority_s);
+ uint32_t mark = atoi(mark_s);
const char *msg;
msg = eth_from_hex(packet_s, &packet);
@@ -6806,7 +6808,7 @@ ofproto_unixctl_trace(struct unixctl_conn *conn, int argc, const char *argv[],
ds_put_cstr(&result, s);
free(s);
- flow_extract(packet, priority, NULL, in_port, &flow);
+ flow_extract(packet, priority, mark, NULL, in_port, &flow);
flow.tunnel.tun_id = tun_id;
initial_tci = flow.vlan_tci;
} else {
@@ -6995,8 +6997,8 @@ ofproto_dpif_unixctl_init(void)
unixctl_command_register(
"ofproto/trace",
- "bridge {priority tun_id in_port packet | odp_flow [-generate]}",
- 2, 5, ofproto_unixctl_trace, NULL);
+ "bridge {priority tun_id in_port mark packet | odp_flow [-generate]}",
+ 2, 6, ofproto_unixctl_trace, NULL);
unixctl_command_register("fdb/flush", "[bridge]", 0, 1,
ofproto_unixctl_fdb_flush, NULL);
unixctl_command_register("fdb/show", "bridge", 1, 1,
diff --git a/ofproto/ofproto-unixctl.man b/ofproto/ofproto-unixctl.man
index 3e36fe63..88903436 100644
--- a/ofproto/ofproto-unixctl.man
+++ b/ofproto/ofproto-unixctl.man
@@ -6,7 +6,7 @@ These commands manage the core OpenFlow switch implementation (called
Lists the names of the running ofproto instances. These are the names
that may be used on \fBofproto/trace\fR.
.
-.IP "\fBofproto/trace \fIswitch priority tun_id in_port packet\fR"
+.IP "\fBofproto/trace \fIswitch priority tun_id in_port mark packet\fR"
.IQ "\fBofproto/trace \fIswitch flow \fB\-generate\fR"
Traces the path of an imaginary packet through \fIswitch\fR. Both
forms require \fIswitch\fR, the switch on which the packet arrived
@@ -21,6 +21,8 @@ The tunnel ID on which the packet arrived. Use
.IP "\fIin_port\fR"
The OpenFlow port on which the packet arrived. Use \fB65534\fR if the
packet arrived on \fBOFPP_LOCAL\fR, the local port.
+.IP "\fImark\fR"
+SKB mark of the packet. Use \fB0\fR if Netfilter marks are not used.
.IP "\fIpacket\fR"
A sequence of hex digits specifying the packet's contents. An
Ethernet frame is at least 14 bytes long, so there must be at least 28
diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c
index 2fb2fc87..5bc6ee94 100644
--- a/ofproto/ofproto.c
+++ b/ofproto/ofproto.c
@@ -1970,7 +1970,7 @@ rule_execute(struct rule *rule, uint16_t in_port, struct ofpbuf *packet)
assert(ofpbuf_headroom(packet) >= sizeof(struct ofp_packet_in));
- flow_extract(packet, 0, NULL, in_port, &flow);
+ flow_extract(packet, 0, 0, NULL, in_port, &flow);
return rule->ofproto->ofproto_class->rule_execute(rule, &flow, packet);
}
@@ -2147,7 +2147,7 @@ handle_packet_out(struct ofconn *ofconn, const struct ofp_header *oh)
}
/* Verify actions against packet, then send packet if successful. */
- flow_extract(payload, 0, NULL, po.in_port, &flow);
+ flow_extract(payload, 0, 0, NULL, po.in_port, &flow);
error = ofpacts_check(po.ofpacts, po.ofpacts_len, &flow, p->max_ports);
if (!error) {
error = p->ofproto_class->packet_out(p, payload, &flow,
diff --git a/tests/odp.at b/tests/odp.at
index 8f5676d6..a5f6dbe5 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.'
diff --git a/tests/test-flows.c b/tests/test-flows.c
index a40709a1..b4dedeeb 100644
--- a/tests/test-flows.c
+++ b/tests/test-flows.c
@@ -68,7 +68,7 @@ main(int argc OVS_UNUSED, char *argv[])
ovs_fatal(retval, "error reading pcap file");
}
- flow_extract(packet, 0, NULL, 1, &flow);
+ flow_extract(packet, 0, 0, NULL, 1, &flow);
match_init_exact(&match, &flow);
ofputil_match_to_ofp10_match(&match, &extracted_match);