mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-08-14 12:25:02 +00:00
Merge pull request #6783 from opensourcerouting/feature/sr-te
lib, zebra: Add SR-TE policy infrastructure to zebra
This commit is contained in:
commit
271ac28499
@ -367,6 +367,8 @@ struct cmd_node {
|
||||
#define SHOW_STR "Show running system information\n"
|
||||
#define IP_STR "IP information\n"
|
||||
#define IPV6_STR "IPv6 information\n"
|
||||
#define SRTE_STR "SR-TE information\n"
|
||||
#define SRTE_COLOR_STR "SR-TE Color information\n"
|
||||
#define NO_STR "Negate a command or set its defaults\n"
|
||||
#define REDIST_STR "Redistribute information from another routing protocol\n"
|
||||
#define CLEAR_STR "Reset functions\n"
|
||||
|
39
lib/ipaddr.h
39
lib/ipaddr.h
@ -25,6 +25,8 @@
|
||||
|
||||
#include <zebra.h>
|
||||
|
||||
#include "lib/log.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
@ -59,6 +61,18 @@ struct ipaddr {
|
||||
#define IPADDRSZ(p) \
|
||||
(IS_IPADDR_V4((p)) ? sizeof(struct in_addr) : sizeof(struct in6_addr))
|
||||
|
||||
static inline int ipaddr_family(const struct ipaddr *ip)
|
||||
{
|
||||
switch (ip->ipa_type) {
|
||||
case IPADDR_V4:
|
||||
return AF_INET;
|
||||
case IPADDR_V6:
|
||||
return AF_INET6;
|
||||
default:
|
||||
return AF_UNSPEC;
|
||||
}
|
||||
}
|
||||
|
||||
static inline int str2ipaddr(const char *str, struct ipaddr *ip)
|
||||
{
|
||||
int ret;
|
||||
@ -131,6 +145,31 @@ static inline bool ipaddr_isset(struct ipaddr *ip)
|
||||
return (0 != memcmp(&a, ip, sizeof(struct ipaddr)));
|
||||
}
|
||||
|
||||
/*
|
||||
* generic ordering comparison between IP addresses
|
||||
*/
|
||||
static inline int ipaddr_cmp(const struct ipaddr *a, const struct ipaddr *b)
|
||||
{
|
||||
uint32_t va, vb;
|
||||
va = a->ipa_type;
|
||||
vb = b->ipa_type;
|
||||
if (va != vb)
|
||||
return (va < vb) ? -1 : 1;
|
||||
switch (a->ipa_type) {
|
||||
case IPADDR_V4:
|
||||
va = ntohl(a->ipaddr_v4.s_addr);
|
||||
vb = ntohl(b->ipaddr_v4.s_addr);
|
||||
if (va != vb)
|
||||
return (va < vb) ? -1 : 1;
|
||||
return 0;
|
||||
case IPADDR_V6:
|
||||
return memcmp((void *)&a->ipaddr_v6, (void *)&b->ipaddr_v6,
|
||||
sizeof(a->ipaddr_v6));
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef _FRR_ATTRIBUTE_PRINTFRR
|
||||
#pragma FRR printfrr_ext "%pIA" (struct ipaddr *)
|
||||
#endif
|
||||
|
@ -384,6 +384,9 @@ static const struct zebra_desc_table command_types[] = {
|
||||
DESC_ENTRY(ZEBRA_MPLS_LABELS_ADD),
|
||||
DESC_ENTRY(ZEBRA_MPLS_LABELS_DELETE),
|
||||
DESC_ENTRY(ZEBRA_MPLS_LABELS_REPLACE),
|
||||
DESC_ENTRY(ZEBRA_SR_POLICY_SET),
|
||||
DESC_ENTRY(ZEBRA_SR_POLICY_DELETE),
|
||||
DESC_ENTRY(ZEBRA_SR_POLICY_NOTIFY_STATUS),
|
||||
DESC_ENTRY(ZEBRA_IPMR_ROUTE_STATS),
|
||||
DESC_ENTRY(ZEBRA_LABEL_MANAGER_CONNECT),
|
||||
DESC_ENTRY(ZEBRA_LABEL_MANAGER_CONNECT_ASYNC),
|
||||
|
@ -129,6 +129,7 @@ enum lsp_types_t {
|
||||
ZEBRA_LSP_OSPF_SR = 4,/* OSPF Segment Routing LSP. */
|
||||
ZEBRA_LSP_ISIS_SR = 5,/* IS-IS Segment Routing LSP. */
|
||||
ZEBRA_LSP_SHARP = 6, /* Identifier for test protocol */
|
||||
ZEBRA_LSP_SRTE = 7, /* SR-TE LSP */
|
||||
};
|
||||
|
||||
/* Functions for basic label operations. */
|
||||
|
@ -152,6 +152,11 @@ static int _nexthop_cmp_no_labels(const struct nexthop *next1,
|
||||
break;
|
||||
}
|
||||
|
||||
if (next1->srte_color < next2->srte_color)
|
||||
return -1;
|
||||
if (next1->srte_color > next2->srte_color)
|
||||
return 1;
|
||||
|
||||
ret = _nexthop_source_cmp(next1, next2);
|
||||
if (ret != 0)
|
||||
goto done;
|
||||
@ -643,6 +648,7 @@ void nexthop_copy_no_recurse(struct nexthop *copy,
|
||||
if (copy->backup_num > 0)
|
||||
memcpy(copy->backup_idx, nexthop->backup_idx, copy->backup_num);
|
||||
|
||||
copy->srte_color = nexthop->srte_color;
|
||||
memcpy(©->gate, &nexthop->gate, sizeof(nexthop->gate));
|
||||
memcpy(©->src, &nexthop->src, sizeof(nexthop->src));
|
||||
memcpy(©->rmap_src, &nexthop->rmap_src, sizeof(nexthop->rmap_src));
|
||||
|
@ -98,6 +98,7 @@ struct nexthop {
|
||||
*/
|
||||
#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_FLAG_SRTE (1 << 7) /* SR-TE color used for BGP traffic */
|
||||
|
||||
#define NEXTHOP_IS_ACTIVE(flags) \
|
||||
(CHECK_FLAG(flags, NEXTHOP_FLAG_ACTIVE) \
|
||||
@ -141,6 +142,9 @@ struct nexthop {
|
||||
union {
|
||||
vni_t vni;
|
||||
} nh_encap;
|
||||
|
||||
/* SR-TE color used for matching SR-TE policies */
|
||||
uint32_t srte_color;
|
||||
};
|
||||
|
||||
/* Utility to append one nexthop to another. */
|
||||
|
@ -2046,18 +2046,21 @@ void *nb_running_unset_entry(const struct lyd_node *dnode)
|
||||
return entry;
|
||||
}
|
||||
|
||||
void *nb_running_get_entry(const struct lyd_node *dnode, const char *xpath,
|
||||
bool abort_if_not_found)
|
||||
static void *nb_running_get_entry_worker(const struct lyd_node *dnode,
|
||||
const char *xpath,
|
||||
bool abort_if_not_found,
|
||||
bool rec_search)
|
||||
{
|
||||
const struct lyd_node *orig_dnode = dnode;
|
||||
char xpath_buf[XPATH_MAXLEN];
|
||||
bool rec_flag = true;
|
||||
|
||||
assert(dnode || xpath);
|
||||
|
||||
if (!dnode)
|
||||
dnode = yang_dnode_get(running_config->dnode, xpath);
|
||||
|
||||
while (dnode) {
|
||||
while (rec_flag && dnode) {
|
||||
struct nb_config_entry *config, s;
|
||||
|
||||
yang_dnode_get_path(dnode, s.xpath, sizeof(s.xpath));
|
||||
@ -2065,6 +2068,8 @@ void *nb_running_get_entry(const struct lyd_node *dnode, const char *xpath,
|
||||
if (config)
|
||||
return config->entry;
|
||||
|
||||
rec_flag = rec_search;
|
||||
|
||||
dnode = dnode->parent;
|
||||
}
|
||||
|
||||
@ -2078,6 +2083,20 @@ void *nb_running_get_entry(const struct lyd_node *dnode, const char *xpath,
|
||||
abort();
|
||||
}
|
||||
|
||||
void *nb_running_get_entry(const struct lyd_node *dnode, const char *xpath,
|
||||
bool abort_if_not_found)
|
||||
{
|
||||
return nb_running_get_entry_worker(dnode, xpath, abort_if_not_found,
|
||||
true);
|
||||
}
|
||||
|
||||
void *nb_running_get_entry_non_rec(const struct lyd_node *dnode,
|
||||
const char *xpath, bool abort_if_not_found)
|
||||
{
|
||||
return nb_running_get_entry_worker(dnode, xpath, abort_if_not_found,
|
||||
false);
|
||||
}
|
||||
|
||||
/* Logging functions. */
|
||||
const char *nb_event_name(enum nb_event event)
|
||||
{
|
||||
|
@ -1164,6 +1164,14 @@ extern void *nb_running_unset_entry(const struct lyd_node *dnode);
|
||||
extern void *nb_running_get_entry(const struct lyd_node *dnode,
|
||||
const char *xpath, bool abort_if_not_found);
|
||||
|
||||
/*
|
||||
* Same as 'nb_running_get_entry', but doesn't search within parent nodes
|
||||
* recursively if an user point is not found.
|
||||
*/
|
||||
extern void *nb_running_get_entry_non_rec(const struct lyd_node *dnode,
|
||||
const char *xpath,
|
||||
bool abort_if_not_found);
|
||||
|
||||
/*
|
||||
* Return a human-readable string representing a northbound event.
|
||||
*
|
||||
|
@ -24,6 +24,7 @@
|
||||
#define _ZEBRA_PRIVS_H
|
||||
|
||||
#include <pthread.h>
|
||||
#include <stdint.h>
|
||||
#include "lib/queue.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
@ -85,6 +85,7 @@ ZEBRA_ROUTE_BFD, bfd, bfdd, '-', 0, 0, 0, "BFD"
|
||||
ZEBRA_ROUTE_OPENFABRIC, openfabric, fabricd, 'f', 1, 1, 1, "OpenFabric"
|
||||
ZEBRA_ROUTE_VRRP, vrrp, vrrpd, '-', 0, 0, 0, "VRRP"
|
||||
ZEBRA_ROUTE_NHG, nhg, none, '-', 0, 0, 0, "Nexthop Group"
|
||||
ZEBRA_ROUTE_SRTE, srte, none, '-', 0, 0, 0, "SR-TE"
|
||||
ZEBRA_ROUTE_ALL, wildcard, none, '-', 0, 0, 0, "-"
|
||||
|
||||
|
||||
|
@ -263,6 +263,24 @@ void route_map_no_match_tag_hook(int (*func)(
|
||||
rmap_match_set_hook.no_match_tag = func;
|
||||
}
|
||||
|
||||
/* set sr-te color */
|
||||
void route_map_set_srte_color_hook(int (*func)(struct vty *vty,
|
||||
struct route_map_index *index,
|
||||
const char *command,
|
||||
const char *arg))
|
||||
{
|
||||
rmap_match_set_hook.set_srte_color = func;
|
||||
}
|
||||
|
||||
/* no set sr-te color */
|
||||
void route_map_no_set_srte_color_hook(int (*func)(struct vty *vty,
|
||||
struct route_map_index *index,
|
||||
const char *command,
|
||||
const char *arg))
|
||||
{
|
||||
rmap_match_set_hook.no_set_srte_color = func;
|
||||
}
|
||||
|
||||
/* set ip nexthop */
|
||||
void route_map_set_ip_nexthop_hook(int (*func)(struct vty *vty,
|
||||
struct route_map_index *index,
|
||||
@ -2613,6 +2631,47 @@ static unsigned int route_map_dep_data_hash_make_key(const void *p)
|
||||
return string_hash_make(dep_data->rname);
|
||||
}
|
||||
|
||||
DEFUN (set_srte_color,
|
||||
set_srte_color_cmd,
|
||||
"set sr-te color [(1-4294967295)]",
|
||||
SET_STR
|
||||
SRTE_STR
|
||||
SRTE_COLOR_STR
|
||||
"Color of the SR-TE Policies to match with\n")
|
||||
{
|
||||
VTY_DECLVAR_CONTEXT(route_map_index, index);
|
||||
int idx = 0;
|
||||
char *arg = argv_find(argv, argc, "(1-4294967295)", &idx)
|
||||
? argv[idx]->arg
|
||||
: NULL;
|
||||
|
||||
if (rmap_match_set_hook.set_srte_color)
|
||||
return rmap_match_set_hook.set_srte_color(vty, index,
|
||||
"sr-te color", arg);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN (no_set_srte_color,
|
||||
no_set_srte_color_cmd,
|
||||
"no set sr-te color [(1-4294967295)]",
|
||||
NO_STR
|
||||
SET_STR
|
||||
SRTE_STR
|
||||
SRTE_COLOR_STR
|
||||
"Color of the SR-TE Policies to match with\n")
|
||||
{
|
||||
VTY_DECLVAR_CONTEXT(route_map_index, index);
|
||||
int idx = 0;
|
||||
char *arg = argv_find(argv, argc, "(1-4294967295)", &idx)
|
||||
? argv[idx]->arg
|
||||
: NULL;
|
||||
|
||||
if (rmap_match_set_hook.no_set_srte_color)
|
||||
return rmap_match_set_hook.no_set_srte_color(
|
||||
vty, index, "sr-te color", arg);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
static void *route_map_dep_hash_alloc(void *p)
|
||||
{
|
||||
char *dep_name = (char *)p;
|
||||
@ -3237,5 +3296,8 @@ void route_map_init(void)
|
||||
install_element(RMAP_NODE, &routemap_optimization_cmd);
|
||||
install_element(RMAP_NODE, &no_routemap_optimization_cmd);
|
||||
|
||||
install_element(RMAP_NODE, &set_srte_color_cmd);
|
||||
install_element(RMAP_NODE, &no_set_srte_color_cmd);
|
||||
|
||||
install_element(ENABLE_NODE, &show_route_map_pfx_tbl_cmd);
|
||||
}
|
||||
|
@ -424,6 +424,14 @@ extern void route_map_match_tag_hook(int (*func)(
|
||||
extern void route_map_no_match_tag_hook(int (*func)(
|
||||
struct vty *vty, struct route_map_index *index, const char *command,
|
||||
const char *arg, route_map_event_t type));
|
||||
/* set sr-te color */
|
||||
extern void route_map_set_srte_color_hook(
|
||||
int (*func)(struct vty *vty, struct route_map_index *index,
|
||||
const char *command, const char *arg));
|
||||
/* no set sr-te color */
|
||||
extern void route_map_no_set_srte_color_hook(
|
||||
int (*func)(struct vty *vty, struct route_map_index *index,
|
||||
const char *command, const char *arg));
|
||||
/* set ip nexthop */
|
||||
extern void route_map_set_ip_nexthop_hook(
|
||||
int (*func)(struct vty *vty, struct route_map_index *index,
|
||||
@ -606,6 +614,14 @@ struct route_map_match_set_hooks {
|
||||
const char *command, const char *arg,
|
||||
route_map_event_t type);
|
||||
|
||||
/* set sr-te color */
|
||||
int (*set_srte_color)(struct vty *vty, struct route_map_index *index,
|
||||
const char *command, const char *arg);
|
||||
|
||||
/* no set sr-te color */
|
||||
int (*no_set_srte_color)(struct vty *vty, struct route_map_index *index,
|
||||
const char *command, const char *arg);
|
||||
|
||||
/* set ip nexthop */
|
||||
int (*set_ip_nexthop)(struct vty *vty, struct route_map_index *index,
|
||||
const char *command, const char *arg);
|
||||
|
56
lib/srte.h
Normal file
56
lib/srte.h
Normal file
@ -0,0 +1,56 @@
|
||||
/*
|
||||
* SR-TE definitions
|
||||
* Copyright 2020 NetDef Inc.
|
||||
* Sascha Kattelmann
|
||||
*
|
||||
* This file is part of GNU Zebra.
|
||||
*
|
||||
* GNU Zebra 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.
|
||||
*
|
||||
* GNU Zebra 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 this program; see the file COPYING; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef _FRR_SRTE_H
|
||||
#define _FRR_SRTE_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define SRTE_POLICY_NAME_MAX_LENGTH 64
|
||||
|
||||
enum zebra_sr_policy_status {
|
||||
ZEBRA_SR_POLICY_UP = 0,
|
||||
ZEBRA_SR_POLICY_DOWN,
|
||||
};
|
||||
|
||||
static inline int sr_policy_compare(const struct ipaddr *a_endpoint,
|
||||
const struct ipaddr *b_endpoint,
|
||||
uint32_t a_color, uint32_t b_color)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = ipaddr_cmp(a_endpoint, b_endpoint);
|
||||
if (ret < 0)
|
||||
return -1;
|
||||
if (ret > 0)
|
||||
return 1;
|
||||
|
||||
return a_color - b_color;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _FRR_SRTE_H */
|
58
lib/stream.c
58
lib/stream.c
@ -586,6 +586,43 @@ uint32_t stream_get_ipv4(struct stream *s)
|
||||
return l;
|
||||
}
|
||||
|
||||
bool stream_get_ipaddr(struct stream *s, struct ipaddr *ip)
|
||||
{
|
||||
uint16_t ipa_len;
|
||||
|
||||
STREAM_VERIFY_SANE(s);
|
||||
|
||||
/* Get address type. */
|
||||
if (STREAM_READABLE(s) < sizeof(uint16_t)) {
|
||||
STREAM_BOUND_WARN2(s, "get ipaddr");
|
||||
return false;
|
||||
}
|
||||
ip->ipa_type = stream_getw(s);
|
||||
|
||||
/* Get address value. */
|
||||
switch (ip->ipa_type) {
|
||||
case IPADDR_V4:
|
||||
ipa_len = IPV4_MAX_BYTELEN;
|
||||
break;
|
||||
case IPADDR_V6:
|
||||
ipa_len = IPV6_MAX_BYTELEN;
|
||||
break;
|
||||
default:
|
||||
flog_err(EC_LIB_DEVELOPMENT,
|
||||
"%s: unknown ip address-family: %u", __func__,
|
||||
ip->ipa_type);
|
||||
return false;
|
||||
}
|
||||
if (STREAM_READABLE(s) < ipa_len) {
|
||||
STREAM_BOUND_WARN2(s, "get ipaddr");
|
||||
return false;
|
||||
}
|
||||
memcpy(&ip->ip, s->data + s->getp, ipa_len);
|
||||
s->getp += ipa_len;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
float stream_getf(struct stream *s)
|
||||
{
|
||||
union {
|
||||
@ -852,6 +889,27 @@ int stream_put_in_addr(struct stream *s, const struct in_addr *addr)
|
||||
return sizeof(uint32_t);
|
||||
}
|
||||
|
||||
bool stream_put_ipaddr(struct stream *s, struct ipaddr *ip)
|
||||
{
|
||||
stream_putw(s, ip->ipa_type);
|
||||
|
||||
switch (ip->ipa_type) {
|
||||
case IPADDR_V4:
|
||||
stream_put_in_addr(s, &ip->ipaddr_v4);
|
||||
break;
|
||||
case IPADDR_V6:
|
||||
stream_write(s, (uint8_t *)&ip->ipaddr_v6, 16);
|
||||
break;
|
||||
default:
|
||||
flog_err(EC_LIB_DEVELOPMENT,
|
||||
"%s: unknown ip address-family: %u", __func__,
|
||||
ip->ipa_type);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Put in_addr at location in the stream. */
|
||||
int stream_put_in_addr_at(struct stream *s, size_t putp,
|
||||
const struct in_addr *addr)
|
||||
|
@ -189,6 +189,7 @@ extern int stream_putq(struct stream *, uint64_t);
|
||||
extern int stream_putq_at(struct stream *, size_t, uint64_t);
|
||||
extern int stream_put_ipv4(struct stream *, uint32_t);
|
||||
extern int stream_put_in_addr(struct stream *s, const struct in_addr *addr);
|
||||
extern bool stream_put_ipaddr(struct stream *s, struct ipaddr *ip);
|
||||
extern int stream_put_in_addr_at(struct stream *s, size_t putp,
|
||||
const struct in_addr *addr);
|
||||
extern int stream_put_in6_addr_at(struct stream *s, size_t putp,
|
||||
@ -219,6 +220,7 @@ extern uint64_t stream_getq(struct stream *);
|
||||
extern uint64_t stream_getq_from(struct stream *, size_t);
|
||||
bool stream_getq2(struct stream *s, uint64_t *q);
|
||||
extern uint32_t stream_get_ipv4(struct stream *);
|
||||
extern bool stream_get_ipaddr(struct stream *s, struct ipaddr *ip);
|
||||
|
||||
/* IEEE-754 floats */
|
||||
extern float stream_getf(struct stream *);
|
||||
@ -439,6 +441,12 @@ static inline const uint8_t *ptr_get_be32(const uint8_t *ptr, uint32_t *out)
|
||||
(P) = _pval; \
|
||||
} while (0)
|
||||
|
||||
#define STREAM_GET_IPADDR(S, P) \
|
||||
do { \
|
||||
if (!stream_get_ipaddr((S), (P))) \
|
||||
goto stream_failure; \
|
||||
} while (0)
|
||||
|
||||
#define STREAM_GET(P, STR, SIZE) \
|
||||
do { \
|
||||
if (!stream_get2((P), (STR), (SIZE))) \
|
||||
|
@ -242,6 +242,7 @@ pkginclude_HEADERS += \
|
||||
lib/sockunion.h \
|
||||
lib/spf_backoff.h \
|
||||
lib/srcdest_table.h \
|
||||
lib/srte.h \
|
||||
lib/stream.h \
|
||||
lib/systemd.h \
|
||||
lib/table.h \
|
||||
|
137
lib/zclient.c
137
lib/zclient.c
@ -39,6 +39,7 @@
|
||||
#include "pbr.h"
|
||||
#include "nexthop_group.h"
|
||||
#include "lib_errors.h"
|
||||
#include "srte.h"
|
||||
|
||||
DEFINE_MTYPE_STATIC(LIB, ZCLIENT, "Zclient")
|
||||
DEFINE_MTYPE_STATIC(LIB, REDIST_INST, "Redistribution instance IDs")
|
||||
@ -900,7 +901,7 @@ static void zapi_nexthop_group_sort(struct zapi_nexthop *nh_grp,
|
||||
* Encode a single zapi nexthop
|
||||
*/
|
||||
int zapi_nexthop_encode(struct stream *s, const struct zapi_nexthop *api_nh,
|
||||
uint32_t api_flags)
|
||||
uint32_t api_flags, uint32_t api_message)
|
||||
{
|
||||
int i, ret = 0;
|
||||
int nh_flags = api_nh->flags;
|
||||
@ -964,6 +965,10 @@ int zapi_nexthop_encode(struct stream *s, const struct zapi_nexthop *api_nh,
|
||||
stream_put(s, &(api_nh->rmac),
|
||||
sizeof(struct ethaddr));
|
||||
|
||||
/* Color for Segment Routing TE. */
|
||||
if (CHECK_FLAG(api_message, ZAPI_MESSAGE_SRTE))
|
||||
stream_putl(s, api_nh->srte_color);
|
||||
|
||||
/* Index of backup nexthop */
|
||||
if (CHECK_FLAG(nh_flags, ZAPI_NEXTHOP_FLAG_HAS_BACKUP)) {
|
||||
/* Validate backup count */
|
||||
@ -1000,7 +1005,7 @@ int zapi_route_encode(uint8_t cmd, struct stream *s, struct zapi_route *api)
|
||||
|
||||
stream_putw(s, api->instance);
|
||||
stream_putl(s, api->flags);
|
||||
stream_putc(s, api->message);
|
||||
stream_putl(s, api->message);
|
||||
|
||||
if (api->safi < SAFI_UNICAST || api->safi >= SAFI_MAX) {
|
||||
flog_err(EC_LIB_ZAPI_ENCODE,
|
||||
@ -1061,7 +1066,9 @@ int zapi_route_encode(uint8_t cmd, struct stream *s, struct zapi_route *api)
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (zapi_nexthop_encode(s, api_nh, api->flags) != 0)
|
||||
if (zapi_nexthop_encode(s, api_nh, api->flags,
|
||||
api->message)
|
||||
!= 0)
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
@ -1105,7 +1112,9 @@ int zapi_route_encode(uint8_t cmd, struct stream *s, struct zapi_route *api)
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (zapi_nexthop_encode(s, api_nh, api->flags) != 0)
|
||||
if (zapi_nexthop_encode(s, api_nh, api->flags,
|
||||
api->message)
|
||||
!= 0)
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
@ -1132,7 +1141,7 @@ int zapi_route_encode(uint8_t cmd, struct stream *s, struct zapi_route *api)
|
||||
* Decode a single zapi nexthop object
|
||||
*/
|
||||
static int zapi_nexthop_decode(struct stream *s, struct zapi_nexthop *api_nh,
|
||||
uint32_t api_flags)
|
||||
uint32_t api_flags, uint32_t api_message)
|
||||
{
|
||||
int i, ret = -1;
|
||||
|
||||
@ -1185,6 +1194,10 @@ static int zapi_nexthop_decode(struct stream *s, struct zapi_nexthop *api_nh,
|
||||
STREAM_GET(&(api_nh->rmac), s,
|
||||
sizeof(struct ethaddr));
|
||||
|
||||
/* Color for Segment Routing TE. */
|
||||
if (CHECK_FLAG(api_message, ZAPI_MESSAGE_SRTE))
|
||||
STREAM_GETL(s, api_nh->srte_color);
|
||||
|
||||
/* Backup nexthop index */
|
||||
if (CHECK_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_HAS_BACKUP)) {
|
||||
STREAM_GETC(s, api_nh->backup_num);
|
||||
@ -1222,7 +1235,7 @@ int zapi_route_decode(struct stream *s, struct zapi_route *api)
|
||||
|
||||
STREAM_GETW(s, api->instance);
|
||||
STREAM_GETL(s, api->flags);
|
||||
STREAM_GETC(s, api->message);
|
||||
STREAM_GETL(s, api->message);
|
||||
STREAM_GETC(s, api->safi);
|
||||
if (api->safi < SAFI_UNICAST || api->safi >= SAFI_MAX) {
|
||||
flog_err(EC_LIB_ZAPI_ENCODE,
|
||||
@ -1297,7 +1310,9 @@ int zapi_route_decode(struct stream *s, struct zapi_route *api)
|
||||
for (i = 0; i < api->nexthop_num; i++) {
|
||||
api_nh = &api->nexthops[i];
|
||||
|
||||
if (zapi_nexthop_decode(s, api_nh, api->flags) != 0)
|
||||
if (zapi_nexthop_decode(s, api_nh, api->flags,
|
||||
api->message)
|
||||
!= 0)
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
@ -1315,7 +1330,9 @@ int zapi_route_decode(struct stream *s, struct zapi_route *api)
|
||||
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)
|
||||
if (zapi_nexthop_decode(s, api_nh, api->flags,
|
||||
api->message)
|
||||
!= 0)
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
@ -1502,6 +1519,7 @@ struct nexthop *nexthop_from_zapi_nexthop(const struct zapi_nexthop *znh)
|
||||
n->vrf_id = znh->vrf_id;
|
||||
n->ifindex = znh->ifindex;
|
||||
n->gate = znh->gate;
|
||||
n->srte_color = znh->srte_color;
|
||||
|
||||
/*
|
||||
* This function currently handles labels
|
||||
@ -1619,6 +1637,7 @@ bool zapi_nexthop_update_decode(struct stream *s, struct zapi_route *nhr)
|
||||
|
||||
memset(nhr, 0, sizeof(*nhr));
|
||||
|
||||
STREAM_GETL(s, nhr->message);
|
||||
STREAM_GETW(s, nhr->prefix.family);
|
||||
STREAM_GETC(s, nhr->prefix.prefixlen);
|
||||
switch (nhr->prefix.family) {
|
||||
@ -1631,6 +1650,8 @@ bool zapi_nexthop_update_decode(struct stream *s, struct zapi_route *nhr)
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (CHECK_FLAG(nhr->message, ZAPI_MESSAGE_SRTE))
|
||||
STREAM_GETL(s, nhr->srte_color);
|
||||
|
||||
STREAM_GETC(s, nhr->type);
|
||||
STREAM_GETW(s, nhr->instance);
|
||||
@ -1639,7 +1660,7 @@ bool zapi_nexthop_update_decode(struct stream *s, struct zapi_route *nhr)
|
||||
STREAM_GETC(s, nhr->nexthop_num);
|
||||
|
||||
for (i = 0; i < nhr->nexthop_num; i++) {
|
||||
if (zapi_nexthop_decode(s, &(nhr->nexthops[i]), 0) != 0)
|
||||
if (zapi_nexthop_decode(s, &(nhr->nexthops[i]), 0, 0) != 0)
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -2835,6 +2856,92 @@ int tm_release_table_chunk(struct zclient *zclient, uint32_t start,
|
||||
return zclient_send_message(zclient);
|
||||
}
|
||||
|
||||
int zebra_send_sr_policy(struct zclient *zclient, int cmd,
|
||||
struct zapi_sr_policy *zp)
|
||||
{
|
||||
if (zapi_sr_policy_encode(zclient->obuf, cmd, zp) < 0)
|
||||
return -1;
|
||||
return zclient_send_message(zclient);
|
||||
}
|
||||
|
||||
int zapi_sr_policy_encode(struct stream *s, int cmd, struct zapi_sr_policy *zp)
|
||||
{
|
||||
struct zapi_srte_tunnel *zt = &zp->segment_list;
|
||||
|
||||
stream_reset(s);
|
||||
|
||||
zclient_create_header(s, cmd, VRF_DEFAULT);
|
||||
stream_putl(s, zp->color);
|
||||
stream_put_ipaddr(s, &zp->endpoint);
|
||||
stream_write(s, &zp->name, SRTE_POLICY_NAME_MAX_LENGTH);
|
||||
|
||||
stream_putc(s, zt->type);
|
||||
stream_putl(s, zt->local_label);
|
||||
|
||||
if (zt->label_num > MPLS_MAX_LABELS) {
|
||||
flog_err(EC_LIB_ZAPI_ENCODE,
|
||||
"%s: label %u: can't encode %u labels (maximum is %u)",
|
||||
__func__, zt->local_label, zt->label_num,
|
||||
MPLS_MAX_LABELS);
|
||||
return -1;
|
||||
}
|
||||
stream_putw(s, zt->label_num);
|
||||
|
||||
for (int i = 0; i < zt->label_num; i++)
|
||||
stream_putl(s, zt->labels[i]);
|
||||
|
||||
/* Put length at the first point of the stream. */
|
||||
stream_putw_at(s, 0, stream_get_endp(s));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int zapi_sr_policy_decode(struct stream *s, struct zapi_sr_policy *zp)
|
||||
{
|
||||
memset(zp, 0, sizeof(*zp));
|
||||
|
||||
struct zapi_srte_tunnel *zt = &zp->segment_list;
|
||||
|
||||
STREAM_GETL(s, zp->color);
|
||||
STREAM_GET_IPADDR(s, &zp->endpoint);
|
||||
STREAM_GET(&zp->name, s, SRTE_POLICY_NAME_MAX_LENGTH);
|
||||
|
||||
/* segment list of active candidate path */
|
||||
STREAM_GETC(s, zt->type);
|
||||
STREAM_GETL(s, zt->local_label);
|
||||
STREAM_GETW(s, zt->label_num);
|
||||
if (zt->label_num > MPLS_MAX_LABELS) {
|
||||
flog_err(EC_LIB_ZAPI_ENCODE,
|
||||
"%s: label %u: can't decode %u labels (maximum is %u)",
|
||||
__func__, zt->local_label, zt->label_num,
|
||||
MPLS_MAX_LABELS);
|
||||
return -1;
|
||||
}
|
||||
for (int i = 0; i < zt->label_num; i++)
|
||||
STREAM_GETL(s, zt->labels[i]);
|
||||
|
||||
return 0;
|
||||
|
||||
stream_failure:
|
||||
return -1;
|
||||
}
|
||||
|
||||
int zapi_sr_policy_notify_status_decode(struct stream *s,
|
||||
struct zapi_sr_policy *zp)
|
||||
{
|
||||
memset(zp, 0, sizeof(*zp));
|
||||
|
||||
STREAM_GETL(s, zp->color);
|
||||
STREAM_GET_IPADDR(s, &zp->endpoint);
|
||||
STREAM_GET(&zp->name, s, SRTE_POLICY_NAME_MAX_LENGTH);
|
||||
STREAM_GETL(s, zp->status);
|
||||
|
||||
return 0;
|
||||
|
||||
stream_failure:
|
||||
return -1;
|
||||
}
|
||||
|
||||
int zebra_send_mpls_labels(struct zclient *zclient, int cmd,
|
||||
struct zapi_labels *zl)
|
||||
{
|
||||
@ -2874,7 +2981,7 @@ int zapi_labels_encode(struct stream *s, int cmd, struct zapi_labels *zl)
|
||||
for (int i = 0; i < zl->nexthop_num; i++) {
|
||||
znh = &zl->nexthops[i];
|
||||
|
||||
if (zapi_nexthop_encode(s, znh, 0) < 0)
|
||||
if (zapi_nexthop_encode(s, znh, 0, 0) < 0)
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -2893,7 +3000,7 @@ int zapi_labels_encode(struct stream *s, int cmd, struct zapi_labels *zl)
|
||||
for (int i = 0; i < zl->backup_nexthop_num; i++) {
|
||||
znh = &zl->backup_nexthops[i];
|
||||
|
||||
if (zapi_nexthop_encode(s, znh, 0) < 0)
|
||||
if (zapi_nexthop_encode(s, znh, 0, 0) < 0)
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -2969,7 +3076,7 @@ int zapi_labels_decode(struct stream *s, struct zapi_labels *zl)
|
||||
for (int i = 0; i < zl->nexthop_num; i++) {
|
||||
znh = &zl->nexthops[i];
|
||||
|
||||
if (zapi_nexthop_decode(s, znh, 0) < 0)
|
||||
if (zapi_nexthop_decode(s, znh, 0, 0) < 0)
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -2990,7 +3097,7 @@ int zapi_labels_decode(struct stream *s, struct zapi_labels *zl)
|
||||
for (int i = 0; i < zl->backup_nexthop_num; i++) {
|
||||
znh = &zl->backup_nexthops[i];
|
||||
|
||||
if (zapi_nexthop_decode(s, znh, 0) < 0)
|
||||
if (zapi_nexthop_decode(s, znh, 0, 0) < 0)
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
@ -3657,6 +3764,10 @@ static int zclient_read(struct thread *thread)
|
||||
(*zclient->opaque_unregister_handler)(command, zclient,
|
||||
length, vrf_id);
|
||||
break;
|
||||
case ZEBRA_SR_POLICY_NOTIFY_STATUS:
|
||||
if (zclient->sr_policy_notify_status)
|
||||
(*zclient->sr_policy_notify_status)(command, zclient,
|
||||
length, vrf_id);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -37,6 +37,7 @@
|
||||
#include "pw.h"
|
||||
|
||||
#include "mlag.h"
|
||||
#include "srte.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@ -89,6 +90,8 @@ enum zserv_client_capabilities {
|
||||
/* Macro to check if there GR enabled. */
|
||||
#define ZEBRA_CLIENT_GR_ENABLED(X) (X == ZEBRA_CLIENT_GR_CAPABILITIES)
|
||||
|
||||
#define ZEBRA_SR_POLICY_NAME_MAX_LENGTH 100
|
||||
|
||||
extern struct sockaddr_storage zclient_addr;
|
||||
extern socklen_t zclient_addr_len;
|
||||
|
||||
@ -143,6 +146,9 @@ typedef enum {
|
||||
ZEBRA_MPLS_LABELS_ADD,
|
||||
ZEBRA_MPLS_LABELS_DELETE,
|
||||
ZEBRA_MPLS_LABELS_REPLACE,
|
||||
ZEBRA_SR_POLICY_SET,
|
||||
ZEBRA_SR_POLICY_DELETE,
|
||||
ZEBRA_SR_POLICY_NOTIFY_STATUS,
|
||||
ZEBRA_IPMR_ROUTE_STATS,
|
||||
ZEBRA_LABEL_MANAGER_CONNECT,
|
||||
ZEBRA_LABEL_MANAGER_CONNECT_ASYNC,
|
||||
@ -351,6 +357,7 @@ struct zclient {
|
||||
int (*opaque_msg_handler)(ZAPI_CALLBACK_ARGS);
|
||||
int (*opaque_register_handler)(ZAPI_CALLBACK_ARGS);
|
||||
int (*opaque_unregister_handler)(ZAPI_CALLBACK_ARGS);
|
||||
int (*sr_policy_notify_status)(ZAPI_CALLBACK_ARGS);
|
||||
};
|
||||
|
||||
/* Zebra API message flag. */
|
||||
@ -368,7 +375,8 @@ struct zclient {
|
||||
* the table being used is not in the VRF. You must pass the
|
||||
* default vrf, else this will be ignored.
|
||||
*/
|
||||
#define ZAPI_MESSAGE_TABLEID 0x80
|
||||
#define ZAPI_MESSAGE_TABLEID 0x0080
|
||||
#define ZAPI_MESSAGE_SRTE 0x0100
|
||||
|
||||
#define ZSERV_VERSION 6
|
||||
/* Zserv protocol message header */
|
||||
@ -403,6 +411,9 @@ struct zapi_nexthop {
|
||||
/* Backup nexthops, for IP-FRR, TI-LFA, etc */
|
||||
uint8_t backup_num;
|
||||
uint8_t backup_idx[NEXTHOP_MAX_BACKUPS];
|
||||
|
||||
/* SR-TE color. */
|
||||
uint32_t srte_color;
|
||||
};
|
||||
|
||||
/*
|
||||
@ -465,7 +476,7 @@ struct zapi_route {
|
||||
#define ZEBRA_FLAG_RR_USE_DISTANCE 0x40
|
||||
|
||||
/* The older XXX_MESSAGE flags live here */
|
||||
uint8_t message;
|
||||
uint32_t message;
|
||||
|
||||
/*
|
||||
* This is an enum but we are going to treat it as a uint8_t
|
||||
@ -494,6 +505,9 @@ struct zapi_route {
|
||||
vrf_id_t vrf_id;
|
||||
|
||||
uint32_t tableid;
|
||||
|
||||
/* SR-TE color (used for nexthop updates only). */
|
||||
uint32_t srte_color;
|
||||
};
|
||||
|
||||
struct zapi_labels {
|
||||
@ -516,6 +530,21 @@ struct zapi_labels {
|
||||
struct zapi_nexthop backup_nexthops[MULTIPATH_NUM];
|
||||
};
|
||||
|
||||
struct zapi_srte_tunnel {
|
||||
enum lsp_types_t type;
|
||||
mpls_label_t local_label;
|
||||
uint8_t label_num;
|
||||
mpls_label_t labels[MPLS_MAX_LABELS];
|
||||
};
|
||||
|
||||
struct zapi_sr_policy {
|
||||
uint32_t color;
|
||||
struct ipaddr endpoint;
|
||||
char name[SRTE_POLICY_NAME_MAX_LENGTH];
|
||||
struct zapi_srte_tunnel segment_list;
|
||||
int status;
|
||||
};
|
||||
|
||||
struct zapi_pw {
|
||||
char ifname[IF_NAMESIZE];
|
||||
ifindex_t ifindex;
|
||||
@ -778,6 +807,14 @@ extern int tm_get_table_chunk(struct zclient *zclient, uint32_t chunk_size,
|
||||
extern int tm_release_table_chunk(struct zclient *zclient, uint32_t start,
|
||||
uint32_t end);
|
||||
|
||||
extern int zebra_send_sr_policy(struct zclient *zclient, int cmd,
|
||||
struct zapi_sr_policy *zp);
|
||||
extern int zapi_sr_policy_encode(struct stream *s, int cmd,
|
||||
struct zapi_sr_policy *zp);
|
||||
extern int zapi_sr_policy_decode(struct stream *s, struct zapi_sr_policy *zp);
|
||||
extern int zapi_sr_policy_notify_status_decode(struct stream *s,
|
||||
struct zapi_sr_policy *zp);
|
||||
|
||||
extern int zebra_send_mpls_labels(struct zclient *zclient, int cmd,
|
||||
struct zapi_labels *zl);
|
||||
extern int zapi_labels_encode(struct stream *s, int cmd,
|
||||
@ -794,7 +831,7 @@ extern int zclient_send_rnh(struct zclient *zclient, int command,
|
||||
const struct prefix *p, bool exact_match,
|
||||
vrf_id_t vrf_id);
|
||||
int zapi_nexthop_encode(struct stream *s, const struct zapi_nexthop *api_nh,
|
||||
uint32_t api_flags);
|
||||
uint32_t api_flags, uint32_t api_message);
|
||||
extern int zapi_route_encode(uint8_t, struct stream *, struct zapi_route *);
|
||||
extern int zapi_route_decode(struct stream *, struct zapi_route *);
|
||||
bool zapi_route_notify_decode(struct stream *s, struct prefix *p,
|
||||
|
@ -6,6 +6,9 @@
|
||||
{
|
||||
"type":"SR (OSPF)",
|
||||
"outLabel":3,
|
||||
"outLabelStack":[
|
||||
3
|
||||
],
|
||||
"distance":150,
|
||||
"installed":true
|
||||
}
|
||||
@ -18,6 +21,9 @@
|
||||
{
|
||||
"type":"SR (OSPF)",
|
||||
"outLabel":3,
|
||||
"outLabelStack":[
|
||||
3
|
||||
],
|
||||
"distance":150,
|
||||
"installed":true,
|
||||
"nexthop":"10.0.1.2"
|
||||
@ -38,6 +44,9 @@
|
||||
{
|
||||
"type":"SR (OSPF)",
|
||||
"outLabel":8300,
|
||||
"outLabelStack":[
|
||||
8300
|
||||
],
|
||||
"distance":150,
|
||||
"installed":true,
|
||||
"nexthop":"10.0.1.2"
|
||||
@ -58,6 +67,9 @@
|
||||
{
|
||||
"type":"SR (OSPF)",
|
||||
"outLabel":8400,
|
||||
"outLabelStack":[
|
||||
8400
|
||||
],
|
||||
"distance":150,
|
||||
"installed":true,
|
||||
"nexthop":"10.0.1.2"
|
||||
@ -104,6 +116,9 @@
|
||||
{
|
||||
"type":"SR (OSPF)",
|
||||
"outLabel":3,
|
||||
"outLabelStack":[
|
||||
3
|
||||
],
|
||||
"distance":150,
|
||||
"installed":true,
|
||||
"nexthop":"10.0.1.2"
|
||||
@ -117,6 +132,9 @@
|
||||
{
|
||||
"type":"SR (OSPF)",
|
||||
"outLabel":3,
|
||||
"outLabelStack":[
|
||||
3
|
||||
],
|
||||
"distance":150,
|
||||
"installed":true,
|
||||
"nexthop":"10.0.1.2"
|
||||
|
@ -6,6 +6,9 @@
|
||||
{
|
||||
"type":"SR (OSPF)",
|
||||
"outLabel":20100,
|
||||
"outLabelStack":[
|
||||
20100
|
||||
],
|
||||
"distance":150,
|
||||
"installed":true,
|
||||
"nexthop":"10.0.1.1"
|
||||
@ -26,6 +29,9 @@
|
||||
{
|
||||
"type":"SR (OSPF)",
|
||||
"outLabel":3,
|
||||
"outLabelStack":[
|
||||
3
|
||||
],
|
||||
"distance":150,
|
||||
"installed":true,
|
||||
"nexthop":"10.0.3.1"
|
||||
@ -39,6 +45,9 @@
|
||||
{
|
||||
"type":"SR (OSPF)",
|
||||
"outLabel":10400,
|
||||
"outLabelStack":[
|
||||
10400
|
||||
],
|
||||
"distance":150,
|
||||
"installed":true,
|
||||
"nexthop":"10.0.4.1"
|
||||
@ -52,6 +61,9 @@
|
||||
{
|
||||
"type":"SR (OSPF)",
|
||||
"outLabel":3,
|
||||
"outLabelStack":[
|
||||
3
|
||||
],
|
||||
"distance":150,
|
||||
"installed":true,
|
||||
"nexthop":"10.0.4.1"
|
||||
@ -65,6 +77,9 @@
|
||||
{
|
||||
"type":"SR (OSPF)",
|
||||
"outLabel":3,
|
||||
"outLabelStack":[
|
||||
3
|
||||
],
|
||||
"distance":150,
|
||||
"installed":true,
|
||||
"nexthop":"10.0.4.1"
|
||||
@ -78,6 +93,9 @@
|
||||
{
|
||||
"type":"SR (OSPF)",
|
||||
"outLabel":3,
|
||||
"outLabelStack":[
|
||||
3
|
||||
],
|
||||
"distance":150,
|
||||
"installed":true,
|
||||
"nexthop":"10.0.0.1"
|
||||
@ -91,6 +109,9 @@
|
||||
{
|
||||
"type":"SR (OSPF)",
|
||||
"outLabel":3,
|
||||
"outLabelStack":[
|
||||
3
|
||||
],
|
||||
"distance":150,
|
||||
"installed":true,
|
||||
"nexthop":"10.0.0.1"
|
||||
@ -104,6 +125,9 @@
|
||||
{
|
||||
"type":"SR (OSPF)",
|
||||
"outLabel":3,
|
||||
"outLabelStack":[
|
||||
3
|
||||
],
|
||||
"distance":150,
|
||||
"installed":true,
|
||||
"nexthop":"10.0.1.1"
|
||||
@ -117,6 +141,9 @@
|
||||
{
|
||||
"type":"SR (OSPF)",
|
||||
"outLabel":3,
|
||||
"outLabelStack":[
|
||||
3
|
||||
],
|
||||
"distance":150,
|
||||
"installed":true,
|
||||
"nexthop":"10.0.1.1"
|
||||
|
@ -6,6 +6,9 @@
|
||||
{
|
||||
"type":"SR (OSPF)",
|
||||
"outLabel":8100,
|
||||
"outLabelStack":[
|
||||
8100
|
||||
],
|
||||
"distance":150,
|
||||
"installed":true,
|
||||
"nexthop":"10.0.3.2"
|
||||
@ -19,6 +22,9 @@
|
||||
{
|
||||
"type":"SR (OSPF)",
|
||||
"outLabel":3,
|
||||
"outLabelStack":[
|
||||
3
|
||||
],
|
||||
"distance":150,
|
||||
"installed":true,
|
||||
"nexthop":"10.0.3.2"
|
||||
@ -32,6 +38,9 @@
|
||||
{
|
||||
"type":"SR (OSPF)",
|
||||
"outLabel":8400,
|
||||
"outLabelStack":[
|
||||
8400
|
||||
],
|
||||
"distance":150,
|
||||
"installed":true,
|
||||
"nexthop":"10.0.3.2"
|
||||
@ -45,6 +54,9 @@
|
||||
{
|
||||
"type":"SR (OSPF)",
|
||||
"outLabel":3,
|
||||
"outLabelStack":[
|
||||
3
|
||||
],
|
||||
"distance":150,
|
||||
"installed":true,
|
||||
"nexthop":"10.0.3.2"
|
||||
@ -58,6 +70,9 @@
|
||||
{
|
||||
"type":"SR (OSPF)",
|
||||
"outLabel":3,
|
||||
"outLabelStack":[
|
||||
3
|
||||
],
|
||||
"distance":150,
|
||||
"installed":true,
|
||||
"nexthop":"10.0.3.2"
|
||||
|
@ -6,6 +6,9 @@
|
||||
{
|
||||
"type":"SR (OSPF)",
|
||||
"outLabel":8100,
|
||||
"outLabelStack":[
|
||||
8100
|
||||
],
|
||||
"distance":150,
|
||||
"installed":true,
|
||||
"nexthop":"10.0.4.2"
|
||||
@ -19,6 +22,9 @@
|
||||
{
|
||||
"type":"SR (OSPF)",
|
||||
"outLabel":3,
|
||||
"outLabelStack":[
|
||||
3
|
||||
],
|
||||
"distance":150,
|
||||
"installed":true,
|
||||
"nexthop":"10.0.4.2"
|
||||
@ -32,6 +38,9 @@
|
||||
{
|
||||
"type":"SR (OSPF)",
|
||||
"outLabel":8300,
|
||||
"outLabelStack":[
|
||||
8300
|
||||
],
|
||||
"distance":150,
|
||||
"installed":true,
|
||||
"nexthop":"10.0.4.2"
|
||||
@ -45,6 +54,9 @@
|
||||
{
|
||||
"type":"SR (OSPF)",
|
||||
"outLabel":3,
|
||||
"outLabelStack":[
|
||||
3
|
||||
],
|
||||
"distance":150,
|
||||
"installed":true
|
||||
}
|
||||
@ -57,6 +69,9 @@
|
||||
{
|
||||
"type":"SR (OSPF)",
|
||||
"outLabel":3,
|
||||
"outLabelStack":[
|
||||
3
|
||||
],
|
||||
"distance":150,
|
||||
"installed":true,
|
||||
"nexthop":"10.0.4.2"
|
||||
@ -70,6 +85,9 @@
|
||||
{
|
||||
"type":"SR (OSPF)",
|
||||
"outLabel":3,
|
||||
"outLabelStack":[
|
||||
3
|
||||
],
|
||||
"distance":150,
|
||||
"installed":true,
|
||||
"nexthop":"10.0.4.2"
|
||||
|
@ -240,7 +240,7 @@ assign_specific_label_chunk(uint8_t proto, unsigned short instance,
|
||||
if (lmc->proto != NO_PROTO)
|
||||
return NULL;
|
||||
|
||||
if (end < lmc->end) {
|
||||
if (end <= lmc->end) {
|
||||
last_node = node;
|
||||
break;
|
||||
}
|
||||
|
@ -57,6 +57,7 @@
|
||||
#include "zebra/zebra_routemap.h"
|
||||
#include "zebra/zebra_nb.h"
|
||||
#include "zebra/zebra_opaque.h"
|
||||
#include "zebra/zebra_srte.h"
|
||||
|
||||
#if defined(HANDLE_NETLINK_FUZZING)
|
||||
#include "zebra/kernel_netlink.h"
|
||||
@ -438,9 +439,10 @@ int main(int argc, char **argv)
|
||||
zebra_pw_vty_init();
|
||||
zebra_pbr_init();
|
||||
zebra_opaque_init();
|
||||
zebra_srte_init();
|
||||
|
||||
/* For debug purpose. */
|
||||
/* SET_FLAG (zebra_debug_event, ZEBRA_DEBUG_EVENT); */
|
||||
/* For debug purpose. */
|
||||
/* SET_FLAG (zebra_debug_event, ZEBRA_DEBUG_EVENT); */
|
||||
|
||||
/* Process the configuration file. Among other configuration
|
||||
* directives we can meet those installing static routes. Such
|
||||
|
@ -179,7 +179,8 @@ static inline bool is_selfroute(int proto)
|
||||
|| (proto == RTPROT_NHRP) || (proto == RTPROT_EIGRP)
|
||||
|| (proto == RTPROT_LDP) || (proto == RTPROT_BABEL)
|
||||
|| (proto == RTPROT_RIP) || (proto == RTPROT_SHARP)
|
||||
|| (proto == RTPROT_PBR) || (proto == RTPROT_OPENFABRIC)) {
|
||||
|| (proto == RTPROT_PBR) || (proto == RTPROT_OPENFABRIC)
|
||||
|| (proto == RTPROT_SRTE)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -229,6 +230,9 @@ static inline int zebra2proto(int proto)
|
||||
case ZEBRA_ROUTE_OPENFABRIC:
|
||||
proto = RTPROT_OPENFABRIC;
|
||||
break;
|
||||
case ZEBRA_ROUTE_SRTE:
|
||||
proto = RTPROT_SRTE;
|
||||
break;
|
||||
case ZEBRA_ROUTE_TABLE:
|
||||
case ZEBRA_ROUTE_NHG:
|
||||
proto = RTPROT_ZEBRA;
|
||||
@ -294,6 +298,9 @@ static inline int proto2zebra(int proto, int family, bool is_nexthop)
|
||||
case RTPROT_OPENFABRIC:
|
||||
proto = ZEBRA_ROUTE_OPENFABRIC;
|
||||
break;
|
||||
case RTPROT_SRTE:
|
||||
proto = ZEBRA_ROUTE_SRTE;
|
||||
break;
|
||||
case RTPROT_ZEBRA:
|
||||
if (is_nexthop) {
|
||||
proto = ZEBRA_ROUTE_NHG;
|
||||
|
@ -60,6 +60,7 @@ extern "C" {
|
||||
#define RTPROT_PBR 195
|
||||
#define RTPROT_ZSTATIC 196
|
||||
#define RTPROT_OPENFABRIC 197
|
||||
#define RTPROT_SRTE 198
|
||||
|
||||
void rt_netlink_init(void);
|
||||
|
||||
|
@ -106,6 +106,7 @@ zebra_zebra_SOURCES = \
|
||||
zebra/zebra_router.c \
|
||||
zebra/zebra_rnh.c \
|
||||
zebra/zebra_routemap.c \
|
||||
zebra/zebra_srte.c \
|
||||
zebra/zebra_vrf.c \
|
||||
zebra/zebra_vty.c \
|
||||
zebra/zebra_vxlan.c \
|
||||
@ -167,6 +168,7 @@ noinst_HEADERS += \
|
||||
zebra/zebra_rnh.h \
|
||||
zebra/zebra_routemap.h \
|
||||
zebra/zebra_router.h \
|
||||
zebra/zebra_srte.h \
|
||||
zebra/zebra_vrf.h \
|
||||
zebra/zebra_vxlan.h \
|
||||
zebra/zebra_vxlan_private.h \
|
||||
|
114
zebra/zapi_msg.c
114
zebra/zapi_msg.c
@ -60,6 +60,7 @@
|
||||
#include "zebra/zebra_mlag.h"
|
||||
#include "zebra/connected.h"
|
||||
#include "zebra/zebra_opaque.h"
|
||||
#include "zebra/zebra_srte.h"
|
||||
|
||||
/* Encoding helpers -------------------------------------------------------- */
|
||||
|
||||
@ -1651,6 +1652,11 @@ static void zread_route_add(ZAPI_HANDLER_ARGS)
|
||||
return;
|
||||
}
|
||||
|
||||
if (CHECK_FLAG(api.message, ZAPI_MESSAGE_SRTE)) {
|
||||
SET_FLAG(nexthop->flags, NEXTHOP_FLAG_SRTE);
|
||||
nexthop->srte_color = api_nh->srte_color;
|
||||
}
|
||||
|
||||
/* MPLS labels for BGP-LU or Segment Routing */
|
||||
if (CHECK_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_LABEL)
|
||||
&& api_nh->type != NEXTHOP_TYPE_IFINDEX
|
||||
@ -1730,6 +1736,11 @@ static void zread_route_add(ZAPI_HANDLER_ARGS)
|
||||
nexthop->backup_num = 0;
|
||||
}
|
||||
|
||||
if (CHECK_FLAG(api.message, ZAPI_MESSAGE_SRTE)) {
|
||||
SET_FLAG(nexthop->flags, NEXTHOP_FLAG_SRTE);
|
||||
nexthop->srte_color = api_nh->srte_color;
|
||||
}
|
||||
|
||||
/* MPLS labels for BGP-LU or Segment Routing */
|
||||
if (CHECK_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_LABEL)
|
||||
&& api_nh->type != NEXTHOP_TYPE_IFINDEX
|
||||
@ -2209,6 +2220,107 @@ static void zread_mpls_labels_replace(ZAPI_HANDLER_ARGS)
|
||||
mpls_zapi_labels_process(true, zvrf, &zl);
|
||||
}
|
||||
|
||||
static void zread_sr_policy_set(ZAPI_HANDLER_ARGS)
|
||||
{
|
||||
struct stream *s;
|
||||
struct zapi_sr_policy zp;
|
||||
struct zapi_srte_tunnel *zt;
|
||||
struct zebra_sr_policy *policy;
|
||||
|
||||
/* Get input stream. */
|
||||
s = msg;
|
||||
if (zapi_sr_policy_decode(s, &zp) < 0) {
|
||||
if (IS_ZEBRA_DEBUG_RECV)
|
||||
zlog_debug("%s: Unable to decode zapi_sr_policy sent",
|
||||
__PRETTY_FUNCTION__);
|
||||
return;
|
||||
}
|
||||
zt = &zp.segment_list;
|
||||
if (zt->label_num < 1) {
|
||||
if (IS_ZEBRA_DEBUG_RECV)
|
||||
zlog_debug(
|
||||
"%s: SR-TE tunnel must contain at least one label",
|
||||
__PRETTY_FUNCTION__);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!mpls_enabled)
|
||||
return;
|
||||
|
||||
policy = zebra_sr_policy_find(zp.color, &zp.endpoint);
|
||||
if (!policy)
|
||||
policy = zebra_sr_policy_add(zp.color, &zp.endpoint, zp.name);
|
||||
/* TODO: per-VRF list of SR-TE policies. */
|
||||
policy->zvrf = zvrf;
|
||||
|
||||
zebra_sr_policy_validate(policy, &zp.segment_list);
|
||||
}
|
||||
|
||||
static void zread_sr_policy_delete(ZAPI_HANDLER_ARGS)
|
||||
{
|
||||
struct stream *s;
|
||||
struct zapi_sr_policy zp;
|
||||
struct zebra_sr_policy *policy;
|
||||
|
||||
/* Get input stream. */
|
||||
s = msg;
|
||||
if (zapi_sr_policy_decode(s, &zp) < 0) {
|
||||
if (IS_ZEBRA_DEBUG_RECV)
|
||||
zlog_debug("%s: Unable to decode zapi_sr_policy sent",
|
||||
__PRETTY_FUNCTION__);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!mpls_enabled)
|
||||
return;
|
||||
|
||||
policy = zebra_sr_policy_find(zp.color, &zp.endpoint);
|
||||
if (!policy) {
|
||||
if (IS_ZEBRA_DEBUG_RECV)
|
||||
zlog_debug("%s: Unable to find SR-TE policy",
|
||||
__PRETTY_FUNCTION__);
|
||||
return;
|
||||
}
|
||||
|
||||
zebra_sr_policy_del(policy);
|
||||
}
|
||||
|
||||
int zsend_sr_policy_notify_status(uint32_t color, struct ipaddr *endpoint,
|
||||
char *name, int status)
|
||||
{
|
||||
struct zserv *client;
|
||||
struct stream *s;
|
||||
|
||||
client = zserv_find_client(ZEBRA_ROUTE_SRTE, 0);
|
||||
if (!client) {
|
||||
if (IS_ZEBRA_DEBUG_PACKET)
|
||||
zlog_debug(
|
||||
"Not notifying pathd about policy %s"
|
||||
" status change to %d",
|
||||
name, status);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (IS_ZEBRA_DEBUG_PACKET)
|
||||
zlog_debug(
|
||||
"Notifying pathd about policy %s status change"
|
||||
" to %d",
|
||||
name, status);
|
||||
|
||||
s = stream_new(ZEBRA_MAX_PACKET_SIZ);
|
||||
stream_reset(s);
|
||||
|
||||
zclient_create_header(s, ZEBRA_SR_POLICY_NOTIFY_STATUS, VRF_DEFAULT);
|
||||
stream_putl(s, color);
|
||||
stream_put_ipaddr(s, endpoint);
|
||||
stream_write(s, name, SRTE_POLICY_NAME_MAX_LENGTH);
|
||||
stream_putl(s, status);
|
||||
|
||||
stream_putw_at(s, 0, stream_get_endp(s));
|
||||
|
||||
return zserv_send_message(client, s);
|
||||
}
|
||||
|
||||
/* Send response to a table manager connect request to client */
|
||||
static void zread_table_manager_connect(struct zserv *client,
|
||||
struct stream *msg, vrf_id_t vrf_id)
|
||||
@ -2908,6 +3020,8 @@ void (*const zserv_handlers[])(ZAPI_HANDLER_ARGS) = {
|
||||
[ZEBRA_BFD_CLIENT_REGISTER] = zebra_ptm_bfd_client_register,
|
||||
[ZEBRA_INTERFACE_ENABLE_RADV] = zebra_interface_radv_enable,
|
||||
[ZEBRA_INTERFACE_DISABLE_RADV] = zebra_interface_radv_disable,
|
||||
[ZEBRA_SR_POLICY_SET] = zread_sr_policy_set,
|
||||
[ZEBRA_SR_POLICY_DELETE] = zread_sr_policy_delete,
|
||||
[ZEBRA_MPLS_LABELS_ADD] = zread_mpls_labels_add,
|
||||
[ZEBRA_MPLS_LABELS_DELETE] = zread_mpls_labels_delete,
|
||||
[ZEBRA_MPLS_LABELS_REPLACE] = zread_mpls_labels_replace,
|
||||
|
@ -100,7 +100,9 @@ extern int zsend_assign_label_chunk_response(struct zserv *client,
|
||||
extern int zsend_label_manager_connect_response(struct zserv *client,
|
||||
vrf_id_t vrf_id,
|
||||
unsigned short result);
|
||||
|
||||
extern int zsend_sr_policy_notify_status(uint32_t color,
|
||||
struct ipaddr *endpoint, char *name,
|
||||
int status);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
@ -47,6 +47,7 @@
|
||||
#include "zebra/zebra_memory.h"
|
||||
#include "zebra/zebra_vrf.h"
|
||||
#include "zebra/zebra_mpls.h"
|
||||
#include "zebra/zebra_srte.h"
|
||||
#include "zebra/zebra_errors.h"
|
||||
|
||||
DEFINE_MTYPE_STATIC(ZEBRA, LSP, "MPLS LSP object")
|
||||
@ -1505,6 +1506,7 @@ static json_object *nhlfe_json(zebra_nhlfe_t *nhlfe)
|
||||
char buf[BUFSIZ];
|
||||
json_object *json_nhlfe = NULL;
|
||||
json_object *json_backups = NULL;
|
||||
json_object *json_label_stack;
|
||||
struct nexthop *nexthop = nhlfe->nexthop;
|
||||
int i;
|
||||
|
||||
@ -1512,6 +1514,14 @@ static json_object *nhlfe_json(zebra_nhlfe_t *nhlfe)
|
||||
json_object_string_add(json_nhlfe, "type", nhlfe_type2str(nhlfe->type));
|
||||
json_object_int_add(json_nhlfe, "outLabel",
|
||||
nexthop->nh_label->label[0]);
|
||||
|
||||
json_label_stack = json_object_new_array();
|
||||
json_object_object_add(json_nhlfe, "outLabelStack", json_label_stack);
|
||||
for (i = 0; i < nexthop->nh_label->num_labels; i++)
|
||||
json_object_array_add(
|
||||
json_label_stack,
|
||||
json_object_new_int(nexthop->nh_label->label[i]));
|
||||
|
||||
json_object_int_add(json_nhlfe, "distance", nhlfe->distance);
|
||||
|
||||
if (CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_INSTALLED))
|
||||
@ -1916,14 +1926,13 @@ static int mpls_processq_init(void)
|
||||
}
|
||||
|
||||
|
||||
/* Public functions */
|
||||
|
||||
/*
|
||||
* Process LSP update results from zebra dataplane.
|
||||
*/
|
||||
void zebra_mpls_lsp_dplane_result(struct zebra_dplane_ctx *ctx)
|
||||
{
|
||||
struct zebra_vrf *zvrf;
|
||||
mpls_label_t label;
|
||||
zebra_ile_t tmp_ile;
|
||||
struct hash *lsp_table;
|
||||
zebra_lsp_t *lsp;
|
||||
@ -1931,6 +1940,7 @@ void zebra_mpls_lsp_dplane_result(struct zebra_dplane_ctx *ctx)
|
||||
struct nexthop *nexthop;
|
||||
enum dplane_op_e op;
|
||||
enum zebra_dplane_result status;
|
||||
enum zebra_sr_policy_update_label_mode update_mode;
|
||||
|
||||
op = dplane_ctx_get_op(ctx);
|
||||
status = dplane_ctx_get_status(ctx);
|
||||
@ -1941,6 +1951,8 @@ void zebra_mpls_lsp_dplane_result(struct zebra_dplane_ctx *ctx)
|
||||
dplane_ctx_get_in_label(ctx),
|
||||
dplane_res2str(status));
|
||||
|
||||
label = dplane_ctx_get_in_label(ctx);
|
||||
|
||||
switch (op) {
|
||||
case DPLANE_OP_LSP_INSTALL:
|
||||
case DPLANE_OP_LSP_UPDATE:
|
||||
@ -1951,7 +1963,7 @@ void zebra_mpls_lsp_dplane_result(struct zebra_dplane_ctx *ctx)
|
||||
|
||||
lsp_table = zvrf->lsp_table;
|
||||
|
||||
tmp_ile.in_label = dplane_ctx_get_in_label(ctx);
|
||||
tmp_ile.in_label = label;
|
||||
lsp = hash_lookup(lsp_table, &tmp_ile);
|
||||
if (lsp == NULL) {
|
||||
if (IS_ZEBRA_DEBUG_DPLANE)
|
||||
@ -1985,13 +1997,21 @@ void zebra_mpls_lsp_dplane_result(struct zebra_dplane_ctx *ctx)
|
||||
}
|
||||
}
|
||||
|
||||
update_mode = (op == DPLANE_OP_LSP_INSTALL)
|
||||
? ZEBRA_SR_POLICY_LABEL_CREATED
|
||||
: ZEBRA_SR_POLICY_LABEL_UPDATED;
|
||||
zebra_sr_policy_label_update(label, update_mode);
|
||||
break;
|
||||
|
||||
case DPLANE_OP_LSP_DELETE:
|
||||
if (status != ZEBRA_DPLANE_REQUEST_SUCCESS)
|
||||
if (status != ZEBRA_DPLANE_REQUEST_SUCCESS) {
|
||||
flog_warn(EC_ZEBRA_LSP_DELETE_FAILURE,
|
||||
"LSP Deletion Failure: in-label %u",
|
||||
dplane_ctx_get_in_label(ctx));
|
||||
break;
|
||||
}
|
||||
zebra_sr_policy_label_update(label,
|
||||
ZEBRA_SR_POLICY_LABEL_REMOVED);
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -3419,6 +3439,21 @@ static int lsp_backup_znh_install(zebra_lsp_t *lsp, enum lsp_types_t type,
|
||||
return 0;
|
||||
}
|
||||
|
||||
zebra_lsp_t *mpls_lsp_find(struct zebra_vrf *zvrf, mpls_label_t in_label)
|
||||
{
|
||||
struct hash *lsp_table;
|
||||
zebra_ile_t tmp_ile;
|
||||
|
||||
/* Lookup table. */
|
||||
lsp_table = zvrf->lsp_table;
|
||||
if (!lsp_table)
|
||||
return NULL;
|
||||
|
||||
/* If entry is not present, exit. */
|
||||
tmp_ile.in_label = in_label;
|
||||
return hash_lookup(lsp_table, &tmp_ile);
|
||||
}
|
||||
|
||||
/*
|
||||
* Uninstall a particular NHLFE in the forwarding table. If this is
|
||||
* the only NHLFE, the entire LSP forwarding entry has to be deleted.
|
||||
|
@ -33,6 +33,7 @@
|
||||
#include "mpls.h"
|
||||
#include "zebra/zserv.h"
|
||||
#include "zebra/zebra_vrf.h"
|
||||
#include "hook.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@ -325,6 +326,11 @@ int mpls_lsp_install(struct zebra_vrf *zvrf, enum lsp_types_t type,
|
||||
const mpls_label_t *out_labels, enum nexthop_types_t gtype,
|
||||
const union g_addr *gate, ifindex_t ifindex);
|
||||
|
||||
/*
|
||||
* Lookup LSP by its input label.
|
||||
*/
|
||||
zebra_lsp_t *mpls_lsp_find(struct zebra_vrf *zvrf, mpls_label_t in_label);
|
||||
|
||||
/*
|
||||
* Uninstall a particular NHLFE in the forwarding table. If this is
|
||||
* the only NHLFE, the entire LSP forwarding entry has to be deleted.
|
||||
@ -461,6 +467,7 @@ static inline uint8_t lsp_distance(enum lsp_types_t type)
|
||||
case ZEBRA_LSP_SHARP:
|
||||
case ZEBRA_LSP_OSPF_SR:
|
||||
case ZEBRA_LSP_ISIS_SR:
|
||||
case ZEBRA_LSP_SRTE:
|
||||
return 150;
|
||||
}
|
||||
|
||||
@ -492,6 +499,8 @@ static inline enum lsp_types_t lsp_type_from_re_type(int re_type)
|
||||
return ZEBRA_LSP_ISIS_SR;
|
||||
case ZEBRA_ROUTE_SHARP:
|
||||
return ZEBRA_LSP_SHARP;
|
||||
case ZEBRA_ROUTE_SRTE:
|
||||
return ZEBRA_LSP_SRTE;
|
||||
default:
|
||||
return ZEBRA_LSP_NONE;
|
||||
}
|
||||
@ -517,6 +526,8 @@ static inline int re_type_from_lsp_type(enum lsp_types_t lsp_type)
|
||||
return ZEBRA_ROUTE_KERNEL;
|
||||
case ZEBRA_LSP_SHARP:
|
||||
return ZEBRA_ROUTE_SHARP;
|
||||
case ZEBRA_LSP_SRTE:
|
||||
return ZEBRA_ROUTE_SRTE;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -544,6 +555,8 @@ static inline const char *nhlfe_type2str(enum lsp_types_t lsp_type)
|
||||
return "SR (IS-IS)";
|
||||
case ZEBRA_LSP_SHARP:
|
||||
return "SHARP";
|
||||
case ZEBRA_LSP_SRTE:
|
||||
return "SR-TE";
|
||||
case ZEBRA_LSP_NONE:
|
||||
return "Unknown";
|
||||
}
|
||||
|
@ -28,6 +28,7 @@
|
||||
#include "lib/mpls.h"
|
||||
#include "lib/jhash.h"
|
||||
#include "lib/debug.h"
|
||||
#include "lib/lib_errors.h"
|
||||
|
||||
#include "zebra/connected.h"
|
||||
#include "zebra/debug.h"
|
||||
@ -36,6 +37,7 @@
|
||||
#include "zebra/zebra_rnh.h"
|
||||
#include "zebra/zebra_routemap.h"
|
||||
#include "zebra/zebra_memory.h"
|
||||
#include "zebra/zebra_srte.h"
|
||||
#include "zebra/zserv.h"
|
||||
#include "zebra/rt.h"
|
||||
#include "zebra_errors.h"
|
||||
@ -1620,7 +1622,8 @@ void zebra_nhg_increment_ref(struct nhg_hash_entry *nhe)
|
||||
}
|
||||
|
||||
static void nexthop_set_resolved(afi_t afi, const struct nexthop *newhop,
|
||||
struct nexthop *nexthop)
|
||||
struct nexthop *nexthop,
|
||||
struct zebra_sr_policy *policy)
|
||||
{
|
||||
struct nexthop *resolved_hop;
|
||||
uint8_t num_labels = 0;
|
||||
@ -1684,7 +1687,21 @@ static void nexthop_set_resolved(afi_t afi, const struct nexthop *newhop,
|
||||
resolved_hop->flags |= NEXTHOP_FLAG_ONLINK;
|
||||
|
||||
/* Copy labels of the resolved route and the parent resolving to it */
|
||||
if (newhop->nh_label) {
|
||||
if (policy) {
|
||||
int i = 0;
|
||||
|
||||
/*
|
||||
* Don't push the first SID if the corresponding action in the
|
||||
* LFIB is POP.
|
||||
*/
|
||||
if (!newhop->nh_label || !newhop->nh_label->num_labels
|
||||
|| newhop->nh_label->label[0] == MPLS_LABEL_IMPLICIT_NULL)
|
||||
i = 1;
|
||||
|
||||
for (; i < policy->segment_list.label_num; i++)
|
||||
labels[num_labels++] = policy->segment_list.labels[i];
|
||||
label_type = policy->segment_list.type;
|
||||
} else if (newhop->nh_label) {
|
||||
for (i = 0; i < newhop->nh_label->num_labels; i++) {
|
||||
/* Be a bit picky about overrunning the local array */
|
||||
if (num_labels >= MPLS_MAX_LABELS) {
|
||||
@ -1771,11 +1788,13 @@ static int nexthop_active(afi_t afi, struct route_entry *re,
|
||||
struct route_node *rn;
|
||||
struct route_entry *match = NULL;
|
||||
int resolved;
|
||||
zebra_nhlfe_t *nhlfe;
|
||||
struct nexthop *newhop;
|
||||
struct interface *ifp;
|
||||
rib_dest_t *dest;
|
||||
struct zebra_vrf *zvrf;
|
||||
struct in_addr ipv4;
|
||||
struct in_addr local_ipv4;
|
||||
struct in_addr *ipv4;
|
||||
|
||||
if ((nexthop->type == NEXTHOP_TYPE_IPV4)
|
||||
|| nexthop->type == NEXTHOP_TYPE_IPV6)
|
||||
@ -1839,6 +1858,51 @@ static int nexthop_active(afi_t afi, struct route_entry *re,
|
||||
/* Validation for ipv4 mapped ipv6 nexthop. */
|
||||
if (IS_MAPPED_IPV6(&nexthop->gate.ipv6)) {
|
||||
afi = AFI_IP;
|
||||
ipv4 = &local_ipv4;
|
||||
ipv4_mapped_ipv6_to_ipv4(&nexthop->gate.ipv6, ipv4);
|
||||
} else {
|
||||
ipv4 = &nexthop->gate.ipv4;
|
||||
}
|
||||
|
||||
if (nexthop->srte_color) {
|
||||
struct ipaddr endpoint = {0};
|
||||
struct zebra_sr_policy *policy;
|
||||
|
||||
switch (afi) {
|
||||
case AFI_IP:
|
||||
endpoint.ipa_type = IPADDR_V4;
|
||||
endpoint.ipaddr_v4 = *ipv4;
|
||||
break;
|
||||
case AFI_IP6:
|
||||
endpoint.ipa_type = IPADDR_V6;
|
||||
endpoint.ipaddr_v6 = nexthop->gate.ipv6;
|
||||
break;
|
||||
default:
|
||||
flog_err(EC_LIB_DEVELOPMENT,
|
||||
"%s: unknown address-family: %u", __func__,
|
||||
afi);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
policy = zebra_sr_policy_find(nexthop->srte_color, &endpoint);
|
||||
if (policy && policy->status == ZEBRA_SR_POLICY_UP) {
|
||||
resolved = 0;
|
||||
frr_each_safe (nhlfe_list, &policy->lsp->nhlfe_list,
|
||||
nhlfe) {
|
||||
if (!CHECK_FLAG(nhlfe->flags,
|
||||
NHLFE_FLAG_SELECTED)
|
||||
|| CHECK_FLAG(nhlfe->flags,
|
||||
NHLFE_FLAG_DELETED))
|
||||
continue;
|
||||
SET_FLAG(nexthop->flags,
|
||||
NEXTHOP_FLAG_RECURSIVE);
|
||||
nexthop_set_resolved(afi, nhlfe->nexthop,
|
||||
nexthop, policy);
|
||||
resolved = 1;
|
||||
}
|
||||
if (resolved)
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Make lookup prefix. */
|
||||
@ -1847,12 +1911,7 @@ static int nexthop_active(afi_t afi, struct route_entry *re,
|
||||
case AFI_IP:
|
||||
p.family = AF_INET;
|
||||
p.prefixlen = IPV4_MAX_PREFIXLEN;
|
||||
if (IS_MAPPED_IPV6(&nexthop->gate.ipv6)) {
|
||||
ipv4_mapped_ipv6_to_ipv4(&nexthop->gate.ipv6, &ipv4);
|
||||
p.u.prefix4 = ipv4;
|
||||
} else {
|
||||
p.u.prefix4 = nexthop->gate.ipv4;
|
||||
}
|
||||
p.u.prefix4 = *ipv4;
|
||||
break;
|
||||
case AFI_IP6:
|
||||
p.family = AF_INET6;
|
||||
@ -1978,7 +2037,8 @@ static int nexthop_active(afi_t afi, struct route_entry *re,
|
||||
|
||||
SET_FLAG(nexthop->flags,
|
||||
NEXTHOP_FLAG_RECURSIVE);
|
||||
nexthop_set_resolved(afi, newhop, nexthop);
|
||||
nexthop_set_resolved(afi, newhop, nexthop,
|
||||
NULL);
|
||||
resolved = 1;
|
||||
}
|
||||
|
||||
@ -2001,7 +2061,8 @@ static int nexthop_active(afi_t afi, struct route_entry *re,
|
||||
|
||||
SET_FLAG(nexthop->flags,
|
||||
NEXTHOP_FLAG_RECURSIVE);
|
||||
nexthop_set_resolved(afi, newhop, nexthop);
|
||||
nexthop_set_resolved(afi, newhop, nexthop,
|
||||
NULL);
|
||||
resolved = 1;
|
||||
}
|
||||
done_with_match:
|
||||
|
@ -106,7 +106,8 @@ static const struct {
|
||||
[ZEBRA_ROUTE_PBR] = {ZEBRA_ROUTE_PBR, 200, 5},
|
||||
[ZEBRA_ROUTE_BFD] = {ZEBRA_ROUTE_BFD, 255, 5},
|
||||
[ZEBRA_ROUTE_OPENFABRIC] = {ZEBRA_ROUTE_OPENFABRIC, 115, 3},
|
||||
[ZEBRA_ROUTE_VRRP] = {ZEBRA_ROUTE_VRRP, 255, 5}
|
||||
[ZEBRA_ROUTE_VRRP] = {ZEBRA_ROUTE_VRRP, 255, 5},
|
||||
[ZEBRA_ROUTE_SRTE] = {ZEBRA_ROUTE_SRTE, 255, 5},
|
||||
/* Any new route type added to zebra, should be mirrored here */
|
||||
|
||||
/* no entry/default: 150 */
|
||||
|
@ -46,6 +46,7 @@
|
||||
#include "zebra/debug.h"
|
||||
#include "zebra/zebra_rnh.h"
|
||||
#include "zebra/zebra_routemap.h"
|
||||
#include "zebra/zebra_srte.h"
|
||||
#include "zebra/interface.h"
|
||||
#include "zebra/zebra_memory.h"
|
||||
#include "zebra/zebra_errors.h"
|
||||
@ -57,8 +58,6 @@ static void free_state(vrf_id_t vrf_id, struct route_entry *re,
|
||||
static void copy_state(struct rnh *rnh, const struct route_entry *re,
|
||||
struct route_node *rn);
|
||||
static int compare_state(struct route_entry *r1, struct route_entry *r2);
|
||||
static int send_client(struct rnh *rnh, struct zserv *client,
|
||||
enum rnh_type type, vrf_id_t vrf_id);
|
||||
static void print_rnh(struct route_node *rn, struct vty *vty);
|
||||
static int zebra_client_cleanup_rnh(struct zserv *client);
|
||||
|
||||
@ -305,7 +304,7 @@ void zebra_add_rnh_client(struct rnh *rnh, struct zserv *client,
|
||||
* We always need to respond with known information,
|
||||
* currently multiple daemons expect this behavior
|
||||
*/
|
||||
send_client(rnh, client, type, vrf_id);
|
||||
zebra_send_rnh_update(rnh, client, type, vrf_id, 0);
|
||||
}
|
||||
|
||||
void zebra_remove_rnh_client(struct rnh *rnh, struct zserv *client,
|
||||
@ -531,8 +530,9 @@ static void zebra_rnh_eval_import_check_entry(struct zebra_vrf *zvrf, afi_t afi,
|
||||
}
|
||||
/* state changed, notify clients */
|
||||
for (ALL_LIST_ELEMENTS_RO(rnh->client_list, node, client)) {
|
||||
send_client(rnh, client,
|
||||
RNH_IMPORT_CHECK_TYPE, zvrf->vrf->vrf_id);
|
||||
zebra_send_rnh_update(rnh, client,
|
||||
RNH_IMPORT_CHECK_TYPE,
|
||||
zvrf->vrf->vrf_id, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -594,7 +594,8 @@ static void zebra_rnh_notify_protocol_clients(struct zebra_vrf *zvrf, afi_t afi,
|
||||
zebra_route_string(client->proto));
|
||||
}
|
||||
|
||||
send_client(rnh, client, RNH_NEXTHOP_TYPE, zvrf->vrf->vrf_id);
|
||||
zebra_send_rnh_update(rnh, client, RNH_NEXTHOP_TYPE,
|
||||
zvrf->vrf->vrf_id, 0);
|
||||
}
|
||||
|
||||
if (re)
|
||||
@ -1107,8 +1108,9 @@ static int compare_state(struct route_entry *r1, struct route_entry *r2)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int send_client(struct rnh *rnh, struct zserv *client,
|
||||
enum rnh_type type, vrf_id_t vrf_id)
|
||||
int zebra_send_rnh_update(struct rnh *rnh, struct zserv *client,
|
||||
enum rnh_type type, vrf_id_t vrf_id,
|
||||
uint32_t srte_color)
|
||||
{
|
||||
struct stream *s = NULL;
|
||||
struct route_entry *re;
|
||||
@ -1117,6 +1119,7 @@ static int send_client(struct rnh *rnh, struct zserv *client,
|
||||
struct nexthop *nh;
|
||||
struct route_node *rn;
|
||||
int ret;
|
||||
uint32_t message = 0;
|
||||
int cmd = (type == RNH_IMPORT_CHECK_TYPE) ? ZEBRA_IMPORT_CHECK_UPDATE
|
||||
: ZEBRA_NEXTHOP_UPDATE;
|
||||
|
||||
@ -1128,6 +1131,11 @@ static int send_client(struct rnh *rnh, struct zserv *client,
|
||||
|
||||
zclient_create_header(s, cmd, vrf_id);
|
||||
|
||||
/* Message flags. */
|
||||
if (srte_color)
|
||||
SET_FLAG(message, ZAPI_MESSAGE_SRTE);
|
||||
stream_putl(s, message);
|
||||
|
||||
stream_putw(s, rn->p.family);
|
||||
switch (rn->p.family) {
|
||||
case AF_INET:
|
||||
@ -1144,6 +1152,9 @@ static int send_client(struct rnh *rnh, struct zserv *client,
|
||||
__func__, rn->p.family);
|
||||
goto failure;
|
||||
}
|
||||
if (srte_color)
|
||||
stream_putl(s, srte_color);
|
||||
|
||||
if (re) {
|
||||
struct zapi_nexthop znh;
|
||||
struct nexthop_group *nhg;
|
||||
@ -1160,7 +1171,7 @@ static int send_client(struct rnh *rnh, struct zserv *client,
|
||||
for (ALL_NEXTHOPS_PTR(nhg, nh))
|
||||
if (rnh_nexthop_valid(re, nh)) {
|
||||
zapi_nexthop_from_nexthop(&znh, nh);
|
||||
ret = zapi_nexthop_encode(s, &znh, 0/*flags*/);
|
||||
ret = zapi_nexthop_encode(s, &znh, 0, message);
|
||||
if (ret < 0)
|
||||
goto failure;
|
||||
|
||||
@ -1173,7 +1184,8 @@ static int send_client(struct rnh *rnh, struct zserv *client,
|
||||
if (rnh_nexthop_valid(re, nh)) {
|
||||
zapi_nexthop_from_nexthop(&znh, nh);
|
||||
ret = zapi_nexthop_encode(
|
||||
s, &znh, 0 /* flags */);
|
||||
s, &znh, 0 /* flags */,
|
||||
0 /* message */);
|
||||
if (ret < 0)
|
||||
goto failure;
|
||||
|
||||
|
@ -50,6 +50,9 @@ extern struct rnh *zebra_lookup_rnh(struct prefix *p, vrf_id_t vrfid,
|
||||
extern void zebra_free_rnh(struct rnh *rnh);
|
||||
extern void zebra_add_rnh_client(struct rnh *rnh, struct zserv *client,
|
||||
enum rnh_type type, vrf_id_t vrfid);
|
||||
extern int zebra_send_rnh_update(struct rnh *rnh, struct zserv *client,
|
||||
enum rnh_type type, vrf_id_t vrf_id,
|
||||
uint32_t srte_color);
|
||||
extern void zebra_register_rnh_pseudowire(vrf_id_t, struct zebra_pw *, bool *);
|
||||
extern void zebra_deregister_rnh_pseudowire(vrf_id_t, struct zebra_pw *);
|
||||
extern void zebra_remove_rnh_client(struct rnh *rnh, struct zserv *client,
|
||||
|
378
zebra/zebra_srte.c
Normal file
378
zebra/zebra_srte.c
Normal file
@ -0,0 +1,378 @@
|
||||
/* Zebra SR-TE code
|
||||
* Copyright (C) 2020 NetDEF, Inc.
|
||||
*
|
||||
* This file is part of GNU Zebra.
|
||||
*
|
||||
* GNU Zebra 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.
|
||||
*
|
||||
* GNU Zebra 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 this program; see the file COPYING; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <zebra.h>
|
||||
|
||||
#include "lib/zclient.h"
|
||||
#include "lib/lib_errors.h"
|
||||
|
||||
#include "zebra/zebra_srte.h"
|
||||
#include "zebra/zebra_memory.h"
|
||||
#include "zebra/zebra_mpls.h"
|
||||
#include "zebra/zebra_rnh.h"
|
||||
#include "zebra/zapi_msg.h"
|
||||
|
||||
DEFINE_MTYPE_STATIC(ZEBRA, ZEBRA_SR_POLICY, "SR Policy")
|
||||
|
||||
static void zebra_sr_policy_deactivate(struct zebra_sr_policy *policy);
|
||||
|
||||
/* Generate rb-tree of SR Policy instances. */
|
||||
static inline int
|
||||
zebra_sr_policy_instance_compare(const struct zebra_sr_policy *a,
|
||||
const struct zebra_sr_policy *b)
|
||||
{
|
||||
return sr_policy_compare(&a->endpoint, &b->endpoint, a->color,
|
||||
b->color);
|
||||
}
|
||||
RB_GENERATE(zebra_sr_policy_instance_head, zebra_sr_policy, entry,
|
||||
zebra_sr_policy_instance_compare)
|
||||
|
||||
struct zebra_sr_policy_instance_head zebra_sr_policy_instances =
|
||||
RB_INITIALIZER(&zebra_sr_policy_instances);
|
||||
|
||||
struct zebra_sr_policy *zebra_sr_policy_add(uint32_t color,
|
||||
struct ipaddr *endpoint, char *name)
|
||||
{
|
||||
struct zebra_sr_policy *policy;
|
||||
|
||||
policy = XCALLOC(MTYPE_ZEBRA_SR_POLICY, sizeof(*policy));
|
||||
policy->color = color;
|
||||
policy->endpoint = *endpoint;
|
||||
strlcpy(policy->name, name, sizeof(policy->name));
|
||||
policy->status = ZEBRA_SR_POLICY_DOWN;
|
||||
RB_INSERT(zebra_sr_policy_instance_head, &zebra_sr_policy_instances,
|
||||
policy);
|
||||
|
||||
return policy;
|
||||
}
|
||||
|
||||
void zebra_sr_policy_del(struct zebra_sr_policy *policy)
|
||||
{
|
||||
if (policy->status == ZEBRA_SR_POLICY_UP)
|
||||
zebra_sr_policy_deactivate(policy);
|
||||
RB_REMOVE(zebra_sr_policy_instance_head, &zebra_sr_policy_instances,
|
||||
policy);
|
||||
XFREE(MTYPE_ZEBRA_SR_POLICY, policy);
|
||||
}
|
||||
|
||||
struct zebra_sr_policy *zebra_sr_policy_find(uint32_t color,
|
||||
struct ipaddr *endpoint)
|
||||
{
|
||||
struct zebra_sr_policy policy = {};
|
||||
|
||||
policy.color = color;
|
||||
policy.endpoint = *endpoint;
|
||||
return RB_FIND(zebra_sr_policy_instance_head,
|
||||
&zebra_sr_policy_instances, &policy);
|
||||
}
|
||||
|
||||
struct zebra_sr_policy *zebra_sr_policy_find_by_name(char *name)
|
||||
{
|
||||
struct zebra_sr_policy *policy;
|
||||
|
||||
// TODO: create index for policy names
|
||||
RB_FOREACH (policy, zebra_sr_policy_instance_head,
|
||||
&zebra_sr_policy_instances) {
|
||||
if (strcmp(policy->name, name) == 0)
|
||||
return policy;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int zebra_sr_policy_notify_update_client(struct zebra_sr_policy *policy,
|
||||
struct zserv *client)
|
||||
{
|
||||
const zebra_nhlfe_t *nhlfe;
|
||||
struct stream *s;
|
||||
uint32_t message = 0;
|
||||
unsigned long nump = 0;
|
||||
uint8_t num;
|
||||
struct zapi_nexthop znh;
|
||||
int ret;
|
||||
|
||||
/* Get output stream. */
|
||||
s = stream_new(ZEBRA_MAX_PACKET_SIZ);
|
||||
|
||||
zclient_create_header(s, ZEBRA_NEXTHOP_UPDATE, zvrf_id(policy->zvrf));
|
||||
|
||||
/* Message flags. */
|
||||
SET_FLAG(message, ZAPI_MESSAGE_SRTE);
|
||||
stream_putl(s, message);
|
||||
|
||||
switch (policy->endpoint.ipa_type) {
|
||||
case IPADDR_V4:
|
||||
stream_putw(s, AF_INET);
|
||||
stream_putc(s, IPV4_MAX_BITLEN);
|
||||
stream_put_in_addr(s, &policy->endpoint.ipaddr_v4);
|
||||
break;
|
||||
case IPADDR_V6:
|
||||
stream_putw(s, AF_INET6);
|
||||
stream_putc(s, IPV6_MAX_BITLEN);
|
||||
stream_put(s, &policy->endpoint.ipaddr_v6, IPV6_MAX_BYTELEN);
|
||||
break;
|
||||
default:
|
||||
flog_warn(EC_LIB_DEVELOPMENT,
|
||||
"%s: unknown policy endpoint address family: %u",
|
||||
__func__, policy->endpoint.ipa_type);
|
||||
exit(1);
|
||||
}
|
||||
stream_putl(s, policy->color);
|
||||
|
||||
num = 0;
|
||||
frr_each (nhlfe_list_const, &policy->lsp->nhlfe_list, nhlfe) {
|
||||
if (!CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_SELECTED)
|
||||
|| CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_DELETED))
|
||||
continue;
|
||||
|
||||
if (num == 0) {
|
||||
stream_putc(s, re_type_from_lsp_type(nhlfe->type));
|
||||
stream_putw(s, 0); /* instance - not available */
|
||||
stream_putc(s, nhlfe->distance);
|
||||
stream_putl(s, 0); /* metric - not available */
|
||||
nump = stream_get_endp(s);
|
||||
stream_putc(s, 0);
|
||||
}
|
||||
|
||||
zapi_nexthop_from_nexthop(&znh, nhlfe->nexthop);
|
||||
ret = zapi_nexthop_encode(s, &znh, 0, message);
|
||||
if (ret < 0)
|
||||
goto failure;
|
||||
|
||||
num++;
|
||||
}
|
||||
stream_putc_at(s, nump, num);
|
||||
stream_putw_at(s, 0, stream_get_endp(s));
|
||||
|
||||
client->nh_last_upd_time = monotime(NULL);
|
||||
client->last_write_cmd = ZEBRA_NEXTHOP_UPDATE;
|
||||
return zserv_send_message(client, s);
|
||||
|
||||
failure:
|
||||
|
||||
stream_free(s);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void zebra_sr_policy_notify_update(struct zebra_sr_policy *policy)
|
||||
{
|
||||
struct rnh *rnh;
|
||||
struct prefix p = {};
|
||||
struct zebra_vrf *zvrf;
|
||||
struct listnode *node;
|
||||
struct zserv *client;
|
||||
|
||||
zvrf = policy->zvrf;
|
||||
switch (policy->endpoint.ipa_type) {
|
||||
case IPADDR_V4:
|
||||
p.family = AF_INET;
|
||||
p.prefixlen = IPV4_MAX_BITLEN;
|
||||
p.u.prefix4 = policy->endpoint.ipaddr_v4;
|
||||
break;
|
||||
case IPADDR_V6:
|
||||
p.family = AF_INET6;
|
||||
p.prefixlen = IPV6_MAX_BITLEN;
|
||||
p.u.prefix6 = policy->endpoint.ipaddr_v6;
|
||||
break;
|
||||
default:
|
||||
flog_warn(EC_LIB_DEVELOPMENT,
|
||||
"%s: unknown policy endpoint address family: %u",
|
||||
__func__, policy->endpoint.ipa_type);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
rnh = zebra_lookup_rnh(&p, zvrf_id(zvrf), RNH_NEXTHOP_TYPE);
|
||||
if (!rnh)
|
||||
return;
|
||||
|
||||
for (ALL_LIST_ELEMENTS_RO(rnh->client_list, node, client)) {
|
||||
if (policy->status == ZEBRA_SR_POLICY_UP)
|
||||
zebra_sr_policy_notify_update_client(policy, client);
|
||||
else
|
||||
/* Fallback to the IGP shortest path. */
|
||||
zebra_send_rnh_update(rnh, client, RNH_NEXTHOP_TYPE,
|
||||
zvrf_id(zvrf), policy->color);
|
||||
}
|
||||
}
|
||||
|
||||
static void zebra_sr_policy_activate(struct zebra_sr_policy *policy,
|
||||
zebra_lsp_t *lsp)
|
||||
{
|
||||
policy->status = ZEBRA_SR_POLICY_UP;
|
||||
policy->lsp = lsp;
|
||||
(void)zebra_sr_policy_bsid_install(policy);
|
||||
zsend_sr_policy_notify_status(policy->color, &policy->endpoint,
|
||||
policy->name, ZEBRA_SR_POLICY_UP);
|
||||
zebra_sr_policy_notify_update(policy);
|
||||
}
|
||||
|
||||
static void zebra_sr_policy_update(struct zebra_sr_policy *policy,
|
||||
zebra_lsp_t *lsp,
|
||||
struct zapi_srte_tunnel *old_tunnel)
|
||||
{
|
||||
bool bsid_changed;
|
||||
bool segment_list_changed;
|
||||
|
||||
policy->lsp = lsp;
|
||||
|
||||
bsid_changed =
|
||||
policy->segment_list.local_label != old_tunnel->local_label;
|
||||
segment_list_changed =
|
||||
policy->segment_list.label_num != old_tunnel->label_num
|
||||
|| memcmp(policy->segment_list.labels, old_tunnel->labels,
|
||||
sizeof(mpls_label_t)
|
||||
* policy->segment_list.label_num);
|
||||
|
||||
/* Re-install label stack if necessary. */
|
||||
if (bsid_changed || segment_list_changed) {
|
||||
zebra_sr_policy_bsid_uninstall(policy, old_tunnel->local_label);
|
||||
(void)zebra_sr_policy_bsid_install(policy);
|
||||
}
|
||||
|
||||
zsend_sr_policy_notify_status(policy->color, &policy->endpoint,
|
||||
policy->name, ZEBRA_SR_POLICY_UP);
|
||||
|
||||
/* Handle segment-list update. */
|
||||
if (segment_list_changed)
|
||||
zebra_sr_policy_notify_update(policy);
|
||||
}
|
||||
|
||||
static void zebra_sr_policy_deactivate(struct zebra_sr_policy *policy)
|
||||
{
|
||||
policy->status = ZEBRA_SR_POLICY_DOWN;
|
||||
policy->lsp = NULL;
|
||||
zebra_sr_policy_bsid_uninstall(policy,
|
||||
policy->segment_list.local_label);
|
||||
zsend_sr_policy_notify_status(policy->color, &policy->endpoint,
|
||||
policy->name, ZEBRA_SR_POLICY_DOWN);
|
||||
zebra_sr_policy_notify_update(policy);
|
||||
}
|
||||
|
||||
int zebra_sr_policy_validate(struct zebra_sr_policy *policy,
|
||||
struct zapi_srte_tunnel *new_tunnel)
|
||||
{
|
||||
struct zapi_srte_tunnel old_tunnel = policy->segment_list;
|
||||
zebra_lsp_t *lsp;
|
||||
|
||||
if (new_tunnel)
|
||||
policy->segment_list = *new_tunnel;
|
||||
|
||||
/* Try to resolve the Binding-SID nexthops. */
|
||||
lsp = mpls_lsp_find(policy->zvrf, policy->segment_list.labels[0]);
|
||||
if (!lsp || !lsp->best_nhlfe
|
||||
|| lsp->addr_family != ipaddr_family(&policy->endpoint)) {
|
||||
if (policy->status == ZEBRA_SR_POLICY_UP)
|
||||
zebra_sr_policy_deactivate(policy);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* First label was resolved successfully. */
|
||||
if (policy->status == ZEBRA_SR_POLICY_DOWN)
|
||||
zebra_sr_policy_activate(policy, lsp);
|
||||
else
|
||||
zebra_sr_policy_update(policy, lsp, &old_tunnel);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int zebra_sr_policy_bsid_install(struct zebra_sr_policy *policy)
|
||||
{
|
||||
struct zapi_srte_tunnel *zt = &policy->segment_list;
|
||||
zebra_nhlfe_t *nhlfe;
|
||||
|
||||
if (zt->local_label == MPLS_LABEL_NONE)
|
||||
return 0;
|
||||
|
||||
frr_each_safe (nhlfe_list, &policy->lsp->nhlfe_list, nhlfe) {
|
||||
uint8_t num_out_labels;
|
||||
mpls_label_t *out_labels;
|
||||
mpls_label_t null_label = MPLS_LABEL_IMPLICIT_NULL;
|
||||
|
||||
if (!CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_SELECTED)
|
||||
|| CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_DELETED))
|
||||
continue;
|
||||
|
||||
/*
|
||||
* Don't push the first SID if the corresponding action in the
|
||||
* LFIB is POP.
|
||||
*/
|
||||
if (!nhlfe->nexthop->nh_label
|
||||
|| !nhlfe->nexthop->nh_label->num_labels
|
||||
|| nhlfe->nexthop->nh_label->label[0]
|
||||
== MPLS_LABEL_IMPLICIT_NULL) {
|
||||
if (zt->label_num > 1) {
|
||||
num_out_labels = zt->label_num - 1;
|
||||
out_labels = &zt->labels[1];
|
||||
} else {
|
||||
num_out_labels = 1;
|
||||
out_labels = &null_label;
|
||||
}
|
||||
} else {
|
||||
num_out_labels = zt->label_num;
|
||||
out_labels = zt->labels;
|
||||
}
|
||||
|
||||
if (mpls_lsp_install(
|
||||
policy->zvrf, zt->type, zt->local_label,
|
||||
num_out_labels, out_labels, nhlfe->nexthop->type,
|
||||
&nhlfe->nexthop->gate, nhlfe->nexthop->ifindex)
|
||||
< 0)
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void zebra_sr_policy_bsid_uninstall(struct zebra_sr_policy *policy,
|
||||
mpls_label_t old_bsid)
|
||||
{
|
||||
struct zapi_srte_tunnel *zt = &policy->segment_list;
|
||||
|
||||
mpls_lsp_uninstall_all_vrf(policy->zvrf, zt->type, old_bsid);
|
||||
}
|
||||
|
||||
int zebra_sr_policy_label_update(mpls_label_t label,
|
||||
enum zebra_sr_policy_update_label_mode mode)
|
||||
{
|
||||
struct zebra_sr_policy *policy;
|
||||
|
||||
RB_FOREACH (policy, zebra_sr_policy_instance_head,
|
||||
&zebra_sr_policy_instances) {
|
||||
mpls_label_t next_hop_label;
|
||||
|
||||
next_hop_label = policy->segment_list.labels[0];
|
||||
if (next_hop_label != label)
|
||||
continue;
|
||||
|
||||
switch (mode) {
|
||||
case ZEBRA_SR_POLICY_LABEL_CREATED:
|
||||
case ZEBRA_SR_POLICY_LABEL_UPDATED:
|
||||
case ZEBRA_SR_POLICY_LABEL_REMOVED:
|
||||
zebra_sr_policy_validate(policy, NULL);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void zebra_srte_init(void)
|
||||
{
|
||||
}
|
74
zebra/zebra_srte.h
Normal file
74
zebra/zebra_srte.h
Normal file
@ -0,0 +1,74 @@
|
||||
/* Zebra's client header.
|
||||
* Copyright (C) 2020 Netdef, Inc.
|
||||
*
|
||||
* This file is part of GNU Zebra.
|
||||
*
|
||||
* GNU Zebra 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.
|
||||
*
|
||||
* GNU Zebra 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 this program; see the file COPYING; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef _ZEBRA_SRTE_H
|
||||
#define _ZEBRA_SRTE_H
|
||||
|
||||
#include "zebra/zebra_mpls.h"
|
||||
|
||||
#include "lib/zclient.h"
|
||||
#include "lib/srte.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
enum zebra_sr_policy_update_label_mode {
|
||||
ZEBRA_SR_POLICY_LABEL_CREATED = 1,
|
||||
ZEBRA_SR_POLICY_LABEL_UPDATED = 2,
|
||||
ZEBRA_SR_POLICY_LABEL_REMOVED = 3,
|
||||
};
|
||||
|
||||
struct zebra_sr_policy {
|
||||
RB_ENTRY(zebra_sr_policy) entry;
|
||||
uint32_t color;
|
||||
struct ipaddr endpoint;
|
||||
char name[SRTE_POLICY_NAME_MAX_LENGTH];
|
||||
enum zebra_sr_policy_status status;
|
||||
struct zapi_srte_tunnel segment_list;
|
||||
zebra_lsp_t *lsp;
|
||||
struct zebra_vrf *zvrf;
|
||||
};
|
||||
RB_HEAD(zebra_sr_policy_instance_head, zebra_sr_policy);
|
||||
RB_PROTOTYPE(zebra_sr_policy_instance_head, zebra_sr_policy, entry,
|
||||
zebra_sr_policy_instance_compare)
|
||||
|
||||
extern struct zebra_sr_policy_instance_head zebra_sr_policy_instances;
|
||||
|
||||
struct zebra_sr_policy *
|
||||
zebra_sr_policy_add(uint32_t color, struct ipaddr *endpoint, char *name);
|
||||
void zebra_sr_policy_del(struct zebra_sr_policy *policy);
|
||||
struct zebra_sr_policy *zebra_sr_policy_find(uint32_t color,
|
||||
struct ipaddr *endpoint);
|
||||
struct zebra_sr_policy *zebra_sr_policy_find_by_name(char *name);
|
||||
int zebra_sr_policy_validate(struct zebra_sr_policy *policy,
|
||||
struct zapi_srte_tunnel *new_tunnel);
|
||||
int zebra_sr_policy_bsid_install(struct zebra_sr_policy *policy);
|
||||
void zebra_sr_policy_bsid_uninstall(struct zebra_sr_policy *policy,
|
||||
mpls_label_t old_bsid);
|
||||
void zebra_srte_init(void);
|
||||
int zebra_sr_policy_label_update(mpls_label_t label,
|
||||
enum zebra_sr_policy_update_label_mode mode);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _ZEBRA_SRTE_H */
|
@ -562,6 +562,10 @@ static void show_route_nexthop_helper(struct vty *vty,
|
||||
if (inet_ntop(AF_INET, &nexthop->src.ipv4, buf,
|
||||
sizeof(buf)))
|
||||
vty_out(vty, ", src %s", buf);
|
||||
/* SR-TE information */
|
||||
if (nexthop->srte_color)
|
||||
vty_out(vty, ", SR-TE color %u",
|
||||
nexthop->srte_color);
|
||||
}
|
||||
break;
|
||||
case NEXTHOP_TYPE_IPV6:
|
||||
@ -781,6 +785,9 @@ static void show_nexthop_json_helper(json_object *json_nexthop,
|
||||
json_object_int_add(json_nexthop, "weight",
|
||||
nexthop->weight);
|
||||
|
||||
if (nexthop->srte_color)
|
||||
json_object_int_add(json_nexthop, "srteColor",
|
||||
nexthop->srte_color);
|
||||
}
|
||||
|
||||
static void vty_show_ip_route(struct vty *vty, struct route_node *rn,
|
||||
|
Loading…
Reference in New Issue
Block a user