mirror of
https://git.FreeBSD.org/src.git
synced 2025-01-23 16:01:42 +00:00
Finish r274175: do control plane MTU tracking.
Update route MTU in case of ifnet MTU change. Add new RTF_FIXEDMTU to track explicitly specified MTU. Old behavior: ifconfig em0 mtu 1500->9000 -> all routes traversing em0 do not change MTU. User has to manually update all routes. ifconfig em0 mtu 9000->1500 -> all routes traversing em0 do not change MTU. However, if ip[6]_output finds route with rt_mtu > interface mtu, rt_mtu gets updated. New behavior: ifconfig em0 mtu 1500->9000 -> all interface routes in all fibs gets updated with new MTU unless RTF_FIXEDMTU flag set on them. ifconfig em0 mtu 9000->1500 -> all routes in all fibs gets updated with new MTU unless RTF_FIXEDMTU flag set on them AND rt_mtu is less than ifp mtu. route add ... -mtu XXX automatically sets RTF_FIXEDMTU flag. route change .. -mtu 0 automatically removes RTF_FIXEDMTU flag. PR: 194238 MFC after: 1 month CR: D1125
This commit is contained in:
parent
e93397e537
commit
7f948f12f6
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=274611
@ -1587,7 +1587,7 @@ static const char routeflags[] =
|
||||
"\1UP\2GATEWAY\3HOST\4REJECT\5DYNAMIC\6MODIFIED\7DONE"
|
||||
"\012XRESOLVE\013LLINFO\014STATIC\015BLACKHOLE"
|
||||
"\017PROTO2\020PROTO1\021PRCLONING\022WASCLONED\023PROTO3"
|
||||
"\025PINNED\026LOCAL\027BROADCAST\030MULTICAST\035STICKY";
|
||||
"\024FIXEDMTU\025PINNED\026LOCAL\027BROADCAST\030MULTICAST\035STICKY";
|
||||
static const char ifnetflags[] =
|
||||
"\1UP\2BROADCAST\3DEBUG\4LOOPBACK\5PTP\6b6\7RUNNING\010NOARP"
|
||||
"\011PPROMISC\012ALLMULTI\013OACTIVE\014SIMPLEX\015LINK0\016LINK1"
|
||||
|
@ -2494,6 +2494,7 @@ ifhwioctl(u_long cmd, struct ifnet *ifp, caddr_t data, struct thread *td)
|
||||
#ifdef INET6
|
||||
nd6_setmtu(ifp);
|
||||
#endif
|
||||
rt_updatemtu(ifp);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
102
sys/net/route.c
102
sys/net/route.c
@ -141,6 +141,14 @@ static int rtrequest1_fib_change(struct radix_node_head *, struct rt_addrinfo *,
|
||||
struct rtentry **, u_int);
|
||||
static void rt_setmetrics(const struct rt_addrinfo *, struct rtentry *);
|
||||
|
||||
struct if_mtuinfo
|
||||
{
|
||||
struct ifnet *ifp;
|
||||
int mtu;
|
||||
};
|
||||
|
||||
static int if_updatemtu_cb(struct radix_node *, void *);
|
||||
|
||||
/*
|
||||
* handler for net.my_fibnum
|
||||
*/
|
||||
@ -947,6 +955,70 @@ rt_expunge(struct radix_node_head *rnh, struct rtentry *rt)
|
||||
return (error);
|
||||
}
|
||||
|
||||
static int
|
||||
if_updatemtu_cb(struct radix_node *rn, void *arg)
|
||||
{
|
||||
struct rtentry *rt;
|
||||
struct if_mtuinfo *ifmtu;
|
||||
|
||||
rt = (struct rtentry *)rn;
|
||||
ifmtu = (struct if_mtuinfo *)arg;
|
||||
|
||||
if (rt->rt_ifp != ifmtu->ifp)
|
||||
return (0);
|
||||
|
||||
if (rt->rt_mtu >= ifmtu->mtu) {
|
||||
/* We have to decrease mtu regardless of flags */
|
||||
rt->rt_mtu = ifmtu->mtu;
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* New MTU is bigger. Check if are allowed to alter it
|
||||
*/
|
||||
if ((rt->rt_flags & (RTF_FIXEDMTU | RTF_GATEWAY | RTF_HOST)) != 0) {
|
||||
|
||||
/*
|
||||
* Skip routes with user-supplied MTU and
|
||||
* non-interface routes
|
||||
*/
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* We are safe to update route MTU */
|
||||
rt->rt_mtu = ifmtu->mtu;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
void
|
||||
rt_updatemtu(struct ifnet *ifp)
|
||||
{
|
||||
struct if_mtuinfo ifmtu;
|
||||
struct radix_node_head *rnh;
|
||||
int i, j;
|
||||
|
||||
ifmtu.ifp = ifp;
|
||||
|
||||
/*
|
||||
* Try to update rt_mtu for all routes using this interface
|
||||
* Unfortunately the only way to do this is to traverse all
|
||||
* routing tables in all fibs/domains.
|
||||
*/
|
||||
for (i = 1; i <= AF_MAX; i++) {
|
||||
ifmtu.mtu = if_getmtu_family(ifp, i);
|
||||
for (j = 0; j < rt_numfibs; j++) {
|
||||
rnh = rt_tables_get_rnh(j, i);
|
||||
if (rnh == NULL)
|
||||
continue;
|
||||
RADIX_NODE_HEAD_LOCK(rnh);
|
||||
rnh->rnh_walktree(rnh, if_updatemtu_cb, &ifmtu);
|
||||
RADIX_NODE_HEAD_UNLOCK(rnh);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#if 0
|
||||
int p_sockaddr(char *buf, int buflen, struct sockaddr *s);
|
||||
int rt_print(char *buf, int buflen, struct rtentry *rt);
|
||||
@ -1408,6 +1480,7 @@ rtrequest1_fib_change(struct radix_node_head *rnh, struct rt_addrinfo *info,
|
||||
int error = 0;
|
||||
int free_ifa = 0;
|
||||
int family, mtu;
|
||||
struct if_mtuinfo ifmtu;
|
||||
|
||||
rt = (struct rtentry *)rnh->rnh_lookup(info->rti_info[RTAX_DST],
|
||||
info->rti_info[RTAX_NETMASK], rnh);
|
||||
@ -1478,12 +1551,19 @@ rtrequest1_fib_change(struct radix_node_head *rnh, struct rt_addrinfo *info,
|
||||
if (rt->rt_ifa && rt->rt_ifa->ifa_rtrequest != NULL)
|
||||
rt->rt_ifa->ifa_rtrequest(RTM_ADD, rt, info);
|
||||
|
||||
/* Ensure route MTU is not bigger than interface MTU */
|
||||
/* Alter route MTU if necessary */
|
||||
if (rt->rt_ifp != NULL) {
|
||||
family = info->rti_info[RTAX_DST]->sa_family;
|
||||
mtu = if_getmtu_family(rt->rt_ifp, family);
|
||||
if (rt->rt_mtu > mtu)
|
||||
/* Set default MTU */
|
||||
if (rt->rt_mtu == 0)
|
||||
rt->rt_mtu = mtu;
|
||||
if (rt->rt_mtu != mtu) {
|
||||
/* Check if we really need to update */
|
||||
ifmtu.ifp = rt->rt_ifp;
|
||||
ifmtu.mtu = mtu;
|
||||
if_updatemtu_cb(rt->rt_nodes, &ifmtu);
|
||||
}
|
||||
}
|
||||
|
||||
if (ret_nrt) {
|
||||
@ -1501,8 +1581,24 @@ static void
|
||||
rt_setmetrics(const struct rt_addrinfo *info, struct rtentry *rt)
|
||||
{
|
||||
|
||||
if (info->rti_mflags & RTV_MTU)
|
||||
if (info->rti_mflags & RTV_MTU) {
|
||||
if (info->rti_rmx->rmx_mtu != 0) {
|
||||
|
||||
/*
|
||||
* MTU was explicitly provided by user.
|
||||
* Keep it.
|
||||
*/
|
||||
rt->rt_flags |= RTF_FIXEDMTU;
|
||||
} else {
|
||||
|
||||
/*
|
||||
* User explicitly sets MTU to 0.
|
||||
* Assume rollback to default.
|
||||
*/
|
||||
rt->rt_flags &= ~RTF_FIXEDMTU;
|
||||
}
|
||||
rt->rt_mtu = info->rti_rmx->rmx_mtu;
|
||||
}
|
||||
if (info->rti_mflags & RTV_WEIGHT)
|
||||
rt->rt_weight = info->rti_rmx->rmx_weight;
|
||||
/* Kernel -> userland timebase conversion. */
|
||||
|
@ -151,7 +151,7 @@ struct rtentry {
|
||||
/* 0x10000 unused, was RTF_PRCLONING */
|
||||
/* 0x20000 unused, was RTF_WASCLONED */
|
||||
#define RTF_PROTO3 0x40000 /* protocol specific routing flag */
|
||||
/* 0x80000 unused */
|
||||
#define RTF_FIXEDMTU 0x80000 /* MTU was explicitly specified */
|
||||
#define RTF_PINNED 0x100000 /* route is immutable */
|
||||
#define RTF_LOCAL 0x200000 /* route represents a local address */
|
||||
#define RTF_BROADCAST 0x400000 /* route represents a bcast address */
|
||||
@ -378,6 +378,7 @@ int rtsock_routemsg(int, struct ifnet *ifp, int, struct rtentry *, int);
|
||||
int rt_expunge(struct radix_node_head *, struct rtentry *);
|
||||
void rtfree(struct rtentry *);
|
||||
int rt_check(struct rtentry **, struct rtentry **, struct sockaddr *);
|
||||
void rt_updatemtu(struct ifnet *);
|
||||
|
||||
/* XXX MRT COMPAT VERSIONS THAT SET UNIVERSE to 0 */
|
||||
/* Thes are used by old code not yet converted to use multiple FIBS */
|
||||
|
@ -322,20 +322,10 @@ ip_output(struct mbuf *m, struct mbuf *opt, struct route *ro, int flags,
|
||||
* Calculate MTU. If we have a route that is up, use that,
|
||||
* otherwise use the interface's MTU.
|
||||
*/
|
||||
if (rte != NULL && (rte->rt_flags & (RTF_UP|RTF_HOST))) {
|
||||
/*
|
||||
* This case can happen if the user changed the MTU
|
||||
* of an interface after enabling IP on it. Because
|
||||
* most netifs don't keep track of routes pointing to
|
||||
* them, there is no way for one to update all its
|
||||
* routes when the MTU is changed.
|
||||
*/
|
||||
if (rte->rt_mtu > ifp->if_mtu)
|
||||
rte->rt_mtu = ifp->if_mtu;
|
||||
if (rte != NULL && (rte->rt_flags & (RTF_UP|RTF_HOST)))
|
||||
mtu = rte->rt_mtu;
|
||||
} else {
|
||||
else
|
||||
mtu = ifp->if_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, rte, (rte != NULL) ? rte->rt_flags : 0, ifp));
|
||||
|
@ -1275,17 +1275,6 @@ ip6_getpmtu(struct route_in6 *ro_pmtu, struct route_in6 *ro,
|
||||
*/
|
||||
alwaysfrag = 1;
|
||||
mtu = IPV6_MMTU;
|
||||
} else if (mtu > ifmtu) {
|
||||
/*
|
||||
* The MTU on the route is larger than the MTU on
|
||||
* the interface! This shouldn't happen, unless the
|
||||
* MTU of the interface has been changed after the
|
||||
* interface was brought up. Change the MTU in the
|
||||
* route to match the interface MTU (as long as the
|
||||
* field isn't locked).
|
||||
*/
|
||||
mtu = ifmtu;
|
||||
ro_pmtu->ro_rt->rt_mtu = mtu;
|
||||
}
|
||||
} else if (ifp) {
|
||||
mtu = IN6_LINKMTU(ifp);
|
||||
|
Loading…
Reference in New Issue
Block a user