From 72e8bf28bb38e8816435c64859fb350215b6a9e6 Mon Sep 17 00:00:00 2001 From: Ansis Atteka Date: Tue, 13 Nov 2012 19:19:36 +0200 Subject: [PATCH] datapath: add skb mark matching and set action This patch adds support for skb mark matching and set action. Acked-by: Jesse Gross Signed-off-by: Ansis Atteka --- NEWS | 4 +++- datapath/actions.c | 4 ++++ datapath/compat.h | 33 ++++++++++++++++++++++++++++++++ datapath/datapath.c | 8 ++++++++ datapath/flow.c | 24 +++++++++++++++++++++++ datapath/flow.h | 6 ++++-- debian/changelog | 4 +++- include/linux/openvswitch.h | 1 + lib/dpif-linux.c | 2 +- lib/dpif-netdev.c | 5 +++-- lib/flow.c | 5 +++-- lib/flow.h | 11 ++++++----- lib/learning-switch.c | 2 +- lib/match.c | 3 ++- lib/nx-match.c | 2 +- lib/odp-util.c | 38 +++++++++++++++++++++++++++++++++++++ lib/odp-util.h | 5 +++-- lib/ofp-print.c | 2 +- lib/ofp-util.c | 4 ++-- ofproto/ofproto-dpif.c | 18 ++++++++++-------- ofproto/ofproto-unixctl.man | 4 +++- ofproto/ofproto.c | 4 ++-- tests/odp.at | 1 + tests/test-flows.c | 2 +- 24 files changed, 158 insertions(+), 34 deletions(-) diff --git a/NEWS b/NEWS index 03729657..bb80bebf 100644 --- a/NEWS +++ b/NEWS @@ -7,7 +7,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 ade9de53..f990b738 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 41c624e5..0c3d75fd 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 54f0fcdc..3f3624ff 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/debian/changelog b/debian/changelog index b9518fb7..a0359bba 100644 --- a/debian/changelog +++ b/debian/changelog @@ -11,7 +11,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 496230e0..87eb9c18 100644 --- a/lib/dpif-linux.c +++ b/lib/dpif-linux.c @@ -1387,7 +1387,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, OVSP_NONE); diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c index 92108df1..682dfc90 100644 --- a/lib/dpif-netdev.c +++ b/lib/dpif-netdev.c @@ -929,7 +929,7 @@ dpif_netdev_execute(struct dpif *dpif, const struct dpif_execute *execute) ofpbuf_reserve(©, DP_NETDEV_HEADROOM); ofpbuf_put(©, execute->packet->data, execute->packet->size); - flow_extract(©, 0, NULL, -1, &key); + flow_extract(©, 0, 0, NULL, -1, &key); error = dpif_netdev_flow_from_nlattrs(execute->key, execute->key_len, &key); if (!error) { @@ -1027,7 +1027,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, port->port_no, &key); + flow_extract(packet, 0, 0, NULL, port->port_no, &key); flow = dp_netdev_lookup_flow(dp, &key); if (flow) { dp_netdev_flow_used(flow, packet); @@ -1192,6 +1192,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 7084079e..3085848d 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 5f4b8cb5..804fee60 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); @@ -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,8 +106,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 { @@ -116,8 +117,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 eeaa3064..5df05f35 100644 --- a/lib/learning-switch.c +++ b/lib/learning-switch.c @@ -539,7 +539,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 9b0876c4..aa9cb465 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; @@ -972,6 +978,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; @@ -1377,6 +1393,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); } @@ -1869,6 +1889,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; @@ -2129,6 +2154,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. */ @@ -2142,4 +2179,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 5cdb2041..9d38f33f 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 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 c1b50e2c..a0f04dcb 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 e335ff86..fb8d6a1e 100644 --- a/lib/ofp-util.c +++ b/lib/ofp-util.c @@ -85,7 +85,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); @@ -988,7 +988,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, OXM, and OF1.1 support 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 211ed428..d32f6d16 100644 --- a/ofproto/ofproto-dpif.c +++ b/ofproto/ofproto-dpif.c @@ -3491,7 +3491,7 @@ handle_miss_upcalls(struct dpif_backer *backer, 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. */ @@ -5182,7 +5182,7 @@ send_packet(const struct ofport_dpif *ofport, struct ofpbuf *packet) struct flow flow; int error; - flow_extract(packet, 0, NULL, OFPP_LOCAL, &flow); + flow_extract(packet, 0, 0, NULL, OFPP_LOCAL, &flow); odp_port = vsp_realdev_to_vlandev(ofproto, ofport->odp_port, flow.vlan_tci); if (odp_port != ofport->odp_port) { @@ -7214,15 +7214,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]; uint32_t in_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); @@ -7236,7 +7238,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 { @@ -7631,8 +7633,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 8bc9b590..dabb590d 100644 --- a/ofproto/ofproto.c +++ b/ofproto/ofproto.c @@ -2171,7 +2171,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); } @@ -2360,7 +2360,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); -- 2.30.2