blob: a29a7c6a4dad1c225b55a99606b3d5556156d6cb [file] [log] [blame]
Gabriel Oginski4e88e042022-06-29 12:54:30 +00001/*
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
42typedef struct private_kernel_vpp_net_t private_kernel_vpp_net_t;
43
44/**
45 * Private data of kernel_vpp_net implementation.
46 */
47struct 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 */
79typedef 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 */
94typedef 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 */
111typedef 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 */
121static iface_t *
122address2entry (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 */
149static status_t
150manage_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 */
243static bool
244addr_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 */
283static host_t *
284get_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
402METHOD (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
433METHOD (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
441METHOD (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
457METHOD (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
483METHOD (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
489METHOD (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
495METHOD (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
501METHOD (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
507METHOD (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
514METHOD (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
521static void
522iface_destroy (iface_t *this)
523{
524 this->addrs->destroy_offset (this->addrs, offsetof (host_t, destroy));
525 free (this);
526}
527
528METHOD (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 */
539static void
540update_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 {
Gabriel Oginski4e88e042022-06-29 12:54:30 +0000566 rmp = tmp;
Timur Celik20721172022-11-22 17:03:14 +0100567 tmp += 1;
Gabriel Oginski4e88e042022-06-29 12:54:30 +0000568 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 {
Gabriel Oginski4e88e042022-06-29 12:54:30 +0000585 rmp = tmp;
Timur Celik20721172022-11-22 17:03:14 +0100586 tmp += 1;
Gabriel Oginski4e88e042022-06-29 12:54:30 +0000587 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 */
603static void
604event_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 */
643static void *
644net_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
724kernel_vpp_net_t *
725kernel_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}