.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
---|
1 | 2 | #include <linux/kernel.h> |
---|
2 | 3 | #include <linux/skbuff.h> |
---|
3 | 4 | #include <linux/export.h> |
---|
.. | .. |
---|
25 | 26 | #include <net/flow_dissector.h> |
---|
26 | 27 | #include <scsi/fc/fc_fcoe.h> |
---|
27 | 28 | #include <uapi/linux/batadv_packet.h> |
---|
| 29 | +#include <linux/bpf.h> |
---|
| 30 | +#if IS_ENABLED(CONFIG_NF_CONNTRACK) |
---|
| 31 | +#include <net/netfilter/nf_conntrack_core.h> |
---|
| 32 | +#include <net/netfilter/nf_conntrack_labels.h> |
---|
| 33 | +#endif |
---|
| 34 | +#include <linux/bpf-netns.h> |
---|
28 | 35 | |
---|
29 | 36 | static void dissector_set_key(struct flow_dissector *flow_dissector, |
---|
30 | 37 | enum flow_dissector_key_id key_id) |
---|
.. | .. |
---|
62 | 69 | } |
---|
63 | 70 | EXPORT_SYMBOL(skb_flow_dissector_init); |
---|
64 | 71 | |
---|
65 | | -/** |
---|
66 | | - * skb_flow_get_be16 - extract be16 entity |
---|
67 | | - * @skb: sk_buff to extract from |
---|
68 | | - * @poff: offset to extract at |
---|
69 | | - * @data: raw buffer pointer to the packet |
---|
70 | | - * @hlen: packet header length |
---|
71 | | - * |
---|
72 | | - * The function will try to retrieve a be32 entity at |
---|
73 | | - * offset poff |
---|
74 | | - */ |
---|
75 | | -static __be16 skb_flow_get_be16(const struct sk_buff *skb, int poff, |
---|
76 | | - void *data, int hlen) |
---|
| 72 | +#ifdef CONFIG_BPF_SYSCALL |
---|
| 73 | +int flow_dissector_bpf_prog_attach_check(struct net *net, |
---|
| 74 | + struct bpf_prog *prog) |
---|
77 | 75 | { |
---|
78 | | - __be16 *u, _u; |
---|
| 76 | + enum netns_bpf_attach_type type = NETNS_BPF_FLOW_DISSECTOR; |
---|
79 | 77 | |
---|
80 | | - u = __skb_header_pointer(skb, poff, sizeof(_u), data, hlen, &_u); |
---|
81 | | - if (u) |
---|
82 | | - return *u; |
---|
| 78 | + if (net == &init_net) { |
---|
| 79 | + /* BPF flow dissector in the root namespace overrides |
---|
| 80 | + * any per-net-namespace one. When attaching to root, |
---|
| 81 | + * make sure we don't have any BPF program attached |
---|
| 82 | + * to the non-root namespaces. |
---|
| 83 | + */ |
---|
| 84 | + struct net *ns; |
---|
| 85 | + |
---|
| 86 | + for_each_net(ns) { |
---|
| 87 | + if (ns == &init_net) |
---|
| 88 | + continue; |
---|
| 89 | + if (rcu_access_pointer(ns->bpf.run_array[type])) |
---|
| 90 | + return -EEXIST; |
---|
| 91 | + } |
---|
| 92 | + } else { |
---|
| 93 | + /* Make sure root flow dissector is not attached |
---|
| 94 | + * when attaching to the non-root namespace. |
---|
| 95 | + */ |
---|
| 96 | + if (rcu_access_pointer(init_net.bpf.run_array[type])) |
---|
| 97 | + return -EEXIST; |
---|
| 98 | + } |
---|
83 | 99 | |
---|
84 | 100 | return 0; |
---|
85 | 101 | } |
---|
| 102 | +#endif /* CONFIG_BPF_SYSCALL */ |
---|
86 | 103 | |
---|
87 | 104 | /** |
---|
88 | 105 | * __skb_flow_get_ports - extract the upper layer ports and return them |
---|
.. | .. |
---|
118 | 135 | } |
---|
119 | 136 | EXPORT_SYMBOL(__skb_flow_get_ports); |
---|
120 | 137 | |
---|
| 138 | +static bool icmp_has_id(u8 type) |
---|
| 139 | +{ |
---|
| 140 | + switch (type) { |
---|
| 141 | + case ICMP_ECHO: |
---|
| 142 | + case ICMP_ECHOREPLY: |
---|
| 143 | + case ICMP_TIMESTAMP: |
---|
| 144 | + case ICMP_TIMESTAMPREPLY: |
---|
| 145 | + case ICMPV6_ECHO_REQUEST: |
---|
| 146 | + case ICMPV6_ECHO_REPLY: |
---|
| 147 | + return true; |
---|
| 148 | + } |
---|
| 149 | + |
---|
| 150 | + return false; |
---|
| 151 | +} |
---|
| 152 | + |
---|
| 153 | +/** |
---|
| 154 | + * skb_flow_get_icmp_tci - extract ICMP(6) Type, Code and Identifier fields |
---|
| 155 | + * @skb: sk_buff to extract from |
---|
| 156 | + * @key_icmp: struct flow_dissector_key_icmp to fill |
---|
| 157 | + * @data: raw buffer pointer to the packet |
---|
| 158 | + * @thoff: offset to extract at |
---|
| 159 | + * @hlen: packet header length |
---|
| 160 | + */ |
---|
| 161 | +void skb_flow_get_icmp_tci(const struct sk_buff *skb, |
---|
| 162 | + struct flow_dissector_key_icmp *key_icmp, |
---|
| 163 | + void *data, int thoff, int hlen) |
---|
| 164 | +{ |
---|
| 165 | + struct icmphdr *ih, _ih; |
---|
| 166 | + |
---|
| 167 | + ih = __skb_header_pointer(skb, thoff, sizeof(_ih), data, hlen, &_ih); |
---|
| 168 | + if (!ih) |
---|
| 169 | + return; |
---|
| 170 | + |
---|
| 171 | + key_icmp->type = ih->type; |
---|
| 172 | + key_icmp->code = ih->code; |
---|
| 173 | + |
---|
| 174 | + /* As we use 0 to signal that the Id field is not present, |
---|
| 175 | + * avoid confusion with packets without such field |
---|
| 176 | + */ |
---|
| 177 | + if (icmp_has_id(ih->type)) |
---|
| 178 | + key_icmp->id = ih->un.echo.id ? ntohs(ih->un.echo.id) : 1; |
---|
| 179 | + else |
---|
| 180 | + key_icmp->id = 0; |
---|
| 181 | +} |
---|
| 182 | +EXPORT_SYMBOL(skb_flow_get_icmp_tci); |
---|
| 183 | + |
---|
| 184 | +/* If FLOW_DISSECTOR_KEY_ICMP is set, dissect an ICMP packet |
---|
| 185 | + * using skb_flow_get_icmp_tci(). |
---|
| 186 | + */ |
---|
| 187 | +static void __skb_flow_dissect_icmp(const struct sk_buff *skb, |
---|
| 188 | + struct flow_dissector *flow_dissector, |
---|
| 189 | + void *target_container, |
---|
| 190 | + void *data, int thoff, int hlen) |
---|
| 191 | +{ |
---|
| 192 | + struct flow_dissector_key_icmp *key_icmp; |
---|
| 193 | + |
---|
| 194 | + if (!dissector_uses_key(flow_dissector, FLOW_DISSECTOR_KEY_ICMP)) |
---|
| 195 | + return; |
---|
| 196 | + |
---|
| 197 | + key_icmp = skb_flow_dissector_target(flow_dissector, |
---|
| 198 | + FLOW_DISSECTOR_KEY_ICMP, |
---|
| 199 | + target_container); |
---|
| 200 | + |
---|
| 201 | + skb_flow_get_icmp_tci(skb, key_icmp, data, thoff, hlen); |
---|
| 202 | +} |
---|
| 203 | + |
---|
| 204 | +void skb_flow_dissect_meta(const struct sk_buff *skb, |
---|
| 205 | + struct flow_dissector *flow_dissector, |
---|
| 206 | + void *target_container) |
---|
| 207 | +{ |
---|
| 208 | + struct flow_dissector_key_meta *meta; |
---|
| 209 | + |
---|
| 210 | + if (!dissector_uses_key(flow_dissector, FLOW_DISSECTOR_KEY_META)) |
---|
| 211 | + return; |
---|
| 212 | + |
---|
| 213 | + meta = skb_flow_dissector_target(flow_dissector, |
---|
| 214 | + FLOW_DISSECTOR_KEY_META, |
---|
| 215 | + target_container); |
---|
| 216 | + meta->ingress_ifindex = skb->skb_iif; |
---|
| 217 | +} |
---|
| 218 | +EXPORT_SYMBOL(skb_flow_dissect_meta); |
---|
| 219 | + |
---|
121 | 220 | static void |
---|
122 | 221 | skb_flow_dissect_set_enc_addr_type(enum flow_dissector_key_id type, |
---|
123 | 222 | struct flow_dissector *flow_dissector, |
---|
.. | .. |
---|
133 | 232 | target_container); |
---|
134 | 233 | ctrl->addr_type = type; |
---|
135 | 234 | } |
---|
| 235 | + |
---|
| 236 | +void |
---|
| 237 | +skb_flow_dissect_ct(const struct sk_buff *skb, |
---|
| 238 | + struct flow_dissector *flow_dissector, |
---|
| 239 | + void *target_container, |
---|
| 240 | + u16 *ctinfo_map, |
---|
| 241 | + size_t mapsize) |
---|
| 242 | +{ |
---|
| 243 | +#if IS_ENABLED(CONFIG_NF_CONNTRACK) |
---|
| 244 | + struct flow_dissector_key_ct *key; |
---|
| 245 | + enum ip_conntrack_info ctinfo; |
---|
| 246 | + struct nf_conn_labels *cl; |
---|
| 247 | + struct nf_conn *ct; |
---|
| 248 | + |
---|
| 249 | + if (!dissector_uses_key(flow_dissector, FLOW_DISSECTOR_KEY_CT)) |
---|
| 250 | + return; |
---|
| 251 | + |
---|
| 252 | + ct = nf_ct_get(skb, &ctinfo); |
---|
| 253 | + if (!ct) |
---|
| 254 | + return; |
---|
| 255 | + |
---|
| 256 | + key = skb_flow_dissector_target(flow_dissector, |
---|
| 257 | + FLOW_DISSECTOR_KEY_CT, |
---|
| 258 | + target_container); |
---|
| 259 | + |
---|
| 260 | + if (ctinfo < mapsize) |
---|
| 261 | + key->ct_state = ctinfo_map[ctinfo]; |
---|
| 262 | +#if IS_ENABLED(CONFIG_NF_CONNTRACK_ZONES) |
---|
| 263 | + key->ct_zone = ct->zone.id; |
---|
| 264 | +#endif |
---|
| 265 | +#if IS_ENABLED(CONFIG_NF_CONNTRACK_MARK) |
---|
| 266 | + key->ct_mark = READ_ONCE(ct->mark); |
---|
| 267 | +#endif |
---|
| 268 | + |
---|
| 269 | + cl = nf_ct_labels_find(ct); |
---|
| 270 | + if (cl) |
---|
| 271 | + memcpy(key->ct_labels, cl->bits, sizeof(key->ct_labels)); |
---|
| 272 | +#endif /* CONFIG_NF_CONNTRACK */ |
---|
| 273 | +} |
---|
| 274 | +EXPORT_SYMBOL(skb_flow_dissect_ct); |
---|
136 | 275 | |
---|
137 | 276 | void |
---|
138 | 277 | skb_flow_dissect_tunnel_info(const struct sk_buff *skb, |
---|
.. | .. |
---|
244 | 383 | } |
---|
245 | 384 | EXPORT_SYMBOL(skb_flow_dissect_tunnel_info); |
---|
246 | 385 | |
---|
| 386 | +void skb_flow_dissect_hash(const struct sk_buff *skb, |
---|
| 387 | + struct flow_dissector *flow_dissector, |
---|
| 388 | + void *target_container) |
---|
| 389 | +{ |
---|
| 390 | + struct flow_dissector_key_hash *key; |
---|
| 391 | + |
---|
| 392 | + if (!dissector_uses_key(flow_dissector, FLOW_DISSECTOR_KEY_HASH)) |
---|
| 393 | + return; |
---|
| 394 | + |
---|
| 395 | + key = skb_flow_dissector_target(flow_dissector, |
---|
| 396 | + FLOW_DISSECTOR_KEY_HASH, |
---|
| 397 | + target_container); |
---|
| 398 | + |
---|
| 399 | + key->hash = skb_get_hash_raw(skb); |
---|
| 400 | +} |
---|
| 401 | +EXPORT_SYMBOL(skb_flow_dissect_hash); |
---|
| 402 | + |
---|
247 | 403 | static enum flow_dissect_ret |
---|
248 | 404 | __skb_flow_dissect_mpls(const struct sk_buff *skb, |
---|
249 | 405 | struct flow_dissector *flow_dissector, |
---|
250 | | - void *target_container, void *data, int nhoff, int hlen) |
---|
| 406 | + void *target_container, void *data, int nhoff, int hlen, |
---|
| 407 | + int lse_index, bool *entropy_label) |
---|
251 | 408 | { |
---|
252 | | - struct flow_dissector_key_keyid *key_keyid; |
---|
253 | | - struct mpls_label *hdr, _hdr[2]; |
---|
254 | | - u32 entry, label; |
---|
| 409 | + struct mpls_label *hdr, _hdr; |
---|
| 410 | + u32 entry, label, bos; |
---|
255 | 411 | |
---|
256 | 412 | if (!dissector_uses_key(flow_dissector, |
---|
257 | 413 | FLOW_DISSECTOR_KEY_MPLS_ENTROPY) && |
---|
258 | 414 | !dissector_uses_key(flow_dissector, FLOW_DISSECTOR_KEY_MPLS)) |
---|
| 415 | + return FLOW_DISSECT_RET_OUT_GOOD; |
---|
| 416 | + |
---|
| 417 | + if (lse_index >= FLOW_DIS_MPLS_MAX) |
---|
259 | 418 | return FLOW_DISSECT_RET_OUT_GOOD; |
---|
260 | 419 | |
---|
261 | 420 | hdr = __skb_header_pointer(skb, nhoff, sizeof(_hdr), data, |
---|
.. | .. |
---|
263 | 422 | if (!hdr) |
---|
264 | 423 | return FLOW_DISSECT_RET_OUT_BAD; |
---|
265 | 424 | |
---|
266 | | - entry = ntohl(hdr[0].entry); |
---|
| 425 | + entry = ntohl(hdr->entry); |
---|
267 | 426 | label = (entry & MPLS_LS_LABEL_MASK) >> MPLS_LS_LABEL_SHIFT; |
---|
| 427 | + bos = (entry & MPLS_LS_S_MASK) >> MPLS_LS_S_SHIFT; |
---|
268 | 428 | |
---|
269 | 429 | if (dissector_uses_key(flow_dissector, FLOW_DISSECTOR_KEY_MPLS)) { |
---|
270 | 430 | struct flow_dissector_key_mpls *key_mpls; |
---|
| 431 | + struct flow_dissector_mpls_lse *lse; |
---|
271 | 432 | |
---|
272 | 433 | key_mpls = skb_flow_dissector_target(flow_dissector, |
---|
273 | 434 | FLOW_DISSECTOR_KEY_MPLS, |
---|
274 | 435 | target_container); |
---|
275 | | - key_mpls->mpls_label = label; |
---|
276 | | - key_mpls->mpls_ttl = (entry & MPLS_LS_TTL_MASK) |
---|
277 | | - >> MPLS_LS_TTL_SHIFT; |
---|
278 | | - key_mpls->mpls_tc = (entry & MPLS_LS_TC_MASK) |
---|
279 | | - >> MPLS_LS_TC_SHIFT; |
---|
280 | | - key_mpls->mpls_bos = (entry & MPLS_LS_S_MASK) |
---|
281 | | - >> MPLS_LS_S_SHIFT; |
---|
| 436 | + lse = &key_mpls->ls[lse_index]; |
---|
| 437 | + |
---|
| 438 | + lse->mpls_ttl = (entry & MPLS_LS_TTL_MASK) >> MPLS_LS_TTL_SHIFT; |
---|
| 439 | + lse->mpls_bos = bos; |
---|
| 440 | + lse->mpls_tc = (entry & MPLS_LS_TC_MASK) >> MPLS_LS_TC_SHIFT; |
---|
| 441 | + lse->mpls_label = label; |
---|
| 442 | + dissector_set_mpls_lse(key_mpls, lse_index); |
---|
282 | 443 | } |
---|
283 | 444 | |
---|
284 | | - if (label == MPLS_LABEL_ENTROPY) { |
---|
| 445 | + if (*entropy_label && |
---|
| 446 | + dissector_uses_key(flow_dissector, |
---|
| 447 | + FLOW_DISSECTOR_KEY_MPLS_ENTROPY)) { |
---|
| 448 | + struct flow_dissector_key_keyid *key_keyid; |
---|
| 449 | + |
---|
285 | 450 | key_keyid = skb_flow_dissector_target(flow_dissector, |
---|
286 | 451 | FLOW_DISSECTOR_KEY_MPLS_ENTROPY, |
---|
287 | 452 | target_container); |
---|
288 | | - key_keyid->keyid = hdr[1].entry & htonl(MPLS_LS_LABEL_MASK); |
---|
| 453 | + key_keyid->keyid = cpu_to_be32(label); |
---|
289 | 454 | } |
---|
290 | | - return FLOW_DISSECT_RET_OUT_GOOD; |
---|
| 455 | + |
---|
| 456 | + *entropy_label = label == MPLS_LABEL_ENTROPY; |
---|
| 457 | + |
---|
| 458 | + return bos ? FLOW_DISSECT_RET_OUT_GOOD : FLOW_DISSECT_RET_PROTO_AGAIN; |
---|
291 | 459 | } |
---|
292 | 460 | |
---|
293 | 461 | static enum flow_dissect_ret |
---|
.. | .. |
---|
382 | 550 | offset += sizeof(struct gre_base_hdr); |
---|
383 | 551 | |
---|
384 | 552 | if (hdr->flags & GRE_CSUM) |
---|
385 | | - offset += sizeof(((struct gre_full_hdr *) 0)->csum) + |
---|
386 | | - sizeof(((struct gre_full_hdr *) 0)->reserved1); |
---|
| 553 | + offset += sizeof_field(struct gre_full_hdr, csum) + |
---|
| 554 | + sizeof_field(struct gre_full_hdr, reserved1); |
---|
387 | 555 | |
---|
388 | 556 | if (hdr->flags & GRE_KEY) { |
---|
389 | 557 | const __be32 *keyid; |
---|
.. | .. |
---|
405 | 573 | else |
---|
406 | 574 | key_keyid->keyid = *keyid & GRE_PPTP_KEY_MASK; |
---|
407 | 575 | } |
---|
408 | | - offset += sizeof(((struct gre_full_hdr *) 0)->key); |
---|
| 576 | + offset += sizeof_field(struct gre_full_hdr, key); |
---|
409 | 577 | } |
---|
410 | 578 | |
---|
411 | 579 | if (hdr->flags & GRE_SEQ) |
---|
412 | | - offset += sizeof(((struct pptp_gre_header *) 0)->seq); |
---|
| 580 | + offset += sizeof_field(struct pptp_gre_header, seq); |
---|
413 | 581 | |
---|
414 | 582 | if (gre_ver == 0) { |
---|
415 | 583 | if (*p_proto == htons(ETH_P_TEB)) { |
---|
.. | .. |
---|
436 | 604 | u8 *ppp_hdr; |
---|
437 | 605 | |
---|
438 | 606 | if (hdr->flags & GRE_ACK) |
---|
439 | | - offset += sizeof(((struct pptp_gre_header *) 0)->ack); |
---|
| 607 | + offset += sizeof_field(struct pptp_gre_header, ack); |
---|
440 | 608 | |
---|
441 | 609 | ppp_hdr = __skb_header_pointer(skb, *p_nhoff + offset, |
---|
442 | 610 | sizeof(_ppp_hdr), |
---|
.. | .. |
---|
543 | 711 | } |
---|
544 | 712 | |
---|
545 | 713 | static void |
---|
| 714 | +__skb_flow_dissect_ports(const struct sk_buff *skb, |
---|
| 715 | + struct flow_dissector *flow_dissector, |
---|
| 716 | + void *target_container, void *data, int nhoff, |
---|
| 717 | + u8 ip_proto, int hlen) |
---|
| 718 | +{ |
---|
| 719 | + enum flow_dissector_key_id dissector_ports = FLOW_DISSECTOR_KEY_MAX; |
---|
| 720 | + struct flow_dissector_key_ports *key_ports; |
---|
| 721 | + |
---|
| 722 | + if (dissector_uses_key(flow_dissector, FLOW_DISSECTOR_KEY_PORTS)) |
---|
| 723 | + dissector_ports = FLOW_DISSECTOR_KEY_PORTS; |
---|
| 724 | + else if (dissector_uses_key(flow_dissector, |
---|
| 725 | + FLOW_DISSECTOR_KEY_PORTS_RANGE)) |
---|
| 726 | + dissector_ports = FLOW_DISSECTOR_KEY_PORTS_RANGE; |
---|
| 727 | + |
---|
| 728 | + if (dissector_ports == FLOW_DISSECTOR_KEY_MAX) |
---|
| 729 | + return; |
---|
| 730 | + |
---|
| 731 | + key_ports = skb_flow_dissector_target(flow_dissector, |
---|
| 732 | + dissector_ports, |
---|
| 733 | + target_container); |
---|
| 734 | + key_ports->ports = __skb_flow_get_ports(skb, nhoff, ip_proto, |
---|
| 735 | + data, hlen); |
---|
| 736 | +} |
---|
| 737 | + |
---|
| 738 | +static void |
---|
546 | 739 | __skb_flow_dissect_ipv4(const struct sk_buff *skb, |
---|
547 | 740 | struct flow_dissector *flow_dissector, |
---|
548 | 741 | void *target_container, void *data, const struct iphdr *iph) |
---|
.. | .. |
---|
588 | 781 | return (*num_hdrs <= MAX_FLOW_DISSECT_HDRS); |
---|
589 | 782 | } |
---|
590 | 783 | |
---|
| 784 | +static void __skb_flow_bpf_to_target(const struct bpf_flow_keys *flow_keys, |
---|
| 785 | + struct flow_dissector *flow_dissector, |
---|
| 786 | + void *target_container) |
---|
| 787 | +{ |
---|
| 788 | + struct flow_dissector_key_ports *key_ports = NULL; |
---|
| 789 | + struct flow_dissector_key_control *key_control; |
---|
| 790 | + struct flow_dissector_key_basic *key_basic; |
---|
| 791 | + struct flow_dissector_key_addrs *key_addrs; |
---|
| 792 | + struct flow_dissector_key_tags *key_tags; |
---|
| 793 | + |
---|
| 794 | + key_control = skb_flow_dissector_target(flow_dissector, |
---|
| 795 | + FLOW_DISSECTOR_KEY_CONTROL, |
---|
| 796 | + target_container); |
---|
| 797 | + key_control->thoff = flow_keys->thoff; |
---|
| 798 | + if (flow_keys->is_frag) |
---|
| 799 | + key_control->flags |= FLOW_DIS_IS_FRAGMENT; |
---|
| 800 | + if (flow_keys->is_first_frag) |
---|
| 801 | + key_control->flags |= FLOW_DIS_FIRST_FRAG; |
---|
| 802 | + if (flow_keys->is_encap) |
---|
| 803 | + key_control->flags |= FLOW_DIS_ENCAPSULATION; |
---|
| 804 | + |
---|
| 805 | + key_basic = skb_flow_dissector_target(flow_dissector, |
---|
| 806 | + FLOW_DISSECTOR_KEY_BASIC, |
---|
| 807 | + target_container); |
---|
| 808 | + key_basic->n_proto = flow_keys->n_proto; |
---|
| 809 | + key_basic->ip_proto = flow_keys->ip_proto; |
---|
| 810 | + |
---|
| 811 | + if (flow_keys->addr_proto == ETH_P_IP && |
---|
| 812 | + dissector_uses_key(flow_dissector, FLOW_DISSECTOR_KEY_IPV4_ADDRS)) { |
---|
| 813 | + key_addrs = skb_flow_dissector_target(flow_dissector, |
---|
| 814 | + FLOW_DISSECTOR_KEY_IPV4_ADDRS, |
---|
| 815 | + target_container); |
---|
| 816 | + key_addrs->v4addrs.src = flow_keys->ipv4_src; |
---|
| 817 | + key_addrs->v4addrs.dst = flow_keys->ipv4_dst; |
---|
| 818 | + key_control->addr_type = FLOW_DISSECTOR_KEY_IPV4_ADDRS; |
---|
| 819 | + } else if (flow_keys->addr_proto == ETH_P_IPV6 && |
---|
| 820 | + dissector_uses_key(flow_dissector, |
---|
| 821 | + FLOW_DISSECTOR_KEY_IPV6_ADDRS)) { |
---|
| 822 | + key_addrs = skb_flow_dissector_target(flow_dissector, |
---|
| 823 | + FLOW_DISSECTOR_KEY_IPV6_ADDRS, |
---|
| 824 | + target_container); |
---|
| 825 | + memcpy(&key_addrs->v6addrs.src, &flow_keys->ipv6_src, |
---|
| 826 | + sizeof(key_addrs->v6addrs.src)); |
---|
| 827 | + memcpy(&key_addrs->v6addrs.dst, &flow_keys->ipv6_dst, |
---|
| 828 | + sizeof(key_addrs->v6addrs.dst)); |
---|
| 829 | + key_control->addr_type = FLOW_DISSECTOR_KEY_IPV6_ADDRS; |
---|
| 830 | + } |
---|
| 831 | + |
---|
| 832 | + if (dissector_uses_key(flow_dissector, FLOW_DISSECTOR_KEY_PORTS)) |
---|
| 833 | + key_ports = skb_flow_dissector_target(flow_dissector, |
---|
| 834 | + FLOW_DISSECTOR_KEY_PORTS, |
---|
| 835 | + target_container); |
---|
| 836 | + else if (dissector_uses_key(flow_dissector, |
---|
| 837 | + FLOW_DISSECTOR_KEY_PORTS_RANGE)) |
---|
| 838 | + key_ports = skb_flow_dissector_target(flow_dissector, |
---|
| 839 | + FLOW_DISSECTOR_KEY_PORTS_RANGE, |
---|
| 840 | + target_container); |
---|
| 841 | + |
---|
| 842 | + if (key_ports) { |
---|
| 843 | + key_ports->src = flow_keys->sport; |
---|
| 844 | + key_ports->dst = flow_keys->dport; |
---|
| 845 | + } |
---|
| 846 | + |
---|
| 847 | + if (dissector_uses_key(flow_dissector, |
---|
| 848 | + FLOW_DISSECTOR_KEY_FLOW_LABEL)) { |
---|
| 849 | + key_tags = skb_flow_dissector_target(flow_dissector, |
---|
| 850 | + FLOW_DISSECTOR_KEY_FLOW_LABEL, |
---|
| 851 | + target_container); |
---|
| 852 | + key_tags->flow_label = ntohl(flow_keys->flow_label); |
---|
| 853 | + } |
---|
| 854 | +} |
---|
| 855 | + |
---|
| 856 | +bool bpf_flow_dissect(struct bpf_prog *prog, struct bpf_flow_dissector *ctx, |
---|
| 857 | + __be16 proto, int nhoff, int hlen, unsigned int flags) |
---|
| 858 | +{ |
---|
| 859 | + struct bpf_flow_keys *flow_keys = ctx->flow_keys; |
---|
| 860 | + u32 result; |
---|
| 861 | + |
---|
| 862 | + /* Pass parameters to the BPF program */ |
---|
| 863 | + memset(flow_keys, 0, sizeof(*flow_keys)); |
---|
| 864 | + flow_keys->n_proto = proto; |
---|
| 865 | + flow_keys->nhoff = nhoff; |
---|
| 866 | + flow_keys->thoff = flow_keys->nhoff; |
---|
| 867 | + |
---|
| 868 | + BUILD_BUG_ON((int)BPF_FLOW_DISSECTOR_F_PARSE_1ST_FRAG != |
---|
| 869 | + (int)FLOW_DISSECTOR_F_PARSE_1ST_FRAG); |
---|
| 870 | + BUILD_BUG_ON((int)BPF_FLOW_DISSECTOR_F_STOP_AT_FLOW_LABEL != |
---|
| 871 | + (int)FLOW_DISSECTOR_F_STOP_AT_FLOW_LABEL); |
---|
| 872 | + BUILD_BUG_ON((int)BPF_FLOW_DISSECTOR_F_STOP_AT_ENCAP != |
---|
| 873 | + (int)FLOW_DISSECTOR_F_STOP_AT_ENCAP); |
---|
| 874 | + flow_keys->flags = flags; |
---|
| 875 | + |
---|
| 876 | + result = bpf_prog_run_pin_on_cpu(prog, ctx); |
---|
| 877 | + |
---|
| 878 | + flow_keys->nhoff = clamp_t(u16, flow_keys->nhoff, nhoff, hlen); |
---|
| 879 | + flow_keys->thoff = clamp_t(u16, flow_keys->thoff, |
---|
| 880 | + flow_keys->nhoff, hlen); |
---|
| 881 | + |
---|
| 882 | + return result == BPF_OK; |
---|
| 883 | +} |
---|
| 884 | + |
---|
591 | 885 | /** |
---|
592 | 886 | * __skb_flow_dissect - extract the flow_keys struct and return it |
---|
| 887 | + * @net: associated network namespace, derived from @skb if NULL |
---|
593 | 888 | * @skb: sk_buff to extract the flow from, can be NULL if the rest are specified |
---|
594 | 889 | * @flow_dissector: list of keys to dissect |
---|
595 | 890 | * @target_container: target structure to put dissected values into |
---|
.. | .. |
---|
597 | 892 | * @proto: protocol for which to get the flow, if @data is NULL use skb->protocol |
---|
598 | 893 | * @nhoff: network header offset, if @data is NULL use skb_network_offset(skb) |
---|
599 | 894 | * @hlen: packet header length, if @data is NULL use skb_headlen(skb) |
---|
| 895 | + * @flags: flags that control the dissection process, e.g. |
---|
| 896 | + * FLOW_DISSECTOR_F_STOP_AT_ENCAP. |
---|
600 | 897 | * |
---|
601 | 898 | * The function will try to retrieve individual keys into target specified |
---|
602 | 899 | * by flow_dissector from either the skbuff or a raw buffer specified by the |
---|
.. | .. |
---|
604 | 901 | * |
---|
605 | 902 | * Caller must take care of zeroing target container memory. |
---|
606 | 903 | */ |
---|
607 | | -bool __skb_flow_dissect(const struct sk_buff *skb, |
---|
| 904 | +bool __skb_flow_dissect(const struct net *net, |
---|
| 905 | + const struct sk_buff *skb, |
---|
608 | 906 | struct flow_dissector *flow_dissector, |
---|
609 | 907 | void *target_container, |
---|
610 | 908 | void *data, __be16 proto, int nhoff, int hlen, |
---|
.. | .. |
---|
613 | 911 | struct flow_dissector_key_control *key_control; |
---|
614 | 912 | struct flow_dissector_key_basic *key_basic; |
---|
615 | 913 | struct flow_dissector_key_addrs *key_addrs; |
---|
616 | | - struct flow_dissector_key_ports *key_ports; |
---|
617 | | - struct flow_dissector_key_icmp *key_icmp; |
---|
618 | 914 | struct flow_dissector_key_tags *key_tags; |
---|
619 | 915 | struct flow_dissector_key_vlan *key_vlan; |
---|
620 | 916 | enum flow_dissect_ret fdret; |
---|
621 | 917 | enum flow_dissector_key_id dissector_vlan = FLOW_DISSECTOR_KEY_MAX; |
---|
| 918 | + bool mpls_el = false; |
---|
| 919 | + int mpls_lse = 0; |
---|
622 | 920 | int num_hdrs = 0; |
---|
623 | 921 | u8 ip_proto = 0; |
---|
624 | 922 | bool ret; |
---|
.. | .. |
---|
636 | 934 | int offset = 0; |
---|
637 | 935 | |
---|
638 | 936 | ops = skb->dev->dsa_ptr->tag_ops; |
---|
639 | | - if (ops->flow_dissect && |
---|
640 | | - !ops->flow_dissect(skb, &proto, &offset)) { |
---|
| 937 | + /* Tail taggers don't break flow dissection */ |
---|
| 938 | + if (!ops->tail_tag) { |
---|
| 939 | + if (ops->flow_dissect) |
---|
| 940 | + ops->flow_dissect(skb, &proto, &offset); |
---|
| 941 | + else |
---|
| 942 | + dsa_tag_generic_flow_dissect(skb, |
---|
| 943 | + &proto, |
---|
| 944 | + &offset); |
---|
641 | 945 | hlen -= offset; |
---|
642 | 946 | nhoff += offset; |
---|
643 | 947 | } |
---|
.. | .. |
---|
658 | 962 | key_basic = skb_flow_dissector_target(flow_dissector, |
---|
659 | 963 | FLOW_DISSECTOR_KEY_BASIC, |
---|
660 | 964 | target_container); |
---|
| 965 | + |
---|
| 966 | + if (skb) { |
---|
| 967 | + if (!net) { |
---|
| 968 | + if (skb->dev) |
---|
| 969 | + net = dev_net(skb->dev); |
---|
| 970 | + else if (skb->sk) |
---|
| 971 | + net = sock_net(skb->sk); |
---|
| 972 | + } |
---|
| 973 | + } |
---|
| 974 | + |
---|
| 975 | + WARN_ON_ONCE(!net); |
---|
| 976 | + if (net) { |
---|
| 977 | + enum netns_bpf_attach_type type = NETNS_BPF_FLOW_DISSECTOR; |
---|
| 978 | + struct bpf_prog_array *run_array; |
---|
| 979 | + |
---|
| 980 | + rcu_read_lock(); |
---|
| 981 | + run_array = rcu_dereference(init_net.bpf.run_array[type]); |
---|
| 982 | + if (!run_array) |
---|
| 983 | + run_array = rcu_dereference(net->bpf.run_array[type]); |
---|
| 984 | + |
---|
| 985 | + if (run_array) { |
---|
| 986 | + struct bpf_flow_keys flow_keys; |
---|
| 987 | + struct bpf_flow_dissector ctx = { |
---|
| 988 | + .flow_keys = &flow_keys, |
---|
| 989 | + .data = data, |
---|
| 990 | + .data_end = data + hlen, |
---|
| 991 | + }; |
---|
| 992 | + __be16 n_proto = proto; |
---|
| 993 | + struct bpf_prog *prog; |
---|
| 994 | + |
---|
| 995 | + if (skb) { |
---|
| 996 | + ctx.skb = skb; |
---|
| 997 | + /* we can't use 'proto' in the skb case |
---|
| 998 | + * because it might be set to skb->vlan_proto |
---|
| 999 | + * which has been pulled from the data |
---|
| 1000 | + */ |
---|
| 1001 | + n_proto = skb->protocol; |
---|
| 1002 | + } |
---|
| 1003 | + |
---|
| 1004 | + prog = READ_ONCE(run_array->items[0].prog); |
---|
| 1005 | + ret = bpf_flow_dissect(prog, &ctx, n_proto, nhoff, |
---|
| 1006 | + hlen, flags); |
---|
| 1007 | + __skb_flow_bpf_to_target(&flow_keys, flow_dissector, |
---|
| 1008 | + target_container); |
---|
| 1009 | + rcu_read_unlock(); |
---|
| 1010 | + return ret; |
---|
| 1011 | + } |
---|
| 1012 | + rcu_read_unlock(); |
---|
| 1013 | + } |
---|
661 | 1014 | |
---|
662 | 1015 | if (dissector_uses_key(flow_dissector, |
---|
663 | 1016 | FLOW_DISSECTOR_KEY_ETH_ADDRS)) { |
---|
.. | .. |
---|
701 | 1054 | key_control->addr_type = FLOW_DISSECTOR_KEY_IPV4_ADDRS; |
---|
702 | 1055 | } |
---|
703 | 1056 | |
---|
| 1057 | + __skb_flow_dissect_ipv4(skb, flow_dissector, |
---|
| 1058 | + target_container, data, iph); |
---|
| 1059 | + |
---|
704 | 1060 | if (ip_is_fragment(iph)) { |
---|
705 | 1061 | key_control->flags |= FLOW_DIS_IS_FRAGMENT; |
---|
706 | 1062 | |
---|
.. | .. |
---|
715 | 1071 | break; |
---|
716 | 1072 | } |
---|
717 | 1073 | } |
---|
718 | | - } |
---|
719 | | - |
---|
720 | | - __skb_flow_dissect_ipv4(skb, flow_dissector, |
---|
721 | | - target_container, data, iph); |
---|
722 | | - |
---|
723 | | - if (flags & FLOW_DISSECTOR_F_STOP_AT_L3) { |
---|
724 | | - fdret = FLOW_DISSECT_RET_OUT_GOOD; |
---|
725 | | - break; |
---|
726 | 1074 | } |
---|
727 | 1075 | |
---|
728 | 1076 | break; |
---|
.. | .. |
---|
775 | 1123 | __skb_flow_dissect_ipv6(skb, flow_dissector, |
---|
776 | 1124 | target_container, data, iph); |
---|
777 | 1125 | |
---|
778 | | - if (flags & FLOW_DISSECTOR_F_STOP_AT_L3) |
---|
779 | | - fdret = FLOW_DISSECT_RET_OUT_GOOD; |
---|
780 | | - |
---|
781 | 1126 | break; |
---|
782 | 1127 | } |
---|
783 | 1128 | case htons(ETH_P_8021AD): |
---|
.. | .. |
---|
817 | 1162 | |
---|
818 | 1163 | if (!vlan) { |
---|
819 | 1164 | key_vlan->vlan_id = skb_vlan_tag_get_id(skb); |
---|
820 | | - key_vlan->vlan_priority = |
---|
821 | | - (skb_vlan_tag_get_prio(skb) >> VLAN_PRIO_SHIFT); |
---|
| 1165 | + key_vlan->vlan_priority = skb_vlan_tag_get_prio(skb); |
---|
822 | 1166 | } else { |
---|
823 | 1167 | key_vlan->vlan_id = ntohs(vlan->h_vlan_TCI) & |
---|
824 | 1168 | VLAN_VID_MASK; |
---|
.. | .. |
---|
827 | 1171 | VLAN_PRIO_MASK) >> VLAN_PRIO_SHIFT; |
---|
828 | 1172 | } |
---|
829 | 1173 | key_vlan->vlan_tpid = saved_vlan_tpid; |
---|
| 1174 | + key_vlan->vlan_eth_type = proto; |
---|
830 | 1175 | } |
---|
831 | 1176 | |
---|
832 | 1177 | fdret = FLOW_DISSECT_RET_PROTO_AGAIN; |
---|
.. | .. |
---|
886 | 1231 | case htons(ETH_P_MPLS_MC): |
---|
887 | 1232 | fdret = __skb_flow_dissect_mpls(skb, flow_dissector, |
---|
888 | 1233 | target_container, data, |
---|
889 | | - nhoff, hlen); |
---|
| 1234 | + nhoff, hlen, mpls_lse, |
---|
| 1235 | + &mpls_el); |
---|
| 1236 | + nhoff += sizeof(struct mpls_label); |
---|
| 1237 | + mpls_lse++; |
---|
890 | 1238 | break; |
---|
891 | 1239 | case htons(ETH_P_FCOE): |
---|
892 | 1240 | if ((hlen - nhoff) < FCOE_HEADER_LEN) { |
---|
.. | .. |
---|
1027 | 1375 | data, nhoff, hlen); |
---|
1028 | 1376 | break; |
---|
1029 | 1377 | |
---|
| 1378 | + case IPPROTO_ICMP: |
---|
| 1379 | + case IPPROTO_ICMPV6: |
---|
| 1380 | + __skb_flow_dissect_icmp(skb, flow_dissector, target_container, |
---|
| 1381 | + data, nhoff, hlen); |
---|
| 1382 | + break; |
---|
| 1383 | + |
---|
1030 | 1384 | default: |
---|
1031 | 1385 | break; |
---|
1032 | 1386 | } |
---|
1033 | 1387 | |
---|
1034 | | - if (dissector_uses_key(flow_dissector, FLOW_DISSECTOR_KEY_PORTS) && |
---|
1035 | | - !(key_control->flags & FLOW_DIS_IS_FRAGMENT)) { |
---|
1036 | | - key_ports = skb_flow_dissector_target(flow_dissector, |
---|
1037 | | - FLOW_DISSECTOR_KEY_PORTS, |
---|
1038 | | - target_container); |
---|
1039 | | - key_ports->ports = __skb_flow_get_ports(skb, nhoff, ip_proto, |
---|
1040 | | - data, hlen); |
---|
1041 | | - } |
---|
1042 | | - |
---|
1043 | | - if (dissector_uses_key(flow_dissector, |
---|
1044 | | - FLOW_DISSECTOR_KEY_ICMP)) { |
---|
1045 | | - key_icmp = skb_flow_dissector_target(flow_dissector, |
---|
1046 | | - FLOW_DISSECTOR_KEY_ICMP, |
---|
1047 | | - target_container); |
---|
1048 | | - key_icmp->icmp = skb_flow_get_be16(skb, nhoff, data, hlen); |
---|
1049 | | - } |
---|
| 1388 | + if (!(key_control->flags & FLOW_DIS_IS_FRAGMENT)) |
---|
| 1389 | + __skb_flow_dissect_ports(skb, flow_dissector, target_container, |
---|
| 1390 | + data, nhoff, ip_proto, hlen); |
---|
1050 | 1391 | |
---|
1051 | 1392 | /* Process result of IP proto processing */ |
---|
1052 | 1393 | switch (fdret) { |
---|
.. | .. |
---|
1097 | 1438 | static inline size_t flow_keys_hash_length(const struct flow_keys *flow) |
---|
1098 | 1439 | { |
---|
1099 | 1440 | size_t diff = FLOW_KEYS_HASH_OFFSET + sizeof(flow->addrs); |
---|
1100 | | - BUILD_BUG_ON(offsetof(typeof(*flow), addrs) != |
---|
1101 | | - sizeof(*flow) - sizeof(flow->addrs)); |
---|
| 1441 | + |
---|
| 1442 | + BUILD_BUG_ON((sizeof(*flow) - FLOW_KEYS_HASH_OFFSET) % sizeof(u32)); |
---|
1102 | 1443 | |
---|
1103 | 1444 | switch (flow->control.addr_type) { |
---|
1104 | 1445 | case FLOW_DISSECTOR_KEY_IPV4_ADDRS: |
---|
.. | .. |
---|
1144 | 1485 | } |
---|
1145 | 1486 | EXPORT_SYMBOL(flow_get_u32_dst); |
---|
1146 | 1487 | |
---|
| 1488 | +/* Sort the source and destination IP and the ports, |
---|
| 1489 | + * to have consistent hash within the two directions |
---|
| 1490 | + */ |
---|
1147 | 1491 | static inline void __flow_hash_consistentify(struct flow_keys *keys) |
---|
1148 | 1492 | { |
---|
1149 | 1493 | int addr_diff, i; |
---|
1150 | 1494 | |
---|
1151 | 1495 | switch (keys->control.addr_type) { |
---|
1152 | 1496 | case FLOW_DISSECTOR_KEY_IPV4_ADDRS: |
---|
1153 | | - addr_diff = (__force u32)keys->addrs.v4addrs.dst - |
---|
1154 | | - (__force u32)keys->addrs.v4addrs.src; |
---|
1155 | | - if ((addr_diff < 0) || |
---|
1156 | | - (addr_diff == 0 && |
---|
1157 | | - ((__force u16)keys->ports.dst < |
---|
1158 | | - (__force u16)keys->ports.src))) { |
---|
| 1497 | + if ((__force u32)keys->addrs.v4addrs.dst < |
---|
| 1498 | + (__force u32)keys->addrs.v4addrs.src) |
---|
1159 | 1499 | swap(keys->addrs.v4addrs.src, keys->addrs.v4addrs.dst); |
---|
| 1500 | + |
---|
| 1501 | + if ((__force u16)keys->ports.dst < |
---|
| 1502 | + (__force u16)keys->ports.src) { |
---|
1160 | 1503 | swap(keys->ports.src, keys->ports.dst); |
---|
1161 | 1504 | } |
---|
1162 | 1505 | break; |
---|
.. | .. |
---|
1164 | 1507 | addr_diff = memcmp(&keys->addrs.v6addrs.dst, |
---|
1165 | 1508 | &keys->addrs.v6addrs.src, |
---|
1166 | 1509 | sizeof(keys->addrs.v6addrs.dst)); |
---|
1167 | | - if ((addr_diff < 0) || |
---|
1168 | | - (addr_diff == 0 && |
---|
1169 | | - ((__force u16)keys->ports.dst < |
---|
1170 | | - (__force u16)keys->ports.src))) { |
---|
| 1510 | + if (addr_diff < 0) { |
---|
1171 | 1511 | for (i = 0; i < 4; i++) |
---|
1172 | 1512 | swap(keys->addrs.v6addrs.src.s6_addr32[i], |
---|
1173 | 1513 | keys->addrs.v6addrs.dst.s6_addr32[i]); |
---|
| 1514 | + } |
---|
| 1515 | + if ((__force u16)keys->ports.dst < |
---|
| 1516 | + (__force u16)keys->ports.src) { |
---|
1174 | 1517 | swap(keys->ports.src, keys->ports.dst); |
---|
1175 | 1518 | } |
---|
1176 | 1519 | break; |
---|
.. | .. |
---|
1245 | 1588 | __flow_hash_secret_init(); |
---|
1246 | 1589 | |
---|
1247 | 1590 | memset(&keys, 0, sizeof(keys)); |
---|
1248 | | - __skb_flow_dissect(skb, &flow_keys_dissector_symmetric, &keys, |
---|
1249 | | - NULL, 0, 0, 0, |
---|
1250 | | - FLOW_DISSECTOR_F_STOP_AT_FLOW_LABEL); |
---|
| 1591 | + __skb_flow_dissect(NULL, skb, &flow_keys_dissector_symmetric, |
---|
| 1592 | + &keys, NULL, 0, 0, 0, 0); |
---|
1251 | 1593 | |
---|
1252 | 1594 | return __flow_hash_from_keys(&keys, &hashrnd); |
---|
1253 | 1595 | } |
---|
.. | .. |
---|
1348 | 1690 | { |
---|
1349 | 1691 | struct flow_keys_basic keys; |
---|
1350 | 1692 | |
---|
1351 | | - if (!skb_flow_dissect_flow_keys_basic(skb, &keys, NULL, 0, 0, 0, 0)) |
---|
| 1693 | + if (!skb_flow_dissect_flow_keys_basic(NULL, skb, &keys, |
---|
| 1694 | + NULL, 0, 0, 0, 0)) |
---|
1352 | 1695 | return 0; |
---|
1353 | 1696 | |
---|
1354 | 1697 | return __skb_get_poff(skb, skb->data, &keys, skb_headlen(skb)); |
---|
.. | .. |
---|
1465 | 1808 | ARRAY_SIZE(flow_keys_basic_dissector_keys)); |
---|
1466 | 1809 | return 0; |
---|
1467 | 1810 | } |
---|
1468 | | - |
---|
1469 | 1811 | core_initcall(init_default_flow_dissectors); |
---|