Skip to content

ANTA Tests for generic routing

Tests

Module related to generic routing tests.

VerifyIPv4RouteNextHops

Verifies the next-hops of the IPv4 prefixes.

This test performs the following checks for each IPv4 prefix:

  1. Verifies the specified IPv4 route exists in the routing table.
  2. For each specified next-hop:
    • Verifies a path with matching next-hop exists.
    • Supports strict: True to verify that routes must be learned exclusively via the exact next-hops specified.
Expected Results
  • Success: The test will pass if routes exist with paths matching the expected next-hops.
  • Failure: The test will fail if:
    • A route entry is not found for given IPv4 prefixes.
    • A path with specified next-hop is not found.
Examples
anta.tests.routing:
  generic:
    - VerifyIPv4RouteNextHops:
        route_entries:
            - prefix: 10.10.0.1/32
              vrf: default
              strict: false
              nexthops:
                - 10.100.0.8
                - 10.100.0.10

Inputs

Name Type Description Default
route_entries list[IPv4RouteEntry]
List of IPv4 route(s).
-
Source code in anta/tests/routing/generic.py
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
class VerifyIPv4RouteNextHops(AntaTest):
    """Verifies the next-hops of the IPv4 prefixes.

    This test performs the following checks for each IPv4 prefix:

      1. Verifies the specified IPv4 route exists in the routing table.
      2. For each specified next-hop:
          - Verifies a path with matching next-hop exists.
          - Supports `strict: True` to verify that routes must be learned exclusively via the exact next-hops specified.

    Expected Results
    ----------------
    * Success: The test will pass if routes exist with paths matching the expected next-hops.
    * Failure: The test will fail if:
        - A route entry is not found for given IPv4 prefixes.
        - A path with specified next-hop is not found.

    Examples
    --------
    ```yaml
    anta.tests.routing:
      generic:
        - VerifyIPv4RouteNextHops:
            route_entries:
                - prefix: 10.10.0.1/32
                  vrf: default
                  strict: false
                  nexthops:
                    - 10.100.0.8
                    - 10.100.0.10
    ```
    """

    categories: ClassVar[list[str]] = ["routing"]
    commands: ClassVar[list[AntaCommand | AntaTemplate]] = [AntaCommand(command="show ip route vrf all", revision=4)]

    class Input(AntaTest.Input):
        """Input model for the VerifyIPv4RouteNextHops test."""

        route_entries: list[IPv4RouteEntry]
        """List of IPv4 route(s)."""

        @field_validator("route_entries")
        @classmethod
        def validate_route_entries(cls, route_entries: list[IPv4RouteEntry]) -> list[IPv4RouteEntry]:
            """Validate that 'nexthops' field is provided in each route entry."""
            for entry in route_entries:
                if entry.nexthops is None:
                    msg = f"{entry} 'nexthops' field missing in the input"
                    raise ValueError(msg)
            return route_entries

    @AntaTest.anta_test
    def test(self) -> None:
        """Main test function for VerifyIPv4RouteNextHops."""
        self.result.is_success()

        output = self.instance_commands[0].json_output

        for entry in self.inputs.route_entries:
            # Verify if the prefix exists in route table
            if (route_data := get_value(output, f"vrfs..{entry.vrf}..routes..{entry.prefix}", separator="..")) is None:
                self.result.is_failure(f"{entry} - prefix not found")
                continue

            # Verify the nexthop addresses
            actual_nexthops = sorted(["Directly connected" if (next_hop := route.get("nexthopAddr")) == "" else next_hop for route in route_data["vias"]])
            expected_nexthops = sorted([str(nexthop) for nexthop in entry.nexthops])

            if entry.strict and expected_nexthops != actual_nexthops:
                exp_nexthops = ", ".join(expected_nexthops)
                self.result.is_failure(f"{entry} - List of next-hops not matching - Expected: {exp_nexthops} Actual: {', '.join(actual_nexthops)}")
                continue

            for nexthop in entry.nexthops:
                if not get_item(route_data["vias"], "nexthopAddr", str(nexthop)):
                    self.result.is_failure(f"{entry} Nexthop: {nexthop} - Route not found")

VerifyIPv4RoutePresencePerPrefix

Atomic support badge

