xref: /openbmc/linux/net/core/flow_dissector.c (revision d37cf9b63113f13d742713881ce691fc615d8b3b)
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_addr_type(enum flow_dissector_key_id type,struct flow_dissector * flow_dissector,void * target_container)302a38402bcSSimon Horman skb_flow_dissect_set_enc_addr_type(enum flow_dissector_key_id type,
303a38402bcSSimon Horman 				   struct flow_dissector *flow_dissector,
304a38402bcSSimon Horman 				   void *target_container)
305a38402bcSSimon Horman {
306a38402bcSSimon Horman 	struct flow_dissector_key_control *ctrl;
307a38402bcSSimon Horman 
308a38402bcSSimon Horman 	if (!dissector_uses_key(flow_dissector, FLOW_DISSECTOR_KEY_ENC_CONTROL))
309a38402bcSSimon Horman 		return;
310a38402bcSSimon Horman 
311a38402bcSSimon Horman 	ctrl = skb_flow_dissector_target(flow_dissector,
312a38402bcSSimon Horman 					 FLOW_DISSECTOR_KEY_ENC_CONTROL,
313a38402bcSSimon Horman 					 target_container);
314a38402bcSSimon Horman 	ctrl->addr_type = type;
315a38402bcSSimon Horman }
316a38402bcSSimon Horman 
31762b32379SSimon 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)31875a56758SPaul Blakey skb_flow_dissect_ct(const struct sk_buff *skb,
31975a56758SPaul Blakey 		    struct flow_dissector *flow_dissector,
3207baf2429Swenxu 		    void *target_container, u16 *ctinfo_map,
32138495958SPaul Blakey 		    size_t mapsize, bool post_ct, u16 zone)
32275a56758SPaul Blakey {
32375a56758SPaul Blakey #if IS_ENABLED(CONFIG_NF_CONNTRACK)
32475a56758SPaul Blakey 	struct flow_dissector_key_ct *key;
32575a56758SPaul Blakey 	enum ip_conntrack_info ctinfo;
32675a56758SPaul Blakey 	struct nf_conn_labels *cl;
32775a56758SPaul Blakey 	struct nf_conn *ct;
32875a56758SPaul Blakey 
32975a56758SPaul Blakey 	if (!dissector_uses_key(flow_dissector, FLOW_DISSECTOR_KEY_CT))
33075a56758SPaul Blakey 		return;
33175a56758SPaul Blakey 
33275a56758SPaul Blakey 	ct = nf_ct_get(skb, &ctinfo);
3337baf2429Swenxu 	if (!ct && !post_ct)
33475a56758SPaul Blakey 		return;
33575a56758SPaul Blakey 
33675a56758SPaul Blakey 	key = skb_flow_dissector_target(flow_dissector,
33775a56758SPaul Blakey 					FLOW_DISSECTOR_KEY_CT,
33875a56758SPaul Blakey 					target_container);
33975a56758SPaul Blakey 
3407baf2429Swenxu 	if (!ct) {
3417baf2429Swenxu 		key->ct_state = TCA_FLOWER_KEY_CT_FLAGS_TRACKED |
3427baf2429Swenxu 				TCA_FLOWER_KEY_CT_FLAGS_INVALID;
34338495958SPaul Blakey 		key->ct_zone = zone;
3447baf2429Swenxu 		return;
3457baf2429Swenxu 	}
3467baf2429Swenxu 
34775a56758SPaul Blakey 	if (ctinfo < mapsize)
34875a56758SPaul Blakey 		key->ct_state = ctinfo_map[ctinfo];
34975a56758SPaul Blakey #if IS_ENABLED(CONFIG_NF_CONNTRACK_ZONES)
35075a56758SPaul Blakey 	key->ct_zone = ct->zone.id;
35175a56758SPaul Blakey #endif
35275a56758SPaul Blakey #if IS_ENABLED(CONFIG_NF_CONNTRACK_MARK)
35352d1aa8bSDaniel Xu 	key->ct_mark = READ_ONCE(ct->mark);
35475a56758SPaul Blakey #endif
35575a56758SPaul Blakey 
35675a56758SPaul Blakey 	cl = nf_ct_labels_find(ct);
35775a56758SPaul Blakey 	if (cl)
35875a56758SPaul Blakey 		memcpy(key->ct_labels, cl->bits, sizeof(key->ct_labels));
35975a56758SPaul Blakey #endif /* CONFIG_NF_CONNTRACK */
36075a56758SPaul Blakey }
36175a56758SPaul Blakey EXPORT_SYMBOL(skb_flow_dissect_ct);
36275a56758SPaul Blakey 
36375a56758SPaul Blakey void
skb_flow_dissect_tunnel_info(const struct sk_buff * skb,struct flow_dissector * flow_dissector,void * target_container)36462b32379SSimon Horman skb_flow_dissect_tunnel_info(const struct sk_buff *skb,
365a38402bcSSimon Horman 			     struct flow_dissector *flow_dissector,
366a38402bcSSimon Horman 			     void *target_container)
367a38402bcSSimon Horman {
368a38402bcSSimon Horman 	struct ip_tunnel_info *info;
369a38402bcSSimon Horman 	struct ip_tunnel_key *key;
370a38402bcSSimon Horman 
371a38402bcSSimon Horman 	/* A quick check to see if there might be something to do. */
372a38402bcSSimon Horman 	if (!dissector_uses_key(flow_dissector,
373a38402bcSSimon Horman 				FLOW_DISSECTOR_KEY_ENC_KEYID) &&
374a38402bcSSimon Horman 	    !dissector_uses_key(flow_dissector,
375a38402bcSSimon Horman 				FLOW_DISSECTOR_KEY_ENC_IPV4_ADDRS) &&
376a38402bcSSimon Horman 	    !dissector_uses_key(flow_dissector,
377a38402bcSSimon Horman 				FLOW_DISSECTOR_KEY_ENC_IPV6_ADDRS) &&
378a38402bcSSimon Horman 	    !dissector_uses_key(flow_dissector,
379a38402bcSSimon Horman 				FLOW_DISSECTOR_KEY_ENC_CONTROL) &&
380a38402bcSSimon Horman 	    !dissector_uses_key(flow_dissector,
3815544adb9SOr Gerlitz 				FLOW_DISSECTOR_KEY_ENC_PORTS) &&
3825544adb9SOr Gerlitz 	    !dissector_uses_key(flow_dissector,
38392e2c405SSimon Horman 				FLOW_DISSECTOR_KEY_ENC_IP) &&
38492e2c405SSimon Horman 	    !dissector_uses_key(flow_dissector,
38592e2c405SSimon Horman 				FLOW_DISSECTOR_KEY_ENC_OPTS))
386a38402bcSSimon Horman 		return;
387a38402bcSSimon Horman 
388a38402bcSSimon Horman 	info = skb_tunnel_info(skb);
389a38402bcSSimon Horman 	if (!info)
390a38402bcSSimon Horman 		return;
391a38402bcSSimon Horman 
392a38402bcSSimon Horman 	key = &info->key;
393a38402bcSSimon Horman 
394a38402bcSSimon Horman 	switch (ip_tunnel_info_af(info)) {
395a38402bcSSimon Horman 	case AF_INET:
396a38402bcSSimon Horman 		skb_flow_dissect_set_enc_addr_type(FLOW_DISSECTOR_KEY_IPV4_ADDRS,
397a38402bcSSimon Horman 						   flow_dissector,
398a38402bcSSimon Horman 						   target_container);
399a38402bcSSimon Horman 		if (dissector_uses_key(flow_dissector,
400a38402bcSSimon Horman 				       FLOW_DISSECTOR_KEY_ENC_IPV4_ADDRS)) {
401a38402bcSSimon Horman 			struct flow_dissector_key_ipv4_addrs *ipv4;
402a38402bcSSimon Horman 
403a38402bcSSimon Horman 			ipv4 = skb_flow_dissector_target(flow_dissector,
404a38402bcSSimon Horman 							 FLOW_DISSECTOR_KEY_ENC_IPV4_ADDRS,
405a38402bcSSimon Horman 							 target_container);
406a38402bcSSimon Horman 			ipv4->src = key->u.ipv4.src;
407a38402bcSSimon Horman 			ipv4->dst = key->u.ipv4.dst;
408a38402bcSSimon Horman 		}
409a38402bcSSimon Horman 		break;
410a38402bcSSimon Horman 	case AF_INET6:
411a38402bcSSimon Horman 		skb_flow_dissect_set_enc_addr_type(FLOW_DISSECTOR_KEY_IPV6_ADDRS,
412a38402bcSSimon Horman 						   flow_dissector,
413a38402bcSSimon Horman 						   target_container);
414a38402bcSSimon Horman 		if (dissector_uses_key(flow_dissector,
415a38402bcSSimon Horman 				       FLOW_DISSECTOR_KEY_ENC_IPV6_ADDRS)) {
416a38402bcSSimon Horman 			struct flow_dissector_key_ipv6_addrs *ipv6;
417a38402bcSSimon Horman 
418a38402bcSSimon Horman 			ipv6 = skb_flow_dissector_target(flow_dissector,
419a38402bcSSimon Horman 							 FLOW_DISSECTOR_KEY_ENC_IPV6_ADDRS,
420a38402bcSSimon Horman 							 target_container);
421a38402bcSSimon Horman 			ipv6->src = key->u.ipv6.src;
422a38402bcSSimon Horman 			ipv6->dst = key->u.ipv6.dst;
423a38402bcSSimon Horman 		}
424a38402bcSSimon Horman 		break;
425a38402bcSSimon Horman 	}
426a38402bcSSimon Horman 
427a38402bcSSimon Horman 	if (dissector_uses_key(flow_dissector, FLOW_DISSECTOR_KEY_ENC_KEYID)) {
428a38402bcSSimon Horman 		struct flow_dissector_key_keyid *keyid;
429a38402bcSSimon Horman 
430a38402bcSSimon Horman 		keyid = skb_flow_dissector_target(flow_dissector,
431a38402bcSSimon Horman 						  FLOW_DISSECTOR_KEY_ENC_KEYID,
432a38402bcSSimon Horman 						  target_container);
433a38402bcSSimon Horman 		keyid->keyid = tunnel_id_to_key32(key->tun_id);
434a38402bcSSimon Horman 	}
435a38402bcSSimon Horman 
436a38402bcSSimon Horman 	if (dissector_uses_key(flow_dissector, FLOW_DISSECTOR_KEY_ENC_PORTS)) {
437a38402bcSSimon Horman 		struct flow_dissector_key_ports *tp;
438a38402bcSSimon Horman 
439a38402bcSSimon Horman 		tp = skb_flow_dissector_target(flow_dissector,
440a38402bcSSimon Horman 					       FLOW_DISSECTOR_KEY_ENC_PORTS,
441a38402bcSSimon Horman 					       target_container);
442a38402bcSSimon Horman 		tp->src = key->tp_src;
443a38402bcSSimon Horman 		tp->dst = key->tp_dst;
444a38402bcSSimon Horman 	}
4455544adb9SOr Gerlitz 
4465544adb9SOr Gerlitz 	if (dissector_uses_key(flow_dissector, FLOW_DISSECTOR_KEY_ENC_IP)) {
4475544adb9SOr Gerlitz 		struct flow_dissector_key_ip *ip;
4485544adb9SOr Gerlitz 
4495544adb9SOr Gerlitz 		ip = skb_flow_dissector_target(flow_dissector,
4505544adb9SOr Gerlitz 					       FLOW_DISSECTOR_KEY_ENC_IP,
4515544adb9SOr Gerlitz 					       target_container);
4525544adb9SOr Gerlitz 		ip->tos = key->tos;
4535544adb9SOr Gerlitz 		ip->ttl = key->ttl;
4545544adb9SOr Gerlitz 	}
45592e2c405SSimon Horman 
45692e2c405SSimon Horman 	if (dissector_uses_key(flow_dissector, FLOW_DISSECTOR_KEY_ENC_OPTS)) {
45792e2c405SSimon Horman 		struct flow_dissector_key_enc_opts *enc_opt;
45892e2c405SSimon Horman 
45992e2c405SSimon Horman 		enc_opt = skb_flow_dissector_target(flow_dissector,
46092e2c405SSimon Horman 						    FLOW_DISSECTOR_KEY_ENC_OPTS,
46192e2c405SSimon Horman 						    target_container);
46292e2c405SSimon Horman 
46392e2c405SSimon Horman 		if (info->options_len) {
46492e2c405SSimon Horman 			enc_opt->len = info->options_len;
46592e2c405SSimon Horman 			ip_tunnel_info_opts_get(enc_opt->data, info);
46692e2c405SSimon Horman 			enc_opt->dst_opt_type = info->key.tun_flags &
46792e2c405SSimon Horman 						TUNNEL_OPTIONS_PRESENT;
46892e2c405SSimon Horman 		}
46992e2c405SSimon Horman 	}
470a38402bcSSimon Horman }
47162b32379SSimon Horman EXPORT_SYMBOL(skb_flow_dissect_tunnel_info);
472a38402bcSSimon Horman 
skb_flow_dissect_hash(const struct sk_buff * skb,struct flow_dissector * flow_dissector,void * target_container)4730cb09affSAriel Levkovich void skb_flow_dissect_hash(const struct sk_buff *skb,
4740cb09affSAriel Levkovich 			   struct flow_dissector *flow_dissector,
4750cb09affSAriel Levkovich 			   void *target_container)
4760cb09affSAriel Levkovich {
4770cb09affSAriel Levkovich 	struct flow_dissector_key_hash *key;
4780cb09affSAriel Levkovich 
4790cb09affSAriel Levkovich 	if (!dissector_uses_key(flow_dissector, FLOW_DISSECTOR_KEY_HASH))
4800cb09affSAriel Levkovich 		return;
4810cb09affSAriel Levkovich 
4820cb09affSAriel Levkovich 	key = skb_flow_dissector_target(flow_dissector,
4830cb09affSAriel Levkovich 					FLOW_DISSECTOR_KEY_HASH,
4840cb09affSAriel Levkovich 					target_container);
4850cb09affSAriel Levkovich 
4860cb09affSAriel Levkovich 	key->hash = skb_get_hash_raw(skb);
4870cb09affSAriel Levkovich }
4880cb09affSAriel Levkovich EXPORT_SYMBOL(skb_flow_dissect_hash);
4890cb09affSAriel Levkovich 
4909bf881ffSJiri 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)4914a5d6c8bSJiri Pirko __skb_flow_dissect_mpls(const struct sk_buff *skb,
4924a5d6c8bSJiri Pirko 			struct flow_dissector *flow_dissector,
493f96533cdSAlexander Lobakin 			void *target_container, const void *data, int nhoff,
494f96533cdSAlexander Lobakin 			int hlen, int lse_index, bool *entropy_label)
4954a5d6c8bSJiri Pirko {
49658cff782SGuillaume Nault 	struct mpls_label *hdr, _hdr;
49758cff782SGuillaume Nault 	u32 entry, label, bos;
4984a5d6c8bSJiri Pirko 
4994a5d6c8bSJiri Pirko 	if (!dissector_uses_key(flow_dissector,
500029c1ecbSBenjamin LaHaise 				FLOW_DISSECTOR_KEY_MPLS_ENTROPY) &&
501029c1ecbSBenjamin LaHaise 	    !dissector_uses_key(flow_dissector, FLOW_DISSECTOR_KEY_MPLS))
5024a5d6c8bSJiri Pirko 		return FLOW_DISSECT_RET_OUT_GOOD;
5034a5d6c8bSJiri Pirko 
50458cff782SGuillaume Nault 	if (lse_index >= FLOW_DIS_MPLS_MAX)
50558cff782SGuillaume Nault 		return FLOW_DISSECT_RET_OUT_GOOD;
50658cff782SGuillaume Nault 
5074a5d6c8bSJiri Pirko 	hdr = __skb_header_pointer(skb, nhoff, sizeof(_hdr), data,
5084a5d6c8bSJiri Pirko 				   hlen, &_hdr);
5094a5d6c8bSJiri Pirko 	if (!hdr)
5104a5d6c8bSJiri Pirko 		return FLOW_DISSECT_RET_OUT_BAD;
5114a5d6c8bSJiri Pirko 
51258cff782SGuillaume Nault 	entry = ntohl(hdr->entry);
513029c1ecbSBenjamin LaHaise 	label = (entry & MPLS_LS_LABEL_MASK) >> MPLS_LS_LABEL_SHIFT;
51458cff782SGuillaume Nault 	bos = (entry & MPLS_LS_S_MASK) >> MPLS_LS_S_SHIFT;
515029c1ecbSBenjamin LaHaise 
516029c1ecbSBenjamin LaHaise 	if (dissector_uses_key(flow_dissector, FLOW_DISSECTOR_KEY_MPLS)) {
517029c1ecbSBenjamin LaHaise 		struct flow_dissector_key_mpls *key_mpls;
51858cff782SGuillaume Nault 		struct flow_dissector_mpls_lse *lse;
519029c1ecbSBenjamin LaHaise 
520029c1ecbSBenjamin LaHaise 		key_mpls = skb_flow_dissector_target(flow_dissector,
521029c1ecbSBenjamin LaHaise 						     FLOW_DISSECTOR_KEY_MPLS,
522029c1ecbSBenjamin LaHaise 						     target_container);
52358cff782SGuillaume Nault 		lse = &key_mpls->ls[lse_index];
52458cff782SGuillaume Nault 
52558cff782SGuillaume Nault 		lse->mpls_ttl = (entry & MPLS_LS_TTL_MASK) >> MPLS_LS_TTL_SHIFT;
52658cff782SGuillaume Nault 		lse->mpls_bos = bos;
52758cff782SGuillaume Nault 		lse->mpls_tc = (entry & MPLS_LS_TC_MASK) >> MPLS_LS_TC_SHIFT;
52858cff782SGuillaume Nault 		lse->mpls_label = label;
52958cff782SGuillaume Nault 		dissector_set_mpls_lse(key_mpls, lse_index);
530029c1ecbSBenjamin LaHaise 	}
531029c1ecbSBenjamin LaHaise 
53258cff782SGuillaume Nault 	if (*entropy_label &&
53358cff782SGuillaume Nault 	    dissector_uses_key(flow_dissector,
53458cff782SGuillaume Nault 			       FLOW_DISSECTOR_KEY_MPLS_ENTROPY)) {
53558cff782SGuillaume Nault 		struct flow_dissector_key_keyid *key_keyid;
53658cff782SGuillaume Nault 
5374a5d6c8bSJiri Pirko 		key_keyid = skb_flow_dissector_target(flow_dissector,
5384a5d6c8bSJiri Pirko 						      FLOW_DISSECTOR_KEY_MPLS_ENTROPY,
5394a5d6c8bSJiri Pirko 						      target_container);
54058cff782SGuillaume Nault 		key_keyid->keyid = cpu_to_be32(label);
5414a5d6c8bSJiri Pirko 	}
54258cff782SGuillaume Nault 
54358cff782SGuillaume Nault 	*entropy_label = label == MPLS_LABEL_ENTROPY;
54458cff782SGuillaume Nault 
54558cff782SGuillaume Nault 	return bos ? FLOW_DISSECT_RET_OUT_GOOD : FLOW_DISSECT_RET_PROTO_AGAIN;
5464a5d6c8bSJiri Pirko }
5474a5d6c8bSJiri Pirko 
5484a5d6c8bSJiri 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)5499bf881ffSJiri Pirko __skb_flow_dissect_arp(const struct sk_buff *skb,
5509bf881ffSJiri Pirko 		       struct flow_dissector *flow_dissector,
551f96533cdSAlexander Lobakin 		       void *target_container, const void *data,
552f96533cdSAlexander Lobakin 		       int nhoff, int hlen)
5539bf881ffSJiri Pirko {
5549bf881ffSJiri Pirko 	struct flow_dissector_key_arp *key_arp;
5559bf881ffSJiri Pirko 	struct {
5569bf881ffSJiri Pirko 		unsigned char ar_sha[ETH_ALEN];
5579bf881ffSJiri Pirko 		unsigned char ar_sip[4];
5589bf881ffSJiri Pirko 		unsigned char ar_tha[ETH_ALEN];
5599bf881ffSJiri Pirko 		unsigned char ar_tip[4];
5609bf881ffSJiri Pirko 	} *arp_eth, _arp_eth;
5619bf881ffSJiri Pirko 	const struct arphdr *arp;
5626f14f443SDavid S. Miller 	struct arphdr _arp;
5639bf881ffSJiri Pirko 
5649bf881ffSJiri Pirko 	if (!dissector_uses_key(flow_dissector, FLOW_DISSECTOR_KEY_ARP))
5659bf881ffSJiri Pirko 		return FLOW_DISSECT_RET_OUT_GOOD;
5669bf881ffSJiri Pirko 
5679bf881ffSJiri Pirko 	arp = __skb_header_pointer(skb, nhoff, sizeof(_arp), data,
5689bf881ffSJiri Pirko 				   hlen, &_arp);
5699bf881ffSJiri Pirko 	if (!arp)
5709bf881ffSJiri Pirko 		return FLOW_DISSECT_RET_OUT_BAD;
5719bf881ffSJiri Pirko 
5729bf881ffSJiri Pirko 	if (arp->ar_hrd != htons(ARPHRD_ETHER) ||
5739bf881ffSJiri Pirko 	    arp->ar_pro != htons(ETH_P_IP) ||
5749bf881ffSJiri Pirko 	    arp->ar_hln != ETH_ALEN ||
5759bf881ffSJiri Pirko 	    arp->ar_pln != 4 ||
5769bf881ffSJiri Pirko 	    (arp->ar_op != htons(ARPOP_REPLY) &&
5779bf881ffSJiri Pirko 	     arp->ar_op != htons(ARPOP_REQUEST)))
5789bf881ffSJiri Pirko 		return FLOW_DISSECT_RET_OUT_BAD;
5799bf881ffSJiri Pirko 
5809bf881ffSJiri Pirko 	arp_eth = __skb_header_pointer(skb, nhoff + sizeof(_arp),
5819bf881ffSJiri Pirko 				       sizeof(_arp_eth), data,
5829bf881ffSJiri Pirko 				       hlen, &_arp_eth);
5839bf881ffSJiri Pirko 	if (!arp_eth)
5849bf881ffSJiri Pirko 		return FLOW_DISSECT_RET_OUT_BAD;
5859bf881ffSJiri Pirko 
5869bf881ffSJiri Pirko 	key_arp = skb_flow_dissector_target(flow_dissector,
5879bf881ffSJiri Pirko 					    FLOW_DISSECTOR_KEY_ARP,
5889bf881ffSJiri Pirko 					    target_container);
5899bf881ffSJiri Pirko 
5909bf881ffSJiri Pirko 	memcpy(&key_arp->sip, arp_eth->ar_sip, sizeof(key_arp->sip));
5919bf881ffSJiri Pirko 	memcpy(&key_arp->tip, arp_eth->ar_tip, sizeof(key_arp->tip));
5929bf881ffSJiri Pirko 
5939bf881ffSJiri Pirko 	/* Only store the lower byte of the opcode;
5949bf881ffSJiri Pirko 	 * this covers ARPOP_REPLY and ARPOP_REQUEST.
5959bf881ffSJiri Pirko 	 */
5969bf881ffSJiri Pirko 	key_arp->op = ntohs(arp->ar_op) & 0xff;
5979bf881ffSJiri Pirko 
5989bf881ffSJiri Pirko 	ether_addr_copy(key_arp->sha, arp_eth->ar_sha);
5999bf881ffSJiri Pirko 	ether_addr_copy(key_arp->tha, arp_eth->ar_tha);
6009bf881ffSJiri Pirko 
6019bf881ffSJiri Pirko 	return FLOW_DISSECT_RET_OUT_GOOD;
6029bf881ffSJiri Pirko }
6039bf881ffSJiri Pirko 
6047c92de8eSJiri 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)605d7ad70b5SZahari Doychev __skb_flow_dissect_cfm(const struct sk_buff *skb,
606d7ad70b5SZahari Doychev 		       struct flow_dissector *flow_dissector,
607d7ad70b5SZahari Doychev 		       void *target_container, const void *data,
608d7ad70b5SZahari Doychev 		       int nhoff, int hlen)
609d7ad70b5SZahari Doychev {
610d7ad70b5SZahari Doychev 	struct flow_dissector_key_cfm *key, *hdr, _hdr;
611d7ad70b5SZahari Doychev 
612d7ad70b5SZahari Doychev 	if (!dissector_uses_key(flow_dissector, FLOW_DISSECTOR_KEY_CFM))
613d7ad70b5SZahari Doychev 		return FLOW_DISSECT_RET_OUT_GOOD;
614d7ad70b5SZahari Doychev 
615d7ad70b5SZahari Doychev 	hdr = __skb_header_pointer(skb, nhoff, sizeof(*key), data, hlen, &_hdr);
616d7ad70b5SZahari Doychev 	if (!hdr)
617d7ad70b5SZahari Doychev 		return FLOW_DISSECT_RET_OUT_BAD;
618d7ad70b5SZahari Doychev 
619d7ad70b5SZahari Doychev 	key = skb_flow_dissector_target(flow_dissector, FLOW_DISSECTOR_KEY_CFM,
620d7ad70b5SZahari Doychev 					target_container);
621d7ad70b5SZahari Doychev 
622d7ad70b5SZahari Doychev 	key->mdl_ver = hdr->mdl_ver;
623d7ad70b5SZahari Doychev 	key->opcode = hdr->opcode;
624d7ad70b5SZahari Doychev 
625d7ad70b5SZahari Doychev 	return FLOW_DISSECT_RET_OUT_GOOD;
626d7ad70b5SZahari Doychev }
627d7ad70b5SZahari Doychev 
628d7ad70b5SZahari 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)6297c92de8eSJiri Pirko __skb_flow_dissect_gre(const struct sk_buff *skb,
6307c92de8eSJiri Pirko 		       struct flow_dissector_key_control *key_control,
6317c92de8eSJiri Pirko 		       struct flow_dissector *flow_dissector,
632f96533cdSAlexander Lobakin 		       void *target_container, const void *data,
6337c92de8eSJiri Pirko 		       __be16 *p_proto, int *p_nhoff, int *p_hlen,
6347c92de8eSJiri Pirko 		       unsigned int flags)
6357c92de8eSJiri Pirko {
6367c92de8eSJiri Pirko 	struct flow_dissector_key_keyid *key_keyid;
6377c92de8eSJiri Pirko 	struct gre_base_hdr *hdr, _hdr;
6387c92de8eSJiri Pirko 	int offset = 0;
6397c92de8eSJiri Pirko 	u16 gre_ver;
6407c92de8eSJiri Pirko 
6417c92de8eSJiri Pirko 	hdr = __skb_header_pointer(skb, *p_nhoff, sizeof(_hdr),
6427c92de8eSJiri Pirko 				   data, *p_hlen, &_hdr);
6437c92de8eSJiri Pirko 	if (!hdr)
6447c92de8eSJiri Pirko 		return FLOW_DISSECT_RET_OUT_BAD;
6457c92de8eSJiri Pirko 
6467c92de8eSJiri Pirko 	/* Only look inside GRE without routing */
6477c92de8eSJiri Pirko 	if (hdr->flags & GRE_ROUTING)
6487c92de8eSJiri Pirko 		return FLOW_DISSECT_RET_OUT_GOOD;
6497c92de8eSJiri Pirko 
6507c92de8eSJiri Pirko 	/* Only look inside GRE for version 0 and 1 */
6517c92de8eSJiri Pirko 	gre_ver = ntohs(hdr->flags & GRE_VERSION);
6527c92de8eSJiri Pirko 	if (gre_ver > 1)
6537c92de8eSJiri Pirko 		return FLOW_DISSECT_RET_OUT_GOOD;
6547c92de8eSJiri Pirko 
6557c92de8eSJiri Pirko 	*p_proto = hdr->protocol;
6567c92de8eSJiri Pirko 	if (gre_ver) {
6577c92de8eSJiri Pirko 		/* Version1 must be PPTP, and check the flags */
6587c92de8eSJiri Pirko 		if (!(*p_proto == GRE_PROTO_PPP && (hdr->flags & GRE_KEY)))
6597c92de8eSJiri Pirko 			return FLOW_DISSECT_RET_OUT_GOOD;
6607c92de8eSJiri Pirko 	}
6617c92de8eSJiri Pirko 
6627c92de8eSJiri Pirko 	offset += sizeof(struct gre_base_hdr);
6637c92de8eSJiri Pirko 
6647c92de8eSJiri Pirko 	if (hdr->flags & GRE_CSUM)
665c593642cSPankaj Bharadiya 		offset += sizeof_field(struct gre_full_hdr, csum) +
666c593642cSPankaj Bharadiya 			  sizeof_field(struct gre_full_hdr, reserved1);
6677c92de8eSJiri Pirko 
6687c92de8eSJiri Pirko 	if (hdr->flags & GRE_KEY) {
6697c92de8eSJiri Pirko 		const __be32 *keyid;
6707c92de8eSJiri Pirko 		__be32 _keyid;
6717c92de8eSJiri Pirko 
6727c92de8eSJiri Pirko 		keyid = __skb_header_pointer(skb, *p_nhoff + offset,
6737c92de8eSJiri Pirko 					     sizeof(_keyid),
6747c92de8eSJiri Pirko 					     data, *p_hlen, &_keyid);
6757c92de8eSJiri Pirko 		if (!keyid)
6767c92de8eSJiri Pirko 			return FLOW_DISSECT_RET_OUT_BAD;
6777c92de8eSJiri Pirko 
6787c92de8eSJiri Pirko 		if (dissector_uses_key(flow_dissector,
6797c92de8eSJiri Pirko 				       FLOW_DISSECTOR_KEY_GRE_KEYID)) {
6807c92de8eSJiri Pirko 			key_keyid = skb_flow_dissector_target(flow_dissector,
6817c92de8eSJiri Pirko 							      FLOW_DISSECTOR_KEY_GRE_KEYID,
6827c92de8eSJiri Pirko 							      target_container);
6837c92de8eSJiri Pirko 			if (gre_ver == 0)
6847c92de8eSJiri Pirko 				key_keyid->keyid = *keyid;
6857c92de8eSJiri Pirko 			else
6867c92de8eSJiri Pirko 				key_keyid->keyid = *keyid & GRE_PPTP_KEY_MASK;
6877c92de8eSJiri Pirko 		}
688c593642cSPankaj Bharadiya 		offset += sizeof_field(struct gre_full_hdr, key);
6897c92de8eSJiri Pirko 	}
6907c92de8eSJiri Pirko 
6917c92de8eSJiri Pirko 	if (hdr->flags & GRE_SEQ)
692c593642cSPankaj Bharadiya 		offset += sizeof_field(struct pptp_gre_header, seq);
6937c92de8eSJiri Pirko 
6947c92de8eSJiri Pirko 	if (gre_ver == 0) {
6957c92de8eSJiri Pirko 		if (*p_proto == htons(ETH_P_TEB)) {
6967c92de8eSJiri Pirko 			const struct ethhdr *eth;
6977c92de8eSJiri Pirko 			struct ethhdr _eth;
6987c92de8eSJiri Pirko 
6997c92de8eSJiri Pirko 			eth = __skb_header_pointer(skb, *p_nhoff + offset,
7007c92de8eSJiri Pirko 						   sizeof(_eth),
7017c92de8eSJiri Pirko 						   data, *p_hlen, &_eth);
7027c92de8eSJiri Pirko 			if (!eth)
7037c92de8eSJiri Pirko 				return FLOW_DISSECT_RET_OUT_BAD;
7047c92de8eSJiri Pirko 			*p_proto = eth->h_proto;
7057c92de8eSJiri Pirko 			offset += sizeof(*eth);
7067c92de8eSJiri Pirko 
7077c92de8eSJiri Pirko 			/* Cap headers that we access via pointers at the
7087c92de8eSJiri Pirko 			 * end of the Ethernet header as our maximum alignment
7097c92de8eSJiri Pirko 			 * at that point is only 2 bytes.
7107c92de8eSJiri Pirko 			 */
7117c92de8eSJiri Pirko 			if (NET_IP_ALIGN)
7127c92de8eSJiri Pirko 				*p_hlen = *p_nhoff + offset;
7137c92de8eSJiri Pirko 		}
7147c92de8eSJiri Pirko 	} else { /* version 1, must be PPTP */
7157c92de8eSJiri Pirko 		u8 _ppp_hdr[PPP_HDRLEN];
7167c92de8eSJiri Pirko 		u8 *ppp_hdr;
7177c92de8eSJiri Pirko 
7187c92de8eSJiri Pirko 		if (hdr->flags & GRE_ACK)
719c593642cSPankaj Bharadiya 			offset += sizeof_field(struct pptp_gre_header, ack);
7207c92de8eSJiri Pirko 
7217c92de8eSJiri Pirko 		ppp_hdr = __skb_header_pointer(skb, *p_nhoff + offset,
7227c92de8eSJiri Pirko 					       sizeof(_ppp_hdr),
7237c92de8eSJiri Pirko 					       data, *p_hlen, _ppp_hdr);
7247c92de8eSJiri Pirko 		if (!ppp_hdr)
7257c92de8eSJiri Pirko 			return FLOW_DISSECT_RET_OUT_BAD;
7267c92de8eSJiri Pirko 
7277c92de8eSJiri Pirko 		switch (PPP_PROTOCOL(ppp_hdr)) {
7287c92de8eSJiri Pirko 		case PPP_IP:
7297c92de8eSJiri Pirko 			*p_proto = htons(ETH_P_IP);
7307c92de8eSJiri Pirko 			break;
7317c92de8eSJiri Pirko 		case PPP_IPV6:
7327c92de8eSJiri Pirko 			*p_proto = htons(ETH_P_IPV6);
7337c92de8eSJiri Pirko 			break;
7347c92de8eSJiri Pirko 		default:
7357c92de8eSJiri Pirko 			/* Could probably catch some more like MPLS */
7367c92de8eSJiri Pirko 			break;
7377c92de8eSJiri Pirko 		}
7387c92de8eSJiri Pirko 
7397c92de8eSJiri Pirko 		offset += PPP_HDRLEN;
7407c92de8eSJiri Pirko 	}
7417c92de8eSJiri Pirko 
7427c92de8eSJiri Pirko 	*p_nhoff += offset;
7437c92de8eSJiri Pirko 	key_control->flags |= FLOW_DIS_ENCAPSULATION;
7447c92de8eSJiri Pirko 	if (flags & FLOW_DISSECTOR_F_STOP_AT_ENCAP)
7457c92de8eSJiri Pirko 		return FLOW_DISSECT_RET_OUT_GOOD;
7467c92de8eSJiri Pirko 
7473a1214e8STom Herbert 	return FLOW_DISSECT_RET_PROTO_AGAIN;
7487c92de8eSJiri Pirko }
7497c92de8eSJiri Pirko 
7505b0890a9SSven Eckelmann /**
7515b0890a9SSven Eckelmann  * __skb_flow_dissect_batadv() - dissect batman-adv header
7525b0890a9SSven Eckelmann  * @skb: sk_buff to with the batman-adv header
7535b0890a9SSven Eckelmann  * @key_control: flow dissectors control key
7545b0890a9SSven Eckelmann  * @data: raw buffer pointer to the packet, if NULL use skb->data
7555b0890a9SSven Eckelmann  * @p_proto: pointer used to update the protocol to process next
7565b0890a9SSven Eckelmann  * @p_nhoff: pointer used to update inner network header offset
7575b0890a9SSven Eckelmann  * @hlen: packet header length
7585b0890a9SSven Eckelmann  * @flags: any combination of FLOW_DISSECTOR_F_*
7595b0890a9SSven Eckelmann  *
7605b0890a9SSven Eckelmann  * ETH_P_BATMAN packets are tried to be dissected. Only
7615b0890a9SSven Eckelmann  * &struct batadv_unicast packets are actually processed because they contain an
7625b0890a9SSven Eckelmann  * inner ethernet header and are usually followed by actual network header. This
7635b0890a9SSven Eckelmann  * allows the flow dissector to continue processing the packet.
7645b0890a9SSven Eckelmann  *
7655b0890a9SSven Eckelmann  * Return: FLOW_DISSECT_RET_PROTO_AGAIN when &struct batadv_unicast was found,
7665b0890a9SSven Eckelmann  *  FLOW_DISSECT_RET_OUT_GOOD when dissector should stop after encapsulation,
7675b0890a9SSven Eckelmann  *  otherwise FLOW_DISSECT_RET_OUT_BAD
7685b0890a9SSven Eckelmann  */
7695b0890a9SSven 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)7705b0890a9SSven Eckelmann __skb_flow_dissect_batadv(const struct sk_buff *skb,
7715b0890a9SSven Eckelmann 			  struct flow_dissector_key_control *key_control,
772f96533cdSAlexander Lobakin 			  const void *data, __be16 *p_proto, int *p_nhoff,
773f96533cdSAlexander Lobakin 			  int hlen, unsigned int flags)
7745b0890a9SSven Eckelmann {
7755b0890a9SSven Eckelmann 	struct {
7765b0890a9SSven Eckelmann 		struct batadv_unicast_packet batadv_unicast;
7775b0890a9SSven Eckelmann 		struct ethhdr eth;
7785b0890a9SSven Eckelmann 	} *hdr, _hdr;
7795b0890a9SSven Eckelmann 
7805b0890a9SSven Eckelmann 	hdr = __skb_header_pointer(skb, *p_nhoff, sizeof(_hdr), data, hlen,
7815b0890a9SSven Eckelmann 				   &_hdr);
7825b0890a9SSven Eckelmann 	if (!hdr)
7835b0890a9SSven Eckelmann 		return FLOW_DISSECT_RET_OUT_BAD;
7845b0890a9SSven Eckelmann 
7855b0890a9SSven Eckelmann 	if (hdr->batadv_unicast.version != BATADV_COMPAT_VERSION)
7865b0890a9SSven Eckelmann 		return FLOW_DISSECT_RET_OUT_BAD;
7875b0890a9SSven Eckelmann 
7885b0890a9SSven Eckelmann 	if (hdr->batadv_unicast.packet_type != BATADV_UNICAST)
7895b0890a9SSven Eckelmann 		return FLOW_DISSECT_RET_OUT_BAD;
7905b0890a9SSven Eckelmann 
7915b0890a9SSven Eckelmann 	*p_proto = hdr->eth.h_proto;
7925b0890a9SSven Eckelmann 	*p_nhoff += sizeof(*hdr);
7935b0890a9SSven Eckelmann 
7945b0890a9SSven Eckelmann 	key_control->flags |= FLOW_DIS_ENCAPSULATION;
7955b0890a9SSven Eckelmann 	if (flags & FLOW_DISSECTOR_F_STOP_AT_ENCAP)
7965b0890a9SSven Eckelmann 		return FLOW_DISSECT_RET_OUT_GOOD;
7975b0890a9SSven Eckelmann 
7985b0890a9SSven Eckelmann 	return FLOW_DISSECT_RET_PROTO_AGAIN;
7995b0890a9SSven Eckelmann }
8005b0890a9SSven Eckelmann 
801ac4bb5deSJiri 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)802ac4bb5deSJiri Pirko __skb_flow_dissect_tcp(const struct sk_buff *skb,
803ac4bb5deSJiri Pirko 		       struct flow_dissector *flow_dissector,
804f96533cdSAlexander Lobakin 		       void *target_container, const void *data,
805f96533cdSAlexander Lobakin 		       int thoff, int hlen)
806ac4bb5deSJiri Pirko {
807ac4bb5deSJiri Pirko 	struct flow_dissector_key_tcp *key_tcp;
808ac4bb5deSJiri Pirko 	struct tcphdr *th, _th;
809ac4bb5deSJiri Pirko 
810ac4bb5deSJiri Pirko 	if (!dissector_uses_key(flow_dissector, FLOW_DISSECTOR_KEY_TCP))
811ac4bb5deSJiri Pirko 		return;
812ac4bb5deSJiri Pirko 
813ac4bb5deSJiri Pirko 	th = __skb_header_pointer(skb, thoff, sizeof(_th), data, hlen, &_th);
814ac4bb5deSJiri Pirko 	if (!th)
815ac4bb5deSJiri Pirko 		return;
816ac4bb5deSJiri Pirko 
817ac4bb5deSJiri Pirko 	if (unlikely(__tcp_hdrlen(th) < sizeof(_th)))
818ac4bb5deSJiri Pirko 		return;
819ac4bb5deSJiri Pirko 
820ac4bb5deSJiri Pirko 	key_tcp = skb_flow_dissector_target(flow_dissector,
821ac4bb5deSJiri Pirko 					    FLOW_DISSECTOR_KEY_TCP,
822ac4bb5deSJiri Pirko 					    target_container);
823ac4bb5deSJiri Pirko 	key_tcp->flags = (*(__be16 *) &tcp_flag_word(th) & htons(0x0FFF));
824ac4bb5deSJiri Pirko }
825ac4bb5deSJiri Pirko 
826518d8a2eSOr 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)8278ffb055bSYoshiki Komachi __skb_flow_dissect_ports(const struct sk_buff *skb,
8288ffb055bSYoshiki Komachi 			 struct flow_dissector *flow_dissector,
829f96533cdSAlexander Lobakin 			 void *target_container, const void *data,
830f96533cdSAlexander Lobakin 			 int nhoff, u8 ip_proto, int hlen)
8318ffb055bSYoshiki Komachi {
832dfc61b8bSCong Wang 	struct flow_dissector_key_ports_range *key_ports_range = NULL;
833dfc61b8bSCong Wang 	struct flow_dissector_key_ports *key_ports = NULL;
834dfc61b8bSCong Wang 	__be32 ports;
8358ffb055bSYoshiki Komachi 
8368ffb055bSYoshiki Komachi 	if (dissector_uses_key(flow_dissector, FLOW_DISSECTOR_KEY_PORTS))
837dfc61b8bSCong Wang 		key_ports = skb_flow_dissector_target(flow_dissector,
838dfc61b8bSCong Wang 						      FLOW_DISSECTOR_KEY_PORTS,
839dfc61b8bSCong Wang 						      target_container);
8408ffb055bSYoshiki Komachi 
841dfc61b8bSCong Wang 	if (dissector_uses_key(flow_dissector, FLOW_DISSECTOR_KEY_PORTS_RANGE))
842dfc61b8bSCong Wang 		key_ports_range = skb_flow_dissector_target(flow_dissector,
843dfc61b8bSCong Wang 							    FLOW_DISSECTOR_KEY_PORTS_RANGE,
844dfc61b8bSCong Wang 							    target_container);
845dfc61b8bSCong Wang 
846dfc61b8bSCong Wang 	if (!key_ports && !key_ports_range)
8478ffb055bSYoshiki Komachi 		return;
8488ffb055bSYoshiki Komachi 
849dfc61b8bSCong Wang 	ports = __skb_flow_get_ports(skb, nhoff, ip_proto, data, hlen);
850dfc61b8bSCong Wang 
851dfc61b8bSCong Wang 	if (key_ports)
852dfc61b8bSCong Wang 		key_ports->ports = ports;
853dfc61b8bSCong Wang 
854dfc61b8bSCong Wang 	if (key_ports_range)
855dfc61b8bSCong Wang 		key_ports_range->tp.ports = ports;
8568ffb055bSYoshiki Komachi }
8578ffb055bSYoshiki Komachi 
8588ffb055bSYoshiki 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)859518d8a2eSOr Gerlitz __skb_flow_dissect_ipv4(const struct sk_buff *skb,
860518d8a2eSOr Gerlitz 			struct flow_dissector *flow_dissector,
861f96533cdSAlexander Lobakin 			void *target_container, const void *data,
862f96533cdSAlexander Lobakin 			const struct iphdr *iph)
863518d8a2eSOr Gerlitz {
864518d8a2eSOr Gerlitz 	struct flow_dissector_key_ip *key_ip;
865518d8a2eSOr Gerlitz 
866518d8a2eSOr Gerlitz 	if (!dissector_uses_key(flow_dissector, FLOW_DISSECTOR_KEY_IP))
867518d8a2eSOr Gerlitz 		return;
868518d8a2eSOr Gerlitz 
869518d8a2eSOr Gerlitz 	key_ip = skb_flow_dissector_target(flow_dissector,
870518d8a2eSOr Gerlitz 					   FLOW_DISSECTOR_KEY_IP,
871518d8a2eSOr Gerlitz 					   target_container);
872518d8a2eSOr Gerlitz 	key_ip->tos = iph->tos;
873518d8a2eSOr Gerlitz 	key_ip->ttl = iph->ttl;
874518d8a2eSOr Gerlitz }
875518d8a2eSOr Gerlitz 
876518d8a2eSOr 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)877518d8a2eSOr Gerlitz __skb_flow_dissect_ipv6(const struct sk_buff *skb,
878518d8a2eSOr Gerlitz 			struct flow_dissector *flow_dissector,
879f96533cdSAlexander Lobakin 			void *target_container, const void *data,
880f96533cdSAlexander Lobakin 			const struct ipv6hdr *iph)
881518d8a2eSOr Gerlitz {
882518d8a2eSOr Gerlitz 	struct flow_dissector_key_ip *key_ip;
883518d8a2eSOr Gerlitz 
884518d8a2eSOr Gerlitz 	if (!dissector_uses_key(flow_dissector, FLOW_DISSECTOR_KEY_IP))
885518d8a2eSOr Gerlitz 		return;
886518d8a2eSOr Gerlitz 
887518d8a2eSOr Gerlitz 	key_ip = skb_flow_dissector_target(flow_dissector,
888518d8a2eSOr Gerlitz 					   FLOW_DISSECTOR_KEY_IP,
889518d8a2eSOr Gerlitz 					   target_container);
890518d8a2eSOr Gerlitz 	key_ip->tos = ipv6_get_dsfield(iph);
891518d8a2eSOr Gerlitz 	key_ip->ttl = iph->hop_limit;
892518d8a2eSOr Gerlitz }
893518d8a2eSOr Gerlitz 
8941eed4dfbSTom Herbert /* Maximum number of protocol headers that can be parsed in
8951eed4dfbSTom Herbert  * __skb_flow_dissect
8961eed4dfbSTom Herbert  */
8971eed4dfbSTom Herbert #define MAX_FLOW_DISSECT_HDRS	15
8981eed4dfbSTom Herbert 
skb_flow_dissect_allowed(int * num_hdrs)8991eed4dfbSTom Herbert static bool skb_flow_dissect_allowed(int *num_hdrs)
9001eed4dfbSTom Herbert {
9011eed4dfbSTom Herbert 	++*num_hdrs;
9021eed4dfbSTom Herbert 
9031eed4dfbSTom Herbert 	return (*num_hdrs <= MAX_FLOW_DISSECT_HDRS);
9041eed4dfbSTom Herbert }
9051eed4dfbSTom Herbert 
__skb_flow_bpf_to_target(const struct bpf_flow_keys * flow_keys,struct flow_dissector * flow_dissector,void * target_container)906d58e468bSPetar Penkov static void __skb_flow_bpf_to_target(const struct bpf_flow_keys *flow_keys,
907d58e468bSPetar Penkov 				     struct flow_dissector *flow_dissector,
908d58e468bSPetar Penkov 				     void *target_container)
909d58e468bSPetar Penkov {
910*ef3d41c5SCong Wang 	struct flow_dissector_key_ports_range *key_ports_range = NULL;
91159fb9b62SYoshiki Komachi 	struct flow_dissector_key_ports *key_ports = NULL;
912d58e468bSPetar Penkov 	struct flow_dissector_key_control *key_control;
913d58e468bSPetar Penkov 	struct flow_dissector_key_basic *key_basic;
914d58e468bSPetar Penkov 	struct flow_dissector_key_addrs *key_addrs;
91571c99e32SStanislav Fomichev 	struct flow_dissector_key_tags *key_tags;
916d58e468bSPetar Penkov 
917d58e468bSPetar Penkov 	key_control = skb_flow_dissector_target(flow_dissector,
918d58e468bSPetar Penkov 						FLOW_DISSECTOR_KEY_CONTROL,
919d58e468bSPetar Penkov 						target_container);
920d58e468bSPetar Penkov 	key_control->thoff = flow_keys->thoff;
921d58e468bSPetar Penkov 	if (flow_keys->is_frag)
922d58e468bSPetar Penkov 		key_control->flags |= FLOW_DIS_IS_FRAGMENT;
923d58e468bSPetar Penkov 	if (flow_keys->is_first_frag)
924d58e468bSPetar Penkov 		key_control->flags |= FLOW_DIS_FIRST_FRAG;
925d58e468bSPetar Penkov 	if (flow_keys->is_encap)
926d58e468bSPetar Penkov 		key_control->flags |= FLOW_DIS_ENCAPSULATION;
927d58e468bSPetar Penkov 
928d58e468bSPetar Penkov 	key_basic = skb_flow_dissector_target(flow_dissector,
929d58e468bSPetar Penkov 					      FLOW_DISSECTOR_KEY_BASIC,
930d58e468bSPetar Penkov 					      target_container);
931d58e468bSPetar Penkov 	key_basic->n_proto = flow_keys->n_proto;
932d58e468bSPetar Penkov 	key_basic->ip_proto = flow_keys->ip_proto;
933d58e468bSPetar Penkov 
934d58e468bSPetar Penkov 	if (flow_keys->addr_proto == ETH_P_IP &&
935d58e468bSPetar Penkov 	    dissector_uses_key(flow_dissector, FLOW_DISSECTOR_KEY_IPV4_ADDRS)) {
936d58e468bSPetar Penkov 		key_addrs = skb_flow_dissector_target(flow_dissector,
937d58e468bSPetar Penkov 						      FLOW_DISSECTOR_KEY_IPV4_ADDRS,
938d58e468bSPetar Penkov 						      target_container);
939d58e468bSPetar Penkov 		key_addrs->v4addrs.src = flow_keys->ipv4_src;
940d58e468bSPetar Penkov 		key_addrs->v4addrs.dst = flow_keys->ipv4_dst;
941d58e468bSPetar Penkov 		key_control->addr_type = FLOW_DISSECTOR_KEY_IPV4_ADDRS;
942d58e468bSPetar Penkov 	} else if (flow_keys->addr_proto == ETH_P_IPV6 &&
943d58e468bSPetar Penkov 		   dissector_uses_key(flow_dissector,
944d58e468bSPetar Penkov 				      FLOW_DISSECTOR_KEY_IPV6_ADDRS)) {
945d58e468bSPetar Penkov 		key_addrs = skb_flow_dissector_target(flow_dissector,
946d58e468bSPetar Penkov 						      FLOW_DISSECTOR_KEY_IPV6_ADDRS,
947d58e468bSPetar Penkov 						      target_container);
9481e3d976dSGustavo A. R. Silva 		memcpy(&key_addrs->v6addrs.src, &flow_keys->ipv6_src,
9491e3d976dSGustavo A. R. Silva 		       sizeof(key_addrs->v6addrs.src));
9501e3d976dSGustavo A. R. Silva 		memcpy(&key_addrs->v6addrs.dst, &flow_keys->ipv6_dst,
9511e3d976dSGustavo A. R. Silva 		       sizeof(key_addrs->v6addrs.dst));
952d58e468bSPetar Penkov 		key_control->addr_type = FLOW_DISSECTOR_KEY_IPV6_ADDRS;
953d58e468bSPetar Penkov 	}
954d58e468bSPetar Penkov 
955*ef3d41c5SCong Wang 	if (dissector_uses_key(flow_dissector, FLOW_DISSECTOR_KEY_PORTS)) {
956d58e468bSPetar Penkov 		key_ports = skb_flow_dissector_target(flow_dissector,
957d58e468bSPetar Penkov 						      FLOW_DISSECTOR_KEY_PORTS,
958d58e468bSPetar Penkov 						      target_container);
959d58e468bSPetar Penkov 		key_ports->src = flow_keys->sport;
960d58e468bSPetar Penkov 		key_ports->dst = flow_keys->dport;
961d58e468bSPetar Penkov 	}
962*ef3d41c5SCong Wang 	if (dissector_uses_key(flow_dissector,
963*ef3d41c5SCong Wang 			       FLOW_DISSECTOR_KEY_PORTS_RANGE)) {
964*ef3d41c5SCong Wang 		key_ports_range = skb_flow_dissector_target(flow_dissector,
965*ef3d41c5SCong Wang 							    FLOW_DISSECTOR_KEY_PORTS_RANGE,
966*ef3d41c5SCong Wang 							    target_container);
967*ef3d41c5SCong Wang 		key_ports_range->tp.src = flow_keys->sport;
968*ef3d41c5SCong Wang 		key_ports_range->tp.dst = flow_keys->dport;
969*ef3d41c5SCong Wang 	}
97071c99e32SStanislav Fomichev 
97171c99e32SStanislav Fomichev 	if (dissector_uses_key(flow_dissector,
97271c99e32SStanislav Fomichev 			       FLOW_DISSECTOR_KEY_FLOW_LABEL)) {
97371c99e32SStanislav Fomichev 		key_tags = skb_flow_dissector_target(flow_dissector,
97471c99e32SStanislav Fomichev 						     FLOW_DISSECTOR_KEY_FLOW_LABEL,
97571c99e32SStanislav Fomichev 						     target_container);
97671c99e32SStanislav Fomichev 		key_tags->flow_label = ntohl(flow_keys->flow_label);
97771c99e32SStanislav Fomichev 	}
978d58e468bSPetar Penkov }
979d58e468bSPetar Penkov 
bpf_flow_dissect(struct bpf_prog * prog,struct bpf_flow_dissector * ctx,__be16 proto,int nhoff,int hlen,unsigned int flags)9800ba98502SShmulik Ladkani u32 bpf_flow_dissect(struct bpf_prog *prog, struct bpf_flow_dissector *ctx,
981086f9568SStanislav Fomichev 		     __be16 proto, int nhoff, int hlen, unsigned int flags)
982089b19a9SStanislav Fomichev {
983089b19a9SStanislav Fomichev 	struct bpf_flow_keys *flow_keys = ctx->flow_keys;
984c8aa7038SStanislav Fomichev 	u32 result;
985c8aa7038SStanislav Fomichev 
986c8aa7038SStanislav Fomichev 	/* Pass parameters to the BPF program */
987c8aa7038SStanislav Fomichev 	memset(flow_keys, 0, sizeof(*flow_keys));
988089b19a9SStanislav Fomichev 	flow_keys->n_proto = proto;
989089b19a9SStanislav Fomichev 	flow_keys->nhoff = nhoff;
990c8aa7038SStanislav Fomichev 	flow_keys->thoff = flow_keys->nhoff;
991c8aa7038SStanislav Fomichev 
992086f9568SStanislav Fomichev 	BUILD_BUG_ON((int)BPF_FLOW_DISSECTOR_F_PARSE_1ST_FRAG !=
993086f9568SStanislav Fomichev 		     (int)FLOW_DISSECTOR_F_PARSE_1ST_FRAG);
994086f9568SStanislav Fomichev 	BUILD_BUG_ON((int)BPF_FLOW_DISSECTOR_F_STOP_AT_FLOW_LABEL !=
995086f9568SStanislav Fomichev 		     (int)FLOW_DISSECTOR_F_STOP_AT_FLOW_LABEL);
996086f9568SStanislav Fomichev 	BUILD_BUG_ON((int)BPF_FLOW_DISSECTOR_F_STOP_AT_ENCAP !=
997086f9568SStanislav Fomichev 		     (int)FLOW_DISSECTOR_F_STOP_AT_ENCAP);
998086f9568SStanislav Fomichev 	flow_keys->flags = flags;
999086f9568SStanislav Fomichev 
10003d9f773cSDavid Miller 	result = bpf_prog_run_pin_on_cpu(prog, ctx);
1001c8aa7038SStanislav Fomichev 
1002089b19a9SStanislav Fomichev 	flow_keys->nhoff = clamp_t(u16, flow_keys->nhoff, nhoff, hlen);
1003c8aa7038SStanislav Fomichev 	flow_keys->thoff = clamp_t(u16, flow_keys->thoff,
1004089b19a9SStanislav Fomichev 				   flow_keys->nhoff, hlen);
1005c8aa7038SStanislav Fomichev 
10060ba98502SShmulik Ladkani 	return result;
1007c8aa7038SStanislav Fomichev }
1008c8aa7038SStanislav Fomichev 
is_pppoe_ses_hdr_valid(const struct pppoe_hdr * hdr)1009f86d1fbbSLinus Torvalds static bool is_pppoe_ses_hdr_valid(const struct pppoe_hdr *hdr)
101046126db9SWojciech Drewek {
1011f86d1fbbSLinus Torvalds 	return hdr->ver == 1 && hdr->type == 1 && hdr->code == 0;
101246126db9SWojciech Drewek }
101346126db9SWojciech Drewek 
1014453a940eSWANG Cong /**
1015453a940eSWANG Cong  * __skb_flow_dissect - extract the flow_keys struct and return it
10163cbf4ffbSStanislav Fomichev  * @net: associated network namespace, derived from @skb if NULL
1017453a940eSWANG Cong  * @skb: sk_buff to extract the flow from, can be NULL if the rest are specified
101806635a35SJiri Pirko  * @flow_dissector: list of keys to dissect
101906635a35SJiri Pirko  * @target_container: target structure to put dissected values into
1020453a940eSWANG Cong  * @data: raw buffer pointer to the packet, if NULL use skb->data
1021453a940eSWANG Cong  * @proto: protocol for which to get the flow, if @data is NULL use skb->protocol
1022453a940eSWANG Cong  * @nhoff: network header offset, if @data is NULL use skb_network_offset(skb)
1023453a940eSWANG Cong  * @hlen: packet header length, if @data is NULL use skb_headlen(skb)
1024d79b3bafSBart Van Assche  * @flags: flags that control the dissection process, e.g.
10251cc26450SStanislav Fomichev  *         FLOW_DISSECTOR_F_STOP_AT_ENCAP.
1026453a940eSWANG Cong  *
102706635a35SJiri Pirko  * The function will try to retrieve individual keys into target specified
102806635a35SJiri Pirko  * by flow_dissector from either the skbuff or a raw buffer specified by the
102906635a35SJiri Pirko  * rest parameters.
103006635a35SJiri Pirko  *
103106635a35SJiri Pirko  * Caller must take care of zeroing target container memory.
1032453a940eSWANG 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)10333cbf4ffbSStanislav Fomichev bool __skb_flow_dissect(const struct net *net,
10343cbf4ffbSStanislav Fomichev 			const struct sk_buff *skb,
103506635a35SJiri Pirko 			struct flow_dissector *flow_dissector,
1036f96533cdSAlexander Lobakin 			void *target_container, const void *data,
1037f96533cdSAlexander Lobakin 			__be16 proto, int nhoff, int hlen, unsigned int flags)
10380744dd00SEric Dumazet {
103942aecaa9STom Herbert 	struct flow_dissector_key_control *key_control;
104006635a35SJiri Pirko 	struct flow_dissector_key_basic *key_basic;
104106635a35SJiri Pirko 	struct flow_dissector_key_addrs *key_addrs;
1042d34af823STom Herbert 	struct flow_dissector_key_tags *key_tags;
1043f6a66927SHadar Hen Zion 	struct flow_dissector_key_vlan *key_vlan;
10443a1214e8STom Herbert 	enum flow_dissect_ret fdret;
104524c590e3SJianbo Liu 	enum flow_dissector_key_id dissector_vlan = FLOW_DISSECTOR_KEY_MAX;
104658cff782SGuillaume Nault 	bool mpls_el = false;
104758cff782SGuillaume Nault 	int mpls_lse = 0;
10481eed4dfbSTom Herbert 	int num_hdrs = 0;
10498e690ffdSGeert Uytterhoeven 	u8 ip_proto = 0;
105034fad54cSEric Dumazet 	bool ret;
10510744dd00SEric Dumazet 
1052690e36e7SDavid S. Miller 	if (!data) {
1053690e36e7SDavid S. Miller 		data = skb->data;
1054d5709f7aSHadar Hen Zion 		proto = skb_vlan_tag_present(skb) ?
1055d5709f7aSHadar Hen Zion 			 skb->vlan_proto : skb->protocol;
1056453a940eSWANG Cong 		nhoff = skb_network_offset(skb);
1057690e36e7SDavid S. Miller 		hlen = skb_headlen(skb);
10582d571645SJohn Crispin #if IS_ENABLED(CONFIG_NET_DSA)
10598bef0af0SAlexander Lobakin 		if (unlikely(skb->dev && netdev_uses_dsa(skb->dev) &&
10608bef0af0SAlexander Lobakin 			     proto == htons(ETH_P_XDSA))) {
1061570d0a58SFelix Fietkau 			struct metadata_dst *md_dst = skb_metadata_dst(skb);
106243e66528SJohn Crispin 			const struct dsa_device_ops *ops;
10638bef0af0SAlexander Lobakin 			int offset = 0;
106443e66528SJohn Crispin 
106543e66528SJohn Crispin 			ops = skb->dev->dsa_ptr->tag_ops;
1066ec133572SVladimir Oltean 			/* Only DSA header taggers break flow dissection */
1067570d0a58SFelix Fietkau 			if (ops->needed_headroom &&
1068570d0a58SFelix Fietkau 			    (!md_dst || md_dst->type != METADATA_HW_PORT_MUX)) {
106954fec335SVladimir Oltean 				if (ops->flow_dissect)
10702e8cb1b3SVladimir Oltean 					ops->flow_dissect(skb, &proto, &offset);
107154fec335SVladimir Oltean 				else
107254fec335SVladimir Oltean 					dsa_tag_generic_flow_dissect(skb,
107354fec335SVladimir Oltean 								     &proto,
107454fec335SVladimir Oltean 								     &offset);
107543e66528SJohn Crispin 				hlen -= offset;
107643e66528SJohn Crispin 				nhoff += offset;
107743e66528SJohn Crispin 			}
107843e66528SJohn Crispin 		}
10792d571645SJohn Crispin #endif
1080690e36e7SDavid S. Miller 	}
1081690e36e7SDavid S. Miller 
108242aecaa9STom Herbert 	/* It is ensured by skb_flow_dissector_init() that control key will
108342aecaa9STom Herbert 	 * be always present.
108442aecaa9STom Herbert 	 */
108542aecaa9STom Herbert 	key_control = skb_flow_dissector_target(flow_dissector,
108642aecaa9STom Herbert 						FLOW_DISSECTOR_KEY_CONTROL,
108742aecaa9STom Herbert 						target_container);
108842aecaa9STom Herbert 
108906635a35SJiri Pirko 	/* It is ensured by skb_flow_dissector_init() that basic key will
109006635a35SJiri Pirko 	 * be always present.
109106635a35SJiri Pirko 	 */
109206635a35SJiri Pirko 	key_basic = skb_flow_dissector_target(flow_dissector,
109306635a35SJiri Pirko 					      FLOW_DISSECTOR_KEY_BASIC,
109406635a35SJiri Pirko 					      target_container);
10950744dd00SEric Dumazet 
1096e99e146bSEric Dumazet 	rcu_read_lock();
1097e99e146bSEric Dumazet 
1098d0e13a14SWillem de Bruijn 	if (skb) {
10993cbf4ffbSStanislav Fomichev 		if (!net) {
1100d0e13a14SWillem de Bruijn 			if (skb->dev)
1101e99e146bSEric Dumazet 				net = dev_net_rcu(skb->dev);
1102d0e13a14SWillem de Bruijn 			else if (skb->sk)
11033cbf4ffbSStanislav Fomichev 				net = sock_net(skb->sk);
11049b52e3f2SStanislav Fomichev 		}
11053cbf4ffbSStanislav Fomichev 	}
11063cbf4ffbSStanislav Fomichev 
11074afbac11SPablo Neira Ayuso 	DEBUG_NET_WARN_ON_ONCE(!net);
11089b52e3f2SStanislav Fomichev 	if (net) {
1109a3fd7ceeSJakub Sitnicki 		enum netns_bpf_attach_type type = NETNS_BPF_FLOW_DISSECTOR;
1110695c1214SJakub Sitnicki 		struct bpf_prog_array *run_array;
1111a3fd7ceeSJakub Sitnicki 
1112695c1214SJakub Sitnicki 		run_array = rcu_dereference(init_net.bpf.run_array[type]);
1113695c1214SJakub Sitnicki 		if (!run_array)
1114695c1214SJakub Sitnicki 			run_array = rcu_dereference(net->bpf.run_array[type]);
1115a11c397cSStanislav Fomichev 
1116695c1214SJakub Sitnicki 		if (run_array) {
11179b52e3f2SStanislav Fomichev 			struct bpf_flow_keys flow_keys;
11189b52e3f2SStanislav Fomichev 			struct bpf_flow_dissector ctx = {
11199b52e3f2SStanislav Fomichev 				.flow_keys = &flow_keys,
11209b52e3f2SStanislav Fomichev 				.data = data,
11219b52e3f2SStanislav Fomichev 				.data_end = data + hlen,
11229b52e3f2SStanislav Fomichev 			};
11239b52e3f2SStanislav Fomichev 			__be16 n_proto = proto;
1124695c1214SJakub Sitnicki 			struct bpf_prog *prog;
11250ba98502SShmulik Ladkani 			u32 result;
11269b52e3f2SStanislav Fomichev 
11279b52e3f2SStanislav Fomichev 			if (skb) {
11289b52e3f2SStanislav Fomichev 				ctx.skb = skb;
11299b52e3f2SStanislav Fomichev 				/* we can't use 'proto' in the skb case
11309b52e3f2SStanislav Fomichev 				 * because it might be set to skb->vlan_proto
11319b52e3f2SStanislav Fomichev 				 * which has been pulled from the data
11329b52e3f2SStanislav Fomichev 				 */
11339b52e3f2SStanislav Fomichev 				n_proto = skb->protocol;
11349b52e3f2SStanislav Fomichev 			}
11359b52e3f2SStanislav Fomichev 
1136695c1214SJakub Sitnicki 			prog = READ_ONCE(run_array->items[0].prog);
11370ba98502SShmulik Ladkani 			result = bpf_flow_dissect(prog, &ctx, n_proto, nhoff,
1138086f9568SStanislav Fomichev 						  hlen, flags);
1139e99e146bSEric Dumazet 			if (result != BPF_FLOW_DISSECTOR_CONTINUE) {
1140d58e468bSPetar Penkov 				__skb_flow_bpf_to_target(&flow_keys, flow_dissector,
1141d58e468bSPetar Penkov 							 target_container);
1142d58e468bSPetar Penkov 				rcu_read_unlock();
11430ba98502SShmulik Ladkani 				return result == BPF_OK;
1144d58e468bSPetar Penkov 			}
1145c8aa7038SStanislav Fomichev 		}
1146e99e146bSEric Dumazet 	}
1147e99e146bSEric Dumazet 
1148e99e146bSEric Dumazet 	rcu_read_unlock();
1149d58e468bSPetar Penkov 
115020a17bf6SDavid S. Miller 	if (dissector_uses_key(flow_dissector,
115167a900ccSJiri Pirko 			       FLOW_DISSECTOR_KEY_ETH_ADDRS)) {
115267a900ccSJiri Pirko 		struct ethhdr *eth = eth_hdr(skb);
115367a900ccSJiri Pirko 		struct flow_dissector_key_eth_addrs *key_eth_addrs;
115467a900ccSJiri Pirko 
115567a900ccSJiri Pirko 		key_eth_addrs = skb_flow_dissector_target(flow_dissector,
115667a900ccSJiri Pirko 							  FLOW_DISSECTOR_KEY_ETH_ADDRS,
115767a900ccSJiri Pirko 							  target_container);
11581b808993SJakub Kicinski 		memcpy(key_eth_addrs, eth, sizeof(*key_eth_addrs));
115967a900ccSJiri Pirko 	}
116067a900ccSJiri Pirko 
116134951fcfSBoris Sukholitko 	if (dissector_uses_key(flow_dissector,
116234951fcfSBoris Sukholitko 			       FLOW_DISSECTOR_KEY_NUM_OF_VLANS)) {
116334951fcfSBoris Sukholitko 		struct flow_dissector_key_num_of_vlans *key_num_of_vlans;
116434951fcfSBoris Sukholitko 
116534951fcfSBoris Sukholitko 		key_num_of_vlans = skb_flow_dissector_target(flow_dissector,
116634951fcfSBoris Sukholitko 							     FLOW_DISSECTOR_KEY_NUM_OF_VLANS,
116734951fcfSBoris Sukholitko 							     target_container);
116834951fcfSBoris Sukholitko 		key_num_of_vlans->num_of_vlans = 0;
116934951fcfSBoris Sukholitko 	}
117034951fcfSBoris Sukholitko 
1171c5ef188eSJiri Pirko proto_again:
11723a1214e8STom Herbert 	fdret = FLOW_DISSECT_RET_CONTINUE;
11733a1214e8STom Herbert 
11740744dd00SEric Dumazet 	switch (proto) {
11752b8837aeSJoe Perches 	case htons(ETH_P_IP): {
11760744dd00SEric Dumazet 		const struct iphdr *iph;
11770744dd00SEric Dumazet 		struct iphdr _iph;
11783a1214e8STom Herbert 
1179690e36e7SDavid S. Miller 		iph = __skb_header_pointer(skb, nhoff, sizeof(_iph), data, hlen, &_iph);
11803a1214e8STom Herbert 		if (!iph || iph->ihl < 5) {
11813a1214e8STom Herbert 			fdret = FLOW_DISSECT_RET_OUT_BAD;
11823a1214e8STom Herbert 			break;
11833a1214e8STom Herbert 		}
11843a1214e8STom Herbert 
11853797d3e8SEric Dumazet 		nhoff += iph->ihl * 4;
11860744dd00SEric Dumazet 
11873797d3e8SEric Dumazet 		ip_proto = iph->protocol;
11883797d3e8SEric Dumazet 
1189918c023fSAlexander Duyck 		if (dissector_uses_key(flow_dissector,
1190918c023fSAlexander Duyck 				       FLOW_DISSECTOR_KEY_IPV4_ADDRS)) {
119106635a35SJiri Pirko 			key_addrs = skb_flow_dissector_target(flow_dissector,
1192918c023fSAlexander Duyck 							      FLOW_DISSECTOR_KEY_IPV4_ADDRS,
1193918c023fSAlexander Duyck 							      target_container);
1194918c023fSAlexander Duyck 
1195323e0cb4SGustavo A. R. Silva 			memcpy(&key_addrs->v4addrs.src, &iph->saddr,
1196323e0cb4SGustavo A. R. Silva 			       sizeof(key_addrs->v4addrs.src));
1197323e0cb4SGustavo A. R. Silva 			memcpy(&key_addrs->v4addrs.dst, &iph->daddr,
1198323e0cb4SGustavo A. R. Silva 			       sizeof(key_addrs->v4addrs.dst));
1199c3f83241STom Herbert 			key_control->addr_type = FLOW_DISSECTOR_KEY_IPV4_ADDRS;
1200918c023fSAlexander Duyck 		}
1201807e165dSTom Herbert 
1202d2126838SDavide Caratti 		__skb_flow_dissect_ipv4(skb, flow_dissector,
1203d2126838SDavide Caratti 					target_container, data, iph);
1204d2126838SDavide Caratti 
1205807e165dSTom Herbert 		if (ip_is_fragment(iph)) {
12064b36993dSDavid S. Miller 			key_control->flags |= FLOW_DIS_IS_FRAGMENT;
1207807e165dSTom Herbert 
1208807e165dSTom Herbert 			if (iph->frag_off & htons(IP_OFFSET)) {
12093a1214e8STom Herbert 				fdret = FLOW_DISSECT_RET_OUT_GOOD;
12103a1214e8STom Herbert 				break;
1211807e165dSTom Herbert 			} else {
12124b36993dSDavid S. Miller 				key_control->flags |= FLOW_DIS_FIRST_FRAG;
12133a1214e8STom Herbert 				if (!(flags &
12143a1214e8STom Herbert 				      FLOW_DISSECTOR_F_PARSE_1ST_FRAG)) {
12153a1214e8STom Herbert 					fdret = FLOW_DISSECT_RET_OUT_GOOD;
12163a1214e8STom Herbert 					break;
12173a1214e8STom Herbert 				}
1218807e165dSTom Herbert 			}
1219807e165dSTom Herbert 		}
1220807e165dSTom Herbert 
12210744dd00SEric Dumazet 		break;
12220744dd00SEric Dumazet 	}
12232b8837aeSJoe Perches 	case htons(ETH_P_IPV6): {
12240744dd00SEric Dumazet 		const struct ipv6hdr *iph;
12250744dd00SEric Dumazet 		struct ipv6hdr _iph;
122619469a87STom Herbert 
1227690e36e7SDavid S. Miller 		iph = __skb_header_pointer(skb, nhoff, sizeof(_iph), data, hlen, &_iph);
12283a1214e8STom Herbert 		if (!iph) {
12293a1214e8STom Herbert 			fdret = FLOW_DISSECT_RET_OUT_BAD;
12303a1214e8STom Herbert 			break;
12313a1214e8STom Herbert 		}
12320744dd00SEric Dumazet 
12330744dd00SEric Dumazet 		ip_proto = iph->nexthdr;
12340744dd00SEric Dumazet 		nhoff += sizeof(struct ipv6hdr);
123519469a87STom Herbert 
123620a17bf6SDavid S. Miller 		if (dissector_uses_key(flow_dissector,
1237b924933cSJiri Pirko 				       FLOW_DISSECTOR_KEY_IPV6_ADDRS)) {
1238b3c3106cSAlexander Duyck 			key_addrs = skb_flow_dissector_target(flow_dissector,
1239b924933cSJiri Pirko 							      FLOW_DISSECTOR_KEY_IPV6_ADDRS,
1240b924933cSJiri Pirko 							      target_container);
1241b924933cSJiri Pirko 
1242323e0cb4SGustavo A. R. Silva 			memcpy(&key_addrs->v6addrs.src, &iph->saddr,
1243323e0cb4SGustavo A. R. Silva 			       sizeof(key_addrs->v6addrs.src));
1244323e0cb4SGustavo A. R. Silva 			memcpy(&key_addrs->v6addrs.dst, &iph->daddr,
1245323e0cb4SGustavo A. R. Silva 			       sizeof(key_addrs->v6addrs.dst));
1246c3f83241STom Herbert 			key_control->addr_type = FLOW_DISSECTOR_KEY_IPV6_ADDRS;
1247b924933cSJiri Pirko 		}
124887ee9e52STom Herbert 
1249461547f3SAlexander Duyck 		if ((dissector_uses_key(flow_dissector,
1250461547f3SAlexander Duyck 					FLOW_DISSECTOR_KEY_FLOW_LABEL) ||
1251461547f3SAlexander Duyck 		     (flags & FLOW_DISSECTOR_F_STOP_AT_FLOW_LABEL)) &&
1252461547f3SAlexander Duyck 		    ip6_flowlabel(iph)) {
1253461547f3SAlexander Duyck 			__be32 flow_label = ip6_flowlabel(iph);
1254461547f3SAlexander Duyck 
125520a17bf6SDavid S. Miller 			if (dissector_uses_key(flow_dissector,
125687ee9e52STom Herbert 					       FLOW_DISSECTOR_KEY_FLOW_LABEL)) {
125787ee9e52STom Herbert 				key_tags = skb_flow_dissector_target(flow_dissector,
125887ee9e52STom Herbert 								     FLOW_DISSECTOR_KEY_FLOW_LABEL,
125906635a35SJiri Pirko 								     target_container);
126087ee9e52STom Herbert 				key_tags->flow_label = ntohl(flow_label);
126112c227ecSJiri Pirko 			}
12623a1214e8STom Herbert 			if (flags & FLOW_DISSECTOR_F_STOP_AT_FLOW_LABEL) {
12633a1214e8STom Herbert 				fdret = FLOW_DISSECT_RET_OUT_GOOD;
12643a1214e8STom Herbert 				break;
12653a1214e8STom Herbert 			}
126619469a87STom Herbert 		}
126719469a87STom Herbert 
1268518d8a2eSOr Gerlitz 		__skb_flow_dissect_ipv6(skb, flow_dissector,
1269518d8a2eSOr Gerlitz 					target_container, data, iph);
1270518d8a2eSOr Gerlitz 
12710744dd00SEric Dumazet 		break;
12720744dd00SEric Dumazet 	}
12732b8837aeSJoe Perches 	case htons(ETH_P_8021AD):
12742b8837aeSJoe Perches 	case htons(ETH_P_8021Q): {
127524c590e3SJianbo Liu 		const struct vlan_hdr *vlan = NULL;
1276bc72f3ddSArnd Bergmann 		struct vlan_hdr _vlan;
12772064c3d4SJianbo Liu 		__be16 saved_vlan_tpid = proto;
1278d5709f7aSHadar Hen Zion 
127924c590e3SJianbo Liu 		if (dissector_vlan == FLOW_DISSECTOR_KEY_MAX &&
128024c590e3SJianbo Liu 		    skb && skb_vlan_tag_present(skb)) {
1281d5709f7aSHadar Hen Zion 			proto = skb->protocol;
128224c590e3SJianbo Liu 		} else {
1283d5709f7aSHadar Hen Zion 			vlan = __skb_header_pointer(skb, nhoff, sizeof(_vlan),
1284d5709f7aSHadar Hen Zion 						    data, hlen, &_vlan);
12853a1214e8STom Herbert 			if (!vlan) {
12863a1214e8STom Herbert 				fdret = FLOW_DISSECT_RET_OUT_BAD;
12873a1214e8STom Herbert 				break;
12883a1214e8STom Herbert 			}
12893a1214e8STom Herbert 
1290d5709f7aSHadar Hen Zion 			proto = vlan->h_vlan_encapsulated_proto;
1291d5709f7aSHadar Hen Zion 			nhoff += sizeof(*vlan);
129224c590e3SJianbo Liu 		}
129324c590e3SJianbo Liu 
12949f87eb42SQingqing Yang 		if (dissector_uses_key(flow_dissector, FLOW_DISSECTOR_KEY_NUM_OF_VLANS) &&
12959f87eb42SQingqing Yang 		    !(key_control->flags & FLOW_DIS_ENCAPSULATION)) {
129634951fcfSBoris Sukholitko 			struct flow_dissector_key_num_of_vlans *key_nvs;
129734951fcfSBoris Sukholitko 
129834951fcfSBoris Sukholitko 			key_nvs = skb_flow_dissector_target(flow_dissector,
129934951fcfSBoris Sukholitko 							    FLOW_DISSECTOR_KEY_NUM_OF_VLANS,
130034951fcfSBoris Sukholitko 							    target_container);
130134951fcfSBoris Sukholitko 			key_nvs->num_of_vlans++;
130234951fcfSBoris Sukholitko 		}
130334951fcfSBoris Sukholitko 
130424c590e3SJianbo Liu 		if (dissector_vlan == FLOW_DISSECTOR_KEY_MAX) {
130524c590e3SJianbo Liu 			dissector_vlan = FLOW_DISSECTOR_KEY_VLAN;
130624c590e3SJianbo Liu 		} else if (dissector_vlan == FLOW_DISSECTOR_KEY_VLAN) {
130724c590e3SJianbo Liu 			dissector_vlan = FLOW_DISSECTOR_KEY_CVLAN;
130824c590e3SJianbo Liu 		} else {
13093a1214e8STom Herbert 			fdret = FLOW_DISSECT_RET_PROTO_AGAIN;
13103a1214e8STom Herbert 			break;
13113a1214e8STom Herbert 		}
13120744dd00SEric Dumazet 
131324c590e3SJianbo Liu 		if (dissector_uses_key(flow_dissector, dissector_vlan)) {
1314f6a66927SHadar Hen Zion 			key_vlan = skb_flow_dissector_target(flow_dissector,
131524c590e3SJianbo Liu 							     dissector_vlan,
1316d34af823STom Herbert 							     target_container);
1317d34af823STom Herbert 
131824c590e3SJianbo Liu 			if (!vlan) {
1319f6a66927SHadar Hen Zion 				key_vlan->vlan_id = skb_vlan_tag_get_id(skb);
13209b319148SMichał Mirosław 				key_vlan->vlan_priority = skb_vlan_tag_get_prio(skb);
1321f6a66927SHadar Hen Zion 			} else {
1322f6a66927SHadar Hen Zion 				key_vlan->vlan_id = ntohs(vlan->h_vlan_TCI) &
1323d5709f7aSHadar Hen Zion 					VLAN_VID_MASK;
1324f6a66927SHadar Hen Zion 				key_vlan->vlan_priority =
1325f6a66927SHadar Hen Zion 					(ntohs(vlan->h_vlan_TCI) &
1326f6a66927SHadar Hen Zion 					 VLAN_PRIO_MASK) >> VLAN_PRIO_SHIFT;
1327f6a66927SHadar Hen Zion 			}
13282064c3d4SJianbo Liu 			key_vlan->vlan_tpid = saved_vlan_tpid;
13292105f700SVlad Buslov 			key_vlan->vlan_eth_type = proto;
1330d34af823STom Herbert 		}
1331d34af823STom Herbert 
13323a1214e8STom Herbert 		fdret = FLOW_DISSECT_RET_PROTO_AGAIN;
13333a1214e8STom Herbert 		break;
13340744dd00SEric Dumazet 	}
13352b8837aeSJoe Perches 	case htons(ETH_P_PPP_SES): {
13360744dd00SEric Dumazet 		struct {
13370744dd00SEric Dumazet 			struct pppoe_hdr hdr;
13380744dd00SEric Dumazet 			__be16 proto;
13390744dd00SEric Dumazet 		} *hdr, _hdr;
134046126db9SWojciech Drewek 		u16 ppp_proto;
134146126db9SWojciech Drewek 
1342690e36e7SDavid S. Miller 		hdr = __skb_header_pointer(skb, nhoff, sizeof(_hdr), data, hlen, &_hdr);
13433a1214e8STom Herbert 		if (!hdr) {
13443a1214e8STom Herbert 			fdret = FLOW_DISSECT_RET_OUT_BAD;
13453a1214e8STom Herbert 			break;
13463a1214e8STom Herbert 		}
13473a1214e8STom Herbert 
1348f86d1fbbSLinus Torvalds 		if (!is_pppoe_ses_hdr_valid(&hdr->hdr)) {
13493a1214e8STom Herbert 			fdret = FLOW_DISSECT_RET_OUT_BAD;
13503a1214e8STom Herbert 			break;
13510744dd00SEric Dumazet 		}
135246126db9SWojciech Drewek 
135346126db9SWojciech Drewek 		/* least significant bit of the most significant octet
135446126db9SWojciech Drewek 		 * indicates if protocol field was compressed
135546126db9SWojciech Drewek 		 */
135646126db9SWojciech Drewek 		ppp_proto = ntohs(hdr->proto);
135746126db9SWojciech Drewek 		if (ppp_proto & 0x0100) {
135846126db9SWojciech Drewek 			ppp_proto = ppp_proto >> 8;
135946126db9SWojciech Drewek 			nhoff += PPPOE_SES_HLEN - 1;
136046126db9SWojciech Drewek 		} else {
136146126db9SWojciech Drewek 			nhoff += PPPOE_SES_HLEN;
136246126db9SWojciech Drewek 		}
136346126db9SWojciech Drewek 
136446126db9SWojciech Drewek 		if (ppp_proto == PPP_IP) {
136546126db9SWojciech Drewek 			proto = htons(ETH_P_IP);
136646126db9SWojciech Drewek 			fdret = FLOW_DISSECT_RET_PROTO_AGAIN;
136746126db9SWojciech Drewek 		} else if (ppp_proto == PPP_IPV6) {
136846126db9SWojciech Drewek 			proto = htons(ETH_P_IPV6);
136946126db9SWojciech Drewek 			fdret = FLOW_DISSECT_RET_PROTO_AGAIN;
137046126db9SWojciech Drewek 		} else if (ppp_proto == PPP_MPLS_UC) {
137146126db9SWojciech Drewek 			proto = htons(ETH_P_MPLS_UC);
137246126db9SWojciech Drewek 			fdret = FLOW_DISSECT_RET_PROTO_AGAIN;
137346126db9SWojciech Drewek 		} else if (ppp_proto == PPP_MPLS_MC) {
137446126db9SWojciech Drewek 			proto = htons(ETH_P_MPLS_MC);
137546126db9SWojciech Drewek 			fdret = FLOW_DISSECT_RET_PROTO_AGAIN;
137646126db9SWojciech Drewek 		} else if (ppp_proto_is_valid(ppp_proto)) {
137746126db9SWojciech Drewek 			fdret = FLOW_DISSECT_RET_OUT_GOOD;
137846126db9SWojciech Drewek 		} else {
137946126db9SWojciech Drewek 			fdret = FLOW_DISSECT_RET_OUT_BAD;
138046126db9SWojciech Drewek 			break;
138146126db9SWojciech Drewek 		}
138246126db9SWojciech Drewek 
138346126db9SWojciech Drewek 		if (dissector_uses_key(flow_dissector,
138446126db9SWojciech Drewek 				       FLOW_DISSECTOR_KEY_PPPOE)) {
138546126db9SWojciech Drewek 			struct flow_dissector_key_pppoe *key_pppoe;
138646126db9SWojciech Drewek 
138746126db9SWojciech Drewek 			key_pppoe = skb_flow_dissector_target(flow_dissector,
138846126db9SWojciech Drewek 							      FLOW_DISSECTOR_KEY_PPPOE,
138946126db9SWojciech Drewek 							      target_container);
139046126db9SWojciech Drewek 			key_pppoe->session_id = hdr->hdr.sid;
139146126db9SWojciech Drewek 			key_pppoe->ppp_proto = htons(ppp_proto);
139246126db9SWojciech Drewek 			key_pppoe->type = htons(ETH_P_PPP_SES);
139346126db9SWojciech Drewek 		}
13943a1214e8STom Herbert 		break;
13950744dd00SEric Dumazet 	}
139608bfc9cbSErik Hugne 	case htons(ETH_P_TIPC): {
13978d6e79d3SJon Maloy 		struct tipc_basic_hdr *hdr, _hdr;
13988d6e79d3SJon Maloy 
13998d6e79d3SJon Maloy 		hdr = __skb_header_pointer(skb, nhoff, sizeof(_hdr),
14008d6e79d3SJon Maloy 					   data, hlen, &_hdr);
14013a1214e8STom Herbert 		if (!hdr) {
14023a1214e8STom Herbert 			fdret = FLOW_DISSECT_RET_OUT_BAD;
14033a1214e8STom Herbert 			break;
14043a1214e8STom Herbert 		}
140506635a35SJiri Pirko 
140620a17bf6SDavid S. Miller 		if (dissector_uses_key(flow_dissector,
14078d6e79d3SJon Maloy 				       FLOW_DISSECTOR_KEY_TIPC)) {
140806635a35SJiri Pirko 			key_addrs = skb_flow_dissector_target(flow_dissector,
14098d6e79d3SJon Maloy 							      FLOW_DISSECTOR_KEY_TIPC,
141006635a35SJiri Pirko 							      target_container);
14118d6e79d3SJon Maloy 			key_addrs->tipckey.key = tipc_hdr_rps_key(hdr);
14128d6e79d3SJon Maloy 			key_control->addr_type = FLOW_DISSECTOR_KEY_TIPC;
141306635a35SJiri Pirko 		}
14143a1214e8STom Herbert 		fdret = FLOW_DISSECT_RET_OUT_GOOD;
14153a1214e8STom Herbert 		break;
141608bfc9cbSErik Hugne 	}
1417b3baa0fbSTom Herbert 
1418b3baa0fbSTom Herbert 	case htons(ETH_P_MPLS_UC):
14194a5d6c8bSJiri Pirko 	case htons(ETH_P_MPLS_MC):
14203a1214e8STom Herbert 		fdret = __skb_flow_dissect_mpls(skb, flow_dissector,
14214a5d6c8bSJiri Pirko 						target_container, data,
142258cff782SGuillaume Nault 						nhoff, hlen, mpls_lse,
142358cff782SGuillaume Nault 						&mpls_el);
142458cff782SGuillaume Nault 		nhoff += sizeof(struct mpls_label);
142558cff782SGuillaume Nault 		mpls_lse++;
14263a1214e8STom Herbert 		break;
142756193d1bSAlexander Duyck 	case htons(ETH_P_FCOE):
14283a1214e8STom Herbert 		if ((hlen - nhoff) < FCOE_HEADER_LEN) {
14293a1214e8STom Herbert 			fdret = FLOW_DISSECT_RET_OUT_BAD;
14303a1214e8STom Herbert 			break;
14313a1214e8STom Herbert 		}
1432224516b3SAlexander Duyck 
1433224516b3SAlexander Duyck 		nhoff += FCOE_HEADER_LEN;
14343a1214e8STom Herbert 		fdret = FLOW_DISSECT_RET_OUT_GOOD;
14353a1214e8STom Herbert 		break;
143655733350SSimon Horman 
143755733350SSimon Horman 	case htons(ETH_P_ARP):
14389bf881ffSJiri Pirko 	case htons(ETH_P_RARP):
14393a1214e8STom Herbert 		fdret = __skb_flow_dissect_arp(skb, flow_dissector,
14409bf881ffSJiri Pirko 					       target_container, data,
14413a1214e8STom Herbert 					       nhoff, hlen);
14423a1214e8STom Herbert 		break;
14433a1214e8STom Herbert 
14445b0890a9SSven Eckelmann 	case htons(ETH_P_BATMAN):
14455b0890a9SSven Eckelmann 		fdret = __skb_flow_dissect_batadv(skb, key_control, data,
14465b0890a9SSven Eckelmann 						  &proto, &nhoff, hlen, flags);
14475b0890a9SSven Eckelmann 		break;
14485b0890a9SSven Eckelmann 
14494f1cc51fSEran Ben Elisha 	case htons(ETH_P_1588): {
14504f1cc51fSEran Ben Elisha 		struct ptp_header *hdr, _hdr;
14514f1cc51fSEran Ben Elisha 
14524f1cc51fSEran Ben Elisha 		hdr = __skb_header_pointer(skb, nhoff, sizeof(_hdr), data,
14534f1cc51fSEran Ben Elisha 					   hlen, &_hdr);
14544f1cc51fSEran Ben Elisha 		if (!hdr) {
14554f1cc51fSEran Ben Elisha 			fdret = FLOW_DISSECT_RET_OUT_BAD;
14564f1cc51fSEran Ben Elisha 			break;
14574f1cc51fSEran Ben Elisha 		}
14584f1cc51fSEran Ben Elisha 
145975ad80edSSasha Neftin 		nhoff += sizeof(struct ptp_header);
14604f1cc51fSEran Ben Elisha 		fdret = FLOW_DISSECT_RET_OUT_GOOD;
14614f1cc51fSEran Ben Elisha 		break;
14624f1cc51fSEran Ben Elisha 	}
14634f1cc51fSEran Ben Elisha 
1464f65e5844SKurt Kanzenbach 	case htons(ETH_P_PRP):
1465bf08824aSKurt Kanzenbach 	case htons(ETH_P_HSR): {
1466bf08824aSKurt Kanzenbach 		struct hsr_tag *hdr, _hdr;
1467bf08824aSKurt Kanzenbach 
1468bf08824aSKurt Kanzenbach 		hdr = __skb_header_pointer(skb, nhoff, sizeof(_hdr), data, hlen,
1469bf08824aSKurt Kanzenbach 					   &_hdr);
1470bf08824aSKurt Kanzenbach 		if (!hdr) {
1471bf08824aSKurt Kanzenbach 			fdret = FLOW_DISSECT_RET_OUT_BAD;
1472bf08824aSKurt Kanzenbach 			break;
1473bf08824aSKurt Kanzenbach 		}
1474bf08824aSKurt Kanzenbach 
1475bf08824aSKurt Kanzenbach 		proto = hdr->encap_proto;
1476bf08824aSKurt Kanzenbach 		nhoff += HSR_HLEN;
1477bf08824aSKurt Kanzenbach 		fdret = FLOW_DISSECT_RET_PROTO_AGAIN;
1478bf08824aSKurt Kanzenbach 		break;
1479bf08824aSKurt Kanzenbach 	}
1480bf08824aSKurt Kanzenbach 
1481d7ad70b5SZahari Doychev 	case htons(ETH_P_CFM):
1482d7ad70b5SZahari Doychev 		fdret = __skb_flow_dissect_cfm(skb, flow_dissector,
1483d7ad70b5SZahari Doychev 					       target_container, data,
1484d7ad70b5SZahari Doychev 					       nhoff, hlen);
1485d7ad70b5SZahari Doychev 		break;
1486d7ad70b5SZahari Doychev 
14873a1214e8STom Herbert 	default:
14883a1214e8STom Herbert 		fdret = FLOW_DISSECT_RET_OUT_BAD;
14893a1214e8STom Herbert 		break;
14903a1214e8STom Herbert 	}
14913a1214e8STom Herbert 
14923a1214e8STom Herbert 	/* Process result of proto processing */
14933a1214e8STom Herbert 	switch (fdret) {
14949bf881ffSJiri Pirko 	case FLOW_DISSECT_RET_OUT_GOOD:
149555733350SSimon Horman 		goto out_good;
14963a1214e8STom Herbert 	case FLOW_DISSECT_RET_PROTO_AGAIN:
14971eed4dfbSTom Herbert 		if (skb_flow_dissect_allowed(&num_hdrs))
14983a1214e8STom Herbert 			goto proto_again;
14991eed4dfbSTom Herbert 		goto out_good;
15003a1214e8STom Herbert 	case FLOW_DISSECT_RET_CONTINUE:
15013a1214e8STom Herbert 	case FLOW_DISSECT_RET_IPPROTO_AGAIN:
15023a1214e8STom Herbert 		break;
15039bf881ffSJiri Pirko 	case FLOW_DISSECT_RET_OUT_BAD:
15047c92de8eSJiri Pirko 	default:
15059bf881ffSJiri Pirko 		goto out_bad;
150655733350SSimon Horman 	}
15070744dd00SEric Dumazet 
15086a74fcf4STom Herbert ip_proto_again:
15093a1214e8STom Herbert 	fdret = FLOW_DISSECT_RET_CONTINUE;
15103a1214e8STom Herbert 
15110744dd00SEric Dumazet 	switch (ip_proto) {
15127c92de8eSJiri Pirko 	case IPPROTO_GRE:
15136de6e46dSYoshiki Komachi 		if (flags & FLOW_DISSECTOR_F_STOP_BEFORE_ENCAP) {
15146de6e46dSYoshiki Komachi 			fdret = FLOW_DISSECT_RET_OUT_GOOD;
15156de6e46dSYoshiki Komachi 			break;
15166de6e46dSYoshiki Komachi 		}
15176de6e46dSYoshiki Komachi 
15183a1214e8STom Herbert 		fdret = __skb_flow_dissect_gre(skb, key_control, flow_dissector,
15197c92de8eSJiri Pirko 					       target_container, data,
15203a1214e8STom Herbert 					       &proto, &nhoff, &hlen, flags);
15213a1214e8STom Herbert 		break;
15223a1214e8STom Herbert 
15236a74fcf4STom Herbert 	case NEXTHDR_HOP:
15246a74fcf4STom Herbert 	case NEXTHDR_ROUTING:
15256a74fcf4STom Herbert 	case NEXTHDR_DEST: {
15266a74fcf4STom Herbert 		u8 _opthdr[2], *opthdr;
15276a74fcf4STom Herbert 
15286a74fcf4STom Herbert 		if (proto != htons(ETH_P_IPV6))
15296a74fcf4STom Herbert 			break;
15306a74fcf4STom Herbert 
15316a74fcf4STom Herbert 		opthdr = __skb_header_pointer(skb, nhoff, sizeof(_opthdr),
15326a74fcf4STom Herbert 					      data, hlen, &_opthdr);
15333a1214e8STom Herbert 		if (!opthdr) {
15343a1214e8STom Herbert 			fdret = FLOW_DISSECT_RET_OUT_BAD;
15353a1214e8STom Herbert 			break;
15363a1214e8STom Herbert 		}
15376a74fcf4STom Herbert 
15381e98a0f0SEric Dumazet 		ip_proto = opthdr[0];
15391e98a0f0SEric Dumazet 		nhoff += (opthdr[1] + 1) << 3;
15406a74fcf4STom Herbert 
15413a1214e8STom Herbert 		fdret = FLOW_DISSECT_RET_IPPROTO_AGAIN;
15423a1214e8STom Herbert 		break;
15436a74fcf4STom Herbert 	}
1544b840f28bSTom Herbert 	case NEXTHDR_FRAGMENT: {
1545b840f28bSTom Herbert 		struct frag_hdr _fh, *fh;
1546b840f28bSTom Herbert 
1547b840f28bSTom Herbert 		if (proto != htons(ETH_P_IPV6))
1548b840f28bSTom Herbert 			break;
1549b840f28bSTom Herbert 
1550b840f28bSTom Herbert 		fh = __skb_header_pointer(skb, nhoff, sizeof(_fh),
1551b840f28bSTom Herbert 					  data, hlen, &_fh);
1552b840f28bSTom Herbert 
15533a1214e8STom Herbert 		if (!fh) {
15543a1214e8STom Herbert 			fdret = FLOW_DISSECT_RET_OUT_BAD;
15553a1214e8STom Herbert 			break;
15563a1214e8STom Herbert 		}
1557b840f28bSTom Herbert 
15584b36993dSDavid S. Miller 		key_control->flags |= FLOW_DIS_IS_FRAGMENT;
1559b840f28bSTom Herbert 
1560b840f28bSTom Herbert 		nhoff += sizeof(_fh);
156143d2ccb3SAlexander Duyck 		ip_proto = fh->nexthdr;
1562b840f28bSTom Herbert 
1563b840f28bSTom Herbert 		if (!(fh->frag_off & htons(IP6_OFFSET))) {
15644b36993dSDavid S. Miller 			key_control->flags |= FLOW_DIS_FIRST_FRAG;
15653a1214e8STom Herbert 			if (flags & FLOW_DISSECTOR_F_PARSE_1ST_FRAG) {
15663a1214e8STom Herbert 				fdret = FLOW_DISSECT_RET_IPPROTO_AGAIN;
15673a1214e8STom Herbert 				break;
1568b840f28bSTom Herbert 			}
15693a1214e8STom Herbert 		}
15703a1214e8STom Herbert 
15713a1214e8STom Herbert 		fdret = FLOW_DISSECT_RET_OUT_GOOD;
15723a1214e8STom Herbert 		break;
1573b840f28bSTom Herbert 	}
15740744dd00SEric Dumazet 	case IPPROTO_IPIP:
15756de6e46dSYoshiki Komachi 		if (flags & FLOW_DISSECTOR_F_STOP_BEFORE_ENCAP) {
15766de6e46dSYoshiki Komachi 			fdret = FLOW_DISSECT_RET_OUT_GOOD;
15776de6e46dSYoshiki Komachi 			break;
15786de6e46dSYoshiki Komachi 		}
15796de6e46dSYoshiki Komachi 
1580fca41895STom Herbert 		proto = htons(ETH_P_IP);
1581823b9693STom Herbert 
15824b36993dSDavid S. Miller 		key_control->flags |= FLOW_DIS_ENCAPSULATION;
15833a1214e8STom Herbert 		if (flags & FLOW_DISSECTOR_F_STOP_AT_ENCAP) {
15843a1214e8STom Herbert 			fdret = FLOW_DISSECT_RET_OUT_GOOD;
15853a1214e8STom Herbert 			break;
15863a1214e8STom Herbert 		}
1587823b9693STom Herbert 
15883a1214e8STom Herbert 		fdret = FLOW_DISSECT_RET_PROTO_AGAIN;
15893a1214e8STom Herbert 		break;
15903a1214e8STom Herbert 
1591b438f940STom Herbert 	case IPPROTO_IPV6:
15926de6e46dSYoshiki Komachi 		if (flags & FLOW_DISSECTOR_F_STOP_BEFORE_ENCAP) {
15936de6e46dSYoshiki Komachi 			fdret = FLOW_DISSECT_RET_OUT_GOOD;
15946de6e46dSYoshiki Komachi 			break;
15956de6e46dSYoshiki Komachi 		}
15966de6e46dSYoshiki Komachi 
1597b438f940STom Herbert 		proto = htons(ETH_P_IPV6);
1598823b9693STom Herbert 
15994b36993dSDavid S. Miller 		key_control->flags |= FLOW_DIS_ENCAPSULATION;
16003a1214e8STom Herbert 		if (flags & FLOW_DISSECTOR_F_STOP_AT_ENCAP) {
16013a1214e8STom Herbert 			fdret = FLOW_DISSECT_RET_OUT_GOOD;
16023a1214e8STom Herbert 			break;
16033a1214e8STom Herbert 		}
1604823b9693STom Herbert 
16053a1214e8STom Herbert 		fdret = FLOW_DISSECT_RET_PROTO_AGAIN;
16063a1214e8STom Herbert 		break;
16073a1214e8STom Herbert 
16083a1214e8STom Herbert 
1609b3baa0fbSTom Herbert 	case IPPROTO_MPLS:
1610b3baa0fbSTom Herbert 		proto = htons(ETH_P_MPLS_UC);
16113a1214e8STom Herbert 		fdret = FLOW_DISSECT_RET_PROTO_AGAIN;
16123a1214e8STom Herbert 		break;
16133a1214e8STom Herbert 
1614ac4bb5deSJiri Pirko 	case IPPROTO_TCP:
1615ac4bb5deSJiri Pirko 		__skb_flow_dissect_tcp(skb, flow_dissector, target_container,
1616ac4bb5deSJiri Pirko 				       data, nhoff, hlen);
1617ac4bb5deSJiri Pirko 		break;
16183a1214e8STom Herbert 
16193b336d6fSMatteo Croce 	case IPPROTO_ICMP:
16203b336d6fSMatteo Croce 	case IPPROTO_ICMPV6:
16213b336d6fSMatteo Croce 		__skb_flow_dissect_icmp(skb, flow_dissector, target_container,
16223b336d6fSMatteo Croce 					data, nhoff, hlen);
16233b336d6fSMatteo Croce 		break;
1624dda2fa08SWojciech Drewek 	case IPPROTO_L2TP:
1625dda2fa08SWojciech Drewek 		__skb_flow_dissect_l2tpv3(skb, flow_dissector, target_container,
1626dda2fa08SWojciech Drewek 					  data, nhoff, hlen);
1627dda2fa08SWojciech Drewek 		break;
1628a57c34a8SRatheesh Kannoth 	case IPPROTO_ESP:
1629a57c34a8SRatheesh Kannoth 		__skb_flow_dissect_esp(skb, flow_dissector, target_container,
1630a57c34a8SRatheesh Kannoth 				       data, nhoff, hlen);
1631a57c34a8SRatheesh Kannoth 		break;
1632a57c34a8SRatheesh Kannoth 	case IPPROTO_AH:
1633a57c34a8SRatheesh Kannoth 		__skb_flow_dissect_ah(skb, flow_dissector, target_container,
1634a57c34a8SRatheesh Kannoth 				      data, nhoff, hlen);
1635a57c34a8SRatheesh Kannoth 		break;
16360744dd00SEric Dumazet 	default:
16370744dd00SEric Dumazet 		break;
16380744dd00SEric Dumazet 	}
16390744dd00SEric Dumazet 
16408ffb055bSYoshiki Komachi 	if (!(key_control->flags & FLOW_DIS_IS_FRAGMENT))
16418ffb055bSYoshiki Komachi 		__skb_flow_dissect_ports(skb, flow_dissector, target_container,
16428ffb055bSYoshiki Komachi 					 data, nhoff, ip_proto, hlen);
16435af7fb6eSAlexander Duyck 
16443a1214e8STom Herbert 	/* Process result of IP proto processing */
16453a1214e8STom Herbert 	switch (fdret) {
16463a1214e8STom Herbert 	case FLOW_DISSECT_RET_PROTO_AGAIN:
16471eed4dfbSTom Herbert 		if (skb_flow_dissect_allowed(&num_hdrs))
16483a1214e8STom Herbert 			goto proto_again;
16491eed4dfbSTom Herbert 		break;
16503a1214e8STom Herbert 	case FLOW_DISSECT_RET_IPPROTO_AGAIN:
16511eed4dfbSTom Herbert 		if (skb_flow_dissect_allowed(&num_hdrs))
16523a1214e8STom Herbert 			goto ip_proto_again;
16531eed4dfbSTom Herbert 		break;
16543a1214e8STom Herbert 	case FLOW_DISSECT_RET_OUT_GOOD:
16553a1214e8STom Herbert 	case FLOW_DISSECT_RET_CONTINUE:
16563a1214e8STom Herbert 		break;
16573a1214e8STom Herbert 	case FLOW_DISSECT_RET_OUT_BAD:
16583a1214e8STom Herbert 	default:
16593a1214e8STom Herbert 		goto out_bad;
16603a1214e8STom Herbert 	}
16613a1214e8STom Herbert 
1662a6e544b0STom Herbert out_good:
1663a6e544b0STom Herbert 	ret = true;
1664a6e544b0STom Herbert 
166534fad54cSEric Dumazet out:
1666d0c081b4SEric Dumazet 	key_control->thoff = min_t(u16, nhoff, skb ? skb->len : hlen);
1667a6e544b0STom Herbert 	key_basic->n_proto = proto;
1668a6e544b0STom Herbert 	key_basic->ip_proto = ip_proto;
1669a6e544b0STom Herbert 
1670a6e544b0STom Herbert 	return ret;
167134fad54cSEric Dumazet 
167234fad54cSEric Dumazet out_bad:
167334fad54cSEric Dumazet 	ret = false;
167434fad54cSEric Dumazet 	goto out;
16750744dd00SEric Dumazet }
1676690e36e7SDavid S. Miller EXPORT_SYMBOL(__skb_flow_dissect);
1677441d9d32SCong Wang 
167849ecc2e9SEric Dumazet static siphash_aligned_key_t hashrnd;
__flow_hash_secret_init(void)167966415cf8SHannes Frederic Sowa static __always_inline void __flow_hash_secret_init(void)
168066415cf8SHannes Frederic Sowa {
168166415cf8SHannes Frederic Sowa 	net_get_random_once(&hashrnd, sizeof(hashrnd));
168266415cf8SHannes Frederic Sowa }
168366415cf8SHannes Frederic Sowa 
flow_keys_hash_start(const struct flow_keys * flow)168455667441SEric Dumazet static const void *flow_keys_hash_start(const struct flow_keys *flow)
168566415cf8SHannes Frederic Sowa {
168655667441SEric Dumazet 	BUILD_BUG_ON(FLOW_KEYS_HASH_OFFSET % SIPHASH_ALIGNMENT);
168755667441SEric Dumazet 	return &flow->FLOW_KEYS_HASH_START_FIELD;
168842aecaa9STom Herbert }
168942aecaa9STom Herbert 
flow_keys_hash_length(const struct flow_keys * flow)169020a17bf6SDavid S. Miller static inline size_t flow_keys_hash_length(const struct flow_keys *flow)
169142aecaa9STom Herbert {
1692c3f83241STom Herbert 	size_t diff = FLOW_KEYS_HASH_OFFSET + sizeof(flow->addrs);
1693d31e9558SDavid S. Miller 
169442aecaa9STom Herbert 	BUILD_BUG_ON((sizeof(*flow) - FLOW_KEYS_HASH_OFFSET) % sizeof(u32));
1695c3f83241STom Herbert 
1696c3f83241STom Herbert 	switch (flow->control.addr_type) {
1697c3f83241STom Herbert 	case FLOW_DISSECTOR_KEY_IPV4_ADDRS:
1698c3f83241STom Herbert 		diff -= sizeof(flow->addrs.v4addrs);
1699c3f83241STom Herbert 		break;
1700c3f83241STom Herbert 	case FLOW_DISSECTOR_KEY_IPV6_ADDRS:
1701c3f83241STom Herbert 		diff -= sizeof(flow->addrs.v6addrs);
1702c3f83241STom Herbert 		break;
17038d6e79d3SJon Maloy 	case FLOW_DISSECTOR_KEY_TIPC:
17048d6e79d3SJon Maloy 		diff -= sizeof(flow->addrs.tipckey);
17059f249089STom Herbert 		break;
1706c3f83241STom Herbert 	}
170755667441SEric Dumazet 	return sizeof(*flow) - diff;
1708c3f83241STom Herbert }
1709c3f83241STom Herbert 
flow_get_u32_src(const struct flow_keys * flow)1710c3f83241STom Herbert __be32 flow_get_u32_src(const struct flow_keys *flow)
1711c3f83241STom Herbert {
1712c3f83241STom Herbert 	switch (flow->control.addr_type) {
1713c3f83241STom Herbert 	case FLOW_DISSECTOR_KEY_IPV4_ADDRS:
1714c3f83241STom Herbert 		return flow->addrs.v4addrs.src;
1715c3f83241STom Herbert 	case FLOW_DISSECTOR_KEY_IPV6_ADDRS:
1716c3f83241STom Herbert 		return (__force __be32)ipv6_addr_hash(
1717c3f83241STom Herbert 			&flow->addrs.v6addrs.src);
17188d6e79d3SJon Maloy 	case FLOW_DISSECTOR_KEY_TIPC:
17198d6e79d3SJon Maloy 		return flow->addrs.tipckey.key;
1720c3f83241STom Herbert 	default:
1721c3f83241STom Herbert 		return 0;
1722c3f83241STom Herbert 	}
1723c3f83241STom Herbert }
1724c3f83241STom Herbert EXPORT_SYMBOL(flow_get_u32_src);
1725c3f83241STom Herbert 
flow_get_u32_dst(const struct flow_keys * flow)1726c3f83241STom Herbert __be32 flow_get_u32_dst(const struct flow_keys *flow)
1727c3f83241STom Herbert {
1728c3f83241STom Herbert 	switch (flow->control.addr_type) {
1729c3f83241STom Herbert 	case FLOW_DISSECTOR_KEY_IPV4_ADDRS:
1730c3f83241STom Herbert 		return flow->addrs.v4addrs.dst;
1731c3f83241STom Herbert 	case FLOW_DISSECTOR_KEY_IPV6_ADDRS:
1732c3f83241STom Herbert 		return (__force __be32)ipv6_addr_hash(
1733c3f83241STom Herbert 			&flow->addrs.v6addrs.dst);
1734c3f83241STom Herbert 	default:
1735c3f83241STom Herbert 		return 0;
1736c3f83241STom Herbert 	}
1737c3f83241STom Herbert }
1738c3f83241STom Herbert EXPORT_SYMBOL(flow_get_u32_dst);
1739c3f83241STom Herbert 
17401e60cebfSzhang kai /* Sort the source and destination IP and the ports,
174198298e6cSMatteo Croce  * to have consistent hash within the two directions
174298298e6cSMatteo Croce  */
__flow_hash_consistentify(struct flow_keys * keys)1743c3f83241STom Herbert static inline void __flow_hash_consistentify(struct flow_keys *keys)
1744c3f83241STom Herbert {
1745c3f83241STom Herbert 	int addr_diff, i;
1746c3f83241STom Herbert 
1747c3f83241STom Herbert 	switch (keys->control.addr_type) {
1748c3f83241STom Herbert 	case FLOW_DISSECTOR_KEY_IPV4_ADDRS:
174964ae13edSLudovic Cintrat 		if ((__force u32)keys->addrs.v4addrs.dst <
175064ae13edSLudovic Cintrat 		    (__force u32)keys->addrs.v4addrs.src)
1751c3f83241STom Herbert 			swap(keys->addrs.v4addrs.src, keys->addrs.v4addrs.dst);
17521e60cebfSzhang kai 
17531e60cebfSzhang kai 		if ((__force u16)keys->ports.dst <
17541e60cebfSzhang kai 		    (__force u16)keys->ports.src) {
1755c3f83241STom Herbert 			swap(keys->ports.src, keys->ports.dst);
1756c3f83241STom Herbert 		}
1757c3f83241STom Herbert 		break;
1758c3f83241STom Herbert 	case FLOW_DISSECTOR_KEY_IPV6_ADDRS:
1759c3f83241STom Herbert 		addr_diff = memcmp(&keys->addrs.v6addrs.dst,
1760c3f83241STom Herbert 				   &keys->addrs.v6addrs.src,
1761c3f83241STom Herbert 				   sizeof(keys->addrs.v6addrs.dst));
17621e60cebfSzhang kai 		if (addr_diff < 0) {
1763c3f83241STom Herbert 			for (i = 0; i < 4; i++)
1764c3f83241STom Herbert 				swap(keys->addrs.v6addrs.src.s6_addr32[i],
1765c3f83241STom Herbert 				     keys->addrs.v6addrs.dst.s6_addr32[i]);
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 	}
177366415cf8SHannes Frederic Sowa }
177466415cf8SHannes Frederic Sowa 
__flow_hash_from_keys(struct flow_keys * keys,const siphash_key_t * keyval)177555667441SEric Dumazet static inline u32 __flow_hash_from_keys(struct flow_keys *keys,
177655667441SEric Dumazet 					const siphash_key_t *keyval)
17775ed20a68STom Herbert {
17785ed20a68STom Herbert 	u32 hash;
17795ed20a68STom Herbert 
1780c3f83241STom Herbert 	__flow_hash_consistentify(keys);
17815ed20a68STom Herbert 
178255667441SEric Dumazet 	hash = siphash(flow_keys_hash_start(keys),
178342aecaa9STom Herbert 		       flow_keys_hash_length(keys), keyval);
17845ed20a68STom Herbert 	if (!hash)
17855ed20a68STom Herbert 		hash = 1;
17865ed20a68STom Herbert 
17875ed20a68STom Herbert 	return hash;
17885ed20a68STom Herbert }
17895ed20a68STom Herbert 
flow_hash_from_keys(struct flow_keys * keys)17905ed20a68STom Herbert u32 flow_hash_from_keys(struct flow_keys *keys)
17915ed20a68STom Herbert {
179250fb7992STom Herbert 	__flow_hash_secret_init();
179355667441SEric Dumazet 	return __flow_hash_from_keys(keys, &hashrnd);
17945ed20a68STom Herbert }
17955ed20a68STom Herbert EXPORT_SYMBOL(flow_hash_from_keys);
17965ed20a68STom Herbert 
___skb_get_hash(const struct sk_buff * skb,struct flow_keys * keys,const siphash_key_t * keyval)179750fb7992STom Herbert static inline u32 ___skb_get_hash(const struct sk_buff *skb,
179855667441SEric Dumazet 				  struct flow_keys *keys,
179955667441SEric Dumazet 				  const siphash_key_t *keyval)
180050fb7992STom Herbert {
18016db61d79STom Herbert 	skb_flow_dissect_flow_keys(skb, keys,
18026db61d79STom Herbert 				   FLOW_DISSECTOR_F_STOP_AT_FLOW_LABEL);
180350fb7992STom Herbert 
180450fb7992STom Herbert 	return __flow_hash_from_keys(keys, keyval);
180550fb7992STom Herbert }
180650fb7992STom Herbert 
18072f59e1ebSTom Herbert struct _flow_keys_digest_data {
18082f59e1ebSTom Herbert 	__be16	n_proto;
18092f59e1ebSTom Herbert 	u8	ip_proto;
18102f59e1ebSTom Herbert 	u8	padding;
18112f59e1ebSTom Herbert 	__be32	ports;
18122f59e1ebSTom Herbert 	__be32	src;
18132f59e1ebSTom Herbert 	__be32	dst;
18142f59e1ebSTom Herbert };
18152f59e1ebSTom Herbert 
make_flow_keys_digest(struct flow_keys_digest * digest,const struct flow_keys * flow)18162f59e1ebSTom Herbert void make_flow_keys_digest(struct flow_keys_digest *digest,
18172f59e1ebSTom Herbert 			   const struct flow_keys *flow)
18182f59e1ebSTom Herbert {
18192f59e1ebSTom Herbert 	struct _flow_keys_digest_data *data =
18202f59e1ebSTom Herbert 	    (struct _flow_keys_digest_data *)digest;
18212f59e1ebSTom Herbert 
18222f59e1ebSTom Herbert 	BUILD_BUG_ON(sizeof(*data) > sizeof(*digest));
18232f59e1ebSTom Herbert 
18242f59e1ebSTom Herbert 	memset(digest, 0, sizeof(*digest));
18252f59e1ebSTom Herbert 
182606635a35SJiri Pirko 	data->n_proto = flow->basic.n_proto;
182706635a35SJiri Pirko 	data->ip_proto = flow->basic.ip_proto;
182806635a35SJiri Pirko 	data->ports = flow->ports.ports;
1829c3f83241STom Herbert 	data->src = flow->addrs.v4addrs.src;
1830c3f83241STom Herbert 	data->dst = flow->addrs.v4addrs.dst;
18312f59e1ebSTom Herbert }
18322f59e1ebSTom Herbert EXPORT_SYMBOL(make_flow_keys_digest);
18332f59e1ebSTom Herbert 
1834eb70db87SDavid S. Miller static struct flow_dissector flow_keys_dissector_symmetric __read_mostly;
1835eb70db87SDavid S. Miller 
__skb_get_hash_symmetric(const struct sk_buff * skb)1836b917783cSFlorian Westphal u32 __skb_get_hash_symmetric(const struct sk_buff *skb)
1837eb70db87SDavid S. Miller {
1838eb70db87SDavid S. Miller 	struct flow_keys keys;
1839eb70db87SDavid S. Miller 
1840eb70db87SDavid S. Miller 	__flow_hash_secret_init();
1841eb70db87SDavid S. Miller 
1842eb70db87SDavid S. Miller 	memset(&keys, 0, sizeof(keys));
18433cbf4ffbSStanislav Fomichev 	__skb_flow_dissect(NULL, skb, &flow_keys_dissector_symmetric,
1844a5e2151fSQuan Tian 			   &keys, NULL, 0, 0, 0, 0);
1845eb70db87SDavid S. Miller 
184655667441SEric Dumazet 	return __flow_hash_from_keys(&keys, &hashrnd);
1847eb70db87SDavid S. Miller }
1848eb70db87SDavid S. Miller EXPORT_SYMBOL_GPL(__skb_get_hash_symmetric);
1849eb70db87SDavid S. Miller 
1850d4fd3275SJiri Pirko /**
1851d4fd3275SJiri Pirko  * __skb_get_hash: calculate a flow hash
1852d4fd3275SJiri Pirko  * @skb: sk_buff to calculate flow hash from
1853d4fd3275SJiri Pirko  *
1854d4fd3275SJiri Pirko  * This function calculates a flow hash based on src/dst addresses
185561b905daSTom Herbert  * and src/dst port numbers.  Sets hash in skb to non-zero hash value
185661b905daSTom Herbert  * on success, zero indicates no valid hash.  Also, sets l4_hash in skb
1857441d9d32SCong Wang  * if hash is a canonical 4-tuple hash over transport ports.
1858441d9d32SCong Wang  */
__skb_get_hash(struct sk_buff * skb)18593958afa1STom Herbert void __skb_get_hash(struct sk_buff *skb)
1860441d9d32SCong Wang {
1861441d9d32SCong Wang 	struct flow_keys keys;
1862635c223cSGao Feng 	u32 hash;
1863441d9d32SCong Wang 
186450fb7992STom Herbert 	__flow_hash_secret_init();
186550fb7992STom Herbert 
186655667441SEric Dumazet 	hash = ___skb_get_hash(skb, &keys, &hashrnd);
1867635c223cSGao Feng 
1868635c223cSGao Feng 	__skb_set_sw_hash(skb, hash, flow_keys_have_l4(&keys));
1869441d9d32SCong Wang }
18703958afa1STom Herbert EXPORT_SYMBOL(__skb_get_hash);
1871441d9d32SCong Wang 
skb_get_hash_perturb(const struct sk_buff * skb,const siphash_key_t * perturb)187255667441SEric Dumazet __u32 skb_get_hash_perturb(const struct sk_buff *skb,
187355667441SEric Dumazet 			   const siphash_key_t *perturb)
187450fb7992STom Herbert {
187550fb7992STom Herbert 	struct flow_keys keys;
187650fb7992STom Herbert 
187750fb7992STom Herbert 	return ___skb_get_hash(skb, &keys, perturb);
187850fb7992STom Herbert }
187950fb7992STom Herbert EXPORT_SYMBOL(skb_get_hash_perturb);
188050fb7992STom Herbert 
__skb_get_poff(const struct sk_buff * skb,const void * data,const struct flow_keys_basic * keys,int hlen)1881f96533cdSAlexander Lobakin u32 __skb_get_poff(const struct sk_buff *skb, const void *data,
188272a338bcSPaolo Abeni 		   const struct flow_keys_basic *keys, int hlen)
1883f77668dcSDaniel Borkmann {
188442aecaa9STom Herbert 	u32 poff = keys->control.thoff;
1885f77668dcSDaniel Borkmann 
188643d2ccb3SAlexander Duyck 	/* skip L4 headers for fragments after the first */
188743d2ccb3SAlexander Duyck 	if ((keys->control.flags & FLOW_DIS_IS_FRAGMENT) &&
188843d2ccb3SAlexander Duyck 	    !(keys->control.flags & FLOW_DIS_FIRST_FRAG))
188943d2ccb3SAlexander Duyck 		return poff;
189043d2ccb3SAlexander Duyck 
189106635a35SJiri Pirko 	switch (keys->basic.ip_proto) {
1892f77668dcSDaniel Borkmann 	case IPPROTO_TCP: {
18935af7fb6eSAlexander Duyck 		/* access doff as u8 to avoid unaligned access */
18945af7fb6eSAlexander Duyck 		const u8 *doff;
18955af7fb6eSAlexander Duyck 		u8 _doff;
1896f77668dcSDaniel Borkmann 
18975af7fb6eSAlexander Duyck 		doff = __skb_header_pointer(skb, poff + 12, sizeof(_doff),
18985af7fb6eSAlexander Duyck 					    data, hlen, &_doff);
18995af7fb6eSAlexander Duyck 		if (!doff)
1900f77668dcSDaniel Borkmann 			return poff;
1901f77668dcSDaniel Borkmann 
19025af7fb6eSAlexander Duyck 		poff += max_t(u32, sizeof(struct tcphdr), (*doff & 0xF0) >> 2);
1903f77668dcSDaniel Borkmann 		break;
1904f77668dcSDaniel Borkmann 	}
1905f77668dcSDaniel Borkmann 	case IPPROTO_UDP:
1906f77668dcSDaniel Borkmann 	case IPPROTO_UDPLITE:
1907f77668dcSDaniel Borkmann 		poff += sizeof(struct udphdr);
1908f77668dcSDaniel Borkmann 		break;
1909f77668dcSDaniel Borkmann 	/* For the rest, we do not really care about header
1910f77668dcSDaniel Borkmann 	 * extensions at this point for now.
1911f77668dcSDaniel Borkmann 	 */
1912f77668dcSDaniel Borkmann 	case IPPROTO_ICMP:
1913f77668dcSDaniel Borkmann 		poff += sizeof(struct icmphdr);
1914f77668dcSDaniel Borkmann 		break;
1915f77668dcSDaniel Borkmann 	case IPPROTO_ICMPV6:
1916f77668dcSDaniel Borkmann 		poff += sizeof(struct icmp6hdr);
1917f77668dcSDaniel Borkmann 		break;
1918f77668dcSDaniel Borkmann 	case IPPROTO_IGMP:
1919f77668dcSDaniel Borkmann 		poff += sizeof(struct igmphdr);
1920f77668dcSDaniel Borkmann 		break;
1921f77668dcSDaniel Borkmann 	case IPPROTO_DCCP:
1922f77668dcSDaniel Borkmann 		poff += sizeof(struct dccp_hdr);
1923f77668dcSDaniel Borkmann 		break;
1924f77668dcSDaniel Borkmann 	case IPPROTO_SCTP:
1925f77668dcSDaniel Borkmann 		poff += sizeof(struct sctphdr);
1926f77668dcSDaniel Borkmann 		break;
1927f77668dcSDaniel Borkmann 	}
1928f77668dcSDaniel Borkmann 
1929f77668dcSDaniel Borkmann 	return poff;
1930f77668dcSDaniel Borkmann }
1931f77668dcSDaniel Borkmann 
19320db89b8bSJiri Pirko /**
19330db89b8bSJiri Pirko  * skb_get_poff - get the offset to the payload
19340db89b8bSJiri Pirko  * @skb: sk_buff to get the payload offset from
19350db89b8bSJiri Pirko  *
19360db89b8bSJiri Pirko  * The function will get the offset to the payload as far as it could
193756193d1bSAlexander Duyck  * be dissected.  The main user is currently BPF, so that we can dynamically
193856193d1bSAlexander Duyck  * truncate packets without needing to push actual payload to the user
193956193d1bSAlexander Duyck  * space and can analyze headers only, instead.
194056193d1bSAlexander Duyck  */
skb_get_poff(const struct sk_buff * skb)194156193d1bSAlexander Duyck u32 skb_get_poff(const struct sk_buff *skb)
194256193d1bSAlexander Duyck {
194372a338bcSPaolo Abeni 	struct flow_keys_basic keys;
194456193d1bSAlexander Duyck 
19453cbf4ffbSStanislav Fomichev 	if (!skb_flow_dissect_flow_keys_basic(NULL, skb, &keys,
19463cbf4ffbSStanislav Fomichev 					      NULL, 0, 0, 0, 0))
194756193d1bSAlexander Duyck 		return 0;
194856193d1bSAlexander Duyck 
194956193d1bSAlexander Duyck 	return __skb_get_poff(skb, skb->data, &keys, skb_headlen(skb));
195056193d1bSAlexander Duyck }
195106635a35SJiri Pirko 
__get_hash_from_flowi6(const struct flowi6 * fl6,struct flow_keys * keys)195220a17bf6SDavid S. Miller __u32 __get_hash_from_flowi6(const struct flowi6 *fl6, struct flow_keys *keys)
1953a17ace95SDavid S. Miller {
1954a17ace95SDavid S. Miller 	memset(keys, 0, sizeof(*keys));
1955a17ace95SDavid S. Miller 
1956a17ace95SDavid S. Miller 	memcpy(&keys->addrs.v6addrs.src, &fl6->saddr,
1957a17ace95SDavid S. Miller 	    sizeof(keys->addrs.v6addrs.src));
1958a17ace95SDavid S. Miller 	memcpy(&keys->addrs.v6addrs.dst, &fl6->daddr,
1959a17ace95SDavid S. Miller 	    sizeof(keys->addrs.v6addrs.dst));
1960a17ace95SDavid S. Miller 	keys->control.addr_type = FLOW_DISSECTOR_KEY_IPV6_ADDRS;
1961a17ace95SDavid S. Miller 	keys->ports.src = fl6->fl6_sport;
1962a17ace95SDavid S. Miller 	keys->ports.dst = fl6->fl6_dport;
1963a17ace95SDavid S. Miller 	keys->keyid.keyid = fl6->fl6_gre_key;
1964fa1be7e0SMichal Kubecek 	keys->tags.flow_label = (__force u32)flowi6_get_flowlabel(fl6);
1965a17ace95SDavid S. Miller 	keys->basic.ip_proto = fl6->flowi6_proto;
1966a17ace95SDavid S. Miller 
1967a17ace95SDavid S. Miller 	return flow_hash_from_keys(keys);
1968a17ace95SDavid S. Miller }
1969a17ace95SDavid S. Miller EXPORT_SYMBOL(__get_hash_from_flowi6);
1970a17ace95SDavid S. Miller 
197106635a35SJiri Pirko static const struct flow_dissector_key flow_keys_dissector_keys[] = {
197206635a35SJiri Pirko 	{
197342aecaa9STom Herbert 		.key_id = FLOW_DISSECTOR_KEY_CONTROL,
197442aecaa9STom Herbert 		.offset = offsetof(struct flow_keys, control),
197542aecaa9STom Herbert 	},
197642aecaa9STom Herbert 	{
197706635a35SJiri Pirko 		.key_id = FLOW_DISSECTOR_KEY_BASIC,
197806635a35SJiri Pirko 		.offset = offsetof(struct flow_keys, basic),
197906635a35SJiri Pirko 	},
198006635a35SJiri Pirko 	{
198106635a35SJiri Pirko 		.key_id = FLOW_DISSECTOR_KEY_IPV4_ADDRS,
1982c3f83241STom Herbert 		.offset = offsetof(struct flow_keys, addrs.v4addrs),
1983c3f83241STom Herbert 	},
1984c3f83241STom Herbert 	{
1985c3f83241STom Herbert 		.key_id = FLOW_DISSECTOR_KEY_IPV6_ADDRS,
1986c3f83241STom Herbert 		.offset = offsetof(struct flow_keys, addrs.v6addrs),
198706635a35SJiri Pirko 	},
198806635a35SJiri Pirko 	{
19898d6e79d3SJon Maloy 		.key_id = FLOW_DISSECTOR_KEY_TIPC,
19908d6e79d3SJon Maloy 		.offset = offsetof(struct flow_keys, addrs.tipckey),
19919f249089STom Herbert 	},
19929f249089STom Herbert 	{
199306635a35SJiri Pirko 		.key_id = FLOW_DISSECTOR_KEY_PORTS,
199406635a35SJiri Pirko 		.offset = offsetof(struct flow_keys, ports),
199506635a35SJiri Pirko 	},
1996d34af823STom Herbert 	{
1997f6a66927SHadar Hen Zion 		.key_id = FLOW_DISSECTOR_KEY_VLAN,
1998f6a66927SHadar Hen Zion 		.offset = offsetof(struct flow_keys, vlan),
1999d34af823STom Herbert 	},
200087ee9e52STom Herbert 	{
200187ee9e52STom Herbert 		.key_id = FLOW_DISSECTOR_KEY_FLOW_LABEL,
200287ee9e52STom Herbert 		.offset = offsetof(struct flow_keys, tags),
200387ee9e52STom Herbert 	},
20041fdd512cSTom Herbert 	{
20051fdd512cSTom Herbert 		.key_id = FLOW_DISSECTOR_KEY_GRE_KEYID,
20061fdd512cSTom Herbert 		.offset = offsetof(struct flow_keys, keyid),
20071fdd512cSTom Herbert 	},
200806635a35SJiri Pirko };
200906635a35SJiri Pirko 
2010eb70db87SDavid S. Miller static const struct flow_dissector_key flow_keys_dissector_symmetric_keys[] = {
2011eb70db87SDavid S. Miller 	{
2012eb70db87SDavid S. Miller 		.key_id = FLOW_DISSECTOR_KEY_CONTROL,
2013eb70db87SDavid S. Miller 		.offset = offsetof(struct flow_keys, control),
2014eb70db87SDavid S. Miller 	},
2015eb70db87SDavid S. Miller 	{
2016eb70db87SDavid S. Miller 		.key_id = FLOW_DISSECTOR_KEY_BASIC,
2017eb70db87SDavid S. Miller 		.offset = offsetof(struct flow_keys, basic),
2018eb70db87SDavid S. Miller 	},
2019eb70db87SDavid S. Miller 	{
2020eb70db87SDavid S. Miller 		.key_id = FLOW_DISSECTOR_KEY_IPV4_ADDRS,
2021eb70db87SDavid S. Miller 		.offset = offsetof(struct flow_keys, addrs.v4addrs),
2022eb70db87SDavid S. Miller 	},
2023eb70db87SDavid S. Miller 	{
2024eb70db87SDavid S. Miller 		.key_id = FLOW_DISSECTOR_KEY_IPV6_ADDRS,
2025eb70db87SDavid S. Miller 		.offset = offsetof(struct flow_keys, addrs.v6addrs),
2026eb70db87SDavid S. Miller 	},
2027eb70db87SDavid S. Miller 	{
2028eb70db87SDavid S. Miller 		.key_id = FLOW_DISSECTOR_KEY_PORTS,
2029eb70db87SDavid S. Miller 		.offset = offsetof(struct flow_keys, ports),
2030eb70db87SDavid S. Miller 	},
2031eb70db87SDavid S. Miller };
2032eb70db87SDavid S. Miller 
203372a338bcSPaolo Abeni static const struct flow_dissector_key flow_keys_basic_dissector_keys[] = {
203406635a35SJiri Pirko 	{
203542aecaa9STom Herbert 		.key_id = FLOW_DISSECTOR_KEY_CONTROL,
203642aecaa9STom Herbert 		.offset = offsetof(struct flow_keys, control),
203742aecaa9STom Herbert 	},
203842aecaa9STom Herbert 	{
203906635a35SJiri Pirko 		.key_id = FLOW_DISSECTOR_KEY_BASIC,
204006635a35SJiri Pirko 		.offset = offsetof(struct flow_keys, basic),
204106635a35SJiri Pirko 	},
204206635a35SJiri Pirko };
204306635a35SJiri Pirko 
204406635a35SJiri Pirko struct flow_dissector flow_keys_dissector __read_mostly;
204506635a35SJiri Pirko EXPORT_SYMBOL(flow_keys_dissector);
204606635a35SJiri Pirko 
204772a338bcSPaolo Abeni struct flow_dissector flow_keys_basic_dissector __read_mostly;
204872a338bcSPaolo Abeni EXPORT_SYMBOL(flow_keys_basic_dissector);
204906635a35SJiri Pirko 
init_default_flow_dissectors(void)205006635a35SJiri Pirko static int __init init_default_flow_dissectors(void)
205106635a35SJiri Pirko {
205206635a35SJiri Pirko 	skb_flow_dissector_init(&flow_keys_dissector,
205306635a35SJiri Pirko 				flow_keys_dissector_keys,
205406635a35SJiri Pirko 				ARRAY_SIZE(flow_keys_dissector_keys));
2055eb70db87SDavid S. Miller 	skb_flow_dissector_init(&flow_keys_dissector_symmetric,
2056eb70db87SDavid S. Miller 				flow_keys_dissector_symmetric_keys,
2057eb70db87SDavid S. Miller 				ARRAY_SIZE(flow_keys_dissector_symmetric_keys));
205872a338bcSPaolo Abeni 	skb_flow_dissector_init(&flow_keys_basic_dissector,
205972a338bcSPaolo Abeni 				flow_keys_basic_dissector_keys,
206072a338bcSPaolo Abeni 				ARRAY_SIZE(flow_keys_basic_dissector_keys));
2061b27f7bb5SJakub Sitnicki 	return 0;
20625cf65922SJakub Sitnicki }
2063c9b8af13SEric Dumazet core_initcall(init_default_flow_dissectors);
2064