summaryrefslogtreecommitdiffstats
path: root/src/vnet/ip
diff options
context:
space:
mode:
Diffstat (limited to 'src/vnet/ip')
-rw-r--r--src/vnet/ip/ip.api31
-rw-r--r--src/vnet/ip/ip.h2
-rw-r--r--src/vnet/ip/ip_api.c49
-rw-r--r--src/vnet/ip/ip_test.c11
-rw-r--r--src/vnet/ip/lookup.c33
5 files changed, 111 insertions, 15 deletions
diff --git a/src/vnet/ip/ip.api b/src/vnet/ip/ip.api
index 28786fa5a90..ca1e2008e4f 100644
--- a/src/vnet/ip/ip.api
+++ b/src/vnet/ip/ip.api
@@ -20,7 +20,7 @@
called through a shared memory interface.
*/
-option version = "3.1.0";
+option version = "3.2.0";
import "vnet/interface_types.api";
import "vnet/fib/fib_types.api";
@@ -57,6 +57,35 @@ autoreply define ip_table_add_del
vl_api_ip_table_t table;
};
+/** \brief Allocate an unused table
+ A table can be added multiple times.
+ If a large number of tables are in use (millions), this API might
+ fail to find a free ID with very low probability, and will return
+ EAGAIN. A subsequent attempt may be successful.
+ @param client_index - opaque cookie to identify the sender
+ @param context - sender context, to match reply w/ request
+ @param table - if table.table_id == ~0, vpp allocates an unused table_id and
+ proceeds as in ip_table_add_del with is_add = true
+ if table.table_id != ~0, vpp uses the table.table_id and
+ proceeds as in ip_table_add_del with is_add = true
+ table.table_id should never be 0
+*/
+define ip_table_allocate
+{
+ u32 client_index;
+ u32 context;
+
+ vl_api_ip_table_t table;
+};
+
+define ip_table_allocate_reply
+{
+ u32 context;
+ i32 retval;
+
+ vl_api_ip_table_t table;
+};
+
/** \brief Dump IP all fib tables
@param client_index - opaque cookie to identify the sender
@param context - sender context, to match reply w/ request
diff --git a/src/vnet/ip/ip.h b/src/vnet/ip/ip.h
index 6d822d29dbe..cda0de2a451 100644
--- a/src/vnet/ip/ip.h
+++ b/src/vnet/ip/ip.h
@@ -270,6 +270,8 @@ void ip_table_delete (fib_protocol_t fproto, u32 table_id, u8 is_api);
int ip_table_bind (fib_protocol_t fproto, u32 sw_if_index,
u32 table_id, u8 is_api);
+u32 ip_table_get_unused_id (fib_protocol_t fproto);
+
u8 ip_is_zero (ip46_address_t * ip46_address, u8 is_ip4);
u8 ip_is_local_host (ip46_address_t * ip46_address, u8 is_ip4);
u8 ip4_is_local_host (ip4_address_t * ip4_address);
diff --git a/src/vnet/ip/ip_api.c b/src/vnet/ip/ip_api.c
index f9f9ac783d9..f5ebd029a46 100644
--- a/src/vnet/ip/ip_api.c
+++ b/src/vnet/ip/ip_api.c
@@ -601,6 +601,32 @@ ip_table_delete (fib_protocol_t fproto, u32 table_id, u8 is_api)
}
}
+/*
+ * Returns an unused table id, and ~0 if it can't find one.
+ */
+u32
+ip_table_get_unused_id (fib_protocol_t fproto)
+{
+ int i, j;
+ u32 seed = random_default_seed ();
+ /* limit to 1M tries */
+ for (j = 0; j < 1 << 10; j++)
+ {
+ seed = random_u32 (&seed);
+ for (i = 0; i < 1 << 10; i++)
+ {
+ /* look around randomly generated id */
+ seed += (2 * (i % 2) - 1) * i;
+ if (seed == ~0)
+ continue;
+ if (fib_table_find (fproto, seed) == ~0)
+ return seed;
+ }
+ }
+
+ return ~0;
+}
+
void
vl_api_ip_table_add_del_t_handler (vl_api_ip_table_add_del_t * mp)
{
@@ -622,6 +648,29 @@ vl_api_ip_table_add_del_t_handler (vl_api_ip_table_add_del_t * mp)
REPLY_MACRO (VL_API_IP_TABLE_ADD_DEL_REPLY);
}
+void
+vl_api_ip_table_allocate_t_handler (vl_api_ip_table_allocate_t *mp)
+{
+ vl_api_ip_table_allocate_reply_t *rmp;
+ fib_protocol_t fproto =
+ (mp->table.is_ip6 ? FIB_PROTOCOL_IP6 : FIB_PROTOCOL_IP4);
+ u32 table_id = ntohl (mp->table.table_id);
+ int rv = 0;
+
+ if (~0 == table_id)
+ table_id = ip_table_get_unused_id (fproto);
+
+ if (~0 == table_id)
+ rv = VNET_API_ERROR_EAGAIN;
+ else
+ ip_table_create (fproto, table_id, 1, mp->table.name);
+
+ REPLY_MACRO2 (VL_API_IP_TABLE_ALLOCATE_REPLY, {
+ clib_memcpy_fast (&rmp->table, &mp->table, sizeof (mp->table));
+ rmp->table.table_id = htonl (table_id);
+ })
+}
+
static int
ip_route_add_del_t_handler (vl_api_ip_route_add_del_t * mp, u32 * stats_index)
{
diff --git a/src/vnet/ip/ip_test.c b/src/vnet/ip/ip_test.c
index 2de8235288d..6bdeca5ff32 100644
--- a/src/vnet/ip/ip_test.c
+++ b/src/vnet/ip/ip_test.c
@@ -524,6 +524,17 @@ api_ip_table_flush (vat_main_t *vam)
return ret;
}
+static int
+api_ip_table_allocate (vat_main_t *vam)
+{
+ return -1;
+}
+
+static void
+vl_api_ip_table_allocate_reply_t_handler (vl_api_ip_table_allocate_reply_t *mp)
+{
+}
+
static void
vl_api_ip_route_add_del_v2_reply_t_handler (
vl_api_ip_route_add_del_v2_reply_t *mp)
diff --git a/src/vnet/ip/lookup.c b/src/vnet/ip/lookup.c
index 1753ffd9232..5db14bac092 100644
--- a/src/vnet/ip/lookup.c
+++ b/src/vnet/ip/lookup.c
@@ -399,27 +399,32 @@ vnet_ip_table_cmd (vlib_main_t * vm,
}
}
- if (~0 == table_id)
- {
- error = clib_error_return (0, "No table id");
- goto done;
- }
- else if (0 == table_id)
+ if (0 == table_id)
{
error = clib_error_return (0, "Can't change the default table");
goto done;
}
else
- {
- if (is_add)
{
- ip_table_create (fproto, table_id, 0, name);
- }
- else
- {
- ip_table_delete (fproto, table_id, 0);
+ if (is_add)
+ {
+ if (~0 == table_id)
+ {
+ table_id = ip_table_get_unused_id (fproto);
+ vlib_cli_output (vm, "%u\n", table_id);
+ }
+ ip_table_create (fproto, table_id, 0, name);
+ }
+ else
+ {
+ if (~0 == table_id)
+ {
+ error = clib_error_return (0, "No table id");
+ goto done;
+ }
+ ip_table_delete (fproto, table_id, 0);
+ }
}
- }
done:
unformat_free (line_input);