2019-05-13 21:46:05 +02:00
|
|
|
/* Zebra Nexthop Group Code.
|
|
|
|
* Copyright (C) 2019 Cumulus Networks, Inc.
|
|
|
|
* Donald Sharp
|
|
|
|
* Stephen Worley
|
|
|
|
*
|
|
|
|
* This file is part of FRR.
|
|
|
|
*
|
|
|
|
* FRR is free software; you can redistribute it and/or modify it
|
|
|
|
* under the terms of the GNU General Public License as published by the
|
|
|
|
* Free Software Foundation; either version 2, or (at your option) any
|
|
|
|
* later version.
|
|
|
|
*
|
|
|
|
* FRR is distributed in the hope that it will be useful, but
|
|
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
* General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with FRR; see the file COPYING. If not, write to the Free
|
|
|
|
* Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
|
|
|
* 02111-1307, USA.
|
|
|
|
*/
|
|
|
|
#include <zebra.h>
|
|
|
|
|
|
|
|
#include "lib/nexthop.h"
|
2019-06-24 20:04:13 +02:00
|
|
|
#include "lib/nexthop_group_private.h"
|
2019-05-13 21:46:05 +02:00
|
|
|
#include "lib/routemap.h"
|
zebra: Append rparent labels when resolving nexthop
When resolving a nexthop, append its labels to the one its
resolving to along with the labels that may already be present there.
Before we were ignoring labels if the resolving level was greater than
two.
Before:
```
S> 2.2.2.2/32 [1/0] via 7.7.7.7 (recursive), label 2222, 00:00:07
* via 7.7.7.7, dummy1 onlink, label 1111, 00:00:07
S> 3.3.3.3/32 [1/0] via 2.2.2.2 (recursive), label 3333, 00:00:04
* via 7.7.7.7, dummy1 onlink, label 1111, 00:00:04
K>* 7.7.7.7/32 [0/0] is directly connected, dummy1, label 1111, 00:00:17
C>* 192.168.122.0/24 is directly connected, ens3, 00:00:17
K>* 192.168.122.1/32 [0/100] is directly connected, ens3, 00:00:17
ubuntu_nh#
```
This patch:
```
S> 2.2.2.2/32 [1/0] via 7.7.7.7 (recursive), label 2222, 00:00:04
* via 7.7.7.7, dummy1 onlink, label 1111/2222, 00:00:04
S> 3.3.3.3/32 [1/0] via 2.2.2.2 (recursive), label 3333, 00:00:02
* via 7.7.7.7, dummy1 onlink, label 1111/2222/3333, 00:00:02
K>* 7.7.7.7/32 [0/0] is directly connected, dummy1, label 1111, 00:00:11
C>* 192.168.122.0/24 is directly connected, ens3, 00:00:11
K>* 192.168.122.1/32 [0/100] is directly connected, ens3, 00:00:11
ubuntu_nh#
```
Signed-off-by: Stephen Worley <sworley@cumulusnetworks.com>
2019-08-08 00:40:36 +02:00
|
|
|
#include "lib/mpls.h"
|
2019-01-24 14:06:34 +01:00
|
|
|
#include "lib/jhash.h"
|
2019-03-15 17:23:51 +01:00
|
|
|
#include "lib/debug.h"
|
2019-05-13 21:46:05 +02:00
|
|
|
|
|
|
|
#include "zebra/connected.h"
|
|
|
|
#include "zebra/debug.h"
|
|
|
|
#include "zebra/zebra_router.h"
|
|
|
|
#include "zebra/zebra_nhg.h"
|
|
|
|
#include "zebra/zebra_rnh.h"
|
|
|
|
#include "zebra/zebra_routemap.h"
|
2019-03-15 17:23:51 +01:00
|
|
|
#include "zebra/zebra_memory.h"
|
|
|
|
#include "zebra/zserv.h"
|
2019-05-13 21:46:05 +02:00
|
|
|
#include "zebra/rt.h"
|
2019-02-26 00:18:07 +01:00
|
|
|
#include "zebra_errors.h"
|
2019-05-14 02:10:34 +02:00
|
|
|
#include "zebra_dplane.h"
|
2019-02-26 00:18:07 +01:00
|
|
|
|
2019-03-15 17:23:51 +01:00
|
|
|
DEFINE_MTYPE_STATIC(ZEBRA, NHG, "Nexthop Group Entry");
|
2019-05-14 03:13:02 +02:00
|
|
|
DEFINE_MTYPE_STATIC(ZEBRA, NHG_CONNECTED, "Nexthop Group Connected");
|
2019-05-14 02:10:34 +02:00
|
|
|
|
2019-05-14 03:13:02 +02:00
|
|
|
static int zebra_nhg_connected_cmp(const struct nhg_connected *dep1,
|
|
|
|
const struct nhg_connected *dep2);
|
2019-05-14 02:10:34 +02:00
|
|
|
|
2019-05-14 03:13:02 +02:00
|
|
|
RB_GENERATE(nhg_connected_head, nhg_connected, nhg_entry,
|
|
|
|
zebra_nhg_connected_cmp);
|
2019-05-14 02:10:34 +02:00
|
|
|
|
2019-05-14 03:13:02 +02:00
|
|
|
static void nhg_connected_free(struct nhg_connected *dep)
|
2019-05-14 02:10:34 +02:00
|
|
|
{
|
2019-05-14 03:13:02 +02:00
|
|
|
XFREE(MTYPE_NHG_CONNECTED, dep);
|
2019-05-14 02:10:34 +02:00
|
|
|
}
|
|
|
|
|
2019-05-14 03:13:02 +02:00
|
|
|
static struct nhg_connected *nhg_connected_new(struct nhg_hash_entry *nhe)
|
2019-05-14 02:10:34 +02:00
|
|
|
{
|
2019-05-14 03:13:02 +02:00
|
|
|
struct nhg_connected *new = NULL;
|
2019-05-14 02:10:34 +02:00
|
|
|
|
2019-05-14 03:13:02 +02:00
|
|
|
new = XCALLOC(MTYPE_NHG_CONNECTED, sizeof(struct nhg_connected));
|
2019-05-14 02:10:34 +02:00
|
|
|
new->nhe = nhe;
|
|
|
|
|
|
|
|
return new;
|
|
|
|
}
|
|
|
|
|
2019-05-14 03:13:02 +02:00
|
|
|
static uint8_t zebra_nhg_connected_count(const struct nhg_connected_head *head)
|
2019-05-14 02:10:34 +02:00
|
|
|
{
|
2019-05-14 03:13:02 +02:00
|
|
|
struct nhg_connected *rb_node_dep = NULL;
|
2019-05-14 02:10:34 +02:00
|
|
|
uint8_t i = 0;
|
|
|
|
|
2019-05-14 03:13:02 +02:00
|
|
|
RB_FOREACH (rb_node_dep, nhg_connected_head, head) {
|
2019-05-14 02:10:34 +02:00
|
|
|
i++;
|
|
|
|
}
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint8_t zebra_nhg_depends_count(const struct nhg_hash_entry *nhe)
|
|
|
|
{
|
2019-05-14 03:13:02 +02:00
|
|
|
return zebra_nhg_connected_count(&nhe->nhg_depends);
|
2019-05-14 02:10:34 +02:00
|
|
|
}
|
|
|
|
|
2019-05-14 03:13:02 +02:00
|
|
|
static bool
|
|
|
|
zebra_nhg_connected_head_is_empty(const struct nhg_connected_head *head)
|
2019-05-14 02:10:34 +02:00
|
|
|
{
|
2019-05-14 03:13:02 +02:00
|
|
|
return RB_EMPTY(nhg_connected_head, head);
|
2019-05-14 02:10:34 +02:00
|
|
|
}
|
2019-03-21 15:43:16 +01:00
|
|
|
|
2019-05-14 02:10:34 +02:00
|
|
|
bool zebra_nhg_depends_is_empty(const struct nhg_hash_entry *nhe)
|
2019-03-21 15:43:16 +01:00
|
|
|
{
|
2019-05-14 03:13:02 +02:00
|
|
|
return zebra_nhg_connected_head_is_empty(&nhe->nhg_depends);
|
2019-05-14 02:10:34 +02:00
|
|
|
}
|
|
|
|
|
2019-05-14 03:13:02 +02:00
|
|
|
void zebra_nhg_connected_head_del(struct nhg_connected_head *head,
|
|
|
|
struct nhg_hash_entry *depend)
|
2019-05-14 02:10:34 +02:00
|
|
|
{
|
2019-05-14 03:13:02 +02:00
|
|
|
struct nhg_connected lookup = {};
|
|
|
|
struct nhg_connected *removed = NULL;
|
2019-05-14 02:10:34 +02:00
|
|
|
|
|
|
|
lookup.nhe = depend;
|
2019-03-21 15:43:16 +01:00
|
|
|
|
2019-05-14 03:13:02 +02:00
|
|
|
removed = RB_REMOVE(nhg_connected_head, head, &lookup);
|
2019-03-21 15:43:16 +01:00
|
|
|
|
2019-05-14 03:13:02 +02:00
|
|
|
nhg_connected_free(removed);
|
2019-03-21 15:43:16 +01:00
|
|
|
}
|
|
|
|
|
2019-05-14 03:13:02 +02:00
|
|
|
void zebra_nhg_connected_head_add(struct nhg_connected_head *head,
|
|
|
|
struct nhg_hash_entry *depend)
|
2019-03-21 15:43:16 +01:00
|
|
|
{
|
2019-05-14 03:13:02 +02:00
|
|
|
struct nhg_connected *new = NULL;
|
2019-05-14 02:10:34 +02:00
|
|
|
|
2019-05-14 03:13:02 +02:00
|
|
|
new = nhg_connected_new(depend);
|
2019-05-14 02:10:34 +02:00
|
|
|
|
2019-05-14 03:13:02 +02:00
|
|
|
RB_INSERT(nhg_connected_head, head, new);
|
2019-03-21 15:43:16 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2019-05-14 03:13:02 +02:00
|
|
|
* zebra_nhg_dependents_del() - Delete a dependent from the nhg_hash_entry
|
|
|
|
*
|
|
|
|
* @from: Nexthop group hash entry we are deleting from
|
|
|
|
* @dependent: Dependent we are deleting
|
|
|
|
*/
|
|
|
|
void zebra_nhg_dependents_del(struct nhg_hash_entry *from,
|
|
|
|
struct nhg_hash_entry *dependent)
|
|
|
|
{
|
|
|
|
zebra_nhg_connected_head_del(&from->nhg_dependents, dependent);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* zebra_nhg_dependents_add() - Add a new dependent to the nhg_hash_entry
|
|
|
|
*
|
|
|
|
* @to: Nexthop group hash entry we are adding to
|
|
|
|
* @dependent: Dependent we are adding
|
|
|
|
*/
|
|
|
|
void zebra_nhg_dependents_add(struct nhg_hash_entry *to,
|
|
|
|
struct nhg_hash_entry *dependent)
|
|
|
|
{
|
|
|
|
zebra_nhg_connected_head_add(&to->nhg_dependents, dependent);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* zebra_nhg_depends_del() - Delete a dependency from the nhg_hash_entry
|
2019-05-14 02:10:34 +02:00
|
|
|
*
|
|
|
|
* @from: Nexthop group hash entry we are deleting from
|
|
|
|
* @depend: Dependency we are deleting
|
2019-03-21 15:43:16 +01:00
|
|
|
*/
|
2019-05-14 02:10:34 +02:00
|
|
|
void zebra_nhg_depends_del(struct nhg_hash_entry *from,
|
|
|
|
struct nhg_hash_entry *depend)
|
2019-03-21 15:43:16 +01:00
|
|
|
{
|
2019-05-14 03:13:02 +02:00
|
|
|
zebra_nhg_connected_head_del(&from->nhg_depends, depend);
|
|
|
|
|
|
|
|
/* Delete from the dependent tree */
|
|
|
|
zebra_nhg_dependents_del(depend, from);
|
2019-03-21 15:43:16 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2019-05-14 02:10:34 +02:00
|
|
|
* zebra_nhg_depends_add() - Add a new dependency to the nhg_hash_entry
|
2019-03-21 15:43:16 +01:00
|
|
|
*
|
2019-05-14 02:10:34 +02:00
|
|
|
* @to: Nexthop group hash entry we are adding to
|
|
|
|
* @depend: Dependency we are adding
|
2019-03-21 15:43:16 +01:00
|
|
|
*/
|
2019-05-14 02:10:34 +02:00
|
|
|
void zebra_nhg_depends_add(struct nhg_hash_entry *to,
|
|
|
|
struct nhg_hash_entry *depend)
|
2019-03-21 15:43:16 +01:00
|
|
|
{
|
2019-05-14 03:13:02 +02:00
|
|
|
zebra_nhg_connected_head_add(&to->nhg_depends, depend);
|
2019-03-21 15:43:16 +01:00
|
|
|
}
|
|
|
|
|
2019-05-14 03:13:02 +02:00
|
|
|
void zebra_nhg_connected_head_init(struct nhg_connected_head *head)
|
2019-03-27 00:28:23 +01:00
|
|
|
{
|
2019-05-14 03:13:02 +02:00
|
|
|
RB_INIT(nhg_connected_head, head);
|
2019-03-27 00:28:23 +01:00
|
|
|
}
|
|
|
|
|
2019-03-29 15:55:10 +01:00
|
|
|
/**
|
2019-05-14 02:10:34 +02:00
|
|
|
* zebra_nhg_depends_init() - Initialize tree for nhg dependencies
|
2019-03-29 15:55:10 +01:00
|
|
|
*
|
2019-05-14 02:10:34 +02:00
|
|
|
* @nhe: Nexthop group hash entry
|
2019-03-29 15:55:10 +01:00
|
|
|
*/
|
2019-05-14 02:10:34 +02:00
|
|
|
void zebra_nhg_depends_init(struct nhg_hash_entry *nhe)
|
2019-03-29 15:55:10 +01:00
|
|
|
{
|
2019-05-14 03:13:02 +02:00
|
|
|
zebra_nhg_connected_head_init(&nhe->nhg_depends);
|
2019-03-29 15:55:10 +01:00
|
|
|
}
|
|
|
|
|
2019-05-14 02:10:34 +02:00
|
|
|
|
2019-03-29 15:56:52 +01:00
|
|
|
/**
|
|
|
|
* zebra_nhg_depends_equal() - Are the dependencies of these nhe's equal
|
|
|
|
*
|
|
|
|
* @nhe1: Nexthop group hash entry
|
|
|
|
* @nhe2: Nexthop group hash entry
|
|
|
|
*
|
|
|
|
* Return: True if equal
|
|
|
|
*
|
|
|
|
* We don't care about ordering of the dependencies. If they contain
|
|
|
|
* the same nhe ID's, they are equivalent.
|
|
|
|
*/
|
|
|
|
static bool zebra_nhg_depends_equal(const struct nhg_hash_entry *nhe1,
|
|
|
|
const struct nhg_hash_entry *nhe2)
|
|
|
|
{
|
2019-05-14 03:13:02 +02:00
|
|
|
struct nhg_connected *rb_node_dep = NULL;
|
2019-03-29 15:56:52 +01:00
|
|
|
|
2019-05-14 02:10:34 +02:00
|
|
|
if (zebra_nhg_depends_is_empty(nhe1)
|
|
|
|
&& zebra_nhg_depends_is_empty(nhe2))
|
2019-03-29 15:56:52 +01:00
|
|
|
return true;
|
|
|
|
|
2019-05-14 02:10:34 +02:00
|
|
|
if ((zebra_nhg_depends_is_empty(nhe1)
|
|
|
|
&& !zebra_nhg_depends_is_empty(nhe2))
|
|
|
|
|| (zebra_nhg_depends_is_empty(nhe2)
|
|
|
|
&& !zebra_nhg_depends_is_empty(nhe1)))
|
2019-03-29 15:56:52 +01:00
|
|
|
return false;
|
|
|
|
|
2019-05-14 03:13:02 +02:00
|
|
|
RB_FOREACH (rb_node_dep, nhg_connected_head, &nhe1->nhg_depends) {
|
|
|
|
if (!RB_FIND(nhg_connected_head, &nhe2->nhg_depends,
|
|
|
|
rb_node_dep))
|
2019-03-29 15:56:52 +01:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2019-02-26 00:18:07 +01:00
|
|
|
/**
|
|
|
|
* zebra_nhg_lookup_id() - Lookup the nexthop group id in the id table
|
|
|
|
*
|
|
|
|
* @id: ID to look for
|
|
|
|
*
|
|
|
|
* Return: Nexthop hash entry if found/NULL if not found
|
|
|
|
*/
|
|
|
|
struct nhg_hash_entry *zebra_nhg_lookup_id(uint32_t id)
|
|
|
|
{
|
2019-05-14 02:10:34 +02:00
|
|
|
struct nhg_hash_entry lookup = {};
|
2019-02-26 00:18:07 +01:00
|
|
|
|
|
|
|
lookup.id = id;
|
|
|
|
return hash_lookup(zrouter.nhgs_id, &lookup);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* zebra_nhg_insert_id() - Insert a nhe into the id hashed table
|
|
|
|
*
|
|
|
|
* @nhe: The entry directly from the other table
|
|
|
|
*
|
|
|
|
* Return: Result status
|
|
|
|
*/
|
|
|
|
int zebra_nhg_insert_id(struct nhg_hash_entry *nhe)
|
|
|
|
{
|
|
|
|
if (hash_lookup(zrouter.nhgs_id, nhe)) {
|
|
|
|
flog_err(
|
|
|
|
EC_ZEBRA_NHG_TABLE_INSERT_FAILED,
|
|
|
|
"Failed inserting NHG id=%u into the ID hash table, entry already exists",
|
|
|
|
nhe->id);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
hash_get(zrouter.nhgs_id, nhe, hash_alloc_intern);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
2019-05-13 21:46:05 +02:00
|
|
|
|
2019-01-24 16:49:28 +01:00
|
|
|
|
|
|
|
static void *zebra_nhg_alloc(void *arg)
|
|
|
|
{
|
|
|
|
struct nhg_hash_entry *nhe;
|
|
|
|
struct nhg_hash_entry *copy = arg;
|
2019-05-14 03:13:02 +02:00
|
|
|
struct nhg_connected *rb_node_dep = NULL;
|
|
|
|
|
2019-01-24 16:49:28 +01:00
|
|
|
|
2019-03-15 17:23:51 +01:00
|
|
|
nhe = XCALLOC(MTYPE_NHG, sizeof(struct nhg_hash_entry));
|
2019-02-26 00:18:07 +01:00
|
|
|
|
2019-03-28 20:20:29 +01:00
|
|
|
|
|
|
|
nhe->id = copy->id;
|
2019-01-24 16:49:28 +01:00
|
|
|
|
2019-05-14 02:10:34 +02:00
|
|
|
nhe->nhg_depends = copy->nhg_depends;
|
2019-03-22 18:11:07 +01:00
|
|
|
|
2019-03-27 00:40:23 +01:00
|
|
|
nhe->nhg = nexthop_group_new();
|
|
|
|
nexthop_group_copy(nhe->nhg, copy->nhg);
|
2019-03-21 15:43:16 +01:00
|
|
|
|
2019-01-24 16:49:28 +01:00
|
|
|
nhe->vrf_id = copy->vrf_id;
|
2019-03-19 22:06:01 +01:00
|
|
|
nhe->afi = copy->afi;
|
2019-01-24 16:49:28 +01:00
|
|
|
nhe->refcnt = 0;
|
2019-03-29 15:46:50 +01:00
|
|
|
nhe->is_kernel_nh = copy->is_kernel_nh;
|
2019-01-24 16:49:28 +01:00
|
|
|
nhe->dplane_ref = zebra_router_get_next_sequence();
|
2019-05-14 22:46:05 +02:00
|
|
|
nhe->ifp = NULL;
|
2019-01-24 16:49:28 +01:00
|
|
|
|
2019-05-14 03:13:02 +02:00
|
|
|
/* Attach backpointer to anything that it depends on */
|
|
|
|
if (!zebra_nhg_depends_is_empty(nhe)) {
|
|
|
|
RB_FOREACH (rb_node_dep, nhg_connected_head,
|
|
|
|
&nhe->nhg_depends) {
|
|
|
|
zebra_nhg_dependents_add(rb_node_dep->nhe, nhe);
|
|
|
|
}
|
|
|
|
}
|
2019-01-24 16:49:28 +01:00
|
|
|
|
2019-02-26 00:18:07 +01:00
|
|
|
/* Add to id table as well */
|
|
|
|
zebra_nhg_insert_id(nhe);
|
|
|
|
|
2019-01-24 16:49:28 +01:00
|
|
|
|
2019-03-29 15:56:52 +01:00
|
|
|
/* Send it to the kernel */
|
|
|
|
if (!nhe->is_kernel_nh)
|
|
|
|
zebra_nhg_install_kernel(nhe);
|
|
|
|
|
2019-01-24 16:49:28 +01:00
|
|
|
return nhe;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t zebra_nhg_hash_key(const void *arg)
|
|
|
|
{
|
|
|
|
const struct nhg_hash_entry *nhe = arg;
|
2019-02-26 00:18:07 +01:00
|
|
|
|
2019-03-29 15:53:14 +01:00
|
|
|
uint32_t key = 0x5a351234;
|
2019-01-24 16:49:28 +01:00
|
|
|
|
2019-03-19 22:06:01 +01:00
|
|
|
key = jhash_2words(nhe->vrf_id, nhe->afi, key);
|
2019-01-24 16:49:28 +01:00
|
|
|
|
2019-05-14 02:10:34 +02:00
|
|
|
key = jhash_1word(nexthop_group_hash(nhe->nhg), key);
|
2019-02-26 00:18:07 +01:00
|
|
|
|
|
|
|
return key;
|
2019-01-24 16:49:28 +01:00
|
|
|
}
|
|
|
|
|
2019-02-15 19:18:48 +01:00
|
|
|
uint32_t zebra_nhg_id_key(const void *arg)
|
|
|
|
{
|
|
|
|
const struct nhg_hash_entry *nhe = arg;
|
|
|
|
|
|
|
|
return nhe->id;
|
|
|
|
}
|
|
|
|
|
2019-01-24 16:49:28 +01:00
|
|
|
bool zebra_nhg_hash_equal(const void *arg1, const void *arg2)
|
|
|
|
{
|
|
|
|
const struct nhg_hash_entry *nhe1 = arg1;
|
|
|
|
const struct nhg_hash_entry *nhe2 = arg2;
|
|
|
|
|
|
|
|
if (nhe1->vrf_id != nhe2->vrf_id)
|
|
|
|
return false;
|
|
|
|
|
2019-03-19 22:06:01 +01:00
|
|
|
if (nhe1->afi != nhe2->afi)
|
|
|
|
return false;
|
|
|
|
|
2019-03-29 15:56:52 +01:00
|
|
|
if (!zebra_nhg_depends_equal(nhe1, nhe2))
|
|
|
|
return false;
|
2019-01-24 16:49:28 +01:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2019-02-26 00:18:07 +01:00
|
|
|
bool zebra_nhg_hash_id_equal(const void *arg1, const void *arg2)
|
2019-01-24 16:49:28 +01:00
|
|
|
{
|
2019-02-26 00:18:07 +01:00
|
|
|
const struct nhg_hash_entry *nhe1 = arg1;
|
|
|
|
const struct nhg_hash_entry *nhe2 = arg2;
|
2019-01-24 16:49:28 +01:00
|
|
|
|
2019-02-26 00:18:07 +01:00
|
|
|
return nhe1->id == nhe2->id;
|
|
|
|
}
|
2019-01-24 16:49:28 +01:00
|
|
|
|
2019-05-14 02:10:34 +02:00
|
|
|
/**
|
|
|
|
* zebra_nhg_cmp() - Compare the ID's of two nhe's
|
|
|
|
*
|
|
|
|
* @nhe1: Nexthop group hash entry #1
|
|
|
|
* @nhe2: Nexthop group hash entry #2
|
|
|
|
*
|
|
|
|
* Return:
|
|
|
|
* - Negative: #1 < #2
|
|
|
|
* - Positive: #1 > #2
|
|
|
|
* - Zero: #1 = #2
|
|
|
|
*
|
|
|
|
* This is used in the nhg RB trees.
|
|
|
|
*/
|
|
|
|
static int zebra_nhg_cmp(const struct nhg_hash_entry *nhe1,
|
|
|
|
const struct nhg_hash_entry *nhe2)
|
|
|
|
{
|
|
|
|
return nhe1->id - nhe2->id;
|
|
|
|
}
|
|
|
|
|
2019-05-14 03:13:02 +02:00
|
|
|
static int zebra_nhg_connected_cmp(const struct nhg_connected *dep1,
|
|
|
|
const struct nhg_connected *dep2)
|
2019-05-14 02:10:34 +02:00
|
|
|
{
|
|
|
|
return zebra_nhg_cmp(dep1->nhe, dep2->nhe);
|
|
|
|
}
|
|
|
|
|
2019-02-26 00:18:07 +01:00
|
|
|
/**
|
|
|
|
* zebra_nhg_find() - Find the zebra nhg in our table, or create it
|
|
|
|
*
|
2019-03-22 18:11:07 +01:00
|
|
|
* @nhg: Nexthop group we lookup with
|
|
|
|
* @vrf_id: VRF id
|
|
|
|
* @afi: Address Family type
|
|
|
|
* @id: ID we lookup with, 0 means its from us and we
|
|
|
|
* need to give it an ID, otherwise its from the
|
|
|
|
* kernel as we use the ID it gave us.
|
2019-05-14 02:10:34 +02:00
|
|
|
* @nhg_depends: Nexthop dependency tree head
|
2019-03-29 15:46:50 +01:00
|
|
|
* @is_kernel_nh: Was the nexthop created by the kernel
|
2019-02-26 00:18:07 +01:00
|
|
|
*
|
2019-03-22 18:11:07 +01:00
|
|
|
* Return: Hash entry found or created
|
2019-03-21 15:47:19 +01:00
|
|
|
*
|
|
|
|
* The nhg and n_grp are fundementally the same thing (a group of nexthops).
|
|
|
|
* We are just using the nhg representation with routes and the n_grp
|
|
|
|
* is what the kernel gives us (a list of IDs). Our nhg_hash_entry
|
|
|
|
* will contain both.
|
|
|
|
*
|
|
|
|
* nhg_hash_entry example:
|
|
|
|
*
|
|
|
|
* nhe:
|
|
|
|
* ->nhg:
|
|
|
|
* .nexthop->nexthop->nexthop
|
|
|
|
* ->nhg_depends:
|
|
|
|
* .nhe->nhe->nhe
|
|
|
|
*
|
|
|
|
* Routes will use the nhg directly, and any updating of nexthops
|
|
|
|
* we have to do or flag setting, we use the nhg_depends.
|
|
|
|
*
|
2019-02-26 00:18:07 +01:00
|
|
|
*/
|
|
|
|
struct nhg_hash_entry *zebra_nhg_find(struct nexthop_group *nhg,
|
2019-03-21 15:47:19 +01:00
|
|
|
vrf_id_t vrf_id, afi_t afi, uint32_t id,
|
2019-05-14 03:13:02 +02:00
|
|
|
struct nhg_connected_head *nhg_depends,
|
2019-03-29 15:46:50 +01:00
|
|
|
bool is_kernel_nh)
|
2019-02-15 19:18:48 +01:00
|
|
|
{
|
2019-03-28 20:20:29 +01:00
|
|
|
/* lock for getiing and setting the id */
|
|
|
|
static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
|
|
|
|
/* id counter to keep in sync with kernel */
|
|
|
|
static uint32_t id_counter = 0;
|
|
|
|
|
2019-05-14 02:10:34 +02:00
|
|
|
struct nhg_hash_entry lookup = {};
|
2019-02-26 00:18:07 +01:00
|
|
|
struct nhg_hash_entry *nhe = NULL;
|
2019-03-28 20:20:29 +01:00
|
|
|
uint32_t old_id_counter = 0;
|
|
|
|
|
|
|
|
pthread_mutex_lock(&lock); /* Lock, set the id counter */
|
|
|
|
|
|
|
|
old_id_counter = id_counter;
|
|
|
|
|
|
|
|
if (id) {
|
|
|
|
if (id > id_counter) {
|
|
|
|
/* Increase our counter so we don't try to create
|
|
|
|
* an ID that already exists
|
|
|
|
*/
|
|
|
|
id_counter = id;
|
|
|
|
}
|
|
|
|
lookup.id = id;
|
|
|
|
} else {
|
|
|
|
lookup.id = ++id_counter;
|
|
|
|
}
|
2019-02-15 19:18:48 +01:00
|
|
|
|
2019-02-26 00:18:07 +01:00
|
|
|
lookup.vrf_id = vrf_id;
|
2019-03-19 22:06:01 +01:00
|
|
|
lookup.afi = afi;
|
2019-03-22 18:07:22 +01:00
|
|
|
lookup.nhg = nhg;
|
2019-05-14 02:10:34 +02:00
|
|
|
lookup.nhg_depends = *nhg_depends;
|
2019-03-29 15:46:50 +01:00
|
|
|
lookup.is_kernel_nh = is_kernel_nh;
|
2019-02-15 19:18:48 +01:00
|
|
|
|
2019-03-22 18:07:22 +01:00
|
|
|
if (id)
|
|
|
|
nhe = zebra_nhg_lookup_id(id);
|
|
|
|
else
|
|
|
|
nhe = hash_lookup(zrouter.nhgs, &lookup);
|
2019-02-26 00:18:07 +01:00
|
|
|
|
2019-03-28 20:20:29 +01:00
|
|
|
/* If it found an nhe in our tables, this new ID is unused */
|
|
|
|
if (nhe)
|
|
|
|
id_counter = old_id_counter;
|
|
|
|
|
|
|
|
pthread_mutex_unlock(&lock);
|
|
|
|
|
2019-03-27 00:40:23 +01:00
|
|
|
if (!nhe)
|
2019-02-26 00:18:07 +01:00
|
|
|
nhe = hash_get(zrouter.nhgs, &lookup, zebra_nhg_alloc);
|
|
|
|
|
|
|
|
return nhe;
|
2019-02-15 19:18:48 +01:00
|
|
|
}
|
|
|
|
|
2019-03-29 15:51:07 +01:00
|
|
|
/**
|
|
|
|
* zebra_nhg_find_nexthop() - Create a group with a single nexthop, find it in
|
|
|
|
* our table, or create it
|
|
|
|
*
|
|
|
|
* @nh: Nexthop to lookup
|
|
|
|
* @afi: Address Family type
|
|
|
|
*
|
|
|
|
* Return: Hash entry found or created
|
|
|
|
*/
|
|
|
|
struct nhg_hash_entry *zebra_nhg_find_nexthop(struct nexthop *nh, afi_t afi)
|
|
|
|
{
|
|
|
|
struct nhg_hash_entry *nhe = NULL;
|
|
|
|
|
|
|
|
struct nexthop_group *nhg = nexthop_group_new();
|
|
|
|
|
|
|
|
nexthop_group_add_sorted(nhg, nh);
|
|
|
|
nhe = zebra_nhg_find(nhg, nh->vrf_id, afi, 0, NULL, false);
|
|
|
|
|
|
|
|
nexthop_group_delete(&nhg);
|
|
|
|
|
|
|
|
return nhe;
|
|
|
|
}
|
|
|
|
|
2019-05-14 03:13:02 +02:00
|
|
|
void zebra_nhg_connected_head_free(struct nhg_connected_head *head)
|
2019-05-14 02:10:34 +02:00
|
|
|
{
|
2019-05-14 03:13:02 +02:00
|
|
|
struct nhg_connected *rb_node_dep = NULL;
|
|
|
|
struct nhg_connected *tmp = NULL;
|
2019-05-14 02:10:34 +02:00
|
|
|
|
2019-05-14 03:13:02 +02:00
|
|
|
if (!zebra_nhg_connected_head_is_empty(head)) {
|
|
|
|
RB_FOREACH_SAFE (rb_node_dep, nhg_connected_head, head, tmp) {
|
|
|
|
RB_REMOVE(nhg_connected_head, head, rb_node_dep);
|
|
|
|
nhg_connected_free(rb_node_dep);
|
2019-05-14 02:10:34 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-03-22 18:07:22 +01:00
|
|
|
/**
|
|
|
|
* zebra_nhg_free_group_depends() - Helper function for freeing nexthop_group
|
|
|
|
* struct and depends
|
|
|
|
*
|
2019-05-14 02:10:34 +02:00
|
|
|
* @nhg: Nexthop_group
|
|
|
|
* @nhg_depends: Nexthop group dependency tree head
|
2019-03-22 18:07:22 +01:00
|
|
|
*/
|
2019-05-14 02:10:34 +02:00
|
|
|
void zebra_nhg_free_group_depends(struct nexthop_group **nhg,
|
2019-05-14 03:13:02 +02:00
|
|
|
struct nhg_connected_head *head)
|
|
|
|
{
|
|
|
|
// TODO
|
|
|
|
//
|
|
|
|
//
|
|
|
|
// FIX THIS NAMING
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
|
|
|
//
|
2019-05-14 02:10:34 +02:00
|
|
|
if (head)
|
2019-05-14 03:13:02 +02:00
|
|
|
zebra_nhg_connected_head_free(head);
|
2019-05-14 02:10:34 +02:00
|
|
|
|
|
|
|
if (nhg)
|
|
|
|
nexthop_group_free_delete(nhg);
|
2019-03-22 18:07:22 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* zebra_nhg_free_members() - Free all members in the hash entry struct
|
|
|
|
*
|
|
|
|
* @nhe: Nexthop group hash entry
|
|
|
|
*
|
|
|
|
* Just use this to free everything but the entry itself.
|
|
|
|
*/
|
|
|
|
void zebra_nhg_free_members(struct nhg_hash_entry *nhe)
|
|
|
|
{
|
2019-05-14 02:10:34 +02:00
|
|
|
zebra_nhg_free_group_depends(&nhe->nhg, &nhe->nhg_depends);
|
2019-05-14 03:13:02 +02:00
|
|
|
|
|
|
|
// TODO: Fixup this function
|
|
|
|
zebra_nhg_connected_head_free(&nhe->nhg_dependents);
|
2019-03-22 18:07:22 +01:00
|
|
|
}
|
|
|
|
|
2019-02-26 00:18:07 +01:00
|
|
|
/**
|
|
|
|
* zebra_nhg_free() - Free the nexthop group hash entry
|
|
|
|
*
|
|
|
|
* arg: Nexthop group entry to free
|
|
|
|
*/
|
|
|
|
void zebra_nhg_free(void *arg)
|
2019-02-15 19:18:48 +01:00
|
|
|
{
|
2019-02-26 00:18:07 +01:00
|
|
|
struct nhg_hash_entry *nhe = NULL;
|
2019-02-15 19:18:48 +01:00
|
|
|
|
2019-02-26 00:18:07 +01:00
|
|
|
nhe = (struct nhg_hash_entry *)arg;
|
2019-02-15 19:18:48 +01:00
|
|
|
|
2019-03-22 18:11:07 +01:00
|
|
|
zebra_nhg_free_members(nhe);
|
2019-03-15 17:23:51 +01:00
|
|
|
|
|
|
|
XFREE(MTYPE_NHG, nhe);
|
2019-02-15 19:18:48 +01:00
|
|
|
}
|
|
|
|
|
2019-02-26 00:18:07 +01:00
|
|
|
/**
|
|
|
|
* zebra_nhg_release() - Release a nhe from the tables
|
|
|
|
*
|
|
|
|
* @nhe: Nexthop group hash entry
|
|
|
|
*/
|
|
|
|
void zebra_nhg_release(struct nhg_hash_entry *nhe)
|
2019-01-24 16:49:28 +01:00
|
|
|
{
|
2019-05-14 22:56:38 +02:00
|
|
|
if (!nhe->refcnt) {
|
|
|
|
zlog_debug("Releasing nexthop group with ID (%u)", nhe->id);
|
|
|
|
hash_release(zrouter.nhgs, nhe);
|
|
|
|
hash_release(zrouter.nhgs_id, nhe);
|
|
|
|
zebra_nhg_free(nhe);
|
|
|
|
}
|
|
|
|
}
|
2019-01-24 16:49:28 +01:00
|
|
|
|
2019-05-14 22:56:38 +02:00
|
|
|
/**
|
|
|
|
* zebra_nhg_uninstall_release() - Unistall and release a nhe
|
|
|
|
*
|
|
|
|
* @nhe: Nexthop group hash entry
|
|
|
|
*/
|
|
|
|
static void zebra_nhg_uninstall_release(struct nhg_hash_entry *nhe)
|
|
|
|
{
|
|
|
|
zebra_nhg_uninstall_kernel(nhe);
|
|
|
|
// zebra_nhg_release(nhe);
|
2019-02-26 00:18:07 +01:00
|
|
|
}
|
2019-01-24 16:49:28 +01:00
|
|
|
|
2019-02-26 00:18:07 +01:00
|
|
|
/**
|
|
|
|
* zebra_nhg_decrement_ref() - Decrement the reference count, release if unused
|
|
|
|
*
|
|
|
|
* @nhe: Nexthop group hash entry
|
|
|
|
*
|
|
|
|
* If the counter hits 0 and is not a nexthop group that was created by the
|
|
|
|
* kernel, we don't need to have it in our table anymore.
|
|
|
|
*/
|
|
|
|
void zebra_nhg_decrement_ref(struct nhg_hash_entry *nhe)
|
|
|
|
{
|
2019-05-14 02:10:34 +02:00
|
|
|
if (!zebra_nhg_depends_is_empty(nhe)) {
|
2019-05-14 03:13:02 +02:00
|
|
|
struct nhg_connected *rb_node_dep = NULL;
|
2019-03-29 23:16:27 +01:00
|
|
|
|
2019-05-14 03:13:02 +02:00
|
|
|
RB_FOREACH (rb_node_dep, nhg_connected_head,
|
|
|
|
&nhe->nhg_depends) {
|
2019-05-14 02:10:34 +02:00
|
|
|
zebra_nhg_decrement_ref(rb_node_dep->nhe);
|
2019-03-29 23:16:27 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-01-24 16:49:28 +01:00
|
|
|
nhe->refcnt--;
|
|
|
|
|
2019-02-26 00:18:07 +01:00
|
|
|
if (!nhe->is_kernel_nh && nhe->refcnt <= 0) {
|
2019-05-14 22:56:38 +02:00
|
|
|
zebra_nhg_uninstall_release(nhe);
|
2019-02-26 00:18:07 +01:00
|
|
|
}
|
2019-03-29 23:14:20 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* zebra_nhg_increment_ref() - Increment the reference count
|
|
|
|
*
|
|
|
|
* @nhe: Nexthop group hash entry
|
|
|
|
*/
|
|
|
|
void zebra_nhg_increment_ref(struct nhg_hash_entry *nhe)
|
|
|
|
{
|
2019-05-14 02:10:34 +02:00
|
|
|
if (!zebra_nhg_depends_is_empty(nhe)) {
|
2019-05-14 03:13:02 +02:00
|
|
|
struct nhg_connected *rb_node_dep = NULL;
|
2019-03-29 23:14:20 +01:00
|
|
|
|
2019-05-14 03:13:02 +02:00
|
|
|
RB_FOREACH (rb_node_dep, nhg_connected_head,
|
|
|
|
&nhe->nhg_depends) {
|
2019-05-14 02:10:34 +02:00
|
|
|
zebra_nhg_increment_ref(rb_node_dep->nhe);
|
2019-03-29 23:14:20 +01:00
|
|
|
}
|
|
|
|
}
|
2019-02-26 00:18:07 +01:00
|
|
|
|
2019-03-29 23:14:20 +01:00
|
|
|
nhe->refcnt++;
|
2019-01-24 16:49:28 +01:00
|
|
|
}
|
|
|
|
|
2019-05-13 21:46:05 +02:00
|
|
|
static void nexthop_set_resolved(afi_t afi, const struct nexthop *newhop,
|
|
|
|
struct nexthop *nexthop)
|
|
|
|
{
|
|
|
|
struct nexthop *resolved_hop;
|
zebra: Append rparent labels when resolving nexthop
When resolving a nexthop, append its labels to the one its
resolving to along with the labels that may already be present there.
Before we were ignoring labels if the resolving level was greater than
two.
Before:
```
S> 2.2.2.2/32 [1/0] via 7.7.7.7 (recursive), label 2222, 00:00:07
* via 7.7.7.7, dummy1 onlink, label 1111, 00:00:07
S> 3.3.3.3/32 [1/0] via 2.2.2.2 (recursive), label 3333, 00:00:04
* via 7.7.7.7, dummy1 onlink, label 1111, 00:00:04
K>* 7.7.7.7/32 [0/0] is directly connected, dummy1, label 1111, 00:00:17
C>* 192.168.122.0/24 is directly connected, ens3, 00:00:17
K>* 192.168.122.1/32 [0/100] is directly connected, ens3, 00:00:17
ubuntu_nh#
```
This patch:
```
S> 2.2.2.2/32 [1/0] via 7.7.7.7 (recursive), label 2222, 00:00:04
* via 7.7.7.7, dummy1 onlink, label 1111/2222, 00:00:04
S> 3.3.3.3/32 [1/0] via 2.2.2.2 (recursive), label 3333, 00:00:02
* via 7.7.7.7, dummy1 onlink, label 1111/2222/3333, 00:00:02
K>* 7.7.7.7/32 [0/0] is directly connected, dummy1, label 1111, 00:00:11
C>* 192.168.122.0/24 is directly connected, ens3, 00:00:11
K>* 192.168.122.1/32 [0/100] is directly connected, ens3, 00:00:11
ubuntu_nh#
```
Signed-off-by: Stephen Worley <sworley@cumulusnetworks.com>
2019-08-08 00:40:36 +02:00
|
|
|
uint8_t num_labels = 0;
|
|
|
|
mpls_label_t labels[MPLS_MAX_LABELS];
|
|
|
|
enum lsp_types_t label_type = ZEBRA_LSP_NONE;
|
|
|
|
int i = 0;
|
2019-05-13 21:46:05 +02:00
|
|
|
|
|
|
|
resolved_hop = nexthop_new();
|
|
|
|
SET_FLAG(resolved_hop->flags, NEXTHOP_FLAG_ACTIVE);
|
|
|
|
|
|
|
|
resolved_hop->vrf_id = nexthop->vrf_id;
|
|
|
|
switch (newhop->type) {
|
|
|
|
case NEXTHOP_TYPE_IPV4:
|
|
|
|
case NEXTHOP_TYPE_IPV4_IFINDEX:
|
|
|
|
/* If the resolving route specifies a gateway, use it */
|
|
|
|
resolved_hop->type = newhop->type;
|
|
|
|
resolved_hop->gate.ipv4 = newhop->gate.ipv4;
|
|
|
|
|
|
|
|
if (newhop->ifindex) {
|
|
|
|
resolved_hop->type = NEXTHOP_TYPE_IPV4_IFINDEX;
|
|
|
|
resolved_hop->ifindex = newhop->ifindex;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case NEXTHOP_TYPE_IPV6:
|
|
|
|
case NEXTHOP_TYPE_IPV6_IFINDEX:
|
|
|
|
resolved_hop->type = newhop->type;
|
|
|
|
resolved_hop->gate.ipv6 = newhop->gate.ipv6;
|
|
|
|
|
|
|
|
if (newhop->ifindex) {
|
|
|
|
resolved_hop->type = NEXTHOP_TYPE_IPV6_IFINDEX;
|
|
|
|
resolved_hop->ifindex = newhop->ifindex;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case NEXTHOP_TYPE_IFINDEX:
|
|
|
|
/* If the resolving route is an interface route,
|
|
|
|
* it means the gateway we are looking up is connected
|
|
|
|
* to that interface. (The actual network is _not_ onlink).
|
|
|
|
* Therefore, the resolved route should have the original
|
|
|
|
* gateway as nexthop as it is directly connected.
|
|
|
|
*
|
|
|
|
* On Linux, we have to set the onlink netlink flag because
|
|
|
|
* otherwise, the kernel won't accept the route.
|
|
|
|
*/
|
|
|
|
resolved_hop->flags |= NEXTHOP_FLAG_ONLINK;
|
|
|
|
if (afi == AFI_IP) {
|
|
|
|
resolved_hop->type = NEXTHOP_TYPE_IPV4_IFINDEX;
|
|
|
|
resolved_hop->gate.ipv4 = nexthop->gate.ipv4;
|
|
|
|
} else if (afi == AFI_IP6) {
|
|
|
|
resolved_hop->type = NEXTHOP_TYPE_IPV6_IFINDEX;
|
|
|
|
resolved_hop->gate.ipv6 = nexthop->gate.ipv6;
|
|
|
|
}
|
|
|
|
resolved_hop->ifindex = newhop->ifindex;
|
|
|
|
break;
|
|
|
|
case NEXTHOP_TYPE_BLACKHOLE:
|
|
|
|
resolved_hop->type = NEXTHOP_TYPE_BLACKHOLE;
|
2019-08-13 07:56:38 +02:00
|
|
|
resolved_hop->bh_type = newhop->bh_type;
|
2019-05-13 21:46:05 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (newhop->flags & NEXTHOP_FLAG_ONLINK)
|
|
|
|
resolved_hop->flags |= NEXTHOP_FLAG_ONLINK;
|
|
|
|
|
zebra: Append rparent labels when resolving nexthop
When resolving a nexthop, append its labels to the one its
resolving to along with the labels that may already be present there.
Before we were ignoring labels if the resolving level was greater than
two.
Before:
```
S> 2.2.2.2/32 [1/0] via 7.7.7.7 (recursive), label 2222, 00:00:07
* via 7.7.7.7, dummy1 onlink, label 1111, 00:00:07
S> 3.3.3.3/32 [1/0] via 2.2.2.2 (recursive), label 3333, 00:00:04
* via 7.7.7.7, dummy1 onlink, label 1111, 00:00:04
K>* 7.7.7.7/32 [0/0] is directly connected, dummy1, label 1111, 00:00:17
C>* 192.168.122.0/24 is directly connected, ens3, 00:00:17
K>* 192.168.122.1/32 [0/100] is directly connected, ens3, 00:00:17
ubuntu_nh#
```
This patch:
```
S> 2.2.2.2/32 [1/0] via 7.7.7.7 (recursive), label 2222, 00:00:04
* via 7.7.7.7, dummy1 onlink, label 1111/2222, 00:00:04
S> 3.3.3.3/32 [1/0] via 2.2.2.2 (recursive), label 3333, 00:00:02
* via 7.7.7.7, dummy1 onlink, label 1111/2222/3333, 00:00:02
K>* 7.7.7.7/32 [0/0] is directly connected, dummy1, label 1111, 00:00:11
C>* 192.168.122.0/24 is directly connected, ens3, 00:00:11
K>* 192.168.122.1/32 [0/100] is directly connected, ens3, 00:00:11
ubuntu_nh#
```
Signed-off-by: Stephen Worley <sworley@cumulusnetworks.com>
2019-08-08 00:40:36 +02:00
|
|
|
/* Copy labels of the resolved route and the parent resolving to it */
|
|
|
|
if (newhop->nh_label) {
|
|
|
|
for (i = 0; i < newhop->nh_label->num_labels; i++)
|
|
|
|
labels[num_labels++] = newhop->nh_label->label[i];
|
|
|
|
label_type = newhop->nh_label_type;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (nexthop->nh_label) {
|
|
|
|
for (i = 0; i < nexthop->nh_label->num_labels; i++)
|
|
|
|
labels[num_labels++] = nexthop->nh_label->label[i];
|
|
|
|
|
|
|
|
/* If the parent has labels, use its type */
|
|
|
|
label_type = nexthop->nh_label_type;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (num_labels)
|
|
|
|
nexthop_add_labels(resolved_hop, label_type, num_labels,
|
|
|
|
labels);
|
2019-05-13 21:46:05 +02:00
|
|
|
|
|
|
|
resolved_hop->rparent = nexthop;
|
2019-06-24 20:04:13 +02:00
|
|
|
_nexthop_add(&nexthop->resolved, resolved_hop);
|
2019-05-13 21:46:05 +02:00
|
|
|
}
|
|
|
|
|
2019-09-09 23:20:17 +02:00
|
|
|
/* Checks if nexthop we are trying to resolve to is valid */
|
|
|
|
static bool nexthop_valid_resolve(const struct nexthop *nexthop,
|
|
|
|
const struct nexthop *resolved)
|
|
|
|
{
|
|
|
|
/* Can't resolve to a recursive nexthop */
|
|
|
|
if (CHECK_FLAG(resolved->flags, NEXTHOP_FLAG_RECURSIVE))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
switch (nexthop->type) {
|
|
|
|
case NEXTHOP_TYPE_IPV4_IFINDEX:
|
|
|
|
case NEXTHOP_TYPE_IPV6_IFINDEX:
|
|
|
|
/* If the nexthop we are resolving to does not match the
|
|
|
|
* ifindex for the nexthop the route wanted, its not valid.
|
|
|
|
*/
|
|
|
|
if (nexthop->ifindex != resolved->ifindex)
|
|
|
|
return false;
|
|
|
|
break;
|
|
|
|
case NEXTHOP_TYPE_IPV4:
|
|
|
|
case NEXTHOP_TYPE_IPV6:
|
|
|
|
case NEXTHOP_TYPE_IFINDEX:
|
|
|
|
case NEXTHOP_TYPE_BLACKHOLE:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2019-05-13 21:46:05 +02:00
|
|
|
/*
|
|
|
|
* Given a nexthop we need to properly recursively resolve
|
|
|
|
* the route. As such, do a table lookup to find and match
|
|
|
|
* if at all possible. Set the nexthop->ifindex as appropriate
|
|
|
|
*/
|
|
|
|
static int nexthop_active(afi_t afi, struct route_entry *re,
|
|
|
|
struct nexthop *nexthop, struct route_node *top)
|
|
|
|
{
|
|
|
|
struct prefix p;
|
|
|
|
struct route_table *table;
|
|
|
|
struct route_node *rn;
|
|
|
|
struct route_entry *match = NULL;
|
|
|
|
int resolved;
|
|
|
|
struct nexthop *newhop;
|
|
|
|
struct interface *ifp;
|
|
|
|
rib_dest_t *dest;
|
2019-08-28 16:01:38 +02:00
|
|
|
struct zebra_vrf *zvrf;
|
2019-05-13 21:46:05 +02:00
|
|
|
|
|
|
|
if ((nexthop->type == NEXTHOP_TYPE_IPV4)
|
|
|
|
|| nexthop->type == NEXTHOP_TYPE_IPV6)
|
|
|
|
nexthop->ifindex = 0;
|
|
|
|
|
|
|
|
UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE);
|
|
|
|
nexthops_free(nexthop->resolved);
|
|
|
|
nexthop->resolved = NULL;
|
|
|
|
re->nexthop_mtu = 0;
|
|
|
|
|
|
|
|
/*
|
2019-10-17 21:41:25 +02:00
|
|
|
* If the kernel has sent us a NEW route, then
|
2019-05-13 21:46:05 +02:00
|
|
|
* by golly gee whiz it's a good route.
|
2019-10-17 21:41:25 +02:00
|
|
|
*
|
|
|
|
* If its an already INSTALLED route we have already handled, then the
|
|
|
|
* kernel route's nexthop might have became unreachable
|
|
|
|
* and we have to handle that.
|
2019-05-13 21:46:05 +02:00
|
|
|
*/
|
2019-10-17 21:41:25 +02:00
|
|
|
if (!CHECK_FLAG(re->status, ROUTE_ENTRY_INSTALLED)
|
|
|
|
&& (re->type == ZEBRA_ROUTE_KERNEL
|
|
|
|
|| re->type == ZEBRA_ROUTE_SYSTEM))
|
2019-05-13 21:46:05 +02:00
|
|
|
return 1;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Check to see if we should trust the passed in information
|
|
|
|
* for UNNUMBERED interfaces as that we won't find the GW
|
|
|
|
* address in the routing table.
|
|
|
|
* This check should suffice to handle IPv4 or IPv6 routes
|
|
|
|
* sourced from EVPN routes which are installed with the
|
|
|
|
* next hop as the remote VTEP IP.
|
|
|
|
*/
|
|
|
|
if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK)) {
|
|
|
|
ifp = if_lookup_by_index(nexthop->ifindex, nexthop->vrf_id);
|
|
|
|
if (!ifp) {
|
|
|
|
if (IS_ZEBRA_DEBUG_RIB_DETAILED)
|
|
|
|
zlog_debug(
|
|
|
|
"\t%s: Onlink and interface: %u[%u] does not exist",
|
|
|
|
__PRETTY_FUNCTION__, nexthop->ifindex,
|
|
|
|
nexthop->vrf_id);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
if (connected_is_unnumbered(ifp)) {
|
|
|
|
if (if_is_operative(ifp))
|
|
|
|
return 1;
|
|
|
|
else {
|
|
|
|
if (IS_ZEBRA_DEBUG_RIB_DETAILED)
|
|
|
|
zlog_debug(
|
|
|
|
"\t%s: Onlink and interface %s is not operative",
|
|
|
|
__PRETTY_FUNCTION__, ifp->name);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!if_is_operative(ifp)) {
|
|
|
|
if (IS_ZEBRA_DEBUG_RIB_DETAILED)
|
|
|
|
zlog_debug(
|
|
|
|
"\t%s: Interface %s is not unnumbered",
|
|
|
|
__PRETTY_FUNCTION__, ifp->name);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Make lookup prefix. */
|
|
|
|
memset(&p, 0, sizeof(struct prefix));
|
|
|
|
switch (afi) {
|
|
|
|
case AFI_IP:
|
|
|
|
p.family = AF_INET;
|
|
|
|
p.prefixlen = IPV4_MAX_PREFIXLEN;
|
|
|
|
p.u.prefix4 = nexthop->gate.ipv4;
|
|
|
|
break;
|
|
|
|
case AFI_IP6:
|
|
|
|
p.family = AF_INET6;
|
|
|
|
p.prefixlen = IPV6_MAX_PREFIXLEN;
|
|
|
|
p.u.prefix6 = nexthop->gate.ipv6;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
assert(afi != AFI_IP && afi != AFI_IP6);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
/* Lookup table. */
|
|
|
|
table = zebra_vrf_table(afi, SAFI_UNICAST, nexthop->vrf_id);
|
2019-08-28 16:01:38 +02:00
|
|
|
/* get zvrf */
|
|
|
|
zvrf = zebra_vrf_lookup_by_id(nexthop->vrf_id);
|
|
|
|
if (!table || !zvrf) {
|
2019-05-13 21:46:05 +02:00
|
|
|
if (IS_ZEBRA_DEBUG_RIB_DETAILED)
|
|
|
|
zlog_debug("\t%s: Table not found",
|
|
|
|
__PRETTY_FUNCTION__);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
rn = route_node_match(table, (struct prefix *)&p);
|
|
|
|
while (rn) {
|
|
|
|
route_unlock_node(rn);
|
|
|
|
|
|
|
|
/* Lookup should halt if we've matched against ourselves ('top',
|
|
|
|
* if specified) - i.e., we cannot have a nexthop NH1 is
|
|
|
|
* resolved by a route NH1. The exception is if the route is a
|
|
|
|
* host route.
|
|
|
|
*/
|
|
|
|
if (top && rn == top)
|
|
|
|
if (((afi == AFI_IP) && (rn->p.prefixlen != 32))
|
|
|
|
|| ((afi == AFI_IP6) && (rn->p.prefixlen != 128))) {
|
|
|
|
if (IS_ZEBRA_DEBUG_RIB_DETAILED)
|
|
|
|
zlog_debug(
|
|
|
|
"\t%s: Matched against ourself and prefix length is not max bit length",
|
|
|
|
__PRETTY_FUNCTION__);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Pick up selected route. */
|
|
|
|
/* However, do not resolve over default route unless explicitly
|
|
|
|
* allowed. */
|
|
|
|
if (is_default_prefix(&rn->p)
|
2019-08-28 16:01:38 +02:00
|
|
|
&& !rnh_resolve_via_default(zvrf, p.family)) {
|
2019-05-13 21:46:05 +02:00
|
|
|
if (IS_ZEBRA_DEBUG_RIB_DETAILED)
|
|
|
|
zlog_debug(
|
|
|
|
"\t:%s: Resolved against default route",
|
|
|
|
__PRETTY_FUNCTION__);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
dest = rib_dest_from_rnode(rn);
|
|
|
|
if (dest && dest->selected_fib
|
|
|
|
&& !CHECK_FLAG(dest->selected_fib->status,
|
|
|
|
ROUTE_ENTRY_REMOVED)
|
|
|
|
&& dest->selected_fib->type != ZEBRA_ROUTE_TABLE)
|
|
|
|
match = dest->selected_fib;
|
|
|
|
|
|
|
|
/* If there is no selected route or matched route is EGP, go up
|
|
|
|
tree. */
|
|
|
|
if (!match) {
|
|
|
|
do {
|
|
|
|
rn = rn->parent;
|
|
|
|
} while (rn && rn->info == NULL);
|
|
|
|
if (rn)
|
|
|
|
route_lock_node(rn);
|
|
|
|
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (match->type == ZEBRA_ROUTE_CONNECT) {
|
|
|
|
/* Directly point connected route. */
|
2019-02-13 22:06:48 +01:00
|
|
|
newhop = match->ng->nexthop;
|
2019-05-13 21:46:05 +02:00
|
|
|
if (newhop) {
|
|
|
|
if (nexthop->type == NEXTHOP_TYPE_IPV4
|
|
|
|
|| nexthop->type == NEXTHOP_TYPE_IPV6)
|
|
|
|
nexthop->ifindex = newhop->ifindex;
|
|
|
|
}
|
|
|
|
return 1;
|
|
|
|
} else if (CHECK_FLAG(re->flags, ZEBRA_FLAG_ALLOW_RECURSION)) {
|
|
|
|
resolved = 0;
|
2019-02-13 22:06:48 +01:00
|
|
|
for (ALL_NEXTHOPS_PTR(match->ng, newhop)) {
|
2019-05-13 21:46:05 +02:00
|
|
|
if (!CHECK_FLAG(match->status,
|
|
|
|
ROUTE_ENTRY_INSTALLED))
|
|
|
|
continue;
|
2019-09-09 23:20:17 +02:00
|
|
|
if (!nexthop_valid_resolve(nexthop, newhop))
|
2019-05-13 21:46:05 +02:00
|
|
|
continue;
|
|
|
|
|
|
|
|
SET_FLAG(nexthop->flags,
|
|
|
|
NEXTHOP_FLAG_RECURSIVE);
|
|
|
|
nexthop_set_resolved(afi, newhop, nexthop);
|
|
|
|
resolved = 1;
|
|
|
|
}
|
|
|
|
if (resolved)
|
|
|
|
re->nexthop_mtu = match->mtu;
|
|
|
|
if (!resolved && IS_ZEBRA_DEBUG_RIB_DETAILED)
|
|
|
|
zlog_debug("\t%s: Recursion failed to find",
|
|
|
|
__PRETTY_FUNCTION__);
|
|
|
|
return resolved;
|
|
|
|
} else if (re->type == ZEBRA_ROUTE_STATIC) {
|
|
|
|
resolved = 0;
|
2019-02-13 22:06:48 +01:00
|
|
|
for (ALL_NEXTHOPS_PTR(match->ng, newhop)) {
|
2019-05-13 21:46:05 +02:00
|
|
|
if (!CHECK_FLAG(match->status,
|
|
|
|
ROUTE_ENTRY_INSTALLED))
|
|
|
|
continue;
|
2019-09-09 23:20:17 +02:00
|
|
|
if (!nexthop_valid_resolve(nexthop, newhop))
|
2019-05-13 21:46:05 +02:00
|
|
|
continue;
|
|
|
|
|
|
|
|
SET_FLAG(nexthop->flags,
|
|
|
|
NEXTHOP_FLAG_RECURSIVE);
|
|
|
|
nexthop_set_resolved(afi, newhop, nexthop);
|
|
|
|
resolved = 1;
|
|
|
|
}
|
|
|
|
if (resolved)
|
|
|
|
re->nexthop_mtu = match->mtu;
|
|
|
|
|
|
|
|
if (!resolved && IS_ZEBRA_DEBUG_RIB_DETAILED)
|
|
|
|
zlog_debug(
|
|
|
|
"\t%s: Static route unable to resolve",
|
|
|
|
__PRETTY_FUNCTION__);
|
|
|
|
return resolved;
|
|
|
|
} else {
|
|
|
|
if (IS_ZEBRA_DEBUG_RIB_DETAILED) {
|
|
|
|
zlog_debug(
|
|
|
|
"\t%s: Route Type %s has not turned on recursion",
|
|
|
|
__PRETTY_FUNCTION__,
|
|
|
|
zebra_route_string(re->type));
|
|
|
|
if (re->type == ZEBRA_ROUTE_BGP
|
|
|
|
&& !CHECK_FLAG(re->flags, ZEBRA_FLAG_IBGP))
|
|
|
|
zlog_debug(
|
|
|
|
"\tEBGP: see \"disable-ebgp-connected-route-check\" or \"disable-connected-check\"");
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (IS_ZEBRA_DEBUG_RIB_DETAILED)
|
|
|
|
zlog_debug("\t%s: Nexthop did not lookup in table",
|
|
|
|
__PRETTY_FUNCTION__);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* This function verifies reachability of one given nexthop, which can be
|
|
|
|
* numbered or unnumbered, IPv4 or IPv6. The result is unconditionally stored
|
|
|
|
* in nexthop->flags field. The nexthop->ifindex will be updated
|
|
|
|
* appropriately as well. An existing route map can turn
|
|
|
|
* (otherwise active) nexthop into inactive, but not vice versa.
|
|
|
|
*
|
|
|
|
* The return value is the final value of 'ACTIVE' flag.
|
|
|
|
*/
|
|
|
|
static unsigned nexthop_active_check(struct route_node *rn,
|
|
|
|
struct route_entry *re,
|
|
|
|
struct nexthop *nexthop)
|
|
|
|
{
|
|
|
|
struct interface *ifp;
|
lib: Introducing a 3rd state for route-map match cmd: RMAP_NOOP
Introducing a 3rd state for route_map_apply library function: RMAP_NOOP
Traditionally route map MATCH rule apis were designed to return
a binary response, consisting of either RMAP_MATCH or RMAP_NOMATCH.
(Route-map SET rule apis return RMAP_OKAY or RMAP_ERROR).
Depending on this response, the following statemachine decided the
course of action:
State1:
If match cmd returns RMAP_MATCH then, keep existing behaviour.
If routemap type is PERMIT, execute set cmds or call cmds if applicable,
otherwise PERMIT!
Else If routemap type is DENY, we DENYMATCH right away
State2:
If match cmd returns RMAP_NOMATCH, continue on to next route-map. If there
are no other rules or if all the rules return RMAP_NOMATCH, return DENYMATCH
We require a 3rd state because of the following situation:
The issue - what if, the rule api needs to abort or ignore a rule?:
"match evpn vni xx" route-map filter can be applied to incoming routes
regardless of whether the tunnel type is vxlan or mpls.
This rule should be N/A for mpls based evpn route, but applicable to only
vxlan based evpn route.
Also, this rule should be applicable for routes with VNI label only, and
not for routes without labels. For example, type 3 and type 4 EVPN routes
do not have labels, so, this match cmd should let them through.
Today, the filter produces either a match or nomatch response regardless of
whether it is mpls/vxlan, resulting in either permitting or denying the
route.. So an mpls evpn route may get filtered out incorrectly.
Eg: "route-map RM1 permit 10 ; match evpn vni 20" or
"route-map RM2 deny 20 ; match vni 20"
With the introduction of the 3rd state, we can abort this rule check safely.
How? The rules api can now return RMAP_NOOP to indicate
that it encountered an invalid check, and needs to abort just that rule,
but continue with other rules.
As a result we have a 3rd state:
State3:
If match cmd returned RMAP_NOOP
Then, proceed to other route-map, otherwise if there are no more
rules or if all the rules return RMAP_NOOP, then, return RMAP_PERMITMATCH.
Signed-off-by: Lakshman Krishnamoorthy <lkrishnamoor@vmware.com>
2019-06-19 23:04:36 +02:00
|
|
|
route_map_result_t ret = RMAP_PERMITMATCH;
|
2019-05-13 21:46:05 +02:00
|
|
|
int family;
|
|
|
|
char buf[SRCDEST2STR_BUFFER];
|
|
|
|
const struct prefix *p, *src_p;
|
|
|
|
struct zebra_vrf *zvrf;
|
|
|
|
|
|
|
|
srcdest_rnode_prefixes(rn, &p, &src_p);
|
|
|
|
|
|
|
|
if (rn->p.family == AF_INET)
|
|
|
|
family = AFI_IP;
|
|
|
|
else if (rn->p.family == AF_INET6)
|
|
|
|
family = AFI_IP6;
|
|
|
|
else
|
|
|
|
family = 0;
|
|
|
|
switch (nexthop->type) {
|
|
|
|
case NEXTHOP_TYPE_IFINDEX:
|
|
|
|
ifp = if_lookup_by_index(nexthop->ifindex, nexthop->vrf_id);
|
|
|
|
if (ifp && if_is_operative(ifp))
|
|
|
|
SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
|
|
|
|
else
|
|
|
|
UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
|
|
|
|
break;
|
|
|
|
case NEXTHOP_TYPE_IPV4:
|
|
|
|
case NEXTHOP_TYPE_IPV4_IFINDEX:
|
|
|
|
family = AFI_IP;
|
|
|
|
if (nexthop_active(AFI_IP, re, nexthop, rn))
|
|
|
|
SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
|
|
|
|
else
|
|
|
|
UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
|
|
|
|
break;
|
|
|
|
case NEXTHOP_TYPE_IPV6:
|
|
|
|
family = AFI_IP6;
|
|
|
|
if (nexthop_active(AFI_IP6, re, nexthop, rn))
|
|
|
|
SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
|
|
|
|
else
|
|
|
|
UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
|
|
|
|
break;
|
|
|
|
case NEXTHOP_TYPE_IPV6_IFINDEX:
|
|
|
|
/* RFC 5549, v4 prefix with v6 NH */
|
|
|
|
if (rn->p.family != AF_INET)
|
|
|
|
family = AFI_IP6;
|
|
|
|
if (IN6_IS_ADDR_LINKLOCAL(&nexthop->gate.ipv6)) {
|
|
|
|
ifp = if_lookup_by_index(nexthop->ifindex,
|
|
|
|
nexthop->vrf_id);
|
|
|
|
if (ifp && if_is_operative(ifp))
|
|
|
|
SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
|
|
|
|
else
|
|
|
|
UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
|
|
|
|
} else {
|
|
|
|
if (nexthop_active(AFI_IP6, re, nexthop, rn))
|
|
|
|
SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
|
|
|
|
else
|
|
|
|
UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case NEXTHOP_TYPE_BLACKHOLE:
|
|
|
|
SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (!CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE)) {
|
|
|
|
if (IS_ZEBRA_DEBUG_RIB_DETAILED)
|
|
|
|
zlog_debug("\t%s: Unable to find a active nexthop",
|
|
|
|
__PRETTY_FUNCTION__);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* XXX: What exactly do those checks do? Do we support
|
|
|
|
* e.g. IPv4 routes with IPv6 nexthops or vice versa?
|
|
|
|
*/
|
|
|
|
if (RIB_SYSTEM_ROUTE(re) || (family == AFI_IP && p->family != AF_INET)
|
|
|
|
|| (family == AFI_IP6 && p->family != AF_INET6))
|
|
|
|
return CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
|
|
|
|
|
|
|
|
/* The original code didn't determine the family correctly
|
|
|
|
* e.g. for NEXTHOP_TYPE_IFINDEX. Retrieve the correct afi
|
|
|
|
* from the rib_table_info in those cases.
|
|
|
|
* Possibly it may be better to use only the rib_table_info
|
|
|
|
* in every case.
|
|
|
|
*/
|
|
|
|
if (!family) {
|
|
|
|
rib_table_info_t *info;
|
|
|
|
|
|
|
|
info = srcdest_rnode_table_info(rn);
|
|
|
|
family = info->afi;
|
|
|
|
}
|
|
|
|
|
|
|
|
memset(&nexthop->rmap_src.ipv6, 0, sizeof(union g_addr));
|
|
|
|
|
|
|
|
zvrf = zebra_vrf_lookup_by_id(nexthop->vrf_id);
|
|
|
|
if (!zvrf) {
|
|
|
|
if (IS_ZEBRA_DEBUG_RIB_DETAILED)
|
|
|
|
zlog_debug("\t%s: zvrf is NULL", __PRETTY_FUNCTION__);
|
|
|
|
return CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* It'll get set if required inside */
|
|
|
|
ret = zebra_route_map_check(family, re->type, re->instance, p, nexthop,
|
|
|
|
zvrf, re->tag);
|
|
|
|
if (ret == RMAP_DENYMATCH) {
|
|
|
|
if (IS_ZEBRA_DEBUG_RIB) {
|
|
|
|
srcdest_rnode2str(rn, buf, sizeof(buf));
|
|
|
|
zlog_debug(
|
|
|
|
"%u:%s: Filtering out with NH out %s due to route map",
|
|
|
|
re->vrf_id, buf,
|
|
|
|
ifindex2ifname(nexthop->ifindex,
|
|
|
|
nexthop->vrf_id));
|
|
|
|
}
|
|
|
|
UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
|
|
|
|
}
|
|
|
|
return CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Iterate over all nexthops of the given RIB entry and refresh their
|
2019-02-15 17:39:12 +01:00
|
|
|
* ACTIVE flag. If any nexthop is found to toggle the ACTIVE flag,
|
|
|
|
* the whole re structure is flagged with ROUTE_ENTRY_CHANGED.
|
2019-05-13 21:46:05 +02:00
|
|
|
*
|
|
|
|
* Return value is the new number of active nexthops.
|
|
|
|
*/
|
|
|
|
int nexthop_active_update(struct route_node *rn, struct route_entry *re)
|
|
|
|
{
|
|
|
|
struct nexthop *nexthop;
|
|
|
|
union g_addr prev_src;
|
|
|
|
unsigned int prev_active, new_active;
|
|
|
|
ifindex_t prev_index;
|
2019-02-15 17:39:12 +01:00
|
|
|
uint8_t curr_active = 0;
|
2019-05-13 21:46:05 +02:00
|
|
|
|
|
|
|
UNSET_FLAG(re->status, ROUTE_ENTRY_CHANGED);
|
|
|
|
|
2019-02-13 22:06:48 +01:00
|
|
|
for (nexthop = re->ng->nexthop; nexthop; nexthop = nexthop->next) {
|
2019-05-13 21:46:05 +02:00
|
|
|
/* No protocol daemon provides src and so we're skipping
|
|
|
|
* tracking it */
|
|
|
|
prev_src = nexthop->rmap_src;
|
|
|
|
prev_active = CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
|
|
|
|
prev_index = nexthop->ifindex;
|
|
|
|
/*
|
|
|
|
* We need to respect the multipath_num here
|
|
|
|
* as that what we should be able to install from
|
|
|
|
* a multipath perpsective should not be a data plane
|
|
|
|
* decision point.
|
|
|
|
*/
|
|
|
|
new_active = nexthop_active_check(rn, re, nexthop);
|
|
|
|
if (new_active
|
2019-02-15 17:39:12 +01:00
|
|
|
&& nexthop_group_active_nexthop_num(re->ng)
|
|
|
|
>= zrouter.multipath_num) {
|
2019-05-13 21:46:05 +02:00
|
|
|
UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
|
|
|
|
new_active = 0;
|
|
|
|
}
|
2019-02-15 17:39:12 +01:00
|
|
|
|
2019-05-13 21:46:05 +02:00
|
|
|
if (new_active)
|
2019-02-15 17:39:12 +01:00
|
|
|
curr_active++;
|
|
|
|
|
2019-05-13 21:46:05 +02:00
|
|
|
/* Don't allow src setting on IPv6 addr for now */
|
|
|
|
if (prev_active != new_active || prev_index != nexthop->ifindex
|
|
|
|
|| ((nexthop->type >= NEXTHOP_TYPE_IFINDEX
|
|
|
|
&& nexthop->type < NEXTHOP_TYPE_IPV6)
|
|
|
|
&& prev_src.ipv4.s_addr
|
|
|
|
!= nexthop->rmap_src.ipv4.s_addr)
|
|
|
|
|| ((nexthop->type >= NEXTHOP_TYPE_IPV6
|
|
|
|
&& nexthop->type < NEXTHOP_TYPE_BLACKHOLE)
|
|
|
|
&& !(IPV6_ADDR_SAME(&prev_src.ipv6,
|
|
|
|
&nexthop->rmap_src.ipv6)))
|
2019-07-29 20:53:58 +02:00
|
|
|
|| CHECK_FLAG(re->status, ROUTE_ENTRY_LABELS_CHANGED))
|
2019-05-13 21:46:05 +02:00
|
|
|
SET_FLAG(re->status, ROUTE_ENTRY_CHANGED);
|
|
|
|
}
|
|
|
|
|
2019-02-15 17:39:12 +01:00
|
|
|
return curr_active;
|
2019-05-13 21:46:05 +02:00
|
|
|
}
|
2019-03-06 20:58:57 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* zebra_nhg_install_kernel() - Install Nexthop Group hash entry into kernel
|
|
|
|
*
|
|
|
|
* @nhe: Nexthop Group hash entry to install
|
|
|
|
*/
|
|
|
|
void zebra_nhg_install_kernel(struct nhg_hash_entry *nhe)
|
|
|
|
{
|
2019-03-08 00:11:57 +01:00
|
|
|
if (!CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED)) {
|
|
|
|
nhe->is_kernel_nh = false;
|
|
|
|
int ret = dplane_nexthop_add(nhe);
|
|
|
|
switch (ret) {
|
|
|
|
case ZEBRA_DPLANE_REQUEST_QUEUED:
|
|
|
|
SET_FLAG(nhe->flags, NEXTHOP_GROUP_QUEUED);
|
|
|
|
break;
|
|
|
|
case ZEBRA_DPLANE_REQUEST_FAILURE:
|
|
|
|
flog_err(
|
|
|
|
EC_ZEBRA_DP_INSTALL_FAIL,
|
|
|
|
"Failed to install Nexthop ID (%u) into the kernel",
|
|
|
|
nhe->id);
|
|
|
|
break;
|
|
|
|
case ZEBRA_DPLANE_REQUEST_SUCCESS:
|
|
|
|
SET_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* zebra_nhg_uninstall_kernel() - Uninstall Nexthop Group hash entry into kernel
|
|
|
|
*
|
|
|
|
* @nhe: Nexthop Group hash entry to uninstall
|
|
|
|
*/
|
|
|
|
void zebra_nhg_uninstall_kernel(struct nhg_hash_entry *nhe)
|
|
|
|
{
|
|
|
|
if (CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED)) {
|
|
|
|
int ret = dplane_nexthop_delete(nhe);
|
|
|
|
switch (ret) {
|
|
|
|
case ZEBRA_DPLANE_REQUEST_QUEUED:
|
|
|
|
SET_FLAG(nhe->flags, NEXTHOP_GROUP_QUEUED);
|
|
|
|
break;
|
|
|
|
case ZEBRA_DPLANE_REQUEST_FAILURE:
|
|
|
|
flog_err(
|
|
|
|
EC_ZEBRA_DP_DELETE_FAIL,
|
|
|
|
"Failed to uninstall Nexthop ID (%u) from the kernel",
|
|
|
|
nhe->id);
|
|
|
|
break;
|
|
|
|
case ZEBRA_DPLANE_REQUEST_SUCCESS:
|
|
|
|
UNSET_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-03-08 16:35:38 +01:00
|
|
|
/**
|
|
|
|
* zebra_nhg_uninstall_created() - Uninstall nexthops we created in the kernel
|
|
|
|
*
|
|
|
|
* @nhe: Nexthop group hash entry
|
|
|
|
*/
|
|
|
|
static void zebra_nhg_uninstall_created(struct hash_bucket *bucket, void *arg)
|
|
|
|
{
|
|
|
|
struct nhg_hash_entry *nhe = NULL;
|
|
|
|
|
|
|
|
nhe = (struct nhg_hash_entry *)bucket->data;
|
|
|
|
|
|
|
|
if (nhe && !nhe->is_kernel_nh)
|
|
|
|
zebra_nhg_uninstall_kernel(nhe);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* zebra_nhg_cleanup_tables() - Iterate over our tables to uninstall nh's
|
|
|
|
* we created
|
|
|
|
*/
|
|
|
|
void zebra_nhg_cleanup_tables(void)
|
|
|
|
{
|
|
|
|
hash_iterate(zrouter.nhgs, zebra_nhg_uninstall_created, NULL);
|
|
|
|
}
|
|
|
|
|
2019-03-08 00:15:30 +01:00
|
|
|
/**
|
|
|
|
* zebra_nhg_dplane_result() - Process dplane result
|
|
|
|
*
|
|
|
|
* @ctx: Dataplane context
|
|
|
|
*/
|
|
|
|
void zebra_nhg_dplane_result(struct zebra_dplane_ctx *ctx)
|
|
|
|
{
|
|
|
|
enum dplane_op_e op;
|
|
|
|
enum zebra_dplane_result status;
|
|
|
|
uint32_t id = 0;
|
|
|
|
struct nhg_hash_entry *nhe = NULL;
|
|
|
|
|
|
|
|
op = dplane_ctx_get_op(ctx);
|
|
|
|
status = dplane_ctx_get_status(ctx);
|
|
|
|
|
2019-05-14 02:10:34 +02:00
|
|
|
id = dplane_ctx_get_nhe_id(ctx);
|
2019-03-08 00:15:30 +01:00
|
|
|
nhe = zebra_nhg_lookup_id(id);
|
|
|
|
|
|
|
|
if (nhe) {
|
2019-05-14 22:56:38 +02:00
|
|
|
UNSET_FLAG(nhe->flags, NEXTHOP_GROUP_QUEUED);
|
2019-03-08 00:15:30 +01:00
|
|
|
if (IS_ZEBRA_DEBUG_DPLANE_DETAIL)
|
|
|
|
zlog_debug(
|
|
|
|
"Nexthop dplane ctx %p, op %s, nexthop ID (%u), result %s",
|
|
|
|
ctx, dplane_op2str(op), nhe->id,
|
|
|
|
dplane_res2str(status));
|
|
|
|
|
|
|
|
switch (op) {
|
|
|
|
case DPLANE_OP_NH_DELETE:
|
|
|
|
if (status == ZEBRA_DPLANE_REQUEST_SUCCESS) {
|
|
|
|
UNSET_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED);
|
|
|
|
} else {
|
|
|
|
flog_err(
|
|
|
|
EC_ZEBRA_DP_DELETE_FAIL,
|
|
|
|
"Failed to uninstall Nexthop ID (%u) from the kernel",
|
|
|
|
nhe->id);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case DPLANE_OP_NH_INSTALL:
|
|
|
|
case DPLANE_OP_NH_UPDATE:
|
|
|
|
if (status == ZEBRA_DPLANE_REQUEST_SUCCESS) {
|
|
|
|
SET_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED);
|
|
|
|
} else {
|
|
|
|
flog_err(
|
|
|
|
EC_ZEBRA_DP_INSTALL_FAIL,
|
|
|
|
"Failed to install Nexthop ID (%u) into the kernel",
|
|
|
|
nhe->id);
|
|
|
|
UNSET_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED);
|
|
|
|
}
|
|
|
|
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_NONE:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
dplane_ctx_fini(&ctx);
|
|
|
|
|
|
|
|
} else {
|
|
|
|
flog_err(
|
|
|
|
EC_ZEBRA_NHG_SYNC,
|
|
|
|
"%s operation preformed on Nexthop ID (%u) in the kernel, that we no longer have in our table",
|
|
|
|
dplane_op2str(op), id);
|
2019-03-06 20:58:57 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|