pbrd: Add set vrf NAME and set vrf unchanged

`set vrf NAME` allows the pbr map to point to an arbitrary vrf table.

`set vrf unchanged` will use the interface's vrf for table lookup.

Further, add functionality for pbr to respond to interface events
such as interface vrf changes & interface creation/deletion.

Ex)
ubuntu_nh# show pbr map
  pbr-map TEST valid: 1
    Seq: 1 rule: 300 Installed: 3(1) Reason: Valid
        SRC Match: 3.3.3.3/32
        VRF Unchanged (use interface vrf)
  pbr-map TEST2 valid: 1
    Seq: 2 rule: 301 Installed: 3(2) Reason: Valid
        SRC Match: 4.4.4.4/32
        VRF Lookup: vrf-red

root@ubuntu_nh:/home# ip rule show
0:      from all lookup local
300:    from 3.3.3.3 iif dummy2 lookup main
300:    from 3.3.3.3 iif dummyVRF lookup 1111
301:    from 4.4.4.4 iif dummy1 lookup 1111
301:    from 4.4.4.4 iif dummy3 lookup 1111

Signed-off-by: Stephen Worley <sworley@cumulusnetworks.com-
This commit is contained in:
Stephen Worley 2019-09-27 16:38:31 -04:00
parent 2d7ef3bba7
commit be3b67b5ef
10 changed files with 558 additions and 51 deletions

View File

@ -107,6 +107,14 @@ end destination.
Use this individual nexthop as the place to forward packets when the match Use this individual nexthop as the place to forward packets when the match
commands have matched a packet. commands have matched a packet.
.. clicmd:: set vrf unchanged|NAME
If unchanged is set, the rule will use the vrf table the interface is in
as its lookup. If NAME is specified, the rule will use that vrf table as
its lookup.
Not supported with NETNS VRF backend.
.. _pbr-policy: .. _pbr-policy:
PBR Policy PBR Policy

View File

