Skip to content

Commit

Permalink
pbrd: Add PBR to FRR
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
donaldsharp committed Apr 6, 2018
1 parent 52483fa commit e5c83d9
Show file tree
Hide file tree
Showing 35 changed files with 3,861 additions and 20 deletions.
1 change: 1 addition & 0 deletions Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -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@ \
Expand Down
1 change: 1 addition & 0 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
3 changes: 3 additions & 0 deletions lib/command.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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:
Expand Down
1 change: 1 addition & 0 deletions lib/command.h
Original file line number Diff line number Diff line change
Expand Up @@ -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. */
Expand Down
2 changes: 2 additions & 0 deletions lib/route_types.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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, "-"


Expand All @@ -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)"
2 changes: 2 additions & 0 deletions lib/vty.c
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -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:
Expand Down
15 changes: 15 additions & 0 deletions pbrd/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
!Makefile
Makefile.in
libpbr.a
pbrd
tags
TAGS
.deps
*.o
*.lo
*.la
*.libs
.arch-inventory
.arch-ids
*~
*.loT
10 changes: 10 additions & 0 deletions pbrd/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
all: ALWAYS
@$(MAKE) -s -C .. pbrd/pbrd
%: ALWAYS
@$(MAKE) -s -C .. pbrd/$@

Makefile:
#nothing
ALWAYS:
.PHONY: ALWAYS makefiles
.SUFFIXES:
171 changes: 171 additions & 0 deletions pbrd/pbr_debug.c
Original file line number Diff line number Diff line change
@@ -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 changes: 53 additions & 0 deletions pbrd/pbr_debug.h
Original file line number Diff line number Diff line change
@@ -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__ */
Loading

0 comments on commit e5c83d9

Please sign in to comment.