aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2015-09-01 18:06:24 -0400
committerDavid S. Miller <davem@davemloft.net>2015-09-01 18:06:24 -0400
commit41ecc3d390266acc1aa911d2ec477928a5248f75 (patch)
treeaf5886ed49d500ad34a2d0a8d69e92c6d3cf84fe
parentd3d11fe08ccc9bff174fc958722b5661f0932486 (diff)
parent6db61d79c1e1b2346e2142d6c950a8d2e8380b82 (diff)
Merge branch 'flow-dissector-features'
Tom Herbert says: ==================== flow_dissector: Paramterize dissection and other features This patch set adds some new capabilities to flow_dissector: - Add flags to flow dissector functions to control dissection - Flag to stop dissection when L3 header is seen (don't dissect L4) - Flag to stop dissection when encapsulation is detected - Flag to parse first fragment of fragmented packet. This may provide L4 ports - Added new reporting in key_control - Packet is a fragment - Packet is a first fragment - Packet has encapsulation Also: - Make __skb_set_sw_hash a general function - Create functions to get a flow hash based on flowi4 or flowi6 structures without an reference to an skbuff - Ignore flow dissector return value from ___skb_get_hash. Just use whatever key fields are found to make a hash Tested: Ran 200 netperf TCP_RR instances for IPv6 and IPv4. Did not see any regression. Ran UDP_RR with 10000 byte request and response size for IPv4 and IPv6, no regression observed however I did see better performance with IPv6 flow labels due to use of flow labels for L4 hash. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/net/bonding/bond_main.c2
-rw-r--r--drivers/net/ethernet/cisco/enic/enic_clsf.c2
-rw-r--r--drivers/net/hyperv/netvsc_drv.c2
-rw-r--r--include/linux/skbuff.h113
-rw-r--r--include/net/flow.h19
-rw-r--r--include/net/flow_dissector.h65
-rw-r--r--net/core/flow.c36
-rw-r--r--net/core/flow_dissector.c146
-rw-r--r--net/ethernet/eth.c2
-rw-r--r--net/sched/cls_flow.c2
-rw-r--r--net/sched/cls_flower.c2
-rw-r--r--net/sched/sch_choke.c4
12 files changed, 267 insertions, 128 deletions
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index 06e2d01f0b4e..771a449d2f56 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -3095,7 +3095,7 @@ static bool bond_flow_dissect(struct bonding *bond, struct sk_buff *skb,
3095 int noff, proto = -1; 3095 int noff, proto = -1;
3096 3096
3097 if (bond->params.xmit_policy > BOND_XMIT_POLICY_LAYER23) 3097 if (bond->params.xmit_policy > BOND_XMIT_POLICY_LAYER23)
3098 return skb_flow_dissect_flow_keys(skb, fk); 3098 return skb_flow_dissect_flow_keys(skb, fk, 0);
3099 3099
3100 fk->ports.ports = 0; 3100 fk->ports.ports = 0;
3101 noff = skb_network_offset(skb); 3101 noff = skb_network_offset(skb);
diff --git a/drivers/net/ethernet/cisco/enic/enic_clsf.c b/drivers/net/ethernet/cisco/enic/enic_clsf.c
index d106186f4f4a..3c677ed3c29e 100644
--- a/drivers/net/ethernet/cisco/enic/enic_clsf.c
+++ b/drivers/net/ethernet/cisco/enic/enic_clsf.c
@@ -177,7 +177,7 @@ int enic_rx_flow_steer(struct net_device *dev, const struct sk_buff *skb,
177 int res, i; 177 int res, i;
178 178
179 enic = netdev_priv(dev); 179 enic = netdev_priv(dev);
180 res = skb_flow_dissect_flow_keys(skb, &keys); 180 res = skb_flow_dissect_flow_keys(skb, &keys, 0);
181 if (!res || keys.basic.n_proto != htons(ETH_P_IP) || 181 if (!res || keys.basic.n_proto != htons(ETH_P_IP) ||
182 (keys.basic.ip_proto != IPPROTO_TCP && 182 (keys.basic.ip_proto != IPPROTO_TCP &&
183 keys.basic.ip_proto != IPPROTO_UDP)) 183 keys.basic.ip_proto != IPPROTO_UDP))
diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c
index 2990024b90f9..409b48e1e589 100644
--- a/drivers/net/hyperv/netvsc_drv.c
+++ b/drivers/net/hyperv/netvsc_drv.c
@@ -239,7 +239,7 @@ static bool netvsc_set_hash(u32 *hash, struct sk_buff *skb)
239 struct flow_keys flow; 239 struct flow_keys flow;
240 int data_len; 240 int data_len;
241 241
242 if (!skb_flow_dissect_flow_keys(skb, &flow) || 242 if (!skb_flow_dissect_flow_keys(skb, &flow, 0) ||
243 !(flow.basic.n_proto == htons(ETH_P_IP) || 243 !(flow.basic.n_proto == htons(ETH_P_IP) ||
244 flow.basic.n_proto == htons(ETH_P_IPV6))) 244 flow.basic.n_proto == htons(ETH_P_IPV6)))
245 return false; 245 return false;
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
index 989307f991db..9e62687c70f3 100644
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -937,14 +937,90 @@ enum pkt_hash_types {
937 PKT_HASH_TYPE_L4, /* Input: src_IP, dst_IP, src_port, dst_port */ 937 PKT_HASH_TYPE_L4, /* Input: src_IP, dst_IP, src_port, dst_port */
938}; 938};
939 939
940static inline void 940static inline void skb_clear_hash(struct sk_buff *skb)
941skb_set_hash(struct sk_buff *skb, __u32 hash, enum pkt_hash_types type)
942{ 941{
943 skb->l4_hash = (type == PKT_HASH_TYPE_L4); 942 skb->hash = 0;
944 skb->sw_hash = 0; 943 skb->sw_hash = 0;
944 skb->l4_hash = 0;
945}
946
947static inline void skb_clear_hash_if_not_l4(struct sk_buff *skb)
948{
949 if (!skb->l4_hash)
950 skb_clear_hash(skb);
951}
952
953static inline void
954__skb_set_hash(struct sk_buff *skb, __u32 hash, bool is_sw, bool is_l4)
955{
956 skb->l4_hash = is_l4;
957 skb->sw_hash = is_sw;
945 skb->hash = hash; 958 skb->hash = hash;
946} 959}
947 960
961static inline void
962skb_set_hash(struct sk_buff *skb, __u32 hash, enum pkt_hash_types type)
963{
964 /* Used by drivers to set hash from HW */
965 __skb_set_hash(skb, hash, false, type == PKT_HASH_TYPE_L4);
966}
967
968static inline void
969__skb_set_sw_hash(struct sk_buff *skb, __u32 hash, bool is_l4)
970{
971 __skb_set_hash(skb, hash, true, is_l4);
972}
973
974void __skb_get_hash(struct sk_buff *skb);
975u32 skb_get_poff(const struct sk_buff *skb);
976u32 __skb_get_poff(const struct sk_buff *skb, void *data,
977 const struct flow_keys *keys, int hlen);
978__be32 __skb_flow_get_ports(const struct sk_buff *skb, int thoff, u8 ip_proto,
979 void *data, int hlen_proto);
980
981static inline __be32 skb_flow_get_ports(const struct sk_buff *skb,
982 int thoff, u8 ip_proto)
983{
984 return __skb_flow_get_ports(skb, thoff, ip_proto, NULL, 0);
985}
986
987void skb_flow_dissector_init(struct flow_dissector *flow_dissector,
988 const struct flow_dissector_key *key,
989 unsigned int key_count);
990
991bool __skb_flow_dissect(const struct sk_buff *skb,
992 struct flow_dissector *flow_dissector,
993 void *target_container,
994 void *data, __be16 proto, int nhoff, int hlen,
995 unsigned int flags);
996
997static inline bool skb_flow_dissect(const struct sk_buff *skb,
998 struct flow_dissector *flow_dissector,
999 void *target_container, unsigned int flags)
1000{
1001 return __skb_flow_dissect(skb, flow_dissector, target_container,
1002 NULL, 0, 0, 0, flags);
1003}
1004
1005static inline bool skb_flow_dissect_flow_keys(const struct sk_buff *skb,
1006 struct flow_keys *flow,
1007 unsigned int flags)
1008{
1009 memset(flow, 0, sizeof(*flow));
1010 return __skb_flow_dissect(skb, &flow_keys_dissector, flow,
1011 NULL, 0, 0, 0, flags);
1012}
1013
1014static inline bool skb_flow_dissect_flow_keys_buf(struct flow_keys *flow,
1015 void *data, __be16 proto,
1016 int nhoff, int hlen,
1017 unsigned int flags)
1018{
1019 memset(flow, 0, sizeof(*flow));
1020 return __skb_flow_dissect(NULL, &flow_keys_buf_dissector, flow,
1021 data, proto, nhoff, hlen, flags);
1022}
1023
948static inline __u32 skb_get_hash(struct sk_buff *skb) 1024static inline __u32 skb_get_hash(struct sk_buff *skb)
949{ 1025{
950 if (!skb->l4_hash && !skb->sw_hash) 1026 if (!skb->l4_hash && !skb->sw_hash)
@@ -957,8 +1033,12 @@ __u32 __skb_get_hash_flowi6(struct sk_buff *skb, struct flowi6 *fl6);
957 1033
958static inline __u32 skb_get_hash_flowi6(struct sk_buff *skb, struct flowi6 *fl6) 1034static inline __u32 skb_get_hash_flowi6(struct sk_buff *skb, struct flowi6 *fl6)
959{ 1035{
960 if (!skb->l4_hash && !skb->sw_hash) 1036 if (!skb->l4_hash && !skb->sw_hash) {
961 __skb_get_hash_flowi6(skb, fl6); 1037 struct flow_keys keys;
1038
1039 __skb_set_sw_hash(skb, __get_hash_from_flowi6(fl6, &keys),
1040 flow_keys_have_l4(&keys));
1041 }
962 1042
963 return skb->hash; 1043 return skb->hash;
964} 1044}
@@ -967,8 +1047,12 @@ __u32 __skb_get_hash_flowi4(struct sk_buff *skb, struct flowi4 *fl);
967 1047
968static inline __u32 skb_get_hash_flowi4(struct sk_buff *skb, struct flowi4 *fl4) 1048static inline __u32 skb_get_hash_flowi4(struct sk_buff *skb, struct flowi4 *fl4)
969{ 1049{
970 if (!skb->l4_hash && !skb->sw_hash) 1050 if (!skb->l4_hash && !skb->sw_hash) {
971 __skb_get_hash_flowi4(skb, fl4); 1051 struct flow_keys keys;
1052
1053 __skb_set_sw_hash(skb, __get_hash_from_flowi4(fl4, &keys),
1054 flow_keys_have_l4(&keys));
1055 }
972 1056
973 return skb->hash; 1057 return skb->hash;
974} 1058}
@@ -980,19 +1064,6 @@ static inline __u32 skb_get_hash_raw(const struct sk_buff *skb)
980 return skb->hash; 1064 return skb->hash;
981} 1065}
982 1066
983static inline void skb_clear_hash(struct sk_buff *skb)
984{
985 skb->hash = 0;
986 skb->sw_hash = 0;
987 skb->l4_hash = 0;
988}
989
990static inline void skb_clear_hash_if_not_l4(struct sk_buff *skb)