Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] QPPB | QoS Policy Propagation via BGP (using XDP/BCC/BPF) #12777

Draft
wants to merge 6 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions bgpd/bgp_attr.c
Original file line number Diff line number Diff line change
Expand Up @@ -1076,6 +1076,7 @@ struct attr *bgp_attr_default_set(struct attr *attr, struct bgp *bgp,
attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_AS_PATH);
attr->weight = BGP_ATTR_DEFAULT_WEIGHT;
attr->tag = 0;
attr->dscp = 0;
attr->label_index = BGP_INVALID_LABEL_INDEX;
attr->label = MPLS_INVALID_LABEL;
attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP);
Expand Down
3 changes: 3 additions & 0 deletions bgpd/bgp_attr.h
Original file line number Diff line number Diff line change
Expand Up @@ -309,6 +309,9 @@ struct attr {
/* SR-TE Color */
uint32_t srte_color;

/* DSCP tag, used by the QPPB plugin */
uint8_t dscp;

/* Nexthop type */
enum nexthop_types_t nh_type;

Expand Down
15 changes: 14 additions & 1 deletion bgpd/bgp_route.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include "stream.h"
#include "filter.h"
#include "log.h"
#include "dscp.h"
#include "routemap.h"
#include "buffer.h"
#include "sockunion.h"
Expand Down Expand Up @@ -10156,7 +10157,7 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn,
json_object *json_peer = NULL;
json_object *json_string = NULL;
json_object *json_adv_to = NULL;
int first = 0;
int first = 0, dscp = attr->dscp >> 2;
struct listnode *node, *nnode;
struct peer *peer;
bool addpath_capable;
Expand Down Expand Up @@ -10838,6 +10839,18 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn,
}
}

/* XXX: on Cisco
* R1# sh ip cef 5.5.0.0 de
* 5.5.0.0/24, epoch 0
* QOS: Precedence critical (5)
* recursive via ...
* nexthop ... iface
*/
if (dscp) {
vty_out(vty, " QOS: Precedence %s (%d)\n",
dscp_enum_str(dscp), dscp);
}

/* Line 5 display Extended-community */
if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES)) {
if (json_paths) {
Expand Down
29 changes: 29 additions & 0 deletions bgpd/bgp_routemap.c
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ o Cisco route-map
metric-type : Not yet
origin : Done
tag : Done
dscp : Done
weight : Done
table : Done

Expand Down Expand Up @@ -3567,6 +3568,30 @@ static const struct route_map_rule_cmd route_set_tag_cmd = {
route_map_rule_tag_free,
};

/* Set dscp to object. object must be pointer to struct bgp_path_info */
static enum route_map_cmd_result_t
route_set_dscp(void *rule, const struct prefix *prefix, void *object)
{
struct bgp_path_info *path;
uint8_t *rawDscp;

rawDscp = rule;
path = object;

/* Set dscp value */
path->attr->dscp = *rawDscp;

return RMAP_OKAY;
}

/* Route map commands for dscp set. */
static const struct route_map_rule_cmd route_set_dscp_cmd = {
"dscp",
route_set_dscp,
route_map_rule_dscp_compile,
route_map_rule_dscp_free,
};

/* Set label-index to object. object must be pointer to struct bgp_path_info */
static enum route_map_cmd_result_t
route_set_label_index(void *rule, const struct prefix *prefix, void *object)
Expand Down Expand Up @@ -7840,6 +7865,9 @@ void bgp_route_map_init(void)
route_map_set_tag_hook(generic_set_add);
route_map_no_set_tag_hook(generic_set_delete);

route_map_set_dscp_hook(generic_set_add);
route_map_no_set_dscp_hook(generic_set_delete);

route_map_install_match(&route_match_peer_cmd);
route_map_install_match(&route_match_alias_cmd);
route_map_install_match(&route_match_local_pref_cmd);
Expand Down Expand Up @@ -7903,6 +7931,7 @@ void bgp_route_map_init(void)
route_map_install_set(&route_set_ecommunity_color_cmd);
route_map_install_set(&route_set_ecommunity_none_cmd);
route_map_install_set(&route_set_tag_cmd);
route_map_install_set(&route_set_dscp_cmd);
route_map_install_set(&route_set_label_index_cmd);
route_map_install_set(&route_set_l3vpn_nexthop_encapsulation_cmd);

Expand Down
21 changes: 17 additions & 4 deletions bgpd/bgp_zebra.c
Original file line number Diff line number Diff line change
Expand Up @@ -1233,7 +1233,7 @@ static void bgp_zebra_announce_parse_nexthop(
struct bgp_path_info *info, const struct prefix *p, struct bgp *bgp,
struct zapi_route *api, unsigned int *valid_nh_count, afi_t afi,
safi_t safi, uint32_t *nhg_id, uint32_t *metric, route_tag_t *tag,
bool *allow_recursion)
uint8_t *dscp, bool *allow_recursion)
{
struct zapi_nexthop *api_nh;
int nh_family;
Expand Down Expand Up @@ -1334,13 +1334,21 @@ static void bgp_zebra_announce_parse_nexthop(
p, mpinfo_cp))
continue;

/* metric/tag is only allowed to be
/* metric/tag/dscp is only allowed to be
* overridden on 1st nexthop */
if (mpinfo == info) {
if (metric)
*metric = mpinfo_cp->attr->med;
if (tag)
*tag = mpinfo_cp->attr->tag;
if (dscp) {
/* used by hook from the QPPB plugin */
*dscp = mpinfo_cp->attr->dscp;
/* expose value back to CLI `show bgp ipv4 nh`
* displayed by route_vty_out_detail()`
*/
mpinfo->attr->dscp = *dscp;
}
}
}

