On Mon, Nov 25, 2019 at 11:40:41AM +0100, Jakub Sitnicki wrote: > On Mon, Nov 25, 2019 at 05:17 AM CET, John Fastabend wrote: > > Alexei Starovoitov wrote: > >> On Sat, Nov 23, 2019 at 12:07:48PM +0100, Jakub Sitnicki wrote: > >> > SOCKMAP now supports storing references to listening sockets. Nothing keeps > >> > us from using it as an array of sockets to select from in SK_REUSEPORT > >> > programs. > >> > > >> > Whitelist the map type with the BPF helper for selecting socket. However, > >> > impose a restriction that the selected socket needs to be a listening TCP > >> > socket or a bound UDP socket (connected or not). > >> > > >> > The only other map type that works with the BPF reuseport helper, > >> > REUSEPORT_SOCKARRAY, has a corresponding check in its update operation > >> > handler. > >> > > >> > Signed-off-by: Jakub Sitnicki <jakub@xxxxxxxxxxxxxx> > >> > --- > > > > [...] > > > >> > diff --git a/net/core/filter.c b/net/core/filter.c > >> > index 49ded4a7588a..e3fb77353248 100644 > >> > --- a/net/core/filter.c > >> > +++ b/net/core/filter.c > >> > @@ -8723,6 +8723,8 @@ BPF_CALL_4(sk_select_reuseport, struct sk_reuseport_kern *, reuse_kern, > >> > selected_sk = map->ops->map_lookup_elem(map, key); > >> > if (!selected_sk) > >> > return -ENOENT; > >> > + if (!sock_flag(selected_sk, SOCK_RCU_FREE)) > >> > + return -EINVAL; If I read it correctly, this is to avoid the following "if (!reuse)" to return -ENOENT, and instead returns -EINVAL for non TCP_LISTEN tcp_sock. It should at least only be done under the "if (!reuse)" then. Checking SOCK_RCU_FREE to imply TCP_LISTEN is not ideal. It is not immediately obvious. Why not directly check TCP_LISTEN? Note that the SOCK_RCU_FREE check at the 'slow-path' reuseport_array_update_check() is because reuseport_array does depend on call_rcu(&sk->sk_rcu,...) to work, e.g. the reuseport_array does not hold the sk_refcnt. > >> > >> hmm. I wonder whether this breaks existing users... > > > > There is already this check in reuseport_array_update_check() > > > > /* > > * sk must be hashed (i.e. listening in the TCP case or binded > > * in the UDP case) and > > * it must also be a SO_REUSEPORT sk (i.e. reuse cannot be NULL). > > * > > * Also, sk will be used in bpf helper that is protected by > > * rcu_read_lock(). > > */ > > if (!sock_flag(nsk, SOCK_RCU_FREE) || !sk_hashed(nsk) || !nsk_reuse) > > return -EINVAL; > > > > So I believe it should not cause any problems with existing users. Perhaps > > we could consolidate the checks a bit or move it into the update paths if we > > wanted. I assume Jakub was just ensuring we don't get here with SOCK_RCU_FREE > > set from any of the new paths now. I'll let him answer though. > > That was exactly my thinking here. > > REUSEPORT_SOCKARRAY can't be populated with sockets that don't have > SOCK_RCU_FREE set. This makes the flag check in sk_select_reuseport BPF > helper redundant for this map type. > > SOCKMAP, OTOH, allows storing established TCP sockets, which don't have > SOCK_RCU_FREE flag and shouldn't be used as reuseport targets. The newly > added check protects us against it. > > I have a couple tests in the last patch for it - > test_sockmap_reuseport_select_{listening,connected}. Admittedly, UDP is > not covered. > > Not sure how we could go about moving the checks to the update path for > SOCKMAP. At update time we don't know if the map will be used with a > reuseport or a sk_{skb,msg} program. or make these checks specific to the sockmap's lookup path. digress a little from this patch, will the upcoming patches/examples show the use case to have both TCP_LISTEN and TCP_ESTABLISHED sk in the same sock_map?