mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-08-03 15:16:20 +00:00
Merge pull request #8509 from volta-networks/pathd_ls_client
pathd: Traffic Engineering Database support
This commit is contained in:
commit
31db7fc227
@ -28,25 +28,8 @@ documented elsewhere.
|
||||
PCEP Support
|
||||
============
|
||||
|
||||
To build the PCC for pathd, the externall library `pceplib 1.2 <https://github.com/volta-networks/pceplib/tree/devel-1.2>`_ is required.
|
||||
A pceplib is included in the frr source tree and build by default.
|
||||
|
||||
To build FRR with support for PCEP the following steps must be followed:
|
||||
|
||||
- Checkout and build pceplib:
|
||||
|
||||
```
|
||||
$ git clone https://github.com/volta-networks/pceplib
|
||||
$ cd pceplib
|
||||
$ make
|
||||
$ make install
|
||||
$ export PCEPLIB_ROOT=$PWD
|
||||
```
|
||||
|
||||
- Configure FRR with the extra parameters:
|
||||
|
||||
```
|
||||
--enable-pcep LDFLAGS="-L${PCEPLIB_ROOT}/install/lib" CPPFLAGS="-I${PCEPLIB_ROOT}/install/include"
|
||||
```
|
||||
|
||||
To start pathd with pcep support the extra parameter `-M pathd_pcep` should be
|
||||
passed to the pathd daemon.
|
||||
@ -62,10 +45,18 @@ Example:
|
||||
debug pathd pcep basic
|
||||
segment-routing
|
||||
traffic-eng
|
||||
mpls-te on
|
||||
mpls-te import ospfv2
|
||||
segment-list SL1
|
||||
index 10 mpls label 16010
|
||||
index 20 mpls label 16030
|
||||
!
|
||||
segment-list SL2
|
||||
index 10 nai prefix 10.1.2.1/32 iface 1
|
||||
index 20 nai adjacency 10.1.20.1 10.1.20.2
|
||||
index 30 nai prefix 10.10.10.5/32 algorithm 0
|
||||
index 40 mpls label 18001
|
||||
!
|
||||
policy color 1 endpoint 1.1.1.1
|
||||
name default
|
||||
binding-sid 4000
|
||||
@ -113,11 +104,22 @@ Configuration Commands
|
||||
|
||||
Configure segment routing traffic engineering.
|
||||
|
||||
.. clicmd:: [no] mpls-te <on|off>
|
||||
|
||||
Activate/Deactivate use of internal Traffic Engineering Database
|
||||
|
||||
.. clicmd:: [no] mpls-te import <ospfv2|ospfv3|isis>
|
||||
|
||||
Load data from the selected igp
|
||||
|
||||
.. clicmd:: segment-list NAME
|
||||
|
||||
Delete or start a segment list definition.
|
||||
|
||||
.. clicmd:: index INDEX mpls label LABEL [nai node ADDRESS]
|
||||
.. clicmd:: index INDEX mpls label LABEL
|
||||
.. clicmd:: index INDEX nai adjacency A.B.C.D A.B.C.D
|
||||
.. clicmd:: index INDEX nai prefix A.B.C.D/M algorithm <0|1>
|
||||
.. clicmd:: index INDEX nai prefix A.B.C.D/M iface (0-65535)
|
||||
|
||||
Delete or specify a segment in a segment list definition.
|
||||
|
||||
|
297
pathd/path_cli.c
297
pathd/path_cli.c
@ -34,6 +34,7 @@
|
||||
#ifndef VTYSH_EXTRACT_PL
|
||||
#include "pathd/path_cli_clippy.c"
|
||||
#endif
|
||||
#include "pathd/path_ted.h"
|
||||
|
||||
#define XPATH_MAXATTRSIZE 64
|
||||
#define XPATH_MAXKEYSIZE 42
|
||||
@ -47,6 +48,18 @@ static int config_write_segment_routing(struct vty *vty);
|
||||
static int config_write_traffic_eng(struct vty *vty);
|
||||
static int config_write_segment_lists(struct vty *vty);
|
||||
static int config_write_sr_policies(struct vty *vty);
|
||||
static int segment_list_has_src_dst(
|
||||
struct vty *vty, char *xpath, long index, const char *index_str,
|
||||
struct in_addr adj_src_ipv4, struct in_addr adj_dst_ipv4,
|
||||
struct in6_addr adj_src_ipv6, struct in6_addr adj_dst_ipv6,
|
||||
const char *adj_src_ipv4_str, const char *adj_dst_ipv4_str,
|
||||
const char *adj_src_ipv6_str, const char *adj_dst_ipv6_str);
|
||||
static int segment_list_has_prefix(
|
||||
struct vty *vty, char *xpath, long index, const char *index_str,
|
||||
const struct prefix_ipv4 *prefix_ipv4, const char *prefix_ipv4_str,
|
||||
const struct prefix_ipv6 *prefix_ipv6, const char *prefix_ipv6_str,
|
||||
const char *has_algo, long algo, const char *algo_str,
|
||||
const char *has_iface_id, long iface_id, const char *iface_id_str);
|
||||
|
||||
DEFINE_MTYPE_STATIC(PATHD, PATH_CLI, "Client");
|
||||
|
||||
@ -144,6 +157,7 @@ DEFPY(show_srte_policy,
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Show detailed SR-TE info
|
||||
*/
|
||||
@ -295,56 +309,227 @@ void cli_show_srte_segment_list(struct vty *vty, struct lyd_node *dnode,
|
||||
yang_dnode_get_string(dnode, "./name"));
|
||||
}
|
||||
|
||||
static int segment_list_has_src_dst(
|
||||
struct vty *vty, char *xpath, long index, const char *index_str,
|
||||
struct in_addr adj_src_ipv4, struct in_addr adj_dst_ipv4,
|
||||
struct in6_addr adj_src_ipv6, struct in6_addr adj_dst_ipv6,
|
||||
const char *adj_src_ipv4_str, const char *adj_dst_ipv4_str,
|
||||
const char *adj_src_ipv6_str, const char *adj_dst_ipv6_str)
|
||||
{
|
||||
const char *node_src_id;
|
||||
uint32_t ted_sid = MPLS_LABEL_NONE;
|
||||
|
||||
struct ipaddr ip_src = {};
|
||||
struct ipaddr ip_dst = {};
|
||||
if (adj_src_ipv4_str != NULL) {
|
||||
ip_src.ipa_type = IPADDR_V4;
|
||||
ip_src.ip._v4_addr = adj_src_ipv4;
|
||||
ip_dst.ipa_type = IPADDR_V4;
|
||||
ip_dst.ip._v4_addr = adj_dst_ipv4;
|
||||
} else if (adj_src_ipv6_str != NULL) {
|
||||
ip_src.ipa_type = IPADDR_V6;
|
||||
ip_src.ip._v6_addr = adj_src_ipv6;
|
||||
ip_dst.ipa_type = IPADDR_V6;
|
||||
ip_dst.ip._v6_addr = adj_dst_ipv6;
|
||||
} else {
|
||||
return CMD_ERR_NO_MATCH;
|
||||
}
|
||||
ted_sid = path_ted_query_type_f(&ip_src, &ip_dst);
|
||||
if (ted_sid == MPLS_LABEL_NONE) {
|
||||
zlog_warn(
|
||||
"%s: [rcv ted] CLI NOT FOUND Continue query_type_f SRC (%pIA) DST (%pIA)!",
|
||||
__func__, &ip_src, &ip_dst);
|
||||
}
|
||||
/* type */
|
||||
snprintf(xpath, XPATH_MAXLEN, "./segment[index='%s']/nai/type",
|
||||
index_str);
|
||||
if (adj_src_ipv4_str != NULL) {
|
||||
nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY,
|
||||
"ipv4_adjacency");
|
||||
node_src_id = adj_src_ipv4_str;
|
||||
} else if (adj_src_ipv6_str != NULL) {
|
||||
nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY,
|
||||
"ipv6_adjacency");
|
||||
node_src_id = adj_src_ipv6_str;
|
||||
} else {
|
||||
return CMD_ERR_NO_MATCH;
|
||||
}
|
||||
/* addresses */
|
||||
snprintf(xpath, XPATH_MAXLEN, "./segment[index='%s']/nai/local-address",
|
||||
index_str);
|
||||
nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY, node_src_id);
|
||||
snprintf(xpath, XPATH_MAXLEN,
|
||||
"./segment[index='%s']/nai/remote-address", index_str);
|
||||
nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY,
|
||||
adj_dst_ipv4_str ? adj_dst_ipv4_str
|
||||
: adj_dst_ipv6_str);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
int segment_list_has_prefix(
|
||||
struct vty *vty, char *xpath, long index, const char *index_str,
|
||||
const struct prefix_ipv4 *prefix_ipv4, const char *prefix_ipv4_str,
|
||||
const struct prefix_ipv6 *prefix_ipv6, const char *prefix_ipv6_str,
|
||||
const char *has_algo, long algo, const char *algo_str,
|
||||
const char *has_iface_id, long iface_id, const char *iface_id_str)
|
||||
{
|
||||
char buf_prefix[INET6_ADDRSTRLEN];
|
||||
|
||||
uint32_t ted_sid = MPLS_LABEL_NONE;
|
||||
struct prefix prefix_cli = {};
|
||||
struct ipaddr pre_ipaddr = {};
|
||||
/* prefix with algorithm or local interface id */
|
||||
/* Type */
|
||||
snprintf(xpath, XPATH_MAXLEN, "./segment[index='%s']/nai/type",
|
||||
index_str);
|
||||
if (has_iface_id != NULL) {
|
||||
if (prefix_ipv4_str != NULL) {
|
||||
nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY,
|
||||
"ipv4_local_iface");
|
||||
} else if (prefix_ipv6_str != NULL) {
|
||||
nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY,
|
||||
"ipv6_local_iface");
|
||||
} else {
|
||||
return CMD_ERR_NO_MATCH;
|
||||
}
|
||||
} else {
|
||||
if (prefix_ipv4_str != NULL) {
|
||||
nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY,
|
||||
"ipv4_algo");
|
||||
} else if (prefix_ipv6_str != NULL) {
|
||||
nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY,
|
||||
"ipv6_algo");
|
||||
} else {
|
||||
return CMD_ERR_NO_MATCH;
|
||||
}
|
||||
}
|
||||
/* Prefix */
|
||||
if (prefix_ipv4_str != NULL) {
|
||||
if (!str2prefix(prefix_ipv4_str, &prefix_cli)) {
|
||||
vty_out(vty, "%% Malformed prefix\n");
|
||||
return CMD_WARNING_CONFIG_FAILED;
|
||||
}
|
||||
inet_ntop(AF_INET, &prefix_cli.u.prefix4, buf_prefix,
|
||||
sizeof(buf_prefix));
|
||||
pre_ipaddr.ipa_type = IPADDR_V4;
|
||||
pre_ipaddr.ip._v4_addr = prefix_cli.u.prefix4;
|
||||
} else if (prefix_ipv6_str != NULL) {
|
||||
if (!str2prefix(prefix_ipv6_str, &prefix_cli)) {
|
||||
vty_out(vty, "%% Malformed prefix\n");
|
||||
return CMD_WARNING_CONFIG_FAILED;
|
||||
}
|
||||
inet_ntop(AF_INET6, &prefix_cli.u.prefix6, buf_prefix,
|
||||
sizeof(buf_prefix));
|
||||
pre_ipaddr.ipa_type = IPADDR_V6;
|
||||
pre_ipaddr.ip._v6_addr = prefix_cli.u.prefix6;
|
||||
} else {
|
||||
return CMD_ERR_NO_MATCH;
|
||||
}
|
||||
snprintf(xpath, XPATH_MAXLEN, "./segment[index='%s']/nai/local-address",
|
||||
index_str);
|
||||
nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY, buf_prefix);
|
||||
snprintf(xpath, XPATH_MAXLEN,
|
||||
"./segment[index='%s']/nai/local-prefix-len", index_str);
|
||||
nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY,
|
||||
prefix_ipv4_str
|
||||
? strchr(prefix_ipv4_str, '/') + 1
|
||||
: strchr(prefix_ipv6_str, '/') + 1);
|
||||
/* Alg / Iface */
|
||||
if (has_algo != NULL) {
|
||||
snprintf(xpath, XPATH_MAXLEN,
|
||||
"./segment[index='%s']/nai/algorithm", index_str);
|
||||
nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY, algo_str);
|
||||
} else {
|
||||
if (has_iface_id != NULL) {
|
||||
snprintf(xpath, XPATH_MAXLEN,
|
||||
"./segment[index='%s']/nai/local-interface",
|
||||
index_str);
|
||||
nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY,
|
||||
iface_id_str);
|
||||
}
|
||||
}
|
||||
if (has_algo != NULL) {
|
||||
ted_sid = path_ted_query_type_c(&prefix_cli, algo);
|
||||
if (ted_sid == MPLS_LABEL_NONE) {
|
||||
zlog_err(
|
||||
"%s: [rcv ted] CLI NOT FOUND Continue query_type_c PREFIX (%pIA/%d) ALGO (%ld) sid:(%d)!",
|
||||
__func__, &pre_ipaddr, prefix_cli.prefixlen,
|
||||
algo, ted_sid);
|
||||
}
|
||||
}
|
||||
if (has_iface_id != NULL) {
|
||||
ted_sid = path_ted_query_type_e(&prefix_cli, iface_id);
|
||||
if (ted_sid == MPLS_LABEL_NONE) {
|
||||
zlog_err(
|
||||
"%s: [rcv ted] CLI NOT FOUND Continue query_type_e PREFIX (%pIA/%d) IFACE (%ld) sid:(%d)!",
|
||||
__func__, &pre_ipaddr, prefix_cli.prefixlen,
|
||||
iface_id, ted_sid);
|
||||
}
|
||||
}
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
/*
|
||||
* XPath: /frr-pathd:pathd/srte/segment-list/segment
|
||||
*/
|
||||
DEFPY(srte_segment_list_segment,
|
||||
srte_segment_list_segment_cmd,
|
||||
"index (0-4294967295)$index mpls label (16-1048575)$label "
|
||||
/* clang-format off */
|
||||
DEFPY(srte_segment_list_segment, srte_segment_list_segment_cmd,
|
||||
"index (0-4294967295)$index <[mpls$has_mpls_label label (16-1048575)$label] "
|
||||
"|"
|
||||
"[nai$has_nai <"
|
||||
"node <A.B.C.D$node_ipv4|X:X::X:X$node_ipv6>"
|
||||
">]",
|
||||
"prefix <A.B.C.D/M$prefix_ipv4|X:X::X:X/M$prefix_ipv6>"
|
||||
"<algorithm$has_algo (0-1)$algo| iface$has_iface_id (0-4294967295)$iface_id>"
|
||||
"| adjacency$has_adj "
|
||||
"<A.B.C.D$adj_src_ipv4 A.B.C.D$adj_dst_ipv4|X:X::X:X$adj_src_ipv6 X:X::X:X$adj_dst_ipv6>"
|
||||
">]"
|
||||
">",
|
||||
"Index\n"
|
||||
"Index Value\n"
|
||||
"MPLS or IP Label\n"
|
||||
"Label\n"
|
||||
"Label Value\n"
|
||||
"Segment NAI\n"
|
||||
"NAI node identifier\n"
|
||||
"NAI IPv4 node identifier\n"
|
||||
"NAI IPv6 node identifier\n")
|
||||
"NAI prefix identifier\n"
|
||||
"NAI IPv4 prefix identifier\n"
|
||||
"NAI IPv6 prefix identifier\n"
|
||||
"IGP Algorithm\n"
|
||||
"Algorithm Value SPF or Strict-SPF\n"
|
||||
"Interface Id\n"
|
||||
"Interface Value\n"
|
||||
"ADJ identifier\n"
|
||||
"ADJ IPv4 src identifier\n"
|
||||
"ADJ IPv4 dst identifier\n"
|
||||
"ADJ IPv6 src identifier\n"
|
||||
"ADJ IPv6 dst identifier\n")
|
||||
/* clang-format on */
|
||||
{
|
||||
char xpath[XPATH_MAXLEN];
|
||||
const char *node_id;
|
||||
int status = CMD_SUCCESS;
|
||||
|
||||
|
||||
snprintf(xpath, sizeof(xpath), "./segment[index='%s']", index_str);
|
||||
nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
|
||||
|
||||
snprintf(xpath, sizeof(xpath), "./segment[index='%s']/sid-value",
|
||||
index_str);
|
||||
nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY, label_str);
|
||||
|
||||
if (has_nai != NULL) {
|
||||
snprintf(xpath, sizeof(xpath), "./segment[index='%s']/nai/type",
|
||||
index_str);
|
||||
if (node_ipv4_str != NULL) {
|
||||
nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY,
|
||||
"ipv4_node");
|
||||
node_id = node_ipv4_str;
|
||||
} else if (node_ipv6_str != NULL) {
|
||||
nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY,
|
||||
"ipv6_node");
|
||||
node_id = node_ipv6_str;
|
||||
} else {
|
||||
return CMD_ERR_NO_MATCH;
|
||||
}
|
||||
if (has_mpls_label != NULL) {
|
||||
snprintf(xpath, sizeof(xpath),
|
||||
"./segment[index='%s']/nai/local-address", index_str);
|
||||
nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY, node_id);
|
||||
"./segment[index='%s']/sid-value", index_str);
|
||||
nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY, label_str);
|
||||
return nb_cli_apply_changes(vty, NULL);
|
||||
}
|
||||
|
||||
if (has_adj != NULL) {
|
||||
status = segment_list_has_src_dst(vty, xpath, index, index_str,
|
||||
adj_src_ipv4, adj_dst_ipv4,
|
||||
adj_src_ipv6, adj_dst_ipv6,
|
||||
adj_src_ipv4_str, adj_dst_ipv4_str,
|
||||
adj_dst_ipv6_str, adj_src_ipv6_str);
|
||||
if (status != CMD_SUCCESS)
|
||||
return status;
|
||||
} else {
|
||||
snprintf(xpath, sizeof(xpath), "./segment[index='%s']/nai",
|
||||
index_str);
|
||||
nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
|
||||
segment_list_has_prefix(
|
||||
vty, xpath, index, index_str, prefix_ipv4,
|
||||
prefix_ipv4_str, prefix_ipv6, prefix_ipv6_str, has_algo,
|
||||
algo, algo_str, has_iface_id, iface_id, iface_id_str);
|
||||
if (status != CMD_SUCCESS)
|
||||
return status;
|
||||
}
|
||||
|
||||
return nb_cli_apply_changes(vty, NULL);
|
||||
@ -369,23 +554,60 @@ void cli_show_srte_segment_list_segment(struct vty *vty,
|
||||
struct lyd_node *dnode,
|
||||
bool show_defaults)
|
||||
{
|
||||
vty_out(vty, " index %s mpls label %s",
|
||||
yang_dnode_get_string(dnode, "./index"),
|
||||
yang_dnode_get_string(dnode, "./sid-value"));
|
||||
vty_out(vty, " index %s ", yang_dnode_get_string(dnode, "./index"));
|
||||
if (yang_dnode_exists(dnode, "./sid-value")) {
|
||||
vty_out(vty, " mpls label %s",
|
||||
yang_dnode_get_string(dnode, "./sid-value"));
|
||||
}
|
||||
if (yang_dnode_exists(dnode, "./nai")) {
|
||||
struct ipaddr addr;
|
||||
struct ipaddr addr_rmt;
|
||||
|
||||
switch (yang_dnode_get_enum(dnode, "./nai/type")) {
|
||||
case SRTE_SEGMENT_NAI_TYPE_IPV4_NODE:
|
||||
case SRTE_SEGMENT_NAI_TYPE_IPV4_LOCAL_IFACE:
|
||||
case SRTE_SEGMENT_NAI_TYPE_IPV4_ALGORITHM:
|
||||
yang_dnode_get_ip(&addr, dnode, "./nai/local-address");
|
||||
vty_out(vty, " nai node %pI4", &addr.ipaddr_v4);
|
||||
vty_out(vty, " nai prefix %pI4", &addr.ipaddr_v4);
|
||||
break;
|
||||
case SRTE_SEGMENT_NAI_TYPE_IPV6_NODE:
|
||||
case SRTE_SEGMENT_NAI_TYPE_IPV6_LOCAL_IFACE:
|
||||
case SRTE_SEGMENT_NAI_TYPE_IPV6_ALGORITHM:
|
||||
yang_dnode_get_ip(&addr, dnode, "./nai/local-address");
|
||||
vty_out(vty, " nai node %pI6", &addr.ipaddr_v6);
|
||||
vty_out(vty, " nai prefix %pI6", &addr.ipaddr_v6);
|
||||
break;
|
||||
case SRTE_SEGMENT_NAI_TYPE_IPV4_ADJACENCY:
|
||||
yang_dnode_get_ip(&addr, dnode, "./nai/local-address");
|
||||
yang_dnode_get_ip(&addr_rmt, dnode,
|
||||
"./nai/remote-address");
|
||||
vty_out(vty, " nai adjacency %pI4", &addr.ipaddr_v4);
|
||||
vty_out(vty, " %pI4", &addr_rmt.ipaddr_v4);
|
||||
break;
|
||||
case SRTE_SEGMENT_NAI_TYPE_IPV6_ADJACENCY:
|
||||
yang_dnode_get_ip(&addr, dnode, "./nai/local-address");
|
||||
yang_dnode_get_ip(&addr_rmt, dnode,
|
||||
"./nai/remote-address");
|
||||
vty_out(vty, " nai adjacency %pI6", &addr.ipaddr_v6);
|
||||
vty_out(vty, " %pI6", &addr_rmt.ipaddr_v6);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (yang_dnode_exists(dnode, "./nai/local-prefix-len")) {
|
||||
vty_out(vty, "/%s",
|
||||
yang_dnode_get_string(
|
||||
dnode, "./nai/local-prefix-len"));
|
||||
}
|
||||
if (yang_dnode_exists(dnode, "./nai/local-interface")) {
|
||||
vty_out(vty, " iface %s",
|
||||
yang_dnode_get_string(dnode,
|
||||
"./nai/local-interface"));
|
||||
}
|
||||
if (yang_dnode_exists(dnode, "./nai/algorithm")) {
|
||||
vty_out(vty, " algorithm %s",
|
||||
yang_dnode_get_string(dnode,
|
||||
"./nai/algorithm"));
|
||||
}
|
||||
}
|
||||
vty_out(vty, "\n");
|
||||
}
|
||||
@ -1038,6 +1260,7 @@ int config_write_segment_routing(struct vty *vty)
|
||||
int config_write_traffic_eng(struct vty *vty)
|
||||
{
|
||||
vty_out(vty, " traffic-eng\n");
|
||||
path_ted_config_write(vty);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -33,6 +33,7 @@
|
||||
#include "path_nb.h"
|
||||
#include "path_zebra.h"
|
||||
#include "path_errors.h"
|
||||
#include "path_ted.h"
|
||||
|
||||
char backup_config_file[256];
|
||||
|
||||
@ -70,6 +71,8 @@ static void sighup(void)
|
||||
static void sigint(void)
|
||||
{
|
||||
zlog_notice("Terminating on signal");
|
||||
zlog_notice("Unregisterfrom opaque,etc ");
|
||||
pathd_shutdown();
|
||||
|
||||
exit(0);
|
||||
}
|
||||
@ -146,6 +149,7 @@ int main(int argc, char **argv, char **envp)
|
||||
path_error_init();
|
||||
path_zebra_init(master);
|
||||
path_cli_init();
|
||||
path_ted_init(master);
|
||||
|
||||
frr_config_fork();
|
||||
frr_run(master);
|
||||
|
@ -90,6 +90,7 @@ const struct frr_yang_module_info frr_pathd_info = {
|
||||
.xpath = "/frr-pathd:pathd/srte/segment-list/segment/sid-value",
|
||||
.cbs = {
|
||||
.modify = pathd_srte_segment_list_segment_sid_value_modify,
|
||||
.destroy = pathd_srte_segment_list_segment_sid_value_destroy,
|
||||
},
|
||||
.priority = NB_DFLT_PRIORITY - 1
|
||||
},
|
||||
@ -114,6 +115,10 @@ const struct frr_yang_module_info frr_pathd_info = {
|
||||
.xpath = "/frr-pathd:pathd/srte/segment-list/segment/nai/local-interface",
|
||||
.cbs = {.modify = dummy_modify, .destroy = dummy_destroy}
|
||||
},
|
||||
{
|
||||
.xpath = "/frr-pathd:pathd/srte/segment-list/segment/nai/local-prefix-len",
|
||||
.cbs = {.modify = dummy_modify, .destroy = dummy_destroy}
|
||||
},
|
||||
{
|
||||
.xpath = "/frr-pathd:pathd/srte/segment-list/segment/nai/remote-address",
|
||||
.cbs = {.modify = dummy_modify, .destroy = dummy_destroy}
|
||||
@ -122,6 +127,10 @@ const struct frr_yang_module_info frr_pathd_info = {
|
||||
.xpath = "/frr-pathd:pathd/srte/segment-list/segment/nai/remote-interface",
|
||||
.cbs = {.modify = dummy_modify, .destroy = dummy_destroy}
|
||||
},
|
||||
{
|
||||
.xpath = "/frr-pathd:pathd/srte/segment-list/segment/nai/algorithm",
|
||||
.cbs = {.modify = dummy_modify, .destroy = dummy_destroy}
|
||||
},
|
||||
{
|
||||
.xpath = "/frr-pathd:pathd/srte/policy",
|
||||
.cbs = {
|
||||
|
@ -43,6 +43,8 @@ int pathd_srte_segment_list_segment_nai_destroy(
|
||||
struct nb_cb_destroy_args *args);
|
||||
void pathd_srte_segment_list_segment_nai_apply_finish(
|
||||
struct nb_cb_apply_finish_args *args);
|
||||
int pathd_srte_segment_list_segment_sid_value_destroy(
|
||||
struct nb_cb_destroy_args *args);
|
||||
int pathd_srte_policy_create(struct nb_cb_create_args *args);
|
||||
int pathd_srte_policy_destroy(struct nb_cb_destroy_args *args);
|
||||
const void *pathd_srte_policy_get_next(struct nb_cb_get_next_args *args);
|
||||
|
@ -160,6 +160,22 @@ int pathd_srte_segment_list_segment_sid_value_modify(
|
||||
return NB_OK;
|
||||
}
|
||||
|
||||
int pathd_srte_segment_list_segment_sid_value_destroy(
|
||||
struct nb_cb_destroy_args *args)
|
||||
{
|
||||
struct srte_segment_entry *segment;
|
||||
|
||||
if (args->event != NB_EV_APPLY)
|
||||
return NB_OK;
|
||||
|
||||
segment = nb_running_get_entry(args->dnode, NULL, true);
|
||||
segment->sid_value = MPLS_LABEL_NONE;
|
||||
SET_FLAG(segment->segment_list->flags, F_SEGMENT_LIST_MODIFIED);
|
||||
|
||||
return NB_OK;
|
||||
}
|
||||
|
||||
|
||||
int pathd_srte_segment_list_segment_nai_destroy(struct nb_cb_destroy_args *args)
|
||||
{
|
||||
struct srte_segment_entry *segment;
|
||||
@ -184,6 +200,8 @@ void pathd_srte_segment_list_segment_nai_apply_finish(
|
||||
enum srte_segment_nai_type type;
|
||||
struct ipaddr local_addr, remote_addr;
|
||||
uint32_t local_iface = 0, remote_iface = 0;
|
||||
uint8_t algo = 0, local_prefix_len = 0;
|
||||
const char *algo_buf, *local_prefix_len_buf;
|
||||
|
||||
segment = nb_running_get_entry(args->dnode, NULL, true);
|
||||
type = yang_dnode_get_enum(args->dnode, "./type");
|
||||
@ -207,12 +225,31 @@ void pathd_srte_segment_list_segment_nai_apply_finish(
|
||||
remote_iface = yang_dnode_get_uint32(args->dnode,
|
||||
"./remote-interface");
|
||||
break;
|
||||
case SRTE_SEGMENT_NAI_TYPE_IPV4_ALGORITHM:
|
||||
algo_buf = yang_dnode_get_string(args->dnode, "./algorithm");
|
||||
algo = atoi(algo_buf);
|
||||
local_prefix_len_buf = yang_dnode_get_string(
|
||||
args->dnode, "./local-prefix-len");
|
||||
local_prefix_len = atoi(local_prefix_len_buf);
|
||||
break;
|
||||
case SRTE_SEGMENT_NAI_TYPE_IPV4_LOCAL_IFACE:
|
||||
local_iface =
|
||||
yang_dnode_get_uint32(args->dnode, "./local-interface");
|
||||
local_prefix_len_buf = yang_dnode_get_string(
|
||||
args->dnode, "./local-prefix-len");
|
||||
local_prefix_len = atoi(local_prefix_len_buf);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
srte_segment_entry_set_nai(segment, type, &local_addr, local_iface,
|
||||
&remote_addr, remote_iface);
|
||||
zlog_debug(" Segment list name (%d) index (%s) ", segment->index,
|
||||
segment->segment_list->name);
|
||||
if (srte_segment_entry_set_nai(segment, type, &local_addr, local_iface,
|
||||
&remote_addr, remote_iface, algo,
|
||||
local_prefix_len))
|
||||
SET_FLAG(segment->segment_list->flags,
|
||||
F_SEGMENT_LIST_SID_CONFLICT);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -246,6 +246,10 @@ path_pcep_config_list_path_hops(struct srte_segment_list *segment_list)
|
||||
switch (segment->nai_type) {
|
||||
case SRTE_SEGMENT_NAI_TYPE_IPV4_NODE:
|
||||
case SRTE_SEGMENT_NAI_TYPE_IPV6_NODE:
|
||||
case SRTE_SEGMENT_NAI_TYPE_IPV4_LOCAL_IFACE:
|
||||
case SRTE_SEGMENT_NAI_TYPE_IPV6_LOCAL_IFACE:
|
||||
case SRTE_SEGMENT_NAI_TYPE_IPV4_ALGORITHM:
|
||||
case SRTE_SEGMENT_NAI_TYPE_IPV6_ALGORITHM:
|
||||
memcpy(&hop->nai.local_addr, &segment->nai_local_addr,
|
||||
sizeof(struct ipaddr));
|
||||
break;
|
||||
@ -278,6 +282,7 @@ int path_pcep_config_update_path(struct path *path)
|
||||
assert(path->nbkey.preference != 0);
|
||||
assert(path->nbkey.endpoint.ipa_type == IPADDR_V4);
|
||||
|
||||
int number_of_sid_clashed = 0;
|
||||
struct path_hop *hop;
|
||||
struct path_metric *metric;
|
||||
int index;
|
||||
@ -297,40 +302,44 @@ int path_pcep_config_update_path(struct path *path)
|
||||
if (candidate->lsp->segment_list) {
|
||||
SET_FLAG(candidate->lsp->segment_list->flags,
|
||||
F_SEGMENT_LIST_DELETED);
|
||||
srte_segment_list_del(candidate->lsp->segment_list);
|
||||
candidate->lsp->segment_list = NULL;
|
||||
}
|
||||
|
||||
if (path->first_hop != NULL) {
|
||||
snprintf(segment_list_name_buff, sizeof(segment_list_name_buff),
|
||||
"%s-%u", path->name, path->plsp_id);
|
||||
segment_list_name = segment_list_name_buff;
|
||||
if (path->first_hop == NULL)
|
||||
return PATH_NB_ERR;
|
||||
|
||||
segment_list = srte_segment_list_add(segment_list_name);
|
||||
segment_list->protocol_origin = path->update_origin;
|
||||
strlcpy(segment_list->originator, path->originator,
|
||||
sizeof(segment_list->originator));
|
||||
SET_FLAG(segment_list->flags, F_SEGMENT_LIST_NEW);
|
||||
SET_FLAG(segment_list->flags, F_SEGMENT_LIST_MODIFIED);
|
||||
snprintf(segment_list_name_buff, sizeof(segment_list_name_buff),
|
||||
"%s-%u", path->name, path->plsp_id);
|
||||
segment_list_name = segment_list_name_buff;
|
||||
|
||||
for (hop = path->first_hop, index = 10; hop != NULL;
|
||||
hop = hop->next, index += 10) {
|
||||
assert(hop->has_sid);
|
||||
assert(hop->is_mpls);
|
||||
segment_list = srte_segment_list_add(segment_list_name);
|
||||
segment_list->protocol_origin = path->update_origin;
|
||||
strlcpy(segment_list->originator, path->originator,
|
||||
sizeof(segment_list->originator));
|
||||
SET_FLAG(segment_list->flags, F_SEGMENT_LIST_NEW);
|
||||
SET_FLAG(segment_list->flags, F_SEGMENT_LIST_MODIFIED);
|
||||
|
||||
segment = srte_segment_entry_add(segment_list, index);
|
||||
for (hop = path->first_hop, index = 10; hop != NULL;
|
||||
hop = hop->next, index += 10) {
|
||||
assert(hop->has_sid);
|
||||
assert(hop->is_mpls);
|
||||
|
||||
segment->sid_value = (mpls_label_t)hop->sid.mpls.label;
|
||||
SET_FLAG(segment->segment_list->flags,
|
||||
F_SEGMENT_LIST_MODIFIED);
|
||||
segment = srte_segment_entry_add(segment_list, index);
|
||||
|
||||
if (hop->has_nai)
|
||||
srte_segment_entry_set_nai(
|
||||
segment, srte_nai_type(hop->nai.type),
|
||||
&hop->nai.local_addr,
|
||||
hop->nai.local_iface,
|
||||
&hop->nai.remote_addr,
|
||||
hop->nai.remote_iface);
|
||||
}
|
||||
segment->sid_value = (mpls_label_t)hop->sid.mpls.label;
|
||||
SET_FLAG(segment->segment_list->flags, F_SEGMENT_LIST_MODIFIED);
|
||||
|
||||
if (!hop->has_nai)
|
||||
continue;
|
||||
if (srte_segment_entry_set_nai(
|
||||
segment, srte_nai_type(hop->nai.type),
|
||||
&hop->nai.local_addr, hop->nai.local_iface,
|
||||
&hop->nai.remote_addr, hop->nai.remote_iface, 0, 0)
|
||||
== PATH_SID_ERROR)
|
||||
/* TED queries don't match PCE */
|
||||
/* Don't apply srte,zebra changes */
|
||||
number_of_sid_clashed++;
|
||||
}
|
||||
|
||||
candidate->lsp->segment_list = segment_list;
|
||||
@ -352,7 +361,11 @@ int path_pcep_config_update_path(struct path *path)
|
||||
candidate->lsp->objfun = path->pce_objfun;
|
||||
}
|
||||
|
||||
srte_apply_changes();
|
||||
if (number_of_sid_clashed)
|
||||
SET_FLAG(segment->segment_list->flags,
|
||||
F_SEGMENT_LIST_SID_CONFLICT);
|
||||
else
|
||||
srte_apply_changes();
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -402,6 +415,16 @@ enum pcep_sr_subobj_nai pcep_nai_type(enum srte_segment_nai_type type)
|
||||
return PCEP_SR_SUBOBJ_NAI_IPV6_ADJACENCY;
|
||||
case SRTE_SEGMENT_NAI_TYPE_IPV4_UNNUMBERED_ADJACENCY:
|
||||
return PCEP_SR_SUBOBJ_NAI_UNNUMBERED_IPV4_ADJACENCY;
|
||||
case SRTE_SEGMENT_NAI_TYPE_IPV6_ADJACENCY_LINK_LOCAL_ADDRESSES:
|
||||
return PCEP_SR_SUBOBJ_NAI_LINK_LOCAL_IPV6_ADJACENCY;
|
||||
case SRTE_SEGMENT_NAI_TYPE_IPV4_LOCAL_IFACE:
|
||||
return PCEP_SR_SUBOBJ_NAI_IPV4_NODE;
|
||||
case SRTE_SEGMENT_NAI_TYPE_IPV6_LOCAL_IFACE:
|
||||
return PCEP_SR_SUBOBJ_NAI_IPV6_NODE;
|
||||
case SRTE_SEGMENT_NAI_TYPE_IPV4_ALGORITHM:
|
||||
return PCEP_SR_SUBOBJ_NAI_IPV4_NODE;
|
||||
case SRTE_SEGMENT_NAI_TYPE_IPV6_ALGORITHM:
|
||||
return PCEP_SR_SUBOBJ_NAI_IPV6_NODE;
|
||||
default:
|
||||
return PCEP_SR_SUBOBJ_NAI_UNKNOWN;
|
||||
}
|
||||
|
726
pathd/path_ted.c
Normal file
726
pathd/path_ted.c
Normal file
@ -0,0 +1,726 @@
|
||||
/*
|
||||
* Copyright (C) 2020 Volta Networks, Inc
|
||||
*
|
||||
* This program 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 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program 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 Lesser General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "stdlib.h"
|
||||
|
||||
#include <zebra.h>
|
||||
|
||||
#include "memory.h"
|
||||
#include "log.h"
|
||||
#include "command.h"
|
||||
#include "prefix.h"
|
||||
#include <lib/json.h>
|
||||
|
||||
#include "pathd.h"
|
||||
#include "pathd/path_errors.h"
|
||||
#include "pathd/path_ted.h"
|
||||
|
||||
#ifndef VTYSH_EXTRACT_PL
|
||||
#include "pathd/path_ted_clippy.c"
|
||||
#endif
|
||||
|
||||
static struct ls_ted *path_ted_create_ted(void);
|
||||
static void path_ted_register_vty(void);
|
||||
static void path_ted_unregister_vty(void);
|
||||
static uint32_t path_ted_start_importing_igp(const char *daemon_str);
|
||||
static uint32_t path_ted_stop_importing_igp(void);
|
||||
static enum zclient_send_status path_ted_link_state_sync(void);
|
||||
static int path_ted_timer_handler_sync(struct thread *thread);
|
||||
static int path_ted_timer_handler_refresh(struct thread *thread);
|
||||
static int path_ted_cli_debug_config_write(struct vty *vty);
|
||||
static int path_ted_cli_debug_set_all(uint32_t flags, bool set);
|
||||
|
||||
extern struct zclient *zclient;
|
||||
|
||||
struct ted_state ted_state_g = {};
|
||||
|
||||
/*
|
||||
* path_path_ted public API function implementations
|
||||
*/
|
||||
|
||||
void path_ted_init(struct thread_master *master)
|
||||
{
|
||||
ted_state_g.main = master;
|
||||
ted_state_g.link_state_delay_interval = TIMER_RETRY_DELAY;
|
||||
ted_state_g.segment_list_refresh_interval = TIMER_RETRY_DELAY;
|
||||
path_ted_register_vty();
|
||||
path_ted_segment_list_refresh();
|
||||
}
|
||||
|
||||
uint32_t path_ted_teardown(void)
|
||||
{
|
||||
PATH_TED_DEBUG("%s : TED [%p]", __func__, ted_state_g.ted);
|
||||
path_ted_unregister_vty();
|
||||
path_ted_stop_importing_igp();
|
||||
ls_ted_del_all(ted_state_g.ted);
|
||||
path_ted_timer_sync_cancel();
|
||||
path_ted_timer_refresh_cancel();
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set all needed to receive igp data.
|
||||
*
|
||||
* @return true if ok
|
||||
*
|
||||
*/
|
||||
uint32_t path_ted_start_importing_igp(const char *daemon_str)
|
||||
{
|
||||
uint32_t status = 0;
|
||||
|
||||
if (strcmp(daemon_str, "ospfv2") == 0)
|
||||
ted_state_g.import = IMPORT_OSPFv2;
|
||||
else if (strcmp(daemon_str, "ospfv3") == 0) {
|
||||
ted_state_g.import = IMPORT_UNKNOWN;
|
||||
return 1;
|
||||
} else if (strcmp(daemon_str, "isis") == 0)
|
||||
ted_state_g.import = IMPORT_ISIS;
|
||||
else {
|
||||
ted_state_g.import = IMPORT_UNKNOWN;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (ls_register(zclient, false /*client*/) != 0) {
|
||||
PATH_TED_ERROR("%s: PATHD-TED: Unable to register Link State",
|
||||
__func__);
|
||||
ted_state_g.import = IMPORT_UNKNOWN;
|
||||
status = 1;
|
||||
} else {
|
||||
if (path_ted_link_state_sync() != -1) {
|
||||
PATH_TED_DEBUG("%s: PATHD-TED: Importing %s data ON",
|
||||
__func__,
|
||||
PATH_TED_IGP_PRINT(ted_state_g.import));
|
||||
} else {
|
||||
PATH_TED_WARN("%s: PATHD-TED: Importing %s data OFF",
|
||||
__func__,
|
||||
PATH_TED_IGP_PRINT(ted_state_g.import));
|
||||
ted_state_g.import = IMPORT_UNKNOWN;
|
||||
}
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unset all needed to receive igp data.
|
||||
*
|
||||
* @return true if ok
|
||||
*
|
||||
*/
|
||||
uint32_t path_ted_stop_importing_igp(void)
|
||||
{
|
||||
uint32_t status = 0;
|
||||
|
||||
if (ted_state_g.import != IMPORT_UNKNOWN) {
|
||||
if (ls_unregister(zclient, false /*client*/) != 0) {
|
||||
PATH_TED_ERROR(
|
||||
"%s: PATHD-TED: Unable to unregister Link State",
|
||||
__func__);
|
||||
status = 1;
|
||||
} else {
|
||||
ted_state_g.import = IMPORT_UNKNOWN;
|
||||
PATH_TED_DEBUG("%s: PATHD-TED: Importing igp data OFF",
|
||||
__func__);
|
||||
}
|
||||
path_ted_timer_sync_cancel();
|
||||
}
|
||||
return status;
|
||||
}
|
||||
/**
|
||||
* Check for ted status
|
||||
*
|
||||
* @return true if ok
|
||||
*
|
||||
*/
|
||||
bool path_ted_is_initialized(void)
|
||||
{
|
||||
if (ted_state_g.ted == NULL) {
|
||||
PATH_TED_WARN("PATHD TED ls_ted not initialized");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an empty ted
|
||||
*
|
||||
* @param void
|
||||
*
|
||||
* @return Ptr to ted or NULL
|
||||
*/
|
||||
struct ls_ted *path_ted_create_ted()
|
||||
{
|
||||
struct ls_ted *ted = ls_ted_new(TED_KEY, TED_NAME, TED_ASN);
|
||||
|
||||
if (ted == NULL) {
|
||||
PATH_TED_ERROR("%s Unable to initialize TED Key [%d] ASN [%d] Name [%s]",
|
||||
__func__, TED_KEY, TED_ASN, TED_NAME);
|
||||
} else {
|
||||
PATH_TED_INFO("%s Initialize TED Key [%d] ASN [%d] Name [%s]",
|
||||
__func__, TED_KEY, TED_ASN, TED_NAME);
|
||||
}
|
||||
|
||||
return ted;
|
||||
}
|
||||
|
||||
uint32_t path_ted_rcvd_message(struct ls_message *msg)
|
||||
{
|
||||
if (!path_ted_is_initialized())
|
||||
return 1;
|
||||
|
||||
if (msg == NULL) {
|
||||
PATH_TED_ERROR("%s: [rcv ted] TED received NULL message ",
|
||||
__func__);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (path_ted_get_current_igp(msg->data.node->adv.origin))
|
||||
return 1;
|
||||
|
||||
switch (msg->type) {
|
||||
case LS_MSG_TYPE_NODE:
|
||||
ls_msg2vertex(ted_state_g.ted, msg, true /*hard delete*/);
|
||||
break;
|
||||
|
||||
case LS_MSG_TYPE_ATTRIBUTES:
|
||||
ls_msg2edge(ted_state_g.ted, msg, true /*ĥard delete*/);
|
||||
break;
|
||||
|
||||
case LS_MSG_TYPE_PREFIX:
|
||||
ls_msg2subnet(ted_state_g.ted, msg, true /*hard delete*/);
|
||||
break;
|
||||
|
||||
default:
|
||||
PATH_TED_DEBUG(
|
||||
"%s: [rcv ted] TED received unknown message type [%d]",
|
||||
__func__, msg->type);
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t path_ted_query_type_f(struct ipaddr *local, struct ipaddr *remote)
|
||||
{
|
||||
uint32_t sid = MPLS_LABEL_NONE;
|
||||
struct ls_edge *edge;
|
||||
uint64_t key;
|
||||
|
||||
if (!path_ted_is_initialized())
|
||||
return MPLS_LABEL_NONE;
|
||||
|
||||
if (!local || !remote)
|
||||
return MPLS_LABEL_NONE;
|
||||
|
||||
switch (local->ipa_type) {
|
||||
case IPADDR_V4:
|
||||
/* We have local and remote ip */
|
||||
/* so check all attributes in ted */
|
||||
key = ((uint64_t)ntohl(local->ip._v4_addr.s_addr)) & 0xffffffff;
|
||||
edge = ls_find_edge_by_key(ted_state_g.ted, key);
|
||||
if (edge) {
|
||||
if (edge->attributes->standard.remote.s_addr
|
||||
== remote->ip._v4_addr.s_addr
|
||||
&& CHECK_FLAG(edge->attributes->flags,
|
||||
LS_ATTR_ADJ_SID)) {
|
||||
sid = edge->attributes->adj_sid[0]
|
||||
.sid; /* from primary */
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case IPADDR_V6:
|
||||
key = (uint64_t)(local->ip._v6_addr.s6_addr32[0] & 0xffffffff)
|
||||
| ((uint64_t)local->ip._v6_addr.s6_addr32[1] << 32);
|
||||
edge = ls_find_edge_by_key(ted_state_g.ted, key);
|
||||
if (edge) {
|
||||
if ((memcmp(&edge->attributes->standard.remote6,
|
||||
&remote->ip._v6_addr,
|
||||
sizeof(remote->ip._v6_addr))
|
||||
&& CHECK_FLAG(edge->attributes->flags,
|
||||
LS_ATTR_ADJ_SID))) {
|
||||
sid = edge->attributes->adj_sid[0]
|
||||
.sid; /* from primary */
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case IPADDR_NONE:
|
||||
break;
|
||||
}
|
||||
|
||||
return sid;
|
||||
}
|
||||
|
||||
uint32_t path_ted_query_type_c(struct prefix *prefix, uint8_t algo)
|
||||
{
|
||||
uint32_t sid = MPLS_LABEL_NONE;
|
||||
struct ls_subnet *subnet;
|
||||
|
||||
if (!path_ted_is_initialized())
|
||||
return MPLS_LABEL_NONE;
|
||||
|
||||
if (!prefix)
|
||||
return MPLS_LABEL_NONE;
|
||||
|
||||
switch (prefix->family) {
|
||||
case AF_INET:
|
||||
case AF_INET6:
|
||||
subnet = ls_find_subnet(ted_state_g.ted, *prefix);
|
||||
if (subnet) {
|
||||
if ((CHECK_FLAG(subnet->ls_pref->flags, LS_PREF_SR))
|
||||
&& (subnet->ls_pref->sr.algo == algo))
|
||||
sid = subnet->ls_pref->sr.sid;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return sid;
|
||||
}
|
||||
|
||||
uint32_t path_ted_query_type_e(struct prefix *prefix, uint32_t iface_id)
|
||||
{
|
||||
uint32_t sid = MPLS_LABEL_NONE;
|
||||
struct ls_subnet *subnet;
|
||||
struct listnode *lst_node;
|
||||
struct ls_edge *edge;
|
||||
|
||||
if (!path_ted_is_initialized())
|
||||
return MPLS_LABEL_NONE;
|
||||
|
||||
if (!prefix)
|
||||
return MPLS_LABEL_NONE;
|
||||
|
||||
switch (prefix->family) {
|
||||
case AF_INET:
|
||||
case AF_INET6:
|
||||
subnet = ls_find_subnet(ted_state_g.ted, *prefix);
|
||||
if (subnet && subnet->vertex
|
||||
&& subnet->vertex->outgoing_edges) {
|
||||
/* from the vertex linked in subnet */
|
||||
/* loop over outgoing edges */
|
||||
for (ALL_LIST_ELEMENTS_RO(
|
||||
subnet->vertex->outgoing_edges, lst_node,
|
||||
edge)) {
|
||||
/* and look for ifaceid */
|
||||
/* so get sid of attribute */
|
||||
if (CHECK_FLAG(edge->attributes->flags,
|
||||
LS_ATTR_LOCAL_ID)
|
||||
&& edge->attributes->standard.local_id
|
||||
== iface_id) {
|
||||
sid = subnet->ls_pref->sr.sid;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return sid;
|
||||
}
|
||||
|
||||
DEFPY (debug_path_ted,
|
||||
debug_path_ted_cmd,
|
||||
"[no] debug pathd mpls-te",
|
||||
NO_STR
|
||||
DEBUG_STR
|
||||
"path debugging\n"
|
||||
"ted debugging\n")
|
||||
{
|
||||
uint32_t mode = DEBUG_NODE2MODE(vty->node);
|
||||
bool no_debug = (no != NULL);
|
||||
|
||||
DEBUG_MODE_SET(&ted_state_g.dbg, mode, !no);
|
||||
DEBUG_FLAGS_SET(&ted_state_g.dbg, PATH_TED_DEBUG_BASIC, !no_debug);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
* Followings are vty command functions.
|
||||
*/
|
||||
/* clang-format off */
|
||||
DEFUN (path_ted_on,
|
||||
path_ted_on_cmd,
|
||||
"mpls-te on",
|
||||
NO_STR
|
||||
"Enable the TE database (TED) functionality\n")
|
||||
/* clang-format on */
|
||||
{
|
||||
|
||||
if (ted_state_g.enabled) {
|
||||
PATH_TED_DEBUG("%s: PATHD-TED: Enabled ON -> ON.", __func__);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
ted_state_g.ted = path_ted_create_ted();
|
||||
ted_state_g.enabled = true;
|
||||
PATH_TED_DEBUG("%s: PATHD-TED: Enabled OFF -> ON.", __func__);
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
/* clang-format off */
|
||||
DEFUN (no_path_ted,
|
||||
no_path_ted_cmd,
|
||||
"no mpls-te [on]",
|
||||
NO_STR
|
||||
NO_STR
|
||||
"Disable the TE Database functionality\n")
|
||||
/* clang-format on */
|
||||
{
|
||||
if (ted_state_g.enabled) {
|
||||
PATH_TED_DEBUG("%s: PATHD-TED: OFF -> OFF", __func__);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
/* Remove TED */
|
||||
ls_ted_del_all(ted_state_g.ted);
|
||||
ted_state_g.enabled = false;
|
||||
PATH_TED_DEBUG("%s: PATHD-TED: ON -> OFF", __func__);
|
||||
ted_state_g.import = IMPORT_UNKNOWN;
|
||||
if (ls_unregister(zclient, false /*client*/) != 0) {
|
||||
vty_out(vty, "Unable to unregister Link State\n");
|
||||
return CMD_WARNING;
|
||||
}
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
/* clang-format off */
|
||||
DEFPY(path_ted_import,
|
||||
path_ted_import_cmd,
|
||||
"mpls-te import <ospfv2|ospfv3|isis>$import_daemon",
|
||||
"Enable the TE database (TED) fill with remote igp data\n"
|
||||
"import\n"
|
||||
"Origin ospfv2\n"
|
||||
"Origin ospfv3\n"
|
||||
"Origin isis\n")
|
||||
/* clang-format on */
|
||||
{
|
||||
|
||||
if (ted_state_g.enabled)
|
||||
if (path_ted_start_importing_igp(import_daemon)) {
|
||||
vty_out(vty, "Unable to start importing\n");
|
||||
return CMD_WARNING;
|
||||
}
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
/* clang-format off */
|
||||
DEFUN (no_path_ted_import,
|
||||
no_path_ted_import_cmd,
|
||||
"no mpls-te import",
|
||||
NO_STR
|
||||
NO_STR
|
||||
"Disable the TE Database fill with remote igp data\n")
|
||||
/* clang-format on */
|
||||
{
|
||||
|
||||
if (ted_state_g.import) {
|
||||
if (path_ted_stop_importing_igp()) {
|
||||
vty_out(vty, "Unable to stop importing\n");
|
||||
return CMD_WARNING;
|
||||
} else {
|
||||
PATH_TED_DEBUG(
|
||||
"%s: PATHD-TED: Importing igp data already OFF",
|
||||
__func__);
|
||||
}
|
||||
}
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
/* clang-format off */
|
||||
DEFPY (show_pahtd_ted_db,
|
||||
show_pathd_ted_db_cmd,
|
||||
"show pathd ted database <verbose|json>$ver_json ",
|
||||
"show command\n"
|
||||
"pathd daemon\n"
|
||||
"traffic eng\n"
|
||||
"database\n"
|
||||
"verbose output\n"
|
||||
"Show complete received TED database\n")
|
||||
/* clang-format on */
|
||||
{
|
||||
bool st_json = false;
|
||||
json_object *json = NULL;
|
||||
|
||||
if (!ted_state_g.enabled) {
|
||||
vty_out(vty, "PATHD TED database is not enabled\n");
|
||||
return CMD_WARNING;
|
||||
}
|
||||
if (strcmp(ver_json, "json") == 0) {
|
||||
st_json = true;
|
||||
json = json_object_new_object();
|
||||
}
|
||||
/* Show the complete TED */
|
||||
ls_show_ted(ted_state_g.ted, vty, json, !st_json);
|
||||
if (st_json) {
|
||||
vty_out(vty, "%s\n",
|
||||
json_object_to_json_string_ext(
|
||||
json, JSON_C_TO_STRING_PRETTY));
|
||||
json_object_free(json);
|
||||
}
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
* Config Write functions
|
||||
*/
|
||||
|
||||
int path_ted_cli_debug_config_write(struct vty *vty)
|
||||
{
|
||||
if (DEBUG_MODE_CHECK(&ted_state_g.dbg, DEBUG_MODE_CONF)) {
|
||||
if (DEBUG_FLAGS_CHECK(&ted_state_g.dbg, PATH_TED_DEBUG_BASIC))
|
||||
vty_out(vty, "debug pathd mpls-te\n");
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int path_ted_cli_debug_set_all(uint32_t flags, bool set)
|
||||
{
|
||||
DEBUG_FLAGS_SET(&ted_state_g.dbg, flags, set);
|
||||
|
||||
/* If all modes have been turned off, don't preserve options. */
|
||||
if (!DEBUG_MODE_CHECK(&ted_state_g.dbg, DEBUG_MODE_ALL))
|
||||
DEBUG_CLEAR(&ted_state_g.dbg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Help fn to show ted related configuration
|
||||
*
|
||||
* @param vty
|
||||
*
|
||||
* @return Status
|
||||
*/
|
||||
uint32_t path_ted_config_write(struct vty *vty)
|
||||
{
|
||||
|
||||
if (ted_state_g.enabled) {
|
||||
vty_out(vty, " mpls-te on\n");
|
||||
switch (ted_state_g.import) {
|
||||
case IMPORT_ISIS:
|
||||
vty_out(vty, " mpls-te import isis\n");
|
||||
break;
|
||||
case IMPORT_OSPFv2:
|
||||
vty_out(vty, " mpls-te import ospfv2\n");
|
||||
break;
|
||||
case IMPORT_OSPFv3:
|
||||
vty_out(vty, " mpls-te import ospfv3\n");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the fn's for CLI and hook for config show
|
||||
*
|
||||
* @param void
|
||||
*
|
||||
*/
|
||||
static void path_ted_register_vty(void)
|
||||
{
|
||||
install_element(VIEW_NODE, &show_pathd_ted_db_cmd);
|
||||
install_element(SR_TRAFFIC_ENG_NODE, &path_ted_on_cmd);
|
||||
install_element(SR_TRAFFIC_ENG_NODE, &no_path_ted_cmd);
|
||||
install_element(SR_TRAFFIC_ENG_NODE, &path_ted_import_cmd);
|
||||
install_element(SR_TRAFFIC_ENG_NODE, &no_path_ted_import_cmd);
|
||||
|
||||
install_element(CONFIG_NODE, &debug_path_ted_cmd);
|
||||
install_element(ENABLE_NODE, &debug_path_ted_cmd);
|
||||
|
||||
hook_register(nb_client_debug_config_write,
|
||||
path_ted_cli_debug_config_write);
|
||||
hook_register(nb_client_debug_set_all, path_ted_cli_debug_set_all);
|
||||
}
|
||||
|
||||
/**
|
||||
* UnRegister the fn's for CLI and hook for config show
|
||||
*
|
||||
* @param void
|
||||
*
|
||||
*/
|
||||
static void path_ted_unregister_vty(void)
|
||||
{
|
||||
uninstall_element(VIEW_NODE, &show_pathd_ted_db_cmd);
|
||||
uninstall_element(SR_TRAFFIC_ENG_NODE, &path_ted_on_cmd);
|
||||
uninstall_element(SR_TRAFFIC_ENG_NODE, &no_path_ted_cmd);
|
||||
uninstall_element(SR_TRAFFIC_ENG_NODE, &path_ted_import_cmd);
|
||||
uninstall_element(SR_TRAFFIC_ENG_NODE, &no_path_ted_import_cmd);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ask igp for a complete TED so far
|
||||
*
|
||||
* @param void
|
||||
*
|
||||
* @return zclient status
|
||||
*/
|
||||
enum zclient_send_status path_ted_link_state_sync(void)
|
||||
{
|
||||
enum zclient_send_status status;
|
||||
|
||||
status = ls_request_sync(zclient);
|
||||
if (status == -1) {
|
||||
PATH_TED_ERROR(
|
||||
"%s: PATHD-TED: Opaque error asking for TED sync ",
|
||||
__func__);
|
||||
return status;
|
||||
} else {
|
||||
PATH_TED_DEBUG("%s: PATHD-TED: Opaque asked for TED sync ",
|
||||
__func__);
|
||||
}
|
||||
thread_add_timer(ted_state_g.main, path_ted_timer_handler_sync,
|
||||
&ted_state_g, ted_state_g.link_state_delay_interval,
|
||||
&ted_state_g.t_link_state_sync);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Timer cb for check link state sync
|
||||
*
|
||||
* @param thread Current thread
|
||||
*
|
||||
* @return status
|
||||
*/
|
||||
int path_ted_timer_handler_sync(struct thread *thread)
|
||||
{
|
||||
/* data unpacking */
|
||||
struct ted_state *data = THREAD_ARG(thread);
|
||||
|
||||
assert(data != NULL);
|
||||
/* Retry the sync */
|
||||
return path_ted_link_state_sync();
|
||||
}
|
||||
|
||||
/**
|
||||
* refresg segment list and create timer to keep up updated
|
||||
*
|
||||
* @param void
|
||||
*
|
||||
* @return status
|
||||
*/
|
||||
int path_ted_segment_list_refresh(void)
|
||||
{
|
||||
int status = 0;
|
||||
|
||||
path_ted_timer_refresh_cancel();
|
||||
thread_add_timer(ted_state_g.main, path_ted_timer_handler_refresh,
|
||||
&ted_state_g,
|
||||
ted_state_g.segment_list_refresh_interval,
|
||||
&ted_state_g.t_segment_list_refresh);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Timer cb for refreshing sid in segment lists
|
||||
*
|
||||
* @param void
|
||||
*
|
||||
* @return status
|
||||
*/
|
||||
int path_ted_timer_handler_refresh(struct thread *thread)
|
||||
{
|
||||
if (!path_ted_is_initialized())
|
||||
return MPLS_LABEL_NONE;
|
||||
|
||||
PATH_TED_DEBUG("%s: PATHD-TED: Refresh sid from current TED", __func__);
|
||||
/* data unpacking */
|
||||
struct ted_state *data = THREAD_ARG(thread);
|
||||
|
||||
assert(data != NULL);
|
||||
|
||||
srte_policy_update_ted_sid();
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancel sync timer
|
||||
*
|
||||
* @param void
|
||||
*
|
||||
* @return void status
|
||||
*/
|
||||
void path_ted_timer_sync_cancel(void)
|
||||
{
|
||||
if (ted_state_g.t_link_state_sync != NULL) {
|
||||
thread_cancel(&ted_state_g.t_link_state_sync);
|
||||
ted_state_g.t_link_state_sync = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancel refresh timer
|
||||
*
|
||||
* @param void
|
||||
*
|
||||
* @return void status
|
||||
*/
|
||||
void path_ted_timer_refresh_cancel(void)
|
||||
{
|
||||
if (ted_state_g.t_segment_list_refresh != NULL) {
|
||||
thread_cancel(&ted_state_g.t_segment_list_refresh);
|
||||
ted_state_g.t_segment_list_refresh = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check which igp is configured
|
||||
*
|
||||
* @param igp who want to check against config-
|
||||
*
|
||||
* @return status
|
||||
*/
|
||||
uint32_t path_ted_get_current_igp(uint32_t igp)
|
||||
{
|
||||
switch (igp) {
|
||||
case ISIS_L1:
|
||||
case ISIS_L2:
|
||||
if (ted_state_g.import != IMPORT_ISIS) {
|
||||
PATH_TED_ERROR(
|
||||
"%s: [rcv ted] Incorrect igp origin wait (%s) got (%s) ",
|
||||
__func__,
|
||||
PATH_TED_IGP_PRINT(ted_state_g.import),
|
||||
LS_IGP_PRINT(igp));
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
case OSPFv2:
|
||||
if (ted_state_g.import != IMPORT_OSPFv2) {
|
||||
PATH_TED_ERROR(
|
||||
"%s: [rcv ted] Incorrect igp origin wait (%s) got (%s) ",
|
||||
__func__,
|
||||
PATH_TED_IGP_PRINT(ted_state_g.import),
|
||||
LS_IGP_PRINT(igp));
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
case STATIC:
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
178
pathd/path_ted.h
Normal file
178
pathd/path_ted.h
Normal file
@ -0,0 +1,178 @@
|
||||
/*
|
||||
* Copyright (C) 2020 Volta Networks, Inc
|
||||
*
|
||||
* This program 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 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program 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 Lesser General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _PATH_TED_H
|
||||
#define _PATH_TED_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <zebra.h>
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#include <debug.h>
|
||||
#include "linklist.h"
|
||||
#include "log.h"
|
||||
#include "command.h"
|
||||
#include "stream.h"
|
||||
#include "prefix.h"
|
||||
#include "zclient.h"
|
||||
#include "link_state.h"
|
||||
|
||||
extern struct ted_state ted_state_g;
|
||||
#define TIMER_RETRY_DELAY 5 /* Timeout in seconds between ls sync request */
|
||||
#define TED_KEY 1
|
||||
#define TED_ASN 1
|
||||
#define TED_NAME "PATHD TED"
|
||||
|
||||
enum igp_import {
|
||||
IMPORT_UNKNOWN = 0,
|
||||
IMPORT_ISIS,
|
||||
IMPORT_OSPFv2,
|
||||
IMPORT_OSPFv3
|
||||
};
|
||||
struct ted_state {
|
||||
struct thread_master *main;
|
||||
/* Status of TED: enable or disable */
|
||||
bool enabled;
|
||||
/* From which igp is going to receive data */
|
||||
enum igp_import import;
|
||||
/* The TED itself as in link_state.h */
|
||||
struct ls_ted *ted;
|
||||
/* Timer for ted sync */
|
||||
struct thread *t_link_state_sync;
|
||||
/* Timer for refresh sid in segment list */
|
||||
struct thread *t_segment_list_refresh;
|
||||
/* delay interval in seconds */
|
||||
uint32_t link_state_delay_interval;
|
||||
/* delay interval refresh in seconds */
|
||||
uint32_t segment_list_refresh_interval;
|
||||
struct debug dbg;
|
||||
};
|
||||
/* Debug flags. */
|
||||
#define PATH_TED_DEBUG_BASIC 0x01
|
||||
#define PATH_TED_DEBUG(fmt, ...) \
|
||||
do { \
|
||||
if (DEBUG_FLAGS_CHECK(&ted_state_g.dbg, PATH_TED_DEBUG_BASIC)) \
|
||||
DEBUGD(&ted_state_g.dbg, "mpls-te: " fmt, ##__VA_ARGS__); \
|
||||
} while (0)
|
||||
|
||||
#define PATH_TED_ERROR(fmt, ...) \
|
||||
do { \
|
||||
if (DEBUG_FLAGS_CHECK(&ted_state_g.dbg, PATH_TED_DEBUG_BASIC)) \
|
||||
DEBUGE(&ted_state_g.dbg, "mpls-te: " fmt, ##__VA_ARGS__); \
|
||||
} while (0)
|
||||
#define PATH_TED_WARN(fmt, ...) \
|
||||
do { \
|
||||
if (DEBUG_FLAGS_CHECK(&ted_state_g.dbg, PATH_TED_DEBUG_BASIC)) \
|
||||
DEBUGW(&ted_state_g.dbg, "mpls-te: " fmt, ##__VA_ARGS__); \
|
||||
} while (0)
|
||||
#define PATH_TED_INFO(fmt, ...) \
|
||||
do { \
|
||||
if (DEBUG_FLAGS_CHECK(&ted_state_g.dbg, PATH_TED_DEBUG_BASIC)) \
|
||||
DEBUGI(&ted_state_g.dbg, "mpls-te: " fmt, ##__VA_ARGS__); \
|
||||
} while (0)
|
||||
|
||||
/* TED management functions */
|
||||
bool path_ted_is_initialized(void);
|
||||
void path_ted_init(struct thread_master *master);
|
||||
uint32_t path_ted_teardown(void);
|
||||
void path_ted_timer_sync_cancel(void);
|
||||
void path_ted_timer_refresh_cancel(void);
|
||||
int path_ted_segment_list_refresh(void);
|
||||
|
||||
/* TED configuration functions */
|
||||
uint32_t path_ted_config_write(struct vty *vty);
|
||||
|
||||
/* TED util functions */
|
||||
/* clang-format off */
|
||||
#define LS_MSG_EVENT_PRINT(event) event == LS_MSG_EVENT_ADD?"add"\
|
||||
: event == LS_MSG_EVENT_DELETE?"del"\
|
||||
: event == LS_MSG_EVENT_UPDATE?"upd"\
|
||||
: event == LS_MSG_EVENT_SYNC?"syn"\
|
||||
: event == LS_MSG_EVENT_SYNC?"und" : "none"
|
||||
#define LS_MSG_TYPE_PRINT(type) type == LS_MSG_TYPE_NODE?"node"\
|
||||
: type == LS_MSG_TYPE_ATTRIBUTES?"att"\
|
||||
: type == LS_MSG_TYPE_PREFIX?"pre" : "none"
|
||||
#define LS_IGP_PRINT(type) type == ISIS_L1?"ISIS_L1"\
|
||||
: type == ISIS_L2?"ISIS_L2"\
|
||||
: type == DIRECT?"DIRECT"\
|
||||
: type == STATIC?"STATIC"\
|
||||
: type == OSPFv2?"OSPFv2" : "none"
|
||||
#define PATH_TED_IGP_PRINT(type) type == IMPORT_OSPFv2?"OSPFv2"\
|
||||
: type == IMPORT_OSPFv3?"OSPFv3"\
|
||||
: type == IMPORT_ISIS?"ISIS" : "none"
|
||||
/* clang-format on */
|
||||
|
||||
|
||||
uint32_t path_ted_get_current_igp(uint32_t);
|
||||
/* TED Query functions */
|
||||
|
||||
/*
|
||||
* Type of queries from draft-ietf-spring-segment-routing-policy-07 for types
|
||||
* f,c,e
|
||||
*/
|
||||
|
||||
/**
|
||||
* Search for sid based in prefix and optional algo
|
||||
*
|
||||
* @param prefix Net prefix to resolv
|
||||
* @param algo Algorithm for link state
|
||||
*
|
||||
* @return sid of attribute
|
||||
*/
|
||||
uint32_t path_ted_query_type_c(struct prefix *prefix, uint8_t algo);
|
||||
|
||||
/**
|
||||
* Search for sid based in prefix and interface id
|
||||
*
|
||||
* @param prefix Net prefix to resolv
|
||||
* @param iface_id The interface id
|
||||
*
|
||||
* @return sid of attribute
|
||||
*/
|
||||
uint32_t path_ted_query_type_e(struct prefix *prefix, uint32_t iface_id);
|
||||
|
||||
/**
|
||||
* Search for sid based in local, remote pair
|
||||
*
|
||||
* @param local local ip of attribute
|
||||
* @param remote remote ip of attribute
|
||||
*
|
||||
* @return sid of attribute
|
||||
*/
|
||||
uint32_t path_ted_query_type_f(struct ipaddr *local, struct ipaddr *remote);
|
||||
|
||||
|
||||
/**
|
||||
* Handle the received opaque msg
|
||||
*
|
||||
* @param msg Holds the ted data
|
||||
*
|
||||
* @return sid of attribute
|
||||
*/
|
||||
uint32_t path_ted_rcvd_message(struct ls_message *msg);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _PATH_TED_H */
|
@ -32,9 +32,14 @@
|
||||
#include "typesafe.h"
|
||||
|
||||
#include "pathd/pathd.h"
|
||||
#include "pathd/path_ted.h"
|
||||
#include "pathd/path_zebra.h"
|
||||
#include "lib/command.h"
|
||||
#include "lib/link_state.h"
|
||||
|
||||
static struct zclient *zclient;
|
||||
static int path_zebra_opaque_msg_handler(ZAPI_CALLBACK_ARGS);
|
||||
|
||||
struct zclient *zclient;
|
||||
static struct zclient *zclient_sync;
|
||||
|
||||
/* Global Variables */
|
||||
@ -267,6 +272,54 @@ static void path_zebra_label_manager_connect(void)
|
||||
}
|
||||
}
|
||||
|
||||
static int path_zebra_opaque_msg_handler(ZAPI_CALLBACK_ARGS)
|
||||
{
|
||||
int ret = 0;
|
||||
struct stream *s;
|
||||
struct zapi_opaque_msg info;
|
||||
|
||||
s = zclient->ibuf;
|
||||
|
||||
if (zclient_opaque_decode(s, &info) != 0)
|
||||
return -1;
|
||||
|
||||
switch (info.type) {
|
||||
case LINK_STATE_UPDATE:
|
||||
case LINK_STATE_SYNC:
|
||||
/* Start receiving ls data so cancel request sync timer */
|
||||
path_ted_timer_sync_cancel();
|
||||
|
||||
struct ls_message *msg = ls_parse_msg(s);
|
||||
|
||||
if (msg) {
|
||||
zlog_debug("%s: [rcv ted] ls (%s) msg (%s)-(%s) !",
|
||||
__func__,
|
||||
info.type == LINK_STATE_UPDATE
|
||||
? "LINK_STATE_UPDATE"
|
||||
: "LINK_STATE_SYNC",
|
||||
LS_MSG_TYPE_PRINT(msg->type),
|
||||
LS_MSG_EVENT_PRINT(msg->event));
|
||||
} else {
|
||||
zlog_err(
|
||||
"%s: [rcv ted] Could not parse LinkState stream message.",
|
||||
__func__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = path_ted_rcvd_message(msg);
|
||||
ls_delete_msg(msg);
|
||||
/* Update local configuration after process update. */
|
||||
path_ted_segment_list_refresh();
|
||||
break;
|
||||
default:
|
||||
zlog_debug("%s: [rcv ted] unknown opaque event (%d) !",
|
||||
__func__, info.type);
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes Zebra asynchronous connection.
|
||||
*
|
||||
@ -283,6 +336,7 @@ void path_zebra_init(struct thread_master *master)
|
||||
zclient->zebra_connected = path_zebra_connected;
|
||||
zclient->sr_policy_notify_status = path_zebra_sr_policy_notify_status;
|
||||
zclient->router_id_update = path_zebra_router_id_update;
|
||||
zclient->opaque_msg_handler = path_zebra_opaque_msg_handler;
|
||||
|
||||
/* Initialize special zclient for synchronous message exchanges. */
|
||||
zclient_sync = zclient_new(master, &options);
|
||||
|
278
pathd/pathd.c
278
pathd/pathd.c
@ -26,6 +26,7 @@
|
||||
#include "pathd/pathd.h"
|
||||
#include "pathd/path_zebra.h"
|
||||
#include "pathd/path_debug.h"
|
||||
#include "pathd/path_ted.h"
|
||||
|
||||
#define HOOK_DELAY 3
|
||||
|
||||
@ -188,14 +189,20 @@ void srte_segment_entry_del(struct srte_segment_entry *segment)
|
||||
* @param type The remote address of the adjacency
|
||||
* @param type The remote interface index of the unumbered adjacency
|
||||
*/
|
||||
void srte_segment_entry_set_nai(struct srte_segment_entry *segment,
|
||||
enum srte_segment_nai_type type,
|
||||
struct ipaddr *local_ip, uint32_t local_iface,
|
||||
struct ipaddr *remote_ip, uint32_t remote_iface)
|
||||
int srte_segment_entry_set_nai(struct srte_segment_entry *segment,
|
||||
enum srte_segment_nai_type type,
|
||||
struct ipaddr *local_ip, uint32_t local_iface,
|
||||
struct ipaddr *remote_ip, uint32_t remote_iface,
|
||||
uint8_t algo, uint8_t pref_len)
|
||||
{
|
||||
int32_t status = 0;
|
||||
struct prefix pre = {0};
|
||||
segment->nai_type = type;
|
||||
memcpy(&segment->nai_local_addr, local_ip, sizeof(struct ipaddr));
|
||||
|
||||
if (!segment || !local_ip || !remote_ip)
|
||||
return 1;
|
||||
|
||||
switch (type) {
|
||||
case SRTE_SEGMENT_NAI_TYPE_IPV4_NODE:
|
||||
case SRTE_SEGMENT_NAI_TYPE_IPV6_NODE:
|
||||
@ -204,6 +211,7 @@ void srte_segment_entry_set_nai(struct srte_segment_entry *segment,
|
||||
case SRTE_SEGMENT_NAI_TYPE_IPV6_ADJACENCY:
|
||||
memcpy(&segment->nai_remote_addr, remote_ip,
|
||||
sizeof(struct ipaddr));
|
||||
status = srte_ted_do_query_type_f(segment, local_ip, remote_ip);
|
||||
break;
|
||||
case SRTE_SEGMENT_NAI_TYPE_IPV4_UNNUMBERED_ADJACENCY:
|
||||
memcpy(&segment->nai_remote_addr, remote_ip,
|
||||
@ -211,12 +219,68 @@ void srte_segment_entry_set_nai(struct srte_segment_entry *segment,
|
||||
segment->nai_local_iface = local_iface;
|
||||
segment->nai_remote_iface = remote_iface;
|
||||
break;
|
||||
case SRTE_SEGMENT_NAI_TYPE_IPV6_ALGORITHM:
|
||||
pre.family = AF_INET6;
|
||||
pre.prefixlen = pref_len;
|
||||
pre.u.prefix6 = local_ip->ip._v6_addr;
|
||||
segment->nai_local_prefix_len = pref_len;
|
||||
segment->nai_algorithm = algo;
|
||||
status = srte_ted_do_query_type_c(segment, &pre, algo);
|
||||
break;
|
||||
case SRTE_SEGMENT_NAI_TYPE_IPV4_ALGORITHM:
|
||||
pre.family = AF_INET;
|
||||
pre.prefixlen = pref_len;
|
||||
pre.u.prefix4 = local_ip->ip._v4_addr;
|
||||
segment->nai_local_prefix_len = pref_len;
|
||||
segment->nai_algorithm = algo;
|
||||
status = srte_ted_do_query_type_c(segment, &pre, algo);
|
||||
break;
|
||||
case SRTE_SEGMENT_NAI_TYPE_IPV6_LOCAL_IFACE:
|
||||
pre.family = AF_INET6;
|
||||
pre.prefixlen = pref_len;
|
||||
pre.u.prefix6 = local_ip->ip._v6_addr;
|
||||
segment->nai_local_prefix_len = pref_len;
|
||||
segment->nai_local_iface = local_iface;
|
||||
status = srte_ted_do_query_type_e(segment, &pre, local_iface);
|
||||
break;
|
||||
case SRTE_SEGMENT_NAI_TYPE_IPV4_LOCAL_IFACE:
|
||||
pre.family = AF_INET;
|
||||
pre.prefixlen = pref_len;
|
||||
pre.u.prefix4 = local_ip->ip._v4_addr;
|
||||
segment->nai_local_prefix_len = pref_len;
|
||||
segment->nai_local_iface = local_iface;
|
||||
status = srte_ted_do_query_type_e(segment, &pre, local_iface);
|
||||
break;
|
||||
default:
|
||||
segment->nai_local_addr.ipa_type = IPADDR_NONE;
|
||||
segment->nai_local_iface = 0;
|
||||
segment->nai_remote_addr.ipa_type = IPADDR_NONE;
|
||||
segment->nai_remote_iface = 0;
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark segment as modified depending in protocol and sid conditions
|
||||
*
|
||||
* @param protocol_origin Origin of the segment list
|
||||
* @param s_list Ptr to segment list with flags,sid to modidy
|
||||
* @param s_entry Ptr to segment entry with sid to modidy
|
||||
* @param ted_sid The sid from ted query
|
||||
* @return void
|
||||
*/
|
||||
void srte_segment_set_local_modification(struct srte_segment_list *s_list,
|
||||
struct srte_segment_entry *s_entry,
|
||||
uint32_t ted_sid)
|
||||
{
|
||||
if (!s_list || !s_entry)
|
||||
return;
|
||||
|
||||
if (s_list->protocol_origin == SRTE_ORIGIN_LOCAL
|
||||
&& s_entry->sid_value != ted_sid) {
|
||||
s_entry->sid_value = ted_sid;
|
||||
SET_FLAG(s_list->flags, F_SEGMENT_LIST_MODIFIED);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -287,6 +351,105 @@ struct srte_policy *srte_policy_find(uint32_t color, struct ipaddr *endpoint)
|
||||
return RB_FIND(srte_policy_head, &srte_policies, &search);
|
||||
}
|
||||
|
||||
/*
|
||||
* After new data from igp,local and pce the segment list :
|
||||
* Mark as invalid for origin pce if cannot be validated
|
||||
* Updated for origin local
|
||||
*/
|
||||
int srte_policy_update_ted_sid(void)
|
||||
{
|
||||
|
||||
int number_of_sid_clashed = 0;
|
||||
struct srte_segment_list *s_list;
|
||||
struct srte_segment_entry *s_entry;
|
||||
|
||||
if (!path_ted_is_initialized())
|
||||
return 0;
|
||||
if (RB_EMPTY(srte_segment_list_head, &srte_segment_lists))
|
||||
return 0;
|
||||
|
||||
RB_FOREACH (s_list, srte_segment_list_head, &srte_segment_lists) {
|
||||
if (CHECK_FLAG(s_list->flags, F_SEGMENT_LIST_DELETED))
|
||||
continue;
|
||||
RB_FOREACH (s_entry, srte_segment_entry_head,
|
||||
&s_list->segments) {
|
||||
PATH_TED_DEBUG(
|
||||
"%s:PATHD-TED: SL: Name: %s index:(%d) sid:(%d) prefix_len:(%d) local iface:(%d) algorithm:(%d)",
|
||||
__func__, s_list->name, s_entry->index,
|
||||
s_entry->sid_value,
|
||||
s_entry->nai_local_prefix_len,
|
||||
s_entry->nai_local_iface,
|
||||
s_entry->nai_algorithm);
|
||||
struct prefix prefix_cli = {0};
|
||||
|
||||
switch (s_entry->nai_type) {
|
||||
case SRTE_SEGMENT_NAI_TYPE_IPV6_ADJACENCY:
|
||||
case SRTE_SEGMENT_NAI_TYPE_IPV4_ADJACENCY:
|
||||
number_of_sid_clashed +=
|
||||
srte_ted_do_query_type_f(
|
||||
s_entry,
|
||||
&s_entry->nai_local_addr,
|
||||
&s_entry->nai_remote_addr);
|
||||
break;
|
||||
case SRTE_SEGMENT_NAI_TYPE_IPV6_LOCAL_IFACE:
|
||||
prefix_cli.family = AF_INET6;
|
||||
prefix_cli.prefixlen =
|
||||
s_entry->nai_local_prefix_len;
|
||||
prefix_cli.u.prefix6 =
|
||||
s_entry->nai_local_addr.ip._v6_addr;
|
||||
number_of_sid_clashed +=
|
||||
srte_ted_do_query_type_e(
|
||||
s_entry, &prefix_cli,
|
||||
s_entry->nai_local_iface);
|
||||
break;
|
||||
case SRTE_SEGMENT_NAI_TYPE_IPV4_LOCAL_IFACE:
|
||||
prefix_cli.family = AF_INET;
|
||||
prefix_cli.prefixlen =
|
||||
s_entry->nai_local_prefix_len;
|
||||
prefix_cli.u.prefix4 =
|
||||
s_entry->nai_local_addr.ip._v4_addr;
|
||||
number_of_sid_clashed +=
|
||||
srte_ted_do_query_type_e(
|
||||
s_entry, &prefix_cli,
|
||||
s_entry->nai_local_iface);
|
||||
break;
|
||||
case SRTE_SEGMENT_NAI_TYPE_IPV6_ALGORITHM:
|
||||
prefix_cli.family = AF_INET6;
|
||||
prefix_cli.prefixlen =
|
||||
s_entry->nai_local_prefix_len;
|
||||
prefix_cli.u.prefix6 =
|
||||
s_entry->nai_local_addr.ip._v6_addr;
|
||||
number_of_sid_clashed +=
|
||||
srte_ted_do_query_type_c(
|
||||
s_entry, &prefix_cli,
|
||||
s_entry->nai_algorithm);
|
||||
break;
|
||||
case SRTE_SEGMENT_NAI_TYPE_IPV4_ALGORITHM:
|
||||
prefix_cli.family = AF_INET;
|
||||
prefix_cli.prefixlen =
|
||||
s_entry->nai_local_prefix_len;
|
||||
prefix_cli.u.prefix4 =
|
||||
s_entry->nai_local_addr.ip._v4_addr;
|
||||
number_of_sid_clashed +=
|
||||
srte_ted_do_query_type_c(
|
||||
s_entry, &prefix_cli,
|
||||
s_entry->nai_algorithm);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (number_of_sid_clashed) {
|
||||
SET_FLAG(s_list->flags, F_SEGMENT_LIST_SID_CONFLICT);
|
||||
number_of_sid_clashed = 0;
|
||||
} else
|
||||
UNSET_FLAG(s_list->flags, F_SEGMENT_LIST_SID_CONFLICT);
|
||||
}
|
||||
srte_apply_changes();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update a policy binding SID.
|
||||
*
|
||||
@ -322,13 +485,23 @@ srte_policy_best_candidate(const struct srte_policy *policy)
|
||||
&policy->candidate_paths) {
|
||||
/* search for highest preference with existing segment list */
|
||||
if (!CHECK_FLAG(candidate->flags, F_CANDIDATE_DELETED)
|
||||
&& candidate->lsp->segment_list)
|
||||
&& candidate->lsp->segment_list
|
||||
&& (!CHECK_FLAG(candidate->lsp->segment_list->flags,
|
||||
F_SEGMENT_LIST_SID_CONFLICT)))
|
||||
return candidate;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void srte_clean_zebra(void)
|
||||
{
|
||||
struct srte_policy *policy, *safe_pol;
|
||||
|
||||
RB_FOREACH_SAFE (policy, srte_policy_head, &srte_policies, safe_pol)
|
||||
srte_policy_del(policy);
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply changes defined by setting the policies, candidate paths
|
||||
* and segment lists modification flags NEW, MODIFIED and DELETED.
|
||||
@ -526,6 +699,7 @@ void srte_candidate_set_bandwidth(struct srte_candidate *candidate,
|
||||
{
|
||||
struct srte_policy *policy = candidate->policy;
|
||||
char endpoint[46];
|
||||
|
||||
ipaddr2str(&policy->endpoint, endpoint, sizeof(endpoint));
|
||||
zlog_debug(
|
||||
"SR-TE(%s, %u): candidate %s %sconfig bandwidth set to %f B/s",
|
||||
@ -1024,6 +1198,12 @@ const char *srte_origin2str(enum srte_protocol_origin origin)
|
||||
}
|
||||
}
|
||||
|
||||
void pathd_shutdown(void)
|
||||
{
|
||||
path_ted_teardown();
|
||||
srte_clean_zebra();
|
||||
}
|
||||
|
||||
void trigger_pathd_candidate_created(struct srte_candidate *candidate)
|
||||
{
|
||||
/* The hook is called asynchronously to let the PCEP module
|
||||
@ -1124,3 +1304,91 @@ const char *srte_candidate_metric_name(enum srte_candidate_metric_type type)
|
||||
return "UNKNOWN";
|
||||
}
|
||||
}
|
||||
|
||||
int32_t srte_ted_do_query_type_c(struct srte_segment_entry *entry,
|
||||
struct prefix *prefix_cli, uint32_t algo)
|
||||
{
|
||||
int32_t status = 0;
|
||||
uint32_t ted_sid = MPLS_LABEL_NONE;
|
||||
|
||||
if (!entry || !prefix_cli)
|
||||
return 0;
|
||||
|
||||
if (!path_ted_is_initialized())
|
||||
return 0;
|
||||
|
||||
ted_sid = path_ted_query_type_c(prefix_cli, algo);
|
||||
if (ted_sid == MPLS_LABEL_NONE) {
|
||||
zlog_warn(" %s: PATHD-TED: SL: ERROR query C : ted-sid (%d)",
|
||||
__func__, ted_sid);
|
||||
} else {
|
||||
zlog_debug("%s: PATHD-TED: SL: Sucess query C : ted-sid (%d)",
|
||||
__func__, ted_sid);
|
||||
}
|
||||
if (CHECK_SID(entry->segment_list->protocol_origin, ted_sid,
|
||||
entry->sid_value)) {
|
||||
status = PATH_SID_ERROR;
|
||||
} else
|
||||
srte_segment_set_local_modification(entry->segment_list, entry,
|
||||
ted_sid);
|
||||
return status;
|
||||
}
|
||||
|
||||
int32_t srte_ted_do_query_type_e(struct srte_segment_entry *entry,
|
||||
struct prefix *prefix_cli,
|
||||
uint32_t local_iface)
|
||||
{
|
||||
int32_t status = 0;
|
||||
uint32_t ted_sid = MPLS_LABEL_NONE;
|
||||
|
||||
if (!entry || !prefix_cli)
|
||||
return 0;
|
||||
|
||||
if (!path_ted_is_initialized())
|
||||
return 0;
|
||||
|
||||
ted_sid = path_ted_query_type_e(prefix_cli, local_iface);
|
||||
if (ted_sid == MPLS_LABEL_NONE) {
|
||||
zlog_warn(" %s: PATHD-TED: SL: ERROR query E : ted-sid (%d)",
|
||||
__func__, ted_sid);
|
||||
} else {
|
||||
zlog_debug("%s: PATHD-TED: SL: Sucess query E : ted-sid (%d)",
|
||||
__func__, ted_sid);
|
||||
}
|
||||
if (CHECK_SID(entry->segment_list->protocol_origin, ted_sid,
|
||||
entry->sid_value)) {
|
||||
status = PATH_SID_ERROR;
|
||||
} else
|
||||
srte_segment_set_local_modification(entry->segment_list, entry,
|
||||
ted_sid);
|
||||
return status;
|
||||
}
|
||||
|
||||
int32_t srte_ted_do_query_type_f(struct srte_segment_entry *entry,
|
||||
struct ipaddr *local, struct ipaddr *remote)
|
||||
{
|
||||
int32_t status = 0;
|
||||
uint32_t ted_sid = MPLS_LABEL_NONE;
|
||||
|
||||
if (!entry || !local || !remote)
|
||||
return 0;
|
||||
|
||||
if (!path_ted_is_initialized())
|
||||
return status;
|
||||
|
||||
ted_sid = path_ted_query_type_f(local, remote);
|
||||
if (ted_sid == MPLS_LABEL_NONE) {
|
||||
zlog_warn("%s:SL: ERROR query F : ted-sid (%d)", __func__,
|
||||
ted_sid);
|
||||
} else {
|
||||
zlog_debug("%s:SL: Sucess query F : ted-sid (%d)", __func__,
|
||||
ted_sid);
|
||||
}
|
||||
if (CHECK_SID(entry->segment_list->protocol_origin, ted_sid,
|
||||
entry->sid_value)) {
|
||||
status = PATH_SID_ERROR;
|
||||
} else
|
||||
srte_segment_set_local_modification(entry->segment_list, entry,
|
||||
ted_sid);
|
||||
return status;
|
||||
}
|
||||
|
@ -24,6 +24,13 @@
|
||||
#include "lib/ipaddr.h"
|
||||
#include "lib/srte.h"
|
||||
#include "lib/hook.h"
|
||||
#include "lib/prefix.h"
|
||||
|
||||
#define PATH_SID_ERROR 1
|
||||
#define PATH_SID_NO_ERROR 0
|
||||
#define CHECK_SID(or, ts, es) \
|
||||
((or == SRTE_ORIGIN_PCEP && (ts == MPLS_LABEL_NONE || es != ts)) \
|
||||
|| (or == SRTE_ORIGIN_LOCAL && ts == MPLS_LABEL_NONE))
|
||||
|
||||
DECLARE_MGROUP(PATHD);
|
||||
|
||||
@ -100,7 +107,12 @@ enum srte_segment_nai_type {
|
||||
SRTE_SEGMENT_NAI_TYPE_IPV6_NODE = 2,
|
||||
SRTE_SEGMENT_NAI_TYPE_IPV4_ADJACENCY = 3,
|
||||
SRTE_SEGMENT_NAI_TYPE_IPV6_ADJACENCY = 4,
|
||||
SRTE_SEGMENT_NAI_TYPE_IPV4_UNNUMBERED_ADJACENCY = 5
|
||||
SRTE_SEGMENT_NAI_TYPE_IPV4_UNNUMBERED_ADJACENCY = 5,
|
||||
SRTE_SEGMENT_NAI_TYPE_IPV6_ADJACENCY_LINK_LOCAL_ADDRESSES = 6,
|
||||
SRTE_SEGMENT_NAI_TYPE_IPV4_LOCAL_IFACE = 7,
|
||||
SRTE_SEGMENT_NAI_TYPE_IPV6_LOCAL_IFACE = 8,
|
||||
SRTE_SEGMENT_NAI_TYPE_IPV4_ALGORITHM = 9,
|
||||
SRTE_SEGMENT_NAI_TYPE_IPV6_ALGORITHM = 10
|
||||
};
|
||||
|
||||
enum objfun_type {
|
||||
@ -175,6 +187,9 @@ struct srte_segment_entry {
|
||||
/* NAI remote interface when nai type is not IPv4 unnumbered adjacency
|
||||
*/
|
||||
uint32_t nai_remote_iface;
|
||||
/* Support draft-ietf-spring-segment-routing-policy sl types queries*/
|
||||
uint8_t nai_local_prefix_len;
|
||||
uint8_t nai_algorithm;
|
||||
};
|
||||
RB_HEAD(srte_segment_entry_head, srte_segment_entry);
|
||||
RB_PROTOTYPE(srte_segment_entry_head, srte_segment_entry, entry,
|
||||
@ -200,6 +215,7 @@ struct srte_segment_list {
|
||||
#define F_SEGMENT_LIST_NEW 0x0002
|
||||
#define F_SEGMENT_LIST_MODIFIED 0x0004
|
||||
#define F_SEGMENT_LIST_DELETED 0x0008
|
||||
#define F_SEGMENT_LIST_SID_CONFLICT 0x0010
|
||||
};
|
||||
RB_HEAD(srte_segment_list_head, srte_segment_list);
|
||||
RB_PROTOTYPE(srte_segment_list_head, srte_segment_list, entry,
|
||||
@ -361,17 +377,22 @@ struct srte_segment_list *srte_segment_list_find(const char *name);
|
||||
struct srte_segment_entry *
|
||||
srte_segment_entry_add(struct srte_segment_list *segment_list, uint32_t index);
|
||||
void srte_segment_entry_del(struct srte_segment_entry *segment);
|
||||
void srte_segment_entry_set_nai(struct srte_segment_entry *segment,
|
||||
enum srte_segment_nai_type type,
|
||||
struct ipaddr *local_ip, uint32_t local_iface,
|
||||
struct ipaddr *remote_ip,
|
||||
uint32_t remote_iface);
|
||||
int srte_segment_entry_set_nai(struct srte_segment_entry *segment,
|
||||
enum srte_segment_nai_type type,
|
||||
struct ipaddr *local_ip, uint32_t local_iface,
|
||||
struct ipaddr *remote_ip, uint32_t remote_iface,
|
||||
uint8_t algo, uint8_t pref_len);
|
||||
void srte_segment_set_local_modification(struct srte_segment_list *s_list,
|
||||
struct srte_segment_entry *s_entry,
|
||||
uint32_t ted_sid);
|
||||
struct srte_policy *srte_policy_add(uint32_t color, struct ipaddr *endpoint);
|
||||
void srte_policy_del(struct srte_policy *policy);
|
||||
struct srte_policy *srte_policy_find(uint32_t color, struct ipaddr *endpoint);
|
||||
int srte_policy_update_ted_sid(void);
|
||||
void srte_policy_update_binding_sid(struct srte_policy *policy,
|
||||
uint32_t binding_sid);
|
||||
void srte_apply_changes(void);
|
||||
void srte_clean_zebra(void);
|
||||
void srte_policy_apply_changes(struct srte_policy *policy);
|
||||
struct srte_candidate *srte_candidate_add(struct srte_policy *policy,
|
||||
uint32_t preference);
|
||||
@ -408,8 +429,45 @@ srte_segment_entry_find(struct srte_segment_list *segment_list, uint32_t index);
|
||||
void srte_candidate_status_update(struct srte_candidate *candidate, int status);
|
||||
void srte_candidate_unset_segment_list(const char *originator, bool force);
|
||||
const char *srte_origin2str(enum srte_protocol_origin origin);
|
||||
void pathd_shutdown(void);
|
||||
|
||||
/* path_cli.c */
|
||||
void path_cli_init(void);
|
||||
|
||||
|
||||
/**
|
||||
* Search for sid based in prefix and algorithm
|
||||
*
|
||||
* @param Prefix The prefix to use
|
||||
* @param algo Algorithm we want to query for
|
||||
* @param ted_sid Sid to query
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
int32_t srte_ted_do_query_type_c(struct srte_segment_entry *entry,
|
||||
struct prefix *prefix_cli, uint32_t algo);
|
||||
|
||||
/**
|
||||
* Search for sid based in prefix and interface id
|
||||
*
|
||||
* @param Prefix The prefix to use
|
||||
* @param local_iface The id of interface
|
||||
* @param ted_sid Sid to query
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
int32_t srte_ted_do_query_type_e(struct srte_segment_entry *entry,
|
||||
struct prefix *prefix_cli,
|
||||
uint32_t local_iface);
|
||||
/**
|
||||
* Search for sid based in local and remote ip
|
||||
*
|
||||
* @param entry entry to update
|
||||
* @param local Local addr for query
|
||||
* @param remote Local addr for query
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
int32_t srte_ted_do_query_type_f(struct srte_segment_entry *entry,
|
||||
struct ipaddr *local, struct ipaddr *remote);
|
||||
#endif /* _FRR_PATHD_H_ */
|
||||
|
@ -5,7 +5,10 @@
|
||||
if PATHD
|
||||
noinst_LIBRARIES += pathd/libpath.a
|
||||
sbin_PROGRAMS += pathd/pathd
|
||||
vtysh_scan += pathd/path_cli.c
|
||||
vtysh_scan += \
|
||||
pathd/path_cli.c \
|
||||
pathd/path_ted.c \
|
||||
#end
|
||||
vtysh_daemons += pathd
|
||||
# TODO add man page
|
||||
#man8 += $(MANBUILD)/pathd.8
|
||||
@ -24,6 +27,7 @@ pathd_libpath_a_SOURCES = \
|
||||
pathd/path_nb.c \
|
||||
pathd/path_nb_config.c \
|
||||
pathd/path_nb_state.c \
|
||||
pathd/path_ted.c \
|
||||
pathd/path_zebra.c \
|
||||
pathd/pathd.c \
|
||||
# end
|
||||
@ -31,6 +35,7 @@ pathd_libpath_a_SOURCES = \
|
||||
clippy_scan += \
|
||||
pathd/path_cli.c \
|
||||
pathd/path_pcep_cli.c \
|
||||
pathd/path_ted.c \
|
||||
# end
|
||||
|
||||
noinst_HEADERS += \
|
||||
@ -44,6 +49,7 @@ noinst_HEADERS += \
|
||||
pathd/path_pcep_lib.h \
|
||||
pathd/path_pcep_config.h \
|
||||
pathd/path_pcep_pcc.h \
|
||||
pathd/path_ted.h \
|
||||
pathd/path_zebra.h \
|
||||
pathd/pathd.h \
|
||||
# end
|
||||
|
23
tests/topotests/ospf-sr-te-topo1/dst/zebra.conf
Normal file
23
tests/topotests/ospf-sr-te-topo1/dst/zebra.conf
Normal file
@ -0,0 +1,23 @@
|
||||
log file zebra.log
|
||||
!
|
||||
hostname dst
|
||||
!
|
||||
debug zebra kernel
|
||||
debug zebra packet
|
||||
debug zebra mpls
|
||||
!
|
||||
interface lo
|
||||
ip address 9.9.9.2/32
|
||||
ipv6 address 2001:db8:1066::2/128
|
||||
!
|
||||
interface eth-rt6
|
||||
ip address 10.0.11.2/24
|
||||
link-params
|
||||
enable
|
||||
exit-link-params
|
||||
!
|
||||
!
|
||||
ip forwarding
|
||||
!
|
||||
line vty
|
||||
!
|
16
tests/topotests/ospf-sr-te-topo1/rt1/bgpd.conf
Normal file
16
tests/topotests/ospf-sr-te-topo1/rt1/bgpd.conf
Normal file
@ -0,0 +1,16 @@
|
||||
log file bgpd.log
|
||||
!
|
||||
router bgp 1
|
||||
bgp router-id 1.1.1.1
|
||||
neighbor 6.6.6.6 remote-as 1
|
||||
neighbor 6.6.6.6 update-source lo
|
||||
!
|
||||
address-family ipv4 unicast
|
||||
redistribute static
|
||||
neighbor 6.6.6.6 next-hop-self
|
||||
neighbor 6.6.6.6 route-map SET_SR_POLICY in
|
||||
exit-address-family
|
||||
!
|
||||
route-map SET_SR_POLICY permit 10
|
||||
set sr-te color 1
|
||||
!
|
36
tests/topotests/ospf-sr-te-topo1/rt1/ospfd.conf
Normal file
36
tests/topotests/ospf-sr-te-topo1/rt1/ospfd.conf
Normal file
@ -0,0 +1,36 @@
|
||||
password 1
|
||||
hostname rt1
|
||||
log file ospfd.log
|
||||
!
|
||||
debug ospf sr
|
||||
debug ospf te
|
||||
debug ospf event
|
||||
debug ospf lsa
|
||||
debug ospf zebra
|
||||
!
|
||||
interface lo
|
||||
ip ospf area 0.0.0.0
|
||||
!
|
||||
interface eth-sw1
|
||||
ip ospf network point-to-point
|
||||
ip ospf hello-interval 2
|
||||
ip ospf dead-interval 10
|
||||
ip ospf area 0.0.0.0
|
||||
!
|
||||
router ospf
|
||||
ospf router-id 1.1.1.1
|
||||
network 1.1.1.1/32 area 0.0.0.0
|
||||
network 10.0.0.0/16 area 0.0.0.0
|
||||
capability opaque
|
||||
!ospf opaque-lsa
|
||||
mpls-te on
|
||||
mpls-te export
|
||||
mpls-te router-address 1.1.1.1
|
||||
router-info area 0.0.0.0
|
||||
passive-interface lo
|
||||
segment-routing on
|
||||
segment-routing global-block 16000 23999
|
||||
!segment-routing local-block 15000 15999
|
||||
segment-routing node-msd 8
|
||||
segment-routing prefix 1.1.1.1/32 index 10
|
||||
!
|
27
tests/topotests/ospf-sr-te-topo1/rt1/pathd.conf
Normal file
27
tests/topotests/ospf-sr-te-topo1/rt1/pathd.conf
Normal file
@ -0,0 +1,27 @@
|
||||
log file pathd.log
|
||||
!
|
||||
hostname rt1
|
||||
!
|
||||
segment-routing
|
||||
traffic-eng
|
||||
mpls-te on
|
||||
mpls-te import ospfv2
|
||||
segment-list default
|
||||
index 10 nai adjacency 10.0.1.1 10.0.1.2
|
||||
index 20 nai adjacency 10.0.2.2 10.0.2.4
|
||||
index 30 nai adjacency 10.0.7.4 10.0.7.6
|
||||
|
||||
|
||||
!
|
||||
segment-list test
|
||||
index 10 nai adjacency 10.0.1.1 10.0.1.2
|
||||
index 20 nai adjacency 10.0.2.2 10.0.2.4
|
||||
index 30 nai adjacency 10.0.6.4 10.0.6.5
|
||||
index 40 nai adjacency 10.0.8.5 10.0.8.6
|
||||
!
|
||||
policy color 1 endpoint 6.6.6.6
|
||||
name default
|
||||
binding-sid 1111
|
||||
!
|
||||
!
|
||||
!
|
@ -0,0 +1,13 @@
|
||||
{
|
||||
"frr-pathd:pathd": {
|
||||
"srte": {
|
||||
"policy": [
|
||||
{
|
||||
"color": 1,
|
||||
"endpoint": "6.6.6.6",
|
||||
"is-operational": false
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
{
|
||||
"frr-pathd:pathd": {
|
||||
"srte": {
|
||||
"policy": [
|
||||
{
|
||||
"color": 1,
|
||||
"endpoint": "6.6.6.6",
|
||||
"is-operational": true,
|
||||
"candidate-path": [
|
||||
{
|
||||
"preference": 100,
|
||||
"discriminator": "*",
|
||||
"is-best-candidate-path": true
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
{
|
||||
"frr-pathd:pathd": {
|
||||
"srte": {
|
||||
"policy": [
|
||||
{
|
||||
"color": 1,
|
||||
"endpoint": "6.6.6.6",
|
||||
"is-operational": true,
|
||||
"candidate-path": [
|
||||
{
|
||||
"preference": 100,
|
||||
"discriminator": "*",
|
||||
"is-best-candidate-path": true
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
{
|
||||
"frr-pathd:pathd": {
|
||||
"srte": {
|
||||
"policy": [
|
||||
{
|
||||
"color": 1,
|
||||
"endpoint": "6.6.6.6",
|
||||
"is-operational": true,
|
||||
"candidate-path": [
|
||||
{
|
||||
"preference": 100,
|
||||
"discriminator": "*",
|
||||
"is-best-candidate-path": false
|
||||
},
|
||||
{
|
||||
"preference": 200,
|
||||
"discriminator": "*",
|
||||
"is-best-candidate-path": true
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
21
tests/topotests/ospf-sr-te-topo1/rt1/zebra.conf
Normal file
21
tests/topotests/ospf-sr-te-topo1/rt1/zebra.conf
Normal file
@ -0,0 +1,21 @@
|
||||
log file zebra.log
|
||||
!
|
||||
hostname rt1
|
||||
!
|
||||
debug zebra kernel
|
||||
debug zebra packet
|
||||
debug zebra mpls
|
||||
!
|
||||
interface lo
|
||||
ip address 1.1.1.1/32
|
||||
!
|
||||
interface eth-sw1
|
||||
ip address 10.0.1.1/24
|
||||
link-params
|
||||
enable
|
||||
exit-link-params
|
||||
!
|
||||
ip forwarding
|
||||
!
|
||||
line vty
|
||||
!
|
47
tests/topotests/ospf-sr-te-topo1/rt2/ospfd.conf
Normal file
47
tests/topotests/ospf-sr-te-topo1/rt2/ospfd.conf
Normal file
@ -0,0 +1,47 @@
|
||||
hostname rt2
|
||||
log file ospfd.log
|
||||
!
|
||||
debug ospf sr
|
||||
debug ospf te
|
||||
debug ospf event
|
||||
debug ospf lsa
|
||||
debug ospf zebra
|
||||
!
|
||||
interface lo
|
||||
ip ospf area 0.0.0.0
|
||||
!
|
||||
interface eth-sw1
|
||||
ip ospf network point-to-point
|
||||
ip ospf hello-interval 2
|
||||
ip ospf dead-interval 10
|
||||
ip ospf area 0.0.0.0
|
||||
!
|
||||
interface eth-rt4-1
|
||||
ip ospf network point-to-point
|
||||
ip ospf hello-interval 2
|
||||
ip ospf dead-interval 10
|
||||
ip ospf area 0.0.0.0
|
||||
!
|
||||
interface eth-rt4-2
|
||||
ip ospf network point-to-point
|
||||
ip ospf hello-interval 2
|
||||
ip ospf dead-interval 10
|
||||
ip ospf area 0.0.0.0
|
||||
!
|
||||
router ospf
|
||||
ospf router-id 2.2.2.2
|
||||
network 2.2.2.2/32 area 0.0.0.0
|
||||
network 10.0.0.0/16 area 0.0.0.0
|
||||
capability opaque
|
||||
!ospf opaque-lsa
|
||||
mpls-te on
|
||||
!mpls-te export
|
||||
mpls-te router-address 2.2.2.2
|
||||
router-info area 0.0.0.0
|
||||
passive-interface lo
|
||||
segment-routing on
|
||||
segment-routing global-block 16000 23999
|
||||
!segment-routing local-block 15000 15999
|
||||
segment-routing node-msd 8
|
||||
segment-routing prefix 2.2.2.2/32 index 20
|
||||
!
|
35
tests/topotests/ospf-sr-te-topo1/rt2/zebra.conf
Normal file
35
tests/topotests/ospf-sr-te-topo1/rt2/zebra.conf
Normal file
@ -0,0 +1,35 @@
|
||||
log file zebra.log
|
||||
!
|
||||
hostname rt2
|
||||
!
|
||||
debug zebra kernel
|
||||
debug zebra packet
|
||||
debug zebra mpls
|
||||
!
|
||||
interface lo
|
||||
ip address 2.2.2.2/32
|
||||
!
|
||||
interface eth-sw1
|
||||
ip address 10.0.1.2/24
|
||||
link-params
|
||||
enable
|
||||
exit-link-params
|
||||
!
|
||||
interface eth-rt4-1
|
||||
ip address 10.0.2.2/24
|
||||
link-params
|
||||
enable
|
||||
exit-link-params
|
||||
!
|
||||
!
|
||||
interface eth-rt4-2
|
||||
ip address 10.0.3.2/24
|
||||
link-params
|
||||
enable
|
||||
exit-link-params
|
||||
!
|
||||
!
|
||||
ip forwarding
|
||||
!
|
||||
line vty
|
||||
!
|
46
tests/topotests/ospf-sr-te-topo1/rt3/ospfd.conf
Normal file
46
tests/topotests/ospf-sr-te-topo1/rt3/ospfd.conf
Normal file
@ -0,0 +1,46 @@
|
||||
hostname rt3
|
||||
log file ospfd.log
|
||||
!
|
||||
debug ospf sr
|
||||
debug ospf te
|
||||
debug ospf event
|
||||
debug ospf lsa
|
||||
debug ospf zebra
|
||||
!
|
||||
interface lo
|
||||
ip ospf area 0.0.0.0
|
||||
!
|
||||
interface eth-sw1
|
||||
ip ospf network point-to-point
|
||||
ip ospf hello-interval 2
|
||||
ip ospf dead-interval 10
|
||||
ip ospf area 0.0.0.0
|
||||
!
|
||||
interface eth-rt5-1
|
||||
ip ospf network point-to-point
|
||||
ip ospf hello-interval 2
|
||||
ip ospf dead-interval 10
|
||||
ip ospf area 0.0.0.0
|
||||
!
|
||||
interface eth-rt5-2
|
||||
ip ospf network point-to-point
|
||||
ip ospf hello-interval 2
|
||||
ip ospf dead-interval 10
|
||||
ip ospf area 0.0.0.0
|
||||
!
|
||||
router ospf
|
||||
ospf router-id 3.3.3.3
|
||||
network 3.3.3.3/32 area 0.0.0.0
|
||||
network 10.0.0.0/16 area 0.0.0.0
|
||||
capability opaque
|
||||
!ospf opaque-lsa
|
||||
mpls-te on
|
||||
!mpls-te export
|
||||
mpls-te router-address 3.3.3.3
|
||||
router-info area 0.0.0.0
|
||||
segment-routing on
|
||||
segment-routing global-block 16000 23999
|
||||
!segment-routing local-block 15000 15999
|
||||
segment-routing node-msd 8
|
||||
segment-routing prefix 3.3.3.3/32 index 30
|
||||
!
|
33
tests/topotests/ospf-sr-te-topo1/rt3/zebra.conf
Normal file
33
tests/topotests/ospf-sr-te-topo1/rt3/zebra.conf
Normal file
@ -0,0 +1,33 @@
|
||||
log file zebra.log
|
||||
!
|
||||
hostname rt3
|
||||
!
|
||||
debug zebra kernel
|
||||
debug zebra packet
|
||||
debug zebra mpls
|
||||
!
|
||||
interface lo
|
||||
ip address 3.3.3.3/32
|
||||
!
|
||||
interface eth-sw1
|
||||
ip address 10.0.1.3/24
|
||||
link-params
|
||||
enable
|
||||
exit-link-params
|
||||
!!
|
||||
interface eth-rt5-1
|
||||
ip address 10.0.4.3/24
|
||||
link-params
|
||||
enable
|
||||
exit-link-params
|
||||
!!
|
||||
interface eth-rt5-2
|
||||
ip address 10.0.5.3/24
|
||||
link-params
|
||||
enable
|
||||
exit-link-params
|
||||
!!
|
||||
ip forwarding
|
||||
!
|
||||
line vty
|
||||
!
|
53
tests/topotests/ospf-sr-te-topo1/rt4/ospfd.conf
Normal file
53
tests/topotests/ospf-sr-te-topo1/rt4/ospfd.conf
Normal file
@ -0,0 +1,53 @@
|
||||
hostname rt4
|
||||
log file ospfd.log
|
||||
!
|
||||
debug ospf sr
|
||||
debug ospf te
|
||||
debug ospf event
|
||||
debug ospf lsa
|
||||
debug ospf zebra
|
||||
!
|
||||
interface lo
|
||||
ip ospf area 0.0.0.0
|
||||
!
|
||||
interface eth-rt2-1
|
||||
ip ospf network point-to-point
|
||||
ip ospf hello-interval 2
|
||||
ip ospf dead-interval 10
|
||||
ip ospf area 0.0.0.0
|
||||
!
|
||||
interface eth-rt2-2
|
||||
ip ospf network point-to-point
|
||||
ip ospf hello-interval 2
|
||||
ip ospf dead-interval 10
|
||||
ip ospf area 0.0.0.0
|
||||
!
|
||||
interface eth-rt5
|
||||
ip ospf network point-to-point
|
||||
ip ospf hello-interval 2
|
||||
ip ospf dead-interval 10
|
||||
ip ospf area 0.0.0.0
|
||||
!
|
||||
interface eth-rt6
|
||||
ip ospf network point-to-point
|
||||
ip ospf hello-interval 2
|
||||
ip ospf dead-interval 10
|
||||
ip ospf area 0.0.0.0
|
||||
!
|
||||
router ospf
|
||||
ospf router-id 4.4.4.4
|
||||
network 4.4.4.4/32 area 0.0.0.0
|
||||
network 10.0.0.0/16 area 0.0.0.0
|
||||
capability opaque
|
||||
!ospf opaque-lsa
|
||||
mpls-te on
|
||||
!mpls-te export
|
||||
mpls-te router-address 4.4.4.4
|
||||
router-info area 0.0.0.0
|
||||
passive-interface lo
|
||||
segment-routing on
|
||||
segment-routing global-block 16000 23999
|
||||
!segment-routing local-block 15000 15999
|
||||
segment-routing node-msd 8
|
||||
segment-routing prefix 4.4.4.4/32 index 40
|
||||
!
|
43
tests/topotests/ospf-sr-te-topo1/rt4/zebra.conf
Normal file
43
tests/topotests/ospf-sr-te-topo1/rt4/zebra.conf
Normal file
@ -0,0 +1,43 @@
|
||||
log file zebra.log
|
||||
!
|
||||
hostname rt4
|
||||
!
|
||||
debug zebra kernel
|
||||
debug zebra packet
|
||||
debug zebra mpls
|
||||
!
|
||||
interface lo
|
||||
ip address 4.4.4.4/32
|
||||
!
|
||||
interface eth-rt2-1
|
||||
ip address 10.0.2.4/24
|
||||
link-params
|
||||
enable
|
||||
exit-link-params
|
||||
!!
|
||||
!
|
||||
interface eth-rt2-2
|
||||
ip address 10.0.3.4/24
|
||||
link-params
|
||||
enable
|
||||
exit-link-params
|
||||
!!
|
||||
!
|
||||
interface eth-rt5
|
||||
ip address 10.0.6.4/24
|
||||
link-params
|
||||
enable
|
||||
exit-link-params
|
||||
!!
|
||||
!
|
||||
interface eth-rt6
|
||||
ip address 10.0.7.4/24
|
||||
link-params
|
||||
enable
|
||||
exit-link-params
|
||||
!!
|
||||
!
|
||||
ip forwarding
|
||||
!
|
||||
line vty
|
||||
!
|
53
tests/topotests/ospf-sr-te-topo1/rt5/ospfd.conf
Normal file
53
tests/topotests/ospf-sr-te-topo1/rt5/ospfd.conf
Normal file
@ -0,0 +1,53 @@
|
||||
hostname rt5
|
||||
log file ospfd.log
|
||||
!
|
||||
debug ospf sr
|
||||
debug ospf te
|
||||
debug ospf event
|
||||
debug ospf lsa
|
||||
debug ospf zebra
|
||||
!
|
||||
interface lo
|
||||
ip ospf area 0.0.0.0
|
||||
!
|
||||
interface eth-rt3-1
|
||||
ip ospf network point-to-point
|
||||
ip ospf hello-interval 2
|
||||
ip ospf dead-interval 10
|
||||
ip ospf area 0.0.0.0
|
||||
!
|
||||
interface eth-rt3-2
|
||||
ip ospf network point-to-point
|
||||
ip ospf hello-interval 2
|
||||
ip ospf dead-interval 10
|
||||
ip ospf area 0.0.0.0
|
||||
!
|
||||
interface eth-rt4
|
||||
ip ospf network point-to-point
|
||||
ip ospf hello-interval 2
|
||||
ip ospf dead-interval 10
|
||||
ip ospf area 0.0.0.0
|
||||
!
|
||||
interface eth-rt6
|
||||
ip ospf network point-to-point
|
||||
ip ospf hello-interval 2
|
||||
ip ospf dead-interval 10
|
||||
ip ospf area 0.0.0.0
|
||||
!
|
||||
router ospf
|
||||
ospf router-id 5.5.5.5
|
||||
network 5.5.5.5/32 area 0.0.0.0
|
||||
network 10.0.0.0/16 area 0.0.0.0
|
||||
capability opaque
|
||||
! ospf opaque-lsa
|
||||
mpls-te on
|
||||
! mpls-te export
|
||||
mpls-te router-address 5.5.5.5
|
||||
router-info area 0.0.0.0
|
||||
passive-interface lo
|
||||
segment-routing on
|
||||
segment-routing global-block 16000 23999
|
||||
! segment-routing local-block 15000 15999
|
||||
segment-routing node-msd 8
|
||||
segment-routing prefix 5.5.5.5/32 index 50
|
||||
!
|
43
tests/topotests/ospf-sr-te-topo1/rt5/zebra.conf
Normal file
43
tests/topotests/ospf-sr-te-topo1/rt5/zebra.conf
Normal file
@ -0,0 +1,43 @@
|
||||
log file zebra.log
|
||||
!
|
||||
hostname rt5
|
||||
!
|
||||
debug zebra kernel
|
||||
debug zebra packet
|
||||
debug zebra mpls
|
||||
!
|
||||
interface lo
|
||||
ip address 5.5.5.5/32
|
||||
!
|
||||
interface eth-rt3-1
|
||||
ip address 10.0.4.5/24
|
||||
link-params
|
||||
enable
|
||||
exit-link-params
|
||||
!!
|
||||
!
|
||||
interface eth-rt3-2
|
||||
ip address 10.0.5.5/24
|
||||
link-params
|
||||
enable
|
||||
exit-link-params
|
||||
!!
|
||||
!
|
||||
interface eth-rt4
|
||||
ip address 10.0.6.5/24
|
||||
link-params
|
||||
enable
|
||||
exit-link-params
|
||||
!!
|
||||
!
|
||||
interface eth-rt6
|
||||
ip address 10.0.8.5/24
|
||||
link-params
|
||||
enable
|
||||
exit-link-params
|
||||
!!
|
||||
!
|
||||
ip forwarding
|
||||
!
|
||||
line vty
|
||||
!
|
12
tests/topotests/ospf-sr-te-topo1/rt6/bgpd.conf
Normal file
12
tests/topotests/ospf-sr-te-topo1/rt6/bgpd.conf
Normal file
@ -0,0 +1,12 @@
|
||||
log file bgpd.log
|
||||
!
|
||||
router bgp 1
|
||||
bgp router-id 6.6.6.6
|
||||
neighbor 1.1.1.1 remote-as 1
|
||||
neighbor 1.1.1.1 update-source lo
|
||||
!
|
||||
address-family ipv4 unicast
|
||||
redistribute static
|
||||
neighbor 1.1.1.1 next-hop-self
|
||||
exit-address-family
|
||||
!
|
41
tests/topotests/ospf-sr-te-topo1/rt6/ospfd.conf
Normal file
41
tests/topotests/ospf-sr-te-topo1/rt6/ospfd.conf
Normal file
@ -0,0 +1,41 @@
|
||||
hostname rt6
|
||||
log file ospfd.log
|
||||
!
|
||||
debug ospf sr
|
||||
debug ospf te
|
||||
debug ospf event
|
||||
debug ospf lsa
|
||||
debug ospf zebra
|
||||
!
|
||||
interface lo
|
||||
ip ospf area 0.0.0.0
|
||||
!
|
||||
interface eth-rt4
|
||||
ip ospf network point-to-point
|
||||
ip ospf hello-interval 2
|
||||
ip ospf dead-interval 10
|
||||
ip ospf area 0.0.0.0
|
||||
!
|
||||
interface eth-rt5
|
||||
ip ospf network point-to-point
|
||||
ip ospf hello-interval 2
|
||||
ip ospf dead-interval 10
|
||||
ip ospf area 0.0.0.0
|
||||
!
|
||||
router ospf
|
||||
ospf router-id 6.6.6.6
|
||||
network 6.6.6.6/32 area 0.0.0.0
|
||||
network 10.0.0.0/16 area 0.0.0.0
|
||||
capability opaque
|
||||
! ospf opaque-lsa
|
||||
mpls-te on
|
||||
mpls-te export
|
||||
mpls-te router-address 6.6.6.6
|
||||
router-info area 0.0.0.0
|
||||
passive-interface lo
|
||||
segment-routing on
|
||||
segment-routing global-block 16000 23999
|
||||
! segment-routing local-block 15000 15999
|
||||
segment-routing node-msd 8
|
||||
segment-routing prefix 6.6.6.6/32 index 60
|
||||
!
|
25
tests/topotests/ospf-sr-te-topo1/rt6/pathd.conf
Normal file
25
tests/topotests/ospf-sr-te-topo1/rt6/pathd.conf
Normal file
@ -0,0 +1,25 @@
|
||||
log file pathd.log
|
||||
!
|
||||
hostname rt6
|
||||
!
|
||||
segment-routing
|
||||
traffic-eng
|
||||
mpls-te on
|
||||
mpls-te import ospfv2
|
||||
segment-list default
|
||||
index 10 nai adjacency 10.0.7.6 10.0.7.4
|
||||
index 20 nai adjacency 10.0.2.4 10.0.2.2
|
||||
index 30 nai adjacency 10.0.1.2 10.0.1.1
|
||||
!
|
||||
segment-list test
|
||||
index 10 nai adjacency 10.0.8.6 10.0.8.5
|
||||
index 20 nai adjacency 10.0.6.5 10.0.6.4
|
||||
index 30 nai adjacency 10.0.2.4 10.0.2.2
|
||||
index 40 nai adjacency 10.0.1.2 10.0.1.1
|
||||
!
|
||||
policy color 1 endpoint 1.1.1.1
|
||||
name default
|
||||
binding-sid 6666
|
||||
!
|
||||
!
|
||||
!
|
@ -0,0 +1,13 @@
|
||||
{
|
||||
"frr-pathd:pathd": {
|
||||
"srte": {
|
||||
"policy": [
|
||||
{
|
||||
"color": 1,
|
||||
"endpoint": "1.1.1.1",
|
||||
"is-operational": false
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
{
|
||||
"frr-pathd:pathd": {
|
||||
"srte": {
|
||||
"policy": [
|
||||
{
|
||||
"color": 1,
|
||||
"endpoint": "1.1.1.1",
|
||||
"is-operational": true,
|
||||
"candidate-path": [
|
||||
{
|
||||
"preference": 100,
|
||||
"is-best-candidate-path": true
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
{
|
||||
"frr-pathd:pathd": {
|
||||
"srte": {
|
||||
"policy": [
|
||||
{
|
||||
"color": 1,
|
||||
"endpoint": "1.1.1.1",
|
||||
"is-operational": true,
|
||||
"candidate-path": [
|
||||
{
|
||||
"preference": 100,
|
||||
"is-best-candidate-path": true
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
{
|
||||
"frr-pathd:pathd": {
|
||||
"srte": {
|
||||
"policy": [
|
||||
{
|
||||
"color": 1,
|
||||
"endpoint": "1.1.1.1",
|
||||
"is-operational": true,
|
||||
"candidate-path": [
|
||||
{
|
||||
"preference": 100,
|
||||
"is-best-candidate-path": false
|
||||
},
|
||||
{
|
||||
"preference": 200,
|
||||
"is-best-candidate-path": true
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
38
tests/topotests/ospf-sr-te-topo1/rt6/zebra.conf
Normal file
38
tests/topotests/ospf-sr-te-topo1/rt6/zebra.conf
Normal file
@ -0,0 +1,38 @@
|
||||
log file zebra.log
|
||||
!
|
||||
hostname rt6
|
||||
!
|
||||
debug zebra kernel
|
||||
debug zebra packet
|
||||
debug zebra mpls
|
||||
!
|
||||
interface lo
|
||||
ip address 6.6.6.6/32
|
||||
!
|
||||
interface eth-rt4
|
||||
ip address 10.0.7.6/24
|
||||
link-params
|
||||
enable
|
||||
exit-link-params
|
||||
!!
|
||||
!
|
||||
interface eth-rt5
|
||||
ip address 10.0.8.6/24
|
||||
link-params
|
||||
enable
|
||||
exit-link-params
|
||||
!!
|
||||
!
|
||||
interface eth-dst
|
||||
ip address 10.0.11.1/24
|
||||
link-params
|
||||
enable
|
||||
exit-link-params
|
||||
!!
|
||||
!
|
||||
ip forwarding
|
||||
!
|
||||
ip route 9.9.9.2/32 10.0.11.2
|
||||
!
|
||||
line vty
|
||||
!
|
640
tests/topotests/ospf-sr-te-topo1/test_ospf_sr_te_topo1.py
Executable file
640
tests/topotests/ospf-sr-te-topo1/test_ospf_sr_te_topo1.py
Executable file
@ -0,0 +1,640 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
#
|
||||
# test_ospf_sr_te_topo1.py
|
||||
#
|
||||
# Copyright (c) 2021 by
|
||||
# Volta Networks
|
||||
#
|
||||
# Permission to use, copy, modify, and/or distribute this software
|
||||
# for any purpose with or without fee is hereby granted, provided
|
||||
# that the above copyright notice and this permission notice appear
|
||||
# in all copies.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS" AND NETDEF DISCLAIMS ALL WARRANTIES
|
||||
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR
|
||||
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
|
||||
# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
|
||||
# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
|
||||
# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
|
||||
# OF THIS SOFTWARE.
|
||||
#
|
||||
|
||||
"""
|
||||
test_ospf_sr_te_topo1.py:
|
||||
|
||||
+---------+
|
||||
| |
|
||||
| RT1 |
|
||||
| 1.1.1.1 |
|
||||
| |
|
||||
+---------+
|
||||
|eth-sw1
|
||||
|
|
||||
|
|
||||
|
|
||||
+---------+ | +---------+
|
||||
| | | | |
|
||||
| RT2 |eth-sw1 | eth-sw1| RT3 |
|
||||
| 2.2.2.2 +----------+ + 3.3.3.3 |
|
||||
| | 10.0.1.0/24 | |
|
||||
+---------+ +---------+
|
||||
eth-rt4-1| eth-rt5-1| |eth-rt5-2
|
||||
| | |
|
||||
10.0.2.0/24| 10.0.4.0/24| |10.0.5.0/24
|
||||
| | |
|
||||
eth-rt2-1| eth-rt3-1| |eth-rt3-2
|
||||
+---------+ +---------+
|
||||
| | | |
|
||||
| RT4 | 10.0.6.0/24 | RT5 |
|
||||
| 4.4.4.4 +---------------------+ 5.5.5.5 |
|
||||
| |eth-rt5 eth-rt4| |
|
||||
+---------+ +---------+
|
||||
eth-rt6| |eth-rt6
|
||||
| |
|
||||
10.0.7.0/24| |10.0.8.0/24
|
||||
| +---------+ |
|
||||
| | | |
|
||||
| | RT6 | |
|
||||
+----------+ 6.6.6.6 +-----------+
|
||||
eth-rt4| |eth-rt5
|
||||
+---------+
|
||||
|eth-dst (.1)
|
||||
|
|
||||
|10.0.11.0/24
|
||||
|
|
||||
|eth-rt6 (.2)
|
||||
+---------+
|
||||
| |
|
||||
| DST |
|
||||
| 9.9.9.2 |
|
||||
| |
|
||||
+---------+
|
||||
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
import pytest
|
||||
import json
|
||||
import re
|
||||
from time import sleep
|
||||
from functools import partial
|
||||
|
||||
# Save the Current Working Directory to find configuration files.
|
||||
CWD = os.path.dirname(os.path.realpath(__file__))
|
||||
sys.path.append(os.path.join(CWD, "../"))
|
||||
|
||||
# pylint: disable=C0413
|
||||
# Import topogen and topotest helpers
|
||||
from lib import topotest
|
||||
from lib.topogen import Topogen, TopoRouter, get_topogen
|
||||
from lib.topolog import logger
|
||||
|
||||
# Required to instantiate the topology builder class.
|
||||
from mininet.topo import Topo
|
||||
|
||||
pytestmark = [pytest.mark.bgpd, pytest.mark.ospfd, pytest.mark.pathd]
|
||||
|
||||
|
||||
class TemplateTopo(Topo):
|
||||
"Test topology builder"
|
||||
|
||||
def build(self, *_args, **_opts):
|
||||
"Build function"
|
||||
tgen = get_topogen(self)
|
||||
|
||||
#
|
||||
# Define FRR Routers
|
||||
#
|
||||
for router in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6", "dst"]:
|
||||
tgen.add_router(router)
|
||||
|
||||
#
|
||||
# Define connections
|
||||
#
|
||||
switch = tgen.add_switch("s1")
|
||||
switch.add_link(tgen.gears["rt1"], nodeif="eth-sw1")
|
||||
switch.add_link(tgen.gears["rt2"], nodeif="eth-sw1")
|
||||
#switch.add_link(tgen.gears["rt3"], nodeif="eth-sw1")
|
||||
|
||||
switch = tgen.add_switch("s2")
|
||||
switch.add_link(tgen.gears["rt2"], nodeif="eth-rt4-1")
|
||||
switch.add_link(tgen.gears["rt4"], nodeif="eth-rt2-1")
|
||||
|
||||
#switch = tgen.add_switch("s3")
|
||||
#switch.add_link(tgen.gears["rt2"], nodeif="eth-rt4-2")
|
||||
#switch.add_link(tgen.gears["rt4"], nodeif="eth-rt2-2")
|
||||
|
||||
switch = tgen.add_switch("s4")
|
||||
switch.add_link(tgen.gears["rt3"], nodeif="eth-rt5-1")
|
||||
switch.add_link(tgen.gears["rt5"], nodeif="eth-rt3-1")
|
||||
|
||||
switch = tgen.add_switch("s5")
|
||||
switch.add_link(tgen.gears["rt3"], nodeif="eth-rt5-2")
|
||||
switch.add_link(tgen.gears["rt5"], nodeif="eth-rt3-2")
|
||||
|
||||
switch = tgen.add_switch("s6")
|
||||
switch.add_link(tgen.gears["rt4"], nodeif="eth-rt5")
|
||||
switch.add_link(tgen.gears["rt5"], nodeif="eth-rt4")
|
||||
|
||||
switch = tgen.add_switch("s7")
|
||||
switch.add_link(tgen.gears["rt4"], nodeif="eth-rt6")
|
||||
switch.add_link(tgen.gears["rt6"], nodeif="eth-rt4")
|
||||
|
||||
switch = tgen.add_switch("s8")
|
||||
switch.add_link(tgen.gears["rt5"], nodeif="eth-rt6")
|
||||
switch.add_link(tgen.gears["rt6"], nodeif="eth-rt5")
|
||||
|
||||
switch = tgen.add_switch("s9")
|
||||
switch.add_link(tgen.gears["rt6"], nodeif="eth-dst")
|
||||
switch.add_link(tgen.gears["dst"], nodeif="eth-rt6")
|
||||
|
||||
|
||||
def setup_module(mod):
|
||||
"Sets up the pytest environment"
|
||||
|
||||
tgen = Topogen(TemplateTopo, mod.__name__)
|
||||
|
||||
frrdir = tgen.config.get(tgen.CONFIG_SECTION, "frrdir")
|
||||
if not os.path.isfile(os.path.join(frrdir, "pathd")):
|
||||
pytest.skip("pathd daemon wasn't built in:"+frrdir)
|
||||
|
||||
tgen.start_topology()
|
||||
|
||||
router_list = tgen.routers()
|
||||
|
||||
# For all registered routers, load the zebra configuration file
|
||||
for rname, router in router_list.items():
|
||||
router.load_config(
|
||||
TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname))
|
||||
)
|
||||
router.load_config(
|
||||
TopoRouter.RD_OSPF, os.path.join(CWD, "{}/ospfd.conf".format(rname))
|
||||
)
|
||||
router.load_config(
|
||||
TopoRouter.RD_PATH, os.path.join(CWD, "{}/pathd.conf".format(rname))
|
||||
)
|
||||
router.load_config(
|
||||
TopoRouter.RD_BGP, os.path.join(CWD, "{}/bgpd.conf".format(rname))
|
||||
)
|
||||
|
||||
tgen.start_router()
|
||||
|
||||
|
||||
def teardown_module(mod):
|
||||
"Teardown the pytest environment"
|
||||
tgen = get_topogen()
|
||||
|
||||
# This function tears down the whole topology.
|
||||
tgen.stop_topology()
|
||||
|
||||
|
||||
def setup_testcase(msg):
|
||||
logger.info(msg)
|
||||
tgen = get_topogen()
|
||||
|
||||
# Skip if previous fatal error condition is raised
|
||||
if tgen.routers_have_failure():
|
||||
pytest.skip(tgen.errors)
|
||||
|
||||
return tgen
|
||||
|
||||
|
||||
def print_cmd_result(rname, command):
|
||||
print(get_topogen().gears[rname].vtysh_cmd(command, isjson=False))
|
||||
|
||||
|
||||
def compare_json_test(router, command, reference, exact):
|
||||
output = router.vtysh_cmd(command, isjson=True)
|
||||
result = topotest.json_cmp(output, reference)
|
||||
|
||||
# Note: topotest.json_cmp() just checks on inclusion of keys.
|
||||
# For exact matching also compare the other way around.
|
||||
if not result and exact:
|
||||
return topotest.json_cmp(reference, output)
|
||||
else:
|
||||
return result
|
||||
|
||||
|
||||
def cmp_json_output(rname, command, reference, exact=False):
|
||||
"Compare router JSON output"
|
||||
|
||||
logger.info('Comparing router "%s" "%s" output', rname, command)
|
||||
|
||||
tgen = get_topogen()
|
||||
filename = "{}/{}/{}".format(CWD, rname, reference)
|
||||
expected = json.loads(open(filename).read())
|
||||
|
||||
# Run test function until we get an result. Wait at most 60 seconds.
|
||||
test_func = partial(compare_json_test, tgen.gears[rname], command, expected, exact)
|
||||
_, diff = topotest.run_and_expect(test_func, None, count=60, wait=0.5)
|
||||
assertmsg = '"{}" JSON output mismatches the expected result'.format(rname)
|
||||
assert diff is None, assertmsg
|
||||
|
||||
|
||||
def cmp_json_output_exact(rname, command, reference):
|
||||
return cmp_json_output(rname, command, reference, True)
|
||||
|
||||
|
||||
def add_candidate_path(rname, endpoint, pref, name, segment_list="default"):
|
||||
get_topogen().net[rname].cmd(
|
||||
""" \
|
||||
vtysh -c "conf t" \
|
||||
-c "segment-routing" \
|
||||
-c "traffic-eng" \
|
||||
-c "policy color 1 endpoint """
|
||||
+ endpoint
|
||||
+ """" \
|
||||
-c "candidate-path preference """
|
||||
+ str(pref)
|
||||
+ """ name """
|
||||
+ name
|
||||
+ """ explicit segment-list """
|
||||
+ segment_list
|
||||
+ '''"'''
|
||||
)
|
||||
|
||||
|
||||
def delete_candidate_path(rname, endpoint, pref):
|
||||
get_topogen().net[rname].cmd(
|
||||
""" \
|
||||
vtysh -c "conf t" \
|
||||
-c "segment-routing" \
|
||||
-c "traffic-eng" \
|
||||
-c "policy color 1 endpoint """
|
||||
+ endpoint
|
||||
+ """" \
|
||||
-c "no candidate-path preference """
|
||||
+ str(pref)
|
||||
+ '''"'''
|
||||
)
|
||||
|
||||
|
||||
def add_segment(rname, name, index, label):
|
||||
get_topogen().net[rname].cmd(
|
||||
""" \
|
||||
vtysh -c "conf t" \
|
||||
-c "segment-routing" \
|
||||
-c "traffic-eng" \
|
||||
-c "segment-list """
|
||||
+ name
|
||||
+ """" \
|
||||
-c "index """
|
||||
+ str(index)
|
||||
+ """ mpls label """
|
||||
+ str(label)
|
||||
+ '''"'''
|
||||
)
|
||||
|
||||
|
||||
def delete_segment(rname, name, index):
|
||||
get_topogen().net[rname].cmd(
|
||||
""" \
|
||||
vtysh -c "conf t" \
|
||||
-c "segment-routing" \
|
||||
-c "traffic-eng" \
|
||||
-c "segment-list """
|
||||
+ name
|
||||
+ """" \
|
||||
-c "no index """
|
||||
+ str(index)
|
||||
+ '''"'''
|
||||
)
|
||||
|
||||
|
||||
def add_segment_adj(rname, name, index, src, dst):
|
||||
get_topogen().net[rname].cmd(
|
||||
""" \
|
||||
vtysh -c "conf t" \
|
||||
-c "segment-routing" \
|
||||
-c "traffic-eng" \
|
||||
-c "segment-list """
|
||||
+ name
|
||||
+ """" \
|
||||
-c "index """
|
||||
+ str(index)
|
||||
+ """ nai adjacency """
|
||||
+ str(src)
|
||||
+ """ """
|
||||
+ str(dst)
|
||||
+ '''"'''
|
||||
)
|
||||
|
||||
|
||||
def create_sr_policy(rname, endpoint, bsid):
|
||||
get_topogen().net[rname].cmd(
|
||||
""" \
|
||||
vtysh -c "conf t" \
|
||||
-c "segment-routing" \
|
||||
-c "traffic-eng" \
|
||||
-c "policy color 1 endpoint """
|
||||
+ endpoint
|
||||
+ """" \
|
||||
-c "name default" \
|
||||
-c "binding-sid """
|
||||
+ str(bsid)
|
||||
+ '''"'''
|
||||
)
|
||||
|
||||
|
||||
def delete_sr_policy(rname, endpoint):
|
||||
get_topogen().net[rname].cmd(
|
||||
""" \
|
||||
vtysh -c "conf t" \
|
||||
-c "segment-routing" \
|
||||
-c "traffic-eng" \
|
||||
-c "no policy color 1 endpoint """
|
||||
+ endpoint
|
||||
+ '''"'''
|
||||
)
|
||||
|
||||
|
||||
def create_prefix_sid(rname, prefix, sid):
|
||||
get_topogen().net[rname].cmd(
|
||||
""" \
|
||||
vtysh -c "conf t" \
|
||||
-c "router ospf " \
|
||||
-c "segment-routing prefix """
|
||||
+ prefix
|
||||
+ " index "
|
||||
+ str(sid)
|
||||
+ '''"'''
|
||||
)
|
||||
|
||||
|
||||
def delete_prefix_sid(rname, prefix):
|
||||
get_topogen().net[rname].cmd(
|
||||
''' \
|
||||
vtysh -c "conf t" \
|
||||
-c "router ospf " \
|
||||
-c "no segment-routing prefix "'''
|
||||
+ prefix
|
||||
)
|
||||
|
||||
|
||||
def check_bsid(rt, bsid, fn_name, positive):
|
||||
"""
|
||||
Search for a bsid in rt1 and rt6
|
||||
Positive means that check is true is bsid is found
|
||||
Positive="False" means that check is true is bsid is NOT found
|
||||
"""
|
||||
|
||||
logger.info('Checking "%s" bsid "%s" for router "%s" ', positive, bsid, rt)
|
||||
|
||||
count = 0
|
||||
candidate_key = bsid
|
||||
candidate_output = ""
|
||||
# First wait for convergence
|
||||
tgen = get_topogen()
|
||||
while count < 30:
|
||||
matched = False
|
||||
matched_key = False
|
||||
sleep(1)
|
||||
count += 1
|
||||
router = tgen.gears[rt]
|
||||
candidate_output = router.vtysh_cmd("show mpls table json")
|
||||
candidate_output_json = json.loads(candidate_output)
|
||||
for item in candidate_output_json.items():
|
||||
# logger.info('item "%s"', item)
|
||||
if item[0] == candidate_key:
|
||||
matched_key = True
|
||||
if positive:
|
||||
break
|
||||
if positive:
|
||||
if matched_key:
|
||||
matched = True
|
||||
assertmsg = "{} don't has entry {} but is was expected".format(
|
||||
router.name, candidate_key)
|
||||
else:
|
||||
if not matched_key:
|
||||
matched = True
|
||||
assertmsg = "{} has entry {} but is wans't expected".format(
|
||||
router.name, candidate_key)
|
||||
if matched:
|
||||
logger.info('Success "%s" in "%s"', router.name, fn_name)
|
||||
return
|
||||
assert matched, assertmsg
|
||||
|
||||
|
||||
#
|
||||
# Step 1
|
||||
#
|
||||
# Checking the MPLS table using a single SR Policy and a single Candidate Path
|
||||
# Segment list are base in adjacency that query TED
|
||||
#
|
||||
def test_srte_init_step1():
|
||||
setup_testcase("Test (step 1): wait OSPF convergence / label distribution")
|
||||
|
||||
check_bsid("rt1", "1111", test_srte_init_step1.__name__, False)
|
||||
check_bsid("rt6", "6666", test_srte_init_step1.__name__, False)
|
||||
|
||||
|
||||
def test_srte_add_candidate_check_mpls_table_step1():
|
||||
setup_testcase("Test (step 1): check MPLS table regarding the added Candidate Path")
|
||||
|
||||
for rname, endpoint in [("rt1", "6.6.6.6"), ("rt6", "1.1.1.1")]:
|
||||
add_candidate_path(rname, endpoint, 100, "default")
|
||||
check_bsid(rname, "1111" if rname == "rt1" else "6666", test_srte_init_step1.__name__, True)
|
||||
delete_candidate_path(rname, endpoint, 100)
|
||||
|
||||
|
||||
def test_srte_reinstall_sr_policy_check_mpls_table_step1():
|
||||
setup_testcase(
|
||||
"Test (step 1): check MPLS table after the SR Policy was removed and reinstalled"
|
||||
)
|
||||
|
||||
for rname, endpoint, bsid in [("rt1", "6.6.6.6", 1111), ("rt6", "1.1.1.1", 6666)]:
|
||||
add_candidate_path(rname, endpoint, 100, "default")
|
||||
delete_sr_policy(rname, endpoint)
|
||||
check_bsid(rname, bsid, test_srte_init_step1.__name__, False)
|
||||
create_sr_policy(rname, endpoint, bsid)
|
||||
add_candidate_path(rname, endpoint, 100, "default")
|
||||
check_bsid(rname, "1111" if rname == "rt1" else "6666", test_srte_init_step1.__name__, True)
|
||||
delete_candidate_path(rname, endpoint, 100)
|
||||
|
||||
|
||||
#
|
||||
# Step 2
|
||||
#
|
||||
# Checking pathd operational data using a single SR Policy and a single Candidate Path
|
||||
# Segment list are base in adjacency that query TED
|
||||
#
|
||||
def test_srte_bare_policy_step2():
|
||||
setup_testcase("Test (step 2): bare SR Policy should not be operational")
|
||||
|
||||
for rname in ["rt1", "rt6"]:
|
||||
cmp_json_output_exact(
|
||||
rname,
|
||||
"show yang operational-data /frr-pathd:pathd pathd",
|
||||
"step2/show_operational_data.ref",
|
||||
)
|
||||
|
||||
|
||||
def test_srte_add_candidate_check_operational_data_step2():
|
||||
setup_testcase(
|
||||
"Test (step 2): add single Candidate Path, SR Policy should be operational"
|
||||
)
|
||||
|
||||
for rname, endpoint in [("rt1", "6.6.6.6"), ("rt6", "1.1.1.1")]:
|
||||
add_candidate_path(rname, endpoint, 100, "default")
|
||||
cmp_json_output(
|
||||
rname,
|
||||
"show yang operational-data /frr-pathd:pathd pathd",
|
||||
"step2/show_operational_data_with_candidate.ref",
|
||||
)
|
||||
|
||||
|
||||
def test_srte_config_remove_candidate_check_operational_data_step2():
|
||||
setup_testcase(
|
||||
"Test (step 2): remove single Candidate Path, SR Policy should not be operational anymore"
|
||||
)
|
||||
|
||||
for rname, endpoint in [("rt1", "6.6.6.6"), ("rt6", "1.1.1.1")]:
|
||||
delete_candidate_path(rname, endpoint, 100)
|
||||
cmp_json_output_exact(
|
||||
rname,
|
||||
"show yang operational-data /frr-pathd:pathd pathd",
|
||||
"step2/show_operational_data.ref",
|
||||
)
|
||||
|
||||
|
||||
#
|
||||
# Step 3
|
||||
#
|
||||
# Testing the Candidate Path selection
|
||||
# Segment list are based in adjacencies resolved by query TED
|
||||
#
|
||||
def test_srte_add_two_candidates_step3():
|
||||
setup_testcase("Test (step 3): second Candidate Path has higher Priority")
|
||||
|
||||
for rname, endpoint in [("rt1", "6.6.6.6"), ("rt6", "1.1.1.1")]:
|
||||
for pref, cand_name in [("100", "first"), ("200", "second")]:
|
||||
add_candidate_path(rname, endpoint, pref, cand_name)
|
||||
cmp_json_output(
|
||||
rname,
|
||||
"show yang operational-data /frr-pathd:pathd pathd",
|
||||
"step3/show_operational_data_with_two_candidates.ref",
|
||||
)
|
||||
|
||||
# cleanup
|
||||
for rname, endpoint in [("rt1", "6.6.6.6"), ("rt6", "1.1.1.1")]:
|
||||
for pref in ["100", "200"]:
|
||||
delete_candidate_path(rname, endpoint, pref)
|
||||
|
||||
|
||||
def test_srte_add_two_candidates_with_reverse_priority_step3():
|
||||
setup_testcase("Test (step 3): second Candidate Path has lower Priority")
|
||||
|
||||
# Use reversed priorities here
|
||||
for rname, endpoint in [("rt1", "6.6.6.6"), ("rt6", "1.1.1.1")]:
|
||||
for pref, cand_name in [("200", "first"), ("100", "second")]:
|
||||
add_candidate_path(rname, endpoint, pref, cand_name)
|
||||
cmp_json_output(
|
||||
rname,
|
||||
"show yang operational-data /frr-pathd:pathd pathd",
|
||||
"step3/show_operational_data_with_two_candidates.ref",
|
||||
)
|
||||
|
||||
# cleanup
|
||||
for rname, endpoint in [("rt1", "6.6.6.6"), ("rt6", "1.1.1.1")]:
|
||||
for pref in ["100", "200"]:
|
||||
delete_candidate_path(rname, endpoint, pref)
|
||||
|
||||
|
||||
def test_srte_remove_best_candidate_step3():
|
||||
setup_testcase("Test (step 3): delete the Candidate Path with higher priority")
|
||||
|
||||
for rname, endpoint in [("rt1", "6.6.6.6"), ("rt6", "1.1.1.1")]:
|
||||
for pref, cand_name in [("100", "first"), ("200", "second")]:
|
||||
add_candidate_path(rname, endpoint, pref, cand_name)
|
||||
|
||||
# Delete candidate with higher priority
|
||||
for rname, endpoint in [("rt1", "6.6.6.6"), ("rt6", "1.1.1.1")]:
|
||||
delete_candidate_path(rname, endpoint, 200)
|
||||
|
||||
# Candidate with lower priority should get active now
|
||||
for rname, endpoint in [("rt1", "6.6.6.6"), ("rt6", "1.1.1.1")]:
|
||||
cmp_json_output(
|
||||
rname,
|
||||
"show yang operational-data /frr-pathd:pathd pathd",
|
||||
"step3/show_operational_data_with_single_candidate.ref",
|
||||
)
|
||||
# cleanup
|
||||
delete_candidate_path(rname, endpoint, 100)
|
||||
|
||||
|
||||
#
|
||||
# Step 4
|
||||
#
|
||||
# Checking MPLS table with a single SR Policy and a Candidate Path with different Segment Lists and other modifications
|
||||
# Segment list are base in adjacency that query TED
|
||||
#
|
||||
def test_srte_change_segment_list_check_mpls_table_step4():
|
||||
setup_testcase("Test (step 4): check MPLS table for changed Segment List")
|
||||
|
||||
for rname, endpoint in [("rt1", "6.6.6.6"), ("rt6", "1.1.1.1")]:
|
||||
add_candidate_path(rname, endpoint, 100, "default")
|
||||
# now change the segment list name
|
||||
add_candidate_path(rname, endpoint, 100, "default", "test")
|
||||
check_bsid(rname, "1111" if rname == "rt1" else "6666", test_srte_init_step1.__name__, True)
|
||||
delete_segment(rname, "test", 10)
|
||||
delete_segment(rname, "test", 20)
|
||||
delete_segment(rname, "test", 30)
|
||||
delete_segment(rname, "test", 40)
|
||||
if rname == "rt1":
|
||||
add_segment_adj(rname, "test", 10, "10.0.1.1", "10.0.1.2")
|
||||
add_segment_adj(rname, "test", 20, "10.0.2.2", "10.0.2.4")
|
||||
add_segment_adj(rname, "test", 30, "10.0.6.4", "10.0.6.5")
|
||||
add_segment_adj(rname, "test", 40, "10.0.8.5", "10.0.8.6")
|
||||
else:
|
||||
add_segment_adj(rname, "test", 10, "10.0.8.6", "10.0.8.5")
|
||||
add_segment_adj(rname, "test", 20, "10.0.6.5", "10.0.6.4")
|
||||
add_segment_adj(rname, "test", 30, "10.0.2.4", "10.0.2.2")
|
||||
add_segment_adj(rname, "test", 40, "10.0.1.2", "10.0.1.1")
|
||||
check_bsid(rname, "1111" if rname == "rt1" else "6666", test_srte_init_step1.__name__, True)
|
||||
delete_candidate_path(rname, endpoint, 100)
|
||||
|
||||
|
||||
def test_srte_change_sl_priority_error_ted_check_mpls_table_step4():
|
||||
setup_testcase("Test (step 4): check MPLS table keeps low prio sl")
|
||||
|
||||
for rname, endpoint in [("rt1", "6.6.6.6"), ("rt6", "1.1.1.1")]:
|
||||
add_candidate_path(rname, endpoint, 100, "default")
|
||||
# now change the segment list name
|
||||
add_candidate_path(rname, endpoint, 200, "test", "test")
|
||||
check_bsid(rname, "1111" if rname == "rt1" else "6666", test_srte_init_step1.__name__, True)
|
||||
delete_segment(rname, "test", 10)
|
||||
delete_segment(rname, "test", 20)
|
||||
delete_segment(rname, "test", 30)
|
||||
delete_segment(rname, "test", 40)
|
||||
# These won't resolv
|
||||
if rname == "rt1":
|
||||
add_segment_adj(rname, "test", 10, "10.0.1.99", "10.0.1.99")
|
||||
add_segment_adj(rname, "test", 20, "10.0.2.99", "10.0.2.99")
|
||||
add_segment_adj(rname, "test", 30, "10.0.6.99", "10.0.6.99")
|
||||
add_segment_adj(rname, "test", 40, "10.0.8.99", "10.0.8.99")
|
||||
else:
|
||||
add_segment_adj(rname, "test", 10, "10.0.8.99", "10.0.8.99")
|
||||
add_segment_adj(rname, "test", 20, "10.0.6.99", "10.0.6.99")
|
||||
add_segment_adj(rname, "test", 30, "10.0.2.99", "10.0.2.99")
|
||||
add_segment_adj(rname, "test", 40, "10.0.1.99", "10.0.1.99")
|
||||
# So policy sticks with default sl even higher prio
|
||||
check_bsid(rname, "1111" if rname == "rt1" else "6666", test_srte_init_step1.__name__, True)
|
||||
delete_candidate_path(rname, endpoint, 100)
|
||||
|
||||
|
||||
# Memory leak test template
|
||||
def test_memory_leak():
|
||||
"Run the memory leak test and report results."
|
||||
tgen = get_topogen()
|
||||
if not tgen.is_memleak_enabled():
|
||||
pytest.skip("Memory leak test/report is disabled")
|
||||
|
||||
tgen.report_memory_leaks()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
args = ["-s"] + sys.argv[1:]
|
||||
sys.exit(pytest.main(args))
|
@ -84,51 +84,71 @@ module frr-pathd {
|
||||
leaf index {
|
||||
type uint32;
|
||||
description "Segment index";
|
||||
}
|
||||
leaf sid-value {
|
||||
type rt-types:mpls-label;
|
||||
}
|
||||
leaf sid-value {
|
||||
type rt-types:mpls-label;
|
||||
description "MPLS label value";
|
||||
}
|
||||
container nai {
|
||||
presence "The segment has a Node or Adjacency Identifier";
|
||||
leaf type {
|
||||
description "NAI type";
|
||||
mandatory true;
|
||||
description "MPLS label value";
|
||||
}
|
||||
container nai {
|
||||
presence "The segement has a Node or Adjacency Identifier";
|
||||
leaf type {
|
||||
description "NAI type";
|
||||
mandatory true;
|
||||
type enumeration {
|
||||
enum ipv4_node {
|
||||
value 1;
|
||||
description "IPv4 node identifier";
|
||||
}
|
||||
enum ipv6_node {
|
||||
value 2;
|
||||
description "IPv6 node identifier";
|
||||
}
|
||||
enum ipv4_adjacency {
|
||||
value 3;
|
||||
description "IPv4 adjacency";
|
||||
}
|
||||
enum ipv6_adjacency {
|
||||
value 4;
|
||||
description "IPv6 adjacency";
|
||||
}
|
||||
enum ipv4_unnumbered_adjacency {
|
||||
value 5;
|
||||
description "IPv4 unnumbered adjacency";
|
||||
}
|
||||
type enumeration {
|
||||
enum ipv4_node {
|
||||
value 1;
|
||||
description "IPv4 node identifier";
|
||||
}
|
||||
enum ipv6_node {
|
||||
value 2;
|
||||
description "IPv6 node identifier";
|
||||
}
|
||||
enum ipv4_adjacency {
|
||||
value 3;
|
||||
description "IPv4 adjacency";
|
||||
}
|
||||
enum ipv6_adjacency {
|
||||
value 4;
|
||||
description "IPv6 adjacency";
|
||||
}
|
||||
enum ipv4_unnumbered_adjacency {
|
||||
value 5;
|
||||
description "IPv4 unnumbered adjacency";
|
||||
}
|
||||
enum ipv4_local_iface {
|
||||
value 7;
|
||||
description "IPv4 prefix with local interface id";
|
||||
}
|
||||
enum ipv6_local_iface {
|
||||
value 8;
|
||||
description "IPv6 prefix with local interface id";
|
||||
}
|
||||
enum ipv4_algo {
|
||||
value 9;
|
||||
description "IPv4 prefix with optional algorithm";
|
||||
}
|
||||
enum ipv6_algo {
|
||||
value 10;
|
||||
description "IPv6 prefix with optional algorithm";
|
||||
}
|
||||
}
|
||||
leaf local-address {
|
||||
type inet:ip-address;
|
||||
mandatory true;
|
||||
}
|
||||
leaf local-interface {
|
||||
type uint32;
|
||||
mandatory true;
|
||||
when "../type = 'ipv4_unnumbered_adjacency'";
|
||||
}
|
||||
leaf remote-address {
|
||||
type inet:ip-address;
|
||||
}
|
||||
leaf local-address {
|
||||
type inet:ip-address;
|
||||
mandatory true;
|
||||
}
|
||||
leaf local-prefix-len {
|
||||
type uint8;
|
||||
mandatory true;
|
||||
when "../type = 'ipv4_local_iface' or ../type = 'ipv6_local_iface' or ../type = 'ipv4_algo' or ../type = 'ipv6_algo'";
|
||||
}
|
||||
leaf local-interface {
|
||||
type uint32;
|
||||
mandatory true;
|
||||
when "../type = 'ipv4_local_iface' or ../type = 'ipv6_local_iface' or ../type = 'ipv4_unnumbered_adjacency'";
|
||||
}
|
||||
leaf remote-address {
|
||||
type inet:ip-address;
|
||||
mandatory true;
|
||||
when "../type = 'ipv4_adjacency' or ../type = 'ipv6_adjacency' or ../type = 'ipv4_unnumbered_adjacency'";
|
||||
}
|
||||
@ -137,6 +157,11 @@ module frr-pathd {
|
||||
mandatory true;
|
||||
when "../type = 'ipv4_unnumbered_adjacency'";
|
||||
}
|
||||
leaf algorithm {
|
||||
type uint8;
|
||||
mandatory true;
|
||||
when "../type = 'ipv4_algo' or ../type = 'ipv6_algo'";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user