Merge pull request #6442 from wesleycoakley/pbrd-showjson

pbrd: Optional JSON output for all `show pbr` directives
This commit is contained in:
Russ White 2020-06-01 07:44:36 -04:00 committed by GitHub
commit b12b5d2097
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 737 additions and 10 deletions

View File

@ -56,10 +56,36 @@ listing of ECMP nexthops used to forward packets for when a pbr-map is matched.
Showing Nexthop Group Information Showing Nexthop Group Information
--------------------------------- ---------------------------------
.. clicmd:: show pbr nexthop-groups [NAME] .. clicmd:: show pbr nexthop-groups [NAME] [json]
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. nexthop groups are shown. Setting ``json`` will provide the same
information in an array of objects which obey the schema below:
+-----------+----------------------------+---------+
| Key | Description | Type |
+===========+============================+=========+
| id | Unique ID | Integer |
+-----------+----------------------------+---------+
| name | Name of this group | String |
+-----------+----------------------------+---------+
| valid | Is this group well-formed? | Boolean |
+-----------+----------------------------+---------+
| installed | ... and is it installed? | Boolean |
+-----------+----------------------------+---------+
| nexthops | Nexthops within this group | Array |
+-----------+----------------------------+---------+
Each element within ``nexthops`` describes a single target within this
group, and its structure is described by the JSON below:
+---------+------------------------------+---------+
| Key | Description | Type |
+=========+==============================+=========+
| nexthop | Name of this nexthop | String |
+---------+------------------------------+---------+
| valid | Is this nexthop well-formed? | Boolean |
+---------+------------------------------+---------+
.. _pbr-maps: .. _pbr-maps:
@ -115,11 +141,68 @@ end destination.
Not supported with NETNS VRF backend. Not supported with NETNS VRF backend.
.. clicmd:: show pbr map [NAME] [detail] .. 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 the rules unique ID used internally 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
which obey the schema below:
+----------+--------------------------------+---------+
| Key | Description | Type |
+==========+================================+=========+
| name | Map name | String |
+----------+--------------------------------+---------+
| valid | Is the map well-formed? | Boolean |
+----------+--------------------------------+---------+
| policies | Rules to match packets against | Array |
+----------+--------------------------------+---------+
Each element of the ``policies`` array is composed of a handful of objects
representing the policies associated with this map. Each policy is
described as below (not all fields are required):
+-----------------+-------------------------------------------+---------+
| Key | Description | Type |
+=================+===========================================+=========+
| id | Unique ID | Integer |
+-----------------+-------------------------------------------+---------+
| sequenceNumber | Order of this policy within the map | Integer |
+-----------------+-------------------------------------------+---------+
| ruleNumber | Rule number to install into | Integer |
+-----------------+-------------------------------------------+---------+
| vrfUnchanged | Use interface's VRF | Boolean |
+-----------------+-------------------------------------------+---------+
| installed | Is this policy installed? | Boolean |
+-----------------+-------------------------------------------+---------+
| installedReason | Why (or why not?) | String |
+-----------------+-------------------------------------------+---------+
| matchSrc | Match packets with this source address | String |
+-----------------+-------------------------------------------+---------+
| matchDst | ... or with this destination address | String |
+-----------------+-------------------------------------------+---------+
| matchMark | ... or with this marker | Integer |
+-----------------+-------------------------------------------+---------+
| vrfName | Associated VRF (if relevant) | String |
+-----------------+-------------------------------------------+---------+
| nexthopGroup | This policy's nexthop group (if relevant) | Object |
+-----------------+-------------------------------------------+---------+
Finally, the ``nexthopGroup`` object above cotains information we know
about the configured nexthop for this policy:
+---------------------+--------------------------------------+---------+
| Key | Description | Type |
+=====================+======================================+=========+
| tableId | Nexthop table ID | Integer |
+---------------------+--------------------------------------+---------+
| name | Name of the nexthop group | String |
+---------------------+--------------------------------------+---------+
| installed | Is this nexthop group installed? | Boolean |
+---------------------+--------------------------------------+---------+
| installedInternally | Do we think this group is installed? | Integer |
+---------------------+--------------------------------------+---------+
.. _pbr-policy: .. _pbr-policy:
@ -141,6 +224,24 @@ causes the policy to be installed into the kernel.
even if one is on the master. Each must have the PBR map explicitly added even if one is on the master. Each must have the PBR map explicitly added
to the interface. to the interface.
.. clicmd:: show pbr interface [NAME] [json]
Enumerates all interfaces which ``pbrd`` is keeping track of. Passing
``json`` will return an array of interfaces; each returned interface will
adhere to the JSON schema below:
+--------+----------------------------+---------+
| Key | Description | Type |
+========+============================+=========+
| name | Interface name | String |
+--------+----------------------------+---------+
| index | Device Index | Integer |
+--------+----------------------------+---------+
| policy | PBR map for this interface | String |
+--------+----------------------------+---------+
| valid | Is the map well-formed? | Boolean |
+--------+----------------------------+---------+
.. _pbr-details: .. _pbr-details:
PBR Details PBR Details

