]>
git.ipfire.org Git - thirdparty/bird.git/blob - sysdep/linux/netlink/netlink.c
bdc879f6ef4ba7dc8d5f49c1da4d493cf8f9613b
2 * BIRD -- Linux Netlink Interface
4 * (c) 1999 Martin Mares <mj@ucw.cz>
6 * Can be freely distributed and used under the terms of the GNU GPL.
13 #include <sys/socket.h>
19 #include "nest/bird.h"
20 #include "nest/route.h"
21 #include "nest/protocol.h"
22 #include "nest/iface.h"
23 #include "lib/timer.h"
26 #include "lib/socket.h"
27 #include "conf/conf.h"
29 #include <asm/types.h>
30 #include <linux/netlink.h>
31 #include <linux/rtnetlink.h>
33 #ifndef MSG_TRUNC /* Hack: Several versions of glibc miss this one :( */
34 #define MSG_TRUNC 0x20
38 * Synchronous Netlink interface
41 static int nl_sync_fd
= -1; /* Unix socket for synchronous netlink actions */
42 static u32 nl_sync_seq
; /* Sequence number of last request sent */
44 static byte
*nl_rx_buffer
; /* Receive buffer */
45 #define NL_RX_SIZE 2048
47 static struct nlmsghdr
*nl_last_hdr
; /* Recently received packet */
48 static unsigned int nl_last_size
;
55 nl_sync_fd
= socket(PF_NETLINK
, SOCK_RAW
, NETLINK_ROUTE
);
57 die("Unable to open rtnetlink socket: %m");
59 nl_rx_buffer
= xmalloc(NL_RX_SIZE
);
64 nl_send(struct nlmsghdr
*nh
)
66 struct sockaddr_nl sa
;
68 memset(&sa
, 0, sizeof(sa
));
69 sa
.nl_family
= AF_NETLINK
;
71 nh
->nlmsg_seq
= ++nl_sync_seq
;
72 if (sendto(nl_sync_fd
, nh
, nh
->nlmsg_len
, 0, (struct sockaddr
*)&sa
, sizeof(sa
)) < 0)
73 die("rtnetlink sendto: %m");
78 nl_request_dump(int cmd
)
84 req
.nh
.nlmsg_type
= cmd
;
85 req
.nh
.nlmsg_len
= sizeof(req
);
86 req
.nh
.nlmsg_flags
= NLM_F_REQUEST
| NLM_F_DUMP
;
87 req
.g
.rtgen_family
= BIRD_PF
;
91 static struct nlmsghdr
*
98 struct iovec iov
= { nl_rx_buffer
, NL_RX_SIZE
};
99 struct sockaddr_nl sa
;
100 struct msghdr m
= { (struct sockaddr
*) &sa
, sizeof(sa
), &iov
, 1, NULL
, 0, 0 };
101 int x
= recvmsg(nl_sync_fd
, &m
, 0);
103 die("nl_get_reply: %m");
104 if (sa
.nl_pid
) /* It isn't from the kernel */
106 DBG("Non-kernel packet\n");
110 nl_last_hdr
= (void *) nl_rx_buffer
;
111 if (m
.msg_flags
& MSG_TRUNC
)
112 bug("nl_get_reply: got truncated reply which should be impossible");
114 if (NLMSG_OK(nl_last_hdr
, nl_last_size
))
116 struct nlmsghdr
*h
= nl_last_hdr
;
117 if (h
->nlmsg_seq
!= nl_sync_seq
)
119 log(L_WARN
"nl_get_reply: Ignoring out of sequence netlink packet (%x != %x)",
120 h
->nlmsg_seq
, nl_sync_seq
);
123 nl_last_hdr
= NLMSG_NEXT(h
, nl_last_size
);
127 log(L_WARN
"nl_get_reply: Found packet remnant of size %d", nl_last_size
);
133 nl_error(struct nlmsghdr
*h
)
138 if (h
->nlmsg_len
< NLMSG_LENGTH(sizeof(struct nlmsgerr
)))
140 log(L_WARN
"Netlink: Truncated error message received");
143 e
= (struct nlmsgerr
*) NLMSG_DATA(h
);
146 log(L_WARN
"Netlink: %s", strerror(ec
));
150 static struct nlmsghdr
*
153 struct nlmsghdr
*h
= nl_get_reply();
155 if (h
->nlmsg_type
== NLMSG_DONE
)
157 if (h
->nlmsg_type
== NLMSG_ERROR
)
166 nl_exchange(struct nlmsghdr
*pkt
)
174 if (h
->nlmsg_type
== NLMSG_ERROR
)
176 log(L_WARN
"nl_exchange: Unexpected reply received");
185 static int nl_attr_len
;
188 nl_checkin(struct nlmsghdr
*h
, int lsize
)
190 nl_attr_len
= h
->nlmsg_len
- NLMSG_LENGTH(lsize
);
193 log(L_ERR
"nl_checkin: underrun by %d bytes", -nl_attr_len
);
196 return NLMSG_DATA(h
);
200 nl_parse_attrs(struct rtattr
*a
, struct rtattr
**k
, int ksize
)
202 int max
= ksize
/ sizeof(struct rtattr
*);
204 while (RTA_OK(a
, nl_attr_len
))
206 if (a
->rta_type
< max
)
208 a
= RTA_NEXT(a
, nl_attr_len
);
212 log(L_ERR
"nl_parse_attrs: remnant of size %d", nl_attr_len
);
220 nl_add_attr_u32(struct nlmsghdr
*h
, unsigned maxsize
, int code
, u32 data
)
222 unsigned len
= RTA_LENGTH(4);
225 if (NLMSG_ALIGN(h
->nlmsg_len
) + len
> maxsize
)
226 bug("nl_add_attr32: packet buffer overflow");
227 a
= (struct rtattr
*)((char *)h
+ NLMSG_ALIGN(h
->nlmsg_len
));
230 memcpy(RTA_DATA(a
), &data
, 4);
231 h
->nlmsg_len
= NLMSG_ALIGN(h
->nlmsg_len
) + len
;
235 nl_add_attr_ipa(struct nlmsghdr
*h
, unsigned maxsize
, int code
, ip_addr ipa
)
237 unsigned len
= RTA_LENGTH(sizeof(ipa
));
240 if (NLMSG_ALIGN(h
->nlmsg_len
) + len
> maxsize
)
241 bug("nl_add_attr_ipa: packet buffer overflow");
242 a
= (struct rtattr
*)((char *)h
+ NLMSG_ALIGN(h
->nlmsg_len
));
246 memcpy(RTA_DATA(a
), &ipa
, sizeof(ipa
));
247 h
->nlmsg_len
= NLMSG_ALIGN(h
->nlmsg_len
) + len
;
251 * Scanning of interfaces
255 nl_parse_link(struct nlmsghdr
*h
, int scan
)
258 struct rtattr
*a
[IFLA_STATS
+1];
259 int new = h
->nlmsg_type
== RTM_NEWLINK
;
266 if (!(i
= nl_checkin(h
, sizeof(*i
))) || !nl_parse_attrs(IFLA_RTA(i
), a
, sizeof(a
)))
268 if (!a
[IFLA_IFNAME
] || RTA_PAYLOAD(a
[IFLA_IFNAME
]) < 2 ||
269 !a
[IFLA_MTU
] || RTA_PAYLOAD(a
[IFLA_MTU
]) != 4)
271 log(L_ERR
"nl_parse_link: Malformed message received");
274 name
= RTA_DATA(a
[IFLA_IFNAME
]);
275 memcpy(&mtu
, RTA_DATA(a
[IFLA_MTU
]), sizeof(u32
));
277 ifi
= if_find_by_index(i
->ifi_index
);
280 DBG("KIF: IF%d(%s) goes down\n", i
->ifi_index
, name
);
283 memcpy(&f
, ifi
, sizeof(struct iface
));
284 f
.flags
|= IF_ADMIN_DOWN
;
290 DBG("KIF: IF%d(%s) goes up (mtu=%d,flg=%x)\n", i
->ifi_index
, name
, mtu
, i
->ifi_flags
);
292 memcpy(&f
, ifi
, sizeof(f
));
295 bzero(&f
, sizeof(f
));
296 f
.index
= i
->ifi_index
;
298 strncpy(f
.name
, RTA_DATA(a
[IFLA_IFNAME
]), sizeof(f
.name
)-1);
303 f
.flags
|= IF_LINK_UP
;
304 if (fl
& IFF_LOOPBACK
) /* Loopback */
305 f
.flags
|= IF_MULTIACCESS
| IF_LOOPBACK
| IF_IGNORE
;
306 else if (fl
& IFF_POINTOPOINT
) /* PtP */
307 f
.flags
|= IF_MULTICAST
;
308 else if (fl
& IFF_BROADCAST
) /* Broadcast */
309 f
.flags
|= IF_MULTIACCESS
| IF_BROADCAST
| IF_MULTICAST
;
311 f
.flags
|= IF_MULTIACCESS
; /* NBMA */
317 nl_parse_addr(struct nlmsghdr
*h
)
320 struct rtattr
*a
[IFA_ANYCAST
+1];
321 int new = h
->nlmsg_type
== RTM_NEWADDR
;
325 if (!(i
= nl_checkin(h
, sizeof(*i
))) || !nl_parse_attrs(IFA_RTA(i
), a
, sizeof(a
)))
327 if (i
->ifa_family
!= BIRD_AF
)
329 if (!a
[IFA_ADDRESS
] || RTA_PAYLOAD(a
[IFA_ADDRESS
]) != sizeof(ip_addr
)
331 || a
[IFA_LOCAL
] && RTA_PAYLOAD(a
[IFA_LOCAL
]) != sizeof(ip_addr
)
333 || !a
[IFA_LOCAL
] || RTA_PAYLOAD(a
[IFA_LOCAL
]) != sizeof(ip_addr
)
334 || (a
[IFA_BROADCAST
] && RTA_PAYLOAD(a
[IFA_BROADCAST
]) != sizeof(ip_addr
))
338 log(L_ERR
"nl_parse_addr: Malformed message received");
343 if (i
->ifa_scope
== RT_SCOPE_LINK
)
347 ifi
= if_find_by_index(i
->ifa_index
);
350 log(L_ERR
"KIF: Received address message for unknown interface %d\n", i
->ifa_index
);
354 bzero(&ifa
, sizeof(ifa
));
356 if (i
->ifa_flags
& IFA_F_SECONDARY
)
357 ifa
.flags
|= IA_SECONDARY
;
358 /* IFA_LOCAL can be unset for IPv6 interfaces */
359 memcpy(&ifa
.ip
, RTA_DATA(a
[IFA_LOCAL
] ? : a
[IFA_ADDRESS
]), sizeof(ifa
.ip
));
361 ifa
.pxlen
= i
->ifa_prefixlen
;
362 if (i
->ifa_prefixlen
> BITS_PER_IP_ADDRESS
||
363 i
->ifa_prefixlen
== BITS_PER_IP_ADDRESS
- 1)
365 log(L_ERR
"KIF: Invalid prefix length for interface %s: %d", ifi
->name
, i
->ifa_prefixlen
);
368 if (i
->ifa_prefixlen
== BITS_PER_IP_ADDRESS
)
370 ifa
.flags
|= IA_UNNUMBERED
;
371 memcpy(&ifa
.opposite
, RTA_DATA(a
[IFA_ADDRESS
]), sizeof(ifa
.opposite
));
372 ipa_ntoh(ifa
.opposite
);
373 ifa
.prefix
= ifa
.brd
= ifa
.opposite
;
378 if (i
->ifa_prefixlen
== BITS_PER_IP_ADDRESS
- 2)
379 ifa
.opposite
= ipa_opposite(ifa
.ip
);
380 if ((ifi
->flags
& IF_BROADCAST
) && a
[IFA_BROADCAST
])
382 memcpy(&ifa
.brd
, RTA_DATA(a
[IFA_BROADCAST
]), sizeof(ifa
.brd
));
386 ifa
.prefix
= ipa_and(ifa
.ip
, ipa_mkmask(ifa
.pxlen
));
389 DBG("KIF: IF%d(%s): %s IPA %I, flg %x, net %I/%d, brd %I, opp %I\n",
390 ifi
->index
, ifi
->name
,
391 new ? "added" : "removed",
392 ifa
.ip
, ifa
.flags
, ifa
.prefix
, ifa
.pxlen
, ifa
.brd
, ifa
.opposite
);
400 krt_if_scan(struct kif_proto
*p
)
406 nl_request_dump(RTM_GETLINK
);
407 while (h
= nl_get_scan())
408 if (h
->nlmsg_type
== RTM_NEWLINK
|| h
->nlmsg_type
== RTM_DELLINK
)
411 log(L_DEBUG
"nl_scan_ifaces: Unknown packet received (type=%d)", h
->nlmsg_type
);
413 nl_request_dump(RTM_GETADDR
);
414 while (h
= nl_get_scan())
415 if (h
->nlmsg_type
== RTM_NEWADDR
|| h
->nlmsg_type
== RTM_DELADDR
)
418 log(L_DEBUG
"nl_scan_ifaces: Unknown packet received (type=%d)", h
->nlmsg_type
);
427 static struct krt_proto
*nl_table_map
[NL_NUM_TABLES
];
434 if (a
->cast
!= RTC_UNICAST
436 && a
->cast
!= RTC_ANYCAST
440 if (a
->source
== RTS_DEVICE
) /* Kernel takes care of device routes itself */
447 case RTD_UNREACHABLE
:
457 nl_send_route(struct krt_proto
*p
, rte
*e
, int new)
466 struct nlmsghdr
*reply
;
468 DBG("nl_send_route(%I/%d,new=%d)\n", net
->n
.prefix
, net
->n
.pxlen
, new);
470 bzero(&r
.h
, sizeof(r
.h
));
471 bzero(&r
.r
, sizeof(r
.r
));
472 r
.h
.nlmsg_type
= new ? RTM_NEWROUTE
: RTM_DELROUTE
;
473 r
.h
.nlmsg_len
= NLMSG_LENGTH(sizeof(struct rtmsg
));
474 r
.h
.nlmsg_flags
= NLM_F_REQUEST
| NLM_F_ACK
| (new ? NLM_F_CREATE
|NLM_F_REPLACE
: 0);
476 r
.r
.rtm_family
= BIRD_AF
;
477 r
.r
.rtm_dst_len
= net
->n
.pxlen
;
479 r
.r
.rtm_table
= KRT_CF
->scan
.table_id
;
480 r
.r
.rtm_protocol
= RTPROT_BIRD
;
481 r
.r
.rtm_scope
= RT_SCOPE_UNIVERSE
;
482 nl_add_attr_ipa(&r
.h
, sizeof(r
), RTA_DST
, net
->n
.prefix
);
486 r
.r
.rtm_type
= RTN_UNICAST
;
487 nl_add_attr_ipa(&r
.h
, sizeof(r
), RTA_GATEWAY
, a
->gw
);
490 r
.r
.rtm_type
= RTN_UNICAST
;
491 nl_add_attr_u32(&r
.h
, sizeof(r
), RTA_OIF
, a
->iface
->index
);
494 r
.r
.rtm_type
= RTN_BLACKHOLE
;
496 case RTD_UNREACHABLE
:
497 r
.r
.rtm_type
= RTN_UNREACHABLE
;
500 r
.r
.rtm_type
= RTN_PROHIBIT
;
503 bug("krt_capable inconsistent with nl_send_route");
510 krt_set_notify(struct krt_proto
*p
, net
*n
, rte
*new, rte
*old
)
515 * We should check whether priority and TOS is identical as well,
516 * but we don't use these and default value is always equal to default value. :-)
518 nl_send_route(p
, new, 1);
524 if (!old
->attrs
->iface
|| (old
->attrs
->iface
->flags
& IF_UP
))
525 nl_send_route(p
, old
, 0);
526 /* else the kernel has already flushed it */
529 nl_send_route(p
, new, 1);
534 krt_temp_iface(struct krt_proto
*p
, unsigned index
)
538 WALK_LIST(i
, p
->scan
.temp_ifs
)
539 if (i
->index
== index
)
541 i
= mb_allocz(p
->p
.pool
, sizeof(struct iface
));
542 if (j
= if_find_by_index(index
))
543 strcpy(i
->name
, j
->name
);
545 strcpy(i
->name
, "?");
547 add_tail(&p
->scan
.temp_ifs
, &i
->n
);
552 nl_parse_route(struct nlmsghdr
*h
, int scan
)
556 struct rtattr
*a
[RTA_CACHEINFO
+1];
557 int new = h
->nlmsg_type
== RTM_NEWROUTE
;
565 if (!(i
= nl_checkin(h
, sizeof(*i
))) || !nl_parse_attrs(RTM_RTA(i
), a
, sizeof(a
)))
567 if (i
->rtm_family
!= BIRD_AF
)
569 if ((a
[RTA_DST
] && RTA_PAYLOAD(a
[RTA_DST
]) != sizeof(ip_addr
)) ||
570 (a
[RTA_OIF
] && RTA_PAYLOAD(a
[RTA_OIF
]) != 4) ||
571 (a
[RTA_PRIORITY
] && RTA_PAYLOAD(a
[RTA_PRIORITY
]) != 4) ||
573 (a
[RTA_IIF
] && RTA_PAYLOAD(a
[RTA_IIF
]) != 4) ||
575 (a
[RTA_GATEWAY
] && RTA_PAYLOAD(a
[RTA_GATEWAY
]) != sizeof(ip_addr
)))
577 log(L_ERR
"nl_parse_route: Malformed message received");
581 p
= nl_table_map
[i
->rtm_table
]; /* Do we know this table? */
588 DBG("KRT: Ignoring route with IIF set\n");
592 if (i
->rtm_tos
!= 0) /* We don't support TOS */
594 DBG("KRT: Ignoring route with TOS %02x\n", i
->rtm_tos
);
601 DBG("KRT: Ignoring route deletion\n");
607 memcpy(&dst
, RTA_DATA(a
[RTA_DST
]), sizeof(dst
));
613 memcpy(&oif
, RTA_DATA(a
[RTA_OIF
]), sizeof(oif
));
617 DBG("Got %I/%d, type=%d, oif=%d, table=%d, proto=%s\n", dst
, i
->rtm_dst_len
, i
->rtm_type
, oif
, i
->rtm_table
, p
->p
.name
);
619 switch (i
->rtm_protocol
)
621 case RTPROT_REDIRECT
:
622 src
= KRT_SRC_REDIRECT
;
625 DBG("Route originated in kernel, ignoring\n");
630 DBG("Echo of our own route, ignoring\n");
639 net
= net_get(p
->p
.table
, dst
, i
->rtm_dst_len
);
641 ra
.source
= RTS_INHERIT
;
642 ra
.scope
= SCOPE_UNIVERSE
;
643 ra
.cast
= RTC_UNICAST
;
644 ra
.flags
= ra
.aflags
= 0;
655 log(L_ERR
"KRT: Mysterious route with no OIF (%I/%d)", net
->n
.prefix
, net
->n
.pxlen
);
661 ra
.dest
= RTD_ROUTER
;
662 memcpy(&ra
.gw
, RTA_DATA(a
[RTA_GATEWAY
]), sizeof(ra
.gw
));
664 ng
= neigh_find(&p
->p
, &ra
.gw
, 0);
666 ra
.iface
= ng
->iface
;
668 /* FIXME: Remove this warning? Handle it somehow... */
669 log(L_WARN
"Kernel told us to use non-neighbor %I for %I/%d", ra
.gw
, net
->n
.prefix
, net
->n
.pxlen
);
673 ra
.dest
= RTD_DEVICE
;
674 ra
.iface
= krt_temp_iface(p
, oif
);
678 ra
.dest
= RTD_BLACKHOLE
;
680 case RTN_UNREACHABLE
:
681 ra
.dest
= RTD_UNREACHABLE
;
684 ra
.dest
= RTD_PROHIBIT
;
686 /* FIXME: What about RTN_THROW? */
688 DBG("KRT: Ignoring route with type=%d\n", i
->rtm_type
);
692 if (i
->rtm_scope
!= RT_SCOPE_UNIVERSE
)
694 DBG("KRT: Ignoring route with scope=%d\n", i
->rtm_scope
);
698 e
= rte_get_temp(&ra
);
701 e
->u
.krt
.proto
= i
->rtm_protocol
;
702 e
->u
.krt
.type
= i
->rtm_type
;
704 memcpy(&e
->u
.krt
.metric
, RTA_DATA(a
[RTA_PRIORITY
]), sizeof(e
->u
.krt
.metric
));
710 krt_got_route_async(p
, e
, new);
714 krt_scan_fire(struct krt_proto
*p
) /* CONFIG_ALL_TABLES_AT_ONCE => p is NULL */
718 nl_request_dump(RTM_GETROUTE
);
719 while (h
= nl_get_scan())
720 if (h
->nlmsg_type
== RTM_NEWROUTE
|| h
->nlmsg_type
== RTM_DELROUTE
)
721 nl_parse_route(h
, 1);
723 log(L_DEBUG
"nl_scan_fire: Unknown packet received (type=%d)", h
->nlmsg_type
);
727 * Asynchronous Netlink interface
730 static sock
*nl_async_sk
; /* BIRD socket for asynchronous notifications */
731 static byte
*nl_async_rx_buffer
; /* Receive buffer */
734 nl_async_msg(struct nlmsghdr
*h
)
736 switch (h
->nlmsg_type
)
740 DBG("KRT: Received async route notification (%d)\n", h
->nlmsg_type
);
741 nl_parse_route(h
, 0);
745 DBG("KRT: Received async link notification (%d)\n", h
->nlmsg_type
);
750 DBG("KRT: Received async address notification (%d)\n", h
->nlmsg_type
);
754 DBG("KRT: Received unknown async notification (%d)\n", h
->nlmsg_type
);
759 nl_async_hook(sock
*sk
, int size
)
761 struct iovec iov
= { nl_async_rx_buffer
, NL_RX_SIZE
};
762 struct sockaddr_nl sa
;
763 struct msghdr m
= { (struct sockaddr
*) &sa
, sizeof(sa
), &iov
, 1, NULL
, 0, 0 };
768 nl_last_hdr
= NULL
; /* Discard packets accidentally remaining in the rxbuf */
769 x
= recvmsg(sk
->fd
, &m
, 0);
772 if (errno
!= EWOULDBLOCK
)
773 log(L_ERR
"Netlink recvmsg: %m");
776 if (sa
.nl_pid
) /* It isn't from the kernel */
778 DBG("Non-kernel packet\n");
781 h
= (void *) nl_async_rx_buffer
;
783 if (m
.msg_flags
& MSG_TRUNC
)
785 log(L_WARN
"Netlink got truncated asynchronous message");
788 while (NLMSG_OK(h
, len
))
791 h
= NLMSG_NEXT(h
, len
);
794 log(L_WARN
"nl_async_hook: Found packet remnant of size %d", len
);
802 struct sockaddr_nl sa
;
805 DBG("KRT: Opening async netlink socket\n");
807 fd
= socket(PF_NETLINK
, SOCK_RAW
, NETLINK_ROUTE
);
810 log(L_ERR
"Unable to open asynchronous rtnetlink socket: %m");
814 bzero(&sa
, sizeof(sa
));
815 sa
.nl_family
= AF_NETLINK
;
817 sa
.nl_groups
= RTMGRP_LINK
| RTMGRP_IPV6_IFADDR
| RTMGRP_IPV6_ROUTE
;
819 sa
.nl_groups
= RTMGRP_LINK
| RTMGRP_IPV4_IFADDR
| RTMGRP_IPV4_ROUTE
;
821 if (bind(fd
, (struct sockaddr
*) &sa
, sizeof(sa
)) < 0)
823 log(L_ERR
"Unable to bind asynchronous rtnetlink socket: %m");
827 sk
= nl_async_sk
= sk_new(krt_pool
);
829 sk
->rx_hook
= nl_async_hook
;
832 bug("Netlink: sk_open failed");
834 if (!nl_async_rx_buffer
)
835 nl_async_rx_buffer
= xmalloc(NL_RX_SIZE
);
839 * Interface to the UNIX krt module
842 static u8 nl_cf_table
[(NL_NUM_TABLES
+7) / 8];
845 krt_scan_preconfig(struct config
*c
)
847 bzero(&nl_cf_table
, sizeof(nl_cf_table
));
851 krt_scan_postconfig(struct krt_config
*x
)
853 int id
= x
->scan
.table_id
;
855 if (nl_cf_table
[id
/8] & (1 << (id
%8)))
856 cf_error("Multiple kernel syncers defined for table #%d", id
);
857 nl_cf_table
[id
/8] |= (1 << (id
%8));
861 krt_scan_construct(struct krt_config
*x
)
865 x
->scan
.table_id
= RT_TABLE_MAIN
;
867 /* FIXME: Use larger defaults for scanning times? */
871 krt_scan_start(struct krt_proto
*p
, int first
)
873 init_list(&p
->scan
.temp_ifs
);
874 nl_table_map
[KRT_CF
->scan
.table_id
] = p
;
878 if (KRT_CF
->scan
.async
) /* FIXME: Async is for debugging only. Get rid of it some day. */
884 krt_scan_shutdown(struct krt_proto
*p
, int last
)
889 krt_if_start(struct kif_proto
*p
)
892 /* FIXME: nl_open_async() after scan.async is gone */