summaryrefslogtreecommitdiff
path: root/sys/net/if_vxlan.c
diff options
context:
space:
mode:
authorReyk Floeter <reyk@cvs.openbsd.org>2013-10-19 18:22:38 +0000
committerReyk Floeter <reyk@cvs.openbsd.org>2013-10-19 18:22:38 +0000
commit4627a77ff9dc7948a60f3492ef392d87a12c8ce5 (patch)
tree1f3dbe36c954f85e75e68d1e8e86dc2db68b2244 /sys/net/if_vxlan.c
parentb644a1f743b064f39b07db2e068a72fa1317e622 (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.c95
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));
}