Changeset View
Changeset View
Standalone View
Standalone View
sys/netinet/ip_fastfwd.c
Show First 20 Lines • Show All 90 Lines • ▼ Show 20 Lines | |||||
#include <sys/sysctl.h> | #include <sys/sysctl.h> | ||||
#include <net/if.h> | #include <net/if.h> | ||||
#include <net/if_types.h> | #include <net/if_types.h> | ||||
#include <net/if_var.h> | #include <net/if_var.h> | ||||
#include <net/if_dl.h> | #include <net/if_dl.h> | ||||
#include <net/pfil.h> | #include <net/pfil.h> | ||||
#include <net/route.h> | #include <net/route.h> | ||||
#include <net/route/nhop.h> | |||||
#include <net/vnet.h> | #include <net/vnet.h> | ||||
#include <netinet/in.h> | #include <netinet/in.h> | ||||
#include <netinet/in_fib.h> | #include <netinet/in_fib.h> | ||||
#include <netinet/in_kdtrace.h> | #include <netinet/in_kdtrace.h> | ||||
#include <netinet/in_systm.h> | #include <netinet/in_systm.h> | ||||
#include <netinet/in_var.h> | #include <netinet/in_var.h> | ||||
#include <netinet/ip.h> | #include <netinet/ip.h> | ||||
#include <netinet/ip_var.h> | #include <netinet/ip_var.h> | ||||
#include <netinet/ip_icmp.h> | #include <netinet/ip_icmp.h> | ||||
#include <netinet/ip_options.h> | #include <netinet/ip_options.h> | ||||
#include <machine/in_cksum.h> | #include <machine/in_cksum.h> | ||||
static int | static int | ||||
ip_findroute(struct nhop4_basic *pnh, struct in_addr dest, struct mbuf *m) | ip_findroute(struct nhop_object **pnh, struct in_addr dest, struct mbuf *m) | ||||
{ | { | ||||
struct nhop_object *nh; | |||||
bzero(pnh, sizeof(*pnh)); | nh = fib4_lookup_nh_ptr(M_GETFIB(m), dest, 0, NHR_NONE, | ||||
if (fib4_lookup_nh_basic(M_GETFIB(m), dest, 0, 0, pnh) != 0) { | m->m_pkthdr.flowid); | ||||
if (nh == NULL) { | |||||
IPSTAT_INC(ips_noroute); | IPSTAT_INC(ips_noroute); | ||||
IPSTAT_INC(ips_cantforward); | IPSTAT_INC(ips_cantforward); | ||||
icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_HOST, 0, 0); | icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_HOST, 0, 0); | ||||
return (EHOSTUNREACH); | return (EHOSTUNREACH); | ||||
} | } | ||||
/* | /* | ||||
* Drop blackholed traffic and directed broadcasts. | * Drop blackholed traffic and directed broadcasts. | ||||
*/ | */ | ||||
if ((pnh->nh_flags & (NHF_BLACKHOLE | NHF_BROADCAST)) != 0) { | if ((nh->nh_flags & (NHF_BLACKHOLE | NHF_BROADCAST)) != 0) { | ||||
IPSTAT_INC(ips_cantforward); | IPSTAT_INC(ips_cantforward); | ||||
m_freem(m); | m_freem(m); | ||||
return (EHOSTUNREACH); | return (EHOSTUNREACH); | ||||
} | } | ||||
if (pnh->nh_flags & NHF_REJECT) { | if (nh->nh_flags & NHF_REJECT) { | ||||
IPSTAT_INC(ips_cantforward); | IPSTAT_INC(ips_cantforward); | ||||
icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_HOST, 0, 0); | icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_HOST, 0, 0); | ||||
return (EHOSTUNREACH); | return (EHOSTUNREACH); | ||||
} | } | ||||
*pnh = nh; | |||||
return (0); | return (0); | ||||
} | } | ||||
/* | /* | ||||
* Try to forward a packet based on the destination address. | * Try to forward a packet based on the destination address. | ||||
* This is a fast path optimized for the plain forwarding case. | * This is a fast path optimized for the plain forwarding case. | ||||
* If the packet is handled (and consumed) here then we return NULL; | * If the packet is handled (and consumed) here then we return NULL; | ||||
* otherwise mbuf is returned and the packet should be delivered | * otherwise mbuf is returned and the packet should be delivered | ||||
* to ip_input for full processing. | * to ip_input for full processing. | ||||
*/ | */ | ||||
struct mbuf * | struct mbuf * | ||||
ip_tryforward(struct mbuf *m) | ip_tryforward(struct mbuf *m) | ||||
{ | { | ||||
struct ip *ip; | struct ip *ip; | ||||
struct mbuf *m0 = NULL; | struct mbuf *m0 = NULL; | ||||
struct nhop4_basic nh; | struct nhop_object *nh; | ||||
struct sockaddr_in dst; | struct sockaddr_in dst; | ||||
struct in_addr dest, odest, rtdest; | struct in_addr dest, odest, rtdest; | ||||
uint16_t ip_len, ip_off; | uint16_t ip_len, ip_off; | ||||
int error = 0; | int error = 0; | ||||
struct m_tag *fwd_tag = NULL; | struct m_tag *fwd_tag = NULL; | ||||
/* | /* | ||||
* Are we active and forwarding packets? | * Are we active and forwarding packets? | ||||
▲ Show 20 Lines • Show All 155 Lines • ▼ Show 20 Lines | #endif | ||||
rtdest.s_addr = dest.s_addr; | rtdest.s_addr = dest.s_addr; | ||||
/* | /* | ||||
* Step 5: outgoing firewall packet processing | * Step 5: outgoing firewall packet processing | ||||
*/ | */ | ||||
if (!PFIL_HOOKED_OUT(V_inet_pfil_head)) | if (!PFIL_HOOKED_OUT(V_inet_pfil_head)) | ||||
goto passout; | goto passout; | ||||
if (pfil_run_hooks(V_inet_pfil_head, &m, nh.nh_ifp, | if (pfil_run_hooks(V_inet_pfil_head, &m, nh->nh_ifp, | ||||
PFIL_OUT | PFIL_FWD, NULL) != PFIL_PASS) | PFIL_OUT | PFIL_FWD, NULL) != PFIL_PASS) | ||||
goto drop; | goto drop; | ||||
M_ASSERTVALID(m); | M_ASSERTVALID(m); | ||||
M_ASSERTPKTHDR(m); | M_ASSERTPKTHDR(m); | ||||
ip = mtod(m, struct ip *); | ip = mtod(m, struct ip *); | ||||
dest.s_addr = ip->ip_dst.s_addr; | dest.s_addr = ip->ip_dst.s_addr; | ||||
Show All 36 Lines | passout: | ||||
* Step 6: send off the packet | * Step 6: send off the packet | ||||
*/ | */ | ||||
ip_len = ntohs(ip->ip_len); | ip_len = ntohs(ip->ip_len); | ||||
ip_off = ntohs(ip->ip_off); | ip_off = ntohs(ip->ip_off); | ||||
bzero(&dst, sizeof(dst)); | bzero(&dst, sizeof(dst)); | ||||
dst.sin_family = AF_INET; | dst.sin_family = AF_INET; | ||||
dst.sin_len = sizeof(dst); | dst.sin_len = sizeof(dst); | ||||
dst.sin_addr = nh.nh_addr; | if (nh->nh_flags & NHF_GATEWAY) | ||||
dst.sin_addr = nh->gw4_sa.sin_addr; | |||||
else | |||||
dst.sin_addr = dest; | |||||
/* | /* | ||||
* Check if packet fits MTU or if hardware will fragment for us | * Check if packet fits MTU or if hardware will fragment for us | ||||
*/ | */ | ||||
if (ip_len <= nh.nh_mtu) { | if (ip_len <= nh->nh_mtu) { | ||||
/* | /* | ||||
* Avoid confusing lower layers. | * Avoid confusing lower layers. | ||||
*/ | */ | ||||
m_clrprotoflags(m); | m_clrprotoflags(m); | ||||
/* | /* | ||||
* Send off the packet via outgoing interface | * Send off the packet via outgoing interface | ||||
*/ | */ | ||||
IP_PROBE(send, NULL, NULL, ip, nh.nh_ifp, ip, NULL); | IP_PROBE(send, NULL, NULL, ip, nh->nh_ifp, ip, NULL); | ||||
error = (*nh.nh_ifp->if_output)(nh.nh_ifp, m, | error = (*nh->nh_ifp->if_output)(nh->nh_ifp, m, | ||||
(struct sockaddr *)&dst, NULL); | (struct sockaddr *)&dst, NULL); | ||||
} else { | } else { | ||||
/* | /* | ||||
* Handle EMSGSIZE with icmp reply needfrag for TCP MTU discovery | * Handle EMSGSIZE with icmp reply needfrag for TCP MTU discovery | ||||
*/ | */ | ||||
if (ip_off & IP_DF) { | if (ip_off & IP_DF) { | ||||
IPSTAT_INC(ips_cantfrag); | IPSTAT_INC(ips_cantfrag); | ||||
icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_NEEDFRAG, | icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_NEEDFRAG, | ||||
0, nh.nh_mtu); | 0, nh->nh_mtu); | ||||
goto consumed; | goto consumed; | ||||
} else { | } else { | ||||
/* | /* | ||||
* We have to fragment the packet | * We have to fragment the packet | ||||
*/ | */ | ||||
m->m_pkthdr.csum_flags |= CSUM_IP; | m->m_pkthdr.csum_flags |= CSUM_IP; | ||||
if (ip_fragment(ip, &m, nh.nh_mtu, | if (ip_fragment(ip, &m, nh->nh_mtu, | ||||
nh.nh_ifp->if_hwassist) != 0) | nh->nh_ifp->if_hwassist) != 0) | ||||
goto drop; | goto drop; | ||||
KASSERT(m != NULL, ("null mbuf and no error")); | KASSERT(m != NULL, ("null mbuf and no error")); | ||||
/* | /* | ||||
* Send off the fragments via outgoing interface | * Send off the fragments via outgoing interface | ||||
*/ | */ | ||||
error = 0; | error = 0; | ||||
do { | do { | ||||
m0 = m->m_nextpkt; | m0 = m->m_nextpkt; | ||||
m->m_nextpkt = NULL; | m->m_nextpkt = NULL; | ||||
/* | /* | ||||
* Avoid confusing lower layers. | * Avoid confusing lower layers. | ||||
*/ | */ | ||||
m_clrprotoflags(m); | m_clrprotoflags(m); | ||||
IP_PROBE(send, NULL, NULL, | IP_PROBE(send, NULL, NULL, | ||||
mtod(m, struct ip *), nh.nh_ifp, | mtod(m, struct ip *), nh->nh_ifp, | ||||
mtod(m, struct ip *), NULL); | mtod(m, struct ip *), NULL); | ||||
/* XXX: we can use cached route here */ | /* XXX: we can use cached route here */ | ||||
error = (*nh.nh_ifp->if_output)(nh.nh_ifp, m, | error = (*nh->nh_ifp->if_output)(nh->nh_ifp, m, | ||||
(struct sockaddr *)&dst, NULL); | (struct sockaddr *)&dst, NULL); | ||||
if (error) | if (error) | ||||
break; | break; | ||||
} while ((m = m0) != NULL); | } while ((m = m0) != NULL); | ||||
if (error) { | if (error) { | ||||
/* Reclaim remaining fragments */ | /* Reclaim remaining fragments */ | ||||
for (m = m0; m; m = m0) { | for (m = m0; m; m = m0) { | ||||
m0 = m->m_nextpkt; | m0 = m->m_nextpkt; | ||||
Show All 20 Lines |