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