Verifies that the provided IPv4 prefixes are present in the routing table.

Note

This test performs the same verifications as VerifyIPv4RoutePresencePerVRF but is more efficient for devices with large routing tables.

Tip

The optimal test depends on the routing table size and number of prefixes to verify. Benchmark both to find the best fit.

Expected Results
  • Success: If all the specified IPv4 prefixes are found.
  • Failure: If any specified IPv4 prefix is not found in the routing table.
Examples
anta.tests.routing:
  generic:
    - VerifyIPv4RoutePresencePerPrefix:
        route_entries:
          - prefix: 10.10.0.1/32
            vrf: default
          - prefix: 10.100.0.12/31
            vrf: MGMT
          - prefix: 10.100.1.5/32
            vrf: data

Inputs

Name Type Description Default
route_entries list[IPv4RouteEntry]
List of IPv4 route entries to verify.
-
Source code in anta/tests/routing/generic.py
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
class VerifyIPv4RoutePresencePerPrefix(AntaTest):
    """Verifies that the provided IPv4 prefixes are present in the routing table.

    !!! note
        This test performs the same verifications as `VerifyIPv4RoutePresencePerVRF` but is more efficient for devices with large routing tables.

    !!! tip
        The optimal test depends on the routing table size and number of prefixes to verify. Benchmark both to find the best fit.

    Expected Results
    ----------------
    * Success: If all the specified IPv4 prefixes are found.
    * Failure: If any specified IPv4 prefix is not found in the routing table.

    Examples
    --------
    ```yaml
    anta.tests.routing:
      generic:
        - VerifyIPv4RoutePresencePerPrefix:
            route_entries:
              - prefix: 10.10.0.1/32
                vrf: default
              - prefix: 10.100.0.12/31
                vrf: MGMT
              - prefix: 10.100.1.5/32
                vrf: data
    ```
    """

    categories: ClassVar[list[str]] = ["routing"]
    commands: ClassVar[list[AntaCommand | AntaTemplate]] = [AntaTemplate(template="show ip route vrf {vrf} {prefix}", revision=4)]
    _atomic_support: ClassVar[bool] = True

    class Input(AntaTest.Input):
        """Input model for the VerifyIPv4RoutePresencePerPrefix test."""

        route_entries: list[IPv4RouteEntry]
        """List of IPv4 route entries to verify."""

    def render(self, template: AntaTemplate) -> list[AntaCommand]:
        """Render the template for each route entry in the input list."""
        return [template.render(vrf=entry.vrf, prefix=str(entry.prefix)) for entry in self.inputs.route_entries]

    @AntaTest.anta_test
    def test(self) -> None:
        """Main test function for VerifyIPv4RoutePresencePerPrefix."""
        self.result.is_success()

        # Iterating over the all routes entries mentioned in the inputs
        for command, entry in zip(self.instance_commands, self.inputs.route_entries, strict=False):
            # Atomic result
            result = self.result.add(description=f"{entry}", status=AntaTestStatus.SUCCESS)

            prefix = str(entry.prefix)
            vrf = entry.vrf
            routes_details = get_value(command.json_output, f"vrfs.{vrf}.routes", {})

            # Verifying that the expected IPv4 prefix is present or not in the routing table
            if prefix not in routes_details:
                result.is_failure("Route not found")

VerifyIPv4RoutePresencePerVRF

Atomic support badge

Verifies that the provided IPv4 prefixes are present in the routing table.

Note

This test performs the same verifications as VerifyIPv4RoutePresencePerPrefix but is more efficient for devices with small routing tables.

Tip

The optimal test depends on the routing table size and number of prefixes to verify. Benchmark both to find the best fit.

Expected Results
  • Success: If all the specified IPv4 prefixes are found.
  • Failure: If any specified IPv4 prefixes is not found in the routing table.
Examples
anta.tests.routing:
  generic:
    - VerifyIPv4RoutePresencePerVRF:
        route_entries:
          - prefix: 10.10.0.1/32
            vrf: default
          - prefix: 10.100.0.12/31
            vrf: MGMT
          - prefix: 10.100.1.5/32
            vrf: data

Inputs

