summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bgpd/bgp_attr.c5
-rw-r--r--bgpd/bgp_attr_evpn.c10
-rw-r--r--bgpd/bgp_ecommunity.c24
-rw-r--r--bgpd/bgp_ecommunity.h2
-rw-r--r--bgpd/bgp_evpn.c16
-rw-r--r--bgpd/bgp_main.c5
-rw-r--r--bgpd/bgp_mplsvpn.c3
-rw-r--r--bgpd/bgp_pbr.c2
-rw-r--r--bgpd/bgp_routemap.c210
-rw-r--r--bgpd/bgp_script.c192
-rw-r--r--bgpd/bgp_script.h34
-rw-r--r--bgpd/bgp_updgrp_adv.c5
-rw-r--r--bgpd/bgp_vty.c64
-rw-r--r--bgpd/bgpd.c64
-rw-r--r--bgpd/rfapi/rfapi_import.c8
-rw-r--r--bgpd/rfapi/vnc_export_bgp.c2
-rw-r--r--bgpd/subdir.am2
-rwxr-xr-xconfigure.ac37
-rw-r--r--debian/control3
-rwxr-xr-xdebian/rules7
-rw-r--r--doc/developer/library.rst2
-rw-r--r--doc/developer/lua.rst65
-rw-r--r--doc/developer/scripting.rst433
-rw-r--r--doc/developer/subdir.am2
-rw-r--r--doc/user/index.rst1
-rw-r--r--doc/user/installation.rst8
-rw-r--r--doc/user/ospfd.rst17
-rw-r--r--doc/user/scripting.rst28
-rw-r--r--doc/user/subdir.am1
-rw-r--r--eigrpd/eigrp_cli.c1
-rw-r--r--eigrpd/eigrp_cli.h70
-rw-r--r--eigrpd/eigrp_const.h8
-rw-r--r--eigrpd/eigrp_dump.c10
-rw-r--r--eigrpd/eigrp_dump.h10
-rw-r--r--eigrpd/eigrp_fsm.c54
-rw-r--r--eigrpd/eigrp_interface.c53
-rw-r--r--eigrpd/eigrp_interface.h5
-rw-r--r--eigrpd/eigrp_main.c2
-rw-r--r--eigrpd/eigrp_memory.c4
-rw-r--r--eigrpd/eigrp_memory.h4
-rw-r--r--eigrpd/eigrp_metric.c146
-rw-r--r--eigrpd/eigrp_metric.h63
-rw-r--r--eigrpd/eigrp_neighbor.c2
-rw-r--r--eigrpd/eigrp_neighbor.h2
-rw-r--r--eigrpd/eigrp_network.c70
-rw-r--r--eigrpd/eigrp_network.h5
-rw-r--r--eigrpd/eigrp_northbound.c1
-rw-r--r--eigrpd/eigrp_packet.c2
-rw-r--r--eigrpd/eigrp_packet.h178
-rw-r--r--eigrpd/eigrp_query.c12
-rw-r--r--eigrpd/eigrp_reply.c19
-rw-r--r--eigrpd/eigrp_routemap.c4
-rw-r--r--eigrpd/eigrp_siaquery.c10
-rw-r--r--eigrpd/eigrp_siareply.c10
-rw-r--r--eigrpd/eigrp_structs.h50
-rw-r--r--eigrpd/eigrp_topology.c126
-rw-r--r--eigrpd/eigrp_topology.h52
-rw-r--r--eigrpd/eigrp_types.h36
-rw-r--r--eigrpd/eigrp_update.c58
-rw-r--r--eigrpd/eigrp_vty.c24
-rw-r--r--eigrpd/eigrp_yang.h32
-rw-r--r--eigrpd/eigrp_zebra.c4
-rw-r--r--eigrpd/eigrpd.h77
-rw-r--r--eigrpd/subdir.am5
-rw-r--r--ldpd/lde.h2
-rw-r--r--ldpd/lde_lib.c8
-rw-r--r--lib/command.c30
-rw-r--r--lib/compiler.h23
-rw-r--r--lib/frrlua.c387
-rw-r--r--lib/frrlua.h205
-rw-r--r--lib/frrscript.c272
-rw-r--r--lib/frrscript.h138
-rw-r--r--lib/libfrr.c16
-rw-r--r--lib/libfrr.h2
-rw-r--r--lib/northbound_cli.c6
-rw-r--r--lib/subdir.am2
-rw-r--r--lib/zclient.c49
-rw-r--r--lib/zclient.h8
-rw-r--r--ospfd/ospf_ase.c9
-rw-r--r--ospfd/ospf_lsa.c13
-rw-r--r--ospfd/ospf_vty.c72
-rw-r--r--ospfd/ospfd.c99
-rw-r--r--ospfd/ospfd.h5
-rw-r--r--pbrd/pbr_nht.c26
-rw-r--r--staticd/static_nb.c12
-rw-r--r--staticd/static_nb.h10
-rw-r--r--staticd/static_nb_config.c130
-rw-r--r--staticd/static_routes.c4
-rw-r--r--staticd/static_routes.h2
-rw-r--r--staticd/static_vty.c19
-rw-r--r--tests/topotests/all-protocol-startup/test_all_protocol_startup.py4
-rw-r--r--tests/topotests/bfd-bgp-cbit-topo3/test_bfd_bgp_cbit_topo3.py2
-rw-r--r--tests/topotests/bfd-isis-topo1/test_bfd_isis_topo1.py3
-rw-r--r--tests/topotests/bfd-ospf-topo1/__init__.py0
-rw-r--r--tests/topotests/bfd-ospf-topo1/rt1/bfdd.conf9
-rw-r--r--tests/topotests/bfd-ospf-topo1/rt1/ospf6d.conf21
-rw-r--r--tests/topotests/bfd-ospf-topo1/rt1/ospfd.conf26
-rw-r--r--tests/topotests/bfd-ospf-topo1/rt1/step1/show_ip_route.ref74
-rw-r--r--tests/topotests/bfd-ospf-topo1/rt1/step1/show_ipv6_route.ref70
-rw-r--r--tests/topotests/bfd-ospf-topo1/rt1/step2/show_bfd_peers.ref26
-rw-r--r--tests/topotests/bfd-ospf-topo1/rt1/step3/show_bfd_peers_healthy.ref28
-rw-r--r--tests/topotests/bfd-ospf-topo1/rt1/step3/show_bfd_peers_rt2_down.ref15
-rw-r--r--tests/topotests/bfd-ospf-topo1/rt1/step3/show_bfd_peers_rt3_down.ref15
-rw-r--r--tests/topotests/bfd-ospf-topo1/rt1/step3/show_ip_route_healthy.ref74
-rw-r--r--tests/topotests/bfd-ospf-topo1/rt1/step3/show_ip_route_rt2_down.ref74
-rw-r--r--tests/topotests/bfd-ospf-topo1/rt1/step3/show_ip_route_rt3_down.ref74
-rw-r--r--tests/topotests/bfd-ospf-topo1/rt1/step3/show_ipv6_route_healthy.ref70
-rw-r--r--tests/topotests/bfd-ospf-topo1/rt1/step3/show_ipv6_route_rt2_down.ref70
-rw-r--r--tests/topotests/bfd-ospf-topo1/rt1/step3/show_ipv6_route_rt3_down.ref70
-rw-r--r--tests/topotests/bfd-ospf-topo1/rt1/zebra.conf25
-rw-r--r--tests/topotests/bfd-ospf-topo1/rt2/bfdd.conf7
-rw-r--r--tests/topotests/bfd-ospf-topo1/rt2/ospf6d.conf19
-rw-r--r--tests/topotests/bfd-ospf-topo1/rt2/ospfd.conf24
-rw-r--r--tests/topotests/bfd-ospf-topo1/rt2/step2/show_bfd_peers.ref14
-rw-r--r--tests/topotests/bfd-ospf-topo1/rt2/zebra.conf22
-rw-r--r--tests/topotests/bfd-ospf-topo1/rt3/bfdd.conf7
-rw-r--r--tests/topotests/bfd-ospf-topo1/rt3/ospf6d.conf19
-rw-r--r--tests/topotests/bfd-ospf-topo1/rt3/ospfd.conf24
-rw-r--r--tests/topotests/bfd-ospf-topo1/rt3/step2/show_bfd_peers.ref14
-rw-r--r--tests/topotests/bfd-ospf-topo1/rt3/zebra.conf22
-rw-r--r--tests/topotests/bfd-ospf-topo1/rt4/bfdd.conf5
-rw-r--r--tests/topotests/bfd-ospf-topo1/rt4/ospf6d.conf18
-rw-r--r--tests/topotests/bfd-ospf-topo1/rt4/ospfd.conf23
-rw-r--r--tests/topotests/bfd-ospf-topo1/rt4/zebra.conf22
-rw-r--r--tests/topotests/bfd-ospf-topo1/rt5/bfdd.conf5
-rw-r--r--tests/topotests/bfd-ospf-topo1/rt5/ospf6d.conf18
-rw-r--r--tests/topotests/bfd-ospf-topo1/rt5/ospfd.conf23
-rw-r--r--tests/topotests/bfd-ospf-topo1/rt5/zebra.conf22
-rwxr-xr-xtests/topotests/bfd-ospf-topo1/test_bfd_ospf_topo1.py307
-rw-r--r--tests/topotests/bfd-profiles-topo1/test_bfd_profiles_topo1.py3
-rw-r--r--tests/topotests/bfd-topo1/test_bfd_topo1.py2
-rw-r--r--tests/topotests/bfd-topo2/test_bfd_topo2.py2
-rw-r--r--tests/topotests/bfd-vrf-topo1/test_bfd_vrf_topo1.py2
-rw-r--r--tests/topotests/bgp-evpn-mh/test_evpn_mh.py2
-rw-r--r--tests/topotests/bgp_peer-group/__init__.py0
-rw-r--r--tests/topotests/bgp_peer-group/r1/bgpd.conf8
-rw-r--r--tests/topotests/bgp_peer-group/r1/zebra.conf6
-rw-r--r--tests/topotests/bgp_peer-group/r2/bgpd.conf7
-rw-r--r--tests/topotests/bgp_peer-group/r2/zebra.conf6
-rw-r--r--tests/topotests/bgp_peer-group/r3/bgpd.conf7
-rw-r--r--tests/topotests/bgp_peer-group/r3/zebra.conf6
-rw-r--r--tests/topotests/bgp_peer-group/test_bgp_peer-group.py99
-rw-r--r--tests/topotests/eigrp-topo1/test_eigrp_topo1.py2
-rw-r--r--tests/topotests/evpn-pim-1/test_evpn_pim_topo1.py2
-rwxr-xr-xtests/topotests/isis-lfa-topo1/test_isis_lfa_topo1.py2
-rwxr-xr-xtests/topotests/isis-rlfa-topo1/test_isis_rlfa_topo1.py2
-rwxr-xr-xtests/topotests/isis-sr-te-topo1/test_isis_sr_te_topo1.py1
-rw-r--r--tests/topotests/isis-sr-topo1/test_isis_sr_topo1.py2
-rwxr-xr-xtests/topotests/isis-tilfa-topo1/test_isis_tilfa_topo1.py2
-rw-r--r--tests/topotests/isis-topo1-vrf/test_isis_topo1_vrf.py2
-rw-r--r--tests/topotests/isis-topo1/test_isis_topo1.py2
-rw-r--r--tests/topotests/ldp-topo1/test_ldp_topo1.py2
-rw-r--r--tests/topotests/ldp-vpls-topo1/test_ldp_vpls_topo1.py3
-rw-r--r--tests/topotests/lib/bgp.py4
-rw-r--r--tests/topotests/lib/common_config.py16
-rw-r--r--tests/topotests/lib/ospf.py45
-rw-r--r--tests/topotests/ospf_basic_functionality/test_ospf_ecmp.py45
-rw-r--r--tests/topotests/ospf_basic_functionality/test_ospf_ecmp_lan.py39
-rw-r--r--tests/topotests/ospf_basic_functionality/test_ospf_lan.py36
-rw-r--r--tests/topotests/ospf_basic_functionality/test_ospf_nssa.py35
-rw-r--r--tests/topotests/ospf_basic_functionality/test_ospf_routemaps.py53
-rw-r--r--tests/topotests/ospf_basic_functionality/test_ospf_rte_calc.py49
-rw-r--r--tests/topotests/pbr-topo1/test_pbr_topo1.py2
-rw-r--r--tests/topotests/pim-basic/test_pim.py2
-rw-r--r--tests/topotests/pytest.ini10
-rw-r--r--tests/topotests/rip-topo1/test_rip_topo1.py2
-rw-r--r--tests/topotests/ripng-topo1/test_ripng_topo1.py2
-rwxr-xr-xtools/frr-reload.py114
-rw-r--r--yang/frr-staticd.yang15
-rw-r--r--zebra/dplane_fpm_nl.c8
-rw-r--r--zebra/zebra_evpn_mac.c311
-rw-r--r--zebra/zebra_evpn_mac.h1
-rw-r--r--zebra/zebra_fpm.c22
-rw-r--r--zebra/zebra_fpm_netlink.c10
-rw-r--r--zebra/zebra_rib.c52
175 files changed, 4946 insertions, 1474 deletions
diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c
index ce22e8404d..c25d0e269a 100644
--- a/bgpd/bgp_attr.c
+++ b/bgpd/bgp_attr.c
@@ -3395,7 +3395,8 @@ void bgp_attr_extcom_tunnel_type(struct attr *attr,
bgp_encap_types *tunnel_type)
{
struct ecommunity *ecom;
- int i;
+ uint32_t i;
+
if (!attr)
return;
@@ -4021,7 +4022,7 @@ bgp_size_t bgp_packet_attribute(struct bgp *bgp, struct peer *peer,
uint8_t *pnt;
int tbit;
int ecom_tr_size = 0;
- int i;
+ uint32_t i;
for (i = 0; i < attr->ecommunity->size; i++) {
pnt = attr->ecommunity->val + (i * 8);
diff --git a/bgpd/bgp_attr_evpn.c b/bgpd/bgp_attr_evpn.c
index 7cc9ecd79e..1df646c346 100644
--- a/bgpd/bgp_attr_evpn.c
+++ b/bgpd/bgp_attr_evpn.c
@@ -89,7 +89,7 @@ char *ecom_mac2str(char *ecom_mac)
/* Fetch router-mac from extended community */
bool bgp_attr_rmac(struct attr *attr, struct ethaddr *rmac)
{
- int i = 0;
+ uint32_t i = 0;
struct ecommunity *ecom;
ecom = attr->ecommunity;
@@ -122,7 +122,7 @@ bool bgp_attr_rmac(struct attr *attr, struct ethaddr *rmac)
uint8_t bgp_attr_default_gw(struct attr *attr)
{
struct ecommunity *ecom;
- int i;
+ uint32_t i;
ecom = attr->ecommunity;
if (!ecom || !ecom->size)
@@ -153,7 +153,7 @@ uint8_t bgp_attr_default_gw(struct attr *attr)
uint16_t bgp_attr_df_pref_from_ec(struct attr *attr, uint8_t *alg)
{
struct ecommunity *ecom;
- int i;
+ uint32_t i;
uint16_t df_pref = 0;
*alg = EVPN_MH_DF_ALG_SERVICE_CARVING;
@@ -190,7 +190,7 @@ uint16_t bgp_attr_df_pref_from_ec(struct attr *attr, uint8_t *alg)
uint32_t bgp_attr_mac_mobility_seqnum(struct attr *attr, uint8_t *sticky)
{
struct ecommunity *ecom;
- int i;
+ uint32_t i;
uint8_t flags = 0;
ecom = attr->ecommunity;
@@ -237,7 +237,7 @@ void bgp_attr_evpn_na_flag(struct attr *attr,
uint8_t *router_flag, bool *proxy)
{
struct ecommunity *ecom;
- int i;
+ uint32_t i;
uint8_t val;
ecom = attr->ecommunity;
diff --git a/bgpd/bgp_ecommunity.c b/bgpd/bgp_ecommunity.c
index 43bfb3e2bc..c358d4203e 100644
--- a/bgpd/bgp_ecommunity.c
+++ b/bgpd/bgp_ecommunity.c
@@ -95,7 +95,7 @@ static bool ecommunity_add_val_internal(struct ecommunity *ecom,
bool unique, bool overwrite,
uint8_t ecom_size)
{
- int c, ins_idx;
+ uint32_t c, ins_idx;
const struct ecommunity_val *eval4 = (struct ecommunity_val *)eval;
const struct ecommunity_val_ipv6 *eval6 =
(struct ecommunity_val_ipv6 *)eval;
@@ -113,7 +113,7 @@ static bool ecommunity_add_val_internal(struct ecommunity *ecom,
/* check also if the extended community itself exists. */
c = 0;
- ins_idx = -1;
+ ins_idx = UINT32_MAX;
for (uint8_t *p = ecom->val; c < ecom->size;
p += ecom_size, c++) {
if (unique) {
@@ -145,12 +145,12 @@ static bool ecommunity_add_val_internal(struct ecommunity *ecom,
if (ret > 0) {
if (!unique)
break;
- if (ins_idx == -1)
+ if (ins_idx == UINT32_MAX)
ins_idx = c;
}
}
- if (ins_idx == -1)
+ if (ins_idx == UINT32_MAX)
ins_idx = c;
/* Add the value to the structure with numerical sorting. */
@@ -193,7 +193,7 @@ static struct ecommunity *
ecommunity_uniq_sort_internal(struct ecommunity *ecom,
unsigned short ecom_size)
{
- int i;
+ uint32_t i;
struct ecommunity *new;
const void *eval;
@@ -895,7 +895,7 @@ static int ecommunity_lb_str(char *buf, size_t bufsz, const uint8_t *pnt)
*/
char *ecommunity_ecom2str(struct ecommunity *ecom, int format, int filter)
{
- int i;
+ uint32_t i;
uint8_t *pnt;
uint8_t type = 0;
uint8_t sub_type = 0;
@@ -1176,8 +1176,8 @@ char *ecommunity_ecom2str(struct ecommunity *ecom, int format, int filter)
bool ecommunity_match(const struct ecommunity *ecom1,
const struct ecommunity *ecom2)
{
- int i = 0;
- int j = 0;
+ uint32_t i = 0;
+ uint32_t j = 0;
if (ecom1 == NULL && ecom2 == NULL)
return true;
@@ -1209,7 +1209,7 @@ extern struct ecommunity_val *ecommunity_lookup(const struct ecommunity *ecom,
uint8_t type, uint8_t subtype)
{
uint8_t *p;
- int c;
+ uint32_t c;
/* If the value already exists in the structure return 0. */
c = 0;
@@ -1230,7 +1230,7 @@ bool ecommunity_strip(struct ecommunity *ecom, uint8_t type,
uint8_t subtype)
{
uint8_t *p, *q, *new;
- int c, found = 0;
+ uint32_t c, found = 0;
/* When this is fist value, just add it. */
if (ecom == NULL || ecom->val == NULL)
return false;
@@ -1278,7 +1278,7 @@ bool ecommunity_strip(struct ecommunity *ecom, uint8_t type,
bool ecommunity_del_val(struct ecommunity *ecom, struct ecommunity_val *eval)
{
uint8_t *p;
- int c, found = 0;
+ uint32_t c, found = 0;
/* Make sure specified value exists. */
if (ecom == NULL || ecom->val == NULL)
@@ -1512,7 +1512,7 @@ void bgp_remove_ecomm_from_aggregate_hash(struct bgp_aggregate *aggregate,
const uint8_t *ecommunity_linkbw_present(struct ecommunity *ecom, uint32_t *bw)
{
const uint8_t *eval;
- int i;
+ uint32_t i;
if (bw)
*bw = 0;
diff --git a/bgpd/bgp_ecommunity.h b/bgpd/bgp_ecommunity.h
index 6318e7edb1..6d0275a0c3 100644
--- a/bgpd/bgp_ecommunity.h
+++ b/bgpd/bgp_ecommunity.h
@@ -114,7 +114,7 @@ struct ecommunity {
uint8_t unit_size;
/* Size of Extended Communities attribute. */
- int size;
+ uint32_t size;
/* Extended Communities value. */
uint8_t *val;
diff --git a/bgpd/bgp_evpn.c b/bgpd/bgp_evpn.c
index 96f4b0aa78..88747b14b1 100644
--- a/bgpd/bgp_evpn.c
+++ b/bgpd/bgp_evpn.c
@@ -870,7 +870,7 @@ static void add_mac_mobility_to_attr(uint32_t seq_num, struct attr *attr)
struct ecommunity ecom_tmp;
struct ecommunity_val eval;
uint8_t *ecom_val_ptr;
- int i;
+ uint32_t i;
uint8_t *pnt;
int type = 0;
int sub_type = 0;
@@ -2710,7 +2710,7 @@ static int is_route_matching_for_vrf(struct bgp *bgp_vrf,
{
struct attr *attr = pi->attr;
struct ecommunity *ecom;
- int i;
+ uint32_t i;
assert(attr);
/* Route should have valid RT to be even considered. */
@@ -2777,7 +2777,7 @@ static int is_route_matching_for_vni(struct bgp *bgp, struct bgpevpn *vpn,
{
struct attr *attr = pi->attr;
struct ecommunity *ecom;
- int i;
+ uint32_t i;
assert(attr);
/* Route should have valid RT to be even considered. */
@@ -3260,7 +3260,7 @@ static int bgp_evpn_install_uninstall_table(struct bgp *bgp, afi_t afi,
struct prefix_evpn *evp = (struct prefix_evpn *)p;
struct attr *attr = pi->attr;
struct ecommunity *ecom;
- int i;
+ uint32_t i;
struct prefix_evpn ad_evp;
assert(attr);
@@ -4906,7 +4906,7 @@ int bgp_nlri_parse_evpn(struct peer *peer, struct attr *attr,
*/
void bgp_evpn_map_vrf_to_its_rts(struct bgp *bgp_vrf)
{
- int i = 0;
+ uint32_t i = 0;
struct ecommunity_val *eval = NULL;
struct listnode *node = NULL, *nnode = NULL;
struct ecommunity *ecom = NULL;
@@ -4926,7 +4926,7 @@ void bgp_evpn_map_vrf_to_its_rts(struct bgp *bgp_vrf)
*/
void bgp_evpn_unmap_vrf_from_its_rts(struct bgp *bgp_vrf)
{
- int i;
+ uint32_t i;
struct ecommunity_val *eval;
struct listnode *node, *nnode;
struct ecommunity *ecom;
@@ -4963,7 +4963,7 @@ void bgp_evpn_unmap_vrf_from_its_rts(struct bgp *bgp_vrf)
*/
void bgp_evpn_map_vni_to_its_rts(struct bgp *bgp, struct bgpevpn *vpn)
{
- int i;
+ uint32_t i;
struct ecommunity_val *eval;
struct listnode *node, *nnode;
struct ecommunity *ecom;
@@ -4983,7 +4983,7 @@ void bgp_evpn_map_vni_to_its_rts(struct bgp *bgp, struct bgpevpn *vpn)
*/
void bgp_evpn_unmap_vni_from_its_rts(struct bgp *bgp, struct bgpevpn *vpn)
{
- int i;
+ uint32_t i;
struct ecommunity_val *eval;
struct listnode *node, *nnode;
struct ecommunity *ecom;
diff --git a/bgpd/bgp_main.c b/bgpd/bgp_main.c
index 287555b1fc..3cb3d06217 100644
--- a/bgpd/bgp_main.c
+++ b/bgpd/bgp_main.c
@@ -60,6 +60,7 @@
#include "bgpd/bgp_keepalives.h"
#include "bgpd/bgp_network.h"
#include "bgpd/bgp_errors.h"
+#include "bgpd/bgp_script.h"
#include "lib/routing_nb.h"
#include "bgpd/bgp_nb.h"
#include "bgpd/bgp_evpn_mh.h"
@@ -510,6 +511,10 @@ int main(int argc, char **argv)
/* Initializations. */
bgp_vrf_init();
+#ifdef HAVE_SCRIPTING
+ bgp_script_init();
+#endif
+
hook_register(routing_conf_event,
routing_control_plane_protocols_name_validate);
diff --git a/bgpd/bgp_mplsvpn.c b/bgpd/bgp_mplsvpn.c
index 3bc4c03233..1d66d75288 100644
--- a/bgpd/bgp_mplsvpn.c
+++ b/bgpd/bgp_mplsvpn.c
@@ -419,8 +419,7 @@ int vpn_leak_label_callback(
static bool ecom_intersect(struct ecommunity *e1, struct ecommunity *e2)
{
- int i;
- int j;
+ uint32_t i, j;
if (!e1 || !e2)
return false;
diff --git a/bgpd/bgp_pbr.c b/bgpd/bgp_pbr.c
index a3f1eb8401..4f22f5bcfe 100644
--- a/bgpd/bgp_pbr.c
+++ b/bgpd/bgp_pbr.c
@@ -754,7 +754,7 @@ int bgp_pbr_build_and_validate_entry(const struct prefix *p,
struct bgp_pbr_entry_main *api)
{
int ret;
- int i, action_count = 0;
+ uint32_t i, action_count = 0;
struct ecommunity *ecom;
struct ecommunity_val *ecom_eval;
struct bgp_pbr_entry_action *api_action;
diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c
index 0f4f26e3ee..ceaf8c0963 100644
--- a/bgpd/bgp_routemap.c
+++ b/bgpd/bgp_routemap.c
@@ -65,6 +65,7 @@
#include "bgpd/bgp_flowspec_util.h"
#include "bgpd/bgp_encap_types.h"
#include "bgpd/bgp_mpath.h"
+#include "bgpd/bgp_script.h"
#ifdef ENABLE_BGP_VNC
#include "bgpd/rfapi/bgp_rfapi_cfg.h"
@@ -337,99 +338,138 @@ static const struct route_map_rule_cmd route_match_peer_cmd = {
route_match_peer_free
};
-#if defined(HAVE_LUA)
-static enum route_map_cmd_result_t
-route_match_command(void *rule, const struct prefix *prefix, void *object)
-{
- int status = RMAP_NOMATCH;
- u_int32_t locpref = 0;
- u_int32_t newlocpref = 0;
- enum lua_rm_status lrm_status;
- struct bgp_path_info *path = (struct bgp_path_info *)object;
- lua_State *L = lua_initialize("/etc/frr/lua.scr");
-
- if (L == NULL)
- return status;
+#ifdef HAVE_SCRIPTING
+enum frrlua_rm_status {
/*
- * Setup the prefix information to pass in
+ * Script function run failure. This will translate into a deny
*/
- lua_setup_prefix_table(L, prefix);
-
- zlog_debug("Set up prefix table");
+ LUA_RM_FAILURE = 0,
/*
- * Setup the bgp_path_info information
+ * No Match was found for the route map function
*/
- lua_newtable(L);
- lua_pushinteger(L, path->attr->med);
- lua_setfield(L, -2, "metric");
- lua_pushinteger(L, path->attr->nh_ifindex);
- lua_setfield(L, -2, "ifindex");
- lua_pushstring(L, path->attr->aspath->str);
- lua_setfield(L, -2, "aspath");
- lua_pushinteger(L, path->attr->local_pref);
- lua_setfield(L, -2, "localpref");
- zlog_debug("%s %d", path->attr->aspath->str, path->attr->nh_ifindex);
- lua_setglobal(L, "nexthop");
-
- zlog_debug("Set up nexthop information");
+ LUA_RM_NOMATCH,
/*
- * Run the rule
+ * Match was found but no changes were made to the incoming data.
*/
- lrm_status = lua_run_rm_rule(L, rule);
- switch (lrm_status) {
+ LUA_RM_MATCH,
+ /*
+ * Match was found and data was modified, so figure out what changed
+ */
+ LUA_RM_MATCH_AND_CHANGE,
+};
+
+static enum route_map_cmd_result_t
+route_match_script(void *rule, const struct prefix *prefix, void *object)
+{
+ const char *scriptname = rule;
+ struct bgp_path_info *path = (struct bgp_path_info *)object;
+
+ struct frrscript *fs = frrscript_load(scriptname, NULL);
+
+ if (!fs) {
+ zlog_err("Issue loading script rule; defaulting to no match");
+ return RMAP_NOMATCH;
+ }
+
+ enum frrlua_rm_status status_failure = LUA_RM_FAILURE,
+ status_nomatch = LUA_RM_NOMATCH,
+ status_match = LUA_RM_MATCH,
+ status_match_and_change = LUA_RM_MATCH_AND_CHANGE;
+
+ /* Make result values available */
+ struct frrscript_env env[] = {
+ {"integer", "RM_FAILURE", &status_failure},
+ {"integer", "RM_NOMATCH", &status_nomatch},
+ {"integer", "RM_MATCH", &status_match},
+ {"integer", "RM_MATCH_AND_CHANGE", &status_match_and_change},
+ {"integer", "action", &status_failure},
+ {"prefix", "prefix", prefix},
+ {"attr", "attributes", path->attr},
+ {"peer", "peer", path->peer},
+ {}};
+
+ struct frrscript_env results[] = {
+ {"integer", "action"},
+ {"attr", "attributes"},
+ {},
+ };
+
+ int result = frrscript_call(fs, env);
+
+ if (result) {
+ zlog_err("Issue running script rule; defaulting to no match");
+ return RMAP_NOMATCH;
+ }
+
+ enum frrlua_rm_status *lrm_status =
+ frrscript_get_result(fs, &results[0]);
+
+ int status = RMAP_NOMATCH;
+
+ switch (*lrm_status) {
case LUA_RM_FAILURE:
- zlog_debug("RM_FAILURE");
+ zlog_err(
+ "Executing route-map match script '%s' failed; defaulting to no match",
+ scriptname);
+ status = RMAP_NOMATCH;
break;
case LUA_RM_NOMATCH:
- zlog_debug("RM_NOMATCH");
+ status = RMAP_NOMATCH;
break;
case LUA_RM_MATCH_AND_CHANGE:
- zlog_debug("MATCH AND CHANGE");
- lua_getglobal(L, "nexthop");
- path->attr->med = get_integer(L, "metric");
- /*
- * This needs to be abstraced with the set function
- */
+ status = RMAP_MATCH;
+ zlog_debug("Updating attribute based on script's values");
+
+ uint32_t locpref = 0;
+ struct attr *newattr = frrscript_get_result(fs, &results[1]);
+
+ path->attr->med = newattr->med;
+
if (path->attr->flag & ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF))
locpref = path->attr->local_pref;
- newlocpref = get_integer(L, "localpref");
- if (newlocpref != locpref) {
- path->attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF);
- path->attr->local_pref = newlocpref;
+ if (locpref != newattr->local_pref) {
+ SET_FLAG(path->attr->flag,
+ ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF));
+ path->attr->local_pref = newattr->local_pref;
}
- status = RMAP_MATCH;
+
+ aspath_free(newattr->aspath);
+ XFREE(MTYPE_TMP, newattr);
break;
case LUA_RM_MATCH:
- zlog_debug("MATCH ONLY");
status = RMAP_MATCH;
break;
}
- lua_close(L);
+
+ XFREE(MTYPE_TMP, lrm_status);
+ frrscript_unload(fs);
+
return status;
}
-static void *route_match_command_compile(const char *arg)
+static void *route_match_script_compile(const char *arg)
{
- char *command;
+ char *scriptname;
+
+ scriptname = XSTRDUP(MTYPE_ROUTE_MAP_COMPILED, arg);
- command = XSTRDUP(MTYPE_ROUTE_MAP_COMPILED, arg);
- return command;
+ return scriptname;
}
-static void
-route_match_command_free(void *rule)
+static void route_match_script_free(void *rule)
{
XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
}
-static const struct route_map_rule_cmd route_match_command_cmd = {
- "command",
- route_match_command,
- route_match_command_compile,
- route_match_command_free
+static const struct route_map_rule_cmd route_match_script_cmd = {
+ "script",
+ route_match_script,
+ route_match_script_compile,
+ route_match_script_free
};
-#endif
+
+#endif /* HAVE_SCRIPTING */
/* `match ip address IP_ACCESS_LIST' */
@@ -4096,30 +4136,29 @@ DEFUN (no_match_peer,
RMAP_EVENT_MATCH_DELETED);
}
-#if defined(HAVE_LUA)
-DEFUN (match_command,
- match_command_cmd,
- "match command WORD",
- MATCH_STR
- "Run a command to match\n"
- "The command to run\n")
-{
- return bgp_route_match_add(vty, "command", argv[2]->arg,
- RMAP_EVENT_FILTER_ADDED);
-}
-
-DEFUN (no_match_command,
- no_match_command_cmd,
- "no match command WORD",
+#ifdef HAVE_SCRIPTING
+DEFUN (match_script,
+ match_script_cmd,
+ "[no] match script WORD",
NO_STR
MATCH_STR
- "Run a command to match\n"
- "The command to run\n")
+ "Execute script to determine match\n"
+ "The script name to run, without .lua; e.g. 'myroutemap' to run myroutemap.lua\n")
{
- return bgp_route_match_delete(vty, "command", argv[3]->arg,
- RMAP_EVENT_FILTER_DELETED);
+ bool no = strmatch(argv[0]->text, "no");
+ int i = 0;
+ argv_find(argv, argc, "WORD", &i);
+ const char *script = argv[i]->arg;
+
+ if (no) {
+ return bgp_route_match_delete(vty, "script", script,
+ RMAP_EVENT_FILTER_DELETED);
+ } else {
+ return bgp_route_match_add(vty, "script", script,
+ RMAP_EVENT_FILTER_ADDED);
+ }
}
-#endif
+#endif /* HAVE_SCRIPTING */
/* match probability */
DEFUN (match_probability,
@@ -5633,8 +5672,8 @@ void bgp_route_map_init(void)
route_map_install_match(&route_match_peer_cmd);
route_map_install_match(&route_match_local_pref_cmd);
-#if defined(HAVE_LUA)
- route_map_install_match(&route_match_command_cmd);
+#ifdef HAVE_SCRIPTING
+ route_map_install_match(&route_match_script_cmd);
#endif
route_map_install_match(&route_match_ip_address_cmd);
route_map_install_match(&route_match_ip_next_hop_cmd);
@@ -5798,9 +5837,8 @@ void bgp_route_map_init(void)
install_element(RMAP_NODE, &no_set_ipv6_nexthop_prefer_global_cmd);
install_element(RMAP_NODE, &set_ipv6_nexthop_peer_cmd);
install_element(RMAP_NODE, &no_set_ipv6_nexthop_peer_cmd);
-#if defined(HAVE_LUA)
- install_element(RMAP_NODE, &match_command_cmd);
- install_element(RMAP_NODE, &no_match_command_cmd);
+#ifdef HAVE_SCRIPTING
+ install_element(RMAP_NODE, &match_script_cmd);
#endif
}
diff --git a/bgpd/bgp_script.c b/bgpd/bgp_script.c
new file mode 100644
index 0000000000..0cda1927f8
--- /dev/null
+++ b/bgpd/bgp_script.c
@@ -0,0 +1,192 @@
+/* BGP scripting foo
+ * Copyright (C) 2020 NVIDIA Corporation
+ * Quentin Young
+ *
+ * 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 General Public License
+ * along with this program; see the file COPYING; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ * MA 02110-1301 USA
+ */
+
+#include <zebra.h>
+
+#ifdef HAVE_SCRIPTING
+
+#include "bgpd.h"
+#include "bgp_script.h"
+#include "bgp_debug.h"
+#include "bgp_aspath.h"
+#include "frratomic.h"
+#include "frrscript.h"
+#include "frrlua.h"
+
+static void lua_pushpeer(lua_State *L, const struct peer *peer)
+{
+ lua_newtable(L);
+ lua_pushinteger(L, peer->as);
+ lua_setfield(L, -2, "remote_as");
+ lua_pushinteger(L, peer->local_as);
+ lua_setfield(L, -2, "local_as");
+ lua_pushinaddr(L, &peer->remote_id);
+ lua_setfield(L, -2, "remote_id");
+ lua_pushinaddr(L, &peer->local_id);
+ lua_setfield(L, -2, "local_id");
+ lua_pushstring(L, lookup_msg(bgp_status_msg, peer->status, NULL));
+ lua_setfield(L, -2, "state");
+ lua_pushstring(L, peer->desc ? peer->desc : "");
+ lua_setfield(L, -2, "description");
+ lua_pushtimet(L, &peer->uptime);
+ lua_setfield(L, -2, "uptime");
+ lua_pushtimet(L, &peer->readtime);
+ lua_setfield(L, -2, "last_readtime");
+ lua_pushtimet(L, &peer->resettime);
+ lua_setfield(L, -2, "last_resettime");
+ lua_pushsockunion(L, peer->su_local);
+ lua_setfield(L, -2, "local_address");
+ lua_pushsockunion(L, peer->su_remote);
+ lua_setfield(L, -2, "remote_address");
+ lua_pushinteger(L, peer->cap);
+ lua_setfield(L, -2, "capabilities");
+ lua_pushinteger(L, peer->flags);
+ lua_setfield(L, -2, "flags");
+ lua_pushstring(L, peer->password ? peer->password : "");
+ lua_setfield(L, -2, "password");
+
+ /* Nested tables here */
+ lua_newtable(L);
+ {
+ lua_newtable(L);
+ {
+ lua_pushinteger(L, peer->holdtime);
+ lua_setfield(L, -2, "hold");
+ lua_pushinteger(L, peer->keepalive);
+ lua_setfield(L, -2, "keepalive");
+ lua_pushinteger(L, peer->connect);
+ lua_setfield(L, -2, "connect");
+ lua_pushinteger(L, peer->routeadv);
+ lua_setfield(L, -2, "route_advertisement");
+ }
+ lua_setfield(L, -2, "configured");
+
+ lua_newtable(L);
+ {
+ lua_pushinteger(L, peer->v_holdtime);
+ lua_setfield(L, -2, "hold");
+ lua_pushinteger(L, peer->v_keepalive);
+ lua_setfield(L, -2, "keepalive");
+ lua_pushinteger(L, peer->v_connect);
+ lua_setfield(L, -2, "connect");
+ lua_pushinteger(L, peer->v_routeadv);
+ lua_setfield(L, -2, "route_advertisement");
+ }
+ lua_setfield(L, -2, "negotiated");
+ }
+ lua_setfield(L, -2, "timers");
+
+ lua_newtable(L);
+ {
+ lua_pushinteger(L, atomic_load_explicit(&peer->open_in,
+ memory_order_relaxed));
+ lua_setfield(L, -2, "open_in");
+ lua_pushinteger(L, atomic_load_explicit(&peer->open_out,
+ memory_order_relaxed));
+ lua_setfield(L, -2, "open_out");
+ lua_pushinteger(L, atomic_load_explicit(&peer->update_in,
+ memory_order_relaxed));
+ lua_setfield(L, -2, "update_in");
+ lua_pushinteger(L, atomic_load_explicit(&peer->update_out,
+ memory_order_relaxed));
+ lua_setfield(L, -2, "update_out");
+ lua_pushinteger(L, atomic_load_explicit(&peer->update_time,
+ memory_order_relaxed));
+ lua_setfield(L, -2, "update_time");
+ lua_pushinteger(L, atomic_load_explicit(&peer->keepalive_in,
+ memory_order_relaxed));
+ lua_setfield(L, -2, "keepalive_in");
+ lua_pushinteger(L, atomic_load_explicit(&peer->keepalive_out,
+ memory_order_relaxed));
+ lua_setfield(L, -2, "keepalive_out");
+ lua_pushinteger(L, atomic_load_explicit(&peer->notify_in,
+ memory_order_relaxed));
+ lua_setfield(L, -2, "notify_in");
+ lua_pushinteger(L, atomic_load_explicit(&peer->notify_out,
+ memory_order_relaxed));
+ lua_setfield(L, -2, "notify_out");
+ lua_pushinteger(L, atomic_load_explicit(&peer->refresh_in,
+ memory_order_relaxed));
+ lua_setfield(L, -2, "refresh_in");
+ lua_pushinteger(L, atomic_load_explicit(&peer->refresh_out,
+ memory_order_relaxed));
+ lua_setfield(L, -2, "refresh_out");
+ lua_pushinteger(L, atomic_load_explicit(&peer->dynamic_cap_in,
+ memory_order_relaxed));
+ lua_setfield(L, -2, "dynamic_cap_in");
+ lua_pushinteger(L, atomic_load_explicit(&peer->dynamic_cap_out,
+ memory_order_relaxed));
+ lua_setfield(L, -2, "dynamic_cap_out");
+ lua_pushinteger(L, peer->established);
+ lua_setfield(L, -2, "times_established");
+ lua_pushinteger(L, peer->dropped);
+ lua_setfield(L, -2, "times_dropped");
+ }
+ lua_setfield(L, -2, "stats");
+}
+
+static void lua_pushattr(lua_State *L, const struct attr *attr)
+{
+ lua_newtable(L);
+ lua_pushinteger(L, attr->med);
+ lua_setfield(L, -2, "metric");
+ lua_pushinteger(L, attr->nh_ifindex);
+ lua_setfield(L, -2, "ifindex");
+ lua_pushstring(L, attr->aspath->str);
+ lua_setfield(L, -2, "aspath");
+ lua_pushinteger(L, attr->local_pref);
+ lua_setfield(L, -2, "localpref");
+}
+
+static void *lua_toattr(lua_State *L, int idx)
+{
+ struct attr *attr = XCALLOC(MTYPE_TMP, sizeof(struct attr));
+
+ lua_getfield(L, -1, "metric");
+ attr->med = lua_tointeger(L, -1);
+ lua_pop(L, 1);
+ lua_getfield(L, -1, "ifindex");
+ attr->nh_ifindex = lua_tointeger(L, -1);
+ lua_pop(L, 1);
+ lua_getfield(L, -1, "aspath");
+ attr->aspath = aspath_str2aspath(lua_tostring(L, -1));
+ lua_pop(L, 1);
+ lua_getfield(L, -1, "localpref");
+ attr->local_pref = lua_tointeger(L, -1);
+ lua_pop(L, 1);
+
+ return attr;
+}
+
+struct frrscript_codec frrscript_codecs_bgpd[] = {
+ {.typename = "peer",
+ .encoder = (encoder_func)lua_pushpeer,
+ .decoder = NULL},
+ {.typename = "attr",
+ .encoder = (encoder_func)lua_pushattr,
+ .decoder = lua_toattr},
+ {}};
+
+void bgp_script_init(void)
+{
+ frrscript_register_type_codecs(frrscript_codecs_bgpd);
+}
+
+#endif /* HAVE_SCRIPTING */
diff --git a/bgpd/bgp_script.h b/bgpd/bgp_script.h
new file mode 100644
index 0000000000..6682c2eebd
--- /dev/null
+++ b/bgpd/bgp_script.h
@@ -0,0 +1,34 @@
+/* BGP scripting foo
+ * Copyright (C) 2020 NVIDIA Corporation
+ * Quentin Young
+ *
+ * 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 General Public License
+ * along with this program; see the file COPYING; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ * MA 02110-1301 USA
+ */
+#ifndef __BGP_SCRIPT__
+#define __BGP_SCRIPT__
+
+#include <zebra.h>
+
+#ifdef HAVE_SCRIPTING
+
+/*
+ * Initialize scripting stuff.
+ */
+void bgp_script_init(void);
+
+#endif /* HAVE_SCRIPTING */
+
+#endif /* __BGP_SCRIPT__ */
diff --git a/bgpd/bgp_updgrp_adv.c b/bgpd/bgp_updgrp_adv.c
index b1ff9ac251..30babb7b76 100644
--- a/bgpd/bgp_updgrp_adv.c
+++ b/bgpd/bgp_updgrp_adv.c
@@ -518,10 +518,7 @@ void bgp_adj_out_set_subgroup(struct bgp_dest *dest,
/* bgp_path_info adj_out reference */
adv->pathi = bgp_path_info_lock(path);
- if (attr)
- adv->baa = bgp_advertise_intern(subgrp->hash, attr);
- else
- adv->baa = baa_new();
+ adv->baa = bgp_advertise_intern(subgrp->hash, attr);
adv->adj = adj;
adj->attr_hash = attr_hash;
diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c
index 114a00cc36..e5f1b78b66 100644
--- a/bgpd/bgp_vty.c
+++ b/bgpd/bgp_vty.c
@@ -4952,27 +4952,63 @@ ALIAS_HIDDEN(no_neighbor_activate, no_neighbor_activate_hidden_cmd,
NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR2
"Enable the Address Family for this Neighbor\n")
-DEFUN_YANG (neighbor_set_peer_group,
- neighbor_set_peer_group_cmd,
- "neighbor <A.B.C.D|X:X::X:X|WORD> peer-group PGNAME",
- NEIGHBOR_STR
- NEIGHBOR_ADDR_STR2
- "Member of the peer-group\n"
- "Peer-group name\n")
+DEFUN (neighbor_set_peer_group,
+ neighbor_set_peer_group_cmd,
+ "neighbor <A.B.C.D|X:X::X:X|WORD> peer-group PGNAME",
+ NEIGHBOR_STR
+ NEIGHBOR_ADDR_STR2
+ "Member of the peer-group\n"
+ "Peer-group name\n")
{
+ VTY_DECLVAR_CONTEXT(bgp, bgp);
int idx_peer = 1;
int idx_word = 3;
- char base_xpath[XPATH_MAXLEN];
+ int ret;
+ as_t as;
+ union sockunion su;
+ struct peer *peer;
+ struct peer_group *group;
- if (peer_and_group_lookup_nb(vty, argv[idx_peer]->arg, base_xpath,
- sizeof(base_xpath), NULL)
- < 0)
+ ret = str2sockunion(argv[idx_peer]->arg, &su);
+ if (ret < 0) {
+ peer = peer_lookup_by_conf_if(bgp, argv[idx_peer]->arg);
+ if (!peer) {
+ vty_out(vty, "%% Malformed address or name: %s\n",
+ argv[idx_peer]->arg);
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+ } else {
+ if (peer_address_self_check(bgp, &su)) {
+ vty_out(vty,
+ "%% Can not configure the local system as neighbor\n");
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+
+ /* Disallow for dynamic neighbor. */
+ peer = peer_lookup(bgp, &su);
+ if (peer && peer_dynamic_neighbor(peer)) {
+ vty_out(vty,
+ "%% Operation not allowed on a dynamic neighbor\n");
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+ }
+
+ group = peer_group_lookup(bgp, argv[idx_word]->arg);
+ if (!group) {
+ vty_out(vty, "%% Configure the peer-group first\n");
return CMD_WARNING_CONFIG_FAILED;
+ }
- nb_cli_enqueue_change(vty, "./peer-group", NB_OP_MODIFY,
- argv[idx_word]->arg);
+ ret = peer_group_bind(bgp, &su, peer, group, &as);
- return nb_cli_apply_changes(vty, base_xpath);
+ if (ret == BGP_ERR_PEER_GROUP_PEER_TYPE_DIFFERENT) {
+ vty_out(vty,
+ "%% Peer with AS %u cannot be in this peer-group, members must be all internal or all external\n",
+ as);
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+
+ return bgp_vty_return(vty, ret);
}
ALIAS_HIDDEN(neighbor_set_peer_group, neighbor_set_peer_group_hidden_cmd,
diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c
index 9a2693fd56..368397d7aa 100644
--- a/bgpd/bgpd.c
+++ b/bgpd/bgpd.c
@@ -6974,6 +6974,22 @@ int peer_advertise_map_unset(struct peer *peer, afi_t afi, safi_t safi,
return 0;
}
+static bool peer_maximum_prefix_clear_overflow(struct peer *peer)
+{
+ if (!CHECK_FLAG(peer->sflags, PEER_STATUS_PREFIX_OVERFLOW))
+ return false;
+
+ UNSET_FLAG(peer->sflags, PEER_STATUS_PREFIX_OVERFLOW);
+ if (peer->t_pmax_restart) {
+ BGP_TIMER_OFF(peer->t_pmax_restart);
+ if (bgp_debug_neighbor_events(peer))
+ zlog_debug("%s Maximum-prefix restart timer cancelled",
+ peer->host);
+ }
+ BGP_EVENT_ADD(peer, BGP_Start);
+ return true;
+}
+
int peer_maximum_prefix_set(struct peer *peer, afi_t afi, safi_t safi,
uint32_t max, uint8_t threshold, int warning,
uint16_t restart, bool force)
@@ -7095,7 +7111,11 @@ int peer_maximum_prefix_unset(struct peer *peer, afi_t afi, safi_t safi)
member->pmax[afi][safi] = 0;
member->pmax_threshold[afi][safi] = 0;
member->pmax_restart[afi][safi] = 0;
+
+ peer_maximum_prefix_clear_overflow(member);
}
+ } else {
+ peer_maximum_prefix_clear_overflow(peer);
}
return 0;
@@ -7130,6 +7150,7 @@ int is_ebgp_multihop_configured(struct peer *peer)
int peer_ttl_security_hops_set(struct peer *peer, int gtsm_hops)
{
struct peer_group *group;
+ struct peer *gpeer;
struct listnode *node, *nnode;
int ret;
@@ -7166,9 +7187,10 @@ int peer_ttl_security_hops_set(struct peer *peer, int gtsm_hops)
return ret;
} else {
group = peer->group;
+ group->conf->gtsm_hops = gtsm_hops;
for (ALL_LIST_ELEMENTS(group->peer, node, nnode,
- peer)) {
- peer->gtsm_hops = group->conf->gtsm_hops;
+ gpeer)) {
+ gpeer->gtsm_hops = group->conf->gtsm_hops;
/* Calling ebgp multihop also resets the
* session.
@@ -7178,7 +7200,7 @@ int peer_ttl_security_hops_set(struct peer *peer, int gtsm_hops)
* value is
* irrelevant.
*/
- peer_ebgp_multihop_set(peer, MAXTTL);
+ peer_ebgp_multihop_set(gpeer, MAXTTL);
}
}
} else {
@@ -7199,9 +7221,10 @@ int peer_ttl_security_hops_set(struct peer *peer, int gtsm_hops)
MAXTTL + 1 - gtsm_hops);
} else {
group = peer->group;
+ group->conf->gtsm_hops = gtsm_hops;
for (ALL_LIST_ELEMENTS(group->peer, node, nnode,
- peer)) {
- peer->gtsm_hops = group->conf->gtsm_hops;
+ gpeer)) {
+ gpeer->gtsm_hops = group->conf->gtsm_hops;
/* Change setting of existing peer
* established then change value (may break
@@ -7211,17 +7234,18 @@ int peer_ttl_security_hops_set(struct peer *peer, int gtsm_hops)
* no session then do nothing (will get
* handled by next connection)
*/
- if (peer->fd >= 0
- && peer->gtsm_hops
+ if (gpeer->fd >= 0
+ && gpeer->gtsm_hops
!= BGP_GTSM_HOPS_DISABLED)
sockopt_minttl(
- peer->su.sa.sa_family, peer->fd,
- MAXTTL + 1 - peer->gtsm_hops);
- if ((peer->status < Established)
- && peer->doppelganger
- && (peer->doppelganger->fd >= 0))
- sockopt_minttl(peer->su.sa.sa_family,
- peer->doppelganger->fd,
+ gpeer->su.sa.sa_family,
+ gpeer->fd,
+ MAXTTL + 1 - gpeer->gtsm_hops);
+ if ((gpeer->status < Established)
+ && gpeer->doppelganger
+ && (gpeer->doppelganger->fd >= 0))
+ sockopt_minttl(gpeer->su.sa.sa_family,
+ gpeer->doppelganger->fd,
MAXTTL + 1 - gtsm_hops);
}
}
@@ -7298,18 +7322,8 @@ int peer_clear(struct peer *peer, struct listnode **nnode)
{
if (!CHECK_FLAG(peer->flags, PEER_FLAG_SHUTDOWN)
|| !CHECK_FLAG(peer->bgp->flags, BGP_FLAG_SHUTDOWN)) {
- if (CHECK_FLAG(peer->sflags, PEER_STATUS_PREFIX_OVERFLOW)) {
- UNSET_FLAG(peer->sflags, PEER_STATUS_PREFIX_OVERFLOW);
- if (peer->t_pmax_restart) {
- BGP_TIMER_OFF(peer->t_pmax_restart);
- if (bgp_debug_neighbor_events(peer))
- zlog_debug(
- "%s Maximum-prefix restart timer canceled",
- peer->host);
- }
- BGP_EVENT_ADD(peer, BGP_Start);
+ if (peer_maximum_prefix_clear_overflow(peer))
return 0;
- }
peer->v_start = BGP_INIT_START_TIMER;
if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status))
diff --git a/bgpd/rfapi/rfapi_import.c b/bgpd/rfapi/rfapi_import.c
index 3d87b63542..b2732a40b4 100644
--- a/bgpd/rfapi/rfapi_import.c
+++ b/bgpd/rfapi/rfapi_import.c
@@ -984,7 +984,7 @@ static int rfapiEcommunitiesMatchBeec(struct ecommunity *ecom,
int rfapiEcommunitiesIntersect(struct ecommunity *e1, struct ecommunity *e2)
{
- int i, j;
+ uint32_t i, j;
if (!e1 || !e2)
return 0;
@@ -1014,7 +1014,8 @@ int rfapiEcommunitiesIntersect(struct ecommunity *e1, struct ecommunity *e2)
int rfapiEcommunityGetLNI(struct ecommunity *ecom, uint32_t *lni)
{
if (ecom) {
- int i;
+ uint32_t i;
+
for (i = 0; i < ecom->size; ++i) {
uint8_t *p = ecom->val + (i * ECOMMUNITY_SIZE);
@@ -1034,7 +1035,8 @@ int rfapiEcommunityGetEthernetTag(struct ecommunity *ecom, uint16_t *tag_id)
struct bgp *bgp = bgp_get_default();
*tag_id = 0; /* default to untagged */
if (ecom) {
- int i;
+ uint32_t i;
+
for (i = 0; i < ecom->size; ++i) {
as_t as = 0;
int encode = 0;
diff --git a/bgpd/rfapi/vnc_export_bgp.c b/bgpd/rfapi/vnc_export_bgp.c
index 762cd2596f..bc29f05aeb 100644
--- a/bgpd/rfapi/vnc_export_bgp.c
+++ b/bgpd/rfapi/vnc_export_bgp.c
@@ -134,7 +134,7 @@ static void encap_attr_export_ce(struct attr *new, struct attr *orig,
static int getce(struct bgp *bgp, struct attr *attr, struct prefix *pfx_ce)
{
uint8_t *ecp;
- int i;
+ uint32_t i;
uint16_t localadmin = bgp->rfapi_cfg->resolve_nve_roo_local_admin;
for (ecp = attr->ecommunity->val, i = 0; i < attr->ecommunity->size;
diff --git a/bgpd/subdir.am b/bgpd/subdir.am
index ac84f4b9e4..df1555c32a 100644
--- a/bgpd/subdir.am
+++ b/bgpd/subdir.am
@@ -96,6 +96,7 @@ bgpd_libbgp_a_SOURCES = \
bgpd/bgp_regex.c \
bgpd/bgp_route.c \
bgpd/bgp_routemap.c \
+ bgpd/bgp_script.c \
bgpd/bgp_table.c \
bgpd/bgp_updgrp.c \
bgpd/bgp_updgrp_adv.c \
@@ -175,6 +176,7 @@ noinst_HEADERS += \
bgpd/bgp_rd.h \
bgpd/bgp_regex.h \
bgpd/bgp_route.h \
+ bgpd/bgp_script.h \
bgpd/bgp_table.h \
bgpd/bgp_updgrp.h \
bgpd/bgp_vpn.h \
diff --git a/configure.ac b/configure.ac
index 0cbf4d22e6..8f9517763d 100755
--- a/configure.ac
+++ b/configure.ac
@@ -138,6 +138,12 @@ AC_ARG_WITH([moduledir], [AS_HELP_STRING([--with-moduledir=DIR], [module directo
])
AC_SUBST([moduledir], [$moduledir])
+AC_ARG_WITH([scriptdir], [AS_HELP_STRING([--with-scriptdir=DIR], [script directory (${sysconfdir}/scripts)])], [
+ scriptdir="$withval"
+], [
+ scriptdir="\${sysconfdir}/scripts"
+])
+AC_SUBST([scriptdir], [$scriptdir])
AC_ARG_WITH([yangmodelsdir], [AS_HELP_STRING([--with-yangmodelsdir=DIR], [yang models directory (${datarootdir}/yang)])], [
yangmodelsdir="$withval"
@@ -274,24 +280,22 @@ if test "$enable_clang_coverage" = "yes"; then
])
fi
+if test "$enable_scripting" = "yes"; then
+ AX_PROG_LUA([5.3])
+ AX_LUA_HEADERS
+ AX_LUA_LIBS([
+ AC_DEFINE([HAVE_SCRIPTING], [1], [Have support for scripting])
+ LIBS="$LIBS $LUA_LIB"
+ ])
+fi
+
if test "$enable_dev_build" = "yes"; then
AC_DEFINE([DEV_BUILD], [1], [Build for development])
if test "$orig_cflags" = ""; then
AC_C_FLAG([-g3])
AC_C_FLAG([-O0])
fi
- if test "$enable_lua" = "yes"; then
- AX_PROG_LUA([5.3])
- AX_LUA_HEADERS
- AX_LUA_LIBS([
- AC_DEFINE([HAVE_LUA], [1], [Have support for Lua interpreter])
- LIBS="$LIBS $LUA_LIB"
- ])
- fi
else
- if test "$enable_lua" = "yes"; then
- AC_MSG_ERROR([Lua is not meant to be built/used outside of development at this time])
- fi
if test "$orig_cflags" = ""; then
AC_C_FLAG([-g])
AC_C_FLAG([-O2])
@@ -697,8 +701,8 @@ fi
AC_ARG_ENABLE([dev_build],
AS_HELP_STRING([--enable-dev-build], [build for development]))
-AC_ARG_ENABLE([lua],
- AS_HELP_STRING([--enable-lua], [Build Lua scripting]))
+AC_ARG_ENABLE([scripting],
+ AS_HELP_STRING([--enable-scripting], [Build with scripting support]))
AC_ARG_ENABLE([netlink-debug],
AS_HELP_STRING([--disable-netlink-debug], [pretty print netlink debug messages]))
@@ -1862,7 +1866,7 @@ dnl ---------------
dnl sysrepo
dnl ---------------
if test "$enable_sysrepo" = "yes"; then
- PKG_CHECK_MODULES([SYSREPO], [libsysrepo],
+ PKG_CHECK_MODULES([SYSREPO], [sysrepo],
[AC_DEFINE([HAVE_SYSREPO], [1], [Enable sysrepo integration])
SYSREPO=true],
[SYSREPO=false
@@ -2446,19 +2450,23 @@ CFG_SBIN="$sbindir"
CFG_STATE="$frr_statedir"
CFG_MODULE="$moduledir"
CFG_YANGMODELS="$yangmodelsdir"
+CFG_SCRIPT="$scriptdir"
for I in 1 2 3 4 5 6 7 8 9 10; do
eval CFG_SYSCONF="\"$CFG_SYSCONF\""
eval CFG_SBIN="\"$CFG_SBIN\""
eval CFG_STATE="\"$CFG_STATE\""
eval CFG_MODULE="\"$CFG_MODULE\""
eval CFG_YANGMODELS="\"$CFG_YANGMODELS\""
+ eval CFG_SCRIPT="\"$CFG_SCRIPT\""
done
AC_SUBST([CFG_SYSCONF])
AC_SUBST([CFG_SBIN])
AC_SUBST([CFG_STATE])
AC_SUBST([CFG_MODULE])
+AC_SUBST([CFG_SCRIPT])
AC_SUBST([CFG_YANGMODELS])
AC_DEFINE_UNQUOTED([MODULE_PATH], ["$CFG_MODULE"], [path to modules])
+AC_DEFINE_UNQUOTED([SCRIPT_PATH], ["$CFG_SCRIPT"], [path to scripts])
AC_DEFINE_UNQUOTED([YANG_MODELS_PATH], ["$CFG_YANGMODELS"], [path to YANG data models])
AC_DEFINE_UNQUOTED([WATCHFRR_SH_PATH], ["${CFG_SBIN%/}/watchfrr.sh"], [path to watchfrr.sh])
@@ -2582,6 +2590,7 @@ state file directory : ${frr_statedir}
config file directory : `eval echo \`echo ${sysconfdir}\``
example directory : `eval echo \`echo ${exampledir}\``
module directory : ${CFG_MODULE}
+script directory : ${CFG_SCRIPT}
user to run as : ${enable_user}
group to run as : ${enable_group}
group for vty sockets : ${enable_vty_group}
diff --git a/debian/control b/debian/control
index 4aaa9f21bf..b9e96b55d0 100644
--- a/debian/control
+++ b/debian/control
@@ -29,7 +29,8 @@ Build-Depends: bison,
python3-dev,
python3-pytest <!nocheck>,
python3-sphinx,
- texinfo (>= 4.7)
+ texinfo (>= 4.7),
+ liblua5.3-dev <pkg.frr.lua>
Standards-Version: 4.5.0.3
Homepage: https://www.frrouting.org/
Vcs-Browser: https://github.com/FRRouting/frr/tree/debian/master
diff --git a/debian/rules b/debian/rules
index 6cc03c378a..25ae04261d 100755
--- a/debian/rules
+++ b/debian/rules
@@ -29,6 +29,12 @@ else
CONF_SYSTEMD=--enable-systemd=no
endif
+ifeq ($(filter pkg.frr.lua,$(DEB_BUILD_PROFILES)),)
+ CONF_LUA=--disable-scripting
+else
+ CONF_LUA=--enable-scripting
+endif
+
export PYTHON=python3
%:
@@ -49,6 +55,7 @@ override_dh_auto_configure:
\
$(CONF_SYSTEMD) \
$(CONF_RPKI) \
+ $(CONF_LUA) \
--with-libpam \
--enable-doc \
--enable-doc-html \
diff --git a/doc/developer/library.rst b/doc/developer/library.rst
index 3d5c6a2a15..1bfe5df2f0 100644
--- a/doc/developer/library.rst
+++ b/doc/developer/library.rst
@@ -15,6 +15,6 @@ Library Facilities (libfrr)
hooks
cli
modules
- lua
+ scripting
diff --git a/doc/developer/lua.rst b/doc/developer/lua.rst
deleted file mode 100644
index 3315c31ad7..0000000000
--- a/doc/developer/lua.rst
+++ /dev/null
@@ -1,65 +0,0 @@
-.. _lua:
-
-Lua
-===
-
-Lua is currently experimental within FRR and has very limited
-support. If you would like to compile FRR with Lua you must
-follow these steps:
-
-1. Installation of Relevant Libraries
-
- .. code-block:: shell
-
- apt-get install lua5.3 liblua5-3 liblua5.3-dev
-
- These are the Debian libraries that are needed. There should
- be equivalent RPM's that can be found
-
-2. Compilation
-
- Configure needs these options
-
- .. code-block:: shell
-
- ./configure --enable-dev-build --enable-lua <all other interesting options>
-
- Typically you just include the two new enable lines to build with it.
-
-3. Using Lua
-
- * Copy tools/lua.scr into /etc/frr
-
- * Create a route-map match command
-
- .. code-block:: console
-
- !
- router bgp 55
- neighbor 10.50.11.116 remote-as external
- address-family ipv4 unicast
- neighbor 10.50.11.116 route-map TEST in
- exit-address-family
- !
- route-map TEST permit 10
- match command mooey
- !
-
- * In the lua.scr file make sure that you have a function named 'mooey'
-
- .. code-block:: console
-
- function mooey ()
- zlog_debug(string.format("afi: %d: %s %d ifdx: %d aspath: %s localpref: %d",
- prefix.family, prefix.route, nexthop.metric,
- nexthop.ifindex, nexthop.aspath, nexthop.localpref))
-
- nexthop.metric = 33
- nexthop.localpref = 13
- return 3
- end
-
-4. General Comments
-
- Please be aware that this is extremely experimental and needs a ton of work
- to get this up into a state that is usable.
diff --git a/doc/developer/scripting.rst b/doc/developer/scripting.rst
new file mode 100644
index 0000000000..b0413619ab
--- /dev/null
+++ b/doc/developer/scripting.rst
@@ -0,0 +1,433 @@
+.. _scripting:
+
+Scripting
+=========
+
+.. seealso:: User docs for scripting
+
+Overview
+--------
+
+FRR has the ability to call Lua scripts to perform calculations, make
+decisions, or otherwise extend builtin behavior with arbitrary user code. This
+is implemented using the standard Lua C bindings. The supported version of Lua
+is 5.3.
+
+C objects may be passed into Lua and Lua objects may be retrieved by C code via
+a marshalling system. In this way, arbitrary data from FRR may be passed to
+scripts. It is possible to pass C functions as well.
+
+The Lua environment is isolated from the C environment; user scripts cannot
+access FRR's address space unless explicitly allowed by FRR.
+
+For general information on how Lua is used to extend C, refer to Part IV of
+"Programming in Lua".
+
+https://www.lua.org/pil/contents.html#24
+
+
+Design
+------
+
+Why Lua
+^^^^^^^
+
+Lua is designed to be embedded in C applications. It is very small; the
+standard library is 220K. It is relatively fast. It has a simple, minimal
+syntax that is relatively easy to learn and can be understood by someone with
+little to no programming experience. Moreover it is widely used to add
+scripting capabilities to applications. In short it is designed for this task.
+
+Reasons against supporting multiple scripting languages:
+
+- Each language would require different FFI methods, and specifically
+ different object encoders; a lot of code
+- Languages have different capabilities that would have to be brought to
+ parity with each other; a lot of work
+- Languages have vastly different performance characteristics; this would
+ create alot of basically unfixable issues, and result in a single de facto
+ standard scripting language (the fastest)
+- Each language would need a dedicated maintainer for the above reasons;
+ this is pragmatically difficult
+- Supporting multiple languages fractures the community and limits the audience
+ with which a given script can be shared
+
+General
+^^^^^^^
+
+FRR's concept of a script is somewhat abstracted away from the fact that it is
+Lua underneath. A script in has two things:
+
+- name
+- state
+
+In code:
+
+.. code-block:: c
+
+ struct frrscript {
+ /* Script name */
+ char *name;
+
+ /* Lua state */
+ struct lua_State *L;
+ };
+
+
+``name`` is simply a string. Everything else is in ``state``, which is itself a
+Lua library object (``lua_State``). This is an opaque struct that is
+manipulated using ``lua_*`` functions. The basic ones are imported from
+``lua.h`` and the rest are implemented within FRR to fill our use cases. The
+thing to remember is that all operations beyond the initial loading the script
+take place on this opaque state object.
+
+There are four basic actions that can be done on a script:
+
+- load
+- execute
+- query state
+- unload
+
+They are typically done in this order.
+
+
+Loading
+^^^^^^^
+
+A snippet of Lua code is referred to as a "chunk". These are simply text. FRR
+presently assumes chunks are located in individual files specific to one task.
+These files are stored in the scripts directory and must end in ``.lua``.
+
+A script object is created by loading a script. This is done with
+``frrscript_load()``. This function takes the name of the script and an
+optional callback function. The string ".lua" is appended to the script name,
+and the resultant filename is looked for in the scripts directory.
+
+For example, to load ``/etc/frr/scripts/bingus.lua``:
+
+.. code-block:: c
+
+ struct frrscript *fs = frrscript_load("bingus", NULL);
+
+During loading the script is validated for syntax and its initial environment
+is setup. By default this does not include the Lua standard library; there are
+security issues to consider, though for practical purposes untrusted users
+should not be able to write the scripts directory anyway. If desired the Lua
+standard library may be added to the script environment using
+``luaL_openlibs(fs->L)`` after loading the script. Further information on
+setting up the script environment is in the Lua manual.
+
+
+Executing
+^^^^^^^^^
+
+After loading, scripts may be executed. A script may take input in the form of
+variable bindings set in its environment prior to being run, and may provide
+results by setting the value of variables. Arbitrary C values may be
+transferred into the script environment, including functions.
+
+A typical execution call looks something like this:
+
+.. code-block:: c
+
+ struct frrscript *fs = frrscript_load(...);
+
+ int status_ok = 0, status_fail = 1;
+ struct prefix p = ...;
+
+ struct frrscript_env env[] = {
+ {"integer", "STATUS_FAIL", &status_fail},
+ {"integer", "STATUS_OK", &status_ok},
+ {"prefix", "myprefix", &p},
+ {}};
+
+ int result = frrscript_call(fs, env);
+
+
+To execute a loaded script, we need to define the inputs. These inputs are
+passed by binding values to variable names that will be accessible within the
+Lua environment. Basically, all communication with the script takes place via
+global variables within the script, and to provide inputs we predefine globals
+before the script runs. This is done by passing ``frrscript_call()`` an array
+of ``struct frrscript_env``. Each struct has three fields. The first identifies
+the type of the value being passed; more on this later. The second defines the
+name of the global variable within the script environment to bind the third
+argument (the value) to.
+
+The script is then executed and returns a general status code. In the success
+case this will be 0, otherwise it will be nonzero. The script itself does not
+determine this code, it is provided by the Lua interpreter.
+
+
+Querying State
+^^^^^^^^^^^^^^
+
+When a chunk is executed, its state at exit is preserved and can be inspected.
+
+After running a script, results may be retrieved by querying the script's
+state. Again this is done by retrieving the values of global variables, which
+are known to the script author to be "output" variables.
+
+A result is retrieved like so:
+
+.. code-block:: c
+
+ struct frrscript_env myresult = {"string", "myresult"};
+
+ char *myresult = frrscript_get_result(fs, &myresult);
+
+ ... do something ...
+
+ XFREE(MTYPE_TMP, myresult);
+
+
+As with arguments, results are retrieved by providing a ``struct
+frrscript_env`` specifying a type and a global name. No value is necessary, nor
+is it modified by ``frrscript_get_result()``. That function simply extracts the
+requested value from the script state and returns it.
+
+In most cases the returned value will be allocated with ``MTYPE_TMP`` and will
+need to be freed after use.
+
+
+Unloading
+^^^^^^^^^
+
+To destroy a script and its associated state:
+
+.. code-block:: c
+
+ frrscript_unload(fs);
+
+Values returned by ``frrscript_get_result`` are still valid after the script
+they were retrieved from is unloaded.
+
+Note that you must unload and then load the script if you want to reset its
+state, for example to run it again with different inputs. Otherwise the state
+from the previous run carries over into subsequent runs.
+
+
+.. _marshalling:
+
+Marshalling
+^^^^^^^^^^^
+
+Earlier sections glossed over the meaning of the type name field in ``struct
+frrscript_env`` and how data is passed between C and Lua. Lua, as a dynamically
+typed, garbage collected language, cannot directly use C values without some
+kind of marshalling / unmarshalling system to translate types between the two
+runtimes.
+
+Lua communicates with C code using a stack. C code wishing to provide data to
+Lua scripts must provide a function that marshalls the C data into a Lua
+representation and pushes it on the stack. C code wishing to retrieve data from
+Lua must provide a corresponding unmarshalling function that retrieves a Lua
+value from the stack and converts it to the corresponding C type. These two
+functions, together with a chosen name of the type they operate on, are
+referred to as ``codecs`` in FRR.
+
+A codec is defined as:
+
+.. code-block:: c
+
+ typedef void (*encoder_func)(lua_State *, const void *);
+ typedef void *(*decoder_func)(lua_State *, int);
+
+ struct frrscript_codec {
+ const char *typename;
+ encoder_func encoder;
+ decoder_func decoder;
+ };
+
+A typename string and two function pointers.
+
+``typename`` can be anything you want. For example, for the combined types of
+``struct prefix`` and its equivalent in Lua I have chosen the name ``prefix``.
+There is no restriction on naming here, it is just a human name used as a key
+and specified when passing and retrieving values.
+
+``encoder`` is a function that takes a ``lua_State *`` and a C type and pushes
+onto the Lua stack a value representing the C type. For C structs, the usual
+case, this will typically be a Lua table (tables are the only datastructure Lua
+has). For example, here is the encoder function for ``struct prefix``:
+
+
+.. code-block:: c
+
+ void lua_pushprefix(lua_State *L, const struct prefix *prefix)
+ {
+ char buffer[PREFIX_STRLEN];
+
+ zlog_debug("frrlua: pushing prefix table");
+
+ lua_newtable(L);
+ lua_pushstring(L, prefix2str(prefix, buffer, PREFIX_STRLEN));
+ lua_setfield(L, -2, "network");
+ lua_pushinteger(L, prefix->prefixlen);
+ lua_setfield(L, -2, "length");
+ lua_pushinteger(L, prefix->family);
+ lua_setfield(L, -2, "family");
+ }
+
+This function pushes a single value onto the Lua stack. It is a table whose equivalent in Lua is:
+
+.. code-block::
+
+ { ["network"] = "1.2.3.4/24", ["prefixlen"] = 24, ["family"] = 2 }
+
+
+``decoder`` does the reverse; it takes a ``lua_State *`` and an index into the
+stack, and unmarshalls a Lua value there into the corresponding C type. Again
+for ``struct prefix``:
+
+
+.. code-block:: c
+
+ void *lua_toprefix(lua_State *L, int idx)
+ {
+ struct prefix *p = XCALLOC(MTYPE_TMP, sizeof(struct prefix));
+
+ lua_getfield(L, idx, "network");
+ str2prefix(lua_tostring(L, -1), p);
+ lua_pop(L, 1);
+
+ return p;
+ }
+
+By convention these functions should be called ``lua_to*``, as this is the
+naming convention used by the Lua C library for the basic types e.g.
+``lua_tointeger`` and ``lua_tostring``.
+
+The returned data must always be copied off the stack and the copy must be
+allocated with ``MTYPE_TMP``. This way it is possible to unload the script
+(destroy the state) without invalidating any references to values stored in it.
+
+To register a new type with its corresponding encoding functions:
+
+.. code-block:: c
+
+ struct frrscript_codec frrscript_codecs_lib[] = {
+ {.typename = "prefix",
+ .encoder = (encoder_func)lua_pushprefix,
+ .decoder = lua_toprefix},
+ {.typename = "sockunion",
+ .encoder = (encoder_func)lua_pushsockunion,
+ .decoder = lua_tosockunion},
+ ...
+ {}};
+
+ frrscript_register_type_codecs(frrscript_codecs_lib);
+
+From this point on the type names are available to be used when calling any
+script and getting its results.
+
+.. note::
+
+ Marshalled types are not restricted to simple values like integers, strings
+ and tables. It is possible to marshall a type such that the resultant object
+ in Lua is an actual object-oriented object, complete with methods that call
+ back into defined C functions. See the Lua manual for how to do this; for a
+ code example, look at how zlog is exported into the script environment.
+
+
+Script Environment
+------------------
+
+Logging
+^^^^^^^
+
+For convenience, script environments are populated by default with a ``log``
+object which contains methods corresponding to each of the ``zlog`` levels:
+
+.. code-block:: lua
+
+ log.info("info")
+ log.warn("warn")
+ log.error("error")
+ log.notice("notice")
+ log.debug("debug")
+
+The log messages will show up in the daemon's log output.
+
+
+Examples
+--------
+
+For a complete code example involving passing custom types, retrieving results,
+and doing complex calculations in Lua, look at the implementation of the
+``match script SCRIPT`` command for BGP routemaps. This example calls into a
+script with a route prefix and attributes received from a peer and expects the
+script to return a match / no match / match and update result.
+
+An example script to use with this follows. This script matches, does not match
+or updates a route depending on how many BGP UPDATE messages the peer has
+received when the script is called, simply as a demonstration of what can be
+accomplished with scripting.
+
+.. code-block:: lua
+
+
+ -- Example route map matching
+ -- author: qlyoung
+ --
+ -- The following variables are available to us:
+ -- log
+ -- logging library, with the usual functions
+ -- prefix
+ -- the route under consideration
+ -- attributes
+ -- the route's attributes
+ -- peer
+ -- the peer which received this route
+ -- RM_FAILURE
+ -- status code in case of failure
+ -- RM_NOMATCH
+ -- status code for no match
+ -- RM_MATCH
+ -- status code for match
+ -- RM_MATCH_AND_CHANGE
+ -- status code for match-and-set
+ --
+ -- We need to set the following out values:
+ -- action
+ -- Set to the appropriate status code to indicate what we did
+ -- attributes
+ -- Setting fields on here will propagate them back up to the caller if
+ -- 'action' is set to RM_MATCH_AND_CHANGE.
+
+
+ log.info("Evaluating route " .. prefix.network .. " from peer " .. peer.remote_id.string)
+
+ function on_match (prefix, attrs)
+ log.info("Match")
+ action = RM_MATCH
+ end
+
+ function on_nomatch (prefix, attrs)
+ log.info("No match")
+ action = RM_NOMATCH
+ end
+
+ function on_match_and_change (prefix, attrs)
+ action = RM_MATCH_AND_CHANGE
+ log.info("Match and change")
+ attrs["metric"] = attrs["metric"] + 7
+ end
+
+ special_routes = {
+ ["172.16.10.4/24"] = on_match,
+ ["172.16.13.1/8"] = on_nomatch,
+ ["192.168.0.24/8"] = on_match_and_change,
+ }
+
+
+ if special_routes[prefix.network] then
+ special_routes[prefix.network](prefix, attributes)
+ elseif peer.stats.update_in % 3 == 0 then
+ on_match(prefix, attributes)
+ elseif peer.stats.update_in % 2 == 0 then
+ on_nomatch(prefix, attributes)
+ else
+ on_match_and_change(prefix, attributes)
+ end
+
diff --git a/doc/developer/subdir.am b/doc/developer/subdir.am
index 0129be6bf1..07a25886d0 100644
--- a/doc/developer/subdir.am
+++ b/doc/developer/subdir.am
@@ -37,7 +37,6 @@ dev_RSTFILES = \
doc/developer/lists.rst \
doc/developer/locking.rst \
doc/developer/logging.rst \
- doc/developer/lua.rst \
doc/developer/memtypes.rst \
doc/developer/modules.rst \
doc/developer/next-hop-tracking.rst \
@@ -52,6 +51,7 @@ dev_RSTFILES = \
doc/developer/path-internals.rst \
doc/developer/path.rst \
doc/developer/rcu.rst \
+ doc/developer/scripting.rst \
doc/developer/static-linking.rst \
doc/developer/tracing.rst \
doc/developer/testing.rst \
diff --git a/doc/user/index.rst b/doc/user/index.rst
index 993acf3b4c..7b9464668b 100644
--- a/doc/user/index.rst
+++ b/doc/user/index.rst
@@ -29,6 +29,7 @@ Basics
ipv6
kernel
snmp
+ scripting
.. modules
#########
diff --git a/doc/user/installation.rst b/doc/user/installation.rst
index 382d71b71f..a13e6ce43b 100644
--- a/doc/user/installation.rst
+++ b/doc/user/installation.rst
@@ -362,6 +362,10 @@ options from the list below.
Set hardcoded rpaths in the executable [default=yes].
+.. option:: --enable-scripting
+
+ Enable Lua scripting [default=no].
+
You may specify any combination of the above options to the configure
script. By default, the executables are placed in :file:`/usr/local/sbin`
and the configuration files in :file:`/usr/local/etc`. The :file:`/usr/local/`
@@ -382,6 +386,10 @@ options to the configuration script.
Configure zebra to use `dir` for local state files, such as pid files and
unix sockets.
+.. option:: --with-scriptdir <dir>
+
+ Look for Lua scripts in ``dir`` [``prefix``/etc/frr/scripts].
+
.. option:: --with-yangmodelsdir <dir>
Look for YANG modules in `dir` [`prefix`/share/yang]. Note that the FRR
diff --git a/doc/user/ospfd.rst b/doc/user/ospfd.rst
index cbde0fd46f..7184a0e197 100644
--- a/doc/user/ospfd.rst
+++ b/doc/user/ospfd.rst
@@ -322,6 +322,23 @@ To start OSPF process you have to specify the OSPF router.
This feature is enabled by default.
+.. index:: clear ip ospf [(1-65535)] process
+.. clicmd:: clear ip ospf [(1-65535)] process
+
+ This command can be used to clear the ospf process data structures. This
+ will clear the ospf neighborship as well and it will get re-established.
+ This will clear the LSDB too. This will be helpful when there is a change
+ in router-id and if user wants the router-id change to take effect, user can
+ use this cli instead of restarting the ospfd daemon.
+
+.. index:: clear ip ospf [(1-65535)] neighbor
+.. clicmd:: clear ip ospf [(1-65535)] neighbor
+
+ This command can be used to clear the ospf neighbor data structures. This
+ will clear the ospf neighborship and it will get re-established. This
+ command can be used when the neighbor state get stuck at some state and
+ this can be used to recover it from that state.
+
.. _ospf-area:
Areas
diff --git a/doc/user/scripting.rst b/doc/user/scripting.rst
new file mode 100644
index 0000000000..b0295e5706
--- /dev/null
+++ b/doc/user/scripting.rst
@@ -0,0 +1,28 @@
+.. _scripting:
+
+*********
+Scripting
+*********
+
+The behavior of FRR may be extended or customized using its built-in scripting
+capabilities.
+
+Some configuration commands accept the name of a Lua script to call to perform
+some task or make some decision. These scripts have their environments
+populated with some set of inputs, and are expected to populate some set of
+output variables, which are read by FRR after the script completes. The names
+and expected contents of these scripts are documented alongside the commands
+that support them.
+
+These scripts live in :file:`/etc/frr/scripts/` by default. This is
+configurable at compile time via ``--with-scriptdir``. It may be
+overriden at runtime with the ``--scriptdir`` daemon option.
+
+In order to use scripting, FRR must be built with ``--enable-scripting``.
+
+.. note::
+
+ Scripts are typically loaded just-in-time. This means you can change the
+ contents of a script that is in use without restarting FRR. Not all
+ scripting locations may behave this way; refer to the documentation for the
+ particular location.
diff --git a/doc/user/subdir.am b/doc/user/subdir.am
index a78d261863..3585245e85 100644
--- a/doc/user/subdir.am
+++ b/doc/user/subdir.am
@@ -35,6 +35,7 @@ user_RSTFILES = \
doc/user/routemap.rst \
doc/user/routeserver.rst \
doc/user/rpki.rst \
+ doc/user/scripting.rst \
doc/user/setup.rst \
doc/user/sharp.rst \
doc/user/snmp.rst \
diff --git a/eigrpd/eigrp_cli.c b/eigrpd/eigrp_cli.c
index 3610b3a869..00d8ea8867 100644
--- a/eigrpd/eigrp_cli.c
+++ b/eigrpd/eigrp_cli.c
@@ -29,6 +29,7 @@
#include "eigrp_structs.h"
#include "eigrpd.h"
#include "eigrp_zebra.h"
+#include "eigrp_cli.h"
#ifndef VTYSH_EXTRACT_PL
#include "eigrpd/eigrp_cli_clippy.c"
diff --git a/eigrpd/eigrp_cli.h b/eigrpd/eigrp_cli.h
new file mode 100644
index 0000000000..c5f2fd8009
--- /dev/null
+++ b/eigrpd/eigrp_cli.h
@@ -0,0 +1,70 @@
+/*
+ * EIGRP CLI Functions.
+ * Copyright (C) 2019
+ * Authors:
+ * Donnie Savage
+ *
+ * This file is part of FRR.
+ *
+ * FRR is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * FRR is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; see the file COPYING; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef _EIGRP_CLI_H_
+#define _EIGRP_CLI_H_
+
+/*Prototypes*/
+extern void eigrp_cli_show_header(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults);
+extern void eigrp_cli_show_end_header(struct vty *vty, struct lyd_node *dnode);
+extern void eigrp_cli_show_router_id(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults);
+extern void eigrp_cli_show_passive_interface(struct vty *vty,
+ struct lyd_node *dnode,
+ bool show_defaults);
+extern void eigrp_cli_show_active_time(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults);
+extern void eigrp_cli_show_variance(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults);
+extern void eigrp_cli_show_maximum_paths(struct vty *vty,
+ struct lyd_node *dnode,
+ bool show_defaults);
+extern void eigrp_cli_show_metrics(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults);
+extern void eigrp_cli_show_network(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults);
+extern void eigrp_cli_show_neighbor(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults);
+extern void eigrp_cli_show_redistribute(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults);
+extern void eigrp_cli_show_delay(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults);
+extern void eigrp_cli_show_bandwidth(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults);
+extern void eigrp_cli_show_hello_interval(struct vty *vty,
+ struct lyd_node *dnode,
+ bool show_defaults);
+extern void eigrp_cli_show_hold_time(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults);
+extern void eigrp_cli_show_summarize_address(struct vty *vty,
+ struct lyd_node *dnode,
+ bool show_defaults);
+extern void eigrp_cli_show_authentication(struct vty *vty,
+ struct lyd_node *dnode,
+ bool show_defaults);
+extern void eigrp_cli_show_keychain(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults);
+extern void eigrp_cli_init(void);
+
+#endif /*EIGRP_CLI_H_ */
diff --git a/eigrpd/eigrp_const.h b/eigrpd/eigrp_const.h
index d3d9bca82a..149cf00efc 100644
--- a/eigrpd/eigrp_const.h
+++ b/eigrpd/eigrp_const.h
@@ -122,10 +122,10 @@ enum metric_change { METRIC_DECREASE, METRIC_SAME, METRIC_INCREASE };
#define EIGRP_TOPOLOGY_TYPE_REMOTE_EXTERNAL 2 // Remote external network
/*EIGRP TT entry flags*/
-#define EIGRP_NEXTHOP_ENTRY_SUCCESSOR_FLAG (1 << 0)
-#define EIGRP_NEXTHOP_ENTRY_FSUCCESSOR_FLAG (1 << 1)
-#define EIGRP_NEXTHOP_ENTRY_INTABLE_FLAG (1 << 2)
-#define EIGRP_NEXTHOP_ENTRY_EXTERNAL_FLAG (1 << 3)
+#define EIGRP_ROUTE_DESCRIPTOR_SUCCESSOR_FLAG (1 << 0)
+#define EIGRP_ROUTE_DESCRIPTOR_FSUCCESSOR_FLAG (1 << 1)
+#define EIGRP_ROUTE_DESCRIPTOR_INTABLE_FLAG (1 << 2)
+#define EIGRP_ROUTE_DESCRIPTOR_EXTERNAL_FLAG (1 << 3)
/*EIGRP FSM state count, event count*/
#define EIGRP_FSM_STATE_MAX 5
diff --git a/eigrpd/eigrp_dump.c b/eigrpd/eigrp_dump.c
index dfce2acad4..e1ad51a9db 100644
--- a/eigrpd/eigrp_dump.c
+++ b/eigrpd/eigrp_dump.c
@@ -236,7 +236,8 @@ void show_ip_eigrp_topology_header(struct vty *vty, struct eigrp *eigrp)
"Codes: P - Passive, A - Active, U - Update, Q - Query, R - Reply\n r - reply Status, s - sia Status\n\n");
}
-void show_ip_eigrp_prefix_entry(struct vty *vty, struct eigrp_prefix_entry *tn)
+void show_ip_eigrp_prefix_descriptor(struct vty *vty,
+ struct eigrp_prefix_descriptor *tn)
{
struct list *successors = eigrp_topology_get_successor(tn);
@@ -251,14 +252,15 @@ void show_ip_eigrp_prefix_entry(struct vty *vty, struct eigrp_prefix_entry *tn)
list_delete(&successors);
}
-void show_ip_eigrp_nexthop_entry(struct vty *vty, struct eigrp *eigrp,
- struct eigrp_nexthop_entry *te, bool *first)
+void show_ip_eigrp_route_descriptor(struct vty *vty, struct eigrp *eigrp,
+ struct eigrp_route_descriptor *te,
+ bool *first)
{
if (te->reported_distance == EIGRP_MAX_METRIC)
return;
if (*first) {
- show_ip_eigrp_prefix_entry(vty, te->prefix);
+ show_ip_eigrp_prefix_descriptor(vty, te->prefix);
*first = false;
}
diff --git a/eigrpd/eigrp_dump.h b/eigrpd/eigrp_dump.h
index 348356bb3c..0d512fc63f 100644
--- a/eigrpd/eigrp_dump.h
+++ b/eigrpd/eigrp_dump.h
@@ -151,11 +151,11 @@ extern void show_ip_eigrp_interface_sub(struct vty *, struct eigrp *,
struct eigrp_interface *);
extern void show_ip_eigrp_neighbor_sub(struct vty *, struct eigrp_neighbor *,
int);
-extern void show_ip_eigrp_prefix_entry(struct vty *,
- struct eigrp_prefix_entry *);
-extern void show_ip_eigrp_nexthop_entry(struct vty *vty, struct eigrp *eigrp,
- struct eigrp_nexthop_entry *ne,
- bool *first);
+extern void show_ip_eigrp_prefix_descriptor(struct vty *vty,
+ struct eigrp_prefix_descriptor *tn);
+extern void show_ip_eigrp_route_descriptor(struct vty *vty, struct eigrp *eigrp,
+ struct eigrp_route_descriptor *ne,
+ bool *first);
extern void eigrp_debug_init(void);
diff --git a/eigrpd/eigrp_fsm.c b/eigrpd/eigrp_fsm.c
index a69a3eec0a..d2d435bf2d 100644
--- a/eigrpd/eigrp_fsm.c
+++ b/eigrpd/eigrp_fsm.c
@@ -77,6 +77,7 @@
#include "linklist.h"
#include "vty.h"
+#include "eigrpd/eigrp_types.h"
#include "eigrpd/eigrp_structs.h"
#include "eigrpd/eigrpd.h"
#include "eigrpd/eigrp_interface.h"
@@ -88,6 +89,7 @@
#include "eigrpd/eigrp_dump.h"
#include "eigrpd/eigrp_topology.h"
#include "eigrpd/eigrp_fsm.h"
+#include "eigrpd/eigrp_metric.h"
/*
* Prototypes
@@ -262,13 +264,13 @@ eigrp_get_fsm_event(struct eigrp_fsm_action_message *msg)
{
// Loading base information from message
// struct eigrp *eigrp = msg->eigrp;
- struct eigrp_prefix_entry *prefix = msg->prefix;
- struct eigrp_nexthop_entry *entry = msg->entry;
+ struct eigrp_prefix_descriptor *prefix = msg->prefix;
+ struct eigrp_route_descriptor *entry = msg->entry;
uint8_t actual_state = prefix->state;
enum metric_change change;
if (entry == NULL) {
- entry = eigrp_nexthop_entry_new();
+ entry = eigrp_route_descriptor_new();
entry->adv_router = msg->adv_router;
entry->ei = msg->adv_router->ei;
entry->prefix = prefix;
@@ -286,7 +288,7 @@ eigrp_get_fsm_event(struct eigrp_fsm_action_message *msg)
switch (actual_state) {
case EIGRP_FSM_STATE_PASSIVE: {
- struct eigrp_nexthop_entry *head =
+ struct eigrp_route_descriptor *head =
listnode_head(prefix->entries);
if (head->reported_distance < prefix->fdistance) {
@@ -307,7 +309,7 @@ eigrp_get_fsm_event(struct eigrp_fsm_action_message *msg)
}
case EIGRP_FSM_STATE_ACTIVE_0: {
if (msg->packet_type == EIGRP_OPC_REPLY) {
- struct eigrp_nexthop_entry *head =
+ struct eigrp_route_descriptor *head =
listnode_head(prefix->entries);
listnode_delete(prefix->rij, entry->adv_router);
@@ -322,7 +324,7 @@ eigrp_get_fsm_event(struct eigrp_fsm_action_message *msg)
return EIGRP_FSM_EVENT_LR_FCN;
} else if (msg->packet_type == EIGRP_OPC_QUERY
&& (entry->flags
- & EIGRP_NEXTHOP_ENTRY_SUCCESSOR_FLAG)) {
+ & EIGRP_ROUTE_DESCRIPTOR_SUCCESSOR_FLAG)) {
return EIGRP_FSM_EVENT_QACT;
}
@@ -332,14 +334,14 @@ eigrp_get_fsm_event(struct eigrp_fsm_action_message *msg)
}
case EIGRP_FSM_STATE_ACTIVE_1: {
if (msg->packet_type == EIGRP_OPC_QUERY
- && (entry->flags & EIGRP_NEXTHOP_ENTRY_SUCCESSOR_FLAG)) {
+ && (entry->flags & EIGRP_ROUTE_DESCRIPTOR_SUCCESSOR_FLAG)) {
return EIGRP_FSM_EVENT_QACT;
} else if (msg->packet_type == EIGRP_OPC_REPLY) {
listnode_delete(prefix->rij, entry->adv_router);
if (change == METRIC_INCREASE
&& (entry->flags
- & EIGRP_NEXTHOP_ENTRY_SUCCESSOR_FLAG)) {
+ & EIGRP_ROUTE_DESCRIPTOR_SUCCESSOR_FLAG)) {
return EIGRP_FSM_EVENT_DINC;
} else if (prefix->rij->count) {
return EIGRP_FSM_KEEP_STATE;
@@ -350,7 +352,7 @@ eigrp_get_fsm_event(struct eigrp_fsm_action_message *msg)
} else if (msg->packet_type == EIGRP_OPC_UPDATE
&& change == METRIC_INCREASE
&& (entry->flags
- & EIGRP_NEXTHOP_ENTRY_SUCCESSOR_FLAG)) {
+ & EIGRP_ROUTE_DESCRIPTOR_SUCCESSOR_FLAG)) {
return EIGRP_FSM_EVENT_DINC;
}
return EIGRP_FSM_KEEP_STATE;
@@ -359,7 +361,7 @@ eigrp_get_fsm_event(struct eigrp_fsm_action_message *msg)
}
case EIGRP_FSM_STATE_ACTIVE_2: {
if (msg->packet_type == EIGRP_OPC_REPLY) {
- struct eigrp_nexthop_entry *head =
+ struct eigrp_route_descriptor *head =
listnode_head(prefix->entries);
listnode_delete(prefix->rij, entry->adv_router);
@@ -385,7 +387,7 @@ eigrp_get_fsm_event(struct eigrp_fsm_action_message *msg)
if (change == METRIC_INCREASE
&& (entry->flags
- & EIGRP_NEXTHOP_ENTRY_SUCCESSOR_FLAG)) {
+ & EIGRP_ROUTE_DESCRIPTOR_SUCCESSOR_FLAG)) {
return EIGRP_FSM_EVENT_DINC;
} else if (prefix->rij->count) {
return EIGRP_FSM_KEEP_STATE;
@@ -396,7 +398,7 @@ eigrp_get_fsm_event(struct eigrp_fsm_action_message *msg)
} else if (msg->packet_type == EIGRP_OPC_UPDATE
&& change == METRIC_INCREASE
&& (entry->flags
- & EIGRP_NEXTHOP_ENTRY_SUCCESSOR_FLAG)) {
+ & EIGRP_ROUTE_DESCRIPTOR_SUCCESSOR_FLAG)) {
return EIGRP_FSM_EVENT_DINC;
}
return EIGRP_FSM_KEEP_STATE;
@@ -434,9 +436,9 @@ int eigrp_fsm_event(struct eigrp_fsm_action_message *msg)
int eigrp_fsm_event_nq_fcn(struct eigrp_fsm_action_message *msg)
{
struct eigrp *eigrp = msg->eigrp;
- struct eigrp_prefix_entry *prefix = msg->prefix;
+ struct eigrp_prefix_descriptor *prefix = msg->prefix;
struct list *successors = eigrp_topology_get_successor(prefix);
- struct eigrp_nexthop_entry *ne;
+ struct eigrp_route_descriptor *ne;
assert(successors); // If this is NULL we have shit the bed, fun huh?
@@ -461,9 +463,9 @@ int eigrp_fsm_event_nq_fcn(struct eigrp_fsm_action_message *msg)
int eigrp_fsm_event_q_fcn(struct eigrp_fsm_action_message *msg)
{
struct eigrp *eigrp = msg->eigrp;
- struct eigrp_prefix_entry *prefix = msg->prefix;
+ struct eigrp_prefix_descriptor *prefix = msg->prefix;
struct list *successors = eigrp_topology_get_successor(prefix);
- struct eigrp_nexthop_entry *ne;
+ struct eigrp_route_descriptor *ne;
assert(successors); // If this is NULL somebody poked us in the eye.
@@ -487,8 +489,8 @@ int eigrp_fsm_event_q_fcn(struct eigrp_fsm_action_message *msg)
int eigrp_fsm_event_keep_state(struct eigrp_fsm_action_message *msg)
{
struct eigrp *eigrp = msg->eigrp;
- struct eigrp_prefix_entry *prefix = msg->prefix;
- struct eigrp_nexthop_entry *ne = listnode_head(prefix->entries);
+ struct eigrp_prefix_descriptor *prefix = msg->prefix;
+ struct eigrp_route_descriptor *ne = listnode_head(prefix->entries);
if (prefix->state == EIGRP_FSM_STATE_PASSIVE) {
if (!eigrp_metrics_is_same(prefix->reported_metric,
@@ -515,8 +517,8 @@ int eigrp_fsm_event_keep_state(struct eigrp_fsm_action_message *msg)
int eigrp_fsm_event_lr(struct eigrp_fsm_action_message *msg)
{
struct eigrp *eigrp = msg->eigrp;
- struct eigrp_prefix_entry *prefix = msg->prefix;
- struct eigrp_nexthop_entry *ne = listnode_head(prefix->entries);
+ struct eigrp_prefix_descriptor *prefix = msg->prefix;
+ struct eigrp_route_descriptor *ne = listnode_head(prefix->entries);
prefix->fdistance = prefix->distance = prefix->rdistance = ne->distance;
prefix->reported_metric = ne->total_metric;
@@ -545,7 +547,7 @@ int eigrp_fsm_event_lr(struct eigrp_fsm_action_message *msg)
int eigrp_fsm_event_dinc(struct eigrp_fsm_action_message *msg)
{
struct list *successors = eigrp_topology_get_successor(msg->prefix);
- struct eigrp_nexthop_entry *ne;
+ struct eigrp_route_descriptor *ne;
assert(successors); // Trump and his big hands
@@ -566,8 +568,8 @@ int eigrp_fsm_event_dinc(struct eigrp_fsm_action_message *msg)
int eigrp_fsm_event_lr_fcs(struct eigrp_fsm_action_message *msg)
{
struct eigrp *eigrp = msg->eigrp;
- struct eigrp_prefix_entry *prefix = msg->prefix;
- struct eigrp_nexthop_entry *ne = listnode_head(prefix->entries);
+ struct eigrp_prefix_descriptor *prefix = msg->prefix;
+ struct eigrp_route_descriptor *ne = listnode_head(prefix->entries);
prefix->state = EIGRP_FSM_STATE_PASSIVE;
prefix->distance = prefix->rdistance = ne->distance;
@@ -598,8 +600,8 @@ int eigrp_fsm_event_lr_fcs(struct eigrp_fsm_action_message *msg)
int eigrp_fsm_event_lr_fcn(struct eigrp_fsm_action_message *msg)
{
struct eigrp *eigrp = msg->eigrp;
- struct eigrp_prefix_entry *prefix = msg->prefix;
- struct eigrp_nexthop_entry *best_successor;
+ struct eigrp_prefix_descriptor *prefix = msg->prefix;
+ struct eigrp_route_descriptor *best_successor;
struct list *successors = eigrp_topology_get_successor(prefix);
assert(successors); // Routing without a stack
@@ -628,7 +630,7 @@ int eigrp_fsm_event_lr_fcn(struct eigrp_fsm_action_message *msg)
int eigrp_fsm_event_qact(struct eigrp_fsm_action_message *msg)
{
struct list *successors = eigrp_topology_get_successor(msg->prefix);
- struct eigrp_nexthop_entry *ne;
+ struct eigrp_route_descriptor *ne;
assert(successors); // Cats and no Dogs
diff --git a/eigrpd/eigrp_interface.c b/eigrpd/eigrp_interface.c
index dd43dd0478..74eff958da 100644
--- a/eigrpd/eigrp_interface.c
+++ b/eigrpd/eigrp_interface.c
@@ -55,6 +55,8 @@
#include "eigrpd/eigrp_memory.h"
#include "eigrpd/eigrp_fsm.h"
#include "eigrpd/eigrp_dump.h"
+#include "eigrpd/eigrp_types.h"
+#include "eigrpd/eigrp_metric.h"
struct eigrp_interface *eigrp_if_new(struct eigrp *eigrp, struct interface *ifp,
struct prefix *p)
@@ -229,8 +231,8 @@ void eigrp_del_if_params(struct eigrp_if_params *eip)
int eigrp_if_up(struct eigrp_interface *ei)
{
- struct eigrp_prefix_entry *pe;
- struct eigrp_nexthop_entry *ne;
+ struct eigrp_prefix_descriptor *pe;
+ struct eigrp_route_descriptor *ne;
struct eigrp_metrics metric;
struct eigrp_interface *ei2;
struct listnode *node, *nnode;
@@ -263,14 +265,14 @@ int eigrp_if_up(struct eigrp_interface *ei)
/*Add connected entry to topology table*/
- ne = eigrp_nexthop_entry_new();
+ ne = eigrp_route_descriptor_new();
ne->ei = ei;
ne->reported_metric = metric;
ne->total_metric = metric;
ne->distance = eigrp_calculate_metrics(eigrp, metric);
ne->reported_distance = 0;
ne->adv_router = eigrp->neighbor_self;
- ne->flags = EIGRP_NEXTHOP_ENTRY_SUCCESSOR_FLAG;
+ ne->flags = EIGRP_ROUTE_DESCRIPTOR_SUCCESSOR_FLAG;
struct prefix dest_addr;
@@ -280,7 +282,7 @@ int eigrp_if_up(struct eigrp_interface *ei)
&dest_addr);
if (pe == NULL) {
- pe = eigrp_prefix_entry_new();
+ pe = eigrp_prefix_descriptor_new();
pe->serno = eigrp->serno;
pe->destination = (struct prefix *)prefix_ipv4_new();
prefix_copy(pe->destination, &dest_addr);
@@ -292,10 +294,10 @@ int eigrp_if_up(struct eigrp_interface *ei)
pe->state = EIGRP_FSM_STATE_PASSIVE;
pe->fdistance = eigrp_calculate_metrics(eigrp, metric);
pe->req_action |= EIGRP_FSM_NEED_UPDATE;
- eigrp_prefix_entry_add(eigrp->topology_table, pe);
+ eigrp_prefix_descriptor_add(eigrp->topology_table, pe);
listnode_add(eigrp->topology_changes_internalIPV4, pe);
- eigrp_nexthop_entry_add(eigrp, pe, ne);
+ eigrp_route_descriptor_add(eigrp, pe, ne);
for (ALL_LIST_ELEMENTS(eigrp->eiflist, node, nnode, ei2)) {
eigrp_update_send(ei2);
@@ -307,7 +309,7 @@ int eigrp_if_up(struct eigrp_interface *ei)
struct eigrp_fsm_action_message msg;
ne->prefix = pe;
- eigrp_nexthop_entry_add(eigrp, pe, ne);
+ eigrp_route_descriptor_add(eigrp, pe, ne);
msg.packet_type = EIGRP_OPC_UPDATE;
msg.eigrp = eigrp;
@@ -416,7 +418,7 @@ uint8_t eigrp_default_iftype(struct interface *ifp)
void eigrp_if_free(struct eigrp_interface *ei, int source)
{
struct prefix dest_addr;
- struct eigrp_prefix_entry *pe;
+ struct eigrp_prefix_descriptor *pe;
struct eigrp *eigrp = ei->eigrp;
if (source == INTERFACE_DOWN_BY_VTY) {
@@ -429,7 +431,8 @@ void eigrp_if_free(struct eigrp_interface *ei, int source)
pe = eigrp_topology_table_lookup_ipv4(eigrp->topology_table,
&dest_addr);
if (pe)
- eigrp_prefix_entry_delete(eigrp, eigrp->topology_table, pe);
+ eigrp_prefix_descriptor_delete(eigrp, eigrp->topology_table,
+ pe);
eigrp_if_down(ei);
@@ -494,33 +497,3 @@ struct eigrp_interface *eigrp_if_lookup_by_name(struct eigrp *eigrp,
return NULL;
}
-
-uint32_t eigrp_bandwidth_to_scaled(uint32_t bandwidth)
-{
- uint64_t temp_bandwidth = (256ull * 10000000) / bandwidth;
-
- temp_bandwidth = temp_bandwidth < EIGRP_MAX_METRIC ? temp_bandwidth
- : EIGRP_MAX_METRIC;
-
- return (uint32_t)temp_bandwidth;
-}
-
-uint32_t eigrp_scaled_to_bandwidth(uint32_t scaled)
-{
- uint64_t temp_scaled = scaled * (256ull * 10000000);
-
- temp_scaled =
- temp_scaled < EIGRP_MAX_METRIC ? temp_scaled : EIGRP_MAX_METRIC;
-
- return (uint32_t)temp_scaled;
-}
-
-uint32_t eigrp_delay_to_scaled(uint32_t delay)
-{
- return delay * 256;
-}
-
-uint32_t eigrp_scaled_to_delay(uint32_t scaled)
-{
- return scaled / 256;
-}
diff --git a/eigrpd/eigrp_interface.h b/eigrpd/eigrp_interface.h
index 1e66dafde2..68ab5125e3 100644
--- a/eigrpd/eigrp_interface.h
+++ b/eigrpd/eigrp_interface.h
@@ -58,9 +58,4 @@ extern struct eigrp_interface *eigrp_if_lookup_by_name(struct eigrp *,
/* Simulate down/up on the interface. */
extern void eigrp_if_reset(struct interface *);
-extern uint32_t eigrp_bandwidth_to_scaled(uint32_t);
-extern uint32_t eigrp_scaled_to_bandwidth(uint32_t);
-extern uint32_t eigrp_delay_to_scaled(uint32_t);
-extern uint32_t eigrp_scaled_to_delay(uint32_t);
-
#endif /* ZEBRA_EIGRP_INTERFACE_H_ */
diff --git a/eigrpd/eigrp_main.c b/eigrpd/eigrp_main.c
index 6c44ce361c..b1a6498cbc 100644
--- a/eigrpd/eigrp_main.c
+++ b/eigrpd/eigrp_main.c
@@ -66,6 +66,8 @@
#include "eigrpd/eigrp_filter.h"
#include "eigrpd/eigrp_errors.h"
#include "eigrpd/eigrp_vrf.h"
+#include "eigrpd/eigrp_cli.h"
+#include "eigrpd/eigrp_yang.h"
//#include "eigrpd/eigrp_routemap.h"
/* eigprd privileges */
diff --git a/eigrpd/eigrp_memory.c b/eigrpd/eigrp_memory.c
index 85b14c28ce..57ca785340 100644
--- a/eigrpd/eigrp_memory.c
+++ b/eigrpd/eigrp_memory.c
@@ -37,6 +37,6 @@ DEFINE_MTYPE(EIGRPD, EIGRP_IPV4_INT_TLV, "EIGRP IPv4 TLV")
DEFINE_MTYPE(EIGRPD, EIGRP_SEQ_TLV, "EIGRP SEQ TLV")
DEFINE_MTYPE(EIGRPD, EIGRP_AUTH_TLV, "EIGRP AUTH TLV")
DEFINE_MTYPE(EIGRPD, EIGRP_AUTH_SHA256_TLV, "EIGRP SHA TLV")
-DEFINE_MTYPE(EIGRPD, EIGRP_PREFIX_ENTRY, "EIGRP Prefix")
-DEFINE_MTYPE(EIGRPD, EIGRP_NEXTHOP_ENTRY, "EIGRP Nexthop Entry")
+DEFINE_MTYPE(EIGRPD, EIGRP_PREFIX_DESCRIPTOR, "EIGRP Prefix")
+DEFINE_MTYPE(EIGRPD, EIGRP_ROUTE_DESCRIPTOR, "EIGRP Nexthop Entry")
DEFINE_MTYPE(EIGRPD, EIGRP_FSM_MSG, "EIGRP FSM Message")
diff --git a/eigrpd/eigrp_memory.h b/eigrpd/eigrp_memory.h
index e4d02c09d4..21ecba2aae 100644
--- a/eigrpd/eigrp_memory.h
+++ b/eigrpd/eigrp_memory.h
@@ -36,8 +36,8 @@ DECLARE_MTYPE(EIGRP_IPV4_INT_TLV)
DECLARE_MTYPE(EIGRP_SEQ_TLV)
DECLARE_MTYPE(EIGRP_AUTH_TLV)
DECLARE_MTYPE(EIGRP_AUTH_SHA256_TLV)
-DECLARE_MTYPE(EIGRP_PREFIX_ENTRY)
-DECLARE_MTYPE(EIGRP_NEXTHOP_ENTRY)
+DECLARE_MTYPE(EIGRP_PREFIX_DESCRIPTOR)
+DECLARE_MTYPE(EIGRP_ROUTE_DESCRIPTOR)
DECLARE_MTYPE(EIGRP_FSM_MSG)
#endif /* _FRR_EIGRP_MEMORY_H */
diff --git a/eigrpd/eigrp_metric.c b/eigrpd/eigrp_metric.c
new file mode 100644
index 0000000000..2b05db71d5
--- /dev/null
+++ b/eigrpd/eigrp_metric.c
@@ -0,0 +1,146 @@
+/*
+ * EIGRP Metric Math Functions.
+ * Copyright (C) 2013-2016
+ * Authors:
+ * Donnie Savage
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; see the file COPYING; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "eigrpd/eigrp_structs.h"
+#include "eigrpd/eigrpd.h"
+#include "eigrpd/eigrp_types.h"
+#include "eigrpd/eigrp_metric.h"
+
+eigrp_scaled_t eigrp_bandwidth_to_scaled(eigrp_bandwidth_t bandwidth)
+{
+ eigrp_bandwidth_t scaled = EIGRP_BANDWIDTH_MAX;
+
+ if (bandwidth != EIGRP_BANDWIDTH_MAX) {
+ scaled = (EIGRP_CLASSIC_SCALER * EIGRP_BANDWIDTH_SCALER);
+ scaled = scaled / bandwidth;
+
+ scaled = scaled ? scaled : EIGRP_BANDWIDTH_MIN;
+ }
+
+ scaled = (scaled < EIGRP_METRIC_MAX) ? scaled : EIGRP_METRIC_MAX;
+ return (eigrp_scaled_t)scaled;
+}
+
+eigrp_bandwidth_t eigrp_scaled_to_bandwidth(eigrp_scaled_t scaled)
+{
+ eigrp_bandwidth_t bandwidth = EIGRP_BANDWIDTH_MAX;
+
+ if (scaled != EIGRP_CLASSIC_MAX) {
+ bandwidth = (EIGRP_CLASSIC_SCALER * EIGRP_BANDWIDTH_SCALER);
+ bandwidth = scaled * bandwidth;
+ bandwidth = (bandwidth < EIGRP_METRIC_MAX)
+ ? bandwidth
+ : EIGRP_BANDWIDTH_MAX;
+ }
+
+ return bandwidth;
+}
+
+eigrp_scaled_t eigrp_delay_to_scaled(eigrp_delay_t delay)
+{
+ delay = delay ? delay : EIGRP_DELAY_MIN;
+ return delay * EIGRP_CLASSIC_SCALER;
+}
+
+eigrp_delay_t eigrp_scaled_to_delay(eigrp_scaled_t scaled)
+{
+ scaled = scaled / EIGRP_CLASSIC_SCALER;
+ scaled = scaled ? scaled : EIGRP_DELAY_MIN;
+
+ return scaled;
+}
+
+eigrp_metric_t eigrp_calculate_metrics(struct eigrp *eigrp,
+ struct eigrp_metrics metric)
+{
+ eigrp_metric_t composite = 0;
+
+ if (metric.delay == EIGRP_MAX_METRIC)
+ return EIGRP_METRIC_MAX;
+
+ /*
+ * EIGRP Composite =
+ * {K1*BW+[(K2*BW)/(256-load)]+(K3*delay)}*{K5/(reliability+K4)}
+ */
+
+ if (eigrp->k_values[0])
+ composite += (eigrp->k_values[0] * metric.bandwidth);
+ if (eigrp->k_values[1])
+ composite += ((eigrp->k_values[1] * metric.bandwidth)
+ / (256 - metric.load));
+ if (eigrp->k_values[2])
+ composite += (eigrp->k_values[2] * metric.delay);
+ if (eigrp->k_values[3] && !eigrp->k_values[4])
+ composite *= eigrp->k_values[3];
+ if (!eigrp->k_values[3] && eigrp->k_values[4])
+ composite *= (eigrp->k_values[4] / metric.reliability);
+ if (eigrp->k_values[3] && eigrp->k_values[4])
+ composite *= ((eigrp->k_values[4] / metric.reliability)
+ + eigrp->k_values[3]);
+
+ composite =
+ (composite <= EIGRP_METRIC_MAX) ? composite : EIGRP_METRIC_MAX;
+
+ return composite;
+}
+
+eigrp_metric_t
+eigrp_calculate_total_metrics(struct eigrp *eigrp,
+ struct eigrp_route_descriptor *entry)
+{
+ struct eigrp_interface *ei = entry->ei;
+ eigrp_delay_t temp_delay;
+ eigrp_bandwidth_t bw;
+
+ entry->total_metric = entry->reported_metric;
+ temp_delay = entry->total_metric.delay
+ + eigrp_delay_to_scaled(ei->params.delay);
+
+ entry->total_metric.delay = temp_delay > EIGRP_METRIC_MAX_CLASSIC
+ ? EIGRP_METRIC_MAX_CLASSIC
+ : temp_delay;
+
+ bw = eigrp_bandwidth_to_scaled(ei->params.bandwidth);
+ entry->total_metric.bandwidth = entry->total_metric.bandwidth > bw
+ ? bw
+ : entry->total_metric.bandwidth;
+
+ return eigrp_calculate_metrics(eigrp, entry->total_metric);
+}
+
+bool eigrp_metrics_is_same(struct eigrp_metrics metric1,
+ struct eigrp_metrics metric2)
+{
+ if ((metric1.bandwidth == metric2.bandwidth)
+ && (metric1.delay == metric2.delay)
+ && (metric1.hop_count == metric2.hop_count)
+ && (metric1.load == metric2.load)
+ && (metric1.reliability == metric2.reliability)
+ && (metric1.mtu[0] == metric2.mtu[0])
+ && (metric1.mtu[1] == metric2.mtu[1])
+ && (metric1.mtu[2] == metric2.mtu[2])) {
+ return true;
+ }
+
+ return false; /* if different */
+}
diff --git a/eigrpd/eigrp_metric.h b/eigrpd/eigrp_metric.h
new file mode 100644
index 0000000000..8e9cd66747
--- /dev/null
+++ b/eigrpd/eigrp_metric.h
@@ -0,0 +1,63 @@
+/*
+ * EIGRP Metric Math Functions.
+ * Copyright (C) 2013-2016
+ * Authors:
+ * Donnie Savage
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; see the file COPYING; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef _ZEBRA_EIGRP_METRIC_H_
+#define _ZEBRA_EIGRP_METRIC_H_
+
+/* Constants */
+#define EIGRP_BANDWIDTH_MIN 0x1ull /* 1 */
+#define EIGRP_BANDWIDTH_SCALER 10000000ull /* Inversion value */
+#define EIGRP_BANDWIDTH_MAX 0xffffffffffffffffull /* 1.84467441x10^19 */
+
+#define EIGRP_DELAY_MIN 0x1ull /* 1 */
+#define EIGRP_DELAY_PICO 1000000ull
+#define EIGRP_DELAY_MAX 0xffffffffffffffffull /* 1.84467441x10^19 */
+
+#define EIGRP_MAX_LOAD 256
+#define EIGRP_MAX_HOPS 100
+
+#define EIGRP_INACCESSIBLE 0xFFFFFFFFFFFFFFFFull
+
+#define EIGRP_METRIC_MAX 0xffffffffffffffffull /* 1.84467441x10^19 */
+#define EIGRP_METRIC_MAX_CLASSIC 0xffffffff
+#define EIGRP_METRIC_SCALER 65536 /* CLASSIC to WIDE conversion */
+
+#define EIGRP_CLASSIC_MAX 0xffffffff /* 4294967295 */
+#define EIGRP_CLASSIC_SCALER 256 /* IGRP to EIGRP conversion */
+
+
+/* Prototypes */
+extern eigrp_scaled_t eigrp_bandwidth_to_scaled(eigrp_bandwidth_t bw);
+extern eigrp_bandwidth_t eigrp_scaled_to_bandwidth(eigrp_scaled_t scale);
+extern eigrp_scaled_t eigrp_delay_to_scaled(eigrp_delay_t delay);
+extern eigrp_delay_t eigrp_scaled_to_delay(eigrp_scaled_t scale);
+
+extern eigrp_metric_t eigrp_calculate_metrics(struct eigrp *eigrp,
+ struct eigrp_metrics metric);
+extern eigrp_metric_t
+eigrp_calculate_total_metrics(struct eigrp *eigrp,
+ struct eigrp_route_descriptor *rd);
+extern bool eigrp_metrics_is_same(struct eigrp_metrics m1,
+ struct eigrp_metrics m2);
+
+#endif /* _ZEBRA_EIGRP_METRIC_H_ */
diff --git a/eigrpd/eigrp_neighbor.c b/eigrpd/eigrp_neighbor.c
index 2d5bb0a7d1..1da2f7a108 100644
--- a/eigrpd/eigrp_neighbor.c
+++ b/eigrpd/eigrp_neighbor.c
@@ -343,7 +343,7 @@ void eigrp_nbr_hard_restart(struct eigrp_neighbor *nbr, struct vty *vty)
eigrp_nbr_delete(nbr);
}
-int eigrp_nbr_split_horizon_check(struct eigrp_nexthop_entry *ne,
+int eigrp_nbr_split_horizon_check(struct eigrp_route_descriptor *ne,
struct eigrp_interface *ei)
{
if (ne->distance == EIGRP_MAX_METRIC)
diff --git a/eigrpd/eigrp_neighbor.h b/eigrpd/eigrp_neighbor.h
index 1c308fa981..80ab1eded5 100644
--- a/eigrpd/eigrp_neighbor.h
+++ b/eigrpd/eigrp_neighbor.h
@@ -54,6 +54,6 @@ extern struct eigrp_neighbor *
eigrp_nbr_lookup_by_addr_process(struct eigrp *eigrp, struct in_addr addr);
extern void eigrp_nbr_hard_restart(struct eigrp_neighbor *nbr, struct vty *vty);
-extern int eigrp_nbr_split_horizon_check(struct eigrp_nexthop_entry *ne,
+extern int eigrp_nbr_split_horizon_check(struct eigrp_route_descriptor *ne,
struct eigrp_interface *ei);
#endif /* _ZEBRA_EIGRP_NEIGHBOR_H */
diff --git a/eigrpd/eigrp_network.c b/eigrpd/eigrp_network.c
index 51b4998959..69dcc20253 100644
--- a/eigrpd/eigrp_network.c
+++ b/eigrpd/eigrp_network.c
@@ -346,76 +346,6 @@ int eigrp_network_unset(struct eigrp *eigrp, struct prefix *p)
return 1;
}
-uint32_t eigrp_calculate_metrics(struct eigrp *eigrp,
- struct eigrp_metrics metric)
-{
- uint64_t temp_metric;
- temp_metric = 0;
-
- if (metric.delay == EIGRP_MAX_METRIC)
- return EIGRP_MAX_METRIC;
-
- // EIGRP Metric =
- // {K1*BW+[(K2*BW)/(256-load)]+(K3*delay)}*{K5/(reliability+K4)}
-
- if (eigrp->k_values[0])
- temp_metric += (eigrp->k_values[0] * metric.bandwidth);
- if (eigrp->k_values[1])
- temp_metric += ((eigrp->k_values[1] * metric.bandwidth)
- / (256 - metric.load));
- if (eigrp->k_values[2])
- temp_metric += (eigrp->k_values[2] * metric.delay);
- if (eigrp->k_values[3] && !eigrp->k_values[4])
- temp_metric *= eigrp->k_values[3];
- if (!eigrp->k_values[3] && eigrp->k_values[4])
- temp_metric *= (eigrp->k_values[4] / metric.reliability);
- if (eigrp->k_values[3] && eigrp->k_values[4])
- temp_metric *= ((eigrp->k_values[4] / metric.reliability)
- + eigrp->k_values[3]);
-
- if (temp_metric <= EIGRP_MAX_METRIC)
- return (uint32_t)temp_metric;
- else
- return EIGRP_MAX_METRIC;
-}
-
-uint32_t eigrp_calculate_total_metrics(struct eigrp *eigrp,
- struct eigrp_nexthop_entry *entry)
-{
- struct eigrp_interface *ei = entry->ei;
-
- entry->total_metric = entry->reported_metric;
- uint64_t temp_delay =
- (uint64_t)entry->total_metric.delay
- + (uint64_t)eigrp_delay_to_scaled(ei->params.delay);
- entry->total_metric.delay = temp_delay > EIGRP_MAX_METRIC
- ? EIGRP_MAX_METRIC
- : (uint32_t)temp_delay;
-
- uint32_t bw = eigrp_bandwidth_to_scaled(ei->params.bandwidth);
- entry->total_metric.bandwidth = entry->total_metric.bandwidth > bw
- ? bw
- : entry->total_metric.bandwidth;
-
- return eigrp_calculate_metrics(eigrp, entry->total_metric);
-}
-
-uint8_t eigrp_metrics_is_same(struct eigrp_metrics metric1,
- struct eigrp_metrics metric2)
-{
- if ((metric1.bandwidth == metric2.bandwidth)
- && (metric1.delay == metric2.delay)
- && (metric1.hop_count == metric2.hop_count)
- && (metric1.load == metric2.load)
- && (metric1.reliability == metric2.reliability)
- && (metric1.mtu[0] == metric2.mtu[0])
- && (metric1.mtu[1] == metric2.mtu[1])
- && (metric1.mtu[2] == metric2.mtu[2]))
- return 1;
-
- return 0; // if different
-}
-
void eigrp_external_routes_refresh(struct eigrp *eigrp, int type)
{
}
diff --git a/eigrpd/eigrp_network.h b/eigrpd/eigrp_network.h
index 7839fc946b..eeb32ba356 100644
--- a/eigrpd/eigrp_network.h
+++ b/eigrpd/eigrp_network.h
@@ -43,11 +43,6 @@ extern int eigrp_if_drop_allspfrouters(struct eigrp *top, struct prefix *p,
unsigned int ifindex);
extern void eigrp_adjust_sndbuflen(struct eigrp *, unsigned int);
-extern uint32_t eigrp_calculate_metrics(struct eigrp *, struct eigrp_metrics);
-extern uint32_t eigrp_calculate_total_metrics(struct eigrp *,
- struct eigrp_nexthop_entry *);
-extern uint8_t eigrp_metrics_is_same(struct eigrp_metrics,
- struct eigrp_metrics);
extern void eigrp_external_routes_refresh(struct eigrp *, int);
#endif /* EIGRP_NETWORK_H_ */
diff --git a/eigrpd/eigrp_northbound.c b/eigrpd/eigrp_northbound.c
index 5b87f72640..482667f633 100644
--- a/eigrpd/eigrp_northbound.c
+++ b/eigrpd/eigrp_northbound.c
@@ -34,6 +34,7 @@
#include "eigrp_interface.h"
#include "eigrp_network.h"
#include "eigrp_zebra.h"
+#include "eigrp_cli.h"
/* Helper functions. */
static void redistribute_get_metrics(const struct lyd_node *dnode,
diff --git a/eigrpd/eigrp_packet.c b/eigrpd/eigrp_packet.c
index f5f6ab5dff..252cd647a2 100644
--- a/eigrpd/eigrp_packet.c
+++ b/eigrpd/eigrp_packet.c
@@ -1144,7 +1144,7 @@ struct TLV_IPv4_Internal_type *eigrp_read_ipv4_tlv(struct stream *s)
}
uint16_t eigrp_add_internalTLV_to_stream(struct stream *s,
- struct eigrp_prefix_entry *pe)
+ struct eigrp_prefix_descriptor *pe)
{
uint16_t length;
diff --git a/eigrpd/eigrp_packet.h b/eigrpd/eigrp_packet.h
index f354615fdb..cb69bc26b2 100644
--- a/eigrpd/eigrp_packet.h
+++ b/eigrpd/eigrp_packet.h
@@ -36,48 +36,51 @@
extern int eigrp_read(struct thread *);
extern int eigrp_write(struct thread *);
-extern struct eigrp_packet *eigrp_packet_new(size_t, struct eigrp_neighbor *);
-extern struct eigrp_packet *eigrp_packet_duplicate(struct eigrp_packet *,
- struct eigrp_neighbor *);
-extern void eigrp_packet_free(struct eigrp_packet *);
-extern void eigrp_packet_delete(struct eigrp_interface *);
-extern void eigrp_packet_header_init(int, struct eigrp *, struct stream *,
- uint32_t, uint32_t, uint32_t);
-extern void eigrp_packet_checksum(struct eigrp_interface *, struct stream *,
- uint16_t);
+extern struct eigrp_packet *eigrp_packet_new(size_t size,
+ struct eigrp_neighbor *nbr);
+extern struct eigrp_packet *eigrp_packet_duplicate(struct eigrp_packet *old,
+ struct eigrp_neighbor *nbr);
+extern void eigrp_packet_free(struct eigrp_packet *ep);
+extern void eigrp_packet_delete(struct eigrp_interface *ei);
+extern void eigrp_packet_header_init(int type, struct eigrp *eigrp,
+ struct stream *s, uint32_t flags,
+ uint32_t sequence, uint32_t ack);
+extern void eigrp_packet_checksum(struct eigrp_interface *ei, struct stream *s,
+ uint16_t length);
extern struct eigrp_fifo *eigrp_fifo_new(void);
-extern struct eigrp_packet *eigrp_fifo_next(struct eigrp_fifo *);
-extern struct eigrp_packet *eigrp_fifo_pop(struct eigrp_fifo *);
-extern void eigrp_fifo_push(struct eigrp_fifo *, struct eigrp_packet *);
-extern void eigrp_fifo_free(struct eigrp_fifo *);
-extern void eigrp_fifo_reset(struct eigrp_fifo *);
-
-extern void eigrp_send_packet_reliably(struct eigrp_neighbor *);
-
-extern struct TLV_IPv4_Internal_type *eigrp_read_ipv4_tlv(struct stream *);
-extern uint16_t eigrp_add_internalTLV_to_stream(struct stream *,
- struct eigrp_prefix_entry *);
-extern uint16_t eigrp_add_authTLV_MD5_to_stream(struct stream *,
- struct eigrp_interface *);
-extern uint16_t eigrp_add_authTLV_SHA256_to_stream(struct stream *,
- struct eigrp_interface *);
-
-extern int eigrp_unack_packet_retrans(struct thread *);
-extern int eigrp_unack_multicast_packet_retrans(struct thread *);
+extern struct eigrp_packet *eigrp_fifo_next(struct eigrp_fifo *fifo);
+extern struct eigrp_packet *eigrp_fifo_pop(struct eigrp_fifo *fifo);
+extern void eigrp_fifo_push(struct eigrp_fifo *fifo, struct eigrp_packet *ep);
+extern void eigrp_fifo_free(struct eigrp_fifo *fifo);
+extern void eigrp_fifo_reset(struct eigrp_fifo *fifo);
+
+extern void eigrp_send_packet_reliably(struct eigrp_neighbor *nbr);
+
+extern struct TLV_IPv4_Internal_type *eigrp_read_ipv4_tlv(struct stream *s);
+extern uint16_t
+eigrp_add_internalTLV_to_stream(struct stream *s,
+ struct eigrp_prefix_descriptor *pe);
+extern uint16_t eigrp_add_authTLV_MD5_to_stream(struct stream *s,
+ struct eigrp_interface *ei);
+extern uint16_t eigrp_add_authTLV_SHA256_to_stream(struct stream *s,
+ struct eigrp_interface *ei);
+
+extern int eigrp_unack_packet_retrans(struct thread *thread);
+extern int eigrp_unack_multicast_packet_retrans(struct thread *thread);
/*
* untill there is reason to have their own header, these externs are found in
* eigrp_hello.c
*/
extern void eigrp_sw_version_initialize(void);
-extern void eigrp_hello_send(struct eigrp_interface *, uint8_t,
- struct in_addr *);
-extern void eigrp_hello_send_ack(struct eigrp_neighbor *);
-extern void eigrp_hello_receive(struct eigrp *, struct ip *,
- struct eigrp_header *, struct stream *,
- struct eigrp_interface *, int);
-extern int eigrp_hello_timer(struct thread *);
+extern void eigrp_hello_send(struct eigrp_interface *ei, uint8_t flags,
+ struct in_addr *nbr_addr);
+extern void eigrp_hello_send_ack(struct eigrp_neighbor *nbr);
+extern void eigrp_hello_receive(struct eigrp *eigrp, struct ip *iph,
+ struct eigrp_header *eigrph, struct stream *s,
+ struct eigrp_interface *ei, int size);
+extern int eigrp_hello_timer(struct thread *thread);
/*
* These externs are found in eigrp_update.c
@@ -85,76 +88,83 @@ extern int eigrp_hello_timer(struct thread *);
extern bool eigrp_update_prefix_apply(struct eigrp *eigrp,
struct eigrp_interface *ei, int in,
struct prefix *prefix);
-extern void eigrp_update_send(struct eigrp_interface *);
-extern void eigrp_update_receive(struct eigrp *, struct ip *,
- struct eigrp_header *, struct stream *,
- struct eigrp_interface *, int);
-extern void eigrp_update_send_all(struct eigrp *, struct eigrp_interface *);
-extern void eigrp_update_send_init(struct eigrp_neighbor *);
-extern void eigrp_update_send_EOT(struct eigrp_neighbor *);
-extern int eigrp_update_send_GR_thread(struct thread *);
-extern void eigrp_update_send_GR(struct eigrp_neighbor *, enum GR_type,
- struct vty *);
-extern void eigrp_update_send_interface_GR(struct eigrp_interface *,
- enum GR_type, struct vty *);
-extern void eigrp_update_send_process_GR(struct eigrp *, enum GR_type,
- struct vty *);
+extern void eigrp_update_send(struct eigrp_interface *ei);
+extern void eigrp_update_receive(struct eigrp *eigrp, struct ip *iph,
+ struct eigrp_header *eigrph, struct stream *s,
+ struct eigrp_interface *ei, int size);
+extern void eigrp_update_send_all(struct eigrp *eigrp,
+ struct eigrp_interface *exception);
+extern void eigrp_update_send_init(struct eigrp_neighbor *nbr);
+extern void eigrp_update_send_EOT(struct eigrp_neighbor *nbr);
+extern int eigrp_update_send_GR_thread(struct thread *thread);
+extern void eigrp_update_send_GR(struct eigrp_neighbor *nbr,
+ enum GR_type gr_type, struct vty *vty);
+extern void eigrp_update_send_interface_GR(struct eigrp_interface *ei,
+ enum GR_type gr_type,
+ struct vty *vty);
+extern void eigrp_update_send_process_GR(struct eigrp *eigrp,
+ enum GR_type gr_type, struct vty *vty);
/*
* These externs are found in eigrp_query.c
*/
-extern void eigrp_send_query(struct eigrp_interface *);
-extern void eigrp_query_receive(struct eigrp *, struct ip *,
- struct eigrp_header *, struct stream *,
- struct eigrp_interface *, int);
-extern uint32_t eigrp_query_send_all(struct eigrp *);
+extern void eigrp_send_query(struct eigrp_interface *ei);
+extern void eigrp_query_receive(struct eigrp *eigrp, struct ip *iph,
+ struct eigrp_header *eigrph, struct stream *s,
+ struct eigrp_interface *ei, int size);
+extern uint32_t eigrp_query_send_all(struct eigrp *eigrp);
/*
* These externs are found in eigrp_reply.c
*/
-extern void eigrp_send_reply(struct eigrp_neighbor *,
- struct eigrp_prefix_entry *);
-extern void eigrp_reply_receive(struct eigrp *, struct ip *,
- struct eigrp_header *, struct stream *,
- struct eigrp_interface *, int);
+extern void eigrp_send_reply(struct eigrp_neighbor *nbr,
+ struct eigrp_prefix_descriptor *pe);
+extern void eigrp_reply_receive(struct eigrp *eigrp, struct ip *iph,
+ struct eigrp_header *eigrph, struct stream *s,
+ struct eigrp_interface *ei, int size);
/*
* These externs are found in eigrp_siaquery.c
*/
-extern void eigrp_send_siaquery(struct eigrp_neighbor *,
- struct eigrp_prefix_entry *);
-extern void eigrp_siaquery_receive(struct eigrp *, struct ip *,
- struct eigrp_header *, struct stream *,
- struct eigrp_interface *, int);
+extern void eigrp_send_siaquery(struct eigrp_neighbor *nbr,
+ struct eigrp_prefix_descriptor *pe);
+extern void eigrp_siaquery_receive(struct eigrp *eigrp, struct ip *iph,
+ struct eigrp_header *eigrph,
+ struct stream *s, struct eigrp_interface *ei,
+ int size);
/*
* These externs are found in eigrp_siareply.c
*/
-extern void eigrp_send_siareply(struct eigrp_neighbor *,
- struct eigrp_prefix_entry *);
-extern void eigrp_siareply_receive(struct eigrp *, struct ip *,
- struct eigrp_header *, struct stream *,
- struct eigrp_interface *, int);
+extern void eigrp_send_siareply(struct eigrp_neighbor *nbr,
+ struct eigrp_prefix_descriptor *pe);
+extern void eigrp_siareply_receive(struct eigrp *eigrp, struct ip *iph,
+ struct eigrp_header *eigrph,
+ struct stream *s, struct eigrp_interface *ei,
+ int size);
extern struct TLV_MD5_Authentication_Type *eigrp_authTLV_MD5_new(void);
-extern void eigrp_authTLV_MD5_free(struct TLV_MD5_Authentication_Type *);
+extern void eigrp_authTLV_MD5_free(struct TLV_MD5_Authentication_Type *authTLV);
extern struct TLV_SHA256_Authentication_Type *eigrp_authTLV_SHA256_new(void);
-extern void eigrp_authTLV_SHA256_free(struct TLV_SHA256_Authentication_Type *);
-
-extern int eigrp_make_md5_digest(struct eigrp_interface *, struct stream *,
- uint8_t);
-extern int eigrp_check_md5_digest(struct stream *,
- struct TLV_MD5_Authentication_Type *,
- struct eigrp_neighbor *, uint8_t);
-extern int eigrp_make_sha256_digest(struct eigrp_interface *, struct stream *,
- uint8_t);
-extern int eigrp_check_sha256_digest(struct stream *,
- struct TLV_SHA256_Authentication_Type *,
- struct eigrp_neighbor *, uint8_t);
-
-
-extern void eigrp_IPv4_InternalTLV_free(struct TLV_IPv4_Internal_type *);
+extern void
+eigrp_authTLV_SHA256_free(struct TLV_SHA256_Authentication_Type *authTLV);
+
+extern int eigrp_make_md5_digest(struct eigrp_interface *ei, struct stream *s,
+ uint8_t flags);
+extern int eigrp_check_md5_digest(struct stream *s,
+ struct TLV_MD5_Authentication_Type *authTLV,
+ struct eigrp_neighbor *nbr, uint8_t flags);
+extern int eigrp_make_sha256_digest(struct eigrp_interface *ei,
+ struct stream *s, uint8_t flags);
+extern int
+eigrp_check_sha256_digest(struct stream *s,
+ struct TLV_SHA256_Authentication_Type *authTLV,
+ struct eigrp_neighbor *nbr, uint8_t flags);
+
+
+extern void
+eigrp_IPv4_InternalTLV_free(struct TLV_IPv4_Internal_type *IPv4_InternalTLV);
extern struct TLV_Sequence_Type *eigrp_SequenceTLV_new(void);
diff --git a/eigrpd/eigrp_query.c b/eigrpd/eigrp_query.c
index 84dcf5e2d5..0ab7b59dbb 100644
--- a/eigrpd/eigrp_query.c
+++ b/eigrpd/eigrp_query.c
@@ -58,7 +58,7 @@ uint32_t eigrp_query_send_all(struct eigrp *eigrp)
{
struct eigrp_interface *iface;
struct listnode *node, *node2, *nnode2;
- struct eigrp_prefix_entry *pe;
+ struct eigrp_prefix_descriptor *pe;
uint32_t counter;
if (eigrp == NULL) {
@@ -118,7 +118,7 @@ void eigrp_query_receive(struct eigrp *eigrp, struct ip *iph,
dest_addr.family = AF_INET;
dest_addr.u.prefix4 = tlv->destination;
dest_addr.prefixlen = tlv->prefix_length;
- struct eigrp_prefix_entry *dest =
+ struct eigrp_prefix_descriptor *dest =
eigrp_topology_table_lookup_ipv4(
eigrp->topology_table, &dest_addr);
@@ -126,9 +126,9 @@ void eigrp_query_receive(struct eigrp *eigrp, struct ip *iph,
* know)*/
if (dest != NULL) {
struct eigrp_fsm_action_message msg;
- struct eigrp_nexthop_entry *entry =
- eigrp_prefix_entry_lookup(dest->entries,
- nbr);
+ struct eigrp_route_descriptor *entry =
+ eigrp_route_descriptor_lookup(
+ dest->entries, nbr);
msg.packet_type = EIGRP_OPC_QUERY;
msg.eigrp = eigrp;
msg.data_type = EIGRP_INT;
@@ -164,7 +164,7 @@ void eigrp_send_query(struct eigrp_interface *ei)
uint16_t length = EIGRP_HEADER_LEN;
struct listnode *node, *nnode, *node2, *nnode2;
struct eigrp_neighbor *nbr;
- struct eigrp_prefix_entry *pe;
+ struct eigrp_prefix_descriptor *pe;
bool has_tlv = false;
bool new_packet = true;
uint16_t eigrp_mtu = EIGRP_PACKET_MTU(ei->ifp->mtu);
diff --git a/eigrpd/eigrp_reply.c b/eigrpd/eigrp_reply.c
index 26bb27d7ac..d16482173c 100644
--- a/eigrpd/eigrp_reply.c
+++ b/eigrpd/eigrp_reply.c
@@ -61,20 +61,21 @@
#include "eigrpd/eigrp_memory.h"
#include "eigrpd/eigrp_errors.h"
-void eigrp_send_reply(struct eigrp_neighbor *nbr, struct eigrp_prefix_entry *pe)
+void eigrp_send_reply(struct eigrp_neighbor *nbr,
+ struct eigrp_prefix_descriptor *pe)
{
struct eigrp_packet *ep;
uint16_t length = EIGRP_HEADER_LEN;
struct eigrp_interface *ei = nbr->ei;
struct eigrp *eigrp = ei->eigrp;
- struct eigrp_prefix_entry *pe2;
+ struct eigrp_prefix_descriptor *pe2;
// TODO: Work in progress
/* Filtering */
/* get list from eigrp process */
- pe2 = XCALLOC(MTYPE_EIGRP_PREFIX_ENTRY,
- sizeof(struct eigrp_prefix_entry));
- memcpy(pe2, pe, sizeof(struct eigrp_prefix_entry));
+ pe2 = XCALLOC(MTYPE_EIGRP_PREFIX_DESCRIPTOR,
+ sizeof(struct eigrp_prefix_descriptor));
+ memcpy(pe2, pe, sizeof(struct eigrp_prefix_descriptor));
if (eigrp_update_prefix_apply(eigrp, ei, EIGRP_FILTER_OUT,
pe2->destination)) {
@@ -122,7 +123,7 @@ void eigrp_send_reply(struct eigrp_neighbor *nbr, struct eigrp_prefix_entry *pe)
eigrp_send_packet_reliably(nbr);
}
- XFREE(MTYPE_EIGRP_PREFIX_ENTRY, pe2);
+ XFREE(MTYPE_EIGRP_PREFIX_DESCRIPTOR, pe2);
}
/*EIGRP REPLY read function*/
@@ -161,7 +162,7 @@ void eigrp_reply_receive(struct eigrp *eigrp, struct ip *iph,
dest_addr.family = AF_INET;
dest_addr.u.prefix4 = tlv->destination;
dest_addr.prefixlen = tlv->prefix_length;
- struct eigrp_prefix_entry *dest =
+ struct eigrp_prefix_descriptor *dest =
eigrp_topology_table_lookup_ipv4(eigrp->topology_table,
&dest_addr);
/*
@@ -177,8 +178,8 @@ void eigrp_reply_receive(struct eigrp *eigrp, struct ip *iph,
}
struct eigrp_fsm_action_message msg;
- struct eigrp_nexthop_entry *entry =
- eigrp_prefix_entry_lookup(dest->entries, nbr);
+ struct eigrp_route_descriptor *entry =
+ eigrp_route_descriptor_lookup(dest->entries, nbr);
if (eigrp_update_prefix_apply(eigrp, ei, EIGRP_FILTER_IN,
&dest_addr)) {
diff --git a/eigrpd/eigrp_routemap.c b/eigrpd/eigrp_routemap.c
index e15f777954..5183e645e5 100644
--- a/eigrpd/eigrp_routemap.c
+++ b/eigrpd/eigrp_routemap.c
@@ -265,8 +265,8 @@ route_match_metric(void *rule, struct prefix *prefix, route_map_object_t type,
// uint32_t *metric;
// uint32_t check;
// struct rip_info *rinfo;
- // struct eigrp_nexthop_entry *te;
- // struct eigrp_prefix_entry *pe;
+ // struct eigrp_route_descriptor *te;
+ // struct eigrp_prefix_descriptor *pe;
// struct listnode *node, *node2, *nnode, *nnode2;
// struct eigrp *e;
//
diff --git a/eigrpd/eigrp_siaquery.c b/eigrpd/eigrp_siaquery.c
index ff38325465..027700fe11 100644
--- a/eigrpd/eigrp_siaquery.c
+++ b/eigrpd/eigrp_siaquery.c
@@ -87,7 +87,7 @@ void eigrp_siaquery_receive(struct eigrp *eigrp, struct ip *iph,
dest_addr.family = AFI_IP;
dest_addr.u.prefix4 = tlv->destination;
dest_addr.prefixlen = tlv->prefix_length;
- struct eigrp_prefix_entry *dest =
+ struct eigrp_prefix_descriptor *dest =
eigrp_topology_table_lookup_ipv4(
eigrp->topology_table, &dest_addr);
@@ -95,9 +95,9 @@ void eigrp_siaquery_receive(struct eigrp *eigrp, struct ip *iph,
* know)*/
if (dest != NULL) {
struct eigrp_fsm_action_message msg;
- struct eigrp_nexthop_entry *entry =
- eigrp_prefix_entry_lookup(dest->entries,
- nbr);
+ struct eigrp_route_descriptor *entry =
+ eigrp_route_descriptor_lookup(
+ dest->entries, nbr);
msg.packet_type = EIGRP_OPC_SIAQUERY;
msg.eigrp = eigrp;
msg.data_type = EIGRP_INT;
@@ -114,7 +114,7 @@ void eigrp_siaquery_receive(struct eigrp *eigrp, struct ip *iph,
}
void eigrp_send_siaquery(struct eigrp_neighbor *nbr,
- struct eigrp_prefix_entry *pe)
+ struct eigrp_prefix_descriptor *pe)
{
struct eigrp_packet *ep;
uint16_t length = EIGRP_HEADER_LEN;
diff --git a/eigrpd/eigrp_siareply.c b/eigrpd/eigrp_siareply.c
index d3dd123f90..590b224d68 100644
--- a/eigrpd/eigrp_siareply.c
+++ b/eigrpd/eigrp_siareply.c
@@ -86,7 +86,7 @@ void eigrp_siareply_receive(struct eigrp *eigrp, struct ip *iph,
dest_addr.family = AFI_IP;
dest_addr.u.prefix4 = tlv->destination;
dest_addr.prefixlen = tlv->prefix_length;
- struct eigrp_prefix_entry *dest =
+ struct eigrp_prefix_descriptor *dest =
eigrp_topology_table_lookup_ipv4(
eigrp->topology_table, &dest_addr);
@@ -94,9 +94,9 @@ void eigrp_siareply_receive(struct eigrp *eigrp, struct ip *iph,
* know)*/
if (dest != NULL) {
struct eigrp_fsm_action_message msg;
- struct eigrp_nexthop_entry *entry =
- eigrp_prefix_entry_lookup(dest->entries,
- nbr);
+ struct eigrp_route_descriptor *entry =
+ eigrp_route_descriptor_lookup(
+ dest->entries, nbr);
msg.packet_type = EIGRP_OPC_SIAQUERY;
msg.eigrp = eigrp;
msg.data_type = EIGRP_INT;
@@ -113,7 +113,7 @@ void eigrp_siareply_receive(struct eigrp *eigrp, struct ip *iph,
}
void eigrp_send_siareply(struct eigrp_neighbor *nbr,
- struct eigrp_prefix_entry *pe)
+ struct eigrp_prefix_descriptor *pe)
{
struct eigrp_packet *ep;
uint16_t length = EIGRP_HEADER_LEN;
diff --git a/eigrpd/eigrp_structs.h b/eigrpd/eigrp_structs.h
index 82bddaaae3..cddab57dd5 100644
--- a/eigrpd/eigrp_structs.h
+++ b/eigrpd/eigrp_structs.h
@@ -37,26 +37,6 @@
#include "eigrpd/eigrp_const.h"
#include "eigrpd/eigrp_macros.h"
-/* EIGRP master for system wide configuration and variables. */
-struct eigrp_master {
- /* EIGRP instance. */
- struct list *eigrp;
-
- /* EIGRP thread master. */
- struct thread_master *master;
-
- /* Zebra interface list. */
- struct list *iflist;
-
- /* EIGRP start time. */
- time_t start_time;
-
- /* Various EIGRP global configuration. */
- uint8_t options;
-
-#define EIGRP_MASTER_SHUTDOWN (1 << 0) /* deferred-shutdown */
-};
-
struct eigrp_metrics {
uint32_t delay;
uint32_t bandwidth;
@@ -68,6 +48,16 @@ struct eigrp_metrics {
uint8_t flags;
};
+struct eigrp_extdata {
+ uint32_t orig;
+ uint32_t as;
+ uint32_t tag;
+ uint32_t metric;
+ uint16_t reserved;
+ uint8_t protocol;
+ uint8_t flags;
+};
+
struct eigrp {
vrf_id_t vrf_id;
@@ -450,7 +440,7 @@ enum GR_type { EIGRP_GR_MANUAL, EIGRP_GR_FILTER };
//---------------------------------------------------------------------------------------------------------------------------------------------
/* EIGRP Topology table node structure */
-struct eigrp_prefix_entry {
+struct eigrp_prefix_descriptor {
struct list *entries, *rij;
uint32_t fdistance; // FD
uint32_t rdistance; // RD
@@ -473,8 +463,14 @@ struct eigrp_prefix_entry {
};
/* EIGRP Topology table record structure */
-struct eigrp_nexthop_entry {
- struct eigrp_prefix_entry *prefix;
+struct eigrp_route_descriptor {
+ uint16_t type;
+ uint16_t afi;
+
+ struct eigrp_prefix_descriptor *prefix;
+ struct eigrp_neighbor *adv_router;
+ struct in_addr nexthop;
+
uint32_t reported_distance; // distance reported by neighbor
uint32_t distance; // sum of reported distance and link cost to
// advertised neighbor
@@ -482,7 +478,9 @@ struct eigrp_nexthop_entry {
struct eigrp_metrics reported_metric;
struct eigrp_metrics total_metric;
- struct eigrp_neighbor *adv_router; // ip address of advertising neighbor
+ struct eigrp_metrics metric;
+ struct eigrp_extdata extdata;
+
uint8_t flags; // used for marking successor and FS
struct eigrp_interface *ei; // pointer for case of connected entry
@@ -501,8 +499,8 @@ struct eigrp_fsm_action_message {
uint8_t packet_type; // UPDATE, QUERY, SIAQUERY, SIAREPLY
struct eigrp *eigrp; // which thread sent mesg
struct eigrp_neighbor *adv_router; // advertising neighbor
- struct eigrp_nexthop_entry *entry;
- struct eigrp_prefix_entry *prefix;
+ struct eigrp_route_descriptor *entry;
+ struct eigrp_prefix_descriptor *prefix;
msg_data_t data_type; // internal or external tlv type
struct eigrp_metrics metrics;
enum metric_change change;
diff --git a/eigrpd/eigrp_topology.c b/eigrpd/eigrp_topology.c
index 2dbee16694..1b7e9fc15b 100644
--- a/eigrpd/eigrp_topology.c
+++ b/eigrpd/eigrp_topology.c
@@ -39,6 +39,7 @@
#include "vty.h"
#include "lib_errors.h"
+#include "eigrpd/eigrp_types.h"
#include "eigrpd/eigrp_structs.h"
#include "eigrpd/eigrpd.h"
#include "eigrpd/eigrp_interface.h"
@@ -51,9 +52,10 @@
#include "eigrpd/eigrp_topology.h"
#include "eigrpd/eigrp_fsm.h"
#include "eigrpd/eigrp_memory.h"
+#include "eigrpd/eigrp_metric.h"
-static int eigrp_nexthop_entry_cmp(struct eigrp_nexthop_entry *,
- struct eigrp_nexthop_entry *);
+static int eigrp_route_descriptor_cmp(struct eigrp_route_descriptor *rd1,
+ struct eigrp_route_descriptor *rd2);
/*
* Returns linkedlist used as topology table
@@ -70,14 +72,14 @@ struct route_table *eigrp_topology_new(void)
* Returns new created toplogy node
* cmp - assigned function for comparing topology entry
*/
-struct eigrp_prefix_entry *eigrp_prefix_entry_new(void)
+struct eigrp_prefix_descriptor *eigrp_prefix_descriptor_new(void)
{
- struct eigrp_prefix_entry *new;
- new = XCALLOC(MTYPE_EIGRP_PREFIX_ENTRY,
- sizeof(struct eigrp_prefix_entry));
+ struct eigrp_prefix_descriptor *new;
+ new = XCALLOC(MTYPE_EIGRP_PREFIX_DESCRIPTOR,
+ sizeof(struct eigrp_prefix_descriptor));
new->entries = list_new();
new->rij = list_new();
- new->entries->cmp = (int (*)(void *, void *))eigrp_nexthop_entry_cmp;
+ new->entries->cmp = (int (*)(void *, void *))eigrp_route_descriptor_cmp;
new->distance = new->fdistance = new->rdistance = EIGRP_MAX_METRIC;
new->destination = NULL;
@@ -87,8 +89,8 @@ struct eigrp_prefix_entry *eigrp_prefix_entry_new(void)
/*
* Topology entry comparison
*/
-static int eigrp_nexthop_entry_cmp(struct eigrp_nexthop_entry *entry1,
- struct eigrp_nexthop_entry *entry2)
+static int eigrp_route_descriptor_cmp(struct eigrp_route_descriptor *entry1,
+ struct eigrp_route_descriptor *entry2)
{
if (entry1->distance < entry2->distance)
return -1;
@@ -102,12 +104,12 @@ static int eigrp_nexthop_entry_cmp(struct eigrp_nexthop_entry *entry1,
* Returns new topology entry
*/
-struct eigrp_nexthop_entry *eigrp_nexthop_entry_new(void)
+struct eigrp_route_descriptor *eigrp_route_descriptor_new(void)
{
- struct eigrp_nexthop_entry *new;
+ struct eigrp_route_descriptor *new;
- new = XCALLOC(MTYPE_EIGRP_NEXTHOP_ENTRY,
- sizeof(struct eigrp_nexthop_entry));
+ new = XCALLOC(MTYPE_EIGRP_ROUTE_DESCRIPTOR,
+ sizeof(struct eigrp_route_descriptor));
new->reported_distance = EIGRP_MAX_METRIC;
new->distance = EIGRP_MAX_METRIC;
@@ -126,8 +128,8 @@ void eigrp_topology_free(struct eigrp *eigrp, struct route_table *table)
/*
* Adding topology node to topology table
*/
-void eigrp_prefix_entry_add(struct route_table *topology,
- struct eigrp_prefix_entry *pe)
+void eigrp_prefix_descriptor_add(struct route_table *topology,
+ struct eigrp_prefix_descriptor *pe)
{
struct route_node *rn;
@@ -146,9 +148,9 @@ void eigrp_prefix_entry_add(struct route_table *topology,
/*
* Adding topology entry to topology node
*/
-void eigrp_nexthop_entry_add(struct eigrp *eigrp,
- struct eigrp_prefix_entry *node,
- struct eigrp_nexthop_entry *entry)
+void eigrp_route_descriptor_add(struct eigrp *eigrp,
+ struct eigrp_prefix_descriptor *node,
+ struct eigrp_route_descriptor *entry)
{
struct list *l = list_new();
@@ -168,10 +170,11 @@ void eigrp_nexthop_entry_add(struct eigrp *eigrp,
/*
* Deleting topology node from topology table
*/
-void eigrp_prefix_entry_delete(struct eigrp *eigrp, struct route_table *table,
- struct eigrp_prefix_entry *pe)
+void eigrp_prefix_descriptor_delete(struct eigrp *eigrp,
+ struct route_table *table,
+ struct eigrp_prefix_descriptor *pe)
{
- struct eigrp_nexthop_entry *ne;
+ struct eigrp_route_descriptor *ne;
struct listnode *node, *nnode;
struct route_node *rn;
@@ -189,7 +192,7 @@ void eigrp_prefix_entry_delete(struct eigrp *eigrp, struct route_table *table,
listnode_delete(eigrp->topology_changes_internalIPV4, pe);
for (ALL_LIST_ELEMENTS(pe->entries, node, nnode, ne))
- eigrp_nexthop_entry_delete(eigrp, pe, ne);
+ eigrp_route_descriptor_delete(eigrp, pe, ne);
list_delete(&pe->entries);
list_delete(&pe->rij);
eigrp_zebra_route_delete(eigrp, pe->destination);
@@ -198,20 +201,20 @@ void eigrp_prefix_entry_delete(struct eigrp *eigrp, struct route_table *table,
rn->info = NULL;
route_unlock_node(rn); // Lookup above
route_unlock_node(rn); // Initial creation
- XFREE(MTYPE_EIGRP_PREFIX_ENTRY, pe);
+ XFREE(MTYPE_EIGRP_PREFIX_DESCRIPTOR, pe);
}
/*
* Deleting topology entry from topology node
*/
-void eigrp_nexthop_entry_delete(struct eigrp *eigrp,
- struct eigrp_prefix_entry *node,
- struct eigrp_nexthop_entry *entry)
+void eigrp_route_descriptor_delete(struct eigrp *eigrp,
+ struct eigrp_prefix_descriptor *node,
+ struct eigrp_route_descriptor *entry)
{
if (listnode_lookup(node->entries, entry) != NULL) {
listnode_delete(node->entries, entry);
eigrp_zebra_route_delete(eigrp, node->destination);
- XFREE(MTYPE_EIGRP_NEXTHOP_ENTRY, entry);
+ XFREE(MTYPE_EIGRP_ROUTE_DESCRIPTOR, entry);
}
}
@@ -222,7 +225,7 @@ void eigrp_topology_delete_all(struct eigrp *eigrp,
struct route_table *topology)
{
struct route_node *rn;
- struct eigrp_prefix_entry *pe;
+ struct eigrp_prefix_descriptor *pe;
for (rn = route_top(topology); rn; rn = route_next(rn)) {
pe = rn->info;
@@ -230,15 +233,15 @@ void eigrp_topology_delete_all(struct eigrp *eigrp,
if (!pe)
continue;
- eigrp_prefix_entry_delete(eigrp, topology, pe);
+ eigrp_prefix_descriptor_delete(eigrp, topology, pe);
}
}
-struct eigrp_prefix_entry *
+struct eigrp_prefix_descriptor *
eigrp_topology_table_lookup_ipv4(struct route_table *table,
struct prefix *address)
{
- struct eigrp_prefix_entry *pe;
+ struct eigrp_prefix_descriptor *pe;
struct route_node *rn;
rn = route_node_lookup(table, address);
@@ -259,14 +262,15 @@ eigrp_topology_table_lookup_ipv4(struct route_table *table,
* That way we can clean up all the list_new and list_delete's
* that we are doing. DBS
*/
-struct list *eigrp_topology_get_successor(struct eigrp_prefix_entry *table_node)
+struct list *
+eigrp_topology_get_successor(struct eigrp_prefix_descriptor *table_node)
{
struct list *successors = list_new();
- struct eigrp_nexthop_entry *data;
+ struct eigrp_route_descriptor *data;
struct listnode *node1, *node2;
for (ALL_LIST_ELEMENTS(table_node->entries, node1, node2, data)) {
- if (data->flags & EIGRP_NEXTHOP_ENTRY_SUCCESSOR_FLAG) {
+ if (data->flags & EIGRP_ROUTE_DESCRIPTOR_SUCCESSOR_FLAG) {
listnode_add(successors, data);
}
}
@@ -283,7 +287,7 @@ struct list *eigrp_topology_get_successor(struct eigrp_prefix_entry *table_node)
}
struct list *
-eigrp_topology_get_successor_max(struct eigrp_prefix_entry *table_node,
+eigrp_topology_get_successor_max(struct eigrp_prefix_descriptor *table_node,
unsigned int maxpaths)
{
struct list *successors = eigrp_topology_get_successor(table_node);
@@ -300,10 +304,10 @@ eigrp_topology_get_successor_max(struct eigrp_prefix_entry *table_node,
return successors;
}
-struct eigrp_nexthop_entry *
-eigrp_prefix_entry_lookup(struct list *entries, struct eigrp_neighbor *nbr)
+struct eigrp_route_descriptor *
+eigrp_route_descriptor_lookup(struct list *entries, struct eigrp_neighbor *nbr)
{
- struct eigrp_nexthop_entry *data;
+ struct eigrp_route_descriptor *data;
struct listnode *node, *nnode;
for (ALL_LIST_ELEMENTS(entries, node, nnode, data)) {
if (data->adv_router == nbr) {
@@ -319,8 +323,8 @@ struct list *eigrp_neighbor_prefixes_lookup(struct eigrp *eigrp,
struct eigrp_neighbor *nbr)
{
struct listnode *node2, *node22;
- struct eigrp_nexthop_entry *entry;
- struct eigrp_prefix_entry *pe;
+ struct eigrp_route_descriptor *entry;
+ struct eigrp_prefix_descriptor *pe;
struct route_node *rn;
/* create new empty list for prefixes storage */
@@ -348,8 +352,8 @@ enum metric_change
eigrp_topology_update_distance(struct eigrp_fsm_action_message *msg)
{
struct eigrp *eigrp = msg->eigrp;
- struct eigrp_prefix_entry *prefix = msg->prefix;
- struct eigrp_nexthop_entry *entry = msg->entry;
+ struct eigrp_prefix_descriptor *prefix = msg->prefix;
+ struct eigrp_route_descriptor *entry = msg->entry;
enum metric_change change = METRIC_SAME;
uint32_t new_reported_distance;
@@ -413,7 +417,7 @@ distance_done:
void eigrp_topology_update_all_node_flags(struct eigrp *eigrp)
{
- struct eigrp_prefix_entry *pe;
+ struct eigrp_prefix_descriptor *pe;
struct route_node *rn;
if (!eigrp)
@@ -430,10 +434,10 @@ void eigrp_topology_update_all_node_flags(struct eigrp *eigrp)
}
void eigrp_topology_update_node_flags(struct eigrp *eigrp,
- struct eigrp_prefix_entry *dest)
+ struct eigrp_prefix_descriptor *dest)
{
struct listnode *node;
- struct eigrp_nexthop_entry *entry;
+ struct eigrp_route_descriptor *entry;
for (ALL_LIST_ELEMENTS_RO(dest->entries, node, entry)) {
if (entry->reported_distance < dest->fdistance) {
@@ -444,29 +448,29 @@ void eigrp_topology_update_node_flags(struct eigrp *eigrp,
&& entry->distance != EIGRP_MAX_METRIC) {
// is successor
entry->flags |=
- EIGRP_NEXTHOP_ENTRY_SUCCESSOR_FLAG;
+ EIGRP_ROUTE_DESCRIPTOR_SUCCESSOR_FLAG;
entry->flags &=
- ~EIGRP_NEXTHOP_ENTRY_FSUCCESSOR_FLAG;
+ ~EIGRP_ROUTE_DESCRIPTOR_FSUCCESSOR_FLAG;
} else {
// is feasible successor only
entry->flags |=
- EIGRP_NEXTHOP_ENTRY_FSUCCESSOR_FLAG;
+ EIGRP_ROUTE_DESCRIPTOR_FSUCCESSOR_FLAG;
entry->flags &=
- ~EIGRP_NEXTHOP_ENTRY_SUCCESSOR_FLAG;
+ ~EIGRP_ROUTE_DESCRIPTOR_SUCCESSOR_FLAG;
}
} else {
- entry->flags &= ~EIGRP_NEXTHOP_ENTRY_FSUCCESSOR_FLAG;
- entry->flags &= ~EIGRP_NEXTHOP_ENTRY_SUCCESSOR_FLAG;
+ entry->flags &= ~EIGRP_ROUTE_DESCRIPTOR_FSUCCESSOR_FLAG;
+ entry->flags &= ~EIGRP_ROUTE_DESCRIPTOR_SUCCESSOR_FLAG;
}
}
}
void eigrp_update_routing_table(struct eigrp *eigrp,
- struct eigrp_prefix_entry *prefix)
+ struct eigrp_prefix_descriptor *prefix)
{
struct list *successors;
struct listnode *node;
- struct eigrp_nexthop_entry *entry;
+ struct eigrp_route_descriptor *entry;
successors = eigrp_topology_get_successor_max(prefix, eigrp->max_paths);
@@ -474,13 +478,13 @@ void eigrp_update_routing_table(struct eigrp *eigrp,
eigrp_zebra_route_add(eigrp, prefix->destination, successors,
prefix->fdistance);
for (ALL_LIST_ELEMENTS_RO(successors, node, entry))
- entry->flags |= EIGRP_NEXTHOP_ENTRY_INTABLE_FLAG;
+ entry->flags |= EIGRP_ROUTE_DESCRIPTOR_INTABLE_FLAG;
list_delete(&successors);
} else {
eigrp_zebra_route_delete(eigrp, prefix->destination);
for (ALL_LIST_ELEMENTS_RO(prefix->entries, node, entry))
- entry->flags &= ~EIGRP_NEXTHOP_ENTRY_INTABLE_FLAG;
+ entry->flags &= ~EIGRP_ROUTE_DESCRIPTOR_INTABLE_FLAG;
}
}
@@ -488,8 +492,8 @@ void eigrp_topology_neighbor_down(struct eigrp *eigrp,
struct eigrp_neighbor *nbr)
{
struct listnode *node2, *node22;
- struct eigrp_prefix_entry *pe;
- struct eigrp_nexthop_entry *entry;
+ struct eigrp_prefix_descriptor *pe;
+ struct eigrp_route_descriptor *entry;
struct route_node *rn;
for (rn = route_top(eigrp->topology_table); rn; rn = route_next(rn)) {
@@ -521,18 +525,18 @@ void eigrp_topology_neighbor_down(struct eigrp *eigrp,
void eigrp_update_topology_table_prefix(struct eigrp *eigrp,
struct route_table *table,
- struct eigrp_prefix_entry *prefix)
+ struct eigrp_prefix_descriptor *prefix)
{
struct listnode *node1, *node2;
- struct eigrp_nexthop_entry *entry;
+ struct eigrp_route_descriptor *entry;
for (ALL_LIST_ELEMENTS(prefix->entries, node1, node2, entry)) {
if (entry->distance == EIGRP_MAX_METRIC) {
- eigrp_nexthop_entry_delete(eigrp, prefix, entry);
+ eigrp_route_descriptor_delete(eigrp, prefix, entry);
}
}
if (prefix->distance == EIGRP_MAX_METRIC
&& prefix->nt != EIGRP_TOPOLOGY_TYPE_CONNECTED) {
- eigrp_prefix_entry_delete(eigrp, table, prefix);
+ eigrp_prefix_descriptor_delete(eigrp, table, prefix);
}
}
diff --git a/eigrpd/eigrp_topology.h b/eigrpd/eigrp_topology.h
index 718cece403..26fa1a11b0 100644
--- a/eigrpd/eigrp_topology.h
+++ b/eigrpd/eigrp_topology.h
@@ -35,43 +35,47 @@
/* EIGRP Topology table related functions. */
extern struct route_table *eigrp_topology_new(void);
extern void eigrp_topology_init(struct route_table *table);
-extern struct eigrp_prefix_entry *eigrp_prefix_entry_new(void);
-extern struct eigrp_nexthop_entry *eigrp_nexthop_entry_new(void);
+extern struct eigrp_prefix_descriptor *eigrp_prefix_descriptor_new(void);
+extern struct eigrp_route_descriptor *eigrp_route_descriptor_new(void);
extern void eigrp_topology_free(struct eigrp *eigrp, struct route_table *table);
-extern void eigrp_prefix_entry_add(struct route_table *table,
- struct eigrp_prefix_entry *pe);
-extern void eigrp_nexthop_entry_add(struct eigrp *eigrp,
- struct eigrp_prefix_entry *pe,
- struct eigrp_nexthop_entry *ne);
-extern void eigrp_prefix_entry_delete(struct eigrp *eigrp,
- struct route_table *table,
- struct eigrp_prefix_entry *pe);
-extern void eigrp_nexthop_entry_delete(struct eigrp *eigrp,
- struct eigrp_prefix_entry *pe,
- struct eigrp_nexthop_entry *ne);
+extern void eigrp_prefix_descriptor_add(struct route_table *table,
+ struct eigrp_prefix_descriptor *pe);
+extern void eigrp_route_descriptor_add(struct eigrp *eigrp,
+ struct eigrp_prefix_descriptor *pe,
+ struct eigrp_route_descriptor *ne);
+extern void eigrp_prefix_descriptor_delete(struct eigrp *eigrp,
+ struct route_table *table,
+ struct eigrp_prefix_descriptor *pe);
+extern void eigrp_route_descriptor_delete(struct eigrp *eigrp,
+ struct eigrp_prefix_descriptor *pe,
+ struct eigrp_route_descriptor *ne);
extern void eigrp_topology_delete_all(struct eigrp *eigrp,
struct route_table *table);
-extern struct eigrp_prefix_entry *
+extern struct eigrp_prefix_descriptor *
eigrp_topology_table_lookup_ipv4(struct route_table *table, struct prefix *p);
-extern struct list *eigrp_topology_get_successor(struct eigrp_prefix_entry *pe);
extern struct list *
-eigrp_topology_get_successor_max(struct eigrp_prefix_entry *pe,
+eigrp_topology_get_successor(struct eigrp_prefix_descriptor *pe);
+extern struct list *
+eigrp_topology_get_successor_max(struct eigrp_prefix_descriptor *pe,
unsigned int maxpaths);
-extern struct eigrp_nexthop_entry *
-eigrp_prefix_entry_lookup(struct list *entries, struct eigrp_neighbor *neigh);
+extern struct eigrp_route_descriptor *
+eigrp_route_descriptor_lookup(struct list *entries,
+ struct eigrp_neighbor *neigh);
extern struct list *eigrp_neighbor_prefixes_lookup(struct eigrp *eigrp,
struct eigrp_neighbor *n);
extern void eigrp_topology_update_all_node_flags(struct eigrp *eigrp);
-extern void eigrp_topology_update_node_flags(struct eigrp *eigrp,
- struct eigrp_prefix_entry *pe);
+extern void
+eigrp_topology_update_node_flags(struct eigrp *eigrp,
+ struct eigrp_prefix_descriptor *pe);
extern enum metric_change
eigrp_topology_update_distance(struct eigrp_fsm_action_message *msg);
extern void eigrp_update_routing_table(struct eigrp *eigrp,
- struct eigrp_prefix_entry *pe);
+ struct eigrp_prefix_descriptor *pe);
extern void eigrp_topology_neighbor_down(struct eigrp *eigrp,
struct eigrp_neighbor *neigh);
-extern void eigrp_update_topology_table_prefix(struct eigrp *eigrp,
- struct route_table *table,
- struct eigrp_prefix_entry *pe);
+extern void
+eigrp_update_topology_table_prefix(struct eigrp *eigrp,
+ struct route_table *table,
+ struct eigrp_prefix_descriptor *pe);
#endif
diff --git a/eigrpd/eigrp_types.h b/eigrpd/eigrp_types.h
new file mode 100644
index 0000000000..bd6510733b
--- /dev/null
+++ b/eigrpd/eigrp_types.h
@@ -0,0 +1,36 @@
+/*
+ * EIGRP Definition of Data Types
+ * Copyright (C) 2018
+ * Authors:
+ * Donnie Savage
+ *
+ * This file is part of FRR.
+ *
+ * FRR is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * FRR is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; see the file COPYING; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef _ZEBRA_EIGRP_TYPES_H_
+#define _ZEBRA_EIGRP_TYPES_H_
+
+typedef uint64_t eigrp_bandwidth_t;
+typedef uint64_t eigrp_delay_t;
+typedef uint64_t eigrp_metric_t;
+typedef uint32_t eigrp_scaled_t;
+
+typedef uint32_t eigrp_system_metric_t;
+typedef uint32_t eigrp_system_delay_t;
+typedef uint32_t eigrp_system_bandwidth_t;
+
+#endif /* _ZEBRA_EIGRP_TYPES_H_ */
diff --git a/eigrpd/eigrp_update.c b/eigrpd/eigrp_update.c
index cd30eb5ab5..91f3b3218b 100644
--- a/eigrpd/eigrp_update.c
+++ b/eigrpd/eigrp_update.c
@@ -49,6 +49,7 @@
#include "routemap.h"
#include "vty.h"
+#include "eigrpd/eigrp_types.h"
#include "eigrpd/eigrp_structs.h"
#include "eigrpd/eigrpd.h"
#include "eigrpd/eigrp_interface.h"
@@ -62,6 +63,7 @@
#include "eigrpd/eigrp_fsm.h"
#include "eigrpd/eigrp_network.h"
#include "eigrpd/eigrp_memory.h"
+#include "eigrpd/eigrp_metric.h"
bool eigrp_update_prefix_apply(struct eigrp *eigrp, struct eigrp_interface *ei,
int in, struct prefix *prefix)
@@ -101,11 +103,12 @@ bool eigrp_update_prefix_apply(struct eigrp *eigrp, struct eigrp_interface *ei,
* Function is used for removing received prefix
* from list of neighbor prefixes
*/
-static void remove_received_prefix_gr(struct list *nbr_prefixes,
- struct eigrp_prefix_entry *recv_prefix)
+static void
+remove_received_prefix_gr(struct list *nbr_prefixes,
+ struct eigrp_prefix_descriptor *recv_prefix)
{
struct listnode *node1, *node11;
- struct eigrp_prefix_entry *prefix = NULL;
+ struct eigrp_prefix_descriptor *prefix = NULL;
/* iterate over all prefixes in list */
for (ALL_LIST_ELEMENTS(nbr_prefixes, node1, node11, prefix)) {
@@ -136,7 +139,7 @@ static void eigrp_update_receive_GR_ask(struct eigrp *eigrp,
struct list *nbr_prefixes)
{
struct listnode *node1;
- struct eigrp_prefix_entry *prefix;
+ struct eigrp_prefix_descriptor *prefix;
struct eigrp_fsm_action_message fsm_msg;
/* iterate over all prefixes which weren't advertised by neighbor */
@@ -148,8 +151,8 @@ static void eigrp_update_receive_GR_ask(struct eigrp *eigrp,
/* set delay to MAX */
fsm_msg.metrics.delay = EIGRP_MAX_METRIC;
- struct eigrp_nexthop_entry *entry =
- eigrp_prefix_entry_lookup(prefix->entries, nbr);
+ struct eigrp_route_descriptor *entry =
+ eigrp_route_descriptor_lookup(prefix->entries, nbr);
fsm_msg.packet_type = EIGRP_OPC_UPDATE;
fsm_msg.eigrp = eigrp;
@@ -172,8 +175,8 @@ void eigrp_update_receive(struct eigrp *eigrp, struct ip *iph,
{
struct eigrp_neighbor *nbr;
struct TLV_IPv4_Internal_type *tlv;
- struct eigrp_prefix_entry *pe;
- struct eigrp_nexthop_entry *ne;
+ struct eigrp_prefix_descriptor *pe;
+ struct eigrp_route_descriptor *ne;
uint32_t flags;
uint16_t type;
uint16_t length;
@@ -304,7 +307,7 @@ void eigrp_update_receive(struct eigrp *eigrp, struct ip *iph,
dest_addr.family = AF_INET;
dest_addr.u.prefix4 = tlv->destination;
dest_addr.prefixlen = tlv->prefix_length;
- struct eigrp_prefix_entry *dest =
+ struct eigrp_prefix_descriptor *dest =
eigrp_topology_table_lookup_ipv4(
eigrp->topology_table, &dest_addr);
@@ -317,9 +320,9 @@ void eigrp_update_receive(struct eigrp *eigrp, struct ip *iph,
dest);
struct eigrp_fsm_action_message msg;
- struct eigrp_nexthop_entry *entry =
- eigrp_prefix_entry_lookup(dest->entries,
- nbr);
+ struct eigrp_route_descriptor *entry =
+ eigrp_route_descriptor_lookup(
+ dest->entries, nbr);
msg.packet_type = EIGRP_OPC_UPDATE;
msg.eigrp = eigrp;
@@ -331,7 +334,7 @@ void eigrp_update_receive(struct eigrp *eigrp, struct ip *iph,
eigrp_fsm_event(&msg);
} else {
/*Here comes topology information save*/
- pe = eigrp_prefix_entry_new();
+ pe = eigrp_prefix_descriptor_new();
pe->serno = eigrp->serno;
pe->destination =
(struct prefix *)prefix_ipv4_new();
@@ -340,7 +343,7 @@ void eigrp_update_receive(struct eigrp *eigrp, struct ip *iph,
pe->state = EIGRP_FSM_STATE_PASSIVE;
pe->nt = EIGRP_TOPOLOGY_TYPE_REMOTE;
- ne = eigrp_nexthop_entry_new();
+ ne = eigrp_route_descriptor_new();
ne->ei = ei;
ne->adv_router = nbr;
ne->reported_metric = tlv->metric;
@@ -361,11 +364,12 @@ void eigrp_update_receive(struct eigrp *eigrp, struct ip *iph,
pe->fdistance = pe->distance = pe->rdistance =
ne->distance;
ne->prefix = pe;
- ne->flags = EIGRP_NEXTHOP_ENTRY_SUCCESSOR_FLAG;
+ ne->flags =
+ EIGRP_ROUTE_DESCRIPTOR_SUCCESSOR_FLAG;
- eigrp_prefix_entry_add(eigrp->topology_table,
- pe);
- eigrp_nexthop_entry_add(eigrp, pe, ne);
+ eigrp_prefix_descriptor_add(
+ eigrp->topology_table, pe);
+ eigrp_route_descriptor_add(eigrp, pe, ne);
pe->distance = pe->fdistance = pe->rdistance =
ne->distance;
pe->reported_metric = ne->total_metric;
@@ -527,8 +531,8 @@ void eigrp_update_send_EOT(struct eigrp_neighbor *nbr)
{
struct eigrp_packet *ep;
uint16_t length = EIGRP_HEADER_LEN;
- struct eigrp_nexthop_entry *te;
- struct eigrp_prefix_entry *pe;
+ struct eigrp_route_descriptor *te;
+ struct eigrp_prefix_descriptor *pe;
struct listnode *node2, *nnode2;
struct eigrp_interface *ei = nbr->ei;
struct eigrp *eigrp = ei->eigrp;
@@ -600,7 +604,7 @@ void eigrp_update_send(struct eigrp_interface *ei)
{
struct eigrp_packet *ep;
struct listnode *node, *nnode;
- struct eigrp_prefix_entry *pe;
+ struct eigrp_prefix_descriptor *pe;
uint8_t has_tlv;
struct eigrp *eigrp = ei->eigrp;
struct prefix *dest_addr;
@@ -626,7 +630,7 @@ void eigrp_update_send(struct eigrp_interface *ei)
has_tlv = 0;
for (ALL_LIST_ELEMENTS(ei->eigrp->topology_changes_internalIPV4, node,
nnode, pe)) {
- struct eigrp_nexthop_entry *ne;
+ struct eigrp_route_descriptor *ne;
if (!(pe->req_action & EIGRP_FSM_NEED_UPDATE))
continue;
@@ -707,7 +711,7 @@ void eigrp_update_send_all(struct eigrp *eigrp,
{
struct eigrp_interface *iface;
struct listnode *node, *node2, *nnode2;
- struct eigrp_prefix_entry *pe;
+ struct eigrp_prefix_descriptor *pe;
for (ALL_LIST_ELEMENTS_RO(eigrp->eiflist, node, iface)) {
if (iface != exception) {
@@ -745,7 +749,7 @@ static void eigrp_update_send_GR_part(struct eigrp_neighbor *nbr)
{
struct eigrp_packet *ep;
uint16_t length = EIGRP_HEADER_LEN;
- struct eigrp_prefix_entry *pe;
+ struct eigrp_prefix_descriptor *pe;
struct prefix *dest_addr;
struct eigrp_interface *ei = nbr->ei;
struct eigrp *eigrp = ei->eigrp;
@@ -837,8 +841,8 @@ static void eigrp_update_send_GR_part(struct eigrp_neighbor *nbr)
/* prepare message for FSM */
struct eigrp_fsm_action_message fsm_msg;
- struct eigrp_nexthop_entry *entry =
- eigrp_prefix_entry_lookup(pe->entries, nbr);
+ struct eigrp_route_descriptor *entry =
+ eigrp_route_descriptor_lookup(pe->entries, nbr);
fsm_msg.packet_type = EIGRP_OPC_UPDATE;
fsm_msg.eigrp = eigrp;
@@ -956,7 +960,7 @@ int eigrp_update_send_GR_thread(struct thread *thread)
void eigrp_update_send_GR(struct eigrp_neighbor *nbr, enum GR_type gr_type,
struct vty *vty)
{
- struct eigrp_prefix_entry *pe2;
+ struct eigrp_prefix_descriptor *pe2;
struct list *prefixes;
struct route_node *rn;
struct eigrp_interface *ei = nbr->ei;
diff --git a/eigrpd/eigrp_vty.c b/eigrpd/eigrp_vty.c
index 66dfbaa538..0809ac2cf0 100644
--- a/eigrpd/eigrp_vty.c
+++ b/eigrpd/eigrp_vty.c
@@ -59,25 +59,21 @@
#include "eigrpd/eigrp_vty_clippy.c"
#endif
-static void eigrp_vty_display_prefix_entry(struct vty *vty,
- struct eigrp *eigrp,
- struct eigrp_prefix_entry *pe,
+static void eigrp_vty_display_prefix_entry(struct vty *vty, struct eigrp *eigrp,
+ struct eigrp_prefix_descriptor *pe,
bool all)
{
bool first = true;
- struct eigrp_nexthop_entry *te;
+ struct eigrp_route_descriptor *te;
struct listnode *node;
for (ALL_LIST_ELEMENTS_RO(pe->entries, node, te)) {
if (all
- || (((te->flags
- & EIGRP_NEXTHOP_ENTRY_SUCCESSOR_FLAG)
- == EIGRP_NEXTHOP_ENTRY_SUCCESSOR_FLAG)
- || ((te->flags
- & EIGRP_NEXTHOP_ENTRY_FSUCCESSOR_FLAG)
- == EIGRP_NEXTHOP_ENTRY_FSUCCESSOR_FLAG))) {
- show_ip_eigrp_nexthop_entry(vty, eigrp, te,
- &first);
+ || (((te->flags & EIGRP_ROUTE_DESCRIPTOR_SUCCESSOR_FLAG)
+ == EIGRP_ROUTE_DESCRIPTOR_SUCCESSOR_FLAG)
+ || ((te->flags & EIGRP_ROUTE_DESCRIPTOR_FSUCCESSOR_FLAG)
+ == EIGRP_ROUTE_DESCRIPTOR_FSUCCESSOR_FLAG))) {
+ show_ip_eigrp_route_descriptor(vty, eigrp, te, &first);
first = false;
}
}
@@ -104,7 +100,7 @@ static struct eigrp *eigrp_vty_get_eigrp(struct vty *vty, const char *vrf_name)
static void eigrp_topology_helper(struct vty *vty, struct eigrp *eigrp,
const char *all)
{
- struct eigrp_prefix_entry *tn;
+ struct eigrp_prefix_descriptor *tn;
struct route_node *rn;
show_ip_eigrp_topology_header(vty, eigrp);
@@ -168,7 +164,7 @@ DEFPY (show_ip_eigrp_topology,
"For a specific prefix\n")
{
struct eigrp *eigrp;
- struct eigrp_prefix_entry *tn;
+ struct eigrp_prefix_descriptor *tn;
struct route_node *rn;
struct prefix cmp;
diff --git a/eigrpd/eigrp_yang.h b/eigrpd/eigrp_yang.h
new file mode 100644
index 0000000000..a95e5310fb
--- /dev/null
+++ b/eigrpd/eigrp_yang.h
@@ -0,0 +1,32 @@
+/*
+ * EIGRP YANG Functions.
+ * Copyright (C) 2019
+ * Authors:
+ * Donnie Savage
+ *
+ * This file is part of FRR.
+ *
+ * FRR is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * FRR is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; see the file COPYING; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef _EIGRP_YANG_H_
+#define _EIGRP_YANG_H_
+
+/*Prototypes*/
+
+/* eigrp_northbound.c */
+extern const struct frr_yang_module_info frr_eigrpd_info;
+
+#endif /*EIGRP_YANG_H_ */
diff --git a/eigrpd/eigrp_zebra.c b/eigrpd/eigrp_zebra.c
index 0795fbd6df..e79123e6b4 100644
--- a/eigrpd/eigrp_zebra.c
+++ b/eigrpd/eigrp_zebra.c
@@ -41,6 +41,7 @@
#include "log.h"
#include "nexthop.h"
+#include "eigrpd/eigrp_types.h"
#include "eigrpd/eigrp_structs.h"
#include "eigrpd/eigrpd.h"
#include "eigrpd/eigrp_interface.h"
@@ -52,6 +53,7 @@
#include "eigrpd/eigrp_network.h"
#include "eigrpd/eigrp_topology.h"
#include "eigrpd/eigrp_fsm.h"
+#include "eigrpd/eigrp_metric.h"
static int eigrp_interface_address_add(ZAPI_CALLBACK_ARGS);
static int eigrp_interface_address_delete(ZAPI_CALLBACK_ARGS);
@@ -194,7 +196,7 @@ void eigrp_zebra_route_add(struct eigrp *eigrp, struct prefix *p,
{
struct zapi_route api;
struct zapi_nexthop *api_nh;
- struct eigrp_nexthop_entry *te;
+ struct eigrp_route_descriptor *te;
struct listnode *node;
int count = 0;
diff --git a/eigrpd/eigrpd.h b/eigrpd/eigrpd.h
index 6b4d45d1fc..01173768ba 100644
--- a/eigrpd/eigrpd.h
+++ b/eigrpd/eigrpd.h
@@ -37,6 +37,30 @@
#define EIGRP_MAJOR_VERSION 1
#define EIGRP_MINOR_VERSION 2
+#define EIGRP_TLV_32B_VERSION 1 /* Original 32bit scaled metrics */
+#define EIGRP_TLV_64B_VERSION 2 /* Current 64bit 'wide' metrics */
+#define EIGRP_TLV_MTR_VERSION 3 /* MTR TLVs with 32bit metric *Not Supported */
+#define EIGRP_TLV_SAF_VERSION 4 /* SAF TLVs with 64bit metric *Not Supported */
+
+struct eigrp_master {
+ /* EIGRP instance. */
+ struct list *eigrp;
+
+ /* EIGRP thread master. */
+ struct thread_master *master;
+
+ /* Zebra interface list. */
+ struct list *iflist;
+
+ /* EIGRP start time. */
+ time_t start_time;
+
+ /* Various EIGRP global configuration. */
+ uint8_t options;
+
+#define EIGRP_MASTER_SHUTDOWN (1 << 0) /* deferred-shutdown */
+};
+
/* Extern variables. */
extern struct zclient *zclient;
extern struct thread_master *master;
@@ -46,57 +70,10 @@ extern struct zebra_privs_t eigrpd_privs;
/* Prototypes */
extern void eigrp_master_init(void);
extern void eigrp_terminate(void);
-extern void eigrp_finish_final(struct eigrp *);
-extern void eigrp_finish(struct eigrp *);
+extern void eigrp_finish_final(struct eigrp *eigrp);
+extern void eigrp_finish(struct eigrp *eigrp);
extern struct eigrp *eigrp_get(uint16_t as, vrf_id_t vrf_id);
extern struct eigrp *eigrp_lookup(vrf_id_t vrf_id);
-extern void eigrp_router_id_update(struct eigrp *);
-
-/* eigrp_cli.c */
-extern void eigrp_cli_show_header(struct vty *vty, struct lyd_node *dnode,
- bool show_defaults);
-extern void eigrp_cli_show_end_header(struct vty *vty, struct lyd_node *dnode);
-extern void eigrp_cli_show_router_id(struct vty *vty, struct lyd_node *dnode,
- bool show_defaults);
-extern void eigrp_cli_show_passive_interface(struct vty *vty,
- struct lyd_node *dnode,
- bool show_defaults);
-extern void eigrp_cli_show_active_time(struct vty *vty, struct lyd_node *dnode,
- bool show_defaults);
-extern void eigrp_cli_show_variance(struct vty *vty, struct lyd_node *dnode,
- bool show_defaults);
-extern void eigrp_cli_show_maximum_paths(struct vty *vty,
- struct lyd_node *dnode,
- bool show_defaults);
-extern void eigrp_cli_show_metrics(struct vty *vty, struct lyd_node *dnode,
- bool show_defaults);
-extern void eigrp_cli_show_network(struct vty *vty, struct lyd_node *dnode,
- bool show_defaults);
-extern void eigrp_cli_show_neighbor(struct vty *vty, struct lyd_node *dnode,
- bool show_defaults);
-extern void eigrp_cli_show_redistribute(struct vty *vty,
- struct lyd_node *dnode,
- bool show_defaults);
-extern void eigrp_cli_show_delay(struct vty *vty, struct lyd_node *dnode,
- bool show_defaults);
-extern void eigrp_cli_show_bandwidth(struct vty *vty, struct lyd_node *dnode,
- bool show_defaults);
-extern void eigrp_cli_show_hello_interval(struct vty *vty,
- struct lyd_node *dnode,
- bool show_defaults);
-extern void eigrp_cli_show_hold_time(struct vty *vty, struct lyd_node *dnode,
- bool show_defaults);
-extern void eigrp_cli_show_summarize_address(struct vty *vty,
- struct lyd_node *dnode,
- bool show_defaults);
-extern void eigrp_cli_show_authentication(struct vty *vty,
- struct lyd_node *dnode,
- bool show_defaults);
-extern void eigrp_cli_show_keychain(struct vty *vty, struct lyd_node *dnode,
- bool show_defaults);
-extern void eigrp_cli_init(void);
-
-/* eigrp_northbound.c */
-extern const struct frr_yang_module_info frr_eigrpd_info;
+extern void eigrp_router_id_update(struct eigrp *eigrp);
#endif /* _ZEBRA_EIGRPD_H */
diff --git a/eigrpd/subdir.am b/eigrpd/subdir.am
index 98f39440c3..13c9f7f8ae 100644
--- a/eigrpd/subdir.am
+++ b/eigrpd/subdir.am
@@ -25,6 +25,7 @@ eigrpd_libeigrp_a_SOURCES = \
eigrpd/eigrp_hello.c \
eigrpd/eigrp_interface.c \
eigrpd/eigrp_memory.c \
+ eigrpd/eigrp_metric.c \
eigrpd/eigrp_neighbor.c \
eigrpd/eigrp_network.c \
eigrpd/eigrp_northbound.c \
@@ -55,6 +56,7 @@ clippy_scan += \
# end
noinst_HEADERS += \
+ eigrpd/eigrp_cli.h \
eigrpd/eigrp_const.h \
eigrpd/eigrp_errors.h \
eigrpd/eigrp_filter.h \
@@ -62,13 +64,16 @@ noinst_HEADERS += \
eigrpd/eigrp_interface.h \
eigrpd/eigrp_macros.h \
eigrpd/eigrp_memory.h \
+ eigrpd/eigrp_metric.h \
eigrpd/eigrp_neighbor.h \
eigrpd/eigrp_network.h \
eigrpd/eigrp_packet.h \
eigrpd/eigrp_snmp.h \
eigrpd/eigrp_structs.h \
+ eigrpd/eigrp_types.h \
eigrpd/eigrp_vrf.h \
eigrpd/eigrp_vty.h \
+ eigrpd/eigrp_yang.h \
eigrpd/eigrp_zebra.h \
# end
diff --git a/ldpd/lde.h b/ldpd/lde.h
index 28468931ec..e09be01ece 100644
--- a/ldpd/lde.h
+++ b/ldpd/lde.h
@@ -129,9 +129,7 @@ struct fec_node {
uint32_t pw_remote_status;
void *data; /* fec specific data */
- uint8_t flags;
};
-#define F_FEC_NHS_CHANGED 0x01
#define CHUNK_SIZE 64
struct label_chunk {
diff --git a/ldpd/lde_lib.c b/ldpd/lde_lib.c
index 68b721e213..0f91f49920 100644
--- a/ldpd/lde_lib.c
+++ b/ldpd/lde_lib.c
@@ -340,8 +340,6 @@ lde_kernel_insert(struct fec *fec, int af, union ldpd_addr *nexthop,
fnh = fec_nh_find(fn, af, nexthop, ifindex, route_type, route_instance);
if (fnh == NULL) {
- fn->flags |= F_FEC_NHS_CHANGED;
-
fnh = fec_nh_add(fn, af, nexthop, ifindex, route_type,
route_instance);
/*
@@ -418,17 +416,11 @@ lde_kernel_update(struct fec *fec)
} else
fnh->flags |= F_FEC_NH_NO_LDP;
} else {
- fn->flags |= F_FEC_NHS_CHANGED;
lde_send_delete_klabel(fn, fnh);
fec_nh_del(fnh);
}
}
- if (!(fn->flags & F_FEC_NHS_CHANGED))
- /* return earlier if nothing has changed */
- return;
- fn->flags &= ~F_FEC_NHS_CHANGED;
-
if (LIST_EMPTY(&fn->nexthops)) {
RB_FOREACH(ln, nbr_tree, &lde_nbrs)
lde_send_labelwithdraw(ln, fn, NULL, NULL);
diff --git a/lib/command.c b/lib/command.c
index f40fe6e2c5..b9d607a101 100644
--- a/lib/command.c
+++ b/lib/command.c
@@ -49,6 +49,8 @@
#include "northbound_cli.h"
#include "network.h"
+#include "frrscript.h"
+
DEFINE_MTYPE_STATIC(LIB, HOST, "Host config")
DEFINE_MTYPE(LIB, COMPLETION, "Completion item")
@@ -2303,6 +2305,30 @@ done:
return CMD_SUCCESS;
}
+#if defined(DEV_BUILD) && defined(HAVE_SCRIPTING)
+DEFUN(script,
+ script_cmd,
+ "script SCRIPT",
+ "Test command - execute a script\n"
+ "Script name (same as filename in /etc/frr/scripts/\n")
+{
+ struct prefix p;
+ str2prefix("1.2.3.4/24", &p);
+
+ struct frrscript *fs = frrscript_load(argv[1]->arg, NULL);
+
+ if (fs == NULL) {
+ vty_out(vty, "Script '/etc/frr/scripts/%s.lua' not found\n",
+ argv[1]->arg);
+ } else {
+ int ret = frrscript_call(fs, NULL);
+ vty_out(vty, "Script result: %d\n", ret);
+ }
+
+ return CMD_SUCCESS;
+}
+#endif
+
/* Set config filename. Called from vty.c */
void host_config_set(const char *filename)
{
@@ -2397,6 +2423,10 @@ void cmd_init(int terminal)
install_element(VIEW_NODE, &echo_cmd);
install_element(VIEW_NODE, &autocomplete_cmd);
install_element(VIEW_NODE, &find_cmd);
+#if defined(DEV_BUILD) && defined(HAVE_SCRIPTING)
+ install_element(VIEW_NODE, &script_cmd);
+#endif
+
install_element(ENABLE_NODE, &config_end_cmd);
install_element(ENABLE_NODE, &config_disable_cmd);
diff --git a/lib/compiler.h b/lib/compiler.h
index 217a60d888..70ef8e9bc8 100644
--- a/lib/compiler.h
+++ b/lib/compiler.h
@@ -279,6 +279,29 @@ extern "C" {
#define array_size(ar) (sizeof(ar) / sizeof(ar[0]))
+/* Some insane macros to count number of varargs to a functionlike macro */
+#define PP_ARG_N( \
+ _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, \
+ _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, \
+ _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, \
+ _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, \
+ _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, \
+ _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, \
+ _61, _62, _63, N, ...) N
+
+#define PP_RSEQ_N() \
+ 62, 61, 60, \
+ 59, 58, 57, 56, 55, 54, 53, 52, 51, 50, \
+ 49, 48, 47, 46, 45, 44, 43, 42, 41, 40, \
+ 39, 38, 37, 36, 35, 34, 33, 32, 31, 30, \
+ 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, \
+ 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, \
+ 9, 8, 7, 6, 5, 4, 3, 2, 1, 0
+
+#define PP_NARG_(...) PP_ARG_N(__VA_ARGS__)
+#define PP_NARG(...) PP_NARG_(_, ##__VA_ARGS__, PP_RSEQ_N())
+
+
/* sigh. this is so ugly, it overflows and wraps to being nice again.
*
* printfrr() supports "%Ld" for <int64_t>, whatever that is typedef'd to.
diff --git a/lib/frrlua.c b/lib/frrlua.c
index 9f9cf8c1f6..3c270b2340 100644
--- a/lib/frrlua.c
+++ b/lib/frrlua.c
@@ -2,128 +2,365 @@
* This file defines the lua interface into
* FRRouting.
*
- * Copyright (C) 2016 Cumulus Networks, Inc.
- * Donald Sharp
+ * Copyright (C) 2016-2019 Cumulus Networks, Inc.
+ * Donald Sharp, Quentin Young
*
- * This file is part of FRRouting (FRR).
+ * 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.
*
- * FRR is free software; you can redistribute it and/or modify it under the
- * terms of the GNU General Public License as published by the Free Software
- * Foundation; either version 2, or (at your option) any later version.
- *
- * FRR is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
- * details.
+ * 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 General Public License along
- * with FRR; see the file COPYING. If not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * with this program; see the file COPYING; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <zebra.h>
-#if defined(HAVE_LUA)
+#ifdef HAVE_SCRIPTING
+
#include "prefix.h"
#include "frrlua.h"
#include "log.h"
+#include "buffer.h"
+
+/* Lua stuff */
-static int lua_zlog_debug(lua_State *L)
+/*
+ * FRR convenience functions.
+ *
+ * This section has convenience functions used to make interacting with the Lua
+ * stack easier.
+ */
+
+int frrlua_table_get_integer(lua_State *L, const char *key)
{
- int debug_lua = 1;
- const char *string = lua_tostring(L, 1);
+ int result;
- if (debug_lua)
- zlog_debug("%s", string);
+ lua_pushstring(L, key);
+ lua_gettable(L, -2);
- return 0;
+ result = lua_tointeger(L, -1);
+ lua_pop(L, 1);
+
+ return result;
}
-const char *get_string(lua_State *L, const char *key)
+/*
+ * Encoders.
+ *
+ * This section has functions that convert internal FRR datatypes into Lua
+ * datatypes.
+ */
+
+void lua_pushprefix(lua_State *L, const struct prefix *prefix)
{
- const char *str;
+ char buffer[PREFIX_STRLEN];
- lua_pushstring(L, key);
- lua_gettable(L, -2);
+ lua_newtable(L);
+ lua_pushstring(L, prefix2str(prefix, buffer, PREFIX_STRLEN));
+ lua_setfield(L, -2, "network");
+ lua_pushinteger(L, prefix->prefixlen);
+ lua_setfield(L, -2, "length");
+ lua_pushinteger(L, prefix->family);
+ lua_setfield(L, -2, "family");
+}
- str = (const char *)lua_tostring(L, -1);
+void *lua_toprefix(lua_State *L, int idx)
+{
+ struct prefix *p = XCALLOC(MTYPE_TMP, sizeof(struct prefix));
+
+ lua_getfield(L, idx, "network");
+ str2prefix(lua_tostring(L, -1), p);
lua_pop(L, 1);
- return str;
+ return p;
}
-int get_integer(lua_State *L, const char *key)
+void lua_pushinterface(lua_State *L, const struct interface *ifp)
{
- int result;
+ lua_newtable(L);
+ lua_pushstring(L, ifp->name);
+ lua_setfield(L, -2, "name");
+ lua_pushinteger(L, ifp->ifindex);
+ lua_setfield(L, -2, "ifindex");
+ lua_pushinteger(L, ifp->status);
+ lua_setfield(L, -2, "status");
+ lua_pushinteger(L, ifp->flags);
+ lua_setfield(L, -2, "flags");
+ lua_pushinteger(L, ifp->metric);
+ lua_setfield(L, -2, "metric");
+ lua_pushinteger(L, ifp->speed);
+ lua_setfield(L, -2, "speed");
+ lua_pushinteger(L, ifp->mtu);
+ lua_setfield(L, -2, "mtu");
+ lua_pushinteger(L, ifp->mtu6);
+ lua_setfield(L, -2, "mtu6");
+ lua_pushinteger(L, ifp->bandwidth);
+ lua_setfield(L, -2, "bandwidth");
+ lua_pushinteger(L, ifp->link_ifindex);
+ lua_setfield(L, -2, "link_ifindex");
+ lua_pushinteger(L, ifp->ll_type);
+ lua_setfield(L, -2, "linklayer_type");
+}
- lua_pushstring(L, key);
- lua_gettable(L, -2);
+void *lua_tointerface(lua_State *L, int idx)
+{
+ struct interface *ifp = XCALLOC(MTYPE_TMP, sizeof(struct interface));
- result = lua_tointeger(L, -1);
+ lua_getfield(L, idx, "name");
+ strlcpy(ifp->name, lua_tostring(L, -1), sizeof(ifp->name));
+ lua_pop(L, 1);
+ lua_getfield(L, idx, "ifindex");
+ ifp->ifindex = lua_tointeger(L, -1);
+ lua_pop(L, 1);
+ lua_getfield(L, idx, "status");
+ ifp->status = lua_tointeger(L, -1);
+ lua_pop(L, 1);
+ lua_getfield(L, idx, "flags");
+ ifp->flags = lua_tointeger(L, -1);
+ lua_pop(L, 1);
+ lua_getfield(L, idx, "metric");
+ ifp->metric = lua_tointeger(L, -1);
+ lua_pop(L, 1);
+ lua_getfield(L, idx, "speed");
+ ifp->speed = lua_tointeger(L, -1);
+ lua_pop(L, 1);
+ lua_getfield(L, idx, "mtu");
+ ifp->mtu = lua_tointeger(L, -1);
+ lua_pop(L, 1);
+ lua_getfield(L, idx, "mtu6");
+ ifp->mtu6 = lua_tointeger(L, -1);
+ lua_pop(L, 1);
+ lua_getfield(L, idx, "bandwidth");
+ ifp->bandwidth = lua_tointeger(L, -1);
+ lua_pop(L, 1);
+ lua_getfield(L, idx, "link_ifindex");
+ ifp->link_ifindex = lua_tointeger(L, -1);
+ lua_pop(L, 1);
+ lua_getfield(L, idx, "linklayer_type");
+ ifp->ll_type = lua_tointeger(L, -1);
lua_pop(L, 1);
- return result;
+ return ifp;
}
-static void *lua_alloc(void *ud, void *ptr, size_t osize,
- size_t nsize)
+void lua_pushinaddr(lua_State *L, const struct in_addr *addr)
{
- (void)ud; (void)osize; /* not used */
- if (nsize == 0) {
- free(ptr);
- return NULL;
- } else
- return realloc(ptr, nsize);
+ char buf[INET_ADDRSTRLEN];
+ inet_ntop(AF_INET, addr, buf, sizeof(buf));
+
+ lua_newtable(L);
+ lua_pushinteger(L, addr->s_addr);
+ lua_setfield(L, -2, "value");
+ lua_pushstring(L, buf);
+ lua_setfield(L, -2, "string");
}
-lua_State *lua_initialize(const char *file)
+void *lua_toinaddr(lua_State *L, int idx)
{
- int status;
- lua_State *L = lua_newstate(lua_alloc, NULL);
+ struct in_addr *inaddr = XCALLOC(MTYPE_TMP, sizeof(struct in_addr));
- zlog_debug("Newstate: %p", L);
- luaL_openlibs(L);
- zlog_debug("Opened lib");
- status = luaL_loadfile(L, file);
- if (status) {
- zlog_debug("Failure to open %s %d", file, status);
- lua_close(L);
- return NULL;
- }
+ lua_getfield(L, idx, "value");
+ inaddr->s_addr = lua_tointeger(L, -1);
+ lua_pop(L, 1);
- lua_pcall(L, 0, LUA_MULTRET, 0);
- zlog_debug("Setting global function");
- lua_pushcfunction(L, lua_zlog_debug);
- lua_setglobal(L, "zlog_debug");
+ return inaddr;
+}
+
+
+void lua_pushin6addr(lua_State *L, const struct in6_addr *addr)
+{
+ char buf[INET6_ADDRSTRLEN];
+ inet_ntop(AF_INET6, addr, buf, sizeof(buf));
+
+ lua_newtable(L);
+ lua_pushlstring(L, (const char *)addr->s6_addr, 16);
+ lua_setfield(L, -2, "value");
+ lua_pushstring(L, buf);
+ lua_setfield(L, -2, "string");
+}
+
+void *lua_toin6addr(lua_State *L, int idx)
+{
+ struct in6_addr *in6addr = XCALLOC(MTYPE_TMP, sizeof(struct in6_addr));
+
+ lua_getfield(L, idx, "string");
+ inet_pton(AF_INET6, lua_tostring(L, -1), in6addr);
+ lua_pop(L, 1);
- return L;
+ return in6addr;
}
-void lua_setup_prefix_table(lua_State *L, const struct prefix *prefix)
+void lua_pushsockunion(lua_State *L, const union sockunion *su)
{
- char buffer[100];
+ char buf[SU_ADDRSTRLEN];
+ sockunion2str(su, buf, sizeof(buf));
lua_newtable(L);
- lua_pushstring(L, prefix2str(prefix, buffer, 100));
- lua_setfield(L, -2, "route");
- lua_pushinteger(L, prefix->family);
- lua_setfield(L, -2, "family");
- lua_setglobal(L, "prefix");
+ lua_pushlstring(L, (const char *)sockunion_get_addr(su),
+ sockunion_get_addrlen(su));
+ lua_setfield(L, -2, "value");
+ lua_pushstring(L, buf);
+ lua_setfield(L, -2, "string");
}
-enum lua_rm_status lua_run_rm_rule(lua_State *L, const char *rule)
+void *lua_tosockunion(lua_State *L, int idx)
{
- int status;
+ union sockunion *su = XCALLOC(MTYPE_TMP, sizeof(union sockunion));
+
+ lua_getfield(L, idx, "string");
+ str2sockunion(lua_tostring(L, -1), su);
+
+ return su;
+}
- lua_getglobal(L, rule);
- status = lua_pcall(L, 0, 1, 0);
- if (status) {
- zlog_debug("Executing Failure with function: %s: %d",
- rule, status);
- return LUA_RM_FAILURE;
+void lua_pushtimet(lua_State *L, const time_t *time)
+{
+ lua_pushinteger(L, *time);
+}
+
+void *lua_totimet(lua_State *L, int idx)
+{
+ time_t *t = XCALLOC(MTYPE_TMP, sizeof(time_t));
+
+ *t = lua_tointeger(L, idx);
+
+ return t;
+}
+
+void lua_pushintegerp(lua_State *L, const long long *num)
+{
+ lua_pushinteger(L, *num);
+}
+
+void *lua_tointegerp(lua_State *L, int idx)
+{
+ int isnum;
+ long long *num = XCALLOC(MTYPE_TMP, sizeof(long long));
+
+ *num = lua_tonumberx(L, idx, &isnum);
+ assert(isnum);
+
+ return num;
+}
+
+void *lua_tostringp(lua_State *L, int idx)
+{
+ char *string = XSTRDUP(MTYPE_TMP, lua_tostring(L, idx));
+
+ return string;
+}
+
+/*
+ * Logging.
+ *
+ * Lua-compatible wrappers for FRR logging functions.
+ */
+static const char *frrlua_log_thunk(lua_State *L)
+{
+ int nargs;
+
+ nargs = lua_gettop(L);
+ assert(nargs == 1);
+
+ return lua_tostring(L, 1);
+}
+
+static int frrlua_log_debug(lua_State *L)
+{
+ zlog_debug("%s", frrlua_log_thunk(L));
+ return 0;
+}
+
+static int frrlua_log_info(lua_State *L)
+{
+ zlog_info("%s", frrlua_log_thunk(L));
+ return 0;
+}
+
+static int frrlua_log_notice(lua_State *L)
+{
+ zlog_notice("%s", frrlua_log_thunk(L));
+ return 0;
+}
+
+static int frrlua_log_warn(lua_State *L)
+{
+ zlog_warn("%s", frrlua_log_thunk(L));
+ return 0;
+}
+
+static int frrlua_log_error(lua_State *L)
+{
+ zlog_err("%s", frrlua_log_thunk(L));
+ return 0;
+}
+
+static const luaL_Reg log_funcs[] = {
+ {"debug", frrlua_log_debug},
+ {"info", frrlua_log_info},
+ {"notice", frrlua_log_notice},
+ {"warn", frrlua_log_warn},
+ {"error", frrlua_log_error},
+ {},
+};
+
+void frrlua_export_logging(lua_State *L)
+{
+ lua_newtable(L);
+ luaL_setfuncs(L, log_funcs, 0);
+ lua_setglobal(L, "log");
+}
+
+/*
+ * Debugging.
+ */
+
+char *frrlua_stackdump(lua_State *L)
+{
+ int top = lua_gettop(L);
+
+ char tmpbuf[64];
+ struct buffer *buf = buffer_new(4098);
+
+ for (int i = 1; i <= top; i++) {
+ int t = lua_type(L, i);
+
+ switch (t) {
+ case LUA_TSTRING: /* strings */
+ snprintf(tmpbuf, sizeof(tmpbuf), "\"%s\"\n",
+ lua_tostring(L, i));
+ buffer_putstr(buf, tmpbuf);
+ break;
+ case LUA_TBOOLEAN: /* booleans */
+ snprintf(tmpbuf, sizeof(tmpbuf), "%s\n",
+ lua_toboolean(L, i) ? "true" : "false");
+ buffer_putstr(buf, tmpbuf);
+ break;
+ case LUA_TNUMBER: /* numbers */
+ snprintf(tmpbuf, sizeof(tmpbuf), "%g\n",
+ lua_tonumber(L, i));
+ buffer_putstr(buf, tmpbuf);
+ break;
+ default: /* other values */
+ snprintf(tmpbuf, sizeof(tmpbuf), "%s\n",
+ lua_typename(L, t));
+ buffer_putstr(buf, tmpbuf);
+ break;
+ }
}
- status = lua_tonumber(L, -1);
- return status;
+ char *result = XSTRDUP(MTYPE_TMP, buffer_getstr(buf));
+
+ buffer_free(buf);
+
+ return result;
}
-#endif
+
+#endif /* HAVE_SCRIPTING */
diff --git a/lib/frrlua.h b/lib/frrlua.h
index 40c7a67b89..8e52931e50 100644
--- a/lib/frrlua.h
+++ b/lib/frrlua.h
@@ -1,88 +1,173 @@
/*
- * This file defines the lua interface into
- * FRRouting.
+ * Copyright (C) 2016-2019 Cumulus Networks, Inc.
+ * Donald Sharp, Quentin Young
*
- * Copyright (C) 2016 Cumulus Networks, Inc.
- * Donald Sharp
+ * 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 file is part of FRRouting (FRR).
- *
- * FRR is free software; you can redistribute it and/or modify it under the
- * terms of the GNU General Public License as published by the Free Software
- * Foundation; either version 2, or (at your option) any later version.
- *
- * FRR is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
- * details.
+ * 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 General Public License along
- * with FRR; see the file COPYING. If not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * with this program; see the file COPYING; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
-#ifndef __LUA_H__
-#define __LUA_H__
+#ifndef __FRRLUA_H__
+#define __FRRLUA_H__
+
+#include <zebra.h>
+
+#ifdef HAVE_SCRIPTING
-#if defined(HAVE_LUA)
+#include <lua.h>
+#include <lualib.h>
+#include <lauxlib.h>
-#include "lua.h"
-#include "lualib.h"
-#include "lauxlib.h"
+#include "prefix.h"
+#include "frrscript.h"
#ifdef __cplusplus
extern "C" {
#endif
/*
- * These functions are helper functions that
- * try to glom some of the lua_XXX functionality
- * into what we actually need, instead of having
- * to make multiple calls to set up what
- * we want
+ * Converts a prefix to a Lua value and pushes it on the stack.
+ */
+void lua_pushprefix(lua_State *L, const struct prefix *prefix);
+
+/*
+ * Converts the Lua value at idx to a prefix.
+ *
+ * Returns:
+ * struct prefix allocated with MTYPE_TMP
+ */
+void *lua_toprefix(lua_State *L, int idx);
+
+/*
+ * Converts an interface to a Lua value and pushes it on the stack.
+ */
+void lua_pushinterface(lua_State *L, const struct interface *ifp);
+
+/*
+ * Converts the Lua value at idx to an interface.
+ *
+ * Returns:
+ * struct interface allocated with MTYPE_TMP. This interface is not hooked
+ * to anything, nor is it inserted in the global interface tree.
+ */
+void *lua_tointerface(lua_State *L, int idx);
+
+/*
+ * Converts an in_addr to a Lua value and pushes it on the stack.
+ */
+void lua_pushinaddr(lua_State *L, const struct in_addr *addr);
+
+/*
+ * Converts the Lua value at idx to an in_addr.
+ *
+ * Returns:
+ * struct in_addr allocated with MTYPE_TMP.
+ */
+void *lua_toinaddr(lua_State *L, int idx);
+
+/*
+ * Converts an in6_addr to a Lua value and pushes it on the stack.
*/
-enum lua_rm_status {
- /*
- * Script function run failure. This will translate into a
- * deny
- */
- LUA_RM_FAILURE = 0,
- /*
- * No Match was found for the route map function
- */
- LUA_RM_NOMATCH,
- /*
- * Match was found but no changes were made to the
- * incoming data.
- */
- LUA_RM_MATCH,
- /*
- * Match was found and data was modified, so
- * figure out what changed
- */
- LUA_RM_MATCH_AND_CHANGE,
-};
+void lua_pushin6addr(lua_State *L, const struct in6_addr *addr);
/*
- * Open up the lua.scr file and parse
- * initial global values, if any.
+ * Converts the Lua value at idx to an in6_addr.
+ *
+ * Returns:
+ * struct in6_addr allocated with MTYPE_TMP.
*/
-lua_State *lua_initialize(const char *file);
+void *lua_toin6addr(lua_State *L, int idx);
-void lua_setup_prefix_table(lua_State *L, const struct prefix *prefix);
+/*
+ * Converts a time_t to a Lua value and pushes it on the stack.
+ */
+void lua_pushtimet(lua_State *L, const time_t *time);
-enum lua_rm_status lua_run_rm_rule(lua_State *L, const char *rule);
+/*
+ * Converts the Lua value at idx to a time_t.
+ *
+ * Returns:
+ * time_t allocated with MTYPE_TMP.
+ */
+void *lua_totimet(lua_State *L, int idx);
/*
- * Get particular string/integer information
- * from a table. It is *assumed* that
- * the table has already been selected
+ * Converts a sockunion to a Lua value and pushes it on the stack.
*/
-const char *get_string(lua_State *L, const char *key);
-int get_integer(lua_State *L, const char *key);
+void lua_pushsockunion(lua_State *L, const union sockunion *su);
+
+/*
+ * Converts the Lua value at idx to a sockunion.
+ *
+ * Returns:
+ * sockunion allocated with MTYPE_TMP.
+ */
+void *lua_tosockunion(lua_State *L, int idx);
+
+/*
+ * Converts an int to a Lua value and pushes it on the stack.
+ */
+void lua_pushintegerp(lua_State *L, const long long *num);
+
+/*
+ * Converts the Lua value at idx to an int.
+ *
+ * Returns:
+ * int allocated with MTYPE_TMP.
+ */
+void *lua_tointegerp(lua_State *L, int idx);
+
+/*
+ * Pop string.
+ *
+ * Sets *string to a copy of the string at the top of the stack. The copy is
+ * allocated with MTYPE_TMP and the caller is responsible for freeing it.
+ */
+void *lua_tostringp(lua_State *L, int idx);
+
+/*
+ * Retrieve an integer from table on the top of the stack.
+ *
+ * key
+ * Key of string value in table
+ */
+int frrlua_table_get_integer(lua_State *L, const char *key);
+
+/*
+ * Exports a new table containing bindings to FRR zlog functions into the
+ * global namespace.
+ *
+ * From Lua, these functions may be accessed as:
+ *
+ * - log.debug()
+ * - log.info()
+ * - log.warn()
+ * - log.error()
+ *
+ * They take a single string argument.
+ */
+void frrlua_export_logging(lua_State *L);
+
+/*
+ * Dump Lua stack to a string.
+ *
+ * Return value must be freed with XFREE(MTYPE_TMP, ...);
+ */
+char *frrlua_stackdump(lua_State *L);
#ifdef __cplusplus
}
#endif
-#endif
-#endif
+#endif /* HAVE_SCRIPTING */
+
+#endif /* __FRRLUA_H__ */
diff --git a/lib/frrscript.c b/lib/frrscript.c
new file mode 100644
index 0000000000..a3de474a4e
--- /dev/null
+++ b/lib/frrscript.c
@@ -0,0 +1,272 @@
+/* Scripting foo
+ * Copyright (C) 2020 NVIDIA Corporation
+ * Quentin Young
+ *
+ * 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 General Public License along
+ * with this program; see the file COPYING; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+#include <zebra.h>
+
+#ifdef HAVE_SCRIPTING
+
+#include <stdarg.h>
+#include <lua.h>
+
+#include "frrscript.h"
+#include "frrlua.h"
+#include "memory.h"
+#include "hash.h"
+#include "log.h"
+
+
+DEFINE_MTYPE_STATIC(LIB, SCRIPT, "Scripting");
+
+/* Codecs */
+
+struct frrscript_codec frrscript_codecs_lib[] = {
+ {.typename = "integer",
+ .encoder = (encoder_func)lua_pushintegerp,
+ .decoder = lua_tointegerp},
+ {.typename = "string",
+ .encoder = (encoder_func)lua_pushstring,
+ .decoder = lua_tostringp},
+ {.typename = "prefix",
+ .encoder = (encoder_func)lua_pushprefix,
+ .decoder = lua_toprefix},
+ {.typename = "interface",
+ .encoder = (encoder_func)lua_pushinterface,
+ .decoder = lua_tointerface},
+ {.typename = "in_addr",
+ .encoder = (encoder_func)lua_pushinaddr,
+ .decoder = lua_toinaddr},
+ {.typename = "in6_addr",
+ .encoder = (encoder_func)lua_pushin6addr,
+ .decoder = lua_toin6addr},
+ {.typename = "sockunion",
+ .encoder = (encoder_func)lua_pushsockunion,
+ .decoder = lua_tosockunion},
+ {.typename = "time_t",
+ .encoder = (encoder_func)lua_pushtimet,
+ .decoder = lua_totimet},
+ {}};
+
+/* Type codecs */
+
+struct hash *codec_hash;
+char scriptdir[MAXPATHLEN];
+
+static unsigned int codec_hash_key(const void *data)
+{
+ const struct frrscript_codec *c = data;
+
+ return string_hash_make(c->typename);
+}
+
+static bool codec_hash_cmp(const void *d1, const void *d2)
+{
+ const struct frrscript_codec *e1 = d1;
+ const struct frrscript_codec *e2 = d2;
+
+ return strmatch(e1->typename, e2->typename);
+}
+
+static void *codec_alloc(void *arg)
+{
+ struct frrscript_codec *tmp = arg;
+
+ struct frrscript_codec *e =
+ XCALLOC(MTYPE_SCRIPT, sizeof(struct frrscript_codec));
+ e->typename = XSTRDUP(MTYPE_SCRIPT, tmp->typename);
+ e->encoder = tmp->encoder;
+ e->decoder = tmp->decoder;
+
+ return e;
+}
+
+#if 0
+static void codec_free(struct codec *c)
+{
+ XFREE(MTYPE_TMP, c->typename);
+ XFREE(MTYPE_TMP, c);
+}
+#endif
+
+/* Generic script APIs */
+
+int frrscript_call(struct frrscript *fs, struct frrscript_env *env)
+{
+ struct frrscript_codec c = {};
+ const void *arg;
+ const char *bindname;
+
+ /* Encode script arguments */
+ for (int i = 0; env && env[i].val != NULL; i++) {
+ bindname = env[i].name;
+ c.typename = env[i].typename;
+ arg = env[i].val;
+
+ struct frrscript_codec *codec = hash_lookup(codec_hash, &c);
+ assert(codec && "No encoder for type");
+ codec->encoder(fs->L, arg);
+
+ lua_setglobal(fs->L, bindname);
+ }
+
+ int ret = lua_pcall(fs->L, 0, 0, 0);
+
+ switch (ret) {
+ case LUA_OK:
+ break;
+ case LUA_ERRRUN:
+ zlog_err("Script '%s' runtime error: %s", fs->name,
+ lua_tostring(fs->L, -1));
+ break;
+ case LUA_ERRMEM:
+ zlog_err("Script '%s' memory error: %s", fs->name,
+ lua_tostring(fs->L, -1));
+ break;
+ case LUA_ERRERR:
+ zlog_err("Script '%s' error handler error: %s", fs->name,
+ lua_tostring(fs->L, -1));
+ break;
+ case LUA_ERRGCMM:
+ zlog_err("Script '%s' garbage collector error: %s", fs->name,
+ lua_tostring(fs->L, -1));
+ break;
+ default:
+ zlog_err("Script '%s' unknown error: %s", fs->name,
+ lua_tostring(fs->L, -1));
+ break;
+ }
+
+ if (ret != LUA_OK) {
+ lua_pop(fs->L, 1);
+ goto done;
+ }
+
+done:
+ /* LUA_OK is 0, so we can just return lua_pcall's result directly */
+ return ret;
+}
+
+void *frrscript_get_result(struct frrscript *fs,
+ const struct frrscript_env *result)
+{
+ void *r;
+ struct frrscript_codec c = {.typename = result->typename};
+
+ struct frrscript_codec *codec = hash_lookup(codec_hash, &c);
+ assert(codec && "No encoder for type");
+
+ if (!codec->decoder) {
+ zlog_err("No script decoder for type '%s'", result->typename);
+ return NULL;
+ }
+
+ lua_getglobal(fs->L, result->name);
+ r = codec->decoder(fs->L, -1);
+ lua_pop(fs->L, 1);
+
+ return r;
+}
+
+void frrscript_register_type_codec(struct frrscript_codec *codec)
+{
+ struct frrscript_codec c = *codec;
+
+ if (hash_lookup(codec_hash, &c)) {
+ zlog_backtrace(LOG_ERR);
+ assert(!"Type codec double-registered.");
+ }
+
+ assert(hash_get(codec_hash, &c, codec_alloc));
+}
+
+void frrscript_register_type_codecs(struct frrscript_codec *codecs)
+{
+ for (int i = 0; codecs[i].typename != NULL; i++)
+ frrscript_register_type_codec(&codecs[i]);
+}
+
+struct frrscript *frrscript_load(const char *name,
+ int (*load_cb)(struct frrscript *))
+{
+ struct frrscript *fs = XCALLOC(MTYPE_SCRIPT, sizeof(struct frrscript));
+
+ fs->name = XSTRDUP(MTYPE_SCRIPT, name);
+ fs->L = luaL_newstate();
+ frrlua_export_logging(fs->L);
+
+ char fname[MAXPATHLEN];
+ snprintf(fname, sizeof(fname), "%s/%s.lua", scriptdir, fs->name);
+
+ int ret = luaL_loadfile(fs->L, fname);
+
+ switch (ret) {
+ case LUA_OK:
+ break;
+ case LUA_ERRSYNTAX:
+ zlog_err("Failed loading script '%s': syntax error: %s", fname,
+ lua_tostring(fs->L, -1));
+ break;
+ case LUA_ERRMEM:
+ zlog_err("Failed loading script '%s': out-of-memory error: %s",
+ fname, lua_tostring(fs->L, -1));
+ break;
+ case LUA_ERRGCMM:
+ zlog_err(
+ "Failed loading script '%s': garbage collector error: %s",
+ fname, lua_tostring(fs->L, -1));
+ break;
+ case LUA_ERRFILE:
+ zlog_err("Failed loading script '%s': file read error: %s",
+ fname, lua_tostring(fs->L, -1));
+ break;
+ default:
+ zlog_err("Failed loading script '%s': unknown error: %s", fname,
+ lua_tostring(fs->L, -1));
+ break;
+ }
+
+ if (ret != LUA_OK)
+ goto fail;
+
+ if (load_cb && (*load_cb)(fs) != 0)
+ goto fail;
+
+ return fs;
+fail:
+ frrscript_unload(fs);
+ return NULL;
+}
+
+void frrscript_unload(struct frrscript *fs)
+{
+ lua_close(fs->L);
+ XFREE(MTYPE_SCRIPT, fs->name);
+ XFREE(MTYPE_SCRIPT, fs);
+}
+
+void frrscript_init(const char *sd)
+{
+ codec_hash = hash_create(codec_hash_key, codec_hash_cmp,
+ "Lua type encoders");
+
+ strlcpy(scriptdir, sd, sizeof(scriptdir));
+
+ /* Register core library types */
+ frrscript_register_type_codecs(frrscript_codecs_lib);
+}
+
+#endif /* HAVE_SCRIPTING */
diff --git a/lib/frrscript.h b/lib/frrscript.h
new file mode 100644
index 0000000000..f4057f531b
--- /dev/null
+++ b/lib/frrscript.h
@@ -0,0 +1,138 @@
+/* Scripting foo
+ * Copyright (C) 2020 NVIDIA Corporation
+ * Quentin Young
+ *
+ * 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 General Public License along
+ * with this program; see the file COPYING; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+#ifndef __FRRSCRIPT_H__
+#define __FRRSCRIPT_H__
+
+#include <zebra.h>
+
+#ifdef HAVE_SCRIPTING
+
+#include <lua.h>
+#include "frrlua.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef void (*encoder_func)(lua_State *, const void *);
+typedef void *(*decoder_func)(lua_State *, int);
+
+struct frrscript_codec {
+ const char *typename;
+ encoder_func encoder;
+ decoder_func decoder;
+};
+
+struct frrscript {
+ /* Script name */
+ char *name;
+
+ /* Lua state */
+ struct lua_State *L;
+};
+
+struct frrscript_env {
+ /* Value type */
+ const char *typename;
+
+ /* Binding name */
+ const char *name;
+
+ /* Value */
+ const void *val;
+};
+
+/*
+ * Create new FRR script.
+ */
+struct frrscript *frrscript_load(const char *name,
+ int (*load_cb)(struct frrscript *));
+
+/*
+ * Destroy FRR script.
+ */
+void frrscript_unload(struct frrscript *fs);
+
+/*
+ * Register a Lua codec for a type.
+ *
+ * tname
+ * Name of type; e.g., "peer", "ospf_interface", etc. Chosen at will.
+ *
+ * codec(s)
+ * Function pointer to codec struct. Encoder function should push a Lua
+ * table representing the passed argument - which will have the C type
+ * associated with the chosen 'tname' to the provided stack. The decoder
+ * function should pop a value from the top of the stack and return a heap
+ * chunk containing that value. Allocations should be made with MTYPE_TMP.
+ *
+ * If using the plural function variant, pass a NULL-terminated array.
+ *
+ */
+void frrscript_register_type_codec(struct frrscript_codec *codec);
+void frrscript_register_type_codecs(struct frrscript_codec *codecs);
+
+/*
+ * Initialize scripting subsystem. Call this before anything else.
+ *
+ * scriptdir
+ * Directory in which to look for scripts
+ */
+void frrscript_init(const char *scriptdir);
+
+
+/*
+ * Call script.
+ *
+ * fs
+ * The script to call; this is obtained from frrscript_load().
+ *
+ * env
+ * The script's environment. Specify this as an array of frrscript_env.
+ *
+ * Returns:
+ * 0 if the script ran successfully, nonzero otherwise.
+ */
+int frrscript_call(struct frrscript *fs, struct frrscript_env *env);
+
+
+/*
+ * Get result from finished script.
+ *
+ * fs
+ * The script. This script must have been run already.
+ *
+ * result
+ * The result to extract from the script.
+ * This reuses the frrscript_env type, but only the typename and name fields
+ * need to be set. The value is returned directly.
+ *
+ * Returns:
+ * The script result of the specified name and type, or NULL.
+ */
+void *frrscript_get_result(struct frrscript *fs,
+ const struct frrscript_env *result);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* HAVE_SCRIPTING */
+
+#endif /* __FRRSCRIPT_H__ */
diff --git a/lib/libfrr.c b/lib/libfrr.c
index 8e7777a1a9..b83883779c 100644
--- a/lib/libfrr.c
+++ b/lib/libfrr.c
@@ -43,6 +43,7 @@
#include "frrcu.h"
#include "frr_pthread.h"
#include "defaults.h"
+#include "frrscript.h"
DEFINE_HOOK(frr_late_init, (struct thread_master * tm), (tm))
DEFINE_HOOK(frr_very_late_init, (struct thread_master * tm), (tm))
@@ -55,6 +56,7 @@ char frr_vtydir[256];
const char frr_dbdir[] = DAEMON_DB_DIR;
#endif
const char frr_moduledir[] = MODULE_PATH;
+const char frr_scriptdir[] = SCRIPT_PATH;
char frr_protoname[256] = "NONE";
char frr_protonameinst[256] = "NONE";
@@ -100,6 +102,7 @@ static void opt_extend(const struct optspec *os)
#define OPTION_DB_FILE 1006
#define OPTION_LOGGING 1007
#define OPTION_LIMIT_FDS 1008
+#define OPTION_SCRIPTDIR 1009
static const struct option lo_always[] = {
{"help", no_argument, NULL, 'h'},
@@ -110,6 +113,7 @@ static const struct option lo_always[] = {
{"pathspace", required_argument, NULL, 'N'},
{"vty_socket", required_argument, NULL, OPTION_VTYSOCK},
{"moduledir", required_argument, NULL, OPTION_MODULEDIR},
+ {"scriptdir", required_argument, NULL, OPTION_SCRIPTDIR},
{"log", required_argument, NULL, OPTION_LOG},
{"log-level", required_argument, NULL, OPTION_LOGLEVEL},
{"tcli", no_argument, NULL, OPTION_TCLI},
@@ -126,6 +130,7 @@ static const struct optspec os_always = {
" -N, --pathspace Insert prefix into config & socket paths\n"
" --vty_socket Override vty socket path\n"
" --moduledir Override modules directory\n"
+ " --scriptdir Override scripts directory\n"
" --log Set Logging to stdout, syslog, or file:<name>\n"
" --log-level Set Logging Level to use, debug, info, warn, etc\n"
" --tcli Use transaction-based CLI\n"
@@ -533,6 +538,14 @@ static int frr_opt(int opt)
}
di->module_path = optarg;
break;
+ case OPTION_SCRIPTDIR:
+ if (di->script_path) {
+ fprintf(stderr, "--scriptdir option specified more than once!\n");
+ errors++;
+ break;
+ }
+ di->script_path = optarg;
+ break;
case OPTION_TCLI:
di->cli_mode = FRR_CLI_TRANSACTIONAL;
break;
@@ -717,6 +730,9 @@ struct thread_master *frr_init(void)
lib_cmd_init();
frr_pthread_init();
+#ifdef HAVE_SCRIPTING
+ frrscript_init(di->script_path ? di->script_path : frr_scriptdir);
+#endif
log_ref_init();
log_ref_vty_init();
diff --git a/lib/libfrr.h b/lib/libfrr.h
index 2e4dcbe093..c446931468 100644
--- a/lib/libfrr.h
+++ b/lib/libfrr.h
@@ -81,6 +81,7 @@ struct frr_daemon_info {
#endif
const char *vty_path;
const char *module_path;
+ const char *script_path;
const char *pathspace;
bool zpathspace;
@@ -162,6 +163,7 @@ extern char frr_zclientpath[256];
extern const char frr_sysconfdir[];
extern char frr_vtydir[256];
extern const char frr_moduledir[];
+extern const char frr_scriptdir[];
extern char frr_protoname[];
extern char frr_protonameinst[];
diff --git a/lib/northbound_cli.c b/lib/northbound_cli.c
index 7048df99fb..853f643472 100644
--- a/lib/northbound_cli.c
+++ b/lib/northbound_cli.c
@@ -693,6 +693,12 @@ static int nb_write_config(struct nb_config *config, enum nb_cfg_format format,
__func__, safe_strerror(errno));
return -1;
}
+ if (fchmod(fd, CONFIGFILE_MASK) != 0) {
+ flog_warn(EC_LIB_SYSTEM_CALL,
+ "%s: fchmod() failed: %s(%d):", __func__,
+ safe_strerror(errno), errno);
+ return -1;
+ }
/* Make vty for configuration file. */
file_vty = vty_new();
diff --git a/lib/subdir.am b/lib/subdir.am
index ee9e827ee8..570e0c3d28 100644
--- a/lib/subdir.am
+++ b/lib/subdir.am
@@ -26,6 +26,7 @@ lib_libfrr_la_SOURCES = \
lib/filter_nb.c \
lib/frrcu.c \
lib/frrlua.c \
+ lib/frrscript.c \
lib/frr_pthread.c \
lib/frrstr.c \
lib/getopt.c \
@@ -185,6 +186,7 @@ pkginclude_HEADERS += \
lib/filter.h \
lib/freebsd-queue.h \
lib/frrlua.h \
+ lib/frrscript.h \
lib/frr_pthread.h \
lib/frratomic.h \
lib/frrcu.h \
diff --git a/lib/zclient.c b/lib/zclient.c
index cb4555650d..f16c94369b 100644
--- a/lib/zclient.c
+++ b/lib/zclient.c
@@ -40,6 +40,7 @@
#include "nexthop_group.h"
#include "lib_errors.h"
#include "srte.h"
+#include "printfrr.h"
DEFINE_MTYPE_STATIC(LIB, ZCLIENT, "Zclient")
DEFINE_MTYPE_STATIC(LIB, REDIST_INST, "Redistribution instance IDs")
@@ -4121,3 +4122,51 @@ uint32_t zclient_get_nhg_start(uint32_t proto)
return ZEBRA_NHG_PROTO_SPACING * proto;
}
+
+char *zclient_dump_route_flags(uint32_t flags, char *buf, size_t len)
+{
+ if (flags == 0) {
+ snprintfrr(buf, len, "None ");
+ return buf;
+ }
+
+ snprintfrr(
+ buf, len, "%s%s%s%s%s%s%s%s%s%s",
+ CHECK_FLAG(flags, ZEBRA_FLAG_ALLOW_RECURSION) ? "Recursion "
+ : "",
+ CHECK_FLAG(flags, ZEBRA_FLAG_SELFROUTE) ? "Self " : "",
+ CHECK_FLAG(flags, ZEBRA_FLAG_IBGP) ? "iBGP " : "",
+ CHECK_FLAG(flags, ZEBRA_FLAG_SELECTED) ? "Selected " : "",
+ CHECK_FLAG(flags, ZEBRA_FLAG_FIB_OVERRIDE) ? "Override " : "",
+ CHECK_FLAG(flags, ZEBRA_FLAG_EVPN_ROUTE) ? "Evpn " : "",
+ CHECK_FLAG(flags, ZEBRA_FLAG_RR_USE_DISTANCE) ? "RR Distance "
+ : "",
+ CHECK_FLAG(flags, ZEBRA_FLAG_TRAPPED) ? "Trapped " : "",
+ CHECK_FLAG(flags, ZEBRA_FLAG_OFFLOADED) ? "Offloaded " : "",
+ CHECK_FLAG(flags, ZEBRA_FLAG_OFFLOAD_FAILED) ? "Offload Failed "
+ : "");
+ return buf;
+}
+
+char *zclient_evpn_dump_macip_flags(uint8_t flags, char *buf, size_t len)
+{
+ if (flags == 0) {
+ snprintfrr(buf, len, "None ");
+ return buf;
+ }
+
+ snprintfrr(
+ buf, len, "%s%s%s%s%s%s%s",
+ CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_STICKY) ? "Sticky MAC " : "",
+ CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_GW) ? "Gateway MAC " : "",
+ CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_ROUTER_FLAG) ? "Router "
+ : "",
+ CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_OVERRIDE_FLAG) ? "Override "
+ : "",
+ CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_SVI_IP) ? "SVI MAC " : "",
+ CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_PROXY_ADVERT) ? "Proxy "
+ : "",
+ CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_SYNC_PATH) ? "Sync " : "");
+
+ return buf;
+}
diff --git a/lib/zclient.h b/lib/zclient.h
index 910a4dbae5..57bad7c2e6 100644
--- a/lib/zclient.h
+++ b/lib/zclient.h
@@ -479,6 +479,7 @@ struct zapi_route {
uint8_t type;
unsigned short instance;
+ /* If you add flags, update zclient_dump_route_flags */
uint32_t flags;
/*
* Cause Zebra to consider this routes nexthops recursively
@@ -580,6 +581,8 @@ struct zapi_route {
} opaque;
};
+extern char *zclient_dump_route_flags(uint32_t flags, char *buf, size_t len);
+
struct zapi_labels {
uint8_t message;
#define ZAPI_LABELS_FTN 0x01
@@ -768,8 +771,11 @@ zapi_rule_notify_owner2str(enum zapi_rule_notify_owner note)
#define ZEBRA_MACIP_TYPE_PROXY_ADVERT 0x20 /* Not locally active */
#define ZEBRA_MACIP_TYPE_SYNC_PATH 0x40 /* sync path */
/* XXX - flags is an u8; that needs to be changed to u32 if you need
- * to allocate past 0x80
+ * to allocate past 0x80. Additionally touch zclient_evpn_dump_macip_flags
*/
+#define MACIP_BUF_SIZE 128
+extern char *zclient_evpn_dump_macip_flags(uint8_t flags, char *buf,
+ size_t len);
/* Zebra ES VTEP flags (ZEBRA_REMOTE_ES_VTEP_ADD) */
/* ESR has been rxed from the VTEP. Only VTEPs that have advertised the
diff --git a/ospfd/ospf_ase.c b/ospfd/ospf_ase.c
index e99653f918..e18d8ddb31 100644
--- a/ospfd/ospf_ase.c
+++ b/ospfd/ospf_ase.c
@@ -748,8 +748,13 @@ void ospf_ase_unregister_external_lsa(struct ospf_lsa *lsa, struct ospf *top)
if (rn) {
lst = rn->info;
- listnode_delete(lst, lsa);
- ospf_lsa_unlock(&lsa); /* external_lsas list */
+ struct listnode *node = listnode_lookup(lst, lsa);
+ /* Unlock lsa only if node is present in the list */
+ if (node) {
+ listnode_delete(lst, lsa);
+ ospf_lsa_unlock(&lsa); /* external_lsas list */
+ }
+
route_unlock_node(rn);
}
}
diff --git a/ospfd/ospf_lsa.c b/ospfd/ospf_lsa.c
index d5eba74fd4..4c9db16c6b 100644
--- a/ospfd/ospf_lsa.c
+++ b/ospfd/ospf_lsa.c
@@ -2789,7 +2789,7 @@ int ospf_check_nbr_status(struct ospf *ospf)
static int ospf_maxage_lsa_remover(struct thread *thread)
{
struct ospf *ospf = THREAD_ARG(thread);
- struct ospf_lsa *lsa;
+ struct ospf_lsa *lsa, *old;
struct route_node *rn;
int reschedule = 0;
@@ -2851,6 +2851,17 @@ static int ospf_maxage_lsa_remover(struct thread *thread)
/* Remove from lsdb. */
if (lsa->lsdb) {
+ old = ospf_lsdb_lookup(lsa->lsdb, lsa);
+ /* The max age LSA here must be the same
+ * as the LSA in LSDB
+ */
+ if (old != lsa) {
+ flog_err(EC_OSPF_LSA_MISSING,
+ "%s: LSA[Type%d:%s]: LSA not in LSDB",
+ __func__, lsa->data->type,
+ inet_ntoa(lsa->data->id));
+ continue;
+ }
ospf_discard_from_db(ospf, lsa->lsdb, lsa);
ospf_lsdb_delete(lsa->lsdb, lsa);
} else {
diff --git a/ospfd/ospf_vty.c b/ospfd/ospf_vty.c
index c58073c521..68ad62cda4 100644
--- a/ospfd/ospf_vty.c
+++ b/ospfd/ospf_vty.c
@@ -280,7 +280,7 @@ DEFPY (ospf_router_id,
for (ALL_LIST_ELEMENTS_RO(ospf->areas, node, area))
if (area->full_nbrs) {
vty_out(vty,
- "For this router-id change to take effect, save config and restart ospfd\n");
+ "For this router-id change to take effect, use “clear ip ospf process” command\n");
return CMD_SUCCESS;
}
@@ -313,7 +313,7 @@ DEFUN_HIDDEN (ospf_router_id_old,
for (ALL_LIST_ELEMENTS_RO(ospf->areas, node, area))
if (area->full_nbrs) {
vty_out(vty,
- "For this router-id change to take effect, save config and restart ospfd\n");
+ "For this router-id change to take effect, use “clear ip ospf process” command\n");
return CMD_SUCCESS;
}
@@ -346,7 +346,7 @@ DEFPY (no_ospf_router_id,
for (ALL_LIST_ELEMENTS_RO(ospf->areas, node, area))
if (area->full_nbrs) {
vty_out(vty,
- "For this router-id change to take effect, save config and restart ospfd\n");
+ "For this router-id change to take effect, use “clear ip ospf process” command\n");
return CMD_SUCCESS;
}
@@ -11227,6 +11227,70 @@ DEFUN (show_ip_ospf_vrfs,
return CMD_SUCCESS;
}
+DEFPY (clear_ip_ospf_neighbor,
+ clear_ip_ospf_neighbor_cmd,
+ "clear ip ospf [(1-65535)]$instance neighbor [A.B.C.D$nbr_id]",
+ CLEAR_STR
+ IP_STR
+ "OSPF information\n"
+ "Instance ID\n"
+ "Reset OSPF Neighbor\n"
+ "Neighbor ID\n")
+{
+ struct listnode *node;
+ struct ospf *ospf = NULL;
+
+ /* If user does not specify the arguments,
+ * instance = 0 and nbr_id = 0.0.0.0
+ */
+ if (instance != 0) {
+ /* This means clear only the particular ospf process */
+ ospf = ospf_lookup_instance(instance);
+ if (ospf == NULL)
+ return CMD_NOT_MY_INSTANCE;
+ }
+
+ /* Clear all the ospf processes */
+ for (ALL_LIST_ELEMENTS_RO(om->ospf, node, ospf)) {
+ if (!ospf->oi_running)
+ continue;
+
+ ospf_neighbor_reset(ospf, nbr_id, nbr_id_str);
+ }
+
+ return CMD_SUCCESS;
+}
+
+DEFPY (clear_ip_ospf_process,
+ clear_ip_ospf_process_cmd,
+ "clear ip ospf [(1-65535)]$instance process",
+ CLEAR_STR
+ IP_STR
+ "OSPF information\n"
+ "Instance ID\n"
+ "Reset OSPF Process\n")
+{
+ struct listnode *node;
+ struct ospf *ospf = NULL;
+
+ /* Check if instance is not passed as an argument */
+ if (instance != 0) {
+ /* This means clear only the particular ospf process */
+ ospf = ospf_lookup_instance(instance);
+ if (ospf == NULL)
+ return CMD_NOT_MY_INSTANCE;
+ }
+
+ /* Clear all the ospf processes */
+ for (ALL_LIST_ELEMENTS_RO(om->ospf, node, ospf)) {
+ if (!ospf->oi_running)
+ continue;
+
+ ospf_process_reset(ospf);
+ }
+
+ return CMD_SUCCESS;
+}
static const char *const ospf_abr_type_str[] = {
"unknown", "standard", "ibm", "cisco", "shortcut"
@@ -12623,6 +12687,8 @@ DEFUN (clear_ip_ospf_interface,
void ospf_vty_clear_init(void)
{
install_element(ENABLE_NODE, &clear_ip_ospf_interface_cmd);
+ install_element(ENABLE_NODE, &clear_ip_ospf_process_cmd);
+ install_element(ENABLE_NODE, &clear_ip_ospf_neighbor_cmd);
}
diff --git a/ospfd/ospfd.c b/ospfd/ospfd.c
index 0adf8a7b41..bab75995b7 100644
--- a/ospfd/ospfd.c
+++ b/ospfd/ospfd.c
@@ -87,13 +87,15 @@ static void ospf_finish_final(struct ospf *);
#define OSPF_EXTERNAL_LSA_ORIGINATE_DELAY 1
-void ospf_router_id_update(struct ospf *ospf)
+void ospf_process_refresh_data(struct ospf *ospf, bool reset)
{
struct vrf *vrf = vrf_lookup_by_id(ospf->vrf_id);
struct in_addr router_id, router_id_old;
struct ospf_interface *oi;
struct interface *ifp;
- struct listnode *node;
+ struct listnode *node, *nnode;
+ struct ospf_area *area;
+ bool rid_change = false;
if (!ospf->oi_running) {
if (IS_DEBUG_OSPF_EVENT)
@@ -126,8 +128,8 @@ void ospf_router_id_update(struct ospf *ospf)
zlog_debug("Router-ID[OLD:%pI4]: Update to %pI4",
&ospf->router_id, &router_id);
- if (!IPV4_ADDR_SAME(&router_id_old, &router_id)) {
-
+ rid_change = !(IPV4_ADDR_SAME(&router_id_old, &router_id));
+ if (rid_change || (reset)) {
for (ALL_LIST_ELEMENTS_RO(ospf->oiflist, node, oi)) {
/* Some nbrs are identified by router_id, these needs
* to be rebuilt. Possible optimization would be to do
@@ -149,16 +151,8 @@ void ospf_router_id_update(struct ospf *ospf)
ospf_if_up(oi);
}
- /* Flush (inline) all external LSAs based on the OSPF_LSA_SELF
- * flag */
- if (ospf->lsdb) {
- struct route_node *rn;
- struct ospf_lsa *lsa;
-
- LSDB_LOOP (EXTERNAL_LSDB(ospf), rn, lsa)
- if (IS_LSA_SELF(lsa))
- ospf_lsa_flush_schedule(ospf, lsa);
- }
+ /* Flush (inline) all the self originated LSAs */
+ ospf_flush_self_originated_lsas_now(ospf);
ospf->router_id = router_id;
if (IS_DEBUG_OSPF_EVENT)
@@ -183,24 +177,81 @@ void ospf_router_id_update(struct ospf *ospf)
LSDB_LOOP (EXTERNAL_LSDB(ospf), rn, lsa) {
/* AdvRouter and Router ID is the same. */
if (IPV4_ADDR_SAME(&lsa->data->adv_router,
- &ospf->router_id)) {
+ &ospf->router_id) && rid_change) {
SET_FLAG(lsa->flags,
OSPF_LSA_SELF_CHECKED);
SET_FLAG(lsa->flags, OSPF_LSA_SELF);
ospf_lsa_flush_schedule(ospf, lsa);
}
+ /* The above flush will send immediately
+ * So discard the LSA to originate new
+ */
+ ospf_discard_from_db(ospf, ospf->lsdb, lsa);
}
+
+ LSDB_LOOP (OPAQUE_AS_LSDB(ospf), rn, lsa)
+ ospf_discard_from_db(ospf, ospf->lsdb, lsa);
+
+ ospf_lsdb_delete_all(ospf->lsdb);
}
+ /* Delete the LSDB */
+ for (ALL_LIST_ELEMENTS(ospf->areas, node, nnode, area))
+ ospf_area_lsdb_discard_delete(area);
+
/* update router-lsa's for each area */
ospf_router_lsa_update(ospf);
/* update ospf_interface's */
- FOR_ALL_INTERFACES (vrf, ifp)
- ospf_if_update(ospf, ifp);
+ FOR_ALL_INTERFACES (vrf, ifp) {
+ if (reset)
+ ospf_if_reset(ifp);
+ else
+ ospf_if_update(ospf, ifp);
+ }
ospf_external_lsa_rid_change(ospf);
}
+
+ ospf->inst_shutdown = 0;
+}
+
+void ospf_router_id_update(struct ospf *ospf)
+{
+ ospf_process_refresh_data(ospf, false);
+}
+
+void ospf_process_reset(struct ospf *ospf)
+{
+ ospf_process_refresh_data(ospf, true);
+}
+
+void ospf_neighbor_reset(struct ospf *ospf, struct in_addr nbr_id,
+ const char *nbr_str)
+{
+ struct route_node *rn;
+ struct ospf_neighbor *nbr;
+ struct ospf_interface *oi;
+ struct listnode *node;
+
+ /* Clear only a particular nbr with nbr router id as nbr_id */
+ if (nbr_str != NULL) {
+ for (ALL_LIST_ELEMENTS_RO(ospf->oiflist, node, oi)) {
+ nbr = ospf_nbr_lookup_by_routerid(oi->nbrs, &nbr_id);
+ if (nbr)
+ OSPF_NSM_EVENT_EXECUTE(nbr, NSM_KillNbr);
+ }
+ return;
+ }
+
+ /* send Neighbor event KillNbr to all associated neighbors. */
+ for (ALL_LIST_ELEMENTS_RO(ospf->oiflist, node, oi)) {
+ for (rn = route_top(oi->nbrs); rn; rn = route_next(rn)) {
+ nbr = rn->info;
+ if (nbr && (nbr != oi->nbr_self))
+ OSPF_NSM_EVENT_EXECUTE(nbr, NSM_KillNbr);
+ }
+ }
}
/* For OSPF area sort by area id. */
@@ -870,14 +921,11 @@ static struct ospf_area *ospf_area_new(struct ospf *ospf,
return new;
}
-static void ospf_area_free(struct ospf_area *area)
+void ospf_area_lsdb_discard_delete(struct ospf_area *area)
{
struct route_node *rn;
struct ospf_lsa *lsa;
- ospf_opaque_type10_lsa_term(area);
-
- /* Free LSDBs. */
LSDB_LOOP (ROUTER_LSDB(area), rn, lsa)
ospf_discard_from_db(area->ospf, area->lsdb, lsa);
LSDB_LOOP (NETWORK_LSDB(area), rn, lsa)
@@ -895,6 +943,15 @@ static void ospf_area_free(struct ospf_area *area)
ospf_discard_from_db(area->ospf, area->lsdb, lsa);
ospf_lsdb_delete_all(area->lsdb);
+}
+
+static void ospf_area_free(struct ospf_area *area)
+{
+ ospf_opaque_type10_lsa_term(area);
+
+ /* Free LSDBs. */
+ ospf_area_lsdb_discard_delete(area);
+
ospf_lsdb_free(area->lsdb);
ospf_lsa_unlock(&area->router_lsa_self);
diff --git a/ospfd/ospfd.h b/ospfd/ospfd.h
index 3087b735ae..6960d151c2 100644
--- a/ospfd/ospfd.h
+++ b/ospfd/ospfd.h
@@ -571,7 +571,11 @@ extern struct ospf *ospf_lookup_by_inst_name(unsigned short instance,
const char *name);
extern struct ospf *ospf_lookup_by_vrf_id(vrf_id_t vrf_id);
extern void ospf_finish(struct ospf *);
+extern void ospf_process_refresh_data(struct ospf *ospf, bool reset);
extern void ospf_router_id_update(struct ospf *ospf);
+extern void ospf_process_reset(struct ospf *ospf);
+extern void ospf_neighbor_reset(struct ospf *ospf, struct in_addr nbr_id,
+ const char *nbr_str);
extern int ospf_network_set(struct ospf *, struct prefix_ipv4 *, struct in_addr,
int);
extern int ospf_network_unset(struct ospf *, struct prefix_ipv4 *,
@@ -596,6 +600,7 @@ extern int ospf_area_shortcut_set(struct ospf *, struct ospf_area *, int);
extern int ospf_area_shortcut_unset(struct ospf *, struct ospf_area *);
extern int ospf_timers_refresh_set(struct ospf *, int);
extern int ospf_timers_refresh_unset(struct ospf *);
+void ospf_area_lsdb_discard_delete(struct ospf_area *area);
extern int ospf_nbr_nbma_set(struct ospf *, struct in_addr);
extern int ospf_nbr_nbma_unset(struct ospf *, struct in_addr);
extern int ospf_nbr_nbma_priority_set(struct ospf *, struct in_addr, uint8_t);
diff --git a/pbrd/pbr_nht.c b/pbrd/pbr_nht.c
index dbe5de724c..f99971ab7b 100644
--- a/pbrd/pbr_nht.c
+++ b/pbrd/pbr_nht.c
@@ -770,18 +770,20 @@ pbr_nht_individual_nexthop_gw_update(struct pbr_nexthop_cache *pnhc,
goto done;
}
- switch (pnhi->nhr->prefix.family) {
- case AF_INET:
- if (pnhc->nexthop.gate.ipv4.s_addr
- != pnhi->nhr->prefix.u.prefix4.s_addr)
- goto done; /* Unrelated change */
- break;
- case AF_INET6:
- if (memcmp(&pnhc->nexthop.gate.ipv6,
- &pnhi->nhr->prefix.u.prefix6, 16)
- != 0)
- goto done; /* Unrelated change */
- break;
+ if (pnhi->nhr) {
+ switch (pnhi->nhr->prefix.family) {
+ case AF_INET:
+ if (pnhc->nexthop.gate.ipv4.s_addr
+ != pnhi->nhr->prefix.u.prefix4.s_addr)
+ goto done; /* Unrelated change */
+ break;
+ case AF_INET6:
+ if (memcmp(&pnhc->nexthop.gate.ipv6,
+ &pnhi->nhr->prefix.u.prefix6, 16)
+ != 0)
+ goto done; /* Unrelated change */
+ break;
+ }
}
pnhi->nhr_matched = true;
diff --git a/staticd/static_nb.c b/staticd/static_nb.c
index 2010020367..a2a14751cf 100644
--- a/staticd/static_nb.c
+++ b/staticd/static_nb.c
@@ -47,12 +47,6 @@ const struct frr_yang_module_info frr_staticd_info = {
}
},
{
- .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/route-list/path-list/table-id",
- .cbs = {
- .modify = routing_control_plane_protocols_control_plane_protocol_staticd_route_list_path_list_table_id_modify,
- }
- },
- {
.xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/route-list/path-list/frr-nexthops/nexthop",
.cbs = {
.apply_finish = routing_control_plane_protocols_control_plane_protocol_staticd_route_list_path_list_frr_nexthops_nexthop_apply_finish,
@@ -131,12 +125,6 @@ const struct frr_yang_module_info frr_staticd_info = {
}
},
{
- .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/route-list/src-list/path-list/table-id",
- .cbs = {
- .modify = routing_control_plane_protocols_control_plane_protocol_staticd_route_list_src_list_path_list_table_id_modify,
- }
- },
- {
.xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/route-list/src-list/path-list/frr-nexthops/nexthop",
.cbs = {
.apply_finish = routing_control_plane_protocols_control_plane_protocol_staticd_route_list_src_list_path_list_frr_nexthops_nexthop_apply_finish,
diff --git a/staticd/static_nb.h b/staticd/static_nb.h
index 0a846ab6fb..e85e1d0e9f 100644
--- a/staticd/static_nb.h
+++ b/staticd/static_nb.h
@@ -31,8 +31,6 @@ int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_pa
struct nb_cb_destroy_args *args);
int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_path_list_tag_modify(
struct nb_cb_modify_args *args);
-int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_path_list_table_id_modify(
- struct nb_cb_modify_args *args);
int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_path_list_frr_nexthops_nexthop_create(
struct nb_cb_create_args *args);
int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_path_list_frr_nexthops_nexthop_destroy(
@@ -73,8 +71,6 @@ int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_sr
struct nb_cb_destroy_args *args);
int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_src_list_path_list_tag_modify(
struct nb_cb_modify_args *args);
-int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_src_list_path_list_table_id_modify(
- struct nb_cb_modify_args *args);
int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_src_list_path_list_frr_nexthops_nexthop_create(
struct nb_cb_create_args *args);
int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_src_list_path_list_frr_nexthops_nexthop_destroy(
@@ -130,13 +126,11 @@ int routing_control_plane_protocols_name_validate(
"/frr-routing:routing/control-plane-protocols/" \
"control-plane-protocol[type='%s'][name='%s'][vrf='%s']/" \
"frr-staticd:staticd/route-list[prefix='%s'][afi-safi='%s']/" \
- "path-list[distance='%u']"
+ "path-list[table-id='%u'][distance='%u']"
#define FRR_STATIC_ROUTE_PATH_TAG_XPATH "/tag"
-#define FRR_STATIC_ROUTE_PATH_TABLEID_XPATH "/table-id"
-
/* route-list/frr-nexthops */
#define FRR_STATIC_ROUTE_NH_KEY_XPATH \
"/frr-nexthops/" \
@@ -157,7 +151,7 @@ int routing_control_plane_protocols_name_validate(
"/frr-routing:routing/control-plane-protocols/" \
"control-plane-protocol[type='%s'][name='%s'][vrf='%s']/" \
"frr-staticd:staticd/route-list[prefix='%s'][afi-safi='%s']/" \
- "src-list[src-prefix='%s']/path-list[distance='%u']"
+ "src-list[src-prefix='%s']/path-list[table-id='%u'][distance='%u']"
/* route-list/frr-nexthops */
#define FRR_DEL_S_ROUTE_NH_KEY_XPATH \
diff --git a/staticd/static_nb_config.c b/staticd/static_nb_config.c
index 1360660bce..bf669957bf 100644
--- a/staticd/static_nb_config.c
+++ b/staticd/static_nb_config.c
@@ -35,17 +35,40 @@ static int static_path_list_create(struct nb_cb_create_args *args)
{
struct route_node *rn;
struct static_path *pn;
+ const struct lyd_node *vrf_dnode;
+ const char *vrf;
uint8_t distance;
+ uint32_t table_id;
switch (args->event) {
case NB_EV_VALIDATE:
+ vrf_dnode = yang_dnode_get_parent(args->dnode,
+ "control-plane-protocol");
+ vrf = yang_dnode_get_string(vrf_dnode, "./vrf");
+ table_id = yang_dnode_get_uint32(args->dnode, "./table-id");
+
+ /*
+ * TableId is not applicable for VRF. Consider the case of
+ * l3mdev, there is one uint32_t space to work with.
+ * A l3mdev device points at a specific table that it
+ * relates to and a set of interfaces it belongs to.
+ */
+ if (table_id && (strcmp(vrf, vrf_get_default_name()) != 0)
+ && !vrf_is_backend_netns()) {
+ snprintf(
+ args->errmsg, args->errmsg_len,
+ "%% table param only available when running on netns-based vrfs");
+ return NB_ERR_VALIDATION;
+ }
+ break;
case NB_EV_ABORT:
case NB_EV_PREPARE:
break;
case NB_EV_APPLY:
rn = nb_running_get_entry(args->dnode, NULL, true);
distance = yang_dnode_get_uint8(args->dnode, "./distance");
- pn = static_add_path(rn, distance);
+ table_id = yang_dnode_get_uint32(args->dnode, "./table-id");
+ pn = static_add_path(rn, table_id, distance);
nb_running_set_entry(args->dnode, pn);
}
@@ -80,44 +103,6 @@ static void static_path_list_tag_modify(struct nb_cb_modify_args *args,
static_install_path(rn, pn, info->safi, info->svrf);
}
-static int static_path_list_tableid_modify(struct nb_cb_modify_args *args,
- const struct lyd_node *rn_dnode,
- struct stable_info *info)
-{
- struct static_path *pn;
- struct route_node *rn;
- uint32_t table_id;
- const struct lyd_node *vrf_dnode;
- const char *vrf;
-
- switch (args->event) {
- case NB_EV_VALIDATE:
- vrf_dnode = yang_dnode_get_parent(args->dnode,
- "control-plane-protocol");
- vrf = yang_dnode_get_string(vrf_dnode, "./vrf");
- table_id = yang_dnode_get_uint32(args->dnode, NULL);
- if (table_id && (strcmp(vrf, vrf_get_default_name()) != 0)
- && !vrf_is_backend_netns()) {
- snprintf(args->errmsg, args->errmsg_len,
- "%% table param only available when running on netns-based vrfs");
- return NB_ERR_VALIDATION;
- }
- break;
- case NB_EV_PREPARE:
- case NB_EV_ABORT:
- break;
- case NB_EV_APPLY:
- table_id = yang_dnode_get_uint32(args->dnode, NULL);
- pn = nb_running_get_entry(args->dnode, NULL, true);
- pn->table_id = table_id;
- rn = nb_running_get_entry(rn_dnode, NULL, true);
- static_install_path(rn, pn, info->safi, info->svrf);
- break;
- }
-
- return NB_OK;
-}
-
static bool static_nexthop_create(struct nb_cb_create_args *args,
const struct lyd_node *rn_dnode,
struct stable_info *info)
@@ -614,38 +599,6 @@ int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_pa
/*
* XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/route-list/path-list/table-id
- */
-int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_path_list_table_id_modify(
- struct nb_cb_modify_args *args)
-{
- struct route_node *rn;
- const struct lyd_node *rn_dnode;
- struct stable_info *info;
-
- switch (args->event) {
- case NB_EV_VALIDATE:
- if (static_path_list_tableid_modify(args, NULL, NULL) != NB_OK)
- return NB_ERR_VALIDATION;
- break;
- case NB_EV_PREPARE:
- case NB_EV_ABORT:
- break;
- case NB_EV_APPLY:
- rn_dnode = yang_dnode_get_parent(args->dnode, "route-list");
- rn = nb_running_get_entry(rn_dnode, NULL, true);
- info = route_table_get_info(rn->table);
-
- if (static_path_list_tableid_modify(args, rn_dnode, info)
- != NB_OK)
- return NB_ERR_VALIDATION;
- break;
- }
- return NB_OK;
-}
-
-/*
- * XPath:
* /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/route-list/path-list/frr-nexthops/nexthop
*/
int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_path_list_frr_nexthops_nexthop_create(
@@ -1021,41 +974,6 @@ int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_sr
/*
* XPath:
- * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/route-list/src-list/path-list/table-id
- */
-int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_src_list_path_list_table_id_modify(
- struct nb_cb_modify_args *args)
-{
- struct route_node *rn;
- const struct lyd_node *rn_dnode;
- const struct lyd_node *src_dnode;
- struct stable_info *info;
-
- switch (args->event) {
- case NB_EV_VALIDATE:
- if (static_path_list_tableid_modify(args, NULL, NULL) != NB_OK)
- return NB_ERR_VALIDATION;
- break;
- case NB_EV_PREPARE:
- case NB_EV_ABORT:
- break;
- case NB_EV_APPLY:
- src_dnode = yang_dnode_get_parent(args->dnode, "src-list");
- rn_dnode = yang_dnode_get_parent(src_dnode, "route-list");
- rn = nb_running_get_entry(rn_dnode, NULL, true);
- info = route_table_get_info(rn->table);
-
- if (static_path_list_tableid_modify(args, src_dnode, info)
- != NB_OK)
- return NB_ERR_VALIDATION;
-
- break;
- }
- return NB_OK;
-}
-
-/*
- * XPath:
* /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/route-list/src-list/path-list/frr-nexthops/nexthop
*/
int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_src_list_path_list_frr_nexthops_nexthop_create(
diff --git a/staticd/static_routes.c b/staticd/static_routes.c
index 05355c48fe..1c436a66b0 100644
--- a/staticd/static_routes.c
+++ b/staticd/static_routes.c
@@ -161,7 +161,8 @@ bool static_add_nexthop_validate(struct static_vrf *svrf, static_types type,
return true;
}
-struct static_path *static_add_path(struct route_node *rn, uint8_t distance)
+struct static_path *static_add_path(struct route_node *rn, uint32_t table_id,
+ uint8_t distance)
{
struct static_path *pn;
struct static_route_info *si;
@@ -172,6 +173,7 @@ struct static_path *static_add_path(struct route_node *rn, uint8_t distance)
pn = XCALLOC(MTYPE_STATIC_PATH, sizeof(struct static_path));
pn->distance = distance;
+ pn->table_id = table_id;
static_nexthop_list_init(&(pn->nexthop_list));
si = rn->info;
diff --git a/staticd/static_routes.h b/staticd/static_routes.h
index bd2cd78fd9..470afb605d 100644
--- a/staticd/static_routes.h
+++ b/staticd/static_routes.h
@@ -187,7 +187,7 @@ extern void static_del_route(struct route_node *rn, safi_t safi,
struct static_vrf *svrf);
extern struct static_path *static_add_path(struct route_node *rn,
- uint8_t distance);
+ uint32_t table_id, uint8_t distance);
extern void static_del_path(struct route_node *rn, struct static_path *pn,
safi_t safi, struct static_vrf *svrf);
diff --git a/staticd/static_vty.c b/staticd/static_vty.c
index c3c453f42d..1488cc1775 100644
--- a/staticd/static_vty.c
+++ b/staticd/static_vty.c
@@ -68,7 +68,6 @@ static int static_route_leak(struct vty *vty, const char *svrf,
char buf_src_prefix[PREFIX_STRLEN];
char buf_nh_type[PREFIX_STRLEN];
char buf_tag[PREFIX_STRLEN];
- char buf_tableid[PREFIX_STRLEN];
uint8_t label_stack_id = 0;
const char *buf_gate_str;
uint8_t distance = ZEBRA_STATIC_DISTANCE_DEFAULT;
@@ -162,14 +161,14 @@ static int static_route_leak(struct vty *vty, const char *svrf,
"frr-staticd:staticd", "staticd", svrf,
buf_prefix,
yang_afi_safi_value2identity(afi, safi),
- buf_src_prefix, distance);
+ buf_src_prefix, table_id, distance);
else
snprintf(xpath_prefix, sizeof(xpath_prefix),
FRR_STATIC_ROUTE_INFO_KEY_XPATH,
"frr-staticd:staticd", "staticd", svrf,
buf_prefix,
yang_afi_safi_value2identity(afi, safi),
- distance);
+ table_id, distance);
nb_cli_enqueue_change(vty, xpath_prefix, NB_OP_CREATE, NULL);
@@ -180,12 +179,6 @@ static int static_route_leak(struct vty *vty, const char *svrf,
sizeof(ab_xpath));
nb_cli_enqueue_change(vty, ab_xpath, NB_OP_MODIFY, buf_tag);
- /* Table-Id processing */
- snprintf(buf_tableid, sizeof(buf_tableid), "%u", table_id);
- strlcpy(ab_xpath, xpath_prefix, sizeof(ab_xpath));
- strlcat(ab_xpath, FRR_STATIC_ROUTE_PATH_TABLEID_XPATH,
- sizeof(ab_xpath));
- nb_cli_enqueue_change(vty, ab_xpath, NB_OP_MODIFY, buf_tableid);
/* nexthop processing */
snprintf(ab_xpath, sizeof(ab_xpath),
@@ -289,16 +282,16 @@ static int static_route_leak(struct vty *vty, const char *svrf,
"frr-staticd:staticd", "staticd", svrf,
buf_prefix,
yang_afi_safi_value2identity(afi, safi),
- buf_src_prefix, distance, buf_nh_type, nh_svrf,
- buf_gate_str, ifname);
+ buf_src_prefix, table_id, distance,
+ buf_nh_type, nh_svrf, buf_gate_str, ifname);
else
snprintf(ab_xpath, sizeof(ab_xpath),
FRR_DEL_S_ROUTE_NH_KEY_XPATH,
"frr-staticd:staticd", "staticd", svrf,
buf_prefix,
yang_afi_safi_value2identity(afi, safi),
- distance, buf_nh_type, nh_svrf, buf_gate_str,
- ifname);
+ table_id, distance, buf_nh_type, nh_svrf,
+ buf_gate_str, ifname);
dnode = yang_dnode_get(vty->candidate_config->dnode, ab_xpath);
if (!dnode)
diff --git a/tests/topotests/all-protocol-startup/test_all_protocol_startup.py b/tests/topotests/all-protocol-startup/test_all_protocol_startup.py
index ab9358408e..24bef07ec2 100644
--- a/tests/topotests/all-protocol-startup/test_all_protocol_startup.py
+++ b/tests/topotests/all-protocol-startup/test_all_protocol_startup.py
@@ -82,7 +82,9 @@ class NetworkTopo(Topo):
##
#####################################################
-
+@pytest.mark.isis
+@pytest.mark.ospf
+@pytest.mark.rip
def setup_module(module):
global topo, net
global fatal_error
diff --git a/tests/topotests/bfd-bgp-cbit-topo3/test_bfd_bgp_cbit_topo3.py b/tests/topotests/bfd-bgp-cbit-topo3/test_bfd_bgp_cbit_topo3.py
index 98a5033f53..cc1c1e3a0c 100644
--- a/tests/topotests/bfd-bgp-cbit-topo3/test_bfd_bgp_cbit_topo3.py
+++ b/tests/topotests/bfd-bgp-cbit-topo3/test_bfd_bgp_cbit_topo3.py
@@ -64,7 +64,7 @@ class BFDTopo(Topo):
switch.add_link(tgen.gears["r2"])
switch.add_link(tgen.gears["r3"])
-
+@pytest.mark.bfd
def setup_module(mod):
"Sets up the pytest environment"
tgen = Topogen(BFDTopo, mod.__name__)
diff --git a/tests/topotests/bfd-isis-topo1/test_bfd_isis_topo1.py b/tests/topotests/bfd-isis-topo1/test_bfd_isis_topo1.py
index 1adfec76d8..23da7ed850 100644
--- a/tests/topotests/bfd-isis-topo1/test_bfd_isis_topo1.py
+++ b/tests/topotests/bfd-isis-topo1/test_bfd_isis_topo1.py
@@ -127,7 +127,8 @@ class TemplateTopo(Topo):
switch.add_link(tgen.gears["rt4"], nodeif="eth-rt5")
switch.add_link(tgen.gears["rt5"], nodeif="eth-rt4")
-
+@pytest.mark.bfd
+@pytest.mark.isis
def setup_module(mod):
"Sets up the pytest environment"
tgen = Topogen(TemplateTopo, mod.__name__)
diff --git a/tests/topotests/bfd-ospf-topo1/__init__.py b/tests/topotests/bfd-ospf-topo1/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/topotests/bfd-ospf-topo1/__init__.py
diff --git a/tests/topotests/bfd-ospf-topo1/rt1/bfdd.conf b/tests/topotests/bfd-ospf-topo1/rt1/bfdd.conf
new file mode 100644
index 0000000000..610a20f88a
--- /dev/null
+++ b/tests/topotests/bfd-ospf-topo1/rt1/bfdd.conf
@@ -0,0 +1,9 @@
+log file bfdd.log
+log timestamp precision 3
+!
+debug bfd network
+debug bfd peer
+debug bfd zebra
+!
+bfd
+!
diff --git a/tests/topotests/bfd-ospf-topo1/rt1/ospf6d.conf b/tests/topotests/bfd-ospf-topo1/rt1/ospf6d.conf
new file mode 100644
index 0000000000..18def599b4
--- /dev/null
+++ b/tests/topotests/bfd-ospf-topo1/rt1/ospf6d.conf
@@ -0,0 +1,21 @@
+log file ospf6d.log
+log timestamp precision 3
+!
+hostname rt1
+!
+password 1
+!
+interface eth-rt2
+ ipv6 ospf6 network broadcast
+ ipv6 ospf6 bfd
+!
+interface eth-rt3
+ ipv6 ospf6 network broadcast
+ ipv6 ospf6 bfd
+!
+router ospf6
+ ospf6 router-id 1.1.1.1
+ interface eth-rt2 area 0.0.0.0
+ interface eth-rt3 area 0.0.0.0
+ redistribute connected
+!
diff --git a/tests/topotests/bfd-ospf-topo1/rt1/ospfd.conf b/tests/topotests/bfd-ospf-topo1/rt1/ospfd.conf
new file mode 100644
index 0000000000..07b42f9885
--- /dev/null
+++ b/tests/topotests/bfd-ospf-topo1/rt1/ospfd.conf
@@ -0,0 +1,26 @@
+log file ospfd.log
+log timestamp precision 3
+!
+hostname rt1
+!
+password 1
+!
+debug ospf event
+debug ospf zebra
+!
+interface lo
+ ip ospf area 0.0.0.0
+!
+interface eth-rt2
+ ip ospf area 0.0.0.0
+ ip ospf bfd
+!
+interface eth-rt3
+ ip ospf area 0.0.0.0
+ ip ospf bfd
+!
+router ospf
+ ospf router-id 1.1.1.1
+ passive interface lo
+ router-info area 0.0.0.0
+!
diff --git a/tests/topotests/bfd-ospf-topo1/rt1/step1/show_ip_route.ref b/tests/topotests/bfd-ospf-topo1/rt1/step1/show_ip_route.ref
new file mode 100644
index 0000000000..f354eff697
--- /dev/null
+++ b/tests/topotests/bfd-ospf-topo1/rt1/step1/show_ip_route.ref
@@ -0,0 +1,74 @@
+{
+ "2.2.2.2\/32":[
+ {
+ "prefix":"2.2.2.2\/32",
+ "protocol":"ospf",
+ "selected":true,
+ "destSelected":true,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "3.3.3.3\/32":[
+ {
+ "prefix":"3.3.3.3\/32",
+ "protocol":"ospf",
+ "selected":true,
+ "destSelected":true,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.2.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "4.4.4.4\/32":[
+ {
+ "prefix":"4.4.4.4\/32",
+ "protocol":"ospf",
+ "selected":true,
+ "destSelected":true,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.2.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "5.5.5.5\/32":[
+ {
+ "prefix":"5.5.5.5\/32",
+ "protocol":"ospf",
+ "selected":true,
+ "destSelected":true,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2",
+ "active":true
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/bfd-ospf-topo1/rt1/step1/show_ipv6_route.ref b/tests/topotests/bfd-ospf-topo1/rt1/step1/show_ipv6_route.ref
new file mode 100644
index 0000000000..6465efb8b5
--- /dev/null
+++ b/tests/topotests/bfd-ospf-topo1/rt1/step1/show_ipv6_route.ref
@@ -0,0 +1,70 @@
+{
+ "::ffff:202:202\/128":[
+ {
+ "prefix":"::ffff:202:202\/128",
+ "protocol":"ospf6",
+ "selected":true,
+ "destSelected":true,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt2",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "::ffff:303:303\/128":[
+ {
+ "prefix":"::ffff:303:303\/128",
+ "protocol":"ospf6",
+ "selected":true,
+ "destSelected":true,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt3",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "::ffff:404:404\/128":[
+ {
+ "prefix":"::ffff:404:404\/128",
+ "protocol":"ospf6",
+ "selected":true,
+ "destSelected":true,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt3",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "::ffff:505:505\/128":[
+ {
+ "prefix":"::ffff:505:505\/128",
+ "protocol":"ospf6",
+ "selected":true,
+ "destSelected":true,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt2",
+ "active":true
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/bfd-ospf-topo1/rt1/step2/show_bfd_peers.ref b/tests/topotests/bfd-ospf-topo1/rt1/step2/show_bfd_peers.ref
new file mode 100644
index 0000000000..63f0d50784
--- /dev/null
+++ b/tests/topotests/bfd-ospf-topo1/rt1/step2/show_bfd_peers.ref
@@ -0,0 +1,26 @@
+[
+ {
+ "interface": "eth-rt3",
+ "status": "up",
+ "diagnostic": "ok",
+ "remote-diagnostic": "ok"
+ },
+ {
+ "interface": "eth-rt2",
+ "status": "up",
+ "diagnostic": "ok",
+ "remote-diagnostic": "ok"
+ },
+ {
+ "interface": "eth-rt3",
+ "status": "up",
+ "diagnostic": "ok",
+ "remote-diagnostic": "ok"
+ },
+ {
+ "interface": "eth-rt2",
+ "status": "up",
+ "diagnostic": "ok",
+ "remote-diagnostic": "ok"
+ }
+]
diff --git a/tests/topotests/bfd-ospf-topo1/rt1/step3/show_bfd_peers_healthy.ref b/tests/topotests/bfd-ospf-topo1/rt1/step3/show_bfd_peers_healthy.ref
new file mode 100644
index 0000000000..42051f9582
--- /dev/null
+++ b/tests/topotests/bfd-ospf-topo1/rt1/step3/show_bfd_peers_healthy.ref
@@ -0,0 +1,28 @@
+[
+ {
+ "peer": "10.0.2.2",
+ "interface": "eth-rt3",
+ "status": "up",
+ "diagnostic": "ok",
+ "remote-diagnostic": "ok"
+ },
+ {
+ "peer": "10.0.1.2",
+ "interface": "eth-rt2",
+ "status": "up",
+ "diagnostic": "ok",
+ "remote-diagnostic": "ok"
+ },
+ {
+ "interface": "eth-rt3",
+ "status": "up",
+ "diagnostic": "ok",
+ "remote-diagnostic": "ok"
+ },
+ {
+ "interface": "eth-rt2",
+ "status": "up",
+ "diagnostic": "ok",
+ "remote-diagnostic": "ok"
+ }
+]
diff --git a/tests/topotests/bfd-ospf-topo1/rt1/step3/show_bfd_peers_rt2_down.ref b/tests/topotests/bfd-ospf-topo1/rt1/step3/show_bfd_peers_rt2_down.ref
new file mode 100644
index 0000000000..d844ee6813
--- /dev/null
+++ b/tests/topotests/bfd-ospf-topo1/rt1/step3/show_bfd_peers_rt2_down.ref
@@ -0,0 +1,15 @@
+[
+ {
+ "peer": "10.0.2.2",
+ "interface": "eth-rt3",
+ "status": "up",
+ "diagnostic": "ok",
+ "remote-diagnostic": "ok"
+ },
+ {
+ "interface": "eth-rt3",
+ "status": "up",
+ "diagnostic": "ok",
+ "remote-diagnostic": "ok"
+ }
+]
diff --git a/tests/topotests/bfd-ospf-topo1/rt1/step3/show_bfd_peers_rt3_down.ref b/tests/topotests/bfd-ospf-topo1/rt1/step3/show_bfd_peers_rt3_down.ref
new file mode 100644
index 0000000000..32799084fb
--- /dev/null
+++ b/tests/topotests/bfd-ospf-topo1/rt1/step3/show_bfd_peers_rt3_down.ref
@@ -0,0 +1,15 @@
+[
+ {
+ "peer": "10.0.1.2",
+ "interface": "eth-rt2",
+ "status": "up",
+ "diagnostic": "ok",
+ "remote-diagnostic": "ok"
+ },
+ {
+ "interface": "eth-rt2",
+ "status": "up",
+ "diagnostic": "ok",
+ "remote-diagnostic": "ok"
+ }
+]
diff --git a/tests/topotests/bfd-ospf-topo1/rt1/step3/show_ip_route_healthy.ref b/tests/topotests/bfd-ospf-topo1/rt1/step3/show_ip_route_healthy.ref
new file mode 100644
index 0000000000..f354eff697
--- /dev/null
+++ b/tests/topotests/bfd-ospf-topo1/rt1/step3/show_ip_route_healthy.ref
@@ -0,0 +1,74 @@
+{
+ "2.2.2.2\/32":[
+ {
+ "prefix":"2.2.2.2\/32",
+ "protocol":"ospf",
+ "selected":true,
+ "destSelected":true,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "3.3.3.3\/32":[
+ {
+ "prefix":"3.3.3.3\/32",
+ "protocol":"ospf",
+ "selected":true,
+ "destSelected":true,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.2.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "4.4.4.4\/32":[
+ {
+ "prefix":"4.4.4.4\/32",
+ "protocol":"ospf",
+ "selected":true,
+ "destSelected":true,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.2.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "5.5.5.5\/32":[
+ {
+ "prefix":"5.5.5.5\/32",
+ "protocol":"ospf",
+ "selected":true,
+ "destSelected":true,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2",
+ "active":true
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/bfd-ospf-topo1/rt1/step3/show_ip_route_rt2_down.ref b/tests/topotests/bfd-ospf-topo1/rt1/step3/show_ip_route_rt2_down.ref
new file mode 100644
index 0000000000..43eecd0b7a
--- /dev/null
+++ b/tests/topotests/bfd-ospf-topo1/rt1/step3/show_ip_route_rt2_down.ref
@@ -0,0 +1,74 @@
+{
+ "2.2.2.2\/32":[
+ {
+ "prefix":"2.2.2.2\/32",
+ "protocol":"ospf",
+ "selected":true,
+ "destSelected":true,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.2.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "3.3.3.3\/32":[
+ {
+ "prefix":"3.3.3.3\/32",
+ "protocol":"ospf",
+ "selected":true,
+ "destSelected":true,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.2.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "4.4.4.4\/32":[
+ {
+ "prefix":"4.4.4.4\/32",
+ "protocol":"ospf",
+ "selected":true,
+ "destSelected":true,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.2.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "5.5.5.5\/32":[
+ {
+ "prefix":"5.5.5.5\/32",
+ "protocol":"ospf",
+ "selected":true,
+ "destSelected":true,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.2.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3",
+ "active":true
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/bfd-ospf-topo1/rt1/step3/show_ip_route_rt3_down.ref b/tests/topotests/bfd-ospf-topo1/rt1/step3/show_ip_route_rt3_down.ref
new file mode 100644
index 0000000000..409af6308b
--- /dev/null
+++ b/tests/topotests/bfd-ospf-topo1/rt1/step3/show_ip_route_rt3_down.ref
@@ -0,0 +1,74 @@
+{
+ "2.2.2.2\/32":[
+ {
+ "prefix":"2.2.2.2\/32",
+ "protocol":"ospf",
+ "selected":true,
+ "destSelected":true,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "3.3.3.3\/32":[
+ {
+ "prefix":"3.3.3.3\/32",
+ "protocol":"ospf",
+ "selected":true,
+ "destSelected":true,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "4.4.4.4\/32":[
+ {
+ "prefix":"4.4.4.4\/32",
+ "protocol":"ospf",
+ "selected":true,
+ "destSelected":true,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "5.5.5.5\/32":[
+ {
+ "prefix":"5.5.5.5\/32",
+ "protocol":"ospf",
+ "selected":true,
+ "destSelected":true,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2",
+ "active":true
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/bfd-ospf-topo1/rt1/step3/show_ipv6_route_healthy.ref b/tests/topotests/bfd-ospf-topo1/rt1/step3/show_ipv6_route_healthy.ref
new file mode 100644
index 0000000000..6465efb8b5
--- /dev/null
+++ b/tests/topotests/bfd-ospf-topo1/rt1/step3/show_ipv6_route_healthy.ref
@@ -0,0 +1,70 @@
+{
+ "::ffff:202:202\/128":[
+ {
+ "prefix":"::ffff:202:202\/128",
+ "protocol":"ospf6",
+ "selected":true,
+ "destSelected":true,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt2",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "::ffff:303:303\/128":[
+ {
+ "prefix":"::ffff:303:303\/128",
+ "protocol":"ospf6",
+ "selected":true,
+ "destSelected":true,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt3",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "::ffff:404:404\/128":[
+ {
+ "prefix":"::ffff:404:404\/128",
+ "protocol":"ospf6",
+ "selected":true,
+ "destSelected":true,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt3",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "::ffff:505:505\/128":[
+ {
+ "prefix":"::ffff:505:505\/128",
+ "protocol":"ospf6",
+ "selected":true,
+ "destSelected":true,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt2",
+ "active":true
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/bfd-ospf-topo1/rt1/step3/show_ipv6_route_rt2_down.ref b/tests/topotests/bfd-ospf-topo1/rt1/step3/show_ipv6_route_rt2_down.ref
new file mode 100644
index 0000000000..cfb1ef1bb6
--- /dev/null
+++ b/tests/topotests/bfd-ospf-topo1/rt1/step3/show_ipv6_route_rt2_down.ref
@@ -0,0 +1,70 @@
+{
+ "::ffff:202:202\/128":[
+ {
+ "prefix":"::ffff:202:202\/128",
+ "protocol":"ospf6",
+ "selected":true,
+ "destSelected":true,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt3",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "::ffff:303:303\/128":[
+ {
+ "prefix":"::ffff:303:303\/128",
+ "protocol":"ospf6",
+ "selected":true,
+ "destSelected":true,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt3",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "::ffff:404:404\/128":[
+ {
+ "prefix":"::ffff:404:404\/128",
+ "protocol":"ospf6",
+ "selected":true,
+ "destSelected":true,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt3",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "::ffff:505:505\/128":[
+ {
+ "prefix":"::ffff:505:505\/128",
+ "protocol":"ospf6",
+ "selected":true,
+ "destSelected":true,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt3",
+ "active":true
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/bfd-ospf-topo1/rt1/step3/show_ipv6_route_rt3_down.ref b/tests/topotests/bfd-ospf-topo1/rt1/step3/show_ipv6_route_rt3_down.ref
new file mode 100644
index 0000000000..58b44da5c2
--- /dev/null
+++ b/tests/topotests/bfd-ospf-topo1/rt1/step3/show_ipv6_route_rt3_down.ref
@@ -0,0 +1,70 @@
+{
+ "::ffff:202:202\/128":[
+ {
+ "prefix":"::ffff:202:202\/128",
+ "protocol":"ospf6",
+ "selected":true,
+ "destSelected":true,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt2",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "::ffff:303:303\/128":[
+ {
+ "prefix":"::ffff:303:303\/128",
+ "protocol":"ospf6",
+ "selected":true,
+ "destSelected":true,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt2",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "::ffff:404:404\/128":[
+ {
+ "prefix":"::ffff:404:404\/128",
+ "protocol":"ospf6",
+ "selected":true,
+ "destSelected":true,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt2",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "::ffff:505:505\/128":[
+ {
+ "prefix":"::ffff:505:505\/128",
+ "protocol":"ospf6",
+ "selected":true,
+ "destSelected":true,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt2",
+ "active":true
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/bfd-ospf-topo1/rt1/zebra.conf b/tests/topotests/bfd-ospf-topo1/rt1/zebra.conf
new file mode 100644
index 0000000000..6003125b6b
--- /dev/null
+++ b/tests/topotests/bfd-ospf-topo1/rt1/zebra.conf
@@ -0,0 +1,25 @@
+log file zebra.log
+log timestamp precision 3
+!
+hostname rt1
+!
+debug zebra kernel
+debug zebra packet
+debug zebra events
+debug zebra rib
+!
+interface lo
+ ip address 1.1.1.1/32
+ ipv6 address ::ffff:0101:0101/128
+!
+interface eth-rt2
+ ip address 10.0.1.1/24
+!
+interface eth-rt3
+ ip address 10.0.2.1/24
+!
+ip forwarding
+ipv6 forwarding
+!
+line vty
+!
diff --git a/tests/topotests/bfd-ospf-topo1/rt2/bfdd.conf b/tests/topotests/bfd-ospf-topo1/rt2/bfdd.conf
new file mode 100644
index 0000000000..437f063d8f
--- /dev/null
+++ b/tests/topotests/bfd-ospf-topo1/rt2/bfdd.conf
@@ -0,0 +1,7 @@
+!
+debug bfd network
+debug bfd peer
+debug bfd zebra
+!
+bfd
+!
diff --git a/tests/topotests/bfd-ospf-topo1/rt2/ospf6d.conf b/tests/topotests/bfd-ospf-topo1/rt2/ospf6d.conf
new file mode 100644
index 0000000000..2f35099564
--- /dev/null
+++ b/tests/topotests/bfd-ospf-topo1/rt2/ospf6d.conf
@@ -0,0 +1,19 @@
+log file ospf6d.log
+!
+hostname rt2
+!
+password 1
+!
+interface eth-rt1
+ ipv6 ospf6 network broadcast
+ ipv6 ospf6 bfd
+!
+interface eth-rt5
+ ipv6 ospf6 network broadcast
+!
+router ospf6
+ ospf6 router-id 2.2.2.2
+ interface eth-rt1 area 0.0.0.0
+ interface eth-rt5 area 0.0.0.0
+ redistribute connected
+!
diff --git a/tests/topotests/bfd-ospf-topo1/rt2/ospfd.conf b/tests/topotests/bfd-ospf-topo1/rt2/ospfd.conf
new file mode 100644
index 0000000000..a05d8b58c8
--- /dev/null
+++ b/tests/topotests/bfd-ospf-topo1/rt2/ospfd.conf
@@ -0,0 +1,24 @@
+log file ospfd.log
+!
+hostname rt2
+!
+password 1
+!
+debug ospf event
+debug ospf zebra
+!
+interface lo
+ ip ospf area 0.0.0.0
+!
+interface eth-rt1
+ ip ospf area 0.0.0.0
+ ip ospf bfd
+!
+interface eth-rt5
+ ip ospf area 0.0.0.0
+!
+router ospf
+ ospf router-id 2.2.2.2
+ passive interface lo
+ router-info area 0.0.0.0
+!
diff --git a/tests/topotests/bfd-ospf-topo1/rt2/step2/show_bfd_peers.ref b/tests/topotests/bfd-ospf-topo1/rt2/step2/show_bfd_peers.ref
new file mode 100644
index 0000000000..d6df1ebfb2
--- /dev/null
+++ b/tests/topotests/bfd-ospf-topo1/rt2/step2/show_bfd_peers.ref
@@ -0,0 +1,14 @@
+[
+ {
+ "interface": "eth-rt1",
+ "status": "up",
+ "diagnostic": "ok",
+ "remote-diagnostic": "ok"
+ },
+ {
+ "interface": "eth-rt1",
+ "status": "up",
+ "diagnostic": "ok",
+ "remote-diagnostic": "ok"
+ }
+]
diff --git a/tests/topotests/bfd-ospf-topo1/rt2/zebra.conf b/tests/topotests/bfd-ospf-topo1/rt2/zebra.conf
new file mode 100644
index 0000000000..5fc7fc5b28
--- /dev/null
+++ b/tests/topotests/bfd-ospf-topo1/rt2/zebra.conf
@@ -0,0 +1,22 @@
+log file zebra.log
+!
+hostname rt2
+!
+debug zebra kernel
+debug zebra packet
+!
+interface lo
+ ip address 2.2.2.2/32
+ ipv6 address ::ffff:0202:0202/128
+!
+interface eth-rt1
+ ip address 10.0.1.2/24
+!
+interface eth-rt5
+ ip address 10.0.3.1/24
+!
+ip forwarding
+ipv6 forwarding
+!
+line vty
+!
diff --git a/tests/topotests/bfd-ospf-topo1/rt3/bfdd.conf b/tests/topotests/bfd-ospf-topo1/rt3/bfdd.conf
new file mode 100644
index 0000000000..437f063d8f
--- /dev/null
+++ b/tests/topotests/bfd-ospf-topo1/rt3/bfdd.conf
@@ -0,0 +1,7 @@
+!
+debug bfd network
+debug bfd peer
+debug bfd zebra
+!
+bfd
+!
diff --git a/tests/topotests/bfd-ospf-topo1/rt3/ospf6d.conf b/tests/topotests/bfd-ospf-topo1/rt3/ospf6d.conf
new file mode 100644
index 0000000000..3e8777019e
--- /dev/null
+++ b/tests/topotests/bfd-ospf-topo1/rt3/ospf6d.conf
@@ -0,0 +1,19 @@
+log file ospf6d.log
+!
+hostname rt3
+!
+password 1
+!
+interface eth-rt1
+ ipv6 ospf6 network broadcast
+ ipv6 ospf6 bfd
+!
+interface eth-rt4
+ ipv6 ospf6 network broadcast
+!
+router ospf6
+ ospf6 router-id 3.3.3.3
+ interface eth-rt1 area 0.0.0.0
+ interface eth-rt4 area 0.0.0.0
+ redistribute connected
+!
diff --git a/tests/topotests/bfd-ospf-topo1/rt3/ospfd.conf b/tests/topotests/bfd-ospf-topo1/rt3/ospfd.conf
new file mode 100644
index 0000000000..1196e6d189
--- /dev/null
+++ b/tests/topotests/bfd-ospf-topo1/rt3/ospfd.conf
@@ -0,0 +1,24 @@
+log file ospfd.log
+!
+hostname rt3
+!
+password 1
+!
+debug ospf event
+debug ospf zebra
+!
+interface lo
+ ip ospf area 0.0.0.0
+!
+interface eth-rt1
+ ip ospf area 0.0.0.0
+ ip ospf bfd
+!
+interface eth-rt4
+ ip ospf area 0.0.0.0
+!
+router ospf
+ ospf router-id 3.3.3.3
+ passive interface lo
+ router-info area 0.0.0.0
+!
diff --git a/tests/topotests/bfd-ospf-topo1/rt3/step2/show_bfd_peers.ref b/tests/topotests/bfd-ospf-topo1/rt3/step2/show_bfd_peers.ref
new file mode 100644
index 0000000000..d6df1ebfb2
--- /dev/null
+++ b/tests/topotests/bfd-ospf-topo1/rt3/step2/show_bfd_peers.ref
@@ -0,0 +1,14 @@
+[
+ {
+ "interface": "eth-rt1",
+ "status": "up",
+ "diagnostic": "ok",
+ "remote-diagnostic": "ok"
+ },
+ {
+ "interface": "eth-rt1",
+ "status": "up",
+ "diagnostic": "ok",
+ "remote-diagnostic": "ok"
+ }
+]
diff --git a/tests/topotests/bfd-ospf-topo1/rt3/zebra.conf b/tests/topotests/bfd-ospf-topo1/rt3/zebra.conf
new file mode 100644
index 0000000000..d368de9bbe
--- /dev/null
+++ b/tests/topotests/bfd-ospf-topo1/rt3/zebra.conf
@@ -0,0 +1,22 @@
+log file zebra.log
+!
+hostname rt3
+!
+debug zebra kernel
+debug zebra packet
+!
+interface lo
+ ip address 3.3.3.3/32
+ ipv6 address ::ffff:0303:0303/128
+!
+interface eth-rt1
+ ip address 10.0.2.2/24
+!
+interface eth-rt4
+ ip address 10.0.4.1/24
+!
+ip forwarding
+ipv6 forwarding
+!
+line vty
+!
diff --git a/tests/topotests/bfd-ospf-topo1/rt4/bfdd.conf b/tests/topotests/bfd-ospf-topo1/rt4/bfdd.conf
new file mode 100644
index 0000000000..f35e772790
--- /dev/null
+++ b/tests/topotests/bfd-ospf-topo1/rt4/bfdd.conf
@@ -0,0 +1,5 @@
+!
+debug bfd network
+debug bfd peer
+debug bfd zebra
+!
diff --git a/tests/topotests/bfd-ospf-topo1/rt4/ospf6d.conf b/tests/topotests/bfd-ospf-topo1/rt4/ospf6d.conf
new file mode 100644
index 0000000000..bccd1e75bd
--- /dev/null
+++ b/tests/topotests/bfd-ospf-topo1/rt4/ospf6d.conf
@@ -0,0 +1,18 @@
+log file ospf6d.log
+!
+hostname rt4
+!
+password 1
+!
+interface eth-rt3
+ ipv6 ospf6 network broadcast
+!
+interface eth-rt5
+ ipv6 ospf6 network broadcast
+!
+router ospf6
+ ospf6 router-id 4.4.4.4
+ interface eth-rt3 area 0.0.0.0
+ interface eth-rt5 area 0.0.0.0
+ redistribute connected
+!
diff --git a/tests/topotests/bfd-ospf-topo1/rt4/ospfd.conf b/tests/topotests/bfd-ospf-topo1/rt4/ospfd.conf
new file mode 100644
index 0000000000..3a2568b4ab
--- /dev/null
+++ b/tests/topotests/bfd-ospf-topo1/rt4/ospfd.conf
@@ -0,0 +1,23 @@
+log file ospfd.log
+!
+hostname rt4
+!
+password 1
+!
+debug ospf event
+debug ospf zebra
+!
+interface lo
+ ip ospf area 0.0.0.0
+!
+interface eth-rt3
+ ip ospf area 0.0.0.0
+!
+interface eth-rt5
+ ip ospf area 0.0.0.0
+!
+router ospf
+ ospf router-id 4.4.4.4
+ passive interface lo
+ router-info area 0.0.0.0
+!
diff --git a/tests/topotests/bfd-ospf-topo1/rt4/zebra.conf b/tests/topotests/bfd-ospf-topo1/rt4/zebra.conf
new file mode 100644
index 0000000000..7b053bac35
--- /dev/null
+++ b/tests/topotests/bfd-ospf-topo1/rt4/zebra.conf
@@ -0,0 +1,22 @@
+log file zebra.log
+!
+hostname rt4
+!
+debug zebra kernel
+debug zebra packet
+!
+interface lo
+ ip address 4.4.4.4/32
+ ipv6 address ::ffff:0404:0404/128
+!
+interface eth-rt3
+ ip address 10.0.4.2/24
+!
+interface eth-rt5
+ ip address 10.0.5.1/24
+!
+ip forwarding
+ipv6 forwarding
+!
+line vty
+!
diff --git a/tests/topotests/bfd-ospf-topo1/rt5/bfdd.conf b/tests/topotests/bfd-ospf-topo1/rt5/bfdd.conf
new file mode 100644
index 0000000000..f35e772790
--- /dev/null
+++ b/tests/topotests/bfd-ospf-topo1/rt5/bfdd.conf
@@ -0,0 +1,5 @@
+!
+debug bfd network
+debug bfd peer
+debug bfd zebra
+!
diff --git a/tests/topotests/bfd-ospf-topo1/rt5/ospf6d.conf b/tests/topotests/bfd-ospf-topo1/rt5/ospf6d.conf
new file mode 100644
index 0000000000..766862276c
--- /dev/null
+++ b/tests/topotests/bfd-ospf-topo1/rt5/ospf6d.conf
@@ -0,0 +1,18 @@
+log file ospf6d.log
+!
+hostname rt5
+!
+password 1
+!
+interface eth-rt2
+ ipv6 ospf6 network broadcast
+!
+interface eth-rt4
+ ipv6 ospf6 network broadcast
+!
+router ospf6
+ ospf6 router-id 5.5.5.5
+ interface eth-rt2 area 0.0.0.0
+ interface eth-rt4 area 0.0.0.0
+ redistribute connected
+!
diff --git a/tests/topotests/bfd-ospf-topo1/rt5/ospfd.conf b/tests/topotests/bfd-ospf-topo1/rt5/ospfd.conf
new file mode 100644
index 0000000000..a35de5f45f
--- /dev/null
+++ b/tests/topotests/bfd-ospf-topo1/rt5/ospfd.conf
@@ -0,0 +1,23 @@
+log file ospfd.log
+!
+hostname rt5
+!
+password 1
+!
+debug ospf event
+debug ospf zebra
+!
+interface lo
+ ip ospf area 0.0.0.0
+!
+interface eth-rt2
+ ip ospf area 0.0.0.0
+!
+interface eth-rt4
+ ip ospf area 0.0.0.0
+!
+router ospf
+ ospf router-id 5.5.5.5
+ passive interface lo
+ router-info area 0.0.0.0
+!
diff --git a/tests/topotests/bfd-ospf-topo1/rt5/zebra.conf b/tests/topotests/bfd-ospf-topo1/rt5/zebra.conf
new file mode 100644
index 0000000000..0b7c9e02f3
--- /dev/null
+++ b/tests/topotests/bfd-ospf-topo1/rt5/zebra.conf
@@ -0,0 +1,22 @@
+log file zebra.log
+!
+hostname rt5
+!
+debug zebra kernel
+debug zebra packet
+!
+interface lo
+ ip address 5.5.5.5/32
+ ipv6 address ::ffff:0505:0505/128
+!
+interface eth-rt2
+ ip address 10.0.3.2/24
+!
+interface eth-rt4
+ ip address 10.0.5.2/24
+!
+ip forwarding
+ipv6 forwarding
+!
+line vty
+!
diff --git a/tests/topotests/bfd-ospf-topo1/test_bfd_ospf_topo1.py b/tests/topotests/bfd-ospf-topo1/test_bfd_ospf_topo1.py
new file mode 100755
index 0000000000..1cec62789b
--- /dev/null
+++ b/tests/topotests/bfd-ospf-topo1/test_bfd_ospf_topo1.py
@@ -0,0 +1,307 @@
+#!/usr/bin/env python
+
+#
+# test_bfd_ospf_topo1.py
+# Part of NetDEF Topology Tests
+#
+# Copyright (c) 2020 by
+# Network Device Education Foundation, Inc. ("NetDEF")
+#
+# 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_bfd_ospf_topo1.py:
+
+ +---------+
+ | |
+ eth-rt2 (.1) | RT1 | eth-rt3 (.1)
+ +----------+ 1.1.1.1 +----------+
+ | | | |
+ | +---------+ |
+ | |
+ | 10.0.2.0/24 |
+ | |
+ | eth-rt1 | (.2)
+ | 10.0.1.0/24 +----+----+
+ | | |
+ | | RT3 |
+ | | 3.3.3.3 |
+ | | |
+ (.2) | eth-rt1 +----+----+
+ +----+----+ eth-rt4 | (.1)
+ | | |
+ | RT2 | |
+ | 2.2.2.2 | 10.0.4.0/24 |
+ | | |
+ +----+----+ |
+ (.1) | eth-rt5 eth-rt3 | (.2)
+ | +----+----+
+ | | |
+ | | RT4 |
+ | | 4.4.4.4 |
+ | | |
+ | +----+----+
+ | 10.0.3.0/24 eth-rt5 | (.1)
+ | |
+ | |
+ | 10.0.5.0/24 |
+ | |
+ | +---------+ |
+ | | | |
+ +----------+ RT5 +----------+
+ eth-rt2 (.2) | 5.5.5.5 | eth-rt4 (.2)
+ | |
+ +---------+
+
+"""
+
+import os
+import sys
+import pytest
+import json
+import re
+from time import sleep
+from time import time
+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
+
+
+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"]:
+ tgen.add_router(router)
+
+ #
+ # Define connections
+ #
+ switch = tgen.add_switch("s1")
+ switch.add_link(tgen.gears["rt1"], nodeif="eth-rt2")
+ switch.add_link(tgen.gears["rt2"], nodeif="eth-rt1")
+
+ switch = tgen.add_switch("s2")
+ switch.add_link(tgen.gears["rt1"], nodeif="eth-rt3")
+ switch.add_link(tgen.gears["rt3"], nodeif="eth-rt1")
+
+ switch = tgen.add_switch("s3")
+ switch.add_link(tgen.gears["rt2"], nodeif="eth-rt5")
+ switch.add_link(tgen.gears["rt5"], nodeif="eth-rt2")
+
+ switch = tgen.add_switch("s4")
+ switch.add_link(tgen.gears["rt3"], nodeif="eth-rt4")
+ switch.add_link(tgen.gears["rt4"], nodeif="eth-rt3")
+
+ switch = tgen.add_switch("s5")
+ switch.add_link(tgen.gears["rt4"], nodeif="eth-rt5")
+ switch.add_link(tgen.gears["rt5"], nodeif="eth-rt4")
+
+
+def setup_module(mod):
+ "Sets up the pytest environment"
+ tgen = Topogen(TemplateTopo, mod.__name__)
+ tgen.start_topology()
+
+ router_list = tgen.routers()
+
+ # For all registered routers, load the zebra configuration file
+ for rname, router in router_list.iteritems():
+ router.load_config(
+ TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname))
+ )
+ router.load_config(
+ TopoRouter.RD_BFD, os.path.join(CWD, "{}/bfdd.conf".format(rname))
+ )
+ router.load_config(
+ TopoRouter.RD_OSPF, os.path.join(CWD, "{}/ospfd.conf".format(rname))
+ )
+ router.load_config(
+ TopoRouter.RD_OSPF6, os.path.join(CWD, "{}/ospf6d.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 print_cmd_result(rname, command):
+ print(get_topogen().gears[rname].vtysh_cmd(command, isjson=False))
+
+
+def router_compare_json_output(rname, command, reference, count=120, wait=0.5):
+ "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(topotest.router_json_cmp, tgen.gears[rname], command, expected)
+ _, diff = topotest.run_and_expect(test_func, None, count=count, wait=wait)
+ assertmsg = '"{}" JSON output mismatches the expected result'.format(rname)
+ assert diff is None, assertmsg
+
+
+## TEST STEPS
+
+
+def test_rib_ospf_step1():
+ logger.info("Test (step 1): verify RIB for OSPF")
+ tgen = get_topogen()
+
+ # Skip if previous fatal error condition is raised
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ router_compare_json_output(
+ "rt1", "show ip route ospf json", "step1/show_ip_route.ref"
+ )
+ router_compare_json_output(
+ "rt1", "show ipv6 route ospf json", "step1/show_ipv6_route.ref"
+ )
+
+
+def test_bfd_ospf_sessions_step2():
+ logger.info("Test (step 2): verify BFD peers for OSPF")
+ tgen = get_topogen()
+
+ # Skip if previous fatal error condition is raised
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ # BFD is just used on three routers
+ for rt in ["rt1", "rt2", "rt3"]:
+ router_compare_json_output(
+ rt, "show bfd peers json", "step2/show_bfd_peers.ref"
+ )
+
+
+def test_bfd_ospf_interface_failure_rt2_step3():
+ logger.info("Test (step 3): Check failover handling with RT2 down")
+ tgen = get_topogen()
+
+ # Skip if previous fatal error condition is raised
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ # Let's kill the interface on rt2 and see what happens with the RIB and BFD on rt1
+ tgen.gears["rt2"].link_enable("eth-rt1", enabled=False)
+
+ # By default BFD provides a recovery time of 900ms plus jitter, so let's wait
+ # initial 2 seconds to let the CI not suffer.
+ # TODO: add check for array size
+ sleep(2)
+ router_compare_json_output(
+ "rt1", "show ip route ospf json", "step3/show_ip_route_rt2_down.ref", 1, 0
+ )
+ router_compare_json_output(
+ "rt1", "show ipv6 route ospf json", "step3/show_ipv6_route_rt2_down.ref", 1, 0
+ )
+ router_compare_json_output(
+ "rt1", "show bfd peers json", "step3/show_bfd_peers_rt2_down.ref", 1, 0
+ )
+
+ # Check recovery, this can take some time
+ tgen.gears["rt2"].link_enable("eth-rt1", enabled=True)
+
+ router_compare_json_output(
+ "rt1", "show ip route ospf json", "step3/show_ip_route_healthy.ref"
+ )
+ router_compare_json_output(
+ "rt1", "show ipv6 route ospf json", "step3/show_ipv6_route_healthy.ref"
+ )
+ router_compare_json_output(
+ "rt1", "show bfd peers json", "step3/show_bfd_peers_healthy.ref"
+ )
+
+
+def test_bfd_ospf_interface_failure_rt3_step3():
+ logger.info("Test (step 3): Check failover handling with RT3 down")
+ tgen = get_topogen()
+
+ # Skip if previous fatal error condition is raised
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ # Let's kill the interface on rt3 and see what happens with the RIB and BFD on rt1
+ tgen.gears["rt3"].link_enable("eth-rt1", enabled=False)
+
+ # By default BFD provides a recovery time of 900ms plus jitter, so let's wait
+ # initial 2 seconds to let the CI not suffer.
+ # TODO: add check for array size
+ sleep(2)
+ router_compare_json_output(
+ "rt1", "show ip route ospf json", "step3/show_ip_route_rt3_down.ref", 1, 0
+ )
+ router_compare_json_output(
+ "rt1", "show ipv6 route ospf json", "step3/show_ipv6_route_rt3_down.ref", 1, 0
+ )
+ router_compare_json_output(
+ "rt1", "show bfd peers json", "step3/show_bfd_peers_rt3_down.ref", 1, 0
+ )
+
+ # Check recovery, this can take some time
+ tgen.gears["rt3"].link_enable("eth-rt1", enabled=True)
+
+ router_compare_json_output(
+ "rt1", "show ip route ospf json", "step3/show_ip_route_healthy.ref"
+ )
+ router_compare_json_output(
+ "rt1", "show ipv6 route ospf json", "step3/show_ipv6_route_healthy.ref"
+ )
+ router_compare_json_output(
+ "rt1", "show bfd peers json", "step3/show_bfd_peers_healthy.ref"
+ )
+
+
+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))
diff --git a/tests/topotests/bfd-profiles-topo1/test_bfd_profiles_topo1.py b/tests/topotests/bfd-profiles-topo1/test_bfd_profiles_topo1.py
index bd3b876eeb..6283f03ddf 100644
--- a/tests/topotests/bfd-profiles-topo1/test_bfd_profiles_topo1.py
+++ b/tests/topotests/bfd-profiles-topo1/test_bfd_profiles_topo1.py
@@ -77,7 +77,8 @@ class BFDProfTopo(Topo):
switch.add_link(tgen.gears["r1"])
switch.add_link(tgen.gears["r6"])
-
+@pytest.mark.bfd
+@pytest.mark.isis
def setup_module(mod):
"Sets up the pytest environment"
tgen = Topogen(BFDProfTopo, mod.__name__)
diff --git a/tests/topotests/bfd-topo1/test_bfd_topo1.py b/tests/topotests/bfd-topo1/test_bfd_topo1.py
index 6e589d55eb..4c13fdcfc5 100644
--- a/tests/topotests/bfd-topo1/test_bfd_topo1.py
+++ b/tests/topotests/bfd-topo1/test_bfd_topo1.py
@@ -69,7 +69,7 @@ class BFDTopo(Topo):
switch.add_link(tgen.gears["r2"])
switch.add_link(tgen.gears["r4"])
-
+@pytest.mark.bfd
def setup_module(mod):
"Sets up the pytest environment"
tgen = Topogen(BFDTopo, mod.__name__)
diff --git a/tests/topotests/bfd-topo2/test_bfd_topo2.py b/tests/topotests/bfd-topo2/test_bfd_topo2.py
index feb4576bd3..5181a40f47 100644
--- a/tests/topotests/bfd-topo2/test_bfd_topo2.py
+++ b/tests/topotests/bfd-topo2/test_bfd_topo2.py
@@ -70,7 +70,7 @@ class BFDTopo(Topo):
switch.add_link(tgen.gears["r2"])
switch.add_link(tgen.gears["r4"])
-
+@pytest.mark.bfd
def setup_module(mod):
"Sets up the pytest environment"
tgen = Topogen(BFDTopo, mod.__name__)
diff --git a/tests/topotests/bfd-vrf-topo1/test_bfd_vrf_topo1.py b/tests/topotests/bfd-vrf-topo1/test_bfd_vrf_topo1.py
index 5fed135f8d..956b526583 100644
--- a/tests/topotests/bfd-vrf-topo1/test_bfd_vrf_topo1.py
+++ b/tests/topotests/bfd-vrf-topo1/test_bfd_vrf_topo1.py
@@ -70,7 +70,7 @@ class BFDTopo(Topo):
switch.add_link(tgen.gears["r2"])
switch.add_link(tgen.gears["r4"])
-
+@pytest.mark.bfd
def setup_module(mod):
"Sets up the pytest environment"
tgen = Topogen(BFDTopo, mod.__name__)
diff --git a/tests/topotests/bgp-evpn-mh/test_evpn_mh.py b/tests/topotests/bgp-evpn-mh/test_evpn_mh.py
index 6a24684649..4e37ab00a3 100644
--- a/tests/topotests/bgp-evpn-mh/test_evpn_mh.py
+++ b/tests/topotests/bgp-evpn-mh/test_evpn_mh.py
@@ -362,7 +362,7 @@ def config_hosts(tgen, hosts):
host = tgen.gears[host_name]
config_host(host_name, host)
-
+@pytest.mark.pim
def setup_module(module):
"Setup topology"
tgen = Topogen(NetworkTopo, module.__name__)
diff --git a/tests/topotests/bgp_peer-group/__init__.py b/tests/topotests/bgp_peer-group/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/topotests/bgp_peer-group/__init__.py
diff --git a/tests/topotests/bgp_peer-group/r1/bgpd.conf b/tests/topotests/bgp_peer-group/r1/bgpd.conf
new file mode 100644
index 0000000000..19b490a359
--- /dev/null
+++ b/tests/topotests/bgp_peer-group/r1/bgpd.conf
@@ -0,0 +1,8 @@
+!
+router bgp 65001
+ neighbor PG peer-group
+ neighbor PG remote-as external
+ neighbor PG timers 3 10
+ neighbor 192.168.255.3 peer-group PG
+ neighbor r1-eth0 interface peer-group PG
+!
diff --git a/tests/topotests/bgp_peer-group/r1/zebra.conf b/tests/topotests/bgp_peer-group/r1/zebra.conf
new file mode 100644
index 0000000000..e2c399e536
--- /dev/null
+++ b/tests/topotests/bgp_peer-group/r1/zebra.conf
@@ -0,0 +1,6 @@
+!
+interface r1-eth0
+ ip address 192.168.255.1/24
+!
+ip forwarding
+!
diff --git a/tests/topotests/bgp_peer-group/r2/bgpd.conf b/tests/topotests/bgp_peer-group/r2/bgpd.conf
new file mode 100644
index 0000000000..0880ee9fae
--- /dev/null
+++ b/tests/topotests/bgp_peer-group/r2/bgpd.conf
@@ -0,0 +1,7 @@
+!
+router bgp 65002
+ neighbor PG peer-group
+ neighbor PG remote-as external
+ neighbor PG timers 3 10
+ neighbor r2-eth0 interface peer-group PG
+!
diff --git a/tests/topotests/bgp_peer-group/r2/zebra.conf b/tests/topotests/bgp_peer-group/r2/zebra.conf
new file mode 100644
index 0000000000..606c17bec9
--- /dev/null
+++ b/tests/topotests/bgp_peer-group/r2/zebra.conf
@@ -0,0 +1,6 @@
+!
+interface r2-eth0
+ ip address 192.168.255.2/24
+!
+ip forwarding
+!
diff --git a/tests/topotests/bgp_peer-group/r3/bgpd.conf b/tests/topotests/bgp_peer-group/r3/bgpd.conf
new file mode 100644
index 0000000000..eb2fca15fb
--- /dev/null
+++ b/tests/topotests/bgp_peer-group/r3/bgpd.conf
@@ -0,0 +1,7 @@
+!
+router bgp 65003
+ neighbor PG peer-group
+ neighbor PG remote-as external
+ neighbor PG timers 3 10
+ neighbor 192.168.255.1 peer-group PG
+!
diff --git a/tests/topotests/bgp_peer-group/r3/zebra.conf b/tests/topotests/bgp_peer-group/r3/zebra.conf
new file mode 100644
index 0000000000..e9fdfb70c5
--- /dev/null
+++ b/tests/topotests/bgp_peer-group/r3/zebra.conf
@@ -0,0 +1,6 @@
+!
+interface r3-eth0
+ ip address 192.168.255.3/24
+!
+ip forwarding
+!
diff --git a/tests/topotests/bgp_peer-group/test_bgp_peer-group.py b/tests/topotests/bgp_peer-group/test_bgp_peer-group.py
new file mode 100644
index 0000000000..7c7a8b87ed
--- /dev/null
+++ b/tests/topotests/bgp_peer-group/test_bgp_peer-group.py
@@ -0,0 +1,99 @@
+#!/usr/bin/env python
+
+#
+# Copyright (c) 2021 by
+# Donatas Abraitis <donatas.abraitis@gmail.com>
+#
+# 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 if peer-group works for numbered and unnumbered configurations.
+"""
+
+import os
+import sys
+import json
+import pytest
+import functools
+
+CWD = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join(CWD, "../"))
+
+# pylint: disable=C0413
+from lib import topotest
+from lib.topogen import Topogen, TopoRouter, get_topogen
+from lib.topolog import logger
+from mininet.topo import Topo
+
+
+class TemplateTopo(Topo):
+ def build(self, *_args, **_opts):
+ tgen = get_topogen(self)
+
+ for routern in range(1, 4):
+ tgen.add_router("r{}".format(routern))
+
+ switch = tgen.add_switch("s1")
+ switch.add_link(tgen.gears["r1"])
+ switch.add_link(tgen.gears["r2"])
+ switch.add_link(tgen.gears["r3"])
+
+
+def setup_module(mod):
+ tgen = Topogen(TemplateTopo, mod.__name__)
+ tgen.start_topology()
+
+ router_list = tgen.routers()
+
+ for i, (rname, router) in enumerate(router_list.items(), 1):
+ router.load_config(
+ TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname))
+ )
+ router.load_config(
+ TopoRouter.RD_BGP, os.path.join(CWD, "{}/bgpd.conf".format(rname))
+ )
+
+ tgen.start_router()
+
+
+def teardown_module(mod):
+ tgen = get_topogen()
+ tgen.stop_topology()
+
+
+def test_bgp_peer_group():
+ tgen = get_topogen()
+
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ def _bgp_peer_group_configured():
+ output = json.loads(tgen.gears["r1"].vtysh_cmd("show ip bgp neighbor json"))
+ expected = {
+ "r1-eth0": {"peerGroup": "PG", "bgpState": "Established"},
+ "192.168.255.3": {"peerGroup": "PG", "bgpState": "Established"},
+ }
+ return topotest.json_cmp(output, expected)
+
+ test_func = functools.partial(_bgp_peer_group_configured)
+ success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5)
+
+ assert result is None, 'Failed bgp convergence in "{}"'.format(tgen.gears["r1"])
+
+
+if __name__ == "__main__":
+ args = ["-s"] + sys.argv[1:]
+ sys.exit(pytest.main(args))
diff --git a/tests/topotests/eigrp-topo1/test_eigrp_topo1.py b/tests/topotests/eigrp-topo1/test_eigrp_topo1.py
index 3ce1472ac0..bf94d39a4b 100644
--- a/tests/topotests/eigrp-topo1/test_eigrp_topo1.py
+++ b/tests/topotests/eigrp-topo1/test_eigrp_topo1.py
@@ -91,7 +91,7 @@ class NetworkTopo(Topo):
##
#####################################################
-
+@pytest.mark.eigrp
def setup_module(module):
"Setup topology"
tgen = Topogen(NetworkTopo, module.__name__)
diff --git a/tests/topotests/evpn-pim-1/test_evpn_pim_topo1.py b/tests/topotests/evpn-pim-1/test_evpn_pim_topo1.py
index 265124132f..07623af063 100644
--- a/tests/topotests/evpn-pim-1/test_evpn_pim_topo1.py
+++ b/tests/topotests/evpn-pim-1/test_evpn_pim_topo1.py
@@ -97,7 +97,7 @@ class NetworkTopo(Topo):
##
#####################################################
-
+@pytest.mark.pim
def setup_module(module):
"Setup topology"
tgen = Topogen(NetworkTopo, module.__name__)
diff --git a/tests/topotests/isis-lfa-topo1/test_isis_lfa_topo1.py b/tests/topotests/isis-lfa-topo1/test_isis_lfa_topo1.py
index 6f80ffd1aa..a655b418cf 100755
--- a/tests/topotests/isis-lfa-topo1/test_isis_lfa_topo1.py
+++ b/tests/topotests/isis-lfa-topo1/test_isis_lfa_topo1.py
@@ -163,7 +163,7 @@ class TemplateTopo(Topo):
f_in.close()
f_out.close()
-
+@pytest.mark.isis
def setup_module(mod):
"Sets up the pytest environment"
tgen = Topogen(TemplateTopo, mod.__name__)
diff --git a/tests/topotests/isis-rlfa-topo1/test_isis_rlfa_topo1.py b/tests/topotests/isis-rlfa-topo1/test_isis_rlfa_topo1.py
index 872fef8fdb..bb43e6b114 100755
--- a/tests/topotests/isis-rlfa-topo1/test_isis_rlfa_topo1.py
+++ b/tests/topotests/isis-rlfa-topo1/test_isis_rlfa_topo1.py
@@ -165,7 +165,7 @@ class TemplateTopo(Topo):
f_in.close()
f_out.close()
-
+@pytest.mark.isis
def setup_module(mod):
"Sets up the pytest environment"
tgen = Topogen(TemplateTopo, mod.__name__)
diff --git a/tests/topotests/isis-sr-te-topo1/test_isis_sr_te_topo1.py b/tests/topotests/isis-sr-te-topo1/test_isis_sr_te_topo1.py
index b1071310cf..bfd2f92a28 100755
--- a/tests/topotests/isis-sr-te-topo1/test_isis_sr_te_topo1.py
+++ b/tests/topotests/isis-sr-te-topo1/test_isis_sr_te_topo1.py
@@ -148,6 +148,7 @@ class TemplateTopo(Topo):
switch.add_link(tgen.gears['rt6'], nodeif="eth-dst")
switch.add_link(tgen.gears['dst'], nodeif="eth-rt6")
+@pytest.mark.isis
def setup_module(mod):
"Sets up the pytest environment"
diff --git a/tests/topotests/isis-sr-topo1/test_isis_sr_topo1.py b/tests/topotests/isis-sr-topo1/test_isis_sr_topo1.py
index 34eb6d90f6..63be3f78aa 100644
--- a/tests/topotests/isis-sr-topo1/test_isis_sr_topo1.py
+++ b/tests/topotests/isis-sr-topo1/test_isis_sr_topo1.py
@@ -134,7 +134,7 @@ class TemplateTopo(Topo):
switch.add_link(tgen.gears["rt5"], nodeif="eth-rt6")
switch.add_link(tgen.gears["rt6"], nodeif="eth-rt5")
-
+@pytest.mark.isis
def setup_module(mod):
"Sets up the pytest environment"
tgen = Topogen(TemplateTopo, mod.__name__)
diff --git a/tests/topotests/isis-tilfa-topo1/test_isis_tilfa_topo1.py b/tests/topotests/isis-tilfa-topo1/test_isis_tilfa_topo1.py
index a1263de8ad..83751fabcd 100755
--- a/tests/topotests/isis-tilfa-topo1/test_isis_tilfa_topo1.py
+++ b/tests/topotests/isis-tilfa-topo1/test_isis_tilfa_topo1.py
@@ -177,7 +177,7 @@ class TemplateTopo(Topo):
f_in.close()
f_out.close()
-
+@pytest.mark.isis
def setup_module(mod):
"Sets up the pytest environment"
tgen = Topogen(TemplateTopo, mod.__name__)
diff --git a/tests/topotests/isis-topo1-vrf/test_isis_topo1_vrf.py b/tests/topotests/isis-topo1-vrf/test_isis_topo1_vrf.py
index 12121e4ddf..a79c8a268b 100644
--- a/tests/topotests/isis-topo1-vrf/test_isis_topo1_vrf.py
+++ b/tests/topotests/isis-topo1-vrf/test_isis_topo1_vrf.py
@@ -82,7 +82,7 @@ class ISISTopo1(Topo):
sw.add_link(tgen.gears["r4"])
sw.add_link(tgen.gears["r5"])
-
+@pytest.mark.isis
def setup_module(mod):
"Sets up the pytest environment"
tgen = Topogen(ISISTopo1, mod.__name__)
diff --git a/tests/topotests/isis-topo1/test_isis_topo1.py b/tests/topotests/isis-topo1/test_isis_topo1.py
index 71005a0362..25116d9452 100644
--- a/tests/topotests/isis-topo1/test_isis_topo1.py
+++ b/tests/topotests/isis-topo1/test_isis_topo1.py
@@ -84,7 +84,7 @@ class ISISTopo1(Topo):
sw.add_link(tgen.gears["r4"])
sw.add_link(tgen.gears["r5"])
-
+@pytest.mark.isis
def setup_module(mod):
"Sets up the pytest environment"
tgen = Topogen(ISISTopo1, mod.__name__)
diff --git a/tests/topotests/ldp-topo1/test_ldp_topo1.py b/tests/topotests/ldp-topo1/test_ldp_topo1.py
index 9822686dfc..dfe65f010e 100644
--- a/tests/topotests/ldp-topo1/test_ldp_topo1.py
+++ b/tests/topotests/ldp-topo1/test_ldp_topo1.py
@@ -159,7 +159,7 @@ class NetworkTopo(Topo):
##
#####################################################
-
+@pytest.mark.ldp
def setup_module(module):
global topo, net
global fatal_error
diff --git a/tests/topotests/ldp-vpls-topo1/test_ldp_vpls_topo1.py b/tests/topotests/ldp-vpls-topo1/test_ldp_vpls_topo1.py
index ba94cd47d4..d659acb470 100644
--- a/tests/topotests/ldp-vpls-topo1/test_ldp_vpls_topo1.py
+++ b/tests/topotests/ldp-vpls-topo1/test_ldp_vpls_topo1.py
@@ -121,7 +121,8 @@ class TemplateTopo(Topo):
switch.add_link(tgen.gears["r2"])
switch.add_link(tgen.gears["r3"])
-
+@pytest.mark.ldp
+@pytest.mark.ospf
def setup_module(mod):
"Sets up the pytest environment"
tgen = Topogen(TemplateTopo, mod.__name__)
diff --git a/tests/topotests/lib/bgp.py b/tests/topotests/lib/bgp.py
index 68a7217dd6..22602cb460 100644
--- a/tests/topotests/lib/bgp.py
+++ b/tests/topotests/lib/bgp.py
@@ -692,8 +692,8 @@ def __create_bgp_neighbor(topo, input_dict, router, addr_type, add_neigh=True):
config_data.append("{} activate".format(neigh_cxt))
disable_connected = peer.setdefault("disable_connected_check", False)
- keep_alive = peer.setdefault("keepalivetimer", 60)
- hold_down = peer.setdefault("holddowntimer", 180)
+ keep_alive = peer.setdefault("keepalivetimer", 3)
+ hold_down = peer.setdefault("holddowntimer", 10)
password = peer.setdefault("password", None)
no_password = peer.setdefault("no_password", None)
max_hop_limit = peer.setdefault("ebgp_multihop", 1)
diff --git a/tests/topotests/lib/common_config.py b/tests/topotests/lib/common_config.py
index 85e8c9caed..175d660d1e 100644
--- a/tests/topotests/lib/common_config.py
+++ b/tests/topotests/lib/common_config.py
@@ -1659,7 +1659,7 @@ def create_interfaces_cfg(tgen, topo, build=False):
interface_data.append("no ip ospf " " hello-interval")
else:
interface_data.append(
- "ip ospf " " hello-interval {}".format(intf_ospf_hello)
+ "ip ospf" " hello-interval {}".format(intf_ospf_hello)
)
if "dead_interval" in ospf_data:
@@ -1670,7 +1670,7 @@ def create_interfaces_cfg(tgen, topo, build=False):
interface_data.append("no ip ospf" " dead-interval")
else:
interface_data.append(
- "ip ospf " " dead-interval {}".format(intf_ospf_dead)
+ "ip ospf" " dead-interval {}".format(intf_ospf_dead)
)
if "network" in ospf_data:
@@ -3065,7 +3065,11 @@ def verify_rib(
errormsg = (
"[DUT: {}]: tag value {}"
" is not matched for"
- " route {} in RIB \n".format(dut, _tag, st_rt,)
+ " route {} in RIB \n".format(
+ dut,
+ _tag,
+ st_rt,
+ )
)
return errormsg
@@ -3082,7 +3086,11 @@ def verify_rib(
errormsg = (
"[DUT: {}]: metric value "
"{} is not matched for "
- "route {} in RIB \n".format(dut, metric, st_rt,)
+ "route {} in RIB \n".format(
+ dut,
+ metric,
+ st_rt,
+ )
)
return errormsg
diff --git a/tests/topotests/lib/ospf.py b/tests/topotests/lib/ospf.py
index 23b647d094..3e368cd7d3 100644
--- a/tests/topotests/lib/ospf.py
+++ b/tests/topotests/lib/ospf.py
@@ -62,7 +62,7 @@ def create_router_ospf(tgen, topo, input_dict=None, build=False, load_config=Tru
"r1": {
"ospf": {
"router_id": "22.22.22.22",
- "area": [{ "id":0.0.0.0, "type": "nssa"}]
+ "area": [{ "id": "0.0.0.0", "type": "nssa"}]
}
}
@@ -327,7 +327,7 @@ def config_ospf_interface(tgen, topo, input_dict=None, build=False, load_config=
"links": {
"r2": {
"ospf": {
- "authentication": 'message-digest',
+ "authentication": "message-digest",
"authentication-key": "ospf",
"message-digest-key": "10"
}
@@ -376,6 +376,7 @@ def config_ospf_interface(tgen, topo, input_dict=None, build=False, load_config=
if data_ospf_area:
cmd = "ip ospf area {}".format(data_ospf_area)
config_data.append(cmd)
+
# interface ospf auth
if data_ospf_auth:
if data_ospf_auth == "null":
@@ -461,6 +462,32 @@ def clear_ospf(tgen, router):
logger.debug("Exiting lib API: clear_ospf()")
+def redistribute_ospf(tgen, topo, dut, route_type, **kwargs):
+ """
+ Redstribution of routes inside ospf.
+
+ Parameters
+ ----------
+ * `tgen`: Topogen object
+ * `topo` : json file data
+ * `dut`: device under test
+ * `route_type`: "static" or "connected" or ....
+ * `kwargs`: pass extra information (see below)
+
+ Usage
+ -----
+ redistribute_ospf(tgen, topo, "r0", "static", delete=True)
+ redistribute_ospf(tgen, topo, "r0", "static", route_map="rmap_ipv4")
+ """
+
+ ospf_red = {dut: {"ospf": {"redistribute": [{"redist_type": route_type}]}}}
+ for k, v in kwargs.items():
+ ospf_red[dut]["ospf"]["redistribute"][0][k] = v
+
+ result = create_router_ospf(tgen, topo, ospf_red)
+ assert result is True, "Testcase : Failed \n Error: {}".format(result)
+
+
################################
# Verification procs
################################
@@ -522,7 +549,7 @@ def verify_ospf_neighbor(tgen, topo, dut=None, input_dict=None, lan=False):
logger.info("Verifying OSPF neighborship on router %s:", router)
show_ospf_json = run_frr_cmd(
- rnode, "show ip ospf neighbor all json", isjson=True
+ rnode, "show ip ospf neighbor all json", isjson=True
)
# Verifying output dictionary show_ospf_json is empty or not
@@ -844,19 +871,23 @@ def verify_ospf_rib(
if "routeType" not in ospf_rib_json[st_rt]:
errormsg = (
"[DUT: {}]: routeType missing"
- "for route {} in OSPF RIB \n".format(dut, st_rt)
+ " for route {} in OSPF RIB \n".format(
+ dut, st_rt
+ )
)
return errormsg
elif _rtype != ospf_rib_json[st_rt]["routeType"]:
errormsg = (
"[DUT: {}]: routeType mismatch"
- "for route {} in OSPF RIB \n".format(dut, st_rt)
+ " for route {} in OSPF RIB \n".format(
+ dut, st_rt
+ )
)
return errormsg
else:
logger.info(
- "DUT: {}]: Found routeType {}"
- "for route {}".format(dut, _rtype, st_rt)
+ "[DUT: {}]: Found routeType {}"
+ " for route {}".format(dut, _rtype, st_rt)
)
if tag:
if "tag" not in ospf_rib_json[st_rt]:
diff --git a/tests/topotests/ospf_basic_functionality/test_ospf_ecmp.py b/tests/topotests/ospf_basic_functionality/test_ospf_ecmp.py
index 5ef6b9b0be..441368e8fa 100644
--- a/tests/topotests/ospf_basic_functionality/test_ospf_ecmp.py
+++ b/tests/topotests/ospf_basic_functionality/test_ospf_ecmp.py
@@ -65,6 +65,7 @@ from lib.ospf import (
verify_ospf_rib,
create_router_ospf,
verify_ospf_interface,
+ redistribute_ospf,
)
topo = None
@@ -184,38 +185,6 @@ def teardown_module(mod):
logger.info("=" * 40)
-def red_static(dut, config=True):
- """Local def for Redstribute static routes inside ospf."""
- global topo
- tgen = get_topogen()
- if config:
- ospf_red = {dut: {"ospf": {"redistribute": [{"redist_type": "static"}]}}}
- else:
- ospf_red = {
- dut: {"ospf": {"redistribute": [{"redist_type": "static", "delete": True}]}}
- }
- result = create_router_ospf(tgen, topo, ospf_red)
- assert result is True, "Testcase : Failed \n Error: {}".format(result)
-
-
-def red_connected(dut, config=True):
- """Local def for Redstribute connected routes inside ospf."""
- global topo
- tgen = get_topogen()
- if config:
- ospf_red = {dut: {"ospf": {"redistribute": [{"redist_type": "connected"}]}}}
- else:
- ospf_red = {
- dut: {
- "ospf": {
- "redistribute": [{"redist_type": "connected", "del_action": True}]
- }
- }
- }
- result = create_router_ospf(tgen, topo, ospf_red)
- assert result is True, "Testcase: Failed \n Error: {}".format(result)
-
-
# ##################################
# Test cases start here.
# ##################################
@@ -264,7 +233,7 @@ def test_ospf_ecmp_tc16_p0(request):
assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
dut = "r0"
- red_static(dut)
+ redistribute_ospf(tgen, topo, dut, "static")
step("Verify that route in R2 in stalled with 8 next hops.")
nh = []
@@ -345,7 +314,7 @@ def test_ospf_ecmp_tc16_p0(request):
step(" Un configure static route on R0")
dut = "r0"
- red_static(dut, config=False)
+ redistribute_ospf(tgen, topo, dut, "static", delete=True)
# Wait for R0 to flush external LSAs.
sleep(10)
@@ -376,7 +345,7 @@ def test_ospf_ecmp_tc16_p0(request):
step("Re configure the static route in R0.")
dut = "r0"
- red_static(dut)
+ redistribute_ospf(tgen, topo, dut, "static")
dut = "r1"
result = verify_ospf_rib(tgen, dut, input_dict, next_hop=nh)
@@ -431,7 +400,7 @@ def test_ospf_ecmp_tc17_p0(request):
assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
dut = "r0"
- red_static(dut)
+ redistribute_ospf(tgen, topo, dut, "static")
step("Verify that route in R2 in stalled with 2 next hops.")
@@ -450,7 +419,7 @@ def test_ospf_ecmp_tc17_p0(request):
step(" Un configure static route on R0")
dut = "r0"
- red_static(dut, config=False)
+ redistribute_ospf(tgen, topo, dut, "static", delete=True)
# sleep till the route gets withdrawn
sleep(10)
@@ -480,7 +449,7 @@ def test_ospf_ecmp_tc17_p0(request):
step("Reconfigure the static route in R0.Change ECMP value to 2.")
dut = "r0"
- red_static(dut)
+ redistribute_ospf(tgen, topo, dut, "static")
step("Configure cost on R0 as 100")
r0_ospf_cost = {"r0": {"links": {"r1": {"ospf": {"cost": 100}}}}}
diff --git a/tests/topotests/ospf_basic_functionality/test_ospf_ecmp_lan.py b/tests/topotests/ospf_basic_functionality/test_ospf_ecmp_lan.py
index 967bc44879..2da1dcd21a 100644
--- a/tests/topotests/ospf_basic_functionality/test_ospf_ecmp_lan.py
+++ b/tests/topotests/ospf_basic_functionality/test_ospf_ecmp_lan.py
@@ -66,6 +66,7 @@ from lib.ospf import (
verify_ospf_rib,
create_router_ospf,
verify_ospf_interface,
+ redistribute_ospf,
)
from ipaddress import IPv4Address
@@ -187,42 +188,6 @@ def teardown_module():
pass
-def red_static(dut, config=True):
- """Local def for Redstribute static routes inside ospf."""
- global topo
- tgen = get_topogen()
- if config:
- ospf_red = {dut: {"ospf": {"redistribute": [{"redist_type": "static"}]}}}
- else:
- ospf_red = {
- dut: {
- "ospf": {
- "redistribute": [{"redist_type": "static", "del_action": True}]
- }
- }
- }
- result = create_router_ospf(tgen, topo, ospf_red)
- assert result is True, "Testcase : Failed \n Error: {}".format(result)
-
-
-def red_connected(dut, config=True):
- """Local def for Redstribute connected routes inside ospf."""
- global topo
- tgen = get_topogen()
- if config:
- ospf_red = {dut: {"ospf": {"redistribute": [{"redist_type": "connected"}]}}}
- else:
- ospf_red = {
- dut: {
- "ospf": {
- "redistribute": [{"redist_type": "connected", "del_action": True}]
- }
- }
- }
- result = create_router_ospf(tgen, topo, ospf_red)
- assert result is True, "Testcase: Failed \n Error: {}".format(result)
-
-
# ##################################
# Test cases start here.
# ##################################
@@ -275,7 +240,7 @@ def test_ospf_lan_ecmp_tc18_p0(request):
)
dut = rtr
- red_static(dut)
+ redistribute_ospf(tgen, topo, dut, "static")
step(
"Verify that route in R0 in stalled with 8 hops. "
diff --git a/tests/topotests/ospf_basic_functionality/test_ospf_lan.py b/tests/topotests/ospf_basic_functionality/test_ospf_lan.py
index 0f1115f815..dac32090bc 100644
--- a/tests/topotests/ospf_basic_functionality/test_ospf_lan.py
+++ b/tests/topotests/ospf_basic_functionality/test_ospf_lan.py
@@ -183,42 +183,6 @@ def teardown_module():
pass
-def red_static(dut, config=True):
- """Local def for Redstribute static routes inside ospf."""
- global topo
- tgen = get_topogen()
- if config:
- ospf_red = {dut: {"ospf": {"redistribute": [{"redist_type": "static"}]}}}
- else:
- ospf_red = {
- dut: {
- "ospf": {
- "redistribute": [{"redist_type": "static", "del_action": True}]
- }
- }
- }
- result = create_router_ospf(tgen, topo, ospf_red)
- assert result is True, "Testcase : Failed \n Error: {}".format(result)
-
-
-def red_connected(dut, config=True):
- """Local def for Redstribute connected routes inside ospf."""
- global topo
- tgen = get_topogen()
- if config:
- ospf_red = {dut: {"ospf": {"redistribute": [{"redist_type": "connected"}]}}}
- else:
- ospf_red = {
- dut: {
- "ospf": {
- "redistribute": [{"redist_type": "connected", "del_action": True}]
- }
- }
- }
- result = create_router_ospf(tgen, topo, ospf_red)
- assert result is True, "Testcase: Failed \n Error: {}".format(result)
-
-
# ##################################
# Test cases start here.
# ##################################
diff --git a/tests/topotests/ospf_basic_functionality/test_ospf_nssa.py b/tests/topotests/ospf_basic_functionality/test_ospf_nssa.py
index 82a34d046c..3644bff3dc 100644
--- a/tests/topotests/ospf_basic_functionality/test_ospf_nssa.py
+++ b/tests/topotests/ospf_basic_functionality/test_ospf_nssa.py
@@ -30,6 +30,7 @@ from lib.ospf import (
verify_ospf_rib,
create_router_ospf,
verify_ospf_interface,
+ redistribute_ospf,
)
from lib.topojson import build_topo_from_json, build_config_from_json
from lib.topolog import logger
@@ -181,38 +182,6 @@ def teardown_module(mod):
logger.info("=" * 40)
-def red_static(dut, config=True):
- """Local def for Redstribute static routes inside ospf."""
- global topo
- tgen = get_topogen()
- if config:
- ospf_red = {dut: {"ospf": {"redistribute": [{"redist_type": "static"}]}}}
- else:
- ospf_red = {
- dut: {"ospf": {"redistribute": [{"redist_type": "static", "delete": True}]}}
- }
- result = create_router_ospf(tgen, topo, ospf_red)
- assert result is True, "Testcase : Failed \n Error: {}".format(result)
-
-
-def red_connected(dut, config=True):
- """Local def for Redstribute connected routes inside ospf."""
- global topo
- tgen = get_topogen()
- if config:
- ospf_red = {dut: {"ospf": {"redistribute": [{"redist_type": "connected"}]}}}
- else:
- ospf_red = {
- dut: {
- "ospf": {
- "redistribute": [{"redist_type": "connected", "del_action": True}]
- }
- }
- }
- result = create_router_ospf(tgen, topo, ospf_red)
- assert result is True, "Testcase: Failed \n Error: {}".format(result)
-
-
# ##################################
# Test cases start here.
# ##################################
@@ -268,7 +237,7 @@ def test_ospf_learning_tc15_p0(request):
step("Redistribute static route in R2 ospf.")
dut = "r2"
- red_static(dut)
+ redistribute_ospf(tgen, topo, dut, "static")
step("Verify that Type 5 LSA is originated by R2.")
dut = "r0"
diff --git a/tests/topotests/ospf_basic_functionality/test_ospf_routemaps.py b/tests/topotests/ospf_basic_functionality/test_ospf_routemaps.py
index 88667a6ac8..ceadb3975b 100644
--- a/tests/topotests/ospf_basic_functionality/test_ospf_routemaps.py
+++ b/tests/topotests/ospf_basic_functionality/test_ospf_routemaps.py
@@ -62,6 +62,7 @@ from lib.ospf import (
verify_ospf_rib,
create_router_ospf,
verify_ospf_database,
+ redistribute_ospf,
)
# Global variables
@@ -226,9 +227,7 @@ def test_ospf_routemaps_functionality_tc19_p0(request):
result = create_static_routes(tgen, input_dict)
assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
- ospf_red_r1 = {"r0": {"ospf": {"redistribute": [{"redist_type": "static"}]}}}
- result = create_router_ospf(tgen, topo, ospf_red_r1)
- assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+ redistribute_ospf(tgen, topo, "r0", "static")
dut = "r1"
lsid = NETWORK["ipv4"][0].split("/")[0]
@@ -240,13 +239,7 @@ def test_ospf_routemaps_functionality_tc19_p0(request):
result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol)
assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
- ospf_red_r1 = {
- "r0": {
- "ospf": {"redistribute": [{"redist_type": "static", "del_action": True}]}
- }
- }
- result = create_router_ospf(tgen, topo, ospf_red_r1)
- assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+ redistribute_ospf(tgen, topo, "r0", "static", delete=True)
step(
"Create prefix-list in R0 to permit 10.0.20.1/32 prefix &" " deny 10.0.20.2/32"
@@ -293,15 +286,7 @@ def test_ospf_routemaps_functionality_tc19_p0(request):
" ospf using route map rmap1"
)
- ospf_red_r1 = {
- "r0": {
- "ospf": {
- "redistribute": [{"redist_type": "static", "route_map": "rmap_ipv4"}]
- }
- }
- }
- result = create_router_ospf(tgen, topo, ospf_red_r1)
- assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+ redistribute_ospf(tgen, topo, "r0", "static", route_map="rmap_ipv4")
step("Change prefix rules to permit 10.0.20.2 and deny 10.0.20.1")
# Create ip prefix list
@@ -495,15 +480,7 @@ def test_ospf_routemaps_functionality_tc20_p0(request):
assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
step("Redistribute to ospf using route map ( non existent route map)")
- ospf_red_r1 = {
- "r0": {
- "ospf": {
- "redistribute": [{"redist_type": "static", "route_map": "rmap_ipv4"}]
- }
- }
- }
- result = create_router_ospf(tgen, topo, ospf_red_r1)
- assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+ redistribute_ospf(tgen, topo, "r0", "static", route_map="rmap_ipv4")
step(
"Verify that routes are not allowed in OSPF even tough no "
@@ -633,15 +610,7 @@ def test_ospf_routemaps_functionality_tc21_p0(request):
result = create_static_routes(tgen, input_dict)
assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
- ospf_red_r0 = {
- "r0": {
- "ospf": {
- "redistribute": [{"redist_type": "static", "route_map": "rmap_ipv4"}]
- }
- }
- }
- result = create_router_ospf(tgen, topo, ospf_red_r0)
- assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+ redistribute_ospf(tgen, topo, "r0", "static", route_map="rmap_ipv4")
# Create route map
routemaps = {
@@ -877,15 +846,7 @@ def test_ospf_routemaps_functionality_tc24_p0(request):
result = create_static_routes(tgen, input_dict)
assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
- ospf_red_r0 = {
- "r0": {
- "ospf": {
- "redistribute": [{"redist_type": "static", "route_map": "rmap_ipv4"}]
- }
- }
- }
- result = create_router_ospf(tgen, topo, ospf_red_r0)
- assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+ redistribute_ospf(tgen, topo, "r0", "static", route_map="rmap_ipv4")
# Create ip prefix list
pfx_list = {
diff --git a/tests/topotests/ospf_basic_functionality/test_ospf_rte_calc.py b/tests/topotests/ospf_basic_functionality/test_ospf_rte_calc.py
index 434d7f8ef5..5aa2779aee 100644
--- a/tests/topotests/ospf_basic_functionality/test_ospf_rte_calc.py
+++ b/tests/topotests/ospf_basic_functionality/test_ospf_rte_calc.py
@@ -61,6 +61,7 @@ from lib.ospf import (
clear_ospf,
verify_ospf_rib,
create_router_ospf,
+ redistribute_ospf,
)
# Global variables
@@ -183,42 +184,6 @@ def teardown_module(mod):
logger.info("=" * 40)
-def red_static(dut, config=True):
- """Local def for Redstribute static routes inside ospf."""
- global topo
- tgen = get_topogen()
- if config:
- ospf_red = {dut: {"ospf": {"redistribute": [{"redist_type": "static"}]}}}
- else:
- ospf_red = {
- dut: {
- "ospf": {
- "redistribute": [{"redist_type": "static", "del_action": True}]
- }
- }
- }
- result = create_router_ospf(tgen, topo, ospf_red)
- assert result is True, "Testcase : Failed \n Error: {}".format(result)
-
-
-def red_connected(dut, config=True):
- """Local def for Redstribute connected routes inside ospf."""
- global topo
- tgen = get_topogen()
- if config:
- ospf_red = {dut: {"ospf": {"redistribute": [{"redist_type": "connected"}]}}}
- else:
- ospf_red = {
- dut: {
- "ospf": {
- "redistribute": [{"redist_type": "connected", "del_action": True}]
- }
- }
- }
- result = create_router_ospf(tgen, topo, ospf_red)
- assert result is True, "Testcase: Failed \n Error: {}".format(result)
-
-
# ##################################
# Test cases start here.
# ##################################
@@ -486,8 +451,8 @@ def test_ospf_redistribution_tc8_p1(request):
"advertised/exchaged via ospf"
)
for rtr in topo["routers"]:
- red_static(rtr)
- red_connected(rtr)
+ redistribute_ospf(tgen, topo, rtr, "static")
+ redistribute_ospf(tgen, topo, rtr, "connected")
for node in topo["routers"]:
input_dict = {
"r0": {
@@ -544,13 +509,7 @@ def test_ospf_redistribution_tc8_p1(request):
)
for rtr in topo["routers"]:
- ospf_red = {
- rtr: {"ospf": {"redistribute": [{"redist_type": "static", "delete": True}]}}
- }
- result = create_router_ospf(tgen, topo, ospf_red)
- assert result is True, "Testcase {} : Failed \n Error: {}".format(
- tc_name, result
- )
+ redistribute_ospf(tgen, topo, rtr, "static", delete=True)
input_dict = {
"r0": {
diff --git a/tests/topotests/pbr-topo1/test_pbr_topo1.py b/tests/topotests/pbr-topo1/test_pbr_topo1.py
index fcbe3c0adf..5161d5eec7 100644
--- a/tests/topotests/pbr-topo1/test_pbr_topo1.py
+++ b/tests/topotests/pbr-topo1/test_pbr_topo1.py
@@ -80,7 +80,7 @@ class NetworkTopo(Topo):
##
#####################################################
-
+@pytest.mark.pbr
def setup_module(module):
"Setup topology"
tgen = Topogen(NetworkTopo, module.__name__)
diff --git a/tests/topotests/pim-basic/test_pim.py b/tests/topotests/pim-basic/test_pim.py
index e8a9f72b48..74a7fbf16e 100644
--- a/tests/topotests/pim-basic/test_pim.py
+++ b/tests/topotests/pim-basic/test_pim.py
@@ -80,7 +80,7 @@ class PIMTopo(Topo):
sw.add_link(tgen.gears["r1"])
sw.add_link(tgen.gears["r3"])
-
+@pytest.mark.pim
def setup_module(mod):
"Sets up the pytest environment"
tgen = Topogen(PIMTopo, mod.__name__)
diff --git a/tests/topotests/pytest.ini b/tests/topotests/pytest.ini
index 6e8e749092..d1b18a57bb 100644
--- a/tests/topotests/pytest.ini
+++ b/tests/topotests/pytest.ini
@@ -1,6 +1,16 @@
# Skip pytests example directory
[pytest]
norecursedirs = .git example-test example-topojson-test lib docker
+markers =
+ babel: Tests that run against BABEL
+ bfd: Tests that run against BFDD
+ eigrp: Tests that run against EIGRPD
+ isis: Tests that run against ISISD
+ ldp: Tests that run against LDPD
+ ospf: Tests that run against OSPF( v2 and v3 )
+ pbr: Tests that run against PBRD
+ pim: Tests that run against pim
+ rip: Tests that run against RIP, both v4 and v6
[topogen]
# Default configuration values
diff --git a/tests/topotests/rip-topo1/test_rip_topo1.py b/tests/topotests/rip-topo1/test_rip_topo1.py
index fdafa50aba..edad1ff65d 100644
--- a/tests/topotests/rip-topo1/test_rip_topo1.py
+++ b/tests/topotests/rip-topo1/test_rip_topo1.py
@@ -104,7 +104,7 @@ class NetworkTopo(Topo):
##
#####################################################
-
+@pytest.mark.rip
def setup_module(module):
global topo, net
diff --git a/tests/topotests/ripng-topo1/test_ripng_topo1.py b/tests/topotests/ripng-topo1/test_ripng_topo1.py
index 4702d33dae..47b63e5b26 100644
--- a/tests/topotests/ripng-topo1/test_ripng_topo1.py
+++ b/tests/topotests/ripng-topo1/test_ripng_topo1.py
@@ -104,7 +104,7 @@ class NetworkTopo(Topo):
##
#####################################################
-
+@pytest.mark.rip
def setup_module(module):
global topo, net
diff --git a/tools/frr-reload.py b/tools/frr-reload.py
index d5fa8ab6a3..0aa5f1e516 100755
--- a/tools/frr-reload.py
+++ b/tools/frr-reload.py
@@ -221,6 +221,7 @@ ip forwarding
for ligne in lines:
self.dlines[ligne] = True
+
def get_normalized_es_id(line):
"""
The es-id or es-sys-mac need to be converted to lower case
@@ -233,6 +234,7 @@ def get_normalized_es_id(line):
break
return line
+
def get_normalized_mac_ip_line(line):
if line.startswith("evpn mh es"):
return get_normalized_es_id(line)
@@ -242,6 +244,7 @@ def get_normalized_mac_ip_line(line):
return line
+
class Config(object):
"""
@@ -640,7 +643,7 @@ end
log.debug(
"LINE %-50s: popping segment routing sub-context to ctx%-50s",
line,
- ctx_keys
+ ctx_keys,
)
elif line in ["exit-address-family", "exit", "exit-vnc"]:
@@ -654,7 +657,7 @@ end
log.debug(
"LINE %-50s: popping from subcontext to ctx%-50s",
line,
- ctx_keys
+ ctx_keys,
)
elif line in ["exit-vni", "exit-ldp-if"]:
@@ -755,7 +758,8 @@ end
self.save_contexts(ctx_keys, current_context_lines)
current_context_lines = []
log.debug(
- "LINE %-50s: entering segment routing sub-context, append to ctx_keys", line
+ "LINE %-50s: entering segment routing sub-context, append to ctx_keys",
+ line,
)
ctx_keys.append(line)
@@ -770,7 +774,8 @@ end
self.save_contexts(ctx_keys, current_context_lines)
current_context_lines = []
log.debug(
- "LINE %-50s: entering segment routing sub-context, append to ctx_keys", line
+ "LINE %-50s: entering segment routing sub-context, append to ctx_keys",
+ line,
)
ctx_keys.append(line)
@@ -785,7 +790,8 @@ end
self.save_contexts(ctx_keys, current_context_lines)
current_context_lines = []
log.debug(
- "LINE %-50s: entering segment routing sub-context, append to ctx_keys", line
+ "LINE %-50s: entering segment routing sub-context, append to ctx_keys",
+ line,
)
ctx_keys.append(line)
@@ -803,7 +809,8 @@ end
current_context_lines = []
main_ctx_key = copy.deepcopy(ctx_keys)
log.debug(
- "LINE %-50s: entering candidate-path sub-context, append to ctx_keys", line
+ "LINE %-50s: entering candidate-path sub-context, append to ctx_keys",
+ line,
)
ctx_keys.append(line)
@@ -836,7 +843,8 @@ end
current_context_lines = []
main_ctx_key = copy.deepcopy(ctx_keys)
log.debug(
- "LINE %-50s: entering pce-config sub-context, append to ctx_keys", line
+ "LINE %-50s: entering pce-config sub-context, append to ctx_keys",
+ line,
)
ctx_keys.append(line)
@@ -1230,30 +1238,44 @@ def ignore_delete_re_add_lines(lines_to_add, lines_to_del):
lines_to_add_to_del.append((ctx[0], None))
"""
- ip/ipv6 prefix-list can be specified without a seq number. However,
- the running config always adds 'seq x', where x is a number incremented
- by 5 for every element, to the prefix list. So, ignore such lines as
- well. Sample prefix-list lines:
+ ip/ipv6 prefix-lists and access-lists can be specified without a seq number.
+ However, the running config always adds 'seq x', where x is a number
+ incremented by 5 for every element of the prefix/access list.
+ So, ignore such lines as well. Sample prefix-list and acces-list lines:
ip prefix-list PR-TABLE-2 seq 5 permit 20.8.2.0/24 le 32
ip prefix-list PR-TABLE-2 seq 10 permit 20.8.2.0/24 le 32
ipv6 prefix-list vrfdev6-12 permit 2000:9:2::/64 gt 64
+ access-list FOO seq 5 permit 2.2.2.2/32
+ ipv6 access-list BAR seq 5 permit 2:2:2::2/128
"""
- re_ip_pfxlst = re.search(
- "^(ip|ipv6)(\s+prefix-list\s+)(\S+\s+)(seq \d+\s+)(permit|deny)(.*)$",
+ re_acl_pfxlst = re.search(
+ "^(ip |ipv6 |)(prefix-list|access-list)(\s+\S+\s+)(seq \d+\s+)(permit|deny)(.*)$",
ctx_keys[0],
)
- if re_ip_pfxlst:
+ if re_acl_pfxlst:
+ found = False
tmpline = (
- re_ip_pfxlst.group(1)
- + re_ip_pfxlst.group(2)
- + re_ip_pfxlst.group(3)
- + re_ip_pfxlst.group(5)
- + re_ip_pfxlst.group(6)
+ re_acl_pfxlst.group(1)
+ + re_acl_pfxlst.group(2)
+ + re_acl_pfxlst.group(3)
+ + re_acl_pfxlst.group(5)
+ + re_acl_pfxlst.group(6)
)
for ctx in lines_to_add:
if ctx[0][0] == tmpline:
lines_to_del_to_del.append((ctx_keys, None))
lines_to_add_to_del.append(((tmpline,), None))
+ found = True
+ """
+ If prefix-lists or access-lists are being deleted and
+ not added (see comment above), add command with 'no' to
+ lines_to_add and remove from lines_to_del to improve
+ scaling performance.
+ """
+ if found is False:
+ add_cmd = ("no " + ctx_keys[0],)
+ lines_to_add.append((add_cmd, None))
+ lines_to_del_to_del.append((ctx_keys, None))
if (
len(ctx_keys) == 3
@@ -1451,14 +1473,9 @@ def compare_context_objects(newconf, running):
# doing vtysh -c inefficient (and can time out.) For
# these commands, instead of adding them to lines_to_del,
# add the "no " version to lines_to_add.
- elif (
- running_ctx_keys[0].startswith("ip route")
- or running_ctx_keys[0].startswith("ipv6 route")
- or running_ctx_keys[0].startswith("access-list")
- or running_ctx_keys[0].startswith("ipv6 access-list")
- or running_ctx_keys[0].startswith("ip prefix-list")
- or running_ctx_keys[0].startswith("ipv6 prefix-list")
- ):
+ elif running_ctx_keys[0].startswith("ip route") or running_ctx_keys[
+ 0
+ ].startswith("ipv6 route"):
add_cmd = ("no " + running_ctx_keys[0],)
lines_to_add.append((add_cmd, None))
@@ -1473,14 +1490,17 @@ def compare_context_objects(newconf, running):
continue
# same thing for a pseudowire sub-context inside an l2vpn context
- elif (len(running_ctx_keys) > 1 and running_ctx_keys[0].startswith('l2vpn') and
- running_ctx_keys[1].startswith('member pseudowire') and
- (running_ctx_keys[:1], None) in lines_to_del):
+ elif (
+ len(running_ctx_keys) > 1
+ and running_ctx_keys[0].startswith("l2vpn")
+ and running_ctx_keys[1].startswith("member pseudowire")
+ and (running_ctx_keys[:1], None) in lines_to_del
+ ):
continue
# Segment routing and traffic engineering never need to be deleted
elif (
- running_ctx_keys[0].startswith('segment-routing')
+ running_ctx_keys[0].startswith("segment-routing")
and len(running_ctx_keys) < 3
):
continue
@@ -1488,8 +1508,8 @@ def compare_context_objects(newconf, running):
# Neither the pcep command
elif (
len(running_ctx_keys) == 3
- and running_ctx_keys[0].startswith('segment-routing')
- and running_ctx_keys[2].startswith('pcep')
+ and running_ctx_keys[0].startswith("segment-routing")
+ and running_ctx_keys[2].startswith("pcep")
):
continue
@@ -1497,8 +1517,8 @@ def compare_context_objects(newconf, running):
# use them, so add them to a separate array that is going to be appended at the end
elif (
len(running_ctx_keys) == 3
- and running_ctx_keys[0].startswith('segment-routing')
- and running_ctx_keys[2].startswith('segment-list')
+ and running_ctx_keys[0].startswith("segment-routing")
+ and running_ctx_keys[2].startswith("segment-list")
):
seglist_to_del.append((running_ctx_keys, None))
@@ -1506,8 +1526,8 @@ def compare_context_objects(newconf, running):
# we add them to a separate array that is going to be appended at the end
elif (
len(running_ctx_keys) == 3
- and running_ctx_keys[0].startswith('segment-routing')
- and running_ctx_keys[2].startswith('policy')
+ and running_ctx_keys[0].startswith("segment-routing")
+ and running_ctx_keys[2].startswith("policy")
):
pollist_to_del.append((running_ctx_keys, None))
@@ -1515,16 +1535,16 @@ def compare_context_objects(newconf, running):
# to a separate array that is going to be appended at the end
elif (
len(running_ctx_keys) >= 4
- and running_ctx_keys[0].startswith('segment-routing')
- and running_ctx_keys[3].startswith('pce-config')
+ and running_ctx_keys[0].startswith("segment-routing")
+ and running_ctx_keys[3].startswith("pce-config")
):
pceconf_to_del.append((running_ctx_keys, None))
# pcc must be deleted after the pce and pce-config too
elif (
len(running_ctx_keys) >= 4
- and running_ctx_keys[0].startswith('segment-routing')
- and running_ctx_keys[3].startswith('pcc')
+ and running_ctx_keys[0].startswith("segment-routing")
+ and running_ctx_keys[3].startswith("pcc")
):
pcclist_to_del.append((running_ctx_keys, None))
@@ -1572,9 +1592,9 @@ def compare_context_objects(newconf, running):
# so add them to a separate array that is going to be appended at the end
if (
len(newconf_ctx_keys) == 3
- and newconf_ctx_keys[0].startswith('segment-routing')
- and newconf_ctx_keys[2].startswith('policy ')
- and line.startswith('candidate-path ')
+ and newconf_ctx_keys[0].startswith("segment-routing")
+ and newconf_ctx_keys[2].startswith("policy ")
+ and line.startswith("candidate-path ")
):
candidates_to_add.append((newconf_ctx_keys, line))
@@ -1593,8 +1613,8 @@ def compare_context_objects(newconf, running):
# so add them to a separate array that is going to be appended at the end
if (
len(newconf_ctx_keys) == 4
- and newconf_ctx_keys[0].startswith('segment-routing')
- and newconf_ctx_keys[3].startswith('candidate-path')
+ and newconf_ctx_keys[0].startswith("segment-routing")
+ and newconf_ctx_keys[3].startswith("candidate-path")
):
candidates_to_add.append((newconf_ctx_keys, None))
for line in newconf_ctx.lines:
@@ -1823,8 +1843,6 @@ if __name__ == "__main__":
else:
running.load_from_show_running(args.daemon)
-
-
(lines_to_add, lines_to_del) = compare_context_objects(newconf, running)
lines_to_configure = []
diff --git a/yang/frr-staticd.yang b/yang/frr-staticd.yang
index 281b4903c0..98ff3a83c6 100644
--- a/yang/frr-staticd.yang
+++ b/yang/frr-staticd.yang
@@ -63,7 +63,13 @@ module frr-staticd {
grouping staticd-prefix-attributes {
list path-list {
- key "distance";
+ key "table-id distance";
+ leaf table-id {
+ type uint32;
+ description
+ "Table-id";
+ }
+
leaf distance {
type frr-rt:administrative-distance;
description
@@ -77,13 +83,6 @@ module frr-staticd {
"Route tag";
}
- leaf table-id {
- type uint32;
- default "0";
- description
- "Table-id";
- }
-
uses frr-nexthop:frr-nexthop;
}
}
diff --git a/zebra/dplane_fpm_nl.c b/zebra/dplane_fpm_nl.c
index 51ce59c477..bf733e38f7 100644
--- a/zebra/dplane_fpm_nl.c
+++ b/zebra/dplane_fpm_nl.c
@@ -1236,7 +1236,13 @@ static int fpm_process_queue(struct thread *t)
if (ctx == NULL)
break;
- fpm_nl_enqueue(fnc, ctx);
+ /*
+ * Intentionally ignoring the return value
+ * as that we are ensuring that we can write to
+ * the output data in the STREAM_WRITEABLE
+ * check above, so we can ignore the return
+ */
+ (void)fpm_nl_enqueue(fnc, ctx);
/* Account the processed entries. */
processed_contexts++;
diff --git a/zebra/zebra_evpn_mac.c b/zebra/zebra_evpn_mac.c
index 376721f83a..6753bf520c 100644
--- a/zebra/zebra_evpn_mac.c
+++ b/zebra/zebra_evpn_mac.c
@@ -29,6 +29,7 @@
#include "prefix.h"
#include "vlan.h"
#include "json.h"
+#include "printfrr.h"
#include "zebra/zserv.h"
#include "zebra/debug.h"
@@ -254,6 +255,37 @@ static void zebra_evpn_mac_get_access_info(zebra_mac_t *mac,
}
}
+#define MAC_BUF_SIZE 256
+static char *zebra_evpn_zebra_mac_flag_dump(struct zebra_mac_t_ *mac, char *buf,
+ size_t len)
+{
+ if (mac->flags == 0) {
+ snprintfrr(buf, len, "None ");
+ return buf;
+ }
+
+ snprintfrr(
+ buf, len, "%s%s%s%s%s%s%s%s%s%s%s%s",
+ CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL) ? "LOC " : "",
+ CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE) ? "REM " : "",
+ CHECK_FLAG(mac->flags, ZEBRA_MAC_AUTO) ? "AUTO " : "",
+ CHECK_FLAG(mac->flags, ZEBRA_MAC_STICKY) ? "STICKY " : "",
+ CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE_RMAC) ? "REM Router "
+ : "",
+ CHECK_FLAG(mac->flags, ZEBRA_MAC_DEF_GW) ? "Default GW " : "",
+ CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE_DEF_GW) ? "REM DEF GW "
+ : "",
+ CHECK_FLAG(mac->flags, ZEBRA_MAC_DUPLICATE) ? "DUP " : "",
+ CHECK_FLAG(mac->flags, ZEBRA_MAC_FPM_SENT) ? "FPM " : "",
+ CHECK_FLAG(mac->flags, ZEBRA_MAC_ES_PEER_ACTIVE) ? "LOC Active "
+ : "",
+ CHECK_FLAG(mac->flags, ZEBRA_MAC_ES_PEER_PROXY) ? "PROXY " : "",
+ CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL_INACTIVE)
+ ? "LOC Inactive "
+ : "");
+ return buf;
+}
+
static int zebra_evpn_dad_mac_auto_recovery_exp(struct thread *t)
{
struct zebra_vrf *zvrf = NULL;
@@ -278,12 +310,17 @@ static int zebra_evpn_dad_mac_auto_recovery_exp(struct thread *t)
if (!mac)
return 0;
- if (IS_ZEBRA_DEBUG_VXLAN)
+ if (IS_ZEBRA_DEBUG_VXLAN) {
+ char mac_buf[MAC_BUF_SIZE];
+
zlog_debug(
- "%s: duplicate addr mac %s flags 0x%x learn count %u host count %u auto recovery expired",
+ "%s: duplicate addr mac %s flags %slearn count %u host count %u auto recovery expired",
__func__,
prefix_mac2str(&mac->macaddr, buf, sizeof(buf)),
- mac->flags, mac->dad_count, listcount(mac->neigh_list));
+ zebra_evpn_zebra_mac_flag_dump(mac, mac_buf,
+ sizeof(mac_buf)),
+ mac->dad_count, listcount(mac->neigh_list));
+ }
/* Remove all IPs as duplicate associcated with this MAC */
for (ALL_LIST_ELEMENTS_RO(mac->neigh_list, node, nbr)) {
@@ -350,14 +387,17 @@ static void zebra_evpn_dup_addr_detect_for_mac(struct zebra_vrf *zvrf,
* Remote MAC event -> hold on installing it.
*/
if (CHECK_FLAG(mac->flags, ZEBRA_MAC_DUPLICATE)) {
- if (IS_ZEBRA_DEBUG_VXLAN)
+ if (IS_ZEBRA_DEBUG_VXLAN) {
+ char mac_buf[MAC_BUF_SIZE];
+
zlog_debug(
- "%s: duplicate addr MAC %s flags 0x%x skip update to client, learn count %u recover time %u",
+ "%s: duplicate addr MAC %s flags %sskip update to client, learn count %u recover time %u",
__func__,
prefix_mac2str(&mac->macaddr, buf, sizeof(buf)),
- mac->flags, mac->dad_count,
- zvrf->dad_freeze_time);
-
+ zebra_evpn_zebra_mac_flag_dump(mac, mac_buf,
+ sizeof(mac_buf)),
+ mac->dad_count, zvrf->dad_freeze_time);
+ }
/* For duplicate MAC do not update
* client but update neigh due to
* this MAC update.
@@ -385,12 +425,17 @@ static void zebra_evpn_dup_addr_detect_for_mac(struct zebra_vrf *zvrf,
}
if (reset_params) {
- if (IS_ZEBRA_DEBUG_VXLAN)
+ if (IS_ZEBRA_DEBUG_VXLAN) {
+ char mac_buf[MAC_BUF_SIZE];
+
zlog_debug(
- "%s: duplicate addr MAC %s flags 0x%x detection time passed, reset learn count %u",
+ "%s: duplicate addr MAC %s flags %sdetection time passed, reset learn count %u",
__func__,
prefix_mac2str(&mac->macaddr, buf, sizeof(buf)),
- mac->flags, mac->dad_count);
+ zebra_evpn_zebra_mac_flag_dump(mac, mac_buf,
+ sizeof(mac_buf)),
+ mac->dad_count);
+ }
mac->dad_count = 0;
/* Start dup. addr detection (DAD) start time,
@@ -452,13 +497,18 @@ static void zebra_evpn_dup_addr_detect_for_mac(struct zebra_vrf *zvrf,
/* Start auto recovery timer for this MAC */
THREAD_OFF(mac->dad_mac_auto_recovery_timer);
if (zvrf->dad_freeze && zvrf->dad_freeze_time) {
- if (IS_ZEBRA_DEBUG_VXLAN)
+ if (IS_ZEBRA_DEBUG_VXLAN) {
+ char mac_buf[MAC_BUF_SIZE];
+
zlog_debug(
- "%s: duplicate addr MAC %s flags 0x%x auto recovery time %u start",
+ "%s: duplicate addr MAC %s flags %sauto recovery time %u start",
__func__,
prefix_mac2str(&mac->macaddr, buf,
sizeof(buf)),
- mac->flags, zvrf->dad_freeze_time);
+ zebra_evpn_zebra_mac_flag_dump(
+ mac, mac_buf, sizeof(mac_buf)),
+ zvrf->dad_freeze_time);
+ }
thread_add_timer(zrouter.master,
zebra_evpn_dad_mac_auto_recovery_exp,
@@ -694,7 +744,7 @@ void zebra_evpn_print_mac(zebra_mac_t *mac, void *ctxt, json_object *json)
}
static char *zebra_evpn_print_mac_flags(zebra_mac_t *mac, char *flags_buf,
- uint32_t flags_buf_sz)
+ size_t flags_buf_sz)
{
snprintf(flags_buf, flags_buf_sz, "%s%s%s%s",
mac->sync_neigh_cnt ?
@@ -903,14 +953,19 @@ int zebra_evpn_macip_send_msg_to_client(vni_t vni, struct ethaddr *macaddr,
/* Write packet size. */
stream_putw_at(s, 0, stream_get_endp(s));
- if (IS_ZEBRA_DEBUG_VXLAN)
+ if (IS_ZEBRA_DEBUG_VXLAN) {
+ char flag_buf[MACIP_BUF_SIZE];
+
zlog_debug(
- "Send MACIP %s f 0x%x MAC %s IP %s seq %u L2-VNI %u ESI %s to %s",
- (cmd == ZEBRA_MACIP_ADD) ? "Add" : "Del", flags,
+ "Send MACIP %s f %s MAC %s IP %s seq %u L2-VNI %u ESI %s to %s",
+ (cmd == ZEBRA_MACIP_ADD) ? "Add" : "Del",
+ zclient_evpn_dump_macip_flags(flags, flag_buf,
+ sizeof(flag_buf)),
prefix_mac2str(macaddr, buf, sizeof(buf)),
ipaddr2str(ip, buf2, sizeof(buf2)), seq, vni,
es ? es->esi_str : "-",
zebra_route_string(client->proto));
+ }
if (cmd == ZEBRA_MACIP_ADD)
client->macipadd_cnt++;
@@ -982,10 +1037,12 @@ zebra_mac_t *zebra_evpn_mac_add(zebra_evpn_t *zevpn, struct ethaddr *macaddr)
mac->uptime = monotime(NULL);
if (IS_ZEBRA_DEBUG_VXLAN || IS_ZEBRA_DEBUG_EVPN_MH_MAC) {
char buf[ETHER_ADDR_STRLEN];
+ char mac_buf[MAC_BUF_SIZE];
- zlog_debug("%s: MAC %s flags 0x%x", __func__,
+ zlog_debug("%s: MAC %s flags %s", __func__,
prefix_mac2str(&mac->macaddr, buf, sizeof(buf)),
- mac->flags);
+ zebra_evpn_zebra_mac_flag_dump(mac, mac_buf,
+ sizeof(mac_buf)));
}
return mac;
}
@@ -999,10 +1056,12 @@ int zebra_evpn_mac_del(zebra_evpn_t *zevpn, zebra_mac_t *mac)
if (IS_ZEBRA_DEBUG_VXLAN || IS_ZEBRA_DEBUG_EVPN_MH_MAC) {
char buf[ETHER_ADDR_STRLEN];
+ char mac_buf[MAC_BUF_SIZE];
- zlog_debug("%s: MAC %s flags 0x%x", __func__,
+ zlog_debug("%s: MAC %s flags %s", __func__,
prefix_mac2str(&mac->macaddr, buf, sizeof(buf)),
- mac->flags);
+ zebra_evpn_zebra_mac_flag_dump(mac, mac_buf,
+ sizeof(mac_buf)));
}
/* If the MAC is freed before the neigh we will end up
@@ -1047,11 +1106,13 @@ static bool zebra_evpn_check_mac_del_from_db(struct mac_walk_ctx *wctx,
&& !listcount(mac->neigh_list)) {
if (IS_ZEBRA_DEBUG_VXLAN) {
char buf[ETHER_ADDR_STRLEN];
+ char mac_buf[MAC_BUF_SIZE];
zlog_debug(
- "%s: Del MAC %s flags 0x%x", __func__,
+ "%s: Del MAC %s flags %s", __func__,
prefix_mac2str(&mac->macaddr, buf, sizeof(buf)),
- mac->flags);
+ zebra_evpn_zebra_mac_flag_dump(
+ mac, mac_buf, sizeof(mac_buf)));
}
wctx->uninstall = 0;
@@ -1204,24 +1265,34 @@ int zebra_evpn_sync_mac_dp_install(zebra_mac_t *mac, bool set_inactive,
zebra_evpn_mac_get_access_info(mac, &ifp, &vid);
if (!ifp) {
- if (IS_ZEBRA_DEBUG_EVPN_MH_MAC)
+ if (IS_ZEBRA_DEBUG_EVPN_MH_MAC) {
+ char mac_buf[MAC_BUF_SIZE];
+
zlog_debug(
- "%s: dp-install sync-mac vni %u mac %pEA es %s 0x%x %sskipped, no access-port",
+ "%s: dp-install sync-mac vni %u mac %pEA es %s %s%sskipped, no access-port",
caller, zevpn->vni, &mac->macaddr,
- mac->es ? mac->es->esi_str : "-", mac->flags,
+ mac->es ? mac->es->esi_str : "-",
+ zebra_evpn_zebra_mac_flag_dump(mac, mac_buf,
+ sizeof(mac_buf)),
set_inactive ? "inactive " : "");
+ }
return -1;
}
zif = ifp->info;
br_ifp = zif->brslave_info.br_if;
if (!br_ifp) {
- if (IS_ZEBRA_DEBUG_EVPN_MH_MAC)
+ if (IS_ZEBRA_DEBUG_EVPN_MH_MAC) {
+ char mac_buf[MAC_BUF_SIZE];
+
zlog_debug(
- "%s: dp-install sync-mac vni %u mac %pEA es %s 0x%x %sskipped, no br",
+ "%s: dp-install sync-mac vni %u mac %pEA es %s %s%sskipped, no br",
caller, zevpn->vni, &mac->macaddr,
- mac->es ? mac->es->esi_str : "-", mac->flags,
+ mac->es ? mac->es->esi_str : "-",
+ zebra_evpn_zebra_mac_flag_dump(mac, mac_buf,
+ sizeof(mac_buf)),
set_inactive ? "inactive " : "");
+ }
return -1;
}
@@ -1236,13 +1307,18 @@ int zebra_evpn_sync_mac_dp_install(zebra_mac_t *mac, bool set_inactive,
* supported and if the local ES is oper-down.
*/
if (mac->es && zebra_evpn_es_local_mac_via_network_port(mac->es)) {
- if (IS_ZEBRA_DEBUG_EVPN_MH_MAC)
+ if (IS_ZEBRA_DEBUG_EVPN_MH_MAC) {
+ char mac_buf[MAC_BUF_SIZE];
+
zlog_debug(
- "dp-%s sync-nw-mac vni %u mac %pEA es %s 0x%x %s",
+ "dp-%s sync-nw-mac vni %u mac %pEA es %s %s%s",
set_static ? "install" : "uninstall",
zevpn->vni, &mac->macaddr,
- mac->es ? mac->es->esi_str : "-", mac->flags,
+ mac->es ? mac->es->esi_str : "-",
+ zebra_evpn_zebra_mac_flag_dump(mac, mac_buf,
+ sizeof(mac_buf)),
set_inactive ? "inactive " : "");
+ }
if (set_static)
/* XXX - old_static needs to be computed more
* accurately
@@ -1256,13 +1332,17 @@ int zebra_evpn_sync_mac_dp_install(zebra_mac_t *mac, bool set_inactive,
return 0;
}
- if (IS_ZEBRA_DEBUG_EVPN_MH_MAC)
- zlog_debug(
- "dp-install sync-mac vni %u mac %pEA es %s 0x%x %s%s",
- zevpn->vni, &mac->macaddr,
- mac->es ? mac->es->esi_str : "-", mac->flags,
- set_static ? "static " : "",
- set_inactive ? "inactive " : "");
+ if (IS_ZEBRA_DEBUG_EVPN_MH_MAC) {
+ char mac_buf[MAC_BUF_SIZE];
+
+ zlog_debug("dp-install sync-mac vni %u mac %pEA es %s %s%s%s",
+ zevpn->vni, &mac->macaddr,
+ mac->es ? mac->es->esi_str : "-",
+ zebra_evpn_zebra_mac_flag_dump(mac, mac_buf,
+ sizeof(mac_buf)),
+ set_static ? "static " : "",
+ set_inactive ? "inactive " : "");
+ }
dplane_local_mac_add(ifp, br_ifp, vid, &mac->macaddr, sticky,
set_static, set_inactive);
@@ -1310,12 +1390,17 @@ static int zebra_evpn_mac_hold_exp_cb(struct thread *t)
new_bgp_ready = zebra_evpn_mac_is_ready_for_bgp(mac->flags);
new_static = zebra_evpn_mac_is_static(mac);
- if (IS_ZEBRA_DEBUG_EVPN_MH_MAC)
+ if (IS_ZEBRA_DEBUG_EVPN_MH_MAC) {
+ char mac_buf[MAC_BUF_SIZE];
+
zlog_debug(
- "sync-mac vni %u mac %s es %s 0x%x hold expired",
+ "sync-mac vni %u mac %s es %s %shold expired",
mac->zevpn->vni,
prefix_mac2str(&mac->macaddr, macbuf, sizeof(macbuf)),
- mac->es ? mac->es->esi_str : "-", mac->flags);
+ mac->es ? mac->es->esi_str : "-",
+ zebra_evpn_zebra_mac_flag_dump(mac, mac_buf,
+ sizeof(mac_buf)));
+ }
/* re-program the local mac in the dataplane if the mac is no
* longer static
@@ -1340,12 +1425,17 @@ static inline void zebra_evpn_mac_start_hold_timer(zebra_mac_t *mac)
if (mac->hold_timer)
return;
- if (IS_ZEBRA_DEBUG_EVPN_MH_MAC)
+ if (IS_ZEBRA_DEBUG_EVPN_MH_MAC) {
+ char mac_buf[MAC_BUF_SIZE];
+
zlog_debug(
- "sync-mac vni %u mac %s es %s 0x%x hold started",
+ "sync-mac vni %u mac %s es %s %shold started",
mac->zevpn->vni,
prefix_mac2str(&mac->macaddr, macbuf, sizeof(macbuf)),
- mac->es ? mac->es->esi_str : "-", mac->flags);
+ mac->es ? mac->es->esi_str : "-",
+ zebra_evpn_zebra_mac_flag_dump(mac, mac_buf,
+ sizeof(mac_buf)));
+ }
thread_add_timer(zrouter.master, zebra_evpn_mac_hold_exp_cb, mac,
zmh_info->mac_hold_time, &mac->hold_timer);
}
@@ -1357,12 +1447,18 @@ void zebra_evpn_mac_stop_hold_timer(zebra_mac_t *mac)
if (!mac->hold_timer)
return;
- if (IS_ZEBRA_DEBUG_EVPN_MH_MAC)
+ if (IS_ZEBRA_DEBUG_EVPN_MH_MAC) {
+ char mac_buf[MAC_BUF_SIZE];
+
zlog_debug(
- "sync-mac vni %u mac %s es %s 0x%x hold stopped",
+ "sync-mac vni %u mac %s es %s %shold stopped",
mac->zevpn->vni,
prefix_mac2str(&mac->macaddr, macbuf, sizeof(macbuf)),
- mac->es ? mac->es->esi_str : "-", mac->flags);
+ mac->es ? mac->es->esi_str : "-",
+ zebra_evpn_zebra_mac_flag_dump(mac, mac_buf,
+ sizeof(mac_buf)));
+ }
+
THREAD_OFF(mac->hold_timer);
}
@@ -1372,13 +1468,18 @@ void zebra_evpn_sync_mac_del(zebra_mac_t *mac)
bool old_static;
bool new_static;
- if (IS_ZEBRA_DEBUG_EVPN_MH_MAC)
+ if (IS_ZEBRA_DEBUG_EVPN_MH_MAC) {
+ char mac_buf[MAC_BUF_SIZE];
+
zlog_debug(
- "sync-mac del vni %u mac %s es %s seq %d f 0x%x",
+ "sync-mac del vni %u mac %s es %s seq %d f %s",
mac->zevpn->vni,
prefix_mac2str(&mac->macaddr, macbuf, sizeof(macbuf)),
mac->es ? mac->es->esi_str : "-", mac->loc_seq,
- mac->flags);
+ zebra_evpn_zebra_mac_flag_dump(mac, mac_buf,
+ sizeof(mac_buf)));
+ }
+
old_static = zebra_evpn_mac_is_static(mac);
UNSET_FLAG(mac->flags, ZEBRA_MAC_ES_PEER_PROXY);
if (CHECK_FLAG(mac->flags, ZEBRA_MAC_ES_PEER_ACTIVE))
@@ -1418,9 +1519,12 @@ static inline bool zebra_evpn_mac_is_bgp_seq_ok(zebra_evpn_t *zevpn,
*/
if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)
&& !zebra_evpn_mac_is_ready_for_bgp(mac->flags)) {
- if (IS_ZEBRA_DEBUG_EVPN_MH_MAC || IS_ZEBRA_DEBUG_VXLAN)
+ if (IS_ZEBRA_DEBUG_EVPN_MH_MAC
+ || IS_ZEBRA_DEBUG_VXLAN) {
+ char mac_buf[MAC_BUF_SIZE];
+
zlog_debug(
- "%s-macip accept vni %u %s-mac %s%s%s lower seq %u f 0x%x",
+ "%s-macip accept vni %u %s-mac %s%s%s lower seq %u f %s",
sync ? "sync" : "rem", zevpn->vni,
n_type,
prefix_mac2str(&mac->macaddr, macbuf,
@@ -1429,13 +1533,19 @@ static inline bool zebra_evpn_mac_is_bgp_seq_ok(zebra_evpn_t *zevpn,
ipa_len ? ipaddr2str(ipaddr, ipbuf,
sizeof(ipbuf))
: "",
- tmp_seq, mac->flags);
+ tmp_seq,
+ zebra_evpn_zebra_mac_flag_dump(
+ mac, mac_buf, sizeof(mac_buf)));
+ }
+
return true;
}
- if (IS_ZEBRA_DEBUG_EVPN_MH_MAC || IS_ZEBRA_DEBUG_VXLAN)
+ if (IS_ZEBRA_DEBUG_EVPN_MH_MAC || IS_ZEBRA_DEBUG_VXLAN) {
+ char mac_buf[MAC_BUF_SIZE];
+
zlog_debug(
- "%s-macip ignore vni %u %s-mac %s%s%s as existing has higher seq %u f 0x%x",
+ "%s-macip ignore vni %u %s-mac %s%s%s as existing has higher seq %u f %s",
sync ? "sync" : "rem", zevpn->vni, n_type,
prefix_mac2str(&mac->macaddr, macbuf,
sizeof(macbuf)),
@@ -1443,7 +1553,10 @@ static inline bool zebra_evpn_mac_is_bgp_seq_ok(zebra_evpn_t *zevpn,
ipa_len ? ipaddr2str(ipaddr, ipbuf,
sizeof(ipbuf))
: "",
- tmp_seq, mac->flags);
+ tmp_seq,
+ zebra_evpn_zebra_mac_flag_dump(
+ mac, mac_buf, sizeof(mac_buf)));
+ }
return false;
}
@@ -1574,12 +1687,20 @@ zebra_evpn_proc_sync_mac_update(zebra_evpn_t *zevpn, struct ethaddr *macaddr,
memset(&mac->fwd_info, 0, sizeof(mac->fwd_info));
mac->flags = new_flags;
- if (IS_ZEBRA_DEBUG_EVPN_MH_MAC && (old_flags != new_flags))
+ if (IS_ZEBRA_DEBUG_EVPN_MH_MAC && (old_flags != new_flags)) {
+ char mac_buf[MAC_BUF_SIZE], omac_buf[MAC_BUF_SIZE];
+ struct zebra_mac_t_ omac;
+
+ omac.flags = old_flags;
zlog_debug(
- "sync-mac vni %u mac %s old_f 0x%x new_f 0x%x",
+ "sync-mac vni %u mac %s old_f %snew_f %s",
zevpn->vni,
prefix_mac2str(macaddr, macbuf, sizeof(macbuf)),
- old_flags, mac->flags);
+ zebra_evpn_zebra_mac_flag_dump(
+ &omac, omac_buf, sizeof(omac_buf)),
+ zebra_evpn_zebra_mac_flag_dump(
+ mac, mac_buf, sizeof(mac_buf)));
+ }
/* update es */
es_change = zebra_evpn_es_mac_ref(mac, esi);
@@ -1613,13 +1734,18 @@ zebra_evpn_proc_sync_mac_update(zebra_evpn_t *zevpn, struct ethaddr *macaddr,
inform_bgp = true;
}
- if (IS_ZEBRA_DEBUG_EVPN_MH_MAC)
- zlog_debug("sync-mac %s vni %u mac %s es %s seq %d f 0x%x%s%s",
+ if (IS_ZEBRA_DEBUG_EVPN_MH_MAC) {
+ char mac_buf[MAC_BUF_SIZE];
+
+ zlog_debug("sync-mac %s vni %u mac %s es %s seq %d f %s%s%s",
ctx->mac_created ? "created" : "updated", zevpn->vni,
prefix_mac2str(macaddr, macbuf, sizeof(macbuf)),
mac->es ? mac->es->esi_str : "-", mac->loc_seq,
- mac->flags, inform_bgp ? " inform_bgp" : "",
+ zebra_evpn_zebra_mac_flag_dump(mac, mac_buf,
+ sizeof(mac_buf)),
+ inform_bgp ? "inform_bgp" : "",
inform_dataplane ? " inform_dp" : "");
+ }
if (inform_bgp)
zebra_evpn_mac_send_add_del_to_client(mac, old_bgp_ready,
@@ -1869,14 +1995,20 @@ int process_mac_remote_macip_add(zebra_evpn_t *zevpn, struct zebra_vrf *zvrf,
if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)) {
/* force drop the sync flags */
old_static = zebra_evpn_mac_is_static(mac);
- if (IS_ZEBRA_DEBUG_EVPN_MH_MAC)
+ if (IS_ZEBRA_DEBUG_EVPN_MH_MAC) {
+ char mac_buf[MAC_BUF_SIZE];
+
zlog_debug(
- "sync-mac->remote vni %u mac %s es %s seq %d f 0x%x",
+ "sync-mac->remote vni %u mac %s es %s seq %d f %s",
zevpn->vni,
prefix_mac2str(macaddr, buf,
sizeof(buf)),
mac->es ? mac->es->esi_str : "-",
- mac->loc_seq, mac->flags);
+ mac->loc_seq,
+ zebra_evpn_zebra_mac_flag_dump(
+ mac, mac_buf, sizeof(mac_buf)));
+ }
+
zebra_evpn_mac_clear_sync_info(mac);
zebra_evpn_mac_send_del_to_client(zevpn->vni, macaddr,
mac->flags,
@@ -1970,14 +2102,18 @@ int zebra_evpn_add_update_local_mac(struct zebra_vrf *zvrf, zebra_evpn_t *zevpn,
SET_FLAG(mac->flags, ZEBRA_MAC_STICKY);
inform_client = true;
} else {
- if (IS_ZEBRA_DEBUG_VXLAN || IS_ZEBRA_DEBUG_EVPN_MH_MAC)
+ if (IS_ZEBRA_DEBUG_VXLAN || IS_ZEBRA_DEBUG_EVPN_MH_MAC) {
+ char mac_buf[MAC_BUF_SIZE];
+
zlog_debug(
- "UPD %sMAC %s intf %s(%u) VID %u -> VNI %u %scurFlags 0x%x",
+ "UPD %sMAC %s intf %s(%u) VID %u -> VNI %u %scurFlags %s",
sticky ? "sticky " : "",
prefix_mac2str(macaddr, buf, sizeof(buf)),
ifp->name, ifp->ifindex, vid, zevpn->vni,
local_inactive ? "local-inactive " : "",
- mac->flags);
+ zebra_evpn_zebra_mac_flag_dump(
+ mac, mac_buf, sizeof(mac_buf)));
+ }
if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)) {
struct interface *old_ifp;
@@ -2125,14 +2261,19 @@ int zebra_evpn_add_update_local_mac(struct zebra_vrf *zvrf, zebra_evpn_t *zevpn,
*/
if ((old_local_inactive != local_inactive)
|| (new_bgp_ready != old_bgp_ready)) {
- if (IS_ZEBRA_DEBUG_EVPN_MH_MAC)
+ if (IS_ZEBRA_DEBUG_EVPN_MH_MAC) {
+ char mac_buf[MAC_BUF_SIZE];
+
zlog_debug(
- "local mac vni %u mac %s es %s seq %d f 0x%x%s",
+ "local mac vni %u mac %s es %s seq %d f %s%s",
zevpn->vni,
prefix_mac2str(macaddr, buf, sizeof(buf)),
mac->es ? mac->es->esi_str : "", mac->loc_seq,
- mac->flags,
- local_inactive ? " local-inactive" : "");
+ zebra_evpn_zebra_mac_flag_dump(mac, mac_buf,
+ sizeof(mac_buf)),
+ local_inactive ? "local-inactive" : "");
+ }
+
if (!is_dup_detect)
inform_client = true;
}
@@ -2177,12 +2318,18 @@ int zebra_evpn_del_local_mac(zebra_evpn_t *zevpn, struct ethaddr *macaddr,
if (!CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL))
return 0;
- if (IS_ZEBRA_DEBUG_VXLAN)
+ if (IS_ZEBRA_DEBUG_VXLAN) {
+ char mac_buf[MAC_BUF_SIZE];
+
zlog_debug(
- "DEL MAC %s intf %s(%u) VID %u -> VNI %u seq %u flags 0x%x nbr count %u",
+ "DEL MAC %s intf %s(%u) VID %u -> VNI %u seq %u flags %snbr count %u",
prefix_mac2str(macaddr, buf, sizeof(buf)), ifp->name,
ifp->ifindex, mac->fwd_info.local.vid, zevpn->vni,
- mac->loc_seq, mac->flags, listcount(mac->neigh_list));
+ mac->loc_seq,
+ zebra_evpn_zebra_mac_flag_dump(mac, mac_buf,
+ sizeof(mac_buf)),
+ listcount(mac->neigh_list));
+ }
old_bgp_ready = zebra_evpn_mac_is_ready_for_bgp(mac->flags);
if (zebra_evpn_mac_is_static(mac)) {
@@ -2191,13 +2338,17 @@ int zebra_evpn_del_local_mac(zebra_evpn_t *zevpn, struct ethaddr *macaddr,
*/
memset(&mac->fwd_info, 0, sizeof(mac->fwd_info));
- if (IS_ZEBRA_DEBUG_EVPN_MH_MAC)
+ if (IS_ZEBRA_DEBUG_EVPN_MH_MAC) {
+ char mac_buf[MAC_BUF_SIZE];
+
zlog_debug(
- "re-add sync-mac vni %u mac %s es %s seq %d f 0x%x",
+ "re-add sync-mac vni %u mac %s es %s seq %d f %s",
zevpn->vni,
prefix_mac2str(macaddr, buf, sizeof(buf)),
mac->es ? mac->es->esi_str : "-", mac->loc_seq,
- mac->flags);
+ zebra_evpn_zebra_mac_flag_dump(
+ mac, mac_buf, sizeof(mac_buf)));
+ }
/* inform-bgp about change in local-activity if any */
if (!CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL_INACTIVE)) {
diff --git a/zebra/zebra_evpn_mac.h b/zebra/zebra_evpn_mac.h
index 1730991f1e..e21b610501 100644
--- a/zebra/zebra_evpn_mac.h
+++ b/zebra/zebra_evpn_mac.h
@@ -56,6 +56,7 @@ struct zebra_mac_t_ {
/* MAC address. */
struct ethaddr macaddr;
+ /* When modifying flags please fixup zebra_evpn_zebra_mac_flag_dump */
uint32_t flags;
#define ZEBRA_MAC_LOCAL 0x01
#define ZEBRA_MAC_REMOTE 0x02
diff --git a/zebra/zebra_fpm.c b/zebra/zebra_fpm.c
index 2bf48c6277..18ccbb79fb 100644
--- a/zebra/zebra_fpm.c
+++ b/zebra/zebra_fpm.c
@@ -273,6 +273,11 @@ struct zfpm_glob {
* If non-zero, the last time when statistics were cleared.
*/
time_t last_stats_clear_time;
+
+ /*
+ * Flag to track the MAC dump status to FPM
+ */
+ bool fpm_mac_dump_done;
};
static struct zfpm_glob zfpm_glob_space;
@@ -517,8 +522,6 @@ static int zfpm_conn_up_thread_cb(struct thread *thread)
struct zfpm_rnodes_iter *iter;
rib_dest_t *dest;
- zfpm_g->t_conn_up = NULL;
-
iter = &zfpm_g->t_conn_up_state.iter;
if (zfpm_g->state != ZFPM_STATE_ESTABLISHED) {
@@ -528,8 +531,13 @@ static int zfpm_conn_up_thread_cb(struct thread *thread)
goto done;
}
- /* Enqueue FPM updates for all the RMAC entries */
- hash_iterate(zrouter.l3vni_table, zfpm_iterate_rmac_table, NULL);
+ if (!zfpm_g->fpm_mac_dump_done) {
+ /* Enqueue FPM updates for all the RMAC entries */
+ hash_iterate(zrouter.l3vni_table, zfpm_iterate_rmac_table,
+ NULL);
+ /* mark dump done so that its not repeated after yield */
+ zfpm_g->fpm_mac_dump_done = true;
+ }
while ((rnode = zfpm_rnodes_iter_next(iter))) {
dest = rib_dest_from_rnode(rnode);
@@ -547,7 +555,6 @@ static int zfpm_conn_up_thread_cb(struct thread *thread)
zfpm_g->stats.t_conn_up_yields++;
zfpm_rnodes_iter_pause(iter);
- zfpm_g->t_conn_up = NULL;
thread_add_timer_msec(zfpm_g->master, zfpm_conn_up_thread_cb,
NULL, 0, &zfpm_g->t_conn_up);
return 0;
@@ -575,12 +582,13 @@ static void zfpm_connection_up(const char *detail)
/*
* Start thread to push existing routes to the FPM.
*/
- assert(!zfpm_g->t_conn_up);
+ thread_cancel(&zfpm_g->t_conn_up);
zfpm_rnodes_iter_init(&zfpm_g->t_conn_up_state.iter);
+ zfpm_g->fpm_mac_dump_done = false;
zfpm_debug("Starting conn_up thread");
- zfpm_g->t_conn_up = NULL;
+
thread_add_timer_msec(zfpm_g->master, zfpm_conn_up_thread_cb, NULL, 0,
&zfpm_g->t_conn_up);
zfpm_g->stats.t_conn_up_starts++;
diff --git a/zebra/zebra_fpm_netlink.c b/zebra/zebra_fpm_netlink.c
index 44f574073c..f7c5da5dec 100644
--- a/zebra/zebra_fpm_netlink.c
+++ b/zebra/zebra_fpm_netlink.c
@@ -133,6 +133,7 @@ struct netlink_nh_info {
* A structure for holding information for a netlink route message.
*/
struct netlink_route_info {
+ uint32_t nlmsg_pid;
uint16_t nlmsg_type;
uint8_t rtm_type;
uint32_t rtm_table;
@@ -244,14 +245,20 @@ static int netlink_route_info_fill(struct netlink_route_info *ri, int cmd,
rib_dest_t *dest, struct route_entry *re)
{
struct nexthop *nexthop;
+ struct rib_table_info *table_info =
+ rib_table_info(rib_dest_table(dest));
+ struct zebra_vrf *zvrf = table_info->zvrf;
memset(ri, 0, sizeof(*ri));
ri->prefix = rib_dest_prefix(dest);
ri->af = rib_dest_af(dest);
+ if (zvrf && zvrf->zns)
+ ri->nlmsg_pid = zvrf->zns->netlink_dplane.snl.nl_pid;
+
ri->nlmsg_type = cmd;
- ri->rtm_table = rib_table_info(rib_dest_table(dest))->table_id;
+ ri->rtm_table = table_info->table_id;
ri->rtm_protocol = RTPROT_UNSPEC;
/*
@@ -357,6 +364,7 @@ static int netlink_route_info_encode(struct netlink_route_info *ri,
req->n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
req->n.nlmsg_flags = NLM_F_CREATE | NLM_F_REQUEST;
+ req->n.nlmsg_pid = ri->nlmsg_pid;
req->n.nlmsg_type = ri->nlmsg_type;
req->r.rtm_family = ri->af;
diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c
index 40b30e0547..7c86735545 100644
--- a/zebra/zebra_rib.c
+++ b/zebra/zebra_rib.c
@@ -38,6 +38,7 @@
#include "workqueue.h"
#include "nexthop_group_private.h"
#include "frr_pthread.h"
+#include "printfrr.h"
#include "zebra/zebra_router.h"
#include "zebra/connected.h"
@@ -148,6 +149,30 @@ _rnode_zlog(const char *_func, vrf_id_t vrf_id, struct route_node *rn,
zlog(priority, "%s: (%u:%u):%s: %s", _func, vrf_id, table, buf, msgbuf);
}
+static char *_dump_re_status(const struct route_entry *re, char *buf,
+ size_t len)
+{
+ if (re->status == 0) {
+ snprintfrr(buf, len, "None ");
+ return buf;
+ }
+
+ snprintfrr(
+ buf, len, "%s%s%s%s%s%s%s",
+ CHECK_FLAG(re->status, ROUTE_ENTRY_REMOVED) ? "Removed " : "",
+ CHECK_FLAG(re->status, ROUTE_ENTRY_CHANGED) ? "Changed " : "",
+ CHECK_FLAG(re->status, ROUTE_ENTRY_LABELS_CHANGED)
+ ? "Label Changed "
+ : "",
+ CHECK_FLAG(re->status, ROUTE_ENTRY_QUEUED) ? "Queued " : "",
+ CHECK_FLAG(re->status, ROUTE_ENTRY_INSTALLED) ? "Installed "
+ : "",
+ CHECK_FLAG(re->status, ROUTE_ENTRY_FAILED) ? "Failed " : "",
+ CHECK_FLAG(re->status, ROUTE_ENTRY_USE_FIB_NHG) ? "Fib NHG "
+ : "");
+ return buf;
+}
+
#define rnode_debug(node, vrf_id, ...) \
_rnode_zlog(__func__, vrf_id, node, LOG_DEBUG, __VA_ARGS__)
#define rnode_info(node, ...) \
@@ -1080,12 +1105,20 @@ static void rib_process(struct route_node *rn)
}
RNODE_FOREACH_RE_SAFE (rn, re, next) {
- if (IS_ZEBRA_DEBUG_RIB_DETAILED)
+ if (IS_ZEBRA_DEBUG_RIB_DETAILED) {
+ char flags_buf[128];
+ char status_buf[128];
+
zlog_debug(
- "%s(%u:%u):%s: Examine re %p (%s) status %x flags %x dist %d metric %d",
+ "%s(%u:%u):%s: Examine re %p (%s) status: %sflags: %sdist %d metric %d",
VRF_LOGNAME(vrf), vrf_id, re->table, buf, re,
- zebra_route_string(re->type), re->status,
- re->flags, re->distance, re->metric);
+ zebra_route_string(re->type),
+ _dump_re_status(re, status_buf,
+ sizeof(status_buf)),
+ zclient_dump_route_flags(re->flags, flags_buf,
+ sizeof(flags_buf)),
+ re->distance, re->metric);
+ }
/* Currently selected re. */
if (CHECK_FLAG(re->flags, ZEBRA_FLAG_SELECTED)) {
@@ -2799,6 +2832,8 @@ void _route_entry_dump(const char *func, union prefixconstptr pp,
bool is_srcdst = src_p && src_p->prefixlen;
char straddr[PREFIX_STRLEN];
char srcaddr[PREFIX_STRLEN];
+ char flags_buf[128];
+ char status_buf[128];
struct nexthop *nexthop;
struct vrf *vrf = vrf_lookup_by_id(re->vrf_id);
struct nexthop_group *nhg;
@@ -2812,9 +2847,12 @@ void _route_entry_dump(const char *func, union prefixconstptr pp,
zlog_debug("%s: uptime == %lu, type == %u, instance == %d, table == %d",
straddr, (unsigned long)re->uptime, re->type, re->instance,
re->table);
- zlog_debug("%s: metric == %u, mtu == %u, distance == %u, flags == %u, status == %u",
- straddr, re->metric, re->mtu, re->distance, re->flags,
- re->status);
+ zlog_debug(
+ "%s: metric == %u, mtu == %u, distance == %u, flags == %sstatus == %s",
+ straddr, re->metric, re->mtu, re->distance,
+ zclient_dump_route_flags(re->flags, flags_buf,
+ sizeof(flags_buf)),
+ _dump_re_status(re, status_buf, sizeof(status_buf)));
zlog_debug("%s: nexthop_num == %u, nexthop_active_num == %u", straddr,
nexthop_group_nexthop_num(&(re->nhe->nhg)),
nexthop_group_active_nexthop_num(&(re->nhe->nhg)));