Changeset View
Changeset View
Standalone View
Standalone View
sys/netinet/ip_fastfwd.c
Show First 20 Lines • Show All 94 Lines • ▼ Show 20 Lines | |||||
#include <net/if_var.h> | #include <net/if_var.h> | ||||
#include <net/if_dl.h> | #include <net/if_dl.h> | ||||
#include <net/route.h> | #include <net/route.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_systm.h> | #include <netinet/in_systm.h> | ||||
#include <netinet/in_fib.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 <net/rt_nhops.h> | |||||
#include <machine/in_cksum.h> | #include <machine/in_cksum.h> | ||||
static struct sockaddr_in * | static struct sockaddr_in * | ||||
ip_findroute(struct route *ro, struct in_addr dest, struct mbuf *m) | ip_findroute(struct route *ro, struct in_addr dest, struct mbuf *m, | ||||
struct nhop_prepend *pnh) | |||||
{ | { | ||||
struct sockaddr_in *dst; | struct sockaddr_in *dst; | ||||
struct rtentry *rt; | uint32_t hash; | ||||
int error; | |||||
/* | /* | ||||
* Find route to destination. | * Find route to destination. | ||||
*/ | */ | ||||
bzero(ro, sizeof(*ro)); | bzero(ro, sizeof(*ro)); | ||||
/* XXX: Temporary cast to until ro_rt rename */ | |||||
ro->ro_rt = (struct rtentry *)pnh; | |||||
struct ip *ip; | |||||
ip = mtod(m, struct ip *); | |||||
hash = m->m_pkthdr.flowid; | |||||
error = fib4_lookup_prepend(M_GETFIB(m), dest, 0, hash, ro, NULL); | |||||
if (error == 0) { | |||||
dst = (struct sockaddr_in *)&ro->ro_dst; | dst = (struct sockaddr_in *)&ro->ro_dst; | ||||
dst->sin_family = AF_INET; | dst->sin_family = AF_INET; | ||||
dst->sin_len = sizeof(*dst); | dst->sin_len = sizeof(*dst); | ||||
dst->sin_addr.s_addr = dest.s_addr; | dst->sin_addr = pnh->nh4_addr; | ||||
in_rtalloc_ign(ro, 0, M_GETFIB(m)); | return (dst); | ||||
} | |||||
/* | |||||
* Route there and interface still up? | |||||
*/ | |||||
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 { | |||||
IPSTAT_INC(ips_noroute); | IPSTAT_INC(ips_noroute); | ||||
IPSTAT_INC(ips_cantforward); | IPSTAT_INC(ips_cantforward); | ||||
if (rt) | |||||
RTFREE(rt); | |||||
icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_HOST, 0, 0); | icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_HOST, 0, 0); | ||||
return NULL; | return NULL; | ||||
} | } | ||||
return dst; | |||||
} | |||||
/* | /* | ||||
* 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 route ro; | struct route ro; | ||||
struct sockaddr_in *dst = NULL; | struct sockaddr_in *dst = NULL; | ||||
struct ifnet *ifp; | struct ifnet *ifp; | ||||
struct in_addr odest, dest; | struct in_addr odest, dest; | ||||
uint16_t ip_len, ip_off; | uint16_t ip_len, ip_off; | ||||
int error = 0; | int error = 0; | ||||
int mtu; | int mtu; | ||||
struct nhop_prepend nh; | |||||
struct m_tag *fwd_tag = NULL; | struct m_tag *fwd_tag = NULL; | ||||
/* | /* | ||||
* Are we active and forwarding packets? | * Are we active and forwarding packets? | ||||
*/ | */ | ||||
M_ASSERTVALID(m); | M_ASSERTVALID(m); | ||||
M_ASSERTPKTHDR(m); | M_ASSERTPKTHDR(m); | ||||
▲ Show 20 Lines • Show All 127 Lines • ▼ Show 20 Lines | else | ||||
ip->ip_sum += htons(IPTTLDEC << 8); | ip->ip_sum += htons(IPTTLDEC << 8); | ||||
#ifdef IPSTEALTH | #ifdef IPSTEALTH | ||||
} | } | ||||
#endif | #endif | ||||
/* | /* | ||||
* Find route to destination. | * Find route to destination. | ||||
*/ | */ | ||||
if ((dst = ip_findroute(&ro, dest, m)) == NULL) | if ((dst = ip_findroute(&ro, dest, m, &nh)) == NULL) | ||||
return NULL; /* icmp unreach already sent */ | return NULL; /* icmp unreach already sent */ | ||||
ifp = ro.ro_rt->rt_ifp; | ifp = nh.nh_lifp; | ||||
/* | /* | ||||
* Immediately drop blackholed traffic, and directed broadcasts | * Immediately drop blackholed traffic, and directed broadcasts | ||||
* for either the all-ones or all-zero subnet addresses on | * for either the all-ones or all-zero subnet addresses on | ||||
* locally attached networks. | * locally attached networks. | ||||
*/ | */ | ||||
if ((ro.ro_rt->rt_flags & (RTF_BLACKHOLE|RTF_BROADCAST)) != 0) | if ((nh.nh_flags & (NHF_BLACKHOLE|NHF_BROADCAST)) != 0) | ||||
goto drop; | goto drop; | ||||
/* | /* | ||||
* Step 5: outgoing firewall packet processing | * Step 5: outgoing firewall packet processing | ||||
*/ | */ | ||||
/* | /* | ||||
* Run through list of hooks for output packets. | * Run through list of hooks for output packets. | ||||
Show All 21 Lines | if (odest.s_addr != dest.s_addr || fwd_tag != NULL) { | ||||
* Is it now for a local address on this host? | * Is it now for a local address on this host? | ||||
*/ | */ | ||||
if (m->m_flags & M_FASTFWD_OURS || in_localip(dest)) { | if (m->m_flags & M_FASTFWD_OURS || in_localip(dest)) { | ||||
forwardlocal: | forwardlocal: | ||||
/* | /* | ||||
* Return packet for processing by ip_input(). | * Return packet for processing by ip_input(). | ||||
*/ | */ | ||||
m->m_flags |= M_FASTFWD_OURS; | m->m_flags |= M_FASTFWD_OURS; | ||||
if (ro.ro_rt) | if (ro.ro_rt) { | ||||
RTFREE(ro.ro_rt); | fib4_free_prepend(&nh); | ||||
ro.ro_rt = NULL; | |||||
} | |||||
return m; | return m; | ||||
} | } | ||||
/* | /* | ||||
* Redo route lookup with new destination address | * Redo route lookup with new destination address | ||||
*/ | */ | ||||
if (fwd_tag) { | if (fwd_tag) { | ||||
dest.s_addr = ((struct sockaddr_in *) | dest.s_addr = ((struct sockaddr_in *) | ||||
(fwd_tag + 1))->sin_addr.s_addr; | (fwd_tag + 1))->sin_addr.s_addr; | ||||
m_tag_delete(m, fwd_tag); | m_tag_delete(m, fwd_tag); | ||||
m->m_flags &= ~M_IP_NEXTHOP; | m->m_flags &= ~M_IP_NEXTHOP; | ||||
} | } | ||||
RTFREE(ro.ro_rt); | fib4_free_prepend(&nh); | ||||
if ((dst = ip_findroute(&ro, dest, m)) == NULL) | ro.ro_rt = NULL; | ||||
if ((dst = ip_findroute(&ro, dest, m, &nh)) == NULL) | |||||
return NULL; /* icmp unreach already sent */ | return NULL; /* icmp unreach already sent */ | ||||
ifp = ro.ro_rt->rt_ifp; | ifp = nh.nh_lifp; | ||||
} | } | ||||
passout: | 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); | ||||
/* | /* | ||||
* Check if route is dampned (when ARP is unable to resolve) | * Check if route is dampned (when ARP is unable to resolve) | ||||
*/ | */ | ||||
if ((ro.ro_rt->rt_flags & RTF_REJECT) && | if (nh.nh_flags & NHF_REJECT) { | ||||
(ro.ro_rt->rt_expire == 0 || time_uptime < ro.ro_rt->rt_expire)) { | |||||
icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_HOST, 0, 0); | icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_HOST, 0, 0); | ||||
goto consumed; | goto consumed; | ||||
} | } | ||||
/* | /* | ||||
* Check if media link state of interface is not down | * Check if media link state of interface is not down | ||||
*/ | */ | ||||
if (ifp->if_link_state == LINK_STATE_DOWN) { | if (ifp->if_link_state == LINK_STATE_DOWN) { | ||||
icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_HOST, 0, 0); | icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_HOST, 0, 0); | ||||
goto consumed; | goto consumed; | ||||
} | } | ||||
/* | /* | ||||
* 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 (ro.ro_rt->rt_mtu) | mtu = nh.nh_mtu; | ||||
mtu = min(ro.ro_rt->rt_mtu, ifp->if_mtu); | |||||
else | |||||
mtu = ifp->if_mtu; | |||||
if (ip_len <= mtu) { | if (ip_len <= 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 | ||||
*/ | */ | ||||
▲ Show 20 Lines • Show All 44 Lines • ▼ Show 20 Lines | if (ip_off & IP_DF) { | ||||
} else | } else | ||||
IPSTAT_INC(ips_fragmented); | IPSTAT_INC(ips_fragmented); | ||||
} | } | ||||
} | } | ||||
if (error != 0) | if (error != 0) | ||||
IPSTAT_INC(ips_odropped); | IPSTAT_INC(ips_odropped); | ||||
else { | else { | ||||
counter_u64_add(ro.ro_rt->rt_pksent, 1); | |||||
IPSTAT_INC(ips_forward); | IPSTAT_INC(ips_forward); | ||||
IPSTAT_INC(ips_fastforward); | IPSTAT_INC(ips_fastforward); | ||||
} | } | ||||
consumed: | consumed: | ||||
RTFREE(ro.ro_rt); | fib4_free_prepend(&nh); | ||||
return NULL; | return NULL; | ||||
drop: | drop: | ||||
if (m) | if (m) | ||||
m_freem(m); | m_freem(m); | ||||
if (ro.ro_rt) | if (ro.ro_rt) | ||||
RTFREE(ro.ro_rt); | fib4_free_prepend(&nh); | ||||
return NULL; | return NULL; | ||||
} | } |