Name Type Description Default
route_entries list[IPv4RouteEntry]
List of IPv4 route entries to verify.
-
Source code in anta/tests/routing/generic.py
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
class VerifyIPv4RoutePresencePerVRF(AntaTest):
    """Verifies that the provided IPv4 prefixes are present in the routing table.

    !!! note
        This test performs the same verifications as `VerifyIPv4RoutePresencePerPrefix` but is more efficient for devices with small routing tables.

    !!! tip
        The optimal test depends on the routing table size and number of prefixes to verify. Benchmark both to find the best fit.

    Expected Results
    ----------------
    * Success: If all the specified IPv4 prefixes are found.
    * Failure: If any specified IPv4 prefixes is not found in the routing table.

    Examples
    --------
    ```yaml
    anta.tests.routing:
      generic:
        - VerifyIPv4RoutePresencePerVRF:
            route_entries:
              - prefix: 10.10.0.1/32
                vrf: default
              - prefix: 10.100.0.12/31
                vrf: MGMT
              - prefix: 10.100.1.5/32
                vrf: data
    ```
    """

    categories: ClassVar[list[str]] = ["routing"]
    commands: ClassVar[list[AntaCommand | AntaTemplate]] = [AntaTemplate(template="show ip route vrf {vrf}", revision=4)]
    _atomic_support: ClassVar[bool] = True

    class Input(AntaTest.Input):
        """Input model for the VerifyIPv4RoutePresencePerVRF test."""

        route_entries: list[IPv4RouteEntry]
        """List of IPv4 route entries to verify."""

    def render(self, template: AntaTemplate) -> list[AntaCommand]:
        """Render the template for each route entry in the input list."""
        vrfs = [entry.vrf for entry in self.inputs.route_entries]
        return [template.render(vrf=vrf) for vrf in dict.fromkeys(vrfs)]

    @AntaTest.anta_test
    def test(self) -> None:
        """Main test function for VerifyIPv4RoutePresencePerVRF."""
        self.result.is_success()
        command_output = {command.params.vrf: command.json_output for command in self.instance_commands}

        # Iterating over the all routes entries mentioned in the inputs
        for entry in self.inputs.route_entries:
            # Atomic result
            result = self.result.add(description=f"{entry}", status=AntaTestStatus.SUCCESS)

            vrf = entry.vrf
            prefix = str(entry.prefix)
            route_output = command_output[vrf]
            routes_details = get_value(route_output, f"vrfs.{vrf}.routes", {})

            # Verifying that the expected IPv4 prefix is present or not in the routing table
            if prefix not in routes_details:
                result.is_failure("Route not found")

VerifyIPv4RouteType

Verifies the route-type of the IPv4 prefixes.

This test performs the following checks for each IPv4 route:

  1. Verifies that the specified VRF is configured.
  2. Verifies that the specified IPv4 route is exists in the configuration.
  3. Verifies that the the specified IPv4 route is of the expected type.
Expected Results
  • Success: If all of the following conditions are met:
    • All the specified VRFs are configured.
    • All the specified IPv4 routes are found.
    • All the specified IPv4 routes are of the expected type.
  • Failure: If any of the following occur:
    • A specified VRF is not configured.
    • A specified IPv4 route is not found.
    • Any specified IPv4 route is not of the expected type.
Examples
anta.tests.routing:
  generic:
    - VerifyIPv4RouteType:
        routes_entries:
          - prefix: 10.10.0.1/32
            vrf: default
            route_type: eBGP
          - prefix: 10.100.0.12/31
            vrf: default
            route_type: connected
          - prefix: 10.100.1.5/32
            vrf: default
            route_type: iBGP

Inputs

