linux-cp: Fix looping netlink messages
[vpp.git] / src / plugins / linux-cp / lcp_nl.c
1 /*
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:
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
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.
14  */
15
16 #define _GNU_SOURCE
17 #include <sched.h>
18 #include <fcntl.h>
19
20 #include <linux-cp/lcp_nl.h>
21
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>
30
31 #include <vlib/vlib.h>
32 #include <vlib/unix/unix.h>
33 #include <vppinfra/error.h>
34 #include <vppinfra/linux/netns.h>
35
36 #include <vnet/fib/fib_table.h>
37
38 #include <libmnl/libmnl.h>
39
40 #include <plugins/linux-cp/lcp_interface.h>
41
42 typedef enum nl_status_t_
43 {
44   NL_STATUS_NOTIF_PROC,
45   NL_STATUS_SYNC,
46 } nl_status_t;
47
48 typedef enum nl_sock_type_t_
49 {
50   NL_SOCK_TYPE_LINK,
51   NL_SOCK_TYPE_ADDR,
52   NL_SOCK_TYPE_NEIGH,
53   NL_SOCK_TYPE_ROUTE,
54 } nl_sock_type_t;
55
56 #define NL_SOCK_TYPES_N (NL_SOCK_TYPE_ROUTE + 1)
57
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)
64
65 typedef enum nl_event_type_t_
66 {
67   NL_EVENT_READ,
68   NL_EVENT_ERR,
69 } nl_event_type_t;
70
71 typedef struct nl_main
72 {
73
74   nl_status_t nl_status;
75
76   struct nl_sock *sk_route;
77   struct nl_sock *sk_route_sync[NL_SOCK_TYPES_N];
78   vlib_log_class_t nl_logger;
79   nl_vft_t *nl_vfts;
80   struct nl_cache *nl_caches[LCP_NL_N_OBJS];
81   nl_msg_info_t *nl_msg_queue;
82   uword clib_file_index;
83
84   u32 rx_buf_size;
85   u32 tx_buf_size;
86   u32 batch_size;
87   u32 batch_delay_ms;
88
89   u32 sync_batch_limit;
90   u32 sync_batch_delay_ms;
91   u32 sync_attempt_delay_ms;
92
93 } nl_main_t;
94
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 */
99
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 */
103
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,
112 };
113
114 /* #define foreach_nl_nft_proto  \ */
115 /*   _(IP4, "ip", AF_INT)  \ */
116 /*   _(IP6, "ip6", NFPROTO_IPV6) */
117
118 /* typedef enum nl_nft_proto_t_ */
119 /* { */
120 /* #define _(a,b,c) NL_NFT_PROTO_##a = c, */
121 /*   foreach_nl_nft_proto */
122 /* #undef _ */
123 /* } nl_nft_proto_t; */
124
125 #define FOREACH_VFT(__func, __arg)                                            \
126   {                                                                           \
127     nl_main_t *nm = &nl_main;                                                 \
128     nl_vft_t *__nv;                                                           \
129     vec_foreach (__nv, nm->nl_vfts)                                           \
130       {                                                                       \
131         if (!__nv->__func.cb)                                                 \
132           continue;                                                           \
133                                                                               \
134         if (!__nv->__func.is_mp_safe)                                         \
135           vlib_worker_thread_barrier_sync (vlib_get_main ());                 \
136                                                                               \
137         __nv->__func.cb (__arg);                                              \
138                                                                               \
139         if (!__nv->__func.is_mp_safe)                                         \
140           vlib_worker_thread_barrier_release (vlib_get_main ());              \
141       }                                                                       \
142   }
143
144 #define FOREACH_VFT_NO_ARG(__func)                                            \
145   {                                                                           \
146     nl_main_t *nm = &nl_main;                                                 \
147     nl_vft_t *__nv;                                                           \
148     vec_foreach (__nv, nm->nl_vfts)                                           \
149       {                                                                       \
150         if (!__nv->__func.cb)                                                 \
151           continue;                                                           \
152                                                                               \
153         if (!__nv->__func.is_mp_safe)                                         \
154           vlib_worker_thread_barrier_sync (vlib_get_main ());                 \
155                                                                               \
156         __nv->__func.cb ();                                                   \
157                                                                               \
158         if (!__nv->__func.is_mp_safe)                                         \
159           vlib_worker_thread_barrier_release (vlib_get_main ());              \
160       }                                                                       \
161   }
162
163 #define FOREACH_VFT_CTX(__func, __arg, __ctx)                                 \
164   {                                                                           \
165     nl_main_t *nm = &nl_main;                                                 \
166     nl_vft_t *__nv;                                                           \
167     vec_foreach (__nv, nm->nl_vfts)                                           \
168       {                                                                       \
169         if (!__nv->__func.cb)                                                 \
170           continue;                                                           \
171                                                                               \
172         if (!__nv->__func.is_mp_safe)                                         \
173           vlib_worker_thread_barrier_sync (vlib_get_main ());                 \
174                                                                               \
175         __nv->__func.cb (__arg, __ctx);                                       \
176                                                                               \
177         if (!__nv->__func.is_mp_safe)                                         \
178           vlib_worker_thread_barrier_release (vlib_get_main ());              \
179       }                                                                       \
180   }
181
182 void
183 nl_register_vft (const nl_vft_t *nv)
184 {
185   nl_main_t *nm = &nl_main;
186
187   vec_add1 (nm->nl_vfts, *nv);
188 }
189
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__);
193
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);
198
199 static void
200 nl_route_del (struct rtnl_route *rr, void *arg)
201 {
202   FOREACH_VFT (nvl_rt_route_del, rr);
203 }
204
205 static void
206 nl_route_add (struct rtnl_route *rr, void *arg)
207 {
208   int is_replace = 0;
209
210   if (arg)
211     {
212       nl_msg_info_t *msg_info = (nl_msg_info_t *) arg;
213       struct nlmsghdr *nlh = nlmsg_hdr (msg_info->msg);
214
215       is_replace = (nlh->nlmsg_flags & NLM_F_REPLACE);
216     }
217
218   FOREACH_VFT_CTX (nvl_rt_route_add, rr, is_replace);
219 }
220
221 static void
222 nl_route_sync_begin (void)
223 {
224   FOREACH_VFT_NO_ARG (nvl_rt_route_sync_begin);
225 }
226
227 static void
228 nl_route_sync_end (void)
229 {
230   FOREACH_VFT_NO_ARG (nvl_rt_route_sync_end);
231 }
232
233 static void
234 nl_neigh_del (struct rtnl_neigh *rn, void *arg)
235 {
236   FOREACH_VFT (nvl_rt_neigh_del, rn);
237 }
238
239 static void
240 nl_neigh_add (struct rtnl_neigh *rn, void *arg)
241 {
242   FOREACH_VFT (nvl_rt_neigh_add, rn);
243 }
244
245 static void
246 nl_neigh_sync_begin (void)
247 {
248   FOREACH_VFT_NO_ARG (nvl_rt_neigh_sync_begin);
249 }
250
251 static void
252 nl_neigh_sync_end (void)
253 {
254   FOREACH_VFT_NO_ARG (nvl_rt_neigh_sync_end);
255 }
256
257 static void
258 nl_link_addr_del (struct rtnl_addr *rla, void *arg)
259 {
260   FOREACH_VFT (nvl_rt_addr_del, rla);
261 }
262
263 static void
264 nl_link_addr_add (struct rtnl_addr *rla, void *arg)
265 {
266   FOREACH_VFT (nvl_rt_addr_add, rla);
267 }
268
269 static void
270 nl_link_addr_sync_begin (void)
271 {
272   FOREACH_VFT_NO_ARG (nvl_rt_addr_sync_begin);
273 }
274
275 static void
276 nl_link_addr_sync_end (void)
277 {
278   FOREACH_VFT_NO_ARG (nvl_rt_addr_sync_end);
279 }
280
281 static void
282 nl_link_del (struct rtnl_link *rl, void *arg)
283 {
284   FOREACH_VFT_CTX (nvl_rt_link_del, rl, arg);
285 }
286
287 static void
288 nl_link_add (struct rtnl_link *rl, void *arg)
289 {
290   FOREACH_VFT_CTX (nvl_rt_link_add, rl, arg);
291 }
292
293 static void
294 nl_link_sync_begin (void)
295 {
296   FOREACH_VFT_NO_ARG (nvl_rt_link_sync_begin);
297 }
298
299 static void
300 nl_link_sync_end (void)
301 {
302   FOREACH_VFT_NO_ARG (nvl_rt_link_sync_end);
303 }
304
305 static void
306 nl_route_dispatch (struct nl_object *obj, void *arg)
307 {
308   /* nothing can be done without interface mappings */
309   if (!lcp_itf_num_pairs ())
310     return;
311
312   switch (nl_object_get_msgtype (obj))
313     {
314     case RTM_NEWROUTE:
315       nl_route_add ((struct rtnl_route *) obj, arg);
316       break;
317     case RTM_DELROUTE:
318       nl_route_del ((struct rtnl_route *) obj, arg);
319       break;
320     case RTM_NEWNEIGH:
321       nl_neigh_add ((struct rtnl_neigh *) obj, arg);
322       break;
323     case RTM_DELNEIGH:
324       nl_neigh_del ((struct rtnl_neigh *) obj, arg);
325       break;
326     case RTM_NEWADDR:
327       nl_link_addr_add ((struct rtnl_addr *) obj, arg);
328       break;
329     case RTM_DELADDR:
330       nl_link_addr_del ((struct rtnl_addr *) obj, arg);
331       break;
332     case RTM_NEWLINK:
333       nl_link_add ((struct rtnl_link *) obj, arg);
334       break;
335     case RTM_DELLINK:
336       nl_link_del ((struct rtnl_link *) obj, arg);
337       break;
338     default:
339       NL_INFO ("unhandled: %s", nl_object_get_type (obj));
340       break;
341     }
342 }
343
344 static int
345 nl_route_process_msgs (void)
346 {
347   nl_main_t *nm = &nl_main;
348   nl_msg_info_t *msg_info;
349   int err, n_msgs = 0;
350
351   lcp_set_netlink_processing_active (1);
352
353   /* process a batch of messages. break if we hit our limit */
354   vec_foreach (msg_info, nm->nl_msg_queue)
355     {
356       if ((err = nl_msg_parse (msg_info->msg, nl_route_dispatch, msg_info)) <
357           0)
358         NL_ERROR ("Unable to parse object: %s", nl_geterror (err));
359       nlmsg_free (msg_info->msg);
360       if (++n_msgs >= nm->batch_size)
361         break;
362     }
363
364   /* remove the messages we processed from the head of the queue */
365   if (n_msgs)
366     vec_delete (nm->nl_msg_queue, n_msgs, 0);
367
368   NL_DBG ("Processed %u messages", n_msgs);
369
370   lcp_set_netlink_processing_active (0);
371
372   return n_msgs;
373 }
374
375 static int
376 lcp_nl_route_discard_msgs (void)
377 {
378   nl_main_t *nm = &nl_main;
379   nl_msg_info_t *msg_info;
380   int n_msgs;
381
382   n_msgs = vec_len (nm->nl_msg_queue);
383   if (n_msgs == 0)
384     return 0;
385
386   vec_foreach (msg_info, nm->nl_msg_queue)
387     {
388       nlmsg_free (msg_info->msg);
389     }
390
391   vec_reset_length (nm->nl_msg_queue);
392
393   NL_INFO ("Discarded %u messages", n_msgs);
394
395   return n_msgs;
396 }
397
398 static int
399 lcp_nl_route_send_dump_req (nl_sock_type_t sock_type, int msg_type)
400 {
401   nl_main_t *nm = &nl_main;
402   struct nl_sock *sk_route = nm->sk_route_sync[sock_type];
403   int err;
404   struct rtgenmsg rt_hdr = {
405     .rtgen_family = AF_UNSPEC,
406   };
407
408   err =
409     nl_send_simple (sk_route, msg_type, NLM_F_DUMP, &rt_hdr, sizeof (rt_hdr));
410
411   if (err < 0)
412     {
413       NL_ERROR ("Unable to send a dump request: %s", nl_geterror (err));
414     }
415   else
416     NL_INFO ("Dump request sent via socket %d of type %d",
417              nl_socket_get_fd (sk_route), sock_type);
418
419   return err;
420 }
421
422 static int
423 lcp_nl_route_dump_cb (struct nl_msg *msg, void *arg)
424 {
425   int err;
426
427   if ((err = nl_msg_parse (msg, nl_route_dispatch, NULL)) < 0)
428     NL_ERROR ("Unable to parse object: %s", nl_geterror (err));
429
430   return NL_OK;
431 }
432
433 static int
434 lcp_nl_recv_dump_replies (nl_sock_type_t sock_type, int msg_limit,
435                           int *is_done_rcvd)
436 {
437   nl_main_t *nm = &nl_main;
438   struct nl_sock *sk_route = nm->sk_route_sync[sock_type];
439   struct sockaddr_nl nla;
440   uint8_t *buf = NULL;
441   int n_bytes;
442   struct nlmsghdr *hdr;
443   struct nl_msg *msg = NULL;
444   int err = 0;
445   int done = 0;
446   int n_msgs = 0;
447
448   lcp_set_netlink_processing_active (1);
449
450 continue_reading:
451   n_bytes = nl_recv (sk_route, &nla, &buf, /* creds */ NULL);
452   if (n_bytes <= 0)
453     {
454       lcp_set_netlink_processing_active (0);
455       return n_bytes;
456     }
457
458   hdr = (struct nlmsghdr *) buf;
459   while (nlmsg_ok (hdr, n_bytes))
460     {
461       nlmsg_free (msg);
462       msg = nlmsg_convert (hdr);
463       if (!msg)
464         {
465           err = -NLE_NOMEM;
466           goto out;
467         }
468
469       n_msgs++;
470
471       nlmsg_set_proto (msg, NETLINK_ROUTE);
472       nlmsg_set_src (msg, &nla);
473
474       /* Message that terminates a multipart message. Finish parsing and signal
475        * the caller that all dump replies have been received
476        */
477       if (hdr->nlmsg_type == NLMSG_DONE)
478         {
479           done = 1;
480           goto out;
481         }
482       /* Message to be ignored. Continue parsing */
483       else if (hdr->nlmsg_type == NLMSG_NOOP)
484         ;
485       /* Message that indicates data was lost. Finish parsing and return an
486        * error
487        */
488       else if (hdr->nlmsg_type == NLMSG_OVERRUN)
489         {
490           err = -NLE_MSG_OVERFLOW;
491           goto out;
492         }
493       /* Message that indicates an error. Finish parsing, extract the error
494        * code, and return it */
495       else if (hdr->nlmsg_type == NLMSG_ERROR)
496         {
497           struct nlmsgerr *e = nlmsg_data (hdr);
498
499           if (hdr->nlmsg_len < nlmsg_size (sizeof (*e)))
500             {
501               err = -NLE_MSG_TRUNC;
502               goto out;
503             }
504           else if (e->error)
505             {
506               err = -nl_syserr2nlerr (e->error);
507               goto out;
508             }
509           /* Message is an acknowledgement (err_code = 0). Continue parsing */
510           else
511             ;
512         }
513       /* Message that contains the requested data. Pass it for processing and
514        * continue parsing
515        */
516       else
517         {
518           lcp_nl_route_dump_cb (msg, NULL);
519         }
520
521       hdr = nlmsg_next (hdr, &n_bytes);
522     }
523
524   nlmsg_free (msg);
525   free (buf);
526   msg = NULL;
527   buf = NULL;
528
529   if (!done && n_msgs < msg_limit)
530     goto continue_reading;
531
532 out:
533   lcp_set_netlink_processing_active (0);
534
535   nlmsg_free (msg);
536   free (buf);
537
538   if (err)
539     return err;
540
541   *is_done_rcvd = done;
542
543   return n_msgs;
544 }
545
546 #define DAY_F64 (1.0 * (24 * 60 * 60))
547
548 static uword
549 nl_route_process (vlib_main_t *vm, vlib_node_runtime_t *node,
550                   vlib_frame_t *frame)
551 {
552   nl_main_t *nm = &nl_main;
553   uword event_type;
554   uword *event_data = 0;
555   f64 wait_time = DAY_F64;
556   int n_msgs;
557   int is_done;
558
559   while (1)
560     {
561       if (nm->nl_status == NL_STATUS_NOTIF_PROC)
562         {
563           /* If we process a batch of messages and stop because we reached the
564            * batch size limit, we want to wake up after the batch delay and
565            * process more. Otherwise we just want to wait for a read event.
566            */
567           vlib_process_wait_for_event_or_clock (vm, wait_time);
568           event_type = vlib_process_get_events (vm, &event_data);
569           vec_reset_length (event_data);
570
571           switch (event_type)
572             {
573             /* Process batch of queued messages on timeout or read event
574              * signal
575              */
576             case ~0:
577             case NL_EVENT_READ:
578               nl_route_process_msgs ();
579               wait_time = (vec_len (nm->nl_msg_queue) != 0) ?
580                             nm->batch_delay_ms * 1e-3 :
581                             DAY_F64;
582               break;
583
584             /* Initiate synchronization if there was an error polling or
585              * reading the notification socket
586              */
587             case NL_EVENT_ERR:
588               nm->nl_status = NL_STATUS_SYNC;
589               break;
590
591             default:
592               NL_ERROR ("Unknown event type: %u", (u32) event_type);
593             }
594         }
595       else if (nm->nl_status == NL_STATUS_SYNC)
596         {
597           /* Stop processing notifications - close the notification socket and
598            * discard all messages that are currently in the queue
599            */
600           lcp_nl_close_socket ();
601           lcp_nl_route_discard_msgs ();
602
603           /* Wait some time before next synchronization attempt. Allows to
604            * reduce the number of failed attempts that stall the main thread by
605            * waiting out the notification storm
606            */
607           NL_INFO ("Wait before next synchronization attempt for %ums",
608                    nm->sync_attempt_delay_ms);
609           vlib_process_suspend (vm, nm->sync_attempt_delay_ms * 1e-3);
610
611           /* Open netlink synchronization socket, one for every data type of
612            * interest: link, address, neighbor, and route. That is needed to
613            * be able to send dump requests for every data type simultaneously.
614            * If send a dump request while the previous one is in progress,
615            * the request will fail and EBUSY returned
616            */
617 #define _(stype, mtype, tname, fn) lcp_nl_open_sync_socket (stype);
618           foreach_sock_type
619 #undef _
620
621           /* Start reading notifications and enqueueing them for further
622            * processing. The notifications will serve as a difference between
623            * the snapshot made after the dump request and the actual state at
624            * the moment. Once all the dump replies are processed, the
625            * notifications will be processed
626            */
627           lcp_nl_open_socket ();
628
629           /* Request the current entry set from the kernel for every data type
630            * of interest. Thus requesting a snapshot of the current routing
631            * state that the kernel will make and then reply with
632            */
633 #define _(stype, mtype, tname, fn) lcp_nl_route_send_dump_req (stype, mtype);
634           foreach_sock_type
635 #undef _
636
637           /* Process all the dump replies */
638 #define _(stype, mtype, tname, fn)                                            \
639   nl_##fn##_sync_begin ();                                                    \
640   is_done = 0;                                                                \
641   do                                                                          \
642     {                                                                         \
643       n_msgs =                                                                \
644         lcp_nl_recv_dump_replies (stype, nm->sync_batch_limit, &is_done);     \
645       if (n_msgs < 0)                                                         \
646         {                                                                     \
647           NL_ERROR ("Error receiving dump replies of type " tname             \
648                     ": %s (%d)",                                              \
649                     nl_geterror (n_msgs), n_msgs);                            \
650           break;                                                              \
651         }                                                                     \
652       else if (n_msgs == 0)                                                   \
653         {                                                                     \
654           NL_ERROR ("EOF while receiving dump replies of type " tname);       \
655           break;                                                              \
656         }                                                                     \
657       else                                                                    \
658         NL_INFO ("Processed %u dump replies of type " tname, n_msgs);         \
659                                                                               \
660       /* Suspend the processing loop and wait until event signal is           \
661        * received or timeout expires. During synchronization, only            \
662        * error event is expected because read event is suppressed.            \
663        * Allows not to stall the main thread and detect errors on the         \
664        * notification socket that will make synchronization                   \
665        * incomplete                                                           \
666        */                                                                     \
667       vlib_process_wait_for_event_or_clock (vm,                               \
668                                             nm->sync_batch_delay_ms * 1e-3);  \
669       event_type = vlib_process_get_events (vm, &event_data);                 \
670       vec_reset_length (event_data);                                          \
671                                                                               \
672       /* If error event received, stop synchronization and repeat an          \
673        * attempt later                                                        \
674        */                                                                     \
675       if (event_type == NL_EVENT_ERR)                                         \
676         goto sync_later;                                                      \
677     }                                                                         \
678   while (!is_done);                                                           \
679   nl_##fn##_sync_end ();
680
681             foreach_sock_type
682 #undef _
683
684               /* Start processing notifications */
685               nm->nl_status = NL_STATUS_NOTIF_PROC;
686
687           /* Trigger messages processing if there are notifications received
688            * during synchronization
689            */
690           wait_time = (vec_len (nm->nl_msg_queue) != 0) ? 1e-3 : DAY_F64;
691
692         sync_later:
693           /* Close netlink synchronization sockets */
694 #define _(stype, mtype, tname, fn) lcp_nl_close_sync_socket (stype);
695           foreach_sock_type
696 #undef _
697         }
698       else
699         NL_ERROR ("Unknown status: %d", nm->nl_status);
700     }
701   return frame->n_vectors;
702 }
703
704 VLIB_REGISTER_NODE (nl_route_process_node, static) = {
705   .function = nl_route_process,
706   .name = "linux-cp-netlink-process",
707   .type = VLIB_NODE_TYPE_PROCESS,
708   .process_log2_n_stack_bytes = 17,
709 };
710
711 static int
712 nl_route_cb (struct nl_msg *msg, void *arg)
713 {
714   nl_main_t *nm = &nl_main;
715   nl_msg_info_t *msg_info = 0;
716
717   /* delay processing - increment ref count and queue for later */
718   vec_add2 (nm->nl_msg_queue, msg_info, 1);
719
720   /* store a timestamp for the message */
721   msg_info->ts = vlib_time_now (vlib_get_main ());
722   msg_info->msg = msg;
723   nlmsg_get (msg);
724
725   return 0;
726 }
727
728 int
729 lcp_nl_drain_messages (void)
730 {
731   int err;
732   nl_main_t *nm = &nl_main;
733
734   /* Read until there's an error */
735   while ((err = nl_recvmsgs_default (nm->sk_route)) > -1)
736     ;
737
738   /* If there was an error other then EAGAIN, signal process node */
739   if (err != -NLE_AGAIN)
740     vlib_process_signal_event (vlib_get_main (), nl_route_process_node.index,
741                                NL_EVENT_ERR, 0);
742   else
743     {
744       /* If netlink notification processing is active, signal process node
745        * there were notifications read
746        */
747       if (nm->nl_status == NL_STATUS_NOTIF_PROC)
748         vlib_process_signal_event (
749           vlib_get_main (), nl_route_process_node.index, NL_EVENT_READ, 0);
750     }
751
752   return err;
753 }
754
755 void
756 lcp_nl_pair_add_cb (lcp_itf_pair_t *pair)
757 {
758   lcp_nl_drain_messages ();
759 }
760
761 static clib_error_t *
762 nl_route_read_cb (clib_file_t *f)
763 {
764   int err;
765   err = lcp_nl_drain_messages ();
766   if (err < 0 && err != -NLE_AGAIN)
767     NL_ERROR ("Error reading netlink socket (fd %d): %s (%d)",
768               f->file_descriptor, nl_geterror (err), err);
769
770   return 0;
771 }
772
773 static clib_error_t *
774 nl_route_error_cb (clib_file_t *f)
775 {
776   NL_ERROR ("Error polling netlink socket (fd %d)", f->file_descriptor);
777
778   /* notify process node */
779   vlib_process_signal_event (vlib_get_main (), nl_route_process_node.index,
780                              NL_EVENT_ERR, 0);
781
782   return clib_error_return (0, "Error polling netlink socket %d",
783                             f->file_descriptor);
784 }
785
786 struct nl_cache *
787 lcp_nl_get_cache (lcp_nl_obj_t t)
788 {
789   nl_main_t *nm = &nl_main;
790
791   return nm->nl_caches[t];
792 }
793
794 /* Set the RX buffer size to be used on the netlink socket */
795 void
796 lcp_nl_set_buffer_size (u32 buf_size)
797 {
798   nl_main_t *nm = &nl_main;
799
800   nm->rx_buf_size = buf_size;
801
802   if (nm->sk_route)
803     nl_socket_set_buffer_size (nm->sk_route, nm->rx_buf_size, nm->tx_buf_size);
804 }
805
806 /* Set the batch size - maximum netlink messages to process at one time */
807 void
808 lcp_nl_set_batch_size (u32 batch_size)
809 {
810   nl_main_t *nm = &nl_main;
811
812   nm->batch_size = batch_size;
813 }
814
815 /* Set the batch delay - how long to wait in ms between processing batches */
816 void
817 lcp_nl_set_batch_delay (u32 batch_delay_ms)
818 {
819   nl_main_t *nm = &nl_main;
820
821   nm->batch_delay_ms = batch_delay_ms;
822 }
823
824 static clib_error_t *
825 lcp_itf_pair_config (vlib_main_t *vm, unformat_input_t *input)
826 {
827   u32 buf_size, batch_size, batch_delay_ms;
828
829   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
830     {
831       if (unformat (input, "nl-rx-buffer-size %u", &buf_size))
832         lcp_nl_set_buffer_size (buf_size);
833       else if (unformat (input, "nl-batch-size %u", &batch_size))
834         lcp_nl_set_batch_size (batch_size);
835       else if (unformat (input, "nl-batch-delay-ms %u", &batch_delay_ms))
836         lcp_nl_set_batch_delay (batch_delay_ms);
837       else
838         return clib_error_return (0, "invalid netlink option: %U",
839                                   format_unformat_error, input);
840     }
841
842   return NULL;
843 }
844
845 VLIB_CONFIG_FUNCTION (lcp_itf_pair_config, "linux-nl");
846
847 static void
848 lcp_nl_close_socket (void)
849 {
850   nl_main_t *nm = &nl_main;
851
852   /* delete existing fd from epoll fd set */
853   if (nm->clib_file_index != ~0)
854     {
855       clib_file_main_t *fm = &file_main;
856       clib_file_t *f = clib_file_get (fm, nm->clib_file_index);
857
858       if (f)
859         {
860           NL_INFO ("Stopping poll of fd %u", f->file_descriptor);
861           fm->file_update (f, UNIX_FILE_UPDATE_DELETE);
862         }
863       else
864         /* stored index was not a valid file, reset stored index to ~0 */
865         nm->clib_file_index = ~0;
866     }
867
868   /* If we already created a socket, close/free it */
869   if (nm->sk_route)
870     {
871       NL_INFO ("Closing netlink socket %d", nl_socket_get_fd (nm->sk_route));
872       nl_socket_free (nm->sk_route);
873       nm->sk_route = NULL;
874     }
875 }
876
877 static void
878 lcp_nl_open_socket (void)
879 {
880   nl_main_t *nm = &nl_main;
881   int dest_ns_fd, curr_ns_fd;
882
883   /* Allocate a new socket for both routes and acls
884    * Notifications do not use sequence numbers, disable sequence number
885    * checking.
886    * Define a callback function, which will be called for each notification
887    * received
888    */
889   nm->sk_route = nl_socket_alloc ();
890   nl_socket_disable_seq_check (nm->sk_route);
891
892   dest_ns_fd = lcp_get_default_ns_fd ();
893   if (dest_ns_fd)
894     {
895       curr_ns_fd = open ("/proc/self/ns/net", O_RDONLY);
896       setns (dest_ns_fd, CLONE_NEWNET);
897     }
898
899   nl_connect (nm->sk_route, NETLINK_ROUTE);
900
901   if (dest_ns_fd && curr_ns_fd >= 0)
902     {
903       setns (curr_ns_fd, CLONE_NEWNET);
904       close (curr_ns_fd);
905     }
906
907   /* Subscribe to all the 'routing' notifications on the route socket */
908   nl_socket_add_memberships (nm->sk_route, RTNLGRP_LINK, RTNLGRP_IPV6_IFADDR,
909                              RTNLGRP_IPV4_IFADDR, RTNLGRP_IPV4_ROUTE,
910                              RTNLGRP_IPV6_ROUTE, RTNLGRP_NEIGH, RTNLGRP_NOTIFY,
911 #ifdef RTNLGRP_MPLS_ROUTE /* not defined on CentOS/RHEL 7 */
912                              RTNLGRP_MPLS_ROUTE,
913 #endif
914                              RTNLGRP_IPV4_RULE, RTNLGRP_IPV6_RULE, 0);
915
916   /* Set socket in nonblocking mode and increase buffer sizes */
917   nl_socket_set_nonblocking (nm->sk_route);
918   nl_socket_set_buffer_size (nm->sk_route, nm->rx_buf_size, nm->tx_buf_size);
919
920   if (nm->clib_file_index == ~0)
921     {
922       clib_file_t rt_file = {
923         .read_function = nl_route_read_cb,
924         .error_function = nl_route_error_cb,
925         .file_descriptor = nl_socket_get_fd (nm->sk_route),
926         .description = format (0, "linux-cp netlink route socket"),
927       };
928
929       nm->clib_file_index = clib_file_add (&file_main, &rt_file);
930       NL_INFO ("Added file %u", nm->clib_file_index);
931     }
932   else
933     /* clib file already created and socket was closed due to error */
934     {
935       clib_file_main_t *fm = &file_main;
936       clib_file_t *f = clib_file_get (fm, nm->clib_file_index);
937
938       f->file_descriptor = nl_socket_get_fd (nm->sk_route);
939       fm->file_update (f, UNIX_FILE_UPDATE_ADD);
940       NL_INFO ("Starting poll of %d", f->file_descriptor);
941     }
942
943   nl_socket_modify_cb (nm->sk_route, NL_CB_VALID, NL_CB_CUSTOM, nl_route_cb,
944                        NULL);
945   NL_INFO ("Opened netlink socket %d", nl_socket_get_fd (nm->sk_route));
946 }
947
948 static void
949 lcp_nl_open_sync_socket (nl_sock_type_t sock_type)
950 {
951   nl_main_t *nm = &nl_main;
952   int dest_ns_fd, curr_ns_fd;
953   struct nl_sock *sk_route;
954
955   /* Allocate a new blocking socket for routes that will be used for dump
956    * requests. Buffer sizes are left default because replies to dump requests
957    * are flow-controlled and the kernel will not overflow the socket by sending
958    * these
959    */
960
961   nm->sk_route_sync[sock_type] = sk_route = nl_socket_alloc ();
962
963   dest_ns_fd = lcp_get_default_ns_fd ();
964   if (dest_ns_fd > 0)
965     {
966       curr_ns_fd = clib_netns_open (NULL /* self */);
967       if (clib_setns (dest_ns_fd) == -1)
968         NL_ERROR ("Cannot set destination ns");
969     }
970
971   nl_connect (sk_route, NETLINK_ROUTE);
972
973   if (dest_ns_fd > 0)
974     {
975       if (curr_ns_fd == -1)
976         {
977           NL_ERROR ("No previous ns to set");
978         }
979       else
980         {
981           if (clib_setns (curr_ns_fd) == -1)
982             NL_ERROR ("Cannot set previous ns");
983           close (curr_ns_fd);
984         }
985     }
986
987   NL_INFO ("Opened netlink synchronization socket %d of type %d",
988            nl_socket_get_fd (sk_route), sock_type);
989 }
990
991 static void
992 lcp_nl_close_sync_socket (nl_sock_type_t sock_type)
993 {
994   nl_main_t *nm = &nl_main;
995   struct nl_sock *sk_route = nm->sk_route_sync[sock_type];
996
997   if (sk_route)
998     {
999       NL_INFO ("Closing netlink synchronization socket %d of type %d",
1000                nl_socket_get_fd (sk_route), sock_type);
1001       nl_socket_free (sk_route);
1002       nm->sk_route_sync[sock_type] = NULL;
1003     }
1004 }
1005
1006 #include <vnet/plugin/plugin.h>
1007 clib_error_t *
1008 lcp_nl_init (vlib_main_t *vm)
1009 {
1010   nl_main_t *nm = &nl_main;
1011   lcp_itf_pair_vft_t nl_itf_pair_vft = {
1012     .pair_add_fn = lcp_nl_pair_add_cb,
1013   };
1014
1015   nm->nl_status = NL_STATUS_NOTIF_PROC;
1016   nm->clib_file_index = ~0;
1017   nm->nl_logger = vlib_log_register_class ("nl", "nl");
1018
1019   lcp_nl_open_socket ();
1020   lcp_itf_pair_register_vft (&nl_itf_pair_vft);
1021
1022   return (NULL);
1023 }
1024
1025 VLIB_INIT_FUNCTION (lcp_nl_init) = {
1026   .runs_after = VLIB_INITS ("lcp_interface_init", "tuntap_init",
1027                             "ip_neighbor_init"),
1028 };
1029
1030 #include <vpp/app/version.h>
1031 VLIB_PLUGIN_REGISTER () = {
1032   .version = VPP_BUILD_VER,
1033   .description = "linux Control Plane - Netlink listener",
1034   .default_disabled = 1,
1035 };
1036
1037 /*
1038  * fd.io coding-style-patch-verification: ON
1039  *
1040  * Local Variables:
1041  * eval: (c-set-style "gnu")
1042  * End:
1043  */