mirror of
https://github.com/FRRouting/frr.git
synced 2025-04-30 13:37:17 +02:00

This is an implementation of PBR for FRR. This implemenation uses a combination of rules and tables to determine how packets will flow. PBR introduces a new concept of 'nexthop-groups' to specify a group of nexthops that will be used for ecmp. Nexthop-groups are specified on the cli via: nexthop-group DONNA nexthop 192.168.208.1 nexthop 192.168.209.1 nexthop 192.168.210.1 ! PBR sees the nexthop-group and installs these as a default route with these nexthops starting at table 10000 robot# show pbr nexthop-groups Nexthop-Group: DONNA Table: 10001 Valid: 1 Installed: 1 Valid: 1 nexthop 192.168.209.1 Valid: 1 nexthop 192.168.210.1 Valid: 1 nexthop 192.168.208.1 I have also introduced the ability to specify a table in a 'show ip route table XXX' to see the specified tables. robot# show ip route table 10001 Codes: K - kernel route, C - connected, S - static, R - RIP, O - OSPF, I - IS-IS, B - BGP, P - PIM, E - EIGRP, N - NHRP, T - Table, v - VNC, V - VNC-Direct, A - Babel, D - SHARP, F - PBR, > - selected route, * - FIB route F>* 0.0.0.0/0 [0/0] via 192.168.208.1, enp0s8, 00:14:25 * via 192.168.209.1, enp0s9, 00:14:25 * via 192.168.210.1, enp0s10, 00:14:25 PBR tracks PBR-MAPS via the pbr-map command: ! pbr-map EVA seq 10 match src-ip 4.3.4.0/24 set nexthop-group DONNA ! pbr-map EVA seq 20 match dst-ip 4.3.5.0/24 set nexthop-group DONNA ! pbr-maps can have 'match src-ip <prefix>' and 'match dst-ip <prefix>' to affect decisions about incoming packets. Additionally if you only have one nexthop to use for a pbr-map you do not need to setup a nexthop-group and can specify 'set nexthop XXXX'. To apply the pbr-map to an incoming interface you do this: interface enp0s10 pbr-policy EVA ! When a pbr-map is applied to interfaces it can be installed into the kernel as a rule: [sharpd@robot frr1]$ ip rule show 0: from all lookup local 309: from 4.3.4.0/24 iif enp0s10 lookup 10001 319: from all to 4.3.5.0/24 iif enp0s10 lookup 10001 1000: from all lookup [l3mdev-table] 32766: from all lookup main 32767: from all lookup default [sharpd@robot frr1]$ ip route show table 10001 default proto pbr metric 20 nexthop via 192.168.208.1 dev enp0s8 weight 1 nexthop via 192.168.209.1 dev enp0s9 weight 1 nexthop via 192.168.210.1 dev enp0s10 weight 1 The linux kernel now will use the rules and tables to properly apply these policies. Signed-off-by: Donald Sharp <sharpd@cumulusnetworks.com> Signed-off-by: Don Slice <dslice@cumulusnetworks.com> Signed-off-by: Quentin Young <qlyoung@cumulusnetworks.com>
632 lines
15 KiB
C
632 lines
15 KiB
C
/*
|
|
* PBR - vty code
|
|
* Copyright (C) 2018 Cumulus Networks, Inc.
|
|
* Donald Sharp
|
|
*
|
|
* FRR is free software; you can redistribute it and/or modify it
|
|
* under the terms of the GNU General Public License as published by the
|
|
* Free Software Foundation; either version 2, or (at your option) any
|
|
* later version.
|
|
*
|
|
* FRR is distributed in the hope that it will be useful, but
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License along
|
|
* with this program; see the file COPYING; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
*/
|
|
#include <zebra.h>
|
|
|
|
#include "vty.h"
|
|
#include "command.h"
|
|
#include "prefix.h"
|
|
#include "vrf.h"
|
|
#include "nexthop.h"
|
|
#include "nexthop_group.h"
|
|
#include "log.h"
|
|
#include "json.h"
|
|
#include "debug.h"
|
|
|
|
#include "pbrd/pbr_nht.h"
|
|
#include "pbrd/pbr_map.h"
|
|
#include "pbrd/pbr_zebra.h"
|
|
#include "pbrd/pbr_vty.h"
|
|
#include "pbrd/pbr_event.h"
|
|
#include "pbrd/pbr_debug.h"
|
|
#ifndef VTYSH_EXTRACT_PL
|
|
#include "pbrd/pbr_vty_clippy.c"
|
|
#endif
|
|
|
|
DEFUN_NOSH(pbr_map, pbr_map_cmd, "pbr-map WORD seq (1-1000)",
|
|
"Create pbr-map or enter pbr-map command mode\n"
|
|
"The name of the PBR MAP\n"
|
|
"Sequence to insert in existing pbr-map entry\n"
|
|
"Sequence number\n")
|
|
{
|
|
const char *pbrm_name = argv[1]->arg;
|
|
uint32_t seqno = atoi(argv[3]->arg);
|
|
struct pbr_map_sequence *pbrms;
|
|
|
|
pbrms = pbrms_get(pbrm_name, seqno);
|
|
VTY_PUSH_CONTEXT(PBRMAP_NODE, pbrms);
|
|
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
DEFUN_NOSH(no_pbr_map, no_pbr_map_cmd, "no pbr-map WORD [seq (1-65535)]",
|
|
NO_STR
|
|
"Delete pbr-map\n"
|
|
"The name of the PBR MAP\n"
|
|
"Sequence to delete from existing pbr-map entry\n"
|
|
"Sequence number\n")
|
|
{
|
|
const char *pbrm_name = argv[2]->arg;
|
|
uint32_t seqno = 0;
|
|
struct pbr_map *pbrm = pbrm_find(pbrm_name);
|
|
struct pbr_event *pbre;
|
|
struct pbr_map_sequence *pbrms;
|
|
struct listnode *node, *next_node;
|
|
|
|
if (argc > 3)
|
|
seqno = atoi(argv[4]->arg);
|
|
|
|
if (!pbrm) {
|
|
vty_out(vty, "pbr-map %s not found\n", pbrm_name);
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
if (seqno) {
|
|
pbrms = pbrms_get(pbrm->name, seqno);
|
|
pbrms->reason |= PBR_MAP_DEL_SEQUENCE_NUMBER;
|
|
} else {
|
|
for (ALL_LIST_ELEMENTS(pbrm->seqnumbers, node, next_node,
|
|
pbrms)) {
|
|
if (pbrms)
|
|
pbrms->reason |= PBR_MAP_DEL_SEQUENCE_NUMBER;
|
|
}
|
|
}
|
|
|
|
pbre = pbr_event_new(PBR_MAP_DELETE, pbrm_name);
|
|
pbre->seqno = seqno;
|
|
pbr_event_enqueue(pbre);
|
|
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
DEFPY(pbr_map_match_src, pbr_map_match_src_cmd,
|
|
"[no] match src-ip <A.B.C.D/M|X:X::X:X/M>$prefix",
|
|
NO_STR
|
|
"Match the rest of the command\n"
|
|
"Choose the src ip or ipv6 prefix to use\n"
|
|
"v4 Prefix\n"
|
|
"v6 Prefix\n")
|
|
{
|
|
struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence);
|
|
struct pbr_event *pbre;
|
|
|
|
if (!no) {
|
|
if (!pbrms->src)
|
|
pbrms->src = prefix_new();
|
|
prefix_copy(pbrms->src, prefix);
|
|
} else {
|
|
prefix_free(pbrms->src);
|
|
pbrms->src = 0;
|
|
}
|
|
|
|
pbre = pbr_event_new(PBR_MAP_MODIFY, pbrms->parent->name);
|
|
pbre->seqno = pbrms->seqno;
|
|
pbr_event_enqueue(pbre);
|
|
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
DEFPY(pbr_map_match_dst, pbr_map_match_dst_cmd,
|
|
"[no] match dst-ip <A.B.C.D/M|X:X::X:X/M>$prefix",
|
|
NO_STR
|
|
"Match the rest of the command\n"
|
|
"Choose the src ip or ipv6 prefix to use\n"
|
|
"v4 Prefix\n"
|
|
"v6 Prefix\n")
|
|
{
|
|
struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence);
|
|
struct pbr_event *pbre;
|
|
|
|
if (!no) {
|
|
if (!pbrms->dst)
|
|
pbrms->dst = prefix_new();
|
|
prefix_copy(pbrms->dst, prefix);
|
|
} else {
|
|
prefix_free(pbrms->dst);
|
|
pbrms->dst = 0;
|
|
}
|
|
|
|
pbre = pbr_event_new(PBR_MAP_MODIFY, pbrms->parent->name);
|
|
pbre->seqno = pbrms->seqno;
|
|
pbr_event_enqueue(pbre);
|
|
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
DEFPY(pbr_map_nexthop_group, pbr_map_nexthop_group_cmd,
|
|
"[no] set nexthop-group NAME$name",
|
|
NO_STR
|
|
"Set for the PBR-MAP\n"
|
|
"nexthop-group to use\n"
|
|
"The name of the nexthop-group\n")
|
|
{
|
|
struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence);
|
|
struct nexthop_group_cmd *nhgc;
|
|
struct pbr_event *pbre;
|
|
|
|
nhgc = nhgc_find(name);
|
|
if (!nhgc) {
|
|
vty_out(vty, "Specified nexthop-group %s does not exist\n",
|
|
name);
|
|
vty_out(vty, "PBR-MAP will not be applied until it is created\n");
|
|
}
|
|
|
|
if (no) {
|
|
if (pbrms->nhgrp_name && strcmp(name, pbrms->nhgrp_name) == 0)
|
|
pbre = pbr_event_new(PBR_MAP_NHG_DELETE,
|
|
pbrms->parent->name);
|
|
else {
|
|
vty_out(vty,
|
|
"Nexthop Group specified: %s does not exist to remove",
|
|
name);
|
|
return CMD_WARNING;
|
|
}
|
|
} else {
|
|
if (pbrms->nhgrp_name) {
|
|
if (strcmp(name, pbrms->nhgrp_name) != 0) {
|
|
vty_out(vty,
|
|
"Please delete current nexthop group before modifying current one");
|
|
return CMD_WARNING;
|
|
}
|
|
|
|
return CMD_SUCCESS;
|
|
}
|
|
pbrms->nhgrp_name = XSTRDUP(MTYPE_TMP, name);
|
|
pbre = pbr_event_new(PBR_MAP_NHG_ADD, pbrms->parent->name);
|
|
}
|
|
|
|
pbre->seqno = pbrms->seqno;
|
|
pbr_event_enqueue(pbre);
|
|
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
DEFPY(pbr_map_nexthop, pbr_map_nexthop_cmd,
|
|
"[no] set nexthop <A.B.C.D|X:X::X:X>$addr [INTERFACE]$intf [nexthop-vrf NAME$name]",
|
|
NO_STR
|
|
"Set for the PBR-MAP\n"
|
|
"Specify one of the nexthops in this map\n"
|
|
"v4 Address\n"
|
|
"v6 Address\n"
|
|
"Interface to use\n"
|
|
"If the nexthop is in a different vrf tell us\n"
|
|
"The nexthop-vrf Name\n")
|
|
{
|
|
struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence);
|
|
struct vrf *vrf;
|
|
struct nexthop nhop;
|
|
struct nexthop *nh;
|
|
struct pbr_event *pbre;
|
|
|
|
if (pbrms->nhgrp_name) {
|
|
vty_out(vty,
|
|
"Please unconfigure the nexthop group before adding an individual nexthop");
|
|
return CMD_WARNING;
|
|
}
|
|
|
|
if (name)
|
|
vrf = vrf_lookup_by_name(name);
|
|
else
|
|
vrf = vrf_lookup_by_id(VRF_DEFAULT);
|
|
|
|
if (!vrf) {
|
|
vty_out(vty, "Specified: %s is non-existent\n", name);
|
|
return CMD_WARNING;
|
|
}
|
|
|
|
memset(&nhop, 0, sizeof(nhop));
|
|
nhop.vrf_id = vrf->vrf_id;
|
|
|
|
if (addr->sa.sa_family == AF_INET) {
|
|
nhop.gate.ipv4.s_addr = addr->sin.sin_addr.s_addr;
|
|
if (intf) {
|
|
nhop.type = NEXTHOP_TYPE_IPV4_IFINDEX;
|
|
nhop.ifindex = ifname2ifindex(intf, vrf->vrf_id);
|
|
if (nhop.ifindex == IFINDEX_INTERNAL) {
|
|
vty_out(vty,
|
|
"Specified Intf %s does not exist in vrf: %s\n",
|
|
intf, vrf->name);
|
|
return CMD_WARNING;
|
|
}
|
|
} else
|
|
nhop.type = NEXTHOP_TYPE_IPV4;
|
|
} else {
|
|
memcpy(&nhop.gate.ipv6, &addr->sin6.sin6_addr, 16);
|
|
if (intf) {
|
|
nhop.type = NEXTHOP_TYPE_IPV6_IFINDEX;
|
|
nhop.ifindex = ifname2ifindex(intf, vrf->vrf_id);
|
|
if (nhop.ifindex == IFINDEX_INTERNAL) {
|
|
vty_out(vty,
|
|
"Specified Intf %s does not exist in vrf: %s\n",
|
|
intf, vrf->name);
|
|
return CMD_WARNING;
|
|
}
|
|
} else
|
|
nhop.type = NEXTHOP_TYPE_IPV6;
|
|
}
|
|
|
|
if (pbrms->nhg)
|
|
nh = nexthop_exists(pbrms->nhg, &nhop);
|
|
else {
|
|
char buf[100];
|
|
|
|
if (no) {
|
|
vty_out(vty, "No nexthops to delete");
|
|
return CMD_WARNING;
|
|
}
|
|
|
|
pbrms->nhg = nexthop_group_new();
|
|
pbrms->internal_nhg_name =
|
|
XSTRDUP(MTYPE_TMP,
|
|
pbr_nht_nexthop_make_name(pbrms->parent->name,
|
|
PBR_MAP_NAMELEN,
|
|
pbrms->seqno,
|
|
buf));
|
|
nh = NULL;
|
|
}
|
|
|
|
if (no) {
|
|
if (nh) {
|
|
// nexthop_del(pbrms->nhg, nh);
|
|
// nexthop_free(nh);
|
|
pbre = pbr_event_new(PBR_MAP_NEXTHOP_DELETE,
|
|
pbrms->parent->name);
|
|
pbre->seqno = pbrms->seqno;
|
|
pbr_event_enqueue(pbre);
|
|
}
|
|
} else if (!nh) {
|
|
|
|
if (pbrms->nhg->nexthop) {
|
|
vty_out(vty,
|
|
"If you would like more than one nexthop please use nexthop-groups");
|
|
return CMD_WARNING;
|
|
}
|
|
|
|
/* must be adding new nexthop since !no and !nexthop_exists */
|
|
nh = nexthop_new();
|
|
|
|
memcpy(nh, &nhop, sizeof(nhop));
|
|
nexthop_add(&pbrms->nhg->nexthop, nh);
|
|
|
|
pbre = pbr_event_new(PBR_MAP_NEXTHOP_ADD, pbrms->parent->name);
|
|
pbre->seqno = pbrms->seqno;
|
|
pbr_event_enqueue(pbre);
|
|
}
|
|
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
DEFPY (pbr_table_range,
|
|
pbr_table_range_cmd,
|
|
"[no]$no pbr table range (10000-65535)$start (11000-65535)$end",
|
|
NO_STR
|
|
"Policy based routing\n"
|
|
"Policy based routing table\n"
|
|
"Table range\n"
|
|
"Initial value of range\n"
|
|
"Final value of range\n")
|
|
{
|
|
if (no)
|
|
pbr_nht_set_tableid_range(PBR_NHT_DEFAULT_LOW_TABLEID,
|
|
PBR_NHT_DEFAULT_HIGH_TABLEID);
|
|
else
|
|
pbr_nht_set_tableid_range(start, end);
|
|
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
DEFPY (pbr_rule_range,
|
|
pbr_rule_range_cmd,
|
|
"[no] pbr rule range (300-1300)$start (400-1400)$end",
|
|
NO_STR
|
|
"Policy based routing\n"
|
|
"Policy based routing rule\n"
|
|
"Rule range\n"
|
|
"Initial value of range\n"
|
|
"Final value of range\n")
|
|
{
|
|
if (no)
|
|
pbr_nht_set_rule_range(PBR_NHT_DEFAULT_LOW_RULE,
|
|
PBR_NHT_DEFAULT_HIGH_RULE);
|
|
else
|
|
pbr_nht_set_rule_range(start, end);
|
|
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
DEFPY (pbr_policy,
|
|
pbr_policy_cmd,
|
|
"[no] pbr-policy NAME$mapname",
|
|
NO_STR
|
|
"Policy to use\n"
|
|
"Name of the pbr-map to apply\n")
|
|
{
|
|
VTY_DECLVAR_CONTEXT(interface, ifp);
|
|
struct pbr_map *pbrm, *old_pbrm;
|
|
struct pbr_interface *pbr_ifp = ifp->info;
|
|
|
|
pbrm = pbrm_find(mapname);
|
|
|
|
if (no) {
|
|
if (strcmp(pbr_ifp->mapname, mapname) == 0) {
|
|
strcpy(pbr_ifp->mapname, "");
|
|
|
|
if (pbrm)
|
|
pbr_map_interface_delete(pbrm, ifp);
|
|
}
|
|
} else {
|
|
if (strcmp(pbr_ifp->mapname, "") == 0) {
|
|
strcpy(pbr_ifp->mapname, mapname);
|
|
|
|
if (pbrm)
|
|
pbr_map_add_interface(pbrm, ifp);
|
|
} else {
|
|
if (!(strcmp(pbr_ifp->mapname, mapname) == 0)) {
|
|
old_pbrm = pbrm_find(pbr_ifp->mapname);
|
|
if (old_pbrm)
|
|
pbr_map_interface_delete(old_pbrm, ifp);
|
|
strcpy(pbr_ifp->mapname, mapname);
|
|
if (pbrm)
|
|
pbr_map_add_interface(pbrm, ifp);
|
|
}
|
|
}
|
|
}
|
|
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
DEFPY (show_pbr,
|
|
show_pbr_cmd,
|
|
"show pbr [json$json]",
|
|
SHOW_STR
|
|
"Policy Based Routing\n"
|
|
JSON_STR)
|
|
{
|
|
pbr_nht_write_table_range(vty);
|
|
pbr_nht_write_rule_range(vty);
|
|
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
DEFPY (show_pbr_map,
|
|
show_pbr_map_cmd,
|
|
"show pbr map [NAME$name] [detail$detail] [json$json]",
|
|
SHOW_STR
|
|
"Policy Based Routing\n"
|
|
"PBR Map\n"
|
|
"PBR Map Name\n"
|
|
"Detailed information\n"
|
|
JSON_STR)
|
|
{
|
|
struct pbr_map_sequence *pbrms;
|
|
struct pbr_map *pbrm;
|
|
struct listnode *node;
|
|
char buf[PREFIX_STRLEN];
|
|
char rbuf[64];
|
|
|
|
RB_FOREACH (pbrm, pbr_map_entry_head, &pbr_maps) {
|
|
if (name && strcmp(name, pbrm->name) != 0)
|
|
continue;
|
|
|
|
vty_out(vty, " pbr-map %s valid: %d\n", pbrm->name,
|
|
pbrm->valid);
|
|
|
|
for (ALL_LIST_ELEMENTS_RO(pbrm->seqnumbers, node, pbrms)) {
|
|
if (pbrms->reason)
|
|
pbr_map_reason_string(pbrms->reason, rbuf,
|
|
sizeof(rbuf));
|
|
vty_out(vty,
|
|
" Seq: %u rule: %u Installed: %d(%u) Reason: %s\n",
|
|
pbrms->seqno, pbrms->ruleno, pbrms->installed,
|
|
pbrms->unique, pbrms->reason ? rbuf : "Valid");
|
|
|
|
if (pbrms->src)
|
|
vty_out(vty, "\tSRC Match: %s\n",
|
|
prefix2str(pbrms->src, buf,
|
|
sizeof(buf)));
|
|
if (pbrms->dst)
|
|
vty_out(vty, "\tDST Match: %s\n",
|
|
prefix2str(pbrms->dst, buf,
|
|
sizeof(buf)));
|
|
|
|
if (pbrms->nhgrp_name) {
|
|
vty_out(vty,
|
|
"\tNexthop-Group: %s(%u) Installed: %u(%d)\n",
|
|
pbrms->nhgrp_name,
|
|
pbr_nht_get_table(pbrms->nhgrp_name),
|
|
pbrms->nhs_installed,
|
|
pbr_nht_get_installed(
|
|
pbrms->nhgrp_name));
|
|
} else if (pbrms->nhg) {
|
|
vty_out(vty, " ");
|
|
nexthop_group_write_nexthop(
|
|
vty, pbrms->nhg->nexthop);
|
|
vty_out(vty,
|
|
"\tInstalled: %u(%d) Tableid: %d\n",
|
|
pbrms->nhs_installed,
|
|
pbr_nht_get_installed(
|
|
pbrms->internal_nhg_name),
|
|
pbr_nht_get_table(
|
|
pbrms->internal_nhg_name));
|
|
} else {
|
|
vty_out(vty,
|
|
"\tNexthop-Group: Unknown Installed: 0(0)\n");
|
|
}
|
|
}
|
|
}
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
DEFPY(show_pbr_nexthop_group,
|
|
show_pbr_nexthop_group_cmd,
|
|
"show pbr nexthop-groups [WORD$word]",
|
|
SHOW_STR
|
|
"Policy Based Routing\n"
|
|
"Nexthop Groups\n"
|
|
"Optional Name of the nexthop group\n")
|
|
{
|
|
pbr_nht_show_nexthop_group(vty, word);
|
|
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
DEFPY (show_pbr_interface,
|
|
show_pbr_interface_cmd,
|
|
"show pbr interface [NAME$name] [json$json]",
|
|
SHOW_STR
|
|
"Policy Based Routing\n"
|
|
"PBR Interface\n"
|
|
"PBR Interface Name\n"
|
|
JSON_STR)
|
|
{
|
|
struct interface *ifp;
|
|
struct vrf *vrf;
|
|
struct pbr_interface *pbr_ifp;
|
|
|
|
RB_FOREACH(vrf, vrf_name_head, &vrfs_by_name) {
|
|
FOR_ALL_INTERFACES(vrf, ifp) {
|
|
struct pbr_map *pbrm;
|
|
|
|
if (name && strcmp(ifp->name, name) != 0)
|
|
continue;
|
|
|
|
pbr_ifp = ifp->info;
|
|
|
|
if (strcmp(pbr_ifp->mapname, "") == 0)
|
|
continue;
|
|
|
|
pbrm = pbrm_find(pbr_ifp->mapname);
|
|
vty_out(vty, " %s(%d) with pbr-policy %s", ifp->name,
|
|
ifp->ifindex, pbr_ifp->mapname);
|
|
if (!pbrm)
|
|
vty_out(vty, " (map doesn't exist)");
|
|
vty_out(vty, "\n");
|
|
}
|
|
}
|
|
|
|
return CMD_SUCCESS;
|
|
}
|
|
|
|
static struct cmd_node interface_node = {
|
|
INTERFACE_NODE, "%s(config-if)# ", 1 /* vtysh ? yes */
|
|
};
|
|
|
|
static int pbr_interface_config_write(struct vty *vty)
|
|
{
|
|
struct interface *ifp;
|
|
struct vrf *vrf;
|
|
|
|
RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
|
|
FOR_ALL_INTERFACES (vrf, ifp) {
|
|
if (vrf->vrf_id == VRF_DEFAULT)
|
|
vty_frame(vty, "interface %s\n", ifp->name);
|
|
else
|
|
vty_frame(vty, "interface %s vrf %s\n",
|
|
ifp->name, vrf->name);
|
|
|
|
pbr_map_write_interfaces(vty, ifp);
|
|
|
|
vty_endframe(vty, "!\n");
|
|
}
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
/* PBR map node structure. */
|
|
static struct cmd_node pbr_map_node = {PBRMAP_NODE, "%s(config-pbr-map)# ", 1};
|
|
|
|
static int pbr_vty_map_config_write_sequence(struct vty *vty,
|
|
struct pbr_map *pbrm,
|
|
struct pbr_map_sequence *pbrms)
|
|
{
|
|
char buff[PREFIX_STRLEN];
|
|
|
|
vty_out (vty, "pbr-map %s seq %u\n",
|
|
pbrm->name, pbrms->seqno);
|
|
|
|
if (pbrms->src)
|
|
vty_out(vty, " match src-ip %s\n",
|
|
prefix2str(pbrms->src, buff, sizeof buff));
|
|
|
|
if (pbrms->dst)
|
|
vty_out(vty, " match dst-ip %s\n",
|
|
prefix2str(pbrms->dst, buff, sizeof buff));
|
|
|
|
if (pbrms->nhgrp_name)
|
|
vty_out(vty, " set nexthop-group %s\n", pbrms->nhgrp_name);
|
|
|
|
if (pbrms->nhg) {
|
|
vty_out(vty, " set");
|
|
nexthop_group_write_nexthop(vty, pbrms->nhg->nexthop);
|
|
}
|
|
|
|
vty_out (vty, "!\n");
|
|
return 1;
|
|
}
|
|
|
|
static int pbr_vty_map_config_write(struct vty *vty)
|
|
{
|
|
struct pbr_map *pbrm;
|
|
|
|
pbr_nht_write_table_range(vty);
|
|
pbr_nht_write_rule_range(vty);
|
|
|
|
RB_FOREACH(pbrm, pbr_map_entry_head, &pbr_maps) {
|
|
struct pbr_map_sequence *pbrms;
|
|
struct listnode *node;
|
|
|
|
for (ALL_LIST_ELEMENTS_RO(pbrm->seqnumbers, node, pbrms)) {
|
|
pbr_vty_map_config_write_sequence(vty, pbrm, pbrms);
|
|
}
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
void pbr_vty_init(void)
|
|
{
|
|
install_node(&interface_node,
|
|
pbr_interface_config_write);
|
|
if_cmd_init();
|
|
|
|
install_node(&pbr_map_node,
|
|
pbr_vty_map_config_write);
|
|
|
|
install_default(PBRMAP_NODE);
|
|
|
|
install_element(CONFIG_NODE, &pbr_map_cmd);
|
|
install_element(CONFIG_NODE, &no_pbr_map_cmd);
|
|
install_element(INTERFACE_NODE, &pbr_policy_cmd);
|
|
install_element(CONFIG_NODE, &pbr_table_range_cmd);
|
|
install_element(CONFIG_NODE, &pbr_rule_range_cmd);
|
|
install_element(PBRMAP_NODE, &pbr_map_match_src_cmd);
|
|
install_element(PBRMAP_NODE, &pbr_map_match_dst_cmd);
|
|
install_element(PBRMAP_NODE, &pbr_map_nexthop_group_cmd);
|
|
install_element(PBRMAP_NODE, &pbr_map_nexthop_cmd);
|
|
install_element(VIEW_NODE, &show_pbr_cmd);
|
|
install_element(VIEW_NODE, &show_pbr_map_cmd);
|
|
install_element(VIEW_NODE, &show_pbr_interface_cmd);
|
|
install_element(VIEW_NODE, &show_pbr_nexthop_group_cmd);
|
|
|
|
pbr_debug_init_vty();
|
|
|
|
return;
|
|
}
|