void reuseport_update_incoming_cpu(struct sock *sk, int val)
{ struct sock_reuseport *reuse; int old_sk_incoming_cpu;
if (unlikely(!rcu_access_pointer(sk->sk_reuseport_cb))) { /* Paired with REAE_ONCE() in sk_incoming_cpu_update() *andcompute_score().
*/
WRITE_ONCE(sk->sk_incoming_cpu, val); return;
}
spin_lock_bh(&reuseport_lock);
/* This must be done under reuseport_lock to avoid a race with *reuseport_grow(),whichaccessessk->sk_incoming_cpuwithout *lock_sock()whendetachingashutdown()edsk. * *PairedwithREAD_ONCE()inreuseport_select_sock_by_hash().
*/
old_sk_incoming_cpu = sk->sk_incoming_cpu;
WRITE_ONCE(sk->sk_incoming_cpu, val);
int reuseport_alloc(struct sock *sk, bool bind_inany)
{ struct sock_reuseport *reuse; int id, ret = 0;
/* bh lock used since this function call may precede hlist lock in *softirqofreceivepathorsetsockoptfromprocesscontext
*/
spin_lock_bh(&reuseport_lock);
/* Allocation attempts can occur concurrently via the setsockopt path *andthebind/hashpath.Nothingtodowhenwelosetherace.
*/
reuse = rcu_dereference_protected(sk->sk_reuseport_cb,
lockdep_is_held(&reuseport_lock)); if (reuse) { if (reuse->num_closed_socks) { /* sk was shutdown()ed before */
ret = reuseport_resurrect(sk, reuse, NULL, bind_inany); goto out;
}
/* Only set reuse->bind_inany if the bind_inany is true. *Otherwise,itwilloverwritethereuse->bind_inany *whichwassetbythebind/hashpath.
*/ if (bind_inany)
reuse->bind_inany = bind_inany; goto out;
}
reuse = __reuseport_alloc(INIT_SOCKS); if (!reuse) {
ret = -ENOMEM; goto out;
}
id = ida_alloc(&reuseport_ida, GFP_ATOMIC); if (id < 0) {
kfree(reuse);
ret = id; goto out;
}
for (i = 0; i < reuse->max_socks; ++i)
rcu_assign_pointer(reuse->socks[i]->sk_reuseport_cb,
more_reuse);
/* Note: we use kfree_rcu here instead of reuseport_free_rcu so *thatreuseandmore_reusecantemporarilyshareareference *toprog.
*/
kfree_rcu(reuse, rcu); return more_reuse;
}
if (old_reuse)
call_rcu(&old_reuse->rcu, reuseport_free_rcu); return0;
}
EXPORT_SYMBOL(reuseport_add_sock);
staticint reuseport_resurrect(struct sock *sk, struct sock_reuseport *old_reuse, struct sock_reuseport *reuse, bool bind_inany)
{ if (old_reuse == reuse) { /* If sk was in the same reuseport group, just pop sk out of *theclosedsectionandpushskintothelisteningsection.
*/
__reuseport_detach_closed_sock(sk, old_reuse);
__reuseport_add_sock(sk, old_reuse); return0;
}
if (!reuse) { /* In bind()/listen() path, we cannot carry over the eBPF prog *fortheshutdown()edsocket.Insetsockopt()path,weshould *notchangetheeBPFprogoflisteningsocketsbyattachinga *progtotheshutdown()edsocket.Thus,wewillallocateanew *reuseportgroupanddetachskfromtheoldgroup.
*/ int id;
reuse = __reuseport_alloc(INIT_SOCKS); if (!reuse) return -ENOMEM;
id = ida_alloc(&reuseport_ida, GFP_ATOMIC); if (id < 0) {
kfree(reuse); return id;
}
reuse->reuseport_id = id;
reuse->bind_inany = bind_inany;
} else { /* Move sk from the old group to the new one if *-alltheotherlistenersintheoldgroupwereclose()dor *shutdown()ed,andthensk2haslisten()edonthesameport *OR *-sklisten()edwithoutbind()(orwithautobind),was *shutdown()ed,andthenlisten()sonanotherportwhich *sk2listen()son.
*/ if (reuse->num_socks + reuse->num_closed_socks == reuse->max_socks) {
reuse = reuseport_grow(reuse); if (!reuse) return -ENOMEM;
}
}
/* reuseport_grow() has detached a closed sk */ if (!reuse) goto out;
/* Notify the bpf side. The sk may be added to a sockarray *map.Ifso,sockarraylogicwillremoveitfromthemap. * *Otherbpfmaptypesthatworkwithreuseport,likesockmap, *don'tneedanexplicitcallbackfromhere.Theyoverridesk *unhash/closeopstoremovetheskfromthemapbeforewe *gettothispoint.
*/
bpf_sk_reuseport_detach(sk);
rcu_assign_pointer(sk->sk_reuseport_cb, NULL);
if (!__reuseport_detach_closed_sock(sk, reuse))
__reuseport_detach_sock(sk, reuse);
if (reuse->num_socks + reuse->num_closed_socks == 0)
call_rcu(&reuse->rcu, reuseport_free_rcu);
if (skb_shared(skb)) {
nskb = skb_clone(skb, GFP_ATOMIC); if (!nskb) return NULL;
skb = nskb;
}
/* temporarily advance data past protocol header */ if (!pskb_pull(skb, hdr_len)) {
kfree_skb(nskb); return NULL;
}
index = bpf_prog_run_save_cb(prog, skb);
__skb_push(skb, hdr_len);
consume_skb(nskb);
if (index >= socks) return NULL;
return reuse->socks[index];
}
staticstruct sock *reuseport_select_sock_by_hash(struct sock_reuseport *reuse,
u32 hash, u16 num_socks)
{ struct sock *first_valid_sk = NULL; int i, j;
i = j = reciprocal_scale(hash, num_socks); do { struct sock *sk = reuse->socks[i];
if (sk->sk_state != TCP_ESTABLISHED) { /* Paired with WRITE_ONCE() in __reuseport_(get|put)_incoming_cpu(). */ if (!READ_ONCE(reuse->incoming_cpu)) return sk;
/* Paired with WRITE_ONCE() in reuseport_update_incoming_cpu(). */ if (READ_ONCE(sk->sk_incoming_cpu) == raw_smp_processor_id()) return sk;
/* reuse must be checked after acquiring the reuseport_lock *becausereuseport_grow()candetachaclosedsk.
*/ if (!reuse) {
spin_unlock_bh(&reuseport_lock); return sk->sk_reuseport ? -ENOENT : -EINVAL;
}
if (sk_unhashed(sk) && reuse->num_closed_socks) {
spin_unlock_bh(&reuseport_lock); return -ENOENT;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.