#!/usr/bin/env python """ Classifier-based L2 ACL Test Case HLD: """ import unittest import random import binascii import socket from scapy.packet import Raw from scapy.data import ETH_P_IP from scapy.layers.l2 import Ether from scapy.layers.inet import IP, TCP, UDP, ICMP from scapy.layers.inet6 import IPv6, ICMPv6EchoRequest from scapy.layers.inet6 import IPv6ExtHdrFragment from framework import VppTestCase, VppTestRunner from util import Host, ppp class TestClassifyAcl(VppTestCase): """ Classifier-based L2 input and output ACL Test Case """ # traffic types IP = 0 ICMP = 1 # IP version IPRANDOM = -1 IPV4 = 0 IPV6 = 1 # rule types DENY = 0 PERMIT = 1 # supported protocols proto = [[6, 17], [1, 58]] proto_map = {1: 'ICMP', 58: 'ICMPv6EchoRequest', 6: 'TCP', 17: 'UDP'} ICMPv4 = 0 ICMPv6 = 1 TCP = 0 UDP = 1 PROTO_ALL = 0 # port ranges PORTS_ALL = -1 PORTS_RANGE = 0 PORTS_RANGE_2 = 1 udp_sport_from = 10 udp_sport_to = udp_sport_from + 5 udp_dport_from = 20000 udp_dport_to = udp_dport_from + 5000 tcp_sport_from = 30 tcp_sport_to = tcp_sport_from + 5 tcp_dport_from = 40000 tcp_dport_to = tcp_dport_from + 5000 udp_sport_from_2 = 90 udp_sport_to_2 = udp_sport_from_2 + 5 udp_dport_from_2 = 30000 udp_dport_to_2 = udp_dport_from_2 + 5000 tcp_sport_from_2 = 130 tcp_sport_to_2 = tcp_sport_from_2 + 5 tcp_dport_from_2 = 20000 tcp_dport_to_2 = tcp_dport_from_2 + 5000 icmp4_type = 8 # echo request icmp4_code = 3 icmp6_type = 128 # echo request icmp6_code = 3 icmp4_type_2 = 8 icmp4_code_from_2 = 5 icmp4_code_to_2 = 20 icmp6_type_2 = 128 icmp6_code_from_2 = 8 icmp6_code_to_2 = 42 # Test variables bd_id = 1 @classmethod def setUpClass(cls): """ Perform standard class setup (defined by class method setUpClass in class VppTestCase) before running the test case, set test case related variables and configure VPP. """ super(TestClassifyAcl, cls).setUpClass() try: # Create 2 pg interfaces cls.create_pg_interfaces(range(2)) # Packet flows mapping pg0 -> pg1, pg2 etc. cls.flows = dict() cls.flows[cls.pg0] = [cls.pg1] # Packet sizes cls.pg_if_packet_sizes = [64, 512, 1518, 9018] # Create BD with MAC learning and unknown unicast flooding disabled # and put interfaces to this BD cls.vapi.bridge_domain_add_del(bd_id=cls.bd_id, uu_flood=1, learn=1) for pg_if in cls.pg_interfaces: cls.vapi.sw_interface_set_l2_bridge( rx_sw_if_index=pg_if.sw_if_index, bd_id=cls.bd_id) # Set up all interfaces for i in cls.pg_interfaces: i.admin_up() # Mapping between packet-generator index and lists of test hosts cls.hosts_by_pg_idx = dict() for pg_if in cls.pg_interfaces: cls.hosts_by_pg_idx[pg_if.sw_if_index] = [] # Create list of deleted hosts cls.deleted_hosts_by_pg_idx = dict() for pg_if in cls.pg_interfaces: cls.deleted_hosts_by_pg_idx[pg_if.sw_if_index] = [] # warm-up the mac address tables # self.warmup_test() # Holder of the active classify table key cls.acl_active_table = '' except Exception: super(TestClassifyAcl, cls).tearDownClass() raise @classmethod def tearDownClass(cls): super(TestClassifyAcl, cls).tearDownClass() def setUp(self): super(TestClassifyAcl, self).setUp() self.acl_tbl_idx = {} self.reset_packet_infos() def tearDown(self): """ Show various debug prints after each test. """ if not self.vpp_dead: if self.acl_active_table == 'mac_inout': self.output_acl_set_interface( self.pg1, self.acl_tbl_idx.get(self.acl_active_table), 0) self.input_acl_set_interface( self.pg0, self.acl_tbl_idx.get(self.acl_active_table), 0) self.acl_active_table = '' elif self.acl_active_table == 'mac_out': self.output_acl_set_interface( self.pg1, self.acl_tbl_idx.get(self.acl_active_table), 0) self.acl_active_table = '' elif self.acl_active_table == 'mac_in': self.input_acl_set_interface( self.pg0, self.acl_tbl_idx.get(self.acl_active_table), 0) self.acl_active_table = '' super(TestClassifyAcl, self).tearDown() def show_commands_at_teardown(self): self.logger.info(self.vapi.ppcli("show inacl type l2")) self.logger.info(self.vapi.ppcli("show outacl type l2")) self.logger.info(self.vapi.ppcli("show classify tables verbose")) self.logger.info(self.vapi.ppcli("show bridge-domain %s detail" % self.bd_id)) @staticmethod def build_mac_mask(dst_mac='', src_mac='', ether_type=''): """Build MAC ACL mask data with hexstring format :param str dst_mac: source MAC address <0-ffffffffffff> :param str src_mac: destination MAC address <0-ffffffffffff> :param str ether_type: ethernet type <0-ffff> """ return ('{!s:0>12}{!s:0>12}{!s:0>4}'.format( dst_mac, src_mac, ether_type)).rstrip('0') @staticmethod def build_mac_match(dst_mac='', src_mac='', ether_type=''): """Build MAC ACL match data with hexstring format :param str dst_mac: source MAC address :param str src_mac: destination MAC address :param str ether_type: ethernet type <0-ffff> """ if dst_mac: dst_mac = dst_mac.replace(':', '') if src_mac: src_mac = src_mac.replace(':', '') return ('{!s:0>12}{!s:0>12}{!s:0>4}'.format( dst_mac, src_mac, ether_type)).rstrip('0') def create_classify_table(self, key, mask, data_offset=0, is_add=1): """Create Classify Table :param str key: key for classify table (ex, ACL name). :param str mask: mask value for interested traffic. :param int match_n_vectors: :param int is_add: option to configure classify table. - create(1) or delete(0) """ r = self.vapi.classify_add_del_table( is_add, binascii.unhexlify(mask), match_n_vectors=(len(mask) - 1) // 32 + 1, miss_next_index=0, current_data_flag=1, current_data_offset=data_offset) self.assertIsNotNone(r, 'No response msg for add_del_table') self.acl_tbl_idx[key] = r.new_table_index def create_classify_session(self, intf, table_index, match, hit_next_index=0xffffffff, is_add=1): """Create Classify Session :param VppInterface intf: Interface to apply classify session. :param int table_index: table index to identify classify table. :param str match: matched value for interested traffic. :param int pbr_action: enable/disable PBR feature. :param int vrfid: VRF id. :param int is_add: option to configure classify session. - create(1) or delete(0) """ r = self.vapi.classify_add_del_session( is_add, table_index, binascii.unhexlify(match), hit_next_index=hit_next_index) self.assertIsNotNone(r, 'No response msg for add_del_session') def input_acl_set_interface(self, intf, table_index, is_add=1): """Configure Input ACL interface :param VppInterface intf: Interface to apply Input ACL feature. :param int table_index: table index to identify classify table. :param int is_add: option to configure classify session. - enable(1) or disable(0) """ r = self.vapi.input_acl_set_interface( is_add, intf.sw_if_index, l2_table_index=table_index) self.assertIsNotNone(r, 'No response msg for acl_set_interface') def output_acl_set_interface(self, intf, table_index, is_add=1): """Configure Output ACL interface :param VppInterface intf: Interface to apply Output ACL feature. :param int table_index: table index to identify classify table. :param int is_add: option to configure classify session. - enable(1) or disable(0) """ r = self.vapi.output_acl_set_interface( is_add, intf.sw_if_index, l2_table_index=table_index) self.assertIsNotNone(r, 'No response msg for acl_set_interface') def create_hosts(self, count, start=0): """ Create required number of host MAC addresses and distribute them among interfaces. Create host IPv4 address for every host MAC address. :param int count: Number of hosts to create MAC/IPv4 addresses for. :param int start: Number to start numbering from. """ n_int = len(self.pg_interfaces) macs_per_if = count / n_int i = -1 for pg_if in self.pg_interfaces: i += 1 start_nr = macs_per_if * i + start end_nr = count + start if i == (n_int - 1) \ else macs_per_if * (i + 1) + start hosts = self.hosts_by_pg_idx[pg_if.sw_if_index] for j in range(start_nr, end_nr): host = Host( "00:00:00:ff:%02x:%02x" % (pg_if.sw_if_index, j), "172.17.1%02x.%u" % (pg_if.sw_if_index, j), "2017:dead:%02x::%u" % (pg_if.sw_if_index, j)) hosts.append(host) def create_upper_layer(self, packet_index, proto, ports=0): p = self.proto_map[proto] if p == 'UDP': if ports == 0: return UDP(sport=random.randint(self.udp_sport_from, self.udp_sport_to), dport=random.randint(self.udp_dport_from, self.udp_dport_to)) else: return UDP(sport=ports, dport=ports) elif p == 'TCP': if ports == 0: return TCP(sport=random.randint(self.tcp_sport_from, self.tcp_sport_to), dport=random.randint(self.tcp_dport_from, self.tcp_dport_to)) else: return TCP(sport=ports, dport=ports) return '' def create_stream(self, src_if, packet_sizes, traffic_type=0, ipv6=0, proto=-1, ports=0, fragments=False, pkt_raw=True, etype=-1): """ Create input packet stream for defined interface using hosts or deleted_hosts list. :param object src_if: Interface to create packet stream for. :param list packet_sizes: List of required packet sizes. :param traffic_type: 1: ICMP packet, 2: IPv6 with EH, 0: otherwise. :return: Stream of packets. """ pkts = [] if self.flows.__contains__(src_if): src_hosts = self.hosts_by_pg_idx[src_if.sw_if_index] for dst_if in self.flows[src_if]: dst_hosts = self.hosts_by_pg_idx[dst_if.sw_if_index] n_int = len(dst_hosts) * len(src_hosts) for i in range(0, n_int): dst_host = dst_hosts[i / len(src_hosts)] src_host = src_hosts[i % len(src_hosts)] pkt_info = self.create_packet_info(src_if, dst_if) if ipv6 == 1: pkt_info.ip = 1 elif ipv6 == 0:
/*
 * vrrp_periodic.c - vrrp plug-in periodic function
 *
 * Copyright 2019-2020 Rubicon Communications, LLC (Netgate)
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 */

