mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-08-14 00:56:19 +00:00
pbrd: add vlan filters pcp/vlan-id/vlan-flags; ip-protocol any (pbr feature)
Subset: feature in PBR New PBR rule fields: match ip-protocol (was only tcp|udp, now any value in /etc/protocols) match pcp (0-7) match vlan (1-4094) match vlan (tagged|untagged|untagged-or-zero) Filter flags Add filter_bm (flags) field internally to indicate which filter fields should be considered active. Bit definitions as in lib/pbr.h. This commit uses only the PBR_FILTER_PCP bit, but other fields will be added in future commits. (Fixes bug related to determining set/not-set state of pcp filter) Shift vlan filter flags to lib/pbr.h Changes by: Josh Werner <joshuawerner@mitre.org> Eli Baum <ebaum@mitre.org> G. Paul Ziemba <paulz@labn.net> Signed-off-by: G. Paul Ziemba <paulz@labn.net>
This commit is contained in:
parent
ff10abcc89
commit
bfd3e8e012
24
lib/pbr.h
24
lib/pbr.h
@ -1,6 +1,9 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/* Policy Based Routing (PBR) main header
|
||||
* Copyright (C) 2018 6WIND
|
||||
* Portions:
|
||||
* Copyright (c) 2021 The MITRE Corporation.
|
||||
* Copyright (c) 2023 LabN Consulting, L.L.C.
|
||||
*/
|
||||
|
||||
#ifndef _PBR_H
|
||||
@ -25,8 +28,7 @@ extern "C" {
|
||||
* specified.
|
||||
*/
|
||||
struct pbr_filter {
|
||||
uint32_t filter_bm; /* not encoded by zapi
|
||||
*/
|
||||
uint32_t filter_bm;
|
||||
#define PBR_FILTER_SRC_IP (1 << 0)
|
||||
#define PBR_FILTER_DST_IP (1 << 1)
|
||||
#define PBR_FILTER_SRC_PORT (1 << 2)
|
||||
@ -37,18 +39,32 @@ struct pbr_filter {
|
||||
#define PBR_FILTER_DST_PORT_RANGE (1 << 7)
|
||||
#define PBR_FILTER_DSFIELD (1 << 8)
|
||||
#define PBR_FILTER_IP_PROTOCOL (1 << 9)
|
||||
#define PBR_FILTER_PCP (1 << 10)
|
||||
#define PBR_FILTER_VLAN_FLAGS (1 << 11)
|
||||
#define PBR_FILTER_VLAN_ID (1 << 12)
|
||||
|
||||
#define PBR_DSFIELD_DSCP (0xfc) /* Upper 6 bits of DS field: DSCP */
|
||||
#define PBR_DSFIELD_ECN (0x03) /* Lower 2 bits of DS field: BCN */
|
||||
#define PBR_PCP (0x07) /* 3-bit value 0..7 for prioritization*/
|
||||
|
||||
/* Source and Destination IP address with masks. */
|
||||
#define PBR_VLAN_FLAGS_NO_WILD 0
|
||||
#define PBR_VLAN_FLAGS_TAGGED (1 << 0)
|
||||
#define PBR_VLAN_FLAGS_UNTAGGED (1 << 1)
|
||||
#define PBR_VLAN_FLAGS_UNTAGGED_0 (1 << 2)
|
||||
|
||||
/* Source and Destination IP address with masks */
|
||||
struct prefix src_ip;
|
||||
struct prefix dst_ip;
|
||||
|
||||
/* Source and Destination higher-layer (TCP/UDP) port numbers. */
|
||||
/* Source and Destination higher-layer (TCP/UDP) port numbers */
|
||||
uint16_t src_port;
|
||||
uint16_t dst_port;
|
||||
|
||||
/* Filter by VLAN and prioritization */
|
||||
uint8_t pcp;
|
||||
uint16_t vlan_id;
|
||||
uint16_t vlan_flags;
|
||||
|
||||
/* Filter by Differentiated Services field */
|
||||
uint8_t dsfield; /* DSCP (6 bits) & ECN (2 bits) */
|
||||
|
||||
|
@ -3,6 +3,9 @@
|
||||
* PBR-map Code
|
||||
* Copyright (C) 2018 Cumulus Networks, Inc.
|
||||
* Donald Sharp
|
||||
* Portions:
|
||||
* Copyright (c) 2021 The MITRE Corporation.
|
||||
* Copyright (c) 2023 LabN Consulting, L.L.C.
|
||||
*/
|
||||
#include <zebra.h>
|
||||
|
||||
@ -16,6 +19,7 @@
|
||||
#include "memory.h"
|
||||
#include "log.h"
|
||||
#include "vty.h"
|
||||
#include "pbr.h"
|
||||
|
||||
#include "pbr_nht.h"
|
||||
#include "pbr_map.h"
|
||||
@ -101,6 +105,38 @@ static bool pbrms_is_installed(const struct pbr_map_sequence *pbrms,
|
||||
return false;
|
||||
}
|
||||
|
||||
void pbr_set_match_clause_for_pcp(struct pbr_map_sequence *pbrms, bool set,
|
||||
uint8_t pcp)
|
||||
{
|
||||
bool changed = false;
|
||||
|
||||
if (set) {
|
||||
if (!CHECK_FLAG(pbrms->filter_bm, PBR_FILTER_PCP) ||
|
||||
(pcp != pbrms->match_pcp)) {
|
||||
SET_FLAG(pbrms->filter_bm, PBR_FILTER_PCP);
|
||||
pbrms->match_pcp = pcp;
|
||||
changed = true;
|
||||
}
|
||||
} else {
|
||||
if (CHECK_FLAG(pbrms->filter_bm, PBR_FILTER_PCP)) {
|
||||
UNSET_FLAG(pbrms->filter_bm, PBR_FILTER_PCP);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
if (changed)
|
||||
pbr_map_check(pbrms, true);
|
||||
}
|
||||
|
||||
void pbr_set_match_clause_for_vlan(struct pbr_map_sequence *pbrms,
|
||||
uint16_t vlan_id, uint16_t vlan_flags)
|
||||
{
|
||||
if (pbrms) {
|
||||
pbrms->match_vlan_id = vlan_id;
|
||||
pbrms->match_vlan_flags = vlan_flags;
|
||||
pbr_map_check(pbrms, true);
|
||||
}
|
||||
}
|
||||
|
||||
/* If any sequence is installed on the interface, assume installed */
|
||||
static bool
|
||||
pbr_map_interface_is_installed(const struct pbr_map *pbrm,
|
||||
@ -486,9 +522,9 @@ uint8_t pbr_map_decode_dscp_enum(const char *name)
|
||||
|
||||
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_map *pbrm = NULL;
|
||||
struct pbr_map_sequence *pbrms = NULL;
|
||||
struct listnode *node = NULL;
|
||||
|
||||
pbrm = pbrm_find(name);
|
||||
if (!pbrm) {
|
||||
@ -526,6 +562,10 @@ struct pbr_map_sequence *pbrms_get(const char *name, uint32_t seqno)
|
||||
pbrms->ruleno = pbr_nht_get_next_rule(seqno);
|
||||
pbrms->parent = pbrm;
|
||||
|
||||
pbrms->match_vlan_id = 0;
|
||||
pbrms->match_vlan_flags = 0;
|
||||
pbrms->match_pcp = 0;
|
||||
|
||||
pbrms->action_vlan_id = 0;
|
||||
pbrms->action_vlan_flags = 0;
|
||||
pbrms->action_pcp = 0;
|
||||
@ -594,10 +634,12 @@ pbr_map_sequence_check_nexthops_valid(struct pbr_map_sequence *pbrms)
|
||||
|
||||
static void pbr_map_sequence_check_not_empty(struct pbr_map_sequence *pbrms)
|
||||
{
|
||||
if (!pbrms->src && !pbrms->dst && !pbrms->mark && !pbrms->dsfield
|
||||
&& !pbrms->action_vlan_id && !pbrms->action_vlan_flags
|
||||
&& !pbrms->action_pcp
|
||||
&& pbrms->action_queue_id == PBR_MAP_UNDEFINED_QUEUE_ID)
|
||||
if (!pbrms->src && !pbrms->dst && !pbrms->mark && !pbrms->dsfield &&
|
||||
!CHECK_FLAG(pbrms->filter_bm, PBR_FILTER_PCP) &&
|
||||
!pbrms->action_pcp && !pbrms->match_vlan_id &&
|
||||
!pbrms->match_vlan_flags && !pbrms->action_vlan_id &&
|
||||
!pbrms->action_vlan_flags &&
|
||||
pbrms->action_queue_id == PBR_MAP_UNDEFINED_QUEUE_ID)
|
||||
pbrms->reason |= PBR_MAP_INVALID_EMPTY;
|
||||
}
|
||||
|
||||
@ -734,7 +776,6 @@ void pbr_map_policy_delete(struct pbr_map *pbrm, struct pbr_map_interface *pmi)
|
||||
struct pbr_map_sequence *pbrms;
|
||||
bool sent = false;
|
||||
|
||||
|
||||
for (ALL_LIST_ELEMENTS_RO(pbrm->seqnumbers, node, pbrms))
|
||||
if (pbr_send_pbr_map(pbrms, pmi, false, true))
|
||||
sent = true; /* rule removal sent to zebra */
|
||||
|
@ -3,6 +3,7 @@
|
||||
* PBR-map Header
|
||||
* Copyright (C) 2018 Cumulus Networks, Inc.
|
||||
* Donald Sharp
|
||||
* Copyright (c) 2023 LabN Consulting, L.L.C.
|
||||
*/
|
||||
#ifndef __PBR_MAP_H__
|
||||
#define __PBR_MAP_H__
|
||||
@ -71,28 +72,43 @@ struct pbr_map_sequence {
|
||||
*/
|
||||
uint32_t ruleno;
|
||||
|
||||
|
||||
/*****************************************************************
|
||||
* Filter fields
|
||||
* gpz 230716: I hope to replace all of the filter fields with
|
||||
* 'struct pbr_filter' from lib/pbr.h.
|
||||
*****************************************************************/
|
||||
|
||||
/*
|
||||
* src and dst ports
|
||||
* same bit definitions as in lib/pbr.h
|
||||
*/
|
||||
uint32_t filter_bm;
|
||||
|
||||
/* Family of the src/dst. Needed when deleting since we clear them */
|
||||
unsigned char family;
|
||||
|
||||
/* src and dst IP addresses */
|
||||
struct prefix *src;
|
||||
struct prefix *dst;
|
||||
|
||||
/* src and dst UDP/TCP ports */
|
||||
uint16_t src_prt;
|
||||
uint16_t dst_prt;
|
||||
|
||||
/*
|
||||
* The ip protocol we want to match on
|
||||
*/
|
||||
uint8_t ip_proto;
|
||||
|
||||
/*
|
||||
* Our policy Catchers
|
||||
*/
|
||||
struct prefix *src;
|
||||
struct prefix *dst;
|
||||
uint8_t match_pcp;
|
||||
uint16_t match_vlan_id; /* bits defined in lib/pbr.h */
|
||||
|
||||
uint16_t match_vlan_flags;
|
||||
|
||||
uint8_t dsfield;
|
||||
uint32_t mark;
|
||||
|
||||
/*
|
||||
* Actions
|
||||
*/
|
||||
/*****************************************************************
|
||||
* Action fields
|
||||
*****************************************************************/
|
||||
|
||||
uint8_t action_pcp;
|
||||
uint8_t action_vlan_id;
|
||||
#define PBR_MAP_STRIP_INNER_ANY (1 << 0)
|
||||
@ -101,11 +117,6 @@ struct pbr_map_sequence {
|
||||
#define PBR_MAP_UNDEFINED_QUEUE_ID 0
|
||||
uint32_t action_queue_id;
|
||||
|
||||
/*
|
||||
* Family of the src/dst. Needed when deleting since we clear them
|
||||
*/
|
||||
unsigned char family;
|
||||
|
||||
/*
|
||||
* Use interface's vrf.
|
||||
*/
|
||||
@ -222,4 +233,9 @@ extern void pbr_map_check_vrf_nh_group_change(const char *nh_group,
|
||||
extern void pbr_map_check_interface_nh_group_change(const char *nh_group,
|
||||
struct interface *ifp,
|
||||
ifindex_t oldifindex);
|
||||
extern void pbr_set_match_clause_for_vlan(struct pbr_map_sequence *pbrms,
|
||||
uint16_t vlan_id,
|
||||
uint16_t vlan_flags);
|
||||
extern void pbr_set_match_clause_for_pcp(struct pbr_map_sequence *pbrms,
|
||||
bool set, uint8_t pcp);
|
||||
#endif
|
||||
|
116
pbrd/pbr_vty.c
116
pbrd/pbr_vty.c
@ -3,6 +3,9 @@
|
||||
* PBR - vty code
|
||||
* Copyright (C) 2018 Cumulus Networks, Inc.
|
||||
* Donald Sharp
|
||||
* Portions:
|
||||
* Copyright (c) 2021 The MITRE Corporation.
|
||||
* Copyright (c) 2023 LabN Consulting, L.L.C.
|
||||
*/
|
||||
#include <zebra.h>
|
||||
|
||||
@ -25,6 +28,83 @@
|
||||
#include "pbrd/pbr_debug.h"
|
||||
#include "pbrd/pbr_vty_clippy.c"
|
||||
|
||||
/* clang-format off */
|
||||
DEFPY(pbr_map_match_pcp, pbr_map_match_pcp_cmd, "[no] match pcp <(0-7)$pcp>",
|
||||
NO_STR
|
||||
"Match spec follows\n"
|
||||
"Match based on 802.1p Priority Code Point (PCP) value\n"
|
||||
"PCP value to match\n")
|
||||
{
|
||||
/* clang-format on */
|
||||
struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence);
|
||||
|
||||
if (pbrms)
|
||||
pbr_set_match_clause_for_pcp(pbrms, !no, pcp);
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
/* clang-format off */
|
||||
DEFPY(pbr_map_match_vlan_id, pbr_map_match_vlan_id_cmd,
|
||||
"[no] match vlan <(1-4094)$vlan_id>",
|
||||
NO_STR
|
||||
"Match spec follows\n"
|
||||
"Match based on VLAN ID\n"
|
||||
"VLAN ID to match\n")
|
||||
{
|
||||
/* clang-format on */
|
||||
struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence);
|
||||
|
||||
if (pbrms) {
|
||||
if (!no) {
|
||||
pbr_set_match_clause_for_vlan(pbrms, vlan_id, 0);
|
||||
} else {
|
||||
/* if the user previously set a vlan_id value */
|
||||
if (pbrms->match_vlan_id != 0) {
|
||||
if (vlan_id == pbrms->match_vlan_id) {
|
||||
pbr_set_match_clause_for_vlan(pbrms, 0,
|
||||
0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
/* clang-format off */
|
||||
DEFPY(pbr_map_match_vlan_tag, pbr_map_match_vlan_tag_cmd,
|
||||
"[no] match vlan [<tagged|untagged|untagged-or-zero>$tag_type]",
|
||||
NO_STR
|
||||
"Match the rest of the command\n"
|
||||
"Match based on VLAN tagging\n"
|
||||
"Match all tagged frames\n"
|
||||
"Match all untagged frames\n"
|
||||
"Match untagged frames, or tagged frames with id zero\n")
|
||||
{
|
||||
/* clang-format on */
|
||||
struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence);
|
||||
|
||||
if (!pbrms)
|
||||
return CMD_WARNING;
|
||||
|
||||
if (!no) {
|
||||
if (strmatch(tag_type, "tagged")) {
|
||||
pbr_set_match_clause_for_vlan(pbrms, 0,
|
||||
PBR_VLAN_FLAGS_TAGGED);
|
||||
} else if (strmatch(tag_type, "untagged")) {
|
||||
pbr_set_match_clause_for_vlan(pbrms, 0,
|
||||
PBR_VLAN_FLAGS_UNTAGGED);
|
||||
} else if (strmatch(tag_type, "untagged-or-zero")) {
|
||||
pbr_set_match_clause_for_vlan(pbrms, 0,
|
||||
PBR_VLAN_FLAGS_UNTAGGED_0);
|
||||
}
|
||||
} else {
|
||||
pbr_set_match_clause_for_vlan(pbrms, 0, PBR_VLAN_FLAGS_NO_WILD);
|
||||
}
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN_NOSH(pbr_map, pbr_map_cmd, "pbr-map PBRMAP seq (1-700)",
|
||||
"Create pbr-map or enter pbr-map command mode\n"
|
||||
"The name of the PBR MAP\n"
|
||||
@ -185,12 +265,11 @@ DEFPY(pbr_map_match_dst, pbr_map_match_dst_cmd,
|
||||
}
|
||||
|
||||
DEFPY(pbr_map_match_ip_proto, pbr_map_match_ip_proto_cmd,
|
||||
"[no] match ip-protocol [tcp|udp]$ip_proto",
|
||||
"[no] match ip-protocol PROTO$ip_proto",
|
||||
NO_STR
|
||||
"Match the rest of the command\n"
|
||||
"Choose an ip-protocol\n"
|
||||
"Match on tcp flows\n"
|
||||
"Match on udp flows\n")
|
||||
"Protocol name\n")
|
||||
{
|
||||
struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence);
|
||||
struct protoent *p;
|
||||
@ -215,6 +294,8 @@ DEFPY(pbr_map_match_ip_proto, pbr_map_match_ip_proto_cmd,
|
||||
} else
|
||||
pbrms->ip_proto = 0;
|
||||
|
||||
pbr_map_check(pbrms, true);
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
@ -899,6 +980,7 @@ static void vty_show_pbrms(struct vty *vty,
|
||||
vty_out(vty, " SRC Port Match: %u\n", pbrms->src_prt);
|
||||
if (pbrms->dst_prt)
|
||||
vty_out(vty, " DST Port Match: %u\n", pbrms->dst_prt);
|
||||
|
||||
if (pbrms->dsfield & PBR_DSFIELD_DSCP)
|
||||
vty_out(vty, " DSCP Match: %u\n",
|
||||
(pbrms->dsfield & PBR_DSFIELD_DSCP) >> 2);
|
||||
@ -907,9 +989,21 @@ static void vty_show_pbrms(struct vty *vty,
|
||||
pbrms->dsfield & PBR_DSFIELD_ECN);
|
||||
if (pbrms->mark)
|
||||
vty_out(vty, " MARK Match: %u\n", pbrms->mark);
|
||||
if (CHECK_FLAG(pbrms->filter_bm, PBR_FILTER_PCP))
|
||||
vty_out(vty, " PCP Match: %d\n", pbrms->match_pcp);
|
||||
|
||||
if (pbrms->match_vlan_id != 0)
|
||||
vty_out(vty, " Match VLAN ID: %u\n",
|
||||
pbrms->match_vlan_id);
|
||||
if (pbrms->match_vlan_flags == PBR_VLAN_FLAGS_TAGGED)
|
||||
vty_out(vty, " Match VLAN tagged frames\n");
|
||||
if (pbrms->match_vlan_flags == PBR_VLAN_FLAGS_UNTAGGED)
|
||||
vty_out(vty, " Match VLAN untagged frames\n");
|
||||
if (pbrms->match_vlan_flags == PBR_VLAN_FLAGS_UNTAGGED_0)
|
||||
vty_out(vty, " Match VLAN untagged or ID 0\n");
|
||||
|
||||
if (pbrms->action_queue_id != PBR_MAP_UNDEFINED_QUEUE_ID)
|
||||
vty_out(vty, " Set Queue ID %u\n",
|
||||
vty_out(vty, " Set Queue ID: %u\n",
|
||||
pbrms->action_queue_id);
|
||||
|
||||
if (pbrms->action_vlan_id != 0)
|
||||
@ -1306,7 +1400,18 @@ static int pbr_vty_map_config_write_sequence(struct vty *vty,
|
||||
|
||||
if (pbrms->mark)
|
||||
vty_out(vty, " match mark %u\n", pbrms->mark);
|
||||
if (CHECK_FLAG(pbrms->filter_bm, PBR_FILTER_PCP))
|
||||
vty_out(vty, " match pcp %d\n", pbrms->match_pcp);
|
||||
|
||||
if ((pbrms->match_vlan_id) &&
|
||||
(pbrms->match_vlan_flags == PBR_VLAN_FLAGS_NO_WILD))
|
||||
vty_out(vty, " match vlan %u\n", pbrms->match_vlan_id);
|
||||
if (pbrms->match_vlan_flags == PBR_VLAN_FLAGS_TAGGED)
|
||||
vty_out(vty, " match vlan tagged\n");
|
||||
if (pbrms->match_vlan_flags == PBR_VLAN_FLAGS_UNTAGGED)
|
||||
vty_out(vty, " match vlan untagged\n");
|
||||
if (pbrms->match_vlan_flags == PBR_VLAN_FLAGS_UNTAGGED_0)
|
||||
vty_out(vty, " match vlan untagged-or-zero\n");
|
||||
|
||||
if (pbrms->action_queue_id != PBR_MAP_UNDEFINED_QUEUE_ID)
|
||||
vty_out(vty, " set queue-id %d\n", pbrms->action_queue_id);
|
||||
@ -1406,6 +1511,9 @@ void pbr_vty_init(void)
|
||||
install_element(PBRMAP_NODE, &pbr_map_match_dst_cmd);
|
||||
install_element(PBRMAP_NODE, &pbr_map_match_dscp_cmd);
|
||||
install_element(PBRMAP_NODE, &pbr_map_match_ecn_cmd);
|
||||
install_element(PBRMAP_NODE, &pbr_map_match_vlan_id_cmd);
|
||||
install_element(PBRMAP_NODE, &pbr_map_match_vlan_tag_cmd);
|
||||
install_element(PBRMAP_NODE, &pbr_map_match_pcp_cmd);
|
||||
install_element(PBRMAP_NODE, &pbr_map_match_mark_cmd);
|
||||
install_element(PBRMAP_NODE, &pbr_map_action_queue_id_cmd);
|
||||
install_element(PBRMAP_NODE, &pbr_map_action_strip_vlan_cmd);
|
||||
|
Loading…
Reference in New Issue
Block a user