Let’s do something unusual, because how often do you flood your network with dummy prefixes to see the impact on the environment? Stress testing your network can lead to interesting conclusions, but can also blow the network. So today we will flood our network environment with a lot of BGP dummy prefixes. For that, we will use Spirent, but we will configure it using REST API and Python.
Remember, do not try this on the production. However, if you decide to, don’t tell your employer where you got the idea from.
Environment
Today topology is very simple. We have interconnected Spirent chassis with an emulated device called Stormwind and a Cisco router called Ironforge.
Now let’s review IP configuration.
Stormwind device has an IP address of 192.168.255.1, and Ironforge has 192.168.255.2. They are placed in the same /24 network.
Routers have assigned their own AS numbers:
- Stormwind – AS 64512
- Ironforge – AS 64513
Both are using their IP addresses as Router IDs.
Ironforge router BGP configuration
Let’s review the Ironforge router BGP configuration.
router bgp 64513
bgp router-id 192.168.255.1
bgp log-neighbor-changes
!
address-family ipv4 vrf 255
network 192.168.255.0
neighbor 192.168.255.2 remote-as 64512
neighbor 192.168.255.2 activate
exit-address-family
!
Apart from the standard BGP config, we have a custom VRF here – 255. Our only neighbor is the Stormwind router with a corresponding AS number.
We laid the foundation for our Spirent automation. In the next section, we will go through the code.
The code
In this section, we will go through the core code components. Description of basic Spirent actions are skipped. If you want to learn more about the basics, head to this article.
Emulated device
import time
from stcrestclient import stchttp
# Connection variables
spirent_box = "10.0.0.1"
stc_server = "10.0.1.1"
port = 8888
# Session variables
user_name = "Garzum"
session_name = "Script"
session_id = f"{session_name} - {user_name}"
# BGP variables
generated_bgp_routes = 225000
stormwind_router_id = "192.168.255.2"
stormwind_as = 64512
ironforge_as = 64513
generated_prefixes_start_ip = "100.0.0.0"
# IP addresses
ironforge_int_ip = "192.168.255.1"
stormwind_int_ip = "192.168.255.2"
stc_session = stchttp.StcHttp(stc_server, port=port)
stc_session.new_session(
user_name=user_name, session_name=session_name, kill_existing=True
)
stc_project = stc_session.create("project")
stc_session.connect(spirent_box)
port_location = "//10.0.0.1/1/3"
port3_handler = stc_session.create("Port", under=stc_project, Location=port_location)
# Create Emulated Device
stormwind_device = stc_session.create(
"EmulatedDevice",
under=stc_project,
Name="Router 1",
EnablePingResponse="TRUE",
RouterId=stormwind_router_id,
)
stormwind_eth = stc_session.create(
"EthIIIf",
under=stormwind_device,
)
stormwind_ip = stc_session.create(
"Ipv4If",
under=stormwind_device,
Address=stormwind_int_ip,
Gateway=ironforge_int_ip,
PrefixLength="24",
)
At the beginning, we’re defining values for variables. They will be used down the road for the configurations. In this section, they’re used for the configuration of the Stormwind emulated device.
If you’re trying this script, be aware that generating too many BGP prefixes can crash your receiving network devices. It can be adjusted by generated_bgp_routes variable, which is highlighted in the snipped above.
Stormwind BGP configuration
First of all, we have to configure BGP protocol parameters.
# Configure BGP parameters
bgp_router_config = stc_session.create(
"BgpRouterConfig",
under=stormwind_device,
AsNum=stormwind_as,
DutAsNum=ironforge_as,
UseGatewayAsDut="TRUE",
)
bgp_ipv4_route_config = stc_session.create(
"BgpIpv4RouteConfig",
under=bgp_router_config,
NextHop=stormwind_int_ip,
AsPath=stormwind_as,
)
While creating the BGP configuration, we have to specify to which emulated device it will be assigned. In our case, it’s the Stormwind router. We have already saved its handler in the stormwind_device variable. We also have to specify AS numbers, both for the Stormwind and Ironforge routers.
The last argument UseGatewayAsDut is set to True because our routers are placed in the same network. The default value is False, that’s why we have to overwrite it. If you’re curious about this argument, please take a look at the snippet from the Object Reference Guide.
Always remember to use Object Reference Guide according to you’r Spirent version.
The next variable – bgp_ipv4_route_config refers to the characteristics of BGP routes. We’re setting data from the Stormwind router there.
At this point, the Stormwind router has a standard BGP configuration. Now we have to configure the parameters of the routes we want to generate on it.
ipv4_network_block = (
stc_session.get(bgp_ipv4_route_config, "children-Ipv4NetworkBlock")
).split(" ")[0]
stc_session.config(
ipv4_network_block,
StartIpList=generated_prefixes_start_ip,
PrefixLength="24",
NetworkCount=generated_bgp_routes,
)
bgp_route_gen_params = stc_session.create(
"BgpRouteGenParams", under=stc_project
)
ipv4_route_gen_params = stc_session.create(
"Ipv4RouteGenParams",
under=bgp_route_gen_params,
IpAddrStart=generated_prefixes_start_ip,
PrefixLengthStart="24",
PrefixLengthEnd="24",
Count=generated_bgp_routes,
)
bgp_route_gen_route_attr_params = stc_session.create(
"BgpRouteGenRouteAttrParams", under=ipv4_route_gen_params
)
We have to specify prefix characteristics in two places:
- Under the ipv4_network_block
- Under the Ipv4RouteGenParams
Here we can adjust the parameters of generated routes. In our case, we’re generating a /24 prefixes, starting from an IP address of 100.0.0.0 (see generated_prefixes_start_ip variable defined at the beginning of the script). Our goal is to receive on the Ironforge router 225 000 of such prefixes (see generated_bgp_routes variable).
It’s a basic configuration of a prefix generator. There are also options to generate prefixes that are mixed in length. You can adjust it under the Ipv4RouteGenParams.
Associations
stc_session.perform("ReservePortCommand", Location=port_location)
stc_session.perform("attachPorts")
stc_session.config(
port3_handler, **{"AffiliationPort-sources": [stormwind_device]}
)
stc_session.config(
stormwind_device, **{"TopLevelIf-targets": [stormwind_ip]}
)
stc_session.config(
stormwind_device, **{"PrimaryIf-targets": [stormwind_ip]}
)
stc_session.config(
stormwind_ip, **{"StackedOnEndpoint-targets": [stormwind_eth]}
)
stc_session.config(bgp_router_config, **{"UsesIf-targets": [stormwind_ip]})
stc_session.config(
bgp_route_gen_params,
**{"SelectedRouterRelation-targets": [stormwind_device]},
)
stc_session.apply()
In the associations section, we’re gluing together previously defined configurations. In the last line, we’re applying the configuration on the Spirent.
Route generation
print("Starting Stormwind router")
stc_session.perform("ArpNdStartCommand", HandleList=port3_handler)
stc_session.perform("DeviceStartCommand", DeviceList=stormwind_device)
TRAFFIC_GENERATION_TIME = 180
print(f"Waiting for {TRAFFIC_GENERATION_TIME} seconds")
time.sleep(TRAFFIC_GENERATION_TIME)
stc_session.perform("DeviceStopCommand", DeviceList=stormwind_device)
The real impact on the environment is visible after starting the emulated device – the Stormwind router. After it’s launched, it’s establishing BGP peering with the Ironforge router. After that, generated prefixed are redistributed.
We’re waiting for 180 seconds here because the generation of large amounts of prefixes and network convergence takes time.
Cleanup
stc_session.perform("ReleasePortCommand", Location=port_location)
stc_session.perform("chassisDisconnectAll")
stc_session.perform("resetConfig", createnewtestsessionid=0)
stc_session.end_session()
At the end, we’re releasing reserved ports, disconnecting chassis, and resetting configuration. The last step is tearing down session with Spirent Test Center.
The complete code is available on my Spirent Automation Examples repository.
Results
Let’s take a look at the Ironforge router routing table. Checks were made while the script was running, a couple of dozens of seconds after starting the Stormwind router.
100.0.0.0/24 is subnetted, 65536 subnets
B 100.0.0.0 [20/0] via 192.168.255.2, 00:00:26
B 100.0.1.0 [20/0] via 192.168.255.2, 00:00:26
B 100.0.2.0 [20/0] via 192.168.255.2, 00:00:26
B 100.0.3.0 [20/0] via 192.168.255.2, 00:00:26
B 100.0.4.0 [20/0] via 192.168.255.2, 00:00:26
B 100.0.5.0 [20/0] via 192.168.255.2, 00:00:26
B 100.0.6.0 [20/0] via 192.168.255.2, 00:00:26
B 100.0.7.0 [20/0] via 192.168.255.2, 00:00:26
B 100.0.8.0 [20/0] via 192.168.255.2, 00:00:26
B 100.0.9.0 [20/0] via 192.168.255.2, 00:00:26
[...]
The generated prefixes are present in the routing table. It’s impossible to count them manually, so let’s use a pipe.
Ironforge#sh ip route vrf 255 | count via 192.168.255.2
Number of lines which match regexp = 225000
The amount of prefixes is exactly as we expected.
Summary
I don’t know how about you, but I like to do tests like that, because of pure curiosity about the impact on the network. While this example seems to be a niche, I hope it will help you to understand Spirent automation better.