.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
---|
1 | 2 | /* |
---|
2 | 3 | * SR-IPv6 implementation |
---|
3 | 4 | * |
---|
4 | 5 | * Authors: |
---|
5 | 6 | * David Lebrun <david.lebrun@uclouvain.be> |
---|
6 | 7 | * eBPF support: Mathieu Xhonneux <m.xhonneux@gmail.com> |
---|
7 | | - * |
---|
8 | | - * |
---|
9 | | - * This program is free software; you can redistribute it and/or |
---|
10 | | - * modify it under the terms of the GNU General Public License |
---|
11 | | - * as published by the Free Software Foundation; either version |
---|
12 | | - * 2 of the License, or (at your option) any later version. |
---|
13 | 8 | */ |
---|
14 | 9 | |
---|
15 | 10 | #include <linux/types.h> |
---|
.. | .. |
---|
87 | 82 | if (!pskb_may_pull(skb, srhoff + len)) |
---|
88 | 83 | return NULL; |
---|
89 | 84 | |
---|
90 | | - if (!seg6_validate_srh(srh, len)) |
---|
| 85 | + /* note that pskb_may_pull may change pointers in header; |
---|
| 86 | + * for this reason it is necessary to reload them when needed. |
---|
| 87 | + */ |
---|
| 88 | + srh = (struct ipv6_sr_hdr *)(skb->data + srhoff); |
---|
| 89 | + |
---|
| 90 | + if (!seg6_validate_srh(srh, len, true)) |
---|
91 | 91 | return NULL; |
---|
92 | 92 | |
---|
93 | 93 | return srh; |
---|
.. | .. |
---|
151 | 151 | *daddr = *addr; |
---|
152 | 152 | } |
---|
153 | 153 | |
---|
154 | | -int seg6_lookup_nexthop(struct sk_buff *skb, struct in6_addr *nhaddr, |
---|
155 | | - u32 tbl_id) |
---|
| 154 | +static int |
---|
| 155 | +seg6_lookup_any_nexthop(struct sk_buff *skb, struct in6_addr *nhaddr, |
---|
| 156 | + u32 tbl_id, bool local_delivery) |
---|
156 | 157 | { |
---|
157 | 158 | struct net *net = dev_net(skb->dev); |
---|
158 | 159 | struct ipv6hdr *hdr = ipv6_hdr(skb); |
---|
.. | .. |
---|
160 | 161 | struct dst_entry *dst = NULL; |
---|
161 | 162 | struct rt6_info *rt; |
---|
162 | 163 | struct flowi6 fl6; |
---|
| 164 | + int dev_flags = 0; |
---|
163 | 165 | |
---|
164 | 166 | fl6.flowi6_iif = skb->dev->ifindex; |
---|
165 | 167 | fl6.daddr = nhaddr ? *nhaddr : hdr->daddr; |
---|
.. | .. |
---|
184 | 186 | dst = &rt->dst; |
---|
185 | 187 | } |
---|
186 | 188 | |
---|
187 | | - if (dst && dst->dev->flags & IFF_LOOPBACK && !dst->error) { |
---|
| 189 | + /* we want to discard traffic destined for local packet processing, |
---|
| 190 | + * if @local_delivery is set to false. |
---|
| 191 | + */ |
---|
| 192 | + if (!local_delivery) |
---|
| 193 | + dev_flags |= IFF_LOOPBACK; |
---|
| 194 | + |
---|
| 195 | + if (dst && (dst->dev->flags & dev_flags) && !dst->error) { |
---|
188 | 196 | dst_release(dst); |
---|
189 | 197 | dst = NULL; |
---|
190 | 198 | } |
---|
.. | .. |
---|
199 | 207 | skb_dst_drop(skb); |
---|
200 | 208 | skb_dst_set(skb, dst); |
---|
201 | 209 | return dst->error; |
---|
| 210 | +} |
---|
| 211 | + |
---|
| 212 | +int seg6_lookup_nexthop(struct sk_buff *skb, |
---|
| 213 | + struct in6_addr *nhaddr, u32 tbl_id) |
---|
| 214 | +{ |
---|
| 215 | + return seg6_lookup_any_nexthop(skb, nhaddr, tbl_id, false); |
---|
202 | 216 | } |
---|
203 | 217 | |
---|
204 | 218 | /* regular endpoint function */ |
---|
.. | .. |
---|
268 | 282 | struct net_device *odev; |
---|
269 | 283 | struct ethhdr *eth; |
---|
270 | 284 | |
---|
271 | | - if (!decap_and_validate(skb, NEXTHDR_NONE)) |
---|
| 285 | + if (!decap_and_validate(skb, IPPROTO_ETHERNET)) |
---|
272 | 286 | goto drop; |
---|
273 | 287 | |
---|
274 | 288 | if (!pskb_may_pull(skb, ETH_HLEN)) |
---|
.. | .. |
---|
343 | 357 | if (!ipv6_addr_any(&slwt->nh6)) |
---|
344 | 358 | nhaddr = &slwt->nh6; |
---|
345 | 359 | |
---|
| 360 | + skb_set_transport_header(skb, sizeof(struct ipv6hdr)); |
---|
| 361 | + |
---|
346 | 362 | seg6_lookup_nexthop(skb, nhaddr, 0); |
---|
347 | 363 | |
---|
348 | 364 | return dst_input(skb); |
---|
.. | .. |
---|
372 | 388 | |
---|
373 | 389 | skb_dst_drop(skb); |
---|
374 | 390 | |
---|
| 391 | + skb_set_transport_header(skb, sizeof(struct iphdr)); |
---|
| 392 | + |
---|
375 | 393 | err = ip_route_input(skb, nhaddr, iph->saddr, 0, skb->dev); |
---|
376 | 394 | if (err) |
---|
377 | 395 | goto drop; |
---|
.. | .. |
---|
392 | 410 | if (!pskb_may_pull(skb, sizeof(struct ipv6hdr))) |
---|
393 | 411 | goto drop; |
---|
394 | 412 | |
---|
395 | | - seg6_lookup_nexthop(skb, NULL, slwt->table); |
---|
| 413 | + skb_set_transport_header(skb, sizeof(struct ipv6hdr)); |
---|
| 414 | + |
---|
| 415 | + seg6_lookup_any_nexthop(skb, NULL, slwt->table, true); |
---|
396 | 416 | |
---|
397 | 417 | return dst_input(skb); |
---|
398 | 418 | |
---|
.. | .. |
---|
415 | 435 | if (err) |
---|
416 | 436 | goto drop; |
---|
417 | 437 | |
---|
418 | | - ipv6_hdr(skb)->payload_len = htons(skb->len - sizeof(struct ipv6hdr)); |
---|
419 | 438 | skb_set_transport_header(skb, sizeof(struct ipv6hdr)); |
---|
420 | 439 | |
---|
421 | 440 | seg6_lookup_nexthop(skb, NULL, 0); |
---|
.. | .. |
---|
447 | 466 | if (err) |
---|
448 | 467 | goto drop; |
---|
449 | 468 | |
---|
450 | | - ipv6_hdr(skb)->payload_len = htons(skb->len - sizeof(struct ipv6hdr)); |
---|
451 | 469 | skb_set_transport_header(skb, sizeof(struct ipv6hdr)); |
---|
452 | 470 | |
---|
453 | 471 | seg6_lookup_nexthop(skb, NULL, 0); |
---|
.. | .. |
---|
475 | 493 | return false; |
---|
476 | 494 | |
---|
477 | 495 | srh->hdrlen = (u8)(srh_state->hdrlen >> 3); |
---|
478 | | - if (!seg6_validate_srh(srh, (srh->hdrlen + 1) << 3)) |
---|
| 496 | + if (!seg6_validate_srh(srh, (srh->hdrlen + 1) << 3, true)) |
---|
479 | 497 | return false; |
---|
480 | 498 | |
---|
481 | 499 | srh_state->valid = true; |
---|
.. | .. |
---|
650 | 668 | if (len < sizeof(*srh) + sizeof(struct in6_addr)) |
---|
651 | 669 | return -EINVAL; |
---|
652 | 670 | |
---|
653 | | - if (!seg6_validate_srh(srh, len)) |
---|
| 671 | + if (!seg6_validate_srh(srh, len, false)) |
---|
654 | 672 | return -EINVAL; |
---|
655 | 673 | |
---|
656 | 674 | slwt->srh = kmemdup(srh, len, GFP_KERNEL); |
---|
.. | .. |
---|
825 | 843 | int ret; |
---|
826 | 844 | u32 fd; |
---|
827 | 845 | |
---|
828 | | - ret = nla_parse_nested(tb, SEG6_LOCAL_BPF_PROG_MAX, |
---|
829 | | - attrs[SEG6_LOCAL_BPF], bpf_prog_policy, NULL); |
---|
| 846 | + ret = nla_parse_nested_deprecated(tb, SEG6_LOCAL_BPF_PROG_MAX, |
---|
| 847 | + attrs[SEG6_LOCAL_BPF], |
---|
| 848 | + bpf_prog_policy, NULL); |
---|
830 | 849 | if (ret < 0) |
---|
831 | 850 | return ret; |
---|
832 | 851 | |
---|
.. | .. |
---|
855 | 874 | if (!slwt->bpf.prog) |
---|
856 | 875 | return 0; |
---|
857 | 876 | |
---|
858 | | - nest = nla_nest_start(skb, SEG6_LOCAL_BPF); |
---|
| 877 | + nest = nla_nest_start_noflag(skb, SEG6_LOCAL_BPF); |
---|
859 | 878 | if (!nest) |
---|
860 | 879 | return -EMSGSIZE; |
---|
861 | 880 | |
---|
.. | .. |
---|
949 | 968 | return 0; |
---|
950 | 969 | } |
---|
951 | 970 | |
---|
952 | | -static int seg6_local_build_state(struct nlattr *nla, unsigned int family, |
---|
953 | | - const void *cfg, struct lwtunnel_state **ts, |
---|
| 971 | +static int seg6_local_build_state(struct net *net, struct nlattr *nla, |
---|
| 972 | + unsigned int family, const void *cfg, |
---|
| 973 | + struct lwtunnel_state **ts, |
---|
954 | 974 | struct netlink_ext_ack *extack) |
---|
955 | 975 | { |
---|
956 | 976 | struct nlattr *tb[SEG6_LOCAL_MAX + 1]; |
---|
.. | .. |
---|
961 | 981 | if (family != AF_INET6) |
---|
962 | 982 | return -EINVAL; |
---|
963 | 983 | |
---|
964 | | - err = nla_parse_nested(tb, SEG6_LOCAL_MAX, nla, seg6_local_policy, |
---|
965 | | - extack); |
---|
| 984 | + err = nla_parse_nested_deprecated(tb, SEG6_LOCAL_MAX, nla, |
---|
| 985 | + seg6_local_policy, extack); |
---|
966 | 986 | |
---|
967 | 987 | if (err < 0) |
---|
968 | 988 | return err; |
---|