From bcc83839ffdb063dd2b0370cd85c4f825761fc59 Mon Sep 17 00:00:00 2001 From: Tom Herbert Date: Tue, 1 Sep 2015 09:24:24 -0700 Subject: skbuff: Make __skb_set_sw_hash a general function Move __skb_set_sw_hash to skbuff.h and add __skb_set_hash which is a common method (between __skb_set_sw_hash and skb_set_hash) to set the hash in an skbuff. Also, move skb_clear_hash to be closer to __skb_set_hash. Signed-off-by: Tom Herbert Signed-off-by: David S. Miller --- net/core/flow_dissector.c | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) (limited to 'net/core/flow_dissector.c') diff --git a/net/core/flow_dissector.c b/net/core/flow_dissector.c index 11e6540fa386..151b6e48b81f 100644 --- a/net/core/flow_dissector.c +++ b/net/core/flow_dissector.c @@ -590,15 +590,6 @@ void make_flow_keys_digest(struct flow_keys_digest *digest, } EXPORT_SYMBOL(make_flow_keys_digest); -static inline void __skb_set_sw_hash(struct sk_buff *skb, u32 hash, - struct flow_keys *keys) -{ - if (keys->ports.ports) - skb->l4_hash = 1; - skb->sw_hash = 1; - skb->hash = hash; -} - /** * __skb_get_hash: calculate a flow hash * @skb: sk_buff to calculate flow hash from @@ -619,7 +610,8 @@ void __skb_get_hash(struct sk_buff *skb) if (!hash) return; - __skb_set_sw_hash(skb, hash, &keys); + __skb_set_sw_hash(skb, hash, + flow_keys_have_l4(&keys)); } EXPORT_SYMBOL(__skb_get_hash); @@ -648,7 +640,8 @@ __u32 __skb_get_hash_flowi6(struct sk_buff *skb, struct flowi6 *fl6) keys.tags.flow_label = (__force u32)fl6->flowlabel; keys.basic.ip_proto = fl6->flowi6_proto; - __skb_set_sw_hash(skb, flow_hash_from_keys(&keys), &keys); + __skb_set_sw_hash(skb, flow_hash_from_keys(&keys), + flow_keys_have_l4(&keys)); return skb->hash; } @@ -668,7 +661,8 @@ __u32 __skb_get_hash_flowi4(struct sk_buff *skb, struct flowi4 *fl4) keys.keyid.keyid = fl4->fl4_gre_key; keys.basic.ip_proto = fl4->flowi4_proto; - __skb_set_sw_hash(skb, flow_hash_from_keys(&keys), &keys); + __skb_set_sw_hash(skb, flow_hash_from_keys(&keys), + flow_keys_have_l4(&keys)); return skb->hash; } -- cgit v1.2.3 From a6e544b0a88b53114bfa5a57e21b7be7a8dfc9d0 Mon Sep 17 00:00:00 2001 From: Tom Herbert Date: Tue, 1 Sep 2015 09:24:26 -0700 Subject: flow_dissector: Jump to exit code in __skb_flow_dissect Instead of returning immediately (on a parsing failure for instance) we jump to cleanup code. This always sets protocol values in key_control (even on a failure there is still valid information in the key_tags that was set before the problem was hit). Signed-off-by: Tom Herbert Signed-off-by: David S. Miller --- net/core/flow_dissector.c | 51 +++++++++++++++++++++++------------------------ 1 file changed, 25 insertions(+), 26 deletions(-) (limited to 'net/core/flow_dissector.c') diff --git a/net/core/flow_dissector.c b/net/core/flow_dissector.c index 151b6e48b81f..22f3d768b459 100644 --- a/net/core/flow_dissector.c +++ b/net/core/flow_dissector.c @@ -130,6 +130,7 @@ bool __skb_flow_dissect(const struct sk_buff *skb, struct flow_dissector_key_tags *key_tags; struct flow_dissector_key_keyid *key_keyid; u8 ip_proto = 0; + bool ret = false; if (!data) { data = skb->data; @@ -171,7 +172,7 @@ again: ip: iph = __skb_header_pointer(skb, nhoff, sizeof(_iph), data, hlen, &_iph); if (!iph || iph->ihl < 5) - return false; + goto out_bad; nhoff += iph->ihl * 4; ip_proto = iph->protocol; @@ -197,7 +198,7 @@ ip: ipv6: iph = __skb_header_pointer(skb, nhoff, sizeof(_iph), data, hlen, &_iph); if (!iph) - return false; + goto out_bad; ip_proto = iph->nexthdr; nhoff += sizeof(struct ipv6hdr); @@ -234,7 +235,7 @@ ipv6: vlan = __skb_header_pointer(skb, nhoff, sizeof(_vlan), data, hlen, &_vlan); if (!vlan) - return false; + goto out_bad; if (skb_flow_dissector_uses_key(flow_dissector, FLOW_DISSECTOR_KEY_VLANID)) { @@ -256,7 +257,7 @@ ipv6: } *hdr, _hdr; hdr = __skb_header_pointer(skb, nhoff, sizeof(_hdr), data, hlen, &_hdr); if (!hdr) - return false; + goto out_bad; proto = hdr->proto; nhoff += PPPOE_SES_HLEN; switch (proto) { @@ -265,7 +266,7 @@ ipv6: case htons(PPP_IPV6): goto ipv6; default: - return false; + goto out_bad; } } case htons(ETH_P_TIPC): { @@ -275,9 +276,7 @@ ipv6: } *hdr, _hdr; hdr = __skb_header_pointer(skb, nhoff, sizeof(_hdr), data, hlen, &_hdr); if (!hdr) - return false; - key_basic->n_proto = proto; - key_control->thoff = (u16)nhoff; + goto out_bad; if (skb_flow_dissector_uses_key(flow_dissector, FLOW_DISSECTOR_KEY_TIPC_ADDRS)) { @@ -287,7 +286,7 @@ ipv6: key_addrs->tipcaddrs.srcnode = hdr->srcnode; key_control->addr_type = FLOW_DISSECTOR_KEY_TIPC_ADDRS; } - return true; + goto out_good; } case htons(ETH_P_MPLS_UC): @@ -297,7 +296,7 @@ mpls: hdr = __skb_header_pointer(skb, nhoff, sizeof(_hdr), data, hlen, &_hdr); if (!hdr) - return false; + goto out_bad; if ((ntohl(hdr[0].entry) & MPLS_LS_LABEL_MASK) >> MPLS_LS_LABEL_SHIFT == MPLS_LABEL_ENTROPY) { @@ -310,21 +309,17 @@ mpls: htonl(MPLS_LS_LABEL_MASK); } - key_basic->n_proto = proto; - key_basic->ip_proto = ip_proto; - key_control->thoff = (u16)nhoff; - - return true; + goto out_good; } - return true; + goto out_good; } case htons(ETH_P_FCOE): key_control->thoff = (u16)(nhoff + FCOE_HEADER_LEN); /* fall through */ default: - return false; + goto out_bad; } ip_proto_again: @@ -337,7 +332,7 @@ ip_proto_again: hdr = __skb_header_pointer(skb, nhoff, sizeof(_hdr), data, hlen, &_hdr); if (!hdr) - return false; + goto out_bad; /* * Only look inside GRE if version zero and no * routing @@ -357,7 +352,7 @@ ip_proto_again: data, hlen, &_keyid); if (!keyid) - return false; + goto out_bad; if (skb_flow_dissector_uses_key(flow_dissector, FLOW_DISSECTOR_KEY_GRE_KEYID)) { @@ -378,7 +373,7 @@ ip_proto_again: sizeof(_eth), data, hlen, &_eth); if (!eth) - return false; + goto out_bad; proto = eth->h_proto; nhoff += sizeof(*eth); } @@ -395,7 +390,7 @@ ip_proto_again: opthdr = __skb_header_pointer(skb, nhoff, sizeof(_opthdr), data, hlen, &_opthdr); if (!opthdr) - return false; + goto out_bad; ip_proto = opthdr[0]; nhoff += (opthdr[1] + 1) << 3; @@ -415,10 +410,6 @@ ip_proto_again: break; } - key_basic->n_proto = proto; - key_basic->ip_proto = ip_proto; - key_control->thoff = (u16)nhoff; - if (skb_flow_dissector_uses_key(flow_dissector, FLOW_DISSECTOR_KEY_PORTS)) { key_ports = skb_flow_dissector_target(flow_dissector, @@ -428,7 +419,15 @@ ip_proto_again: data, hlen); } - return true; +out_good: + ret = true; + +out_bad: + key_basic->n_proto = proto; + key_basic->ip_proto = ip_proto; + key_control->thoff = (u16)nhoff; + + return ret; } EXPORT_SYMBOL(__skb_flow_dissect); -- cgit v1.2.3 From cd79a2382aa5dcefa6e21a7c59bb1bb19e53b74d Mon Sep 17 00:00:00 2001 From: Tom Herbert Date: Tue, 1 Sep 2015 09:24:27 -0700 Subject: flow_dissector: Add flags argument to skb_flow_dissector functions The flags argument will allow control of the dissection process (for instance whether to parse beyond L3). Signed-off-by: Tom Herbert Signed-off-by: David S. Miller --- drivers/net/bonding/bond_main.c | 2 +- drivers/net/ethernet/cisco/enic/enic_clsf.c | 2 +- drivers/net/hyperv/netvsc_drv.c | 2 +- include/linux/skbuff.h | 19 +++++++++++-------- net/core/flow_dissector.c | 7 ++++--- net/ethernet/eth.c | 2 +- net/sched/cls_flow.c | 2 +- net/sched/cls_flower.c | 2 +- net/sched/sch_choke.c | 4 ++-- 9 files changed, 23 insertions(+), 19 deletions(-) (limited to 'net/core/flow_dissector.c') 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, int noff, proto = -1; if (bond->params.xmit_policy > BOND_XMIT_POLICY_LAYER23) - return skb_flow_dissect_flow_keys(skb, fk); + return skb_flow_dissect_flow_keys(skb, fk, 0); fk->ports.ports = 0; 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, int res, i; enic = netdev_priv(dev); - res = skb_flow_dissect_flow_keys(skb, &keys); + res = skb_flow_dissect_flow_keys(skb, &keys, 0); if (!res || keys.basic.n_proto != htons(ETH_P_IP) || (keys.basic.ip_proto != IPPROTO_TCP && 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) struct flow_keys flow; int data_len; - if (!skb_flow_dissect_flow_keys(skb, &flow) || + if (!skb_flow_dissect_flow_keys(skb, &flow, 0) || !(flow.basic.n_proto == htons(ETH_P_IP) || flow.basic.n_proto == htons(ETH_P_IPV6))) return false; diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index bbe41bccfc5f..9e62687c70f3 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -991,31 +991,34 @@ void skb_flow_dissector_init(struct flow_dissector *flow_dissector, bool __skb_flow_dissect(const struct sk_buff *skb, struct flow_dissector *flow_dissector, void *target_container, - void *data, __be16 proto, int nhoff, int hlen); + void *data, __be16 proto, int nhoff, int hlen, + unsigned int flags); static inline bool skb_flow_dissect(const struct sk_buff *skb, struct flow_dissector *flow_dissector, - void *target_container) + void *target_container, unsigned int flags) { return __skb_flow_dissect(skb, flow_dissector, target_container, - NULL, 0, 0, 0); + NULL, 0, 0, 0, flags); } static inline bool skb_flow_dissect_flow_keys(const struct sk_buff *skb, - struct flow_keys *flow) + struct flow_keys *flow, + unsigned int flags) { memset(flow, 0, sizeof(*flow)); return __skb_flow_dissect(skb, &flow_keys_dissector, flow, - NULL, 0, 0, 0); + NULL, 0, 0, 0, flags); } static inline bool skb_flow_dissect_flow_keys_buf(struct flow_keys *flow, void *data, __be16 proto, - int nhoff, int hlen) + int nhoff, int hlen, + unsigned int flags) { memset(flow, 0, sizeof(*flow)); return __skb_flow_dissect(NULL, &flow_keys_buf_dissector, flow, - data, proto, nhoff, hlen); + data, proto, nhoff, hlen, flags); } static inline __u32 skb_get_hash(struct sk_buff *skb) @@ -2046,7 +2049,7 @@ static inline void skb_probe_transport_header(struct sk_buff *skb, if (skb_transport_header_was_set(skb)) return; - else if (skb_flow_dissect_flow_keys(skb, &keys)) + else if (skb_flow_dissect_flow_keys(skb, &keys, 0)) skb_set_transport_header(skb, keys.control.thoff); else skb_set_transport_header(skb, offset_hint); diff --git a/net/core/flow_dissector.c b/net/core/flow_dissector.c index 22f3d768b459..c3d9807cb34e 100644 --- a/net/core/flow_dissector.c +++ b/net/core/flow_dissector.c @@ -121,7 +121,8 @@ EXPORT_SYMBOL(__skb_flow_get_ports); bool __skb_flow_dissect(const struct sk_buff *skb, struct flow_dissector *flow_dissector, void *target_container, - void *data, __be16 proto, int nhoff, int hlen) + void *data, __be16 proto, int nhoff, int hlen, + unsigned int flags) { struct flow_dissector_key_control *key_control; struct flow_dissector_key_basic *key_basic; @@ -556,7 +557,7 @@ EXPORT_SYMBOL(flow_hash_from_keys); static inline u32 ___skb_get_hash(const struct sk_buff *skb, struct flow_keys *keys, u32 keyval) { - if (!skb_flow_dissect_flow_keys(skb, keys)) + if (!skb_flow_dissect_flow_keys(skb, keys, 0)) return 0; return __flow_hash_from_keys(keys, keyval); @@ -726,7 +727,7 @@ u32 skb_get_poff(const struct sk_buff *skb) { struct flow_keys keys; - if (!skb_flow_dissect_flow_keys(skb, &keys)) + if (!skb_flow_dissect_flow_keys(skb, &keys, 0)) return 0; return __skb_get_poff(skb, skb->data, &keys, skb_headlen(skb)); diff --git a/net/ethernet/eth.c b/net/ethernet/eth.c index 217127c3a3ef..d850fdc828f9 100644 --- a/net/ethernet/eth.c +++ b/net/ethernet/eth.c @@ -132,7 +132,7 @@ u32 eth_get_headlen(void *data, unsigned int len) /* parse any remaining L2/L3 headers, check for L4 */ if (!skb_flow_dissect_flow_keys_buf(&keys, data, eth->h_proto, - sizeof(*eth), len)) + sizeof(*eth), len, 0)) return max_t(u32, keys.control.thoff, sizeof(*eth)); /* parse for any L4 headers */ diff --git a/net/sched/cls_flow.c b/net/sched/cls_flow.c index bb2a0f529c1f..536838b657bf 100644 --- a/net/sched/cls_flow.c +++ b/net/sched/cls_flow.c @@ -301,7 +301,7 @@ static int flow_classify(struct sk_buff *skb, const struct tcf_proto *tp, keymask = f->keymask; if (keymask & FLOW_KEYS_NEEDED) - skb_flow_dissect_flow_keys(skb, &flow_keys); + skb_flow_dissect_flow_keys(skb, &flow_keys, 0); for (n = 0; n < f->nkeys; n++) { key = ffs(keymask) - 1; diff --git a/net/sched/cls_flower.c b/net/sched/cls_flower.c index 2f3d03f99487..57692947ebbe 100644 --- a/net/sched/cls_flower.c +++ b/net/sched/cls_flower.c @@ -129,7 +129,7 @@ static int fl_classify(struct sk_buff *skb, const struct tcf_proto *tp, * so do it rather here. */ skb_key.basic.n_proto = skb->protocol; - skb_flow_dissect(skb, &head->dissector, &skb_key); + skb_flow_dissect(skb, &head->dissector, &skb_key, 0); fl_set_masked_key(&skb_mkey, &skb_key, &head->mask); diff --git a/net/sched/sch_choke.c b/net/sched/sch_choke.c index 665bde07916b..02bfd3d1c4f0 100644 --- a/net/sched/sch_choke.c +++ b/net/sched/sch_choke.c @@ -170,13 +170,13 @@ static bool choke_match_flow(struct sk_buff *skb1, if (!choke_skb_cb(skb1)->keys_valid) { choke_skb_cb(skb1)->keys_valid = 1; - skb_flow_dissect_flow_keys(skb1, &temp); + skb_flow_dissect_flow_keys(skb1, &temp, 0); make_flow_keys_digest(&choke_skb_cb(skb1)->keys, &temp); } if (!choke_skb_cb(skb2)->keys_valid) { choke_skb_cb(skb2)->keys_valid = 1; - skb_flow_dissect_flow_keys(skb2, &temp); + skb_flow_dissect_flow_keys(skb2, &temp, 0); make_flow_keys_digest(&choke_skb_cb(skb2)->keys, &temp); } -- cgit v1.2.3 From 807e165dc44fd93f9d378f861f0540a158d7343a Mon Sep 17 00:00:00 2001 From: Tom Herbert Date: Tue, 1 Sep 2015 09:24:28 -0700 Subject: flow_dissector: Add control/reporting of fragmentation Add an input flag to flow dissector on rather dissection should be attempted on a first fragment. Also add key_control flags to indicate that a packet is a fragment or first fragment. Signed-off-by: Tom Herbert Signed-off-by: David S. Miller --- include/net/flow_dissector.h | 4 ++++ net/core/flow_dissector.c | 15 +++++++++++++-- 2 files changed, 17 insertions(+), 2 deletions(-) (limited to 'net/core/flow_dissector.c') diff --git a/include/net/flow_dissector.h b/include/net/flow_dissector.h index 74fe160f0b05..34102270b086 100644 --- a/include/net/flow_dissector.h +++ b/include/net/flow_dissector.h @@ -12,6 +12,8 @@ struct flow_dissector_key_control { u16 thoff; u16 addr_type; + u32 is_fragment:1; + u32 first_frag:1; }; /** @@ -122,6 +124,8 @@ enum flow_dissector_key_id { FLOW_DISSECTOR_KEY_MAX, }; +#define FLOW_DISSECTOR_F_PARSE_1ST_FRAG BIT(0) + struct flow_dissector_key { enum flow_dissector_key_id key_id; size_t offset; /* offset of struct flow_dissector_key_* diff --git a/net/core/flow_dissector.c b/net/core/flow_dissector.c index c3d9807cb34e..7536a4669029 100644 --- a/net/core/flow_dissector.c +++ b/net/core/flow_dissector.c @@ -177,8 +177,6 @@ ip: nhoff += iph->ihl * 4; ip_proto = iph->protocol; - if (ip_is_fragment(iph)) - ip_proto = 0; if (!skb_flow_dissector_uses_key(flow_dissector, FLOW_DISSECTOR_KEY_IPV4_ADDRS)) @@ -189,6 +187,19 @@ ip: memcpy(&key_addrs->v4addrs, &iph->saddr, sizeof(key_addrs->v4addrs)); key_control->addr_type = FLOW_DISSECTOR_KEY_IPV4_ADDRS; + + if (ip_is_fragment(iph)) { + key_control->is_fragment = 1; + + if (iph->frag_off & htons(IP_OFFSET)) { + goto out_good; + } else { + key_control->first_frag = 1; + if (!(flags & FLOW_DISSECTOR_F_PARSE_1ST_FRAG)) + goto out_good; + } + } + break; } case htons(ETH_P_IPV6): { -- cgit v1.2.3 From b840f28b908da0239c8c5d9c8cae362ad21cda97 Mon Sep 17 00:00:00 2001 From: Tom Herbert Date: Tue, 1 Sep 2015 09:24:29 -0700 Subject: flow_dissector: Support IPv6 fragment header Parse NEXTHDR_FRAGMENT. When seen account for it in the fragment bits of key_control. Also, check if first fragment should be parsed. Signed-off-by: Tom Herbert Signed-off-by: David S. Miller --- net/core/flow_dissector.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) (limited to 'net/core/flow_dissector.c') diff --git a/net/core/flow_dissector.c b/net/core/flow_dissector.c index 7536a4669029..907de2f68b1f 100644 --- a/net/core/flow_dissector.c +++ b/net/core/flow_dissector.c @@ -409,6 +409,31 @@ ip_proto_again: goto ip_proto_again; } + case NEXTHDR_FRAGMENT: { + struct frag_hdr _fh, *fh; + + if (proto != htons(ETH_P_IPV6)) + break; + + fh = __skb_header_pointer(skb, nhoff, sizeof(_fh), + data, hlen, &_fh); + + if (!fh) + goto out_bad; + + key_control->is_fragment = 1; + + nhoff += sizeof(_fh); + + if (!(fh->frag_off & htons(IP6_OFFSET))) { + key_control->first_frag = 1; + if (flags & FLOW_DISSECTOR_F_PARSE_1ST_FRAG) { + ip_proto = fh->nexthdr; + goto ip_proto_again; + } + } + goto out_good; + } case IPPROTO_IPIP: proto = htons(ETH_P_IP); goto ip; -- cgit v1.2.3 From 8306b688f1a6621b9efe3b0d827e26750528b12a Mon Sep 17 00:00:00 2001 From: Tom Herbert Date: Tue, 1 Sep 2015 09:24:30 -0700 Subject: flow_dissector: Add flag to stop parsing at L3 Add an input flag to flow dissector on rather dissection should be stopped when an L3 packet is encountered. This would be useful if a caller just wanted to get IP addresses of the outermost header (e.g. to do an L3 hash). Signed-off-by: Tom Herbert Signed-off-by: David S. Miller --- include/net/flow_dissector.h | 1 + net/core/flow_dissector.c | 6 ++++++ 2 files changed, 7 insertions(+) (limited to 'net/core/flow_dissector.c') diff --git a/include/net/flow_dissector.h b/include/net/flow_dissector.h index 34102270b086..bb81e3b576e7 100644 --- a/include/net/flow_dissector.h +++ b/include/net/flow_dissector.h @@ -125,6 +125,7 @@ enum flow_dissector_key_id { }; #define FLOW_DISSECTOR_F_PARSE_1ST_FRAG BIT(0) +#define FLOW_DISSECTOR_F_STOP_AT_L3 BIT(1) struct flow_dissector_key { enum flow_dissector_key_id key_id; diff --git a/net/core/flow_dissector.c b/net/core/flow_dissector.c index 907de2f68b1f..94fd841f341f 100644 --- a/net/core/flow_dissector.c +++ b/net/core/flow_dissector.c @@ -200,6 +200,9 @@ ip: } } + if (flags & FLOW_DISSECTOR_F_STOP_AT_L3) + goto out_good; + break; } case htons(ETH_P_IPV6): { @@ -238,6 +241,9 @@ ipv6: } } + if (flags & FLOW_DISSECTOR_F_STOP_AT_L3) + goto out_good; + break; } case htons(ETH_P_8021AD): -- cgit v1.2.3 From 872b1abb1ed47a691f465fb3d285f6cf6bcd8663 Mon Sep 17 00:00:00 2001 From: Tom Herbert Date: Tue, 1 Sep 2015 09:24:31 -0700 Subject: flow_dissector: Add flag to stop parsing when an IPv6 flow label is seen Add an input flag to flow dissector on rather dissection should be stopped when a flow label is encountered. Presumably, the flow label is derived from a sufficient hash of an inner transport packet so further dissection is not needed (that is ports are not included in the flow hash). Using the flow label instead of ports has the additional benefit that packet fragments should hash to same value as non-fragments for a flow (assuming that the same flow label is used). We set this flag by default in for skb_get_hash. Signed-off-by: Tom Herbert Signed-off-by: David S. Miller --- include/net/flow_dissector.h | 1 + net/core/flow_dissector.c | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) (limited to 'net/core/flow_dissector.c') diff --git a/include/net/flow_dissector.h b/include/net/flow_dissector.h index bb81e3b576e7..66dbc3498efb 100644 --- a/include/net/flow_dissector.h +++ b/include/net/flow_dissector.h @@ -126,6 +126,7 @@ enum flow_dissector_key_id { #define FLOW_DISSECTOR_F_PARSE_1ST_FRAG BIT(0) #define FLOW_DISSECTOR_F_STOP_AT_L3 BIT(1) +#define FLOW_DISSECTOR_F_STOP_AT_FLOW_LABEL BIT(2) struct flow_dissector_key { enum flow_dissector_key_id key_id; diff --git a/net/core/flow_dissector.c b/net/core/flow_dissector.c index 94fd841f341f..094e34354627 100644 --- a/net/core/flow_dissector.c +++ b/net/core/flow_dissector.c @@ -239,6 +239,8 @@ ipv6: target_container); key_tags->flow_label = ntohl(flow_label); } + if (flags & FLOW_DISSECTOR_F_STOP_AT_FLOW_LABEL) + goto out_good; } if (flags & FLOW_DISSECTOR_F_STOP_AT_L3) @@ -599,7 +601,8 @@ EXPORT_SYMBOL(flow_hash_from_keys); static inline u32 ___skb_get_hash(const struct sk_buff *skb, struct flow_keys *keys, u32 keyval) { - if (!skb_flow_dissect_flow_keys(skb, keys, 0)) + if (!skb_flow_dissect_flow_keys(skb, keys, + FLOW_DISSECTOR_F_STOP_AT_FLOW_LABEL)) return 0; return __flow_hash_from_keys(keys, keyval); -- cgit v1.2.3 From 823b96939578eae67b9d6c0e33a39d6a7b6401e7 Mon Sep 17 00:00:00 2001 From: Tom Herbert Date: Tue, 1 Sep 2015 09:24:32 -0700 Subject: flow_dissector: Add control/reporting of encapsulation Add an input flag to flow dissector on rather dissection should stop when encapsulation is detected (IP/IP or GRE). Also, add a key_control flag that indicates encapsulation was encountered during the dissection. Signed-off-by: Tom Herbert Signed-off-by: David S. Miller --- include/net/flow_dissector.h | 2 ++ net/core/flow_dissector.c | 15 +++++++++++++++ 2 files changed, 17 insertions(+) (limited to 'net/core/flow_dissector.c') diff --git a/include/net/flow_dissector.h b/include/net/flow_dissector.h index 66dbc3498efb..bddd1089dbce 100644 --- a/include/net/flow_dissector.h +++ b/include/net/flow_dissector.h @@ -14,6 +14,7 @@ struct flow_dissector_key_control { u16 addr_type; u32 is_fragment:1; u32 first_frag:1; + u32 encapsulation:1; }; /** @@ -127,6 +128,7 @@ enum flow_dissector_key_id { #define FLOW_DISSECTOR_F_PARSE_1ST_FRAG BIT(0) #define FLOW_DISSECTOR_F_STOP_AT_L3 BIT(1) #define FLOW_DISSECTOR_F_STOP_AT_FLOW_LABEL BIT(2) +#define FLOW_DISSECTOR_F_STOP_AT_ENCAP BIT(3) struct flow_dissector_key { enum flow_dissector_key_id key_id; diff --git a/net/core/flow_dissector.c b/net/core/flow_dissector.c index 094e34354627..8d890132e2d7 100644 --- a/net/core/flow_dissector.c +++ b/net/core/flow_dissector.c @@ -397,6 +397,11 @@ ip_proto_again: proto = eth->h_proto; nhoff += sizeof(*eth); } + + key_control->encapsulation = 1; + if (flags & FLOW_DISSECTOR_F_STOP_AT_ENCAP) + goto out_good; + goto again; } case NEXTHDR_HOP: @@ -444,9 +449,19 @@ ip_proto_again: } case IPPROTO_IPIP: proto = htons(ETH_P_IP); + + key_control->encapsulation = 1; + if (flags & FLOW_DISSECTOR_F_STOP_AT_ENCAP) + goto out_good; + goto ip; case IPPROTO_IPV6: proto = htons(ETH_P_IPV6); + + key_control->encapsulation = 1; + if (flags & FLOW_DISSECTOR_F_STOP_AT_ENCAP) + goto out_good; + goto ipv6; case IPPROTO_MPLS: proto = htons(ETH_P_MPLS_UC); -- cgit v1.2.3 From 6db61d79c1e1b2346e2142d6c950a8d2e8380b82 Mon Sep 17 00:00:00 2001 From: Tom Herbert Date: Tue, 1 Sep 2015 09:24:33 -0700 Subject: flow_dissector: Ignore flow dissector return value from ___skb_get_hash In ___skb_get_hash ignore return value from skb_flow_dissect_flow_keys. A failure in that function likely means that there was a parse error, so we may as well use whatever fields were found before the error was hit. This is also good because it means we won't keep trying to derive the hash on subsequent calls to skb_get_hash for the same packet. Signed-off-by: Tom Herbert Signed-off-by: David S. Miller --- net/core/flow_dissector.c | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) (limited to 'net/core/flow_dissector.c') diff --git a/net/core/flow_dissector.c b/net/core/flow_dissector.c index 8d890132e2d7..b563339436d0 100644 --- a/net/core/flow_dissector.c +++ b/net/core/flow_dissector.c @@ -616,9 +616,8 @@ EXPORT_SYMBOL(flow_hash_from_keys); static inline u32 ___skb_get_hash(const struct sk_buff *skb, struct flow_keys *keys, u32 keyval) { - if (!skb_flow_dissect_flow_keys(skb, keys, - FLOW_DISSECTOR_F_STOP_AT_FLOW_LABEL)) - return 0; + skb_flow_dissect_flow_keys(skb, keys, + FLOW_DISSECTOR_F_STOP_AT_FLOW_LABEL); return __flow_hash_from_keys(keys, keyval); } @@ -662,15 +661,10 @@ EXPORT_SYMBOL(make_flow_keys_digest); void __skb_get_hash(struct sk_buff *skb) { struct flow_keys keys; - u32 hash; __flow_hash_secret_init(); - hash = ___skb_get_hash(skb, &keys, hashrnd); - if (!hash) - return; - - __skb_set_sw_hash(skb, hash, + __skb_set_sw_hash(skb, ___skb_get_hash(skb, &keys, hashrnd), flow_keys_have_l4(&keys)); } EXPORT_SYMBOL(__skb_get_hash); -- cgit v1.2.3