#!/usr/bin/env python
+# SPDX-License-Identifier: ISC
#
# test_evpn_mh.py
# Cumulus Networks, Inc.
# Anuradha Karuppiah
#
-# Permission to use, copy, modify, and/or distribute this software
-# for any purpose with or without fee is hereby granted, provided
-# that the above copyright notice and this permission notice appear
-# in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND NETDEF DISCLAIMS ALL WARRANTIES
-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR
-# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
-# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
-# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
-# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
-# OF THIS SOFTWARE.
-#
"""
test_evpn_mh.py: Testing EVPN multihoming
"""
import os
-import re
import sys
+import subprocess
+from functools import partial
+
import pytest
import json
import platform
# pylint: disable=C0413
# Import topogen and topotest helpers
from lib import topotest
-from lib.topogen import Topogen, TopoRouter, get_topogen
-from lib.topolog import logger
# Required to instantiate the topology builder class.
-from mininet.topo import Topo
+from lib.topogen import Topogen, TopoRouter, get_topogen
+
+pytestmark = [pytest.mark.bgpd, pytest.mark.pimd]
#####################################################
##
#####################################################
-class NetworkTopo(Topo):
+def build_topo(tgen):
"""
EVPN Multihoming Topology -
1. Two level CLOS
4. Two dual attached hosts per-rack - hostdx1, hostdx2
"""
- def build(self, **_opts):
- "Build function"
-
- tgen = get_topogen(self)
-
- tgen.add_router("spine1")
- tgen.add_router("spine2")
- tgen.add_router("torm11")
- tgen.add_router("torm12")
- tgen.add_router("torm21")
- tgen.add_router("torm22")
- tgen.add_router("hostd11")
- tgen.add_router("hostd12")
- tgen.add_router("hostd21")
- tgen.add_router("hostd22")
-
- # On main router
- # First switch is for a dummy interface (for local network)
-
- ##################### spine1 ########################
- # spine1-eth0 is connected to torm11-eth0
- switch = tgen.add_switch("sw1")
- switch.add_link(tgen.gears["spine1"])
- switch.add_link(tgen.gears["torm11"])
-
- # spine1-eth1 is connected to torm12-eth0
- switch = tgen.add_switch("sw2")
- switch.add_link(tgen.gears["spine1"])
- switch.add_link(tgen.gears["torm12"])
-
- # spine1-eth2 is connected to torm21-eth0
- switch = tgen.add_switch("sw3")
- switch.add_link(tgen.gears["spine1"])
- switch.add_link(tgen.gears["torm21"])
-
- # spine1-eth3 is connected to torm22-eth0
- switch = tgen.add_switch("sw4")
- switch.add_link(tgen.gears["spine1"])
- switch.add_link(tgen.gears["torm22"])
-
- ##################### spine2 ########################
- # spine2-eth0 is connected to torm11-eth1
- switch = tgen.add_switch("sw5")
- switch.add_link(tgen.gears["spine2"])
- switch.add_link(tgen.gears["torm11"])
-
- # spine2-eth1 is connected to torm12-eth1
- switch = tgen.add_switch("sw6")
- switch.add_link(tgen.gears["spine2"])
- switch.add_link(tgen.gears["torm12"])
-
- # spine2-eth2 is connected to torm21-eth1
- switch = tgen.add_switch("sw7")
- switch.add_link(tgen.gears["spine2"])
- switch.add_link(tgen.gears["torm21"])
-
- # spine2-eth3 is connected to torm22-eth1
- switch = tgen.add_switch("sw8")
- switch.add_link(tgen.gears["spine2"])
- switch.add_link(tgen.gears["torm22"])
-
- ##################### torm11 ########################
- # torm11-eth2 is connected to hostd11-eth0
- switch = tgen.add_switch("sw9")
- switch.add_link(tgen.gears["torm11"])
- switch.add_link(tgen.gears["hostd11"])
-
- # torm11-eth3 is connected to hostd12-eth0
- switch = tgen.add_switch("sw10")
- switch.add_link(tgen.gears["torm11"])
- switch.add_link(tgen.gears["hostd12"])
-
- ##################### torm12 ########################
- # torm12-eth2 is connected to hostd11-eth1
- switch = tgen.add_switch("sw11")
- switch.add_link(tgen.gears["torm12"])
- switch.add_link(tgen.gears["hostd11"])
-
- # torm12-eth3 is connected to hostd12-eth1
- switch = tgen.add_switch("sw12")
- switch.add_link(tgen.gears["torm12"])
- switch.add_link(tgen.gears["hostd12"])
-
- ##################### torm21 ########################
- # torm21-eth2 is connected to hostd21-eth0
- switch = tgen.add_switch("sw13")
- switch.add_link(tgen.gears["torm21"])
- switch.add_link(tgen.gears["hostd21"])
-
- # torm21-eth3 is connected to hostd22-eth0
- switch = tgen.add_switch("sw14")
- switch.add_link(tgen.gears["torm21"])
- switch.add_link(tgen.gears["hostd22"])
-
- ##################### torm22 ########################
- # torm22-eth2 is connected to hostd21-eth1
- switch = tgen.add_switch("sw15")
- switch.add_link(tgen.gears["torm22"])
- switch.add_link(tgen.gears["hostd21"])
-
- # torm22-eth3 is connected to hostd22-eth1
- switch = tgen.add_switch("sw16")
- switch.add_link(tgen.gears["torm22"])
- switch.add_link(tgen.gears["hostd22"])
+ tgen.add_router("spine1")
+ tgen.add_router("spine2")
+ tgen.add_router("torm11")
+ tgen.add_router("torm12")
+ tgen.add_router("torm21")
+ tgen.add_router("torm22")
+ tgen.add_router("hostd11")
+ tgen.add_router("hostd12")
+ tgen.add_router("hostd21")
+ tgen.add_router("hostd22")
+
+ # On main router
+ # First switch is for a dummy interface (for local network)
+
+ ##################### spine1 ########################
+ # spine1-eth0 is connected to torm11-eth0
+ switch = tgen.add_switch("sw1")
+ switch.add_link(tgen.gears["spine1"])
+ switch.add_link(tgen.gears["torm11"])
+
+ # spine1-eth1 is connected to torm12-eth0
+ switch = tgen.add_switch("sw2")
+ switch.add_link(tgen.gears["spine1"])
+ switch.add_link(tgen.gears["torm12"])
+
+ # spine1-eth2 is connected to torm21-eth0
+ switch = tgen.add_switch("sw3")
+ switch.add_link(tgen.gears["spine1"])
+ switch.add_link(tgen.gears["torm21"])
+
+ # spine1-eth3 is connected to torm22-eth0
+ switch = tgen.add_switch("sw4")
+ switch.add_link(tgen.gears["spine1"])
+ switch.add_link(tgen.gears["torm22"])
+
+ ##################### spine2 ########################
+ # spine2-eth0 is connected to torm11-eth1
+ switch = tgen.add_switch("sw5")
+ switch.add_link(tgen.gears["spine2"])
+ switch.add_link(tgen.gears["torm11"])
+
+ # spine2-eth1 is connected to torm12-eth1
+ switch = tgen.add_switch("sw6")
+ switch.add_link(tgen.gears["spine2"])
+ switch.add_link(tgen.gears["torm12"])
+
+ # spine2-eth2 is connected to torm21-eth1
+ switch = tgen.add_switch("sw7")
+ switch.add_link(tgen.gears["spine2"])
+ switch.add_link(tgen.gears["torm21"])
+
+ # spine2-eth3 is connected to torm22-eth1
+ switch = tgen.add_switch("sw8")
+ switch.add_link(tgen.gears["spine2"])
+ switch.add_link(tgen.gears["torm22"])
+
+ ##################### torm11 ########################
+ # torm11-eth2 is connected to hostd11-eth0
+ switch = tgen.add_switch("sw9")
+ switch.add_link(tgen.gears["torm11"])
+ switch.add_link(tgen.gears["hostd11"])
+
+ # torm11-eth3 is connected to hostd12-eth0
+ switch = tgen.add_switch("sw10")
+ switch.add_link(tgen.gears["torm11"])
+ switch.add_link(tgen.gears["hostd12"])
+
+ ##################### torm12 ########################
+ # torm12-eth2 is connected to hostd11-eth1
+ switch = tgen.add_switch("sw11")
+ switch.add_link(tgen.gears["torm12"])
+ switch.add_link(tgen.gears["hostd11"])
+
+ # torm12-eth3 is connected to hostd12-eth1
+ switch = tgen.add_switch("sw12")
+ switch.add_link(tgen.gears["torm12"])
+ switch.add_link(tgen.gears["hostd12"])
+
+ ##################### torm21 ########################
+ # torm21-eth2 is connected to hostd21-eth0
+ switch = tgen.add_switch("sw13")
+ switch.add_link(tgen.gears["torm21"])
+ switch.add_link(tgen.gears["hostd21"])
+
+ # torm21-eth3 is connected to hostd22-eth0
+ switch = tgen.add_switch("sw14")
+ switch.add_link(tgen.gears["torm21"])
+ switch.add_link(tgen.gears["hostd22"])
+
+ ##################### torm22 ########################
+ # torm22-eth2 is connected to hostd21-eth1
+ switch = tgen.add_switch("sw15")
+ switch.add_link(tgen.gears["torm22"])
+ switch.add_link(tgen.gears["hostd21"])
+
+ # torm22-eth3 is connected to hostd22-eth1
+ switch = tgen.add_switch("sw16")
+ switch.add_link(tgen.gears["torm22"])
+ switch.add_link(tgen.gears["hostd22"])
#####################################################
def setup_module(module):
"Setup topology"
- tgen = Topogen(NetworkTopo, module.__name__)
+ tgen = Topogen(build_topo, module.__name__)
tgen.start_topology()
krel = platform.release()
def ping_anycast_gw(tgen):
- local_host = tgen.gears["hostd11"]
- remote_host = tgen.gears["hostd21"]
-
# ping the anycast gw from the local and remote hosts to populate
# the mac address on the PEs
- cmd_str = "arping -I torbond -c 1 45.0.0.1"
- local_host.run(cmd_str)
- remote_host.run(cmd_str)
+ python3_path = tgen.net.get_exec_path(["python3", "python"])
+ script_path = os.path.abspath(os.path.join(CWD, "../lib/scapy_sendpkt.py"))
+ intf = "torbond"
+ ipaddr = "45.0.0.1"
+ ping_cmd = [
+ python3_path,
+ script_path,
+ "--imports=Ether,ARP",
+ "--interface=" + intf,
+ 'Ether(dst="ff:ff:ff:ff:ff:ff")/ARP(pdst="{}")'.format(ipaddr),
+ ]
+ for name in ("hostd11", "hostd21"):
+ host = tgen.net.hosts[name]
+ _, stdout, _ = host.cmd_status(ping_cmd, warn=False, stderr=subprocess.STDOUT)
+ stdout = stdout.strip()
+ if stdout:
+ host.logger.debug(
+ "%s: arping on %s for %s returned: %s", name, intf, ipaddr, stdout
+ )
def check_mac(dut, vni, mac, m_type, esi, intf, ping_gw=False, tgen=None):