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:
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.
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>
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>
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>
39 #include "kernel_vpp_net.h"
40 #include "kernel_vpp_shared.h"
42 typedef struct private_kernel_vpp_net_t private_kernel_vpp_net_t;
45 * Private data of kernel_vpp_net implementation.
47 struct private_kernel_vpp_net_t
53 kernel_vpp_net_t public;
56 * Mutex to access interface list
61 * Known interfaces, as iface_t
63 linked_list_t *ifaces;
66 * Inteface update thread
71 * TRUE if interface events enabled
81 /** interface index */
85 /** list of known addresses, as host_t */
96 /** implements enumerator_t */
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 */
104 /** mutex to unlock on destruction */
114 uint32_t sw_if_index;
119 * Get an iface entry for a local address
122 address2entry (private_kernel_vpp_net_t *this, host_t *ip)
124 enumerator_t *ifaces, *addrs;
125 iface_t *entry, *found = NULL;
128 ifaces = this->ifaces->create_enumerator (this->ifaces);
129 while (!found && ifaces->enumerate (ifaces, &entry))
131 addrs = entry->addrs->create_enumerator (entry->addrs);
132 while (!found && addrs->enumerate (addrs, &host))
134 if (host->ip_equals (host, ip))
139 addrs->destroy (addrs);
141 ifaces->destroy (ifaces);
147 * Add or remove a route
150 manage_route (private_kernel_vpp_net_t *this, bool add, chunk_t dst,
151 uint8_t prefixlen, host_t *gtw, char *name)
155 enumerator_t *enumerator;
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;
162 this->mutex->lock (this->mutex);
163 enumerator = this->ifaces->create_enumerator (this->ifaces);
164 while (enumerator->enumerate (enumerator, &entry))
166 if (streq (name, entry->if_name))
172 enumerator->destroy (enumerator);
173 this->mutex->unlock (this->mutex);
177 DBG1 (DBG_NET, "if_name %s not found", name);
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);
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);
195 mp->route.prefix.address.af = ntohl (ADDRESS_IP4);
196 memcpy (&mp->route.prefix.address.un.ip4, dst.ptr, dst.len);
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);
205 mp->route.prefix.address.af = ntohl (ADDRESS_IP6);
206 memcpy (&mp->route.prefix.address.un.ip6, dst.ptr, dst.len);
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);
215 vl_msg_api_free (mp);
219 if (vac->send (vac, (char *) mp, sizeof (*mp) + sizeof (*apath), &out,
222 DBG1 (DBG_KNL, "vac %sing route failed", add ? "add" : "remov");
223 vl_msg_api_free (mp);
227 vl_msg_api_free (mp);
230 DBG1 (DBG_KNL, "%s route failed %d", add ? "add" : "delete",
231 ntohl (rmp->retval));
240 * Check if an address or net (addr with prefix net bits) is in
241 * subnet (net with net_len net bits)
244 addr_in_subnet (chunk_t addr, int prefix, chunk_t net, int net_len)
246 static const u_char mask[] = {
247 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe
252 { /* any address matches a /0 network */
255 if (addr.len != net.len || net_len > 8 * net.len || prefix < net_len)
259 /* scan through all bytes in network order */
264 return (mask[net_len] & addr.ptr[byte]) ==
265 (mask[net_len] & net.ptr[byte]);
269 if (addr.ptr[byte] != net.ptr[byte])
281 * Get a route: If "nexthop" the nexthop is returned, source addr otherwise
284 get_route (private_kernel_vpp_net_t *this, host_t *dest, int prefix,
285 bool nexthop, char **iface, host_t *src)
290 vl_api_fib_path_t *fp;
292 enumerator_t *enumerator;
296 path.sw_if_index = ~0;
297 path.preference = ~0;
298 path.next_hop = chunk_empty;
300 vl_api_ip_route_dump_t *mp;
301 vl_api_ip_route_details_t *rmp;
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))
310 vl_msg_api_free (mp);
311 DBG2 (DBG_KNL, "send VL_API_IP_ROUTE_ADD_DEL failed");
314 vl_msg_api_free (mp);
316 if (dest->get_family (dest) == AF_INET)
324 while (tmp < (out + out_len))
327 num = rmp->route.n_paths;
329 if (rmp->route.prefix.len &&
331 dest->get_address (dest), prefix,
332 chunk_create (rmp->route.prefix.address.un.ip4, 4),
333 rmp->route.prefix.len))
335 fp = rmp->route.paths;
336 for (i = 0; i < num; i++)
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)
344 if ((fp->preference < path.preference) ||
345 (path.sw_if_index == ~0) ||
346 IS_IP4_ANY (path.next_hop.ptr))
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);
357 tmp += sizeof (*rmp) + (sizeof (*fp) * num);
362 DBG1 (DBG_KNL, "not yet support ip6");
366 if (path.next_hop.len)
373 this->mutex->lock (this->mutex);
374 enumerator = this->ifaces->create_enumerator (this->ifaces);
375 while (enumerator->enumerate (enumerator, &entry))
377 if (entry->index == path.sw_if_index)
379 *iface = strdup (entry->if_name);
383 enumerator->destroy (enumerator);
384 this->mutex->unlock (this->mutex);
386 addr = host_create_from_chunk (family, path.next_hop, 0);
392 addr = src->clone (src);
402 METHOD (enumerator_t, addr_enumerate, bool, addr_enumerator_t *this,
408 VA_ARGS_VGET (args, host);
414 if (!this->ifaces->enumerate (this->ifaces, &entry))
418 if (!entry->up && !(this->which & ADDR_TYPE_DOWN))
422 this->addrs = entry->addrs->create_enumerator (entry->addrs);
424 if (this->addrs->enumerate (this->addrs, host))
428 this->addrs->destroy (this->addrs);
433 METHOD (enumerator_t, addr_destroy, void, addr_enumerator_t *this)
435 DESTROY_IF (this->addrs);
436 this->ifaces->destroy (this->ifaces);
437 this->mutex->unlock (this->mutex);
441 METHOD (kernel_net_t, get_interface_name, bool, private_kernel_vpp_net_t *this,
442 host_t *ip, char **name)
446 this->mutex->lock (this->mutex);
447 entry = address2entry (this, ip);
450 *name = strdup (entry->if_name);
452 this->mutex->unlock (this->mutex);
454 return entry != NULL;
457 METHOD (kernel_net_t, create_address_enumerator, enumerator_t *,
458 private_kernel_vpp_net_t *this, kernel_address_type_t which)
460 addr_enumerator_t *enumerator;
462 if (!(which & ADDR_TYPE_REGULAR))
464 /* we currently have no virtual, but regular IPs only */
465 return enumerator_create_empty ();
468 this->mutex->lock (this->mutex);
472 .enumerate = enumerator_enumerate_default,
473 .venumerate = _addr_enumerate,
474 .destroy = _addr_destroy,
477 .ifaces = this->ifaces->create_enumerator(this->ifaces),
478 .mutex = this->mutex,
480 return &enumerator->public;
483 METHOD (kernel_net_t, get_source_addr, host_t *,
484 private_kernel_vpp_net_t *this, host_t *dest, host_t *src)
486 return get_route (this, dest, -1, FALSE, NULL, src);
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)
492 return get_route (this, dest, prefix, TRUE, iface, src);
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)
498 return NOT_SUPPORTED;
501 METHOD (kernel_net_t, del_ip, status_t, private_kernel_vpp_net_t *this,
502 host_t *virtual_ip, int prefix, bool wait)
504 return NOT_SUPPORTED;
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,
511 return manage_route (this, TRUE, dst_net, prefixlen, gateway, if_name);
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,
518 return manage_route (this, FALSE, dst_net, prefixlen, gateway, if_name);
522 iface_destroy (iface_t *this)
524 this->addrs->destroy_offset (this->addrs, offsetof (host_t, destroy));
528 METHOD (kernel_net_t, destroy, void, private_kernel_vpp_net_t *this)
530 this->net_update->cancel (this->net_update);
531 this->mutex->destroy (this->mutex);
532 this->ifaces->destroy_function (this->ifaces, (void *) iface_destroy);
537 * Update addresses for an iface entry
540 update_addrs (private_kernel_vpp_net_t *this, iface_t *entry)
544 vl_api_ip_address_dump_t *mp;
545 vl_api_ip_address_details_t *rmp, *tmp;
546 linked_list_t *addrs;
548 enumerator_t *enumerator;
550 mp = vl_msg_api_alloc (sizeof (*mp));
551 clib_memset (mp, 0, sizeof (*mp));
552 u16 msg_id = vl_msg_api_get_msg_index ((u8 *) "ip_address_dump_2d033de4");
553 mp->_vl_msg_id = htons (msg_id);
554 mp->sw_if_index = htonl (entry->index);
556 if (vac->send_dump (vac, (char *) mp, sizeof (*mp), &out, &out_len))
558 DBG2 (DBG_NET, "update_addrs : send VL_API_IP_ADDRESS_DUMP ipv4 failed");
559 vl_msg_api_free (mp);
562 num = out_len / sizeof (*rmp);
563 addrs = linked_list_create ();
564 tmp = (vl_api_ip_address_details_t *) out;
565 for (i = 0; i < num; i++)
569 host = host_create_from_chunk (
570 AF_INET, chunk_create (rmp->prefix.address.un.ip4, 4), 0);
571 addrs->insert_last (addrs, host);
576 if (vac->send_dump (vac, (char *) mp, sizeof (*mp), &out, &out_len))
578 DBG2 (DBG_NET, "update_addrs : send VL_API_IP_ADDRESS_DUMP ipv6 failed");
579 vl_msg_api_free (mp);
582 num = out_len / sizeof (*rmp);
583 tmp = (vl_api_ip_address_details_t *) out;
584 for (i = 0; i < num; i++)
588 host = host_create_from_chunk (
589 AF_INET6, chunk_create (rmp->prefix.address.un.ip6, 16), 0);
590 addrs->insert_last (addrs, host);
592 vl_msg_api_free (mp);
596 enumerator = entry->addrs->create_enumerator (entry->addrs);
597 while (enumerator->enumerate (enumerator, &host))
599 host->destroy (host);
601 enumerator->destroy (enumerator);
602 entry->addrs->destroy (entry->addrs);
604 linked_list_create_from_enumerator (addrs->create_enumerator (addrs));
605 addrs->destroy (addrs);
609 * VPP API interface event callback
612 event_cb (char *data, int data_len, void *ctx)
614 private_kernel_vpp_net_t *this = ctx;
615 vl_api_sw_interface_event_t *event;
617 enumerator_t *enumerator;
619 event = (void *) data;
620 this->mutex->lock (this->mutex);
621 enumerator = this->ifaces->create_enumerator (this->ifaces);
622 while (enumerator->enumerate (enumerator, &entry))
624 if (entry->index == ntohl (event->sw_if_index))
628 this->ifaces->remove_at (this->ifaces, enumerator);
629 DBG2 (DBG_NET, "interface deleted %u %s", entry->index,
631 iface_destroy (entry);
633 else if (entry->up != (event->flags & IF_STATUS_API_FLAG_LINK_UP))
636 (event->flags & IF_STATUS_API_FLAG_LINK_UP) ? TRUE : FALSE;
637 DBG2 (DBG_NET, "interface state changed %u %s %s", entry->index,
638 entry->if_name, entry->up ? "UP" : "DOWN");
643 enumerator->destroy (enumerator);
644 this->mutex->unlock (this->mutex);
649 * Inteface update thread (update interface list and interface address)
652 net_update_thread_fn (private_kernel_vpp_net_t *this)
659 vl_api_sw_interface_dump_t *mp;
660 vl_api_sw_interface_details_t *rmp;
661 enumerator_t *enumerator;
664 mp = vl_msg_api_alloc (sizeof (*mp));
665 memset (mp, 0, sizeof (*mp));
667 vl_msg_api_get_msg_index ((u8 *) "sw_interface_dump_aa610c27");
668 mp->_vl_msg_id = htons (msg_id);
669 mp->name_filter_valid = 0;
670 rv = vac->send_dump (vac, (u8 *) mp, sizeof (*mp), &out, &out_len);
674 this->mutex->lock (this->mutex);
675 enumerator = this->ifaces->create_enumerator (this->ifaces);
676 num = out_len / sizeof (*rmp);
677 rmp = (vl_api_sw_interface_details_t *) out;
678 for (i = 0; i < num; i++)
683 while (enumerator->enumerate (enumerator, &entry))
685 if (entry->index == ntohl (rmp->sw_if_index))
693 INIT (entry, .index = ntohl (rmp->sw_if_index),
694 .up = (rmp->flags & IF_STATUS_API_FLAG_LINK_UP) ?
697 .addrs = linked_list_create (), );
698 memcpy (entry->if_name, rmp->interface_name, 63);
699 this->ifaces->insert_last (this->ifaces, entry);
701 update_addrs (this, entry);
703 enumerator->destroy (enumerator);
704 this->mutex->unlock (this->mutex);
707 vl_msg_api_free (mp);
709 if (!this->events_on)
711 vl_api_want_interface_events_t *emp;
712 api_main_t *am = vlibapi_get_main ();
714 emp = vl_msg_api_alloc (sizeof (*emp));
715 clib_memset (emp, 0, sizeof (*emp));
717 vl_msg_api_get_msg_index ((u8 *) "want_interface_events_476f5a08");
718 emp->_vl_msg_id = ntohs (msg_id);
719 emp->enable_disable = 1;
720 emp->pid = ntohl (am->our_pid);
721 rv = vac->register_event (vac, (char *) emp, sizeof (*emp), event_cb,
722 VL_API_SW_INTERFACE_EVENT, this);
724 this->events_on = TRUE;
733 kernel_vpp_net_create ()
735 private_kernel_vpp_net_t *this;
740 .get_interface = _get_interface_name,
741 .create_address_enumerator = _create_address_enumerator,
742 .get_source_addr = _get_source_addr,
743 .get_nexthop = _get_nexthop,
746 .add_route = _add_route,
747 .del_route = _del_route,
751 .mutex = mutex_create(MUTEX_TYPE_DEFAULT),
752 .ifaces = linked_list_create(),
757 thread_create ((thread_main_t) net_update_thread_fn, this);
759 return &this->public;