mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-08-03 17:24:26 +00:00
lib: support backup nexthops in nexthop-groups and zapi
Add vty support for backup nexthops in nexthop groups. Capture backup nexthop info in zapi route messages. Signed-off-by: Mark Stapp <mjs@voltanet.io>
This commit is contained in:
parent
62e46303f4
commit
0a8881b4b5
@ -43,8 +43,12 @@ struct nexthop_hold {
|
||||
char *intf;
|
||||
char *labels;
|
||||
uint32_t weight;
|
||||
int backup_idx; /* Index of backup nexthop, if >= 0 */
|
||||
};
|
||||
|
||||
/* Invalid/unset value for nexthop_hold's backup_idx */
|
||||
#define NHH_BACKUP_IDX_INVALID -1
|
||||
|
||||
struct nexthop_group_hooks {
|
||||
void (*new)(const char *name);
|
||||
void (*add_nexthop)(const struct nexthop_group_cmd *nhg,
|
||||
@ -571,11 +575,36 @@ DEFUN_NOSH(no_nexthop_group, no_nexthop_group_cmd, "no nexthop-group NHGNAME",
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFPY(nexthop_group_backup, nexthop_group_backup_cmd,
|
||||
"backup-group WORD$name",
|
||||
"Specify a group name containing backup nexthops\n"
|
||||
"The name of the backup group\n")
|
||||
{
|
||||
VTY_DECLVAR_CONTEXT(nexthop_group_cmd, nhgc);
|
||||
|
||||
strlcpy(nhgc->backup_list_name, name, sizeof(nhgc->backup_list_name));
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFPY(no_nexthop_group_backup, no_nexthop_group_backup_cmd,
|
||||
"no backup-group [WORD$name]",
|
||||
NO_STR
|
||||
"Clear group name containing backup nexthops\n"
|
||||
"The name of the backup group\n")
|
||||
{
|
||||
VTY_DECLVAR_CONTEXT(nexthop_group_cmd, nhgc);
|
||||
|
||||
nhgc->backup_list_name[0] = 0;
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
static void nexthop_group_save_nhop(struct nexthop_group_cmd *nhgc,
|
||||
const char *nhvrf_name,
|
||||
const union sockunion *addr,
|
||||
const char *intf, const char *labels,
|
||||
const uint32_t weight)
|
||||
const uint32_t weight, int backup_idx)
|
||||
{
|
||||
struct nexthop_hold *nh;
|
||||
|
||||
@ -592,6 +621,8 @@ static void nexthop_group_save_nhop(struct nexthop_group_cmd *nhgc,
|
||||
|
||||
nh->weight = weight;
|
||||
|
||||
nh->backup_idx = backup_idx;
|
||||
|
||||
listnode_add_sort(nhgc->nhg_list, nh);
|
||||
}
|
||||
|
||||
@ -633,7 +664,7 @@ static bool nexthop_group_parse_nexthop(struct nexthop *nhop,
|
||||
const union sockunion *addr,
|
||||
const char *intf, const char *name,
|
||||
const char *labels, int *lbl_ret,
|
||||
uint32_t weight)
|
||||
uint32_t weight, int backup_idx)
|
||||
{
|
||||
int ret = 0;
|
||||
struct vrf *vrf;
|
||||
@ -692,6 +723,15 @@ static bool nexthop_group_parse_nexthop(struct nexthop *nhop,
|
||||
|
||||
nhop->weight = weight;
|
||||
|
||||
if (backup_idx != NHH_BACKUP_IDX_INVALID) {
|
||||
/* Validate index value */
|
||||
if (backup_idx > NEXTHOP_BACKUP_IDX_MAX)
|
||||
return false;
|
||||
|
||||
SET_FLAG(nhop->flags, NEXTHOP_FLAG_HAS_BACKUP);
|
||||
nhop->backup_idx = backup_idx;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -703,7 +743,7 @@ static bool nexthop_group_parse_nhh(struct nexthop *nhop,
|
||||
{
|
||||
return (nexthop_group_parse_nexthop(nhop, nhh->addr, nhh->intf,
|
||||
nhh->nhvrf_name, nhh->labels, NULL,
|
||||
nhh->weight));
|
||||
nhh->weight, nhh->backup_idx));
|
||||
}
|
||||
|
||||
DEFPY(ecmp_nexthops, ecmp_nexthops_cmd,
|
||||
@ -716,6 +756,7 @@ DEFPY(ecmp_nexthops, ecmp_nexthops_cmd,
|
||||
nexthop-vrf NAME$vrf_name \
|
||||
|label WORD \
|
||||
|weight (1-255) \
|
||||
|backup-idx$bi_str (0-254)$idx \
|
||||
}]",
|
||||
NO_STR
|
||||
"Specify one of the nexthops in this ECMP group\n"
|
||||
@ -728,16 +769,23 @@ DEFPY(ecmp_nexthops, ecmp_nexthops_cmd,
|
||||
"Specify label(s) for this nexthop\n"
|
||||
"One or more labels in the range (16-1048575) separated by '/'\n"
|
||||
"Weight to be used by the nexthop for purposes of ECMP\n"
|
||||
"Weight value to be used\n")
|
||||
"Weight value to be used\n"
|
||||
"Backup nexthop index in another group\n"
|
||||
"Nexthop index value\n")
|
||||
{
|
||||
VTY_DECLVAR_CONTEXT(nexthop_group_cmd, nhgc);
|
||||
struct nexthop nhop;
|
||||
struct nexthop *nh;
|
||||
int lbl_ret = 0;
|
||||
bool legal;
|
||||
int backup_idx = idx;
|
||||
bool add_update = false;
|
||||
|
||||
if (bi_str == NULL)
|
||||
backup_idx = NHH_BACKUP_IDX_INVALID;
|
||||
|
||||
legal = nexthop_group_parse_nexthop(&nhop, addr, intf, vrf_name, label,
|
||||
&lbl_ret, weight);
|
||||
&lbl_ret, weight, backup_idx);
|
||||
|
||||
if (nhop.type == NEXTHOP_TYPE_IPV6
|
||||
&& IN6_IS_ADDR_LINKLOCAL(&nhop.gate.ipv6)) {
|
||||
@ -769,19 +817,30 @@ DEFPY(ecmp_nexthops, ecmp_nexthops_cmd,
|
||||
|
||||
nh = nexthop_exists(&nhgc->nhg, &nhop);
|
||||
|
||||
if (no) {
|
||||
if (no || nh) {
|
||||
/* Remove or replace cases */
|
||||
|
||||
/* Remove existing config */
|
||||
nexthop_group_unsave_nhop(nhgc, vrf_name, addr, intf, label,
|
||||
weight);
|
||||
if (nh) {
|
||||
/* Remove nexthop object */
|
||||
_nexthop_del(&nhgc->nhg, nh);
|
||||
|
||||
if (nhg_hooks.del_nexthop)
|
||||
nhg_hooks.del_nexthop(nhgc, nh);
|
||||
|
||||
nexthop_free(nh);
|
||||
nh = NULL;
|
||||
}
|
||||
} else if (!nh) {
|
||||
/* must be adding new nexthop since !no and !nexthop_exists */
|
||||
}
|
||||
|
||||
add_update = !no;
|
||||
|
||||
if (add_update) {
|
||||
/* Add or replace cases */
|
||||
|
||||
/* If valid config, add nexthop object */
|
||||
if (legal) {
|
||||
nh = nexthop_new();
|
||||
|
||||
@ -789,8 +848,9 @@ DEFPY(ecmp_nexthops, ecmp_nexthops_cmd,
|
||||
_nexthop_add(&nhgc->nhg.nexthop, nh);
|
||||
}
|
||||
|
||||
/* Save config always */
|
||||
nexthop_group_save_nhop(nhgc, vrf_name, addr, intf, label,
|
||||
weight);
|
||||
weight, backup_idx);
|
||||
|
||||
if (legal && nhg_hooks.add_nexthop)
|
||||
nhg_hooks.add_nexthop(nhgc, nh);
|
||||
@ -853,6 +913,9 @@ void nexthop_group_write_nexthop(struct vty *vty, struct nexthop *nh)
|
||||
if (nh->weight)
|
||||
vty_out(vty, " weight %u", nh->weight);
|
||||
|
||||
if (CHECK_FLAG(nh->flags, NEXTHOP_FLAG_HAS_BACKUP))
|
||||
vty_out(vty, " backup-idx %d", nh->backup_idx);
|
||||
|
||||
vty_out(vty, "\n");
|
||||
}
|
||||
|
||||
@ -878,6 +941,9 @@ static void nexthop_group_write_nexthop_internal(struct vty *vty,
|
||||
if (nh->weight)
|
||||
vty_out(vty, " weight %u", nh->weight);
|
||||
|
||||
if (nh->backup_idx != NHH_BACKUP_IDX_INVALID)
|
||||
vty_out(vty, " backup-idx %d", nh->backup_idx);
|
||||
|
||||
vty_out(vty, "\n");
|
||||
}
|
||||
|
||||
@ -891,6 +957,10 @@ static int nexthop_group_write(struct vty *vty)
|
||||
|
||||
vty_out(vty, "nexthop-group %s\n", nhgc->name);
|
||||
|
||||
if (nhgc->backup_list_name[0])
|
||||
vty_out(vty, " backup-group %s\n",
|
||||
nhgc->backup_list_name);
|
||||
|
||||
for (ALL_LIST_ELEMENTS_RO(nhgc->nhg_list, node, nh)) {
|
||||
vty_out(vty, " ");
|
||||
nexthop_group_write_nexthop_internal(vty, nh);
|
||||
@ -1071,6 +1141,8 @@ void nexthop_group_init(void (*new)(const char *name),
|
||||
install_element(CONFIG_NODE, &no_nexthop_group_cmd);
|
||||
|
||||
install_default(NH_GROUP_NODE);
|
||||
install_element(NH_GROUP_NODE, &nexthop_group_backup_cmd);
|
||||
install_element(NH_GROUP_NODE, &no_nexthop_group_backup_cmd);
|
||||
install_element(NH_GROUP_NODE, &ecmp_nexthops_cmd);
|
||||
|
||||
memset(&nhg_hooks, 0, sizeof(nhg_hooks));
|
||||
|
@ -81,11 +81,16 @@ void nexthop_group_add_sorted(struct nexthop_group *nhg,
|
||||
(nhop) = nexthop_next(nhop)
|
||||
|
||||
|
||||
#define NHGC_NAME_SIZE 80
|
||||
|
||||
struct nexthop_group_cmd {
|
||||
|
||||
RB_ENTRY(nexthop_group_cmd) nhgc_entry;
|
||||
|
||||
char name[80];
|
||||
char name[NHGC_NAME_SIZE];
|
||||
|
||||
/* Name of group containing backup nexthops (if set) */
|
||||
char backup_list_name[NHGC_NAME_SIZE];
|
||||
|
||||
struct nexthop_group nhg;
|
||||
|
||||
|
@ -904,6 +904,7 @@ int zapi_nexthop_encode(struct stream *s, const struct zapi_nexthop *api_nh,
|
||||
}
|
||||
}
|
||||
|
||||
/* If present, set 'weight' flag before encoding flags */
|
||||
if (api_nh->weight)
|
||||
SET_FLAG(nh_flags, ZAPI_NEXTHOP_FLAG_WEIGHT);
|
||||
|
||||
@ -1479,6 +1480,11 @@ struct nexthop *nexthop_from_zapi_nexthop(const struct zapi_nexthop *znh)
|
||||
znh->labels);
|
||||
}
|
||||
|
||||
if (CHECK_FLAG(znh->flags, ZAPI_NEXTHOP_FLAG_HAS_BACKUP)) {
|
||||
SET_FLAG(n->flags, NEXTHOP_FLAG_HAS_BACKUP);
|
||||
n->backup_idx = znh->backup_idx;
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
@ -1510,9 +1516,30 @@ int zapi_nexthop_from_nexthop(struct zapi_nexthop *znh,
|
||||
SET_FLAG(znh->flags, ZAPI_NEXTHOP_FLAG_LABEL);
|
||||
}
|
||||
|
||||
if (CHECK_FLAG(nh->flags, NEXTHOP_FLAG_HAS_BACKUP)) {
|
||||
SET_FLAG(znh->flags, ZAPI_NEXTHOP_FLAG_HAS_BACKUP);
|
||||
znh->backup_idx = nh->backup_idx;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Wrapper that converts backup nexthop
|
||||
*/
|
||||
int zapi_backup_nexthop_from_nexthop(struct zapi_nexthop *znh,
|
||||
const struct nexthop *nh)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/* Ensure that zapi flags are correct: backups don't have backups */
|
||||
ret = zapi_nexthop_from_nexthop(znh, nh);
|
||||
if (ret == 0)
|
||||
UNSET_FLAG(znh->flags, ZAPI_NEXTHOP_FLAG_HAS_BACKUP);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Decode the nexthop-tracking update message
|
||||
*/
|
||||
|
@ -783,10 +783,12 @@ bool zapi_iptable_notify_decode(struct stream *s,
|
||||
uint32_t *unique,
|
||||
enum zapi_iptable_notify_owner *note);
|
||||
|
||||
extern struct nexthop *nexthop_from_zapi_nexthop(
|
||||
const struct zapi_nexthop *znh);
|
||||
extern struct nexthop *
|
||||
nexthop_from_zapi_nexthop(const struct zapi_nexthop *znh);
|
||||
int zapi_nexthop_from_nexthop(struct zapi_nexthop *znh,
|
||||
const struct nexthop *nh);
|
||||
int zapi_backup_nexthop_from_nexthop(struct zapi_nexthop *znh,
|
||||
const struct nexthop *nh);
|
||||
extern bool zapi_nexthop_update_decode(struct stream *s,
|
||||
struct zapi_route *nhr);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user