xref: /linux/net/core/flow_dissector.c (revision a1ff5a7d78a036d6c2178ee5acd6ba4946243800)
1457c8996SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2fbff949eSJiri Pirko #include <linux/kernel.h>
30744dd00SEric Dumazet #include <linux/skbuff.h>
4c452ed70SJesper Dangaard Brouer #include <linux/export.h>
50744dd00SEric Dumazet #include <linux/ip.h>
60744dd00SEric Dumazet #include <linux/ipv6.h>
70744dd00SEric Dumazet #include <linux/if_vlan.h>
8b6459415SJakub Kicinski #include <linux/filter.h>
943e66528SJohn Crispin #include <net/dsa.h>
10a38402bcSSimon Horman #include <net/dst_metadata.h>
110744dd00SEric Dumazet #include <net/ip.h>
12ddbe5032SEric Dumazet #include <net/ipv6.h>
13ab10dccbSGao Feng #include <net/gre.h>
14ab10dccbSGao Feng #include <net/pptp.h>
158d6e79d3SJon Maloy #include <net/tipc.h>
16f77668dcSDaniel Borkmann #include <linux/igmp.h>
17f77668dcSDaniel Borkmann #include <linux/icmp.h>
18f77668dcSDaniel Borkmann #include <linux/sctp.h>
19f77668dcSDaniel Borkmann #include <linux/dccp.h>
200744dd00SEric Dumazet #include <linux/if_tunnel.h>
210744dd00SEric Dumazet #include <linux/if_pppox.h>
220744dd00SEric Dumazet #include <linux/ppp_defs.h>
2306635a35SJiri Pirko #include <linux/stddef.h>
2467a900ccSJiri Pirko #include <linux/if_ether.h>
25bf08824aSKurt Kanzenbach #include <linux/if_hsr.h>
26b3baa0fbSTom Herbert #include <linux/mpls.h>
27ac4bb5deSJiri Pirko #include <linux/tcp.h>
284f1cc51fSEran Ben Elisha #include <linux/ptp_classify.h>
291bd758ebSJiri Pirko #include <net/flow_dissector.h>
30d5ccfd90SIdo Schimmel #include <net/pkt_cls.h>
3156193d1bSAlexander Duyck #include <scsi/fc/fc_fcoe.h>
325b0890a9SSven Eckelmann #include <uapi/linux/batadv_packet.h>
33d58e468bSPetar Penkov #include <linux/bpf.h>
3475a56758SPaul Blakey #if IS_ENABLED(CONFIG_NF_CONNTRACK)
3575a56758SPaul Blakey #include <net/netfilter/nf_conntrack_core.h>
3675a56758SPaul Blakey #include <net/netfilter/nf_conntrack_labels.h>
3775a56758SPaul Blakey #endif
38a3fd7ceeSJakub Sitnicki #include <linux/bpf-netns.h>
39d58e468bSPetar Penkov 
dissector_set_key(struct flow_dissector * flow_dissector,enum flow_dissector_key_id key_id)4020a17bf6SDavid S. Miller static void dissector_set_key(struct flow_dissector *flow_dissector,
41fbff949eSJiri Pirko 			      enum flow_dissector_key_id key_id)
42fbff949eSJiri Pirko {
432b3082c6SRatheesh Kannoth 	flow_dissector->used_keys |= (1ULL << key_id);
44fbff949eSJiri Pirko }
45fbff949eSJiri Pirko 
skb_flow_dissector_init(struct flow_dissector * flow_dissector,const struct flow_dissector_key * key,unsigned int key_count)46fbff949eSJiri Pirko void skb_flow_dissector_init(struct flow_dissector *flow_dissector,
47fbff949eSJiri Pirko 			     const struct flow_dissector_key *key,
48fbff949eSJiri Pirko 			     unsigned int key_count)
49fbff949eSJiri Pirko {
50fbff949eSJiri Pirko 	unsigned int i;
51fbff949eSJiri Pirko 
52fbff949eSJiri Pirko 	memset(flow_dissector, 0, sizeof(*flow_dissector));
53fbff949eSJiri Pirko 
54fbff949eSJiri Pirko 	for (i = 0; i < key_count; i++, key++) {
5575a5fb0cSWang Qing 		/* User should make sure that every key target offset is within
56fbff949eSJiri Pirko 		 * boundaries of unsigned short.
57fbff949eSJiri Pirko 		 */
58fbff949eSJiri Pirko 		BUG_ON(key->offset > USHRT_MAX);
5920a17bf6SDavid S. Miller 		BUG_ON(dissector_uses_key(flow_dissector,
60fbff949eSJiri Pirko 					  key->key_id));
61fbff949eSJiri Pirko 
6220a17bf6SDavid S. Miller 		dissector_set_key(flow_dissector, key->key_id);
63fbff949eSJiri Pirko 		flow_dissector->offset[key->key_id] = key->offset;
64fbff949eSJiri Pirko 	}
65fbff949eSJiri Pirko 
6642aecaa9STom Herbert 	/* Ensure that the dissector always includes control and basic key.
6742aecaa9STom Herbert 	 * That way we are able to avoid handling lack of these in fast path.
68fbff949eSJiri Pirko 	 */
6920a17bf6SDavid S. Miller 	BUG_ON(!dissector_uses_key(flow_dissector,
7042aecaa9STom Herbert 				   FLOW_DISSECTOR_KEY_CONTROL));
7120a17bf6SDavid S. Miller 	BUG_ON(!dissector_uses_key(flow_dissector,
72fbff949eSJiri Pirko 				   FLOW_DISSECTOR_KEY_BASIC));
73fbff949eSJiri Pirko }
74fbff949eSJiri Pirko EXPORT_SYMBOL(skb_flow_dissector_init);
75fbff949eSJiri Pirko 
76b27f7bb5SJakub Sitnicki #ifdef CONFIG_BPF_SYSCALL
flow_dissector_bpf_prog_attach_check(struct net * net,struct bpf_prog * prog)773b701699SJakub Sitnicki int flow_dissector_bpf_prog_attach_check(struct net *net,
783b701699SJakub Sitnicki 					 struct bpf_prog *prog)
79d58e468bSPetar Penkov {
80a3fd7ceeSJakub Sitnicki 	enum netns_bpf_attach_type type = NETNS_BPF_FLOW_DISSECTOR;
81a11c397cSStanislav Fomichev 
82a11c397cSStanislav Fomichev 	if (net == &init_net) {
83a11c397cSStanislav Fomichev 		/* BPF flow dissector in the root namespace overrides
84a11c397cSStanislav Fomichev 		 * any per-net-namespace one. When attaching to root,
85a11c397cSStanislav Fomichev 		 * make sure we don't have any BPF program attached
86a11c397cSStanislav Fomichev 		 * to the non-root namespaces.
87a11c397cSStanislav Fomichev 		 */
88a11c397cSStanislav Fomichev 		struct net *ns;
89a11c397cSStanislav Fomichev 
90a11c397cSStanislav Fomichev 		for_each_net(ns) {
91719b78a5SJakub Sitnicki 			if (ns == &init_net)
92719b78a5SJakub Sitnicki 				continue;
93695c1214SJakub Sitnicki 			if (rcu_access_pointer(ns->bpf.run_array[type]))
94171526f6SJakub Sitnicki 				return -EEXIST;
95a11c397cSStanislav Fomichev 		}
96a11c397cSStanislav Fomichev 	} else {
97a11c397cSStanislav Fomichev 		/* Make sure root flow dissector is not attached
98a11c397cSStanislav Fomichev 		 * when attaching to the non-root namespace.
99a11c397cSStanislav Fomichev 		 */
100695c1214SJakub Sitnicki 		if (rcu_access_pointer(init_net.bpf.run_array[type]))
101171526f6SJakub Sitnicki 			return -EEXIST;
102a11c397cSStanislav Fomichev 	}
103a11c397cSStanislav Fomichev 
104171526f6SJakub Sitnicki 	return 0;
105171526f6SJakub Sitnicki }
106b27f7bb5SJakub Sitnicki #endif /* CONFIG_BPF_SYSCALL */
1075cf65922SJakub Sitnicki 
108972d3876SSimon Horman /**
1096451b3f5SWANG Cong  * __skb_flow_get_ports - extract the upper layer ports and return them
1106451b3f5SWANG Cong  * @skb: sk_buff to extract the ports from
111357afe9cSNikolay Aleksandrov  * @thoff: transport header offset
112357afe9cSNikolay Aleksandrov  * @ip_proto: protocol for which to get port offset
1136451b3f5SWANG Cong  * @data: raw buffer pointer to the packet, if NULL use skb->data
1146451b3f5SWANG Cong  * @hlen: packet header length, if @data is NULL use skb_headlen(skb)
115357afe9cSNikolay Aleksandrov  *
116357afe9cSNikolay Aleksandrov  * The function will try to retrieve the ports at offset thoff + poff where poff
117357afe9cSNikolay Aleksandrov  * is the protocol port offset returned from proto_ports_offset
118357afe9cSNikolay Aleksandrov  */
__skb_flow_get_ports(const struct sk_buff * skb,int thoff,u8 ip_proto,const void * data,int hlen)119690e36e7SDavid S. Miller __be32 __skb_flow_get_ports(const struct sk_buff *skb, int thoff, u8 ip_proto,
120f96533cdSAlexander Lobakin 			    const void *data, int hlen)
121357afe9cSNikolay Aleksandrov {
122357afe9cSNikolay Aleksandrov 	int poff = proto_ports_offset(ip_proto);
123357afe9cSNikolay Aleksandrov 
124690e36e7SDavid S. Miller 	if (!data) {
125690e36e7SDavid S. Miller 		data = skb->data;
126690e36e7SDavid S. Miller 		hlen = skb_headlen(skb);
127690e36e7SDavid S. Miller 	}
128690e36e7SDavid S. Miller 
129357afe9cSNikolay Aleksandrov 	if (poff >= 0) {
130357afe9cSNikolay Aleksandrov 		__be32 *ports, _ports;
131357afe9cSNikolay Aleksandrov 
132690e36e7SDavid S. Miller 		ports = __skb_header_pointer(skb, thoff + poff,
133690e36e7SDavid S. Miller 					     sizeof(_ports), data, hlen, &_ports);
134357afe9cSNikolay Aleksandrov 		if (ports)
135357afe9cSNikolay Aleksandrov 			return *ports;
136357afe9cSNikolay Aleksandrov 	}
137357afe9cSNikolay Aleksandrov 
138357afe9cSNikolay Aleksandrov 	return 0;
139357afe9cSNikolay Aleksandrov }
140690e36e7SDavid S. Miller EXPORT_SYMBOL(__skb_flow_get_ports);
141357afe9cSNikolay Aleksandrov 
icmp_has_id(u8 type)1425dec597eSMatteo Croce static bool icmp_has_id(u8 type)
1435dec597eSMatteo Croce {
1445dec597eSMatteo Croce 	switch (type) {
1455dec597eSMatteo Croce 	case ICMP_ECHO:
1465dec597eSMatteo Croce 	case ICMP_ECHOREPLY:
1475dec597eSMatteo Croce 	case ICMP_TIMESTAMP:
1485dec597eSMatteo Croce 	case ICMP_TIMESTAMPREPLY:
1495dec597eSMatteo Croce 	case ICMPV6_ECHO_REQUEST:
1505dec597eSMatteo Croce 	case ICMPV6_ECHO_REPLY:
1515dec597eSMatteo Croce 		return true;
1525dec597eSMatteo Croce 	}
1535dec597eSMatteo Croce 
1545dec597eSMatteo Croce 	return false;
1555dec597eSMatteo Croce }
1565dec597eSMatteo Croce 
1575dec597eSMatteo Croce /**
1585dec597eSMatteo Croce  * skb_flow_get_icmp_tci - extract ICMP(6) Type, Code and Identifier fields
1595dec597eSMatteo Croce  * @skb: sk_buff to extract from
1605dec597eSMatteo Croce  * @key_icmp: struct flow_dissector_key_icmp to fill
1615dec597eSMatteo Croce  * @data: raw buffer pointer to the packet
1626b3acfc3SLi RongQing  * @thoff: offset to extract at
1635dec597eSMatteo Croce  * @hlen: packet header length
1645dec597eSMatteo Croce  */
skb_flow_get_icmp_tci(const struct sk_buff * skb,struct flow_dissector_key_icmp * key_icmp,const void * data,int thoff,int hlen)1655dec597eSMatteo Croce void skb_flow_get_icmp_tci(const struct sk_buff *skb,
1665dec597eSMatteo Croce 			   struct flow_dissector_key_icmp *key_icmp,
167f96533cdSAlexander Lobakin 			   const void *data, int thoff, int hlen)
1685dec597eSMatteo Croce {
1695dec597eSMatteo Croce 	struct icmphdr *ih, _ih;
1705dec597eSMatteo Croce 
1715dec597eSMatteo Croce 	ih = __skb_header_pointer(skb, thoff, sizeof(_ih), data, hlen, &_ih);
1725dec597eSMatteo Croce 	if (!ih)
1735dec597eSMatteo Croce 		return;
1745dec597eSMatteo Croce 
1755dec597eSMatteo Croce 	key_icmp->type = ih->type;
1765dec597eSMatteo Croce 	key_icmp->code = ih->code;
1775dec597eSMatteo Croce 
1785dec597eSMatteo Croce 	/* As we use 0 to signal that the Id field is not present,
1795dec597eSMatteo Croce 	 * avoid confusion with packets without such field
1805dec597eSMatteo Croce 	 */
1815dec597eSMatteo Croce 	if (icmp_has_id(ih->type))
182a25f8222SAlexander Lobakin 		key_icmp->id = ih->un.echo.id ? ntohs(ih->un.echo.id) : 1;
1835dec597eSMatteo Croce 	else
1845dec597eSMatteo Croce 		key_icmp->id = 0;
1855dec597eSMatteo Croce }
1865dec597eSMatteo Croce EXPORT_SYMBOL(skb_flow_get_icmp_tci);
1875dec597eSMatteo Croce 
1885dec597eSMatteo Croce /* If FLOW_DISSECTOR_KEY_ICMP is set, dissect an ICMP packet
1895dec597eSMatteo Croce  * using skb_flow_get_icmp_tci().
1903b336d6fSMatteo Croce  */
__skb_flow_dissect_icmp(const struct sk_buff * skb,struct flow_dissector * flow_dissector,void * target_container,const void * data,int thoff,int hlen)1913b336d6fSMatteo Croce static void __skb_flow_dissect_icmp(const struct sk_buff *skb,
1923b336d6fSMatteo Croce 				    struct flow_dissector *flow_dissector,
193f96533cdSAlexander Lobakin 				    void *target_container, const void *data,
194f96533cdSAlexander Lobakin 				    int thoff, int hlen)
1953b336d6fSMatteo Croce {
1963b336d6fSMatteo Croce 	struct flow_dissector_key_icmp *key_icmp;
1973b336d6fSMatteo Croce 
1983b336d6fSMatteo Croce 	if (!dissector_uses_key(flow_dissector, FLOW_DISSECTOR_KEY_ICMP))
1993b336d6fSMatteo Croce 		return;
2003b336d6fSMatteo Croce 
2013b336d6fSMatteo Croce 	key_icmp = skb_flow_dissector_target(flow_dissector,
2023b336d6fSMatteo Croce 					     FLOW_DISSECTOR_KEY_ICMP,
2033b336d6fSMatteo Croce 					     target_container);
2045dec597eSMatteo Croce 
2055dec597eSMatteo Croce 	skb_flow_get_icmp_tci(skb, key_icmp, data, thoff, hlen);
2063b336d6fSMatteo Croce }
2073b336d6fSMatteo Croce 
__skb_flow_dissect_ah(const struct sk_buff * skb,struct flow_dissector * flow_dissector,void * target_container,const void * data,int nhoff,int hlen)208a57c34a8SRatheesh Kannoth static void __skb_flow_dissect_ah(const struct sk_buff *skb,
209a57c34a8SRatheesh Kannoth 				  struct flow_dissector *flow_dissector,
210a57c34a8SRatheesh Kannoth 				  void *target_container, const void *data,
211a57c34a8SRatheesh Kannoth 				  int nhoff, int hlen)
212a57c34a8SRatheesh Kannoth {
213a57c34a8SRatheesh Kannoth 	struct flow_dissector_key_ipsec *key_ah;
214a57c34a8SRatheesh Kannoth 	struct ip_auth_hdr _hdr, *hdr;
215a57c34a8SRatheesh Kannoth 
216a57c34a8SRatheesh Kannoth 	if (!dissector_uses_key(flow_dissector, FLOW_DISSECTOR_KEY_IPSEC))
217a57c34a8SRatheesh Kannoth 		return;
218a57c34a8SRatheesh Kannoth 
219a57c34a8SRatheesh Kannoth 	hdr = __skb_header_pointer(skb, nhoff, sizeof(_hdr), data, hlen, &_hdr);
220a57c34a8SRatheesh Kannoth 	if (!hdr)
221a57c34a8SRatheesh Kannoth 		return;
222a57c34a8SRatheesh Kannoth 
223a57c34a8SRatheesh Kannoth 	key_ah = skb_flow_dissector_target(flow_dissector,
224a57c34a8SRatheesh Kannoth 					   FLOW_DISSECTOR_KEY_IPSEC,
225a57c34a8SRatheesh Kannoth 					   target_container);
226a57c34a8SRatheesh Kannoth 
227a57c34a8SRatheesh Kannoth 	key_ah->spi = hdr->spi;
228a57c34a8SRatheesh Kannoth }
229a57c34a8SRatheesh Kannoth 
__skb_flow_dissect_esp(const struct sk_buff * skb,struct flow_dissector * flow_dissector,void * target_container,const void * data,int nhoff,int hlen)230a57c34a8SRatheesh Kannoth static void __skb_flow_dissect_esp(const struct sk_buff *skb,
231a57c34a8SRatheesh Kannoth 				   struct flow_dissector *flow_dissector,
232a57c34a8SRatheesh Kannoth 				   void *target_container, const void *data,
233a57c34a8SRatheesh Kannoth 				   int nhoff, int hlen)
234a57c34a8SRatheesh Kannoth {
235a57c34a8SRatheesh Kannoth 	struct flow_dissector_key_ipsec *key_esp;
236a57c34a8SRatheesh Kannoth 	struct ip_esp_hdr _hdr, *hdr;
237a57c34a8SRatheesh Kannoth 
238a57c34a8SRatheesh Kannoth 	if (!dissector_uses_key(flow_dissector, FLOW_DISSECTOR_KEY_IPSEC))
239a57c34a8SRatheesh Kannoth 		return;
240a57c34a8SRatheesh Kannoth 
241a57c34a8SRatheesh Kannoth 	hdr = __skb_header_pointer(skb, nhoff, sizeof(_hdr), data, hlen, &_hdr);
242a57c34a8SRatheesh Kannoth 	if (!hdr)
243a57c34a8SRatheesh Kannoth 		return;
244a57c34a8SRatheesh Kannoth 
245a57c34a8SRatheesh Kannoth 	key_esp = skb_flow_dissector_target(flow_dissector,
246a57c34a8SRatheesh Kannoth 					    FLOW_DISSECTOR_KEY_IPSEC,
247a57c34a8SRatheesh Kannoth 					    target_container);
248a57c34a8SRatheesh Kannoth 
249a57c34a8SRatheesh Kannoth 	key_esp->spi = hdr->spi;
250a57c34a8SRatheesh Kannoth }
251a57c34a8SRatheesh Kannoth 
__skb_flow_dissect_l2tpv3(const struct sk_buff * skb,struct flow_dissector * flow_dissector,void * target_container,const void * data,int nhoff,int hlen)252dda2fa08SWojciech Drewek static void __skb_flow_dissect_l2tpv3(const struct sk_buff *skb,
253dda2fa08SWojciech Drewek 				      struct flow_dissector *flow_dissector,
254dda2fa08SWojciech Drewek 				      void *target_container, const void *data,
255dda2fa08SWojciech Drewek 				      int nhoff, int hlen)
256dda2fa08SWojciech Drewek {
257dda2fa08SWojciech Drewek 	struct flow_dissector_key_l2tpv3 *key_l2tpv3;
258dda2fa08SWojciech Drewek 	struct {
259dda2fa08SWojciech Drewek 		__be32 session_id;
260dda2fa08SWojciech Drewek 	} *hdr, _hdr;
261dda2fa08SWojciech Drewek 
262dda2fa08SWojciech Drewek 	if (!dissector_uses_key(flow_dissector, FLOW_DISSECTOR_KEY_L2TPV3))
263dda2fa08SWojciech Drewek 		return;
264dda2fa08SWojciech Drewek 
265dda2fa08SWojciech Drewek 	hdr = __skb_header_pointer(skb, nhoff, sizeof(_hdr), data, hlen, &_hdr);
266dda2fa08SWojciech Drewek 	if (!hdr)
267dda2fa08SWojciech Drewek 		return;
268dda2fa08SWojciech Drewek 
269dda2fa08SWojciech Drewek 	key_l2tpv3 = skb_flow_dissector_target(flow_dissector,
270dda2fa08SWojciech Drewek 					       FLOW_DISSECTOR_KEY_L2TPV3,
271dda2fa08SWojciech Drewek 					       target_container);
272dda2fa08SWojciech Drewek 
273dda2fa08SWojciech Drewek 	key_l2tpv3->session_id = hdr->session_id;
274dda2fa08SWojciech Drewek }
275dda2fa08SWojciech Drewek 
skb_flow_dissect_meta(const struct sk_buff * skb,struct flow_dissector * flow_dissector,void * target_container)27682828b88SJiri Pirko void skb_flow_dissect_meta(const struct sk_buff *skb,
27782828b88SJiri Pirko 			   struct flow_dissector *flow_dissector,
27882828b88SJiri Pirko 			   void *target_container)
27982828b88SJiri Pirko {
28082828b88SJiri Pirko 	struct flow_dissector_key_meta *meta;
28182828b88SJiri Pirko 
28282828b88SJiri Pirko 	if (!dissector_uses_key(flow_dissector, FLOW_DISSECTOR_KEY_META))
28382828b88SJiri Pirko 		return;
28482828b88SJiri Pirko 
28582828b88SJiri Pirko 	meta = skb_flow_dissector_target(flow_dissector,
28682828b88SJiri Pirko 					 FLOW_DISSECTOR_KEY_META,
28782828b88SJiri Pirko 					 target_container);
28882828b88SJiri Pirko 	meta->ingress_ifindex = skb->skb_iif;
289d5ccfd90SIdo Schimmel #if IS_ENABLED(CONFIG_NET_TC_SKB_EXT)
290d5ccfd90SIdo Schimmel 	if (tc_skb_ext_tc_enabled()) {
291d5ccfd90SIdo Schimmel 		struct tc_skb_ext *ext;
292d5ccfd90SIdo Schimmel 
293d5ccfd90SIdo Schimmel 		ext = skb_ext_find(skb, TC_SKB_EXT);
294d5ccfd90SIdo Schimmel 		if (ext)
295d5ccfd90SIdo Schimmel 			meta->l2_miss = ext->l2_miss;
296d5ccfd90SIdo Schimmel 	}
297d5ccfd90SIdo Schimmel #endif
29882828b88SJiri Pirko }
29982828b88SJiri Pirko EXPORT_SYMBOL(skb_flow_dissect_meta);
30082828b88SJiri Pirko 
301a38402bcSSimon Horman static void
skb_flow_dissect_set_enc_control(enum flow_dissector_key_id type,u32 ctrl_flags,struct flow_dissector * flow_dissector,void * target_container)3024d0aed38SAsbjørn Sloth Tønnesen skb_flow_dissect_set_enc_control(enum flow_dissector_key_id type,
3034d0aed38SAsbjørn Sloth Tønnesen 				 u32 ctrl_flags,
304a38402bcSSimon Horman 				 struct flow_dissector *flow_dissector,
305a38402bcSSimon Horman 				 void *target_container)
306a38402bcSSimon Horman {
307a38402bcSSimon Horman 	struct flow_dissector_key_control *ctrl;
308a38402bcSSimon Horman 
309a38402bcSSimon Horman 	if (!dissector_uses_key(flow_dissector, FLOW_DISSECTOR_KEY_ENC_CONTROL))
310a38402bcSSimon Horman 		return;
311a38402bcSSimon Horman 
312a38402bcSSimon Horman 	ctrl = skb_flow_dissector_target(flow_dissector,
313a38402bcSSimon Horman 					 FLOW_DISSECTOR_KEY_ENC_CONTROL,
314a38402bcSSimon Horman 					 target_container);
315a38402bcSSimon Horman 	ctrl->addr_type = type;
3164d0aed38SAsbjørn Sloth Tønnesen 	ctrl->flags = ctrl_flags;
317a38402bcSSimon Horman }
318a38402bcSSimon Horman 
31962b32379SSimon Horman void
skb_flow_dissect_ct(const struct sk_buff * skb,struct flow_dissector * flow_dissector,void * target_container,u16 * ctinfo_map,size_t mapsize,bool post_ct,u16 zone)32075a56758SPaul Blakey skb_flow_dissect_ct(const struct sk_buff *skb,
32175a56758SPaul Blakey 		    struct flow_dissector *flow_dissector,
3227baf2429Swenxu 		    void *target_container, u16 *ctinfo_map,
32338495958SPaul Blakey 		    size_t mapsize, bool post_ct, u16 zone)
32475a56758SPaul Blakey {
32575a56758SPaul Blakey #if IS_ENABLED(CONFIG_NF_CONNTRACK)
32675a56758SPaul Blakey 	struct flow_dissector_key_ct *key;
32775a56758SPaul Blakey 	enum ip_conntrack_info ctinfo;
32875a56758SPaul Blakey 	struct nf_conn_labels *cl;
32975a56758SPaul Blakey 	struct nf_conn *ct;
33075a56758SPaul Blakey 
33175a56758SPaul Blakey 	if (!dissector_uses_key(flow_dissector, FLOW_DISSECTOR_KEY_CT))
33275a56758SPaul Blakey 		return;
33375a56758SPaul Blakey 
33475a56758SPaul Blakey 	ct = nf_ct_get(skb, &ctinfo);
3357baf2429Swenxu 	if (!ct && !post_ct)
33675a56758SPaul Blakey 		return;
33775a56758SPaul Blakey 
33875a56758SPaul Blakey 	key = skb_flow_dissector_target(flow_dissector,
33975a56758SPaul Blakey 					FLOW_DISSECTOR_KEY_CT,
34075a56758SPaul Blakey 					target_container);
34175a56758SPaul Blakey 
3427baf2429Swenxu 	if (!ct) {
3437baf2429Swenxu 		key->ct_state = TCA_FLOWER_KEY_CT_FLAGS_TRACKED |
3447baf2429Swenxu 				TCA_FLOWER_KEY_CT_FLAGS_INVALID;
34538495958SPaul Blakey 		key->ct_zone = zone;
3467baf2429Swenxu 		return;
3477baf2429Swenxu 	}
3487baf2429Swenxu 
34975a56758SPaul Blakey 	if (ctinfo < mapsize)
35075a56758SPaul Blakey 		key->ct_state = ctinfo_map[ctinfo];
35175a56758SPaul Blakey #if IS_ENABLED(CONFIG_NF_CONNTRACK_ZONES)
35275a56758SPaul Blakey 	key->ct_zone = ct->zone.id;
35375a56758SPaul Blakey #endif
35475a56758SPaul Blakey #if IS_ENABLED(CONFIG_NF_CONNTRACK_MARK)
35552d1aa8bSDaniel Xu 	key->ct_mark = READ_ONCE(ct->mark);
35675a56758SPaul Blakey #endif
35775a56758SPaul Blakey 
35875a56758SPaul Blakey 	cl = nf_ct_labels_find(ct);
35975a56758SPaul Blakey 	if (cl)
36075a56758SPaul Blakey 		memcpy(key->ct_labels, cl->bits, sizeof(key->ct_labels));
36175a56758SPaul Blakey #endif /* CONFIG_NF_CONNTRACK */
36275a56758SPaul Blakey }
36375a56758SPaul Blakey EXPORT_SYMBOL(skb_flow_dissect_ct);
36475a56758SPaul Blakey 
36575a56758SPaul Blakey void
skb_flow_dissect_tunnel_info(const struct sk_buff * skb,struct flow_dissector * flow_dissector,void * target_container)36662b32379SSimon Horman skb_flow_dissect_tunnel_info(const struct sk_buff *skb,
367a38402bcSSimon Horman 			     struct flow_dissector *flow_dissector,
368a38402bcSSimon Horman 			     void *target_container)
369a38402bcSSimon Horman {
370a38402bcSSimon Horman 	struct ip_tunnel_info *info;
371a38402bcSSimon Horman 	struct ip_tunnel_key *key;
3724d0aed38SAsbjørn Sloth Tønnesen 	u32 ctrl_flags = 0;
373a38402bcSSimon Horman 
374a38402bcSSimon Horman 	/* A quick check to see if there might be something to do. */
375a38402bcSSimon Horman 	if (!dissector_uses_key(flow_dissector,
376a38402bcSSimon Horman 				FLOW_DISSECTOR_KEY_ENC_KEYID) &&
377a38402bcSSimon Horman 	    !dissector_uses_key(flow_dissector,
378a38402bcSSimon Horman 				FLOW_DISSECTOR_KEY_ENC_IPV4_ADDRS) &&
379a38402bcSSimon Horman 	    !dissector_uses_key(flow_dissector,
380a38402bcSSimon Horman 				FLOW_DISSECTOR_KEY_ENC_IPV6_ADDRS) &&
381a38402bcSSimon Horman 	    !dissector_uses_key(flow_dissector,
382a38402bcSSimon Horman 				FLOW_DISSECTOR_KEY_ENC_CONTROL) &&
383a38402bcSSimon Horman 	    !dissector_uses_key(flow_dissector,
3845544adb9SOr Gerlitz 				FLOW_DISSECTOR_KEY_ENC_PORTS) &&
3855544adb9SOr Gerlitz 	    !dissector_uses_key(flow_dissector,
38692e2c405SSimon Horman 				FLOW_DISSECTOR_KEY_ENC_IP) &&
38792e2c405SSimon Horman 	    !dissector_uses_key(flow_dissector,
388db5271d5SAsbjørn Sloth Tønnesen 				FLOW_DISSECTOR_KEY_ENC_OPTS))
389a38402bcSSimon Horman 		return;
390a38402bcSSimon Horman 
391a38402bcSSimon Horman 	info = skb_tunnel_info(skb);
392a38402bcSSimon Horman 	if (!info)
393a38402bcSSimon Horman 		return;
394a38402bcSSimon Horman 
395a38402bcSSimon Horman 	key = &info->key;
396a38402bcSSimon Horman 
39703afeb61SAsbjørn Sloth Tønnesen 	if (test_bit(IP_TUNNEL_CSUM_BIT, key->tun_flags))
39803afeb61SAsbjørn Sloth Tønnesen 		ctrl_flags |= FLOW_DIS_F_TUNNEL_CSUM;
39903afeb61SAsbjørn Sloth Tønnesen 	if (test_bit(IP_TUNNEL_DONT_FRAGMENT_BIT, key->tun_flags))
40003afeb61SAsbjørn Sloth Tønnesen 		ctrl_flags |= FLOW_DIS_F_TUNNEL_DONT_FRAGMENT;
40103afeb61SAsbjørn Sloth Tønnesen 	if (test_bit(IP_TUNNEL_OAM_BIT, key->tun_flags))
40203afeb61SAsbjørn Sloth Tønnesen 		ctrl_flags |= FLOW_DIS_F_TUNNEL_OAM;
40303afeb61SAsbjørn Sloth Tønnesen 	if (test_bit(IP_TUNNEL_CRIT_OPT_BIT, key->tun_flags))
40403afeb61SAsbjørn Sloth Tønnesen 		ctrl_flags |= FLOW_DIS_F_TUNNEL_CRIT_OPT;
40503afeb61SAsbjørn Sloth Tønnesen 
406a38402bcSSimon Horman 	switch (ip_tunnel_info_af(info)) {
407a38402bcSSimon Horman 	case AF_INET:
4084d0aed38SAsbjørn Sloth Tønnesen 		skb_flow_dissect_set_enc_control(FLOW_DISSECTOR_KEY_IPV4_ADDRS,
4094d0aed38SAsbjørn Sloth Tønnesen 						 ctrl_flags, flow_dissector,
410a38402bcSSimon Horman 						 target_container);
411a38402bcSSimon Horman 		if (dissector_uses_key(flow_dissector,
412a38402bcSSimon Horman 				       FLOW_DISSECTOR_KEY_ENC_IPV4_ADDRS)) {
413a38402bcSSimon Horman 			struct flow_dissector_key_ipv4_addrs *ipv4;
414a38402bcSSimon Horman 
415a38402bcSSimon Horman 			ipv4 = skb_flow_dissector_target(flow_dissector,
416a38402bcSSimon Horman 							 FLOW_DISSECTOR_KEY_ENC_IPV4_ADDRS,
417a38402bcSSimon Horman 							 target_container);
418a38402bcSSimon Horman 			ipv4->src = key->u.ipv4.src;
419a38402bcSSimon Horman 			ipv4->dst = key->u.ipv4.dst;
420a38402bcSSimon Horman 		}
421a38402bcSSimon Horman 		break;
422a38402bcSSimon Horman 	case AF_INET6:
4234d0aed38SAsbjørn Sloth Tønnesen 		skb_flow_dissect_set_enc_control(FLOW_DISSECTOR_KEY_IPV6_ADDRS,
4244d0aed38SAsbjørn Sloth Tønnesen 						 ctrl_flags, flow_dissector,
425a38402bcSSimon Horman 						 target_container);
426a38402bcSSimon Horman 		if (dissector_uses_key(flow_dissector,
427a38402bcSSimon Horman 				       FLOW_DISSECTOR_KEY_ENC_IPV6_ADDRS)) {
428a38402bcSSimon Horman 			struct flow_dissector_key_ipv6_addrs *ipv6;
429a38402bcSSimon Horman 
430a38402bcSSimon Horman 			ipv6 = skb_flow_dissector_target(flow_dissector,
431a38402bcSSimon Horman 							 FLOW_DISSECTOR_KEY_ENC_IPV6_ADDRS,
432a38402bcSSimon Horman 							 target_container);
433a38402bcSSimon Horman 			ipv6->src = key->u.ipv6.src;
434a38402bcSSimon Horman 			ipv6->dst = key->u.ipv6.dst;
435a38402bcSSimon Horman 		}
436a38402bcSSimon Horman 		break;
437706bf4f4SAsbjørn Sloth Tønnesen 	default:
438706bf4f4SAsbjørn Sloth Tønnesen 		skb_flow_dissect_set_enc_control(0, ctrl_flags, flow_dissector,
439706bf4f4SAsbjørn Sloth Tønnesen 						 target_container);
440706bf4f4SAsbjørn Sloth Tønnesen 		break;
441a38402bcSSimon Horman 	}
442a38402bcSSimon Horman 
443a38402bcSSimon Horman 	if (dissector_uses_key(flow_dissector, FLOW_DISSECTOR_KEY_ENC_KEYID)) {
444a38402bcSSimon Horman 		struct flow_dissector_key_keyid *keyid;
445a38402bcSSimon Horman 
446a38402bcSSimon Horman 		keyid = skb_flow_dissector_target(flow_dissector,
447a38402bcSSimon Horman 						  FLOW_DISSECTOR_KEY_ENC_KEYID,
448a38402bcSSimon Horman 						  target_container);
449a38402bcSSimon Horman 		keyid->keyid = tunnel_id_to_key32(key->tun_id);
450a38402bcSSimon Horman 	}
451a38402bcSSimon Horman 
452a38402bcSSimon Horman 	if (dissector_uses_key(flow_dissector, FLOW_DISSECTOR_KEY_ENC_PORTS)) {
453a38402bcSSimon Horman 		struct flow_dissector_key_ports *tp;
454a38402bcSSimon Horman 
455a38402bcSSimon Horman 		tp = skb_flow_dissector_target(flow_dissector,
456a38402bcSSimon Horman 					       FLOW_DISSECTOR_KEY_ENC_PORTS,
457a38402bcSSimon Horman 					       target_container);
458a38402bcSSimon Horman 		tp->src = key->tp_src;
459a38402bcSSimon Horman 		tp->dst = key->tp_dst;
460a38402bcSSimon Horman 	}
4615544adb9SOr Gerlitz 
4625544adb9SOr Gerlitz 	if (dissector_uses_key(flow_dissector, FLOW_DISSECTOR_KEY_ENC_IP)) {
4635544adb9SOr Gerlitz 		struct flow_dissector_key_ip *ip;
4645544adb9SOr Gerlitz 
4655544adb9SOr Gerlitz 		ip = skb_flow_dissector_target(flow_dissector,
4665544adb9SOr Gerlitz 					       FLOW_DISSECTOR_KEY_ENC_IP,
4675544adb9SOr Gerlitz 					       target_container);
4685544adb9SOr Gerlitz 		ip->tos = key->tos;
4695544adb9SOr Gerlitz 		ip->ttl = key->ttl;
4705544adb9SOr Gerlitz 	}
47192e2c405SSimon Horman 
47292e2c405SSimon Horman 	if (dissector_uses_key(flow_dissector, FLOW_DISSECTOR_KEY_ENC_OPTS)) {
47392e2c405SSimon Horman 		struct flow_dissector_key_enc_opts *enc_opt;
4745832c4a7SAlexander Lobakin 		IP_TUNNEL_DECLARE_FLAGS(flags) = { };
4755832c4a7SAlexander Lobakin 		u32 val;
47692e2c405SSimon Horman 
47792e2c405SSimon Horman 		enc_opt = skb_flow_dissector_target(flow_dissector,
47892e2c405SSimon Horman 						    FLOW_DISSECTOR_KEY_ENC_OPTS,
47992e2c405SSimon Horman 						    target_container);
48092e2c405SSimon Horman 
4815832c4a7SAlexander Lobakin 		if (!info->options_len)
4825832c4a7SAlexander Lobakin 			return;
4835832c4a7SAlexander Lobakin 
48492e2c405SSimon Horman 		enc_opt->len = info->options_len;
48592e2c405SSimon Horman 		ip_tunnel_info_opts_get(enc_opt->data, info);
4865832c4a7SAlexander Lobakin 
4875832c4a7SAlexander Lobakin 		ip_tunnel_set_options_present(flags);
4885832c4a7SAlexander Lobakin 		ip_tunnel_flags_and(flags, info->key.tun_flags, flags);
4895832c4a7SAlexander Lobakin 
4905832c4a7SAlexander Lobakin 		val = find_next_bit(flags, __IP_TUNNEL_FLAG_NUM,
4915832c4a7SAlexander Lobakin 				    IP_TUNNEL_GENEVE_OPT_BIT);
4925832c4a7SAlexander Lobakin 		enc_opt->dst_opt_type = val < __IP_TUNNEL_FLAG_NUM ? val : 0;
49392e2c405SSimon Horman 	}
494a38402bcSSimon Horman }
49562b32379SSimon Horman EXPORT_SYMBOL(skb_flow_dissect_tunnel_info);
496a38402bcSSimon Horman 
skb_flow_dissect_hash(const struct sk_buff * skb,struct flow_dissector * flow_dissector,void * target_container)4970cb09affSAriel Levkovich void skb_flow_dissect_hash(const struct sk_buff *skb,
4980cb09affSAriel Levkovich 			   struct flow_dissector *flow_dissector,
4990cb09affSAriel Levkovich 			   void *target_container)
5000cb09affSAriel Levkovich {
5010cb09affSAriel Levkovich 	struct flow_dissector_key_hash *key;
5020cb09affSAriel Levkovich 
5030cb09affSAriel Levkovich 	if (!dissector_uses_key(flow_dissector, FLOW_DISSECTOR_KEY_HASH))
5040cb09affSAriel Levkovich 		return;
5050cb09affSAriel Levkovich 
5060cb09affSAriel Levkovich 	key = skb_flow_dissector_target(flow_dissector,
5070cb09affSAriel Levkovich 					FLOW_DISSECTOR_KEY_HASH,
5080cb09affSAriel Levkovich 					target_container);
5090cb09affSAriel Levkovich 
5100cb09affSAriel Levkovich 	key->hash = skb_get_hash_raw(skb);
5110cb09affSAriel Levkovich }
5120cb09affSAriel Levkovich EXPORT_SYMBOL(skb_flow_dissect_hash);
5130cb09affSAriel Levkovich 
5149bf881ffSJiri Pirko static enum flow_dissect_ret
__skb_flow_dissect_mpls(const struct sk_buff * skb,struct flow_dissector * flow_dissector,void * target_container,const void * data,int nhoff,int hlen,int lse_index,bool * entropy_label)5154a5d6c8bSJiri Pirko __skb_flow_dissect_mpls(const struct sk_buff *skb,
5164a5d6c8bSJiri Pirko 			struct flow_dissector *flow_dissector,
517f96533cdSAlexander Lobakin 			void *target_container, const void *data, int nhoff,
518f96533cdSAlexander Lobakin 			int hlen, int lse_index, bool *entropy_label)
5194a5d6c8bSJiri Pirko {
52058cff782SGuillaume Nault 	struct mpls_label *hdr, _hdr;
52158cff782SGuillaume Nault 	u32 entry, label, bos;
5224a5d6c8bSJiri Pirko 
5234a5d6c8bSJiri Pirko 	if (!dissector_uses_key(flow_dissector,
524029c1ecbSBenjamin LaHaise 				FLOW_DISSECTOR_KEY_MPLS_ENTROPY) &&
525029c1ecbSBenjamin LaHaise 	    !dissector_uses_key(flow_dissector, FLOW_DISSECTOR_KEY_MPLS))
5264a5d6c8bSJiri Pirko 		return FLOW_DISSECT_RET_OUT_GOOD;
5274a5d6c8bSJiri Pirko 
52858cff782SGuillaume Nault 	if (lse_index >= FLOW_DIS_MPLS_MAX)
52958cff782SGuillaume Nault 		return FLOW_DISSECT_RET_OUT_GOOD;
53058cff782SGuillaume Nault 
5314a5d6c8bSJiri Pirko 	hdr = __skb_header_pointer(skb, nhoff, sizeof(_hdr), data,
5324a5d6c8bSJiri Pirko 				   hlen, &_hdr);
5334a5d6c8bSJiri Pirko 	if (!hdr)
5344a5d6c8bSJiri Pirko 		return FLOW_DISSECT_RET_OUT_BAD;
5354a5d6c8bSJiri Pirko 
53658cff782SGuillaume Nault 	entry = ntohl(hdr->entry);
537029c1ecbSBenjamin LaHaise 	label = (entry & MPLS_LS_LABEL_MASK) >> MPLS_LS_LABEL_SHIFT;
53858cff782SGuillaume Nault 	bos = (entry & MPLS_LS_S_MASK) >> MPLS_LS_S_SHIFT;
539029c1ecbSBenjamin LaHaise 
540029c1ecbSBenjamin LaHaise 	if (dissector_uses_key(flow_dissector, FLOW_DISSECTOR_KEY_MPLS)) {
541029c1ecbSBenjamin LaHaise 		struct flow_dissector_key_mpls *key_mpls;
54258cff782SGuillaume Nault 		struct flow_dissector_mpls_lse *lse;
543029c1ecbSBenjamin LaHaise 
544029c1ecbSBenjamin LaHaise 		key_mpls = skb_flow_dissector_target(flow_dissector,
545029c1ecbSBenjamin LaHaise 						     FLOW_DISSECTOR_KEY_MPLS,
546029c1ecbSBenjamin LaHaise 						     target_container);
54758cff782SGuillaume Nault 		lse = &key_mpls->ls[lse_index];
54858cff782SGuillaume Nault 
54958cff782SGuillaume Nault 		lse->mpls_ttl = (entry & MPLS_LS_TTL_MASK) >> MPLS_LS_TTL_SHIFT;
55058cff782SGuillaume Nault 		lse->mpls_bos = bos;
55158cff782SGuillaume Nault 		lse->mpls_tc = (entry & MPLS_LS_TC_MASK) >> MPLS_LS_TC_SHIFT;
55258cff782SGuillaume Nault 		lse->mpls_label = label;
55358cff782SGuillaume Nault 		dissector_set_mpls_lse(key_mpls, lse_index);
554029c1ecbSBenjamin LaHaise 	}
555029c1ecbSBenjamin LaHaise 
55658cff782SGuillaume Nault 	if (*entropy_label &&
55758cff782SGuillaume Nault 	    dissector_uses_key(flow_dissector,
55858cff782SGuillaume Nault 			       FLOW_DISSECTOR_KEY_MPLS_ENTROPY)) {
55958cff782SGuillaume Nault 		struct flow_dissector_key_keyid *key_keyid;
56058cff782SGuillaume Nault 
5614a5d6c8bSJiri Pirko 		key_keyid = skb_flow_dissector_target(flow_dissector,
5624a5d6c8bSJiri Pirko 						      FLOW_DISSECTOR_KEY_MPLS_ENTROPY,
5634a5d6c8bSJiri Pirko 						      target_container);
56458cff782SGuillaume Nault 		key_keyid->keyid = cpu_to_be32(label);
5654a5d6c8bSJiri Pirko 	}
56658cff782SGuillaume Nault 
56758cff782SGuillaume Nault 	*entropy_label = label == MPLS_LABEL_ENTROPY;
56858cff782SGuillaume Nault 
56958cff782SGuillaume Nault 	return bos ? FLOW_DISSECT_RET_OUT_GOOD : FLOW_DISSECT_RET_PROTO_AGAIN;
5704a5d6c8bSJiri Pirko }
5714a5d6c8bSJiri Pirko 
5724a5d6c8bSJiri Pirko static enum flow_dissect_ret
__skb_flow_dissect_arp(const struct sk_buff * skb,struct flow_dissector * flow_dissector,void * target_container,const void * data,int nhoff,int hlen)5739bf881ffSJiri Pirko __skb_flow_dissect_arp(const struct sk_buff *skb,
5749bf881ffSJiri Pirko 		       struct flow_dissector *flow_dissector,
575f96533cdSAlexander Lobakin 		       void *target_container, const void *data,
576f96533cdSAlexander Lobakin 		       int nhoff, int hlen)
5779bf881ffSJiri Pirko {
5789bf881ffSJiri Pirko 	struct flow_dissector_key_arp *key_arp;
5799bf881ffSJiri Pirko 	struct {
5809bf881ffSJiri Pirko 		unsigned char ar_sha[ETH_ALEN];
5819bf881ffSJiri Pirko 		unsigned char ar_sip[4];
5829bf881ffSJiri Pirko 		unsigned char ar_tha[ETH_ALEN];
5839bf881ffSJiri Pirko 		unsigned char ar_tip[4];
5849bf881ffSJiri Pirko 	} *arp_eth, _arp_eth;
5859bf881ffSJiri Pirko 	const struct arphdr *arp;
5866f14f443SDavid S. Miller 	struct arphdr _arp;
5879bf881ffSJiri Pirko 
5889bf881ffSJiri Pirko 	if (!dissector_uses_key(flow_dissector, FLOW_DISSECTOR_KEY_ARP))
5899bf881ffSJiri Pirko 		return FLOW_DISSECT_RET_OUT_GOOD;
5909bf881ffSJiri Pirko 
5919bf881ffSJiri Pirko 	arp = __skb_header_pointer(skb, nhoff, sizeof(_arp), data,
5929bf881ffSJiri Pirko 				   hlen, &_arp);
5939bf881ffSJiri Pirko 	if (!arp)
5949bf881ffSJiri Pirko 		return FLOW_DISSECT_RET_OUT_BAD;
5959bf881ffSJiri Pirko 
5969bf881ffSJiri Pirko 	if (arp->ar_hrd != htons(ARPHRD_ETHER) ||
5979bf881ffSJiri Pirko 	    arp->ar_pro != htons(ETH_P_IP) ||
5989bf881ffSJiri Pirko 	    arp->ar_hln != ETH_ALEN ||
5999bf881ffSJiri Pirko 	    arp->ar_pln != 4 ||
6009bf881ffSJiri Pirko 	    (arp->ar_op != htons(ARPOP_REPLY) &&
6019bf881ffSJiri Pirko 	     arp->ar_op != htons(ARPOP_REQUEST)))
6029bf881ffSJiri Pirko 		return FLOW_DISSECT_RET_OUT_BAD;
6039bf881ffSJiri Pirko 
6049bf881ffSJiri Pirko 	arp_eth = __skb_header_pointer(skb, nhoff + sizeof(_arp),
6059bf881ffSJiri Pirko 				       sizeof(_arp_eth), data,
6069bf881ffSJiri Pirko 				       hlen, &_arp_eth);
6079bf881ffSJiri Pirko 	if (!arp_eth)
6089bf881ffSJiri Pirko 		return FLOW_DISSECT_RET_OUT_BAD;
6099bf881ffSJiri Pirko 
6109bf881ffSJiri Pirko 	key_arp = skb_flow_dissector_target(flow_dissector,
6119bf881ffSJiri Pirko 					    FLOW_DISSECTOR_KEY_ARP,
6129bf881ffSJiri Pirko 					    target_container);
6139bf881ffSJiri Pirko 
6149bf881ffSJiri Pirko 	memcpy(&key_arp->sip, arp_eth->ar_sip, sizeof(key_arp->sip));
6159bf881ffSJiri Pirko 	memcpy(&key_arp->tip, arp_eth->ar_tip, sizeof(key_arp->tip));
6169bf881ffSJiri Pirko 
6179bf881ffSJiri Pirko 	/* Only store the lower byte of the opcode;
6189bf881ffSJiri Pirko 	 * this covers ARPOP_REPLY and ARPOP_REQUEST.
6199bf881ffSJiri Pirko 	 */
6209bf881ffSJiri Pirko 	key_arp->op = ntohs(arp->ar_op) & 0xff;
6219bf881ffSJiri Pirko 
6229bf881ffSJiri Pirko 	ether_addr_copy(key_arp->sha, arp_eth->ar_sha);
6239bf881ffSJiri Pirko 	ether_addr_copy(key_arp->tha, arp_eth->ar_tha);
6249bf881ffSJiri Pirko 
6259bf881ffSJiri Pirko 	return FLOW_DISSECT_RET_OUT_GOOD;
6269bf881ffSJiri Pirko }
6279bf881ffSJiri Pirko 
6287c92de8eSJiri Pirko static enum flow_dissect_ret
__skb_flow_dissect_cfm(const struct sk_buff * skb,struct flow_dissector * flow_dissector,void * target_container,const void * data,int nhoff,int hlen)629d7ad70b5SZahari Doychev __skb_flow_dissect_cfm(const struct sk_buff *skb,
630d7ad70b5SZahari Doychev 		       struct flow_dissector *flow_dissector,
631d7ad70b5SZahari Doychev 		       void *target_container, const void *data,
632d7ad70b5SZahari Doychev 		       int nhoff, int hlen)
633d7ad70b5SZahari Doychev {
634d7ad70b5SZahari Doychev 	struct flow_dissector_key_cfm *key, *hdr, _hdr;
635d7ad70b5SZahari Doychev 
636d7ad70b5SZahari Doychev 	if (!dissector_uses_key(flow_dissector, FLOW_DISSECTOR_KEY_CFM))
637d7ad70b5SZahari Doychev 		return FLOW_DISSECT_RET_OUT_GOOD;
638d7ad70b5SZahari Doychev 
639d7ad70b5SZahari Doychev 	hdr = __skb_header_pointer(skb, nhoff, sizeof(*key), data, hlen, &_hdr);
640d7ad70b5SZahari Doychev 	if (!hdr)
641d7ad70b5SZahari Doychev 		return FLOW_DISSECT_RET_OUT_BAD;
642d7ad70b5SZahari Doychev 
643d7ad70b5SZahari Doychev 	key = skb_flow_dissector_target(flow_dissector, FLOW_DISSECTOR_KEY_CFM,
644d7ad70b5SZahari Doychev 					target_container);
645d7ad70b5SZahari Doychev 
646d7ad70b5SZahari Doychev 	key->mdl_ver = hdr->mdl_ver;
647d7ad70b5SZahari Doychev 	key->opcode = hdr->opcode;
648d7ad70b5SZahari Doychev 
649d7ad70b5SZahari Doychev 	return FLOW_DISSECT_RET_OUT_GOOD;
650d7ad70b5SZahari Doychev }
651d7ad70b5SZahari Doychev 
652d7ad70b5SZahari Doychev static enum flow_dissect_ret
__skb_flow_dissect_gre(const struct sk_buff * skb,struct flow_dissector_key_control * key_control,struct flow_dissector * flow_dissector,void * target_container,const void * data,__be16 * p_proto,int * p_nhoff,int * p_hlen,unsigned int flags)6537c92de8eSJiri Pirko __skb_flow_dissect_gre(const struct sk_buff *skb,
6547c92de8eSJiri Pirko 		       struct flow_dissector_key_control *key_control,
6557c92de8eSJiri Pirko 		       struct flow_dissector *flow_dissector,
656f96533cdSAlexander Lobakin 		       void *target_container, const void *data,
6577c92de8eSJiri Pirko 		       __be16 *p_proto, int *p_nhoff, int *p_hlen,
6587c92de8eSJiri Pirko 		       unsigned int flags)
6597c92de8eSJiri Pirko {
6607c92de8eSJiri Pirko 	struct flow_dissector_key_keyid *key_keyid;
6617c92de8eSJiri Pirko 	struct gre_base_hdr *hdr, _hdr;
6627c92de8eSJiri Pirko 	int offset = 0;
6637c92de8eSJiri Pirko 	u16 gre_ver;
6647c92de8eSJiri Pirko 
6657c92de8eSJiri Pirko 	hdr = __skb_header_pointer(skb, *p_nhoff, sizeof(_hdr),
6667c92de8eSJiri Pirko 				   data, *p_hlen, &_hdr);
6677c92de8eSJiri Pirko 	if (!hdr)
6687c92de8eSJiri Pirko 		return FLOW_DISSECT_RET_OUT_BAD;
6697c92de8eSJiri Pirko 
6707c92de8eSJiri Pirko 	/* Only look inside GRE without routing */
6717c92de8eSJiri Pirko 	if (hdr->flags & GRE_ROUTING)
6727c92de8eSJiri Pirko 		return FLOW_DISSECT_RET_OUT_GOOD;
6737c92de8eSJiri Pirko 
6747c92de8eSJiri Pirko 	/* Only look inside GRE for version 0 and 1 */
6757c92de8eSJiri Pirko 	gre_ver = ntohs(hdr->flags & GRE_VERSION);
6767c92de8eSJiri Pirko 	if (gre_ver > 1)
6777c92de8eSJiri Pirko 		return FLOW_DISSECT_RET_OUT_GOOD;
6787c92de8eSJiri Pirko 
6797c92de8eSJiri Pirko 	*p_proto = hdr->protocol;
6807c92de8eSJiri Pirko 	if (gre_ver) {
6817c92de8eSJiri Pirko 		/* Version1 must be PPTP, and check the flags */
6827c92de8eSJiri Pirko 		if (!(*p_proto == GRE_PROTO_PPP && (hdr->flags & GRE_KEY)))
6837c92de8eSJiri Pirko 			return FLOW_DISSECT_RET_OUT_GOOD;
6847c92de8eSJiri Pirko 	}
6857c92de8eSJiri Pirko 
6867c92de8eSJiri Pirko 	offset += sizeof(struct gre_base_hdr);
6877c92de8eSJiri Pirko 
6887c92de8eSJiri Pirko 	if (hdr->flags & GRE_CSUM)
689c593642cSPankaj Bharadiya 		offset += sizeof_field(struct gre_full_hdr, csum) +
690c593642cSPankaj Bharadiya 			  sizeof_field(struct gre_full_hdr, reserved1);
6917c92de8eSJiri Pirko 
6927c92de8eSJiri Pirko 	if (hdr->flags & GRE_KEY) {
6937c92de8eSJiri Pirko 		const __be32 *keyid;
6947c92de8eSJiri Pirko 		__be32 _keyid;
6957c92de8eSJiri Pirko 
6967c92de8eSJiri Pirko 		keyid = __skb_header_pointer(skb, *p_nhoff + offset,
6977c92de8eSJiri Pirko 					     sizeof(_keyid),
6987c92de8eSJiri Pirko 					     data, *p_hlen, &_keyid);
6997c92de8eSJiri Pirko 		if (!keyid)
7007c92de8eSJiri Pirko 			return FLOW_DISSECT_RET_OUT_BAD;
7017c92de8eSJiri Pirko 
7027c92de8eSJiri Pirko 		if (dissector_uses_key(flow_dissector,
7037c92de8eSJiri Pirko 				       FLOW_DISSECTOR_KEY_GRE_KEYID)) {
7047c92de8eSJiri Pirko 			key_keyid = skb_flow_dissector_target(flow_dissector,
7057c92de8eSJiri Pirko 							      FLOW_DISSECTOR_KEY_GRE_KEYID,
7067c92de8eSJiri Pirko 							      target_container);
7077c92de8eSJiri Pirko 			if (gre_ver == 0)
7087c92de8eSJiri Pirko 				key_keyid->keyid = *keyid;
7097c92de8eSJiri Pirko 			else
7107c92de8eSJiri Pirko 				key_keyid->keyid = *keyid & GRE_PPTP_KEY_MASK;
7117c92de8eSJiri Pirko 		}
712c593642cSPankaj Bharadiya 		offset += sizeof_field(struct gre_full_hdr, key);
7137c92de8eSJiri Pirko 	}
7147c92de8eSJiri Pirko 
7157c92de8eSJiri Pirko 	if (hdr->flags & GRE_SEQ)
716c593642cSPankaj Bharadiya 		offset += sizeof_field(struct pptp_gre_header, seq);
7177c92de8eSJiri Pirko 
7187c92de8eSJiri Pirko 	if (gre_ver == 0) {
7197c92de8eSJiri Pirko 		if (*p_proto == htons(ETH_P_TEB)) {
7207c92de8eSJiri Pirko 			const struct ethhdr *eth;
7217c92de8eSJiri Pirko 			struct ethhdr _eth;
7227c92de8eSJiri Pirko 
7237c92de8eSJiri Pirko 			eth = __skb_header_pointer(skb, *p_nhoff + offset,
7247c92de8eSJiri Pirko 						   sizeof(_eth),
7257c92de8eSJiri Pirko 						   data, *p_hlen, &_eth);
7267c92de8eSJiri Pirko 			if (!eth)
7277c92de8eSJiri Pirko 				return FLOW_DISSECT_RET_OUT_BAD;
7287c92de8eSJiri Pirko 			*p_proto = eth->h_proto;
7297c92de8eSJiri Pirko 			offset += sizeof(*eth);
7307c92de8eSJiri Pirko 
7317c92de8eSJiri Pirko 			/* Cap headers that we access via pointers at the
7327c92de8eSJiri Pirko 			 * end of the Ethernet header as our maximum alignment
7337c92de8eSJiri Pirko 			 * at that point is only 2 bytes.
7347c92de8eSJiri Pirko 			 */
7357c92de8eSJiri Pirko 			if (NET_IP_ALIGN)
7367c92de8eSJiri Pirko 				*p_hlen = *p_nhoff + offset;
7377c92de8eSJiri Pirko 		}
7387c92de8eSJiri Pirko 	} else { /* version 1, must be PPTP */
7397c92de8eSJiri Pirko 		u8 _ppp_hdr[PPP_HDRLEN];
7407c92de8eSJiri Pirko 		u8 *ppp_hdr;
7417c92de8eSJiri Pirko 
7427c92de8eSJiri Pirko 		if (hdr->flags & GRE_ACK)
743c593642cSPankaj Bharadiya 			offset += sizeof_field(struct pptp_gre_header, ack);
7447c92de8eSJiri Pirko 
7457c92de8eSJiri Pirko 		ppp_hdr = __skb_header_pointer(skb, *p_nhoff + offset,
7467c92de8eSJiri Pirko 					       sizeof(_ppp_hdr),
7477c92de8eSJiri Pirko 					       data, *p_hlen, _ppp_hdr);
7487c92de8eSJiri Pirko 		if (!ppp_hdr)
7497c92de8eSJiri Pirko 			return FLOW_DISSECT_RET_OUT_BAD;
7507c92de8eSJiri Pirko 
7517c92de8eSJiri Pirko 		switch (PPP_PROTOCOL(ppp_hdr)) {
7527c92de8eSJiri Pirko 		case PPP_IP:
7537c92de8eSJiri Pirko 			*p_proto = htons(ETH_P_IP);
7547c92de8eSJiri Pirko 			break;
7557c92de8eSJiri Pirko 		case PPP_IPV6:
7567c92de8eSJiri Pirko 			*p_proto = htons(ETH_P_IPV6);
7577c92de8eSJiri Pirko 			break;
7587c92de8eSJiri Pirko 		default:
7597c92de8eSJiri Pirko 			/* Could probably catch some more like MPLS */
7607c92de8eSJiri Pirko 			break;
7617c92de8eSJiri Pirko 		}
7627c92de8eSJiri Pirko 
7637c92de8eSJiri Pirko 		offset += PPP_HDRLEN;
7647c92de8eSJiri Pirko 	}
7657c92de8eSJiri Pirko 
7667c92de8eSJiri Pirko 	*p_nhoff += offset;
7677c92de8eSJiri Pirko 	key_control->flags |= FLOW_DIS_ENCAPSULATION;
7687c92de8eSJiri Pirko 	if (flags & FLOW_DISSECTOR_F_STOP_AT_ENCAP)
7697c92de8eSJiri Pirko 		return FLOW_DISSECT_RET_OUT_GOOD;
7707c92de8eSJiri Pirko 
7713a1214e8STom Herbert 	return FLOW_DISSECT_RET_PROTO_AGAIN;
7727c92de8eSJiri Pirko }
7737c92de8eSJiri Pirko 
7745b0890a9SSven Eckelmann /**
7755b0890a9SSven Eckelmann  * __skb_flow_dissect_batadv() - dissect batman-adv header
7765b0890a9SSven Eckelmann  * @skb: sk_buff to with the batman-adv header
7775b0890a9SSven Eckelmann  * @key_control: flow dissectors control key
7785b0890a9SSven Eckelmann  * @data: raw buffer pointer to the packet, if NULL use skb->data
7795b0890a9SSven Eckelmann  * @p_proto: pointer used to update the protocol to process next
7805b0890a9SSven Eckelmann  * @p_nhoff: pointer used to update inner network header offset
7815b0890a9SSven Eckelmann  * @hlen: packet header length
7825b0890a9SSven Eckelmann  * @flags: any combination of FLOW_DISSECTOR_F_*
7835b0890a9SSven Eckelmann  *
7845b0890a9SSven Eckelmann  * ETH_P_BATMAN packets are tried to be dissected. Only
7855b0890a9SSven Eckelmann  * &struct batadv_unicast packets are actually processed because they contain an
7865b0890a9SSven Eckelmann  * inner ethernet header and are usually followed by actual network header. This
7875b0890a9SSven Eckelmann  * allows the flow dissector to continue processing the packet.
7885b0890a9SSven Eckelmann  *
7895b0890a9SSven Eckelmann  * Return: FLOW_DISSECT_RET_PROTO_AGAIN when &struct batadv_unicast was found,
7905b0890a9SSven Eckelmann  *  FLOW_DISSECT_RET_OUT_GOOD when dissector should stop after encapsulation,
7915b0890a9SSven Eckelmann  *  otherwise FLOW_DISSECT_RET_OUT_BAD
7925b0890a9SSven Eckelmann  */
7935b0890a9SSven Eckelmann static enum flow_dissect_ret
__skb_flow_dissect_batadv(const struct sk_buff * skb,struct flow_dissector_key_control * key_control,const void * data,__be16 * p_proto,int * p_nhoff,int hlen,unsigned int flags)7945b0890a9SSven Eckelmann __skb_flow_dissect_batadv(const struct sk_buff *skb,
7955b0890a9SSven Eckelmann 			  struct flow_dissector_key_control *key_control,
796f96533cdSAlexander Lobakin 			  const void *data, __be16 *p_proto, int *p_nhoff,
797f96533cdSAlexander Lobakin 			  int hlen, unsigned int flags)
7985b0890a9SSven Eckelmann {
7995b0890a9SSven Eckelmann 	struct {
8005b0890a9SSven Eckelmann 		struct batadv_unicast_packet batadv_unicast;
8015b0890a9SSven Eckelmann 		struct ethhdr eth;
8025b0890a9SSven Eckelmann 	} *hdr, _hdr;
8035b0890a9SSven Eckelmann 
8045b0890a9SSven Eckelmann 	hdr = __skb_header_pointer(skb, *p_nhoff, sizeof(_hdr), data, hlen,
8055b0890a9SSven Eckelmann 				   &_hdr);
8065b0890a9SSven Eckelmann 	if (!hdr)
8075b0890a9SSven Eckelmann 		return FLOW_DISSECT_RET_OUT_BAD;
8085b0890a9SSven Eckelmann 
8095b0890a9SSven Eckelmann 	if (hdr->batadv_unicast.version != BATADV_COMPAT_VERSION)
8105b0890a9SSven Eckelmann 		return FLOW_DISSECT_RET_OUT_BAD;
8115b0890a9SSven Eckelmann 
8125b0890a9SSven Eckelmann 	if (hdr->batadv_unicast.packet_type != BATADV_UNICAST)
8135b0890a9SSven Eckelmann 		return FLOW_DISSECT_RET_OUT_BAD;
8145b0890a9SSven Eckelmann 
8155b0890a9SSven Eckelmann 	*p_proto = hdr->eth.h_proto;
8165b0890a9SSven Eckelmann 	*p_nhoff += sizeof(*hdr);
8175b0890a9SSven Eckelmann 
8185b0890a9SSven Eckelmann 	key_control->flags |= FLOW_DIS_ENCAPSULATION;
8195b0890a9SSven Eckelmann 	if (flags & FLOW_DISSECTOR_F_STOP_AT_ENCAP)
8205b0890a9SSven Eckelmann 		return FLOW_DISSECT_RET_OUT_GOOD;
8215b0890a9SSven Eckelmann 
8225b0890a9SSven Eckelmann 	return FLOW_DISSECT_RET_PROTO_AGAIN;
8235b0890a9SSven Eckelmann }
8245b0890a9SSven Eckelmann 
825ac4bb5deSJiri Pirko static void
__skb_flow_dissect_tcp(const struct sk_buff * skb,struct flow_dissector * flow_dissector,void * target_container,const void * data,int thoff,int hlen)826ac4bb5deSJiri Pirko __skb_flow_dissect_tcp(const struct sk_buff *skb,
827ac4bb5deSJiri Pirko 		       struct flow_dissector *flow_dissector,
828f96533cdSAlexander Lobakin 		       void *target_container, const void *data,
829f96533cdSAlexander Lobakin 		       int thoff, int hlen)
830ac4bb5deSJiri Pirko {
831ac4bb5deSJiri Pirko 	struct flow_dissector_key_tcp *key_tcp;
832ac4bb5deSJiri Pirko 	struct tcphdr *th, _th;
833ac4bb5deSJiri Pirko 
834ac4bb5deSJiri Pirko 	if (!dissector_uses_key(flow_dissector, FLOW_DISSECTOR_KEY_TCP))
835ac4bb5deSJiri Pirko 		return;
836ac4bb5deSJiri Pirko 
837ac4bb5deSJiri Pirko 	th = __skb_header_pointer(skb, thoff, sizeof(_th), data, hlen, &_th);
838ac4bb5deSJiri Pirko 	if (!th)
839ac4bb5deSJiri Pirko 		return;
840ac4bb5deSJiri Pirko 
841ac4bb5deSJiri Pirko 	if (unlikely(__tcp_hdrlen(th) < sizeof(_th)))
842ac4bb5deSJiri Pirko 		return;
843ac4bb5deSJiri Pirko 
844ac4bb5deSJiri Pirko 	key_tcp = skb_flow_dissector_target(flow_dissector,
845ac4bb5deSJiri Pirko 					    FLOW_DISSECTOR_KEY_TCP,
846ac4bb5deSJiri Pirko 					    target_container);
847ac4bb5deSJiri Pirko 	key_tcp->flags = (*(__be16 *) &tcp_flag_word(th) & htons(0x0FFF));
848ac4bb5deSJiri Pirko }
849ac4bb5deSJiri Pirko 
850518d8a2eSOr Gerlitz static void
__skb_flow_dissect_ports(const struct sk_buff * skb,struct flow_dissector * flow_dissector,void * target_container,const void * data,int nhoff,u8 ip_proto,int hlen)8518ffb055bSYoshiki Komachi __skb_flow_dissect_ports(const struct sk_buff *skb,
8528ffb055bSYoshiki Komachi 			 struct flow_dissector *flow_dissector,
853f96533cdSAlexander Lobakin 			 void *target_container, const void *data,
854f96533cdSAlexander Lobakin 			 int nhoff, u8 ip_proto, int hlen)
8558ffb055bSYoshiki Komachi {
8568ffb055bSYoshiki Komachi 	enum flow_dissector_key_id dissector_ports = FLOW_DISSECTOR_KEY_MAX;
8578ffb055bSYoshiki Komachi 	struct flow_dissector_key_ports *key_ports;
8588ffb055bSYoshiki Komachi 
8598ffb055bSYoshiki Komachi 	if (dissector_uses_key(flow_dissector, FLOW_DISSECTOR_KEY_PORTS))
8608ffb055bSYoshiki Komachi 		dissector_ports = FLOW_DISSECTOR_KEY_PORTS;
8618ffb055bSYoshiki Komachi 	else if (dissector_uses_key(flow_dissector,
8628ffb055bSYoshiki Komachi 				    FLOW_DISSECTOR_KEY_PORTS_RANGE))
8638ffb055bSYoshiki Komachi 		dissector_ports = FLOW_DISSECTOR_KEY_PORTS_RANGE;
8648ffb055bSYoshiki Komachi 
8658ffb055bSYoshiki Komachi 	if (dissector_ports == FLOW_DISSECTOR_KEY_MAX)
8668ffb055bSYoshiki Komachi 		return;
8678ffb055bSYoshiki Komachi 
8688ffb055bSYoshiki Komachi 	key_ports = skb_flow_dissector_target(flow_dissector,
8698ffb055bSYoshiki Komachi 					      dissector_ports,
8708ffb055bSYoshiki Komachi 					      target_container);
8718ffb055bSYoshiki Komachi 	key_ports->ports = __skb_flow_get_ports(skb, nhoff, ip_proto,
8728ffb055bSYoshiki Komachi 						data, hlen);
8738ffb055bSYoshiki Komachi }
8748ffb055bSYoshiki Komachi 
8758ffb055bSYoshiki Komachi static void
__skb_flow_dissect_ipv4(const struct sk_buff * skb,struct flow_dissector * flow_dissector,void * target_container,const void * data,const struct iphdr * iph)876518d8a2eSOr Gerlitz __skb_flow_dissect_ipv4(const struct sk_buff *skb,
877518d8a2eSOr Gerlitz 			struct flow_dissector *flow_dissector,
878f96533cdSAlexander Lobakin 			void *target_container, const void *data,
879f96533cdSAlexander Lobakin 			const struct iphdr *iph)
880518d8a2eSOr Gerlitz {
881518d8a2eSOr Gerlitz 	struct flow_dissector_key_ip *key_ip;
882518d8a2eSOr Gerlitz 
883518d8a2eSOr Gerlitz 	if (!dissector_uses_key(flow_dissector, FLOW_DISSECTOR_KEY_IP))
884518d8a2eSOr Gerlitz 		return;
885518d8a2eSOr Gerlitz 
886518d8a2eSOr Gerlitz 	key_ip = skb_flow_dissector_target(flow_dissector,
887518d8a2eSOr Gerlitz 					   FLOW_DISSECTOR_KEY_IP,
888518d8a2eSOr Gerlitz 					   target_container);
889518d8a2eSOr Gerlitz 	key_ip->tos = iph->tos;
890518d8a2eSOr Gerlitz 	key_ip->ttl = iph->ttl;
891518d8a2eSOr Gerlitz }
892518d8a2eSOr Gerlitz 
893518d8a2eSOr Gerlitz static void
__skb_flow_dissect_ipv6(const struct sk_buff * skb,struct flow_dissector * flow_dissector,void * target_container,const void * data,const struct ipv6hdr * iph)894518d8a2eSOr Gerlitz __skb_flow_dissect_ipv6(const struct sk_buff *skb,
895518d8a2eSOr Gerlitz 			struct flow_dissector *flow_dissector,
896f96533cdSAlexander Lobakin 			void *target_container, const void *data,
897f96533cdSAlexander Lobakin 			const struct ipv6hdr *iph)
898518d8a2eSOr Gerlitz {
899518d8a2eSOr Gerlitz 	struct flow_dissector_key_ip *key_ip;
900518d8a2eSOr Gerlitz 
901518d8a2eSOr Gerlitz 	if (!dissector_uses_key(flow_dissector, FLOW_DISSECTOR_KEY_IP))
902518d8a2eSOr Gerlitz 		return;
903518d8a2eSOr Gerlitz 
904518d8a2eSOr Gerlitz 	key_ip = skb_flow_dissector_target(flow_dissector,
905518d8a2eSOr Gerlitz 					   FLOW_DISSECTOR_KEY_IP,
906518d8a2eSOr Gerlitz 					   target_container);
907518d8a2eSOr Gerlitz 	key_ip->tos = ipv6_get_dsfield(iph);
908518d8a2eSOr Gerlitz 	key_ip->ttl = iph->hop_limit;
909518d8a2eSOr Gerlitz }
910518d8a2eSOr Gerlitz 
9111eed4dfbSTom Herbert /* Maximum number of protocol headers that can be parsed in
9121eed4dfbSTom Herbert  * __skb_flow_dissect
9131eed4dfbSTom Herbert  */
9141eed4dfbSTom Herbert #define MAX_FLOW_DISSECT_HDRS	15
9151eed4dfbSTom Herbert 
skb_flow_dissect_allowed(int * num_hdrs)9161eed4dfbSTom Herbert static bool skb_flow_dissect_allowed(int *num_hdrs)
9171eed4dfbSTom Herbert {
9181eed4dfbSTom Herbert 	++*num_hdrs;
9191eed4dfbSTom Herbert 
9201eed4dfbSTom Herbert 	return (*num_hdrs <= MAX_FLOW_DISSECT_HDRS);
9211eed4dfbSTom Herbert }
9221eed4dfbSTom Herbert 
__skb_flow_bpf_to_target(const struct bpf_flow_keys * flow_keys,struct flow_dissector * flow_dissector,void * target_container)923d58e468bSPetar Penkov static void __skb_flow_bpf_to_target(const struct bpf_flow_keys *flow_keys,
924d58e468bSPetar Penkov 				     struct flow_dissector *flow_dissector,
925d58e468bSPetar Penkov 				     void *target_container)
926d58e468bSPetar Penkov {
92759fb9b62SYoshiki Komachi 	struct flow_dissector_key_ports *key_ports = NULL;
928d58e468bSPetar Penkov 	struct flow_dissector_key_control *key_control;
929d58e468bSPetar Penkov 	struct flow_dissector_key_basic *key_basic;
930d58e468bSPetar Penkov 	struct flow_dissector_key_addrs *key_addrs;
93171c99e32SStanislav Fomichev 	struct flow_dissector_key_tags *key_tags;
932d58e468bSPetar Penkov 
933d58e468bSPetar Penkov 	key_control = skb_flow_dissector_target(flow_dissector,
934d58e468bSPetar Penkov 						FLOW_DISSECTOR_KEY_CONTROL,
935d58e468bSPetar Penkov 						target_container);
936d58e468bSPetar Penkov 	key_control->thoff = flow_keys->thoff;
937d58e468bSPetar Penkov 	if (flow_keys->is_frag)
938d58e468bSPetar Penkov 		key_control->flags |= FLOW_DIS_IS_FRAGMENT;
939d58e468bSPetar Penkov 	if (flow_keys->is_first_frag)
940d58e468bSPetar Penkov 		key_control->flags |= FLOW_DIS_FIRST_FRAG;
941d58e468bSPetar Penkov 	if (flow_keys->is_encap)
942d58e468bSPetar Penkov 		key_control->flags |= FLOW_DIS_ENCAPSULATION;
943d58e468bSPetar Penkov 
944d58e468bSPetar Penkov 	key_basic = skb_flow_dissector_target(flow_dissector,
945d58e468bSPetar Penkov 					      FLOW_DISSECTOR_KEY_BASIC,
946d58e468bSPetar Penkov 					      target_container);
947d58e468bSPetar Penkov 	key_basic->n_proto = flow_keys->n_proto;
948d58e468bSPetar Penkov 	key_basic->ip_proto = flow_keys->ip_proto;
949d58e468bSPetar Penkov 
950d58e468bSPetar Penkov 	if (flow_keys->addr_proto == ETH_P_IP &&
951d58e468bSPetar Penkov 	    dissector_uses_key(flow_dissector, FLOW_DISSECTOR_KEY_IPV4_ADDRS)) {
952d58e468bSPetar Penkov 		key_addrs = skb_flow_dissector_target(flow_dissector,
953d58e468bSPetar Penkov 						      FLOW_DISSECTOR_KEY_IPV4_ADDRS,
954d58e468bSPetar Penkov 						      target_container);
955d58e468bSPetar Penkov 		key_addrs->v4addrs.src = flow_keys->ipv4_src;
956d58e468bSPetar Penkov 		key_addrs->v4addrs.dst = flow_keys->ipv4_dst;
957d58e468bSPetar Penkov 		key_control->addr_type = FLOW_DISSECTOR_KEY_IPV4_ADDRS;
958d58e468bSPetar Penkov 	} else if (flow_keys->addr_proto == ETH_P_IPV6 &&
959d58e468bSPetar Penkov 		   dissector_uses_key(flow_dissector,
960d58e468bSPetar Penkov 				      FLOW_DISSECTOR_KEY_IPV6_ADDRS)) {
961d58e468bSPetar Penkov 		key_addrs = skb_flow_dissector_target(flow_dissector,
962d58e468bSPetar Penkov 						      FLOW_DISSECTOR_KEY_IPV6_ADDRS,
963d58e468bSPetar Penkov 						      target_container);
9641e3d976dSGustavo A. R. Silva 		memcpy(&key_addrs->v6addrs.src, &flow_keys->ipv6_src,
9651e3d976dSGustavo A. R. Silva 		       sizeof(key_addrs->v6addrs.src));
9661e3d976dSGustavo A. R. Silva 		memcpy(&key_addrs->v6addrs.dst, &flow_keys->ipv6_dst,
9671e3d976dSGustavo A. R. Silva 		       sizeof(key_addrs->v6addrs.dst));
968d58e468bSPetar Penkov 		key_control->addr_type = FLOW_DISSECTOR_KEY_IPV6_ADDRS;
969d58e468bSPetar Penkov 	}
970d58e468bSPetar Penkov 
97159fb9b62SYoshiki Komachi 	if (dissector_uses_key(flow_dissector, FLOW_DISSECTOR_KEY_PORTS))
972d58e468bSPetar Penkov 		key_ports = skb_flow_dissector_target(flow_dissector,
973d58e468bSPetar Penkov 						      FLOW_DISSECTOR_KEY_PORTS,
974d58e468bSPetar Penkov 						      target_container);
97559fb9b62SYoshiki Komachi 	else if (dissector_uses_key(flow_dissector,
97659fb9b62SYoshiki Komachi 				    FLOW_DISSECTOR_KEY_PORTS_RANGE))
97759fb9b62SYoshiki Komachi 		key_ports = skb_flow_dissector_target(flow_dissector,
97859fb9b62SYoshiki Komachi 						      FLOW_DISSECTOR_KEY_PORTS_RANGE,
97959fb9b62SYoshiki Komachi 						      target_container);
98059fb9b62SYoshiki Komachi 
98159fb9b62SYoshiki Komachi 	if (key_ports) {
982d58e468bSPetar Penkov 		key_ports->src = flow_keys->sport;
983d58e468bSPetar Penkov 		key_ports->dst = flow_keys->dport;
984d58e468bSPetar Penkov 	}
98571c99e32SStanislav Fomichev 
98671c99e32SStanislav Fomichev 	if (dissector_uses_key(flow_dissector,
98771c99e32SStanislav Fomichev 			       FLOW_DISSECTOR_KEY_FLOW_LABEL)) {
98871c99e32SStanislav Fomichev 		key_tags = skb_flow_dissector_target(flow_dissector,
98971c99e32SStanislav Fomichev 						     FLOW_DISSECTOR_KEY_FLOW_LABEL,
99071c99e32SStanislav Fomichev 						     target_container);
99171c99e32SStanislav Fomichev 		key_tags->flow_label = ntohl(flow_keys->flow_label);
99271c99e32SStanislav Fomichev 	}
993d58e468bSPetar Penkov }
994d58e468bSPetar Penkov 
bpf_flow_dissect(struct bpf_prog * prog,struct bpf_flow_dissector * ctx,__be16 proto,int nhoff,int hlen,unsigned int flags)9950ba98502SShmulik Ladkani u32 bpf_flow_dissect(struct bpf_prog *prog, struct bpf_flow_dissector *ctx,
996086f9568SStanislav Fomichev 		     __be16 proto, int nhoff, int hlen, unsigned int flags)
997089b19a9SStanislav Fomichev {
998089b19a9SStanislav Fomichev 	struct bpf_flow_keys *flow_keys = ctx->flow_keys;
999c8aa7038SStanislav Fomichev 	u32 result;
1000c8aa7038SStanislav Fomichev 
1001c8aa7038SStanislav Fomichev 	/* Pass parameters to the BPF program */
1002c8aa7038SStanislav Fomichev 	memset(flow_keys, 0, sizeof(*flow_keys));
1003089b19a9SStanislav Fomichev 	flow_keys->n_proto = proto;
1004089b19a9SStanislav Fomichev 	flow_keys->nhoff = nhoff;
1005c8aa7038SStanislav Fomichev 	flow_keys->thoff = flow_keys->nhoff;
1006c8aa7038SStanislav Fomichev 
1007086f9568SStanislav Fomichev 	BUILD_BUG_ON((int)BPF_FLOW_DISSECTOR_F_PARSE_1ST_FRAG !=
1008086f9568SStanislav Fomichev 		     (int)FLOW_DISSECTOR_F_PARSE_1ST_FRAG);
1009086f9568SStanislav Fomichev 	BUILD_BUG_ON((int)BPF_FLOW_DISSECTOR_F_STOP_AT_FLOW_LABEL !=
1010086f9568SStanislav Fomichev 		     (int)FLOW_DISSECTOR_F_STOP_AT_FLOW_LABEL);
1011086f9568SStanislav Fomichev 	BUILD_BUG_ON((int)BPF_FLOW_DISSECTOR_F_STOP_AT_ENCAP !=
1012086f9568SStanislav Fomichev 		     (int)FLOW_DISSECTOR_F_STOP_AT_ENCAP);
1013086f9568SStanislav Fomichev 	flow_keys->flags = flags;
1014086f9568SStanislav Fomichev 
10153d9f773cSDavid Miller 	result = bpf_prog_run_pin_on_cpu(prog, ctx);
1016c8aa7038SStanislav Fomichev 
1017089b19a9SStanislav Fomichev 	flow_keys->nhoff = clamp_t(u16, flow_keys->nhoff, nhoff, hlen);
1018c8aa7038SStanislav Fomichev 	flow_keys->thoff = clamp_t(u16, flow_keys->thoff,
1019089b19a9SStanislav Fomichev 				   flow_keys->nhoff, hlen);
1020c8aa7038SStanislav Fomichev 
10210ba98502SShmulik Ladkani 	return result;
1022c8aa7038SStanislav Fomichev }
1023c8aa7038SStanislav Fomichev 
is_pppoe_ses_hdr_valid(const struct pppoe_hdr * hdr)1024f86d1fbbSLinus Torvalds static bool is_pppoe_ses_hdr_valid(const struct pppoe_hdr *hdr)
102546126db9SWojciech Drewek {
1026f86d1fbbSLinus Torvalds 	return hdr->ver == 1 && hdr->type == 1 && hdr->code == 0;
102746126db9SWojciech Drewek }
102846126db9SWojciech Drewek 
1029453a940eSWANG Cong /**
1030453a940eSWANG Cong  * __skb_flow_dissect - extract the flow_keys struct and return it
10313cbf4ffbSStanislav Fomichev  * @net: associated network namespace, derived from @skb if NULL
1032453a940eSWANG Cong  * @skb: sk_buff to extract the flow from, can be NULL if the rest are specified
103306635a35SJiri Pirko  * @flow_dissector: list of keys to dissect
103406635a35SJiri Pirko  * @target_container: target structure to put dissected values into
1035453a940eSWANG Cong  * @data: raw buffer pointer to the packet, if NULL use skb->data
1036453a940eSWANG Cong  * @proto: protocol for which to get the flow, if @data is NULL use skb->protocol
1037453a940eSWANG Cong  * @nhoff: network header offset, if @data is NULL use skb_network_offset(skb)
1038453a940eSWANG Cong  * @hlen: packet header length, if @data is NULL use skb_headlen(skb)
1039d79b3bafSBart Van Assche  * @flags: flags that control the dissection process, e.g.
10401cc26450SStanislav Fomichev  *         FLOW_DISSECTOR_F_STOP_AT_ENCAP.
1041453a940eSWANG Cong  *
104206635a35SJiri Pirko  * The function will try to retrieve individual keys into target specified
104306635a35SJiri Pirko  * by flow_dissector from either the skbuff or a raw buffer specified by the
104406635a35SJiri Pirko  * rest parameters.
104506635a35SJiri Pirko  *
104606635a35SJiri Pirko  * Caller must take care of zeroing target container memory.
1047453a940eSWANG Cong  */
__skb_flow_dissect(const struct net * net,const struct sk_buff * skb,struct flow_dissector * flow_dissector,void * target_container,const void * data,__be16 proto,int nhoff,int hlen,unsigned int flags)10483cbf4ffbSStanislav Fomichev bool __skb_flow_dissect(const struct net *net,
10493cbf4ffbSStanislav Fomichev 			const struct sk_buff *skb,
105006635a35SJiri Pirko 			struct flow_dissector *flow_dissector,
1051f96533cdSAlexander Lobakin 			void *target_container, const void *data,
1052f96533cdSAlexander Lobakin 			__be16 proto, int nhoff, int hlen, unsigned int flags)
10530744dd00SEric Dumazet {
105442aecaa9STom Herbert 	struct flow_dissector_key_control *key_control;
105506635a35SJiri Pirko 	struct flow_dissector_key_basic *key_basic;
105606635a35SJiri Pirko 	struct flow_dissector_key_addrs *key_addrs;
1057d34af823STom Herbert 	struct flow_dissector_key_tags *key_tags;
1058f6a66927SHadar Hen Zion 	struct flow_dissector_key_vlan *key_vlan;
10593a1214e8STom Herbert 	enum flow_dissect_ret fdret;
106024c590e3SJianbo Liu 	enum flow_dissector_key_id dissector_vlan = FLOW_DISSECTOR_KEY_MAX;
106158cff782SGuillaume Nault 	bool mpls_el = false;
106258cff782SGuillaume Nault 	int mpls_lse = 0;
10631eed4dfbSTom Herbert 	int num_hdrs = 0;
10648e690ffdSGeert Uytterhoeven 	u8 ip_proto = 0;
106534fad54cSEric Dumazet 	bool ret;
10660744dd00SEric Dumazet 
1067690e36e7SDavid S. Miller 	if (!data) {
1068690e36e7SDavid S. Miller 		data = skb->data;
1069d5709f7aSHadar Hen Zion 		proto = skb_vlan_tag_present(skb) ?
1070d5709f7aSHadar Hen Zion 			 skb->vlan_proto : skb->protocol;
1071453a940eSWANG Cong 		nhoff = skb_network_offset(skb);
1072690e36e7SDavid S. Miller 		hlen = skb_headlen(skb);
10732d571645SJohn Crispin #if IS_ENABLED(CONFIG_NET_DSA)
10748bef0af0SAlexander Lobakin 		if (unlikely(skb->dev && netdev_uses_dsa(skb->dev) &&
10758bef0af0SAlexander Lobakin 			     proto == htons(ETH_P_XDSA))) {
1076570d0a58SFelix Fietkau 			struct metadata_dst *md_dst = skb_metadata_dst(skb);
107743e66528SJohn Crispin 			const struct dsa_device_ops *ops;
10788bef0af0SAlexander Lobakin 			int offset = 0;
107943e66528SJohn Crispin 
108043e66528SJohn Crispin 			ops = skb->dev->dsa_ptr->tag_ops;
1081ec133572SVladimir Oltean 			/* Only DSA header taggers break flow dissection */
1082570d0a58SFelix Fietkau 			if (ops->needed_headroom &&
1083570d0a58SFelix Fietkau 			    (!md_dst || md_dst->type != METADATA_HW_PORT_MUX)) {
108454fec335SVladimir Oltean 				if (ops->flow_dissect)
10852e8cb1b3SVladimir Oltean 					ops->flow_dissect(skb, &proto, &offset);
108654fec335SVladimir Oltean 				else
108754fec335SVladimir Oltean 					dsa_tag_generic_flow_dissect(skb,
108854fec335SVladimir Oltean 								     &proto,
108954fec335SVladimir Oltean 								     &offset);
109043e66528SJohn Crispin 				hlen -= offset;
109143e66528SJohn Crispin 				nhoff += offset;
109243e66528SJohn Crispin 			}
109343e66528SJohn Crispin 		}
10942d571645SJohn Crispin #endif
1095690e36e7SDavid S. Miller 	}
1096690e36e7SDavid S. Miller 
109742aecaa9STom Herbert 	/* It is ensured by skb_flow_dissector_init() that control key will
109842aecaa9STom Herbert 	 * be always present.
109942aecaa9STom Herbert 	 */
110042aecaa9STom Herbert 	key_control = skb_flow_dissector_target(flow_dissector,
110142aecaa9STom Herbert 						FLOW_DISSECTOR_KEY_CONTROL,
110242aecaa9STom Herbert 						target_container);
110342aecaa9STom Herbert 
110406635a35SJiri Pirko 	/* It is ensured by skb_flow_dissector_init() that basic key will
110506635a35SJiri Pirko 	 * be always present.
110606635a35SJiri Pirko 	 */
110706635a35SJiri Pirko 	key_basic = skb_flow_dissector_target(flow_dissector,
110806635a35SJiri Pirko 					      FLOW_DISSECTOR_KEY_BASIC,
110906635a35SJiri Pirko 					      target_container);
11100744dd00SEric Dumazet 
1111d0e13a14SWillem de Bruijn 	if (skb) {
11123cbf4ffbSStanislav Fomichev 		if (!net) {
1113d0e13a14SWillem de Bruijn 			if (skb->dev)
11143cbf4ffbSStanislav Fomichev 				net = dev_net(skb->dev);
1115d0e13a14SWillem de Bruijn 			else if (skb->sk)
11163cbf4ffbSStanislav Fomichev 				net = sock_net(skb->sk);
11179b52e3f2SStanislav Fomichev 		}
11183cbf4ffbSStanislav Fomichev 	}
11193cbf4ffbSStanislav Fomichev 
1120*120f1c85SPablo Neira Ayuso 	DEBUG_NET_WARN_ON_ONCE(!net);
11219b52e3f2SStanislav Fomichev 	if (net) {
1122a3fd7ceeSJakub Sitnicki 		enum netns_bpf_attach_type type = NETNS_BPF_FLOW_DISSECTOR;
1123695c1214SJakub Sitnicki 		struct bpf_prog_array *run_array;
1124a3fd7ceeSJakub Sitnicki 
11259b52e3f2SStanislav Fomichev 		rcu_read_lock();
1126695c1214SJakub Sitnicki 		run_array = rcu_dereference(init_net.bpf.run_array[type]);
1127695c1214SJakub Sitnicki 		if (!run_array)
1128695c1214SJakub Sitnicki 			run_array = rcu_dereference(net->bpf.run_array[type]);
1129a11c397cSStanislav Fomichev 
1130695c1214SJakub Sitnicki 		if (run_array) {
11319b52e3f2SStanislav Fomichev 			struct bpf_flow_keys flow_keys;
11329b52e3f2SStanislav Fomichev 			struct bpf_flow_dissector ctx = {
11339b52e3f2SStanislav Fomichev 				.flow_keys = &flow_keys,
11349b52e3f2SStanislav Fomichev 				.data = data,
11359b52e3f2SStanislav Fomichev 				.data_end = data + hlen,
11369b52e3f2SStanislav Fomichev 			};
11379b52e3f2SStanislav Fomichev 			__be16 n_proto = proto;
1138695c1214SJakub Sitnicki 			struct bpf_prog *prog;
11390ba98502SShmulik Ladkani 			u32 result;
11409b52e3f2SStanislav Fomichev 
11419b52e3f2SStanislav Fomichev 			if (skb) {
11429b52e3f2SStanislav Fomichev 				ctx.skb = skb;
11439b52e3f2SStanislav Fomichev 				/* we can't use 'proto' in the skb case
11449b52e3f2SStanislav Fomichev 				 * because it might be set to skb->vlan_proto
11459b52e3f2SStanislav Fomichev 				 * which has been pulled from the data
11469b52e3f2SStanislav Fomichev 				 */
11479b52e3f2SStanislav Fomichev 				n_proto = skb->protocol;
11489b52e3f2SStanislav Fomichev 			}
11499b52e3f2SStanislav Fomichev 
1150695c1214SJakub Sitnicki 			prog = READ_ONCE(run_array->items[0].prog);
11510ba98502SShmulik Ladkani 			result = bpf_flow_dissect(prog, &ctx, n_proto, nhoff,
1152086f9568SStanislav Fomichev 						  hlen, flags);
115391350fe1SShmulik Ladkani 			if (result == BPF_FLOW_DISSECTOR_CONTINUE)
115491350fe1SShmulik Ladkani 				goto dissect_continue;
1155d58e468bSPetar Penkov 			__skb_flow_bpf_to_target(&flow_keys, flow_dissector,
1156d58e468bSPetar Penkov 						 target_container);
1157d58e468bSPetar Penkov 			rcu_read_unlock();
11580ba98502SShmulik Ladkani 			return result == BPF_OK;
1159d58e468bSPetar Penkov 		}
116091350fe1SShmulik Ladkani dissect_continue:
1161d58e468bSPetar Penkov 		rcu_read_unlock();
1162c8aa7038SStanislav Fomichev 	}
1163d58e468bSPetar Penkov 
116420a17bf6SDavid S. Miller 	if (dissector_uses_key(flow_dissector,
116567a900ccSJiri Pirko 			       FLOW_DISSECTOR_KEY_ETH_ADDRS)) {
116667a900ccSJiri Pirko 		struct ethhdr *eth = eth_hdr(skb);
116767a900ccSJiri Pirko 		struct flow_dissector_key_eth_addrs *key_eth_addrs;
116867a900ccSJiri Pirko 
116967a900ccSJiri Pirko 		key_eth_addrs = skb_flow_dissector_target(flow_dissector,
117067a900ccSJiri Pirko 							  FLOW_DISSECTOR_KEY_ETH_ADDRS,
117167a900ccSJiri Pirko 							  target_container);
11721b808993SJakub Kicinski 		memcpy(key_eth_addrs, eth, sizeof(*key_eth_addrs));
117367a900ccSJiri Pirko 	}
117467a900ccSJiri Pirko 
117534951fcfSBoris Sukholitko 	if (dissector_uses_key(flow_dissector,
117634951fcfSBoris Sukholitko 			       FLOW_DISSECTOR_KEY_NUM_OF_VLANS)) {
117734951fcfSBoris Sukholitko 		struct flow_dissector_key_num_of_vlans *key_num_of_vlans;
117834951fcfSBoris Sukholitko 
117934951fcfSBoris Sukholitko 		key_num_of_vlans = skb_flow_dissector_target(flow_dissector,
118034951fcfSBoris Sukholitko 							     FLOW_DISSECTOR_KEY_NUM_OF_VLANS,
118134951fcfSBoris Sukholitko 							     target_container);
118234951fcfSBoris Sukholitko 		key_num_of_vlans->num_of_vlans = 0;
118334951fcfSBoris Sukholitko 	}
118434951fcfSBoris Sukholitko 
1185c5ef188eSJiri Pirko proto_again:
11863a1214e8STom Herbert 	fdret = FLOW_DISSECT_RET_CONTINUE;
11873a1214e8STom Herbert 
11880744dd00SEric Dumazet 	switch (proto) {
11892b8837aeSJoe Perches 	case htons(ETH_P_IP): {
11900744dd00SEric Dumazet 		const struct iphdr *iph;
11910744dd00SEric Dumazet 		struct iphdr _iph;
11923a1214e8STom Herbert 
1193690e36e7SDavid S. Miller 		iph = __skb_header_pointer(skb, nhoff, sizeof(_iph), data, hlen, &_iph);
11943a1214e8STom Herbert 		if (!iph || iph->ihl < 5) {
11953a1214e8STom Herbert 			fdret = FLOW_DISSECT_RET_OUT_BAD;
11963a1214e8STom Herbert 			break;
11973a1214e8STom Herbert 		}
11983a1214e8STom Herbert 
11993797d3e8SEric Dumazet 		nhoff += iph->ihl * 4;
12000744dd00SEric Dumazet 
12013797d3e8SEric Dumazet 		ip_proto = iph->protocol;
12023797d3e8SEric Dumazet 
1203918c023fSAlexander Duyck 		if (dissector_uses_key(flow_dissector,
1204918c023fSAlexander Duyck 				       FLOW_DISSECTOR_KEY_IPV4_ADDRS)) {
120506635a35SJiri Pirko 			key_addrs = skb_flow_dissector_target(flow_dissector,
1206918c023fSAlexander Duyck 							      FLOW_DISSECTOR_KEY_IPV4_ADDRS,
1207918c023fSAlexander Duyck 							      target_container);
1208918c023fSAlexander Duyck 
1209323e0cb4SGustavo A. R. Silva 			memcpy(&key_addrs->v4addrs.src, &iph->saddr,
1210323e0cb4SGustavo A. R. Silva 			       sizeof(key_addrs->v4addrs.src));
1211323e0cb4SGustavo A. R. Silva 			memcpy(&key_addrs->v4addrs.dst, &iph->daddr,
1212323e0cb4SGustavo A. R. Silva 			       sizeof(key_addrs->v4addrs.dst));
1213c3f83241STom Herbert 			key_control->addr_type = FLOW_DISSECTOR_KEY_IPV4_ADDRS;
1214918c023fSAlexander Duyck 		}
1215807e165dSTom Herbert 
1216d2126838SDavide Caratti 		__skb_flow_dissect_ipv4(skb, flow_dissector,
1217d2126838SDavide Caratti 					target_container, data, iph);
1218d2126838SDavide Caratti 
1219807e165dSTom Herbert 		if (ip_is_fragment(iph)) {
12204b36993dSDavid S. Miller 			key_control->flags |= FLOW_DIS_IS_FRAGMENT;
1221807e165dSTom Herbert 
1222807e165dSTom Herbert 			if (iph->frag_off & htons(IP_OFFSET)) {
12233a1214e8STom Herbert 				fdret = FLOW_DISSECT_RET_OUT_GOOD;
12243a1214e8STom Herbert 				break;
1225807e165dSTom Herbert 			} else {
12264b36993dSDavid S. Miller 				key_control->flags |= FLOW_DIS_FIRST_FRAG;
12273a1214e8STom Herbert 				if (!(flags &
12283a1214e8STom Herbert 				      FLOW_DISSECTOR_F_PARSE_1ST_FRAG)) {
12293a1214e8STom Herbert 					fdret = FLOW_DISSECT_RET_OUT_GOOD;
12303a1214e8STom Herbert 					break;
12313a1214e8STom Herbert 				}
1232807e165dSTom Herbert 			}
1233807e165dSTom Herbert 		}
1234807e165dSTom Herbert 
12350744dd00SEric Dumazet 		break;
12360744dd00SEric Dumazet 	}
12372b8837aeSJoe Perches 	case htons(ETH_P_IPV6): {
12380744dd00SEric Dumazet 		const struct ipv6hdr *iph;
12390744dd00SEric Dumazet 		struct ipv6hdr _iph;
124019469a87STom Herbert 
1241690e36e7SDavid S. Miller 		iph = __skb_header_pointer(skb, nhoff, sizeof(_iph), data, hlen, &_iph);
12423a1214e8STom Herbert 		if (!iph) {
12433a1214e8STom Herbert 			fdret = FLOW_DISSECT_RET_OUT_BAD;
12443a1214e8STom Herbert 			break;
12453a1214e8STom Herbert 		}
12460744dd00SEric Dumazet 
12470744dd00SEric Dumazet 		ip_proto = iph->nexthdr;
12480744dd00SEric Dumazet 		nhoff += sizeof(struct ipv6hdr);
124919469a87STom Herbert 
125020a17bf6SDavid S. Miller 		if (dissector_uses_key(flow_dissector,
1251b924933cSJiri Pirko 				       FLOW_DISSECTOR_KEY_IPV6_ADDRS)) {
1252b3c3106cSAlexander Duyck 			key_addrs = skb_flow_dissector_target(flow_dissector,
1253b924933cSJiri Pirko 							      FLOW_DISSECTOR_KEY_IPV6_ADDRS,
1254b924933cSJiri Pirko 							      target_container);
1255b924933cSJiri Pirko 
1256323e0cb4SGustavo A. R. Silva 			memcpy(&key_addrs->v6addrs.src, &iph->saddr,
1257323e0cb4SGustavo A. R. Silva 			       sizeof(key_addrs->v6addrs.src));
1258323e0cb4SGustavo A. R. Silva 			memcpy(&key_addrs->v6addrs.dst, &iph->daddr,
1259323e0cb4SGustavo A. R. Silva 			       sizeof(key_addrs->v6addrs.dst));
1260c3f83241STom Herbert 			key_control->addr_type = FLOW_DISSECTOR_KEY_IPV6_ADDRS;
1261b924933cSJiri Pirko 		}
126287ee9e52STom Herbert 
1263461547f3SAlexander Duyck 		if ((dissector_uses_key(flow_dissector,
1264461547f3SAlexander Duyck 					FLOW_DISSECTOR_KEY_FLOW_LABEL) ||
1265461547f3SAlexander Duyck 		     (flags & FLOW_DISSECTOR_F_STOP_AT_FLOW_LABEL)) &&
1266461547f3SAlexander Duyck 		    ip6_flowlabel(iph)) {
1267461547f3SAlexander Duyck 			__be32 flow_label = ip6_flowlabel(iph);
1268461547f3SAlexander Duyck 
126920a17bf6SDavid S. Miller 			if (dissector_uses_key(flow_dissector,
127087ee9e52STom Herbert 					       FLOW_DISSECTOR_KEY_FLOW_LABEL)) {
127187ee9e52STom Herbert 				key_tags = skb_flow_dissector_target(flow_dissector,
127287ee9e52STom Herbert 								     FLOW_DISSECTOR_KEY_FLOW_LABEL,
127306635a35SJiri Pirko 								     target_container);
127487ee9e52STom Herbert 				key_tags->flow_label = ntohl(flow_label);
127512c227ecSJiri Pirko 			}
12763a1214e8STom Herbert 			if (flags & FLOW_DISSECTOR_F_STOP_AT_FLOW_LABEL) {
12773a1214e8STom Herbert 				fdret = FLOW_DISSECT_RET_OUT_GOOD;
12783a1214e8STom Herbert 				break;
12793a1214e8STom Herbert 			}
128019469a87STom Herbert 		}
128119469a87STom Herbert 
1282518d8a2eSOr Gerlitz 		__skb_flow_dissect_ipv6(skb, flow_dissector,
1283518d8a2eSOr Gerlitz 					target_container, data, iph);
1284518d8a2eSOr Gerlitz 
12850744dd00SEric Dumazet 		break;
12860744dd00SEric Dumazet 	}
12872b8837aeSJoe Perches 	case htons(ETH_P_8021AD):
12882b8837aeSJoe Perches 	case htons(ETH_P_8021Q): {
128924c590e3SJianbo Liu 		const struct vlan_hdr *vlan = NULL;
1290bc72f3ddSArnd Bergmann 		struct vlan_hdr _vlan;
12912064c3d4SJianbo Liu 		__be16 saved_vlan_tpid = proto;
1292d5709f7aSHadar Hen Zion 
129324c590e3SJianbo Liu 		if (dissector_vlan == FLOW_DISSECTOR_KEY_MAX &&
129424c590e3SJianbo Liu 		    skb && skb_vlan_tag_present(skb)) {
1295d5709f7aSHadar Hen Zion 			proto = skb->protocol;
129624c590e3SJianbo Liu 		} else {
1297d5709f7aSHadar Hen Zion 			vlan = __skb_header_pointer(skb, nhoff, sizeof(_vlan),
1298d5709f7aSHadar Hen Zion 						    data, hlen, &_vlan);
12993a1214e8STom Herbert 			if (!vlan) {
13003a1214e8STom Herbert 				fdret = FLOW_DISSECT_RET_OUT_BAD;
13013a1214e8STom Herbert 				break;
13023a1214e8STom Herbert 			}
13033a1214e8STom Herbert 
1304d5709f7aSHadar Hen Zion 			proto = vlan->h_vlan_encapsulated_proto;
1305d5709f7aSHadar Hen Zion 			nhoff += sizeof(*vlan);
130624c590e3SJianbo Liu 		}
130724c590e3SJianbo Liu 
13089f87eb42SQingqing Yang 		if (dissector_uses_key(flow_dissector, FLOW_DISSECTOR_KEY_NUM_OF_VLANS) &&
13099f87eb42SQingqing Yang 		    !(key_control->flags & FLOW_DIS_ENCAPSULATION)) {
131034951fcfSBoris Sukholitko 			struct flow_dissector_key_num_of_vlans *key_nvs;
131134951fcfSBoris Sukholitko 
131234951fcfSBoris Sukholitko 			key_nvs = skb_flow_dissector_target(flow_dissector,
131334951fcfSBoris Sukholitko 							    FLOW_DISSECTOR_KEY_NUM_OF_VLANS,
131434951fcfSBoris Sukholitko 							    target_container);
131534951fcfSBoris Sukholitko 			key_nvs->num_of_vlans++;
131634951fcfSBoris Sukholitko 		}
131734951fcfSBoris Sukholitko 
131824c590e3SJianbo Liu 		if (dissector_vlan == FLOW_DISSECTOR_KEY_MAX) {
131924c590e3SJianbo Liu 			dissector_vlan = FLOW_DISSECTOR_KEY_VLAN;
132024c590e3SJianbo Liu 		} else if (dissector_vlan == FLOW_DISSECTOR_KEY_VLAN) {
132124c590e3SJianbo Liu 			dissector_vlan = FLOW_DISSECTOR_KEY_CVLAN;
132224c590e3SJianbo Liu 		} else {
13233a1214e8STom Herbert 			fdret = FLOW_DISSECT_RET_PROTO_AGAIN;
13243a1214e8STom Herbert 			break;
13253a1214e8STom Herbert 		}
13260744dd00SEric Dumazet 
132724c590e3SJianbo Liu 		if (dissector_uses_key(flow_dissector, dissector_vlan)) {
1328f6a66927SHadar Hen Zion 			key_vlan = skb_flow_dissector_target(flow_dissector,
132924c590e3SJianbo Liu 							     dissector_vlan,
1330d34af823STom Herbert 							     target_container);
1331d34af823STom Herbert 
133224c590e3SJianbo Liu 			if (!vlan) {
1333f6a66927SHadar Hen Zion 				key_vlan->vlan_id = skb_vlan_tag_get_id(skb);
13349b319148SMichał Mirosław 				key_vlan->vlan_priority = skb_vlan_tag_get_prio(skb);
1335f6a66927SHadar Hen Zion 			} else {
1336f6a66927SHadar Hen Zion 				key_vlan->vlan_id = ntohs(vlan->h_vlan_TCI) &
1337d5709f7aSHadar Hen Zion 					VLAN_VID_MASK;
1338f6a66927SHadar Hen Zion 				key_vlan->vlan_priority =
1339f6a66927SHadar Hen Zion 					(ntohs(vlan->h_vlan_TCI) &
1340f6a66927SHadar Hen Zion 					 VLAN_PRIO_MASK) >> VLAN_PRIO_SHIFT;
1341f6a66927SHadar Hen Zion 			}
13422064c3d4SJianbo Liu 			key_vlan->vlan_tpid = saved_vlan_tpid;
13432105f700SVlad Buslov 			key_vlan->vlan_eth_type = proto;
1344d34af823STom Herbert 		}
1345d34af823STom Herbert 
13463a1214e8STom Herbert 		fdret = FLOW_DISSECT_RET_PROTO_AGAIN;
13473a1214e8STom Herbert 		break;
13480744dd00SEric Dumazet 	}
13492b8837aeSJoe Perches 	case htons(ETH_P_PPP_SES): {
13500744dd00SEric Dumazet 		struct {
13510744dd00SEric Dumazet 			struct pppoe_hdr hdr;
13520744dd00SEric Dumazet 			__be16 proto;
13530744dd00SEric Dumazet 		} *hdr, _hdr;
135446126db9SWojciech Drewek 		u16 ppp_proto;
135546126db9SWojciech Drewek 
1356690e36e7SDavid S. Miller 		hdr = __skb_header_pointer(skb, nhoff, sizeof(_hdr), data, hlen, &_hdr);
13573a1214e8STom Herbert 		if (!hdr) {
13583a1214e8STom Herbert 			fdret = FLOW_DISSECT_RET_OUT_BAD;
13593a1214e8STom Herbert 			break;
13603a1214e8STom Herbert 		}
13613a1214e8STom Herbert 
1362f86d1fbbSLinus Torvalds 		if (!is_pppoe_ses_hdr_valid(&hdr->hdr)) {
13633a1214e8STom Herbert 			fdret = FLOW_DISSECT_RET_OUT_BAD;
13643a1214e8STom Herbert 			break;
13650744dd00SEric Dumazet 		}
136646126db9SWojciech Drewek 
136746126db9SWojciech Drewek 		/* least significant bit of the most significant octet
136846126db9SWojciech Drewek 		 * indicates if protocol field was compressed
136946126db9SWojciech Drewek 		 */
137046126db9SWojciech Drewek 		ppp_proto = ntohs(hdr->proto);
137146126db9SWojciech Drewek 		if (ppp_proto & 0x0100) {
137246126db9SWojciech Drewek 			ppp_proto = ppp_proto >> 8;
137346126db9SWojciech Drewek 			nhoff += PPPOE_SES_HLEN - 1;
137446126db9SWojciech Drewek 		} else {
137546126db9SWojciech Drewek 			nhoff += PPPOE_SES_HLEN;
137646126db9SWojciech Drewek 		}
137746126db9SWojciech Drewek 
137846126db9SWojciech Drewek 		if (ppp_proto == PPP_IP) {
137946126db9SWojciech Drewek 			proto = htons(ETH_P_IP);
138046126db9SWojciech Drewek 			fdret = FLOW_DISSECT_RET_PROTO_AGAIN;
138146126db9SWojciech Drewek 		} else if (ppp_proto == PPP_IPV6) {
138246126db9SWojciech Drewek 			proto = htons(ETH_P_IPV6);
138346126db9SWojciech Drewek 			fdret = FLOW_DISSECT_RET_PROTO_AGAIN;
138446126db9SWojciech Drewek 		} else if (ppp_proto == PPP_MPLS_UC) {
138546126db9SWojciech Drewek 			proto = htons(ETH_P_MPLS_UC);
138646126db9SWojciech Drewek 			fdret = FLOW_DISSECT_RET_PROTO_AGAIN;
138746126db9SWojciech Drewek 		} else if (ppp_proto == PPP_MPLS_MC) {
138846126db9SWojciech Drewek 			proto = htons(ETH_P_MPLS_MC);
138946126db9SWojciech Drewek 			fdret = FLOW_DISSECT_RET_PROTO_AGAIN;
139046126db9SWojciech Drewek 		} else if (ppp_proto_is_valid(ppp_proto)) {
139146126db9SWojciech Drewek 			fdret = FLOW_DISSECT_RET_OUT_GOOD;
139246126db9SWojciech Drewek 		} else {
139346126db9SWojciech Drewek 			fdret = FLOW_DISSECT_RET_OUT_BAD;
139446126db9SWojciech Drewek 			break;
139546126db9SWojciech Drewek 		}
139646126db9SWojciech Drewek 
139746126db9SWojciech Drewek 		if (dissector_uses_key(flow_dissector,
139846126db9SWojciech Drewek 				       FLOW_DISSECTOR_KEY_PPPOE)) {
139946126db9SWojciech Drewek 			struct flow_dissector_key_pppoe *key_pppoe;
140046126db9SWojciech Drewek 
140146126db9SWojciech Drewek 			key_pppoe = skb_flow_dissector_target(flow_dissector,
140246126db9SWojciech Drewek 							      FLOW_DISSECTOR_KEY_PPPOE,
140346126db9SWojciech Drewek 							      target_container);
140446126db9SWojciech Drewek 			key_pppoe->session_id = hdr->hdr.sid;
140546126db9SWojciech Drewek 			key_pppoe->ppp_proto = htons(ppp_proto);
140646126db9SWojciech Drewek 			key_pppoe->type = htons(ETH_P_PPP_SES);
140746126db9SWojciech Drewek 		}
14083a1214e8STom Herbert 		break;
14090744dd00SEric Dumazet 	}
141008bfc9cbSErik Hugne 	case htons(ETH_P_TIPC): {
14118d6e79d3SJon Maloy 		struct tipc_basic_hdr *hdr, _hdr;
14128d6e79d3SJon Maloy 
14138d6e79d3SJon Maloy 		hdr = __skb_header_pointer(skb, nhoff, sizeof(_hdr),
14148d6e79d3SJon Maloy 					   data, hlen, &_hdr);
14153a1214e8STom Herbert 		if (!hdr) {
14163a1214e8STom Herbert 			fdret = FLOW_DISSECT_RET_OUT_BAD;
14173a1214e8STom Herbert 			break;
14183a1214e8STom Herbert 		}
141906635a35SJiri Pirko 
142020a17bf6SDavid S. Miller 		if (dissector_uses_key(flow_dissector,
14218d6e79d3SJon Maloy 				       FLOW_DISSECTOR_KEY_TIPC)) {
142206635a35SJiri Pirko 			key_addrs = skb_flow_dissector_target(flow_dissector,
14238d6e79d3SJon Maloy 							      FLOW_DISSECTOR_KEY_TIPC,
142406635a35SJiri Pirko 							      target_container);
14258d6e79d3SJon Maloy 			key_addrs->tipckey.key = tipc_hdr_rps_key(hdr);
14268d6e79d3SJon Maloy 			key_control->addr_type = FLOW_DISSECTOR_KEY_TIPC;
142706635a35SJiri Pirko 		}
14283a1214e8STom Herbert 		fdret = FLOW_DISSECT_RET_OUT_GOOD;
14293a1214e8STom Herbert 		break;
143008bfc9cbSErik Hugne 	}
1431b3baa0fbSTom Herbert 
1432b3baa0fbSTom Herbert 	case htons(ETH_P_MPLS_UC):
14334a5d6c8bSJiri Pirko 	case htons(ETH_P_MPLS_MC):
14343a1214e8STom Herbert 		fdret = __skb_flow_dissect_mpls(skb, flow_dissector,
14354a5d6c8bSJiri Pirko 						target_container, data,
143658cff782SGuillaume Nault 						nhoff, hlen, mpls_lse,
143758cff782SGuillaume Nault 						&mpls_el);
143858cff782SGuillaume Nault 		nhoff += sizeof(struct mpls_label);
143958cff782SGuillaume Nault 		mpls_lse++;
14403a1214e8STom Herbert 		break;
144156193d1bSAlexander Duyck 	case htons(ETH_P_FCOE):
14423a1214e8STom Herbert 		if ((hlen - nhoff) < FCOE_HEADER_LEN) {
14433a1214e8STom Herbert 			fdret = FLOW_DISSECT_RET_OUT_BAD;
14443a1214e8STom Herbert 			break;
14453a1214e8STom Herbert 		}
1446224516b3SAlexander Duyck 
1447224516b3SAlexander Duyck 		nhoff += FCOE_HEADER_LEN;
14483a1214e8STom Herbert 		fdret = FLOW_DISSECT_RET_OUT_GOOD;
14493a1214e8STom Herbert 		break;
145055733350SSimon Horman 
145155733350SSimon Horman 	case htons(ETH_P_ARP):
14529bf881ffSJiri Pirko 	case htons(ETH_P_RARP):
14533a1214e8STom Herbert 		fdret = __skb_flow_dissect_arp(skb, flow_dissector,
14549bf881ffSJiri Pirko 					       target_container, data,
14553a1214e8STom Herbert 					       nhoff, hlen);
14563a1214e8STom Herbert 		break;
14573a1214e8STom Herbert 
14585b0890a9SSven Eckelmann 	case htons(ETH_P_BATMAN):
14595b0890a9SSven Eckelmann 		fdret = __skb_flow_dissect_batadv(skb, key_control, data,
14605b0890a9SSven Eckelmann 						  &proto, &nhoff, hlen, flags);
14615b0890a9SSven Eckelmann 		break;
14625b0890a9SSven Eckelmann 
14634f1cc51fSEran Ben Elisha 	case htons(ETH_P_1588): {
14644f1cc51fSEran Ben Elisha 		struct ptp_header *hdr, _hdr;
14654f1cc51fSEran Ben Elisha 
14664f1cc51fSEran Ben Elisha 		hdr = __skb_header_pointer(skb, nhoff, sizeof(_hdr), data,
14674f1cc51fSEran Ben Elisha 					   hlen, &_hdr);
14684f1cc51fSEran Ben Elisha 		if (!hdr) {
14694f1cc51fSEran Ben Elisha 			fdret = FLOW_DISSECT_RET_OUT_BAD;
14704f1cc51fSEran Ben Elisha 			break;
14714f1cc51fSEran Ben Elisha 		}
14724f1cc51fSEran Ben Elisha 
147375ad80edSSasha Neftin 		nhoff += sizeof(struct ptp_header);
14744f1cc51fSEran Ben Elisha 		fdret = FLOW_DISSECT_RET_OUT_GOOD;
14754f1cc51fSEran Ben Elisha 		break;
14764f1cc51fSEran Ben Elisha 	}
14774f1cc51fSEran Ben Elisha 
1478f65e5844SKurt Kanzenbach 	case htons(ETH_P_PRP):
1479bf08824aSKurt Kanzenbach 	case htons(ETH_P_HSR): {
1480bf08824aSKurt Kanzenbach 		struct hsr_tag *hdr, _hdr;
1481bf08824aSKurt Kanzenbach 
1482bf08824aSKurt Kanzenbach 		hdr = __skb_header_pointer(skb, nhoff, sizeof(_hdr), data, hlen,
1483bf08824aSKurt Kanzenbach 					   &_hdr);
1484bf08824aSKurt Kanzenbach 		if (!hdr) {
1485bf08824aSKurt Kanzenbach 			fdret = FLOW_DISSECT_RET_OUT_BAD;
1486bf08824aSKurt Kanzenbach 			break;
1487bf08824aSKurt Kanzenbach 		}
1488bf08824aSKurt Kanzenbach 
1489bf08824aSKurt Kanzenbach 		proto = hdr->encap_proto;
1490bf08824aSKurt Kanzenbach 		nhoff += HSR_HLEN;
1491bf08824aSKurt Kanzenbach 		fdret = FLOW_DISSECT_RET_PROTO_AGAIN;
1492bf08824aSKurt Kanzenbach 		break;
1493bf08824aSKurt Kanzenbach 	}
1494bf08824aSKurt Kanzenbach 
1495d7ad70b5SZahari Doychev 	case htons(ETH_P_CFM):
1496d7ad70b5SZahari Doychev 		fdret = __skb_flow_dissect_cfm(skb, flow_dissector,
1497d7ad70b5SZahari Doychev 					       target_container, data,
1498d7ad70b5SZahari Doychev 					       nhoff, hlen);
1499d7ad70b5SZahari Doychev 		break;
1500d7ad70b5SZahari Doychev 
15013a1214e8STom Herbert 	default:
15023a1214e8STom Herbert 		fdret = FLOW_DISSECT_RET_OUT_BAD;
15033a1214e8STom Herbert 		break;
15043a1214e8STom Herbert 	}
15053a1214e8STom Herbert 
15063a1214e8STom Herbert 	/* Process result of proto processing */
15073a1214e8STom Herbert 	switch (fdret) {
15089bf881ffSJiri Pirko 	case FLOW_DISSECT_RET_OUT_GOOD:
150955733350SSimon Horman 		goto out_good;
15103a1214e8STom Herbert 	case FLOW_DISSECT_RET_PROTO_AGAIN:
15111eed4dfbSTom Herbert 		if (skb_flow_dissect_allowed(&num_hdrs))
15123a1214e8STom Herbert 			goto proto_again;
15131eed4dfbSTom Herbert 		goto out_good;
15143a1214e8STom Herbert 	case FLOW_DISSECT_RET_CONTINUE:
15153a1214e8STom Herbert 	case FLOW_DISSECT_RET_IPPROTO_AGAIN:
15163a1214e8STom Herbert 		break;
15179bf881ffSJiri Pirko 	case FLOW_DISSECT_RET_OUT_BAD:
15187c92de8eSJiri Pirko 	default:
15199bf881ffSJiri Pirko 		goto out_bad;
152055733350SSimon Horman 	}
15210744dd00SEric Dumazet 
15226a74fcf4STom Herbert ip_proto_again:
15233a1214e8STom Herbert 	fdret = FLOW_DISSECT_RET_CONTINUE;
15243a1214e8STom Herbert 
15250744dd00SEric Dumazet 	switch (ip_proto) {
15267c92de8eSJiri Pirko 	case IPPROTO_GRE:
15276de6e46dSYoshiki Komachi 		if (flags & FLOW_DISSECTOR_F_STOP_BEFORE_ENCAP) {
15286de6e46dSYoshiki Komachi 			fdret = FLOW_DISSECT_RET_OUT_GOOD;
15296de6e46dSYoshiki Komachi 			break;
15306de6e46dSYoshiki Komachi 		}
15316de6e46dSYoshiki Komachi 
15323a1214e8STom Herbert 		fdret = __skb_flow_dissect_gre(skb, key_control, flow_dissector,
15337c92de8eSJiri Pirko 					       target_container, data,
15343a1214e8STom Herbert 					       &proto, &nhoff, &hlen, flags);
15353a1214e8STom Herbert 		break;
15363a1214e8STom Herbert 
15376a74fcf4STom Herbert 	case NEXTHDR_HOP:
15386a74fcf4STom Herbert 	case NEXTHDR_ROUTING:
15396a74fcf4STom Herbert 	case NEXTHDR_DEST: {
15406a74fcf4STom Herbert 		u8 _opthdr[2], *opthdr;
15416a74fcf4STom Herbert 
15426a74fcf4STom Herbert 		if (proto != htons(ETH_P_IPV6))
15436a74fcf4STom Herbert 			break;
15446a74fcf4STom Herbert 
15456a74fcf4STom Herbert 		opthdr = __skb_header_pointer(skb, nhoff, sizeof(_opthdr),
15466a74fcf4STom Herbert 					      data, hlen, &_opthdr);
15473a1214e8STom Herbert 		if (!opthdr) {
15483a1214e8STom Herbert 			fdret = FLOW_DISSECT_RET_OUT_BAD;
15493a1214e8STom Herbert 			break;
15503a1214e8STom Herbert 		}
15516a74fcf4STom Herbert 
15521e98a0f0SEric Dumazet 		ip_proto = opthdr[0];
15531e98a0f0SEric Dumazet 		nhoff += (opthdr[1] + 1) << 3;
15546a74fcf4STom Herbert 
15553a1214e8STom Herbert 		fdret = FLOW_DISSECT_RET_IPPROTO_AGAIN;
15563a1214e8STom Herbert 		break;
15576a74fcf4STom Herbert 	}
1558b840f28bSTom Herbert 	case NEXTHDR_FRAGMENT: {
1559b840f28bSTom Herbert 		struct frag_hdr _fh, *fh;
1560b840f28bSTom Herbert 
1561b840f28bSTom Herbert 		if (proto != htons(ETH_P_IPV6))
1562b840f28bSTom Herbert 			break;
1563b840f28bSTom Herbert 
1564b840f28bSTom Herbert 		fh = __skb_header_pointer(skb, nhoff, sizeof(_fh),
1565b840f28bSTom Herbert 					  data, hlen, &_fh);
1566b840f28bSTom Herbert 
15673a1214e8STom Herbert 		if (!fh) {
15683a1214e8STom Herbert 			fdret = FLOW_DISSECT_RET_OUT_BAD;
15693a1214e8STom Herbert 			break;
15703a1214e8STom Herbert 		}
1571b840f28bSTom Herbert 
15724b36993dSDavid S. Miller 		key_control->flags |= FLOW_DIS_IS_FRAGMENT;
1573b840f28bSTom Herbert 
1574b840f28bSTom Herbert 		nhoff += sizeof(_fh);
157543d2ccb3SAlexander Duyck 		ip_proto = fh->nexthdr;
1576b840f28bSTom Herbert 
1577b840f28bSTom Herbert 		if (!(fh->frag_off & htons(IP6_OFFSET))) {
15784b36993dSDavid S. Miller 			key_control->flags |= FLOW_DIS_FIRST_FRAG;
15793a1214e8STom Herbert 			if (flags & FLOW_DISSECTOR_F_PARSE_1ST_FRAG) {
15803a1214e8STom Herbert 				fdret = FLOW_DISSECT_RET_IPPROTO_AGAIN;
15813a1214e8STom Herbert 				break;
1582b840f28bSTom Herbert 			}
15833a1214e8STom Herbert 		}
15843a1214e8STom Herbert 
15853a1214e8STom Herbert 		fdret = FLOW_DISSECT_RET_OUT_GOOD;
15863a1214e8STom Herbert 		break;
1587b840f28bSTom Herbert 	}
15880744dd00SEric Dumazet 	case IPPROTO_IPIP:
15896de6e46dSYoshiki Komachi 		if (flags & FLOW_DISSECTOR_F_STOP_BEFORE_ENCAP) {
15906de6e46dSYoshiki Komachi 			fdret = FLOW_DISSECT_RET_OUT_GOOD;
15916de6e46dSYoshiki Komachi 			break;
15926de6e46dSYoshiki Komachi 		}
15936de6e46dSYoshiki Komachi 
1594fca41895STom Herbert 		proto = htons(ETH_P_IP);
1595823b9693STom Herbert 
15964b36993dSDavid S. Miller 		key_control->flags |= FLOW_DIS_ENCAPSULATION;
15973a1214e8STom Herbert 		if (flags & FLOW_DISSECTOR_F_STOP_AT_ENCAP) {
15983a1214e8STom Herbert 			fdret = FLOW_DISSECT_RET_OUT_GOOD;
15993a1214e8STom Herbert 			break;
16003a1214e8STom Herbert 		}
1601823b9693STom Herbert 
16023a1214e8STom Herbert 		fdret = FLOW_DISSECT_RET_PROTO_AGAIN;
16033a1214e8STom Herbert 		break;
16043a1214e8STom Herbert 
1605b438f940STom Herbert 	case IPPROTO_IPV6:
16066de6e46dSYoshiki Komachi 		if (flags & FLOW_DISSECTOR_F_STOP_BEFORE_ENCAP) {
16076de6e46dSYoshiki Komachi 			fdret = FLOW_DISSECT_RET_OUT_GOOD;
16086de6e46dSYoshiki Komachi 			break;
16096de6e46dSYoshiki Komachi 		}
16106de6e46dSYoshiki Komachi 
1611b438f940STom Herbert 		proto = htons(ETH_P_IPV6);
1612823b9693STom Herbert 
16134b36993dSDavid S. Miller 		key_control->flags |= FLOW_DIS_ENCAPSULATION;
16143a1214e8STom Herbert 		if (flags & FLOW_DISSECTOR_F_STOP_AT_ENCAP) {
16153a1214e8STom Herbert 			fdret = FLOW_DISSECT_RET_OUT_GOOD;
16163a1214e8STom Herbert 			break;
16173a1214e8STom Herbert 		}
1618823b9693STom Herbert 
16193a1214e8STom Herbert 		fdret = FLOW_DISSECT_RET_PROTO_AGAIN;
16203a1214e8STom Herbert 		break;
16213a1214e8STom Herbert 
16223a1214e8STom Herbert 
1623b3baa0fbSTom Herbert 	case IPPROTO_MPLS:
1624b3baa0fbSTom Herbert 		proto = htons(ETH_P_MPLS_UC);
16253a1214e8STom Herbert 		fdret = FLOW_DISSECT_RET_PROTO_AGAIN;
16263a1214e8STom Herbert 		break;
16273a1214e8STom Herbert 
1628ac4bb5deSJiri Pirko 	case IPPROTO_TCP:
1629ac4bb5deSJiri Pirko 		__skb_flow_dissect_tcp(skb, flow_dissector, target_container,
1630ac4bb5deSJiri Pirko 				       data, nhoff, hlen);
1631ac4bb5deSJiri Pirko 		break;
16323a1214e8STom Herbert 
16333b336d6fSMatteo Croce 	case IPPROTO_ICMP:
16343b336d6fSMatteo Croce 	case IPPROTO_ICMPV6:
16353b336d6fSMatteo Croce 		__skb_flow_dissect_icmp(skb, flow_dissector, target_container,
16363b336d6fSMatteo Croce 					data, nhoff, hlen);
16373b336d6fSMatteo Croce 		break;
1638dda2fa08SWojciech Drewek 	case IPPROTO_L2TP:
1639dda2fa08SWojciech Drewek 		__skb_flow_dissect_l2tpv3(skb, flow_dissector, target_container,
1640dda2fa08SWojciech Drewek 					  data, nhoff, hlen);
1641dda2fa08SWojciech Drewek 		break;
1642a57c34a8SRatheesh Kannoth 	case IPPROTO_ESP:
1643a57c34a8SRatheesh Kannoth 		__skb_flow_dissect_esp(skb, flow_dissector, target_container,
1644a57c34a8SRatheesh Kannoth 				       data, nhoff, hlen);
1645a57c34a8SRatheesh Kannoth 		break;
1646a57c34a8SRatheesh Kannoth 	case IPPROTO_AH:
1647a57c34a8SRatheesh Kannoth 		__skb_flow_dissect_ah(skb, flow_dissector, target_container,
1648a57c34a8SRatheesh Kannoth 				      data, nhoff, hlen);
1649a57c34a8SRatheesh Kannoth 		break;
16500744dd00SEric Dumazet 	default:
16510744dd00SEric Dumazet 		break;
16520744dd00SEric Dumazet 	}
16530744dd00SEric Dumazet 
16548ffb055bSYoshiki Komachi 	if (!(key_control->flags & FLOW_DIS_IS_FRAGMENT))
16558ffb055bSYoshiki Komachi 		__skb_flow_dissect_ports(skb, flow_dissector, target_container,
16568ffb055bSYoshiki Komachi 					 data, nhoff, ip_proto, hlen);
16575af7fb6eSAlexander Duyck 
16583a1214e8STom Herbert 	/* Process result of IP proto processing */
16593a1214e8STom Herbert 	switch (fdret) {
16603a1214e8STom Herbert 	case FLOW_DISSECT_RET_PROTO_AGAIN:
16611eed4dfbSTom Herbert 		if (skb_flow_dissect_allowed(&num_hdrs))
16623a1214e8STom Herbert 			goto proto_again;
16631eed4dfbSTom Herbert 		break;
16643a1214e8STom Herbert 	case FLOW_DISSECT_RET_IPPROTO_AGAIN:
16651eed4dfbSTom Herbert 		if (skb_flow_dissect_allowed(&num_hdrs))
16663a1214e8STom Herbert 			goto ip_proto_again;
16671eed4dfbSTom Herbert 		break;
16683a1214e8STom Herbert 	case FLOW_DISSECT_RET_OUT_GOOD:
16693a1214e8STom Herbert 	case FLOW_DISSECT_RET_CONTINUE:
16703a1214e8STom Herbert 		break;
16713a1214e8STom Herbert 	case FLOW_DISSECT_RET_OUT_BAD:
16723a1214e8STom Herbert 	default:
16733a1214e8STom Herbert 		goto out_bad;
16743a1214e8STom Herbert 	}
16753a1214e8STom Herbert 
1676a6e544b0STom Herbert out_good:
1677a6e544b0STom Herbert 	ret = true;
1678a6e544b0STom Herbert 
167934fad54cSEric Dumazet out:
1680d0c081b4SEric Dumazet 	key_control->thoff = min_t(u16, nhoff, skb ? skb->len : hlen);
1681a6e544b0STom Herbert 	key_basic->n_proto = proto;
1682a6e544b0STom Herbert 	key_basic->ip_proto = ip_proto;
1683a6e544b0STom Herbert 
1684a6e544b0STom Herbert 	return ret;
168534fad54cSEric Dumazet 
168634fad54cSEric Dumazet out_bad:
168734fad54cSEric Dumazet 	ret = false;
168834fad54cSEric Dumazet 	goto out;
16890744dd00SEric Dumazet }
1690690e36e7SDavid S. Miller EXPORT_SYMBOL(__skb_flow_dissect);
1691441d9d32SCong Wang 
169249ecc2e9SEric Dumazet static siphash_aligned_key_t hashrnd;
__flow_hash_secret_init(void)169366415cf8SHannes Frederic Sowa static __always_inline void __flow_hash_secret_init(void)
169466415cf8SHannes Frederic Sowa {
169566415cf8SHannes Frederic Sowa 	net_get_random_once(&hashrnd, sizeof(hashrnd));
169666415cf8SHannes Frederic Sowa }
169766415cf8SHannes Frederic Sowa 
flow_keys_hash_start(const struct flow_keys * flow)169855667441SEric Dumazet static const void *flow_keys_hash_start(const struct flow_keys *flow)
169966415cf8SHannes Frederic Sowa {
170055667441SEric Dumazet 	BUILD_BUG_ON(FLOW_KEYS_HASH_OFFSET % SIPHASH_ALIGNMENT);
170155667441SEric Dumazet 	return &flow->FLOW_KEYS_HASH_START_FIELD;
170242aecaa9STom Herbert }
170342aecaa9STom Herbert 
flow_keys_hash_length(const struct flow_keys * flow)170420a17bf6SDavid S. Miller static inline size_t flow_keys_hash_length(const struct flow_keys *flow)
170542aecaa9STom Herbert {
1706c3f83241STom Herbert 	size_t diff = FLOW_KEYS_HASH_OFFSET + sizeof(flow->addrs);
1707d31e9558SDavid S. Miller 
170842aecaa9STom Herbert 	BUILD_BUG_ON((sizeof(*flow) - FLOW_KEYS_HASH_OFFSET) % sizeof(u32));
1709c3f83241STom Herbert 
1710c3f83241STom Herbert 	switch (flow->control.addr_type) {
1711c3f83241STom Herbert 	case FLOW_DISSECTOR_KEY_IPV4_ADDRS:
1712c3f83241STom Herbert 		diff -= sizeof(flow->addrs.v4addrs);
1713c3f83241STom Herbert 		break;
1714c3f83241STom Herbert 	case FLOW_DISSECTOR_KEY_IPV6_ADDRS:
1715c3f83241STom Herbert 		diff -= sizeof(flow->addrs.v6addrs);
1716c3f83241STom Herbert 		break;
17178d6e79d3SJon Maloy 	case FLOW_DISSECTOR_KEY_TIPC:
17188d6e79d3SJon Maloy 		diff -= sizeof(flow->addrs.tipckey);
17199f249089STom Herbert 		break;
1720c3f83241STom Herbert 	}
172155667441SEric Dumazet 	return sizeof(*flow) - diff;
1722c3f83241STom Herbert }
1723c3f83241STom Herbert 
flow_get_u32_src(const struct flow_keys * flow)1724c3f83241STom Herbert __be32 flow_get_u32_src(const struct flow_keys *flow)
1725c3f83241STom Herbert {
1726c3f83241STom Herbert 	switch (flow->control.addr_type) {
1727c3f83241STom Herbert 	case FLOW_DISSECTOR_KEY_IPV4_ADDRS:
1728c3f83241STom Herbert 		return flow->addrs.v4addrs.src;
1729c3f83241STom Herbert 	case FLOW_DISSECTOR_KEY_IPV6_ADDRS:
1730c3f83241STom Herbert 		return (__force __be32)ipv6_addr_hash(
1731c3f83241STom Herbert 			&flow->addrs.v6addrs.src);
17328d6e79d3SJon Maloy 	case FLOW_DISSECTOR_KEY_TIPC:
17338d6e79d3SJon Maloy 		return flow->addrs.tipckey.key;
1734c3f83241STom Herbert 	default:
1735c3f83241STom Herbert 		return 0;
1736c3f83241STom Herbert 	}
1737c3f83241STom Herbert }
1738c3f83241STom Herbert EXPORT_SYMBOL(flow_get_u32_src);
1739c3f83241STom Herbert 
flow_get_u32_dst(const struct flow_keys * flow)1740c3f83241STom Herbert __be32 flow_get_u32_dst(const struct flow_keys *flow)
1741c3f83241STom Herbert {
1742c3f83241STom Herbert 	switch (flow->control.addr_type) {
1743c3f83241STom Herbert 	case FLOW_DISSECTOR_KEY_IPV4_ADDRS:
1744c3f83241STom Herbert 		return flow->addrs.v4addrs.dst;
1745c3f83241STom Herbert 	case FLOW_DISSECTOR_KEY_IPV6_ADDRS:
1746c3f83241STom Herbert 		return (__force __be32)ipv6_addr_hash(
1747c3f83241STom Herbert 			&flow->addrs.v6addrs.dst);
1748c3f83241STom Herbert 	default:
1749c3f83241STom Herbert 		return 0;
1750c3f83241STom Herbert 	}
1751c3f83241STom Herbert }
1752c3f83241STom Herbert EXPORT_SYMBOL(flow_get_u32_dst);
1753c3f83241STom Herbert 
17541e60cebfSzhang kai /* Sort the source and destination IP and the ports,
175598298e6cSMatteo Croce  * to have consistent hash within the two directions
175698298e6cSMatteo Croce  */
__flow_hash_consistentify(struct flow_keys * keys)1757c3f83241STom Herbert static inline void __flow_hash_consistentify(struct flow_keys *keys)
1758c3f83241STom Herbert {
1759c3f83241STom Herbert 	int addr_diff, i;
1760c3f83241STom Herbert 
1761c3f83241STom Herbert 	switch (keys->control.addr_type) {
1762c3f83241STom Herbert 	case FLOW_DISSECTOR_KEY_IPV4_ADDRS:
176364ae13edSLudovic Cintrat 		if ((__force u32)keys->addrs.v4addrs.dst <
176464ae13edSLudovic Cintrat 		    (__force u32)keys->addrs.v4addrs.src)
1765c3f83241STom Herbert 			swap(keys->addrs.v4addrs.src, keys->addrs.v4addrs.dst);
17661e60cebfSzhang kai 
17671e60cebfSzhang kai 		if ((__force u16)keys->ports.dst <
17681e60cebfSzhang kai 		    (__force u16)keys->ports.src) {
1769c3f83241STom Herbert 			swap(keys->ports.src, keys->ports.dst);
1770c3f83241STom Herbert 		}
1771c3f83241STom Herbert 		break;
1772c3f83241STom Herbert 	case FLOW_DISSECTOR_KEY_IPV6_ADDRS:
1773c3f83241STom Herbert 		addr_diff = memcmp(&keys->addrs.v6addrs.dst,
1774c3f83241STom Herbert 				   &keys->addrs.v6addrs.src,
1775c3f83241STom Herbert 				   sizeof(keys->addrs.v6addrs.dst));
17761e60cebfSzhang kai 		if (addr_diff < 0) {
1777c3f83241STom Herbert 			for (i = 0; i < 4; i++)
1778c3f83241STom Herbert 				swap(keys->addrs.v6addrs.src.s6_addr32[i],
1779c3f83241STom Herbert 				     keys->addrs.v6addrs.dst.s6_addr32[i]);
17801e60cebfSzhang kai 		}
17811e60cebfSzhang kai 		if ((__force u16)keys->ports.dst <
17821e60cebfSzhang kai 		    (__force u16)keys->ports.src) {
1783c3f83241STom Herbert 			swap(keys->ports.src, keys->ports.dst);
1784c3f83241STom Herbert 		}
1785c3f83241STom Herbert 		break;
1786c3f83241STom Herbert 	}
178766415cf8SHannes Frederic Sowa }
178866415cf8SHannes Frederic Sowa 
__flow_hash_from_keys(struct flow_keys * keys,const siphash_key_t * keyval)178955667441SEric Dumazet static inline u32 __flow_hash_from_keys(struct flow_keys *keys,
179055667441SEric Dumazet 					const siphash_key_t *keyval)
17915ed20a68STom Herbert {
17925ed20a68STom Herbert 	u32 hash;
17935ed20a68STom Herbert 
1794c3f83241STom Herbert 	__flow_hash_consistentify(keys);
17955ed20a68STom Herbert 
179655667441SEric Dumazet 	hash = siphash(flow_keys_hash_start(keys),
179742aecaa9STom Herbert 		       flow_keys_hash_length(keys), keyval);
17985ed20a68STom Herbert 	if (!hash)
17995ed20a68STom Herbert 		hash = 1;
18005ed20a68STom Herbert 
18015ed20a68STom Herbert 	return hash;
18025ed20a68STom Herbert }
18035ed20a68STom Herbert 
flow_hash_from_keys(struct flow_keys * keys)18045ed20a68STom Herbert u32 flow_hash_from_keys(struct flow_keys *keys)
18055ed20a68STom Herbert {
180650fb7992STom Herbert 	__flow_hash_secret_init();
180755667441SEric Dumazet 	return __flow_hash_from_keys(keys, &hashrnd);
18085ed20a68STom Herbert }
18095ed20a68STom Herbert EXPORT_SYMBOL(flow_hash_from_keys);
18105ed20a68STom Herbert 
flow_hash_from_keys_seed(struct flow_keys * keys,const siphash_key_t * keyval)18114ee2a8caSPetr Machata u32 flow_hash_from_keys_seed(struct flow_keys *keys,
18124ee2a8caSPetr Machata 			     const siphash_key_t *keyval)
18134ee2a8caSPetr Machata {
18144ee2a8caSPetr Machata 	return __flow_hash_from_keys(keys, keyval);
18154ee2a8caSPetr Machata }
18164ee2a8caSPetr Machata EXPORT_SYMBOL(flow_hash_from_keys_seed);
18174ee2a8caSPetr Machata 
___skb_get_hash(const struct sk_buff * skb,struct flow_keys * keys,const siphash_key_t * keyval)181850fb7992STom Herbert static inline u32 ___skb_get_hash(const struct sk_buff *skb,
181955667441SEric Dumazet 				  struct flow_keys *keys,
182055667441SEric Dumazet 				  const siphash_key_t *keyval)
182150fb7992STom Herbert {
18226db61d79STom Herbert 	skb_flow_dissect_flow_keys(skb, keys,
18236db61d79STom Herbert 				   FLOW_DISSECTOR_F_STOP_AT_FLOW_LABEL);
182450fb7992STom Herbert 
182550fb7992STom Herbert 	return __flow_hash_from_keys(keys, keyval);
182650fb7992STom Herbert }
182750fb7992STom Herbert 
18282f59e1ebSTom Herbert struct _flow_keys_digest_data {
18292f59e1ebSTom Herbert 	__be16	n_proto;
18302f59e1ebSTom Herbert 	u8	ip_proto;
18312f59e1ebSTom Herbert 	u8	padding;
18322f59e1ebSTom Herbert 	__be32	ports;
18332f59e1ebSTom Herbert 	__be32	src;
18342f59e1ebSTom Herbert 	__be32	dst;
18352f59e1ebSTom Herbert };
18362f59e1ebSTom Herbert 
make_flow_keys_digest(struct flow_keys_digest * digest,const struct flow_keys * flow)18372f59e1ebSTom Herbert void make_flow_keys_digest(struct flow_keys_digest *digest,
18382f59e1ebSTom Herbert 			   const struct flow_keys *flow)
18392f59e1ebSTom Herbert {
18402f59e1ebSTom Herbert 	struct _flow_keys_digest_data *data =
18412f59e1ebSTom Herbert 	    (struct _flow_keys_digest_data *)digest;
18422f59e1ebSTom Herbert 
18432f59e1ebSTom Herbert 	BUILD_BUG_ON(sizeof(*data) > sizeof(*digest));
18442f59e1ebSTom Herbert 
18452f59e1ebSTom Herbert 	memset(digest, 0, sizeof(*digest));
18462f59e1ebSTom Herbert 
184706635a35SJiri Pirko 	data->n_proto = flow->basic.n_proto;
184806635a35SJiri Pirko 	data->ip_proto = flow->basic.ip_proto;
184906635a35SJiri Pirko 	data->ports = flow->ports.ports;
1850c3f83241STom Herbert 	data->src = flow->addrs.v4addrs.src;
1851c3f83241STom Herbert 	data->dst = flow->addrs.v4addrs.dst;
18522f59e1ebSTom Herbert }
18532f59e1ebSTom Herbert EXPORT_SYMBOL(make_flow_keys_digest);
18542f59e1ebSTom Herbert 
1855eb70db87SDavid S. Miller static struct flow_dissector flow_keys_dissector_symmetric __read_mostly;
1856eb70db87SDavid S. Miller 
__skb_get_hash_symmetric_net(const struct net * net,const struct sk_buff * skb)1857d1dab4f7SFlorian Westphal u32 __skb_get_hash_symmetric_net(const struct net *net, const struct sk_buff *skb)
1858eb70db87SDavid S. Miller {
1859eb70db87SDavid S. Miller 	struct flow_keys keys;
1860eb70db87SDavid S. Miller 
1861eb70db87SDavid S. Miller 	__flow_hash_secret_init();
1862eb70db87SDavid S. Miller 
1863eb70db87SDavid S. Miller 	memset(&keys, 0, sizeof(keys));
1864d1dab4f7SFlorian Westphal 	__skb_flow_dissect(net, skb, &flow_keys_dissector_symmetric,
1865a5e2151fSQuan Tian 			   &keys, NULL, 0, 0, 0, 0);
1866eb70db87SDavid S. Miller 
186755667441SEric Dumazet 	return __flow_hash_from_keys(&keys, &hashrnd);
1868eb70db87SDavid S. Miller }
1869d1dab4f7SFlorian Westphal EXPORT_SYMBOL_GPL(__skb_get_hash_symmetric_net);
1870eb70db87SDavid S. Miller 
1871d4fd3275SJiri Pirko /**
1872b975d3eeSFlorian Westphal  * __skb_get_hash_net: calculate a flow hash
1873b975d3eeSFlorian Westphal  * @net: associated network namespace, derived from @skb if NULL
1874d4fd3275SJiri Pirko  * @skb: sk_buff to calculate flow hash from
1875d4fd3275SJiri Pirko  *
1876d4fd3275SJiri Pirko  * This function calculates a flow hash based on src/dst addresses
187761b905daSTom Herbert  * and src/dst port numbers.  Sets hash in skb to non-zero hash value
187861b905daSTom Herbert  * on success, zero indicates no valid hash.  Also, sets l4_hash in skb
1879441d9d32SCong Wang  * if hash is a canonical 4-tuple hash over transport ports.
1880441d9d32SCong Wang  */
__skb_get_hash_net(const struct net * net,struct sk_buff * skb)1881b975d3eeSFlorian Westphal void __skb_get_hash_net(const struct net *net, struct sk_buff *skb)
1882441d9d32SCong Wang {
1883441d9d32SCong Wang 	struct flow_keys keys;
1884635c223cSGao Feng 	u32 hash;
1885441d9d32SCong Wang 
1886b975d3eeSFlorian Westphal 	memset(&keys, 0, sizeof(keys));
1887b975d3eeSFlorian Westphal 
1888b975d3eeSFlorian Westphal 	__skb_flow_dissect(net, skb, &flow_keys_dissector,
1889b975d3eeSFlorian Westphal 			   &keys, NULL, 0, 0, 0,
1890b975d3eeSFlorian Westphal 			   FLOW_DISSECTOR_F_STOP_AT_FLOW_LABEL);
1891b975d3eeSFlorian Westphal 
189250fb7992STom Herbert 	__flow_hash_secret_init();
189350fb7992STom Herbert 
1894b975d3eeSFlorian Westphal 	hash = __flow_hash_from_keys(&keys, &hashrnd);
1895635c223cSGao Feng 
1896635c223cSGao Feng 	__skb_set_sw_hash(skb, hash, flow_keys_have_l4(&keys));
1897441d9d32SCong Wang }
1898b975d3eeSFlorian Westphal EXPORT_SYMBOL(__skb_get_hash_net);
1899441d9d32SCong Wang 
skb_get_hash_perturb(const struct sk_buff * skb,const siphash_key_t * perturb)190055667441SEric Dumazet __u32 skb_get_hash_perturb(const struct sk_buff *skb,
190155667441SEric Dumazet 			   const siphash_key_t *perturb)
190250fb7992STom Herbert {
190350fb7992STom Herbert 	struct flow_keys keys;
190450fb7992STom Herbert 
190550fb7992STom Herbert 	return ___skb_get_hash(skb, &keys, perturb);
190650fb7992STom Herbert }
190750fb7992STom Herbert EXPORT_SYMBOL(skb_get_hash_perturb);
190850fb7992STom Herbert 
__skb_get_poff(const struct sk_buff * skb,const void * data,const struct flow_keys_basic * keys,int hlen)1909f96533cdSAlexander Lobakin u32 __skb_get_poff(const struct sk_buff *skb, const void *data,
191072a338bcSPaolo Abeni 		   const struct flow_keys_basic *keys, int hlen)
1911f77668dcSDaniel Borkmann {
191242aecaa9STom Herbert 	u32 poff = keys->control.thoff;
1913f77668dcSDaniel Borkmann 
191443d2ccb3SAlexander Duyck 	/* skip L4 headers for fragments after the first */
191543d2ccb3SAlexander Duyck 	if ((keys->control.flags & FLOW_DIS_IS_FRAGMENT) &&
191643d2ccb3SAlexander Duyck 	    !(keys->control.flags & FLOW_DIS_FIRST_FRAG))
191743d2ccb3SAlexander Duyck 		return poff;
191843d2ccb3SAlexander Duyck 
191906635a35SJiri Pirko 	switch (keys->basic.ip_proto) {
1920f77668dcSDaniel Borkmann 	case IPPROTO_TCP: {
19215af7fb6eSAlexander Duyck 		/* access doff as u8 to avoid unaligned access */
19225af7fb6eSAlexander Duyck 		const u8 *doff;
19235af7fb6eSAlexander Duyck 		u8 _doff;
1924f77668dcSDaniel Borkmann 
19255af7fb6eSAlexander Duyck 		doff = __skb_header_pointer(skb, poff + 12, sizeof(_doff),
19265af7fb6eSAlexander Duyck 					    data, hlen, &_doff);
19275af7fb6eSAlexander Duyck 		if (!doff)
1928f77668dcSDaniel Borkmann 			return poff;
1929f77668dcSDaniel Borkmann 
19305af7fb6eSAlexander Duyck 		poff += max_t(u32, sizeof(struct tcphdr), (*doff & 0xF0) >> 2);
1931f77668dcSDaniel Borkmann 		break;
1932f77668dcSDaniel Borkmann 	}
1933f77668dcSDaniel Borkmann 	case IPPROTO_UDP:
1934f77668dcSDaniel Borkmann 	case IPPROTO_UDPLITE:
1935f77668dcSDaniel Borkmann 		poff += sizeof(struct udphdr);
1936f77668dcSDaniel Borkmann 		break;
1937f77668dcSDaniel Borkmann 	/* For the rest, we do not really care about header
1938f77668dcSDaniel Borkmann 	 * extensions at this point for now.
1939f77668dcSDaniel Borkmann 	 */
1940f77668dcSDaniel Borkmann 	case IPPROTO_ICMP:
1941f77668dcSDaniel Borkmann 		poff += sizeof(struct icmphdr);
1942f77668dcSDaniel Borkmann 		break;
1943f77668dcSDaniel Borkmann 	case IPPROTO_ICMPV6:
1944f77668dcSDaniel Borkmann 		poff += sizeof(struct icmp6hdr);
1945f77668dcSDaniel Borkmann 		break;
1946f77668dcSDaniel Borkmann 	case IPPROTO_IGMP:
1947f77668dcSDaniel Borkmann 		poff += sizeof(struct igmphdr);
1948f77668dcSDaniel Borkmann 		break;
1949f77668dcSDaniel Borkmann 	case IPPROTO_DCCP:
1950f77668dcSDaniel Borkmann 		poff += sizeof(struct dccp_hdr);
1951f77668dcSDaniel Borkmann 		break;
1952f77668dcSDaniel Borkmann 	case IPPROTO_SCTP:
1953f77668dcSDaniel Borkmann 		poff += sizeof(struct sctphdr);
1954f77668dcSDaniel Borkmann 		break;
1955f77668dcSDaniel Borkmann 	}
1956f77668dcSDaniel Borkmann 
1957f77668dcSDaniel Borkmann 	return poff;
1958f77668dcSDaniel Borkmann }
1959f77668dcSDaniel Borkmann 
19600db89b8bSJiri Pirko /**
19610db89b8bSJiri Pirko  * skb_get_poff - get the offset to the payload
19620db89b8bSJiri Pirko  * @skb: sk_buff to get the payload offset from
19630db89b8bSJiri Pirko  *
19640db89b8bSJiri Pirko  * The function will get the offset to the payload as far as it could
196556193d1bSAlexander Duyck  * be dissected.  The main user is currently BPF, so that we can dynamically
196656193d1bSAlexander Duyck  * truncate packets without needing to push actual payload to the user
196756193d1bSAlexander Duyck  * space and can analyze headers only, instead.
196856193d1bSAlexander Duyck  */
skb_get_poff(const struct sk_buff * skb)196956193d1bSAlexander Duyck u32 skb_get_poff(const struct sk_buff *skb)
197056193d1bSAlexander Duyck {
197172a338bcSPaolo Abeni 	struct flow_keys_basic keys;
197256193d1bSAlexander Duyck 
19733cbf4ffbSStanislav Fomichev 	if (!skb_flow_dissect_flow_keys_basic(NULL, skb, &keys,
19743cbf4ffbSStanislav Fomichev 					      NULL, 0, 0, 0, 0))
197556193d1bSAlexander Duyck 		return 0;
197656193d1bSAlexander Duyck 
197756193d1bSAlexander Duyck 	return __skb_get_poff(skb, skb->data, &keys, skb_headlen(skb));
197856193d1bSAlexander Duyck }
197906635a35SJiri Pirko 
__get_hash_from_flowi6(const struct flowi6 * fl6,struct flow_keys * keys)198020a17bf6SDavid S. Miller __u32 __get_hash_from_flowi6(const struct flowi6 *fl6, struct flow_keys *keys)
1981a17ace95SDavid S. Miller {
1982a17ace95SDavid S. Miller 	memset(keys, 0, sizeof(*keys));
1983a17ace95SDavid S. Miller 
1984a17ace95SDavid S. Miller 	memcpy(&keys->addrs.v6addrs.src, &fl6->saddr,
1985a17ace95SDavid S. Miller 	    sizeof(keys->addrs.v6addrs.src));
1986a17ace95SDavid S. Miller 	memcpy(&keys->addrs.v6addrs.dst, &fl6->daddr,
1987a17ace95SDavid S. Miller 	    sizeof(keys->addrs.v6addrs.dst));
1988a17ace95SDavid S. Miller 	keys->control.addr_type = FLOW_DISSECTOR_KEY_IPV6_ADDRS;
1989a17ace95SDavid S. Miller 	keys->ports.src = fl6->fl6_sport;
1990a17ace95SDavid S. Miller 	keys->ports.dst = fl6->fl6_dport;
1991a17ace95SDavid S. Miller 	keys->keyid.keyid = fl6->fl6_gre_key;
1992fa1be7e0SMichal Kubecek 	keys->tags.flow_label = (__force u32)flowi6_get_flowlabel(fl6);
1993a17ace95SDavid S. Miller 	keys->basic.ip_proto = fl6->flowi6_proto;
1994a17ace95SDavid S. Miller 
1995a17ace95SDavid S. Miller 	return flow_hash_from_keys(keys);
1996a17ace95SDavid S. Miller }
1997a17ace95SDavid S. Miller EXPORT_SYMBOL(__get_hash_from_flowi6);
1998a17ace95SDavid S. Miller 
199906635a35SJiri Pirko static const struct flow_dissector_key flow_keys_dissector_keys[] = {
200006635a35SJiri Pirko 	{
200142aecaa9STom Herbert 		.key_id = FLOW_DISSECTOR_KEY_CONTROL,
200242aecaa9STom Herbert 		.offset = offsetof(struct flow_keys, control),
200342aecaa9STom Herbert 	},
200442aecaa9STom Herbert 	{
200506635a35SJiri Pirko 		.key_id = FLOW_DISSECTOR_KEY_BASIC,
200606635a35SJiri Pirko 		.offset = offsetof(struct flow_keys, basic),
200706635a35SJiri Pirko 	},
200806635a35SJiri Pirko 	{
200906635a35SJiri Pirko 		.key_id = FLOW_DISSECTOR_KEY_IPV4_ADDRS,
2010c3f83241STom Herbert 		.offset = offsetof(struct flow_keys, addrs.v4addrs),
2011c3f83241STom Herbert 	},
2012c3f83241STom Herbert 	{
2013c3f83241STom Herbert 		.key_id = FLOW_DISSECTOR_KEY_IPV6_ADDRS,
2014c3f83241STom Herbert 		.offset = offsetof(struct flow_keys, addrs.v6addrs),
201506635a35SJiri Pirko 	},
201606635a35SJiri Pirko 	{
20178d6e79d3SJon Maloy 		.key_id = FLOW_DISSECTOR_KEY_TIPC,
20188d6e79d3SJon Maloy 		.offset = offsetof(struct flow_keys, addrs.tipckey),
20199f249089STom Herbert 	},
20209f249089STom Herbert 	{
202106635a35SJiri Pirko 		.key_id = FLOW_DISSECTOR_KEY_PORTS,
202206635a35SJiri Pirko 		.offset = offsetof(struct flow_keys, ports),
202306635a35SJiri Pirko 	},
2024d34af823STom Herbert 	{
2025f6a66927SHadar Hen Zion 		.key_id = FLOW_DISSECTOR_KEY_VLAN,
2026f6a66927SHadar Hen Zion 		.offset = offsetof(struct flow_keys, vlan),
2027d34af823STom Herbert 	},
202887ee9e52STom Herbert 	{
202987ee9e52STom Herbert 		.key_id = FLOW_DISSECTOR_KEY_FLOW_LABEL,
203087ee9e52STom Herbert 		.offset = offsetof(struct flow_keys, tags),
203187ee9e52STom Herbert 	},
20321fdd512cSTom Herbert 	{
20331fdd512cSTom Herbert 		.key_id = FLOW_DISSECTOR_KEY_GRE_KEYID,
20341fdd512cSTom Herbert 		.offset = offsetof(struct flow_keys, keyid),
20351fdd512cSTom Herbert 	},
203606635a35SJiri Pirko };
203706635a35SJiri Pirko 
2038eb70db87SDavid S. Miller static const struct flow_dissector_key flow_keys_dissector_symmetric_keys[] = {
2039eb70db87SDavid S. Miller 	{
2040eb70db87SDavid S. Miller 		.key_id = FLOW_DISSECTOR_KEY_CONTROL,
2041eb70db87SDavid S. Miller 		.offset = offsetof(struct flow_keys, control),
2042eb70db87SDavid S. Miller 	},
2043eb70db87SDavid S. Miller 	{
2044eb70db87SDavid S. Miller 		.key_id = FLOW_DISSECTOR_KEY_BASIC,
2045eb70db87SDavid S. Miller 		.offset = offsetof(struct flow_keys, basic),
2046eb70db87SDavid S. Miller 	},
2047eb70db87SDavid S. Miller 	{
2048eb70db87SDavid S. Miller 		.key_id = FLOW_DISSECTOR_KEY_IPV4_ADDRS,
2049eb70db87SDavid S. Miller 		.offset = offsetof(struct flow_keys, addrs.v4addrs),
2050eb70db87SDavid S. Miller 	},
2051eb70db87SDavid S. Miller 	{
2052eb70db87SDavid S. Miller 		.key_id = FLOW_DISSECTOR_KEY_IPV6_ADDRS,
2053eb70db87SDavid S. Miller 		.offset = offsetof(struct flow_keys, addrs.v6addrs),
2054eb70db87SDavid S. Miller 	},
2055eb70db87SDavid S. Miller 	{
2056eb70db87SDavid S. Miller 		.key_id = FLOW_DISSECTOR_KEY_PORTS,
2057eb70db87SDavid S. Miller 		.offset = offsetof(struct flow_keys, ports),
2058eb70db87SDavid S. Miller 	},
2059eb70db87SDavid S. Miller };
2060eb70db87SDavid S. Miller 
206172a338bcSPaolo Abeni static const struct flow_dissector_key flow_keys_basic_dissector_keys[] = {
206206635a35SJiri Pirko 	{
206342aecaa9STom Herbert 		.key_id = FLOW_DISSECTOR_KEY_CONTROL,
206442aecaa9STom Herbert 		.offset = offsetof(struct flow_keys, control),
206542aecaa9STom Herbert 	},
206642aecaa9STom Herbert 	{
206706635a35SJiri Pirko 		.key_id = FLOW_DISSECTOR_KEY_BASIC,
206806635a35SJiri Pirko 		.offset = offsetof(struct flow_keys, basic),
206906635a35SJiri Pirko 	},
207006635a35SJiri Pirko };
207106635a35SJiri Pirko 
207206635a35SJiri Pirko struct flow_dissector flow_keys_dissector __read_mostly;
207306635a35SJiri Pirko EXPORT_SYMBOL(flow_keys_dissector);
207406635a35SJiri Pirko 
207572a338bcSPaolo Abeni struct flow_dissector flow_keys_basic_dissector __read_mostly;
207672a338bcSPaolo Abeni EXPORT_SYMBOL(flow_keys_basic_dissector);
207706635a35SJiri Pirko 
init_default_flow_dissectors(void)207806635a35SJiri Pirko static int __init init_default_flow_dissectors(void)
207906635a35SJiri Pirko {
208006635a35SJiri Pirko 	skb_flow_dissector_init(&flow_keys_dissector,
208106635a35SJiri Pirko 				flow_keys_dissector_keys,
208206635a35SJiri Pirko 				ARRAY_SIZE(flow_keys_dissector_keys));
2083eb70db87SDavid S. Miller 	skb_flow_dissector_init(&flow_keys_dissector_symmetric,
2084eb70db87SDavid S. Miller 				flow_keys_dissector_symmetric_keys,
2085eb70db87SDavid S. Miller 				ARRAY_SIZE(flow_keys_dissector_symmetric_keys));
208672a338bcSPaolo Abeni 	skb_flow_dissector_init(&flow_keys_basic_dissector,
208772a338bcSPaolo Abeni 				flow_keys_basic_dissector_keys,
208872a338bcSPaolo Abeni 				ARRAY_SIZE(flow_keys_basic_dissector_keys));
2089b27f7bb5SJakub Sitnicki 	return 0;
20905cf65922SJakub Sitnicki }
2091c9b8af13SEric Dumazet core_initcall(init_default_flow_dissectors);
2092