Add new rib4/rib6 series of functions returning per-rte info

packed on stack.
Convert ng_netflow to use new routing API.
This commit is contained in:
Alexander V. Chernikov 2014-11-07 02:04:48 +00:00
parent 930d2a42c9
commit 043d919e33
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/projects/routing/; revision=274212
3 changed files with 227 additions and 84 deletions

View File

@ -117,6 +117,8 @@ int fwd_destroy_fib(struct fwd_module *fm, u_int fib);
static inline uint16_t fib_rte_to_nh_flags(int rt_flags);
#ifdef INET
static void rib4_rte_to_nh_extended(struct rtentry *rte, struct in_addr dst,
struct rt4_extended *prt4);
static void fib4_rte_to_nh_extended(struct rtentry *rte, struct in_addr dst,
struct nhop4_extended *pnh4);
static void fib4_rte_to_nh_basic(struct rtentry *rte, struct in_addr dst,
@ -452,6 +454,39 @@ fib4_rte_to_nh_extended(struct rtentry *rte, struct in_addr dst,
pnh4->nh_src = IA_SIN(ia)->sin_addr;
}
static void
rib4_rte_to_nh_extended(struct rtentry *rte, struct in_addr dst,
struct rt4_extended *prt4)
{
struct sockaddr_in *gw;
struct in_ifaddr *ia;
/* Do explicit nexthop zero unless we're copying it */
memset(prt4, 0, sizeof(*prt4));
gw = ((struct sockaddr_in *)rt_key(rte));
prt4->rt_addr = gw->sin_addr;
gw = ((struct sockaddr_in *)rt_mask(rte));
prt4->rt_mask.s_addr = (gw != NULL) ?
gw->sin_addr.s_addr : INADDR_BROADCAST;
if (rte->rt_flags & RTF_GATEWAY) {
gw = (struct sockaddr_in *)rte->rt_gateway;
prt4->rt_gateway = gw->sin_addr;
} else
prt4->rt_gateway = dst;
prt4->rt_lifp = rte->rt_ifp;
prt4->rt_aifp = rte->rt_ifa->ifa_ifp;
prt4->rt_flags = rte->rt_flags;
prt4->rt_mtu = min(rte->rt_mtu, rte->rt_ifp->if_mtu);
prt4->rt_nhop = 0; /* XXX: fill real nexthop */
ia = ifatoia(rte->rt_ifa);
prt4->rt_src = IA_SIN(ia)->sin_addr;
}
/*
* Performs IPv4 route table lookup on @dst. Returns 0 on success.
* Stores nexthop info provided @pnh4 structure.
@ -588,6 +623,50 @@ fib4_free_nh_ext(uint32_t fibnum, struct nhop4_extended *pnh4)
}
int
rib4_lookup_nh_ext(uint32_t fibnum, struct in_addr dst, uint32_t flowid,
uint32_t flags, struct rt4_extended *prt4)
{
struct radix_node_head *rnh;
struct radix_node *rn;
struct sockaddr_in sin;
struct rtentry *rte;
KASSERT((fibnum < rt_numfibs), ("rib4_lookup_nh_ext: bad fibnum"));
rnh = rt_tables_get_rnh(fibnum, AF_INET);
if (rnh == NULL)
return (ENOENT);
/* Prepare lookup key */
memset(&sin, 0, sizeof(sin));
sin.sin_len = sizeof(struct sockaddr_in);
sin.sin_addr = dst;
RADIX_NODE_HEAD_RLOCK(rnh);
rn = rnh->rnh_matchaddr((void *)&sin, rnh);
if (rn != NULL && ((rn->rn_flags & RNF_ROOT) == 0)) {
rte = RNTORT(rn);
/* Ensure route & ifp is UP */
if (RT_LINK_IS_UP(rte->rt_ifp)) {
rib4_rte_to_nh_extended(rte, dst, prt4);
if ((flags & NHOP_LOOKUP_REF) != 0) {
/* TODO: Do lwref on egress ifp's */
}
RADIX_NODE_HEAD_RUNLOCK(rnh);
return (0);
}
}
RADIX_NODE_HEAD_RUNLOCK(rnh);
return (ENOENT);
}
void
rib4_free_nh_ext(uint32_t fibnum, struct rt4_extended *prt4)
{
}
#endif
#ifdef INET6
@ -897,6 +976,36 @@ fib6_lla_to_nh_extended(struct in6_addr *dst, uint32_t scopeid,
return (0);
}
static int
rib6_lla_to_nh_extended(struct in6_addr *dst, uint32_t scopeid,
struct rt6_extended *prt6)
{
struct ifnet *ifp;
ifp = ifnet_byindex_locked(scopeid);
if (ifp == NULL)
return (ENOENT);
/* Do explicit nexthop zero unless we're copying it */
memset(prt6, 0, sizeof(*prt6));
prt6->rt_addr.s6_addr16[0] = htons(0xFE80);
prt6->rt_mask = 64; /* XXX check RFC */
prt6->rt_aifp = ifp;
prt6->rt_lifp = ifp;
/* Check id this is for-us address */
if (in6_ifawithifp_lla(ifp, dst)) {
if ((ifp = V_loif) != NULL)
prt6->rt_lifp = ifp;
}
prt6->rt_mtu = IN6_LINKMTU(ifp);
/* No flags set */
return (0);
}
static int
fib6_lla_to_nh(struct in6_addr *dst, uint32_t scopeid,
struct nhop_prepend *nh, struct ifnet **lifp)
@ -979,6 +1088,37 @@ fib6_rte_to_nh_extended(struct rtentry *rte, struct in6_addr *dst,
ia = ifatoia6(rte->rt_ifa);
}
#define ipv6_masklen(x) bitcount32((x).__u6_addr.__u6_addr32[0]) + \
bitcount32((x).__u6_addr.__u6_addr32[1]) + \
bitcount32((x).__u6_addr.__u6_addr32[2]) + \
bitcount32((x).__u6_addr.__u6_addr32[3])
static void
rib6_rte_to_nh_extended(struct rtentry *rte, struct in6_addr *dst,
struct rt6_extended *prt6)
{
struct sockaddr_in6 *gw;
/* Do explicit nexthop zero unless we're copying it */
memset(prt6, 0, sizeof(*prt6));
gw = ((struct sockaddr_in6 *)rt_key(rte));
prt6->rt_addr = gw->sin6_addr;
gw = ((struct sockaddr_in6 *)rt_mask(rte));
prt6->rt_mask = (gw != NULL) ? ipv6_masklen(gw->sin6_addr) : 128;
if (rte->rt_flags & RTF_GATEWAY) {
gw = (struct sockaddr_in6 *)rte->rt_gateway;
prt6->rt_gateway = gw->sin6_addr;
in6_clearscope(&prt6->rt_gateway);
} else
prt6->rt_gateway = *dst;
prt6->rt_lifp = rte->rt_ifp;
prt6->rt_aifp = ifnet_byindex(fib6_get_ifa(rte));
prt6->rt_flags = fib_rte_to_nh_flags(rte->rt_flags);
prt6->rt_mtu = min(rte->rt_mtu, IN6_LINKMTU(rte->rt_ifp));
}
int
fib6_lookup_nh_ifp(uint32_t fibnum, struct in6_addr *dst, uint32_t scopeid,
uint32_t flowid, struct nhop6_basic *pnh6)
@ -990,6 +1130,7 @@ fib6_lookup_nh_ifp(uint32_t fibnum, struct in6_addr *dst, uint32_t scopeid,
if (IN6_IS_SCOPE_LINKLOCAL(dst)) {
/* Do not lookup link-local addresses in rtable */
/* XXX: Check if dst is local */
return (fib6_lla_to_nh_basic(dst, scopeid, pnh6));
}
@ -1124,6 +1265,59 @@ fib6_free_nh_ext(uint32_t fibnum, struct nhop6_extended *pnh6)
}
int
rib6_lookup_nh_ext(uint32_t fibnum, struct in6_addr *dst, uint32_t scopeid,
uint32_t flowid, uint32_t flags, struct rt6_extended *prt6)
{
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 */
/* XXX: Do lwref on egress ifp */
return (rib6_lla_to_nh_extended(dst, scopeid, prt6));
}
KASSERT((fibnum < rt_numfibs), ("rib6_lookup_nh_ext: 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);
if (rn != NULL && ((rn->rn_flags & RNF_ROOT) == 0)) {
rte = RNTORT(rn);
/* Ensure route & ifp is UP */
if (RT_LINK_IS_UP(rte->rt_ifp)) {
rib6_rte_to_nh_extended(rte, dst, prt6);
if ((flags & NHOP_LOOKUP_REF) != 0) {
/* TODO: Do lwref on egress ifp's */
}
RADIX_NODE_HEAD_RUNLOCK(rnh);
return (0);
}
}
RADIX_NODE_HEAD_RUNLOCK(rnh);
return (ENOENT);
}
void
rib6_free_nh_ext(uint32_t fibnum, struct nhop6_extended *prt6)
{
}
#endif
void

View File

@ -180,23 +180,28 @@ struct nhop6_extended {
};
/* route info used for control plane purposes */
struct rt4_basic {
struct rt4_extended {
struct in_addr rt_addr; /* route prefix */
struct in_addr rt_gateway; /* GW used */
struct ifnet *rt_lifp; /* logical interface */
struct ifnet *rt_aifp; /* address interface */
int rt_flags; /* Copy of rte flags */
uint16_t rt_mtu;
uint16_t rt_nhop; /* nexthop id (might bi mpath) */
struct in_addr rt_mask; /* route mask */
struct in_addr rt_src;
uint16_t spare[2];
};
struct rt6_basic {
struct rt6_extended {
struct in6_addr rt_addr;
struct in6_addr rt_gateway;
struct ifnet *rt_lifp; /* logical interface */
struct ifnet *rt_aifp; /* address interface */
int rt_flags;
uint16_t rt_mtu;
uint16_t rt_nhop;
uint8_t rt_mask;
uint8_t rt_mask; /*Hopefully, no more non-config masks */
uint8_t spare[7];
};
@ -230,6 +235,9 @@ int fib4_lookup_nh_ext(uint32_t fibnum, struct in_addr dst,
uint32_t flowid, uint32_t flags, struct nhop4_extended *pnh4);
void fib4_free_nh_ext(uint32_t fibnum, struct nhop4_extended *pnh4);
#define NHOP_LOOKUP_REF 0x01
int rib4_lookup_nh_ext(uint32_t fibnum, struct in_addr dst, uint32_t flowid,
uint32_t flags, struct rt4_extended *prt4);
void rib4_free_nh_ext(uint32_t fibnum, struct rt4_extended *prt4);
int fib6_lookup_nh_ifp(uint32_t fibnum, struct in6_addr *dst, uint32_t scopeid,
@ -240,6 +248,9 @@ 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);
int rib6_lookup_nh_ext(uint32_t fibnum, struct in6_addr *dst, uint32_t scopeid,
uint32_t flowid, uint32_t flags, struct rt6_extended *prt6);
void rib6_free_nh_ext(uint32_t fibnum, struct nhop6_extended *prt6);
void fib_free_nh_ext(uint32_t fibnum, struct nhopu_extended *pnhu);

View File

@ -45,7 +45,6 @@ __FBSDID("$FreeBSD$");
#include <net/if.h>
#include <net/if_var.h>
#include <net/route.h>
#include <net/route_internal.h>
#include <net/ethernet.h>
#include <netinet/in.h>
#include <netinet/in_systm.h>
@ -53,6 +52,7 @@ __FBSDID("$FreeBSD$");
#include <netinet/ip6.h>
#include <netinet/tcp.h>
#include <netinet/udp.h>
#include <net/rt_nhops.h>
#include <netgraph/ng_message.h>
#include <netgraph/netgraph.h>
@ -307,8 +307,7 @@ hash_insert(priv_p priv, struct flow_hash_entry *hsh, struct flow_rec *r,
int plen, uint8_t flags, uint8_t tcp_flags)
{
struct flow_entry *fle;
struct sockaddr_in sin;
struct rtentry *rt;
struct rt4_extended rt4;
mtx_assert(&hsh->mtx, MA_OWNED);
@ -335,46 +334,20 @@ hash_insert(priv_p priv, struct flow_hash_entry *hsh, struct flow_rec *r,
* fill in out_ifx, dst_mask, nexthop, and dst_as in future releases.
*/
if ((flags & NG_NETFLOW_CONF_NODSTLOOKUP) == 0) {
bzero(&sin, sizeof(sin));
sin.sin_len = sizeof(struct sockaddr_in);
sin.sin_family = AF_INET;
sin.sin_addr = fle->f.r.r_dst;
rt = rtalloc1_fib((struct sockaddr *)&sin, 0, 0, r->fib);
if (rt != NULL) {
fle->f.fle_o_ifx = rt->rt_ifp->if_index;
if (rt->rt_flags & RTF_GATEWAY &&
rt->rt_gateway->sa_family == AF_INET)
fle->f.next_hop =
((struct sockaddr_in *)(rt->rt_gateway))->sin_addr;
if (rt_mask(rt))
fle->f.dst_mask =
bitcount32(((struct sockaddr_in *)rt_mask(rt))->sin_addr.s_addr);
else if (rt->rt_flags & RTF_HOST)
/* Give up. We can't determine mask :( */
fle->f.dst_mask = 32;
RTFREE_LOCKED(rt);
if (rib4_lookup_nh_ext(r->fib, fle->f.r.r_dst, 0, 0, &rt4) != 0) {
fle->f.fle_o_ifx = rt4.rt_lifp->if_index;
if (rt4.rt_flags & RTF_GATEWAY)
fle->f.next_hop = rt4.rt_gateway;
fle->f.dst_mask = bitcount32(rt4.rt_mask.s_addr);
}
}
/* Do route lookup on source address, to fill in src_mask. */
if ((flags & NG_NETFLOW_CONF_NOSRCLOOKUP) == 0) {
bzero(&sin, sizeof(sin));
sin.sin_len = sizeof(struct sockaddr_in);
sin.sin_family = AF_INET;
sin.sin_addr = fle->f.r.r_src;
rt = rtalloc1_fib((struct sockaddr *)&sin, 0, 0, r->fib);
if (rt != NULL) {
if (rt_mask(rt))
fle->f.src_mask =
bitcount32(((struct sockaddr_in *)rt_mask(rt))->sin_addr.s_addr);
else if (rt->rt_flags & RTF_HOST)
/* Give up. We can't determine mask :( */
fle->f.src_mask = 32;
RTFREE_LOCKED(rt);
if (rib4_lookup_nh_ext(r->fib, fle->f.r.r_src, 0, 0, &rt4) != 0) {
if (rt4.rt_flags & RTF_GATEWAY)
fle->f.next_hop = rt4.rt_gateway;
fle->f.src_mask = bitcount32(rt4.rt_mask.s_addr);
}
}
@ -396,9 +369,7 @@ hash6_insert(priv_p priv, struct flow_hash_entry *hsh6, struct flow6_rec *r,
int plen, uint8_t flags, uint8_t tcp_flags)
{
struct flow6_entry *fle6;
struct sockaddr_in6 *src, *dst;
struct rtentry *rt;
struct route_in6 rin6;
struct rt6_extended rt6;
mtx_assert(&hsh6->mtx, MA_OWNED);
@ -426,51 +397,18 @@ hash6_insert(priv_p priv, struct flow_hash_entry *hsh6, struct flow6_rec *r,
* fill in out_ifx, dst_mask, nexthop, and dst_as in future releases.
*/
if ((flags & NG_NETFLOW_CONF_NODSTLOOKUP) == 0) {
bzero(&rin6, sizeof(struct route_in6));
dst = (struct sockaddr_in6 *)&rin6.ro_dst;
dst->sin6_len = sizeof(struct sockaddr_in6);
dst->sin6_family = AF_INET6;
dst->sin6_addr = r->dst.r_dst6;
rin6.ro_rt = rtalloc1_fib((struct sockaddr *)dst, 0, 0, r->fib);
if (rin6.ro_rt != NULL) {
rt = rin6.ro_rt;
fle6->f.fle_o_ifx = rt->rt_ifp->if_index;
if (rt->rt_flags & RTF_GATEWAY &&
rt->rt_gateway->sa_family == AF_INET6)
fle6->f.n.next_hop6 =
((struct sockaddr_in6 *)(rt->rt_gateway))->sin6_addr;
if (rt_mask(rt))
fle6->f.dst_mask = RT_MASK6(rt);
else
fle6->f.dst_mask = 128;
RTFREE_LOCKED(rt);
if (rib6_lookup_nh_ext(r->fib, &r->dst.r_dst6, 0, 0, 0, &rt6) == 0) {
fle6->f.fle_o_ifx = rt6.rt_lifp->if_index;
if ((rt6.rt_flags & RTF_GATEWAY) != 0)
fle6->f.n.next_hop6 = rt6.rt_gateway;
fle6->f.dst_mask = rt6.rt_mask;
}
}
if ((flags & NG_NETFLOW_CONF_NODSTLOOKUP) == 0) {
/* Do route lookup on source address, to fill in src_mask. */
bzero(&rin6, sizeof(struct route_in6));
src = (struct sockaddr_in6 *)&rin6.ro_dst;
src->sin6_len = sizeof(struct sockaddr_in6);
src->sin6_family = AF_INET6;
src->sin6_addr = r->src.r_src6;
rin6.ro_rt = rtalloc1_fib((struct sockaddr *)src, 0, 0, r->fib);
if (rin6.ro_rt != NULL) {
rt = rin6.ro_rt;
if (rt_mask(rt))
fle6->f.src_mask = RT_MASK6(rt);
else
fle6->f.src_mask = 128;
RTFREE_LOCKED(rt);
if (rib6_lookup_nh_ext(r->fib, &r->src.r_src6, 0, 0, 0, &rt6) == 0) {
fle6->f.dst_mask = rt6.rt_mask;
}
}