summaryrefslogtreecommitdiff
path: root/pbrd
diff options
context:
space:
mode:
authorG. Paul Ziemba <paulz@labn.net>2023-07-19 07:58:02 -0700
committerG. Paul Ziemba <paulz@labn.net>2023-07-19 08:14:09 -0700
commitbfd3e8e012f22c62f628f836532e9805b10ae493 (patch)
tree193ca20fd87068f0278d34ce63a991aed40c37c5 /pbrd
parentff10abcc89581c1ed94a45f92fc76daf863c512e (diff)
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>
Diffstat (limited to 'pbrd')
-rw-r--r--pbrd/pbr_map.c57
-rw-r--r--pbrd/pbr_map.h50
-rw-r--r--pbrd/pbr_vty.c118
3 files changed, 195 insertions, 30 deletions
diff --git a/pbrd/pbr_map.c b/pbrd/pbr_map.c
index 16cea3b4cd..758e08b565 100644
--- a/pbrd/pbr_map.c
+++ b/pbrd/pbr_map.c
@@ -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 */
diff --git a/pbrd/pbr_map.h b/pbrd/pbr_map.h
index c9da431b38..3afb199565 100644
--- a/pbrd/pbr_map.h
+++ b/pbrd/pbr_map.h
@@ -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)
@@ -102,11 +118,6 @@ struct pbr_map_sequence {
uint32_t action_queue_id;
/*
- * Family of the src/dst. Needed when deleting since we clear them
- */
- unsigned char family;
-
- /*
* Use interface's vrf.
*/
bool vrf_unchanged;
@@ -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
diff --git a/pbrd/pbr_vty.c b/pbrd/pbr_vty.c
index ee9ee32f8b..bc83c2d61c 100644
--- a/pbrd/pbr_vty.c
+++ b/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);