mirror of
https://github.com/FRRouting/frr.git
synced 2025-04-30 13:37:17 +02:00
pbrd: Add PBR to FRR
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>
This commit is contained in:
parent
52483fa6ff
commit
e5c83d9b31
|
@ -56,6 +56,7 @@ include babeld/subdir.am
|
|||
include eigrpd/subdir.am
|
||||
include sharpd/subdir.am
|
||||
include pimd/subdir.am
|
||||
include pbrd/subdir.am
|
||||
|
||||
SUBDIRS = . @LIBRFP@ @RFPTEST@ \
|
||||
@BGPD@ \
|
||||
|
|
|
@ -1377,6 +1377,7 @@ AM_CONDITIONAL(BABELD, test "${enable_babeld}" != "no")
|
|||
AM_CONDITIONAL(OSPF6D, test "${enable_ospf6d}" != "no")
|
||||
AM_CONDITIONAL(ISISD, test "${enable_isisd}" != "no")
|
||||
AM_CONDITIONAL(PIMD, test "${enable_pimd}" != "no")
|
||||
AM_CONDITIONAL(PBRD, test "${enable_pbrd}" != "no")
|
||||
|
||||
if test "${enable_bgp_announce}" = "no";then
|
||||
AC_DEFINE(DISABLE_BGP_ANNOUNCE,1,Disable BGP installation to zebra)
|
||||
|
|
|
@ -105,6 +105,7 @@ const char *node_names[] = {
|
|||
"as list", // AS_LIST_NODE,
|
||||
"community list", // COMMUNITY_LIST_NODE,
|
||||
"routemap", // RMAP_NODE,
|
||||
"pbr-map", // PBRMAP_NODE,
|
||||
"smux", // SMUX_NODE,
|
||||
"dump", // DUMP_NODE,
|
||||
"forwarding", // FORWARDING_NODE,
|
||||
|
@ -1312,6 +1313,7 @@ void cmd_exit(struct vty *vty)
|
|||
case ISIS_NODE:
|
||||
case KEYCHAIN_NODE:
|
||||
case RMAP_NODE:
|
||||
case PBRMAP_NODE:
|
||||
case VTY_NODE:
|
||||
vty->node = CONFIG_NODE;
|
||||
break;
|
||||
|
@ -1409,6 +1411,7 @@ DEFUN (config_end,
|
|||
case BGP_EVPN_VNI_NODE:
|
||||
case BGP_IPV6L_NODE:
|
||||
case RMAP_NODE:
|
||||
case PBRMAP_NODE:
|
||||
case OSPF_NODE:
|
||||
case OSPF6_NODE:
|
||||
case LDP_NODE:
|
||||
|
|
|
@ -128,6 +128,7 @@ enum node_type {
|
|||
AS_LIST_NODE, /* AS list node. */
|
||||
COMMUNITY_LIST_NODE, /* Community list node. */
|
||||
RMAP_NODE, /* Route map node. */
|
||||
PBRMAP_NODE, /* PBR map node. */
|
||||
SMUX_NODE, /* SNMP configuration node. */
|
||||
DUMP_NODE, /* Packet dump node. */
|
||||
FORWARDING_NODE, /* IP forwarding node. */
|
||||
|
|
|
@ -78,6 +78,7 @@ ZEBRA_ROUTE_BGP_DIRECT, bgp-direct, NULL, 'b', 0, 0, "BGP-Direct"
|
|||
ZEBRA_ROUTE_BGP_DIRECT_EXT, bgp-direct-to-nve-groups, NULL, 'e', 0, 0, "BGP2VNC"
|
||||
ZEBRA_ROUTE_BABEL, babel, babeld, 'A', 1, 1, "Babel"
|
||||
ZEBRA_ROUTE_SHARP, sharp, sharpd, 'D', 1, 1, "SHARP"
|
||||
ZEBRA_ROUTE_PBR, pbr, pbrd, 'F', 1, 1, "PBR"
|
||||
ZEBRA_ROUTE_ALL, wildcard, none, '-', 0, 0, "-"
|
||||
|
||||
|
||||
|
@ -103,3 +104,4 @@ ZEBRA_ROUTE_LDP, "Label Distribution Protocol (LDP)"
|
|||
ZEBRA_ROUTE_VNC_DIRECT, "VNC direct (not via zebra) routes"
|
||||
ZEBRA_ROUTE_BABEL, "Babel routing protocol (Babel)"
|
||||
ZEBRA_ROUTE_SHARP, "Super Happy Advanced Routing Protocol (sharpd)"
|
||||
ZEBRA_ROUTE_PBR, "Policy Based Routing (PBR)"
|
||||
|
|
|
@ -719,6 +719,7 @@ static void vty_end_config(struct vty *vty)
|
|||
case BGP_EVPN_NODE:
|
||||
case BGP_IPV6L_NODE:
|
||||
case RMAP_NODE:
|
||||
case PBRMAP_NODE:
|
||||
case OSPF_NODE:
|
||||
case OSPF6_NODE:
|
||||
case LDP_NODE:
|
||||
|
@ -1115,6 +1116,7 @@ static void vty_stop_input(struct vty *vty)
|
|||
case EIGRP_NODE:
|
||||
case BGP_NODE:
|
||||
case RMAP_NODE:
|
||||
case PBRMAP_NODE:
|
||||
case OSPF_NODE:
|
||||
case OSPF6_NODE:
|
||||
case LDP_NODE:
|
||||
|
|
15
pbrd/.gitignore
vendored
Normal file
15
pbrd/.gitignore
vendored
Normal file
|
@ -0,0 +1,15 @@
|
|||
!Makefile
|
||||
Makefile.in
|
||||
libpbr.a
|
||||
pbrd
|
||||
tags
|
||||
TAGS
|
||||
.deps
|
||||
*.o
|
||||
*.lo
|
||||
*.la
|
||||
*.libs
|
||||
.arch-inventory
|
||||
.arch-ids
|
||||
*~
|
||||
*.loT
|
10
pbrd/Makefile
Normal file
10
pbrd/Makefile
Normal file
|
@ -0,0 +1,10 @@
|
|||
all: ALWAYS
|
||||
@$(MAKE) -s -C .. pbrd/pbrd
|
||||
%: ALWAYS
|
||||
@$(MAKE) -s -C .. pbrd/$@
|
||||
|
||||
Makefile:
|
||||
#nothing
|
||||
ALWAYS:
|
||||
.PHONY: ALWAYS makefiles
|
||||
.SUFFIXES:
|
171
pbrd/pbr_debug.c
Normal file
171
pbrd/pbr_debug.c
Normal file
|
@ -0,0 +1,171 @@
|
|||
/*
|
||||
* PBR - debugging
|
||||
* Copyright (C) 2018 Cumulus Networks, Inc.
|
||||
* Quentin Young
|
||||
*
|
||||
* This program 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 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program 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 "debug.h"
|
||||
#include "command.h"
|
||||
#include "vector.h"
|
||||
|
||||
#ifndef VTYSH_EXTRACT_PL
|
||||
#include "pbrd/pbr_debug_clippy.c"
|
||||
#endif
|
||||
#include "pbrd/pbr_debug.h"
|
||||
|
||||
struct debug pbr_dbg_map = {0, "PBR map"};
|
||||
struct debug pbr_dbg_zebra = {0, "PBR Zebra communications"};
|
||||
struct debug pbr_dbg_nht = {0, "PBR nexthop tracking"};
|
||||
struct debug pbr_dbg_event = {0, "PBR events"};
|
||||
|
||||
struct debug *pbr_debugs[] = {&pbr_dbg_map, &pbr_dbg_zebra, &pbr_dbg_nht,
|
||||
&pbr_dbg_event};
|
||||
|
||||
const char *pbr_debugs_conflines[] = {
|
||||
"debug pbr map",
|
||||
"debug pbr zebra",
|
||||
"debug pbr nht",
|
||||
"debug pbr events",
|
||||
};
|
||||
|
||||
/*
|
||||
* Set or unset flags on all debugs for pbrd.
|
||||
*
|
||||
* flags
|
||||
* The flags to set
|
||||
*
|
||||
* set
|
||||
* Whether to set or unset the specified flags
|
||||
*/
|
||||
static void pbr_debug_set_all(uint32_t flags, bool set)
|
||||
{
|
||||
for (unsigned int i = 0; i < array_size(pbr_debugs); i++) {
|
||||
DEBUG_FLAGS_SET(pbr_debugs[i], flags, set);
|
||||
|
||||
/* if all modes have been turned off, don't preserve options */
|
||||
if (!DEBUG_MODE_CHECK(pbr_debugs[i], DEBUG_MODE_ALL))
|
||||
DEBUG_CLEAR(pbr_debugs[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Check flags on all debugs for pbrd.
|
||||
*
|
||||
* flags
|
||||
* The flags to set
|
||||
*
|
||||
* Returns:
|
||||
* The subset of the given flags that were set in all pbrd debugs
|
||||
*/
|
||||
static uint32_t pbr_debug_check_all(uint32_t flags)
|
||||
{
|
||||
uint32_t mode = DEBUG_MODE_ALL;
|
||||
for (unsigned int i = 0; i < array_size(pbr_debugs); i++)
|
||||
mode &= DEBUG_MODE_CHECK(pbr_debugs[i], flags);
|
||||
return mode;
|
||||
}
|
||||
|
||||
static int pbr_debug_config_write_helper(struct vty *vty, bool config)
|
||||
{
|
||||
uint32_t mode = DEBUG_MODE_ALL;
|
||||
|
||||
if (config)
|
||||
mode = DEBUG_MODE_CONF;
|
||||
|
||||
if (pbr_debug_check_all(DEBUG_MODE_CONF) == mode) {
|
||||
vty_out(vty, "debug pbr\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i < array_size(pbr_debugs); i++)
|
||||
if (DEBUG_MODE_CHECK(pbr_debugs[i], mode))
|
||||
vty_out(vty, "%s\n", pbr_debugs_conflines[i]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pbr_debug_config_write(struct vty *vty)
|
||||
{
|
||||
return pbr_debug_config_write_helper(vty, true);
|
||||
}
|
||||
|
||||
/* PBR debugging CLI ------------------------------------------------------- */
|
||||
/* clang-format off */
|
||||
|
||||
DEFPY(debug_pbr,
|
||||
debug_pbr_cmd,
|
||||
"[no] debug pbr [{map$map|zebra$zebra|nht$nht|events$events}]",
|
||||
NO_STR
|
||||
DEBUG_STR
|
||||
"Policy Based Routing\n"
|
||||
"Policy maps\n"
|
||||
"PBRD <-> Zebra communications\n"
|
||||
"Nexthop tracking\n"
|
||||
"Events\n")
|
||||
{
|
||||
uint32_t mode = DEBUG_NODE2MODE(vty->node);
|
||||
if (map)
|
||||
DEBUG_MODE_SET(&pbr_dbg_map, mode, !no);
|
||||
if (zebra)
|
||||
DEBUG_MODE_SET(&pbr_dbg_zebra, mode, !no);
|
||||
if (nht)
|
||||
DEBUG_MODE_SET(&pbr_dbg_nht, mode, !no);
|
||||
if (events)
|
||||
DEBUG_MODE_SET(&pbr_dbg_event, mode, !no);
|
||||
|
||||
/* no specific debug --> act on all of them */
|
||||
if (strmatch(argv[argc - 1]->text, "pbr"))
|
||||
pbr_debug_set_all(mode, !no);
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN_NOSH(show_debugging_pbr,
|
||||
show_debugging_pbr_cmd,
|
||||
"show debugging [pbr]",
|
||||
SHOW_STR
|
||||
DEBUG_STR
|
||||
"Policy Based Routing\n")
|
||||
{
|
||||
vty_out(vty, "PBR debugging status:\n");
|
||||
|
||||
pbr_debug_config_write_helper(vty, false);
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
/* clang-format on */
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
static struct cmd_node debug_node = {DEBUG_NODE, "", 1};
|
||||
|
||||
struct debug_callbacks pbr_dbg_cbs = {.debug_set_all = pbr_debug_set_all};
|
||||
|
||||
void pbr_debug_init(void)
|
||||
{
|
||||
debug_init(&pbr_dbg_cbs);
|
||||
}
|
||||
|
||||
void pbr_debug_init_vty(void)
|
||||
{
|
||||
install_node(&debug_node, pbr_debug_config_write);
|
||||
|
||||
install_element(VIEW_NODE, &debug_pbr_cmd);
|
||||
install_element(CONFIG_NODE, &debug_pbr_cmd);
|
||||
|
||||
install_element(VIEW_NODE, &show_debugging_pbr_cmd);
|
||||
}
|
53
pbrd/pbr_debug.h
Normal file
53
pbrd/pbr_debug.h
Normal file
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* PBR - debugging
|
||||
* Copyright (C) 2018 Cumulus Networks, Inc.
|
||||
* Quentin Young
|
||||
*
|
||||
* This program 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 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program 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
|
||||
*/
|
||||
#ifndef __PBR_DEBUG_H__
|
||||
#define __PBR_DEBUG_H__
|
||||
|
||||
#include <zebra.h>
|
||||
|
||||
#include "debug.h"
|
||||
|
||||
/* PBR debugging records */
|
||||
extern struct debug pbr_dbg_map;
|
||||
extern struct debug pbr_dbg_zebra;
|
||||
extern struct debug pbr_dbg_nht;
|
||||
extern struct debug pbr_dbg_event;
|
||||
|
||||
/*
|
||||
* Initialize PBR debugging.
|
||||
*
|
||||
* Installs VTY commands and registers callbacks.
|
||||
*/
|
||||
void pbr_debug_init(void);
|
||||
|
||||
/*
|
||||
* Install PBR debugging VTY commands.
|
||||
*/
|
||||
void pbr_debug_init_vty(void);
|
||||
|
||||
/*
|
||||
* Print PBR debugging configuration.
|
||||
*
|
||||
* vty
|
||||
* VTY to print debugging configuration to.
|
||||
*/
|
||||
int pbr_debug_config_write(struct vty *vty);
|
||||
|
||||
#endif /* __PBR_DEBUG_H__ */
|
219
pbrd/pbr_event.c
Normal file
219
pbrd/pbr_event.c
Normal file
|
@ -0,0 +1,219 @@
|
|||
/*
|
||||
* PBR-event Code
|
||||
* Copyright (C) 2018 Cumulus Networks, Inc.
|
||||
* Donald Sharp
|
||||
*
|
||||
* This file is part of FRR.
|
||||
*
|
||||
* 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 <thread.h>
|
||||
#include <workqueue.h>
|
||||
#include <nexthop.h>
|
||||
#include <log.h>
|
||||
#include <vty.h>
|
||||
|
||||
#include "pbrd/pbr_event.h"
|
||||
#include "pbrd/pbr_map.h"
|
||||
#include "pbrd/pbr_nht.h"
|
||||
#include "pbrd/pbr_memory.h"
|
||||
#include "pbrd/pbr_debug.h"
|
||||
|
||||
DEFINE_MTYPE_STATIC(PBRD, PBR_EVENT, "Event WorkQueue")
|
||||
|
||||
struct work_queue *pbr_event_wq;
|
||||
|
||||
static const char *pbr_event_wqentry2str(struct pbr_event *pbre,
|
||||
char *buffer, size_t buflen)
|
||||
{
|
||||
switch(pbre->event) {
|
||||
case PBR_NHG_NEW:
|
||||
snprintf(buffer, buflen, "Nexthop Group Added %s",
|
||||
pbre->name);
|
||||
break;
|
||||
case PBR_NHG_ADD_NEXTHOP:
|
||||
snprintf(buffer, buflen, "Nexthop Group Nexthop Added %s",
|
||||
pbre->name);
|
||||
break;
|
||||
case PBR_NHG_DEL_NEXTHOP:
|
||||
snprintf(buffer, buflen, "Nexthop Group Nexthop Deleted %s",
|
||||
pbre->name);
|
||||
break;
|
||||
case PBR_NHG_DELETE:
|
||||
snprintf(buffer, buflen, "Nexthop Group Deleted %s",
|
||||
pbre->name);
|
||||
break;
|
||||
case PBR_MAP_NEXTHOP_ADD:
|
||||
snprintf(buffer, buflen, "Nexthop Added to %s(%d)", pbre->name,
|
||||
pbre->seqno);
|
||||
break;
|
||||
case PBR_MAP_NEXTHOP_DELETE:
|
||||
snprintf(buffer, buflen, "Nexthop Deleted from %s(%d)",
|
||||
pbre->name, pbre->seqno);
|
||||
break;
|
||||
case PBR_MAP_NHG_ADD:
|
||||
snprintf(buffer, buflen, "Nexthop Group Added to %s(%d)",
|
||||
pbre->name, pbre->seqno);
|
||||
break;
|
||||
case PBR_MAP_NHG_DELETE:
|
||||
snprintf(buffer, buflen, "Nexthop Group Deleted from %s(%d)",
|
||||
pbre->name, pbre->seqno);
|
||||
break;
|
||||
case PBR_MAP_ADD:
|
||||
snprintf(buffer, buflen, "PBR-MAP %s Added",
|
||||
pbre->name);
|
||||
break;
|
||||
case PBR_MAP_MODIFY:
|
||||
snprintf(buffer, buflen, "PBR_MAP %s Modified",
|
||||
pbre->name);
|
||||
break;
|
||||
case PBR_MAP_DELETE:
|
||||
snprintf(buffer, buflen, "PBR_MAP %s Deleted",
|
||||
pbre->name);
|
||||
break;
|
||||
case PBR_NH_CHANGED:
|
||||
snprintf(buffer, buflen, "Nexthop Call back from Zebra");
|
||||
break;
|
||||
case PBR_MAP_INSTALL:
|
||||
snprintf(buffer, buflen, "PBR_MAP %s Installing into zapi",
|
||||
pbre->name);
|
||||
break;
|
||||
case PBR_POLICY_CHANGED:
|
||||
snprintf(buffer, buflen,
|
||||
"PBR-Policy %s applied to an interface", pbre->name);
|
||||
break;
|
||||
case PBR_MAP_POLICY_INSTALL:
|
||||
snprintf(buffer, buflen, "PBR-POLICY installation time for %s",
|
||||
pbre->name);
|
||||
break;
|
||||
case PBR_POLICY_DELETED:
|
||||
snprintf(buffer, buflen, "PBR-POLICY deleted from %s",
|
||||
pbre->name);
|
||||
break;
|
||||
}
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
void pbr_event_free(struct pbr_event **pbre)
|
||||
{
|
||||
XFREE(MTYPE_PBR_EVENT, *pbre);
|
||||
}
|
||||
|
||||
static void pbr_event_delete_wq(struct work_queue *wq, void *data)
|
||||
{
|
||||
struct pbr_event *pbre = (struct pbr_event *)data;
|
||||
|
||||
XFREE(MTYPE_PBR_EVENT, pbre);
|
||||
}
|
||||
|
||||
static wq_item_status pbr_event_process_wq(struct work_queue *wq, void *data)
|
||||
{
|
||||
struct pbr_event *pbre = (struct pbr_event *)data;
|
||||
char buffer[256];
|
||||
|
||||
DEBUGD(&pbr_dbg_event, "%s: Handling event %s", __PRETTY_FUNCTION__,
|
||||
pbr_event_wqentry2str(pbre, buffer, sizeof(buffer)));
|
||||
|
||||
switch (pbre->event) {
|
||||
case PBR_NHG_NEW:
|
||||
pbr_nht_add_group(pbre->name);
|
||||
pbr_map_check_nh_group_change(pbre->name);
|
||||
break;
|
||||
case PBR_NHG_ADD_NEXTHOP:
|
||||
pbr_nht_change_group(pbre->name);
|
||||
pbr_map_check_nh_group_change(pbre->name);
|
||||
break;
|
||||
case PBR_NHG_DEL_NEXTHOP:
|
||||
pbr_nht_change_group(pbre->name);
|
||||
pbr_map_check_nh_group_change(pbre->name);
|
||||
break;
|
||||
case PBR_NHG_DELETE:
|
||||
pbr_nht_delete_group(pbre->name);
|
||||
pbr_map_check_nh_group_change(pbre->name);
|
||||
break;
|
||||
case PBR_MAP_NEXTHOP_ADD:
|
||||
pbr_nht_add_individual_nexthop(pbre->name, pbre->seqno);
|
||||
pbr_map_check(pbre->name, pbre->seqno);
|
||||
break;
|
||||
case PBR_MAP_NEXTHOP_DELETE:
|
||||
pbr_nht_delete_individual_nexthop(pbre->name, pbre->seqno);
|
||||
pbr_map_check(pbre->name, pbre->seqno);
|
||||
break;
|
||||
case PBR_MAP_NHG_ADD:
|
||||
pbr_map_check(pbre->name, pbre->seqno);
|
||||
break;
|
||||
case PBR_MAP_NHG_DELETE:
|
||||
pbr_map_check(pbre->name, pbre->seqno);
|
||||
break;
|
||||
case PBR_MAP_ADD:
|
||||
pbr_map_add_interfaces(pbre->name);
|
||||
break;
|
||||
case PBR_MAP_MODIFY:
|
||||
pbr_map_check(pbre->name, pbre->seqno);
|
||||
break;
|
||||
case PBR_MAP_DELETE:
|
||||
pbr_map_delete(pbre->name, pbre->seqno);
|
||||
break;
|
||||
case PBR_NH_CHANGED:
|
||||
pbr_map_check_nh_group_change(pbre->name);
|
||||
break;
|
||||
case PBR_MAP_INSTALL:
|
||||
pbr_map_install(pbre->name);
|
||||
break;
|
||||
case PBR_POLICY_CHANGED:
|
||||
pbr_map_check_policy_change(pbre->name);
|
||||
break;
|
||||
case PBR_MAP_POLICY_INSTALL:
|
||||
pbr_map_policy_install(pbre->name);
|
||||
break;
|
||||
case PBR_POLICY_DELETED:
|
||||
pbr_map_policy_delete(pbre->name);
|
||||
break;
|
||||
}
|
||||
|
||||
return WQ_SUCCESS;
|
||||
}
|
||||
|
||||
void pbr_event_enqueue(struct pbr_event *pbre)
|
||||
{
|
||||
work_queue_add(pbr_event_wq, pbre);
|
||||
}
|
||||
|
||||
struct pbr_event *pbr_event_new(enum pbr_events ev, const char *name)
|
||||
{
|
||||
struct pbr_event *event;
|
||||
event = XCALLOC(MTYPE_PBR_EVENT, sizeof(struct pbr_event));
|
||||
event->event = ev;
|
||||
if (name)
|
||||
strlcpy(event->name, name, sizeof(event->name));
|
||||
return event;
|
||||
}
|
||||
|
||||
extern struct thread_master *master;
|
||||
|
||||
void pbr_event_init(void)
|
||||
{
|
||||
pbr_event_wq = work_queue_new(master, "PBR Main Work Queue");
|
||||
pbr_event_wq->spec.workfunc = &pbr_event_process_wq;
|
||||
pbr_event_wq->spec.del_item_data = &pbr_event_delete_wq;
|
||||
}
|
||||
|
||||
void pbr_event_stop(void)
|
||||
{
|
||||
work_queue_free_and_null(&pbr_event_wq);
|
||||
}
|
137
pbrd/pbr_event.h
Normal file
137
pbrd/pbr_event.h
Normal file
|
@ -0,0 +1,137 @@
|
|||
/*
|
||||
* PBR-event Header
|
||||
* Copyright (C) 2018 Cumulus Networks, Inc.
|
||||
* Donald Sharp
|
||||
*
|
||||
* This file is part of FRR.
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
#ifndef __PBR_EVENT_H__
|
||||
#define __PBR_EVENT_H__
|
||||
|
||||
enum pbr_events {
|
||||
/*
|
||||
* A NHG has been added to the system, handle it
|
||||
*/
|
||||
PBR_NHG_NEW,
|
||||
|
||||
/*
|
||||
* A NHG has been modified( added a new nexthop )
|
||||
*/
|
||||
PBR_NHG_ADD_NEXTHOP,
|
||||
|
||||
/*
|
||||
* A NHG has been modified( deleted a nexthop )
|
||||
*/
|
||||
PBR_NHG_DEL_NEXTHOP,
|
||||
|
||||
/*
|
||||
* A NHG has been deleted from the system
|
||||
*/
|
||||
PBR_NHG_DELETE,
|
||||
|
||||
/*
|
||||
* A individual nexthop has been added
|
||||
*/
|
||||
PBR_MAP_NEXTHOP_ADD,
|
||||
|
||||
/*
|
||||
* A individual nexthop has been deleted
|
||||
*/
|
||||
PBR_MAP_NEXTHOP_DELETE,
|
||||
|
||||
/*
|
||||
* A nexthop group has been added to a pbr-map
|
||||
*/
|
||||
PBR_MAP_NHG_ADD,
|
||||
|
||||
/*
|
||||
* A nexthop group has been deleted from a pbr-map
|
||||
*/
|
||||
PBR_MAP_NHG_DELETE,
|
||||
|
||||
/*
|
||||
* A new pbr-map has been created
|
||||
*/
|
||||
PBR_MAP_ADD,
|
||||
|
||||
/*
|
||||
* The pbr-map has been modified in some fashion
|
||||
*/
|
||||
PBR_MAP_MODIFY,
|
||||
|
||||
/*
|
||||
* The pbr-map has been deleted from the system
|
||||
*/
|
||||
PBR_MAP_DELETE,
|
||||
|
||||
/*
|
||||
* Start the sequence of events to install/remove the policy
|
||||
* from being installed
|
||||
*/
|
||||
PBR_MAP_INSTALL,
|
||||
|
||||
/*
|
||||
* We believe we have gotten enough information to actually
|
||||
* install the rule portion, since the nexthops are installed
|
||||
*/
|
||||
PBR_MAP_POLICY_INSTALL,
|
||||
|
||||
/*
|
||||
* Callbacks for a Nexthop in a nexthop group has been
|
||||
* changed in some fashion
|
||||
*/
|
||||
PBR_NH_CHANGED,
|
||||
|
||||
/*
|
||||
* Callback for when a policy has been applied to an interface
|
||||
*/
|
||||
PBR_POLICY_CHANGED,
|
||||
|
||||
/*
|
||||
* Callback for when a interface has been issued a no
|
||||
* policy command
|
||||
*/
|
||||
PBR_POLICY_DELETED,
|
||||
};
|
||||
|
||||
struct pbr_event {
|
||||
enum pbr_events event;
|
||||
|
||||
char name[100];
|
||||
union g_addr addr;
|
||||
uint32_t seqno;
|
||||
};
|
||||
|
||||
/*
|
||||
* Return a event structure that can be filled in and enqueued.
|
||||
* Assume this memory is owned by the event subsystem.
|
||||
*/
|
||||
extern struct pbr_event *pbr_event_new(enum pbr_events ev, const char *name);
|
||||
|
||||
/*
|
||||
* Free the associated pbr_event item
|
||||
*/
|
||||
extern void pbr_event_free(struct pbr_event **pbre);
|
||||
|
||||
/*
|
||||
* Enqueue an event for later processing
|
||||
*/
|
||||
void pbr_event_enqueue(struct pbr_event *pbre);
|
||||
|
||||
extern void pbr_event_init(void);
|
||||
extern void pbr_event_stop(void);
|
||||
#endif
|
168
pbrd/pbr_main.c
Normal file
168
pbrd/pbr_main.c
Normal file
|
@ -0,0 +1,168 @@
|
|||
/*
|
||||
* PBR - main 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 <lib/version.h>
|
||||
#include "getopt.h"
|
||||
#include "thread.h"
|
||||
#include "prefix.h"
|
||||
#include "linklist.h"
|
||||
#include "if.h"
|
||||
#include "vector.h"
|
||||
#include "vty.h"
|
||||
#include "command.h"
|
||||
#include "filter.h"
|
||||
#include "plist.h"
|
||||
#include "stream.h"
|
||||
#include "log.h"
|
||||
#include "memory.h"
|
||||
#include "privs.h"
|
||||
#include "sigevent.h"
|
||||
#include "zclient.h"
|
||||
#include "keychain.h"
|
||||
#include "distribute.h"
|
||||
#include "libfrr.h"
|
||||
#include "routemap.h"
|
||||
#include "nexthop.h"
|
||||
#include "nexthop_group.h"
|
||||
|
||||
#include "pbr_nht.h"
|
||||
#include "pbr_map.h"
|
||||
#include "pbr_zebra.h"
|
||||
#include "pbr_event.h"
|
||||
#include "pbr_vty.h"
|
||||
#include "pbr_debug.h"
|
||||
|
||||
zebra_capabilities_t _caps_p[] = {
|
||||
ZCAP_NET_RAW, ZCAP_BIND, ZCAP_NET_ADMIN,
|
||||
};
|
||||
|
||||
struct zebra_privs_t pbr_privs = {
|
||||
#if defined(FRR_USER) && defined(FRR_GROUP)
|
||||
.user = FRR_USER,
|
||||
.group = FRR_GROUP,
|
||||
#endif
|
||||
#if defined(VTY_GROUP)
|
||||
.vty_group = VTY_GROUP,
|
||||
#endif
|
||||
.caps_p = _caps_p,
|
||||
.cap_num_p = array_size(_caps_p),
|
||||
.cap_num_i = 0};
|
||||
|
||||
struct option longopts[] = {{0}};
|
||||
|
||||
/* Master of threads. */
|
||||
struct thread_master *master;
|
||||
|
||||
/* SIGHUP handler. */
|
||||
static void sighup(void)
|
||||
{
|
||||
zlog_info("SIGHUP received");
|
||||
}
|
||||
|
||||
/* SIGINT / SIGTERM handler. */
|
||||
static void sigint(void)
|
||||
{
|
||||
zlog_notice("Terminating on signal");
|
||||
|
||||
pbr_event_stop();
|
||||
exit(0);
|
||||
}
|
||||
|
||||
/* SIGUSR1 handler. */
|
||||
static void sigusr1(void)
|
||||
{
|
||||
zlog_rotate();
|
||||
}
|
||||
|
||||
struct quagga_signal_t pbr_signals[] = {
|
||||
{
|
||||
.signal = SIGHUP,
|
||||
.handler = &sighup,
|
||||
},
|
||||
{
|
||||
.signal = SIGUSR1,
|
||||
.handler = &sigusr1,
|
||||
},
|
||||
{
|
||||
.signal = SIGINT,
|
||||
.handler = &sigint,
|
||||
},
|
||||
{
|
||||
.signal = SIGTERM,
|
||||
.handler = &sigint,
|
||||
},
|
||||
};
|
||||
|
||||
#define PBR_VTY_PORT 2615
|
||||
|
||||
FRR_DAEMON_INFO(pbrd, PBR, .vty_port = PBR_VTY_PORT,
|
||||
|
||||
.proghelp = "Implementation of PBR.",
|
||||
|
||||
.signals = pbr_signals,
|
||||
.n_signals = array_size(pbr_signals),
|
||||
|
||||
.privs = &pbr_privs, )
|
||||
|
||||
int main(int argc, char **argv, char **envp)
|
||||
{
|
||||
frr_preinit(&pbrd_di, argc, argv);
|
||||
frr_opt_add("", longopts, "");
|
||||
|
||||
while (1) {
|
||||
int opt;
|
||||
|
||||
opt = frr_getopt(argc, argv, NULL);
|
||||
|
||||
if (opt == EOF)
|
||||
break;
|
||||
|
||||
switch (opt) {
|
||||
case 0:
|
||||
break;
|
||||
default:
|
||||
frr_help_exit(1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
master = frr_init();
|
||||
|
||||
pbr_debug_init();
|
||||
|
||||
vrf_init(NULL, NULL, NULL, NULL);
|
||||
nexthop_group_init(pbr_nhgroup_add_cb,
|
||||
pbr_nhgroup_add_nexthop_cb,
|
||||
pbr_nhgroup_del_nexthop_cb,
|
||||
pbr_nhgroup_delete_cb);
|
||||
|
||||
pbr_event_init();
|
||||
pbr_nht_init();
|
||||
pbr_map_init();
|
||||
pbr_zebra_init();
|
||||
pbr_vty_init();
|
||||
|
||||
frr_config_fork();
|
||||
frr_run(master);
|
||||
|
||||
/* Not reached. */
|
||||
return 0;
|
||||
}
|
630
pbrd/pbr_map.c
Normal file
630
pbrd/pbr_map.c
Normal file
|
@ -0,0 +1,630 @@
|
|||
/*
|
||||
* PBR-map 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 "thread.h"
|
||||
#include "linklist.h"
|
||||
#include "prefix.h"
|
||||
#include "table.h"
|
||||
#include "vrf.h"
|
||||
#include "nexthop.h"
|
||||
#include "nexthop_group.h"
|
||||
#include "memory.h"
|
||||
#include "log.h"
|
||||
#include "vty.h"
|
||||
|
||||
#include "pbr_nht.h"
|
||||
#include "pbr_map.h"
|
||||
#include "pbr_event.h"
|
||||
#include "pbr_zebra.h"
|
||||
#include "pbr_memory.h"
|
||||
#include "pbr_debug.h"
|
||||
|
||||
DEFINE_MTYPE_STATIC(PBRD, PBR_MAP, "PBR Map")
|
||||
DEFINE_MTYPE_STATIC(PBRD, PBR_MAP_SEQNO, "PBR Map Sequence")
|
||||
DEFINE_MTYPE_STATIC(PBRD, PBR_MAP_INTERFACE, "PBR Map Interface")
|
||||
|
||||
static uint32_t pbr_map_sequence_unique;
|
||||
|
||||
static __inline int pbr_map_compare(const struct pbr_map *pbrmap1,
|
||||
const struct pbr_map *pbrmap2);
|
||||
|
||||
RB_GENERATE(pbr_map_entry_head, pbr_map, pbr_map_entry, pbr_map_compare)
|
||||
|
||||
struct pbr_map_entry_head pbr_maps = RB_INITIALIZER(&pbr_maps);
|
||||
|
||||
DEFINE_QOBJ_TYPE(pbr_map_sequence)
|
||||
|
||||
static __inline int pbr_map_compare(const struct pbr_map *pbrmap1,
|
||||
const struct pbr_map *pbrmap2)
|
||||
{
|
||||
return strcmp(pbrmap1->name, pbrmap2->name);
|
||||
}
|
||||
|
||||
static int pbr_map_sequence_compare(const struct pbr_map_sequence *pbrms1,
|
||||
const struct pbr_map_sequence *pbrms2)
|
||||
{
|
||||
if (pbrms1->seqno == pbrms2->seqno)
|
||||
return 0;
|
||||
|
||||
if (pbrms1->seqno < pbrms2->seqno)
|
||||
return -1;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void pbr_map_sequence_delete(struct pbr_map_sequence *pbrms)
|
||||
{
|
||||
if (pbrms->internal_nhg_name)
|
||||
XFREE(MTYPE_TMP, pbrms->internal_nhg_name);
|
||||
|
||||
XFREE(MTYPE_PBR_MAP_SEQNO, pbrms);
|
||||
}
|
||||
|
||||
static int pbr_map_interface_compare(const struct pbr_map_interface *pmi1,
|
||||
const struct pbr_map_interface *pmi2)
|
||||
{
|
||||
return strcmp(pmi1->ifp->name, pmi2->ifp->name);
|
||||
}
|
||||
|
||||
static void pbr_map_interface_list_delete(const struct pbr_map_interface *pmi)
|
||||
{
|
||||
pbr_map_policy_delete(pmi->ifp->name);
|
||||
}
|
||||
|
||||
static const char *pbr_map_reason_str[] = {
|
||||
"Invalid NH-group", "Invalid NH", "No Nexthops",
|
||||
"Both NH and NH-Group", "Invalid Src or Dst", "Deleting Sequence",
|
||||
};
|
||||
|
||||
void pbr_map_reason_string(unsigned int reason, char *buf, int size)
|
||||
{
|
||||
unsigned int bit;
|
||||
int len = 0;
|
||||
|
||||
if (!buf)
|
||||
return;
|
||||
|
||||
for (bit = 0; bit < array_size(pbr_map_reason_str); bit++) {
|
||||
if ((reason & (1 << bit)) && (len < size)) {
|
||||
len += snprintf((buf + len), (size - len), "%s%s",
|
||||
(len > 0) ? ", " : "",
|
||||
pbr_map_reason_str[bit]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void pbr_map_interface_delete(struct pbr_map *pbrm, struct interface *ifp_del)
|
||||
{
|
||||
|
||||
struct listnode *node;
|
||||
struct pbr_map_interface *pmi;
|
||||
struct pbr_event *pbre;
|
||||
|
||||
for (ALL_LIST_ELEMENTS_RO(pbrm->incoming, node, pmi)) {
|
||||
if (ifp_del == pmi->ifp)
|
||||
break;
|
||||
}
|
||||
|
||||
if (pmi) {
|
||||
pmi->delete = true;
|
||||
|
||||
pbre = pbr_event_new(PBR_POLICY_DELETED, pmi->ifp->name);
|
||||
pbr_event_enqueue(pbre);
|
||||
}
|
||||
}
|
||||
|
||||
void pbr_map_add_interface(struct pbr_map *pbrm, struct interface *ifp_add)
|
||||
{
|
||||
struct listnode *node;
|
||||
struct pbr_map_interface *pmi;
|
||||
struct pbr_event *pbre;
|
||||
|
||||
for (ALL_LIST_ELEMENTS_RO(pbrm->incoming, node, pmi)) {
|
||||
if (ifp_add == pmi->ifp)
|
||||
return;
|
||||
}
|
||||
|
||||
pmi = XCALLOC(MTYPE_PBR_MAP_INTERFACE, sizeof(*pmi));
|
||||
pmi->ifp = ifp_add;
|
||||
pmi->pbrm = pbrm;
|
||||
listnode_add_sort(pbrm->incoming, pmi);
|
||||
|
||||
pbre = pbr_event_new(PBR_POLICY_CHANGED, pbrm->name);
|
||||
pbr_event_enqueue(pbre);
|
||||
}
|
||||
|
||||
void pbr_map_write_interfaces(struct vty *vty, struct interface *ifp)
|
||||
{
|
||||
struct pbr_interface *pbr_ifp = ifp->info;
|
||||
|
||||
if (!(strcmp(pbr_ifp->mapname, "") == 0))
|
||||
vty_out(vty, " pbr-policy %s\n", pbr_ifp->mapname);
|
||||
}
|
||||
|
||||
struct pbr_map *pbrm_find(const char *name)
|
||||
{
|
||||
struct pbr_map pbrm;
|
||||
|
||||
strlcpy(pbrm.name, name, sizeof(pbrm.name));
|
||||
|
||||
return RB_FIND(pbr_map_entry_head, &pbr_maps, &pbrm);
|
||||
}
|
||||
|
||||
extern void pbr_map_delete(const char *name, uint32_t seqno)
|
||||
{
|
||||
struct pbr_map *pbrm;
|
||||
struct pbr_map_sequence *pbrms;
|
||||
struct listnode *node, *nnode;
|
||||
bool uninstall = false;
|
||||
|
||||
pbrm = pbrm_find(name);
|
||||
|
||||
for (ALL_LIST_ELEMENTS(pbrm->seqnumbers, node, nnode, pbrms)) {
|
||||
if (pbrms->reason & PBR_MAP_DEL_SEQUENCE_NUMBER) {
|
||||
uninstall = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (uninstall)
|
||||
pbr_send_pbr_map(pbrm, 0);
|
||||
|
||||
for (ALL_LIST_ELEMENTS(pbrm->seqnumbers, node, nnode, pbrms)) {
|
||||
if (!(pbrms->reason & PBR_MAP_DEL_SEQUENCE_NUMBER))
|
||||
continue;
|
||||
|
||||
if (pbrms->nhg)
|
||||
pbr_nht_delete_individual_nexthop(pbrms->parent->name,
|
||||
pbrms->seqno);
|
||||
|
||||
listnode_delete(pbrm->seqnumbers, pbrms);
|
||||
}
|
||||
|
||||
if (pbrm->seqnumbers->count == 0) {
|
||||
RB_REMOVE(pbr_map_entry_head, &pbr_maps, pbrm);
|
||||
XFREE(MTYPE_PBR_MAP, pbrm);
|
||||
}
|
||||
}
|
||||
|
||||
extern struct pbr_map_sequence *pbrms_lookup_unique(uint32_t unique,
|
||||
ifindex_t ifindex)
|
||||
{
|
||||
struct pbr_map_sequence *pbrms;
|
||||
struct listnode *snode, *inode;
|
||||
struct pbr_map_interface *pmi;
|
||||
struct pbr_map *pbrm;
|
||||
|
||||
RB_FOREACH (pbrm, pbr_map_entry_head, &pbr_maps) {
|
||||
for (ALL_LIST_ELEMENTS_RO(pbrm->incoming, inode, pmi)) {
|
||||
if (pmi->ifp->ifindex != ifindex)
|
||||
continue;
|
||||
|
||||
for (ALL_LIST_ELEMENTS_RO(pbrm->seqnumbers, snode,
|
||||
pbrms)) {
|
||||
DEBUGD(&pbr_dbg_map, "%s: Comparing %u to %u",
|
||||
__PRETTY_FUNCTION__, pbrms->unique,
|
||||
unique);
|
||||
if (pbrms->unique == unique)
|
||||
return pbrms;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
extern struct pbr_map_sequence *pbrms_get(const char *name, uint32_t seqno)
|
||||
{
|
||||
struct pbr_map *pbrm;
|
||||
struct pbr_map_sequence *pbrms;
|
||||
struct listnode *node;
|
||||
struct pbr_event *pbre;
|
||||
|
||||
pbrm = pbrm_find(name);
|
||||
if (!pbrm) {
|
||||
pbrm = XCALLOC(MTYPE_PBR_MAP, sizeof(*pbrm));
|
||||
strcpy(pbrm->name, name);
|
||||
|
||||
pbrm->seqnumbers = list_new();
|
||||
pbrm->seqnumbers->cmp =
|
||||
(int (*)(void *, void *))pbr_map_sequence_compare;
|
||||
pbrm->seqnumbers->del =
|
||||
(void (*)(void *))pbr_map_sequence_delete;
|
||||
|
||||
pbrm->incoming = list_new();
|
||||
pbrm->incoming->cmp =
|
||||
(int (*)(void *, void *))pbr_map_interface_compare;
|
||||
pbrm->incoming->del =
|
||||
(void (*)(void *))pbr_map_interface_list_delete;
|
||||
|
||||
RB_INSERT(pbr_map_entry_head, &pbr_maps, pbrm);
|
||||
|
||||
pbre = pbr_event_new(PBR_MAP_ADD, name);
|
||||
} else
|
||||
pbre = NULL;
|
||||
|
||||
for (ALL_LIST_ELEMENTS_RO(pbrm->seqnumbers, node, pbrms)) {
|
||||
if (pbrms->seqno == seqno)
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
if (!pbrms) {
|
||||
pbrms = XCALLOC(MTYPE_PBR_MAP_SEQNO, sizeof(*pbrms));
|
||||
pbrms->unique = pbr_map_sequence_unique++;
|
||||
pbrms->seqno = seqno;
|
||||
pbrms->ruleno = pbr_nht_get_next_rule(seqno);
|
||||
pbrms->parent = pbrm;
|
||||
pbrms->reason =
|
||||
PBR_MAP_INVALID_SRCDST |
|
||||
PBR_MAP_INVALID_NO_NEXTHOPS;
|
||||
|
||||
QOBJ_REG(pbrms, pbr_map_sequence);
|
||||
listnode_add_sort(pbrm->seqnumbers, pbrms);
|
||||
|
||||
pbrm->installed = false;
|
||||
}
|
||||
|
||||
if (pbre)
|
||||
pbr_event_enqueue(pbre);
|
||||
|
||||
return pbrms;
|
||||
}
|
||||
|
||||
static void
|
||||
pbr_map_sequence_check_nexthops_valid(struct pbr_map_sequence *pbrms)
|
||||
{
|
||||
/*
|
||||
* Check validness of the nexthop or nexthop-group
|
||||
*/
|
||||
if (!pbrms->nhg && !pbrms->nhgrp_name)
|
||||
pbrms->reason |= PBR_MAP_INVALID_NO_NEXTHOPS;
|
||||
|
||||
if (pbrms->nhg && pbrms->nhgrp_name)
|
||||
pbrms->reason |= PBR_MAP_INVALID_BOTH_NHANDGRP;
|
||||
|
||||
if (pbrms->nhg &&
|
||||
!pbr_nht_nexthop_group_valid(pbrms->internal_nhg_name))
|
||||
pbrms->reason |= PBR_MAP_INVALID_NEXTHOP;
|
||||
|
||||
if (pbrms->nhgrp_name) {
|
||||
if (!pbr_nht_nexthop_group_valid(pbrms->nhgrp_name))
|
||||
pbrms->reason |= PBR_MAP_INVALID_NEXTHOP_GROUP;
|
||||
else
|
||||
pbrms->nhs_installed = true;
|
||||
}
|
||||
}
|
||||
|
||||
static void pbr_map_sequence_check_src_dst_valid(struct pbr_map_sequence *pbrms)
|
||||
{
|
||||
if (!pbrms->src && !pbrms->dst)
|
||||
pbrms->reason |= PBR_MAP_INVALID_SRCDST;
|
||||
}
|
||||
|
||||
/*
|
||||
* Checks to see if we think that the pbmrs is valid. If we think
|
||||
* the config is valid return true.
|
||||
*/
|
||||
static void pbr_map_sequence_check_valid(struct pbr_map_sequence *pbrms)
|
||||
{
|
||||
pbr_map_sequence_check_nexthops_valid(pbrms);
|
||||
|
||||
pbr_map_sequence_check_src_dst_valid(pbrms);
|
||||
}
|
||||
|
||||
static bool pbr_map_check_valid_internal(struct pbr_map *pbrm)
|
||||
{
|
||||
struct pbr_map_sequence *pbrms;
|
||||
struct listnode *node;
|
||||
|
||||
pbrm->valid = true;
|
||||
for (ALL_LIST_ELEMENTS_RO(pbrm->seqnumbers, node, pbrms)) {
|
||||
pbrms->reason = 0;
|
||||
pbr_map_sequence_check_valid(pbrms);
|
||||
/*
|
||||
* A pbr_map_sequence that is invalid causes
|
||||
* the whole shebang to be invalid
|
||||
*/
|
||||
if (pbrms->reason != 0)
|
||||
pbrm->valid = false;
|
||||
}
|
||||
|
||||
return pbrm->valid;
|
||||
}
|
||||
|
||||
/*
|
||||
* For a given PBR-MAP check to see if we think it is a
|
||||
* valid config or not. If so note that it is and return
|
||||
* that we are valid.
|
||||
*/
|
||||
extern bool pbr_map_check_valid(const char *name)
|
||||
{
|
||||
struct pbr_map *pbrm;
|
||||
|
||||
pbrm = pbrm_find(name);
|
||||
if (!pbrm) {
|
||||
DEBUGD(&pbr_dbg_map,
|
||||
"%s: Specified PBR-MAP(%s) does not exist?",
|
||||
__PRETTY_FUNCTION__, name);
|
||||
return false;
|
||||
}
|
||||
|
||||
pbr_map_check_valid_internal(pbrm);
|
||||
return pbrm->valid;
|
||||
}
|
||||
|
||||
extern void pbr_map_schedule_policy_from_nhg(const char *nh_group)
|
||||
{
|
||||
struct pbr_map_sequence *pbrms;
|
||||
struct pbr_event *pbre;
|
||||
struct pbr_map *pbrm;
|
||||
struct listnode *node;
|
||||
|
||||
RB_FOREACH (pbrm, pbr_map_entry_head, &pbr_maps) {
|
||||
DEBUGD(&pbr_dbg_map, "%s: Looking at %s", __PRETTY_FUNCTION__,
|
||||
pbrm->name);
|
||||
for (ALL_LIST_ELEMENTS_RO(pbrm->seqnumbers, node, pbrms)) {
|
||||
DEBUGD(&pbr_dbg_map, "\tNH Grp name: %s",
|
||||
pbrms->nhgrp_name ? pbrms->nhgrp_name : "NULL");
|
||||
|
||||
if (pbrms->nhgrp_name
|
||||
&& (strcmp(nh_group, pbrms->nhgrp_name) == 0)) {
|
||||
pbrms->nhs_installed = true;
|
||||
|
||||
pbre = pbr_event_new(PBR_MAP_MODIFY,
|
||||
pbrm->name);
|
||||
pbre->seqno = pbrms->seqno;
|
||||
|
||||
pbr_event_enqueue(pbre);
|
||||
}
|
||||
|
||||
if (pbrms->nhg
|
||||
&& (strcmp(nh_group, pbrms->internal_nhg_name)
|
||||
== 0)) {
|
||||
pbrms->nhs_installed = true;
|
||||
|
||||
pbre = pbr_event_new(PBR_MAP_MODIFY,
|
||||
pbrm->name);
|
||||
pbre->seqno = pbrms->seqno;
|
||||
|
||||
pbr_event_enqueue(pbre);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extern void pbr_map_policy_install(const char *name)
|
||||
{
|
||||
struct pbr_map_sequence *pbrms;
|
||||
struct pbr_map *pbrm;
|
||||
struct listnode *node;
|
||||
bool install;
|
||||
|
||||
DEBUGD(&pbr_dbg_map, "%s: for %s", __PRETTY_FUNCTION__, name);
|
||||
pbrm = pbrm_find(name);
|
||||
if (!pbrm)
|
||||
return;
|
||||
|
||||
install = true;
|
||||
for (ALL_LIST_ELEMENTS_RO(pbrm->seqnumbers, node, pbrms)) {
|
||||
DEBUGD(&pbr_dbg_map,
|
||||
"%s: Looking at what to install %s(%u) %d %d",
|
||||
__PRETTY_FUNCTION__, name, pbrms->seqno, pbrm->valid,
|
||||
pbrms->nhs_installed);
|
||||
if (!pbrm->valid || !pbrms->nhs_installed)
|
||||
install = false;
|
||||
}
|
||||
|
||||
if (install && pbrm->incoming->count) {
|
||||
DEBUGD(&pbr_dbg_map, "\tInstalling");
|
||||
pbr_send_pbr_map(pbrm, true);
|
||||
}
|
||||
}
|
||||
|
||||
extern void pbr_map_policy_delete(const char *ifname)
|
||||
{
|
||||
struct listnode *node, *nnode;
|
||||
struct pbr_map_interface *pmi;
|
||||
struct pbr_map *pbrm;
|
||||
|
||||
RB_FOREACH (pbrm, pbr_map_entry_head, &pbr_maps) {
|
||||
for (ALL_LIST_ELEMENTS(pbrm->incoming, node, nnode, pmi)) {
|
||||
DEBUGD(&pbr_dbg_map, "Comparing %s to %s %d",
|
||||
pmi->ifp->name, ifname, pmi->delete);
|
||||
if (strcmp(ifname, pmi->ifp->name) != 0)
|
||||
continue;
|
||||
|
||||
pbr_send_pbr_map(pbrm, false);
|
||||
listnode_delete(pbrm->incoming, pmi);
|
||||
pmi->pbrm = NULL;
|
||||
XFREE(MTYPE_PBR_MAP_INTERFACE, pmi);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* For a nexthop group specified, see if any of the pbr-maps
|
||||
* are using it and if so, check to see that we are still
|
||||
* valid for usage. If we are valid then schedule the installation/deletion
|
||||
* of the pbr-policy.
|
||||
*/
|
||||
extern void pbr_map_check_nh_group_change(const char *nh_group)
|
||||
{
|
||||
struct pbr_map_sequence *pbrms;
|
||||
struct pbr_map *pbrm;
|
||||
struct listnode *node;
|
||||
bool found_name;
|
||||
|
||||
zlog_warn("*** %s for %s ***", __func__, nh_group);
|
||||
RB_FOREACH (pbrm, pbr_map_entry_head, &pbr_maps) {
|
||||
for (ALL_LIST_ELEMENTS_RO(pbrm->seqnumbers, node, pbrms)) {
|
||||
found_name = false;
|
||||
if (pbrms->nhgrp_name)
|
||||
found_name =
|
||||
!strcmp(nh_group, pbrms->nhgrp_name);
|
||||
else if (pbrms->nhg)
|
||||
found_name = !strcmp(nh_group,
|
||||
pbrms->internal_nhg_name);
|
||||
|
||||
if (found_name) {
|
||||
bool original = pbrm->valid;
|
||||
zlog_warn("*** %s pbrm->valid is %u ***",
|
||||
__func__, pbrm->valid);
|
||||
|
||||
pbr_map_check_valid_internal(pbrm);
|
||||
|
||||
if (original != pbrm->valid) {
|
||||
struct pbr_event *pbre;
|
||||
|
||||
pbre = pbr_event_new(PBR_MAP_INSTALL,
|
||||
pbrm->name);
|
||||
pbr_event_enqueue(pbre);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extern void pbr_map_check(const char *name, uint32_t seqno)
|
||||
{
|
||||
struct pbr_map_sequence *pbrms;
|
||||
struct listnode *node;
|
||||
struct pbr_map *pbrm;
|
||||
|
||||
DEBUGD(&pbr_dbg_map, "%s: for %s(%u)", __PRETTY_FUNCTION__, name,
|
||||
seqno);
|
||||
if (pbr_map_check_valid(name))
|
||||
DEBUGD(&pbr_dbg_map, "We are totally valid %s\n", name);
|
||||
|
||||
pbrm = pbrm_find(name);
|
||||
if (!pbrm)
|
||||
return;
|
||||
|
||||
for (ALL_LIST_ELEMENTS_RO(pbrm->seqnumbers, node, pbrms)) {
|
||||
if (seqno != pbrms->seqno)
|
||||
continue;
|
||||
|
||||
DEBUGD(&pbr_dbg_map, "%s: Installing %s(%u) reason: %" PRIu64,
|
||||
__PRETTY_FUNCTION__, name, seqno, pbrms->reason);
|
||||
|
||||
if (pbrms->reason == PBR_MAP_VALID_SEQUENCE_NUMBER) {
|
||||
struct pbr_event *pbre;
|
||||
|
||||
DEBUGD(&pbr_dbg_map,
|
||||
"%s: Installing %s(%u) reason: %" PRIu64,
|
||||
__PRETTY_FUNCTION__, name, seqno, pbrms->reason);
|
||||
DEBUGD(&pbr_dbg_map,
|
||||
"\tSending PBR_MAP_POLICY_INSTALL event");
|
||||
|
||||
pbre = pbr_event_new(PBR_MAP_POLICY_INSTALL,
|
||||
pbrm->name);
|
||||
pbre->event = PBR_MAP_POLICY_INSTALL;
|
||||
strcpy(pbre->name, pbrm->name);
|
||||
|
||||
pbr_event_enqueue(pbre);
|
||||
|
||||
break;
|
||||
} else {
|
||||
DEBUGD(&pbr_dbg_map,
|
||||
"%s: Removing %s(%u) reason: %" PRIu64,
|
||||
__PRETTY_FUNCTION__, name, seqno, pbrms->reason);
|
||||
pbr_send_pbr_map(pbrm, false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extern void pbr_map_install(const char *name)
|
||||
{
|
||||
struct pbr_map *pbrm;
|
||||
|
||||
pbrm = pbrm_find(name);
|
||||
if (!pbrm) {
|
||||
DEBUGD(&pbr_dbg_map,
|
||||
"%s: Specified PBR-MAP(%s) does not exist?",
|
||||
__PRETTY_FUNCTION__, name);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!pbrm->incoming->count)
|
||||
return;
|
||||
|
||||
pbr_send_pbr_map(pbrm, true);
|
||||
pbrm->installed = true;
|
||||
}
|
||||
|
||||
extern void pbr_map_add_interfaces(const char *name)
|
||||
{
|
||||
struct pbr_map *pbrm;
|
||||
struct interface *ifp;
|
||||
struct pbr_interface *pbr_ifp;
|
||||
struct vrf *vrf;
|
||||
|
||||
pbrm = pbrm_find(name);
|
||||
if (!pbrm) {
|
||||
DEBUGD(&pbr_dbg_map,
|
||||
"%s: Specified PBR-MAP(%s) does not exist?",
|
||||
__PRETTY_FUNCTION__, name);
|
||||
return;
|
||||
}
|
||||
|
||||
RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
|
||||
FOR_ALL_INTERFACES (vrf, ifp) {
|
||||
if (ifp->info) {
|
||||
pbr_ifp = ifp->info;
|
||||
if (strcmp(name, pbr_ifp->mapname) == 0)
|
||||
pbr_map_add_interface(pbrm, ifp);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
extern void pbr_map_check_policy_change(const char *name)
|
||||
{
|
||||
struct pbr_map *pbrm;
|
||||
|
||||
pbrm = pbrm_find(name);
|
||||
if (!pbrm) {
|
||||
DEBUGD(&pbr_dbg_map,
|
||||
"%s: Specified PBR-MAP(%s) does not exist?",
|
||||
__PRETTY_FUNCTION__, name);
|
||||
return;
|
||||
}
|
||||
|
||||
pbr_map_check_valid(name);
|
||||
if (pbrm->valid && !pbrm->installed) {
|
||||
struct pbr_event *pbre;
|
||||
|
||||
pbre = pbr_event_new(PBR_MAP_INSTALL, name);
|
||||
|
||||
pbr_event_enqueue(pbre);
|
||||
}
|
||||
}
|
||||
|
||||
extern void pbr_map_init(void)
|
||||
{
|
||||
RB_INIT(pbr_map_entry_head, &pbr_maps);
|
||||
|
||||
pbr_map_sequence_unique = 1;
|
||||
}
|
154
pbrd/pbr_map.h
Normal file
154
pbrd/pbr_map.h
Normal file
|
@ -0,0 +1,154 @@
|
|||
/*
|
||||
* PBR-map Header
|
||||
* 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
|
||||
*/
|
||||
#ifndef __PBR_MAP_H__
|
||||
#define __PBR_MAP_H__
|
||||
|
||||
struct pbr_map {
|
||||
/*
|
||||
* RB Tree of the pbr_maps
|
||||
*/
|
||||
RB_ENTRY(pbr_map) pbr_map_entry;
|
||||
|
||||
/*
|
||||
* The name of the PBR_MAP
|
||||
*/
|
||||
#define PBR_MAP_NAMELEN 100
|
||||
char name[PBR_MAP_NAMELEN];
|
||||
|
||||
struct list *seqnumbers;
|
||||
|
||||
/*
|
||||
* The list of incoming interfaces that
|
||||
* we will apply this policy map onto
|
||||
*/
|
||||
struct list *incoming;
|
||||
|
||||
/*
|
||||
* If valid is true we think the pbr_map is valid,
|
||||
* If false, look in individual pbrms to see
|
||||
* what we think is the invalid reason
|
||||
*/
|
||||
bool valid;
|
||||
|
||||
bool installed;
|
||||
};
|
||||
|
||||
RB_HEAD(pbr_map_entry_head, pbr_map);
|
||||
RB_PROTOTYPE(pbr_map_entry_head, pbr_map, pbr_map_entry, pbr_map_compare)
|
||||
|
||||
struct pbr_map_interface {
|
||||
struct interface *ifp;
|
||||
|
||||
struct pbr_map *pbrm;
|
||||
|
||||
bool delete;
|
||||
};
|
||||
|
||||
struct pbr_map_sequence {
|
||||
struct pbr_map *parent;
|
||||
|
||||
/*
|
||||
* The Unique identifier of this specific pbrms
|
||||
*/
|
||||
uint32_t unique;
|
||||
|
||||
/*
|
||||
* The sequence of where we are for display
|
||||
*/
|
||||
uint32_t seqno;
|
||||
|
||||
/*
|
||||
* The rule number to install into
|
||||
*/
|
||||
uint32_t ruleno;
|
||||
|
||||
/*
|
||||
* Our policy Catchers
|
||||
*/
|
||||
struct prefix *src;
|
||||
struct prefix *dst;
|
||||
|
||||
/*
|
||||
* The nexthop group we auto create
|
||||
* for when the user specifies a individual
|
||||
* nexthop
|
||||
*/
|
||||
struct nexthop_group *nhg;
|
||||
char *internal_nhg_name;
|
||||
|
||||
/*
|
||||
* The name of the nexthop group
|
||||
* configured in the pbr-map
|
||||
*/
|
||||
char *nhgrp_name;
|
||||
|
||||
/*
|
||||
* Do we think are nexthops are installed
|
||||
*/
|
||||
bool nhs_installed;
|
||||
|
||||
bool installed;
|
||||
/*
|
||||
* A reason of 0 means we think the pbr_map_sequence is good to go
|
||||
* We can accumuluate multiple failure states
|
||||
*/
|
||||
#define PBR_MAP_VALID_SEQUENCE_NUMBER 0
|
||||
#define PBR_MAP_INVALID_NEXTHOP_GROUP (1 << 0)
|
||||
#define PBR_MAP_INVALID_NEXTHOP (1 << 1)
|
||||
#define PBR_MAP_INVALID_NO_NEXTHOPS (1 << 2)
|
||||
#define PBR_MAP_INVALID_BOTH_NHANDGRP (1 << 3)
|
||||
#define PBR_MAP_INVALID_SRCDST (1 << 4)
|
||||
#define PBR_MAP_DEL_SEQUENCE_NUMBER (1 << 5)
|
||||
uint64_t reason;
|
||||
|
||||
QOBJ_FIELDS
|
||||
};
|
||||
|
||||
DECLARE_QOBJ_TYPE(pbr_map_sequence)
|
||||
|
||||
extern struct pbr_map_entry_head pbr_maps;
|
||||
|
||||
extern struct pbr_map_sequence *pbrms_get(const char *name, uint32_t seqno);
|
||||
extern struct pbr_map_sequence *pbrms_lookup_unique(uint32_t unique,
|
||||
ifindex_t ifindex);
|
||||
|
||||
extern struct pbr_map *pbrm_find(const char *name);
|
||||
extern void pbr_map_delete(const char *name, uint32_t seqno);
|
||||
extern void pbr_map_add_interface(struct pbr_map *pbrm, struct interface *ifp);
|
||||
extern void pbr_map_interface_delete(struct pbr_map *pbrm,
|
||||
struct interface *ifp);
|
||||
extern void pbr_map_write_interfaces(struct vty *vty, struct interface *ifp);
|
||||
extern void pbr_map_init(void);
|
||||
|
||||
extern bool pbr_map_check_valid(const char *name);
|
||||
|
||||
extern void pbr_map_check(const char *name, uint32_t seqno);
|
||||
extern void pbr_map_check_nh_group_change(const char *nh_group);
|
||||
extern void pbr_map_check_policy_change(const char *name);
|
||||
extern void pbr_map_reason_string(unsigned int reason, char *buf, int size);
|
||||
extern void pbr_map_add_interfaces(const char *name);
|
||||
|
||||
extern void pbr_map_schedule_policy_from_nhg(const char *nh_group);
|
||||
|
||||
extern void pbr_map_install(const char *name);
|
||||
|
||||
extern void pbr_map_policy_install(const char *name);
|
||||
extern void pbr_map_policy_delete(const char *ifname);
|
||||
#endif
|
27
pbrd/pbr_memory.c
Normal file
27
pbrd/pbr_memory.c
Normal file
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
* PBR memory 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 <memory.h>
|
||||
|
||||
#include "pbrd/pbr_memory.h"
|
||||
|
||||
|
||||
DEFINE_MGROUP(PBRD, "pbrd")
|
24
pbrd/pbr_memory.h
Normal file
24
pbrd/pbr_memory.h
Normal file
|
@ -0,0 +1,24 @@
|
|||
/*
|
||||
* pbr memory 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
|
||||
*/
|
||||
#ifndef __PBR_MEMORY_H__
|
||||
|
||||
DECLARE_MGROUP(PBRD)
|
||||
|
||||
#endif
|
699
pbrd/pbr_nht.c
Normal file
699
pbrd/pbr_nht.c
Normal file
|
@ -0,0 +1,699 @@
|
|||
/*
|
||||
* PBR-nht 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 <log.h>
|
||||
#include <nexthop.h>
|
||||
#include <nexthop_group.h>
|
||||
#include <hash.h>
|
||||
#include <jhash.h>
|
||||
#include <vty.h>
|
||||
#include <zclient.h>
|
||||
|
||||
#include "pbrd/pbr_nht.h"
|
||||
#include "pbrd/pbr_map.h"
|
||||
#include "pbrd/pbr_event.h"
|
||||
#include "pbrd/pbr_zebra.h"
|
||||
#include "pbrd/pbr_memory.h"
|
||||
#include "pbrd/pbr_debug.h"
|
||||
|
||||
DEFINE_MTYPE_STATIC(PBRD, PBR_NHG, "PBR Nexthop Groups")
|
||||
|
||||
static struct hash *pbr_nhg_hash;
|
||||
|
||||
static uint32_t pbr_nhg_low_table;
|
||||
static uint32_t pbr_nhg_high_table;
|
||||
static uint32_t pbr_nhg_low_rule;
|
||||
static uint32_t pbr_nhg_high_rule;
|
||||
static bool nhg_tableid[65535];
|
||||
|
||||
static void *pbr_nh_alloc(void *p)
|
||||
{
|
||||
struct pbr_nexthop_cache *new;
|
||||
struct pbr_nexthop_cache *pnhc = (struct pbr_nexthop_cache *)p;
|
||||
|
||||
new = XCALLOC(MTYPE_PBR_NHG, sizeof(*new));
|
||||
memcpy(&new->nexthop, &pnhc->nexthop, sizeof(struct nexthop));
|
||||
|
||||
DEBUGD(&pbr_dbg_nht, "%s: Sending nexthop to Zebra",
|
||||
__PRETTY_FUNCTION__);
|
||||
|
||||
pbr_send_rnh(&new->nexthop, true);
|
||||
|
||||
new->valid = false;
|
||||
return new;
|
||||
}
|
||||
|
||||
static void pbr_nh_delete(struct pbr_nexthop_cache **pnhc)
|
||||
{
|
||||
pbr_send_rnh(&(*pnhc)->nexthop, false);
|
||||
|
||||
XFREE(MTYPE_PBR_NHG, *pnhc);
|
||||
}
|
||||
|
||||
static uint32_t pbr_nh_hash_key(void *arg)
|
||||
{
|
||||
uint32_t key;
|
||||
struct pbr_nexthop_cache *pbrnc = (struct pbr_nexthop_cache *)arg;
|
||||
|
||||
key = jhash_1word(pbrnc->nexthop.vrf_id, 0x45afe398);
|
||||
key = jhash_1word(pbrnc->nexthop.ifindex, key);
|
||||
key = jhash_1word(pbrnc->nexthop.type, key);
|
||||
key = jhash(&pbrnc->nexthop.gate, sizeof(union g_addr), key);
|
||||
|
||||
return key;
|
||||
}
|
||||
|
||||
static int pbr_nh_hash_equal(const void *arg1, const void *arg2)
|
||||
{
|
||||
const struct pbr_nexthop_cache *pbrnc1 =
|
||||
(const struct pbr_nexthop_cache *)arg1;
|
||||
const struct pbr_nexthop_cache *pbrnc2 =
|
||||
(const struct pbr_nexthop_cache *)arg2;
|
||||
|
||||
if (pbrnc1->nexthop.vrf_id != pbrnc2->nexthop.vrf_id)
|
||||
return 0;
|
||||
|
||||
if (pbrnc1->nexthop.ifindex != pbrnc2->nexthop.ifindex)
|
||||
return 0;
|
||||
|
||||
if (pbrnc1->nexthop.type != pbrnc2->nexthop.type)
|
||||
return 0;
|
||||
|
||||
switch (pbrnc1->nexthop.type) {
|
||||
case NEXTHOP_TYPE_IFINDEX:
|
||||
return 1;
|
||||
case NEXTHOP_TYPE_IPV4_IFINDEX:
|
||||
case NEXTHOP_TYPE_IPV4:
|
||||
return pbrnc1->nexthop.gate.ipv4.s_addr
|
||||
== pbrnc2->nexthop.gate.ipv4.s_addr;
|
||||
case NEXTHOP_TYPE_IPV6_IFINDEX:
|
||||
case NEXTHOP_TYPE_IPV6:
|
||||
return !memcmp(&pbrnc1->nexthop.gate.ipv6,
|
||||
&pbrnc2->nexthop.gate.ipv6, 16);
|
||||
case NEXTHOP_TYPE_BLACKHOLE:
|
||||
return pbrnc1->nexthop.bh_type == pbrnc2->nexthop.bh_type;
|
||||
}
|
||||
|
||||
/*
|
||||
* We should not get here
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
|
||||
void pbr_nhgroup_add_cb(const char *name)
|
||||
{
|
||||
struct pbr_event *pbre;
|
||||
|
||||
pbre = pbr_event_new(PBR_NHG_NEW, name);
|
||||
|
||||
pbr_event_enqueue(pbre);
|
||||
DEBUGD(&pbr_dbg_nht, "%s: Received ADD cb for %s", __PRETTY_FUNCTION__,
|
||||
name);
|
||||
}
|
||||
|
||||
void pbr_nhgroup_add_nexthop_cb(const struct nexthop_group_cmd *nhg,
|
||||
const struct nexthop *nhop)
|
||||
{
|
||||
struct pbr_event *pbre;
|
||||
|
||||
pbre = pbr_event_new(PBR_NHG_ADD_NEXTHOP, nhg->name);
|
||||
|
||||
pbr_event_enqueue(pbre);
|
||||
DEBUGD(&pbr_dbg_nht, "%s: Received NEXTHOP_ADD cb for %s",
|
||||
__PRETTY_FUNCTION__, nhg->name);
|
||||
}
|
||||
|
||||
void pbr_nhgroup_del_nexthop_cb(const struct nexthop_group_cmd *nhg,
|
||||
const struct nexthop *nhop)
|
||||
{
|
||||
struct pbr_event *pbre;
|
||||
|
||||
pbre = pbr_event_new(PBR_NHG_DEL_NEXTHOP, nhg->name);
|
||||
|
||||
pbr_event_enqueue(pbre);
|
||||
DEBUGD(&pbr_dbg_nht, "%s: Received NEXTHOP_DEL cb for %s",
|
||||
__PRETTY_FUNCTION__, nhg->name);
|
||||
}
|
||||
|
||||
void pbr_nhgroup_delete_cb(const char *name)
|
||||
{
|
||||
struct pbr_event *pbre;
|
||||
|
||||
pbre = pbr_event_new(PBR_NHG_DELETE, name);
|
||||
|
||||
pbr_event_enqueue(pbre);
|
||||
DEBUGD(&pbr_dbg_nht, "%s: Received DELETE cb for %s",
|
||||
__PRETTY_FUNCTION__, name);
|
||||
}
|
||||
|
||||
#if 0
|
||||
static struct pbr_nexthop_cache *pbr_nht_lookup_nexthop(struct nexthop *nexthop)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void pbr_nht_find_nhg_from_table_install(struct hash_backet *b,
|
||||
void *data)
|
||||
{
|
||||
struct pbr_nexthop_group_cache *pnhgc =
|
||||
(struct pbr_nexthop_group_cache *)b->data;
|
||||
uint32_t *table_id = (uint32_t *)data;
|
||||
|
||||
if (pnhgc->table_id == *table_id) {
|
||||
DEBUGD(&pbr_dbg_nht, "%s: Table ID (%u) matches %s",
|
||||
__PRETTY_FUNCTION__, *table_id, pnhgc->name);
|
||||
pnhgc->installed = true;
|
||||
pbr_map_schedule_policy_from_nhg(pnhgc->name);
|
||||
}
|
||||
}
|
||||
|
||||
void pbr_nht_route_installed_for_table(uint32_t table_id)
|
||||
{
|
||||
hash_iterate(pbr_nhg_hash, pbr_nht_find_nhg_from_table_install,
|
||||
&table_id);
|
||||
}
|
||||
|
||||
static void pbr_nht_find_nhg_from_table_remove(struct hash_backet *b,
|
||||
void *data)
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
void pbr_nht_route_removed_for_table(uint32_t table_id)
|
||||
{
|
||||
hash_iterate(pbr_nhg_hash, pbr_nht_find_nhg_from_table_remove,
|
||||
&table_id);
|
||||
}
|
||||
|
||||
/*
|
||||
* Loop through all nexthops in a nexthop group to check that they are all the
|
||||
* same. If they are not all the same, log this peculiarity.
|
||||
*
|
||||
* nhg
|
||||
* The nexthop group to check
|
||||
*
|
||||
* Returns:
|
||||
* - AFI of last nexthop in the group
|
||||
* - AFI_MAX on error
|
||||
*/
|
||||
static afi_t pbr_nht_which_afi(struct nexthop_group nhg)
|
||||
{
|
||||
struct nexthop *nexthop;
|
||||
afi_t install_afi = AFI_MAX;
|
||||
bool v6, v4, bh;
|
||||
v6 = v4 = bh = false;
|
||||
|
||||
for (ALL_NEXTHOPS(nhg, nexthop)) {
|
||||
switch (nexthop->type) {
|
||||
case NEXTHOP_TYPE_IFINDEX:
|
||||
break;
|
||||
case NEXTHOP_TYPE_IPV4:
|
||||
case NEXTHOP_TYPE_IPV4_IFINDEX:
|
||||
v6 = true;
|
||||
install_afi = AFI_IP;
|
||||
break;
|
||||
case NEXTHOP_TYPE_IPV6:
|
||||
case NEXTHOP_TYPE_IPV6_IFINDEX:
|
||||
v4 = true;
|
||||
install_afi = AFI_IP6;
|
||||
break;
|
||||
case NEXTHOP_TYPE_BLACKHOLE:
|
||||
bh = true;
|
||||
install_afi = AFI_MAX;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!bh && v6 && v4)
|
||||
DEBUGD(&pbr_dbg_nht,
|
||||
"%s: Saw both V6 and V4 nexthops...using %s",
|
||||
__PRETTY_FUNCTION__, afi2str(install_afi));
|
||||
if (bh && (v6 || v4))
|
||||
DEBUGD(&pbr_dbg_nht,
|
||||
"%s: Saw blackhole nexthop(s) with %s%s%s nexthop(s), using AFI_MAX.",
|
||||
__PRETTY_FUNCTION__, v4 ? "v4" : "",
|
||||
(v4 && v6) ? " and " : "", v6 ? "v6" : "");
|
||||
|
||||
return install_afi;
|
||||
}
|
||||
|
||||
static void pbr_nht_install_nexthop_group(struct pbr_nexthop_group_cache *pnhgc,
|
||||
struct nexthop_group nhg)
|
||||
{
|
||||
afi_t install_afi;
|
||||
|
||||
install_afi = pbr_nht_which_afi(nhg);
|
||||
|
||||
pnhgc->installed = false;
|
||||
route_add(pnhgc, nhg, install_afi);
|
||||
}
|
||||
|
||||
static void
|
||||
pbr_nht_uninstall_nexthop_group(struct pbr_nexthop_group_cache *pnhgc,
|
||||
struct nexthop_group nhg)
|
||||
{
|
||||
afi_t install_afi;
|
||||
|
||||
install_afi = pbr_nht_which_afi(nhg);
|
||||
|
||||
pnhgc->installed = false;
|
||||
pnhgc->valid = false;
|
||||
route_delete(pnhgc, install_afi);
|
||||
}
|
||||
|
||||
void pbr_nht_change_group(const char *name)
|
||||
{
|
||||
struct nexthop_group_cmd *nhgc;
|
||||
struct pbr_nexthop_group_cache *pnhgc;
|
||||
struct pbr_nexthop_group_cache find;
|
||||
struct nexthop *nhop;
|
||||
|
||||
nhgc = nhgc_find(name);
|
||||
if (!nhgc)
|
||||
return;
|
||||
|
||||
memset(&find, 0, sizeof(find));
|
||||
strcpy(find.name, name);
|
||||
pnhgc = hash_lookup(pbr_nhg_hash, &find);
|
||||
|
||||
if (!pnhgc) {
|
||||
DEBUGD(&pbr_dbg_nht,
|
||||
"%s: Could not find nexthop-group cache w/ name '%s'",
|
||||
__PRETTY_FUNCTION__, name);
|
||||
return;
|
||||
}
|
||||
|
||||
for (ALL_NEXTHOPS(nhgc->nhg, nhop)) {
|
||||
struct pbr_nexthop_cache lookup;
|
||||
struct pbr_nexthop_cache *pnhc;
|
||||
|
||||
memcpy(&lookup.nexthop, nhop, sizeof(*nhop));
|
||||
pnhc = hash_lookup(pnhgc->nhh, &lookup);
|
||||
if (!pnhc) {
|
||||
pnhc = hash_get(pnhgc->nhh, &lookup, pbr_nh_alloc);
|
||||
pnhc->parent = pnhgc;
|
||||
}
|
||||
}
|
||||
pbr_nht_install_nexthop_group(pnhgc, nhgc->nhg);
|
||||
}
|
||||
|
||||
char *pbr_nht_nexthop_make_name(char *name, size_t l,
|
||||
uint32_t seqno, char *buffer)
|
||||
{
|
||||
snprintf(buffer, l, "%s%u", name, seqno);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
static void *pbr_nhgc_alloc(void *p)
|
||||
{
|
||||
struct pbr_nexthop_group_cache *new;
|
||||
struct pbr_nexthop_group_cache *pnhgc =
|
||||
(struct pbr_nexthop_group_cache *)p;
|
||||
|
||||
new = XCALLOC(MTYPE_PBR_NHG, sizeof(*new));
|
||||
|
||||
strcpy(new->name, pnhgc->name);
|
||||
new->table_id = pbr_nht_get_next_tableid();
|
||||
|
||||
DEBUGD(&pbr_dbg_nht, "%s: NHT: %s assigned Table ID: %u",
|
||||
__PRETTY_FUNCTION__, new->name, new->table_id);
|
||||
|
||||
new->nhh = hash_create_size(8, pbr_nh_hash_key, pbr_nh_hash_equal,
|
||||
"PBR NH Cache Hash");
|
||||
return new;
|
||||
}
|
||||
|
||||
void pbr_nht_add_individual_nexthop(const char *name, uint32_t seqno)
|
||||
{
|
||||
struct pbr_nexthop_group_cache *pnhgc;
|
||||
struct pbr_nexthop_group_cache find;
|
||||
struct pbr_nexthop_cache *pnhc;
|
||||
struct pbr_map_sequence *pbrms;
|
||||
struct pbr_nexthop_cache lookup;
|
||||
|
||||
pbrms = pbrms_get(name, seqno);
|
||||
|
||||
memset(&find, 0, sizeof(find));
|
||||
pbr_nht_nexthop_make_name(pbrms->parent->name, PBR_MAP_NAMELEN,
|
||||
pbrms->seqno, find.name);
|
||||
if (!pbrms->internal_nhg_name)
|
||||
pbrms->internal_nhg_name = XSTRDUP(MTYPE_TMP, find.name);
|
||||
|
||||
pnhgc = hash_get(pbr_nhg_hash, &find, pbr_nhgc_alloc);
|
||||
|
||||
memcpy(&lookup.nexthop, pbrms->nhg->nexthop, sizeof(struct nexthop));
|
||||
pnhc = hash_get(pnhgc->nhh, &lookup, pbr_nh_alloc);
|
||||
pnhc->parent = pnhgc;
|
||||
pbr_nht_install_nexthop_group(pnhgc, *pbrms->nhg);
|
||||
}
|
||||
|
||||
void pbr_nht_delete_individual_nexthop(const char *name, uint32_t seqno)
|
||||
{
|
||||
struct pbr_nexthop_group_cache *pnhgc;
|
||||
struct pbr_nexthop_group_cache find;
|
||||
struct pbr_nexthop_cache *pnhc;
|
||||
struct pbr_nexthop_cache lup;
|
||||
struct pbr_map_sequence *pbrms;
|
||||
struct nexthop *nh;
|
||||
|
||||
pbrms = pbrms_get(name, seqno);
|
||||
|
||||
memset(&find, 0, sizeof(find));
|
||||
strcpy(&find.name[0], pbrms->internal_nhg_name);
|
||||
pnhgc = hash_lookup(pbr_nhg_hash, &find);
|
||||
|
||||
nh = pbrms->nhg->nexthop;
|
||||
memcpy(&lup.nexthop, nh, sizeof(struct nexthop));
|
||||
pnhc = hash_lookup(pnhgc->nhh, &lup);
|
||||
pnhc->parent = NULL;
|
||||
hash_release(pnhgc->nhh, pnhc);
|
||||
pbr_nh_delete(&pnhc);
|
||||
pbr_nht_uninstall_nexthop_group(pnhgc, *pbrms->nhg);
|
||||
|
||||
hash_release(pbr_nhg_hash, pnhgc);
|
||||
|
||||
nexthop_del(pbrms->nhg, nh);
|
||||
nexthop_free(nh);
|
||||
nexthop_group_delete(&pbrms->nhg);
|
||||
XFREE(MTYPE_TMP, pbrms->internal_nhg_name);
|
||||
}
|
||||
|
||||
void pbr_nht_add_group(const char *name)
|
||||
{
|
||||
struct nexthop *nhop;
|
||||
struct nexthop_group_cmd *nhgc;
|
||||
struct pbr_nexthop_group_cache *pnhgc;
|
||||
struct pbr_nexthop_group_cache lookup;
|
||||
|
||||
nhgc = nhgc_find(name);
|
||||
|
||||
if (!nhgc) {
|
||||
zlog_warn("%s: Could not find group %s to add",
|
||||
__PRETTY_FUNCTION__, name);
|
||||
return;
|
||||
}
|
||||
|
||||
strcpy(lookup.name, name);
|
||||
pnhgc = hash_get(pbr_nhg_hash, &lookup, pbr_nhgc_alloc);
|
||||
DEBUGD(&pbr_dbg_nht, "%s: Retrieved NHGC @ %p", __PRETTY_FUNCTION__,
|
||||
pnhgc);
|
||||
|
||||
for (ALL_NEXTHOPS(nhgc->nhg, nhop)) {
|
||||
struct pbr_nexthop_cache lookup;
|
||||
struct pbr_nexthop_cache *pnhc;
|
||||
|
||||
memcpy(&lookup.nexthop, nhop, sizeof(*nhop));
|
||||
pnhc = hash_lookup(pnhgc->nhh, &lookup);
|
||||
if (!pnhc) {
|
||||
pnhc = hash_get(pnhgc->nhh, &lookup, pbr_nh_alloc);
|
||||
pnhc->parent = pnhgc;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void pbr_nht_delete_group(const char *name)
|
||||
{
|
||||
struct pbr_map_sequence *pbrms;
|
||||
struct listnode *snode;
|
||||
struct pbr_map *pbrm;
|
||||
|
||||
RB_FOREACH (pbrm, pbr_map_entry_head, &pbr_maps) {
|
||||
for (ALL_LIST_ELEMENTS_RO(pbrm->seqnumbers, snode, pbrms)) {
|
||||
if (pbrms->nhgrp_name
|
||||
&& strcmp(pbrms->nhgrp_name, name) == 0) {
|
||||
pbrms->reason |= PBR_MAP_INVALID_NO_NEXTHOPS;
|
||||
pbrm->valid = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool pbr_nht_nexthop_valid(struct nexthop_group *nhg)
|
||||
{
|
||||
DEBUGD(&pbr_dbg_nht, "%s: %p", __PRETTY_FUNCTION__, nhg);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool pbr_nht_nexthop_group_valid(const char *name)
|
||||
{
|
||||
struct pbr_nexthop_group_cache *pnhgc;
|
||||
struct pbr_nexthop_group_cache lookup;
|
||||
|
||||
DEBUGD(&pbr_dbg_nht, "%s: %s", __PRETTY_FUNCTION__, name);
|
||||
|
||||
strcpy(lookup.name, name);
|
||||
pnhgc = hash_get(pbr_nhg_hash, &lookup, NULL);
|
||||
if (!pnhgc)
|
||||
return false;
|
||||
DEBUGD(&pbr_dbg_nht, "%s: \t%d %d", __PRETTY_FUNCTION__, pnhgc->valid,
|
||||
pnhgc->installed);
|
||||
if (pnhgc->valid && pnhgc->installed)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
struct pbr_nht_individual {
|
||||
struct zapi_route *nhr;
|
||||
|
||||
uint32_t valid;
|
||||
};
|
||||
|
||||
static void pbr_nht_individual_nexthop_update_lookup(struct hash_backet *b,
|
||||
void *data)
|
||||
{
|
||||
struct pbr_nexthop_cache *pnhc = b->data;
|
||||
struct pbr_nht_individual *pnhi = data;
|
||||
char buf[PREFIX_STRLEN];
|
||||
bool old_valid;
|
||||
|
||||
old_valid = pnhc->valid;
|
||||
|
||||
switch (pnhi->nhr->prefix.family) {
|
||||
case AF_INET:
|
||||
if (pnhc->nexthop.gate.ipv4.s_addr
|
||||
== pnhi->nhr->prefix.u.prefix4.s_addr)
|
||||
pnhc->valid = !!pnhi->nhr->nexthop_num;
|
||||
break;
|
||||
case AF_INET6:
|
||||
if (memcmp(&pnhc->nexthop.gate.ipv6,
|
||||
&pnhi->nhr->prefix.u.prefix6, 16) == 0)
|
||||
pnhc->valid = !!pnhi->nhr->nexthop_num;
|
||||
break;
|
||||
}
|
||||
|
||||
DEBUGD(&pbr_dbg_nht, "\tFound %s: old: %d new: %d",
|
||||
prefix2str(&pnhi->nhr->prefix, buf, sizeof(buf)), old_valid,
|
||||
pnhc->valid);
|
||||
|
||||
if (old_valid != pnhc->valid) {
|
||||
struct pbr_event *pbre;
|
||||
|
||||
pbre = pbr_event_new(PBR_NH_CHANGED, pnhc->parent->name);
|
||||
|
||||
pbr_event_enqueue(pbre);
|
||||
}
|
||||
|
||||
if (pnhc->valid)
|
||||
pnhi->valid += 1;
|
||||
}
|
||||
|
||||
static void pbr_nht_nexthop_update_lookup(struct hash_backet *b, void *data)
|
||||
{
|
||||
struct pbr_nexthop_group_cache *pnhgc = b->data;
|
||||
struct pbr_nht_individual pnhi;
|
||||
|
||||
pnhi.nhr = (struct zapi_route *)data;
|
||||
pnhi.valid = 0;
|
||||
hash_iterate(pnhgc->nhh, pbr_nht_individual_nexthop_update_lookup,
|
||||
&pnhi);
|
||||
|
||||
/*
|
||||
* If any of the specified nexthops are valid we are valid
|
||||
*/
|
||||
pnhgc->valid = !!pnhi.valid;
|
||||
}
|
||||
|
||||
void pbr_nht_nexthop_update(struct zapi_route *nhr)
|
||||
{
|
||||
hash_iterate(pbr_nhg_hash, pbr_nht_nexthop_update_lookup, nhr);
|
||||
}
|
||||
|
||||
static uint32_t pbr_nhg_hash_key(void *arg)
|
||||
{
|
||||
struct pbr_nexthop_group_cache *nhgc =
|
||||
(struct pbr_nexthop_group_cache *)arg;
|
||||
|
||||
return jhash(&nhgc->name, strlen(nhgc->name), 0x52c34a96);
|
||||
}
|
||||
|
||||
static int pbr_nhg_hash_equal(const void *arg1, const void *arg2)
|
||||
{
|
||||
const struct pbr_nexthop_group_cache *nhgc1 =
|
||||
(const struct pbr_nexthop_group_cache *)arg1;
|
||||
const struct pbr_nexthop_group_cache *nhgc2 =
|
||||
(const struct pbr_nexthop_group_cache *)arg2;
|
||||
|
||||
return !strcmp(nhgc1->name, nhgc2->name);
|
||||
}
|
||||
|
||||
|
||||
uint32_t pbr_nht_get_next_tableid(void)
|
||||
{
|
||||
uint32_t i;
|
||||
bool found = false;
|
||||
|
||||
for (i = pbr_nhg_low_table; i <= pbr_nhg_high_table; i++) {
|
||||
if (nhg_tableid[i] == false) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (found) {
|
||||
nhg_tableid[i] = true;
|
||||
return i;
|
||||
} else
|
||||
return 0;
|
||||
}
|
||||
|
||||
void pbr_nht_set_tableid_range(uint32_t low, uint32_t high)
|
||||
{
|
||||
pbr_nhg_low_table = low;
|
||||
pbr_nhg_high_table = high;
|
||||
}
|
||||
|
||||
void pbr_nht_write_table_range(struct vty *vty)
|
||||
{
|
||||
if (pbr_nhg_low_table != PBR_NHT_DEFAULT_LOW_TABLEID
|
||||
|| pbr_nhg_high_table != PBR_NHT_DEFAULT_HIGH_TABLEID) {
|
||||
vty_out(vty, "pbr table range %u %u\n", pbr_nhg_low_table,
|
||||
pbr_nhg_high_table);
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t pbr_nht_get_next_rule(uint32_t seqno)
|
||||
{
|
||||
return seqno + pbr_nhg_low_rule - 1;
|
||||
}
|
||||
void pbr_nht_set_rule_range(uint32_t low, uint32_t high)
|
||||
{
|
||||
pbr_nhg_low_rule = low;
|
||||
pbr_nhg_high_rule = high;
|
||||
}
|
||||
|
||||
void pbr_nht_write_rule_range(struct vty *vty)
|
||||
{
|
||||
if (pbr_nhg_low_rule != PBR_NHT_DEFAULT_LOW_RULE
|
||||
|| pbr_nhg_high_rule != PBR_NHT_DEFAULT_HIGH_RULE) {
|
||||
vty_out(vty, "pbr rule range %u %u\n", pbr_nhg_low_rule,
|
||||
pbr_nhg_high_rule);
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t pbr_nht_get_table(const char *name)
|
||||
{
|
||||
struct pbr_nexthop_group_cache find;
|
||||
struct pbr_nexthop_group_cache *pnhgc;
|
||||
|
||||
memset(&find, 0, sizeof(find));
|
||||
strcpy(find.name, name);
|
||||
pnhgc = hash_lookup(pbr_nhg_hash, &find);
|
||||
|
||||
if (!pnhgc) {
|
||||
DEBUGD(&pbr_dbg_nht,
|
||||
"%s: Could not find nexthop-group cache w/ name '%s'",
|
||||
__PRETTY_FUNCTION__, name);
|
||||
return 5000;
|
||||
}
|
||||
|
||||
return pnhgc->table_id;
|
||||
}
|
||||
|
||||
bool pbr_nht_get_installed(const char *name)
|
||||
{
|
||||
struct pbr_nexthop_group_cache find;
|
||||
struct pbr_nexthop_group_cache *pnhgc;
|
||||
|
||||
memset(&find, 0, sizeof(find));
|
||||
strcpy(find.name, name);
|
||||
|
||||
pnhgc = hash_lookup(pbr_nhg_hash, &find);
|
||||
|
||||
if (!pnhgc) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return pnhgc->installed;
|
||||
}
|
||||
|
||||
static void pbr_nht_show_nhg_nexthops(struct hash_backet *b, void *data)
|
||||
{
|
||||
struct pbr_nexthop_cache *pnhc = b->data;
|
||||
struct vty *vty = data;
|
||||
|
||||
vty_out(vty, "\tValid: %d", pnhc->valid);
|
||||
nexthop_group_write_nexthop(vty, &pnhc->nexthop);
|
||||
}
|
||||
|
||||
struct pbr_nht_show {
|
||||
struct vty *vty;
|
||||
const char *name;
|
||||
};
|
||||
|
||||
static void pbr_nht_show_nhg(struct hash_backet *b, void *data)
|
||||
{
|
||||
struct pbr_nexthop_group_cache *pnhgc = b->data;
|
||||
struct pbr_nht_show *pns = data;
|
||||
struct vty *vty;
|
||||
|
||||
if (pns->name && strcmp(pns->name, pnhgc->name) != 0)
|
||||
return;
|
||||
|
||||
vty = pns->vty;
|
||||
vty_out(vty, "Nexthop-Group: %s Table: %u Valid: %d Installed: %d\n",
|
||||
pnhgc->name, pnhgc->table_id, pnhgc->valid, pnhgc->installed);
|
||||
|
||||
hash_iterate(pnhgc->nhh, pbr_nht_show_nhg_nexthops, vty);
|
||||
}
|
||||
|
||||
void pbr_nht_show_nexthop_group(struct vty *vty, const char *name)
|
||||
{
|
||||
struct pbr_nht_show pns;
|
||||
|
||||
pns.vty = vty;
|
||||
pns.name = name;
|
||||
|
||||
hash_iterate(pbr_nhg_hash, pbr_nht_show_nhg, &pns);
|
||||
}
|
||||
|
||||
void pbr_nht_init(void)
|
||||
{
|
||||
pbr_nhg_hash = hash_create_size(
|
||||
16, pbr_nhg_hash_key, pbr_nhg_hash_equal, "PBR NHG Cache Hash");
|
||||
|
||||
pbr_nhg_low_table = PBR_NHT_DEFAULT_LOW_TABLEID;
|
||||
pbr_nhg_high_table = PBR_NHT_DEFAULT_HIGH_TABLEID;
|
||||
pbr_nhg_low_rule = PBR_NHT_DEFAULT_LOW_RULE;
|
||||
pbr_nhg_high_rule = PBR_NHT_DEFAULT_HIGH_RULE;
|
||||
memset(&nhg_tableid, 0, 65535 * sizeof(uint8_t));
|
||||
}
|
113
pbrd/pbr_nht.h
Normal file
113
pbrd/pbr_nht.h
Normal file
|
@ -0,0 +1,113 @@
|
|||
/*
|
||||
* PBR-nht Header
|
||||
* 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
|
||||
*/
|
||||
#ifndef __PBR_NHT_H__
|
||||
#define __PBR_NHT_H__
|
||||
|
||||
#include <lib/zclient.h>
|
||||
#include <lib/nexthop_group.h>
|
||||
|
||||
struct pbr_nexthop_group_cache {
|
||||
char name[PBR_MAP_NAMELEN];
|
||||
|
||||
uint32_t table_id;
|
||||
|
||||
struct hash *nhh;
|
||||
|
||||
/*
|
||||
* If all nexthops are considered valid
|
||||
*/
|
||||
bool valid;
|
||||
|
||||
bool installed;
|
||||
};
|
||||
|
||||
struct pbr_nexthop_cache {
|
||||
struct pbr_nexthop_group_cache *parent;
|
||||
|
||||
struct nexthop nexthop;
|
||||
|
||||
bool valid;
|
||||
};
|
||||
|
||||
extern void pbr_nht_write_table_range(struct vty *vty);
|
||||
#define PBR_NHT_DEFAULT_LOW_TABLEID 10000
|
||||
#define PBR_NHT_DEFAULT_HIGH_TABLEID 11000
|
||||
extern void pbr_nht_set_tableid_range(uint32_t low, uint32_t high);
|
||||
|
||||
/*
|
||||
* Get the next tableid to use for installation
|
||||
*/
|
||||
extern uint32_t pbr_nht_get_next_tableid(void);
|
||||
/*
|
||||
* Get the next rule number to use for installation
|
||||
*/
|
||||
extern void pbr_nht_write_rule_range(struct vty *vty);
|
||||
|
||||
#define PBR_NHT_DEFAULT_LOW_RULE 300
|
||||
#define PBR_NHT_DEFAULT_HIGH_RULE 1300
|
||||
extern void pbr_nht_set_rule_range(uint32_t low, uint32_t high);
|
||||
|
||||
extern uint32_t pbr_nht_get_next_rule(uint32_t seqno);
|
||||
|
||||
extern void pbr_nhgroup_add_cb(const char *name);
|
||||
extern void pbr_nhgroup_add_nexthop_cb(const struct nexthop_group_cmd *nhg,
|
||||
const struct nexthop *nhop);
|
||||
extern void pbr_nhgroup_del_nexthop_cb(const struct nexthop_group_cmd *nhg,
|
||||
const struct nexthop *nhop);
|
||||
extern void pbr_nhgroup_delete_cb(const char *name);
|
||||
|
||||
extern bool pbr_nht_nexthop_valid(struct nexthop_group *nhg);
|
||||
extern bool pbr_nht_nexthop_group_valid(const char *name);
|
||||
|
||||
extern void pbr_nht_add_group(const char *name);
|
||||
extern void pbr_nht_change_group(const char *name);
|
||||
extern void pbr_nht_delete_group(const char *name);
|
||||
|
||||
extern void pbr_nht_add_individual_nexthop(const char *name, uint32_t seqno);
|
||||
extern void pbr_nht_delete_individual_nexthop(const char *name, uint32_t seqno);
|
||||
/*
|
||||
* Given the tableid of the installed default
|
||||
* route, find the nexthop-group associated with
|
||||
* it, then find all pbr-maps that use it and
|
||||
* install/delete them as well.
|
||||
*/
|
||||
extern void pbr_nht_route_installed_for_table(uint32_t table_id);
|
||||
extern void pbr_nht_route_removed_for_table(uint32_t table_id);
|
||||
|
||||
/*
|
||||
* Given the nexthop group name, lookup the associated
|
||||
* tableid with it
|
||||
*/
|
||||
extern uint32_t pbr_nht_get_table(const char *name);
|
||||
|
||||
extern bool pbr_nht_get_installed(const char *name);
|
||||
|
||||
extern char *pbr_nht_nexthop_make_name(char *name, size_t l, uint32_t seqno,
|
||||
char *buffer);
|
||||
|
||||
extern void pbr_nht_show_nexthop_group(struct vty *vty, const char *name);
|
||||
|
||||
/*
|
||||
* When we get a callback from zebra about a nexthop changing
|
||||
*/
|
||||
extern void pbr_nht_nexthop_update(struct zapi_route *nhr);
|
||||
|
||||
extern void pbr_nht_init(void);
|
||||
#endif
|
631
pbrd/pbr_vty.c
Normal file
631
pbrd/pbr_vty.c
Normal file
|
@ -0,0 +1,631 @@
|
|||
/*
|
||||
* 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;
|
||||
}
|
24
pbrd/pbr_vty.h
Normal file
24
pbrd/pbr_vty.h
Normal file
|
@ -0,0 +1,24 @@
|
|||
/*
|
||||
* VTY library for PBR
|
||||
* 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
|
||||
*/
|
||||
#ifndef __PBR_VTY_H__
|
||||
#define __PBR_VTY_H__
|
||||
|
||||
extern void pbr_vty_init(void);
|
||||
#endif
|
579
pbrd/pbr_zebra.c
Normal file
579
pbrd/pbr_zebra.c
Normal file
|
@ -0,0 +1,579 @@
|
|||
/*
|
||||
* Zebra connect 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 "thread.h"
|
||||
#include "command.h"
|
||||
#include "network.h"
|
||||
#include "prefix.h"
|
||||
#include "routemap.h"
|
||||
#include "table.h"
|
||||
#include "stream.h"
|
||||
#include "memory.h"
|
||||
#include "zclient.h"
|
||||
#include "filter.h"
|
||||
#include "plist.h"
|
||||
#include "log.h"
|
||||
#include "nexthop.h"
|
||||
#include "nexthop_group.h"
|
||||
|
||||
#include "pbr_nht.h"
|
||||
#include "pbr_map.h"
|
||||
#include "pbr_memory.h"
|
||||
#include "pbr_zebra.h"
|
||||
#include "pbr_debug.h"
|
||||
|
||||
DEFINE_MTYPE_STATIC(PBRD, PBR_INTERFACE, "PBR Interface")
|
||||
|
||||
/* Zebra structure to hold current status. */
|
||||
struct zclient *zclient = NULL;
|
||||
|
||||
/* For registering threads. */
|
||||
extern struct thread_master *master;
|
||||
|
||||
static struct interface *zebra_interface_if_lookup(struct stream *s)
|
||||
{
|
||||
char ifname_tmp[INTERFACE_NAMSIZ];
|
||||
|
||||
/* Read interface name. */
|
||||
stream_get(ifname_tmp, s, INTERFACE_NAMSIZ);
|
||||
|
||||
/* And look it up. */
|
||||
return if_lookup_by_name(ifname_tmp, VRF_DEFAULT);
|
||||
}
|
||||
|
||||
static struct pbr_interface *pbr_if_new(struct interface *ifp)
|
||||
{
|
||||
struct pbr_interface *pbr_ifp;
|
||||
|
||||
zassert(ifp);
|
||||
zassert(!ifp->info);
|
||||
|
||||
pbr_ifp = XCALLOC(MTYPE_PBR_INTERFACE, sizeof(*pbr_ifp));
|
||||
|
||||
if (!pbr_ifp) {
|
||||
zlog_err("%s: PBR XCALLOC(%zu) failure", __PRETTY_FUNCTION__,
|
||||
sizeof(*pbr_ifp));
|
||||
return 0;
|
||||
}
|
||||
|
||||
return (pbr_ifp);
|
||||
}
|
||||
|
||||
/* Inteface addition message from zebra. */
|
||||
static int interface_add(int command, struct zclient *zclient,
|
||||
zebra_size_t length, vrf_id_t vrf_id)
|
||||
{
|
||||
struct interface *ifp;
|
||||
|
||||
ifp = zebra_interface_add_read(zclient->ibuf, vrf_id);
|
||||
|
||||
if (!ifp)
|
||||
return 0;
|
||||
|
||||
if (!ifp->info) {
|
||||
struct pbr_interface *pbr_ifp;
|
||||
|
||||
pbr_ifp = pbr_if_new(ifp);
|
||||
ifp->info = pbr_ifp;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int interface_delete(int command, struct zclient *zclient,
|
||||
zebra_size_t length, vrf_id_t vrf_id)
|
||||
{
|
||||
struct interface *ifp;
|
||||
struct stream *s;
|
||||
|
||||
s = zclient->ibuf;
|
||||
/* zebra_interface_state_read () updates interface structure in iflist
|
||||
*/
|
||||
ifp = zebra_interface_state_read(s, vrf_id);
|
||||
|
||||
if (ifp == NULL)
|
||||
return 0;
|
||||
|
||||
if_set_index(ifp, IFINDEX_INTERNAL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int interface_address_add(int command, struct zclient *zclient,
|
||||
zebra_size_t length, vrf_id_t vrf_id)
|
||||
{
|
||||
zebra_interface_address_read(command, zclient->ibuf, vrf_id);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int interface_address_delete(int command, struct zclient *zclient,
|
||||
zebra_size_t length, vrf_id_t vrf_id)
|
||||
{
|
||||
struct connected *c;
|
||||
|
||||
c = zebra_interface_address_read(command, zclient->ibuf, vrf_id);
|
||||
|
||||
if (!c)
|
||||
return 0;
|
||||
|
||||
connected_free(c);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int interface_state_up(int command, struct zclient *zclient,
|
||||
zebra_size_t length, vrf_id_t vrf_id)
|
||||
{
|
||||
|
||||
zebra_interface_if_lookup(zclient->ibuf);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int interface_state_down(int command, struct zclient *zclient,
|
||||
zebra_size_t length, vrf_id_t vrf_id)
|
||||
{
|
||||
|
||||
zebra_interface_state_read(zclient->ibuf, vrf_id);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int route_notify_owner(int command, struct zclient *zclient,
|
||||
zebra_size_t length, vrf_id_t vrf_id)
|
||||
{
|
||||
struct prefix p;
|
||||
enum zapi_route_notify_owner note;
|
||||
uint32_t table_id;
|
||||
char buf[PREFIX_STRLEN];
|
||||
|
||||
prefix2str(&p, buf, sizeof(buf));
|
||||
|
||||
if (!zapi_route_notify_decode(zclient->ibuf, &p, &table_id, ¬e))
|
||||
return -1;
|
||||
|
||||
switch (note) {
|
||||
case ZAPI_ROUTE_FAIL_INSTALL:
|
||||
DEBUGD(&pbr_dbg_zebra,
|
||||
"%s: [%s] Route install failure for table: %u",
|
||||
__PRETTY_FUNCTION__, buf, table_id);
|
||||
break;
|
||||
case ZAPI_ROUTE_BETTER_ADMIN_WON:
|
||||
DEBUGD(&pbr_dbg_zebra,
|
||||
"%s: [%s] Route better admin distance won for table: %u",
|
||||
__PRETTY_FUNCTION__, buf, table_id);
|
||||
break;
|
||||
case ZAPI_ROUTE_INSTALLED:
|
||||
DEBUGD(&pbr_dbg_zebra,
|
||||
"%s: [%s] Route installed succeeded for table: %u",
|
||||
__PRETTY_FUNCTION__, buf, table_id);
|
||||
pbr_nht_route_installed_for_table(table_id);
|
||||
break;
|
||||
case ZAPI_ROUTE_REMOVED:
|
||||
DEBUGD(&pbr_dbg_zebra,
|
||||
"%s: [%s] Route Removed succeeded for table: %u",
|
||||
__PRETTY_FUNCTION__, buf, table_id);
|
||||
pbr_nht_route_removed_for_table(table_id);
|
||||
break;
|
||||
case ZAPI_ROUTE_REMOVE_FAIL:
|
||||
DEBUGD(&pbr_dbg_zebra,
|
||||
"%s: [%s] Route remove fail for table: %u",
|
||||
__PRETTY_FUNCTION__, buf, table_id);
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rule_notify_owner(int command, struct zclient *zclient,
|
||||
zebra_size_t length, vrf_id_t vrf_id)
|
||||
{
|
||||
uint32_t seqno, priority, unique;
|
||||
enum zapi_rule_notify_owner note;
|
||||
struct pbr_map_sequence *pbrms;
|
||||
ifindex_t ifi;
|
||||
|
||||
if (!zapi_rule_notify_decode(zclient->ibuf, &seqno, &priority, &unique,
|
||||
&ifi, ¬e))
|
||||
return -1;
|
||||
|
||||
pbrms = pbrms_lookup_unique(unique, ifi);
|
||||
if (!pbrms) {
|
||||
DEBUGD(&pbr_dbg_zebra,
|
||||
"%s: Failure to lookup pbrms based upon %u",
|
||||
__PRETTY_FUNCTION__, unique);
|
||||
return 0;
|
||||
}
|
||||
|
||||
switch (note) {
|
||||
case ZAPI_RULE_FAIL_INSTALL:
|
||||
DEBUGD(&pbr_dbg_zebra, "%s: Recieved RULE_FAIL_INSTALL",
|
||||
__PRETTY_FUNCTION__);
|
||||
pbrms->installed = false;
|
||||
break;
|
||||
case ZAPI_RULE_INSTALLED:
|
||||
pbrms->installed = true;
|
||||
DEBUGD(&pbr_dbg_zebra, "%s: Recived RULE_INSTALLED",
|
||||
__PRETTY_FUNCTION__);
|
||||
break;
|
||||
case ZAPI_RULE_REMOVED:
|
||||
DEBUGD(&pbr_dbg_zebra, "%s: Received RULE REMOVED",
|
||||
__PRETTY_FUNCTION__);
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void zebra_connected(struct zclient *zclient)
|
||||
{
|
||||
zclient_send_reg_requests(zclient, VRF_DEFAULT);
|
||||
}
|
||||
|
||||
static void route_add_helper(struct zapi_route *api, struct nexthop_group nhg,
|
||||
uint8_t install_afi)
|
||||
{
|
||||
struct zapi_nexthop *api_nh;
|
||||
struct nexthop *nhop;
|
||||
int i;
|
||||
|
||||
api->prefix.family = install_afi;
|
||||
|
||||
i = 0;
|
||||
for (ALL_NEXTHOPS(nhg, nhop)) {
|
||||
api_nh = &api->nexthops[i];
|
||||
api_nh->vrf_id = nhop->vrf_id;
|
||||
api_nh->type = nhop->type;
|
||||
switch (nhop->type) {
|
||||
case NEXTHOP_TYPE_IPV4:
|
||||
api_nh->gate.ipv4 = nhop->gate.ipv4;
|
||||
break;
|
||||
case NEXTHOP_TYPE_IPV4_IFINDEX:
|
||||
api_nh->gate.ipv4 = nhop->gate.ipv4;
|
||||
api_nh->ifindex = nhop->ifindex;
|
||||
break;
|
||||
case NEXTHOP_TYPE_IFINDEX:
|
||||
api_nh->ifindex = nhop->ifindex;
|
||||
break;
|
||||
case NEXTHOP_TYPE_IPV6:
|
||||
memcpy(&api_nh->gate.ipv6, &nhop->gate.ipv6, 16);
|
||||
break;
|
||||
case NEXTHOP_TYPE_IPV6_IFINDEX:
|
||||
api_nh->ifindex = nhop->ifindex;
|
||||
memcpy(&api_nh->gate.ipv6, &nhop->gate.ipv6, 16);
|
||||
break;
|
||||
case NEXTHOP_TYPE_BLACKHOLE:
|
||||
api_nh->bh_type = nhop->bh_type;
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
api->nexthop_num = i;
|
||||
|
||||
zclient_route_send(ZEBRA_ROUTE_ADD, zclient, api);
|
||||
}
|
||||
|
||||
/*
|
||||
* This function assumes a default route is being
|
||||
* installed into the appropriate tableid
|
||||
*/
|
||||
void route_add(struct pbr_nexthop_group_cache *pnhgc, struct nexthop_group nhg,
|
||||
afi_t install_afi)
|
||||
{
|
||||
struct zapi_route api;
|
||||
|
||||
memset(&api, 0, sizeof(api));
|
||||
|
||||
api.vrf_id = VRF_DEFAULT;
|
||||
api.type = ZEBRA_ROUTE_PBR;
|
||||
api.safi = SAFI_UNICAST;
|
||||
/*
|
||||
* Sending a default route
|
||||
*/
|
||||
api.tableid = pnhgc->table_id;
|
||||
SET_FLAG(api.flags, ZEBRA_FLAG_ALLOW_RECURSION);
|
||||
SET_FLAG(api.message, ZAPI_MESSAGE_TABLEID);
|
||||
SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP);
|
||||
switch (install_afi) {
|
||||
case AFI_MAX:
|
||||
route_add_helper(&api, nhg, AF_INET);
|
||||
route_add_helper(&api, nhg, AF_INET6);
|
||||
break;
|
||||
case AFI_IP:
|
||||
route_add_helper(&api, nhg, AF_INET);
|
||||
break;
|
||||
case AFI_IP6:
|
||||
route_add_helper(&api, nhg, AF_INET6);
|
||||
break;
|
||||
case AFI_L2VPN:
|
||||
DEBUGD(&pbr_dbg_zebra,
|
||||
"%s: Asked to install unsupported route type: L2VPN",
|
||||
__PRETTY_FUNCTION__);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* This function assumes a default route is being
|
||||
* removed from the appropriate tableid
|
||||
*/
|
||||
void route_delete(struct pbr_nexthop_group_cache *pnhgc, afi_t afi)
|
||||
{
|
||||
struct zapi_route api;
|
||||
|
||||
memset(&api, 0, sizeof(api));
|
||||
api.vrf_id = VRF_DEFAULT;
|
||||
api.type = ZEBRA_ROUTE_PBR;
|
||||
api.safi = SAFI_UNICAST;
|
||||
|
||||
api.tableid = pnhgc->table_id;
|
||||
SET_FLAG(api.message, ZAPI_MESSAGE_TABLEID);
|
||||
|
||||
switch (afi) {
|
||||
case AFI_IP:
|
||||
api.prefix.family = AF_INET;
|
||||
zclient_route_send(ZEBRA_ROUTE_DELETE, zclient, &api);
|
||||
break;
|
||||
case AFI_IP6:
|
||||
api.prefix.family = AF_INET6;
|
||||
zclient_route_send(ZEBRA_ROUTE_DELETE, zclient, &api);
|
||||
break;
|
||||
case AFI_MAX:
|
||||
api.prefix.family = AF_INET;
|
||||
zclient_route_send(ZEBRA_ROUTE_DELETE, zclient, &api);
|
||||
api.prefix.family = AF_INET6;
|
||||
zclient_route_send(ZEBRA_ROUTE_DELETE, zclient, &api);
|
||||
break;
|
||||
case AFI_L2VPN:
|
||||
DEBUGD(&pbr_dbg_zebra,
|
||||
"%s: Asked to delete unsupported route type: L2VPN",
|
||||
__PRETTY_FUNCTION__);
|
||||
break;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static int pbr_zebra_nexthop_update(int command, struct zclient *zclient,
|
||||
zebra_size_t length, vrf_id_t vrf_id)
|
||||
{
|
||||
struct zapi_route nhr;
|
||||
char buf[PREFIX2STR_BUFFER];
|
||||
uint32_t i;
|
||||
|
||||
zapi_nexthop_update_decode(zclient->ibuf, &nhr);
|
||||
|
||||
if (DEBUG_MODE_CHECK(&pbr_dbg_zebra, DEBUG_MODE_ALL)) {
|
||||
|
||||
DEBUGD(&pbr_dbg_zebra, "%s: Received Nexthop update: %s",
|
||||
__PRETTY_FUNCTION__,
|
||||
prefix2str(&nhr.prefix, buf, sizeof(buf)));
|
||||
|
||||
DEBUGD(&pbr_dbg_zebra, "%s: (\tNexthops(%u)",
|
||||
__PRETTY_FUNCTION__, nhr.nexthop_num);
|
||||
|
||||
for (i = 0; i < nhr.nexthop_num; i++) {
|
||||
DEBUGD(&pbr_dbg_zebra,
|
||||
"%s: \tType: %d: vrf: %d, ifindex: %d gate: %s",
|
||||
__PRETTY_FUNCTION__, nhr.nexthops[i].type,
|
||||
nhr.nexthops[i].vrf_id, nhr.nexthops[i].ifindex,
|
||||
inet_ntoa(nhr.nexthops[i].gate.ipv4));
|
||||
}
|
||||
}
|
||||
|
||||
pbr_nht_nexthop_update(&nhr);
|
||||
return 1;
|
||||
}
|
||||
|
||||
extern struct zebra_privs_t pbr_privs;
|
||||
|
||||
void pbr_zebra_init(void)
|
||||
{
|
||||
struct zclient_options opt = { .receive_notify = true };
|
||||
|
||||
zclient = zclient_new_notify(master, &opt);
|
||||
|
||||
zclient_init(zclient, ZEBRA_ROUTE_PBR, 0, &pbr_privs);
|
||||
zclient->zebra_connected = zebra_connected;
|
||||
zclient->interface_add = interface_add;
|
||||
zclient->interface_delete = interface_delete;
|
||||
zclient->interface_up = interface_state_up;
|
||||
zclient->interface_down = interface_state_down;
|
||||
zclient->interface_address_add = interface_address_add;
|
||||
zclient->interface_address_delete = interface_address_delete;
|
||||
zclient->route_notify_owner = route_notify_owner;
|
||||
zclient->rule_notify_owner = rule_notify_owner;
|
||||
zclient->nexthop_update = pbr_zebra_nexthop_update;
|
||||
}
|
||||
|
||||
void pbr_send_rnh(struct nexthop *nhop, bool reg)
|
||||
{
|
||||
uint32_t command;
|
||||
struct prefix p;
|
||||
|
||||
command = (reg) ?
|
||||
ZEBRA_NEXTHOP_REGISTER : ZEBRA_NEXTHOP_UNREGISTER;
|
||||
|
||||
memset(&p, 0, sizeof(p));
|
||||
switch(nhop->type) {
|
||||
case NEXTHOP_TYPE_IFINDEX:
|
||||
case NEXTHOP_TYPE_BLACKHOLE:
|
||||
return;
|
||||
case NEXTHOP_TYPE_IPV4:
|
||||
case NEXTHOP_TYPE_IPV4_IFINDEX:
|
||||
p.family = AF_INET;
|
||||
p.u.prefix4.s_addr = nhop->gate.ipv4.s_addr;
|
||||
p.prefixlen = 32;
|
||||
break;
|
||||
case NEXTHOP_TYPE_IPV6:
|
||||
case NEXTHOP_TYPE_IPV6_IFINDEX:
|
||||
p.family = AF_INET6;
|
||||
memcpy(&p.u.prefix6, &nhop->gate.ipv6, 16);
|
||||
p.prefixlen = 128;
|
||||
break;
|
||||
}
|
||||
|
||||
if (zclient_send_rnh(zclient, command, &p,
|
||||
false, nhop->vrf_id) < 0) {
|
||||
zlog_warn("%s: Failure to send nexthop to zebra",
|
||||
__PRETTY_FUNCTION__);
|
||||
}
|
||||
}
|
||||
|
||||
static void pbr_encode_pbr_map_sequence_prefix(struct stream *s,
|
||||
struct prefix *p,
|
||||
u_char family)
|
||||
{
|
||||
struct prefix any;
|
||||
|
||||
if (!p) {
|
||||
memset(&any, 0, sizeof(any));
|
||||
any.family = family;
|
||||
p = &any;
|
||||
}
|
||||
|
||||
stream_putc(s, p->family);
|
||||
stream_putc(s, p->prefixlen);
|
||||
stream_put(s, &p->u.prefix, prefix_blen(p));
|
||||
}
|
||||
|
||||
static void pbr_encode_pbr_map_sequence(struct stream *s,
|
||||
struct pbr_map_sequence *pbrms,
|
||||
struct interface *ifp)
|
||||
{
|
||||
u_char family;
|
||||
|
||||
family = AF_INET;
|
||||
if (pbrms->src)
|
||||
family = pbrms->src->family;
|
||||
|
||||
if (pbrms->dst)
|
||||
family = pbrms->dst->family;
|
||||
|
||||
stream_putl(s, pbrms->seqno);
|
||||
stream_putl(s, pbrms->ruleno);
|
||||
stream_putl(s, pbrms->unique);
|
||||
pbr_encode_pbr_map_sequence_prefix(s, pbrms->src, family);
|
||||
stream_putw(s, 0); /* src port */
|
||||
pbr_encode_pbr_map_sequence_prefix(s, pbrms->dst, family);
|
||||
stream_putw(s, 0); /* dst port */
|
||||
if (pbrms->nhgrp_name)
|
||||
stream_putl(s, pbr_nht_get_table(pbrms->nhgrp_name));
|
||||
else if (pbrms->nhg)
|
||||
stream_putl(s, pbr_nht_get_table(pbrms->internal_nhg_name));
|
||||
stream_putl(s, ifp->ifindex);
|
||||
}
|
||||
|
||||
void pbr_send_pbr_map(struct pbr_map *pbrm, bool install)
|
||||
{
|
||||
struct listnode *inode, *snode;
|
||||
struct pbr_map_sequence *pbrms;
|
||||
struct pbr_map_interface *pmi;
|
||||
struct stream *s;
|
||||
uint32_t total;
|
||||
ssize_t tspot;
|
||||
|
||||
DEBUGD(&pbr_dbg_zebra, "%s: for %s %d", __PRETTY_FUNCTION__, pbrm->name,
|
||||
install);
|
||||
|
||||
s = zclient->obuf;
|
||||
stream_reset(s);
|
||||
|
||||
zclient_create_header(s,
|
||||
install ? ZEBRA_RULE_ADD : ZEBRA_RULE_DELETE,
|
||||
VRF_DEFAULT);
|
||||
|
||||
total = 0;
|
||||
tspot = stream_get_endp(s);
|
||||
stream_putl(s, 0);
|
||||
for (ALL_LIST_ELEMENTS_RO(pbrm->incoming, inode, pmi)) {
|
||||
|
||||
DEBUGD(&pbr_dbg_zebra, "%s: \t%s %s %d %s %u",
|
||||
__PRETTY_FUNCTION__, install ? "Installing" : "Deleting",
|
||||
pbrm->name, install, pmi->ifp->name, pmi->delete);
|
||||
|
||||
if (!install && pmi->delete) {
|
||||
for (ALL_LIST_ELEMENTS_RO(pbrm->seqnumbers, snode,
|
||||
pbrms)) {
|
||||
pbr_encode_pbr_map_sequence(s,
|
||||
pbrms, pmi->ifp);
|
||||
total++;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
for (ALL_LIST_ELEMENTS_RO(pbrm->seqnumbers, snode, pbrms)) {
|
||||
|
||||
DEBUGD(&pbr_dbg_zebra, "%s: \tSeqno: %u %ld valid %u",
|
||||
__PRETTY_FUNCTION__, pbrms->seqno, pbrms->reason,
|
||||
pbrm->valid);
|
||||
|
||||
if (!install &&
|
||||
!(pbrms->reason & PBR_MAP_DEL_SEQUENCE_NUMBER))
|
||||
continue;
|
||||
|
||||
if (!install && !pbrms->installed)
|
||||
continue;
|
||||
|
||||
if (install && pbrms->installed)
|
||||
continue;
|
||||
|
||||
DEBUGD(&pbr_dbg_zebra, "%s: \t Seq: %u ifp %s",
|
||||
__PRETTY_FUNCTION__, pbrms->seqno,
|
||||
pmi->ifp->name);
|
||||
|
||||
pbr_encode_pbr_map_sequence(s, pbrms, pmi->ifp);
|
||||
total++;
|
||||
}
|
||||
}
|
||||
|
||||
DEBUGD(&pbr_dbg_zebra, "%s: Putting %u at %zu ", __PRETTY_FUNCTION__,
|
||||
total, tspot);
|
||||
|
||||
stream_putl_at(s, tspot, total);
|
||||
stream_putw_at(s, 0, stream_get_endp(s));
|
||||
|
||||
if (!total) {
|
||||
stream_reset(s);
|
||||
return;
|
||||
}
|
||||
zclient_send_message(zclient);
|
||||
}
|
37
pbrd/pbr_zebra.h
Normal file
37
pbrd/pbr_zebra.h
Normal file
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* Zebra connect library for PBR
|
||||
* 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
|
||||
*/
|
||||
#ifndef __PBR_ZEBRA_H__
|
||||
#define __PBR_ZEBRA_H__
|
||||
|
||||
struct pbr_interface {
|
||||
char mapname[100];
|
||||
};
|
||||
|
||||
extern void pbr_zebra_init(void);
|
||||
|
||||
extern void route_add(struct pbr_nexthop_group_cache *pnhgc,
|
||||
struct nexthop_group nhg, afi_t install_afi);
|
||||
extern void route_delete(struct pbr_nexthop_group_cache *pnhgc,
|
||||
afi_t install_afi);
|
||||
|
||||
extern void pbr_send_rnh(struct nexthop *nhop, bool reg);
|
||||
|
||||
extern void pbr_send_pbr_map(struct pbr_map *pbrm, bool install);
|
||||
#endif
|
3
pbrd/pbrd.conf.sample
Normal file
3
pbrd/pbrd.conf.sample
Normal file
|
@ -0,0 +1,3 @@
|
|||
!
|
||||
!
|
||||
log stdout
|
39
pbrd/subdir.am
Normal file
39
pbrd/subdir.am
Normal file
|
@ -0,0 +1,39 @@
|
|||
#
|
||||
# pbrd
|
||||
#
|
||||
|
||||
if PBRD
|
||||
noinst_LIBRARIES += pbrd/libpbr.a
|
||||
sbin_PROGRAMS += pbrd/pbrd
|
||||
dist_examples_DATA += pbrd/pbrd.conf.sample
|
||||
endif
|
||||
|
||||
pbrd_libpbr_a_SOURCES = \
|
||||
pbrd/pbr_zebra.c \
|
||||
pbrd/pbr_vty.c \
|
||||
pbrd/pbr_map.c \
|
||||
pbrd/pbr_memory.c \
|
||||
pbrd/pbr_nht.c \
|
||||
pbrd/pbr_event.c \
|
||||
pbrd/pbr_debug.c \
|
||||
# end
|
||||
|
||||
noinst_HEADERS += \
|
||||
pbrd/pbr_event.h \
|
||||
pbrd/pbr_map.h \
|
||||
pbrd/pbr_memory.h \
|
||||
pbrd/pbr_nht.h \
|
||||
pbrd/pbr_vty.h \
|
||||
pbrd/pbr_zebra.h \
|
||||
pbrd/pbr_debug.h \
|
||||
# end
|
||||
|
||||
pbrd/pbr_vty_clippy.c: $(CLIPPY_DEPS)
|
||||
pbrd/pbr_vty.$(OBJEXT): pbrd/pbr_vty_clippy.c
|
||||
|
||||
pbrd/pbr_debug_clippy.c: $(CLIPPY_DEPS)
|
||||
pbrd/pbr_debug.$(OBJEXT): pbrd/pbr_debug_clippy.c
|
||||
|
||||
pbrd_pbrd_SOURCES = pbrd/pbr_main.c
|
||||
pbrd_pbrd_LDADD = pbrd/libpbr.a lib/libfrr.la @LIBCAP@
|
||||
|
|
@ -50,6 +50,7 @@ nhrpd=no
|
|||
eigrpd=no
|
||||
babeld=no
|
||||
sharpd=no
|
||||
pbrd=no
|
||||
#
|
||||
# Command line options for the daemons
|
||||
#
|
||||
|
@ -66,6 +67,7 @@ nhrpd_options=("-A 127.0.0.1")
|
|||
eigrpd_options=("-A 127.0.0.1")
|
||||
babeld_options=("-A 127.0.0.1")
|
||||
sharpd_options=("-A 127.0.0.1")
|
||||
pbrd_options=("-A 127.0.0.1")
|
||||
|
||||
#
|
||||
# If the vtysh_enable is yes, then the unified config is read
|
||||
|
|
|
@ -86,7 +86,7 @@
|
|||
%{!?frr_gid: %global frr_gid 92 }
|
||||
%{!?vty_gid: %global vty_gid 85 }
|
||||
|
||||
%define daemon_list zebra ripd ospfd bgpd isisd ripngd ospf6d
|
||||
%define daemon_list zebra ripd ospfd bgpd isisd ripngd ospf6d pbrd
|
||||
|
||||
%if %{with_ldpd}
|
||||
%define daemon_ldpd ldpd
|
||||
|
|
|
@ -34,3 +34,4 @@ nhrpd=no
|
|||
eigrpd=no
|
||||
babeld=no
|
||||
sharpd=no
|
||||
pbrd=no
|
||||
|
|
|
@ -17,6 +17,7 @@ nhrpd_options=" --daemon -A 127.0.0.1"
|
|||
eigrpd_options=" --daemon -A 127.0.0.1"
|
||||
babeld_options=" --daemon -A 127.0.0.1"
|
||||
sharpd_options=" --daemon -A 127.0.0.1"
|
||||
pbrd_options=" --daemon -A 127.0.0.1"
|
||||
|
||||
# The list of daemons to watch is automatically generated by the init script.
|
||||
watchfrr_enable=yes
|
||||
|
|
|
@ -21,7 +21,7 @@ V_PATH=/var/run/frr
|
|||
# Local Daemon selection may be done by using /etc/frr/daemons.
|
||||
# See /usr/share/doc/frr/README.Debian.gz for further information.
|
||||
# Keep zebra first and do not list watchfrr!
|
||||
DAEMONS="zebra bgpd ripd ripngd ospfd ospf6d isisd babeld pimd ldpd nhrpd eigrpd sharpd"
|
||||
DAEMONS="zebra bgpd ripd ripngd ospfd ospf6d isisd babeld pimd ldpd nhrpd eigrpd sharpd pbrd"
|
||||
MAX_INSTANCES=5
|
||||
RELOAD_SCRIPT=/usr/lib/frr/frr-reload.py
|
||||
|
||||
|
|
|
@ -141,6 +141,11 @@ if SNMP
|
|||
vtysh_scan += $(top_srcdir)/lib/agentx.c
|
||||
endif
|
||||
|
||||
if PBRD
|
||||
vtysh_scan += $(top_srcdir)/pbrd/pbr_vty.c
|
||||
vtysh_scan += $(top_srcdir)/pbrd/pbr_debug.c
|
||||
endif
|
||||
|
||||
vtysh_cmd_FILES = $(vtysh_scan) \
|
||||
$(top_srcdir)/lib/keychain.c $(top_srcdir)/lib/routemap.c \
|
||||
$(top_srcdir)/lib/filter.c $(top_srcdir)/lib/plist.c \
|
||||
|
@ -148,6 +153,7 @@ vtysh_cmd_FILES = $(vtysh_scan) \
|
|||
$(top_srcdir)/lib/vrf.c \
|
||||
$(top_srcdir)/lib/vty.c $(top_srcdir)/zebra/debug.c \
|
||||
$(top_srcdir)/lib/logicalrouter.c \
|
||||
$(top_srcdir)/lib/nexthop_group.c \
|
||||
$(top_srcdir)/zebra/interface.c \
|
||||
$(top_srcdir)/zebra/irdp_interface.c \
|
||||
$(top_srcdir)/zebra/rtadv.c $(top_srcdir)/zebra/zebra_vty.c \
|
||||
|
|
|
@ -99,6 +99,9 @@ foreach (@ARGV) {
|
|||
elsif ($file =~ /lib\/ns\.c$/) {
|
||||
$protocol = "VTYSH_ZEBRA";
|
||||
}
|
||||
elsif ($file =~ /lib\/nexthop_group\.c$/) {
|
||||
$protocol = "VTYSH_PBRD";
|
||||
}
|
||||
elsif ($file =~ /lib\/plist\.c$/) {
|
||||
if ($defun_array[1] =~ m/ipv6/) {
|
||||
$protocol = "VTYSH_RIPNGD|VTYSH_OSPF6D|VTYSH_BGPD|VTYSH_ZEBRA|VTYSH_BABELD|VTYSH_ISISD";
|
||||
|
|
|
@ -79,6 +79,7 @@ struct vtysh_client vtysh_client[] = {
|
|||
{.fd = -1, .name = "babeld", .flag = VTYSH_BABELD, .next = NULL},
|
||||
{.fd = -1, .name = "sharpd", .flag = VTYSH_SHARPD, .next = NULL},
|
||||
{.fd = -1, .name = "watchfrr", .flag = VTYSH_WATCHFRR, .next = NULL},
|
||||
{.fd = -1, .name = "pbrd", .flag = VTYSH_PBRD, .next = NULL},
|
||||
};
|
||||
|
||||
enum vtysh_write_integrated vtysh_write_integrated =
|
||||
|
@ -997,8 +998,15 @@ static struct cmd_node vrf_node = {
|
|||
VRF_NODE, "%s(config-vrf)# ",
|
||||
};
|
||||
|
||||
static struct cmd_node nh_group_node = {
|
||||
NH_GROUP_NODE,
|
||||
"%s(config-nh-group)# ",
|
||||
};
|
||||
|
||||
static struct cmd_node rmap_node = {RMAP_NODE, "%s(config-route-map)# "};
|
||||
|
||||
static struct cmd_node pbr_map_node = {PBRMAP_NODE, "%s(config-pbr-map)# "};
|
||||
|
||||
static struct cmd_node zebra_node = {ZEBRA_NODE, "%s(config-router)# "};
|
||||
|
||||
static struct cmd_node bgp_vpnv4_node = {BGP_VPNV4_NODE,
|
||||
|
@ -1504,6 +1512,24 @@ DEFUNSH(VTYSH_RMAP, vtysh_route_map, vtysh_route_map_cmd,
|
|||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUNSH(VTYSH_PBRD, vtysh_pbr_map, vtysh_pbr_map_cmd,
|
||||
"pbr-map NAME seq (1-1000)",
|
||||
"Create pbr-map or enter pbr-map command mode\n"
|
||||
"The name of the PBR MAP\n"
|
||||
"Sequence to insert to/delete from existing pbr-map entry\n"
|
||||
"Sequence number\n")
|
||||
{
|
||||
vty->node = PBRMAP_NODE;
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFSH(VTYSH_PBRD, vtysh_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")
|
||||
|
||||
DEFUNSH(VTYSH_ALL, vtysh_line_vty, vtysh_line_vty_cmd, "line vty",
|
||||
"Configure a terminal line\n"
|
||||
"Virtual terminal\n")
|
||||
|
@ -1563,6 +1589,7 @@ static int vtysh_exit(struct vty *vty)
|
|||
case LDP_L2VPN_NODE:
|
||||
case ISIS_NODE:
|
||||
case RMAP_NODE:
|
||||
case PBRMAP_NODE:
|
||||
case VTY_NODE:
|
||||
case KEYCHAIN_NODE:
|
||||
vtysh_execute("end");
|
||||
|
@ -1709,6 +1736,18 @@ DEFUNSH(VTYSH_RMAP, vtysh_quit_rmap, vtysh_quit_rmap_cmd, "quit",
|
|||
return vtysh_exit_rmap(self, vty, argc, argv);
|
||||
}
|
||||
|
||||
DEFUNSH(VTYSH_PBRD, vtysh_exit_pbr_map, vtysh_exit_pbr_map_cmd, "exit",
|
||||
"Exit current mode and down to previous mode\n")
|
||||
{
|
||||
return vtysh_exit(vty);
|
||||
}
|
||||
|
||||
DEFUNSH(VTYSH_PBRD, vtysh_quit_pbr_map, vtysh_quit_pbr_map_cmd, "quit",
|
||||
"Exit current mode and down to previous mode\n")
|
||||
{
|
||||
return vtysh_exit_rmap(self, vty, argc, argv);
|
||||
}
|
||||
|
||||
DEFUNSH(VTYSH_BGPD, vtysh_exit_bgpd, vtysh_exit_bgpd_cmd, "exit",
|
||||
"Exit current mode and down to previous mode\n")
|
||||
{
|
||||
|
@ -1852,6 +1891,20 @@ DEFSH(VTYSH_ZEBRA, vtysh_no_logicalrouter_cmd,
|
|||
"The Name Space\n"
|
||||
"The file name in " NS_RUN_DIR ", or a full pathname\n")
|
||||
|
||||
DEFUNSH(VTYSH_PBRD, vtysh_nexthop_group, vtysh_nexthop_group_cmd,
|
||||
"nexthop-group NAME",
|
||||
"Nexthop Group configuration\n"
|
||||
"Name of the Nexthop Group\n")
|
||||
{
|
||||
vty->node = NH_GROUP_NODE;
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFSH(VTYSH_PBRD, vtysh_no_nexthop_group_cmd, "no nexthop-group NAME",
|
||||
NO_STR
|
||||
"Nexthop Group Configuration\n"
|
||||
"Name of the Nexthop Group\n")
|
||||
|
||||
DEFUNSH(VTYSH_VRF, vtysh_vrf, vtysh_vrf_cmd, "vrf NAME",
|
||||
"Select a VRF to configure\n"
|
||||
"VRF's name\n")
|
||||
|
@ -1890,6 +1943,18 @@ DEFUNSH(VTYSH_VRF, vtysh_quit_vrf, vtysh_quit_vrf_cmd, "quit",
|
|||
return vtysh_exit_vrf(self, vty, argc, argv);
|
||||
}
|
||||
|
||||
DEFUNSH(VTYSH_PBRD, vtysh_exit_nexthop_group, vtysh_exit_nexthop_group_cmd,
|
||||
"exit", "Exit current mode and down to previous mode\n")
|
||||
{
|
||||
return vtysh_exit(vty);
|
||||
}
|
||||
|
||||
DEFUNSH(VTYSH_VRF, vtysh_quit_nexthop_group, vtysh_quit_nexthop_group_cmd,
|
||||
"quit", "Exit current mode and down to previous mode\n")
|
||||
{
|
||||
return vtysh_exit_nexthop_group(self, vty, argc, argv);
|
||||
}
|
||||
|
||||
/* TODO Implement interface description commands in ripngd, ospf6d
|
||||
* and isisd. */
|
||||
DEFSH(VTYSH_ZEBRA | VTYSH_RIPD | VTYSH_OSPFD | VTYSH_EIGRPD,
|
||||
|
@ -1965,7 +2030,7 @@ DEFUN (vtysh_show_work_queues,
|
|||
|
||||
DEFUN (vtysh_show_work_queues_daemon,
|
||||
vtysh_show_work_queues_daemon_cmd,
|
||||
"show work-queues <zebra|ripd|ripngd|ospfd|ospf6d|bgpd|isisd>",
|
||||
"show work-queues <zebra|ripd|ripngd|ospfd|ospf6d|bgpd|isisd|pbrd>",
|
||||
SHOW_STR
|
||||
"Work Queue information\n"
|
||||
"For the zebra daemon\n"
|
||||
|
@ -1974,7 +2039,8 @@ DEFUN (vtysh_show_work_queues_daemon,
|
|||
"For the ospf daemon\n"
|
||||
"For the ospfv6 daemon\n"
|
||||
"For the bgp daemon\n"
|
||||
"For the isis daemon\n")
|
||||
"For the isis daemon\n"
|
||||
"For the pbr daemon\n")
|
||||
{
|
||||
int idx_protocol = 2;
|
||||
unsigned int i;
|
||||
|
@ -3130,7 +3196,9 @@ void vtysh_init_vty(void)
|
|||
install_node(&link_params_node, NULL);
|
||||
install_node(&logicalrouter_node, NULL);
|
||||
install_node(&vrf_node, NULL);
|
||||
install_node(&nh_group_node, NULL);
|
||||
install_node(&rmap_node, NULL);
|
||||
install_node(&pbr_map_node, NULL);
|
||||
install_node(&zebra_node, NULL);
|
||||
install_node(&bgp_vpnv4_node, NULL);
|
||||
install_node(&bgp_vpnv6_node, NULL);
|
||||
|
@ -3259,6 +3327,8 @@ void vtysh_init_vty(void)
|
|||
install_element(KEYCHAIN_KEY_NODE, &vtysh_quit_ripd_cmd);
|
||||
install_element(RMAP_NODE, &vtysh_exit_rmap_cmd);
|
||||
install_element(RMAP_NODE, &vtysh_quit_rmap_cmd);
|
||||
install_element(PBRMAP_NODE, &vtysh_exit_pbr_map_cmd);
|
||||
install_element(PBRMAP_NODE, &vtysh_quit_pbr_map_cmd);
|
||||
install_element(VTY_NODE, &vtysh_exit_line_vty_cmd);
|
||||
install_element(VTY_NODE, &vtysh_quit_line_vty_cmd);
|
||||
|
||||
|
@ -3299,6 +3369,7 @@ void vtysh_init_vty(void)
|
|||
install_element(KEYCHAIN_NODE, &vtysh_end_all_cmd);
|
||||
install_element(KEYCHAIN_KEY_NODE, &vtysh_end_all_cmd);
|
||||
install_element(RMAP_NODE, &vtysh_end_all_cmd);
|
||||
install_element(PBRMAP_NODE, &vtysh_end_all_cmd);
|
||||
install_element(VTY_NODE, &vtysh_end_all_cmd);
|
||||
|
||||
install_element(INTERFACE_NODE, &vtysh_interface_desc_cmd);
|
||||
|
@ -3321,6 +3392,11 @@ void vtysh_init_vty(void)
|
|||
install_element(LOGICALROUTER_NODE, &vtysh_exit_logicalrouter_cmd);
|
||||
install_element(LOGICALROUTER_NODE, &vtysh_quit_logicalrouter_cmd);
|
||||
|
||||
install_element(CONFIG_NODE, &vtysh_nexthop_group_cmd);
|
||||
install_element(NH_GROUP_NODE, &vtysh_end_all_cmd);
|
||||
install_element(NH_GROUP_NODE, &vtysh_exit_nexthop_group_cmd);
|
||||
install_element(NH_GROUP_NODE, &vtysh_quit_nexthop_group_cmd);
|
||||
|
||||
install_element(VRF_NODE, &vtysh_end_all_cmd);
|
||||
install_element(VRF_NODE, &vtysh_exit_vrf_cmd);
|
||||
install_element(VRF_NODE, &vtysh_quit_vrf_cmd);
|
||||
|
@ -3394,6 +3470,8 @@ void vtysh_init_vty(void)
|
|||
|
||||
install_element(CONFIG_NODE, &key_chain_cmd);
|
||||
install_element(CONFIG_NODE, &vtysh_route_map_cmd);
|
||||
install_element(CONFIG_NODE, &vtysh_pbr_map_cmd);
|
||||
install_element(CONFIG_NODE, &vtysh_no_pbr_map_cmd);
|
||||
install_element(CONFIG_NODE, &vtysh_line_vty_cmd);
|
||||
install_element(KEYCHAIN_NODE, &key_cmd);
|
||||
install_element(KEYCHAIN_NODE, &key_chain_cmd);
|
||||
|
@ -3410,6 +3488,7 @@ void vtysh_init_vty(void)
|
|||
|
||||
install_element(CONFIG_NODE, &vtysh_vrf_cmd);
|
||||
install_element(CONFIG_NODE, &vtysh_no_vrf_cmd);
|
||||
install_element(CONFIG_NODE, &vtysh_no_nexthop_group_cmd);
|
||||
|
||||
/* "write terminal" command. */
|
||||
install_element(ENABLE_NODE, &vtysh_write_terminal_cmd);
|
||||
|
|
|
@ -24,29 +24,30 @@
|
|||
#include "memory.h"
|
||||
DECLARE_MGROUP(MVTYSH)
|
||||
|
||||
#define VTYSH_ZEBRA 0x01
|
||||
#define VTYSH_RIPD 0x02
|
||||
#define VTYSH_RIPNGD 0x04
|
||||
#define VTYSH_OSPFD 0x08
|
||||
#define VTYSH_OSPF6D 0x10
|
||||
#define VTYSH_BGPD 0x20
|
||||
#define VTYSH_ISISD 0x40
|
||||
#define VTYSH_PIMD 0x100
|
||||
#define VTYSH_LDPD 0x200
|
||||
#define VTYSH_WATCHFRR 0x400
|
||||
#define VTYSH_NHRPD 0x800
|
||||
#define VTYSH_EIGRPD 0x1000
|
||||
#define VTYSH_BABELD 0x2000
|
||||
#define VTYSH_SHARPD 0x4000
|
||||
#define VTYSH_ZEBRA 0x0001
|
||||
#define VTYSH_RIPD 0x0002
|
||||
#define VTYSH_RIPNGD 0x0004
|
||||
#define VTYSH_OSPFD 0x0008
|
||||
#define VTYSH_OSPF6D 0x0010
|
||||
#define VTYSH_BGPD 0x0020
|
||||
#define VTYSH_ISISD 0x0040
|
||||
#define VTYSH_PIMD 0x0080
|
||||
#define VTYSH_LDPD 0x0100
|
||||
#define VTYSH_WATCHFRR 0x0200
|
||||
#define VTYSH_NHRPD 0x0400
|
||||
#define VTYSH_EIGRPD 0x0800
|
||||
#define VTYSH_BABELD 0x1000
|
||||
#define VTYSH_SHARPD 0x2000
|
||||
#define VTYSH_PBRD 0x4000
|
||||
|
||||
/* commands in REALLYALL are crucial to correct vtysh operation */
|
||||
#define VTYSH_REALLYALL ~0U
|
||||
/* watchfrr is not in ALL since library CLI functions should not be
|
||||
* run on it (logging & co. should stay in a fixed/frozen config, and
|
||||
* things like prefix lists are not even initialised) */
|
||||
#define VTYSH_ALL VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_LDPD|VTYSH_BGPD|VTYSH_ISISD|VTYSH_PIMD|VTYSH_NHRPD|VTYSH_EIGRPD|VTYSH_BABELD|VTYSH_SHARPD
|
||||
#define VTYSH_ALL VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_LDPD|VTYSH_BGPD|VTYSH_ISISD|VTYSH_PIMD|VTYSH_NHRPD|VTYSH_EIGRPD|VTYSH_BABELD|VTYSH_SHARPD|VTYSH_PBRD
|
||||
#define VTYSH_RMAP VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_BGPD|VTYSH_ISISD|VTYSH_PIMD|VTYSH_EIGRPD|VTYSH_SHARPD
|
||||
#define VTYSH_INTERFACE VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_ISISD|VTYSH_PIMD|VTYSH_NHRPD|VTYSH_EIGRPD|VTYSH_BABELD
|
||||
#define VTYSH_INTERFACE VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_ISISD|VTYSH_PIMD|VTYSH_NHRPD|VTYSH_EIGRPD|VTYSH_BABELD|VTYSH_PBRD
|
||||
#define VTYSH_NS VTYSH_ZEBRA
|
||||
#define VTYSH_VRF VTYSH_ZEBRA|VTYSH_PIMD
|
||||
|
||||
|
|
|
@ -205,6 +205,9 @@ void vtysh_config_parse_line(void *arg, const char *line)
|
|||
config = config_get(LOGICALROUTER_NODE, line);
|
||||
else if (strncmp(line, "vrf", strlen("vrf")) == 0)
|
||||
config = config_get(VRF_NODE, line);
|
||||
else if (strncmp(line, "nexthop-group", strlen("nexthop-group"))
|
||||
== 0)
|
||||
config = config_get(NH_GROUP_NODE, line);
|
||||
else if (strncmp(line, "router-id", strlen("router-id")) == 0)
|
||||
config = config_get(ZEBRA_NODE, line);
|
||||
else if (strncmp(line, "router rip", strlen("router rip")) == 0)
|
||||
|
@ -235,6 +238,8 @@ void vtysh_config_parse_line(void *arg, const char *line)
|
|||
config = config_get(ISIS_NODE, line);
|
||||
else if (strncmp(line, "route-map", strlen("route-map")) == 0)
|
||||
config = config_get(RMAP_NODE, line);
|
||||
else if (strncmp(line, "pbr-map", strlen("pbr-map")) == 0)
|
||||
config = config_get(PBRMAP_NODE, line);
|
||||
else if (strncmp(line, "access-list", strlen("access-list"))
|
||||
== 0)
|
||||
config = config_get(ACCESS_NODE, line);
|
||||
|
|
Loading…
Reference in a new issue