On Thu, Jun 30, 2022 at 11:56:55AM +0200, Claudio Jeker wrote:
> On Thu, Jun 30, 2022 at 12:34:33PM +0300, Vitaliy Makkoveev wrote:
> > On Thu, Jun 30, 2022 at 11:08:48AM +0200, Claudio Jeker wrote:
> > > This diff converts the SRP list to a SMR list in rtsock.c
> > > SRP is a bit strange with how it works and the SMR code is a bit easier to
> > > understand. Since we can sleep in the SMR_TAILQ_FOREACH() we need to grab
> > > a refcount on the route pcb so that we can leave the SMR critical section
> > > and then enter the SMR critical section at the end of the loop before
> > > dropping the refcount again.
> > > 
> > > The diff does not immeditaly explode but I doubt we can exploit
> > > parallelism in route_input() so this may fail at some later stage if it is
> > > wrong.
> > > 
> > > Comments from the lock critics welcome
> > 
> > We use `so_lock' rwlock(9) to protect route domain sockets. We can't
> > convert this SRP list to SMR list because we call solock() within
> > foreach loop.
> 
> because of the so_lock the code uses a refcnt on the route pcb to make
> sure that the object is not freed while we sleep. So that is handled by
> this diff.
>  
> > We can easily crash kernel by running in parallel some "route monitor"
> > commands and "while true; ifconfig vether0 create ; ifconfig vether0
> > destroy; done".
> 
> That does not cause problem on my system.
>  

Sorry, I missed you leave SMR section before solock() call:

> > > @@ -519,7 +498,8 @@ route_input(struct mbuf *m0, struct sock
> > >               rop->rop_proto != sa_family)
> > >                   continue;
> > >  
> > > -
> > > +         refcnt_take(&rop->rop_refcnt);
> > > +         smr_read_leave();
> > >           so = rop->rop_socket;
> > >           solock(so);
> > >  

My system is stable with the second version of this diff and the
following test.

#include <sys/ioctl.h>
#include <sys/select.h>
#include <sys/socket.h>
#include <net/if.h>
#include <stdio.h>
#include <stdlib.h>
#include <err.h>
#include <errno.h>
#include <pthread.h>
#include <string.h>
#include <unistd.h>

static struct ifreq ifr;

static void *clone(void *arg)
{
        int s;

        if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
                err(1, "socket");
        while (1) {
                if (ioctl(s, SIOCIFCREATE, &ifr) < 0)
                        if (errno == EINVAL)
                                err(1, "ioctl");
                if(ioctl(s, SIOCIFDESTROY, &ifr)<0)
                        if(errno == EINVAL)
                                err(1, "ioctl");
        }

        return NULL;
}

static void *rtsock(void *arg)
{
        int s;

        while (1){
                if ((s = socket(AF_ROUTE, SOCK_RAW, 0)) < 0)
                        err(1, "socket");
                close(s);
        }

        return NULL;
}

int main(int argc, char *argv[])
{
        pthread_t thr;
        int i;

        if( argc != 2) {
                fprintf(stderr, "usage: %s ifname\n", getprogname());
                return 1;
        }

        if (getuid() != 0) {
                fprintf(stderr, "should be root\n");
                return 1;
        }

        memset(&ifr, 0, sizeof(ifr));
        strlcpy(ifr.ifr_name, argv[1], sizeof(ifr.ifr_name));

        for(i = 0; i < 8 * 4; ++i) {
                if (pthread_create(&thr, NULL, clone, NULL)!=0)
                        errx(1, "pthread_create");
        }

        for (i = 0; i < 8 * 4; ++i) {
                if (pthread_create(&thr, NULL, rtsock, NULL) != 0)
                        errx(1, "pthread_create");
        }

        select(0, NULL, NULL, NULL, NULL);

        return 0;
}

Reply via email to