From ab2d7cdfa4bf8c0f4e11a687e48f871879cdfbd3 Mon Sep 17 00:00:00 2001 From: Roy Marples Date: Mon, 17 Feb 2025 15:01:45 +0000 Subject: [PATCH] For route MTU comparison allow zero MTU to match interface MTU Because some OS put the interface MTU into the route MTU if the route does not define its own. --- src/dhcpcd.h | 1 + src/if-bsd.c | 1 + src/if-linux.c | 10 ++++++++-- src/if-sun.c | 1 + src/if.c | 13 +++++++++++++ src/if.h | 1 + src/route.c | 12 +++++++++++- 7 files changed, 36 insertions(+), 3 deletions(-) diff --git a/src/dhcpcd.h b/src/dhcpcd.h index 17aa8d96..074ae1ca 100644 --- a/src/dhcpcd.h +++ b/src/dhcpcd.h @@ -80,6 +80,7 @@ struct interface { uint16_t hwtype; /* ARPHRD_ETHER for example */ unsigned char hwaddr[HWADDR_LEN]; uint8_t hwlen; + unsigned int mtu; unsigned short vlanid; unsigned int metric; int carrier; diff --git a/src/if-bsd.c b/src/if-bsd.c index d184ef84..8af59610 100644 --- a/src/if-bsd.c +++ b/src/if-bsd.c @@ -1252,6 +1252,7 @@ if_ifinfo(struct dhcpcd_ctx *ctx, const struct if_msghdr *ifm) if ((ifp = if_findindex(ctx->ifaces, ifm->ifm_index)) == NULL) return 0; + ifp->mtu = if_mtu(ifp); link_state = if_carrier(ifp, &ifm->ifm_data); dhcpcd_handlecarrier(ifp, link_state, (unsigned int)ifm->ifm_flags); return 0; diff --git a/src/if-linux.c b/src/if-linux.c index b6317c35..2a105a11 100644 --- a/src/if-linux.c +++ b/src/if-linux.c @@ -1053,7 +1053,7 @@ link_netlink(struct dhcpcd_ctx *ctx, void *arg, struct nlmsghdr *nlm) struct interface *ifp = arg; int r; size_t len; - struct rtattr *rta, *hwaddr; + struct rtattr *rta, *hwaddr, *mtu; struct ifinfomsg *ifi; char ifn[IF_NAMESIZE + 1]; @@ -1082,7 +1082,7 @@ link_netlink(struct dhcpcd_ctx *ctx, void *arg, struct nlmsghdr *nlm) rta = (void *)((char *)ifi + NLMSG_ALIGN(sizeof(*ifi))); len = NLMSG_PAYLOAD(nlm, sizeof(*ifi)); *ifn = '\0'; - hwaddr = NULL; + hwaddr = mtu = NULL; for (; RTA_OK(rta, len); rta = RTA_NEXT(rta, len)) { switch (rta->rta_type) { @@ -1098,6 +1098,9 @@ link_netlink(struct dhcpcd_ctx *ctx, void *arg, struct nlmsghdr *nlm) case IFLA_ADDRESS: hwaddr = rta; break; + case IFLA_MTU: + mtu = rta; + break; } } @@ -1139,6 +1142,9 @@ link_netlink(struct dhcpcd_ctx *ctx, void *arg, struct nlmsghdr *nlm) return 0; } + if (mtu != NULL) + ifp->mtu = *(unsigned int *)RTA_DATA(mtu); + /* Re-read hardware address and friends */ if (!(ifi->ifi_flags & IFF_UP)) { void *hwa = hwaddr != NULL ? RTA_DATA(hwaddr) : NULL; diff --git a/src/if-sun.c b/src/if-sun.c index 7f244b77..cb4849b4 100644 --- a/src/if-sun.c +++ b/src/if-sun.c @@ -1059,6 +1059,7 @@ if_ifinfo(struct dhcpcd_ctx *ctx, const struct if_msghdr *ifm) state = LINK_UP; flags |= IFF_UP; } + ifp->mtu = if_mtu(ifp); dhcpcd_handlecarrier(ifp, state, flags); return 0; } diff --git a/src/if.c b/src/if.c index dea833df..69c2c4c1 100644 --- a/src/if.c +++ b/src/if.c @@ -182,6 +182,18 @@ if_setflag(struct interface *ifp, short setflag, short unsetflag) return 0; } +unsigned int +if_mtu(struct interface *ifp) +{ + struct ifreq ifr = { .ifr_mtu = 0 }; + + strlcpy(ifr.ifr_name, ifp->name, sizeof(ifr.ifr_name)); + if (ioctl(ifp->ctx->pf_inet_fd, SIOCGIFMTU, &ifr) == -1) + return 0; + + return (unsigned int)ifr.ifr_mtu; +} + bool if_is_link_up(const struct interface *ifp) { @@ -685,6 +697,7 @@ if_discover(struct dhcpcd_ctx *ctx, struct ifaddrs **ifaddrs, } } + ifp->mtu = if_mtu(ifp); ifp->vlanid = if_vlanid(ifp); #ifdef SIOCGIFPRIORITY diff --git a/src/if.h b/src/if.h index 6cb9d766..1872a37b 100644 --- a/src/if.h +++ b/src/if.h @@ -163,6 +163,7 @@ int if_ioctl(struct dhcpcd_ctx *, ioctl_request_t, void *, size_t); #define pioctl(ctx, req, data, len) ioctl((ctx)->pf_inet_fd, (req),(data),(len)) #endif int if_setflag(struct interface *, short, short); +unsigned int if_mtu(struct interface *); #define if_up(ifp) if_setflag((ifp), (IFF_UP | IFF_RUNNING), 0) #define if_down(ifp) if_setflag((ifp), 0, IFF_UP); bool if_is_link_up(const struct interface *); diff --git a/src/route.c b/src/route.c index d56b9d30..bbc7bfd7 100644 --- a/src/route.c +++ b/src/route.c @@ -506,9 +506,19 @@ rt_recvrt(int cmd, const struct rt *rt, pid_t pid) static bool rt_cmp_misc(struct rt *nrt, struct rt *ort) { - /* MTU changed */ +#if defined(__FreeBSD__) || defined(__DragonFly__) + /* FreeBSD puts the interface MTU into the route MTU + * if the route does not define it's own. */ + unsigned int nmtu, omtu; + + nmtu = nrt->rt_mtu ? nrt->rt_mtu : nrt->rt_ifp->mtu; + omtu = ort->rt_mtu ? ort->rt_mtu : ort->rt_ifp->mtu; + if (omtu != nmtu) + return false; +#else if (ort->rt_mtu != nrt->rt_mtu) return false; +#endif #ifdef HAVE_ROUTE_LIFETIME uint32_t deviation; -- 2.47.2