#!/usr/bin/env python """ BFD tests """ from __future__ import division import binascii import hashlib import time import unittest from random import randint, shuffle, getrandbits from socket import AF_INET, AF_INET6, inet_ntop from struct import pack, unpack from six import moves import scapy.compat from scapy.layers.inet import UDP, IP from scapy.layers.inet6 import IPv6 from scapy.layers.l2 import Ether from scapy.packet import Raw from bfd import VppBFDAuthKey, BFD, BFDAuthType, VppBFDUDPSession, \ BFDDiagCode, BFDState, BFD_vpp_echo from framework import VppTestCase, VppTestRunner, running_extended_tests from util import ppp from vpp_ip import DpoProto from vpp_ip_route import VppIpRoute, VppRoutePath from vpp_lo_interface import VppLoInterface from vpp_papi_provider import UnexpectedApiReturnValueError from vpp_pg_interface import CaptureTimeoutError, is_ipv6_misc USEC_IN_SEC = 1000000 class AuthKeyFactory(object): """Factory class for creating auth keys with unique conf key ID""" def __init__(self): self._conf_key_ids = {} def create_random_key(self, test, auth_type=BFDAuthType.keyed_sha1): """ create a random key with unique conf key id """ conf_key_id = randint(0, 0xFFFFFFFF) while conf_key_id in self._conf_key_ids: conf_key_id = randint(0, 0xFFFFFFFF) self._conf_key_ids[conf_key_id] = 1 key = scapy.compat.raw( bytearray([randint(0, 255) for _ in range(randint(1, 20))])) return VppBFDAuthKey(test=test, auth_type=auth_type, conf_key_id=conf_key_id, key=key) @unittest.skipUnless(running_extended_tests, "part of extended tests") class BFDAPITestCase(VppTestCase): """Bidirectional Forwarding Detection (BFD) - API""" pg0 = None pg1 = None @classmethod def setUpClass(cls): super(BFDAPITestCase, cls).setUpClass() cls.vapi.cli("set log class bfd level debug") try: cls.create_pg_interfaces(range(2)) for i in cls.pg_interfaces: i.config_ip4() i.config_ip6() i.resolve_arp() except Exception: super(BFDAPITestCase, cls).tearDownClass() raise @classmethod def tearDownClass(cls): super(BFDAPITestCase, cls).tearDownClass() def setUp(self): super(BFDAPITestCase, self).setUp() self.factory = AuthKeyFactory() def test_add_bfd(self): """ create a BFD session """ session = VppBFDUDPSession(self, self.pg0, self.pg0.remote_ip4) session.add_vpp_config() self.logger.debug("Session state is %s", session.state) session.remove_vpp_config() session.add_vpp_config() self.logger.debug("Session state is %s", session.state) session.remove_vpp_config() def test_double_add(self): """ create the same BFD session twice (negative case) """ session = VppBFDUDPSession(self, self.pg0, self.pg0.remote_ip4) session.add_vpp_config() with self.vapi.assert_negative_api_retval(): session.add_vpp_config() session.remove_vpp_config() def test_add_bfd6(self): """ create IPv6 BFD session """ session = VppBFDUDPSession( self, self.pg0, self.pg0.remote_ip6, af=AF_INET6) session.add_vpp_config() self.logger.debug("Session state is %s", session.state) session.remove_vpp_config() session.add_vpp_config() self.logger.debug("Session state is %s", session.state) session.remove_vpp_config() def test_mod_bfd(self): """ modify BFD session parameters """ session = VppBFDUDPSession(self, self.pg0, self.pg0.remote_ip4, desired_min_tx=50000, required_min_rx=10000, detect_mult=1) session.add_vpp_config() s = session.get_bfd_udp_session_dump_entry() self.assert_equal(session.desired_min_tx, s.desired_min_tx, "desired min transmit interval") self.assert_equal(session.required_min_rx, s.required_min_rx, "required min receive interval") self.assert_equal(session.detect_mult, s.detect_mult, "detect mult") session.modify_parameters(desired_min_tx=session.desired_min_tx * 2, required_min_rx=session.required_min_rx * 2, detect_mult=session.detect_mult * 2) s = session.get_bfd_udp_session_dump_entry() self.assert_equal(session.desired_min_tx, s.desired_min_tx, "desired min transmit interval") self.assert_equal(session.required_min_rx, s.required_min_rx, "required min receive interval") self.assert_equal(session.detect_mult, s.detect_mult, "detect mult") def test_add_sha1_keys(self): """ add SHA1 keys """ key_count = 10 keys = [self.factory.create_random_key( self) for i in range(0, key_count)] for key in keys: self.assertFalse(key.query_vpp_config()) for key in keys: key.add_vpp_config() for key in keys: self.assertTrue(key.query_vpp_config()) # remove randomly indexes = range(key_count) shuffle(indexes) removed = [] for i in indexes: key = keys[i] key.remove_vpp_config() removed.append(i) for j in range(key_count): key = keys[j] if j in removed: self.assertFalse(key.query_vpp_config()) else: self.assertTrue(key.query_vpp_config()) # should be removed now for key in keys: self.assertFalse(key.query_vpp_config()) # add back and remove again for key in keys: key.add_vpp_config() for key in keys: self.assertTrue(key.query_vpp_config()) for key in keys: key.remove_vpp_config() for key in keys: self.assertFalse(key.query_vpp_config()) def test_add_bfd_sha1(self): """ create a BFD session (SHA1) """ key = self.factory.create_random_key(self) key.add_vpp_config() session = VppBFDUDPSession(self, self.pg0, self.pg0.remote_ip4, sha1_key=key) session.add_vpp_config() self.logger.debug("Session state is %s", session.state) session.remove_vpp_config() session.add_vpp_config() self.logger.debug("Session state is %s", session.state) session.remove_vpp_config() def test_double_add_sha1(self): """ create the same BFD session twice (negative case) (SHA1) """ key = self.factory.create_random_key(self) key.add_vpp_config() session = VppBFDUDPSession(self, self.pg0, self.pg0.remote_ip4, sha1_key=key) session.add_vpp_config() with self.assertRaises(Exception): session.add_vpp_config() def test_add_auth_nonexistent_key(self): """ create BFD session using non-existent SHA1 (negative case) """ session = VppBFDUDPSession( self, self.pg0, self.pg0.remote_ip4, sha1_key=self.factory.create_random_key(self)) with self.assertRaises(Exception): session.add_vpp_config() def test_shared_sha1_key(self): """ share single SHA1 key between multiple BFD sessions """ key = self.factory.create_random_key(self) key.add_vpp_config() sessions = [ VppBFDUDPSession(self, self.pg0, self.pg0.remote_ip4, sha1_key=key), VppBFDUDPSession(self, self.pg0, self.pg0.remote_ip6, sha1_key=key, af=AF_INET6), VppBFDUDPSession(self, self.pg1, self.pg1.remote_ip4, sha1_key=key), VppBFDUDPSession(self, self.pg1, self.pg1.remote_ip6, sha1_key=key, af=AF_INET6)] for s in sessions: s.add_vpp_config() removed = 0 for s in sessions: e = key.get_bfd_auth_keys_dump_entry() self.assert_equal(e.use_count, len(sessions) - removed, "Use count for shared key") s.remove_vpp_config() removed += 1 e = key.get_bfd_auth_keys_dump_entry() self.assert_equal(e.use_count, len(sessions) - removed, "Use count for shared key") def test_activate_auth(self): """ activate SHA1 authentication """ key = self.factory.cr
/*
* 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/vnet.h>
/* funciton declarations */
u32 vnet_hw_if_get_rx_queue_index_by_id (vnet_main_t *vnm, u32 hw_if_index,
u32 queue_id);
u32 vnet_hw_if_register_rx_queue (vnet_main_t *vnm, u32 hw_if_index,
u32 queue_id, u32 thread_idnex);
void vnet_hw_if_unregister_rx_queue (vnet_main_t *vnm, u32 queue_index);
void vnet_hw_if_unregister_all_rx_queues (vnet_main_t *vnm, u32 hw_if_index);
void vnet_hw_if_set_rx_queue_file_index (vnet_main_t *vnm, u32 queue_index,
u32 file_index);
void vnet_hw_if_set_input_node (vnet_main_t *vnm, u32 hw_if_index,
u32 node_index);
int vnet_hw_if_set_rx_queue_mode (vnet_main_t *vnm, u32 queue_index,
vnet_hw_if_rx_mode mode);
vnet_hw_if_rx_mode vnet_hw_if_get_rx_queue_mode (vnet_main_t *vnm,
u32 queue_index);
void vnet_hw_if_set_rx_queue_thread_index (vnet_main_t *vnm, u32 queue_index,
u32 thread_index);
void vnet_hw_if_generate_rxq_int_poll_vector (vlib_main_t *vm,
vlib_node_runtime_t *node);
/* inline functions */
static_always_inline vnet_hw_if_rx_queue_t *
vnet_hw_if_get_rx_queue (vnet_main_t *vnm, u32 queue_index)
{
vnet_interface_main_t *im = &vnm->interface_main;
if (pool_is_free_index (im->hw_if_rx_queues, queue_index))
return 0;
return pool_elt_at_index (im->hw_if_rx_queues, queue_index);
}
static_always_inline void
vnet_hw_if_rx_queue_set_int_pending (vnet_main_t *vnm, u32 queue_index)
{
vnet_hw_if_rx_queue_t *rxq = vnet_hw_if_get_rx_queue (vnm, queue_index);
vnet_hw_interface_t *hi = vnet_get_hw_interface (vnm, rxq->hw_if_index);
vlib_main_t *vm = vlib_get_main_by_index (rxq->thread_index);
vnet_hw_if_rx_node_runtime_t *rt;
if (PREDICT_FALSE (rxq->mode != VNET_HW_IF_RX_MODE_INTERRUPT &&
rxq->mode != VNET_HW_IF_RX_MODE_ADAPTIVE))
return;
rt = vlib_node_get_runtime_data (vm, hi->input_node_index);
if (vm == vlib_get_main ())
clib_interrupt_set (rt->rxq_interrupts, queue_index);
else
clib_interrupt_set_atomic (rt->rxq_interrupts, queue_index);
vlib_node_set_interrupt_pending (vm, hi->input_node_index);
}
static_always_inline vnet_hw_if_rxq_poll_vector_t *
vnet_hw_if_get_rxq_poll_vector (vlib_main_t *vm, vlib_node_runtime_t *node)
{
vnet_hw_if_rx_node_runtime_t *rt = (void *) node->runtime_data;
if (PREDICT_FALSE (node->state == VLIB_NODE_STATE_INTERRUPT))
vnet_hw_if_generate_rxq_int_poll_vector (vm, node);
return rt->rxq_poll_vector;
}
static_always_inline u8
vnet_hw_if_get_rx_queue_numa_node (vnet_main_t *vnm, u32 queue_index)
{
vnet_hw_if_rx_queue_t *rxq = vnet_hw_if_get_rx_queue (vnm, queue_index);
vnet_hw_interface_t *hi = vnet_get_hw_interface (vnm, rxq->hw_if_index);
return hi->numa_node;
}
static_always_inline u32
vnet_hw_if_get_rx_queue_thread_index (vnet_main_t *vnm, u32 queue_index)
{
vnet_hw_if_rx_queue_t *rxq = vnet_hw_if_get_rx_queue (vnm, queue_index);
return rxq->thread_index;
}
static_always_inline int
vnet_hw_if_rxq_cmp_cli_api (vnet_hw_if_rx_queue_t **a,
vnet_hw_if_rx_queue_t **b)
{
vnet_main_t *vnm;
vnet_hw_interface_t *hif_a;
vnet_hw_interface_t *hif_b;
if (*a == *b)
return 0;
if (a[0]->thread_index != b[0]->thread_index)
return 2 * (a[0]->thread_index > b[0]->thread_index) - 1;
vnm = vnet_get_main ();
hif_a = vnet_get_hw_interface (vnm, a[0]->hw_if_index);
hif_b = vnet_get_hw_interface (vnm, b[0]->hw_if_index);
if (hif_a->input_node_index != hif_b->input_node_index)
return 2 * (hif_a->input_node_index > hif_b->input_node_index) - 1;
if (a[0]->hw_if_index != b[0]->hw_if_index)
return 2 * (a[0]->hw_if_index > b[0]->hw_if_index) - 1;
if (a[0]->queue_id != b[0]->queue_id)
return 2 * (a[0]->queue_id > b[0]->queue_id) - 1;
ASSERT (0);
return ~0;
}
/*
* fd.io coding-style-patch-verification: ON
*
* Local Variables:
* eval: (c-set-style "gnu")
* End:
*/