Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F107170330
D22988.id66234.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
34 KB
Referenced Files
None
Subscribers
None
D22988.id66234.diff
View Options
Index: sys/conf/files
===================================================================
--- sys/conf/files
+++ sys/conf/files
@@ -4098,6 +4098,7 @@
net/raw_cb.c standard
net/raw_usrreq.c standard
net/route.c standard
+net/route_temporal.c standard
net/rss_config.c optional inet rss | inet6 rss
net/rtsock.c standard
net/slcompress.c optional netgraph_vjc | sppp | \
Index: sys/net/radix_mpath.h
===================================================================
--- sys/net/radix_mpath.h
+++ sys/net/radix_mpath.h
@@ -57,8 +57,8 @@
void rtalloc_mpath_fib(struct route *, u_int32_t, u_int);
struct rtentry *rt_mpath_select(struct rtentry *, uint32_t);
int rt_mpath_deldup(struct rtentry *, struct rtentry *);
-int rn4_mpath_inithead(void **, int);
-int rn6_mpath_inithead(void **, int);
+int rn4_mpath_inithead(void **, int, u_int);
+int rn6_mpath_inithead(void **, int, u_int);
#endif
Index: sys/net/radix_mpath.c
===================================================================
--- sys/net/radix_mpath.c
+++ sys/net/radix_mpath.c
@@ -290,17 +290,17 @@
RT_UNLOCK(ro->ro_rt);
}
-extern int in6_inithead(void **head, int off);
-extern int in_inithead(void **head, int off);
+extern int in6_inithead(void **head, int off, u_int fibnum);
+extern int in_inithead(void **head, int off, u_int fibnum);
#ifdef INET
int
-rn4_mpath_inithead(void **head, int off)
+rn4_mpath_inithead(void **head, int off, u_int fibnum)
{
struct rib_head *rnh;
hashjitter = arc4random();
- if (in_inithead(head, off) == 1) {
+ if (in_inithead(head, off, fibnum) == 1) {
rnh = (struct rib_head *)*head;
rnh->rnh_multipath = 1;
return 1;
@@ -311,12 +311,12 @@
#ifdef INET6
int
-rn6_mpath_inithead(void **head, int off)
+rn6_mpath_inithead(void **head, int off, u_int fibnum)
{
struct rib_head *rnh;
hashjitter = arc4random();
- if (in6_inithead(head, off) == 1) {
+ if (in6_inithead(head, off, fibnum) == 1) {
rnh = (struct rib_head *)*head;
rnh->rnh_multipath = 1;
return 1;
Index: sys/net/route.h
===================================================================
--- sys/net/route.h
+++ sys/net/route.h
@@ -455,7 +455,7 @@
void rt_newmaddrmsg(int, struct ifmultiaddr *);
int rt_setgate(struct rtentry *, struct sockaddr *, struct sockaddr *);
void rt_maskedcopy(struct sockaddr *, struct sockaddr *, struct sockaddr *);
-struct rib_head *rt_table_init(int);
+struct rib_head *rt_table_init(int, int, u_int);
void rt_table_destroy(struct rib_head *);
u_int rt_tables_get_gen(int table, int fam);
@@ -477,6 +477,8 @@
typedef int rt_walktree_f_t(struct rtentry *, void *);
typedef void rt_setwarg_t(struct rib_head *, uint32_t, int, void *);
+void rib_walk_del(u_int fibnum, int family, rt_filter_f_t *filter_f,
+ void *arg, int report);
void rt_foreach_fib_walk(int af, rt_setwarg_t *, rt_walktree_f_t *, void *);
void rt_foreach_fib_walk_del(int af, rt_filter_f_t *filter_f, void *arg);
void rt_flushifroutes_af(struct ifnet *, int);
@@ -494,8 +496,8 @@
void rtalloc_ign_fib(struct route *ro, u_long ignflags, u_int fibnum);
struct rtentry *rtalloc1_fib(struct sockaddr *, int, u_long, u_int);
int rtioctl_fib(u_long, caddr_t, u_int);
-void rtredirect_fib(struct sockaddr *, struct sockaddr *,
- struct sockaddr *, int, struct sockaddr *, u_int);
+int rtredirect_fib(struct sockaddr *, struct sockaddr *,
+ int, struct sockaddr *, int, u_int);
int rtrequest_fib(int, struct sockaddr *,
struct sockaddr *, struct sockaddr *, int, struct rtentry **, u_int);
int rtrequest1_fib(int, struct rt_addrinfo *, struct rtentry **, u_int);
Index: sys/net/route.c
===================================================================
--- sys/net/route.c
+++ sys/net/route.c
@@ -187,10 +187,11 @@
{
struct rib_head **rnh;
- KASSERT(table >= 0 && table < rt_numfibs, ("%s: table out of bounds.",
- __func__));
- KASSERT(fam >= 0 && fam < (AF_MAX+1), ("%s: fam out of bounds.",
- __func__));
+ KASSERT(table >= 0 && table < rt_numfibs,
+ ("%s: table out of bounds (0 < %d < %d)", __func__, table,
+ rt_numfibs));
+ KASSERT(fam >= 0 && fam < (AF_MAX + 1),
+ ("%s: fam out of bounds (0 < %d < %d)", __func__, fam, AF_MAX + 1));
/* rnh is [fib=0][af=0]. */
rnh = (struct rib_head **)V_rt_tables;
@@ -304,7 +305,7 @@
rnh = rt_tables_get_rnh_ptr(table, fam);
if (rnh == NULL)
panic("%s: rnh NULL", __func__);
- dom->dom_rtattach((void **)rnh, 0);
+ dom->dom_rtattach((void **)rnh, 0, table);
}
}
}
@@ -345,7 +346,7 @@
#endif
struct rib_head *
-rt_table_init(int offset)
+rt_table_init(int offset, int family, u_int fibnum)
{
struct rib_head *rh;
@@ -357,9 +358,19 @@
rn_inithead_internal(&rh->rmhead.head, rh->rmhead.mask_nodes, 0);
rh->head.rnh_masks = &rh->rmhead;
+ rh->rib_family = family;
+ rh->rib_fibnum = fibnum;
+
/* Init locks */
RIB_LOCK_INIT(rh);
+ tmproutes_init(rh);
+
+ /* Save vnet pointer for callouts */
+#ifdef VIMAGE
+ rh->rib_vnet = curvnet;
+#endif
+
/* Finally, set base callbacks */
rh->rnh_addaddr = rn_addroute;
rh->rnh_deladdr = rn_delete;
@@ -387,6 +398,8 @@
rt_table_destroy(struct rib_head *rh)
{
+ tmproutes_destroy(rh);
+
rn_walktree(&rh->rmhead.head, rt_freeentry, &rh->rmhead.head);
/* Assume table is already empty */
@@ -578,131 +591,125 @@
}
-/*
- * Force a routing table entry to the specified
- * destination to go through the given gateway.
- * Normally called as a result of a routing redirect
- * message from the network layer.
- */
-void
-rtredirect_fib(struct sockaddr *dst,
- struct sockaddr *gateway,
- struct sockaddr *netmask,
- int flags,
- struct sockaddr *src,
- u_int fibnum)
+static int
+verify_redirect_gateway(struct sockaddr *src, struct sockaddr *dst,
+ struct sockaddr *gateway, int flags, u_int fibnum)
{
struct rtentry *rt;
- int error = 0;
- struct rt_addrinfo info;
struct ifaddr *ifa;
- struct rib_head *rnh;
NET_EPOCH_ASSERT();
- ifa = NULL;
- rnh = rt_tables_get_rnh(fibnum, dst->sa_family);
- if (rnh == NULL) {
- error = EAFNOSUPPORT;
- goto out;
- }
/* verify the gateway is directly reachable */
- if ((ifa = ifa_ifwithnet(gateway, 0, fibnum)) == NULL) {
- error = ENETUNREACH;
- goto out;
- }
- rt = rtalloc1_fib(dst, 0, 0UL, fibnum); /* NB: rt is locked */
+ if ((ifa = ifa_ifwithnet(gateway, 0, fibnum)) == NULL)
+ return (ENETUNREACH);
+
+ /* TODO: fib-aware */
+ if ((flags & RTF_GATEWAY) && ifa_ifwithaddr_check(gateway))
+ return (EHOSTUNREACH);
+
+ rt = rtalloc1_fib(dst, 0, 0UL, fibnum); /* NB: rt is locked */
+
/*
* If the redirect isn't from our current router for this dst,
* it's either old or wrong. If it redirects us to ourselves,
* we have a routing loop, perhaps as a result of an interface
* going down recently.
*/
- if (!(flags & RTF_DONE) && rt) {
+ if (rt != NULL) {
if (!sa_equal(src, rt->rt_gateway)) {
- error = EINVAL;
- goto done;
+ RTFREE_LOCKED(rt);
+ return (EINVAL);
}
if (rt->rt_ifa != ifa && ifa->ifa_addr->sa_family != AF_LINK) {
- error = EINVAL;
- goto done;
+ RTFREE_LOCKED(rt);
+ return (EINVAL);
}
}
- if ((flags & RTF_GATEWAY) && ifa_ifwithaddr_check(gateway)) {
- error = EHOSTUNREACH;
- goto done;
+
+ /* If host route already exists, ignore redirect. */
+ if (rt != NULL && (rt->rt_flags & RTF_HOST)) {
+ RTFREE_LOCKED(rt);
+ return (EEXIST);
}
- /*
- * Create a new entry if we just got back a wildcard entry
- * or the lookup failed. This is necessary for hosts
- * which use routing redirects generated by smart gateways
- * to dynamically build the routing tables.
- */
- if (rt == NULL || (rt_mask(rt) && rt_mask(rt)->sa_len < 2))
- goto create;
- /*
- * Don't listen to the redirect if it's
- * for a route to an interface.
- */
- if (rt->rt_flags & RTF_GATEWAY) {
- if (((rt->rt_flags & RTF_HOST) == 0) && (flags & RTF_HOST)) {
- /*
- * Changing from route to net => route to host.
- * Create new route, rather than smashing route to net.
- */
- create:
- if (rt != NULL)
- RTFREE_LOCKED(rt);
-
- flags |= RTF_DYNAMIC;
- bzero((caddr_t)&info, sizeof(info));
- info.rti_info[RTAX_DST] = dst;
- info.rti_info[RTAX_GATEWAY] = gateway;
- info.rti_info[RTAX_NETMASK] = netmask;
- ifa_ref(ifa);
- info.rti_ifa = ifa;
- info.rti_flags = flags;
- error = rtrequest1_fib(RTM_ADD, &info, &rt, fibnum);
- if (rt != NULL) {
- RT_LOCK(rt);
- flags = rt->rt_flags;
- }
- if (error == 0)
- RTSTAT_INC(rts_dynamic);
- } else {
- /*
- * Smash the current notion of the gateway to
- * this destination. Should check about netmask!!!
- */
- if ((flags & RTF_GATEWAY) == 0)
- rt->rt_flags &= ~RTF_GATEWAY;
- rt->rt_flags |= RTF_MODIFIED;
- flags |= RTF_MODIFIED;
- RTSTAT_INC(rts_newgateway);
- /*
- * add the key and gateway (in one malloc'd chunk).
- */
- RT_UNLOCK(rt);
- RIB_WLOCK(rnh);
- RT_LOCK(rt);
- rt_setgate(rt, rt_key(rt), gateway);
- RIB_WUNLOCK(rnh);
- }
- } else
- error = EHOSTUNREACH;
-done:
- if (rt)
+ /* If the prefix is directly reachable, ignore redirect */
+ if (rt != NULL && !(rt->rt_flags & RTF_GATEWAY)) {
RTFREE_LOCKED(rt);
- out:
- if (error)
+ return (EEXIST);
+ }
+
+ RTFREE_LOCKED(rt);
+ return (0);
+}
+
+
+/*
+ * Force a routing table entry to the specified
+ * destination to go through the given gateway.
+ * Normally called as a result of a routing redirect
+ * message from the network layer.
+ */
+int
+rtredirect_fib(struct sockaddr *dst, struct sockaddr *gateway,
+ int flags, struct sockaddr *src, int expire_sec, u_int fibnum)
+{
+ struct rtentry *rt;
+ int error = 0;
+ struct rt_addrinfo info;
+ struct rt_metrics rti_rmx;
+ struct ifaddr *ifa;
+
+ NET_EPOCH_ASSERT();
+
+ if (rt_tables_get_rnh(fibnum, dst->sa_family) == NULL)
+ return (error);
+
+ error = verify_redirect_gateway(src, dst, gateway, flags, fibnum);
+ if (error != 0)
+ return (error);
+
+ /* verify the gateway is directly reachable */
+ if ((ifa = ifa_ifwithnet(gateway, 0, fibnum)) == NULL)
+ return (ENETUNREACH);
+ ifa_ref(ifa);
+
+ flags |= RTF_DYNAMIC;
+
+ bzero(&info, sizeof(info));
+ info.rti_info[RTAX_DST] = dst;
+ info.rti_info[RTAX_GATEWAY] = gateway;
+ info.rti_ifa = ifa;
+ info.rti_flags = flags;
+
+ /* Setup route metrics to define expire time */
+ bzero(&rti_rmx, sizeof(rti_rmx));
+ /* Define expire time as absolute */
+ rti_rmx.rmx_expire = expire_sec + time_second;
+ info.rti_mflags |= RTV_EXPIRE;
+ info.rti_rmx = &rti_rmx;
+
+ error = rtrequest1_fib(RTM_ADD, &info, &rt, fibnum);
+ ifa_free(ifa);
+
+ if (error != 0) {
RTSTAT_INC(rts_badredirect);
- bzero((caddr_t)&info, sizeof(info));
+ return (error);
+ }
+
+ RT_LOCK(rt);
+ flags = rt->rt_flags;
+ RTFREE_LOCKED(rt);
+
+ RTSTAT_INC(rts_dynamic);
+
+ bzero(&info, sizeof(info));
info.rti_info[RTAX_DST] = dst;
info.rti_info[RTAX_GATEWAY] = gateway;
- info.rti_info[RTAX_NETMASK] = netmask;
info.rti_info[RTAX_AUTHOR] = src;
rt_missmsg_fib(RTM_REDIRECT, &info, flags, error, fibnum);
+
+ return (0);
}
/*
@@ -1052,6 +1059,56 @@
}
/*
+ * Iterates over rtable specified by @fibnum and @af and deletes elements
+ * marked by @filter_f.
+ * @fibnum: rtable id
+ * @family: AF_ address family
+ * @filter_f: lambda function returning non-zero value for items to delete
+ * @arg: data to pass to the @filter_f
+ * @report: true if rtsock notification is needed.
+ */
+void
+rib_walk_del(u_int fibnum, int family, rt_filter_f_t *filter_f, void *arg, int report)
+{
+ struct rib_head *rnh;
+ struct rt_delinfo di;
+ struct rtentry *rt;
+
+ rnh = rt_tables_get_rnh(fibnum, family);
+ if (rnh == NULL)
+ return;
+
+ bzero(&di, sizeof(di));
+ di.info.rti_filter = filter_f;
+ di.info.rti_filterdata = arg;
+ di.rnh = rnh;
+
+ RIB_WLOCK(rnh);
+ rnh->rnh_walktree(&rnh->head, rt_checkdelroute, &di);
+ RIB_WUNLOCK(rnh);
+
+ if (di.head == NULL)
+ return;
+
+ /* We might have something to reclaim */
+ while (di.head != NULL) {
+ rt = di.head;
+ di.head = rt->rt_chain;
+ rt->rt_chain = NULL;
+
+ /* TODO std rt -> rt_addrinfo export */
+ di.info.rti_info[RTAX_DST] = rt_key(rt);
+ di.info.rti_info[RTAX_NETMASK] = rt_mask(rt);
+
+ rt_notifydelete(rt, &di.info);
+
+ if (report)
+ rt_routemsg(RTM_DELETE, rt->rt_ifp, 0, rt, fibnum);
+ RTFREE_LOCKED(rt);
+ }
+}
+
+/*
* Iterates over all existing fibs in system.
* Deletes each element for which @filter_f function returned
* non-zero value.
@@ -1061,16 +1118,9 @@
void
rt_foreach_fib_walk_del(int af, rt_filter_f_t *filter_f, void *arg)
{
- struct rib_head *rnh;
- struct rt_delinfo di;
- struct rtentry *rt;
uint32_t fibnum;
int i, start, end;
- bzero(&di, sizeof(di));
- di.info.rti_filter = filter_f;
- di.info.rti_filterdata = arg;
-
for (fibnum = 0; fibnum < rt_numfibs; fibnum++) {
/* Do we want some specific family? */
if (af != AF_UNSPEC) {
@@ -1082,32 +1132,10 @@
}
for (i = start; i <= end; i++) {
- rnh = rt_tables_get_rnh(fibnum, i);
- if (rnh == NULL)
+ if (rt_tables_get_rnh(fibnum, i) == NULL)
continue;
- di.rnh = rnh;
- RIB_WLOCK(rnh);
- rnh->rnh_walktree(&rnh->head, rt_checkdelroute, &di);
- RIB_WUNLOCK(rnh);
-
- if (di.head == NULL)
- continue;
-
- /* We might have something to reclaim */
- while (di.head != NULL) {
- rt = di.head;
- di.head = rt->rt_chain;
- rt->rt_chain = NULL;
-
- /* TODO std rt -> rt_addrinfo export */
- di.info.rti_info[RTAX_DST] = rt_key(rt);
- di.info.rti_info[RTAX_NETMASK] = rt_mask(rt);
-
- rt_notifydelete(rt, &di.info);
- RTFREE_LOCKED(rt);
- }
-
+ rib_walk_del(fibnum, i, filter_f, arg, 0);
}
}
}
@@ -1692,6 +1720,9 @@
/* XXX mtu manipulation will be done in rnh_addaddr -- itojun */
rn = rnh->rnh_addaddr(ndst, netmask, &rnh->head, rt->rt_nodes);
+
+ if (rn != NULL && rt->rt_expire > 0)
+ tmproutes_update(rnh, rt);
rt_old = NULL;
if (rn == NULL && (info->rti_flags & RTF_PINNED) != 0) {
Index: sys/net/route_temporal.c
===================================================================
--- /dev/null
+++ sys/net/route_temporal.c
@@ -0,0 +1,156 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2020 Alexander V. Chernikov
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+/*
+ * This file contains code responsible for expiring temporal routes
+ * (typically, redirect-originated) from the route tables.
+ */
+
+#include <sys/cdefs.h>
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/socket.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/rmlock.h>
+
+#include <net/if.h>
+#include <net/route.h>
+#include <net/route_var.h>
+#include <net/vnet.h>
+
+/*
+ * Callback returning 1 for the expired routes.
+ * Updates time of the next nearest route expiration
+ * as a side effect.
+ */
+static int
+expire_route(const struct rtentry *rt, void *arg)
+{
+ time_t *next_callout = (time_t *)arg;
+
+ if (rt->rt_expire == 0)
+ return (0);
+
+ if (rt->rt_expire <= time_uptime) {
+ printf("expiring %p, ts %lu\n", rt, rt->rt_expire);
+ return (1);
+ }
+
+ /*
+ * Update next_callout to determine the next ts to
+ * run the callback at.
+ */
+ if (*next_callout == 0 || *next_callout > rt->rt_expire)
+ *next_callout = rt->rt_expire;
+
+ return (0);
+}
+
+/*
+ * Per-rnh callout function traversing the tree and deleting
+ * expired routes. Calculates next callout run by looking at
+ * the rt_expire time for the remaining temporal routes.
+ */
+static void
+expire_callout(void *arg)
+{
+ struct rib_head *rnh = (struct rib_head *)arg;
+ time_t next_expire = 0;
+ int ticks;
+
+ CURVNET_SET(rnh->rib_vnet);
+
+ rib_walk_del(rnh->rib_fibnum, rnh->rib_family, expire_route,
+ (void *)&next_expire, 1);
+
+ RIB_WLOCK(rnh);
+ if (next_expire > 0) {
+ ticks = (next_expire - time_uptime) * hz;
+ if (ticks < 0)
+ ticks = 0;
+ callout_reset(&rnh->expire_callout, ticks, expire_callout, rnh);
+ rnh->next_expire = next_expire;
+ } else {
+ /*
+ * Before resetting next_expire, check that tmproutes_update()
+ * has not kicked in and scheduled another invocation.
+ */
+ if (callout_pending(&rnh->expire_callout) == 0)
+ rnh->next_expire = 0;
+ }
+ RIB_WUNLOCK(rnh);
+ CURVNET_RESTORE();
+}
+
+/*
+ * Function responsible for updating the time of the next calllout
+ * w.r.t. new temporal routes insertion.
+ *
+ * Called by the routing code upon adding new temporal route
+ * to the tree. RIB_WLOCK must be held.
+ */
+void
+tmproutes_update(struct rib_head *rnh, struct rtentry *rt)
+{
+ int ticks;
+
+ RIB_WLOCK_ASSERT(rnh);
+
+ if (rnh->next_expire == 0 || rnh->next_expire > rt->rt_expire) {
+ /*
+ * Callback is not scheduled, is executing,
+ * or is scheduled for a later time than we need.
+ *
+ * Schedule the one for the current @rt expiration time.
+ */
+ ticks = (rt->rt_expire - time_uptime) * hz;
+ if (ticks < 0)
+ ticks = 0;
+ callout_reset(&rnh->expire_callout, ticks, expire_callout, rnh);
+
+ rnh->next_expire = rt->rt_expire;
+ }
+}
+
+void
+tmproutes_init(struct rib_head *rh)
+{
+
+ callout_init(&rh->expire_callout, 1);
+}
+
+
+void
+tmproutes_destroy(struct rib_head *rh)
+{
+
+ callout_drain(&rh->expire_callout);
+}
+
Index: sys/net/route_var.h
===================================================================
--- sys/net/route_var.h
+++ sys/net/route_var.h
@@ -46,6 +46,11 @@
struct radix_node rnh_nodes[3]; /* empty tree for common case */
struct rmlock rib_lock; /* config/data path lock */
struct radix_mask_head rmhead; /* masks radix head */
+ struct vnet *rib_vnet; /* vnet pointer */
+ int rib_family; /* AF of the rtable */
+ u_int rib_fibnum; /* tableid */
+ struct callout expire_callout; /* Callout for expiring dynamic routes */
+ time_t next_expire; /* Next expire run ts */
};
#define RIB_RLOCK_TRACKER struct rm_priotracker _rib_tracker
@@ -76,5 +81,8 @@
return (res);
}
+void tmproutes_update(struct rib_head *rnh, struct rtentry *rt);
+void tmproutes_init(struct rib_head *rh);
+void tmproutes_destroy(struct rib_head *rh);
#endif
Index: sys/netinet/in_proto.c
===================================================================
--- sys/netinet/in_proto.c
+++ sys/netinet/in_proto.c
@@ -297,7 +297,7 @@
},
};
-extern int in_inithead(void **, int);
+extern int in_inithead(void **, int, u_int);
extern int in_detachhead(void **, int);
struct domain inetdomain = {
Index: sys/netinet/in_rmx.c
===================================================================
--- sys/netinet/in_rmx.c
+++ sys/netinet/in_rmx.c
@@ -49,7 +49,7 @@
#include <netinet/ip_icmp.h>
#include <netinet/ip_var.h>
-extern int in_inithead(void **head, int off);
+extern int in_inithead(void **head, int off, u_int fibnum);
#ifdef VIMAGE
extern int in_detachhead(void **head, int off);
#endif
@@ -116,11 +116,11 @@
* Initialize our routing tree.
*/
int
-in_inithead(void **head, int off)
+in_inithead(void **head, int off, u_int fibnum)
{
struct rib_head *rh;
- rh = rt_table_init(32);
+ rh = rt_table_init(32, AF_INET, fibnum);
if (rh == NULL)
return (0);
@@ -197,14 +197,3 @@
rtalloc_ign_fib(ro, ignflags, fibnum);
}
-void
-in_rtredirect(struct sockaddr *dst,
- struct sockaddr *gateway,
- struct sockaddr *netmask,
- int flags,
- struct sockaddr *src,
- u_int fibnum)
-{
- rtredirect_fib(dst, gateway, netmask, flags, src, fibnum);
-}
-
Index: sys/netinet/in_var.h
===================================================================
--- sys/netinet/in_var.h
+++ sys/netinet/in_var.h
@@ -474,8 +474,6 @@
/* XXX */
void in_rtalloc_ign(struct route *ro, u_long ignflags, u_int fibnum);
-void in_rtredirect(struct sockaddr *, struct sockaddr *,
- struct sockaddr *, int, struct sockaddr *, u_int);
#endif /* _KERNEL */
/* INET6 stuff */
Index: sys/netinet/ip_icmp.c
===================================================================
--- sys/netinet/ip_icmp.c
+++ sys/netinet/ip_icmp.c
@@ -128,6 +128,12 @@
&VNET_NAME(log_redirect), 0,
"Log ICMP redirects to the console");
+VNET_DEFINE_STATIC(int, redirtimeout) = 60 * 10; /* 10 minutes */
+#define V_redirtimeout VNET(redirtimeout)
+SYSCTL_INT(_net_inet_icmp, OID_AUTO, redirtimeout, CTLFLAG_VNET | CTLFLAG_RW,
+ &VNET_NAME(redirtimeout), 0,
+ "Delay in seconds before expiring redirect route");
+
VNET_DEFINE_STATIC(char, reply_src[IFNAMSIZ]);
#define V_reply_src VNET(reply_src)
SYSCTL_STRING(_net_inet_icmp, OID_AUTO, reply_src, CTLFLAG_VNET | CTLFLAG_RW,
@@ -690,10 +696,10 @@
#endif
icmpsrc.sin_addr = icp->icmp_ip.ip_dst;
for ( fibnum = 0; fibnum < rt_numfibs; fibnum++) {
- in_rtredirect((struct sockaddr *)&icmpsrc,
+ rtredirect_fib((struct sockaddr *)&icmpsrc,
(struct sockaddr *)&icmpdst,
- (struct sockaddr *)0, RTF_GATEWAY | RTF_HOST,
- (struct sockaddr *)&icmpgw, fibnum);
+ RTF_GATEWAY | RTF_HOST, (struct sockaddr *)&icmpgw,
+ V_redirtimeout, fibnum);
}
pfctlinput(PRC_REDIRECT_HOST, (struct sockaddr *)&icmpsrc);
break;
Index: sys/netinet6/icmp6.c
===================================================================
--- sys/netinet6/icmp6.c
+++ sys/netinet6/icmp6.c
@@ -2387,9 +2387,9 @@
} else
gw = ifp->if_addr->ifa_addr;
for (fibnum = 0; fibnum < rt_numfibs; fibnum++)
- in6_rtredirect((struct sockaddr *)&sdst, gw,
- (struct sockaddr *)NULL, rt_flags,
- (struct sockaddr *)&ssrc, fibnum);
+ rtredirect_fib((struct sockaddr *)&sdst, gw,
+ rt_flags, (struct sockaddr *)&ssrc,
+ V_icmp6_redirtimeout, fibnum);
}
/* finally update cached route in each socket via pfctlinput */
{
Index: sys/netinet6/in6_proto.c
===================================================================
--- sys/netinet6/in6_proto.c
+++ sys/netinet6/in6_proto.c
@@ -336,7 +336,7 @@
},
};
-extern int in6_inithead(void **, int);
+extern int in6_inithead(void **, int, u_int);
#ifdef VIMAGE
extern int in6_detachhead(void **, int);
#endif
@@ -566,7 +566,7 @@
"Accept ICMPv6 redirect messages");
SYSCTL_INT(_net_inet6_icmp6, ICMPV6CTL_REDIRTIMEOUT, redirtimeout,
CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(icmp6_redirtimeout), 0,
- ""); /* XXX unused */
+ "Delay in seconds before expiring redirect route");
SYSCTL_VNET_PCPUSTAT(_net_inet6_icmp6, ICMPV6CTL_STATS, stats,
struct icmp6stat, icmp6stat,
"ICMPv6 statistics (struct icmp6stat, netinet/icmp6.h)");
Index: sys/netinet6/in6_rmx.c
===================================================================
--- sys/netinet6/in6_rmx.c
+++ sys/netinet6/in6_rmx.c
@@ -96,7 +96,7 @@
#include <netinet/tcp_timer.h>
#include <netinet/tcp_var.h>
-extern int in6_inithead(void **head, int off);
+extern int in6_inithead(void **head, int off, u_int fibnum);
#ifdef VIMAGE
extern int in6_detachhead(void **head, int off);
#endif
@@ -157,11 +157,12 @@
*/
int
-in6_inithead(void **head, int off)
+in6_inithead(void **head, int off, u_int fibnum)
{
struct rib_head *rh;
- rh = rt_table_init(offsetof(struct sockaddr_in6, sin6_addr) << 3);
+ rh = rt_table_init(offsetof(struct sockaddr_in6, sin6_addr) << 3,
+ AF_INET6, fibnum);
if (rh == NULL)
return (0);
@@ -185,14 +186,6 @@
/*
* Extended API for IPv6 FIB support.
*/
-void
-in6_rtredirect(struct sockaddr *dst, struct sockaddr *gw, struct sockaddr *nm,
- int flags, struct sockaddr *src, u_int fibnum)
-{
-
- rtredirect_fib(dst, gw, nm, flags, src, fibnum);
-}
-
int
in6_rtrequest(int req, struct sockaddr *dst, struct sockaddr *gw,
struct sockaddr *mask, int flags, struct rtentry **ret_nrt, u_int fibnum)
Index: sys/netinet6/in6_var.h
===================================================================
--- sys/netinet6/in6_var.h
+++ sys/netinet6/in6_var.h
@@ -917,8 +917,6 @@
* Extended API for IPv6 FIB support.
*/
struct mbuf *ip6_tryforward(struct mbuf *);
-void in6_rtredirect(struct sockaddr *, struct sockaddr *, struct sockaddr *,
- int, struct sockaddr *, u_int);
int in6_rtrequest(int, struct sockaddr *, struct sockaddr *,
struct sockaddr *, int, struct rtentry **, u_int);
void in6_rtalloc(struct route_in6 *, u_int);
Index: sys/sys/domain.h
===================================================================
--- sys/sys/domain.h
+++ sys/sys/domain.h
@@ -60,7 +60,7 @@
struct protosw *dom_protosw, *dom_protoswNPROTOSW;
struct domain *dom_next;
int (*dom_rtattach) /* initialize routing table */
- (void **, int);
+ (void **, int, u_int);
int (*dom_rtdetach) /* clean up routing table */
(void **, int);
void *(*dom_ifattach)(struct ifnet *);
Index: tests/sys/net/routing/rtsock_print.h
===================================================================
--- tests/sys/net/routing/rtsock_print.h
+++ tests/sys/net/routing/rtsock_print.h
@@ -259,6 +259,19 @@
printf("%s: len %hu, pid: %d, seq %d, errno %d, flags: %s\n", msgtypes[rtm->rtm_type],
rtm->rtm_msglen, rtm->rtm_pid, rtm->rtm_seq, rtm->rtm_errno, flags_buf);
+ if (rtm->rtm_inits > 0) {
+ _printb(flags_buf, sizeof(flags_buf), rtm->rtm_inits, metricnames);
+ printf("metrics: %s\n", flags_buf);
+ if (rtm->rtm_inits & RTV_MTU)
+ printf("mtu: %lu\n", rtm->rtm_rmx.rmx_mtu);
+ if (rtm->rtm_inits & RTV_EXPIRE) {
+ struct timeval tv;
+ gettimeofday(&tv, NULL);
+ printf("expire: %d (%lu raw)\n",
+ (int)(rtm->rtm_rmx.rmx_expire - tv.tv_sec), rtm->rtm_rmx.rmx_expire);
+ }
+ }
+
_printb(flags_buf, sizeof(flags_buf), rtm->rtm_addrs, addrnames);
printf("sockaddrs: 0x%X %s\n", rtm->rtm_addrs, flags_buf);
Index: tests/sys/net/routing/test_rtsock_l3.c
===================================================================
--- tests/sys/net/routing/test_rtsock_l3.c
+++ tests/sys/net/routing/test_rtsock_l3.c
@@ -29,7 +29,12 @@
#include "rtsock_common.h"
#include "rtsock_config.h"
+#include "sys/types.h"
+#include <sys/time.h>
+#include <sys/ioctl.h>
+#include "net/bpf.h"
+
static inline struct rtsock_test_config *
presetup_ipv6(const atf_tc_t *tc)
{
@@ -158,8 +163,6 @@
ret = sa_equal_msg(sa, gw, msg, sizeof(msg));
RTSOCK_ATF_REQUIRE_MSG(rtm, ret != 0, "GATEWAY sa diff: %s", msg);
}
-
- RTSOCK_ATF_REQUIRE_MSG(rtm, rtm->rtm_pid > 0, "expected non-zero pid");
}
static void
@@ -503,8 +506,106 @@
CLEANUP_AFTER_TEST;
}
+ATF_TC_WITH_CLEANUP(rtm_add_v4_temporal1_success);
+ATF_TC_HEAD(rtm_add_v4_temporal1_success, tc)
+{
+ DESCRIBE_ROOT_TEST("Tests IPv4 route expiration with expire time set");
+}
+ATF_TC_BODY(rtm_add_v4_temporal1_success, tc)
+{
+ DECLARE_TEST_VARS;
+ c = presetup_ipv4(tc);
+
+ /* Create IPv4 subnetwork with smaller prefix */
+ struct sockaddr_in mask4;
+ struct sockaddr_in net4;
+ struct sockaddr_in gw4;
+ prepare_v4_network(c, &net4, &mask4, &gw4);
+
+ prepare_route_message(rtm, RTM_ADD, (struct sockaddr *)&net4,
+ (struct sockaddr *)&mask4, (struct sockaddr *)&gw4);
+
+ /* Set expire time to now */
+ struct timeval tv;
+ gettimeofday(&tv, NULL);
+ rtm->rtm_rmx.rmx_expire = tv.tv_sec - 1;
+ rtm->rtm_inits |= RTV_EXPIRE;
+
+ rtsock_send_rtm(c->rtsock_fd, rtm);
+ rtm = rtsock_read_rtm_reply(c->rtsock_fd, buffer, sizeof(buffer), rtm->rtm_seq);
+ ATF_REQUIRE_MSG(rtm != NULL, "unable to get rtsock reply for RTM_ADD");
+ RTSOCK_ATF_REQUIRE_MSG(rtm, rtm->rtm_inits & RTV_EXPIRE, "RTV_EXPIRE not set");
+
+ /* The next should be route deletion */
+ rtm = rtsock_read_rtm(c->rtsock_fd, buffer, sizeof(buffer));
+
+ verify_route_message(rtm, RTM_DELETE, (struct sockaddr *)&net4,
+ (struct sockaddr *)&mask4, (struct sockaddr *)&gw4);
+
+ /* TODO: add RTF_DONE */
+ verify_route_message_extra(rtm, c->ifindex, RTF_GATEWAY | RTF_STATIC);
+}
+
+ATF_TC_CLEANUP(rtm_add_v4_temporal1_success, tc)
+{
+ CLEANUP_AFTER_TEST;
+}
+
+ATF_TC_WITH_CLEANUP(rtm_add_v6_temporal1_success);
+ATF_TC_HEAD(rtm_add_v6_temporal1_success, tc)
+{
+ DESCRIBE_ROOT_TEST("Tests IPv6 global unicast prefix addition with directly-reachable GU GW");
+}
+
+ATF_TC_BODY(rtm_add_v6_temporal1_success, tc)
+{
+ DECLARE_TEST_VARS;
+
+ c = presetup_ipv6(tc);
+
+ /* Create IPv6 subnetwork with smaller prefix */
+ struct sockaddr_in6 mask6;
+ struct sockaddr_in6 net6;
+ struct sockaddr_in6 gw6;
+ prepare_v6_network(c, &net6, &mask6, &gw6);
+
+ prepare_route_message(rtm, RTM_ADD, (struct sockaddr *)&net6,
+ (struct sockaddr *)&mask6, (struct sockaddr *)&gw6);
+
+ /* Set expire time to now */
+ struct timeval tv;
+ gettimeofday(&tv, NULL);
+ rtm->rtm_rmx.rmx_expire = tv.tv_sec - 1;
+ rtm->rtm_inits |= RTV_EXPIRE;
+
+ rtsock_send_rtm(c->rtsock_fd, rtm);
+ rtm = rtsock_read_rtm_reply(c->rtsock_fd, buffer, sizeof(buffer), rtm->rtm_seq);
+ ATF_REQUIRE_MSG(rtm != NULL, "unable to get rtsock reply for RTM_ADD");
+ RTSOCK_ATF_REQUIRE_MSG(rtm, rtm->rtm_inits & RTV_EXPIRE, "RTV_EXPIRE not set");
+
+ /* The next should be route deletion */
+ rtm = rtsock_read_rtm(c->rtsock_fd, buffer, sizeof(buffer));
+
+ ATF_REQUIRE_MSG(0 == 1, "XX: %x %x\n", BIOCIMMEDIATE, BIOCFEEDBACK);
+
+ verify_route_message(rtm, RTM_DELETE, (struct sockaddr *)&net6,
+ (struct sockaddr *)&mask6, (struct sockaddr *)&gw6);
+
+
+ /* XXX: Currently kernel sets RTF_UP automatically but does NOT report it in the reply */
+ /* TODO: add RTF_DONE */
+ verify_route_message_extra(rtm, c->ifindex, RTF_GATEWAY | RTF_STATIC);
+}
+
+ATF_TC_CLEANUP(rtm_add_v6_temporal1_success, tc)
+{
+ CLEANUP_AFTER_TEST;
+}
+
+
+
ATF_TP_ADD_TCS(tp)
{
ATF_TP_ADD_TC(tp, rtm_get_v4_exact_success);
@@ -515,6 +616,9 @@
ATF_TP_ADD_TC(tp, rtm_del_v4_prefix_nogw_success);
ATF_TP_ADD_TC(tp, rtm_add_v6_gu_gw_gu_direct_success);
ATF_TP_ADD_TC(tp, rtm_del_v6_gu_prefix_nogw_success);
+ /* temporal routes */
+ ATF_TP_ADD_TC(tp, rtm_add_v4_temporal1_success);
+ ATF_TP_ADD_TC(tp, rtm_add_v6_temporal1_success);
return (atf_no_error());
}
Index: tests/sys/netinet6/Makefile
===================================================================
--- tests/sys/netinet6/Makefile
+++ tests/sys/netinet6/Makefile
@@ -8,15 +8,18 @@
ATF_TESTS_SH= \
exthdr \
mld \
- scapyi386
+ scapyi386 \
+ redirect
${PACKAGE}FILES+= exthdr.py
${PACKAGE}FILES+= mld.py
${PACKAGE}FILES+= scapyi386.py
+${PACKAGE}FILES+= redirect.py
${PACKAGE}FILESMODE_exthdr.py= 0555
${PACKAGE}FILESMODE_mld.py= 0555
${PACKAGE}FILESMODE_scapyi386.py=0555
+${PACKAGE}FILESMODE_redirect.py=0555
TESTS_SUBDIRS+= frag6
Index: tests/sys/netinet6/redirect.sh
===================================================================
--- /dev/null
+++ tests/sys/netinet6/redirect.sh
@@ -0,0 +1,113 @@
+#-
+# SPDX-License-Identifier: BSD-2-Clause
+#
+# Copyright (c) 2020 Alexander V. Chernikov
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+# $FreeBSD$
+#
+
+. $(atf_get_srcdir)/../common/vnet.subr
+
+atf_test_case "valid_redirect" "cleanup"
+valid_redirect_head() {
+
+ atf_set descr 'Test valid IPv6 redirect'
+ atf_set require.user root
+ atf_set require.progs scapy
+}
+
+valid_redirect_body() {
+
+ ids=65533
+ id=`printf "%x" ${ids}`
+ if [ $$ -gt 65535 ]; then
+ xl=`printf "%x" $(($$ - 65535))`
+ yl="1"
+ else
+ xl=`printf "%x" $$`
+ yl=""
+ fi
+
+ vnet_init
+
+ ip6a="2001:db8:6666:0000:${yl}:${id}:1:${xl}"
+ ip6b="2001:db8:6666:0000:${yl}:${id}:2:${xl}"
+
+ net6="2001:db8:6667::/64"
+ dst_addr6=`echo ${net6} | awk -F/ '{printf"%s4242", $1}'`
+ new_rtr_ll_ip="fe80::5555"
+
+ # remote_rtr
+ remote_rtr_ll_ip="fe80::4242"
+ remote_rtr_mac="00:00:5E:00:53:42"
+
+ script_name="redirect.py"
+
+ epair=$(vnet_mkepair)
+ ifconfig ${epair}a up
+ ifconfig ${epair}a inet6 ${ip6a}/64
+
+ jname="v6t-${id}-${yl}-${xl}"
+ vnet_mkjail ${jname} ${epair}b
+ jexec ${jname} ifconfig ${epair}b up
+ jexec ${jname} ifconfig ${epair}b inet6 ${ip6b}/64
+
+ # Setup static entry for the remote router
+ jexec ${jname} ndp -s ${remote_rtr_ll_ip}%${epair}b ${remote_rtr_mac}
+ # setup prefix reachable via router
+ jexec ${jname} route add -6 -net ${net6} ${remote_rtr_ll_ip}%${epair}b
+
+ local_ll_ip=`jexec ${jname} ifconfig ${epair}b inet6 | awk '$1 ~ /inet6/&&$2~/^fe80/ {print$2}'|awk -F% '{print$1}'`
+ local_ll_mac=`jexec ${jname} ifconfig ${epair}b ether | awk '$1~/ether/{print$2}'`
+
+ # wait for DAD to complete
+ sleep 2
+
+ # echo "LOCAL: ${local_ll_ip} ${local_ll_mac}"
+ # echo "REMOTE: ${remote_rtr_ll_ip} ${remote_rtr_mac}"
+
+ atf_check -s exit:0 $(atf_get_srcdir)/${script_name} \
+ --smac ${remote_rtr_mac} --dmac ${local_ll_mac} \
+ --sip ${remote_rtr_ll_ip} --dip ${local_ll_ip} \
+ --route ${dst_addr6} --gw ${new_rtr_ll_ip} \
+ --iface ${epair}a
+
+ count=`jexec ${jname} route -n get -6 ${dst_addr6} | grep destination | grep -c ${dst_addr6}`
+ # Verify redirect got installed
+ atf_check_equal "1" "${count}"
+}
+
+valid_redirect_cleanup() {
+
+ vnet_cleanup
+}
+
+atf_init_test_cases()
+{
+
+ atf_add_test_case "valid_redirect"
+}
+
+# end
+
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Sun, Jan 12, 4:58 AM (18 h, 9 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
15761446
Default Alt Text
D22988.id66234.diff (34 KB)
Attached To
Mode
D22988: Bring back redirect route expiration.
Attached
Detach File
Event Timeline
Log In to Comment