Name Type Description Default
routes_entries list[IPv4RouteEntry]
List of IPv4 route(s).
-
Source code in anta/tests/routing/generic.py
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
class VerifyIPv4RouteType(AntaTest):
    """Verifies the route-type of the IPv4 prefixes.

    This test performs the following checks for each IPv4 route:

      1. Verifies that the specified VRF is configured.
      2. Verifies that the specified IPv4 route is exists in the configuration.
      3. Verifies that the the specified IPv4 route is of the expected type.

    Expected Results
    ----------------
    * Success: If all of the following conditions are met:
        - All the specified VRFs are configured.
        - All the specified IPv4 routes are found.
        - All the specified IPv4 routes are of the expected type.
    * Failure: If any of the following occur:
        - A specified VRF is not configured.
        - A specified IPv4 route is not found.
        - Any specified IPv4 route is not of the expected type.

    Examples
    --------
    ```yaml
    anta.tests.routing:
      generic:
        - VerifyIPv4RouteType:
            routes_entries:
              - prefix: 10.10.0.1/32
                vrf: default
                route_type: eBGP
              - prefix: 10.100.0.12/31
                vrf: default
                route_type: connected
              - prefix: 10.100.1.5/32
                vrf: default
                route_type: iBGP
    ```
    """

    categories: ClassVar[list[str]] = ["routing"]
    commands: ClassVar[list[AntaCommand | AntaTemplate]] = [AntaCommand(command="show ip route vrf all", revision=4)]

    class Input(AntaTest.Input):
        """Input model for the VerifyIPv4RouteType test."""

        routes_entries: list[IPv4RouteEntry]
        """List of IPv4 route(s)."""

        @field_validator("routes_entries")
        @classmethod
        def validate_routes_entries(cls, routes_entries: list[IPv4RouteEntry]) -> list[IPv4RouteEntry]:
            """Validate that 'route_type' field is provided in each BGP route entry."""
            for entry in routes_entries:
                if entry.route_type is None:
                    msg = f"{entry} 'route_type' field missing in the input"
                    raise ValueError(msg)
            return routes_entries

    @AntaTest.anta_test
    def test(self) -> None:
        """Main test function for VerifyIPv4RouteType."""
        self.result.is_success()
        output = self.instance_commands[0].json_output

        # Iterating over the all routes entries mentioned in the inputs.
        for entry in self.inputs.routes_entries:
            prefix = str(entry.prefix)
            vrf = entry.vrf
            expected_route_type = entry.route_type

            # Verifying that on device, expected VRF is configured.
            if (routes_details := get_value(output, f"vrfs.{vrf}.routes")) is None:
                self.result.is_failure(f"{entry} - VRF not configured")
                continue

            # Verifying that the expected IPv4 route is present or not on the device
            if (route_data := routes_details.get(prefix)) is None:
                self.result.is_failure(f"{entry} - Route not found")
                continue

            # Verifying that the specified IPv4 routes are of the expected type.
            if expected_route_type != (actual_route_type := route_data.get("routeType")):
                self.result.is_failure(f"{entry} - Incorrect route type - Expected: {expected_route_type} Actual: {actual_route_type}")

VerifyRoutingProtocolModel

Verifies the configured routing protocol model.

Expected Results
  • Success: The test will pass if the configured routing protocol model is the one we expect.
  • Failure: The test will fail if the configured routing protocol model is not the one we expect.
Examples
anta.tests.routing:
  generic:
    - VerifyRoutingProtocolModel:
        model: multi-agent

Inputs

Name Type Description Default
model Literal['multi-agent', 'ribd']
Expected routing protocol model. Defaults to `multi-agent`.
'multi-agent'
Source code in anta/tests/routing/generic.py
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
class VerifyRoutingProtocolModel(AntaTest):
    """Verifies the configured routing protocol model.

    Expected Results
    ----------------
    * Success: The test will pass if the configured routing protocol model is the one we expect.
    * Failure: The test will fail if the configured routing protocol model is not the one we expect.

    Examples
    --------
    ```yaml
    anta.tests.routing:
      generic:
        - VerifyRoutingProtocolModel:
            model: multi-agent
    ```
    """

    categories: ClassVar[list[str]] = ["routing"]
    commands: ClassVar[list[AntaCommand | AntaTemplate]] = [AntaCommand(command="show ip route summary", revision=3)]

    class Input(AntaTest.Input):
        """Input model for the VerifyRoutingProtocolModel test."""

        model: Literal["multi-agent", "ribd"] = "multi-agent"
        """Expected routing protocol model. Defaults to `multi-agent`."""

    @AntaTest.anta_test
    def test(self) -> None:
        """Main test function for VerifyRoutingProtocolModel."""
        command_output = self.instance_commands[0].json_output
        configured_model = command_output["protoModelStatus"]["configuredProtoModel"]
        operating_model = command_output["protoModelStatus"]["operatingProtoModel"]
        if configured_model == operating_model == self.inputs.model:
            self.result.is_success()
        else:
            self.result.is_failure(f"Routing model is misconfigured - Expected: {self.inputs.model} Actual: {operating_model}")

