Merge pull request #5901 from mjstapp/backup_nh_prep

zebra, lib: Backup nexthop (path) prep work
This commit is contained in:
Stephen Worley 2020-03-30 10:26:17 -04:00 committed by GitHub
commit ff82bbbb91
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
26 changed files with 1938 additions and 777 deletions

View File

@ -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));

View File

@ -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];

View File

@ -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

View File

@ -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(&copy->gate, &nexthop->gate, sizeof(nexthop->gate));
memcpy(&copy->src, &nexthop->src, sizeof(nexthop->src));
memcpy(&copy->rmap_src, &nexthop->rmap_src, sizeof(nexthop->rmap_src));

View File

@ -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 *);
/*

View File

@ -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));

View File

@ -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;

View File

@ -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
*/

View File

@ -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);

View File

@ -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;

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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);

View File

@ -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,

View File

@ -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;
}

View File

@ -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) {

View File

@ -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 */
}

View File

@ -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);

View File

@ -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)

View File

@ -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

View File

@ -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);

View File

@ -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. */

View File

@ -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,

View File

@ -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;

View File

@ -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);