Expand Down Expand Up @@ -1532,7 +1540,7 @@ bgp_zebra_announce_actual(struct bgp_dest *dest, struct bgp_path_info *info,
struct zapi_route api = { 0 };
unsigned int valid_nh_count = 0;
bool allow_recursion = false;
uint8_t distance;
uint8_t distance, dscp = 0;
struct peer *peer;
uint32_t metric;
route_tag_t tag;
Expand Down Expand Up @@ -1589,7 +1597,7 @@ bgp_zebra_announce_actual(struct bgp_dest *dest, struct bgp_path_info *info,

bgp_zebra_announce_parse_nexthop(info, p, bgp, &api, &valid_nh_count,
table->afi, table->safi, &nhg_id,
&metric, &tag, &allow_recursion);
&metric, &tag, &dscp, &allow_recursion);

is_add = (valid_nh_count || nhg_id) ? true : false;

Expand Down Expand Up @@ -1637,6 +1645,11 @@ bgp_zebra_announce_actual(struct bgp_dest *dest, struct bgp_path_info *info,
SET_FLAG(api.message, ZAPI_MESSAGE_METRIC);
api.metric = metric;

if (dscp) {
SET_FLAG(api.message, ZAPI_MESSAGE_DSCP);
api.dscp = dscp;
}

if (tag) {
SET_FLAG(api.message, ZAPI_MESSAGE_TAG);
api.tag = tag;
Expand Down
15 changes: 15 additions & 0 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -749,6 +749,8 @@ AC_ARG_ENABLE([bgp-bmp],
AS_HELP_STRING([--disable-bgp-bmp],[turn off BGP BMP support]))
AC_ARG_ENABLE([snmp],
AS_HELP_STRING([--enable-snmp], [enable SNMP support for agentx]))
AC_ARG_ENABLE([qppb],
AS_HELP_STRING([--enable-qppb], [enable QPPB support for BGP (requires libbpf)]))
AC_ARG_ENABLE([config_rollbacks],
AS_HELP_STRING([--enable-config-rollbacks], [enable configuration rollbacks (requires sqlite3)]))
AC_ARG_ENABLE([sysrepo],
Expand Down Expand Up @@ -2079,6 +2081,18 @@ if test "$enable_config_rollbacks" = "yes"; then
])
fi

dnl ---------------
dnl configuration QPPB
dnl ---------------
QPPB=false
if test "$enable_qppb" = "yes"; then
PKG_CHECK_MODULES([LIBBPF], [libbpf], [
QPPB=true
], [
AC_MSG_ERROR([--enable-qppb given but libbpf was not found on your system.])
])
fi

dnl ---------------
dnl sysrepo
dnl ---------------
Expand Down Expand Up @@ -2748,6 +2762,7 @@ AM_CONDITIONAL([ENABLE_BGP_VNC], [test "$enable_bgp_vnc" != "no"])
AM_CONDITIONAL([BGP_BMP], [$bgpd_bmp])
dnl northbound
AM_CONDITIONAL([SQLITE3], [$SQLITE3])
AM_CONDITIONAL([QPPB], [$QPPB])
AM_CONDITIONAL([SYSREPO], [test "$enable_sysrepo" = "yes"])
AM_CONDITIONAL([GRPC], [test "$enable_grpc" = "yes"])
AM_CONDITIONAL([ZEROMQ], [test "$ZEROMQ" = "true"])
Expand Down
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
46 changes: 46 additions & 0 deletions lib/routemap.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include "table.h"
#include "json.h"
#include "jhash.h"
#include "dscp.h"

#include "lib/routemap_clippy.c"

Expand Down Expand Up @@ -446,6 +447,24 @@ void route_map_no_set_tag_hook(int (*func)(struct route_map_index *index,
rmap_match_set_hook.no_set_tag = func;
}

/* set dscp */
void route_map_set_dscp_hook(int (*func)(struct route_map_index *index,
const char *command, const char *arg,
char *errmsg, size_t errmsg_len))
{

rmap_match_set_hook.set_dscp = func;
}

/* no set dscp */
void route_map_no_set_dscp_hook(int (*func)(struct route_map_index *index,
const char *command,
const char *arg, char *errmsg,
size_t errmsg_len))
{
rmap_match_set_hook.no_set_dscp = func;
}

int generic_match_add(struct route_map_index *index,
const char *command, const char *arg,
route_map_event_t type,
Expand Down Expand Up @@ -3228,6 +3247,33 @@ void *route_map_rule_tag_compile(const char *arg)
return tag;
}

void *route_map_rule_dscp_compile(const char *dscp)
{
unsigned long ul_dscp;
char *pend = NULL;
uint8_t *shifted_dscp;

assert(dscp);
ul_dscp = strtoul(dscp, &pend, 0);
if (pend && *pend)
ul_dscp = dscp_decode_enum(dscp);

if (ul_dscp > (DSFIELD_DSCP >> 2)) {
zlog_err("Invalid dscp value: %s%s", dscp,
((pend && *pend) ? "" : " (numeric value must be in range 0-63)"));
return NULL;
}

shifted_dscp = XMALLOC(MTYPE_ROUTE_MAP_COMPILED, sizeof(*shifted_dscp));
*shifted_dscp = (ul_dscp << 2) & DSFIELD_DSCP;
return shifted_dscp;
}

void route_map_rule_dscp_free(void *rule)
{
XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
}

void route_map_rule_tag_free(void *rule)
{
XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
Expand Down
Loading
Loading