VerifyRoutingStatus

Verifies the routing status for IPv4/IPv6 unicast, multicast, and IPv6 interfaces (RFC5549).

Expected Results
  • Success: The test will pass if the routing status is correct.
  • Failure: The test will fail if the routing status doesn’t match the expected configuration.
Examples
anta.tests.routing:
  generic:
    - VerifyRoutingStatus:
       ipv4_unicast: True
       ipv6_unicast: True

Inputs

Name Type Description Default
ipv4_unicast bool
IPv4 unicast routing status.
False
ipv6_unicast bool
IPv6 unicast routing status.
False
ipv4_multicast bool
IPv4 multicast routing status.
False
ipv6_multicast bool
IPv6 multicast routing status.
False
ipv6_interfaces bool
IPv6 interface forwarding status.
False
Source code in anta/tests/routing/generic.py
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
class VerifyRoutingStatus(AntaTest):
    """Verifies the routing status for IPv4/IPv6 unicast, multicast, and IPv6 interfaces (RFC5549).

    Expected Results
    ----------------
    * Success: The test will pass if the routing status is correct.
    * Failure: The test will fail if the routing status doesn't match the expected configuration.

    Examples
    --------
    ```yaml
    anta.tests.routing:
      generic:
        - VerifyRoutingStatus:
           ipv4_unicast: True
           ipv6_unicast: True
    ```
    """

    categories: ClassVar[list[str]] = ["routing"]
    commands: ClassVar[list[AntaCommand | AntaTemplate]] = [AntaCommand(command="show ip", revision=1)]

    class Input(AntaTest.Input):
        """Input model for the VerifyRoutingStatus test."""

        ipv4_unicast: bool = False
        """IPv4 unicast routing status."""
        ipv6_unicast: bool = False
        """IPv6 unicast routing status."""
        ipv4_multicast: bool = False
        """IPv4 multicast routing status."""
        ipv6_multicast: bool = False
        """IPv6 multicast routing status."""
        ipv6_interfaces: bool = False
        """IPv6 interface forwarding status."""

    @AntaTest.anta_test
    def test(self) -> None:
        """Main test function for VerifyRoutingStatus."""
        self.result.is_success()
        command_output = self.instance_commands[0].json_output
        actual_routing_status: dict[str, Any] = {
            "ipv4_unicast": command_output["v4RoutingEnabled"],
            "ipv6_unicast": command_output["v6RoutingEnabled"],
            "ipv4_multicast": get_value(command_output, "multicastRouting.ipMulticastEnabled", default=False),
            "ipv6_multicast": get_value(command_output, "multicastRouting.ip6MulticastEnabled", default=False),
            "ipv6_interfaces": command_output.get("v6IntfForwarding", False),
        }

        for input_key, value in self.inputs:
            if input_key in actual_routing_status and value != actual_routing_status[input_key]:
                route_type = " ".join([{"ipv4": "IPv4", "ipv6": "IPv6"}.get(part, part) for part in input_key.split("_")])
                self.result.is_failure(f"{route_type} routing enabled status mismatch - Expected: {value} Actual: {actual_routing_status[input_key]}")

VerifyRoutingTableEntry

Static Badge Static Badge
Replaced with: VerifyIPv4RoutePresencePerPrefix, VerifyIPv4RoutePresencePerVRF

(Deprecated) Verifies that the provided routes are present in the routing table of a specified VRF.

Expected Results
  • Success: The test will pass if the provided routes are present in the routing table.
  • Failure: The test will fail if one or many provided routes are missing from the routing table.
Examples
anta.tests.routing:
  generic:
    - VerifyRoutingTableEntry:
        vrf: default
        routes:
          - 10.1.0.1
          - 10.1.0.2

Inputs

