
Added plugin vpp-swan is a plugin that helps offloading Strongswan IPsec ESP process from Linux Kernel to VPP. Type: feature Signed-off-by: Gabriel Oginski <gabrielx.oginski@intel.com> Change-Id: Iec77945892453fac1890d3c49d7d86fc6b09c893
753 lines
18 KiB
C
753 lines
18 KiB
C
/*
|
|
* Copyright (c) 2022 Intel and/or its affiliates.
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at:
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
#include <utils/debug.h>
|
|
#include <vlibapi/api.h>
|
|
#include <vlibmemory/api.h>
|
|
#include <threading/thread.h>
|
|
#include <threading/mutex.h>
|
|
|
|
#define vl_typedefs
|
|
#define vl_endianfun
|
|
/* Include the (first) vlib-api API definition layer */
|
|
#include <vlibmemory/vl_memory_api_h.h>
|
|
/* Include the current layer (third) vpp API definition layer */
|
|
#include <vpp/api/vpe_types.api.h>
|
|
#include <vpp/api/vpe.api.h>
|
|
|
|
#include <vnet/ip-neighbor/ip_neighbor.api_enum.h>
|
|
#include <vnet/ip-neighbor/ip_neighbor.api_types.h>
|
|
#include <vnet/ip/ip.api_enum.h>
|
|
#include <vnet/ip/ip.api_types.h>
|
|
#include <vnet/interface.api_enum.h>
|
|
#include <vnet/interface.api_types.h>
|
|
#undef vl_typedefs
|
|
#undef vl_endianfun
|
|
|
|
#include "kernel_vpp_net.h"
|
|
#include "kernel_vpp_shared.h"
|
|
|
|
typedef struct private_kernel_vpp_net_t private_kernel_vpp_net_t;
|
|
|
|
/**
|
|
* Private data of kernel_vpp_net implementation.
|
|
*/
|
|
struct private_kernel_vpp_net_t
|
|
{
|
|
|
|
/**
|
|
* Public interface.
|
|
*/
|
|
kernel_vpp_net_t public;
|
|
|
|
/**
|
|
* Mutex to access interface list
|
|
*/
|
|
mutex_t *mutex;
|
|
|
|
/**
|
|
* Known interfaces, as iface_t
|
|
*/
|
|
linked_list_t *ifaces;
|
|
|
|
/**
|
|
* Inteface update thread
|
|
*/
|
|
thread_t *net_update;
|
|
|
|
/**
|
|
* TRUE if interface events enabled
|
|
*/
|
|
bool events_on;
|
|
};
|
|
|
|
/**
|
|
* Interface entry
|
|
*/
|
|
typedef struct
|
|
{
|
|
/** interface index */
|
|
uint32_t index;
|
|
/** interface name */
|
|
char if_name[64];
|
|
/** list of known addresses, as host_t */
|
|
linked_list_t *addrs;
|
|
/** TRUE if up */
|
|
bool up;
|
|
} iface_t;
|
|
|
|
/**
|
|
* Address enumerator
|
|
*/
|
|
typedef struct
|
|
{
|
|
/** implements enumerator_t */
|
|
enumerator_t public;
|
|
/** what kind of address should we enumerate? */
|
|
kernel_address_type_t which;
|
|
/** enumerator over interfaces */
|
|
enumerator_t *ifaces;
|
|
/** current enumerator over addresses, or NULL */
|
|
enumerator_t *addrs;
|
|
/** mutex to unlock on destruction */
|
|
mutex_t *mutex;
|
|
} addr_enumerator_t;
|
|
|
|
/**
|
|
* FIB path entry
|
|
*/
|
|
typedef struct
|
|
{
|
|
chunk_t next_hop;
|
|
uint32_t sw_if_index;
|
|
uint8_t preference;
|
|
} fib_path_t;
|
|
|
|
/**
|
|
* Get an iface entry for a local address
|
|
*/
|
|
static iface_t *
|
|
address2entry (private_kernel_vpp_net_t *this, host_t *ip)
|
|
{
|
|
enumerator_t *ifaces, *addrs;
|
|
iface_t *entry, *found = NULL;
|
|
host_t *host;
|
|
|
|
ifaces = this->ifaces->create_enumerator (this->ifaces);
|
|
while (!found && ifaces->enumerate (ifaces, &entry))
|
|
{
|
|
addrs = entry->addrs->create_enumerator (entry->addrs);
|
|
while (!found && addrs->enumerate (addrs, &host))
|
|
{
|
|
if (host->ip_equals (host, ip))
|
|
{
|
|
found = entry;
|
|
}
|
|
}
|
|
addrs->destroy (addrs);
|
|
}
|
|
ifaces->destroy (ifaces);
|
|
|
|
return found;
|
|
}
|
|
|
|
/**
|
|
* Add or remove a route
|
|
*/
|
|
static status_t
|
|
manage_route (private_kernel_vpp_net_t *this, bool add, chunk_t dst,
|
|
uint8_t prefixlen, host_t *gtw, char *name)
|
|
{
|
|
char *out;
|
|
int out_len;
|
|
enumerator_t *enumerator;
|
|
iface_t *entry;
|
|
vl_api_ip_route_add_del_t *mp;
|
|
vl_api_ip_route_add_del_reply_t *rmp;
|
|
vl_api_fib_path_t *apath;
|
|
bool exists = FALSE;
|
|
|
|
this->mutex->lock (this->mutex);
|
|
enumerator = this->ifaces->create_enumerator (this->ifaces);
|
|
while (enumerator->enumerate (enumerator, &entry))
|
|
{
|
|
if (streq (name, entry->if_name))
|
|
{
|
|
exists = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
enumerator->destroy (enumerator);
|
|
this->mutex->unlock (this->mutex);
|
|
|
|
if (!exists)
|
|
{
|
|
DBG1 (DBG_NET, "if_name %s not found", name);
|
|
return NOT_FOUND;
|
|
}
|
|
|
|
mp = vl_msg_api_alloc (sizeof (*mp) + sizeof (*apath));
|
|
memset (mp, 0, sizeof (*mp) + sizeof (*apath));
|
|
u16 msg_id = vl_msg_api_get_msg_index ((u8 *) "ip_route_add_del_b8ecfe0d");
|
|
mp->_vl_msg_id = ntohs (msg_id);
|
|
mp->is_add = add;
|
|
mp->route.prefix.len = prefixlen;
|
|
mp->route.n_paths = 1;
|
|
apath = &mp->route.paths[0];
|
|
apath->sw_if_index = ntohl (entry->index);
|
|
apath->rpf_id = ~0;
|
|
apath->weight = 1;
|
|
switch (dst.len)
|
|
{
|
|
case 4:
|
|
mp->route.prefix.address.af = ntohl (ADDRESS_IP4);
|
|
memcpy (&mp->route.prefix.address.un.ip4, dst.ptr, dst.len);
|
|
if (gtw)
|
|
{
|
|
chunk_t addr = gtw->get_address (gtw);
|
|
apath->proto = ntohl (FIB_API_PATH_NH_PROTO_IP4);
|
|
memcpy (&apath->nh.address.ip4, addr.ptr, dst.len);
|
|
}
|
|
break;
|
|
case 16:
|
|
mp->route.prefix.address.af = ntohl (ADDRESS_IP6);
|
|
memcpy (&mp->route.prefix.address.un.ip6, dst.ptr, dst.len);
|
|
if (gtw)
|
|
{
|
|
chunk_t addr = gtw->get_address (gtw);
|
|
apath->proto = ntohl (FIB_API_PATH_NH_PROTO_IP6);
|
|
memcpy (&apath->nh.address.ip6, addr.ptr, dst.len);
|
|
}
|
|
break;
|
|
default:
|
|
vl_msg_api_free (mp);
|
|
return FAILED;
|
|
}
|
|
|
|
if (vac->send (vac, (char *) mp, sizeof (*mp) + sizeof (*apath), &out,
|
|
&out_len))
|
|
{
|
|
DBG1 (DBG_KNL, "vac %sing route failed", add ? "add" : "remov");
|
|
vl_msg_api_free (mp);
|
|
return FAILED;
|
|
}
|
|
rmp = (void *) out;
|
|
vl_msg_api_free (mp);
|
|
if (rmp->retval)
|
|
{
|
|
DBG1 (DBG_KNL, "%s route failed %d", add ? "add" : "delete",
|
|
ntohl (rmp->retval));
|
|
free (out);
|
|
return FAILED;
|
|
}
|
|
free (out);
|
|
return SUCCESS;
|
|
}
|
|
|
|
/**
|
|
* Check if an address or net (addr with prefix net bits) is in
|
|
* subnet (net with net_len net bits)
|
|
*/
|
|
static bool
|
|
addr_in_subnet (chunk_t addr, int prefix, chunk_t net, int net_len)
|
|
{
|
|
static const u_char mask[] = {
|
|
0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe
|
|
};
|
|
int byte = 0;
|
|
|
|
if (net_len == 0)
|
|
{ /* any address matches a /0 network */
|
|
return TRUE;
|
|
}
|
|
if (addr.len != net.len || net_len > 8 * net.len || prefix < net_len)
|
|
{
|
|
return FALSE;
|
|
}
|
|
/* scan through all bytes in network order */
|
|
while (net_len > 0)
|
|
{
|
|
if (net_len < 8)
|
|
{
|
|
return (mask[net_len] & addr.ptr[byte]) ==
|
|
(mask[net_len] & net.ptr[byte]);
|
|
}
|
|
else
|
|
{
|
|
if (addr.ptr[byte] != net.ptr[byte])
|
|
{
|
|
return FALSE;
|
|
}
|
|
byte++;
|
|
net_len -= 8;
|
|
}
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
/**
|
|
* Get a route: If "nexthop" the nexthop is returned, source addr otherwise
|
|
*/
|
|
static host_t *
|
|
get_route (private_kernel_vpp_net_t *this, host_t *dest, int prefix,
|
|
bool nexthop, char **iface, host_t *src)
|
|
{
|
|
fib_path_t path;
|
|
char *out, *tmp;
|
|
int out_len, i, num;
|
|
vl_api_fib_path_t *fp;
|
|
host_t *addr = NULL;
|
|
enumerator_t *enumerator;
|
|
iface_t *entry;
|
|
int family;
|
|
|
|
path.sw_if_index = ~0;
|
|
path.preference = ~0;
|
|
path.next_hop = chunk_empty;
|
|
|
|
vl_api_ip_route_dump_t *mp;
|
|
vl_api_ip_route_details_t *rmp;
|
|
|
|
mp = vl_msg_api_alloc (sizeof (*mp));
|
|
clib_memset (mp, 0, sizeof (*mp));
|
|
u16 msg_id = vl_msg_api_get_msg_index ((u8 *) "ip_route_dump_b9d2e09e");
|
|
mp->_vl_msg_id = htons (msg_id);
|
|
mp->table.is_ip6 = dest->get_family (dest) == AF_INET6 ? 1 : 0;
|
|
if (vac->send_dump (vac, (char *) mp, sizeof (*mp), &out, &out_len))
|
|
{
|
|
vl_msg_api_free (mp);
|
|
DBG2 (DBG_KNL, "send VL_API_IP_ROUTE_ADD_DEL failed");
|
|
return NULL;
|
|
}
|
|
vl_msg_api_free (mp);
|
|
|
|
if (dest->get_family (dest) == AF_INET)
|
|
{
|
|
i = 0;
|
|
family = AF_INET;
|
|
if (prefix == -1)
|
|
prefix = 32;
|
|
|
|
tmp = out;
|
|
while (tmp < (out + out_len))
|
|
{
|
|
rmp = (void *) tmp;
|
|
num = rmp->route.n_paths;
|
|
|
|
if (rmp->route.prefix.len &&
|
|
addr_in_subnet (
|
|
dest->get_address (dest), prefix,
|
|
chunk_create (rmp->route.prefix.address.un.ip4, 4),
|
|
rmp->route.prefix.len))
|
|
{
|
|
fp = rmp->route.paths;
|
|
for (i = 0; i < num; i++)
|
|
{
|
|
#define IS_IP4_ANY(a) (a[0] == 0 && a[1] == 0 && a[2] == 0 & a[3] == 0)
|
|
if (fp->type == FIB_API_PATH_TYPE_DROP)
|
|
{
|
|
fp++;
|
|
continue;
|
|
}
|
|
if ((fp->preference < path.preference) ||
|
|
(path.sw_if_index == ~0) ||
|
|
IS_IP4_ANY (path.next_hop.ptr))
|
|
{
|
|
path.sw_if_index = ntohl (fp->sw_if_index);
|
|
path.preference = fp->preference;
|
|
if (path.next_hop.ptr)
|
|
vl_msg_api_free (path.next_hop.ptr);
|
|
path.next_hop = chunk_create (fp->nh.address.ip4, 4);
|
|
}
|
|
fp++;
|
|
}
|
|
}
|
|
tmp += sizeof (*rmp) + (sizeof (*fp) * num);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
DBG1 (DBG_KNL, "not yet support ip6");
|
|
return NULL;
|
|
}
|
|
|
|
if (path.next_hop.len)
|
|
{
|
|
if (nexthop)
|
|
{
|
|
if (iface)
|
|
{
|
|
*iface = NULL;
|
|
this->mutex->lock (this->mutex);
|
|
enumerator = this->ifaces->create_enumerator (this->ifaces);
|
|
while (enumerator->enumerate (enumerator, &entry))
|
|
{
|
|
if (entry->index == path.sw_if_index)
|
|
{
|
|
*iface = strdup (entry->if_name);
|
|
break;
|
|
}
|
|
}
|
|
enumerator->destroy (enumerator);
|
|
this->mutex->unlock (this->mutex);
|
|
}
|
|
addr = host_create_from_chunk (family, path.next_hop, 0);
|
|
}
|
|
else
|
|
{
|
|
if (src)
|
|
{
|
|
addr = src->clone (src);
|
|
}
|
|
}
|
|
}
|
|
|
|
free (out);
|
|
|
|
return addr;
|
|
}
|
|
|
|
METHOD (enumerator_t, addr_enumerate, bool, addr_enumerator_t *this,
|
|
va_list args)
|
|
{
|
|
iface_t *entry;
|
|
host_t **host;
|
|
|
|
VA_ARGS_VGET (args, host);
|
|
|
|
while (TRUE)
|
|
{
|
|
while (!this->addrs)
|
|
{
|
|
if (!this->ifaces->enumerate (this->ifaces, &entry))
|
|
{
|
|
return FALSE;
|
|
}
|
|
if (!entry->up && !(this->which & ADDR_TYPE_DOWN))
|
|
{
|
|
continue;
|
|
}
|
|
this->addrs = entry->addrs->create_enumerator (entry->addrs);
|
|
}
|
|
if (this->addrs->enumerate (this->addrs, host))
|
|
{
|
|
return TRUE;
|
|
}
|
|
this->addrs->destroy (this->addrs);
|
|
this->addrs = NULL;
|
|
}
|
|
}
|
|
|
|
METHOD (enumerator_t, addr_destroy, void, addr_enumerator_t *this)
|
|
{
|
|
DESTROY_IF (this->addrs);
|
|
this->ifaces->destroy (this->ifaces);
|
|
this->mutex->unlock (this->mutex);
|
|
free (this);
|
|
}
|
|
|
|
METHOD (kernel_net_t, get_interface_name, bool, private_kernel_vpp_net_t *this,
|
|
host_t *ip, char **name)
|
|
{
|
|
iface_t *entry;
|
|
|
|
this->mutex->lock (this->mutex);
|
|
entry = address2entry (this, ip);
|
|
if (entry && name)
|
|
{
|
|
*name = strdup (entry->if_name);
|
|
}
|
|
this->mutex->unlock (this->mutex);
|
|
|
|
return entry != NULL;
|
|
}
|
|
|
|
METHOD (kernel_net_t, create_address_enumerator, enumerator_t *,
|
|
private_kernel_vpp_net_t *this, kernel_address_type_t which)
|
|
{
|
|
addr_enumerator_t *enumerator;
|
|
|
|
if (!(which & ADDR_TYPE_REGULAR))
|
|
{
|
|
/* we currently have no virtual, but regular IPs only */
|
|
return enumerator_create_empty ();
|
|
}
|
|
|
|
this->mutex->lock (this->mutex);
|
|
|
|
INIT(enumerator,
|
|
.public = {
|
|
.enumerate = enumerator_enumerate_default,
|
|
.venumerate = _addr_enumerate,
|
|
.destroy = _addr_destroy,
|
|
},
|
|
.which = which,
|
|
.ifaces = this->ifaces->create_enumerator(this->ifaces),
|
|
.mutex = this->mutex,
|
|
);
|
|
return &enumerator->public;
|
|
}
|
|
|
|
METHOD (kernel_net_t, get_source_addr, host_t *,
|
|
private_kernel_vpp_net_t *this, host_t *dest, host_t *src)
|
|
{
|
|
return get_route (this, dest, -1, FALSE, NULL, src);
|
|
}
|
|
|
|
METHOD (kernel_net_t, get_nexthop, host_t *, private_kernel_vpp_net_t *this,
|
|
host_t *dest, int prefix, host_t *src, char **iface)
|
|
{
|
|
return get_route (this, dest, prefix, TRUE, iface, src);
|
|
}
|
|
|
|
METHOD (kernel_net_t, add_ip, status_t, private_kernel_vpp_net_t *this,
|
|
host_t *virtual_ip, int prefix, char *iface_name)
|
|
{
|
|
return NOT_SUPPORTED;
|
|
}
|
|
|
|
METHOD (kernel_net_t, del_ip, status_t, private_kernel_vpp_net_t *this,
|
|
host_t *virtual_ip, int prefix, bool wait)
|
|
{
|
|
return NOT_SUPPORTED;
|
|
}
|
|
|
|
METHOD (kernel_net_t, add_route, status_t, private_kernel_vpp_net_t *this,
|
|
chunk_t dst_net, u_int8_t prefixlen, host_t *gateway, host_t *src_ip,
|
|
char *if_name)
|
|
{
|
|
return manage_route (this, TRUE, dst_net, prefixlen, gateway, if_name);
|
|
}
|
|
|
|
METHOD (kernel_net_t, del_route, status_t, private_kernel_vpp_net_t *this,
|
|
chunk_t dst_net, u_int8_t prefixlen, host_t *gateway, host_t *src_ip,
|
|
char *if_name)
|
|
{
|
|
return manage_route (this, FALSE, dst_net, prefixlen, gateway, if_name);
|
|
}
|
|
|
|
static void
|
|
iface_destroy (iface_t *this)
|
|
{
|
|
this->addrs->destroy_offset (this->addrs, offsetof (host_t, destroy));
|
|
free (this);
|
|
}
|
|
|
|
METHOD (kernel_net_t, destroy, void, private_kernel_vpp_net_t *this)
|
|
{
|
|
this->net_update->cancel (this->net_update);
|
|
this->mutex->destroy (this->mutex);
|
|
this->ifaces->destroy_function (this->ifaces, (void *) iface_destroy);
|
|
free (this);
|
|
}
|
|
|
|
/**
|
|
* Update addresses for an iface entry
|
|
*/
|
|
static void
|
|
update_addrs (private_kernel_vpp_net_t *this, iface_t *entry)
|
|
{
|
|
char *out;
|
|
int out_len, i, num;
|
|
vl_api_ip_address_dump_t *mp;
|
|
vl_api_ip_address_details_t *rmp, *tmp;
|
|
linked_list_t *addrs;
|
|
host_t *host;
|
|
|
|
mp = vl_msg_api_alloc (sizeof (*mp));
|
|
clib_memset (mp, 0, sizeof (*mp));
|
|
u16 msg_id = vl_msg_api_get_msg_index ((u8 *) "ip_address_dump_2d033de4");
|
|
mp->_vl_msg_id = htons (msg_id);
|
|
mp->sw_if_index = htonl (entry->index);
|
|
mp->is_ipv6 = 0;
|
|
if (vac->send_dump (vac, (char *) mp, sizeof (*mp), &out, &out_len))
|
|
{
|
|
DBG2 (DBG_NET, "update_addrs : send VL_API_IP_ADDRESS_DUMP ipv4 failed");
|
|
vl_msg_api_free (mp);
|
|
return;
|
|
}
|
|
num = out_len / sizeof (*rmp);
|
|
addrs = linked_list_create ();
|
|
tmp = (vl_api_ip_address_details_t *) out;
|
|
for (i = 0; i < num; i++)
|
|
{
|
|
tmp += i;
|
|
rmp = tmp;
|
|
host = host_create_from_chunk (
|
|
AF_INET, chunk_create (rmp->prefix.address.un.ip4, 4), 0);
|
|
addrs->insert_last (addrs, host);
|
|
}
|
|
free (out);
|
|
|
|
mp->is_ipv6 = 1;
|
|
if (vac->send_dump (vac, (char *) mp, sizeof (*mp), &out, &out_len))
|
|
{
|
|
DBG2 (DBG_NET, "update_addrs : send VL_API_IP_ADDRESS_DUMP ipv6 failed");
|
|
vl_msg_api_free (mp);
|
|
return;
|
|
}
|
|
num = out_len / sizeof (*rmp);
|
|
tmp = (vl_api_ip_address_details_t *) out;
|
|
for (i = 0; i < num; i++)
|
|
{
|
|
tmp += i;
|
|
rmp = tmp;
|
|
host = host_create_from_chunk (
|
|
AF_INET6, chunk_create (rmp->prefix.address.un.ip6, 16), 0);
|
|
addrs->insert_last (addrs, host);
|
|
}
|
|
vl_msg_api_free (mp);
|
|
free (out);
|
|
|
|
entry->addrs->destroy (entry->addrs);
|
|
entry->addrs =
|
|
linked_list_create_from_enumerator (addrs->create_enumerator (addrs));
|
|
addrs->destroy (addrs);
|
|
}
|
|
|
|
/**
|
|
* VPP API interface event callback
|
|
*/
|
|
static void
|
|
event_cb (char *data, int data_len, void *ctx)
|
|
{
|
|
private_kernel_vpp_net_t *this = ctx;
|
|
vl_api_sw_interface_event_t *event;
|
|
iface_t *entry;
|
|
enumerator_t *enumerator;
|
|
|
|
event = (void *) data;
|
|
this->mutex->lock (this->mutex);
|
|
enumerator = this->ifaces->create_enumerator (this->ifaces);
|
|
while (enumerator->enumerate (enumerator, &entry))
|
|
{
|
|
if (entry->index == ntohl (event->sw_if_index))
|
|
{
|
|
if (event->deleted)
|
|
{
|
|
this->ifaces->remove_at (this->ifaces, enumerator);
|
|
DBG2 (DBG_NET, "interface deleted %u %s", entry->index,
|
|
entry->if_name);
|
|
iface_destroy (entry);
|
|
}
|
|
else if (entry->up != (event->flags & IF_STATUS_API_FLAG_LINK_UP))
|
|
{
|
|
entry->up =
|
|
(event->flags & IF_STATUS_API_FLAG_LINK_UP) ? TRUE : FALSE;
|
|
DBG2 (DBG_NET, "interface state changed %u %s %s", entry->index,
|
|
entry->if_name, entry->up ? "UP" : "DOWN");
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
enumerator->destroy (enumerator);
|
|
this->mutex->unlock (this->mutex);
|
|
free (data);
|
|
}
|
|
|
|
/**
|
|
* Inteface update thread (update interface list and interface address)
|
|
*/
|
|
static void *
|
|
net_update_thread_fn (private_kernel_vpp_net_t *this)
|
|
{
|
|
status_t rv;
|
|
while (1)
|
|
{
|
|
char *out;
|
|
int out_len;
|
|
vl_api_sw_interface_dump_t *mp;
|
|
vl_api_sw_interface_details_t *rmp;
|
|
enumerator_t *enumerator;
|
|
iface_t *entry;
|
|
|
|
mp = vl_msg_api_alloc (sizeof (*mp));
|
|
memset (mp, 0, sizeof (*mp));
|
|
u16 msg_id =
|
|
vl_msg_api_get_msg_index ((u8 *) "sw_interface_dump_aa610c27");
|
|
mp->_vl_msg_id = htons (msg_id);
|
|
mp->name_filter_valid = 0;
|
|
rv = vac->send_dump (vac, (u8 *) mp, sizeof (*mp), &out, &out_len);
|
|
if (!rv)
|
|
{
|
|
int i, num;
|
|
this->mutex->lock (this->mutex);
|
|
enumerator = this->ifaces->create_enumerator (this->ifaces);
|
|
num = out_len / sizeof (*rmp);
|
|
rmp = (vl_api_sw_interface_details_t *) out;
|
|
for (i = 0; i < num; i++)
|
|
{
|
|
bool exists = FALSE;
|
|
if (i)
|
|
rmp += 1;
|
|
while (enumerator->enumerate (enumerator, &entry))
|
|
{
|
|
if (entry->index == ntohl (rmp->sw_if_index))
|
|
{
|
|
exists = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
if (!exists)
|
|
{
|
|
INIT (entry, .index = ntohl (rmp->sw_if_index),
|
|
.up = (rmp->flags & IF_STATUS_API_FLAG_LINK_UP) ?
|
|
TRUE :
|
|
FALSE,
|
|
.addrs = linked_list_create (), );
|
|
memcpy (entry->if_name, rmp->interface_name, 63);
|
|
this->ifaces->insert_last (this->ifaces, entry);
|
|
}
|
|
update_addrs (this, entry);
|
|
}
|
|
enumerator->destroy (enumerator);
|
|
this->mutex->unlock (this->mutex);
|
|
free (out);
|
|
}
|
|
vl_msg_api_free (mp);
|
|
|
|
if (!this->events_on)
|
|
{
|
|
vl_api_want_interface_events_t *emp;
|
|
api_main_t *am = vlibapi_get_main ();
|
|
|
|
emp = vl_msg_api_alloc (sizeof (*emp));
|
|
clib_memset (emp, 0, sizeof (*emp));
|
|
u16 msg_id =
|
|
vl_msg_api_get_msg_index ((u8 *) "want_interface_events_476f5a08");
|
|
emp->_vl_msg_id = ntohs (msg_id);
|
|
emp->enable_disable = 1;
|
|
emp->pid = ntohl (am->our_pid);
|
|
rv = vac->register_event (vac, (char *) emp, sizeof (*emp), event_cb,
|
|
VL_API_SW_INTERFACE_EVENT, this);
|
|
if (!rv)
|
|
this->events_on = TRUE;
|
|
}
|
|
|
|
sleep (2);
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
kernel_vpp_net_t *
|
|
kernel_vpp_net_create ()
|
|
{
|
|
private_kernel_vpp_net_t *this;
|
|
|
|
INIT(this,
|
|
.public = {
|
|
.interface = {
|
|
.get_interface = _get_interface_name,
|
|
.create_address_enumerator = _create_address_enumerator,
|
|
.get_source_addr = _get_source_addr,
|
|
.get_nexthop = _get_nexthop,
|
|
.add_ip = _add_ip,
|
|
.del_ip = _del_ip,
|
|
.add_route = _add_route,
|
|
.del_route = _del_route,
|
|
.destroy = _destroy,
|
|
},
|
|
},
|
|
.mutex = mutex_create(MUTEX_TYPE_DEFAULT),
|
|
.ifaces = linked_list_create(),
|
|
.events_on = FALSE,
|
|
);
|
|
|
|
this->net_update =
|
|
thread_create ((thread_main_t) net_update_thread_fn, this);
|
|
|
|
return &this->public;
|
|
}
|