summaryrefslogtreecommitdiff
path: root/pbrd
diff options
context:
space:
mode:
Diffstat (limited to 'pbrd')
-rw-r--r--pbrd/pbr_map.c61
-rw-r--r--pbrd/pbr_map.h6
-rw-r--r--pbrd/pbr_nht.c51
-rw-r--r--pbrd/pbr_vty.c107
-rw-r--r--pbrd/pbr_zebra.c1
5 files changed, 200 insertions, 26 deletions
diff --git a/pbrd/pbr_map.c b/pbrd/pbr_map.c
index edc3f1d8da..10a75a9f54 100644
--- a/pbrd/pbr_map.c
+++ b/pbrd/pbr_map.c
@@ -444,6 +444,59 @@ static void pbr_map_add_interfaces(struct pbr_map *pbrm)
}
}
+/* Decodes a standardized DSCP into its representative value */
+uint8_t pbr_map_decode_dscp_enum(const char *name)
+{
+ /* Standard Differentiated Services Field Codepoints */
+ if (!strcmp(name, "cs0"))
+ return 0;
+ if (!strcmp(name, "cs1"))
+ return 8;
+ if (!strcmp(name, "cs2"))
+ return 16;
+ if (!strcmp(name, "cs3"))
+ return 24;
+ if (!strcmp(name, "cs4"))
+ return 32;
+ if (!strcmp(name, "cs5"))
+ return 40;
+ if (!strcmp(name, "cs6"))
+ return 48;
+ if (!strcmp(name, "cs7"))
+ return 56;
+ if (!strcmp(name, "af11"))
+ return 10;
+ if (!strcmp(name, "af12"))
+ return 12;
+ if (!strcmp(name, "af13"))
+ return 14;
+ if (!strcmp(name, "af21"))
+ return 18;
+ if (!strcmp(name, "af22"))
+ return 20;
+ if (!strcmp(name, "af23"))
+ return 22;
+ if (!strcmp(name, "af31"))
+ return 26;
+ if (!strcmp(name, "af32"))
+ return 28;
+ if (!strcmp(name, "af33"))
+ return 30;
+ if (!strcmp(name, "af41"))
+ return 34;
+ if (!strcmp(name, "af42"))
+ return 36;
+ if (!strcmp(name, "af43"))
+ return 38;
+ if (!strcmp(name, "ef"))
+ return 46;
+ if (!strcmp(name, "voice-admit"))
+ return 44;
+
+ /* No match? Error out */
+ return -1;
+}
+
struct pbr_map_sequence *pbrms_get(const char *name, uint32_t seqno)
{
struct pbr_map *pbrm;
@@ -547,7 +600,7 @@ 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)
+ if (!pbrms->src && !pbrms->dst && !pbrms->mark && !pbrms->dsfield)
pbrms->reason |= PBR_MAP_INVALID_EMPTY;
}
@@ -603,7 +656,7 @@ bool pbr_map_check_valid(const char *name)
return pbrm->valid;
}
-void pbr_map_schedule_policy_from_nhg(const char *nh_group)
+void pbr_map_schedule_policy_from_nhg(const char *nh_group, bool installed)
{
struct pbr_map_sequence *pbrms;
struct pbr_map *pbrm;
@@ -618,7 +671,7 @@ void pbr_map_schedule_policy_from_nhg(const char *nh_group)
if (pbrms->nhgrp_name
&& (strcmp(nh_group, pbrms->nhgrp_name) == 0)) {
- pbrms->nhs_installed = true;
+ pbrms->nhs_installed = installed;
pbr_map_check(pbrms, false);
}
@@ -626,7 +679,7 @@ void pbr_map_schedule_policy_from_nhg(const char *nh_group)
if (pbrms->nhg
&& (strcmp(nh_group, pbrms->internal_nhg_name)
== 0)) {
- pbrms->nhs_installed = true;
+ pbrms->nhs_installed = installed;
pbr_map_check(pbrms, false);
}
diff --git a/pbrd/pbr_map.h b/pbrd/pbr_map.h
index 41f1703954..64c090d2e8 100644
--- a/pbrd/pbr_map.h
+++ b/pbrd/pbr_map.h
@@ -89,6 +89,7 @@ struct pbr_map_sequence {
*/
struct prefix *src;
struct prefix *dst;
+ uint8_t dsfield;
uint32_t mark;
/*
@@ -168,6 +169,8 @@ 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 uint8_t pbr_map_decode_dscp_enum(const char *name);
+
/* Update maps installed on interface */
extern void pbr_map_policy_interface_update(const struct interface *ifp,
bool state_up);
@@ -194,7 +197,8 @@ extern void pbr_map_check(struct pbr_map_sequence *pbrms, bool changed);
extern void pbr_map_check_nh_group_change(const char *nh_group);
extern void pbr_map_reason_string(unsigned int reason, char *buf, int size);
-extern void pbr_map_schedule_policy_from_nhg(const char *nh_group);
+extern void pbr_map_schedule_policy_from_nhg(const char *nh_group,
+ bool installed);
extern void pbr_map_install(struct pbr_map *pbrm);
diff --git a/pbrd/pbr_nht.c b/pbrd/pbr_nht.c
index 98be958fce..31da656793 100644
--- a/pbrd/pbr_nht.c
+++ b/pbrd/pbr_nht.c
@@ -328,27 +328,29 @@ static struct pbr_nexthop_cache *pbr_nht_lookup_nexthop(struct nexthop *nexthop)
}
#endif
+static void
+pbr_nht_find_nhg_from_table_update(struct pbr_nexthop_group_cache *pnhgc,
+ uint32_t table_id, bool installed)
+{
+ if (pnhgc->table_id == table_id) {
+ DEBUGD(&pbr_dbg_nht, "%s: %s: Table ID (%u) matches %s",
+ __func__, (installed ? "install" : "remove"), table_id,
+ pnhgc->name);
+
+ pnhgc->installed = installed;
+ pnhgc->valid = installed;
+ pbr_map_schedule_policy_from_nhg(pnhgc->name, pnhgc->installed);
+ }
+}
+
static void pbr_nht_find_nhg_from_table_install(struct hash_bucket *b,
void *data)
{
struct pbr_nexthop_group_cache *pnhgc =
(struct pbr_nexthop_group_cache *)b->data;
- uint32_t *table_id = (uint32_t *)data;
-
- if (pnhgc->table_id == *table_id) {
- DEBUGD(&pbr_dbg_nht, "%s: Table ID (%u) matches %s", __func__,
- *table_id, pnhgc->name);
+ uint32_t table_id = *(uint32_t *)data;
- /*
- * If the table has been re-handled by zebra
- * and we are already installed no need to do
- * anything here.
- */
- if (!pnhgc->installed) {
- pnhgc->installed = true;
- pbr_map_schedule_policy_from_nhg(pnhgc->name);
- }
- }
+ pbr_nht_find_nhg_from_table_update(pnhgc, table_id, true);
}
void pbr_nht_route_installed_for_table(uint32_t table_id)
@@ -360,7 +362,11 @@ void pbr_nht_route_installed_for_table(uint32_t table_id)
static void pbr_nht_find_nhg_from_table_remove(struct hash_bucket *b,
void *data)
{
- ;
+ struct pbr_nexthop_group_cache *pnhgc =
+ (struct pbr_nexthop_group_cache *)b->data;
+ uint32_t table_id = *(uint32_t *)data;
+
+ pbr_nht_find_nhg_from_table_update(pnhgc, table_id, false);
}
void pbr_nht_route_removed_for_table(uint32_t table_id)
@@ -852,12 +858,15 @@ static void pbr_nht_nexthop_update_lookup(struct hash_bucket *b, void *data)
*/
pnhgc->valid = !!pnhi.valid;
- if (pnhgc->valid) {
- pbr_nexthop_group_cache_to_nexthop_group(&nhg, pnhgc);
+ pbr_nexthop_group_cache_to_nexthop_group(&nhg, pnhgc);
+
+ if (pnhgc->valid)
pbr_nht_install_nexthop_group(pnhgc, nhg);
- /* Don't need copied nexthops anymore */
- nexthops_free(nhg.nexthop);
- }
+ else
+ pbr_nht_uninstall_nexthop_group(pnhgc, nhg, 0);
+
+ /* Don't need copied nexthops anymore */
+ nexthops_free(nhg.nexthop);
if (old_valid != pnhgc->valid)
pbr_map_check_nh_group_change(pnhgc->name);
diff --git a/pbrd/pbr_vty.c b/pbrd/pbr_vty.c
index cd9096cbc8..a73d885ea6 100644
--- a/pbrd/pbr_vty.c
+++ b/pbrd/pbr_vty.c
@@ -183,6 +183,91 @@ DEFPY(pbr_map_match_dst, pbr_map_match_dst_cmd,
return CMD_SUCCESS;
}
+DEFPY(pbr_map_match_dscp, pbr_map_match_dscp_cmd,
+ "[no] match dscp DSCP$dscp",
+ NO_STR
+ "Match the rest of the command\n"
+ "Match based on IP DSCP field\n"
+ "DSCP value (below 64) or standard codepoint name\n")
+{
+ struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence);
+ char dscpname[100];
+ uint8_t rawDscp;
+
+ /* Discriminate dscp enums (cs0, cs1 etc.) and numbers */
+ bool isANumber = true;
+ for (int i = 0; i < (int)strlen(dscp); i++) {
+ /* Letters are not numbers */
+ if (!isdigit(dscp[i]))
+ isANumber = false;
+
+ /* Lowercase the dscp enum (if needed) */
+ if (isupper(dscp[i]))
+ dscpname[i] = tolower(dscp[i]);
+ else
+ dscpname[i] = dscp[i];
+ }
+ dscpname[strlen(dscp)] = '\0';
+
+ if (isANumber) {
+ /* dscp passed is a regular number */
+ long dscpAsNum = strtol(dscp, NULL, 0);
+
+ if (dscpAsNum > PBR_DSFIELD_DSCP >> 2) {
+ /* Refuse to install on overflow */
+ vty_out(vty, "dscp (%s) must be less than 64\n", dscp);
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+ rawDscp = dscpAsNum;
+ } else {
+ /* check dscp if it is an enum like cs0 */
+ rawDscp = pbr_map_decode_dscp_enum(dscpname);
+ if (rawDscp > PBR_DSFIELD_DSCP) {
+ vty_out(vty, "Invalid dscp value: %s\n", dscpname);
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+ }
+
+ if (!no) {
+ if (((pbrms->dsfield & PBR_DSFIELD_DSCP) >> 2) == rawDscp)
+ return CMD_SUCCESS;
+
+ /* Set the DSCP bits of the DSField */
+ pbrms->dsfield =
+ (pbrms->dsfield & ~PBR_DSFIELD_DSCP) | (rawDscp << 2);
+ } else {
+ pbrms->dsfield &= ~PBR_DSFIELD_DSCP;
+ }
+
+ pbr_map_check(pbrms, true);
+
+ return CMD_SUCCESS;
+}
+
+DEFPY(pbr_map_match_ecn, pbr_map_match_ecn_cmd,
+ "[no] match ecn (0-3)$ecn",
+ NO_STR
+ "Match the rest of the command\n"
+ "Match based on IP ECN field\n"
+ "Explicit Congestion Notification\n")
+{
+ struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence);
+
+ if (!no) {
+ if ((pbrms->dsfield & PBR_DSFIELD_ECN) == ecn)
+ return CMD_SUCCESS;
+
+ /* Set the ECN bits of the DSField */
+ pbrms->dsfield = (pbrms->dsfield & ~PBR_DSFIELD_ECN) | ecn;
+ } else {
+ pbrms->dsfield &= ~PBR_DSFIELD_ECN;
+ }
+
+ pbr_map_check(pbrms, true);
+
+ return CMD_SUCCESS;
+}
+
DEFPY(pbr_map_match_mark, pbr_map_match_mark_cmd,
"[no] match mark (1-4294967295)$mark",
NO_STR
@@ -559,6 +644,12 @@ static void vty_show_pbrms(struct vty *vty,
if (pbrms->dst)
vty_out(vty, " DST Match: %s\n",
prefix2str(pbrms->dst, buf, sizeof(buf)));
+ if (pbrms->dsfield & PBR_DSFIELD_DSCP)
+ vty_out(vty, " DSCP Match: %u\n",
+ (pbrms->dsfield & PBR_DSFIELD_DSCP) >> 2);
+ if (pbrms->dsfield & PBR_DSFIELD_ECN)
+ vty_out(vty, " ECN Match: %u\n",
+ pbrms->dsfield & PBR_DSFIELD_ECN);
if (pbrms->mark)
vty_out(vty, " MARK Match: %u\n", pbrms->mark);
@@ -653,6 +744,12 @@ static void vty_json_pbrms(json_object *j, struct vty *vty,
prefix2str(pbrms->dst, buf, sizeof(buf)));
if (pbrms->mark)
json_object_int_add(jpbrm, "matchMark", pbrms->mark);
+ if (pbrms->dsfield & PBR_DSFIELD_DSCP)
+ json_object_int_add(jpbrm, "matchDscp",
+ (pbrms->dsfield & PBR_DSFIELD_DSCP) >> 2);
+ if (pbrms->dsfield & PBR_DSFIELD_ECN)
+ json_object_int_add(jpbrm, "matchEcn",
+ pbrms->dsfield & PBR_DSFIELD_ECN);
json_object_array_add(j, jpbrm);
}
@@ -946,6 +1043,14 @@ static int pbr_vty_map_config_write_sequence(struct vty *vty,
vty_out(vty, " match dst-ip %s\n",
prefix2str(pbrms->dst, buff, sizeof(buff)));
+ if (pbrms->dsfield & PBR_DSFIELD_DSCP)
+ vty_out(vty, " match dscp %u\n",
+ (pbrms->dsfield & PBR_DSFIELD_DSCP) >> 2);
+
+ if (pbrms->dsfield & PBR_DSFIELD_ECN)
+ vty_out(vty, " match ecn %u\n",
+ pbrms->dsfield & PBR_DSFIELD_ECN);
+
if (pbrms->mark)
vty_out(vty, " match mark %u\n", pbrms->mark);
@@ -1026,6 +1131,8 @@ void pbr_vty_init(void)
install_element(INTERFACE_NODE, &pbr_policy_cmd);
install_element(PBRMAP_NODE, &pbr_map_match_src_cmd);
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_mark_cmd);
install_element(PBRMAP_NODE, &pbr_map_nexthop_group_cmd);
install_element(PBRMAP_NODE, &no_pbr_map_nexthop_group_cmd);
diff --git a/pbrd/pbr_zebra.c b/pbrd/pbr_zebra.c
index de2a99e269..d0099a46e3 100644
--- a/pbrd/pbr_zebra.c
+++ b/pbrd/pbr_zebra.c
@@ -536,6 +536,7 @@ static void pbr_encode_pbr_map_sequence(struct stream *s,
stream_putw(s, 0); /* src port */
pbr_encode_pbr_map_sequence_prefix(s, pbrms->dst, family);
stream_putw(s, 0); /* dst port */
+ stream_putc(s, pbrms->dsfield);
stream_putl(s, pbrms->mark);
if (pbrms->vrf_unchanged || pbrms->vrf_lookup)