Name Type Description Default
vrf str
VRF context. Defaults to `default` VRF.
'default'
routes list[IPv4Address]
List of routes to verify.
-
collect Literal['one', 'all']
Route collect behavior: one=one route per command, all=all routes in vrf per command. Defaults to `one`
'one'
Source code in anta/tests/routing/generic.py
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
@deprecated_test_class(new_tests=["VerifyIPv4RoutePresencePerPrefix", "VerifyIPv4RoutePresencePerVRF"], removal_in_version="v2.0.0")
class VerifyRoutingTableEntry(AntaTest):
    """(Deprecated) Verifies that the provided routes are present in the routing table of a specified VRF.

    Expected Results
    ----------------
    * Success: The test will pass if the provided routes are present in the routing table.
    * Failure: The test will fail if one or many provided routes are missing from the routing table.

    Examples
    --------
    ```yaml
    anta.tests.routing:
      generic:
        - VerifyRoutingTableEntry:
            vrf: default
            routes:
              - 10.1.0.1
              - 10.1.0.2
    ```
    """

    categories: ClassVar[list[str]] = ["routing"]
    commands: ClassVar[list[AntaCommand | AntaTemplate]] = [
        AntaTemplate(template="show ip route vrf {vrf} {route}", revision=4),
        AntaTemplate(template="show ip route vrf {vrf}", revision=4),
    ]

    class Input(AntaTest.Input):
        """Input model for the VerifyRoutingTableEntry test."""

        vrf: str = "default"
        """VRF context. Defaults to `default` VRF."""
        routes: list[IPv4Address]
        """List of routes to verify."""
        collect: Literal["one", "all"] = "one"
        """Route collect behavior: one=one route per command, all=all routes in vrf per command. Defaults to `one`"""

    def render(self, template: AntaTemplate) -> list[AntaCommand]:
        """Render the template for the input vrf."""
        if template == VerifyRoutingTableEntry.commands[0] and self.inputs.collect == "one":
            return [template.render(vrf=self.inputs.vrf, route=route) for route in self.inputs.routes]

        if template == VerifyRoutingTableEntry.commands[1] and self.inputs.collect == "all":
            return [template.render(vrf=self.inputs.vrf)]

        return []

    @staticmethod
    @cache
    def ip_interface_ip(route: str) -> IPv4Address:
        """Return the IP address of the provided ip route with mask."""
        return IPv4Interface(route).ip

    @AntaTest.anta_test
    def test(self) -> None:
        """Main test function for VerifyRoutingTableEntry."""
        commands_output_route_ips = set()

        for command in self.instance_commands:
            command_output_vrf = command.json_output["vrfs"][self.inputs.vrf]
            commands_output_route_ips |= {self.ip_interface_ip(route) for route in command_output_vrf["routes"]}

        missing_routes = [str(route) for route in self.inputs.routes if route not in commands_output_route_ips]

        if not missing_routes:
            self.result.is_success()
        else:
            self.result.is_failure(f"The following route(s) are missing from the routing table of VRF {self.inputs.vrf}: {', '.join(missing_routes)}")

VerifyRoutingTableSize

Verifies the size of the IP routing table of the default VRF.

Expected Results
  • Success: The test will pass if the routing table size is between the provided minimum and maximum values.
  • Failure: The test will fail if the routing table size is not between the provided minimum and maximum values.
Examples
anta.tests.routing:
  generic:
    - VerifyRoutingTableSize:
        minimum: 2
        maximum: 20

Inputs

Name Type Description Default
minimum PositiveInteger
Expected minimum routing table size.
-
maximum PositiveInteger
Expected maximum routing table size.
-
Source code in anta/tests/routing/generic.py
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
class VerifyRoutingTableSize(AntaTest):
    """Verifies the size of the IP routing table of the default VRF.

    Expected Results
    ----------------
    * Success: The test will pass if the routing table size is between the provided minimum and maximum values.
    * Failure: The test will fail if the routing table size is not between the provided minimum and maximum values.

    Examples
    --------
    ```yaml
    anta.tests.routing:
      generic:
        - VerifyRoutingTableSize:
            minimum: 2
            maximum: 20
    ```
    """

    categories: ClassVar[list[str]] = ["routing"]
    commands: ClassVar[list[AntaCommand | AntaTemplate]] = [AntaCommand(command="show ip route summary", revision=3)]

    class Input(AntaTest.Input):
        """Input model for the VerifyRoutingTableSize test."""

        minimum: PositiveInteger
        """Expected minimum routing table size."""
        maximum: PositiveInteger
        """Expected maximum routing table size."""

        @model_validator(mode="after")
        def check_min_max(self) -> Self:
            """Validate that maximum is greater than minimum."""
            if self.minimum > self.maximum:
                msg = f"Minimum {self.minimum} is greater than maximum {self.maximum}"
                raise ValueError(msg)
            return self

    @AntaTest.anta_test
    def test(self) -> None:
        """Main test function for VerifyRoutingTableSize."""
        command_output = self.instance_commands[0].json_output
        total_routes = int(command_output["vrfs"]["default"]["totalRoutes"])
        if self.inputs.minimum <= total_routes <= self.inputs.maximum:
            self.result.is_success()
        else:
            self.result.is_failure(
                f"Routing table routes are outside the routes range - Expected: {self.inputs.minimum} <= to >= {self.inputs.maximum} Actual: {total_routes}"
            )

