freebsd-src/sbin/route/route_netlink.c

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

914 lines
22 KiB
C
Raw Normal View History

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <err.h>
#include <errno.h>
#include <sys/bitcount.h>
#include <sys/param.h>
#include <sys/linker.h>
#include <sys/module.h>
#include <sys/socket.h>
#include <sys/sysctl.h>
#include <sys/time.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <net/ethernet.h>
#include <net/if.h>
#include <net/if_dl.h>
#include <net/if_types.h>
#include <netlink/netlink.h>
#include <netlink/netlink_route.h>
#include <netlink/netlink_snl.h>
#include <netlink/netlink_snl_route.h>
#include <netlink/netlink_snl_route_compat.h>
#include <netlink/netlink_snl_route_parsers.h>
const char *routename(struct sockaddr *);
const char *netname(struct sockaddr *);
void printb(int, const char *);
extern const char routeflags[];
extern int verbose, debugonly;
int rtmsg_nl(int cmd, int rtm_flags, int fib, int rtm_addrs, struct sockaddr_storage *so,
struct rt_metrics *rt_metrics);
int flushroutes_fib_nl(int fib, int af);
void monitor_nl(int fib);
struct nl_helper;
route: show originator PID in netlink monitor Replacing rtsock with netlink also means providing similar tracing facilities, rtsock provides `route -n monitor` interface, where each message can be traced to the originating PID. This diff closes the feature gap between rtsock and netlink in that regard. Netlink works slightly differently from rtsock, as it is a generic message "broker". It calls some kernel KPIs and returns the result to the caller. Other Netlink consumers gets notified on the changed kernel state using the relevant subsystem callbacks. Typically, it is close to impossible to pass some data through these KPIs to enhance the notification. This diff approaches the problem by using osd(9) to assign the relevant socket pointer (`'nlp`) to the per-socket taskqueue execution thread. This change allows to recover the pointer in the aforementioned notification callbacks and extract some additional data. Using `osd(9)` (and adding additional metadata) to the notification receiver comes with some additional cost attached, so this interface needs to be enabled explicitly by using a newly-created `NETLINK_MSG_INFO` `SOL_NETLINK` socket option. The actual medatadata (which includes the originator PID) is provided via control messages. To enable extensibility, the control message data is encoded in the standard netlink(TLV-based) fashion. The list of the currently-provided properties can be found in `nlmsginfo_attrs`. snl(3) is extended to enable decoding of netlink messages with metadata (`snl_read_message_dbg()` stores the parsed structure in the provided buffer). Differential Revision: https://reviews.freebsd.org/D39391
2023-04-28 12:44:04 +00:00
struct snl_msg_info;
static void print_getmsg(struct nl_helper *h, struct nlmsghdr *hdr,
struct sockaddr *dst);
static void print_nlmsg(struct nl_helper *h, struct nlmsghdr *hdr,
struct snl_msg_info *cinfo);
#define s6_addr32 __u6_addr.__u6_addr32
#define bitcount32(x) __bitcount32((uint32_t)(x))
static int
inet6_get_plen(const struct in6_addr *addr)
{
return (bitcount32(addr->s6_addr32[0]) + bitcount32(addr->s6_addr32[1]) +
bitcount32(addr->s6_addr32[2]) + bitcount32(addr->s6_addr32[3]));
}
static void
ip6_writemask(struct in6_addr *addr6, uint8_t mask)
{
uint32_t *cp;
for (cp = (uint32_t *)addr6; mask >= 32; mask -= 32)
*cp++ = 0xFFFFFFFF;
if (mask > 0)
*cp = htonl(mask ? ~((1 << (32 - mask)) - 1) : 0);
}
static struct sockaddr *
get_netmask(struct snl_state *ss, int family, int plen)
{
if (family == AF_INET) {
if (plen == 32)
return (NULL);
struct sockaddr_in *sin = snl_allocz(ss, sizeof(*sin));
sin->sin_len = sizeof(*sin);
sin->sin_family = family;
sin->sin_addr.s_addr = htonl(plen ? ~((1 << (32 - plen)) - 1) : 0);
return (struct sockaddr *)sin;
} else if (family == AF_INET6) {
if (plen == 128)
return (NULL);
struct sockaddr_in6 *sin6 = snl_allocz(ss, sizeof(*sin6));
sin6->sin6_len = sizeof(*sin6);
sin6->sin6_family = family;
ip6_writemask(&sin6->sin6_addr, plen);
return (struct sockaddr *)sin6;
}
return (NULL);
}
static void
nl_init_socket(struct snl_state *ss)
{
if (snl_init(ss, NETLINK_ROUTE))
return;
if (modfind("netlink") == -1 && errno == ENOENT) {
/* Try to load */
if (kldload("netlink") == -1)
err(1, "netlink is not loaded and load attempt failed");
if (snl_init(ss, NETLINK_ROUTE))
return;
}
err(1, "unable to open netlink socket");
}
struct nl_helper {
struct snl_state ss_cmd;
};
static void
nl_helper_init(struct nl_helper *h)
{
nl_init_socket(&h->ss_cmd);
}
static void
nl_helper_free(struct nl_helper *h)
{
snl_free(&h->ss_cmd);
}
static struct sockaddr *
get_addr(struct sockaddr_storage *so, int rtm_addrs, int addr_type)
{
struct sockaddr *sa = NULL;
if (rtm_addrs & (1 << addr_type))
sa = (struct sockaddr *)&so[addr_type];
return (sa);
}
static int
rtmsg_nl_int(struct nl_helper *h, int cmd, int rtm_flags, int fib, int rtm_addrs,
struct sockaddr_storage *so, struct rt_metrics *rt_metrics)
{
struct snl_state *ss = &h->ss_cmd;
struct snl_writer nw;
int nl_type = 0, nl_flags = 0;
snl_init_writer(ss, &nw);
switch (cmd) {
case RTSOCK_RTM_ADD:
nl_type = RTM_NEWROUTE;
nl_flags = NLM_F_CREATE | NLM_F_APPEND; /* Do append by default */
break;
case RTSOCK_RTM_CHANGE:
nl_type = RTM_NEWROUTE;
nl_flags = NLM_F_REPLACE;
break;
case RTSOCK_RTM_DELETE:
nl_type = RTM_DELROUTE;
break;
case RTSOCK_RTM_GET:
nl_type = RTM_GETROUTE;
break;
default:
exit(1);
}
struct sockaddr *dst = get_addr(so, rtm_addrs, RTAX_DST);
struct sockaddr *mask = get_addr(so, rtm_addrs, RTAX_NETMASK);
struct sockaddr *gw = get_addr(so, rtm_addrs, RTAX_GATEWAY);
if (dst == NULL)
return (EINVAL);
struct nlmsghdr *hdr = snl_create_msg_request(&nw, nl_type);
hdr->nlmsg_flags |= nl_flags;
int plen = 0;
int rtm_type = RTN_UNICAST;
switch (dst->sa_family) {
case AF_INET:
{
struct sockaddr_in *mask4 = (struct sockaddr_in *)mask;
if ((rtm_flags & RTF_HOST) == 0 && mask4 != NULL)
plen = bitcount32(mask4->sin_addr.s_addr);
else
plen = 32;
break;
}
case AF_INET6:
{
struct sockaddr_in6 *mask6 = (struct sockaddr_in6 *)mask;
if ((rtm_flags & RTF_HOST) == 0 && mask6 != NULL)
plen = inet6_get_plen(&mask6->sin6_addr);
else
plen = 128;
break;
}
default:
return (ENOTSUP);
}
if (rtm_flags & RTF_REJECT)
rtm_type = RTN_PROHIBIT;
else if (rtm_flags & RTF_BLACKHOLE)
rtm_type = RTN_BLACKHOLE;
struct rtmsg *rtm = snl_reserve_msg_object(&nw, struct rtmsg);
rtm->rtm_family = dst->sa_family;
rtm->rtm_protocol = RTPROT_STATIC;
rtm->rtm_type = rtm_type;
rtm->rtm_dst_len = plen;
/* Request exact prefix match if mask is set */
if ((cmd == RTSOCK_RTM_GET) && (mask != NULL))
rtm->rtm_flags = RTM_F_PREFIX;
snl_add_msg_attr_ip(&nw, RTA_DST, dst);
snl_add_msg_attr_u32(&nw, RTA_TABLE, fib);
uint32_t rta_oif = 0;
if (gw != NULL) {
if (rtm_flags & RTF_GATEWAY) {
if (gw->sa_family == dst->sa_family)
snl_add_msg_attr_ip(&nw, RTA_GATEWAY, gw);
else
snl_add_msg_attr_ipvia(&nw, RTA_VIA, gw);
if (gw->sa_family == AF_INET6) {
struct sockaddr_in6 *gw6 = (struct sockaddr_in6 *)gw;
if (IN6_IS_ADDR_LINKLOCAL(&gw6->sin6_addr))
rta_oif = gw6->sin6_scope_id;
}
} else {
/* Should be AF_LINK */
struct sockaddr_dl *sdl = (struct sockaddr_dl *)gw;
if (sdl->sdl_index != 0)
rta_oif = sdl->sdl_index;
}
}
if (dst->sa_family == AF_INET6 && rta_oif == 0) {
struct sockaddr_in6 *dst6 = (struct sockaddr_in6 *)dst;
if (IN6_IS_ADDR_LINKLOCAL(&dst6->sin6_addr))
rta_oif = dst6->sin6_scope_id;
}
if (rta_oif != 0)
snl_add_msg_attr_u32(&nw, RTA_OIF, rta_oif);
if (rtm_flags != 0)
snl_add_msg_attr_u32(&nw, NL_RTA_RTFLAGS, rtm_flags);
if (rt_metrics->rmx_mtu > 0) {
int off = snl_add_msg_attr_nested(&nw, RTA_METRICS);
snl_add_msg_attr_u32(&nw, RTAX_MTU, rt_metrics->rmx_mtu);
snl_end_attr_nested(&nw, off);
}
if (rt_metrics->rmx_weight > 0)
snl_add_msg_attr_u32(&nw, NL_RTA_WEIGHT, rt_metrics->rmx_weight);
if ((hdr = snl_finalize_msg(&nw)) && snl_send_message(ss, hdr)) {
struct snl_errmsg_data e = {};
hdr = snl_read_reply(ss, hdr->nlmsg_seq);
if (nl_type == NL_RTM_GETROUTE) {
if (hdr->nlmsg_type == NL_RTM_NEWROUTE) {
print_getmsg(h, hdr, dst);
return (0);
}
}
if (snl_parse_errmsg(ss, hdr, &e)) {
switch (e.error) {
case (ESRCH):
warnx("route has not been found");
break;
default:
if (e.error == 0)
break;
warnc(e.error, "message indicates error");
}
return (e.error);
}
}
return (EINVAL);
}
int
rtmsg_nl(int cmd, int rtm_flags, int fib, int rtm_addrs,
struct sockaddr_storage *so, struct rt_metrics *rt_metrics)
{
struct nl_helper h = {};
nl_helper_init(&h);
int error = rtmsg_nl_int(&h, cmd, rtm_flags, fib, rtm_addrs, so, rt_metrics);
nl_helper_free(&h);
return (error);
}
static void
get_ifdata(struct nl_helper *h, uint32_t ifindex, struct snl_parsed_link_simple *link)
{
struct snl_state *ss = &h->ss_cmd;
struct snl_writer nw;
snl_init_writer(ss, &nw);
struct nlmsghdr *hdr = snl_create_msg_request(&nw, NL_RTM_GETLINK);
struct ifinfomsg *ifmsg = snl_reserve_msg_object(&nw, struct ifinfomsg);
if (ifmsg != NULL)
ifmsg->ifi_index = ifindex;
if (! (hdr = snl_finalize_msg(&nw)) || !snl_send_message(ss, hdr))
return;
hdr = snl_read_reply(ss, hdr->nlmsg_seq);
if (hdr != NULL && hdr->nlmsg_type == RTM_NEWLINK) {
snl_parse_nlmsg(ss, hdr, &snl_rtm_link_parser_simple, link);
}
if (link->ifla_ifname == NULL) {
char ifname[16];
snprintf(ifname, sizeof(ifname), "if#%u", ifindex);
int len = strlen(ifname);
char *buf = snl_allocz(ss, len + 1);
strlcpy(buf, ifname, len + 1);
link->ifla_ifname = buf;
}
}
static void
print_getmsg(struct nl_helper *h, struct nlmsghdr *hdr, struct sockaddr *dst)
{
struct snl_state *ss = &h->ss_cmd;
struct timespec ts;
struct snl_parsed_route r = { .rtax_weight = RT_DEFAULT_WEIGHT };
if (!snl_parse_nlmsg(ss, hdr, &snl_rtm_route_parser, &r))
return;
struct snl_parsed_link_simple link = {};
get_ifdata(h, r.rta_oif, &link);
if (r.rtax_mtu == 0)
r.rtax_mtu = link.ifla_mtu;
r.rta_rtflags |= (RTF_UP | RTF_DONE);
(void)printf(" route to: %s\n", routename(dst));
if (r.rta_dst)
(void)printf("destination: %s\n", routename(r.rta_dst));
struct sockaddr *mask = get_netmask(ss, r.rtm_family, r.rtm_dst_len);
if (mask)
(void)printf(" mask: %s\n", routename(mask));
if (r.rta_gw && (r.rta_rtflags & RTF_GATEWAY))
(void)printf(" gateway: %s\n", routename(r.rta_gw));
(void)printf(" fib: %u\n", (unsigned int)r.rta_table);
if (link.ifla_ifname)
(void)printf(" interface: %s\n", link.ifla_ifname);
(void)printf(" flags: ");
printb(r.rta_rtflags, routeflags);
struct rt_metrics rmx = {
.rmx_mtu = r.rtax_mtu,
.rmx_weight = r.rtax_weight,
.rmx_expire = r.rta_expire,
};
printf("\n%9s %9s %9s %9s %9s %10s %9s\n", "recvpipe",
"sendpipe", "ssthresh", "rtt,msec", "mtu ", "weight", "expire");
printf("%8lu ", rmx.rmx_recvpipe);
printf("%8lu ", rmx.rmx_sendpipe);
printf("%8lu ", rmx.rmx_ssthresh);
printf("%8lu ", 0UL);
printf("%8lu ", rmx.rmx_mtu);
printf("%8lu ", rmx.rmx_weight);
if (rmx.rmx_expire > 0)
clock_gettime(CLOCK_REALTIME_FAST, &ts);
else
ts.tv_sec = 0;
printf("%8ld \n", (long)(rmx.rmx_expire - ts.tv_sec));
}
static void
print_prefix(struct nl_helper *h, char *buf, int bufsize, struct sockaddr *sa, int plen)
{
int sz = 0;
if (sa == NULL) {
snprintf(buf, bufsize, "<NULL>");
return;
}
switch (sa->sa_family) {
case AF_INET:
{
struct sockaddr_in *sin = (struct sockaddr_in *)sa;
char abuf[INET_ADDRSTRLEN];
inet_ntop(AF_INET, &sin->sin_addr, abuf, sizeof(abuf));
sz = snprintf(buf, bufsize, "%s", abuf);
break;
}
case AF_INET6:
{
struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa;
char abuf[INET6_ADDRSTRLEN];
char *ifname = NULL;
inet_ntop(AF_INET6, &sin6->sin6_addr, abuf, sizeof(abuf));
if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) {
struct snl_parsed_link_simple link = {};
if (sin6->sin6_scope_id != 0) {
get_ifdata(h, sin6->sin6_scope_id, &link);
ifname = link.ifla_ifname;
}
}
if (ifname == NULL)
sz = snprintf(buf, bufsize, "%s", abuf);
else
sz = snprintf(buf, bufsize, "%s%%%s", abuf, ifname);
break;
}
default:
snprintf(buf, bufsize, "unknown_af#%d", sa->sa_family);
plen = -1;
}
if (plen >= 0)
snprintf(buf + sz, bufsize - sz, "/%d", plen);
}
static int
route: show originator PID in netlink monitor Replacing rtsock with netlink also means providing similar tracing facilities, rtsock provides `route -n monitor` interface, where each message can be traced to the originating PID. This diff closes the feature gap between rtsock and netlink in that regard. Netlink works slightly differently from rtsock, as it is a generic message "broker". It calls some kernel KPIs and returns the result to the caller. Other Netlink consumers gets notified on the changed kernel state using the relevant subsystem callbacks. Typically, it is close to impossible to pass some data through these KPIs to enhance the notification. This diff approaches the problem by using osd(9) to assign the relevant socket pointer (`'nlp`) to the per-socket taskqueue execution thread. This change allows to recover the pointer in the aforementioned notification callbacks and extract some additional data. Using `osd(9)` (and adding additional metadata) to the notification receiver comes with some additional cost attached, so this interface needs to be enabled explicitly by using a newly-created `NETLINK_MSG_INFO` `SOL_NETLINK` socket option. The actual medatadata (which includes the originator PID) is provided via control messages. To enable extensibility, the control message data is encoded in the standard netlink(TLV-based) fashion. The list of the currently-provided properties can be found in `nlmsginfo_attrs`. snl(3) is extended to enable decoding of netlink messages with metadata (`snl_read_message_dbg()` stores the parsed structure in the provided buffer). Differential Revision: https://reviews.freebsd.org/D39391
2023-04-28 12:44:04 +00:00
print_line_prefix(struct nlmsghdr *hdr, struct snl_msg_info *cinfo,
const char *cmd, const char *name)
{
struct timespec tp;
struct tm tm;
char buf[32];
clock_gettime(CLOCK_REALTIME, &tp);
localtime_r(&tp.tv_sec, &tm);
strftime(buf, sizeof(buf), "%T", &tm);
route: show originator PID in netlink monitor Replacing rtsock with netlink also means providing similar tracing facilities, rtsock provides `route -n monitor` interface, where each message can be traced to the originating PID. This diff closes the feature gap between rtsock and netlink in that regard. Netlink works slightly differently from rtsock, as it is a generic message "broker". It calls some kernel KPIs and returns the result to the caller. Other Netlink consumers gets notified on the changed kernel state using the relevant subsystem callbacks. Typically, it is close to impossible to pass some data through these KPIs to enhance the notification. This diff approaches the problem by using osd(9) to assign the relevant socket pointer (`'nlp`) to the per-socket taskqueue execution thread. This change allows to recover the pointer in the aforementioned notification callbacks and extract some additional data. Using `osd(9)` (and adding additional metadata) to the notification receiver comes with some additional cost attached, so this interface needs to be enabled explicitly by using a newly-created `NETLINK_MSG_INFO` `SOL_NETLINK` socket option. The actual medatadata (which includes the originator PID) is provided via control messages. To enable extensibility, the control message data is encoded in the standard netlink(TLV-based) fashion. The list of the currently-provided properties can be found in `nlmsginfo_attrs`. snl(3) is extended to enable decoding of netlink messages with metadata (`snl_read_message_dbg()` stores the parsed structure in the provided buffer). Differential Revision: https://reviews.freebsd.org/D39391
2023-04-28 12:44:04 +00:00
int len = printf("%s.%03ld PID %4u %s %s ", buf, tp.tv_nsec / 1000000,
cinfo->process_id, cmd, name);
return (len);
}
static const char *
get_action_name(struct nlmsghdr *hdr, int new_cmd)
{
if (hdr->nlmsg_type == new_cmd) {
//return ((hdr->nlmsg_flags & NLM_F_REPLACE) ? "replace" : "add");
return ("add/repl");
} else
return ("delete");
}
static void
print_nlmsg_route_nhop(struct nl_helper *h, struct snl_parsed_route *r,
struct rta_mpath_nh *nh, bool first)
{
// gw 10.0.0.1 ifp vtnet0 mtu 1500 table inet.0
if (nh->gw != NULL) {
char gwbuf[128];
print_prefix(h, gwbuf, sizeof(gwbuf), nh->gw, -1);
printf("gw %s ", gwbuf);
}
if (nh->ifindex != 0) {
struct snl_parsed_link_simple link = {};
get_ifdata(h, nh->ifindex, &link);
if (nh->rtax_mtu == 0)
nh->rtax_mtu = link.ifla_mtu;
printf("iface %s ", link.ifla_ifname);
if (nh->rtax_mtu != 0)
printf("mtu %d ", nh->rtax_mtu);
}
if (first) {
switch (r->rtm_family) {
case AF_INET:
printf("table inet.%d", r->rta_table);
break;
case AF_INET6:
printf("table inet6.%d", r->rta_table);
break;
}
}
printf("\n");
}
static void
route: show originator PID in netlink monitor Replacing rtsock with netlink also means providing similar tracing facilities, rtsock provides `route -n monitor` interface, where each message can be traced to the originating PID. This diff closes the feature gap between rtsock and netlink in that regard. Netlink works slightly differently from rtsock, as it is a generic message "broker". It calls some kernel KPIs and returns the result to the caller. Other Netlink consumers gets notified on the changed kernel state using the relevant subsystem callbacks. Typically, it is close to impossible to pass some data through these KPIs to enhance the notification. This diff approaches the problem by using osd(9) to assign the relevant socket pointer (`'nlp`) to the per-socket taskqueue execution thread. This change allows to recover the pointer in the aforementioned notification callbacks and extract some additional data. Using `osd(9)` (and adding additional metadata) to the notification receiver comes with some additional cost attached, so this interface needs to be enabled explicitly by using a newly-created `NETLINK_MSG_INFO` `SOL_NETLINK` socket option. The actual medatadata (which includes the originator PID) is provided via control messages. To enable extensibility, the control message data is encoded in the standard netlink(TLV-based) fashion. The list of the currently-provided properties can be found in `nlmsginfo_attrs`. snl(3) is extended to enable decoding of netlink messages with metadata (`snl_read_message_dbg()` stores the parsed structure in the provided buffer). Differential Revision: https://reviews.freebsd.org/D39391
2023-04-28 12:44:04 +00:00
print_nlmsg_route(struct nl_helper *h, struct nlmsghdr *hdr,
struct snl_msg_info *cinfo)
{
struct snl_parsed_route r = { .rtax_weight = RT_DEFAULT_WEIGHT };
struct snl_state *ss = &h->ss_cmd;
if (!snl_parse_nlmsg(ss, hdr, &snl_rtm_route_parser, &r))
return;
// 20:19:41.333 add route 10.0.0.0/24 gw 10.0.0.1 ifp vtnet0 mtu 1500 table inet.0
const char *cmd = get_action_name(hdr, RTM_NEWROUTE);
route: show originator PID in netlink monitor Replacing rtsock with netlink also means providing similar tracing facilities, rtsock provides `route -n monitor` interface, where each message can be traced to the originating PID. This diff closes the feature gap between rtsock and netlink in that regard. Netlink works slightly differently from rtsock, as it is a generic message "broker". It calls some kernel KPIs and returns the result to the caller. Other Netlink consumers gets notified on the changed kernel state using the relevant subsystem callbacks. Typically, it is close to impossible to pass some data through these KPIs to enhance the notification. This diff approaches the problem by using osd(9) to assign the relevant socket pointer (`'nlp`) to the per-socket taskqueue execution thread. This change allows to recover the pointer in the aforementioned notification callbacks and extract some additional data. Using `osd(9)` (and adding additional metadata) to the notification receiver comes with some additional cost attached, so this interface needs to be enabled explicitly by using a newly-created `NETLINK_MSG_INFO` `SOL_NETLINK` socket option. The actual medatadata (which includes the originator PID) is provided via control messages. To enable extensibility, the control message data is encoded in the standard netlink(TLV-based) fashion. The list of the currently-provided properties can be found in `nlmsginfo_attrs`. snl(3) is extended to enable decoding of netlink messages with metadata (`snl_read_message_dbg()` stores the parsed structure in the provided buffer). Differential Revision: https://reviews.freebsd.org/D39391
2023-04-28 12:44:04 +00:00
int len = print_line_prefix(hdr, cinfo, cmd, "route");
char buf[128];
print_prefix(h, buf, sizeof(buf), r.rta_dst, r.rtm_dst_len);
len += strlen(buf) + 1;
printf("%s ", buf);
switch (r.rtm_type) {
case RTN_BLACKHOLE:
printf("blackhole\n");
return;
case RTN_UNREACHABLE:
printf("unreach(reject)\n");
return;
case RTN_PROHIBIT:
printf("prohibit(reject)\n");
return;
}
if (r.rta_multipath.num_nhops != 0) {
bool first = true;
memset(buf, ' ', sizeof(buf));
buf[len] = '\0';
for (uint32_t i = 0; i < r.rta_multipath.num_nhops; i++) {
struct rta_mpath_nh *nh = r.rta_multipath.nhops[i];
if (!first)
printf("%s", buf);
print_nlmsg_route_nhop(h, &r, nh, first);
first = false;
}
} else {
struct rta_mpath_nh nh = {
.gw = r.rta_gw,
.ifindex = r.rta_oif,
.rtax_mtu = r.rtax_mtu,
};
print_nlmsg_route_nhop(h, &r, &nh, true);
}
}
static const char *operstate[] = {
"UNKNOWN", /* 0, IF_OPER_UNKNOWN */
"NOTPRESENT", /* 1, IF_OPER_NOTPRESENT */
"DOWN", /* 2, IF_OPER_DOWN */
"LLDOWN", /* 3, IF_OPER_LOWERLAYERDOWN */
"TESTING", /* 4, IF_OPER_TESTING */
"DORMANT", /* 5, IF_OPER_DORMANT */
"UP", /* 6, IF_OPER_UP */
};
static void
route: show originator PID in netlink monitor Replacing rtsock with netlink also means providing similar tracing facilities, rtsock provides `route -n monitor` interface, where each message can be traced to the originating PID. This diff closes the feature gap between rtsock and netlink in that regard. Netlink works slightly differently from rtsock, as it is a generic message "broker". It calls some kernel KPIs and returns the result to the caller. Other Netlink consumers gets notified on the changed kernel state using the relevant subsystem callbacks. Typically, it is close to impossible to pass some data through these KPIs to enhance the notification. This diff approaches the problem by using osd(9) to assign the relevant socket pointer (`'nlp`) to the per-socket taskqueue execution thread. This change allows to recover the pointer in the aforementioned notification callbacks and extract some additional data. Using `osd(9)` (and adding additional metadata) to the notification receiver comes with some additional cost attached, so this interface needs to be enabled explicitly by using a newly-created `NETLINK_MSG_INFO` `SOL_NETLINK` socket option. The actual medatadata (which includes the originator PID) is provided via control messages. To enable extensibility, the control message data is encoded in the standard netlink(TLV-based) fashion. The list of the currently-provided properties can be found in `nlmsginfo_attrs`. snl(3) is extended to enable decoding of netlink messages with metadata (`snl_read_message_dbg()` stores the parsed structure in the provided buffer). Differential Revision: https://reviews.freebsd.org/D39391
2023-04-28 12:44:04 +00:00
print_nlmsg_link(struct nl_helper *h, struct nlmsghdr *hdr,
struct snl_msg_info *cinfo)
{
struct snl_parsed_link l = {};
struct snl_state *ss = &h->ss_cmd;
if (!snl_parse_nlmsg(ss, hdr, &snl_rtm_link_parser, &l))
return;
// 20:19:41.333 add iface#3 vtnet0 admin UP oper UP mtu 1500 table inet.0
const char *cmd = get_action_name(hdr, RTM_NEWLINK);
route: show originator PID in netlink monitor Replacing rtsock with netlink also means providing similar tracing facilities, rtsock provides `route -n monitor` interface, where each message can be traced to the originating PID. This diff closes the feature gap between rtsock and netlink in that regard. Netlink works slightly differently from rtsock, as it is a generic message "broker". It calls some kernel KPIs and returns the result to the caller. Other Netlink consumers gets notified on the changed kernel state using the relevant subsystem callbacks. Typically, it is close to impossible to pass some data through these KPIs to enhance the notification. This diff approaches the problem by using osd(9) to assign the relevant socket pointer (`'nlp`) to the per-socket taskqueue execution thread. This change allows to recover the pointer in the aforementioned notification callbacks and extract some additional data. Using `osd(9)` (and adding additional metadata) to the notification receiver comes with some additional cost attached, so this interface needs to be enabled explicitly by using a newly-created `NETLINK_MSG_INFO` `SOL_NETLINK` socket option. The actual medatadata (which includes the originator PID) is provided via control messages. To enable extensibility, the control message data is encoded in the standard netlink(TLV-based) fashion. The list of the currently-provided properties can be found in `nlmsginfo_attrs`. snl(3) is extended to enable decoding of netlink messages with metadata (`snl_read_message_dbg()` stores the parsed structure in the provided buffer). Differential Revision: https://reviews.freebsd.org/D39391
2023-04-28 12:44:04 +00:00
print_line_prefix(hdr, cinfo, cmd, "iface");
printf("iface#%u %s ", l.ifi_index, l.ifla_ifname);
printf("admin %s ", (l.ifi_flags & IFF_UP) ? "UP" : "DOWN");
if (l.ifla_operstate < NL_ARRAY_LEN(operstate))
printf("oper %s ", operstate[l.ifla_operstate]);
if (l.ifla_mtu > 0)
printf("mtu %u ", l.ifla_mtu);
printf("\n");
}
static void
route: show originator PID in netlink monitor Replacing rtsock with netlink also means providing similar tracing facilities, rtsock provides `route -n monitor` interface, where each message can be traced to the originating PID. This diff closes the feature gap between rtsock and netlink in that regard. Netlink works slightly differently from rtsock, as it is a generic message "broker". It calls some kernel KPIs and returns the result to the caller. Other Netlink consumers gets notified on the changed kernel state using the relevant subsystem callbacks. Typically, it is close to impossible to pass some data through these KPIs to enhance the notification. This diff approaches the problem by using osd(9) to assign the relevant socket pointer (`'nlp`) to the per-socket taskqueue execution thread. This change allows to recover the pointer in the aforementioned notification callbacks and extract some additional data. Using `osd(9)` (and adding additional metadata) to the notification receiver comes with some additional cost attached, so this interface needs to be enabled explicitly by using a newly-created `NETLINK_MSG_INFO` `SOL_NETLINK` socket option. The actual medatadata (which includes the originator PID) is provided via control messages. To enable extensibility, the control message data is encoded in the standard netlink(TLV-based) fashion. The list of the currently-provided properties can be found in `nlmsginfo_attrs`. snl(3) is extended to enable decoding of netlink messages with metadata (`snl_read_message_dbg()` stores the parsed structure in the provided buffer). Differential Revision: https://reviews.freebsd.org/D39391
2023-04-28 12:44:04 +00:00
print_nlmsg_addr(struct nl_helper *h, struct nlmsghdr *hdr,
struct snl_msg_info *cinfo)
{
struct snl_parsed_addr attrs = {};
struct snl_state *ss = &h->ss_cmd;
if (!snl_parse_nlmsg(ss, hdr, &snl_rtm_addr_parser, &attrs))
return;
// add addr 192.168.1.1/24 iface vtnet0
const char *cmd = get_action_name(hdr, RTM_NEWADDR);
route: show originator PID in netlink monitor Replacing rtsock with netlink also means providing similar tracing facilities, rtsock provides `route -n monitor` interface, where each message can be traced to the originating PID. This diff closes the feature gap between rtsock and netlink in that regard. Netlink works slightly differently from rtsock, as it is a generic message "broker". It calls some kernel KPIs and returns the result to the caller. Other Netlink consumers gets notified on the changed kernel state using the relevant subsystem callbacks. Typically, it is close to impossible to pass some data through these KPIs to enhance the notification. This diff approaches the problem by using osd(9) to assign the relevant socket pointer (`'nlp`) to the per-socket taskqueue execution thread. This change allows to recover the pointer in the aforementioned notification callbacks and extract some additional data. Using `osd(9)` (and adding additional metadata) to the notification receiver comes with some additional cost attached, so this interface needs to be enabled explicitly by using a newly-created `NETLINK_MSG_INFO` `SOL_NETLINK` socket option. The actual medatadata (which includes the originator PID) is provided via control messages. To enable extensibility, the control message data is encoded in the standard netlink(TLV-based) fashion. The list of the currently-provided properties can be found in `nlmsginfo_attrs`. snl(3) is extended to enable decoding of netlink messages with metadata (`snl_read_message_dbg()` stores the parsed structure in the provided buffer). Differential Revision: https://reviews.freebsd.org/D39391
2023-04-28 12:44:04 +00:00
print_line_prefix(hdr, cinfo, cmd, "addr");
char buf[128];
struct sockaddr *addr = attrs.ifa_local ? attrs.ifa_local : attrs.ifa_address;
print_prefix(h, buf, sizeof(buf), addr, attrs.ifa_prefixlen);
printf("%s ", buf);
struct snl_parsed_link_simple link = {};
get_ifdata(h, attrs.ifa_index, &link);
if (link.ifi_flags & IFF_POINTOPOINT) {
char buf[64];
print_prefix(h, buf, sizeof(buf), attrs.ifa_address, -1);
printf("-> %s ", buf);
}
printf("iface %s ", link.ifla_ifname);
printf("\n");
}
static const char *nudstate[] = {
"INCOMPLETE", /* 0x01(0) */
"REACHABLE", /* 0x02(1) */
"STALE", /* 0x04(2) */
"DELAY", /* 0x08(3) */
"PROBE", /* 0x10(4) */
"FAILED", /* 0x20(5) */
};
#define NUD_INCOMPLETE 0x01 /* No lladdr, address resolution in progress */
#define NUD_REACHABLE 0x02 /* reachable & recently resolved */
#define NUD_STALE 0x04 /* has lladdr but it's stale */
#define NUD_DELAY 0x08 /* has lladdr, is stale, probes delayed */
#define NUD_PROBE 0x10 /* has lladdr, is stale, probes sent */
#define NUD_FAILED 0x20 /* unused */
static void
route: show originator PID in netlink monitor Replacing rtsock with netlink also means providing similar tracing facilities, rtsock provides `route -n monitor` interface, where each message can be traced to the originating PID. This diff closes the feature gap between rtsock and netlink in that regard. Netlink works slightly differently from rtsock, as it is a generic message "broker". It calls some kernel KPIs and returns the result to the caller. Other Netlink consumers gets notified on the changed kernel state using the relevant subsystem callbacks. Typically, it is close to impossible to pass some data through these KPIs to enhance the notification. This diff approaches the problem by using osd(9) to assign the relevant socket pointer (`'nlp`) to the per-socket taskqueue execution thread. This change allows to recover the pointer in the aforementioned notification callbacks and extract some additional data. Using `osd(9)` (and adding additional metadata) to the notification receiver comes with some additional cost attached, so this interface needs to be enabled explicitly by using a newly-created `NETLINK_MSG_INFO` `SOL_NETLINK` socket option. The actual medatadata (which includes the originator PID) is provided via control messages. To enable extensibility, the control message data is encoded in the standard netlink(TLV-based) fashion. The list of the currently-provided properties can be found in `nlmsginfo_attrs`. snl(3) is extended to enable decoding of netlink messages with metadata (`snl_read_message_dbg()` stores the parsed structure in the provided buffer). Differential Revision: https://reviews.freebsd.org/D39391
2023-04-28 12:44:04 +00:00
print_nlmsg_neigh(struct nl_helper *h, struct nlmsghdr *hdr,
struct snl_msg_info *cinfo)
{
struct snl_parsed_neigh attrs = {};
struct snl_state *ss = &h->ss_cmd;
if (!snl_parse_nlmsg(ss, hdr, &snl_rtm_neigh_parser, &attrs))
return;
// add addr 192.168.1.1 state %s lladdr %s iface vtnet0
const char *cmd = get_action_name(hdr, RTM_NEWNEIGH);
route: show originator PID in netlink monitor Replacing rtsock with netlink also means providing similar tracing facilities, rtsock provides `route -n monitor` interface, where each message can be traced to the originating PID. This diff closes the feature gap between rtsock and netlink in that regard. Netlink works slightly differently from rtsock, as it is a generic message "broker". It calls some kernel KPIs and returns the result to the caller. Other Netlink consumers gets notified on the changed kernel state using the relevant subsystem callbacks. Typically, it is close to impossible to pass some data through these KPIs to enhance the notification. This diff approaches the problem by using osd(9) to assign the relevant socket pointer (`'nlp`) to the per-socket taskqueue execution thread. This change allows to recover the pointer in the aforementioned notification callbacks and extract some additional data. Using `osd(9)` (and adding additional metadata) to the notification receiver comes with some additional cost attached, so this interface needs to be enabled explicitly by using a newly-created `NETLINK_MSG_INFO` `SOL_NETLINK` socket option. The actual medatadata (which includes the originator PID) is provided via control messages. To enable extensibility, the control message data is encoded in the standard netlink(TLV-based) fashion. The list of the currently-provided properties can be found in `nlmsginfo_attrs`. snl(3) is extended to enable decoding of netlink messages with metadata (`snl_read_message_dbg()` stores the parsed structure in the provided buffer). Differential Revision: https://reviews.freebsd.org/D39391
2023-04-28 12:44:04 +00:00
print_line_prefix(hdr, cinfo, cmd, "neigh");
char buf[128];
print_prefix(h, buf, sizeof(buf), attrs.nda_dst, -1);
printf("%s ", buf);
struct snl_parsed_link_simple link = {};
get_ifdata(h, attrs.nda_ifindex, &link);
for (unsigned int i = 0; i < NL_ARRAY_LEN(nudstate); i++) {
if ((1 << i) & attrs.ndm_state) {
printf("state %s ", nudstate[i]);
break;
}
}
if (attrs.nda_lladdr != NULL) {
int if_type = link.ifi_type;
if ((if_type == IFT_ETHER || if_type == IFT_L2VLAN || if_type == IFT_BRIDGE) &&
NLA_DATA_LEN(attrs.nda_lladdr) == ETHER_ADDR_LEN) {
struct ether_addr *ll;
ll = (struct ether_addr *)NLA_DATA(attrs.nda_lladdr);
printf("lladdr %s ", ether_ntoa(ll));
} else {
struct sockaddr_dl sdl = {
.sdl_len = sizeof(sdl),
.sdl_family = AF_LINK,
.sdl_index = attrs.nda_ifindex,
.sdl_type = if_type,
.sdl_alen = NLA_DATA_LEN(attrs.nda_lladdr),
};
if (sdl.sdl_alen < sizeof(sdl.sdl_data)) {
void *ll = NLA_DATA(attrs.nda_lladdr);
memcpy(sdl.sdl_data, ll, sdl.sdl_alen);
printf("lladdr %s ", link_ntoa(&sdl));
}
}
}
if (link.ifla_ifname != NULL)
printf("iface %s ", link.ifla_ifname);
printf("\n");
}
static void
route: show originator PID in netlink monitor Replacing rtsock with netlink also means providing similar tracing facilities, rtsock provides `route -n monitor` interface, where each message can be traced to the originating PID. This diff closes the feature gap between rtsock and netlink in that regard. Netlink works slightly differently from rtsock, as it is a generic message "broker". It calls some kernel KPIs and returns the result to the caller. Other Netlink consumers gets notified on the changed kernel state using the relevant subsystem callbacks. Typically, it is close to impossible to pass some data through these KPIs to enhance the notification. This diff approaches the problem by using osd(9) to assign the relevant socket pointer (`'nlp`) to the per-socket taskqueue execution thread. This change allows to recover the pointer in the aforementioned notification callbacks and extract some additional data. Using `osd(9)` (and adding additional metadata) to the notification receiver comes with some additional cost attached, so this interface needs to be enabled explicitly by using a newly-created `NETLINK_MSG_INFO` `SOL_NETLINK` socket option. The actual medatadata (which includes the originator PID) is provided via control messages. To enable extensibility, the control message data is encoded in the standard netlink(TLV-based) fashion. The list of the currently-provided properties can be found in `nlmsginfo_attrs`. snl(3) is extended to enable decoding of netlink messages with metadata (`snl_read_message_dbg()` stores the parsed structure in the provided buffer). Differential Revision: https://reviews.freebsd.org/D39391
2023-04-28 12:44:04 +00:00
print_nlmsg_generic(struct nl_helper *h, struct nlmsghdr *hdr, struct snl_msg_info *cinfo)
{
route: show originator PID in netlink monitor Replacing rtsock with netlink also means providing similar tracing facilities, rtsock provides `route -n monitor` interface, where each message can be traced to the originating PID. This diff closes the feature gap between rtsock and netlink in that regard. Netlink works slightly differently from rtsock, as it is a generic message "broker". It calls some kernel KPIs and returns the result to the caller. Other Netlink consumers gets notified on the changed kernel state using the relevant subsystem callbacks. Typically, it is close to impossible to pass some data through these KPIs to enhance the notification. This diff approaches the problem by using osd(9) to assign the relevant socket pointer (`'nlp`) to the per-socket taskqueue execution thread. This change allows to recover the pointer in the aforementioned notification callbacks and extract some additional data. Using `osd(9)` (and adding additional metadata) to the notification receiver comes with some additional cost attached, so this interface needs to be enabled explicitly by using a newly-created `NETLINK_MSG_INFO` `SOL_NETLINK` socket option. The actual medatadata (which includes the originator PID) is provided via control messages. To enable extensibility, the control message data is encoded in the standard netlink(TLV-based) fashion. The list of the currently-provided properties can be found in `nlmsginfo_attrs`. snl(3) is extended to enable decoding of netlink messages with metadata (`snl_read_message_dbg()` stores the parsed structure in the provided buffer). Differential Revision: https://reviews.freebsd.org/D39391
2023-04-28 12:44:04 +00:00
const char *cmd = get_action_name(hdr, 0);
print_line_prefix(hdr, cinfo, cmd, "unknown message");
printf(" type %u\n", hdr->nlmsg_type);
}
static void
route: show originator PID in netlink monitor Replacing rtsock with netlink also means providing similar tracing facilities, rtsock provides `route -n monitor` interface, where each message can be traced to the originating PID. This diff closes the feature gap between rtsock and netlink in that regard. Netlink works slightly differently from rtsock, as it is a generic message "broker". It calls some kernel KPIs and returns the result to the caller. Other Netlink consumers gets notified on the changed kernel state using the relevant subsystem callbacks. Typically, it is close to impossible to pass some data through these KPIs to enhance the notification. This diff approaches the problem by using osd(9) to assign the relevant socket pointer (`'nlp`) to the per-socket taskqueue execution thread. This change allows to recover the pointer in the aforementioned notification callbacks and extract some additional data. Using `osd(9)` (and adding additional metadata) to the notification receiver comes with some additional cost attached, so this interface needs to be enabled explicitly by using a newly-created `NETLINK_MSG_INFO` `SOL_NETLINK` socket option. The actual medatadata (which includes the originator PID) is provided via control messages. To enable extensibility, the control message data is encoded in the standard netlink(TLV-based) fashion. The list of the currently-provided properties can be found in `nlmsginfo_attrs`. snl(3) is extended to enable decoding of netlink messages with metadata (`snl_read_message_dbg()` stores the parsed structure in the provided buffer). Differential Revision: https://reviews.freebsd.org/D39391
2023-04-28 12:44:04 +00:00
print_nlmsg(struct nl_helper *h, struct nlmsghdr *hdr, struct snl_msg_info *cinfo)
{
switch (hdr->nlmsg_type) {
case RTM_NEWLINK:
case RTM_DELLINK:
route: show originator PID in netlink monitor Replacing rtsock with netlink also means providing similar tracing facilities, rtsock provides `route -n monitor` interface, where each message can be traced to the originating PID. This diff closes the feature gap between rtsock and netlink in that regard. Netlink works slightly differently from rtsock, as it is a generic message "broker". It calls some kernel KPIs and returns the result to the caller. Other Netlink consumers gets notified on the changed kernel state using the relevant subsystem callbacks. Typically, it is close to impossible to pass some data through these KPIs to enhance the notification. This diff approaches the problem by using osd(9) to assign the relevant socket pointer (`'nlp`) to the per-socket taskqueue execution thread. This change allows to recover the pointer in the aforementioned notification callbacks and extract some additional data. Using `osd(9)` (and adding additional metadata) to the notification receiver comes with some additional cost attached, so this interface needs to be enabled explicitly by using a newly-created `NETLINK_MSG_INFO` `SOL_NETLINK` socket option. The actual medatadata (which includes the originator PID) is provided via control messages. To enable extensibility, the control message data is encoded in the standard netlink(TLV-based) fashion. The list of the currently-provided properties can be found in `nlmsginfo_attrs`. snl(3) is extended to enable decoding of netlink messages with metadata (`snl_read_message_dbg()` stores the parsed structure in the provided buffer). Differential Revision: https://reviews.freebsd.org/D39391
2023-04-28 12:44:04 +00:00
print_nlmsg_link(h, hdr, cinfo);
break;
case RTM_NEWADDR:
case RTM_DELADDR:
route: show originator PID in netlink monitor Replacing rtsock with netlink also means providing similar tracing facilities, rtsock provides `route -n monitor` interface, where each message can be traced to the originating PID. This diff closes the feature gap between rtsock and netlink in that regard. Netlink works slightly differently from rtsock, as it is a generic message "broker". It calls some kernel KPIs and returns the result to the caller. Other Netlink consumers gets notified on the changed kernel state using the relevant subsystem callbacks. Typically, it is close to impossible to pass some data through these KPIs to enhance the notification. This diff approaches the problem by using osd(9) to assign the relevant socket pointer (`'nlp`) to the per-socket taskqueue execution thread. This change allows to recover the pointer in the aforementioned notification callbacks and extract some additional data. Using `osd(9)` (and adding additional metadata) to the notification receiver comes with some additional cost attached, so this interface needs to be enabled explicitly by using a newly-created `NETLINK_MSG_INFO` `SOL_NETLINK` socket option. The actual medatadata (which includes the originator PID) is provided via control messages. To enable extensibility, the control message data is encoded in the standard netlink(TLV-based) fashion. The list of the currently-provided properties can be found in `nlmsginfo_attrs`. snl(3) is extended to enable decoding of netlink messages with metadata (`snl_read_message_dbg()` stores the parsed structure in the provided buffer). Differential Revision: https://reviews.freebsd.org/D39391
2023-04-28 12:44:04 +00:00
print_nlmsg_addr(h, hdr, cinfo);
break;
case RTM_NEWROUTE:
case RTM_DELROUTE:
route: show originator PID in netlink monitor Replacing rtsock with netlink also means providing similar tracing facilities, rtsock provides `route -n monitor` interface, where each message can be traced to the originating PID. This diff closes the feature gap between rtsock and netlink in that regard. Netlink works slightly differently from rtsock, as it is a generic message "broker". It calls some kernel KPIs and returns the result to the caller. Other Netlink consumers gets notified on the changed kernel state using the relevant subsystem callbacks. Typically, it is close to impossible to pass some data through these KPIs to enhance the notification. This diff approaches the problem by using osd(9) to assign the relevant socket pointer (`'nlp`) to the per-socket taskqueue execution thread. This change allows to recover the pointer in the aforementioned notification callbacks and extract some additional data. Using `osd(9)` (and adding additional metadata) to the notification receiver comes with some additional cost attached, so this interface needs to be enabled explicitly by using a newly-created `NETLINK_MSG_INFO` `SOL_NETLINK` socket option. The actual medatadata (which includes the originator PID) is provided via control messages. To enable extensibility, the control message data is encoded in the standard netlink(TLV-based) fashion. The list of the currently-provided properties can be found in `nlmsginfo_attrs`. snl(3) is extended to enable decoding of netlink messages with metadata (`snl_read_message_dbg()` stores the parsed structure in the provided buffer). Differential Revision: https://reviews.freebsd.org/D39391
2023-04-28 12:44:04 +00:00
print_nlmsg_route(h, hdr, cinfo);
break;
case RTM_NEWNEIGH:
case RTM_DELNEIGH:
route: show originator PID in netlink monitor Replacing rtsock with netlink also means providing similar tracing facilities, rtsock provides `route -n monitor` interface, where each message can be traced to the originating PID. This diff closes the feature gap between rtsock and netlink in that regard. Netlink works slightly differently from rtsock, as it is a generic message "broker". It calls some kernel KPIs and returns the result to the caller. Other Netlink consumers gets notified on the changed kernel state using the relevant subsystem callbacks. Typically, it is close to impossible to pass some data through these KPIs to enhance the notification. This diff approaches the problem by using osd(9) to assign the relevant socket pointer (`'nlp`) to the per-socket taskqueue execution thread. This change allows to recover the pointer in the aforementioned notification callbacks and extract some additional data. Using `osd(9)` (and adding additional metadata) to the notification receiver comes with some additional cost attached, so this interface needs to be enabled explicitly by using a newly-created `NETLINK_MSG_INFO` `SOL_NETLINK` socket option. The actual medatadata (which includes the originator PID) is provided via control messages. To enable extensibility, the control message data is encoded in the standard netlink(TLV-based) fashion. The list of the currently-provided properties can be found in `nlmsginfo_attrs`. snl(3) is extended to enable decoding of netlink messages with metadata (`snl_read_message_dbg()` stores the parsed structure in the provided buffer). Differential Revision: https://reviews.freebsd.org/D39391
2023-04-28 12:44:04 +00:00
print_nlmsg_neigh(h, hdr, cinfo);
break;
default:
route: show originator PID in netlink monitor Replacing rtsock with netlink also means providing similar tracing facilities, rtsock provides `route -n monitor` interface, where each message can be traced to the originating PID. This diff closes the feature gap between rtsock and netlink in that regard. Netlink works slightly differently from rtsock, as it is a generic message "broker". It calls some kernel KPIs and returns the result to the caller. Other Netlink consumers gets notified on the changed kernel state using the relevant subsystem callbacks. Typically, it is close to impossible to pass some data through these KPIs to enhance the notification. This diff approaches the problem by using osd(9) to assign the relevant socket pointer (`'nlp`) to the per-socket taskqueue execution thread. This change allows to recover the pointer in the aforementioned notification callbacks and extract some additional data. Using `osd(9)` (and adding additional metadata) to the notification receiver comes with some additional cost attached, so this interface needs to be enabled explicitly by using a newly-created `NETLINK_MSG_INFO` `SOL_NETLINK` socket option. The actual medatadata (which includes the originator PID) is provided via control messages. To enable extensibility, the control message data is encoded in the standard netlink(TLV-based) fashion. The list of the currently-provided properties can be found in `nlmsginfo_attrs`. snl(3) is extended to enable decoding of netlink messages with metadata (`snl_read_message_dbg()` stores the parsed structure in the provided buffer). Differential Revision: https://reviews.freebsd.org/D39391
2023-04-28 12:44:04 +00:00
print_nlmsg_generic(h, hdr, cinfo);
}
snl_clear_lb(&h->ss_cmd);
}
void
monitor_nl(int fib)
{
struct snl_state ss_event = {};
struct nl_helper h;
nl_init_socket(&ss_event);
nl_helper_init(&h);
int groups[] = {
RTNLGRP_LINK,
RTNLGRP_NEIGH,
RTNLGRP_NEXTHOP,
#ifdef INET
RTNLGRP_IPV4_IFADDR,
RTNLGRP_IPV4_ROUTE,
#endif
#ifdef INET6
RTNLGRP_IPV6_IFADDR,
RTNLGRP_IPV6_ROUTE,
#endif
};
route: show originator PID in netlink monitor Replacing rtsock with netlink also means providing similar tracing facilities, rtsock provides `route -n monitor` interface, where each message can be traced to the originating PID. This diff closes the feature gap between rtsock and netlink in that regard. Netlink works slightly differently from rtsock, as it is a generic message "broker". It calls some kernel KPIs and returns the result to the caller. Other Netlink consumers gets notified on the changed kernel state using the relevant subsystem callbacks. Typically, it is close to impossible to pass some data through these KPIs to enhance the notification. This diff approaches the problem by using osd(9) to assign the relevant socket pointer (`'nlp`) to the per-socket taskqueue execution thread. This change allows to recover the pointer in the aforementioned notification callbacks and extract some additional data. Using `osd(9)` (and adding additional metadata) to the notification receiver comes with some additional cost attached, so this interface needs to be enabled explicitly by using a newly-created `NETLINK_MSG_INFO` `SOL_NETLINK` socket option. The actual medatadata (which includes the originator PID) is provided via control messages. To enable extensibility, the control message data is encoded in the standard netlink(TLV-based) fashion. The list of the currently-provided properties can be found in `nlmsginfo_attrs`. snl(3) is extended to enable decoding of netlink messages with metadata (`snl_read_message_dbg()` stores the parsed structure in the provided buffer). Differential Revision: https://reviews.freebsd.org/D39391
2023-04-28 12:44:04 +00:00
int optval = 1;
socklen_t optlen = sizeof(optval);
setsockopt(ss_event.fd, SOL_NETLINK, NETLINK_MSG_INFO, &optval, optlen);
for (unsigned int i = 0; i < NL_ARRAY_LEN(groups); i++) {
int error;
int optval = groups[i];
socklen_t optlen = sizeof(optval);
error = setsockopt(ss_event.fd, SOL_NETLINK,
NETLINK_ADD_MEMBERSHIP, &optval, optlen);
if (error != 0)
warn("Unable to subscribe to group %d", optval);
}
route: show originator PID in netlink monitor Replacing rtsock with netlink also means providing similar tracing facilities, rtsock provides `route -n monitor` interface, where each message can be traced to the originating PID. This diff closes the feature gap between rtsock and netlink in that regard. Netlink works slightly differently from rtsock, as it is a generic message "broker". It calls some kernel KPIs and returns the result to the caller. Other Netlink consumers gets notified on the changed kernel state using the relevant subsystem callbacks. Typically, it is close to impossible to pass some data through these KPIs to enhance the notification. This diff approaches the problem by using osd(9) to assign the relevant socket pointer (`'nlp`) to the per-socket taskqueue execution thread. This change allows to recover the pointer in the aforementioned notification callbacks and extract some additional data. Using `osd(9)` (and adding additional metadata) to the notification receiver comes with some additional cost attached, so this interface needs to be enabled explicitly by using a newly-created `NETLINK_MSG_INFO` `SOL_NETLINK` socket option. The actual medatadata (which includes the originator PID) is provided via control messages. To enable extensibility, the control message data is encoded in the standard netlink(TLV-based) fashion. The list of the currently-provided properties can be found in `nlmsginfo_attrs`. snl(3) is extended to enable decoding of netlink messages with metadata (`snl_read_message_dbg()` stores the parsed structure in the provided buffer). Differential Revision: https://reviews.freebsd.org/D39391
2023-04-28 12:44:04 +00:00
struct snl_msg_info attrs = {};
struct nlmsghdr *hdr;
route: show originator PID in netlink monitor Replacing rtsock with netlink also means providing similar tracing facilities, rtsock provides `route -n monitor` interface, where each message can be traced to the originating PID. This diff closes the feature gap between rtsock and netlink in that regard. Netlink works slightly differently from rtsock, as it is a generic message "broker". It calls some kernel KPIs and returns the result to the caller. Other Netlink consumers gets notified on the changed kernel state using the relevant subsystem callbacks. Typically, it is close to impossible to pass some data through these KPIs to enhance the notification. This diff approaches the problem by using osd(9) to assign the relevant socket pointer (`'nlp`) to the per-socket taskqueue execution thread. This change allows to recover the pointer in the aforementioned notification callbacks and extract some additional data. Using `osd(9)` (and adding additional metadata) to the notification receiver comes with some additional cost attached, so this interface needs to be enabled explicitly by using a newly-created `NETLINK_MSG_INFO` `SOL_NETLINK` socket option. The actual medatadata (which includes the originator PID) is provided via control messages. To enable extensibility, the control message data is encoded in the standard netlink(TLV-based) fashion. The list of the currently-provided properties can be found in `nlmsginfo_attrs`. snl(3) is extended to enable decoding of netlink messages with metadata (`snl_read_message_dbg()` stores the parsed structure in the provided buffer). Differential Revision: https://reviews.freebsd.org/D39391
2023-04-28 12:44:04 +00:00
while ((hdr = snl_read_message_dbg(&ss_event, &attrs)) != NULL)
{
route: show originator PID in netlink monitor Replacing rtsock with netlink also means providing similar tracing facilities, rtsock provides `route -n monitor` interface, where each message can be traced to the originating PID. This diff closes the feature gap between rtsock and netlink in that regard. Netlink works slightly differently from rtsock, as it is a generic message "broker". It calls some kernel KPIs and returns the result to the caller. Other Netlink consumers gets notified on the changed kernel state using the relevant subsystem callbacks. Typically, it is close to impossible to pass some data through these KPIs to enhance the notification. This diff approaches the problem by using osd(9) to assign the relevant socket pointer (`'nlp`) to the per-socket taskqueue execution thread. This change allows to recover the pointer in the aforementioned notification callbacks and extract some additional data. Using `osd(9)` (and adding additional metadata) to the notification receiver comes with some additional cost attached, so this interface needs to be enabled explicitly by using a newly-created `NETLINK_MSG_INFO` `SOL_NETLINK` socket option. The actual medatadata (which includes the originator PID) is provided via control messages. To enable extensibility, the control message data is encoded in the standard netlink(TLV-based) fashion. The list of the currently-provided properties can be found in `nlmsginfo_attrs`. snl(3) is extended to enable decoding of netlink messages with metadata (`snl_read_message_dbg()` stores the parsed structure in the provided buffer). Differential Revision: https://reviews.freebsd.org/D39391
2023-04-28 12:44:04 +00:00
print_nlmsg(&h, hdr, &attrs);
snl_clear_lb(&h.ss_cmd);
snl_clear_lb(&ss_event);
}
snl_free(&ss_event);
nl_helper_free(&h);
exit(0);
}
static void
print_flushed_route(struct snl_parsed_route *r, struct sockaddr *gw)
{
struct sockaddr *sa = r->rta_dst;
printf("%-20.20s ", r->rta_rtflags & RTF_HOST ?
routename(sa) : netname(sa));
sa = gw;
printf("%-20.20s ", routename(sa));
2023-04-09 10:04:56 +00:00
printf("-fib %-3d ", r->rta_table);
printf("done\n");
}
static int
flushroute_one(struct nl_helper *h, struct snl_parsed_route *r)
{
struct snl_state *ss = &h->ss_cmd;
struct snl_errmsg_data e = {};
struct snl_writer nw;
snl_init_writer(ss, &nw);
struct nlmsghdr *hdr = snl_create_msg_request(&nw, NL_RTM_DELROUTE);
struct rtmsg *rtm = snl_reserve_msg_object(&nw, struct rtmsg);
rtm->rtm_family = r->rtm_family;
rtm->rtm_dst_len = r->rtm_dst_len;
snl_add_msg_attr_u32(&nw, RTA_TABLE, r->rta_table);
snl_add_msg_attr_ip(&nw, RTA_DST, r->rta_dst);
if (! (hdr = snl_finalize_msg(&nw)) || !snl_send_message(ss, hdr))
return (ENOMEM);
if (!snl_read_reply_code(ss, hdr->nlmsg_seq, &e)) {
return (e.error);
if (e.error == EPERM)
errc(1, e.error, "RTM_DELROUTE failed:");
else
warnc(e.error, "RTM_DELROUTE failed:");
return (true);
};
route: show originator PID in netlink monitor Replacing rtsock with netlink also means providing similar tracing facilities, rtsock provides `route -n monitor` interface, where each message can be traced to the originating PID. This diff closes the feature gap between rtsock and netlink in that regard. Netlink works slightly differently from rtsock, as it is a generic message "broker". It calls some kernel KPIs and returns the result to the caller. Other Netlink consumers gets notified on the changed kernel state using the relevant subsystem callbacks. Typically, it is close to impossible to pass some data through these KPIs to enhance the notification. This diff approaches the problem by using osd(9) to assign the relevant socket pointer (`'nlp`) to the per-socket taskqueue execution thread. This change allows to recover the pointer in the aforementioned notification callbacks and extract some additional data. Using `osd(9)` (and adding additional metadata) to the notification receiver comes with some additional cost attached, so this interface needs to be enabled explicitly by using a newly-created `NETLINK_MSG_INFO` `SOL_NETLINK` socket option. The actual medatadata (which includes the originator PID) is provided via control messages. To enable extensibility, the control message data is encoded in the standard netlink(TLV-based) fashion. The list of the currently-provided properties can be found in `nlmsginfo_attrs`. snl(3) is extended to enable decoding of netlink messages with metadata (`snl_read_message_dbg()` stores the parsed structure in the provided buffer). Differential Revision: https://reviews.freebsd.org/D39391
2023-04-28 12:44:04 +00:00
if (verbose) {
struct snl_msg_info attrs = {};
print_nlmsg(h, hdr, &attrs);
}
else {
if (r->rta_multipath.num_nhops != 0) {
for (uint32_t i = 0; i < r->rta_multipath.num_nhops; i++) {
struct rta_mpath_nh *nh = r->rta_multipath.nhops[i];
print_flushed_route(r, nh->gw);
}
} else
print_flushed_route(r, r->rta_gw);
}
return (0);
}
int
flushroutes_fib_nl(int fib, int af)
{
struct snl_state ss = {};
struct snl_writer nw;
struct nl_helper h = {};
nl_init_socket(&ss);
snl_init_writer(&ss, &nw);
struct nlmsghdr *hdr = snl_create_msg_request(&nw, NL_RTM_GETROUTE);
hdr->nlmsg_flags |= NLM_F_DUMP;
struct rtmsg *rtm = snl_reserve_msg_object(&nw, struct rtmsg);
rtm->rtm_family = af;
snl_add_msg_attr_u32(&nw, RTA_TABLE, fib);
if (! (hdr = snl_finalize_msg(&nw)) || !snl_send_message(&ss, hdr)) {
snl_free(&ss);
return (EINVAL);
}
struct snl_errmsg_data e = {};
uint32_t nlm_seq = hdr->nlmsg_seq;
nl_helper_init(&h);
while ((hdr = snl_read_reply_multi(&ss, nlm_seq, &e)) != NULL) {
struct snl_parsed_route r = { .rtax_weight = RT_DEFAULT_WEIGHT };
int error;
if (!snl_parse_nlmsg(&ss, hdr, &snl_rtm_route_parser, &r))
continue;
route: show originator PID in netlink monitor Replacing rtsock with netlink also means providing similar tracing facilities, rtsock provides `route -n monitor` interface, where each message can be traced to the originating PID. This diff closes the feature gap between rtsock and netlink in that regard. Netlink works slightly differently from rtsock, as it is a generic message "broker". It calls some kernel KPIs and returns the result to the caller. Other Netlink consumers gets notified on the changed kernel state using the relevant subsystem callbacks. Typically, it is close to impossible to pass some data through these KPIs to enhance the notification. This diff approaches the problem by using osd(9) to assign the relevant socket pointer (`'nlp`) to the per-socket taskqueue execution thread. This change allows to recover the pointer in the aforementioned notification callbacks and extract some additional data. Using `osd(9)` (and adding additional metadata) to the notification receiver comes with some additional cost attached, so this interface needs to be enabled explicitly by using a newly-created `NETLINK_MSG_INFO` `SOL_NETLINK` socket option. The actual medatadata (which includes the originator PID) is provided via control messages. To enable extensibility, the control message data is encoded in the standard netlink(TLV-based) fashion. The list of the currently-provided properties can be found in `nlmsginfo_attrs`. snl(3) is extended to enable decoding of netlink messages with metadata (`snl_read_message_dbg()` stores the parsed structure in the provided buffer). Differential Revision: https://reviews.freebsd.org/D39391
2023-04-28 12:44:04 +00:00
if (verbose) {
struct snl_msg_info attrs = {};
print_nlmsg(&h, hdr, &attrs);
}
if (r.rta_table != (uint32_t)fib || r.rtm_family != af)
continue;
if ((r.rta_rtflags & RTF_GATEWAY) == 0)
continue;
if (debugonly)
continue;
if ((error = flushroute_one(&h, &r)) != 0) {
if (error == EPERM)
errc(1, error, "RTM_DELROUTE failed:");
else
warnc(error, "RTM_DELROUTE failed:");
}
snl_clear_lb(&h.ss_cmd);
}
snl_free(&ss);
nl_helper_free(&h);
return (e.error);
}