2 * Copyright (c) 2019 Cisco and/or its affiliates.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at:
7 * http://www.apache.org/licenses/LICENSE-2.0
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
20 #include <linux-cp/lcp_nl.h>
22 #include <netlink/route/rule.h>
23 #include <netlink/msg.h>
24 #include <netlink/netlink.h>
25 #include <netlink/socket.h>
26 #include <netlink/route/link.h>
27 #include <netlink/route/route.h>
28 #include <netlink/route/neighbour.h>
29 #include <netlink/route/addr.h>
31 #include <vlib/vlib.h>
32 #include <vlib/unix/unix.h>
33 #include <vppinfra/error.h>
34 #include <vppinfra/linux/netns.h>
36 #include <vnet/fib/fib_table.h>
38 #include <libmnl/libmnl.h>
40 #include <plugins/linux-cp/lcp_interface.h>
42 typedef enum nl_status_t_
48 typedef enum nl_sock_type_t_
56 #define NL_SOCK_TYPES_N (NL_SOCK_TYPE_ROUTE + 1)
58 /* Socket type, message type, type name, function subname */
59 #define foreach_sock_type \
60 _ (NL_SOCK_TYPE_LINK, RTM_GETLINK, "link", link) \
61 _ (NL_SOCK_TYPE_ADDR, RTM_GETADDR, "address", link_addr) \
62 _ (NL_SOCK_TYPE_NEIGH, RTM_GETNEIGH, "neighbor", neigh) \
63 _ (NL_SOCK_TYPE_ROUTE, RTM_GETROUTE, "route", route)
65 typedef enum nl_event_type_t_
71 typedef struct nl_main
74 nl_status_t nl_status;
76 struct nl_sock *sk_route;
77 struct nl_sock *sk_route_sync[NL_SOCK_TYPES_N];
78 vlib_log_class_t nl_logger;
80 struct nl_cache *nl_caches[LCP_NL_N_OBJS];
81 nl_msg_info_t *nl_msg_queue;
82 uword clib_file_index;
90 u32 sync_batch_delay_ms;
91 u32 sync_attempt_delay_ms;
95 #define NL_RX_BUF_SIZE_DEF (1 << 27) /* 128 MB */
96 #define NL_TX_BUF_SIZE_DEF (1 << 18) /* 256 kB */
97 #define NL_BATCH_SIZE_DEF (1 << 11) /* 2048 */
98 #define NL_BATCH_DELAY_MS_DEF 50 /* 50 ms, max 20 batch/s */
100 #define NL_SYNC_BATCH_LIMIT_DEF (1 << 10) /* 1024 */
101 #define NL_SYNC_BATCH_DELAY_MS_DEF 20 /* 20ms, max 50 batch/s */
102 #define NL_SYNC_ATTEMPT_DELAY_MS_DEF 2000 /* 2s */
104 static nl_main_t nl_main = {
105 .rx_buf_size = NL_RX_BUF_SIZE_DEF,
106 .tx_buf_size = NL_TX_BUF_SIZE_DEF,
107 .batch_size = NL_BATCH_SIZE_DEF,
108 .batch_delay_ms = NL_BATCH_DELAY_MS_DEF,
109 .sync_batch_limit = NL_SYNC_BATCH_LIMIT_DEF,
110 .sync_batch_delay_ms = NL_SYNC_BATCH_DELAY_MS_DEF,
111 .sync_attempt_delay_ms = NL_SYNC_ATTEMPT_DELAY_MS_DEF,
114 /* #define foreach_nl_nft_proto \ */
115 /* _(IP4, "ip", AF_INT) \ */
116 /* _(IP6, "ip6", NFPROTO_IPV6) */
118 /* typedef enum nl_nft_proto_t_ */
120 /* #define _(a,b,c) NL_NFT_PROTO_##a = c, */
121 /* foreach_nl_nft_proto */
123 /* } nl_nft_proto_t; */
125 #define FOREACH_VFT(__func, __arg) \
127 nl_main_t *nm = &nl_main; \
129 vec_foreach (__nv, nm->nl_vfts) \
131 if (!__nv->__func.cb) \
134 if (!__nv->__func.is_mp_safe) \
135 vlib_worker_thread_barrier_sync (vlib_get_main ()); \
137 __nv->__func.cb (__arg); \
139 if (!__nv->__func.is_mp_safe) \
140 vlib_worker_thread_barrier_release (vlib_get_main ()); \
144 #define FOREACH_VFT_NO_ARG(__func) \
146 nl_main_t *nm = &nl_main; \
148 vec_foreach (__nv, nm->nl_vfts) \
150 if (!__nv->__func.cb) \
153 if (!__nv->__func.is_mp_safe) \
154 vlib_worker_thread_barrier_sync (vlib_get_main ()); \
156 __nv->__func.cb (); \
158 if (!__nv->__func.is_mp_safe) \
159 vlib_worker_thread_barrier_release (vlib_get_main ()); \
163 #define FOREACH_VFT_CTX(__func, __arg, __ctx) \
165 nl_main_t *nm = &nl_main; \
167 vec_foreach (__nv, nm->nl_vfts) \
169 if (!__nv->__func.cb) \
172 if (!__nv->__func.is_mp_safe) \
173 vlib_worker_thread_barrier_sync (vlib_get_main ()); \
175 __nv->__func.cb (__arg, __ctx); \
177 if (!__nv->__func.is_mp_safe) \
178 vlib_worker_thread_barrier_release (vlib_get_main ()); \
183 nl_register_vft (const nl_vft_t *nv)
185 nl_main_t *nm = &nl_main;
187 vec_add1 (nm->nl_vfts, *nv);
190 #define NL_DBG(...) vlib_log_debug (nl_main.nl_logger, __VA_ARGS__);
191 #define NL_INFO(...) vlib_log_notice (nl_main.nl_logger, __VA_ARGS__);
192 #define NL_ERROR(...) vlib_log_err (nl_main.nl_logger, __VA_ARGS__);
194 static void lcp_nl_open_socket (void);
195 static void lcp_nl_close_socket (void);
196 static void lcp_nl_open_sync_socket (nl_sock_type_t sock_type);
197 static void lcp_nl_close_sync_socket (nl_sock_type_t sock_type);
200 nl_route_del (struct rtnl_route *rr, void *arg)
202 FOREACH_VFT (nvl_rt_route_del, rr);
206 nl_route_add (struct rtnl_route *rr, void *arg)
208 FOREACH_VFT (nvl_rt_route_add, rr);
212 nl_route_sync_begin (void)
214 FOREACH_VFT_NO_ARG (nvl_rt_route_sync_begin);
218 nl_route_sync_end (void)
220 FOREACH_VFT_NO_ARG (nvl_rt_route_sync_end);
224 nl_neigh_del (struct rtnl_neigh *rn, void *arg)
226 FOREACH_VFT (nvl_rt_neigh_del, rn);
230 nl_neigh_add (struct rtnl_neigh *rn, void *arg)
232 FOREACH_VFT (nvl_rt_neigh_add, rn);
236 nl_neigh_sync_begin (void)
238 FOREACH_VFT_NO_ARG (nvl_rt_neigh_sync_begin);
242 nl_neigh_sync_end (void)
244 FOREACH_VFT_NO_ARG (nvl_rt_neigh_sync_end);
248 nl_link_addr_del (struct rtnl_addr *rla, void *arg)
250 FOREACH_VFT (nvl_rt_addr_del, rla);
254 nl_link_addr_add (struct rtnl_addr *rla, void *arg)
256 FOREACH_VFT (nvl_rt_addr_add, rla);
260 nl_link_addr_sync_begin (void)
262 FOREACH_VFT_NO_ARG (nvl_rt_addr_sync_begin);
266 nl_link_addr_sync_end (void)
268 FOREACH_VFT_NO_ARG (nvl_rt_addr_sync_end);
272 nl_link_del (struct rtnl_link *rl, void *arg)
274 FOREACH_VFT_CTX (nvl_rt_link_del, rl, arg);
278 nl_link_add (struct rtnl_link *rl, void *arg)
280 FOREACH_VFT_CTX (nvl_rt_link_add, rl, arg);
284 nl_link_sync_begin (void)
286 FOREACH_VFT_NO_ARG (nvl_rt_link_sync_begin);
290 nl_link_sync_end (void)
292 FOREACH_VFT_NO_ARG (nvl_rt_link_sync_end);
296 nl_route_dispatch (struct nl_object *obj, void *arg)
298 /* nothing can be done without interface mappings */
299 if (!lcp_itf_num_pairs ())
302 switch (nl_object_get_msgtype (obj))
305 nl_route_add ((struct rtnl_route *) obj, arg);
308 nl_route_del ((struct rtnl_route *) obj, arg);
311 nl_neigh_add ((struct rtnl_neigh *) obj, arg);
314 nl_neigh_del ((struct rtnl_neigh *) obj, arg);
317 nl_link_addr_add ((struct rtnl_addr *) obj, arg);
320 nl_link_addr_del ((struct rtnl_addr *) obj, arg);
323 nl_link_add ((struct rtnl_link *) obj, arg);
326 nl_link_del ((struct rtnl_link *) obj, arg);
329 NL_INFO ("unhandled: %s", nl_object_get_type (obj));
335 nl_route_process_msgs (void)
337 nl_main_t *nm = &nl_main;
338 nl_msg_info_t *msg_info;
341 /* process a batch of messages. break if we hit our limit */
342 vec_foreach (msg_info, nm->nl_msg_queue)
344 if ((err = nl_msg_parse (msg_info->msg, nl_route_dispatch, msg_info)) <
346 NL_ERROR ("Unable to parse object: %s", nl_geterror (err));
347 nlmsg_free (msg_info->msg);
348 if (++n_msgs >= nm->batch_size)
352 /* remove the messages we processed from the head of the queue */
354 vec_delete (nm->nl_msg_queue, n_msgs, 0);
356 NL_INFO ("Processed %u messages", n_msgs);
362 lcp_nl_route_discard_msgs (void)
364 nl_main_t *nm = &nl_main;
365 nl_msg_info_t *msg_info;
368 n_msgs = vec_len (nm->nl_msg_queue);
372 vec_foreach (msg_info, nm->nl_msg_queue)
374 nlmsg_free (msg_info->msg);
377 vec_reset_length (nm->nl_msg_queue);
379 NL_INFO ("Discarded %u messages", n_msgs);
385 lcp_nl_route_send_dump_req (nl_sock_type_t sock_type, int msg_type)
387 nl_main_t *nm = &nl_main;
388 struct nl_sock *sk_route = nm->sk_route_sync[sock_type];
390 struct rtgenmsg rt_hdr = {
391 .rtgen_family = AF_UNSPEC,
395 nl_send_simple (sk_route, msg_type, NLM_F_DUMP, &rt_hdr, sizeof (rt_hdr));
399 NL_ERROR ("Unable to send a dump request: %s", nl_geterror (err));
402 NL_INFO ("Dump request sent via socket %d of type %d",
403 nl_socket_get_fd (sk_route), sock_type);
409 lcp_nl_route_dump_cb (struct nl_msg *msg, void *arg)
413 if ((err = nl_msg_parse (msg, nl_route_dispatch, NULL)) < 0)
414 NL_ERROR ("Unable to parse object: %s", nl_geterror (err));
420 lcp_nl_recv_dump_replies (nl_sock_type_t sock_type, int msg_limit,
423 nl_main_t *nm = &nl_main;
424 struct nl_sock *sk_route = nm->sk_route_sync[sock_type];
425 struct sockaddr_nl nla;
428 struct nlmsghdr *hdr;
429 struct nl_msg *msg = NULL;
435 n_bytes = nl_recv (sk_route, &nla, &buf, /* creds */ NULL);
439 hdr = (struct nlmsghdr *) buf;
440 while (nlmsg_ok (hdr, n_bytes))
443 msg = nlmsg_convert (hdr);
452 nlmsg_set_proto (msg, NETLINK_ROUTE);
453 nlmsg_set_src (msg, &nla);
455 /* Message that terminates a multipart message. Finish parsing and signal
456 * the caller that all dump replies have been received
458 if (hdr->nlmsg_type == NLMSG_DONE)
463 /* Message to be ignored. Continue parsing */
464 else if (hdr->nlmsg_type == NLMSG_NOOP)
466 /* Message that indicates data was lost. Finish parsing and return an
469 else if (hdr->nlmsg_type == NLMSG_OVERRUN)
471 err = -NLE_MSG_OVERFLOW;
474 /* Message that indicates an error. Finish parsing, extract the error
475 * code, and return it */
476 else if (hdr->nlmsg_type == NLMSG_ERROR)
478 struct nlmsgerr *e = nlmsg_data (hdr);
480 if (hdr->nlmsg_len < nlmsg_size (sizeof (*e)))
482 err = -NLE_MSG_TRUNC;
487 err = -nl_syserr2nlerr (e->error);
490 /* Message is an acknowledgement (err_code = 0). Continue parsing */
494 /* Message that contains the requested data. Pass it for processing and
499 lcp_nl_route_dump_cb (msg, NULL);
502 hdr = nlmsg_next (hdr, &n_bytes);
510 if (!done && n_msgs < msg_limit)
511 goto continue_reading;
520 *is_done_rcvd = done;
525 #define DAY_F64 (1.0 * (24 * 60 * 60))
528 nl_route_process (vlib_main_t *vm, vlib_node_runtime_t *node,
531 nl_main_t *nm = &nl_main;
533 uword *event_data = 0;
534 f64 wait_time = DAY_F64;
540 if (nm->nl_status == NL_STATUS_NOTIF_PROC)
542 /* If we process a batch of messages and stop because we reached the
543 * batch size limit, we want to wake up after the batch delay and
544 * process more. Otherwise we just want to wait for a read event.
546 vlib_process_wait_for_event_or_clock (vm, wait_time);
547 event_type = vlib_process_get_events (vm, &event_data);
548 vec_reset_length (event_data);
552 /* Process batch of queued messages on timeout or read event
557 nl_route_process_msgs ();
558 wait_time = (vec_len (nm->nl_msg_queue) != 0) ?
559 nm->batch_delay_ms * 1e-3 :
563 /* Initiate synchronization if there was an error polling or
564 * reading the notification socket
567 nm->nl_status = NL_STATUS_SYNC;
571 NL_ERROR ("Unknown event type: %u", (u32) event_type);
574 else if (nm->nl_status == NL_STATUS_SYNC)
576 /* Stop processing notifications - close the notification socket and
577 * discard all messages that are currently in the queue
579 lcp_nl_close_socket ();
580 lcp_nl_route_discard_msgs ();
582 /* Wait some time before next synchronization attempt. Allows to
583 * reduce the number of failed attempts that stall the main thread by
584 * waiting out the notification storm
586 NL_INFO ("Wait before next synchronization attempt for %ums",
587 nm->sync_attempt_delay_ms);
588 vlib_process_suspend (vm, nm->sync_attempt_delay_ms * 1e-3);
590 /* Open netlink synchronization socket, one for every data type of
591 * interest: link, address, neighbor, and route. That is needed to
592 * be able to send dump requests for every data type simultaneously.
593 * If send a dump request while the previous one is in progress,
594 * the request will fail and EBUSY returned
596 #define _(stype, mtype, tname, fn) lcp_nl_open_sync_socket (stype);
600 /* Start reading notifications and enqueueing them for further
601 * processing. The notifications will serve as a difference between
602 * the snapshot made after the dump request and the actual state at
603 * the moment. Once all the dump replies are processed, the
604 * notifications will be processed
606 lcp_nl_open_socket ();
608 /* Request the current entry set from the kernel for every data type
609 * of interest. Thus requesting a snapshot of the current routing
610 * state that the kernel will make and then reply with
612 #define _(stype, mtype, tname, fn) lcp_nl_route_send_dump_req (stype, mtype);
616 /* Process all the dump replies */
617 #define _(stype, mtype, tname, fn) \
618 nl_##fn##_sync_begin (); \
623 lcp_nl_recv_dump_replies (stype, nm->sync_batch_limit, &is_done); \
626 NL_ERROR ("Error receiving dump replies of type " tname \
628 nl_geterror (n_msgs), n_msgs); \
631 else if (n_msgs == 0) \
633 NL_ERROR ("EOF while receiving dump replies of type " tname); \
637 NL_INFO ("Processed %u dump replies of type " tname, n_msgs); \
639 /* Suspend the processing loop and wait until event signal is \
640 * received or timeout expires. During synchronization, only \
641 * error event is expected because read event is suppressed. \
642 * Allows not to stall the main thread and detect errors on the \
643 * notification socket that will make synchronization \
646 vlib_process_wait_for_event_or_clock (vm, \
647 nm->sync_batch_delay_ms * 1e-3); \
648 event_type = vlib_process_get_events (vm, &event_data); \
649 vec_reset_length (event_data); \
651 /* If error event received, stop synchronization and repeat an \
654 if (event_type == NL_EVENT_ERR) \
658 nl_##fn##_sync_end ();
663 /* Start processing notifications */
664 nm->nl_status = NL_STATUS_NOTIF_PROC;
666 /* Trigger messages processing if there are notifications received
667 * during synchronization
669 wait_time = (vec_len (nm->nl_msg_queue) != 0) ? 1e-3 : DAY_F64;
672 /* Close netlink synchronization sockets */
673 #define _(stype, mtype, tname, fn) lcp_nl_close_sync_socket (stype);
678 NL_ERROR ("Unknown status: %d", nm->nl_status);
680 return frame->n_vectors;
683 VLIB_REGISTER_NODE (nl_route_process_node, static) = {
684 .function = nl_route_process,
685 .name = "linux-cp-netlink-process",
686 .type = VLIB_NODE_TYPE_PROCESS,
687 .process_log2_n_stack_bytes = 17,
691 nl_route_cb (struct nl_msg *msg, void *arg)
693 nl_main_t *nm = &nl_main;
694 nl_msg_info_t *msg_info = 0;
696 /* delay processing - increment ref count and queue for later */
697 vec_add2 (nm->nl_msg_queue, msg_info, 1);
699 /* store a timestamp for the message */
700 msg_info->ts = vlib_time_now (vlib_get_main ());
708 lcp_nl_drain_messages (void)
711 nl_main_t *nm = &nl_main;
713 /* Read until there's an error */
714 while ((err = nl_recvmsgs_default (nm->sk_route)) > -1)
717 /* If there was an error other then EAGAIN, signal process node */
718 if (err != -NLE_AGAIN)
719 vlib_process_signal_event (vlib_get_main (), nl_route_process_node.index,
723 /* If netlink notification processing is active, signal process node
724 * there were notifications read
726 if (nm->nl_status == NL_STATUS_NOTIF_PROC)
727 vlib_process_signal_event (
728 vlib_get_main (), nl_route_process_node.index, NL_EVENT_READ, 0);
735 lcp_nl_pair_add_cb (lcp_itf_pair_t *pair)
737 lcp_nl_drain_messages ();
740 static clib_error_t *
741 nl_route_read_cb (clib_file_t *f)
744 err = lcp_nl_drain_messages ();
745 if (err < 0 && err != -NLE_AGAIN)
746 NL_ERROR ("Error reading netlink socket (fd %d): %s (%d)",
747 f->file_descriptor, nl_geterror (err), err);
752 static clib_error_t *
753 nl_route_error_cb (clib_file_t *f)
755 NL_ERROR ("Error polling netlink socket (fd %d)", f->file_descriptor);
757 /* notify process node */
758 vlib_process_signal_event (vlib_get_main (), nl_route_process_node.index,
761 return clib_error_return (0, "Error polling netlink socket %d",
766 lcp_nl_get_cache (lcp_nl_obj_t t)
768 nl_main_t *nm = &nl_main;
770 return nm->nl_caches[t];
773 /* Set the RX buffer size to be used on the netlink socket */
775 lcp_nl_set_buffer_size (u32 buf_size)
777 nl_main_t *nm = &nl_main;
779 nm->rx_buf_size = buf_size;
782 nl_socket_set_buffer_size (nm->sk_route, nm->rx_buf_size, nm->tx_buf_size);
785 /* Set the batch size - maximum netlink messages to process at one time */
787 lcp_nl_set_batch_size (u32 batch_size)
789 nl_main_t *nm = &nl_main;
791 nm->batch_size = batch_size;
794 /* Set the batch delay - how long to wait in ms between processing batches */
796 lcp_nl_set_batch_delay (u32 batch_delay_ms)
798 nl_main_t *nm = &nl_main;
800 nm->batch_delay_ms = batch_delay_ms;
803 static clib_error_t *
804 lcp_itf_pair_config (vlib_main_t *vm, unformat_input_t *input)
806 u32 buf_size, batch_size, batch_delay_ms;
808 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
810 if (unformat (input, "nl-rx-buffer-size %u", &buf_size))
811 lcp_nl_set_buffer_size (buf_size);
812 else if (unformat (input, "nl-batch-size %u", &batch_size))
813 lcp_nl_set_batch_size (batch_size);
814 else if (unformat (input, "nl-batch-delay-ms %u", &batch_delay_ms))
815 lcp_nl_set_batch_delay (batch_delay_ms);
817 return clib_error_return (0, "invalid netlink option: %U",
818 format_unformat_error, input);
824 VLIB_CONFIG_FUNCTION (lcp_itf_pair_config, "linux-nl");
827 lcp_nl_close_socket (void)
829 nl_main_t *nm = &nl_main;
831 /* delete existing fd from epoll fd set */
832 if (nm->clib_file_index != ~0)
834 clib_file_main_t *fm = &file_main;
835 clib_file_t *f = clib_file_get (fm, nm->clib_file_index);
839 NL_INFO ("Stopping poll of fd %u", f->file_descriptor);
840 fm->file_update (f, UNIX_FILE_UPDATE_DELETE);
843 /* stored index was not a valid file, reset stored index to ~0 */
844 nm->clib_file_index = ~0;
847 /* If we already created a socket, close/free it */
850 NL_INFO ("Closing netlink socket %d", nl_socket_get_fd (nm->sk_route));
851 nl_socket_free (nm->sk_route);
857 lcp_nl_open_socket (void)
859 nl_main_t *nm = &nl_main;
860 int dest_ns_fd, curr_ns_fd;
862 /* Allocate a new socket for both routes and acls
863 * Notifications do not use sequence numbers, disable sequence number
865 * Define a callback function, which will be called for each notification
868 nm->sk_route = nl_socket_alloc ();
869 nl_socket_disable_seq_check (nm->sk_route);
871 dest_ns_fd = lcp_get_default_ns_fd ();
874 curr_ns_fd = open ("/proc/self/ns/net", O_RDONLY);
875 setns (dest_ns_fd, CLONE_NEWNET);
878 nl_connect (nm->sk_route, NETLINK_ROUTE);
880 if (dest_ns_fd && curr_ns_fd >= 0)
882 setns (curr_ns_fd, CLONE_NEWNET);
886 /* Subscribe to all the 'routing' notifications on the route socket */
887 nl_socket_add_memberships (nm->sk_route, RTNLGRP_LINK, RTNLGRP_IPV6_IFADDR,
888 RTNLGRP_IPV4_IFADDR, RTNLGRP_IPV4_ROUTE,
889 RTNLGRP_IPV6_ROUTE, RTNLGRP_NEIGH, RTNLGRP_NOTIFY,
890 #ifdef RTNLGRP_MPLS_ROUTE /* not defined on CentOS/RHEL 7 */
893 RTNLGRP_IPV4_RULE, RTNLGRP_IPV6_RULE, 0);
895 /* Set socket in nonblocking mode and increase buffer sizes */
896 nl_socket_set_nonblocking (nm->sk_route);
897 nl_socket_set_buffer_size (nm->sk_route, nm->rx_buf_size, nm->tx_buf_size);
899 if (nm->clib_file_index == ~0)
901 clib_file_t rt_file = {
902 .read_function = nl_route_read_cb,
903 .error_function = nl_route_error_cb,
904 .file_descriptor = nl_socket_get_fd (nm->sk_route),
905 .description = format (0, "linux-cp netlink route socket"),
908 nm->clib_file_index = clib_file_add (&file_main, &rt_file);
909 NL_INFO ("Added file %u", nm->clib_file_index);
912 /* clib file already created and socket was closed due to error */
914 clib_file_main_t *fm = &file_main;
915 clib_file_t *f = clib_file_get (fm, nm->clib_file_index);
917 f->file_descriptor = nl_socket_get_fd (nm->sk_route);
918 fm->file_update (f, UNIX_FILE_UPDATE_ADD);
919 NL_INFO ("Starting poll of %d", f->file_descriptor);
922 nl_socket_modify_cb (nm->sk_route, NL_CB_VALID, NL_CB_CUSTOM, nl_route_cb,
924 NL_INFO ("Opened netlink socket %d", nl_socket_get_fd (nm->sk_route));
928 lcp_nl_open_sync_socket (nl_sock_type_t sock_type)
930 nl_main_t *nm = &nl_main;
931 int dest_ns_fd, curr_ns_fd;
932 struct nl_sock *sk_route;
934 /* Allocate a new blocking socket for routes that will be used for dump
935 * requests. Buffer sizes are left default because replies to dump requests
936 * are flow-controlled and the kernel will not overflow the socket by sending
940 nm->sk_route_sync[sock_type] = sk_route = nl_socket_alloc ();
942 dest_ns_fd = lcp_get_default_ns_fd ();
945 curr_ns_fd = clib_netns_open (NULL /* self */);
946 if (clib_setns (dest_ns_fd) == -1)
947 NL_ERROR ("Cannot set destination ns");
950 nl_connect (sk_route, NETLINK_ROUTE);
954 if (curr_ns_fd == -1)
956 NL_ERROR ("No previous ns to set");
960 if (clib_setns (curr_ns_fd) == -1)
961 NL_ERROR ("Cannot set previous ns");
966 NL_INFO ("Opened netlink synchronization socket %d of type %d",
967 nl_socket_get_fd (sk_route), sock_type);
971 lcp_nl_close_sync_socket (nl_sock_type_t sock_type)
973 nl_main_t *nm = &nl_main;
974 struct nl_sock *sk_route = nm->sk_route_sync[sock_type];
978 NL_INFO ("Closing netlink synchronization socket %d of type %d",
979 nl_socket_get_fd (sk_route), sock_type);
980 nl_socket_free (sk_route);
981 nm->sk_route_sync[sock_type] = NULL;
985 #include <vnet/plugin/plugin.h>
987 lcp_nl_init (vlib_main_t *vm)
989 nl_main_t *nm = &nl_main;
990 lcp_itf_pair_vft_t nl_itf_pair_vft = {
991 .pair_add_fn = lcp_nl_pair_add_cb,
994 nm->nl_status = NL_STATUS_NOTIF_PROC;
995 nm->clib_file_index = ~0;
996 nm->nl_logger = vlib_log_register_class ("nl", "nl");
998 lcp_nl_open_socket ();
999 lcp_itf_pair_register_vft (&nl_itf_pair_vft);
1004 VLIB_INIT_FUNCTION (lcp_nl_init) = {
1005 .runs_after = VLIB_INITS ("lcp_interface_init", "tuntap_init",
1006 "ip_neighbor_init"),
1009 #include <vpp/app/version.h>
1010 VLIB_PLUGIN_REGISTER () = {
1011 .version = VPP_BUILD_VER,
1012 .description = "linux Control Plane - Netlink listener",
1013 .default_disabled = 1,
1017 * fd.io coding-style-patch-verification: ON
1020 * eval: (c-set-style "gnu")