mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-08-07 10:46:22 +00:00
pbrd: add vlan filters pcp/vlan-id/vlan-flags; ip-protocol any (doc, tests)
Subset: doc and tests doc PBR section updated with new fields and some copy-editing tests pbr_topo1: ensure new vlan fields arrive at zebra Changes by: Josh Werner <joshuawerner@mitre.org> Eli Baum <ebaum@mitre.org> G. Paul Ziemba <paulz@labn.net> Signed-off-by: G. Paul Ziemba <paulz@labn.net>
This commit is contained in:
parent
657882c430
commit
8b330fe8b7
203
doc/user/pbr.rst
203
doc/user/pbr.rst
@ -4,10 +4,11 @@
|
|||||||
PBR
|
PBR
|
||||||
***
|
***
|
||||||
|
|
||||||
:abbr:`PBR` is Policy Based Routing. This implementation supports a very simple
|
:abbr:`PBR` is Policy Based Routing, which means forwarding based on
|
||||||
interface to allow admins to influence routing on their router. At this time
|
packet fields other than solely the destination IP address.
|
||||||
you can only match on destination and source prefixes for an incoming interface.
|
This implementation currently works only on Linux. Note that some
|
||||||
At this point in time, this implementation will only work on Linux.
|
functionality (VLAN matching, packet mangling) is not supported by
|
||||||
|
the default Linux kernel dataplane provider.
|
||||||
|
|
||||||
.. _starting-pbr:
|
.. _starting-pbr:
|
||||||
|
|
||||||
@ -17,12 +18,12 @@ Starting PBR
|
|||||||
Default configuration file for *pbrd* is :file:`pbrd.conf`. The typical
|
Default configuration file for *pbrd* is :file:`pbrd.conf`. The typical
|
||||||
location of :file:`pbrd.conf` is |INSTALL_PREFIX_ETC|/pbrd.conf.
|
location of :file:`pbrd.conf` is |INSTALL_PREFIX_ETC|/pbrd.conf.
|
||||||
|
|
||||||
If the user is using integrated config, then :file:`pbrd.conf` need not be
|
If FRR is using integrated config, then :file:`pbrd.conf` need not be
|
||||||
present and the :file:`frr.conf` is read instead.
|
present and the :file:`frr.conf` is read instead.
|
||||||
|
|
||||||
.. program:: pbrd
|
.. program:: pbrd
|
||||||
|
|
||||||
:abbr:`PBR` supports all the common FRR daemon start options which are
|
:abbr:`PBR` supports all the common FRR daemon start options, which are
|
||||||
documented elsewhere.
|
documented elsewhere.
|
||||||
|
|
||||||
.. _nexthop-groups:
|
.. _nexthop-groups:
|
||||||
@ -30,9 +31,9 @@ documented elsewhere.
|
|||||||
Nexthop Groups
|
Nexthop Groups
|
||||||
==============
|
==============
|
||||||
|
|
||||||
Nexthop groups are a way to encapsulate ECMP information together. It's a
|
A nexthop group is a list of ECMP nexthops used to forward packets
|
||||||
listing of ECMP nexthops used to forward packets for when a pbr-map is matched.
|
when a pbr-map is matched.
|
||||||
For detailed instructions on how to specify a nexthop group on the CLI, see
|
For details on specifying a nexthop group in the CLI, see
|
||||||
the nexthop-groups section.
|
the nexthop-groups section.
|
||||||
|
|
||||||
Showing Nexthop Group Information
|
Showing Nexthop Group Information
|
||||||
@ -42,7 +43,7 @@ Showing Nexthop Group Information
|
|||||||
|
|
||||||
Display information on a PBR nexthop-group. If ``NAME`` is omitted, all
|
Display information on a PBR nexthop-group. If ``NAME`` is omitted, all
|
||||||
nexthop groups are shown. Setting ``json`` will provide the same
|
nexthop groups are shown. Setting ``json`` will provide the same
|
||||||
information in an array of objects which obey the schema below:
|
information in an array of objects that adhere to the schema below:
|
||||||
|
|
||||||
+-----------+----------------------------+---------+
|
+-----------+----------------------------+---------+
|
||||||
| Key | Description | Type |
|
| Key | Description | Type |
|
||||||
@ -74,118 +75,152 @@ Showing Nexthop Group Information
|
|||||||
PBR Maps
|
PBR Maps
|
||||||
========
|
========
|
||||||
|
|
||||||
PBR maps are a way to group policies that we would like to apply to individual
|
PBR maps are a way to specify a set of rules that are applied to
|
||||||
interfaces. These policies when applied are matched against incoming packets.
|
packets received on individual interfaces.
|
||||||
If matched the nexthop-group or nexthop is used to forward the packets to the
|
If a received packet matches a rule, the rule's nexthop-group or
|
||||||
end destination.
|
nexthop is used to forward it; any other actions
|
||||||
|
specified in the rule are also applied to the packet.
|
||||||
|
|
||||||
.. clicmd:: pbr-map NAME seq (1-700)
|
.. clicmd:: pbr-map NAME seq (1-700)
|
||||||
|
|
||||||
Create a pbr-map with NAME and sequence number specified. This command puts
|
Create a pbr-map rule with map NAME and specified sequence number.
|
||||||
you into a new submode for pbr-map specification. To exit this mode type
|
This command puts the CLI into a new submode for pbr-map rule specification.
|
||||||
exit or end as per normal conventions for leaving a sub-mode.
|
To exit this submode, type ``exit`` or ``end``.
|
||||||
|
|
||||||
.. clicmd:: match src-ip PREFIX
|
.. clicmd:: match src-ip PREFIX
|
||||||
|
|
||||||
When a incoming packet matches the source prefix specified, take the packet
|
Match the packet's source IP address.
|
||||||
and forward according to the nexthops specified. This command accepts both
|
|
||||||
v4 and v6 prefixes. This command is used in conjunction of the
|
This command accepts both v4 and v6 prefixes.
|
||||||
:clicmd:`match dst-ip PREFIX` command for matching.
|
|
||||||
|
|
||||||
.. clicmd:: match dst-ip PREFIX
|
.. clicmd:: match dst-ip PREFIX
|
||||||
|
|
||||||
When a incoming packet matches the destination prefix specified, take the
|
Match the packet's destination IP address.
|
||||||
packet and forward according to the nexthops specified. This command accepts
|
|
||||||
both v4 and v6 prefixes. This command is used in conjunction of the
|
This command accepts both v4 and v6 prefixes.
|
||||||
:clicmd:`match src-ip PREFIX` command for matching.
|
|
||||||
|
|
||||||
.. clicmd:: match src-port (1-65535)
|
.. clicmd:: match src-port (1-65535)
|
||||||
|
|
||||||
When a incoming packet matches the source port specified, take the
|
Match the packet's UDP or TCP source port.
|
||||||
packet and forward according to the nexthops specified.
|
|
||||||
|
|
||||||
.. clicmd:: match dst-port (1-65535)
|
.. clicmd:: match dst-port (1-65535)
|
||||||
|
|
||||||
When a incoming packet matches the destination port specified, take the
|
Match the packet's UDP or TCP destination port.
|
||||||
packet and forward according to the nexthops specified.
|
|
||||||
|
|
||||||
.. clicmd:: match ip-protocol [tcp|udp]
|
.. clicmd:: match ip-protocol PROTOCOL
|
||||||
|
|
||||||
When a incoming packet matches the specified ip protocol, take the
|
Match the packet's IP protocol.
|
||||||
packet and forward according to the nexthops specified.
|
|
||||||
|
Protocol names are queried from the protocols database (``/etc/protocols``;
|
||||||
|
see ``man 5 protocols`` and ``man 3 getprotobyname``).
|
||||||
|
|
||||||
.. clicmd:: match mark (1-4294967295)
|
.. clicmd:: match mark (1-4294967295)
|
||||||
|
|
||||||
Select the mark to match. This is a linux only command and if attempted
|
Match the packet's meta-information mark.
|
||||||
on another platform it will be denied. This mark translates to the
|
The mark value is attached to the packet by the kernel/dataplane and
|
||||||
underlying `ip rule .... fwmark XXXX` command.
|
is platform-specific.
|
||||||
|
Currently, this field is supported only on linux and corresponds to
|
||||||
|
the underlying `ip rule .... fwmark XXXX` command.
|
||||||
|
|
||||||
.. clicmd:: match dscp (DSCP|0-63)
|
.. clicmd:: match dscp (DSCP|0-63)
|
||||||
|
|
||||||
Match packets according to the specified differentiated services code point
|
Match the packet's IP differentiated services code point (DSCP).
|
||||||
(DSCP) in the IP header; if this value matches then forward the packet
|
The specified DSCP may also be a standard name for a
|
||||||
according to the nexthop(s) specified. The passed DSCP value may also be a
|
differentiated service code point such as ``cs0`` or ``af11``.
|
||||||
standard name for a differentiated service code point like cs0 or af11.
|
|
||||||
|
|
||||||
You may only specify one dscp per route map sequence; to match on multiple
|
You may only specify one dscp per route map rule; to match on multiple
|
||||||
dscp values you will need to create several sequences, one for each value.
|
dscp values you will need to create several rules, one for each value.
|
||||||
|
|
||||||
.. clicmd:: match ecn (0-3)
|
.. clicmd:: match ecn (0-3)
|
||||||
|
|
||||||
Match packets according to the specified explicit congestion notification
|
Match the packet's IP explicit congestion notification (ECN) field.
|
||||||
(ECN) field in the IP header; if this value matches then forward the packet
|
|
||||||
according to the nexthop(s) specified.
|
|
||||||
|
|
||||||
|
.. clicmd:: match pcp (0-7)
|
||||||
|
|
||||||
|
Match the packet's 802.1Q Priority Code Point.
|
||||||
|
Zero is the default (nominally, "best effort").
|
||||||
|
The Linux kernel dataplane provider does not currently support
|
||||||
|
matching PCPs,
|
||||||
|
so this field will be ignored unless other dataplane providers are used.
|
||||||
|
|
||||||
|
.. clicmd:: match vlan (1-4094)
|
||||||
|
|
||||||
|
Match the packet's VLAN (802.1Q) identifier.
|
||||||
|
Note that VLAN IDs 0 and 4095 are reserved.
|
||||||
|
The Linux kernel dataplane provider does not currently support
|
||||||
|
VLAN-matching facilities,
|
||||||
|
so this field will be ignored unless other dataplane providers are used.
|
||||||
|
|
||||||
|
.. clicmd:: match vlan (tagged|untagged|untagged-or-zero)
|
||||||
|
|
||||||
|
Match packets according to whether or not they have a VLAN tag.
|
||||||
|
Use `untagged-or-zero` to also match packets with either no VLAN tag
|
||||||
|
or with the reserved VLAN ID of 0 (indicating an untagged frame that
|
||||||
|
includes other 802.1Q fields).
|
||||||
|
The Linux kernel dataplane provider does not currently support
|
||||||
|
VLAN-matching facilities,
|
||||||
|
so this field will be ignored unless other dataplane providers are used.
|
||||||
|
|
||||||
.. clicmd:: set queue-id (1-65535)
|
.. clicmd:: set queue-id (1-65535)
|
||||||
|
|
||||||
Set the egress port queue identifier for matched packets. The Linux Kernel
|
Action:
|
||||||
provider does not currently support packet mangling, so this field will be
|
set the egress port queue identifier.
|
||||||
ignored unless another provider is used.
|
The Linux Kernel dataplane provider does not currently support
|
||||||
|
packet mangling,
|
||||||
|
so this field will be ignored unless another dataplane provider is used.
|
||||||
|
|
||||||
.. clicmd:: set pcp (0-7)
|
.. clicmd:: set pcp (0-7)
|
||||||
|
|
||||||
Set the 802.1Q priority code point (PCP) for matched packets. A PCP of zero
|
Action:
|
||||||
is the defaul (nominally, "best effort"). The Linux Kernel provider does not
|
set the 802.1Q priority code point (PCP).
|
||||||
currently support packet mangling, so this field will be ignored unless
|
A PCP of zero is the default (nominally, "best effort").
|
||||||
another provider is used.
|
The Linux Kernel dataplane provider does not currently support
|
||||||
|
packet mangling,
|
||||||
|
so this field will be ignored unless another dataplane provider is used.
|
||||||
|
|
||||||
.. clicmd:: set vlan (1-4094)
|
.. clicmd:: set vlan (1-4094)
|
||||||
|
|
||||||
Set the VLAN tag for matched packets. Identifiers 0 and 4095 are reserved.
|
Action:
|
||||||
The Linux Kernel provider does not currently support packet mangling, so
|
set the VLAN tag. Identifiers 0 and 4095 are reserved.
|
||||||
this field will be ignored unless another provider is used.
|
The Linux Kernel dataplane provider does not currently support
|
||||||
|
packet mangling,
|
||||||
|
so this field will be ignored unless another dataplane provider is used.
|
||||||
|
|
||||||
.. clicmd:: strip vlan
|
.. clicmd:: strip vlan
|
||||||
|
|
||||||
Strip inner vlan tags from matched packets. The Linux Kernel provider does not currently support packet mangling, so this field will be ignored unless another provider is used. It is invalid to specify both a `strip` and `set
|
Action:
|
||||||
vlan` action.
|
strip inner vlan tags.
|
||||||
|
The Linux Kernel dataplane provider does not currently support
|
||||||
|
packet mangling,
|
||||||
|
so this field will be ignored unless another dataplane provider is used.
|
||||||
|
It is invalid to specify both a `strip` and `set vlan` action.
|
||||||
|
|
||||||
.. clicmd:: set nexthop-group NAME
|
.. clicmd:: set nexthop-group NAME
|
||||||
|
|
||||||
Use the nexthop-group NAME as the place to forward packets when the match
|
Action:
|
||||||
commands have matched a packet.
|
forward the packet using nexthop-group NAME.
|
||||||
|
|
||||||
.. clicmd:: set nexthop [A.B.C.D|X:X::X:XX] [interface] [nexthop-vrf NAME]
|
.. clicmd:: set nexthop [A.B.C.D|X:X::X:XX] [interface] [nexthop-vrf NAME]
|
||||||
|
|
||||||
Use this individual nexthop as the place to forward packets when the match
|
Action:
|
||||||
commands have matched a packet.
|
forward the packet using the specified single nexthop.
|
||||||
|
|
||||||
.. clicmd:: set vrf unchanged|NAME
|
.. clicmd:: set vrf unchanged|NAME
|
||||||
|
|
||||||
If unchanged is set, the rule will use the vrf table the interface is in
|
Action:
|
||||||
as its lookup. If NAME is specified, the rule will use that vrf table as
|
If set to ``unchanged``, the rule will use the vrf table the interface
|
||||||
its lookup.
|
is in as its lookup.
|
||||||
|
If set to NAME, the rule will use that vrf table as its lookup.
|
||||||
|
|
||||||
Not supported with NETNS VRF backend.
|
Not supported with NETNS VRF backend.
|
||||||
|
|
||||||
.. clicmd:: show pbr map [NAME] [detail|json]
|
.. clicmd:: show pbr map [NAME] [detail|json]
|
||||||
|
|
||||||
Display pbr maps either all or by ``NAME``. If ``detail`` is set, it will
|
Display pbr maps either all or by ``NAME``. If ``detail`` is set, it will
|
||||||
give information about the rules unique ID used internally and some extra
|
give information about each rule's unique internal ID and some extra
|
||||||
debugging information about install state for the nexthop/nexthop group.
|
debugging information about install state for the nexthop/nexthop group.
|
||||||
Setting ``json`` will provide the same information in an array of objects
|
Setting ``json`` will provide the same information in an array of objects
|
||||||
which obey the schema below:
|
that adher to the schema below:
|
||||||
|
|
||||||
+----------+--------------------------------+---------+
|
+----------+--------------------------------+---------+
|
||||||
| Key | Description | Type |
|
| Key | Description | Type |
|
||||||
@ -197,9 +232,9 @@ end destination.
|
|||||||
| policies | Rules to match packets against | Array |
|
| policies | Rules to match packets against | Array |
|
||||||
+----------+--------------------------------+---------+
|
+----------+--------------------------------+---------+
|
||||||
|
|
||||||
Each element of the ``policies`` array is composed of a handful of objects
|
Each element of the ``policies`` array is composed of a set of objects
|
||||||
representing the policies associated with this map. Each policy is
|
representing the policies associated with this map. Each policy is
|
||||||
described as below (not all fields are required):
|
described below (not all fields are required):
|
||||||
|
|
||||||
+-----------------+-------------------------------------------+---------+
|
+-----------------+-------------------------------------------+---------+
|
||||||
| Key | Description | Type |
|
| Key | Description | Type |
|
||||||
@ -227,8 +262,8 @@ end destination.
|
|||||||
| nexthopGroup | This policy's nexthop group (if relevant) | Object |
|
| nexthopGroup | This policy's nexthop group (if relevant) | Object |
|
||||||
+-----------------+-------------------------------------------+---------+
|
+-----------------+-------------------------------------------+---------+
|
||||||
|
|
||||||
Finally, the ``nexthopGroup`` object above cotains information we know
|
Finally, the ``nexthopGroup`` object above contains information FRR
|
||||||
about the configured nexthop for this policy:
|
knows about the configured nexthop for this policy:
|
||||||
|
|
||||||
+---------------------+--------------------------------------+---------+
|
+---------------------+--------------------------------------+---------+
|
||||||
| Key | Description | Type |
|
| Key | Description | Type |
|
||||||
@ -239,7 +274,7 @@ end destination.
|
|||||||
+---------------------+--------------------------------------+---------+
|
+---------------------+--------------------------------------+---------+
|
||||||
| installed | Is this nexthop group installed? | Boolean |
|
| installed | Is this nexthop group installed? | Boolean |
|
||||||
+---------------------+--------------------------------------+---------+
|
+---------------------+--------------------------------------+---------+
|
||||||
| installedInternally | Do we think this group is installed? | Integer |
|
| installedInternally | Does FRR think NHG is installed? | Integer |
|
||||||
+---------------------+--------------------------------------+---------+
|
+---------------------+--------------------------------------+---------+
|
||||||
|
|
||||||
|
|
||||||
@ -251,19 +286,19 @@ end destination.
|
|||||||
PBR Policy
|
PBR Policy
|
||||||
==========
|
==========
|
||||||
|
|
||||||
After you have specified a PBR map, in order for it to be turned on, you must
|
After you have specified a PBR map, in order for it to be enabled, it must
|
||||||
apply the PBR map to an interface. This policy application to an interface
|
be applied to an interface. This policy application to an interface
|
||||||
causes the policy to be installed into the kernel.
|
causes the policy to be installed into the kernel.
|
||||||
|
|
||||||
.. clicmd:: pbr-policy NAME
|
.. clicmd:: pbr-policy NAME
|
||||||
|
|
||||||
This command is available under interface sub-mode. This turns
|
This command is available under interface sub-mode.
|
||||||
on the PBR map NAME and allows it to work properly.
|
It enables the PBR map NAME on the interface.
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
This will not dynamically create PBR maps on sub-interfaces (i.e. vlans)
|
This command will not dynamically create PBR maps on sub-interfaces
|
||||||
even if one is on the master. Each must have the PBR map explicitly added
|
(i.e. vlans), even if one is on the master.
|
||||||
to the interface.
|
Each sub-interface must have the PBR map enabled explicitly.
|
||||||
|
|
||||||
.. clicmd:: show pbr interface [NAME] [json]
|
.. clicmd:: show pbr interface [NAME] [json]
|
||||||
|
|
||||||
@ -285,9 +320,9 @@ causes the policy to be installed into the kernel.
|
|||||||
|
|
||||||
.. clicmd:: pbr table range (10000-4294966272) (10000-4294966272)
|
.. clicmd:: pbr table range (10000-4294966272) (10000-4294966272)
|
||||||
|
|
||||||
Set or unset the range used to assign numeric table ID's to new
|
Set or unset the range used to assign numeric table IDs to new
|
||||||
nexthop-group tables. Existing tables will not be modified to fit in this
|
nexthop-group tables. Existing tables will not be modified to fit in this
|
||||||
range, so it is recommended to configure this before adding nexthop groups.
|
range, so this range should be configured before adding nexthop groups.
|
||||||
|
|
||||||
.. seealso:: :ref:`pbr-details`
|
.. seealso:: :ref:`pbr-details`
|
||||||
|
|
||||||
@ -299,23 +334,23 @@ PBR Debugs
|
|||||||
|
|
||||||
.. clicmd:: debug pbr events|map|nht|zebra
|
.. clicmd:: debug pbr events|map|nht|zebra
|
||||||
|
|
||||||
Debug pbr in pbrd daemon. You specify what types of debugs to turn on.
|
Debug pbr in pbrd daemon. You must specify what types of debugs to turn on.
|
||||||
|
|
||||||
.. _pbr-details:
|
.. _pbr-details:
|
||||||
|
|
||||||
PBR Details
|
PBR Details
|
||||||
===========
|
===========
|
||||||
|
|
||||||
Under the covers a PBR map is translated into two separate constructs in the
|
Internally, a PBR map is translated into two separate constructs in the
|
||||||
Linux kernel.
|
Linux kernel.
|
||||||
|
|
||||||
|
|
||||||
The PBR map specified creates a `ip rule ...` that is inserted into the Linux
|
The PBR map creates an `ip rule ...` that is inserted into the Linux
|
||||||
kernel that points to a table to use for forwarding once the rule matches.
|
kernel that points to a table to use for forwarding once the rule matches.
|
||||||
|
|
||||||
|
|
||||||
The creation of a nexthop or nexthop-group is translated to a default route in a
|
The creation of a nexthop or nexthop-group is translated to a
|
||||||
table with the nexthops specified as the nexthops for the default route.
|
table with a default route having the specified nexthop(s).
|
||||||
|
|
||||||
|
|
||||||
Sample configuration
|
Sample configuration
|
||||||
|
@ -8,6 +8,8 @@
|
|||||||
# Cumulus Networks, Inc.
|
# Cumulus Networks, Inc.
|
||||||
# Donald Sharp
|
# Donald Sharp
|
||||||
#
|
#
|
||||||
|
# Copyright (c) 2023 LabN Consulting, L.L.C.
|
||||||
|
#
|
||||||
|
|
||||||
"""
|
"""
|
||||||
test_pbr_topo1.py: Testing PBR
|
test_pbr_topo1.py: Testing PBR
|
||||||
@ -19,6 +21,7 @@ import sys
|
|||||||
import pytest
|
import pytest
|
||||||
import json
|
import json
|
||||||
import platform
|
import platform
|
||||||
|
import re
|
||||||
from functools import partial
|
from functools import partial
|
||||||
|
|
||||||
# Save the Current Working Directory to find configuration files.
|
# Save the Current Working Directory to find configuration files.
|
||||||
@ -109,8 +112,29 @@ def test_converge_protocols():
|
|||||||
topotest.sleep(5, "Waiting for PBR convergence")
|
topotest.sleep(5, "Waiting for PBR convergence")
|
||||||
|
|
||||||
|
|
||||||
|
#
|
||||||
|
# router: r1
|
||||||
|
# tag: "show pbr interface"
|
||||||
|
# cmd: "show pbr interface json"
|
||||||
|
# expfile: "{}/{}/pbr-interface.json".format(CWD, router.name)
|
||||||
|
#
|
||||||
|
def runit(router, tag, cmd, expfile):
|
||||||
|
logger.info(expfile)
|
||||||
|
|
||||||
|
# Read expected result from file
|
||||||
|
expected = json.loads(open(expfile).read())
|
||||||
|
|
||||||
|
# Actual output from router
|
||||||
|
test_func = partial(topotest.router_json_cmp, router, cmd, expected)
|
||||||
|
_, result = topotest.run_and_expect(test_func, None, count=30, wait=1)
|
||||||
|
assertmsg = '"{}" mismatches on {}'.format(tag, router.name)
|
||||||
|
if result is not None:
|
||||||
|
gather_pbr_data_on_error(router)
|
||||||
|
assert result is None, assertmsg
|
||||||
|
|
||||||
|
|
||||||
def test_pbr_data():
|
def test_pbr_data():
|
||||||
"Test PBR 'show ip eigrp'"
|
"Test PBR"
|
||||||
|
|
||||||
tgen = get_topogen()
|
tgen = get_topogen()
|
||||||
# Don't run this test if we have any failure.
|
# Don't run this test if we have any failure.
|
||||||
@ -122,53 +146,145 @@ def test_pbr_data():
|
|||||||
|
|
||||||
router_list = tgen.routers().values()
|
router_list = tgen.routers().values()
|
||||||
for router in router_list:
|
for router in router_list:
|
||||||
intf_file = "{}/{}/pbr-interface.json".format(CWD, router.name)
|
runit(
|
||||||
logger.info(intf_file)
|
router,
|
||||||
|
"show pbr interface",
|
||||||
# Read expected result from file
|
"show pbr interface json",
|
||||||
expected = json.loads(open(intf_file).read())
|
"{}/{}/pbr-interface.json".format(CWD, router.name),
|
||||||
|
|
||||||
# Actual output from router
|
|
||||||
test_func = partial(
|
|
||||||
topotest.router_json_cmp, router, "show pbr interface json", expected
|
|
||||||
)
|
)
|
||||||
_, result = topotest.run_and_expect(test_func, None, count=30, wait=1)
|
|
||||||
assertmsg = '"show pbr interface" mismatches on {}'.format(router.name)
|
runit(
|
||||||
|
router,
|
||||||
|
"show pbr map",
|
||||||
|
"show pbr map json",
|
||||||
|
"{}/{}/pbr-map.json".format(CWD, router.name),
|
||||||
|
)
|
||||||
|
|
||||||
|
runit(
|
||||||
|
router,
|
||||||
|
"show pbr nexthop-groups",
|
||||||
|
"show pbr nexthop-groups json",
|
||||||
|
"{}/{}/pbr-nexthop-groups.json".format(CWD, router.name),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
########################################################################
|
||||||
|
# Field test - START
|
||||||
|
########################################################################
|
||||||
|
|
||||||
|
#
|
||||||
|
# New fields:
|
||||||
|
# match ip-protocol (was only tcp|udp, now any value in /etc/protocols)
|
||||||
|
# match pcp (0-7)
|
||||||
|
# match vlan (1-4094)
|
||||||
|
# match vlan (tagged|untagged|untagged-or-zero)
|
||||||
|
#
|
||||||
|
|
||||||
|
#
|
||||||
|
# tm: must-match pattern
|
||||||
|
# tN: must Not match pattern
|
||||||
|
#
|
||||||
|
# Note we are searching amid a bunch of other rules, so these elements
|
||||||
|
# should be unique.
|
||||||
|
#
|
||||||
|
ftest = [
|
||||||
|
{"c": "match ip-protocol icmp", "tm": r"IP protocol Match: 1$"},
|
||||||
|
{"c": "no match ip-protocol icmp", "tN": r"IP protocol Match:"},
|
||||||
|
{"c": "match pcp 6", "tm": r"PCP Match: 6$"},
|
||||||
|
{"c": "match pcp 0", "tm": r"PCP Match: 0$"},
|
||||||
|
{"c": "no match pcp 0", "tN": r"PCP Match:"},
|
||||||
|
{"c": "match vlan 33", "tm": r"VLAN ID Match: 33$"},
|
||||||
|
{"c": "no match vlan 33", "tN": r"VLAN ID Match:"},
|
||||||
|
{"c": "match vlan tagged", "tm": r"VLAN Flags Match: tagged$"},
|
||||||
|
{"c": "match vlan untagged", "tm": r"VLAN Flags Match: untagged$"},
|
||||||
|
{"c": "match vlan untagged-or-zero", "tm": r"VLAN Flags Match: untagged-or-zero$"},
|
||||||
|
{"c": "no match vlan tagged", "tN": r"VLAN Flags Match:"},
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
# returns None if command output is correct, otherwise returns output
|
||||||
|
def rtr_field_cmp(rtr, cmd, pat_mustmatch, pat_mustnotmatch):
|
||||||
|
outstr = rtr.vtysh_cmd(cmd)
|
||||||
|
if pat_mustmatch is not None:
|
||||||
|
logger.info("MUSTMATCH: {}".format(pat_mustmatch))
|
||||||
|
m = re.search(pat_mustmatch, outstr, flags=re.M)
|
||||||
|
if not m:
|
||||||
|
logger.info('Missing MUSTMATCH "{}"'.format(pat_mustmatch))
|
||||||
|
return "MISSING MUSTMATCH: " + outstr
|
||||||
|
if pat_mustnotmatch is not None:
|
||||||
|
logger.info("MUSTNOTMATCH: {}".format(pat_mustnotmatch))
|
||||||
|
m = re.search(pat_mustnotmatch, outstr, flags=re.M)
|
||||||
|
if m:
|
||||||
|
logger.info('Has MUSTNOTMATCH "{}"'.format(pat_mustnotmatch))
|
||||||
|
return "HAS MUSTNOTMATCH: " + outstr
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
#
|
||||||
|
# This test sets fields in pbrd and looks for them in zebra via "sh pbr map"
|
||||||
|
#
|
||||||
|
def test_pbr_fields():
|
||||||
|
"Test setting and clearing rule fields"
|
||||||
|
|
||||||
|
tgen = get_topogen()
|
||||||
|
# Don't run this test if we have any failure.
|
||||||
|
if tgen.routers_have_failure():
|
||||||
|
pytest.skip(tgen.errors)
|
||||||
|
|
||||||
|
logger.info("Verifying PBR rule fields")
|
||||||
|
|
||||||
|
tag = "field"
|
||||||
|
|
||||||
|
router_list = tgen.routers().values()
|
||||||
|
for router in router_list:
|
||||||
|
for t in ftest:
|
||||||
|
# send field-setting command
|
||||||
|
# always have a match dst-ip to satisfy rule non-empty check
|
||||||
|
vcmd = "c t\npbr-map ASAKUSA seq 100\n{}\nmatch dst-ip 9.9.9.9/32\nset nexthop-group A\nend\nend".format(
|
||||||
|
t["c"]
|
||||||
|
)
|
||||||
|
router.vtysh_multicmd(vcmd)
|
||||||
|
|
||||||
|
# debug
|
||||||
|
router.vtysh_cmd("sh pbr map")
|
||||||
|
|
||||||
|
match = None
|
||||||
|
notmatch = None
|
||||||
|
|
||||||
|
if "tm" in t:
|
||||||
|
match = t["tm"]
|
||||||
|
logger.info("MUSTMATCH: {}".format(match))
|
||||||
|
if "tN" in t:
|
||||||
|
notmatch = t["tN"]
|
||||||
|
logger.info("NOTMATCH: {}".format(notmatch))
|
||||||
|
|
||||||
|
test_func = partial(rtr_field_cmp, router, "sh pbr rule", match, notmatch)
|
||||||
|
_, result = topotest.run_and_expect(test_func, None, count=10, wait=1)
|
||||||
|
assertmsg = '"{}" mismatches on {}'.format(tag, router.name)
|
||||||
|
if result is not None:
|
||||||
|
gather_pbr_data_on_error(router)
|
||||||
|
assert result is None, assertmsg
|
||||||
|
|
||||||
|
#
|
||||||
|
# clean up
|
||||||
|
#
|
||||||
|
vcmd = "c t\nno pbr-map ASAKUSA seq 100\nend"
|
||||||
|
router.vtysh_multicmd(vcmd)
|
||||||
|
|
||||||
|
match = None
|
||||||
|
notmatch = r"Seq 100\w"
|
||||||
|
|
||||||
|
test_func = partial(rtr_field_cmp, router, "sh pbr rule", match, notmatch)
|
||||||
|
_, result = topotest.run_and_expect(test_func, None, count=10, wait=1)
|
||||||
|
assertmsg = '"{}" mismatches on {}'.format(tag, router.name)
|
||||||
if result is not None:
|
if result is not None:
|
||||||
gather_pbr_data_on_error(router)
|
gather_pbr_data_on_error(router)
|
||||||
assert result is None, assertmsg
|
assert result is None, assertmsg
|
||||||
|
|
||||||
map_file = "{}/{}/pbr-map.json".format(CWD, router.name)
|
|
||||||
logger.info(map_file)
|
|
||||||
|
|
||||||
# Read expected result from file
|
########################################################################
|
||||||
expected = json.loads(open(map_file).read())
|
# Field test - END
|
||||||
|
########################################################################
|
||||||
# Actual output from router
|
|
||||||
test_func = partial(
|
|
||||||
topotest.router_json_cmp, router, "show pbr map json", expected
|
|
||||||
)
|
|
||||||
_, result = topotest.run_and_expect(test_func, None, count=30, wait=1)
|
|
||||||
assertmsg = '"show pbr map" mismatches on {}'.format(router.name)
|
|
||||||
if result is not None:
|
|
||||||
gather_pbr_data_on_error(router)
|
|
||||||
assert result is None, assertmsg
|
|
||||||
|
|
||||||
nexthop_file = "{}/{}/pbr-nexthop-groups.json".format(CWD, router.name)
|
|
||||||
logger.info(nexthop_file)
|
|
||||||
|
|
||||||
# Read expected result from file
|
|
||||||
expected = json.loads(open(nexthop_file).read())
|
|
||||||
|
|
||||||
# Actual output from router
|
|
||||||
test_func = partial(
|
|
||||||
topotest.router_json_cmp, router, "show pbr nexthop-groups json", expected
|
|
||||||
)
|
|
||||||
_, result = topotest.run_and_expect(test_func, None, count=30, wait=1)
|
|
||||||
assertmsg = '"show pbr nexthop-groups" mismatches on {}'.format(router.name)
|
|
||||||
if result is not None:
|
|
||||||
gather_pbr_data_on_error(router)
|
|
||||||
assert result is None, assertmsg
|
|
||||||
|
|
||||||
|
|
||||||
def test_pbr_flap():
|
def test_pbr_flap():
|
||||||
@ -244,6 +360,7 @@ if __name__ == "__main__":
|
|||||||
args = ["-s"] + sys.argv[1:]
|
args = ["-s"] + sys.argv[1:]
|
||||||
sys.exit(pytest.main(args))
|
sys.exit(pytest.main(args))
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# EXTRA SAUCE
|
# EXTRA SAUCE
|
||||||
#
|
#
|
||||||
|
Loading…
Reference in New Issue
Block a user