02f002a3183c4b91fe6785c4ee65628fc805fdeb
[vpp.git] / extras / strongswan / vpp_sswan / kernel_vpp_net.c
1 /*
2  * Copyright (c) 2022 Intel 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 #include <utils/debug.h>
17 #include <vlibapi/api.h>
18 #include <vlibmemory/api.h>
19 #include <threading/thread.h>
20 #include <threading/mutex.h>
21
22 #define vl_typedefs
23 #define vl_endianfun
24 /* Include the (first) vlib-api API definition layer */
25 #include <vlibmemory/vl_memory_api_h.h>
26 /* Include the current layer (third) vpp API definition layer */
27 #include <vpp/api/vpe_types.api.h>
28 #include <vpp/api/vpe.api.h>
29
30 #include <vnet/ip-neighbor/ip_neighbor.api_enum.h>
31 #include <vnet/ip-neighbor/ip_neighbor.api_types.h>
32 #include <vnet/ip/ip.api_enum.h>
33 #include <vnet/ip/ip.api_types.h>
34 #include <vnet/interface.api_enum.h>
35 #include <vnet/interface.api_types.h>
36 #undef vl_typedefs
37 #undef vl_endianfun
38
39 #include "kernel_vpp_net.h"
40 #include "kernel_vpp_shared.h"
41
42 typedef struct private_kernel_vpp_net_t private_kernel_vpp_net_t;
43
44 /**
45  * Private data of kernel_vpp_net implementation.
46  */
47 struct private_kernel_vpp_net_t
48 {
49
50   /**
51    * Public interface.
52    */
53   kernel_vpp_net_t public;
54
55   /**
56    * Mutex to access interface list
57    */
58   mutex_t *mutex;
59
60   /**
61    * Known interfaces, as iface_t
62    */
63   linked_list_t *ifaces;
64
65   /**
66    * Inteface update thread
67    */
68   thread_t *net_update;
69
70   /**
71    * TRUE if interface events enabled
72    */
73   bool events_on;
74 };
75
76 /**
77  * Interface entry
78  */
79 typedef struct
80 {
81   /** interface index */
82   uint32_t index;
83   /** interface name */
84   char if_name[64];
85   /** list of known addresses, as host_t */
86   linked_list_t *addrs;
87   /** TRUE if up */
88   bool up;
89 } iface_t;
90
91 /**
92  * Address enumerator
93  */
94 typedef struct
95 {
96   /** implements enumerator_t */
97   enumerator_t public;
98   /** what kind of address should we enumerate? */
99   kernel_address_type_t which;
100   /** enumerator over interfaces */
101   enumerator_t *ifaces;
102   /** current enumerator over addresses, or NULL */
103   enumerator_t *addrs;
104   /** mutex to unlock on destruction */
105   mutex_t *mutex;
106 } addr_enumerator_t;
107
108 /**
109  * FIB path entry
110  */
111 typedef struct
112 {
113   chunk_t next_hop;
114   uint32_t sw_if_index;
115   uint8_t preference;
116 } fib_path_t;
117
118 /**
119  * Get an iface entry for a local address
120  */
121 static iface_t *
122 address2entry (private_kernel_vpp_net_t *this, host_t *ip)
123 {
124   enumerator_t *ifaces, *addrs;
125   iface_t *entry, *found = NULL;
126   host_t *host;
127
128   ifaces = this->ifaces->create_enumerator (this->ifaces);
129   while (!found && ifaces->enumerate (ifaces, &entry))
130     {
131       addrs = entry->addrs->create_enumerator (entry->addrs);
132       while (!found && addrs->enumerate (addrs, &host))
133         {
134           if (host->ip_equals (host, ip))
135             {
136               found = entry;
137             }
138         }
139       addrs->destroy (addrs);
140     }
141   ifaces->destroy (ifaces);
142
143   return found;
144 }
145
146 /**
147  * Add or remove a route
148  */
149 static status_t
150 manage_route (private_kernel_vpp_net_t *this, bool add, chunk_t dst,
151               uint8_t prefixlen, host_t *gtw, char *name)
152 {
153   char *out;
154   int out_len;
155   enumerator_t *enumerator;
156   iface_t *entry;
157   vl_api_ip_route_add_del_t *mp;
158   vl_api_ip_route_add_del_reply_t *rmp;
159   vl_api_fib_path_t *apath;
160   bool exists = FALSE;
161
162   this->mutex->lock (this->mutex);
163   enumerator = this->ifaces->create_enumerator (this->ifaces);
164   while (enumerator->enumerate (enumerator, &entry))
165     {
166       if (streq (name, entry->if_name))
167         {
168           exists = TRUE;
169           break;
170         }
171     }
172   enumerator->destroy (enumerator);
173   this->mutex->unlock (this->mutex);
174
175   if (!exists)
176     {
177       DBG1 (DBG_NET, "if_name %s not found", name);
178       return NOT_FOUND;
179     }
180
181   mp = vl_msg_api_alloc (sizeof (*mp) + sizeof (*apath));
182   memset (mp, 0, sizeof (*mp) + sizeof (*apath));
183   u16 msg_id = vl_msg_api_get_msg_index ((u8 *) "ip_route_add_del_b8ecfe0d");
184   mp->_vl_msg_id = ntohs (msg_id);
185   mp->is_add = add;
186   mp->route.prefix.len = prefixlen;
187   mp->route.n_paths = 1;
188   apath = &mp->route.paths[0];
189   apath->sw_if_index = ntohl (entry->index);
190   apath->rpf_id = ~0;
191   apath->weight = 1;
192   switch (dst.len)
193     {
194     case 4:
195       mp->route.prefix.address.af = ntohl (ADDRESS_IP4);
196       memcpy (&mp->route.prefix.address.un.ip4, dst.ptr, dst.len);
197       if (gtw)
198         {
199           chunk_t addr = gtw->get_address (gtw);
200           apath->proto = ntohl (FIB_API_PATH_NH_PROTO_IP4);
201           memcpy (&apath->nh.address.ip4, addr.ptr, dst.len);
202         }
203       break;
204     case 16:
205       mp->route.prefix.address.af = ntohl (ADDRESS_IP6);
206       memcpy (&mp->route.prefix.address.un.ip6, dst.ptr, dst.len);
207       if (gtw)
208         {
209           chunk_t addr = gtw->get_address (gtw);
210           apath->proto = ntohl (FIB_API_PATH_NH_PROTO_IP6);
211           memcpy (&apath->nh.address.ip6, addr.ptr, dst.len);
212         }
213       break;
214     default:
215       vl_msg_api_free (mp);
216       return FAILED;
217     }
218
219   if (vac->send (vac, (char *) mp, sizeof (*mp) + sizeof (*apath), &out,
220                  &out_len))
221     {
222       DBG1 (DBG_KNL, "vac %sing route failed", add ? "add" : "remov");
223       vl_msg_api_free (mp);
224       return FAILED;
225     }
226   rmp = (void *) out;
227   vl_msg_api_free (mp);
228   if (rmp->retval)
229     {
230       DBG1 (DBG_KNL, "%s route failed %d", add ? "add" : "delete",
231             ntohl (rmp->retval));
232       free (out);
233       return FAILED;
234     }
235   free (out);
236   return SUCCESS;
237 }
238
239 /**
240  * Check if an address or net (addr with prefix net bits) is in
241  * subnet (net with net_len net bits)
242  */
243 static bool
244 addr_in_subnet (chunk_t addr, int prefix, chunk_t net, int net_len)
245 {
246   static const u_char mask[] = {
247     0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe
248   };
249   int byte = 0;
250
251   if (net_len == 0)
252     { /* any address matches a /0 network */
253       return TRUE;
254     }
255   if (addr.len != net.len || net_len > 8 * net.len || prefix < net_len)
256     {
257       return FALSE;
258     }
259   /* scan through all bytes in network order */
260   while (net_len > 0)
261     {
262       if (net_len < 8)
263         {
264           return (mask[net_len] & addr.ptr[byte]) ==
265                  (mask[net_len] & net.ptr[byte]);
266         }
267       else
268         {
269           if (addr.ptr[byte] != net.ptr[byte])
270             {
271               return FALSE;
272             }
273           byte++;
274           net_len -= 8;
275         }
276     }
277   return TRUE;
278 }
279
280 /**
281  * Get a route: If "nexthop" the nexthop is returned, source addr otherwise
282  */
283 static host_t *
284 get_route (private_kernel_vpp_net_t *this, host_t *dest, int prefix,
285            bool nexthop, char **iface, host_t *src)
286 {
287   fib_path_t path;
288   char *out, *tmp;
289   int out_len, i, num;
290   vl_api_fib_path_t *fp;
291   host_t *addr = NULL;
292   enumerator_t *enumerator;
293   iface_t *entry;
294   int family;
295
296   path.sw_if_index = ~0;
297   path.preference = ~0;
298   path.next_hop = chunk_empty;
299
300   vl_api_ip_route_dump_t *mp;
301   vl_api_ip_route_details_t *rmp;
302
303   mp = vl_msg_api_alloc (sizeof (*mp));
304   clib_memset (mp, 0, sizeof (*mp));
305   u16 msg_id = vl_msg_api_get_msg_index ((u8 *) "ip_route_dump_b9d2e09e");
306   mp->_vl_msg_id = htons (msg_id);
307   mp->table.is_ip6 = dest->get_family (dest) == AF_INET6 ? 1 : 0;
308   if (vac->send_dump (vac, (char *) mp, sizeof (*mp), &out, &out_len))
309     {
310       vl_msg_api_free (mp);
311       DBG2 (DBG_KNL, "send VL_API_IP_ROUTE_ADD_DEL failed");
312       return NULL;
313     }
314   vl_msg_api_free (mp);
315
316   if (dest->get_family (dest) == AF_INET)
317     {
318       i = 0;
319       family = AF_INET;
320       if (prefix == -1)
321         prefix = 32;
322
323       tmp = out;
324       while (tmp < (out + out_len))
325         {
326           rmp = (void *) tmp;
327           num = rmp->route.n_paths;
328
329           if (rmp->route.prefix.len &&
330               addr_in_subnet (
331                 dest->get_address (dest), prefix,
332                 chunk_create (rmp->route.prefix.address.un.ip4, 4),
333                 rmp->route.prefix.len))
334             {
335               fp = rmp->route.paths;
336               for (i = 0; i < num; i++)
337                 {
338 #define IS_IP4_ANY(a) (a[0] == 0 && a[1] == 0 && a[2] == 0 & a[3] == 0)
339                   if (fp->type == FIB_API_PATH_TYPE_DROP)
340                     {
341                       fp++;
342                       continue;
343                     }
344                   if ((fp->preference < path.preference) ||
345                       (path.sw_if_index == ~0) ||
346                       IS_IP4_ANY (path.next_hop.ptr))
347                     {
348                       path.sw_if_index = ntohl (fp->sw_if_index);
349                       path.preference = fp->preference;
350                       if (path.next_hop.ptr)
351                         vl_msg_api_free (path.next_hop.ptr);
352                       path.next_hop = chunk_create (fp->nh.address.ip4, 4);
353                     }
354                   fp++;
355                 }
356             }
357           tmp += sizeof (*rmp) + (sizeof (*fp) * num);
358         }
359     }
360   else
361     {
362       DBG1 (DBG_KNL, "not yet support ip6");
363       return NULL;
364     }
365
366   if (path.next_hop.len)
367     {
368       if (nexthop)
369         {
370           if (iface)
371             {
372               *iface = NULL;
373               this->mutex->lock (this->mutex);
374               enumerator = this->ifaces->create_enumerator (this->ifaces);
375               while (enumerator->enumerate (enumerator, &entry))
376                 {
377                   if (entry->index == path.sw_if_index)
378                     {
379                       *iface = strdup (entry->if_name);
380                       break;
381                     }
382                 }
383               enumerator->destroy (enumerator);
384               this->mutex->unlock (this->mutex);
385             }
386           addr = host_create_from_chunk (family, path.next_hop, 0);
387         }
388       else
389         {
390           if (src)
391             {
392               addr = src->clone (src);
393             }
394         }
395     }
396
397   free (out);
398
399   return addr;
400 }
401
402 METHOD (enumerator_t, addr_enumerate, bool, addr_enumerator_t *this,
403         va_list args)
404 {
405   iface_t *entry;
406   host_t **host;
407
408   VA_ARGS_VGET (args, host);
409
410   while (TRUE)
411     {
412       while (!this->addrs)
413         {
414           if (!this->ifaces->enumerate (this->ifaces, &entry))
415             {
416               return FALSE;
417             }
418           if (!entry->up && !(this->which & ADDR_TYPE_DOWN))
419             {
420               continue;
421             }
422           this->addrs = entry->addrs->create_enumerator (entry->addrs);
423         }
424       if (this->addrs->enumerate (this->addrs, host))
425         {
426           return TRUE;
427         }
428       this->addrs->destroy (this->addrs);
429       this->addrs = NULL;
430     }
431 }
432
433 METHOD (enumerator_t, addr_destroy, void, addr_enumerator_t *this)
434 {
435   DESTROY_IF (this->addrs);
436   this->ifaces->destroy (this->ifaces);
437   this->mutex->unlock (this->mutex);
438   free (this);
439 }
440
441 METHOD (kernel_net_t, get_interface_name, bool, private_kernel_vpp_net_t *this,
442         host_t *ip, char **name)
443 {
444   iface_t *entry;
445
446   this->mutex->lock (this->mutex);
447   entry = address2entry (this, ip);
448   if (entry && name)
449     {
450       *name = strdup (entry->if_name);
451     }
452   this->mutex->unlock (this->mutex);
453
454   return entry != NULL;
455 }
456
457 METHOD (kernel_net_t, create_address_enumerator, enumerator_t *,
458         private_kernel_vpp_net_t *this, kernel_address_type_t which)
459 {
460   addr_enumerator_t *enumerator;
461
462   if (!(which & ADDR_TYPE_REGULAR))
463     {
464       /* we currently have no virtual, but regular IPs only */
465       return enumerator_create_empty ();
466     }
467
468   this->mutex->lock (this->mutex);
469
470   INIT(enumerator,
471         .public = {
472             .enumerate = enumerator_enumerate_default,
473             .venumerate = _addr_enumerate,
474             .destroy = _addr_destroy,
475         },
476         .which = which,
477         .ifaces = this->ifaces->create_enumerator(this->ifaces),
478         .mutex = this->mutex,
479     );
480   return &enumerator->public;
481 }
482
483 METHOD (kernel_net_t, get_source_addr, host_t *,
484         private_kernel_vpp_net_t *this, host_t *dest, host_t *src)
485 {
486   return get_route (this, dest, -1, FALSE, NULL, src);
487 }
488
489 METHOD (kernel_net_t, get_nexthop, host_t *, private_kernel_vpp_net_t *this,
490         host_t *dest, int prefix, host_t *src, char **iface)
491 {
492   return get_route (this, dest, prefix, TRUE, iface, src);
493 }
494
495 METHOD (kernel_net_t, add_ip, status_t, private_kernel_vpp_net_t *this,
496         host_t *virtual_ip, int prefix, char *iface_name)
497 {
498   return NOT_SUPPORTED;
499 }
500
501 METHOD (kernel_net_t, del_ip, status_t, private_kernel_vpp_net_t *this,
502         host_t *virtual_ip, int prefix, bool wait)
503 {
504   return NOT_SUPPORTED;
505 }
506
507 METHOD (kernel_net_t, add_route, status_t, private_kernel_vpp_net_t *this,
508         chunk_t dst_net, u_int8_t prefixlen, host_t *gateway, host_t *src_ip,
509         char *if_name)
510 {
511   return manage_route (this, TRUE, dst_net, prefixlen, gateway, if_name);
512 }
513
514 METHOD (kernel_net_t, del_route, status_t, private_kernel_vpp_net_t *this,
515         chunk_t dst_net, u_int8_t prefixlen, host_t *gateway, host_t *src_ip,
516         char *if_name)
517 {
518   return manage_route (this, FALSE, dst_net, prefixlen, gateway, if_name);
519 }
520
521 static void
522 iface_destroy (iface_t *this)
523 {
524   this->addrs->destroy_offset (this->addrs, offsetof (host_t, destroy));
525   free (this);
526 }
527
528 METHOD (kernel_net_t, destroy, void, private_kernel_vpp_net_t *this)
529 {
530   this->net_update->cancel (this->net_update);
531   this->mutex->destroy (this->mutex);
532   this->ifaces->destroy_function (this->ifaces, (void *) iface_destroy);
533   free (this);
534 }
535
536 /**
537  * Update addresses for an iface entry
538  */
539 static void
540 update_addrs (private_kernel_vpp_net_t *this, iface_t *entry)
541 {
542   char *out;
543   int out_len, i, num;
544   vl_api_ip_address_dump_t *mp;
545   vl_api_ip_address_details_t *rmp, *tmp;
546   linked_list_t *addrs;
547   host_t *host;
548
549   mp = vl_msg_api_alloc (sizeof (*mp));
550   clib_memset (mp, 0, sizeof (*mp));
551   u16 msg_id = vl_msg_api_get_msg_index ((u8 *) "ip_address_dump_2d033de4");
552   mp->_vl_msg_id = htons (msg_id);
553   mp->sw_if_index = htonl (entry->index);
554   mp->is_ipv6 = 0;
555   if (vac->send_dump (vac, (char *) mp, sizeof (*mp), &out, &out_len))
556     {
557       DBG2 (DBG_NET, "update_addrs : send VL_API_IP_ADDRESS_DUMP ipv4 failed");
558       vl_msg_api_free (mp);
559       return;
560     }
561   num = out_len / sizeof (*rmp);
562   addrs = linked_list_create ();
563   tmp = (vl_api_ip_address_details_t *) out;
564   for (i = 0; i < num; i++)
565     {
566       tmp += i;
567       rmp = tmp;
568       host = host_create_from_chunk (
569         AF_INET, chunk_create (rmp->prefix.address.un.ip4, 4), 0);
570       addrs->insert_last (addrs, host);
571     }
572   free (out);
573
574   mp->is_ipv6 = 1;
575   if (vac->send_dump (vac, (char *) mp, sizeof (*mp), &out, &out_len))
576     {
577       DBG2 (DBG_NET, "update_addrs : send VL_API_IP_ADDRESS_DUMP ipv6 failed");
578       vl_msg_api_free (mp);
579       return;
580     }
581   num = out_len / sizeof (*rmp);
582   tmp = (vl_api_ip_address_details_t *) out;
583   for (i = 0; i < num; i++)
584     {
585       tmp += i;
586       rmp = tmp;
587       host = host_create_from_chunk (
588         AF_INET6, chunk_create (rmp->prefix.address.un.ip6, 16), 0);
589       addrs->insert_last (addrs, host);
590     }
591   vl_msg_api_free (mp);
592   free (out);
593
594   entry->addrs->destroy (entry->addrs);
595   entry->addrs =
596     linked_list_create_from_enumerator (addrs->create_enumerator (addrs));
597   addrs->destroy (addrs);
598 }
599
600 /**
601  * VPP API interface event callback
602  */
603 static void
604 event_cb (char *data, int data_len, void *ctx)
605 {
606   private_kernel_vpp_net_t *this = ctx;
607   vl_api_sw_interface_event_t *event;
608   iface_t *entry;
609   enumerator_t *enumerator;
610
611   event = (void *) data;
612   this->mutex->lock (this->mutex);
613   enumerator = this->ifaces->create_enumerator (this->ifaces);
614   while (enumerator->enumerate (enumerator, &entry))
615     {
616       if (entry->index == ntohl (event->sw_if_index))
617         {
618           if (event->deleted)
619             {
620               this->ifaces->remove_at (this->ifaces, enumerator);
621               DBG2 (DBG_NET, "interface deleted %u %s", entry->index,
622                     entry->if_name);
623               iface_destroy (entry);
624             }
625           else if (entry->up != (event->flags & IF_STATUS_API_FLAG_LINK_UP))
626             {
627               entry->up =
628                 (event->flags & IF_STATUS_API_FLAG_LINK_UP) ? TRUE : FALSE;
629               DBG2 (DBG_NET, "interface state changed %u %s %s", entry->index,
630                     entry->if_name, entry->up ? "UP" : "DOWN");
631             }
632           break;
633         }
634     }
635   enumerator->destroy (enumerator);
636   this->mutex->unlock (this->mutex);
637   free (data);
638 }
639
640 /**
641  * Inteface update thread (update interface list and interface address)
642  */
643 static void *
644 net_update_thread_fn (private_kernel_vpp_net_t *this)
645 {
646   status_t rv;
647   while (1)
648     {
649       char *out;
650       int out_len;
651       vl_api_sw_interface_dump_t *mp;
652       vl_api_sw_interface_details_t *rmp;
653       enumerator_t *enumerator;
654       iface_t *entry;
655
656       mp = vl_msg_api_alloc (sizeof (*mp));
657       memset (mp, 0, sizeof (*mp));
658       u16 msg_id =
659         vl_msg_api_get_msg_index ((u8 *) "sw_interface_dump_aa610c27");
660       mp->_vl_msg_id = htons (msg_id);
661       mp->name_filter_valid = 0;
662       rv = vac->send_dump (vac, (u8 *) mp, sizeof (*mp), &out, &out_len);
663       if (!rv)
664         {
665           int i, num;
666           this->mutex->lock (this->mutex);
667           enumerator = this->ifaces->create_enumerator (this->ifaces);
668           num = out_len / sizeof (*rmp);
669           rmp = (vl_api_sw_interface_details_t *) out;
670           for (i = 0; i < num; i++)
671             {
672               bool exists = FALSE;
673               if (i)
674                 rmp += 1;
675               while (enumerator->enumerate (enumerator, &entry))
676                 {
677                   if (entry->index == ntohl (rmp->sw_if_index))
678                     {
679                       exists = TRUE;
680                       break;
681                     }
682                 }
683               if (!exists)
684                 {
685                   INIT (entry, .index = ntohl (rmp->sw_if_index),
686                         .up = (rmp->flags & IF_STATUS_API_FLAG_LINK_UP) ?
687                                       TRUE :
688                                       FALSE,
689                         .addrs = linked_list_create (), );
690                   memcpy (entry->if_name, rmp->interface_name, 63);
691                   this->ifaces->insert_last (this->ifaces, entry);
692                 }
693               update_addrs (this, entry);
694             }
695           enumerator->destroy (enumerator);
696           this->mutex->unlock (this->mutex);
697           free (out);
698         }
699       vl_msg_api_free (mp);
700
701       if (!this->events_on)
702         {
703           vl_api_want_interface_events_t *emp;
704           api_main_t *am = vlibapi_get_main ();
705
706           emp = vl_msg_api_alloc (sizeof (*emp));
707           clib_memset (emp, 0, sizeof (*emp));
708           u16 msg_id =
709             vl_msg_api_get_msg_index ((u8 *) "want_interface_events_476f5a08");
710           emp->_vl_msg_id = ntohs (msg_id);
711           emp->enable_disable = 1;
712           emp->pid = ntohl (am->our_pid);
713           rv = vac->register_event (vac, (char *) emp, sizeof (*emp), event_cb,
714                                     VL_API_SW_INTERFACE_EVENT, this);
715           if (!rv)
716             this->events_on = TRUE;
717         }
718
719       sleep (2);
720     }
721   return NULL;
722 }
723
724 kernel_vpp_net_t *
725 kernel_vpp_net_create ()
726 {
727   private_kernel_vpp_net_t *this;
728
729   INIT(this,
730         .public = {
731             .interface = {
732                 .get_interface = _get_interface_name,
733                 .create_address_enumerator = _create_address_enumerator,
734                 .get_source_addr = _get_source_addr,
735                 .get_nexthop = _get_nexthop,
736                 .add_ip = _add_ip,
737                 .del_ip = _del_ip,
738                 .add_route = _add_route,
739                 .del_route = _del_route,
740                 .destroy = _destroy,
741             },
742         },
743         .mutex = mutex_create(MUTEX_TYPE_DEFAULT),
744         .ifaces = linked_list_create(),
745         .events_on = FALSE,
746     );
747
748   this->net_update =
749     thread_create ((thread_main_t) net_update_thread_fn, this);
750
751   return &this->public;
752 }