svn commit: r287059 - in projects/routing/sys: contrib/ipfilter/netinet dev/cxgbe/tom net netgraph netinet netinet6 netipsec netpfil/ipfw netpfil/pf
Alexander V. Chernikov
melifaro at FreeBSD.org
Sun Aug 23 18:23:23 UTC 2015
Author: melifaro
Date: Sun Aug 23 18:23:17 2015
New Revision: 287059
URL: https://svnweb.freebsd.org/changeset/base/287059
Log:
Convert netinet6/ to use new routing API.
* Remove &ifpp from ip6_output() in favor of ri->ri_nh_info
* Provide different wrappers to in6_selectsrc:
Currently it is used by 2 differenct type of customers:
- socket-based one, which all are unsure about provided
address scope and
- in-kernel ones (ND code mostly), which don't have
any sockets, options, crededentials, etc.
So, we provide two different wrappers to in6_selectsrc()
returning select source.
* Make different versions of selectroute():
Currenly selectroute() is used in two scenarios:
- SAS, via in6_selecsrc() -> in6_selectif() -> selectroute()
- output, via in6_output -> wrapper -> selectroute()
Provide different versions for each customer:
- fib6_lookup_nh_basic()-based in6_selectif() which is
capable of returning interface only, without MTU/NHOP/L2
calculations
- full-blown fib6_selectroute() with cached route/multipath/
MTU/L2
* Stop using routing table for link-local address lookups
* Add in6_ifawithifp_lla() to make for-us check faster for link-local
* Add in6_splitscope / in6_setllascope for faster embed/deembed scopes
Modified:
projects/routing/sys/contrib/ipfilter/netinet/ip_fil_freebsd.c
projects/routing/sys/dev/cxgbe/tom/t4_listen.c
projects/routing/sys/net/if_vxlan.c
projects/routing/sys/net/rt_nhops.c
projects/routing/sys/net/rt_nhops.h
projects/routing/sys/netgraph/ng_ipfw.c
projects/routing/sys/netinet/in_gif.c
projects/routing/sys/netinet/ip_carp.c
projects/routing/sys/netinet/ip_divert.c
projects/routing/sys/netinet/ip_output.c
projects/routing/sys/netinet/sctp_os_bsd.h
projects/routing/sys/netinet/tcp_offload.c
projects/routing/sys/netinet/tcp_output.c
projects/routing/sys/netinet/tcp_subr.c
projects/routing/sys/netinet/tcp_syncache.c
projects/routing/sys/netinet/tcp_timewait.c
projects/routing/sys/netinet6/icmp6.c
projects/routing/sys/netinet6/in6.c
projects/routing/sys/netinet6/in6.h
projects/routing/sys/netinet6/in6_gif.c
projects/routing/sys/netinet6/in6_pcb.c
projects/routing/sys/netinet6/in6_src.c
projects/routing/sys/netinet6/ip6_gre.c
projects/routing/sys/netinet6/ip6_mroute.c
projects/routing/sys/netinet6/ip6_output.c
projects/routing/sys/netinet6/ip6_var.h
projects/routing/sys/netinet6/mld6.c
projects/routing/sys/netinet6/nd6_nbr.c
projects/routing/sys/netinet6/raw_ip6.c
projects/routing/sys/netinet6/scope6.c
projects/routing/sys/netinet6/scope6_var.h
projects/routing/sys/netinet6/udp6_usrreq.c
projects/routing/sys/netipsec/ipsec_output.c
projects/routing/sys/netpfil/ipfw/ip_dn_io.c
projects/routing/sys/netpfil/ipfw/ip_fw2.c
projects/routing/sys/netpfil/ipfw/ip_fw_dynamic.c
projects/routing/sys/netpfil/pf/pf.c
Modified: projects/routing/sys/contrib/ipfilter/netinet/ip_fil_freebsd.c
==============================================================================
--- projects/routing/sys/contrib/ipfilter/netinet/ip_fil_freebsd.c Sun Aug 23 18:22:41 2015 (r287058)
+++ projects/routing/sys/contrib/ipfilter/netinet/ip_fil_freebsd.c Sun Aug 23 18:23:17 2015 (r287059)
@@ -756,7 +756,7 @@ ipf_fastroute(m0, mpp, fin, fdp)
* currently "to <if>" and "to <if>:ip#" are not supported
* for IPv6
*/
- return ip6_output(m, NULL, NULL, 0, NULL, NULL, NULL);
+ return ip6_output(m, NULL, NULL, 0, NULL, NULL);
}
#endif
Modified: projects/routing/sys/dev/cxgbe/tom/t4_listen.c
==============================================================================
--- projects/routing/sys/dev/cxgbe/tom/t4_listen.c Sun Aug 23 18:22:41 2015 (r287058)
+++ projects/routing/sys/dev/cxgbe/tom/t4_listen.c Sun Aug 23 18:23:17 2015 (r287059)
@@ -1111,7 +1111,7 @@ get_l2te_for_nexthop(struct port_info *p
}
/* TODO: Multipath */
- if (fib6_lookup_nh_ext(inc->inc_fibnum, inc->inc6_faddr,
+ if (fib6_lookup_nh_ext(inc->inc_fibnum, &inc->inc6_faddr,
0, 0, 0, &nhu.u.nh6) != 0)
return (NULL);
((struct sockaddr_in6 *)dst)->sin6_addr = nhu.u.nh6.nh_addr;
Modified: projects/routing/sys/net/if_vxlan.c
==============================================================================
--- projects/routing/sys/net/if_vxlan.c Sun Aug 23 18:22:41 2015 (r287058)
+++ projects/routing/sys/net/if_vxlan.c Sun Aug 23 18:23:17 2015 (r287059)
@@ -2381,7 +2381,7 @@ vxlan_encap6(struct vxlan_softc *sc, con
mcast = (m->m_flags & (M_MCAST | M_BCAST)) ? 1 : 0;
m->m_flags &= ~(M_MCAST | M_BCAST);
- error = ip6_output(m, NULL, NULL, 0, sc->vxl_im6o, NULL, NULL);
+ error = ip6_output(m, NULL, NULL, 0, sc->vxl_im6o, NULL);
if (error == 0) {
if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1);
if_inc_counter(ifp, IFCOUNTER_OBYTES, len);
Modified: projects/routing/sys/net/rt_nhops.c
==============================================================================
--- projects/routing/sys/net/rt_nhops.c Sun Aug 23 18:22:41 2015 (r287058)
+++ projects/routing/sys/net/rt_nhops.c Sun Aug 23 18:23:17 2015 (r287059)
@@ -66,6 +66,10 @@
#include <netinet/ip_mroute.h>
#include <netinet/ip6.h>
#include <netinet6/in6_var.h>
+#include <netinet6/nd6.h>
+#include <netinet6/scope6_var.h>
+
+#include <net/if_llatbl.h>
#include <net/if_types.h>
#include <netinet/if_ether.h>
@@ -117,11 +121,20 @@ static void fib4_rte_to_nh_extended(stru
static void fib4_rte_to_nh_basic(struct rtentry *rte, struct in_addr dst,
struct nhop4_basic *pnh4);
#endif
-#ifdef INET
-static void fib6_rte_to_nh_extended(struct rtentry *rte, struct in6_addr dst,
+#ifdef INET6
+static void fib6_rte_to_nh_extended(struct rtentry *rte, struct in6_addr *dst,
struct nhop6_extended *pnh6);
-static void fib6_rte_to_nh_basic(struct rtentry *rte, struct in6_addr dst,
+static void fib6_rte_to_nh_basic(struct rtentry *rte, const struct in6_addr *dst,
struct nhop6_basic *pnh6);
+static int fib6_storelladdr(struct ifnet *ifp, struct in6_addr *dst,
+ int mm_flags, u_char *desten);
+static uint16_t fib6_get_ifa(struct rtentry *rte);
+static int fib6_lla_to_nh_basic(const struct in6_addr *dst, uint32_t scopeid,
+ struct nhop6_basic *pnh6);
+static int fib6_lla_to_nh_extended(struct in6_addr *dst, uint32_t scopeid,
+ struct nhop6_extended *pnh6);
+static int fib6_lla_to_nh(struct in6_addr *dst, uint32_t scopeid,
+ struct nhop_prepend *nh, struct ifnet **lifp);
#endif
MALLOC_DEFINE(M_RTFIB, "rtfib", "routing fwd");
@@ -292,8 +305,11 @@ fib4_lookup_prepend(uint32_t fibnum, str
* Currently all we have is rte ifp.
* Simply use it.
*/
- lifp = rte->rt_ifp;
+ /* Save interface address ifp */
+ lifp = rte->rt_ifa->ifa_ifp;
+ nh->aifp_idx = lifp->if_index;
/* Save both logical and transmit interface indexes */
+ lifp = rte->rt_ifp;
nh->lifp_idx = lifp->if_index;
nh->i.ifp_idx = nh->lifp_idx;
@@ -407,6 +423,7 @@ fib4_rte_to_nh_basic(struct rtentry *rte
gw = (struct sockaddr_in *)rt_key(rte);
if (gw->sin_addr.s_addr == 0)
pnh4->nh_flags |= NHF_DEFAULT;
+ /* XXX: Set RTF_BROADCAST if GW address is broadcast */
}
static void
@@ -428,6 +445,7 @@ fib4_rte_to_nh_extended(struct rtentry *
gw = (struct sockaddr_in *)rt_key(rte);
if (gw->sin_addr.s_addr == 0)
pnh4->nh_flags |= NHF_DEFAULT;
+ /* XXX: Set RTF_BROADCAST if GW address is broadcast */
ia = ifatoia(rte->rt_ifa);
pnh4->nh_src = IA_SIN(ia)->sin_addr;
@@ -570,19 +588,335 @@ fib6_choose_prepend(uint32_t fibnum, str
*/
}
+/*
+ * Temporary function to copy ethernet address from valid lle
+ */
+static int
+fib6_storelladdr(struct ifnet *ifp, struct in6_addr *dst, int mm_flags,
+ u_char *desten)
+{
+ struct llentry *ln;
+ struct sockaddr_in6 dst_sa;
+
+ if (mm_flags & M_MCAST) {
+ ETHER_MAP_IPV6_MULTICAST(&dst, desten);
+ return (0);
+ }
+
+ memset(&dst_sa, 0, sizeof(dst_sa));
+ dst_sa.sin6_family = AF_INET6;
+ dst_sa.sin6_len = sizeof(dst_sa);
+ dst_sa.sin6_addr = *dst;
+ dst_sa.sin6_scope_id = ifp->if_index;
+
+
+ /*
+ * the entry should have been created in nd6_store_lladdr
+ */
+ IF_AFDATA_RLOCK(ifp);
+ ln = lla_lookup(LLTABLE6(ifp), 0, (struct sockaddr *)&dst_sa);
+
+ /*
+ * Perform fast path for the following cases:
+ * 1) lle state is REACHABLE
+ * 2) lle state is DELAY (NS message sentNS message sent)
+ *
+ * Every other case involves lle modification, so we handle
+ * them separately.
+ */
+ if (ln == NULL || (ln->ln_state != ND6_LLINFO_REACHABLE &&
+ ln->ln_state != ND6_LLINFO_DELAY)) {
+ if (ln != NULL)
+ LLE_RUNLOCK(ln);
+ IF_AFDATA_RUNLOCK(ifp);
+ return (1);
+ }
+ bcopy(&ln->ll_addr, desten, ifp->if_addrlen);
+ LLE_RUNLOCK(ln);
+ IF_AFDATA_RUNLOCK(ifp);
+
+ return (0);
+}
+
+int
+fib6_lookup_prepend(uint32_t fibnum, struct in6_addr *dst, uint32_t scopeid,
+ struct mbuf *m, struct nhop_prepend *nh, struct nhop6_extended *nh_ext)
+{
+ struct radix_node_head *rnh;
+ struct radix_node *rn;
+ struct sockaddr_in6 sin6, *gw_sa;
+ struct in6_addr gw6;
+ struct rtentry *rte;
+ struct ifnet *lifp;
+ struct ether_header *eh;
+ uint32_t flags;
+ int error;
+
+ if (IN6_IS_SCOPE_LINKLOCAL(dst)) {
+ /* Do not lookup link-local addresses in rtable */
+ error = fib6_lla_to_nh(dst, scopeid, nh, &lifp);
+ if (error != 0)
+ return (error);
+ /* */
+ gw6 = *dst;
+ goto do_l2;
+ }
+
+
+ KASSERT((fibnum < rt_numfibs), ("fib6_lookup_prepend: bad fibnum"));
+ rnh = rt_tables_get_rnh(fibnum, AF_INET6);
+ if (rnh == NULL)
+ return (ENOENT);
+
+ /* Prepare lookup key */
+ memset(&sin6, 0, sizeof(sin6));
+ sin6.sin6_len = sizeof(struct sockaddr_in6);
+ sin6.sin6_addr = *dst;
+ sin6.sin6_scope_id = scopeid;
+ sa6_embedscope(&sin6, 0);
+
+
+ RADIX_NODE_HEAD_RLOCK(rnh);
+ rn = rnh->rnh_matchaddr((void *)&sin6, rnh);
+ rte = RNTORT(rn);
+ if (rn == NULL || ((rn->rn_flags & RNF_ROOT) != 0) ||
+ RT_LINK_IS_UP(rte->rt_ifp) == 0) {
+ RADIX_NODE_HEAD_RUNLOCK(rnh);
+ return (EHOSTUNREACH);
+ }
+
+ /* Explicitly zero nexthop */
+ memset(nh, 0, sizeof(*nh));
+ flags = 0;
+ nh->nh_mtu = min(rte->rt_mtu, IN6_LINKMTU(rte->rt_ifp));
+ if (rte->rt_flags & RTF_GATEWAY) {
+ gw_sa = (struct sockaddr_in6 *)rte->rt_gateway;
+ gw6 = gw_sa->sin6_addr;
+ in6_clearscope(&gw6);
+ } else
+ gw6 = *dst;
+ /* Set flags */
+ flags = fib_rte_to_nh_flags(rte->rt_flags);
+ gw_sa = (struct sockaddr_in6 *)rt_key(rte);
+ if (IN6_IS_ADDR_UNSPECIFIED(&gw_sa->sin6_addr))
+ flags |= NHF_DEFAULT;
+
+ /*
+ * TODO: nh L2/L3 resolve.
+ * Currently all we have is rte ifp.
+ * Simply use it.
+ */
+ /* Save interface address ifp */
+ nh->aifp_idx = fib6_get_ifa(rte);
+ /* Save both logical and transmit interface indexes */
+ lifp = rte->rt_ifp;
+ nh->lifp_idx = lifp->if_index;
+ nh->i.ifp_idx = nh->lifp_idx;
+
+ RADIX_NODE_HEAD_RUNLOCK(rnh);
+
+ nh->nh_flags = flags;
+do_l2:
+ /*
+ * Try to lookup L2 info.
+ * Do this using separate LLE locks.
+ * TODO: move this under radix lock.
+ */
+ if (lifp->if_type == IFT_ETHER) {
+ eh = (struct ether_header *)nh->d.data;
+
+ /*
+ * Fill in ethernet header.
+ * It should be already presented if we're
+ * sending data via known gateway.
+ */
+ error = fib6_storelladdr(lifp, &gw6, m ? m->m_flags : 0,
+ eh->ether_dhost);
+ if (error == 0) {
+ memcpy(&eh->ether_shost, IF_LLADDR(lifp), ETHER_ADDR_LEN);
+ eh->ether_type = htons(ETHERTYPE_IPV6);
+ nh->nh_count = ETHER_HDR_LEN;
+ return (0);
+ }
+ }
+
+ /* Notify caller that no L2 info is linked */
+ nh->nh_count = 0;
+ nh->nh_flags |= NHF_L2_INCOMPLETE;
+ /* ..And save gateway address */
+ nh->d.gw6 = gw6;
+ return (0);
+}
+
+int
+fib6_sendmbuf(struct ifnet *ifp, struct ifnet *origifp, struct mbuf *m,
+ struct nhop_prepend *nh)
+{
+ int error;
+
+ if (nh != NULL && (nh->nh_flags & NHF_L2_INCOMPLETE) == 0) {
+
+ /*
+ * Fast path case. Most packets should
+ * be sent from here.
+ * TODO: Make special ifnet
+ * 'if_output_frame' handler for that.
+ */
+ struct route_compat rc;
+ struct ether_header *eh;
+ rc.ro_flags = AF_INET6 << 8 | RT_NHOP;
+ rc.ro_nh = nh;
+
+ M_PREPEND(m, nh->nh_count, M_NOWAIT);
+ if (m == NULL)
+ return (ENOBUFS);
+ eh = mtod(m, struct ether_header *);
+ memcpy(eh, nh->d.data, nh->nh_count);
+ error = (*ifp->if_output)(ifp, m,
+ NULL, (struct route *)&rc);
+ } else {
+ /* We need to perform ND lookup */
+ struct sockaddr_in6 gw_out;
+
+ memset(&gw_out, 0, sizeof(gw_out));
+ gw_out.sin6_family = AF_INET6;
+ gw_out.sin6_len = sizeof(gw_out);
+ gw_out.sin6_addr = nh->d.gw6;
+ gw_out.sin6_scope_id = ifp->if_index;
+ sa6_embedscope(&gw_out, 0);
+
+ error = nd6_output(ifp, origifp, m, &gw_out, NULL);
+ }
+
+ return (error);
+}
+
+static uint16_t
+fib6_get_ifa(struct rtentry *rte)
+{
+ struct ifnet *ifp;
+ struct sockaddr_dl *sdl;
+
+ ifp = rte->rt_ifp;
+ if ((ifp->if_flags & IFF_LOOPBACK) &&
+ rte->rt_gateway->sa_family == AF_LINK) {
+ sdl = (struct sockaddr_dl *)rte->rt_gateway;
+ return (sdl->sdl_index);
+ }
+
+ return (ifp->if_index);
+#if 0
+ /* IPv6 case */
+ /* Alternative way to get interface address ifp */
+ /*
+ * Adjust the "outgoing" interface. If we're going to loop
+ * the packet back to ourselves, the ifp would be the loopback
+ * interface. However, we'd rather know the interface associated
+ * to the destination address (which should probably be one of
+ * our own addresses.)
+ */
+ if (rt) {
+ if ((rt->rt_ifp->if_flags & IFF_LOOPBACK) &&
+ (rt->rt_gateway->sa_family == AF_LINK))
+ *retifp =
+ ifnet_byindex(((struct sockaddr_dl *)
+ rt->rt_gateway)->sdl_index);
+ }
+ /* IPv4 case */
+ //pnh6->nh_ifp = rte->rt_ifa->ifa_ifp;
+#endif
+}
+
+static int
+fib6_lla_to_nh_basic(const struct in6_addr *dst, uint32_t scopeid,
+ struct nhop6_basic *pnh6)
+{
+ struct ifnet *ifp;
+
+ ifp = ifnet_byindex_locked(scopeid);
+ if (ifp == NULL)
+ return (ENOENT);
+
+ /* Do explicit nexthop zero unless we're copying it */
+ memset(pnh6, 0, sizeof(*pnh6));
+
+ pnh6->nh_ifp = ifp;
+ pnh6->nh_mtu = IN6_LINKMTU(ifp);
+ /* No flags set */
+ pnh6->nh_addr = *dst;
+
+ return (0);
+}
+
+static int
+fib6_lla_to_nh_extended(struct in6_addr *dst, uint32_t scopeid,
+ struct nhop6_extended *pnh6)
+{
+ struct ifnet *ifp;
+
+ ifp = ifnet_byindex_locked(scopeid);
+ if (ifp == NULL)
+ return (ENOENT);
+
+ /* Do explicit nexthop zero unless we're copying it */
+ memset(pnh6, 0, sizeof(*pnh6));
+
+ pnh6->nh_ifp = ifp;
+ pnh6->nh_mtu = IN6_LINKMTU(ifp);
+ /* No flags set */
+ pnh6->nh_addr = *dst;
+
+ return (0);
+}
+
+static int
+fib6_lla_to_nh(struct in6_addr *dst, uint32_t scopeid,
+ struct nhop_prepend *nh, struct ifnet **lifp)
+{
+ struct ifnet *ifp;
+
+ ifp = ifnet_byindex_locked(scopeid);
+ if (ifp == NULL)
+ return (ENOENT);
+
+ /* Do explicit nexthop zero unless we're copying it */
+ memset(nh, 0, sizeof(*nh));
+ /* No flags set */
+ nh->nh_mtu = IN6_LINKMTU(ifp);
+
+ /* Save lifp */
+ *lifp = ifp;
+
+ nh->aifp_idx = scopeid;
+ nh->lifp_idx = scopeid;
+ /* Check id this is for-us address */
+ if (in6_ifawithifp_lla(ifp, dst)) {
+ if ((ifp = V_loif) != NULL)
+ nh->lifp_idx = ifp->if_index;
+ }
+
+ return (0);
+}
+
+
static void
-fib6_rte_to_nh_basic(struct rtentry *rte, struct in6_addr dst,
+fib6_rte_to_nh_basic(struct rtentry *rte, const struct in6_addr *dst,
struct nhop6_basic *pnh6)
{
struct sockaddr_in6 *gw;
- pnh6->nh_ifp = rte->rt_ifa->ifa_ifp;
- pnh6->nh_mtu = min(rte->rt_mtu, rte->rt_ifp->if_mtu);
+ /* Do explicit nexthop zero unless we're copying it */
+ memset(pnh6, 0, sizeof(*pnh6));
+
+ pnh6->nh_ifp = ifnet_byindex(fib6_get_ifa(rte));
+
+ pnh6->nh_mtu = min(rte->rt_mtu, IN6_LINKMTU(rte->rt_ifp));
if (rte->rt_flags & RTF_GATEWAY) {
gw = (struct sockaddr_in6 *)rte->rt_gateway;
pnh6->nh_addr = gw->sin6_addr;
+ in6_clearscope(&pnh6->nh_addr);
} else
- pnh6->nh_addr = dst;
+ pnh6->nh_addr = *dst;
/* Set flags */
pnh6->nh_flags = fib_rte_to_nh_flags(rte->rt_flags);
gw = (struct sockaddr_in6 *)rt_key(rte);
@@ -591,19 +925,23 @@ fib6_rte_to_nh_basic(struct rtentry *rte
}
static void
-fib6_rte_to_nh_extended(struct rtentry *rte, struct in6_addr dst,
+fib6_rte_to_nh_extended(struct rtentry *rte, struct in6_addr *dst,
struct nhop6_extended *pnh6)
{
struct sockaddr_in6 *gw;
struct in6_ifaddr *ia;
- pnh6->nh_ifp = rte->rt_ifa->ifa_ifp;
- pnh6->nh_mtu = min(rte->rt_mtu, rte->rt_ifp->if_mtu);
+ /* Do explicit nexthop zero unless we're copying it */
+ memset(pnh6, 0, sizeof(*pnh6));
+
+ pnh6->nh_ifp = ifnet_byindex(fib6_get_ifa(rte));
+ pnh6->nh_mtu = min(rte->rt_mtu, IN6_LINKMTU(rte->rt_ifp));
if (rte->rt_flags & RTF_GATEWAY) {
gw = (struct sockaddr_in6 *)rte->rt_gateway;
pnh6->nh_addr = gw->sin6_addr;
+ in6_clearscope(&pnh6->nh_addr);
} else
- pnh6->nh_addr = dst;
+ pnh6->nh_addr = *dst;
/* Set flags */
pnh6->nh_flags = fib_rte_to_nh_flags(rte->rt_flags);
gw = (struct sockaddr_in6 *)rt_key(rte);
@@ -611,18 +949,22 @@ fib6_rte_to_nh_extended(struct rtentry *
pnh6->nh_flags |= NHF_DEFAULT;
ia = ifatoia6(rte->rt_ifa);
- pnh6->nh_src = IA6_SIN6(ia)->sin6_addr;
}
int
-fib6_lookup_nh_basic(uint32_t fibnum, struct in6_addr dst, uint32_t flowid,
- struct nhop6_basic *pnh6)
+fib6_lookup_nh_basic(uint32_t fibnum, const struct in6_addr *dst, uint32_t scopeid,
+ uint32_t flowid, struct nhop6_basic *pnh6)
{
struct radix_node_head *rnh;
struct radix_node *rn;
struct sockaddr_in6 sin6;
struct rtentry *rte;
+ if (IN6_IS_SCOPE_LINKLOCAL(dst)) {
+ /* Do not lookup link-local addresses in rtable */
+ return (fib6_lla_to_nh_basic(dst, scopeid, pnh6));
+ }
+
KASSERT((fibnum < rt_numfibs), ("fib6_lookup_nh_basic: bad fibnum"));
rnh = rt_tables_get_rnh(fibnum, AF_INET6);
if (rnh == NULL)
@@ -630,7 +972,9 @@ fib6_lookup_nh_basic(uint32_t fibnum, st
/* Prepare lookup key */
memset(&sin6, 0, sizeof(sin6));
- sin6.sin6_addr = dst;
+ sin6.sin6_addr = *dst;
+ sin6.sin6_scope_id = scopeid;
+ sa6_embedscope(&sin6, 0);
RADIX_NODE_HEAD_RLOCK(rnh);
rn = rnh->rnh_matchaddr((void *)&sin6, rnh);
@@ -658,7 +1002,7 @@ fib6_lookup_nh_basic(uint32_t fibnum, st
* - mtu from logical transmit interface will be returned.
*/
int
-fib6_lookup_nh_ext(uint32_t fibnum, struct in6_addr dst, uint32_t scopeid,
+fib6_lookup_nh_ext(uint32_t fibnum, struct in6_addr *dst, uint32_t scopeid,
uint32_t flowid, uint32_t flags, struct nhop6_extended *pnh6)
{
struct radix_node_head *rnh;
@@ -666,6 +1010,12 @@ fib6_lookup_nh_ext(uint32_t fibnum, stru
struct sockaddr_in6 sin6;
struct rtentry *rte;
+ if (IN6_IS_SCOPE_LINKLOCAL(dst)) {
+ /* Do not lookup link-local addresses in rtable */
+ /* XXX: Do lwref on egress ifp */
+ return (fib6_lla_to_nh_extended(dst, scopeid, pnh6));
+ }
+
KASSERT((fibnum < rt_numfibs), ("fib4_lookup_nh_ext: bad fibnum"));
rnh = rt_tables_get_rnh(fibnum, AF_INET6);
if (rnh == NULL)
@@ -674,7 +1024,9 @@ fib6_lookup_nh_ext(uint32_t fibnum, stru
/* Prepare lookup key */
memset(&sin6, 0, sizeof(sin6));
sin6.sin6_len = sizeof(struct sockaddr_in6);
- sin6.sin6_addr = dst;
+ sin6.sin6_addr = *dst;
+ sin6.sin6_scope_id = scopeid;
+ sa6_embedscope(&sin6, 0);
RADIX_NODE_HEAD_RLOCK(rnh);
rn = rnh->rnh_matchaddr((void *)&sin6, rnh);
@@ -702,15 +1054,6 @@ fib6_free_nh_ext(uint32_t fibnum, struct
}
-void
-fib6_source_to_sa_ext(const struct nhopu_extended *pnhu,
- struct sockaddr_in6 *sin6)
-{
-
- sin6->sin6_family = AF_INET6;
- sin6->sin6_len = sizeof(*sin6);
- sin6->sin6_addr = pnhu->u.nh6.nh_src;
-}
#endif
void
Modified: projects/routing/sys/net/rt_nhops.h
==============================================================================
--- projects/routing/sys/net/rt_nhops.h Sun Aug 23 18:22:41 2015 (r287058)
+++ projects/routing/sys/net/rt_nhops.h Sun Aug 23 18:23:17 2015 (r287059)
@@ -74,7 +74,8 @@ struct nhop_prepend {
uint16_t ifp_idx; /* Transmit interface index */
uint16_t nhop_idx; /* L2 multipath nhop index */
} i;
- uint16_t spare1[3];
+ uint16_t aifp_idx; /* Interface address index */
+ uint16_t spare1[2];
union {
char data[MAX_PREPEND_LEN]; /* data to prepend */
#ifdef INET
@@ -102,6 +103,7 @@ struct nhop_prepend {
#define NH_LIFP(nh) ifnet_byindex_locked((nh)->lifp_idx)
#define NH_TIFP(nh) ifnet_byindex_locked((nh)->i.ifp_idx)
+#define NH_AIFP(nh) ifnet_byindex_locked((nh)->aifp_idx)
/* L2/L3 recursive nexthop */
struct nhop_multi {
@@ -173,7 +175,6 @@ struct nhop6_extended {
uint16_t nh_flags; /* nhop flags */
uint8_t spare[4];
struct in6_addr nh_addr; /* GW/DST IPv6 address */
- struct in6_addr nh_src; /* default source IPv6 address */
uint64_t spare2[2];
};
@@ -186,9 +187,10 @@ struct nhopu_extended {
struct route_info {
struct nhop_prepend *ri_nh; /* Desired nexthop to use */
- struct nhop64_basic *ri_nh_info; /* Get selected route info */
- uint16_t ri_mtu;
- uint16_t spare[3];
+ struct nhopu_basic *ri_nh_info; /* Get selected route info */
+ uint16_t ri_mtu; /* Get selected route MTU */
+ uint16_t spare;
+ uint32_t scopeid; /* Desired scope id to use */
};
struct route_compat {
@@ -208,14 +210,12 @@ void fib4_source_to_sa_ext(const struct
struct sockaddr_in *sin);
-int fib6_lookup_nh_basic(uint32_t fibnum, struct in6_addr dst, uint32_t flowid,
- struct nhop6_basic *pnh6);
-int fib6_lookup_nh_ext(uint32_t fibnum, struct in6_addr dst,
+int fib6_lookup_nh_basic(uint32_t fibnum, const struct in6_addr *dst,
+ uint32_t scopeid, uint32_t flowid, struct nhop6_basic *pnh6);
+int fib6_lookup_nh_ext(uint32_t fibnum, struct in6_addr *dst,
uint32_t scopeid, uint32_t flowid, uint32_t flags,
struct nhop6_extended *pnh6);
void fib6_free_nh_ext(uint32_t fibnum, struct nhop6_extended *pnh6);
-void fib6_source_to_sa_ext(const struct nhopu_extended *pnhu,
- struct sockaddr_in6 *sin6);
void fib_free_nh_ext(uint32_t fibnum, struct nhopu_extended *pnhu);
@@ -232,6 +232,11 @@ int fib4_sendmbuf(struct ifnet *ifp, str
void fib6_free_nh_prepend(uint32_t fibnum, struct nhop_prepend *nh);
void fib6_choose_prepend(uint32_t fibnum, struct nhop_prepend *nh_src,
uint32_t flowid, struct nhop_prepend *nh, struct nhop6_extended *nh_ext);
+int fib6_lookup_prepend(uint32_t fibnum, struct in6_addr *dst, uint32_t scopeid,
+ struct mbuf *m, struct nhop_prepend *nh, struct nhop6_extended *nh_ext);
+
+int fib6_sendmbuf(struct ifnet *ifp, struct ifnet *origifp, struct mbuf *m,
+ struct nhop_prepend *nh);
#define FWD_INET 0
#define FWD_INET6 1
Modified: projects/routing/sys/netgraph/ng_ipfw.c
==============================================================================
--- projects/routing/sys/netgraph/ng_ipfw.c Sun Aug 23 18:22:41 2015 (r287058)
+++ projects/routing/sys/netgraph/ng_ipfw.c Sun Aug 23 18:23:17 2015 (r287059)
@@ -271,8 +271,7 @@ ng_ipfw_rcvdata(hook_p hook, item_p item
#endif
#ifdef INET6
case IPV6_VERSION >> 4:
- return (ip6_output(m, NULL, NULL, 0, NULL,
- NULL, NULL));
+ return (ip6_output(m, NULL, NULL, 0, NULL, NULL));
#endif
}
}
Modified: projects/routing/sys/netinet/in_gif.c
==============================================================================
--- projects/routing/sys/netinet/in_gif.c Sun Aug 23 18:22:41 2015 (r287058)
+++ projects/routing/sys/netinet/in_gif.c Sun Aug 23 18:23:17 2015 (r287059)
@@ -61,6 +61,8 @@ __FBSDID("$FreeBSD$");
#include <netinet/ip_encap.h>
#include <netinet/ip_ecn.h>
+#include <net/rt_nhops.h>
+
#ifdef INET6
#include <netinet/ip6.h>
#endif
@@ -188,22 +190,13 @@ in_gif_encapcheck(const struct mbuf *m,
/* ingress filters on outer source */
if ((GIF2IFP(sc)->if_flags & IFF_LINK2) == 0) {
- struct sockaddr_in sin;
- struct rtentry *rt;
+ struct nhop4_basic nh4;
- bzero(&sin, sizeof(sin));
- sin.sin_family = AF_INET;
- sin.sin_len = sizeof(struct sockaddr_in);
- sin.sin_addr = ip->ip_src;
- /* XXX MRT check for the interface we would use on output */
- rt = in_rtalloc1((struct sockaddr *)&sin, 0,
- 0UL, sc->gif_fibnum);
- if (rt == NULL || rt->rt_ifp != m->m_pkthdr.rcvif) {
- if (rt != NULL)
- RTFREE_LOCKED(rt);
+ if (fib4_lookup_nh_basic(sc->gif_fibnum, ip->ip_src, 0,
+ &nh4) != 0)
+ return (0);
+ if (nh4.nh_ifp != m->m_pkthdr.rcvif)
return (0);
- }
- RTFREE_LOCKED(rt);
}
return (ret);
}
Modified: projects/routing/sys/netinet/ip_carp.c
==============================================================================
--- projects/routing/sys/netinet/ip_carp.c Sun Aug 23 18:22:41 2015 (r287058)
+++ projects/routing/sys/netinet/ip_carp.c Sun Aug 23 18:23:17 2015 (r287059)
@@ -921,7 +921,7 @@ carp_send_ad_locked(struct carp_softc *s
CARPSTATS_INC(carps_opackets6);
carp_send_ad_error(sc, ip6_output(m, NULL, NULL, 0,
- &sc->sc_carpdev->if_carp->cif_im6o, NULL, NULL));
+ &sc->sc_carpdev->if_carp->cif_im6o, NULL));
}
#endif /* INET6 */
Modified: projects/routing/sys/netinet/ip_divert.c
==============================================================================
--- projects/routing/sys/netinet/ip_divert.c Sun Aug 23 18:22:41 2015 (r287058)
+++ projects/routing/sys/netinet/ip_divert.c Sun Aug 23 18:23:17 2015 (r287059)
@@ -456,7 +456,7 @@ div_output(struct socket *so, struct mbu
break;
#ifdef INET6
case IPV6_VERSION >> 4:
- error = ip6_output(m, NULL, NULL, 0, NULL, NULL, NULL);
+ error = ip6_output(m, NULL, NULL, 0, NULL, NULL);
break;
#endif
}
Modified: projects/routing/sys/netinet/ip_output.c
==============================================================================
--- projects/routing/sys/netinet/ip_output.c Sun Aug 23 18:22:41 2015 (r287058)
+++ projects/routing/sys/netinet/ip_output.c Sun Aug 23 18:23:17 2015 (r287059)
@@ -200,9 +200,13 @@ ip_output_pfil(struct mbuf *m, struct if
* header (with len, off, ttl, proto, tos, src, dst).
* The mbuf chain containing the packet will be freed.
* The mbuf opt, if present, will not be freed.
- * If route ro is present and has ro_rt initialized, route lookup would be
- * skipped and ro->ro_rt would be used. If ro is present but ro->ro_rt is NULL,
- * then result of route lookup is stored in ro->ro_rt.
+ *
+ * If @ri is present:
+ * - if ri->ri_nh is not null, route will be calculated using ri_nh.
+ * - if ri->ri_nh_info is set, nhop4_basic route info will be stored on
+ * successful transmit (error=0).
+ * - ri->ri_mtu will be set if packet fails to be transmitted due to MTU
+ * issues
*
* In the IP forwarding case, the packet will arrive with options already
* inserted, so must have a NULL opt pointer.
@@ -407,19 +411,12 @@ again:
nh = &local_nh;
ifp = NH_LIFP(nh);
mtu = nh->nh_mtu;
- if (nh->nh_flags & (RTF_HOST|RTF_GATEWAY)) {
- /* XXX: Set RTF_BROADCAST if GW address is broadcast */
+ if (nh->nh_flags & (RTF_HOST|RTF_GATEWAY))
isbroadcast = (nh->nh_flags & RTF_BROADCAST);
- } else
+ else
isbroadcast = in_broadcast(dst, ifp);
}
- /*
- * XXX: Move somewhere to sendit
- */
- if (ri != NULL)
- ri->ri_mtu = mtu;
-
/* Catch a possible divide by zero later. */
KASSERT(mtu > 0, ("%s: mtu %d <= 0, rte=%p (rt_flags=0x%08x) ifp=%p",
__func__, mtu, nh, (nh != NULL) ? nh->nh_flags : 0, ifp));
@@ -586,6 +583,20 @@ sendit:
}
}
+ if (ri != NULL) {
+ ri->ri_mtu = mtu;
+ if (ri->ri_nh_info != NULL) {
+ struct nhop4_basic *pnh4;
+
+ pnh4 = &ri->ri_nh_info->u.nh4;
+ pnh4->nh_ifp = ifp;
+ pnh4->nh_flags = nh ? nh->nh_flags : 0;
+ pnh4->nh_mtu = mtu;
+ /* XXX: This is not always correct. */
+ pnh4->nh_addr = dst;
+ }
+ }
+
/* 127/8 must not appear on wire - RFC1122. */
if ((ntohl(ip->ip_dst.s_addr) >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET ||
(ntohl(ip->ip_src.s_addr) >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET) {
Modified: projects/routing/sys/netinet/sctp_os_bsd.h
==============================================================================
--- projects/routing/sys/netinet/sctp_os_bsd.h Sun Aug 23 18:22:41 2015 (r287058)
+++ projects/routing/sys/netinet/sctp_os_bsd.h Sun Aug 23 18:23:17 2015 (r287059)
@@ -447,9 +447,9 @@ typedef struct rtentry sctp_rtentry_t;
if (local_stcb && local_stcb->sctp_ep) \
result = ip6_output(o_pak, \
((struct in6pcb *)(local_stcb->sctp_ep))->in6p_outputopts, \
- (ro), 0, 0, ifp, NULL); \
+ NULL, 0, NULL, NULL); \
else \
- result = ip6_output(o_pak, NULL, (ro), 0, 0, ifp, NULL); \
+ result = ip6_output(o_pak, NULL, NULL, 0, NULL, NULL); \
}
struct mbuf *
Modified: projects/routing/sys/netinet/tcp_offload.c
==============================================================================
--- projects/routing/sys/netinet/tcp_offload.c Sun Aug 23 18:22:41 2015 (r287058)
+++ projects/routing/sys/netinet/tcp_offload.c Sun Aug 23 18:23:17 2015 (r287059)
@@ -48,6 +48,7 @@ __FBSDID("$FreeBSD$");
#define TCPOUTFLAGS
#include <netinet/tcp_fsm.h>
#include <netinet/toecore.h>
+#include <netinet6/scope6_var.h>
int registered_toedevs;
@@ -86,11 +87,13 @@ tcp_offload_connect(struct socket *so, s
goto done;
} else if (af == AF_INET6) {
struct sockaddr_in6 *sin6;
+ struct in6_addr dst;
+ uint32_t scopeid;
sin6 = (struct sockaddr_in6 *)nam;
+ in6_splitscope(&sin6->sin6_addr, &dst, &scopeid);
- if (fib6_lookup_nh_ext(fibnum,
- sin6->sin6_addr, sin6->sin6_scope_id,
+ if (fib6_lookup_nh_ext(fibnum, &dst, scopeid,
0, NHOP_LOOKUP_REF, &nhu_ext.u.nh6) != 0)
return (EHOSTUNREACH);
Modified: projects/routing/sys/netinet/tcp_output.c
==============================================================================
--- projects/routing/sys/netinet/tcp_output.c Sun Aug 23 18:22:41 2015 (r287058)
+++ projects/routing/sys/netinet/tcp_output.c Sun Aug 23 18:23:17 2015 (r287059)
@@ -1268,9 +1268,9 @@ send:
*/
#ifdef INET6
if (isipv6) {
- struct route_in6 ro;
+ struct route_info ri;
- bzero(&ro, sizeof(ro));
+ bzero(&ri, sizeof(ri));
/*
* we separately set hoplimit for every segment, since the
* user might want to change the value via setsockopt.
@@ -1297,13 +1297,12 @@ send:
TCP_PROBE5(send, NULL, tp, ip6, tp, th);
/* TODO: IPv6 IP6TOS_ECT bit on */
- error = ip6_output(m, tp->t_inpcb->in6p_outputopts, &ro,
+ error = ip6_output(m, tp->t_inpcb->in6p_outputopts, &ri,
((so->so_options & SO_DONTROUTE) ? IP_ROUTETOIF : 0),
- NULL, NULL, tp->t_inpcb);
+ NULL, tp->t_inpcb);
- if (error == EMSGSIZE && ro.ro_rt != NULL)
- mtu = ro.ro_rt->rt_mtu;
- RO_RTFREE(&ro);
+ if (error == EMSGSIZE)
+ mtu = ri.ri_mtu;
}
#endif /* INET6 */
#if defined(INET) && defined(INET6)
@@ -1340,7 +1339,7 @@ send:
TCP_PROBE5(send, NULL, tp, ip, tp, th);
error = ip_output(m, tp->t_inpcb->inp_options, &ri,
- ((so->so_options & SO_DONTROUTE) ? IP_ROUTETOIF : 0), 0,
+ ((so->so_options & SO_DONTROUTE) ? IP_ROUTETOIF : 0), NULL,
tp->t_inpcb);
if (error == EMSGSIZE)
Modified: projects/routing/sys/netinet/tcp_subr.c
==============================================================================
--- projects/routing/sys/netinet/tcp_subr.c Sun Aug 23 18:22:41 2015 (r287058)
+++ projects/routing/sys/netinet/tcp_subr.c Sun Aug 23 18:23:17 2015 (r287059)
@@ -728,7 +728,7 @@ tcp_respond(struct tcpcb *tp, void *ipge
TCP_PROBE5(send, NULL, tp, mtod(m, const char *), tp, nth);
#ifdef INET6
if (isipv6)
- (void) ip6_output(m, NULL, NULL, ipflags, NULL, NULL, inp);
+ (void) ip6_output(m, NULL, NULL, ipflags, NULL, inp);
#endif /* INET6 */
#if defined(INET) && defined(INET6)
else
Modified: projects/routing/sys/netinet/tcp_syncache.c
==============================================================================
--- projects/routing/sys/netinet/tcp_syncache.c Sun Aug 23 18:22:41 2015 (r287058)
+++ projects/routing/sys/netinet/tcp_syncache.c Sun Aug 23 18:23:17 2015 (r287059)
@@ -1569,7 +1569,7 @@ syncache_respond(struct syncache *sc, st
return (error);
}
#endif
- error = ip6_output(m, NULL, NULL, 0, NULL, NULL, NULL);
+ error = ip6_output(m, NULL, NULL, 0, NULL, NULL);
}
#endif
#if defined(INET6) && defined(INET)
Modified: projects/routing/sys/netinet/tcp_timewait.c
==============================================================================
--- projects/routing/sys/netinet/tcp_timewait.c Sun Aug 23 18:22:41 2015 (r287058)
+++ projects/routing/sys/netinet/tcp_timewait.c Sun Aug 23 18:23:17 2015 (r287059)
@@ -592,7 +592,7 @@ tcp_twrespond(struct tcptw *tw, int flag
sizeof(struct tcphdr) + optlen, IPPROTO_TCP, 0);
ip6->ip6_hlim = in6_selecthlim(inp, NULL);
error = ip6_output(m, inp->in6p_outputopts, NULL,
- (tw->tw_so_options & SO_DONTROUTE), NULL, NULL, inp);
+ (tw->tw_so_options & SO_DONTROUTE), NULL, inp);
}
#endif
#if defined(INET6) && defined(INET)
Modified: projects/routing/sys/netinet6/icmp6.c
==============================================================================
--- projects/routing/sys/netinet6/icmp6.c Sun Aug 23 18:22:41 2015 (r287058)
+++ projects/routing/sys/netinet6/icmp6.c Sun Aug 23 18:23:17 2015 (r287059)
@@ -2115,13 +2115,17 @@ icmp6_rip6_input(struct mbuf **mp, int o
void
icmp6_reflect(struct mbuf *m, size_t off)
{
- struct in6_addr src, *srcp = NULL;
struct ip6_hdr *ip6;
struct icmp6_hdr *icmp6;
struct in6_ifaddr *ia = NULL;
- struct ifnet *outif = NULL;
int plen;
int type, code;
+ struct ifnet *outif = NULL;
+ struct in6_addr origdst, src, dst;
+ struct route_info ri;
+ struct nhop6_basic nh6;
+ uint32_t scopeid;
+ int e;
/* too short to reflect */
if (off < sizeof(struct ip6_hdr)) {
@@ -2175,48 +2179,61 @@ icmp6_reflect(struct mbuf *m, size_t off
* (for example) when we encounter an error while forwarding procedure
* destined to a duplicated address of ours.
*/
- if (!IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) {
- ia = in6ifa_ifwithaddr(&ip6->ip6_dst, 0 /* XXX */);
- if (ia != NULL && !(ia->ia6_flags &
- (IN6_IFF_ANYCAST|IN6_IFF_NOTREADY)))
- srcp = &ia->ia_addr.sin6_addr;
+ memset(&src, 0, sizeof(src));
+ if (!IN6_IS_ADDR_MULTICAST(&origdst)) {
+ if ((ia = in6ifa_ifwithaddr(&ip6->ip6_dst, 0 /* XXX */))) {
+ if (!(ia->ia6_flags &
+ (IN6_IFF_ANYCAST|IN6_IFF_NOTREADY)))
+ src = ia->ia_addr.sin6_addr;
+ ifa_free(&ia->ia_ifa);
+ }
}
- if (srcp == NULL) {
- int e;
- struct sockaddr_in6 sin6;
- struct route_in6 ro;
+
+ ip6->ip6_src = src;
+ ip6->ip6_flow = 0;
+ ip6->ip6_vfc &= ~IPV6_VERSION_MASK;
+ ip6->ip6_vfc |= IPV6_VERSION;
+ ip6->ip6_nxt = IPPROTO_ICMPV6;
+ if (outif)
+ ip6->ip6_hlim = ND_IFINFO(outif)->chlim;
+ else if (m->m_pkthdr.rcvif) {
+ /* XXX: This may not be the outgoing interface */
+ ip6->ip6_hlim = ND_IFINFO(m->m_pkthdr.rcvif)->chlim;
+ } else
+ ip6->ip6_hlim = V_ip6_defhlim;
+
+
+ /*
+ * Deembed scope
+ */
+ in6_splitscope(&ip6->ip6_dst, &dst, &scopeid);
+
+ if (IN6_IS_ADDR_UNSPECIFIED(&src)) {
/*
* This case matches to multicasts, our anycast, or unicasts
* that we do not own. Select a source address based on the
* source address of the erroneous packet.
*/
- bzero(&sin6, sizeof(sin6));
- sin6.sin6_family = AF_INET6;
- sin6.sin6_len = sizeof(sin6);
- sin6.sin6_addr = ip6->ip6_dst; /* zone ID should be embedded */
-
- bzero(&ro, sizeof(ro));
- e = in6_selectsrc(&sin6, NULL, NULL, &ro, NULL, &outif, &src);
- if (ro.ro_rt)
- RTFREE(ro.ro_rt); /* XXX: we could use this */
+
+ e = in6_selectsrc_addr(M_GETFIB(m), &dst, scopeid, &src);
if (e) {
char ip6buf[INET6_ADDRSTRLEN];
nd6log((LOG_DEBUG,
"icmp6_reflect: source can't be determined: "
"dst=%s, error=%d\n",
- ip6_sprintf(ip6buf, &sin6.sin6_addr), e));
+ ip6_sprintf(ip6buf, &dst), e));
goto bad;
}
- srcp = &src;
+ ip6->ip6_src = src;
}
/*
* ip6_input() drops a packet if its src is multicast.
* So, the src is never multicast.
*/
ip6->ip6_dst = ip6->ip6_src;
- ip6->ip6_src = *srcp;
+ ip6->ip6_src = src;
ip6->ip6_flow = 0;
ip6->ip6_vfc &= ~IPV6_VERSION_MASK;
ip6->ip6_vfc |= IPV6_VERSION;
@@ -2239,17 +2256,20 @@ icmp6_reflect(struct mbuf *m, size_t off
m->m_flags &= ~(M_BCAST|M_MCAST);
- ip6_output(m, NULL, NULL, 0, NULL, &outif, NULL);
- if (outif)
- icmp6_ifoutstat_inc(outif, type, code);
+ memset(&ri, 0, sizeof(ri));
+ ri.ri_nh_info = (struct nhopu_basic *)&nh6;
+ ri.scopeid = scopeid;
+
+ e = ip6_output(m, NULL, &ri, 0, NULL, NULL);
+ if (e == 0) {
+ /* XXX: Possible use after free */
+ outif = nh6.nh_ifp;
+ //icmp6_ifoutstat_inc(outif, type, code);
+ }
- if (ia != NULL)
- ifa_free(&ia->ia_ifa);
return;
*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***
More information about the svn-src-projects
mailing list