diff options
-rw-r--r-- | include/net/tcp.h | 1 | ||||
-rw-r--r-- | kernel/bpf/sockmap.c | 39 | ||||
-rw-r--r-- | net/ipv4/tcp_ulp.c | 71 |
3 files changed, 23 insertions, 88 deletions
diff --git a/include/net/tcp.h b/include/net/tcp.h index 0d2929223c70..8f5cef67fd35 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h | |||
@@ -2057,7 +2057,6 @@ struct tcp_ulp_ops { | |||
2057 | int tcp_register_ulp(struct tcp_ulp_ops *type); | 2057 | int tcp_register_ulp(struct tcp_ulp_ops *type); |
2058 | void tcp_unregister_ulp(struct tcp_ulp_ops *type); | 2058 | void tcp_unregister_ulp(struct tcp_ulp_ops *type); |
2059 | int tcp_set_ulp(struct sock *sk, const char *name); | 2059 | int tcp_set_ulp(struct sock *sk, const char *name); |
2060 | int tcp_set_ulp_id(struct sock *sk, const int ulp); | ||
2061 | void tcp_get_available_ulp(char *buf, size_t len); | 2060 | void tcp_get_available_ulp(char *buf, size_t len); |
2062 | void tcp_cleanup_ulp(struct sock *sk); | 2061 | void tcp_cleanup_ulp(struct sock *sk); |
2063 | 2062 | ||
diff --git a/kernel/bpf/sockmap.c b/kernel/bpf/sockmap.c index 5d0677d808ae..de6f7a65c72b 100644 --- a/kernel/bpf/sockmap.c +++ b/kernel/bpf/sockmap.c | |||
@@ -182,6 +182,7 @@ enum { | |||
182 | static struct proto *saved_tcpv6_prot __read_mostly; | 182 | static struct proto *saved_tcpv6_prot __read_mostly; |
183 | static DEFINE_SPINLOCK(tcpv6_prot_lock); | 183 | static DEFINE_SPINLOCK(tcpv6_prot_lock); |
184 | static struct proto bpf_tcp_prots[SOCKMAP_NUM_PROTS][SOCKMAP_NUM_CONFIGS]; | 184 | static struct proto bpf_tcp_prots[SOCKMAP_NUM_PROTS][SOCKMAP_NUM_CONFIGS]; |
185 | |||
185 | static void build_protos(struct proto prot[SOCKMAP_NUM_CONFIGS], | 186 | static void build_protos(struct proto prot[SOCKMAP_NUM_CONFIGS], |
186 | struct proto *base) | 187 | struct proto *base) |
187 | { | 188 | { |
@@ -239,6 +240,13 @@ static int bpf_tcp_init(struct sock *sk) | |||
239 | return 0; | 240 | return 0; |
240 | } | 241 | } |
241 | 242 | ||
243 | static int __init bpf_sock_init(void) | ||
244 | { | ||
245 | build_protos(bpf_tcp_prots[SOCKMAP_IPV4], &tcp_prot); | ||
246 | return 0; | ||
247 | } | ||
248 | core_initcall(bpf_sock_init); | ||
249 | |||
242 | static void smap_release_sock(struct smap_psock *psock, struct sock *sock); | 250 | static void smap_release_sock(struct smap_psock *psock, struct sock *sock); |
243 | static int free_start_sg(struct sock *sk, struct sk_msg_buff *md, bool charge); | 251 | static int free_start_sg(struct sock *sk, struct sk_msg_buff *md, bool charge); |
244 | 252 | ||
@@ -413,15 +421,6 @@ enum __sk_action { | |||
413 | __SK_NONE, | 421 | __SK_NONE, |
414 | }; | 422 | }; |
415 | 423 | ||
416 | static struct tcp_ulp_ops bpf_tcp_ulp_ops __read_mostly = { | ||
417 | .name = "bpf_tcp", | ||
418 | .uid = TCP_ULP_BPF, | ||
419 | .user_visible = false, | ||
420 | .owner = NULL, | ||
421 | .init = bpf_tcp_init, | ||
422 | .release = bpf_tcp_release, | ||
423 | }; | ||
424 | |||
425 | static int memcopy_from_iter(struct sock *sk, | 424 | static int memcopy_from_iter(struct sock *sk, |
426 | struct sk_msg_buff *md, | 425 | struct sk_msg_buff *md, |
427 | struct iov_iter *from, int bytes) | 426 | struct iov_iter *from, int bytes) |
@@ -1236,16 +1235,6 @@ static void bpf_tcp_msg_add(struct smap_psock *psock, | |||
1236 | bpf_prog_put(orig_tx_msg); | 1235 | bpf_prog_put(orig_tx_msg); |
1237 | } | 1236 | } |
1238 | 1237 | ||
1239 | static int bpf_tcp_ulp_register(void) | ||
1240 | { | ||
1241 | build_protos(bpf_tcp_prots[SOCKMAP_IPV4], &tcp_prot); | ||
1242 | /* Once BPF TX ULP is registered it is never unregistered. It | ||
1243 | * will be in the ULP list for the lifetime of the system. Doing | ||
1244 | * duplicate registers is not a problem. | ||
1245 | */ | ||
1246 | return tcp_register_ulp(&bpf_tcp_ulp_ops); | ||
1247 | } | ||
1248 | |||
1249 | static int smap_verdict_func(struct smap_psock *psock, struct sk_buff *skb) | 1238 | static int smap_verdict_func(struct smap_psock *psock, struct sk_buff *skb) |
1250 | { | 1239 | { |
1251 | struct bpf_prog *prog = READ_ONCE(psock->bpf_verdict); | 1240 | struct bpf_prog *prog = READ_ONCE(psock->bpf_verdict); |
@@ -1491,7 +1480,7 @@ static void smap_release_sock(struct smap_psock *psock, struct sock *sock) | |||
1491 | { | 1480 | { |
1492 | if (refcount_dec_and_test(&psock->refcnt)) { | 1481 | if (refcount_dec_and_test(&psock->refcnt)) { |
1493 | if (psock_is_smap_sk(sock)) | 1482 | if (psock_is_smap_sk(sock)) |
1494 | tcp_cleanup_ulp(sock); | 1483 | bpf_tcp_release(sock); |
1495 | write_lock_bh(&sock->sk_callback_lock); | 1484 | write_lock_bh(&sock->sk_callback_lock); |
1496 | smap_stop_sock(psock, sock); | 1485 | smap_stop_sock(psock, sock); |
1497 | write_unlock_bh(&sock->sk_callback_lock); | 1486 | write_unlock_bh(&sock->sk_callback_lock); |
@@ -1666,10 +1655,6 @@ static struct bpf_map *sock_map_alloc(union bpf_attr *attr) | |||
1666 | attr->value_size != 4 || attr->map_flags & ~SOCK_CREATE_FLAG_MASK) | 1655 | attr->value_size != 4 || attr->map_flags & ~SOCK_CREATE_FLAG_MASK) |
1667 | return ERR_PTR(-EINVAL); | 1656 | return ERR_PTR(-EINVAL); |
1668 | 1657 | ||
1669 | err = bpf_tcp_ulp_register(); | ||
1670 | if (err && err != -EEXIST) | ||
1671 | return ERR_PTR(err); | ||
1672 | |||
1673 | stab = kzalloc(sizeof(*stab), GFP_USER); | 1658 | stab = kzalloc(sizeof(*stab), GFP_USER); |
1674 | if (!stab) | 1659 | if (!stab) |
1675 | return ERR_PTR(-ENOMEM); | 1660 | return ERR_PTR(-ENOMEM); |
@@ -1951,7 +1936,7 @@ static int __sock_map_ctx_update_elem(struct bpf_map *map, | |||
1951 | if (tx_msg) | 1936 | if (tx_msg) |
1952 | bpf_tcp_msg_add(psock, sock, tx_msg); | 1937 | bpf_tcp_msg_add(psock, sock, tx_msg); |
1953 | if (new) { | 1938 | if (new) { |
1954 | err = tcp_set_ulp_id(sock, TCP_ULP_BPF); | 1939 | err = bpf_tcp_init(sock); |
1955 | if (err) | 1940 | if (err) |
1956 | goto out_free; | 1941 | goto out_free; |
1957 | } | 1942 | } |
@@ -2187,10 +2172,6 @@ static struct bpf_map *sock_hash_alloc(union bpf_attr *attr) | |||
2187 | */ | 2172 | */ |
2188 | return ERR_PTR(-E2BIG); | 2173 | return ERR_PTR(-E2BIG); |
2189 | 2174 | ||
2190 | err = bpf_tcp_ulp_register(); | ||
2191 | if (err && err != -EEXIST) | ||
2192 | return ERR_PTR(err); | ||
2193 | |||
2194 | htab = kzalloc(sizeof(*htab), GFP_USER); | 2175 | htab = kzalloc(sizeof(*htab), GFP_USER); |
2195 | if (!htab) | 2176 | if (!htab) |
2196 | return ERR_PTR(-ENOMEM); | 2177 | return ERR_PTR(-ENOMEM); |
diff --git a/net/ipv4/tcp_ulp.c b/net/ipv4/tcp_ulp.c index 34e96353f115..a9162aa11af9 100644 --- a/net/ipv4/tcp_ulp.c +++ b/net/ipv4/tcp_ulp.c | |||
@@ -6,7 +6,7 @@ | |||
6 | * | 6 | * |
7 | */ | 7 | */ |
8 | 8 | ||
9 | #include<linux/module.h> | 9 | #include <linux/module.h> |
10 | #include <linux/mm.h> | 10 | #include <linux/mm.h> |
11 | #include <linux/types.h> | 11 | #include <linux/types.h> |
12 | #include <linux/list.h> | 12 | #include <linux/list.h> |
@@ -29,18 +29,6 @@ static struct tcp_ulp_ops *tcp_ulp_find(const char *name) | |||
29 | return NULL; | 29 | return NULL; |
30 | } | 30 | } |
31 | 31 | ||
32 | static struct tcp_ulp_ops *tcp_ulp_find_id(const int ulp) | ||
33 | { | ||
34 | struct tcp_ulp_ops *e; | ||
35 | |||
36 | list_for_each_entry_rcu(e, &tcp_ulp_list, list) { | ||
37 | if (e->uid == ulp) | ||
38 | return e; | ||
39 | } | ||
40 | |||
41 | return NULL; | ||
42 | } | ||
43 | |||
44 | static const struct tcp_ulp_ops *__tcp_ulp_find_autoload(const char *name) | 32 | static const struct tcp_ulp_ops *__tcp_ulp_find_autoload(const char *name) |
45 | { | 33 | { |
46 | const struct tcp_ulp_ops *ulp = NULL; | 34 | const struct tcp_ulp_ops *ulp = NULL; |
@@ -63,18 +51,6 @@ static const struct tcp_ulp_ops *__tcp_ulp_find_autoload(const char *name) | |||
63 | return ulp; | 51 | return ulp; |
64 | } | 52 | } |
65 | 53 | ||
66 | static const struct tcp_ulp_ops *__tcp_ulp_lookup(const int uid) | ||
67 | { | ||
68 | const struct tcp_ulp_ops *ulp; | ||
69 | |||
70 | rcu_read_lock(); | ||
71 | ulp = tcp_ulp_find_id(uid); | ||
72 | if (!ulp || !try_module_get(ulp->owner)) | ||
73 | ulp = NULL; | ||
74 | rcu_read_unlock(); | ||
75 | return ulp; | ||
76 | } | ||
77 | |||
78 | /* Attach new upper layer protocol to the list | 54 | /* Attach new upper layer protocol to the list |
79 | * of available protocols. | 55 | * of available protocols. |
80 | */ | 56 | */ |
@@ -135,56 +111,35 @@ void tcp_cleanup_ulp(struct sock *sk) | |||
135 | icsk->icsk_ulp_ops = NULL; | 111 | icsk->icsk_ulp_ops = NULL; |
136 | } | 112 | } |
137 | 113 | ||
138 | /* Change upper layer protocol for socket */ | 114 | static int __tcp_set_ulp(struct sock *sk, const struct tcp_ulp_ops *ulp_ops) |
139 | int tcp_set_ulp(struct sock *sk, const char *name) | ||
140 | { | 115 | { |
141 | struct inet_connection_sock *icsk = inet_csk(sk); | 116 | struct inet_connection_sock *icsk = inet_csk(sk); |
142 | const struct tcp_ulp_ops *ulp_ops; | 117 | int err; |
143 | int err = 0; | ||
144 | 118 | ||
145 | sock_owned_by_me(sk); | 119 | err = -EEXIST; |
146 | if (icsk->icsk_ulp_ops) | 120 | if (icsk->icsk_ulp_ops) |
147 | return -EEXIST; | 121 | goto out_err; |
148 | |||
149 | ulp_ops = __tcp_ulp_find_autoload(name); | ||
150 | if (!ulp_ops) | ||
151 | return -ENOENT; | ||
152 | |||
153 | if (!ulp_ops->user_visible) { | ||
154 | module_put(ulp_ops->owner); | ||
155 | return -ENOENT; | ||
156 | } | ||
157 | 122 | ||
158 | err = ulp_ops->init(sk); | 123 | err = ulp_ops->init(sk); |
159 | if (err) { | 124 | if (err) |
160 | module_put(ulp_ops->owner); | 125 | goto out_err; |
161 | return err; | ||
162 | } | ||
163 | 126 | ||
164 | icsk->icsk_ulp_ops = ulp_ops; | 127 | icsk->icsk_ulp_ops = ulp_ops; |
165 | return 0; | 128 | return 0; |
129 | out_err: | ||
130 | module_put(ulp_ops->owner); | ||
131 | return err; | ||
166 | } | 132 | } |
167 | 133 | ||
168 | int tcp_set_ulp_id(struct sock *sk, int ulp) | 134 | int tcp_set_ulp(struct sock *sk, const char *name) |
169 | { | 135 | { |
170 | struct inet_connection_sock *icsk = inet_csk(sk); | ||
171 | const struct tcp_ulp_ops *ulp_ops; | 136 | const struct tcp_ulp_ops *ulp_ops; |
172 | int err; | ||
173 | 137 | ||
174 | sock_owned_by_me(sk); | 138 | sock_owned_by_me(sk); |
175 | if (icsk->icsk_ulp_ops) | ||
176 | return -EEXIST; | ||
177 | 139 | ||
178 | ulp_ops = __tcp_ulp_lookup(ulp); | 140 | ulp_ops = __tcp_ulp_find_autoload(name); |
179 | if (!ulp_ops) | 141 | if (!ulp_ops) |
180 | return -ENOENT; | 142 | return -ENOENT; |
181 | 143 | ||
182 | err = ulp_ops->init(sk); | 144 | return __tcp_set_ulp(sk, ulp_ops); |
183 | if (err) { | ||
184 | module_put(ulp_ops->owner); | ||
185 | return err; | ||
186 | } | ||
187 | |||
188 | icsk->icsk_ulp_ops = ulp_ops; | ||
189 | return 0; | ||
190 | } | 145 | } |