On Thu, 30 Jul 2020 22:43:10 +0300
Vitaliy Makkoveev <[email protected]> wrote:
> On Thu, Jul 30, 2020 at 10:05:13PM +0900, YASUOKA Masahiko wrote:
>> On Thu, 30 Jul 2020 15:34:09 +0300
>> Vitaliy Makkoveev <[email protected]> wrote:
>> > On Thu, Jul 30, 2020 at 09:13:46PM +0900, YASUOKA Masahiko wrote:
>> >> Hi,
>> >>
>> >> sys/net/if_ethersubr.c:
>> >> 372 void
>> >> 373 ether_input(struct ifnet *ifp, struct mbuf *m)
>> >> (snip)
>> >> 519 #if NPPPOE > 0 || defined(PIPEX)
>> >> 520 case ETHERTYPE_PPPOEDISC:
>> >> 521 case ETHERTYPE_PPPOE:
>> >> 522 if (m->m_flags & (M_MCAST | M_BCAST))
>> >> 523 goto dropanyway;
>> >> 524 #ifdef PIPEX
>> >> 525 if (pipex_enable) {
>> >> 526 struct pipex_session *session;
>> >> 527
>> >> 528 if ((session = pipex_pppoe_lookup_session(m))
>> >> != NULL) {
>> >> 529 pipex_pppoe_input(m, session);
>> >> 530 return;
>> >> 531 }
>> >> 532 }
>> >> 533 #endif
>> >>
>> >> previously a packet which branchces to #529 is enqueued.
>> >>
>> >> If the diff removes the queue, then the pipex input routine is
>> >> executed by the NIC's interrupt handler.
>> >>
>> >> The queues had been made to avoid that kind of situations.
>> >
>> > It's not enqueued in pppoe case. According pipex_pppoe_input() code we
>> > call pipex_common_input() with `useq' argument set to '0', so we don't
>> > enqueue mbuf(9) but pass it to pipex_ppp_input() which will pass it to
>> > ipv{4,6}_input().
>>
>> You are right. Sorry, I forgot about this which I did that by myself.
>>
>
> I'm interesting the reason why you did that.
>
>> >> Also I don't see a relation of the use-after-free problem and killing
>> >> queues. Can't we fix the problem unless we kill the queues?
>> >
>> > Yes we can. Reference counters allow us to keep orphan sessions in these
>> > queues without use after free issue.
>> >
>> > I will wait your commentaries current enqueuing before to do something.
>>
>> I have another concern.
>>
>> You might know, when L2TP/IPsec is used heavily, the crypto thread
>> uses 100% of 1 CPU core. In that case, that thread becomes like
>> below:
>>
>> crypto thread -> udp_userreq -> pipex_l2tp_input
>>
>> some clients are using MPPE(RC4 encryption) on CCP. It's not so
>> light.
>>
>> How do we offload this for CPUs? I am thinking that "pipex" can have
>> a dedicated thread. Do we have another scenario?
>>
>
> I suppose you mean udp_input(). What is you call "crypto thread"? I did
> a little backtrace but I didn't find this thread.
>
> ether_resolve
> if_input_local
> ipv4_input
> ip_input_if
> ip_ours
> ip_deliver
> udp_input (through pr_input)
> pipex_l2tp_input
>
> ipi{,6}_mloopback
> if_input_local
> ipv4_input
> ...
> udp_input (through pr_input)
> pipex_l2tp_input
>
> loinput
> if_input_local
> ipv4_input
> ...
> udp_input (through pr_input)
> pipex_l2tp_input
>
> Also various pseudo drivers call ipv{4,6}_input() and underlay
> udp_unput() too.
>
> Except nfs, we call udp_usrreq() through socket layer only. Do you mean
> userland as "crypto thread"?
Sorry, udp_usrreq() should be usr_input() and crypto thread meant a
kthread for crypto_taskq_mp_safe, whose name is "crynlk" (see
crypto_init()).
A packet of L2TP/IPsec (encapsulated IP/PPP/L2TP/UDP/ESP/UDP/IP) is
processed like:
ipv4_input
...
udp_input
ipsec_common_input
esp_input
crypto_dispatch
=> crypto_taskq_mp_safe
kthread "crynlk"
crypto_invoke
... (*1)
crypto_done
esp_input_cb
ipsec_common_input_cb
ip_deliver
udp_input
pipex_l2tp_input
pipex_common_input
(*2)
pipex_ppp_input
pipex_mppe_input (*3)
pipex_ppp_input
pipex_ip_input
ipv4_input
...
At *2 there was a queue. "crynlk" is a busy thread, since it is doing
decryption at *1. I think it's better pipex input is be done by
another thread than crypto since it also has decryption at *3.
> But upd_input(), udp_usrreq() and pipexintr() are serialized by
> NET_LOCK(). We should move pipex(4) under it's own rwlock to allow them
> simultaneous execution. Also, should we move outgoing pppx(4) mbufs to
> queue too?
pppx has a dedicated queue for each pppx interface. I think that is a
reason why it skips pipexoutq.
Also I noticed there is a generic queue for IP.
pipex_ppp_output
pipex_l2tp_output
ipsend()
=> net_tq
For PPPoE,
pipex_ppp_output
pipex_pppoe_output
ipsend()
=> ifp->if_output
Currently it seems there is enough queues for output side.
--yasuoka