Flood your network with BGF prefixes – Spirent automation

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:

  1. Under the ipv4_network_block
  2. 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.

Share

Leave a Reply

Your email address will not be published. Required fields are marked *