Date: Sun, 21 Oct 2018 18:18:37 +0000 (UTC) From: "Andrey V. Elsukov" <ae@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r339553 - head/sys/net Message-ID: <201810211818.w9LIIb8p089218@repo.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: ae Date: Sun Oct 21 18:18:37 2018 New Revision: 339553 URL: https://svnweb.freebsd.org/changeset/base/339553 Log: Add handling for appearing/disappearing of ingress addresses to if_me(4). * register handler for ingress address appearing/disappearing; * add new srcaddr hash table for fast softc lookup by srcaddr; * when srcaddr disappears, clear IFF_DRV_RUNNING flag from interface, and set it otherwise; MFC after: 1 month Sponsored by: Yandex LLC Modified: head/sys/net/if_me.c Modified: head/sys/net/if_me.c ============================================================================== --- head/sys/net/if_me.c Sun Oct 21 18:13:45 2018 (r339552) +++ head/sys/net/if_me.c Sun Oct 21 18:18:37 2018 (r339553) @@ -83,11 +83,13 @@ struct me_softc { struct in_addr me_dst; CK_LIST_ENTRY(me_softc) chain; + CK_LIST_ENTRY(me_softc) srchash; }; CK_LIST_HEAD(me_list, me_softc); #define ME2IFP(sc) ((sc)->me_ifp) #define ME_READY(sc) ((sc)->me_src.s_addr != 0) -#define ME_RLOCK() struct epoch_tracker me_et; epoch_enter_preempt(net_epoch_preempt, &me_et) +#define ME_RLOCK_TRACKER struct epoch_tracker me_et +#define ME_RLOCK() epoch_enter_preempt(net_epoch_preempt, &me_et) #define ME_RUNLOCK() epoch_exit_preempt(net_epoch_preempt, &me_et) #define ME_WAIT() epoch_wait_preempt(net_epoch_preempt) @@ -95,9 +97,13 @@ CK_LIST_HEAD(me_list, me_softc); #define ME_HASH_SIZE (1 << 4) #endif VNET_DEFINE_STATIC(struct me_list *, me_hashtbl) = NULL; +VNET_DEFINE_STATIC(struct me_list *, me_srchashtbl) = NULL; #define V_me_hashtbl VNET(me_hashtbl) +#define V_me_srchashtbl VNET(me_srchashtbl) #define ME_HASH(src, dst) (V_me_hashtbl[\ me_hashval((src), (dst)) & (ME_HASH_SIZE - 1)]) +#define ME_SRCHASH(src) (V_me_srchashtbl[\ + fnv_32_buf(&(src), sizeof(src), FNV1_32_INIT) & (ME_HASH_SIZE - 1)]) static struct sx me_ioctl_sx; SX_SYSINIT(me_ioctl_sx, &me_ioctl_sx, "me_ioctl"); @@ -165,8 +171,10 @@ static void vnet_me_uninit(const void *unused __unused) { - if (V_me_hashtbl != NULL) + if (V_me_hashtbl != NULL) { free(V_me_hashtbl, M_IFME); + free(V_me_srchashtbl, M_IFME); + } if_clone_detach(V_me_cloner); } VNET_SYSUNINIT(vnet_me_uninit, SI_SUB_PROTO_IFATTACHDOMAIN, SI_ORDER_ANY, @@ -330,6 +338,43 @@ me_lookup(const struct mbuf *m, int off, int proto, vo return (0); } +/* + * Check that ingress address belongs to local host. + */ +static void +me_set_running(struct me_softc *sc) +{ + + if (in_localip(sc->me_src)) + ME2IFP(sc)->if_drv_flags |= IFF_DRV_RUNNING; + else + ME2IFP(sc)->if_drv_flags &= ~IFF_DRV_RUNNING; +} + +/* + * ifaddr_event handler. + * Clear IFF_DRV_RUNNING flag when ingress address disappears to prevent + * source address spoofing. + */ +static void +me_srcaddr(void *arg __unused, const struct sockaddr *sa, + int event __unused) +{ + const struct sockaddr_in *sin; + struct me_softc *sc; + + if (V_me_srchashtbl == NULL) + return; + + MPASS(in_epoch(net_epoch_preempt)); + sin = (const struct sockaddr_in *)sa; + CK_LIST_FOREACH(sc, &ME_SRCHASH(sin->sin_addr.s_addr), srchash) { + if (sc->me_src.s_addr != sin->sin_addr.s_addr) + continue; + me_set_running(sc); + } +} + static int me_set_tunnel(struct me_softc *sc, in_addr_t src, in_addr_t dst) { @@ -337,8 +382,10 @@ me_set_tunnel(struct me_softc *sc, in_addr_t src, in_a sx_assert(&me_ioctl_sx, SA_XLOCKED); - if (V_me_hashtbl == NULL) + if (V_me_hashtbl == NULL) { V_me_hashtbl = me_hashinit(); + V_me_srchashtbl = me_hashinit(); + } if (sc->me_src.s_addr == src && sc->me_dst.s_addr == dst) return (0); @@ -355,8 +402,9 @@ me_set_tunnel(struct me_softc *sc, in_addr_t src, in_a sc->me_dst.s_addr = dst; sc->me_src.s_addr = src; CK_LIST_INSERT_HEAD(&ME_HASH(src, dst), sc, chain); + CK_LIST_INSERT_HEAD(&ME_SRCHASH(src), sc, srchash); - ME2IFP(sc)->if_drv_flags |= IFF_DRV_RUNNING; + me_set_running(sc); if_link_state_change(ME2IFP(sc), LINK_STATE_UP); return (0); } @@ -368,6 +416,7 @@ me_delete_tunnel(struct me_softc *sc) sx_assert(&me_ioctl_sx, SA_XLOCKED); if (ME_READY(sc)) { CK_LIST_REMOVE(sc, chain); + CK_LIST_REMOVE(sc, srchash); ME_WAIT(); sc->me_src.s_addr = 0; @@ -473,6 +522,7 @@ me_output(struct ifnet *ifp, struct mbuf *m, const str static int me_transmit(struct ifnet *ifp, struct mbuf *m) { + ME_RLOCK_TRACKER; struct mobhdr mh; struct me_softc *sc; struct ip *ip; @@ -490,6 +540,7 @@ me_transmit(struct ifnet *ifp, struct mbuf *m) if (sc == NULL || !ME_READY(sc) || (ifp->if_flags & IFF_MONITOR) != 0 || (ifp->if_flags & IFF_UP) == 0 || + (ifp->if_drv_flags & IFF_DRV_RUNNING) == 0 || (error = if_tunnel_check_nesting(ifp, m, MTAG_ME, V_max_me_nesting)) != 0) { m_freem(m); @@ -567,6 +618,7 @@ me_qflush(struct ifnet *ifp __unused) } +static const struct srcaddrtab *me_srcaddrtab = NULL; static const struct encaptab *ecookie = NULL; static const struct encap_config me_encap_cfg = { .proto = IPPROTO_MOBILE, @@ -583,10 +635,13 @@ memodevent(module_t mod, int type, void *data) switch (type) { case MOD_LOAD: + me_srcaddrtab = ip_encap_register_srcaddr(me_srcaddr, + NULL, M_WAITOK); ecookie = ip_encap_attach(&me_encap_cfg, NULL, M_WAITOK); break; case MOD_UNLOAD: ip_encap_detach(ecookie); + ip_encap_unregister_srcaddr(me_srcaddrtab); break; default: return (EOPNOTSUPP);
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201810211818.w9LIIb8p089218>