On Fri, Dec 30, 2016 at 18:57 +0100, Mike Belopuhov wrote:
> On Thu, Dec 29, 2016 at 09:30 +0100, Martin Pieuchot wrote:
> > On 29/12/16(Thu) 01:15, Alexander Bluhm wrote:
> > > On Fri, Dec 23, 2016 at 12:09:32AM +0100, Martin Pieuchot wrote:
> > > > On 22/12/16(Thu) 20:45, Mike Belopuhov wrote:
> > > > > I think this is what is required here.  Works here, but YMMV.
> > > > 
> > > > splnet() in a pseudo-driver seems completely wrong, you could get rid of
> > > > it.
> > > 
> > > Yes, but that is another issue.  Can we get the netlock splasserts
> > > fixed first?  This diff looks good to me.
> > 
> > Sure I'm ok with the diff.
> > 
> 
> I agree with Martin and have cooked a diff but couldn't test it yet.
> This is it for the reference.
> 

I got to test the diff and I had to make another adjustment:
vxlan_if_change is setup as a detach hook, however dohooks is
called very early in if_detach before we remove IP addresses
from the interface.  It makes vxlan_config find these IP
addresses just fine and re-add its own detach hook again. This
repeats ad infinitum hogging the machine.  I couldn't think of
anything better than deferring an operation via a task.  Seems
to do the trick.

OK?

diff --git sys/net/if_vxlan.c sys/net/if_vxlan.c
index e9bc1cb8305..082e4ab5814 100644
--- sys/net/if_vxlan.c
+++ sys/net/if_vxlan.c
@@ -71,10 +71,12 @@ struct vxlan_softc {
        in_port_t                sc_dstport;
        u_int                    sc_rdomain;
        int64_t                  sc_vnetid;
        u_int8_t                 sc_ttl;
 
+       struct task              sc_task;
+
        LIST_ENTRY(vxlan_softc)  sc_entry;
 };
 
 void    vxlanattach(int);
 int     vxlanioctl(struct ifnet *, u_long, caddr_t);
@@ -89,10 +91,11 @@ void         vxlan_media_status(struct ifnet *, struct 
ifmediareq *);
 int     vxlan_config(struct ifnet *, struct sockaddr *, struct sockaddr *);
 int     vxlan_output(struct ifnet *, struct mbuf *);
 void    vxlan_addr_change(void *);
 void    vxlan_if_change(void *);
 void    vxlan_link_change(void *);
+void    vxlan_config_defer(void *);
 
 int     vxlan_sockaddr_cmp(struct sockaddr *, struct sockaddr *);
 uint16_t vxlan_sockaddr_port(struct sockaddr *);
 
 struct if_clone        vxlan_cloner =
@@ -166,10 +169,12 @@ vxlan_clone_create(struct if_clone *ifc, int unit)
         */
        ifp->if_mtu = ETHERMTU - sizeof(struct ether_header);
        ifp->if_mtu -= sizeof(struct vxlanudphdr) + sizeof(struct ipovly);
 #endif
 
+       task_set(&sc->sc_task, vxlan_config_defer, sc);
+
        LIST_INSERT_HEAD(&vxlan_tagh[VXLAN_TAGHASH(0)], sc, sc_entry);
        vxlan_enable++;
 
        return (0);
 }
@@ -178,13 +183,13 @@ int
 vxlan_clone_destroy(struct ifnet *ifp)
 {
        struct vxlan_softc      *sc = ifp->if_softc;
        int                      s;
 
-       s = splnet();
+       NET_LOCK(s);
        vxlan_multicast_cleanup(ifp);
-       splx(s);
+       NET_UNLOCK(s);
 
        vxlan_enable--;
        LIST_REMOVE(sc, sc_entry);
 
        ifmedia_delete_instance(&sc->sc_media, IFM_INST_ANY);
@@ -392,11 +397,11 @@ int
 vxlanioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
 {
        struct vxlan_softc      *sc = (struct vxlan_softc *)ifp->if_softc;
        struct ifreq            *ifr = (struct ifreq *)data;
        struct if_laddrreq      *lifr = (struct if_laddrreq *)data;
-       int                      error = 0, s;
+       int                      error = 0;
 
        switch (cmd) {
        case SIOCSIFADDR:
                ifp->if_flags |= IFF_UP;
                /* FALLTHROUGH */
@@ -417,24 +422,20 @@ vxlanioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
        case SIOCSIFMEDIA:
                error = ifmedia_ioctl(ifp, ifr, &sc->sc_media, cmd);
                break;
 
        case SIOCSLIFPHYADDR:
-               s = splnet();
                error = vxlan_config(ifp,
                    (struct sockaddr *)&lifr->addr,
                    (struct sockaddr *)&lifr->dstaddr);
-               splx(s);
                break;
 
        case SIOCDIFPHYADDR:
-               s = splnet();
                vxlan_multicast_cleanup(ifp);
                bzero(&sc->sc_src, sizeof(sc->sc_src));
                bzero(&sc->sc_dst, sizeof(sc->sc_dst));
                sc->sc_dstport = htons(VXLAN_PORT);
-               splx(s);
                break;
 
        case SIOCGLIFPHYADDR:
                if (sc->sc_dst.ss_family == AF_UNSPEC) {
                        error = EADDRNOTAVAIL;
@@ -451,14 +452,12 @@ vxlanioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
                    ifr->ifr_rdomainid > RT_TABLEID_MAX ||
                    !rtable_exists(ifr->ifr_rdomainid)) {
                        error = EINVAL;
                        break;
                }
-               s = splnet();
                sc->sc_rdomain = ifr->ifr_rdomainid;
                (void)vxlan_config(ifp, NULL, NULL);
-               splx(s);
                break;
 
        case SIOCGLIFPHYRTABLE:
                ifr->ifr_rdomainid = sc->sc_rdomain;
                break;
@@ -468,14 +467,12 @@ vxlanioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
                        error = EINVAL;
                        break;
                }
                if (sc->sc_ttl == (u_int8_t)ifr->ifr_ttl)
                        break;
-               s = splnet();
                sc->sc_ttl = (u_int8_t)(ifr->ifr_ttl);
                (void)vxlan_config(ifp, NULL, NULL);
-               splx(s);
                break;
 
        case SIOCGLIFPHYTTL:
                ifr->ifr_ttl = (int)sc->sc_ttl;
                break;
@@ -489,14 +486,12 @@ vxlanioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
                     ifr->ifr_vnetid < VXLAN_VNI_MIN)) {
                        error = EINVAL;
                        break;
                }
 
-               s = splnet();
                sc->sc_vnetid = (int)ifr->ifr_vnetid;
                (void)vxlan_config(ifp, NULL, NULL);
-               splx(s);
                break;
 
        case SIOCGVNETID:
                if ((sc->sc_vnetid != VXLAN_VNI_ANY) &&
                    (sc->sc_vnetid > VXLAN_VNI_MAX ||
@@ -507,14 +502,12 @@ vxlanioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
 
                ifr->ifr_vnetid = sc->sc_vnetid;
                break;
 
        case SIOCDVNETID:
-               s = splnet();
                sc->sc_vnetid = VXLAN_VNI_UNSET;
                (void)vxlan_config(ifp, NULL, NULL);
-               splx(s);
                break;
 
        default:
                error = ether_ioctl(ifp, &sc->sc_ac, cmd, data);
                break;
@@ -923,57 +916,61 @@ vxlan_output(struct ifnet *ifp, struct mbuf *m)
 void
 vxlan_addr_change(void *arg)
 {
        struct vxlan_softc      *sc = arg;
        struct ifnet            *ifp = &sc->sc_ac.ac_if;
-       int                      s, error;
+       int                      error;
 
        /*
         * Reset the configuration after resume or any possible address
         * configuration changes.
         */
-       s = splnet();
        if ((error = vxlan_config(ifp, NULL, NULL))) {
                /*
                 * The source address of the tunnel can temporarily disappear,
                 * after a link state change when running the DHCP client,
                 * so keep it configured.
                 */
        }
-       splx(s);
 }
 
 void
 vxlan_if_change(void *arg)
 {
        struct vxlan_softc      *sc = arg;
-       struct ifnet            *ifp = &sc->sc_ac.ac_if;
-       int                      s, error;
 
        /*
-        * Reset the configuration after the parent interface disappeared.
+        * Defer resetting the configuration after the parent interface
+        * disappeared to give system a chance to update configuration.
         */
-       s = splnet();
-       if ((error = vxlan_config(ifp, NULL, NULL)) != 0) {
-               /* The configured tunnel addresses are invalid, remove them */
-               bzero(&sc->sc_src, sizeof(sc->sc_src));
-               bzero(&sc->sc_dst, sizeof(sc->sc_dst));
-       }
-       splx(s);
+       task_add(systq, &sc->sc_task);
 }
 
 void
 vxlan_link_change(void *arg)
 {
        struct vxlan_softc      *sc = arg;
        struct ifnet            *ifp = &sc->sc_ac.ac_if;
-       int                      s;
 
        /*
         * The machine might have lost its multicast associations after
         * link state changes.  This fixes a problem with VMware after
         * suspend/resume of the host or guest.
         */
-       s = splnet();
        (void)vxlan_config(ifp, NULL, NULL);
-       splx(s);
+}
+
+void
+vxlan_config_defer(void *arg)
+{
+       struct vxlan_softc      *sc = arg;
+       struct ifnet            *ifp = &sc->sc_ac.ac_if;
+       int                      s;
+
+       NET_LOCK(s);
+       if (vxlan_config(ifp, NULL, NULL) != 0) {
+               /* The configured tunnel addresses are invalid, remove them */
+               bzero(&sc->sc_src, sizeof(sc->sc_src));
+               bzero(&sc->sc_dst, sizeof(sc->sc_dst));
+       }
+       NET_UNLOCK(s);
 }

Reply via email to