#include <vlib/vlib.h>
#include <vppinfra/error.h>
#include <vrrp/vrrp.h>
#include <vrrp/vrrp_packet.h>

static int
vrrp_vr_timer_compare (const void *v1, const void *v2)
{
  vrrp_main_t *vmp = &vrrp_main;
  const u32 *idx1, *idx2;
  vrrp_vr_timer_t *timer1, *timer2;

  idx1 = v1;
  idx2 = v2;

  timer1 = pool_elt_at_index (vmp->vr_timers, *idx1);
  timer2 = pool_elt_at_index (vmp->vr_timers, *idx2);

  /* don't check equality, they are unlikely to be exactly equal and
   * if it occurs, it won't matter what order they were in.
   * sort the list in reverse so we can pick the next timer off the end */
  if (timer1->expire_time > timer2->expire_time)
    return -1;
  else
    return 1;
}

static u32
vrrp_vr_timer_get_next (void)
{
  vrrp_main_t *vmp = &vrrp_main;
  int n_timers;

  n_timers = vec_len (vmp->pending_timers);

  if (!n_timers)
    return ~0;

  return vec_elt (vmp->pending_timers, n_timers - 1);
}

/* cancel an existing timer. This could happen because:
 * - adv timer expired on master. another adv should be scheduled.
 * - a shutdown event is received
 * - a master is preempted by a higher priority master
 * - adv received on backup. master down timer should be rescheduled.
 */
void
vrrp_vr_timer_cancel (vrrp_vr_t * vr)
{
  vrrp_main_t *vmp = &vrrp_main;
  u32 *t;

  /* don't search for a timer that was already canceled or never set */
  if (vr->runtime.timer_index == ~0)
    return;

  /* timers stored in descending order, start at the end of the list */
  /* vec_foreach_backwards does not deal with 0 pointers, check first */
  if (vmp->pending_timers)
    vec_foreach_backwards (t, vmp->pending_timers)
    {
      if (*t == vr->runtime