aboutsummaryrefslogtreecommitdiff
path: root/sys/net
diff options
context:
space:
mode:
authorAlexander V. Chernikov <melifaro@FreeBSD.org>2022-12-03 17:10:50 +0000
committerAlexander V. Chernikov <melifaro@FreeBSD.org>2023-01-23 22:04:03 +0000
commitdfc6db8e18b65ee3101a007aace55e21d72c4011 (patch)
tree3924149bf6482324caec87d85512960b4e53dda2 /sys/net
parenta9ed45a937697f7e2b331c39c9237e9c63a7c799 (diff)
downloadsrc-dfc6db8e18b65ee3101a007aace55e21d72c4011.tar.gz
src-dfc6db8e18b65ee3101a007aace55e21d72c4011.zip
netlink: add interface notification on link status / flags change.
* Add link-state change notifications by subscribing to ifnet_link_event. In the Linux netlink model, link state is reported in 2 places: first is the IFLA_OPERSTATE, which stores state per RFC2863. The second is an IFF_LOWER_UP interface flag. As many applications rely on the latter, reserve 1 bit from if_flags, named as IFF_NETLINK_1. This flag is mapped to IFF_LOWER_UP in the netlink headers. This is done to avoid making applications think this flag is actually supported / presented in non-netlink outputs. * Add flag change notifications, by hooking into rt_ifmsg(). In the netlink model, notification should include the bitmask for the change flags. Update rt_ifmsg() to include such bitmask. Differential Revision: https://reviews.freebsd.org/D37597 (cherry picked from commit 1bcd230f9508b3c917f26be4b905e4b5141decea)
Diffstat (limited to 'sys/net')
-rw-r--r--sys/net/if.c10
-rw-r--r--sys/net/if.h1
-rw-r--r--sys/net/route.c24
-rw-r--r--sys/net/route.h1
-rw-r--r--sys/net/route/route_ctl.h2
-rw-r--r--sys/net/rtsock.c10
6 files changed, 39 insertions, 9 deletions
diff --git a/sys/net/if.c b/sys/net/if.c
index d42b642e8d18..7423c4963f57 100644
--- a/sys/net/if.c
+++ b/sys/net/if.c
@@ -2222,7 +2222,7 @@ if_unroute(struct ifnet *ifp, int flag, int fam)
if (ifp->if_carp)
(*carp_linkstate_p)(ifp);
- rt_ifmsg(ifp);
+ rt_ifmsg_14(ifp, IFF_UP);
}
/*
@@ -2246,7 +2246,7 @@ if_route(struct ifnet *ifp, int flag, int fam)
NET_EPOCH_EXIT(et);
if (ifp->if_carp)
(*carp_linkstate_p)(ifp);
- rt_ifmsg(ifp);
+ rt_ifmsg_14(ifp, IFF_UP);
#ifdef INET6
in6_if_up(ifp);
#endif
@@ -2290,7 +2290,7 @@ do_link_state_change(void *arg, int pending)
link_state = ifp->if_link_state;
CURVNET_SET(ifp->if_vnet);
- rt_ifmsg(ifp);
+ rt_ifmsg_14(ifp, 0);
if (ifp->if_vlantrunk != NULL)
(*vlan_link_state_p)(ifp);
@@ -2760,7 +2760,7 @@ ifhwioctl(u_long cmd, struct ifnet *ifp, caddr_t data, struct thread *td)
error = (*ifp->if_ioctl)(ifp, cmd, data);
if (error == 0) {
getmicrotime(&ifp->if_lastchange);
- rt_ifmsg(ifp);
+ rt_ifmsg_14(ifp, 0);
#ifdef INET
DEBUGNET_NOTIFY_MTU(ifp);
#endif
@@ -3190,7 +3190,7 @@ if_setflag(struct ifnet *ifp, int flag, int pflag, int *refcount, int onswitch)
if (error)
goto recover;
/* Notify userland that interface flags have changed */
- rt_ifmsg(ifp);
+ rt_ifmsg_14(ifp, flag);
return (0);
recover:
diff --git a/sys/net/if.h b/sys/net/if.h
index 782e792cf87c..409289869c27 100644
--- a/sys/net/if.h
+++ b/sys/net/if.h
@@ -163,6 +163,7 @@ struct if_data {
#define IFF_DYING 0x200000 /* (n) interface is winding down */
#define IFF_RENAMING 0x400000 /* (n) interface is being renamed */
#define IFF_NOGROUP 0x800000 /* (n) interface is not part of any groups */
+#define IFF_NETLINK_1 0x1000000 /* (n) used by netlink */
/*
* Old names for driver flags so that user space tools can continue to use
diff --git a/sys/net/route.c b/sys/net/route.c
index b4076123e5d6..80d08d1bc7f0 100644
--- a/sys/net/route.c
+++ b/sys/net/route.c
@@ -813,12 +813,34 @@ rt_routemsg_info(int cmd, struct rt_addrinfo *info, int fibnum)
return (rtsock_routemsg_info(cmd, info, fibnum));
}
+void
+rt_ifmsg(struct ifnet *ifp)
+{
+ rt_ifmsg_14(ifp, 0);
+}
+
+void
+rt_ifmsg_14(struct ifnet *ifp, int if_flags_mask)
+{
+ rtsock_callback_p->ifmsg_f(ifp, if_flags_mask);
+ netlink_callback_p->ifmsg_f(ifp, if_flags_mask);
+}
+
/* Netlink-related callbacks needed to glue rtsock, netlink and linuxolator */
static void
ignore_route_event(uint32_t fibnum, const struct rib_cmd_info *rc)
{
}
-static struct rtbridge ignore_cb = { .route_f = ignore_route_event };
+
+static void
+ignore_ifmsg_event(struct ifnet *ifp, int if_flags_mask)
+{
+}
+
+static struct rtbridge ignore_cb = {
+ .route_f = ignore_route_event,
+ .ifmsg_f = ignore_ifmsg_event,
+};
void *linux_netlink_p = NULL; /* Callback pointer for Linux translator functions */
struct rtbridge *rtsock_callback_p = &ignore_cb;
diff --git a/sys/net/route.h b/sys/net/route.h
index a2394d54b92f..3dac437426b0 100644
--- a/sys/net/route.h
+++ b/sys/net/route.h
@@ -416,6 +416,7 @@ struct rib_head;
void rt_ieee80211msg(struct ifnet *, int, void *, size_t);
void rt_ifmsg(struct ifnet *);
+void rt_ifmsg_14(struct ifnet *, int);
void rt_missmsg(int, struct rt_addrinfo *, int, int);
void rt_missmsg_fib(int, struct rt_addrinfo *, int, int, int);
int rt_addrmsg(int, struct ifaddr *, int);
diff --git a/sys/net/route/route_ctl.h b/sys/net/route/route_ctl.h
index d150da6264d4..e8560e681ddb 100644
--- a/sys/net/route/route_ctl.h
+++ b/sys/net/route/route_ctl.h
@@ -191,8 +191,10 @@ void rib_notify(struct rib_head *rnh, enum rib_subscription_type type,
/* Event bridge */
typedef void route_event_f(uint32_t fibnum, const struct rib_cmd_info *rc);
+typedef void ifmsg_event_f(struct ifnet *ifp, int if_flags_mask);
struct rtbridge{
route_event_f *route_f;
+ ifmsg_event_f *ifmsg_f;
};
extern struct rtbridge *rtsock_callback_p;
extern struct rtbridge *netlink_callback_p;
diff --git a/sys/net/rtsock.c b/sys/net/rtsock.c
index 69a5698e4b5f..fc9439602c13 100644
--- a/sys/net/rtsock.c
+++ b/sys/net/rtsock.c
@@ -211,6 +211,7 @@ static void send_rtm_reply(struct socket *so, struct rt_msghdr *rtm,
static bool can_export_rte(struct ucred *td_ucred, bool rt_is_host,
const struct sockaddr *rt_dst);
static void rtsock_notify_event(uint32_t fibnum, const struct rib_cmd_info *rc);
+static void rtsock_ifmsg(struct ifnet *ifp, int if_flags_mask);
static struct netisr_handler rtsock_nh = {
.nh_name = "rtsock",
@@ -288,7 +289,10 @@ rts_handle_route_event(uint32_t fibnum, const struct rib_cmd_info *rc)
#endif
report_route_event(rc, (void *)(uintptr_t)fibnum);
}
-static struct rtbridge rtsbridge = { .route_f = rts_handle_route_event };
+static struct rtbridge rtsbridge = {
+ .route_f = rts_handle_route_event,
+ .ifmsg_f = rtsock_ifmsg,
+};
static struct rtbridge *rtsbridge_orig_p;
static void
@@ -1984,8 +1988,8 @@ rt_missmsg(int type, struct rt_addrinfo *rtinfo, int flags, int error)
* This routine is called to generate a message from the routing
* socket indicating that the status of a network interface has changed.
*/
-void
-rt_ifmsg(struct ifnet *ifp)
+static void
+rtsock_ifmsg(struct ifnet *ifp, int if_flags_mask __unused)
{
struct if_msghdr *ifm;
struct mbuf *m;