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