summaryrefslogtreecommitdiffstats
path: root/src/vnet/ip6-nd/ip6_nd_api.c
diff options
context:
space:
mode:
authorNeale Ranns <nranns@cisco.com>2019-09-30 10:53:31 +0000
committerOle Trøan <otroan@employees.org>2019-12-17 10:56:20 +0000
commitcbe25aab3be72154f2c706c39eeba6a77f34450f (patch)
tree131fb53b5ec973be045ffb9e2eb797af01d112a0 /src/vnet/ip6-nd/ip6_nd_api.c
parent96453fd2417ebd1d69354a7fb692976129cea80e (diff)
ip: Protocol Independent IP Neighbors
Type: feature - ip-neighbour: generic neighbour handling; APIs, DBs, event handling, aging - arp: ARP protocol implementation - ip6-nd; IPv6 neighbor discovery implementation; separate ND, MLD, RA - ip6-link; manage link-local addresses - l2-arp-term; events separated from IP neighbours, since they are not the same. vnet retains just enough education to perform ND/ARP packet construction. arp and ip6-nd to be moved to plugins soon. Change-Id: I88dedd0006b299344f4c7024a0aa5baa6b9a8bbe Signed-off-by: Neale Ranns <nranns@cisco.com>
Diffstat (limited to 'src/vnet/ip6-nd/ip6_nd_api.c')
-rw-r--r--src/vnet/ip6-nd/ip6_nd_api.c382
1 files changed, 382 insertions, 0 deletions
diff --git a/src/vnet/ip6-nd/ip6_nd_api.c b/src/vnet/ip6-nd/ip6_nd_api.c
new file mode 100644
index 00000000000..65b3ee381b3
--- /dev/null
+++ b/src/vnet/ip6-nd/ip6_nd_api.c
@@ -0,0 +1,382 @@
+/*
+ *------------------------------------------------------------------
+ * ip_api.c - vnet ip api
+ *
+ * Copyright (c) 2016 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 <stddef.h>
+
+#include <vnet/ip6-nd/ip6_nd.h>
+#include <vnet/ip6-nd/ip6_ra.h>
+
+#include <vnet/fib/fib_table.h>
+#include <vnet/ip/ip_types_api.h>
+
+#include <vpp/app/version.h>
+
+#include <vlibapi/api.h>
+#include <vlibmemory/api.h>
+
+/* define message IDs */
+#include <vnet/format_fns.h>
+#include <vnet/ip6-nd/ip6_nd.api_enum.h>
+#include <vnet/ip6-nd/ip6_nd.api_types.h>
+
+/**
+ * Base message ID fot the plugin
+ */
+static u32 ip6_nd_base_msg_id;
+#define REPLY_MSG_ID_BASE ip6_nd_base_msg_id
+
+#include <vlibapi/api_helper_macros.h>
+
+static void
+send_ip6nd_proxy_details (vl_api_registration_t * reg,
+ u32 context,
+ const ip46_address_t * addr, u32 sw_if_index)
+{
+ vl_api_ip6nd_proxy_details_t *mp;
+
+ mp = vl_msg_api_alloc (sizeof (*mp));
+ clib_memset (mp, 0, sizeof (*mp));
+ mp->_vl_msg_id = ntohs (VL_API_IP6ND_PROXY_DETAILS);
+ mp->context = context;
+ mp->sw_if_index = htonl (sw_if_index);
+
+ ip6_address_encode (&addr->ip6, mp->ip);
+
+ vl_api_send_msg (reg, (u8 *) mp);
+}
+
+typedef struct api_ip6nd_proxy_fib_table_walk_ctx_t_
+{
+ u32 *indices;
+} api_ip6nd_proxy_fib_table_walk_ctx_t;
+
+static fib_table_walk_rc_t
+api_ip6nd_proxy_fib_table_walk (fib_node_index_t fei, void *arg)
+{
+ api_ip6nd_proxy_fib_table_walk_ctx_t *ctx = arg;
+
+ if (fib_entry_is_sourced (fei, FIB_SOURCE_IP6_ND_PROXY))
+ {
+ vec_add1 (ctx->indices, fei);
+ }
+
+ return (FIB_TABLE_WALK_CONTINUE);
+}
+
+static void
+vl_api_ip6nd_proxy_dump_t_handler (vl_api_ip6nd_proxy_dump_t * mp)
+{
+ ip6_main_t *im6 = &ip6_main;
+ fib_table_t *fib_table;
+ api_ip6nd_proxy_fib_table_walk_ctx_t ctx = {
+ .indices = NULL,
+ };
+ fib_node_index_t *feip;
+ const fib_prefix_t *pfx;
+ vl_api_registration_t *reg;
+
+ reg = vl_api_client_index_to_registration (mp->client_index);
+ if (!reg)
+ return;
+
+ /* *INDENT-OFF* */
+ pool_foreach (fib_table, im6->fibs,
+ ({
+ fib_table_walk(fib_table->ft_index,
+ FIB_PROTOCOL_IP6,
+ api_ip6nd_proxy_fib_table_walk,
+ &ctx);
+ }));
+ /* *INDENT-ON* */
+
+ vec_sort_with_function (ctx.indices, fib_entry_cmp_for_sort);
+
+ vec_foreach (feip, ctx.indices)
+ {
+ pfx = fib_entry_get_prefix (*feip);
+
+ send_ip6nd_proxy_details (reg,
+ mp->context,
+ &pfx->fp_addr,
+ fib_entry_get_resolving_interface (*feip));
+ }
+
+ vec_free (ctx.indices);
+}
+
+static void
+vl_api_ip6nd_proxy_add_del_t_handler (vl_api_ip6nd_proxy_add_del_t * mp)
+{
+ vl_api_ip6nd_proxy_add_del_reply_t *rmp;
+ ip6_address_t ip6;
+ int rv = 0;
+
+ VALIDATE_SW_IF_INDEX (mp);
+
+ ip6_address_decode (mp->ip, &ip6);
+ if (mp->is_add)
+ rv = ip6_nd_proxy_add (ntohl (mp->sw_if_index), &ip6);
+ else
+ rv = ip6_nd_proxy_del (ntohl (mp->sw_if_index), &ip6);
+
+ BAD_SW_IF_INDEX_LABEL;
+ REPLY_MACRO (VL_API_IP6ND_PROXY_ADD_DEL_REPLY);
+}
+
+static void
+ vl_api_sw_interface_ip6nd_ra_config_t_handler
+ (vl_api_sw_interface_ip6nd_ra_config_t * mp)
+{
+ vl_api_sw_interface_ip6nd_ra_config_reply_t *rmp;
+ vlib_main_t *vm = vlib_get_main ();
+ int rv = 0;
+ u8 is_no, suppress, managed, other, ll_option, send_unicast, cease,
+ default_router;
+
+ is_no = mp->is_no == 1;
+ suppress = mp->suppress == 1;
+ managed = mp->managed == 1;
+ other = mp->other == 1;
+ ll_option = mp->ll_option == 1;
+ send_unicast = mp->send_unicast == 1;
+ cease = mp->cease == 1;
+ default_router = mp->default_router == 1;
+
+ VALIDATE_SW_IF_INDEX (mp);
+
+ rv = ip6_ra_config (vm, ntohl (mp->sw_if_index),
+ suppress, managed, other,
+ ll_option, send_unicast, cease,
+ default_router, ntohl (mp->lifetime),
+ ntohl (mp->initial_count),
+ ntohl (mp->initial_interval),
+ ntohl (mp->max_interval),
+ ntohl (mp->min_interval), is_no);
+
+ BAD_SW_IF_INDEX_LABEL;
+
+ REPLY_MACRO (VL_API_SW_INTERFACE_IP6ND_RA_CONFIG_REPLY);
+}
+
+static void
+ vl_api_sw_interface_ip6nd_ra_prefix_t_handler
+ (vl_api_sw_interface_ip6nd_ra_prefix_t * mp)
+{
+ vlib_main_t *vm = vlib_get_main ();
+ vl_api_sw_interface_ip6nd_ra_prefix_reply_t *rmp;
+ fib_prefix_t pfx;
+ int rv = 0;
+ u8 is_no, use_default, no_advertise, off_link, no_autoconfig, no_onlink;
+
+ VALIDATE_SW_IF_INDEX (mp);
+
+ ip_prefix_decode (&mp->prefix, &pfx);
+ is_no = mp->is_no == 1;
+ use_default = mp->use_default == 1;
+ no_advertise = mp->no_advertise == 1;
+ off_link = mp->off_link == 1;
+ no_autoconfig = mp->no_autoconfig == 1;
+ no_onlink = mp->no_onlink == 1;
+
+ rv = ip6_ra_prefix (vm, ntohl (mp->sw_if_index),
+ &pfx.fp_addr.ip6,
+ pfx.fp_len, use_default,
+ ntohl (mp->val_lifetime),
+ ntohl (mp->pref_lifetime), no_advertise,
+ off_link, no_autoconfig, no_onlink, is_no);
+
+ BAD_SW_IF_INDEX_LABEL;
+ REPLY_MACRO (VL_API_SW_INTERFACE_IP6ND_RA_PREFIX_REPLY);
+}
+
+static void
+ vl_api_ip6nd_send_router_solicitation_t_handler
+ (vl_api_ip6nd_send_router_solicitation_t * mp)
+{
+ vl_api_ip6nd_send_router_solicitation_reply_t *rmp;
+ icmp6_send_router_solicitation_params_t params;
+ vlib_main_t *vm = vlib_get_main ();
+ int rv = 0;
+
+ VALIDATE_SW_IF_INDEX (mp);
+
+ BAD_SW_IF_INDEX_LABEL;
+ REPLY_MACRO (VL_API_IP6ND_SEND_ROUTER_SOLICITATION_REPLY);
+
+ if (rv != 0)
+ return;
+
+ params.irt = ntohl (mp->irt);
+ params.mrt = ntohl (mp->mrt);
+ params.mrc = ntohl (mp->mrc);
+ params.mrd = ntohl (mp->mrd);
+
+ icmp6_send_router_solicitation (vm, ntohl (mp->sw_if_index), mp->stop,
+ &params);
+}
+
+static void
+ip6_ra_handle_report (const ip6_ra_report_t * rap)
+{
+ /* *INDENT-OFF* */
+ vpe_client_registration_t *rp;
+
+ pool_foreach(rp, vpe_api_main.ip6_ra_events_registrations,
+ ({
+ vl_api_registration_t *vl_reg;
+
+ vl_reg = vl_api_client_index_to_registration (rp->client_index);
+
+ if (vl_reg && vl_api_can_send_msg (vl_reg))
+ {
+ vl_api_ip6_ra_prefix_info_t *prefix;
+ vl_api_ip6_ra_event_t *event;
+
+ u32 event_size = (sizeof (vl_api_ip6_ra_event_t) +
+ vec_len (rap->prefixes) *
+ sizeof (vl_api_ip6_ra_prefix_info_t));
+ event = vl_msg_api_alloc_zero (event_size);
+
+ event->_vl_msg_id = htons (VL_API_IP6_RA_EVENT + REPLY_MSG_ID_BASE);
+ event->client_index = rp->client_index;
+ event->pid = rp->client_pid;
+ event->sw_if_index = clib_host_to_net_u32 (rap->sw_if_index);
+
+ ip6_address_encode (&rap->router_address,
+ event->router_addr);
+
+ event->current_hop_limit = rap->current_hop_limit;
+ event->flags = rap->flags;
+ event->router_lifetime_in_sec =
+ clib_host_to_net_u16 (rap->router_lifetime_in_sec);
+ event->neighbor_reachable_time_in_msec =
+ clib_host_to_net_u32 (rap->neighbor_reachable_time_in_msec);
+ event->time_in_msec_between_retransmitted_neighbor_solicitations =
+ clib_host_to_net_u32 (rap->time_in_msec_between_retransmitted_neighbor_solicitations);
+ event->n_prefixes = clib_host_to_net_u32 (vec_len (rap->prefixes));
+
+ prefix = event->prefixes;
+ // (typeof (prefix)) event->prefixes;
+ u32 j;
+ for (j = 0; j < vec_len (rap->prefixes); j++)
+ {
+ ra_report_prefix_info_t *info = &rap->prefixes[j];
+ ip_prefix_encode(&info->prefix, &prefix->prefix);
+ prefix->flags = info->flags;
+ prefix->valid_time = clib_host_to_net_u32 (info->valid_time);
+ prefix->preferred_time =
+ clib_host_to_net_u32 (info->preferred_time);
+ prefix++;
+ }
+
+ vl_api_send_msg (vl_reg, (u8 *) event);
+ }
+ }));
+ /* *INDENT-ON* */
+}
+
+static void
+vl_api_want_ip6_ra_events_t_handler (vl_api_want_ip6_ra_events_t * mp)
+{
+ vpe_api_main_t *am = &vpe_api_main;
+ vl_api_want_ip6_ra_events_reply_t *rmp;
+ int rv = 0, had_reg, have_reg;
+
+ had_reg = hash_elts (am->ip6_ra_events_registration_hash);
+ uword *p = hash_get (am->ip6_ra_events_registration_hash, mp->client_index);
+ vpe_client_registration_t *rp;
+ if (p)
+ {
+ if (mp->enable)
+ {
+ clib_warning ("pid %d: already enabled...", ntohl (mp->pid));
+ rv = VNET_API_ERROR_INVALID_REGISTRATION;
+ goto reply;
+ }
+ else
+ {
+ rp = pool_elt_at_index (am->ip6_ra_events_registrations, p[0]);
+ pool_put (am->ip6_ra_events_registrations, rp);
+ hash_unset (am->ip6_ra_events_registration_hash, mp->client_index);
+ goto reply;
+ }
+ }
+ if (mp->enable == 0)
+ {
+ clib_warning ("pid %d: already disabled...", ntohl (mp->pid));
+ rv = VNET_API_ERROR_INVALID_REGISTRATION;
+ goto reply;
+ }
+ pool_get (am->ip6_ra_events_registrations, rp);
+ rp->client_index = mp->client_index;
+ rp->client_pid = ntohl (mp->pid);
+ hash_set (am->ip6_ra_events_registration_hash, rp->client_index,
+ rp - am->ip6_ra_events_registrations);
+
+reply:
+ have_reg = hash_elts (am->ip6_ra_events_registration_hash);
+
+ if (!had_reg && have_reg)
+ ip6_ra_report_register (ip6_ra_handle_report);
+ else if (had_reg && !have_reg)
+ ip6_ra_report_unregister (ip6_ra_handle_report);
+
+ REPLY_MACRO (VL_API_WANT_IP6_RA_EVENTS_REPLY);
+}
+
+static clib_error_t *
+want_ip6_ra_events_reaper (u32 client_index)
+{
+ vpe_api_main_t *am = &vpe_api_main;
+ vpe_client_registration_t *rp;
+ uword *p;
+
+ p = hash_get (am->ip6_ra_events_registration_hash, client_index);
+
+ if (p)
+ {
+ rp = pool_elt_at_index (am->ip6_ra_events_registrations, p[0]);
+ pool_put (am->ip6_ra_events_registrations, rp);
+ hash_unset (am->ip6_ra_events_registration_hash, client_index);
+ }
+ return (NULL);
+}
+
+VL_MSG_API_REAPER_FUNCTION (want_ip6_ra_events_reaper);
+
+#include <vnet/ip6-nd/ip6_nd.api.c>
+
+static clib_error_t *
+ip6_nd_api_init (vlib_main_t * vm)
+{
+ /* Ask for a correctly-sized block of API message decode slots */
+ ip6_nd_base_msg_id = setup_message_id_table ();
+
+ return 0;
+}
+
+VLIB_INIT_FUNCTION (ip6_nd_api_init);
+
+/*
+ * fd.io coding-style-patch-verification: ON
+ *
+ * Local Variables:
+ * eval: (c-set-style "gnu")
+ * End:
+ */