|
58 | 58 | #include <net/busy_poll.h>
|
59 | 59 | #include <net/tcp.h>
|
60 | 60 | #include <net/xfrm.h>
|
| 61 | +#include <net/udp.h> |
61 | 62 | #include <linux/bpf_trace.h>
|
62 | 63 | #include <net/xdp_sock.h>
|
63 | 64 | #include <linux/inetdevice.h>
|
| 65 | +#include <net/inet_hashtables.h> |
| 66 | +#include <net/inet6_hashtables.h> |
64 | 67 | #include <net/ip_fib.h>
|
65 | 68 | #include <net/flow.h>
|
66 | 69 | #include <net/arp.h>
|
67 | 70 | #include <net/ipv6.h>
|
| 71 | +#include <net/net_namespace.h> |
68 | 72 | #include <linux/seg6_local.h>
|
69 | 73 | #include <net/seg6.h>
|
70 | 74 | #include <net/seg6_local.h>
|
@@ -4813,6 +4817,141 @@ static const struct bpf_func_proto bpf_lwt_seg6_adjust_srh_proto = {
|
4813 | 4817 | };
|
4814 | 4818 | #endif /* CONFIG_IPV6_SEG6_BPF */
|
4815 | 4819 |
|
| 4820 | +struct sock *sk_lookup(struct net *net, struct bpf_sock_tuple *tuple, |
| 4821 | + struct sk_buff *skb, u8 family, u8 proto) |
| 4822 | +{ |
| 4823 | + int dif = skb->dev->ifindex; |
| 4824 | + bool refcounted = false; |
| 4825 | + struct sock *sk = NULL; |
| 4826 | + |
| 4827 | + if (family == AF_INET) { |
| 4828 | + __be32 src4 = tuple->ipv4.saddr; |
| 4829 | + __be32 dst4 = tuple->ipv4.daddr; |
| 4830 | + int sdif = inet_sdif(skb); |
| 4831 | + |
| 4832 | + if (proto == IPPROTO_TCP) |
| 4833 | + sk = __inet_lookup(net, &tcp_hashinfo, skb, 0, |
| 4834 | + src4, tuple->ipv4.sport, |
| 4835 | + dst4, tuple->ipv4.dport, |
| 4836 | + dif, sdif, &refcounted); |
| 4837 | + else |
| 4838 | + sk = __udp4_lib_lookup(net, src4, tuple->ipv4.sport, |
| 4839 | + dst4, tuple->ipv4.dport, |
| 4840 | + dif, sdif, &udp_table, skb); |
| 4841 | +#if IS_ENABLED(CONFIG_IPV6) |
| 4842 | + } else { |
| 4843 | + struct in6_addr *src6 = (struct in6_addr *)&tuple->ipv6.saddr; |
| 4844 | + struct in6_addr *dst6 = (struct in6_addr *)&tuple->ipv6.daddr; |
| 4845 | + int sdif = inet6_sdif(skb); |
| 4846 | + |
| 4847 | + if (proto == IPPROTO_TCP) |
| 4848 | + sk = __inet6_lookup(net, &tcp_hashinfo, skb, 0, |
| 4849 | + src6, tuple->ipv6.sport, |
| 4850 | + dst6, tuple->ipv6.dport, |
| 4851 | + dif, sdif, &refcounted); |
| 4852 | + else |
| 4853 | + sk = __udp6_lib_lookup(net, src6, tuple->ipv6.sport, |
| 4854 | + dst6, tuple->ipv6.dport, |
| 4855 | + dif, sdif, &udp_table, skb); |
| 4856 | +#endif |
| 4857 | + } |
| 4858 | + |
| 4859 | + if (unlikely(sk && !refcounted && !sock_flag(sk, SOCK_RCU_FREE))) { |
| 4860 | + WARN_ONCE(1, "Found non-RCU, unreferenced socket!"); |
| 4861 | + sk = NULL; |
| 4862 | + } |
| 4863 | + return sk; |
| 4864 | +} |
| 4865 | + |
| 4866 | +/* bpf_sk_lookup performs the core lookup for different types of sockets, |
| 4867 | + * taking a reference on the socket if it doesn't have the flag SOCK_RCU_FREE. |
| 4868 | + * Returns the socket as an 'unsigned long' to simplify the casting in the |
| 4869 | + * callers to satisfy BPF_CALL declarations. |
| 4870 | + */ |
| 4871 | +static unsigned long |
| 4872 | +bpf_sk_lookup(struct sk_buff *skb, struct bpf_sock_tuple *tuple, u32 len, |
| 4873 | + u8 proto, u64 netns_id, u64 flags) |
| 4874 | +{ |
| 4875 | + struct net *caller_net; |
| 4876 | + struct sock *sk = NULL; |
| 4877 | + u8 family = AF_UNSPEC; |
| 4878 | + struct net *net; |
| 4879 | + |
| 4880 | + family = len == sizeof(tuple->ipv4) ? AF_INET : AF_INET6; |
| 4881 | + if (unlikely(family == AF_UNSPEC || netns_id > U32_MAX || flags)) |
| 4882 | + goto out; |
| 4883 | + |
| 4884 | + if (skb->dev) |
| 4885 | + caller_net = dev_net(skb->dev); |
| 4886 | + else |
| 4887 | + caller_net = sock_net(skb->sk); |
| 4888 | + if (netns_id) { |
| 4889 | + net = get_net_ns_by_id(caller_net, netns_id); |
| 4890 | + if (unlikely(!net)) |
| 4891 | + goto out; |
| 4892 | + sk = sk_lookup(net, tuple, skb, family, proto); |
| 4893 | + put_net(net); |
| 4894 | + } else { |
| 4895 | + net = caller_net; |
| 4896 | + sk = sk_lookup(net, tuple, skb, family, proto); |
| 4897 | + } |
| 4898 | + |
| 4899 | + if (sk) |
| 4900 | + sk = sk_to_full_sk(sk); |
| 4901 | +out: |
| 4902 | + return (unsigned long) sk; |
| 4903 | +} |
| 4904 | + |
| 4905 | +BPF_CALL_5(bpf_sk_lookup_tcp, struct sk_buff *, skb, |
| 4906 | + struct bpf_sock_tuple *, tuple, u32, len, u64, netns_id, u64, flags) |
| 4907 | +{ |
| 4908 | + return bpf_sk_lookup(skb, tuple, len, IPPROTO_TCP, netns_id, flags); |
| 4909 | +} |
| 4910 | + |
| 4911 | +static const struct bpf_func_proto bpf_sk_lookup_tcp_proto = { |
| 4912 | + .func = bpf_sk_lookup_tcp, |
| 4913 | + .gpl_only = false, |
| 4914 | + .pkt_access = true, |
| 4915 | + .ret_type = RET_PTR_TO_SOCKET_OR_NULL, |
| 4916 | + .arg1_type = ARG_PTR_TO_CTX, |
| 4917 | + .arg2_type = ARG_PTR_TO_MEM, |
| 4918 | + .arg3_type = ARG_CONST_SIZE, |
| 4919 | + .arg4_type = ARG_ANYTHING, |
| 4920 | + .arg5_type = ARG_ANYTHING, |
| 4921 | +}; |
| 4922 | + |
| 4923 | +BPF_CALL_5(bpf_sk_lookup_udp, struct sk_buff *, skb, |
| 4924 | + struct bpf_sock_tuple *, tuple, u32, len, u64, netns_id, u64, flags) |
| 4925 | +{ |
| 4926 | + return bpf_sk_lookup(skb, tuple, len, IPPROTO_UDP, netns_id, flags); |
| 4927 | +} |
| 4928 | + |
| 4929 | +static const struct bpf_func_proto bpf_sk_lookup_udp_proto = { |
| 4930 | + .func = bpf_sk_lookup_udp, |
| 4931 | + .gpl_only = false, |
| 4932 | + .pkt_access = true, |
| 4933 | + .ret_type = RET_PTR_TO_SOCKET_OR_NULL, |
| 4934 | + .arg1_type = ARG_PTR_TO_CTX, |
| 4935 | + .arg2_type = ARG_PTR_TO_MEM, |
| 4936 | + .arg3_type = ARG_CONST_SIZE, |
| 4937 | + .arg4_type = ARG_ANYTHING, |
| 4938 | + .arg5_type = ARG_ANYTHING, |
| 4939 | +}; |
| 4940 | + |
| 4941 | +BPF_CALL_1(bpf_sk_release, struct sock *, sk) |
| 4942 | +{ |
| 4943 | + if (!sock_flag(sk, SOCK_RCU_FREE)) |
| 4944 | + sock_gen_put(sk); |
| 4945 | + return 0; |
| 4946 | +} |
| 4947 | + |
| 4948 | +static const struct bpf_func_proto bpf_sk_release_proto = { |
| 4949 | + .func = bpf_sk_release, |
| 4950 | + .gpl_only = false, |
| 4951 | + .ret_type = RET_INTEGER, |
| 4952 | + .arg1_type = ARG_PTR_TO_SOCKET, |
| 4953 | +}; |
| 4954 | + |
4816 | 4955 | bool bpf_helper_changes_pkt_data(void *func)
|
4817 | 4956 | {
|
4818 | 4957 | if (func == bpf_skb_vlan_push ||
|
@@ -5019,6 +5158,12 @@ tc_cls_act_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog)
|
5019 | 5158 | case BPF_FUNC_skb_ancestor_cgroup_id:
|
5020 | 5159 | return &bpf_skb_ancestor_cgroup_id_proto;
|
5021 | 5160 | #endif
|
| 5161 | + case BPF_FUNC_sk_lookup_tcp: |
| 5162 | + return &bpf_sk_lookup_tcp_proto; |
| 5163 | + case BPF_FUNC_sk_lookup_udp: |
| 5164 | + return &bpf_sk_lookup_udp_proto; |
| 5165 | + case BPF_FUNC_sk_release: |
| 5166 | + return &bpf_sk_release_proto; |
5022 | 5167 | default:
|
5023 | 5168 | return bpf_base_func_proto(func_id);
|
5024 | 5169 | }
|
@@ -5119,6 +5264,12 @@ sk_skb_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog)
|
5119 | 5264 | return &bpf_sk_redirect_hash_proto;
|
5120 | 5265 | case BPF_FUNC_get_local_storage:
|
5121 | 5266 | return &bpf_get_local_storage_proto;
|
| 5267 | + case BPF_FUNC_sk_lookup_tcp: |
| 5268 | + return &bpf_sk_lookup_tcp_proto; |
| 5269 | + case BPF_FUNC_sk_lookup_udp: |
| 5270 | + return &bpf_sk_lookup_udp_proto; |
| 5271 | + case BPF_FUNC_sk_release: |
| 5272 | + return &bpf_sk_release_proto; |
5122 | 5273 | default:
|
5123 | 5274 | return bpf_base_func_proto(func_id);
|
5124 | 5275 | }
|
|
0 commit comments