diff --git a/sys/net/if_gif.h b/sys/net/if_gif.h --- a/sys/net/if_gif.h +++ b/sys/net/if_gif.h @@ -40,6 +40,7 @@ struct ip; struct ip6_hdr; +struct route_cache; extern void (*ng_gif_input_p)(struct ifnet *ifp, struct mbuf **mp, int af); @@ -61,6 +62,7 @@ struct ip *iphdr; struct ip6_hdr *ip6hdr; } gif_uhdr; + struct route_cache gif_rc; CK_LIST_ENTRY(gif_softc) chain; CK_LIST_ENTRY(gif_softc) srchash; diff --git a/sys/net/if_gif.c b/sys/net/if_gif.c --- a/sys/net/if_gif.c +++ b/sys/net/if_gif.c @@ -89,6 +89,7 @@ #include #include #include +#include #include #include @@ -647,8 +648,15 @@ break; if (ifr->ifr_fib >= rt_numfibs) error = EINVAL; - else + else if (ifr->ifr_fib != sc->gif_fibnum) { sc->gif_fibnum = ifr->ifr_fib; + if (sc->gif_family != 0) { + route_cache_unsubscribe_rib_event(&sc->gif_rc); + route_cache_invalidate(&sc->gif_rc, sc->gif_family); + route_cache_subscribe_rib_event(&sc->gif_rc, + sc->gif_family, sc->gif_fibnum); + } + } break; case GIFGOPTS: options = sc->gif_options; @@ -711,13 +719,19 @@ sx_assert(&gif_ioctl_sx, SA_XLOCKED); if (sc->gif_family != 0) { +#ifdef VIMAGE + // On vnet destroy, it is too late to unsubscribe_rib_event + if (!curvnet->vnet_shutdown) +#endif + route_cache_unsubscribe_rib_event(&sc->gif_rc); CK_LIST_REMOVE(sc, srchash); CK_LIST_REMOVE(sc, chain); /* Wait until it become safe to free gif_hdr */ GIF_WAIT(); free(sc->gif_hdr, M_GIF); + route_cache_uninit(&sc->gif_rc, sc->gif_family); + sc->gif_family = 0; } - sc->gif_family = 0; GIF2IFP(sc)->if_drv_flags &= ~IFF_DRV_RUNNING; if_link_state_change(GIF2IFP(sc), LINK_STATE_DOWN); } diff --git a/sys/netgraph/ng_gif.c b/sys/netgraph/ng_gif.c --- a/sys/netgraph/ng_gif.c +++ b/sys/netgraph/ng_gif.c @@ -70,6 +70,9 @@ /* * ng_gif(4) netgraph node type */ +#include "opt_inet.h" +#include "opt_inet6.h" + #include #include #include @@ -83,6 +86,8 @@ #include #include #include +#include +#include #include #include diff --git a/sys/netinet/in_gif.c b/sys/netinet/in_gif.c --- a/sys/netinet/in_gif.c +++ b/sys/netinet/in_gif.c @@ -69,6 +69,7 @@ #include #endif +#include #include #define GIF_TTL 30 @@ -236,19 +237,24 @@ ip->ip_src.s_addr = src->sin_addr.s_addr; ip->ip_dst.s_addr = dst->sin_addr.s_addr; if (sc->gif_family != 0) { + route_cache_unsubscribe_rib_event(&sc->gif_rc); /* Detach existing tunnel first */ CK_LIST_REMOVE(sc, srchash); CK_LIST_REMOVE(sc, chain); GIF_WAIT(); free(sc->gif_hdr, M_GIF); + route_cache_uninit(&sc->gif_rc, sc->gif_family); /* XXX: should we notify about link state change? */ } sc->gif_family = AF_INET; sc->gif_iphdr = ip; in_gif_attach(sc); + route_cache_init(&sc->gif_rc, sc->gif_family); NET_EPOCH_ENTER(et); in_gif_set_running(sc); NET_EPOCH_EXIT(et); + route_cache_subscribe_rib_event(&sc->gif_rc, sc->gif_family, + sc->gif_fibnum); break; case SIOCGIFPSRCADDR: case SIOCGIFPDSTADDR: @@ -275,7 +281,9 @@ { struct gif_softc *sc = ifp->if_softc; struct ip *ip; + struct route *ro; int len; + int error; /* prepend new IP header */ NET_EPOCH_ASSERT(); @@ -306,7 +314,10 @@ ip->ip_len = htons(m->m_pkthdr.len); ip->ip_tos = ecn; - return (ip_output(m, NULL, NULL, 0, NULL, NULL)); + ro = route_cache_acquire(&sc->gif_rc); + error = ip_output(m, NULL, ro, 0, NULL, NULL); + route_cache_release(ro); + return (error); } static int diff --git a/sys/netinet6/in6_gif.c b/sys/netinet6/in6_gif.c --- a/sys/netinet6/in6_gif.c +++ b/sys/netinet6/in6_gif.c @@ -71,6 +71,7 @@ #include #include +#include #include #define GIF_HLIM 30 @@ -251,17 +252,22 @@ ip6->ip6_dst = dst->sin6_addr; ip6->ip6_vfc = IPV6_VERSION; if (sc->gif_family != 0) { + route_cache_unsubscribe_rib_event(&sc->gif_rc); /* Detach existing tunnel first */ CK_LIST_REMOVE(sc, srchash); CK_LIST_REMOVE(sc, chain); GIF_WAIT(); free(sc->gif_hdr, M_GIF); + route_cache_uninit(&sc->gif_rc, sc->gif_family); /* XXX: should we notify about link state change? */ } sc->gif_family = AF_INET6; sc->gif_ip6hdr = ip6; in6_gif_attach(sc); + route_cache_init(&sc->gif_rc, sc->gif_family); in6_gif_set_running(sc); + route_cache_subscribe_rib_event(&sc->gif_rc, sc->gif_family, + sc->gif_fibnum); break; case SIOCGIFPSRCADDR_IN6: case SIOCGIFPDSTADDR_IN6: @@ -290,7 +296,9 @@ { struct gif_softc *sc = ifp->if_softc; struct ip6_hdr *ip6; + struct route_in6 *ro; int len; + int error; /* prepend new IP header */ NET_EPOCH_ASSERT(); @@ -319,12 +327,16 @@ ip6->ip6_flow |= htonl((uint32_t)ecn << 20); ip6->ip6_nxt = proto; ip6->ip6_hlim = V_ip6_gif_hlim; + + ro = route_cache_acquire6(&sc->gif_rc); /* * force fragmentation to minimum MTU, to avoid path MTU discovery. * it is too painful to ask for resend of inner packet, to achieve * path MTU discovery for encapsulated packets. */ - return (ip6_output(m, 0, NULL, IPV6_MINMTU, 0, NULL, NULL)); + error = ip6_output(m, 0, ro, IPV6_MINMTU, 0, NULL, NULL); + route_cache_release6(ro); + return (error); } static int