168636dcbSAlexander V. Chernikov /*- 268636dcbSAlexander V. Chernikov * SPDX-License-Identifier: BSD-3-Clause 368636dcbSAlexander V. Chernikov * 468636dcbSAlexander V. Chernikov * Copyright (c) 1983, 1988, 1993 568636dcbSAlexander V. Chernikov * The Regents of the University of California. All rights reserved. 668636dcbSAlexander V. Chernikov * 768636dcbSAlexander V. Chernikov * Redistribution and use in source and binary forms, with or without 868636dcbSAlexander V. Chernikov * modification, are permitted provided that the following conditions 968636dcbSAlexander V. Chernikov * are met: 1068636dcbSAlexander V. Chernikov * 1. Redistributions of source code must retain the above copyright 1168636dcbSAlexander V. Chernikov * notice, this list of conditions and the following disclaimer. 1268636dcbSAlexander V. Chernikov * 2. Redistributions in binary form must reproduce the above copyright 1368636dcbSAlexander V. Chernikov * notice, this list of conditions and the following disclaimer in the 1468636dcbSAlexander V. Chernikov * documentation and/or other materials provided with the distribution. 1568636dcbSAlexander V. Chernikov * 3. Neither the name of the University nor the names of its contributors 1668636dcbSAlexander V. Chernikov * may be used to endorse or promote products derived from this software 1768636dcbSAlexander V. Chernikov * without specific prior written permission. 1868636dcbSAlexander V. Chernikov * 1968636dcbSAlexander V. Chernikov * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2068636dcbSAlexander V. Chernikov * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2168636dcbSAlexander V. Chernikov * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2268636dcbSAlexander V. Chernikov * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2368636dcbSAlexander V. Chernikov * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2468636dcbSAlexander V. Chernikov * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2568636dcbSAlexander V. Chernikov * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2668636dcbSAlexander V. Chernikov * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2768636dcbSAlexander V. Chernikov * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2868636dcbSAlexander V. Chernikov * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2968636dcbSAlexander V. Chernikov * SUCH DAMAGE. 3068636dcbSAlexander V. Chernikov */ 3168636dcbSAlexander V. Chernikov 3268636dcbSAlexander V. Chernikov #include <sys/cdefs.h> 3368636dcbSAlexander V. Chernikov __FBSDID("$FreeBSD$"); 3468636dcbSAlexander V. Chernikov 3568636dcbSAlexander V. Chernikov #include <sys/param.h> 3668636dcbSAlexander V. Chernikov #include <sys/protosw.h> 3768636dcbSAlexander V. Chernikov #include <sys/socket.h> 3868636dcbSAlexander V. Chernikov #include <sys/socketvar.h> 3968636dcbSAlexander V. Chernikov #include <sys/sysctl.h> 4068636dcbSAlexander V. Chernikov #include <sys/time.h> 4168636dcbSAlexander V. Chernikov 4268636dcbSAlexander V. Chernikov #include <net/ethernet.h> 4368636dcbSAlexander V. Chernikov #include <net/if.h> 4468636dcbSAlexander V. Chernikov #include <net/if_dl.h> 4568636dcbSAlexander V. Chernikov #include <net/if_types.h> 4668636dcbSAlexander V. Chernikov #include <netlink/netlink.h> 4768636dcbSAlexander V. Chernikov #include <netlink/netlink_route.h> 4868636dcbSAlexander V. Chernikov #include <netlink/netlink_snl.h> 4968636dcbSAlexander V. Chernikov #include <netlink/netlink_snl_route.h> 50*aee2f11bSAlexander V. Chernikov #include <netlink/netlink_snl_route_parsers.h> 51*aee2f11bSAlexander V. Chernikov #include <netlink/netlink_snl_route_compat.h> 5268636dcbSAlexander V. Chernikov 5368636dcbSAlexander V. Chernikov #include <netinet/in.h> 5468636dcbSAlexander V. Chernikov #include <netgraph/ng_socket.h> 5568636dcbSAlexander V. Chernikov 5668636dcbSAlexander V. Chernikov #include <arpa/inet.h> 5768636dcbSAlexander V. Chernikov #include <ifaddrs.h> 5868636dcbSAlexander V. Chernikov #include <libutil.h> 5968636dcbSAlexander V. Chernikov #include <netdb.h> 6068636dcbSAlexander V. Chernikov #include <stdbool.h> 6168636dcbSAlexander V. Chernikov #include <stdint.h> 6268636dcbSAlexander V. Chernikov #include <stdio.h> 6368636dcbSAlexander V. Chernikov #include <stdlib.h> 6468636dcbSAlexander V. Chernikov #include <stdbool.h> 6568636dcbSAlexander V. Chernikov #include <string.h> 6668636dcbSAlexander V. Chernikov #include <sysexits.h> 6768636dcbSAlexander V. Chernikov #include <unistd.h> 6868636dcbSAlexander V. Chernikov #include <err.h> 6968636dcbSAlexander V. Chernikov #include <libxo/xo.h> 7068636dcbSAlexander V. Chernikov #include "netstat.h" 7168636dcbSAlexander V. Chernikov #include "common.h" 7268636dcbSAlexander V. Chernikov #include "nl_defs.h" 7368636dcbSAlexander V. Chernikov 7468636dcbSAlexander V. Chernikov 7568636dcbSAlexander V. Chernikov static void p_rtentry_netlink(struct snl_state *ss, const char *name, struct nlmsghdr *hdr); 7668636dcbSAlexander V. Chernikov 7768636dcbSAlexander V. Chernikov static struct ifmap_entry *ifmap; 7868636dcbSAlexander V. Chernikov static size_t ifmap_size; 7968636dcbSAlexander V. Chernikov 8068636dcbSAlexander V. Chernikov /* Generate ifmap using netlink */ 8168636dcbSAlexander V. Chernikov static struct ifmap_entry * 8268636dcbSAlexander V. Chernikov prepare_ifmap_netlink(struct snl_state *ss, size_t *pifmap_size) 8368636dcbSAlexander V. Chernikov { 8468636dcbSAlexander V. Chernikov struct { 8568636dcbSAlexander V. Chernikov struct nlmsghdr hdr; 8668636dcbSAlexander V. Chernikov struct ifinfomsg ifmsg; 8768636dcbSAlexander V. Chernikov } msg = { 8868636dcbSAlexander V. Chernikov .hdr.nlmsg_type = RTM_GETLINK, 8968636dcbSAlexander V. Chernikov .hdr.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST, 9068636dcbSAlexander V. Chernikov .hdr.nlmsg_seq = snl_get_seq(ss), 9168636dcbSAlexander V. Chernikov }; 9268636dcbSAlexander V. Chernikov msg.hdr.nlmsg_len = sizeof(msg); 9368636dcbSAlexander V. Chernikov 94*aee2f11bSAlexander V. Chernikov if (!snl_send_message(ss, &msg.hdr)) { 9568636dcbSAlexander V. Chernikov snl_free(ss); 9668636dcbSAlexander V. Chernikov return (NULL); 9768636dcbSAlexander V. Chernikov } 9868636dcbSAlexander V. Chernikov 9968636dcbSAlexander V. Chernikov struct ifmap_entry *ifmap = NULL; 10068636dcbSAlexander V. Chernikov uint32_t ifmap_size = 0; 10168636dcbSAlexander V. Chernikov struct nlmsghdr *hdr; 102*aee2f11bSAlexander V. Chernikov struct snl_errmsg_data e = {}; 103*aee2f11bSAlexander V. Chernikov 104*aee2f11bSAlexander V. Chernikov while ((hdr = snl_read_reply_multi(ss, msg.hdr.nlmsg_seq, &e)) != NULL) { 105*aee2f11bSAlexander V. Chernikov struct snl_parsed_link_simple link = {}; 106*aee2f11bSAlexander V. Chernikov 107*aee2f11bSAlexander V. Chernikov if (!snl_parse_nlmsg(ss, hdr, &snl_rtm_link_parser_simple, &link)) 10868636dcbSAlexander V. Chernikov continue; 10968636dcbSAlexander V. Chernikov if (link.ifi_index >= ifmap_size) { 11068636dcbSAlexander V. Chernikov size_t size = roundup2(link.ifi_index + 1, 32) * sizeof(struct ifmap_entry); 11168636dcbSAlexander V. Chernikov if ((ifmap = realloc(ifmap, size)) == NULL) 11279111aa2SAlexander V. Chernikov errx(2, "realloc(%zu) failed", size); 11368636dcbSAlexander V. Chernikov memset(&ifmap[ifmap_size], 0, 11468636dcbSAlexander V. Chernikov size - ifmap_size * 11568636dcbSAlexander V. Chernikov sizeof(struct ifmap_entry)); 11668636dcbSAlexander V. Chernikov ifmap_size = roundup2(link.ifi_index + 1, 32); 11768636dcbSAlexander V. Chernikov } 11868636dcbSAlexander V. Chernikov if (*ifmap[link.ifi_index].ifname != '\0') 11968636dcbSAlexander V. Chernikov continue; 12068636dcbSAlexander V. Chernikov strlcpy(ifmap[link.ifi_index].ifname, link.ifla_ifname, IFNAMSIZ); 12168636dcbSAlexander V. Chernikov ifmap[link.ifi_index].mtu = link.ifla_mtu; 12268636dcbSAlexander V. Chernikov } 12368636dcbSAlexander V. Chernikov *pifmap_size = ifmap_size; 12468636dcbSAlexander V. Chernikov return (ifmap); 12568636dcbSAlexander V. Chernikov } 12668636dcbSAlexander V. Chernikov 12768636dcbSAlexander V. Chernikov static void 12868636dcbSAlexander V. Chernikov ip6_writemask(struct in6_addr *addr6, uint8_t mask) 12968636dcbSAlexander V. Chernikov { 13068636dcbSAlexander V. Chernikov uint32_t *cp; 13168636dcbSAlexander V. Chernikov 13268636dcbSAlexander V. Chernikov for (cp = (uint32_t *)addr6; mask >= 32; mask -= 32) 13368636dcbSAlexander V. Chernikov *cp++ = 0xFFFFFFFF; 13468636dcbSAlexander V. Chernikov if (mask > 0) 13568636dcbSAlexander V. Chernikov *cp = htonl(mask ? ~((1 << (32 - mask)) - 1) : 0); 13668636dcbSAlexander V. Chernikov } 13768636dcbSAlexander V. Chernikov 13868636dcbSAlexander V. Chernikov static void 13968636dcbSAlexander V. Chernikov gen_mask(int family, int plen, struct sockaddr *sa) 14068636dcbSAlexander V. Chernikov { 14168636dcbSAlexander V. Chernikov if (family == AF_INET6) { 14268636dcbSAlexander V. Chernikov struct sockaddr_in6 sin6 = { 14368636dcbSAlexander V. Chernikov .sin6_family = AF_INET6, 14468636dcbSAlexander V. Chernikov .sin6_len = sizeof(struct sockaddr_in6), 14568636dcbSAlexander V. Chernikov }; 14668636dcbSAlexander V. Chernikov ip6_writemask(&sin6.sin6_addr, plen); 14768636dcbSAlexander V. Chernikov *((struct sockaddr_in6 *)sa) = sin6; 14868636dcbSAlexander V. Chernikov } else if (family == AF_INET) { 14968636dcbSAlexander V. Chernikov struct sockaddr_in sin = { 15068636dcbSAlexander V. Chernikov .sin_family = AF_INET, 15168636dcbSAlexander V. Chernikov .sin_len = sizeof(struct sockaddr_in), 15268636dcbSAlexander V. Chernikov .sin_addr.s_addr = htonl(plen ? ~((1 << (32 - plen)) - 1) : 0), 15368636dcbSAlexander V. Chernikov }; 15468636dcbSAlexander V. Chernikov *((struct sockaddr_in *)sa) = sin; 15568636dcbSAlexander V. Chernikov } 15668636dcbSAlexander V. Chernikov } 15768636dcbSAlexander V. Chernikov 15868636dcbSAlexander V. Chernikov static void 1596a6f2b0cSAlexander V. Chernikov add_scopeid(struct sockaddr *sa, int ifindex) 1606a6f2b0cSAlexander V. Chernikov { 1616a6f2b0cSAlexander V. Chernikov if (sa->sa_family == AF_INET6) { 1626a6f2b0cSAlexander V. Chernikov struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa; 1636a6f2b0cSAlexander V. Chernikov if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) 1646a6f2b0cSAlexander V. Chernikov sin6->sin6_scope_id = ifindex; 1656a6f2b0cSAlexander V. Chernikov } 1666a6f2b0cSAlexander V. Chernikov } 1676a6f2b0cSAlexander V. Chernikov 1686a6f2b0cSAlexander V. Chernikov static void 169*aee2f11bSAlexander V. Chernikov p_path(struct snl_parsed_route *rt, bool is_mpath) 17068636dcbSAlexander V. Chernikov { 17168636dcbSAlexander V. Chernikov struct sockaddr_in6 mask6; 17268636dcbSAlexander V. Chernikov struct sockaddr *pmask = (struct sockaddr *)&mask6; 17368636dcbSAlexander V. Chernikov char buffer[128]; 17468636dcbSAlexander V. Chernikov char prettyname[128]; 17568636dcbSAlexander V. Chernikov int protrusion; 17668636dcbSAlexander V. Chernikov 17768636dcbSAlexander V. Chernikov gen_mask(rt->rtm_family, rt->rtm_dst_len, pmask); 1786a6f2b0cSAlexander V. Chernikov add_scopeid(rt->rta_dst, rt->rta_oif); 1796a6f2b0cSAlexander V. Chernikov add_scopeid(rt->rta_gw, rt->rta_oif); 18068636dcbSAlexander V. Chernikov protrusion = p_sockaddr("destination", rt->rta_dst, pmask, rt->rta_rtflags, wid.dst); 18168636dcbSAlexander V. Chernikov protrusion = p_sockaddr("gateway", rt->rta_gw, NULL, RTF_HOST, 18268636dcbSAlexander V. Chernikov wid.gw - protrusion); 18368636dcbSAlexander V. Chernikov snprintf(buffer, sizeof(buffer), "{[:-%d}{:flags/%%s}{]:} ", 18468636dcbSAlexander V. Chernikov wid.flags - protrusion); 18568636dcbSAlexander V. Chernikov p_flags(rt->rta_rtflags | RTF_UP, buffer); 18668636dcbSAlexander V. Chernikov /* Output path weight as non-visual property */ 18768636dcbSAlexander V. Chernikov xo_emit("{e:weight/%u}", rt->rtax_weight); 18815dbf5a2SAlexander V. Chernikov if (is_mpath) 18915dbf5a2SAlexander V. Chernikov xo_emit("{e:nhg-kidx/%u}", rt->rta_knh_id); 19015dbf5a2SAlexander V. Chernikov else 19115dbf5a2SAlexander V. Chernikov xo_emit("{e:nhop-kidx/%u}", rt->rta_knh_id); 19215dbf5a2SAlexander V. Chernikov if (rt->rta_nh_id != 0) { 19315dbf5a2SAlexander V. Chernikov if (is_mpath) 19415dbf5a2SAlexander V. Chernikov xo_emit("{e:nhg-uidx/%u}", rt->rta_nh_id); 19515dbf5a2SAlexander V. Chernikov else 19615dbf5a2SAlexander V. Chernikov xo_emit("{e:nhop-uidx/%u}", rt->rta_nh_id); 19715dbf5a2SAlexander V. Chernikov } 19868636dcbSAlexander V. Chernikov 19968636dcbSAlexander V. Chernikov memset(prettyname, 0, sizeof(prettyname)); 20068636dcbSAlexander V. Chernikov if (rt->rta_oif < ifmap_size) { 20168636dcbSAlexander V. Chernikov strlcpy(prettyname, ifmap[rt->rta_oif].ifname, 20268636dcbSAlexander V. Chernikov sizeof(prettyname)); 20368636dcbSAlexander V. Chernikov if (*prettyname == '\0') 20468636dcbSAlexander V. Chernikov strlcpy(prettyname, "---", sizeof(prettyname)); 20568636dcbSAlexander V. Chernikov if (rt->rtax_mtu == 0) 20668636dcbSAlexander V. Chernikov rt->rtax_mtu = ifmap[rt->rta_oif].mtu; 20768636dcbSAlexander V. Chernikov } 20868636dcbSAlexander V. Chernikov 20968636dcbSAlexander V. Chernikov if (Wflag) { 21068636dcbSAlexander V. Chernikov /* XXX: use=0? */ 21115dbf5a2SAlexander V. Chernikov xo_emit("{t:nhop/%*lu} ", wid.mtu, is_mpath ? 0 : rt->rta_knh_id); 21268636dcbSAlexander V. Chernikov 21368636dcbSAlexander V. Chernikov if (rt->rtax_mtu != 0) 21468636dcbSAlexander V. Chernikov xo_emit("{t:mtu/%*lu} ", wid.mtu, rt->rtax_mtu); 21568636dcbSAlexander V. Chernikov else { 21668636dcbSAlexander V. Chernikov /* use interface mtu */ 21768636dcbSAlexander V. Chernikov xo_emit("{P:/%*s} ", wid.mtu, ""); 21868636dcbSAlexander V. Chernikov } 21968636dcbSAlexander V. Chernikov 22068636dcbSAlexander V. Chernikov } 22168636dcbSAlexander V. Chernikov 22268636dcbSAlexander V. Chernikov if (Wflag) 22368636dcbSAlexander V. Chernikov xo_emit("{t:interface-name/%*s}", wid.iface, prettyname); 22468636dcbSAlexander V. Chernikov else 22568636dcbSAlexander V. Chernikov xo_emit("{t:interface-name/%*.*s}", wid.iface, wid.iface, 22668636dcbSAlexander V. Chernikov prettyname); 22768636dcbSAlexander V. Chernikov if (rt->rta_expires > 0) { 22868636dcbSAlexander V. Chernikov xo_emit(" {:expire-time/%*u}", wid.expire, rt->rta_expires); 22968636dcbSAlexander V. Chernikov } 23068636dcbSAlexander V. Chernikov } 23168636dcbSAlexander V. Chernikov 23268636dcbSAlexander V. Chernikov static void 23368636dcbSAlexander V. Chernikov p_rtentry_netlink(struct snl_state *ss, const char *name, struct nlmsghdr *hdr) 23468636dcbSAlexander V. Chernikov { 23568636dcbSAlexander V. Chernikov 236*aee2f11bSAlexander V. Chernikov struct snl_parsed_route rt = {}; 237*aee2f11bSAlexander V. Chernikov if (!snl_parse_nlmsg(ss, hdr, &snl_rtm_route_parser, &rt)) 23868636dcbSAlexander V. Chernikov return; 23915dbf5a2SAlexander V. Chernikov if (rt.rtax_weight == 0) 24015dbf5a2SAlexander V. Chernikov rt.rtax_weight = rt_default_weight; 24168636dcbSAlexander V. Chernikov 24268636dcbSAlexander V. Chernikov if (rt.rta_multipath != NULL) { 24368636dcbSAlexander V. Chernikov uint32_t orig_rtflags = rt.rta_rtflags; 24468636dcbSAlexander V. Chernikov uint32_t orig_mtu = rt.rtax_mtu; 24568636dcbSAlexander V. Chernikov for (int i = 0; i < rt.rta_multipath->num_nhops; i++) { 24668636dcbSAlexander V. Chernikov struct rta_mpath_nh *nhop = &rt.rta_multipath->nhops[i]; 24768636dcbSAlexander V. Chernikov 24868636dcbSAlexander V. Chernikov rt.rta_gw = nhop->gw; 24968636dcbSAlexander V. Chernikov rt.rta_oif = nhop->ifindex; 25068636dcbSAlexander V. Chernikov rt.rtax_weight = nhop->rtnh_weight; 25168636dcbSAlexander V. Chernikov rt.rta_rtflags = nhop->rta_rtflags ? nhop->rta_rtflags : orig_rtflags; 25268636dcbSAlexander V. Chernikov rt.rtax_mtu = nhop->rtax_mtu ? nhop->rtax_mtu : orig_mtu; 25368636dcbSAlexander V. Chernikov 25468636dcbSAlexander V. Chernikov xo_open_instance(name); 25515dbf5a2SAlexander V. Chernikov p_path(&rt, true); 25668636dcbSAlexander V. Chernikov xo_emit("\n"); 25768636dcbSAlexander V. Chernikov xo_close_instance(name); 25868636dcbSAlexander V. Chernikov } 25968636dcbSAlexander V. Chernikov return; 26068636dcbSAlexander V. Chernikov } 26168636dcbSAlexander V. Chernikov 262*aee2f11bSAlexander V. Chernikov struct sockaddr_dl sdl_gw = { 26368636dcbSAlexander V. Chernikov .sdl_family = AF_LINK, 264*aee2f11bSAlexander V. Chernikov .sdl_len = sizeof(struct sockaddr_dl), 26568636dcbSAlexander V. Chernikov .sdl_index = rt.rta_oif, 26668636dcbSAlexander V. Chernikov }; 26768636dcbSAlexander V. Chernikov if (rt.rta_gw == NULL) 26868636dcbSAlexander V. Chernikov rt.rta_gw = (struct sockaddr *)&sdl_gw; 26968636dcbSAlexander V. Chernikov 27068636dcbSAlexander V. Chernikov xo_open_instance(name); 27115dbf5a2SAlexander V. Chernikov p_path(&rt, false); 27268636dcbSAlexander V. Chernikov xo_emit("\n"); 27368636dcbSAlexander V. Chernikov xo_close_instance(name); 27468636dcbSAlexander V. Chernikov } 27568636dcbSAlexander V. Chernikov 27668636dcbSAlexander V. Chernikov bool 27768636dcbSAlexander V. Chernikov p_rtable_netlink(int fibnum, int af) 27868636dcbSAlexander V. Chernikov { 27968636dcbSAlexander V. Chernikov int fam = AF_UNSPEC; 28068636dcbSAlexander V. Chernikov int need_table_close = false; 28168636dcbSAlexander V. Chernikov struct nlmsghdr *hdr; 282*aee2f11bSAlexander V. Chernikov struct snl_errmsg_data e = {}; 28368636dcbSAlexander V. Chernikov struct snl_state ss = {}; 28468636dcbSAlexander V. Chernikov 28568636dcbSAlexander V. Chernikov if (!snl_init(&ss, NETLINK_ROUTE)) 28668636dcbSAlexander V. Chernikov return (false); 28768636dcbSAlexander V. Chernikov 28868636dcbSAlexander V. Chernikov ifmap = prepare_ifmap_netlink(&ss, &ifmap_size); 28968636dcbSAlexander V. Chernikov 29068636dcbSAlexander V. Chernikov struct { 29168636dcbSAlexander V. Chernikov struct nlmsghdr hdr; 29268636dcbSAlexander V. Chernikov struct rtmsg rtmsg; 29368636dcbSAlexander V. Chernikov struct nlattr nla_fibnum; 29468636dcbSAlexander V. Chernikov uint32_t fibnum; 29568636dcbSAlexander V. Chernikov } msg = { 29668636dcbSAlexander V. Chernikov .hdr.nlmsg_type = RTM_GETROUTE, 29768636dcbSAlexander V. Chernikov .hdr.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST, 29868636dcbSAlexander V. Chernikov .hdr.nlmsg_seq = snl_get_seq(&ss), 29968636dcbSAlexander V. Chernikov .rtmsg.rtm_family = af, 30068636dcbSAlexander V. Chernikov .nla_fibnum.nla_len = sizeof(struct nlattr) + sizeof(uint32_t), 30168636dcbSAlexander V. Chernikov .nla_fibnum.nla_type = RTA_TABLE, 30268636dcbSAlexander V. Chernikov .fibnum = fibnum, 30368636dcbSAlexander V. Chernikov }; 30468636dcbSAlexander V. Chernikov msg.hdr.nlmsg_len = sizeof(msg); 30568636dcbSAlexander V. Chernikov 306*aee2f11bSAlexander V. Chernikov if (!snl_send_message(&ss, &msg.hdr)) { 30768636dcbSAlexander V. Chernikov snl_free(&ss); 30868636dcbSAlexander V. Chernikov return (false); 30968636dcbSAlexander V. Chernikov } 31068636dcbSAlexander V. Chernikov 31168636dcbSAlexander V. Chernikov xo_open_container("route-table"); 31268636dcbSAlexander V. Chernikov xo_open_list("rt-family"); 313*aee2f11bSAlexander V. Chernikov while ((hdr = snl_read_reply_multi(&ss, msg.hdr.nlmsg_seq, &e)) != NULL) { 31468636dcbSAlexander V. Chernikov struct rtmsg *rtm = (struct rtmsg *)(hdr + 1); 31568636dcbSAlexander V. Chernikov /* Only print family first time. */ 31668636dcbSAlexander V. Chernikov if (fam != rtm->rtm_family) { 31768636dcbSAlexander V. Chernikov if (need_table_close) { 31868636dcbSAlexander V. Chernikov xo_close_list("rt-entry"); 31968636dcbSAlexander V. Chernikov xo_close_instance("rt-family"); 32068636dcbSAlexander V. Chernikov } 32168636dcbSAlexander V. Chernikov need_table_close = true; 32268636dcbSAlexander V. Chernikov fam = rtm->rtm_family; 32368636dcbSAlexander V. Chernikov set_wid(fam); 32468636dcbSAlexander V. Chernikov xo_open_instance("rt-family"); 32568636dcbSAlexander V. Chernikov pr_family(fam); 32668636dcbSAlexander V. Chernikov xo_open_list("rt-entry"); 32768636dcbSAlexander V. Chernikov pr_rthdr(fam); 32868636dcbSAlexander V. Chernikov } 32968636dcbSAlexander V. Chernikov p_rtentry_netlink(&ss, "rt-entry", hdr); 33068636dcbSAlexander V. Chernikov snl_clear_lb(&ss); 33168636dcbSAlexander V. Chernikov } 33268636dcbSAlexander V. Chernikov if (need_table_close) { 33368636dcbSAlexander V. Chernikov xo_close_list("rt-entry"); 33468636dcbSAlexander V. Chernikov xo_close_instance("rt-family"); 33568636dcbSAlexander V. Chernikov } 33668636dcbSAlexander V. Chernikov xo_close_list("rt-family"); 33768636dcbSAlexander V. Chernikov xo_close_container("route-table"); 33868636dcbSAlexander V. Chernikov snl_free(&ss); 33968636dcbSAlexander V. Chernikov return (true); 34068636dcbSAlexander V. Chernikov } 34168636dcbSAlexander V. Chernikov 34268636dcbSAlexander V. Chernikov 343