Changeset View
Changeset View
Standalone View
Standalone View
sys/netinet6/ip6_output.c
Show First 20 Lines • Show All 89 Lines • ▼ Show 20 Lines | |||||
#include <machine/in_cksum.h> | #include <machine/in_cksum.h> | ||||
#include <net/if.h> | #include <net/if.h> | ||||
#include <net/if_var.h> | #include <net/if_var.h> | ||||
#include <net/if_llatbl.h> | #include <net/if_llatbl.h> | ||||
#include <net/netisr.h> | #include <net/netisr.h> | ||||
#include <net/route.h> | #include <net/route.h> | ||||
#include <net/route/nhop.h> | |||||
#include <net/pfil.h> | #include <net/pfil.h> | ||||
#include <net/rss_config.h> | #include <net/rss_config.h> | ||||
#include <net/vnet.h> | #include <net/vnet.h> | ||||
#include <netinet/in.h> | #include <netinet/in.h> | ||||
#include <netinet/in_var.h> | #include <netinet/in_var.h> | ||||
#include <netinet/ip_var.h> | #include <netinet/ip_var.h> | ||||
#include <netinet6/in6_fib.h> | #include <netinet6/in6_fib.h> | ||||
▲ Show 20 Lines • Show All 292 Lines • ▼ Show 20 Lines | |||||
/* | /* | ||||
* IP6 output. | * IP6 output. | ||||
* The packet in mbuf chain m contains a skeletal IP6 header (with pri, len, | * The packet in mbuf chain m contains a skeletal IP6 header (with pri, len, | ||||
* nxt, hlim, src, dst). | * nxt, hlim, src, dst). | ||||
* This function may modify ver and hlim only. | * This function may modify ver and hlim only. | ||||
* The mbuf chain containing the packet will be freed. | * The mbuf chain containing the packet will be freed. | ||||
* The mbuf opt, if present, will not be freed. | * The mbuf opt, if present, will not be freed. | ||||
* If route_in6 ro is present and has ro_rt initialized, route lookup would be | * If route_in6 ro is present and has ro_nh initialized, route lookup would be | ||||
* skipped and ro->ro_rt would be used. If ro is present but ro->ro_rt is NULL, | * skipped and ro->ro_nh would be used. If ro is present but ro->ro_nh is NULL, | ||||
* then result of route lookup is stored in ro->ro_rt. | * then result of route lookup is stored in ro->ro_nh. | ||||
* | * | ||||
* Type of "mtu": rt_mtu is u_long, ifnet.ifr_mtu is int, and nd_ifinfo.linkmtu | * Type of "mtu": rt_mtu is u_long, ifnet.ifr_mtu is int, and nd_ifinfo.linkmtu | ||||
* is uint32_t. So we use u_long to hold largest one, which is rt_mtu. | * is uint32_t. So we use u_long to hold largest one, which is rt_mtu. | ||||
* | * | ||||
* ifpp - XXX: just for statistics | * ifpp - XXX: just for statistics | ||||
*/ | */ | ||||
/* | /* | ||||
* XXX TODO: no flowid is assigned for outbound flows? | * XXX TODO: no flowid is assigned for outbound flows? | ||||
*/ | */ | ||||
int | int | ||||
ip6_output(struct mbuf *m0, struct ip6_pktopts *opt, | ip6_output(struct mbuf *m0, struct ip6_pktopts *opt, | ||||
struct route_in6 *ro, int flags, struct ip6_moptions *im6o, | struct route_in6 *ro, int flags, struct ip6_moptions *im6o, | ||||
struct ifnet **ifpp, struct inpcb *inp) | struct ifnet **ifpp, struct inpcb *inp) | ||||
{ | { | ||||
struct ip6_hdr *ip6; | struct ip6_hdr *ip6; | ||||
struct ifnet *ifp, *origifp; | struct ifnet *ifp, *origifp; | ||||
struct mbuf *m = m0; | struct mbuf *m = m0; | ||||
struct mbuf *mprev; | struct mbuf *mprev; | ||||
struct route_in6 *ro_pmtu; | struct route_in6 *ro_pmtu; | ||||
struct rtentry *rt; | struct nhop_object *nh; | ||||
struct sockaddr_in6 *dst, sin6, src_sa, dst_sa; | struct sockaddr_in6 *dst, sin6, src_sa, dst_sa; | ||||
struct in6_addr odst; | struct in6_addr odst; | ||||
u_char *nexthdrp; | u_char *nexthdrp; | ||||
int tlen, len; | int tlen, len; | ||||
int error = 0; | int error = 0; | ||||
struct in6_ifaddr *ia = NULL; | struct in6_ifaddr *ia = NULL; | ||||
u_long mtu; | u_long mtu; | ||||
int alwaysfrag, dontfrag; | int alwaysfrag, dontfrag; | ||||
▲ Show 20 Lines • Show All 224 Lines • ▼ Show 20 Lines | if (opt && opt->ip6po_hlim != -1) | ||||
ip6->ip6_hlim = opt->ip6po_hlim & 0xff; | ip6->ip6_hlim = opt->ip6po_hlim & 0xff; | ||||
else if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) { | else if (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) { | ||||
if (im6o != NULL) | if (im6o != NULL) | ||||
ip6->ip6_hlim = im6o->im6o_multicast_hlim; | ip6->ip6_hlim = im6o->im6o_multicast_hlim; | ||||
else | else | ||||
ip6->ip6_hlim = V_ip6_defmcasthlim; | ip6->ip6_hlim = V_ip6_defmcasthlim; | ||||
} | } | ||||
if (ro == NULL || ro->ro_rt == NULL) { | if (ro == NULL || ro->ro_nh == NULL) { | ||||
bzero(dst, sizeof(*dst)); | bzero(dst, sizeof(*dst)); | ||||
dst->sin6_family = AF_INET6; | dst->sin6_family = AF_INET6; | ||||
dst->sin6_len = sizeof(*dst); | dst->sin6_len = sizeof(*dst); | ||||
dst->sin6_addr = ip6->ip6_dst; | dst->sin6_addr = ip6->ip6_dst; | ||||
} | } | ||||
/* | /* | ||||
* Validate route against routing table changes. | * Validate route against routing table changes. | ||||
* Make sure that the address family is set in route. | * Make sure that the address family is set in route. | ||||
*/ | */ | ||||
rt = NULL; | nh = NULL; | ||||
ifp = NULL; | ifp = NULL; | ||||
mtu = 0; | mtu = 0; | ||||
if (ro != NULL) { | if (ro != NULL) { | ||||
if (ro->ro_rt != NULL && inp != NULL) { | if (ro->ro_nh != NULL && inp != NULL) { | ||||
ro->ro_dst.sin6_family = AF_INET6; /* XXX KASSERT? */ | ro->ro_dst.sin6_family = AF_INET6; /* XXX KASSERT? */ | ||||
RT_VALIDATE((struct route *)ro, &inp->inp_rt_cookie, | NH_VALIDATE((struct route *)ro, &inp->inp_rt_cookie, | ||||
fibnum); | fibnum); | ||||
} | } | ||||
if (ro->ro_rt != NULL && fwd_tag == NULL && | if (ro->ro_nh != NULL && fwd_tag == NULL && | ||||
((ro->ro_rt->rt_flags & RTF_UP) == 0 || | (!NH_IS_VALID(ro->ro_nh) || | ||||
ro->ro_rt->rt_ifp == NULL || | |||||
!RT_LINK_IS_UP(ro->ro_rt->rt_ifp) || | |||||
ro->ro_dst.sin6_family != AF_INET6 || | ro->ro_dst.sin6_family != AF_INET6 || | ||||
!IN6_ARE_ADDR_EQUAL(&ro->ro_dst.sin6_addr, &ip6->ip6_dst))) | !IN6_ARE_ADDR_EQUAL(&ro->ro_dst.sin6_addr, &ip6->ip6_dst))) | ||||
RO_INVALIDATE_CACHE(ro); | RO_INVALIDATE_CACHE(ro); | ||||
if (ro->ro_rt != NULL && fwd_tag == NULL && | if (ro->ro_nh != NULL && fwd_tag == NULL && | ||||
(ro->ro_rt->rt_flags & RTF_UP) && | |||||
ro->ro_dst.sin6_family == AF_INET6 && | ro->ro_dst.sin6_family == AF_INET6 && | ||||
IN6_ARE_ADDR_EQUAL(&ro->ro_dst.sin6_addr, &ip6->ip6_dst)) { | IN6_ARE_ADDR_EQUAL(&ro->ro_dst.sin6_addr, &ip6->ip6_dst)) { | ||||
rt = ro->ro_rt; | nh = ro->ro_nh; | ||||
ifp = ro->ro_rt->rt_ifp; | ifp = nh->nh_ifp; | ||||
} else { | } else { | ||||
if (ro->ro_lle) | if (ro->ro_lle) | ||||
LLE_FREE(ro->ro_lle); /* zeros ro_lle */ | LLE_FREE(ro->ro_lle); /* zeros ro_lle */ | ||||
ro->ro_lle = NULL; | ro->ro_lle = NULL; | ||||
if (fwd_tag == NULL) { | if (fwd_tag == NULL) { | ||||
bzero(&dst_sa, sizeof(dst_sa)); | bzero(&dst_sa, sizeof(dst_sa)); | ||||
dst_sa.sin6_family = AF_INET6; | dst_sa.sin6_family = AF_INET6; | ||||
dst_sa.sin6_len = sizeof(dst_sa); | dst_sa.sin6_len = sizeof(dst_sa); | ||||
dst_sa.sin6_addr = ip6->ip6_dst; | dst_sa.sin6_addr = ip6->ip6_dst; | ||||
} | } | ||||
error = in6_selectroute(&dst_sa, opt, im6o, ro, &ifp, | error = in6_selectroute(&dst_sa, opt, im6o, ro, &ifp, | ||||
&rt, fibnum); | &nh, fibnum, m->m_pkthdr.flowid); | ||||
if (error != 0) { | if (error != 0) { | ||||
IP6STAT_INC(ip6s_noroute); | IP6STAT_INC(ip6s_noroute); | ||||
if (ifp != NULL) | if (ifp != NULL) | ||||
in6_ifstat_inc(ifp, ifs6_out_discard); | in6_ifstat_inc(ifp, ifs6_out_discard); | ||||
goto bad; | goto bad; | ||||
} | } | ||||
if (ifp != NULL) | if (ifp != NULL) | ||||
mtu = ifp->if_mtu; | mtu = ifp->if_mtu; | ||||
} | } | ||||
if (rt == NULL) { | if (nh == NULL) { | ||||
/* | /* | ||||
* If in6_selectroute() does not return a route entry | * If in6_selectroute() does not return a nexthop | ||||
* dst may not have been updated. | * dst may not have been updated. | ||||
*/ | */ | ||||
*dst = dst_sa; /* XXX */ | *dst = dst_sa; /* XXX */ | ||||
} else { | } else { | ||||
if (rt->rt_flags & RTF_HOST) | if (nh->nh_flags & NHF_HOST) | ||||
mtu = rt->rt_mtu; | mtu = nh->nh_mtu; | ||||
ia = (struct in6_ifaddr *)(rt->rt_ifa); | ia = (struct in6_ifaddr *)(nh->nh_ifa); | ||||
counter_u64_add(rt->rt_pksent, 1); | counter_u64_add(nh->nh_pksent, 1); | ||||
} | } | ||||
} else { | } else { | ||||
struct nhop6_extended nh6; | struct nhop6_extended nh6; | ||||
struct in6_addr kdst; | struct in6_addr kdst; | ||||
uint32_t scopeid; | uint32_t scopeid; | ||||
if (fwd_tag == NULL) { | if (fwd_tag == NULL) { | ||||
bzero(&dst_sa, sizeof(dst_sa)); | bzero(&dst_sa, sizeof(dst_sa)); | ||||
Show All 34 Lines | if (ro != NULL) { | ||||
mtu = nh6.nh_mtu; | mtu = nh6.nh_mtu; | ||||
dst->sin6_addr = nh6.nh_addr; | dst->sin6_addr = nh6.nh_addr; | ||||
ia = nh6.nh_ia; | ia = nh6.nh_ia; | ||||
fib6_free_nh_ext(fibnum, &nh6); | fib6_free_nh_ext(fibnum, &nh6); | ||||
nonh6lookup: | nonh6lookup: | ||||
; | ; | ||||
} | } | ||||
/* Then rt (for unicast) and ifp must be non-NULL valid values. */ | /* Then nh (for unicast) and ifp must be non-NULL valid values. */ | ||||
if ((flags & IPV6_FORWARDING) == 0) { | if ((flags & IPV6_FORWARDING) == 0) { | ||||
/* XXX: the FORWARDING flag can be set for mrouting. */ | /* XXX: the FORWARDING flag can be set for mrouting. */ | ||||
in6_ifstat_inc(ifp, ifs6_out_request); | in6_ifstat_inc(ifp, ifs6_out_request); | ||||
} | } | ||||
/* Setup data structures for scope ID checks. */ | /* Setup data structures for scope ID checks. */ | ||||
src0 = ip6->ip6_src; | src0 = ip6->ip6_src; | ||||
bzero(&src_sa, sizeof(src_sa)); | bzero(&src_sa, sizeof(src_sa)); | ||||
▲ Show 20 Lines • Show All 54 Lines • ▼ Show 20 Lines | if (in6_setscope(&src0, ifp, &zone) == 0 && | ||||
IP6STAT_INC(ip6s_badscope); | IP6STAT_INC(ip6s_badscope); | ||||
in6_ifstat_inc(ifp, ifs6_out_discard); | in6_ifstat_inc(ifp, ifs6_out_discard); | ||||
if (error == 0) | if (error == 0) | ||||
error = EHOSTUNREACH; /* XXX */ | error = EHOSTUNREACH; /* XXX */ | ||||
goto bad; | goto bad; | ||||
} | } | ||||
/* All scope ID checks are successful. */ | /* All scope ID checks are successful. */ | ||||
if (rt && !IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) { | if (nh && !IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) { | ||||
if (opt && opt->ip6po_nextroute.ro_rt) { | if (opt && opt->ip6po_nextroute.ro_nh) { | ||||
/* | /* | ||||
* The nexthop is explicitly specified by the | * The nexthop is explicitly specified by the | ||||
* application. We assume the next hop is an IPv6 | * application. We assume the next hop is an IPv6 | ||||
* address. | * address. | ||||
*/ | */ | ||||
dst = (struct sockaddr_in6 *)opt->ip6po_nexthop; | dst = (struct sockaddr_in6 *)opt->ip6po_nexthop; | ||||
} | } | ||||
else if ((rt->rt_flags & RTF_GATEWAY)) | else if ((nh->nh_flags & NHF_GATEWAY)) | ||||
dst = (struct sockaddr_in6 *)rt->rt_gateway; | dst = &nh->gw6_sa; | ||||
} | } | ||||
if (!IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) { | if (!IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) { | ||||
m->m_flags &= ~(M_BCAST | M_MCAST); /* Just in case. */ | m->m_flags &= ~(M_BCAST | M_MCAST); /* Just in case. */ | ||||
} else { | } else { | ||||
m->m_flags = (m->m_flags & ~M_BCAST) | M_MCAST; | m->m_flags = (m->m_flags & ~M_BCAST) | M_MCAST; | ||||
in6_ifstat_inc(ifp, ifs6_out_mcast); | in6_ifstat_inc(ifp, ifs6_out_mcast); | ||||
▲ Show 20 Lines • Show All 638 Lines • ▼ Show 20 Lines | if (ro_pmtu == NULL || ro_pmtu->ro_mtu == 0) { | ||||
mtu = nh6.nh_mtu; | mtu = nh6.nh_mtu; | ||||
if (ro_pmtu != NULL) | if (ro_pmtu != NULL) | ||||
ro_pmtu->ro_mtu = mtu; | ro_pmtu->ro_mtu = mtu; | ||||
} | } | ||||
} else | } else | ||||
mtu = ro_pmtu->ro_mtu; | mtu = ro_pmtu->ro_mtu; | ||||
} | } | ||||
if (ro_pmtu != NULL && ro_pmtu->ro_rt != NULL) | if (ro_pmtu != NULL && ro_pmtu->ro_nh != NULL) | ||||
mtu = ro_pmtu->ro_rt->rt_mtu; | mtu = ro_pmtu->ro_nh->nh_mtu; | ||||
return (ip6_calcmtu(ifp, dst, mtu, mtup, alwaysfragp, proto)); | return (ip6_calcmtu(ifp, dst, mtu, mtup, alwaysfragp, proto)); | ||||
} | } | ||||
/* | /* | ||||
* Calculate MTU based on transmit @ifp, route mtu @rt_mtu and | * Calculate MTU based on transmit @ifp, route mtu @rt_mtu and | ||||
* hostcache data for @dst. | * hostcache data for @dst. | ||||
* Stores mtu and always-frag value into @mtup and @alwaysfragp. | * Stores mtu and always-frag value into @mtup and @alwaysfragp. | ||||
▲ Show 20 Lines • Show All 1,116 Lines • ▼ Show 20 Lines | if (pktopt->ip6po_pktinfo) | ||||
free(pktopt->ip6po_pktinfo, M_IP6OPT); | free(pktopt->ip6po_pktinfo, M_IP6OPT); | ||||
pktopt->ip6po_pktinfo = NULL; | pktopt->ip6po_pktinfo = NULL; | ||||
} | } | ||||
if (optname == -1 || optname == IPV6_HOPLIMIT) | if (optname == -1 || optname == IPV6_HOPLIMIT) | ||||
pktopt->ip6po_hlim = -1; | pktopt->ip6po_hlim = -1; | ||||
if (optname == -1 || optname == IPV6_TCLASS) | if (optname == -1 || optname == IPV6_TCLASS) | ||||
pktopt->ip6po_tclass = -1; | pktopt->ip6po_tclass = -1; | ||||
if (optname == -1 || optname == IPV6_NEXTHOP) { | if (optname == -1 || optname == IPV6_NEXTHOP) { | ||||
if (pktopt->ip6po_nextroute.ro_rt) { | if (pktopt->ip6po_nextroute.ro_nh) { | ||||
RTFREE(pktopt->ip6po_nextroute.ro_rt); | NH_FREE(pktopt->ip6po_nextroute.ro_nh); | ||||
pktopt->ip6po_nextroute.ro_rt = NULL; | pktopt->ip6po_nextroute.ro_nh = NULL; | ||||
} | } | ||||
if (pktopt->ip6po_nexthop) | if (pktopt->ip6po_nexthop) | ||||
free(pktopt->ip6po_nexthop, M_IP6OPT); | free(pktopt->ip6po_nexthop, M_IP6OPT); | ||||
pktopt->ip6po_nexthop = NULL; | pktopt->ip6po_nexthop = NULL; | ||||
} | } | ||||
if (optname == -1 || optname == IPV6_HOPOPTS) { | if (optname == -1 || optname == IPV6_HOPOPTS) { | ||||
if (pktopt->ip6po_hbh) | if (pktopt->ip6po_hbh) | ||||
free(pktopt->ip6po_hbh, M_IP6OPT); | free(pktopt->ip6po_hbh, M_IP6OPT); | ||||
pktopt->ip6po_hbh = NULL; | pktopt->ip6po_hbh = NULL; | ||||
} | } | ||||
if (optname == -1 || optname == IPV6_RTHDRDSTOPTS) { | if (optname == -1 || optname == IPV6_RTHDRDSTOPTS) { | ||||
if (pktopt->ip6po_dest1) | if (pktopt->ip6po_dest1) | ||||
free(pktopt->ip6po_dest1, M_IP6OPT); | free(pktopt->ip6po_dest1, M_IP6OPT); | ||||
pktopt->ip6po_dest1 = NULL; | pktopt->ip6po_dest1 = NULL; | ||||
} | } | ||||
if (optname == -1 || optname == IPV6_RTHDR) { | if (optname == -1 || optname == IPV6_RTHDR) { | ||||
if (pktopt->ip6po_rhinfo.ip6po_rhi_rthdr) | if (pktopt->ip6po_rhinfo.ip6po_rhi_rthdr) | ||||
free(pktopt->ip6po_rhinfo.ip6po_rhi_rthdr, M_IP6OPT); | free(pktopt->ip6po_rhinfo.ip6po_rhi_rthdr, M_IP6OPT); | ||||
pktopt->ip6po_rhinfo.ip6po_rhi_rthdr = NULL; | pktopt->ip6po_rhinfo.ip6po_rhi_rthdr = NULL; | ||||
if (pktopt->ip6po_route.ro_rt) { | if (pktopt->ip6po_route.ro_nh) { | ||||
RTFREE(pktopt->ip6po_route.ro_rt); | NH_FREE(pktopt->ip6po_route.ro_nh); | ||||
pktopt->ip6po_route.ro_rt = NULL; | pktopt->ip6po_route.ro_nh = NULL; | ||||
} | } | ||||
} | } | ||||
if (optname == -1 || optname == IPV6_DSTOPTS) { | if (optname == -1 || optname == IPV6_DSTOPTS) { | ||||
if (pktopt->ip6po_dest2) | if (pktopt->ip6po_dest2) | ||||
free(pktopt->ip6po_dest2, M_IP6OPT); | free(pktopt->ip6po_dest2, M_IP6OPT); | ||||
pktopt->ip6po_dest2 = NULL; | pktopt->ip6po_dest2 = NULL; | ||||
} | } | ||||
} | } | ||||
▲ Show 20 Lines • Show All 644 Lines • Show Last 20 Lines |