@ -48,6 +48,7 @@
#include "pbr_zebra.h" #include "pbr_zebra.h"
#include "pbr_vty.h" #include "pbr_vty.h"
#include "pbr_debug.h" #include "pbr_debug.h"
#include "pbr_vrf.h"
zebra_capabilities_t _caps_p[] = { zebra_capabilities_t _caps_p[] = {
ZCAP_NET_RAW, ZCAP_BIND, ZCAP_NET_ADMIN, ZCAP_NET_RAW, ZCAP_BIND, ZCAP_NET_ADMIN,
@ -153,7 +154,6 @@ int main(int argc, char **argv, char **envp)
pbr_debug_init(); pbr_debug_init();
vrf_init(NULL, NULL, NULL, NULL, NULL);
nexthop_group_init(pbr_nhgroup_add_cb, nexthop_group_init(pbr_nhgroup_add_cb,
pbr_nhgroup_add_nexthop_cb, pbr_nhgroup_add_nexthop_cb,
pbr_nhgroup_del_nexthop_cb, pbr_nhgroup_del_nexthop_cb,
@ -169,6 +169,7 @@ int main(int argc, char **argv, char **envp)
if_zapi_callbacks(pbr_ifp_create, pbr_ifp_up, if_zapi_callbacks(pbr_ifp_create, pbr_ifp_up,
pbr_ifp_down, pbr_ifp_destroy); pbr_ifp_down, pbr_ifp_destroy);
pbr_zebra_init(); pbr_zebra_init();
pbr_vrf_init();
pbr_vty_init(); pbr_vty_init();
frr_config_fork(); frr_config_fork();

View File

@ -35,6 +35,7 @@
#include "pbr_zebra.h" #include "pbr_zebra.h"
#include "pbr_memory.h" #include "pbr_memory.h"
#include "pbr_debug.h" #include "pbr_debug.h"
#include "pbr_vrf.h"
DEFINE_MTYPE_STATIC(PBRD, PBR_MAP, "PBR Map") DEFINE_MTYPE_STATIC(PBRD, PBR_MAP, "PBR Map")
DEFINE_MTYPE_STATIC(PBRD, PBR_MAP_SEQNO, "PBR Map Sequence") DEFINE_MTYPE_STATIC(PBRD, PBR_MAP_SEQNO, "PBR Map Sequence")
@ -42,6 +43,7 @@ DEFINE_MTYPE_STATIC(PBRD, PBR_MAP_INTERFACE, "PBR Map Interface")
static uint32_t pbr_map_sequence_unique; static uint32_t pbr_map_sequence_unique;
static bool pbr_map_check_valid_internal(struct pbr_map *pbrm);
static inline int pbr_map_compare(const struct pbr_map *pbrmap1, static inline int pbr_map_compare(const struct pbr_map *pbrmap1,
const struct pbr_map *pbrmap2); const struct pbr_map *pbrmap2);
@ -98,9 +100,55 @@ static void pbr_map_interface_list_delete(struct pbr_map_interface *pmi)
} }
} }
static bool pbr_map_interface_is_valid(const struct pbr_map_interface *pmi)
{
/* Don't install rules without a real ifindex on the incoming interface.
*
* This can happen when we have config for an interface that does not
* exist or when an interface is changing vrfs.
*/
if (pmi->ifp && pmi->ifp->ifindex != IFINDEX_INTERNAL)
return true;
return false;
}
static void pbr_map_pbrms_update_common(struct pbr_map_sequence *pbrms,
bool install)
{
struct pbr_map *pbrm;
struct listnode *node;
struct pbr_map_interface *pmi;
pbrm = pbrms->parent;
if (pbrms->nhs_installed && pbrm->incoming->count) {
for (ALL_LIST_ELEMENTS_RO(pbrm->incoming, node, pmi)) {
if (!pmi->ifp)
continue;
if (install && !pbr_map_interface_is_valid(pmi))
continue;
pbr_send_pbr_map(pbrms, pmi, install);
}
}
}
static void pbr_map_pbrms_install(struct pbr_map_sequence *pbrms)
{
pbr_map_pbrms_update_common(pbrms, true);
}
static void pbr_map_pbrms_uninstall(struct pbr_map_sequence *pbrms)
{
pbr_map_pbrms_update_common(pbrms, false);
}
static const char *pbr_map_reason_str[] = { static const char *pbr_map_reason_str[] = {
"Invalid NH-group", "Invalid NH", "No Nexthops", "Invalid NH-group", "Invalid NH", "No Nexthops",
"Both NH and NH-Group", "Invalid Src or Dst", "Deleting Sequence", "Both NH and NH-Group", "Invalid Src or Dst", "Invalid VRF",
"Deleting Sequence",
}; };
void pbr_map_reason_string(unsigned int reason, char *buf, int size) void pbr_map_reason_string(unsigned int reason, char *buf, int size)
@ -168,6 +216,93 @@ void pbr_map_add_interface(struct pbr_map *pbrm, struct interface *ifp_add)
pbr_map_install(pbrm); pbr_map_install(pbrm);
} }
static int
pbr_map_policy_interface_update_common(const struct interface *ifp,
struct pbr_interface **pbr_ifp,
struct pbr_map **pbrm)
{
if (!ifp->info) {
DEBUGD(&pbr_dbg_map, "%s: %s has no pbr_interface info",
__func__, ifp->name);
return -1;
}
*pbr_ifp = ifp->info;
*pbrm = pbrm_find((*pbr_ifp)->mapname);
if (!*pbrm) {
DEBUGD(&pbr_dbg_map, "%s: applied PBR-MAP(%s) does not exist?",
__func__, (*pbr_ifp)->mapname);
return -1;
}
return 0;
}
void pbr_map_policy_interface_update(const struct interface *ifp, bool state_up)
{
struct pbr_interface *pbr_ifp;
struct pbr_map_sequence *pbrms;
struct pbr_map *pbrm;
struct listnode *node, *inode;
struct pbr_map_interface *pmi;
if (pbr_map_policy_interface_update_common(ifp, &pbr_ifp, &pbrm))
return;
DEBUGD(&pbr_dbg_map, "%s: %s %s rules on interface %s", __func__,
pbr_ifp->mapname, (state_up ? "installing" : "removing"),
ifp->name);
/*
* Walk the list and install/remove maps on the interface.
*/
for (ALL_LIST_ELEMENTS_RO(pbrm->seqnumbers, node, pbrms))
for (ALL_LIST_ELEMENTS_RO(pbrm->incoming, inode, pmi))
if (pmi->ifp == ifp && pbr_map_interface_is_valid(pmi))
pbr_send_pbr_map(pbrms, pmi, state_up);
}
static void pbrms_vrf_update(struct pbr_map_sequence *pbrms,
const struct pbr_vrf *pbr_vrf)
{
const char *vrf_name = pbr_vrf_name(pbr_vrf);
if (pbrms->vrf_lookup
&& (strncmp(vrf_name, pbrms->vrf_name, sizeof(pbrms->vrf_name))
== 0)) {
DEBUGD(&pbr_dbg_map, "\tSeq %u uses vrf %s (%u), updating map",
pbrms->seqno, vrf_name, pbr_vrf_id(pbr_vrf));
pbr_map_check(pbrms);
}
}
/* Vrf enabled/disabled */
void pbr_map_vrf_update(const struct pbr_vrf *pbr_vrf)
{
struct pbr_map *pbrm;
struct pbr_map_sequence *pbrms;
struct listnode *node;
if (!pbr_vrf)
return;
bool enabled = pbr_vrf_is_enabled(pbr_vrf);
DEBUGD(&pbr_dbg_map, "%s: %s (%u) %s, updating pbr maps", __func__,
pbr_vrf_name(pbr_vrf), pbr_vrf_id(pbr_vrf),
enabled ? "enabled" : "disabled");
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))
pbrms_vrf_update(pbrms, pbr_vrf);
}
}
void pbr_map_write_interfaces(struct vty *vty, struct interface *ifp) void pbr_map_write_interfaces(struct vty *vty, struct interface *ifp)
{ {
struct pbr_interface *pbr_ifp = ifp->info; struct pbr_interface *pbr_ifp = ifp->info;
@ -210,16 +345,11 @@ extern void pbr_map_delete(struct pbr_map_sequence *pbrms)
} }
} }
void pbr_map_delete_nexthop_group(struct pbr_map_sequence *pbrms) static void pbr_map_delete_common(struct pbr_map_sequence *pbrms)
{ {
struct pbr_map *pbrm = pbrms->parent; struct pbr_map *pbrm = pbrms->parent;
struct listnode *node;
struct pbr_map_interface *pmi;
if (pbrm->valid && pbrms->nhs_installed && pbrm->incoming->count) { pbr_map_pbrms_uninstall(pbrms);
for (ALL_LIST_ELEMENTS_RO(pbrm->incoming, node, pmi))
pbr_send_pbr_map(pbrms, pmi, false);
}
pbrm->valid = false; pbrm->valid = false;
pbrms->nhs_installed = false; pbrms->nhs_installed = false;
@ -227,6 +357,16 @@ void pbr_map_delete_nexthop_group(struct pbr_map_sequence *pbrms)
pbrms->nhgrp_name = NULL; pbrms->nhgrp_name = NULL;
} }
void pbr_map_delete_nexthops(struct pbr_map_sequence *pbrms)
{
pbr_map_delete_common(pbrms);
}
void pbr_map_delete_vrf(struct pbr_map_sequence *pbrms)
{
pbr_map_delete_common(pbrms);
}
struct pbr_map_sequence *pbrms_lookup_unique(uint32_t unique, ifindex_t ifindex, struct pbr_map_sequence *pbrms_lookup_unique(uint32_t unique, ifindex_t ifindex,
struct pbr_map_interface **ppmi) struct pbr_map_interface **ppmi)
{ {
@ -318,6 +458,7 @@ struct pbr_map_sequence *pbrms_get(const char *name, uint32_t seqno)
pbrms->reason = pbrms->reason =
PBR_MAP_INVALID_EMPTY | PBR_MAP_INVALID_EMPTY |
PBR_MAP_INVALID_NO_NEXTHOPS; PBR_MAP_INVALID_NO_NEXTHOPS;
pbrms->vrf_name[0] = '\0';
QOBJ_REG(pbrms, pbr_map_sequence); QOBJ_REG(pbrms, pbr_map_sequence);
listnode_add_sort(pbrm->seqnumbers, pbrms); listnode_add_sort(pbrm->seqnumbers, pbrms);
@ -329,12 +470,36 @@ struct pbr_map_sequence *pbrms_get(const char *name, uint32_t seqno)
static void static void
pbr_map_sequence_check_nexthops_valid(struct pbr_map_sequence *pbrms) pbr_map_sequence_check_nexthops_valid(struct pbr_map_sequence *pbrms)
{ {
/* Check if any are present first */
if (!pbrms->vrf_unchanged && !pbrms->vrf_lookup && !pbrms->nhg
&& !pbrms->nhgrp_name) {
pbrms->reason |= PBR_MAP_INVALID_NO_NEXTHOPS;
return;
}
/*
* Check validness of vrf.
*/
/* This one can be considered always valid */
if (pbrms->vrf_unchanged)
pbrms->nhs_installed = true;
if (pbrms->vrf_lookup) {
struct pbr_vrf *pbr_vrf =
pbr_vrf_lookup_by_name(pbrms->vrf_name);
if (pbr_vrf && pbr_vrf_is_valid(pbr_vrf))
pbrms->nhs_installed = true;
else
pbrms->reason |= PBR_MAP_INVALID_VRF;
}
/* /*
* Check validness of the nexthop or nexthop-group * Check validness of the nexthop or nexthop-group
*/ */
if (!pbrms->nhg && !pbrms->nhgrp_name)
pbrms->reason |= PBR_MAP_INVALID_NO_NEXTHOPS;
/* Only nexthop or nexthop group allowed */
if (pbrms->nhg && pbrms->nhgrp_name) if (pbrms->nhg && pbrms->nhgrp_name)
pbrms->reason |= PBR_MAP_INVALID_BOTH_NHANDGRP; pbrms->reason |= PBR_MAP_INVALID_BOTH_NHANDGRP;
@ -458,10 +623,12 @@ void pbr_map_policy_install(const char *name)
__PRETTY_FUNCTION__, name, pbrms->seqno, pbrm->valid, __PRETTY_FUNCTION__, name, pbrms->seqno, pbrm->valid,
pbrms->nhs_installed); pbrms->nhs_installed);
if (pbrm->valid && pbrms->nhs_installed && pbrm->incoming->count) { if (pbrm->valid && pbrms->nhs_installed
DEBUGD(&pbr_dbg_map, "\tInstalling %s %u", && pbrm->incoming->count) {
pbrm->name, pbrms->seqno); DEBUGD(&pbr_dbg_map, "\tInstalling %s %u", pbrm->name,
pbrms->seqno);
for (ALL_LIST_ELEMENTS_RO(pbrm->incoming, inode, pmi)) for (ALL_LIST_ELEMENTS_RO(pbrm->incoming, inode, pmi))
if (pbr_map_interface_is_valid(pmi))
pbr_send_pbr_map(pbrms, pmi, true); pbr_send_pbr_map(pbrms, pmi, true);
} }
} }
@ -525,8 +692,6 @@ void pbr_map_check_nh_group_change(const char *nh_group)
void pbr_map_check(struct pbr_map_sequence *pbrms) void pbr_map_check(struct pbr_map_sequence *pbrms)
{ {
struct pbr_map *pbrm; struct pbr_map *pbrm;
struct listnode *inode;
struct pbr_map_interface *pmi;
bool install; bool install;
pbrm = pbrms->parent; pbrm = pbrms->parent;
@ -551,23 +716,22 @@ void pbr_map_check(struct pbr_map_sequence *pbrms)
pbrms->seqno, pbrms->reason); pbrms->seqno, pbrms->reason);
} }
for (ALL_LIST_ELEMENTS_RO(pbrm->incoming, inode, pmi)) { if (install)
pbr_send_pbr_map(pbrms, pmi, install); pbr_map_pbrms_install(pbrms);
} else
pbr_map_pbrms_uninstall(pbrms);
} }
void pbr_map_install(struct pbr_map *pbrm) void pbr_map_install(struct pbr_map *pbrm)
{ {
struct listnode *node, *inode;
struct pbr_map_sequence *pbrms; struct pbr_map_sequence *pbrms;
struct pbr_map_interface *pmi; struct listnode *node;
if (!pbrm->incoming->count) if (!pbrm->incoming->count)
return; return;
for (ALL_LIST_ELEMENTS_RO(pbrm->seqnumbers, node, pbrms)) for (ALL_LIST_ELEMENTS_RO(pbrm->seqnumbers, node, pbrms))
for (ALL_LIST_ELEMENTS_RO(pbrm->incoming, inode, pmi)) pbr_map_pbrms_install(pbrms);
pbr_send_pbr_map(pbrms, pmi, true);
} }
void pbr_map_init(void) void pbr_map_init(void)

