Date: Thu, 19 Apr 2018 10:13:28 +0000 (UTC) From: "Andrey V. Elsukov" <ae@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-11@freebsd.org Subject: svn commit: r332766 - stable/11/sys/netpfil/ipfw/nat64 Message-ID: <201804191013.w3JADSw9003117@repo.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: ae Date: Thu Apr 19 10:13:28 2018 New Revision: 332766 URL: https://svnweb.freebsd.org/changeset/base/332766 Log: MFC r332456: Migrate NAT64 to FIB KPI. Modified: stable/11/sys/netpfil/ipfw/nat64/nat64_translate.c stable/11/sys/netpfil/ipfw/nat64/nat64_translate.h Directory Properties: stable/11/ (props changed) Modified: stable/11/sys/netpfil/ipfw/nat64/nat64_translate.c ============================================================================== --- stable/11/sys/netpfil/ipfw/nat64/nat64_translate.c Thu Apr 19 10:11:39 2018 (r332765) +++ stable/11/sys/netpfil/ipfw/nat64/nat64_translate.c Thu Apr 19 10:13:28 2018 (r332766) @@ -51,6 +51,7 @@ __FBSDID("$FreeBSD$"); #include <net/route.h> #include <netinet/in.h> +#include <netinet/in_fib.h> #include <netinet/ip.h> #include <netinet/ip_var.h> #include <netinet/ip_fw.h> @@ -60,6 +61,7 @@ __FBSDID("$FreeBSD$"); #include <netinet/tcp.h> #include <netinet/udp.h> #include <netinet6/in6_var.h> +#include <netinet6/in6_fib.h> #include <netinet6/ip6_var.h> #include <netpfil/pf/pf.h> @@ -76,11 +78,12 @@ nat64_log(struct pfloghdr *logdata, struct mbuf *m, sa logdata->af = family; ipfw_bpf_mtap2(logdata, PFLOG_HDRLEN, m); } + #ifdef IPFIREWALL_NAT64_DIRECT_OUTPUT -static NAT64NOINLINE struct sockaddr* nat64_find_route4(struct route *ro, - in_addr_t dest, struct mbuf *m); -static NAT64NOINLINE struct sockaddr* nat64_find_route6(struct route_in6 *ro, - struct in6_addr *dest, struct mbuf *m); +static NAT64NOINLINE int nat64_find_route4(struct nhop4_basic *, + struct sockaddr_in *, struct mbuf *); +static NAT64NOINLINE int nat64_find_route6(struct nhop6_basic *, + struct sockaddr_in6 *, struct mbuf *); static NAT64NOINLINE int nat64_output(struct ifnet *ifp, struct mbuf *m, @@ -100,28 +103,38 @@ nat64_output(struct ifnet *ifp, struct mbuf *m, static NAT64NOINLINE int nat64_output_one(struct mbuf *m, nat64_stats_block *stats, void *logdata) { - struct route_in6 ro6; - struct route ro4, *ro; + struct nhop6_basic nh6; + struct nhop4_basic nh4; + struct sockaddr_in6 dst6; + struct sockaddr_in dst4; struct sockaddr *dst; - struct ifnet *ifp; struct ip6_hdr *ip6; struct ip *ip4; + struct ifnet *ifp; int error; ip4 = mtod(m, struct ip *); switch (ip4->ip_v) { case IPVERSION: - ro = &ro4; - dst = nat64_find_route4(&ro4, ip4->ip_dst.s_addr, m); - if (dst == NULL) + dst4.sin_addr = ip4->ip_dst; + error = nat64_find_route4(&nh4, &dst4, m); + if (error != 0) NAT64STAT_INC(stats, noroute4); + else { + ifp = nh4.nh_ifp; + dst = (struct sockaddr *)&dst4; + } break; case (IPV6_VERSION >> 4): - ip6 = (struct ip6_hdr *)ip4; - ro = (struct route *)&ro6; - dst = nat64_find_route6(&ro6, &ip6->ip6_dst, m); - if (dst == NULL) + ip6 = mtod(m, struct ip6_hdr *); + dst6.sin6_addr = ip6->ip6_dst; + error = nat64_find_route6(&nh6, &dst6, m); + if (error != 0) NAT64STAT_INC(stats, noroute6); + else { + ifp = nh6.nh_ifp; + dst = (struct sockaddr *)&dst6; + } break; default: m_freem(m); @@ -129,18 +142,15 @@ nat64_output_one(struct mbuf *m, nat64_stats_block *st DPRINTF(DP_DROPS, "dropped due to unknown IP version"); return (EAFNOSUPPORT); } - if (dst == NULL) { - FREE_ROUTE(ro); + if (error != 0) { m_freem(m); return (EHOSTUNREACH); } if (logdata != NULL) nat64_log(logdata, m, dst->sa_family); - ifp = ro->ro_rt->rt_ifp; - error = (*ifp->if_output)(ifp, m, dst, ro); + error = (*ifp->if_output)(ifp, m, dst, NULL); if (error != 0) NAT64STAT_INC(stats, oerrors); - FREE_ROUTE(ro); return (error); } #else /* !IPFIREWALL_NAT64_DIRECT_OUTPUT */ @@ -470,36 +480,31 @@ fail: return (ENOMEM); } -#if __FreeBSD_version < 1100000 -#define rt_expire rt_rmx.rmx_expire -#define rt_mtu rt_rmx.rmx_mtu -#endif -static NAT64NOINLINE struct sockaddr* -nat64_find_route6(struct route_in6 *ro, struct in6_addr *dest, struct mbuf *m) +static NAT64NOINLINE int +nat64_find_route6(struct nhop6_basic *pnh, struct sockaddr_in6 *dst, + struct mbuf *m) { - struct sockaddr_in6 *dst; - struct rtentry *rt; - bzero(ro, sizeof(*ro)); - dst = (struct sockaddr_in6 *)&ro->ro_dst; + if (fib6_lookup_nh_basic(M_GETFIB(m), &dst->sin6_addr, 0, 0, 0, + pnh) != 0) + return (EHOSTUNREACH); + if (pnh->nh_flags & (NHF_BLACKHOLE | NHF_REJECT)) + return (EHOSTUNREACH); + /* + * XXX: we need to use destination address with embedded scope + * zone id, because LLTABLE uses such form of addresses for lookup. + */ dst->sin6_family = AF_INET6; dst->sin6_len = sizeof(*dst); - dst->sin6_addr = *dest; - IN6_LOOKUP_ROUTE(ro, M_GETFIB(m)); - rt = ro->ro_rt; - if (rt && (rt->rt_flags & RTF_UP) && - (rt->rt_ifp->if_flags & IFF_UP) && - (rt->rt_ifp->if_drv_flags & IFF_DRV_RUNNING)) { - if (rt->rt_flags & RTF_GATEWAY) - dst = (struct sockaddr_in6 *)rt->rt_gateway; - } else - return (NULL); - if (((rt->rt_flags & RTF_REJECT) && - (rt->rt_expire == 0 || - time_uptime < rt->rt_expire)) || - rt->rt_ifp->if_link_state == LINK_STATE_DOWN) - return (NULL); - return ((struct sockaddr *)dst); + dst->sin6_addr = pnh->nh_addr; + if (IN6_IS_SCOPE_LINKLOCAL(&dst->sin6_addr)) + dst->sin6_addr.s6_addr16[1] = + htons(pnh->nh_ifp->if_index & 0xffff); + dst->sin6_port = 0; + dst->sin6_scope_id = 0; + dst->sin6_flowinfo = 0; + + return (0); } #define NAT64_ICMP6_PLEN 64 @@ -600,32 +605,21 @@ freeit: m_freem(m); } -static NAT64NOINLINE struct sockaddr* -nat64_find_route4(struct route *ro, in_addr_t dest, struct mbuf *m) +static NAT64NOINLINE int +nat64_find_route4(struct nhop4_basic *pnh, struct sockaddr_in *dst, + struct mbuf *m) { - struct sockaddr_in *dst; - struct rtentry *rt; - bzero(ro, sizeof(*ro)); - dst = (struct sockaddr_in *)&ro->ro_dst; + if (fib4_lookup_nh_basic(M_GETFIB(m), dst->sin_addr, 0, 0, pnh) != 0) + return (EHOSTUNREACH); + if (pnh->nh_flags & (NHF_BLACKHOLE | NHF_BROADCAST | NHF_REJECT)) + return (EHOSTUNREACH); + dst->sin_family = AF_INET; dst->sin_len = sizeof(*dst); - dst->sin_addr.s_addr = dest; - IN_LOOKUP_ROUTE(ro, M_GETFIB(m)); - rt = ro->ro_rt; - if (rt && (rt->rt_flags & RTF_UP) && - (rt->rt_ifp->if_flags & IFF_UP) && - (rt->rt_ifp->if_drv_flags & IFF_DRV_RUNNING)) { - if (rt->rt_flags & RTF_GATEWAY) - dst = (struct sockaddr_in *)rt->rt_gateway; - } else - return (NULL); - if (((rt->rt_flags & RTF_REJECT) && - (rt->rt_expire == 0 || - time_uptime < rt->rt_expire)) || - rt->rt_ifp->if_link_state == LINK_STATE_DOWN) - return (NULL); - return ((struct sockaddr *)dst); + dst->sin_addr = pnh->nh_addr; + dst->sin_port = 0; + return (0); } #define NAT64_ICMP_PLEN 64 @@ -1066,13 +1060,11 @@ nat64_do_handle_ip4(struct mbuf *m, struct in6_addr *s struct in6_addr *daddr, uint16_t lport, nat64_stats_block *stats, void *logdata) { - struct route_in6 ro; + struct nhop6_basic nh; struct ip6_hdr ip6; - struct ifnet *ifp; + struct sockaddr_in6 dst; struct ip *ip; struct mbufq mq; - struct sockaddr *dst; - uint32_t mtu; uint16_t ip_id, ip_off; uint16_t *csum; int plen, hlen; @@ -1110,23 +1102,17 @@ nat64_do_handle_ip4(struct mbuf *m, struct in6_addr *s return (NAT64MFREE); } - dst = nat64_find_route6(&ro, &ip6.ip6_dst, m); - if (dst == NULL) { - FREE_ROUTE(&ro); + dst.sin6_addr = ip6.ip6_dst; + if (nat64_find_route6(&nh, &dst, m) != 0) { NAT64STAT_INC(stats, noroute6); nat64_icmp_reflect(m, ICMP_UNREACH, ICMP_UNREACH_HOST, 0, stats, logdata); return (NAT64RETURN); } - ifp = ro.ro_rt->rt_ifp; - if (ro.ro_rt->rt_mtu != 0) - mtu = min(ro.ro_rt->rt_mtu, ifp->if_mtu); - else - mtu = ifp->if_mtu; - if (mtu < plen + sizeof(ip6) && (ip->ip_off & htons(IP_DF)) != 0) { - FREE_ROUTE(&ro); + if (nh.nh_mtu < plen + sizeof(ip6) && + (ip->ip_off & htons(IP_DF)) != 0) { nat64_icmp_reflect(m, ICMP_UNREACH, ICMP_UNREACH_NEEDFRAG, - FRAGSZ(mtu) + sizeof(struct ip), stats, logdata); + FRAGSZ(nh.nh_mtu) + sizeof(struct ip), stats, logdata); return (NAT64RETURN); } @@ -1162,24 +1148,20 @@ nat64_do_handle_ip4(struct mbuf *m, struct in6_addr *s break; case IPPROTO_ICMP: m = nat64_icmp_translate(m, &ip6, lport, hlen, stats); - if (m == NULL) { - FREE_ROUTE(&ro); - /* stats already accounted */ + if (m == NULL) /* stats already accounted */ return (NAT64RETURN); - } } m_adj(m, hlen); mbufq_init(&mq, 255); - nat64_fragment6(stats, &ip6, &mq, m, mtu, ip_id, ip_off); + nat64_fragment6(stats, &ip6, &mq, m, nh.nh_mtu, ip_id, ip_off); while ((m = mbufq_dequeue(&mq)) != NULL) { - if (nat64_output(ifp, m, dst, (struct route *)&ro, stats, - logdata) != 0) + if (nat64_output(nh.nh_ifp, m, (struct sockaddr *)&dst, + NULL, stats, logdata) != 0) break; NAT64STAT_INC(stats, opcnt46); } mbufq_drain(&mq); - FREE_ROUTE(&ro); return (NAT64RETURN); } @@ -1406,15 +1388,13 @@ int nat64_do_handle_ip6(struct mbuf *m, uint32_t aaddr, uint16_t aport, nat64_stats_block *stats, void *logdata) { - struct route ro; struct ip ip; - struct ifnet *ifp; + struct nhop4_basic nh; + struct sockaddr_in dst; struct ip6_frag *frag; struct ip6_hdr *ip6; struct icmp6_hdr *icmp6; - struct sockaddr *dst; uint16_t *csum; - uint32_t mtu; int plen, hlen, proto; /* @@ -1501,24 +1481,16 @@ nat64_do_handle_ip6(struct mbuf *m, uint32_t aaddr, ui return (nat64_handle_icmp6(m, hlen, aaddr, aport, stats, logdata)); } - dst = nat64_find_route4(&ro, ip.ip_dst.s_addr, m); - if (dst == NULL) { - FREE_ROUTE(&ro); + dst.sin_addr.s_addr = ip.ip_dst.s_addr; + if (nat64_find_route4(&nh, &dst, m) != 0) { NAT64STAT_INC(stats, noroute4); nat64_icmp6_reflect(m, ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_NOROUTE, 0, stats, logdata); return (NAT64RETURN); } - - ifp = ro.ro_rt->rt_ifp; - if (ro.ro_rt->rt_mtu != 0) - mtu = min(ro.ro_rt->rt_mtu, ifp->if_mtu); - else - mtu = ifp->if_mtu; - if (mtu < plen + sizeof(ip)) { - FREE_ROUTE(&ro); - nat64_icmp6_reflect(m, ICMP6_PACKET_TOO_BIG, 0, mtu, stats, - logdata); + if (nh.nh_mtu < plen + sizeof(ip)) { + nat64_icmp6_reflect(m, ICMP6_PACKET_TOO_BIG, 0, nh.nh_mtu, + stats, logdata); return (NAT64RETURN); } nat64_init_ip4hdr(ip6, frag, plen, proto, &ip); @@ -1548,12 +1520,13 @@ nat64_do_handle_ip6(struct mbuf *m, uint32_t aaddr, ui *csum = cksum_add(*csum, in6_cksum_pseudo(ip6, plen, IPPROTO_ICMPV6, 0)); /* Convert ICMPv6 types to ICMP */ - mtu = *(uint16_t *)icmp6; /* save old word for cksum_adjust */ + proto = *(uint16_t *)icmp6; /* save old word for cksum_adjust */ if (icmp6->icmp6_type == ICMP6_ECHO_REQUEST) icmp6->icmp6_type = ICMP_ECHO; else /* ICMP6_ECHO_REPLY */ icmp6->icmp6_type = ICMP_ECHOREPLY; - *csum = cksum_adjust(*csum, (uint16_t)mtu, *(uint16_t *)icmp6); + *csum = cksum_adjust(*csum, (uint16_t)proto, + *(uint16_t *)icmp6); if (aport != 0) { uint16_t old_id = icmp6->icmp6_id; icmp6->icmp6_id = aport; @@ -1564,9 +1537,9 @@ nat64_do_handle_ip6(struct mbuf *m, uint32_t aaddr, ui m_adj(m, hlen - sizeof(ip)); bcopy(&ip, mtod(m, void *), sizeof(ip)); - if (nat64_output(ifp, m, dst, &ro, stats, logdata) == 0) + if (nat64_output(nh.nh_ifp, m, (struct sockaddr *)&dst, NULL, + stats, logdata) == 0) NAT64STAT_INC(stats, opcnt64); - FREE_ROUTE(&ro); return (NAT64RETURN); } Modified: stable/11/sys/netpfil/ipfw/nat64/nat64_translate.h ============================================================================== --- stable/11/sys/netpfil/ipfw/nat64/nat64_translate.h Thu Apr 19 10:11:39 2018 (r332765) +++ stable/11/sys/netpfil/ipfw/nat64/nat64_translate.h Thu Apr 19 10:13:28 2018 (r332766) @@ -30,16 +30,6 @@ #ifndef _IP_FW_NAT64_TRANSLATE_H_ #define _IP_FW_NAT64_TRANSLATE_H_ -#ifdef RTALLOC_NOLOCK -#define IN_LOOKUP_ROUTE(ro, fib) rtalloc_fib_nolock((ro), 0, (fib)) -#define IN6_LOOKUP_ROUTE(ro, fib) in6_rtalloc_nolock((ro), (fib)) -#define FREE_ROUTE(ro) -#else -#define IN_LOOKUP_ROUTE(ro, fib) rtalloc_ign_fib((ro), 0, (fib)) -#define IN6_LOOKUP_ROUTE(ro, fib) in6_rtalloc((ro), (fib)) -#define FREE_ROUTE(ro) RO_RTFREE((ro)) -#endif - static inline int nat64_check_ip6(struct in6_addr *addr) {
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201804191013.w3JADSw9003117>