Date: Tue, 28 Mar 2023 10:08:53 +0100 From: Alexander Chernikov <melifaro@FreeBSD.org> To: Jessica Clarke <jrtc27@freebsd.org> Cc: "src-committers@freebsd.org" <src-committers@FreeBSD.org>, "dev-commits-src-all@freebsd.org" <dev-commits-src-all@FreeBSD.org>, "dev-commits-src-main@freebsd.org" <dev-commits-src-main@FreeBSD.org> Subject: Re: git: c597432e2297 - main - route(8): convert to netlink Message-ID: <F0DD3830-654C-49F1-B6D6-C17171A30553@FreeBSD.org> In-Reply-To: <81A0DF64-F466-451F-83CB-86A9FC1EB300@freebsd.org> References: <202303261107.32QB7UZK058893@gitrepo.freebsd.org> <81A0DF64-F466-451F-83CB-86A9FC1EB300@freebsd.org>
next in thread | previous in thread | raw e-mail | index | archive | help
[-- Attachment #1 --] > On 27 Mar 2023, at 21:41, Jessica Clarke <jrtc27@freebsd.org> wrote: > > On 26 Mar 2023, at 12:07, Alexander V. Chernikov <melifaro@FreeBSD.org <mailto:melifaro@FreeBSD.org>> wrote: >> >> The branch main has been updated by melifaro: >> >> URL: https://cgit.FreeBSD.org/src/commit/?id=c597432e22975f4d409b8453779967129c6b57e9 >> >> commit c597432e22975f4d409b8453779967129c6b57e9 >> Author: Alexander V. Chernikov <melifaro@FreeBSD.org> >> AuthorDate: 2023-03-26 09:13:50 +0000 >> Commit: Alexander V. Chernikov <melifaro@FreeBSD.org> >> CommitDate: 2023-03-26 11:06:56 +0000 >> >> route(8): convert to netlink >> >> This change converts all kernel rtsock interactions in route(8) >> to Netlink. >> >> Based on the WITHOUT_NETLINK_SUPPORT src.conf(5) variable, route(8) >> now fully operates either via Netlink or via rtsock/sysctl. >> The default (compile-time) is Netlink. >> >> The output for route delete/add/get/flush is targeted to be exactly >> the same (apart from some error handling cases). >> The output for the route monitor has been changed to improve >> readability and support netlink models. >> >> Other behaviour changes: >> * exact prefix lookup (route -n get a.b.c.d/e) is not yet supported. >> * route monitor does not show the change originator yet. > > If there are regressions then it should be off by default, *especially* Hi Jessica, I have a plan to fix both this week. I’d also want to note that these two are not the documented / often used features. > when we’re just under a month out from the proposed 14 code slush. > > Jess > >> Differential Revision: https://reviews.freebsd.org/D39007 >> --- >> sbin/route/Makefile | 6 + >> sbin/route/route.c | 117 +++++-- >> sbin/route/route_netlink.c | 835 +++++++++++++++++++++++++++++++++++++++++++++ >> 3 files changed, 930 insertions(+), 28 deletions(-) >> >> diff --git a/sbin/route/Makefile b/sbin/route/Makefile >> index e65030f805bb..aec222310d46 100644 >> --- a/sbin/route/Makefile >> +++ b/sbin/route/Makefile >> @@ -19,6 +19,12 @@ CFLAGS+= -DINET6 >> .endif >> CFLAGS+= -I. >> >> +.if ${MK_NETLINK_SUPPORT} != "no" >> +SRCS+= route_netlink.c >> +.else >> +CFLAGS+=-DWITHOUT_NETLINK >> +.endif >> + >> HAS_TESTS= >> SUBDIR.${MK_TESTS}+= tests >> >> diff --git a/sbin/route/route.c b/sbin/route/route.c >> index 5f33cecb1b20..947c97ce794a 100644 >> --- a/sbin/route/route.c >> +++ b/sbin/route/route.c >> @@ -90,12 +90,11 @@ static struct keytab { >> {0, 0} >> }; >> >> +int verbose, debugonly; >> static struct sockaddr_storage so[RTAX_MAX]; >> static int pid, rtm_addrs; >> -static int s; >> -static int nflag, af, qflag, tflag; >> -static int verbose, aflen; >> -static int locking, lockrest, debugonly; >> +static int nflag, af, aflen, qflag, tflag; >> +static int locking, lockrest; >> static struct rt_metrics rt_metrics; >> static u_long rtm_inits; >> static uid_t uid; >> @@ -103,18 +102,30 @@ static int defaultfib; >> static int numfibs; >> static char domain[MAXHOSTNAMELEN + 1]; >> static bool domain_initialized; >> -static int rtm_seq; >> static char rt_line[NI_MAXHOST]; >> static char net_line[MAXHOSTNAMELEN + 1]; >> >> +#ifdef WITHOUT_NETLINK >> +static int s; >> +static int rtm_seq; >> + >> static struct { >> struct rt_msghdr m_rtm; >> char m_space[512]; >> } m_rtmsg; >> >> +static int rtmsg_rtsock(int, int, int); >> +static int flushroutes_fib_rtsock(int); >> +static void monitor_rtsock(void); >> +#else >> +int rtmsg_nl(int, int, int, struct sockaddr_storage *, struct rt_metrics *); >> +int flushroutes_fib_nl(int, int); >> +void monitor_nl(int); >> +#endif >> + >> static TAILQ_HEAD(fibl_head_t, fibl) fibl_head; >> >> -static void printb(int, const char *); >> +void printb(int, const char *); >> static void flushroutes(int argc, char *argv[]); >> static int flushroutes_fib(int); >> static int getaddr(int, char *, int); >> @@ -127,7 +138,7 @@ static int inet6_makenetandmask(struct sockaddr_in6 *, const char *); >> #endif >> static void interfaces(void); >> static void monitor(int, char*[]); >> -static const char *netname(struct sockaddr *); >> +const char *netname(struct sockaddr *); >> static void newroute(int, char **); >> static int newroute_fib(int, char *, int); >> static void pmsg_addrs(char *, int, size_t); >> @@ -135,7 +146,7 @@ static void pmsg_common(struct rt_msghdr *, size_t); >> static int prefixlen(const char *); >> static void print_getmsg(struct rt_msghdr *, int, int); >> static void print_rtmsg(struct rt_msghdr *, size_t); >> -static const char *routename(struct sockaddr *); >> +const char *routename(struct sockaddr *); >> static int rtmsg(int, int, int); >> static void set_metric(char *, int); >> static int set_sofib(int); >> @@ -216,12 +227,14 @@ main(int argc, char **argv) >> >> pid = getpid(); >> uid = geteuid(); >> +#ifdef WITHOUT_NETLINK >> if (tflag) >> s = open(_PATH_DEVNULL, O_WRONLY, 0); >> else >> s = socket(PF_ROUTE, SOCK_RAW, 0); >> if (s < 0) >> err(EX_OSERR, "socket"); >> +#endif >> >> len = sizeof(numfibs); >> if (sysctlbyname("net.fibs", (void *)&numfibs, &len, NULL, 0) == -1) >> @@ -264,10 +277,14 @@ static int >> set_sofib(int fib) >> { >> >> +#ifdef WITHOUT_NETLINK >> if (fib < 0) >> return (0); >> return (setsockopt(s, SOL_SOCKET, SO_SETFIB, (void *)&fib, >> sizeof(fib))); >> +#else >> + return (0); >> +#endif >> } >> >> static int >> @@ -395,7 +412,9 @@ flushroutes(int argc, char *argv[]) >> >> if (uid != 0 && !debugonly && !tflag) >> errx(EX_NOPERM, "must be root to alter routing table"); >> +#ifdef WITHOUT_NETLINK >> shutdown(s, SHUT_RD); /* Don't want to read back our messages */ >> +#endif >> >> TAILQ_INIT(&fibl_head); >> while (argc > 1) { >> @@ -441,6 +460,17 @@ flushroutes(int argc, char *argv[]) >> >> static int >> flushroutes_fib(int fib) >> +{ >> +#ifdef WITHOUT_NETLINK >> + return (flushroutes_fib_rtsock(fib)); >> +#else >> + return (flushroutes_fib_nl(fib, af)); >> +#endif >> +} >> + >> +#ifdef WITHOUT_NETLINK >> +static int >> +flushroutes_fib_rtsock(int fib) >> { >> struct rt_msghdr *rtm; >> size_t needed; >> @@ -525,8 +555,9 @@ retry: >> free(buf); >> return (error); >> } >> +#endif >> >> -static const char * >> +const char * >> routename(struct sockaddr *sa) >> { >> struct sockaddr_dl *sdl; >> @@ -645,7 +676,7 @@ routename(struct sockaddr *sa) >> * Return the name of the network whose address is given. >> * The address is assumed to be that of a net, not a host. >> */ >> -static const char * >> +const char * >> netname(struct sockaddr *sa) >> { >> struct sockaddr_dl *sdl; >> @@ -810,8 +841,10 @@ newroute(int argc, char **argv) >> warn("sigaction SIGALRM"); >> >> cmd = argv[0]; >> +#ifdef WITHOUT_NETLINK >> if (*cmd != 'g' && *cmd != 's') >> shutdown(s, SHUT_RD); /* Don't want to read back our messages */ >> +#endif >> while (--argc > 0) { >> if (**(++argv)== '-') { >> switch (key = keyword(1 + *argv)) { >> @@ -1398,8 +1431,8 @@ retry2: >> static void >> monitor(int argc, char *argv[]) >> { >> - int n, fib, error; >> - char msg[2048], *endptr; >> + int fib, error; >> + char *endptr; >> >> fib = defaultfib; >> while (argc > 1) { >> @@ -1435,6 +1468,19 @@ monitor(int argc, char *argv[]) >> interfaces(); >> exit(0); >> } >> +#ifdef WITHOUT_NETLINK >> + monitor_rtsock(); >> +#else >> + monitor_nl(fib); >> +#endif >> +} >> + >> +#ifdef WITHOUT_NETLINK >> +static void >> +monitor_rtsock(void) >> +{ >> + char msg[2048]; >> + int n; >> >> #ifdef SO_RERROR >> n = 1; >> @@ -1454,25 +1500,12 @@ monitor(int argc, char *argv[]) >> print_rtmsg((struct rt_msghdr *)(void *)msg, n); >> } >> } >> +#endif >> >> static int >> rtmsg(int cmd, int flags, int fib) >> { >> - int rlen; >> - char *cp = m_rtmsg.m_space; >> - int l; >> - >> -#define NEXTADDR(w, u) \ >> - if (rtm_addrs & (w)) { \ >> - l = SA_SIZE(&(u)); \ >> - memmove(cp, (char *)&(u), l); \ >> - cp += l; \ >> - if (verbose) \ >> - sodump((struct sockaddr *)&(u), #w); \ >> - } >> - >> errno = 0; >> - memset(&m_rtmsg, 0, sizeof(m_rtmsg)); >> if (cmd == 'a') >> cmd = RTM_ADD; >> else if (cmd == 'c') >> @@ -1488,6 +1521,33 @@ rtmsg(int cmd, int flags, int fib) >> cmd = RTM_DELETE; >> flags |= RTF_PINNED; >> } >> +#ifdef WITHOUT_NETLINK >> + return (rtmsg_rtsock(cmd, flags, fib)); >> +#else >> + errno = rtmsg_nl(cmd, flags, fib, so, &rt_metrics); >> + return (errno == 0 ? 0 : -1); >> +#endif >> +} >> + >> +#ifdef WITHOUT_NETLINK >> +static int >> +rtmsg_rtsock(int cmd, int flags, int fib) >> +{ >> + int rlen; >> + char *cp = m_rtmsg.m_space; >> + int l; >> + >> + memset(&m_rtmsg, 0, sizeof(m_rtmsg)); >> + >> +#define NEXTADDR(w, u) \ >> + if (rtm_addrs & (w)) { \ >> + l = SA_SIZE(&(u)); \ >> + memmove(cp, (char *)&(u), l); \ >> + cp += l; \ >> + if (verbose) \ >> + sodump((struct sockaddr *)&(u), #w); \ >> + } >> + >> #define rtm m_rtmsg.m_rtm >> rtm.rtm_type = cmd; >> rtm.rtm_flags = flags; >> @@ -1545,6 +1605,7 @@ rtmsg(int cmd, int flags, int fib) >> #undef rtm >> return (0); >> } >> +#endif >> >> static const char *const msgtypes[] = { >> "", >> @@ -1571,7 +1632,7 @@ static const char *const msgtypes[] = { >> static const char metricnames[] = >> "\011weight\010rttvar\7rtt\6ssthresh\5sendpipe\4recvpipe\3expire" >> "\1mtu"; >> -static const char routeflags[] = >> +const char routeflags[] = >> "\1UP\2GATEWAY\3HOST\4REJECT\5DYNAMIC\6MODIFIED\7DONE" >> "\012XRESOLVE\013LLINFO\014STATIC\015BLACKHOLE" >> "\017PROTO2\020PROTO1\021PRCLONING\022WASCLONED\023PROTO3" >> @@ -1812,7 +1873,7 @@ pmsg_addrs(char *cp, int addrs, size_t len) >> (void)fflush(stdout); >> } >> >> -static void >> +void >> printb(int b, const char *str) >> { >> int i; >> diff --git a/sbin/route/route_netlink.c b/sbin/route/route_netlink.c >> new file mode 100644 >> index 000000000000..648d866670fc >> --- /dev/null >> +++ b/sbin/route/route_netlink.c >> @@ -0,0 +1,835 @@ >> +#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/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, 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; >> +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); >> + >> +#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); >> +} >> + >> +struct nl_helper { >> + struct snl_state ss_cmd; >> +}; >> + >> +static void >> +nl_helper_init(struct nl_helper *h) >> +{ >> + if (!snl_init(&h->ss_cmd, NETLINK_ROUTE)) >> + err(1, "unable to open netlink socket"); >> +} >> + >> +static void >> +nl_helper_free(struct nl_helper *h) >> +{ >> + snl_free(&h->ss_cmd); >> +} >> + >> +static int >> +rtmsg_nl_int(struct nl_helper *h, int cmd, int rtm_flags, int fib, >> + 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 = (struct sockaddr *)&so[RTAX_DST]; >> + struct sockaddr *mask = (struct sockaddr *)&so[RTAX_NETMASK]; >> + struct sockaddr *gw = (struct sockaddr *)&so[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; >> + >> + plen = mask4 ? bitcount32(mask4->sin_addr.s_addr) : 32; >> + break; >> + } >> + case AF_INET6: >> + { >> + struct sockaddr_in6 *mask6 = (struct sockaddr_in6 *)mask; >> + >> + plen = mask6 ? inet6_get_plen(&mask6->sin6_addr) : 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; >> + >> + snl_add_msg_attr_ip(&nw, RTA_DST, dst); >> + snl_add_msg_attr_u32(&nw, RTA_TABLE, fib); >> + >> + 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); >> + } else if (gw != NULL) { >> + /* Should be AF_LINK */ >> + struct sockaddr_dl *sdl = (struct sockaddr_dl *)gw; >> + if (sdl->sdl_index != 0) >> + snl_add_msg_attr_u32(&nw, RTA_OIF, sdl->sdl_index); >> + } >> + >> + 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 (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); >> + else { >> + snl_parse_errmsg(ss, hdr, &e); >> + if (e.error == ESRCH) >> + warn("route has not been found"); >> + else >> + warn("message indicates error %d", e.error); >> + } >> + >> + return (0); >> + } >> + >> + if (snl_parse_errmsg(ss, hdr, &e)) >> + return (e.error); >> + } >> + return (EINVAL); >> +} >> + >> +int >> +rtmsg_nl(int cmd, int rtm_flags, int fib, 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, 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 (!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 >> +print_line_prefix(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); >> + int len = printf("%s.%03ld %s %s ", buf, tp.tv_nsec / 1000000, 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 >> +print_nlmsg_route(struct nl_helper *h, struct nlmsghdr *hdr) >> +{ >> + 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); >> + int len = print_line_prefix(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 != NULL) { >> + bool first = true; >> + >> + memset(buf, ' ', sizeof(buf)); >> + buf[len] = '\0'; >> + >> + for (int 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 >> +print_nlmsg_link(struct nl_helper *h, struct nlmsghdr *hdr) >> +{ >> + 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); >> + print_line_prefix(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 >> +print_nlmsg_addr(struct nl_helper *h, struct nlmsghdr *hdr) >> +{ >> + 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); >> + print_line_prefix(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 >> +print_nlmsg_neigh(struct nl_helper *h, struct nlmsghdr *hdr) >> +{ >> + 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); >> + print_line_prefix(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 >> +print_nlmsg_generic(struct nl_helper *h, struct nlmsghdr *hdr) >> +{ >> +} >> + >> +static void >> +print_nlmsg(struct nl_helper *h, struct nlmsghdr *hdr) >> +{ >> + switch (hdr->nlmsg_type) { >> + case RTM_NEWLINK: >> + case RTM_DELLINK: >> + print_nlmsg_link(h, hdr); >> + break; >> *** 184 LINES SKIPPED *** [-- Attachment #2 --] <html><head><meta http-equiv="content-type" content="text/html; charset=utf-8"></head><body style="overflow-wrap: break-word; -webkit-nbsp-mode: space; line-break: after-white-space;"><br><div><br><blockquote type="cite"><div>On 27 Mar 2023, at 21:41, Jessica Clarke <jrtc27@freebsd.org> wrote:</div><br class="Apple-interchange-newline"><div><meta charset="UTF-8"><span style="caret-color: rgb(0, 0, 0); font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none; float: none; display: inline !important;">On 26 Mar 2023, at 12:07, Alexander V. Chernikov <</span><a href="mailto:melifaro@FreeBSD.org" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px;">melifaro@FreeBSD.org</a><span style="caret-color: rgb(0, 0, 0); font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none; float: none; display: inline !important;">> wrote:</span><br style="caret-color: rgb(0, 0, 0); font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none;"><blockquote type="cite" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; text-decoration: none;"><br>The branch main has been updated by melifaro:<br><br>URL: https://cgit.FreeBSD.org/src/commit/?id=c597432e22975f4d409b8453779967129c6b57e9<br><br>commit c597432e22975f4d409b8453779967129c6b57e9<br>Author: Alexander V. Chernikov <melifaro@FreeBSD.org><br>AuthorDate: 2023-03-26 09:13:50 +0000<br>Commit: Alexander V. Chernikov <melifaro@FreeBSD.org><br>CommitDate: 2023-03-26 11:06:56 +0000<br><br> route(8): convert to netlink<br><br> This change converts all kernel rtsock interactions in route(8)<br> to Netlink.<br><br> Based on the WITHOUT_NETLINK_SUPPORT src.conf(5) variable, route(8)<br> now fully operates either via Netlink or via rtsock/sysctl.<br> The default (compile-time) is Netlink.<br><br> The output for route delete/add/get/flush is targeted to be exactly<br> the same (apart from some error handling cases).<br> The output for the route monitor has been changed to improve<br> readability and support netlink models.<br><br> Other behaviour changes:<br> * exact prefix lookup (route -n get a.b.c.d/e) is not yet supported.<br> * route monitor does not show the change originator yet.<br></blockquote><br style="caret-color: rgb(0, 0, 0); font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none;"><span style="caret-color: rgb(0, 0, 0); font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none; float: none; display: inline !important;">If there are regressions then it should be off by default, *especially*</span><br style="caret-color: rgb(0, 0, 0); font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none;"></div></blockquote>Hi Jessica,</div><div>I have a plan to fix both this week. I’d also want to note that these two are not the documented / often used features.</div><div><blockquote type="cite"><div><span style="caret-color: rgb(0, 0, 0); font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none; float: none; display: inline !important;">when we’re just under a month out from the proposed 14 code slush.</span><br style="caret-color: rgb(0, 0, 0); font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none;"><br style="caret-color: rgb(0, 0, 0); font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none;"><span style="caret-color: rgb(0, 0, 0); font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none; float: none; display: inline !important;">Jess</span><br style="caret-color: rgb(0, 0, 0); font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none;"><br style="caret-color: rgb(0, 0, 0); font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration: none;"><blockquote type="cite" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; text-decoration: none;"> Differential Revision: https://reviews.freebsd.org/D39007<br>---<br>sbin/route/Makefile | 6 +<br>sbin/route/route.c | 117 +++++--<br>sbin/route/route_netlink.c | 835 +++++++++++++++++++++++++++++++++++++++++++++<br>3 files changed, 930 insertions(+), 28 deletions(-)<br><br>diff --git a/sbin/route/Makefile b/sbin/route/Makefile<br>index e65030f805bb..aec222310d46 100644<br>--- a/sbin/route/Makefile<br>+++ b/sbin/route/Makefile<br>@@ -19,6 +19,12 @@ CFLAGS+= -DINET6<br>.endif<br>CFLAGS+= -I.<br><br>+.if ${MK_NETLINK_SUPPORT} != "no"<br>+SRCS+=<span class="Apple-tab-span" style="white-space: pre;"> </span>route_netlink.c<br>+.else<br>+CFLAGS+=-DWITHOUT_NETLINK<br>+.endif<br>+<br>HAS_TESTS=<br>SUBDIR.${MK_TESTS}+= tests<br><br>diff --git a/sbin/route/route.c b/sbin/route/route.c<br>index 5f33cecb1b20..947c97ce794a 100644<br>--- a/sbin/route/route.c<br>+++ b/sbin/route/route.c<br>@@ -90,12 +90,11 @@ static struct keytab {<br><span class="Apple-tab-span" style="white-space: pre;"> </span>{0, 0}<br>};<br><br>+int<span class="Apple-tab-span" style="white-space: pre;"> </span>verbose, debugonly;<br>static struct sockaddr_storage so[RTAX_MAX];<br>static int<span class="Apple-tab-span" style="white-space: pre;"> </span>pid, rtm_addrs;<br>-static int<span class="Apple-tab-span" style="white-space: pre;"> </span>s;<br>-static int<span class="Apple-tab-span" style="white-space: pre;"> </span>nflag, af, qflag, tflag;<br>-static int<span class="Apple-tab-span" style="white-space: pre;"> </span>verbose, aflen;<br>-static int<span class="Apple-tab-span" style="white-space: pre;"> </span>locking, lockrest, debugonly;<br>+static int<span class="Apple-tab-span" style="white-space: pre;"> </span>nflag, af, aflen, qflag, tflag;<br>+static int<span class="Apple-tab-span" style="white-space: pre;"> </span>locking, lockrest;<br>static struct rt_metrics rt_metrics;<br>static u_long rtm_inits;<br>static uid_t<span class="Apple-tab-span" style="white-space: pre;"> </span>uid;<br>@@ -103,18 +102,30 @@ static int<span class="Apple-tab-span" style="white-space: pre;"> </span>defaultfib;<br>static int<span class="Apple-tab-span" style="white-space: pre;"> </span>numfibs;<br>static char<span class="Apple-tab-span" style="white-space: pre;"> </span>domain[MAXHOSTNAMELEN + 1];<br>static bool<span class="Apple-tab-span" style="white-space: pre;"> </span>domain_initialized;<br>-static int<span class="Apple-tab-span" style="white-space: pre;"> </span>rtm_seq;<br>static char<span class="Apple-tab-span" style="white-space: pre;"> </span>rt_line[NI_MAXHOST];<br>static char<span class="Apple-tab-span" style="white-space: pre;"> </span>net_line[MAXHOSTNAMELEN + 1];<br><br>+#ifdef WITHOUT_NETLINK<br>+static int<span class="Apple-tab-span" style="white-space: pre;"> </span>s;<br>+static int<span class="Apple-tab-span" style="white-space: pre;"> </span>rtm_seq;<br>+<br>static struct {<br><span class="Apple-tab-span" style="white-space: pre;"> </span>struct<span class="Apple-tab-span" style="white-space: pre;"> </span>rt_msghdr m_rtm;<br><span class="Apple-tab-span" style="white-space: pre;"> </span>char<span class="Apple-tab-span" style="white-space: pre;"> </span>m_space[512];<br>} m_rtmsg;<br><br>+static int<span class="Apple-tab-span" style="white-space: pre;"> </span>rtmsg_rtsock(int, int, int);<br>+static int<span class="Apple-tab-span" style="white-space: pre;"> </span>flushroutes_fib_rtsock(int);<br>+static void<span class="Apple-tab-span" style="white-space: pre;"> </span>monitor_rtsock(void);<br>+#else<br>+int<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>rtmsg_nl(int, int, int, struct sockaddr_storage *, struct rt_metrics *);<br>+int<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>flushroutes_fib_nl(int, int);<br>+void<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>monitor_nl(int);<br>+#endif<br>+<br>static TAILQ_HEAD(fibl_head_t, fibl) fibl_head;<br><br>-static void<span class="Apple-tab-span" style="white-space: pre;"> </span>printb(int, const char *);<br>+void<span class="Apple-tab-span" style="white-space: pre;"> </span>printb(int, const char *);<br>static void<span class="Apple-tab-span" style="white-space: pre;"> </span>flushroutes(int argc, char *argv[]);<br>static int<span class="Apple-tab-span" style="white-space: pre;"> </span>flushroutes_fib(int);<br>static int<span class="Apple-tab-span" style="white-space: pre;"> </span>getaddr(int, char *, int);<br>@@ -127,7 +138,7 @@ static int<span class="Apple-tab-span" style="white-space: pre;"> </span>inet6_makenetandmask(struct sockaddr_in6 *, const char *);<br>#endif<br>static void<span class="Apple-tab-span" style="white-space: pre;"> </span>interfaces(void);<br>static void<span class="Apple-tab-span" style="white-space: pre;"> </span>monitor(int, char*[]);<br>-static const char<span class="Apple-tab-span" style="white-space: pre;"> </span>*netname(struct sockaddr *);<br>+const char<span class="Apple-tab-span" style="white-space: pre;"> </span>*netname(struct sockaddr *);<br>static void<span class="Apple-tab-span" style="white-space: pre;"> </span>newroute(int, char **);<br>static int<span class="Apple-tab-span" style="white-space: pre;"> </span>newroute_fib(int, char *, int);<br>static void<span class="Apple-tab-span" style="white-space: pre;"> </span>pmsg_addrs(char *, int, size_t);<br>@@ -135,7 +146,7 @@ static void<span class="Apple-tab-span" style="white-space: pre;"> </span>pmsg_common(struct rt_msghdr *, size_t);<br>static int<span class="Apple-tab-span" style="white-space: pre;"> </span>prefixlen(const char *);<br>static void<span class="Apple-tab-span" style="white-space: pre;"> </span>print_getmsg(struct rt_msghdr *, int, int);<br>static void<span class="Apple-tab-span" style="white-space: pre;"> </span>print_rtmsg(struct rt_msghdr *, size_t);<br>-static const char<span class="Apple-tab-span" style="white-space: pre;"> </span>*routename(struct sockaddr *);<br>+const char<span class="Apple-tab-span" style="white-space: pre;"> </span>*routename(struct sockaddr *);<br>static int<span class="Apple-tab-span" style="white-space: pre;"> </span>rtmsg(int, int, int);<br>static void<span class="Apple-tab-span" style="white-space: pre;"> </span>set_metric(char *, int);<br>static int<span class="Apple-tab-span" style="white-space: pre;"> </span>set_sofib(int);<br>@@ -216,12 +227,14 @@ main(int argc, char **argv)<br><br><span class="Apple-tab-span" style="white-space: pre;"> </span>pid = getpid();<br><span class="Apple-tab-span" style="white-space: pre;"> </span>uid = geteuid();<br>+#ifdef WITHOUT_NETLINK<br><span class="Apple-tab-span" style="white-space: pre;"> </span>if (tflag)<br><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>s = open(_PATH_DEVNULL, O_WRONLY, 0);<br><span class="Apple-tab-span" style="white-space: pre;"> </span>else<br><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>s = socket(PF_ROUTE, SOCK_RAW, 0);<br><span class="Apple-tab-span" style="white-space: pre;"> </span>if (s < 0)<br><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>err(EX_OSERR, "socket");<br>+#endif<br><br><span class="Apple-tab-span" style="white-space: pre;"> </span>len = sizeof(numfibs);<br><span class="Apple-tab-span" style="white-space: pre;"> </span>if (sysctlbyname("net.fibs", (void *)&numfibs, &len, NULL, 0) == -1)<br>@@ -264,10 +277,14 @@ static int<br>set_sofib(int fib)<br>{<br><br>+#ifdef WITHOUT_NETLINK<br><span class="Apple-tab-span" style="white-space: pre;"> </span>if (fib < 0)<br><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>return (0);<br><span class="Apple-tab-span" style="white-space: pre;"> </span>return (setsockopt(s, SOL_SOCKET, SO_SETFIB, (void *)&fib,<br><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-converted-space"> </span> sizeof(fib)));<br>+#else<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>return (0);<br>+#endif<br>}<br><br>static int<br>@@ -395,7 +412,9 @@ flushroutes(int argc, char *argv[])<br><br><span class="Apple-tab-span" style="white-space: pre;"> </span>if (uid != 0 && !debugonly && !tflag)<br><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>errx(EX_NOPERM, "must be root to alter routing table");<br>+#ifdef WITHOUT_NETLINK<br><span class="Apple-tab-span" style="white-space: pre;"> </span>shutdown(s, SHUT_RD); /* Don't want to read back our messages */<br>+#endif<br><br><span class="Apple-tab-span" style="white-space: pre;"> </span>TAILQ_INIT(&fibl_head);<br><span class="Apple-tab-span" style="white-space: pre;"> </span>while (argc > 1) {<br>@@ -441,6 +460,17 @@ flushroutes(int argc, char *argv[])<br><br>static int<br>flushroutes_fib(int fib)<br>+{<br>+#ifdef WITHOUT_NETLINK<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>return (flushroutes_fib_rtsock(fib));<br>+#else<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>return (flushroutes_fib_nl(fib, af));<br>+#endif<br>+}<br>+<br>+#ifdef WITHOUT_NETLINK<br>+static int<br>+flushroutes_fib_rtsock(int fib)<br>{<br><span class="Apple-tab-span" style="white-space: pre;"> </span>struct rt_msghdr *rtm;<br><span class="Apple-tab-span" style="white-space: pre;"> </span>size_t needed;<br>@@ -525,8 +555,9 @@ retry:<br><span class="Apple-tab-span" style="white-space: pre;"> </span>free(buf);<br><span class="Apple-tab-span" style="white-space: pre;"> </span>return (error);<br>}<br>+#endif<br><br>-static const char *<br>+const char *<br>routename(struct sockaddr *sa)<br>{<br><span class="Apple-tab-span" style="white-space: pre;"> </span>struct sockaddr_dl *sdl;<br>@@ -645,7 +676,7 @@ routename(struct sockaddr *sa)<br>* Return the name of the network whose address is given.<br>* The address is assumed to be that of a net, not a host.<br>*/<br>-static const char *<br>+const char *<br>netname(struct sockaddr *sa)<br>{<br><span class="Apple-tab-span" style="white-space: pre;"> </span>struct sockaddr_dl *sdl;<br>@@ -810,8 +841,10 @@ newroute(int argc, char **argv)<br><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>warn("sigaction SIGALRM");<br><br><span class="Apple-tab-span" style="white-space: pre;"> </span>cmd = argv[0];<br>+#ifdef WITHOUT_NETLINK<br><span class="Apple-tab-span" style="white-space: pre;"> </span>if (*cmd != 'g' && *cmd != 's')<br><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>shutdown(s, SHUT_RD); /* Don't want to read back our messages */<br>+#endif<br><span class="Apple-tab-span" style="white-space: pre;"> </span>while (--argc > 0) {<br><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>if (**(++argv)== '-') {<br><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>switch (key = keyword(1 + *argv)) {<br>@@ -1398,8 +1431,8 @@ retry2:<br>static void<br>monitor(int argc, char *argv[])<br>{<br>-<span class="Apple-tab-span" style="white-space: pre;"> </span>int n, fib, error;<br>-<span class="Apple-tab-span" style="white-space: pre;"> </span>char msg[2048], *endptr;<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>int fib, error;<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>char *endptr;<br><br><span class="Apple-tab-span" style="white-space: pre;"> </span>fib = defaultfib;<br><span class="Apple-tab-span" style="white-space: pre;"> </span>while (argc > 1) {<br>@@ -1435,6 +1468,19 @@ monitor(int argc, char *argv[])<br><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>interfaces();<br><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>exit(0);<br><span class="Apple-tab-span" style="white-space: pre;"> </span>}<br>+#ifdef WITHOUT_NETLINK<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>monitor_rtsock();<br>+#else<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>monitor_nl(fib);<br>+#endif<br>+}<br>+<br>+#ifdef WITHOUT_NETLINK<br>+static void<br>+monitor_rtsock(void)<br>+{<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>char msg[2048];<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>int n;<br><br>#ifdef SO_RERROR<br><span class="Apple-tab-span" style="white-space: pre;"> </span>n = 1;<br>@@ -1454,25 +1500,12 @@ monitor(int argc, char *argv[])<br><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>print_rtmsg((struct rt_msghdr *)(void *)msg, n);<br><span class="Apple-tab-span" style="white-space: pre;"> </span>}<br>}<br>+#endif<br><br>static int<br>rtmsg(int cmd, int flags, int fib)<br>{<br>-<span class="Apple-tab-span" style="white-space: pre;"> </span>int rlen;<br>-<span class="Apple-tab-span" style="white-space: pre;"> </span>char *cp = m_rtmsg.m_space;<br>-<span class="Apple-tab-span" style="white-space: pre;"> </span>int l;<br>-<br>-#define NEXTADDR(w, u)<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>\<br>-<span class="Apple-tab-span" style="white-space: pre;"> </span>if (rtm_addrs & (w)) {<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>\<br>-<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>l = SA_SIZE(&(u));<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>\<br>-<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>memmove(cp, (char *)&(u), l);<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>\<br>-<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>cp += l;<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>\<br>-<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>if (verbose)<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>\<br>-<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>sodump((struct sockaddr *)&(u), #w);<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>\<br>-<span class="Apple-tab-span" style="white-space: pre;"> </span>}<br>-<br><span class="Apple-tab-span" style="white-space: pre;"> </span>errno = 0;<br>-<span class="Apple-tab-span" style="white-space: pre;"> </span>memset(&m_rtmsg, 0, sizeof(m_rtmsg));<br><span class="Apple-tab-span" style="white-space: pre;"> </span>if (cmd == 'a')<br><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>cmd = RTM_ADD;<br><span class="Apple-tab-span" style="white-space: pre;"> </span>else if (cmd == 'c')<br>@@ -1488,6 +1521,33 @@ rtmsg(int cmd, int flags, int fib)<br><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>cmd = RTM_DELETE;<br><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>flags |= RTF_PINNED;<br><span class="Apple-tab-span" style="white-space: pre;"> </span>}<br>+#ifdef WITHOUT_NETLINK<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>return (rtmsg_rtsock(cmd, flags, fib));<br>+#else<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>errno = rtmsg_nl(cmd, flags, fib, so, &rt_metrics);<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>return (errno == 0 ? 0 : -1);<br>+#endif<br>+}<br>+<br>+#ifdef WITHOUT_NETLINK<br>+static int<br>+rtmsg_rtsock(int cmd, int flags, int fib)<br>+{<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>int rlen;<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>char *cp = m_rtmsg.m_space;<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>int l;<br>+<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>memset(&m_rtmsg, 0, sizeof(m_rtmsg));<br>+<br>+#define NEXTADDR(w, u)<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>\<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>if (rtm_addrs & (w)) {<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>\<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>l = SA_SIZE(&(u));<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>\<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>memmove(cp, (char *)&(u), l);<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>\<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>cp += l;<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>\<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>if (verbose)<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>\<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>sodump((struct sockaddr *)&(u), #w);<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>\<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>}<br>+<br>#define rtm m_rtmsg.m_rtm<br><span class="Apple-tab-span" style="white-space: pre;"> </span>rtm.rtm_type = cmd;<br><span class="Apple-tab-span" style="white-space: pre;"> </span>rtm.rtm_flags = flags;<br>@@ -1545,6 +1605,7 @@ rtmsg(int cmd, int flags, int fib)<br>#undef rtm<br><span class="Apple-tab-span" style="white-space: pre;"> </span>return (0);<br>}<br>+#endif<br><br>static const char *const msgtypes[] = {<br><span class="Apple-tab-span" style="white-space: pre;"> </span>"",<br>@@ -1571,7 +1632,7 @@ static const char *const msgtypes[] = {<br>static const char metricnames[] =<br> "\011weight\010rttvar\7rtt\6ssthresh\5sendpipe\4recvpipe\3expire"<br> "\1mtu";<br>-static const char routeflags[] =<br>+const char routeflags[] =<br> "\1UP\2GATEWAY\3HOST\4REJECT\5DYNAMIC\6MODIFIED\7DONE"<br> "\012XRESOLVE\013LLINFO\014STATIC\015BLACKHOLE"<br> "\017PROTO2\020PROTO1\021PRCLONING\022WASCLONED\023PROTO3"<br>@@ -1812,7 +1873,7 @@ pmsg_addrs(char *cp, int addrs, size_t len)<br><span class="Apple-tab-span" style="white-space: pre;"> </span>(void)fflush(stdout);<br>}<br><br>-static void<br>+void<br>printb(int b, const char *str)<br>{<br><span class="Apple-tab-span" style="white-space: pre;"> </span>int i;<br>diff --git a/sbin/route/route_netlink.c b/sbin/route/route_netlink.c<br>new file mode 100644<br>index 000000000000..648d866670fc<br>--- /dev/null<br>+++ b/sbin/route/route_netlink.c<br>@@ -0,0 +1,835 @@<br>+#include <stdio.h><br>+#include <stdlib.h><br>+#include <string.h><br>+#include <err.h><br>+#include <errno.h><br>+<br>+#include <sys/bitcount.h><br>+#include <sys/param.h><br>+#include <sys/socket.h><br>+#include <sys/sysctl.h><br>+#include <sys/time.h><br>+#include <sys/types.h><br>+<br>+#include <netinet/in.h><br>+#include <arpa/inet.h><br>+<br>+#include <net/ethernet.h><br>+#include <net/if.h><br>+#include <net/if_dl.h><br>+#include <net/if_types.h><br>+#include <netlink/netlink.h><br>+#include <netlink/netlink_route.h><br>+#include <netlink/netlink_snl.h><br>+#include <netlink/netlink_snl_route.h><br>+#include <netlink/netlink_snl_route_compat.h><br>+#include <netlink/netlink_snl_route_parsers.h><br>+<br>+const char *routename(struct sockaddr *);<br>+const char *netname(struct sockaddr *);<br>+void printb(int, const char *);<br>+extern const char routeflags[];<br>+extern int verbose, debugonly;<br>+<br>+int rtmsg_nl(int cmd, int rtm_flags, int fib, struct sockaddr_storage *so,<br>+ struct rt_metrics *rt_metrics);<br>+int flushroutes_fib_nl(int fib, int af);<br>+void monitor_nl(int fib);<br>+<br>+struct nl_helper;<br>+static void print_getmsg(struct nl_helper *h, struct nlmsghdr *hdr, struct sockaddr *dst);<br>+static void print_nlmsg(struct nl_helper *h, struct nlmsghdr *hdr);<br>+<br>+#define s6_addr32 __u6_addr.__u6_addr32<br>+#define<span class="Apple-tab-span" style="white-space: pre;"> </span>bitcount32(x)<span class="Apple-tab-span" style="white-space: pre;"> </span>__bitcount32((uint32_t)(x))<br>+static int<br>+inet6_get_plen(const struct in6_addr *addr)<br>+{<br>+<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>return (bitcount32(addr->s6_addr32[0]) + bitcount32(addr->s6_addr32[1]) +<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-converted-space"> </span> bitcount32(addr->s6_addr32[2]) + bitcount32(addr->s6_addr32[3]));<br>+}<br>+<br>+static void<br>+ip6_writemask(struct in6_addr *addr6, uint8_t mask)<br>+{<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>uint32_t *cp;<br>+<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>for (cp = (uint32_t *)addr6; mask >= 32; mask -= 32)<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>*cp++ = 0xFFFFFFFF;<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>if (mask > 0)<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>*cp = htonl(mask ? ~((1 << (32 - mask)) - 1) : 0);<br>+}<br>+<br>+static struct sockaddr *<br>+get_netmask(struct snl_state *ss, int family, int plen)<br>+{<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>if (family == AF_INET) {<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>if (plen == 32)<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>return (NULL);<br>+<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>struct sockaddr_in *sin = snl_allocz(ss, sizeof(*sin));<br>+<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>sin->sin_len = sizeof(*sin);<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>sin->sin_family = family;<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>sin->sin_addr.s_addr = htonl(plen ? ~((1 << (32 - plen)) - 1) : 0);<br>+<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>return (struct sockaddr *)sin;<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>} else if (family == AF_INET6) {<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>if (plen == 128)<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>return (NULL);<br>+<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>struct sockaddr_in6 *sin6 = snl_allocz(ss, sizeof(*sin6));<br>+<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>sin6->sin6_len = sizeof(*sin6);<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>sin6->sin6_family = family;<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>ip6_writemask(&sin6->sin6_addr, plen);<br>+<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>return (struct sockaddr *)sin6;<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>}<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>return (NULL);<br>+}<br>+<br>+struct nl_helper {<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>struct snl_state ss_cmd;<br>+};<br>+<br>+static void<br>+nl_helper_init(struct nl_helper *h)<br>+{<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>if (!snl_init(&h->ss_cmd, NETLINK_ROUTE))<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>err(1, "unable to open netlink socket");<br>+}<br>+<br>+static void<br>+nl_helper_free(struct nl_helper *h)<br>+{<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>snl_free(&h->ss_cmd);<br>+}<br>+<br>+static int<br>+rtmsg_nl_int(struct nl_helper *h, int cmd, int rtm_flags, int fib,<br>+ struct sockaddr_storage *so, struct rt_metrics *rt_metrics)<br>+{<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>struct snl_state *ss = &h->ss_cmd;<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>struct snl_writer nw;<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>int nl_type = 0, nl_flags = 0;<br>+<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>snl_init_writer(ss, &nw);<br>+<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>switch (cmd) {<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>case RTSOCK_RTM_ADD:<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>nl_type = RTM_NEWROUTE;<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>nl_flags = NLM_F_CREATE | NLM_F_APPEND; /* Do append by default */<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>break;<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>case RTSOCK_RTM_CHANGE:<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>nl_type = RTM_NEWROUTE;<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>nl_flags = NLM_F_REPLACE;<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>break;<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>case RTSOCK_RTM_DELETE:<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>nl_type = RTM_DELROUTE;<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>break;<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>case RTSOCK_RTM_GET:<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>nl_type = RTM_GETROUTE;<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>break;<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>default:<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>exit(1);<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>}<br>+<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>struct sockaddr *dst = (struct sockaddr *)&so[RTAX_DST];<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>struct sockaddr *mask = (struct sockaddr *)&so[RTAX_NETMASK];<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>struct sockaddr *gw = (struct sockaddr *)&so[RTAX_GATEWAY];<br>+<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>if (dst == NULL)<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>return (EINVAL);<br>+<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>struct nlmsghdr *hdr = snl_create_msg_request(&nw, nl_type);<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>hdr->nlmsg_flags |= nl_flags;<br>+<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>int plen = 0;<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>int rtm_type = RTN_UNICAST;<br>+<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>switch (dst->sa_family) {<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>case AF_INET:<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-converted-space"> </span> {<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>struct sockaddr_in *mask4 = (struct sockaddr_in *)mask;<br>+<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>plen = mask4 ? bitcount32(mask4->sin_addr.s_addr) : 32;<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>break;<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-converted-space"> </span> }<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>case AF_INET6:<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-converted-space"> </span> {<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>struct sockaddr_in6 *mask6 = (struct sockaddr_in6 *)mask;<br>+<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>plen = mask6 ? inet6_get_plen(&mask6->sin6_addr) : 128;<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>break;<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-converted-space"> </span> }<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>default:<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>return (ENOTSUP);<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>}<br>+<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>if (rtm_flags & RTF_REJECT)<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>rtm_type = RTN_PROHIBIT;<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>else if (rtm_flags & RTF_BLACKHOLE)<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>rtm_type = RTN_BLACKHOLE;<br>+<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>struct rtmsg *rtm = snl_reserve_msg_object(&nw, struct rtmsg);<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>rtm->rtm_family = dst->sa_family;<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>rtm->rtm_protocol = RTPROT_STATIC;<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>rtm->rtm_type = rtm_type;<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>rtm->rtm_dst_len = plen;<br>+<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>snl_add_msg_attr_ip(&nw, RTA_DST, dst);<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>snl_add_msg_attr_u32(&nw, RTA_TABLE, fib);<br>+<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>if (rtm_flags & RTF_GATEWAY) {<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>if (gw->sa_family == dst->sa_family)<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>snl_add_msg_attr_ip(&nw, RTA_GATEWAY, gw);<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>else<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>snl_add_msg_attr_ipvia(&nw, RTA_VIA, gw);<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>} else if (gw != NULL) {<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>/* Should be AF_LINK */<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>struct sockaddr_dl *sdl = (struct sockaddr_dl *)gw;<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>if (sdl->sdl_index != 0)<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>snl_add_msg_attr_u32(&nw, RTA_OIF, sdl->sdl_index);<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>}<br>+<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>if (rtm_flags != 0)<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>snl_add_msg_attr_u32(&nw, NL_RTA_RTFLAGS, rtm_flags);<br>+<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>if (rt_metrics->rmx_mtu > 0) {<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>int off = snl_add_msg_attr_nested(&nw, RTA_METRICS);<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>snl_add_msg_attr_u32(&nw, RTAX_MTU, rt_metrics->rmx_mtu);<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>snl_end_attr_nested(&nw, off);<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>}<br>+<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>if (rt_metrics->rmx_weight > 0)<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>snl_add_msg_attr_u32(&nw, NL_RTA_WEIGHT, rt_metrics->rmx_weight);<br>+<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>if (snl_finalize_msg(&nw) && snl_send_message(ss, hdr)) {<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>struct snl_errmsg_data e = {};<br>+<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>hdr = snl_read_reply(ss, hdr->nlmsg_seq);<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>if (nl_type == NL_RTM_GETROUTE) {<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>if (hdr->nlmsg_type == NL_RTM_NEWROUTE)<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>print_getmsg(h, hdr, dst);<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>else {<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>snl_parse_errmsg(ss, hdr, &e);<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>if (e.error == ESRCH)<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>warn("route has not been found");<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>else<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>warn("message indicates error %d", e.error);<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>}<br>+<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>return (0);<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>}<br>+<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>if (snl_parse_errmsg(ss, hdr, &e))<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>return (e.error);<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>}<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>return (EINVAL);<br>+}<br>+<br>+int<br>+rtmsg_nl(int cmd, int rtm_flags, int fib, struct sockaddr_storage *so,<br>+ struct rt_metrics *rt_metrics)<br>+{<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>struct nl_helper h = {};<br>+<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>nl_helper_init(&h);<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>int error = rtmsg_nl_int(&h, cmd, rtm_flags, fib, so, rt_metrics);<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>nl_helper_free(&h);<br>+<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>return (error);<br>+}<br>+<br>+static void<br>+get_ifdata(struct nl_helper *h, uint32_t ifindex, struct snl_parsed_link_simple *link)<br>+{<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>struct snl_state *ss = &h->ss_cmd;<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>struct snl_writer nw;<br>+<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>snl_init_writer(ss, &nw);<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>struct nlmsghdr *hdr = snl_create_msg_request(&nw, NL_RTM_GETLINK);<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>struct ifinfomsg *ifmsg = snl_reserve_msg_object(&nw, struct ifinfomsg);<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>if (ifmsg != NULL)<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>ifmsg->ifi_index = ifindex;<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>if (!snl_finalize_msg(&nw) || !snl_send_message(ss, hdr))<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>return;<br>+<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>hdr = snl_read_reply(ss, hdr->nlmsg_seq);<br>+<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>if (hdr != NULL && hdr->nlmsg_type == RTM_NEWLINK) {<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>snl_parse_nlmsg(ss, hdr, &snl_rtm_link_parser_simple, link);<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>}<br>+<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>if (link->ifla_ifname == NULL) {<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>char ifname[16];<br>+<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>snprintf(ifname, sizeof(ifname), "if#%u", ifindex);<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>int len = strlen(ifname);<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>char *buf = snl_allocz(ss, len + 1);<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>strlcpy(buf, ifname, len + 1);<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>link->ifla_ifname = buf;<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>}<br>+}<br>+<br>+static void<br>+print_getmsg(struct nl_helper *h, struct nlmsghdr *hdr, struct sockaddr *dst)<br>+{<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>struct snl_state *ss = &h->ss_cmd;<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>struct timespec ts;<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>struct snl_parsed_route r = { .rtax_weight = RT_DEFAULT_WEIGHT };<br>+<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>if (!snl_parse_nlmsg(ss, hdr, &snl_rtm_route_parser, &r))<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>return;<br>+<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>struct snl_parsed_link_simple link = {};<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>get_ifdata(h, r.rta_oif, &link);<br>+<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>if (r.rtax_mtu == 0)<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>r.rtax_mtu = link.ifla_mtu;<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>r.rta_rtflags |= (RTF_UP | RTF_DONE);<br>+<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>(void)printf(" route to: %s\n", routename(dst));<br>+<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>if (r.rta_dst)<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>(void)printf("destination: %s\n", routename(r.rta_dst));<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>struct sockaddr *mask = get_netmask(ss, r.rtm_family, r.rtm_dst_len);<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>if (mask)<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>(void)printf(" mask: %s\n", routename(mask));<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>if (r.rta_gw && (r.rta_rtflags & RTF_GATEWAY))<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>(void)printf(" gateway: %s\n", routename(r.rta_gw));<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>(void)printf(" fib: %u\n", (unsigned int)r.rta_table);<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>if (link.ifla_ifname)<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>(void)printf(" interface: %s\n", link.ifla_ifname);<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>(void)printf(" flags: ");<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>printb(r.rta_rtflags, routeflags);<br>+<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>struct rt_metrics rmx = {<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>.rmx_mtu = r.rtax_mtu,<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>.rmx_weight = r.rtax_weight,<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>.rmx_expire = r.rta_expire,<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>};<br>+<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>printf("\n%9s %9s %9s %9s %9s %10s %9s\n", "recvpipe",<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-converted-space"> </span> "sendpipe", "ssthresh", "rtt,msec", "mtu ", "weight", "expire");<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>printf("%8lu ", rmx.rmx_recvpipe);<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>printf("%8lu ", rmx.rmx_sendpipe);<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>printf("%8lu ", rmx.rmx_ssthresh);<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>printf("%8lu ", 0UL);<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>printf("%8lu ", rmx.rmx_mtu);<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>printf("%8lu ", rmx.rmx_weight);<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>if (rmx.rmx_expire > 0)<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>clock_gettime(CLOCK_REALTIME_FAST, &ts);<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>else<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>ts.tv_sec = 0;<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>printf("%8ld \n", (long)(rmx.rmx_expire - ts.tv_sec));<br>+}<br>+<br>+static void<br>+print_prefix(struct nl_helper *h, char *buf, int bufsize, struct sockaddr *sa, int plen)<br>+{<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>int sz = 0;<br>+<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>if (sa == NULL) {<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>snprintf(buf, bufsize, "<NULL>");<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>return;<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>}<br>+<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>switch (sa->sa_family) {<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>case AF_INET:<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>{<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>struct sockaddr_in *sin = (struct sockaddr_in *)sa;<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>char abuf[INET_ADDRSTRLEN];<br>+<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>inet_ntop(AF_INET, &sin->sin_addr, abuf, sizeof(abuf));<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>sz = snprintf(buf, bufsize, "%s", abuf);<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>break;<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>}<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>case AF_INET6:<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>{<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa;<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>char abuf[INET6_ADDRSTRLEN];<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>char *ifname = NULL;<br>+<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>inet_ntop(AF_INET6, &sin6->sin6_addr, abuf, sizeof(abuf));<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) {<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>struct snl_parsed_link_simple link = {};<br>+<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>if (sin6->sin6_scope_id != 0) {<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>get_ifdata(h, sin6->sin6_scope_id, &link);<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>ifname = link.ifla_ifname;<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>}<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>}<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>if (ifname == NULL)<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>sz = snprintf(buf, bufsize, "%s", abuf);<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>else<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>sz = snprintf(buf, bufsize, "%s%%%s", abuf, ifname);<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>break;<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>}<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>default:<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>snprintf(buf, bufsize, "unknown_af#%d", sa->sa_family);<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>plen = -1;<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>}<br>+<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>if (plen >= 0)<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>snprintf(buf + sz, bufsize - sz, "/%d", plen);<br>+}<br>+<br>+<br>+static int<br>+print_line_prefix(const char *cmd, const char *name)<br>+{<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>struct timespec tp;<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>struct tm tm;<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>char buf[32];<br>+<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>clock_gettime(CLOCK_REALTIME, &tp);<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>localtime_r(&tp.tv_sec, &tm);<br>+<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>strftime(buf, sizeof(buf), "%T", &tm);<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>int len = printf("%s.%03ld %s %s ", buf, tp.tv_nsec / 1000000, cmd, name);<br>+<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>return (len);<br>+}<br>+<br>+static const char *<br>+get_action_name(struct nlmsghdr *hdr, int new_cmd)<br>+{<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>if (hdr->nlmsg_type == new_cmd) {<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>//return ((hdr->nlmsg_flags & NLM_F_REPLACE) ? "replace" : "add");<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>return ("add/repl");<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>} else<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>return ("delete");<br>+}<br>+<br>+static void<br>+print_nlmsg_route_nhop(struct nl_helper *h, struct snl_parsed_route *r,<br>+ struct rta_mpath_nh *nh, bool first)<br>+{<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>// gw 10.0.0.1 ifp vtnet0 mtu 1500 table inet.0<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>if (nh->gw != NULL) {<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>char gwbuf[128];<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>print_prefix(h, gwbuf, sizeof(gwbuf), nh->gw, -1);<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>printf("gw %s ", gwbuf);<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>}<br>+<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>if (nh->ifindex != 0) {<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>struct snl_parsed_link_simple link = {};<br>+<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>get_ifdata(h, nh->ifindex, &link);<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>if (nh->rtax_mtu == 0)<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>nh->rtax_mtu = link.ifla_mtu;<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>printf("iface %s ", link.ifla_ifname);<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>if (nh->rtax_mtu != 0)<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>printf("mtu %d ", nh->rtax_mtu);<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>}<br>+<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>if (first) {<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>switch (r->rtm_family) {<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>case AF_INET:<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>printf("table inet.%d", r->rta_table);<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>break;<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>case AF_INET6:<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>printf("table inet6.%d", r->rta_table);<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>break;<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>}<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>}<br>+<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>printf("\n");<br>+}<br>+<br>+static void<br>+print_nlmsg_route(struct nl_helper *h, struct nlmsghdr *hdr)<br>+{<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>struct snl_parsed_route r = { .rtax_weight = RT_DEFAULT_WEIGHT };<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>struct snl_state *ss = &h->ss_cmd;<br>+<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>if (!snl_parse_nlmsg(ss, hdr, &snl_rtm_route_parser, &r))<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>return;<br>+<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>// 20:19:41.333 add route 10.0.0.0/24 gw 10.0.0.1 ifp vtnet0 mtu 1500 table inet.0<br>+<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>const char *cmd = get_action_name(hdr, RTM_NEWROUTE);<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>int len = print_line_prefix(cmd, "route");<br>+<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>char buf[128];<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>print_prefix(h, buf, sizeof(buf), r.rta_dst, r.rtm_dst_len);<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>len += strlen(buf) + 1;<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>printf("%s ", buf);<br>+<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>switch (r.rtm_type) {<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>case RTN_BLACKHOLE:<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>printf("blackhole\n");<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>return;<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>case RTN_UNREACHABLE:<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>printf("unreach(reject)\n");<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>return;<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>case RTN_PROHIBIT:<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>printf("prohibit(reject)\n");<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>return;<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>}<br>+<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>if (r.rta_multipath != NULL) {<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>bool first = true;<br>+<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>memset(buf, ' ', sizeof(buf));<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>buf[len] = '\0';<br>+<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>for (int i = 0; i < r.rta_multipath->num_nhops; i++) {<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>struct rta_mpath_nh *nh = &r.rta_multipath->nhops[i];<br>+<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>if (!first)<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>printf("%s", buf);<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>print_nlmsg_route_nhop(h, &r, nh, first);<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>first = false;<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>}<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>} else {<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>struct rta_mpath_nh nh = {<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>.gw = r.rta_gw,<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>.ifindex = r.rta_oif,<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>.rtax_mtu = r.rtax_mtu,<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>};<br>+<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>print_nlmsg_route_nhop(h, &r, &nh, true);<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>}<br>+}<br>+<br>+static const char *operstate[] = {<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>"UNKNOWN",<span class="Apple-tab-span" style="white-space: pre;"> </span>/* 0, IF_OPER_UNKNOWN */<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>"NOTPRESENT",<span class="Apple-tab-span" style="white-space: pre;"> </span>/* 1, IF_OPER_NOTPRESENT */<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>"DOWN",<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>/* 2, IF_OPER_DOWN */<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>"LLDOWN",<span class="Apple-tab-span" style="white-space: pre;"> </span>/* 3, IF_OPER_LOWERLAYERDOWN */<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>"TESTING",<span class="Apple-tab-span" style="white-space: pre;"> </span>/* 4, IF_OPER_TESTING */<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>"DORMANT",<span class="Apple-tab-span" style="white-space: pre;"> </span>/* 5, IF_OPER_DORMANT */<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>"UP",<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>/* 6, IF_OPER_UP */<br>+};<br>+<br>+static void<br>+print_nlmsg_link(struct nl_helper *h, struct nlmsghdr *hdr)<br>+{<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>struct snl_parsed_link l = {};<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>struct snl_state *ss = &h->ss_cmd;<br>+<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>if (!snl_parse_nlmsg(ss, hdr, &snl_rtm_link_parser, &l))<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>return;<br>+<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>// 20:19:41.333 add iface#3 vtnet0 admin UP oper UP mtu 1500 table inet.0<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>const char *cmd = get_action_name(hdr, RTM_NEWLINK);<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>print_line_prefix(cmd, "iface");<br>+<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>printf("iface#%u %s ", l.ifi_index, l.ifla_ifname);<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>printf("admin %s ", (l.ifi_flags & IFF_UP) ? "UP" : "DOWN");<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>if (l.ifla_operstate < NL_ARRAY_LEN(operstate))<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>printf("oper %s ", operstate[l.ifla_operstate]);<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>if (l.ifla_mtu > 0)<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>printf("mtu %u ", l.ifla_mtu);<br>+<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>printf("\n");<br>+}<br>+<br>+static void<br>+print_nlmsg_addr(struct nl_helper *h, struct nlmsghdr *hdr)<br>+{<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>struct snl_parsed_addr attrs = {};<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>struct snl_state *ss = &h->ss_cmd;<br>+<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>if (!snl_parse_nlmsg(ss, hdr, &snl_rtm_addr_parser, &attrs))<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>return;<br>+<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>// add addr 192.168.1.1/24 iface vtnet0<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>const char *cmd = get_action_name(hdr, RTM_NEWADDR);<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>print_line_prefix(cmd, "addr");<br>+<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>char buf[128];<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>struct sockaddr *addr = attrs.ifa_local ? attrs.ifa_local : attrs.ifa_address;<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>print_prefix(h, buf, sizeof(buf), addr, attrs.ifa_prefixlen);<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>printf("%s ", buf);<br>+<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>struct snl_parsed_link_simple link = {};<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>get_ifdata(h, attrs.ifa_index, &link);<br>+<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>if (link.ifi_flags & IFF_POINTOPOINT) {<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>char buf[64];<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>print_prefix(h, buf, sizeof(buf), attrs.ifa_address, -1);<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>printf("-> %s ", buf);<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>}<br>+<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>printf("iface %s ", link.ifla_ifname);<br>+<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>printf("\n");<br>+}<br>+<br>+static const char *nudstate[] = {<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>"INCOMPLETE",<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>/* 0x01(0) */<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>"REACHABLE",<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>/* 0x02(1) */<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>"STALE",<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>/* 0x04(2) */<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>"DELAY",<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>/* 0x08(3) */<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>"PROBE",<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>/* 0x10(4) */<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>"FAILED",<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>/* 0x20(5) */<br>+};<br>+<br>+#define<span class="Apple-tab-span" style="white-space: pre;"> </span>NUD_INCOMPLETE<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>0x01<span class="Apple-tab-span" style="white-space: pre;"> </span>/* No lladdr, address resolution in progress */<br>+#define<span class="Apple-tab-span" style="white-space: pre;"> </span>NUD_REACHABLE<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>0x02<span class="Apple-tab-span" style="white-space: pre;"> </span>/* reachable & recently resolved */<br>+#define<span class="Apple-tab-span" style="white-space: pre;"> </span>NUD_STALE<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>0x04<span class="Apple-tab-span" style="white-space: pre;"> </span>/* has lladdr but it's stale */<br>+#define<span class="Apple-tab-span" style="white-space: pre;"> </span>NUD_DELAY<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>0x08<span class="Apple-tab-span" style="white-space: pre;"> </span>/* has lladdr, is stale, probes delayed */<br>+#define<span class="Apple-tab-span" style="white-space: pre;"> </span>NUD_PROBE<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>0x10<span class="Apple-tab-span" style="white-space: pre;"> </span>/* has lladdr, is stale, probes sent */<br>+#define<span class="Apple-tab-span" style="white-space: pre;"> </span>NUD_FAILED<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>0x20<span class="Apple-tab-span" style="white-space: pre;"> </span>/* unused */<br>+<br>+<br>+static void<br>+print_nlmsg_neigh(struct nl_helper *h, struct nlmsghdr *hdr)<br>+{<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>struct snl_parsed_neigh attrs = {};<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>struct snl_state *ss = &h->ss_cmd;<br>+<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>if (!snl_parse_nlmsg(ss, hdr, &snl_rtm_neigh_parser, &attrs))<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>return;<br>+<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>// add addr 192.168.1.1 state %s lladdr %s iface vtnet0<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>const char *cmd = get_action_name(hdr, RTM_NEWNEIGH);<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>print_line_prefix(cmd, "neigh");<br>+<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>char buf[128];<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>print_prefix(h, buf, sizeof(buf), attrs.nda_dst, -1);<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>printf("%s ", buf);<br>+<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>struct snl_parsed_link_simple link = {};<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>get_ifdata(h, attrs.nda_ifindex, &link);<br>+<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>for (unsigned int i = 0; i < NL_ARRAY_LEN(nudstate); i++) {<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>if ((1 << i) & attrs.ndm_state) {<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>printf("state %s ", nudstate[i]);<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>break;<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>}<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>}<br>+<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>if (attrs.nda_lladdr != NULL) {<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>int if_type = link.ifi_type;<br>+<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>if ((if_type == IFT_ETHER || if_type == IFT_L2VLAN || if_type == IFT_BRIDGE) &&<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-converted-space"> </span> NLA_DATA_LEN(attrs.nda_lladdr) == ETHER_ADDR_LEN) {<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>struct ether_addr *ll;<br>+<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>ll = (struct ether_addr *)NLA_DATA(attrs.nda_lladdr);<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>printf("lladdr %s ", ether_ntoa(ll));<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>} else {<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>struct sockaddr_dl sdl = {<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>.sdl_len = sizeof(sdl),<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>.sdl_family = AF_LINK,<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>.sdl_index = attrs.nda_ifindex,<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>.sdl_type = if_type,<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>.sdl_alen = NLA_DATA_LEN(attrs.nda_lladdr),<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>};<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>if (sdl.sdl_alen < sizeof(sdl.sdl_data)) {<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>void *ll = NLA_DATA(attrs.nda_lladdr);<br>+<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>memcpy(sdl.sdl_data, ll, sdl.sdl_alen);<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>printf("lladdr %s ", link_ntoa(&sdl));<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>}<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>}<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>}<br>+<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>if (link.ifla_ifname != NULL)<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>printf("iface %s ", link.ifla_ifname);<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>printf("\n");<br>+}<br>+<br>+static void<br>+print_nlmsg_generic(struct nl_helper *h, struct nlmsghdr *hdr)<br>+{<br>+}<br>+<br>+static void<br>+print_nlmsg(struct nl_helper *h, struct nlmsghdr *hdr)<br>+{<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>switch (hdr->nlmsg_type) {<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>case RTM_NEWLINK:<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span>case RTM_DELLINK:<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>print_nlmsg_link(h, hdr);<br>+<span class="Apple-tab-span" style="white-space: pre;"> </span><span class="Apple-tab-span" style="white-space: pre;"> </span>break;<br>*** 184 LINES SKIPPED ***</blockquote></div></blockquote></div><br></body></html>
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?F0DD3830-654C-49F1-B6D6-C17171A30553>