Input models

Module containing input models for generic routing tests.

IPv4RouteEntry

Model for an IPv4 route entry.

Name Type Description Default
prefix IPv4Network
IPv4 prefix in CIDR notation.
-
vrf str
VRF context.
'default'
description str | None
Optional metadata describing the IPv4 route entry. Used for reporting.
None
route_type IPv4RouteType | None
Expected route type. Required field in the `VerifyIPv4RouteType` test.
None
nexthops list[IPv4Address] | None
A list of the next-hop IP addresses for the route. Required field in the `VerifyIPv4RouteNextHops` test.
None
strict bool
If True, requires exact matching of provided nexthop(s). Can be enabled in `VerifyIPv4RouteNextHops` test.
False
Source code in anta/input_models/routing/generic.py
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
class IPv4RouteEntry(BaseModel):
    """Model for an IPv4 route entry."""

    model_config = ConfigDict(extra="forbid")
    prefix: IPv4Network
    """IPv4 prefix in CIDR notation."""
    vrf: str = "default"
    """VRF context."""
    description: str | None = None
    """Optional metadata describing the IPv4 route entry. Used for reporting."""
    route_type: IPv4RouteType | None = None
    """Expected route type. Required field in the `VerifyIPv4RouteType` test."""
    nexthops: list[IPv4Address] | None = None
    """A list of the next-hop IP addresses for the route. Required field in the `VerifyIPv4RouteNextHops` test."""
    strict: bool = False
    """If True, requires exact matching of provided nexthop(s).

    Can be enabled in `VerifyIPv4RouteNextHops` test."""

    def __str__(self) -> str:
        """Return a human-readable string representation of the IPv4Routes for reporting."""
        identifier = f"Prefix: {self.prefix}"
        description = f" ({self.description})" if self.description else ""
        return f"{identifier}{description} VRF: {self.vrf}"

IPv4Routes

Alias for the IPv4RouteEntry model to maintain backward compatibility.

When initialized, it will emit a deprecation warning and call the IPv4RouteEntry model.

TODO: Remove this class in ANTA v2.0.0.

__init__

__init__(**data: Any) -> None
Source code in anta/input_models/routing/generic.py
51
52
53
54
55
56
57
58
def __init__(self, **data: Any) -> None:  # noqa: ANN401
    """Initialize the IPv4Routes class, emitting a deprecation warning."""
    warn(
        message="IPv4Routes model is deprecated and will be removed in ANTA v2.0.0. Use the IPv4RouteEntry model instead.",
        category=DeprecationWarning,
        stacklevel=2,
    )
    super().__init__(**data)
Source code in anta/input_models/routing/generic.py
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
class IPv4Routes(IPv4RouteEntry):  # pragma: no cover
    """Alias for the IPv4RouteEntry model to maintain backward compatibility.

    When initialized, it will emit a deprecation warning and call the IPv4RouteEntry model.

    TODO: Remove this class in ANTA v2.0.0.
    """

    def __init__(self, **data: Any) -> None:  # noqa: ANN401
        """Initialize the IPv4Routes class, emitting a deprecation warning."""
        warn(
            message="IPv4Routes model is deprecated and will be removed in ANTA v2.0.0. Use the IPv4RouteEntry model instead.",
            category=DeprecationWarning,
            stacklevel=2,
        )
        super().__init__(**data)