This patch adds support for skb mark matching and set action. Signed-off-by: Ansis Atteka <aatt...@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 _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev