diff options
author | Reyk Floeter <reyk@cvs.openbsd.org> | 2013-10-19 18:22:38 +0000 |
---|---|---|
committer | Reyk Floeter <reyk@cvs.openbsd.org> | 2013-10-19 18:22:38 +0000 |
commit | 4627a77ff9dc7948a60f3492ef392d87a12c8ce5 (patch) | |
tree | 1f3dbe36c954f85e75e68d1e8e86dc2db68b2244 /sys/net/if_vxlan.c | |
parent | b644a1f743b064f39b07db2e068a72fa1317e622 (diff) |
Improve the address and linkstate hooks and add an additional detach
hook to track any changes of the parent multicast interface.
Diffstat (limited to 'sys/net/if_vxlan.c')
-rw-r--r-- | sys/net/if_vxlan.c | 95 |
1 files changed, 62 insertions, 33 deletions
diff --git a/sys/net/if_vxlan.c b/sys/net/if_vxlan.c index 343ec9fedaf..de555f10572 100644 --- a/sys/net/if_vxlan.c +++ b/sys/net/if_vxlan.c @@ -1,4 +1,4 @@ -/* $OpenBSD: if_vxlan.c,v 1.8 2013/10/19 14:46:31 mpi Exp $ */ +/* $OpenBSD: if_vxlan.c,v 1.9 2013/10/19 18:22:37 reyk Exp $ */ /* * Copyright (c) 2013 Reyk Floeter <reyk@openbsd.org> @@ -64,13 +64,14 @@ void vxlanstart(struct ifnet *); int vxlan_clone_create(struct if_clone *, int); int vxlan_clone_destroy(struct ifnet *); void vxlan_multicast_cleanup(struct ifnet *); -int vxlan_join_multicast(struct ifnet *, struct sockaddr_in *, +int vxlan_multicast_join(struct ifnet *, struct sockaddr_in *, struct sockaddr_in *); int vxlan_media_change(struct ifnet *); 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 *); struct if_clone vxlan_cloner = @@ -180,13 +181,21 @@ vxlan_multicast_cleanup(struct ifnet *ifp) struct ip_moptions *imo = &sc->sc_imo; struct ifnet *mifp = imo->imo_multicast_ifp; - if (mifp != NULL && sc->sc_ahcookie != NULL) { - hook_disestablish(mifp->if_addrhooks, sc->sc_ahcookie); - sc->sc_ahcookie = NULL; - } - if (mifp != NULL && sc->sc_lhcookie != NULL) { - hook_disestablish(mifp->if_linkstatehooks, sc->sc_lhcookie); - sc->sc_lhcookie = NULL; + if (mifp != NULL) { + if (sc->sc_ahcookie != NULL) { + hook_disestablish(mifp->if_addrhooks, sc->sc_ahcookie); + sc->sc_ahcookie = NULL; + } + if (sc->sc_lhcookie != NULL) { + hook_disestablish(mifp->if_linkstatehooks, + sc->sc_lhcookie); + sc->sc_lhcookie = NULL; + } + if (sc->sc_dhcookie != NULL) { + hook_disestablish(mifp->if_detachhooks, + sc->sc_dhcookie); + sc->sc_dhcookie = NULL; + } } if (imo->imo_num_memberships > 0) { @@ -196,12 +205,13 @@ vxlan_multicast_cleanup(struct ifnet *ifp) } int -vxlan_join_multicast(struct ifnet *ifp, struct sockaddr_in *src, +vxlan_multicast_join(struct ifnet *ifp, struct sockaddr_in *src, struct sockaddr_in *dst) { struct vxlan_softc *sc = ifp->if_softc; struct ip_moptions *imo = &sc->sc_imo; struct ifaddr *ifa; + struct ifnet *mifp; if (!IN_MULTICAST(dst->sin_addr.s_addr)) return (0); @@ -210,22 +220,35 @@ vxlan_join_multicast(struct ifnet *ifp, struct sockaddr_in *src, IN_MULTICAST(src->sin_addr.s_addr)) return (EINVAL); if ((ifa = ifa_ifwithaddr(sintosa(src), - sc->sc_rtableid)) == NULL || ifa->ifa_ifp == NULL || - (ifa->ifa_ifp->if_flags & IFF_MULTICAST) == 0) + sc->sc_rtableid)) == NULL || (mifp = ifa->ifa_ifp) == NULL || + (mifp->if_flags & IFF_MULTICAST) == 0) return (EADDRNOTAVAIL); if ((imo->imo_membership[0] = - in_addmulti(&dst->sin_addr, ifa->ifa_ifp)) == NULL) + in_addmulti(&dst->sin_addr, mifp)) == NULL) return (ENOBUFS); imo->imo_num_memberships++; - imo->imo_multicast_ifp = ifa->ifa_ifp; + imo->imo_multicast_ifp = mifp; if (sc->sc_ttl > 0) imo->imo_multicast_ttl = sc->sc_ttl; else imo->imo_multicast_ttl = IP_DEFAULT_MULTICAST_TTL; imo->imo_multicast_loop = 0; + /* + * Use interface hooks to track any changes on the interface + * that is used to send out the tunnel traffic as multicast. + */ + if ((sc->sc_ahcookie = hook_establish(mifp->if_addrhooks, + 0, vxlan_addr_change, sc)) == NULL || + (sc->sc_lhcookie = hook_establish(mifp->if_linkstatehooks, + 0, vxlan_link_change, sc)) == NULL || + (sc->sc_dhcookie = hook_establish(mifp->if_detachhooks, + 0, vxlan_if_change, sc)) == NULL) + panic("%s: cannot allocate interface hook", + mifp->if_xname); + return (0); } @@ -257,12 +280,10 @@ int vxlan_config(struct ifnet *ifp, struct sockaddr *src, struct sockaddr *dst) { struct vxlan_softc *sc = (struct vxlan_softc *)ifp->if_softc; - struct ip_moptions *imo = &sc->sc_imo; #ifdef INET struct sockaddr_in *src4, *dst4; #endif int reset = 0, error; - struct ifnet *mifp = imo->imo_multicast_ifp; if (src != NULL && dst != NULL) { /* XXX inet6 is not supported */ @@ -287,22 +308,8 @@ vxlan_config(struct ifnet *ifp, struct sockaddr *src, struct sockaddr *dst) #ifdef INET if (IN_MULTICAST(dst4->sin_addr.s_addr)) { - if ((error = vxlan_join_multicast(ifp, src4, dst4)) != 0) + if ((error = vxlan_multicast_join(ifp, src4, dst4)) != 0) return (error); - - mifp = imo->imo_multicast_ifp; - - /* Insert addr and link state hooks at head */ - if ((sc->sc_ahcookie = - hook_establish(mifp->if_addrhooks, - 0, vxlan_addr_change, sc)) == NULL) - panic("%s: cannot allocate %s address hook", - __func__, mifp->if_xname); - if ((sc->sc_lhcookie = - hook_establish(mifp->if_linkstatehooks, - 0, vxlan_link_change, sc)) == NULL) - panic("%s: cannot allocate %s linkstate hook", - __func__, mifp->if_xname); } if (dst4->sin_port) sc->sc_dstport = dst4->sin_port; @@ -642,14 +649,36 @@ vxlan_addr_change(void *arg) { struct vxlan_softc *sc = arg; struct ifnet *ifp = &sc->sc_ac.ac_if; - int s; + int s, error; /* * Reset the configuration after resume or any possible address * configuration changes. */ s = splnet(); - if (vxlan_config(ifp, NULL, NULL) != 0) { + 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. + */ + 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)); } |