| .. | .. |
|---|
| 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; |
|---|