frr/pbrd/pbr_map.h
Donald Sharp e5c83d9b31 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>
2018-04-06 13:22:43 -04:00

155 lines
3.9 KiB
C

/*
* 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