summaryrefslogtreecommitdiffstats
path: root/src/vnet/ip/ip_interface.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/vnet/ip/ip_interface.c')
-rw-r--r--src/vnet/ip/ip_interface.c288
1 files changed, 288 insertions, 0 deletions
diff --git a/src/vnet/ip/ip_interface.c b/src/vnet/ip/ip_interface.c
new file mode 100644
index 00000000000..23c3df81638
--- /dev/null
+++ b/src/vnet/ip/ip_interface.c
@@ -0,0 +1,288 @@
+/*
+ * Copyright (c) 2020 Cisco 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 <vnet/ip/ip.h>
+
+/**
+ * @file
+ * @brief IP prefix management on interfaces
+ */
+
+u32
+ip_interface_address_find (ip_lookup_main_t * lm,
+ void *addr_fib, u32 address_length)
+{
+ uword *p = mhash_get (&lm->address_to_if_address_index, addr_fib);
+
+ if (p)
+ return (p[0]);
+
+ return (~0);
+}
+
+clib_error_t *
+ip_interface_address_add (ip_lookup_main_t * lm,
+ u32 sw_if_index,
+ void *addr_fib,
+ u32 address_length, u32 * result_if_address_index)
+{
+ vnet_main_t *vnm = vnet_get_main ();
+ ip_interface_address_t *a, *prev;
+ u32 pi; /* previous index */
+ u32 ai;
+ u32 hi; /* head index */
+
+ /* Verify given length. */
+ if ((address_length == 0) ||
+ (lm->is_ip6 && address_length > 128) ||
+ (!lm->is_ip6 && address_length > 32))
+ {
+ vnm->api_errno = VNET_API_ERROR_ADDRESS_LENGTH_MISMATCH;
+ return clib_error_create
+ ("%U wrong length for interface %U",
+ lm->format_address_and_length, addr_fib,
+ address_length, format_vnet_sw_if_index_name, vnm, sw_if_index);
+ }
+
+ vec_validate_init_empty (lm->if_address_pool_index_by_sw_if_index,
+ sw_if_index, ~0);
+
+ pool_get_zero (lm->if_address_pool, a);
+
+ ai = a - lm->if_address_pool;
+ hi = pi = lm->if_address_pool_index_by_sw_if_index[sw_if_index];
+
+ prev = 0;
+ while (pi != (u32) ~ 0)
+ {
+ prev = pool_elt_at_index (lm->if_address_pool, pi);
+ pi = prev->next_this_sw_interface;
+ }
+ pi = prev ? prev - lm->if_address_pool : (u32) ~ 0;
+
+ a->address_key = mhash_set (&lm->address_to_if_address_index,
+ addr_fib, ai, /* old_value */ 0);
+ a->address_length = address_length;
+ a->sw_if_index = sw_if_index;
+ a->flags = 0;
+ a->prev_this_sw_interface = pi;
+ a->next_this_sw_interface = ~0;
+ if (prev)
+ prev->next_this_sw_interface = ai;
+
+ lm->if_address_pool_index_by_sw_if_index[sw_if_index] =
+ (hi != ~0) ? hi : ai;
+
+ *result_if_address_index = ai;
+
+ return (NULL);
+}
+
+void
+ip_interface_address_del (ip_lookup_main_t * lm,
+ u32 address_index, void *addr_fib)
+{
+ ip_interface_address_t *a, *prev, *next;
+
+ a = pool_elt_at_index (lm->if_address_pool, address_index);
+
+ if (a->prev_this_sw_interface != ~0)
+ {
+ prev = pool_elt_at_index (lm->if_address_pool,
+ a->prev_this_sw_interface);
+ prev->next_this_sw_interface = a->next_this_sw_interface;
+ }
+ if (a->next_this_sw_interface != ~0)
+ {
+ next = pool_elt_at_index (lm->if_address_pool,
+ a->next_this_sw_interface);
+ next->prev_this_sw_interface = a->prev_this_sw_interface;
+
+ if (a->prev_this_sw_interface == ~0)
+ lm->if_address_pool_index_by_sw_if_index[a->sw_if_index] =
+ a->next_this_sw_interface;
+ }
+
+ if ((a->next_this_sw_interface == ~0) && (a->prev_this_sw_interface == ~0))
+ lm->if_address_pool_index_by_sw_if_index[a->sw_if_index] = ~0;
+
+ mhash_unset (&lm->address_to_if_address_index, addr_fib,
+ /* old_value */ 0);
+ pool_put (lm->if_address_pool, a);
+}
+
+u8
+ip_interface_has_address (u32 sw_if_index, ip46_address_t * ip, u8 is_ip4)
+{
+ ip_interface_address_t *ia = 0;
+
+ if (is_ip4)
+ {
+ ip_lookup_main_t *lm4 = &ip4_main.lookup_main;
+ ip4_address_t *ip4;
+ /* *INDENT-OFF* */
+ foreach_ip_interface_address (lm4, ia, sw_if_index, 1 /* unnumbered */ ,
+ ({
+ ip4 = ip_interface_address_get_address (lm4, ia);
+ if (ip4_address_compare (ip4, &ip->ip4) == 0)
+ return 1;
+ }));
+ /* *INDENT-ON* */
+ }
+ else
+ {
+ ip_lookup_main_t *lm6 = &ip6_main.lookup_main;
+ ip6_address_t *ip6;
+ /* *INDENT-OFF* */
+ foreach_ip_interface_address (lm6, ia, sw_if_index, 1 /* unnumbered */ ,
+ ({
+ ip6 = ip_interface_address_get_address (lm6, ia);
+ if (ip6_address_compare (ip6, &ip->ip6) == 0)
+ return 1;
+ }));
+ /* *INDENT-ON* */
+ }
+ return 0;
+}
+
+void *
+ip_interface_get_first_ip (u32 sw_if_index, u8 is_ip4)
+{
+ ip_lookup_main_t *lm4 = &ip4_main.lookup_main;
+ ip_lookup_main_t *lm6 = &ip6_main.lookup_main;
+ ip_interface_address_t *ia = 0;
+
+ if (is_ip4)
+ {
+ /* *INDENT-OFF* */
+ foreach_ip_interface_address (lm4, ia, sw_if_index, 1 /* unnumbered */ ,
+ ({
+ return ip_interface_address_get_address (lm4, ia);
+ }));
+ /* *INDENT-ON* */
+ }
+ else
+ {
+ /* *INDENT-OFF* */
+ foreach_ip_interface_address (lm6, ia, sw_if_index, 1 /* unnumbered */ ,
+ ({
+ ip6_address_t *rv;
+ rv = ip_interface_address_get_address (lm6, ia);
+ /* Trying to use a link-local ip6 src address is a fool's errand */
+ if (!ip6_address_is_link_local_unicast (rv))
+ return rv;
+ }));
+ /* *INDENT-ON* */
+ }
+
+ return 0;
+}
+
+static walk_rc_t
+ip_interface_address_mark_one_interface (vnet_main_t * vnm,
+ vnet_sw_interface_t * si, void *ctx)
+{
+ ip_lookup_main_t *lm4 = &ip4_main.lookup_main;
+ ip_lookup_main_t *lm6 = &ip6_main.lookup_main;
+ ip_interface_address_t *ia = 0;
+
+ /* *INDENT-OFF* */
+ foreach_ip_interface_address (lm4, ia, si->sw_if_index, 1 /* unnumbered */ ,
+ ({
+ ia->flags |= IP_INTERFACE_ADDRESS_FLAG_STALE;
+ }));
+ foreach_ip_interface_address (lm6, ia, si->sw_if_index, 1 /* unnumbered */ ,
+ ({
+ ia->flags |= IP_INTERFACE_ADDRESS_FLAG_STALE;
+ }));
+ /* *INDENT-ON* */
+
+ return (WALK_CONTINUE);
+}
+
+void
+ip_interface_address_mark (void)
+{
+ vnet_sw_interface_walk (vnet_get_main (),
+ ip_interface_address_mark_one_interface, NULL);
+}
+
+static walk_rc_t
+ip_interface_address_sweep_one_interface (vnet_main_t * vnm,
+ vnet_sw_interface_t * si, void *ctx)
+{
+ vlib_main_t *vm = vlib_get_main ();
+ ip4_address_t *ip4_addrs = 0;
+ ip6_address_t *ip6_addrs = 0;
+ ip4_main_t *im4 = &ip4_main;
+ ip6_main_t *im6 = &ip6_main;
+ ip_interface_address_t *ia;
+ u32 *ip6_masks = 0;
+ u32 *ip4_masks = 0;
+ int i;
+
+ /* *INDENT-OFF* */
+ foreach_ip_interface_address (&im4->lookup_main, ia, si->sw_if_index, 1,
+ ({
+ if (ia->flags & IP_INTERFACE_ADDRESS_FLAG_STALE)
+ {
+ ip4_address_t * x = (ip4_address_t *)
+ ip_interface_address_get_address (&im4->lookup_main, ia);
+ vec_add1 (ip4_addrs, x[0]);
+ vec_add1 (ip4_masks, ia->address_length);
+ }
+ }));
+
+ foreach_ip_interface_address (&im6->lookup_main, ia, si->sw_if_index, 1,
+ ({
+ if (ia->flags & IP_INTERFACE_ADDRESS_FLAG_STALE)
+ {
+ ip6_address_t * x = (ip6_address_t *)
+ ip_interface_address_get_address (&im6->lookup_main, ia);
+ vec_add1 (ip6_addrs, x[0]);
+ vec_add1 (ip6_masks, ia->address_length);
+ }
+ }));
+ /* *INDENT-ON* */
+
+ for (i = 0; i < vec_len (ip4_addrs); i++)
+ ip4_add_del_interface_address (vm, si->sw_if_index, &ip4_addrs[i],
+ ip4_masks[i], 1 /* is_del */ );
+ for (i = 0; i < vec_len (ip6_addrs); i++)
+ ip6_add_del_interface_address (vm, si->sw_if_index, &ip6_addrs[i],
+ ip6_masks[i], 1 /* is_del */ );
+
+ vec_free (ip4_addrs);
+ vec_free (ip4_masks);
+ vec_free (ip6_addrs);
+ vec_free (ip6_masks);
+
+ return (WALK_CONTINUE);
+}
+
+void
+ip_interface_address_sweep (void)
+{
+ vnet_sw_interface_walk (vnet_get_main (),
+ ip_interface_address_sweep_one_interface, NULL);
+}
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */