Skip to content

Commit

Permalink
lib, pbrd: Move DSCP logic into a library module
Browse files Browse the repository at this point in the history
Pull out all DSCP related code from PBR into a separate library module.
Relevant for route-maps used by the QPPB plugin.

Signed-off-by: Volodymyr Huti <[email protected]>
  • Loading branch information
Volodymyr Huti committed Oct 31, 2023
1 parent 644386f commit 4e1f4a4
Show file tree
Hide file tree
Showing 11 changed files with 144 additions and 87 deletions.
82 changes: 82 additions & 0 deletions lib/dscp.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* DSCP manipulation routines
* Copyright (C) 2023 VyOS Inc.
* Volodymyr Huti
*/

#include "dscp.h"

enum dscp_val {
DSCP_CS0 = 0x00,
DSCP_CS1 = 0x08,
DSCP_CS2 = 0x10,
DSCP_CS3 = 0x18,
DSCP_CS4 = 0x20,
DSCP_CS5 = 0x28,
DSCP_CS6 = 0x30,
DSCP_CS7 = 0x38,
DSCP_AF11 = 0x0A,
DSCP_AF12 = 0x0C,
DSCP_AF13 = 0x0E,
DSCP_AF21 = 0x12,
DSCP_AF22 = 0x14,
DSCP_AF23 = 0x16,
DSCP_AF31 = 0x1A,
DSCP_AF32 = 0x1C,
DSCP_AF33 = 0x1E,
DSCP_AF41 = 0x22,
DSCP_AF42 = 0x34,
DSCP_AF43 = 0x26,
DSCP_EF = 0x2E,
DSCP_VOICE = 0x2C,
DSCP_MAX = DSCP_CS7 + 1,
DSCP_ERR
};

static const struct {
const char *name;
int val;
} dscp_enum_int_map[] = {
{"cs0", DSCP_CS0}, {"cs1", DSCP_CS1}, {"cs2", DSCP_CS2},
{"cs3", DSCP_CS3}, {"cs4", DSCP_CS4}, {"cs5", DSCP_CS5},
{"cs6", DSCP_CS6}, {"cs7", DSCP_CS7}, {"af11", DSCP_AF11},
{"af12", DSCP_AF12}, {"af13", DSCP_AF13}, {"af21", DSCP_AF21},
{"af22", DSCP_AF22}, {"af23", DSCP_AF23}, {"af31", DSCP_AF31},
{"af32", DSCP_AF32}, {"af33", DSCP_AF33}, {"af41", DSCP_AF41},
{"af42", DSCP_AF42}, {"af43", DSCP_AF43}, {"ef", DSCP_EF},
{"voice-admit", DSCP_VOICE}};

static const char *dscp_int_enum_map[DSCP_MAX] = {
[DSCP_CS0] = "cs0", [DSCP_CS1] = "cs1", [DSCP_CS2] = "cs2",
[DSCP_CS3] = "cs3", [DSCP_CS4] = "cs4", [DSCP_CS5] = "cs5",
[DSCP_CS6] = "cs6", [DSCP_CS7] = "cs7", [DSCP_AF11] = "af11",
[DSCP_AF12] = "af12", [DSCP_AF13] = "af13", [DSCP_AF21] = "af21",
[DSCP_AF22] = "af22", [DSCP_AF23] = "af23", [DSCP_AF31] = "af31",
[DSCP_AF32] = "af32", [DSCP_AF33] = "af33", [DSCP_AF41] = "af41",
[DSCP_AF42] = "af42", [DSCP_AF43] = "af43", [DSCP_EF] = "ef",
[DSCP_VOICE] = "voice-admit"};

static const int dscp_msize =
(sizeof(dscp_enum_int_map) / sizeof(*dscp_enum_int_map));

/* Decodes a standardized DSCP into its representative value */
uint8_t dscp_decode_enum(const char *name)
{
int dscp_val = -1;

for (int i = 0; i < dscp_msize; ++i) {
if (!strcmp(dscp_enum_int_map[i].name, name)) {
dscp_val = dscp_enum_int_map[i].val;
break;
}
}

return dscp_val;
}

const char *dscp_enum_str(int dscp)
{
return (dscp < DSCP_MAX) ? dscp_int_enum_map[dscp] : NULL;
}

28 changes: 28 additions & 0 deletions lib/dscp.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* DSCP manipulation routines header
* Copyright (C) 2023 VyOS Inc.
* Volodymyr Huti
*/

#ifndef FRR_DSCP_H
#define FRR_DSCP_H

#ifdef __cplusplus
extern "C" {
#endif

#include <zebra.h>
#include "vty.h"

#define DSFIELD_DSCP (0xfc) /* Upper 6 bits of DS field: DSCP */
#define DSFIELD_ECN (0x03) /* Lower 2 bits of DS field: BCN */

extern uint8_t dscp_decode_enum(const char *dscp);
extern const char *dscp_enum_str(int dscp);

#ifdef __cplusplus
}
#endif

#endif /* FRR_DSCP_H */
3 changes: 0 additions & 3 deletions lib/pbr.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,6 @@ struct pbr_filter {
#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*/

#define PBR_VLAN_FLAGS_NO_WILD 0
Expand Down
1 change: 1 addition & 0 deletions lib/subdir.am
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@ lib_libfrr_la_SOURCES = \
lib/printf/glue.c \
lib/routing_nb.c \
lib/routing_nb_config.c \
lib/dscp.c \
lib/tc.c \
# end

Expand Down
15 changes: 8 additions & 7 deletions lib/zclient.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
#include "srte.h"
#include "printfrr.h"
#include "srv6.h"
#include "dscp.h"

DEFINE_MTYPE_STATIC(LIB, ZCLIENT, "Zclient");
DEFINE_MTYPE_STATIC(LIB, REDIST_INST, "Redistribution instance IDs");
Expand Down Expand Up @@ -1699,9 +1700,9 @@ static void zapi_pbr_rule_filter_encode(struct stream *s, struct pbr_filter *f)
stream_putw(s, f->dst_port);

if (CHECK_FLAG(f->filter_bm, PBR_FILTER_DSCP))
stream_putc(s, f->dsfield & PBR_DSFIELD_DSCP);
stream_putc(s, f->dsfield & DSFIELD_DSCP);
if (CHECK_FLAG(f->filter_bm, PBR_FILTER_ECN))
stream_putc(s, f->dsfield & PBR_DSFIELD_ECN);
stream_putc(s, f->dsfield & DSFIELD_ECN);

/* vlan */
if (CHECK_FLAG(f->filter_bm, PBR_FILTER_PCP))
Expand Down Expand Up @@ -1742,7 +1743,7 @@ static bool zapi_pbr_rule_filter_decode(struct stream *s, struct pbr_filter *f)
STREAM_GETC(s, dscp);
if (CHECK_FLAG(f->filter_bm, PBR_FILTER_ECN))
STREAM_GETC(s, ecn);
f->dsfield = (dscp & PBR_DSFIELD_DSCP) | (ecn & PBR_DSFIELD_ECN);
f->dsfield = (dscp & DSFIELD_DSCP) | (ecn & DSFIELD_ECN);

/* vlan */
if (CHECK_FLAG(f->filter_bm, PBR_FILTER_PCP))
Expand Down Expand Up @@ -1781,9 +1782,9 @@ static void zapi_pbr_rule_action_encode(struct stream *s, struct pbr_action *a)
stream_putw(s, a->dst_port);

if (CHECK_FLAG(a->flags, PBR_ACTION_DSCP))
stream_putc(s, a->dscp & PBR_DSFIELD_DSCP);
stream_putc(s, a->dscp & DSFIELD_DSCP);
if (CHECK_FLAG(a->flags, PBR_ACTION_ECN))
stream_putc(s, a->ecn & PBR_DSFIELD_ECN);
stream_putc(s, a->ecn & DSFIELD_ECN);

/* L2 */
if (CHECK_FLAG(a->flags, PBR_ACTION_PCP))
Expand Down Expand Up @@ -1817,11 +1818,11 @@ static bool zapi_pbr_rule_action_decode(struct stream *s, struct pbr_action *a)

if (CHECK_FLAG(a->flags, PBR_ACTION_DSCP)) {
STREAM_GETC(s, a->dscp);
a->dscp &= PBR_DSFIELD_DSCP;
a->dscp &= DSFIELD_DSCP;
}
if (CHECK_FLAG(a->flags, PBR_ACTION_ECN)) {
STREAM_GETC(s, a->ecn);
a->ecn &= PBR_DSFIELD_ECN;
a->ecn &= DSFIELD_ECN;
}

/* L2 */
Expand Down
53 changes: 0 additions & 53 deletions pbrd/pbr_map.c
Original file line number Diff line number Diff line change
Expand Up @@ -440,59 +440,6 @@ 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 = NULL;
Expand Down
2 changes: 0 additions & 2 deletions pbrd/pbr_map.h
Original file line number Diff line number Diff line change
Expand Up @@ -214,8 +214,6 @@ 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);
Expand Down
38 changes: 19 additions & 19 deletions pbrd/pbr_vty.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include "json.h"
#include "debug.h"
#include "pbr.h"
#include "dscp.h"

#include "pbrd/pbr_nht.h"
#include "pbrd/pbr_map.h"
Expand Down Expand Up @@ -437,7 +438,7 @@ DEFPY (pbr_map_match_dscp,
if (!CHECK_FLAG(pbrms->filter_bm, PBR_FILTER_DSCP))
return CMD_SUCCESS;
UNSET_FLAG(pbrms->filter_bm, PBR_FILTER_DSCP);
pbrms->dsfield &= ~PBR_DSFIELD_DSCP;
pbrms->dsfield &= ~DSFIELD_DSCP;
goto check;
}

Expand All @@ -448,23 +449,23 @@ DEFPY (pbr_map_match_dscp,
assert(dscp);
ul_dscp = strtoul(dscp, &pend, 0);
if (pend && *pend)
ul_dscp = pbr_map_decode_dscp_enum(dscp);
ul_dscp = dscp_decode_enum(dscp);

if (ul_dscp > (PBR_DSFIELD_DSCP >> 2)) {
if (ul_dscp > (DSFIELD_DSCP >> 2)) {
vty_out(vty, "Invalid dscp value: %s%s\n", dscp,
((pend && *pend) ? "" : " (numeric value must be in range 0-63)"));
return CMD_WARNING_CONFIG_FAILED;
}

shifted_dscp = (ul_dscp << 2) & PBR_DSFIELD_DSCP;
shifted_dscp = (ul_dscp << 2) & DSFIELD_DSCP;

if (CHECK_FLAG(pbrms->filter_bm, PBR_FILTER_DSCP) &&
((pbrms->dsfield & PBR_DSFIELD_DSCP) == shifted_dscp)) {
((pbrms->dsfield & DSFIELD_DSCP) == shifted_dscp)) {
return CMD_SUCCESS;
}

/* Set the DSCP bits of the DSField */
pbrms->dsfield = (pbrms->dsfield & ~PBR_DSFIELD_DSCP) | shifted_dscp;
pbrms->dsfield = (pbrms->dsfield & ~DSFIELD_DSCP) | shifted_dscp;
SET_FLAG(pbrms->filter_bm, PBR_FILTER_DSCP);

check:
Expand All @@ -491,17 +492,17 @@ DEFPY (pbr_map_match_ecn,
if (!CHECK_FLAG(pbrms->filter_bm, PBR_FILTER_ECN))
return CMD_SUCCESS;
UNSET_FLAG(pbrms->filter_bm, PBR_FILTER_ECN);
pbrms->dsfield &= ~PBR_DSFIELD_ECN;
pbrms->dsfield &= ~DSFIELD_ECN;
goto check;
}

if (CHECK_FLAG(pbrms->filter_bm, PBR_FILTER_ECN) &&
((pbrms->dsfield & PBR_DSFIELD_ECN) == ecn)) {
((pbrms->dsfield & DSFIELD_ECN) == ecn)) {
return CMD_SUCCESS;
}

/* Set the ECN bits of the DSField */
pbrms->dsfield = (pbrms->dsfield & ~PBR_DSFIELD_ECN) | ecn;
pbrms->dsfield = (pbrms->dsfield & ~DSFIELD_ECN) | ecn;
SET_FLAG(pbrms->filter_bm, PBR_FILTER_ECN);

check:
Expand Down Expand Up @@ -876,15 +877,15 @@ DEFPY (pbr_map_action_dscp,
assert(dscp);
ul_dscp = strtoul(dscp, &pend, 0);
if (pend && *pend)
ul_dscp = pbr_map_decode_dscp_enum(dscp);
ul_dscp = dscp_decode_enum(dscp);

if (ul_dscp > (PBR_DSFIELD_DSCP >> 2)) {
if (ul_dscp > (DSFIELD_DSCP >> 2)) {
vty_out(vty, "Invalid dscp value: %s%s\n", dscp,
((pend && *pend) ? "" : " (numeric value must be in range 0-63)"));
return CMD_WARNING_CONFIG_FAILED;
}

shifted_dscp = (ul_dscp << 2) & PBR_DSFIELD_DSCP;
shifted_dscp = (ul_dscp << 2) & DSFIELD_DSCP;

if (CHECK_FLAG(pbrms->action_bm, PBR_ACTION_DSCP) &&
(pbrms->action_dscp == shifted_dscp)) {
Expand Down Expand Up @@ -1549,10 +1550,10 @@ static void vty_show_pbrms(struct vty *vty,

if (CHECK_FLAG(pbrms->filter_bm, PBR_FILTER_DSCP))
vty_out(vty, " DSCP Match: %u\n",
(pbrms->dsfield & PBR_DSFIELD_DSCP) >> 2);
(pbrms->dsfield & DSFIELD_DSCP) >> 2);
if (CHECK_FLAG(pbrms->filter_bm, PBR_FILTER_ECN))
vty_out(vty, " ECN Match: %u\n",
pbrms->dsfield & PBR_DSFIELD_ECN);
pbrms->dsfield & DSFIELD_ECN);

if (CHECK_FLAG(pbrms->filter_bm, PBR_FILTER_FWMARK))
vty_out(vty, " MARK Match: %u\n", pbrms->mark);
Expand Down Expand Up @@ -1717,11 +1718,10 @@ static void vty_json_pbrms(json_object *j, struct vty *vty,

if (CHECK_FLAG(pbrms->filter_bm, PBR_FILTER_DSCP))
json_object_int_add(jpbrm, "matchDscp",
(pbrms->dsfield & PBR_DSFIELD_DSCP) >> 2);
(pbrms->dsfield & DSFIELD_DSCP) >> 2);
if (CHECK_FLAG(pbrms->filter_bm, PBR_FILTER_ECN))
json_object_int_add(jpbrm, "matchEcn",
pbrms->dsfield & PBR_DSFIELD_ECN);

pbrms->dsfield & DSFIELD_ECN);
/* L2 headers */
if (CHECK_FLAG(pbrms->filter_bm, PBR_FILTER_PCP))
json_object_int_add(jpbrm, "matchPcp", pbrms->match_pcp);
Expand Down Expand Up @@ -2067,11 +2067,11 @@ static int pbr_vty_map_config_write_sequence(struct vty *vty,

if (CHECK_FLAG(pbrms->filter_bm, PBR_FILTER_DSCP))
vty_out(vty, " match dscp %u\n",
(pbrms->dsfield & PBR_DSFIELD_DSCP) >> 2);
(pbrms->dsfield & DSFIELD_DSCP) >> 2);

if (CHECK_FLAG(pbrms->filter_bm, PBR_FILTER_ECN))
vty_out(vty, " match ecn %u\n",
pbrms->dsfield & PBR_DSFIELD_ECN);
pbrms->dsfield & DSFIELD_ECN);

if (CHECK_FLAG(pbrms->filter_bm, PBR_FILTER_PCP))
vty_out(vty, " match pcp %d\n", pbrms->match_pcp);
Expand Down
1 change: 1 addition & 0 deletions tests/lib/cxxcompat.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
#include "lib/if.h"
#include "lib/if_rmap.h"
#include "lib/imsg.h"
#include "lib/dscp.h"
#include "lib/ipaddr.h"
#include "lib/jhash.h"
#include "lib/json.h"
Expand Down
Loading

0 comments on commit 4e1f4a4

Please sign in to comment.