summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--babeld/babel_main.c5
-rw-r--r--babeld/message.c4
-rw-r--r--bfdd/bfd_packet.c14
-rw-r--r--bfdd/bfdd.c16
-rw-r--r--bgpd/bgp_evpn.c2
-rw-r--r--bgpd/bgp_mpath.c5
-rw-r--r--bgpd/bgp_route.c89
-rw-r--r--bgpd/bgp_routemap.c353
-rw-r--r--bgpd/bgp_rpki.c12
-rw-r--r--bgpd/bgp_updgrp_adv.c2
-rw-r--r--bgpd/bgp_vty.c91
-rw-r--r--bgpd/bgpd.c158
-rw-r--r--bgpd/bgpd.h6
-rw-r--r--bgpd/rfapi/rfapi_import.c5
-rwxr-xr-xconfigure.ac8
-rw-r--r--doc/developer/logging.rst108
-rw-r--r--doc/developer/workflow.rst27
-rw-r--r--doc/user/basic.rst22
-rw-r--r--doc/user/bfd.rst3
-rw-r--r--doc/user/ldpd.rst6
-rw-r--r--doc/user/pim.rst7
-rw-r--r--doc/user/zebra.rst6
-rw-r--r--eigrpd/eigrp_routemap.c54
-rw-r--r--isisd/isis_routemap.c25
-rw-r--r--isisd/isis_tlvs.c5
-rw-r--r--ldpd/ldpd.c11
-rw-r--r--lib/compiler.h10
-rw-r--r--lib/grammar_sandbox_main.c2
-rw-r--r--lib/libfrr.c47
-rw-r--r--lib/libfrr.h8
-rw-r--r--lib/log.c371
-rw-r--r--lib/log.h8
-rw-r--r--lib/module.h10
-rw-r--r--lib/nexthop.c85
-rw-r--r--lib/prefix.c46
-rw-r--r--lib/printf/README9
-rw-r--r--lib/printf/glue.c249
-rw-r--r--lib/printf/printf-pos.c786
-rw-r--r--lib/printf/printfcommon.h244
-rw-r--r--lib/printf/printflocal.h105
-rw-r--r--lib/printf/vfprintf.c730
-rw-r--r--lib/printfrr.h149
-rw-r--r--lib/routemap.c57
-rw-r--r--lib/routemap.h37
-rw-r--r--lib/sigevent.c27
-rw-r--r--lib/srcdest_table.c18
-rw-r--r--lib/srcdest_table.h8
-rw-r--r--lib/subdir.am8
-rw-r--r--lib/vty.c85
-rw-r--r--lib/vty.h6
-rw-r--r--nhrpd/vici.c4
-rw-r--r--ospf6d/ospf6_asbr.c26
-rw-r--r--ospfd/ospf_routemap.c50
-rw-r--r--ospfd/ospf_zebra.c2
-rw-r--r--pimd/pim_cmd.c122
-rw-r--r--pimd/pim_oil.h3
-rw-r--r--ripd/rip_routemap.c51
-rw-r--r--ripngd/ripng_interface.c3
-rw-r--r--ripngd/ripng_routemap.c41
-rw-r--r--tests/.gitignore1
-rw-r--r--tests/helpers/c/main.c2
-rw-r--r--tests/lib/cli/common_cli.c2
-rw-r--r--tests/lib/northbound/test_oper_data.c2
-rw-r--r--tests/lib/test_printfrr.c148
-rw-r--r--tests/lib/test_printfrr.py6
-rw-r--r--tests/subdir.am6
-rw-r--r--tests/topotests/bgp_ipv6_rtadv/__init__.py0
-rw-r--r--tests/topotests/bgp_ipv6_rtadv/r1/bgpd.conf13
-rw-r--r--tests/topotests/bgp_ipv6_rtadv/r1/ipv4_routes.json44
-rw-r--r--tests/topotests/bgp_ipv6_rtadv/r1/ipv6_routes.json39
-rw-r--r--tests/topotests/bgp_ipv6_rtadv/r1/zebra.conf9
-rw-r--r--tests/topotests/bgp_ipv6_rtadv/r2/bgpd.conf16
-rw-r--r--tests/topotests/bgp_ipv6_rtadv/r2/ipv4_routes.json44
-rw-r--r--tests/topotests/bgp_ipv6_rtadv/r2/ipv6_routes.json23
-rw-r--r--tests/topotests/bgp_ipv6_rtadv/r2/zebra.conf9
-rw-r--r--tests/topotests/bgp_ipv6_rtadv/test_bgp_ipv6_rtadv.dot44
-rw-r--r--tests/topotests/bgp_ipv6_rtadv/test_bgp_ipv6_rtadv.py142
-rw-r--r--tests/topotests/bgp_vrf_lite_ipv6_rtadv/__init__.py0
-rw-r--r--tests/topotests/bgp_vrf_lite_ipv6_rtadv/r1/bgpd.conf13
-rw-r--r--tests/topotests/bgp_vrf_lite_ipv6_rtadv/r1/ipv4_routes.json50
-rw-r--r--tests/topotests/bgp_vrf_lite_ipv6_rtadv/r1/ipv6_routes.json44
-rw-r--r--tests/topotests/bgp_vrf_lite_ipv6_rtadv/r1/zebra.conf9
-rw-r--r--tests/topotests/bgp_vrf_lite_ipv6_rtadv/r2/bgpd.conf16
-rw-r--r--tests/topotests/bgp_vrf_lite_ipv6_rtadv/r2/ipv4_routes.json50
-rw-r--r--tests/topotests/bgp_vrf_lite_ipv6_rtadv/r2/ipv6_routes.json26
-rw-r--r--tests/topotests/bgp_vrf_lite_ipv6_rtadv/r2/zebra.conf9
-rw-r--r--tests/topotests/bgp_vrf_lite_ipv6_rtadv/test_bgp_vrf_lite_ipv6_rtadv.dot44
-rw-r--r--tests/topotests/bgp_vrf_lite_ipv6_rtadv/test_bgp_vrf_lite_ipv6_rtadv.py154
-rw-r--r--tests/topotests/lib/topotest.py27
-rw-r--r--tests/topotests/ospf6-topo1/r1/ospf6d.conf-pre-v427
-rw-r--r--tests/topotests/ospf6-topo1/r1/show_ipv6_route.ref18
-rw-r--r--tests/topotests/ospf6-topo1/r1/zebra.conf3
-rw-r--r--tests/topotests/ospf6-topo1/r2/ospf6d.conf-pre-v427
-rw-r--r--tests/topotests/ospf6-topo1/r2/show_ipv6_route.ref18
-rw-r--r--tests/topotests/ospf6-topo1/r2/zebra.conf3
-rw-r--r--tests/topotests/ospf6-topo1/r3/ospf6d.conf-pre-v431
-rw-r--r--tests/topotests/ospf6-topo1/r3/show_ipv6_route.ref18
-rw-r--r--tests/topotests/ospf6-topo1/r3/zebra.conf3
-rw-r--r--tests/topotests/ospf6-topo1/r4/ospf6d.conf-pre-v427
-rw-r--r--tests/topotests/ospf6-topo1/r4/show_ipv6_route.ref18
-rw-r--r--tests/topotests/ospf6-topo1/r4/zebra.conf3
-rwxr-xr-xtests/topotests/ospf6-topo1/test_ospf6_topo1.py384
-rwxr-xr-xtools/frr.in25
-rw-r--r--vtysh/vtysh_main.c2
-rw-r--r--watchfrr/watchfrr.c5
-rw-r--r--zebra/kernel_netlink.c3
-rw-r--r--zebra/redistribute.c4
-rw-r--r--zebra/rib.h13
-rw-r--r--zebra/rtadv.c139
-rw-r--r--zebra/rtadv.h4
-rw-r--r--zebra/zapi_msg.c2
-rw-r--r--zebra/zebra_nhg.c2
-rw-r--r--zebra/zebra_ns.c8
-rw-r--r--zebra/zebra_rib.c19
-rw-r--r--zebra/zebra_rnh.c2
-rw-r--r--zebra/zebra_routemap.c79
-rw-r--r--zebra/zebra_router.c16
-rw-r--r--zebra/zebra_router.h23
-rw-r--r--zebra/zebra_vrf.c9
-rw-r--r--zebra/zebra_vrf.h4
-rw-r--r--zebra/zebra_vxlan.c12
121 files changed, 4811 insertions, 1583 deletions
diff --git a/babeld/babel_main.c b/babeld/babel_main.c
index eaff97a49..a3f2b4e7d 100644
--- a/babeld/babel_main.c
+++ b/babeld/babel_main.c
@@ -68,7 +68,7 @@ const unsigned char ones[16] =
{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
-static const char *state_file = DAEMON_VTY_DIR "/babel-state";
+static char state_file[1024];
unsigned char protocol_group[16]; /* babel's link-local multicast address */
int protocol_port; /* babel's port */
@@ -187,6 +187,9 @@ main(int argc, char **argv)
}
}
+ snprintf(state_file, sizeof(state_file), "%s/%s",
+ frr_vtydir, "babel-state");
+
/* create the threads handler */
master = frr_init ();
diff --git a/babeld/message.c b/babeld/message.c
index 794b6e997..d88790824 100644
--- a/babeld/message.c
+++ b/babeld/message.c
@@ -1115,7 +1115,9 @@ really_send_update(struct interface *ifp,
if(channels_len >= 0) {
accumulate_byte(ifp, 2);
accumulate_byte(ifp, channels_len);
- accumulate_bytes(ifp, channels, channels_len);
+
+ if (channels && channels_len > 0)
+ accumulate_bytes(ifp, channels, channels_len);
}
end_message(ifp, MESSAGE_UPDATE, 10 + (real_plen + 7) / 8 - omit +
channels_size);
diff --git a/bfdd/bfd_packet.c b/bfdd/bfd_packet.c
index f3acfa416..d68a1ad5f 100644
--- a/bfdd/bfd_packet.c
+++ b/bfdd/bfd_packet.c
@@ -435,16 +435,18 @@ ssize_t bfd_recv_ipv6(int sd, uint8_t *msgbuf, size_t msgbuflen, uint8_t *ttl,
#endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */
*ifindex = pi6->ipi6_ifindex;
+
+ /* Set scope ID for link local addresses. */
+ if (IN6_IS_ADDR_LINKLOCAL(
+ &peer->sa_sin6.sin6_addr))
+ peer->sa_sin6.sin6_scope_id = *ifindex;
+ if (IN6_IS_ADDR_LINKLOCAL(
+ &local->sa_sin6.sin6_addr))
+ local->sa_sin6.sin6_scope_id = *ifindex;
}
}
}
- /* Set scope ID for link local addresses. */
- if (IN6_IS_ADDR_LINKLOCAL(&peer->sa_sin6.sin6_addr))
- peer->sa_sin6.sin6_scope_id = *ifindex;
- if (IN6_IS_ADDR_LINKLOCAL(&local->sa_sin6.sin6_addr))
- local->sa_sin6.sin6_scope_id = *ifindex;
-
return mlen;
}
diff --git a/bfdd/bfdd.c b/bfdd/bfdd.c
index 218f0883c..06e01abcf 100644
--- a/bfdd/bfdd.c
+++ b/bfdd/bfdd.c
@@ -20,6 +20,8 @@
#include <zebra.h>
+#include "filter.h"
+
#include "bfd.h"
#include "lib/version.h"
@@ -158,7 +160,8 @@ static void bg_init(void)
int main(int argc, char *argv[])
{
- const char *ctl_path = BFDD_CONTROL_SOCKET;
+ char ctl_path[512];
+ bool ctlsockused = false;
int opt;
/* Initialize system sockets. */
@@ -168,6 +171,8 @@ int main(int argc, char *argv[])
frr_opt_add("", longopts,
" --bfdctl Specify bfdd control socket\n");
+ snprintf(ctl_path, sizeof(ctl_path), BFDD_CONTROL_SOCKET,
+ "", "");
while (true) {
opt = frr_getopt(argc, argv, NULL);
if (opt == EOF)
@@ -175,7 +180,8 @@ int main(int argc, char *argv[])
switch (opt) {
case OPTION_CTLSOCK:
- ctl_path = optarg;
+ strlcpy(ctl_path, optarg, sizeof(ctl_path));
+ ctlsockused = true;
break;
default:
@@ -184,6 +190,10 @@ int main(int argc, char *argv[])
}
}
+ if (bfdd_di.pathspace && !ctlsockused)
+ snprintf(ctl_path, sizeof(ctl_path), BFDD_CONTROL_SOCKET,
+ "/", bfdd_di.pathspace);
+
#if 0 /* TODO add support for JSON configuration files. */
parse_config(conf);
#endif
@@ -202,6 +212,8 @@ int main(int argc, char *argv[])
bfd_vrf_init();
+ access_list_init();
+
/* Initialize zebra connection. */
bfdd_zclient_init(&bglobal.bfdd_privs);
diff --git a/bgpd/bgp_evpn.c b/bgpd/bgp_evpn.c
index a58fca0cc..c4b2a606c 100644
--- a/bgpd/bgp_evpn.c
+++ b/bgpd/bgp_evpn.c
@@ -4411,7 +4411,7 @@ void bgp_evpn_advertise_type5_routes(struct bgp *bgp_vrf, afi_t afi,
/* apply the route-map */
if (bgp_vrf->adv_cmd_rmap[afi][safi].map) {
- route_map_result_t ret;
+ int ret = 0;
ret = route_map_apply(
bgp_vrf->adv_cmd_rmap[afi][safi]
diff --git a/bgpd/bgp_mpath.c b/bgpd/bgp_mpath.c
index d5b3d6b19..648c3be47 100644
--- a/bgpd/bgp_mpath.c
+++ b/bgpd/bgp_mpath.c
@@ -294,6 +294,10 @@ static struct bgp_path_info_mpath *
bgp_path_info_mpath_get(struct bgp_path_info *path)
{
struct bgp_path_info_mpath *mpath;
+
+ if (!path)
+ return NULL;
+
if (!path->mpath) {
mpath = bgp_path_info_mpath_new();
if (!mpath)
@@ -523,6 +527,7 @@ void bgp_path_info_mpath_update(struct bgp_node *rn,
list_delete_node(mp_list, mp_node);
bgp_path_info_mpath_dequeue(cur_mpath);
if ((mpath_count < maxpaths)
+ && prev_mpath
&& bgp_path_info_nexthop_cmp(prev_mpath,
cur_mpath)) {
bgp_path_info_mpath_enqueue(prev_mpath,
diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c
index 543df2b04..4de73f124 100644
--- a/bgpd/bgp_route.c
+++ b/bgpd/bgp_route.c
@@ -1236,12 +1236,10 @@ static int bgp_cluster_filter(struct peer *peer, struct attr *attr)
static int bgp_input_modifier(struct peer *peer, struct prefix *p,
struct attr *attr, afi_t afi, safi_t safi,
- const char *rmap_name, mpls_label_t *label,
- uint32_t num_labels)
+ const char *rmap_name)
{
struct bgp_filter *filter;
- struct bgp_path_info rmap_path = { 0 };
- struct bgp_path_info_extra extra = { 0 };
+ struct bgp_path_info rmap_path;
route_map_result_t ret;
struct route_map *rmap = NULL;
@@ -1271,11 +1269,6 @@ static int bgp_input_modifier(struct peer *peer, struct prefix *p,
/* Duplicate current value to new strucutre for modification. */
rmap_path.peer = peer;
rmap_path.attr = attr;
- rmap_path.extra = &extra;
- extra.num_labels = num_labels;
- if (label && num_labels && num_labels <= BGP_MAX_LABELS)
- memcpy(extra.label, label,
- num_labels * sizeof(mpls_label_t));
SET_FLAG(peer->rmap_type, PEER_RMAP_TYPE_IN);
@@ -1465,7 +1458,7 @@ int subgroup_announce_check(struct bgp_node *rn, struct bgp_path_info *pi,
struct bgp *bgp;
struct attr *piattr;
char buf[PREFIX_STRLEN];
- route_map_result_t ret;
+ int ret;
int transparent;
int reflect;
afi_t afi;
@@ -2533,12 +2526,12 @@ static void bgp_process_main_one(struct bgp *bgp, struct bgp_node *rn,
/* apply the route-map */
if (bgp->adv_cmd_rmap[afi][safi].map) {
- route_map_result_t ret;
+ int ret = 0;
ret = route_map_apply(
bgp->adv_cmd_rmap[afi][safi].map,
&rn->p, RMAP_BGP, new_select);
- if (ret == RMAP_PERMITMATCH)
+ if (ret == RMAP_MATCH)
bgp_evpn_advertise_type5_route(
bgp, &rn->p, new_select->attr,
afi, safi);
@@ -3131,8 +3124,8 @@ int bgp_update(struct peer *peer, struct prefix *p, uint32_t addpath_id,
* commands, so we need bgp_attr_flush in the error paths, until we
* intern
* the attr (which takes over the memory references) */
- if (bgp_input_modifier(peer, p, &new_attr, afi, safi, NULL,
- label, num_labels) == RMAP_DENY) {
+ if (bgp_input_modifier(peer, p, &new_attr, afi, safi, NULL)
+ == RMAP_DENY) {
reason = "route-map;";
bgp_attr_flush(&new_attr);
goto filtered;
@@ -4564,7 +4557,7 @@ void bgp_static_update(struct bgp *bgp, struct prefix *p,
struct bgp_path_info rmap_path;
struct attr attr;
struct attr *attr_new;
- route_map_result_t ret;
+ int ret;
#if ENABLE_BGP_VNC
int vnc_implicit_withdraw = 0;
#endif
@@ -4912,7 +4905,7 @@ static void bgp_static_update_safi(struct bgp *bgp, struct prefix *p,
if (bgp_static->rmap.name) {
struct attr attr_tmp = attr;
struct bgp_path_info rmap_path;
- route_map_result_t ret;
+ int ret;
rmap_path.peer = bgp->peer_self;
rmap_path.attr = &attr_tmp;
@@ -6574,7 +6567,7 @@ void bgp_redistribute_add(struct bgp *bgp, struct prefix *p,
struct attr attr;
struct attr *new_attr;
afi_t afi;
- route_map_result_t ret;
+ int ret;
struct bgp_redist *red;
/* Make default attribute. */
@@ -9089,7 +9082,7 @@ static int bgp_show_table(struct vty *vty, struct bgp *bgp, safi_t safi,
struct route_map *rmap = output_arg;
struct bgp_path_info path;
struct attr dummy_attr;
- route_map_result_t ret;
+ int ret;
bgp_attr_dup(&dummy_attr, pi->attr);
@@ -9549,12 +9542,14 @@ void route_vty_out_detail_header(struct vty *vty, struct bgp *bgp,
vty_out(vty, "Paths: (%d available", count);
if (best) {
vty_out(vty, ", best #%d", best);
- if (safi == SAFI_UNICAST)
- vty_out(vty, ", table %s",
- (bgp->inst_type
- == BGP_INSTANCE_TYPE_DEFAULT)
- ? VRF_DEFAULT_NAME
- : bgp->name);
+ if (safi == SAFI_UNICAST) {
+ if (bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT)
+ vty_out(vty, ", table %s",
+ VRF_DEFAULT_NAME);
+ else
+ vty_out(vty, ", vrf %s",
+ bgp->name);
+ }
} else
vty_out(vty, ", no best path");
@@ -11198,7 +11193,7 @@ static void show_adj_route(struct vty *vty, struct peer *peer, afi_t afi,
/* Filter prefix using route-map */
ret = bgp_input_modifier(peer, &rn->p, &attr,
- afi, safi, rmap_name, NULL, 0);
+ afi, safi, rmap_name);
if (type == bgp_show_adj_route_filtered &&
!route_filtered && ret != RMAP_DENY) {
@@ -12380,30 +12375,9 @@ void bgp_config_write_network(struct vty *vty, struct bgp *bgp, afi_t afi,
p = &rn->p;
- /* "network" configuration display. */
- if (bgp_option_check(BGP_OPT_CONFIG_CISCO) && afi == AFI_IP) {
- uint32_t destination;
- struct in_addr netmask;
-
- destination = ntohl(p->u.prefix4.s_addr);
- masklen2ip(p->prefixlen, &netmask);
- vty_out(vty, " network %s",
- inet_ntop(p->family, &p->u.prefix, buf,
- SU_ADDRSTRLEN));
-
- if ((IN_CLASSC(destination) && p->prefixlen == 24)
- || (IN_CLASSB(destination) && p->prefixlen == 16)
- || (IN_CLASSA(destination) && p->prefixlen == 8)
- || p->u.prefix4.s_addr == 0) {
- /* Natural mask is not display. */
- } else
- vty_out(vty, " mask %s", inet_ntoa(netmask));
- } else {
- vty_out(vty, " network %s/%d",
- inet_ntop(p->family, &p->u.prefix, buf,
- SU_ADDRSTRLEN),
- p->prefixlen);
- }
+ vty_out(vty, " network %s/%d",
+ inet_ntop(p->family, &p->u.prefix, buf, SU_ADDRSTRLEN),
+ p->prefixlen);
if (bgp_static->label_index != BGP_INVALID_LABEL_INDEX)
vty_out(vty, " label-index %u",
@@ -12427,20 +12401,9 @@ void bgp_config_write_network(struct vty *vty, struct bgp *bgp, afi_t afi,
p = &rn->p;
- if (bgp_option_check(BGP_OPT_CONFIG_CISCO) && afi == AFI_IP) {
- struct in_addr netmask;
-
- masklen2ip(p->prefixlen, &netmask);
- vty_out(vty, " aggregate-address %s %s",
- inet_ntop(p->family, &p->u.prefix, buf,
- SU_ADDRSTRLEN),
- inet_ntoa(netmask));
- } else {
- vty_out(vty, " aggregate-address %s/%d",
- inet_ntop(p->family, &p->u.prefix, buf,
- SU_ADDRSTRLEN),
- p->prefixlen);
- }
+ vty_out(vty, " aggregate-address %s/%d",
+ inet_ntop(p->family, &p->u.prefix, buf, SU_ADDRSTRLEN),
+ p->prefixlen);
if (bgp_aggregate->as_set)
vty_out(vty, " as-set");
diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c
index 8c3a02429..28a763ed5 100644
--- a/bgpd/bgp_routemap.c
+++ b/bgpd/bgp_routemap.c
@@ -60,7 +60,6 @@
#include "bgpd/bgp_evpn_private.h"
#include "bgpd/bgp_evpn_vty.h"
#include "bgpd/bgp_mplsvpn.h"
-#include "bgpd/bgp_encap_types.h"
#if ENABLE_BGP_VNC
#include "bgpd/rfapi/bgp_rfapi_cfg.h"
@@ -238,9 +237,10 @@ struct bgp_match_peer_compiled {
/* Compares the peer specified in the 'match peer' clause with the peer
received in bgp_path_info->peer. If it is the same, or if the peer structure
received is a peer_group containing it, returns RMAP_MATCH. */
-static enum route_map_match_result_t
-route_match_peer(void *rule, const struct prefix *prefix,
- route_map_object_t type, void *object)
+static route_map_result_t route_match_peer(void *rule,
+ const struct prefix *prefix,
+ route_map_object_t type,
+ void *object)
{
struct bgp_match_peer_compiled *pc;
union sockunion *su;
@@ -333,9 +333,10 @@ struct route_map_rule_cmd route_match_peer_cmd = {"peer", route_match_peer,
route_match_peer_free};
#if defined(HAVE_LUA)
-static enum route_map_match_result_t
-route_match_command(void *rule, const struct prefix *prefix,
- route_map_object_t type, void *object)
+static route_map_result_t route_match_command(void *rule,
+ const struct prefix *prefix,
+ route_map_object_t type,
+ void *object)
{
int status = RMAP_NOMATCH;
u_int32_t locpref = 0;
@@ -431,9 +432,10 @@ struct route_map_rule_cmd route_match_command_cmd = {
/* Match function should return 1 if match is success else return
zero. */
-static enum route_map_match_result_t
-route_match_ip_address(void *rule, const struct prefix *prefix,
- route_map_object_t type, void *object)
+static route_map_result_t route_match_ip_address(void *rule,
+ const struct prefix *prefix,
+ route_map_object_t type,
+ void *object)
{
struct access_list *alist;
@@ -470,9 +472,10 @@ struct route_map_rule_cmd route_match_ip_address_cmd = {
/* `match ip next-hop IP_ADDRESS' */
/* Match function return 1 if match is success else return zero. */
-static enum route_map_match_result_t
-route_match_ip_next_hop(void *rule, const struct prefix *prefix,
- route_map_object_t type, void *object)
+static route_map_result_t route_match_ip_next_hop(void *rule,
+ const struct prefix *prefix,
+ route_map_object_t type,
+ void *object)
{
struct access_list *alist;
struct bgp_path_info *path;
@@ -516,9 +519,10 @@ struct route_map_rule_cmd route_match_ip_next_hop_cmd = {
/* `match ip route-source ACCESS-LIST' */
/* Match function return 1 if match is success else return zero. */
-static enum route_map_match_result_t
-route_match_ip_route_source(void *rule, const struct prefix *pfx,
- route_map_object_t type, void *object)
+static route_map_result_t route_match_ip_route_source(void *rule,
+ const struct prefix *pfx,
+ route_map_object_t type,
+ void *object)
{
struct access_list *alist;
struct bgp_path_info *path;
@@ -567,7 +571,7 @@ struct route_map_rule_cmd route_match_ip_route_source_cmd = {
/* `match ip address prefix-list PREFIX_LIST' */
-static enum route_map_match_result_t
+static route_map_result_t
route_match_ip_address_prefix_list(void *rule, const struct prefix *prefix,
route_map_object_t type, void *object)
{
@@ -602,7 +606,7 @@ struct route_map_rule_cmd route_match_ip_address_prefix_list_cmd = {
/* `match ip next-hop prefix-list PREFIX_LIST' */
-static enum route_map_match_result_t
+static route_map_result_t
route_match_ip_next_hop_prefix_list(void *rule, const struct prefix *prefix,
route_map_object_t type, void *object)
{
@@ -644,7 +648,7 @@ struct route_map_rule_cmd route_match_ip_next_hop_prefix_list_cmd = {
/* `match ip next-hop type <blackhole>' */
-static enum route_map_match_result_t
+static route_map_result_t
route_match_ip_next_hop_type(void *rule, const struct prefix *prefix,
route_map_object_t type, void *object)
{
@@ -683,7 +687,7 @@ static struct route_map_rule_cmd route_match_ip_next_hop_type_cmd = {
/* `match ip route-source prefix-list PREFIX_LIST' */
-static enum route_map_match_result_t
+static route_map_result_t
route_match_ip_route_source_prefix_list(void *rule,
const struct prefix *prefix,
route_map_object_t type, void *object)
@@ -733,9 +737,10 @@ struct route_map_rule_cmd route_match_ip_route_source_prefix_list_cmd = {
/* `match evpn default-route' */
/* Match function should return 1 if match is success else 0 */
-static enum route_map_match_result_t
-route_match_evpn_default_route(void *rule, const struct prefix *p,
- route_map_object_t type, void *object)
+static route_map_result_t route_match_evpn_default_route(void *rule,
+ const struct prefix *p,
+ route_map_object_t
+ type, void *object)
{
if (type == RMAP_BGP && is_evpn_prefix_default(p))
return RMAP_MATCH;
@@ -751,9 +756,10 @@ struct route_map_rule_cmd route_match_evpn_default_route_cmd = {
/* Match function should return 1 if match is success else return
zero. */
-static enum route_map_match_result_t
-route_match_mac_address(void *rule, const struct prefix *prefix,
- route_map_object_t type, void *object)
+static route_map_result_t route_match_mac_address(void *rule,
+ const struct prefix *prefix,
+ route_map_object_t type,
+ void *object)
{
struct access_list *alist;
struct prefix p;
@@ -796,49 +802,26 @@ struct route_map_rule_cmd route_match_mac_address_cmd = {
"mac address", route_match_mac_address, route_match_mac_address_compile,
route_match_mac_address_free};
-/*
- * Match function returns:
- * ...RMAP_MATCH if match is found.
- * ...RMAP_NOMATCH if match is not found.
- * ...RMAP_NOOP to ignore this match check.
- */
-static enum route_map_match_result_t
-route_match_vni(void *rule, const struct prefix *prefix,
- route_map_object_t type, void *object)
+/* `match vni' */
+
+/* Match function should return 1 if match is success else return
+ zero. */
+static route_map_result_t route_match_vni(void *rule,
+ const struct prefix *prefix,
+ route_map_object_t type, void *object)
{
vni_t vni = 0;
- unsigned int label_cnt = 0;
struct bgp_path_info *path = NULL;
- struct prefix_evpn *evp = (struct prefix_evpn *) prefix;
if (type == RMAP_BGP) {
vni = *((vni_t *)rule);
path = (struct bgp_path_info *)object;
- /*
- * This rmap filter is valid for vxlan tunnel type only.
- * For any other tunnel type, return noop to ignore
- * this check.
- */
- if (path->attr && path->attr->encap_tunneltype !=
- BGP_ENCAP_TYPE_VXLAN)
- return RMAP_NOOP;
-
- /*
- * We do not want to filter type 3 routes because
- * they do not have vni associated with them.
- */
- if (evp && evp->prefix.route_type == BGP_EVPN_IMET_ROUTE)
- return RMAP_NOOP;
-
if (path->extra == NULL)
return RMAP_NOMATCH;
- for ( ; label_cnt < BGP_MAX_LABELS &&
- label_cnt < path->extra->num_labels; label_cnt++) {
- if (vni == label2vni(&path->extra->label[label_cnt]))
- return RMAP_MATCH;
- }
+ if (vni == label2vni(&path->extra->label[0]))
+ return RMAP_MATCH;
}
return RMAP_NOMATCH;
@@ -876,9 +859,10 @@ struct route_map_rule_cmd route_match_evpn_vni_cmd = {
/* Match function should return 1 if match is success else return
zero. */
-static enum route_map_match_result_t
-route_match_evpn_route_type(void *rule, const struct prefix *pfx,
- route_map_object_t type, void *object)
+static route_map_result_t route_match_evpn_route_type(void *rule,
+ const struct prefix *pfx,
+ route_map_object_t type,
+ void *object)
{
uint8_t route_type = 0;
@@ -921,7 +905,7 @@ struct route_map_rule_cmd route_match_evpn_route_type_cmd = {
route_match_evpn_route_type_compile, route_match_evpn_route_type_free};
/* Route map commands for VRF route leak with source vrf matching */
-static enum route_map_match_result_t
+static route_map_result_t
route_match_vrl_source_vrf(void *rule, const struct prefix *prefix,
route_map_object_t type, void *object)
{
@@ -970,9 +954,10 @@ struct route_map_rule_cmd route_match_vrl_source_vrf_cmd = {
/* `match local-preference LOCAL-PREF' */
/* Match function return 1 if match is success else return zero. */
-static enum route_map_match_result_t
-route_match_local_pref(void *rule, const struct prefix *prefix,
- route_map_object_t type, void *object)
+static route_map_result_t route_match_local_pref(void *rule,
+ const struct prefix *prefix,
+ route_map_object_t type,
+ void *object)
{
uint32_t *local_pref;
struct bgp_path_info *path;
@@ -1026,9 +1011,10 @@ struct route_map_rule_cmd route_match_local_pref_cmd = {
/* `match metric METRIC' */
/* Match function return 1 if match is success else return zero. */
-static enum route_map_match_result_t
-route_match_metric(void *rule, const struct prefix *prefix,
- route_map_object_t type, void *object)
+static route_map_result_t route_match_metric(void *rule,
+ const struct prefix *prefix,
+ route_map_object_t type,
+ void *object)
{
struct rmap_value *rv;
struct bgp_path_info *path;
@@ -1049,9 +1035,10 @@ struct route_map_rule_cmd route_match_metric_cmd = {
/* `match as-path ASPATH' */
/* Match function for as-path match. I assume given object is */
-static enum route_map_match_result_t
-route_match_aspath(void *rule, const struct prefix *prefix,
- route_map_object_t type, void *object)
+static route_map_result_t route_match_aspath(void *rule,
+ const struct prefix *prefix,
+ route_map_object_t type,
+ void *object)
{
struct as_list *as_list;
@@ -1098,9 +1085,10 @@ struct rmap_community {
};
/* Match function for community match. */
-static enum route_map_match_result_t
-route_match_community(void *rule, const struct prefix *prefix,
- route_map_object_t type, void *object)
+static route_map_result_t route_match_community(void *rule,
+ const struct prefix *prefix,
+ route_map_object_t type,
+ void *object)
{
struct community_list *list;
struct bgp_path_info *path;
@@ -1167,9 +1155,10 @@ struct route_map_rule_cmd route_match_community_cmd = {
route_match_community_free};
/* Match function for lcommunity match. */
-static enum route_map_match_result_t
-route_match_lcommunity(void *rule, const struct prefix *prefix,
- route_map_object_t type, void *object)
+static route_map_result_t route_match_lcommunity(void *rule,
+ const struct prefix *prefix,
+ route_map_object_t type,
+ void *object)
{
struct community_list *list;
struct bgp_path_info *path;
@@ -1229,9 +1218,10 @@ struct route_map_rule_cmd route_match_lcommunity_cmd = {
/* Match function for extcommunity match. */
-static enum route_map_match_result_t
-route_match_ecommunity(void *rule, const struct prefix *prefix,
- route_map_object_t type, void *object)
+static route_map_result_t route_match_ecommunity(void *rule,
+ const struct prefix *prefix,
+ route_map_object_t type,
+ void *object)
{
struct community_list *list;
struct bgp_path_info *path;
@@ -1282,9 +1272,10 @@ struct route_map_rule_cmd route_match_ecommunity_cmd = {
and `address-family vpnv4'. */
/* `match origin' */
-static enum route_map_match_result_t
-route_match_origin(void *rule, const struct prefix *prefix,
- route_map_object_t type, void *object)
+static route_map_result_t route_match_origin(void *rule,
+ const struct prefix *prefix,
+ route_map_object_t type,
+ void *object)
{
uint8_t *origin;
struct bgp_path_info *path;
@@ -1329,9 +1320,10 @@ struct route_map_rule_cmd route_match_origin_cmd = {
/* match probability { */
-static enum route_map_match_result_t
-route_match_probability(void *rule, const struct prefix *prefix,
- route_map_object_t type, void *object)
+static route_map_result_t route_match_probability(void *rule,
+ const struct prefix *prefix,
+ route_map_object_t type,
+ void *object)
{
long r = random();
@@ -1383,9 +1375,10 @@ struct route_map_rule_cmd route_match_probability_cmd = {
/* `match interface IFNAME' */
/* Match function should return 1 if match is success else return
zero. */
-static enum route_map_match_result_t
-route_match_interface(void *rule, const struct prefix *prefix,
- route_map_object_t type, void *object)
+static route_map_result_t route_match_interface(void *rule,
+ const struct prefix *prefix,
+ route_map_object_t type,
+ void *object)
{
struct interface *ifp;
struct bgp_path_info *path;
@@ -1429,9 +1422,9 @@ struct route_map_rule_cmd route_match_interface_cmd = {
/* `set ip next-hop IP_ADDRESS' */
/* Match function return 1 if match is success else return zero. */
-static enum route_map_match_result_t
-route_match_tag(void *rule, const struct prefix *prefix,
- route_map_object_t type, void *object)
+static route_map_result_t route_match_tag(void *rule,
+ const struct prefix *prefix,
+ route_map_object_t type, void *object)
{
route_tag_t *tag;
struct bgp_path_info *path;
@@ -1461,9 +1454,10 @@ struct rmap_ip_nexthop_set {
int unchanged;
};
-static enum route_map_match_result_t
-route_set_ip_nexthop(void *rule, const struct prefix *prefix,
- route_map_object_t type, void *object)
+static route_map_result_t route_set_ip_nexthop(void *rule,
+ const struct prefix *prefix,
+ route_map_object_t type,
+ void *object)
{
struct rmap_ip_nexthop_set *rins = rule;
struct bgp_path_info *path;
@@ -1566,9 +1560,10 @@ struct route_map_rule_cmd route_set_ip_nexthop_cmd = {
/* `set local-preference LOCAL_PREF' */
/* Set local preference. */
-static enum route_map_match_result_t
-route_set_local_pref(void *rule, const struct prefix *prefix,
- route_map_object_t type, void *object)
+static route_map_result_t route_set_local_pref(void *rule,
+ const struct prefix *prefix,
+ route_map_object_t type,
+ void *object)
{
struct rmap_value *rv;
struct bgp_path_info *path;
@@ -1600,9 +1595,10 @@ struct route_map_rule_cmd route_set_local_pref_cmd = {
/* `set weight WEIGHT' */
/* Set weight. */
-static enum route_map_match_result_t
-route_set_weight(void *rule, const struct prefix *prefix,
- route_map_object_t type, void *object)
+static route_map_result_t route_set_weight(void *rule,
+ const struct prefix *prefix,
+ route_map_object_t type,
+ void *object)
{
struct rmap_value *rv;
struct bgp_path_info *path;
@@ -1627,9 +1623,10 @@ struct route_map_rule_cmd route_set_weight_cmd = {
/* `set metric METRIC' */
/* Set metric to attribute. */
-static enum route_map_match_result_t
-route_set_metric(void *rule, const struct prefix *prefix,
- route_map_object_t type, void *object)
+static route_map_result_t route_set_metric(void *rule,
+ const struct prefix *prefix,
+ route_map_object_t type,
+ void *object)
{
struct rmap_value *rv;
struct bgp_path_info *path;
@@ -1657,9 +1654,10 @@ struct route_map_rule_cmd route_set_metric_cmd = {
/* `set as-path prepend ASPATH' */
/* For AS path prepend mechanism. */
-static enum route_map_match_result_t
-route_set_aspath_prepend(void *rule, const struct prefix *prefix,
- route_map_object_t type, void *object)
+static route_map_result_t route_set_aspath_prepend(void *rule,
+ const struct prefix *prefix,
+ route_map_object_t type,
+ void *object)
{
struct aspath *aspath;
struct aspath *new;
@@ -1719,9 +1717,10 @@ struct route_map_rule_cmd route_set_aspath_prepend_cmd = {
* one.
* Make a deep copy of existing AS_PATH, but for the first ASn only.
*/
-static enum route_map_match_result_t
-route_set_aspath_exclude(void *rule, const struct prefix *dummy,
- route_map_object_t type, void *object)
+static route_map_result_t route_set_aspath_exclude(void *rule,
+ const struct prefix *dummy,
+ route_map_object_t type,
+ void *object)
{
struct aspath *new_path, *exclude_path;
struct bgp_path_info *path;
@@ -1753,9 +1752,10 @@ struct rmap_com_set {
};
/* For community set mechanism. */
-static enum route_map_match_result_t
-route_set_community(void *rule, const struct prefix *prefix,
- route_map_object_t type, void *object)
+static route_map_result_t route_set_community(void *rule,
+ const struct prefix *prefix,
+ route_map_object_t type,
+ void *object)
{
struct rmap_com_set *rcs;
struct bgp_path_info *path;
@@ -1868,9 +1868,10 @@ struct rmap_lcom_set {
/* For lcommunity set mechanism. */
-static enum route_map_match_result_t
-route_set_lcommunity(void *rule, const struct prefix *prefix,
- route_map_object_t type, void *object)
+static route_map_result_t route_set_lcommunity(void *rule,
+ const struct prefix *prefix,
+ route_map_object_t type,
+ void *object)
{
struct rmap_lcom_set *rcs;
struct bgp_path_info *path;
@@ -1980,9 +1981,10 @@ struct route_map_rule_cmd route_set_lcommunity_cmd = {
/* `set large-comm-list (<1-99>|<100-500>|WORD) delete' */
/* For large community set mechanism. */
-static enum route_map_match_result_t
-route_set_lcommunity_delete(void *rule, const struct prefix *pfx,
- route_map_object_t type, void *object)
+static route_map_result_t route_set_lcommunity_delete(void *rule,
+ const struct prefix *pfx,
+ route_map_object_t type,
+ void *object)
{
struct community_list *list;
struct lcommunity *merge;
@@ -2063,9 +2065,11 @@ struct route_map_rule_cmd route_set_lcommunity_delete_cmd = {
/* `set comm-list (<1-99>|<100-500>|WORD) delete' */
/* For community set mechanism. */
-static enum route_map_match_result_t
-route_set_community_delete(void *rule, const struct prefix *prefix,
- route_map_object_t type, void *object)
+static route_map_result_t route_set_community_delete(
+ void *rule,
+ const struct prefix *prefix,
+ route_map_object_t type,
+ void *object)
{
struct community_list *list;
struct community *merge;
@@ -2145,9 +2149,10 @@ struct route_map_rule_cmd route_set_community_delete_cmd = {
/* `set extcommunity rt COMMUNITY' */
/* For community set mechanism. Used by _rt and _soo. */
-static enum route_map_match_result_t
-route_set_ecommunity(void *rule, const struct prefix *prefix,
- route_map_object_t type, void *object)
+static route_map_result_t route_set_ecommunity(void *rule,
+ const struct prefix *prefix,
+ route_map_object_t type,
+ void *object)
{
struct ecommunity *ecom;
struct ecommunity *new_ecom;
@@ -2232,9 +2237,10 @@ struct route_map_rule_cmd route_set_ecommunity_soo_cmd = {
/* `set origin ORIGIN' */
/* For origin set. */
-static enum route_map_match_result_t
-route_set_origin(void *rule, const struct prefix *prefix,
- route_map_object_t type, void *object)
+static route_map_result_t route_set_origin(void *rule,
+ const struct prefix *prefix,
+ route_map_object_t type,
+ void *object)
{
uint8_t *origin;
struct bgp_path_info *path;
@@ -2281,9 +2287,10 @@ struct route_map_rule_cmd route_set_origin_cmd = {
/* `set atomic-aggregate' */
/* For atomic aggregate set. */
-static enum route_map_match_result_t
-route_set_atomic_aggregate(void *rule, const struct prefix *pfx,
- route_map_object_t type, void *object)
+static route_map_result_t route_set_atomic_aggregate(void *rule,
+ const struct prefix *pfx,
+ route_map_object_t type,
+ void *object)
{
struct bgp_path_info *path;
@@ -2319,9 +2326,10 @@ struct aggregator {
struct in_addr address;
};
-static enum route_map_match_result_t
-route_set_aggregator_as(void *rule, const struct prefix *prefix,
- route_map_object_t type, void *object)
+static route_map_result_t route_set_aggregator_as(void *rule,
+ const struct prefix *prefix,
+ route_map_object_t type,
+ void *object)
{
struct bgp_path_info *path;
struct aggregator *aggregator;
@@ -2372,9 +2380,9 @@ struct route_map_rule_cmd route_set_aggregator_as_cmd = {
};
/* Set tag to object. object must be pointer to struct bgp_path_info */
-static enum route_map_match_result_t
-route_set_tag(void *rule, const struct prefix *prefix,
- route_map_object_t type, void *object)
+static route_map_result_t route_set_tag(void *rule,
+ const struct prefix *prefix,
+ route_map_object_t type, void *object)
{
route_tag_t *tag;
struct bgp_path_info *path;
@@ -2397,9 +2405,10 @@ static struct route_map_rule_cmd route_set_tag_cmd = {
};
/* Set label-index to object. object must be pointer to struct bgp_path_info */
-static enum route_map_match_result_t
-route_set_label_index(void *rule, const struct prefix *prefix,
- route_map_object_t type, void *object)
+static route_map_result_t route_set_label_index(void *rule,
+ const struct prefix *prefix,
+ route_map_object_t type,
+ void *object)
{
struct rmap_value *rv;
struct bgp_path_info *path;
@@ -2429,9 +2438,10 @@ static struct route_map_rule_cmd route_set_label_index_cmd = {
/* `match ipv6 address IP_ACCESS_LIST' */
-static enum route_map_match_result_t
-route_match_ipv6_address(void *rule, const struct prefix *prefix,
- route_map_object_t type, void *object)
+static route_map_result_t route_match_ipv6_address(void *rule,
+ const struct prefix *prefix,
+ route_map_object_t type,
+ void *object)
{
struct access_list *alist;
@@ -2464,9 +2474,10 @@ struct route_map_rule_cmd route_match_ipv6_address_cmd = {
/* `match ipv6 next-hop IP_ADDRESS' */
-static enum route_map_match_result_t
-route_match_ipv6_next_hop(void *rule, const struct prefix *prefix,
- route_map_object_t type, void *object)
+static route_map_result_t route_match_ipv6_next_hop(void *rule,
+ const struct prefix *prefix,
+ route_map_object_t type,
+ void *object)
{
struct in6_addr *addr = rule;
struct bgp_path_info *path;
@@ -2515,7 +2526,7 @@ struct route_map_rule_cmd route_match_ipv6_next_hop_cmd = {
/* `match ipv6 address prefix-list PREFIX_LIST' */
-static enum route_map_match_result_t
+static route_map_result_t
route_match_ipv6_address_prefix_list(void *rule, const struct prefix *prefix,
route_map_object_t type, void *object)
{
@@ -2550,9 +2561,9 @@ struct route_map_rule_cmd route_match_ipv6_address_prefix_list_cmd = {
/* `match ipv6 next-hop type <TYPE>' */
-static enum route_map_match_result_t
+static route_map_result_t
route_match_ipv6_next_hop_type(void *rule, const struct prefix *prefix,
- route_map_object_t type, void *object)
+ route_map_object_t type, void *object)
{
struct bgp_path_info *path;
struct in6_addr *addr = rule;
@@ -2598,9 +2609,10 @@ struct route_map_rule_cmd route_match_ipv6_next_hop_type_cmd = {
/* `set ipv6 nexthop global IP_ADDRESS' */
/* Set nexthop to object. ojbect must be pointer to struct attr. */
-static enum route_map_match_result_t
-route_set_ipv6_nexthop_global(void *rule, const struct prefix *p,
- route_map_object_t type, void *object)
+static route_map_result_t route_set_ipv6_nexthop_global(void *rule,
+ const struct prefix *p,
+ route_map_object_t type,
+ void *object)
{
struct in6_addr *address;
struct bgp_path_info *path;
@@ -2656,7 +2668,7 @@ struct route_map_rule_cmd route_set_ipv6_nexthop_global_cmd = {
route_set_ipv6_nexthop_global_free};
/* Set next-hop preference value. */
-static enum route_map_match_result_t
+static route_map_result_t
route_set_ipv6_nexthop_prefer_global(void *rule, const struct prefix *prefix,
route_map_object_t type, void *object)
{
@@ -2710,9 +2722,10 @@ struct route_map_rule_cmd route_set_ipv6_nexthop_prefer_global_cmd = {
/* `set ipv6 nexthop local IP_ADDRESS' */
/* Set nexthop to object. ojbect must be pointer to struct attr. */
-static enum route_map_match_result_t
-route_set_ipv6_nexthop_local(void *rule, const struct prefix *p,
- route_map_object_t type, void *object)
+static route_map_result_t route_set_ipv6_nexthop_local(void *rule,
+ const struct prefix *p,
+ route_map_object_t type,
+ void *object)
{
struct in6_addr *address;
struct bgp_path_info *path;
@@ -2772,9 +2785,10 @@ struct route_map_rule_cmd route_set_ipv6_nexthop_local_cmd = {
/* `set ipv6 nexthop peer-address' */
/* Set nexthop to object. ojbect must be pointer to struct attr. */
-static enum route_map_match_result_t
-route_set_ipv6_nexthop_peer(void *rule, const struct prefix *pfx,
- route_map_object_t type, void *object)
+static route_map_result_t route_set_ipv6_nexthop_peer(void *rule,
+ const struct prefix *pfx,
+ route_map_object_t type,
+ void *object)
{
struct in6_addr peer_address;
struct bgp_path_info *path;
@@ -2849,9 +2863,10 @@ struct route_map_rule_cmd route_set_ipv6_nexthop_peer_cmd = {
/* `set ipv4 vpn next-hop A.B.C.D' */
-static enum route_map_match_result_t
-route_set_vpnv4_nexthop(void *rule, const struct prefix *prefix,
- route_map_object_t type, void *object)
+static route_map_result_t route_set_vpnv4_nexthop(void *rule,
+ const struct prefix *prefix,
+ route_map_object_t type,
+ void *object)
{
struct in_addr *address;
struct bgp_path_info *path;
@@ -2888,9 +2903,10 @@ static void *route_set_vpnv4_nexthop_compile(const char *arg)
/* `set ipv6 vpn next-hop A.B.C.D' */
-static enum route_map_match_result_t
-route_set_vpnv6_nexthop(void *rule, const struct prefix *prefix,
- route_map_object_t type, void *object)
+static route_map_result_t route_set_vpnv6_nexthop(void *rule,
+ const struct prefix *prefix,
+ route_map_object_t type,
+ void *object)
{
struct in6_addr *address;
struct bgp_path_info *path;
@@ -2943,9 +2959,10 @@ struct route_map_rule_cmd route_set_vpnv6_nexthop_cmd = {
/* `set originator-id' */
/* For origin set. */
-static enum route_map_match_result_t
-route_set_originator_id(void *rule, const struct prefix *prefix,
- route_map_object_t type, void *object)
+static route_map_result_t route_set_originator_id(void *rule,
+ const struct prefix *prefix,
+ route_map_object_t type,
+ void *object)
{
struct in_addr *address;
struct bgp_path_info *path;
diff --git a/bgpd/bgp_rpki.c b/bgpd/bgp_rpki.c
index ab93ade56..063772399 100644
--- a/bgpd/bgp_rpki.c
+++ b/bgpd/bgp_rpki.c
@@ -129,10 +129,8 @@ static void print_record(const struct pfx_record *record, struct vty *vty);
static int is_synchronized(void);
static int is_running(void);
static void route_match_free(void *rule);
-static enum route_map_match_result_t route_match(void *rule,
- const struct prefix *prefix,
- route_map_object_t type,
- void *object);
+static route_map_result_t route_match(void *rule, const struct prefix *prefix,
+ route_map_object_t type, void *object);
static void *route_match_compile(const char *arg);
static void revalidate_bgp_node(struct bgp_node *bgp_node, afi_t afi,
safi_t safi);
@@ -215,10 +213,8 @@ static void ipv6_addr_to_host_byte_order(const uint32_t *src, uint32_t *dest)
dest[i] = ntohl(src[i]);
}
-static enum route_map_match_result_t route_match(void *rule,
- const struct prefix *prefix,
- route_map_object_t type,
- void *object)
+static route_map_result_t route_match(void *rule, const struct prefix *prefix,
+ route_map_object_t type, void *object)
{
int *rpki_status = rule;
struct bgp_path_info *path;
diff --git a/bgpd/bgp_updgrp_adv.c b/bgpd/bgp_updgrp_adv.c
index 21f1dff60..b64c51f34 100644
--- a/bgpd/bgp_updgrp_adv.c
+++ b/bgpd/bgp_updgrp_adv.c
@@ -716,7 +716,7 @@ void subgroup_default_originate(struct update_subgroup *subgrp, int withdraw)
struct bgp_node *rn;
struct bgp_path_info *ri;
struct peer *peer;
- route_map_result_t ret = RMAP_DENYMATCH;
+ int ret = RMAP_DENYMATCH;
afi_t afi;
safi_t safi;
diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c
index 6451c8d8e..7dc3f02b0 100644
--- a/bgpd/bgp_vty.c
+++ b/bgpd/bgp_vty.c
@@ -815,41 +815,6 @@ static void bgp_clear_star_soft_out(struct vty *vty, const char *name)
#include "bgpd/bgp_vty_clippy.c"
#endif
-/* BGP global configuration. */
-#if (CONFDATE > 20190601)
-CPP_NOTICE("bgpd: time to remove deprecated bgp multiple-instance")
-CPP_NOTICE("This includes BGP_OPT_MULTIPLE_INSTANCE")
-#endif
-DEFUN_HIDDEN (bgp_multiple_instance_func,
- bgp_multiple_instance_cmd,
- "bgp multiple-instance",
- BGP_STR
- "Enable bgp multiple instance\n")
-{
- bgp_option_set(BGP_OPT_MULTIPLE_INSTANCE);
- return CMD_SUCCESS;
-}
-
-DEFUN_HIDDEN (no_bgp_multiple_instance,
- no_bgp_multiple_instance_cmd,
- "no bgp multiple-instance",
- NO_STR
- BGP_STR
- "BGP multiple instance\n")
-{
- int ret;
-
- vty_out(vty, "This config option is deprecated, and is scheduled for removal.\n");
- vty_out(vty, "if you are using this please let the developers know\n");
- zlog_info("Deprecated option: `bgp multiple-instance` being used");
- ret = bgp_option_unset(BGP_OPT_MULTIPLE_INSTANCE);
- if (ret < 0) {
- vty_out(vty, "%% There are more than two BGP instances\n");
- return CMD_WARNING_CONFIG_FAILED;
- }
- return CMD_SUCCESS;
-}
-
DEFUN_HIDDEN (bgp_local_mac,
bgp_local_mac_cmd,
"bgp local-mac vni " CMD_VNI_RANGE " mac WORD seq (0-4294967295)",
@@ -931,44 +896,6 @@ DEFUN_HIDDEN (no_bgp_local_mac,
return CMD_SUCCESS;
}
-#if (CONFDATE > 20190601)
-CPP_NOTICE("bgpd: time to remove deprecated cli bgp config-type cisco")
-CPP_NOTICE("This includes BGP_OPT_CISCO_CONFIG")
-#endif
-DEFUN_HIDDEN (bgp_config_type,
- bgp_config_type_cmd,
- "bgp config-type <cisco|zebra>",
- BGP_STR
- "Configuration type\n"
- "cisco\n"
- "zebra\n")
-{
- int idx = 0;
- if (argv_find(argv, argc, "cisco", &idx)) {
- vty_out(vty, "This config option is deprecated, and is scheduled for removal.\n");
- vty_out(vty, "if you are using this please let the developers know!\n");
- zlog_info("Deprecated option: `bgp config-type cisco` being used");
- bgp_option_set(BGP_OPT_CONFIG_CISCO);
- } else
- bgp_option_unset(BGP_OPT_CONFIG_CISCO);
-
- return CMD_SUCCESS;
-}
-
-DEFUN_HIDDEN (no_bgp_config_type,
- no_bgp_config_type_cmd,
- "no bgp config-type [<cisco|zebra>]",
- NO_STR
- BGP_STR
- "Display configuration type\n"
- "cisco\n"
- "zebra\n")
-{
- bgp_option_unset(BGP_OPT_CONFIG_CISCO);
- return CMD_SUCCESS;
-}
-
-
DEFUN (no_synchronization,
no_synchronization_cmd,
"no synchronization",
@@ -7481,11 +7408,6 @@ DEFUN (show_bgp_views,
struct listnode *node;
struct bgp *bgp;
- if (!bgp_option_check(BGP_OPT_MULTIPLE_INSTANCE)) {
- vty_out(vty, "BGP Multiple Instance is not enabled\n");
- return CMD_WARNING;
- }
-
vty_out(vty, "Defined BGP views:\n");
for (ALL_LIST_ELEMENTS_RO(inst, node, bgp)) {
/* Skip VRFs. */
@@ -7516,11 +7438,6 @@ DEFUN (show_bgp_vrfs,
json_object *json_vrfs = NULL;
int count = 0;
- if (!bgp_option_check(BGP_OPT_MULTIPLE_INSTANCE)) {
- vty_out(vty, "BGP Multiple Instance is not enabled\n");
- return CMD_WARNING;
- }
-
if (uj) {
json = json_object_new_object();
json_vrfs = json_object_new_object();
@@ -12896,14 +12813,6 @@ void bgp_vty_init(void)
install_default(BGP_EVPN_NODE);
install_default(BGP_EVPN_VNI_NODE);
- /* "bgp multiple-instance" commands. */
- install_element(CONFIG_NODE, &bgp_multiple_instance_cmd);
- install_element(CONFIG_NODE, &no_bgp_multiple_instance_cmd);
-
- /* "bgp config-type" commands. */
- install_element(CONFIG_NODE, &bgp_config_type_cmd);
- install_element(CONFIG_NODE, &no_bgp_config_type_cmd);
-
/* "bgp local-mac" hidden commands. */
install_element(CONFIG_NODE, &bgp_local_mac_cmd);
install_element(CONFIG_NODE, &no_bgp_local_mac_cmd);
diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c
index 2e648af1b..02eda7a43 100644
--- a/bgpd/bgpd.c
+++ b/bgpd/bgpd.c
@@ -171,8 +171,6 @@ int bgp_option_set(int flag)
{
switch (flag) {
case BGP_OPT_NO_FIB:
- case BGP_OPT_MULTIPLE_INSTANCE:
- case BGP_OPT_CONFIG_CISCO:
case BGP_OPT_NO_LISTEN:
case BGP_OPT_NO_ZEBRA:
SET_FLAG(bm->options, flag);
@@ -186,13 +184,9 @@ int bgp_option_set(int flag)
int bgp_option_unset(int flag)
{
switch (flag) {
- case BGP_OPT_MULTIPLE_INSTANCE:
- if (listcount(bm->bgp) > 1)
- return BGP_ERR_MULTIPLE_INSTANCE_USED;
/* Fall through. */
case BGP_OPT_NO_ZEBRA:
case BGP_OPT_NO_FIB:
- case BGP_OPT_CONFIG_CISCO:
UNSET_FLAG(bm->options, flag);
break;
default:
@@ -1205,21 +1199,18 @@ struct peer *peer_new(struct bgp *bgp)
/* Set default flags. */
FOREACH_AFI_SAFI (afi, safi) {
- if (!bgp_option_check(BGP_OPT_CONFIG_CISCO)) {
- SET_FLAG(peer->af_flags[afi][safi],
- PEER_FLAG_SEND_COMMUNITY);
- SET_FLAG(peer->af_flags[afi][safi],
- PEER_FLAG_SEND_EXT_COMMUNITY);
- SET_FLAG(peer->af_flags[afi][safi],
- PEER_FLAG_SEND_LARGE_COMMUNITY);
-
- SET_FLAG(peer->af_flags_invert[afi][safi],
- PEER_FLAG_SEND_COMMUNITY);
- SET_FLAG(peer->af_flags_invert[afi][safi],
- PEER_FLAG_SEND_EXT_COMMUNITY);
- SET_FLAG(peer->af_flags_invert[afi][safi],
- PEER_FLAG_SEND_LARGE_COMMUNITY);
- }
+ SET_FLAG(peer->af_flags[afi][safi], PEER_FLAG_SEND_COMMUNITY);
+ SET_FLAG(peer->af_flags[afi][safi],
+ PEER_FLAG_SEND_EXT_COMMUNITY);
+ SET_FLAG(peer->af_flags[afi][safi],
+ PEER_FLAG_SEND_LARGE_COMMUNITY);
+
+ SET_FLAG(peer->af_flags_invert[afi][safi],
+ PEER_FLAG_SEND_COMMUNITY);
+ SET_FLAG(peer->af_flags_invert[afi][safi],
+ PEER_FLAG_SEND_EXT_COMMUNITY);
+ SET_FLAG(peer->af_flags_invert[afi][safi],
+ PEER_FLAG_SEND_LARGE_COMMUNITY);
peer->addpath_type[afi][safi] = BGP_ADDPATH_NONE;
}
@@ -3174,40 +3165,21 @@ int bgp_get(struct bgp **bgp_val, as_t *as, const char *name,
struct vrf *vrf = NULL;
/* Multiple instance check. */
- if (bgp_option_check(BGP_OPT_MULTIPLE_INSTANCE)) {
- if (name)
- bgp = bgp_lookup_by_name(name);
- else
- bgp = bgp_get_default();
-
- /* Already exists. */
- if (bgp) {
- if (bgp->as != *as) {
- *as = bgp->as;
- return BGP_ERR_INSTANCE_MISMATCH;
- }
- if (bgp->inst_type != inst_type)
- return BGP_ERR_INSTANCE_MISMATCH;
- *bgp_val = bgp;
- return 0;
- }
- } else {
- /* BGP instance name can not be specified for single instance.
- */
- if (name)
- return BGP_ERR_MULTIPLE_INSTANCE_NOT_SET;
-
- /* Get default BGP structure if exists. */
+ if (name)
+ bgp = bgp_lookup_by_name(name);
+ else
bgp = bgp_get_default();
- if (bgp) {
- if (bgp->as != *as) {
- *as = bgp->as;
- return BGP_ERR_AS_MISMATCH;
- }
- *bgp_val = bgp;
- return 0;
+ /* Already exists. */
+ if (bgp) {
+ if (bgp->as != *as) {
+ *as = bgp->as;
+ return BGP_ERR_INSTANCE_MISMATCH;
}
+ if (bgp->inst_type != inst_type)
+ return BGP_ERR_INSTANCE_MISMATCH;
+ *bgp_val = bgp;
+ return 0;
}
bgp = bgp_create(as, name, inst_type);
@@ -7319,45 +7291,19 @@ static void bgp_config_write_peer_af(struct vty *vty, struct bgp *bgp,
flag_slcomm = peergroup_af_flag_check(peer, afi, safi,
PEER_FLAG_SEND_LARGE_COMMUNITY);
- if (!bgp_option_check(BGP_OPT_CONFIG_CISCO)) {
- if (flag_scomm && flag_secomm && flag_slcomm) {
- vty_out(vty, " no neighbor %s send-community all\n",
- addr);
- } else {
- if (flag_scomm)
- vty_out(vty,
- " no neighbor %s send-community\n",
- addr);
- if (flag_secomm)
- vty_out(vty,
- " no neighbor %s send-community extended\n",
- addr);
-
- if (flag_slcomm)
- vty_out(vty,
- " no neighbor %s send-community large\n",
- addr);
- }
+ if (flag_scomm && flag_secomm && flag_slcomm) {
+ vty_out(vty, " no neighbor %s send-community all\n", addr);
} else {
- if (flag_scomm && flag_secomm && flag_slcomm) {
- vty_out(vty, " neighbor %s send-community all\n",
+ if (flag_scomm)
+ vty_out(vty, " no neighbor %s send-community\n", addr);
+ if (flag_secomm)
+ vty_out(vty,
+ " no neighbor %s send-community extended\n",
addr);
- } else if (flag_scomm && flag_secomm) {
- vty_out(vty, " neighbor %s send-community both\n",
+
+ if (flag_slcomm)
+ vty_out(vty, " no neighbor %s send-community large\n",
addr);
- } else {
- if (flag_scomm)
- vty_out(vty, " neighbor %s send-community\n",
- addr);
- if (flag_secomm)
- vty_out(vty,
- " neighbor %s send-community extended\n",
- addr);
- if (flag_slcomm)
- vty_out(vty,
- " neighbor %s send-community large\n",
- addr);
- }
}
/* Default information */
@@ -7568,18 +7514,6 @@ int bgp_config_write(struct vty *vty)
struct listnode *node, *nnode;
struct listnode *mnode, *mnnode;
- /* BGP Multiple instance. */
- if (!bgp_option_check(BGP_OPT_MULTIPLE_INSTANCE)) {
- vty_out(vty, "no bgp multiple-instance\n");
- write++;
- }
-
- /* BGP Config type. */
- if (bgp_option_check(BGP_OPT_CONFIG_CISCO)) {
- vty_out(vty, "bgp config-type cisco\n");
- write++;
- }
-
if (bm->rmap_update_timer != RMAP_DEFAULT_UPDATE_TIMER)
vty_out(vty, "bgp route-map delay-timer %u\n",
bm->rmap_update_timer);
@@ -7597,21 +7531,12 @@ int bgp_config_write(struct vty *vty)
/* Router bgp ASN */
vty_out(vty, "router bgp %u", bgp->as);
- if (bgp_option_check(BGP_OPT_MULTIPLE_INSTANCE)) {
- if (bgp->name)
- vty_out(vty, " %s %s",
- (bgp->inst_type
- == BGP_INSTANCE_TYPE_VIEW)
- ? "view"
- : "vrf",
- bgp->name);
- }
+ if (bgp->name)
+ vty_out(vty, " %s %s",
+ (bgp->inst_type == BGP_INSTANCE_TYPE_VIEW)
+ ? "view" : "vrf", bgp->name);
vty_out(vty, "\n");
- /* No Synchronization */
- if (bgp_option_check(BGP_OPT_CONFIG_CISCO))
- vty_out(vty, " no synchronization\n");
-
/* BGP fast-external-failover. */
if (CHECK_FLAG(bgp->flags, BGP_FLAG_NO_FAST_EXT_FAILOVER))
vty_out(vty, " no bgp fast-external-failover\n");
@@ -7825,10 +7750,6 @@ int bgp_config_write(struct vty *vty)
if (bgp->autoshutdown)
vty_out(vty, " bgp default shutdown\n");
- /* No auto-summary */
- if (bgp_option_check(BGP_OPT_CONFIG_CISCO))
- vty_out(vty, " no auto-summary\n");
-
/* IPv4 unicast configuration. */
bgp_config_write_family(vty, bgp, AFI_IP, SAFI_UNICAST);
@@ -7904,9 +7825,6 @@ void bgp_master_init(struct thread_master *master)
bf_init(bm->rd_idspace, UINT16_MAX);
bf_assign_zero_index(bm->rd_idspace);
- /* Enable multiple instances by default. */
- bgp_option_set(BGP_OPT_MULTIPLE_INSTANCE);
-
/* mpls label dynamic allocation pool */
bgp_lp_init(bm->master, &bm->labelpool);
diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h
index c600d9f3f..518f1f671 100644
--- a/bgpd/bgpd.h
+++ b/bgpd/bgpd.h
@@ -134,10 +134,8 @@ struct bgp_master {
/* Various BGP global configuration. */
uint8_t options;
#define BGP_OPT_NO_FIB (1 << 0)
-#define BGP_OPT_MULTIPLE_INSTANCE (1 << 1)
-#define BGP_OPT_CONFIG_CISCO (1 << 2)
-#define BGP_OPT_NO_LISTEN (1 << 3)
-#define BGP_OPT_NO_ZEBRA (1 << 4)
+#define BGP_OPT_NO_LISTEN (1 << 1)
+#define BGP_OPT_NO_ZEBRA (1 << 2)
uint64_t updgrp_idspace;
uint64_t subgrp_idspace;
diff --git a/bgpd/rfapi/rfapi_import.c b/bgpd/rfapi/rfapi_import.c
index b6d32d36e..583adcda7 100644
--- a/bgpd/rfapi/rfapi_import.c
+++ b/bgpd/rfapi/rfapi_import.c
@@ -1143,6 +1143,9 @@ static int rfapiVpnBiSamePtUn(struct bgp_path_info *bpi1,
break;
}
+ memset(&pfx_un1, 0, sizeof(pfx_un1));
+ memset(&pfx_un2, 0, sizeof(pfx_un2));
+
/*
* UN address comparisons
*/
@@ -1184,7 +1187,7 @@ static int rfapiVpnBiSamePtUn(struct bgp_path_info *bpi1,
}
}
- if (!pfx_un1.family || !pfx_un2.family)
+ if (pfx_un1.family == 0 || pfx_un2.family == 0)
return 0;
if (pfx_un1.family != pfx_un2.family)
diff --git a/configure.ac b/configure.ac
index 906006a97..77d5ee155 100755
--- a/configure.ac
+++ b/configure.ac
@@ -2133,10 +2133,10 @@ fi
AC_MSG_RESULT([${frr_statedir}])
AC_SUBST([frr_statedir])
-AC_DEFINE_UNQUOTED([LDPD_SOCKET], ["$frr_statedir/ldpd.sock"], [ldpd control socket])
-AC_DEFINE_UNQUOTED([ZEBRA_SERV_PATH], ["$frr_statedir/zserv.api"], [zebra api socket])
-AC_DEFINE_UNQUOTED([BFDD_CONTROL_SOCKET], ["$frr_statedir/bfdd.sock"], [bfdd control socket])
-AC_DEFINE_UNQUOTED([DAEMON_VTY_DIR], ["$frr_statedir"], [daemon vty directory])
+AC_DEFINE_UNQUOTED([LDPD_SOCKET], ["$frr_statedir%s%s/ldpd.sock"], [ldpd control socket])
+AC_DEFINE_UNQUOTED([ZEBRA_SERV_PATH], ["$frr_statedir%s%s/zserv.api"], [zebra api socket])
+AC_DEFINE_UNQUOTED([BFDD_CONTROL_SOCKET], ["$frr_statedir%s%s/bfdd.sock"], [bfdd control socket])
+AC_DEFINE_UNQUOTED([DAEMON_VTY_DIR], ["$frr_statedir%s%s"], [daemon vty directory])
AC_DEFINE_UNQUOTED([DAEMON_DB_DIR], ["$frr_statedir"], [daemon database directory])
dnl autoconf does this, but it does it too late...
diff --git a/doc/developer/logging.rst b/doc/developer/logging.rst
index 1dc188515..e393fe6fb 100644
--- a/doc/developer/logging.rst
+++ b/doc/developer/logging.rst
@@ -6,6 +6,114 @@ to log, what level to log it at, and when to log it. Here is a list of
recommendations for these decisions.
+printfrr()
+----------
+
+``printfrr()`` is FRR's modified version of ``printf()``, designed to make
+life easier when printing nontrivial datastructures. The following variants
+are available:
+
+.. c:function:: ssize_t snprintfrr(char *buf, size_t len, const char *fmt, ...)
+.. c:function:: ssize_t vsnprintfrr(char *buf, size_t len, const char *fmt, va_list)
+
+ These correspond to ``snprintf``/``vsnprintf``. If you pass NULL for buf
+ or 0 for len, no output is written but the return value is still calculated.
+
+ The return value is always the full length of the output, unconstrained by
+ `len`. It does **not** include the terminating ``\0`` character. A
+ malformed format string can result in a ``-1`` return value.
+
+.. c:function:: ssize_t csnprintfrr(char *buf, size_t len, const char *fmt, ...)
+.. c:function:: ssize_t vcsnprintfrr(char *buf, size_t len, const char *fmt, va_list)
+
+ Same as above, but the ``c`` stands for "continue" or "concatenate". The
+ output is appended to the string instead of overwriting it.
+
+.. c:function:: char *asprintfrr(struct memtype *mt, const char *fmt, ...)
+.. c:function:: char *vasprintfrr(struct memtype *mt, const char *fmt, va_list)
+
+ These functions allocate a dynamic buffer (using MTYPE `mt`) and print to
+ that. If the format string is malformed, they return a copy of the format
+ string, so the return value is always non-NULL and always dynamically
+ allocated with `mt`.
+
+.. c:function:: char *asnprintfrr(struct memtype *mt, char *buf, size_t len, const char *fmt, ...)
+.. c:function:: char *vasnprintfrr(struct memtype *mt, char *buf, size_t len, const char *fmt, va_list)
+
+ This variant tries to use the static buffer provided, but falls back to
+ dynamic allocation if it is insufficient.
+
+ The return value can be either `buf` or a newly allocated string using
+ `mt`. You MUST free it like this::
+
+ char *ret = asnprintfrr(MTYPE_FOO, buf, sizeof(buf), ...);
+ if (ret != buf)
+ XFREE(MTYPE_FOO, ret);
+
+Extensions
+^^^^^^^^^^
+
+``printfrr()`` format strings can be extended with suffixes after `%p` or
+`%d`. The following extended format specifiers are available:
+
++-----------+--------------------------+----------------------------------------------+
+| Specifier | Argument | Output |
++===========+==========================+==============================================+
+| ``%Lu`` | ``uint64_t`` | ``12345`` |
++-----------+--------------------------+----------------------------------------------+
+| ``%Ld`` | ``int64_t`` | ``-12345`` |
++-----------+--------------------------+----------------------------------------------+
+| ``%pI4`` | ``struct in_addr *`` | ``1.2.3.4`` |
+| | | |
+| | ``in_addr_t *`` | |
++-----------+--------------------------+----------------------------------------------+
+| ``%pI6`` | ``struct in6_addr *`` | ``fe80::1234`` |
++-----------+--------------------------+----------------------------------------------+
+| ``%pFX`` | ``struct prefix *`` | ``fe80::1234/64`` |
++-----------+--------------------------+----------------------------------------------+
+| ``%pSG4`` | ``struct prefix_sg *`` | ``(*,1.2.3.4)`` |
++-----------+--------------------------+----------------------------------------------+
+| ``%pRN`` | ``struct route_node *`` | ``192.168.1.0/24`` (dst-only node) |
+| | | |
+| | | ``2001:db8::/32 from fe80::/64`` (SADR node) |
++-----------+--------------------------+----------------------------------------------+
+| ``%pNHv`` | ``struct nexthop *`` | ``1.2.3.4, via eth0`` |
++-----------+--------------------------+----------------------------------------------+
+| ``%pNHs`` | ``struct nexthop *`` | ``1.2.3.4 if 15`` |
++-----------+--------------------------+----------------------------------------------+
+
+Printf features like field lengths can be used normally with these extensions,
+e.g. ``%-15pI4`` works correctly.
+
+The extension specifier after ``%p`` or ``%d`` is always an uppercase letter;
+by means of established pattern uppercase letters and numbers form the type
+identifier which may be followed by lowercase flags.
+
+You can grep the FRR source for ``printfrr_ext_autoreg`` to see all extended
+printers and what exactly they do. More printers are likely to be added as
+needed/useful, so the list above may become outdated.
+
+``%Ld`` is not an "extension" for printfrr; it's wired directly into the main
+printf logic.
+
+.. note::
+
+ The ``zlog_*``/``flog_*`` and ``vty_out`` functions all use printfrr
+ internally, so these extensions are available there. However, they are
+ **not** available when calling ``snprintf`` directly. You need to call
+ ``snprintfrr`` instead.
+
+AS-Safety
+^^^^^^^^^
+
+``printfrr()`` are AS-Safe under the following conditions:
+
+* the ``[v]as[n]printfrr`` variants are not AS-Safe (allocating memory)
+* floating point specifiers are not AS-Safe (system printf is used for these)
+* the positional ``%1$d`` syntax should not be used (8 arguments are supported
+ while AS-Safe)
+* extensions are only AS-Safe if their printer is AS-Safe
+
Errors and warnings
-------------------
diff --git a/doc/developer/workflow.rst b/doc/developer/workflow.rst
index 16707c0bd..07c43ac2d 100644
--- a/doc/developer/workflow.rst
+++ b/doc/developer/workflow.rst
@@ -73,14 +73,20 @@ Releases
FRR employs a ``<MAJOR>.<MINOR>.<BUGFIX>`` versioning scheme.
``MAJOR``
- Significant new features or multiple minor features. The addition of a new
- routing protocol or daemon would fall under this class.
+ Significant new features or multiple minor features. This should mostly
+ cover any kind of disruptive change that is visible or "risky" to operators.
+ New features or protocols do not necessarily trigger this. (This was changed
+ for FRR 7.x after feedback from users that the pace of major version number
+ increments was too high.)
``MINOR``
- Small features, e.g. options for automatic BGP shutdown.
+ General incremental development releases, excluding "major" changes
+ mentioned above. Not necessarily fully backwards compatible, as smaller
+ (but still visible) changes or deprecated feature removals may still happen.
+ However, there shouldn't be any huge "surprises" between minor releases.
``BUGFIX``
- Fixes for actual bugs and/or security issues.
+ Fixes for actual bugs and/or security issues. Fully compatible.
We will pull a new development branch for the next release every 4 months. The
current schedule is Feb/June/October 1. The decision for a ``MAJOR/MINOR``
@@ -362,6 +368,19 @@ Documentation should be written in reStructuredText. Sphinx extensions may be
utilized but pure ReST is preferred where possible. See
:ref:`documentation`.
+Use of C++
+----------
+
+While C++ is not accepted for core components of FRR, extensions, modules or
+other distinct components may want to use C++ and include FRR header files.
+There is no requirement on contributors to work to retain C++ compatibility,
+but fixes for C++ compatibility are welcome.
+
+This implies that the burden of work to keep C++ compatibility is placed with
+the people who need it, and they may provide it at their leisure to the extent
+it is useful to them. So, if only a subset of header files, or even parts of
+a header file are made available to C++, this is perfectly fine.
+
Code Reviews
============
diff --git a/doc/user/basic.rst b/doc/user/basic.rst
index 3df60169f..3d3a75d4b 100644
--- a/doc/user/basic.rst
+++ b/doc/user/basic.rst
@@ -180,13 +180,14 @@ Basic Config Commands
In this example, the precision is set to provide timestamps with
millisecond accuracy.
-.. index:: log commands
-.. clicmd:: log commands
+.. index:: [no] log commands
+.. clicmd:: [no] log commands
This command enables the logging of all commands typed by a user to all
enabled log destinations. The note that logging includes full command lines,
- including passwords. Once set, command logging can only be turned off by
- restarting the daemon.
+ including passwords. If the daemon startup option `--command-log-always`
+ is used to start the daemon then this command is turned on by default
+ and cannot be turned off and the [no] form of the command is dissallowed.
.. index:: service password-encryption
.. clicmd:: service password-encryption
@@ -478,10 +479,23 @@ These options apply to all |PACKAGE_NAME| daemons.
Set the user and group to run as.
+.. option:: -N <namespace>
+
+ Set the namespace that the daemon will run in. A "/<namespace>" will
+ be added to all files that use the statedir. If you have "/var/run/frr"
+ as the default statedir then it will become "/var/run/frr/<namespace>".
+
.. option:: -v, --version
Print program version.
+.. option:: --command-log-always
+
+ Cause the daemon to always log commands entered to the specified log file.
+ This also makes the `no log commands` command dissallowed. Enabling this
+ is suggested if you have need to track what the operator is doing on
+ this router.
+
.. option:: --log <stdout|syslog|file:/path/to/log/file>
When initializing the daemon, setup the log to go to either stdout,
diff --git a/doc/user/bfd.rst b/doc/user/bfd.rst
index 33bc77049..32ca5707d 100644
--- a/doc/user/bfd.rst
+++ b/doc/user/bfd.rst
@@ -47,6 +47,9 @@ may also be specified (:ref:`common-invocation-options`).
#define BFDD_CONTROL_SOCKET "|INSTALL_PREFIX_STATE|/bfdd.sock"
+ This option overrides the location addition that the -N option provides
+ to the bfdd.sock
+
.. _bfd-commands:
diff --git a/doc/user/ldpd.rst b/doc/user/ldpd.rst
index 85d280343..977195d6a 100644
--- a/doc/user/ldpd.rst
+++ b/doc/user/ldpd.rst
@@ -24,6 +24,12 @@ Running Ldpd
The *ldpd* daemon can be invoked with any of the common
options (:ref:`common-invocation-options`).
+..option:: --ctl_socket
+
+ This option allows you to override the path to the ldpd.sock file
+ used to control this daemon. If specified this option overrides
+ the -N option path addition.
+
The *zebra* daemon must be running before *ldpd* is invoked.
Configuration of *ldpd* is done in its configuration file
diff --git a/doc/user/pim.rst b/doc/user/pim.rst
index 8b0fba5f8..e8c74f7b8 100644
--- a/doc/user/pim.rst
+++ b/doc/user/pim.rst
@@ -547,6 +547,13 @@ Clear commands reset various variables.
Reset multicast routes.
+.. index:: clear ip mroute [vrf NAME] count
+.. clicmd:: clear ip mroute [vrf NAME] count
+
+ When this command is issued, reset the counts of data shown for
+ packet count, byte count and wrong interface to 0 and start count
+ up from this spot.
+
.. index:: clear ip pim interfaces
.. clicmd:: clear ip pim interfaces
diff --git a/doc/user/zebra.rst b/doc/user/zebra.rst
index 40d894929..eefc5802a 100644
--- a/doc/user/zebra.rst
+++ b/doc/user/zebra.rst
@@ -58,6 +58,12 @@ Besides the common invocation options (:ref:`common-invocation-options`), the
.. seealso:: :ref:`zebra-vrf`
+.. option:: -z <path_to_socket>, --socket <path_to_socket>
+
+ If this option is supplied on the cli, the path to the zebra
+ control socket(zapi), is used. This option overrides a -N <namespace>
+ option if handed to it on the cli.
+
.. option:: --v6-rr-semantics
The linux kernel is receiving the ability to use the same route
diff --git a/eigrpd/eigrp_routemap.c b/eigrpd/eigrp_routemap.c
index 961556d43..0a00497d5 100644
--- a/eigrpd/eigrp_routemap.c
+++ b/eigrpd/eigrp_routemap.c
@@ -251,9 +251,9 @@ void eigrp_route_map_update(const char *notused)
/* `match metric METRIC' */
/* Match function return 1 if match is success else return zero. */
-static enum route_map_match_result_t
-route_match_metric(void *rule, struct prefix *prefix, route_map_object_t type,
- void *object)
+static route_map_result_t route_match_metric(void *rule, struct prefix *prefix,
+ route_map_object_t type,
+ void *object)
{
// uint32_t *metric;
// uint32_t check;
@@ -311,9 +311,10 @@ struct route_map_rule_cmd route_match_metric_cmd = {
/* `match interface IFNAME' */
/* Match function return 1 if match is success else return zero. */
-static enum route_map_match_result_t
-route_match_interface(void *rule, struct prefix *prefix,
- route_map_object_t type, void *object)
+static route_map_result_t route_match_interface(void *rule,
+ struct prefix *prefix,
+ route_map_object_t type,
+ void *object)
{
// struct rip_info *rinfo;
// struct interface *ifp;
@@ -359,9 +360,10 @@ struct route_map_rule_cmd route_match_interface_cmd = {
/* `match ip next-hop IP_ACCESS_LIST' */
/* Match function return 1 if match is success else return zero. */
-static enum route_map_match_result_t
-route_match_ip_next_hop(void *rule, struct prefix *prefix,
- route_map_object_t type, void *object)
+static route_map_result_t route_match_ip_next_hop(void *rule,
+ struct prefix *prefix,
+ route_map_object_t type,
+ void *object)
{
// struct access_list *alist;
// struct rip_info *rinfo;
@@ -405,7 +407,7 @@ static struct route_map_rule_cmd route_match_ip_next_hop_cmd = {
/* `match ip next-hop prefix-list PREFIX_LIST' */
-static enum route_map_match_result_t
+static route_map_result_t
route_match_ip_next_hop_prefix_list(void *rule, struct prefix *prefix,
route_map_object_t type, void *object)
{
@@ -450,9 +452,10 @@ static struct route_map_rule_cmd route_match_ip_next_hop_prefix_list_cmd = {
/* Match function should return 1 if match is success else return
zero. */
-static enum route_map_match_result_t
-route_match_ip_address(void *rule, struct prefix *prefix,
- route_map_object_t type, void *object)
+static route_map_result_t route_match_ip_address(void *rule,
+ struct prefix *prefix,
+ route_map_object_t type,
+ void *object)
{
struct access_list *alist;
@@ -488,7 +491,7 @@ static struct route_map_rule_cmd route_match_ip_address_cmd = {
/* `match ip address prefix-list PREFIX_LIST' */
-static enum route_map_match_result_t
+static route_map_result_t
route_match_ip_address_prefix_list(void *rule, struct prefix *prefix,
route_map_object_t type, void *object)
{
@@ -523,9 +526,8 @@ static struct route_map_rule_cmd route_match_ip_address_prefix_list_cmd = {
/* `match tag TAG' */
/* Match function return 1 if match is success else return zero. */
-static enum route_map_match_result_t
-route_match_tag(void *rule, struct prefix *prefix, route_map_object_t type,
- void *object)
+static route_map_result_t route_match_tag(void *rule, struct prefix *prefix,
+ route_map_object_t type, void *object)
{
// unsigned short *tag;
// struct rip_info *rinfo;
@@ -566,9 +568,9 @@ struct route_map_rule_cmd route_match_tag_cmd = {
"tag", route_match_tag, route_match_tag_compile, route_match_tag_free};
/* Set metric to attribute. */
-static enum route_map_match_result_t
-route_set_metric(void *rule, struct prefix *prefix,
- route_map_object_t type, void *object)
+static route_map_result_t route_set_metric(void *rule, struct prefix *prefix,
+ route_map_object_t type,
+ void *object)
{
// if (type == RMAP_RIP)
// {
@@ -660,9 +662,10 @@ static struct route_map_rule_cmd route_set_metric_cmd = {
/* `set ip next-hop IP_ADDRESS' */
/* Set nexthop to object. ojbect must be pointer to struct attr. */
-static enum route_map_match_result_t
-route_set_ip_nexthop(void *rule, struct prefix *prefix,
- route_map_object_t type, void *object)
+static route_map_result_t route_set_ip_nexthop(void *rule,
+ struct prefix *prefix,
+ route_map_object_t type,
+ void *object)
{
// struct in_addr *address;
// struct rip_info *rinfo;
@@ -715,9 +718,8 @@ static struct route_map_rule_cmd route_set_ip_nexthop_cmd = {
/* `set tag TAG' */
/* Set tag to object. ojbect must be pointer to struct attr. */
-static enum route_map_match_result_t
-route_set_tag(void *rule, struct prefix *prefix,
- route_map_object_t type, void *object)
+static route_map_result_t route_set_tag(void *rule, struct prefix *prefix,
+ route_map_object_t type, void *object)
{
// unsigned short *tag;
// struct rip_info *rinfo;
diff --git a/isisd/isis_routemap.c b/isisd/isis_routemap.c
index 69694f26e..d63676256 100644
--- a/isisd/isis_routemap.c
+++ b/isisd/isis_routemap.c
@@ -48,9 +48,10 @@
#include "isis_zebra.h"
#include "isis_routemap.h"
-static enum route_map_match_result_t
-route_match_ip_address(void *rule, const struct prefix *prefix,
- route_map_object_t type, void *object)
+static route_map_result_t route_match_ip_address(void *rule,
+ const struct prefix *prefix,
+ route_map_object_t type,
+ void *object)
{
struct access_list *alist;
@@ -80,7 +81,7 @@ static struct route_map_rule_cmd route_match_ip_address_cmd = {
/* ------------------------------------------------------------*/
-static enum route_map_match_result_t
+static route_map_result_t
route_match_ip_address_prefix_list(void *rule, const struct prefix *prefix,
route_map_object_t type, void *object)
{
@@ -113,9 +114,10 @@ struct route_map_rule_cmd route_match_ip_address_prefix_list_cmd = {
/* ------------------------------------------------------------*/
-static enum route_map_match_result_t
-route_match_ipv6_address(void *rule, const struct prefix *prefix,
- route_map_object_t type, void *object)
+static route_map_result_t route_match_ipv6_address(void *rule,
+ const struct prefix *prefix,
+ route_map_object_t type,
+ void *object)
{
struct access_list *alist;
@@ -145,7 +147,7 @@ static struct route_map_rule_cmd route_match_ipv6_address_cmd = {
/* ------------------------------------------------------------*/
-static enum route_map_match_result_t
+static route_map_result_t
route_match_ipv6_address_prefix_list(void *rule, const struct prefix *prefix,
route_map_object_t type, void *object)
{
@@ -178,9 +180,10 @@ struct route_map_rule_cmd route_match_ipv6_address_prefix_list_cmd = {
/* ------------------------------------------------------------*/
-static enum route_map_match_result_t
-route_set_metric(void *rule, const struct prefix *prefix,
- route_map_object_t type, void *object)
+static route_map_result_t route_set_metric(void *rule,
+ const struct prefix *prefix,
+ route_map_object_t type,
+ void *object)
{
uint32_t *metric;
struct isis_ext_info *info;
diff --git a/isisd/isis_tlvs.c b/isisd/isis_tlvs.c
index 6b8e74f07..6edfeb4c9 100644
--- a/isisd/isis_tlvs.c
+++ b/isisd/isis_tlvs.c
@@ -3271,13 +3271,18 @@ void isis_tlvs_add_ipv6_addresses(struct isis_tlvs *tlvs,
{
struct listnode *node;
struct prefix_ipv6 *ip_addr;
+ unsigned int addr_count = 0;
for (ALL_LIST_ELEMENTS_RO(addresses, node, ip_addr)) {
+ if (addr_count >= 15)
+ break;
+
struct isis_ipv6_address *a =
XCALLOC(MTYPE_ISIS_TLV, sizeof(*a));
a->addr = ip_addr->prefix;
append_item(&tlvs->ipv6_address, (struct isis_item *)a);
+ addr_count++;
}
}
diff --git a/ldpd/ldpd.c b/ldpd/ldpd.c
index 771d3b745..5aaa2ec32 100644
--- a/ldpd/ldpd.c
+++ b/ldpd/ldpd.c
@@ -116,7 +116,7 @@ struct zebra_privs_t ldpd_privs =
};
/* CTL Socket path */
-char ctl_sock_path[MAXPATHLEN] = LDPD_SOCKET;
+char ctl_sock_path[MAXPATHLEN];
/* LDPd options. */
#define OPTION_CTLSOCK 1001
@@ -219,6 +219,10 @@ main(int argc, char *argv[])
int pipe_parent2lde[2], pipe_parent2lde_sync[2];
char *ctl_sock_name;
struct thread *thread = NULL;
+ bool ctl_sock_used = false;
+
+ snprintf(ctl_sock_path, sizeof(ctl_sock_path), LDPD_SOCKET,
+ "", "");
ldpd_process = PROC_MAIN;
log_procname = log_procnames[ldpd_process];
@@ -244,6 +248,7 @@ main(int argc, char *argv[])
case 0:
break;
case OPTION_CTLSOCK:
+ ctl_sock_used = true;
ctl_sock_name = strrchr(LDPD_SOCKET, '/');
if (ctl_sock_name)
/* skip '/' */
@@ -277,6 +282,10 @@ main(int argc, char *argv[])
}
}
+ if (ldpd_di.pathspace && !ctl_sock_used)
+ snprintf(ctl_sock_path, sizeof(ctl_sock_path), LDPD_SOCKET,
+ "/", ldpd_di.pathspace);
+
strlcpy(init.user, ldpd_privs.user, sizeof(init.user));
strlcpy(init.group, ldpd_privs.group, sizeof(init.group));
strlcpy(init.ctl_sock_path, ctl_sock_path, sizeof(init.ctl_sock_path));
diff --git a/lib/compiler.h b/lib/compiler.h
index c2e57db7f..750942822 100644
--- a/lib/compiler.h
+++ b/lib/compiler.h
@@ -50,6 +50,16 @@ extern "C" {
#endif
#endif
+#if !defined(__GNUC__)
+#error module code needs GCC visibility extensions
+#elif __GNUC__ < 4
+#error module code needs GCC visibility extensions
+#else
+# define DSO_PUBLIC __attribute__ ((visibility ("default")))
+# define DSO_SELF __attribute__ ((visibility ("protected")))
+# define DSO_LOCAL __attribute__ ((visibility ("hidden")))
+#endif
+
#ifdef __sun
/* Solaris doesn't do constructor priorities due to linker restrictions */
#undef _CONSTRUCTOR
diff --git a/lib/grammar_sandbox_main.c b/lib/grammar_sandbox_main.c
index 38494fb00..6d28a667b 100644
--- a/lib/grammar_sandbox_main.c
+++ b/lib/grammar_sandbox_main.c
@@ -56,7 +56,7 @@ int main(int argc, char **argv)
host.name = strdup("test");
host.domainname = strdup("testdomainname");
- vty_init(master);
+ vty_init(master, true);
memory_init();
yang_init();
nb_init(master, NULL, 0);
diff --git a/lib/libfrr.c b/lib/libfrr.c
index c60e26085..ed784fc73 100644
--- a/lib/libfrr.c
+++ b/lib/libfrr.c
@@ -46,7 +46,7 @@ DEFINE_KOOH(frr_early_fini, (), ())
DEFINE_KOOH(frr_fini, (), ())
const char frr_sysconfdir[] = SYSCONFDIR;
-const char frr_vtydir[] = DAEMON_VTY_DIR;
+char frr_vtydir[256];
#ifdef HAVE_SQLITE3
const char frr_dbdir[] = DAEMON_DB_DIR;
#endif
@@ -57,7 +57,7 @@ char frr_protonameinst[256] = "NONE";
char config_default[512];
char frr_zclientpath[256];
-static char pidfile_default[512];
+static char pidfile_default[1024];
#ifdef HAVE_SQLITE3
static char dbfile_default[512];
#endif
@@ -94,6 +94,7 @@ static void opt_extend(const struct optspec *os)
#define OPTION_LOGLEVEL 1004
#define OPTION_TCLI 1005
#define OPTION_DB_FILE 1006
+#define OPTION_LOGGING 1007
static const struct option lo_always[] = {
{"help", no_argument, NULL, 'h'},
@@ -105,6 +106,7 @@ static const struct option lo_always[] = {
{"log", required_argument, NULL, OPTION_LOG},
{"log-level", required_argument, NULL, OPTION_LOGLEVEL},
{"tcli", no_argument, NULL, OPTION_TCLI},
+ {"command-log-always", no_argument, NULL, OPTION_LOGGING},
{NULL}};
static const struct optspec os_always = {
"hvdM:",
@@ -177,7 +179,7 @@ bool frr_zclient_addr(struct sockaddr_storage *sa, socklen_t *sa_len,
memset(sa, 0, sizeof(*sa));
if (!path)
- path = ZEBRA_SERV_PATH;
+ path = frr_zclientpath;
if (!strncmp(path, ZAPI_TCP_PATHNAME, strlen(ZAPI_TCP_PATHNAME))) {
/* note: this functionality is disabled at bottom */
@@ -283,6 +285,11 @@ bool frr_zclient_addr(struct sockaddr_storage *sa, socklen_t *sa_len,
static struct frr_daemon_info *di = NULL;
+void frr_init_vtydir(void)
+{
+ snprintf(frr_vtydir, sizeof(frr_vtydir), DAEMON_VTY_DIR, "", "");
+}
+
void frr_preinit(struct frr_daemon_info *daemon, int argc, char **argv)
{
di = daemon;
@@ -305,10 +312,13 @@ void frr_preinit(struct frr_daemon_info *daemon, int argc, char **argv)
if (di->flags & FRR_DETACH_LATER)
nodetach_daemon = true;
+ frr_init_vtydir();
snprintf(config_default, sizeof(config_default), "%s/%s.conf",
frr_sysconfdir, di->name);
snprintf(pidfile_default, sizeof(pidfile_default), "%s/%s.pid",
frr_vtydir, di->name);
+ snprintf(frr_zclientpath, sizeof(frr_zclientpath),
+ ZEBRA_SERV_PATH, "", "");
#ifdef HAVE_SQLITE3
snprintf(dbfile_default, sizeof(dbfile_default), "%s/%s.db",
frr_dbdir, di->name);
@@ -317,8 +327,6 @@ void frr_preinit(struct frr_daemon_info *daemon, int argc, char **argv)
strlcpy(frr_protoname, di->logname, sizeof(frr_protoname));
strlcpy(frr_protonameinst, di->logname, sizeof(frr_protonameinst));
- strlcpy(frr_zclientpath, ZEBRA_SERV_PATH, sizeof(frr_zclientpath));
-
di->cli_mode = FRR_CLI_CLASSIC;
}
@@ -398,6 +406,10 @@ static int frr_opt(int opt)
errors++;
break;
}
+ if (di->zpathspace)
+ fprintf(stderr,
+ "-N option overriden by -z for zebra named socket path\n");
+
if (strchr(optarg, '/') || strchr(optarg, '.')) {
fprintf(stderr,
"slashes or dots are not permitted in the --pathspace option.\n");
@@ -405,6 +417,14 @@ static int frr_opt(int opt)
break;
}
di->pathspace = optarg;
+
+ if (!di->zpathspace)
+ snprintf(frr_zclientpath, sizeof(frr_zclientpath),
+ ZEBRA_SERV_PATH, "/", di->pathspace);
+ snprintf(frr_vtydir, sizeof(frr_vtydir), DAEMON_VTY_DIR, "/",
+ di->pathspace);
+ snprintf(pidfile_default, sizeof(pidfile_default), "%s/%s.pid",
+ frr_vtydir, di->name);
break;
#ifdef HAVE_SQLITE3
case OPTION_DB_FILE:
@@ -424,6 +444,10 @@ static int frr_opt(int opt)
di->terminal = 1;
break;
case 'z':
+ di->zpathspace = true;
+ if (di->pathspace)
+ fprintf(stderr,
+ "-z option overrides -N option for zebra named socket path\n");
if (di->flags & FRR_NO_ZCLIENT)
return 1;
strlcpy(frr_zclientpath, optarg, sizeof(frr_zclientpath));
@@ -496,6 +520,9 @@ static int frr_opt(int opt)
case OPTION_LOGLEVEL:
di->early_loglevel = optarg;
break;
+ case OPTION_LOGGING:
+ di->log_always = true;
+ break;
default:
return 1;
}
@@ -590,8 +617,8 @@ struct thread_master *frr_init(void)
snprintf(config_default, sizeof(config_default), "%s%s%s%s.conf",
frr_sysconfdir, p_pathspace, di->name, p_instance);
- snprintf(pidfile_default, sizeof(pidfile_default), "%s/%s%s%s.pid",
- frr_vtydir, p_pathspace, di->name, p_instance);
+ snprintf(pidfile_default, sizeof(pidfile_default), "%s/%s%s.pid",
+ frr_vtydir, di->name, p_instance);
#ifdef HAVE_SQLITE3
snprintf(dbfile_default, sizeof(dbfile_default), "%s/%s%s%s.db",
frr_dbdir, p_pathspace, di->name, p_instance);
@@ -648,7 +675,7 @@ struct thread_master *frr_init(void)
else
cmd_init(1);
- vty_init(master);
+ vty_init(master, di->log_always);
memory_init();
log_ref_init();
@@ -875,9 +902,7 @@ static void frr_vty_serv(void)
const char *dir;
char defvtydir[256];
- snprintf(defvtydir, sizeof(defvtydir), "%s%s%s", frr_vtydir,
- di->pathspace ? "/" : "",
- di->pathspace ? di->pathspace : "");
+ snprintf(defvtydir, sizeof(defvtydir), "%s", frr_vtydir);
dir = di->vty_sock_path ? di->vty_sock_path : defvtydir;
diff --git a/lib/libfrr.h b/lib/libfrr.h
index 891e2c128..e2b3db74a 100644
--- a/lib/libfrr.h
+++ b/lib/libfrr.h
@@ -81,7 +81,10 @@ struct frr_daemon_info {
#endif
const char *vty_path;
const char *module_path;
+
const char *pathspace;
+ bool zpathspace;
+
const char *early_logging;
const char *early_loglevel;
@@ -97,6 +100,8 @@ struct frr_daemon_info {
const struct frr_yang_module_info **yang_modules;
size_t n_yang_modules;
+
+ bool log_always;
};
/* execname is the daemon's executable (and pidfile and configfile) name,
@@ -118,6 +123,7 @@ struct frr_daemon_info {
.version = FRR_VERSION, ) \
/* end */
+extern void frr_init_vtydir(void);
extern void frr_preinit(struct frr_daemon_info *daemon, int argc, char **argv);
extern void frr_opt_add(const char *optstr, const struct option *longopts,
const char *helpstr);
@@ -148,7 +154,7 @@ extern void frr_fini(void);
extern char config_default[512];
extern char frr_zclientpath[256];
extern const char frr_sysconfdir[];
-extern const char frr_vtydir[];
+extern char frr_vtydir[256];
extern const char frr_moduledir[];
extern char frr_protoname[];
diff --git a/lib/log.c b/lib/log.c
index 5e3064a8d..5ce3bd702 100644
--- a/lib/log.c
+++ b/lib/log.c
@@ -30,6 +30,7 @@
#include "command.h"
#include "lib_errors.h"
#include "lib/hook.h"
+#include "printfrr.h"
#ifndef SUNOS_5
#include <sys/un.h>
@@ -191,19 +192,13 @@ static void time_print(FILE *fp, struct timestamp_control *ctl)
static void vzlog_file(struct zlog *zl, struct timestamp_control *tsctl,
const char *proto_str, int record_priority, int priority,
- FILE *fp, const char *format, va_list args)
+ FILE *fp, const char *msg)
{
- va_list ac;
-
time_print(fp, tsctl);
if (record_priority)
fprintf(fp, "%s: ", zlog_priority[priority]);
- fprintf(fp, "%s", proto_str);
- va_copy(ac, args);
- vfprintf(fp, format, ac);
- va_end(ac);
- fprintf(fp, "\n");
+ fprintf(fp, "%s%s\n", proto_str, msg);
fflush(fp);
}
@@ -217,33 +212,26 @@ void vzlog(int priority, const char *format, va_list args)
struct timestamp_control tsctl;
tsctl.already_rendered = 0;
struct zlog *zl = zlog_default;
+ char buf[256], *msg;
/* call external hook */
hook_call(zebra_ext_log, priority, format, args);
+ msg = vasnprintfrr(MTYPE_TMP, buf, sizeof(buf), format, args);
+
/* When zlog_default is also NULL, use stderr for logging. */
if (zl == NULL) {
tsctl.precision = 0;
time_print(stderr, &tsctl);
- fprintf(stderr, "%s: ", "unknown");
- vfprintf(stderr, format, args);
- fprintf(stderr, "\n");
+ fprintf(stderr, "%s: %s\n", "unknown", msg);
fflush(stderr);
-
- /* In this case we return at here. */
- errno = original_errno;
- pthread_mutex_unlock(&loglock);
- return;
+ goto out;
}
tsctl.precision = zl->timestamp_precision;
/* Syslog output */
- if (priority <= zl->maxlvl[ZLOG_DEST_SYSLOG]) {
- va_list ac;
- va_copy(ac, args);
- vsyslog(priority | zlog_default->facility, format, ac);
- va_end(ac);
- }
+ if (priority <= zl->maxlvl[ZLOG_DEST_SYSLOG])
+ syslog(priority | zlog_default->facility, "%s", msg);
if (zl->instance)
sprintf(proto_str, "%s[%d]: ", zl->protoname, zl->instance);
@@ -253,7 +241,7 @@ void vzlog(int priority, const char *format, va_list args)
/* File output. */
if ((priority <= zl->maxlvl[ZLOG_DEST_FILE]) && zl->fp)
vzlog_file(zl, &tsctl, proto_str, zl->record_priority, priority,
- zl->fp, format, args);
+ zl->fp, msg);
/* fixed-config logging to stderr while we're stating up & haven't
* daemonized / reached mainloop yet
@@ -261,17 +249,19 @@ void vzlog(int priority, const char *format, va_list args)
* note the "else" on stdout output -- we don't want to print the same
* message to both stderr and stdout. */
if (zlog_startup_stderr && priority <= LOG_WARNING)
- vzlog_file(zl, &tsctl, proto_str, 1, priority, stderr, format,
- args);
+ vzlog_file(zl, &tsctl, proto_str, 1, priority, stderr, msg);
else if (priority <= zl->maxlvl[ZLOG_DEST_STDOUT])
vzlog_file(zl, &tsctl, proto_str, zl->record_priority, priority,
- stdout, format, args);
+ stdout, msg);
/* Terminal monitor. */
if (priority <= zl->maxlvl[ZLOG_DEST_MONITOR])
vty_log((zl->record_priority ? zlog_priority[priority] : NULL),
- proto_str, format, &tsctl, args);
+ proto_str, msg, &tsctl);
+out:
+ if (msg != buf)
+ XFREE(MTYPE_TMP, msg);
errno = original_errno;
pthread_mutex_unlock(&loglock);
}
@@ -305,47 +295,11 @@ int vzlog_test(int priority)
return ret;
}
-static char *str_append(char *dst, int len, const char *src)
-{
- while ((len-- > 0) && *src)
- *dst++ = *src++;
- return dst;
-}
-
-static char *num_append(char *s, int len, unsigned long x)
-{
- char buf[30];
- char *t;
-
- if (!x)
- return str_append(s, len, "0");
- *(t = &buf[sizeof(buf) - 1]) = '\0';
- while (x && (t > buf)) {
- *--t = '0' + (x % 10);
- x /= 10;
- }
- return str_append(s, len, t);
-}
-
-#if defined(SA_SIGINFO) \
- || defined(HAVE_PRINTSTACK) \
- || defined(HAVE_GLIBC_BACKTRACE)
-static char *hex_append(char *s, int len, unsigned long x)
-{
- char buf[30];
- char *t;
-
- if (!x)
- return str_append(s, len, "0");
- *(t = &buf[sizeof(buf) - 1]) = '\0';
- while (x && (t > buf)) {
- unsigned int cc = (x % 16);
- *--t = ((cc < 10) ? ('0' + cc) : ('a' + cc - 10));
- x /= 16;
- }
- return str_append(s, len, t);
-}
-#endif
+/*
+ * crash handling
+ *
+ * NB: only AS-Safe (async-signal) functions can be used here!
+ */
/* Needs to be enhanced to support Solaris. */
static int syslog_connect(void)
@@ -354,7 +308,6 @@ static int syslog_connect(void)
return -1;
#else
int fd;
- char *s;
struct sockaddr_un addr;
if ((fd = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0)
@@ -365,10 +318,8 @@ static int syslog_connect(void)
#else
#define SYSLOG_SOCKET_PATH "/dev/log"
#endif
- s = str_append(addr.sun_path, sizeof(addr.sun_path),
- SYSLOG_SOCKET_PATH);
+ strlcpy(addr.sun_path, SYSLOG_SOCKET_PATH, sizeof(addr.sun_path));
#undef SYSLOG_SOCKET_PATH
- *s = '\0';
if (connect(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
close(fd);
return -1;
@@ -381,168 +332,109 @@ static void syslog_sigsafe(int priority, const char *msg, size_t msglen)
{
static int syslog_fd = -1;
char buf[sizeof("<1234567890>ripngd[1234567890]: ") + msglen + 50];
- char *s;
+ struct fbuf fb = { .buf = buf, .pos = buf, .len = sizeof(buf) };
if ((syslog_fd < 0) && ((syslog_fd = syslog_connect()) < 0))
return;
-#define LOC s,buf+sizeof(buf)-s
- s = buf;
- s = str_append(LOC, "<");
- s = num_append(LOC, priority);
- s = str_append(LOC, ">");
/* forget about the timestamp, too difficult in a signal handler */
- s = str_append(LOC, zlog_default->ident);
- if (zlog_default->syslog_options & LOG_PID) {
- s = str_append(LOC, "[");
- s = num_append(LOC, getpid());
- s = str_append(LOC, "]");
- }
- s = str_append(LOC, ": ");
- s = str_append(LOC, msg);
- write_wrapper(syslog_fd, buf, s - buf);
-#undef LOC
+ bprintfrr(&fb, "<%d>%s", priority, zlog_default->ident);
+ if (zlog_default->syslog_options & LOG_PID)
+ bprintfrr(&fb, "[%ld]", (long)getpid());
+ bprintfrr(&fb, ": %s", msg);
+ write_wrapper(syslog_fd, fb.buf, fb.pos - fb.buf);
}
static int open_crashlog(void)
{
-#define CRASHLOG_PREFIX "/var/tmp/quagga."
-#define CRASHLOG_SUFFIX "crashlog"
- if (zlog_default && zlog_default->ident) {
- /* Avoid strlen since it is not async-signal-safe. */
- const char *p;
- size_t ilen;
-
- for (p = zlog_default->ident, ilen = 0; *p; p++)
- ilen++;
- {
- char buf[sizeof(CRASHLOG_PREFIX) + ilen
- + sizeof(CRASHLOG_SUFFIX) + 3];
- char *s = buf;
-#define LOC s,buf+sizeof(buf)-s
- s = str_append(LOC, CRASHLOG_PREFIX);
- s = str_append(LOC, zlog_default->ident);
- s = str_append(LOC, ".");
- s = str_append(LOC, CRASHLOG_SUFFIX);
-#undef LOC
- *s = '\0';
- return open(buf, O_WRONLY | O_CREAT | O_EXCL,
- LOGFILE_MASK);
- }
- }
- return open(CRASHLOG_PREFIX CRASHLOG_SUFFIX,
- O_WRONLY | O_CREAT | O_EXCL, LOGFILE_MASK);
-#undef CRASHLOG_SUFFIX
-#undef CRASHLOG_PREFIX
-}
-
-/* Note: the goal here is to use only async-signal-safe functions. */
-void zlog_signal(int signo, const char *action
-#ifdef SA_SIGINFO
- ,
- siginfo_t *siginfo, void *program_counter
-#endif
- )
-{
- time_t now;
- char buf[sizeof("DEFAULT: Received signal S at T (si_addr 0xP, PC 0xP); aborting...")
- + 100];
- char *s = buf;
- char *msgstart = buf;
-#define LOC s,buf+sizeof(buf)-s
+ char crashlog_buf[PATH_MAX];
+ const char *crashlog_default = "/var/tmp/frr.crashlog", *crashlog;
- time(&now);
- if (zlog_default) {
- s = str_append(LOC, zlog_default->protoname);
- *s++ = ':';
- *s++ = ' ';
- msgstart = s;
- }
- s = str_append(LOC, "Received signal ");
- s = num_append(LOC, signo);
- s = str_append(LOC, " at ");
- s = num_append(LOC, now);
-#ifdef SA_SIGINFO
- s = str_append(LOC, " (si_addr 0x");
- s = hex_append(LOC, (unsigned long)(siginfo->si_addr));
- if (program_counter) {
- s = str_append(LOC, ", PC 0x");
- s = hex_append(LOC, (unsigned long)program_counter);
+ if (!zlog_default || !zlog_default->ident)
+ crashlog = crashlog_default;
+ else {
+ snprintfrr(crashlog_buf, sizeof(crashlog_buf),
+ "/var/tmp/frr.%s.crashlog", zlog_default->ident);
+ crashlog = crashlog_buf;
}
- s = str_append(LOC, "); ");
-#else /* SA_SIGINFO */
- s = str_append(LOC, "; ");
-#endif /* SA_SIGINFO */
- s = str_append(LOC, action);
- if (s < buf + sizeof(buf))
- *s++ = '\n';
+ return open(crashlog, O_WRONLY | O_CREAT | O_EXCL, LOGFILE_MASK);
+}
/* N.B. implicit priority is most severe */
#define PRI LOG_CRIT
-#define DUMP(FD) write_wrapper(FD, buf, s-buf);
+static void crash_write(struct fbuf *fb, char *msgstart)
+{
+ if (fb->pos == fb->buf)
+ return;
+ if (!msgstart)
+ msgstart = fb->buf;
+
/* If no file logging configured, try to write to fallback log file. */
if ((logfile_fd >= 0) || ((logfile_fd = open_crashlog()) >= 0))
- DUMP(logfile_fd)
+ write(logfile_fd, fb->buf, fb->pos - fb->buf);
if (!zlog_default)
- DUMP(STDERR_FILENO)
+ write(STDERR_FILENO, fb->buf, fb->pos - fb->buf);
else {
if (PRI <= zlog_default->maxlvl[ZLOG_DEST_STDOUT])
- DUMP(STDOUT_FILENO)
+ write(STDOUT_FILENO, fb->buf, fb->pos - fb->buf);
/* Remove trailing '\n' for monitor and syslog */
- *--s = '\0';
+ fb->pos--;
if (PRI <= zlog_default->maxlvl[ZLOG_DEST_MONITOR])
- vty_log_fixed(buf, s - buf);
+ vty_log_fixed(fb->buf, fb->pos - fb->buf);
if (PRI <= zlog_default->maxlvl[ZLOG_DEST_SYSLOG])
syslog_sigsafe(PRI | zlog_default->facility, msgstart,
- s - msgstart);
+ fb->pos - msgstart);
}
-#undef DUMP
+}
- zlog_backtrace_sigsafe(PRI,
+/* Note: the goal here is to use only async-signal-safe functions. */
+void zlog_signal(int signo, const char *action, void *siginfo_v,
+ void *program_counter)
+{
#ifdef SA_SIGINFO
- program_counter
-#else
- NULL
+ siginfo_t *siginfo = siginfo_v;
#endif
- );
+ time_t now;
+ char buf[sizeof("DEFAULT: Received signal S at T (si_addr 0xP, PC 0xP); aborting...")
+ + 100];
+ char *msgstart;
+ struct fbuf fb = { .buf = buf, .pos = buf, .len = sizeof(buf) };
+
+ time(&now);
+ if (zlog_default)
+ bprintfrr(&fb, "%s: ", zlog_default->protoname);
+
+ msgstart = fb.pos;
+
+ bprintfrr(&fb, "Received signal %d at %lld", signo, (long long)now);
+#ifdef SA_SIGINFO
+ if (program_counter)
+ bprintfrr(&fb, " (si_addr 0x%tx, PC 0x%tx)",
+ (ptrdiff_t)siginfo->si_addr,
+ (ptrdiff_t)program_counter);
+ else
+ bprintfrr(&fb, " (si_addr 0x%tx)",
+ (ptrdiff_t)siginfo->si_addr);
+#endif /* SA_SIGINFO */
+ bprintfrr(&fb, "; %s\n", action);
+
+ crash_write(&fb, msgstart);
+
+ zlog_backtrace_sigsafe(PRI, program_counter);
+
+ fb.pos = buf;
- s = buf;
struct thread *tc;
tc = pthread_getspecific(thread_current);
- if (!tc)
- s = str_append(LOC, "no thread information available\n");
- else {
- s = str_append(LOC, "in thread ");
- s = str_append(LOC, tc->funcname);
- s = str_append(LOC, " scheduled from ");
- s = str_append(LOC, tc->schedfrom);
- s = str_append(LOC, ":");
- s = num_append(LOC, tc->schedfrom_line);
- s = str_append(LOC, "\n");
- }
-#define DUMP(FD) write_wrapper(FD, buf, s-buf);
- /* If no file logging configured, try to write to fallback log file. */
- if (logfile_fd >= 0)
- DUMP(logfile_fd)
- if (!zlog_default)
- DUMP(STDERR_FILENO)
- else {
- if (PRI <= zlog_default->maxlvl[ZLOG_DEST_STDOUT])
- DUMP(STDOUT_FILENO)
- /* Remove trailing '\n' for monitor and syslog */
- *--s = '\0';
- if (PRI <= zlog_default->maxlvl[ZLOG_DEST_MONITOR])
- vty_log_fixed(buf, s - buf);
- if (PRI <= zlog_default->maxlvl[ZLOG_DEST_SYSLOG])
- syslog_sigsafe(PRI | zlog_default->facility, msgstart,
- s - msgstart);
- }
-#undef DUMP
+ if (!tc)
+ bprintfrr(&fb, "no thread information available\n");
+ else
+ bprintfrr(&fb, "in thread %s scheduled from %s:%d\n",
+ tc->funcname, tc->schedfrom, tc->schedfrom_line);
-#undef PRI
-#undef LOC
+ crash_write(&fb, NULL);
}
/* Log a backtrace using only async-signal-safe functions.
@@ -550,7 +442,8 @@ void zlog_signal(int signo, const char *action
void zlog_backtrace_sigsafe(int priority, void *program_counter)
{
#ifdef HAVE_LIBUNWIND
- char buf[100];
+ char buf[256];
+ struct fbuf fb = { .buf = buf, .len = sizeof(buf) };
unw_cursor_t cursor;
unw_context_t uc;
unw_word_t ip, off, sp;
@@ -564,28 +457,27 @@ void zlog_backtrace_sigsafe(int priority, void *program_counter)
unw_get_reg(&cursor, UNW_REG_IP, &ip);
unw_get_reg(&cursor, UNW_REG_SP, &sp);
- if (unw_is_signal_frame(&cursor))
- dprintf(2, " ---- signal ----\n");
-
- if (!unw_get_proc_name(&cursor, buf, sizeof(buf), &off)) {
- snprintf(name, sizeof(name), "%s+%#lx",
- buf, (long)off);
- }
- dprintf(2, "%-30s %16lx %16lx", name, (long)ip, (long)sp);
- if (dladdr((void *)ip, &dlinfo)) {
- dprintf(2, " %s (mapped at %p)",
- dlinfo.dli_fname, dlinfo.dli_fbase);
- }
- dprintf(2, "\n");
+ if (!unw_get_proc_name(&cursor, buf, sizeof(buf), &off))
+ snprintfrr(name, sizeof(name), "%s+%#lx",
+ buf, (long)off);
+ fb.pos = buf;
+ if (unw_is_signal_frame(&cursor))
+ bprintfrr(&fb, " ---- signal ----\n");
+ bprintfrr(&fb, "%-30s %16lx %16lx", name, (long)ip, (long)sp);
+ if (dladdr((void *)ip, &dlinfo))
+ bprintfrr(&fb, " %s (mapped at %p)",
+ dlinfo.dli_fname, dlinfo.dli_fbase);
+ bprintfrr(&fb, "\n");
+ crash_write(&fb, NULL);
}
#elif defined(HAVE_GLIBC_BACKTRACE) || defined(HAVE_PRINTSTACK)
static const char pclabel[] = "Program counter: ";
void *array[64];
int size;
- char buf[100];
- char *s, **bt = NULL;
-#define LOC s,buf+sizeof(buf)-s
+ char buf[128];
+ struct fbuf fb = { .buf = buf, .pos = buf, .len = sizeof(buf) };
+ char **bt = NULL;
#ifdef HAVE_GLIBC_BACKTRACE
size = backtrace(array, array_size(array));
@@ -598,7 +490,7 @@ void zlog_backtrace_sigsafe(int priority, void *program_counter)
write_wrapper(FD, pclabel, sizeof(pclabel) - 1); \
backtrace_symbols_fd(&program_counter, 1, FD); \
} \
- write_wrapper(FD, buf, s - buf); \
+ write_wrapper(FD, fb.buf, fb.pos - fb.buf); \
backtrace_symbols_fd(array, size, FD); \
}
#elif defined(HAVE_PRINTSTACK)
@@ -608,15 +500,12 @@ void zlog_backtrace_sigsafe(int priority, void *program_counter)
{ \
if (program_counter) \
write_wrapper((FD), pclabel, sizeof(pclabel) - 1); \
- write_wrapper((FD), buf, s - buf); \
+ write_wrapper((FD), fb.buf, fb.pos - fb.buf); \
printstack((FD)); \
}
#endif /* HAVE_GLIBC_BACKTRACE, HAVE_PRINTSTACK */
- s = buf;
- s = str_append(LOC, "Backtrace for ");
- s = num_append(LOC, size);
- s = str_append(LOC, " stack frames:\n");
+ bprintfrr(&fb, "Backtrace for %d stack frames:\n", size);
if ((logfile_fd >= 0) || ((logfile_fd = open_crashlog()) >= 0))
DUMP(logfile_fd)
@@ -626,12 +515,12 @@ void zlog_backtrace_sigsafe(int priority, void *program_counter)
if (priority <= zlog_default->maxlvl[ZLOG_DEST_STDOUT])
DUMP(STDOUT_FILENO)
/* Remove trailing '\n' for monitor and syslog */
- *--s = '\0';
+ fb.pos--;
if (priority <= zlog_default->maxlvl[ZLOG_DEST_MONITOR])
- vty_log_fixed(buf, s - buf);
+ vty_log_fixed(fb.buf, fb.pos - fb.buf);
if (priority <= zlog_default->maxlvl[ZLOG_DEST_SYSLOG])
- syslog_sigsafe(priority | zlog_default->facility, buf,
- s - buf);
+ syslog_sigsafe(priority | zlog_default->facility,
+ fb.buf, fb.pos - fb.buf);
{
int i;
#ifdef HAVE_GLIBC_BACKTRACE
@@ -639,34 +528,26 @@ void zlog_backtrace_sigsafe(int priority, void *program_counter)
#endif
/* Just print the function addresses. */
for (i = 0; i < size; i++) {
- s = buf;
+ fb.pos = buf;
if (bt)
- s = str_append(LOC, bt[i]);
- else {
- s = str_append(LOC, "[bt ");
- s = num_append(LOC, i);
- s = str_append(LOC, "] 0x");
- s = hex_append(
- LOC, (unsigned long)(array[i]));
- }
- *s = '\0';
+ bprintfrr(&fb, "%s", bt[i]);
+ else
+ bprintfrr(&fb, "[bt %d] 0x%tx", i,
+ (ptrdiff_t)(array[i]));
if (priority
<= zlog_default->maxlvl[ZLOG_DEST_MONITOR])
- vty_log_fixed(buf, s - buf);
+ vty_log_fixed(fb.buf, fb.pos - fb.buf);
if (priority
<= zlog_default->maxlvl[ZLOG_DEST_SYSLOG])
- syslog_sigsafe(
- priority
- | zlog_default
- ->facility,
- buf, s - buf);
+ syslog_sigsafe(priority
+ | zlog_default->facility,
+ fb.buf, fb.pos - fb.buf);
}
if (bt)
free(bt);
}
}
#undef DUMP
-#undef LOC
#endif /* HAVE_STRACK_TRACE */
}
diff --git a/lib/log.h b/lib/log.h
index 9368bf9e8..e41a472e0 100644
--- a/lib/log.h
+++ b/lib/log.h
@@ -128,12 +128,8 @@ const char *lookup_msg(const struct message *mz, int kz, const char *nf);
extern const char *safe_strerror(int errnum);
/* To be called when a fatal signal is caught. */
-extern void zlog_signal(int signo, const char *action
-#ifdef SA_SIGINFO
- ,
- siginfo_t *siginfo, void *program_counter
-#endif
- );
+extern void zlog_signal(int signo, const char *action, void *siginfo,
+ void *program_counter);
/* Log a backtrace. */
extern void zlog_backtrace(int priority);
diff --git a/lib/module.h b/lib/module.h
index c5f96db85..79cf52d75 100644
--- a/lib/module.h
+++ b/lib/module.h
@@ -24,16 +24,6 @@
extern "C" {
#endif
-#if !defined(__GNUC__)
-#error module code needs GCC visibility extensions
-#elif __GNUC__ < 4
-#error module code needs GCC visibility extensions
-#else
-# define DSO_PUBLIC __attribute__ ((visibility ("default")))
-# define DSO_SELF __attribute__ ((visibility ("protected")))
-# define DSO_LOCAL __attribute__ ((visibility ("hidden")))
-#endif
-
struct frrmod_runtime;
struct frrmod_info {
diff --git a/lib/nexthop.c b/lib/nexthop.c
index 57a2f1daa..4cea14955 100644
--- a/lib/nexthop.c
+++ b/lib/nexthop.c
@@ -32,6 +32,7 @@
#include "nexthop.h"
#include "mpls.h"
#include "jhash.h"
+#include "printfrr.h"
DEFINE_MTYPE_STATIC(LIB, NEXTHOP, "Nexthop")
DEFINE_MTYPE_STATIC(LIB, NH_LABEL, "Nexthop label")
@@ -423,3 +424,87 @@ uint32_t nexthop_hash(const struct nexthop *nexthop)
}
return key;
}
+
+/*
+ * nexthop printing variants:
+ * %pNHvv
+ * via 1.2.3.4
+ * via 1.2.3.4, eth0
+ * is directly connected, eth0
+ * unreachable (blackhole)
+ * %pNHv
+ * 1.2.3.4
+ * 1.2.3.4, via eth0
+ * directly connected, eth0
+ * unreachable (blackhole)
+ * %pNHs
+ * nexthop2str()
+ */
+printfrr_ext_autoreg_p("NH", printfrr_nh)
+static ssize_t printfrr_nh(char *buf, size_t bsz, const char *fmt,
+ int prec, const void *ptr)
+{
+ const struct nexthop *nexthop = ptr;
+ struct fbuf fb = { .buf = buf, .pos = buf, .len = bsz - 1 };
+ bool do_ifi = false;
+ const char *s, *v_is = "", *v_via = "", *v_viaif = "via ";
+ ssize_t ret = 3;
+
+ switch (fmt[2]) {
+ case 'v':
+ if (fmt[3] == 'v') {
+ v_is = "is ";
+ v_via = "via ";
+ v_viaif = "";
+ ret++;
+ }
+
+ switch (nexthop->type) {
+ case NEXTHOP_TYPE_IPV4:
+ case NEXTHOP_TYPE_IPV4_IFINDEX:
+ bprintfrr(&fb, "%s%pI4", v_via, &nexthop->gate.ipv4);
+ do_ifi = true;
+ break;
+ case NEXTHOP_TYPE_IPV6:
+ case NEXTHOP_TYPE_IPV6_IFINDEX:
+ bprintfrr(&fb, "%s%pI6", v_via, &nexthop->gate.ipv6);
+ do_ifi = true;
+ break;
+ case NEXTHOP_TYPE_IFINDEX:
+ bprintfrr(&fb, "%sdirectly connected, %s", v_is,
+ ifindex2ifname(nexthop->ifindex,
+ nexthop->vrf_id));
+ break;
+ case NEXTHOP_TYPE_BLACKHOLE:
+ switch (nexthop->bh_type) {
+ case BLACKHOLE_REJECT:
+ s = " (ICMP unreachable)";
+ break;
+ case BLACKHOLE_ADMINPROHIB:
+ s = " (ICMP admin-prohibited)";
+ break;
+ case BLACKHOLE_NULL:
+ s = " (blackhole)";
+ break;
+ default:
+ s = "";
+ break;
+ }
+ bprintfrr(&fb, "unreachable%s", s);
+ break;
+ default:
+ break;
+ }
+ if (do_ifi && nexthop->ifindex)
+ bprintfrr(&fb, ", %s%s", v_viaif, ifindex2ifname(
+ nexthop->ifindex,
+ nexthop->vrf_id));
+
+ *fb.pos = '\0';
+ return ret;
+ case 's':
+ nexthop2str(nexthop, buf, bsz);
+ return 3;
+ }
+ return 0;
+}
diff --git a/lib/prefix.c b/lib/prefix.c
index 42d202ddb..134d9cf90 100644
--- a/lib/prefix.c
+++ b/lib/prefix.c
@@ -28,6 +28,7 @@
#include "log.h"
#include "jhash.h"
#include "lib_errors.h"
+#include "printfrr.h"
DEFINE_MTYPE_STATIC(LIB, PREFIX, "Prefix")
DEFINE_MTYPE_STATIC(LIB, PREFIX_FLOWSPEC, "Prefix Flowspec")
@@ -1626,3 +1627,48 @@ char *esi_to_str(const esi_t *esi, char *buf, int size)
esi->val[9]);
return ptr;
}
+
+printfrr_ext_autoreg_p("I4", printfrr_i4)
+static ssize_t printfrr_i4(char *buf, size_t bsz, const char *fmt,
+ int prec, const void *ptr)
+{
+ inet_ntop(AF_INET, ptr, buf, bsz);
+ return 2;
+}
+
+printfrr_ext_autoreg_p("I6", printfrr_i6)
+static ssize_t printfrr_i6(char *buf, size_t bsz, const char *fmt,
+ int prec, const void *ptr)
+{
+ inet_ntop(AF_INET6, ptr, buf, bsz);
+ return 2;
+}
+
+printfrr_ext_autoreg_p("FX", printfrr_pfx)
+static ssize_t printfrr_pfx(char *buf, size_t bsz, const char *fmt,
+ int prec, const void *ptr)
+{
+ prefix2str(ptr, buf, bsz);
+ return 2;
+}
+
+printfrr_ext_autoreg_p("SG4", printfrr_psg)
+static ssize_t printfrr_psg(char *buf, size_t bsz, const char *fmt,
+ int prec, const void *ptr)
+{
+ const struct prefix_sg *sg = ptr;
+ struct fbuf fb = { .buf = buf, .pos = buf, .len = bsz - 1 };
+
+ if (sg->src.s_addr == INADDR_ANY)
+ bprintfrr(&fb, "(*,");
+ else
+ bprintfrr(&fb, "(%pI4,", &sg->src);
+
+ if (sg->grp.s_addr == INADDR_ANY)
+ bprintfrr(&fb, "*)");
+ else
+ bprintfrr(&fb, "%pI4)", &sg->grp);
+
+ fb.pos[0] = '\0';
+ return 3;
+}
diff --git a/lib/printf/README b/lib/printf/README
new file mode 100644
index 000000000..ac283642d
--- /dev/null
+++ b/lib/printf/README
@@ -0,0 +1,9 @@
+This is the printf implementation from FreeBSD. It was imported on 2019-05-12,
+from SVN revision 347514 (but the code hadn't been touched for 2 years before
+that.)
+
+Please don't reindent or otherwise mangle the files to make importing fixes
+easy (not that there are significant changes likely to happen...)
+
+The changes to this code are published under FreeBSD's license as listed in the
+file headers. If you change license, please make that as obvious as possible.
diff --git a/lib/printf/glue.c b/lib/printf/glue.c
new file mode 100644
index 000000000..1b760dc2d
--- /dev/null
+++ b/lib/printf/glue.c
@@ -0,0 +1,249 @@
+/*
+ * Copyright (c) 2019 David Lamparter, for NetDEF, Inc.
+ *
+ * Permission to use, copy, modify, and 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 THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <sys/types.h>
+#include <string.h>
+#include <wchar.h>
+
+#include "printfrr.h"
+#include "printflocal.h"
+
+ssize_t bprintfrr(struct fbuf *out, const char *fmt, ...)
+{
+ ssize_t ret;
+ va_list ap;
+
+ va_start(ap, fmt);
+ ret = vbprintfrr(out, fmt, ap);
+ va_end(ap);
+ return ret;
+}
+
+ssize_t vsnprintfrr(char *out, size_t outsz, const char *fmt, va_list ap)
+{
+ struct fbuf fbb = { .buf = out, .pos = out, .len = outsz - 1, };
+ struct fbuf *fb = (out && outsz) ? &fbb : NULL;
+ ssize_t ret;
+
+ ret = vbprintfrr(fb, fmt, ap);
+ if (fb)
+ fb->pos[0] = '\0';
+ return ret;
+}
+
+ssize_t snprintfrr(char *out, size_t outsz, const char *fmt, ...)
+{
+ struct fbuf fbb = { .buf = out, .pos = out, .len = outsz - 1, };
+ struct fbuf *fb = (out && outsz) ? &fbb : NULL;
+ ssize_t ret;
+ va_list ap;
+
+ va_start(ap, fmt);
+ ret = vbprintfrr(fb, fmt, ap);
+ va_end(ap);
+ if (fb)
+ fb->pos[0] = '\0';
+ return ret;
+}
+
+ssize_t vcsnprintfrr(char *out, size_t outsz, const char *fmt, va_list ap)
+{
+ if (!out || !outsz)
+ return vbprintfrr(NULL, fmt, ap);
+
+ struct fbuf fbb = { .buf = out, .pos = out, .len = outsz - 1, };
+ ssize_t ret;
+ size_t pos;
+
+ pos = strnlen(out, outsz);
+ fbb.pos += pos;
+
+ ret = vbprintfrr(&fbb, fmt, ap);
+ fbb.pos[0] = '\0';
+ return ret >= 0 ? ret + (ssize_t)pos : ret;
+}
+
+ssize_t csnprintfrr(char *out, size_t outsz, const char *fmt, ...)
+{
+ ssize_t ret;
+ va_list ap;
+
+ va_start(ap, fmt);
+ ret = vcsnprintfrr(out, outsz, fmt, ap);
+ va_end(ap);
+ return ret;
+}
+
+char *vasnprintfrr(struct memtype *mt, char *out, size_t outsz, const char *fmt,
+ va_list ap)
+{
+ struct fbuf fb = { .buf = out, .pos = out, .len = outsz - 1, };
+ ssize_t len;
+ va_list ap2;
+ char *ret = out;
+
+ va_copy(ap2, ap);
+ len = vbprintfrr(&fb, fmt, ap);
+ if (len < 0)
+ /* error = malformed format string => try something useful */
+ return qstrdup(mt, fmt);
+
+ if ((size_t)len >= outsz - 1) {
+ ret = qmalloc(mt, len + 1);
+ fb.buf = fb.pos = ret;
+ fb.len = len;
+
+ vbprintfrr(&fb, fmt, ap2);
+ }
+ ret[len] = '\0';
+ return ret;
+}
+
+char *asnprintfrr(struct memtype *mt, char *out, size_t outsz, const char *fmt,
+ ...)
+{
+ va_list ap;
+ char *ret;
+
+ va_start(ap, fmt);
+ ret = vasnprintfrr(mt, out, outsz, fmt, ap);
+ va_end(ap);
+ return ret;
+}
+
+char *vasprintfrr(struct memtype *mt, const char *fmt, va_list ap)
+{
+ char buf[256];
+ char *ret;
+
+ ret = vasnprintfrr(mt, buf, sizeof(buf), fmt, ap);
+
+ if (ret == buf)
+ ret = qstrdup(mt, ret);
+ return ret;
+}
+
+char *asprintfrr(struct memtype *mt, const char *fmt, ...)
+{
+ char buf[256];
+ va_list ap;
+ char *ret;
+
+ va_start(ap, fmt);
+ ret = vasnprintfrr(mt, buf, sizeof(buf), fmt, ap);
+ va_end(ap);
+
+ if (ret == buf)
+ ret = qstrdup(mt, ret);
+ return ret;
+}
+
+/* Q: WTF?
+ * A: since printf should be reasonably fast (think debugging logs), the idea
+ * here is to keep things close by each other in a cacheline. That's why
+ * ext_quick just has the first 2 characters of an extension, and we do a
+ * nice linear continuous sweep. Only if we find something, we go do more
+ * expensive things.
+ *
+ * Q: doesn't this need a mutex/lock?
+ * A: theoretically, yes, but that's quite expensive and I rather elide that
+ * necessity by putting down some usage rules. Just call this at startup
+ * while singlethreaded and all is fine. Ideally, just use constructors
+ * (and make sure dlopen() doesn't mess things up...)
+ */
+#define MAXEXT 64
+
+struct ext_quick {
+ char fmt[2];
+};
+
+static uint8_t ext_offsets[26] __attribute__((aligned(32)));
+static struct ext_quick entries[MAXEXT] __attribute__((aligned(64)));
+static const struct printfrr_ext *exts[MAXEXT] __attribute__((aligned(64)));
+
+void printfrr_ext_reg(const struct printfrr_ext *ext)
+{
+ uint8_t o;
+ ptrdiff_t i;
+
+ if (!printfrr_ext_char(ext->match[0]))
+ return;
+
+ o = ext->match[0] - 'A';
+ for (i = ext_offsets[o];
+ i < MAXEXT && entries[i].fmt[0] &&
+ memcmp(entries[i].fmt, ext->match, 2) < 0;
+ i++)
+ ;
+ if (i == MAXEXT)
+ return;
+ for (o++; o <= 'Z' - 'A'; o++)
+ ext_offsets[o]++;
+
+ memmove(entries + i + 1, entries + i,
+ (MAXEXT - i - 1) * sizeof(entries[0]));
+ memmove(exts + i + 1, exts + i,
+ (MAXEXT - i - 1) * sizeof(exts[0]));
+
+ memcpy(entries[i].fmt, ext->match, 2);
+ exts[i] = ext;
+}
+
+ssize_t printfrr_extp(char *buf, size_t sz, const char *fmt, int prec,
+ const void *ptr)
+{
+ const struct printfrr_ext *ext;
+ size_t i;
+
+ for (i = ext_offsets[fmt[0] - 'A']; i < MAXEXT; i++) {
+ if (!entries[i].fmt[0] || entries[i].fmt[0] > fmt[0])
+ return 0;
+ if (entries[i].fmt[1] && entries[i].fmt[1] != fmt[1])
+ continue;
+ ext = exts[i];
+ if (!ext->print_ptr)
+ continue;
+ if (strncmp(ext->match, fmt, strlen(ext->match)))
+ continue;
+ return ext->print_ptr(buf, sz, fmt, prec, ptr);
+ }
+ return 0;
+}
+
+ssize_t printfrr_exti(char *buf, size_t sz, const char *fmt, int prec,
+ uintmax_t num)
+{
+ const struct printfrr_ext *ext;
+ size_t i;
+
+ for (i = ext_offsets[fmt[0] - 'A']; i < MAXEXT; i++) {
+ if (!entries[i].fmt[0] || entries[i].fmt[0] > fmt[0])
+ return 0;
+ if (entries[i].fmt[1] && entries[i].fmt[1] != fmt[1])
+ continue;
+ ext = exts[i];
+ if (!ext->print_int)
+ continue;
+ if (strncmp(ext->match, fmt, strlen(ext->match)))
+ continue;
+ return ext->print_int(buf, sz, fmt, prec, num);
+ }
+ return 0;
+}
diff --git a/lib/printf/printf-pos.c b/lib/printf/printf-pos.c
new file mode 100644
index 000000000..399573e6c
--- /dev/null
+++ b/lib/printf/printf-pos.c
@@ -0,0 +1,786 @@
+/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef HAVE_SYS_CDEFS_H
+#include <sys/cdefs.h>
+#endif
+
+/*
+ * This is the code responsible for handling positional arguments
+ * (%m$ and %m$.n$) for vfprintf() and vfwprintf().
+ */
+
+#include <sys/types.h>
+
+#include <limits.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <wchar.h>
+
+#include "printflocal.h"
+
+#ifdef NL_ARGMAX
+#define MAX_POSARG NL_ARGMAX
+#else
+#define MAX_POSARG 65536
+#endif
+
+/*
+ * Type ids for argument type table.
+ */
+enum typeid {
+ T_UNUSED, TP_SHORT, T_INT, T_U_INT, TP_INT,
+ T_LONG, T_U_LONG, TP_LONG, T_LLONG, T_U_LLONG, TP_LLONG,
+ T_PTRDIFFT, TP_PTRDIFFT, T_SSIZET, T_SIZET, TP_SSIZET,
+ T_INT64T, T_UINT64T, T_INTMAXT, T_UINTMAXT, TP_INTMAXT, TP_VOID,
+ TP_CHAR, TP_SCHAR, T_DOUBLE, T_LONG_DOUBLE, T_WINT, TP_WCHAR
+};
+
+/* An expandable array of types. */
+struct typetable {
+ enum typeid *table; /* table of types */
+ enum typeid stattable[STATIC_ARG_TBL_SIZE];
+ u_int tablesize; /* current size of type table */
+ u_int tablemax; /* largest used index in table */
+ u_int nextarg; /* 1-based argument index */
+};
+
+static int __grow_type_table(struct typetable *);
+static void build_arg_table (struct typetable *, va_list, union arg **);
+
+/*
+ * Initialize a struct typetable.
+ */
+static inline void
+inittypes(struct typetable *types)
+{
+ u_int n;
+
+ types->table = types->stattable;
+ types->tablesize = STATIC_ARG_TBL_SIZE;
+ types->tablemax = 0;
+ types->nextarg = 1;
+ for (n = 0; n < STATIC_ARG_TBL_SIZE; n++)
+ types->table[n] = T_UNUSED;
+}
+
+/*
+ * struct typetable destructor.
+ */
+static inline void
+freetypes(struct typetable *types)
+{
+
+ if (types->table != types->stattable)
+ free (types->table);
+}
+
+/*
+ * Ensure that there is space to add a new argument type to the type table.
+ * Expand the table if necessary. Returns 0 on success.
+ */
+static inline int
+_ensurespace(struct typetable *types)
+{
+
+ if (types->nextarg >= types->tablesize) {
+ if (__grow_type_table(types))
+ return (-1);
+ }
+ if (types->nextarg > types->tablemax)
+ types->tablemax = types->nextarg;
+ return (0);
+}
+
+/*
+ * Add an argument type to the table, expanding if necessary.
+ * Returns 0 on success.
+ */
+static inline int
+addtype(struct typetable *types, enum typeid type)
+{
+
+ if (_ensurespace(types))
+ return (-1);
+ types->table[types->nextarg++] = type;
+ return (0);
+}
+
+static inline int
+addsarg(struct typetable *types, int flags)
+{
+
+ if (_ensurespace(types))
+ return (-1);
+ if (flags & LONGDBL)
+ types->table[types->nextarg++] = T_INT64T;
+ else if (flags & INTMAXT)
+ types->table[types->nextarg++] = T_INTMAXT;
+ else if (flags & SIZET)
+ types->table[types->nextarg++] = T_SSIZET;
+ else if (flags & PTRDIFFT)
+ types->table[types->nextarg++] = T_PTRDIFFT;
+ else if (flags & LLONGINT)
+ types->table[types->nextarg++] = T_LLONG;
+ else if (flags & LONGINT)
+ types->table[types->nextarg++] = T_LONG;
+ else
+ types->table[types->nextarg++] = T_INT;
+ return (0);
+}
+
+static inline int
+adduarg(struct typetable *types, int flags)
+{
+
+ if (_ensurespace(types))
+ return (-1);
+ if (flags & LONGDBL)
+ types->table[types->nextarg++] = T_UINT64T;
+ else if (flags & INTMAXT)
+ types->table[types->nextarg++] = T_UINTMAXT;
+ else if (flags & SIZET)
+ types->table[types->nextarg++] = T_SIZET;
+ else if (flags & PTRDIFFT)
+ types->table[types->nextarg++] = T_SIZET;
+ else if (flags & LLONGINT)
+ types->table[types->nextarg++] = T_U_LLONG;
+ else if (flags & LONGINT)
+ types->table[types->nextarg++] = T_U_LONG;
+ else
+ types->table[types->nextarg++] = T_U_INT;
+ return (0);
+}
+
+/*
+ * Add * arguments to the type array.
+ */
+static inline int
+addaster(struct typetable *types, char **fmtp)
+{
+ char *cp;
+ u_int n2;
+
+ n2 = 0;
+ cp = *fmtp;
+ while (is_digit(*cp)) {
+ n2 = 10 * n2 + to_digit(*cp);
+ cp++;
+ }
+ if (*cp == '$') {
+ u_int hold = types->nextarg;
+ types->nextarg = n2;
+ if (addtype(types, T_INT))
+ return (-1);
+ types->nextarg = hold;
+ *fmtp = ++cp;
+ } else {
+ if (addtype(types, T_INT))
+ return (-1);
+ }
+ return (0);
+}
+
+#ifdef WCHAR_SUPPORT
+static inline int
+addwaster(struct typetable *types, wchar_t **fmtp)
+{
+ wchar_t *cp;
+ u_int n2;
+
+ n2 = 0;
+ cp = *fmtp;
+ while (is_digit(*cp)) {
+ n2 = 10 * n2 + to_digit(*cp);
+ cp++;
+ }
+ if (*cp == '$') {
+ u_int hold = types->nextarg;
+ types->nextarg = n2;
+ if (addtype(types, T_INT))
+ return (-1);
+ types->nextarg = hold;
+ *fmtp = ++cp;
+ } else {
+ if (addtype(types, T_INT))
+ return (-1);
+ }
+ return (0);
+}
+#endif /* WCHAR_SUPPORT */
+
+/*
+ * Find all arguments when a positional parameter is encountered. Returns a
+ * table, indexed by argument number, of pointers to each arguments. The
+ * initial argument table should be an array of STATIC_ARG_TBL_SIZE entries.
+ * It will be replaces with a malloc-ed one if it overflows.
+ * Returns 0 on success. On failure, returns nonzero and sets errno.
+ */
+int
+_frr_find_arguments (const char *fmt0, va_list ap, union arg **argtable)
+{
+ char *fmt; /* format string */
+ int ch; /* character from fmt */
+ u_int n; /* handy integer (short term usage) */
+ int error;
+ int flags; /* flags as above */
+ struct typetable types; /* table of types */
+
+ fmt = (char *)fmt0;
+ inittypes(&types);
+ error = 0;
+
+ /*
+ * Scan the format for conversions (`%' character).
+ */
+ for (;;) {
+ while ((ch = *fmt) != '\0' && ch != '%')
+ fmt++;
+ if (ch == '\0')
+ goto done;
+ fmt++; /* skip over '%' */
+
+ flags = 0;
+
+rflag: ch = *fmt++;
+reswitch: switch (ch) {
+ case ' ':
+ case '#':
+ goto rflag;
+ case '*':
+ if ((error = addaster(&types, &fmt)))
+ goto error;
+ goto rflag;
+ case '-':
+ case '+':
+ case '\'':
+ goto rflag;
+ case '.':
+ if ((ch = *fmt++) == '*') {
+ if ((error = addaster(&types, &fmt)))
+ goto error;
+ goto rflag;
+ }
+ while (is_digit(ch)) {
+ ch = *fmt++;
+ }
+ goto reswitch;
+ case '0':
+ goto rflag;
+ case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ n = 0;
+ do {
+ n = 10 * n + to_digit(ch);
+ /* Detect overflow */
+ if (n > MAX_POSARG) {
+ error = -1;
+ goto error;
+ }
+ ch = *fmt++;
+ } while (is_digit(ch));
+ if (ch == '$') {
+ types.nextarg = n;
+ goto rflag;
+ }
+ goto reswitch;
+ case 'L':
+ flags |= LONGDBL;
+ goto rflag;
+ case 'h':
+ if (flags & SHORTINT) {
+ flags &= ~SHORTINT;
+ flags |= CHARINT;
+ } else
+ flags |= SHORTINT;
+ goto rflag;
+ case 'j':
+ flags |= INTMAXT;
+ goto rflag;
+ case 'l':
+ if (flags & LONGINT) {
+ flags &= ~LONGINT;
+ flags |= LLONGINT;
+ } else
+ flags |= LONGINT;
+ goto rflag;
+ case 'q':
+ flags |= LLONGINT; /* not necessarily */
+ goto rflag;
+ case 't':
+ flags |= PTRDIFFT;
+ goto rflag;
+ case 'z':
+ flags |= SIZET;
+ goto rflag;
+ case 'C':
+ flags |= LONGINT;
+ /*FALLTHROUGH*/
+ case 'c':
+ error = addtype(&types,
+ (flags & LONGINT) ? T_WINT : T_INT);
+ if (error)
+ goto error;
+ break;
+ case 'D':
+ flags |= LONGINT;
+ /*FALLTHROUGH*/
+ case 'd':
+ case 'i':
+ if ((error = addsarg(&types, flags)))
+ goto error;
+ break;
+#ifndef NO_FLOATING_POINT
+ case 'a':
+ case 'A':
+ case 'e':
+ case 'E':
+ case 'f':
+ case 'g':
+ case 'G':
+ error = addtype(&types,
+ (flags & LONGDBL) ? T_LONG_DOUBLE : T_DOUBLE);
+ if (error)
+ goto error;
+ break;
+#endif /* !NO_FLOATING_POINT */
+ case 'n':
+ if (flags & INTMAXT)
+ error = addtype(&types, TP_INTMAXT);
+ else if (flags & PTRDIFFT)
+ error = addtype(&types, TP_PTRDIFFT);
+ else if (flags & SIZET)
+ error = addtype(&types, TP_SSIZET);
+ else if (flags & LLONGINT)
+ error = addtype(&types, TP_LLONG);
+ else if (flags & LONGINT)
+ error = addtype(&types, TP_LONG);
+ else if (flags & SHORTINT)
+ error = addtype(&types, TP_SHORT);
+ else if (flags & CHARINT)
+ error = addtype(&types, TP_SCHAR);
+ else
+ error = addtype(&types, TP_INT);
+ if (error)
+ goto error;
+ continue; /* no output */
+ case 'O':
+ flags |= LONGINT;
+ /*FALLTHROUGH*/
+ case 'o':
+ if ((error = adduarg(&types, flags)))
+ goto error;
+ break;
+ case 'p':
+ if ((error = addtype(&types, TP_VOID)))
+ goto error;
+ break;
+ case 'S':
+ flags |= LONGINT;
+ /*FALLTHROUGH*/
+ case 's':
+ error = addtype(&types,
+ (flags & LONGINT) ? TP_WCHAR : TP_CHAR);
+ if (error)
+ goto error;
+ break;
+ case 'U':
+ flags |= LONGINT;
+ /*FALLTHROUGH*/
+ case 'u':
+ case 'X':
+ case 'x':
+ if ((error = adduarg(&types, flags)))
+ goto error;
+ break;
+ default: /* "%?" prints ?, unless ? is NUL */
+ if (ch == '\0')
+ goto done;
+ break;
+ }
+ }
+done:
+ build_arg_table(&types, ap, argtable);
+error:
+ freetypes(&types);
+ return (error || *argtable == NULL);
+}
+
+#ifdef WCHAR_SUPPORT
+/* wchar version of __find_arguments. */
+int
+_frr_find_warguments (const wchar_t *fmt0, va_list ap, union arg **argtable)
+{
+ wchar_t *fmt; /* format string */
+ wchar_t ch; /* character from fmt */
+ u_int n; /* handy integer (short term usage) */
+ int error;
+ int flags; /* flags as above */
+ struct typetable types; /* table of types */
+
+ fmt = (wchar_t *)fmt0;
+ inittypes(&types);
+ error = 0;
+
+ /*
+ * Scan the format for conversions (`%' character).
+ */
+ for (;;) {
+ while ((ch = *fmt) != '\0' && ch != '%')
+ fmt++;
+ if (ch == '\0')
+ goto done;
+ fmt++; /* skip over '%' */
+
+ flags = 0;
+
+rflag: ch = *fmt++;
+reswitch: switch (ch) {
+ case ' ':
+ case '#':
+ goto rflag;
+ case '*':
+ if ((error = addwaster(&types, &fmt)))
+ goto error;
+ goto rflag;
+ case '-':
+ case '+':
+ case '\'':
+ goto rflag;
+ case '.':
+ if ((ch = *fmt++) == '*') {
+ if ((error = addwaster(&types, &fmt)))
+ goto error;
+ goto rflag;
+ }
+ while (is_digit(ch)) {
+ ch = *fmt++;
+ }
+ goto reswitch;
+ case '0':
+ goto rflag;
+ case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ n = 0;
+ do {
+ n = 10 * n + to_digit(ch);
+ /* Detect overflow */
+ if (n > MAX_POSARG) {
+ error = -1;
+ goto error;
+ }
+ ch = *fmt++;
+ } while (is_digit(ch));
+ if (ch == '$') {
+ types.nextarg = n;
+ goto rflag;
+ }
+ goto reswitch;
+ case 'L':
+ flags |= LONGDBL;
+ goto rflag;
+ case 'h':
+ if (flags & SHORTINT) {
+ flags &= ~SHORTINT;
+ flags |= CHARINT;
+ } else
+ flags |= SHORTINT;
+ goto rflag;
+ case 'j':
+ flags |= INTMAXT;
+ goto rflag;
+ case 'l':
+ if (flags & LONGINT) {
+ flags &= ~LONGINT;
+ flags |= LLONGINT;
+ } else
+ flags |= LONGINT;
+ goto rflag;
+ case 'q':
+ flags |= LLONGINT; /* not necessarily */
+ goto rflag;
+ case 't':
+ flags |= PTRDIFFT;
+ goto rflag;
+ case 'z':
+ flags |= SIZET;
+ goto rflag;
+ case 'C':
+ flags |= LONGINT;
+ /*FALLTHROUGH*/
+ case 'c':
+ error = addtype(&types,
+ (flags & LONGINT) ? T_WINT : T_INT);
+ if (error)
+ goto error;
+ break;
+ case 'D':
+ flags |= LONGINT;
+ /*FALLTHROUGH*/
+ case 'd':
+ case 'i':
+ if ((error = addsarg(&types, flags)))
+ goto error;
+ break;
+#ifndef NO_FLOATING_POINT
+ case 'a':
+ case 'A':
+ case 'e':
+ case 'E':
+ case 'f':
+ case 'g':
+ case 'G':
+ error = addtype(&types,
+ (flags & LONGDBL) ? T_LONG_DOUBLE : T_DOUBLE);
+ if (error)
+ goto error;
+ break;
+#endif /* !NO_FLOATING_POINT */
+ case 'n':
+ if (flags & INTMAXT)
+ error = addtype(&types, TP_INTMAXT);
+ else if (flags & PTRDIFFT)
+ error = addtype(&types, TP_PTRDIFFT);
+ else if (flags & SIZET)
+ error = addtype(&types, TP_SSIZET);
+ else if (flags & LLONGINT)
+ error = addtype(&types, TP_LLONG);
+ else if (flags & LONGINT)
+ error = addtype(&types, TP_LONG);
+ else if (flags & SHORTINT)
+ error = addtype(&types, TP_SHORT);
+ else if (flags & CHARINT)
+ error = addtype(&types, TP_SCHAR);
+ else
+ error = addtype(&types, TP_INT);
+ if (error)
+ goto error;
+ continue; /* no output */
+ case 'O':
+ flags |= LONGINT;
+ /*FALLTHROUGH*/
+ case 'o':
+ if ((error = adduarg(&types, flags)))
+ goto error;
+ break;
+ case 'p':
+ if ((error = addtype(&types, TP_VOID)))
+ goto error;
+ break;
+ case 'S':
+ flags |= LONGINT;
+ /*FALLTHROUGH*/
+ case 's':
+ error = addtype(&types,
+ (flags & LONGINT) ? TP_WCHAR : TP_CHAR);
+ if (error)
+ goto error;
+ break;
+ case 'U':
+ flags |= LONGINT;
+ /*FALLTHROUGH*/
+ case 'u':
+ case 'X':
+ case 'x':
+ if ((error = adduarg(&types, flags)))
+ goto error;
+ break;
+ default: /* "%?" prints ?, unless ? is NUL */
+ if (ch == '\0')
+ goto done;
+ break;
+ }
+ }
+done:
+ build_arg_table(&types, ap, argtable);
+error:
+ freetypes(&types);
+ return (error || *argtable == NULL);
+}
+#endif /* WCHAR_SUPPORT */
+
+/*
+ * Increase the size of the type table. Returns 0 on success.
+ */
+static int
+__grow_type_table(struct typetable *types)
+{
+ enum typeid *const oldtable = types->table;
+ const int oldsize = types->tablesize;
+ enum typeid *newtable;
+ u_int n, newsize;
+
+ /* Detect overflow */
+ if (types->nextarg > MAX_POSARG)
+ return (-1);
+
+ newsize = oldsize * 2;
+ if (newsize < types->nextarg + 1)
+ newsize = types->nextarg + 1;
+ if (oldsize == STATIC_ARG_TBL_SIZE) {
+ if ((newtable = malloc(newsize * sizeof(enum typeid))) == NULL)
+ return (-1);
+ bcopy(oldtable, newtable, oldsize * sizeof(enum typeid));
+ } else {
+ newtable = realloc(oldtable, newsize * sizeof(enum typeid));
+ if (newtable == NULL)
+ return (-1);
+ }
+ for (n = oldsize; n < newsize; n++)
+ newtable[n] = T_UNUSED;
+
+ types->table = newtable;
+ types->tablesize = newsize;
+
+ return (0);
+}
+
+/*
+ * Build the argument table from the completed type table.
+ * On malloc failure, *argtable is set to NULL.
+ */
+static void
+build_arg_table(struct typetable *types, va_list ap, union arg **argtable)
+{
+ u_int n;
+
+ if (types->tablemax >= STATIC_ARG_TBL_SIZE) {
+ *argtable = (union arg *)
+ malloc (sizeof (union arg) * (types->tablemax + 1));
+ if (*argtable == NULL)
+ return;
+ }
+
+ (*argtable) [0].intarg = 0;
+ for (n = 1; n <= types->tablemax; n++) {
+ switch (types->table[n]) {
+ case T_UNUSED: /* whoops! */
+ (*argtable) [n].intarg = va_arg (ap, int);
+ break;
+ case TP_SCHAR:
+ (*argtable) [n].pschararg = va_arg (ap, signed char *);
+ break;
+ case TP_SHORT:
+ (*argtable) [n].pshortarg = va_arg (ap, short *);
+ break;
+ case T_INT:
+ (*argtable) [n].intarg = va_arg (ap, int);
+ break;
+ case T_U_INT:
+ (*argtable) [n].uintarg = va_arg (ap, unsigned int);
+ break;
+ case TP_INT:
+ (*argtable) [n].pintarg = va_arg (ap, int *);
+ break;
+ case T_LONG:
+ (*argtable) [n].longarg = va_arg (ap, long);
+ break;
+ case T_U_LONG:
+ (*argtable) [n].ulongarg = va_arg (ap, unsigned long);
+ break;
+ case TP_LONG:
+ (*argtable) [n].plongarg = va_arg (ap, long *);
+ break;
+ case T_LLONG:
+ (*argtable) [n].longlongarg = va_arg (ap, long long);
+ break;
+ case T_U_LLONG:
+ (*argtable) [n].ulonglongarg = va_arg (ap, unsigned long long);
+ break;
+ case TP_LLONG:
+ (*argtable) [n].plonglongarg = va_arg (ap, long long *);
+ break;
+ case T_PTRDIFFT:
+ (*argtable) [n].ptrdiffarg = va_arg (ap, ptrdiff_t);
+ break;
+ case TP_PTRDIFFT:
+ (*argtable) [n].pptrdiffarg = va_arg (ap, ptrdiff_t *);
+ break;
+ case T_SIZET:
+ (*argtable) [n].sizearg = va_arg (ap, size_t);
+ break;
+ case T_SSIZET:
+ (*argtable) [n].sizearg = va_arg (ap, ssize_t);
+ break;
+ case TP_SSIZET:
+ (*argtable) [n].pssizearg = va_arg (ap, ssize_t *);
+ break;
+ case T_INTMAXT:
+ (*argtable) [n].intmaxarg = va_arg (ap, intmax_t);
+ break;
+ case T_UINTMAXT:
+ (*argtable) [n].uintmaxarg = va_arg (ap, uintmax_t);
+ break;
+ case TP_INTMAXT:
+ (*argtable) [n].pintmaxarg = va_arg (ap, intmax_t *);
+ break;
+ case T_INT64T:
+ (*argtable) [n].intmaxarg = va_arg (ap, int64_t);
+ break;
+ case T_UINT64T:
+ (*argtable) [n].uintmaxarg = va_arg (ap, uint64_t);
+ break;
+ case T_DOUBLE:
+#ifndef NO_FLOATING_POINT
+ (*argtable) [n].doublearg = va_arg (ap, double);
+#endif
+ break;
+ case T_LONG_DOUBLE:
+#ifndef NO_FLOATING_POINT
+ (*argtable) [n].longdoublearg = va_arg (ap, long double);
+#endif
+ break;
+ case TP_CHAR:
+ (*argtable) [n].pchararg = va_arg (ap, char *);
+ break;
+ case TP_VOID:
+ (*argtable) [n].pvoidarg = va_arg (ap, void *);
+ break;
+ case T_WINT:
+ (*argtable) [n].wintarg = va_arg (ap, wint_t);
+ break;
+ case TP_WCHAR:
+ (*argtable) [n].pwchararg = va_arg (ap, wchar_t *);
+ break;
+ }
+ }
+}
diff --git a/lib/printf/printfcommon.h b/lib/printf/printfcommon.h
new file mode 100644
index 000000000..5c45520b4
--- /dev/null
+++ b/lib/printf/printfcommon.h
@@ -0,0 +1,244 @@
+/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+/*
+ * This file defines common routines used by both printf and wprintf.
+ * You must define CHAR to either char or wchar_t prior to including this.
+ */
+
+
+static CHAR *__ujtoa(uintmax_t, CHAR *, int, int, const char *);
+static CHAR *__ultoa(u_long, CHAR *, int, int, const char *);
+
+#define NIOV 8
+struct io_state {
+ struct fbuf *cb;
+ size_t avail;
+};
+
+static inline void
+io_init(struct io_state *iop, struct fbuf *cb)
+{
+ iop->cb = cb;
+ iop->avail = cb ? cb->len - (cb->pos - cb->buf) : 0;
+}
+
+/*
+ * WARNING: The buffer passed to io_print() is not copied immediately; it must
+ * remain valid until io_flush() is called.
+ */
+static inline int
+io_print(struct io_state *iop, const CHAR * __restrict ptr, size_t len)
+{
+ size_t copylen = len;
+
+ if (!iop->cb)
+ return 0;
+ if (iop->avail < copylen)
+ copylen = iop->avail;
+
+ memcpy(iop->cb->pos, ptr, copylen);
+ iop->avail -= copylen;
+ iop->cb->pos += copylen;
+ return 0;
+}
+
+/*
+ * Choose PADSIZE to trade efficiency vs. size. If larger printf
+ * fields occur frequently, increase PADSIZE and make the initialisers
+ * below longer.
+ */
+#define PADSIZE 16 /* pad chunk size */
+static const CHAR blanks[PADSIZE] =
+{' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '};
+static const CHAR zeroes[PADSIZE] =
+{'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'};
+
+/*
+ * Pad with blanks or zeroes. 'with' should point to either the blanks array
+ * or the zeroes array.
+ */
+static inline int
+io_pad(struct io_state *iop, int howmany, const CHAR * __restrict with)
+{
+ int n;
+
+ while (howmany > 0) {
+ n = (howmany >= PADSIZE) ? PADSIZE : howmany;
+ if (io_print(iop, with, n))
+ return (-1);
+ howmany -= n;
+ }
+ return (0);
+}
+
+/*
+ * Print exactly len characters of the string spanning p to ep, truncating
+ * or padding with 'with' as necessary.
+ */
+static inline int
+io_printandpad(struct io_state *iop, const CHAR *p, const CHAR *ep,
+ int len, const CHAR * __restrict with)
+{
+ int p_len;
+
+ p_len = ep - p;
+ if (p_len > len)
+ p_len = len;
+ if (p_len > 0) {
+ if (io_print(iop, p, p_len))
+ return (-1);
+ } else {
+ p_len = 0;
+ }
+ return (io_pad(iop, len - p_len, with));
+}
+
+/*
+ * Convert an unsigned long to ASCII for printf purposes, returning
+ * a pointer to the first character of the string representation.
+ * Octal numbers can be forced to have a leading zero; hex numbers
+ * use the given digits.
+ */
+static CHAR *
+__ultoa(u_long val, CHAR *endp, int base, int octzero, const char *xdigs)
+{
+ CHAR *cp = endp;
+ long sval;
+
+ /*
+ * Handle the three cases separately, in the hope of getting
+ * better/faster code.
+ */
+ switch (base) {
+ case 10:
+ if (val < 10) { /* many numbers are 1 digit */
+ *--cp = to_char(val);
+ return (cp);
+ }
+ /*
+ * On many machines, unsigned arithmetic is harder than
+ * signed arithmetic, so we do at most one unsigned mod and
+ * divide; this is sufficient to reduce the range of
+ * the incoming value to where signed arithmetic works.
+ */
+ if (val > LONG_MAX) {
+ *--cp = to_char(val % 10);
+ sval = val / 10;
+ } else
+ sval = val;
+ do {
+ *--cp = to_char(sval % 10);
+ sval /= 10;
+ } while (sval != 0);
+ break;
+
+ case 8:
+ do {
+ *--cp = to_char(val & 7);
+ val >>= 3;
+ } while (val);
+ if (octzero && *cp != '0')
+ *--cp = '0';
+ break;
+
+ case 16:
+ do {
+ *--cp = xdigs[val & 15];
+ val >>= 4;
+ } while (val);
+ break;
+
+ default: /* oops */
+ abort();
+ }
+ return (cp);
+}
+
+/* Identical to __ultoa, but for intmax_t. */
+static CHAR *
+__ujtoa(uintmax_t val, CHAR *endp, int base, int octzero, const char *xdigs)
+{
+ CHAR *cp = endp;
+ intmax_t sval;
+
+ /* quick test for small values; __ultoa is typically much faster */
+ /* (perhaps instead we should run until small, then call __ultoa?) */
+ if (val <= ULONG_MAX)
+ return (__ultoa((u_long)val, endp, base, octzero, xdigs));
+ switch (base) {
+ case 10:
+ if (val < 10) {
+ *--cp = to_char(val % 10);
+ return (cp);
+ }
+ if (val > INTMAX_MAX) {
+ *--cp = to_char(val % 10);
+ sval = val / 10;
+ } else
+ sval = val;
+ do {
+ *--cp = to_char(sval % 10);
+ sval /= 10;
+ } while (sval != 0);
+ break;
+
+ case 8:
+ do {
+ *--cp = to_char(val & 7);
+ val >>= 3;
+ } while (val);
+ if (octzero && *cp != '0')
+ *--cp = '0';
+ break;
+
+ case 16:
+ do {
+ *--cp = xdigs[val & 15];
+ val >>= 4;
+ } while (val);
+ break;
+
+ default:
+ abort();
+ }
+ return (cp);
+}
diff --git a/lib/printf/printflocal.h b/lib/printf/printflocal.h
new file mode 100644
index 000000000..335e09872
--- /dev/null
+++ b/lib/printf/printflocal.h
@@ -0,0 +1,105 @@
+/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include "compiler.h"
+#include "printfrr.h"
+
+/*
+ * Flags used during conversion.
+ */
+#define ALT 0x001 /* alternate form */
+#define LADJUST 0x004 /* left adjustment */
+#define LONGDBL 0x008 /* long double */
+#define LONGINT 0x010 /* long integer */
+#define LLONGINT 0x020 /* long long integer */
+#define SHORTINT 0x040 /* short integer */
+#define ZEROPAD 0x080 /* zero (as opposed to blank) pad */
+#define FPT 0x100 /* Floating point number */
+#define GROUPING 0x200 /* use grouping ("'" flag) */
+ /* C99 additional size modifiers: */
+#define SIZET 0x400 /* size_t */
+#define PTRDIFFT 0x800 /* ptrdiff_t */
+#define INTMAXT 0x1000 /* intmax_t */
+#define CHARINT 0x2000 /* print char using int format */
+
+/*
+ * Macros for converting digits to letters and vice versa
+ */
+#define to_digit(c) ((c) - '0')
+#define is_digit(c) ((unsigned)to_digit(c) <= 9)
+#define to_char(n) ((n) + '0')
+
+/* Size of the static argument table. */
+#define STATIC_ARG_TBL_SIZE 8
+
+union arg {
+ int intarg;
+ u_int uintarg;
+ long longarg;
+ u_long ulongarg;
+ long long longlongarg;
+ unsigned long long ulonglongarg;
+ ptrdiff_t ptrdiffarg;
+ size_t sizearg;
+ intmax_t intmaxarg;
+ uintmax_t uintmaxarg;
+ void *pvoidarg;
+ char *pchararg;
+ signed char *pschararg;
+ short *pshortarg;
+ int *pintarg;
+ long *plongarg;
+ long long *plonglongarg;
+ ptrdiff_t *pptrdiffarg;
+ ssize_t *pssizearg;
+ intmax_t *pintmaxarg;
+#ifndef NO_FLOATING_POINT
+ double doublearg;
+ long double longdoublearg;
+#endif
+ wint_t wintarg;
+ wchar_t *pwchararg;
+};
+
+/* Handle positional parameters. */
+int _frr_find_arguments(const char *, va_list, union arg **) DSO_LOCAL;
+#ifdef WCHAR_SUPPORT
+int _frr_find_warguments(const wchar_t *, va_list, union arg **) DSO_LOCAL;
+#endif
+
+/* returns number of bytes consumed for extended specifier */
+ssize_t printfrr_extp(char *, size_t, const char *, int, const void *) DSO_LOCAL;
+ssize_t printfrr_exti(char *, size_t, const char *, int, uintmax_t) DSO_LOCAL;
diff --git a/lib/printf/vfprintf.c b/lib/printf/vfprintf.c
new file mode 100644
index 000000000..07df6dd8f
--- /dev/null
+++ b/lib/printf/vfprintf.c
@@ -0,0 +1,730 @@
+/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef HAVE_SYS_CDEFS_H
+#include <sys/cdefs.h>
+#endif
+
+/*
+ * Actual printf innards.
+ *
+ * This code is large and complicated...
+ */
+
+#include <sys/types.h>
+#include <sys/uio.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <limits.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <wchar.h>
+
+#include <stdarg.h>
+
+#include "printflocal.h"
+
+#define CHAR char
+#include "printfcommon.h"
+
+#ifdef WCHAR_SUPPORT
+/*
+ * Convert a wide character string argument for the %ls format to a multibyte
+ * string representation. If not -1, prec specifies the maximum number of
+ * bytes to output, and also means that we can't assume that the wide char.
+ * string ends is null-terminated.
+ */
+static char *
+__wcsconv(wchar_t *wcsarg, int prec)
+{
+ static const mbstate_t initial;
+ mbstate_t mbs;
+ char buf[MB_LEN_MAX];
+ wchar_t *p;
+ char *convbuf;
+ size_t clen, nbytes;
+
+ /* Allocate space for the maximum number of bytes we could output. */
+ if (prec < 0) {
+ p = wcsarg;
+ mbs = initial;
+ nbytes = wcsrtombs(NULL, (const wchar_t **)&p, 0, &mbs);
+ if (nbytes == (size_t)-1)
+ return (NULL);
+ } else {
+ /*
+ * Optimisation: if the output precision is small enough,
+ * just allocate enough memory for the maximum instead of
+ * scanning the string.
+ */
+ if (prec < 128)
+ nbytes = prec;
+ else {
+ nbytes = 0;
+ p = wcsarg;
+ mbs = initial;
+ for (;;) {
+ clen = wcrtomb(buf, *p++, &mbs);
+ if (clen == 0 || clen == (size_t)-1 ||
+ nbytes + clen > (size_t)prec)
+ break;
+ nbytes += clen;
+ }
+ }
+ }
+ if ((convbuf = malloc(nbytes + 1)) == NULL)
+ return (NULL);
+
+ /* Fill the output buffer. */
+ p = wcsarg;
+ mbs = initial;
+ if ((nbytes = wcsrtombs(convbuf, (const wchar_t **)&p,
+ nbytes, &mbs)) == (size_t)-1) {
+ free(convbuf);
+ return (NULL);
+ }
+ convbuf[nbytes] = '\0';
+ return (convbuf);
+}
+#endif /* WCHAR_SUPPORT */
+
+/*
+ * The size of the buffer we use as scratch space for integer
+ * conversions, among other things. We need enough space to
+ * write a uintmax_t in octal (plus one byte).
+ */
+#if UINTMAX_MAX <= UINT64_MAX
+#define BUF 64
+#else
+#error "BUF must be large enough to format a uintmax_t"
+#endif
+
+/*
+ * Non-MT-safe version
+ */
+ssize_t
+vbprintfrr(struct fbuf *cb, const char *fmt0, va_list ap)
+{
+ const char *fmt; /* format string */
+ int ch; /* character from fmt */
+ int n, n2; /* handy integer (short term usage) */
+ const char *cp; /* handy char pointer (short term usage) */
+ int flags; /* flags as above */
+ int ret; /* return value accumulator */
+ int width; /* width from format (%8d), or 0 */
+ int prec; /* precision from format; <0 for N/A */
+ int saved_errno;
+ char sign; /* sign prefix (' ', '+', '-', or \0) */
+
+ u_long ulval = 0; /* integer arguments %[diouxX] */
+ uintmax_t ujval = 0; /* %j, %ll, %q, %t, %z integers */
+ void *ptrval; /* %p */
+ int base; /* base for [diouxX] conversion */
+ int dprec; /* a copy of prec if [diouxX], 0 otherwise */
+ int realsz; /* field size expanded by dprec, sign, etc */
+ int size; /* size of converted field or string */
+ int prsize; /* max size of printed field */
+ const char *xdigs; /* digits for %[xX] conversion */
+ struct io_state io; /* I/O buffering state */
+ char buf[BUF]; /* buffer with space for digits of uintmax_t */
+ char ox[2]; /* space for 0x; ox[1] is either x, X, or \0 */
+ union arg *argtable; /* args, built due to positional arg */
+ union arg statargtable [STATIC_ARG_TBL_SIZE];
+ int nextarg; /* 1-based argument index */
+ va_list orgap; /* original argument pointer */
+ char *convbuf; /* wide to multibyte conversion result */
+
+ static const char xdigs_lower[16] = "0123456789abcdef";
+ static const char xdigs_upper[16] = "0123456789ABCDEF";
+
+ /* BEWARE, these `goto error' on error. */
+#define PRINT(ptr, len) { \
+ if (io_print(&io, (ptr), (len))) \
+ goto error; \
+}
+#define PAD(howmany, with) { \
+ if (io_pad(&io, (howmany), (with))) \
+ goto error; \
+}
+#define PRINTANDPAD(p, ep, len, with) { \
+ if (io_printandpad(&io, (p), (ep), (len), (with))) \
+ goto error; \
+}
+#define FLUSH() do { } while (0)
+
+ /*
+ * Get the argument indexed by nextarg. If the argument table is
+ * built, use it to get the argument. If its not, get the next
+ * argument (and arguments must be gotten sequentially).
+ */
+#define GETARG(type) \
+ ((argtable != NULL) ? *((type*)(&argtable[nextarg++])) : \
+ (nextarg++, va_arg(ap, type)))
+
+ /*
+ * To extend shorts properly, we need both signed and unsigned
+ * argument extraction methods.
+ */
+#define SARG() \
+ (flags&LONGINT ? GETARG(long) : \
+ flags&SHORTINT ? (long)(short)GETARG(int) : \
+ flags&CHARINT ? (long)(signed char)GETARG(int) : \
+ (long)GETARG(int))
+#define UARG() \
+ (flags&LONGINT ? GETARG(u_long) : \
+ flags&SHORTINT ? (u_long)(u_short)GETARG(int) : \
+ flags&CHARINT ? (u_long)(u_char)GETARG(int) : \
+ (u_long)GETARG(u_int))
+#define INTMAX_SIZE (INTMAXT|SIZET|PTRDIFFT|LLONGINT|LONGDBL)
+#define SJARG() \
+ (flags&LONGDBL ? GETARG(int64_t) : \
+ flags&INTMAXT ? GETARG(intmax_t) : \
+ flags&SIZET ? (intmax_t)GETARG(ssize_t) : \
+ flags&PTRDIFFT ? (intmax_t)GETARG(ptrdiff_t) : \
+ (intmax_t)GETARG(long long))
+#define UJARG() \
+ (flags&LONGDBL ? GETARG(uint64_t) : \
+ flags&INTMAXT ? GETARG(uintmax_t) : \
+ flags&SIZET ? (uintmax_t)GETARG(size_t) : \
+ flags&PTRDIFFT ? (uintmax_t)GETARG(ptrdiff_t) : \
+ (uintmax_t)GETARG(unsigned long long))
+
+ /*
+ * Get * arguments, including the form *nn$. Preserve the nextarg
+ * that the argument can be gotten once the type is determined.
+ */
+#define GETASTER(val) \
+ n2 = 0; \
+ cp = fmt; \
+ while (is_digit(*cp)) { \
+ n2 = 10 * n2 + to_digit(*cp); \
+ cp++; \
+ } \
+ if (*cp == '$') { \
+ int hold = nextarg; \
+ if (argtable == NULL) { \
+ argtable = statargtable; \
+ if (_frr_find_arguments (fmt0, orgap, &argtable)) { \
+ ret = EOF; \
+ goto error; \
+ } \
+ } \
+ nextarg = n2; \
+ val = GETARG (int); \
+ nextarg = hold; \
+ fmt = ++cp; \
+ } else { \
+ val = GETARG (int); \
+ }
+
+ xdigs = xdigs_lower;
+ saved_errno = errno;
+ convbuf = NULL;
+ fmt = (char *)fmt0;
+ argtable = NULL;
+ nextarg = 1;
+ va_copy(orgap, ap);
+ io_init(&io, cb);
+ ret = 0;
+
+ /*
+ * Scan the format for conversions (`%' character).
+ */
+ for (;;) {
+ for (cp = fmt; (ch = *fmt) != '\0' && ch != '%'; fmt++)
+ /* void */;
+ if ((n = fmt - cp) != 0) {
+ if ((unsigned)ret + n > INT_MAX) {
+ ret = EOF;
+ errno = EOVERFLOW;
+ goto error;
+ }
+ PRINT(cp, n);
+ ret += n;
+ }
+ if (ch == '\0')
+ goto done;
+ fmt++; /* skip over '%' */
+
+ flags = 0;
+ dprec = 0;
+ width = 0;
+ prec = -1;
+ sign = '\0';
+ ox[1] = '\0';
+
+rflag: ch = *fmt++;
+reswitch: switch (ch) {
+ case ' ':
+ /*-
+ * ``If the space and + flags both appear, the space
+ * flag will be ignored.''
+ * -- ANSI X3J11
+ */
+ if (!sign)
+ sign = ' ';
+ goto rflag;
+ case '#':
+ flags |= ALT;
+ goto rflag;
+ case '*':
+ /*-
+ * ``A negative field width argument is taken as a
+ * - flag followed by a positive field width.''
+ * -- ANSI X3J11
+ * They don't exclude field widths read from args.
+ */
+ GETASTER (width);
+ if (width >= 0)
+ goto rflag;
+ width = -width;
+ /* FALLTHROUGH */
+ case '-':
+ flags |= LADJUST;
+ goto rflag;
+ case '+':
+ sign = '+';
+ goto rflag;
+ case '\'':
+ flags |= GROUPING;
+ goto rflag;
+ case '.':
+ if ((ch = *fmt++) == '*') {
+ GETASTER (prec);
+ goto rflag;
+ }
+ prec = 0;
+ while (is_digit(ch)) {
+ prec = 10 * prec + to_digit(ch);
+ ch = *fmt++;
+ }
+ goto reswitch;
+ case '0':
+ /*-
+ * ``Note that 0 is taken as a flag, not as the
+ * beginning of a field width.''
+ * -- ANSI X3J11
+ */
+ flags |= ZEROPAD;
+ goto rflag;
+ case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ n = 0;
+ do {
+ n = 10 * n + to_digit(ch);
+ ch = *fmt++;
+ } while (is_digit(ch));
+ if (ch == '$') {
+ nextarg = n;
+ if (argtable == NULL) {
+ argtable = statargtable;
+ if (_frr_find_arguments (fmt0, orgap,
+ &argtable)) {
+ ret = EOF;
+ goto error;
+ }
+ }
+ goto rflag;
+ }
+ width = n;
+ goto reswitch;
+ case 'L':
+ flags |= LONGDBL;
+ goto rflag;
+ case 'h':
+ if (flags & SHORTINT) {
+ flags &= ~SHORTINT;
+ flags |= CHARINT;
+ } else
+ flags |= SHORTINT;
+ goto rflag;
+ case 'j':
+ flags |= INTMAXT;
+ goto rflag;
+ case 'l':
+ if (flags & LONGINT) {
+ flags &= ~LONGINT;
+ flags |= LLONGINT;
+ } else
+ flags |= LONGINT;
+ goto rflag;
+ case 'q':
+ flags |= LLONGINT; /* not necessarily */
+ goto rflag;
+ case 't':
+ flags |= PTRDIFFT;
+ goto rflag;
+ case 'z':
+ flags |= SIZET;
+ goto rflag;
+ case 'C':
+ flags |= LONGINT;
+ /*FALLTHROUGH*/
+ case 'c':
+#ifdef WCHAR_SUPPORT
+ if (flags & LONGINT) {
+ static const mbstate_t initial;
+ mbstate_t mbs;
+ size_t mbseqlen;
+
+ mbs = initial;
+ mbseqlen = wcrtomb(cp = buf,
+ (wchar_t)GETARG(wint_t), &mbs);
+ if (mbseqlen == (size_t)-1) {
+ goto error;
+ }
+ size = (int)mbseqlen;
+ } else
+#endif /* WCHAR_SUPPORT */
+ {
+ buf[0] = GETARG(int);
+ cp = buf;
+ size = 1;
+ }
+ sign = '\0';
+ break;
+ case 'D':
+ flags |= LONGINT;
+ /*FALLTHROUGH*/
+ case 'd':
+ case 'i':
+ if (flags & INTMAX_SIZE)
+ ujval = SJARG();
+ else
+ ulval = SARG();
+
+ if (printfrr_ext_char(fmt[0])) {
+ n2 = printfrr_exti(buf, sizeof(buf), fmt, prec,
+ (flags & INTMAX_SIZE) ? ujval
+ : (uintmax_t)ulval);
+ if (n2 > 0) {
+ fmt += n2;
+ cp = buf;
+ size = strlen(cp);
+ sign = '\0';
+ break;
+ }
+ }
+ if (flags & INTMAX_SIZE) {
+ if ((intmax_t)ujval < 0) {
+ ujval = -ujval;
+ sign = '-';
+ }
+ } else {
+ if ((long)ulval < 0) {
+ ulval = -ulval;
+ sign = '-';
+ }
+ }
+ base = 10;
+ goto number;
+#ifndef NO_FLOATING_POINT
+ case 'a':
+ case 'A':
+ case 'e':
+ case 'E':
+ case 'f':
+ case 'F':
+ case 'g':
+ case 'G':
+ if (flags & LONGDBL) {
+ long double arg = GETARG(long double);
+ char fmt[6] = "%.*L";
+ fmt[4] = ch;
+ fmt[5] = '\0';
+
+ snprintf(buf, sizeof(buf), fmt, prec, arg);
+ } else {
+ double arg = GETARG(double);
+ char fmt[5] = "%.*";
+ fmt[3] = ch;
+ fmt[4] = '\0';
+
+ snprintf(buf, sizeof(buf), fmt, prec, arg);
+ }
+ cp = buf;
+ /* for proper padding */
+ if (*cp == '-') {
+ cp++;
+ sign = '-';
+ }
+ /* "inf" */
+ if (!is_digit(*cp) && *cp != '.')
+ flags &= ~ZEROPAD;
+ size = strlen(buf);
+ break;
+#endif
+ case 'm':
+ cp = strerror(saved_errno);
+ size = (prec >= 0) ? strnlen(cp, prec) : strlen(cp);
+ sign = '\0';
+ break;
+ case 'n':
+ /*
+ * Assignment-like behavior is specified if the
+ * value overflows or is otherwise unrepresentable.
+ * C99 says to use `signed char' for %hhn conversions.
+ */
+ if (flags & LLONGINT)
+ *GETARG(long long *) = ret;
+ else if (flags & SIZET)
+ *GETARG(ssize_t *) = (ssize_t)ret;
+ else if (flags & PTRDIFFT)
+ *GETARG(ptrdiff_t *) = ret;
+ else if (flags & INTMAXT)
+ *GETARG(intmax_t *) = ret;
+ else if (flags & LONGINT)
+ *GETARG(long *) = ret;
+ else if (flags & SHORTINT)
+ *GETARG(short *) = ret;
+ else if (flags & CHARINT)
+ *GETARG(signed char *) = ret;
+ else
+ *GETARG(int *) = ret;
+ continue; /* no output */
+ case 'O':
+ flags |= LONGINT;
+ /*FALLTHROUGH*/
+ case 'o':
+ if (flags & INTMAX_SIZE)
+ ujval = UJARG();
+ else
+ ulval = UARG();
+ base = 8;
+ goto nosign;
+ case 'p':
+ /*-
+ * ``The argument shall be a pointer to void. The
+ * value of the pointer is converted to a sequence
+ * of printable characters, in an implementation-
+ * defined manner.''
+ * -- ANSI X3J11
+ */
+ ptrval = GETARG(void *);
+ if (printfrr_ext_char(fmt[0]) &&
+ (n2 = printfrr_extp(buf, sizeof(buf),
+ fmt, prec, ptrval)) > 0) {
+ fmt += n2;
+ cp = buf;
+ size = strlen(cp);
+ sign = '\0';
+ break;
+ }
+ ujval = (uintmax_t)(uintptr_t)ptrval;
+ base = 16;
+ xdigs = xdigs_lower;
+ flags = flags | INTMAXT;
+ ox[1] = 'x';
+ goto nosign;
+ case 'S':
+ flags |= LONGINT;
+ /*FALLTHROUGH*/
+ case 's':
+#ifdef WCHAR_SUPPORT
+ if (flags & LONGINT) {
+ wchar_t *wcp;
+
+ if (convbuf != NULL)
+ free(convbuf);
+ if ((wcp = GETARG(wchar_t *)) == NULL)
+ cp = "(null)";
+ else {
+ convbuf = __wcsconv(wcp, prec);
+ if (convbuf == NULL) {
+ goto error;
+ }
+ cp = convbuf;
+ }
+ } else
+#endif
+ if ((cp = GETARG(char *)) == NULL)
+ cp = "(null)";
+ size = (prec >= 0) ? strnlen(cp, prec) : strlen(cp);
+ sign = '\0';
+ break;
+ case 'U':
+ flags |= LONGINT;
+ /*FALLTHROUGH*/
+ case 'u':
+ if (flags & INTMAX_SIZE)
+ ujval = UJARG();
+ else
+ ulval = UARG();
+ base = 10;
+ goto nosign;
+ case 'X':
+ xdigs = xdigs_upper;
+ goto hex;
+ case 'x':
+ xdigs = xdigs_lower;
+hex:
+ if (flags & INTMAX_SIZE)
+ ujval = UJARG();
+ else
+ ulval = UARG();
+ base = 16;
+ /* leading 0x/X only if non-zero */
+ if (flags & ALT &&
+ (flags & INTMAX_SIZE ? ujval != 0 : ulval != 0))
+ ox[1] = ch;
+
+ flags &= ~GROUPING;
+ /* unsigned conversions */
+nosign: sign = '\0';
+ /*-
+ * ``... diouXx conversions ... if a precision is
+ * specified, the 0 flag will be ignored.''
+ * -- ANSI X3J11
+ */
+number: if ((dprec = prec) >= 0)
+ flags &= ~ZEROPAD;
+
+ /*-
+ * ``The result of converting a zero value with an
+ * explicit precision of zero is no characters.''
+ * -- ANSI X3J11
+ *
+ * ``The C Standard is clear enough as is. The call
+ * printf("%#.0o", 0) should print 0.''
+ * -- Defect Report #151
+ */
+ cp = buf + BUF;
+ if (flags & INTMAX_SIZE) {
+ if (ujval != 0 || prec != 0 ||
+ (flags & ALT && base == 8))
+ cp = __ujtoa(ujval, buf + BUF, base,
+ flags & ALT, xdigs);
+ } else {
+ if (ulval != 0 || prec != 0 ||
+ (flags & ALT && base == 8))
+ cp = __ultoa(ulval, buf + BUF, base,
+ flags & ALT, xdigs);
+ }
+ size = buf + BUF - cp;
+ if (size > BUF) /* should never happen */
+ abort();
+ break;
+ default: /* "%?" prints ?, unless ? is NUL */
+ if (ch == '\0')
+ goto done;
+ /* pretend it was %c with argument ch */
+ buf[0] = ch;
+ cp = buf;
+ size = 1;
+ sign = '\0';
+ break;
+ }
+
+ /*
+ * All reasonable formats wind up here. At this point, `cp'
+ * points to a string which (if not flags&LADJUST) should be
+ * padded out to `width' places. If flags&ZEROPAD, it should
+ * first be prefixed by any sign or other prefix; otherwise,
+ * it should be blank padded before the prefix is emitted.
+ * After any left-hand padding and prefixing, emit zeroes
+ * required by a decimal [diouxX] precision, then print the
+ * string proper, then emit zeroes required by any leftover
+ * floating precision; finally, if LADJUST, pad with blanks.
+ *
+ * Compute actual size, so we know how much to pad.
+ * size excludes decimal prec; realsz includes it.
+ */
+ realsz = dprec > size ? dprec : size;
+ if (sign)
+ realsz++;
+ if (ox[1])
+ realsz += 2;
+
+ prsize = width > realsz ? width : realsz;
+ if ((unsigned)ret + prsize > INT_MAX) {
+ ret = EOF;
+ errno = EOVERFLOW;
+ goto error;
+ }
+
+ /* right-adjusting blank padding */
+ if ((flags & (LADJUST|ZEROPAD)) == 0)
+ PAD(width - realsz, blanks);
+
+ /* prefix */
+ if (sign)
+ PRINT(&sign, 1);
+
+ if (ox[1]) { /* ox[1] is either x, X, or \0 */
+ ox[0] = '0';
+ PRINT(ox, 2);
+ }
+
+ /* right-adjusting zero padding */
+ if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD)
+ PAD(width - realsz, zeroes);
+
+ /* the string or number proper */
+ /* leading zeroes from decimal precision */
+ PAD(dprec - size, zeroes);
+ PRINT(cp, size);
+ /* left-adjusting padding (always blank) */
+ if (flags & LADJUST)
+ PAD(width - realsz, blanks);
+
+ /* finally, adjust ret */
+ ret += prsize;
+
+ FLUSH(); /* copy out the I/O vectors */
+ }
+done:
+ FLUSH();
+error:
+ va_end(orgap);
+ if (convbuf != NULL)
+ free(convbuf);
+ if ((argtable != NULL) && (argtable != statargtable))
+ free (argtable);
+ return (ret);
+ /* NOTREACHED */
+}
+
diff --git a/lib/printfrr.h b/lib/printfrr.h
new file mode 100644
index 000000000..95dace702
--- /dev/null
+++ b/lib/printfrr.h
@@ -0,0 +1,149 @@
+/*
+ * Copyright (c) 2019 David Lamparter, for NetDEF, Inc.
+ *
+ * Permission to use, copy, modify, and 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 THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR 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.
+ */
+
+#ifndef _FRR_PRINTFRR_H
+#define _FRR_PRINTFRR_H
+
+#include <stddef.h>
+#include <stdarg.h>
+#include <stdint.h>
+
+#include "compiler.h"
+#include "memory.h"
+
+struct fbuf {
+ char *buf;
+ char *pos;
+ size_t len;
+};
+
+#define at(a, b) \
+ __attribute__((format(printf, a, b)))
+#define atn(a, b) \
+ at(a, b) __attribute__((nonnull(1) _RET_NONNULL))
+#define atm(a, b) \
+ atn(a, b) __attribute__((malloc))
+
+/* return value is length needed for the full string (excluding \0) in all
+ * cases. The functions write as much as they can, but continue regardless,
+ * so the return value is independent of buffer length. Both bprintfrr and
+ * snprintf also accept NULL as output buffer.
+ */
+
+/* bprintfrr does NOT null terminate! use sparingly (only provided since it's
+ * the most direct interface) - useful for incrementally building long text
+ * (call bprintfrr repeatedly with the same buffer)
+ */
+ssize_t vbprintfrr(struct fbuf *out, const char *fmt, va_list) at(2, 0);
+ssize_t bprintfrr(struct fbuf *out, const char *fmt, ...) at(2, 3);
+
+/* these do null terminate like their snprintf cousins */
+ssize_t vsnprintfrr(char *out, size_t sz, const char *fmt, va_list) at(3, 0);
+ssize_t snprintfrr(char *out, size_t sz, const char *fmt, ...) at(3, 4);
+
+/* c = continue / concatenate (append at the end of the string)
+ * return value is would-be string length (regardless of buffer length),
+ * i.e. includes already written chars */
+ssize_t vcsnprintfrr(char *out, size_t sz, const char *fmt, va_list) at(3, 0);
+ssize_t csnprintfrr(char *out, size_t sz, const char *fmt, ...) at(3, 4);
+
+/* memory allocations don't fail in FRR, so you always get something here.
+ * (in case of error, returns a strdup of the format string) */
+char *vasprintfrr(struct memtype *mt, const char *fmt, va_list) atm(2, 0);
+char *asprintfrr(struct memtype *mt, const char *fmt, ...) atm(2, 3);
+
+/* try to use provided buffer (presumably from stack), allocate if it's too
+ * short. Must call XFREE(mt, return value) if return value != out.
+ */
+char *vasnprintfrr(struct memtype *mt, char *out, size_t sz,
+ const char *fmt, va_list) atn(4, 0);
+char *asnprintfrr(struct memtype *mt, char *out, size_t sz,
+ const char *fmt, ...) atn(4, 5);
+
+#undef at
+#undef atm
+
+/* extension specs must start with a capital letter (this is a restriction
+ * for both performance's and human understanding's sake.)
+ *
+ * Note that the entire thing mostly works because a letter directly following
+ * a %p print specifier is extremely unlikely to occur (why would you want to
+ * print "0x12345678HELLO"?) Normally, you'd expect spacing or punctuation
+ * after a placeholder. That also means that neither of those works well for
+ * extension purposes, e.g. "%p{foo}" is reasonable to see actually used.
+ *
+ * TODO: would be nice to support a "%pF%dF" specifier that consumes 2
+ * arguments, e.g. to pass an integer + a list of known values... can be
+ * done, but a bit tricky.
+ */
+#define printfrr_ext_char(ch) ((ch) >= 'A' && (ch) <= 'Z')
+
+struct printfrr_ext {
+ /* embedded string to minimize cache line pollution */
+ char match[8];
+
+ /* both can be given, if not the code continues searching
+ * (you can do %pX and %dX in 2 different entries)
+ *
+ * return value: number of bytes consumed from the format string, so
+ * you can consume extra flags (e.g. register for "%pX", consume
+ * "%pXfoo" or "%pXbar" for flags.) Convention is to make those flags
+ * lowercase letters or numbers.
+ *
+ * bsz is a compile-time constant in printf; it's gonna be relatively
+ * small. This isn't designed to print Shakespeare from a pointer.
+ *
+ * prec is the precision specifier (the 999 in "%.999p") -1 means
+ * none given (value in the format string cannot be negative)
+ */
+ ssize_t (*print_ptr)(char *buf, size_t bsz, const char *fmt, int prec,
+ const void *);
+ ssize_t (*print_int)(char *buf, size_t bsz, const char *fmt, int prec,
+ uintmax_t);
+};
+
+/* no locking - must be called when single threaded (e.g. at startup.)
+ * this restriction hopefully won't be a huge bother considering normal usage
+ * scenarios...
+ */
+void printfrr_ext_reg(const struct printfrr_ext *);
+
+#define printfrr_ext_autoreg_p(matchs, print_fn) \
+ static ssize_t print_fn(char *, size_t, const char *, int, \
+ const void *); \
+ static struct printfrr_ext _printext_##print_fn = { \
+ .match = matchs, \
+ .print_ptr = print_fn, \
+ }; \
+ static void _printreg_##print_fn(void) __attribute__((constructor)); \
+ static void _printreg_##print_fn(void) { \
+ printfrr_ext_reg(&_printext_##print_fn); \
+ } \
+ /* end */
+
+#define printfrr_ext_autoreg_i(matchs, print_fn) \
+ static ssize_t print_fn(char *, size_t, const char *, int, uintmax_t); \
+ static struct printfrr_ext _printext_##print_fn = { \
+ .match = matchs, \
+ .print_int = print_fn, \
+ }; \
+ static void _printreg_##print_fn(void) __attribute__((constructor)); \
+ static void _printreg_##print_fn(void) { \
+ printfrr_ext_reg(&_printext_##print_fn); \
+ } \
+ /* end */
+
+#endif
diff --git a/lib/routemap.c b/lib/routemap.c
index 807eec9c5..9336154b1 100644
--- a/lib/routemap.c
+++ b/lib/routemap.c
@@ -1333,6 +1333,13 @@ static route_map_event_t get_route_map_delete_event(route_map_event_t type)
*/
assert(0);
}
+
+ assert(0);
+ /*
+ * Return to make c happy but if we get here something has gone
+ * terribly terribly wrong, so yes this return makes no sense.
+ */
+ return RMAP_EVENT_CALL_ADDED;
}
/* Add match statement to route map. */
@@ -1524,14 +1531,14 @@ int route_map_delete_set(struct route_map_index *index, const char *set_name,
(note, this includes the description for the "NEXT"
and "GOTO" frobs now
- | Match | No Match | No op
- |-----------|--------------|-------
- permit | action | cont | cont.
- | | default:deny | default:permit
- -------------------+-----------------------
- | deny | cont | cont.
- deny | | default:deny | default:permit
- |-----------|--------------|--------
+ Match | No Match
+ |
+ permit action | cont
+ |
+ ------------------+---------------
+ |
+ deny deny | cont
+ |
action)
-Apply Set statements, accept route
@@ -1565,12 +1572,12 @@ int route_map_delete_set(struct route_map_index *index, const char *set_name,
We need to make sure our route-map processing matches the above
*/
-static enum route_map_match_result_t
+static route_map_result_t
route_map_apply_match(struct route_map_rule_list *match_list,
const struct prefix *prefix, route_map_object_t type,
void *object)
{
- enum route_map_match_result_t ret = RMAP_NOMATCH;
+ route_map_result_t ret = RMAP_NOMATCH;
struct route_map_rule *match;
@@ -1602,8 +1609,7 @@ route_map_result_t route_map_apply(struct route_map *map,
route_map_object_t type, void *object)
{
static int recursion = 0;
- enum route_map_match_result_t match_ret = RMAP_NOMATCH;
- route_map_result_t ret = 0;
+ int ret = 0;
struct route_map_index *index;
struct route_map_rule *set;
@@ -1623,33 +1629,24 @@ route_map_result_t route_map_apply(struct route_map *map,
for (index = map->head; index; index = index->next) {
/* Apply this index. */
index->applied++;
- match_ret = route_map_apply_match(&index->match_list, prefix,
- type, object);
+ ret = route_map_apply_match(&index->match_list, prefix, type,
+ object);
/* Now we apply the matrix from above */
- if (match_ret == RMAP_NOMATCH || match_ret == RMAP_NOOP)
+ if (ret == RMAP_NOMATCH)
/* 'cont' from matrix - continue to next route-map
* sequence */
continue;
- else if (match_ret == RMAP_MATCH) {
+ else if (ret == RMAP_MATCH) {
if (index->type == RMAP_PERMIT)
/* 'action' */
{
- /* Match succeeded, rmap is of type permit */
- ret = RMAP_PERMITMATCH;
-
/* permit+match must execute sets */
for (set = index->set_list.head; set;
set = set->next)
- /*
- * We dont care abt the return value
- * for set cmd. Almost always,
- * RMAP_OKAY is returned. Rarely
- * do we see RMAP_ERROR
- */
- match_ret = (*set->cmd->func_apply)(
- set->value, prefix, type,
- object);
+ ret = (*set->cmd->func_apply)(
+ set->value, prefix, type,
+ object);
/* Call another route-map if available */
if (index->nextrm) {
@@ -1700,10 +1697,6 @@ route_map_result_t route_map_apply(struct route_map *map,
}
}
}
-
- if (match_ret == RMAP_NOOP)
- return RMAP_PERMITMATCH;
-
/* Finally route-map does not match at all. */
return RMAP_DENYMATCH;
}
diff --git a/lib/routemap.h b/lib/routemap.h
index d7acd7f3f..3781d227d 100644
--- a/lib/routemap.h
+++ b/lib/routemap.h
@@ -34,36 +34,15 @@ DECLARE_MTYPE(ROUTE_MAP_NAME)
DECLARE_MTYPE(ROUTE_MAP_RULE)
DECLARE_MTYPE(ROUTE_MAP_COMPILED)
-/*
- * Route-map match or set result "Eg: match evpn vni xx"
- * route-map match cmd always returns match/nomatch/noop
- * match--> found a match
- * nomatch--> didnt find a match
- * noop--> invalid
- * route-map set retuns okay/error
- * okay --> set was successful
- * error --> set was not successful
- */
-enum route_map_match_result_t {
- /*
- * route-map match cmd results
- */
- RMAP_MATCH,
- RMAP_NOMATCH,
- RMAP_NOOP,
- /*
- * route-map set cmd results
- */
- RMAP_OKAY,
- RMAP_ERROR
-};
-
/* Route map's type. */
enum route_map_type { RMAP_PERMIT, RMAP_DENY, RMAP_ANY };
typedef enum {
+ RMAP_MATCH,
RMAP_DENYMATCH,
- RMAP_PERMITMATCH
+ RMAP_NOMATCH,
+ RMAP_ERROR,
+ RMAP_OKAY
} route_map_result_t;
typedef enum {
@@ -112,10 +91,10 @@ struct route_map_rule_cmd {
const char *str;
/* Function for value set or match. */
- enum route_map_match_result_t (*func_apply)(void *rule,
- const struct prefix *prefix,
- route_map_object_t type,
- void *object);
+ route_map_result_t (*func_apply)(void *rule,
+ const struct prefix *prefix,
+ route_map_object_t type,
+ void *object);
/* Compile argument and return result as void *. */
void *(*func_compile)(const char *);
diff --git a/lib/sigevent.c b/lib/sigevent.c
index f00ff4921..d02b07422 100644
--- a/lib/sigevent.c
+++ b/lib/sigevent.c
@@ -209,12 +209,14 @@ exit_handler(int signo
#endif
)
{
- zlog_signal(signo, "exiting..."
-#ifdef SA_SIGINFO
- ,
- siginfo, program_counter(context)
+#ifndef SA_SIGINFO
+ void *siginfo = NULL;
+ void *pc = NULL;
+#else
+ void *pc = program_counter(context);
#endif
- );
+
+ zlog_signal(signo, "exiting...", siginfo, pc);
_exit(128 + signo);
}
@@ -226,6 +228,13 @@ core_handler(int signo
#endif
)
{
+#ifndef SA_SIGINFO
+ void *siginfo = NULL;
+ void *pc = NULL;
+#else
+ void *pc = program_counter(context);
+#endif
+
/* make sure we don't hang in here. default for SIGALRM is terminate.
* - if we're in backtrace for more than a second, abort. */
struct sigaction sa_default = {.sa_handler = SIG_DFL};
@@ -238,12 +247,8 @@ core_handler(int signo
alarm(1);
- zlog_signal(signo, "aborting..."
-#ifdef SA_SIGINFO
- ,
- siginfo, program_counter(context)
-#endif
- );
+ zlog_signal(signo, "aborting...", siginfo, pc);
+
/* dump memory stats on core */
log_memstats(stderr, "core_handler");
abort();
diff --git a/lib/srcdest_table.c b/lib/srcdest_table.c
index 80004b41a..ee87d7307 100644
--- a/lib/srcdest_table.c
+++ b/lib/srcdest_table.c
@@ -28,6 +28,7 @@
#include "memory.h"
#include "prefix.h"
#include "table.h"
+#include "printfrr.h"
DEFINE_MTYPE_STATIC(LIB, ROUTE_SRC_NODE, "Route source node")
@@ -264,7 +265,8 @@ struct route_node *srcdest_rnode_lookup(struct route_table *table,
return srn;
}
-void srcdest_rnode_prefixes(struct route_node *rn, const struct prefix **p,
+void srcdest_rnode_prefixes(const struct route_node *rn,
+ const struct prefix **p,
const struct prefix **src_p)
{
if (rnode_is_srcnode(rn)) {
@@ -296,10 +298,22 @@ const char *srcdest2str(const struct prefix *dst_p,
return str;
}
-const char *srcdest_rnode2str(struct route_node *rn, char *str, int size)
+const char *srcdest_rnode2str(const struct route_node *rn, char *str, int size)
{
const struct prefix *dst_p, *src_p;
srcdest_rnode_prefixes(rn, &dst_p, &src_p);
return srcdest2str(dst_p, (const struct prefix_ipv6 *)src_p, str, size);
}
+
+printfrr_ext_autoreg_p("RN", printfrr_rn)
+static ssize_t printfrr_rn(char *buf, size_t bsz, const char *fmt,
+ int prec, const void *ptr)
+{
+ const struct route_node *rn = ptr;
+ const struct prefix *dst_p, *src_p;
+
+ srcdest_rnode_prefixes(rn, &dst_p, &src_p);
+ srcdest2str(dst_p, (const struct prefix_ipv6 *)src_p, buf, bsz);
+ return 2;
+}
diff --git a/lib/srcdest_table.h b/lib/srcdest_table.h
index 8845931de..90418944c 100644
--- a/lib/srcdest_table.h
+++ b/lib/srcdest_table.h
@@ -65,22 +65,22 @@ extern struct route_node *srcdest_rnode_get(struct route_table *table,
extern struct route_node *srcdest_rnode_lookup(struct route_table *table,
union prefixconstptr dst_pu,
const struct prefix_ipv6 *src_p);
-extern void srcdest_rnode_prefixes(struct route_node *rn,
+extern void srcdest_rnode_prefixes(const struct route_node *rn,
const struct prefix **p,
const struct prefix **src_p);
extern const char *srcdest2str(const struct prefix *dst_p,
const struct prefix_ipv6 *src_p,
char *str, int size);
-extern const char *srcdest_rnode2str(struct route_node *rn, char *str,
+extern const char *srcdest_rnode2str(const struct route_node *rn, char *str,
int size);
extern struct route_node *srcdest_route_next(struct route_node *rn);
-static inline int rnode_is_dstnode(struct route_node *rn)
+static inline int rnode_is_dstnode(const struct route_node *rn)
{
return rn->table->delegate == &_srcdest_dstnode_delegate;
}
-static inline int rnode_is_srcnode(struct route_node *rn)
+static inline int rnode_is_srcnode(const struct route_node *rn)
{
return rn->table->delegate == &_srcdest_srcnode_delegate;
}
diff --git a/lib/subdir.am b/lib/subdir.am
index 4897f5e8e..50ff1feec 100644
--- a/lib/subdir.am
+++ b/lib/subdir.am
@@ -94,6 +94,9 @@ lib_libfrr_la_SOURCES = \
lib/yang_wrappers.c \
lib/zclient.c \
lib/logicalrouter.c \
+ lib/printf/printf-pos.c \
+ lib/printf/vfprintf.c \
+ lib/printf/glue.c \
# end
nodist_lib_libfrr_la_SOURCES = \
@@ -131,6 +134,8 @@ lib/nexthop_group_clippy.c: $(CLIPPY_DEPS)
lib/nexthop_group.lo: lib/nexthop_group_clippy.c
lib/northbound_cli_clippy.c: $(CLIPPY_DEPS)
lib/northbound_cli.lo: lib/northbound_cli_clippy.c
+lib/vty_clippy.c: $(CLIPPY_DEPS)
+lib/vty.lo: lib/vty_clippy.c
pkginclude_HEADERS += \
lib/agg_table.h \
@@ -190,6 +195,7 @@ pkginclude_HEADERS += \
lib/plist.h \
lib/pqueue.h \
lib/prefix.h \
+ lib/printfrr.h \
lib/privs.h \
lib/ptm_lib.h \
lib/pw.h \
@@ -242,6 +248,8 @@ noinst_HEADERS += \
lib/clippy.h \
lib/log_int.h \
lib/plist_int.h \
+ lib/printf/printfcommon.h \
+ lib/printf/printflocal.h \
#end
# General note about module and module helper library (libfrrsnmp, libfrrzmq)
diff --git a/lib/vty.c b/lib/vty.c
index 2d97cca35..e306e69b8 100644
--- a/lib/vty.c
+++ b/lib/vty.c
@@ -42,10 +42,15 @@
#include "frrstr.h"
#include "lib_errors.h"
#include "northbound_cli.h"
+#include "printfrr.h"
#include <arpa/telnet.h>
#include <termios.h>
+#ifndef VTYSH_EXTRACT_PL
+#include "lib/vty_clippy.c"
+#endif
+
DEFINE_MTYPE_STATIC(LIB, VTY, "VTY")
DEFINE_MTYPE_STATIC(LIB, VTY_OUT_BUF, "VTY output buffer")
DEFINE_MTYPE_STATIC(LIB, VTY_HIST, "VTY history")
@@ -92,7 +97,8 @@ static int no_password_check = 0;
/* Integrated configuration file path */
static char integrate_default[] = SYSCONFDIR INTEGRATE_DEFAULT_CONFIG;
-static int do_log_commands = 0;
+static bool do_log_commands;
+static bool do_log_commands_perm;
void vty_frame(struct vty *vty, const char *format, ...)
{
@@ -143,8 +149,7 @@ bool vty_set_include(struct vty *vty, const char *regexp)
int vty_out(struct vty *vty, const char *format, ...)
{
va_list args;
- int len = 0;
- int size = 1024;
+ ssize_t len;
char buf[1024];
char *p = NULL;
char *filtered;
@@ -154,35 +159,11 @@ int vty_out(struct vty *vty, const char *format, ...)
vty_out(vty, "%s", vty->frame);
}
- /* Try to write to initial buffer. */
va_start(args, format);
- len = vsnprintf(buf, sizeof(buf), format, args);
+ p = vasnprintfrr(MTYPE_VTY_OUT_BUF, buf, sizeof(buf), format, args);
va_end(args);
- /* Initial buffer is not enough. */
- if (len < 0 || len >= size) {
- while (1) {
- if (len > -1)
- size = len + 1;
- else
- size = size * 2;
-
- p = XREALLOC(MTYPE_VTY_OUT_BUF, p, size);
- if (!p)
- return -1;
-
- va_start(args, format);
- len = vsnprintf(p, size, format, args);
- va_end(args);
-
- if (len > -1 && len < size)
- break;
- }
- }
-
- /* When initial buffer is enough to store all output. */
- if (!p)
- p = buf;
+ len = strlen(p);
/* filter buffer */
if (vty->filter) {
@@ -269,8 +250,8 @@ done:
}
static int vty_log_out(struct vty *vty, const char *level,
- const char *proto_str, const char *format,
- struct timestamp_control *ctl, va_list va)
+ const char *proto_str, const char *msg,
+ struct timestamp_control *ctl)
{
int ret;
int len;
@@ -295,7 +276,7 @@ static int vty_log_out(struct vty *vty, const char *level,
if ((ret < 0) || ((size_t)(len += ret) >= sizeof(buf)))
return -1;
- if (((ret = vsnprintf(buf + len, sizeof(buf) - len, format, va)) < 0)
+ if (((ret = snprintf(buf + len, sizeof(buf) - len, "%s", msg)) < 0)
|| ((size_t)((len += ret) + 2) > sizeof(buf)))
return -1;
@@ -2547,8 +2528,8 @@ tmp_free_and_out:
}
/* Small utility function which output log to the VTY. */
-void vty_log(const char *level, const char *proto_str, const char *format,
- struct timestamp_control *ctl, va_list va)
+void vty_log(const char *level, const char *proto_str, const char *msg,
+ struct timestamp_control *ctl)
{
unsigned int i;
struct vty *vty;
@@ -2558,13 +2539,8 @@ void vty_log(const char *level, const char *proto_str, const char *format,
for (i = 0; i < vector_active(vtyvec); i++)
if ((vty = vector_slot(vtyvec, i)) != NULL)
- if (vty->monitor) {
- va_list ac;
- va_copy(ac, va);
- vty_log_out(vty, level, proto_str, format, ctl,
- ac);
- va_end(ac);
- }
+ if (vty->monitor)
+ vty_log_out(vty, level, proto_str, msg, ctl);
}
/* Async-signal-safe version of vty_log for fixed strings. */
@@ -2975,13 +2951,24 @@ DEFUN_NOSH (show_history,
}
/* vty login. */
-DEFUN (log_commands,
+DEFPY (log_commands,
log_commands_cmd,
- "log commands",
+ "[no] log commands",
+ NO_STR
"Logging control\n"
- "Log all commands (can't be unset without restart)\n")
+ "Log all commands\n")
{
- do_log_commands = 1;
+ if (no) {
+ if (do_log_commands_perm) {
+ vty_out(vty,
+ "Daemon started with permanent logging turned on for commands, ignoring\n");
+ return CMD_WARNING;
+ }
+
+ do_log_commands = false;
+ } else
+ do_log_commands = true;
+
return CMD_SUCCESS;
}
@@ -3101,7 +3088,7 @@ void vty_init_vtysh(void)
}
/* Install vty's own commands like `who' command. */
-void vty_init(struct thread_master *master_thread)
+void vty_init(struct thread_master *master_thread, bool do_command_logging)
{
/* For further configuration read, preserve current directory. */
vty_save_cwd();
@@ -3125,6 +3112,12 @@ void vty_init(struct thread_master *master_thread)
install_element(CONFIG_NODE, &no_service_advanced_vty_cmd);
install_element(CONFIG_NODE, &show_history_cmd);
install_element(CONFIG_NODE, &log_commands_cmd);
+
+ if (do_command_logging) {
+ do_log_commands = true;
+ do_log_commands_perm = true;
+ }
+
install_element(ENABLE_NODE, &terminal_monitor_cmd);
install_element(ENABLE_NODE, &terminal_no_monitor_cmd);
install_element(ENABLE_NODE, &no_terminal_monitor_cmd);
diff --git a/lib/vty.h b/lib/vty.h
index 98d75542f..035e75802 100644
--- a/lib/vty.h
+++ b/lib/vty.h
@@ -290,7 +290,7 @@ struct vty_arg {
#endif
/* Prototypes. */
-extern void vty_init(struct thread_master *);
+extern void vty_init(struct thread_master *, bool do_command_logging);
extern void vty_init_vtysh(void);
extern void vty_terminate(void);
extern void vty_reset(void);
@@ -313,8 +313,8 @@ extern void vty_time_print(struct vty *, int);
extern void vty_serv_sock(const char *, unsigned short, const char *);
extern void vty_close(struct vty *);
extern char *vty_get_cwd(void);
-extern void vty_log(const char *level, const char *proto, const char *fmt,
- struct timestamp_control *, va_list);
+extern void vty_log(const char *level, const char *proto, const char *msg,
+ struct timestamp_control *);
extern int vty_config_enter(struct vty *vty, bool private_config,
bool exclusive);
extern void vty_config_exit(struct vty *);
diff --git a/nhrpd/vici.c b/nhrpd/vici.c
index 3de4609a2..d6105b71d 100644
--- a/nhrpd/vici.c
+++ b/nhrpd/vici.c
@@ -207,7 +207,7 @@ static void parse_sa_message(struct vici_message_ctx *ctx,
}
break;
default:
- if (!key)
+ if (!key || !key->ptr)
break;
switch (key->ptr[0]) {
@@ -550,7 +550,7 @@ int sock_open_unix(const char *path)
memset(&addr, 0, sizeof(struct sockaddr_un));
addr.sun_family = AF_UNIX;
- strncpy(addr.sun_path, path, sizeof(addr.sun_path) - 1);
+ strlcpy(addr.sun_path, path, sizeof(addr.sun_path));
ret = connect(fd, (struct sockaddr *)&addr,
sizeof(addr.sun_family) + strlen(addr.sun_path));
diff --git a/ospf6d/ospf6_asbr.c b/ospf6d/ospf6_asbr.c
index 4fbf70c9d..946bbf8cc 100644
--- a/ospf6d/ospf6_asbr.c
+++ b/ospf6d/ospf6_asbr.c
@@ -1018,7 +1018,7 @@ void ospf6_asbr_redistribute_add(int type, ifindex_t ifindex,
unsigned int nexthop_num,
struct in6_addr *nexthop, route_tag_t tag)
{
- route_map_result_t ret;
+ int ret;
struct ospf6_route troute;
struct ospf6_external_info tinfo;
struct ospf6_route *route, *match;
@@ -1355,7 +1355,7 @@ static void ospf6_redistribute_show_config(struct vty *vty)
/* Routemap Functions */
-static enum route_map_match_result_t
+static route_map_result_t
ospf6_routemap_rule_match_address_prefixlist(void *rule,
const struct prefix *prefix,
route_map_object_t type,
@@ -1395,7 +1395,7 @@ struct route_map_rule_cmd ospf6_routemap_rule_match_address_prefixlist_cmd = {
/* `match interface IFNAME' */
/* Match function should return 1 if match is success else return
zero. */
-static enum route_map_match_result_t
+static route_map_result_t
ospf6_routemap_rule_match_interface(void *rule, const struct prefix *prefix,
route_map_object_t type, void *object)
{
@@ -1433,9 +1433,10 @@ struct route_map_rule_cmd ospf6_routemap_rule_match_interface_cmd = {
ospf6_routemap_rule_match_interface_free};
/* Match function for matching route tags */
-static enum route_map_match_result_t
-ospf6_routemap_rule_match_tag(void *rule, const struct prefix *p,
- route_map_object_t type, void *object)
+static route_map_result_t ospf6_routemap_rule_match_tag(void *rule,
+ const struct prefix *p,
+ route_map_object_t type,
+ void *object)
{
route_tag_t *tag = rule;
struct ospf6_route *route = object;
@@ -1452,7 +1453,7 @@ static struct route_map_rule_cmd ospf6_routemap_rule_match_tag_cmd = {
route_map_rule_tag_free,
};
-static enum route_map_match_result_t
+static route_map_result_t
ospf6_routemap_rule_set_metric_type(void *rule, const struct prefix *prefix,
route_map_object_t type, void *object)
{
@@ -1488,7 +1489,7 @@ struct route_map_rule_cmd ospf6_routemap_rule_set_metric_type_cmd = {
ospf6_routemap_rule_set_metric_type_free,
};
-static enum route_map_match_result_t
+static route_map_result_t
ospf6_routemap_rule_set_metric(void *rule, const struct prefix *prefix,
route_map_object_t type, void *object)
{
@@ -1523,7 +1524,7 @@ struct route_map_rule_cmd ospf6_routemap_rule_set_metric_cmd = {
ospf6_routemap_rule_set_metric_free,
};
-static enum route_map_match_result_t
+static route_map_result_t
ospf6_routemap_rule_set_forwarding(void *rule, const struct prefix *prefix,
route_map_object_t type, void *object)
{
@@ -1561,9 +1562,10 @@ struct route_map_rule_cmd ospf6_routemap_rule_set_forwarding_cmd = {
ospf6_routemap_rule_set_forwarding_free,
};
-static enum route_map_match_result_t
-ospf6_routemap_rule_set_tag(void *rule, const struct prefix *p,
- route_map_object_t type, void *object)
+static route_map_result_t ospf6_routemap_rule_set_tag(void *rule,
+ const struct prefix *p,
+ route_map_object_t type,
+ void *object)
{
route_tag_t *tag = rule;
struct ospf6_route *route = object;
diff --git a/ospfd/ospf_routemap.c b/ospfd/ospf_routemap.c
index d725837fe..ab2d5ae58 100644
--- a/ospfd/ospf_routemap.c
+++ b/ospfd/ospf_routemap.c
@@ -126,9 +126,10 @@ static void ospf_route_map_event(const char *name)
/* `match ip netxthop ' */
/* Match function return 1 if match is success else return zero. */
-static enum route_map_match_result_t
-route_match_ip_nexthop(void *rule, const struct prefix *prefix,
- route_map_object_t type, void *object)
+static route_map_result_t route_match_ip_nexthop(void *rule,
+ const struct prefix *prefix,
+ route_map_object_t type,
+ void *object)
{
struct access_list *alist;
struct external_info *ei = object;
@@ -170,7 +171,7 @@ struct route_map_rule_cmd route_match_ip_nexthop_cmd = {
/* `match ip next-hop prefix-list PREFIX_LIST' */
-static enum route_map_match_result_t
+static route_map_result_t
route_match_ip_next_hop_prefix_list(void *rule, const struct prefix *prefix,
route_map_object_t type, void *object)
{
@@ -212,9 +213,10 @@ struct route_map_rule_cmd route_match_ip_next_hop_prefix_list_cmd = {
/* `match ip address IP_ACCESS_LIST' */
/* Match function should return 1 if match is success else return
zero. */
-static enum route_map_match_result_t
-route_match_ip_address(void *rule, const struct prefix *prefix,
- route_map_object_t type, void *object)
+static route_map_result_t route_match_ip_address(void *rule,
+ const struct prefix *prefix,
+ route_map_object_t type,
+ void *object)
{
struct access_list *alist;
/* struct prefix_ipv4 match; */
@@ -250,7 +252,7 @@ struct route_map_rule_cmd route_match_ip_address_cmd = {
route_match_ip_address_free};
/* `match ip address prefix-list PREFIX_LIST' */
-static enum route_map_match_result_t
+static route_map_result_t
route_match_ip_address_prefix_list(void *rule, const struct prefix *prefix,
route_map_object_t type, void *object)
{
@@ -286,9 +288,10 @@ struct route_map_rule_cmd route_match_ip_address_prefix_list_cmd = {
/* `match interface IFNAME' */
/* Match function should return 1 if match is success else return
zero. */
-static enum route_map_match_result_t
-route_match_interface(void *rule, const struct prefix *prefix,
- route_map_object_t type, void *object)
+static route_map_result_t route_match_interface(void *rule,
+ const struct prefix *prefix,
+ route_map_object_t type,
+ void *object)
{
struct interface *ifp;
struct external_info *ei;
@@ -324,9 +327,9 @@ struct route_map_rule_cmd route_match_interface_cmd = {
route_match_interface_free};
/* Match function return 1 if match is success else return zero. */
-static enum route_map_match_result_t
-route_match_tag(void *rule, const struct prefix *prefix,
- route_map_object_t type, void *object)
+static route_map_result_t route_match_tag(void *rule,
+ const struct prefix *prefix,
+ route_map_object_t type, void *object)
{
route_tag_t *tag;
struct external_info *ei;
@@ -355,9 +358,10 @@ struct ospf_metric {
/* `set metric METRIC' */
/* Set metric to attribute. */
-static enum route_map_match_result_t
-route_set_metric(void *rule, const struct prefix *prefix,
- route_map_object_t type, void *object)
+static route_map_result_t route_set_metric(void *rule,
+ const struct prefix *prefix,
+ route_map_object_t type,
+ void *object)
{
struct ospf_metric *metric;
struct external_info *ei;
@@ -435,9 +439,10 @@ struct route_map_rule_cmd route_set_metric_cmd = {
/* `set metric-type TYPE' */
/* Set metric-type to attribute. */
-static enum route_map_match_result_t
-route_set_metric_type(void *rule, const struct prefix *prefix,
- route_map_object_t type, void *object)
+static route_map_result_t route_set_metric_type(void *rule,
+ const struct prefix *prefix,
+ route_map_object_t type,
+ void *object)
{
uint32_t *metric_type;
struct external_info *ei;
@@ -484,9 +489,8 @@ struct route_map_rule_cmd route_set_metric_type_cmd = {
route_set_metric_type_free,
};
-static enum route_map_match_result_t
-route_set_tag(void *rule, const struct prefix *prefix, route_map_object_t type,
- void *object)
+static route_map_result_t route_set_tag(void *rule, const struct prefix *prefix,
+ route_map_object_t type, void *object)
{
route_tag_t *tag;
struct external_info *ei;
diff --git a/ospfd/ospf_zebra.c b/ospfd/ospf_zebra.c
index 951402f47..c178e367d 100644
--- a/ospfd/ospf_zebra.c
+++ b/ospfd/ospf_zebra.c
@@ -943,7 +943,7 @@ int ospf_redistribute_check(struct ospf *ospf, struct external_info *ei,
/* apply route-map if needed */
red = ospf_redist_lookup(ospf, type, instance);
if (red && ROUTEMAP_NAME(red)) {
- route_map_result_t ret;
+ int ret;
ret = route_map_apply(ROUTEMAP(red), (struct prefix *)p,
RMAP_OSPF, ei);
diff --git a/pimd/pim_cmd.c b/pimd/pim_cmd.c
index 2b97dd382..778819145 100644
--- a/pimd/pim_cmd.c
+++ b/pimd/pim_cmd.c
@@ -3082,7 +3082,7 @@ static void pim_show_group_rp_mappings_info(struct pim_instance *pim,
json_object *json_row = NULL;
if (pim->global_scope.current_bsr.s_addr == INADDR_ANY)
- strncpy(bsr_str, "0.0.0.0", sizeof(bsr_str));
+ strlcpy(bsr_str, "0.0.0.0", sizeof(bsr_str));
else
pim_inet4_dump("<bsr?>", pim->global_scope.current_bsr, bsr_str,
@@ -3650,7 +3650,7 @@ static void pim_show_bsr(struct pim_instance *pim,
vty_out(vty, "PIMv2 Bootstrap information\n");
if (pim->global_scope.current_bsr.s_addr == INADDR_ANY) {
- strncpy(bsr_str, "0.0.0.0", sizeof(bsr_str));
+ strlcpy(bsr_str, "0.0.0.0", sizeof(bsr_str));
pim_time_uptime(uptime, sizeof(uptime),
pim->global_scope.current_bsr_first_ts);
pim_time_uptime(last_bsm_seen, sizeof(last_bsm_seen),
@@ -3669,16 +3669,16 @@ static void pim_show_bsr(struct pim_instance *pim,
switch (pim->global_scope.state) {
case NO_INFO:
- strncpy(bsr_state, "NO_INFO", sizeof(bsr_state));
+ strlcpy(bsr_state, "NO_INFO", sizeof(bsr_state));
break;
case ACCEPT_ANY:
- strncpy(bsr_state, "ACCEPT_ANY", sizeof(bsr_state));
+ strlcpy(bsr_state, "ACCEPT_ANY", sizeof(bsr_state));
break;
case ACCEPT_PREFERRED:
- strncpy(bsr_state, "ACCEPT_PREFERRED", sizeof(bsr_state));
+ strlcpy(bsr_state, "ACCEPT_PREFERRED", sizeof(bsr_state));
break;
default:
- strncpy(bsr_state, "", sizeof(bsr_state));
+ strlcpy(bsr_state, "", sizeof(bsr_state));
}
if (uj) {
@@ -3806,48 +3806,6 @@ DEFUN (clear_ip_pim_statistics,
return CMD_SUCCESS;
}
-static void mroute_add_all(struct pim_instance *pim)
-{
- struct listnode *node;
- struct channel_oil *c_oil;
-
- for (ALL_LIST_ELEMENTS_RO(pim->channel_oil_list, node, c_oil)) {
- if (pim_mroute_add(c_oil, __PRETTY_FUNCTION__)) {
- /* just log warning */
- char source_str[INET_ADDRSTRLEN];
- char group_str[INET_ADDRSTRLEN];
- pim_inet4_dump("<source?>", c_oil->oil.mfcc_origin,
- source_str, sizeof(source_str));
- pim_inet4_dump("<group?>", c_oil->oil.mfcc_mcastgrp,
- group_str, sizeof(group_str));
- zlog_warn("%s %s: (S,G)=(%s,%s) failure writing MFC",
- __FILE__, __PRETTY_FUNCTION__, source_str,
- group_str);
- }
- }
-}
-
-static void mroute_del_all(struct pim_instance *pim)
-{
- struct listnode *node;
- struct channel_oil *c_oil;
-
- for (ALL_LIST_ELEMENTS_RO(pim->channel_oil_list, node, c_oil)) {
- if (pim_mroute_del(c_oil, __PRETTY_FUNCTION__)) {
- /* just log warning */
- char source_str[INET_ADDRSTRLEN];
- char group_str[INET_ADDRSTRLEN];
- pim_inet4_dump("<source?>", c_oil->oil.mfcc_origin,
- source_str, sizeof(source_str));
- pim_inet4_dump("<group?>", c_oil->oil.mfcc_mcastgrp,
- group_str, sizeof(group_str));
- zlog_warn("%s %s: (S,G)=(%s,%s) failure clearing MFC",
- __FILE__, __PRETTY_FUNCTION__, source_str,
- group_str);
- }
- }
-}
-
static void clear_mroute(struct pim_instance *pim)
{
struct pim_upstream *up;
@@ -5658,11 +5616,54 @@ DEFUN (show_ip_mroute_vrf_all,
return CMD_SUCCESS;
}
+DEFUN (clear_ip_mroute_count,
+ clear_ip_mroute_count_cmd,
+ "clear ip mroute [vrf NAME] count",
+ CLEAR_STR
+ IP_STR
+ MROUTE_STR
+ VRF_CMD_HELP_STR
+ "Route and packet count data\n")
+{
+ int idx = 2;
+ struct listnode *node;
+ struct channel_oil *c_oil;
+ struct static_route *sr;
+ struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx);
+ struct pim_instance *pim;
+
+ if (!vrf)
+ return CMD_WARNING;
+
+ pim = vrf->info;
+ for (ALL_LIST_ELEMENTS_RO(pim->channel_oil_list, node, c_oil)) {
+ if (!c_oil->installed)
+ continue;
+
+ pim_mroute_update_counters(c_oil);
+ c_oil->cc.origpktcnt = c_oil->cc.pktcnt;
+ c_oil->cc.origbytecnt = c_oil->cc.bytecnt;
+ c_oil->cc.origwrong_if = c_oil->cc.wrong_if;
+ }
+
+ for (ALL_LIST_ELEMENTS_RO(pim->static_routes, node, sr)) {
+ if (!sr->c_oil.installed)
+ continue;
+
+ pim_mroute_update_counters(&sr->c_oil);
+
+ sr->c_oil.cc.origpktcnt = sr->c_oil.cc.pktcnt;
+ sr->c_oil.cc.origbytecnt = sr->c_oil.cc.bytecnt;
+ sr->c_oil.cc.origwrong_if = sr->c_oil.cc.wrong_if;
+ }
+ return CMD_SUCCESS;
+}
+
static void show_mroute_count(struct pim_instance *pim, struct vty *vty)
{
struct listnode *node;
struct channel_oil *c_oil;
- struct static_route *s_route;
+ struct static_route *sr;
vty_out(vty, "\n");
@@ -5686,28 +5687,30 @@ static void show_mroute_count(struct pim_instance *pim, struct vty *vty)
vty_out(vty, "%-15s %-15s %-8llu %-7ld %-10ld %-7ld\n",
source_str, group_str, c_oil->cc.lastused / 100,
- c_oil->cc.pktcnt, c_oil->cc.bytecnt,
- c_oil->cc.wrong_if);
+ c_oil->cc.pktcnt - c_oil->cc.origpktcnt,
+ c_oil->cc.bytecnt - c_oil->cc.origbytecnt,
+ c_oil->cc.wrong_if - c_oil->cc.origwrong_if);
}
- for (ALL_LIST_ELEMENTS_RO(pim->static_routes, node, s_route)) {
+ for (ALL_LIST_ELEMENTS_RO(pim->static_routes, node, sr)) {
char group_str[INET_ADDRSTRLEN];
char source_str[INET_ADDRSTRLEN];
- if (!s_route->c_oil.installed)
+ if (!sr->c_oil.installed)
continue;
- pim_mroute_update_counters(&s_route->c_oil);
+ pim_mroute_update_counters(&sr->c_oil);
- pim_inet4_dump("<group?>", s_route->c_oil.oil.mfcc_mcastgrp,
+ pim_inet4_dump("<group?>", sr->c_oil.oil.mfcc_mcastgrp,
group_str, sizeof(group_str));
- pim_inet4_dump("<source?>", s_route->c_oil.oil.mfcc_origin,
+ pim_inet4_dump("<source?>", sr->c_oil.oil.mfcc_origin,
source_str, sizeof(source_str));
vty_out(vty, "%-15s %-15s %-8llu %-7ld %-10ld %-7ld\n",
- source_str, group_str, s_route->c_oil.cc.lastused,
- s_route->c_oil.cc.pktcnt, s_route->c_oil.cc.bytecnt,
- s_route->c_oil.cc.wrong_if);
+ source_str, group_str, sr->c_oil.cc.lastused,
+ sr->c_oil.cc.pktcnt - sr->c_oil.cc.origpktcnt,
+ sr->c_oil.cc.bytecnt - sr->c_oil.cc.origbytecnt,
+ sr->c_oil.cc.wrong_if - sr->c_oil.cc.origwrong_if);
}
}
@@ -10351,6 +10354,7 @@ void pim_cmd_init(void)
install_element(VIEW_NODE, &show_ip_pim_bsm_db_cmd);
install_element(VIEW_NODE, &show_ip_pim_statistics_cmd);
+ install_element(ENABLE_NODE, &clear_ip_mroute_count_cmd);
install_element(ENABLE_NODE, &clear_ip_interfaces_cmd);
install_element(ENABLE_NODE, &clear_ip_igmp_interfaces_cmd);
install_element(ENABLE_NODE, &clear_ip_mroute_cmd);
diff --git a/pimd/pim_oil.h b/pimd/pim_oil.h
index c5106d01c..57930e341 100644
--- a/pimd/pim_oil.h
+++ b/pimd/pim_oil.h
@@ -53,10 +53,13 @@
struct channel_counts {
unsigned long long lastused;
+ unsigned long origpktcnt;
unsigned long pktcnt;
unsigned long oldpktcnt;
+ unsigned long origbytecnt;
unsigned long bytecnt;
unsigned long oldbytecnt;
+ unsigned long origwrong_if;
unsigned long wrong_if;
unsigned long oldwrong_if;
};
diff --git a/ripd/rip_routemap.c b/ripd/rip_routemap.c
index 3c1c779ba..3216b8f89 100644
--- a/ripd/rip_routemap.c
+++ b/ripd/rip_routemap.c
@@ -42,9 +42,10 @@ struct rip_metric_modifier {
/* `match metric METRIC' */
/* Match function return 1 if match is success else return zero. */
-static enum route_map_match_result_t
-route_match_metric(void *rule, const struct prefix *prefix,
- route_map_object_t type, void *object)
+static route_map_result_t route_match_metric(void *rule,
+ const struct prefix *prefix,
+ route_map_object_t type,
+ void *object)
{
uint32_t *metric;
uint32_t check;
@@ -94,9 +95,10 @@ struct route_map_rule_cmd route_match_metric_cmd = {
/* `match interface IFNAME' */
/* Match function return 1 if match is success else return zero. */
-static enum route_map_match_result_t
-route_match_interface(void *rule, const struct prefix *prefix,
- route_map_object_t type, void *object)
+static route_map_result_t route_match_interface(void *rule,
+ const struct prefix *prefix,
+ route_map_object_t type,
+ void *object)
{
struct rip_info *rinfo;
struct interface *ifp;
@@ -141,9 +143,10 @@ struct route_map_rule_cmd route_match_interface_cmd = {
/* `match ip next-hop IP_ACCESS_LIST' */
/* Match function return 1 if match is success else return zero. */
-static enum route_map_match_result_t
-route_match_ip_next_hop(void *rule, const struct prefix *prefix,
- route_map_object_t type, void *object)
+static route_map_result_t route_match_ip_next_hop(void *rule,
+ const struct prefix *prefix,
+ route_map_object_t type,
+ void *object)
{
struct access_list *alist;
struct rip_info *rinfo;
@@ -187,7 +190,7 @@ static struct route_map_rule_cmd route_match_ip_next_hop_cmd = {
/* `match ip next-hop prefix-list PREFIX_LIST' */
-static enum route_map_match_result_t
+static route_map_result_t
route_match_ip_next_hop_prefix_list(void *rule, const struct prefix *prefix,
route_map_object_t type, void *object)
{
@@ -232,9 +235,10 @@ static struct route_map_rule_cmd route_match_ip_next_hop_prefix_list_cmd = {
/* Match function should return 1 if match is success else return
zero. */
-static enum route_map_match_result_t
-route_match_ip_address(void *rule, const struct prefix *prefix,
- route_map_object_t type, void *object)
+static route_map_result_t route_match_ip_address(void *rule,
+ const struct prefix *prefix,
+ route_map_object_t type,
+ void *object)
{
struct access_list *alist;
@@ -270,7 +274,7 @@ static struct route_map_rule_cmd route_match_ip_address_cmd = {
/* `match ip address prefix-list PREFIX_LIST' */
-static enum route_map_match_result_t
+static route_map_result_t
route_match_ip_address_prefix_list(void *rule, const struct prefix *prefix,
route_map_object_t type, void *object)
{
@@ -305,9 +309,8 @@ static struct route_map_rule_cmd route_match_ip_address_prefix_list_cmd = {
/* `match tag TAG' */
/* Match function return 1 if match is success else return zero. */
-static enum route_map_match_result_t
-route_match_tag(void *rule, const struct prefix *p, route_map_object_t type,
- void *object)
+static route_map_result_t route_match_tag(void *rule, const struct prefix *p,
+ route_map_object_t type, void *object)
{
route_tag_t *tag;
struct rip_info *rinfo;
@@ -336,9 +339,10 @@ static struct route_map_rule_cmd route_match_tag_cmd = {
/* `set metric METRIC' */
/* Set metric to attribute. */
-static enum route_map_match_result_t
-route_set_metric(void *rule, const struct prefix *prefix,
- route_map_object_t type, void *object)
+static route_map_result_t route_set_metric(void *rule,
+ const struct prefix *prefix,
+ route_map_object_t type,
+ void *object)
{
if (type == RMAP_RIP) {
struct rip_metric_modifier *mod;
@@ -434,7 +438,7 @@ static struct route_map_rule_cmd route_set_metric_cmd = {
/* `set ip next-hop IP_ADDRESS' */
/* Set nexthop to object. ojbect must be pointer to struct attr. */
-static enum route_map_match_result_t route_set_ip_nexthop(void *rule,
+static route_map_result_t route_set_ip_nexthop(void *rule,
const struct prefix *prefix,
route_map_object_t type,
void *object)
@@ -487,9 +491,8 @@ static struct route_map_rule_cmd route_set_ip_nexthop_cmd = {
/* `set tag TAG' */
/* Set tag to object. ojbect must be pointer to struct attr. */
-static enum route_map_match_result_t
-route_set_tag(void *rule, const struct prefix *prefix, route_map_object_t type,
- void *object)
+static route_map_result_t route_set_tag(void *rule, const struct prefix *prefix,
+ route_map_object_t type, void *object)
{
route_tag_t *tag;
struct rip_info *rinfo;
diff --git a/ripngd/ripng_interface.c b/ripngd/ripng_interface.c
index 5a4087b17..d83f4d279 100644
--- a/ripngd/ripng_interface.c
+++ b/ripngd/ripng_interface.c
@@ -184,7 +184,8 @@ static int ripng_if_down(struct interface *ifp)
zlog_debug("turn off %s", ifp->name);
/* Leave from multicast group. */
- ripng_multicast_leave(ifp, ripng->sock);
+ if (ripng)
+ ripng_multicast_leave(ifp, ripng->sock);
ri->running = 0;
}
diff --git a/ripngd/ripng_routemap.c b/ripngd/ripng_routemap.c
index 671586cfd..0604e272c 100644
--- a/ripngd/ripng_routemap.c
+++ b/ripngd/ripng_routemap.c
@@ -38,9 +38,10 @@ struct rip_metric_modifier {
/* `match metric METRIC' */
/* Match function return 1 if match is success else return zero. */
-static enum route_map_match_result_t
-route_match_metric(void *rule, const struct prefix *prefix,
- route_map_object_t type, void *object)
+static route_map_result_t route_match_metric(void *rule,
+ const struct prefix *prefix,
+ route_map_object_t type,
+ void *object)
{
uint32_t *metric;
struct ripng_info *rinfo;
@@ -85,9 +86,10 @@ static struct route_map_rule_cmd route_match_metric_cmd = {
/* `match interface IFNAME' */
/* Match function return 1 if match is success else return zero. */
-static enum route_map_match_result_t
-route_match_interface(void *rule, const struct prefix *prefix,
- route_map_object_t type, void *object)
+static route_map_result_t route_match_interface(void *rule,
+ const struct prefix *prefix,
+ route_map_object_t type,
+ void *object)
{
struct ripng_info *rinfo;
struct interface *ifp;
@@ -127,10 +129,9 @@ static struct route_map_rule_cmd route_match_interface_cmd = {
/* `match tag TAG' */
/* Match function return 1 if match is success else return zero. */
-static enum route_map_match_result_t route_match_tag(void *rule,
- const struct prefix *prefix,
- route_map_object_t type,
- void *object)
+static route_map_result_t route_match_tag(void *rule,
+ const struct prefix *prefix,
+ route_map_object_t type, void *object)
{
route_tag_t *tag;
struct ripng_info *rinfo;
@@ -158,9 +159,10 @@ static struct route_map_rule_cmd route_match_tag_cmd = {
/* `set metric METRIC' */
/* Set metric to attribute. */
-static enum route_map_match_result_t
-route_set_metric(void *rule, const struct prefix *prefix,
- route_map_object_t type, void *object)
+static route_map_result_t route_set_metric(void *rule,
+ const struct prefix *prefix,
+ route_map_object_t type,
+ void *object)
{
if (type == RMAP_RIPNG) {
struct rip_metric_modifier *mod;
@@ -254,9 +256,10 @@ static struct route_map_rule_cmd route_set_metric_cmd = {
/* `set ipv6 next-hop local IP_ADDRESS' */
/* Set nexthop to object. ojbect must be pointer to struct attr. */
-static enum route_map_match_result_t
-route_set_ipv6_nexthop_local(void *rule, const struct prefix *p,
- route_map_object_t type, void *object)
+static route_map_result_t route_set_ipv6_nexthop_local(void *rule,
+ const struct prefix *p,
+ route_map_object_t type,
+ void *object)
{
struct in6_addr *address;
struct ripng_info *rinfo;
@@ -307,9 +310,9 @@ static struct route_map_rule_cmd route_set_ipv6_nexthop_local_cmd = {
/* `set tag TAG' */
/* Set tag to object. ojbect must be pointer to struct attr. */
-static enum route_map_match_result_t
-route_set_tag(void *rule, const struct prefix *prefix, route_map_object_t type,
- void *object)
+static route_map_result_t route_set_tag(void *rule,
+ const struct prefix *prefix,
+ route_map_object_t type, void *object)
{
route_tag_t *tag;
struct ripng_info *rinfo;
diff --git a/tests/.gitignore b/tests/.gitignore
index 380172487..7177165e4 100644
--- a/tests/.gitignore
+++ b/tests/.gitignore
@@ -30,6 +30,7 @@
/lib/test_idalloc
/lib/test_memory
/lib/test_nexthop_iter
+/lib/test_printfrr
/lib/test_privs
/lib/test_ringbuf
/lib/test_segv
diff --git a/tests/helpers/c/main.c b/tests/helpers/c/main.c
index 11db2dabc..b1dcfcf70 100644
--- a/tests/helpers/c/main.c
+++ b/tests/helpers/c/main.c
@@ -153,7 +153,7 @@ int main(int argc, char **argv)
/* Library inits. */
cmd_init(1);
- vty_init(master);
+ vty_init(master, false);
memory_init();
yang_init();
nb_init(master, NULL, 0);
diff --git a/tests/lib/cli/common_cli.c b/tests/lib/cli/common_cli.c
index 393b58874..2071ae08c 100644
--- a/tests/lib/cli/common_cli.c
+++ b/tests/lib/cli/common_cli.c
@@ -82,7 +82,7 @@ int main(int argc, char **argv)
cmd_hostname_set("test");
cmd_domainname_set("test.domain");
- vty_init(master);
+ vty_init(master, false);
memory_init();
yang_init();
nb_init(master, NULL, 0);
diff --git a/tests/lib/northbound/test_oper_data.c b/tests/lib/northbound/test_oper_data.c
index 7cd622854..3180f9f9f 100644
--- a/tests/lib/northbound/test_oper_data.c
+++ b/tests/lib/northbound/test_oper_data.c
@@ -411,7 +411,7 @@ int main(int argc, char **argv)
/* Library inits. */
cmd_init(1);
cmd_hostname_set("test");
- vty_init(master);
+ vty_init(master, false);
memory_init();
yang_init();
nb_init(master, modules, array_size(modules));
diff --git a/tests/lib/test_printfrr.c b/tests/lib/test_printfrr.c
new file mode 100644
index 000000000..c8ef150b0
--- /dev/null
+++ b/tests/lib/test_printfrr.c
@@ -0,0 +1,148 @@
+/*
+ * printfrr() unit test
+ * Copyright (C) 2019 David Lamparter
+ *
+ * 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"
+
+#include <math.h>
+
+#include "lib/printfrr.h"
+#include "lib/memory.h"
+#include "lib/prefix.h"
+
+static int errors;
+
+static void printcmp(const char *fmt, ...)
+{
+ va_list ap;
+ char buf[256], bufrr[256], *p;
+ int cmp;
+ memset(bufrr, 0xcc, sizeof(bufrr));
+
+ va_start(ap, fmt);
+ vsnprintf(buf, sizeof(buf), fmt, ap);
+ va_end(ap);
+
+ va_start(ap, fmt);
+ vsnprintfrr(bufrr, sizeof(bufrr), fmt, ap);
+ va_end(ap);
+
+ cmp = strcmp(buf, bufrr);
+
+ /* OS dependent "+nan" vs. "nan" */
+ if (cmp && (p = strstr(bufrr, "+nan"))) {
+ p[0] = ' ';
+ if (!strcmp(buf, bufrr))
+ cmp = 0;
+ p[0] = '+';
+ }
+ printf("fmt: \"%s\"\nsys: \"%s\"\nfrr: \"%s\"\n%s\n\n",
+ fmt, buf, bufrr, cmp ? "ERROR" : "ok");
+
+ if (cmp)
+ errors++;
+}
+
+static void printchk(const char *ref, const char *fmt, ...)
+{
+ va_list ap;
+ char bufrr[256];
+ memset(bufrr, 0xcc, sizeof(bufrr));
+
+ va_start(ap, fmt);
+ vsnprintfrr(bufrr, sizeof(bufrr), fmt, ap);
+ va_end(ap);
+
+ printf("fmt: \"%s\"\nref: \"%s\"\nfrr: \"%s\"\n%s\n\n",
+ fmt, ref, bufrr, strcmp(ref, bufrr) ? "ERROR" : "ok");
+ if (strcmp(ref, bufrr))
+ errors++;
+}
+
+int main(int argc, char **argv)
+{
+ size_t i;
+ float flts[] = {
+ 123.456789,
+ 23.456789e-30,
+ 3.456789e+30,
+ INFINITY,
+ NAN,
+ };
+ uint64_t ui64 = 0xfeed1278cafef00d;
+ struct in_addr ip;
+ char *p;
+ char buf[256];
+
+ printcmp("%d %u %d %u", 123, 123, -456, -456);
+ printcmp("%lld %llu %lld %llu", 123LL, 123LL, -456LL, -456LL);
+
+ printcmp("%-20s,%20s,%.20s", "test", "test", "test");
+ printcmp("%-3s,%3s,%.3s", "test", "test", "test");
+ printcmp("%-6.3s,%6.3s,%6.3s", "test", "test", "test");
+ printcmp("%*s,%*s,%.*s", -3, "test", 3, "test", 3, "test");
+
+ for (i = 0; i < array_size(flts); i++) {
+ printcmp("%-6.3e,%6.3e,%+06.3e", flts[i], flts[i], flts[i]);
+ printcmp("%-6.3f,%6.3f,%+06.3f", flts[i], flts[i], flts[i]);
+ printcmp("%-6.3g,%6.3g,%+06.3g", flts[i], flts[i], flts[i]);
+ printcmp("%-6.3a,%6.3a,%+06.3a", flts[i], flts[i], flts[i]);
+ }
+
+ printchk("-77385308584349683 18369358765125201933 feed1278cafef00d",
+ "%Ld %Lu %Lx", ui64, ui64, ui64);
+
+ inet_aton("192.168.1.2", &ip);
+ printchk("192.168.1.2", "%pI4", &ip);
+ printchk(" 192.168.1.2", "%20pI4", &ip);
+
+ printcmp("%p", &ip);
+
+ snprintfrr(buf, sizeof(buf), "test%s", "#1");
+ csnprintfrr(buf, sizeof(buf), "test%s", "#2");
+ assert(strcmp(buf, "test#1test#2") == 0);
+
+ p = asnprintfrr(MTYPE_TMP, buf, sizeof(buf), "test%s", "#3");
+ assert(p == buf);
+ assert(strcmp(buf, "test#3") == 0);
+
+ p = asnprintfrr(MTYPE_TMP, buf, 4, "test%s", "#4");
+ assert(p != buf);
+ assert(strcmp(p, "test#4") == 0);
+ XFREE(MTYPE_TMP, p);
+
+ p = asprintfrr(MTYPE_TMP, "test%s", "#5");
+ assert(strcmp(p, "test#5") == 0);
+ XFREE(MTYPE_TMP, p);
+
+ struct prefix_sg sg;
+ sg.src.s_addr = INADDR_ANY;
+ sg.grp.s_addr = INADDR_ANY;
+ printchk("(*,*)", "%pSG4", &sg);
+
+ inet_aton("192.168.1.2", &sg.src);
+ printchk("(192.168.1.2,*)", "%pSG4", &sg);
+
+ inet_aton("224.1.2.3", &sg.grp);
+ printchk("(192.168.1.2,224.1.2.3)", "%pSG4", &sg);
+
+ sg.src.s_addr = INADDR_ANY;
+ printchk("(*,224.1.2.3)", "%pSG4", &sg);
+
+ return !!errors;
+}
diff --git a/tests/lib/test_printfrr.py b/tests/lib/test_printfrr.py
new file mode 100644
index 000000000..4fe238618
--- /dev/null
+++ b/tests/lib/test_printfrr.py
@@ -0,0 +1,6 @@
+import frrtest
+
+class TestPrintfrr(frrtest.TestMultiOut):
+ program = './test_printfrr'
+
+TestPrintfrr.exit_cleanly()
diff --git a/tests/subdir.am b/tests/subdir.am
index 10a78b98a..1d29a418c 100644
--- a/tests/subdir.am
+++ b/tests/subdir.am
@@ -54,6 +54,7 @@ check_PROGRAMS = \
tests/lib/test_idalloc \
tests/lib/test_memory \
tests/lib/test_nexthop_iter \
+ tests/lib/test_printfrr \
tests/lib/test_privs \
tests/lib/test_ringbuf \
tests/lib/test_srcdest_table \
@@ -230,6 +231,10 @@ tests_lib_test_nexthop_iter_CFLAGS = $(TESTS_CFLAGS)
tests_lib_test_nexthop_iter_CPPFLAGS = $(TESTS_CPPFLAGS)
tests_lib_test_nexthop_iter_LDADD = $(ALL_TESTS_LDADD)
tests_lib_test_nexthop_iter_SOURCES = tests/lib/test_nexthop_iter.c tests/helpers/c/prng.c
+tests_lib_test_printfrr_CFLAGS = $(TESTS_CFLAGS)
+tests_lib_test_printfrr_CPPFLAGS = $(TESTS_CPPFLAGS)
+tests_lib_test_printfrr_LDADD = $(ALL_TESTS_LDADD)
+tests_lib_test_printfrr_SOURCES = tests/lib/test_printfrr.c
tests_lib_test_privs_CFLAGS = $(TESTS_CFLAGS)
tests_lib_test_privs_CPPFLAGS = $(TESTS_CPPFLAGS)
tests_lib_test_privs_LDADD = $(ALL_TESTS_LDADD)
@@ -317,6 +322,7 @@ EXTRA_DIST += \
tests/lib/northbound/test_oper_data.refout \
tests/lib/test_atomlist.py \
tests/lib/test_nexthop_iter.py \
+ tests/lib/test_printfrr.py \
tests/lib/test_ringbuf.py \
tests/lib/test_srcdest_table.py \
tests/lib/test_stream.py \
diff --git a/tests/topotests/bgp_ipv6_rtadv/__init__.py b/tests/topotests/bgp_ipv6_rtadv/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/tests/topotests/bgp_ipv6_rtadv/__init__.py
diff --git a/tests/topotests/bgp_ipv6_rtadv/r1/bgpd.conf b/tests/topotests/bgp_ipv6_rtadv/r1/bgpd.conf
new file mode 100644
index 000000000..1623b4578
--- /dev/null
+++ b/tests/topotests/bgp_ipv6_rtadv/r1/bgpd.conf
@@ -0,0 +1,13 @@
+router bgp 101
+ bgp router-id 10.254.254.1
+ neighbor r2g peer-group
+ neighbor r2g remote-as external
+ neighbor r2g bfd
+ neighbor r1-eth0 interface peer-group r2g
+ address-family ipv4 unicast
+ redistribute connected
+ exit-address-family
+ address-family ipv6 unicast
+ neighbor r2g activate
+ exit-address-family
+!
diff --git a/tests/topotests/bgp_ipv6_rtadv/r1/ipv4_routes.json b/tests/topotests/bgp_ipv6_rtadv/r1/ipv4_routes.json
new file mode 100644
index 000000000..8718e4977
--- /dev/null
+++ b/tests/topotests/bgp_ipv6_rtadv/r1/ipv4_routes.json
@@ -0,0 +1,44 @@
+{
+ "10.254.254.2/32": [
+ {
+ "distance": 20,
+ "protocol": "bgp",
+ "internalFlags": 8,
+ "metric": 0,
+ "selected": true,
+ "destSelected": true,
+ "prefix": "10.254.254.2/32",
+ "nexthops": [
+ {
+ "interfaceName": "r1-eth0",
+ "interfaceIndex": 2,
+ "fib": true,
+ "flags": 3,
+ "active": true,
+ "afi": "ipv6"
+ }
+ ]
+ }
+ ],
+ "10.254.254.1/32": [
+ {
+ "distance": 0,
+ "protocol": "connected",
+ "internalFlags": 8,
+ "metric": 0,
+ "selected": true,
+ "destSelected": true,
+ "prefix": "10.254.254.1/32",
+ "nexthops": [
+ {
+ "directlyConnected": true,
+ "interfaceName": "lo",
+ "interfaceIndex": 1,
+ "fib": true,
+ "flags": 3,
+ "active": true
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/bgp_ipv6_rtadv/r1/ipv6_routes.json b/tests/topotests/bgp_ipv6_rtadv/r1/ipv6_routes.json
new file mode 100644
index 000000000..d0378b564
--- /dev/null
+++ b/tests/topotests/bgp_ipv6_rtadv/r1/ipv6_routes.json
@@ -0,0 +1,39 @@
+{
+ "2001:db8:1::/64": [
+ {
+ "distance": 20,
+ "protocol": "bgp",
+ "internalFlags": 0,
+ "metric": 0,
+ "prefix": "2001:db8:1::/64",
+ "nexthops": [
+ {
+ "interfaceName": "r1-eth0",
+ "interfaceIndex": 2,
+ "flags": 1,
+ "active": true,
+ "afi": "ipv6"
+ }
+ ]
+ },
+ {
+ "distance": 0,
+ "protocol": "connected",
+ "internalFlags": 8,
+ "metric": 0,
+ "selected": true,
+ "destSelected": true,
+ "prefix": "2001:db8:1::/64",
+ "nexthops": [
+ {
+ "directlyConnected": true,
+ "interfaceName": "r1-eth0",
+ "interfaceIndex": 2,
+ "fib": true,
+ "flags": 3,
+ "active": true
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/bgp_ipv6_rtadv/r1/zebra.conf b/tests/topotests/bgp_ipv6_rtadv/r1/zebra.conf
new file mode 100644
index 000000000..f95c3b07a
--- /dev/null
+++ b/tests/topotests/bgp_ipv6_rtadv/r1/zebra.conf
@@ -0,0 +1,9 @@
+debug zebra packet recv
+debug zebra packet send
+log stdout
+interface lo
+ ip address 10.254.254.1/32
+!
+interface r1-eth0
+ ipv6 address 2001:db8:1::1/64
+!
diff --git a/tests/topotests/bgp_ipv6_rtadv/r2/bgpd.conf b/tests/topotests/bgp_ipv6_rtadv/r2/bgpd.conf
new file mode 100644
index 000000000..bf42d2181
--- /dev/null
+++ b/tests/topotests/bgp_ipv6_rtadv/r2/bgpd.conf
@@ -0,0 +1,16 @@
+router bgp 102
+ bgp router-id 10.254.254.2
+ neighbor r2g peer-group
+ neighbor r2g remote-as external
+ neighbor r2g bfd
+ neighbor r2-eth0 interface peer-group r2g
+ !
+ address-family ipv4 unicast
+ redistribute connected
+ exit-address-family
+ !
+ address-family ipv6 unicast
+ redistribute connected
+ neighbor r2g activate
+ exit-address-family
+!
diff --git a/tests/topotests/bgp_ipv6_rtadv/r2/ipv4_routes.json b/tests/topotests/bgp_ipv6_rtadv/r2/ipv4_routes.json
new file mode 100644
index 000000000..fe26937e8
--- /dev/null
+++ b/tests/topotests/bgp_ipv6_rtadv/r2/ipv4_routes.json
@@ -0,0 +1,44 @@
+{
+ "10.254.254.2/32": [
+ {
+ "distance": 0,
+ "protocol": "connected",
+ "internalFlags": 8,
+ "metric": 0,
+ "selected": true,
+ "destSelected": true,
+ "prefix": "10.254.254.2/32",
+ "nexthops": [
+ {
+ "directlyConnected": true,
+ "interfaceName": "lo",
+ "interfaceIndex": 1,
+ "fib": true,
+ "flags": 3,
+ "active": true
+ }
+ ]
+ }
+ ],
+ "10.254.254.1/32": [
+ {
+ "distance": 20,
+ "protocol": "bgp",
+ "internalFlags": 8,
+ "metric": 0,
+ "selected": true,
+ "destSelected": true,
+ "prefix": "10.254.254.1/32",
+ "nexthops": [
+ {
+ "interfaceName": "r2-eth0",
+ "interfaceIndex": 2,
+ "fib": true,
+ "flags": 3,
+ "active": true,
+ "afi": "ipv6"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/bgp_ipv6_rtadv/r2/ipv6_routes.json b/tests/topotests/bgp_ipv6_rtadv/r2/ipv6_routes.json
new file mode 100644
index 000000000..d5ad1a2c5
--- /dev/null
+++ b/tests/topotests/bgp_ipv6_rtadv/r2/ipv6_routes.json
@@ -0,0 +1,23 @@
+{
+ "2001:db8:1::/64": [
+ {
+ "distance": 0,
+ "protocol": "connected",
+ "internalFlags": 8,
+ "metric": 0,
+ "selected": true,
+ "destSelected": true,
+ "prefix": "2001:db8:1::/64",
+ "nexthops": [
+ {
+ "directlyConnected": true,
+ "interfaceName": "r2-eth0",
+ "interfaceIndex": 2,
+ "fib": true,
+ "flags": 3,
+ "active": true
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/bgp_ipv6_rtadv/r2/zebra.conf b/tests/topotests/bgp_ipv6_rtadv/r2/zebra.conf
new file mode 100644
index 000000000..0131a11be
--- /dev/null
+++ b/tests/topotests/bgp_ipv6_rtadv/r2/zebra.conf
@@ -0,0 +1,9 @@
+ip forwarding
+ipv6 forwarding
+!
+interface lo
+ ip address 10.254.254.2/32
+!
+interface r2-eth0
+ ipv6 address 2001:db8:1::2/64
+!
diff --git a/tests/topotests/bgp_ipv6_rtadv/test_bgp_ipv6_rtadv.dot b/tests/topotests/bgp_ipv6_rtadv/test_bgp_ipv6_rtadv.dot
new file mode 100644
index 000000000..da67c29a0
--- /dev/null
+++ b/tests/topotests/bgp_ipv6_rtadv/test_bgp_ipv6_rtadv.dot
@@ -0,0 +1,44 @@
+## Color coding:
+#########################
+## Main FRR: #f08080 red
+## Switches: #d0e0d0 gray
+## RIP: #19e3d9 Cyan
+## RIPng: #fcb314 dark yellow
+## OSPFv2: #32b835 Green
+## OSPFv3: #19e3d9 Cyan
+## ISIS IPv4 #fcb314 dark yellow
+## ISIS IPv6 #9a81ec purple
+## BGP IPv4 #eee3d3 beige
+## BGP IPv6 #fdff00 yellow
+##### Colors (see http://www.color-hex.com/)
+
+graph template {
+ label="bfd-topo2";
+
+ # Routers
+ r1 [
+ shape=doubleoctagon,
+ label="r1",
+ fillcolor="#f08080",
+ style=filled,
+ ];
+ r2 [
+ shape=doubleoctagon
+ label="r2",
+ fillcolor="#f08080",
+ style=filled,
+ ];
+
+ # Switches
+ sw1 [
+ shape=oval,
+ label="sw1\n2001:db8:1::/64",
+ fillcolor="#d0e0d0",
+ style=filled,
+ ];
+
+ # Connections
+ r1 -- sw1 [label="eth0"];
+ r2 -- sw1 [label="eth0"];
+
+}
diff --git a/tests/topotests/bgp_ipv6_rtadv/test_bgp_ipv6_rtadv.py b/tests/topotests/bgp_ipv6_rtadv/test_bgp_ipv6_rtadv.py
new file mode 100644
index 000000000..6cf223af4
--- /dev/null
+++ b/tests/topotests/bgp_ipv6_rtadv/test_bgp_ipv6_rtadv.py
@@ -0,0 +1,142 @@
+#!/usr/bin/env python
+
+#
+# test_bgp_ipv6_rtadv.py
+# Part of NetDEF Topology Tests
+#
+# Copyright (c) 2019 by 6WIND
+#
+# 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_bgp_ipv6_rtadv.py: Test the FRR/Quagga BGP daemon with BGP IPv6 interface
+ with route advertisements on a separate netns.
+"""
+
+import os
+import sys
+import json
+from functools import partial
+import pytest
+
+# 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 BGPIPV6RTADVTopo(Topo):
+ "Test topology builder"
+ def build(self, *_args, **_opts):
+ "Build function"
+ tgen = get_topogen(self)
+
+ # Create 2 routers.
+ tgen.add_router('r1')
+ tgen.add_router('r2')
+
+ switch = tgen.add_switch('s1')
+ switch.add_link(tgen.gears['r1'])
+ switch.add_link(tgen.gears['r2'])
+
+def setup_module(mod):
+ "Sets up the pytest environment"
+ tgen = Topogen(BGPIPV6RTADVTopo, mod.__name__)
+ tgen.start_topology()
+
+ router_list = tgen.routers()
+
+ 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_BGP,
+ os.path.join(CWD, '{}/bgpd.conf'.format(rname))
+ )
+
+ # Initialize all routers.
+ tgen.start_router()
+
+def teardown_module(_mod):
+ "Teardown the pytest environment"
+ tgen = get_topogen()
+
+ tgen.stop_topology()
+
+
+def test_protocols_convergence():
+ """
+ Assert that all protocols have converged
+ statuses as they depend on it.
+ """
+ tgen = get_topogen()
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ # Check IPv4 routing tables.
+ logger.info("Checking IPv4 routes for convergence")
+ for router in tgen.routers().values():
+ json_file = '{}/{}/ipv4_routes.json'.format(CWD, router.name)
+ if not os.path.isfile(json_file):
+ logger.info('skipping file {}'.format(json_file))
+ continue
+
+ expected = json.loads(open(json_file).read())
+ test_func = partial(topotest.router_json_cmp,
+ router, 'show ip route json'.format(router.name), expected)
+ _, result = topotest.run_and_expect(test_func, None, count=160,
+ wait=0.5)
+ assertmsg = '"{}" JSON output mismatches'.format(router.name)
+ assert result is None, assertmsg
+
+ # Check IPv6 routing tables.
+ logger.info("Checking IPv6 routes for convergence")
+ for router in tgen.routers().values():
+ json_file = '{}/{}/ipv6_routes.json'.format(CWD, router.name)
+ if not os.path.isfile(json_file):
+ logger.info('skipping file {}'.format(json_file))
+ continue
+
+ expected = json.loads(open(json_file).read())
+ test_func = partial(topotest.router_json_cmp,
+ router, 'show ipv6 route json'.format(router.name), expected)
+ _, result = topotest.run_and_expect(test_func, None, count=160,
+ wait=0.5)
+ assertmsg = '"{}" JSON output mismatches'.format(router.name)
+ assert result is None, assertmsg
+
+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/bgp_vrf_lite_ipv6_rtadv/__init__.py b/tests/topotests/bgp_vrf_lite_ipv6_rtadv/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/tests/topotests/bgp_vrf_lite_ipv6_rtadv/__init__.py
diff --git a/tests/topotests/bgp_vrf_lite_ipv6_rtadv/r1/bgpd.conf b/tests/topotests/bgp_vrf_lite_ipv6_rtadv/r1/bgpd.conf
new file mode 100644
index 000000000..3c974c767
--- /dev/null
+++ b/tests/topotests/bgp_vrf_lite_ipv6_rtadv/r1/bgpd.conf
@@ -0,0 +1,13 @@
+router bgp 101 vrf r1-cust1
+ bgp router-id 10.254.254.1
+ neighbor r2g peer-group
+ neighbor r2g remote-as external
+ neighbor r2g bfd
+ neighbor r1-eth0 interface peer-group r2g
+ address-family ipv4 unicast
+ redistribute connected
+ exit-address-family
+ address-family ipv6 unicast
+ neighbor r2g activate
+ exit-address-family
+!
diff --git a/tests/topotests/bgp_vrf_lite_ipv6_rtadv/r1/ipv4_routes.json b/tests/topotests/bgp_vrf_lite_ipv6_rtadv/r1/ipv4_routes.json
new file mode 100644
index 000000000..e32c84b7d
--- /dev/null
+++ b/tests/topotests/bgp_vrf_lite_ipv6_rtadv/r1/ipv4_routes.json
@@ -0,0 +1,50 @@
+{
+ "10.254.254.2/32": [
+ {
+ "prefix": "10.254.254.2/32",
+ "protocol": "bgp",
+ "vrfId":3,
+ "selected": true,
+ "destSelected": true,
+ "distance": 20,
+ "metric": 0,
+ "installed": true,
+ "internalStatus": 34,
+ "internalFlags": 8,
+ "nexthops": [
+ {
+ "flags": 3,
+ "fib": true,
+ "afi": "ipv6",
+ "interfaceIndex": 2,
+ "interfaceName": "r1-eth0",
+ "active": true
+ }
+ ]
+ }
+ ],
+ "10.254.254.1/32": [
+ {
+ "prefix": "10.254.254.1/32",
+ "protocol": "connected",
+ "vrfId":3,
+ "selected": true,
+ "destSelected": true,
+ "distance": 0,
+ "metric": 0,
+ "installed": true,
+ "internalStatus": 32,
+ "internalFlags": 8,
+ "nexthops": [
+ {
+ "flags": 3,
+ "fib": true,
+ "directlyConnected": true,
+ "interfaceIndex": 4,
+ "interfaceName": "loop1",
+ "active": true
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/bgp_vrf_lite_ipv6_rtadv/r1/ipv6_routes.json b/tests/topotests/bgp_vrf_lite_ipv6_rtadv/r1/ipv6_routes.json
new file mode 100644
index 000000000..88e8c5cd8
--- /dev/null
+++ b/tests/topotests/bgp_vrf_lite_ipv6_rtadv/r1/ipv6_routes.json
@@ -0,0 +1,44 @@
+{
+ "2001:db8:1::/64": [
+ {
+ "prefix": "2001:db8:1::/64",
+ "protocol": "bgp",
+ "vrfId":3,
+ "distance": 20,
+ "metric": 0,
+ "internalStatus": 2,
+ "internalFlags": 0,
+ "nexthops": [
+ {
+ "flags": 1,
+ "afi": "ipv6",
+ "interfaceIndex": 2,
+ "interfaceName": "r1-eth0",
+ "active": true
+ }
+ ]
+ },
+ {
+ "prefix": "2001:db8:1::/64",
+ "protocol": "connected",
+ "vrfId":3,
+ "selected": true,
+ "destSelected": true,
+ "distance": 0,
+ "metric": 0,
+ "installed": true,
+ "internalStatus": 32,
+ "internalFlags": 8,
+ "nexthops": [
+ {
+ "flags": 3,
+ "fib": true,
+ "directlyConnected": true,
+ "interfaceIndex": 2,
+ "interfaceName": "r1-eth0",
+ "active": true
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/bgp_vrf_lite_ipv6_rtadv/r1/zebra.conf b/tests/topotests/bgp_vrf_lite_ipv6_rtadv/r1/zebra.conf
new file mode 100644
index 000000000..f19c49720
--- /dev/null
+++ b/tests/topotests/bgp_vrf_lite_ipv6_rtadv/r1/zebra.conf
@@ -0,0 +1,9 @@
+debug zebra packet recv
+debug zebra packet send
+log stdout
+interface loop1 vrf r1-cust1
+ ip address 10.254.254.1/32
+!
+interface r1-eth0 vrf r1-cust1
+ ipv6 address 2001:db8:1::1/64
+!
diff --git a/tests/topotests/bgp_vrf_lite_ipv6_rtadv/r2/bgpd.conf b/tests/topotests/bgp_vrf_lite_ipv6_rtadv/r2/bgpd.conf
new file mode 100644
index 000000000..39362abd4
--- /dev/null
+++ b/tests/topotests/bgp_vrf_lite_ipv6_rtadv/r2/bgpd.conf
@@ -0,0 +1,16 @@
+router bgp 102 vrf r2-cust1
+ bgp router-id 10.254.254.2
+ neighbor r2g peer-group
+ neighbor r2g remote-as external
+ neighbor r2g bfd
+ neighbor r2-eth0 interface peer-group r2g
+ !
+ address-family ipv4 unicast
+ redistribute connected
+ exit-address-family
+ !
+ address-family ipv6 unicast
+ redistribute connected
+ neighbor r2g activate
+ exit-address-family
+!
diff --git a/tests/topotests/bgp_vrf_lite_ipv6_rtadv/r2/ipv4_routes.json b/tests/topotests/bgp_vrf_lite_ipv6_rtadv/r2/ipv4_routes.json
new file mode 100644
index 000000000..9d7c0e6e4
--- /dev/null
+++ b/tests/topotests/bgp_vrf_lite_ipv6_rtadv/r2/ipv4_routes.json
@@ -0,0 +1,50 @@
+{
+ "10.254.254.2/32": [
+ {
+ "prefix": "10.254.254.2/32",
+ "protocol": "connected",
+ "vrfId":3,
+ "selected": true,
+ "destSelected": true,
+ "distance": 0,
+ "metric": 0,
+ "installed": true,
+ "internalStatus": 32,
+ "internalFlags": 8,
+ "nexthops": [
+ {
+ "flags": 3,
+ "fib": true,
+ "directlyConnected": true,
+ "interfaceIndex": 4,
+ "interfaceName": "loop1",
+ "active": true
+ }
+ ]
+ }
+ ],
+ "10.254.254.1/32": [
+ {
+ "prefix": "10.254.254.1/32",
+ "protocol": "bgp",
+ "vrfId":3,
+ "selected": true,
+ "destSelected": true,
+ "distance": 20,
+ "metric": 0,
+ "installed": true,
+ "internalStatus": 34,
+ "internalFlags": 8,
+ "nexthops": [
+ {
+ "flags": 3,
+ "fib": true,
+ "afi": "ipv6",
+ "interfaceIndex": 2,
+ "interfaceName": "r2-eth0",
+ "active": true
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/bgp_vrf_lite_ipv6_rtadv/r2/ipv6_routes.json b/tests/topotests/bgp_vrf_lite_ipv6_rtadv/r2/ipv6_routes.json
new file mode 100644
index 000000000..230fe3874
--- /dev/null
+++ b/tests/topotests/bgp_vrf_lite_ipv6_rtadv/r2/ipv6_routes.json
@@ -0,0 +1,26 @@
+{
+ "2001:db8:1::/64": [
+ {
+ "prefix": "2001:db8:1::/64",
+ "protocol": "connected",
+ "vrfId":3,
+ "selected": true,
+ "destSelected": true,
+ "distance": 0,
+ "metric": 0,
+ "installed": true,
+ "internalStatus": 32,
+ "internalFlags": 8,
+ "nexthops": [
+ {
+ "flags": 3,
+ "fib": true,
+ "directlyConnected": true,
+ "interfaceIndex": 2,
+ "interfaceName": "r2-eth0",
+ "active": true
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/bgp_vrf_lite_ipv6_rtadv/r2/zebra.conf b/tests/topotests/bgp_vrf_lite_ipv6_rtadv/r2/zebra.conf
new file mode 100644
index 000000000..c3795ab95
--- /dev/null
+++ b/tests/topotests/bgp_vrf_lite_ipv6_rtadv/r2/zebra.conf
@@ -0,0 +1,9 @@
+ip forwarding
+ipv6 forwarding
+!
+interface loop1 vrf r2-cust1
+ ip address 10.254.254.2/32
+!
+interface r2-eth0 vrf r2-cust1
+ ipv6 address 2001:db8:1::2/64
+!
diff --git a/tests/topotests/bgp_vrf_lite_ipv6_rtadv/test_bgp_vrf_lite_ipv6_rtadv.dot b/tests/topotests/bgp_vrf_lite_ipv6_rtadv/test_bgp_vrf_lite_ipv6_rtadv.dot
new file mode 100644
index 000000000..da67c29a0
--- /dev/null
+++ b/tests/topotests/bgp_vrf_lite_ipv6_rtadv/test_bgp_vrf_lite_ipv6_rtadv.dot
@@ -0,0 +1,44 @@
+## Color coding:
+#########################
+## Main FRR: #f08080 red
+## Switches: #d0e0d0 gray
+## RIP: #19e3d9 Cyan
+## RIPng: #fcb314 dark yellow
+## OSPFv2: #32b835 Green
+## OSPFv3: #19e3d9 Cyan
+## ISIS IPv4 #fcb314 dark yellow
+## ISIS IPv6 #9a81ec purple
+## BGP IPv4 #eee3d3 beige
+## BGP IPv6 #fdff00 yellow
+##### Colors (see http://www.color-hex.com/)
+
+graph template {
+ label="bfd-topo2";
+
+ # Routers
+ r1 [
+ shape=doubleoctagon,
+ label="r1",
+ fillcolor="#f08080",
+ style=filled,
+ ];
+ r2 [
+ shape=doubleoctagon
+ label="r2",
+ fillcolor="#f08080",
+ style=filled,
+ ];
+
+ # Switches
+ sw1 [
+ shape=oval,
+ label="sw1\n2001:db8:1::/64",
+ fillcolor="#d0e0d0",
+ style=filled,
+ ];
+
+ # Connections
+ r1 -- sw1 [label="eth0"];
+ r2 -- sw1 [label="eth0"];
+
+}
diff --git a/tests/topotests/bgp_vrf_lite_ipv6_rtadv/test_bgp_vrf_lite_ipv6_rtadv.py b/tests/topotests/bgp_vrf_lite_ipv6_rtadv/test_bgp_vrf_lite_ipv6_rtadv.py
new file mode 100644
index 000000000..6b4df78c6
--- /dev/null
+++ b/tests/topotests/bgp_vrf_lite_ipv6_rtadv/test_bgp_vrf_lite_ipv6_rtadv.py
@@ -0,0 +1,154 @@
+#!/usr/bin/env python
+
+#
+# test_bgp_ipv6_rtadv.py
+# Part of NetDEF Topology Tests
+#
+# Copyright (c) 2019 by 6WIND
+#
+# 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_bgp_ipv6_rtadv.py: Test the FRR/Quagga BGP daemon with BGP IPv6 interface
+ with route advertisements on a separate netns.
+"""
+
+import os
+import sys
+import json
+from functools import partial
+import pytest
+
+# 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 BGPIPV6RTADVVRFTopo(Topo):
+ "Test topology builder"
+ def build(self, *_args, **_opts):
+ "Build function"
+ tgen = get_topogen(self)
+
+ # Create 2 routers.
+ tgen.add_router('r1')
+ tgen.add_router('r2')
+
+ switch = tgen.add_switch('s1')
+ switch.add_link(tgen.gears['r1'])
+ switch.add_link(tgen.gears['r2'])
+
+def setup_module(mod):
+ "Sets up the pytest environment"
+ tgen = Topogen(BGPIPV6RTADVVRFTopo, mod.__name__)
+ tgen.start_topology()
+
+ router_list = tgen.routers()
+
+ logger.info('Testing with VRF Lite support')
+
+ cmds = ['ip link add {0}-cust1 type vrf table 1001',
+ 'ip link add loop1 type dummy',
+ 'ip link set loop1 master {0}-cust1',
+ 'ip link set {0}-eth0 master {0}-cust1']
+
+ for rname, router in router_list.iteritems():
+ for cmd in cmds:
+ output = tgen.net[rname].cmd(cmd.format(rname))
+
+ 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_BGP,
+ os.path.join(CWD, '{}/bgpd.conf'.format(rname))
+ )
+
+ # Initialize all routers.
+ tgen.start_router()
+
+def teardown_module(_mod):
+ "Teardown the pytest environment"
+ tgen = get_topogen()
+
+ tgen.stop_topology()
+
+
+def test_protocols_convergence():
+ """
+ Assert that all protocols have converged
+ statuses as they depend on it.
+ """
+ tgen = get_topogen()
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ # Check IPv4 routing tables.
+ logger.info("Checking IPv4 routes for convergence")
+
+ for router in tgen.routers().values():
+ json_file = '{}/{}/ipv4_routes.json'.format(CWD, router.name)
+ if not os.path.isfile(json_file):
+ logger.info('skipping file {}'.format(json_file))
+ continue
+
+ expected = json.loads(open(json_file).read())
+ test_func = partial(topotest.router_json_cmp,
+ router, 'show ip route vrf {}-cust1 json'.format(router.name), expected)
+ _, result = topotest.run_and_expect(test_func, None, count=160,
+ wait=0.5)
+ assertmsg = '"{}" JSON output mismatches'.format(router.name)
+ assert result is None, assertmsg
+
+ # Check IPv6 routing tables.
+ logger.info("Checking IPv6 routes for convergence")
+ for router in tgen.routers().values():
+ json_file = '{}/{}/ipv6_routes.json'.format(CWD, router.name)
+ if not os.path.isfile(json_file):
+ logger.info('skipping file {}'.format(json_file))
+ continue
+
+ expected = json.loads(open(json_file).read())
+ test_func = partial(topotest.router_json_cmp,
+ router, 'show ipv6 route vrf {}-cust1 json'.format(router.name), expected)
+ _, result = topotest.run_and_expect(test_func, None, count=160,
+ wait=0.5)
+ assertmsg = '"{}" JSON output mismatches'.format(router.name)
+ assert result is None, assertmsg
+
+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/lib/topotest.py b/tests/topotests/lib/topotest.py
index e0da20e07..2acb04fb0 100644
--- a/tests/topotests/lib/topotest.py
+++ b/tests/topotests/lib/topotest.py
@@ -429,6 +429,33 @@ def ip4_route_zebra(node, vrf_name=None):
lines = lines[1:]
return '\n'.join(lines)
+def ip6_route_zebra(node, vrf_name=None):
+ """
+ Retrieves the output of 'show ipv6 route [vrf vrf_name]', then
+ canonicalizes it by eliding link-locals.
+ """
+
+ if vrf_name == None:
+ tmp = node.vtysh_cmd('show ipv6 route')
+ else:
+ tmp = node.vtysh_cmd('show ipv6 route vrf {0}'.format(vrf_name))
+
+ # Mask out timestamp
+ output = re.sub(r" [0-2][0-9]:[0-5][0-9]:[0-5][0-9]", " XX:XX:XX", tmp)
+
+ # Mask out the link-local addresses
+ output = re.sub(r'fe80::[^ ]+,', 'fe80::XXXX:XXXX:XXXX:XXXX,', output)
+
+ lines = output.splitlines()
+ header_found = False
+ while lines and (not lines[0].strip() or not header_found):
+ if '> - selected route' in lines[0]:
+ header_found = True
+ lines = lines[1:]
+
+ return '\n'.join(lines)
+
+
def proto_name_to_number(protocol):
return {
'bgp': '186',
diff --git a/tests/topotests/ospf6-topo1/r1/ospf6d.conf-pre-v4 b/tests/topotests/ospf6-topo1/r1/ospf6d.conf-pre-v4
deleted file mode 100644
index c4b382171..000000000
--- a/tests/topotests/ospf6-topo1/r1/ospf6d.conf-pre-v4
+++ /dev/null
@@ -1,27 +0,0 @@
-hostname r1
-log file ospf6d.log
-!
-debug ospf6 message all
-debug ospf6 lsa unknown
-debug ospf6 zebra
-debug ospf6 interface
-debug ospf6 neighbor
-debug ospf6 route table
-debug ospf6 flooding
-!
-interface r1-stubnet
- ipv6 ospf6 network broadcast
-!
-interface r1-sw5
- ipv6 ospf6 network broadcast
-!
-router ospf6
- router-id 10.0.0.1
- log-adjacency-changes detail
- redistribute static
- interface r1-stubnet area 0.0.0.0
- interface r1-sw5 area 0.0.0.0
-!
-line vty
- exec-timeout 0 0
-!
diff --git a/tests/topotests/ospf6-topo1/r1/show_ipv6_route.ref b/tests/topotests/ospf6-topo1/r1/show_ipv6_route.ref
index c961512bd..2db6f620f 100644
--- a/tests/topotests/ospf6-topo1/r1/show_ipv6_route.ref
+++ b/tests/topotests/ospf6-topo1/r1/show_ipv6_route.ref
@@ -1,9 +1,9 @@
-O fc00:1:1:1::/64 [110/10] is directly connected, r1-stubnet
-O>* fc00:2:2:2::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r1-sw5
-O>* fc00:3:3:3::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r1-sw5
-O>* fc00:4:4:4::/64 [110/30] via fe80::XXXX:XXXX:XXXX:XXXX, r1-sw5
-O fc00:a:a:a::/64 [110/10] is directly connected, r1-sw5
-O>* fc00:b:b:b::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r1-sw5
-O>* fc00:2222:2222:2222::/64 [110/10] via fe80::XXXX:XXXX:XXXX:XXXX, r1-sw5
-O>* fc00:3333:3333:3333::/64 [110/10] via fe80::XXXX:XXXX:XXXX:XXXX, r1-sw5
-O>* fc00:4444:4444:4444::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r1-sw5
+O fc00:1:1:1::/64 [110/10] is directly connected, r1-stubnet, XX:XX:XX
+O>* fc00:2:2:2::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r1-sw5, XX:XX:XX
+O>* fc00:3:3:3::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r1-sw5, XX:XX:XX
+O>* fc00:4:4:4::/64 [110/30] via fe80::XXXX:XXXX:XXXX:XXXX, r1-sw5, XX:XX:XX
+O fc00:a:a:a::/64 [110/10] is directly connected, r1-sw5, XX:XX:XX
+O>* fc00:b:b:b::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r1-sw5, XX:XX:XX
+O>* fc00:2222:2222:2222::/64 [110/10] via fe80::XXXX:XXXX:XXXX:XXXX, r1-sw5, XX:XX:XX
+O>* fc00:3333:3333:3333::/64 [110/10] via fe80::XXXX:XXXX:XXXX:XXXX, r1-sw5, XX:XX:XX
+O>* fc00:4444:4444:4444::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r1-sw5, XX:XX:XX
diff --git a/tests/topotests/ospf6-topo1/r1/zebra.conf b/tests/topotests/ospf6-topo1/r1/zebra.conf
index de298f40e..dfbcea8d2 100644
--- a/tests/topotests/ospf6-topo1/r1/zebra.conf
+++ b/tests/topotests/ospf6-topo1/r1/zebra.conf
@@ -2,6 +2,9 @@
hostname r1
log file zebra.log
!
+debug zebra events
+debug zebra rib
+!
interface r1-stubnet
ipv6 address fc00:1:1:1::1/64
!
diff --git a/tests/topotests/ospf6-topo1/r2/ospf6d.conf-pre-v4 b/tests/topotests/ospf6-topo1/r2/ospf6d.conf-pre-v4
deleted file mode 100644
index bb9958d17..000000000
--- a/tests/topotests/ospf6-topo1/r2/ospf6d.conf-pre-v4
+++ /dev/null
@@ -1,27 +0,0 @@
-hostname r2
-log file ospf6d.log
-!
-debug ospf6 message all
-debug ospf6 lsa unknown
-debug ospf6 zebra
-debug ospf6 interface
-debug ospf6 neighbor
-debug ospf6 route table
-debug ospf6 flooding
-!
-interface r2-stubnet
- ipv6 ospf6 network broadcast
-!
-interface r2-sw5
- ipv6 ospf6 network broadcast
-!
-router ospf6
- router-id 10.0.0.2
- log-adjacency-changes detail
- redistribute static
- interface r2-stubnet area 0.0.0.0
- interface r2-sw5 area 0.0.0.0
-!
-line vty
- exec-timeout 0 0
-!
diff --git a/tests/topotests/ospf6-topo1/r2/show_ipv6_route.ref b/tests/topotests/ospf6-topo1/r2/show_ipv6_route.ref
index 014eddbcb..9060b0739 100644
--- a/tests/topotests/ospf6-topo1/r2/show_ipv6_route.ref
+++ b/tests/topotests/ospf6-topo1/r2/show_ipv6_route.ref
@@ -1,10 +1,10 @@
-O>* fc00:1:1:1::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r2-sw5
-O fc00:2:2:2::/64 [110/10] is directly connected, r2-stubnet
-O>* fc00:3:3:3::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r2-sw5
-O>* fc00:4:4:4::/64 [110/30] via fe80::XXXX:XXXX:XXXX:XXXX, r2-sw5
-O fc00:a:a:a::/64 [110/10] is directly connected, r2-sw5
-O>* fc00:b:b:b::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r2-sw5
-O>* fc00:1111:1111:1111::/64 [110/10] via fe80::XXXX:XXXX:XXXX:XXXX, r2-sw5
-O>* fc00:3333:3333:3333::/64 [110/10] via fe80::XXXX:XXXX:XXXX:XXXX, r2-sw5
-O>* fc00:4444:4444:4444::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r2-sw5
+O>* fc00:1:1:1::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r2-sw5, XX:XX:XX
+O fc00:2:2:2::/64 [110/10] is directly connected, r2-stubnet, XX:XX:XX
+O>* fc00:3:3:3::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r2-sw5, XX:XX:XX
+O>* fc00:4:4:4::/64 [110/30] via fe80::XXXX:XXXX:XXXX:XXXX, r2-sw5, XX:XX:XX
+O fc00:a:a:a::/64 [110/10] is directly connected, r2-sw5, XX:XX:XX
+O>* fc00:b:b:b::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r2-sw5, XX:XX:XX
+O>* fc00:1111:1111:1111::/64 [110/10] via fe80::XXXX:XXXX:XXXX:XXXX, r2-sw5, XX:XX:XX
+O>* fc00:3333:3333:3333::/64 [110/10] via fe80::XXXX:XXXX:XXXX:XXXX, r2-sw5, XX:XX:XX
+O>* fc00:4444:4444:4444::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r2-sw5, XX:XX:XX
diff --git a/tests/topotests/ospf6-topo1/r2/zebra.conf b/tests/topotests/ospf6-topo1/r2/zebra.conf
index d5345fede..f05d1a60f 100644
--- a/tests/topotests/ospf6-topo1/r2/zebra.conf
+++ b/tests/topotests/ospf6-topo1/r2/zebra.conf
@@ -2,6 +2,9 @@
hostname r2
log file zebra.log
!
+debug zebra events
+debug zebra rib
+!
interface r2-stubnet
ipv6 address fc00:2:2:2::2/64
!
diff --git a/tests/topotests/ospf6-topo1/r3/ospf6d.conf-pre-v4 b/tests/topotests/ospf6-topo1/r3/ospf6d.conf-pre-v4
deleted file mode 100644
index d2dbc4a41..000000000
--- a/tests/topotests/ospf6-topo1/r3/ospf6d.conf-pre-v4
+++ /dev/null
@@ -1,31 +0,0 @@
-hostname r3
-log file ospf6d.log
-!
-debug ospf6 message all
-debug ospf6 lsa unknown
-debug ospf6 zebra
-debug ospf6 interface
-debug ospf6 neighbor
-debug ospf6 route table
-debug ospf6 flooding
-!
-interface r3-stubnet
- ipv6 ospf6 network broadcast
-!
-interface r3-sw5
- ipv6 ospf6 network broadcast
-!
-interface r3-sw6
- ipv6 ospf6 network broadcast
-!
-router ospf6
- router-id 10.0.0.3
- log-adjacency-changes detail
- redistribute static
- interface r3-stubnet area 0.0.0.0
- interface r3-sw5 area 0.0.0.0
- interface r3-sw6 area 0.0.0.1
-!
-line vty
- exec-timeout 0 0
-!
diff --git a/tests/topotests/ospf6-topo1/r3/show_ipv6_route.ref b/tests/topotests/ospf6-topo1/r3/show_ipv6_route.ref
index 1ac7cbd6b..9406f41e9 100644
--- a/tests/topotests/ospf6-topo1/r3/show_ipv6_route.ref
+++ b/tests/topotests/ospf6-topo1/r3/show_ipv6_route.ref
@@ -1,10 +1,10 @@
-O>* fc00:1:1:1::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r3-sw5
-O>* fc00:2:2:2::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r3-sw5
-O fc00:3:3:3::/64 [110/10] is directly connected, r3-stubnet
-O>* fc00:4:4:4::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r3-sw6
-O fc00:a:a:a::/64 [110/10] is directly connected, r3-sw5
-O fc00:b:b:b::/64 [110/10] is directly connected, r3-sw6
-O>* fc00:1111:1111:1111::/64 [110/10] via fe80::XXXX:XXXX:XXXX:XXXX, r3-sw5
-O>* fc00:2222:2222:2222::/64 [110/10] via fe80::XXXX:XXXX:XXXX:XXXX, r3-sw5
-O>* fc00:4444:4444:4444::/64 [110/10] via fe80::XXXX:XXXX:XXXX:XXXX, r3-sw6
+O>* fc00:1:1:1::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r3-sw5, XX:XX:XX
+O>* fc00:2:2:2::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r3-sw5, XX:XX:XX
+O fc00:3:3:3::/64 [110/10] is directly connected, r3-stubnet, XX:XX:XX
+O>* fc00:4:4:4::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r3-sw6, XX:XX:XX
+O fc00:a:a:a::/64 [110/10] is directly connected, r3-sw5, XX:XX:XX
+O fc00:b:b:b::/64 [110/10] is directly connected, r3-sw6, XX:XX:XX
+O>* fc00:1111:1111:1111::/64 [110/10] via fe80::XXXX:XXXX:XXXX:XXXX, r3-sw5, XX:XX:XX
+O>* fc00:2222:2222:2222::/64 [110/10] via fe80::XXXX:XXXX:XXXX:XXXX, r3-sw5, XX:XX:XX
+O>* fc00:4444:4444:4444::/64 [110/10] via fe80::XXXX:XXXX:XXXX:XXXX, r3-sw6, XX:XX:XX
diff --git a/tests/topotests/ospf6-topo1/r3/zebra.conf b/tests/topotests/ospf6-topo1/r3/zebra.conf
index 11f1ff59f..d8051c350 100644
--- a/tests/topotests/ospf6-topo1/r3/zebra.conf
+++ b/tests/topotests/ospf6-topo1/r3/zebra.conf
@@ -2,6 +2,9 @@
hostname r3
log file zebra.log
!
+debug zebra events
+debug zebra rib
+!
interface r3-stubnet
ipv6 address fc00:3:3:3::3/64
!
diff --git a/tests/topotests/ospf6-topo1/r4/ospf6d.conf-pre-v4 b/tests/topotests/ospf6-topo1/r4/ospf6d.conf-pre-v4
deleted file mode 100644
index 6f9c30d75..000000000
--- a/tests/topotests/ospf6-topo1/r4/ospf6d.conf-pre-v4
+++ /dev/null
@@ -1,27 +0,0 @@
-hostname r4
-log file ospf6d.log
-!
-debug ospf6 message all
-debug ospf6 lsa unknown
-debug ospf6 zebra
-debug ospf6 interface
-debug ospf6 neighbor
-debug ospf6 route table
-debug ospf6 flooding
-!
-interface r4-stubnet
- ipv6 ospf6 network broadcast
-!
-interface r4-sw6
- ipv6 ospf6 network broadcast
-!
-router ospf6
- router-id 10.0.0.4
- log-adjacency-changes detail
- redistribute static
- interface r4-stubnet area 0.0.0.1
- interface r4-sw6 area 0.0.0.1
-!
-line vty
- exec-timeout 0 0
-!
diff --git a/tests/topotests/ospf6-topo1/r4/show_ipv6_route.ref b/tests/topotests/ospf6-topo1/r4/show_ipv6_route.ref
index 698dea6c7..9bf032b5e 100644
--- a/tests/topotests/ospf6-topo1/r4/show_ipv6_route.ref
+++ b/tests/topotests/ospf6-topo1/r4/show_ipv6_route.ref
@@ -1,9 +1,9 @@
-O>* fc00:1:1:1::/64 [110/30] via fe80::XXXX:XXXX:XXXX:XXXX, r4-sw6
-O>* fc00:2:2:2::/64 [110/30] via fe80::XXXX:XXXX:XXXX:XXXX, r4-sw6
-O>* fc00:3:3:3::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r4-sw6
-O fc00:4:4:4::/64 [110/10] is directly connected, r4-stubnet
-O>* fc00:a:a:a::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r4-sw6
-O fc00:b:b:b::/64 [110/10] is directly connected, r4-sw6
-O>* fc00:1111:1111:1111::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r4-sw6
-O>* fc00:2222:2222:2222::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r4-sw6
-O>* fc00:3333:3333:3333::/64 [110/10] via fe80::XXXX:XXXX:XXXX:XXXX, r4-sw6
+O>* fc00:1:1:1::/64 [110/30] via fe80::XXXX:XXXX:XXXX:XXXX, r4-sw6, XX:XX:XX
+O>* fc00:2:2:2::/64 [110/30] via fe80::XXXX:XXXX:XXXX:XXXX, r4-sw6, XX:XX:XX
+O>* fc00:3:3:3::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r4-sw6, XX:XX:XX
+O fc00:4:4:4::/64 [110/10] is directly connected, r4-stubnet, XX:XX:XX
+O>* fc00:a:a:a::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r4-sw6, XX:XX:XX
+O fc00:b:b:b::/64 [110/10] is directly connected, r4-sw6, XX:XX:XX
+O>* fc00:1111:1111:1111::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r4-sw6, XX:XX:XX
+O>* fc00:2222:2222:2222::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r4-sw6, XX:XX:XX
+O>* fc00:3333:3333:3333::/64 [110/10] via fe80::XXXX:XXXX:XXXX:XXXX, r4-sw6, XX:XX:XX
diff --git a/tests/topotests/ospf6-topo1/r4/zebra.conf b/tests/topotests/ospf6-topo1/r4/zebra.conf
index 4b0a8a1f9..cada58bd0 100644
--- a/tests/topotests/ospf6-topo1/r4/zebra.conf
+++ b/tests/topotests/ospf6-topo1/r4/zebra.conf
@@ -2,6 +2,9 @@
hostname r4
log file zebra.log
!
+debug zebra events
+debug zebra rib
+!
interface r4-stubnet
ipv6 address fc00:4:4:4::4/64
!
diff --git a/tests/topotests/ospf6-topo1/test_ospf6_topo1.py b/tests/topotests/ospf6-topo1/test_ospf6_topo1.py
index 5da04b644..b70ae0226 100755
--- a/tests/topotests/ospf6-topo1/test_ospf6_topo1.py
+++ b/tests/topotests/ospf6-topo1/test_ospf6_topo1.py
@@ -76,20 +76,19 @@ import sys
import pytest
from time import sleep
-from mininet.topo import Topo
-from mininet.net import Mininet
-from mininet.node import Node, OVSSwitch, Host
-from mininet.log import setLogLevel, info
-from mininet.cli import CLI
-from mininet.link import Intf
-
from functools import partial
-sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
-from lib import topotest
+from mininet.topo import Topo
+# Save the Current Working Directory to find configuration files later.
+CWD = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join(CWD, '../'))
-fatal_error = ""
+# 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
#####################################################
@@ -102,34 +101,45 @@ class NetworkTopo(Topo):
"OSPFv3 (IPv6) Test Topology 1"
def build(self, **_opts):
- #
- # Define Switches first
- #
- switch = {}
- for i in range(1, 7):
- switch[i] = self.addSwitch('SW%s' % i,
- dpid=topotest.int2dpid(i),
- cls=topotest.LegacySwitch)
- #
- # Define FRR/Quagga Routers
- #
- router = {}
- for i in range(1, 5):
- router[i] = topotest.addRouter(self, 'r%s' % i)
+ "Build function"
+
+ tgen = get_topogen(self)
+
+ # Create 4 routers
+ for routern in range(1, 5):
+ tgen.add_router('r{}'.format(routern))
#
# Wire up the switches and routers
+ # Note that we specify the link names so we match the config files
#
- # Stub nets
- for i in range(1, 5):
- self.addLink(switch[i], router[i], intfName2='r%s-stubnet' % i)
- # Switch 5
- self.addLink(switch[5], router[1], intfName2='r1-sw5')
- self.addLink(switch[5], router[2], intfName2='r2-sw5')
- self.addLink(switch[5], router[3], intfName2='r3-sw5')
- # Switch 6
- self.addLink(switch[6], router[3], intfName2='r3-sw6')
- self.addLink(switch[6], router[4], intfName2='r4-sw6')
+
+ # Create a empty network for router 1
+ switch = tgen.add_switch('s1')
+ switch.add_link(tgen.gears['r1'], nodeif='r1-stubnet')
+
+ # Create a empty network for router 2
+ switch = tgen.add_switch('s2')
+ switch.add_link(tgen.gears['r2'], nodeif='r2-stubnet')
+
+ # Create a empty network for router 3
+ switch = tgen.add_switch('s3')
+ switch.add_link(tgen.gears['r3'], nodeif='r3-stubnet')
+
+ # Create a empty network for router 4
+ switch = tgen.add_switch('s4')
+ switch.add_link(tgen.gears['r4'], nodeif='r4-stubnet')
+
+ # Interconnect routers 1, 2, and 3
+ switch = tgen.add_switch('s5')
+ switch.add_link(tgen.gears['r1'], nodeif='r1-sw5')
+ switch.add_link(tgen.gears['r2'], nodeif='r2-sw5')
+ switch.add_link(tgen.gears['r3'], nodeif='r3-sw5')
+
+ # Interconnect routers 3 and 4
+ switch = tgen.add_switch('s6')
+ switch.add_link(tgen.gears['r3'], nodeif='r3-sw6')
+ switch.add_link(tgen.gears['r4'], nodeif='r4-sw6')
#####################################################
@@ -138,192 +148,178 @@ class NetworkTopo(Topo):
##
#####################################################
-def setup_module(module):
- global topo, net
+def setup_module(mod):
+ "Sets up the pytest environment"
- print("\n\n** %s: Setup Topology" % module.__name__)
- print("******************************************\n")
+ tgen = Topogen(NetworkTopo, mod.__name__)
+ tgen.start_topology()
- print("Cleanup old Mininet runs")
- os.system('sudo mn -c > /dev/null 2>&1')
+ logger.info("** %s: Setup Topology" % mod.__name__)
+ logger.info("******************************************")
- thisDir = os.path.dirname(os.path.realpath(__file__))
- topo = NetworkTopo()
+ # For debugging after starting net, but before starting FRR,
+ # uncomment the next line
+ # tgen.mininet_cli()
- net = Mininet(controller=None, topo=topo)
- net.start()
+ router_list = tgen.routers()
+ 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_OSPF6,
+ os.path.join(CWD, '{}/ospf6d.conf'.format(rname))
+ )
- # For debugging after starting net, but before starting FRR/Quagga, uncomment the next line
- # CLI(net)
+ # Initialize all routers.
+ tgen.start_router()
- ospf_config = 'ospf6d.conf'
- if net['r1'].checkRouterVersion('<', '4.0'):
- ospf_config = 'ospf6d.conf-pre-v4'
+ # For debugging after starting FRR daemons, uncomment the next line
+ # tgen.mininet_cli()
- # Starting Routers
- for i in range(1, 5):
- net['r%s' % i].loadConf('zebra', '%s/r%s/zebra.conf' % (thisDir, i))
- net['r%s' % i].loadConf('ospf6d', '%s/r%s/%s' % (thisDir, i, ospf_config))
- net['r%s' % i].startRouter()
- # For debugging after starting FRR/Quagga daemons, uncomment the next line
- # CLI(net)
+def teardown_module(mod):
+ "Teardown the pytest environment"
+ tgen = get_topogen()
+ tgen.stop_topology()
-def teardown_module(module):
- global net
+def test_ospf6_converged():
- print("\n\n** %s: Shutdown Topology" % module.__name__)
- print("******************************************\n")
+ tgen = get_topogen()
- # End - Shutdown network
- net.stop()
+ # Don't run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+ # For debugging, uncomment the next line
+ #tgen.mininet_cli()
-def test_router_running():
- global fatal_error
- global net
+ # Wait for OSPF6 to converge (All Neighbors in either Full or TwoWay State)
+ logger.info("Waiting for OSPF6 convergence")
- # Skip if previous fatal error condition is raised
- if (fatal_error != ""):
- pytest.skip(fatal_error)
+ # Set up for regex
+ pat1 = re.compile('^[0-9]')
+ pat2 = re.compile('Full')
- print("\n\n** Check if FRR/Quagga is running on each Router node")
- print("******************************************\n")
- sleep(5)
+ timeout = 60
+ while timeout > 0:
+ logger.info("Timeout in %s: " % timeout),
+ sys.stdout.flush()
- # Make sure that all daemons are running
- for i in range(1, 5):
- fatal_error = net['r%s' % i].checkRouterRunning()
- assert fatal_error == "", fatal_error
+ # Look for any node not yet converged
+ for router, rnode in tgen.routers().iteritems():
+ resStr = rnode.vtysh_cmd('show ipv6 ospf neigh')
- # For debugging after starting FRR/Quagga daemons, uncomment the next line
- # CLI(net)
+ isConverged = False
-def test_ospf6_converged():
- global fatal_error
- global net
+ for line in resStr.splitlines():
+ res1 = pat1.match(line)
+ if res1:
+ isConverged = True
+ res2 = pat2.search(line)
- # Skip if previous fatal error condition is raised
- if (fatal_error != ""):
- pytest.skip(fatal_error)
+ if res2 == None:
+ isConverged = False
+ break
- # Wait for OSPF6 to converge (All Neighbors in either Full or TwoWay State)
- print("\n\n** Verify OSPF6 daemons to converge")
- print("******************************************\n")
- timeout = 60
- while timeout > 0:
- print("Timeout in %s: " % timeout),
- sys.stdout.flush()
- # Look for any node not yet converged
- for i in range(1, 5):
- notConverged = net['r%s' % i].cmd('vtysh -c "show ipv6 ospf neigh" 2> /dev/null | grep ^[0-9] | grep -v Full')
- if notConverged:
- print('Waiting for r%s' %i)
+ if isConverged == False:
+ logger.info('Waiting for {}'.format(router))
sys.stdout.flush()
break
- if notConverged:
+
+ if isConverged:
+ logger.info('Done')
+ break
+ else:
sleep(5)
timeout -= 5
- else:
- print('Done')
- print(notConverged)
- break
- else:
+
+ if timeout == 0:
# Bail out with error if a router fails to converge
- ospfStatus = net['r%s' % i].cmd('vtysh -c "show ipv6 ospf neigh"')
- fatal_error = "OSPFv6 did not converge"
- assert False, "OSPFv6 did not converge:\n%s" % ospfStatus
+ ospfStatus = rnode.vtysh_cmd('show ipv6 ospf neigh')
+ assert False, "OSPFv6 did not converge:\n{}".format(ospfStatus)
- print("OSPFv3 converged.")
+ logger.info("OSPFv3 converged.")
- if timeout < 60:
- # Only wait if we actually went through a convergence
- print("\nwaiting 15s for routes to populate")
- sleep(15)
+ # For debugging, uncomment the next line
+ # tgen.mininet_cli()
# Make sure that all daemons are still running
- for i in range(1, 5):
- fatal_error = net['r%s' % i].checkRouterRunning()
- assert fatal_error == "", fatal_error
+ if tgen.routers_have_failure():
+ assert tgen.errors == "", tgen.errors
-def test_ospfv3_routingTable():
- global fatal_error
- global net
+def compare_show_ipv6(rname, expected):
+ """
+ Calls 'show ipv6 route' for router `rname` and compare the obtained
+ result with the expected output.
+ """
+ tgen = get_topogen()
- # Skip if previous fatal error condition is raised
- if (fatal_error != ""):
- pytest.skip(fatal_error)
+ # Use the vtysh output, with some masking to make comparison easy
+ current = topotest.ip6_route_zebra(tgen.gears[rname])
- thisDir = os.path.dirname(os.path.realpath(__file__))
+ # Use just the 'O'spf lines of the output
+ linearr = []
+ for line in current.splitlines():
+ if re.match('^O', line):
+ linearr.append(line)
- # Verify OSPFv3 Routing Table
- print("\n\n** Verifying OSPFv3 Routing Table")
- print("******************************************\n")
- failures = 0
- for i in range(1, 5):
- refTableFile = '%s/r%s/show_ipv6_route.ref' % (thisDir, i)
- if os.path.isfile(refTableFile):
- # Read expected result from file
- expected = open(refTableFile).read().rstrip()
- # Fix newlines (make them all the same)
- expected = ('\n'.join(expected.splitlines()) + '\n').splitlines(1)
+ current = '\n'.join(linearr)
- # Actual output from router
- actual = net['r%s' % i].cmd('vtysh -c "show ipv6 route" 2> /dev/null | grep "^O"').rstrip()
- # Mask out Link-Local mac address portion. They are random...
- actual = re.sub(r" fe80::[0-9a-f:]+", " fe80::XXXX:XXXX:XXXX:XXXX", actual)
- # Drop timers on end of line (older Quagga Versions)
- actual = re.sub(r", [0-2][0-9]:[0-5][0-9]:[0-5][0-9]", "", actual)
- # Fix newlines (make them all the same)
- actual = ('\n'.join(actual.splitlines()) + '\n').splitlines(1)
+ return topotest.difflines(topotest.normalize_text(current),
+ topotest.normalize_text(expected),
+ title1="Current output",
+ title2="Expected output")
- # Generate Diff
- diff = topotest.get_textdiff(actual, expected,
- title1="actual OSPFv3 IPv6 routing table",
- title2="expected OSPFv3 IPv6 routing table")
+def test_ospfv3_routingTable():
- # Empty string if it matches, otherwise diff contains unified diff
- if diff:
- sys.stderr.write('r%s failed OSPFv3 (IPv6) Routing Table Check:\n%s\n' % (i, diff))
- failures += 1
- else:
- print("r%s ok" % i)
+ tgen = get_topogen()
+ if tgen.routers_have_failure():
+ pytest.skip('skipped because of router(s) failure')
- assert failures == 0, "OSPFv3 (IPv6) Routing Table verification failed for router r%s:\n%s" % (i, diff)
+ # For debugging, uncomment the next line
+ # tgen.mininet_cli()
- # Make sure that all daemons are still running
- for i in range(1, 5):
- fatal_error = net['r%s' % i].checkRouterRunning()
- assert fatal_error == "", fatal_error
+ # Verify OSPFv3 Routing Table
+ for router, rnode in tgen.routers().iteritems():
+ logger.info('Waiting for router "%s" convergence', router)
+
+ # Load expected results from the command
+ reffile = os.path.join(CWD, '{}/show_ipv6_route.ref'.format(router))
+ expected = open(reffile).read()
+
+ # Run test function until we get an result. Wait at most 60 seconds.
+ test_func = partial(
+ compare_show_ipv6, router, expected)
+ result, diff = topotest.run_and_expect(test_func, '',
+ count=120, wait=0.5)
+ assert result, 'OSPFv3 did not converge on {}:\n{}'.format(router, diff)
- # For debugging after starting FRR/Quagga daemons, uncomment the next line
- # CLI(net)
def test_linux_ipv6_kernel_routingTable():
- global fatal_error
- global net
- # Skip if previous fatal error condition is raised
- if (fatal_error != ""):
- pytest.skip(fatal_error)
+ tgen = get_topogen()
- thisDir = os.path.dirname(os.path.realpath(__file__))
+ if tgen.routers_have_failure():
+ pytest.skip('skipped because of router(s) failure')
# Verify Linux Kernel Routing Table
- print("\n\n** Verifying Linux IPv6 Kernel Routing Table")
- print("******************************************\n")
+ logger.info("Verifying Linux IPv6 Kernel Routing Table")
+
failures = 0
# Get a list of all current link-local addresses first as they change for
# each run and we need to translate them
linklocals = []
for i in range(1, 5):
- linklocals += net['r%s' % i].get_ipv6_linklocal()
+ linklocals += tgen.net['r{}'.format(i)].get_ipv6_linklocal()
+
+ # Now compare the routing tables (after substituting link-local addresses)
- # Now compare the routing tables (after substituting link-local addresses)
for i in range(1, 5):
- refTableFile = '%s/r%s/ip_6_address.ref' % (thisDir, i)
+ refTableFile = os.path.join(CWD, 'r{}/ip_6_address.ref'.format(i))
if os.path.isfile(refTableFile):
expected = open(refTableFile).read().rstrip()
@@ -331,7 +327,7 @@ def test_linux_ipv6_kernel_routingTable():
expected = ('\n'.join(expected.splitlines())).splitlines(1)
# Actual output from router
- actual = net['r%s' % i].cmd('ip -6 route').rstrip()
+ actual = tgen.gears['r{}'.format(i)].run('ip -6 route').rstrip()
# Mask out Link-Local mac addresses
for ll in linklocals:
actual = actual.replace(ll[1], "fe80::__(%s)__" % ll[0])
@@ -354,9 +350,9 @@ def test_linux_ipv6_kernel_routingTable():
actual = '\n'.join(filtered_lines).splitlines(1)
# Print Actual table
- # print("Router r%s table" % i)
+ # logger.info("Router r%s table" % i)
# for line in actual:
- # print(line.rstrip())
+ # logger.info(line.rstrip())
# Generate Diff
diff = topotest.get_textdiff(actual, expected,
@@ -368,64 +364,60 @@ def test_linux_ipv6_kernel_routingTable():
sys.stderr.write('r%s failed Linux IPv6 Kernel Routing Table Check:\n%s\n' % (i, diff))
failures += 1
else:
- print("r%s ok" % i)
+ logger.info("r%s ok" % i)
assert failures == 0, "Linux Kernel IPv6 Routing Table verification failed for router r%s:\n%s" % (i, diff)
- # For debugging after starting FRR/Quagga daemons, uncomment the next line
- # CLI(net)
-
def test_shutdown_check_stderr():
- global fatal_error
- global net
- # Skip if previous fatal error condition is raised
- if (fatal_error != ""):
- pytest.skip(fatal_error)
+ tgen = get_topogen()
+
+ if tgen.routers_have_failure():
+ pytest.skip('skipped because of router(s) failure')
if os.environ.get('TOPOTESTS_CHECK_STDERR') is None:
- print("SKIPPED final check on StdErr output: Disabled (TOPOTESTS_CHECK_STDERR undefined)\n")
+ logger.info("SKIPPED final check on StdErr output: Disabled (TOPOTESTS_CHECK_STDERR undefined)\n")
pytest.skip('Skipping test for Stderr output')
- thisDir = os.path.dirname(os.path.realpath(__file__))
+ net = tgen.net
- print("\n\n** Verifying unexpected STDERR output from daemons")
- print("******************************************\n")
+ logger.info("\n\n** Verifying unexpected STDERR output from daemons")
+ logger.info("******************************************")
for i in range(1, 5):
net['r%s' % i].stopRouter()
log = net['r%s' % i].getStdErr('ospf6d')
if log:
- print("\nRouter r%s OSPF6d StdErr Log:\n%s" % (i, log))
+ logger.info("\nRouter r%s OSPF6d StdErr Log:\n%s" % (i, log))
log = net['r%s' % i].getStdErr('zebra')
if log:
- print("\nRouter r%s Zebra StdErr Log:\n%s" % (i, log))
+ logger.info("\nRouter r%s Zebra StdErr Log:\n%s" % (i, log))
def test_shutdown_check_memleak():
- global fatal_error
- global net
-
- # Skip if previous fatal error condition is raised
- if (fatal_error != ""):
- pytest.skip(fatal_error)
+ "Run the memory leak test and report results."
if os.environ.get('TOPOTESTS_CHECK_MEMLEAK') is None:
- print("SKIPPED final check on Memory leaks: Disabled (TOPOTESTS_CHECK_MEMLEAK undefined)\n")
+ logger.info("SKIPPED final check on Memory leaks: Disabled (TOPOTESTS_CHECK_MEMLEAK undefined)")
pytest.skip('Skipping test for memory leaks')
-
- thisDir = os.path.dirname(os.path.realpath(__file__))
+
+ tgen = get_topogen()
+
+ net = tgen.net
for i in range(1, 5):
net['r%s' % i].stopRouter()
- net['r%s' % i].report_memory_leaks(os.environ.get('TOPOTESTS_CHECK_MEMLEAK'), os.path.basename(__file__))
+ net['r%s' % i].report_memory_leaks(
+ os.environ.get('TOPOTESTS_CHECK_MEMLEAK'),
+ os.path.basename(__file__))
if __name__ == '__main__':
- setLogLevel('info')
- # To suppress tracebacks, either use the following pytest call or add "--tb=no" to cli
+ # To suppress tracebacks, either use the following pytest call or
+ # add "--tb=no" to cli
# retval = pytest.main(["-s", "--tb=no"])
+
retval = pytest.main(["-s"])
sys.exit(retval)
diff --git a/tools/frr.in b/tools/frr.in
index d871afa42..50f7ecaa9 100755
--- a/tools/frr.in
+++ b/tools/frr.in
@@ -561,30 +561,7 @@ case "$1" in
stop_prio 0 $dmn
fi
- if [ -z "$dmn" -o "$dmn" = "zebra" ]; then
- echo "Removing all routes made by FRR."
- # Specific values for each proto can be found
- # in /etc/iproute2/rt_protos as well as FRR
- # specific ones in /etc/iproute2/rt_protos.d
- # Additionally if a new protocol is added
- # we need to add it here as well as
- # in rt_netlink.h( follow the directions! )
- ip route flush proto 4
- ip route flush proto 11
- ip route flush proto 42
- ip route flush proto 186
- ip route flush proto 187
- ip route flush proto 188
- ip route flush proto 189
- ip route flush proto 190
- ip route flush proto 191
- ip route flush proto 192
- ip route flush proto 193
- ip route flush proto 194
- ip route flush proto 195
- ip route flush proto 196
- ip route flush proto 197
- else
+ if [ [ -n "$dmn" ] && [ "$dmn" != "zebra" ] ]; then
[ -n "$dmn" ] && eval "${dmn/-/_}=0"
start_watchfrr
fi
diff --git a/vtysh/vtysh_main.c b/vtysh/vtysh_main.c
index 2e4510a45..966746018 100644
--- a/vtysh/vtysh_main.c
+++ b/vtysh/vtysh_main.c
@@ -332,6 +332,8 @@ int main(int argc, char **argv, char **env)
progname = ((p = strrchr(argv[0], '/')) ? ++p : argv[0]);
strlcpy(sysconfdir, frr_sysconfdir, sizeof(sysconfdir));
+
+ frr_init_vtydir();
strlcpy(vtydir, frr_vtydir, sizeof(vtydir));
/* Option handling. */
diff --git a/watchfrr/watchfrr.c b/watchfrr/watchfrr.c
index 34f8dabdf..1cc7722f4 100644
--- a/watchfrr/watchfrr.c
+++ b/watchfrr/watchfrr.c
@@ -648,6 +648,7 @@ static void daemon_send_ready(int exitcode)
{
FILE *fp;
static int sent = 0;
+ char started[1024];
if (sent)
return;
@@ -669,7 +670,9 @@ static void daemon_send_ready(int exitcode)
frr_detach();
- fp = fopen(DAEMON_VTY_DIR "/watchfrr.started", "w");
+ snprintf(started, sizeof(started), "%s%s", frr_vtydir,
+ "watchfrr.started");
+ fp = fopen(started, "w");
if (fp)
fclose(fp);
#if defined HAVE_SYSTEMD
diff --git a/zebra/kernel_netlink.c b/zebra/kernel_netlink.c
index fe37a3335..387a3531b 100644
--- a/zebra/kernel_netlink.c
+++ b/zebra/kernel_netlink.c
@@ -340,8 +340,7 @@ static void netlink_write_incoming(const char *buf, const unsigned int size,
char fname[MAXPATHLEN];
FILE *f;
- snprintf(fname, MAXPATHLEN, "%s/%s_%u", DAEMON_VTY_DIR, "netlink",
- counter);
+ snprintf(fname, MAXPATHLEN, "%s/%s_%u", frr_vtydir, "netlink", counter);
frr_elevate_privs(&zserv_privs) {
f = fopen(fname, "w");
}
diff --git a/zebra/redistribute.c b/zebra/redistribute.c
index dfff76664..b13f1170c 100644
--- a/zebra/redistribute.c
+++ b/zebra/redistribute.c
@@ -574,7 +574,7 @@ int zebra_add_import_table_entry(struct route_node *rn, struct route_entry *re,
struct route_entry *newre;
struct route_entry *same;
struct prefix p;
- route_map_result_t ret = RMAP_PERMITMATCH;
+ route_map_result_t ret = RMAP_MATCH;
afi_t afi;
afi = family2afi(rn->p.family);
@@ -583,7 +583,7 @@ int zebra_add_import_table_entry(struct route_node *rn, struct route_entry *re,
afi, re->type, re->instance, &rn->p, re->ng.nexthop,
re->vrf_id, re->tag, rmap_name);
- if (ret != RMAP_PERMITMATCH) {
+ if (ret != RMAP_MATCH) {
UNSET_FLAG(re->flags, ZEBRA_FLAG_SELECTED);
zebra_del_import_table_entry(rn, re);
return 0;
diff --git a/zebra/rib.h b/zebra/rib.h
index a54e164d9..292f6bc60 100644
--- a/zebra/rib.h
+++ b/zebra/rib.h
@@ -340,19 +340,6 @@ extern void route_entry_copy_nexthops(struct route_entry *re,
extern void _route_entry_dump(const char *func, union prefixconstptr pp,
union prefixconstptr src_pp,
const struct route_entry *re);
-/* RPF lookup behaviour */
-enum multicast_mode {
- MCAST_NO_CONFIG = 0, /* MIX_MRIB_FIRST, but no show in config write */
- MCAST_MRIB_ONLY, /* MRIB only */
- MCAST_URIB_ONLY, /* URIB only */
- MCAST_MIX_MRIB_FIRST, /* MRIB, if nothing at all then URIB */
- MCAST_MIX_DISTANCE, /* MRIB & URIB, lower distance wins */
- MCAST_MIX_PFXLEN, /* MRIB & URIB, longer prefix wins */
- /* on equal value, MRIB wins for last 2 */
-};
-
-extern void multicast_mode_ipv4_set(enum multicast_mode mode);
-extern enum multicast_mode multicast_mode_ipv4_get(void);
extern void rib_lookup_and_dump(struct prefix_ipv4 *p, vrf_id_t vrf_id);
extern void rib_lookup_and_pushup(struct prefix_ipv4 *p, vrf_id_t vrf_id);
diff --git a/zebra/rtadv.c b/zebra/rtadv.c
index 5088e2e8e..e181b495b 100644
--- a/zebra/rtadv.c
+++ b/zebra/rtadv.c
@@ -42,7 +42,6 @@
#include "zebra/debug.h"
#include "zebra/rib.h"
#include "zebra/zapi_msg.h"
-#include "zebra/zebra_ns.h"
#include "zebra/zebra_vrf.h"
#include "zebra/zebra_errors.h"
#include "zebra/zebra_router.h"
@@ -81,18 +80,25 @@ enum rtadv_event {
RTADV_READ
};
-static void rtadv_event(struct zebra_ns *, enum rtadv_event, int);
+static void rtadv_event(struct zebra_vrf *, enum rtadv_event, int);
static int if_join_all_router(int, struct interface *);
static int if_leave_all_router(int, struct interface *);
-static int rtadv_increment_received(struct zebra_ns *zns, ifindex_t *ifindex)
+static int rtadv_get_socket(struct zebra_vrf *zvrf)
+{
+ if (zvrf->rtadv.sock > 0)
+ return zvrf->rtadv.sock;
+ return zrouter.rtadv_sock;
+}
+
+static int rtadv_increment_received(struct zebra_vrf *zvrf, ifindex_t *ifindex)
{
int ret = -1;
struct interface *iface;
struct zebra_if *zif;
- iface = if_lookup_by_index_per_ns(zns, *ifindex);
+ iface = if_lookup_by_index(*ifindex, zvrf->vrf->vrf_id);
if (iface && iface->info) {
zif = iface->info;
zif->ra_rcvd++;
@@ -101,7 +107,7 @@ static int rtadv_increment_received(struct zebra_ns *zns, ifindex_t *ifindex)
return ret;
}
-static int rtadv_recv_packet(struct zebra_ns *zns, int sock, uint8_t *buf,
+static int rtadv_recv_packet(struct zebra_vrf *zvrf, int sock, uint8_t *buf,
int buflen, struct sockaddr_in6 *from,
ifindex_t *ifindex, int *hoplimit)
{
@@ -149,7 +155,7 @@ static int rtadv_recv_packet(struct zebra_ns *zns, int sock, uint8_t *buf,
}
}
- rtadv_increment_received(zns, ifindex);
+ rtadv_increment_received(zvrf, ifindex);
return ret;
}
@@ -461,19 +467,19 @@ no_more_opts:
static int rtadv_timer(struct thread *thread)
{
- struct zebra_ns *zns = THREAD_ARG(thread);
+ struct zebra_vrf *zvrf = THREAD_ARG(thread);
struct vrf *vrf;
struct interface *ifp;
struct zebra_if *zif;
int period;
- zrouter.rtadv.ra_timer = NULL;
- if (zrouter.rtadv.adv_msec_if_count == 0) {
+ zvrf->rtadv.ra_timer = NULL;
+ if (zvrf->rtadv.adv_msec_if_count == 0) {
period = 1000; /* 1 s */
- rtadv_event(zns, RTADV_TIMER, 1 /* 1 s */);
+ rtadv_event(zvrf, RTADV_TIMER, 1 /* 1 s */);
} else {
period = 10; /* 10 ms */
- rtadv_event(zns, RTADV_TIMER_MSEC, 10 /* 10 ms */);
+ rtadv_event(zvrf, RTADV_TIMER_MSEC, 10 /* 10 ms */);
}
RB_FOREACH (vrf, vrf_id_head, &vrfs_by_id)
@@ -500,7 +506,7 @@ static int rtadv_timer(struct thread *thread)
"Fast RA Rexmit on interface %s",
ifp->name);
- rtadv_send_packet(zrouter.rtadv.sock,
+ rtadv_send_packet(rtadv_get_socket(zvrf),
ifp);
} else {
zif->rtadv.AdvIntervalTimer -= period;
@@ -514,8 +520,8 @@ static int rtadv_timer(struct thread *thread)
zif->rtadv
.MaxRtrAdvInterval;
rtadv_send_packet(
- zrouter.rtadv.sock,
- ifp);
+ rtadv_get_socket(zvrf),
+ ifp);
}
}
}
@@ -527,10 +533,9 @@ static int rtadv_timer(struct thread *thread)
static void rtadv_process_solicit(struct interface *ifp)
{
struct zebra_vrf *zvrf = vrf_info_lookup(ifp->vrf_id);
- struct zebra_ns *zns = zvrf->zns;
- assert(zns);
- rtadv_send_packet(zrouter.rtadv.sock, ifp);
+ assert(zvrf);
+ rtadv_send_packet(rtadv_get_socket(zvrf), ifp);
}
/*
@@ -652,7 +657,7 @@ static void rtadv_process_advert(uint8_t *msg, unsigned int len,
static void rtadv_process_packet(uint8_t *buf, unsigned int len,
ifindex_t ifindex, int hoplimit,
struct sockaddr_in6 *from,
- struct zebra_ns *zns)
+ struct zebra_vrf *zvrf)
{
struct icmp6_hdr *icmph;
struct interface *ifp;
@@ -662,7 +667,7 @@ static void rtadv_process_packet(uint8_t *buf, unsigned int len,
inet_ntop(AF_INET6, &from->sin6_addr, addr_str, INET6_ADDRSTRLEN);
/* Interface search. */
- ifp = if_lookup_by_index_per_ns(zns, ifindex);
+ ifp = if_lookup_by_index(ifindex, zvrf->vrf->vrf_id);
if (ifp == NULL) {
flog_warn(EC_ZEBRA_UNKNOWN_INTERFACE,
"RA/RS received on unknown IF %u from %s", ifindex,
@@ -724,15 +729,15 @@ static int rtadv_read(struct thread *thread)
struct sockaddr_in6 from;
ifindex_t ifindex = 0;
int hoplimit = -1;
- struct zebra_ns *zns = THREAD_ARG(thread);
+ struct zebra_vrf *zvrf = THREAD_ARG(thread);
sock = THREAD_FD(thread);
- zrouter.rtadv.ra_read = NULL;
+ zvrf->rtadv.ra_read = NULL;
/* Register myself. */
- rtadv_event(zns, RTADV_READ, sock);
+ rtadv_event(zvrf, RTADV_READ, sock);
- len = rtadv_recv_packet(zns, sock, buf, sizeof(buf), &from, &ifindex,
+ len = rtadv_recv_packet(zvrf, sock, buf, sizeof(buf), &from, &ifindex,
&hoplimit);
if (len < 0) {
@@ -742,7 +747,7 @@ static int rtadv_read(struct thread *thread)
return len;
}
- rtadv_process_packet(buf, (unsigned)len, ifindex, hoplimit, &from, zns);
+ rtadv_process_packet(buf, (unsigned)len, ifindex, hoplimit, &from, zvrf);
return 0;
}
@@ -875,29 +880,27 @@ static void ipv6_nd_suppress_ra_set(struct interface *ifp,
{
struct zebra_if *zif;
struct zebra_vrf *zvrf;
- struct zebra_ns *zns;
zif = ifp->info;
zvrf = vrf_info_lookup(ifp->vrf_id);
- zns = zvrf->zns;
if (status == RA_SUPPRESS) {
/* RA is currently enabled */
if (zif->rtadv.AdvSendAdvertisements) {
zif->rtadv.AdvSendAdvertisements = 0;
zif->rtadv.AdvIntervalTimer = 0;
- zrouter.rtadv.adv_if_count--;
+ zvrf->rtadv.adv_if_count--;
- if_leave_all_router(zrouter.rtadv.sock, ifp);
+ if_leave_all_router(rtadv_get_socket(zvrf), ifp);
- if (zrouter.rtadv.adv_if_count == 0)
- rtadv_event(zns, RTADV_STOP, 0);
+ if (zvrf->rtadv.adv_if_count == 0)
+ rtadv_event(zvrf, RTADV_STOP, 0);
}
} else {
if (!zif->rtadv.AdvSendAdvertisements) {
zif->rtadv.AdvSendAdvertisements = 1;
zif->rtadv.AdvIntervalTimer = 0;
- zrouter.rtadv.adv_if_count++;
+ zvrf->rtadv.adv_if_count++;
if (zif->rtadv.MaxRtrAdvInterval >= 1000) {
/* Enable Fast RA only when RA interval is in
@@ -907,11 +910,11 @@ static void ipv6_nd_suppress_ra_set(struct interface *ifp,
RTADV_NUM_FAST_REXMITS;
}
- if_join_all_router(zrouter.rtadv.sock, ifp);
+ if_join_all_router(rtadv_get_socket(zvrf), ifp);
- if (zrouter.rtadv.adv_if_count == 1)
- rtadv_event(zns, RTADV_START,
- zrouter.rtadv.sock);
+ if (zvrf->rtadv.adv_if_count == 1)
+ rtadv_event(zvrf, RTADV_START,
+ rtadv_get_socket(zvrf));
}
}
}
@@ -944,7 +947,7 @@ static void zebra_interface_radv_set(ZAPI_HANDLER_ARGS, int enable)
zebra_route_string(client->proto), ra_interval);
/* Locate interface and check VRF match. */
- ifp = if_lookup_by_index_per_ns(zebra_ns_lookup(NS_DEFAULT), ifindex);
+ ifp = if_lookup_by_index(ifindex, zvrf->vrf->vrf_id);
if (!ifp) {
flog_warn(EC_ZEBRA_UNKNOWN_INTERFACE,
"%u: IF %u RA %s client %s - interface unknown",
@@ -1051,6 +1054,9 @@ DEFUN (ipv6_nd_ra_interval_msec,
VTY_DECLVAR_CONTEXT(interface, ifp);
unsigned interval;
struct zebra_if *zif = ifp->info;
+ struct zebra_vrf *zvrf;
+
+ zvrf = vrf_info_lookup(ifp->vrf_id);
interval = strtoul(argv[idx_number]->arg, NULL, 10);
if ((zif->rtadv.AdvDefaultLifetime != -1
@@ -1061,10 +1067,10 @@ DEFUN (ipv6_nd_ra_interval_msec,
}
if (zif->rtadv.MaxRtrAdvInterval % 1000)
- zrouter.rtadv.adv_msec_if_count--;
+ zvrf->rtadv.adv_msec_if_count--;
if (interval % 1000)
- zrouter.rtadv.adv_msec_if_count++;
+ zvrf->rtadv.adv_msec_if_count++;
SET_FLAG(zif->rtadv.ra_configured, VTY_RA_INTERVAL_CONFIGURED);
zif->rtadv.MaxRtrAdvInterval = interval;
@@ -1086,6 +1092,9 @@ DEFUN (ipv6_nd_ra_interval,
VTY_DECLVAR_CONTEXT(interface, ifp);
unsigned interval;
struct zebra_if *zif = ifp->info;
+ struct zebra_vrf *zvrf;
+
+ zvrf = vrf_info_lookup(ifp->vrf_id);
interval = strtoul(argv[idx_number]->arg, NULL, 10);
if ((zif->rtadv.AdvDefaultLifetime != -1
@@ -1096,7 +1105,7 @@ DEFUN (ipv6_nd_ra_interval,
}
if (zif->rtadv.MaxRtrAdvInterval % 1000)
- zrouter.rtadv.adv_msec_if_count--;
+ zvrf->rtadv.adv_msec_if_count--;
/* convert to milliseconds */
interval = interval * 1000;
@@ -1122,9 +1131,12 @@ DEFUN (no_ipv6_nd_ra_interval,
{
VTY_DECLVAR_CONTEXT(interface, ifp);
struct zebra_if *zif = ifp->info;
+ struct zebra_vrf *zvrf = NULL;
+
+ zvrf = vrf_info_lookup(ifp->vrf_id);
if (zif->rtadv.MaxRtrAdvInterval % 1000)
- zrouter.rtadv.adv_msec_if_count--;
+ zvrf->rtadv.adv_msec_if_count--;
UNSET_FLAG(zif->rtadv.ra_configured, VTY_RA_INTERVAL_CONFIGURED);
@@ -2094,15 +2106,15 @@ static int rtadv_config_write(struct vty *vty, struct interface *ifp)
}
-static void rtadv_event(struct zebra_ns *zns, enum rtadv_event event, int val)
+static void rtadv_event(struct zebra_vrf *zvrf, enum rtadv_event event, int val)
{
- struct rtadv *rtadv = &zrouter.rtadv;
+ struct rtadv *rtadv = &zvrf->rtadv;
switch (event) {
case RTADV_START:
- thread_add_read(zrouter.master, rtadv_read, zns, val,
+ thread_add_read(zrouter.master, rtadv_read, zvrf, val,
&rtadv->ra_read);
- thread_add_event(zrouter.master, rtadv_timer, zns, 0,
+ thread_add_event(zrouter.master, rtadv_timer, zvrf, 0,
&rtadv->ra_timer);
break;
case RTADV_STOP:
@@ -2116,15 +2128,15 @@ static void rtadv_event(struct zebra_ns *zns, enum rtadv_event event, int val)
}
break;
case RTADV_TIMER:
- thread_add_timer(zrouter.master, rtadv_timer, zns, val,
+ thread_add_timer(zrouter.master, rtadv_timer, zvrf, val,
&rtadv->ra_timer);
break;
case RTADV_TIMER_MSEC:
- thread_add_timer_msec(zrouter.master, rtadv_timer, zns, val,
+ thread_add_timer_msec(zrouter.master, rtadv_timer, zvrf, val,
&rtadv->ra_timer);
break;
case RTADV_READ:
- thread_add_read(zrouter.master, rtadv_read, zns, val,
+ thread_add_read(zrouter.master, rtadv_read, zvrf, val,
&rtadv->ra_read);
break;
default:
@@ -2133,21 +2145,30 @@ static void rtadv_event(struct zebra_ns *zns, enum rtadv_event event, int val)
return;
}
-void rtadv_init(struct zebra_ns *zns)
+void rtadv_init(struct zebra_vrf *zvrf)
{
- zrouter.rtadv.sock = rtadv_make_socket(zns->ns_id);
+ if (vrf_is_backend_netns()) {
+ zvrf->rtadv.sock = rtadv_make_socket(zvrf->zns->ns_id);
+ zrouter.rtadv_sock = -1;
+ } else if (!zrouter.rtadv_sock) {
+ zvrf->rtadv.sock = -1;
+ if (!zrouter.rtadv_sock)
+ zrouter.rtadv_sock = rtadv_make_socket(zvrf->zns->ns_id);
+ }
}
-void rtadv_terminate(struct zebra_ns *zns)
+void rtadv_terminate(struct zebra_vrf *zvrf)
{
- rtadv_event(zns, RTADV_STOP, 0);
- if (zrouter.rtadv.sock >= 0) {
- close(zrouter.rtadv.sock);
- zrouter.rtadv.sock = -1;
+ rtadv_event(zvrf, RTADV_STOP, 0);
+ if (zvrf->rtadv.sock >= 0) {
+ close(zvrf->rtadv.sock);
+ zvrf->rtadv.sock = -1;
+ } else if (zrouter.rtadv_sock >= 0) {
+ close(zrouter.rtadv_sock);
+ zrouter.rtadv_sock = -1;
}
-
- zrouter.rtadv.adv_if_count = 0;
- zrouter.rtadv.adv_msec_if_count = 0;
+ zvrf->rtadv.adv_if_count = 0;
+ zvrf->rtadv.adv_msec_if_count = 0;
}
void rtadv_cmd_init(void)
@@ -2243,11 +2264,11 @@ static int if_leave_all_router(int sock, struct interface *ifp)
}
#else
-void rtadv_init(struct zebra_ns *zns)
+void rtadv_init(struct zebra_vrf *zvrf)
{
/* Empty.*/;
}
-void rtadv_terminate(struct zebra_ns *zns)
+void rtadv_terminate(struct zebra_vrf *zvrf)
{
/* Empty.*/;
}
diff --git a/zebra/rtadv.h b/zebra/rtadv.h
index 53c497fc0..d692ef241 100644
--- a/zebra/rtadv.h
+++ b/zebra/rtadv.h
@@ -135,8 +135,8 @@ typedef enum {
RA_SUPPRESS,
} ipv6_nd_suppress_ra_status;
-extern void rtadv_init(struct zebra_ns *);
-extern void rtadv_terminate(struct zebra_ns *);
+extern void rtadv_init(struct zebra_vrf *zvrf);
+extern void rtadv_terminate(struct zebra_vrf *zvrf);
extern void rtadv_cmd_init(void);
extern void zebra_interface_radv_disable(ZAPI_HANDLER_ARGS);
extern void zebra_interface_radv_enable(ZAPI_HANDLER_ARGS);
diff --git a/zebra/zapi_msg.c b/zebra/zapi_msg.c
index 49e43f494..61200806b 100644
--- a/zebra/zapi_msg.c
+++ b/zebra/zapi_msg.c
@@ -2526,7 +2526,7 @@ static void zserv_write_incoming(struct stream *orig, uint16_t command)
copy = stream_dup(orig);
stream_set_getp(copy, 0);
- snprintf(fname, MAXPATHLEN, "%s/%u", DAEMON_VTY_DIR, command);
+ snprintf(fname, MAXPATHLEN, "%s/%u", frr_vtydir, command);
frr_elevate_privs(&zserv_privs) {
fd = open(fname, O_CREAT | O_WRONLY | O_EXCL, 0644);
diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c
index caab06d2f..f2a76d1c5 100644
--- a/zebra/zebra_nhg.c
+++ b/zebra/zebra_nhg.c
@@ -338,7 +338,7 @@ static unsigned nexthop_active_check(struct route_node *rn,
struct nexthop *nexthop)
{
struct interface *ifp;
- route_map_result_t ret = RMAP_PERMITMATCH;
+ route_map_result_t ret = RMAP_MATCH;
int family;
char buf[SRCDEST2STR_BUFFER];
const struct prefix *p, *src_p;
diff --git a/zebra/zebra_ns.c b/zebra/zebra_ns.c
index 0c743d867..db4f9d001 100644
--- a/zebra/zebra_ns.c
+++ b/zebra/zebra_ns.c
@@ -27,7 +27,6 @@
#include "lib/prefix.h"
#include "lib/memory.h"
-#include "rtadv.h"
#include "zebra_ns.h"
#include "zebra_vrf.h"
#include "zebra_memory.h"
@@ -122,10 +121,6 @@ int zebra_ns_enable(ns_id_t ns_id, void **info)
zns->ns_id = ns_id;
-#if defined(HAVE_RTADV)
- rtadv_init(zns);
-#endif
-
kernel_init(zns);
interface_list(zns);
route_read(zns);
@@ -142,9 +137,6 @@ int zebra_ns_enable(ns_id_t ns_id, void **info)
static int zebra_ns_disable_internal(struct zebra_ns *zns, bool complete)
{
route_table_finish(zns->if_table);
-#if defined(HAVE_RTADV)
- rtadv_terminate(zns);
-#endif
kernel_terminate(zns, complete);
diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c
index 83eb5f422..cc614abac 100644
--- a/zebra/zebra_rib.c
+++ b/zebra/zebra_rib.c
@@ -108,10 +108,6 @@ static const struct {
/* no entry/default: 150 */
};
-/* RPF lookup behaviour */
-static enum multicast_mode ipv4_multicast_mode = MCAST_NO_CONFIG;
-
-
static void __attribute__((format(printf, 5, 6)))
_rnode_zlog(const char *_func, vrf_id_t vrf_id, struct route_node *rn,
int priority, const char *msgfmt, ...)
@@ -404,7 +400,7 @@ struct route_entry *rib_match_ipv4_multicast(vrf_id_t vrf_id,
struct route_node *m_rn = NULL, *u_rn = NULL;
union g_addr gaddr = {.ipv4 = addr};
- switch (ipv4_multicast_mode) {
+ switch (zrouter.ipv4_multicast_mode) {
case MCAST_MRIB_ONLY:
return rib_match(AFI_IP, SAFI_MULTICAST, vrf_id, &gaddr,
rn_out);
@@ -456,19 +452,6 @@ struct route_entry *rib_match_ipv4_multicast(vrf_id_t vrf_id,
return re;
}
-void multicast_mode_ipv4_set(enum multicast_mode mode)
-{
- if (IS_ZEBRA_DEBUG_RIB)
- zlog_debug("%s: multicast lookup mode set (%d)", __func__,
- mode);
- ipv4_multicast_mode = mode;
-}
-
-enum multicast_mode multicast_mode_ipv4_get(void)
-{
- return ipv4_multicast_mode;
-}
-
struct route_entry *rib_lookup_ipv4(struct prefix_ipv4 *p, vrf_id_t vrf_id)
{
struct route_table *table;
diff --git a/zebra/zebra_rnh.c b/zebra/zebra_rnh.c
index a8389f2ad..a63d01571 100644
--- a/zebra/zebra_rnh.c
+++ b/zebra/zebra_rnh.c
@@ -400,7 +400,7 @@ static int zebra_rnh_apply_nht_rmap(afi_t afi, struct zebra_vrf *zvrf,
{
int at_least_one = 0;
struct nexthop *nexthop;
- route_map_result_t ret;
+ int ret;
if (prn && re) {
for (nexthop = re->ng.nexthop; nexthop;
diff --git a/zebra/zebra_routemap.c b/zebra/zebra_routemap.c
index 78804635f..dbfe695a0 100644
--- a/zebra/zebra_routemap.c
+++ b/zebra/zebra_routemap.c
@@ -136,9 +136,9 @@ static int zebra_route_match_delete(struct vty *vty, const char *command,
/* 'match tag TAG'
* Match function return 1 if match is success else return 0
*/
-static enum route_map_match_result_t
-route_match_tag(void *rule, const struct prefix *prefix,
- route_map_object_t type, void *object)
+static route_map_result_t route_match_tag(void *rule,
+ const struct prefix *prefix,
+ route_map_object_t type, void *object)
{
route_tag_t *tag;
struct nh_rmap_obj *nh_data;
@@ -162,9 +162,10 @@ static struct route_map_rule_cmd route_match_tag_cmd = {
/* `match interface IFNAME' */
/* Match function return 1 if match is success else return zero. */
-static enum route_map_match_result_t
-route_match_interface(void *rule, const struct prefix *prefix,
- route_map_object_t type, void *object)
+static route_map_result_t route_match_interface(void *rule,
+ const struct prefix *prefix,
+ route_map_object_t type,
+ void *object)
{
struct nh_rmap_obj *nh_data;
char *ifname = rule;
@@ -1024,9 +1025,10 @@ DEFPY (show_ipv6_protocol_nht,
/* `match ip next-hop IP_ACCESS_LIST' */
/* Match function return 1 if match is success else return zero. */
-static enum route_map_match_result_t
-route_match_ip_next_hop(void *rule, const struct prefix *prefix,
- route_map_object_t type, void *object)
+static route_map_result_t route_match_ip_next_hop(void *rule,
+ const struct prefix *prefix,
+ route_map_object_t type,
+ void *object)
{
struct access_list *alist;
struct nh_rmap_obj *nh_data;
@@ -1081,7 +1083,7 @@ static struct route_map_rule_cmd route_match_ip_next_hop_cmd = {
/* `match ip next-hop prefix-list PREFIX_LIST' */
-static enum route_map_match_result_t
+static route_map_result_t
route_match_ip_next_hop_prefix_list(void *rule, const struct prefix *prefix,
route_map_object_t type, void *object)
{
@@ -1137,9 +1139,10 @@ static struct route_map_rule_cmd route_match_ip_next_hop_prefix_list_cmd = {
/* Match function should return 1 if match is success else return
zero. */
-static enum route_map_match_result_t
-route_match_address(afi_t afi, void *rule, const struct prefix *prefix,
- route_map_object_t type, void *object)
+static route_map_result_t route_match_address(afi_t afi, void *rule,
+ const struct prefix *prefix,
+ route_map_object_t type,
+ void *object)
{
struct access_list *alist;
@@ -1155,16 +1158,19 @@ route_match_address(afi_t afi, void *rule, const struct prefix *prefix,
return RMAP_NOMATCH;
}
-static enum route_map_match_result_t
-route_match_ip_address(void *rule, const struct prefix *prefix,
- route_map_object_t type, void *object)
+static route_map_result_t route_match_ip_address(void *rule,
+ const struct prefix *prefix,
+ route_map_object_t type,
+ void *object)
{
return route_match_address(AFI_IP, rule, prefix, type, object);
}
-static enum route_map_match_result_t
-route_match_ipv6_address(void *rule, const struct prefix *prefix,
- route_map_object_t type, void *object)
+static route_map_result_t route_match_ipv6_address(void *rule,
+ const struct prefix *prefix,
+ route_map_object_t type,
+ void *object)
+
{
return route_match_address(AFI_IP6, rule, prefix, type, object);
}
@@ -1194,7 +1200,7 @@ static struct route_map_rule_cmd route_match_ipv6_address_cmd = {
/* `match ip address prefix-list PREFIX_LIST' */
-static enum route_map_match_result_t
+static route_map_result_t
route_match_address_prefix_list(void *rule, const struct prefix *prefix,
route_map_object_t type, void *object, afi_t afi)
{
@@ -1212,7 +1218,7 @@ route_match_address_prefix_list(void *rule, const struct prefix *prefix,
return RMAP_NOMATCH;
}
-static enum route_map_match_result_t
+static route_map_result_t
route_match_ip_address_prefix_list(void *rule, const struct prefix *prefix,
route_map_object_t type, void *object)
{
@@ -1235,7 +1241,7 @@ static struct route_map_rule_cmd route_match_ip_address_prefix_list_cmd = {
route_match_address_prefix_list_compile,
route_match_address_prefix_list_free};
-static enum route_map_match_result_t
+static route_map_result_t
route_match_ipv6_address_prefix_list(void *rule, const struct prefix *prefix,
route_map_object_t type, void *object)
{
@@ -1250,7 +1256,7 @@ static struct route_map_rule_cmd route_match_ipv6_address_prefix_list_cmd = {
/* `match ip address prefix-len PREFIXLEN' */
-static enum route_map_match_result_t
+static route_map_result_t
route_match_address_prefix_len(void *rule, const struct prefix *prefix,
route_map_object_t type, void *object)
{
@@ -1301,7 +1307,7 @@ static struct route_map_rule_cmd route_match_ipv6_address_prefix_len_cmd = {
/* `match ip nexthop prefix-len PREFIXLEN' */
-static enum route_map_match_result_t
+static route_map_result_t
route_match_ip_nexthop_prefix_len(void *rule, const struct prefix *prefix,
route_map_object_t type, void *object)
{
@@ -1341,9 +1347,10 @@ static struct route_map_rule_cmd route_match_ip_nexthop_prefix_len_cmd = {
/* `match source-protocol PROTOCOL' */
-static enum route_map_match_result_t
-route_match_source_protocol(void *rule, const struct prefix *p,
- route_map_object_t type, void *object)
+static route_map_result_t route_match_source_protocol(void *rule,
+ const struct prefix *p,
+ route_map_object_t type,
+ void *object)
{
uint32_t *rib_type = (uint32_t *)rule;
struct nh_rmap_obj *nh_data;
@@ -1382,9 +1389,10 @@ static struct route_map_rule_cmd route_match_source_protocol_cmd = {
route_match_source_protocol_compile, route_match_source_protocol_free};
/* `source-instance` */
-static enum route_map_match_result_t
-route_match_source_instance(void *rule, const struct prefix *p,
- route_map_object_t type, void *object)
+static route_map_result_t route_match_source_instance(void *rule,
+ const struct prefix *p,
+ route_map_object_t type,
+ void *object)
{
uint8_t *instance = (uint8_t *)rule;
struct nh_rmap_obj *nh_data;
@@ -1424,9 +1432,8 @@ static struct route_map_rule_cmd route_match_source_instance_cmd = {
/* `set src A.B.C.D' */
/* Set src. */
-static enum route_map_match_result_t
-route_set_src(void *rule, const struct prefix *prefix, route_map_object_t type,
- void *object)
+static route_map_result_t route_set_src(void *rule, const struct prefix *prefix,
+ route_map_object_t type, void *object)
{
struct nh_rmap_obj *nh_data;
@@ -1692,7 +1699,7 @@ zebra_route_map_check(int family, int rib_type, uint8_t instance,
struct zebra_vrf *zvrf, route_tag_t tag)
{
struct route_map *rmap = NULL;
- route_map_result_t ret = RMAP_PERMITMATCH;
+ route_map_result_t ret = RMAP_MATCH;
struct nh_rmap_obj nh_obj;
nh_obj.nexthop = nexthop;
@@ -1738,7 +1745,7 @@ zebra_import_table_route_map_check(int family, int re_type, uint8_t instance,
const char *rmap_name)
{
struct route_map *rmap = NULL;
- enum route_map_match_result_t ret = RMAP_DENYMATCH;
+ route_map_result_t ret = RMAP_DENYMATCH;
struct nh_rmap_obj nh_obj;
nh_obj.nexthop = nexthop;
@@ -1764,7 +1771,7 @@ route_map_result_t zebra_nht_route_map_check(afi_t afi, int client_proto,
struct nexthop *nexthop)
{
struct route_map *rmap = NULL;
- route_map_result_t ret = RMAP_PERMITMATCH;
+ route_map_result_t ret = RMAP_MATCH;
struct nh_rmap_obj nh_obj;
nh_obj.nexthop = nexthop;
diff --git a/zebra/zebra_router.c b/zebra/zebra_router.c
index 610d51d3e..4352d688a 100644
--- a/zebra/zebra_router.c
+++ b/zebra/zebra_router.c
@@ -29,9 +29,12 @@
#include "zebra_pbr.h"
#include "zebra_vxlan.h"
#include "zebra_mlag.h"
+#include "zebra_nhg.h"
+#include "debug.h"
struct zebra_router zrouter = {
.multipath_num = MULTIPATH_NUM,
+ .ipv4_multicast_mode = MCAST_NO_CONFIG,
};
static inline int
@@ -187,6 +190,19 @@ uint32_t zebra_router_get_next_sequence(void)
memory_order_relaxed);
}
+void multicast_mode_ipv4_set(enum multicast_mode mode)
+{
+ if (IS_ZEBRA_DEBUG_RIB)
+ zlog_debug("%s: multicast lookup mode set (%d)", __func__,
+ mode);
+ zrouter.ipv4_multicast_mode = mode;
+}
+
+enum multicast_mode multicast_mode_ipv4_get(void)
+{
+ return zrouter.ipv4_multicast_mode;
+}
+
void zebra_router_terminate(void)
{
struct zebra_router_table *zrt, *tmp;
diff --git a/zebra/zebra_router.h b/zebra/zebra_router.h
index 6c9f3a0f2..e50f8a118 100644
--- a/zebra/zebra_router.h
+++ b/zebra/zebra_router.h
@@ -50,6 +50,17 @@ RB_HEAD(zebra_router_table_head, zebra_router_table);
RB_PROTOTYPE(zebra_router_table_head, zebra_router_table,
zebra_router_table_entry, zebra_router_table_entry_compare)
+/* RPF lookup behaviour */
+enum multicast_mode {
+ MCAST_NO_CONFIG = 0, /* MIX_MRIB_FIRST, but no show in config write */
+ MCAST_MRIB_ONLY, /* MRIB only */
+ MCAST_URIB_ONLY, /* URIB only */
+ MCAST_MIX_MRIB_FIRST, /* MRIB, if nothing at all then URIB */
+ MCAST_MIX_DISTANCE, /* MRIB & URIB, lower distance wins */
+ MCAST_MIX_PFXLEN, /* MRIB & URIB, longer prefix wins */
+ /* on equal value, MRIB wins for last 2 */
+};
+
struct zebra_mlag_info {
/* Role this zebra router is playing */
enum mlag_role role;
@@ -82,9 +93,8 @@ struct zebra_router {
struct hash *iptable_hash;
-#if defined(HAVE_RTADV)
- struct rtadv rtadv;
-#endif /* HAVE_RTADV */
+ /* used if vrf backend is not network namespace */
+ int rtadv_sock;
/* A sequence number used for tracking routes */
_Atomic uint32_t sequence_num;
@@ -113,6 +123,9 @@ struct zebra_router {
uint32_t multipath_num;
+ /* RPF Lookup behavior */
+ enum multicast_mode ipv4_multicast_mode;
+
/*
* Time for when we sweep the rib from old routes
*/
@@ -153,6 +166,10 @@ static inline struct zebra_vrf *zebra_vrf_get_evpn(void)
: zebra_vrf_lookup_by_id(VRF_DEFAULT);
}
+extern void multicast_mode_ipv4_set(enum multicast_mode mode);
+
+extern enum multicast_mode multicast_mode_ipv4_get(void);
+
#ifdef __cplusplus
}
#endif
diff --git a/zebra/zebra_vrf.c b/zebra/zebra_vrf.c
index 634305494..fdf0cbc69 100644
--- a/zebra/zebra_vrf.c
+++ b/zebra/zebra_vrf.c
@@ -29,6 +29,7 @@
#include "vty.h"
#include "zebra/zebra_router.h"
+#include "zebra/rtadv.h"
#include "zebra/debug.h"
#include "zebra/zapi_msg.h"
#include "zebra/rib.h"
@@ -119,6 +120,10 @@ static int zebra_vrf_enable(struct vrf *vrf)
zvrf->zns = zebra_ns_lookup((ns_id_t)vrf->vrf_id);
else
zvrf->zns = zebra_ns_lookup(NS_DEFAULT);
+#if defined(HAVE_RTADV)
+ rtadv_init(zvrf);
+#endif
+
/* Inform clients that the VRF is now active. This is an
* add for the clients.
*/
@@ -161,6 +166,10 @@ static int zebra_vrf_disable(struct vrf *vrf)
/* Stop any VxLAN-EVPN processing. */
zebra_vxlan_vrf_disable(zvrf);
+#if defined(HAVE_RTADV)
+ rtadv_terminate(zvrf);
+#endif
+
/* Inform clients that the VRF is now inactive. This is a
* delete for the clients.
*/
diff --git a/zebra/zebra_vrf.h b/zebra/zebra_vrf.h
index febaf3c84..972fe381c 100644
--- a/zebra/zebra_vrf.h
+++ b/zebra/zebra_vrf.h
@@ -169,6 +169,10 @@ struct zebra_vrf {
uint64_t lsp_removals_queued;
uint64_t lsp_installs;
uint64_t lsp_removals;
+
+#if defined(HAVE_RTADV)
+ struct rtadv rtadv;
+#endif /* HAVE_RTADV */
};
#define PROTO_RM_NAME(zvrf, afi, rtype) zvrf->proto_rm[afi][rtype].name
#define NHT_RM_NAME(zvrf, afi, rtype) zvrf->nht_rm[afi][rtype].name
diff --git a/zebra/zebra_vxlan.c b/zebra/zebra_vxlan.c
index f2f8a2a05..077c1ff8f 100644
--- a/zebra/zebra_vxlan.c
+++ b/zebra/zebra_vxlan.c
@@ -839,9 +839,9 @@ static void zvni_print_neigh_hash(struct hash_bucket *bucket, void *ctxt)
return;
if (json_vni == NULL) {
- vty_out(vty, "%*s %-6s %-8s %-17s\n",
+ vty_out(vty, "%*s %-6s %-8s %-17s %u/%u\n",
-wctx->addr_width, buf2, "local",
- state_str, buf1);
+ state_str, buf1, n->loc_seq, n->rem_seq);
} else {
json_object_string_add(json_row, "type", "local");
json_object_string_add(json_row, "state", state_str);
@@ -875,9 +875,9 @@ static void zvni_print_neigh_hash(struct hash_bucket *bucket, void *ctxt)
"%*s %-6s %-8s %-17s %-21s\n",
-wctx->addr_width, "Neighbor", "Type",
"State", "MAC", "Remote VTEP");
- vty_out(vty, "%*s %-6s %-8s %-17s %-21s\n",
+ vty_out(vty, "%*s %-6s %-8s %-17s %-21s %u/%u\n",
-wctx->addr_width, buf2, "remote", state_str,
- buf1, inet_ntoa(n->r_vtep_ip));
+ buf1, inet_ntoa(n->r_vtep_ip), n->loc_seq, n->rem_seq);
} else {
json_object_string_add(json_row, "type", "remote");
json_object_string_add(json_row, "state", state_str);
@@ -987,9 +987,9 @@ static void zvni_print_neigh_hash_all_vni(struct hash_bucket *bucket,
hash_iterate(zvni->neigh_table, zvni_find_neigh_addr_width, &wctx);
if (json == NULL) {
- vty_out(vty, "%*s %-6s %-8s %-17s %-21s\n",
+ vty_out(vty, "%*s %-6s %-8s %-17s %-21s %s\n",
-wctx.addr_width, "IP", "Type",
- "State", "MAC", "Remote VTEP");
+ "State", "MAC", "Remote VTEP", "Seq #'s");
}
if (print_dup)
hash_iterate(zvni->neigh_table, zvni_print_dad_neigh_hash,