
This patches fixes an issue that could cause fib locks to underflow: if an API user deletes a fib and quickly recreates it, the fib may not have been actually deleted. As a result, the lock would not be incremented on the create call leading to the fib potentially disappearing afterwards - or to the lock to underflow when the fib is deleted again. In order to keep the existing API semantics, we use the locks with API and CLI source as flags. This means we need to use a different counter for the interface-related locks. This also prevents an issue where an interface being bound to a vrf via API and released via CLI could mess up the lock counter. Finally, this will help with cleaning up the interface-related locks on interface deletion in a later patch. Type: fix Change-Id: I93030a7660646d6dd179ddf27fe4e708aa11b90e Signed-off-by: Nathan Skrzypczak <nathan.skrzypczak@gmail.com> Signed-off-by: Aloys Augustin <aloaugus@cisco.com>
1469 lines
41 KiB
C
1469 lines
41 KiB
C
/*
|
|
*------------------------------------------------------------------
|
|
* interface_api.c - vnet interface 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 <vnet/vnet.h>
|
|
#include <vlibmemory/api.h>
|
|
|
|
#include <vnet/interface.h>
|
|
#include <vnet/interface/rx_queue_funcs.h>
|
|
#include <vnet/api_errno.h>
|
|
#include <vnet/ethernet/ethernet.h>
|
|
#include <vnet/ip/ip.h>
|
|
#include <vnet/fib/fib_table.h>
|
|
#include <vnet/mfib/mfib_table.h>
|
|
#include <vnet/l2/l2_vtr.h>
|
|
#include <vnet/fib/fib_api.h>
|
|
#include <vnet/mfib/mfib_table.h>
|
|
#include <vlibapi/api_types.h>
|
|
|
|
#include <vnet/format_fns.h>
|
|
#include <vnet/ip/ip_types_api.h>
|
|
#include <vnet/ethernet/ethernet_types_api.h>
|
|
|
|
#include <interface.api_enum.h>
|
|
#include <interface.api_types.h>
|
|
|
|
#define REPLY_MSG_ID_BASE msg_id_base
|
|
#include <vlibapi/api_helper_macros.h>
|
|
|
|
static u16 msg_id_base;
|
|
|
|
vpe_api_main_t vpe_api_main;
|
|
|
|
#define foreach_vpe_api_msg \
|
|
_ (SW_INTERFACE_SET_FLAGS, sw_interface_set_flags) \
|
|
_ (SW_INTERFACE_SET_PROMISC, sw_interface_set_promisc) \
|
|
_ (HW_INTERFACE_SET_MTU, hw_interface_set_mtu) \
|
|
_ (SW_INTERFACE_SET_MTU, sw_interface_set_mtu) \
|
|
_ (WANT_INTERFACE_EVENTS, want_interface_events) \
|
|
_ (SW_INTERFACE_DUMP, sw_interface_dump) \
|
|
_ (SW_INTERFACE_ADD_DEL_ADDRESS, sw_interface_add_del_address) \
|
|
_ (SW_INTERFACE_SET_RX_MODE, sw_interface_set_rx_mode) \
|
|
_ (SW_INTERFACE_RX_PLACEMENT_DUMP, sw_interface_rx_placement_dump) \
|
|
_ (SW_INTERFACE_SET_RX_PLACEMENT, sw_interface_set_rx_placement) \
|
|
_ (SW_INTERFACE_SET_TABLE, sw_interface_set_table) \
|
|
_ (SW_INTERFACE_GET_TABLE, sw_interface_get_table) \
|
|
_ (SW_INTERFACE_SET_UNNUMBERED, sw_interface_set_unnumbered) \
|
|
_ (SW_INTERFACE_CLEAR_STATS, sw_interface_clear_stats) \
|
|
_ (SW_INTERFACE_TAG_ADD_DEL, sw_interface_tag_add_del) \
|
|
_ (SW_INTERFACE_ADD_DEL_MAC_ADDRESS, sw_interface_add_del_mac_address) \
|
|
_ (SW_INTERFACE_SET_MAC_ADDRESS, sw_interface_set_mac_address) \
|
|
_ (SW_INTERFACE_GET_MAC_ADDRESS, sw_interface_get_mac_address) \
|
|
_ (CREATE_VLAN_SUBIF, create_vlan_subif) \
|
|
_ (CREATE_SUBIF, create_subif) \
|
|
_ (DELETE_SUBIF, delete_subif) \
|
|
_ (CREATE_LOOPBACK, create_loopback) \
|
|
_ (CREATE_LOOPBACK_INSTANCE, create_loopback_instance) \
|
|
_ (DELETE_LOOPBACK, delete_loopback) \
|
|
_ (INTERFACE_NAME_RENUMBER, interface_name_renumber) \
|
|
_ (COLLECT_DETAILED_INTERFACE_STATS, collect_detailed_interface_stats) \
|
|
_ (SW_INTERFACE_SET_IP_DIRECTED_BROADCAST, \
|
|
sw_interface_set_ip_directed_broadcast) \
|
|
_ (SW_INTERFACE_ADDRESS_REPLACE_BEGIN, sw_interface_address_replace_begin) \
|
|
_ (SW_INTERFACE_ADDRESS_REPLACE_END, sw_interface_address_replace_end)
|
|
|
|
static void
|
|
vl_api_sw_interface_set_flags_t_handler (vl_api_sw_interface_set_flags_t * mp)
|
|
{
|
|
vl_api_sw_interface_set_flags_reply_t *rmp;
|
|
vnet_main_t *vnm = vnet_get_main ();
|
|
int rv = 0;
|
|
clib_error_t *error;
|
|
u16 flags;
|
|
|
|
VALIDATE_SW_IF_INDEX (mp);
|
|
|
|
flags =
|
|
((ntohl (mp->flags)) & IF_STATUS_API_FLAG_ADMIN_UP) ?
|
|
VNET_SW_INTERFACE_FLAG_ADMIN_UP : 0;
|
|
|
|
error = vnet_sw_interface_set_flags (vnm, ntohl (mp->sw_if_index), flags);
|
|
if (error)
|
|
{
|
|
rv = -1;
|
|
clib_error_report (error);
|
|
}
|
|
|
|
BAD_SW_IF_INDEX_LABEL;
|
|
REPLY_MACRO (VL_API_SW_INTERFACE_SET_FLAGS_REPLY);
|
|
}
|
|
|
|
static void
|
|
vl_api_sw_interface_set_promisc_t_handler (
|
|
vl_api_sw_interface_set_promisc_t *mp)
|
|
{
|
|
vl_api_sw_interface_set_promisc_reply_t *rmp;
|
|
vnet_main_t *vnm = vnet_get_main ();
|
|
ethernet_main_t *em = ðernet_main;
|
|
int rv = 0;
|
|
ethernet_interface_t *eif;
|
|
vnet_sw_interface_t *swif;
|
|
u32 flags, sw_if_index;
|
|
|
|
VALIDATE_SW_IF_INDEX (mp);
|
|
|
|
sw_if_index = ntohl (mp->sw_if_index);
|
|
swif = vnet_get_sw_interface (vnm, sw_if_index);
|
|
eif = ethernet_get_interface (em, swif->hw_if_index);
|
|
if (!eif)
|
|
{
|
|
rv = VNET_API_ERROR_INVALID_VALUE;
|
|
goto done;
|
|
}
|
|
|
|
flags = mp->promisc_on ? ETHERNET_INTERFACE_FLAG_ACCEPT_ALL : 0;
|
|
rv = ethernet_set_flags (vnm, swif->hw_if_index, flags);
|
|
|
|
done:
|
|
BAD_SW_IF_INDEX_LABEL;
|
|
REPLY_MACRO (VL_API_SW_INTERFACE_SET_PROMISC_REPLY);
|
|
}
|
|
|
|
static void
|
|
vl_api_hw_interface_set_mtu_t_handler (vl_api_hw_interface_set_mtu_t * mp)
|
|
{
|
|
vl_api_hw_interface_set_mtu_reply_t *rmp;
|
|
vnet_main_t *vnm = vnet_get_main ();
|
|
u32 sw_if_index = ntohl (mp->sw_if_index);
|
|
u16 mtu = ntohs (mp->mtu);
|
|
ethernet_main_t *em = ðernet_main;
|
|
int rv = 0;
|
|
|
|
VALIDATE_SW_IF_INDEX (mp);
|
|
|
|
vnet_sw_interface_t *si = vnet_get_sw_interface (vnm, sw_if_index);
|
|
if (si->type != VNET_SW_INTERFACE_TYPE_HARDWARE)
|
|
{
|
|
rv = VNET_API_ERROR_INVALID_VALUE;
|
|
goto bad_sw_if_index;
|
|
}
|
|
|
|
vnet_hw_interface_t *hi = vnet_get_hw_interface (vnm, si->hw_if_index);
|
|
ethernet_interface_t *eif = ethernet_get_interface (em, si->hw_if_index);
|
|
|
|
if (!eif)
|
|
{
|
|
rv = VNET_API_ERROR_FEATURE_DISABLED;
|
|
goto bad_sw_if_index;
|
|
}
|
|
|
|
if (mtu < hi->min_supported_packet_bytes)
|
|
{
|
|
rv = VNET_API_ERROR_INVALID_VALUE;
|
|
goto bad_sw_if_index;
|
|
}
|
|
|
|
if (mtu > hi->max_supported_packet_bytes)
|
|
{
|
|
rv = VNET_API_ERROR_INVALID_VALUE;
|
|
goto bad_sw_if_index;
|
|
}
|
|
|
|
vnet_hw_interface_set_mtu (vnm, si->hw_if_index, mtu);
|
|
|
|
BAD_SW_IF_INDEX_LABEL;
|
|
REPLY_MACRO (VL_API_HW_INTERFACE_SET_MTU_REPLY);
|
|
}
|
|
|
|
static void
|
|
vl_api_sw_interface_set_mtu_t_handler (vl_api_sw_interface_set_mtu_t * mp)
|
|
{
|
|
vl_api_sw_interface_set_mtu_reply_t *rmp;
|
|
vnet_main_t *vnm = vnet_get_main ();
|
|
u32 sw_if_index = ntohl (mp->sw_if_index);
|
|
int rv = 0;
|
|
int i;
|
|
u32 per_protocol_mtu[VNET_N_MTU];
|
|
|
|
VALIDATE_SW_IF_INDEX (mp);
|
|
|
|
for (i = 0; i < VNET_N_MTU; i++)
|
|
{
|
|
per_protocol_mtu[i] = ntohl (mp->mtu[i]);
|
|
}
|
|
vnet_sw_interface_set_protocol_mtu (vnm, sw_if_index, per_protocol_mtu);
|
|
|
|
BAD_SW_IF_INDEX_LABEL;
|
|
REPLY_MACRO (VL_API_SW_INTERFACE_SET_MTU_REPLY);
|
|
}
|
|
|
|
static void
|
|
vl_api_sw_interface_set_ip_directed_broadcast_t_handler
|
|
(vl_api_sw_interface_set_ip_directed_broadcast_t * mp)
|
|
{
|
|
vl_api_sw_interface_set_ip_directed_broadcast_reply_t *rmp;
|
|
u32 sw_if_index = ntohl (mp->sw_if_index);
|
|
int rv = 0;
|
|
|
|
VALIDATE_SW_IF_INDEX (mp);
|
|
|
|
vnet_sw_interface_ip_directed_broadcast (vnet_get_main (),
|
|
sw_if_index, mp->enable);
|
|
|
|
BAD_SW_IF_INDEX_LABEL;
|
|
REPLY_MACRO (VL_API_SW_INTERFACE_SET_IP_DIRECTED_BROADCAST_REPLY);
|
|
}
|
|
|
|
static void
|
|
send_sw_interface_details (vpe_api_main_t * am,
|
|
vl_api_registration_t * rp,
|
|
vnet_sw_interface_t * swif,
|
|
u8 * interface_name, u32 context)
|
|
{
|
|
vnet_hw_interface_t *hi =
|
|
vnet_get_sup_hw_interface (am->vnet_main, swif->sw_if_index);
|
|
vnet_device_class_t *dev_class =
|
|
vnet_get_device_class (am->vnet_main, hi->dev_class_index);
|
|
|
|
vl_api_sw_interface_details_t *mp = vl_msg_api_alloc (sizeof (*mp));
|
|
clib_memset (mp, 0, sizeof (*mp));
|
|
mp->_vl_msg_id = ntohs (REPLY_MSG_ID_BASE + VL_API_SW_INTERFACE_DETAILS);
|
|
mp->sw_if_index = ntohl (swif->sw_if_index);
|
|
mp->sup_sw_if_index = ntohl (swif->sup_sw_if_index);
|
|
|
|
mp->flags |= (swif->flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP) ?
|
|
IF_STATUS_API_FLAG_ADMIN_UP : 0;
|
|
mp->flags |= (hi->flags & VNET_HW_INTERFACE_FLAG_LINK_UP) ?
|
|
IF_STATUS_API_FLAG_LINK_UP : 0;
|
|
mp->flags = ntohl (mp->flags);
|
|
|
|
switch (swif->type)
|
|
{
|
|
case VNET_SW_INTERFACE_TYPE_SUB:
|
|
mp->type = IF_API_TYPE_SUB;
|
|
break;
|
|
case VNET_SW_INTERFACE_TYPE_P2P:
|
|
mp->type = IF_API_TYPE_P2P;
|
|
break;
|
|
case VNET_SW_INTERFACE_TYPE_PIPE:
|
|
mp->type = IF_API_TYPE_PIPE;
|
|
break;
|
|
default:
|
|
mp->type = IF_API_TYPE_HARDWARE;
|
|
}
|
|
mp->type = ntohl (mp->type);
|
|
|
|
mp->link_duplex = ntohl (((hi->flags & VNET_HW_INTERFACE_FLAG_DUPLEX_MASK) >>
|
|
VNET_HW_INTERFACE_FLAG_DUPLEX_SHIFT));
|
|
mp->link_speed = ntohl (hi->link_speed);
|
|
mp->link_mtu = ntohs (hi->max_packet_bytes);
|
|
mp->mtu[VNET_MTU_L3] = ntohl (swif->mtu[VNET_MTU_L3]);
|
|
mp->mtu[VNET_MTU_IP4] = ntohl (swif->mtu[VNET_MTU_IP4]);
|
|
mp->mtu[VNET_MTU_IP6] = ntohl (swif->mtu[VNET_MTU_IP6]);
|
|
mp->mtu[VNET_MTU_MPLS] = ntohl (swif->mtu[VNET_MTU_MPLS]);
|
|
|
|
mp->context = context;
|
|
|
|
strncpy ((char *) mp->interface_name,
|
|
(char *) interface_name, ARRAY_LEN (mp->interface_name) - 1);
|
|
|
|
if (dev_class && dev_class->name)
|
|
strncpy ((char *) mp->interface_dev_type, (char *) dev_class->name,
|
|
ARRAY_LEN (mp->interface_dev_type) - 1);
|
|
|
|
/* Send the L2 address for ethernet physical intfcs */
|
|
if (swif->sup_sw_if_index == swif->sw_if_index
|
|
&& hi->hw_class_index == ethernet_hw_interface_class.index)
|
|
{
|
|
ethernet_main_t *em = ethernet_get_main (am->vlib_main);
|
|
ethernet_interface_t *ei;
|
|
|
|
ei = pool_elt_at_index (em->interfaces, hi->hw_instance);
|
|
ASSERT (sizeof (mp->l2_address) >= sizeof (ei->address.mac));
|
|
mac_address_encode (&ei->address.mac, mp->l2_address);
|
|
}
|
|
else if (swif->sup_sw_if_index != swif->sw_if_index)
|
|
{
|
|
vnet_sub_interface_t *sub = &swif->sub;
|
|
mp->sub_id = ntohl (sub->id);
|
|
mp->sub_number_of_tags =
|
|
sub->eth.flags.one_tag + sub->eth.flags.two_tags * 2;
|
|
mp->sub_outer_vlan_id = ntohs (sub->eth.outer_vlan_id);
|
|
mp->sub_inner_vlan_id = ntohs (sub->eth.inner_vlan_id);
|
|
mp->sub_if_flags =
|
|
ntohl (sub->eth.raw_flags & SUB_IF_API_FLAG_MASK_VNET);
|
|
}
|
|
|
|
/* vlan tag rewrite data */
|
|
u32 vtr_op = L2_VTR_DISABLED;
|
|
u32 vtr_push_dot1q = 0, vtr_tag1 = 0, vtr_tag2 = 0;
|
|
|
|
if (l2vtr_get (am->vlib_main, am->vnet_main, swif->sw_if_index,
|
|
&vtr_op, &vtr_push_dot1q, &vtr_tag1, &vtr_tag2) != 0)
|
|
{
|
|
// error - default to disabled
|
|
mp->vtr_op = ntohl (L2_VTR_DISABLED);
|
|
clib_warning ("cannot get vlan tag rewrite for sw_if_index %d",
|
|
swif->sw_if_index);
|
|
}
|
|
else
|
|
{
|
|
mp->vtr_op = ntohl (vtr_op);
|
|
mp->vtr_push_dot1q = ntohl (vtr_push_dot1q);
|
|
mp->vtr_tag1 = ntohl (vtr_tag1);
|
|
mp->vtr_tag2 = ntohl (vtr_tag2);
|
|
}
|
|
|
|
/* pbb tag rewrite data */
|
|
ethernet_header_t eth_hdr;
|
|
u32 pbb_vtr_op = L2_VTR_DISABLED;
|
|
u16 outer_tag = 0;
|
|
u16 b_vlanid = 0;
|
|
u32 i_sid = 0;
|
|
clib_memset (ð_hdr, 0, sizeof (eth_hdr));
|
|
|
|
if (!l2pbb_get (am->vlib_main, am->vnet_main, swif->sw_if_index,
|
|
&pbb_vtr_op, &outer_tag, ð_hdr, &b_vlanid, &i_sid))
|
|
{
|
|
mp->sub_if_flags |= ntohl (SUB_IF_API_FLAG_DOT1AH);
|
|
mac_address_encode ((mac_address_t *) eth_hdr.dst_address, mp->b_dmac);
|
|
mac_address_encode ((mac_address_t *) eth_hdr.src_address, mp->b_smac);
|
|
mp->b_vlanid = b_vlanid;
|
|
mp->i_sid = i_sid;
|
|
}
|
|
|
|
u8 *tag = vnet_get_sw_interface_tag (vnet_get_main (), swif->sw_if_index);
|
|
if (tag)
|
|
strncpy ((char *) mp->tag, (char *) tag, ARRAY_LEN (mp->tag) - 1);
|
|
|
|
vl_api_send_msg (rp, (u8 *) mp);
|
|
}
|
|
|
|
static void
|
|
vl_api_sw_interface_dump_t_handler (vl_api_sw_interface_dump_t * mp)
|
|
{
|
|
vpe_api_main_t *am = &vpe_api_main;
|
|
vnet_sw_interface_t *swif;
|
|
vnet_interface_main_t *im = &am->vnet_main->interface_main;
|
|
vl_api_registration_t *rp;
|
|
u32 sw_if_index;
|
|
|
|
rp = vl_api_client_index_to_registration (mp->client_index);
|
|
|
|
if (rp == 0)
|
|
{
|
|
clib_warning ("Client %d AWOL", mp->client_index);
|
|
return;
|
|
}
|
|
|
|
u8 *filter = 0, *name = 0;
|
|
sw_if_index = ntohl (mp->sw_if_index);
|
|
|
|
if (!mp->name_filter_valid && sw_if_index != ~0 && sw_if_index != 0)
|
|
{
|
|
/* is it a valid sw_if_index? */
|
|
if (!vnet_sw_if_index_is_api_valid (sw_if_index))
|
|
return;
|
|
|
|
swif = vec_elt_at_index (im->sw_interfaces, sw_if_index);
|
|
|
|
vec_reset_length (name);
|
|
name =
|
|
format (name, "%U%c", format_vnet_sw_interface_name, am->vnet_main,
|
|
swif, 0);
|
|
send_sw_interface_details (am, rp, swif, name, mp->context);
|
|
vec_free (name);
|
|
return;
|
|
}
|
|
|
|
if (mp->name_filter_valid)
|
|
{
|
|
filter = vl_api_from_api_to_new_vec (mp, &mp->name_filter);
|
|
vec_add1 (filter, 0); /* Ensure it's a C string for strcasecmp() */
|
|
}
|
|
|
|
char *strcasestr (char *, char *); /* lnx hdr file botch */
|
|
/* *INDENT-OFF* */
|
|
pool_foreach (swif, im->sw_interfaces)
|
|
{
|
|
if (!vnet_swif_is_api_visible (swif))
|
|
continue;
|
|
vec_reset_length(name);
|
|
name = format (name, "%U%c", format_vnet_sw_interface_name, am->vnet_main,
|
|
swif, 0);
|
|
|
|
if (filter && !strcasestr((char *) name, (char *) filter))
|
|
continue;
|
|
|
|
send_sw_interface_details (am, rp, swif, name, mp->context);
|
|
}
|
|
/* *INDENT-ON* */
|
|
|
|
vec_free (name);
|
|
vec_free (filter);
|
|
}
|
|
|
|
static void
|
|
vl_api_sw_interface_add_del_address_t_handler
|
|
(vl_api_sw_interface_add_del_address_t * mp)
|
|
{
|
|
vlib_main_t *vm = vlib_get_main ();
|
|
vnet_main_t *vnm = vnet_get_main ();
|
|
vl_api_sw_interface_add_del_address_reply_t *rmp;
|
|
int rv = 0;
|
|
u32 is_del;
|
|
clib_error_t *error = 0;
|
|
ip46_address_t address;
|
|
|
|
VALIDATE_SW_IF_INDEX (mp);
|
|
|
|
is_del = mp->is_add == 0;
|
|
vnm->api_errno = 0;
|
|
|
|
if (mp->del_all)
|
|
ip_del_all_interface_addresses (vm, ntohl (mp->sw_if_index));
|
|
else if (ip_address_decode (&mp->prefix.address, &address) == IP46_TYPE_IP6)
|
|
error = ip6_add_del_interface_address (vm, ntohl (mp->sw_if_index),
|
|
(void *) &address.ip6,
|
|
mp->prefix.len, is_del);
|
|
else
|
|
error = ip4_add_del_interface_address (vm, ntohl (mp->sw_if_index),
|
|
(void *) &address.ip4,
|
|
mp->prefix.len, is_del);
|
|
|
|
if (error)
|
|
{
|
|
rv = vnm->api_errno;
|
|
clib_error_report (error);
|
|
goto done;
|
|
}
|
|
|
|
BAD_SW_IF_INDEX_LABEL;
|
|
|
|
done:
|
|
REPLY_MACRO (VL_API_SW_INTERFACE_ADD_DEL_ADDRESS_REPLY);
|
|
}
|
|
|
|
static void
|
|
vl_api_sw_interface_set_table_t_handler (vl_api_sw_interface_set_table_t * mp)
|
|
{
|
|
vl_api_sw_interface_set_table_reply_t *rmp;
|
|
u32 sw_if_index = ntohl (mp->sw_if_index);
|
|
u32 table_id = ntohl (mp->vrf_id);
|
|
int rv = 0;
|
|
|
|
VALIDATE_SW_IF_INDEX (mp);
|
|
|
|
if (mp->is_ipv6)
|
|
rv = ip_table_bind (FIB_PROTOCOL_IP6, sw_if_index, table_id);
|
|
else
|
|
rv = ip_table_bind (FIB_PROTOCOL_IP4, sw_if_index, table_id);
|
|
|
|
BAD_SW_IF_INDEX_LABEL;
|
|
|
|
REPLY_MACRO (VL_API_SW_INTERFACE_SET_TABLE_REPLY);
|
|
}
|
|
|
|
int
|
|
ip_table_bind (fib_protocol_t fproto, u32 sw_if_index, u32 table_id)
|
|
{
|
|
CLIB_UNUSED (ip_interface_address_t * ia);
|
|
u32 fib_index, mfib_index;
|
|
|
|
/*
|
|
* This if table does not exist = error is what we want in the end.
|
|
*/
|
|
fib_index = fib_table_find (fproto, table_id);
|
|
mfib_index = mfib_table_find (fproto, table_id);
|
|
|
|
if (~0 == fib_index || ~0 == mfib_index)
|
|
{
|
|
return (VNET_API_ERROR_NO_SUCH_FIB);
|
|
}
|
|
|
|
if (FIB_PROTOCOL_IP6 == fproto)
|
|
{
|
|
/*
|
|
* If the interface already has in IP address, then a change int
|
|
* VRF is not allowed. The IP address applied must first be removed.
|
|
* We do not do that automatically here, since VPP has no knowledge
|
|
* of whether those subnets are valid in the destination VRF.
|
|
*/
|
|
/* *INDENT-OFF* */
|
|
foreach_ip_interface_address (&ip6_main.lookup_main,
|
|
ia, sw_if_index,
|
|
1 /* honor unnumbered */ ,
|
|
({
|
|
return (VNET_API_ERROR_ADDRESS_FOUND_FOR_INTERFACE);
|
|
}));
|
|
/* *INDENT-ON* */
|
|
|
|
/*
|
|
* tell those that are interested that the binding is changing.
|
|
*/
|
|
ip6_table_bind_callback_t *cb;
|
|
vec_foreach (cb, ip6_main.table_bind_callbacks)
|
|
cb->function (&ip6_main, cb->function_opaque,
|
|
sw_if_index,
|
|
fib_index,
|
|
ip6_main.fib_index_by_sw_if_index[sw_if_index]);
|
|
|
|
/* unlock currently assigned tables */
|
|
if (0 != ip6_main.fib_index_by_sw_if_index[sw_if_index])
|
|
fib_table_unlock (ip6_main.fib_index_by_sw_if_index[sw_if_index],
|
|
FIB_PROTOCOL_IP6, FIB_SOURCE_INTERFACE);
|
|
if (0 != ip6_main.mfib_index_by_sw_if_index[sw_if_index])
|
|
mfib_table_unlock (ip6_main.mfib_index_by_sw_if_index[sw_if_index],
|
|
FIB_PROTOCOL_IP6, MFIB_SOURCE_INTERFACE);
|
|
|
|
if (0 != table_id)
|
|
{
|
|
/* we need to lock the table now it's inuse */
|
|
fib_table_lock (fib_index, FIB_PROTOCOL_IP6, FIB_SOURCE_INTERFACE);
|
|
mfib_table_lock (mfib_index, FIB_PROTOCOL_IP6,
|
|
MFIB_SOURCE_INTERFACE);
|
|
}
|
|
|
|
ip6_main.fib_index_by_sw_if_index[sw_if_index] = fib_index;
|
|
ip6_main.mfib_index_by_sw_if_index[sw_if_index] = mfib_index;
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
* If the interface already has in IP address, then a change int
|
|
* VRF is not allowed. The IP address applied must first be removed.
|
|
* We do not do that automatically here, since VPP has no knowledge
|
|
* of whether those subnets are valid in the destination VRF.
|
|
*/
|
|
/* *INDENT-OFF* */
|
|
foreach_ip_interface_address (&ip4_main.lookup_main,
|
|
ia, sw_if_index,
|
|
1 /* honor unnumbered */ ,
|
|
({
|
|
return (VNET_API_ERROR_ADDRESS_FOUND_FOR_INTERFACE);
|
|
}));
|
|
/* *INDENT-ON* */
|
|
|
|
/*
|
|
* tell those that are interested that the binding is changing.
|
|
*/
|
|
ip4_table_bind_callback_t *cb;
|
|
vec_foreach (cb, ip4_main.table_bind_callbacks)
|
|
cb->function (&ip4_main, cb->function_opaque,
|
|
sw_if_index,
|
|
fib_index,
|
|
ip4_main.fib_index_by_sw_if_index[sw_if_index]);
|
|
|
|
/* unlock currently assigned tables */
|
|
if (0 != ip4_main.fib_index_by_sw_if_index[sw_if_index])
|
|
fib_table_unlock (ip4_main.fib_index_by_sw_if_index[sw_if_index],
|
|
FIB_PROTOCOL_IP4, FIB_SOURCE_INTERFACE);
|
|
if (0 != ip4_main.mfib_index_by_sw_if_index[sw_if_index])
|
|
mfib_table_unlock (ip4_main.mfib_index_by_sw_if_index[sw_if_index],
|
|
FIB_PROTOCOL_IP4, MFIB_SOURCE_INTERFACE);
|
|
|
|
if (0 != table_id)
|
|
{
|
|
/* we need to lock the table now it's inuse */
|
|
fib_index = fib_table_find_or_create_and_lock (
|
|
FIB_PROTOCOL_IP4, table_id, FIB_SOURCE_INTERFACE);
|
|
|
|
mfib_index = mfib_table_find_or_create_and_lock (
|
|
FIB_PROTOCOL_IP4, table_id, MFIB_SOURCE_INTERFACE);
|
|
}
|
|
|
|
ip4_main.fib_index_by_sw_if_index[sw_if_index] = fib_index;
|
|
ip4_main.mfib_index_by_sw_if_index[sw_if_index] = mfib_index;
|
|
}
|
|
|
|
return (0);
|
|
}
|
|
|
|
static void
|
|
send_sw_interface_get_table_reply (vl_api_registration_t * reg,
|
|
u32 context, int retval, u32 vrf_id)
|
|
{
|
|
vl_api_sw_interface_get_table_reply_t *mp;
|
|
|
|
mp = vl_msg_api_alloc (sizeof (*mp));
|
|
clib_memset (mp, 0, sizeof (*mp));
|
|
mp->_vl_msg_id =
|
|
ntohs (REPLY_MSG_ID_BASE + VL_API_SW_INTERFACE_GET_TABLE_REPLY);
|
|
mp->context = context;
|
|
mp->retval = htonl (retval);
|
|
mp->vrf_id = htonl (vrf_id);
|
|
|
|
vl_api_send_msg (reg, (u8 *) mp);
|
|
}
|
|
|
|
static void
|
|
vl_api_sw_interface_get_table_t_handler (vl_api_sw_interface_get_table_t * mp)
|
|
{
|
|
vl_api_registration_t *reg;
|
|
fib_table_t *fib_table = 0;
|
|
u32 sw_if_index = ~0;
|
|
u32 fib_index = ~0;
|
|
u32 table_id = ~0;
|
|
fib_protocol_t fib_proto = FIB_PROTOCOL_IP4;
|
|
int rv = 0;
|
|
|
|
reg = vl_api_client_index_to_registration (mp->client_index);
|
|
if (!reg)
|
|
return;
|
|
|
|
VALIDATE_SW_IF_INDEX (mp);
|
|
|
|
sw_if_index = ntohl (mp->sw_if_index);
|
|
|
|
if (mp->is_ipv6)
|
|
fib_proto = FIB_PROTOCOL_IP6;
|
|
|
|
fib_index = fib_table_get_index_for_sw_if_index (fib_proto, sw_if_index);
|
|
if (fib_index != ~0)
|
|
{
|
|
fib_table = fib_table_get (fib_index, fib_proto);
|
|
table_id = fib_table->ft_table_id;
|
|
}
|
|
|
|
BAD_SW_IF_INDEX_LABEL;
|
|
|
|
send_sw_interface_get_table_reply (reg, mp->context, rv, table_id);
|
|
}
|
|
|
|
static void vl_api_sw_interface_set_unnumbered_t_handler
|
|
(vl_api_sw_interface_set_unnumbered_t * mp)
|
|
{
|
|
vl_api_sw_interface_set_unnumbered_reply_t *rmp;
|
|
int rv = 0;
|
|
vnet_main_t *vnm = vnet_get_main ();
|
|
u32 sw_if_index = ntohl (mp->sw_if_index);
|
|
u32 unnumbered_sw_if_index = ntohl (mp->unnumbered_sw_if_index);
|
|
|
|
/*
|
|
* The API message field names are backwards from
|
|
* the underlying data structure names.
|
|
* It's not worth changing them now.
|
|
*/
|
|
if (!vnet_sw_interface_is_api_valid (vnm, unnumbered_sw_if_index))
|
|
{
|
|
rv = VNET_API_ERROR_INVALID_SW_IF_INDEX;
|
|
goto done;
|
|
}
|
|
|
|
/* Only check the "use loop0" field when setting the binding */
|
|
if (mp->is_add && !vnet_sw_interface_is_api_valid (vnm, sw_if_index))
|
|
{
|
|
rv = VNET_API_ERROR_INVALID_SW_IF_INDEX_2;
|
|
goto done;
|
|
}
|
|
|
|
rv = vnet_sw_interface_update_unnumbered (unnumbered_sw_if_index,
|
|
sw_if_index, mp->is_add);
|
|
done:
|
|
REPLY_MACRO (VL_API_SW_INTERFACE_SET_UNNUMBERED_REPLY);
|
|
}
|
|
|
|
static void
|
|
vl_api_sw_interface_clear_stats_t_handler (vl_api_sw_interface_clear_stats_t *
|
|
mp)
|
|
{
|
|
vl_api_sw_interface_clear_stats_reply_t *rmp;
|
|
|
|
vnet_main_t *vnm = vnet_get_main ();
|
|
vnet_interface_main_t *im = &vnm->interface_main;
|
|
vlib_simple_counter_main_t *sm;
|
|
vlib_combined_counter_main_t *cm;
|
|
int j, n_counters;
|
|
int rv = 0;
|
|
|
|
if (mp->sw_if_index != ~0)
|
|
VALIDATE_SW_IF_INDEX (mp);
|
|
|
|
n_counters = vec_len (im->combined_sw_if_counters);
|
|
|
|
for (j = 0; j < n_counters; j++)
|
|
{
|
|
im = &vnm->interface_main;
|
|
cm = im->combined_sw_if_counters + j;
|
|
if (mp->sw_if_index == (u32) ~ 0)
|
|
vlib_clear_combined_counters (cm);
|
|
else
|
|
vlib_zero_combined_counter (cm, ntohl (mp->sw_if_index));
|
|
}
|
|
|
|
n_counters = vec_len (im->sw_if_counters);
|
|
|
|
for (j = 0; j < n_counters; j++)
|
|
{
|
|
im = &vnm->interface_main;
|
|
sm = im->sw_if_counters + j;
|
|
if (mp->sw_if_index == (u32) ~ 0)
|
|
vlib_clear_simple_counters (sm);
|
|
else
|
|
vlib_zero_simple_counter (sm, ntohl (mp->sw_if_index));
|
|
}
|
|
|
|
BAD_SW_IF_INDEX_LABEL;
|
|
|
|
REPLY_MACRO (VL_API_SW_INTERFACE_CLEAR_STATS_REPLY);
|
|
}
|
|
|
|
/*
|
|
* Events used for sw_interface_events
|
|
*/
|
|
enum api_events
|
|
{
|
|
API_LINK_STATE_UP_EVENT = 1 << 1,
|
|
API_LINK_STATE_DOWN_EVENT = 1 << 2,
|
|
API_ADMIN_UP_EVENT = 1 << 3,
|
|
API_ADMIN_DOWN_EVENT = 1 << 4,
|
|
API_SW_INTERFACE_ADD_EVENT = 1 << 5,
|
|
API_SW_INTERFACE_DEL_EVENT = 1 << 6,
|
|
};
|
|
|
|
static void
|
|
send_sw_interface_event (vpe_api_main_t * am,
|
|
vpe_client_registration_t * reg,
|
|
vl_api_registration_t * vl_reg,
|
|
u32 sw_if_index, enum api_events events)
|
|
{
|
|
vl_api_sw_interface_event_t *mp;
|
|
|
|
mp = vl_msg_api_alloc (sizeof (*mp));
|
|
clib_memset (mp, 0, sizeof (*mp));
|
|
mp->_vl_msg_id = ntohs (REPLY_MSG_ID_BASE + VL_API_SW_INTERFACE_EVENT);
|
|
mp->sw_if_index = ntohl (sw_if_index);
|
|
mp->client_index = reg->client_index;
|
|
mp->pid = reg->client_pid;
|
|
mp->flags = 0;
|
|
mp->flags |= (events & API_ADMIN_UP_EVENT) ?
|
|
IF_STATUS_API_FLAG_ADMIN_UP : 0;
|
|
mp->flags |= (events & API_LINK_STATE_UP_EVENT) ?
|
|
IF_STATUS_API_FLAG_LINK_UP : 0;
|
|
mp->flags = ntohl (mp->flags);
|
|
mp->deleted = events & API_SW_INTERFACE_DEL_EVENT ? true : false;
|
|
vl_api_send_msg (vl_reg, (u8 *) mp);
|
|
}
|
|
|
|
static uword
|
|
link_state_process (vlib_main_t * vm,
|
|
vlib_node_runtime_t * rt, vlib_frame_t * f)
|
|
{
|
|
vpe_api_main_t *vam = &vpe_api_main;
|
|
uword *event_by_sw_if_index = 0;
|
|
vpe_client_registration_t *reg;
|
|
int i;
|
|
vl_api_registration_t *vl_reg;
|
|
uword event_type;
|
|
uword *event_data = 0;
|
|
u32 sw_if_index;
|
|
|
|
vam->link_state_process_up = 1;
|
|
|
|
while (1)
|
|
{
|
|
vlib_process_wait_for_event (vm);
|
|
|
|
/* Batch up events */
|
|
while ((event_type = vlib_process_get_events (vm, &event_data)) != ~0)
|
|
{
|
|
for (i = 0; i < vec_len (event_data); i++)
|
|
{
|
|
sw_if_index = event_data[i];
|
|
vec_validate_init_empty (event_by_sw_if_index, sw_if_index, 0);
|
|
event_by_sw_if_index[sw_if_index] |= event_type;
|
|
}
|
|
vec_reset_length (event_data);
|
|
}
|
|
|
|
for (i = 0; i < vec_len (event_by_sw_if_index); i++)
|
|
{
|
|
if (event_by_sw_if_index[i] == 0)
|
|
continue;
|
|
|
|
/* *INDENT-OFF* */
|
|
pool_foreach (reg, vam->interface_events_registrations)
|
|
{
|
|
vl_reg = vl_api_client_index_to_registration (reg->client_index);
|
|
if (vl_reg)
|
|
send_sw_interface_event (vam, reg, vl_reg, i, event_by_sw_if_index[i]);
|
|
}
|
|
/* *INDENT-ON* */
|
|
}
|
|
vec_reset_length (event_by_sw_if_index);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static clib_error_t *link_up_down_function (vnet_main_t * vm, u32 hw_if_index,
|
|
u32 flags);
|
|
static clib_error_t *admin_up_down_function (vnet_main_t * vm,
|
|
u32 hw_if_index, u32 flags);
|
|
static clib_error_t *sw_interface_add_del_function (vnet_main_t * vm,
|
|
u32 sw_if_index,
|
|
u32 flags);
|
|
|
|
/* *INDENT-OFF* */
|
|
VLIB_REGISTER_NODE (link_state_process_node,static) = {
|
|
.function = link_state_process,
|
|
.type = VLIB_NODE_TYPE_PROCESS,
|
|
.name = "vpe-link-state-process",
|
|
};
|
|
/* *INDENT-ON* */
|
|
|
|
VNET_SW_INTERFACE_ADMIN_UP_DOWN_FUNCTION (admin_up_down_function);
|
|
VNET_HW_INTERFACE_LINK_UP_DOWN_FUNCTION (link_up_down_function);
|
|
VNET_SW_INTERFACE_ADD_DEL_FUNCTION (sw_interface_add_del_function);
|
|
|
|
static clib_error_t *
|
|
link_up_down_function (vnet_main_t * vm, u32 hw_if_index, u32 flags)
|
|
{
|
|
vpe_api_main_t *vam = &vpe_api_main;
|
|
vnet_hw_interface_t *hi = vnet_get_hw_interface (vm, hw_if_index);
|
|
|
|
if (vam->link_state_process_up)
|
|
{
|
|
enum api_events event = ((flags & VNET_HW_INTERFACE_FLAG_LINK_UP) ?
|
|
API_LINK_STATE_UP_EVENT :
|
|
API_LINK_STATE_DOWN_EVENT);
|
|
vlib_process_signal_event (vam->vlib_main,
|
|
link_state_process_node.index, event,
|
|
hi->sw_if_index);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static clib_error_t *
|
|
admin_up_down_function (vnet_main_t * vm, u32 sw_if_index, u32 flags)
|
|
{
|
|
vpe_api_main_t *vam = &vpe_api_main;
|
|
|
|
/*
|
|
* Note: it's perfectly fair to set a subif admin up / admin down.
|
|
* Note the subtle distinction between this routine and the previous
|
|
* routine.
|
|
*/
|
|
if (vam->link_state_process_up)
|
|
{
|
|
enum api_events event = ((flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP) ?
|
|
API_ADMIN_UP_EVENT : API_ADMIN_DOWN_EVENT);
|
|
vlib_process_signal_event (vam->vlib_main,
|
|
link_state_process_node.index, event,
|
|
sw_if_index);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static clib_error_t *
|
|
sw_interface_add_del_function (vnet_main_t * vm, u32 sw_if_index, u32 flags)
|
|
{
|
|
vpe_api_main_t *vam = &vpe_api_main;
|
|
|
|
if (vam->link_state_process_up)
|
|
{
|
|
enum api_events event =
|
|
flags ? API_SW_INTERFACE_ADD_EVENT : API_SW_INTERFACE_DEL_EVENT;
|
|
vlib_process_signal_event (vam->vlib_main,
|
|
link_state_process_node.index, event,
|
|
sw_if_index);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static void vl_api_sw_interface_tag_add_del_t_handler
|
|
(vl_api_sw_interface_tag_add_del_t * mp)
|
|
{
|
|
vnet_main_t *vnm = vnet_get_main ();
|
|
vl_api_sw_interface_tag_add_del_reply_t *rmp;
|
|
int rv = 0;
|
|
u8 *tag;
|
|
u32 sw_if_index = ntohl (mp->sw_if_index);
|
|
|
|
VALIDATE_SW_IF_INDEX (mp);
|
|
|
|
if (mp->is_add)
|
|
{
|
|
if (mp->tag[0] == 0)
|
|
{
|
|
rv = VNET_API_ERROR_INVALID_VALUE;
|
|
goto out;
|
|
}
|
|
|
|
mp->tag[ARRAY_LEN (mp->tag) - 1] = 0;
|
|
tag = format (0, "%s%c", mp->tag, 0);
|
|
vnet_set_sw_interface_tag (vnm, tag, sw_if_index);
|
|
}
|
|
else
|
|
vnet_clear_sw_interface_tag (vnm, sw_if_index);
|
|
|
|
BAD_SW_IF_INDEX_LABEL;
|
|
out:
|
|
REPLY_MACRO (VL_API_SW_INTERFACE_TAG_ADD_DEL_REPLY);
|
|
}
|
|
|
|
static void vl_api_sw_interface_add_del_mac_address_t_handler
|
|
(vl_api_sw_interface_add_del_mac_address_t * mp)
|
|
{
|
|
vl_api_sw_interface_add_del_mac_address_reply_t *rmp;
|
|
vnet_main_t *vnm = vnet_get_main ();
|
|
u32 sw_if_index = ntohl (mp->sw_if_index);
|
|
vnet_hw_interface_t *hi;
|
|
clib_error_t *error;
|
|
int rv = 0;
|
|
|
|
VALIDATE_SW_IF_INDEX (mp);
|
|
|
|
/* for subifs, the MAC should be changed on the actual hw if */
|
|
hi = vnet_get_sup_hw_interface (vnm, sw_if_index);
|
|
error = vnet_hw_interface_add_del_mac_address (vnm, hi->hw_if_index,
|
|
mp->addr, mp->is_add);
|
|
if (error)
|
|
{
|
|
rv = VNET_API_ERROR_UNIMPLEMENTED;
|
|
clib_error_report (error);
|
|
goto out;
|
|
}
|
|
|
|
BAD_SW_IF_INDEX_LABEL;
|
|
out:
|
|
REPLY_MACRO (VL_API_SW_INTERFACE_ADD_DEL_MAC_ADDRESS_REPLY);
|
|
}
|
|
|
|
static void vl_api_sw_interface_set_mac_address_t_handler
|
|
(vl_api_sw_interface_set_mac_address_t * mp)
|
|
{
|
|
vl_api_sw_interface_set_mac_address_reply_t *rmp;
|
|
vnet_main_t *vnm = vnet_get_main ();
|
|
u32 sw_if_index = ntohl (mp->sw_if_index);
|
|
vnet_sw_interface_t *si;
|
|
clib_error_t *error;
|
|
int rv = 0;
|
|
mac_address_t mac;
|
|
|
|
VALIDATE_SW_IF_INDEX (mp);
|
|
|
|
si = vnet_get_sw_interface (vnm, sw_if_index);
|
|
mac_address_decode (mp->mac_address, &mac);
|
|
error =
|
|
vnet_hw_interface_change_mac_address (vnm, si->hw_if_index, (u8 *) & mac);
|
|
if (error)
|
|
{
|
|
rv = VNET_API_ERROR_UNIMPLEMENTED;
|
|
clib_error_report (error);
|
|
goto out;
|
|
}
|
|
|
|
BAD_SW_IF_INDEX_LABEL;
|
|
out:
|
|
REPLY_MACRO (VL_API_SW_INTERFACE_SET_MAC_ADDRESS_REPLY);
|
|
}
|
|
|
|
static void vl_api_sw_interface_get_mac_address_t_handler
|
|
(vl_api_sw_interface_get_mac_address_t * mp)
|
|
{
|
|
vl_api_sw_interface_get_mac_address_reply_t *rmp;
|
|
vl_api_registration_t *reg;
|
|
vnet_main_t *vnm = vnet_get_main ();
|
|
u32 sw_if_index = ntohl (mp->sw_if_index);
|
|
vnet_sw_interface_t *si;
|
|
ethernet_interface_t *eth_if = 0;
|
|
int rv = 0;
|
|
|
|
VALIDATE_SW_IF_INDEX (mp);
|
|
|
|
si = vnet_get_sup_sw_interface (vnm, sw_if_index);
|
|
if (si->type == VNET_SW_INTERFACE_TYPE_HARDWARE)
|
|
eth_if = ethernet_get_interface (ðernet_main, si->hw_if_index);
|
|
|
|
BAD_SW_IF_INDEX_LABEL;
|
|
|
|
reg = vl_api_client_index_to_registration (mp->client_index);
|
|
if (!reg)
|
|
return;
|
|
rmp = vl_msg_api_alloc (sizeof (*rmp));
|
|
rmp->_vl_msg_id =
|
|
htons (REPLY_MSG_ID_BASE + VL_API_SW_INTERFACE_GET_MAC_ADDRESS_REPLY);
|
|
rmp->context = mp->context;
|
|
rmp->retval = htonl (rv);
|
|
if (!rv && eth_if)
|
|
mac_address_encode (ð_if->address.mac, rmp->mac_address);
|
|
vl_api_send_msg (reg, (u8 *) rmp);
|
|
}
|
|
|
|
static void
|
|
vl_api_sw_interface_set_interface_name_t_handler (
|
|
vl_api_sw_interface_set_interface_name_t *mp)
|
|
{
|
|
vl_api_sw_interface_set_interface_name_reply_t *rmp;
|
|
vnet_main_t *vnm = vnet_get_main ();
|
|
u32 sw_if_index = ntohl (mp->sw_if_index);
|
|
vnet_sw_interface_t *si = vnet_get_sw_interface (vnm, sw_if_index);
|
|
clib_error_t *error;
|
|
int rv = 0;
|
|
|
|
if (mp->name[0] == 0)
|
|
{
|
|
rv = VNET_API_ERROR_INVALID_VALUE;
|
|
goto out;
|
|
}
|
|
if (si == 0)
|
|
{
|
|
rv = VNET_API_ERROR_INVALID_SW_IF_INDEX;
|
|
goto out;
|
|
}
|
|
|
|
error = vnet_rename_interface (vnm, si->hw_if_index, (char *) mp->name);
|
|
if (error)
|
|
{
|
|
clib_error_free (error);
|
|
rv = VNET_API_ERROR_INVALID_SW_IF_INDEX;
|
|
}
|
|
|
|
out:
|
|
REPLY_MACRO (VL_API_SW_INTERFACE_SET_INTERFACE_NAME_REPLY);
|
|
}
|
|
|
|
static void vl_api_sw_interface_set_rx_mode_t_handler
|
|
(vl_api_sw_interface_set_rx_mode_t * mp)
|
|
{
|
|
vl_api_sw_interface_set_rx_mode_reply_t *rmp;
|
|
vnet_main_t *vnm = vnet_get_main ();
|
|
u32 sw_if_index = ntohl (mp->sw_if_index);
|
|
vnet_sw_interface_t *si;
|
|
clib_error_t *error;
|
|
int rv = 0;
|
|
vnet_hw_if_rx_mode rx_mode;
|
|
|
|
VALIDATE_SW_IF_INDEX (mp);
|
|
|
|
si = vnet_get_sw_interface (vnm, sw_if_index);
|
|
if (si->type != VNET_SW_INTERFACE_TYPE_HARDWARE)
|
|
{
|
|
rv = VNET_API_ERROR_INVALID_VALUE;
|
|
goto bad_sw_if_index;
|
|
}
|
|
|
|
rx_mode = (vnet_hw_if_rx_mode) ntohl (mp->mode);
|
|
error = set_hw_interface_change_rx_mode (vnm, si->hw_if_index,
|
|
mp->queue_id_valid,
|
|
ntohl (mp->queue_id),
|
|
(vnet_hw_if_rx_mode) rx_mode);
|
|
|
|
if (error)
|
|
{
|
|
rv = VNET_API_ERROR_UNIMPLEMENTED;
|
|
clib_error_report (error);
|
|
goto out;
|
|
}
|
|
|
|
BAD_SW_IF_INDEX_LABEL;
|
|
out:
|
|
REPLY_MACRO (VL_API_SW_INTERFACE_SET_RX_MODE_REPLY);
|
|
}
|
|
|
|
static void
|
|
send_interface_rx_placement_details (vpe_api_main_t * am,
|
|
vl_api_registration_t * rp,
|
|
u32 sw_if_index, u32 worker_id,
|
|
u32 queue_id, u8 mode, u32 context)
|
|
{
|
|
vl_api_sw_interface_rx_placement_details_t *mp;
|
|
mp = vl_msg_api_alloc (sizeof (*mp));
|
|
clib_memset (mp, 0, sizeof (*mp));
|
|
|
|
mp->_vl_msg_id =
|
|
htons (REPLY_MSG_ID_BASE + VL_API_SW_INTERFACE_RX_PLACEMENT_DETAILS);
|
|
mp->sw_if_index = htonl (sw_if_index);
|
|
mp->queue_id = htonl (queue_id);
|
|
mp->worker_id = htonl (worker_id);
|
|
mp->mode = htonl (mode);
|
|
mp->context = context;
|
|
|
|
vl_api_send_msg (rp, (u8 *) mp);
|
|
}
|
|
|
|
static void vl_api_sw_interface_rx_placement_dump_t_handler
|
|
(vl_api_sw_interface_rx_placement_dump_t * mp)
|
|
{
|
|
vnet_main_t *vnm = vnet_get_main ();
|
|
vpe_api_main_t *am = &vpe_api_main;
|
|
u32 sw_if_index = ntohl (mp->sw_if_index);
|
|
vl_api_registration_t *reg;
|
|
|
|
reg = vl_api_client_index_to_registration (mp->client_index);
|
|
if (!reg)
|
|
return;
|
|
|
|
if (sw_if_index == ~0)
|
|
{
|
|
vnet_hw_if_rx_queue_t **all_queues = 0;
|
|
vnet_hw_if_rx_queue_t **qptr;
|
|
vnet_hw_if_rx_queue_t *q;
|
|
pool_foreach (q, vnm->interface_main.hw_if_rx_queues)
|
|
vec_add1 (all_queues, q);
|
|
vec_sort_with_function (all_queues, vnet_hw_if_rxq_cmp_cli_api);
|
|
|
|
vec_foreach (qptr, all_queues)
|
|
{
|
|
u32 current_thread = qptr[0]->thread_index;
|
|
u32 hw_if_index = qptr[0]->hw_if_index;
|
|
vnet_hw_interface_t *hw_if =
|
|
vnet_get_hw_interface (vnm, hw_if_index);
|
|
send_interface_rx_placement_details (
|
|
am, reg, hw_if->sw_if_index, current_thread, qptr[0]->queue_id,
|
|
qptr[0]->mode, mp->context);
|
|
}
|
|
vec_free (all_queues);
|
|
}
|
|
else
|
|
{
|
|
int i;
|
|
vnet_sw_interface_t *si;
|
|
|
|
if (!vnet_sw_if_index_is_api_valid (sw_if_index))
|
|
{
|
|
clib_warning ("sw_if_index %u does not exist", sw_if_index);
|
|
goto bad_sw_if_index;
|
|
}
|
|
|
|
si = vnet_get_sw_interface (vnm, sw_if_index);
|
|
if (si->type != VNET_SW_INTERFACE_TYPE_HARDWARE)
|
|
{
|
|
clib_warning ("interface type is not HARDWARE! P2P, PIPE and SUB"
|
|
" interfaces are not supported");
|
|
goto bad_sw_if_index;
|
|
}
|
|
|
|
vnet_hw_interface_t *hw = vnet_get_hw_interface (vnm, si->hw_if_index);
|
|
|
|
for (i = 0; i < vec_len (hw->rx_queue_indices); i++)
|
|
{
|
|
vnet_hw_if_rx_queue_t *rxq =
|
|
vnet_hw_if_get_rx_queue (vnm, hw->rx_queue_indices[i]);
|
|
send_interface_rx_placement_details (
|
|
am, reg, hw->sw_if_index, rxq->thread_index, rxq->queue_id,
|
|
rxq->mode, mp->context);
|
|
}
|
|
}
|
|
|
|
BAD_SW_IF_INDEX_LABEL;
|
|
}
|
|
|
|
static void vl_api_sw_interface_set_rx_placement_t_handler
|
|
(vl_api_sw_interface_set_rx_placement_t * mp)
|
|
{
|
|
vl_api_sw_interface_set_rx_placement_reply_t *rmp;
|
|
vnet_main_t *vnm = vnet_get_main ();
|
|
u32 sw_if_index = ntohl (mp->sw_if_index);
|
|
vnet_sw_interface_t *si;
|
|
clib_error_t *error = 0;
|
|
int rv = 0;
|
|
|
|
VALIDATE_SW_IF_INDEX (mp);
|
|
|
|
si = vnet_get_sw_interface (vnm, sw_if_index);
|
|
if (si->type != VNET_SW_INTERFACE_TYPE_HARDWARE)
|
|
{
|
|
rv = VNET_API_ERROR_INVALID_VALUE;
|
|
goto bad_sw_if_index;
|
|
}
|
|
|
|
error = set_hw_interface_rx_placement (si->hw_if_index,
|
|
ntohl (mp->queue_id),
|
|
ntohl (mp->worker_id), mp->is_main);
|
|
if (error)
|
|
{
|
|
rv = VNET_API_ERROR_UNIMPLEMENTED;
|
|
clib_error_report (error);
|
|
goto out;
|
|
}
|
|
|
|
BAD_SW_IF_INDEX_LABEL;
|
|
out:
|
|
REPLY_MACRO (VL_API_SW_INTERFACE_SET_RX_PLACEMENT_REPLY);
|
|
}
|
|
|
|
static void
|
|
vl_api_create_vlan_subif_t_handler (vl_api_create_vlan_subif_t * mp)
|
|
{
|
|
vl_api_create_vlan_subif_reply_t *rmp;
|
|
vnet_main_t *vnm = vnet_get_main ();
|
|
u32 sw_if_index = (u32) ~ 0;
|
|
vnet_hw_interface_t *hi;
|
|
int rv = 0;
|
|
u32 id;
|
|
vnet_sw_interface_t template;
|
|
uword *p;
|
|
vnet_interface_main_t *im = &vnm->interface_main;
|
|
u64 sup_and_sub_key;
|
|
vl_api_registration_t *reg;
|
|
clib_error_t *error;
|
|
|
|
VALIDATE_SW_IF_INDEX (mp);
|
|
|
|
hi = vnet_get_sup_hw_interface (vnm, ntohl (mp->sw_if_index));
|
|
|
|
if (hi->bond_info == VNET_HW_INTERFACE_BOND_INFO_SLAVE)
|
|
{
|
|
rv = VNET_API_ERROR_BOND_SLAVE_NOT_ALLOWED;
|
|
goto out;
|
|
}
|
|
|
|
id = ntohl (mp->vlan_id);
|
|
if (id == 0 || id > 4095)
|
|
{
|
|
rv = VNET_API_ERROR_INVALID_VLAN;
|
|
goto out;
|
|
}
|
|
|
|
sup_and_sub_key = ((u64) (hi->sw_if_index) << 32) | (u64) id;
|
|
|
|
p = hash_get_mem (im->sw_if_index_by_sup_and_sub, &sup_and_sub_key);
|
|
if (p)
|
|
{
|
|
rv = VNET_API_ERROR_VLAN_ALREADY_EXISTS;
|
|
goto out;
|
|
}
|
|
|
|
clib_memset (&template, 0, sizeof (template));
|
|
template.type = VNET_SW_INTERFACE_TYPE_SUB;
|
|
template.flood_class = VNET_FLOOD_CLASS_NORMAL;
|
|
template.sup_sw_if_index = hi->sw_if_index;
|
|
template.sub.id = id;
|
|
template.sub.eth.raw_flags = 0;
|
|
template.sub.eth.flags.one_tag = 1;
|
|
template.sub.eth.outer_vlan_id = id;
|
|
template.sub.eth.flags.exact_match = 1;
|
|
|
|
error = vnet_create_sw_interface (vnm, &template, &sw_if_index);
|
|
if (error)
|
|
{
|
|
clib_error_report (error);
|
|
rv = VNET_API_ERROR_INVALID_REGISTRATION;
|
|
goto out;
|
|
}
|
|
|
|
u64 *kp = clib_mem_alloc (sizeof (*kp));
|
|
*kp = sup_and_sub_key;
|
|
|
|
hash_set (hi->sub_interface_sw_if_index_by_id, id, sw_if_index);
|
|
hash_set_mem (im->sw_if_index_by_sup_and_sub, kp, sw_if_index);
|
|
|
|
BAD_SW_IF_INDEX_LABEL;
|
|
|
|
out:
|
|
reg = vl_api_client_index_to_registration (mp->client_index);
|
|
if (!reg)
|
|
return;
|
|
|
|
rmp = vl_msg_api_alloc (sizeof (*rmp));
|
|
rmp->_vl_msg_id = htons (REPLY_MSG_ID_BASE + VL_API_CREATE_VLAN_SUBIF_REPLY);
|
|
rmp->context = mp->context;
|
|
rmp->retval = htonl (rv);
|
|
rmp->sw_if_index = htonl (sw_if_index);
|
|
vl_api_send_msg (reg, (u8 *) rmp);
|
|
}
|
|
|
|
static void
|
|
vl_api_create_subif_t_handler (vl_api_create_subif_t * mp)
|
|
{
|
|
vl_api_create_subif_reply_t *rmp;
|
|
vnet_main_t *vnm = vnet_get_main ();
|
|
u32 sub_sw_if_index = ~0;
|
|
vnet_hw_interface_t *hi;
|
|
int rv = 0;
|
|
|
|
VALIDATE_SW_IF_INDEX (mp);
|
|
|
|
hi = vnet_get_sup_hw_interface (vnm, ntohl (mp->sw_if_index));
|
|
|
|
if (hi->bond_info == VNET_HW_INTERFACE_BOND_INFO_SLAVE)
|
|
rv = VNET_API_ERROR_BOND_SLAVE_NOT_ALLOWED;
|
|
else
|
|
rv = vnet_create_sub_interface (ntohl (mp->sw_if_index),
|
|
ntohl (mp->sub_id),
|
|
ntohl (mp->sub_if_flags),
|
|
ntohs (mp->inner_vlan_id),
|
|
ntohs (mp->outer_vlan_id),
|
|
&sub_sw_if_index);
|
|
|
|
BAD_SW_IF_INDEX_LABEL;
|
|
|
|
/* *INDENT-OFF* */
|
|
REPLY_MACRO2(VL_API_CREATE_SUBIF_REPLY,
|
|
({
|
|
rmp->sw_if_index = ntohl(sub_sw_if_index);
|
|
}));
|
|
/* *INDENT-ON* */
|
|
}
|
|
|
|
static void
|
|
vl_api_delete_subif_t_handler (vl_api_delete_subif_t * mp)
|
|
{
|
|
vl_api_delete_subif_reply_t *rmp;
|
|
int rv;
|
|
|
|
rv = vnet_delete_sub_interface (ntohl (mp->sw_if_index));
|
|
|
|
REPLY_MACRO (VL_API_DELETE_SUBIF_REPLY);
|
|
}
|
|
|
|
static void
|
|
vl_api_interface_name_renumber_t_handler (vl_api_interface_name_renumber_t *
|
|
mp)
|
|
{
|
|
vl_api_interface_name_renumber_reply_t *rmp;
|
|
int rv = 0;
|
|
|
|
VALIDATE_SW_IF_INDEX (mp);
|
|
|
|
rv = vnet_interface_name_renumber
|
|
(ntohl (mp->sw_if_index), ntohl (mp->new_show_dev_instance));
|
|
|
|
BAD_SW_IF_INDEX_LABEL;
|
|
|
|
REPLY_MACRO (VL_API_INTERFACE_NAME_RENUMBER_REPLY);
|
|
}
|
|
|
|
static void
|
|
vl_api_create_loopback_t_handler (vl_api_create_loopback_t * mp)
|
|
{
|
|
vl_api_create_loopback_reply_t *rmp;
|
|
u32 sw_if_index;
|
|
int rv;
|
|
mac_address_t mac;
|
|
|
|
mac_address_decode (mp->mac_address, &mac);
|
|
rv = vnet_create_loopback_interface (&sw_if_index, (u8 *) & mac, 0, 0);
|
|
|
|
/* *INDENT-OFF* */
|
|
REPLY_MACRO2(VL_API_CREATE_LOOPBACK_REPLY,
|
|
({
|
|
rmp->sw_if_index = ntohl (sw_if_index);
|
|
}));
|
|
/* *INDENT-ON* */
|
|
}
|
|
|
|
static void vl_api_create_loopback_instance_t_handler
|
|
(vl_api_create_loopback_instance_t * mp)
|
|
{
|
|
vl_api_create_loopback_instance_reply_t *rmp;
|
|
u32 sw_if_index;
|
|
u8 is_specified = mp->is_specified;
|
|
u32 user_instance = ntohl (mp->user_instance);
|
|
int rv;
|
|
mac_address_t mac;
|
|
|
|
mac_address_decode (mp->mac_address, &mac);
|
|
rv = vnet_create_loopback_interface (&sw_if_index, (u8 *) & mac,
|
|
is_specified, user_instance);
|
|
|
|
/* *INDENT-OFF* */
|
|
REPLY_MACRO2(VL_API_CREATE_LOOPBACK_INSTANCE_REPLY,
|
|
({
|
|
rmp->sw_if_index = ntohl (sw_if_index);
|
|
}));
|
|
/* *INDENT-ON* */
|
|
}
|
|
|
|
static void
|
|
vl_api_delete_loopback_t_handler (vl_api_delete_loopback_t * mp)
|
|
{
|
|
vl_api_delete_loopback_reply_t *rmp;
|
|
u32 sw_if_index;
|
|
int rv;
|
|
|
|
sw_if_index = ntohl (mp->sw_if_index);
|
|
rv = vnet_delete_loopback_interface (sw_if_index);
|
|
|
|
REPLY_MACRO (VL_API_DELETE_LOOPBACK_REPLY);
|
|
}
|
|
|
|
static void
|
|
vl_api_collect_detailed_interface_stats_t_handler
|
|
(vl_api_collect_detailed_interface_stats_t * mp)
|
|
{
|
|
vl_api_collect_detailed_interface_stats_reply_t *rmp;
|
|
int rv = 0;
|
|
|
|
rv =
|
|
vnet_sw_interface_stats_collect_enable_disable (ntohl (mp->sw_if_index),
|
|
mp->enable_disable);
|
|
|
|
REPLY_MACRO (VL_API_COLLECT_DETAILED_INTERFACE_STATS_REPLY);
|
|
}
|
|
|
|
static void
|
|
vl_api_sw_interface_address_replace_begin_t_handler
|
|
(vl_api_sw_interface_address_replace_begin_t * mp)
|
|
{
|
|
vl_api_sw_interface_address_replace_begin_reply_t *rmp;
|
|
int rv = 0;
|
|
|
|
ip_interface_address_mark ();
|
|
|
|
REPLY_MACRO (VL_API_SW_INTERFACE_ADDRESS_REPLACE_BEGIN_REPLY);
|
|
}
|
|
|
|
static void
|
|
vl_api_sw_interface_address_replace_end_t_handler
|
|
(vl_api_sw_interface_address_replace_end_t * mp)
|
|
{
|
|
vl_api_sw_interface_address_replace_end_reply_t *rmp;
|
|
int rv = 0;
|
|
|
|
ip_interface_address_sweep ();
|
|
|
|
REPLY_MACRO (VL_API_SW_INTERFACE_ADDRESS_REPLACE_END_REPLY);
|
|
}
|
|
|
|
/*
|
|
* vpe_api_hookup
|
|
* Add vpe's API message handlers to the table.
|
|
* vlib has already mapped shared memory and
|
|
* added the client registration handlers.
|
|
* See .../vlib-api/vlibmemory/memclnt_vlib.c:memclnt_process()
|
|
*/
|
|
|
|
pub_sub_handler (interface_events, INTERFACE_EVENTS);
|
|
|
|
#include <vnet/interface.api.c>
|
|
static clib_error_t *
|
|
interface_api_hookup (vlib_main_t * vm)
|
|
{
|
|
api_main_t *am = vlibapi_get_main ();
|
|
|
|
/* Mark these APIs as mp safe */
|
|
am->is_mp_safe[VL_API_SW_INTERFACE_DUMP] = 1;
|
|
am->is_mp_safe[VL_API_SW_INTERFACE_DETAILS] = 1;
|
|
am->is_mp_safe[VL_API_SW_INTERFACE_TAG_ADD_DEL] = 1;
|
|
am->is_mp_safe[VL_API_SW_INTERFACE_SET_INTERFACE_NAME] = 1;
|
|
|
|
/* Do not replay VL_API_SW_INTERFACE_DUMP messages */
|
|
am->api_trace_cfg[VL_API_SW_INTERFACE_DUMP].replay_enable = 0;
|
|
|
|
/*
|
|
* Set up the (msg_name, crc, message-id) table
|
|
*/
|
|
REPLY_MSG_ID_BASE = setup_message_id_table ();
|
|
|
|
return 0;
|
|
}
|
|
|
|
VLIB_API_INIT_FUNCTION (interface_api_hookup);
|
|
|
|
/*
|
|
* fd.io coding-style-patch-verification: ON
|
|
*
|
|
* Local Variables:
|
|
* eval: (c-set-style "gnu")
|
|
* End:
|
|
*/
|