Changeset View
Changeset View
Standalone View
Standalone View
sys/netinet6/ip6_fastfwd.c
Show All 34 Lines | |||||
#include <sys/mbuf.h> | #include <sys/mbuf.h> | ||||
#include <sys/socket.h> | #include <sys/socket.h> | ||||
#include <sys/kernel.h> | #include <sys/kernel.h> | ||||
#include <sys/sysctl.h> | #include <sys/sysctl.h> | ||||
#include <net/if.h> | #include <net/if.h> | ||||
#include <net/if_var.h> | #include <net/if_var.h> | ||||
#include <net/route.h> | #include <net/route.h> | ||||
#include <net/route/nhop.h> | |||||
#include <net/pfil.h> | #include <net/pfil.h> | ||||
#include <net/vnet.h> | #include <net/vnet.h> | ||||
#include <netinet/in.h> | #include <netinet/in.h> | ||||
#include <netinet/in_kdtrace.h> | #include <netinet/in_kdtrace.h> | ||||
#include <netinet/in_var.h> | #include <netinet/in_var.h> | ||||
#include <netinet/ip_var.h> | #include <netinet/ip_var.h> | ||||
#include <netinet/ip6.h> | #include <netinet/ip6.h> | ||||
#include <netinet/icmp6.h> | #include <netinet/icmp6.h> | ||||
#include <netinet6/in6_var.h> | #include <netinet6/in6_var.h> | ||||
#include <netinet6/in6_fib.h> | #include <netinet6/in6_fib.h> | ||||
#include <netinet6/ip6_var.h> | #include <netinet6/ip6_var.h> | ||||
#include <netinet6/nd6.h> | #include <netinet6/nd6.h> | ||||
static int | static int | ||||
ip6_findroute(struct nhop6_basic *pnh, const struct sockaddr_in6 *dst, | ip6_findroute(struct nhop_object **pnh, const struct sockaddr_in6 *dst, | ||||
struct mbuf *m) | struct mbuf *m) | ||||
{ | { | ||||
struct nhop_object *nh; | |||||
if (fib6_lookup_nh_basic(M_GETFIB(m), &dst->sin6_addr, | nh = fib6_lookup_nh_ptr(M_GETFIB(m), &dst->sin6_addr, | ||||
dst->sin6_scope_id, 0, dst->sin6_flowinfo, pnh) != 0) { | dst->sin6_scope_id, NHR_NONE, m->m_pkthdr.flowid); | ||||
if (nh == NULL) { | |||||
IP6STAT_INC(ip6s_noroute); | IP6STAT_INC(ip6s_noroute); | ||||
IP6STAT_INC(ip6s_cantforward); | IP6STAT_INC(ip6s_cantforward); | ||||
icmp6_error(m, ICMP6_DST_UNREACH, | icmp6_error(m, ICMP6_DST_UNREACH, | ||||
ICMP6_DST_UNREACH_NOROUTE, 0); | ICMP6_DST_UNREACH_NOROUTE, 0); | ||||
return (EHOSTUNREACH); | return (EHOSTUNREACH); | ||||
} | } | ||||
if (pnh->nh_flags & NHF_BLACKHOLE) { | if (nh->nh_flags & NHF_BLACKHOLE) { | ||||
IP6STAT_INC(ip6s_cantforward); | IP6STAT_INC(ip6s_cantforward); | ||||
m_freem(m); | m_freem(m); | ||||
return (EHOSTUNREACH); | return (EHOSTUNREACH); | ||||
} | } | ||||
if (pnh->nh_flags & NHF_REJECT) { | if (nh->nh_flags & NHF_REJECT) { | ||||
IP6STAT_INC(ip6s_cantforward); | IP6STAT_INC(ip6s_cantforward); | ||||
icmp6_error(m, ICMP6_DST_UNREACH, | icmp6_error(m, ICMP6_DST_UNREACH, | ||||
ICMP6_DST_UNREACH_REJECT, 0); | ICMP6_DST_UNREACH_REJECT, 0); | ||||
return (EHOSTUNREACH); | return (EHOSTUNREACH); | ||||
} | } | ||||
*pnh = nh; | |||||
return (0); | return (0); | ||||
} | } | ||||
struct mbuf* | struct mbuf* | ||||
ip6_tryforward(struct mbuf *m) | ip6_tryforward(struct mbuf *m) | ||||
{ | { | ||||
struct sockaddr_in6 dst; | struct sockaddr_in6 dst; | ||||
struct nhop6_basic nh; | struct nhop_object *nh; | ||||
struct m_tag *fwd_tag; | struct m_tag *fwd_tag; | ||||
struct ip6_hdr *ip6; | struct ip6_hdr *ip6; | ||||
struct ifnet *rcvif; | struct ifnet *rcvif; | ||||
uint32_t plen; | uint32_t plen; | ||||
int error; | int error; | ||||
/* | /* | ||||
* Fallback conditions to ip6_input for slow path processing. | * Fallback conditions to ip6_input for slow path processing. | ||||
▲ Show 20 Lines • Show All 93 Lines • ▼ Show 20 Lines | passin: | ||||
* Find route to destination. | * Find route to destination. | ||||
*/ | */ | ||||
if (ip6_findroute(&nh, &dst, m) != 0) { | if (ip6_findroute(&nh, &dst, m) != 0) { | ||||
m = NULL; | m = NULL; | ||||
in6_ifstat_inc(rcvif, ifs6_in_noroute); | in6_ifstat_inc(rcvif, ifs6_in_noroute); | ||||
goto dropin; | goto dropin; | ||||
} | } | ||||
if (!PFIL_HOOKED_OUT(V_inet6_pfil_head)) { | if (!PFIL_HOOKED_OUT(V_inet6_pfil_head)) { | ||||
if (m->m_pkthdr.len > nh.nh_mtu) { | if (m->m_pkthdr.len > nh->nh_mtu) { | ||||
in6_ifstat_inc(nh.nh_ifp, ifs6_in_toobig); | in6_ifstat_inc(nh->nh_ifp, ifs6_in_toobig); | ||||
icmp6_error(m, ICMP6_PACKET_TOO_BIG, 0, nh.nh_mtu); | icmp6_error(m, ICMP6_PACKET_TOO_BIG, 0, nh->nh_mtu); | ||||
m = NULL; | m = NULL; | ||||
goto dropout; | goto dropout; | ||||
} | } | ||||
goto passout; | goto passout; | ||||
} | } | ||||
/* | /* | ||||
* Outgoing packet firewall processing. | * Outgoing packet firewall processing. | ||||
*/ | */ | ||||
if (pfil_run_hooks(V_inet6_pfil_head, &m, nh.nh_ifp, PFIL_OUT | | if (pfil_run_hooks(V_inet6_pfil_head, &m, nh->nh_ifp, PFIL_OUT | | ||||
PFIL_FWD, NULL) != PFIL_PASS) | PFIL_FWD, NULL) != PFIL_PASS) | ||||
goto dropout; | goto dropout; | ||||
/* | /* | ||||
* We used slow path processing for packets with scoped addresses. | * We used slow path processing for packets with scoped addresses. | ||||
* So, scope checks aren't needed here. | * So, scope checks aren't needed here. | ||||
*/ | */ | ||||
if (m->m_pkthdr.len > nh.nh_mtu) { | if (m->m_pkthdr.len > nh->nh_mtu) { | ||||
in6_ifstat_inc(nh.nh_ifp, ifs6_in_toobig); | in6_ifstat_inc(nh->nh_ifp, ifs6_in_toobig); | ||||
icmp6_error(m, ICMP6_PACKET_TOO_BIG, 0, nh.nh_mtu); | icmp6_error(m, ICMP6_PACKET_TOO_BIG, 0, nh->nh_mtu); | ||||
m = NULL; | m = NULL; | ||||
goto dropout; | goto dropout; | ||||
} | } | ||||
/* | /* | ||||
* If packet filter sets the M_FASTFWD_OURS flag, this means | * If packet filter sets the M_FASTFWD_OURS flag, this means | ||||
* that new destination or next hop is our local address. | * that new destination or next hop is our local address. | ||||
* So, we can just go back to ip6_input. | * So, we can just go back to ip6_input. | ||||
Show All 37 Lines | |||||
#ifdef IPSTEALTH | #ifdef IPSTEALTH | ||||
if (!V_ip6stealth) | if (!V_ip6stealth) | ||||
#endif | #endif | ||||
{ | { | ||||
ip6->ip6_hlim -= IPV6_HLIMDEC; | ip6->ip6_hlim -= IPV6_HLIMDEC; | ||||
} | } | ||||
m_clrprotoflags(m); /* Avoid confusing lower layers. */ | m_clrprotoflags(m); /* Avoid confusing lower layers. */ | ||||
IP_PROBE(send, NULL, NULL, ip6, nh.nh_ifp, NULL, ip6); | IP_PROBE(send, NULL, NULL, ip6, nh->nh_ifp, NULL, ip6); | ||||
dst.sin6_addr = nh.nh_addr; | if (nh->nh_flags & NHF_GATEWAY) | ||||
error = (*nh.nh_ifp->if_output)(nh.nh_ifp, m, | dst.sin6_addr = nh->gw6_sa.sin6_addr; | ||||
error = (*nh->nh_ifp->if_output)(nh->nh_ifp, m, | |||||
(struct sockaddr *)&dst, NULL); | (struct sockaddr *)&dst, NULL); | ||||
if (error != 0) { | if (error != 0) { | ||||
in6_ifstat_inc(nh.nh_ifp, ifs6_out_discard); | in6_ifstat_inc(nh->nh_ifp, ifs6_out_discard); | ||||
IP6STAT_INC(ip6s_cantforward); | IP6STAT_INC(ip6s_cantforward); | ||||
} else { | } else { | ||||
in6_ifstat_inc(nh.nh_ifp, ifs6_out_forward); | in6_ifstat_inc(nh->nh_ifp, ifs6_out_forward); | ||||
IP6STAT_INC(ip6s_forward); | IP6STAT_INC(ip6s_forward); | ||||
} | } | ||||
return (NULL); | return (NULL); | ||||
dropin: | dropin: | ||||
in6_ifstat_inc(rcvif, ifs6_in_discard); | in6_ifstat_inc(rcvif, ifs6_in_discard); | ||||
goto drop; | goto drop; | ||||
dropout: | dropout: | ||||
in6_ifstat_inc(nh.nh_ifp, ifs6_out_discard); | in6_ifstat_inc(nh->nh_ifp, ifs6_out_discard); | ||||
drop: | drop: | ||||
if (m != NULL) | if (m != NULL) | ||||
m_freem(m); | m_freem(m); | ||||
return (NULL); | return (NULL); | ||||
} | } | ||||