diff options
-rw-r--r-- | kernel/bpf/sockmap.c | 58 |
1 files changed, 48 insertions, 10 deletions
diff --git a/kernel/bpf/sockmap.c b/kernel/bpf/sockmap.c index 81d0c55a77aa..bfdfbd199c3b 100644 --- a/kernel/bpf/sockmap.c +++ b/kernel/bpf/sockmap.c | |||
@@ -140,6 +140,7 @@ static int bpf_tcp_recvmsg(struct sock *sk, struct msghdr *msg, size_t len, | |||
140 | static int bpf_tcp_sendmsg(struct sock *sk, struct msghdr *msg, size_t size); | 140 | static int bpf_tcp_sendmsg(struct sock *sk, struct msghdr *msg, size_t size); |
141 | static int bpf_tcp_sendpage(struct sock *sk, struct page *page, | 141 | static int bpf_tcp_sendpage(struct sock *sk, struct page *page, |
142 | int offset, size_t size, int flags); | 142 | int offset, size_t size, int flags); |
143 | static void bpf_tcp_close(struct sock *sk, long timeout); | ||
143 | 144 | ||
144 | static inline struct smap_psock *smap_psock_sk(const struct sock *sk) | 145 | static inline struct smap_psock *smap_psock_sk(const struct sock *sk) |
145 | { | 146 | { |
@@ -161,7 +162,42 @@ out: | |||
161 | return !empty; | 162 | return !empty; |
162 | } | 163 | } |
163 | 164 | ||
164 | static struct proto tcp_bpf_proto; | 165 | enum { |
166 | SOCKMAP_IPV4, | ||
167 | SOCKMAP_IPV6, | ||
168 | SOCKMAP_NUM_PROTS, | ||
169 | }; | ||
170 | |||
171 | enum { | ||
172 | SOCKMAP_BASE, | ||
173 | SOCKMAP_TX, | ||
174 | SOCKMAP_NUM_CONFIGS, | ||
175 | }; | ||
176 | |||
177 | static struct proto *saved_tcpv6_prot __read_mostly; | ||
178 | static DEFINE_SPINLOCK(tcpv6_prot_lock); | ||
179 | static struct proto bpf_tcp_prots[SOCKMAP_NUM_PROTS][SOCKMAP_NUM_CONFIGS]; | ||
180 | static void build_protos(struct proto prot[SOCKMAP_NUM_CONFIGS], | ||
181 | struct proto *base) | ||
182 | { | ||
183 | prot[SOCKMAP_BASE] = *base; | ||
184 | prot[SOCKMAP_BASE].close = bpf_tcp_close; | ||
185 | prot[SOCKMAP_BASE].recvmsg = bpf_tcp_recvmsg; | ||
186 | prot[SOCKMAP_BASE].stream_memory_read = bpf_tcp_stream_read; | ||
187 | |||
188 | prot[SOCKMAP_TX] = prot[SOCKMAP_BASE]; | ||
189 | prot[SOCKMAP_TX].sendmsg = bpf_tcp_sendmsg; | ||
190 | prot[SOCKMAP_TX].sendpage = bpf_tcp_sendpage; | ||
191 | } | ||
192 | |||
193 | static void update_sk_prot(struct sock *sk, struct smap_psock *psock) | ||
194 | { | ||
195 | int family = sk->sk_family == AF_INET6 ? SOCKMAP_IPV6 : SOCKMAP_IPV4; | ||
196 | int conf = psock->bpf_tx_msg ? SOCKMAP_TX : SOCKMAP_BASE; | ||
197 | |||
198 | sk->sk_prot = &bpf_tcp_prots[family][conf]; | ||
199 | } | ||
200 | |||
165 | static int bpf_tcp_init(struct sock *sk) | 201 | static int bpf_tcp_init(struct sock *sk) |
166 | { | 202 | { |
167 | struct smap_psock *psock; | 203 | struct smap_psock *psock; |
@@ -181,14 +217,17 @@ static int bpf_tcp_init(struct sock *sk) | |||
181 | psock->save_close = sk->sk_prot->close; | 217 | psock->save_close = sk->sk_prot->close; |
182 | psock->sk_proto = sk->sk_prot; | 218 | psock->sk_proto = sk->sk_prot; |
183 | 219 | ||
184 | if (psock->bpf_tx_msg) { | 220 | /* Build IPv6 sockmap whenever the address of tcpv6_prot changes */ |
185 | tcp_bpf_proto.sendmsg = bpf_tcp_sendmsg; | 221 | if (sk->sk_family == AF_INET6 && |
186 | tcp_bpf_proto.sendpage = bpf_tcp_sendpage; | 222 | unlikely(sk->sk_prot != smp_load_acquire(&saved_tcpv6_prot))) { |
187 | tcp_bpf_proto.recvmsg = bpf_tcp_recvmsg; | 223 | spin_lock_bh(&tcpv6_prot_lock); |
188 | tcp_bpf_proto.stream_memory_read = bpf_tcp_stream_read; | 224 | if (likely(sk->sk_prot != saved_tcpv6_prot)) { |
225 | build_protos(bpf_tcp_prots[SOCKMAP_IPV6], sk->sk_prot); | ||
226 | smp_store_release(&saved_tcpv6_prot, sk->sk_prot); | ||
227 | } | ||
228 | spin_unlock_bh(&tcpv6_prot_lock); | ||
189 | } | 229 | } |
190 | 230 | update_sk_prot(sk, psock); | |
191 | sk->sk_prot = &tcp_bpf_proto; | ||
192 | rcu_read_unlock(); | 231 | rcu_read_unlock(); |
193 | return 0; | 232 | return 0; |
194 | } | 233 | } |
@@ -1111,8 +1150,7 @@ static void bpf_tcp_msg_add(struct smap_psock *psock, | |||
1111 | 1150 | ||
1112 | static int bpf_tcp_ulp_register(void) | 1151 | static int bpf_tcp_ulp_register(void) |
1113 | { | 1152 | { |
1114 | tcp_bpf_proto = tcp_prot; | 1153 | build_protos(bpf_tcp_prots[SOCKMAP_IPV4], &tcp_prot); |
1115 | tcp_bpf_proto.close = bpf_tcp_close; | ||
1116 | /* Once BPF TX ULP is registered it is never unregistered. It | 1154 | /* Once BPF TX ULP is registered it is never unregistered. It |
1117 | * will be in the ULP list for the lifetime of the system. Doing | 1155 | * will be in the ULP list for the lifetime of the system. Doing |
1118 | * duplicate registers is not a problem. | 1156 | * duplicate registers is not a problem. |