View File

@ -22,6 +22,8 @@
#include <bitfield.h> #include <bitfield.h>
#include "pbr_vrf.h"
struct pbr_map { struct pbr_map {
/* /*
* RB Tree of the pbr_maps * RB Tree of the pbr_maps
@ -94,6 +96,21 @@ struct pbr_map_sequence {
*/ */
unsigned char family; unsigned char family;
/*
* Use interface's vrf.
*/
bool vrf_unchanged;
/*
* The vrf to lookup in was directly configured.
*/
bool vrf_lookup;
/*
* VRF to lookup.
*/
char vrf_name[VRF_NAMSIZ + 1];
/* /*
* The nexthop group we auto create * The nexthop group we auto create
* for when the user specifies a individual * for when the user specifies a individual
@ -128,6 +145,7 @@ struct pbr_map_sequence {
#define PBR_MAP_INVALID_NO_NEXTHOPS (1 << 2) #define PBR_MAP_INVALID_NO_NEXTHOPS (1 << 2)
#define PBR_MAP_INVALID_BOTH_NHANDGRP (1 << 3) #define PBR_MAP_INVALID_BOTH_NHANDGRP (1 << 3)
#define PBR_MAP_INVALID_EMPTY (1 << 4) #define PBR_MAP_INVALID_EMPTY (1 << 4)
#define PBR_MAP_INVALID_VRF (1 << 5)
uint64_t reason; uint64_t reason;
QOBJ_FIELDS QOBJ_FIELDS
@ -144,12 +162,21 @@ pbrms_lookup_unique(uint32_t unique, ifindex_t ifindex,
extern struct pbr_map *pbrm_find(const char *name); extern struct pbr_map *pbrm_find(const char *name);
extern void pbr_map_delete(struct pbr_map_sequence *pbrms); extern void pbr_map_delete(struct pbr_map_sequence *pbrms);
extern void pbr_map_delete_nexthop_group(struct pbr_map_sequence *pbrms); extern void pbr_map_delete_nexthops(struct pbr_map_sequence *pbrms);
extern void pbr_map_delete_vrf(struct pbr_map_sequence *pbrms);
extern void pbr_map_add_interface(struct pbr_map *pbrm, struct interface *ifp); extern void pbr_map_add_interface(struct pbr_map *pbrm, struct interface *ifp);
extern void pbr_map_interface_delete(struct pbr_map *pbrm, extern void pbr_map_interface_delete(struct pbr_map *pbrm,
struct interface *ifp); struct interface *ifp);
/* Update maps installed on interface */
extern void pbr_map_policy_interface_update(const struct interface *ifp,
bool state_up);
extern void pbr_map_final_interface_deletion(struct pbr_map *pbrm, extern void pbr_map_final_interface_deletion(struct pbr_map *pbrm,
struct pbr_map_interface *pmi); struct pbr_map_interface *pmi);
extern void pbr_map_vrf_update(const struct pbr_vrf *pbr_vrf);
extern void pbr_map_write_interfaces(struct vty *vty, struct interface *ifp); extern void pbr_map_write_interfaces(struct vty *vty, struct interface *ifp);
extern void pbr_map_init(void); extern void pbr_map_init(void);

View File

@ -548,20 +548,10 @@ void pbr_nht_delete_individual_nexthop(struct pbr_map_sequence *pbrms)
struct pbr_nexthop_group_cache find; struct pbr_nexthop_group_cache find;
struct pbr_nexthop_cache *pnhc; struct pbr_nexthop_cache *pnhc;
struct pbr_nexthop_cache lup; struct pbr_nexthop_cache lup;
struct pbr_map *pbrm = pbrms->parent;
struct listnode *node;
struct pbr_map_interface *pmi;
struct nexthop *nh; struct nexthop *nh;
enum nexthop_types_t nh_type = 0; enum nexthop_types_t nh_type = 0;
if (pbrm->valid && pbrms->nhs_installed && pbrm->incoming->count) { pbr_map_delete_nexthops(pbrms);
for (ALL_LIST_ELEMENTS_RO(pbrm->incoming, node, pmi))
pbr_send_pbr_map(pbrms, pmi, false);
}
pbrm->valid = false;
pbrms->nhs_installed = false;
pbrms->reason |= PBR_MAP_INVALID_NO_NEXTHOPS;
memset(&find, 0, sizeof(find)); memset(&find, 0, sizeof(find));
snprintf(find.name, sizeof(find.name), "%s", pbrms->internal_nhg_name); snprintf(find.name, sizeof(find.name), "%s", pbrms->internal_nhg_name);

137
pbrd/pbr_vrf.c Normal file
View File

@ -0,0 +1,137 @@
/*
* PBR - vrf code
* Copyright (C) 2019 Cumulus Networks, Inc.
* Stephen Worley
*
* 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 "vrf.h"
#include "pbr_vrf.h"
#include "pbr_memory.h"
#include "pbr_map.h"
#include "pbr_debug.h"
DEFINE_MTYPE_STATIC(PBRD, PBR_MAP_VRF, "PBR Map VRF")
static struct pbr_vrf *pbr_vrf_alloc(void)
{
struct pbr_vrf *pbr_vrf;
pbr_vrf = XCALLOC(MTYPE_PBR_MAP_VRF, sizeof(struct pbr_vrf));
return pbr_vrf;
}
static void pbr_vrf_free(struct pbr_vrf *pbr_vrf)
{
XFREE(MTYPE_PBR_MAP_VRF, pbr_vrf);
}
static int pbr_vrf_new(struct vrf *vrf)
{
struct pbr_vrf *pbr_vrf;
DEBUGD(&pbr_dbg_event, "%s: %u (%s)", __func__, vrf->vrf_id, vrf->name);
pbr_vrf = pbr_vrf_alloc();
vrf->info = pbr_vrf;
pbr_vrf->vrf = vrf;
return 0;
}
static int pbr_vrf_enable(struct vrf *vrf)
{
DEBUGD(&pbr_dbg_event, "%s: %u (%s)", __func__, vrf->vrf_id, vrf->name);
pbr_map_vrf_update(vrf->info);
return 0;
}
static int pbr_vrf_disable(struct vrf *vrf)
{
DEBUGD(&pbr_dbg_event, "%s: %u (%s)", __func__, vrf->vrf_id, vrf->name);
pbr_map_vrf_update(vrf->info);
return 0;
}
static int pbr_vrf_delete(struct vrf *vrf)
{
DEBUGD(&pbr_dbg_event, "%s: %u (%s)", __func__, vrf->vrf_id, vrf->name);
/*
* Make sure vrf is always marked disabled first so we handle
* pbr rules using it.
*/
assert(!vrf_is_enabled(vrf));
pbr_vrf_free(vrf->info);
vrf->info = NULL;
return 0;
}
struct pbr_vrf *pbr_vrf_lookup_by_id(vrf_id_t vrf_id)
{
struct vrf *vrf;
vrf = vrf_lookup_by_id(vrf_id);
if (vrf)
return ((struct pbr_vrf *)vrf->info);
return NULL;
}
struct pbr_vrf *pbr_vrf_lookup_by_name(const char *name)
{
struct vrf *vrf;
if (!name)
name = VRF_DEFAULT_NAME;
vrf = vrf_lookup_by_name(name);
if (vrf)
return ((struct pbr_vrf *)vrf->info);
return NULL;
}
bool pbr_vrf_is_enabled(const struct pbr_vrf *pbr_vrf)
{
return vrf_is_enabled(pbr_vrf->vrf) ? true : false;
}
bool pbr_vrf_is_valid(const struct pbr_vrf *pbr_vrf)
{
if (vrf_is_backend_netns())
return false;
if (!pbr_vrf->vrf)
return false;
return pbr_vrf_is_enabled(pbr_vrf);
}
void pbr_vrf_init(void)
{
vrf_init(pbr_vrf_new, pbr_vrf_enable, pbr_vrf_disable, pbr_vrf_delete,
NULL);
}

43
pbrd/pbr_vrf.h Normal file
View File

@ -0,0 +1,43 @@
/*
* VRF library for PBR
* Copyright (C) 2019 Cumulus Networks, Inc.
* Stephen Worley
*
* 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_VRF_H__
#define __PBR_VRF_H__
struct pbr_vrf {
struct vrf *vrf;
};
static inline const char *pbr_vrf_name(const struct pbr_vrf *pbr_vrf)
{
return pbr_vrf->vrf->name;
}
static inline vrf_id_t pbr_vrf_id(const struct pbr_vrf *pbr_vrf)
{
return pbr_vrf->vrf->vrf_id;
}
extern struct pbr_vrf *pbr_vrf_lookup_by_id(vrf_id_t vrf_id);
extern struct pbr_vrf *pbr_vrf_lookup_by_name(const char *name);
extern bool pbr_vrf_is_valid(const struct pbr_vrf *pbr_vrf);
extern bool pbr_vrf_is_enabled(const struct pbr_vrf *pbr_vrf);
extern void pbr_vrf_init(void);
#endif

View File

@ -193,7 +193,10 @@ DEFPY(pbr_map_match_mark, pbr_map_match_mark_cmd,
pbr_map_check(pbrms); pbr_map_check(pbrms);
return CMD_SUCCESS; return CMD_SUCCESS;
} }
#define SET_VRF_EXISTS_STR \
"A `set vrf XX` command already exists, please remove that first\n"
DEFPY(pbr_map_nexthop_group, pbr_map_nexthop_group_cmd, DEFPY(pbr_map_nexthop_group, pbr_map_nexthop_group_cmd,
"[no] set nexthop-group NHGNAME$name", "[no] set nexthop-group NHGNAME$name",
@ -211,16 +214,22 @@ DEFPY(pbr_map_nexthop_group, pbr_map_nexthop_group_cmd,
return CMD_WARNING_CONFIG_FAILED; return CMD_WARNING_CONFIG_FAILED;
} }
if (pbrms->vrf_lookup || pbrms->vrf_unchanged) {
vty_out(vty, SET_VRF_EXISTS_STR);
return CMD_WARNING_CONFIG_FAILED;
}
nhgc = nhgc_find(name); nhgc = nhgc_find(name);
if (!nhgc) { if (!nhgc) {
vty_out(vty, "Specified nexthop-group %s does not exist\n", vty_out(vty, "Specified nexthop-group %s does not exist\n",
name); name);
vty_out(vty, "PBR-MAP will not be applied until it is created\n"); vty_out(vty,
"PBR-MAP will not be applied until it is created\n");
} }
if (no) { if (no) {
if (pbrms->nhgrp_name && strcmp(name, pbrms->nhgrp_name) == 0) if (pbrms->nhgrp_name && strcmp(name, pbrms->nhgrp_name) == 0)
pbr_map_delete_nexthop_group(pbrms); pbr_map_delete_nexthops(pbrms);
else { else {
vty_out(vty, vty_out(vty,
"Nexthop Group specified: %s does not exist to remove", "Nexthop Group specified: %s does not exist to remove",
@ -272,6 +281,11 @@ DEFPY(pbr_map_nexthop, pbr_map_nexthop_cmd,
return CMD_WARNING_CONFIG_FAILED; return CMD_WARNING_CONFIG_FAILED;
} }
if (pbrms->vrf_lookup || pbrms->vrf_unchanged) {
vty_out(vty, SET_VRF_EXISTS_STR);
return CMD_WARNING_CONFIG_FAILED;
}
if (vrf_name) if (vrf_name)
vrf = vrf_lookup_by_name(vrf_name); vrf = vrf_lookup_by_name(vrf_name);
else else
@ -372,6 +386,61 @@ DEFPY(pbr_map_nexthop, pbr_map_nexthop_cmd,
return CMD_SUCCESS; return CMD_SUCCESS;
} }
DEFPY(pbr_map_vrf, pbr_map_vrf_cmd,
"[no] set vrf <NAME$vrf_name|unchanged>",
NO_STR
"Set for the PBR-MAP\n"
"Specify the VRF for this map\n"
"The VRF Name\n"
"Use the interface's VRF for lookup\n")
{
struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence);
int ret = CMD_SUCCESS;
if (no) {
pbr_map_delete_vrf(pbrms);
/* Reset all data */
pbrms->nhs_installed = false;
pbrms->vrf_name[0] = '\0';
pbrms->vrf_lookup = false;
pbrms->vrf_unchanged = false;
goto done;
}
if (pbrms->nhgrp_name || pbrms->nhg) {
vty_out(vty,
"A `set nexthop/nexthop-group XX` command already exits, please remove that first\n");
ret = CMD_WARNING_CONFIG_FAILED;
goto done;
}
if (pbrms->vrf_lookup || pbrms->vrf_unchanged) {
vty_out(vty, SET_VRF_EXISTS_STR);
ret = CMD_WARNING_CONFIG_FAILED;
goto done;
}
if (vrf_name) {
if (!pbr_vrf_lookup_by_name(vrf_name)) {
vty_out(vty, "Specified: %s is non-existent\n",
vrf_name);
ret = CMD_WARNING_CONFIG_FAILED;
goto done;
}
pbrms->vrf_lookup = true;
strlcpy(pbrms->vrf_name, vrf_name, sizeof(pbrms->vrf_name));
} else
pbrms->vrf_unchanged = true;
pbr_map_check(pbrms);
done:
return ret;
}
DEFPY (pbr_policy, DEFPY (pbr_policy,
pbr_policy_cmd, pbr_policy_cmd,
"[no] pbr-policy PBRMAP$mapname", "[no] pbr-policy PBRMAP$mapname",
@ -500,6 +569,12 @@ DEFPY (show_pbr_map,
pbrms->internal_nhg_name), pbrms->internal_nhg_name),
pbr_nht_get_table( pbr_nht_get_table(
pbrms->internal_nhg_name)); pbrms->internal_nhg_name));
} else if (pbrms->vrf_unchanged) {
vty_out(vty,
"\tVRF Unchanged (use interface vrf)\n");
} else if (pbrms->vrf_lookup) {
vty_out(vty, "\tVRF Lookup: %s\n",
pbrms->vrf_name);
} else { } else {
vty_out(vty, vty_out(vty,
"\tNexthop-Group: Unknown Installed: 0(0)\n"); "\tNexthop-Group: Unknown Installed: 0(0)\n");
@ -662,6 +737,12 @@ static int pbr_vty_map_config_write_sequence(struct vty *vty,
if (pbrms->mark) if (pbrms->mark)
vty_out(vty, " match mark %u\n", pbrms->mark); vty_out(vty, " match mark %u\n", pbrms->mark);
if (pbrms->vrf_unchanged)
vty_out(vty, " set vrf unchanged\n");
if (pbrms->vrf_lookup)
vty_out(vty, " set vrf %s\n", pbrms->vrf_name);
if (pbrms->nhgrp_name) if (pbrms->nhgrp_name)
vty_out(vty, " set nexthop-group %s\n", pbrms->nhgrp_name); vty_out(vty, " set nexthop-group %s\n", pbrms->nhgrp_name);
@ -737,6 +818,7 @@ void pbr_vty_init(void)
install_element(PBRMAP_NODE, &pbr_map_match_mark_cmd); install_element(PBRMAP_NODE, &pbr_map_match_mark_cmd);
install_element(PBRMAP_NODE, &pbr_map_nexthop_group_cmd); install_element(PBRMAP_NODE, &pbr_map_nexthop_group_cmd);
install_element(PBRMAP_NODE, &pbr_map_nexthop_cmd); install_element(PBRMAP_NODE, &pbr_map_nexthop_cmd);
install_element(PBRMAP_NODE, &pbr_map_vrf_cmd);
install_element(VIEW_NODE, &show_pbr_cmd); install_element(VIEW_NODE, &show_pbr_cmd);
install_element(VIEW_NODE, &show_pbr_map_cmd); install_element(VIEW_NODE, &show_pbr_map_cmd);
install_element(VIEW_NODE, &show_pbr_interface_cmd); install_element(VIEW_NODE, &show_pbr_interface_cmd);

View File

@ -39,6 +39,7 @@
#include "pbr_memory.h" #include "pbr_memory.h"
#include "pbr_zebra.h" #include "pbr_zebra.h"
#include "pbr_debug.h" #include "pbr_debug.h"
#include "pbr_vrf.h"
DEFINE_MTYPE_STATIC(PBRD, PBR_INTERFACE, "PBR Interface") DEFINE_MTYPE_STATIC(PBRD, PBR_INTERFACE, "PBR Interface")
@ -67,8 +68,11 @@ int pbr_ifp_create(struct interface *ifp)
if (!ifp->info) if (!ifp->info)
pbr_if_new(ifp); pbr_if_new(ifp);
/* Update nexthops tracked from a `set nexthop` command */
pbr_nht_nexthop_interface_update(ifp); pbr_nht_nexthop_interface_update(ifp);
pbr_map_policy_interface_update(ifp, true);
return 0; return 0;
} }
@ -77,6 +81,8 @@ int pbr_ifp_destroy(struct interface *ifp)
DEBUGD(&pbr_dbg_zebra, DEBUGD(&pbr_dbg_zebra,
"%s: %s", __PRETTY_FUNCTION__, ifp->name); "%s: %s", __PRETTY_FUNCTION__, ifp->name);
pbr_map_policy_interface_update(ifp, false);
return 0; return 0;
} }
@ -133,6 +139,29 @@ int pbr_ifp_down(struct interface *ifp)
return 0; return 0;
} }
static int interface_vrf_update(ZAPI_CALLBACK_ARGS)
{
struct interface *ifp;
vrf_id_t new_vrf_id;
ifp = zebra_interface_vrf_update_read(zclient->ibuf, vrf_id,
&new_vrf_id);
if (!ifp) {
DEBUGD(&pbr_dbg_zebra, "%s: VRF change interface not found",
__func__);
return 0;
}
DEBUGD(&pbr_dbg_zebra, "%s: %s VRF change %u -> %u", __func__,
ifp->name, vrf_id, new_vrf_id);
if_update_to_new_vrf(ifp, new_vrf_id);
return 0;
}
static int route_notify_owner(ZAPI_CALLBACK_ARGS) static int route_notify_owner(ZAPI_CALLBACK_ARGS)
{ {
struct prefix p; struct prefix p;
@ -421,6 +450,7 @@ void pbr_zebra_init(void)
zclient->zebra_connected = zebra_connected; zclient->zebra_connected = zebra_connected;
zclient->interface_address_add = interface_address_add; zclient->interface_address_add = interface_address_add;
zclient->interface_address_delete = interface_address_delete; zclient->interface_address_delete = interface_address_delete;
zclient->interface_vrf_update = interface_vrf_update;
zclient->route_notify_owner = route_notify_owner; zclient->route_notify_owner = route_notify_owner;
zclient->rule_notify_owner = rule_notify_owner; zclient->rule_notify_owner = rule_notify_owner;
zclient->nexthop_update = pbr_zebra_nexthop_update; zclient->nexthop_update = pbr_zebra_nexthop_update;
@ -483,6 +513,26 @@ static void pbr_encode_pbr_map_sequence_prefix(struct stream *s,
stream_put(s, &p->u.prefix, prefix_blen(p)); stream_put(s, &p->u.prefix, prefix_blen(p));
} }
static void
pbr_encode_pbr_map_sequence_vrf(struct stream *s,
const struct pbr_map_sequence *pbrms,
const struct interface *ifp)
{
struct pbr_vrf *pbr_vrf;
if (pbrms->vrf_unchanged)
pbr_vrf = pbr_vrf_lookup_by_id(ifp->vrf_id);
else
pbr_vrf = pbr_vrf_lookup_by_name(pbrms->vrf_name);
if (!pbr_vrf) {
DEBUGD(&pbr_dbg_zebra, "%s: VRF not found", __func__);
return;
}
stream_putl(s, pbr_vrf->vrf->data.l.table_id);
}
static void pbr_encode_pbr_map_sequence(struct stream *s, static void pbr_encode_pbr_map_sequence(struct stream *s,
struct pbr_map_sequence *pbrms, struct pbr_map_sequence *pbrms,
struct interface *ifp) struct interface *ifp)
@ -501,7 +551,10 @@ static void pbr_encode_pbr_map_sequence(struct stream *s,
pbr_encode_pbr_map_sequence_prefix(s, pbrms->dst, family); pbr_encode_pbr_map_sequence_prefix(s, pbrms->dst, family);
stream_putw(s, 0); /* dst port */ stream_putw(s, 0); /* dst port */
stream_putl(s, pbrms->mark); stream_putl(s, pbrms->mark);
if (pbrms->nhgrp_name)
if (pbrms->vrf_unchanged || pbrms->vrf_lookup)
pbr_encode_pbr_map_sequence_vrf(s, pbrms, ifp);
else if (pbrms->nhgrp_name)
stream_putl(s, pbr_nht_get_table(pbrms->nhgrp_name)); stream_putl(s, pbr_nht_get_table(pbrms->nhgrp_name));
else if (pbrms->nhg) else if (pbrms->nhg)
stream_putl(s, pbr_nht_get_table(pbrms->internal_nhg_name)); stream_putl(s, pbr_nht_get_table(pbrms->internal_nhg_name));

View File

@ -20,6 +20,7 @@ pbrd_libpbr_a_SOURCES = \
pbrd/pbr_memory.c \ pbrd/pbr_memory.c \
pbrd/pbr_nht.c \ pbrd/pbr_nht.c \
pbrd/pbr_debug.c \ pbrd/pbr_debug.c \
pbrd/pbr_vrf.c \
# end # end
noinst_HEADERS += \ noinst_HEADERS += \
@ -29,6 +30,7 @@ noinst_HEADERS += \
pbrd/pbr_vty.h \ pbrd/pbr_vty.h \
pbrd/pbr_zebra.h \ pbrd/pbr_zebra.h \
pbrd/pbr_debug.h \ pbrd/pbr_debug.h \
pbrd/pbr_vrf.h \
# end # end
pbrd/pbr_vty_clippy.c: $(CLIPPY_DEPS) pbrd/pbr_vty_clippy.c: $(CLIPPY_DEPS)