View File

@ -996,6 +996,60 @@ void nexthop_group_write_nexthop(struct vty *vty, struct nexthop *nh)
vty_out(vty, "\n"); vty_out(vty, "\n");
} }
void nexthop_group_json_nexthop(json_object *j, struct nexthop *nh)
{
char buf[100];
struct vrf *vrf;
switch (nh->type) {
case NEXTHOP_TYPE_IFINDEX:
json_object_string_add(j, "nexthop",
ifindex2ifname(nh->ifindex, nh->vrf_id));
break;
case NEXTHOP_TYPE_IPV4:
json_object_string_add(j, "nexthop", inet_ntoa(nh->gate.ipv4));
break;
case NEXTHOP_TYPE_IPV4_IFINDEX:
json_object_string_add(j, "nexthop", inet_ntoa(nh->gate.ipv4));
json_object_string_add(j, "vrfId",
ifindex2ifname(nh->ifindex, nh->vrf_id));
break;
case NEXTHOP_TYPE_IPV6:
json_object_string_add(
j, "nexthop",
inet_ntop(AF_INET6, &nh->gate.ipv6, buf, sizeof(buf)));
break;
case NEXTHOP_TYPE_IPV6_IFINDEX:
json_object_string_add(
j, "nexthop",
inet_ntop(AF_INET6, &nh->gate.ipv6, buf, sizeof(buf)));
json_object_string_add(j, "vrfId",
ifindex2ifname(nh->ifindex, nh->vrf_id));
break;
case NEXTHOP_TYPE_BLACKHOLE:
break;
}
if (nh->vrf_id != VRF_DEFAULT) {
vrf = vrf_lookup_by_id(nh->vrf_id);
json_object_string_add(j, "targetVrf", vrf->name);
}
if (nh->nh_label && nh->nh_label->num_labels > 0) {
char buf[200];
mpls_label2str(nh->nh_label->num_labels, nh->nh_label->label,
buf, sizeof(buf), 0);
json_object_string_add(j, "label", buf);
}
if (nh->weight)
json_object_int_add(j, "weight", nh->weight);
if (CHECK_FLAG(nh->flags, NEXTHOP_FLAG_HAS_BACKUP))
json_object_int_add(j, "backupIdx", nh->backup_idx);
}
static void nexthop_group_write_nexthop_internal(struct vty *vty, static void nexthop_group_write_nexthop_internal(struct vty *vty,
struct nexthop_hold *nh) struct nexthop_hold *nh)
{ {

View File

@ -22,6 +22,7 @@
#define __NEXTHOP_GROUP__ #define __NEXTHOP_GROUP__
#include <vty.h> #include <vty.h>
#include "json.h"
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
@ -136,6 +137,8 @@ extern struct nexthop_group_cmd *nhgc_find(const char *name);
extern void nexthop_group_write_nexthop(struct vty *vty, struct nexthop *nh); extern void nexthop_group_write_nexthop(struct vty *vty, struct nexthop *nh);
extern void nexthop_group_json_nexthop(json_object *j, struct nexthop *nh);
/* Return the number of nexthops in this nhg */ /* Return the number of nexthops in this nhg */
extern uint8_t nexthop_group_nexthop_num(const struct nexthop_group *nhg); extern uint8_t nexthop_group_nexthop_num(const struct nexthop_group *nhg);
extern uint8_t extern uint8_t

View File

@ -1030,8 +1030,22 @@ static void pbr_nht_show_nhg_nexthops(struct hash_bucket *b, void *data)
nexthop_group_write_nexthop(vty, pnhc->nexthop); nexthop_group_write_nexthop(vty, pnhc->nexthop);
} }
static void pbr_nht_json_nhg_nexthops(struct hash_bucket *b, void *data)
{
struct pbr_nexthop_cache *pnhc = b->data;
json_object *all_hops = data;
json_object *this_hop;
this_hop = json_object_new_object();
nexthop_group_json_nexthop(this_hop, pnhc->nexthop);
json_object_boolean_add(this_hop, "valid", pnhc->valid);
json_object_array_add(all_hops, this_hop);
}
struct pbr_nht_show { struct pbr_nht_show {
struct vty *vty; struct vty *vty;
json_object *json;
const char *name; const char *name;
}; };
@ -1051,6 +1065,36 @@ static void pbr_nht_show_nhg(struct hash_bucket *b, void *data)
hash_iterate(pnhgc->nhh, pbr_nht_show_nhg_nexthops, vty); hash_iterate(pnhgc->nhh, pbr_nht_show_nhg_nexthops, vty);
} }
static void pbr_nht_json_nhg(struct hash_bucket *b, void *data)
{
struct pbr_nexthop_group_cache *pnhgc = b->data;
struct pbr_nht_show *pns = data;
json_object *j, *this_group, *group_hops;
if (pns->name && strcmp(pns->name, pnhgc->name) != 0)
return;
j = pns->json;
this_group = json_object_new_object();
if (!j || !this_group)
return;
json_object_int_add(this_group, "id", pnhgc->table_id);
json_object_string_add(this_group, "name", pnhgc->name);
json_object_boolean_add(this_group, "valid", pnhgc->valid);
json_object_boolean_add(this_group, "installed", pnhgc->installed);
group_hops = json_object_new_array();
if (group_hops) {
hash_iterate(pnhgc->nhh, pbr_nht_json_nhg_nexthops, group_hops);
json_object_object_add(this_group, "nexthops", group_hops);
}
json_object_array_add(j, this_group);
}
void pbr_nht_show_nexthop_group(struct vty *vty, const char *name) void pbr_nht_show_nexthop_group(struct vty *vty, const char *name)
{ {
struct pbr_nht_show pns; struct pbr_nht_show pns;
@ -1061,6 +1105,16 @@ void pbr_nht_show_nexthop_group(struct vty *vty, const char *name)
hash_iterate(pbr_nhg_hash, pbr_nht_show_nhg, &pns); hash_iterate(pbr_nhg_hash, pbr_nht_show_nhg, &pns);
} }
void pbr_nht_json_nexthop_group(json_object *j, const char *name)
{
struct pbr_nht_show pns;
pns.name = name;
pns.json = j;
hash_iterate(pbr_nhg_hash, pbr_nht_json_nhg, &pns);
}
void pbr_nht_init(void) void pbr_nht_init(void)
{ {
pbr_nhg_hash = hash_create_size( pbr_nhg_hash = hash_create_size(

View File

@ -24,6 +24,7 @@
#include <lib/nexthop_group.h> #include <lib/nexthop_group.h>
#include "pbr_map.h" #include "pbr_map.h"
#include "json.h"
#define PBR_NHC_NAMELEN PBR_MAP_NAMELEN + 10 #define PBR_NHC_NAMELEN PBR_MAP_NAMELEN + 10
@ -112,6 +113,7 @@ extern char *pbr_nht_nexthop_make_name(char *name, size_t l, uint32_t seqno,
char *buffer); char *buffer);
extern void pbr_nht_show_nexthop_group(struct vty *vty, const char *name); extern void pbr_nht_show_nexthop_group(struct vty *vty, const char *name);
extern void pbr_nht_json_nexthop_group(json_object *j, const char *name);
/* /*
* When we get a callback from zebra about a nexthop changing * When we get a callback from zebra about a nexthop changing

View File

@ -27,6 +27,7 @@
#include "nexthop_group.h" #include "nexthop_group.h"
#include "nexthop_group_private.h" #include "nexthop_group_private.h"
#include "log.h" #include "log.h"
#include "json.h"
#include "debug.h" #include "debug.h"
#include "pbr.h" #include "pbr.h"
@ -590,6 +591,61 @@ static void vty_show_pbrms(struct vty *vty,
} }
} }
static void vty_json_pbrms(json_object *j, struct vty *vty,
const struct pbr_map_sequence *pbrms)
{
json_object *jpbrm, *nexthop_group;
char *nhg_name = pbrms->nhgrp_name ? pbrms->nhgrp_name
: pbrms->internal_nhg_name;
char buf[PREFIX_STRLEN];
char rbuf[64];
jpbrm = json_object_new_object();
json_object_int_add(jpbrm, "id", pbrms->unique);
if (pbrms->reason)
pbr_map_reason_string(pbrms->reason, rbuf, sizeof(rbuf));
json_object_int_add(jpbrm, "sequenceNumber", pbrms->seqno);
json_object_int_add(jpbrm, "ruleNumber", pbrms->ruleno);
json_object_boolean_add(jpbrm, "vrfUnchanged", pbrms->vrf_unchanged);
json_object_boolean_add(jpbrm, "installed",
pbr_nht_get_installed(nhg_name));
json_object_string_add(jpbrm, "installedReason",
pbrms->reason ? rbuf : "Valid");
if (nhg_name) {
nexthop_group = json_object_new_object();
json_object_int_add(nexthop_group, "tableId",
pbr_nht_get_table(nhg_name));
json_object_string_add(nexthop_group, "name", nhg_name);
json_object_boolean_add(nexthop_group, "installed",
pbr_nht_get_installed(nhg_name));
json_object_int_add(nexthop_group, "installedInternally",
pbrms->nhs_installed);
json_object_object_add(jpbrm, "nexthopGroup", nexthop_group);
}
if (pbrms->vrf_lookup)
json_object_string_add(jpbrm, "vrfName", pbrms->vrf_name);
if (pbrms->src)
json_object_string_add(
jpbrm, "matchSrc",
prefix2str(pbrms->src, buf, sizeof(buf)));
if (pbrms->dst)
json_object_string_add(
jpbrm, "matchDst",
prefix2str(pbrms->dst, buf, sizeof(buf)));
if (pbrms->mark)
json_object_int_add(jpbrm, "matchMark", pbrms->mark);
json_object_array_add(j, jpbrm);
}
static void vty_show_pbr_map(struct vty *vty, const struct pbr_map *pbrm, static void vty_show_pbr_map(struct vty *vty, const struct pbr_map *pbrm,
bool detail) bool detail)
{ {
@ -603,54 +659,121 @@ static void vty_show_pbr_map(struct vty *vty, const struct pbr_map *pbrm,
vty_show_pbrms(vty, pbrms, detail); vty_show_pbrms(vty, pbrms, detail);
} }
static void vty_json_pbr_map(json_object *j, struct vty *vty,
const struct pbr_map *pbrm)
{
struct pbr_map_sequence *pbrms;
struct listnode *node;
json_object *jpbrms;
json_object_string_add(j, "name", pbrm->name);
json_object_boolean_add(j, "valid", pbrm->valid);
jpbrms = json_object_new_array();
for (ALL_LIST_ELEMENTS_RO(pbrm->seqnumbers, node, pbrms))
vty_json_pbrms(jpbrms, vty, pbrms);
json_object_object_add(j, "policies", jpbrms);
}
DEFPY (show_pbr_map, DEFPY (show_pbr_map,
show_pbr_map_cmd, show_pbr_map_cmd,
"show pbr map [NAME$name] [detail$detail]", "show pbr map [NAME$name] [detail$detail|json$json]",
SHOW_STR SHOW_STR
PBR_STR PBR_STR
"PBR Map\n" "PBR Map\n"
"PBR Map Name\n" "PBR Map Name\n"
"Detailed information\n") "Detailed information\n"
JSON_STR)
{ {
struct pbr_map *pbrm; struct pbr_map *pbrm;
json_object *j = NULL;
if (json)
j = json_object_new_array();
RB_FOREACH (pbrm, pbr_map_entry_head, &pbr_maps) { RB_FOREACH (pbrm, pbr_map_entry_head, &pbr_maps) {
json_object *this_map = NULL;
if (name && strcmp(name, pbrm->name) != 0) if (name && strcmp(name, pbrm->name) != 0)
continue; continue;
if (j)
this_map = json_object_new_object();
if (this_map) {
vty_json_pbr_map(this_map, vty, pbrm);
json_object_array_add(j, this_map);
continue;
}
vty_show_pbr_map(vty, pbrm, detail); vty_show_pbr_map(vty, pbrm, detail);
} }
if (j) {
vty_out(vty, "%s\n",
json_object_to_json_string_ext(
j, JSON_C_TO_STRING_PRETTY));
json_object_free(j);
}
return CMD_SUCCESS; return CMD_SUCCESS;
} }
DEFPY(show_pbr_nexthop_group, DEFPY(show_pbr_nexthop_group,
show_pbr_nexthop_group_cmd, show_pbr_nexthop_group_cmd,
"show pbr nexthop-groups [WORD$word]", "show pbr nexthop-groups [WORD$word] [json$json]",
SHOW_STR SHOW_STR
PBR_STR PBR_STR
"Nexthop Groups\n" "Nexthop Groups\n"
"Optional Name of the nexthop group\n") "Optional Name of the nexthop group\n"
JSON_STR)
{ {
pbr_nht_show_nexthop_group(vty, word); json_object *j = NULL;
if (json)
j = json_object_new_array();
if (j) {
pbr_nht_json_nexthop_group(j, word);
vty_out(vty, "%s\n",
json_object_to_json_string_ext(
j, JSON_C_TO_STRING_PRETTY));
json_object_free(j);
} else
pbr_nht_show_nexthop_group(vty, word);
return CMD_SUCCESS; return CMD_SUCCESS;
} }
DEFPY (show_pbr_interface, DEFPY (show_pbr_interface,
show_pbr_interface_cmd, show_pbr_interface_cmd,
"show pbr interface [NAME$name]", "show pbr interface [NAME$name] [json$json]",
SHOW_STR SHOW_STR
PBR_STR PBR_STR
"PBR Interface\n" "PBR Interface\n"
"PBR Interface Name\n") "PBR Interface Name\n"
JSON_STR)
{ {
struct interface *ifp; struct interface *ifp;
struct vrf *vrf; struct vrf *vrf;
struct pbr_interface *pbr_ifp; struct pbr_interface *pbr_ifp;
json_object *j = NULL;
if (json)
j = json_object_new_array();
RB_FOREACH(vrf, vrf_name_head, &vrfs_by_name) { RB_FOREACH(vrf, vrf_name_head, &vrfs_by_name) {
FOR_ALL_INTERFACES(vrf, ifp) { FOR_ALL_INTERFACES(vrf, ifp) {
struct pbr_map *pbrm; struct pbr_map *pbrm;
json_object *this_iface = NULL;
if (j)
this_iface = json_object_new_object();
if (!ifp->info) if (!ifp->info)
continue; continue;
@ -664,6 +787,21 @@ DEFPY (show_pbr_interface,
continue; continue;
pbrm = pbrm_find(pbr_ifp->mapname); pbrm = pbrm_find(pbr_ifp->mapname);
if (this_iface) {
json_object_string_add(this_iface, "name",
ifp->name);
json_object_int_add(this_iface, "index",
ifp->ifindex);
json_object_string_add(this_iface, "policy",
pbr_ifp->mapname);
json_object_boolean_add(this_iface, "valid",
pbrm);
json_object_array_add(j, this_iface);
continue;
}
vty_out(vty, " %s(%d) with pbr-policy %s", ifp->name, vty_out(vty, " %s(%d) with pbr-policy %s", ifp->name,
ifp->ifindex, pbr_ifp->mapname); ifp->ifindex, pbr_ifp->mapname);
if (!pbrm) if (!pbrm)
@ -672,6 +810,13 @@ DEFPY (show_pbr_interface,
} }
} }
if (j) {
vty_out(vty, "%s\n",
json_object_to_json_string_ext(
j, JSON_C_TO_STRING_PRETTY));
json_object_free(j);
}
return CMD_SUCCESS; return CMD_SUCCESS;
} }

View File

@ -0,0 +1,10 @@
log file pbrd.log
nexthop-group A
nexthop 192.168.161.4
!
pbr-map FOO seq 10
match dst-ip 4.5.6.7/32
match src-ip 6.7.8.8/32
set nexthop-group A
!

View File

@ -123,6 +123,7 @@ def setup_module(module):
net['r%s' % i].loadConf('sharpd') net['r%s' % i].loadConf('sharpd')
net['r%s' % i].loadConf('nhrpd', '%s/r%s/nhrpd.conf' % (thisDir, i)) net['r%s' % i].loadConf('nhrpd', '%s/r%s/nhrpd.conf' % (thisDir, i))
net['r%s' % i].loadConf('babeld', '%s/r%s/babeld.conf' % (thisDir, i)) net['r%s' % i].loadConf('babeld', '%s/r%s/babeld.conf' % (thisDir, i))
net['r%s' % i].loadConf('pbrd', '%s/r%s/pbrd.conf' % (thisDir, i))
net['r%s' % i].startRouter() net['r%s' % i].startRouter()
# For debugging after starting Quagga/FRR daemons, uncomment the next line # For debugging after starting Quagga/FRR daemons, uncomment the next line

View File

@ -556,6 +556,7 @@ class TopoRouter(TopoGear):
RD_BFD = 13 RD_BFD = 13
RD_SHARP = 14 RD_SHARP = 14
RD_BABEL = 15 RD_BABEL = 15
RD_PBRD = 16
RD = { RD = {
RD_ZEBRA: "zebra", RD_ZEBRA: "zebra",
RD_RIP: "ripd", RD_RIP: "ripd",
@ -572,6 +573,7 @@ class TopoRouter(TopoGear):
RD_BFD: "bfdd", RD_BFD: "bfdd",
RD_SHARP: "sharpd", RD_SHARP: "sharpd",
RD_BABEL: "babeld", RD_BABEL: "babeld",
RD_PBRD: "pbrd",
} }
def __init__(self, tgen, cls, name, **params): def __init__(self, tgen, cls, name, **params):

View File

@ -871,6 +871,7 @@ class Router(Node):
"bfdd": 0, "bfdd": 0,
"sharpd": 0, "sharpd": 0,
"babeld": 0, "babeld": 0,
"pbrd": 0,
} }
self.daemons_options = {"zebra": ""} self.daemons_options = {"zebra": ""}
self.reportCores = True self.reportCores = True

View File

@ -0,0 +1,12 @@
[
{
"name":"r1-eth1",
"policy":"EVA",
"valid":true
},
{
"name":"r1-eth2",
"policy":"DONNA",
"valid":true
}
]

View File

@ -0,0 +1,60 @@
[
{
"name":"DONNA",
"valid":true,
"policies":[
{
"id":3,
"sequenceNumber":5,
"ruleNumber":304,
"vrfUnchanged":false,
"installed":true,
"installedReason":"Valid",
"nexthopGroup":{
"tableId":10002,
"name":"C",
"installed":true,
"installedInternally":1
},
"matchSrc":"1.2.0.0\/16",
"matchDst":"3.4.5.0\/24"
}
]
},
{
"name":"EVA",
"valid":true,
"policies":[
{
"id":1,
"sequenceNumber":5,
"ruleNumber":304,
"vrfUnchanged":false,
"installed":true,
"installedReason":"Valid",
"nexthopGroup":{
"tableId":10003,
"name":"EVA5",
"installed":true,
"installedInternally":1
},
"matchSrc":"4.5.6.7\/32"
},
{
"id":2,
"sequenceNumber":10,
"ruleNumber":309,
"vrfUnchanged":false,
"installed":true,
"installedReason":"Valid",
"nexthopGroup":{
"tableId":10000,
"name":"A",
"installed":true,
"installedInternally":1
},
"matchDst":"9.9.9.9\/32"
}
]
}
]

View File

@ -0,0 +1,58 @@
[
{
"id":10000,
"name":"A",
"valid":true,
"installed":true,
"nexthops":[
{
"nexthop":"192.168.2.2",
"valid":true
},
{
"nexthop":"192.168.3.2",
"valid":true
},
{
"nexthop":"192.168.1.2",
"valid":true
}
]
},
{
"id":10002,
"name":"C",
"valid":true,
"installed":true,
"nexthops":[
{
"nexthop":"192.168.1.44",
"valid":true
}
]
},
{
"id":10001,
"name":"B",
"valid":false,
"installed":false,
"nexthops":[
{
"nexthop":"192.168.50.1",
"valid":false
}
]
},
{
"id":10003,
"name":"EVA5",
"valid":true,
"installed":true,
"nexthops":[
{
"nexthop":"192.168.1.5",
"valid":true
}
]
}
]

View File

@ -0,0 +1,33 @@
nexthop-group A
nexthop 192.168.1.2
nexthop 192.168.2.2
nexthop 192.168.3.2
nexhtop 192.168.4.2
!
# This one is bogus and should
# never work
nexthop-group B
nexthop 192.168.50.1
!
nexthop-group C
nexthop 192.168.1.44
!
pbr-map EVA seq 5
match src-ip 4.5.6.7/32
set nexthop 192.168.1.5
!
pbr-map EVA seq 10
match dst-ip 9.9.9.9/32
set nexthop-group A
!
pbr-map DONNA seq 5
match dst-ip 3.4.5.0/24
match src-ip 1.2.0.0/16
set nexthop-group C
!
int r1-eth1
pbr-policy EVA
!
int r1-eth2
pbr-policy DONNA

View File

@ -0,0 +1,11 @@
int r1-eth0
ip address 192.168.1.1/24
int r1-eth1
ip address 192.168.2.1/24
int r1-eth2
ip address 192.168.3.1/24
int r1-eth3
ip address 192.168.4.1/24

View File

@ -0,0 +1,180 @@
#!/usr/bin/env python
#
# test_pbr_topo1.py
#
# Copyright (c) 2020 by
# Cumulus Networks, Inc.
# Donald Sharp
#
# 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_pbr_topo1.py: Testing PBR
"""
import os
import re
import sys
import pytest
import json
# Save the Current Working Directory to find configuration files.
CWD = os.path.dirname(os.path.realpath(__file__))
sys.path.append(os.path.join(CWD, "../"))
# 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
#####################################################
##
## Network Topology Definition
##
#####################################################
class NetworkTopo(Topo):
"PBR Topology 1"
def build(self, **_opts):
"Build function"
tgen = get_topogen(self)
for routern in range(1, 2):
tgen.add_router("r{}".format(routern))
# On main router
# First switch is for a dummy interface (for local network)
switch = tgen.add_switch("sw1")
switch.add_link(tgen.gears["r1"])
# Switches for PBR
# switch 2 switch is for connection to PBR router
switch = tgen.add_switch("sw2")
switch.add_link(tgen.gears["r1"])
# switch 4 is stub on remote PBR router
switch = tgen.add_switch("sw4")
switch.add_link(tgen.gears["r1"])
# switch 3 is between PBR routers
switch = tgen.add_switch("sw3")
switch.add_link(tgen.gears["r1"])
#####################################################
##
## Tests starting
##
#####################################################
def setup_module(module):
"Setup topology"
tgen = Topogen(NetworkTopo, module.__name__)
tgen.start_topology()
# This is a sample of configuration loading.
router_list = tgen.routers()
for rname, router in router_list.iteritems():
router.load_config(
TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname))
)
router.load_config(
TopoRouter.RD_PBRD, os.path.join(CWD, "{}/pbrd.conf".format(rname))
)
tgen.start_router()
#gen.mininet_cli()
def teardown_module(_mod):
"Teardown the pytest environment"
tgen = get_topogen()
# This function tears down the whole topology.
tgen.stop_topology()
def test_converge_protocols():
"Wait for protocol convergence"
tgen = get_topogen()
# Don't run this test if we have any failure.
if tgen.routers_have_failure():
pytest.skip(tgen.errors)
topotest.sleep(5, "Waiting for PBR convergence")
def test_pbr_data():
"Test PBR 'show ip eigrp'"
tgen = get_topogen()
# Don't run this test if we have any failure.
if tgen.routers_have_failure():
pytest.skip(tgen.errors)
# Verify PBR Status
logger.info("Verifying PBR routes")
router_list = tgen.routers().values()
for router in router_list:
intf_file = "{}/{}/pbr-interface.json".format(CWD, router.name)
logger.info(intf_file)
# Read expected result from file
expected = json.loads(open(intf_file).read())
# Actual output from router
actual = router.vtysh_cmd("show pbr interface json", isjson=True)
assertmsg = '"show pbr interface" mismatches on {}'.format(router.name)
assert topotest.json_cmp(actual, expected) 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())
# Actual output from router
actual = router.vtysh_cmd("show pbr map json", isjson=True)
assertmsg = '"show pbr map" mismatches on {}'.format(router.name)
assert topotest.json_cmp(actual, expected) is None, assertmsg
nexthop_file = "{}/{}/pbr-nexthop-groups.json".format(CWD, router.name)
# Read expected result from file
expected = json.loads(open(nexthop_file).read())
# Actual output from router
actual = router.vtysh_cmd("show pbr nexthop-groups json", isjson=True)
assertmsg = '"show pbr nexthop-groups" mismatches on {}'.format(router.name)
assert topotest.json_cmp(actual, expected) is None, assertmsg
if __name__ == "__main__":
args = ["-s"] + sys.argv[1:]
sys.exit(pytest.main(args))