mirror of
https://git.proxmox.com/git/mirror_frr
synced 2026-01-04 02:56:54 +00:00
Merge pull request #5901 from mjstapp/backup_nh_prep
zebra, lib: Backup nexthop (path) prep work
This commit is contained in:
commit
ff82bbbb91
@ -112,7 +112,7 @@ static inline void ipv4_to_ipv4_mapped_ipv6(struct in6_addr *in6,
|
||||
/*
|
||||
* convert an ipv4 mapped ipv6 address back to ipv4 address
|
||||
*/
|
||||
static inline void ipv4_mapped_ipv6_to_ipv4(struct in6_addr *in6,
|
||||
static inline void ipv4_mapped_ipv6_to_ipv4(const struct in6_addr *in6,
|
||||
struct in_addr *in)
|
||||
{
|
||||
memset(in, 0, sizeof(struct in_addr));
|
||||
|
||||
@ -79,7 +79,7 @@ int mpls_str2label(const char *label_str, uint8_t *num_labels,
|
||||
/*
|
||||
* Label to string conversion, labels in string separated by '/'.
|
||||
*/
|
||||
char *mpls_label2str(uint8_t num_labels, mpls_label_t *labels, char *buf,
|
||||
char *mpls_label2str(uint8_t num_labels, const mpls_label_t *labels, char *buf,
|
||||
int len, int pretty)
|
||||
{
|
||||
char label_buf[BUFSIZ];
|
||||
|
||||
@ -209,10 +209,13 @@ static inline char *label2str(mpls_label_t label, char *buf, size_t len)
|
||||
int mpls_str2label(const char *label_str, uint8_t *num_labels,
|
||||
mpls_label_t *labels);
|
||||
|
||||
/* Generic string buffer for label-stack-to-str */
|
||||
#define MPLS_LABEL_STRLEN 1024
|
||||
|
||||
/*
|
||||
* Label to string conversion, labels in string separated by '/'.
|
||||
*/
|
||||
char *mpls_label2str(uint8_t num_labels, mpls_label_t *labels, char *buf,
|
||||
char *mpls_label2str(uint8_t num_labels, const mpls_label_t *labels, char *buf,
|
||||
int len, int pretty);
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
@ -23,11 +23,9 @@
|
||||
#include "table.h"
|
||||
#include "memory.h"
|
||||
#include "command.h"
|
||||
#include "if.h"
|
||||
#include "log.h"
|
||||
#include "sockunion.h"
|
||||
#include "linklist.h"
|
||||
#include "thread.h"
|
||||
#include "prefix.h"
|
||||
#include "nexthop.h"
|
||||
#include "mpls.h"
|
||||
@ -155,7 +153,24 @@ static int _nexthop_cmp_no_labels(const struct nexthop *next1,
|
||||
}
|
||||
|
||||
ret = _nexthop_source_cmp(next1, next2);
|
||||
if (ret != 0)
|
||||
goto done;
|
||||
|
||||
if (!CHECK_FLAG(next1->flags, NEXTHOP_FLAG_HAS_BACKUP) &&
|
||||
CHECK_FLAG(next2->flags, NEXTHOP_FLAG_HAS_BACKUP))
|
||||
return -1;
|
||||
|
||||
if (CHECK_FLAG(next1->flags, NEXTHOP_FLAG_HAS_BACKUP) &&
|
||||
!CHECK_FLAG(next2->flags, NEXTHOP_FLAG_HAS_BACKUP))
|
||||
return 1;
|
||||
|
||||
if (next1->backup_idx < next2->backup_idx)
|
||||
return -1;
|
||||
|
||||
if (next1->backup_idx > next2->backup_idx)
|
||||
return 1;
|
||||
|
||||
done:
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -240,7 +255,7 @@ struct nexthop *nexthop_new(void)
|
||||
* The linux kernel does some weird stuff with adding +1 to
|
||||
* all nexthop weights it gets over netlink.
|
||||
* To handle this, just default everything to 1 right from
|
||||
* from the beggining so we don't have to special case
|
||||
* from the beginning so we don't have to special case
|
||||
* default weights in the linux netlink code.
|
||||
*
|
||||
* 1 should be a valid on all platforms anyway.
|
||||
@ -393,8 +408,8 @@ struct nexthop *nexthop_from_blackhole(enum blackhole_type bh_type)
|
||||
}
|
||||
|
||||
/* Update nexthop with label information. */
|
||||
void nexthop_add_labels(struct nexthop *nexthop, enum lsp_types_t type,
|
||||
uint8_t num_labels, mpls_label_t *label)
|
||||
void nexthop_add_labels(struct nexthop *nexthop, enum lsp_types_t ltype,
|
||||
uint8_t num_labels, const mpls_label_t *labels)
|
||||
{
|
||||
struct mpls_label_stack *nh_label;
|
||||
int i;
|
||||
@ -402,13 +417,18 @@ void nexthop_add_labels(struct nexthop *nexthop, enum lsp_types_t type,
|
||||
if (num_labels == 0)
|
||||
return;
|
||||
|
||||
nexthop->nh_label_type = type;
|
||||
/* Enforce limit on label stack size */
|
||||
if (num_labels > MPLS_MAX_LABELS)
|
||||
num_labels = MPLS_MAX_LABELS;
|
||||
|
||||
nexthop->nh_label_type = ltype;
|
||||
|
||||
nh_label = XCALLOC(MTYPE_NH_LABEL,
|
||||
sizeof(struct mpls_label_stack)
|
||||
+ num_labels * sizeof(mpls_label_t));
|
||||
nh_label->num_labels = num_labels;
|
||||
for (i = 0; i < num_labels; i++)
|
||||
nh_label->label[i] = *(label + i);
|
||||
nh_label->label[i] = *(labels + i);
|
||||
nexthop->nh_label = nh_label;
|
||||
}
|
||||
|
||||
@ -503,6 +523,7 @@ unsigned int nexthop_level(struct nexthop *nexthop)
|
||||
uint32_t nexthop_hash_quick(const struct nexthop *nexthop)
|
||||
{
|
||||
uint32_t key = 0x45afe398;
|
||||
uint32_t val;
|
||||
|
||||
key = jhash_3words(nexthop->type, nexthop->vrf_id,
|
||||
nexthop->nh_label_type, key);
|
||||
@ -532,8 +553,12 @@ uint32_t nexthop_hash_quick(const struct nexthop *nexthop)
|
||||
key = jhash_1word(nexthop->nh_label->label[i], key);
|
||||
}
|
||||
|
||||
key = jhash_2words(nexthop->ifindex,
|
||||
CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK),
|
||||
val = 0;
|
||||
if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_HAS_BACKUP))
|
||||
val = (uint32_t)nexthop->backup_idx;
|
||||
|
||||
key = jhash_3words(nexthop->ifindex,
|
||||
CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK), val,
|
||||
key);
|
||||
|
||||
return key;
|
||||
@ -573,6 +598,7 @@ void nexthop_copy_no_recurse(struct nexthop *copy,
|
||||
copy->type = nexthop->type;
|
||||
copy->flags = nexthop->flags;
|
||||
copy->weight = nexthop->weight;
|
||||
copy->backup_idx = nexthop->backup_idx;
|
||||
memcpy(©->gate, &nexthop->gate, sizeof(nexthop->gate));
|
||||
memcpy(©->src, &nexthop->src, sizeof(nexthop->src));
|
||||
memcpy(©->rmap_src, &nexthop->rmap_src, sizeof(nexthop->rmap_src));
|
||||
|
||||
@ -86,6 +86,8 @@ struct nexthop {
|
||||
* active one
|
||||
*/
|
||||
#define NEXTHOP_FLAG_RNH_FILTERED (1 << 5) /* rmap filtered, used by rnh */
|
||||
#define NEXTHOP_FLAG_HAS_BACKUP (1 << 6) /* Backup nexthop index is set */
|
||||
|
||||
#define NEXTHOP_IS_ACTIVE(flags) \
|
||||
(CHECK_FLAG(flags, NEXTHOP_FLAG_ACTIVE) \
|
||||
&& !CHECK_FLAG(flags, NEXTHOP_FLAG_DUPLICATE))
|
||||
@ -116,15 +118,31 @@ struct nexthop {
|
||||
|
||||
/* Weight of the nexthop ( for unequal cost ECMP ) */
|
||||
uint8_t weight;
|
||||
|
||||
/* Index of a corresponding backup nexthop in a backup list;
|
||||
* only meaningful if the HAS_BACKUP flag is set.
|
||||
*/
|
||||
uint8_t backup_idx;
|
||||
};
|
||||
|
||||
/* Backup index value is limited */
|
||||
#define NEXTHOP_BACKUP_IDX_MAX 255
|
||||
|
||||
/* Utility to append one nexthop to another. */
|
||||
#define NEXTHOP_APPEND(to, new) \
|
||||
do { \
|
||||
(to)->next = (new); \
|
||||
(new)->prev = (to); \
|
||||
(new)->next = NULL; \
|
||||
} while (0)
|
||||
|
||||
struct nexthop *nexthop_new(void);
|
||||
|
||||
void nexthop_free(struct nexthop *nexthop);
|
||||
void nexthops_free(struct nexthop *nexthop);
|
||||
|
||||
void nexthop_add_labels(struct nexthop *, enum lsp_types_t, uint8_t,
|
||||
mpls_label_t *);
|
||||
void nexthop_add_labels(struct nexthop *nexthop, enum lsp_types_t ltype,
|
||||
uint8_t num_labels, const mpls_label_t *labels);
|
||||
void nexthop_del_labels(struct nexthop *);
|
||||
|
||||
/*
|
||||
|
||||
@ -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,
|
||||
@ -225,6 +229,10 @@ void nexthop_group_copy(struct nexthop_group *to,
|
||||
|
||||
void nexthop_group_delete(struct nexthop_group **nhg)
|
||||
{
|
||||
/* OK to call with NULL group */
|
||||
if ((*nhg) == NULL)
|
||||
return;
|
||||
|
||||
if ((*nhg)->nexthop)
|
||||
nexthops_free((*nhg)->nexthop);
|
||||
|
||||
@ -567,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;
|
||||
|
||||
@ -588,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);
|
||||
}
|
||||
|
||||
@ -629,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;
|
||||
@ -688,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;
|
||||
}
|
||||
|
||||
@ -699,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,
|
||||
@ -712,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"
|
||||
@ -724,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)) {
|
||||
@ -765,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();
|
||||
|
||||
@ -785,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);
|
||||
@ -849,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");
|
||||
}
|
||||
|
||||
@ -874,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");
|
||||
}
|
||||
|
||||
@ -887,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);
|
||||
@ -1067,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));
|
||||
|
||||
@ -57,6 +57,8 @@ void copy_nexthops(struct nexthop **tnh, const struct nexthop *nh,
|
||||
uint32_t nexthop_group_hash_no_recurse(const struct nexthop_group *nhg);
|
||||
uint32_t nexthop_group_hash(const struct nexthop_group *nhg);
|
||||
void nexthop_group_mark_duplicates(struct nexthop_group *nhg);
|
||||
|
||||
/* Add a nexthop to a list, enforcing the canonical sort order. */
|
||||
void nexthop_group_add_sorted(struct nexthop_group *nhg,
|
||||
struct nexthop *nexthop);
|
||||
|
||||
@ -79,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;
|
||||
|
||||
|
||||
109
lib/zclient.c
109
lib/zclient.c
@ -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);
|
||||
|
||||
@ -948,6 +949,10 @@ int zapi_nexthop_encode(struct stream *s, const struct zapi_nexthop *api_nh,
|
||||
stream_put(s, &(api_nh->rmac),
|
||||
sizeof(struct ethaddr));
|
||||
|
||||
/* Index of backup nexthop */
|
||||
if (CHECK_FLAG(nh_flags, ZAPI_NEXTHOP_FLAG_HAS_BACKUP))
|
||||
stream_putc(s, api_nh->backup_idx);
|
||||
|
||||
done:
|
||||
return ret;
|
||||
}
|
||||
@ -1007,6 +1012,10 @@ int zapi_route_encode(uint8_t cmd, struct stream *s, struct zapi_route *api)
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* We canonicalize the nexthops by sorting them; this allows
|
||||
* zebra to resolve the list of nexthops to a nexthop-group
|
||||
* more efficiently.
|
||||
*/
|
||||
zapi_nexthop_group_sort(api->nexthops, api->nexthop_num);
|
||||
|
||||
stream_putw(s, api->nexthop_num);
|
||||
@ -1033,6 +1042,50 @@ int zapi_route_encode(uint8_t cmd, struct stream *s, struct zapi_route *api)
|
||||
}
|
||||
}
|
||||
|
||||
/* Backup nexthops */
|
||||
if (CHECK_FLAG(api->message, ZAPI_MESSAGE_BACKUP_NEXTHOPS)) {
|
||||
/* limit the number of nexthops if necessary */
|
||||
if (api->backup_nexthop_num > MULTIPATH_NUM) {
|
||||
char buf[PREFIX2STR_BUFFER];
|
||||
|
||||
prefix2str(&api->prefix, buf, sizeof(buf));
|
||||
flog_err(
|
||||
EC_LIB_ZAPI_ENCODE,
|
||||
"%s: prefix %s: can't encode %u backup nexthops (maximum is %u)",
|
||||
__func__, buf, api->backup_nexthop_num,
|
||||
MULTIPATH_NUM);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Note that we do not sort the list of backup nexthops -
|
||||
* this list is treated as an array and indexed by each
|
||||
* primary nexthop that is associated with a backup.
|
||||
*/
|
||||
|
||||
stream_putw(s, api->backup_nexthop_num);
|
||||
|
||||
for (i = 0; i < api->backup_nexthop_num; i++) {
|
||||
api_nh = &api->backup_nexthops[i];
|
||||
|
||||
/* MPLS labels for BGP-LU or Segment Routing */
|
||||
if (api_nh->label_num > MPLS_MAX_LABELS) {
|
||||
char buf[PREFIX2STR_BUFFER];
|
||||
|
||||
prefix2str(&api->prefix, buf, sizeof(buf));
|
||||
|
||||
flog_err(EC_LIB_ZAPI_ENCODE,
|
||||
"%s: prefix %s: backup: can't encode %u labels (maximum is %u)",
|
||||
__func__, buf,
|
||||
api_nh->label_num,
|
||||
MPLS_MAX_LABELS);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (zapi_nexthop_encode(s, api_nh, api->flags) != 0)
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Attributes. */
|
||||
if (CHECK_FLAG(api->message, ZAPI_MESSAGE_DISTANCE))
|
||||
stream_putc(s, api->distance);
|
||||
@ -1108,6 +1161,10 @@ static int zapi_nexthop_decode(struct stream *s, struct zapi_nexthop *api_nh,
|
||||
STREAM_GET(&(api_nh->rmac), s,
|
||||
sizeof(struct ethaddr));
|
||||
|
||||
/* Backup nexthop index */
|
||||
if (CHECK_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_HAS_BACKUP))
|
||||
STREAM_GETC(s, api_nh->backup_idx);
|
||||
|
||||
/* Success */
|
||||
ret = 0;
|
||||
|
||||
@ -1214,6 +1271,24 @@ int zapi_route_decode(struct stream *s, struct zapi_route *api)
|
||||
}
|
||||
}
|
||||
|
||||
/* Backup nexthops. */
|
||||
if (CHECK_FLAG(api->message, ZAPI_MESSAGE_BACKUP_NEXTHOPS)) {
|
||||
STREAM_GETW(s, api->backup_nexthop_num);
|
||||
if (api->backup_nexthop_num > MULTIPATH_NUM) {
|
||||
flog_err(EC_LIB_ZAPI_ENCODE,
|
||||
"%s: invalid number of backup nexthops (%u)",
|
||||
__func__, api->backup_nexthop_num);
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (i = 0; i < api->backup_nexthop_num; i++) {
|
||||
api_nh = &api->backup_nexthops[i];
|
||||
|
||||
if (zapi_nexthop_decode(s, api_nh, api->flags) != 0)
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Attributes. */
|
||||
if (CHECK_FLAG(api->message, ZAPI_MESSAGE_DISTANCE))
|
||||
STREAM_GETC(s, api->distance);
|
||||
@ -1388,7 +1463,7 @@ stream_failure:
|
||||
return false;
|
||||
}
|
||||
|
||||
struct nexthop *nexthop_from_zapi_nexthop(struct zapi_nexthop *znh)
|
||||
struct nexthop *nexthop_from_zapi_nexthop(const struct zapi_nexthop *znh)
|
||||
{
|
||||
struct nexthop *n = nexthop_new();
|
||||
|
||||
@ -1405,6 +1480,11 @@ struct nexthop *nexthop_from_zapi_nexthop(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;
|
||||
}
|
||||
|
||||
@ -1420,10 +1500,16 @@ int zapi_nexthop_from_nexthop(struct zapi_nexthop *znh,
|
||||
|
||||
znh->type = nh->type;
|
||||
znh->vrf_id = nh->vrf_id;
|
||||
znh->weight = nh->weight;
|
||||
znh->ifindex = nh->ifindex;
|
||||
znh->gate = nh->gate;
|
||||
|
||||
if (nh->nh_label && (nh->nh_label->num_labels > 0)) {
|
||||
|
||||
/* Validate */
|
||||
if (nh->nh_label->num_labels > MPLS_MAX_LABELS)
|
||||
return -1;
|
||||
|
||||
for (i = 0; i < nh->nh_label->num_labels; i++)
|
||||
znh->labels[i] = nh->nh_label->label[i];
|
||||
|
||||
@ -1431,9 +1517,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
|
||||
*/
|
||||
|
||||
@ -341,6 +341,9 @@ struct zclient {
|
||||
#define ZAPI_MESSAGE_TAG 0x08
|
||||
#define ZAPI_MESSAGE_MTU 0x10
|
||||
#define ZAPI_MESSAGE_SRCPFX 0x20
|
||||
/* Backup nexthops are present */
|
||||
#define ZAPI_MESSAGE_BACKUP_NEXTHOPS 0x40
|
||||
|
||||
/*
|
||||
* This should only be used by a DAEMON that needs to communicate
|
||||
* the table being used is not in the VRF. You must pass the
|
||||
@ -377,14 +380,21 @@ struct zapi_nexthop {
|
||||
struct ethaddr rmac;
|
||||
|
||||
uint32_t weight;
|
||||
|
||||
/* Index of backup nexthop */
|
||||
uint8_t backup_idx;
|
||||
};
|
||||
|
||||
/*
|
||||
* ZAPI nexthop flags values
|
||||
* ZAPI nexthop flags values - we're encoding a single octet
|
||||
* initially, so ensure that the on-the-wire encoding continues
|
||||
* to match the number of valid flags.
|
||||
*/
|
||||
|
||||
#define ZAPI_NEXTHOP_FLAG_ONLINK 0x01
|
||||
#define ZAPI_NEXTHOP_FLAG_LABEL 0x02
|
||||
#define ZAPI_NEXTHOP_FLAG_WEIGHT 0x04
|
||||
#define ZAPI_NEXTHOP_FLAG_HAS_BACKUP 0x08 /* Nexthop has a backup */
|
||||
|
||||
/*
|
||||
* Some of these data structures do not map easily to
|
||||
@ -448,6 +458,10 @@ struct zapi_route {
|
||||
uint16_t nexthop_num;
|
||||
struct zapi_nexthop nexthops[MULTIPATH_NUM];
|
||||
|
||||
/* Support backup routes for IP FRR, TI-LFA, traffic engineering */
|
||||
uint16_t backup_nexthop_num;
|
||||
struct zapi_nexthop backup_nexthops[MULTIPATH_NUM];
|
||||
|
||||
uint8_t distance;
|
||||
|
||||
uint32_t metric;
|
||||
@ -769,9 +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(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);
|
||||
|
||||
|
||||
@ -28,9 +28,11 @@ struct sharp_routes {
|
||||
/* The original prefix for route installation */
|
||||
struct prefix orig_prefix;
|
||||
|
||||
/* The nexthop group we are using for installation */
|
||||
/* The nexthop info we are using for installation */
|
||||
struct nexthop nhop;
|
||||
struct nexthop backup_nhop;
|
||||
struct nexthop_group nhop_group;
|
||||
struct nexthop_group backup_nhop_group;
|
||||
|
||||
uint32_t total_routes;
|
||||
uint32_t installed_routes;
|
||||
|
||||
@ -162,7 +162,12 @@ DEFPY (install_routes_data_dump,
|
||||
|
||||
DEFPY (install_routes,
|
||||
install_routes_cmd,
|
||||
"sharp install routes [vrf NAME$vrf_name] <A.B.C.D$start4|X:X::X:X$start6> <nexthop <A.B.C.D$nexthop4|X:X::X:X$nexthop6>|nexthop-group NHGNAME$nexthop_group> (1-1000000)$routes [instance (0-255)$instance] [repeat (2-1000)$rpt]",
|
||||
"sharp install routes [vrf NAME$vrf_name]\
|
||||
<A.B.C.D$start4|X:X::X:X$start6>\
|
||||
<nexthop <A.B.C.D$nexthop4|X:X::X:X$nexthop6>|\
|
||||
nexthop-group NHGNAME$nexthop_group>\
|
||||
[backup$backup <A.B.C.D$backup_nexthop4|X:X::X:X$backup_nexthop6>] \
|
||||
(1-1000000)$routes [instance (0-255)$instance] [repeat (2-1000)$rpt]",
|
||||
"Sharp routing Protocol\n"
|
||||
"install some routes\n"
|
||||
"Routes to install\n"
|
||||
@ -175,6 +180,9 @@ DEFPY (install_routes,
|
||||
"V6 Nexthop address to use\n"
|
||||
"Nexthop-Group to use\n"
|
||||
"The Name of the nexthop-group\n"
|
||||
"Backup nexthop to use(Can be an IPv4 or IPv6 address)\n"
|
||||
"Backup V4 Nexthop address to use\n"
|
||||
"Backup V6 Nexthop address to use\n"
|
||||
"How many to create\n"
|
||||
"Instance to use\n"
|
||||
"Instance\n"
|
||||
@ -197,6 +205,8 @@ DEFPY (install_routes,
|
||||
memset(&sg.r.orig_prefix, 0, sizeof(sg.r.orig_prefix));
|
||||
memset(&sg.r.nhop, 0, sizeof(sg.r.nhop));
|
||||
memset(&sg.r.nhop_group, 0, sizeof(sg.r.nhop_group));
|
||||
memset(&sg.r.backup_nhop, 0, sizeof(sg.r.nhop));
|
||||
memset(&sg.r.backup_nhop_group, 0, sizeof(sg.r.nhop_group));
|
||||
|
||||
if (start4.s_addr != 0) {
|
||||
prefix.family = AF_INET;
|
||||
@ -219,6 +229,12 @@ DEFPY (install_routes,
|
||||
return CMD_WARNING;
|
||||
}
|
||||
|
||||
/* Explicit backup not available with named nexthop-group */
|
||||
if (backup && nexthop_group) {
|
||||
vty_out(vty, "%% Invalid: cannot specify both nexthop-group and backup\n");
|
||||
return CMD_WARNING;
|
||||
}
|
||||
|
||||
if (nexthop_group) {
|
||||
struct nexthop_group_cmd *nhgc = nhgc_find(nexthop_group);
|
||||
if (!nhgc) {
|
||||
@ -229,6 +245,22 @@ DEFPY (install_routes,
|
||||
}
|
||||
|
||||
sg.r.nhop_group.nexthop = nhgc->nhg.nexthop;
|
||||
|
||||
/* Use group's backup nexthop info if present */
|
||||
if (nhgc->backup_list_name[0]) {
|
||||
struct nexthop_group_cmd *bnhgc =
|
||||
nhgc_find(nhgc->backup_list_name);
|
||||
|
||||
if (!bnhgc) {
|
||||
vty_out(vty, "%% Backup group %s not found for group %s\n",
|
||||
nhgc->backup_list_name,
|
||||
nhgc->name);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
|
||||
sg.r.backup_nhop.vrf_id = vrf->vrf_id;
|
||||
sg.r.backup_nhop_group.nexthop = bnhgc->nhg.nexthop;
|
||||
}
|
||||
} else {
|
||||
if (nexthop4.s_addr != INADDR_ANY) {
|
||||
sg.r.nhop.gate.ipv4 = nexthop4;
|
||||
@ -242,11 +274,30 @@ DEFPY (install_routes,
|
||||
sg.r.nhop_group.nexthop = &sg.r.nhop;
|
||||
}
|
||||
|
||||
/* Use single backup nexthop if specified */
|
||||
if (backup) {
|
||||
/* Set flag and index in primary nexthop */
|
||||
SET_FLAG(sg.r.nhop.flags, NEXTHOP_FLAG_HAS_BACKUP);
|
||||
sg.r.nhop.backup_idx = 0;
|
||||
|
||||
if (backup_nexthop4.s_addr != INADDR_ANY) {
|
||||
sg.r.backup_nhop.gate.ipv4 = backup_nexthop4;
|
||||
sg.r.backup_nhop.type = NEXTHOP_TYPE_IPV4;
|
||||
} else {
|
||||
sg.r.backup_nhop.gate.ipv6 = backup_nexthop6;
|
||||
sg.r.backup_nhop.type = NEXTHOP_TYPE_IPV6;
|
||||
}
|
||||
|
||||
sg.r.backup_nhop.vrf_id = vrf->vrf_id;
|
||||
sg.r.backup_nhop_group.nexthop = &sg.r.backup_nhop;
|
||||
}
|
||||
|
||||
sg.r.inst = instance;
|
||||
sg.r.vrf_id = vrf->vrf_id;
|
||||
rts = routes;
|
||||
sharp_install_routes_helper(&prefix, sg.r.vrf_id,
|
||||
sg.r.inst, &sg.r.nhop_group, rts);
|
||||
sharp_install_routes_helper(&prefix, sg.r.vrf_id, sg.r.inst,
|
||||
&sg.r.nhop_group, &sg.r.backup_nhop_group,
|
||||
rts);
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
@ -143,7 +143,9 @@ int sharp_install_lsps_helper(bool install_p, const struct prefix *p,
|
||||
}
|
||||
|
||||
void sharp_install_routes_helper(struct prefix *p, vrf_id_t vrf_id,
|
||||
uint8_t instance, struct nexthop_group *nhg,
|
||||
uint8_t instance,
|
||||
const struct nexthop_group *nhg,
|
||||
const struct nexthop_group *backup_nhg,
|
||||
uint32_t routes)
|
||||
{
|
||||
uint32_t temp, i;
|
||||
@ -157,9 +159,13 @@ void sharp_install_routes_helper(struct prefix *p, vrf_id_t vrf_id,
|
||||
} else
|
||||
temp = ntohl(p->u.val32[3]);
|
||||
|
||||
/* Only use backup route/nexthops if present */
|
||||
if (backup_nhg && (backup_nhg->nexthop == NULL))
|
||||
backup_nhg = NULL;
|
||||
|
||||
monotime(&sg.r.t_start);
|
||||
for (i = 0; i < routes; i++) {
|
||||
route_add(p, vrf_id, (uint8_t)instance, nhg);
|
||||
route_add(p, vrf_id, (uint8_t)instance, nhg, backup_nhg);
|
||||
if (v4)
|
||||
p->u.prefix4.s_addr = htonl(++temp);
|
||||
else
|
||||
@ -209,6 +215,7 @@ static void handle_repeated(bool installed)
|
||||
sg.r.installed_routes = 0;
|
||||
sharp_install_routes_helper(&p, sg.r.vrf_id, sg.r.inst,
|
||||
&sg.r.nhop_group,
|
||||
&sg.r.backup_nhop_group,
|
||||
sg.r.total_routes);
|
||||
}
|
||||
}
|
||||
@ -276,8 +283,9 @@ void vrf_label_add(vrf_id_t vrf_id, afi_t afi, mpls_label_t label)
|
||||
zclient_send_vrf_label(zclient, vrf_id, afi, label, ZEBRA_LSP_SHARP);
|
||||
}
|
||||
|
||||
void route_add(struct prefix *p, vrf_id_t vrf_id,
|
||||
uint8_t instance, struct nexthop_group *nhg)
|
||||
void route_add(const struct prefix *p, vrf_id_t vrf_id,
|
||||
uint8_t instance, const struct nexthop_group *nhg,
|
||||
const struct nexthop_group *backup_nhg)
|
||||
{
|
||||
struct zapi_route api;
|
||||
struct zapi_nexthop *api_nh;
|
||||
@ -298,10 +306,27 @@ void route_add(struct prefix *p, vrf_id_t vrf_id,
|
||||
api_nh = &api.nexthops[i];
|
||||
|
||||
zapi_nexthop_from_nexthop(api_nh, nh);
|
||||
|
||||
i++;
|
||||
}
|
||||
api.nexthop_num = i;
|
||||
|
||||
/* Include backup nexthops, if present */
|
||||
if (backup_nhg && backup_nhg->nexthop) {
|
||||
SET_FLAG(api.message, ZAPI_MESSAGE_BACKUP_NEXTHOPS);
|
||||
|
||||
i = 0;
|
||||
for (ALL_NEXTHOPS_PTR(backup_nhg, nh)) {
|
||||
api_nh = &api.backup_nexthops[i];
|
||||
|
||||
zapi_backup_nexthop_from_nexthop(api_nh, nh);
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
api.backup_nexthop_num = i;
|
||||
}
|
||||
|
||||
zclient_route_send(ZEBRA_ROUTE_ADD, zclient, &api);
|
||||
}
|
||||
|
||||
|
||||
@ -25,15 +25,17 @@
|
||||
extern void sharp_zebra_init(void);
|
||||
|
||||
extern void vrf_label_add(vrf_id_t vrf_id, afi_t afi, mpls_label_t label);
|
||||
extern void route_add(struct prefix *p, vrf_id_t, uint8_t instance,
|
||||
struct nexthop_group *nhg);
|
||||
extern void route_add(const struct prefix *p, vrf_id_t, uint8_t instance,
|
||||
const struct nexthop_group *nhg,
|
||||
const struct nexthop_group *backup_nhg);
|
||||
extern void route_delete(struct prefix *p, vrf_id_t vrf_id, uint8_t instance);
|
||||
extern void sharp_zebra_nexthop_watch(struct prefix *p, vrf_id_t vrf_id,
|
||||
bool import, bool watch, bool connected);
|
||||
|
||||
extern void sharp_install_routes_helper(struct prefix *p, vrf_id_t vrf_id,
|
||||
uint8_t instance,
|
||||
struct nexthop_group *nhg,
|
||||
const struct nexthop_group *nhg,
|
||||
const struct nexthop_group *backup_nhg,
|
||||
uint32_t routes);
|
||||
extern void sharp_remove_routes_helper(struct prefix *p, vrf_id_t vrf_id,
|
||||
uint8_t instance, uint32_t routes);
|
||||
|
||||
10
zebra/rib.h
10
zebra/rib.h
@ -107,7 +107,7 @@ struct route_entry {
|
||||
/* Uptime. */
|
||||
time_t uptime;
|
||||
|
||||
/* Type fo this route. */
|
||||
/* Type of this route. */
|
||||
int type;
|
||||
|
||||
/* VRF identifier. */
|
||||
@ -347,10 +347,16 @@ extern int rib_add(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type,
|
||||
struct prefix_ipv6 *src_p, const struct nexthop *nh,
|
||||
uint32_t nhe_id, uint32_t table_id, uint32_t metric,
|
||||
uint32_t mtu, uint8_t distance, route_tag_t tag);
|
||||
|
||||
/*
|
||||
* Multipath route apis.
|
||||
*/
|
||||
extern int rib_add_multipath(afi_t afi, safi_t safi, struct prefix *p,
|
||||
struct prefix_ipv6 *src_p, struct route_entry *re,
|
||||
struct nexthop_group *ng);
|
||||
extern int rib_add_multipath_nhe(afi_t afi, safi_t safi, struct prefix *p,
|
||||
struct prefix_ipv6 *src_p,
|
||||
struct route_entry *re,
|
||||
struct nhg_hash_entry *nhe);
|
||||
|
||||
extern void rib_delete(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type,
|
||||
unsigned short instance, int flags, struct prefix *p,
|
||||
|
||||
@ -1982,6 +1982,12 @@ static int netlink_nexthop(int cmd, struct zebra_dplane_ctx *ctx)
|
||||
addattr32(&req.n, req_size, NHA_ID, id);
|
||||
|
||||
if (cmd == RTM_NEWNEXTHOP) {
|
||||
/*
|
||||
* We distinguish between a "group", which is a collection
|
||||
* of ids, and a singleton nexthop with an id. The
|
||||
* group is installed as an id that just refers to a list of
|
||||
* other ids.
|
||||
*/
|
||||
if (dplane_ctx_get_nhe_nh_grp_count(ctx))
|
||||
_netlink_nexthop_build_group(
|
||||
&req.n, req_size, id,
|
||||
@ -2068,14 +2074,13 @@ static int netlink_nexthop(int cmd, struct zebra_dplane_ctx *ctx)
|
||||
}
|
||||
}
|
||||
|
||||
nexthop_done:
|
||||
if (IS_ZEBRA_DEBUG_KERNEL) {
|
||||
char buf[NEXTHOP_STRLEN];
|
||||
nexthop_done:
|
||||
|
||||
if (IS_ZEBRA_DEBUG_KERNEL)
|
||||
zlog_debug("%s: ID (%u): %pNHv (%u) %s ",
|
||||
__func__, id, nh, nh->vrf_id,
|
||||
label_buf);
|
||||
|
||||
snprintfrr(buf, sizeof(buf), "%pNHv", nh);
|
||||
zlog_debug("%s: ID (%u): %s (%u) %s ", __func__,
|
||||
id, buf, nh->vrf_id, label_buf);
|
||||
}
|
||||
}
|
||||
|
||||
req.nhm.nh_protocol = zebra2proto(dplane_ctx_get_nhe_type(ctx));
|
||||
@ -2103,43 +2108,19 @@ static int netlink_nexthop(int cmd, struct zebra_dplane_ctx *ctx)
|
||||
*/
|
||||
enum zebra_dplane_result kernel_nexthop_update(struct zebra_dplane_ctx *ctx)
|
||||
{
|
||||
enum dplane_op_e op;
|
||||
int cmd = 0;
|
||||
int ret = 0;
|
||||
|
||||
switch (dplane_ctx_get_op(ctx)) {
|
||||
case DPLANE_OP_NH_DELETE:
|
||||
cmd = RTM_DELNEXTHOP;
|
||||
break;
|
||||
case DPLANE_OP_NH_INSTALL:
|
||||
case DPLANE_OP_NH_UPDATE:
|
||||
op = dplane_ctx_get_op(ctx);
|
||||
if (op == DPLANE_OP_NH_INSTALL || op == DPLANE_OP_NH_UPDATE)
|
||||
cmd = RTM_NEWNEXTHOP;
|
||||
break;
|
||||
case DPLANE_OP_ROUTE_INSTALL:
|
||||
case DPLANE_OP_ROUTE_UPDATE:
|
||||
case DPLANE_OP_ROUTE_DELETE:
|
||||
case DPLANE_OP_ROUTE_NOTIFY:
|
||||
case DPLANE_OP_LSP_INSTALL:
|
||||
case DPLANE_OP_LSP_UPDATE:
|
||||
case DPLANE_OP_LSP_DELETE:
|
||||
case DPLANE_OP_LSP_NOTIFY:
|
||||
case DPLANE_OP_PW_INSTALL:
|
||||
case DPLANE_OP_PW_UNINSTALL:
|
||||
case DPLANE_OP_SYS_ROUTE_ADD:
|
||||
case DPLANE_OP_SYS_ROUTE_DELETE:
|
||||
case DPLANE_OP_ADDR_INSTALL:
|
||||
case DPLANE_OP_ADDR_UNINSTALL:
|
||||
case DPLANE_OP_MAC_INSTALL:
|
||||
case DPLANE_OP_MAC_DELETE:
|
||||
case DPLANE_OP_NEIGH_INSTALL:
|
||||
case DPLANE_OP_NEIGH_UPDATE:
|
||||
case DPLANE_OP_NEIGH_DELETE:
|
||||
case DPLANE_OP_VTEP_ADD:
|
||||
case DPLANE_OP_VTEP_DELETE:
|
||||
case DPLANE_OP_NONE:
|
||||
flog_err(
|
||||
EC_ZEBRA_NHG_FIB_UPDATE,
|
||||
"Context received for kernel nexthop update with incorrect OP code (%u)",
|
||||
dplane_ctx_get_op(ctx));
|
||||
else if (op == DPLANE_OP_NH_DELETE)
|
||||
cmd = RTM_DELNEXTHOP;
|
||||
else {
|
||||
flog_err(EC_ZEBRA_NHG_FIB_UPDATE,
|
||||
"Context received for kernel nexthop update with incorrect OP code (%u)",
|
||||
op);
|
||||
return ZEBRA_DPLANE_REQUEST_FAILURE;
|
||||
}
|
||||
|
||||
|
||||
381
zebra/zapi_msg.c
381
zebra/zapi_msg.c
@ -1413,6 +1413,132 @@ void zserv_nexthop_num_warn(const char *caller, const struct prefix *p,
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Create a new nexthop based on a zapi nexthop.
|
||||
*/
|
||||
static struct nexthop *nexthop_from_zapi(struct route_entry *re,
|
||||
const struct zapi_nexthop *api_nh,
|
||||
const struct zapi_route *api)
|
||||
{
|
||||
struct nexthop *nexthop = NULL;
|
||||
struct ipaddr vtep_ip;
|
||||
struct interface *ifp;
|
||||
char nhbuf[INET6_ADDRSTRLEN] = "";
|
||||
|
||||
switch (api_nh->type) {
|
||||
case NEXTHOP_TYPE_IFINDEX:
|
||||
nexthop = nexthop_from_ifindex(api_nh->ifindex, api_nh->vrf_id);
|
||||
break;
|
||||
case NEXTHOP_TYPE_IPV4:
|
||||
if (IS_ZEBRA_DEBUG_RECV) {
|
||||
inet_ntop(AF_INET, &api_nh->gate.ipv4, nhbuf,
|
||||
sizeof(nhbuf));
|
||||
zlog_debug("%s: nh=%s, vrf_id=%d", __func__,
|
||||
nhbuf, api_nh->vrf_id);
|
||||
}
|
||||
nexthop = nexthop_from_ipv4(&api_nh->gate.ipv4, NULL,
|
||||
api_nh->vrf_id);
|
||||
break;
|
||||
case NEXTHOP_TYPE_IPV4_IFINDEX:
|
||||
if (IS_ZEBRA_DEBUG_RECV) {
|
||||
inet_ntop(AF_INET, &api_nh->gate.ipv4, nhbuf,
|
||||
sizeof(nhbuf));
|
||||
zlog_debug("%s: nh=%s, vrf_id=%d, ifindex=%d",
|
||||
__func__, nhbuf, api_nh->vrf_id,
|
||||
api_nh->ifindex);
|
||||
}
|
||||
|
||||
nexthop = nexthop_from_ipv4_ifindex(
|
||||
&api_nh->gate.ipv4, NULL, api_nh->ifindex,
|
||||
api_nh->vrf_id);
|
||||
|
||||
ifp = if_lookup_by_index(api_nh->ifindex, api_nh->vrf_id);
|
||||
if (ifp && connected_is_unnumbered(ifp))
|
||||
SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK);
|
||||
|
||||
/* Special handling for IPv4 routes sourced from EVPN:
|
||||
* the nexthop and associated MAC need to be installed.
|
||||
*/
|
||||
if (CHECK_FLAG(api->flags, ZEBRA_FLAG_EVPN_ROUTE)) {
|
||||
memset(&vtep_ip, 0, sizeof(struct ipaddr));
|
||||
vtep_ip.ipa_type = IPADDR_V4;
|
||||
memcpy(&(vtep_ip.ipaddr_v4), &(api_nh->gate.ipv4),
|
||||
sizeof(struct in_addr));
|
||||
zebra_vxlan_evpn_vrf_route_add(
|
||||
api_nh->vrf_id, &api_nh->rmac,
|
||||
&vtep_ip, &api->prefix);
|
||||
}
|
||||
break;
|
||||
case NEXTHOP_TYPE_IPV6:
|
||||
if (IS_ZEBRA_DEBUG_RECV) {
|
||||
inet_ntop(AF_INET6, &api_nh->gate.ipv6, nhbuf,
|
||||
sizeof(nhbuf));
|
||||
zlog_debug("%s: nh=%s, vrf_id=%d", __func__,
|
||||
nhbuf, api_nh->vrf_id);
|
||||
}
|
||||
nexthop = nexthop_from_ipv6(&api_nh->gate.ipv6, api_nh->vrf_id);
|
||||
break;
|
||||
case NEXTHOP_TYPE_IPV6_IFINDEX:
|
||||
if (IS_ZEBRA_DEBUG_RECV) {
|
||||
inet_ntop(AF_INET6, &api_nh->gate.ipv6, nhbuf,
|
||||
sizeof(nhbuf));
|
||||
zlog_debug("%s: nh=%s, vrf_id=%d, ifindex=%d",
|
||||
__func__, nhbuf, api_nh->vrf_id,
|
||||
api_nh->ifindex);
|
||||
}
|
||||
nexthop = nexthop_from_ipv6_ifindex(&api_nh->gate.ipv6,
|
||||
api_nh->ifindex,
|
||||
api_nh->vrf_id);
|
||||
|
||||
/* Special handling for IPv6 routes sourced from EVPN:
|
||||
* the nexthop and associated MAC need to be installed.
|
||||
*/
|
||||
if (CHECK_FLAG(api->flags, ZEBRA_FLAG_EVPN_ROUTE)) {
|
||||
memset(&vtep_ip, 0, sizeof(struct ipaddr));
|
||||
vtep_ip.ipa_type = IPADDR_V6;
|
||||
memcpy(&vtep_ip.ipaddr_v6, &(api_nh->gate.ipv6),
|
||||
sizeof(struct in6_addr));
|
||||
zebra_vxlan_evpn_vrf_route_add(
|
||||
api_nh->vrf_id, &api_nh->rmac,
|
||||
&vtep_ip, &api->prefix);
|
||||
}
|
||||
break;
|
||||
case NEXTHOP_TYPE_BLACKHOLE:
|
||||
if (IS_ZEBRA_DEBUG_RECV)
|
||||
zlog_debug("%s: nh blackhole %d",
|
||||
__func__, api_nh->bh_type);
|
||||
|
||||
nexthop = nexthop_from_blackhole(api_nh->bh_type);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Return early if we couldn't process the zapi nexthop */
|
||||
if (nexthop == NULL) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (CHECK_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_ONLINK))
|
||||
SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK);
|
||||
|
||||
if (CHECK_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_WEIGHT))
|
||||
nexthop->weight = api_nh->weight;
|
||||
|
||||
if (CHECK_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_HAS_BACKUP)) {
|
||||
if (api_nh->backup_idx < api->backup_nexthop_num) {
|
||||
/* Capture backup info */
|
||||
SET_FLAG(nexthop->flags, NEXTHOP_FLAG_HAS_BACKUP);
|
||||
nexthop->backup_idx = api_nh->backup_idx;
|
||||
} else {
|
||||
/* Warn about invalid backup index */
|
||||
if (IS_ZEBRA_DEBUG_RECV || IS_ZEBRA_DEBUG_EVENT)
|
||||
zlog_debug("%s: invalid backup nh idx %d",
|
||||
__func__, api_nh->backup_idx);
|
||||
}
|
||||
}
|
||||
done:
|
||||
return nexthop;
|
||||
}
|
||||
|
||||
static void zread_route_add(ZAPI_HANDLER_ARGS)
|
||||
{
|
||||
struct stream *s;
|
||||
@ -1421,12 +1547,15 @@ static void zread_route_add(ZAPI_HANDLER_ARGS)
|
||||
afi_t afi;
|
||||
struct prefix_ipv6 *src_p = NULL;
|
||||
struct route_entry *re;
|
||||
struct nexthop *nexthop = NULL;
|
||||
struct nexthop *nexthop = NULL, *last_nh;
|
||||
struct nexthop_group *ng = NULL;
|
||||
struct nhg_backup_info *bnhg = NULL;
|
||||
int i, ret;
|
||||
vrf_id_t vrf_id;
|
||||
struct ipaddr vtep_ip;
|
||||
struct interface *ifp;
|
||||
struct nhg_hash_entry nhe;
|
||||
enum lsp_types_t label_type;
|
||||
char nhbuf[NEXTHOP_STRLEN];
|
||||
char labelbuf[MPLS_LABEL_STRLEN];
|
||||
|
||||
s = msg;
|
||||
if (zapi_route_decode(s, &api) < 0) {
|
||||
@ -1440,8 +1569,8 @@ static void zread_route_add(ZAPI_HANDLER_ARGS)
|
||||
char buf_prefix[PREFIX_STRLEN];
|
||||
|
||||
prefix2str(&api.prefix, buf_prefix, sizeof(buf_prefix));
|
||||
zlog_debug("%s: p=%s, flags=0x%x",
|
||||
__func__, buf_prefix, api.flags);
|
||||
zlog_debug("%s: p=%s, msg flags=0x%x, flags=0x%x",
|
||||
__func__, buf_prefix, (int)api.message, api.flags);
|
||||
}
|
||||
|
||||
/* Allocate new route. */
|
||||
@ -1469,6 +1598,15 @@ static void zread_route_add(ZAPI_HANDLER_ARGS)
|
||||
return;
|
||||
}
|
||||
|
||||
/* Report misuse of the backup flag */
|
||||
if (CHECK_FLAG(api.message, ZAPI_MESSAGE_BACKUP_NEXTHOPS) &&
|
||||
api.backup_nexthop_num == 0) {
|
||||
if (IS_ZEBRA_DEBUG_RECV || IS_ZEBRA_DEBUG_EVENT)
|
||||
zlog_debug("%s: client %s: BACKUP flag set but no backup nexthops, prefix %pFX",
|
||||
__func__,
|
||||
zebra_route_string(client->proto), &api.prefix);
|
||||
}
|
||||
|
||||
/* Use temporary list of nexthops */
|
||||
ng = nexthop_group_new();
|
||||
|
||||
@ -1479,92 +1617,9 @@ static void zread_route_add(ZAPI_HANDLER_ARGS)
|
||||
*/
|
||||
for (i = 0; i < api.nexthop_num; i++) {
|
||||
api_nh = &api.nexthops[i];
|
||||
ifindex_t ifindex = 0;
|
||||
|
||||
nexthop = NULL;
|
||||
|
||||
if (IS_ZEBRA_DEBUG_RECV)
|
||||
zlog_debug("nh type %d", api_nh->type);
|
||||
|
||||
switch (api_nh->type) {
|
||||
case NEXTHOP_TYPE_IFINDEX:
|
||||
nexthop = nexthop_from_ifindex(api_nh->ifindex,
|
||||
api_nh->vrf_id);
|
||||
break;
|
||||
case NEXTHOP_TYPE_IPV4:
|
||||
if (IS_ZEBRA_DEBUG_RECV) {
|
||||
char nhbuf[INET6_ADDRSTRLEN] = {0};
|
||||
|
||||
inet_ntop(AF_INET, &api_nh->gate.ipv4, nhbuf,
|
||||
INET6_ADDRSTRLEN);
|
||||
zlog_debug("%s: nh=%s, vrf_id=%d", __func__,
|
||||
nhbuf, api_nh->vrf_id);
|
||||
}
|
||||
nexthop = nexthop_from_ipv4(&api_nh->gate.ipv4,
|
||||
NULL, api_nh->vrf_id);
|
||||
break;
|
||||
case NEXTHOP_TYPE_IPV4_IFINDEX:
|
||||
|
||||
memset(&vtep_ip, 0, sizeof(struct ipaddr));
|
||||
ifindex = api_nh->ifindex;
|
||||
if (IS_ZEBRA_DEBUG_RECV) {
|
||||
char nhbuf[INET6_ADDRSTRLEN] = {0};
|
||||
|
||||
inet_ntop(AF_INET, &api_nh->gate.ipv4, nhbuf,
|
||||
INET6_ADDRSTRLEN);
|
||||
zlog_debug(
|
||||
"%s: nh=%s, vrf_id=%d (re->vrf_id=%d), ifindex=%d",
|
||||
__func__, nhbuf, api_nh->vrf_id,
|
||||
re->vrf_id, ifindex);
|
||||
}
|
||||
nexthop = nexthop_from_ipv4_ifindex(
|
||||
&api_nh->gate.ipv4, NULL, ifindex,
|
||||
api_nh->vrf_id);
|
||||
|
||||
ifp = if_lookup_by_index(ifindex, api_nh->vrf_id);
|
||||
if (ifp && connected_is_unnumbered(ifp))
|
||||
SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK);
|
||||
/* Special handling for IPv4 routes sourced from EVPN:
|
||||
* the nexthop and associated MAC need to be installed.
|
||||
*/
|
||||
if (CHECK_FLAG(api.flags, ZEBRA_FLAG_EVPN_ROUTE)) {
|
||||
vtep_ip.ipa_type = IPADDR_V4;
|
||||
memcpy(&(vtep_ip.ipaddr_v4),
|
||||
&(api_nh->gate.ipv4),
|
||||
sizeof(struct in_addr));
|
||||
zebra_vxlan_evpn_vrf_route_add(
|
||||
api_nh->vrf_id, &api_nh->rmac,
|
||||
&vtep_ip, &api.prefix);
|
||||
}
|
||||
break;
|
||||
case NEXTHOP_TYPE_IPV6:
|
||||
nexthop = nexthop_from_ipv6(&api_nh->gate.ipv6,
|
||||
api_nh->vrf_id);
|
||||
break;
|
||||
case NEXTHOP_TYPE_IPV6_IFINDEX:
|
||||
memset(&vtep_ip, 0, sizeof(struct ipaddr));
|
||||
ifindex = api_nh->ifindex;
|
||||
nexthop = nexthop_from_ipv6_ifindex(&api_nh->gate.ipv6,
|
||||
ifindex,
|
||||
api_nh->vrf_id);
|
||||
|
||||
/* Special handling for IPv6 routes sourced from EVPN:
|
||||
* the nexthop and associated MAC need to be installed.
|
||||
*/
|
||||
if (CHECK_FLAG(api.flags, ZEBRA_FLAG_EVPN_ROUTE)) {
|
||||
vtep_ip.ipa_type = IPADDR_V6;
|
||||
memcpy(&vtep_ip.ipaddr_v6, &(api_nh->gate.ipv6),
|
||||
sizeof(struct in6_addr));
|
||||
zebra_vxlan_evpn_vrf_route_add(
|
||||
api_nh->vrf_id, &api_nh->rmac,
|
||||
&vtep_ip, &api.prefix);
|
||||
}
|
||||
break;
|
||||
case NEXTHOP_TYPE_BLACKHOLE:
|
||||
nexthop = nexthop_from_blackhole(api_nh->bh_type);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Convert zapi nexthop */
|
||||
nexthop = nexthop_from_zapi(re, api_nh, &api);
|
||||
if (!nexthop) {
|
||||
flog_warn(
|
||||
EC_ZEBRA_NEXTHOP_CREATION_FAILED,
|
||||
@ -1575,36 +1630,127 @@ static void zread_route_add(ZAPI_HANDLER_ARGS)
|
||||
return;
|
||||
}
|
||||
|
||||
if (CHECK_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_ONLINK))
|
||||
SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK);
|
||||
|
||||
if (CHECK_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_WEIGHT))
|
||||
nexthop->weight = api_nh->weight;
|
||||
|
||||
/* MPLS labels for BGP-LU or Segment Routing */
|
||||
if (CHECK_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_LABEL)
|
||||
&& api_nh->type != NEXTHOP_TYPE_IFINDEX
|
||||
&& api_nh->type != NEXTHOP_TYPE_BLACKHOLE) {
|
||||
enum lsp_types_t label_type;
|
||||
&& api_nh->type != NEXTHOP_TYPE_BLACKHOLE
|
||||
&& api_nh->label_num > 0) {
|
||||
|
||||
label_type = lsp_type_from_re_type(client->proto);
|
||||
|
||||
if (IS_ZEBRA_DEBUG_RECV) {
|
||||
zlog_debug(
|
||||
"%s: adding %d labels of type %d (1st=%u)",
|
||||
__func__, api_nh->label_num, label_type,
|
||||
api_nh->labels[0]);
|
||||
}
|
||||
|
||||
nexthop_add_labels(nexthop, label_type,
|
||||
api_nh->label_num,
|
||||
&api_nh->labels[0]);
|
||||
}
|
||||
|
||||
/* Add new nexthop to temporary list */
|
||||
if (IS_ZEBRA_DEBUG_RECV) {
|
||||
labelbuf[0] = '\0';
|
||||
nhbuf[0] = '\0';
|
||||
|
||||
nexthop2str(nexthop, nhbuf, sizeof(nhbuf));
|
||||
|
||||
if (nexthop->nh_label &&
|
||||
nexthop->nh_label->num_labels > 0) {
|
||||
mpls_label2str(nexthop->nh_label->num_labels,
|
||||
nexthop->nh_label->label,
|
||||
labelbuf, sizeof(labelbuf),
|
||||
false);
|
||||
}
|
||||
|
||||
zlog_debug("%s: nh=%s, vrf_id=%d %s",
|
||||
__func__, nhbuf, api_nh->vrf_id, labelbuf);
|
||||
}
|
||||
|
||||
/* Add new nexthop to temporary list. This list is
|
||||
* canonicalized - sorted - so that it can be hashed later
|
||||
* in route processing. We expect that the sender has sent
|
||||
* the list sorted, and the zapi client api attempts to enforce
|
||||
* that, so this should be inexpensive - but it is necessary
|
||||
* to support shared nexthop-groups.
|
||||
*/
|
||||
nexthop_group_add_sorted(ng, nexthop);
|
||||
}
|
||||
|
||||
/* Allocate temporary list of backup nexthops, if necessary */
|
||||
if (api.backup_nexthop_num > 0) {
|
||||
if (IS_ZEBRA_DEBUG_RECV)
|
||||
zlog_debug("%s: adding %d backup nexthops",
|
||||
__func__, api.backup_nexthop_num);
|
||||
|
||||
bnhg = zebra_nhg_backup_alloc();
|
||||
nexthop = NULL;
|
||||
last_nh = NULL;
|
||||
}
|
||||
|
||||
/* Copy backup nexthops also, if present */
|
||||
for (i = 0; i < api.backup_nexthop_num; i++) {
|
||||
api_nh = &api.backup_nexthops[i];
|
||||
|
||||
/* Convert zapi backup nexthop */
|
||||
nexthop = nexthop_from_zapi(re, api_nh, &api);
|
||||
if (!nexthop) {
|
||||
flog_warn(
|
||||
EC_ZEBRA_NEXTHOP_CREATION_FAILED,
|
||||
"%s: Backup Nexthops Specified: %d but we failed to properly create one",
|
||||
__func__, api.backup_nexthop_num);
|
||||
nexthop_group_delete(&ng);
|
||||
zebra_nhg_backup_free(&bnhg);
|
||||
XFREE(MTYPE_RE, re);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Backup nexthops can't have backups; that's not valid. */
|
||||
if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_HAS_BACKUP)) {
|
||||
if (IS_ZEBRA_DEBUG_RECV) {
|
||||
nexthop2str(nexthop, nhbuf, sizeof(nhbuf));
|
||||
zlog_debug("%s: backup nh %s with BACKUP flag!",
|
||||
__func__, nhbuf);
|
||||
}
|
||||
UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_HAS_BACKUP);
|
||||
nexthop->backup_idx = 0;
|
||||
}
|
||||
|
||||
/* MPLS labels for BGP-LU or Segment Routing */
|
||||
if (CHECK_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_LABEL)
|
||||
&& api_nh->type != NEXTHOP_TYPE_IFINDEX
|
||||
&& api_nh->type != NEXTHOP_TYPE_BLACKHOLE
|
||||
&& api_nh->label_num > 0) {
|
||||
|
||||
label_type = lsp_type_from_re_type(client->proto);
|
||||
nexthop_add_labels(nexthop, label_type,
|
||||
api_nh->label_num,
|
||||
&api_nh->labels[0]);
|
||||
}
|
||||
|
||||
if (IS_ZEBRA_DEBUG_RECV) {
|
||||
labelbuf[0] = '\0';
|
||||
nhbuf[0] = '\0';
|
||||
|
||||
nexthop2str(nexthop, nhbuf, sizeof(nhbuf));
|
||||
|
||||
if (nexthop->nh_label &&
|
||||
nexthop->nh_label->num_labels > 0) {
|
||||
mpls_label2str(nexthop->nh_label->num_labels,
|
||||
nexthop->nh_label->label,
|
||||
labelbuf, sizeof(labelbuf),
|
||||
false);
|
||||
}
|
||||
|
||||
zlog_debug("%s: backup nh=%s, vrf_id=%d %s",
|
||||
__func__, nhbuf, api_nh->vrf_id, labelbuf);
|
||||
}
|
||||
|
||||
/* Note that the order of the backup nexthops is significant,
|
||||
* so we don't sort this list as we do the primary nexthops,
|
||||
* we just append.
|
||||
*/
|
||||
if (last_nh)
|
||||
NEXTHOP_APPEND(last_nh, nexthop);
|
||||
else
|
||||
bnhg->nhe->nhg.nexthop = nexthop;
|
||||
|
||||
last_nh = nexthop;
|
||||
}
|
||||
|
||||
if (CHECK_FLAG(api.message, ZAPI_MESSAGE_DISTANCE))
|
||||
re->distance = api.distance;
|
||||
if (CHECK_FLAG(api.message, ZAPI_MESSAGE_METRIC))
|
||||
@ -1620,6 +1766,7 @@ static void zread_route_add(ZAPI_HANDLER_ARGS)
|
||||
"%s: Received SRC Prefix but afi is not v6",
|
||||
__func__);
|
||||
nexthop_group_delete(&ng);
|
||||
zebra_nhg_backup_free(&bnhg);
|
||||
XFREE(MTYPE_RE, re);
|
||||
return;
|
||||
}
|
||||
@ -1631,10 +1778,28 @@ static void zread_route_add(ZAPI_HANDLER_ARGS)
|
||||
"%s: Received safi: %d but we can only accept UNICAST or MULTICAST",
|
||||
__func__, api.safi);
|
||||
nexthop_group_delete(&ng);
|
||||
zebra_nhg_backup_free(&bnhg);
|
||||
XFREE(MTYPE_RE, re);
|
||||
return;
|
||||
}
|
||||
ret = rib_add_multipath(afi, api.safi, &api.prefix, src_p, re, ng);
|
||||
|
||||
/* Include backup info with the route. We use a temporary nhe here;
|
||||
* if this is a new/unknown nhe, a new copy will be allocated
|
||||
* and stored.
|
||||
*/
|
||||
zebra_nhe_init(&nhe, afi, ng->nexthop);
|
||||
nhe.nhg.nexthop = ng->nexthop;
|
||||
nhe.backup_info = bnhg;
|
||||
ret = rib_add_multipath_nhe(afi, api.safi, &api.prefix, src_p,
|
||||
re, &nhe);
|
||||
|
||||
/* At this point, these allocations are not needed: 're' has been
|
||||
* retained or freed, and if 're' still exists, it is using
|
||||
* a reference to a shared group object.
|
||||
*/
|
||||
nexthop_group_delete(&ng);
|
||||
if (bnhg)
|
||||
zebra_nhg_backup_free(&bnhg);
|
||||
|
||||
/* Stats */
|
||||
switch (api.prefix.family) {
|
||||
|
||||
@ -113,10 +113,15 @@ struct dplane_route_info {
|
||||
struct dplane_nexthop_info nhe;
|
||||
|
||||
/* Nexthops */
|
||||
uint32_t zd_nhg_id;
|
||||
struct nexthop_group zd_ng;
|
||||
|
||||
/* Backup nexthops (if present) */
|
||||
struct nexthop_group backup_ng;
|
||||
|
||||
/* "Previous" nexthops, used only in route updates without netlink */
|
||||
struct nexthop_group zd_old_ng;
|
||||
struct nexthop_group old_backup_ng;
|
||||
|
||||
/* TODO -- use fixed array of nexthops, to avoid mallocs? */
|
||||
|
||||
@ -472,6 +477,14 @@ static void dplane_ctx_free(struct zebra_dplane_ctx **pctx)
|
||||
(*pctx)->u.rinfo.zd_ng.nexthop = NULL;
|
||||
}
|
||||
|
||||
/* Free backup info also (if present) */
|
||||
if ((*pctx)->u.rinfo.backup_ng.nexthop) {
|
||||
/* This deals with recursive nexthops too */
|
||||
nexthops_free((*pctx)->u.rinfo.backup_ng.nexthop);
|
||||
|
||||
(*pctx)->u.rinfo.backup_ng.nexthop = NULL;
|
||||
}
|
||||
|
||||
if ((*pctx)->u.rinfo.zd_old_ng.nexthop) {
|
||||
/* This deals with recursive nexthops too */
|
||||
nexthops_free((*pctx)->u.rinfo.zd_old_ng.nexthop);
|
||||
@ -479,6 +492,13 @@ static void dplane_ctx_free(struct zebra_dplane_ctx **pctx)
|
||||
(*pctx)->u.rinfo.zd_old_ng.nexthop = NULL;
|
||||
}
|
||||
|
||||
if ((*pctx)->u.rinfo.old_backup_ng.nexthop) {
|
||||
/* This deals with recursive nexthops too */
|
||||
nexthops_free((*pctx)->u.rinfo.old_backup_ng.nexthop);
|
||||
|
||||
(*pctx)->u.rinfo.old_backup_ng.nexthop = NULL;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case DPLANE_OP_NH_INSTALL:
|
||||
@ -1038,6 +1058,12 @@ void dplane_ctx_set_nexthops(struct zebra_dplane_ctx *ctx, struct nexthop *nh)
|
||||
nexthop_group_copy_nh_sorted(&(ctx->u.rinfo.zd_ng), nh);
|
||||
}
|
||||
|
||||
uint32_t dplane_ctx_get_nhg_id(const struct zebra_dplane_ctx *ctx)
|
||||
{
|
||||
DPLANE_CTX_VALID(ctx);
|
||||
return ctx->u.rinfo.zd_nhg_id;
|
||||
}
|
||||
|
||||
const struct nexthop_group *dplane_ctx_get_ng(
|
||||
const struct zebra_dplane_ctx *ctx)
|
||||
{
|
||||
@ -1046,14 +1072,30 @@ const struct nexthop_group *dplane_ctx_get_ng(
|
||||
return &(ctx->u.rinfo.zd_ng);
|
||||
}
|
||||
|
||||
const struct nexthop_group *dplane_ctx_get_old_ng(
|
||||
const struct zebra_dplane_ctx *ctx)
|
||||
const struct nexthop_group *
|
||||
dplane_ctx_get_backup_ng(const struct zebra_dplane_ctx *ctx)
|
||||
{
|
||||
DPLANE_CTX_VALID(ctx);
|
||||
|
||||
return &(ctx->u.rinfo.backup_ng);
|
||||
}
|
||||
|
||||
const struct nexthop_group *
|
||||
dplane_ctx_get_old_ng(const struct zebra_dplane_ctx *ctx)
|
||||
{
|
||||
DPLANE_CTX_VALID(ctx);
|
||||
|
||||
return &(ctx->u.rinfo.zd_old_ng);
|
||||
}
|
||||
|
||||
const struct nexthop_group *
|
||||
dplane_ctx_get_old_backup_ng(const struct zebra_dplane_ctx *ctx)
|
||||
{
|
||||
DPLANE_CTX_VALID(ctx);
|
||||
|
||||
return &(ctx->u.rinfo.old_backup_ng);
|
||||
}
|
||||
|
||||
const struct zebra_dplane_info *dplane_ctx_get_ns(
|
||||
const struct zebra_dplane_ctx *ctx)
|
||||
{
|
||||
@ -1514,6 +1556,13 @@ static int dplane_ctx_route_init(struct zebra_dplane_ctx *ctx,
|
||||
/* Copy nexthops; recursive info is included too */
|
||||
copy_nexthops(&(ctx->u.rinfo.zd_ng.nexthop),
|
||||
re->nhe->nhg.nexthop, NULL);
|
||||
ctx->u.rinfo.zd_nhg_id = re->nhe->id;
|
||||
|
||||
/* Copy backup nexthop info, if present */
|
||||
if (re->nhe->backup_info && re->nhe->backup_info->nhe) {
|
||||
copy_nexthops(&(ctx->u.rinfo.backup_ng.nexthop),
|
||||
re->nhe->backup_info->nhe->nhg.nexthop, NULL);
|
||||
}
|
||||
|
||||
/* Ensure that the dplane nexthops' flags are clear. */
|
||||
for (ALL_NEXTHOPS(ctx->u.rinfo.zd_ng, nexthop))
|
||||
@ -1532,9 +1581,8 @@ static int dplane_ctx_route_init(struct zebra_dplane_ctx *ctx,
|
||||
dplane_ctx_ns_init(ctx, zns, (op == DPLANE_OP_ROUTE_UPDATE));
|
||||
|
||||
#ifdef HAVE_NETLINK
|
||||
if (re->nhe_id) {
|
||||
struct nhg_hash_entry *nhe =
|
||||
zebra_nhg_resolve(zebra_nhg_lookup_id(re->nhe_id));
|
||||
if (re->nhe) {
|
||||
struct nhg_hash_entry *nhe = zebra_nhg_resolve(re->nhe);
|
||||
|
||||
ctx->u.rinfo.nhe.id = nhe->id;
|
||||
/*
|
||||
@ -1581,7 +1629,6 @@ static int dplane_ctx_nexthop_init(struct zebra_dplane_ctx *ctx,
|
||||
{
|
||||
struct zebra_vrf *zvrf = NULL;
|
||||
struct zebra_ns *zns = NULL;
|
||||
|
||||
int ret = EINVAL;
|
||||
|
||||
if (!ctx || !nhe)
|
||||
@ -1850,6 +1897,17 @@ dplane_route_update_internal(struct route_node *rn,
|
||||
*/
|
||||
copy_nexthops(&(ctx->u.rinfo.zd_old_ng.nexthop),
|
||||
old_re->nhe->nhg.nexthop, NULL);
|
||||
|
||||
if (zebra_nhg_get_backup_nhg(old_re->nhe) != NULL) {
|
||||
struct nexthop_group *nhg;
|
||||
struct nexthop **nh;
|
||||
|
||||
nhg = zebra_nhg_get_backup_nhg(old_re->nhe);
|
||||
nh = &(ctx->u.rinfo.old_backup_ng.nexthop);
|
||||
|
||||
if (nhg->nexthop)
|
||||
copy_nexthops(nh, nhg->nexthop, NULL);
|
||||
}
|
||||
#endif /* !HAVE_NETLINK */
|
||||
}
|
||||
|
||||
|
||||
@ -270,11 +270,19 @@ void dplane_ctx_set_distance(struct zebra_dplane_ctx *ctx, uint8_t distance);
|
||||
uint8_t dplane_ctx_get_old_distance(const struct zebra_dplane_ctx *ctx);
|
||||
|
||||
void dplane_ctx_set_nexthops(struct zebra_dplane_ctx *ctx, struct nexthop *nh);
|
||||
|
||||
uint32_t dplane_ctx_get_nhg_id(const struct zebra_dplane_ctx *ctx);
|
||||
const struct nexthop_group *dplane_ctx_get_ng(
|
||||
const struct zebra_dplane_ctx *ctx);
|
||||
const struct nexthop_group *dplane_ctx_get_old_ng(
|
||||
const struct zebra_dplane_ctx *ctx);
|
||||
|
||||
/* Backup nexthop information (list of nexthops) if present. */
|
||||
const struct nexthop_group *
|
||||
dplane_ctx_get_backup_ng(const struct zebra_dplane_ctx *ctx);
|
||||
const struct nexthop_group *
|
||||
dplane_ctx_get_old_backup_ng(const struct zebra_dplane_ctx *ctx);
|
||||
|
||||
/* Accessors for nexthop information */
|
||||
uint32_t dplane_ctx_get_nhe_id(const struct zebra_dplane_ctx *ctx);
|
||||
afi_t dplane_ctx_get_nhe_afi(const struct zebra_dplane_ctx *ctx);
|
||||
|
||||
@ -98,14 +98,14 @@ static void lsp_free(struct hash *lsp_table, zebra_lsp_t **plsp);
|
||||
|
||||
static char *nhlfe2str(zebra_nhlfe_t *nhlfe, char *buf, int size);
|
||||
static int nhlfe_nhop_match(zebra_nhlfe_t *nhlfe, enum nexthop_types_t gtype,
|
||||
union g_addr *gate, ifindex_t ifindex);
|
||||
const union g_addr *gate, ifindex_t ifindex);
|
||||
static zebra_nhlfe_t *nhlfe_find(zebra_lsp_t *lsp, enum lsp_types_t lsp_type,
|
||||
enum nexthop_types_t gtype, union g_addr *gate,
|
||||
ifindex_t ifindex);
|
||||
enum nexthop_types_t gtype,
|
||||
const union g_addr *gate, ifindex_t ifindex);
|
||||
static zebra_nhlfe_t *nhlfe_add(zebra_lsp_t *lsp, enum lsp_types_t lsp_type,
|
||||
enum nexthop_types_t gtype, union g_addr *gate,
|
||||
ifindex_t ifindex, uint8_t num_labels,
|
||||
mpls_label_t *labels);
|
||||
enum nexthop_types_t gtype,
|
||||
const union g_addr *gate, ifindex_t ifindex,
|
||||
uint8_t num_labels, mpls_label_t *labels);
|
||||
static int nhlfe_del(zebra_nhlfe_t *snhlfe);
|
||||
static void nhlfe_out_label_update(zebra_nhlfe_t *nhlfe,
|
||||
struct mpls_label_stack *nh_label);
|
||||
@ -117,13 +117,13 @@ static void nhlfe_print(zebra_nhlfe_t *nhlfe, struct vty *vty);
|
||||
static void lsp_print(zebra_lsp_t *lsp, void *ctxt);
|
||||
static void *slsp_alloc(void *p);
|
||||
static int snhlfe_match(zebra_snhlfe_t *snhlfe, enum nexthop_types_t gtype,
|
||||
union g_addr *gate, ifindex_t ifindex);
|
||||
const union g_addr *gate, ifindex_t ifindex);
|
||||
static zebra_snhlfe_t *snhlfe_find(zebra_slsp_t *slsp,
|
||||
enum nexthop_types_t gtype,
|
||||
union g_addr *gate, ifindex_t ifindex);
|
||||
const union g_addr *gate, ifindex_t ifindex);
|
||||
static zebra_snhlfe_t *snhlfe_add(zebra_slsp_t *slsp,
|
||||
enum nexthop_types_t gtype,
|
||||
union g_addr *gate, ifindex_t ifindex,
|
||||
const union g_addr *gate, ifindex_t ifindex,
|
||||
mpls_label_t out_label);
|
||||
static int snhlfe_del(zebra_snhlfe_t *snhlfe);
|
||||
static int snhlfe_del_all(zebra_slsp_t *slsp);
|
||||
@ -960,7 +960,7 @@ static wq_item_status lsp_process(struct work_queue *wq, void *data)
|
||||
UNSET_FLAG(lsp->flags, LSP_FLAG_CHANGED);
|
||||
|
||||
/* We leave the INSTALLED flag set here
|
||||
* so we know an update in in-flight.
|
||||
* so we know an update is in-flight.
|
||||
*/
|
||||
|
||||
/*
|
||||
@ -1149,7 +1149,7 @@ static char *nhlfe2str(zebra_nhlfe_t *nhlfe, char *buf, int size)
|
||||
* Check if NHLFE matches with search info passed.
|
||||
*/
|
||||
static int nhlfe_nhop_match(zebra_nhlfe_t *nhlfe, enum nexthop_types_t gtype,
|
||||
union g_addr *gate, ifindex_t ifindex)
|
||||
const union g_addr *gate, ifindex_t ifindex)
|
||||
{
|
||||
struct nexthop *nhop;
|
||||
int cmp = 1;
|
||||
@ -1191,8 +1191,8 @@ static int nhlfe_nhop_match(zebra_nhlfe_t *nhlfe, enum nexthop_types_t gtype,
|
||||
* Locate NHLFE that matches with passed info.
|
||||
*/
|
||||
static zebra_nhlfe_t *nhlfe_find(zebra_lsp_t *lsp, enum lsp_types_t lsp_type,
|
||||
enum nexthop_types_t gtype, union g_addr *gate,
|
||||
ifindex_t ifindex)
|
||||
enum nexthop_types_t gtype,
|
||||
const union g_addr *gate, ifindex_t ifindex)
|
||||
{
|
||||
zebra_nhlfe_t *nhlfe;
|
||||
|
||||
@ -1214,9 +1214,9 @@ static zebra_nhlfe_t *nhlfe_find(zebra_lsp_t *lsp, enum lsp_types_t lsp_type,
|
||||
* check done.
|
||||
*/
|
||||
static zebra_nhlfe_t *nhlfe_add(zebra_lsp_t *lsp, enum lsp_types_t lsp_type,
|
||||
enum nexthop_types_t gtype, union g_addr *gate,
|
||||
ifindex_t ifindex, uint8_t num_labels,
|
||||
mpls_label_t labels[])
|
||||
enum nexthop_types_t gtype,
|
||||
const union g_addr *gate, ifindex_t ifindex,
|
||||
uint8_t num_labels, mpls_label_t labels[])
|
||||
{
|
||||
zebra_nhlfe_t *nhlfe;
|
||||
struct nexthop *nexthop;
|
||||
@ -1520,7 +1520,7 @@ static struct list *hash_get_sorted_list(struct hash *hash, void *cmp)
|
||||
/*
|
||||
* Compare two LSPs based on their label values.
|
||||
*/
|
||||
static int lsp_cmp(zebra_lsp_t *lsp1, zebra_lsp_t *lsp2)
|
||||
static int lsp_cmp(const zebra_lsp_t *lsp1, const zebra_lsp_t *lsp2)
|
||||
{
|
||||
if (lsp1->ile.in_label < lsp2->ile.in_label)
|
||||
return -1;
|
||||
@ -1547,7 +1547,7 @@ static void *slsp_alloc(void *p)
|
||||
/*
|
||||
* Compare two static LSPs based on their label values.
|
||||
*/
|
||||
static int slsp_cmp(zebra_slsp_t *slsp1, zebra_slsp_t *slsp2)
|
||||
static int slsp_cmp(const zebra_slsp_t *slsp1, const zebra_slsp_t *slsp2)
|
||||
{
|
||||
if (slsp1->ile.in_label < slsp2->ile.in_label)
|
||||
return -1;
|
||||
@ -1562,7 +1562,7 @@ static int slsp_cmp(zebra_slsp_t *slsp1, zebra_slsp_t *slsp2)
|
||||
* Check if static NHLFE matches with search info passed.
|
||||
*/
|
||||
static int snhlfe_match(zebra_snhlfe_t *snhlfe, enum nexthop_types_t gtype,
|
||||
union g_addr *gate, ifindex_t ifindex)
|
||||
const union g_addr *gate, ifindex_t ifindex)
|
||||
{
|
||||
int cmp = 1;
|
||||
|
||||
@ -1593,7 +1593,7 @@ static int snhlfe_match(zebra_snhlfe_t *snhlfe, enum nexthop_types_t gtype,
|
||||
*/
|
||||
static zebra_snhlfe_t *snhlfe_find(zebra_slsp_t *slsp,
|
||||
enum nexthop_types_t gtype,
|
||||
union g_addr *gate, ifindex_t ifindex)
|
||||
const union g_addr *gate, ifindex_t ifindex)
|
||||
{
|
||||
zebra_snhlfe_t *snhlfe;
|
||||
|
||||
@ -1615,7 +1615,7 @@ static zebra_snhlfe_t *snhlfe_find(zebra_slsp_t *slsp,
|
||||
*/
|
||||
static zebra_snhlfe_t *snhlfe_add(zebra_slsp_t *slsp,
|
||||
enum nexthop_types_t gtype,
|
||||
union g_addr *gate, ifindex_t ifindex,
|
||||
const union g_addr *gate, ifindex_t ifindex,
|
||||
mpls_label_t out_label)
|
||||
{
|
||||
zebra_snhlfe_t *snhlfe;
|
||||
@ -2746,7 +2746,7 @@ int mpls_ftn_uninstall(struct zebra_vrf *zvrf, enum lsp_types_t type,
|
||||
int mpls_lsp_install(struct zebra_vrf *zvrf, enum lsp_types_t type,
|
||||
mpls_label_t in_label, uint8_t num_out_labels,
|
||||
mpls_label_t out_labels[], enum nexthop_types_t gtype,
|
||||
union g_addr *gate, ifindex_t ifindex)
|
||||
const union g_addr *gate, ifindex_t ifindex)
|
||||
{
|
||||
struct hash *lsp_table;
|
||||
zebra_ile_t tmp_ile;
|
||||
@ -2759,11 +2759,12 @@ int mpls_lsp_install(struct zebra_vrf *zvrf, enum lsp_types_t type,
|
||||
if (!lsp_table)
|
||||
return -1;
|
||||
|
||||
/* If entry is present, exit. */
|
||||
/* Find or create LSP object */
|
||||
tmp_ile.in_label = in_label;
|
||||
lsp = hash_get(lsp_table, &tmp_ile, lsp_alloc);
|
||||
if (!lsp)
|
||||
return -1;
|
||||
|
||||
nhlfe = nhlfe_find(lsp, type, gtype, gate, ifindex);
|
||||
if (nhlfe) {
|
||||
struct nexthop *nh = nhlfe->nexthop;
|
||||
@ -2780,8 +2781,8 @@ int mpls_lsp_install(struct zebra_vrf *zvrf, enum lsp_types_t type,
|
||||
return 0;
|
||||
|
||||
if (IS_ZEBRA_DEBUG_MPLS) {
|
||||
char buf2[BUFSIZ];
|
||||
char buf3[BUFSIZ];
|
||||
char buf2[MPLS_LABEL_STRLEN];
|
||||
char buf3[MPLS_LABEL_STRLEN];
|
||||
|
||||
nhlfe2str(nhlfe, buf, BUFSIZ);
|
||||
mpls_label2str(num_out_labels, out_labels, buf2,
|
||||
@ -2842,7 +2843,7 @@ int mpls_lsp_install(struct zebra_vrf *zvrf, enum lsp_types_t type,
|
||||
*/
|
||||
int mpls_lsp_uninstall(struct zebra_vrf *zvrf, enum lsp_types_t type,
|
||||
mpls_label_t in_label, enum nexthop_types_t gtype,
|
||||
union g_addr *gate, ifindex_t ifindex)
|
||||
const union g_addr *gate, ifindex_t ifindex)
|
||||
{
|
||||
struct hash *lsp_table;
|
||||
zebra_ile_t tmp_ile;
|
||||
@ -3056,11 +3057,12 @@ int zebra_mpls_static_lsp_add(struct zebra_vrf *zvrf, mpls_label_t in_label,
|
||||
if (!slsp_table)
|
||||
return -1;
|
||||
|
||||
/* If entry is present, exit. */
|
||||
/* Find or create LSP. */
|
||||
tmp_ile.in_label = in_label;
|
||||
slsp = hash_get(slsp_table, &tmp_ile, slsp_alloc);
|
||||
if (!slsp)
|
||||
return -1;
|
||||
|
||||
snhlfe = snhlfe_find(slsp, gtype, gate, ifindex);
|
||||
if (snhlfe) {
|
||||
if (snhlfe->out_label == out_label)
|
||||
|
||||
@ -288,7 +288,7 @@ int mpls_ftn_uninstall(struct zebra_vrf *zvrf, enum lsp_types_t type,
|
||||
int mpls_lsp_install(struct zebra_vrf *zvrf, enum lsp_types_t type,
|
||||
mpls_label_t in_label, uint8_t num_out_labels,
|
||||
mpls_label_t out_labels[], enum nexthop_types_t gtype,
|
||||
union g_addr *gate, ifindex_t ifindex);
|
||||
const union g_addr *gate, ifindex_t ifindex);
|
||||
|
||||
/*
|
||||
* Uninstall a particular NHLFE in the forwarding table. If this is
|
||||
@ -296,7 +296,7 @@ int mpls_lsp_install(struct zebra_vrf *zvrf, enum lsp_types_t type,
|
||||
*/
|
||||
int mpls_lsp_uninstall(struct zebra_vrf *zvrf, enum lsp_types_t type,
|
||||
mpls_label_t in_label, enum nexthop_types_t gtype,
|
||||
union g_addr *gate, ifindex_t ifindex);
|
||||
const union g_addr *gate, ifindex_t ifindex);
|
||||
|
||||
/*
|
||||
* Uninstall all NHLFEs for a particular LSP forwarding entry.
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -50,6 +50,9 @@ struct nhg_hash_entry {
|
||||
|
||||
struct nexthop_group nhg;
|
||||
|
||||
/* If supported, a mapping of backup nexthops. */
|
||||
struct nhg_backup_info *backup_info;
|
||||
|
||||
/* If this is not a group, it
|
||||
* will be a single nexthop
|
||||
* and must have an interface
|
||||
@ -72,6 +75,7 @@ struct nhg_hash_entry {
|
||||
* faster with ID's.
|
||||
*/
|
||||
struct nhg_connected_tree_head nhg_depends, nhg_dependents;
|
||||
|
||||
/*
|
||||
* Is this nexthop group valid, ie all nexthops are fully resolved.
|
||||
* What is fully resolved? It's a nexthop that is either self contained
|
||||
@ -102,11 +106,25 @@ struct nhg_hash_entry {
|
||||
* from the kernel. Therefore, it is unhashable.
|
||||
*/
|
||||
#define NEXTHOP_GROUP_UNHASHABLE (1 << 4)
|
||||
|
||||
/*
|
||||
* Backup nexthop support - identify groups that are backups for
|
||||
* another group.
|
||||
*/
|
||||
#define NEXTHOP_GROUP_BACKUP (1 << 5)
|
||||
|
||||
};
|
||||
|
||||
/* Was this one we created, either this session or previously? */
|
||||
#define ZEBRA_NHG_CREATED(NHE) ((NHE->type) == ZEBRA_ROUTE_NHG)
|
||||
|
||||
/*
|
||||
* Backup nexthops: this is a group object itself, so
|
||||
* that the backup nexthops can use the same code as a normal object.
|
||||
*/
|
||||
struct nhg_backup_info {
|
||||
struct nhg_hash_entry *nhe;
|
||||
};
|
||||
|
||||
enum nhg_ctx_op_e {
|
||||
NHG_CTX_OP_NONE = 0,
|
||||
@ -162,13 +180,26 @@ bool zebra_nhg_kernel_nexthops_enabled(void);
|
||||
|
||||
/**
|
||||
* NHE abstracted tree functions.
|
||||
* Use these where possible instead of the direct ones access ones.
|
||||
* Use these where possible instead of direct access.
|
||||
*/
|
||||
struct nhg_hash_entry *zebra_nhg_alloc(void);
|
||||
void zebra_nhg_free(struct nhg_hash_entry *nhe);
|
||||
/* In order to clear a generic hash, we need a generic api, sigh. */
|
||||
void zebra_nhg_hash_free(void *p);
|
||||
|
||||
/* Init an nhe, for use in a hash lookup for example. There's some fuzziness
|
||||
* if the nhe represents only a single nexthop, so we try to capture that
|
||||
* variant also.
|
||||
*/
|
||||
void zebra_nhe_init(struct nhg_hash_entry *nhe, afi_t afi,
|
||||
const struct nexthop *nh);
|
||||
|
||||
/* Allocate, free backup nexthop info objects */
|
||||
struct nhg_backup_info *zebra_nhg_backup_alloc(void);
|
||||
void zebra_nhg_backup_free(struct nhg_backup_info **p);
|
||||
|
||||
struct nexthop_group *zebra_nhg_get_backup_nhg(struct nhg_hash_entry *nhe);
|
||||
|
||||
extern struct nhg_hash_entry *zebra_nhg_resolve(struct nhg_hash_entry *nhe);
|
||||
|
||||
extern unsigned int zebra_nhg_depends_count(const struct nhg_hash_entry *nhe);
|
||||
@ -203,10 +234,14 @@ extern int zebra_nhg_kernel_find(uint32_t id, struct nexthop *nh,
|
||||
/* Del via kernel */
|
||||
extern int zebra_nhg_kernel_del(uint32_t id, vrf_id_t vrf_id);
|
||||
|
||||
/* Find via route creation */
|
||||
/* Find an nhe based on a nexthop_group */
|
||||
extern struct nhg_hash_entry *
|
||||
zebra_nhg_rib_find(uint32_t id, struct nexthop_group *nhg, afi_t rt_afi);
|
||||
|
||||
/* Find an nhe based on a route's nhe, used during route creation */
|
||||
struct nhg_hash_entry *
|
||||
zebra_nhg_rib_find_nhe(struct nhg_hash_entry *rt_nhe, afi_t rt_afi);
|
||||
|
||||
/* Reference counter functions */
|
||||
extern void zebra_nhg_decrement_ref(struct nhg_hash_entry *nhe);
|
||||
extern void zebra_nhg_increment_ref(struct nhg_hash_entry *nhe);
|
||||
|
||||
@ -213,7 +213,7 @@ static void route_entry_attach_ref(struct route_entry *re,
|
||||
|
||||
int route_entry_update_nhe(struct route_entry *re, struct nhg_hash_entry *new)
|
||||
{
|
||||
struct nhg_hash_entry *old = NULL;
|
||||
struct nhg_hash_entry *old;
|
||||
int ret = 0;
|
||||
|
||||
if (new == NULL) {
|
||||
@ -223,7 +223,7 @@ int route_entry_update_nhe(struct route_entry *re, struct nhg_hash_entry *new)
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (re->nhe_id != new->id) {
|
||||
if ((re->nhe_id != 0) && (re->nhe_id != new->id)) {
|
||||
old = re->nhe;
|
||||
|
||||
route_entry_attach_ref(re, new);
|
||||
@ -2338,7 +2338,6 @@ static void rib_addnode(struct route_node *rn,
|
||||
void rib_unlink(struct route_node *rn, struct route_entry *re)
|
||||
{
|
||||
rib_dest_t *dest;
|
||||
struct nhg_hash_entry *nhe = NULL;
|
||||
|
||||
assert(rn && re);
|
||||
|
||||
@ -2353,11 +2352,10 @@ void rib_unlink(struct route_node *rn, struct route_entry *re)
|
||||
if (dest->selected_fib == re)
|
||||
dest->selected_fib = NULL;
|
||||
|
||||
if (re->nhe_id) {
|
||||
nhe = zebra_nhg_lookup_id(re->nhe_id);
|
||||
if (nhe)
|
||||
zebra_nhg_decrement_ref(nhe);
|
||||
} else if (re->nhe->nhg.nexthop)
|
||||
if (re->nhe && re->nhe_id) {
|
||||
assert(re->nhe->id == re->nhe_id);
|
||||
zebra_nhg_decrement_ref(re->nhe);
|
||||
} else if (re->nhe && re->nhe->nhg.nexthop)
|
||||
nexthops_free(re->nhe->nhg.nexthop);
|
||||
|
||||
nexthops_free(re->fib_ng.nexthop);
|
||||
@ -2396,11 +2394,75 @@ void rib_delnode(struct route_node *rn, struct route_entry *re)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Helper that debugs a single nexthop within a route-entry
|
||||
*/
|
||||
static void _route_entry_dump_nh(const struct route_entry *re,
|
||||
const char *straddr,
|
||||
const struct nexthop *nexthop)
|
||||
{
|
||||
char nhname[PREFIX_STRLEN];
|
||||
char backup_str[50];
|
||||
char wgt_str[50];
|
||||
struct interface *ifp;
|
||||
struct vrf *vrf = vrf_lookup_by_id(nexthop->vrf_id);
|
||||
|
||||
switch (nexthop->type) {
|
||||
case NEXTHOP_TYPE_BLACKHOLE:
|
||||
sprintf(nhname, "Blackhole");
|
||||
break;
|
||||
case NEXTHOP_TYPE_IFINDEX:
|
||||
ifp = if_lookup_by_index(nexthop->ifindex, nexthop->vrf_id);
|
||||
sprintf(nhname, "%s", ifp ? ifp->name : "Unknown");
|
||||
break;
|
||||
case NEXTHOP_TYPE_IPV4:
|
||||
/* fallthrough */
|
||||
case NEXTHOP_TYPE_IPV4_IFINDEX:
|
||||
inet_ntop(AF_INET, &nexthop->gate, nhname, INET6_ADDRSTRLEN);
|
||||
break;
|
||||
case NEXTHOP_TYPE_IPV6:
|
||||
case NEXTHOP_TYPE_IPV6_IFINDEX:
|
||||
inet_ntop(AF_INET6, &nexthop->gate, nhname, INET6_ADDRSTRLEN);
|
||||
break;
|
||||
}
|
||||
|
||||
backup_str[0] = '\0';
|
||||
if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_HAS_BACKUP)) {
|
||||
snprintf(backup_str, sizeof(backup_str), "backup %d,",
|
||||
(int)nexthop->backup_idx);
|
||||
}
|
||||
|
||||
wgt_str[0] = '\0';
|
||||
if (nexthop->weight)
|
||||
snprintf(wgt_str, sizeof(wgt_str), "wgt %d,", nexthop->weight);
|
||||
|
||||
zlog_debug("%s: %s %s[%u] vrf %s(%u) %s%s with flags %s%s%s%s%s",
|
||||
straddr, (nexthop->rparent ? " NH" : "NH"), nhname,
|
||||
nexthop->ifindex, vrf ? vrf->name : "Unknown",
|
||||
nexthop->vrf_id,
|
||||
wgt_str, backup_str,
|
||||
(CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE)
|
||||
? "ACTIVE "
|
||||
: ""),
|
||||
(CHECK_FLAG(re->status, ROUTE_ENTRY_INSTALLED)
|
||||
? "FIB "
|
||||
: ""),
|
||||
(CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE)
|
||||
? "RECURSIVE "
|
||||
: ""),
|
||||
(CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK)
|
||||
? "ONLINK "
|
||||
: ""),
|
||||
(CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_DUPLICATE)
|
||||
? "DUPLICATE "
|
||||
: ""));
|
||||
|
||||
}
|
||||
|
||||
/* This function dumps the contents of a given RE entry into
|
||||
* standard debug log. Calling function name and IP prefix in
|
||||
* question are passed as 1st and 2nd arguments.
|
||||
*/
|
||||
|
||||
void _route_entry_dump(const char *func, union prefixconstptr pp,
|
||||
union prefixconstptr src_pp,
|
||||
const struct route_entry *re)
|
||||
@ -2409,9 +2471,9 @@ void _route_entry_dump(const char *func, union prefixconstptr pp,
|
||||
bool is_srcdst = src_p && src_p->prefixlen;
|
||||
char straddr[PREFIX_STRLEN];
|
||||
char srcaddr[PREFIX_STRLEN];
|
||||
char nhname[PREFIX_STRLEN];
|
||||
struct nexthop *nexthop;
|
||||
struct vrf *vrf = vrf_lookup_by_id(re->vrf_id);
|
||||
struct nexthop_group *nhg;
|
||||
|
||||
zlog_debug("%s: dumping RE entry %p for %s%s%s vrf %s(%u)", func,
|
||||
(const void *)re, prefix2str(pp, straddr, sizeof(straddr)),
|
||||
@ -2422,65 +2484,32 @@ void _route_entry_dump(const char *func, union prefixconstptr pp,
|
||||
zlog_debug("%s: uptime == %lu, type == %u, instance == %d, table == %d",
|
||||
straddr, (unsigned long)re->uptime, re->type, re->instance,
|
||||
re->table);
|
||||
zlog_debug(
|
||||
"%s: metric == %u, mtu == %u, distance == %u, flags == %u, status == %u",
|
||||
straddr, re->metric, re->mtu, re->distance, re->flags, re->status);
|
||||
zlog_debug("%s: metric == %u, mtu == %u, distance == %u, flags == %u, status == %u",
|
||||
straddr, re->metric, re->mtu, re->distance, re->flags,
|
||||
re->status);
|
||||
zlog_debug("%s: nexthop_num == %u, nexthop_active_num == %u", straddr,
|
||||
nexthop_group_nexthop_num(&(re->nhe->nhg)),
|
||||
nexthop_group_active_nexthop_num(&(re->nhe->nhg)));
|
||||
|
||||
for (ALL_NEXTHOPS(re->nhe->nhg, nexthop)) {
|
||||
struct interface *ifp;
|
||||
struct vrf *vrf = vrf_lookup_by_id(nexthop->vrf_id);
|
||||
/* Dump nexthops */
|
||||
for (ALL_NEXTHOPS(re->nhe->nhg, nexthop))
|
||||
_route_entry_dump_nh(re, straddr, nexthop);
|
||||
|
||||
switch (nexthop->type) {
|
||||
case NEXTHOP_TYPE_BLACKHOLE:
|
||||
sprintf(nhname, "Blackhole");
|
||||
break;
|
||||
case NEXTHOP_TYPE_IFINDEX:
|
||||
ifp = if_lookup_by_index(nexthop->ifindex,
|
||||
nexthop->vrf_id);
|
||||
sprintf(nhname, "%s", ifp ? ifp->name : "Unknown");
|
||||
break;
|
||||
case NEXTHOP_TYPE_IPV4:
|
||||
/* fallthrough */
|
||||
case NEXTHOP_TYPE_IPV4_IFINDEX:
|
||||
inet_ntop(AF_INET, &nexthop->gate, nhname,
|
||||
INET6_ADDRSTRLEN);
|
||||
break;
|
||||
case NEXTHOP_TYPE_IPV6:
|
||||
case NEXTHOP_TYPE_IPV6_IFINDEX:
|
||||
inet_ntop(AF_INET6, &nexthop->gate, nhname,
|
||||
INET6_ADDRSTRLEN);
|
||||
break;
|
||||
}
|
||||
zlog_debug("%s: %s %s[%u] vrf %s(%u) with flags %s%s%s%s%s",
|
||||
straddr, (nexthop->rparent ? " NH" : "NH"), nhname,
|
||||
nexthop->ifindex, vrf ? vrf->name : "Unknown",
|
||||
nexthop->vrf_id,
|
||||
(CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE)
|
||||
? "ACTIVE "
|
||||
: ""),
|
||||
(CHECK_FLAG(re->status, ROUTE_ENTRY_INSTALLED)
|
||||
? "FIB "
|
||||
: ""),
|
||||
(CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE)
|
||||
? "RECURSIVE "
|
||||
: ""),
|
||||
(CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK)
|
||||
? "ONLINK "
|
||||
: ""),
|
||||
(CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_DUPLICATE)
|
||||
? "DUPLICATE "
|
||||
: ""));
|
||||
if (zebra_nhg_get_backup_nhg(re->nhe)) {
|
||||
zlog_debug("%s: backup nexthops:", straddr);
|
||||
|
||||
nhg = zebra_nhg_get_backup_nhg(re->nhe);
|
||||
for (ALL_NEXTHOPS_PTR(nhg, nexthop))
|
||||
_route_entry_dump_nh(re, straddr, nexthop);
|
||||
}
|
||||
|
||||
zlog_debug("%s: dump complete", straddr);
|
||||
}
|
||||
|
||||
/* This is an exported helper to rtm_read() to dump the strange
|
||||
/*
|
||||
* This is an exported helper to rtm_read() to dump the strange
|
||||
* RE entry found by rib_lookup_ipv4_route()
|
||||
*/
|
||||
|
||||
void rib_lookup_and_dump(struct prefix_ipv4 *p, vrf_id_t vrf_id)
|
||||
{
|
||||
struct route_table *table;
|
||||
@ -2574,9 +2603,16 @@ void rib_lookup_and_pushup(struct prefix_ipv4 *p, vrf_id_t vrf_id)
|
||||
}
|
||||
}
|
||||
|
||||
int rib_add_multipath(afi_t afi, safi_t safi, struct prefix *p,
|
||||
struct prefix_ipv6 *src_p, struct route_entry *re,
|
||||
struct nexthop_group *ng)
|
||||
/*
|
||||
* Internal route-add implementation; there are a couple of different public
|
||||
* signatures. Callers in this path are responsible for the memory they
|
||||
* allocate: if they allocate a nexthop_group or backup nexthop info, they
|
||||
* must free those objects. If this returns < 0, an error has occurred and the
|
||||
* route_entry 're' has not been captured; the caller should free that also.
|
||||
*/
|
||||
int rib_add_multipath_nhe(afi_t afi, safi_t safi, struct prefix *p,
|
||||
struct prefix_ipv6 *src_p, struct route_entry *re,
|
||||
struct nhg_hash_entry *re_nhe)
|
||||
{
|
||||
struct nhg_hash_entry *nhe = NULL;
|
||||
struct route_table *table;
|
||||
@ -2584,41 +2620,31 @@ int rib_add_multipath(afi_t afi, safi_t safi, struct prefix *p,
|
||||
struct route_entry *same = NULL;
|
||||
int ret = 0;
|
||||
|
||||
if (!re)
|
||||
return 0;
|
||||
if (!re || !re_nhe)
|
||||
return -1;
|
||||
|
||||
assert(!src_p || !src_p->prefixlen || afi == AFI_IP6);
|
||||
|
||||
/* Lookup table. */
|
||||
table = zebra_vrf_get_table_with_table_id(afi, safi, re->vrf_id,
|
||||
re->table);
|
||||
if (!table) {
|
||||
if (ng)
|
||||
nexthop_group_delete(&ng);
|
||||
XFREE(MTYPE_RE, re);
|
||||
return 0;
|
||||
}
|
||||
if (!table)
|
||||
return -1;
|
||||
|
||||
if (re->nhe_id) {
|
||||
nhe = zebra_nhg_lookup_id(re->nhe_id);
|
||||
if (re_nhe->id > 0) {
|
||||
nhe = zebra_nhg_lookup_id(re_nhe->id);
|
||||
|
||||
if (!nhe) {
|
||||
flog_err(
|
||||
EC_ZEBRA_TABLE_LOOKUP_FAILED,
|
||||
"Zebra failed to find the nexthop hash entry for id=%u in a route entry",
|
||||
re->nhe_id);
|
||||
XFREE(MTYPE_RE, re);
|
||||
re_nhe->id);
|
||||
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
nhe = zebra_nhg_rib_find(0, ng, afi);
|
||||
|
||||
/*
|
||||
* The nexthops got copied over into an nhe,
|
||||
* so free them now.
|
||||
*/
|
||||
nexthop_group_delete(&ng);
|
||||
|
||||
/* Lookup nhe from route information */
|
||||
nhe = zebra_nhg_rib_find_nhe(re_nhe, afi);
|
||||
if (!nhe) {
|
||||
char buf[PREFIX_STRLEN] = "";
|
||||
char buf2[PREFIX_STRLEN] = "";
|
||||
@ -2631,7 +2657,6 @@ int rib_add_multipath(afi_t afi, safi_t safi, struct prefix *p,
|
||||
src_p ? prefix2str(src_p, buf2, sizeof(buf2))
|
||||
: "");
|
||||
|
||||
XFREE(MTYPE_RE, re);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
@ -2709,15 +2734,51 @@ int rib_add_multipath(afi_t afi, safi_t safi, struct prefix *p,
|
||||
ret = 1;
|
||||
|
||||
/* Free implicit route.*/
|
||||
if (same) {
|
||||
if (same)
|
||||
rib_delnode(rn, same);
|
||||
ret = -1;
|
||||
}
|
||||
|
||||
route_unlock_node(rn);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Add a single route.
|
||||
*/
|
||||
int rib_add_multipath(afi_t afi, safi_t safi, struct prefix *p,
|
||||
struct prefix_ipv6 *src_p, struct route_entry *re,
|
||||
struct nexthop_group *ng)
|
||||
{
|
||||
int ret;
|
||||
struct nhg_hash_entry nhe;
|
||||
|
||||
if (!re)
|
||||
return -1;
|
||||
|
||||
/* We either need nexthop(s) or an existing nexthop id */
|
||||
if (ng == NULL && re->nhe_id == 0)
|
||||
return -1;
|
||||
|
||||
/*
|
||||
* Use a temporary nhe to convey info to the common/main api.
|
||||
*/
|
||||
zebra_nhe_init(&nhe, afi, (ng ? ng->nexthop : NULL));
|
||||
if (ng)
|
||||
nhe.nhg.nexthop = ng->nexthop;
|
||||
else if (re->nhe_id > 0)
|
||||
nhe.id = re->nhe_id;
|
||||
|
||||
ret = rib_add_multipath_nhe(afi, safi, p, src_p, re, &nhe);
|
||||
|
||||
/* In this path, the callers expect memory to be freed. */
|
||||
nexthop_group_delete(&ng);
|
||||
|
||||
/* In error cases, free the route also */
|
||||
if (ret < 0)
|
||||
XFREE(MTYPE_RE, re);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void rib_delete(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type,
|
||||
unsigned short instance, int flags, struct prefix *p,
|
||||
struct prefix_ipv6 *src_p, const struct nexthop *nh,
|
||||
@ -3188,6 +3249,9 @@ void rib_sweep_table(struct route_table *table)
|
||||
if (!table)
|
||||
return;
|
||||
|
||||
if (IS_ZEBRA_DEBUG_RIB)
|
||||
zlog_debug("%s: starting", __func__);
|
||||
|
||||
for (rn = route_top(table); rn; rn = srcdest_route_next(rn)) {
|
||||
RNODE_FOREACH_RE_SAFE (rn, re, next) {
|
||||
|
||||
@ -3234,6 +3298,9 @@ void rib_sweep_table(struct route_table *table)
|
||||
rib_delnode(rn, re);
|
||||
}
|
||||
}
|
||||
|
||||
if (IS_ZEBRA_DEBUG_RIB)
|
||||
zlog_debug("%s: ends", __func__);
|
||||
}
|
||||
|
||||
/* Sweep all RIB tables. */
|
||||
|
||||
@ -164,7 +164,8 @@ DEFUN (show_ip_rpf_addr,
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
static char re_status_output_char(struct route_entry *re, struct nexthop *nhop)
|
||||
static char re_status_output_char(const struct route_entry *re,
|
||||
const struct nexthop *nhop)
|
||||
{
|
||||
if (CHECK_FLAG(re->status, ROUTE_ENTRY_INSTALLED)) {
|
||||
if (!CHECK_FLAG(nhop->flags, NEXTHOP_FLAG_DUPLICATE) &&
|
||||
@ -187,6 +188,152 @@ static char re_status_output_char(struct route_entry *re, struct nexthop *nhop)
|
||||
return ' ';
|
||||
}
|
||||
|
||||
/*
|
||||
* TODO -- Show backup nexthop info
|
||||
*/
|
||||
static void show_nh_backup_helper(struct vty *vty,
|
||||
const struct nhg_hash_entry *nhe,
|
||||
const struct nexthop *nexthop)
|
||||
{
|
||||
/* Double-check that there _is_ a backup */
|
||||
if (!CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_HAS_BACKUP))
|
||||
return;
|
||||
|
||||
/* Locate the backup nexthop */
|
||||
|
||||
/* Format the backup (indented) */
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Helper api to format output for a nexthop, used in the 'detailed'
|
||||
* output path.
|
||||
*/
|
||||
static void show_nexthop_detail_helper(struct vty *vty,
|
||||
const struct route_entry *re,
|
||||
const struct nexthop *nexthop)
|
||||
{
|
||||
char addrstr[32];
|
||||
char buf[MPLS_LABEL_STRLEN];
|
||||
|
||||
vty_out(vty, " %c%s",
|
||||
re_status_output_char(re, nexthop),
|
||||
nexthop->rparent ? " " : "");
|
||||
|
||||
switch (nexthop->type) {
|
||||
case NEXTHOP_TYPE_IPV4:
|
||||
case NEXTHOP_TYPE_IPV4_IFINDEX:
|
||||
vty_out(vty, " %s",
|
||||
inet_ntoa(nexthop->gate.ipv4));
|
||||
if (nexthop->ifindex)
|
||||
vty_out(vty, ", via %s",
|
||||
ifindex2ifname(
|
||||
nexthop->ifindex,
|
||||
nexthop->vrf_id));
|
||||
break;
|
||||
case NEXTHOP_TYPE_IPV6:
|
||||
case NEXTHOP_TYPE_IPV6_IFINDEX:
|
||||
vty_out(vty, " %s",
|
||||
inet_ntop(AF_INET6, &nexthop->gate.ipv6,
|
||||
buf, sizeof(buf)));
|
||||
if (nexthop->ifindex)
|
||||
vty_out(vty, ", via %s",
|
||||
ifindex2ifname(
|
||||
nexthop->ifindex,
|
||||
nexthop->vrf_id));
|
||||
break;
|
||||
|
||||
case NEXTHOP_TYPE_IFINDEX:
|
||||
vty_out(vty, " directly connected, %s",
|
||||
ifindex2ifname(nexthop->ifindex,
|
||||
nexthop->vrf_id));
|
||||
break;
|
||||
case NEXTHOP_TYPE_BLACKHOLE:
|
||||
vty_out(vty, " unreachable");
|
||||
switch (nexthop->bh_type) {
|
||||
case BLACKHOLE_REJECT:
|
||||
vty_out(vty, " (ICMP unreachable)");
|
||||
break;
|
||||
case BLACKHOLE_ADMINPROHIB:
|
||||
vty_out(vty,
|
||||
" (ICMP admin-prohibited)");
|
||||
break;
|
||||
case BLACKHOLE_NULL:
|
||||
vty_out(vty, " (blackhole)");
|
||||
break;
|
||||
case BLACKHOLE_UNSPEC:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if ((re->vrf_id != nexthop->vrf_id)
|
||||
&& (nexthop->type != NEXTHOP_TYPE_BLACKHOLE)) {
|
||||
struct vrf *vrf =
|
||||
vrf_lookup_by_id(nexthop->vrf_id);
|
||||
|
||||
if (vrf)
|
||||
vty_out(vty, "(vrf %s)", vrf->name);
|
||||
else
|
||||
vty_out(vty, "(vrf UNKNOWN)");
|
||||
}
|
||||
|
||||
if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_DUPLICATE))
|
||||
vty_out(vty, " (duplicate nexthop removed)");
|
||||
|
||||
if (!CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE))
|
||||
vty_out(vty, " inactive");
|
||||
|
||||
if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK))
|
||||
vty_out(vty, " onlink");
|
||||
|
||||
if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
|
||||
vty_out(vty, " (recursive)");
|
||||
|
||||
/* Source specified? */
|
||||
switch (nexthop->type) {
|
||||
case NEXTHOP_TYPE_IPV4:
|
||||
case NEXTHOP_TYPE_IPV4_IFINDEX:
|
||||
if (nexthop->src.ipv4.s_addr) {
|
||||
if (inet_ntop(AF_INET, &nexthop->src.ipv4,
|
||||
addrstr, sizeof(addrstr)))
|
||||
vty_out(vty, ", src %s",
|
||||
addrstr);
|
||||
}
|
||||
break;
|
||||
|
||||
case NEXTHOP_TYPE_IPV6:
|
||||
case NEXTHOP_TYPE_IPV6_IFINDEX:
|
||||
if (!IPV6_ADDR_SAME(&nexthop->src.ipv6,
|
||||
&in6addr_any)) {
|
||||
if (inet_ntop(AF_INET6, &nexthop->src.ipv6,
|
||||
addrstr, sizeof(addrstr)))
|
||||
vty_out(vty, ", src %s",
|
||||
addrstr);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (re->nexthop_mtu)
|
||||
vty_out(vty, ", mtu %u", re->nexthop_mtu);
|
||||
|
||||
/* Label information */
|
||||
if (nexthop->nh_label && nexthop->nh_label->num_labels) {
|
||||
vty_out(vty, ", label %s",
|
||||
mpls_label2str(nexthop->nh_label->num_labels,
|
||||
nexthop->nh_label->label, buf,
|
||||
sizeof(buf), 1 /*pretty*/));
|
||||
}
|
||||
|
||||
if (nexthop->weight)
|
||||
vty_out(vty, ", weight %u", nexthop->weight);
|
||||
}
|
||||
|
||||
/* New RIB. Detailed information for IPv4 route. */
|
||||
static void vty_show_ip_route_detail(struct vty *vty, struct route_node *rn,
|
||||
int mcast, bool use_fib, bool show_ng)
|
||||
@ -253,131 +400,124 @@ static void vty_show_ip_route_detail(struct vty *vty, struct route_node *rn,
|
||||
vty_out(vty, " Nexthop Group ID: %u\n", re->nhe_id);
|
||||
|
||||
for (ALL_NEXTHOPS(re->nhe->nhg, nexthop)) {
|
||||
char addrstr[32];
|
||||
|
||||
vty_out(vty, " %c%s",
|
||||
re_status_output_char(re, nexthop),
|
||||
nexthop->rparent ? " " : "");
|
||||
|
||||
switch (nexthop->type) {
|
||||
case NEXTHOP_TYPE_IPV4:
|
||||
case NEXTHOP_TYPE_IPV4_IFINDEX:
|
||||
vty_out(vty, " %s",
|
||||
inet_ntoa(nexthop->gate.ipv4));
|
||||
if (nexthop->ifindex)
|
||||
vty_out(vty, ", via %s",
|
||||
ifindex2ifname(
|
||||
nexthop->ifindex,
|
||||
nexthop->vrf_id));
|
||||
break;
|
||||
case NEXTHOP_TYPE_IPV6:
|
||||
case NEXTHOP_TYPE_IPV6_IFINDEX:
|
||||
vty_out(vty, " %s",
|
||||
inet_ntop(AF_INET6, &nexthop->gate.ipv6,
|
||||
buf, sizeof(buf)));
|
||||
if (nexthop->ifindex)
|
||||
vty_out(vty, ", via %s",
|
||||
ifindex2ifname(
|
||||
nexthop->ifindex,
|
||||
nexthop->vrf_id));
|
||||
break;
|
||||
case NEXTHOP_TYPE_IFINDEX:
|
||||
vty_out(vty, " directly connected, %s",
|
||||
ifindex2ifname(nexthop->ifindex,
|
||||
nexthop->vrf_id));
|
||||
break;
|
||||
case NEXTHOP_TYPE_BLACKHOLE:
|
||||
vty_out(vty, " unreachable");
|
||||
switch (nexthop->bh_type) {
|
||||
case BLACKHOLE_REJECT:
|
||||
vty_out(vty, " (ICMP unreachable)");
|
||||
break;
|
||||
case BLACKHOLE_ADMINPROHIB:
|
||||
vty_out(vty,
|
||||
" (ICMP admin-prohibited)");
|
||||
break;
|
||||
case BLACKHOLE_NULL:
|
||||
vty_out(vty, " (blackhole)");
|
||||
break;
|
||||
case BLACKHOLE_UNSPEC:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if ((re->vrf_id != nexthop->vrf_id)
|
||||
&& (nexthop->type != NEXTHOP_TYPE_BLACKHOLE)) {
|
||||
struct vrf *vrf =
|
||||
vrf_lookup_by_id(nexthop->vrf_id);
|
||||
|
||||
if (vrf)
|
||||
vty_out(vty, "(vrf %s)", vrf->name);
|
||||
else
|
||||
vty_out(vty, "(vrf UNKNOWN)");
|
||||
}
|
||||
|
||||
if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_DUPLICATE))
|
||||
vty_out(vty, " (duplicate nexthop removed)");
|
||||
|
||||
if (!CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE))
|
||||
vty_out(vty, " inactive");
|
||||
|
||||
if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK))
|
||||
vty_out(vty, " onlink");
|
||||
|
||||
if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
|
||||
vty_out(vty, " (recursive)");
|
||||
|
||||
switch (nexthop->type) {
|
||||
case NEXTHOP_TYPE_IPV4:
|
||||
case NEXTHOP_TYPE_IPV4_IFINDEX:
|
||||
if (nexthop->src.ipv4.s_addr) {
|
||||
if (inet_ntop(AF_INET,
|
||||
&nexthop->src.ipv4,
|
||||
addrstr, sizeof(addrstr)))
|
||||
vty_out(vty, ", src %s",
|
||||
addrstr);
|
||||
}
|
||||
break;
|
||||
case NEXTHOP_TYPE_IPV6:
|
||||
case NEXTHOP_TYPE_IPV6_IFINDEX:
|
||||
if (!IPV6_ADDR_SAME(&nexthop->src.ipv6,
|
||||
&in6addr_any)) {
|
||||
if (inet_ntop(AF_INET6,
|
||||
&nexthop->src.ipv6,
|
||||
addrstr, sizeof(addrstr)))
|
||||
vty_out(vty, ", src %s",
|
||||
addrstr);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (re->nexthop_mtu)
|
||||
vty_out(vty, ", mtu %u", re->nexthop_mtu);
|
||||
|
||||
/* Label information */
|
||||
if (nexthop->nh_label
|
||||
&& nexthop->nh_label->num_labels) {
|
||||
vty_out(vty, ", label %s",
|
||||
mpls_label2str(
|
||||
nexthop->nh_label->num_labels,
|
||||
nexthop->nh_label->label, buf,
|
||||
sizeof(buf), 1));
|
||||
}
|
||||
|
||||
if (nexthop->weight)
|
||||
vty_out(vty, ", weight %u", nexthop->weight);
|
||||
|
||||
/* Use helper to format each nexthop */
|
||||
show_nexthop_detail_helper(vty, re, nexthop);
|
||||
vty_out(vty, "\n");
|
||||
|
||||
/* Include backup info, if present */
|
||||
if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_HAS_BACKUP))
|
||||
show_nh_backup_helper(vty, re->nhe, nexthop);
|
||||
}
|
||||
vty_out(vty, "\n");
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Helper for nexthop output, used in the 'show ip route' path
|
||||
*/
|
||||
static void show_route_nexthop_helper(struct vty *vty,
|
||||
const struct route_entry *re,
|
||||
const struct nexthop *nexthop)
|
||||
{
|
||||
char buf[MPLS_LABEL_STRLEN];
|
||||
|
||||
switch (nexthop->type) {
|
||||
case NEXTHOP_TYPE_IPV4:
|
||||
case NEXTHOP_TYPE_IPV4_IFINDEX:
|
||||
vty_out(vty, " via %s", inet_ntoa(nexthop->gate.ipv4));
|
||||
if (nexthop->ifindex)
|
||||
vty_out(vty, ", %s",
|
||||
ifindex2ifname(nexthop->ifindex,
|
||||
nexthop->vrf_id));
|
||||
break;
|
||||
case NEXTHOP_TYPE_IPV6:
|
||||
case NEXTHOP_TYPE_IPV6_IFINDEX:
|
||||
vty_out(vty, " via %s",
|
||||
inet_ntop(AF_INET6, &nexthop->gate.ipv6, buf,
|
||||
sizeof(buf)));
|
||||
if (nexthop->ifindex)
|
||||
vty_out(vty, ", %s",
|
||||
ifindex2ifname(nexthop->ifindex,
|
||||
nexthop->vrf_id));
|
||||
break;
|
||||
|
||||
case NEXTHOP_TYPE_IFINDEX:
|
||||
vty_out(vty, " is directly connected, %s",
|
||||
ifindex2ifname(nexthop->ifindex,
|
||||
nexthop->vrf_id));
|
||||
break;
|
||||
case NEXTHOP_TYPE_BLACKHOLE:
|
||||
vty_out(vty, " unreachable");
|
||||
switch (nexthop->bh_type) {
|
||||
case BLACKHOLE_REJECT:
|
||||
vty_out(vty, " (ICMP unreachable)");
|
||||
break;
|
||||
case BLACKHOLE_ADMINPROHIB:
|
||||
vty_out(vty, " (ICMP admin-prohibited)");
|
||||
break;
|
||||
case BLACKHOLE_NULL:
|
||||
vty_out(vty, " (blackhole)");
|
||||
break;
|
||||
case BLACKHOLE_UNSPEC:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if ((re == NULL || (nexthop->vrf_id != re->vrf_id)) &&
|
||||
(nexthop->type != NEXTHOP_TYPE_BLACKHOLE)) {
|
||||
struct vrf *vrf = vrf_lookup_by_id(nexthop->vrf_id);
|
||||
|
||||
if (vrf)
|
||||
vty_out(vty, " (vrf %s)", vrf->name);
|
||||
else
|
||||
vty_out(vty, " (vrf UNKNOWN)");
|
||||
}
|
||||
|
||||
if (!CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE))
|
||||
vty_out(vty, " inactive");
|
||||
|
||||
if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK))
|
||||
vty_out(vty, " onlink");
|
||||
|
||||
if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
|
||||
vty_out(vty, " (recursive)");
|
||||
|
||||
switch (nexthop->type) {
|
||||
case NEXTHOP_TYPE_IPV4:
|
||||
case NEXTHOP_TYPE_IPV4_IFINDEX:
|
||||
if (nexthop->src.ipv4.s_addr) {
|
||||
if (inet_ntop(AF_INET, &nexthop->src.ipv4, buf,
|
||||
sizeof(buf)))
|
||||
vty_out(vty, ", src %s", buf);
|
||||
}
|
||||
break;
|
||||
case NEXTHOP_TYPE_IPV6:
|
||||
case NEXTHOP_TYPE_IPV6_IFINDEX:
|
||||
if (!IPV6_ADDR_SAME(&nexthop->src.ipv6, &in6addr_any)) {
|
||||
if (inet_ntop(AF_INET6, &nexthop->src.ipv6, buf,
|
||||
sizeof(buf)))
|
||||
vty_out(vty, ", src %s", buf);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/* Label information */
|
||||
if (nexthop->nh_label && nexthop->nh_label->num_labels) {
|
||||
vty_out(vty, ", label %s",
|
||||
mpls_label2str(nexthop->nh_label->num_labels,
|
||||
nexthop->nh_label->label, buf,
|
||||
sizeof(buf), 1));
|
||||
}
|
||||
|
||||
if ((re == NULL) && nexthop->weight)
|
||||
vty_out(vty, ", weight %u", nexthop->weight);
|
||||
}
|
||||
|
||||
static void vty_show_ip_route(struct vty *vty, struct route_node *rn,
|
||||
struct route_entry *re, json_object *json,
|
||||
bool is_fib)
|
||||
@ -660,105 +800,43 @@ static void vty_show_ip_route(struct vty *vty, struct route_node *rn,
|
||||
len - 3 + (2 * nexthop_level(nexthop)), ' ');
|
||||
}
|
||||
|
||||
switch (nexthop->type) {
|
||||
case NEXTHOP_TYPE_IPV4:
|
||||
case NEXTHOP_TYPE_IPV4_IFINDEX:
|
||||
vty_out(vty, " via %s", inet_ntoa(nexthop->gate.ipv4));
|
||||
if (nexthop->ifindex)
|
||||
vty_out(vty, ", %s",
|
||||
ifindex2ifname(nexthop->ifindex,
|
||||
nexthop->vrf_id));
|
||||
break;
|
||||
case NEXTHOP_TYPE_IPV6:
|
||||
case NEXTHOP_TYPE_IPV6_IFINDEX:
|
||||
vty_out(vty, " via %s",
|
||||
inet_ntop(AF_INET6, &nexthop->gate.ipv6, buf,
|
||||
sizeof(buf)));
|
||||
if (nexthop->ifindex)
|
||||
vty_out(vty, ", %s",
|
||||
ifindex2ifname(nexthop->ifindex,
|
||||
nexthop->vrf_id));
|
||||
break;
|
||||
|
||||
case NEXTHOP_TYPE_IFINDEX:
|
||||
vty_out(vty, " is directly connected, %s",
|
||||
ifindex2ifname(nexthop->ifindex,
|
||||
nexthop->vrf_id));
|
||||
break;
|
||||
case NEXTHOP_TYPE_BLACKHOLE:
|
||||
vty_out(vty, " unreachable");
|
||||
switch (nexthop->bh_type) {
|
||||
case BLACKHOLE_REJECT:
|
||||
vty_out(vty, " (ICMP unreachable)");
|
||||
break;
|
||||
case BLACKHOLE_ADMINPROHIB:
|
||||
vty_out(vty, " (ICMP admin-prohibited)");
|
||||
break;
|
||||
case BLACKHOLE_NULL:
|
||||
vty_out(vty, " (blackhole)");
|
||||
break;
|
||||
case BLACKHOLE_UNSPEC:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if ((nexthop->vrf_id != re->vrf_id)
|
||||
&& (nexthop->type != NEXTHOP_TYPE_BLACKHOLE)) {
|
||||
struct vrf *vrf = vrf_lookup_by_id(nexthop->vrf_id);
|
||||
|
||||
if (vrf)
|
||||
vty_out(vty, "(vrf %s)", vrf->name);
|
||||
else
|
||||
vty_out(vty, "(vrf UNKNOWN)");
|
||||
}
|
||||
|
||||
if (!CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE))
|
||||
vty_out(vty, " inactive");
|
||||
|
||||
if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK))
|
||||
vty_out(vty, " onlink");
|
||||
|
||||
if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
|
||||
vty_out(vty, " (recursive)");
|
||||
|
||||
switch (nexthop->type) {
|
||||
case NEXTHOP_TYPE_IPV4:
|
||||
case NEXTHOP_TYPE_IPV4_IFINDEX:
|
||||
if (nexthop->src.ipv4.s_addr) {
|
||||
if (inet_ntop(AF_INET, &nexthop->src.ipv4, buf,
|
||||
sizeof(buf)))
|
||||
vty_out(vty, ", src %s", buf);
|
||||
}
|
||||
break;
|
||||
case NEXTHOP_TYPE_IPV6:
|
||||
case NEXTHOP_TYPE_IPV6_IFINDEX:
|
||||
if (!IPV6_ADDR_SAME(&nexthop->src.ipv6, &in6addr_any)) {
|
||||
if (inet_ntop(AF_INET6, &nexthop->src.ipv6, buf,
|
||||
sizeof(buf)))
|
||||
vty_out(vty, ", src %s", buf);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/* Label information */
|
||||
if (nexthop->nh_label && nexthop->nh_label->num_labels) {
|
||||
vty_out(vty, ", label %s",
|
||||
mpls_label2str(nexthop->nh_label->num_labels,
|
||||
nexthop->nh_label->label, buf,
|
||||
sizeof(buf), 1));
|
||||
}
|
||||
show_route_nexthop_helper(vty, re, nexthop);
|
||||
|
||||
vty_out(vty, ", %s\n", up_str);
|
||||
|
||||
/* Check for backup info */
|
||||
if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_HAS_BACKUP)) {
|
||||
struct nexthop *backup;
|
||||
int i;
|
||||
|
||||
if (re->nhe->backup_info == NULL ||
|
||||
re->nhe->backup_info->nhe == NULL)
|
||||
continue;
|
||||
|
||||
i = 0;
|
||||
for (ALL_NEXTHOPS(re->nhe->backup_info->nhe->nhg,
|
||||
backup)) {
|
||||
if (i == nexthop->backup_idx)
|
||||
break;
|
||||
i++;
|
||||
}
|
||||
|
||||
/* Print useful backup info */
|
||||
if (backup) {
|
||||
/* TODO -- install state is not accurate */
|
||||
vty_out(vty, " %*c [backup %d]",
|
||||
/*re_status_output_char(re, backup),*/
|
||||
len - 3 + (2 * nexthop_level(nexthop)),
|
||||
' ', nexthop->backup_idx);
|
||||
show_route_nexthop_helper(vty, re, backup);
|
||||
vty_out(vty, "\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void vty_show_ip_route_detail_json(struct vty *vty,
|
||||
struct route_node *rn, bool use_fib)
|
||||
struct route_node *rn, bool use_fib)
|
||||
{
|
||||
json_object *json = NULL;
|
||||
json_object *json_prefix = NULL;
|
||||
@ -1028,9 +1106,8 @@ static void show_nexthop_group_out(struct vty *vty, struct nhg_hash_entry *nhe)
|
||||
{
|
||||
struct nexthop *nexthop = NULL;
|
||||
struct nhg_connected *rb_node_dep = NULL;
|
||||
char buf[SRCDEST2STR_BUFFER];
|
||||
|
||||
struct vrf *nhe_vrf = vrf_lookup_by_id(nhe->vrf_id);
|
||||
struct nexthop_group *backup_nhg;
|
||||
|
||||
vty_out(vty, "ID: %u\n", nhe->id);
|
||||
vty_out(vty, " RefCnt: %d\n", nhe->refcnt);
|
||||
@ -1062,6 +1139,7 @@ static void show_nexthop_group_out(struct vty *vty, struct nhg_hash_entry *nhe)
|
||||
vty_out(vty, "\n");
|
||||
}
|
||||
|
||||
/* Output nexthops */
|
||||
for (ALL_NEXTHOPS(nhe->nhg, nexthop)) {
|
||||
if (!CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
|
||||
vty_out(vty, " ");
|
||||
@ -1069,102 +1147,58 @@ static void show_nexthop_group_out(struct vty *vty, struct nhg_hash_entry *nhe)
|
||||
/* Make recursive nexthops a bit more clear */
|
||||
vty_out(vty, " ");
|
||||
|
||||
switch (nexthop->type) {
|
||||
case NEXTHOP_TYPE_IPV4:
|
||||
case NEXTHOP_TYPE_IPV4_IFINDEX:
|
||||
vty_out(vty, " %s", inet_ntoa(nexthop->gate.ipv4));
|
||||
if (nexthop->ifindex)
|
||||
vty_out(vty, ", %s",
|
||||
ifindex2ifname(nexthop->ifindex,
|
||||
nexthop->vrf_id));
|
||||
break;
|
||||
case NEXTHOP_TYPE_IPV6:
|
||||
case NEXTHOP_TYPE_IPV6_IFINDEX:
|
||||
vty_out(vty, " %s",
|
||||
inet_ntop(AF_INET6, &nexthop->gate.ipv6, buf,
|
||||
sizeof(buf)));
|
||||
if (nexthop->ifindex)
|
||||
vty_out(vty, ", %s",
|
||||
ifindex2ifname(nexthop->ifindex,
|
||||
nexthop->vrf_id));
|
||||
break;
|
||||
show_route_nexthop_helper(vty, NULL, nexthop);
|
||||
|
||||
case NEXTHOP_TYPE_IFINDEX:
|
||||
vty_out(vty, " directly connected %s",
|
||||
ifindex2ifname(nexthop->ifindex,
|
||||
nexthop->vrf_id));
|
||||
break;
|
||||
case NEXTHOP_TYPE_BLACKHOLE:
|
||||
vty_out(vty, " unreachable");
|
||||
switch (nexthop->bh_type) {
|
||||
case BLACKHOLE_REJECT:
|
||||
vty_out(vty, " (ICMP unreachable)");
|
||||
break;
|
||||
case BLACKHOLE_ADMINPROHIB:
|
||||
vty_out(vty, " (ICMP admin-prohibited)");
|
||||
break;
|
||||
case BLACKHOLE_NULL:
|
||||
vty_out(vty, " (blackhole)");
|
||||
break;
|
||||
case BLACKHOLE_UNSPEC:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
if (nhe->backup_info == NULL || nhe->backup_info->nhe == NULL) {
|
||||
if (CHECK_FLAG(nexthop->flags,
|
||||
NEXTHOP_FLAG_HAS_BACKUP))
|
||||
vty_out(vty, " [backup %d]",
|
||||
nexthop->backup_idx);
|
||||
|
||||
vty_out(vty, "\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
struct vrf *vrf = vrf_lookup_by_id(nexthop->vrf_id);
|
||||
/* TODO -- print more useful backup info */
|
||||
if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_HAS_BACKUP)) {
|
||||
struct nexthop *backup;
|
||||
int i;
|
||||
|
||||
if (vrf)
|
||||
vty_out(vty, " (vrf %s)", vrf->name);
|
||||
else
|
||||
vty_out(vty, " (vrf UNKNOWN)");
|
||||
|
||||
if (!CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE))
|
||||
vty_out(vty, " inactive");
|
||||
|
||||
if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK))
|
||||
vty_out(vty, " onlink");
|
||||
|
||||
if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
|
||||
vty_out(vty, " (recursive)");
|
||||
|
||||
switch (nexthop->type) {
|
||||
case NEXTHOP_TYPE_IPV4:
|
||||
case NEXTHOP_TYPE_IPV4_IFINDEX:
|
||||
if (nexthop->src.ipv4.s_addr) {
|
||||
if (inet_ntop(AF_INET, &nexthop->src.ipv4, buf,
|
||||
sizeof(buf)))
|
||||
vty_out(vty, ", src %s", buf);
|
||||
i = 0;
|
||||
for (ALL_NEXTHOPS(nhe->backup_info->nhe->nhg, backup)) {
|
||||
if (i == nexthop->backup_idx)
|
||||
break;
|
||||
i++;
|
||||
}
|
||||
break;
|
||||
case NEXTHOP_TYPE_IPV6:
|
||||
case NEXTHOP_TYPE_IPV6_IFINDEX:
|
||||
if (!IPV6_ADDR_SAME(&nexthop->src.ipv6, &in6addr_any)) {
|
||||
if (inet_ntop(AF_INET6, &nexthop->src.ipv6, buf,
|
||||
sizeof(buf)))
|
||||
vty_out(vty, ", src %s", buf);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/* Label information */
|
||||
if (nexthop->nh_label && nexthop->nh_label->num_labels) {
|
||||
vty_out(vty, ", label %s",
|
||||
mpls_label2str(nexthop->nh_label->num_labels,
|
||||
nexthop->nh_label->label, buf,
|
||||
sizeof(buf), 1));
|
||||
/* TODO */
|
||||
if (backup)
|
||||
vty_out(vty, " [backup %d]",
|
||||
nexthop->backup_idx);
|
||||
else
|
||||
vty_out(vty, " [backup INVALID]");
|
||||
}
|
||||
|
||||
if (nexthop->weight)
|
||||
vty_out(vty, ", weight %u", nexthop->weight);
|
||||
|
||||
vty_out(vty, "\n");
|
||||
}
|
||||
|
||||
/* Output backup nexthops (if any) */
|
||||
backup_nhg = zebra_nhg_get_backup_nhg(nhe);
|
||||
if (backup_nhg) {
|
||||
vty_out(vty, " Backups:\n");
|
||||
|
||||
for (ALL_NEXTHOPS_PTR(backup_nhg, nexthop)) {
|
||||
if (!CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
|
||||
vty_out(vty, " ");
|
||||
else
|
||||
/* Make recursive nexthops a bit more clear */
|
||||
vty_out(vty, " ");
|
||||
|
||||
show_route_nexthop_helper(vty, NULL, nexthop);
|
||||
vty_out(vty, "\n");
|
||||
}
|
||||
}
|
||||
|
||||
if (!zebra_nhg_dependents_is_empty(nhe)) {
|
||||
vty_out(vty, " Dependents:");
|
||||
frr_each(nhg_connected_tree, &nhe->nhg_dependents,
|
||||
|
||||
@ -121,11 +121,11 @@ static struct interface *zvni_map_to_macvlan(struct interface *br_if,
|
||||
|
||||
/* l3-vni next-hop neigh related APIs */
|
||||
static zebra_neigh_t *zl3vni_nh_lookup(zebra_l3vni_t *zl3vni,
|
||||
struct ipaddr *ip);
|
||||
const struct ipaddr *ip);
|
||||
static void *zl3vni_nh_alloc(void *p);
|
||||
static zebra_neigh_t *zl3vni_nh_add(zebra_l3vni_t *zl3vni,
|
||||
struct ipaddr *vtep_ip,
|
||||
struct ethaddr *rmac);
|
||||
const struct ipaddr *vtep_ip,
|
||||
const struct ethaddr *rmac);
|
||||
static int zl3vni_nh_del(zebra_l3vni_t *zl3vni, zebra_neigh_t *n);
|
||||
static int zl3vni_nh_install(zebra_l3vni_t *zl3vni, zebra_neigh_t *n);
|
||||
static int zl3vni_nh_uninstall(zebra_l3vni_t *zl3vni, zebra_neigh_t *n);
|
||||
@ -133,10 +133,10 @@ static int zl3vni_nh_uninstall(zebra_l3vni_t *zl3vni, zebra_neigh_t *n);
|
||||
/* l3-vni rmac related APIs */
|
||||
static void zl3vni_print_rmac_hash(struct hash_bucket *, void *);
|
||||
static zebra_mac_t *zl3vni_rmac_lookup(zebra_l3vni_t *zl3vni,
|
||||
struct ethaddr *rmac);
|
||||
const struct ethaddr *rmac);
|
||||
static void *zl3vni_rmac_alloc(void *p);
|
||||
static zebra_mac_t *zl3vni_rmac_add(zebra_l3vni_t *zl3vni,
|
||||
struct ethaddr *rmac);
|
||||
const struct ethaddr *rmac);
|
||||
static int zl3vni_rmac_del(zebra_l3vni_t *zl3vni, zebra_mac_t *zrmac);
|
||||
static int zl3vni_rmac_install(zebra_l3vni_t *zl3vni, zebra_mac_t *zrmac);
|
||||
static int zl3vni_rmac_uninstall(zebra_l3vni_t *zl3vni, zebra_mac_t *zrmac);
|
||||
@ -4434,7 +4434,7 @@ static void zl3vni_cleanup_all(struct hash_bucket *bucket, void *args)
|
||||
}
|
||||
|
||||
static void rb_find_or_add_host(struct host_rb_tree_entry *hrbe,
|
||||
struct prefix *host)
|
||||
const struct prefix *host)
|
||||
{
|
||||
struct host_rb_entry lookup;
|
||||
struct host_rb_entry *hle;
|
||||
@ -4473,7 +4473,7 @@ static void rb_delete_host(struct host_rb_tree_entry *hrbe, struct prefix *host)
|
||||
* Look up MAC hash entry.
|
||||
*/
|
||||
static zebra_mac_t *zl3vni_rmac_lookup(zebra_l3vni_t *zl3vni,
|
||||
struct ethaddr *rmac)
|
||||
const struct ethaddr *rmac)
|
||||
{
|
||||
zebra_mac_t tmp;
|
||||
zebra_mac_t *pmac;
|
||||
@ -4502,7 +4502,8 @@ static void *zl3vni_rmac_alloc(void *p)
|
||||
/*
|
||||
* Add RMAC entry to l3-vni
|
||||
*/
|
||||
static zebra_mac_t *zl3vni_rmac_add(zebra_l3vni_t *zl3vni, struct ethaddr *rmac)
|
||||
static zebra_mac_t *zl3vni_rmac_add(zebra_l3vni_t *zl3vni,
|
||||
const struct ethaddr *rmac)
|
||||
{
|
||||
zebra_mac_t tmp_rmac;
|
||||
zebra_mac_t *zrmac = NULL;
|
||||
@ -4632,9 +4633,10 @@ static int zl3vni_rmac_uninstall(zebra_l3vni_t *zl3vni, zebra_mac_t *zrmac)
|
||||
}
|
||||
|
||||
/* handle rmac add */
|
||||
static int zl3vni_remote_rmac_add(zebra_l3vni_t *zl3vni, struct ethaddr *rmac,
|
||||
struct ipaddr *vtep_ip,
|
||||
struct prefix *host_prefix)
|
||||
static int zl3vni_remote_rmac_add(zebra_l3vni_t *zl3vni,
|
||||
const struct ethaddr *rmac,
|
||||
const struct ipaddr *vtep_ip,
|
||||
const struct prefix *host_prefix)
|
||||
{
|
||||
char buf[ETHER_ADDR_STRLEN];
|
||||
char buf1[INET6_ADDRSTRLEN];
|
||||
@ -4709,7 +4711,8 @@ static void zl3vni_remote_rmac_del(zebra_l3vni_t *zl3vni, zebra_mac_t *zrmac,
|
||||
/*
|
||||
* Look up nh hash entry on a l3-vni.
|
||||
*/
|
||||
static zebra_neigh_t *zl3vni_nh_lookup(zebra_l3vni_t *zl3vni, struct ipaddr *ip)
|
||||
static zebra_neigh_t *zl3vni_nh_lookup(zebra_l3vni_t *zl3vni,
|
||||
const struct ipaddr *ip)
|
||||
{
|
||||
zebra_neigh_t tmp;
|
||||
zebra_neigh_t *n;
|
||||
@ -4739,8 +4742,9 @@ static void *zl3vni_nh_alloc(void *p)
|
||||
/*
|
||||
* Add neighbor entry.
|
||||
*/
|
||||
static zebra_neigh_t *zl3vni_nh_add(zebra_l3vni_t *zl3vni, struct ipaddr *ip,
|
||||
struct ethaddr *mac)
|
||||
static zebra_neigh_t *zl3vni_nh_add(zebra_l3vni_t *zl3vni,
|
||||
const struct ipaddr *ip,
|
||||
const struct ethaddr *mac)
|
||||
{
|
||||
zebra_neigh_t tmp_n;
|
||||
zebra_neigh_t *n = NULL;
|
||||
@ -4822,9 +4826,10 @@ static int zl3vni_nh_uninstall(zebra_l3vni_t *zl3vni, zebra_neigh_t *n)
|
||||
}
|
||||
|
||||
/* add remote vtep as a neigh entry */
|
||||
static int zl3vni_remote_nh_add(zebra_l3vni_t *zl3vni, struct ipaddr *vtep_ip,
|
||||
struct ethaddr *rmac,
|
||||
struct prefix *host_prefix)
|
||||
static int zl3vni_remote_nh_add(zebra_l3vni_t *zl3vni,
|
||||
const struct ipaddr *vtep_ip,
|
||||
const struct ethaddr *rmac,
|
||||
const struct prefix *host_prefix)
|
||||
{
|
||||
char buf[ETHER_ADDR_STRLEN];
|
||||
char buf1[ETHER_ADDR_STRLEN];
|
||||
@ -5960,9 +5965,9 @@ int is_l3vni_for_prefix_routes_only(vni_t vni)
|
||||
}
|
||||
|
||||
/* handle evpn route in vrf table */
|
||||
void zebra_vxlan_evpn_vrf_route_add(vrf_id_t vrf_id, struct ethaddr *rmac,
|
||||
struct ipaddr *vtep_ip,
|
||||
struct prefix *host_prefix)
|
||||
void zebra_vxlan_evpn_vrf_route_add(vrf_id_t vrf_id, const struct ethaddr *rmac,
|
||||
const struct ipaddr *vtep_ip,
|
||||
const struct prefix *host_prefix)
|
||||
{
|
||||
zebra_l3vni_t *zl3vni = NULL;
|
||||
struct ipaddr ipv4_vtep;
|
||||
|
||||
@ -199,9 +199,9 @@ extern void zebra_vxlan_cleanup_tables(struct zebra_vrf *);
|
||||
extern void zebra_vxlan_init(void);
|
||||
extern void zebra_vxlan_disable(void);
|
||||
extern void zebra_vxlan_evpn_vrf_route_add(vrf_id_t vrf_id,
|
||||
struct ethaddr *rmac,
|
||||
struct ipaddr *ip,
|
||||
struct prefix *host_prefix);
|
||||
const struct ethaddr *rmac,
|
||||
const struct ipaddr *ip,
|
||||
const struct prefix *host_prefix);
|
||||
extern void zebra_vxlan_evpn_vrf_route_del(vrf_id_t vrf_id,
|
||||
struct ipaddr *vtep_ip,
|
||||
struct prefix *host_prefix);
|
||||
|
||||
Loading…
Reference in New Issue
Block a user