summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.clang-format1
-rw-r--r--Makefile.am1
-rw-r--r--babeld/babel_errors.c61
-rw-r--r--babeld/babel_errors.h35
-rw-r--r--babeld/babel_interface.c32
-rw-r--r--babeld/babel_main.c43
-rw-r--r--babeld/babeld.c19
-rw-r--r--babeld/kernel.c13
-rw-r--r--babeld/kernel.h16
-rw-r--r--babeld/message.c84
-rw-r--r--babeld/neighbour.c4
-rw-r--r--babeld/route.c37
-rw-r--r--babeld/route.h13
-rw-r--r--babeld/source.c3
-rw-r--r--babeld/subdir.am2
-rw-r--r--bfdd/.gitignore3
-rw-r--r--bfdd/bfd.c1294
-rw-r--r--bfdd/bfd.h631
-rw-r--r--bfdd/bfd_packet.c1555
-rw-r--r--bfdd/bfdctl.h160
-rw-r--r--bfdd/bfdd.c236
-rw-r--r--bfdd/bfdd.conf.sample5
-rw-r--r--bfdd/bfdd_vty.c870
-rw-r--r--bfdd/bsd.c290
-rw-r--r--bfdd/config.c606
-rw-r--r--bfdd/control.c895
-rw-r--r--bfdd/event.c155
-rw-r--r--bfdd/linux.c221
-rw-r--r--bfdd/log.c125
-rw-r--r--bfdd/ptm_adapter.c712
-rw-r--r--bfdd/subdir.am33
-rw-r--r--bgpd/Makefile.am4
-rw-r--r--bgpd/bgp_aspath.c15
-rw-r--r--bgpd/bgp_attr.c128
-rw-r--r--bgpd/bgp_bfd.c20
-rw-r--r--bgpd/bgp_debug.c2
-rw-r--r--bgpd/bgp_errors.c306
-rw-r--r--bgpd/bgp_errors.h79
-rw-r--r--bgpd/bgp_evpn.c184
-rw-r--r--bgpd/bgp_evpn_vty.c4
-rw-r--r--bgpd/bgp_flowspec.c23
-rw-r--r--bgpd/bgp_flowspec_util.c25
-rw-r--r--bgpd/bgp_fsm.c54
-rw-r--r--bgpd/bgp_io.c6
-rw-r--r--bgpd/bgp_label.c24
-rw-r--r--bgpd/bgp_labelpool.c18
-rw-r--r--bgpd/bgp_main.c6
-rw-r--r--bgpd/bgp_mplsvpn.c25
-rw-r--r--bgpd/bgp_network.c170
-rw-r--r--bgpd/bgp_nht.c6
-rw-r--r--bgpd/bgp_open.c14
-rw-r--r--bgpd/bgp_packet.c87
-rw-r--r--bgpd/bgp_pbr.c16
-rw-r--r--bgpd/bgp_route.c56
-rw-r--r--bgpd/bgp_rpki.c8
-rw-r--r--bgpd/bgp_updgrp.c6
-rw-r--r--bgpd/bgp_updgrp_packet.c4
-rw-r--r--bgpd/bgp_vty.c4
-rw-r--r--bgpd/bgp_zebra.c21
-rw-r--r--bgpd/bgpd.c25
-rw-r--r--bgpd/rfapi/rfapi.c7
-rw-r--r--bgpd/rfapi/rfapi_import.c8
-rw-r--r--bgpd/rfapi/vnc_export_bgp.c32
-rw-r--r--bgpd/rfapi/vnc_import_bgp.c13
-rw-r--r--bgpd/rfapi/vnc_zebra.c12
-rwxr-xr-xconfigure.ac115
-rwxr-xr-xdebianpkg/backports/ubuntu12.04/debian/rules1
-rwxr-xr-xdebianpkg/backports/ubuntu14.04/debian/rules8
-rwxr-xr-xdebianpkg/rules8
-rw-r--r--doc/Makefile.am8
-rw-r--r--doc/manpages/bfd-options.rst10
-rw-r--r--doc/manpages/bfdd.rst40
-rw-r--r--doc/manpages/common-options.rst1
-rw-r--r--doc/manpages/conf.py1
-rw-r--r--doc/user/basic.rst61
-rw-r--r--doc/user/bfd.rst302
-rw-r--r--doc/user/bgp.rst15
-rw-r--r--doc/user/index.rst1
-rw-r--r--doc/user/installation.rst4
-rw-r--r--doc/user/overview.rst8
-rw-r--r--doc/user/setup.rst3
-rw-r--r--eigrpd/eigrp_errors.c49
-rw-r--r--eigrpd/eigrp_errors.h33
-rw-r--r--eigrpd/eigrp_hello.c6
-rw-r--r--eigrpd/eigrp_main.c2
-rw-r--r--eigrpd/eigrp_neighbor.c4
-rw-r--r--eigrpd/eigrp_network.c97
-rw-r--r--eigrpd/eigrp_packet.c15
-rw-r--r--eigrpd/eigrp_reply.c9
-rw-r--r--eigrpd/eigrp_topology.c4
-rw-r--r--eigrpd/eigrpd.c14
-rw-r--r--eigrpd/subdir.am2
-rw-r--r--isisd/dict.c41
-rw-r--r--isisd/isis_bpf.c36
-rw-r--r--isisd/isis_circuit.c12
-rw-r--r--isisd/isis_csm.c7
-rw-r--r--isisd/isis_dlpi.c36
-rw-r--r--isisd/isis_errors.c49
-rw-r--r--isisd/isis_errors.h33
-rw-r--r--isisd/isis_events.c7
-rw-r--r--isisd/isis_lsp.c14
-rw-r--r--isisd/isis_main.c4
-rw-r--r--isisd/isis_pdu.c73
-rw-r--r--isisd/isis_pfpacket.c42
-rw-r--r--isisd/isis_spf.c7
-rw-r--r--isisd/isis_te.c3
-rw-r--r--isisd/subdir.am2
-rw-r--r--ldpd/ldp_vty_cmds.c54
-rw-r--r--ldpd/ldpd.c6
-rw-r--r--ldpd/socket.c56
-rw-r--r--lib/agentx.c13
-rw-r--r--lib/bfd.h1
-rw-r--r--lib/buffer.c11
-rw-r--r--lib/command.c21
-rw-r--r--lib/command.h8
-rw-r--r--lib/command_parse.y8
-rw-r--r--lib/defun_lex.l1
-rw-r--r--lib/ferr.c169
-rw-r--r--lib/ferr.h68
-rw-r--r--lib/frr_zmq.c7
-rw-r--r--lib/if.c17
-rw-r--r--lib/if.h12
-rw-r--r--lib/json.h14
-rw-r--r--lib/lib_errors.c118
-rw-r--r--lib/lib_errors.h45
-rw-r--r--lib/libfrr.c15
-rw-r--r--lib/linklist.c20
-rw-r--r--lib/linklist.h13
-rw-r--r--lib/log.c29
-rw-r--r--lib/log.h7
-rw-r--r--lib/memory.c28
-rw-r--r--lib/memory.h8
-rw-r--r--lib/memory_vty.c20
-rw-r--r--lib/mpls.h1
-rw-r--r--lib/netns_linux.c23
-rw-r--r--lib/pid_output.c17
-rw-r--r--lib/prefix.c6
-rw-r--r--lib/privs.c35
-rw-r--r--lib/privs.h39
-rw-r--r--lib/route_types.txt2
-rw-r--r--lib/sigevent.c4
-rw-r--r--lib/skiplist.c4
-rw-r--r--lib/sockopt.c14
-rw-r--r--lib/sockunion.c13
-rw-r--r--lib/subdir.am2
-rw-r--r--lib/vrf.c75
-rw-r--r--lib/vty.c71
-rw-r--r--lib/workqueue.c8
-rw-r--r--lib/zclient.c107
-rw-r--r--lib/zclient.h1
-rw-r--r--lib/zebra.h17
-rw-r--r--nhrpd/nhrp_cache.c21
-rw-r--r--nhrpd/nhrp_errors.c49
-rw-r--r--nhrpd/nhrp_errors.h33
-rw-r--r--nhrpd/nhrp_interface.c2
-rw-r--r--nhrpd/nhrp_main.c2
-rw-r--r--nhrpd/nhrp_nhs.c2
-rw-r--r--nhrpd/nhrp_peer.c24
-rw-r--r--nhrpd/nhrp_vc.c17
-rw-r--r--nhrpd/resolver.c9
-rw-r--r--nhrpd/subdir.am2
-rw-r--r--nhrpd/vici.c20
-rw-r--r--nhrpd/zbuf.c2
-rw-r--r--ospf6d/ospf6_bfd.c11
-rw-r--r--ospf6d/ospf6_flood.c1
-rw-r--r--ospf6d/ospf6_interface.c6
-rw-r--r--ospf6d/ospf6_message.c14
-rw-r--r--ospf6d/ospf6_neighbor.c4
-rw-r--r--ospf6d/ospf6_network.c25
-rw-r--r--ospf6d/ospf6_route.c4
-rw-r--r--ospf6d/ospf6_spf.c10
-rw-r--r--ospf6d/ospf6_zebra.c8
-rw-r--r--ospfclient/ospf_apiclient.c10
-rw-r--r--ospfd/ospf_apiserver.c12
-rw-r--r--ospfd/ospf_bfd.c20
-rw-r--r--ospfd/ospf_errors.c84
-rw-r--r--ospfd/ospf_errors.h39
-rw-r--r--ospfd/ospf_ext.c5
-rw-r--r--ospfd/ospf_interface.c3
-rw-r--r--ospfd/ospf_lsa.c27
-rw-r--r--ospfd/ospf_main.c7
-rw-r--r--ospfd/ospf_network.c80
-rw-r--r--ospfd/ospf_opaque.c29
-rw-r--r--ospfd/ospf_packet.c30
-rw-r--r--ospfd/ospf_spf.c3
-rw-r--r--ospfd/ospf_sr.c74
-rw-r--r--ospfd/ospf_te.c5
-rw-r--r--ospfd/ospfd.c25
-rw-r--r--ospfd/subdir.am2
-rw-r--r--pbrd/pbr_vty.c3
-rw-r--r--pbrd/pbr_zebra.c6
-rw-r--r--pimd/pim_bfd.c2
-rw-r--r--pimd/pim_br.c1
-rw-r--r--pimd/pim_cmd.c16
-rw-r--r--pimd/pim_errors.c49
-rw-r--r--pimd/pim_errors.h33
-rw-r--r--pimd/pim_ifchannel.c20
-rw-r--r--pimd/pim_igmp.c13
-rw-r--r--pimd/pim_igmpv3.c35
-rw-r--r--pimd/pim_instance.c13
-rw-r--r--pimd/pim_main.c2
-rw-r--r--pimd/pim_mroute.c71
-rw-r--r--pimd/pim_msdp.c4
-rw-r--r--pimd/pim_msdp_packet.c10
-rw-r--r--pimd/pim_msdp_socket.c83
-rw-r--r--pimd/pim_neighbor.c4
-rw-r--r--pimd/pim_pim.c6
-rw-r--r--pimd/pim_rp.c28
-rw-r--r--pimd/pim_sock.c43
-rw-r--r--pimd/pim_ssm.c6
-rw-r--r--pimd/pim_ssmpingd.c9
-rw-r--r--pimd/pim_time.c21
-rw-r--r--pimd/pim_tlv.c6
-rw-r--r--pimd/pim_vty.c5
-rw-r--r--pimd/pim_zlookup.c35
-rw-r--r--pimd/pimd.c4
-rw-r--r--pimd/pimd.h1
-rw-r--r--pimd/subdir.am2
-rw-r--r--redhat/daemons3
-rwxr-xr-xredhat/frr.init6
-rw-r--r--redhat/frr.logrotate7
-rw-r--r--redhat/frr.spec.in31
-rw-r--r--ripd/rip_errors.c41
-rw-r--r--ripd/rip_errors.h33
-rw-r--r--ripd/rip_interface.c6
-rw-r--r--ripd/rip_main.c2
-rw-r--r--ripd/ripd.c43
-rw-r--r--ripd/subdir.am2
-rw-r--r--ripngd/ripng_interface.c19
-rw-r--r--ripngd/ripngd.c35
-rw-r--r--snapcraft/README.usage.md18
-rw-r--r--snapcraft/defaults/bfdd.conf.default0
-rw-r--r--snapcraft/defaults/staticd.conf.default0
-rw-r--r--snapcraft/scripts/Makefile2
-rw-r--r--snapcraft/scripts/bfdd-service14
-rw-r--r--snapcraft/scripts/staticd-service20
-rw-r--r--snapcraft/snapcraft.yaml.in33
-rw-r--r--staticd/static_nht.c2
-rw-r--r--staticd/static_zebra.c2
-rw-r--r--tests/lib/test_heavy_thread.c11
-rw-r--r--tests/lib/test_heavy_wq.c17
-rw-r--r--tests/lib/test_privs.c14
-rwxr-xr-xtools/checkpatch.pl8
-rw-r--r--tools/etc/frr/daemons1
-rw-r--r--tools/etc/frr/daemons.conf1
-rwxr-xr-xtools/frr2
-rwxr-xr-xtools/frr-reload.py29
-rw-r--r--tools/zprivs.cocci76
-rw-r--r--vtysh/Makefile.am6
-rwxr-xr-xvtysh/extract.pl.in5
-rw-r--r--vtysh/vtysh.c144
-rw-r--r--vtysh/vtysh.h35
-rw-r--r--vtysh/vtysh_config.c2
-rw-r--r--vtysh/vtysh_main.c2
-rw-r--r--watchfrr/subdir.am2
-rw-r--r--watchfrr/watchfrr.c75
-rw-r--r--watchfrr/watchfrr_errors.c43
-rw-r--r--watchfrr/watchfrr_errors.h32
-rw-r--r--zebra/connected.h6
-rw-r--r--zebra/debug.h2
-rw-r--r--zebra/if_ioctl.c12
-rw-r--r--zebra/if_ioctl_solaris.c49
-rw-r--r--zebra/if_netlink.c51
-rw-r--r--zebra/interface.c4
-rw-r--r--zebra/ioctl.c87
-rw-r--r--zebra/ioctl_solaris.c55
-rw-r--r--zebra/ipforward_proc.c85
-rw-r--r--zebra/ipforward_solaris.c41
-rw-r--r--zebra/ipforward_sysctl.c73
-rw-r--r--zebra/irdp_interface.c23
-rw-r--r--zebra/irdp_main.c15
-rw-r--r--zebra/irdp_packet.c47
-rw-r--r--zebra/kernel_netlink.c171
-rw-r--r--zebra/kernel_socket.c20
-rw-r--r--zebra/label_manager.c49
-rw-r--r--zebra/main.c7
-rw-r--r--zebra/rt_socket.c23
-rw-r--r--zebra/rtadv.c26
-rw-r--r--zebra/rule_socket.c7
-rw-r--r--zebra/subdir.am2
-rw-r--r--zebra/table_manager.c12
-rw-r--r--zebra/zapi_msg.c60
-rw-r--r--zebra/zapi_msg.h1
-rw-r--r--zebra/zebra_errors.c278
-rw-r--r--zebra/zebra_errors.h73
-rw-r--r--zebra/zebra_fpm.c8
-rw-r--r--zebra/zebra_mpls.c37
-rw-r--r--zebra/zebra_mpls_openbsd.c37
-rw-r--r--zebra/zebra_netns_id.c30
-rw-r--r--zebra/zebra_netns_notify.c35
-rw-r--r--zebra/zebra_ns.c9
-rw-r--r--zebra/zebra_ptm.c482
-rw-r--r--zebra/zebra_ptm.h3
-rw-r--r--zebra/zebra_pw.c45
-rw-r--r--zebra/zebra_rib.c77
-rw-r--r--zebra/zebra_rnh.c6
-rw-r--r--zebra/zebra_routemap.c3
-rw-r--r--zebra/zebra_vxlan.c208
-rw-r--r--zebra/zserv.c18
299 files changed, 13766 insertions, 2549 deletions
diff --git a/.clang-format b/.clang-format
index cc5a95baf6..3c6a2784ce 100644
--- a/.clang-format
+++ b/.clang-format
@@ -43,6 +43,7 @@ ForEachMacros:
- SPLAY_FOREACH
- FOR_ALL_INTERFACES
- FOR_ALL_INTERFACES_ADDRESSES
+ - JSON_FOREACH
# zebra
- RE_DEST_FOREACH_ROUTE
- RE_DEST_FOREACH_ROUTE_SAFE
diff --git a/Makefile.am b/Makefile.am
index 8c96f39f39..3e268f703d 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -56,6 +56,7 @@ include sharpd/subdir.am
include pimd/subdir.am
include pbrd/subdir.am
include staticd/subdir.am
+include bfdd/subdir.am
SUBDIRS = . @LIBRFP@ @RFPTEST@ \
@BGPD@ \
diff --git a/babeld/babel_errors.c b/babeld/babel_errors.c
new file mode 100644
index 0000000000..e03cace379
--- /dev/null
+++ b/babeld/babel_errors.c
@@ -0,0 +1,61 @@
+/*
+ * Babel-specific error messages.
+ * Copyright (C) 2018 Cumulus Networks, Inc.
+ * Donald Sharp
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This 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 "lib/ferr.h"
+#include "babel_errors.h"
+
+/* clang-format off */
+static struct log_ref ferr_babel_err[] = {
+ {
+ .code = BABEL_ERR_MEMORY,
+ .title = "BABEL Memory Errors",
+ .description = "Babel has failed to allocate memory, the system is about to run out of memory",
+ .suggestion = "Find the process that is causing memory shortages, remediate that process and restart FRR"
+ },
+ {
+ .code = BABEL_ERR_PACKET,
+ .title = "BABEL Packet Error",
+ .description = "Babel has detected a packet encode/decode problem",
+ .suggestion = "Collect relevant log files and file an Issue"
+ },
+ {
+ .code = BABEL_ERR_CONFIG,
+ .title = "BABEL Configuration Error",
+ .description = "Babel has detected a configuration error of some sort",
+ .suggestion = "Ensure that the configuration is correct"
+ },
+ {
+ .code = BABEL_ERR_ROUTE,
+ .title = "BABEL Route Error",
+ .description = "Babel has detected a routing error and has an inconsistent state",
+ .suggestion = "Gather data for filing an Issue and then restart FRR"
+ },
+ {
+ .code = END_FERR,
+ }
+};
+/* clang-format on */
+
+void babel_error_init(void)
+{
+ log_ref_add(ferr_babel_err);
+}
diff --git a/babeld/babel_errors.h b/babeld/babel_errors.h
new file mode 100644
index 0000000000..19adc63f04
--- /dev/null
+++ b/babeld/babel_errors.h
@@ -0,0 +1,35 @@
+/*
+ * Babel-specific error messages.
+ * Copyright (C) 2018 Cumulus Networks, Inc.
+ * Donald Sharp
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; see the file COPYING; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef __BABEL_ERRORS_H__
+#define __BABEL_ERRORS_H__
+
+#include "lib/ferr.h"
+
+enum babel_log_refs {
+ BABEL_ERR_MEMORY = BABEL_FERR_START,
+ BABEL_ERR_PACKET,
+ BABEL_ERR_CONFIG,
+ BABEL_ERR_ROUTE,
+};
+
+extern void babel_error_init(void);
+
+#endif
diff --git a/babeld/babel_interface.c b/babeld/babel_interface.c
index 453fd8e04e..b7c01e73dc 100644
--- a/babeld/babel_interface.c
+++ b/babeld/babel_interface.c
@@ -27,6 +27,7 @@ THE SOFTWARE.
#include "prefix.h"
#include "vector.h"
#include "distribute.h"
+#include "lib_errors.h"
#include "babel_main.h"
#include "util.h"
@@ -39,6 +40,7 @@ THE SOFTWARE.
#include "route.h"
#include "xroute.h"
#include "babel_memory.h"
+#include "babel_errors.h"
#define IS_ENABLE(ifp) (babel_enable_if_lookup(ifp->name) >= 0)
@@ -167,7 +169,7 @@ babel_interface_address_add (int cmd, struct zclient *client,
if (babel_ifp->ipv4 == NULL) {
babel_ifp->ipv4 = malloc(4);
if (babel_ifp->ipv4 == NULL) {
- zlog_err("not einough memory");
+ flog_err(BABEL_ERR_MEMORY, "not enough memory");
} else {
memcpy(babel_ifp->ipv4, &prefix->u.prefix4, 4);
}
@@ -707,7 +709,7 @@ interface_recalculate(struct interface *ifp)
tmp = babel_ifp->sendbuf;
babel_ifp->sendbuf = realloc(babel_ifp->sendbuf, babel_ifp->bufsize);
if(babel_ifp->sendbuf == NULL) {
- zlog_err("Couldn't reallocate sendbuf.");
+ flog_err(BABEL_ERR_MEMORY, "Couldn't reallocate sendbuf.");
free(tmp);
babel_ifp->bufsize = 0;
return -1;
@@ -727,8 +729,9 @@ interface_recalculate(struct interface *ifp)
rc = setsockopt(protocol_socket, IPPROTO_IPV6, IPV6_JOIN_GROUP,
(char*)&mreq, sizeof(mreq));
if(rc < 0) {
- zlog_err("setsockopt(IPV6_JOIN_GROUP) on interface '%s': %s",
- ifp->name, safe_strerror(errno));
+ flog_err_sys(LIB_ERR_SOCKET,
+ "setsockopt(IPV6_JOIN_GROUP) on interface '%s': %s",
+ ifp->name, safe_strerror(errno));
/* This is probably due to a missing link-local address,
so down this interface, and wait until the main loop
tries to up it again. */
@@ -790,8 +793,9 @@ interface_reset(struct interface *ifp)
rc = setsockopt(protocol_socket, IPPROTO_IPV6, IPV6_LEAVE_GROUP,
(char*)&mreq, sizeof(mreq));
if(rc < 0)
- zlog_err("setsockopt(IPV6_LEAVE_GROUP) on interface '%s': %s",
- ifp->name, safe_strerror(errno));
+ flog_err_sys(LIB_ERR_SOCKET,
+ "setsockopt(IPV6_LEAVE_GROUP) on interface '%s': %s",
+ ifp->name, safe_strerror(errno));
}
update_interface_metric(ifp);
@@ -1056,7 +1060,7 @@ DEFUN (show_babel_route,
}
route_stream_done(routes);
} else {
- zlog_err("Couldn't allocate route stream.");
+ flog_err(BABEL_ERR_MEMORY, "Couldn't allocate route stream.");
}
xroutes = xroute_stream();
if(xroutes) {
@@ -1068,7 +1072,7 @@ DEFUN (show_babel_route,
}
xroute_stream_done(xroutes);
} else {
- zlog_err("Couldn't allocate route stream.");
+ flog_err(BABEL_ERR_MEMORY, "Couldn't allocate route stream.");
}
return CMD_SUCCESS;
}
@@ -1103,7 +1107,7 @@ DEFUN (show_babel_route_prefix,
}
route_stream_done(routes);
} else {
- zlog_err("Couldn't allocate route stream.");
+ flog_err(BABEL_ERR_MEMORY, "Couldn't allocate route stream.");
}
xroutes = xroute_stream();
if(xroutes) {
@@ -1115,7 +1119,7 @@ DEFUN (show_babel_route_prefix,
}
xroute_stream_done(xroutes);
} else {
- zlog_err("Couldn't allocate route stream.");
+ flog_err(BABEL_ERR_MEMORY, "Couldn't allocate route stream.");
}
return CMD_SUCCESS;
}
@@ -1161,7 +1165,7 @@ DEFUN (show_babel_route_addr,
}
route_stream_done(routes);
} else {
- zlog_err("Couldn't allocate route stream.");
+ flog_err(BABEL_ERR_MEMORY, "Couldn't allocate route stream.");
}
xroutes = xroute_stream();
if(xroutes) {
@@ -1173,7 +1177,7 @@ DEFUN (show_babel_route_addr,
}
xroute_stream_done(xroutes);
} else {
- zlog_err("Couldn't allocate route stream.");
+ flog_err(BABEL_ERR_MEMORY, "Couldn't allocate route stream.");
}
return CMD_SUCCESS;
}
@@ -1220,7 +1224,7 @@ DEFUN (show_babel_route_addr6,
}
route_stream_done(routes);
} else {
- zlog_err("Couldn't allocate route stream.");
+ flog_err(BABEL_ERR_MEMORY, "Couldn't allocate route stream.");
}
xroutes = xroute_stream();
if(xroutes) {
@@ -1232,7 +1236,7 @@ DEFUN (show_babel_route_addr6,
}
xroute_stream_done(xroutes);
} else {
- zlog_err("Couldn't allocate route stream.");
+ flog_err(BABEL_ERR_MEMORY, "Couldn't allocate route stream.");
}
return CMD_SUCCESS;
}
diff --git a/babeld/babel_main.c b/babeld/babel_main.c
index 9ea123c8f9..31a3fb5b4d 100644
--- a/babeld/babel_main.c
+++ b/babeld/babel_main.c
@@ -33,6 +33,7 @@ THE SOFTWARE.
#include "vty.h"
#include "memory.h"
#include "libfrr.h"
+#include "lib_errors.h"
#include "babel_main.h"
#include "babeld.h"
@@ -45,6 +46,7 @@ THE SOFTWARE.
#include "message.h"
#include "resend.h"
#include "babel_zebra.h"
+#include "babel_errors.h"
static void babel_fail(void);
static void babel_init_random(void);
@@ -151,7 +153,7 @@ main(int argc, char **argv)
frr_preinit (&babeld_di, argc, argv);
frr_opt_add ("", longopts, "");
-
+
babel_init_random();
/* set the Babel's default link-local multicast address and Babel's port */
@@ -181,9 +183,7 @@ main(int argc, char **argv)
master = frr_init ();
/* Library inits. */
- zprivs_init (&babeld_privs);
- cmd_init (1);
- vty_init (master);
+ babel_error_init();
resend_delay = BABEL_DEFAULT_RESEND_DELAY;
change_smoothing_half_life(BABEL_DEFAULT_SMOOTHING_HALF_LIFE);
@@ -196,9 +196,6 @@ main(int argc, char **argv)
/* this replace kernel_setup && kernel_setup_socket */
babelz_zebra_init ();
- /* Get zebra configuration file. */
- vty_read_config (babeld_di.config_file, babel_config_default);
-
/* init buffer */
rc = resize_receive_buffer(1500);
if(rc < 0)
@@ -228,7 +225,8 @@ babel_init_random(void)
rc = read_random_bytes(&seed, sizeof(seed));
if(rc < 0) {
- zlog_err("read(random): %s", safe_strerror(errno));
+ flog_err_sys(LIB_ERR_SYSTEM_CALL, "read(random): %s",
+ safe_strerror(errno));
seed = 42;
}
@@ -248,13 +246,14 @@ babel_replace_by_null(int fd)
fd_null = open("/dev/null", O_RDONLY);
if(fd_null < 0) {
- zlog_err("open(null): %s", safe_strerror(errno));
+ flog_err_sys(LIB_ERR_SYSTEM_CALL, "open(null): %s", safe_strerror(errno));
exit(1);
}
rc = dup2(fd_null, fd);
if(rc < 0) {
- zlog_err("dup2(null, 0): %s", safe_strerror(errno));
+ flog_err_sys(LIB_ERR_SYSTEM_CALL, "dup2(null, 0): %s",
+ safe_strerror(errno));
exit(1);
}
@@ -273,10 +272,12 @@ babel_load_state_file(void)
fd = open(state_file, O_RDONLY);
if(fd < 0 && errno != ENOENT)
- zlog_err("open(babel-state: %s)", safe_strerror(errno));
+ flog_err_sys(LIB_ERR_SYSTEM_CALL, "open(babel-state: %s)",
+ safe_strerror(errno));
rc = unlink(state_file);
if(fd >= 0 && rc < 0) {
- zlog_err("unlink(babel-state): %s", safe_strerror(errno));
+ flog_err_sys(LIB_ERR_SYSTEM_CALL, "unlink(babel-state): %s",
+ safe_strerror(errno));
/* If we couldn't unlink it, it's probably stale. */
goto fini;
}
@@ -287,7 +288,8 @@ babel_load_state_file(void)
long t;
rc = read(fd, buf, 99);
if(rc < 0) {
- zlog_err("read(babel-state): %s", safe_strerror(errno));
+ flog_err_sys(LIB_ERR_SYSTEM_CALL, "read(babel-state): %s",
+ safe_strerror(errno));
} else {
buf[rc] = '\0';
rc = sscanf(buf, "%99s %d %ld\n", buf2, &s, &t);
@@ -295,7 +297,7 @@ babel_load_state_file(void)
unsigned char sid[8];
rc = parse_eui64(buf2, sid);
if(rc < 0) {
- zlog_err("Couldn't parse babel-state.");
+ flog_err(BABEL_ERR_CONFIG, "Couldn't parse babel-state.");
} else {
struct timeval realnow;
debugf(BABEL_DEBUG_COMMON,
@@ -305,12 +307,13 @@ babel_load_state_file(void)
if(memcmp(sid, myid, 8) == 0)
myseqno = seqno_plus(s, 1);
else
- zlog_err("ID mismatch in babel-state. id=%s; old=%s",
+ flog_err(BABEL_ERR_CONFIG,
+ "ID mismatch in babel-state. id=%s; old=%s",
format_eui64(myid),
format_eui64(sid));
}
} else {
- zlog_err("Couldn't parse babel-state.");
+ flog_err(BABEL_ERR_CONFIG, "Couldn't parse babel-state.");
}
}
goto fini;
@@ -350,7 +353,8 @@ babel_save_state_file(void)
debugf(BABEL_DEBUG_COMMON, "Save state file.");
fd = open(state_file, O_WRONLY | O_TRUNC | O_CREAT, 0644);
if(fd < 0) {
- zlog_err("creat(babel-state): %s", safe_strerror(errno));
+ flog_err_sys(LIB_ERR_SYSTEM_CALL, "creat(babel-state): %s",
+ safe_strerror(errno));
unlink(state_file);
} else {
struct timeval realnow;
@@ -360,12 +364,13 @@ babel_save_state_file(void)
format_eui64(myid), (int)myseqno,
(long)realnow.tv_sec);
if(rc < 0 || rc >= 100) {
- zlog_err("write(babel-state): overflow.");
+ flog_err(BABEL_ERR_CONFIG, "write(babel-state): overflow.");
unlink(state_file);
} else {
rc = write(fd, buf, rc);
if(rc < 0) {
- zlog_err("write(babel-state): %s", safe_strerror(errno));
+ flog_err(BABEL_ERR_CONFIG, "write(babel-state): %s",
+ safe_strerror(errno));
unlink(state_file);
}
fsync(fd);
diff --git a/babeld/babeld.c b/babeld/babeld.c
index 20dd098f33..54692cdf2e 100644
--- a/babeld/babeld.c
+++ b/babeld/babeld.c
@@ -29,6 +29,7 @@ THE SOFTWARE.
#include "prefix.h"
#include "filter.h"
#include "plist.h"
+#include "lib_errors.h"
#include "babel_main.h"
#include "babeld.h"
@@ -43,6 +44,7 @@ THE SOFTWARE.
#include "babel_filter.h"
#include "babel_zebra.h"
#include "babel_memory.h"
+#include "babel_errors.h"
static int babel_init_routing_process(struct thread *thread);
static void babel_get_myid(void);
@@ -143,7 +145,8 @@ babel_create_routing_process (void)
/* Make socket for Babel protocol. */
protocol_socket = babel_socket(protocol_port);
if (protocol_socket < 0) {
- zlog_err("Couldn't create link local socket: %s", safe_strerror(errno));
+ flog_err_sys(LIB_ERR_SOCKET, "Couldn't create link local socket: %s",
+ safe_strerror(errno));
goto fail;
}
@@ -176,7 +179,7 @@ babel_read_protocol (struct thread *thread)
(struct sockaddr*)&sin6, sizeof(sin6));
if(rc < 0) {
if(errno != EAGAIN && errno != EINTR) {
- zlog_err("recv: %s", safe_strerror(errno));
+ flog_err_sys(LIB_ERR_SOCKET, "recv: %s", safe_strerror(errno));
}
} else {
FOR_ALL_INTERFACES(vrf, ifp) {
@@ -252,11 +255,13 @@ babel_get_myid(void)
return;
}
- zlog_err("Warning: couldn't find router id -- using random value.");
+ flog_err(BABEL_ERR_CONFIG,
+ "Warning: couldn't find router id -- using random value.");
rc = read_random_bytes(myid, 8);
if(rc < 0) {
- zlog_err("read(random): %s (cannot assign an ID)",safe_strerror(errno));
+ flog_err(BABEL_ERR_CONFIG, "read(random): %s (cannot assign an ID)",
+ safe_strerror(errno));
exit(1);
}
/* Clear group and global bits */
@@ -514,7 +519,8 @@ resize_receive_buffer(int size)
if(receive_buffer == NULL) {
receive_buffer = malloc(size);
if(receive_buffer == NULL) {
- zlog_err("malloc(receive_buffer): %s", safe_strerror(errno));
+ flog_err(BABEL_ERR_MEMORY, "malloc(receive_buffer): %s",
+ safe_strerror(errno));
return -1;
}
receive_buffer_size = size;
@@ -522,7 +528,8 @@ resize_receive_buffer(int size)
unsigned char *new;
new = realloc(receive_buffer, size);
if(new == NULL) {
- zlog_err("realloc(receive_buffer): %s", safe_strerror(errno));
+ flog_err(BABEL_ERR_MEMORY, "realloc(receive_buffer): %s",
+ safe_strerror(errno));
return -1;
}
receive_buffer = new;
diff --git a/babeld/kernel.c b/babeld/kernel.c
index 7e78b6dec7..ba2b58131c 100644
--- a/babeld/kernel.c
+++ b/babeld/kernel.c
@@ -73,9 +73,9 @@ kernel_interface_wireless(struct interface *interface)
}
int
-kernel_route(int operation, const unsigned char *pref, unsigned short plen,
- const unsigned char *gate, int ifindex, unsigned int metric,
- const unsigned char *newgate, int newifindex,
+kernel_route(enum babel_kernel_routes operation, const unsigned char *pref,
+ unsigned short plen, const unsigned char *gate, int ifindex,
+ unsigned int metric, const unsigned char *newgate, int newifindex,
unsigned int newmetric)
{
int rc;
@@ -116,12 +116,9 @@ kernel_route(int operation, const unsigned char *pref, unsigned short plen,
newmetric);
return rc;
break;
- default:
- zlog_err("this should never happen (false value - kernel_route)");
- assert(0);
- exit(1);
- break;
}
+
+ return 0;
}
static int
diff --git a/babeld/kernel.h b/babeld/kernel.h
index eb1e793279..5b1437ef3e 100644
--- a/babeld/kernel.h
+++ b/babeld/kernel.h
@@ -29,17 +29,19 @@ THE SOFTWARE.
#define KERNEL_INFINITY 0xFFFF
-#define ROUTE_FLUSH 0
-#define ROUTE_ADD 1
-#define ROUTE_MODIFY 2
+enum babel_kernel_routes {
+ ROUTE_FLUSH,
+ ROUTE_ADD,
+ ROUTE_MODIFY,
+};
int kernel_interface_operational(struct interface *interface);
int kernel_interface_mtu(struct interface *interface);
int kernel_interface_wireless(struct interface *interface);
-int kernel_route(int operation, const unsigned char *dest, unsigned short plen,
- const unsigned char *gate, int ifindex, unsigned int metric,
- const unsigned char *newgate, int newifindex,
- unsigned int newmetric);
+int kernel_route(enum babel_kernel_routes operation, const unsigned char *dest,
+ unsigned short plen, const unsigned char *gate, int ifindex,
+ unsigned int metric, const unsigned char *newgate,
+ int newifindex, unsigned int newmetric);
int if_eui64(int ifindex, unsigned char *eui);
int gettime(struct timeval *tv);
int read_random_bytes(void *buf, size_t len);
diff --git a/babeld/message.c b/babeld/message.c
index 95b4e87cc7..09eaca7a48 100644
--- a/babeld/message.c
+++ b/babeld/message.c
@@ -35,6 +35,7 @@ THE SOFTWARE.
#include "message.h"
#include "kernel.h"
#include "babel_main.h"
+#include "babel_errors.h"
static unsigned char packet_header[4] = {42, 2};
@@ -140,12 +141,12 @@ parse_update_subtlv(const unsigned char *a, int alen,
}
if(i + 1 > alen) {
- zlog_err("Received truncated attributes.");
+ flog_err(BABEL_ERR_PACKET, "Received truncated attributes.");
return;
}
len = a[i + 1];
if(i + len > alen) {
- zlog_err("Received truncated attributes.");
+ flog_err(BABEL_ERR_PACKET, "Received truncated attributes.");
return;
}
@@ -153,13 +154,14 @@ parse_update_subtlv(const unsigned char *a, int alen,
/* Nothing. */
} else if(type == SUBTLV_DIVERSITY) {
if(len > DIVERSITY_HOPS) {
- zlog_err("Received overlong channel information (%d > %d).n",
- len, DIVERSITY_HOPS);
+ flog_err(BABEL_ERR_PACKET,
+ "Received overlong channel information (%d > %d).n",
+ len, DIVERSITY_HOPS);
len = DIVERSITY_HOPS;
}
if(memchr(a + i + 2, 0, len) != NULL) {
/* 0 is reserved. */
- zlog_err("Channel information contains 0!");
+ flog_err(BABEL_ERR_PACKET, "Channel information contains 0!");
return;
}
memset(channels, 0, DIVERSITY_HOPS);
@@ -187,12 +189,14 @@ parse_hello_subtlv(const unsigned char *a, int alen,
}
if(i + 1 > alen) {
- zlog_err("Received truncated sub-TLV on Hello message.");
+ flog_err(BABEL_ERR_PACKET,
+ "Received truncated sub-TLV on Hello message.");
return -1;
}
len = a[i + 1];
if(i + len > alen) {
- zlog_err("Received truncated sub-TLV on Hello message.");
+ flog_err(BABEL_ERR_PACKET,
+ "Received truncated sub-TLV on Hello message.");
return -1;
}
@@ -203,7 +207,8 @@ parse_hello_subtlv(const unsigned char *a, int alen,
DO_NTOHL(*hello_send_us, a + i + 2);
ret = 1;
} else {
- zlog_err("Received incorrect RTT sub-TLV on Hello message.");
+ flog_err(BABEL_ERR_PACKET,
+ "Received incorrect RTT sub-TLV on Hello message.");
}
} else {
debugf(BABEL_DEBUG_COMMON,
@@ -230,12 +235,14 @@ parse_ihu_subtlv(const unsigned char *a, int alen,
}
if(i + 1 > alen) {
- zlog_err("Received truncated sub-TLV on IHU message.");
+ flog_err(BABEL_ERR_PACKET,
+ "Received truncated sub-TLV on IHU message.");
return -1;
}
len = a[i + 1];
if(i + len > alen) {
- zlog_err("Received truncated sub-TLV on IHU message.");
+ flog_err(BABEL_ERR_PACKET,
+ "Received truncated sub-TLV on IHU message.");
return -1;
}
@@ -248,7 +255,8 @@ parse_ihu_subtlv(const unsigned char *a, int alen,
ret = 1;
}
else {
- zlog_err("Received incorrect RTT sub-TLV on IHU message.");
+ flog_err(BABEL_ERR_PACKET,
+ "Received incorrect RTT sub-TLV on IHU message.");
}
} else {
debugf(BABEL_DEBUG_COMMON,
@@ -337,27 +345,29 @@ parse_packet(const unsigned char *from, struct interface *ifp,
}
if(!linklocal(from)) {
- zlog_err("Received packet from non-local address %s.",
- format_address(from));
+ flog_err(BABEL_ERR_PACKET,
+ "Received packet from non-local address %s.",
+ format_address(from));
return;
}
if (babel_packet_examin (packet, packetlen)) {
- zlog_err("Received malformed packet on %s from %s.",
- ifp->name, format_address(from));
+ flog_err(BABEL_ERR_PACKET,
+ "Received malformed packet on %s from %s.",
+ ifp->name, format_address(from));
return;
}
neigh = find_neighbour(from, ifp);
if(neigh == NULL) {
- zlog_err("Couldn't allocate neighbour.");
+ flog_err(BABEL_ERR_PACKET, "Couldn't allocate neighbour.");
return;
}
DO_NTOHS(bodylen, packet + 2);
if(bodylen + 4 > packetlen) {
- zlog_err("Received truncated packet (%d + 4 > %d).",
+ flog_err(BABEL_ERR_PACKET, "Received truncated packet (%d + 4 > %d).",
bodylen, packetlen);
bodylen = packetlen - 4;
}
@@ -506,7 +516,8 @@ parse_packet(const unsigned char *from, struct interface *ifp,
have_router_id = 1;
}
if(!have_router_id && message[2] != 0) {
- zlog_err("Received prefix with no router id.");
+ flog_err(BABEL_ERR_PACKET,
+ "Received prefix with no router id.");
goto fail;
}
debugf(BABEL_DEBUG_COMMON,"Received update%s%s for %s from %s on %s.",
@@ -517,7 +528,8 @@ parse_packet(const unsigned char *from, struct interface *ifp,
if(message[2] == 0) {
if(metric < 0xFFFF) {
- zlog_err("Received wildcard update with finite metric.");
+ flog_err(BABEL_ERR_PACKET,
+ "Received wildcard update with finite metric.");
goto done;
}
retract_neighbour_routes(neigh);
@@ -609,8 +621,9 @@ parse_packet(const unsigned char *from, struct interface *ifp,
continue;
fail:
- zlog_err("Couldn't parse packet (%d, %d) from %s on %s.",
- message[0], message[1], format_address(from), ifp->name);
+ flog_err(BABEL_ERR_PACKET,
+ "Couldn't parse packet (%d, %d) from %s on %s.",
+ message[0], message[1], format_address(from), ifp->name);
goto done;
}
@@ -697,7 +710,7 @@ fill_rtt_message(struct interface *ifp)
DO_HTONL(babel_ifp->sendbuf + babel_ifp->buffered_hello + 10, time);
return 1;
} else {
- zlog_err("No space left for timestamp sub-TLV "
+ flog_err(BABEL_ERR_PACKET, "No space left for timestamp sub-TLV "
"(this shouldn't happen)");
return -1;
}
@@ -732,10 +745,11 @@ flushbuf(struct interface *ifp)
babel_ifp->sendbuf, babel_ifp->buffered,
(struct sockaddr*)&sin6, sizeof(sin6));
if(rc < 0)
- zlog_err("send: %s", safe_strerror(errno));
+ flog_err(BABEL_ERR_PACKET, "send: %s", safe_strerror(errno));
} else {
- zlog_err("Warning: bucket full, dropping packet to %s.",
- ifp->name);
+ flog_err(BABEL_ERR_PACKET,
+ "Warning: bucket full, dropping packet to %s.",
+ ifp->name);
}
}
VALGRIND_MAKE_MEM_UNDEFINED(babel_ifp->sendbuf, babel_ifp->bufsize);
@@ -856,7 +870,8 @@ start_unicast_message(struct neighbour *neigh, int type, int len)
if(!unicast_buffer)
unicast_buffer = malloc(UNICAST_BUFSIZE);
if(!unicast_buffer) {
- zlog_err("malloc(unicast_buffer): %s", safe_strerror(errno));
+ flog_err(BABEL_ERR_MEMORY, "malloc(unicast_buffer): %s",
+ safe_strerror(errno));
return -1;
}
@@ -992,11 +1007,13 @@ flush_unicast(int dofree)
unicast_buffer, unicast_buffered,
(struct sockaddr*)&sin6, sizeof(sin6));
if(rc < 0)
- zlog_err("send(unicast): %s", safe_strerror(errno));
+ flog_err(BABEL_ERR_PACKET, "send(unicast): %s",
+ safe_strerror(errno));
} else {
- zlog_err("Warning: bucket full, dropping unicast packet to %s if %s.",
- format_address(unicast_neighbour->address),
- unicast_neighbour->ifp->name);
+ flog_err(BABEL_ERR_PACKET,
+ "Warning: bucket full, dropping unicast packet to %s if %s.",
+ format_address(unicast_neighbour->address),
+ unicast_neighbour->ifp->name);
}
done:
@@ -1301,7 +1318,8 @@ buffer_update(struct interface *ifp,
again:
babel_ifp->buffered_updates = malloc(n *sizeof(struct buffered_update));
if(babel_ifp->buffered_updates == NULL) {
- zlog_err("malloc(buffered_updates): %s", safe_strerror(errno));
+ flog_err(BABEL_ERR_MEMORY, "malloc(buffered_updates): %s",
+ safe_strerror(errno));
if(n > 4) {
/* Try again with a tiny buffer. */
n = 4;
@@ -1364,7 +1382,7 @@ send_update(struct interface *ifp, int urgent,
}
route_stream_done(routes);
} else {
- zlog_err("Couldn't allocate route stream.");
+ flog_err(BABEL_ERR_MEMORY, "Couldn't allocate route stream.");
}
set_timeout(&babel_ifp->update_timeout, babel_ifp->update_interval);
babel_ifp->last_update_time = babel_now.tv_sec;
@@ -1442,7 +1460,7 @@ send_self_update(struct interface *ifp)
}
xroute_stream_done(xroutes);
} else {
- zlog_err("Couldn't allocate xroute stream.");
+ flog_err(BABEL_ERR_MEMORY, "Couldn't allocate xroute stream.");
}
}
diff --git a/babeld/neighbour.c b/babeld/neighbour.c
index 3db121fd26..c1592fb18a 100644
--- a/babeld/neighbour.c
+++ b/babeld/neighbour.c
@@ -38,6 +38,7 @@ THE SOFTWARE.
#include "route.h"
#include "message.h"
#include "resend.h"
+#include "babel_errors.h"
struct neighbour *neighs = NULL;
@@ -89,7 +90,8 @@ find_neighbour(const unsigned char *address, struct interface *ifp)
neigh = malloc(sizeof(struct neighbour));
if(neigh == NULL) {
- zlog_err("malloc(neighbour): %s", safe_strerror(errno));
+ flog_err(BABEL_ERR_MEMORY, "malloc(neighbour): %s",
+ safe_strerror(errno));
return NULL;
}
diff --git a/babeld/route.c b/babeld/route.c
index bc7590fb39..ceeaa10577 100644
--- a/babeld/route.c
+++ b/babeld/route.c
@@ -34,13 +34,14 @@ THE SOFTWARE.
#include "xroute.h"
#include "message.h"
#include "resend.h"
+#include "babel_errors.h"
static void consider_route(struct babel_route *route);
struct babel_route **routes = NULL;
static int route_slots = 0, max_route_slots = 0;
int kernel_metric = 0;
-int diversity_kind = DIVERSITY_NONE;
+enum babel_diversity diversity_kind = DIVERSITY_NONE;
int diversity_factor = BABEL_DEFAULT_DIVERSITY_FACTOR;
int keep_unfeasible = 0;
@@ -398,15 +399,16 @@ install_route(struct babel_route *route)
return;
if(!route_feasible(route))
- zlog_err("WARNING: installing unfeasible route "
- "(this shouldn't happen).");
+ flog_err(BABEL_ERR_ROUTE, "WARNING: installing unfeasible route "
+ "(this shouldn't happen).");
i = find_route_slot(route->src->prefix, route->src->plen, NULL);
assert(i >= 0 && i < route_slots);
if(routes[i] != route && routes[i]->installed) {
- zlog_err("WARNING: attempting to install duplicate route "
- "(this shouldn't happen).");
+ flog_err(BABEL_ERR_ROUTE,
+ "WARNING: attempting to install duplicate route "
+ "(this shouldn't happen).");
return;
}
@@ -416,7 +418,8 @@ install_route(struct babel_route *route)
metric_to_kernel(route_metric(route)), NULL, 0, 0);
if(rc < 0) {
int save = errno;
- zlog_err("kernel_route(ADD): %s", safe_strerror(errno));
+ flog_err(BABEL_ERR_ROUTE, "kernel_route(ADD): %s",
+ safe_strerror(errno));
if(save != EEXIST)
return;
}
@@ -438,7 +441,8 @@ uninstall_route(struct babel_route *route)
route->neigh->ifp->ifindex,
metric_to_kernel(route_metric(route)), NULL, 0, 0);
if(rc < 0)
- zlog_err("kernel_route(FLUSH): %s", safe_strerror(errno));
+ flog_err(BABEL_ERR_ROUTE, "kernel_route(FLUSH): %s",
+ safe_strerror(errno));
route->installed = 0;
}
@@ -461,8 +465,8 @@ switch_routes(struct babel_route *old, struct babel_route *new)
return;
if(!route_feasible(new))
- zlog_err("WARNING: switching to unfeasible route "
- "(this shouldn't happen).");
+ flog_err(BABEL_ERR_ROUTE, "WARNING: switching to unfeasible route "
+ "(this shouldn't happen).");
rc = kernel_route(ROUTE_MODIFY, old->src->prefix, old->src->plen,
old->nexthop, old->neigh->ifp->ifindex,
@@ -470,7 +474,8 @@ switch_routes(struct babel_route *old, struct babel_route *new)
new->nexthop, new->neigh->ifp->ifindex,
metric_to_kernel(route_metric(new)));
if(rc < 0) {
- zlog_err("kernel_route(MODIFY): %s", safe_strerror(errno));
+ flog_err(BABEL_ERR_ROUTE, "kernel_route(MODIFY): %s",
+ safe_strerror(errno));
return;
}
@@ -498,7 +503,8 @@ change_route_metric(struct babel_route *route,
route->nexthop, route->neigh->ifp->ifindex,
new);
if(rc < 0) {
- zlog_err("kernel_route(MODIFY metric): %s", safe_strerror(errno));
+ flog_err(BABEL_ERR_ROUTE, "kernel_route(MODIFY metric): %s",
+ safe_strerror(errno));
return;
}
}
@@ -581,10 +587,9 @@ route_interferes(struct babel_route *route, struct interface *ifp)
}
}
return 0;
- default:
- zlog_err("Unknown kind of diversity.");
- return 1;
}
+
+ return 1;
}
int
@@ -793,7 +798,7 @@ update_route(const unsigned char *router_id,
return NULL;
if(martian_prefix(prefix, plen)) {
- zlog_err("Rejecting martian route to %s through %s.",
+ flog_err(BABEL_ERR_ROUTE, "Rejecting martian route to %s through %s.",
format_prefix(prefix, plen), format_address(nexthop));
return NULL;
}
@@ -901,7 +906,7 @@ update_route(const unsigned char *router_id,
route->next = NULL;
new_route = insert_route(route);
if(new_route == NULL) {
- zlog_err("Couldn't insert route.");
+ flog_err(BABEL_ERR_ROUTE, "Couldn't insert route.");
free(route);
return NULL;
}
diff --git a/babeld/route.h b/babeld/route.h
index c2026d1765..c994d22a9f 100644
--- a/babeld/route.h
+++ b/babeld/route.h
@@ -27,10 +27,12 @@ THE SOFTWARE.
#include "babel_interface.h"
#include "source.h"
-#define DIVERSITY_NONE 0
-#define DIVERSITY_INTERFACE_1 1
-#define DIVERSITY_CHANNEL_1 2
-#define DIVERSITY_CHANNEL 3
+enum babel_diversity {
+ DIVERSITY_NONE,
+ DIVERSITY_INTERFACE_1,
+ DIVERSITY_CHANNEL_1,
+ DIVERSITY_CHANNEL,
+};
#define DIVERSITY_HOPS 8
@@ -55,7 +57,8 @@ struct route_stream;
extern struct babel_route **routes;
extern int kernel_metric;
-extern int diversity_kind, diversity_factor;
+extern enum babel_diversity diversity_kind;
+extern int diversity_factor;
extern int keep_unfeasible;
extern int smoothing_half_life;
diff --git a/babeld/source.c b/babeld/source.c
index 72396102b3..d6dd848952 100644
--- a/babeld/source.c
+++ b/babeld/source.c
@@ -31,6 +31,7 @@ THE SOFTWARE.
#include "source.h"
#include "babel_interface.h"
#include "route.h"
+#include "babel_errors.h"
struct source *srcs = NULL;
@@ -58,7 +59,7 @@ find_source(const unsigned char *id, const unsigned char *p, unsigned char plen,
src = malloc(sizeof(struct source));
if(src == NULL) {
- zlog_err("malloc(source): %s", safe_strerror(errno));
+ flog_err(BABEL_ERR_MEMORY, "malloc(source): %s", safe_strerror(errno));
return NULL;
}
diff --git a/babeld/subdir.am b/babeld/subdir.am
index c44cb275c2..6f91f73930 100644
--- a/babeld/subdir.am
+++ b/babeld/subdir.am
@@ -9,6 +9,7 @@ dist_examples_DATA += babeld/babeld.conf.sample
endif
babeld_libbabel_a_SOURCES = \
+ babeld/babel_errors.c \
babeld/babel_filter.c \
babeld/babel_interface.c \
babeld/babel_memory.c \
@@ -26,6 +27,7 @@ babeld_libbabel_a_SOURCES = \
# end
noinst_HEADERS += \
+ babeld/babel_errors.h \
babeld/babel_filter.h \
babeld/babel_interface.h \
babeld/babel_main.h \
diff --git a/bfdd/.gitignore b/bfdd/.gitignore
new file mode 100644
index 0000000000..e554d1b33f
--- /dev/null
+++ b/bfdd/.gitignore
@@ -0,0 +1,3 @@
+# ignore binary files
+*.a
+bfdd
diff --git a/bfdd/bfd.c b/bfdd/bfd.c
new file mode 100644
index 0000000000..28b6beadcb
--- /dev/null
+++ b/bfdd/bfd.c
@@ -0,0 +1,1294 @@
+/*********************************************************************
+ * Copyright 2013 Cumulus Networks, LLC. All rights reserved.
+ * Copyright 2014,2015,2016,2017 Cumulus Networks, Inc. All rights reserved.
+ *
+ * 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
+ *
+ * bfd.c: implements the BFD protocol.
+ *
+ * Authors
+ * -------
+ * Shrijeet Mukherjee [shm@cumulusnetworks.com]
+ * Kanna Rajagopal [kanna@cumulusnetworks.com]
+ * Radhika Mahankali [Radhika@cumulusnetworks.com]
+ */
+
+#include <zebra.h>
+
+#include "lib/jhash.h"
+
+#include "bfd.h"
+
+DEFINE_QOBJ_TYPE(bfd_session);
+
+/*
+ * Prototypes
+ */
+static uint32_t ptm_bfd_gen_ID(void);
+static void ptm_bfd_echo_xmt_TO(struct bfd_session *bfd);
+static void bfd_session_free(struct bfd_session *bs);
+static struct bfd_session *bfd_session_new(int sd);
+static struct bfd_session *bfd_find_disc(struct sockaddr_any *sa,
+ uint32_t ldisc);
+static int bfd_session_update(struct bfd_session *bs, struct bfd_peer_cfg *bpc);
+static const char *get_diag_str(int diag);
+
+
+/*
+ * Functions
+ */
+struct bfd_session *bs_peer_find(struct bfd_peer_cfg *bpc)
+{
+ struct bfd_session *bs;
+ struct peer_label *pl;
+ struct bfd_mhop_key mhop;
+ struct bfd_shop_key shop;
+
+ /* Try to find label first. */
+ if (bpc->bpc_has_label) {
+ pl = pl_find(bpc->bpc_label);
+ if (pl != NULL) {
+ bs = pl->pl_bs;
+ return bs;
+ }
+ }
+
+ /* Otherwise fallback to peer/local hash lookup. */
+ if (bpc->bpc_mhop) {
+ memset(&mhop, 0, sizeof(mhop));
+ mhop.peer = bpc->bpc_peer;
+ mhop.local = bpc->bpc_local;
+ if (bpc->bpc_has_vrfname)
+ strlcpy(mhop.vrf_name, bpc->bpc_vrfname,
+ sizeof(mhop.vrf_name));
+
+ bs = bfd_mhop_lookup(mhop);
+ } else {
+ memset(&shop, 0, sizeof(shop));
+ shop.peer = bpc->bpc_peer;
+ if (!bpc->bpc_has_vxlan && bpc->bpc_has_localif)
+ strlcpy(shop.port_name, bpc->bpc_localif,
+ sizeof(shop.port_name));
+
+ bs = bfd_shop_lookup(shop);
+ }
+
+ return bs;
+}
+
+static uint32_t ptm_bfd_gen_ID(void)
+{
+ static uint32_t sessionID = 1;
+
+ return (sessionID++);
+}
+
+void ptm_bfd_start_xmt_timer(struct bfd_session *bfd, bool is_echo)
+{
+ uint64_t jitter, xmt_TO;
+ int maxpercent;
+
+ xmt_TO = is_echo ? bfd->echo_xmt_TO : bfd->xmt_TO;
+
+ /*
+ * From section 6.5.2: trasmit interval should be randomly jittered
+ * between
+ * 75% and 100% of nominal value, unless detect_mult is 1, then should
+ * be
+ * between 75% and 90%.
+ */
+ maxpercent = (bfd->detect_mult == 1) ? 16 : 26;
+ jitter = (xmt_TO * (75 + (random() % maxpercent))) / 100;
+ /* XXX remove that division above */
+
+ if (is_echo)
+ bfd_echo_xmttimer_update(bfd, jitter);
+ else
+ bfd_xmttimer_update(bfd, jitter);
+}
+
+static void ptm_bfd_echo_xmt_TO(struct bfd_session *bfd)
+{
+ /* Send the scheduled echo packet */
+ ptm_bfd_echo_snd(bfd);
+
+ /* Restart the timer for next time */
+ ptm_bfd_start_xmt_timer(bfd, true);
+}
+
+void ptm_bfd_xmt_TO(struct bfd_session *bfd, int fbit)
+{
+ /* Send the scheduled control packet */
+ ptm_bfd_snd(bfd, fbit);
+
+ /* Restart the timer for next time */
+ ptm_bfd_start_xmt_timer(bfd, false);
+}
+
+void ptm_bfd_echo_stop(struct bfd_session *bfd, int polling)
+{
+ bfd->echo_xmt_TO = 0;
+ bfd->echo_detect_TO = 0;
+ BFD_UNSET_FLAG(bfd->flags, BFD_SESS_FLAG_ECHO_ACTIVE);
+
+ bfd_echo_xmttimer_delete(bfd);
+ bfd_echo_recvtimer_delete(bfd);
+
+ if (polling) {
+ bfd->polling = polling;
+ bfd->new_timers.desired_min_tx = bfd->up_min_tx;
+ bfd->new_timers.required_min_rx = bfd->timers.required_min_rx;
+ ptm_bfd_snd(bfd, 0);
+ }
+}
+
+void ptm_bfd_echo_start(struct bfd_session *bfd)
+{
+ bfd->echo_detect_TO = (bfd->remote_detect_mult * bfd->echo_xmt_TO);
+ ptm_bfd_echo_xmt_TO(bfd);
+
+ bfd->polling = 1;
+ bfd->new_timers.desired_min_tx = bfd->up_min_tx;
+ bfd->new_timers.required_min_rx = bfd->timers.required_min_rx;
+ ptm_bfd_snd(bfd, 0);
+}
+
+void ptm_bfd_ses_up(struct bfd_session *bfd)
+{
+ int old_state = bfd->ses_state;
+
+ bfd->local_diag = 0;
+ bfd->ses_state = PTM_BFD_UP;
+ bfd->polling = 1;
+ monotime(&bfd->uptime);
+
+ /* If the peer is capable to receiving Echo pkts */
+ if (bfd->echo_xmt_TO && !BFD_CHECK_FLAG(bfd->flags, BFD_SESS_FLAG_MH)) {
+ ptm_bfd_echo_start(bfd);
+ } else {
+ bfd->new_timers.desired_min_tx = bfd->up_min_tx;
+ bfd->new_timers.required_min_rx = bfd->timers.required_min_rx;
+ ptm_bfd_snd(bfd, 0);
+ }
+
+ control_notify(bfd);
+
+ if (old_state != bfd->ses_state)
+ log_info("state-change: [%s] %s -> %s", bs_to_string(bfd),
+ state_list[old_state].str,
+ state_list[bfd->ses_state].str);
+}
+
+void ptm_bfd_ses_dn(struct bfd_session *bfd, uint8_t diag)
+{
+ int old_state = bfd->ses_state;
+
+ bfd->local_diag = diag;
+ bfd->discrs.remote_discr = 0;
+ bfd->ses_state = PTM_BFD_DOWN;
+ bfd->polling = 0;
+ bfd->demand_mode = 0;
+ monotime(&bfd->downtime);
+
+ ptm_bfd_snd(bfd, 0);
+
+ /* only signal clients when going from up->down state */
+ if (old_state == PTM_BFD_UP)
+ control_notify(bfd);
+
+ /* Stop echo packet transmission if they are active */
+ if (BFD_CHECK_FLAG(bfd->flags, BFD_SESS_FLAG_ECHO_ACTIVE))
+ ptm_bfd_echo_stop(bfd, 0);
+
+ if (old_state != bfd->ses_state)
+ log_info("state-change: [%s] %s -> %s reason:%s",
+ bs_to_string(bfd), state_list[old_state].str,
+ state_list[bfd->ses_state].str,
+ get_diag_str(bfd->local_diag));
+}
+
+static int ptm_bfd_get_vrf_name(char *port_name, char *vrf_name)
+{
+ struct bfd_iface *iface;
+ struct bfd_vrf *vrf;
+
+ if ((port_name == NULL) || (vrf_name == NULL))
+ return -1;
+
+ iface = bfd_iface_lookup(port_name);
+ if (iface) {
+ vrf = bfd_vrf_lookup(iface->vrf_id);
+ if (vrf) {
+ strlcpy(vrf_name, vrf->name, sizeof(vrf->name));
+ return 0;
+ }
+ }
+ return -1;
+}
+
+static struct bfd_session *bfd_find_disc(struct sockaddr_any *sa,
+ uint32_t ldisc)
+{
+ struct bfd_session *bs;
+
+ bs = bfd_id_lookup(ldisc);
+ if (bs == NULL)
+ return NULL;
+
+ /* Remove unused fields. */
+ switch (sa->sa_sin.sin_family) {
+ case AF_INET:
+ sa->sa_sin.sin_port = 0;
+ if (memcmp(sa, &bs->shop.peer, sizeof(sa->sa_sin)) == 0)
+ return bs;
+ break;
+ case AF_INET6:
+ sa->sa_sin6.sin6_port = 0;
+ if (memcmp(sa, &bs->shop.peer, sizeof(sa->sa_sin6)) == 0)
+ return bs;
+ break;
+ }
+
+ return NULL;
+}
+
+struct bfd_session *ptm_bfd_sess_find(struct bfd_pkt *cp, char *port_name,
+ struct sockaddr_any *peer,
+ struct sockaddr_any *local,
+ char *vrf_name, bool is_mhop)
+{
+ struct bfd_session *l_bfd = NULL;
+ struct bfd_mhop_key mhop;
+ struct bfd_shop_key shop;
+ char vrf_buf[MAXNAMELEN];
+
+ /* Find our session using the ID signaled by the remote end. */
+ if (cp->discrs.remote_discr)
+ return bfd_find_disc(peer, ntohl(cp->discrs.remote_discr));
+
+ /* Search for session without using discriminator. */
+ if (is_mhop) {
+ memset(&mhop, 0, sizeof(mhop));
+ mhop.peer = *peer;
+ mhop.local = *local;
+ if (vrf_name && vrf_name[0]) {
+ strlcpy(mhop.vrf_name, vrf_name, sizeof(mhop.vrf_name));
+ } else if (port_name && port_name[0]) {
+ memset(vrf_buf, 0, sizeof(vrf_buf));
+ if (ptm_bfd_get_vrf_name(port_name, vrf_buf) != -1)
+ strlcpy(mhop.vrf_name, vrf_buf,
+ sizeof(mhop.vrf_name));
+ }
+
+ l_bfd = bfd_mhop_lookup(mhop);
+ } else {
+ memset(&shop, 0, sizeof(shop));
+ shop.peer = *peer;
+ if (port_name && port_name[0])
+ strlcpy(shop.port_name, port_name,
+ sizeof(shop.port_name));
+
+ l_bfd = bfd_shop_lookup(shop);
+ }
+
+ /* XXX maybe remoteDiscr should be checked for remoteHeard cases. */
+ return l_bfd;
+}
+
+#if 0 /* TODO VxLAN Support */
+static void
+_update_vxlan_sess_parms(struct bfd_session *bfd, bfd_sess_parms *sess_parms)
+{
+ struct bfd_session_vxlan_info *vxlan_info = &bfd->vxlan_info;
+ bfd_parms_list *parms = &sess_parms->parms;
+
+ vxlan_info->vnid = parms->vnid;
+ vxlan_info->check_tnl_key = parms->check_tnl_key;
+ vxlan_info->forwarding_if_rx = parms->forwarding_if_rx;
+ vxlan_info->cpath_down = parms->cpath_down;
+ vxlan_info->decay_min_rx = parms->decay_min_rx;
+
+ inet_aton(parms->local_dst_ip, &vxlan_info->local_dst_ip);
+ inet_aton(parms->remote_dst_ip, &vxlan_info->peer_dst_ip);
+
+ memcpy(vxlan_info->local_dst_mac, parms->local_dst_mac, ETH_ALEN);
+ memcpy(vxlan_info->peer_dst_mac, parms->remote_dst_mac, ETH_ALEN);
+
+ /* The interface may change for Vxlan BFD sessions, so update
+ * the local mac and ifindex
+ */
+ bfd->ifindex = sess_parms->ifindex;
+ memcpy(bfd->local_mac, sess_parms->local_mac, sizeof(bfd->local_mac));
+}
+#endif /* VxLAN support */
+
+int bfd_xmt_cb(struct thread *t)
+{
+ struct bfd_session *bs = THREAD_ARG(t);
+
+ ptm_bfd_xmt_TO(bs, 0);
+
+ return 0;
+}
+
+int bfd_echo_xmt_cb(struct thread *t)
+{
+ struct bfd_session *bs = THREAD_ARG(t);
+
+ ptm_bfd_echo_xmt_TO(bs);
+
+ return 0;
+}
+
+/* Was ptm_bfd_detect_TO() */
+int bfd_recvtimer_cb(struct thread *t)
+{
+ struct bfd_session *bs = THREAD_ARG(t);
+
+ switch (bs->ses_state) {
+ case PTM_BFD_INIT:
+ case PTM_BFD_UP:
+ ptm_bfd_ses_dn(bs, BFD_DIAGDETECTTIME);
+ bfd_recvtimer_update(bs);
+ break;
+
+ default:
+ /* Second detect time expiration, zero remote discr (section
+ * 6.5.1)
+ */
+ bs->discrs.remote_discr = 0;
+ break;
+ }
+
+ return 0;
+}
+
+/* Was ptm_bfd_echo_detect_TO() */
+int bfd_echo_recvtimer_cb(struct thread *t)
+{
+ struct bfd_session *bs = THREAD_ARG(t);
+
+ switch (bs->ses_state) {
+ case PTM_BFD_INIT:
+ case PTM_BFD_UP:
+ ptm_bfd_ses_dn(bs, BFD_DIAGDETECTTIME);
+ break;
+ }
+
+ return 0;
+}
+
+static struct bfd_session *bfd_session_new(int sd)
+{
+ struct bfd_session *bs;
+
+ bs = XCALLOC(MTYPE_BFDD_CONFIG, sizeof(*bs));
+ if (bs == NULL)
+ return NULL;
+
+ QOBJ_REG(bs, bfd_session);
+
+ bs->up_min_tx = BFD_DEFDESIREDMINTX;
+ bs->timers.required_min_rx = BFD_DEFREQUIREDMINRX;
+ bs->timers.required_min_echo = BFD_DEF_REQ_MIN_ECHO;
+ bs->detect_mult = BFD_DEFDETECTMULT;
+ bs->mh_ttl = BFD_DEF_MHOP_TTL;
+
+ bs->sock = sd;
+ monotime(&bs->uptime);
+ bs->downtime = bs->uptime;
+
+ return bs;
+}
+
+int bfd_session_update_label(struct bfd_session *bs, const char *nlabel)
+{
+ /* New label treatment:
+ * - Check if the label is taken;
+ * - Try to allocate the memory for it and register;
+ */
+ if (bs->pl == NULL) {
+ if (pl_find(nlabel) != NULL) {
+ /* Someone is already using it. */
+ return -1;
+ }
+
+ if (pl_new(nlabel, bs) == NULL)
+ return -1;
+
+ return 0;
+ }
+
+ /*
+ * Test label change consistency:
+ * - Do nothing if it's the same label;
+ * - Check if the future label is already taken;
+ * - Change label;
+ */
+ if (strcmp(nlabel, bs->pl->pl_label) == 0)
+ return -1;
+ if (pl_find(nlabel) != NULL)
+ return -1;
+
+ strlcpy(bs->pl->pl_label, nlabel, sizeof(bs->pl->pl_label));
+ return 0;
+}
+
+static void _bfd_session_update(struct bfd_session *bs,
+ struct bfd_peer_cfg *bpc)
+{
+ if (bpc->bpc_echo) {
+ /* Check if echo mode is already active. */
+ if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_ECHO))
+ goto skip_echo;
+
+ BFD_SET_FLAG(bs->flags, BFD_SESS_FLAG_ECHO);
+ ptm_bfd_echo_start(bs);
+
+ /* Activate/update echo receive timeout timer. */
+ bfd_echo_recvtimer_update(bs);
+ } else {
+ /* Check if echo mode is already disabled. */
+ if (!BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_ECHO))
+ goto skip_echo;
+
+ BFD_UNSET_FLAG(bs->flags, BFD_SESS_FLAG_ECHO);
+ ptm_bfd_echo_stop(bs, 0);
+ }
+
+skip_echo:
+ if (bpc->bpc_has_txinterval)
+ bs->up_min_tx = bpc->bpc_txinterval * 1000;
+
+ if (bpc->bpc_has_recvinterval)
+ bs->timers.required_min_rx = bpc->bpc_recvinterval * 1000;
+
+ if (bpc->bpc_has_detectmultiplier)
+ bs->detect_mult = bpc->bpc_detectmultiplier;
+
+ if (bpc->bpc_has_echointerval)
+ bs->timers.required_min_echo = bpc->bpc_echointerval * 1000;
+
+ if (bpc->bpc_has_label)
+ bfd_session_update_label(bs, bpc->bpc_label);
+
+ if (bpc->bpc_shutdown) {
+ /* Check if already shutdown. */
+ if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_SHUTDOWN))
+ return;
+
+ BFD_SET_FLAG(bs->flags, BFD_SESS_FLAG_SHUTDOWN);
+
+ /* Disable all events. */
+ bfd_recvtimer_delete(bs);
+ bfd_echo_recvtimer_delete(bs);
+ bfd_xmttimer_delete(bs);
+ bfd_echo_xmttimer_delete(bs);
+
+ /* Change and notify state change. */
+ bs->ses_state = PTM_BFD_ADM_DOWN;
+ control_notify(bs);
+
+ ptm_bfd_snd(bs, 0);
+ } else {
+ /* Check if already working. */
+ if (!BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_SHUTDOWN))
+ return;
+
+ BFD_UNSET_FLAG(bs->flags, BFD_SESS_FLAG_SHUTDOWN);
+
+ /* Change and notify state change. */
+ bs->ses_state = PTM_BFD_DOWN;
+ control_notify(bs);
+
+ /* Enable all timers. */
+ bfd_recvtimer_update(bs);
+ bfd_xmttimer_update(bs, bs->xmt_TO);
+ if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_ECHO)) {
+ bfd_echo_recvtimer_update(bs);
+ bfd_echo_xmttimer_update(bs, bs->echo_xmt_TO);
+ }
+ }
+}
+
+static int bfd_session_update(struct bfd_session *bs, struct bfd_peer_cfg *bpc)
+{
+ /* User didn't want to update, return failure. */
+ if (bpc->bpc_createonly)
+ return -1;
+
+ _bfd_session_update(bs, bpc);
+
+ /* TODO add VxLAN support. */
+
+ control_notify_config(BCM_NOTIFY_CONFIG_UPDATE, bs);
+
+ return 0;
+}
+
+static void bfd_session_free(struct bfd_session *bs)
+{
+ if (bs->sock != -1)
+ close(bs->sock);
+
+ bfd_recvtimer_delete(bs);
+ bfd_echo_recvtimer_delete(bs);
+ bfd_xmttimer_delete(bs);
+ bfd_echo_xmttimer_delete(bs);
+
+ bfd_id_delete(bs->discrs.my_discr);
+ if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH))
+ bfd_mhop_delete(bs->mhop);
+ else
+ bfd_shop_delete(bs->shop);
+
+ pl_free(bs->pl);
+
+ QOBJ_UNREG(bs);
+ XFREE(MTYPE_BFDD_CONFIG, bs);
+}
+
+struct bfd_session *ptm_bfd_sess_new(struct bfd_peer_cfg *bpc)
+{
+ struct bfd_session *bfd, *l_bfd;
+ int psock;
+
+ /* check to see if this needs a new session */
+ l_bfd = bs_peer_find(bpc);
+ if (l_bfd) {
+ /* Requesting a duplicated peer means update configuration. */
+ if (bfd_session_update(l_bfd, bpc) == 0)
+ return l_bfd;
+ else
+ return NULL;
+ }
+
+ /*
+ * Get socket for transmitting control packets. Note that if we
+ * could use the destination port (3784) for the source
+ * port we wouldn't need a socket per session.
+ */
+ if (bpc->bpc_ipv4) {
+ psock = bp_peer_socket(bpc);
+ if (psock == -1)
+ return NULL;
+ } else {
+ psock = bp_peer_socketv6(bpc);
+ if (psock == -1)
+ return NULL;
+ }
+
+ /* Get memory */
+ bfd = bfd_session_new(psock);
+ if (bfd == NULL) {
+ log_error("session-new: allocation failed");
+ return NULL;
+ }
+
+ if (bpc->bpc_has_localif && !bpc->bpc_mhop) {
+ bfd->ifindex = ptm_bfd_fetch_ifindex(bpc->bpc_localif);
+ ptm_bfd_fetch_local_mac(bpc->bpc_localif, bfd->local_mac);
+ }
+
+ if (bpc->bpc_has_vxlan)
+ BFD_SET_FLAG(bfd->flags, BFD_SESS_FLAG_VXLAN);
+
+ if (bpc->bpc_ipv4 == false) {
+ BFD_SET_FLAG(bfd->flags, BFD_SESS_FLAG_IPV6);
+
+ /* Set the IPv6 scope id for link-local addresses. */
+ if (IN6_IS_ADDR_LINKLOCAL(&bpc->bpc_local.sa_sin6.sin6_addr))
+ bpc->bpc_local.sa_sin6.sin6_scope_id = bfd->ifindex;
+ if (IN6_IS_ADDR_LINKLOCAL(&bpc->bpc_peer.sa_sin6.sin6_addr))
+ bpc->bpc_peer.sa_sin6.sin6_scope_id = bfd->ifindex;
+ }
+
+ /* Initialize the session */
+ bfd->ses_state = PTM_BFD_DOWN;
+ bfd->discrs.my_discr = ptm_bfd_gen_ID();
+ bfd->discrs.remote_discr = 0;
+ bfd->local_ip = bpc->bpc_local;
+ bfd->local_address = bpc->bpc_local;
+ bfd->timers.desired_min_tx = bfd->up_min_tx;
+ bfd->detect_TO = (bfd->detect_mult * BFD_DEF_SLOWTX);
+
+ /* Use detect_TO first for slow detection, then use recvtimer_update. */
+ bfd_recvtimer_update(bfd);
+
+ bfd_id_insert(bfd);
+
+ if (bpc->bpc_mhop) {
+ BFD_SET_FLAG(bfd->flags, BFD_SESS_FLAG_MH);
+ bfd->mhop.peer = bpc->bpc_peer;
+ bfd->mhop.local = bpc->bpc_local;
+ if (bpc->bpc_has_vrfname)
+ strlcpy(bfd->mhop.vrf_name, bpc->bpc_vrfname,
+ sizeof(bfd->mhop.vrf_name));
+
+ bfd_mhop_insert(bfd);
+ } else {
+ bfd->shop.peer = bpc->bpc_peer;
+ if (!bpc->bpc_has_vxlan && bpc->bpc_has_localif)
+ strlcpy(bfd->shop.port_name, bpc->bpc_localif,
+ sizeof(bfd->shop.port_name));
+
+ bfd_shop_insert(bfd);
+ }
+
+ if (BFD_CHECK_FLAG(bfd->flags, BFD_SESS_FLAG_VXLAN)) {
+ static uint8_t bfd_def_vxlan_dmac[] = {0x00, 0x23, 0x20,
+ 0x00, 0x00, 0x01};
+ memcpy(bfd->peer_mac, bfd_def_vxlan_dmac,
+ sizeof(bfd_def_vxlan_dmac));
+ }
+#if 0 /* TODO */
+ else if (event->rmac) {
+ if (sscanf(event->rmac, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx",
+ &bfd->peer_mac[0], &bfd->peer_mac[1], &bfd->peer_mac[2],
+ &bfd->peer_mac[3], &bfd->peer_mac[4], &bfd->peer_mac[5])
+ != 6)
+ DLOG("%s: Assigning remote mac = %s", __func__,
+ event->rmac);
+ }
+#endif
+
+ /*
+ * XXX: session update triggers echo start, so we must have our
+ * discriminator ID set first.
+ */
+ _bfd_session_update(bfd, bpc);
+
+ /* Start transmitting with slow interval until peer responds */
+ bfd->xmt_TO = BFD_DEF_SLOWTX;
+
+ ptm_bfd_xmt_TO(bfd, 0);
+
+ log_info("session-new: %s", bs_to_string(bfd));
+
+ control_notify_config(BCM_NOTIFY_CONFIG_ADD, bfd);
+
+ return bfd;
+}
+
+int ptm_bfd_ses_del(struct bfd_peer_cfg *bpc)
+{
+ struct bfd_session *bs;
+
+ /* Find session and call free(). */
+ bs = bs_peer_find(bpc);
+ if (bs == NULL)
+ return -1;
+
+ /* This pointer is being referenced, don't let it be deleted. */
+ if (bs->refcount > 0) {
+ log_error("session-delete: refcount failure: %" PRIu64
+ " references",
+ bs->refcount);
+ return -1;
+ }
+
+ log_info("session-delete: %s", bs_to_string(bs));
+
+ control_notify_config(BCM_NOTIFY_CONFIG_DELETE, bs);
+
+ bfd_session_free(bs);
+
+ return 0;
+}
+
+void bfd_set_polling(struct bfd_session *bs)
+{
+ bs->new_timers.desired_min_tx = bs->up_min_tx;
+ bs->new_timers.required_min_rx = bs->timers.required_min_rx;
+ bs->new_timers.required_min_echo = bs->timers.required_min_echo;
+ bs->polling = 1;
+}
+
+
+/*
+ * Helper functions.
+ */
+static const char *get_diag_str(int diag)
+{
+ for (int i = 0; diag_list[i].str; i++) {
+ if (diag_list[i].type == diag)
+ return diag_list[i].str;
+ }
+ return "N/A";
+}
+
+const char *satostr(struct sockaddr_any *sa)
+{
+#define INETSTR_BUFCOUNT 8
+ static char buf[INETSTR_BUFCOUNT][INET6_ADDRSTRLEN];
+ static int bufidx;
+ struct sockaddr_in *sin = &sa->sa_sin;
+ struct sockaddr_in6 *sin6 = &sa->sa_sin6;
+
+ bufidx += (bufidx + 1) % INETSTR_BUFCOUNT;
+ buf[bufidx][0] = 0;
+
+ switch (sin->sin_family) {
+ case AF_INET:
+ inet_ntop(AF_INET, &sin->sin_addr, buf[bufidx],
+ sizeof(buf[bufidx]));
+ break;
+ case AF_INET6:
+ inet_ntop(AF_INET6, &sin6->sin6_addr, buf[bufidx],
+ sizeof(buf[bufidx]));
+ break;
+
+ default:
+ strlcpy(buf[bufidx], "unknown", sizeof(buf[bufidx]));
+ break;
+ }
+
+ return buf[bufidx];
+}
+
+const char *diag2str(uint8_t diag)
+{
+ switch (diag) {
+ case 0:
+ return "ok";
+ case 1:
+ return "control detection time expired";
+ case 2:
+ return "echo function failed";
+ case 3:
+ return "neighbor signaled session down";
+ case 4:
+ return "forwarding plane reset";
+ case 5:
+ return "path down";
+ case 6:
+ return "concatenated path down";
+ case 7:
+ return "administratively down";
+ case 8:
+ return "reverse concatenated path down";
+ default:
+ return "unknown";
+ }
+}
+
+int strtosa(const char *addr, struct sockaddr_any *sa)
+{
+ memset(sa, 0, sizeof(*sa));
+
+ if (inet_pton(AF_INET, addr, &sa->sa_sin.sin_addr) == 1) {
+ sa->sa_sin.sin_family = AF_INET;
+#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
+ sa->sa_sin.sin_len = sizeof(sa->sa_sin);
+#endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */
+ return 0;
+ }
+
+ if (inet_pton(AF_INET6, addr, &sa->sa_sin6.sin6_addr) == 1) {
+ sa->sa_sin6.sin6_family = AF_INET6;
+#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
+ sa->sa_sin6.sin6_len = sizeof(sa->sa_sin6);
+#endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */
+ return 0;
+ }
+
+ return -1;
+}
+
+void integer2timestr(uint64_t time, char *buf, size_t buflen)
+{
+ unsigned int year, month, day, hour, minute, second;
+ int rv;
+
+#define MINUTES (60)
+#define HOURS (24 * MINUTES)
+#define DAYS (30 * HOURS)
+#define MONTHS (12 * DAYS)
+#define YEARS (MONTHS)
+ if (time >= YEARS) {
+ year = time / YEARS;
+ time -= year * YEARS;
+
+ rv = snprintf(buf, buflen, "%u year(s), ", year);
+ buf += rv;
+ buflen -= rv;
+ }
+ if (time >= MONTHS) {
+ month = time / MONTHS;
+ time -= month * MONTHS;
+
+ rv = snprintf(buf, buflen, "%u month(s), ", month);
+ buf += rv;
+ buflen -= rv;
+ }
+ if (time >= DAYS) {
+ day = time / DAYS;
+ time -= day * DAYS;
+
+ rv = snprintf(buf, buflen, "%u day(s), ", day);
+ buf += rv;
+ buflen -= rv;
+ }
+ if (time >= HOURS) {
+ hour = time / HOURS;
+ time -= hour * HOURS;
+
+ rv = snprintf(buf, buflen, "%u hour(s), ", hour);
+ buf += rv;
+ buflen -= rv;
+ }
+ if (time >= MINUTES) {
+ minute = time / MINUTES;
+ time -= minute * MINUTES;
+
+ rv = snprintf(buf, buflen, "%u minute(s), ", minute);
+ buf += rv;
+ buflen -= rv;
+ }
+ second = time % MINUTES;
+ snprintf(buf, buflen, "%u second(s)", second);
+}
+
+const char *bs_to_string(struct bfd_session *bs)
+{
+ static char buf[256];
+ int pos;
+ bool is_mhop = BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH);
+
+ pos = snprintf(buf, sizeof(buf), "mhop:%s", is_mhop ? "yes" : "no");
+ if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH)) {
+ pos += snprintf(buf + pos, sizeof(buf) - pos,
+ " peer:%s local:%s", satostr(&bs->mhop.peer),
+ satostr(&bs->mhop.local));
+
+ if (bs->mhop.vrf_name[0])
+ snprintf(buf + pos, sizeof(buf) - pos, " vrf:%s",
+ bs->mhop.vrf_name);
+ } else {
+ pos += snprintf(buf + pos, sizeof(buf) - pos, " peer:%s",
+ satostr(&bs->shop.peer));
+
+ if (bs->local_address.sa_sin.sin_family)
+ pos += snprintf(buf + pos, sizeof(buf) - pos,
+ " local:%s",
+ satostr(&bs->local_address));
+
+ if (bs->shop.port_name[0])
+ snprintf(buf + pos, sizeof(buf) - pos, " interface:%s",
+ bs->shop.port_name);
+ }
+
+ return buf;
+}
+
+
+/*
+ * BFD hash data structures to find sessions.
+ */
+static struct hash *bfd_id_hash;
+static struct hash *bfd_shop_hash;
+static struct hash *bfd_mhop_hash;
+static struct hash *bfd_vrf_hash;
+static struct hash *bfd_iface_hash;
+
+static unsigned int bfd_id_hash_do(void *p);
+static int bfd_id_hash_cmp(const void *n1, const void *n2);
+static unsigned int bfd_shop_hash_do(void *p);
+static int bfd_shop_hash_cmp(const void *n1, const void *n2);
+static unsigned int bfd_mhop_hash_do(void *p);
+static int bfd_mhop_hash_cmp(const void *n1, const void *n2);
+static unsigned int bfd_vrf_hash_do(void *p);
+static int bfd_vrf_hash_cmp(const void *n1, const void *n2);
+static unsigned int bfd_iface_hash_do(void *p);
+static int bfd_iface_hash_cmp(const void *n1, const void *n2);
+
+static void _shop_key(struct bfd_session *bs, const struct bfd_shop_key *shop);
+static void _shop_key2(struct bfd_session *bs, const struct bfd_shop_key *shop);
+static void _mhop_key(struct bfd_session *bs, const struct bfd_mhop_key *mhop);
+static int _iface_key(struct bfd_iface *iface, const char *ifname);
+
+static void _bfd_free(struct hash_backet *hb,
+ void *arg __attribute__((__unused__)));
+static void _vrf_free(void *arg);
+static void _iface_free(void *arg);
+
+/* BFD hash for our discriminator. */
+static unsigned int bfd_id_hash_do(void *p)
+{
+ struct bfd_session *bs = p;
+
+ return jhash_1word(bs->discrs.my_discr, 0);
+}
+
+static int bfd_id_hash_cmp(const void *n1, const void *n2)
+{
+ const struct bfd_session *bs1 = n1, *bs2 = n2;
+
+ return bs1->discrs.my_discr == bs2->discrs.my_discr;
+}
+
+/* BFD hash for single hop. */
+static unsigned int bfd_shop_hash_do(void *p)
+{
+ struct bfd_session *bs = p;
+
+ return jhash(&bs->shop, sizeof(bs->shop), 0);
+}
+
+static int bfd_shop_hash_cmp(const void *n1, const void *n2)
+{
+ const struct bfd_session *bs1 = n1, *bs2 = n2;
+
+ return memcmp(&bs1->shop, &bs2->shop, sizeof(bs1->shop)) == 0;
+}
+
+/* BFD hash for multi hop. */
+static unsigned int bfd_mhop_hash_do(void *p)
+{
+ struct bfd_session *bs = p;
+
+ return jhash(&bs->mhop, sizeof(bs->mhop), 0);
+}
+
+static int bfd_mhop_hash_cmp(const void *n1, const void *n2)
+{
+ const struct bfd_session *bs1 = n1, *bs2 = n2;
+
+ return memcmp(&bs1->mhop, &bs2->mhop, sizeof(bs1->mhop)) == 0;
+}
+
+/* BFD hash for VRFs. */
+static unsigned int bfd_vrf_hash_do(void *p)
+{
+ struct bfd_vrf *vrf = p;
+
+ return jhash_1word(vrf->vrf_id, 0);
+}
+
+static int bfd_vrf_hash_cmp(const void *n1, const void *n2)
+{
+ const struct bfd_vrf *v1 = n1, *v2 = n2;
+
+ return v1->vrf_id == v2->vrf_id;
+}
+
+/* BFD hash for interfaces. */
+static unsigned int bfd_iface_hash_do(void *p)
+{
+ struct bfd_iface *iface = p;
+
+ return string_hash_make(iface->ifname);
+}
+
+static int bfd_iface_hash_cmp(const void *n1, const void *n2)
+{
+ const struct bfd_iface *i1 = n1, *i2 = n2;
+
+ return strcmp(i1->ifname, i2->ifname) == 0;
+}
+
+/* Helper functions */
+static void _shop_key(struct bfd_session *bs, const struct bfd_shop_key *shop)
+{
+ bs->shop = *shop;
+
+ /* Remove unused fields. */
+ switch (bs->shop.peer.sa_sin.sin_family) {
+ case AF_INET:
+ bs->shop.peer.sa_sin.sin_port = 0;
+ break;
+ case AF_INET6:
+ bs->shop.peer.sa_sin6.sin6_port = 0;
+ break;
+ }
+}
+
+static void _shop_key2(struct bfd_session *bs, const struct bfd_shop_key *shop)
+{
+ _shop_key(bs, shop);
+ memset(bs->shop.port_name, 0, sizeof(bs->shop.port_name));
+}
+
+static void _mhop_key(struct bfd_session *bs, const struct bfd_mhop_key *mhop)
+{
+ bs->mhop = *mhop;
+
+ /* Remove unused fields. */
+ switch (bs->mhop.peer.sa_sin.sin_family) {
+ case AF_INET:
+ bs->mhop.peer.sa_sin.sin_port = 0;
+ bs->mhop.local.sa_sin.sin_port = 0;
+ break;
+ case AF_INET6:
+ bs->mhop.peer.sa_sin6.sin6_port = 0;
+ bs->mhop.local.sa_sin6.sin6_port = 0;
+ break;
+ }
+}
+
+static int _iface_key(struct bfd_iface *iface, const char *ifname)
+{
+ size_t slen = sizeof(iface->ifname);
+
+ memset(iface->ifname, 0, slen);
+ if (strlcpy(iface->ifname, ifname, slen) >= slen)
+ return -1;
+
+ return 0;
+}
+
+/*
+ * Hash public interface / exported functions.
+ */
+
+/* Lookup functions. */
+struct bfd_session *bfd_id_lookup(uint32_t id)
+{
+ struct bfd_session bs;
+
+ bs.discrs.my_discr = id;
+
+ return hash_lookup(bfd_id_hash, &bs);
+}
+
+struct bfd_session *bfd_shop_lookup(struct bfd_shop_key shop)
+{
+ struct bfd_session bs, *bsp;
+
+ _shop_key(&bs, &shop);
+
+ bsp = hash_lookup(bfd_shop_hash, &bs);
+ if (bsp == NULL && bs.shop.port_name[0] != 0) {
+ /*
+ * Since the local interface spec is optional, try
+ * searching the key without it as well.
+ */
+ _shop_key2(&bs, &shop);
+ bsp = hash_lookup(bfd_shop_hash, &bs);
+ }
+
+ return bsp;
+}
+
+struct bfd_session *bfd_mhop_lookup(struct bfd_mhop_key mhop)
+{
+ struct bfd_session bs;
+
+ _mhop_key(&bs, &mhop);
+
+ return hash_lookup(bfd_shop_hash, &bs);
+}
+
+struct bfd_vrf *bfd_vrf_lookup(int vrf_id)
+{
+ struct bfd_vrf vrf;
+
+ vrf.vrf_id = vrf_id;
+
+ return hash_lookup(bfd_vrf_hash, &vrf);
+}
+
+struct bfd_iface *bfd_iface_lookup(const char *ifname)
+{
+ struct bfd_iface iface;
+
+ if (_iface_key(&iface, ifname) != 0)
+ return NULL;
+
+ return hash_lookup(bfd_iface_hash, &iface);
+}
+
+/*
+ * Delete functions.
+ *
+ * Delete functions searches and remove the item from the hash and
+ * returns a pointer to the removed item data. If the item was not found
+ * then it returns NULL.
+ *
+ * The data stored inside the hash is not free()ed, so you must do it
+ * manually after getting the pointer back.
+ */
+struct bfd_session *bfd_id_delete(uint32_t id)
+{
+ struct bfd_session bs;
+
+ bs.discrs.my_discr = id;
+
+ return hash_release(bfd_id_hash, &bs);
+}
+
+struct bfd_session *bfd_shop_delete(struct bfd_shop_key shop)
+{
+ struct bfd_session bs, *bsp;
+
+ _shop_key(&bs, &shop);
+ bsp = hash_release(bfd_shop_hash, &bs);
+ if (bsp == NULL && shop.port_name[0] != 0) {
+ /*
+ * Since the local interface spec is optional, try
+ * searching the key without it as well.
+ */
+ _shop_key2(&bs, &shop);
+ bsp = hash_release(bfd_shop_hash, &bs);
+ }
+
+ return bsp;
+}
+
+struct bfd_session *bfd_mhop_delete(struct bfd_mhop_key mhop)
+{
+ struct bfd_session bs;
+
+ _mhop_key(&bs, &mhop);
+
+ return hash_release(bfd_mhop_hash, &bs);
+}
+
+struct bfd_vrf *bfd_vrf_delete(int vrf_id)
+{
+ struct bfd_vrf vrf;
+
+ vrf.vrf_id = vrf_id;
+
+ return hash_release(bfd_vrf_hash, &vrf);
+}
+
+struct bfd_iface *bfd_iface_delete(const char *ifname)
+{
+ struct bfd_iface iface;
+
+ if (_iface_key(&iface, ifname) != 0)
+ return NULL;
+
+ return hash_release(bfd_iface_hash, &iface);
+}
+
+/* Iteration functions. */
+void bfd_id_iterate(hash_iter_func hif, void *arg)
+{
+ hash_iterate(bfd_id_hash, hif, arg);
+}
+
+void bfd_shop_iterate(hash_iter_func hif, void *arg)
+{
+ hash_iterate(bfd_shop_hash, hif, arg);
+}
+
+void bfd_mhop_iterate(hash_iter_func hif, void *arg)
+{
+ hash_iterate(bfd_mhop_hash, hif, arg);
+}
+
+void bfd_vrf_iterate(hash_iter_func hif, void *arg)
+{
+ hash_iterate(bfd_vrf_hash, hif, arg);
+}
+
+void bfd_iface_iterate(hash_iter_func hif, void *arg)
+{
+ hash_iterate(bfd_iface_hash, hif, arg);
+}
+
+/*
+ * Insert functions.
+ *
+ * Inserts session into hash and returns `true` on success, otherwise
+ * `false`.
+ */
+bool bfd_id_insert(struct bfd_session *bs)
+{
+ return (hash_get(bfd_id_hash, bs, hash_alloc_intern) == bs);
+}
+
+bool bfd_shop_insert(struct bfd_session *bs)
+{
+ return (hash_get(bfd_shop_hash, bs, hash_alloc_intern) == bs);
+}
+
+bool bfd_mhop_insert(struct bfd_session *bs)
+{
+ return (hash_get(bfd_mhop_hash, bs, hash_alloc_intern) == bs);
+}
+
+bool bfd_vrf_insert(struct bfd_vrf *vrf)
+{
+ return (hash_get(bfd_vrf_hash, vrf, hash_alloc_intern) == vrf);
+}
+
+bool bfd_iface_insert(struct bfd_iface *iface)
+{
+ return (hash_get(bfd_iface_hash, iface, hash_alloc_intern) == iface);
+}
+
+void bfd_initialize(void)
+{
+ bfd_id_hash = hash_create(bfd_id_hash_do, bfd_id_hash_cmp,
+ "BFD discriminator hash");
+ bfd_shop_hash = hash_create(bfd_shop_hash_do, bfd_shop_hash_cmp,
+ "BFD single hop hash");
+ bfd_mhop_hash = hash_create(bfd_mhop_hash_do, bfd_mhop_hash_cmp,
+ "BFD multihop hop hash");
+ bfd_vrf_hash =
+ hash_create(bfd_vrf_hash_do, bfd_vrf_hash_cmp, "BFD VRF hash");
+ bfd_iface_hash = hash_create(bfd_iface_hash_do, bfd_iface_hash_cmp,
+ "BFD interface hash");
+}
+
+static void _bfd_free(struct hash_backet *hb,
+ void *arg __attribute__((__unused__)))
+{
+ struct bfd_session *bs = hb->data;
+
+ bfd_session_free(bs);
+}
+
+static void _vrf_free(void *arg)
+{
+ struct bfd_vrf *vrf = arg;
+
+ XFREE(MTYPE_BFDD_CONFIG, vrf);
+}
+
+static void _iface_free(void *arg)
+{
+ struct bfd_iface *iface = arg;
+
+ XFREE(MTYPE_BFDD_CONFIG, iface);
+}
+
+void bfd_shutdown(void)
+{
+ /*
+ * Close and free all BFD sessions.
+ *
+ * _bfd_free() will call bfd_session_free() which will take care
+ * of removing the session from all hashes, so we just run an
+ * assert() here to make sure it really happened.
+ */
+ bfd_id_iterate(_bfd_free, NULL);
+ assert(bfd_shop_hash->count == 0);
+ assert(bfd_mhop_hash->count == 0);
+
+ /* Clean the VRF and interface hashes. */
+ hash_clean(bfd_vrf_hash, _vrf_free);
+ hash_clean(bfd_iface_hash, _iface_free);
+
+ /* Now free the hashes themselves. */
+ hash_free(bfd_id_hash);
+ hash_free(bfd_shop_hash);
+ hash_free(bfd_mhop_hash);
+ hash_free(bfd_vrf_hash);
+ hash_free(bfd_iface_hash);
+}
diff --git a/bfdd/bfd.h b/bfdd/bfd.h
new file mode 100644
index 0000000000..40aecaa67b
--- /dev/null
+++ b/bfdd/bfd.h
@@ -0,0 +1,631 @@
+/*********************************************************************
+ * Copyright 2014,2015,2016,2017 Cumulus Networks, Inc. All rights reserved.
+ *
+ * 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
+ *
+ * bfd.h: implements the BFD protocol.
+ */
+
+#ifndef _BFD_H_
+#define _BFD_H_
+
+#include <netinet/in.h>
+
+#include <stdbool.h>
+#include <stdarg.h>
+#include <stdint.h>
+
+#include "lib/hash.h"
+#include "lib/libfrr.h"
+#include "lib/qobj.h"
+#include "lib/queue.h"
+
+#include "bfdctl.h"
+
+#define ETHERNET_ADDRESS_LENGTH 6
+
+#ifdef BFD_DEBUG
+#define BFDD_JSON_CONV_OPTIONS (JSON_C_TO_STRING_PRETTY)
+#else
+#define BFDD_JSON_CONV_OPTIONS (0)
+#endif
+
+DECLARE_MGROUP(BFDD);
+DECLARE_MTYPE(BFDD_TMP);
+DECLARE_MTYPE(BFDD_CONFIG);
+DECLARE_MTYPE(BFDD_LABEL);
+DECLARE_MTYPE(BFDD_CONTROL);
+DECLARE_MTYPE(BFDD_NOTIFICATION);
+
+struct bfd_timers {
+ uint32_t desired_min_tx;
+ uint32_t required_min_rx;
+ uint32_t required_min_echo;
+};
+
+struct bfd_discrs {
+ uint32_t my_discr;
+ uint32_t remote_discr;
+};
+
+/*
+ * Format of control packet. From section 4)
+ */
+struct bfd_pkt {
+ union {
+ uint32_t byteFields;
+ struct {
+ uint8_t diag;
+ uint8_t flags;
+ uint8_t detect_mult;
+ uint8_t len;
+ };
+ };
+ struct bfd_discrs discrs;
+ struct bfd_timers timers;
+};
+
+/*
+ * Format of Echo packet.
+ */
+struct bfd_echo_pkt {
+ union {
+ uint32_t byteFields;
+ struct {
+ uint8_t ver;
+ uint8_t len;
+ uint16_t reserved;
+ };
+ };
+ uint32_t my_discr;
+ uint8_t pad[16];
+};
+
+
+/* Macros for manipulating control packets */
+#define BFD_VERMASK 0x03
+#define BFD_DIAGMASK 0x1F
+#define BFD_GETVER(diag) ((diag >> 5) & BFD_VERMASK)
+#define BFD_SETVER(diag, val) ((diag) |= (val & BFD_VERMASK) << 5)
+#define BFD_VERSION 1
+#define BFD_PBIT 0x20
+#define BFD_FBIT 0x10
+#define BFD_CBIT 0x08
+#define BFD_ABIT 0x04
+#define BFD_DEMANDBIT 0x02
+#define BFD_DIAGNEIGHDOWN 3
+#define BFD_DIAGDETECTTIME 1
+#define BFD_DIAGADMINDOWN 7
+#define BFD_SETDEMANDBIT(flags, val) \
+ { \
+ if ((val)) \
+ flags |= BFD_DEMANDBIT; \
+ }
+#define BFD_SETPBIT(flags, val) \
+ { \
+ if ((val)) \
+ flags |= BFD_PBIT; \
+ }
+#define BFD_GETPBIT(flags) (flags & BFD_PBIT)
+#define BFD_SETFBIT(flags, val) \
+ { \
+ if ((val)) \
+ flags |= BFD_FBIT; \
+ }
+#define BFD_GETFBIT(flags) (flags & BFD_FBIT)
+#define BFD_SETSTATE(flags, val) \
+ { \
+ if ((val)) \
+ flags |= (val & 0x3) << 6; \
+ }
+#define BFD_GETSTATE(flags) ((flags >> 6) & 0x3)
+#define BFD_ECHO_VERSION 1
+#define BFD_ECHO_PKT_LEN sizeof(struct bfd_echo_pkt)
+#define BFD_CTRL_PKT_LEN sizeof(struct bfd_pkt)
+#define IP_HDR_LEN 20
+#define UDP_HDR_LEN 8
+#define ETH_HDR_LEN 14
+#define VXLAN_HDR_LEN 8
+#define HEADERS_MIN_LEN (ETH_HDR_LEN + IP_HDR_LEN + UDP_HDR_LEN)
+#define BFD_ECHO_PKT_TOT_LEN \
+ ((int)(ETH_HDR_LEN + IP_HDR_LEN + UDP_HDR_LEN + BFD_ECHO_PKT_LEN))
+#define BFD_VXLAN_PKT_TOT_LEN \
+ ((int)(VXLAN_HDR_LEN + ETH_HDR_LEN + IP_HDR_LEN + UDP_HDR_LEN \
+ + BFD_CTRL_PKT_LEN))
+#define BFD_RX_BUF_LEN 160
+
+/* BFD session flags */
+enum bfd_session_flags {
+ BFD_SESS_FLAG_NONE = 0,
+ BFD_SESS_FLAG_ECHO = 1 << 0, /* BFD Echo functionality */
+ BFD_SESS_FLAG_ECHO_ACTIVE = 1 << 1, /* BFD Echo Packets are being sent
+ * actively
+ */
+ BFD_SESS_FLAG_MH = 1 << 2, /* BFD Multi-hop session */
+ BFD_SESS_FLAG_VXLAN = 1 << 3, /* BFD Multi-hop session which is
+ * used to monitor vxlan tunnel
+ */
+ BFD_SESS_FLAG_IPV6 = 1 << 4, /* BFD IPv6 session */
+ BFD_SESS_FLAG_SEND_EVT_ACTIVE = 1 << 5, /* send event timer active */
+ BFD_SESS_FLAG_SEND_EVT_IGNORE = 1 << 6, /* ignore send event when timer
+ * expires
+ */
+ BFD_SESS_FLAG_SHUTDOWN = 1 << 7, /* disable BGP peer function */
+};
+
+#define BFD_SET_FLAG(field, flag) (field |= flag)
+#define BFD_UNSET_FLAG(field, flag) (field &= ~flag)
+#define BFD_CHECK_FLAG(field, flag) (field & flag)
+
+/* BFD session hash keys */
+struct bfd_shop_key {
+ struct sockaddr_any peer;
+ char port_name[MAXNAMELEN + 1];
+};
+
+struct bfd_mhop_key {
+ struct sockaddr_any peer;
+ struct sockaddr_any local;
+ char vrf_name[MAXNAMELEN + 1];
+};
+
+struct bfd_session_stats {
+ uint64_t rx_ctrl_pkt;
+ uint64_t tx_ctrl_pkt;
+ uint64_t rx_echo_pkt;
+ uint64_t tx_echo_pkt;
+};
+
+struct bfd_session_vxlan_info {
+ uint32_t vnid;
+ uint32_t decay_min_rx;
+ uint8_t forwarding_if_rx;
+ uint8_t cpath_down;
+ uint8_t check_tnl_key;
+ uint8_t local_dst_mac[ETHERNET_ADDRESS_LENGTH];
+ uint8_t peer_dst_mac[ETHERNET_ADDRESS_LENGTH];
+ struct in_addr local_dst_ip;
+ struct in_addr peer_dst_ip;
+};
+
+/* bfd_session shortcut label forwarding. */
+struct peer_label;
+
+/*
+ * Session state information
+ */
+struct bfd_session {
+
+ /* protocol state per RFC 5880*/
+ uint8_t ses_state;
+ struct bfd_discrs discrs;
+ uint8_t local_diag;
+ uint8_t demand_mode;
+ uint8_t detect_mult;
+ uint8_t remote_detect_mult;
+ uint8_t mh_ttl;
+
+ /* Timers */
+ struct bfd_timers timers;
+ struct bfd_timers new_timers;
+ uint32_t up_min_tx;
+ uint64_t detect_TO;
+ struct thread *echo_recvtimer_ev;
+ struct thread *recvtimer_ev;
+ uint64_t xmt_TO;
+ uint64_t echo_xmt_TO;
+ struct thread *xmttimer_ev;
+ struct thread *echo_xmttimer_ev;
+ uint64_t echo_detect_TO;
+
+ /* software object state */
+ uint8_t polling;
+
+ /* This and the localDiscr are the keys to state info */
+ struct peer_label *pl;
+ union {
+ struct bfd_shop_key shop;
+ struct bfd_mhop_key mhop;
+ };
+ int sock;
+
+ struct sockaddr_any local_address;
+ struct sockaddr_any local_ip;
+ int ifindex;
+ uint8_t local_mac[ETHERNET_ADDRESS_LENGTH];
+ uint8_t peer_mac[ETHERNET_ADDRESS_LENGTH];
+ uint16_t ip_id;
+
+ /* BFD session flags */
+ enum bfd_session_flags flags;
+
+ uint8_t echo_pkt[BFD_ECHO_PKT_TOT_LEN]; /* Save the Echo Packet
+ * which will be transmitted
+ */
+ struct bfd_session_stats stats;
+ struct bfd_session_vxlan_info vxlan_info;
+
+ struct timeval uptime; /* last up time */
+ struct timeval downtime; /* last down time */
+
+ /* Remote peer data (for debugging mostly) */
+ uint8_t remote_diag;
+ struct bfd_timers remote_timers;
+
+ uint64_t refcount; /* number of pointers referencing this. */
+
+ /* VTY context data. */
+ QOBJ_FIELDS;
+};
+DECLARE_QOBJ_TYPE(bfd_session);
+
+struct peer_label {
+ TAILQ_ENTRY(peer_label) pl_entry;
+
+ struct bfd_session *pl_bs;
+ char pl_label[MAXNAMELEN];
+};
+TAILQ_HEAD(pllist, peer_label);
+
+struct bfd_diag_str_list {
+ const char *str;
+ int type;
+};
+
+struct bfd_state_str_list {
+ const char *str;
+ int type;
+};
+
+struct bfd_vrf {
+ int vrf_id;
+ char name[MAXNAMELEN + 1];
+} bfd_vrf;
+
+struct bfd_iface {
+ int vrf_id;
+ char ifname[MAXNAMELEN + 1];
+} bfd_iface;
+
+
+/* States defined per 4.1 */
+#define PTM_BFD_ADM_DOWN 0
+#define PTM_BFD_DOWN 1
+#define PTM_BFD_INIT 2
+#define PTM_BFD_UP 3
+
+
+/* Various constants */
+/* Retrieved from ptm_timer.h from Cumulus PTM sources. */
+#define MSEC_PER_SEC 1000L
+#define NSEC_PER_MSEC 1000000L
+
+#define BFD_DEF_DEMAND 0
+#define BFD_DEFDETECTMULT 3
+#define BFD_DEFDESIREDMINTX (300 * MSEC_PER_SEC)
+#define BFD_DEFREQUIREDMINRX (300 * MSEC_PER_SEC)
+#define BFD_DEF_REQ_MIN_ECHO (50 * MSEC_PER_SEC)
+#define BFD_DEF_SLOWTX (2000 * MSEC_PER_SEC)
+#define BFD_DEF_MHOP_TTL 5
+#define BFD_PKT_LEN 24 /* Length of control packet */
+#define BFD_TTL_VAL 255
+#define BFD_RCV_TTL_VAL 1
+#define BFD_TOS_VAL 0xC0
+#define BFD_PKT_INFO_VAL 1
+#define BFD_IPV6_PKT_INFO_VAL 1
+#define BFD_IPV6_ONLY_VAL 1
+#define BFD_SRCPORTINIT 49142
+#define BFD_SRCPORTMAX 65536
+#define BFD_DEFDESTPORT 3784
+#define BFD_DEF_ECHO_PORT 3785
+#define BFD_DEF_MHOP_DEST_PORT 4784
+#define BFD_CMD_STRING_LEN (MAXNAMELEN + 50)
+#define BFD_BUFFER_LEN (BFD_CMD_STRING_LEN + MAXNAMELEN + 1)
+
+/*
+ * control.c
+ *
+ * Daemon control code to speak with local consumers.
+ */
+
+/* See 'bfdctrl.h' for client protocol definitions. */
+
+struct bfd_control_buffer {
+ size_t bcb_left;
+ size_t bcb_pos;
+ union {
+ struct bfd_control_msg *bcb_bcm;
+ uint8_t *bcb_buf;
+ };
+};
+
+struct bfd_control_queue {
+ TAILQ_ENTRY(bfd_control_queue) bcq_entry;
+
+ struct bfd_control_buffer bcq_bcb;
+};
+TAILQ_HEAD(bcqueue, bfd_control_queue);
+
+struct bfd_notify_peer {
+ TAILQ_ENTRY(bfd_notify_peer) bnp_entry;
+
+ struct bfd_session *bnp_bs;
+};
+TAILQ_HEAD(bnplist, bfd_notify_peer);
+
+struct bfd_control_socket {
+ TAILQ_ENTRY(bfd_control_socket) bcs_entry;
+
+ int bcs_sd;
+ struct thread *bcs_ev;
+ struct thread *bcs_outev;
+ struct bcqueue bcs_bcqueue;
+
+ /* Notification data */
+ uint64_t bcs_notify;
+ struct bnplist bcs_bnplist;
+
+ enum bc_msg_version bcs_version;
+ enum bc_msg_type bcs_type;
+
+ /* Message buffering */
+ struct bfd_control_buffer bcs_bin;
+ struct bfd_control_buffer *bcs_bout;
+};
+TAILQ_HEAD(bcslist, bfd_control_socket);
+
+int control_init(const char *path);
+void control_shutdown(void);
+int control_notify(struct bfd_session *bs);
+int control_notify_config(const char *op, struct bfd_session *bs);
+int control_accept(struct thread *t);
+
+
+/*
+ * bfdd.c
+ *
+ * Daemon specific code.
+ */
+struct bfd_global {
+ int bg_shop;
+ int bg_mhop;
+ int bg_shop6;
+ int bg_mhop6;
+ int bg_echo;
+ int bg_vxlan;
+ struct thread *bg_ev[6];
+
+ int bg_csock;
+ struct thread *bg_csockev;
+ struct bcslist bg_bcslist;
+
+ struct pllist bg_pllist;
+};
+extern struct bfd_global bglobal;
+extern struct bfd_diag_str_list diag_list[];
+extern struct bfd_state_str_list state_list[];
+
+void socket_close(int *s);
+
+
+/*
+ * config.c
+ *
+ * Contains the code related with loading/reloading configuration.
+ */
+int parse_config(const char *fname);
+int config_request_add(const char *jsonstr);
+int config_request_del(const char *jsonstr);
+char *config_response(const char *status, const char *error);
+char *config_notify(struct bfd_session *bs);
+char *config_notify_config(const char *op, struct bfd_session *bs);
+
+typedef int (*bpc_handle)(struct bfd_peer_cfg *, void *arg);
+int config_notify_request(struct bfd_control_socket *bcs, const char *jsonstr,
+ bpc_handle bh);
+
+struct peer_label *pl_new(const char *label, struct bfd_session *bs);
+struct peer_label *pl_find(const char *label);
+void pl_free(struct peer_label *pl);
+
+
+/*
+ * log.c
+ *
+ * Contains code that does the logging procedures. Might implement multiple
+ * backends (e.g. zebra log, syslog or other logging lib).
+ */
+enum blog_level {
+ /* level vs syslog equivalent */
+ BLOG_DEBUG = 0, /* LOG_DEBUG */
+ BLOG_INFO = 1, /* LOG_INFO */
+ BLOG_WARNING = 2, /* LOG_WARNING */
+ BLOG_ERROR = 3, /* LOG_ERR */
+ BLOG_FATAL = 4, /* LOG_CRIT */
+};
+
+void log_init(int foreground, enum blog_level level,
+ struct frr_daemon_info *fdi);
+void log_info(const char *fmt, ...);
+void log_debug(const char *fmt, ...);
+void log_warning(const char *fmt, ...);
+void log_error(const char *fmt, ...);
+void log_fatal(const char *fmt, ...);
+
+
+/*
+ * bfd_packet.c
+ *
+ * Contains the code related with receiving/seding, packing/unpacking BFD data.
+ */
+int bp_set_ttlv6(int sd);
+int bp_set_ttl(int sd);
+int bp_set_tosv6(int sd);
+int bp_set_tos(int sd);
+int bp_bind_dev(int sd, const char *dev);
+
+int bp_udp_shop(void);
+int bp_udp_mhop(void);
+int bp_udp6_shop(void);
+int bp_udp6_mhop(void);
+int bp_peer_socket(struct bfd_peer_cfg *bpc);
+int bp_peer_socketv6(struct bfd_peer_cfg *bpc);
+
+void ptm_bfd_snd(struct bfd_session *bfd, int fbit);
+void ptm_bfd_echo_snd(struct bfd_session *bfd);
+
+int bfd_recv_cb(struct thread *t);
+
+uint16_t checksum(uint16_t *buf, int len);
+
+
+/*
+ * event.c
+ *
+ * Contains the code related with event loop.
+ */
+typedef void (*bfd_ev_cb)(struct thread *t);
+
+void bfd_recvtimer_update(struct bfd_session *bs);
+void bfd_echo_recvtimer_update(struct bfd_session *bs);
+void bfd_xmttimer_update(struct bfd_session *bs, uint64_t jitter);
+void bfd_echo_xmttimer_update(struct bfd_session *bs, uint64_t jitter);
+
+void bfd_xmttimer_delete(struct bfd_session *bs);
+void bfd_echo_xmttimer_delete(struct bfd_session *bs);
+void bfd_recvtimer_delete(struct bfd_session *bs);
+void bfd_echo_recvtimer_delete(struct bfd_session *bs);
+
+void bfd_recvtimer_assign(struct bfd_session *bs, bfd_ev_cb cb, int sd);
+void bfd_echo_recvtimer_assign(struct bfd_session *bs, bfd_ev_cb cb, int sd);
+void bfd_xmttimer_assign(struct bfd_session *bs, bfd_ev_cb cb);
+void bfd_echo_xmttimer_assign(struct bfd_session *bs, bfd_ev_cb cb);
+
+
+/*
+ * bfd.c
+ *
+ * BFD protocol specific code.
+ */
+struct bfd_session *ptm_bfd_sess_new(struct bfd_peer_cfg *bpc);
+int ptm_bfd_ses_del(struct bfd_peer_cfg *bpc);
+void ptm_bfd_ses_dn(struct bfd_session *bfd, uint8_t diag);
+void ptm_bfd_ses_up(struct bfd_session *bfd);
+void fetch_portname_from_ifindex(int ifindex, char *ifname, size_t ifnamelen);
+void ptm_bfd_echo_stop(struct bfd_session *bfd, int polling);
+void ptm_bfd_echo_start(struct bfd_session *bfd);
+void ptm_bfd_xmt_TO(struct bfd_session *bfd, int fbit);
+void ptm_bfd_start_xmt_timer(struct bfd_session *bfd, bool is_echo);
+struct bfd_session *ptm_bfd_sess_find(struct bfd_pkt *cp, char *port_name,
+ struct sockaddr_any *peer,
+ struct sockaddr_any *local,
+ char *vrf_name, bool is_mhop);
+
+struct bfd_session *bs_peer_find(struct bfd_peer_cfg *bpc);
+int bfd_session_update_label(struct bfd_session *bs, const char *nlabel);
+void bfd_set_polling(struct bfd_session *bs);
+const char *satostr(struct sockaddr_any *sa);
+const char *diag2str(uint8_t diag);
+int strtosa(const char *addr, struct sockaddr_any *sa);
+void integer2timestr(uint64_t time, char *buf, size_t buflen);
+const char *bs_to_string(struct bfd_session *bs);
+
+/* BFD hash data structures interface */
+void bfd_initialize(void);
+void bfd_shutdown(void);
+struct bfd_session *bfd_id_lookup(uint32_t id);
+struct bfd_session *bfd_shop_lookup(struct bfd_shop_key shop);
+struct bfd_session *bfd_mhop_lookup(struct bfd_mhop_key mhop);
+struct bfd_vrf *bfd_vrf_lookup(int vrf_id);
+struct bfd_iface *bfd_iface_lookup(const char *ifname);
+
+struct bfd_session *bfd_id_delete(uint32_t id);
+struct bfd_session *bfd_shop_delete(struct bfd_shop_key shop);
+struct bfd_session *bfd_mhop_delete(struct bfd_mhop_key mhop);
+struct bfd_vrf *bfd_vrf_delete(int vrf_id);
+struct bfd_iface *bfd_iface_delete(const char *ifname);
+
+bool bfd_id_insert(struct bfd_session *bs);
+bool bfd_shop_insert(struct bfd_session *bs);
+bool bfd_mhop_insert(struct bfd_session *bs);
+bool bfd_vrf_insert(struct bfd_vrf *vrf);
+bool bfd_iface_insert(struct bfd_iface *iface);
+
+typedef void (*hash_iter_func)(struct hash_backet *hb, void *arg);
+void bfd_id_iterate(hash_iter_func hif, void *arg);
+void bfd_shop_iterate(hash_iter_func hif, void *arg);
+void bfd_mhop_iterate(hash_iter_func hif, void *arg);
+void bfd_vrf_iterate(hash_iter_func hif, void *arg);
+void bfd_iface_iterate(hash_iter_func hif, void *arg);
+
+/* Export callback functions for `event.c`. */
+extern struct thread_master *master;
+
+int bfd_recvtimer_cb(struct thread *t);
+int bfd_echo_recvtimer_cb(struct thread *t);
+int bfd_xmt_cb(struct thread *t);
+int bfd_echo_xmt_cb(struct thread *t);
+
+
+/*
+ * bfdd_vty.c
+ *
+ * BFD daemon vty shell commands.
+ */
+void bfdd_vty_init(void);
+
+
+/*
+ * ptm_adapter.c
+ */
+void bfdd_zclient_init(struct zebra_privs_t *bfdd_priv);
+void bfdd_zclient_stop(void);
+
+int ptm_bfd_notify(struct bfd_session *bs);
+
+
+/*
+ * OS compatibility functions.
+ */
+struct udp_psuedo_header {
+ uint32_t saddr;
+ uint32_t daddr;
+ uint8_t reserved;
+ uint8_t protocol;
+ uint16_t len;
+};
+
+#define UDP_PSUEDO_HDR_LEN sizeof(struct udp_psuedo_header)
+
+#if defined(BFD_LINUX) || defined(BFD_BSD)
+int ptm_bfd_fetch_ifindex(const char *ifname);
+void ptm_bfd_fetch_local_mac(const char *ifname, uint8_t *mac);
+void fetch_portname_from_ifindex(int ifindex, char *ifname, size_t ifnamelen);
+int ptm_bfd_echo_sock_init(void);
+int ptm_bfd_vxlan_sock_init(void);
+#endif /* BFD_LINUX || BFD_BSD */
+
+#ifdef BFD_LINUX
+uint16_t udp4_checksum(struct iphdr *iph, uint8_t *buf, int len);
+#endif /* BFD_LINUX */
+
+#ifdef BFD_BSD
+uint16_t udp4_checksum(struct ip *ip, uint8_t *buf, int len);
+ssize_t bsd_echo_sock_read(int sd, uint8_t *buf, ssize_t *buflen,
+ struct sockaddr_storage *ss, socklen_t *sslen,
+ uint8_t *ttl, uint32_t *id);
+#endif /* BFD_BSD */
+
+#endif /* _BFD_H_ */
diff --git a/bfdd/bfd_packet.c b/bfdd/bfd_packet.c
new file mode 100644
index 0000000000..8d74c5c234
--- /dev/null
+++ b/bfdd/bfd_packet.c
@@ -0,0 +1,1555 @@
+/*********************************************************************
+ * Copyright 2017 Cumulus Networks, Inc. All rights reserved.
+ *
+ * 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
+ *
+ * bfd_packet.c: implements the BFD protocol packet handling.
+ *
+ * Authors
+ * -------
+ * Shrijeet Mukherjee [shm@cumulusnetworks.com]
+ * Kanna Rajagopal [kanna@cumulusnetworks.com]
+ * Radhika Mahankali [Radhika@cumulusnetworks.com]
+ */
+
+#include <zebra.h>
+
+#ifdef BFD_LINUX
+#include <linux/if_packet.h>
+#endif /* BFD_LINUX */
+
+#include <netinet/if_ether.h>
+#include <netinet/udp.h>
+
+#include "lib/sockopt.h"
+
+#include "bfd.h"
+
+/*
+ * Definitions
+ */
+
+/* iov for BFD control frames */
+#define CMSG_HDR_LEN sizeof(struct cmsghdr)
+#define CMSG_TTL_LEN (CMSG_HDR_LEN + sizeof(uint32_t))
+#define CMSG_IN_PKT_INFO_LEN (CMSG_HDR_LEN + sizeof(struct in_pktinfo) + 4)
+#define CMSG_IN6_PKT_INFO_LEN \
+ (CMSG_HDR_LEN + sizeof(struct in6_addr) + sizeof(int) + 4)
+
+struct bfd_raw_echo_pkt {
+#ifdef BFD_LINUX
+ struct iphdr ip;
+#endif /* BFD_LINUX */
+#ifdef BFD_BSD
+ struct ip ip;
+#endif /* BFD_BSD */
+ struct udphdr udp;
+ struct bfd_echo_pkt data;
+};
+
+#if 0 /* TODO: VxLAN support. */
+struct bfd_raw_ctrl_pkt {
+ struct iphdr ip;
+ struct udphdr udp;
+ struct bfd_pkt data;
+};
+#endif
+
+struct vxlan_hdr {
+ uint32_t flags;
+ uint32_t vnid;
+};
+
+#define IP_ECHO_PKT_LEN (IP_HDR_LEN + UDP_HDR_LEN + BFD_ECHO_PKT_LEN)
+#define UDP_ECHO_PKT_LEN (UDP_HDR_LEN + BFD_ECHO_PKT_LEN)
+#define IP_CTRL_PKT_LEN (IP_HDR_LEN + UDP_HDR_LEN + BFD_PKT_LEN)
+#define UDP_CTRL_PKT_LEN (UDP_HDR_LEN + BFD_PKT_LEN)
+
+static uint8_t msgbuf[BFD_PKT_LEN];
+
+static int ttlval = BFD_TTL_VAL;
+static int tosval = BFD_TOS_VAL;
+static int rcvttl = BFD_RCV_TTL_VAL;
+
+/*
+ * Prototypes
+ */
+static uint16_t ptm_bfd_gen_IP_ID(struct bfd_session *bfd);
+static void ptm_bfd_echo_pkt_create(struct bfd_session *bfd);
+static int ptm_bfd_echo_loopback(uint8_t *pkt, int pkt_len, struct sockaddr *ss,
+ socklen_t sslen);
+static void ptm_bfd_vxlan_pkt_snd(struct bfd_session *bfd, int fbit);
+static int ptm_bfd_process_echo_pkt(int s);
+static bool
+ptm_bfd_validate_vxlan_pkt(struct bfd_session *bfd,
+ struct bfd_session_vxlan_info *vxlan_info);
+
+static void bfd_sd_reschedule(int sd);
+static ssize_t bfd_recv_ipv4(int sd, bool is_mhop, char *port, size_t portlen,
+ char *vrfname, size_t vrfnamelen,
+ struct sockaddr_any *local,
+ struct sockaddr_any *peer);
+static ssize_t bfd_recv_ipv6(int sd, bool is_mhop, char *port, size_t portlen,
+ char *vrfname, size_t vrfnamelen,
+ struct sockaddr_any *local,
+ struct sockaddr_any *peer);
+
+/* socket related prototypes */
+static void bp_set_ipopts(int sd);
+static void bp_bind_ip(int sd, uint16_t port);
+static void bp_set_ipv6opts(int sd);
+static void bp_bind_ipv6(int sd, uint16_t port);
+
+
+/*
+ * Functions
+ */
+uint16_t checksum(uint16_t *buf, int len)
+{
+ int nbytes = len;
+ int sum = 0;
+ uint16_t csum = 0;
+ int size = sizeof(uint16_t);
+
+ while (nbytes > 1) {
+ sum += *buf++;
+ nbytes -= size;
+ }
+
+ if (nbytes == 1) {
+ *(uint8_t *)(&csum) = *(uint8_t *)buf;
+ sum += csum;
+ }
+
+ sum = (sum >> 16) + (sum & 0xFFFF);
+ sum += (sum >> 16);
+ csum = ~sum;
+ return csum;
+}
+
+static uint16_t ptm_bfd_gen_IP_ID(struct bfd_session *bfd)
+{
+ return (++bfd->ip_id);
+}
+
+static int _ptm_bfd_send(struct bfd_session *bs, bool use_layer2,
+ uint16_t *port, const void *data, size_t datalen)
+{
+ struct sockaddr *sa;
+ struct sockaddr_in sin;
+ struct sockaddr_in6 sin6;
+#ifdef BFD_LINUX
+ struct sockaddr_ll dll;
+#endif /* BFD_LINUX */
+ socklen_t slen;
+ ssize_t rv;
+ int sd = -1;
+
+ if (use_layer2) {
+#ifdef BFD_LINUX
+ memset(&dll, 0, sizeof(dll));
+ dll.sll_family = AF_PACKET;
+ dll.sll_protocol = htons(ETH_P_IP);
+ memcpy(dll.sll_addr, bs->peer_mac, ETHERNET_ADDRESS_LENGTH);
+ dll.sll_halen = htons(ETHERNET_ADDRESS_LENGTH);
+ dll.sll_ifindex = bs->ifindex;
+
+ sd = bglobal.bg_echo;
+ sa = (struct sockaddr *)&dll;
+ slen = sizeof(dll);
+#else
+ /*
+ * TODO: implement layer 2 send for *BSDs. This is
+ * needed for VxLAN.
+ */
+ log_warning("packet-send: not implemented");
+ return -1;
+#endif
+ } else if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_IPV6)) {
+ memset(&sin6, 0, sizeof(sin6));
+ sin6.sin6_family = AF_INET6;
+ sin6.sin6_addr = bs->shop.peer.sa_sin6.sin6_addr;
+ sin6.sin6_port =
+ (port) ? *port
+ : (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH))
+ ? htons(BFD_DEF_MHOP_DEST_PORT)
+ : htons(BFD_DEFDESTPORT);
+
+ sd = bs->sock;
+ sa = (struct sockaddr *)&sin6;
+ slen = sizeof(sin6);
+ } else {
+ memset(&sin, 0, sizeof(sin));
+ sin.sin_family = AF_INET;
+ sin.sin_addr = bs->shop.peer.sa_sin.sin_addr;
+ sin.sin_port =
+ (port) ? *port
+ : (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH))
+ ? htons(BFD_DEF_MHOP_DEST_PORT)
+ : htons(BFD_DEFDESTPORT);
+
+ sd = bs->sock;
+ sa = (struct sockaddr *)&sin;
+ slen = sizeof(sin);
+ }
+
+#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
+ sa->sa_len = slen;
+#endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */
+ rv = sendto(sd, data, datalen, 0, sa, slen);
+ if (rv <= 0) {
+ log_debug("packet-send: send failure: %s", strerror(errno));
+ return -1;
+ }
+ if (rv < (ssize_t)datalen)
+ log_debug("packet-send: send partial", strerror(errno));
+
+ return 0;
+}
+
+static void ptm_bfd_echo_pkt_create(struct bfd_session *bfd)
+{
+ struct bfd_raw_echo_pkt ep;
+ uint8_t *pkt = bfd->echo_pkt;
+
+ memset(&ep, 0, sizeof(ep));
+ memset(bfd->echo_pkt, 0, sizeof(bfd->echo_pkt));
+
+ /* Construct ethernet header information */
+ memcpy(pkt, bfd->peer_mac, ETHERNET_ADDRESS_LENGTH);
+ pkt = pkt + ETHERNET_ADDRESS_LENGTH;
+ memcpy(pkt, bfd->local_mac, ETHERNET_ADDRESS_LENGTH);
+ pkt = pkt + ETHERNET_ADDRESS_LENGTH;
+#ifdef BFD_LINUX
+ pkt[0] = ETH_P_IP / 256;
+ pkt[1] = ETH_P_IP % 256;
+#endif /* BFD_LINUX */
+#ifdef BFD_BSD
+ pkt[0] = ETHERTYPE_IP / 256;
+ pkt[1] = ETHERTYPE_IP % 256;
+#endif /* BFD_BSD */
+ pkt += 2;
+
+ /* Construct IP header information */
+#ifdef BFD_LINUX
+ ep.ip.version = 4;
+ ep.ip.ihl = 5;
+ ep.ip.tos = 0;
+ ep.ip.tot_len = htons(IP_ECHO_PKT_LEN);
+ ep.ip.id = htons(ptm_bfd_gen_IP_ID(bfd));
+ ep.ip.frag_off = 0;
+ ep.ip.ttl = BFD_TTL_VAL;
+ ep.ip.protocol = IPPROTO_UDP;
+ ep.ip.saddr = bfd->local_ip.sa_sin.sin_addr.s_addr;
+ ep.ip.daddr = bfd->shop.peer.sa_sin.sin_addr.s_addr;
+ ep.ip.check = checksum((uint16_t *)&ep.ip, IP_HDR_LEN);
+#endif /* BFD_LINUX */
+#ifdef BFD_BSD
+ ep.ip.ip_v = 4;
+ ep.ip.ip_hl = 5;
+ ep.ip.ip_tos = 0;
+ ep.ip.ip_len = htons(IP_ECHO_PKT_LEN);
+ ep.ip.ip_id = htons(ptm_bfd_gen_IP_ID(bfd));
+ ep.ip.ip_off = 0;
+ ep.ip.ip_ttl = BFD_TTL_VAL;
+ ep.ip.ip_p = IPPROTO_UDP;
+ ep.ip.ip_src = bfd->local_ip.sa_sin.sin_addr;
+ ep.ip.ip_dst = bfd->shop.peer.sa_sin.sin_addr;
+ ep.ip.ip_sum = checksum((uint16_t *)&ep.ip, IP_HDR_LEN);
+#endif /* BFD_BSD */
+
+ /* Construct UDP header information */
+#ifdef BFD_LINUX
+ ep.udp.source = htons(BFD_DEF_ECHO_PORT);
+ ep.udp.dest = htons(BFD_DEF_ECHO_PORT);
+ ep.udp.len = htons(UDP_ECHO_PKT_LEN);
+#endif /* BFD_LINUX */
+#ifdef BFD_BSD
+ ep.udp.uh_sport = htons(BFD_DEF_ECHO_PORT);
+ ep.udp.uh_dport = htons(BFD_DEF_ECHO_PORT);
+ ep.udp.uh_ulen = htons(UDP_ECHO_PKT_LEN);
+#endif /* BFD_BSD */
+
+ /* Construct Echo packet information */
+ ep.data.ver = BFD_ECHO_VERSION;
+ ep.data.len = BFD_ECHO_PKT_LEN;
+ ep.data.my_discr = htonl(bfd->discrs.my_discr);
+#ifdef BFD_LINUX
+ ep.udp.check =
+#endif /* BFD_LINUX */
+#ifdef BFD_BSD
+ ep.udp.uh_sum =
+#endif /* BFD_BSD */
+ udp4_checksum(&ep.ip, (uint8_t *)&ep.udp,
+ UDP_ECHO_PKT_LEN);
+
+ memcpy(pkt, &ep, sizeof(ep));
+}
+
+void ptm_bfd_echo_snd(struct bfd_session *bfd)
+{
+ struct bfd_raw_echo_pkt *ep;
+ bool use_layer2 = false;
+ const void *pkt;
+ size_t pktlen;
+ uint16_t port = htons(BFD_DEF_ECHO_PORT);
+
+ if (!BFD_CHECK_FLAG(bfd->flags, BFD_SESS_FLAG_ECHO_ACTIVE)) {
+ ptm_bfd_echo_pkt_create(bfd);
+ BFD_SET_FLAG(bfd->flags, BFD_SESS_FLAG_ECHO_ACTIVE);
+ } else {
+ /* just update the checksum and ip Id */
+ ep = (struct bfd_raw_echo_pkt *)(bfd->echo_pkt + ETH_HDR_LEN);
+#ifdef BFD_LINUX
+ ep->ip.id = htons(ptm_bfd_gen_IP_ID(bfd));
+ ep->ip.check = 0;
+ ep->ip.check = checksum((uint16_t *)&ep->ip, IP_HDR_LEN);
+#endif /* BFD_LINUX */
+#ifdef BFD_BSD
+ ep->ip.ip_id = htons(ptm_bfd_gen_IP_ID(bfd));
+ ep->ip.ip_sum = 0;
+ ep->ip.ip_sum = checksum((uint16_t *)&ep->ip, IP_HDR_LEN);
+#endif /* BFD_BSD */
+ }
+
+ if (use_layer2) {
+ pkt = bfd->echo_pkt;
+ pktlen = BFD_ECHO_PKT_TOT_LEN;
+ } else {
+ pkt = &bfd->echo_pkt[ETH_HDR_LEN + IP_HDR_LEN + UDP_HDR_LEN];
+ pktlen = BFD_ECHO_PKT_TOT_LEN
+ - (ETH_HDR_LEN + IP_HDR_LEN + UDP_HDR_LEN);
+ }
+
+ if (_ptm_bfd_send(bfd, use_layer2, &port, pkt, pktlen) != 0) {
+ log_debug("echo-packet: send failure: %s", strerror(errno));
+ return;
+ }
+
+ bfd->stats.tx_echo_pkt++;
+}
+
+static int ptm_bfd_echo_loopback(uint8_t *pkt, int pkt_len, struct sockaddr *ss,
+ socklen_t sslen)
+{
+#ifdef BFD_LINUX
+ struct bfd_raw_echo_pkt *ep =
+ (struct bfd_raw_echo_pkt *)(pkt + ETH_HDR_LEN);
+ uint8_t temp_mac[ETHERNET_ADDRESS_LENGTH];
+ uint32_t temp_ip;
+ struct ethhdr *eth = (struct ethhdr *)pkt;
+
+ /* swap the mac addresses */
+ memcpy(temp_mac, eth->h_source, ETHERNET_ADDRESS_LENGTH);
+ memcpy(eth->h_source, eth->h_dest, ETHERNET_ADDRESS_LENGTH);
+ memcpy(eth->h_dest, temp_mac, ETHERNET_ADDRESS_LENGTH);
+
+ /* swap ip addresses */
+ temp_ip = ep->ip.saddr;
+ ep->ip.saddr = ep->ip.daddr;
+ ep->ip.daddr = temp_ip;
+
+ ep->ip.ttl = ep->ip.ttl - 1;
+ ep->ip.check = 0;
+ ep->ip.check = checksum((uint16_t *)ep, IP_HDR_LEN);
+#endif /* BFD_LINUX */
+#ifdef BFD_BSD_FILTER
+ struct bfd_raw_echo_pkt_t *ep =
+ (struct bfd_raw_echo_pkt *)(pkt + ETH_HDR_LEN);
+ uint8_t temp_mac[ETHERNET_ADDRESS_LENGTH];
+ struct in_addr temp_ip;
+ struct ether_header *ether = (struct ether_header *)pkt;
+
+ /*
+ * TODO: this is not yet implemented and requires BPF code for
+ * OmniOS, NetBSD and FreeBSD9.
+ */
+
+ /* swap the mac addresses */
+ memcpy(temp_mac, ether->ether_shost, ETHERNET_ADDRESS_LENGTH);
+ memcpy(ether->ether_shost, ether->ether_dhost, ETHERNET_ADDRESS_LENGTH);
+ memcpy(ether->ether_dhost, temp_mac, ETHERNET_ADDRESS_LENGTH);
+
+ /* swap ip addresses */
+ temp_ip = ep->ip.ip_src;
+ ep->ip.ip_src = ep->ip.ip_dst;
+ ep->ip.ip_dst = temp_ip;
+
+ ep->ip.ip_ttl = ep->ip.ip_ttl - 1;
+ ep->ip.ip_sum = 0;
+ ep->ip.ip_sum = checksum((uint16_t *)ep, IP_HDR_LEN);
+#endif /* BFD_BSD_FILTER */
+
+ if (sendto(bglobal.bg_echo, pkt, pkt_len, 0, ss, sslen) < 0) {
+ log_debug("echo-loopback: send failure: %s", strerror(errno));
+ return -1;
+ }
+
+ return 0;
+}
+
+static void ptm_bfd_vxlan_pkt_snd(struct bfd_session *bfd
+ __attribute__((__unused__)),
+ int fbit __attribute__((__unused__)))
+{
+#if 0 /* TODO: VxLAN support. */
+ struct bfd_raw_ctrl_pkt cp;
+ uint8_t vxlan_pkt[BFD_VXLAN_PKT_TOT_LEN];
+ uint8_t *pkt = vxlan_pkt;
+ struct sockaddr_in sin;
+ struct vxlan_hdr *vhdr;
+
+ memset(vxlan_pkt, 0, sizeof(vxlan_pkt));
+ memset(&cp, 0, sizeof(cp));
+
+ /* Construct VxLAN header information */
+ vhdr = (struct vxlan_hdr *)pkt;
+ vhdr->flags = htonl(0x08000000);
+ vhdr->vnid = htonl(bfd->vxlan_info.vnid << 8);
+ pkt += VXLAN_HDR_LEN;
+
+ /* Construct ethernet header information */
+ memcpy(pkt, bfd->vxlan_info.peer_dst_mac, ETHERNET_ADDRESS_LENGTH);
+ pkt = pkt + ETHERNET_ADDRESS_LENGTH;
+ memcpy(pkt, bfd->vxlan_info.local_dst_mac, ETHERNET_ADDRESS_LENGTH);
+ pkt = pkt + ETHERNET_ADDRESS_LENGTH;
+ pkt[0] = ETH_P_IP / 256;
+ pkt[1] = ETH_P_IP % 256;
+ pkt += 2;
+
+ /* Construct IP header information */
+ cp.ip.version = 4;
+ cp.ip.ihl = 5;
+ cp.ip.tos = 0;
+ cp.ip.tot_len = htons(IP_CTRL_PKT_LEN);
+ cp.ip.id = ptm_bfd_gen_IP_ID(bfd);
+ cp.ip.frag_off = 0;
+ cp.ip.ttl = BFD_TTL_VAL;
+ cp.ip.protocol = IPPROTO_UDP;
+ cp.ip.daddr = bfd->vxlan_info.peer_dst_ip.s_addr;
+ cp.ip.saddr = bfd->vxlan_info.local_dst_ip.s_addr;
+ cp.ip.check = checksum((uint16_t *)&cp.ip, IP_HDR_LEN);
+
+ /* Construct UDP header information */
+ cp.udp.source = htons(BFD_DEFDESTPORT);
+ cp.udp.dest = htons(BFD_DEFDESTPORT);
+ cp.udp.len = htons(UDP_CTRL_PKT_LEN);
+
+ /* Construct BFD control packet information */
+ cp.data.diag = bfd->local_diag;
+ BFD_SETVER(cp.data.diag, BFD_VERSION);
+ BFD_SETSTATE(cp.data.flags, bfd->ses_state);
+ BFD_SETDEMANDBIT(cp.data.flags, BFD_DEF_DEMAND);
+ BFD_SETPBIT(cp.data.flags, bfd->polling);
+ BFD_SETFBIT(cp.data.flags, fbit);
+ cp.data.detect_mult = bfd->detect_mult;
+ cp.data.len = BFD_PKT_LEN;
+ cp.data.discrs.my_discr = htonl(bfd->discrs.my_discr);
+ cp.data.discrs.remote_discr = htonl(bfd->discrs.remote_discr);
+ cp.data.timers.desired_min_tx = htonl(bfd->timers.desired_min_tx);
+ cp.data.timers.required_min_rx = htonl(bfd->timers.required_min_rx);
+ cp.data.timers.required_min_echo = htonl(bfd->timers.required_min_echo);
+
+ cp.udp.check =
+ udp4_checksum(&cp.ip, (uint8_t *)&cp.udp, UDP_CTRL_PKT_LEN);
+
+ memcpy(pkt, &cp, sizeof(cp));
+ sin.sin_family = AF_INET;
+ sin.sin_addr = bfd->shop.peer.sa_sin.sin_addr;
+ sin.sin_port = htons(4789);
+
+ if (sendto(bfd->sock, vxlan_pkt, BFD_VXLAN_PKT_TOT_LEN, 0,
+ (struct sockaddr *)&sin, sizeof(struct sockaddr_in))
+ < 0) {
+ ERRLOG("Error sending vxlan bfd pkt: %s", strerror(errno));
+ } else {
+ bfd->stats.tx_ctrl_pkt++;
+ }
+#endif
+}
+
+static int ptm_bfd_process_echo_pkt(int s)
+{
+ uint32_t my_discr = 0;
+ struct sockaddr_storage ss;
+ socklen_t sslen = sizeof(ss);
+ uint8_t rx_pkt[BFD_RX_BUF_LEN];
+ ssize_t pkt_len = sizeof(rx_pkt);
+ struct bfd_session *bfd;
+#ifdef BFD_LINUX
+ struct bfd_raw_echo_pkt *ep;
+
+ /*
+ * valgrind: memset() ss so valgrind doesn't complain about
+ * uninitialized memory.
+ */
+ memset(&ss, 0, sizeof(ss));
+ pkt_len = recvfrom(s, rx_pkt, sizeof(rx_pkt), MSG_DONTWAIT,
+ (struct sockaddr *)&ss, &sslen);
+ if (pkt_len <= 0) {
+ if (errno != EAGAIN)
+ log_error("echo-packet: read failure: %s",
+ strerror(errno));
+
+ return -1;
+ }
+
+ /* Check if we have at least the basic headers to send back. */
+ if (pkt_len < BFD_ECHO_PKT_TOT_LEN) {
+ log_debug("echo-packet: too short (got %ld, expected %d)",
+ pkt_len, BFD_ECHO_PKT_TOT_LEN);
+ return -1;
+ }
+
+ ep = (struct bfd_raw_echo_pkt *)(rx_pkt + ETH_HDR_LEN);
+ /* if TTL = 255, assume that the received echo packet has
+ * to be looped back
+ */
+ if (ep->ip.ttl == BFD_TTL_VAL)
+ return ptm_bfd_echo_loopback(rx_pkt, pkt_len,
+ (struct sockaddr *)&ss,
+ sizeof(struct sockaddr_ll));
+
+ my_discr = ntohl(ep->data.my_discr);
+ if (ep->data.my_discr == 0) {
+ log_debug("echo-packet: 'my discriminator' is zero");
+ return -1;
+ }
+#endif /* BFD_LINUX */
+#ifdef BFD_BSD
+ int rv;
+ uint8_t ttl;
+
+ /*
+ * bsd_echo_sock_read() already treats invalid TTL values and
+ * zeroed discriminators.
+ */
+ rv = bsd_echo_sock_read(s, rx_pkt, &pkt_len, &ss, &sslen, &ttl,
+ &my_discr);
+ if (rv == -1)
+ return -1;
+
+ if (ttl == BFD_TTL_VAL)
+ return ptm_bfd_echo_loopback(rx_pkt, pkt_len,
+ (struct sockaddr *)&ss, sslen);
+#endif /* BFD_BSD */
+
+ /* Your discriminator not zero - use it to find session */
+ bfd = bfd_id_lookup(my_discr);
+ if (bfd == NULL) {
+ log_debug("echo-packet: no matching session (id:%u)", my_discr);
+ return -1;
+ }
+
+ if (!BFD_CHECK_FLAG(bfd->flags, BFD_SESS_FLAG_ECHO_ACTIVE)) {
+ log_debug("echo-packet: echo disabled [%s]", my_discr,
+ bs_to_string(bfd));
+ return -1;
+ }
+
+ bfd->stats.rx_echo_pkt++;
+
+ /* Compute detect time */
+ bfd->echo_detect_TO = bfd->remote_detect_mult * bfd->echo_xmt_TO;
+
+ /* Update echo receive timeout. */
+ bfd_echo_recvtimer_update(bfd);
+
+ return 0;
+}
+
+void ptm_bfd_snd(struct bfd_session *bfd, int fbit)
+{
+ struct bfd_pkt cp;
+
+ /* if the BFD session is for VxLAN tunnel, then construct and
+ * send bfd raw packet
+ */
+ if (BFD_CHECK_FLAG(bfd->flags, BFD_SESS_FLAG_VXLAN)) {
+ ptm_bfd_vxlan_pkt_snd(bfd, fbit);
+ return;
+ }
+
+ /* Set fields according to section 6.5.7 */
+ cp.diag = bfd->local_diag;
+ BFD_SETVER(cp.diag, BFD_VERSION);
+ cp.flags = 0;
+ BFD_SETSTATE(cp.flags, bfd->ses_state);
+ BFD_SETDEMANDBIT(cp.flags, BFD_DEF_DEMAND);
+ BFD_SETPBIT(cp.flags, bfd->polling);
+ BFD_SETFBIT(cp.flags, fbit);
+ cp.detect_mult = bfd->detect_mult;
+ cp.len = BFD_PKT_LEN;
+ cp.discrs.my_discr = htonl(bfd->discrs.my_discr);
+ cp.discrs.remote_discr = htonl(bfd->discrs.remote_discr);
+ if (bfd->polling) {
+ cp.timers.desired_min_tx =
+ htonl(bfd->new_timers.desired_min_tx);
+ cp.timers.required_min_rx =
+ htonl(bfd->new_timers.required_min_rx);
+ } else {
+ cp.timers.desired_min_tx = htonl(bfd->timers.desired_min_tx);
+ cp.timers.required_min_rx = htonl(bfd->timers.required_min_rx);
+ }
+ cp.timers.required_min_echo = htonl(bfd->timers.required_min_echo);
+
+ if (_ptm_bfd_send(bfd, false, NULL, &cp, BFD_PKT_LEN) != 0)
+ return;
+
+ bfd->stats.tx_ctrl_pkt++;
+}
+
+#if 0 /* TODO VxLAN Support */
+static struct bfd_pkt *
+ptm_bfd_process_vxlan_pkt(int s, ptm_sockevent_e se, void *udata, int *ifindex,
+ struct sockaddr_in *sin,
+ struct bfd_session_vxlan_info_t *vxlan_info,
+ uint8_t *rx_pkt, int *mlen)
+{
+ struct sockaddr_ll sll;
+ uint32_t from_len = sizeof(struct sockaddr_ll);
+ struct bfd_raw_ctrl_pkt *cp;
+ uint8_t *pkt = rx_pkt;
+ struct iphdr *iph;
+ struct ethhdr *inner_ethh;
+
+ *mlen = recvfrom(s, rx_pkt, BFD_RX_BUF_LEN, MSG_DONTWAIT,
+ (struct sockaddr *)&sll, &from_len);
+
+ if (*mlen < 0) {
+ if (errno != EAGAIN)
+ ERRLOG("Error receiving from BFD Vxlan socket %d: %m",
+ s);
+ return NULL;
+ }
+
+ iph = (struct iphdr *)(pkt + ETH_HDR_LEN);
+ pkt = pkt + ETH_HDR_LEN + IP_HDR_LEN + UDP_HDR_LEN;
+ vxlan_info->vnid = ntohl(*((int *)(pkt + 4)));
+ vxlan_info->vnid = vxlan_info->vnid >> 8;
+
+ pkt = pkt + VXLAN_HDR_LEN;
+ inner_ethh = (struct ethhdr *)pkt;
+
+ cp = (struct bfd_raw_ctrl_pkt *)(pkt + ETH_HDR_LEN);
+
+ /* Discard the non BFD packets */
+ if (ntohs(cp->udp.dest) != BFD_DEFDESTPORT)
+ return NULL;
+
+ *ifindex = sll.sll_ifindex;
+ sin->sin_addr.s_addr = iph->saddr;
+ sin->sin_port = ntohs(cp->udp.dest);
+
+ vxlan_info->local_dst_ip.s_addr = cp->ip.daddr;
+ memcpy(vxlan_info->local_dst_mac, inner_ethh->h_dest,
+ ETHERNET_ADDRESS_LENGTH);
+
+ return &cp->data;
+}
+#endif /* VxLAN */
+
+static bool
+ptm_bfd_validate_vxlan_pkt(struct bfd_session *bfd,
+ struct bfd_session_vxlan_info *vxlan_info)
+{
+ if (bfd->vxlan_info.check_tnl_key && (vxlan_info->vnid != 0)) {
+ log_error("vxlan-packet: vnid not zero: %d", vxlan_info->vnid);
+ return false;
+ }
+
+ if (bfd->vxlan_info.local_dst_ip.s_addr
+ != vxlan_info->local_dst_ip.s_addr) {
+ log_error("vxlan-packet: wrong inner destination",
+ inet_ntoa(vxlan_info->local_dst_ip));
+ return false;
+ }
+
+ if (memcmp(bfd->vxlan_info.local_dst_mac, vxlan_info->local_dst_mac,
+ ETHERNET_ADDRESS_LENGTH)) {
+ log_error(
+ "vxlan-packet: wrong inner mac: %02x:%02x:%02x:%02x:%02x:%02x",
+ vxlan_info->local_dst_mac[0],
+ vxlan_info->local_dst_mac[1],
+ vxlan_info->local_dst_mac[2],
+ vxlan_info->local_dst_mac[3],
+ vxlan_info->local_dst_mac[4],
+ vxlan_info->local_dst_mac[5]);
+ return false;
+ }
+
+ return true;
+}
+
+static ssize_t bfd_recv_ipv4(int sd, bool is_mhop, char *port, size_t portlen,
+ char *vrfname, size_t vrfnamelen,
+ struct sockaddr_any *local,
+ struct sockaddr_any *peer)
+{
+ struct cmsghdr *cm;
+ int ifindex;
+ ssize_t mlen;
+ struct sockaddr_in msgaddr;
+ struct msghdr msghdr;
+ struct iovec iov[1];
+ uint8_t cmsgbuf[255];
+
+ /* Prepare the recvmsg params. */
+ iov[0].iov_base = msgbuf;
+ iov[0].iov_len = sizeof(msgbuf);
+
+ memset(&msghdr, 0, sizeof(msghdr));
+ msghdr.msg_name = &msgaddr;
+ msghdr.msg_namelen = sizeof(msgaddr);
+ msghdr.msg_iov = iov;
+ msghdr.msg_iovlen = 1;
+ msghdr.msg_control = cmsgbuf;
+ msghdr.msg_controllen = sizeof(cmsgbuf);
+
+ /* Sanitize input/output. */
+ memset(port, 0, portlen);
+ memset(vrfname, 0, vrfnamelen);
+ memset(local, 0, sizeof(*local));
+ memset(peer, 0, sizeof(*peer));
+
+ mlen = recvmsg(sd, &msghdr, MSG_DONTWAIT);
+ if (mlen == -1) {
+ if (errno != EAGAIN)
+ log_error("ipv4-recv: recv failed: %s",
+ strerror(errno));
+
+ return -1;
+ }
+
+ /* Get source address */
+ peer->sa_sin = *((struct sockaddr_in *)(msghdr.msg_name));
+
+ /* Get and check TTL */
+ for (cm = CMSG_FIRSTHDR(&msghdr); cm != NULL;
+ cm = CMSG_NXTHDR(&msghdr, cm)) {
+ if (cm->cmsg_level != IPPROTO_IP)
+ continue;
+
+ switch (cm->cmsg_type) {
+#ifdef BFD_LINUX
+ case IP_TTL: {
+ uint32_t ttl;
+
+ memcpy(&ttl, CMSG_DATA(cm), sizeof(ttl));
+ if ((is_mhop == false) && (ttl != BFD_TTL_VAL)) {
+ log_debug(
+ "ipv4-recv: invalid TTL from %s (expected %d, got %d flags %d)",
+ satostr(peer), ttl, BFD_TTL_VAL,
+ msghdr.msg_flags);
+ return -1;
+ }
+ break;
+ }
+
+ case IP_PKTINFO: {
+ struct in_pktinfo *pi =
+ (struct in_pktinfo *)CMSG_DATA(cm);
+
+ if (pi == NULL)
+ break;
+
+ local->sa_sin.sin_family = AF_INET;
+ local->sa_sin.sin_addr = pi->ipi_addr;
+ fetch_portname_from_ifindex(pi->ipi_ifindex, port,
+ portlen);
+ break;
+ }
+#endif /* BFD_LINUX */
+#ifdef BFD_BSD
+ case IP_RECVTTL: {
+ uint8_t ttl;
+
+ memcpy(&ttl, CMSG_DATA(cm), sizeof(ttl));
+ if ((is_mhop == false) && (ttl != BFD_TTL_VAL)) {
+ log_debug(
+ "ipv4-recv: invalid TTL from %s (expected %d, got %d flags %d)",
+ satostr(peer), ttl, BFD_TTL_VAL,
+ msghdr.msg_flags);
+ return -1;
+ }
+ break;
+ }
+
+ case IP_RECVDSTADDR: {
+ struct in_addr ia;
+
+ memcpy(&ia, CMSG_DATA(cm), sizeof(ia));
+ local->sa_sin.sin_family = AF_INET;
+ local->sa_sin.sin_addr = ia;
+ break;
+ }
+#endif /* BFD_BSD */
+
+ default:
+ /*
+ * On *BSDs we expect to land here when skipping
+ * the IP_RECVIF header. It will be handled by
+ * getsockopt_ifindex() below.
+ */
+ /* NOTHING */
+ break;
+ }
+ }
+
+ /* OS agnostic way of getting interface name. */
+ if (port[0] == 0) {
+ ifindex = getsockopt_ifindex(AF_INET, &msghdr);
+ if (ifindex > 0)
+ fetch_portname_from_ifindex(ifindex, port, portlen);
+ }
+
+ return mlen;
+}
+
+ssize_t bfd_recv_ipv6(int sd, bool is_mhop, char *port, size_t portlen,
+ char *vrfname, size_t vrfnamelen,
+ struct sockaddr_any *local, struct sockaddr_any *peer)
+{
+ struct cmsghdr *cm;
+ struct in6_pktinfo *pi6 = NULL;
+ int ifindex = 0;
+ ssize_t mlen;
+ struct sockaddr_in6 msgaddr6;
+ struct msghdr msghdr6;
+ struct iovec iov[1];
+ uint8_t cmsgbuf6[255];
+
+ /* Prepare the recvmsg params. */
+ iov[0].iov_base = msgbuf;
+ iov[0].iov_len = sizeof(msgbuf);
+
+ memset(&msghdr6, 0, sizeof(msghdr6));
+ msghdr6.msg_name = &msgaddr6;
+ msghdr6.msg_namelen = sizeof(msgaddr6);
+ msghdr6.msg_iov = iov;
+ msghdr6.msg_iovlen = 1;
+ msghdr6.msg_control = cmsgbuf6;
+ msghdr6.msg_controllen = sizeof(cmsgbuf6);
+
+ /* Sanitize input/output. */
+ memset(port, 0, portlen);
+ memset(vrfname, 0, vrfnamelen);
+ memset(local, 0, sizeof(*local));
+ memset(peer, 0, sizeof(*peer));
+
+ mlen = recvmsg(sd, &msghdr6, MSG_DONTWAIT);
+ if (mlen == -1) {
+ if (errno != EAGAIN)
+ log_error("ipv4-recv: recv failed: %s",
+ strerror(errno));
+
+ return -1;
+ }
+
+ /* Get source address */
+ peer->sa_sin6 = *((struct sockaddr_in6 *)(msghdr6.msg_name));
+
+ /* Get and check TTL */
+ for (cm = CMSG_FIRSTHDR(&msghdr6); cm != NULL;
+ cm = CMSG_NXTHDR(&msghdr6, cm)) {
+ if (cm->cmsg_level != IPPROTO_IPV6)
+ continue;
+
+ if (cm->cmsg_type == IPV6_HOPLIMIT) {
+ memcpy(&ttlval, CMSG_DATA(cm), 4);
+ if ((is_mhop == false) && (ttlval != BFD_TTL_VAL)) {
+ log_debug(
+ "ipv6-recv: invalid TTL from %s (expected %d, got %d flags %d)",
+ satostr(peer), ttlval, BFD_TTL_VAL,
+ msghdr6.msg_flags);
+ return -1;
+ }
+ } else if (cm->cmsg_type == IPV6_PKTINFO) {
+ pi6 = (struct in6_pktinfo *)CMSG_DATA(cm);
+ if (pi6) {
+ local->sa_sin.sin_family = AF_INET6;
+ local->sa_sin6.sin6_addr = pi6->ipi6_addr;
+ fetch_portname_from_ifindex(pi6->ipi6_ifindex,
+ port, portlen);
+ 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;
+
+ return mlen;
+}
+
+static void bfd_sd_reschedule(int sd)
+{
+ if (sd == bglobal.bg_shop) {
+ bglobal.bg_ev[0] = NULL;
+ thread_add_read(master, bfd_recv_cb, NULL, bglobal.bg_shop,
+ &bglobal.bg_ev[0]);
+ } else if (sd == bglobal.bg_mhop) {
+ bglobal.bg_ev[1] = NULL;
+ thread_add_read(master, bfd_recv_cb, NULL, bglobal.bg_mhop,
+ &bglobal.bg_ev[1]);
+ } else if (sd == bglobal.bg_shop6) {
+ bglobal.bg_ev[2] = NULL;
+ thread_add_read(master, bfd_recv_cb, NULL, bglobal.bg_shop6,
+ &bglobal.bg_ev[2]);
+ } else if (sd == bglobal.bg_mhop6) {
+ bglobal.bg_ev[3] = NULL;
+ thread_add_read(master, bfd_recv_cb, NULL, bglobal.bg_mhop6,
+ &bglobal.bg_ev[3]);
+ } else if (sd == bglobal.bg_echo) {
+ bglobal.bg_ev[4] = NULL;
+ thread_add_read(master, bfd_recv_cb, NULL, bglobal.bg_echo,
+ &bglobal.bg_ev[4]);
+ } else if (sd == bglobal.bg_vxlan) {
+ bglobal.bg_ev[5] = NULL;
+ thread_add_read(master, bfd_recv_cb, NULL, bglobal.bg_vxlan,
+ &bglobal.bg_ev[5]);
+ }
+}
+
+static void cp_debug(bool mhop, struct sockaddr_any *peer,
+ struct sockaddr_any *local, const char *port,
+ const char *vrf, const char *fmt, ...)
+{
+ char buf[512], peerstr[128], localstr[128], portstr[64], vrfstr[64];
+ va_list vl;
+
+ if (peer->sa_sin.sin_family)
+ snprintf(peerstr, sizeof(peerstr), " peer:%s", satostr(peer));
+ else
+ peerstr[0] = 0;
+
+ if (local->sa_sin.sin_family)
+ snprintf(localstr, sizeof(localstr), " local:%s",
+ satostr(local));
+ else
+ localstr[0] = 0;
+
+ if (port[0])
+ snprintf(portstr, sizeof(portstr), " port:%s", port);
+ else
+ portstr[0] = 0;
+
+ if (vrf[0])
+ snprintf(vrfstr, sizeof(vrfstr), " vrf:%s", port);
+ else
+ vrfstr[0] = 0;
+
+ va_start(vl, fmt);
+ vsnprintf(buf, sizeof(buf), fmt, vl);
+ va_end(vl);
+
+ log_debug("control-packet: %s [mhop:%s%s%s%s%s]", buf,
+ mhop ? "yes" : "no", peerstr, localstr, portstr, vrfstr);
+}
+
+int bfd_recv_cb(struct thread *t)
+{
+ int sd = THREAD_FD(t);
+ struct bfd_session *bfd;
+ struct bfd_pkt *cp;
+ bool is_mhop, is_vxlan;
+ ssize_t mlen = 0;
+ uint32_t oldEchoXmt_TO, oldXmtTime;
+ struct sockaddr_any local, peer;
+ char port[MAXNAMELEN + 1], vrfname[MAXNAMELEN + 1];
+ struct bfd_session_vxlan_info vxlan_info;
+
+ /* Schedule next read. */
+ bfd_sd_reschedule(sd);
+
+ /* Handle echo packets. */
+ if (sd == bglobal.bg_echo) {
+ ptm_bfd_process_echo_pkt(sd);
+ return 0;
+ }
+
+ /* Handle control packets. */
+ is_mhop = is_vxlan = false;
+ if (sd == bglobal.bg_shop || sd == bglobal.bg_mhop) {
+ is_mhop = sd == bglobal.bg_mhop;
+ mlen = bfd_recv_ipv4(sd, is_mhop, port, sizeof(port), vrfname,
+ sizeof(vrfname), &local, &peer);
+ } else if (sd == bglobal.bg_shop6 || sd == bglobal.bg_mhop6) {
+ is_mhop = sd == bglobal.bg_mhop6;
+ mlen = bfd_recv_ipv6(sd, is_mhop, port, sizeof(port), vrfname,
+ sizeof(vrfname), &local, &peer);
+ }
+#if 0 /* TODO vxlan handling */
+ cp = ptm_bfd_process_vxlan_pkt(s, se, udata, &local_ifindex,
+ &sin, &vxlan_info, rx_pkt, &mlen);
+ if (!cp)
+ return -1;
+
+ is_vxlan = true;
+ /* keep in network-byte order */
+ peer.ip4_addr.s_addr = sin.sin_addr.s_addr;
+ peer.family = AF_INET;
+ strcpy(peer_addr, inet_ntoa(sin.sin_addr));
+#endif
+
+ /* Implement RFC 5880 6.8.6 */
+ if (mlen < BFD_PKT_LEN) {
+ cp_debug(is_mhop, &peer, &local, port, vrfname,
+ "too small (%ld bytes)", mlen);
+ return 0;
+ }
+
+ /*
+ * Parse the control header for inconsistencies:
+ * - Invalid version;
+ * - Bad multiplier configuration;
+ * - Short packets;
+ * - Invalid discriminator;
+ */
+ cp = (struct bfd_pkt *)(msgbuf);
+ if (BFD_GETVER(cp->diag) != BFD_VERSION) {
+ cp_debug(is_mhop, &peer, &local, port, vrfname,
+ "bad version %d", BFD_GETVER(cp->diag));
+ return 0;
+ }
+
+ if (cp->detect_mult == 0) {
+ cp_debug(is_mhop, &peer, &local, port, vrfname,
+ "detect multiplier set to zero");
+ return 0;
+ }
+
+ if ((cp->len < BFD_PKT_LEN) || (cp->len > mlen)) {
+ cp_debug(is_mhop, &peer, &local, port, vrfname, "too small");
+ return 0;
+ }
+
+ if (cp->discrs.my_discr == 0) {
+ cp_debug(is_mhop, &peer, &local, port, vrfname,
+ "'my discriminator' is zero");
+ return 0;
+ }
+
+ /* Find the session that this packet belongs. */
+ bfd = ptm_bfd_sess_find(cp, port, &peer, &local, vrfname, is_mhop);
+ if (bfd == NULL) {
+ cp_debug(is_mhop, &peer, &local, port, vrfname,
+ "no session found");
+ return 0;
+ }
+
+ /* Handle VxLAN cases. */
+ if (is_vxlan && !ptm_bfd_validate_vxlan_pkt(bfd, &vxlan_info))
+ return 0;
+
+ bfd->stats.rx_ctrl_pkt++;
+
+ /*
+ * Multi hop: validate packet TTL.
+ * Single hop: set local address that received the packet.
+ */
+ if (is_mhop) {
+ if ((BFD_TTL_VAL - bfd->mh_ttl) > ttlval) {
+ cp_debug(is_mhop, &peer, &local, port, vrfname,
+ "exceeded max hop count (expected %d, got %d)",
+ bfd->mh_ttl, ttlval);
+ return 0;
+ }
+ } else if (bfd->local_ip.sa_sin.sin_family == AF_UNSPEC) {
+ bfd->local_ip = local;
+ }
+
+ /*
+ * If no interface was detected, save the interface where the
+ * packet came in.
+ */
+ if (bfd->ifindex == 0)
+ bfd->ifindex = ptm_bfd_fetch_ifindex(port);
+
+ /* Log remote discriminator changes. */
+ if ((bfd->discrs.remote_discr != 0)
+ && (bfd->discrs.remote_discr != ntohl(cp->discrs.my_discr)))
+ cp_debug(is_mhop, &peer, &local, port, vrfname,
+ "remote discriminator mismatch (expected %d, got %d)",
+ bfd->discrs.remote_discr, ntohl(cp->discrs.my_discr));
+
+ bfd->discrs.remote_discr = ntohl(cp->discrs.my_discr);
+
+ /* If received the Final bit, the new values should take effect */
+ if (bfd->polling && BFD_GETFBIT(cp->flags)) {
+ bfd->timers.desired_min_tx = bfd->new_timers.desired_min_tx;
+ bfd->timers.required_min_rx = bfd->new_timers.required_min_rx;
+ bfd->new_timers.desired_min_tx = 0;
+ bfd->new_timers.required_min_rx = 0;
+ bfd->polling = 0;
+ }
+
+ if (!bfd->demand_mode) {
+ /* Compute detect time */
+ bfd->detect_TO = cp->detect_mult
+ * ((bfd->timers.required_min_rx
+ > ntohl(cp->timers.desired_min_tx))
+ ? bfd->timers.required_min_rx
+ : ntohl(cp->timers.desired_min_tx));
+ bfd->remote_detect_mult = cp->detect_mult;
+ } else
+ cp_debug(is_mhop, &peer, &local, port, vrfname,
+ "unsupported demand mode");
+
+ /* Save remote diagnostics before state switch. */
+ bfd->remote_diag = cp->diag & BFD_DIAGMASK;
+
+ /* State switch from section 6.8.6 */
+ if (BFD_GETSTATE(cp->flags) == PTM_BFD_ADM_DOWN) {
+ if (bfd->ses_state != PTM_BFD_DOWN)
+ ptm_bfd_ses_dn(bfd, BFD_DIAGNEIGHDOWN);
+ } else {
+ switch (bfd->ses_state) {
+ case (PTM_BFD_DOWN):
+ if (BFD_GETSTATE(cp->flags) == PTM_BFD_INIT)
+ ptm_bfd_ses_up(bfd);
+ else if (BFD_GETSTATE(cp->flags) == PTM_BFD_DOWN)
+ bfd->ses_state = PTM_BFD_INIT;
+ break;
+ case (PTM_BFD_INIT):
+ if (BFD_GETSTATE(cp->flags) == PTM_BFD_INIT
+ || BFD_GETSTATE(cp->flags) == PTM_BFD_UP)
+ ptm_bfd_ses_up(bfd);
+ break;
+ case (PTM_BFD_UP):
+ if (BFD_GETSTATE(cp->flags) == PTM_BFD_DOWN)
+ ptm_bfd_ses_dn(bfd, BFD_DIAGNEIGHDOWN);
+ break;
+ }
+ }
+
+ /*
+ * Handle echo packet status:
+ * - Start echo packets if configured and permitted
+ * (required_min_echo > 0);
+ * - Stop echo packets if not allowed (required_min_echo == 0);
+ * - Recalculate echo packet interval;
+ */
+ if (BFD_CHECK_FLAG(bfd->flags, BFD_SESS_FLAG_ECHO)) {
+ if (BFD_CHECK_FLAG(bfd->flags, BFD_SESS_FLAG_ECHO_ACTIVE)) {
+ if (!ntohl(cp->timers.required_min_echo)) {
+ ptm_bfd_echo_stop(bfd, 1);
+ } else {
+ oldEchoXmt_TO = bfd->echo_xmt_TO;
+ bfd->echo_xmt_TO =
+ bfd->timers.required_min_echo;
+ if (ntohl(cp->timers.required_min_echo)
+ > bfd->echo_xmt_TO)
+ bfd->echo_xmt_TO = ntohl(
+ cp->timers.required_min_echo);
+ if (oldEchoXmt_TO != bfd->echo_xmt_TO)
+ ptm_bfd_echo_start(bfd);
+ }
+ } else if (ntohl(cp->timers.required_min_echo)) {
+ bfd->echo_xmt_TO = bfd->timers.required_min_echo;
+ if (ntohl(cp->timers.required_min_echo)
+ > bfd->echo_xmt_TO)
+ bfd->echo_xmt_TO =
+ ntohl(cp->timers.required_min_echo);
+ ptm_bfd_echo_start(bfd);
+ }
+ }
+
+ if (BFD_CHECK_FLAG(bfd->flags, BFD_SESS_FLAG_ECHO_ACTIVE)) {
+ bfd->echo_xmt_TO = bfd->timers.required_min_echo;
+ if (ntohl(cp->timers.required_min_echo) > bfd->echo_xmt_TO)
+ bfd->echo_xmt_TO = ntohl(cp->timers.required_min_echo);
+ }
+
+ /* Calculate new transmit time */
+ oldXmtTime = bfd->xmt_TO;
+ bfd->xmt_TO =
+ (bfd->timers.desired_min_tx > ntohl(cp->timers.required_min_rx))
+ ? bfd->timers.desired_min_tx
+ : ntohl(cp->timers.required_min_rx);
+
+ /* If transmit time has changed, and too much time until next xmt,
+ * restart
+ */
+ if (BFD_GETPBIT(cp->flags)) {
+ ptm_bfd_xmt_TO(bfd, 1);
+ } else if (oldXmtTime != bfd->xmt_TO) {
+ /* XXX add some skid to this as well */
+ ptm_bfd_start_xmt_timer(bfd, false);
+ }
+
+ /* Restart detection timer (packet received) */
+ if (!bfd->demand_mode)
+ bfd_recvtimer_update(bfd);
+
+ /*
+ * Save the timers and state sent by the remote end
+ * for debugging and statistics.
+ */
+ if (BFD_GETFBIT(cp->flags)) {
+ bfd->remote_timers.desired_min_tx =
+ ntohl(cp->timers.desired_min_tx);
+ bfd->remote_timers.required_min_rx =
+ ntohl(cp->timers.required_min_rx);
+ bfd->remote_timers.required_min_echo =
+ ntohl(cp->timers.required_min_echo);
+
+ control_notify_config(BCM_NOTIFY_CONFIG_UPDATE, bfd);
+ }
+
+ return 0;
+}
+
+
+/*
+ * Sockets creation.
+ */
+
+
+/*
+ * IPv4 sockets
+ */
+int bp_set_ttl(int sd)
+{
+ if (setsockopt(sd, IPPROTO_IP, IP_TTL, &ttlval, sizeof(ttlval)) == -1) {
+ log_warning("%s: setsockopt(IP_TTL): %s", __func__,
+ strerror(errno));
+ return -1;
+ }
+
+ return 0;
+}
+
+int bp_set_tos(int sd)
+{
+ if (setsockopt(sd, IPPROTO_IP, IP_TOS, &tosval, sizeof(tosval)) == -1) {
+ log_warning("%s: setsockopt(IP_TOS): %s", __func__,
+ strerror(errno));
+ return -1;
+ }
+
+ return 0;
+}
+
+static void bp_set_ipopts(int sd)
+{
+ if (bp_set_ttl(sd) != 0)
+ log_fatal("%s: TTL configuration failed", __func__);
+
+ if (setsockopt(sd, IPPROTO_IP, IP_RECVTTL, &rcvttl, sizeof(rcvttl))
+ == -1)
+ log_fatal("%s: setsockopt(IP_RECVTTL): %s", __func__,
+ strerror(errno));
+
+#ifdef BFD_LINUX
+ int pktinfo = BFD_PKT_INFO_VAL;
+ /* Figure out address and interface to do the peer matching. */
+ if (setsockopt(sd, IPPROTO_IP, IP_PKTINFO, &pktinfo, sizeof(pktinfo))
+ == -1)
+ log_fatal("%s: setsockopt(IP_PKTINFO): %s", __func__,
+ strerror(errno));
+#endif /* BFD_LINUX */
+#ifdef BFD_BSD
+ int yes = 1;
+
+ /* Find out our address for peer matching. */
+ if (setsockopt(sd, IPPROTO_IP, IP_RECVDSTADDR, &yes, sizeof(yes)) == -1)
+ log_fatal("%s: setsockopt(IP_RECVDSTADDR): %s", __func__,
+ strerror(errno));
+
+ /* Find out interface where the packet came in. */
+ if (setsockopt_ifindex(AF_INET, sd, yes) == -1)
+ log_fatal("%s: setsockopt_ipv4_ifindex: %s", __func__,
+ strerror(errno));
+#endif /* BFD_BSD */
+}
+
+static void bp_bind_ip(int sd, uint16_t port)
+{
+ struct sockaddr_in sin;
+
+ memset(&sin, 0, sizeof(sin));
+ sin.sin_family = AF_INET;
+ sin.sin_addr.s_addr = htonl(INADDR_ANY);
+ sin.sin_port = htons(port);
+ if (bind(sd, (struct sockaddr *)&sin, sizeof(sin)) == -1)
+ log_fatal("%s: bind: %s", __func__, strerror(errno));
+}
+
+int bp_udp_shop(void)
+{
+ int sd;
+
+ sd = socket(AF_INET, SOCK_DGRAM, PF_UNSPEC);
+ if (sd == -1)
+ log_fatal("%s: socket: %s", __func__, strerror(errno));
+
+ bp_set_ipopts(sd);
+ bp_bind_ip(sd, BFD_DEFDESTPORT);
+
+ return sd;
+}
+
+int bp_udp_mhop(void)
+{
+ int sd;
+
+ sd = socket(AF_INET, SOCK_DGRAM, PF_UNSPEC);
+ if (sd == -1)
+ log_fatal("%s: socket: %s", __func__, strerror(errno));
+
+ bp_set_ipopts(sd);
+ bp_bind_ip(sd, BFD_DEF_MHOP_DEST_PORT);
+
+ return sd;
+}
+
+int bp_peer_socket(struct bfd_peer_cfg *bpc)
+{
+ int sd, pcount;
+ struct sockaddr_in sin;
+ static int srcPort = BFD_SRCPORTINIT;
+
+ sd = socket(AF_INET, SOCK_DGRAM, PF_UNSPEC);
+ if (sd == -1) {
+ log_error("ipv4-new: failed to create socket: %s",
+ strerror(errno));
+ return -1;
+ }
+
+ if (!bpc->bpc_has_vxlan) {
+ /* Set TTL to 255 for all transmitted packets */
+ if (bp_set_ttl(sd) != 0) {
+ close(sd);
+ return -1;
+ }
+ }
+
+ /* Set TOS to CS6 for all transmitted packets */
+ if (bp_set_tos(sd) != 0) {
+ close(sd);
+ return -1;
+ }
+
+ /* dont bind-to-device incase of vxlan */
+ if (!bpc->bpc_has_vxlan && bpc->bpc_has_localif) {
+ if (bp_bind_dev(sd, bpc->bpc_localif) != 0) {
+ close(sd);
+ return -1;
+ }
+ } else if (bpc->bpc_mhop && bpc->bpc_has_vrfname) {
+ if (bp_bind_dev(sd, bpc->bpc_vrfname) != 0) {
+ close(sd);
+ return -1;
+ }
+ }
+
+ /* Find an available source port in the proper range */
+ memset(&sin, 0, sizeof(sin));
+ sin = bpc->bpc_local.sa_sin;
+ sin.sin_family = AF_INET;
+#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
+ sin.sin_len = sizeof(sin);
+#endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */
+ if (bpc->bpc_mhop || bpc->bpc_has_vxlan)
+ sin.sin_addr = bpc->bpc_local.sa_sin.sin_addr;
+ else
+ sin.sin_addr.s_addr = INADDR_ANY;
+
+ pcount = 0;
+ do {
+ if ((++pcount) > (BFD_SRCPORTMAX - BFD_SRCPORTINIT)) {
+ /* Searched all ports, none available */
+ log_error("ipv4-new: failed to bind port: %s",
+ strerror(errno));
+ close(sd);
+ return -1;
+ }
+ if (srcPort >= BFD_SRCPORTMAX)
+ srcPort = BFD_SRCPORTINIT;
+ sin.sin_port = htons(srcPort++);
+ } while (bind(sd, (struct sockaddr *)&sin, sizeof(sin)) < 0);
+
+ return sd;
+}
+
+
+/*
+ * IPv6 sockets
+ */
+
+int bp_peer_socketv6(struct bfd_peer_cfg *bpc)
+{
+ int sd, pcount, ifindex;
+ struct sockaddr_in6 sin6;
+ static int srcPort = BFD_SRCPORTINIT;
+
+ sd = socket(AF_INET6, SOCK_DGRAM, PF_UNSPEC);
+ if (sd == -1) {
+ log_error("ipv6-new: failed to create socket: %s",
+ strerror(errno));
+ return -1;
+ }
+
+ if (!bpc->bpc_has_vxlan) {
+ /* Set TTL to 255 for all transmitted packets */
+ if (bp_set_ttlv6(sd) != 0) {
+ close(sd);
+ return -1;
+ }
+ }
+
+ /* Set TOS to CS6 for all transmitted packets */
+ if (bp_set_tosv6(sd) != 0) {
+ close(sd);
+ return -1;
+ }
+
+ /* Find an available source port in the proper range */
+ memset(&sin6, 0, sizeof(sin6));
+ sin6.sin6_family = AF_INET6;
+#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
+ sin6.sin6_len = sizeof(sin6);
+#endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */
+ sin6 = bpc->bpc_local.sa_sin6;
+ ifindex = ptm_bfd_fetch_ifindex(bpc->bpc_localif);
+ if (IN6_IS_ADDR_LINKLOCAL(&sin6.sin6_addr))
+ sin6.sin6_scope_id = ifindex;
+
+ if (bpc->bpc_has_localif) {
+ if (bp_bind_dev(sd, bpc->bpc_localif) != 0) {
+ close(sd);
+ return -1;
+ }
+ } else if (bpc->bpc_mhop && bpc->bpc_has_vrfname) {
+ if (bp_bind_dev(sd, bpc->bpc_vrfname) != 0) {
+ close(sd);
+ return -1;
+ }
+ }
+
+ pcount = 0;
+ do {
+ if ((++pcount) > (BFD_SRCPORTMAX - BFD_SRCPORTINIT)) {
+ /* Searched all ports, none available */
+ log_error("ipv6-new: failed to bind port: %s",
+ strerror(errno));
+ close(sd);
+ return -1;
+ }
+ if (srcPort >= BFD_SRCPORTMAX)
+ srcPort = BFD_SRCPORTINIT;
+ sin6.sin6_port = htons(srcPort++);
+ } while (bind(sd, (struct sockaddr *)&sin6, sizeof(sin6)) < 0);
+
+ return sd;
+}
+
+int bp_set_ttlv6(int sd)
+{
+ if (setsockopt(sd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &ttlval,
+ sizeof(ttlval))
+ == -1) {
+ log_warning("%s: setsockopt(IPV6_UNICAST_HOPS): %s", __func__,
+ strerror(errno));
+ return -1;
+ }
+
+ return 0;
+}
+
+int bp_set_tosv6(int sd)
+{
+ if (setsockopt(sd, IPPROTO_IPV6, IPV6_TCLASS, &tosval, sizeof(tosval))
+ == -1) {
+ log_warning("%s: setsockopt(IPV6_TCLASS): %s", __func__,
+ strerror(errno));
+ return -1;
+ }
+
+ return 0;
+}
+
+static void bp_set_ipv6opts(int sd)
+{
+ static int ipv6_pktinfo = BFD_IPV6_PKT_INFO_VAL;
+ static int ipv6_only = BFD_IPV6_ONLY_VAL;
+
+ if (setsockopt(sd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &ttlval,
+ sizeof(ttlval))
+ == -1)
+ log_fatal("%s: setsockopt(IPV6_UNICAST_HOPS): %s", __func__,
+ strerror(errno));
+
+ if (setsockopt_ipv6_hoplimit(sd, rcvttl) == -1)
+ log_fatal("%s: setsockopt(IPV6_HOPLIMIT): %s", __func__,
+ strerror(errno));
+
+ if (setsockopt_ipv6_pktinfo(sd, ipv6_pktinfo) == -1)
+ log_fatal("%s: setsockopt(IPV6_PKTINFO): %s", __func__,
+ strerror(errno));
+
+ if (setsockopt(sd, IPPROTO_IPV6, IPV6_V6ONLY, &ipv6_only,
+ sizeof(ipv6_only))
+ == -1)
+ log_fatal("%s: setsockopt(IPV6_V6ONLY): %s", __func__,
+ strerror(errno));
+}
+
+static void bp_bind_ipv6(int sd, uint16_t port)
+{
+ struct sockaddr_in6 sin6;
+
+ memset(&sin6, 0, sizeof(sin6));
+ sin6.sin6_family = AF_INET6;
+ sin6.sin6_addr = in6addr_any;
+ sin6.sin6_port = htons(port);
+#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
+ sin6.sin6_len = sizeof(sin6);
+#endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */
+ if (bind(sd, (struct sockaddr *)&sin6, sizeof(sin6)) == -1)
+ log_fatal("%s: bind: %s", __func__, strerror(errno));
+}
+
+int bp_udp6_shop(void)
+{
+ int sd;
+
+ sd = socket(AF_INET6, SOCK_DGRAM, PF_UNSPEC);
+ if (sd == -1)
+ log_fatal("%s: socket: %s", __func__, strerror(errno));
+
+ bp_set_ipv6opts(sd);
+ bp_bind_ipv6(sd, BFD_DEFDESTPORT);
+
+ return sd;
+}
+
+int bp_udp6_mhop(void)
+{
+ int sd;
+
+ sd = socket(AF_INET6, SOCK_DGRAM, PF_UNSPEC);
+ if (sd == -1)
+ log_fatal("%s: socket: %s", __func__, strerror(errno));
+
+ bp_set_ipv6opts(sd);
+ bp_bind_ipv6(sd, BFD_DEF_MHOP_DEST_PORT);
+
+ return sd;
+}
diff --git a/bfdd/bfdctl.h b/bfdd/bfdctl.h
new file mode 100644
index 0000000000..940efd1614
--- /dev/null
+++ b/bfdd/bfdctl.h
@@ -0,0 +1,160 @@
+/*********************************************************************
+ * Copyright 2017-2018 Network Device Education Foundation, Inc. ("NetDEF")
+ *
+ * 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
+ *
+ * bfdctl.h: all BFDd control socket protocol definitions.
+ *
+ * Authors
+ * -------
+ * Rafael Zalamena <rzalamena@opensourcerouting.org>
+ */
+
+#ifndef _BFDCTRL_H_
+#define _BFDCTRL_H_
+
+#include <netinet/in.h>
+
+#include <stdbool.h>
+#include <stdint.h>
+
+/*
+ * Auxiliary definitions
+ */
+struct sockaddr_any {
+ union {
+ struct sockaddr_in sa_sin;
+ struct sockaddr_in6 sa_sin6;
+ };
+};
+
+#ifndef MAXNAMELEN
+#define MAXNAMELEN 32
+#endif
+
+#define BPC_DEF_DETECTMULTIPLIER 3
+#define BPC_DEF_RECEIVEINTERVAL 300 /* milliseconds */
+#define BPC_DEF_TRANSMITINTERVAL 300 /* milliseconds */
+#define BPC_DEF_ECHOINTERVAL 50 /* milliseconds */
+
+/* Peer status */
+enum bfd_peer_status {
+ BPS_SHUTDOWN = 0, /* == PTM_BFD_ADM_DOWN, "adm-down" */
+ BPS_DOWN = 1, /* == PTM_BFD_DOWN, "down" */
+ BPS_INIT = 2, /* == PTM_BFD_INIT, "init" */
+ BPS_UP = 3, /* == PTM_BFD_UP, "up" */
+};
+
+struct bfd_peer_cfg {
+ bool bpc_mhop;
+ bool bpc_ipv4;
+ struct sockaddr_any bpc_peer;
+ struct sockaddr_any bpc_local;
+
+ bool bpc_has_label;
+ char bpc_label[MAXNAMELEN];
+
+ bool bpc_has_vxlan;
+ unsigned int bpc_vxlan;
+
+ bool bpc_has_localif;
+ char bpc_localif[MAXNAMELEN + 1];
+
+ bool bpc_has_vrfname;
+ char bpc_vrfname[MAXNAMELEN + 1];
+
+ bool bpc_has_detectmultiplier;
+ uint8_t bpc_detectmultiplier;
+
+ bool bpc_has_recvinterval;
+ uint64_t bpc_recvinterval;
+
+ bool bpc_has_txinterval;
+ uint64_t bpc_txinterval;
+
+ bool bpc_has_echointerval;
+ uint64_t bpc_echointerval;
+
+ bool bpc_echo;
+ bool bpc_createonly;
+ bool bpc_shutdown;
+
+ /* Status information */
+ enum bfd_peer_status bpc_bps;
+ uint32_t bpc_id;
+ uint32_t bpc_remoteid;
+ uint8_t bpc_diag;
+ uint8_t bpc_remotediag;
+ uint8_t bpc_remote_detectmultiplier;
+ uint64_t bpc_remote_recvinterval;
+ uint64_t bpc_remote_txinterval;
+ uint64_t bpc_remote_echointerval;
+ uint64_t bpc_lastevent;
+};
+
+
+/*
+ * Protocol definitions
+ */
+enum bc_msg_version {
+ BMV_VERSION_1 = 1,
+};
+
+enum bc_msg_type {
+ BMT_RESPONSE = 1,
+ BMT_REQUEST_ADD = 2,
+ BMT_REQUEST_DEL = 3,
+ BMT_NOTIFY = 4,
+ BMT_NOTIFY_ADD = 5,
+ BMT_NOTIFY_DEL = 6,
+};
+
+/* Notify flags to use with bcm_notify. */
+#define BCM_NOTIFY_ALL ((uint64_t)-1)
+#define BCM_NOTIFY_PEER_STATE (1ULL << 0)
+#define BCM_NOTIFY_CONFIG (1ULL << 1)
+#define BCM_NOTIFY_NONE 0
+
+/* Response 'status' definitions. */
+#define BCM_RESPONSE_OK "ok"
+#define BCM_RESPONSE_ERROR "error"
+
+/* Notify operation. */
+#define BCM_NOTIFY_PEER_STATUS "status"
+#define BCM_NOTIFY_CONFIG_ADD "add"
+#define BCM_NOTIFY_CONFIG_DELETE "delete"
+#define BCM_NOTIFY_CONFIG_UPDATE "update"
+
+/* Notification special ID. */
+#define BCM_NOTIFY_ID 0
+
+struct bfd_control_msg {
+ /* Total length without the header. */
+ uint32_t bcm_length;
+ /*
+ * Message request/response id.
+ * All requests will have a correspondent response with the
+ * same id.
+ */
+ uint16_t bcm_id;
+ /* Message type. */
+ uint8_t bcm_type;
+ /* Message version. */
+ uint8_t bcm_ver;
+ /* Message payload. */
+ uint8_t bcm_data[0];
+};
+
+#endif
diff --git a/bfdd/bfdd.c b/bfdd/bfdd.c
new file mode 100644
index 0000000000..144619088d
--- /dev/null
+++ b/bfdd/bfdd.c
@@ -0,0 +1,236 @@
+/*
+ * BFD daemon code
+ * Copyright (C) 2018 Network Device Education Foundation, Inc. ("NetDEF")
+ *
+ * FRR is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * FRR is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with FRR; see the file COPYING. If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#include <zebra.h>
+
+#include "bfd.h"
+#include "lib/version.h"
+
+
+/*
+ * FRR related code.
+ */
+DEFINE_MGROUP(BFDD, "Bidirectional Forwarding Detection Daemon");
+DEFINE_MTYPE(BFDD, BFDD_TMP, "short-lived temporary memory");
+DEFINE_MTYPE(BFDD, BFDD_CONFIG, "long-lived configuration memory");
+DEFINE_MTYPE(BFDD, BFDD_LABEL, "long-lived label memory");
+DEFINE_MTYPE(BFDD, BFDD_CONTROL, "long-lived control socket memory");
+DEFINE_MTYPE(BFDD, BFDD_NOTIFICATION, "short-lived control notification data");
+
+/* Master of threads. */
+struct thread_master *master;
+
+/* BFDd privileges */
+static zebra_capabilities_t _caps_p[] = {ZCAP_BIND};
+
+struct zebra_privs_t bfdd_privs = {
+#if defined(FRR_USER) && defined(FRR_GROUP)
+ .user = FRR_USER,
+ .group = FRR_GROUP,
+#endif
+#if defined(VTY_GROUP)
+ .vty_group = VTY_GROUP,
+#endif
+ .caps_p = _caps_p,
+ .cap_num_p = array_size(_caps_p),
+ .cap_num_i = 0,
+};
+
+void socket_close(int *s)
+{
+ if (*s <= 0)
+ return;
+
+ if (close(*s) != 0)
+ log_error("%s: close(%d): (%d) %s", __func__, *s, errno,
+ strerror(errno));
+
+ *s = -1;
+}
+
+static void sigusr1_handler(void)
+{
+ zlog_rotate();
+}
+
+static void sigterm_handler(void)
+{
+ /* Signalize shutdown. */
+ frr_early_fini();
+
+ /* Stop receiving message from zebra. */
+ bfdd_zclient_stop();
+
+ /* Shutdown controller to avoid receiving anymore commands. */
+ control_shutdown();
+
+ /* Shutdown and free all protocol related memory. */
+ bfd_shutdown();
+
+ /* Close all descriptors. */
+ socket_close(&bglobal.bg_echo);
+ socket_close(&bglobal.bg_shop);
+ socket_close(&bglobal.bg_mhop);
+ socket_close(&bglobal.bg_shop6);
+ socket_close(&bglobal.bg_mhop6);
+ socket_close(&bglobal.bg_vxlan);
+
+ /* Terminate and free() FRR related memory. */
+ frr_fini();
+
+ exit(0);
+}
+
+static struct quagga_signal_t bfd_signals[] = {
+ {
+ .signal = SIGUSR1,
+ .handler = &sigusr1_handler,
+ },
+ {
+ .signal = SIGTERM,
+ .handler = &sigterm_handler,
+ },
+ {
+ .signal = SIGINT,
+ .handler = &sigterm_handler,
+ },
+};
+
+FRR_DAEMON_INFO(bfdd, BFD, .vty_port = 2617,
+ .proghelp = "Implementation of the BFD protocol.",
+ .signals = bfd_signals, .n_signals = array_size(bfd_signals),
+ .privs = &bfdd_privs)
+
+#define OPTION_CTLSOCK 1001
+static struct option longopts[] = {
+ {"bfdctl", required_argument, NULL, OPTION_CTLSOCK},
+ {0}
+};
+
+
+/*
+ * BFD daemon related code.
+ */
+struct bfd_global bglobal;
+
+struct bfd_diag_str_list diag_list[] = {
+ {.str = "NeighDown", .type = BFD_DIAGNEIGHDOWN},
+ {.str = "DetectTime", .type = BFD_DIAGDETECTTIME},
+ {.str = "AdminDown", .type = BFD_DIAGADMINDOWN},
+ {.str = NULL},
+};
+
+struct bfd_state_str_list state_list[] = {
+ {.str = "AdminDown", .type = PTM_BFD_ADM_DOWN},
+ {.str = "Down", .type = PTM_BFD_DOWN},
+ {.str = "Init", .type = PTM_BFD_INIT},
+ {.str = "Up", .type = PTM_BFD_UP},
+ {.str = NULL},
+};
+
+
+static void bg_init(void)
+{
+ TAILQ_INIT(&bglobal.bg_bcslist);
+
+ bglobal.bg_shop = bp_udp_shop();
+ bglobal.bg_mhop = bp_udp_mhop();
+ bglobal.bg_shop6 = bp_udp6_shop();
+ bglobal.bg_mhop6 = bp_udp6_mhop();
+ bglobal.bg_echo = ptm_bfd_echo_sock_init();
+ bglobal.bg_vxlan = ptm_bfd_vxlan_sock_init();
+}
+
+int main(int argc, char *argv[])
+{
+ const char *ctl_path = BFDD_CONTROL_SOCKET;
+ int opt;
+
+ frr_preinit(&bfdd_di, argc, argv);
+ frr_opt_add("", longopts,
+ " --bfdctl Specify bfdd control socket\n");
+
+ while (true) {
+ opt = frr_getopt(argc, argv, NULL);
+ if (opt == EOF)
+ break;
+
+ switch (opt) {
+ case OPTION_CTLSOCK:
+ ctl_path = optarg;
+ break;
+
+ default:
+ frr_help_exit(1);
+ break;
+ }
+ }
+
+#if 0 /* TODO add support for JSON configuration files. */
+ parse_config(conf);
+#endif
+
+ /* Initialize logging API. */
+ log_init(1, BLOG_DEBUG, &bfdd_di);
+
+ /* Initialize system sockets. */
+ bg_init();
+
+ /* Initialize control socket. */
+ control_init(ctl_path);
+
+ /* Initialize FRR infrastructure. */
+ master = frr_init();
+
+ /* Initialize BFD data structures. */
+ bfd_initialize();
+
+ /* Initialize zebra connection. */
+ bfdd_zclient_init(&bfdd_privs);
+
+ /* Add descriptors to the event loop. */
+ thread_add_read(master, bfd_recv_cb, NULL, bglobal.bg_shop,
+ &bglobal.bg_ev[0]);
+ thread_add_read(master, bfd_recv_cb, NULL, bglobal.bg_mhop,
+ &bglobal.bg_ev[1]);
+ thread_add_read(master, bfd_recv_cb, NULL, bglobal.bg_shop6,
+ &bglobal.bg_ev[2]);
+ thread_add_read(master, bfd_recv_cb, NULL, bglobal.bg_mhop6,
+ &bglobal.bg_ev[3]);
+ thread_add_read(master, bfd_recv_cb, NULL, bglobal.bg_echo,
+ &bglobal.bg_ev[4]);
+#if 0 /* TODO VxLAN support. */
+ thread_add_read(master, bfd_recv_cb, NULL, bglobal.bg_vxlan,
+ &bglobal.bg_ev[5]);
+#endif
+ thread_add_read(master, control_accept, NULL, bglobal.bg_csock,
+ &bglobal.bg_csockev);
+
+ /* Install commands. */
+ bfdd_vty_init();
+
+ /* read configuration file and daemonize */
+ frr_config_fork();
+
+ frr_run(master);
+ /* NOTREACHED */
+
+ return 0;
+}
diff --git a/bfdd/bfdd.conf.sample b/bfdd/bfdd.conf.sample
new file mode 100644
index 0000000000..9981e262bc
--- /dev/null
+++ b/bfdd/bfdd.conf.sample
@@ -0,0 +1,5 @@
+password zebra
+!
+log stdout
+!
+line vty
diff --git a/bfdd/bfdd_vty.c b/bfdd/bfdd_vty.c
new file mode 100644
index 0000000000..eedaec0a16
--- /dev/null
+++ b/bfdd/bfdd_vty.c
@@ -0,0 +1,870 @@
+/*
+ * BFD daemon code
+ * Copyright (C) 2018 Network Device Education Foundation, Inc. ("NetDEF")
+ *
+ * FRR is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * FRR is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with FRR; see the file COPYING. If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#include <zebra.h>
+
+#include "lib/command.h"
+#include "lib/json.h"
+#include "lib/log.h"
+#include "lib/vty.h"
+
+#include "bfd.h"
+
+#ifndef VTYSH_EXTRACT_PL
+#include "bfdd/bfdd_vty_clippy.c"
+#endif
+
+/*
+ * Commands help string definitions.
+ */
+#define PEER_STR "Configure peer\n"
+#define INTERFACE_NAME_STR "Configure interface name to use\n"
+#define PEER_IPV4_STR "IPv4 peer address\n"
+#define PEER_IPV6_STR "IPv6 peer address\n"
+#define MHOP_STR "Configure multihop\n"
+#define LOCAL_STR "Configure local address\n"
+#define LOCAL_IPV4_STR "IPv4 local address\n"
+#define LOCAL_IPV6_STR "IPv6 local address\n"
+#define LOCAL_INTF_STR "Configure local interface name to use\n"
+#define VRF_STR "Configure VRF\n"
+#define VRF_NAME_STR "Configure VRF name\n"
+
+/*
+ * Prototypes
+ */
+static int bfdd_write_config(struct vty *vty);
+static int bfdd_peer_write_config(struct vty *vty);
+static void _bfdd_peer_write_config(struct hash_backet *hb, void *arg);
+static int bfd_configure_peer(struct bfd_peer_cfg *bpc, bool mhop,
+ const struct sockaddr_any *peer,
+ const struct sockaddr_any *local,
+ const char *ifname, const char *vrfname,
+ char *ebuf, size_t ebuflen);
+
+static struct json_object *__display_peer_json(struct bfd_session *bs);
+static void _display_peer_json(struct vty *vty, struct bfd_session *bs);
+static void _display_peer(struct vty *vty, struct bfd_session *bs);
+static void _display_all_peers(struct vty *vty, bool use_json);
+static void _display_peer_iter(struct hash_backet *hb, void *arg);
+static void _display_peer_json_iter(struct hash_backet *hb, void *arg);
+
+
+/*
+ * Commands definition.
+ */
+DEFUN_NOSH(bfd_enter, bfd_enter_cmd, "bfd", "Configure BFD peers\n")
+{
+ vty->node = BFD_NODE;
+ return CMD_SUCCESS;
+}
+
+DEFUN_NOSH(
+ bfd_peer_enter, bfd_peer_enter_cmd,
+ "peer <A.B.C.D|X:X::X:X> [{multihop|local-address <A.B.C.D|X:X::X:X>|interface IFNAME|vrf NAME}]",
+ PEER_STR PEER_IPV4_STR PEER_IPV6_STR
+ MHOP_STR
+ LOCAL_STR LOCAL_IPV4_STR LOCAL_IPV6_STR
+ INTERFACE_STR
+ LOCAL_INTF_STR
+ VRF_STR VRF_NAME_STR)
+{
+ bool mhop;
+ int idx;
+ struct bfd_session *bs;
+ const char *peer, *ifname, *local, *vrfname;
+ struct bfd_peer_cfg bpc;
+ struct sockaddr_any psa, lsa, *lsap;
+ char errormsg[128];
+
+ vrfname = peer = ifname = local = NULL;
+
+ /* Gather all provided information. */
+ peer = argv[1]->arg;
+
+ idx = 0;
+ mhop = argv_find(argv, argc, "multihop", &idx);
+
+ idx = 0;
+ if (argv_find(argv, argc, "interface", &idx))
+ ifname = argv[idx + 1]->arg;
+
+ idx = 0;
+ if (argv_find(argv, argc, "local-address", &idx))
+ local = argv[idx + 1]->arg;
+
+ idx = 0;
+ if (argv_find(argv, argc, "vrf", &idx))
+ vrfname = argv[idx + 1]->arg;
+
+ if (vrfname && ifname) {
+ vty_out(vty, "%% VRF is not mixable with interface\n");
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+
+ strtosa(peer, &psa);
+ if (local) {
+ strtosa(local, &lsa);
+ lsap = &lsa;
+ } else
+ lsap = NULL;
+
+ if (bfd_configure_peer(&bpc, mhop, &psa, lsap, ifname, vrfname,
+ errormsg, sizeof(errormsg))
+ != 0) {
+ vty_out(vty, "%% Invalid peer configuration: %s\n", errormsg);
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+
+ bs = bs_peer_find(&bpc);
+ if (bs == NULL) {
+ bs = ptm_bfd_sess_new(&bpc);
+ if (bs == NULL) {
+ vty_out(vty, "%% Failed to add peer.\n");
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+ }
+
+ VTY_PUSH_CONTEXT(BFD_PEER_NODE, bs);
+
+ return CMD_SUCCESS;
+}
+
+DEFPY(bfd_peer_detectmultiplier, bfd_peer_detectmultiplier_cmd,
+ "detect-multiplier (2-255)$multiplier",
+ "Configure peer detection multiplier\n"
+ "Configure peer detection multiplier value\n")
+{
+ struct bfd_session *bs;
+
+ bs = VTY_GET_CONTEXT(bfd_session);
+ if (bs->detect_mult == multiplier)
+ return CMD_SUCCESS;
+
+ bs->detect_mult = multiplier;
+ bfd_set_polling(bs);
+
+ return CMD_SUCCESS;
+}
+
+DEFPY(bfd_peer_recvinterval, bfd_peer_recvinterval_cmd,
+ "receive-interval (10-60000)$interval",
+ "Configure peer receive interval\n"
+ "Configure peer receive interval value in milliseconds\n")
+{
+ struct bfd_session *bs;
+
+ bs = VTY_GET_CONTEXT(bfd_session);
+ if (bs->timers.required_min_rx == (uint32_t)(interval * 1000))
+ return CMD_SUCCESS;
+
+ bs->timers.required_min_rx = interval * 1000;
+ bfd_set_polling(bs);
+
+ return CMD_SUCCESS;
+}
+
+DEFPY(bfd_peer_txinterval, bfd_peer_txinterval_cmd,
+ "transmit-interval (10-60000)$interval",
+ "Configure peer transmit interval\n"
+ "Configure peer transmit interval value in milliseconds\n")
+{
+ struct bfd_session *bs;
+
+ bs = VTY_GET_CONTEXT(bfd_session);
+ if (bs->up_min_tx == (uint32_t)(interval * 1000))
+ return CMD_SUCCESS;
+
+ bs->up_min_tx = interval * 1000;
+ bfd_set_polling(bs);
+
+ return CMD_SUCCESS;
+}
+
+DEFPY(bfd_peer_echointerval, bfd_peer_echointerval_cmd,
+ "echo-interval (10-60000)$interval",
+ "Configure peer echo interval\n"
+ "Configure peer echo interval value in milliseconds\n")
+{
+ struct bfd_session *bs;
+
+ bs = VTY_GET_CONTEXT(bfd_session);
+ if (bs->timers.required_min_echo == (uint32_t)(interval * 1000))
+ return CMD_SUCCESS;
+
+ bs->timers.required_min_echo = interval * 1000;
+ bfd_set_polling(bs);
+
+ return CMD_SUCCESS;
+}
+
+DEFPY(bfd_peer_shutdown, bfd_peer_shutdown_cmd, "[no] shutdown",
+ NO_STR "Disable BFD peer")
+{
+ struct bfd_session *bs;
+
+ bs = VTY_GET_CONTEXT(bfd_session);
+ if (no) {
+ if (!BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_SHUTDOWN))
+ return CMD_SUCCESS;
+
+ BFD_UNSET_FLAG(bs->flags, BFD_SESS_FLAG_SHUTDOWN);
+
+ /* Change and notify state change. */
+ bs->ses_state = PTM_BFD_DOWN;
+ control_notify(bs);
+
+ /* Enable all timers. */
+ bfd_recvtimer_update(bs);
+ bfd_xmttimer_update(bs, bs->xmt_TO);
+ if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_ECHO)) {
+ bfd_echo_recvtimer_update(bs);
+ bfd_echo_xmttimer_update(bs, bs->echo_xmt_TO);
+ }
+ } else {
+ if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_SHUTDOWN))
+ return CMD_SUCCESS;
+
+ BFD_SET_FLAG(bs->flags, BFD_SESS_FLAG_SHUTDOWN);
+
+ /* Disable all events. */
+ bfd_recvtimer_delete(bs);
+ bfd_echo_recvtimer_delete(bs);
+ bfd_xmttimer_delete(bs);
+ bfd_echo_xmttimer_delete(bs);
+
+ /* Change and notify state change. */
+ bs->ses_state = PTM_BFD_ADM_DOWN;
+ control_notify(bs);
+
+ ptm_bfd_snd(bs, 0);
+ }
+
+ return CMD_SUCCESS;
+}
+
+DEFPY(bfd_peer_echo, bfd_peer_echo_cmd, "[no] echo-mode",
+ NO_STR "Configure echo mode\n")
+{
+ struct bfd_session *bs;
+
+ bs = VTY_GET_CONTEXT(bfd_session);
+ if (no) {
+ if (!BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_ECHO))
+ return CMD_SUCCESS;
+
+ BFD_UNSET_FLAG(bs->flags, BFD_SESS_FLAG_ECHO);
+ ptm_bfd_echo_stop(bs, 0);
+ } else {
+ if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_ECHO))
+ return CMD_SUCCESS;
+
+ BFD_SET_FLAG(bs->flags, BFD_SESS_FLAG_ECHO);
+ /* Apply setting immediately. */
+ if (!BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_SHUTDOWN)) {
+ ptm_bfd_echo_start(bs);
+ bfd_echo_recvtimer_update(bs);
+ }
+ }
+
+ return CMD_SUCCESS;
+}
+
+DEFPY(bfd_peer_label, bfd_peer_label_cmd, "label WORD$label",
+ "Register peer label\n"
+ "Register peer label identification\n")
+{
+ struct bfd_session *bs;
+
+ /* Validate label length. */
+ if (strlen(label) >= MAXNAMELEN) {
+ vty_out(vty, "%% Label name is too long\n");
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+
+ bs = VTY_GET_CONTEXT(bfd_session);
+ if (bfd_session_update_label(bs, label) == -1) {
+ vty_out(vty, "%% Failed to update peer label.\n");
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+
+ return CMD_SUCCESS;
+}
+
+DEFPY(bfd_no_peer, bfd_no_peer_cmd,
+ "no peer <A.B.C.D|X:X::X:X>$peer [{multihop|local-address <A.B.C.D|X:X::X:X>$local|interface IFNAME$ifname|vrf NAME$vrfname}]",
+ NO_STR
+ PEER_STR PEER_IPV4_STR PEER_IPV6_STR
+ MHOP_STR
+ LOCAL_STR LOCAL_IPV4_STR LOCAL_IPV6_STR
+ INTERFACE_STR
+ LOCAL_INTF_STR
+ VRF_STR VRF_NAME_STR)
+{
+ int idx;
+ bool mhop;
+ struct bfd_peer_cfg bpc;
+ struct sockaddr_any psa, lsa, *lsap;
+ char errormsg[128];
+
+ strtosa(peer_str, &psa);
+ if (local) {
+ strtosa(local_str, &lsa);
+ lsap = &lsa;
+ } else {
+ lsap = NULL;
+ }
+
+ idx = 0;
+ mhop = argv_find(argv, argc, "multihop", &idx);
+
+ if (bfd_configure_peer(&bpc, mhop, &psa, lsap, ifname, vrfname,
+ errormsg, sizeof(errormsg))
+ != 0) {
+ vty_out(vty, "%% Invalid peer configuration: %s\n", errormsg);
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+
+ if (ptm_bfd_ses_del(&bpc) != 0) {
+ vty_out(vty, "%% Failed to remove peer.\n");
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+
+ return CMD_SUCCESS;
+}
+
+
+/*
+ * Show commands helper functions
+ */
+static void _display_peer(struct vty *vty, struct bfd_session *bs)
+{
+ char buf[256];
+ time_t now;
+
+ if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH)) {
+ vty_out(vty, "\tpeer %s", satostr(&bs->mhop.peer));
+ vty_out(vty, " multihop");
+ vty_out(vty, " local-address %s", satostr(&bs->mhop.local));
+ if (bs->mhop.vrf_name[0])
+ vty_out(vty, " vrf %s", bs->mhop.vrf_name);
+ vty_out(vty, "\n");
+ } else {
+ vty_out(vty, "\tpeer %s", satostr(&bs->shop.peer));
+ if (bs->local_address.sa_sin.sin_family != AF_UNSPEC)
+ vty_out(vty, " local-address %s",
+ satostr(&bs->local_address));
+ if (bs->shop.port_name[0])
+ vty_out(vty, " interface %s", bs->shop.port_name);
+ vty_out(vty, "\n");
+ }
+
+ if (bs->pl)
+ vty_out(vty, "\t\tlabel: %s\n", bs->pl->pl_label);
+
+ vty_out(vty, "\t\tID: %u\n", bs->discrs.my_discr);
+ vty_out(vty, "\t\tRemote ID: %u\n", bs->discrs.remote_discr);
+
+ vty_out(vty, "\t\tStatus: ");
+ switch (bs->ses_state) {
+ case PTM_BFD_ADM_DOWN:
+ vty_out(vty, "shutdown\n");
+ break;
+ case PTM_BFD_DOWN:
+ vty_out(vty, "down\n");
+
+ now = monotime(NULL);
+ integer2timestr(now - bs->downtime.tv_sec, buf, sizeof(buf));
+ vty_out(vty, "\t\tDowntime: %s\n", buf);
+ break;
+ case PTM_BFD_INIT:
+ vty_out(vty, "init\n");
+ break;
+ case PTM_BFD_UP:
+ vty_out(vty, "up\n");
+
+ now = monotime(NULL);
+ integer2timestr(now - bs->uptime.tv_sec, buf, sizeof(buf));
+ vty_out(vty, "\t\tUptime: %s\n", buf);
+ break;
+
+ default:
+ vty_out(vty, "unknown\n");
+ break;
+ }
+
+ vty_out(vty, "\t\tDiagnostics: %s\n", diag2str(bs->local_diag));
+ vty_out(vty, "\t\tRemote diagnostics: %s\n", diag2str(bs->remote_diag));
+
+ vty_out(vty, "\t\tLocal timers:\n");
+ vty_out(vty, "\t\t\tReceive interval: %" PRIu32 "ms\n",
+ bs->timers.required_min_rx / 1000);
+ vty_out(vty, "\t\t\tTransmission interval: %" PRIu32 "ms",
+ bs->timers.desired_min_tx / 1000);
+ if (bs->up_min_tx != bs->timers.desired_min_tx)
+ vty_out(vty, " (configured %" PRIu32 "ms)\n",
+ bs->up_min_tx / 1000);
+ else
+ vty_out(vty, "\n");
+
+ vty_out(vty, "\t\t\tEcho transmission interval: ");
+ if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_ECHO))
+ vty_out(vty, "%" PRIu32 "ms\n",
+ bs->timers.required_min_echo / 1000);
+ else
+ vty_out(vty, "disabled\n");
+
+ vty_out(vty, "\t\tRemote timers:\n");
+ vty_out(vty, "\t\t\tReceive interval: %" PRIu32 "ms\n",
+ bs->remote_timers.required_min_rx / 1000);
+ vty_out(vty, "\t\t\tTransmission interval: %" PRIu32 "ms\n",
+ bs->remote_timers.desired_min_tx / 1000);
+ vty_out(vty, "\t\t\tEcho transmission interval: %" PRIu32 "ms\n",
+ bs->remote_timers.required_min_echo / 1000);
+
+ vty_out(vty, "\n");
+}
+
+static struct json_object *__display_peer_json(struct bfd_session *bs)
+{
+ struct json_object *jo = json_object_new_object();
+
+ if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH)) {
+ json_object_boolean_true_add(jo, "multihop");
+ json_object_string_add(jo, "peer", satostr(&bs->mhop.peer));
+ json_object_string_add(jo, "local", satostr(&bs->mhop.local));
+ if (bs->mhop.vrf_name[0])
+ json_object_string_add(jo, "vrf", bs->mhop.vrf_name);
+ } else {
+ json_object_boolean_false_add(jo, "multihop");
+ json_object_string_add(jo, "peer", satostr(&bs->shop.peer));
+ if (bs->local_address.sa_sin.sin_family != AF_UNSPEC)
+ json_object_string_add(jo, "local",
+ satostr(&bs->local_address));
+ if (bs->shop.port_name[0])
+ json_object_string_add(jo, "interface",
+ bs->shop.port_name);
+ }
+
+ if (bs->pl)
+ json_object_string_add(jo, "label", bs->pl->pl_label);
+
+ json_object_int_add(jo, "id", bs->discrs.my_discr);
+ json_object_int_add(jo, "remote-id", bs->discrs.remote_discr);
+
+ switch (bs->ses_state) {
+ case PTM_BFD_ADM_DOWN:
+ json_object_string_add(jo, "status", "shutdown");
+ break;
+ case PTM_BFD_DOWN:
+ json_object_string_add(jo, "status", "down");
+ json_object_int_add(jo, "downtime",
+ monotime(NULL) - bs->downtime.tv_sec);
+ break;
+ case PTM_BFD_INIT:
+ json_object_string_add(jo, "status", "init");
+ break;
+ case PTM_BFD_UP:
+ json_object_string_add(jo, "status", "up");
+ json_object_int_add(jo, "uptime",
+ monotime(NULL) - bs->uptime.tv_sec);
+ break;
+
+ default:
+ json_object_string_add(jo, "status", "unknown");
+ break;
+ }
+
+ json_object_string_add(jo, "diagnostic", diag2str(bs->local_diag));
+ json_object_string_add(jo, "remote-diagnostic",
+ diag2str(bs->remote_diag));
+
+ json_object_int_add(jo, "receive-interval",
+ bs->timers.required_min_rx / 1000);
+ json_object_int_add(jo, "transmit-interval",
+ bs->timers.desired_min_tx / 1000);
+ if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_ECHO))
+ json_object_int_add(jo, "echo-interval",
+ bs->timers.required_min_echo / 1000);
+ else
+ json_object_int_add(jo, "echo-interval", 0);
+
+ json_object_int_add(jo, "remote-receive-interval",
+ bs->remote_timers.required_min_rx / 1000);
+ json_object_int_add(jo, "remote-transmit-interval",
+ bs->remote_timers.desired_min_tx / 1000);
+ json_object_int_add(jo, "remote-echo-interval",
+ bs->remote_timers.required_min_echo / 1000);
+
+ return jo;
+}
+
+static void _display_peer_json(struct vty *vty, struct bfd_session *bs)
+{
+ struct json_object *jo = __display_peer_json(bs);
+
+ vty_out(vty, "%s\n", json_object_to_json_string_ext(jo, 0));
+ json_object_free(jo);
+}
+
+static void _display_peer_iter(struct hash_backet *hb, void *arg)
+{
+ struct vty *vty = arg;
+ struct bfd_session *bs = hb->data;
+
+ _display_peer(vty, bs);
+}
+
+static void _display_peer_json_iter(struct hash_backet *hb, void *arg)
+{
+ struct json_object *jo = arg, *jon = NULL;
+ struct bfd_session *bs = hb->data;
+
+ jon = __display_peer_json(bs);
+ if (jon == NULL) {
+ log_warning("%s: not enough memory", __func__);
+ return;
+ }
+
+ json_object_array_add(jo, jon);
+}
+
+static void _display_all_peers(struct vty *vty, bool use_json)
+{
+ struct json_object *jo;
+
+ if (use_json == false) {
+ bfd_id_iterate(_display_peer_iter, vty);
+ return;
+ }
+
+ jo = json_object_new_array();
+ bfd_id_iterate(_display_peer_json_iter, jo);
+
+ vty_out(vty, "%s\n", json_object_to_json_string_ext(jo, 0));
+ json_object_free(jo);
+}
+
+DEFPY(bfd_show_peers, bfd_show_peers_cmd, "show bfd peers [json]",
+ SHOW_STR
+ "Bidirection Forwarding Detection\n"
+ "BFD peers status\n"
+ JSON_STR)
+{
+ bool json = use_json(argc, argv);
+
+ if (json) {
+ _display_all_peers(vty, true);
+ } else {
+ vty_out(vty, "BFD Peers:\n");
+ _display_all_peers(vty, false);
+ }
+
+ return CMD_SUCCESS;
+}
+
+DEFPY(bfd_show_peer, bfd_show_peer_cmd,
+ "show bfd peer <WORD$label|<A.B.C.D|X:X::X:X>$peer [{multihop|local-address <A.B.C.D|X:X::X:X>$local|interface IFNAME$ifname|vrf NAME$vrfname}]> [json]",
+ SHOW_STR
+ "Bidirection Forwarding Detection\n"
+ "BFD peers status\n"
+ "Peer label\n"
+ PEER_IPV4_STR PEER_IPV6_STR
+ MHOP_STR
+ LOCAL_STR LOCAL_IPV4_STR LOCAL_IPV6_STR
+ INTERFACE_STR
+ LOCAL_INTF_STR
+ VRF_STR VRF_NAME_STR
+ JSON_STR)
+{
+ int idx;
+ bool mhop;
+ struct bfd_session *bs = NULL;
+ struct peer_label *pl;
+ struct bfd_peer_cfg bpc;
+ struct sockaddr_any psa, lsa, *lsap;
+ char errormsg[128];
+
+ /* Look up the BFD peer. */
+ if (label) {
+ pl = pl_find(label);
+ if (pl)
+ bs = pl->pl_bs;
+ } else {
+ strtosa(peer_str, &psa);
+ if (local) {
+ strtosa(local_str, &lsa);
+ lsap = &lsa;
+ } else
+ lsap = NULL;
+
+ idx = 0;
+ mhop = argv_find(argv, argc, "multihop", &idx);
+
+ if (bfd_configure_peer(&bpc, mhop, &psa, lsap, ifname, vrfname,
+ errormsg, sizeof(errormsg))
+ != 0) {
+ vty_out(vty, "%% Invalid peer configuration: %s\n",
+ errormsg);
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+
+ bs = bs_peer_find(&bpc);
+ }
+
+ /* Find peer data. */
+ if (bs == NULL) {
+ vty_out(vty, "%% Unable to find 'peer %s",
+ label ? label : peer_str);
+ if (ifname)
+ vty_out(vty, " interface %s", ifname);
+ if (local)
+ vty_out(vty, " local-address %s", local_str);
+ if (vrfname)
+ vty_out(vty, " vrf %s", vrfname);
+ vty_out(vty, "'\n");
+
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+
+ if (use_json(argc, argv)) {
+ _display_peer_json(vty, bs);
+ } else {
+ vty_out(vty, "BFD Peer:\n");
+ _display_peer(vty, bs);
+ }
+
+ return CMD_SUCCESS;
+}
+
+
+/*
+ * Function definitions.
+ */
+
+/*
+ * Configuration rules:
+ *
+ * Single hop:
+ * peer + (optional vxlan or interface name)
+ *
+ * Multi hop:
+ * peer + local + (optional vrf)
+ *
+ * Anything else is misconfiguration.
+ */
+static int bfd_configure_peer(struct bfd_peer_cfg *bpc, bool mhop,
+ const struct sockaddr_any *peer,
+ const struct sockaddr_any *local,
+ const char *ifname, const char *vrfname,
+ char *ebuf, size_t ebuflen)
+{
+ memset(bpc, 0, sizeof(*bpc));
+
+ /* Defaults */
+ bpc->bpc_shutdown = true;
+ bpc->bpc_detectmultiplier = BPC_DEF_DETECTMULTIPLIER;
+ bpc->bpc_recvinterval = BPC_DEF_RECEIVEINTERVAL;
+ bpc->bpc_txinterval = BPC_DEF_TRANSMITINTERVAL;
+ bpc->bpc_echointerval = BPC_DEF_ECHOINTERVAL;
+ bpc->bpc_lastevent = monotime(NULL);
+
+ /* Safety check: when no error buf is provided len must be zero. */
+ if (ebuf == NULL)
+ ebuflen = 0;
+
+ /* Peer is always mandatory. */
+ if (peer == NULL) {
+ snprintf(ebuf, ebuflen, "peer must not be empty");
+ return -1;
+ }
+
+ /* Validate address families. */
+ if (peer->sa_sin.sin_family == AF_INET) {
+ if (local && local->sa_sin.sin_family != AF_INET) {
+ snprintf(ebuf, ebuflen,
+ "local is IPv6, but peer is IPv4");
+ return -1;
+ }
+
+ bpc->bpc_ipv4 = true;
+ } else if (peer->sa_sin.sin_family == AF_INET6) {
+ if (local && local->sa_sin.sin_family != AF_INET6) {
+ snprintf(ebuf, ebuflen,
+ "local is IPv4, but peer is IPv6");
+ return -1;
+ }
+
+ bpc->bpc_ipv4 = false;
+ } else {
+ snprintf(ebuf, ebuflen, "invalid peer address family");
+ return -1;
+ }
+
+ /* Copy local and/or peer addresses. */
+ if (local)
+ bpc->bpc_local = *local;
+
+ if (peer) {
+ bpc->bpc_peer = *peer;
+ } else {
+ /* Peer configuration is mandatory. */
+ snprintf(ebuf, ebuflen, "no peer configured");
+ return -1;
+ }
+
+ bpc->bpc_mhop = mhop;
+
+#if 0
+ /* Handle VxLAN configuration. */
+ if (vxlan >= 0) {
+ if (vxlan > ((1 << 24) - 1)) {
+ snprintf(ebuf, ebuflen, "invalid VxLAN %d", vxlan);
+ return -1;
+ }
+ if (bpc->bpc_mhop) {
+ snprintf(ebuf, ebuflen,
+ "multihop doesn't accept VxLAN");
+ return -1;
+ }
+
+ bpc->bpc_vxlan = vxlan;
+ }
+#endif /* VxLAN */
+
+ /* Handle interface specification configuration. */
+ if (ifname) {
+ if (bpc->bpc_mhop) {
+ snprintf(ebuf, ebuflen,
+ "multihop doesn't accept interface names");
+ return -1;
+ }
+
+ bpc->bpc_has_localif = true;
+ if (strlcpy(bpc->bpc_localif, ifname, sizeof(bpc->bpc_localif))
+ > sizeof(bpc->bpc_localif)) {
+ snprintf(ebuf, ebuflen, "interface name too long");
+ return -1;
+ }
+ }
+
+ /* Handle VRF configuration. */
+ if (vrfname) {
+ bpc->bpc_has_vrfname = true;
+ if (strlcpy(bpc->bpc_vrfname, vrfname, sizeof(bpc->bpc_vrfname))
+ > sizeof(bpc->bpc_vrfname)) {
+ snprintf(ebuf, ebuflen, "vrf name too long");
+ return -1;
+ }
+ }
+
+ return 0;
+}
+static int bfdd_write_config(struct vty *vty)
+{
+ vty_out(vty, "bfd\n");
+ vty_out(vty, "!\n");
+ return 0;
+}
+
+static void _bfdd_peer_write_config(struct hash_backet *hb, void *arg)
+{
+ struct vty *vty = arg;
+ struct bfd_session *bs = hb->data;
+
+ if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH)) {
+ vty_out(vty, " peer %s", satostr(&bs->mhop.peer));
+ vty_out(vty, " multihop");
+ vty_out(vty, " local-address %s", satostr(&bs->mhop.local));
+ if (bs->mhop.vrf_name[0])
+ vty_out(vty, " vrf %s", bs->mhop.vrf_name);
+ vty_out(vty, "\n");
+ } else {
+ vty_out(vty, " peer %s", satostr(&bs->shop.peer));
+ if (bs->local_address.sa_sin.sin_family != AF_UNSPEC)
+ vty_out(vty, " local-address %s",
+ satostr(&bs->local_address));
+ if (bs->shop.port_name[0])
+ vty_out(vty, " interface %s", bs->shop.port_name);
+ vty_out(vty, "\n");
+ }
+
+ if (bs->detect_mult != BPC_DEF_DETECTMULTIPLIER)
+ vty_out(vty, " detect-multiplier %d\n", bs->detect_mult);
+ if (bs->timers.required_min_rx != (BPC_DEF_RECEIVEINTERVAL * 1000))
+ vty_out(vty, " receive-interval %" PRIu32 "\n",
+ bs->timers.required_min_rx / 1000);
+ if (bs->up_min_tx != (BPC_DEF_TRANSMITINTERVAL * 1000))
+ vty_out(vty, " transmit-interval %" PRIu32 "\n",
+ bs->up_min_tx / 1000);
+ if (bs->timers.required_min_echo != (BPC_DEF_ECHOINTERVAL * 1000))
+ vty_out(vty, " echo-interval %" PRIu32 "\n",
+ bs->timers.required_min_echo / 1000);
+ if (bs->pl)
+ vty_out(vty, " label %s\n", bs->pl->pl_label);
+ if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_ECHO))
+ vty_out(vty, " echo-mode\n");
+
+ vty_out(vty, " %sshutdown\n",
+ BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_SHUTDOWN) ? "" : "no ");
+
+ vty_out(vty, " !\n");
+}
+
+static int bfdd_peer_write_config(struct vty *vty)
+{
+ bfd_id_iterate(_bfdd_peer_write_config, vty);
+ return 1;
+}
+
+struct cmd_node bfd_node = {
+ BFD_NODE,
+ "%s(config-bfd)# ",
+ 1,
+};
+
+struct cmd_node bfd_peer_node = {
+ BFD_PEER_NODE,
+ "%s(config-bfd-peer)# ",
+ 1,
+};
+
+void bfdd_vty_init(void)
+{
+ install_element(ENABLE_NODE, &bfd_show_peers_cmd);
+ install_element(ENABLE_NODE, &bfd_show_peer_cmd);
+ install_element(CONFIG_NODE, &bfd_enter_cmd);
+
+ /* Install BFD node and commands. */
+ install_node(&bfd_node, bfdd_write_config);
+ install_default(BFD_NODE);
+ install_element(BFD_NODE, &bfd_peer_enter_cmd);
+ install_element(BFD_NODE, &bfd_no_peer_cmd);
+
+ /* Install BFD peer node. */
+ install_node(&bfd_peer_node, bfdd_peer_write_config);
+ install_default(BFD_PEER_NODE);
+ install_element(BFD_PEER_NODE, &bfd_peer_detectmultiplier_cmd);
+ install_element(BFD_PEER_NODE, &bfd_peer_recvinterval_cmd);
+ install_element(BFD_PEER_NODE, &bfd_peer_txinterval_cmd);
+ install_element(BFD_PEER_NODE, &bfd_peer_echointerval_cmd);
+ install_element(BFD_PEER_NODE, &bfd_peer_shutdown_cmd);
+ install_element(BFD_PEER_NODE, &bfd_peer_echo_cmd);
+ install_element(BFD_PEER_NODE, &bfd_peer_label_cmd);
+}
diff --git a/bfdd/bsd.c b/bfdd/bsd.c
new file mode 100644
index 0000000000..34a3a1a801
--- /dev/null
+++ b/bfdd/bsd.c
@@ -0,0 +1,290 @@
+/*
+ * *BSD specific code
+ *
+ * Copyright (C) 2018 Network Device Education Foundation, Inc. ("NetDEF")
+ *
+ * FRR is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * FRR is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with FRR; see the file COPYING. If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#include <zebra.h>
+
+#ifdef BFD_BSD
+
+#include <net/if.h>
+#include <net/if_types.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <ifaddrs.h>
+
+#include "bfd.h"
+
+/*
+ * Prototypes
+ */
+static const char *sockaddr_to_string(const void *sv, char *buf, size_t buflen);
+
+/*
+ * Definitions.
+ */
+static const char *sockaddr_to_string(const void *sv, char *buf, size_t buflen)
+{
+ const struct sockaddr *sa = sv;
+ const struct sockaddr_in *sin = sv;
+ const struct sockaddr_in6 *sin6 = sv;
+ int unknown = 1;
+
+ switch (sa->sa_family) {
+ case AF_INET:
+ if (inet_ntop(AF_INET, &sin->sin_addr, buf, buflen) != NULL)
+ unknown = 0;
+ break;
+
+ case AF_INET6:
+ if (inet_ntop(AF_INET6, &sin6->sin6_addr, buf, buflen) != NULL)
+ unknown = 0;
+ break;
+ }
+ if (unknown == 0)
+ return buf;
+
+ snprintf(buf, buflen, "unknown (af=%d)", sa->sa_family);
+ return buf;
+}
+
+int ptm_bfd_fetch_ifindex(const char *ifname)
+{
+ return if_nametoindex(ifname);
+}
+
+void ptm_bfd_fetch_local_mac(const char *ifname, uint8_t *mac)
+{
+ struct ifaddrs *ifap, *ifa;
+ struct if_data *ifi;
+ struct sockaddr_dl *sdl;
+ size_t maclen;
+
+ /* Always clean the target, zeroed macs mean failure. */
+ memset(mac, 0, ETHERNET_ADDRESS_LENGTH);
+
+ if (getifaddrs(&ifap) != 0)
+ return;
+
+ for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) {
+ /* Find interface with that name. */
+ if (strcmp(ifa->ifa_name, ifname) != 0)
+ continue;
+ /* Skip non link addresses. We want the MAC address. */
+ if (ifa->ifa_addr->sa_family != AF_LINK)
+ continue;
+
+ sdl = (struct sockaddr_dl *)ifa->ifa_addr;
+ ifi = (struct if_data *)ifa->ifa_data;
+ /* Skip non ethernet related data. */
+ if (ifi->ifi_type != IFT_ETHER)
+ continue;
+
+ if (sdl->sdl_alen != ETHERNET_ADDRESS_LENGTH)
+ log_warning("%s:%d mac address length %d (expected %d)",
+ __func__, __LINE__, sdl->sdl_alen,
+ ETHERNET_ADDRESS_LENGTH);
+
+ maclen = (sdl->sdl_alen > ETHERNET_ADDRESS_LENGTH)
+ ? ETHERNET_ADDRESS_LENGTH
+ : sdl->sdl_alen;
+ memcpy(mac, LLADDR(sdl), maclen);
+ break;
+ }
+
+ freeifaddrs(ifap);
+}
+
+
+/* Was _fetch_portname_from_ifindex() */
+void fetch_portname_from_ifindex(int ifindex, char *ifname, size_t ifnamelen)
+{
+ char ifname_tmp[IF_NAMESIZE];
+
+ /* Set ifname to empty to signalize failures. */
+ memset(ifname, 0, ifnamelen);
+
+ if (if_indextoname(ifindex, ifname_tmp) == NULL)
+ return;
+
+ if (strlcpy(ifname, ifname_tmp, ifnamelen) > ifnamelen)
+ log_warning("%s:%d interface name truncated", __func__,
+ __LINE__);
+}
+
+int ptm_bfd_echo_sock_init(void)
+{
+ int s, ttl, yes = 1;
+ struct sockaddr_in sin;
+
+ s = socket(AF_INET, SOCK_DGRAM, PF_UNSPEC);
+ if (s == -1) {
+ log_error("echo-socket: creation failed: %s", strerror(errno));
+ return -1;
+ }
+
+ memset(&sin, 0, sizeof(sin));
+#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
+ /* OmniOS doesn't have this field, but uses this code. */
+ sin.sin_len = sizeof(sin);
+#endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */
+ sin.sin_family = AF_INET;
+ sin.sin_port = htons(3785);
+ if (bind(s, (struct sockaddr *)&sin, sizeof(sin)) == -1) {
+ log_error("echo-socket: bind failure: %s", strerror(errno));
+ close(s);
+ return -1;
+ }
+
+ if (setsockopt(s, IPPROTO_IP, IP_RECVTTL, &yes, sizeof(yes)) == -1) {
+ log_error("echo-socket: setsockopt(IP_RECVTTL): %s",
+ strerror(errno));
+ close(s);
+ return -1;
+ }
+
+ ttl = BFD_TTL_VAL;
+ if (setsockopt(s, IPPROTO_IP, IP_TTL, &ttl, sizeof(ttl)) == -1) {
+ log_error("echo-socket: setsockopt(IP_TTL): %s",
+ strerror(errno));
+ close(s);
+ return -1;
+ }
+
+ return s;
+}
+
+ssize_t bsd_echo_sock_read(int sd, uint8_t *buf, ssize_t *buflen,
+ struct sockaddr_storage *ss, socklen_t *sslen,
+ uint8_t *ttl, uint32_t *id)
+{
+ struct cmsghdr *cmsg;
+ struct bfd_echo_pkt *bep;
+ ssize_t readlen;
+ struct iovec iov;
+ struct msghdr msg;
+ uint8_t msgctl[255];
+ char errbuf[255];
+
+ /* Prepare socket read. */
+ memset(ss, 0, sizeof(*ss));
+ memset(&msg, 0, sizeof(msg));
+ iov.iov_base = buf;
+ iov.iov_len = *buflen;
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = 1;
+ msg.msg_control = msgctl;
+ msg.msg_controllen = sizeof(msgctl);
+ msg.msg_name = ss;
+ msg.msg_namelen = *sslen;
+
+ /* Read the socket and treat errors. */
+ readlen = recvmsg(sd, &msg, 0);
+ if (readlen == 0) {
+ log_error("%s: recvmsg: socket closed", __func__);
+ return -1;
+ }
+ if (readlen == -1) {
+ if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR)
+ return -1;
+
+ log_error("%s: recvmsg: (%d) %s", __func__, errno,
+ strerror(errno));
+ return -1;
+ }
+ /* Short packet, better not risk reading it. */
+ if (readlen < (ssize_t)sizeof(*bep)) {
+ log_warning("%s: short packet (%ld of %d) from %s", __func__,
+ readlen, sizeof(*bep),
+ sockaddr_to_string(ss, errbuf, sizeof(errbuf)));
+ return -1;
+ }
+ *buflen = readlen;
+
+ /* Read TTL information. */
+ *ttl = 0;
+ for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL;
+ cmsg = CMSG_NXTHDR(&msg, cmsg)) {
+ if (cmsg->cmsg_level != IPPROTO_IP)
+ continue;
+ if (cmsg->cmsg_type != IP_RECVTTL)
+ continue;
+
+ *ttl = *(uint8_t *)CMSG_DATA(cmsg);
+ break;
+ }
+ if (*ttl == 0) {
+ log_debug("%s: failed to read TTL", __func__);
+ return -1;
+ }
+
+ /* Read my discriminator from BFD Echo packet. */
+ bep = (struct bfd_echo_pkt *)buf;
+ *id = bep->my_discr;
+ if (*id == 0) {
+ log_debug("%s: invalid packet discriminator from: %s", __func__,
+ sockaddr_to_string(ss, errbuf, sizeof(errbuf)));
+ return -1;
+ }
+
+ /* Set the returned sockaddr new length. */
+ *sslen = msg.msg_namelen;
+
+ return 0;
+}
+
+int ptm_bfd_vxlan_sock_init(void)
+{
+ /* TODO: not supported yet. */
+ return -1;
+}
+
+int bp_bind_dev(int sd, const char *dev)
+{
+ /*
+ * *BSDs don't support `SO_BINDTODEVICE`, instead you must
+ * manually specify the main address of the interface or use
+ * BPF on the socket descriptor.
+ */
+ return 0;
+}
+
+uint16_t udp4_checksum(struct ip *ip, uint8_t *buf, int len)
+{
+ char *ptr;
+ struct udp_psuedo_header pudp_hdr;
+ uint16_t csum;
+
+ pudp_hdr.saddr = ip->ip_src.s_addr;
+ pudp_hdr.daddr = ip->ip_dst.s_addr;
+ pudp_hdr.reserved = 0;
+ pudp_hdr.protocol = ip->ip_p;
+ pudp_hdr.len = htons(len);
+
+ ptr = XMALLOC(MTYPE_BFDD_TMP, UDP_PSUEDO_HDR_LEN + len);
+ memcpy(ptr, &pudp_hdr, UDP_PSUEDO_HDR_LEN);
+ memcpy(ptr + UDP_PSUEDO_HDR_LEN, buf, len);
+
+ csum = checksum((uint16_t *)ptr, UDP_PSUEDO_HDR_LEN + len);
+ XFREE(MTYPE_BFDD_TMP, ptr);
+ return csum;
+}
+
+#endif /* BFD_BSD */
diff --git a/bfdd/config.c b/bfdd/config.c
new file mode 100644
index 0000000000..0e0d8b7d70
--- /dev/null
+++ b/bfdd/config.c
@@ -0,0 +1,606 @@
+/*********************************************************************
+ * Copyright 2017-2018 Network Device Education Foundation, Inc. ("NetDEF")
+ *
+ * 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
+ *
+ * config.c: implements the BFD daemon configuration handling.
+ *
+ * Authors
+ * -------
+ * Rafael Zalamena <rzalamena@opensourcerouting.org>
+ */
+
+#include <zebra.h>
+
+#include <string.h>
+
+#include "lib/json.h"
+
+#include "bfd.h"
+
+/*
+ * Definitions
+ */
+enum peer_list_type {
+ PLT_IPV4,
+ PLT_IPV6,
+ PLT_LABEL,
+};
+
+
+/*
+ * Prototypes
+ */
+static int parse_config_json(struct json_object *jo, bpc_handle h, void *arg);
+static int parse_list(struct json_object *jo, enum peer_list_type plt,
+ bpc_handle h, void *arg);
+static int parse_peer_config(struct json_object *jo, struct bfd_peer_cfg *bpc);
+static int parse_peer_label_config(struct json_object *jo,
+ struct bfd_peer_cfg *bpc);
+
+static int config_add(struct bfd_peer_cfg *bpc, void *arg);
+static int config_del(struct bfd_peer_cfg *bpc, void *arg);
+
+static int json_object_add_peer(struct json_object *jo, struct bfd_session *bs);
+
+
+/*
+ * Implementation
+ */
+static int config_add(struct bfd_peer_cfg *bpc,
+ void *arg __attribute__((unused)))
+{
+ return ptm_bfd_sess_new(bpc) == NULL;
+}
+
+static int config_del(struct bfd_peer_cfg *bpc,
+ void *arg __attribute__((unused)))
+{
+ return ptm_bfd_ses_del(bpc) != 0;
+}
+
+static int parse_config_json(struct json_object *jo, bpc_handle h, void *arg)
+{
+ const char *key, *sval;
+ struct json_object *jo_val;
+ struct json_object_iterator joi, join;
+ int error = 0;
+
+ JSON_FOREACH (jo, joi, join) {
+ key = json_object_iter_peek_name(&joi);
+ jo_val = json_object_iter_peek_value(&joi);
+
+ if (strcmp(key, "ipv4") == 0) {
+ error += parse_list(jo_val, PLT_IPV4, h, arg);
+ } else if (strcmp(key, "ipv6") == 0) {
+ error += parse_list(jo_val, PLT_IPV6, h, arg);
+ } else if (strcmp(key, "label") == 0) {
+ error += parse_list(jo_val, PLT_LABEL, h, arg);
+ } else {
+ sval = json_object_get_string(jo_val);
+ log_warning("%s:%d invalid configuration: %s", __func__,
+ __LINE__, sval);
+ error++;
+ }
+ }
+
+ /*
+ * Our callers never call free() on json_object and only expect
+ * the return value, so lets free() it here.
+ */
+ json_object_put(jo);
+
+ return error;
+}
+
+int parse_config(const char *fname)
+{
+ struct json_object *jo;
+
+ jo = json_object_from_file(fname);
+ if (jo == NULL)
+ return -1;
+
+ return parse_config_json(jo, config_add, NULL);
+}
+
+static int parse_list(struct json_object *jo, enum peer_list_type plt,
+ bpc_handle h, void *arg)
+{
+ struct json_object *jo_val;
+ struct bfd_peer_cfg bpc;
+ int allen, idx;
+ int error = 0, result;
+
+ allen = json_object_array_length(jo);
+ for (idx = 0; idx < allen; idx++) {
+ jo_val = json_object_array_get_idx(jo, idx);
+
+ /* Set defaults. */
+ memset(&bpc, 0, sizeof(bpc));
+ bpc.bpc_detectmultiplier = BFD_DEFDETECTMULT;
+ bpc.bpc_recvinterval = BFD_DEFREQUIREDMINRX;
+ bpc.bpc_txinterval = BFD_DEFDESIREDMINTX;
+ bpc.bpc_echointerval = BFD_DEF_REQ_MIN_ECHO;
+
+ switch (plt) {
+ case PLT_IPV4:
+ log_debug("ipv4 peers %d:", allen);
+ bpc.bpc_ipv4 = true;
+ break;
+ case PLT_IPV6:
+ log_debug("ipv6 peers %d:", allen);
+ bpc.bpc_ipv4 = false;
+ break;
+ case PLT_LABEL:
+ log_debug("label peers %d:", allen);
+ if (parse_peer_label_config(jo_val, &bpc) != 0) {
+ error++;
+ continue;
+ }
+ break;
+
+ default:
+ error++;
+ log_error("%s:%d: unsupported peer type", __func__,
+ __LINE__);
+ break;
+ }
+
+ result = parse_peer_config(jo_val, &bpc);
+ error += result;
+ if (result == 0)
+ error += (h(&bpc, arg) != 0);
+ }
+
+ return error;
+}
+
+static int parse_peer_config(struct json_object *jo, struct bfd_peer_cfg *bpc)
+{
+ const char *key, *sval;
+ struct json_object *jo_val;
+ struct json_object_iterator joi, join;
+ int family_type = (bpc->bpc_ipv4) ? AF_INET : AF_INET6;
+ int error = 0;
+
+ log_debug("\tpeer: %s", bpc->bpc_ipv4 ? "ipv4" : "ipv6");
+
+ JSON_FOREACH (jo, joi, join) {
+ key = json_object_iter_peek_name(&joi);
+ jo_val = json_object_iter_peek_value(&joi);
+
+ if (strcmp(key, "multihop") == 0) {
+ bpc->bpc_mhop = json_object_get_boolean(jo_val);
+ log_debug("\tmultihop: %s",
+ bpc->bpc_mhop ? "true" : "false");
+ } else if (strcmp(key, "peer-address") == 0) {
+ sval = json_object_get_string(jo_val);
+ if (strtosa(sval, &bpc->bpc_peer) != 0
+ || bpc->bpc_peer.sa_sin.sin_family != family_type) {
+ log_info(
+ "%s:%d failed to parse peer-address '%s'",
+ __func__, __LINE__, sval);
+ error++;
+ }
+ log_debug("\tpeer-address: %s", sval);
+ } else if (strcmp(key, "local-address") == 0) {
+ sval = json_object_get_string(jo_val);
+ if (strtosa(sval, &bpc->bpc_local) != 0
+ || bpc->bpc_local.sa_sin.sin_family
+ != family_type) {
+ log_info(
+ "%s:%d failed to parse local-address '%s'",
+ __func__, __LINE__, sval);
+ error++;
+ }
+ log_debug("\tlocal-address: %s", sval);
+ } else if (strcmp(key, "local-interface") == 0) {
+ bpc->bpc_has_localif = true;
+ sval = json_object_get_string(jo_val);
+ if (strlcpy(bpc->bpc_localif, sval,
+ sizeof(bpc->bpc_localif))
+ > sizeof(bpc->bpc_localif)) {
+ log_debug("\tlocal-interface: %s (truncated)");
+ error++;
+ } else {
+ log_debug("\tlocal-interface: %s", sval);
+ }
+ } else if (strcmp(key, "vxlan") == 0) {
+ bpc->bpc_vxlan = json_object_get_int64(jo_val);
+ bpc->bpc_has_vxlan = true;
+ log_debug("\tvxlan: %ld", bpc->bpc_vxlan);
+ } else if (strcmp(key, "vrf-name") == 0) {
+ bpc->bpc_has_vrfname = true;
+ sval = json_object_get_string(jo_val);
+ if (strlcpy(bpc->bpc_vrfname, sval,
+ sizeof(bpc->bpc_vrfname))
+ > sizeof(bpc->bpc_vrfname)) {
+ log_debug("\tvrf-name: %s (truncated)", sval);
+ error++;
+ } else {
+ log_debug("\tvrf-name: %s", sval);
+ }
+ } else if (strcmp(key, "detect-multiplier") == 0) {
+ bpc->bpc_detectmultiplier =
+ json_object_get_int64(jo_val);
+ bpc->bpc_has_detectmultiplier = true;
+ log_debug("\tdetect-multiplier: %llu",
+ bpc->bpc_detectmultiplier);
+ } else if (strcmp(key, "receive-interval") == 0) {
+ bpc->bpc_recvinterval = json_object_get_int64(jo_val);
+ bpc->bpc_has_recvinterval = true;
+ log_debug("\treceive-interval: %llu",
+ bpc->bpc_recvinterval);
+ } else if (strcmp(key, "transmit-interval") == 0) {
+ bpc->bpc_txinterval = json_object_get_int64(jo_val);
+ bpc->bpc_has_txinterval = true;
+ log_debug("\ttransmit-interval: %llu",
+ bpc->bpc_txinterval);
+ } else if (strcmp(key, "echo-interval") == 0) {
+ bpc->bpc_echointerval = json_object_get_int64(jo_val);
+ bpc->bpc_has_echointerval = true;
+ log_debug("\techo-interval: %llu",
+ bpc->bpc_echointerval);
+ } else if (strcmp(key, "create-only") == 0) {
+ bpc->bpc_createonly = json_object_get_boolean(jo_val);
+ log_debug("\tcreate-only: %s",
+ bpc->bpc_createonly ? "true" : "false");
+ } else if (strcmp(key, "shutdown") == 0) {
+ bpc->bpc_shutdown = json_object_get_boolean(jo_val);
+ log_debug("\tshutdown: %s",
+ bpc->bpc_shutdown ? "true" : "false");
+ } else if (strcmp(key, "echo-mode") == 0) {
+ bpc->bpc_echo = json_object_get_boolean(jo_val);
+ log_debug("\techo-mode: %s",
+ bpc->bpc_echo ? "true" : "false");
+ } else if (strcmp(key, "label") == 0) {
+ bpc->bpc_has_label = true;
+ sval = json_object_get_string(jo_val);
+ if (strlcpy(bpc->bpc_label, sval,
+ sizeof(bpc->bpc_label))
+ > sizeof(bpc->bpc_label)) {
+ log_debug("\tlabel: %s (truncated)", sval);
+ error++;
+ } else {
+ log_debug("\tlabel: %s", sval);
+ }
+ } else {
+ sval = json_object_get_string(jo_val);
+ log_warning("%s:%d invalid configuration: '%s: %s'",
+ __func__, __LINE__, key, sval);
+ error++;
+ }
+ }
+
+ if (bpc->bpc_peer.sa_sin.sin_family == 0) {
+ log_debug("%s:%d no peer address provided", __func__, __LINE__);
+ error++;
+ }
+
+ return error;
+}
+
+static int parse_peer_label_config(struct json_object *jo,
+ struct bfd_peer_cfg *bpc)
+{
+ struct peer_label *pl;
+ struct json_object *label;
+ const char *sval;
+
+ /* Get label and translate it to BFD daemon key. */
+ if (!json_object_object_get_ex(jo, "label", &label))
+ return 1;
+
+ sval = json_object_get_string(label);
+
+ pl = pl_find(sval);
+ if (pl == NULL)
+ return 1;
+
+ log_debug("\tpeer-label: %s", sval);
+
+ /* Translate the label into BFD address keys. */
+ bpc->bpc_ipv4 = !BFD_CHECK_FLAG(pl->pl_bs->flags, BFD_SESS_FLAG_IPV6);
+ bpc->bpc_mhop = BFD_CHECK_FLAG(pl->pl_bs->flags, BFD_SESS_FLAG_MH);
+ if (bpc->bpc_mhop) {
+ bpc->bpc_peer = pl->pl_bs->mhop.peer;
+ bpc->bpc_local = pl->pl_bs->mhop.local;
+ if (pl->pl_bs->mhop.vrf_name[0]) {
+ bpc->bpc_has_vrfname = true;
+ strlcpy(bpc->bpc_vrfname, pl->pl_bs->mhop.vrf_name,
+ sizeof(bpc->bpc_vrfname));
+ }
+ } else {
+ bpc->bpc_peer = pl->pl_bs->shop.peer;
+ if (pl->pl_bs->shop.port_name[0]) {
+ bpc->bpc_has_localif = true;
+ strlcpy(bpc->bpc_localif, pl->pl_bs->shop.port_name,
+ sizeof(bpc->bpc_localif));
+ }
+ }
+
+ return 0;
+}
+
+
+/*
+ * Control socket JSON parsing.
+ */
+int config_request_add(const char *jsonstr)
+{
+ struct json_object *jo;
+
+ jo = json_tokener_parse(jsonstr);
+ if (jo == NULL)
+ return -1;
+
+ return parse_config_json(jo, config_add, NULL);
+}
+
+int config_request_del(const char *jsonstr)
+{
+ struct json_object *jo;
+
+ jo = json_tokener_parse(jsonstr);
+ if (jo == NULL)
+ return -1;
+
+ return parse_config_json(jo, config_del, NULL);
+}
+
+char *config_response(const char *status, const char *error)
+{
+ struct json_object *resp, *jo;
+ char *jsonstr;
+
+ resp = json_object_new_object();
+ if (resp == NULL)
+ return NULL;
+
+ /* Add 'status' response key. */
+ jo = json_object_new_string(status);
+ if (jo == NULL) {
+ json_object_put(resp);
+ return NULL;
+ }
+
+ json_object_object_add(resp, "status", jo);
+
+ /* Add 'error' response key. */
+ if (error != NULL) {
+ jo = json_object_new_string(error);
+ if (jo == NULL) {
+ json_object_put(resp);
+ return NULL;
+ }
+
+ json_object_object_add(resp, "error", jo);
+ }
+
+ /* Generate JSON response. */
+ jsonstr = XSTRDUP(
+ MTYPE_BFDD_NOTIFICATION,
+ json_object_to_json_string_ext(resp, BFDD_JSON_CONV_OPTIONS));
+ json_object_put(resp);
+
+ return jsonstr;
+}
+
+char *config_notify(struct bfd_session *bs)
+{
+ struct json_object *resp;
+ char *jsonstr;
+ time_t now;
+
+ resp = json_object_new_object();
+ if (resp == NULL)
+ return NULL;
+
+ json_object_string_add(resp, "op", BCM_NOTIFY_PEER_STATUS);
+
+ json_object_add_peer(resp, bs);
+
+ /* Add status information */
+ json_object_int_add(resp, "id", bs->discrs.my_discr);
+ json_object_int_add(resp, "remote-id", bs->discrs.my_discr);
+
+ switch (bs->ses_state) {
+ case PTM_BFD_UP:
+ json_object_string_add(resp, "state", "up");
+
+ now = monotime(NULL);
+ json_object_int_add(resp, "uptime", now - bs->uptime.tv_sec);
+ break;
+ case PTM_BFD_ADM_DOWN:
+ json_object_string_add(resp, "state", "adm-down");
+ break;
+ case PTM_BFD_DOWN:
+ json_object_string_add(resp, "state", "down");
+
+ now = monotime(NULL);
+ json_object_int_add(resp, "downtime",
+ now - bs->downtime.tv_sec);
+ break;
+ case PTM_BFD_INIT:
+ json_object_string_add(resp, "state", "init");
+ break;
+
+ default:
+ json_object_string_add(resp, "state", "unknown");
+ break;
+ }
+
+ json_object_int_add(resp, "diagnostics", bs->local_diag);
+ json_object_int_add(resp, "remote-diagnostics", bs->remote_diag);
+
+ /* Generate JSON response. */
+ jsonstr = XSTRDUP(
+ MTYPE_BFDD_NOTIFICATION,
+ json_object_to_json_string_ext(resp, BFDD_JSON_CONV_OPTIONS));
+ json_object_put(resp);
+
+ return jsonstr;
+}
+
+char *config_notify_config(const char *op, struct bfd_session *bs)
+{
+ struct json_object *resp;
+ char *jsonstr;
+
+ resp = json_object_new_object();
+ if (resp == NULL)
+ return NULL;
+
+ json_object_string_add(resp, "op", op);
+
+ json_object_add_peer(resp, bs);
+
+ /* On peer deletion we don't need to add any additional information. */
+ if (strcmp(op, BCM_NOTIFY_CONFIG_DELETE) == 0)
+ goto skip_config;
+
+ json_object_int_add(resp, "detect-multiplier", bs->detect_mult);
+ json_object_int_add(resp, "receive-interval",
+ bs->timers.required_min_rx / 1000);
+ json_object_int_add(resp, "transmit-interval", bs->up_min_tx / 1000);
+ json_object_int_add(resp, "echo-interval",
+ bs->timers.required_min_echo / 1000);
+
+ json_object_int_add(resp, "remote-detect-multiplier",
+ bs->remote_detect_mult);
+ json_object_int_add(resp, "remote-receive-interval",
+ bs->remote_timers.required_min_rx / 1000);
+ json_object_int_add(resp, "remote-transmit-interval",
+ bs->remote_timers.desired_min_tx / 1000);
+ json_object_int_add(resp, "remote-echo-interval",
+ bs->remote_timers.required_min_echo / 1000);
+
+ if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_ECHO))
+ json_object_boolean_true_add(resp, "echo-mode");
+ else
+ json_object_boolean_false_add(resp, "echo-mode");
+
+ if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_SHUTDOWN))
+ json_object_boolean_true_add(resp, "shutdown");
+ else
+ json_object_boolean_false_add(resp, "shutdown");
+
+skip_config:
+ /* Generate JSON response. */
+ jsonstr = XSTRDUP(
+ MTYPE_BFDD_NOTIFICATION,
+ json_object_to_json_string_ext(resp, BFDD_JSON_CONV_OPTIONS));
+ json_object_put(resp);
+
+ return jsonstr;
+}
+
+int config_notify_request(struct bfd_control_socket *bcs, const char *jsonstr,
+ bpc_handle bh)
+{
+ struct json_object *jo;
+
+ jo = json_tokener_parse(jsonstr);
+ if (jo == NULL)
+ return -1;
+
+ return parse_config_json(jo, bh, bcs);
+}
+
+static int json_object_add_peer(struct json_object *jo, struct bfd_session *bs)
+{
+ /* Add peer 'key' information. */
+ if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_IPV6))
+ json_object_boolean_true_add(jo, "ipv6");
+ else
+ json_object_boolean_false_add(jo, "ipv6");
+
+ if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH)) {
+ json_object_boolean_true_add(jo, "multihop");
+ json_object_string_add(jo, "peer-address",
+ satostr(&bs->mhop.peer));
+ json_object_string_add(jo, "local-address",
+ satostr(&bs->mhop.local));
+ if (strlen(bs->mhop.vrf_name) > 0)
+ json_object_string_add(jo, "vrf-name",
+ bs->mhop.vrf_name);
+ } else {
+ json_object_boolean_false_add(jo, "multihop");
+ json_object_string_add(jo, "peer-address",
+ satostr(&bs->shop.peer));
+ if (bs->local_address.sa_sin.sin_family != AF_UNSPEC)
+ json_object_string_add(jo, "local-address",
+ satostr(&bs->local_address));
+ if (strlen(bs->shop.port_name) > 0)
+ json_object_string_add(jo, "local-interface",
+ bs->shop.port_name);
+ }
+
+ if (bs->pl)
+ json_object_string_add(jo, "label", bs->pl->pl_label);
+
+ return 0;
+}
+
+
+/*
+ * Label handling
+ */
+struct peer_label *pl_find(const char *label)
+{
+ struct peer_label *pl;
+
+ TAILQ_FOREACH (pl, &bglobal.bg_pllist, pl_entry) {
+ if (strcmp(pl->pl_label, label) != 0)
+ continue;
+
+ return pl;
+ }
+
+ return NULL;
+}
+
+struct peer_label *pl_new(const char *label, struct bfd_session *bs)
+{
+ struct peer_label *pl;
+
+ pl = XCALLOC(MTYPE_BFDD_LABEL, sizeof(*pl));
+ if (pl == NULL)
+ return NULL;
+
+ if (strlcpy(pl->pl_label, label, sizeof(pl->pl_label))
+ > sizeof(pl->pl_label))
+ log_warning("%s:%d: label was truncated", __func__, __LINE__);
+
+ pl->pl_bs = bs;
+ bs->pl = pl;
+
+ TAILQ_INSERT_HEAD(&bglobal.bg_pllist, pl, pl_entry);
+
+ return pl;
+}
+
+void pl_free(struct peer_label *pl)
+{
+ if (pl == NULL)
+ return;
+
+ /* Remove the pointer back. */
+ pl->pl_bs->pl = NULL;
+
+ TAILQ_REMOVE(&bglobal.bg_pllist, pl, pl_entry);
+ XFREE(MTYPE_BFDD_LABEL, pl);
+}
diff --git a/bfdd/control.c b/bfdd/control.c
new file mode 100644
index 0000000000..7e586dbb45
--- /dev/null
+++ b/bfdd/control.c
@@ -0,0 +1,895 @@
+/*********************************************************************
+ * Copyright 2017-2018 Network Device Education Foundation, Inc. ("NetDEF")
+ *
+ * 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
+ *
+ * control.c: implements the BFD daemon control socket. It will be used
+ * to talk with clients daemon/scripts/consumers.
+ *
+ * Authors
+ * -------
+ * Rafael Zalamena <rzalamena@opensourcerouting.org>
+ */
+
+#include <zebra.h>
+
+#include <sys/un.h>
+
+#include "bfd.h"
+
+/*
+ * Prototypes
+ */
+static int sock_set_nonblock(int fd);
+struct bfd_control_queue *control_queue_new(struct bfd_control_socket *bcs);
+static void control_queue_free(struct bfd_control_socket *bcs,
+ struct bfd_control_queue *bcq);
+static int control_queue_dequeue(struct bfd_control_socket *bcs);
+static int control_queue_enqueue(struct bfd_control_socket *bcs,
+ struct bfd_control_msg *bcm);
+static int control_queue_enqueue_first(struct bfd_control_socket *bcs,
+ struct bfd_control_msg *bcm);
+struct bfd_notify_peer *control_notifypeer_new(struct bfd_control_socket *bcs,
+ struct bfd_session *bs);
+static void control_notifypeer_free(struct bfd_control_socket *bcs,
+ struct bfd_notify_peer *bnp);
+struct bfd_notify_peer *control_notifypeer_find(struct bfd_control_socket *bcs,
+ struct bfd_session *bs);
+
+
+struct bfd_control_socket *control_new(int sd);
+static void control_free(struct bfd_control_socket *bcs);
+static void control_reset_buf(struct bfd_control_buffer *bcb);
+static int control_read(struct thread *t);
+static int control_write(struct thread *t);
+
+static void control_handle_request_add(struct bfd_control_socket *bcs,
+ struct bfd_control_msg *bcm);
+static void control_handle_request_del(struct bfd_control_socket *bcs,
+ struct bfd_control_msg *bcm);
+static int notify_add_cb(struct bfd_peer_cfg *bpc, void *arg);
+static int notify_del_cb(struct bfd_peer_cfg *bpc, void *arg);
+static void control_handle_notify_add(struct bfd_control_socket *bcs,
+ struct bfd_control_msg *bcm);
+static void control_handle_notify_del(struct bfd_control_socket *bcs,
+ struct bfd_control_msg *bcm);
+static void _control_handle_notify(struct hash_backet *hb, void *arg);
+static void control_handle_notify(struct bfd_control_socket *bcs,
+ struct bfd_control_msg *bcm);
+static void control_response(struct bfd_control_socket *bcs, uint16_t id,
+ const char *status, const char *error);
+
+static void _control_notify_config(struct bfd_control_socket *bcs,
+ const char *op, struct bfd_session *bs);
+static void _control_notify(struct bfd_control_socket *bcs,
+ struct bfd_session *bs);
+
+
+/*
+ * Functions
+ */
+static int sock_set_nonblock(int fd)
+{
+ int flags;
+
+ flags = fcntl(fd, F_GETFL, 0);
+ if (flags == -1) {
+ log_warning("%s: fcntl F_GETFL: %s", __func__, strerror(errno));
+ return -1;
+ }
+
+ flags |= O_NONBLOCK;
+ if (fcntl(fd, F_SETFL, flags) == -1) {
+ log_warning("%s: fcntl F_SETFL: %s", __func__, strerror(errno));
+ return -1;
+ }
+
+ return 0;
+}
+
+int control_init(const char *path)
+{
+ int sd;
+ mode_t umval;
+ struct sockaddr_un sun_ = {
+ .sun_family = AF_UNIX,
+ .sun_path = BFDD_CONTROL_SOCKET,
+ };
+
+ if (path)
+ strlcpy(sun_.sun_path, path, sizeof(sun_.sun_path));
+
+ /* Remove previously created sockets. */
+ unlink(sun_.sun_path);
+
+ sd = socket(AF_UNIX, SOCK_STREAM, PF_UNSPEC);
+ if (sd == -1) {
+ log_error("%s: socket: %s", __func__, strerror(errno));
+ return -1;
+ }
+
+ umval = umask(0);
+ if (bind(sd, (struct sockaddr *)&sun_, sizeof(sun_)) == -1) {
+ log_error("%s: bind: %s", __func__, strerror(errno));
+ close(sd);
+ return -1;
+ }
+ umask(umval);
+
+ if (listen(sd, SOMAXCONN) == -1) {
+ log_error("%s: listen: %s", __func__, strerror(errno));
+ close(sd);
+ return -1;
+ }
+
+ sock_set_nonblock(sd);
+
+ bglobal.bg_csock = sd;
+
+ return 0;
+}
+
+void control_shutdown(void)
+{
+ struct bfd_control_socket *bcs;
+
+ if (bglobal.bg_csockev) {
+ thread_cancel(bglobal.bg_csockev);
+ bglobal.bg_csockev = NULL;
+ }
+
+ socket_close(&bglobal.bg_csock);
+
+ while (!TAILQ_EMPTY(&bglobal.bg_bcslist)) {
+ bcs = TAILQ_FIRST(&bglobal.bg_bcslist);
+ control_free(bcs);
+ }
+}
+
+int control_accept(struct thread *t)
+{
+ int csock, sd = THREAD_FD(t);
+
+ csock = accept(sd, NULL, 0);
+ if (csock == -1) {
+ log_warning("%s: accept: %s", __func__, strerror(errno));
+ return 0;
+ }
+
+ if (control_new(csock) == NULL)
+ close(csock);
+
+ bglobal.bg_csockev = NULL;
+ thread_add_read(master, control_accept, NULL, sd, &bglobal.bg_csockev);
+
+ return 0;
+}
+
+
+/*
+ * Client handling
+ */
+struct bfd_control_socket *control_new(int sd)
+{
+ struct bfd_control_socket *bcs;
+
+ bcs = XCALLOC(MTYPE_BFDD_CONTROL, sizeof(*bcs));
+ if (bcs == NULL)
+ return NULL;
+
+ /* Disable notifications by default. */
+ bcs->bcs_notify = 0;
+
+ bcs->bcs_sd = sd;
+ thread_add_read(master, control_read, bcs, sd, &bcs->bcs_ev);
+
+ TAILQ_INIT(&bcs->bcs_bcqueue);
+ TAILQ_INIT(&bcs->bcs_bnplist);
+ TAILQ_INSERT_TAIL(&bglobal.bg_bcslist, bcs, bcs_entry);
+
+ return bcs;
+}
+
+static void control_free(struct bfd_control_socket *bcs)
+{
+ struct bfd_control_queue *bcq;
+ struct bfd_notify_peer *bnp;
+
+ if (bcs->bcs_ev) {
+ thread_cancel(bcs->bcs_ev);
+ bcs->bcs_ev = NULL;
+ }
+
+ if (bcs->bcs_outev) {
+ thread_cancel(bcs->bcs_outev);
+ bcs->bcs_outev = NULL;
+ }
+
+ close(bcs->bcs_sd);
+
+ TAILQ_REMOVE(&bglobal.bg_bcslist, bcs, bcs_entry);
+
+ /* Empty output queue. */
+ while (!TAILQ_EMPTY(&bcs->bcs_bcqueue)) {
+ bcq = TAILQ_FIRST(&bcs->bcs_bcqueue);
+ control_queue_free(bcs, bcq);
+ }
+
+ /* Empty notification list. */
+ while (!TAILQ_EMPTY(&bcs->bcs_bnplist)) {
+ bnp = TAILQ_FIRST(&bcs->bcs_bnplist);
+ control_notifypeer_free(bcs, bnp);
+ }
+
+ control_reset_buf(&bcs->bcs_bin);
+ XFREE(MTYPE_BFDD_CONTROL, bcs);
+}
+
+struct bfd_notify_peer *control_notifypeer_new(struct bfd_control_socket *bcs,
+ struct bfd_session *bs)
+{
+ struct bfd_notify_peer *bnp;
+
+ bnp = control_notifypeer_find(bcs, bs);
+ if (bnp)
+ return bnp;
+
+ bnp = XCALLOC(MTYPE_BFDD_CONTROL, sizeof(*bnp));
+ if (bnp == NULL) {
+ log_warning("%s: calloc: %s", __func__, strerror(errno));
+ return NULL;
+ }
+
+ TAILQ_INSERT_TAIL(&bcs->bcs_bnplist, bnp, bnp_entry);
+ bnp->bnp_bs = bs;
+ bs->refcount++;
+
+ return bnp;
+}
+
+static void control_notifypeer_free(struct bfd_control_socket *bcs,
+ struct bfd_notify_peer *bnp)
+{
+ TAILQ_REMOVE(&bcs->bcs_bnplist, bnp, bnp_entry);
+ bnp->bnp_bs->refcount--;
+ XFREE(MTYPE_BFDD_CONTROL, bnp);
+}
+
+struct bfd_notify_peer *control_notifypeer_find(struct bfd_control_socket *bcs,
+ struct bfd_session *bs)
+{
+ struct bfd_notify_peer *bnp;
+
+ TAILQ_FOREACH (bnp, &bcs->bcs_bnplist, bnp_entry) {
+ if (bnp->bnp_bs == bs)
+ return bnp;
+ }
+
+ return NULL;
+}
+
+struct bfd_control_queue *control_queue_new(struct bfd_control_socket *bcs)
+{
+ struct bfd_control_queue *bcq;
+
+ bcq = XCALLOC(MTYPE_BFDD_NOTIFICATION, sizeof(*bcq));
+ if (bcq == NULL) {
+ log_warning("%s: calloc: %s", __func__, strerror(errno));
+ return NULL;
+ }
+
+ control_reset_buf(&bcq->bcq_bcb);
+ TAILQ_INSERT_TAIL(&bcs->bcs_bcqueue, bcq, bcq_entry);
+
+ return bcq;
+}
+
+static void control_queue_free(struct bfd_control_socket *bcs,
+ struct bfd_control_queue *bcq)
+{
+ control_reset_buf(&bcq->bcq_bcb);
+ TAILQ_REMOVE(&bcs->bcs_bcqueue, bcq, bcq_entry);
+ XFREE(MTYPE_BFDD_NOTIFICATION, bcq);
+}
+
+static int control_queue_dequeue(struct bfd_control_socket *bcs)
+{
+ struct bfd_control_queue *bcq;
+
+ /* List is empty, nothing to do. */
+ if (TAILQ_EMPTY(&bcs->bcs_bcqueue))
+ goto empty_list;
+
+ bcq = TAILQ_FIRST(&bcs->bcs_bcqueue);
+ control_queue_free(bcs, bcq);
+
+ /* Get the next buffer to send. */
+ if (TAILQ_EMPTY(&bcs->bcs_bcqueue))
+ goto empty_list;
+
+ bcq = TAILQ_FIRST(&bcs->bcs_bcqueue);
+ bcs->bcs_bout = &bcq->bcq_bcb;
+
+ bcs->bcs_outev = NULL;
+ thread_add_write(master, control_write, bcs, bcs->bcs_sd,
+ &bcs->bcs_outev);
+
+ return 1;
+
+empty_list:
+ if (bcs->bcs_outev) {
+ thread_cancel(bcs->bcs_outev);
+ bcs->bcs_outev = NULL;
+ }
+ bcs->bcs_bout = NULL;
+ return 0;
+}
+
+static int control_queue_enqueue(struct bfd_control_socket *bcs,
+ struct bfd_control_msg *bcm)
+{
+ struct bfd_control_queue *bcq;
+ struct bfd_control_buffer *bcb;
+
+ bcq = control_queue_new(bcs);
+ if (bcq == NULL)
+ return -1;
+
+ bcb = &bcq->bcq_bcb;
+ bcb->bcb_left = sizeof(struct bfd_control_msg) + ntohl(bcm->bcm_length);
+ bcb->bcb_pos = 0;
+ bcb->bcb_bcm = bcm;
+
+ /* If this is the first item, then dequeue and start using it. */
+ if (bcs->bcs_bout == NULL) {
+ bcs->bcs_bout = bcb;
+
+ /* New messages, active write events. */
+ thread_add_write(master, control_write, bcs, bcs->bcs_sd,
+ &bcs->bcs_outev);
+ }
+
+ return 0;
+}
+
+static int control_queue_enqueue_first(struct bfd_control_socket *bcs,
+ struct bfd_control_msg *bcm)
+{
+ struct bfd_control_queue *bcq, *bcqn;
+ struct bfd_control_buffer *bcb;
+
+ /* Enqueue it somewhere. */
+ if (control_queue_enqueue(bcs, bcm) == -1)
+ return -1;
+
+ /*
+ * The item is either the first or the last. So we must first
+ * check the best case where the item is already the first.
+ */
+ bcq = TAILQ_FIRST(&bcs->bcs_bcqueue);
+ bcb = &bcq->bcq_bcb;
+ if (bcm == bcb->bcb_bcm)
+ return 0;
+
+ /*
+ * The item was not the first, so it is the last. We'll try to
+ * assign it to the head of the queue, however if there is a
+ * transfer in progress, then we have to make the item as the
+ * next one.
+ *
+ * Interrupting the transfer of in progress message will cause
+ * the client to lose track of the message position/data.
+ */
+ bcqn = TAILQ_LAST(&bcs->bcs_bcqueue, bcqueue);
+ TAILQ_REMOVE(&bcs->bcs_bcqueue, bcqn, bcq_entry);
+ if (bcb->bcb_pos != 0) {
+ /*
+ * First position is already being sent, insert into
+ * second position.
+ */
+ TAILQ_INSERT_AFTER(&bcs->bcs_bcqueue, bcq, bcqn, bcq_entry);
+ } else {
+ /*
+ * Old message didn't start being sent, we still have
+ * time to put this one in the head of the queue.
+ */
+ TAILQ_INSERT_HEAD(&bcs->bcs_bcqueue, bcqn, bcq_entry);
+ bcb = &bcqn->bcq_bcb;
+ bcs->bcs_bout = bcb;
+ }
+
+ return 0;
+}
+
+static void control_reset_buf(struct bfd_control_buffer *bcb)
+{
+ /* Get ride of old data. */
+ XFREE(MTYPE_BFDD_NOTIFICATION, bcb->bcb_buf);
+ bcb->bcb_buf = NULL;
+ bcb->bcb_pos = 0;
+ bcb->bcb_left = 0;
+}
+
+static int control_read(struct thread *t)
+{
+ struct bfd_control_socket *bcs = THREAD_ARG(t);
+ struct bfd_control_buffer *bcb = &bcs->bcs_bin;
+ int sd = bcs->bcs_sd;
+ struct bfd_control_msg bcm;
+ ssize_t bread;
+ size_t plen;
+
+ /*
+ * Check if we have already downloaded message content, if so then skip
+ * to
+ * download the rest of it and process.
+ *
+ * Otherwise download a new message header and allocate the necessary
+ * memory.
+ */
+ if (bcb->bcb_buf != NULL)
+ goto skip_header;
+
+ bread = read(sd, &bcm, sizeof(bcm));
+ if (bread == 0) {
+ control_free(bcs);
+ return 0;
+ }
+ if (bread < 0) {
+ if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR)
+ goto schedule_next_read;
+
+ log_warning("%s: read: %s", __func__, strerror(errno));
+ control_free(bcs);
+ return 0;
+ }
+
+ /* Validate header fields. */
+ plen = ntohl(bcm.bcm_length);
+ if (plen < 2) {
+ log_debug("%s: client closed due small message length: %d",
+ __func__, bcm.bcm_length);
+ control_free(bcs);
+ return 0;
+ }
+
+ if (bcm.bcm_ver != BMV_VERSION_1) {
+ log_debug("%s: client closed due bad version: %d", __func__,
+ bcm.bcm_ver);
+ control_free(bcs);
+ return 0;
+ }
+
+ /* Prepare the buffer to load the message. */
+ bcs->bcs_version = bcm.bcm_ver;
+ bcs->bcs_type = bcm.bcm_type;
+
+ bcb->bcb_pos = sizeof(bcm);
+ bcb->bcb_left = plen;
+ bcb->bcb_buf = XMALLOC(MTYPE_BFDD_NOTIFICATION,
+ sizeof(bcm) + bcb->bcb_left + 1);
+ if (bcb->bcb_buf == NULL) {
+ log_warning("%s: not enough memory for message size: %u",
+ __func__, bcb->bcb_left);
+ control_free(bcs);
+ return 0;
+ }
+
+ memcpy(bcb->bcb_buf, &bcm, sizeof(bcm));
+
+ /* Terminate data string with NULL for later processing. */
+ bcb->bcb_buf[sizeof(bcm) + bcb->bcb_left] = 0;
+
+skip_header:
+ /* Download the remaining data of the message and process it. */
+ bread = read(sd, &bcb->bcb_buf[bcb->bcb_pos], bcb->bcb_left);
+ if (bread == 0) {
+ control_free(bcs);
+ return 0;
+ }
+ if (bread < 0) {
+ if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR)
+ goto schedule_next_read;
+
+ log_warning("%s: read: %s", __func__, strerror(errno));
+ control_free(bcs);
+ return 0;
+ }
+
+ bcb->bcb_pos += bread;
+ bcb->bcb_left -= bread;
+ /* We need more data, return to wait more. */
+ if (bcb->bcb_left > 0)
+ goto schedule_next_read;
+
+ switch (bcm.bcm_type) {
+ case BMT_REQUEST_ADD:
+ control_handle_request_add(bcs, bcb->bcb_bcm);
+ break;
+ case BMT_REQUEST_DEL:
+ control_handle_request_del(bcs, bcb->bcb_bcm);
+ break;
+ case BMT_NOTIFY:
+ control_handle_notify(bcs, bcb->bcb_bcm);
+ break;
+ case BMT_NOTIFY_ADD:
+ control_handle_notify_add(bcs, bcb->bcb_bcm);
+ break;
+ case BMT_NOTIFY_DEL:
+ control_handle_notify_del(bcs, bcb->bcb_bcm);
+ break;
+
+ default:
+ log_debug("%s: unhandled message type: %d", __func__,
+ bcm.bcm_type);
+ control_response(bcs, bcm.bcm_id, BCM_RESPONSE_ERROR,
+ "invalid message type");
+ break;
+ }
+
+ bcs->bcs_version = 0;
+ bcs->bcs_type = 0;
+ control_reset_buf(bcb);
+
+schedule_next_read:
+ bcs->bcs_ev = NULL;
+ thread_add_read(master, control_read, bcs, sd, &bcs->bcs_ev);
+
+ return 0;
+}
+
+static int control_write(struct thread *t)
+{
+ struct bfd_control_socket *bcs = THREAD_ARG(t);
+ struct bfd_control_buffer *bcb = bcs->bcs_bout;
+ int sd = bcs->bcs_sd;
+ ssize_t bwrite;
+
+ bwrite = write(sd, &bcb->bcb_buf[bcb->bcb_pos], bcb->bcb_left);
+ if (bwrite == 0) {
+ control_free(bcs);
+ return 0;
+ }
+ if (bwrite < 0) {
+ if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR) {
+ bcs->bcs_outev = NULL;
+ thread_add_write(master, control_write, bcs,
+ bcs->bcs_sd, &bcs->bcs_outev);
+ return 0;
+ }
+
+ log_warning("%s: write: %s", __func__, strerror(errno));
+ control_free(bcs);
+ return 0;
+ }
+
+ bcb->bcb_pos += bwrite;
+ bcb->bcb_left -= bwrite;
+ if (bcb->bcb_left > 0) {
+ bcs->bcs_outev = NULL;
+ thread_add_write(master, control_write, bcs, bcs->bcs_sd,
+ &bcs->bcs_outev);
+ return 0;
+ }
+
+ control_queue_dequeue(bcs);
+
+ return 0;
+}
+
+
+/*
+ * Message processing
+ */
+static void control_handle_request_add(struct bfd_control_socket *bcs,
+ struct bfd_control_msg *bcm)
+{
+ const char *json = (const char *)bcm->bcm_data;
+
+ if (config_request_add(json) == 0)
+ control_response(bcs, bcm->bcm_id, BCM_RESPONSE_OK, NULL);
+ else
+ control_response(bcs, bcm->bcm_id, BCM_RESPONSE_ERROR,
+ "request add failed");
+}
+
+static void control_handle_request_del(struct bfd_control_socket *bcs,
+ struct bfd_control_msg *bcm)
+{
+ const char *json = (const char *)bcm->bcm_data;
+
+ if (config_request_del(json) == 0)
+ control_response(bcs, bcm->bcm_id, BCM_RESPONSE_OK, NULL);
+ else
+ control_response(bcs, bcm->bcm_id, BCM_RESPONSE_ERROR,
+ "request del failed");
+}
+
+static struct bfd_session *_notify_find_peer(struct bfd_peer_cfg *bpc)
+{
+ struct peer_label *pl;
+
+ if (bpc->bpc_has_label) {
+ pl = pl_find(bpc->bpc_label);
+ if (pl)
+ return pl->pl_bs;
+ }
+
+ return bs_peer_find(bpc);
+}
+
+static void _control_handle_notify(struct hash_backet *hb, void *arg)
+{
+ struct bfd_control_socket *bcs = arg;
+ struct bfd_session *bs = hb->data;
+
+ /* Notify peer configuration. */
+ if (bcs->bcs_notify & BCM_NOTIFY_CONFIG)
+ _control_notify_config(bcs, BCM_NOTIFY_CONFIG_ADD, bs);
+
+ /* Notify peer status. */
+ if (bcs->bcs_notify & BCM_NOTIFY_PEER_STATE)
+ _control_notify(bcs, bs);
+}
+
+static void control_handle_notify(struct bfd_control_socket *bcs,
+ struct bfd_control_msg *bcm)
+{
+ memcpy(&bcs->bcs_notify, bcm->bcm_data, sizeof(bcs->bcs_notify));
+
+ control_response(bcs, bcm->bcm_id, BCM_RESPONSE_OK, NULL);
+
+ /*
+ * If peer asked for notification configuration, send everything that
+ * was configured until the moment to sync up.
+ */
+ if (bcs->bcs_notify & (BCM_NOTIFY_CONFIG | BCM_NOTIFY_PEER_STATE))
+ bfd_id_iterate(_control_handle_notify, bcs);
+}
+
+static int notify_add_cb(struct bfd_peer_cfg *bpc, void *arg)
+{
+ struct bfd_control_socket *bcs = arg;
+ struct bfd_session *bs = _notify_find_peer(bpc);
+
+ if (bs == NULL)
+ return -1;
+
+ if (control_notifypeer_new(bcs, bs) == NULL)
+ return -1;
+
+ /* Notify peer status. */
+ _control_notify(bcs, bs);
+
+ return 0;
+}
+
+static int notify_del_cb(struct bfd_peer_cfg *bpc, void *arg)
+{
+ struct bfd_control_socket *bcs = arg;
+ struct bfd_session *bs = _notify_find_peer(bpc);
+ struct bfd_notify_peer *bnp;
+
+ if (bs == NULL)
+ return -1;
+
+ bnp = control_notifypeer_find(bcs, bs);
+ if (bnp)
+ control_notifypeer_free(bcs, bnp);
+
+ return 0;
+}
+
+static void control_handle_notify_add(struct bfd_control_socket *bcs,
+ struct bfd_control_msg *bcm)
+{
+ const char *json = (const char *)bcm->bcm_data;
+
+ if (config_notify_request(bcs, json, notify_add_cb) == 0) {
+ control_response(bcs, bcm->bcm_id, BCM_RESPONSE_OK, NULL);
+ return;
+ }
+
+ control_response(bcs, bcm->bcm_id, BCM_RESPONSE_ERROR,
+ "failed to parse notify data");
+}
+
+static void control_handle_notify_del(struct bfd_control_socket *bcs,
+ struct bfd_control_msg *bcm)
+{
+ const char *json = (const char *)bcm->bcm_data;
+
+ if (config_notify_request(bcs, json, notify_del_cb) == 0) {
+ control_response(bcs, bcm->bcm_id, BCM_RESPONSE_OK, NULL);
+ return;
+ }
+
+ control_response(bcs, bcm->bcm_id, BCM_RESPONSE_ERROR,
+ "failed to parse notify data");
+}
+
+
+/*
+ * Internal functions used by the BFD daemon.
+ */
+static void control_response(struct bfd_control_socket *bcs, uint16_t id,
+ const char *status, const char *error)
+{
+ struct bfd_control_msg *bcm;
+ char *jsonstr;
+ size_t jsonstrlen;
+
+ /* Generate JSON response. */
+ jsonstr = config_response(status, error);
+ if (jsonstr == NULL) {
+ log_warning("%s: config_response: failed to get JSON str",
+ __func__);
+ return;
+ }
+
+ /* Allocate data and answer. */
+ jsonstrlen = strlen(jsonstr);
+ bcm = XMALLOC(MTYPE_BFDD_NOTIFICATION,
+ sizeof(struct bfd_control_msg) + jsonstrlen);
+ if (bcm == NULL) {
+ log_warning("%s: malloc: %s", __func__, strerror(errno));
+ XFREE(MTYPE_BFDD_NOTIFICATION, jsonstr);
+ return;
+ }
+
+ bcm->bcm_length = htonl(jsonstrlen);
+ bcm->bcm_ver = BMV_VERSION_1;
+ bcm->bcm_type = BMT_RESPONSE;
+ bcm->bcm_id = id;
+ memcpy(bcm->bcm_data, jsonstr, jsonstrlen);
+ XFREE(MTYPE_BFDD_NOTIFICATION, jsonstr);
+
+ control_queue_enqueue_first(bcs, bcm);
+}
+
+static void _control_notify(struct bfd_control_socket *bcs,
+ struct bfd_session *bs)
+{
+ struct bfd_control_msg *bcm;
+ char *jsonstr;
+ size_t jsonstrlen;
+
+ /* Generate JSON response. */
+ jsonstr = config_notify(bs);
+ if (jsonstr == NULL) {
+ log_warning("%s: config_notify: failed to get JSON str",
+ __func__);
+ return;
+ }
+
+ /* Allocate data and answer. */
+ jsonstrlen = strlen(jsonstr);
+ bcm = XMALLOC(MTYPE_BFDD_NOTIFICATION,
+ sizeof(struct bfd_control_msg) + jsonstrlen);
+ if (bcm == NULL) {
+ log_warning("%s: malloc: %s", __func__, strerror(errno));
+ XFREE(MTYPE_BFDD_NOTIFICATION, jsonstr);
+ return;
+ }
+
+ bcm->bcm_length = htonl(jsonstrlen);
+ bcm->bcm_ver = BMV_VERSION_1;
+ bcm->bcm_type = BMT_NOTIFY;
+ bcm->bcm_id = htons(BCM_NOTIFY_ID);
+ memcpy(bcm->bcm_data, jsonstr, jsonstrlen);
+ XFREE(MTYPE_BFDD_NOTIFICATION, jsonstr);
+
+ control_queue_enqueue(bcs, bcm);
+}
+
+int control_notify(struct bfd_session *bs)
+{
+ struct bfd_control_socket *bcs;
+ struct bfd_notify_peer *bnp;
+
+ /* Notify zebra listeners as well. */
+ ptm_bfd_notify(bs);
+
+ /*
+ * PERFORMANCE: reuse the bfd_control_msg allocated data for
+ * all control sockets to avoid wasting memory.
+ */
+ TAILQ_FOREACH (bcs, &bglobal.bg_bcslist, bcs_entry) {
+ /*
+ * Test for all notifications first, then search for
+ * specific peers.
+ */
+ if ((bcs->bcs_notify & BCM_NOTIFY_PEER_STATE) == 0) {
+ bnp = control_notifypeer_find(bcs, bs);
+ /*
+ * If the notification is not configured here,
+ * don't send it.
+ */
+ if (bnp == NULL)
+ continue;
+ }
+
+ _control_notify(bcs, bs);
+ }
+
+ return 0;
+}
+
+static void _control_notify_config(struct bfd_control_socket *bcs,
+ const char *op, struct bfd_session *bs)
+{
+ struct bfd_control_msg *bcm;
+ char *jsonstr;
+ size_t jsonstrlen;
+
+ /* Generate JSON response. */
+ jsonstr = config_notify_config(op, bs);
+ if (jsonstr == NULL) {
+ log_warning("%s: config_notify_config: failed to get JSON str",
+ __func__);
+ return;
+ }
+
+ /* Allocate data and answer. */
+ jsonstrlen = strlen(jsonstr);
+ bcm = XMALLOC(MTYPE_BFDD_NOTIFICATION,
+ sizeof(struct bfd_control_msg) + jsonstrlen);
+ if (bcm == NULL) {
+ log_warning("%s: malloc: %s", __func__, strerror(errno));
+ XFREE(MTYPE_BFDD_NOTIFICATION, jsonstr);
+ return;
+ }
+
+ bcm->bcm_length = htonl(jsonstrlen);
+ bcm->bcm_ver = BMV_VERSION_1;
+ bcm->bcm_type = BMT_NOTIFY;
+ bcm->bcm_id = htons(BCM_NOTIFY_ID);
+ memcpy(bcm->bcm_data, jsonstr, jsonstrlen);
+ XFREE(MTYPE_BFDD_NOTIFICATION, jsonstr);
+
+ control_queue_enqueue(bcs, bcm);
+}
+
+int control_notify_config(const char *op, struct bfd_session *bs)
+{
+ struct bfd_control_socket *bcs;
+ struct bfd_notify_peer *bnp;
+
+ /* Remove the control sockets notification for this peer. */
+ if (strcmp(op, BCM_NOTIFY_CONFIG_DELETE) == 0 && bs->refcount > 0) {
+ TAILQ_FOREACH (bcs, &bglobal.bg_bcslist, bcs_entry) {
+ bnp = control_notifypeer_find(bcs, bs);
+ if (bnp)
+ control_notifypeer_free(bcs, bnp);
+ }
+ }
+
+ /*
+ * PERFORMANCE: reuse the bfd_control_msg allocated data for
+ * all control sockets to avoid wasting memory.
+ */
+ TAILQ_FOREACH (bcs, &bglobal.bg_bcslist, bcs_entry) {
+ /*
+ * Test for all notifications first, then search for
+ * specific peers.
+ */
+ if ((bcs->bcs_notify & BCM_NOTIFY_CONFIG) == 0)
+ continue;
+
+ _control_notify_config(bcs, op, bs);
+ }
+
+ return 0;
+}
diff --git a/bfdd/event.c b/bfdd/event.c
new file mode 100644
index 0000000000..ba12f5b4e8
--- /dev/null
+++ b/bfdd/event.c
@@ -0,0 +1,155 @@
+/*********************************************************************
+ * Copyright 2017-2018 Network Device Education Foundation, Inc. ("NetDEF")
+ *
+ * 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
+ *
+ * event.c: implements the BFD loop event handlers.
+ *
+ * Authors
+ * -------
+ * Rafael Zalamena <rzalamena@opensourcerouting.org>
+ */
+
+#include <zebra.h>
+
+#include "bfd.h"
+
+void tv_normalize(struct timeval *tv);
+
+void tv_normalize(struct timeval *tv)
+{
+ /* Remove seconds part from microseconds. */
+ tv->tv_sec = tv->tv_usec / 1000000;
+ tv->tv_usec = tv->tv_usec % 1000000;
+}
+
+void bfd_recvtimer_update(struct bfd_session *bs)
+{
+ struct timeval tv = {.tv_sec = 0, .tv_usec = bs->detect_TO};
+
+ /* Don't add event if peer is deactivated. */
+ if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_SHUTDOWN))
+ return;
+
+ tv_normalize(&tv);
+#ifdef BFD_EVENT_DEBUG
+ log_debug("%s: sec = %ld, usec = %ld", __func__, tv.tv_sec, tv.tv_usec);
+#endif /* BFD_EVENT_DEBUG */
+
+ /* Remove previous schedule if any. */
+ if (bs->recvtimer_ev)
+ bfd_recvtimer_delete(bs);
+
+ thread_add_timer_tv(master, bfd_recvtimer_cb, bs, &tv,
+ &bs->recvtimer_ev);
+}
+
+void bfd_echo_recvtimer_update(struct bfd_session *bs)
+{
+ struct timeval tv = {.tv_sec = 0, .tv_usec = bs->echo_detect_TO};
+
+ /* Don't add event if peer is deactivated. */
+ if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_SHUTDOWN))
+ return;
+
+ tv_normalize(&tv);
+#ifdef BFD_EVENT_DEBUG
+ log_debug("%s: sec = %ld, usec = %ld", __func__, tv.tv_sec, tv.tv_usec);
+#endif /* BFD_EVENT_DEBUG */
+
+ /* Remove previous schedule if any. */
+ if (bs->echo_recvtimer_ev)
+ bfd_echo_recvtimer_delete(bs);
+
+ thread_add_timer_tv(master, bfd_echo_recvtimer_cb, bs, &tv,
+ &bs->echo_recvtimer_ev);
+}
+
+void bfd_xmttimer_update(struct bfd_session *bs, uint64_t jitter)
+{
+ struct timeval tv = {.tv_sec = 0, .tv_usec = jitter};
+
+ /* Don't add event if peer is deactivated. */
+ if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_SHUTDOWN))
+ return;
+
+ tv_normalize(&tv);
+#ifdef BFD_EVENT_DEBUG
+ log_debug("%s: sec = %ld, usec = %ld", __func__, tv.tv_sec, tv.tv_usec);
+#endif /* BFD_EVENT_DEBUG */
+
+ /* Remove previous schedule if any. */
+ if (bs->xmttimer_ev)
+ bfd_xmttimer_delete(bs);
+
+ thread_add_timer_tv(master, bfd_xmt_cb, bs, &tv, &bs->xmttimer_ev);
+}
+
+void bfd_echo_xmttimer_update(struct bfd_session *bs, uint64_t jitter)
+{
+ struct timeval tv = {.tv_sec = 0, .tv_usec = jitter};
+
+ /* Don't add event if peer is deactivated. */
+ if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_SHUTDOWN))
+ return;
+
+ tv_normalize(&tv);
+#ifdef BFD_EVENT_DEBUG
+ log_debug("%s: sec = %ld, usec = %ld", __func__, tv.tv_sec, tv.tv_usec);
+#endif /* BFD_EVENT_DEBUG */
+
+ /* Remove previous schedule if any. */
+ if (bs->echo_xmttimer_ev)
+ bfd_echo_xmttimer_delete(bs);
+
+ thread_add_timer_tv(master, bfd_echo_xmt_cb, bs, &tv,
+ &bs->echo_xmttimer_ev);
+}
+
+void bfd_recvtimer_delete(struct bfd_session *bs)
+{
+ if (bs->recvtimer_ev == NULL)
+ return;
+
+ thread_cancel(bs->recvtimer_ev);
+ bs->recvtimer_ev = NULL;
+}
+
+void bfd_echo_recvtimer_delete(struct bfd_session *bs)
+{
+ if (bs->echo_recvtimer_ev == NULL)
+ return;
+
+ thread_cancel(bs->echo_recvtimer_ev);
+ bs->echo_recvtimer_ev = NULL;
+}
+
+void bfd_xmttimer_delete(struct bfd_session *bs)
+{
+ if (bs->xmttimer_ev == NULL)
+ return;
+
+ thread_cancel(bs->xmttimer_ev);
+ bs->xmttimer_ev = NULL;
+}
+
+void bfd_echo_xmttimer_delete(struct bfd_session *bs)
+{
+ if (bs->echo_xmttimer_ev == NULL)
+ return;
+
+ thread_cancel(bs->echo_xmttimer_ev);
+ bs->echo_xmttimer_ev = NULL;
+}
diff --git a/bfdd/linux.c b/bfdd/linux.c
new file mode 100644
index 0000000000..5f24ef4d19
--- /dev/null
+++ b/bfdd/linux.c
@@ -0,0 +1,221 @@
+/*
+ * Linux specific code
+ *
+ * Copyright (C) 2018 Network Device Education Foundation, Inc. ("NetDEF")
+ *
+ * FRR is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * FRR is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with FRR; see the file COPYING. If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#include <zebra.h>
+
+#ifdef BFD_LINUX
+
+/* XXX: fix compilation error on Ubuntu 16.04 or older. */
+#ifndef _UAPI_IPV6_H
+#define _UAPI_IPV6_H
+#endif /* _UAPI_IPV6_H */
+
+#include <linux/filter.h>
+#include <linux/if_packet.h>
+
+#include <netinet/if_ether.h>
+
+#include <net/if.h>
+#include <sys/ioctl.h>
+
+#include "bfd.h"
+
+/* Berkeley Packet filter code to filter out BFD Echo packets.
+ * tcpdump -dd "(udp dst port 3785)"
+ */
+static struct sock_filter bfd_echo_filter[] = {
+ {0x28, 0, 0, 0x0000000c}, {0x15, 0, 4, 0x000086dd},
+ {0x30, 0, 0, 0x00000014}, {0x15, 0, 11, 0x00000011},
+ {0x28, 0, 0, 0x00000038}, {0x15, 8, 9, 0x00000ec9},
+ {0x15, 0, 8, 0x00000800}, {0x30, 0, 0, 0x00000017},
+ {0x15, 0, 6, 0x00000011}, {0x28, 0, 0, 0x00000014},
+ {0x45, 4, 0, 0x00001fff}, {0xb1, 0, 0, 0x0000000e},
+ {0x48, 0, 0, 0x00000010}, {0x15, 0, 1, 0x00000ec9},
+ {0x6, 0, 0, 0x0000ffff}, {0x6, 0, 0, 0x00000000},
+};
+
+/* Berkeley Packet filter code to filter out BFD vxlan packets.
+ * tcpdump -dd "(udp dst port 4789)"
+ */
+static struct sock_filter bfd_vxlan_filter[] = {
+ {0x28, 0, 0, 0x0000000c}, {0x15, 0, 4, 0x000086dd},
+ {0x30, 0, 0, 0x00000014}, {0x15, 0, 11, 0x00000011},
+ {0x28, 0, 0, 0x00000038}, {0x15, 8, 9, 0x000012b5},
+ {0x15, 0, 8, 0x00000800}, {0x30, 0, 0, 0x00000017},
+ {0x15, 0, 6, 0x00000011}, {0x28, 0, 0, 0x00000014},
+ {0x45, 4, 0, 0x00001fff}, {0xb1, 0, 0, 0x0000000e},
+ {0x48, 0, 0, 0x00000010}, {0x15, 0, 1, 0x000012b5},
+ {0x6, 0, 0, 0x0000ffff}, {0x6, 0, 0, 0x00000000},
+};
+
+
+/*
+ * Definitions.
+ */
+int ptm_bfd_fetch_ifindex(const char *ifname)
+{
+ struct ifreq ifr;
+
+ if (strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name))
+ > sizeof(ifr.ifr_name))
+ log_error("interface-to-index: name truncated ('%s' -> '%s')",
+ ifr.ifr_name, ifname);
+
+ if (ioctl(bglobal.bg_shop, SIOCGIFINDEX, &ifr) == -1) {
+ log_error("interface-to-index: %s translation failed: %s",
+ ifname, strerror(errno));
+ return -1;
+ }
+
+ return ifr.ifr_ifindex;
+}
+
+void ptm_bfd_fetch_local_mac(const char *ifname, uint8_t *mac)
+{
+ struct ifreq ifr;
+
+ if (strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name))
+ > sizeof(ifr.ifr_name))
+ log_error("interface-mac: name truncated ('%s' -> '%s')",
+ ifr.ifr_name, ifname);
+
+ if (ioctl(bglobal.bg_shop, SIOCGIFHWADDR, &ifr) == -1) {
+ log_error("interface-mac: %s MAC retrieval failed: %s", ifname,
+ strerror(errno));
+ return;
+ }
+
+ memcpy(mac, ifr.ifr_hwaddr.sa_data, ETHERNET_ADDRESS_LENGTH);
+}
+
+
+/* Was _fetch_portname_from_ifindex() */
+void fetch_portname_from_ifindex(int ifindex, char *ifname, size_t ifnamelen)
+{
+ struct ifreq ifr;
+
+ ifname[0] = 0;
+
+ memset(&ifr, 0, sizeof(ifr));
+ ifr.ifr_ifindex = ifindex;
+
+ if (ioctl(bglobal.bg_shop, SIOCGIFNAME, &ifr) == -1) {
+ log_error("index-to-interface: index %d failure: %s", ifindex,
+ strerror(errno));
+ return;
+ }
+
+ if (strlcpy(ifname, ifr.ifr_name, ifnamelen) >= ifnamelen)
+ log_debug("index-to-interface: name truncated '%s' -> '%s'",
+ ifr.ifr_name, ifname);
+}
+
+int ptm_bfd_echo_sock_init(void)
+{
+ int s;
+ struct sock_fprog bpf = {.len = sizeof(bfd_echo_filter)
+ / sizeof(bfd_echo_filter[0]),
+ .filter = bfd_echo_filter};
+
+ s = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_IP));
+ if (s == -1) {
+ log_error("echo-socket: creation failure: %s", strerror(errno));
+ return -1;
+ }
+
+ if (setsockopt(s, SOL_SOCKET, SO_ATTACH_FILTER, &bpf, sizeof(bpf))
+ == -1) {
+ log_error("echo-socket: setsockopt(SO_ATTACH_FILTER): %s",
+ strerror(errno));
+ close(s);
+ return -1;
+ }
+
+ return s;
+}
+
+int ptm_bfd_vxlan_sock_init(void)
+{
+ int s;
+ struct sock_fprog bpf = {.len = sizeof(bfd_vxlan_filter)
+ / sizeof(bfd_vxlan_filter[0]),
+ .filter = bfd_vxlan_filter};
+
+ s = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_IP));
+ if (s == -1) {
+ log_error("vxlan-socket: creation failure: %s",
+ strerror(errno));
+ return -1;
+ }
+
+ if (setsockopt(s, SOL_SOCKET, SO_ATTACH_FILTER, &bpf, sizeof(bpf))
+ == -1) {
+ log_error("vxlan-socket: setsockopt(SO_ATTACH_FILTER): %s",
+ strerror(errno));
+ close(s);
+ return -1;
+ }
+
+ return s;
+}
+
+int bp_bind_dev(int sd __attribute__((__unused__)),
+ const char *dev __attribute__((__unused__)))
+{
+ /*
+ * TODO: implement this differently. It is not possible to
+ * SO_BINDTODEVICE after the daemon has dropped its privileges.
+ */
+#if 0
+ size_t devlen = strlen(dev) + 1;
+
+ if (setsockopt(sd, SOL_SOCKET, SO_BINDTODEVICE, dev, devlen) == -1) {
+ log_warning("%s: setsockopt(SO_BINDTODEVICE, \"%s\"): %s",
+ __func__, dev, strerror(errno));
+ return -1;
+ }
+#endif
+
+ return 0;
+}
+
+uint16_t udp4_checksum(struct iphdr *iph, uint8_t *buf, int len)
+{
+ char *ptr;
+ struct udp_psuedo_header pudp_hdr;
+ uint16_t csum;
+
+ pudp_hdr.saddr = iph->saddr;
+ pudp_hdr.daddr = iph->daddr;
+ pudp_hdr.reserved = 0;
+ pudp_hdr.protocol = iph->protocol;
+ pudp_hdr.len = htons(len);
+
+ ptr = XMALLOC(MTYPE_BFDD_TMP, UDP_PSUEDO_HDR_LEN + len);
+ memcpy(ptr, &pudp_hdr, UDP_PSUEDO_HDR_LEN);
+ memcpy(ptr + UDP_PSUEDO_HDR_LEN, buf, len);
+
+ csum = checksum((uint16_t *)ptr, UDP_PSUEDO_HDR_LEN + len);
+ XFREE(MTYPE_BFDD_TMP, ptr);
+ return csum;
+}
+
+#endif /* BFD_LINUX */
diff --git a/bfdd/log.c b/bfdd/log.c
new file mode 100644
index 0000000000..d81d7cd9b3
--- /dev/null
+++ b/bfdd/log.c
@@ -0,0 +1,125 @@
+/*********************************************************************
+ * Copyright 2017-2018 Network Device Education Foundation, Inc. ("NetDEF")
+ *
+ * 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
+ *
+ * log.c: implements an abstraction between loggers interface. Implement all
+ * log backends in this file.
+ *
+ * Authors
+ * -------
+ * Rafael Zalamena <rzalamena@opensourcerouting.org>
+ */
+
+#include <zebra.h>
+
+#include "bfd.h"
+
+#include "lib/log_int.h"
+
+void log_msg(int level, const char *fmt, va_list vl);
+
+
+static int log_fg;
+static int log_level = BLOG_DEBUG;
+
+void log_init(int foreground, enum blog_level level,
+ struct frr_daemon_info *fdi)
+{
+ log_fg = foreground;
+ log_level = level;
+
+ openzlog(fdi->progname, fdi->logname, 0,
+ LOG_CONS | LOG_NDELAY | LOG_PID, LOG_DAEMON);
+}
+
+void log_msg(int level, const char *fmt, va_list vl)
+{
+ if (level < log_level)
+ return;
+
+ switch (level) {
+ case BLOG_DEBUG:
+ vzlog(LOG_DEBUG, fmt, vl);
+ break;
+
+ case BLOG_INFO:
+ vzlog(LOG_INFO, fmt, vl);
+ break;
+
+ case BLOG_WARNING:
+ vzlog(LOG_WARNING, fmt, vl);
+ break;
+
+ case BLOG_ERROR:
+ vzlog(LOG_ERR, fmt, vl);
+ break;
+
+ case BLOG_FATAL:
+ vzlog(LOG_EMERG, fmt, vl);
+ break;
+
+ default:
+ vfprintf(stderr, fmt, vl);
+ break;
+ }
+}
+
+void log_info(const char *fmt, ...)
+{
+ va_list vl;
+
+ va_start(vl, fmt);
+ log_msg(BLOG_INFO, fmt, vl);
+ va_end(vl);
+}
+
+void log_debug(const char *fmt, ...)
+{
+ va_list vl;
+
+ va_start(vl, fmt);
+ log_msg(BLOG_DEBUG, fmt, vl);
+ va_end(vl);
+}
+
+void log_error(const char *fmt, ...)
+{
+ va_list vl;
+
+ va_start(vl, fmt);
+ log_msg(BLOG_ERROR, fmt, vl);
+ va_end(vl);
+}
+
+void log_warning(const char *fmt, ...)
+{
+ va_list vl;
+
+ va_start(vl, fmt);
+ log_msg(BLOG_WARNING, fmt, vl);
+ va_end(vl);
+}
+
+void log_fatal(const char *fmt, ...)
+{
+ va_list vl;
+
+ va_start(vl, fmt);
+ log_msg(BLOG_FATAL, fmt, vl);
+ va_end(vl);
+
+ exit(1);
+}
diff --git a/bfdd/ptm_adapter.c b/bfdd/ptm_adapter.c
new file mode 100644
index 0000000000..9a2b70d36a
--- /dev/null
+++ b/bfdd/ptm_adapter.c
@@ -0,0 +1,712 @@
+/*
+ * BFD PTM adapter code
+ * Copyright (C) 2018 Network Device Education Foundation, Inc. ("NetDEF")
+ *
+ * FRR is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * FRR is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with FRR; see the file COPYING. If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#include <zebra.h>
+
+#include "lib/libfrr.h"
+#include "lib/queue.h"
+#include "lib/stream.h"
+#include "lib/zclient.h"
+
+#include "lib/bfd.h"
+
+#include "bfd.h"
+
+/*
+ * Data structures
+ */
+struct ptm_client_notification {
+ struct bfd_session *pcn_bs;
+ struct ptm_client *pcn_pc;
+
+ TAILQ_ENTRY(ptm_client_notification) pcn_entry;
+};
+TAILQ_HEAD(pcnqueue, ptm_client_notification);
+
+struct ptm_client {
+ uint32_t pc_pid;
+ struct pcnqueue pc_pcnqueue;
+
+ TAILQ_ENTRY(ptm_client) pc_entry;
+};
+TAILQ_HEAD(pcqueue, ptm_client);
+
+static struct pcqueue pcqueue;
+static struct zclient *zclient;
+
+
+/*
+ * Prototypes
+ */
+static int _ptm_msg_address(struct stream *msg, struct sockaddr_any *sa);
+
+static void _ptm_msg_read_address(struct stream *msg, struct sockaddr_any *sa);
+static int _ptm_msg_read(struct stream *msg, int command,
+ struct bfd_peer_cfg *bpc, struct ptm_client **pc);
+
+static struct ptm_client *pc_lookup(uint32_t pid);
+static struct ptm_client *pc_new(uint32_t pid);
+static void pc_free(struct ptm_client *pc);
+static void pc_free_all(void);
+static struct ptm_client_notification *pcn_new(struct ptm_client *pc,
+ struct bfd_session *bs);
+static struct ptm_client_notification *pcn_lookup(struct ptm_client *pc,
+ struct bfd_session *bs);
+static void pcn_free(struct ptm_client_notification *pcn);
+
+
+static void bfdd_dest_register(struct stream *msg);
+static void bfdd_dest_deregister(struct stream *msg);
+static void bfdd_client_register(struct stream *msg);
+static void bfdd_client_deregister(struct stream *msg);
+
+/*
+ * Functions
+ */
+#ifdef BFD_DEBUG
+static void debug_printbpc(const char *func, unsigned int line,
+ struct bfd_peer_cfg *bpc);
+
+static void debug_printbpc(const char *func, unsigned int line,
+ struct bfd_peer_cfg *bpc)
+{
+ char addr[3][128];
+ char timers[3][128];
+
+ addr[0][0] = addr[1][0] = addr[2][0] = timers[0][0] = timers[1][0] =
+ timers[2][0] = 0;
+
+ snprintf(addr[0], sizeof(addr[0]), "peer:%s", satostr(&bpc->bpc_peer));
+ if (bpc->bpc_local.sa_sin.sin_family)
+ snprintf(addr[1], sizeof(addr[1]), " local:%s",
+ satostr(&bpc->bpc_local));
+
+ if (bpc->bpc_has_localif)
+ snprintf(addr[2], sizeof(addr[2]), " ifname:%s",
+ bpc->bpc_localif);
+
+ if (bpc->bpc_has_vrfname)
+ snprintf(addr[2], sizeof(addr[2]), " vrf:%s", bpc->bpc_vrfname);
+
+ if (bpc->bpc_has_recvinterval)
+ snprintf(timers[0], sizeof(timers[0]), " rx:%lu",
+ bpc->bpc_recvinterval);
+
+ if (bpc->bpc_has_txinterval)
+ snprintf(timers[1], sizeof(timers[1]), " tx:%lu",
+ bpc->bpc_recvinterval);
+
+ if (bpc->bpc_has_detectmultiplier)
+ snprintf(timers[2], sizeof(timers[2]), " detect-multiplier:%d",
+ bpc->bpc_detectmultiplier);
+
+ log_debug("%s:%d: %s %s%s%s%s%s%s", func, line,
+ bpc->bpc_mhop ? "multi-hop" : "single-hop", addr[0], addr[1],
+ addr[2], timers[0], timers[1], timers[2]);
+}
+
+#define DEBUG_PRINTBPC(bpc) debug_printbpc(__FILE__, __LINE__, (bpc))
+#else
+#define DEBUG_PRINTBPC(bpc)
+#endif /* BFD_DEBUG */
+
+static int _ptm_msg_address(struct stream *msg, struct sockaddr_any *sa)
+{
+ switch (sa->sa_sin.sin_family) {
+ case AF_INET:
+ stream_putc(msg, sa->sa_sin.sin_family);
+ stream_put_in_addr(msg, &sa->sa_sin.sin_addr);
+ stream_putc(msg, 32);
+ break;
+
+ case AF_INET6:
+ stream_putc(msg, sa->sa_sin6.sin6_family);
+ stream_put(msg, &sa->sa_sin6.sin6_addr,
+ sizeof(sa->sa_sin6.sin6_addr));
+ stream_putc(msg, 128);
+ break;
+
+ default:
+ return -1;
+ }
+
+ return 0;
+}
+
+int ptm_bfd_notify(struct bfd_session *bs)
+{
+ struct stream *msg;
+ struct sockaddr_any sac;
+
+ /*
+ * Message format:
+ * - header: command, vrf
+ * - l: interface index
+ * - c: family
+ * - AF_INET:
+ * - 4 bytes: ipv4
+ * - AF_INET6:
+ * - 16 bytes: ipv6
+ * - c: prefix length
+ * - l: bfd status
+ * - c: family
+ * - AF_INET:
+ * - 4 bytes: ipv4
+ * - AF_INET6:
+ * - 16 bytes: ipv6
+ * - c: prefix length
+ *
+ * Commands: ZEBRA_BFD_DEST_REPLAY
+ *
+ * q(64), l(32), w(16), c(8)
+ */
+ msg = zclient->obuf;
+ stream_reset(msg);
+
+ /* TODO: VRF handling */
+ zclient_create_header(msg, ZEBRA_BFD_DEST_REPLAY, VRF_DEFAULT);
+
+ /* This header will be handled by `zebra_ptm.c`. */
+ stream_putl(msg, ZEBRA_INTERFACE_BFD_DEST_UPDATE);
+
+ /* NOTE: Interface is a shortcut to avoid comparing source address. */
+ stream_putl(msg, bs->ifindex);
+
+ /* BFD destination prefix information. */
+ if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH))
+ _ptm_msg_address(msg, &bs->mhop.peer);
+ else
+ _ptm_msg_address(msg, &bs->shop.peer);
+
+ /* BFD status */
+ switch (bs->ses_state) {
+ case PTM_BFD_UP:
+ stream_putl(msg, BFD_STATUS_UP);
+ break;
+
+ case PTM_BFD_ADM_DOWN:
+ case PTM_BFD_DOWN:
+ case PTM_BFD_INIT:
+ stream_putl(msg, BFD_STATUS_DOWN);
+ break;
+
+ default:
+ stream_putl(msg, BFD_STATUS_UNKNOWN);
+ break;
+ }
+
+ /* BFD source prefix information. */
+ if (BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH)) {
+ _ptm_msg_address(msg, &bs->mhop.local);
+ } else {
+ if (bs->local_address.sa_sin.sin_family)
+ _ptm_msg_address(msg, &bs->local_address);
+ else if (bs->local_address.sa_sin.sin_family)
+ _ptm_msg_address(msg, &bs->local_ip);
+ else {
+ sac = bs->shop.peer;
+ switch (sac.sa_sin.sin_family) {
+ case AF_INET:
+ memset(&sac.sa_sin.sin_addr, 0,
+ sizeof(sac.sa_sin.sin_family));
+ break;
+ case AF_INET6:
+ memset(&sac.sa_sin6.sin6_addr, 0,
+ sizeof(sac.sa_sin6.sin6_family));
+ break;
+
+ default:
+ assert(false);
+ break;
+ }
+
+ /* No local address found yet, so send zeroes. */
+ _ptm_msg_address(msg, &sac);
+ }
+ }
+
+ /* Write packet size. */
+ stream_putw_at(msg, 0, stream_get_endp(msg));
+
+ return zclient_send_message(zclient);
+}
+
+static void _ptm_msg_read_address(struct stream *msg, struct sockaddr_any *sa)
+{
+ uint16_t family;
+
+ STREAM_GETW(msg, family);
+
+ switch (family) {
+ case AF_INET:
+ sa->sa_sin.sin_family = family;
+ STREAM_GET(&sa->sa_sin.sin_addr, msg,
+ sizeof(sa->sa_sin.sin_addr));
+#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
+ sa->sa_sin.sin_len = sizeof(sa->sa_sin);
+#endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */
+ return;
+
+ case AF_INET6:
+ sa->sa_sin6.sin6_family = family;
+ STREAM_GET(&sa->sa_sin6.sin6_addr, msg,
+ sizeof(sa->sa_sin6.sin6_addr));
+#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
+ sa->sa_sin6.sin6_len = sizeof(sa->sa_sin6);
+#endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */
+ return;
+
+ default:
+ log_warning("%s: invalid family: %d", __func__, family);
+ break;
+ }
+
+stream_failure:
+ memset(sa, 0, sizeof(*sa));
+}
+
+static int _ptm_msg_read(struct stream *msg, int command,
+ struct bfd_peer_cfg *bpc, struct ptm_client **pc)
+{
+ uint32_t pid;
+ uint8_t ttl __attribute__((unused));
+ uint8_t ifnamelen;
+
+ /*
+ * Register/Deregister/Update Message format:
+ * - header: Command, VRF
+ * - l: pid
+ * - w: family
+ * - AF_INET:
+ * - l: destination ipv4
+ * - AF_INET6:
+ * - 16 bytes: destination IPv6
+ * - command != ZEBRA_BFD_DEST_DEREGISTER
+ * - l: min_rx
+ * - l: min_tx
+ * - c: detect multiplier
+ * - c: is_multihop?
+ * - multihop:
+ * - w: family
+ * - AF_INET:
+ * - l: destination ipv4
+ * - AF_INET6:
+ * - 16 bytes: destination IPv6
+ * - c: ttl
+ * - no multihop
+ * - AF_INET6:
+ * - w: family
+ * - 16 bytes: ipv6 address
+ * - c: ifname length
+ * - X bytes: interface name
+ *
+ * q(64), l(32), w(16), c(8)
+ */
+
+ /* Initialize parameters return values. */
+ memset(bpc, 0, sizeof(*bpc));
+ *pc = NULL;
+
+ /* Find or allocate process context data. */
+ STREAM_GETL(msg, pid);
+
+ *pc = pc_new(pid);
+ if (*pc == NULL) {
+ log_debug("%s: failed to allocate memory", __func__);
+ return -1;
+ }
+
+ /* Register/update peer information. */
+ _ptm_msg_read_address(msg, &bpc->bpc_peer);
+
+ /* Determine IP type from peer destination. */
+ bpc->bpc_ipv4 = (bpc->bpc_peer.sa_sin.sin_family == AF_INET);
+
+ /* Get peer configuration. */
+ if (command != ZEBRA_BFD_DEST_DEREGISTER) {
+ STREAM_GETL(msg, bpc->bpc_recvinterval);
+ bpc->bpc_has_recvinterval =
+ (bpc->bpc_recvinterval != BPC_DEF_RECEIVEINTERVAL);
+
+ STREAM_GETL(msg, bpc->bpc_txinterval);
+ bpc->bpc_has_txinterval =
+ (bpc->bpc_txinterval != BPC_DEF_TRANSMITINTERVAL);
+
+ STREAM_GETC(msg, bpc->bpc_detectmultiplier);
+ bpc->bpc_has_detectmultiplier =
+ (bpc->bpc_detectmultiplier != BPC_DEF_DETECTMULTIPLIER);
+ }
+
+ /* Read (single|multi)hop and its options. */
+ STREAM_GETC(msg, bpc->bpc_mhop);
+ if (bpc->bpc_mhop) {
+ /* Read multihop source address and TTL. */
+ _ptm_msg_read_address(msg, &bpc->bpc_local);
+ STREAM_GETC(msg, ttl);
+ } else {
+ /* If target is IPv6, then we must obtain local address. */
+ if (bpc->bpc_ipv4 == false)
+ _ptm_msg_read_address(msg, &bpc->bpc_local);
+
+ /*
+ * Read interface name and make sure it fits our data
+ * structure, otherwise fail.
+ */
+ STREAM_GETC(msg, ifnamelen);
+ if (ifnamelen > sizeof(bpc->bpc_localif)) {
+ log_error("%s: interface name is too big", __func__);
+ return -1;
+ }
+
+ bpc->bpc_has_localif = ifnamelen > 0;
+ if (bpc->bpc_has_localif) {
+ STREAM_GET(bpc->bpc_localif, msg, ifnamelen);
+ bpc->bpc_localif[ifnamelen] = 0;
+ }
+ }
+
+ /* Sanity check: peer and local address must match IP types. */
+ if (bpc->bpc_local.sa_sin.sin_family != 0
+ && (bpc->bpc_local.sa_sin.sin_family
+ != bpc->bpc_peer.sa_sin.sin_family)) {
+ log_warning("%s: peer family doesn't match local type",
+ __func__);
+ return -1;
+ }
+
+ return 0;
+
+stream_failure:
+ return -1;
+}
+
+static void bfdd_dest_register(struct stream *msg)
+{
+ struct ptm_client *pc;
+ struct ptm_client_notification *pcn;
+ struct bfd_session *bs;
+ struct bfd_peer_cfg bpc;
+
+ /* Read the client context and peer data. */
+ if (_ptm_msg_read(msg, ZEBRA_BFD_DEST_REGISTER, &bpc, &pc) == -1)
+ return;
+
+ DEBUG_PRINTBPC(&bpc);
+
+ /* Find or start new BFD session. */
+ bs = bs_peer_find(&bpc);
+ if (bs == NULL) {
+ bs = ptm_bfd_sess_new(&bpc);
+ if (bs == NULL) {
+ log_debug("%s: failed to create BFD session", __func__);
+ return;
+ }
+ } else {
+ /* Don't try to change echo/shutdown state. */
+ bpc.bpc_echo = BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_ECHO);
+ bpc.bpc_shutdown =
+ BFD_CHECK_FLAG(bs->flags, BFD_SESS_FLAG_SHUTDOWN);
+ }
+
+ /* Create client peer notification register. */
+ pcn = pcn_new(pc, bs);
+ if (pcn == NULL) {
+ log_error("%s: failed to registrate notifications", __func__);
+ return;
+ }
+
+ ptm_bfd_notify(bs);
+}
+
+static void bfdd_dest_deregister(struct stream *msg)
+{
+ struct ptm_client *pc;
+ struct ptm_client_notification *pcn;
+ struct bfd_session *bs;
+ struct bfd_peer_cfg bpc;
+
+ /* Read the client context and peer data. */
+ if (_ptm_msg_read(msg, ZEBRA_BFD_DEST_DEREGISTER, &bpc, &pc) == -1)
+ return;
+
+ DEBUG_PRINTBPC(&bpc);
+
+ /* Find or start new BFD session. */
+ bs = bs_peer_find(&bpc);
+ if (bs == NULL) {
+ log_debug("%s: failed to create BFD session", __func__);
+ return;
+ }
+
+ /* Unregister client peer notification. */
+ pcn = pcn_lookup(pc, bs);
+ pcn_free(pcn);
+}
+
+/*
+ * header: command, VRF
+ * l: pid
+ */
+static void bfdd_client_register(struct stream *msg)
+{
+ struct ptm_client *pc;
+ uint32_t pid;
+
+ /* Find or allocate process context data. */
+ STREAM_GETL(msg, pid);
+
+ pc = pc_new(pid);
+ if (pc == NULL) {
+ log_error("%s: failed to register client: %u", __func__, pid);
+ return;
+ }
+
+ return;
+
+stream_failure:
+ log_error("%s: failed to register client", __func__);
+}
+
+/*
+ * header: command, VRF
+ * l: pid
+ */
+static void bfdd_client_deregister(struct stream *msg)
+{
+ struct ptm_client *pc;
+ uint32_t pid;
+
+ /* Find or allocate process context data. */
+ STREAM_GETL(msg, pid);
+
+ pc = pc_lookup(pid);
+ if (pc == NULL) {
+ log_debug("%s: failed to find client: %u", __func__, pid);
+ return;
+ }
+
+ pc_free(pc);
+
+ return;
+
+stream_failure:
+ log_error("%s: failed to deregister client", __func__);
+}
+
+static int bfdd_replay(int cmd, struct zclient *zc, uint16_t len, vrf_id_t vid)
+{
+ struct stream *msg = zc->ibuf;
+ uint32_t rcmd;
+
+ STREAM_GETL(msg, rcmd);
+
+ switch (rcmd) {
+ case ZEBRA_BFD_DEST_REGISTER:
+ case ZEBRA_BFD_DEST_UPDATE:
+ bfdd_dest_register(msg);
+ break;
+ case ZEBRA_BFD_DEST_DEREGISTER:
+ bfdd_dest_deregister(msg);
+ break;
+ case ZEBRA_BFD_CLIENT_REGISTER:
+ bfdd_client_register(msg);
+ break;
+ case ZEBRA_BFD_CLIENT_DEREGISTER:
+ bfdd_client_deregister(msg);
+ break;
+
+ default:
+ log_debug("%s: invalid message type %u", __func__, rcmd);
+ return -1;
+ }
+
+ return 0;
+
+stream_failure:
+ log_error("%s: failed to find command", __func__);
+ return -1;
+}
+
+static void bfdd_zebra_connected(struct zclient *zc)
+{
+ struct stream *msg = zc->obuf;
+
+ /* Clean-up and free ptm clients data memory. */
+ pc_free_all();
+
+ /*
+ * The replay is an empty message just to trigger client daemons
+ * configuration replay.
+ */
+ stream_reset(msg);
+ zclient_create_header(msg, ZEBRA_BFD_DEST_REPLAY, VRF_DEFAULT);
+ stream_putl(msg, ZEBRA_BFD_DEST_REPLAY);
+ stream_putw_at(msg, 0, stream_get_endp(msg));
+
+ zclient_send_message(zclient);
+}
+
+void bfdd_zclient_init(struct zebra_privs_t *bfdd_priv)
+{
+ zclient = zclient_new_notify(master, &zclient_options_default);
+ assert(zclient != NULL);
+ zclient_init(zclient, ZEBRA_ROUTE_BFD, 0, bfdd_priv);
+
+ /*
+ * We'll receive all messages through replay, however it will
+ * contain a special field with the real command inside so we
+ * avoid having to create too many handlers.
+ */
+ zclient->bfd_dest_replay = bfdd_replay;
+
+ /* Send replay request on zebra connect. */
+ zclient->zebra_connected = bfdd_zebra_connected;
+}
+
+void bfdd_zclient_stop(void)
+{
+ zclient_stop(zclient);
+
+ /* Clean-up and free ptm clients data memory. */
+ pc_free_all();
+}
+
+
+/*
+ * Client handling.
+ */
+static struct ptm_client *pc_lookup(uint32_t pid)
+{
+ struct ptm_client *pc;
+
+ TAILQ_FOREACH (pc, &pcqueue, pc_entry) {
+ if (pc->pc_pid != pid)
+ continue;
+
+ break;
+ }
+
+ return pc;
+}
+
+static struct ptm_client *pc_new(uint32_t pid)
+{
+ struct ptm_client *pc;
+
+ /* Look up first, if not found create the client. */
+ pc = pc_lookup(pid);
+ if (pc != NULL)
+ return pc;
+
+ /* Allocate the client data and save it. */
+ pc = XCALLOC(MTYPE_BFDD_CONTROL, sizeof(*pc));
+ if (pc == NULL)
+ return NULL;
+
+ pc->pc_pid = pid;
+ TAILQ_INSERT_HEAD(&pcqueue, pc, pc_entry);
+ return pc;
+}
+
+static void pc_free(struct ptm_client *pc)
+{
+ struct ptm_client_notification *pcn;
+
+ if (pc == NULL)
+ return;
+
+ TAILQ_REMOVE(&pcqueue, pc, pc_entry);
+
+ while (!TAILQ_EMPTY(&pc->pc_pcnqueue)) {
+ pcn = TAILQ_FIRST(&pc->pc_pcnqueue);
+ pcn_free(pcn);
+ }
+
+ XFREE(MTYPE_BFDD_CONTROL, pc);
+}
+
+static void pc_free_all(void)
+{
+ struct ptm_client *pc;
+
+ while (!TAILQ_EMPTY(&pcqueue)) {
+ pc = TAILQ_FIRST(&pcqueue);
+ pc_free(pc);
+ }
+}
+
+static struct ptm_client_notification *pcn_new(struct ptm_client *pc,
+ struct bfd_session *bs)
+{
+ struct ptm_client_notification *pcn;
+
+ /* Try to find an existing pcn fist. */
+ pcn = pcn_lookup(pc, bs);
+ if (pcn != NULL)
+ return pcn;
+
+ /* Save the client notification data. */
+ pcn = XCALLOC(MTYPE_BFDD_NOTIFICATION, sizeof(*pcn));
+ if (pcn == NULL)
+ return NULL;
+
+ TAILQ_INSERT_HEAD(&pc->pc_pcnqueue, pcn, pcn_entry);
+ pcn->pcn_pc = pc;
+ pcn->pcn_bs = bs;
+ bs->refcount++;
+
+ return pcn;
+}
+
+static struct ptm_client_notification *pcn_lookup(struct ptm_client *pc,
+ struct bfd_session *bs)
+{
+ struct ptm_client_notification *pcn;
+
+ TAILQ_FOREACH (pcn, &pc->pc_pcnqueue, pcn_entry) {
+ if (pcn->pcn_bs != bs)
+ continue;
+
+ break;
+ }
+
+ return pcn;
+}
+
+static void pcn_free(struct ptm_client_notification *pcn)
+{
+ struct ptm_client *pc;
+ struct bfd_session *bs;
+
+ if (pcn == NULL)
+ return;
+
+ /* Handle session de-registration. */
+ bs = pcn->pcn_bs;
+ pcn->pcn_bs = NULL;
+ bs->refcount--;
+
+ /* Handle ptm_client deregistration. */
+ pc = pcn->pcn_pc;
+ pcn->pcn_pc = NULL;
+ TAILQ_REMOVE(&pc->pc_pcnqueue, pcn, pcn_entry);
+
+ XFREE(MTYPE_BFDD_NOTIFICATION, pcn);
+}
diff --git a/bfdd/subdir.am b/bfdd/subdir.am
new file mode 100644
index 0000000000..86923f5cec
--- /dev/null
+++ b/bfdd/subdir.am
@@ -0,0 +1,33 @@
+#
+# bfdd
+#
+
+if BFDD
+noinst_LIBRARIES += bfdd/libbfd.a
+sbin_PROGRAMS += bfdd/bfdd
+dist_examples_DATA += bfdd/bfdd.conf.sample
+endif
+
+bfdd_libbfd_a_SOURCES = \
+ bfdd/bfd.c \
+ bfdd/bfdd_vty.c \
+ bfdd/bfd_packet.c \
+ bfdd/bsd.c \
+ bfdd/config.c \
+ bfdd/control.c \
+ bfdd/event.c \
+ bfdd/linux.c \
+ bfdd/log.c \
+ bfdd/ptm_adapter.c \
+ # end
+
+bfdd/bfdd_vty_clippy.c: $(CLIPPY_DEPS)
+bfdd/bfdd_vty.$(OBJEXT): bfdd/bfdd_vty_clippy.c
+
+noinst_HEADERS += \
+ bfdd/bfdctl.h \
+ bfdd/bfd.h \
+ # end
+
+bfdd_bfdd_SOURCES = bfdd/bfdd.c
+bfdd_bfdd_LDADD = bfdd/libbfd.a lib/libfrr.la
diff --git a/bgpd/Makefile.am b/bgpd/Makefile.am
index 2f19bbbd73..b6b125f752 100644
--- a/bgpd/Makefile.am
+++ b/bgpd/Makefile.am
@@ -85,7 +85,7 @@ libbgp_a_SOURCES = \
bgp_encap_tlv.c $(BGP_VNC_RFAPI_SRC) bgp_attr_evpn.c \
bgp_evpn.c bgp_evpn_vty.c bgp_vpn.c bgp_label.c bgp_rd.c \
bgp_keepalives.c bgp_io.c bgp_flowspec.c bgp_flowspec_util.c \
- bgp_flowspec_vty.c bgp_labelpool.c bgp_pbr.c
+ bgp_flowspec_vty.c bgp_labelpool.c bgp_pbr.c bgp_errors.c
noinst_HEADERS = \
bgp_memory.h \
@@ -99,7 +99,7 @@ noinst_HEADERS = \
$(BGP_VNC_RFAPI_HD) bgp_attr_evpn.h bgp_evpn.h bgp_evpn_vty.h \
bgp_vpn.h bgp_label.h bgp_rd.h bgp_evpn_private.h bgp_keepalives.h \
bgp_io.h bgp_flowspec.h bgp_flowspec_private.h bgp_flowspec_util.h \
- bgp_labelpool.h bgp_pbr.h
+ bgp_labelpool.h bgp_pbr.h bgp_errors.h
bgpd_SOURCES = bgp_main.c
bgpd_LDADD = libbgp.a $(BGP_VNC_RFP_LIB) ../lib/libfrr.la @LIBCAP@ @LIBM@
diff --git a/bgpd/bgp_aspath.c b/bgpd/bgp_aspath.c
index 05e67baa8a..d6ad52b3a6 100644
--- a/bgpd/bgp_aspath.c
+++ b/bgpd/bgp_aspath.c
@@ -214,16 +214,11 @@ static struct assegment *assegment_append_asns(struct assegment *seg,
newas = XREALLOC(MTYPE_AS_SEG_DATA, seg->as,
ASSEGMENT_DATA_SIZE(seg->length + num, 1));
- if (newas) {
- seg->as = newas;
- memcpy(seg->as + seg->length, asnos,
- ASSEGMENT_DATA_SIZE(num, 1));
- seg->length += num;
- return seg;
- }
-
- assegment_free_all(seg);
- return NULL;
+ seg->as = newas;
+ memcpy(seg->as + seg->length, asnos,
+ ASSEGMENT_DATA_SIZE(num, 1));
+ seg->length += num;
+ return seg;
}
static int int_cmp(const void *p1, const void *p2)
diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c
index e5ad5e2338..6acd4c8cf1 100644
--- a/bgpd/bgp_attr.c
+++ b/bgpd/bgp_attr.c
@@ -39,6 +39,7 @@
#include "bgpd/bgp_aspath.h"
#include "bgpd/bgp_community.h"
#include "bgpd/bgp_debug.h"
+#include "bgpd/bgp_errors.h"
#include "bgpd/bgp_label.h"
#include "bgpd/bgp_packet.h"
#include "bgpd/bgp_ecommunity.h"
@@ -996,12 +997,14 @@ bgp_attr_flags_diagnose(struct bgp_attr_parser_args *args,
for (i = 0; i <= 2; i++) /* O,T,P, but not E */
if (CHECK_FLAG(desired_flags, attr_flag_str[i].key)
!= CHECK_FLAG(real_flags, attr_flag_str[i].key)) {
- zlog_err("%s attribute must%s be flagged as \"%s\"",
- lookup_msg(attr_str, attr_code, NULL),
- CHECK_FLAG(desired_flags, attr_flag_str[i].key)
- ? ""
- : " not",
- attr_flag_str[i].str);
+ flog_err(
+ BGP_ERR_ATTR_FLAG,
+ "%s attribute must%s be flagged as \"%s\"",
+ lookup_msg(attr_str, attr_code, NULL),
+ CHECK_FLAG(desired_flags, attr_flag_str[i].key)
+ ? ""
+ : " not",
+ attr_flag_str[i].str);
seen = 1;
}
if (!seen) {
@@ -1059,7 +1062,8 @@ static int bgp_attr_flag_invalid(struct bgp_attr_parser_args *args)
*/
if (!CHECK_FLAG(BGP_ATTR_FLAG_OPTIONAL, flags)
&& !CHECK_FLAG(BGP_ATTR_FLAG_TRANS, flags)) {
- zlog_err(
+ flog_err(
+ BGP_ERR_ATTR_FLAG,
"%s well-known attributes must have transitive flag set (%x)",
lookup_msg(attr_str, attr_code, NULL), flags);
return 1;
@@ -1071,18 +1075,18 @@ static int bgp_attr_flag_invalid(struct bgp_attr_parser_args *args)
*/
if (CHECK_FLAG(flags, BGP_ATTR_FLAG_PARTIAL)) {
if (!CHECK_FLAG(flags, BGP_ATTR_FLAG_OPTIONAL)) {
- zlog_err(
- "%s well-known attribute "
- "must NOT have the partial flag set (%x)",
- lookup_msg(attr_str, attr_code, NULL), flags);
+ flog_err(BGP_ERR_ATTR_FLAG,
+ "%s well-known attribute "
+ "must NOT have the partial flag set (%x)",
+ lookup_msg(attr_str, attr_code, NULL), flags);
return 1;
}
if (CHECK_FLAG(flags, BGP_ATTR_FLAG_OPTIONAL)
&& !CHECK_FLAG(flags, BGP_ATTR_FLAG_TRANS)) {
- zlog_err(
- "%s optional + transitive attribute "
- "must NOT have the partial flag set (%x)",
- lookup_msg(attr_str, attr_code, NULL), flags);
+ flog_err(BGP_ERR_ATTR_FLAG,
+ "%s optional + transitive attribute "
+ "must NOT have the partial flag set (%x)",
+ lookup_msg(attr_str, attr_code, NULL), flags);
return 1;
}
}
@@ -1114,7 +1118,8 @@ static bgp_attr_parse_ret_t bgp_attr_origin(struct bgp_attr_parser_args *args)
field contains the erroneous attribute (type, length and
value). */
if (length != 1) {
- zlog_err("Origin attribute length is not one %d", length);
+ flog_err(BGP_ERR_ATTR_LEN,
+ "Origin attribute length is not one %d", length);
return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
args->total);
}
@@ -1127,7 +1132,8 @@ static bgp_attr_parse_ret_t bgp_attr_origin(struct bgp_attr_parser_args *args)
contains the unrecognized attribute (type, length and value). */
if ((attr->origin != BGP_ORIGIN_IGP) && (attr->origin != BGP_ORIGIN_EGP)
&& (attr->origin != BGP_ORIGIN_INCOMPLETE)) {
- zlog_err("Origin attribute value is invalid %d", attr->origin);
+ flog_err(BGP_ERR_ATTR_ORIGIN,
+ "Origin attribute value is invalid %d", attr->origin);
return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_INVAL_ORIGIN,
args->total);
}
@@ -1155,8 +1161,9 @@ static int bgp_attr_aspath(struct bgp_attr_parser_args *args)
/* In case of IBGP, length will be zero. */
if (!attr->aspath) {
- zlog_err("Malformed AS path from %s, length is %d", peer->host,
- length);
+ flog_err(BGP_ERR_ATTR_MAL_AS_PATH,
+ "Malformed AS path from %s, length is %d", peer->host,
+ length);
return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_MAL_AS_PATH,
0);
}
@@ -1184,7 +1191,8 @@ static bgp_attr_parse_ret_t bgp_attr_aspath_check(struct peer *const peer,
&& !aspath_left_confed_check(attr->aspath))
|| (peer->sort == BGP_PEER_EBGP
&& aspath_confed_check(attr->aspath))) {
- zlog_err("Malformed AS path from %s", peer->host);
+ flog_err(BGP_ERR_ATTR_MAL_AS_PATH, "Malformed AS path from %s",
+ peer->host);
bgp_notify_send(peer, BGP_NOTIFY_UPDATE_ERR,
BGP_NOTIFY_UPDATE_MAL_AS_PATH);
return BGP_ATTR_PARSE_ERROR;
@@ -1194,8 +1202,9 @@ static bgp_attr_parse_ret_t bgp_attr_aspath_check(struct peer *const peer,
if (CHECK_FLAG(peer->flags, PEER_FLAG_ENFORCE_FIRST_AS)) {
if (peer->sort == BGP_PEER_EBGP
&& !aspath_firstas_check(attr->aspath, peer->as)) {
- zlog_err("%s incorrect first AS (must be %u)",
- peer->host, peer->as);
+ flog_err(BGP_ERR_ATTR_FIRST_AS,
+ "%s incorrect first AS (must be %u)",
+ peer->host, peer->as);
bgp_notify_send(peer, BGP_NOTIFY_UPDATE_ERR,
BGP_NOTIFY_UPDATE_MAL_AS_PATH);
return BGP_ATTR_PARSE_ERROR;
@@ -1227,8 +1236,9 @@ static int bgp_attr_as4_path(struct bgp_attr_parser_args *args,
/* In case of IBGP, length will be zero. */
if (!*as4_path) {
- zlog_err("Malformed AS4 path from %s, length is %d", peer->host,
- length);
+ flog_err(BGP_ERR_ATTR_MAL_AS_PATH,
+ "Malformed AS4 path from %s, length is %d",
+ peer->host, length);
return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_MAL_AS_PATH,
0);
}
@@ -1250,7 +1260,8 @@ static bgp_attr_parse_ret_t bgp_attr_nexthop(struct bgp_attr_parser_args *args)
/* Check nexthop attribute length. */
if (length != 4) {
- zlog_err("Nexthop attribute length isn't four [%d]", length);
+ flog_err(BGP_ERR_ATTR_LEN,
+ "Nexthop attribute length isn't four [%d]", length);
return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
args->total);
@@ -1274,7 +1285,7 @@ static bgp_attr_parse_ret_t bgp_attr_nexthop(struct bgp_attr_parser_args *args)
{
char buf[INET_ADDRSTRLEN];
inet_ntop(AF_INET, &nexthop_n, buf, INET_ADDRSTRLEN);
- zlog_err("Martian nexthop %s", buf);
+ flog_err(BGP_ERR_ATTR_MARTIAN_NH, "Martian nexthop %s", buf);
return bgp_attr_malformed(
args, BGP_NOTIFY_UPDATE_INVAL_NEXT_HOP, args->total);
}
@@ -1294,7 +1305,8 @@ static bgp_attr_parse_ret_t bgp_attr_med(struct bgp_attr_parser_args *args)
/* Length check. */
if (length != 4) {
- zlog_err("MED attribute length isn't four [%d]", length);
+ flog_err(BGP_ERR_ATTR_LEN,
+ "MED attribute length isn't four [%d]", length);
return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
args->total);
@@ -1317,7 +1329,8 @@ bgp_attr_local_pref(struct bgp_attr_parser_args *args)
/* Length check. */
if (length != 4) {
- zlog_err("LOCAL_PREF attribute length isn't 4 [%u]", length);
+ flog_err(BGP_ERR_ATTR_LEN,
+ "LOCAL_PREF attribute length isn't 4 [%u]", length);
return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
args->total);
}
@@ -1346,8 +1359,9 @@ static int bgp_attr_atomic(struct bgp_attr_parser_args *args)
/* Length check. */
if (length != 0) {
- zlog_err("ATOMIC_AGGREGATE attribute length isn't 0 [%u]",
- length);
+ flog_err(BGP_ERR_ATTR_LEN,
+ "ATOMIC_AGGREGATE attribute length isn't 0 [%u]",
+ length);
return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
args->total);
}
@@ -1372,8 +1386,9 @@ static int bgp_attr_aggregator(struct bgp_attr_parser_args *args)
wantedlen = 8;
if (length != wantedlen) {
- zlog_err("AGGREGATOR attribute length isn't %u [%u]", wantedlen,
- length);
+ flog_err(BGP_ERR_ATTR_LEN,
+ "AGGREGATOR attribute length isn't %u [%u]",
+ wantedlen, length);
return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
args->total);
}
@@ -1401,7 +1416,8 @@ bgp_attr_as4_aggregator(struct bgp_attr_parser_args *args,
const bgp_size_t length = args->length;
if (length != 8) {
- zlog_err("New Aggregator length is not 8 [%d]", length);
+ flog_err(BGP_ERR_ATTR_LEN,
+ "New Aggregator length is not 8 [%d]", length);
return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
0);
}
@@ -1560,7 +1576,8 @@ bgp_attr_originator_id(struct bgp_attr_parser_args *args)
/* Length check. */
if (length != 4) {
- zlog_err("Bad originator ID length %d", length);
+ flog_err(BGP_ERR_ATTR_LEN, "Bad originator ID length %d",
+ length);
return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
args->total);
@@ -1583,7 +1600,8 @@ bgp_attr_cluster_list(struct bgp_attr_parser_args *args)
/* Check length. */
if (length % 4) {
- zlog_err("Bad cluster list length %d", length);
+ flog_err(BGP_ERR_ATTR_LEN, "Bad cluster list length %d",
+ length);
return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
args->total);
@@ -2052,10 +2070,10 @@ static bgp_attr_parse_ret_t bgp_attr_psid_sub(int32_t type,
if (type == BGP_PREFIX_SID_LABEL_INDEX) {
if (length != BGP_PREFIX_SID_LABEL_INDEX_LENGTH) {
- zlog_err(
- "Prefix SID label index length is %d instead of %d",
- length,
- BGP_PREFIX_SID_LABEL_INDEX_LENGTH);
+ flog_err(
+ BGP_ERR_ATTR_LEN,
+ "Prefix SID label index length is %d instead of %d",
+ length, BGP_PREFIX_SID_LABEL_INDEX_LENGTH);
return bgp_attr_malformed(args,
BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
args->total);
@@ -2088,8 +2106,9 @@ static bgp_attr_parse_ret_t bgp_attr_psid_sub(int32_t type,
/* Placeholder code for the IPv6 SID type */
else if (type == BGP_PREFIX_SID_IPV6) {
if (length != BGP_PREFIX_SID_IPV6_LENGTH) {
- zlog_err("Prefix SID IPv6 length is %d instead of %d",
- length, BGP_PREFIX_SID_IPV6_LENGTH);
+ flog_err(BGP_ERR_ATTR_LEN,
+ "Prefix SID IPv6 length is %d instead of %d",
+ length, BGP_PREFIX_SID_IPV6_LENGTH);
return bgp_attr_malformed(args,
BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
args->total);
@@ -2110,7 +2129,8 @@ static bgp_attr_parse_ret_t bgp_attr_psid_sub(int32_t type,
length -= 2;
if (length % BGP_PREFIX_SID_ORIGINATOR_SRGB_LENGTH) {
- zlog_err(
+ flog_err(
+ BGP_ERR_ATTR_LEN,
"Prefix SID Originator SRGB length is %d, it must be a multiple of %d ",
length, BGP_PREFIX_SID_ORIGINATOR_SRGB_LENGTH);
return bgp_attr_malformed(
@@ -2159,8 +2179,10 @@ bgp_attr_prefix_sid(int32_t tlength, struct bgp_attr_parser_args *args,
tlength -= length + 3;
if (tlength < 0) {
- zlog_err("Prefix SID internal length %d causes us to read beyond the total Prefix SID length",
- length);
+ flog_err(
+ BGP_ERR_ATTR_LEN,
+ "Prefix SID internal length %d causes us to read beyond the total Prefix SID length",
+ length);
return bgp_attr_malformed(args,
BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
args->total);
@@ -2185,21 +2207,24 @@ bgp_attr_pmsi_tunnel(struct bgp_attr_parser_args *args)
* can only support that.
*/
if (length < 2) {
- zlog_err("Bad PMSI tunnel attribute length %d", length);
+ flog_err(BGP_ERR_ATTR_LEN,
+ "Bad PMSI tunnel attribute length %d", length);
return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
args->total);
}
stream_getc(peer->curr); /* Flags */
tnl_type = stream_getc(peer->curr);
if (tnl_type > PMSI_TNLTYPE_MAX) {
- zlog_err("Invalid PMSI tunnel attribute type %d", tnl_type);
+ flog_err(BGP_ERR_ATTR_PMSI_TYPE,
+ "Invalid PMSI tunnel attribute type %d", tnl_type);
return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_OPT_ATTR_ERR,
args->total);
}
if (tnl_type == PMSI_TNLTYPE_INGR_REPL) {
if (length != 9) {
- zlog_err("Bad PMSI tunnel attribute length %d for IR",
- length);
+ flog_err(BGP_ERR_ATTR_PMSI_LEN,
+ "Bad PMSI tunnel attribute length %d for IR",
+ length);
return bgp_attr_malformed(
args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
args->total);
@@ -2799,9 +2824,10 @@ size_t bgp_packet_mpattr_start(struct stream *s, struct peer *peer, afi_t afi,
break;
default:
if (safi != SAFI_FLOWSPEC)
- zlog_err(
- "Bad nexthop when sending to %s, AFI %u SAFI %u nhlen %d",
- peer->host, afi, safi, attr->mp_nexthop_len);
+ flog_err(
+ BGP_ERR_ATTR_NH_SEND_LEN,
+ "Bad nexthop when sending to %s, AFI %u SAFI %u nhlen %d",
+ peer->host, afi, safi, attr->mp_nexthop_len);
break;
}
diff --git a/bgpd/bgp_bfd.c b/bgpd/bgp_bfd.c
index c7d6249870..47dffd146a 100644
--- a/bgpd/bgp_bfd.c
+++ b/bgpd/bgp_bfd.c
@@ -509,9 +509,13 @@ void bgp_bfd_peer_config_write(struct vty *vty, struct peer *peer, char *addr)
bfd_info = (struct bfd_info *)peer->bfd_info;
if (CHECK_FLAG(bfd_info->flags, BFD_FLAG_PARAM_CFG))
+#if HAVE_BFDD > 0
+ vty_out(vty, " neighbor %s bfd\n", addr);
+#else
vty_out(vty, " neighbor %s bfd %d %d %d\n", addr,
bfd_info->detect_mult, bfd_info->required_min_rx,
bfd_info->desired_min_tx);
+#endif /* HAVE_BFDD */
if (bfd_info->type != BFD_TYPE_NOT_CONFIGURED)
vty_out(vty, " neighbor %s bfd %s\n", addr,
@@ -556,7 +560,12 @@ DEFUN (neighbor_bfd,
return CMD_SUCCESS;
}
-DEFUN (neighbor_bfd_param,
+#if HAVE_BFDD > 0
+DEFUN_HIDDEN(
+#else
+DEFUN(
+#endif /* HAVE_BFDD */
+ neighbor_bfd_param,
neighbor_bfd_param_cmd,
"neighbor <A.B.C.D|X:X::X:X|WORD> bfd (2-255) (50-60000) (50-60000)",
NEIGHBOR_STR
@@ -628,14 +637,21 @@ DEFUN_HIDDEN (neighbor_bfd_type,
DEFUN (no_neighbor_bfd,
no_neighbor_bfd_cmd,
+#if HAVE_BFDD > 0
+ "no neighbor <A.B.C.D|X:X::X:X|WORD> bfd",
+#else
"no neighbor <A.B.C.D|X:X::X:X|WORD> bfd [(2-255) (50-60000) (50-60000)]",
+#endif /* HAVE_BFDD */
NO_STR
NEIGHBOR_STR
NEIGHBOR_ADDR_STR2
"Disables BFD support\n"
+#if HAVE_BFDD == 0
"Detect Multiplier\n"
"Required min receive interval\n"
- "Desired min transmit interval\n")
+ "Desired min transmit interval\n"
+#endif /* !HAVE_BFDD */
+)
{
int idx_peer = 2;
struct peer *peer;
diff --git a/bgpd/bgp_debug.c b/bgpd/bgp_debug.c
index c7c36882af..f49f80b5d9 100644
--- a/bgpd/bgp_debug.c
+++ b/bgpd/bgp_debug.c
@@ -621,7 +621,7 @@ static int bgp_debug_parse_evpn_prefix(struct vty *vty, struct cmd_token **argv,
memset(&ip, 0, sizeof(struct ipaddr));
argv_find(argv, argc, "mac", &mac_idx);
- prefix_str2mac(argv[mac_idx + 1]->arg, &mac);
+ (void)prefix_str2mac(argv[mac_idx + 1]->arg, &mac);
argv_find(argv, argc, "ip", &ip_idx);
str2ipaddr(argv[ip_idx + 1]->arg, &ip);
diff --git a/bgpd/bgp_errors.c b/bgpd/bgp_errors.c
new file mode 100644
index 0000000000..50dd001b8b
--- /dev/null
+++ b/bgpd/bgp_errors.c
@@ -0,0 +1,306 @@
+/*
+ * BGP-specific error messages.
+ * Copyright (C) 2018 Cumulus Networks, Inc.
+ * Don Slice
+ *
+ * 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 "lib/ferr.h"
+#include "bgp_errors.h"
+
+/* clang-format off */
+static struct log_ref ferr_bgp_err[] = {
+ {
+ .code = BGP_ERR_ATTR_FLAG,
+ .title = "BGP attribute flag is incorrect",
+ .description = "BGP attribute flag is set to the wrong value (Optional/Transitive/Partial)",
+ .suggestion = "Determine the soure of the attribute and determine why the attribute flag has been set incorrectly"
+ },
+ {
+ .code = BGP_ERR_ATTR_LEN,
+ .title = "BGP attribute length is incorrect",
+ .description = "BGP attribute length is incorrect",
+ .suggestion = "Determine the soure of the attribute and determine why the attribute length has been set incorrectly"
+ },
+ {
+ .code = BGP_ERR_ATTR_ORIGIN,
+ .title = "BGP attribute origin value invalid",
+ .description = "BGP attribute origin value is invalid",
+ .suggestion = "Determine the soure of the attribute and determine why the origin attribute has been set incorrectly"
+ },
+ {
+ .code = BGP_ERR_ATTR_MAL_AS_PATH,
+ .title = "BGP as path is invalid",
+ .description = "BGP as path has been malformed",
+ .suggestion = "Determine the soure of the update and determine why the as path has been set incorrectly"
+ },
+ {
+ .code = BGP_ERR_ATTR_FIRST_AS,
+ .title = "BGP as path first as is invalid",
+ .description = "BGP update has invalid first as in as path",
+ .suggestion = "Determine the soure of the update and determine why the as path first as value has been set incorrectly"
+ },
+ {
+ .code = BGP_ERR_ATTR_PMSI_TYPE,
+ .title = "BGP PMSI tunnel attribute type is invalid",
+ .description = "BGP update has invalid type for PMSI tunnel",
+ .suggestion = "Determine the soure of the update and determine why the PMSI tunnel attribute type has been set incorrectly"
+ },
+ {
+ .code = BGP_ERR_ATTR_PMSI_LEN,
+ .title = "BGP PMSI tunnel attribute length is invalid",
+ .description = "BGP update has invalid length for PMSI tunnel",
+ .suggestion = "Determine the soure of the update and determine why the PMSI tunnel attribute length has been set incorrectly"
+ },
+ {
+ .code = BGP_ERR_PEER_GROUP,
+ .title = "BGP peergroup operated on in error",
+ .description = "BGP operating on peer-group instead of peers included",
+ .suggestion = "Ensure the config doesn't contain peergroups contained within peergroups"
+ },
+ {
+ .code = BGP_ERR_PEER_DELETE,
+ .title = "BGP failed to delete peer structure",
+ .description = "BGP was unable to delete peer structure when address-family removed",
+ .suggestion = "Determine if all expected peers are removed and restart FRR if not. Most likely a bug"
+ },
+ {
+ .code = BGP_ERR_TABLE_CHUNK,
+ .title = "BGP failed to get table chunk memory",
+ .description = "BGP unable to get chunk memory for table manager",
+ .suggestion = "Ensure there is adequate memory on the device to support the table requirements"
+ },
+ {
+ .code = BGP_ERR_MACIP_LEN,
+ .title = "BGP received MACIP with invalid IP addr len",
+ .description = "BGP received MACIP with invalid IP addr len from Zebra",
+ .suggestion = "Verify MACIP entries inserted in Zebra are correct. Most likely a bug"
+ },
+ {
+ .code = BGP_ERR_LM_ERROR,
+ .title = "BGP received invalid label manager message",
+ .description = "BGP received invalid label manager message from label manager",
+ .suggestion = "Label manager sent invalid essage to BGP for wrong protocol, instance, etc. Most likely a bug"
+ },
+ {
+ .code = BGP_ERR_JSON_MEM_ERROR,
+ .title = "BGP unable to allocate memory for JSON output",
+ .description = "BGP attempted to generate JSON output and was unable to allocate the memory required",
+ .suggestion = "Ensure that the device has adequate memory to suport the required functions"
+ },
+ {
+ .code = BGP_ERR_UPDGRP_ATTR_LEN,
+ .title = "BGP update had attributes too long to send",
+ .description = "BGP attempted to send an update but the attributes were too long to fit",
+ .suggestion = "Most likely a bug. If the problem persists, report the problem for troubleshooting"
+ },
+ {
+ .code = BGP_ERR_UPDGRP_CREATE,
+ .title = "BGP update group creation failed",
+ .description = "BGP attempted to create an update group but was unable to",
+ .suggestion = "Most likely a bug. If the problem persists, report the problem for troubleshooting"
+ },
+ {
+ .code = BGP_ERR_UPDATE_SND,
+ .title = "BGP error creating update packet",
+ .description = "BGP attempted to create an update packet but was unable to",
+ .suggestion = "Most likely a bug. If the problem persists, report the problem for troubleshooting"
+ },
+ {
+ .code = BGP_ERR_PKT_OPEN,
+ .title = "BGP error receiving open packet",
+ .description = "BGP received an open from a peer that was invalid",
+ .suggestion = "Determine the sending peer and correct his invalid open packet"
+ },
+ {
+ .code = BGP_ERR_SND_FAIL,
+ .title = "BGP error sending to peer",
+ .description = "BGP attempted to respond to open from a peer and failed",
+ .suggestion = "BGP attempted to respond to an open and could not sene the packet. Check local IP address for source"
+ },
+ {
+ .code = BGP_ERR_INVALID_STATUS,
+ .title = "BGP error receiving from peer",
+ .description = "BGP received an update from a peer but status was incorrect",
+ .suggestion = "Most likely a bug. If the problem persists, report the problem for troubleshooting"
+ },
+ {
+ .code = BGP_ERR_UPDATE_RCV,
+ .title = "BGP error receiving update packet",
+ .description = "BGP received an invalid update packet",
+ .suggestion = "Determine the source of the update and resolve the invalid update being sent"
+ },
+ {
+ .code = BGP_ERR_NO_CAP,
+ .title = "BGP error due to capability not enabled",
+ .description = "BGP attempted a function that did not have the capability enabled",
+ .suggestion = "Enable the capability if this functionality is desired"
+ },
+ {
+ .code = BGP_ERR_NOTIFY_RCV,
+ .title = "BGP error receiving notify message",
+ .description = "BGP unable to process notification message",
+ .suggestion = "BGP notify received while in stopped state. If the problem persists, report for troubleshooting"
+ },
+ {
+ .code = BGP_ERR_KEEP_RCV,
+ .title = "BGP error receiving keepalive packet",
+ .description = "BGP unable to process keepalive packet",
+ .suggestion = "BGP keepalive received while in stopped state. If the problem persists, report for troubleshooting"
+ },
+ {
+ .code = BGP_ERR_RFSH_RCV,
+ .title = "BGP error receiving route refresh message",
+ .description = "BGP unable to process route refresh message",
+ .suggestion = "BGP route refresh received while in stopped state. If the problem persists, report for troubleshooting"},
+ {
+ .code = BGP_ERR_CAP_RCV,
+ .title = "BGP error capability message",
+ .description = "BGP unable to process received capability",
+ .suggestion = "BGP capability message received while in stopped state. If the problem persists, report for troubleshooting"
+ },
+ {
+ .code = BGP_ERR_NH_UPD,
+ .title = "BGP error with nexthopo update",
+ .description = "BGP unable to process nexthop update",
+ .suggestion = "BGP received nexthop update but nexthop is not reachable in this bgp instance. Report for troubleshooting"
+ },
+ {
+ .code = BGP_ERR_LABEL,
+ .title = "Failure to apply label",
+ .description = "BGP attempted to attempted to apply a label but could not",
+ .suggestion = "Most likely a bug. If the problem persists, report the problem for troubleshooting"
+ },
+ {
+ .code = BGP_ERR_MULTIPATH,
+ .title = "Multipath specified is invalid",
+ .description = "BGP was started with an invalid ecmp/multipath value",
+ .suggestion = "Correct the ecmp/multipath value supplied when starting the BGP daemon"
+ },
+ {
+ .code = BGP_ERR_PKT_PROCESS,
+ .title = "Failure to process a packet",
+ .description = "BGP attempted to process a received packet but could not",
+ .suggestion = "Most likely a bug. If the problem persists, report the problem for troubleshooting"
+ },
+ {
+ .code = BGP_ERR_CONNECT,
+ .title = "Failure to connect to peer",
+ .description = "BGP attempted to send open to peer but couldn't connect",
+ .suggestion = "Most likely a bug. If the problem persists, report the problem for troubleshooting"
+ },
+ {
+ .code = BGP_ERR_FSM,
+ .title = "BGP FSM issue",
+ .description = "BGP neighbor transition problem",
+ .suggestion = "Most likely a bug. If the problem persists, report the problem for troubleshooting"
+ },
+ {
+ .code = BGP_ERR_VNI,
+ .title = "BGP VNI creation issue",
+ .description = "BGP could not create a new VNI",
+ .suggestion = "Most likely a bug. If the problem persists, report the problem for troubleshooting"
+ },
+ {
+ .code = BGP_ERR_NO_DFLT,
+ .title = "BGP default instance missing",
+ .description = "BGP could not find default instance",
+ .suggestion = "Define a default instance of BGP since some feature requires it's existence"
+ },
+ {
+ .code = BGP_ERR_VTEP_INVALID,
+ .title = "BGP remote VTEP invalid",
+ .description = "BGP remote VTEP is invalid and cannot be used",
+ .suggestion = "Correct remote VTEP configuration or resolve the source of the problem"
+ },
+ {
+ .code = BGP_ERR_ES_INVALID,
+ .title = "BGP ES route error",
+ .description = "BGP ES route incorrect, learned both local and remote",
+ .suggestion = "Correct configuration or addressing so that same not learned both local and remote"
+ },
+ {
+ .code = BGP_ERR_EVPN_ROUTE_DELETE,
+ .title = "BGP EVPN route delete error",
+ .description = "BGP attempted to delete an EVPN route and failed",
+ .suggestion = "Most likely a bug. If the problem persists, report the problem for troubleshooting"
+ },
+ {
+ .code = BGP_ERR_EVPN_FAIL,
+ .title = "BGP EVPN install/uninstall error",
+ .description = "BGP attempted to install or uninstall an EVPN prefix and failed",
+ .suggestion = "Most likely a bug. If the problem persists, report the problem for troubleshooting"
+ },
+ {
+ .code = BGP_ERR_EVPN_ROUTE_INVALID,
+ .title = "BGP EVPN route received with invalid contents",
+ .description = "BGP received an EVPN route with invalid contents",
+ .suggestion = "Determine the source of the EVPN route and resolve whatever is causing invalid contents"
+ },
+ {
+ .code = BGP_ERR_EVPN_ROUTE_CREATE,
+ .title = "BGP EVPN route create error",
+ .description = "BGP attempted to create an EVPN route and failed",
+ .suggestion = "Most likely a bug. If the problem persists, report the problem for troubleshooting"
+ },
+ {
+ .code = BGP_ERR_ES_CREATE,
+ .title = "BGP EVPN ES entry create error",
+ .description = "BGP attempted to create an EVPN ES entry and failed",
+ .suggestion = "Most likely a bug. If the problem persists, report the problem for troubleshooting"
+ },
+ {
+ .code = BGP_ERR_MULTI_INSTANCE,
+ .title = "BGP config multi-instance issue",
+ .description = "BGP configuration attempting multiple instances without enabling the feature",
+ .suggestion = "Correct the configuration so that bgp multiple-instance is enabled if desired"
+ },
+ {
+ .code = BGP_ERR_EVPN_AS_MISMATCH,
+ .title = "BGP AS configuration issue",
+ .description = "BGP configuration attempted for a different AS than currently configured",
+ .suggestion = "Correct the configuration so that the correct BGP AS number is used"
+ },
+ {
+ .code = BGP_ERR_EVPN_INSTANCE_MISMATCH,
+ .title = "BGP EVPN AS and process name mismatch",
+ .description = "BGP configuration has AS and process name mismatch",
+ .suggestion = "Correct the configuration so that the BGP AS number and instance name are consistent"
+ },
+ {
+ .code = BGP_ERR_FLOWSPEC_PACKET,
+ .title = "BGP Flowspec packet processing error",
+ .description = "The BGP flowspec subsystem has detected a error in the send or receive of a packet",
+ .suggestion = "Gather log files from both sides of the peering relationship and open an issue"
+ },
+ {
+ .code = BGP_ERR_FLOWSPEC_INSTALLATION,
+ .title = "BGP Flowspec Installation/removal Error",
+ .description = "The BGP flowspec subsystem has detected that there was a failure for installation/removal/modification of Flowspec from the dataplane",
+ .suggestion = "Gather log files from the router and open an issue, Restart FRR"
+ },
+ {
+ .code = END_FERR,
+ }
+};
+/* clang-format on */
+
+void bgp_error_init(void)
+{
+ log_ref_add(ferr_bgp_err);
+}
diff --git a/bgpd/bgp_errors.h b/bgpd/bgp_errors.h
new file mode 100644
index 0000000000..be718d99e7
--- /dev/null
+++ b/bgpd/bgp_errors.h
@@ -0,0 +1,79 @@
+/*
+ * BGP-specific error messages.
+ * Copyright (C) 2018 Cumulus Networks, Inc.
+ * Don Slice
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; see the file COPYING; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef __BGP_ERRORS_H__
+#define __BGP_ERRORS_H__
+
+#include "lib/ferr.h"
+
+enum bgp_log_refs {
+
+ BGP_ERR_ATTR_FLAG = BGP_FERR_START,
+ BGP_ERR_ATTR_LEN,
+ BGP_ERR_ATTR_ORIGIN,
+ BGP_ERR_ATTR_MAL_AS_PATH,
+ BGP_ERR_ATTR_FIRST_AS,
+ BGP_ERR_ATTR_MARTIAN_NH,
+ BGP_ERR_ATTR_PMSI_TYPE,
+ BGP_ERR_ATTR_PMSI_LEN,
+ BGP_ERR_ATTR_NH_SEND_LEN,
+ BGP_ERR_PEER_GROUP,
+ BGP_ERR_PEER_DELETE,
+ BGP_ERR_TABLE_CHUNK,
+ BGP_ERR_MACIP_LEN,
+ BGP_ERR_LM_ERROR,
+ BGP_ERR_JSON_MEM_ERROR,
+ BGP_ERR_UPDGRP_ATTR_LEN,
+ BGP_ERR_UPDGRP_CREATE,
+ BGP_ERR_UPDATE_SND,
+ BGP_ERR_PKT_OPEN,
+ BGP_ERR_SND_FAIL,
+ BGP_ERR_INVALID_STATUS,
+ BGP_ERR_UPDATE_RCV,
+ BGP_ERR_NO_CAP,
+ BGP_ERR_NOTIFY_RCV,
+ BGP_ERR_KEEP_RCV,
+ BGP_ERR_RFSH_RCV,
+ BGP_ERR_CAP_RCV,
+ BGP_ERR_NH_UPD,
+ BGP_ERR_LABEL,
+ BGP_ERR_MULTIPATH,
+ BGP_ERR_PKT_PROCESS,
+ BGP_ERR_CONNECT,
+ BGP_ERR_FSM,
+ BGP_ERR_VNI,
+ BGP_ERR_NO_DFLT,
+ BGP_ERR_VTEP_INVALID,
+ BGP_ERR_ES_INVALID,
+ BGP_ERR_EVPN_ROUTE_DELETE,
+ BGP_ERR_EVPN_FAIL,
+ BGP_ERR_EVPN_ROUTE_INVALID,
+ BGP_ERR_EVPN_ROUTE_CREATE,
+ BGP_ERR_ES_CREATE,
+ BGP_ERR_MULTI_INSTANCE,
+ BGP_ERR_EVPN_AS_MISMATCH,
+ BGP_ERR_EVPN_INSTANCE_MISMATCH,
+ BGP_ERR_FLOWSPEC_PACKET,
+ BGP_ERR_FLOWSPEC_INSTALLATION,
+};
+
+extern void bgp_error_init(void);
+
+#endif
diff --git a/bgpd/bgp_evpn.c b/bgpd/bgp_evpn.c
index 73f225784c..b190e0923f 100644
--- a/bgpd/bgp_evpn.c
+++ b/bgpd/bgp_evpn.c
@@ -43,6 +43,7 @@
#include "bgpd/bgp_ecommunity.h"
#include "bgpd/bgp_encap_types.h"
#include "bgpd/bgp_debug.h"
+#include "bgpd/bgp_errors.h"
#include "bgpd/bgp_aspath.h"
#include "bgpd/bgp_zebra.h"
#include "bgpd/bgp_nexthop.h"
@@ -172,7 +173,8 @@ static struct vrf_irt_node *vrf_import_rt_new(struct ecommunity_val *rt)
bgp_def = bgp_get_default();
if (!bgp_def) {
- zlog_err("vrf import rt new - def instance not created yet");
+ flog_err(BGP_ERR_NO_DFLT,
+ "vrf import rt new - def instance not created yet");
return NULL;
}
@@ -202,7 +204,8 @@ static void vrf_import_rt_free(struct vrf_irt_node *irt)
bgp_def = bgp_get_default();
if (!bgp_def) {
- zlog_err("vrf import rt free - def instance not created yet");
+ flog_err(BGP_ERR_NO_DFLT,
+ "vrf import rt free - def instance not created yet");
return;
}
@@ -223,7 +226,9 @@ static struct vrf_irt_node *lookup_vrf_import_rt(struct ecommunity_val *rt)
bgp_def = bgp_get_default();
if (!bgp_def) {
- zlog_err("vrf import rt lookup - def instance not created yet");
+ flog_err(
+ BGP_ERR_NO_DFLT,
+ "vrf import rt lookup - def instance not created yet");
return NULL;
}
@@ -619,7 +624,8 @@ static int bgp_zebra_send_remote_vtep(struct bgp *bgp, struct bgpevpn *vpn,
if (is_evpn_prefix_ipaddr_v4(p))
stream_put_in_addr(s, &p->prefix.imet_addr.ip.ipaddr_v4);
else if (is_evpn_prefix_ipaddr_v6(p)) {
- zlog_err(
+ flog_err(
+ BGP_ERR_VTEP_INVALID,
"Bad remote IP when trying to %s remote VTEP for VNI %u",
add ? "ADD" : "DEL", vpn->vni);
return -1;
@@ -1289,11 +1295,12 @@ static int update_evpn_type4_route_entry(struct bgp *bgp,
* We shouldn't see the same route from any other vtep.
*/
if (remote_ri) {
- zlog_err(
- "%u ERROR: local es route for ESI: %s Vtep %s also learnt from remote",
- bgp->vrf_id,
- esi_to_str(&evp->prefix.es_addr.esi, buf, sizeof(buf)),
- ipaddr2str(&es->originator_ip, buf1, sizeof(buf1)));
+ flog_err(
+ BGP_ERR_ES_INVALID,
+ "%u ERROR: local es route for ESI: %s Vtep %s also learnt from remote",
+ bgp->vrf_id,
+ esi_to_str(&evp->prefix.es_addr.esi, buf, sizeof(buf)),
+ ipaddr2str(&es->originator_ip, buf1, sizeof(buf1)));
return -1;
}
@@ -1376,10 +1383,12 @@ static int update_evpn_type4_route(struct bgp *bgp,
&attr, 1, &ri,
&route_changed);
if (ret != 0) {
- zlog_err("%u ERROR: Failed to updated ES route ESI: %s VTEP %s",
- bgp->vrf_id,
- esi_to_str(&p->prefix.es_addr.esi, buf, sizeof(buf)),
- ipaddr2str(&es->originator_ip, buf1, sizeof(buf1)));
+ flog_err(
+ BGP_ERR_ES_INVALID,
+ "%u ERROR: Failed to updated ES route ESI: %s VTEP %s",
+ bgp->vrf_id,
+ esi_to_str(&p->prefix.es_addr.esi, buf, sizeof(buf)),
+ ipaddr2str(&es->originator_ip, buf1, sizeof(buf1)));
}
assert(ri);
@@ -2216,10 +2225,9 @@ static int delete_routes_for_es(struct bgp *bgp, struct evpnes *es)
build_evpn_type4_prefix(&p, &es->esi, es->originator_ip.ipaddr_v4);
ret = delete_evpn_type4_route(bgp, es, &p);
if (ret) {
- zlog_err(
- "%u failed to delete type-4 route for ESI %s",
- bgp->vrf_id,
- esi_to_str(&es->esi, buf, sizeof(buf)));
+ flog_err(BGP_ERR_EVPN_ROUTE_DELETE,
+ "%u failed to delete type-4 route for ESI %s",
+ bgp->vrf_id, esi_to_str(&es->esi, buf, sizeof(buf)));
}
/* Delete all routes from per ES table */
@@ -2876,7 +2884,8 @@ static int install_uninstall_routes_for_es(struct bgp *bgp,
bgp, es, evp, ri);
if (ret) {
- zlog_err(
+ flog_err(
+ BGP_ERR_EVPN_FAIL,
"Failed to %s EVPN %s route in ESI %s",
install ? "install"
: "uninstall",
@@ -2955,7 +2964,8 @@ static int install_uninstall_routes_for_vrf(struct bgp *bgp_vrf, int install)
bgp_vrf, evp, ri);
if (ret) {
- zlog_err(
+ flog_err(
+ BGP_ERR_EVPN_FAIL,
"Failed to %s EVPN %s route in VRF %s",
install ? "install"
: "uninstall",
@@ -3028,7 +3038,8 @@ static int install_uninstall_routes_for_vni(struct bgp *bgp,
bgp, vpn, evp, ri);
if (ret) {
- zlog_err(
+ flog_err(
+ BGP_ERR_EVPN_FAIL,
"%u: Failed to %s EVPN %s route in VNI %u",
bgp->vrf_id,
install ? "install"
@@ -3130,11 +3141,11 @@ static int install_uninstall_route_in_es(struct bgp *bgp, struct evpnes *es,
ret = uninstall_evpn_route_entry_in_es(bgp, es, evp, ri);
if (ret) {
- zlog_err("%u: Failed to %s EVPN %s route in ESI %s",
- bgp->vrf_id, install ? "install" : "uninstall",
- "ES",
- esi_to_str(&evp->prefix.es_addr.esi, buf,
- sizeof(buf)));
+ flog_err(
+ BGP_ERR_EVPN_FAIL,
+ "%u: Failed to %s EVPN %s route in ESI %s", bgp->vrf_id,
+ install ? "install" : "uninstall", "ES",
+ esi_to_str(&evp->prefix.es_addr.esi, buf, sizeof(buf)));
return ret;
}
return 0;
@@ -3173,11 +3184,12 @@ static int install_uninstall_route_in_vrfs(struct bgp *bgp_def, afi_t afi,
ri);
if (ret) {
- zlog_err("%u: Failed to %s prefix %s in VRF %s",
- bgp_def->vrf_id,
- install ? "install" : "uninstall",
- prefix2str(evp, buf, sizeof(buf)),
- vrf_id_to_name(bgp_vrf->vrf_id));
+ flog_err(BGP_ERR_EVPN_FAIL,
+ "%u: Failed to %s prefix %s in VRF %s",
+ bgp_def->vrf_id,
+ install ? "install" : "uninstall",
+ prefix2str(evp, buf, sizeof(buf)),
+ vrf_id_to_name(bgp_vrf->vrf_id));
return ret;
}
}
@@ -3208,12 +3220,14 @@ static int install_uninstall_route_in_vnis(struct bgp *bgp, afi_t afi,
ret = uninstall_evpn_route_entry(bgp, vpn, evp, ri);
if (ret) {
- zlog_err("%u: Failed to %s EVPN %s route in VNI %u",
- bgp->vrf_id, install ? "install" : "uninstall",
- evp->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE
- ? "MACIP"
- : "IMET",
- vpn->vni);
+ flog_err(
+ BGP_ERR_EVPN_FAIL,
+ "%u: Failed to %s EVPN %s route in VNI %u",
+ bgp->vrf_id, install ? "install" : "uninstall",
+ evp->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE
+ ? "MACIP"
+ : "IMET",
+ vpn->vni);
return ret;
}
}
@@ -3592,8 +3606,9 @@ static int process_type2_route(struct peer *peer, afi_t afi, safi_t safi,
*/
if (psize != 33 && psize != 37 && psize != 49 && psize != 36
&& psize != 40 && psize != 52) {
- zlog_err("%u:%s - Rx EVPN Type-2 NLRI with invalid length %d",
- peer->bgp->vrf_id, peer->host, psize);
+ flog_err(BGP_ERR_EVPN_ROUTE_INVALID,
+ "%u:%s - Rx EVPN Type-2 NLRI with invalid length %d",
+ peer->bgp->vrf_id, peer->host, psize);
return -1;
}
@@ -3628,7 +3643,8 @@ static int process_type2_route(struct peer *peer, afi_t afi, safi_t safi,
memcpy(&p.prefix.macip_addr.mac.octet, pfx, ETH_ALEN);
pfx += ETH_ALEN;
} else {
- zlog_err(
+ flog_err(
+ BGP_ERR_EVPN_ROUTE_INVALID,
"%u:%s - Rx EVPN Type-2 NLRI with unsupported MAC address length %d",
peer->bgp->vrf_id, peer->host, macaddr_len);
return -1;
@@ -3639,7 +3655,8 @@ static int process_type2_route(struct peer *peer, afi_t afi, safi_t safi,
ipaddr_len = *pfx++;
if (ipaddr_len != 0 && ipaddr_len != IPV4_MAX_BITLEN
&& ipaddr_len != IPV6_MAX_BITLEN) {
- zlog_err(
+ flog_err(
+ BGP_ERR_EVPN_ROUTE_INVALID,
"%u:%s - Rx EVPN Type-2 NLRI with unsupported IP address length %d",
peer->bgp->vrf_id, peer->host, ipaddr_len);
return -1;
@@ -3700,8 +3717,9 @@ static int process_type3_route(struct peer *peer, afi_t afi, safi_t safi,
* IP len (1) and IP (4 or 16).
*/
if (psize != 17 && psize != 29) {
- zlog_err("%u:%s - Rx EVPN Type-3 NLRI with invalid length %d",
- peer->bgp->vrf_id, peer->host, psize);
+ flog_err(BGP_ERR_EVPN_ROUTE_INVALID,
+ "%u:%s - Rx EVPN Type-3 NLRI with invalid length %d",
+ peer->bgp->vrf_id, peer->host, psize);
return -1;
}
@@ -3741,7 +3759,8 @@ static int process_type3_route(struct peer *peer, afi_t afi, safi_t safi,
p.prefix.imet_addr.ip.ipa_type = IPADDR_V4;
memcpy(&p.prefix.imet_addr.ip.ip.addr, pfx, IPV4_MAX_BYTELEN);
} else {
- zlog_err(
+ flog_err(
+ BGP_ERR_EVPN_ROUTE_INVALID,
"%u:%s - Rx EVPN Type-3 NLRI with unsupported IP address length %d",
peer->bgp->vrf_id, peer->host, ipaddr_len);
return -1;
@@ -3777,8 +3796,9 @@ static int process_type4_route(struct peer *peer, afi_t afi, safi_t safi,
* RD (8), ESI (10), ip-len (1), ip (4 or 16)
*/
if (psize != 23 && psize != 35) {
- zlog_err("%u:%s - Rx EVPN Type-4 NLRI with invalid length %d",
- peer->bgp->vrf_id, peer->host, psize);
+ flog_err(BGP_ERR_EVPN_ROUTE_INVALID,
+ "%u:%s - Rx EVPN Type-4 NLRI with invalid length %d",
+ peer->bgp->vrf_id, peer->host, psize);
return -1;
}
@@ -3798,7 +3818,8 @@ static int process_type4_route(struct peer *peer, afi_t afi, safi_t safi,
if (ipaddr_len == IPV4_MAX_BITLEN) {
memcpy(&vtep_ip, pfx, IPV4_MAX_BYTELEN);
} else {
- zlog_err(
+ flog_err(
+ BGP_ERR_EVPN_ROUTE_INVALID,
"%u:%s - Rx EVPN Type-4 NLRI with unsupported IP address length %d",
peer->bgp->vrf_id, peer->host, ipaddr_len);
return -1;
@@ -3840,8 +3861,9 @@ static int process_type5_route(struct peer *peer, afi_t afi, safi_t safi,
* Note that the IP and GW should both be IPv4 or both IPv6.
*/
if (psize != 34 && psize != 58) {
- zlog_err("%u:%s - Rx EVPN Type-5 NLRI with invalid length %d",
- peer->bgp->vrf_id, peer->host, psize);
+ flog_err(BGP_ERR_EVPN_ROUTE_INVALID,
+ "%u:%s - Rx EVPN Type-5 NLRI with invalid length %d",
+ peer->bgp->vrf_id, peer->host, psize);
return -1;
}
@@ -3872,7 +3894,8 @@ static int process_type5_route(struct peer *peer, afi_t afi, safi_t safi,
/* Fetch IP prefix length. */
ippfx_len = *pfx++;
if (ippfx_len > IPV6_MAX_BITLEN) {
- zlog_err(
+ flog_err(
+ BGP_ERR_EVPN_ROUTE_INVALID,
"%u:%s - Rx EVPN Type-5 NLRI with invalid IP Prefix length %d",
peer->bgp->vrf_id, peer->host, ippfx_len);
return -1;
@@ -4104,7 +4127,8 @@ void bgp_evpn_withdraw_type5_route(struct bgp *bgp_vrf, struct prefix *p,
build_type5_prefix_from_ip_prefix(&evp, p);
ret = delete_evpn_type5_route(bgp_vrf, &evp);
if (ret) {
- zlog_err(
+ flog_err(
+ BGP_ERR_EVPN_ROUTE_DELETE,
"%u failed to delete type-5 route for prefix %s in vrf %s",
bgp_vrf->vrf_id, prefix2str(p, buf, sizeof(buf)),
vrf_id_to_name(bgp_vrf->vrf_id));
@@ -4150,8 +4174,9 @@ void bgp_evpn_advertise_type5_route(struct bgp *bgp_vrf, struct prefix *p,
build_type5_prefix_from_ip_prefix(&evp, p);
ret = update_evpn_type5_route(bgp_vrf, &evp, src_attr);
if (ret)
- zlog_err("%u: Failed to create type-5 route for prefix %s",
- bgp_vrf->vrf_id, prefix2str(p, buf, sizeof(buf)));
+ flog_err(BGP_ERR_EVPN_ROUTE_CREATE,
+ "%u: Failed to create type-5 route for prefix %s",
+ bgp_vrf->vrf_id, prefix2str(p, buf, sizeof(buf)));
}
/* Inject all prefixes of a particular address-family (currently, IPv4 or
@@ -4709,7 +4734,8 @@ int bgp_nlri_parse_evpn(struct peer *peer, struct attr *attr,
if (process_type2_route(peer, afi, safi,
withdraw ? NULL : attr, pnt,
psize, addpath_id)) {
- zlog_err(
+ flog_err(
+ BGP_ERR_EVPN_FAIL,
"%u:%s - Error in processing EVPN type-2 NLRI size %d",
peer->bgp->vrf_id, peer->host, psize);
return -1;
@@ -4720,7 +4746,8 @@ int bgp_nlri_parse_evpn(struct peer *peer, struct attr *attr,
if (process_type3_route(peer, afi, safi,
withdraw ? NULL : attr, pnt,
psize, addpath_id)) {
- zlog_err(
+ flog_err(
+ BGP_ERR_PKT_PROCESS,
"%u:%s - Error in processing EVPN type-3 NLRI size %d",
peer->bgp->vrf_id, peer->host, psize);
return -1;
@@ -4731,7 +4758,8 @@ int bgp_nlri_parse_evpn(struct peer *peer, struct attr *attr,
if (process_type4_route(peer, afi, safi,
withdraw ? NULL : attr, pnt,
psize, addpath_id)) {
- zlog_err(
+ flog_err(
+ BGP_ERR_PKT_PROCESS,
"%u:%s - Error in processing EVPN type-4 NLRI size %d",
peer->bgp->vrf_id, peer->host, psize);
return -1;
@@ -4741,7 +4769,8 @@ int bgp_nlri_parse_evpn(struct peer *peer, struct attr *attr,
case BGP_EVPN_IP_PREFIX_ROUTE:
if (process_type5_route(peer, afi, safi, attr, pnt,
psize, addpath_id, withdraw)) {
- zlog_err(
+ flog_err(
+ BGP_ERR_PKT_PROCESS,
"%u:%s - Error in processing EVPN type-5 NLRI size %d",
peer->bgp->vrf_id, peer->host, psize);
return -1;
@@ -5204,7 +5233,8 @@ int bgp_evpn_local_macip_add(struct bgp *bgp, vni_t vni, struct ethaddr *mac,
char buf[ETHER_ADDR_STRLEN];
char buf2[INET6_ADDRSTRLEN];
- zlog_err(
+ flog_err(
+ BGP_ERR_EVPN_ROUTE_CREATE,
"%u:Failed to create Type-2 route, VNI %u %s MAC %s IP %s (flags: 0x%x)",
bgp->vrf_id, vpn->vni,
CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_STICKY)
@@ -5246,7 +5276,8 @@ int bgp_evpn_local_l3vni_add(vni_t l3vni, vrf_id_t vrf_id, struct ethaddr *rmac,
*/
bgp_def = bgp_get_default();
if (!bgp_def) {
- zlog_err(
+ flog_err(
+ BGP_ERR_NO_DFLT,
"Cannot process L3VNI %u ADD - default BGP instance not yet created",
l3vni);
return -1;
@@ -5263,13 +5294,16 @@ int bgp_evpn_local_l3vni_add(vni_t l3vni, vrf_id_t vrf_id, struct ethaddr *rmac,
BGP_INSTANCE_TYPE_VRF);
switch (ret) {
case BGP_ERR_MULTIPLE_INSTANCE_NOT_SET:
- zlog_err("'bgp multiple-instance' not present\n");
+ flog_err(BGP_ERR_MULTI_INSTANCE,
+ "'bgp multiple-instance' not present\n");
return -1;
case BGP_ERR_AS_MISMATCH:
- zlog_err("BGP is already running; AS is %u\n", as);
+ flog_err(BGP_ERR_EVPN_AS_MISMATCH,
+ "BGP is already running; AS is %u\n", as);
return -1;
case BGP_ERR_INSTANCE_MISMATCH:
- zlog_err("BGP instance name and AS number mismatch\n");
+ flog_err(BGP_ERR_EVPN_INSTANCE_MISMATCH,
+ "BGP instance name and AS number mismatch\n");
return -1;
}
@@ -5330,7 +5364,8 @@ int bgp_evpn_local_l3vni_del(vni_t l3vni, vrf_id_t vrf_id)
bgp_vrf = bgp_lookup_by_vrf_id(vrf_id);
if (!bgp_vrf) {
- zlog_err(
+ flog_err(
+ BGP_ERR_NO_DFLT,
"Cannot process L3VNI %u Del - Could not find BGP instance",
l3vni);
return -1;
@@ -5338,7 +5373,8 @@ int bgp_evpn_local_l3vni_del(vni_t l3vni, vrf_id_t vrf_id)
bgp_def = bgp_get_default();
if (!bgp_def) {
- zlog_err(
+ flog_err(
+ BGP_ERR_NO_DFLT,
"Cannot process L3VNI %u Del - Could not find default BGP instance",
l3vni);
return -1;
@@ -5468,7 +5504,8 @@ int bgp_evpn_local_vni_add(struct bgp *bgp, vni_t vni,
if (!vpn) {
vpn = bgp_evpn_new(bgp, vni, originator_ip, tenant_vrf_id);
if (!vpn) {
- zlog_err(
+ flog_err(
+ BGP_ERR_VNI,
"%u: Failed to allocate VNI entry for VNI %u - at Add",
bgp->vrf_id, vni);
return -1;
@@ -5491,8 +5528,9 @@ int bgp_evpn_local_vni_add(struct bgp *bgp, vni_t vni,
/* Create EVPN type-3 route and schedule for processing. */
build_evpn_type3_prefix(&p, vpn->originator_ip);
if (update_evpn_route(bgp, vpn, &p, 0)) {
- zlog_err("%u: Type3 route creation failure for VNI %u",
- bgp->vrf_id, vni);
+ flog_err(BGP_ERR_EVPN_ROUTE_CREATE,
+ "%u: Type3 route creation failure for VNI %u",
+ bgp->vrf_id, vni);
return -1;
}
@@ -5520,7 +5558,8 @@ int bgp_evpn_local_es_del(struct bgp *bgp,
struct evpnes *es = NULL;
if (!bgp->esihash) {
- zlog_err("%u: ESI hash not yet created", bgp->vrf_id);
+ flog_err(BGP_ERR_ES_CREATE, "%u: ESI hash not yet created",
+ bgp->vrf_id);
return -1;
}
@@ -5556,7 +5595,8 @@ int bgp_evpn_local_es_add(struct bgp *bgp,
struct prefix_evpn p;
if (!bgp->esihash) {
- zlog_err("%u: ESI hash not yet created", bgp->vrf_id);
+ flog_err(BGP_ERR_ES_CREATE, "%u: ESI hash not yet created",
+ bgp->vrf_id);
return -1;
}
@@ -5565,7 +5605,8 @@ int bgp_evpn_local_es_add(struct bgp *bgp,
if (!es) {
es = bgp_evpn_es_new(bgp, esi, originator_ip);
if (!es) {
- zlog_err(
+ flog_err(
+ BGP_ERR_ES_CREATE,
"%u: Failed to allocate ES entry for ESI %s - at Local ES Add",
bgp->vrf_id, esi_to_str(esi, buf, sizeof(buf)));
return -1;
@@ -5576,8 +5617,9 @@ int bgp_evpn_local_es_add(struct bgp *bgp,
build_evpn_type4_prefix(&p, esi, originator_ip->ipaddr_v4);
if (update_evpn_type4_route(bgp, es, &p)) {
- zlog_err("%u: Type4 route creation failure for ESI %s",
- bgp->vrf_id, esi_to_str(esi, buf, sizeof(buf)));
+ flog_err(BGP_ERR_EVPN_ROUTE_CREATE,
+ "%u: Type4 route creation failure for ESI %s",
+ bgp->vrf_id, esi_to_str(esi, buf, sizeof(buf)));
return -1;
}
diff --git a/bgpd/bgp_evpn_vty.c b/bgpd/bgp_evpn_vty.c
index b45c1a99db..3828ce216b 100644
--- a/bgpd/bgp_evpn_vty.c
+++ b/bgpd/bgp_evpn_vty.c
@@ -35,6 +35,7 @@
#include "bgpd/bgp_evpn_private.h"
#include "bgpd/bgp_zebra.h"
#include "bgpd/bgp_vty.h"
+#include "bgpd/bgp_errors.h"
#include "bgpd/bgp_ecommunity.h"
#define SHOW_DISPLAY_STANDARD 0
@@ -1892,7 +1893,8 @@ static struct bgpevpn *evpn_create_update_vni(struct bgp *bgp, vni_t vni)
*/
vpn = bgp_evpn_new(bgp, vni, bgp->router_id, 0);
if (!vpn) {
- zlog_err(
+ flog_err(
+ BGP_ERR_VNI,
"%u: Failed to allocate VNI entry for VNI %u - at Config",
bgp->vrf_id, vni);
return NULL;
diff --git a/bgpd/bgp_flowspec.c b/bgpd/bgp_flowspec.c
index 2d336fa6d8..6695596c6f 100644
--- a/bgpd/bgp_flowspec.c
+++ b/bgpd/bgp_flowspec.c
@@ -22,6 +22,7 @@
#include <zebra.h>
#include "prefix.h"
+#include "lib_errors.h"
#include "bgpd/bgpd.h"
#include "bgpd/bgp_route.h"
@@ -30,6 +31,7 @@
#include "bgpd/bgp_flowspec_private.h"
#include "bgpd/bgp_ecommunity.h"
#include "bgpd/bgp_debug.h"
+#include "bgpd/bgp_errors.h"
static int bgp_fs_nlri_validate(uint8_t *nlri_content, uint32_t len)
{
@@ -102,13 +104,15 @@ int bgp_nlri_parse_flowspec(struct peer *peer, struct attr *attr,
safi = packet->safi;
if (afi == AFI_IP6) {
- zlog_err("BGP flowspec IPv6 not supported");
+ flog_err(LIB_ERR_DEVELOPMENT,
+ "BGP flowspec IPv6 not supported");
return -1;
}
if (packet->length >= FLOWSPEC_NLRI_SIZELIMIT) {
- zlog_err("BGP flowspec nlri length maximum reached (%u)",
- packet->length);
+ flog_err(BGP_ERR_FLOWSPEC_PACKET,
+ "BGP flowspec nlri length maximum reached (%u)",
+ packet->length);
return -1;
}
@@ -124,12 +128,14 @@ int bgp_nlri_parse_flowspec(struct peer *peer, struct attr *attr,
/* When packet overflow occur return immediately. */
if (pnt + psize > lim) {
- zlog_err("Flowspec NLRI length inconsistent ( size %u seen)",
- psize);
+ flog_err(BGP_ERR_FLOWSPEC_PACKET,
+ "Flowspec NLRI length inconsistent ( size %u seen)",
+ psize);
return -1;
}
if (bgp_fs_nlri_validate(pnt, psize) < 0) {
- zlog_err("Bad flowspec format or NLRI options not supported");
+ flog_err(BGP_ERR_FLOWSPEC_PACKET,
+ "Bad flowspec format or NLRI options not supported");
return -1;
}
p.family = AF_FLOWSPEC;
@@ -182,8 +188,9 @@ int bgp_nlri_parse_flowspec(struct peer *peer, struct attr *attr,
ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL,
NULL, NULL, 0, NULL);
if (ret) {
- zlog_err("Flowspec NLRI failed to be %s.",
- attr ? "added" : "withdrawn");
+ flog_err(BGP_ERR_FLOWSPEC_INSTALLATION,
+ "Flowspec NLRI failed to be %s.",
+ attr ? "added" : "withdrawn");
return -1;
}
}
diff --git a/bgpd/bgp_flowspec_util.c b/bgpd/bgp_flowspec_util.c
index 6408337a5f..9f92a3c3a6 100644
--- a/bgpd/bgp_flowspec_util.c
+++ b/bgpd/bgp_flowspec_util.c
@@ -21,11 +21,13 @@
#include "zebra.h"
#include "prefix.h"
+#include "lib_errors.h"
#include "bgp_table.h"
#include "bgp_flowspec_util.h"
#include "bgp_flowspec_private.h"
#include "bgp_pbr.h"
+#include "bgp_errors.h"
static void hex2bin(uint8_t *hex, int *bin)
{
@@ -66,8 +68,9 @@ static int bgp_flowspec_call_non_opaque_decode(uint8_t *nlri_content, int len,
len,
mval, error);
if (*error < 0)
- zlog_err("%s: flowspec_op_decode error %d",
- __func__, *error);
+ flog_err(BGP_ERR_FLOWSPEC_PACKET,
+ "%s: flowspec_op_decode error %d",
+ __func__, *error);
else
*match_num = *error;
return ret;
@@ -444,8 +447,9 @@ int bgp_flowspec_match_rules_fill(uint8_t *nlri_content, int len,
len - offset,
prefix, &error);
if (error < 0)
- zlog_err("%s: flowspec_ip_address error %d",
- __func__, error);
+ flog_err(BGP_ERR_FLOWSPEC_PACKET,
+ "%s: flowspec_ip_address error %d",
+ __func__, error);
else
bpem->match_bitmask |= bitmask;
offset += ret;
@@ -538,8 +542,9 @@ int bgp_flowspec_match_rules_fill(uint8_t *nlri_content, int len,
len - offset,
&bpem->tcpflags, &error);
if (error < 0)
- zlog_err("%s: flowspec_tcpflags_decode error %d",
- __func__, error);
+ flog_err(BGP_ERR_FLOWSPEC_PACKET,
+ "%s: flowspec_tcpflags_decode error %d",
+ __func__, error);
else
bpem->match_tcpflags_num = error;
/* contains the number of slots used */
@@ -552,14 +557,16 @@ int bgp_flowspec_match_rules_fill(uint8_t *nlri_content, int len,
len - offset, &bpem->fragment,
&error);
if (error < 0)
- zlog_err("%s: flowspec_fragment_type_decode error %d",
- __func__, error);
+ flog_err(BGP_ERR_FLOWSPEC_PACKET,
+ "%s: flowspec_fragment_type_decode error %d",
+ __func__, error);
else
bpem->match_fragment_num = error;
offset += ret;
break;
default:
- zlog_err("%s: unknown type %d\n", __func__, type);
+ flog_err(LIB_ERR_DEVELOPMENT, "%s: unknown type %d\n",
+ __func__, type);
}
}
return error;
diff --git a/bgpd/bgp_fsm.c b/bgpd/bgp_fsm.c
index 2fd63531db..14d692ebf0 100644
--- a/bgpd/bgp_fsm.c
+++ b/bgpd/bgp_fsm.c
@@ -34,11 +34,13 @@
#include "queue.h"
#include "filter.h"
#include "command.h"
+#include "lib_errors.h"
#include "lib/json.h"
#include "bgpd/bgpd.h"
#include "bgpd/bgp_attr.h"
#include "bgpd/bgp_debug.h"
+#include "bgpd/bgp_errors.h"
#include "bgpd/bgp_fsm.h"
#include "bgpd/bgp_packet.h"
#include "bgpd/bgp_network.h"
@@ -164,7 +166,8 @@ static struct peer *peer_xfer_conn(struct peer *from_peer)
* runs in our pthread.
*/
if (peer->curr) {
- zlog_err(
+ flog_err(
+ BGP_ERR_PKT_PROCESS,
"[%s] Dropping pending packet on connection transfer:",
peer->host);
uint16_t type = stream_getc_from(peer->curr,
@@ -242,7 +245,8 @@ static struct peer *peer_xfer_conn(struct peer *from_peer)
}
if (bgp_getsockname(peer) < 0) {
- zlog_err(
+ flog_err(
+ LIB_ERR_SOCKET,
"%%bgp_getsockname() failed for %s peer %s fd %d (from_peer fd %d)",
(CHECK_FLAG(peer->sflags, PEER_STATUS_ACCEPT_PEER)
? "accept"
@@ -254,8 +258,10 @@ static struct peer *peer_xfer_conn(struct peer *from_peer)
}
if (from_peer->status > Active) {
if (bgp_getsockname(from_peer) < 0) {
- zlog_err(
+ flog_err(
+ LIB_ERR_SOCKET,
"%%bgp_getsockname() failed for %s from_peer %s fd %d (peer fd %d)",
+
(CHECK_FLAG(from_peer->sflags,
PEER_STATUS_ACCEPT_PEER)
? "accept"
@@ -1280,15 +1286,17 @@ static int bgp_connect_check(struct thread *thread)
static int bgp_connect_success(struct peer *peer)
{
if (peer->fd < 0) {
- zlog_err("bgp_connect_success peer's fd is negative value %d",
- peer->fd);
+ flog_err(BGP_ERR_CONNECT,
+ "bgp_connect_success peer's fd is negative value %d",
+ peer->fd);
bgp_stop(peer);
return -1;
}
if (bgp_getsockname(peer) < 0) {
- zlog_err("%s: bgp_getsockname(): failed for peer %s, fd %d",
- __FUNCTION__, peer->host, peer->fd);
+ flog_err_sys(LIB_ERR_SOCKET,
+ "%s: bgp_getsockname(): failed for peer %s, fd %d",
+ __FUNCTION__, peer->host, peer->fd);
bgp_notify_send(peer, BGP_NOTIFY_FSM_ERR,
0); /* internal error */
bgp_writes_on(peer);
@@ -1346,10 +1354,10 @@ int bgp_start(struct peer *peer)
if (BGP_PEER_START_SUPPRESSED(peer)) {
if (bgp_debug_neighbor_events(peer))
- zlog_err(
- "%s [FSM] Trying to start suppressed peer"
- " - this is never supposed to happen!",
- peer->host);
+ flog_err(BGP_ERR_FSM,
+ "%s [FSM] Trying to start suppressed peer"
+ " - this is never supposed to happen!",
+ peer->host);
return -1;
}
@@ -1381,7 +1389,8 @@ int bgp_start(struct peer *peer)
if (peer->bgp->vrf_id == VRF_UNKNOWN) {
if (bgp_debug_neighbor_events(peer))
- zlog_err(
+ flog_err(
+ BGP_ERR_FSM,
"%s [FSM] In a VRF that is not initialised yet",
peer->host);
return -1;
@@ -1435,8 +1444,9 @@ int bgp_start(struct peer *peer)
"%s [FSM] Non blocking connect waiting result, fd %d",
peer->host, peer->fd);
if (peer->fd < 0) {
- zlog_err("bgp_start peer's fd is negative value %d",
- peer->fd);
+ flog_err(BGP_ERR_FSM,
+ "bgp_start peer's fd is negative value %d",
+ peer->fd);
return -1;
}
/*
@@ -1482,8 +1492,9 @@ static int bgp_fsm_open(struct peer *peer)
peer and change to Idle status. */
static int bgp_fsm_event_error(struct peer *peer)
{
- zlog_err("%s [FSM] unexpected packet received in state %s", peer->host,
- lookup_msg(bgp_status_msg, peer->status, NULL));
+ flog_err(BGP_ERR_FSM,
+ "%s [FSM] unexpected packet received in state %s", peer->host,
+ lookup_msg(bgp_status_msg, peer->status, NULL));
return bgp_stop_with_notify(peer, BGP_NOTIFY_FSM_ERR, 0);
}
@@ -1515,7 +1526,7 @@ static int bgp_establish(struct peer *peer)
other = peer->doppelganger;
peer = peer_xfer_conn(peer);
if (!peer) {
- zlog_err("%%Neighbor failed in xfer_conn");
+ flog_err(BGP_ERR_CONNECT, "%%Neighbor failed in xfer_conn");
return -1;
}
@@ -1674,7 +1685,8 @@ static int bgp_fsm_update(struct peer *peer)
/* This is empty event. */
static int bgp_ignore(struct peer *peer)
{
- zlog_err(
+ flog_err(
+ BGP_ERR_FSM,
"%s [FSM] Ignoring event %s in state %s, prior events %s, %s, fd %d",
peer->host, bgp_event_str[peer->cur_event],
lookup_msg(bgp_status_msg, peer->status, NULL),
@@ -1686,7 +1698,8 @@ static int bgp_ignore(struct peer *peer)
/* This is to handle unexpected events.. */
static int bgp_fsm_exeption(struct peer *peer)
{
- zlog_err(
+ flog_err(
+ BGP_ERR_FSM,
"%s [FSM] Unexpected event %s in state %s, prior events %s, %s, fd %d",
peer->host, bgp_event_str[peer->cur_event],
lookup_msg(bgp_status_msg, peer->status, NULL),
@@ -1960,7 +1973,8 @@ int bgp_event_update(struct peer *peer, int event)
* code.
*/
if (!dyn_nbr && !passive_conn && peer->bgp) {
- zlog_err(
+ flog_err(
+ BGP_ERR_FSM,
"%s [FSM] Failure handling event %s in state %s, "
"prior events %s, %s, fd %d",
peer->host, bgp_event_str[peer->cur_event],
diff --git a/bgpd/bgp_io.c b/bgpd/bgp_io.c
index c8d5b1daa1..311f98001d 100644
--- a/bgpd/bgp_io.c
+++ b/bgpd/bgp_io.c
@@ -35,6 +35,7 @@
#include "bgpd/bgp_io.h"
#include "bgpd/bgp_debug.h" // for bgp_debug_neighbor_events, bgp_type_str
+#include "bgpd/bgp_errors.h" // for expanded error reference information
#include "bgpd/bgp_fsm.h" // for BGP_EVENT_ADD, bgp_event
#include "bgpd/bgp_packet.h" // for bgp_notify_send_with_data, bgp_notify...
#include "bgpd/bgpd.h" // for peer, BGP_MARKER_SIZE, bgp_master, bm
@@ -401,8 +402,9 @@ static uint16_t bgp_read(struct peer *peer)
SET_FLAG(status, BGP_IO_TRANS_ERR);
/* Fatal error; tear down session */
} else if (nbytes < 0) {
- zlog_err("%s [Error] bgp_read_packet error: %s", peer->host,
- safe_strerror(errno));
+ flog_err(BGP_ERR_UPDATE_RCV,
+ "%s [Error] bgp_read_packet error: %s", peer->host,
+ safe_strerror(errno));
if (peer->status == Established) {
if (CHECK_FLAG(peer->sflags, PEER_STATUS_NSF_MODE)) {
diff --git a/bgpd/bgp_label.c b/bgpd/bgp_label.c
index 8a051b7ff0..633e589333 100644
--- a/bgpd/bgp_label.c
+++ b/bgpd/bgp_label.c
@@ -38,6 +38,7 @@
#include "bgpd/bgp_label.h"
#include "bgpd/bgp_packet.h"
#include "bgpd/bgp_debug.h"
+#include "bgpd/bgp_errors.h"
extern struct zclient *zclient;
@@ -244,7 +245,8 @@ int bgp_nlri_parse_label(struct peer *peer, struct attr *attr,
/* sanity check against packet data */
if ((pnt + psize) > lim) {
- zlog_err(
+ flog_err(
+ BGP_ERR_UPDATE_RCV,
"%s [Error] Update packet error / L-U (prefix length %d exceeds packet size %u)",
peer->host, prefixlen, (uint)(lim - pnt));
return -1;
@@ -256,10 +258,10 @@ int bgp_nlri_parse_label(struct peer *peer, struct attr *attr,
/* There needs to be at least one label */
if (prefixlen < 24) {
- zlog_err(
- "%s [Error] Update packet error"
- " (wrong label length %d)",
- peer->host, prefixlen);
+ flog_err(BGP_ERR_UPDATE_RCV,
+ "%s [Error] Update packet error"
+ " (wrong label length %d)",
+ peer->host, prefixlen);
bgp_notify_send(peer, BGP_NOTIFY_UPDATE_ERR,
BGP_NOTIFY_UPDATE_INVAL_NETWORK);
return -1;
@@ -284,7 +286,8 @@ int bgp_nlri_parse_label(struct peer *peer, struct attr *attr,
* be logged locally, and the prefix SHOULD be
* ignored.
*/
- zlog_err(
+ flog_err(
+ BGP_ERR_UPDATE_RCV,
"%s: IPv4 labeled-unicast NLRI is multicast address %s, ignoring",
peer->host, inet_ntoa(p.u.prefix4));
continue;
@@ -296,7 +299,8 @@ int bgp_nlri_parse_label(struct peer *peer, struct attr *attr,
if (IN6_IS_ADDR_LINKLOCAL(&p.u.prefix6)) {
char buf[BUFSIZ];
- zlog_err(
+ flog_err(
+ BGP_ERR_UPDATE_RCV,
"%s: IPv6 labeled-unicast NLRI is link-local address %s, ignoring",
peer->host,
inet_ntop(AF_INET6, &p.u.prefix6, buf,
@@ -308,7 +312,8 @@ int bgp_nlri_parse_label(struct peer *peer, struct attr *attr,
if (IN6_IS_ADDR_MULTICAST(&p.u.prefix6)) {
char buf[BUFSIZ];
- zlog_err(
+ flog_err(
+ BGP_ERR_UPDATE_RCV,
"%s: IPv6 unicast NLRI is multicast address %s, ignoring",
peer->host,
inet_ntop(AF_INET6, &p.u.prefix6, buf,
@@ -331,7 +336,8 @@ int bgp_nlri_parse_label(struct peer *peer, struct attr *attr,
/* Packet length consistency check. */
if (pnt != lim) {
- zlog_err(
+ flog_err(
+ BGP_ERR_UPDATE_RCV,
"%s [Error] Update packet error / L-U (%zu data remaining after parsing)",
peer->host, lim - pnt);
return -1;
diff --git a/bgpd/bgp_labelpool.c b/bgpd/bgp_labelpool.c
index 2c98cd9ef9..8d15649ea5 100644
--- a/bgpd/bgp_labelpool.c
+++ b/bgpd/bgp_labelpool.c
@@ -34,6 +34,7 @@
#include "bgpd/bgpd.h"
#include "bgpd/bgp_labelpool.h"
#include "bgpd/bgp_debug.h"
+#include "bgpd/bgp_errors.h"
/*
* Definitions and external declarations.
@@ -126,7 +127,8 @@ static wq_item_status lp_cbq_docallback(struct work_queue *wq, void *data)
if (lcbq->label == MPLS_LABEL_NONE) {
/* shouldn't happen */
- zlog_err("%s: error: label==MPLS_LABEL_NONE", __func__);
+ flog_err(BGP_ERR_LABEL, "%s: error: label==MPLS_LABEL_NONE",
+ __func__);
return WQ_SUCCESS;
}
@@ -202,10 +204,6 @@ void bgp_lp_init(struct thread_master *master, struct labelpool *pool)
lp->requests = XCALLOC(MTYPE_BGP_LABEL_FIFO, sizeof(struct lp_fifo));
LABEL_FIFO_INIT(lp->requests);
lp->callback_q = work_queue_new(master, "label callbacks");
- if (!lp->callback_q) {
- zlog_err("%s: Failed to allocate work queue", __func__);
- exit(1);
- }
lp->callback_q->spec.workfunc = lp_cbq_docallback;
lp->callback_q->spec.del_item_data = lp_cbq_item_free;
@@ -340,8 +338,9 @@ void bgp_lp_get(
if (rc) {
/* shouldn't happen */
- zlog_err("%s: can't insert new LCB into ledger list",
- __func__);
+ flog_err(BGP_ERR_LABEL,
+ "%s: can't insert new LCB into ledger list",
+ __func__);
XFREE(MTYPE_BGP_LABEL_CB, lcb);
return;
}
@@ -428,8 +427,9 @@ void bgp_lp_event_chunk(uint8_t keep, uint32_t first, uint32_t last)
struct lp_fifo *lf;
if (last < first) {
- zlog_err("%s: zebra label chunk invalid: first=%u, last=%u",
- __func__, first, last);
+ flog_err(BGP_ERR_LABEL,
+ "%s: zebra label chunk invalid: first=%u, last=%u",
+ __func__, first, last);
return;
}
diff --git a/bgpd/bgp_main.c b/bgpd/bgp_main.c
index 2327e262a1..8eb1c9e25f 100644
--- a/bgpd/bgp_main.c
+++ b/bgpd/bgp_main.c
@@ -54,11 +54,13 @@
#include "bgpd/bgp_regex.h"
#include "bgpd/bgp_clist.h"
#include "bgpd/bgp_debug.h"
+#include "bgpd/bgp_errors.h"
#include "bgpd/bgp_filter.h"
#include "bgpd/bgp_zebra.h"
#include "bgpd/bgp_packet.h"
#include "bgpd/bgp_keepalives.h"
#include "bgpd/bgp_network.h"
+#include "bgpd/bgp_errors.h"
#ifdef ENABLE_BGP_VNC
#include "bgpd/rfapi/rfapi_backend.h"
@@ -384,7 +386,8 @@ int main(int argc, char **argv)
multipath_num = atoi(optarg);
if (multipath_num > MULTIPATH_NUM
|| multipath_num <= 0) {
- zlog_err(
+ flog_err(
+ BGP_ERR_MULTIPATH,
"Multipath Number specified must be less than %d and greater than 0",
MULTIPATH_NUM);
return 1;
@@ -417,6 +420,7 @@ int main(int argc, char **argv)
if (no_fib_flag)
bgp_option_set(BGP_OPT_NO_FIB);
+ bgp_error_init();
/* Initializations. */
bgp_vrf_init();
diff --git a/bgpd/bgp_mplsvpn.c b/bgpd/bgp_mplsvpn.c
index f72104dd33..c2cb20b061 100644
--- a/bgpd/bgp_mplsvpn.c
+++ b/bgpd/bgp_mplsvpn.c
@@ -33,6 +33,7 @@
#include "bgpd/bgpd.h"
#include "bgpd/bgp_debug.h"
+#include "bgpd/bgp_errors.h"
#include "bgpd/bgp_table.h"
#include "bgpd/bgp_route.h"
#include "bgpd/bgp_attr.h"
@@ -150,7 +151,8 @@ int bgp_nlri_parse_vpn(struct peer *peer, struct attr *attr,
psize = PSIZE(prefixlen);
if (prefixlen < VPN_PREFIXLEN_MIN_BYTES * 8) {
- zlog_err(
+ flog_err(
+ BGP_ERR_UPDATE_RCV,
"%s [Error] Update packet error / VPN (prefix length %d less than VPN min length)",
peer->host, prefixlen);
return -1;
@@ -158,7 +160,8 @@ int bgp_nlri_parse_vpn(struct peer *peer, struct attr *attr,
/* sanity check against packet data */
if ((pnt + psize) > lim) {
- zlog_err(
+ flog_err(
+ BGP_ERR_UPDATE_RCV,
"%s [Error] Update packet error / VPN (prefix length %d exceeds packet size %u)",
peer->host, prefixlen, (uint)(lim - pnt));
return -1;
@@ -166,7 +169,8 @@ int bgp_nlri_parse_vpn(struct peer *peer, struct attr *attr,
/* sanity check against storage for the IP address portion */
if ((psize - VPN_PREFIXLEN_MIN_BYTES) > (ssize_t)sizeof(p.u)) {
- zlog_err(
+ flog_err(
+ BGP_ERR_UPDATE_RCV,
"%s [Error] Update packet error / VPN (psize %d exceeds storage size %zu)",
peer->host,
prefixlen - VPN_PREFIXLEN_MIN_BYTES * 8,
@@ -176,7 +180,8 @@ int bgp_nlri_parse_vpn(struct peer *peer, struct attr *attr,
/* Sanity check against max bitlen of the address family */
if ((psize - VPN_PREFIXLEN_MIN_BYTES) > prefix_blen(&p)) {
- zlog_err(
+ flog_err(
+ BGP_ERR_UPDATE_RCV,
"%s [Error] Update packet error / VPN (psize %d exceeds family (%u) max byte len %u)",
peer->host,
prefixlen - VPN_PREFIXLEN_MIN_BYTES * 8,
@@ -213,7 +218,8 @@ int bgp_nlri_parse_vpn(struct peer *peer, struct attr *attr,
#endif
default:
- zlog_err("Unknown RD type %d", type);
+ flog_err(BGP_ERR_UPDATE_RCV, "Unknown RD type %d",
+ type);
break; /* just report */
}
@@ -235,7 +241,8 @@ int bgp_nlri_parse_vpn(struct peer *peer, struct attr *attr,
}
/* Packet length consistency check. */
if (pnt != lim) {
- zlog_err(
+ flog_err(
+ BGP_ERR_UPDATE_RCV,
"%s [Error] Update packet error / VPN (%zu data remaining after parsing)",
peer->host, lim - pnt);
return -1;
@@ -359,8 +366,10 @@ int vpn_leak_label_callback(
return 0;
}
/* Shouldn't happen: different label allocation */
- zlog_err("%s: %s had label %u but got new assignment %u",
- __func__, vp->bgp->name_pretty, vp->tovpn_label, label);
+ flog_err(BGP_ERR_LABEL,
+ "%s: %s had label %u but got new assignment %u",
+ __func__, vp->bgp->name_pretty, vp->tovpn_label,
+ label);
/* use new one */
}
diff --git a/bgpd/bgp_network.c b/bgpd/bgp_network.c
index 476b64e75a..0664fdfd1c 100644
--- a/bgpd/bgp_network.c
+++ b/bgpd/bgp_network.c
@@ -35,12 +35,14 @@
#include "hash.h"
#include "filter.h"
#include "ns.h"
+#include "lib_errors.h"
#include "bgpd/bgpd.h"
#include "bgpd/bgp_open.h"
#include "bgpd/bgp_fsm.h"
#include "bgpd/bgp_attr.h"
#include "bgpd/bgp_debug.h"
+#include "bgpd/bgp_errors.h"
#include "bgpd/bgp_network.h"
extern struct zebra_privs_t bgpd_privs;
@@ -95,15 +97,9 @@ static int bgp_md5_set_connect(int socket, union sockunion *su,
int ret = -1;
#if HAVE_DECL_TCP_MD5SIG
- if (bgpd_privs.change(ZPRIVS_RAISE)) {
- zlog_err("%s: could not raise privs", __func__);
- return ret;
+ frr_elevate_privs(&bgpd_privs) {
+ ret = bgp_md5_set_socket(socket, su, password);
}
-
- ret = bgp_md5_set_socket(socket, su, password);
-
- if (bgpd_privs.change(ZPRIVS_LOWER))
- zlog_err("%s: could not lower privs", __func__);
#endif /* HAVE_TCP_MD5SIG */
return ret;
@@ -115,25 +111,18 @@ static int bgp_md5_set_password(struct peer *peer, const char *password)
int ret = 0;
struct bgp_listener *listener;
- if (bgpd_privs.change(ZPRIVS_RAISE)) {
- zlog_err("%s: could not raise privs", __func__);
- return -1;
- }
-
+ frr_elevate_privs(&bgpd_privs) {
/* Set or unset the password on the listen socket(s). Outbound
- * connections
- * are taken care of in bgp_connect() below.
+ * connections are taken care of in bgp_connect() below.
*/
- for (ALL_LIST_ELEMENTS_RO(bm->listen_sockets, node, listener))
- if (listener->su.sa.sa_family == peer->su.sa.sa_family) {
- ret = bgp_md5_set_socket(listener->fd, &peer->su,
- password);
- break;
- }
-
- if (bgpd_privs.change(ZPRIVS_LOWER))
- zlog_err("%s: could not lower privs", __func__);
-
+ for (ALL_LIST_ELEMENTS_RO(bm->listen_sockets, node, listener))
+ if (listener->su.sa.sa_family
+ == peer->su.sa.sa_family) {
+ ret = bgp_md5_set_socket(listener->fd,
+ &peer->su, password);
+ break;
+ }
+ }
return ret;
}
@@ -158,10 +147,12 @@ int bgp_set_socket_ttl(struct peer *peer, int bgp_sock)
if (!peer->gtsm_hops && (peer_sort(peer) == BGP_PEER_EBGP)) {
ret = sockopt_ttl(peer->su.sa.sa_family, bgp_sock, peer->ttl);
if (ret) {
- zlog_err(
+ flog_err(
+ LIB_ERR_SOCKET,
"%s: Can't set TxTTL on peer (rtrid %s) socket, err = %d",
- __func__, inet_ntop(AF_INET, &peer->remote_id,
- buf, sizeof(buf)),
+ __func__,
+ inet_ntop(AF_INET, &peer->remote_id, buf,
+ sizeof(buf)),
errno);
return ret;
}
@@ -172,20 +163,24 @@ int bgp_set_socket_ttl(struct peer *peer, int bgp_sock)
*/
ret = sockopt_ttl(peer->su.sa.sa_family, bgp_sock, MAXTTL);
if (ret) {
- zlog_err(
+ flog_err(
+ LIB_ERR_SOCKET,
"%s: Can't set TxTTL on peer (rtrid %s) socket, err = %d",
- __func__, inet_ntop(AF_INET, &peer->remote_id,
- buf, sizeof(buf)),
+ __func__,
+ inet_ntop(AF_INET, &peer->remote_id, buf,
+ sizeof(buf)),
errno);
return ret;
}
ret = sockopt_minttl(peer->su.sa.sa_family, bgp_sock,
MAXTTL + 1 - peer->gtsm_hops);
if (ret) {
- zlog_err(
+ flog_err(
+ LIB_ERR_SOCKET,
"%s: Can't set MinTTL on peer (rtrid %s) socket, err = %d",
- __func__, inet_ntop(AF_INET, &peer->remote_id,
- buf, sizeof(buf)),
+ __func__,
+ inet_ntop(AF_INET, &peer->remote_id, buf,
+ sizeof(buf)),
errno);
return ret;
}
@@ -226,8 +221,10 @@ static int bgp_get_instance_for_inc_conn(int sock, struct bgp **bgp_inst)
rc = getsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, name, &name_len);
if (rc != 0) {
#if defined(HAVE_CUMULUS)
- zlog_err("[Error] BGP SO_BINDTODEVICE get failed (%s), sock %d",
- safe_strerror(errno), sock);
+ flog_err(
+ LIB_ERR_SOCKET,
+ "[Error] BGP SO_BINDTODEVICE get failed (%s), sock %d",
+ safe_strerror(errno), sock);
return -1;
#endif
}
@@ -282,7 +279,8 @@ static int bgp_accept(struct thread *thread)
/* Register accept thread. */
accept_sock = THREAD_FD(thread);
if (accept_sock < 0) {
- zlog_err("accept_sock is nevative value %d", accept_sock);
+ flog_err_sys(LIB_ERR_SOCKET, "accept_sock is nevative value %d",
+ accept_sock);
return -1;
}
listener->thread = NULL;
@@ -293,8 +291,9 @@ static int bgp_accept(struct thread *thread)
/* Accept client connection. */
bgp_sock = sockunion_accept(accept_sock, &su);
if (bgp_sock < 0) {
- zlog_err("[Error] BGP socket accept failed (%s)",
- safe_strerror(errno));
+ flog_err_sys(LIB_ERR_SOCKET,
+ "[Error] BGP socket accept failed (%s)",
+ safe_strerror(errno));
return -1;
}
set_nonblocking(bgp_sock);
@@ -543,13 +542,11 @@ int bgp_connect(struct peer *peer)
zlog_debug("Peer address not learnt: Returning from connect");
return 0;
}
- if (bgpd_privs.change(ZPRIVS_RAISE))
- zlog_err("Can't raise privileges");
+ frr_elevate_privs(&bgpd_privs) {
/* Make socket for the peer. */
- peer->fd = vrf_sockunion_socket(&peer->su, peer->bgp->vrf_id,
- bgp_get_bound_name(peer));
- if (bgpd_privs.change(ZPRIVS_LOWER))
- zlog_err("Can't lower privileges");
+ peer->fd = vrf_sockunion_socket(&peer->su, peer->bgp->vrf_id,
+ bgp_get_bound_name(peer));
+ }
if (peer->fd < 0)
return -1;
@@ -568,14 +565,14 @@ int bgp_connect(struct peer *peer)
peer->host, safe_strerror(errno));
#ifdef IPTOS_PREC_INTERNETCONTROL
- if (bgpd_privs.change(ZPRIVS_RAISE))
- zlog_err("%s: could not raise privs", __func__);
- if (sockunion_family(&peer->su) == AF_INET)
- setsockopt_ipv4_tos(peer->fd, IPTOS_PREC_INTERNETCONTROL);
- else if (sockunion_family(&peer->su) == AF_INET6)
- setsockopt_ipv6_tclass(peer->fd, IPTOS_PREC_INTERNETCONTROL);
- if (bgpd_privs.change(ZPRIVS_LOWER))
- zlog_err("%s: could not lower privs", __func__);
+ frr_elevate_privs(&bgpd_privs) {
+ if (sockunion_family(&peer->su) == AF_INET)
+ setsockopt_ipv4_tos(peer->fd,
+ IPTOS_PREC_INTERNETCONTROL);
+ else if (sockunion_family(&peer->su) == AF_INET6)
+ setsockopt_ipv6_tclass(peer->fd,
+ IPTOS_PREC_INTERNETCONTROL);
+ }
#endif
if (peer->password)
@@ -623,7 +620,8 @@ int bgp_getsockname(struct peer *peer)
if (bgp_nexthop_set(peer->su_local, peer->su_remote, &peer->nexthop,
peer)) {
#if defined(HAVE_CUMULUS)
- zlog_err(
+ flog_err(
+ BGP_ERR_NH_UPD,
"%s: nexthop_set failed, resetting connection - intf %p",
peer->host, peer->nexthop.ifp);
return -1;
@@ -642,31 +640,31 @@ static int bgp_listener(int sock, struct sockaddr *sa, socklen_t salen,
sockopt_reuseaddr(sock);
sockopt_reuseport(sock);
- if (bgpd_privs.change(ZPRIVS_RAISE))
- zlog_err("%s: could not raise privs", __func__);
+ frr_elevate_privs(&bgpd_privs) {
#ifdef IPTOS_PREC_INTERNETCONTROL
- if (sa->sa_family == AF_INET)
- setsockopt_ipv4_tos(sock, IPTOS_PREC_INTERNETCONTROL);
- else if (sa->sa_family == AF_INET6)
- setsockopt_ipv6_tclass(sock, IPTOS_PREC_INTERNETCONTROL);
+ if (sa->sa_family == AF_INET)
+ setsockopt_ipv4_tos(sock, IPTOS_PREC_INTERNETCONTROL);
+ else if (sa->sa_family == AF_INET6)
+ setsockopt_ipv6_tclass(sock,
+ IPTOS_PREC_INTERNETCONTROL);
#endif
- sockopt_v6only(sa->sa_family, sock);
+ sockopt_v6only(sa->sa_family, sock);
- ret = bind(sock, sa, salen);
- en = errno;
- if (bgpd_privs.change(ZPRIVS_LOWER))
- zlog_err("%s: could not lower privs", __func__);
+ ret = bind(sock, sa, salen);
+ en = errno;
+ }
if (ret < 0) {
- zlog_err("bind: %s", safe_strerror(en));
+ flog_err_sys(LIB_ERR_SOCKET, "bind: %s", safe_strerror(en));
return ret;
}
ret = listen(sock, SOMAXCONN);
if (ret < 0) {
- zlog_err("listen: %s", safe_strerror(errno));
+ flog_err_sys(LIB_ERR_SOCKET, "listen: %s",
+ safe_strerror(errno));
return ret;
}
@@ -702,14 +700,13 @@ int bgp_socket(struct bgp *bgp, unsigned short port, const char *address)
snprintf(port_str, sizeof(port_str), "%d", port);
port_str[sizeof(port_str) - 1] = '\0';
- if (bgpd_privs.change(ZPRIVS_RAISE))
- zlog_err("Can't raise privileges");
- ret = vrf_getaddrinfo(address, port_str, &req, &ainfo_save,
- bgp->vrf_id);
- if (bgpd_privs.change(ZPRIVS_LOWER))
- zlog_err("Can't lower privileges");
+ frr_elevate_privs(&bgpd_privs) {
+ ret = vrf_getaddrinfo(address, port_str, &req, &ainfo_save,
+ bgp->vrf_id);
+ }
if (ret != 0) {
- zlog_err("getaddrinfo: %s", gai_strerror(ret));
+ flog_err_sys(LIB_ERR_SOCKET, "getaddrinfo: %s",
+ gai_strerror(ret));
return -1;
}
@@ -720,16 +717,17 @@ int bgp_socket(struct bgp *bgp, unsigned short port, const char *address)
if (ainfo->ai_family != AF_INET && ainfo->ai_family != AF_INET6)
continue;
- if (bgpd_privs.change(ZPRIVS_RAISE))
- zlog_err("Can't raise privileges");
- sock = vrf_socket(ainfo->ai_family, ainfo->ai_socktype,
- ainfo->ai_protocol, bgp->vrf_id,
- (bgp->inst_type == BGP_INSTANCE_TYPE_VRF ?
- bgp->name : NULL));
- if (bgpd_privs.change(ZPRIVS_LOWER))
- zlog_err("Can't lower privileges");
+ frr_elevate_privs(&bgpd_privs) {
+ sock = vrf_socket(ainfo->ai_family,
+ ainfo->ai_socktype,
+ ainfo->ai_protocol, bgp->vrf_id,
+ (bgp->inst_type
+ == BGP_INSTANCE_TYPE_VRF
+ ? bgp->name : NULL));
+ }
if (sock < 0) {
- zlog_err("socket: %s", safe_strerror(errno));
+ flog_err_sys(LIB_ERR_SOCKET, "socket: %s",
+ safe_strerror(errno));
continue;
}
@@ -746,10 +744,12 @@ int bgp_socket(struct bgp *bgp, unsigned short port, const char *address)
}
freeaddrinfo(ainfo_save);
if (count == 0 && bgp->inst_type != BGP_INSTANCE_TYPE_VRF) {
- zlog_err(
+ flog_err(
+ LIB_ERR_SOCKET,
"%s: no usable addresses please check other programs usage of specified port %d",
__func__, port);
- zlog_err("%s: Program cannot continue", __func__);
+ flog_err_sys(LIB_ERR_SOCKET, "%s: Program cannot continue",
+ __func__);
exit(-1);
}
diff --git a/bgpd/bgp_nht.c b/bgpd/bgp_nht.c
index 2c9e379299..0c0c079950 100644
--- a/bgpd/bgp_nht.c
+++ b/bgpd/bgp_nht.c
@@ -38,6 +38,7 @@
#include "bgpd/bgp_attr.h"
#include "bgpd/bgp_nexthop.h"
#include "bgpd/bgp_debug.h"
+#include "bgpd/bgp_errors.h"
#include "bgpd/bgp_nht.h"
#include "bgpd/bgp_fsm.h"
#include "bgpd/bgp_zebra.h"
@@ -88,7 +89,7 @@ int bgp_find_nexthop(struct bgp_info *path, int connected)
static void bgp_unlink_nexthop_check(struct bgp_nexthop_cache *bnc)
{
- if (LIST_EMPTY(&(bnc->paths)) && bnc->nht_info) {
+ if (LIST_EMPTY(&(bnc->paths)) && !bnc->nht_info) {
if (BGP_DEBUG(nht, NHT)) {
char buf[PREFIX2STR_BUFFER];
zlog_debug("bgp_unlink_nexthop: freeing bnc %s",
@@ -343,7 +344,8 @@ void bgp_parse_nexthop_update(int command, vrf_id_t vrf_id)
bgp = bgp_lookup_by_vrf_id(vrf_id);
if (!bgp) {
- zlog_err(
+ flog_err(
+ BGP_ERR_NH_UPD,
"parse nexthop update: instance not found for vrf_id %u",
vrf_id);
return;
diff --git a/bgpd/bgp_open.c b/bgpd/bgp_open.c
index da90bbd67d..7fbc030242 100644
--- a/bgpd/bgp_open.c
+++ b/bgpd/bgp_open.c
@@ -34,6 +34,7 @@
#include "bgpd/bgpd.h"
#include "bgpd/bgp_attr.h"
#include "bgpd/bgp_debug.h"
+#include "bgpd/bgp_errors.h"
#include "bgpd/bgp_fsm.h"
#include "bgpd/bgp_packet.h"
#include "bgpd/bgp_open.h"
@@ -520,8 +521,9 @@ static as_t bgp_capability_as4(struct peer *peer, struct capability_header *hdr)
SET_FLAG(peer->cap, PEER_CAP_AS4_RCV);
if (hdr->length != CAPABILITY_CODE_AS4_LEN) {
- zlog_err("%s AS4 capability has incorrect data length %d",
- peer->host, hdr->length);
+ flog_err(BGP_ERR_PKT_OPEN,
+ "%s AS4 capability has incorrect data length %d",
+ peer->host, hdr->length);
return 0;
}
@@ -1184,10 +1186,10 @@ int bgp_open_option_parse(struct peer *peer, uint8_t length, int *mp_capability)
&& !peer->afc_nego[AFI_IP6][SAFI_ENCAP]
&& !peer->afc_nego[AFI_IP6][SAFI_FLOWSPEC]
&& !peer->afc_nego[AFI_L2VPN][SAFI_EVPN]) {
- zlog_err(
- "%s [Error] Configured AFI/SAFIs do not "
- "overlap with received MP capabilities",
- peer->host);
+ flog_err(BGP_ERR_PKT_OPEN,
+ "%s [Error] Configured AFI/SAFIs do not "
+ "overlap with received MP capabilities",
+ peer->host);
if (error != error_data)
bgp_notify_send_with_data(
diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c
index 446dc5ac12..bb474b9e20 100644
--- a/bgpd/bgp_packet.c
+++ b/bgpd/bgp_packet.c
@@ -36,12 +36,14 @@
#include "plist.h"
#include "queue.h"
#include "filter.h"
+#include "lib_errors.h"
#include "bgpd/bgpd.h"
#include "bgpd/bgp_table.h"
#include "bgpd/bgp_dump.h"
#include "bgpd/bgp_attr.h"
#include "bgpd/bgp_debug.h"
+#include "bgpd/bgp_errors.h"
#include "bgpd/bgp_fsm.h"
#include "bgpd/bgp_route.h"
#include "bgpd/bgp_packet.h"
@@ -1089,8 +1091,9 @@ static int bgp_open_receive(struct peer *peer, bgp_size_t size)
/* Just in case we have a silly peer who sends AS4 capability set to 0
*/
if (CHECK_FLAG(peer->cap, PEER_CAP_AS4_RCV) && !as4) {
- zlog_err("%s bad OPEN, got AS4 capability, but AS4 set to 0",
- peer->host);
+ flog_err(BGP_ERR_PKT_OPEN,
+ "%s bad OPEN, got AS4 capability, but AS4 set to 0",
+ peer->host);
bgp_notify_send_with_data(peer, BGP_NOTIFY_OPEN_ERR,
BGP_NOTIFY_OPEN_BAD_PEER_AS,
notify_data_remote_as4, 4);
@@ -1103,7 +1106,8 @@ static int bgp_open_receive(struct peer *peer, bgp_size_t size)
* BGP_AS_TRANS, for some unknown reason.
*/
if (as4 == BGP_AS_TRANS) {
- zlog_err(
+ flog_err(
+ BGP_ERR_PKT_OPEN,
"%s [AS4] NEW speaker using AS_TRANS for AS4, not allowed",
peer->host);
bgp_notify_send_with_data(peer, BGP_NOTIFY_OPEN_ERR,
@@ -1132,7 +1136,8 @@ static int bgp_open_receive(struct peer *peer, bgp_size_t size)
if (CHECK_FLAG(peer->cap, PEER_CAP_AS4_RCV)
&& as4 != remote_as) {
/* raise error, log this, close session */
- zlog_err(
+ flog_err(
+ BGP_ERR_PKT_OPEN,
"%s bad OPEN, got AS4 capability, but remote_as %u"
" mismatch with 16bit 'myasn' %u in open",
peer->host, as4, remote_as);
@@ -1299,8 +1304,9 @@ static int bgp_open_receive(struct peer *peer, bgp_size_t size)
/* Get sockname. */
if ((ret = bgp_getsockname(peer)) < 0) {
- zlog_err("%s: bgp_getsockname() failed for peer: %s",
- __FUNCTION__, peer->host);
+ flog_err_sys(LIB_ERR_SOCKET,
+ "%s: bgp_getsockname() failed for peer: %s",
+ __FUNCTION__, peer->host);
return BGP_Stop;
}
@@ -1313,7 +1319,8 @@ static int bgp_open_receive(struct peer *peer, bgp_size_t size)
|| peer->afc_nego[AFI_IP][SAFI_ENCAP]) {
if (!peer->nexthop.v4.s_addr) {
#if defined(HAVE_CUMULUS)
- zlog_err(
+ flog_err(
+ BGP_ERR_SND_FAIL,
"%s: No local IPv4 addr resetting connection, fd %d",
peer->host, peer->fd);
bgp_notify_send(peer, BGP_NOTIFY_CEASE,
@@ -1329,7 +1336,8 @@ static int bgp_open_receive(struct peer *peer, bgp_size_t size)
|| peer->afc_nego[AFI_IP6][SAFI_ENCAP]) {
if (IN6_IS_ADDR_UNSPECIFIED(&peer->nexthop.v6_global)) {
#if defined(HAVE_CUMULUS)
- zlog_err(
+ flog_err(
+ BGP_ERR_SND_FAIL,
"%s: No local IPv6 addr resetting connection, fd %d",
peer->host, peer->fd);
bgp_notify_send(peer, BGP_NOTIFY_CEASE,
@@ -1391,9 +1399,10 @@ static int bgp_update_receive(struct peer *peer, bgp_size_t size)
/* Status must be Established. */
if (peer->status != Established) {
- zlog_err("%s [FSM] Update packet received under status %s",
- peer->host,
- lookup_msg(bgp_status_msg, peer->status, NULL));
+ flog_err(BGP_ERR_INVALID_STATUS,
+ "%s [FSM] Update packet received under status %s",
+ peer->host,
+ lookup_msg(bgp_status_msg, peer->status, NULL));
bgp_notify_send(peer, BGP_NOTIFY_FSM_ERR, 0);
return BGP_Stop;
}
@@ -1414,10 +1423,10 @@ static int bgp_update_receive(struct peer *peer, bgp_size_t size)
Attribute Length + 23 exceeds the message Length), then the Error
Subcode is set to Malformed Attribute List. */
if (stream_pnt(s) + 2 > end) {
- zlog_err(
- "%s [Error] Update packet error"
- " (packet length is short for unfeasible length)",
- peer->host);
+ flog_err(BGP_ERR_UPDATE_RCV,
+ "%s [Error] Update packet error"
+ " (packet length is short for unfeasible length)",
+ peer->host);
bgp_notify_send(peer, BGP_NOTIFY_UPDATE_ERR,
BGP_NOTIFY_UPDATE_MAL_ATTR);
return BGP_Stop;
@@ -1428,10 +1437,10 @@ static int bgp_update_receive(struct peer *peer, bgp_size_t size)
/* Unfeasible Route Length check. */
if (stream_pnt(s) + withdraw_len > end) {
- zlog_err(
- "%s [Error] Update packet error"
- " (packet unfeasible length overflow %d)",
- peer->host, withdraw_len);
+ flog_err(BGP_ERR_UPDATE_RCV,
+ "%s [Error] Update packet error"
+ " (packet unfeasible length overflow %d)",
+ peer->host, withdraw_len);
bgp_notify_send(peer, BGP_NOTIFY_UPDATE_ERR,
BGP_NOTIFY_UPDATE_MAL_ATTR);
return BGP_Stop;
@@ -1502,7 +1511,8 @@ static int bgp_update_receive(struct peer *peer, bgp_size_t size)
ret = bgp_dump_attr(&attr, peer->rcvd_attr_str, BUFSIZ);
if (attr_parse_ret == BGP_ATTR_PARSE_WITHDRAW)
- zlog_err(
+ flog_err(
+ BGP_ERR_UPDATE_RCV,
"%s rcvd UPDATE with errors in attr(s)!! Withdrawing route.",
peer->host);
@@ -1562,7 +1572,8 @@ static int bgp_update_receive(struct peer *peer, bgp_size_t size)
}
if (nlri_ret < 0) {
- zlog_err("%s [Error] Error parsing NLRI", peer->host);
+ flog_err(BGP_ERR_UPDATE_RCV,
+ "%s [Error] Error parsing NLRI", peer->host);
if (peer->status == Established)
bgp_notify_send(
peer, BGP_NOTIFY_UPDATE_ERR,
@@ -1733,8 +1744,9 @@ static int bgp_route_refresh_receive(struct peer *peer, bgp_size_t size)
/* If peer does not have the capability, send notification. */
if (!CHECK_FLAG(peer->cap, PEER_CAP_REFRESH_ADV)) {
- zlog_err("%s [Error] BGP route refresh is not enabled",
- peer->host);
+ flog_err(BGP_ERR_NO_CAP,
+ "%s [Error] BGP route refresh is not enabled",
+ peer->host);
bgp_notify_send(peer, BGP_NOTIFY_HEADER_ERR,
BGP_NOTIFY_HEADER_BAD_MESTYPE);
return BGP_Stop;
@@ -1742,7 +1754,8 @@ static int bgp_route_refresh_receive(struct peer *peer, bgp_size_t size)
/* Status must be Established. */
if (peer->status != Established) {
- zlog_err(
+ flog_err(
+ BGP_ERR_INVALID_STATUS,
"%s [Error] Route refresh packet received under status %s",
peer->host,
lookup_msg(bgp_status_msg, peer->status, NULL));
@@ -2122,8 +2135,9 @@ int bgp_capability_receive(struct peer *peer, bgp_size_t size)
/* If peer does not have the capability, send notification. */
if (!CHECK_FLAG(peer->cap, PEER_CAP_DYNAMIC_ADV)) {
- zlog_err("%s [Error] BGP dynamic capability is not enabled",
- peer->host);
+ flog_err(BGP_ERR_NO_CAP,
+ "%s [Error] BGP dynamic capability is not enabled",
+ peer->host);
bgp_notify_send(peer, BGP_NOTIFY_HEADER_ERR,
BGP_NOTIFY_HEADER_BAD_MESTYPE);
return BGP_Stop;
@@ -2131,7 +2145,8 @@ int bgp_capability_receive(struct peer *peer, bgp_size_t size)
/* Status must be Established. */
if (peer->status != Established) {
- zlog_err(
+ flog_err(
+ BGP_ERR_NO_CAP,
"%s [Error] Dynamic capability packet received under status %s",
peer->host,
lookup_msg(bgp_status_msg, peer->status, NULL));
@@ -2212,7 +2227,8 @@ int bgp_process_packet(struct thread *thread)
memory_order_relaxed);
mprc = bgp_open_receive(peer, size);
if (mprc == BGP_Stop)
- zlog_err(
+ flog_err(
+ BGP_ERR_PKT_OPEN,
"%s: BGP OPEN receipt failed for peer: %s",
__FUNCTION__, peer->host);
break;
@@ -2222,7 +2238,8 @@ int bgp_process_packet(struct thread *thread)
peer->readtime = monotime(NULL);
mprc = bgp_update_receive(peer, size);
if (mprc == BGP_Stop)
- zlog_err(
+ flog_err(
+ BGP_ERR_UPDATE_RCV,
"%s: BGP UPDATE receipt failed for peer: %s",
__FUNCTION__, peer->host);
break;
@@ -2231,7 +2248,8 @@ int bgp_process_packet(struct thread *thread)
memory_order_relaxed);
mprc = bgp_notify_receive(peer, size);
if (mprc == BGP_Stop)
- zlog_err(
+ flog_err(
+ BGP_ERR_NOTIFY_RCV,
"%s: BGP NOTIFY receipt failed for peer: %s",
__FUNCTION__, peer->host);
break;
@@ -2241,7 +2259,8 @@ int bgp_process_packet(struct thread *thread)
memory_order_relaxed);
mprc = bgp_keepalive_receive(peer, size);
if (mprc == BGP_Stop)
- zlog_err(
+ flog_err(
+ BGP_ERR_KEEP_RCV,
"%s: BGP KEEPALIVE receipt failed for peer: %s",
__FUNCTION__, peer->host);
break;
@@ -2251,7 +2270,8 @@ int bgp_process_packet(struct thread *thread)
memory_order_relaxed);
mprc = bgp_route_refresh_receive(peer, size);
if (mprc == BGP_Stop)
- zlog_err(
+ flog_err(
+ BGP_ERR_RFSH_RCV,
"%s: BGP ROUTEREFRESH receipt failed for peer: %s",
__FUNCTION__, peer->host);
break;
@@ -2260,7 +2280,8 @@ int bgp_process_packet(struct thread *thread)
memory_order_relaxed);
mprc = bgp_capability_receive(peer, size);
if (mprc == BGP_Stop)
- zlog_err(
+ flog_err(
+ BGP_ERR_CAP_RCV,
"%s: BGP CAPABILITY receipt failed for peer: %s",
__FUNCTION__, peer->host);
break;
diff --git a/bgpd/bgp_pbr.c b/bgpd/bgp_pbr.c
index de475d2dcd..129c143a64 100644
--- a/bgpd/bgp_pbr.c
+++ b/bgpd/bgp_pbr.c
@@ -33,6 +33,7 @@
#include "bgpd/bgp_zebra.h"
#include "bgpd/bgp_mplsvpn.h"
#include "bgpd/bgp_flowspec_private.h"
+#include "bgpd/bgp_errors.h"
DEFINE_MTYPE_STATIC(BGPD, PBR_MATCH_ENTRY, "PBR match entry")
DEFINE_MTYPE_STATIC(BGPD, PBR_MATCH, "PBR match")
@@ -652,8 +653,9 @@ static int bgp_pbr_build_and_validate_entry(struct prefix *p,
action_count++;
if (action_count > ACTIONS_MAX_NUM) {
if (BGP_DEBUG(pbr, PBR_ERROR))
- zlog_err("%s: flowspec actions exceeds limit (max %u)",
- __func__, action_count);
+ flog_err(BGP_ERR_FLOWSPEC_PACKET,
+ "%s: flowspec actions exceeds limit (max %u)",
+ __func__, action_count);
break;
}
api_action = &api->actions[action_count - 1];
@@ -2250,15 +2252,17 @@ void bgp_pbr_update_entry(struct bgp *bgp, struct prefix *p,
if (!bgp_zebra_tm_chunk_obtained()) {
if (BGP_DEBUG(pbr, PBR_ERROR))
- zlog_err("%s: table chunk not obtained yet",
- __func__);
+ flog_err(BGP_ERR_TABLE_CHUNK,
+ "%s: table chunk not obtained yet",
+ __func__);
return;
}
if (bgp_pbr_build_and_validate_entry(p, info, &api) < 0) {
if (BGP_DEBUG(pbr, PBR_ERROR))
- zlog_err("%s: cancel updating entry %p in bgp pbr",
- __func__, info);
+ flog_err(BGP_ERR_FLOWSPEC_INSTALLATION,
+ "%s: cancel updating entry %p in bgp pbr",
+ __func__, info);
return;
}
bgp_pbr_handle_entry(bgp, info, &api, nlri_update);
diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c
index b66a913f54..b395543795 100644
--- a/bgpd/bgp_route.c
+++ b/bgpd/bgp_route.c
@@ -44,6 +44,7 @@
#include "bgpd/bgp_route.h"
#include "bgpd/bgp_attr.h"
#include "bgpd/bgp_debug.h"
+#include "bgpd/bgp_errors.h"
#include "bgpd/bgp_aspath.h"
#include "bgpd/bgp_regex.h"
#include "bgpd/bgp_community.h"
@@ -2459,16 +2460,10 @@ static void bgp_processq_del(struct work_queue *wq, void *data)
void bgp_process_queue_init(void)
{
- if (!bm->process_main_queue) {
+ if (!bm->process_main_queue)
bm->process_main_queue =
work_queue_new(bm->master, "process_main_queue");
- if (!bm->process_main_queue) {
- zlog_err("%s: Failed to allocate work queue", __func__);
- exit(1);
- }
- }
-
bm->process_main_queue->spec.workfunc = &bgp_process_wq;
bm->process_main_queue->spec.del_item_data = &bgp_processq_del;
bm->process_main_queue->spec.max_retries = 0;
@@ -3838,11 +3833,7 @@ static void bgp_clear_node_queue_init(struct peer *peer)
snprintf(wname, sizeof(wname), "clear %s", peer->host);
#undef CLEAR_QUEUE_NAME_LEN
- if ((peer->clear_node_queue = work_queue_new(bm->master, wname))
- == NULL) {
- zlog_err("%s: Failed to allocate work queue", __func__);
- exit(1);
- }
+ peer->clear_node_queue = work_queue_new(bm->master, wname);
peer->clear_node_queue->spec.hold = 10;
peer->clear_node_queue->spec.workfunc = &bgp_clear_route_node;
peer->clear_node_queue->spec.del_item_data = &bgp_clear_node_queue_del;
@@ -4212,8 +4203,9 @@ int bgp_nlri_parse_ip(struct peer *peer, struct attr *attr,
/* Prefix length check. */
if (p.prefixlen > prefix_blen(&p) * 8) {
- zlog_err(
- "%s [Error] Update packet error (wrong perfix length %d for afi %u)",
+ flog_err(
+ BGP_ERR_UPDATE_RCV,
+ "%s [Error] Update packet error (wrong prefix length %d for afi %u)",
peer->host, p.prefixlen, packet->afi);
return -1;
}
@@ -4223,7 +4215,8 @@ int bgp_nlri_parse_ip(struct peer *peer, struct attr *attr,
/* When packet overflow occur return immediately. */
if (pnt + psize > lim) {
- zlog_err(
+ flog_err(
+ BGP_ERR_UPDATE_RCV,
"%s [Error] Update packet error (prefix length %d overflows packet)",
peer->host, p.prefixlen);
return -1;
@@ -4232,7 +4225,8 @@ int bgp_nlri_parse_ip(struct peer *peer, struct attr *attr,
/* Defensive coding, double-check the psize fits in a struct
* prefix */
if (psize > (ssize_t)sizeof(p.u)) {
- zlog_err(
+ flog_err(
+ BGP_ERR_UPDATE_RCV,
"%s [Error] Update packet error (prefix length %d too large for prefix storage %zu)",
peer->host, p.prefixlen, sizeof(p.u));
return -1;
@@ -4253,7 +4247,8 @@ int bgp_nlri_parse_ip(struct peer *peer, struct attr *attr,
* be logged locally, and the prefix SHOULD be
* ignored.
*/
- zlog_err(
+ flog_err(
+ BGP_ERR_UPDATE_RCV,
"%s: IPv4 unicast NLRI is multicast address %s, ignoring",
peer->host, inet_ntoa(p.u.prefix4));
continue;
@@ -4265,7 +4260,8 @@ int bgp_nlri_parse_ip(struct peer *peer, struct attr *attr,
if (IN6_IS_ADDR_LINKLOCAL(&p.u.prefix6)) {
char buf[BUFSIZ];
- zlog_err(
+ flog_err(
+ BGP_ERR_UPDATE_RCV,
"%s: IPv6 unicast NLRI is link-local address %s, ignoring",
peer->host,
inet_ntop(AF_INET6, &p.u.prefix6, buf,
@@ -4276,7 +4272,8 @@ int bgp_nlri_parse_ip(struct peer *peer, struct attr *attr,
if (IN6_IS_ADDR_MULTICAST(&p.u.prefix6)) {
char buf[BUFSIZ];
- zlog_err(
+ flog_err(
+ BGP_ERR_UPDATE_RCV,
"%s: IPv6 unicast NLRI is multicast address %s, ignoring",
peer->host,
inet_ntop(AF_INET6, &p.u.prefix6, buf,
@@ -4305,7 +4302,8 @@ int bgp_nlri_parse_ip(struct peer *peer, struct attr *attr,
/* Packet length consistency check. */
if (pnt != lim) {
- zlog_err(
+ flog_err(
+ BGP_ERR_UPDATE_RCV,
"%s [Error] Update packet error (prefix length mismatch with total length)",
peer->host);
return -1;
@@ -6255,24 +6253,14 @@ static void route_vty_out_route(struct prefix *p, struct vty *vty,
json_object *json)
{
int len = 0;
- uint32_t destination;
char buf[BUFSIZ];
if (p->family == AF_INET) {
if (!json) {
- len = vty_out(vty, "%s",
- inet_ntop(p->family, &p->u.prefix, buf,
- BUFSIZ));
- destination = ntohl(p->u.prefix4.s_addr);
-
- 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) {
- /* When mask is natural,
- mask is not displayed. */
- } else
- len += vty_out(vty, "/%d", p->prefixlen);
+ len = vty_out(
+ vty, "%s/%d",
+ inet_ntop(p->family, &p->u.prefix, buf, BUFSIZ),
+ p->prefixlen);
} else {
json_object_string_add(json, "prefix",
inet_ntop(p->family,
diff --git a/bgpd/bgp_rpki.c b/bgpd/bgp_rpki.c
index 774c484784..52c5dc5e90 100644
--- a/bgpd/bgp_rpki.c
+++ b/bgpd/bgp_rpki.c
@@ -126,7 +126,7 @@ static void print_record(const struct pfx_record *record, void *data);
static int is_synchronized(void);
static int is_running(void);
static void route_match_free(void *rule);
-static route_map_result_t route_match(void *rule, struct prefix *prefix,
+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,
@@ -190,7 +190,7 @@ static void free_tr_socket(struct cache *cache)
}
static int rpki_validate_prefix(struct peer *peer, struct attr *attr,
- struct prefix *prefix);
+ const struct prefix *prefix);
static void ipv6_addr_to_network_byte_order(const uint32_t *src, uint32_t *dest)
{
@@ -208,7 +208,7 @@ static void ipv6_addr_to_host_byte_order(const uint32_t *src, uint32_t *dest)
dest[i] = ntohl(src[i]);
}
-static route_map_result_t route_match(void *rule, struct prefix *prefix,
+static route_map_result_t route_match(void *rule, const struct prefix *prefix,
route_map_object_t type, void *object)
{
int *rpki_status = rule;
@@ -621,7 +621,7 @@ static void print_prefix_table(struct vty *vty)
}
static int rpki_validate_prefix(struct peer *peer, struct attr *attr,
- struct prefix *prefix)
+ const struct prefix *prefix)
{
struct assegment *as_segment;
as_t as_number = 0;
diff --git a/bgpd/bgp_updgrp.c b/bgpd/bgp_updgrp.c
index 6a65f982e0..37740671ca 100644
--- a/bgpd/bgp_updgrp.c
+++ b/bgpd/bgp_updgrp.c
@@ -47,6 +47,7 @@
#include "bgpd/bgpd.h"
#include "bgpd/bgp_table.h"
#include "bgpd/bgp_debug.h"
+#include "bgpd/bgp_errors.h"
#include "bgpd/bgp_fsm.h"
#include "bgpd/bgp_advertise.h"
#include "bgpd/bgp_packet.h"
@@ -1630,8 +1631,9 @@ void update_group_adjust_peer(struct peer_af *paf)
if (!updgrp) {
updgrp = update_group_create(paf);
if (!updgrp) {
- zlog_err("couldn't create update group for peer %s",
- paf->peer->host);
+ flog_err(BGP_ERR_UPDGRP_CREATE,
+ "couldn't create update group for peer %s",
+ paf->peer->host);
return;
}
}
diff --git a/bgpd/bgp_updgrp_packet.c b/bgpd/bgp_updgrp_packet.c
index 34ddbfcd14..c0761503f1 100644
--- a/bgpd/bgp_updgrp_packet.c
+++ b/bgpd/bgp_updgrp_packet.c
@@ -46,6 +46,7 @@
#include "bgpd/bgpd.h"
#include "bgpd/bgp_debug.h"
+#include "bgpd/bgp_errors.h"
#include "bgpd/bgp_fsm.h"
#include "bgpd/bgp_route.h"
#include "bgpd/bgp_packet.h"
@@ -786,7 +787,8 @@ struct bpacket *subgroup_update_packet(struct update_subgroup *subgrp)
* NLRI then
* return */
if (space_remaining < space_needed) {
- zlog_err(
+ flog_err(
+ BGP_ERR_UPDGRP_ATTR_LEN,
"u%" PRIu64 ":s%" PRIu64
" attributes too long, cannot send UPDATE",
subgrp->update_group->id, subgrp->id);
diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c
index e3efbbf252..e12d9ec341 100644
--- a/bgpd/bgp_vty.c
+++ b/bgpd/bgp_vty.c
@@ -45,6 +45,7 @@
#include "bgpd/bgp_lcommunity.h"
#include "bgpd/bgp_damp.h"
#include "bgpd/bgp_debug.h"
+#include "bgpd/bgp_errors.h"
#include "bgpd/bgp_fsm.h"
#include "bgpd/bgp_nexthop.h"
#include "bgpd/bgp_open.h"
@@ -10754,7 +10755,8 @@ static void bgp_show_all_instances_neighbors_vty(struct vty *vty,
for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp)) {
if (use_json) {
if (!(json = json_object_new_object())) {
- zlog_err(
+ flog_err(
+ BGP_ERR_JSON_MEM_ERROR,
"Unable to allocate memory for JSON object");
vty_out(vty,
"{\"error\": {\"message:\": \"Unable to allocate memory for JSON object\"}}}\n");
diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c
index 9591fe673f..59659c9186 100644
--- a/bgpd/bgp_zebra.c
+++ b/bgpd/bgp_zebra.c
@@ -44,6 +44,7 @@
#include "bgpd/bgp_zebra.h"
#include "bgpd/bgp_fsm.h"
#include "bgpd/bgp_debug.h"
+#include "bgpd/bgp_errors.h"
#include "bgpd/bgp_mpath.h"
#include "bgpd/bgp_nexthop.h"
#include "bgpd/bgp_nht.h"
@@ -1077,7 +1078,8 @@ int bgp_zebra_get_table_range(uint32_t chunk_size,
return -1;
ret = tm_get_table_chunk(zclient, chunk_size, start, end);
if (ret < 0) {
- zlog_err("BGP: Error getting table chunk %u", chunk_size);
+ flog_err(BGP_ERR_TABLE_CHUNK,
+ "BGP: Error getting table chunk %u", chunk_size);
return -1;
}
zlog_info("BGP: Table Manager returns range from chunk %u is [%u %u]",
@@ -2381,9 +2383,10 @@ static int bgp_zebra_process_local_macip(int command, struct zclient *zclient,
ipa_len = stream_getl(s);
if (ipa_len != 0 && ipa_len != IPV4_MAX_BYTELEN
&& ipa_len != IPV6_MAX_BYTELEN) {
- zlog_err("%u:Recv MACIP %s with invalid IP addr length %d",
- vrf_id, (command == ZEBRA_MACIP_ADD) ? "Add" : "Del",
- ipa_len);
+ flog_err(BGP_ERR_MACIP_LEN,
+ "%u:Recv MACIP %s with invalid IP addr length %d",
+ vrf_id, (command == ZEBRA_MACIP_ADD) ? "Add" : "Del",
+ ipa_len);
return -1;
}
@@ -2473,11 +2476,13 @@ static void bgp_zebra_process_label_chunk(
STREAM_GETL(s, last);
if (zclient->redist_default != proto) {
- zlog_err("Got LM msg with wrong proto %u", proto);
+ flog_err(BGP_ERR_LM_ERROR, "Got LM msg with wrong proto %u",
+ proto);
return;
}
if (zclient->instance != instance) {
- zlog_err("Got LM msg with wrong instance %u", proto);
+ flog_err(BGP_ERR_LM_ERROR, "Got LM msg with wrong instance %u",
+ proto);
return;
}
@@ -2485,8 +2490,8 @@ static void bgp_zebra_process_label_chunk(
first < MPLS_LABEL_UNRESERVED_MIN ||
last > MPLS_LABEL_UNRESERVED_MAX) {
- zlog_err("%s: Invalid Label chunk: %u - %u",
- __func__, first, last);
+ flog_err(BGP_ERR_LM_ERROR, "%s: Invalid Label chunk: %u - %u",
+ __func__, first, last);
return;
}
if (BGP_DEBUG(zebra, ZEBRA)) {
diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c
index 82da0245b5..555dd2a493 100644
--- a/bgpd/bgpd.c
+++ b/bgpd/bgpd.c
@@ -52,6 +52,7 @@
#include "bgpd/bgp_route.h"
#include "bgpd/bgp_dump.h"
#include "bgpd/bgp_debug.h"
+#include "bgpd/bgp_errors.h"
#include "bgpd/bgp_community.h"
#include "bgpd/bgp_attr.h"
#include "bgpd/bgp_regex.h"
@@ -683,12 +684,6 @@ struct peer_af *peer_af_create(struct peer *peer, afi_t afi, safi_t safi)
/* Allocate new peer af */
af = XCALLOC(MTYPE_BGP_PEER_AF, sizeof(struct peer_af));
- if (af == NULL) {
- zlog_err("Could not create af structure for peer %s",
- peer->host);
- return NULL;
- }
-
peer->peer_af_array[afid] = af;
af->afi = afi;
af->safi = safi;
@@ -1809,8 +1804,8 @@ static int peer_activate_af(struct peer *peer, afi_t afi, safi_t safi)
int active;
if (CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
- zlog_err("%s was called for peer-group %s", __func__,
- peer->host);
+ flog_err(BGP_ERR_PEER_GROUP, "%s was called for peer-group %s",
+ __func__, peer->host);
return 1;
}
@@ -1923,8 +1918,8 @@ static int non_peergroup_deactivate_af(struct peer *peer, afi_t afi,
safi_t safi)
{
if (CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
- zlog_err("%s was called for peer-group %s", __func__,
- peer->host);
+ flog_err(BGP_ERR_PEER_GROUP, "%s was called for peer-group %s",
+ __func__, peer->host);
return 1;
}
@@ -1936,8 +1931,9 @@ static int non_peergroup_deactivate_af(struct peer *peer, afi_t afi,
peer->afc[afi][safi] = 0;
if (peer_af_delete(peer, afi, safi) != 0) {
- zlog_err("couldn't delete af structure for peer %s",
- peer->host);
+ flog_err(BGP_ERR_PEER_DELETE,
+ "couldn't delete af structure for peer %s",
+ peer->host);
return 1;
}
@@ -1986,8 +1982,9 @@ int peer_deactivate(struct peer *peer, afi_t afi, safi_t safi)
group = peer->group;
if (peer_af_delete(peer, afi, safi) != 0) {
- zlog_err("couldn't delete af structure for peer %s",
- peer->host);
+ flog_err(BGP_ERR_PEER_DELETE,
+ "couldn't delete af structure for peer %s",
+ peer->host);
}
for (ALL_LIST_ELEMENTS(group->peer, node, nnode, tmp_peer)) {
diff --git a/bgpd/rfapi/rfapi.c b/bgpd/rfapi/rfapi.c
index a1f1169a7a..355cf92053 100644
--- a/bgpd/rfapi/rfapi.c
+++ b/bgpd/rfapi/rfapi.c
@@ -32,6 +32,7 @@
#include "lib/command.h"
#include "lib/stream.h"
#include "lib/ringbuf.h"
+#include "lib/lib_errors.h"
#include "bgpd/bgpd.h"
#include "bgpd/bgp_ecommunity.h"
@@ -3933,7 +3934,8 @@ void *rfapi_rfp_init_group_config_ptr_vty(void *rfp_start_val,
size);
break;
default:
- zlog_err("%s: Unknown group type=%d", __func__, type);
+ flog_err(LIB_ERR_DEVELOPMENT, "%s: Unknown group type=%d",
+ __func__, type);
/* should never happen */
assert("Unknown type" == NULL);
break;
@@ -4047,7 +4049,8 @@ void *rfapi_rfp_get_group_config_ptr_name(
criteria, search_cb);
break;
default:
- zlog_err("%s: Unknown group type=%d", __func__, type);
+ flog_err(LIB_ERR_DEVELOPMENT, "%s: Unknown group type=%d",
+ __func__, type);
/* should never happen */
assert("Unknown type" == NULL);
break;
diff --git a/bgpd/rfapi/rfapi_import.c b/bgpd/rfapi/rfapi_import.c
index c1af269d3f..ac3b6da230 100644
--- a/bgpd/rfapi/rfapi_import.c
+++ b/bgpd/rfapi/rfapi_import.c
@@ -34,6 +34,7 @@
#include "lib/skiplist.h"
#include "lib/thread.h"
#include "lib/stream.h"
+#include "lib/lib_errors.h"
#include "bgpd/bgpd.h"
#include "bgpd/bgp_ecommunity.h"
@@ -3028,7 +3029,7 @@ static void rfapiBgpInfoFilteredImportEncap(
break;
default:
- zlog_err("%s: bad afi %d", __func__, afi);
+ flog_err(LIB_ERR_DEVELOPMENT, "%s: bad afi %d", __func__, afi);
return;
}
@@ -3485,7 +3486,7 @@ void rfapiBgpInfoFilteredImportVPN(
break;
default:
- zlog_err("%s: bad afi %d", __func__, afi);
+ flog_err(LIB_ERR_DEVELOPMENT, "%s: bad afi %d", __func__, afi);
return;
}
@@ -3890,7 +3891,8 @@ rfapiBgpInfoFilteredImportFunction(safi_t safi)
default:
/* not expected */
- zlog_err("%s: bad safi %d", __func__, safi);
+ flog_err(LIB_ERR_DEVELOPMENT, "%s: bad safi %d", __func__,
+ safi);
return rfapiBgpInfoFilteredImportBadSafi;
}
}
diff --git a/bgpd/rfapi/vnc_export_bgp.c b/bgpd/rfapi/vnc_export_bgp.c
index d4dd34d1dd..69426670a1 100644
--- a/bgpd/rfapi/vnc_export_bgp.c
+++ b/bgpd/rfapi/vnc_export_bgp.c
@@ -33,6 +33,7 @@
#include "lib/linklist.h"
#include "lib/plist.h"
#include "lib/routemap.h"
+#include "lib/lib_errors.h"
#include "bgpd/bgpd.h"
#include "bgpd/bgp_ecommunity.h"
@@ -187,7 +188,8 @@ void vnc_direct_bgp_add_route_ce(struct bgp *bgp, struct route_node *rn,
if (!afi) {
- zlog_err("%s: can't get afi of route node", __func__);
+ flog_err(LIB_ERR_DEVELOPMENT,
+ "%s: can't get afi of route node", __func__);
return;
}
@@ -333,7 +335,7 @@ void vnc_direct_bgp_del_route_ce(struct bgp *bgp, struct route_node *rn,
struct prefix ce_nexthop;
if (!afi) {
- zlog_err("%s: bad afi", __func__);
+ flog_err(LIB_ERR_DEVELOPMENT, "%s: bad afi", __func__);
return;
}
@@ -698,7 +700,8 @@ void vnc_direct_bgp_add_prefix(struct bgp *bgp,
afi_t afi = family2afi(rn->p.family);
if (!afi) {
- zlog_err("%s: can't get afi of route node", __func__);
+ flog_err(LIB_ERR_DEVELOPMENT,
+ "%s: can't get afi of route node", __func__);
return;
}
@@ -807,7 +810,8 @@ void vnc_direct_bgp_del_prefix(struct bgp *bgp,
afi_t afi = family2afi(rn->p.family);
if (!afi) {
- zlog_err("%s: can't get afi route node", __func__);
+ flog_err(LIB_ERR_DEVELOPMENT, "%s: can't get afi route node",
+ __func__);
return;
}
@@ -922,7 +926,8 @@ void vnc_direct_bgp_add_nve(struct bgp *bgp, struct rfapi_descriptor *rfd)
afi_t afi = family2afi(rfd->vn_addr.addr_family);
if (!afi) {
- zlog_err("%s: can't get afi of nve vn addr", __func__);
+ flog_err(LIB_ERR_DEVELOPMENT,
+ "%s: can't get afi of nve vn addr", __func__);
return;
}
@@ -974,7 +979,8 @@ void vnc_direct_bgp_add_nve(struct bgp *bgp, struct rfapi_descriptor *rfd)
if (afi == AFI_IP || afi == AFI_IP6) {
rt = import_table->imported_vpn[afi];
} else {
- zlog_err("%s: bad afi %d", __func__, afi);
+ flog_err(LIB_ERR_DEVELOPMENT, "%s: bad afi %d",
+ __func__, afi);
return;
}
@@ -1066,7 +1072,8 @@ void vnc_direct_bgp_del_nve(struct bgp *bgp, struct rfapi_descriptor *rfd)
afi_t afi = family2afi(rfd->vn_addr.addr_family);
if (!afi) {
- zlog_err("%s: can't get afi of nve vn addr", __func__);
+ flog_err(LIB_ERR_DEVELOPMENT,
+ "%s: can't get afi of nve vn addr", __func__);
return;
}
@@ -1113,7 +1120,8 @@ void vnc_direct_bgp_del_nve(struct bgp *bgp, struct rfapi_descriptor *rfd)
if (afi == AFI_IP || afi == AFI_IP6) {
rt = import_table->imported_vpn[afi];
} else {
- zlog_err("%s: bad afi %d", __func__, afi);
+ flog_err(LIB_ERR_DEVELOPMENT, "%s: bad afi %d",
+ __func__, afi);
return;
}
@@ -1288,7 +1296,7 @@ static void vnc_direct_bgp_add_group_afi(struct bgp *bgp,
if (afi == AFI_IP || afi == AFI_IP6) {
rt = import_table->imported_vpn[afi];
} else {
- zlog_err("%s: bad afi %d", __func__, afi);
+ flog_err(LIB_ERR_DEVELOPMENT, "%s: bad afi %d", __func__, afi);
return;
}
@@ -1632,7 +1640,8 @@ void vnc_direct_bgp_rh_add_route(struct bgp *bgp, afi_t afi,
struct attr *iattr;
if (!afi) {
- zlog_err("%s: can't get afi of route node", __func__);
+ flog_err(LIB_ERR_DEVELOPMENT,
+ "%s: can't get afi of route node", __func__);
return;
}
@@ -1751,7 +1760,8 @@ void vnc_direct_bgp_rh_del_route(struct bgp *bgp, afi_t afi,
struct vnc_export_info *eti;
if (!afi) {
- zlog_err("%s: can't get afi route node", __func__);
+ flog_err(LIB_ERR_DEVELOPMENT, "%s: can't get afi route node",
+ __func__);
return;
}
diff --git a/bgpd/rfapi/vnc_import_bgp.c b/bgpd/rfapi/vnc_import_bgp.c
index 156572b57f..72363f7cfe 100644
--- a/bgpd/rfapi/vnc_import_bgp.c
+++ b/bgpd/rfapi/vnc_import_bgp.c
@@ -32,6 +32,7 @@
#include "lib/linklist.h"
#include "lib/plist.h"
#include "lib/routemap.h"
+#include "lib/lib_errors.h"
#include "bgpd/bgpd.h"
#include "bgpd/bgp_ecommunity.h"
@@ -602,7 +603,8 @@ static void vnc_import_bgp_add_route_mode_resolve_nve(
*/
if (!afi) {
- zlog_err("%s: can't get afi of prefix", __func__);
+ flog_err(LIB_ERR_DEVELOPMENT, "%s: can't get afi of prefix",
+ __func__);
return;
}
@@ -718,7 +720,8 @@ static void vnc_import_bgp_add_route_mode_plain(struct bgp *bgp,
}
if (!afi) {
- zlog_err("%s: can't get afi of prefix", __func__);
+ flog_err(LIB_ERR_DEVELOPMENT, "%s: can't get afi of prefix",
+ __func__);
return;
}
@@ -905,7 +908,8 @@ vnc_import_bgp_add_route_mode_nvegroup(struct bgp *bgp, struct prefix *prefix,
assert(rfg);
if (!afi) {
- zlog_err("%s: can't get afi of prefix", __func__);
+ flog_err(LIB_ERR_DEVELOPMENT, "%s: can't get afi of prefix",
+ __func__);
return;
}
@@ -2628,7 +2632,8 @@ void vnc_import_bgp_add_route(struct bgp *bgp, struct prefix *prefix,
VNC_RHNCK(enter);
if (!afi) {
- zlog_err("%s: can't get afi of prefix", __func__);
+ flog_err(LIB_ERR_DEVELOPMENT, "%s: can't get afi of prefix",
+ __func__);
return;
}
diff --git a/bgpd/rfapi/vnc_zebra.c b/bgpd/rfapi/vnc_zebra.c
index 7d564ef113..a2871188e6 100644
--- a/bgpd/rfapi/vnc_zebra.c
+++ b/bgpd/rfapi/vnc_zebra.c
@@ -32,6 +32,7 @@
#include "lib/stream.h"
#include "lib/ringbuf.h"
#include "lib/memory.h"
+#include "lib/lib_errors.h"
#include "bgpd/bgpd.h"
#include "bgpd/bgp_ecommunity.h"
@@ -570,7 +571,8 @@ static void vnc_zebra_add_del_prefix(struct bgp *bgp,
return;
if (rn->p.family != AF_INET && rn->p.family != AF_INET6) {
- zlog_err("%s: invalid route node addr family", __func__);
+ flog_err(LIB_ERR_DEVELOPMENT,
+ "%s: invalid route node addr family", __func__);
return;
}
@@ -642,7 +644,8 @@ static void vnc_zebra_add_del_nve(struct bgp *bgp, struct rfapi_descriptor *rfd,
return;
if (afi != AFI_IP && afi != AFI_IP6) {
- zlog_err("%s: invalid vn addr family", __func__);
+ flog_err(LIB_ERR_DEVELOPMENT, "%s: invalid vn addr family",
+ __func__);
return;
}
@@ -739,12 +742,13 @@ static void vnc_zebra_add_del_group_afi(struct bgp *bgp,
if (afi == AFI_IP || afi == AFI_IP6) {
rt = import_table->imported_vpn[afi];
} else {
- zlog_err("%s: bad afi %d", __func__, afi);
+ flog_err(LIB_ERR_DEVELOPMENT, "%s: bad afi %d", __func__, afi);
return;
}
if (!family) {
- zlog_err("%s: computed bad family: %d", __func__, family);
+ flog_err(LIB_ERR_DEVELOPMENT, "%s: computed bad family: %d",
+ __func__, family);
return;
}
diff --git a/configure.ac b/configure.ac
index 42c2963ee6..8d18817bd2 100755
--- a/configure.ac
+++ b/configure.ac
@@ -454,6 +454,8 @@ AC_ARG_ENABLE([numeric_version],
AS_HELP_STRING([--enable-numeric-version], [Only numeric digits allowed in version (for Alpine)]))
AC_ARG_ENABLE([gcov],
AS_HELP_STRING([--enable-gcov], [Add code coverage information]))
+AC_ARG_ENABLE(bfdd,
+ AS_HELP_STRING([--disable-bfdd], [do not build bfdd]))
AS_IF([test "${enable_clippy_only}" != "yes"], [
AC_CHECK_HEADERS(json-c/json.h)
@@ -1192,33 +1194,6 @@ case "$host_os" in
esac
AC_DEFINE_UNQUOTED(ISIS_METHOD, $ISIS_METHOD_MACRO, [ selected method for isis, == one of the constants ])
-dnl ------------------------------------
-dnl check for broken CMSG_FIRSTHDR macro
-dnl ------------------------------------
-AC_MSG_CHECKING(for broken CMSG_FIRSTHDR)
-AC_RUN_IFELSE([AC_LANG_SOURCE([[
-#ifdef SUNOS_5
-#define _XPG4_2
-#define __EXTENSIONS__
-#endif
-#include <stdlib.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-
-main()
-{
- struct msghdr msg;
- char buf[4];
-
- msg.msg_control = buf;
- msg.msg_controllen = 0;
-
- if (CMSG_FIRSTHDR(&msg) != NULL)
- exit(0);
- exit (1);
-}]])],[AC_MSG_RESULT(yes - using workaround) AC_DEFINE(HAVE_BROKEN_CMSG_FIRSTHDR,,Broken CMSG_FIRSTHDR)],
-[AC_MSG_RESULT(no)],[AC_MSG_RESULT(no)])
-
dnl ---------------------------------------------------------------
dnl figure out how to specify an interface in multicast sockets API
dnl ---------------------------------------------------------------
@@ -1370,6 +1345,30 @@ AS_IF([test "${enable_ldpd}" != "no"], [
AC_DEFINE(HAVE_LDPD, 1, ldpd)
])
+if test "$enable_bfdd" = "no"; then
+ AC_DEFINE(HAVE_BFDD, 0, bfdd)
+ BFDD=""
+else
+ AC_DEFINE(HAVE_BFDD, 1, bfdd)
+ BFDD="bfdd"
+
+ case $host_os in
+ linux*)
+ AC_DEFINE(BFD_LINUX, 1, bfdd)
+ ;;
+
+ *)
+ AC_DEFINE(BFD_BSD, 1, bfdd)
+ ;;
+ esac
+fi
+
+AM_CONDITIONAL(BFDD, [test "x$BFDD" = "xbfdd"])
+
+if test $ac_cv_lib_json_c_json_object_get = no -a "x$BFDD" = "xbfdd"; then
+ AC_MSG_ERROR(["you must use json-c library to use bfdd"])
+fi
+
NHRPD=""
case "$host_os" in
linux*)
@@ -1813,15 +1812,58 @@ dnl order to check no alternative allocator
dnl has been specified, which might not provide
dnl mallinfo, e.g. such as Umem on Solaris.
dnl -----------------------------------------
-AC_CHECK_HEADER([malloc.h],
- [AC_MSG_CHECKING(whether mallinfo is available)
- AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include <malloc.h>]],
- [[struct mallinfo ac_x; ac_x = mallinfo ();]])],
- [AC_MSG_RESULT(yes)
- AC_DEFINE(HAVE_MALLINFO,,mallinfo)],
- AC_MSG_RESULT(no)
- )
- ], [], FRR_INCLUDES)
+AC_CHECK_HEADERS([malloc.h malloc/malloc.h],,, [FRR_INCLUDES])
+
+AC_MSG_CHECKING(whether mallinfo is available)
+AC_LINK_IFELSE([AC_LANG_PROGRAM([FRR_INCLUDES [
+#ifdef HAVE_MALLOC_H
+#include <malloc.h>
+#endif
+#ifdef HAVE_MALLOC_MALLOC_H
+#include <malloc/malloc.h>
+#endif
+]], [[
+struct mallinfo ac_x; ac_x = mallinfo ();
+]])], [
+ AC_MSG_RESULT(yes)
+ AC_DEFINE(HAVE_MALLINFO,,mallinfo)
+], [
+ AC_MSG_RESULT(no)
+])
+
+AC_MSG_CHECKING(whether malloc_usable_size is available)
+AC_LINK_IFELSE([AC_LANG_PROGRAM([FRR_INCLUDES [
+#ifdef HAVE_MALLOC_H
+#include <malloc.h>
+#endif
+#ifdef HAVE_MALLOC_MALLOC_H
+#include <malloc/malloc.h>
+#endif
+]], [[
+size_t ac_x; ac_x = malloc_usable_size(NULL);
+]])], [
+ AC_MSG_RESULT(yes)
+ AC_DEFINE(HAVE_MALLOC_USABLE_SIZE,,malloc_usable_size)
+], [
+ AC_MSG_RESULT(no)
+
+ AC_MSG_CHECKING(whether malloc_size is available)
+ AC_LINK_IFELSE([AC_LANG_PROGRAM([[
+#ifdef HAVE_MALLOC_H
+#include <malloc.h>
+#endif
+#ifdef HAVE_MALLOC_MALLOC_H
+#include <malloc/malloc.h>
+#endif
+]], [[
+size_t ac_x; ac_x = malloc_size(NULL);
+]])], [
+ AC_MSG_RESULT(yes)
+ AC_DEFINE(HAVE_MALLOC_SIZE,,malloc_size)
+ ], [
+ AC_MSG_RESULT(no)
+ ])
+])
dnl ------
dnl ZeroMQ
@@ -1882,6 +1924,7 @@ 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)
dnl autoconf does this, but it does it too late...
diff --git a/debianpkg/backports/ubuntu12.04/debian/rules b/debianpkg/backports/ubuntu12.04/debian/rules
index 01ad81d371..3a6c80297e 100755
--- a/debianpkg/backports/ubuntu12.04/debian/rules
+++ b/debianpkg/backports/ubuntu12.04/debian/rules
@@ -134,6 +134,7 @@ override_dh_auto_configure:
--enable-poll=yes \
$(USE_CUMULUS) \
$(USE_PIM) \
+ --disable-bfdd \
--enable-dependency-tracking \
$(USE_BGP_VNC) \
$(shell dpkg-buildflags --export=configure); \
diff --git a/debianpkg/backports/ubuntu14.04/debian/rules b/debianpkg/backports/ubuntu14.04/debian/rules
index f7b9428658..f7468d6f79 100755
--- a/debianpkg/backports/ubuntu14.04/debian/rules
+++ b/debianpkg/backports/ubuntu14.04/debian/rules
@@ -16,6 +16,7 @@ WANT_CUMULUS_MODE ?= 0
WANT_MULTIPATH ?= 1
WANT_SNMP ?= 0
WANT_RPKI ?= 0
+WANT_BFD ?= 1
# NOTES:
#
@@ -108,6 +109,12 @@ else
USE_RPKI=--disable-rpki
endif
+ifeq ($(WANT_BFD), 1)
+ USE_BFD=--enable-bfdd
+else
+ USE_BFD=--disable-bfdd
+endif
+
ifneq (,$(filter parallel=%,$(DEB_BUILD_OPTIONS)))
DEBIAN_JOBS := $(subst parallel=,,$(filter parallel=%,$(DEB_BUILD_OPTIONS)))
endif
@@ -159,6 +166,7 @@ override_dh_auto_configure:
--enable-dependency-tracking \
$(USE_BGP_VNC) \
$(USE_RPKI) \
+ $(USE_BFD) \
$(shell dpkg-buildflags --export=configure); \
fi
diff --git a/debianpkg/rules b/debianpkg/rules
index 9c84c06516..c1cb865490 100755
--- a/debianpkg/rules
+++ b/debianpkg/rules
@@ -16,6 +16,7 @@ WANT_CUMULUS_MODE ?= 0
WANT_MULTIPATH ?= 1
WANT_SNMP ?= 0
WANT_RPKI ?= 0
+WANT_BFD ?= 1
# NOTES:
#
@@ -108,6 +109,12 @@ else
USE_RPKI=--disable-rpki
endif
+ifeq ($(WANT_BFD), 1)
+ USE_BFD=--enable-bfdd
+else
+ USE_BFD=--disable-bfdd
+endif
+
ifneq (,$(filter parallel=%,$(DEB_BUILD_OPTIONS)))
DEBIAN_JOBS := $(subst parallel=,,$(filter parallel=%,$(DEB_BUILD_OPTIONS)))
endif
@@ -160,6 +167,7 @@ override_dh_auto_configure:
--enable-dependency-tracking \
$(USE_BGP_VNC) \
$(USE_RPKI) \
+ $(USE_BFD) \
$(shell dpkg-buildflags --export=configure); \
fi
diff --git a/doc/Makefile.am b/doc/Makefile.am
index da8ac3d050..6f72585485 100644
--- a/doc/Makefile.am
+++ b/doc/Makefile.am
@@ -90,6 +90,10 @@ if STATICD
man_MANS += $(MANPAGE_BUILDDIR)/staticd.8
endif
+if BFDD
+man_MANS += $(MANPAGE_BUILDDIR)/bfdd.8
+endif
+
# Automake is particular about manpages. It is aware of them and has some
# special facilities for handling them, but it assumes that manpages are always
# given in groff source and so these facilities are limited to simply
@@ -159,6 +163,8 @@ EXTRA_DIST = frr-sphinx.mk \
manpages/vtysh.rst \
manpages/watchfrr.rst \
manpages/zebra.rst \
+ manpages/bfdd.rst \
+ manpages/bfd-options.rst \
developer/bgpd.rst \
developer/bgp-typecodes.rst \
developer/building-frr-on-alpine.rst \
@@ -234,6 +240,8 @@ EXTRA_DIST = frr-sphinx.mk \
user/vnc.rst \
user/vtysh.rst \
user/zebra.rst \
+ user/bfd.rst \
+ user/flowspec.rst \
mpls/ChangeLog.opaque.txt \
mpls/ospfd.conf \
mpls/cli_summary.txt \
diff --git a/doc/manpages/bfd-options.rst b/doc/manpages/bfd-options.rst
new file mode 100644
index 0000000000..e335ed120b
--- /dev/null
+++ b/doc/manpages/bfd-options.rst
@@ -0,0 +1,10 @@
+BFD SOCKET
+----------
+
+The following option controls the BFD daemon control socket location.
+
+.. option:: --bfdctl bfd-control-socket
+
+ Opens the BFD daemon control socket located at the pointed location.
+
+ (default: |INSTALL_PREFIX_STATE|/bfdd.sock)
diff --git a/doc/manpages/bfdd.rst b/doc/manpages/bfdd.rst
new file mode 100644
index 0000000000..1f8b1475f4
--- /dev/null
+++ b/doc/manpages/bfdd.rst
@@ -0,0 +1,40 @@
+****
+BFDD
+****
+
+.. include:: defines.rst
+.. |DAEMON| replace:: bfdd
+
+SYNOPSIS
+========
+|DAEMON| |synopsis-options-hv|
+
+|DAEMON| |synopsis-options|
+
+DESCRIPTION
+===========
+|DAEMON| is a communication failure detection component that works with
+the FRRouting routing engine.
+
+OPTIONS
+=======
+OPTIONS available for the |DAEMON| command:
+
+.. include:: common-options.rst
+.. include:: bfd-options.rst
+
+FILES
+=====
+
+|INSTALL_PREFIX_SBIN|/|DAEMON|
+ The default location of the |DAEMON| binary.
+
+|INSTALL_PREFIX_ETC|/|DAEMON|.conf
+ The default location of the |DAEMON| config file.
+
+$(PWD)/|DAEMON|.log
+ If the |DAEMON| process is configured to output logs to a file, then you
+ will find this file in the directory where you started |DAEMON|.
+
+.. include:: epilogue.rst
+
diff --git a/doc/manpages/common-options.rst b/doc/manpages/common-options.rst
index 1b2eb18dea..1e99010505 100644
--- a/doc/manpages/common-options.rst
+++ b/doc/manpages/common-options.rst
@@ -124,6 +124,7 @@ These following options control the daemon's VTY (interactive command line) inte
eigrpd 2613
pbrd 2615
staticd 2616
+ bfdd 2617
Port 2607 is used for ospfd's Opaque LSA API, while port 2600 is used for the (insecure) TCP-ZEBRA interface.
diff --git a/doc/manpages/conf.py b/doc/manpages/conf.py
index 4d5797f613..e540d236ea 100644
--- a/doc/manpages/conf.py
+++ b/doc/manpages/conf.py
@@ -332,6 +332,7 @@ man_pages = [
('watchfrr', 'watchfrr', 'a program to monitor the status of FRRouting daemons', [], 8),
('vtysh', 'vtysh', 'an integrated shell for FRRouting.', [], 1),
('frr', 'frr', 'a systemd interaction script', [], 1),
+ ('bfdd', 'bfdd', fwfrr.format("a bfd"), [], 8),
]
# -- Options for Texinfo output -------------------------------------------
diff --git a/doc/user/basic.rst b/doc/user/basic.rst
index cb46080055..da22bb2f86 100644
--- a/doc/user/basic.rst
+++ b/doc/user/basic.rst
@@ -320,6 +320,67 @@ Terminal Mode Commands
Shows the current configuration of the logging system. This includes the
status of all logging destinations.
+.. index:: show memory
+.. clicmd:: show memory
+
+ Show information on how much memory is used for which specific things in
+ |PACKAGE_NAME|. Output may vary depending on system capabilities but will
+ generally look something like this:
+
+ ::
+
+ frr# show memory
+ System allocator statistics:
+ Total heap allocated: 1584 KiB
+ Holding block headers: 0 bytes
+ Used small blocks: 0 bytes
+ Used ordinary blocks: 1484 KiB
+ Free small blocks: 2096 bytes
+ Free ordinary blocks: 100 KiB
+ Ordinary blocks: 2
+ Small blocks: 60
+ Holding blocks: 0
+ (see system documentation for 'mallinfo' for meaning)
+ --- qmem libfrr ---
+ Buffer : 3 24 72
+ Buffer data : 1 4120 4120
+ Host config : 3 (variably sized) 72
+ Command Tokens : 3427 72 247160
+ Command Token Text : 2555 (variably sized) 83720
+ Command Token Help : 2555 (variably sized) 61720
+ Command Argument : 2 (variably sized) 48
+ Command Argument Name : 641 (variably sized) 15672
+ [...]
+ --- qmem Label Manager ---
+ --- qmem zebra ---
+ ZEBRA VRF : 1 912 920
+ Route Entry : 11 80 968
+ Static route : 1 192 200
+ RIB destination : 8 48 448
+ RIB table info : 4 16 96
+ Nexthop tracking object : 1 200 200
+ Zebra Name Space : 1 312 312
+ --- qmem Table Manager ---
+
+ To understand system allocator statistics, refer to your system's
+ :manpage:`mallinfo(3)` man page.
+
+ Below these statistics, statistics on individual memory allocation types
+ in |PACKAGE_NAME| (so-called `MTYPEs`) is printed:
+
+ * the first column of numbers is the current count of allocations made for
+ the type (the number decreases when items are freed.)
+ * the second column is the size of each item. This is only available if
+ allocations on a type are always made with the same size.
+ * the third column is the total amount of memory allocated for the
+ particular type, including padding applied by malloc. This means that
+ the number may be larger than the first column multiplied by the second.
+ Overhead incurred by malloc's bookkeeping is not included in this, and
+ the column may be missing if system support is not available.
+
+ When executing this command from ``vtysh``, each of the daemons' memory
+ usage is printed sequentially.
+
.. index:: logmsg LEVEL MESSAGE
.. clicmd:: logmsg LEVEL MESSAGE
diff --git a/doc/user/bfd.rst b/doc/user/bfd.rst
new file mode 100644
index 0000000000..0e0fd23ece
--- /dev/null
+++ b/doc/user/bfd.rst
@@ -0,0 +1,302 @@
+.. _bfd:
+
+**********************************
+Bidirectional Forwarding Detection
+**********************************
+
+:abbr:`BFD (Bidirectional Forwarding Detection)` stands for
+Bidirectional Forwarding Detection and it is described and extended by
+the following RFCs:
+
+* :rfc:`5880`
+* :rfc:`5881`
+* :rfc:`5883`
+
+Currently, there are two implementations of the BFD commands in FRR:
+
+* :abbr:`PTM (Prescriptive Topology Manager)`: an external daemon which
+ implements BFD;
+* ``bfdd``: a BFD implementation that is able to talk with remote peers;
+
+This document will focus on the later implementation: *bfdd*.
+
+
+.. _bfd-starting:
+
+Starting BFD
+============
+
+*bfdd* default configuration file is :file:`bfdd.conf`. *bfdd* searches
+the current directory first then |INSTALL_PREFIX_ETC|/bfdd.conf. All of
+*bfdd*'s command must be configured in :file:`bfdd.conf`.
+
+*bfdd* specific invocation options are described below. Common options
+may also be specified (:ref:`common-invocation-options`).
+
+.. program:: bfdd
+
+.. option:: --bfdctl <unix-socket>
+
+ Set the BFD daemon control socket location. If using a non-default
+ socket location.
+
+ /usr/lib/frr/bfdd --bfdctl /tmp/bfdd.sock
+
+
+ The default UNIX socket location is:
+
+ #define BFDD_CONTROL_SOCKET "|INSTALL_PREFIX_STATE|/bfdd.sock"
+
+
+.. _bfd-commands:
+
+BFDd Commands
+=============
+
+.. index:: bfd
+.. clicmd:: bfd
+
+ Opens the BFD daemon configuration node.
+
+.. index:: peer <A.B.C.D|X:X::X:X> [{multihop|local-address <A.B.C.D|X:X::X:X>|interface IFNAME|vrf NAME}]
+.. clicmd:: peer <A.B.C.D|X:X::X:X> [{multihop|local-address <A.B.C.D|X:X::X:X>|interface IFNAME|vrf NAME}]
+
+ Creates and configures a new BFD peer to listen and talk to.
+
+ `multihop` tells the BFD daemon that we should expect packets with
+ TTL less than 254 (because it will take more than one hop) and to
+ listen on the multihop port (4784). When using multi-hop mode
+ `echo-mode` will not work (see :rfc:`5883` section 3).
+
+ `local-address` provides a local address that we should bind our
+ peer listener to and the address we should use to send the packets.
+ This option is mandatory for IPv6.
+
+ `interface` selects which interface we should use. This option
+ conflicts with `vrf`.
+
+ `vrf` selects which domain we want to use.
+
+.. index:: no peer <A.B.C.D|X:X::X:X>$peer [{multihop|local-address <A.B.C.D|X:X::X:X>$local|interface IFNAME$ifname|vrf NAME$vrfname}]
+.. clicmd:: no peer <A.B.C.D|X:X::X:X>$peer [{multihop|local-address <A.B.C.D|X:X::X:X>$local|interface IFNAME$ifname|vrf NAME$vrfname}]
+
+ Stops and removes the selected peer.
+
+.. index:: show bfd peers [json]
+.. clicmd:: show bfd peers [json]
+
+ Show all configured BFD peers information and current status.
+
+.. index:: show bfd peer <WORD$label|<A.B.C.D|X:X::X:X>$peer [{multihop|local-address <A.B.C.D|X:X::X:X>$local|interface IFNAME$ifname|vrf NAME$vrfname}]> [json]
+.. clicmd:: show bfd peer <WORD$label|<A.B.C.D|X:X::X:X>$peer [{multihop|local-address <A.B.C.D|X:X::X:X>$local|interface IFNAME$ifname|vrf NAME$vrfname}]> [json]
+
+ Show status for a specific BFD peer.
+
+
+.. _bfd-peer-config:
+
+Peer Configurations
+-------------------
+
+.. index:: detect-multiplier (2-255)
+.. clicmd:: detect-multiplier (2-255)
+
+ Configures the detection multiplier to determine packet loss. The
+ remote transmission interval will be multiplied by this value to
+ determine the connection loss detection timer. The default value is
+ 3.
+
+ Example: when the local system has `detect-multiplier 3` and the
+ remote system has `transmission interval 300`, the local system will
+ detect failures only after 900 milliseconds without receiving
+ packets.
+
+.. index:: receive-interval (10-60000)
+.. clicmd:: receive-interval (10-60000)
+
+ Configures the minimum interval that this system is capable of
+ receiving control packets. The default value is 300 milliseconds.
+
+.. index:: transmit-interval (10-60000)
+.. clicmd:: transmit-interval (10-60000)
+
+ The minimum transmission interval (less jitter) that this system
+ wants to use to send BFD control packets.
+
+.. index:: echo-interval (10-60000)
+.. clicmd:: echo-interval (10-60000)
+
+ Configures the minimal echo receive transmission interval that this
+ system is capable of handling.
+
+.. index:: [no] echo-mode
+.. clicmd:: [no] echo-mode
+
+ Enables or disables the echo transmission mode. This mode is disabled
+ by default.
+
+ It is recommended that the transmission interval of control packets
+ to be increased after enabling echo-mode to reduce bandwidth usage.
+ For example: `transmission-interval 2000`.
+
+ Echo mode is not supported on multi-hop setups (see :rfc:`5883`
+ section 3).
+
+.. index:: [no] shutdown
+.. clicmd:: [no] shutdown
+
+ Enables or disables the peer. When the peer is disabled an
+ 'administrative down' message is sent to the remote peer.
+
+.. index:: label WORD
+.. clicmd:: label WORD
+
+ Labels a peer with the provided word. This word can be referenced
+ later on other daemons to refer to a specific peer.
+
+
+.. _bfd-bgp-peer-config:
+
+BGP BFD Configuration
+---------------------
+
+.. index:: neighbor <A.B.C.D|X:X::X:X|WORD> bfd
+.. clicmd:: neighbor <A.B.C.D|X:X::X:X|WORD> bfd
+
+ Listen for BFD events registered on the same target as this BGP
+ neighbor. When BFD peer goes down it immediately asks BGP to shutdown
+ the connection with its neighbor and, when it goes back up, notify
+ BGP to try to connect to it.
+
+.. index:: no neighbor <A.B.C.D|X:X::X:X|WORD> bfd
+.. clicmd:: no neighbor <A.B.C.D|X:X::X:X|WORD> bfd
+
+ Removes any notification registration for this neighbor.
+
+
+.. _bfd-configuration:
+
+Configuration
+=============
+
+Before applying ``bfdd`` rules to integrated daemons (like BGPd), we must
+create the corresponding peers inside the ``bfd`` configuration node.
+
+Here is an example of BFD configuration:
+
+::
+
+ bfd
+ peer 192.168.0.1
+ label home-peer
+ no shutdown
+ !
+ !
+ router bgp 65530
+ neighbor 192.168.0.1 remote-as 65531
+ neighbor 192.168.0.1 bfd
+ neighbor 192.168.0.2 remote-as 65530
+ neighbor 192.168.0.2 bfd
+ neighbor 192.168.0.3 remote-as 65532
+ neighbor 192.168.0.3 bfd
+ !
+
+Peers can be identified by its address (use ``multihop`` when you need
+to specify a multi hop peer) or can be specified manually by a label.
+
+Here are the available peer configurations:
+
+::
+
+ bfd
+
+ ! configure a peer on an specific interface
+ peer 192.168.0.1 interface eth0
+ no shutdown
+ !
+
+ ! configure a multihop peer
+ peer 192.168.0.2 multihop local-address 192.168.0.3
+ shutdown
+ !
+
+ ! configure a peer in a different vrf
+ peer 192.168.0.3 vrf foo
+ shutdown
+ !
+
+ ! configure a peer with every option possible
+ peer 192.168.0.4
+ label peer-label
+ detect-multiplier 50
+ receive-interval 60000
+ transmit-interval 3000
+ shutdown
+ !
+
+ ! remove a peer
+ no peer 192.168.0.3 vrf foo
+
+
+.. _bfd-status:
+
+Status
+======
+
+You can inspect the current BFD peer status with the following commands:
+
+::
+
+ frr# show bfd peers
+ BFD Peers:
+ peer 192.168.0.1
+ ID: 1
+ Remote ID: 1
+ Status: up
+ Uptime: 1 minute(s), 51 second(s)
+ Diagnostics: ok
+ Remote diagnostics: ok
+ Local timers:
+ Receive interval: 300ms
+ Transmission interval: 300ms
+ Echo transmission interval: disabled
+ Remote timers:
+ Receive interval: 300ms
+ Transmission interval: 300ms
+ Echo transmission interval: 50ms
+
+ peer 192.168.1.1
+ label: router3-peer
+ ID: 2
+ Remote ID: 2
+ Status: up
+ Uptime: 1 minute(s), 53 second(s)
+ Diagnostics: ok
+ Remote diagnostics: ok
+ Local timers:
+ Receive interval: 300ms
+ Transmission interval: 300ms
+ Echo transmission interval: disabled
+ Remote timers:
+ Receive interval: 300ms
+ Transmission interval: 300ms
+ Echo transmission interval: 50ms
+
+ frr# show bfd peer 192.168.1.1
+ BFD Peer:
+ peer 192.168.1.1
+ label: router3-peer
+ ID: 2
+ Remote ID: 2
+ Status: up
+ Uptime: 3 minute(s), 4 second(s)
+ Diagnostics: ok
+ Remote diagnostics: ok
+ Local timers:
+ Receive interval: 300ms
+ Transmission interval: 300ms
+ Echo transmission interval: disabled
+ Remote timers:
+ Receive interval: 300ms
+ Transmission interval: 300ms
+ Echo transmission interval: 50ms
diff --git a/doc/user/bgp.rst b/doc/user/bgp.rst
index 734c9cabd0..f1209c2172 100644
--- a/doc/user/bgp.rst
+++ b/doc/user/bgp.rst
@@ -879,6 +879,14 @@ Peer Filtering
Peer Groups
^^^^^^^^^^^
+Peer groups are used to help improve scaling by generating the same
+update information to all members of a peer group. Note that this means
+that the routes generated by a member of a peer group will be sent back
+to that originating peer with the originator identifier attribute set to
+indicated the originating peer. All peers not associated with a
+specific peer group are treated as belonging to a default peer group,
+and will share updates.
+
.. index:: neighbor WORD peer-group
.. clicmd:: neighbor WORD peer-group
@@ -889,6 +897,13 @@ Peer Groups
This command bind specific peer to peer group WORD.
+.. index:: neighbor PEER solo
+.. clicmd:: neighbor PEER solo
+
+ This command is used to indicate that routes advertised by the peer
+ should not be reflected back to the peer. This command only is only
+ meaningful when there is a single peer defined in the peer-group.
+
Capability Negotiation
^^^^^^^^^^^^^^^^^^^^^^
diff --git a/doc/user/index.rst b/doc/user/index.rst
index 14688e05d8..5818551343 100644
--- a/doc/user/index.rst
+++ b/doc/user/index.rst
@@ -39,6 +39,7 @@ Protocols
:maxdepth: 2
zebra
+ bfd
bgp
babeld
ldpd
diff --git a/doc/user/installation.rst b/doc/user/installation.rst
index 158e2c8595..3da5a6cd30 100644
--- a/doc/user/installation.rst
+++ b/doc/user/installation.rst
@@ -103,6 +103,10 @@ options from the list below.
Do not build bgpd.
+.. option:: --disable-bfdd
+
+ Do not build bfdd.
+
.. option:: --disable-bgp-announce
Make *bgpd* which does not make bgp announcements at all. This
diff --git a/doc/user/overview.rst b/doc/user/overview.rst
index 4886b57594..369f17dcba 100644
--- a/doc/user/overview.rst
+++ b/doc/user/overview.rst
@@ -245,6 +245,14 @@ FRR implements the following RFCs:
- :rfc:`7552`
:t:`Updates to LDP for IPv6, R. Asati, C. Pignataro, K. Raza, V. Manral,
and R. Papneja. June 2015.`
+- :rfc:`5880`
+ :t:`Bidirectional Forwarding Detection (BFD), D. Katz, D. Ward. June 2010`
+- :rfc:`5881`
+ :t:`Bidirectional Forwarding Detection (BFD) for IPv4 and IPv6 (Single Hop),
+ D. Katz, D. Ward. June 2010`
+- :rfc:`5883`
+ :t:`Bidirectional Forwarding Detection (BFD) for Multihop Paths, D. Katz,
+ D. Ward. June 2010`
**When SNMP support is enabled, the following RFCs are also supported:**
diff --git a/doc/user/setup.rst b/doc/user/setup.rst
index e9fd44a347..68ce14982b 100644
--- a/doc/user/setup.rst
+++ b/doc/user/setup.rst
@@ -31,6 +31,7 @@ systemd. The file initially looks like this:
sharpd=no
staticd=no
pbrd=no
+ bfdd=no
To enable a particular daemon, simply change the corresponding 'no' to 'yes'.
Subsequent service restarts should start the daemon.
@@ -66,6 +67,7 @@ This file has several parts. Here is an example:
sharpd_options=" --daemon -A 127.0.0.1"
staticd_options=" --daemon -A 127.0.0.1"
pbrd_options=" --daemon -A 127.0.0.1"
+ bfdd_options=" --daemon -A 127.0.0.1"
# The list of daemons to watch is automatically generated by the init script.
watchfrr_enable=yes
@@ -136,6 +138,7 @@ add the following entries to :file:`/etc/services`.
pimd 2611/tcp # PIMd vty
ldpd 2612/tcp # LDPd vty
eigprd 2613/tcp # EIGRPd vty
+ bfdd 2617/tcp # bfdd vty
If you use a FreeBSD newer than 2.2.8, the above entries are already added to
diff --git a/eigrpd/eigrp_errors.c b/eigrpd/eigrp_errors.c
new file mode 100644
index 0000000000..3db0ec8545
--- /dev/null
+++ b/eigrpd/eigrp_errors.c
@@ -0,0 +1,49 @@
+/*
+ * EIGRP-specific error messages.
+ * Copyright (C) 2018 Cumulus Networks, Inc.
+ * Donald Sharp
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This 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 "lib/ferr.h"
+#include "eigrp_errors.h"
+
+/* clang-format off */
+static struct log_ref ferr_eigrp_err[] = {
+ {
+ .code = EIGRP_ERR_PACKET,
+ .title = "EIGRP Packet Error",
+ .description = "EIGRP has a packet that does not correctly decode or encode",
+ .suggestion = "Gather log files from both sides of the neighbor relationship and open an issue"
+ },
+ {
+ .code = EIGRP_ERR_CONFIG,
+ .title = "EIGRP Configuration Error",
+ .description = "EIGRP has detected a configuration error",
+ .suggestion = "Correct the configuration issue, if it still persists open an Issue"
+ },
+ {
+ .code = END_FERR,
+ }
+};
+/* clang-format on */
+
+void eigrp_error_init(void)
+{
+ log_ref_add(ferr_eigrp_err);
+}
diff --git a/eigrpd/eigrp_errors.h b/eigrpd/eigrp_errors.h
new file mode 100644
index 0000000000..e1ace8ab49
--- /dev/null
+++ b/eigrpd/eigrp_errors.h
@@ -0,0 +1,33 @@
+/*
+ * EIGRP-specific error messages.
+ * Copyright (C) 2018 Cumulus Networks, Inc.
+ * Donald Sharp
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; see the file COPYING; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef __EIGRP_ERRORS_H__
+#define __EIGRP_ERRORS_H__
+
+#include "lib/ferr.h"
+
+enum eigrp_log_refs {
+ EIGRP_ERR_PACKET = EIGRP_FERR_START,
+ EIGRP_ERR_CONFIG,
+};
+
+extern void eigrp_error_init(void);
+
+#endif
diff --git a/eigrpd/eigrp_hello.c b/eigrpd/eigrp_hello.c
index 2e55d57c31..d438db28d6 100644
--- a/eigrpd/eigrp_hello.c
+++ b/eigrpd/eigrp_hello.c
@@ -54,6 +54,7 @@
#include "eigrpd/eigrp_vty.h"
#include "eigrpd/eigrp_dump.h"
#include "eigrpd/eigrp_macros.h"
+#include "eigrpd/eigrp_errors.h"
/* Packet Type String. */
static const struct message eigrp_general_tlv_type_str[] = {
@@ -420,8 +421,9 @@ void eigrp_sw_version_initialize(void)
ret = sscanf(ver_string, "%" SCNu32 ".%" SCNu32, &FRR_MAJOR,
&FRR_MINOR);
if (ret != 2)
- zlog_err("Did not Properly parse %s, please fix VERSION string",
- VERSION);
+ flog_err(EIGRP_ERR_PACKET,
+ "Did not Properly parse %s, please fix VERSION string",
+ VERSION);
}
/**
diff --git a/eigrpd/eigrp_main.c b/eigrpd/eigrp_main.c
index c4ca07178c..31101a52d4 100644
--- a/eigrpd/eigrp_main.c
+++ b/eigrpd/eigrp_main.c
@@ -64,6 +64,7 @@
#include "eigrpd/eigrp_network.h"
#include "eigrpd/eigrp_snmp.h"
#include "eigrpd/eigrp_filter.h"
+#include "eigrpd/eigrp_errors.h"
//#include "eigrpd/eigrp_routemap.h"
/* eigprd privileges */
@@ -168,6 +169,7 @@ int main(int argc, char **argv, char **envp)
eigrp_om->master = frr_init();
master = eigrp_om->master;
+ eigrp_error_init();
vrf_init(NULL, NULL, NULL, NULL);
/*EIGRPd init*/
diff --git a/eigrpd/eigrp_neighbor.c b/eigrpd/eigrp_neighbor.c
index 3bf75072a3..b10673d9e4 100644
--- a/eigrpd/eigrp_neighbor.c
+++ b/eigrpd/eigrp_neighbor.c
@@ -53,6 +53,7 @@
#include "eigrpd/eigrp_network.h"
#include "eigrpd/eigrp_topology.h"
#include "eigrpd/eigrp_memory.h"
+#include "eigrpd/eigrp_errors.h"
struct eigrp_neighbor *eigrp_nbr_new(struct eigrp_interface *ei)
{
@@ -335,7 +336,8 @@ int eigrp_nbr_count_get(void)
void eigrp_nbr_hard_restart(struct eigrp_neighbor *nbr, struct vty *vty)
{
if (nbr == NULL) {
- zlog_err("Nbr Hard restart: Neighbor not specified.");
+ flog_err(EIGRP_ERR_CONFIG,
+ "Nbr Hard restart: Neighbor not specified.");
return;
}
diff --git a/eigrpd/eigrp_network.c b/eigrpd/eigrp_network.c
index 629beddec3..8eaf1e82a3 100644
--- a/eigrpd/eigrp_network.c
+++ b/eigrpd/eigrp_network.c
@@ -37,6 +37,7 @@
#include "privs.h"
#include "table.h"
#include "vty.h"
+#include "lib_errors.h"
#include "eigrpd/eigrp_structs.h"
#include "eigrpd/eigrpd.h"
@@ -60,60 +61,42 @@ int eigrp_sock_init(void)
int hincl = 1;
#endif
- if (eigrpd_privs.change(ZPRIVS_RAISE))
- zlog_err("eigrp_sock_init: could not raise privs, %s",
- safe_strerror(errno));
-
- eigrp_sock = socket(AF_INET, SOCK_RAW, IPPROTO_EIGRPIGP);
- if (eigrp_sock < 0) {
- int save_errno = errno;
- if (eigrpd_privs.change(ZPRIVS_LOWER))
- zlog_err("eigrp_sock_init: could not lower privs, %s",
+ frr_elevate_privs(&eigrpd_privs) {
+ eigrp_sock = socket(AF_INET, SOCK_RAW, IPPROTO_EIGRPIGP);
+ if (eigrp_sock < 0) {
+ zlog_err("eigrp_read_sock_init: socket: %s",
safe_strerror(errno));
- zlog_err("eigrp_read_sock_init: socket: %s",
- safe_strerror(save_errno));
- exit(1);
- }
+ exit(1);
+ }
#ifdef IP_HDRINCL
- /* we will include IP header with packet */
- ret = setsockopt(eigrp_sock, IPPROTO_IP, IP_HDRINCL, &hincl,
- sizeof(hincl));
- if (ret < 0) {
- int save_errno = errno;
- if (eigrpd_privs.change(ZPRIVS_LOWER))
- zlog_err("eigrp_sock_init: could not lower privs, %s",
- safe_strerror(errno));
- zlog_warn("Can't set IP_HDRINCL option for fd %d: %s",
- eigrp_sock, safe_strerror(save_errno));
- }
+ /* we will include IP header with packet */
+ ret = setsockopt(eigrp_sock, IPPROTO_IP, IP_HDRINCL, &hincl,
+ sizeof(hincl));
+ if (ret < 0) {
+ zlog_warn("Can't set IP_HDRINCL option for fd %d: %s",
+ eigrp_sock, safe_strerror(errno));
+ }
#elif defined(IPTOS_PREC_INTERNETCONTROL)
#warning "IP_HDRINCL not available on this system"
#warning "using IPTOS_PREC_INTERNETCONTROL"
- ret = setsockopt_ipv4_tos(eigrp_sock, IPTOS_PREC_INTERNETCONTROL);
- if (ret < 0) {
- int save_errno = errno;
- if (eigrpd_privs.change(ZPRIVS_LOWER))
- zlog_err("eigrpd_sock_init: could not lower privs, %s",
- safe_strerror(errno));
- zlog_warn("can't set sockopt IP_TOS %d to socket %d: %s", tos,
- eigrp_sock, safe_strerror(save_errno));
- close(eigrp_sock); /* Prevent sd leak. */
- return ret;
- }
+ ret = setsockopt_ipv4_tos(eigrp_sock,
+ IPTOS_PREC_INTERNETCONTROL);
+ if (ret < 0) {
+ zlog_warn("can't set sockopt IP_TOS %d to socket %d: %s",
+ tos, eigrp_sock, safe_strerror(errno));
+ close(eigrp_sock); /* Prevent sd leak. */
+ return ret;
+ }
#else /* !IPTOS_PREC_INTERNETCONTROL */
#warning "IP_HDRINCL not available, nor is IPTOS_PREC_INTERNETCONTROL"
- zlog_warn("IP_HDRINCL option not available");
+ zlog_warn("IP_HDRINCL option not available");
#endif /* IP_HDRINCL */
- ret = setsockopt_ifindex(AF_INET, eigrp_sock, 1);
-
- if (ret < 0)
- zlog_warn("Can't set pktinfo option for fd %d", eigrp_sock);
-
- if (eigrpd_privs.change(ZPRIVS_LOWER)) {
- zlog_err("eigrp_sock_init: could not lower privs, %s",
- safe_strerror(errno));
+ ret = setsockopt_ifindex(AF_INET, eigrp_sock, 1);
+ if (ret < 0)
+ zlog_warn("Can't set pktinfo option for fd %d",
+ eigrp_sock);
}
return eigrp_sock;
@@ -125,9 +108,7 @@ void eigrp_adjust_sndbuflen(struct eigrp *eigrp, unsigned int buflen)
/* Check if any work has to be done at all. */
if (eigrp->maxsndbuflen >= buflen)
return;
- if (eigrpd_privs.change(ZPRIVS_RAISE))
- zlog_err("%s: could not raise privs, %s", __func__,
- safe_strerror(errno));
+ frr_elevate_privs(&eigrpd_privs) {
/* Now we try to set SO_SNDBUF to what our caller has requested
* (the MTU of a newly added interface). However, if the OS has
@@ -136,18 +117,16 @@ void eigrp_adjust_sndbuflen(struct eigrp *eigrp, unsigned int buflen)
* may allocate more buffer space, than requested, this isn't
* a error.
*/
- setsockopt_so_sendbuf(eigrp->fd, buflen);
- newbuflen = getsockopt_so_sendbuf(eigrp->fd);
- if (newbuflen < 0 || newbuflen < (int)buflen)
- zlog_warn("%s: tried to set SO_SNDBUF to %u, but got %d",
- __func__, buflen, newbuflen);
- if (newbuflen >= 0)
- eigrp->maxsndbuflen = (unsigned int)newbuflen;
- else
- zlog_warn("%s: failed to get SO_SNDBUF", __func__);
- if (eigrpd_privs.change(ZPRIVS_LOWER))
- zlog_err("%s: could not lower privs, %s", __func__,
- safe_strerror(errno));
+ setsockopt_so_sendbuf(eigrp->fd, buflen);
+ newbuflen = getsockopt_so_sendbuf(eigrp->fd);
+ if (newbuflen < 0 || newbuflen < (int)buflen)
+ zlog_warn("%s: tried to set SO_SNDBUF to %u, but got %d",
+ __func__, buflen, newbuflen);
+ if (newbuflen >= 0)
+ eigrp->maxsndbuflen = (unsigned int)newbuflen;
+ else
+ zlog_warn("%s: failed to get SO_SNDBUF", __func__);
+ }
}
int eigrp_if_ipmulticast(struct eigrp *top, struct prefix *p,
diff --git a/eigrpd/eigrp_packet.c b/eigrpd/eigrp_packet.c
index 027f30563f..6338e5cf74 100644
--- a/eigrpd/eigrp_packet.c
+++ b/eigrpd/eigrp_packet.c
@@ -42,6 +42,7 @@
#include "checksum.h"
#include "md5.h"
#include "sha256.h"
+#include "lib_errors.h"
#include "eigrpd/eigrp_structs.h"
#include "eigrpd/eigrpd.h"
@@ -56,6 +57,7 @@
#include "eigrpd/eigrp_topology.h"
#include "eigrpd/eigrp_fsm.h"
#include "eigrpd/eigrp_memory.h"
+#include "eigrpd/eigrp_errors.h"
/* Packet Type String. */
const struct message eigrp_packet_type_str[] = {
@@ -346,12 +348,14 @@ int eigrp_write(struct thread *thread)
/* Get one packet from queue. */
ep = eigrp_fifo_next(ei->obuf);
if (!ep) {
- zlog_err("%s: Interface %s no packet on queue?",
- __PRETTY_FUNCTION__, ei->ifp->name);
+ flog_err(LIB_ERR_DEVELOPMENT,
+ "%s: Interface %s no packet on queue?",
+ __PRETTY_FUNCTION__, ei->ifp->name);
goto out;
}
if (ep->length < EIGRP_HEADER_LEN) {
- zlog_err("%s: Packet just has a header?", __PRETTY_FUNCTION__);
+ flog_err(EIGRP_ERR_PACKET,
+ "%s: Packet just has a header?", __PRETTY_FUNCTION__);
eigrp_header_dump((struct eigrp_header *)ep->s->data);
eigrp_packet_delete(ei);
goto out;
@@ -1210,8 +1214,9 @@ uint16_t eigrp_add_internalTLV_to_stream(struct stream *s,
stream_putw(s, length);
break;
default:
- zlog_err("%s: Unexpected prefix length: %d",
- __PRETTY_FUNCTION__, pe->destination->prefixlen);
+ flog_err(LIB_ERR_DEVELOPMENT,
+ "%s: Unexpected prefix length: %d",
+ __PRETTY_FUNCTION__, pe->destination->prefixlen);
return 0;
}
stream_putl(s, 0x00000000);
diff --git a/eigrpd/eigrp_reply.c b/eigrpd/eigrp_reply.c
index b7490cd492..b6e6352def 100644
--- a/eigrpd/eigrp_reply.c
+++ b/eigrpd/eigrp_reply.c
@@ -59,6 +59,7 @@
#include "eigrpd/eigrp_topology.h"
#include "eigrpd/eigrp_fsm.h"
#include "eigrpd/eigrp_memory.h"
+#include "eigrpd/eigrp_errors.h"
void eigrp_send_reply(struct eigrp_neighbor *nbr, struct eigrp_prefix_entry *pe)
{
@@ -169,10 +170,10 @@ void eigrp_reply_receive(struct eigrp *eigrp, struct ip *iph,
if (!dest) {
char buf[PREFIX_STRLEN];
- zlog_err(
- "%s: Received prefix %s which we do not know about",
- __PRETTY_FUNCTION__,
- prefix2str(&dest_addr, buf, sizeof(buf)));
+ flog_err(EIGRP_ERR_PACKET,
+ "%s: Received prefix %s which we do not know about",
+ __PRETTY_FUNCTION__,
+ prefix2str(&dest_addr, buf, sizeof(buf)));
eigrp_IPv4_InternalTLV_free(tlv);
continue;
}
diff --git a/eigrpd/eigrp_topology.c b/eigrpd/eigrp_topology.c
index 8ca0e282a8..61eee99f6a 100644
--- a/eigrpd/eigrp_topology.c
+++ b/eigrpd/eigrp_topology.c
@@ -37,6 +37,7 @@
#include "log.h"
#include "linklist.h"
#include "vty.h"
+#include "lib_errors.h"
#include "eigrpd/eigrp_structs.h"
#include "eigrpd/eigrpd.h"
@@ -411,7 +412,8 @@ eigrp_topology_update_distance(struct eigrp_fsm_action_message *msg)
}
break;
default:
- zlog_err("%s: Please implement handler", __PRETTY_FUNCTION__);
+ flog_err(LIB_ERR_DEVELOPMENT, "%s: Please implement handler",
+ __PRETTY_FUNCTION__);
break;
}
distance_done:
diff --git a/eigrpd/eigrpd.c b/eigrpd/eigrpd.c
index 24d1253cb9..91c0046bb9 100644
--- a/eigrpd/eigrpd.c
+++ b/eigrpd/eigrpd.c
@@ -43,6 +43,7 @@
#include "sockopt.h"
#include "keychain.h"
#include "libfrr.h"
+#include "lib_errors.h"
#include "eigrpd/eigrp_structs.h"
#include "eigrpd/eigrpd.h"
@@ -161,21 +162,16 @@ static struct eigrp *eigrp_new(const char *AS)
eigrp->networks = eigrp_topology_new();
if ((eigrp_socket = eigrp_sock_init()) < 0) {
- zlog_err(
- "eigrp_new: fatal error: eigrp_sock_init was unable to open "
- "a socket");
+ flog_err_sys(
+ LIB_ERR_SOCKET,
+ "eigrp_new: fatal error: eigrp_sock_init was unable to open a socket");
exit(1);
}
eigrp->fd = eigrp_socket;
eigrp->maxsndbuflen = getsockopt_so_sendbuf(eigrp->fd);
- if ((eigrp->ibuf = stream_new(EIGRP_PACKET_MAX_LEN + 1)) == NULL) {
- zlog_err(
- "eigrp_new: fatal error: stream_new (%u) failed allocating ibuf",
- EIGRP_PACKET_MAX_LEN + 1);
- exit(1);
- }
+ eigrp->ibuf = stream_new(EIGRP_PACKET_MAX_LEN + 1);
eigrp->t_read = NULL;
thread_add_read(master, eigrp_read, eigrp, eigrp->fd, &eigrp->t_read);
diff --git a/eigrpd/subdir.am b/eigrpd/subdir.am
index 2c6b1e321b..2635d555d9 100644
--- a/eigrpd/subdir.am
+++ b/eigrpd/subdir.am
@@ -10,6 +10,7 @@ endif
eigrpd_libeigrp_a_SOURCES = \
eigrpd/eigrp_dump.c \
+ eigrpd/eigrp_errors.c \
eigrpd/eigrp_filter.c \
eigrpd/eigrp_fsm.c \
eigrpd/eigrp_hello.c \
@@ -39,6 +40,7 @@ eigrpdheader_HEADERS = \
noinst_HEADERS += \
eigrpd/eigrp_const.h \
+ eigrpd/eigrp_errors.h \
eigrpd/eigrp_filter.h \
eigrpd/eigrp_fsm.h \
eigrpd/eigrp_interface.h \
diff --git a/isisd/dict.c b/isisd/dict.c
index 20a4c0ff73..5d3e61e6d6 100644
--- a/isisd/dict.c
+++ b/isisd/dict.c
@@ -244,19 +244,18 @@ dict_t *dict_create(dictcount_t maxcount, dict_comp_t comp)
{
dict_t *new = XCALLOC(MTYPE_ISIS_DICT, sizeof(dict_t));
- if (new) {
- new->compare = comp;
- new->allocnode = dnode_alloc;
- new->freenode = dnode_free;
- new->context = NULL;
- new->nodecount = 0;
- new->maxcount = maxcount;
- new->nilnode.left = &new->nilnode;
- new->nilnode.right = &new->nilnode;
- new->nilnode.parent = &new->nilnode;
- new->nilnode.color = dnode_black;
- new->dupes = 0;
- }
+ new->compare = comp;
+ new->allocnode = dnode_alloc;
+ new->freenode = dnode_free;
+ new->context = NULL;
+ new->nodecount = 0;
+ new->maxcount = maxcount;
+ new->nilnode.left = &new->nilnode;
+ new->nilnode.right = &new->nilnode;
+ new->nilnode.parent = &new->nilnode;
+ new->nilnode.color = dnode_black;
+ new->dupes = 0;
+
return new;
}
@@ -974,12 +973,12 @@ static void dnode_free(dnode_t *node, void *context)
dnode_t *dnode_create(void *data)
{
dnode_t *new = XCALLOC(MTYPE_ISIS_DICT_NODE, sizeof(dnode_t));
- if (new) {
- new->data = data;
- new->parent = NULL;
- new->left = NULL;
- new->right = NULL;
- }
+
+ new->data = data;
+ new->parent = NULL;
+ new->left = NULL;
+ new->right = NULL;
+
return new;
}
@@ -1250,8 +1249,8 @@ static char *dupstring(char *str)
{
int sz = strlen(str) + 1;
char *new = XCALLOC(MTYPE_ISIS_TMP, sz);
- if (new)
- memcpy(new, str, sz);
+
+ memcpy(new, str, sz);
return new;
}
diff --git a/isisd/isis_bpf.c b/isisd/isis_bpf.c
index 2cc2fefd9a..d05dba33ee 100644
--- a/isisd/isis_bpf.c
+++ b/isisd/isis_bpf.c
@@ -32,6 +32,7 @@
#include "network.h"
#include "stream.h"
#include "if.h"
+#include "lib_errors.h"
#include "isisd/dict.h"
#include "isisd/isis_constants.h"
@@ -186,31 +187,26 @@ int isis_sock_init(struct isis_circuit *circuit)
{
int retval = ISIS_OK;
- if (isisd_privs.change(ZPRIVS_RAISE))
- zlog_err("%s: could not raise privs, %s", __func__,
- safe_strerror(errno));
+ frr_elevate_privs(&isisd_privs) {
- retval = open_bpf_dev(circuit);
+ retval = open_bpf_dev(circuit);
- if (retval != ISIS_OK) {
- zlog_warn("%s: could not initialize the socket", __func__);
- goto end;
- }
+ if (retval != ISIS_OK) {
+ zlog_warn("%s: could not initialize the socket",
+ __func__);
+ break;
+ }
- if (if_is_broadcast(circuit->interface)) {
- circuit->tx = isis_send_pdu_bcast;
- circuit->rx = isis_recv_pdu_bcast;
- } else {
- zlog_warn("isis_sock_init(): unknown circuit type");
- retval = ISIS_WARNING;
- goto end;
+ if (if_is_broadcast(circuit->interface)) {
+ circuit->tx = isis_send_pdu_bcast;
+ circuit->rx = isis_recv_pdu_bcast;
+ } else {
+ zlog_warn("isis_sock_init(): unknown circuit type");
+ retval = ISIS_WARNING;
+ break;
+ }
}
-end:
- if (isisd_privs.change(ZPRIVS_LOWER))
- zlog_err("%s: could not lower privs, %s", __func__,
- safe_strerror(errno));
-
return retval;
}
diff --git a/isisd/isis_circuit.c b/isisd/isis_circuit.c
index d51f31ff37..7cf83f20fa 100644
--- a/isisd/isis_circuit.c
+++ b/isisd/isis_circuit.c
@@ -57,6 +57,7 @@
#include "isisd/isis_events.h"
#include "isisd/isis_te.h"
#include "isisd/isis_mt.h"
+#include "isisd/isis_errors.h"
DEFINE_QOBJ_TYPE(isis_circuit)
@@ -73,10 +74,6 @@ struct isis_circuit *isis_circuit_new()
int i;
circuit = XCALLOC(MTYPE_ISIS_CIRCUIT, sizeof(struct isis_circuit));
- if (circuit == NULL) {
- zlog_err("Can't malloc isis circuit");
- return NULL;
- }
/*
* Default values
@@ -570,7 +567,8 @@ int isis_circuit_up(struct isis_circuit *circuit)
return ISIS_OK;
if (circuit->area->lsp_mtu > isis_circuit_pdu_size(circuit)) {
- zlog_err(
+ flog_err(
+ ISIS_ERR_CONFIG,
"Interface MTU %zu on %s is too low to support area lsp mtu %u!",
isis_circuit_pdu_size(circuit),
circuit->interface->name, circuit->area->lsp_mtu);
@@ -581,7 +579,9 @@ int isis_circuit_up(struct isis_circuit *circuit)
if (circuit->circ_type == CIRCUIT_T_BROADCAST) {
circuit->circuit_id = isis_circuit_id_gen(isis, circuit->interface);
if (!circuit->circuit_id) {
- zlog_err("There are already 255 broadcast circuits active!");
+ flog_err(
+ ISIS_ERR_CONFIG,
+ "There are already 255 broadcast circuits active!");
return ISIS_ERROR;
}
diff --git a/isisd/isis_csm.c b/isisd/isis_csm.c
index 10870d5c50..aae90b0080 100644
--- a/isisd/isis_csm.c
+++ b/isisd/isis_csm.c
@@ -47,6 +47,7 @@
#include "isisd/isisd.h"
#include "isisd/isis_csm.h"
#include "isisd/isis_events.h"
+#include "isisd/isis_errors.h"
extern struct isis *isis;
@@ -137,10 +138,12 @@ isis_csm_state_change(int event, struct isis_circuit *circuit, void *arg)
case IF_UP_FROM_Z:
isis_circuit_if_add(circuit, (struct interface *)arg);
if (isis_circuit_up(circuit) != ISIS_OK) {
- zlog_err(
+ flog_err(
+ ISIS_ERR_CONFIG,
"Could not bring up %s because of invalid config.",
circuit->interface->name);
- zlog_err(
+ flog_err(
+ ISIS_ERR_CONFIG,
"Clearing config for %s. Please re-examine it.",
circuit->interface->name);
if (circuit->ip_router) {
diff --git a/isisd/isis_dlpi.c b/isisd/isis_dlpi.c
index 718f3a8982..54a19ad239 100644
--- a/isisd/isis_dlpi.c
+++ b/isisd/isis_dlpi.c
@@ -36,6 +36,7 @@
#include "network.h"
#include "stream.h"
#include "if.h"
+#include "lib_errors.h"
#include "isisd/dict.h"
#include "isisd/isis_constants.h"
@@ -467,31 +468,26 @@ int isis_sock_init(struct isis_circuit *circuit)
{
int retval = ISIS_OK;
- if (isisd_privs.change(ZPRIVS_RAISE))
- zlog_err("%s: could not raise privs, %s", __func__,
- safe_strerror(errno));
+ frr_elevate_privs(&isisd_privs) {
- retval = open_dlpi_dev(circuit);
+ retval = open_dlpi_dev(circuit);
- if (retval != ISIS_OK) {
- zlog_warn("%s: could not initialize the socket", __func__);
- goto end;
- }
+ if (retval != ISIS_OK) {
+ zlog_warn("%s: could not initialize the socket",
+ __func__);
+ break;
+ }
- if (circuit->circ_type == CIRCUIT_T_BROADCAST) {
- circuit->tx = isis_send_pdu_bcast;
- circuit->rx = isis_recv_pdu_bcast;
- } else {
- zlog_warn("isis_sock_init(): unknown circuit type");
- retval = ISIS_WARNING;
- goto end;
+ if (circuit->circ_type == CIRCUIT_T_BROADCAST) {
+ circuit->tx = isis_send_pdu_bcast;
+ circuit->rx = isis_recv_pdu_bcast;
+ } else {
+ zlog_warn("isis_sock_init(): unknown circuit type");
+ retval = ISIS_WARNING;
+ break;
+ }
}
-end:
- if (isisd_privs.change(ZPRIVS_LOWER))
- zlog_err("%s: could not lower privs, %s", __func__,
- safe_strerror(errno));
-
return retval;
}
diff --git a/isisd/isis_errors.c b/isisd/isis_errors.c
new file mode 100644
index 0000000000..ecff65da1f
--- /dev/null
+++ b/isisd/isis_errors.c
@@ -0,0 +1,49 @@
+/*
+ * ISIS-specific error messages.
+ * Copyright (C) 2018 Cumulus Networks, Inc.
+ * Donald Sharp
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This 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 "lib/ferr.h"
+#include "isis_errors.h"
+
+/* clang-format off */
+static struct log_ref ferr_isis_err[] = {
+ {
+ .code = ISIS_ERR_PACKET,
+ .title = "ISIS Packet Error",
+ .description = "Isis has detected an error with a packet from a peer",
+ .suggestion = "Gather log information and open an issue then restart FRR"
+ },
+ {
+ .code = ISIS_ERR_CONFIG,
+ .title = "ISIS Configuration Error",
+ .description = "Isis has detected an error within configuration for the router",
+ .suggestion = "Ensure configuration is correct"
+ },
+ {
+ .code = END_FERR,
+ }
+};
+/* clang-format on */
+
+void isis_error_init(void)
+{
+ log_ref_add(ferr_isis_err);
+}
diff --git a/isisd/isis_errors.h b/isisd/isis_errors.h
new file mode 100644
index 0000000000..f738254a30
--- /dev/null
+++ b/isisd/isis_errors.h
@@ -0,0 +1,33 @@
+/*
+ * ISIS-specific error messages.
+ * Copyright (C) 2018 Cumulus Networks, Inc.
+ * Donald Sharp
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; see the file COPYING; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef __ISIS_ERRORS_H__
+#define __ISIS_ERRORS_H__
+
+#include "lib/ferr.h"
+
+enum isis_log_refs {
+ ISIS_ERR_PACKET = ISIS_FERR_START,
+ ISIS_ERR_CONFIG,
+};
+
+extern void isis_error_init(void);
+
+#endif
diff --git a/isisd/isis_events.c b/isisd/isis_events.c
index 349ec262c0..52a0b9fac6 100644
--- a/isisd/isis_events.c
+++ b/isisd/isis_events.c
@@ -48,6 +48,7 @@
#include "isisd/isis_csm.h"
#include "isisd/isis_events.h"
#include "isisd/isis_spf.h"
+#include "isisd/isis_errors.h"
/* debug isis-spf spf-events
4w4d: ISIS-Spf (tlt): L2 SPF needed, new adjacency, from 0x609229F4
@@ -156,9 +157,9 @@ void isis_circuit_is_type_set(struct isis_circuit *circuit, int newtype)
return; /* No change */
if (!(newtype & circuit->area->is_type)) {
- zlog_err(
- "ISIS-Evt (%s) circuit type change - invalid level %s because"
- " area is %s",
+ flog_err(
+ ISIS_ERR_CONFIG,
+ "ISIS-Evt (%s) circuit type change - invalid level %s because area is %s",
circuit->area->area_tag, circuit_t2string(newtype),
circuit_t2string(circuit->area->is_type));
return;
diff --git a/isisd/isis_lsp.c b/isisd/isis_lsp.c
index 37651163f5..66c97ae897 100644
--- a/isisd/isis_lsp.c
+++ b/isisd/isis_lsp.c
@@ -38,6 +38,7 @@
#include "md5.h"
#include "table.h"
#include "srcdest_table.h"
+#include "lib_errors.h"
#include "isisd/dict.h"
#include "isisd/isis_constants.h"
@@ -453,7 +454,8 @@ void lsp_update(struct isis_lsp *lsp, struct isis_lsp_hdr *hdr,
struct isis_area *area, int level, bool confusion)
{
if (lsp->own_lsp) {
- zlog_err(
+ flog_err(
+ LIB_ERR_DEVELOPMENT,
"ISIS-Upd (%s): BUG updating LSP %s still marked as own LSP",
area->area_tag, rawlspid_print(lsp->hdr.lsp_id));
lsp_clear_data(lsp);
@@ -1242,8 +1244,9 @@ static int lsp_regenerate(struct isis_area *area, int level)
lsp = lsp_search(lspid, lspdb);
if (!lsp) {
- zlog_err("ISIS-Upd (%s): lsp_regenerate: no L%d LSP found!",
- area->area_tag, level);
+ flog_err(LIB_ERR_DEVELOPMENT,
+ "ISIS-Upd (%s): lsp_regenerate: no L%d LSP found!",
+ area->area_tag, level);
return ISIS_ERROR;
}
@@ -1610,8 +1613,9 @@ static int lsp_regenerate_pseudo(struct isis_circuit *circuit, int level)
lsp = lsp_search(lsp_id, lspdb);
if (!lsp) {
- zlog_err("lsp_regenerate_pseudo: no l%d LSP %s found!", level,
- rawlspid_print(lsp_id));
+ flog_err(LIB_ERR_DEVELOPMENT,
+ "lsp_regenerate_pseudo: no l%d LSP %s found!", level,
+ rawlspid_print(lsp_id));
return ISIS_ERROR;
}
diff --git a/isisd/isis_main.c b/isisd/isis_main.c
index 40ceb99fb2..5b18ab0a2c 100644
--- a/isisd/isis_main.c
+++ b/isisd/isis_main.c
@@ -53,6 +53,7 @@
#include "isisd/isis_routemap.h"
#include "isisd/isis_zebra.h"
#include "isisd/isis_te.h"
+#include "isisd/isis_errors.h"
/* Default configuration file name */
#define ISISD_DEFAULT_CONFIG "isisd.conf"
@@ -103,7 +104,7 @@ static __attribute__((__noreturn__)) void terminate(int i)
void sighup(void)
{
- zlog_err("SIGHUP/reload is not implemented for isisd");
+ zlog_notice("SIGHUP/reload is not implemented for isisd");
return;
}
@@ -189,6 +190,7 @@ int main(int argc, char **argv, char **envp)
/*
* initializations
*/
+ isis_error_init();
access_list_init();
vrf_init(NULL, NULL, NULL, NULL);
prefix_list_init();
diff --git a/isisd/isis_pdu.c b/isisd/isis_pdu.c
index 8e2a7f13a5..5c4e3a35bc 100644
--- a/isisd/isis_pdu.c
+++ b/isisd/isis_pdu.c
@@ -34,6 +34,7 @@
#include "if.h"
#include "checksum.h"
#include "md5.h"
+#include "lib_errors.h"
#include "isisd/dict.h"
#include "isisd/isis_constants.h"
@@ -54,6 +55,7 @@
#include "isisd/isis_te.h"
#include "isisd/isis_mt.h"
#include "isisd/isis_tlvs.h"
+#include "isisd/isis_errors.h"
static int ack_lsp(struct isis_lsp_hdr *hdr, struct isis_circuit *circuit,
int level)
@@ -86,9 +88,10 @@ static int ack_lsp(struct isis_lsp_hdr *hdr, struct isis_circuit *circuit,
retval = circuit->tx(circuit, level);
if (retval != ISIS_OK)
- zlog_err("ISIS-Upd (%s): Send L%d LSP PSNP on %s failed",
- circuit->area->area_tag, level,
- circuit->interface->name);
+ flog_err(ISIS_ERR_PACKET,
+ "ISIS-Upd (%s): Send L%d LSP PSNP on %s failed",
+ circuit->area->area_tag, level,
+ circuit->interface->name);
return retval;
}
@@ -614,8 +617,9 @@ static int process_hello(uint8_t pdu_type, struct isis_circuit *circuit,
}
if (!p2p_hello && !(level & iih.circ_type)) {
- zlog_err("Level %d LAN Hello with Circuit Type %d", level,
- iih.circ_type);
+ flog_err(ISIS_ERR_PACKET,
+ "Level %d LAN Hello with Circuit Type %d", level,
+ iih.circ_type);
return ISIS_ERROR;
}
@@ -1350,7 +1354,7 @@ int isis_handle_pdu(struct isis_circuit *circuit, uint8_t *ssnpa)
/* Verify that at least the 8 bytes fixed header have been received */
if (stream_get_endp(circuit->rcv_stream) < ISIS_FIXED_HDR_LEN) {
- zlog_err("PDU is too short to be IS-IS.");
+ flog_err(ISIS_ERR_PACKET, "PDU is too short to be IS-IS.");
return ISIS_ERROR;
}
@@ -1365,12 +1369,14 @@ int isis_handle_pdu(struct isis_circuit *circuit, uint8_t *ssnpa)
uint8_t max_area_addrs = stream_getc(circuit->rcv_stream);
if (idrp == ISO9542_ESIS) {
- zlog_err("No support for ES-IS packet IDRP=%" PRIx8, idrp);
+ flog_err(LIB_ERR_DEVELOPMENT,
+ "No support for ES-IS packet IDRP=%" PRIx8, idrp);
return ISIS_ERROR;
}
if (idrp != ISO10589_ISIS) {
- zlog_err("Not an IS-IS packet IDRP=%" PRIx8, idrp);
+ flog_err(ISIS_ERR_PACKET, "Not an IS-IS packet IDRP=%" PRIx8,
+ idrp);
return ISIS_ERROR;
}
@@ -1380,7 +1386,8 @@ int isis_handle_pdu(struct isis_circuit *circuit, uint8_t *ssnpa)
}
if (id_len != 0 && id_len != ISIS_SYS_ID_LEN) {
- zlog_err(
+ flog_err(
+ ISIS_ERR_PACKET,
"IDFieldLengthMismatch: ID Length field in a received PDU %" PRIu8
", while the parameter for this IS is %u",
id_len, ISIS_SYS_ID_LEN);
@@ -1394,14 +1401,16 @@ int isis_handle_pdu(struct isis_circuit *circuit, uint8_t *ssnpa)
}
if (length != expected_length) {
- zlog_err("Exepected fixed header length = %" PRIu8
- " but got %" PRIu8,
- expected_length, length);
+ flog_err(ISIS_ERR_PACKET,
+ "Exepected fixed header length = %" PRIu8
+ " but got %" PRIu8,
+ expected_length, length);
return ISIS_ERROR;
}
if (stream_get_endp(circuit->rcv_stream) < length) {
- zlog_err(
+ flog_err(
+ ISIS_ERR_PACKET,
"PDU is too short to contain fixed header of given PDU type.");
return ISIS_ERROR;
}
@@ -1419,7 +1428,8 @@ int isis_handle_pdu(struct isis_circuit *circuit, uint8_t *ssnpa)
/* either 3 or 0 */
if (max_area_addrs != 0 && max_area_addrs != isis->max_area_addrs) {
- zlog_err(
+ flog_err(
+ ISIS_ERR_PACKET,
"maximumAreaAddressesMismatch: maximumAreaAdresses in a received PDU %" PRIu8
" while the parameter for this IS is %u",
max_area_addrs, isis->max_area_addrs);
@@ -1643,9 +1653,10 @@ int send_hello(struct isis_circuit *circuit, int level)
retval = circuit->tx(circuit, level);
if (retval != ISIS_OK)
- zlog_err("ISIS-Adj (%s): Send L%d IIH on %s failed",
- circuit->area->area_tag, level,
- circuit->interface->name);
+ flog_err(ISIS_ERR_PACKET,
+ "ISIS-Adj (%s): Send L%d IIH on %s failed",
+ circuit->area->area_tag, level,
+ circuit->interface->name);
return retval;
}
@@ -1840,9 +1851,10 @@ int send_csnp(struct isis_circuit *circuit, int level)
int retval = circuit->tx(circuit, level);
if (retval != ISIS_OK) {
- zlog_err("ISIS-Snp (%s): Send L%d CSNP on %s failed",
- circuit->area->area_tag, level,
- circuit->interface->name);
+ flog_err(ISIS_ERR_PACKET,
+ "ISIS-Snp (%s): Send L%d CSNP on %s failed",
+ circuit->area->area_tag, level,
+ circuit->interface->name);
isis_free_tlvs(tlvs);
return retval;
}
@@ -2004,9 +2016,10 @@ static int send_psnp(int level, struct isis_circuit *circuit)
int retval = circuit->tx(circuit, level);
if (retval != ISIS_OK) {
- zlog_err("ISIS-Snp (%s): Send L%d PSNP on %s failed",
- circuit->area->area_tag, level,
- circuit->interface->name);
+ flog_err(ISIS_ERR_PACKET,
+ "ISIS-Snp (%s): Send L%d PSNP on %s failed",
+ circuit->area->area_tag, level,
+ circuit->interface->name);
isis_free_tlvs(tlvs);
return retval;
}
@@ -2111,7 +2124,8 @@ int send_lsp(struct thread *thread)
* than
* the circuit's MTU. So handle and log this case here. */
if (stream_get_endp(lsp->pdu) > stream_get_size(circuit->snd_stream)) {
- zlog_err(
+ flog_err(
+ ISIS_ERR_PACKET,
"ISIS-Upd (%s): Can't send L%d LSP %s, seq 0x%08" PRIx32
", cksum 0x%04" PRIx16 ", lifetime %" PRIu16
"s on %s. LSP Size is %zu while interface stream size is %zu.",
@@ -2146,11 +2160,12 @@ int send_lsp(struct thread *thread)
clear_srm = 0;
retval = circuit->tx(circuit, lsp->level);
if (retval != ISIS_OK) {
- zlog_err("ISIS-Upd (%s): Send L%d LSP on %s failed %s",
- circuit->area->area_tag, lsp->level,
- circuit->interface->name,
- (retval == ISIS_WARNING) ? "temporarily"
- : "permanently");
+ flog_err(ISIS_ERR_PACKET,
+ "ISIS-Upd (%s): Send L%d LSP on %s failed %s",
+ circuit->area->area_tag, lsp->level,
+ circuit->interface->name,
+ (retval == ISIS_WARNING) ? "temporarily"
+ : "permanently");
}
out:
diff --git a/isisd/isis_pfpacket.c b/isisd/isis_pfpacket.c
index fd82b85f51..2f6526bc5e 100644
--- a/isisd/isis_pfpacket.c
+++ b/isisd/isis_pfpacket.c
@@ -31,6 +31,7 @@
#include "network.h"
#include "stream.h"
#include "if.h"
+#include "lib_errors.h"
#include "isisd/dict.h"
#include "isisd/isis_constants.h"
@@ -184,35 +185,30 @@ int isis_sock_init(struct isis_circuit *circuit)
{
int retval = ISIS_OK;
- if (isisd_privs.change(ZPRIVS_RAISE))
- zlog_err("%s: could not raise privs, %s", __func__,
- safe_strerror(errno));
+ frr_elevate_privs(&isisd_privs) {
- retval = open_packet_socket(circuit);
+ retval = open_packet_socket(circuit);
- if (retval != ISIS_OK) {
- zlog_warn("%s: could not initialize the socket", __func__);
- goto end;
- }
+ if (retval != ISIS_OK) {
+ zlog_warn("%s: could not initialize the socket",
+ __func__);
+ break;
+ }
/* Assign Rx and Tx callbacks are based on real if type */
- if (if_is_broadcast(circuit->interface)) {
- circuit->tx = isis_send_pdu_bcast;
- circuit->rx = isis_recv_pdu_bcast;
- } else if (if_is_pointopoint(circuit->interface)) {
- circuit->tx = isis_send_pdu_p2p;
- circuit->rx = isis_recv_pdu_p2p;
- } else {
- zlog_warn("isis_sock_init(): unknown circuit type");
- retval = ISIS_WARNING;
- goto end;
+ if (if_is_broadcast(circuit->interface)) {
+ circuit->tx = isis_send_pdu_bcast;
+ circuit->rx = isis_recv_pdu_bcast;
+ } else if (if_is_pointopoint(circuit->interface)) {
+ circuit->tx = isis_send_pdu_p2p;
+ circuit->rx = isis_recv_pdu_p2p;
+ } else {
+ zlog_warn("isis_sock_init(): unknown circuit type");
+ retval = ISIS_WARNING;
+ break;
+ }
}
-end:
- if (isisd_privs.change(ZPRIVS_LOWER))
- zlog_err("%s: could not lower privs, %s", __func__,
- safe_strerror(errno));
-
return retval;
}
diff --git a/isisd/isis_spf.c b/isisd/isis_spf.c
index 0a8b0e927e..341921146b 100644
--- a/isisd/isis_spf.c
+++ b/isisd/isis_spf.c
@@ -38,6 +38,7 @@
#include "jhash.h"
#include "skiplist.h"
#include "srcdest_table.h"
+#include "lib_errors.h"
#include "isis_constants.h"
#include "isis_common.h"
@@ -437,7 +438,7 @@ static void isis_vertex_id_init(struct isis_vertex *vertex, union isis_N *n,
} else if (VTYPE_IP(vtype)) {
memcpy(&vertex->N.ip, &n->ip, sizeof(n->ip));
} else {
- zlog_err("WTF!");
+ flog_err(LIB_ERR_DEVELOPMENT, "Unknown Vertex Type");
}
}
@@ -486,10 +487,6 @@ struct isis_spftree *isis_spftree_new(struct isis_area *area)
struct isis_spftree *tree;
tree = XCALLOC(MTYPE_ISIS_SPFTREE, sizeof(struct isis_spftree));
- if (tree == NULL) {
- zlog_err("ISIS-Spf: isis_spftree_new Out of memory!");
- return NULL;
- }
isis_vertex_queue_init(&tree->tents, "IS-IS SPF tents", true);
isis_vertex_queue_init(&tree->paths, "IS-IS SPF paths", false);
diff --git a/isisd/isis_te.c b/isisd/isis_te.c
index 8e53df3b61..44ba64ce26 100644
--- a/isisd/isis_te.c
+++ b/isisd/isis_te.c
@@ -87,9 +87,6 @@ struct mpls_te_circuit *mpls_te_circuit_new()
mtc = XCALLOC(MTYPE_ISIS_MPLS_TE, sizeof(struct mpls_te_circuit));
- if (mtc == NULL)
- return NULL;
-
mtc->status = disable;
mtc->type = STD_TE;
mtc->length = 0;
diff --git a/isisd/subdir.am b/isisd/subdir.am
index 7b56715fa9..7b8be46167 100644
--- a/isisd/subdir.am
+++ b/isisd/subdir.am
@@ -15,6 +15,7 @@ isisd_libisis_a_SOURCES = \
isisd/isis_csm.c \
isisd/isis_dr.c \
isisd/isis_dynhn.c \
+ isisd/isis_errors.c \
isisd/isis_events.c \
isisd/isis_flags.c \
isisd/isis_lsp.c \
@@ -44,6 +45,7 @@ noinst_HEADERS += \
isisd/isis_csm.h \
isisd/isis_dr.h \
isisd/isis_dynhn.h \
+ isisd/isis_errors.h \
isisd/isis_events.h \
isisd/isis_flags.h \
isisd/isis_lsp.h \
diff --git a/ldpd/ldp_vty_cmds.c b/ldpd/ldp_vty_cmds.c
index d77a3e7e93..8eed089900 100644
--- a/ldpd/ldp_vty_cmds.c
+++ b/ldpd/ldp_vty_cmds.c
@@ -29,7 +29,7 @@
#include "ldpd/ldp_vty_cmds_clippy.c"
#endif
-DEFUN_NOSH(ldp_mpls_ldp,
+DEFPY_NOSH(ldp_mpls_ldp,
ldp_mpls_ldp_cmd,
"mpls ldp",
"Global MPLS configuration subcommands\n"
@@ -48,21 +48,15 @@ DEFPY (no_ldp_mpls_ldp,
return (ldp_vty_mpls_ldp(vty, "no"));
}
-DEFUN_NOSH(ldp_l2vpn,
+DEFPY_NOSH(ldp_l2vpn,
ldp_l2vpn_cmd,
- "l2vpn WORD type vpls",
+ "l2vpn WORD$l2vpn_name type vpls",
"Configure l2vpn commands\n"
"L2VPN name\n"
"L2VPN type\n"
"Virtual Private LAN Service\n")
{
- int idx = 0;
- const char *name;
-
- argv_find(argv, argc, "WORD", &idx);
- name = argv[idx]->arg;
-
- return (ldp_vty_l2vpn(vty, 0, name));
+ return (ldp_vty_l2vpn(vty, NULL, l2vpn_name));
}
DEFPY (no_ldp_l2vpn,
@@ -77,20 +71,14 @@ DEFPY (no_ldp_l2vpn,
return (ldp_vty_l2vpn(vty, "no", l2vpn_name));
}
-DEFUN_NOSH(ldp_address_family,
+DEFPY_NOSH(ldp_address_family,
ldp_address_family_cmd,
- "address-family <ipv4|ipv6>",
+ "address-family <ipv4|ipv6>$af",
"Configure Address Family and its parameters\n"
"IPv4\n"
"IPv6\n")
{
- int idx = 0;
- const char *af;
-
- argv_find(argv, argc, "address-family", &idx);
- af = argv[idx + 1]->text;
-
- return (ldp_vty_address_family(vty, 0, af));
+ return (ldp_vty_address_family(vty, NULL, af));
}
DEFPY (no_ldp_address_family,
@@ -104,7 +92,7 @@ DEFPY (no_ldp_address_family,
return (ldp_vty_address_family(vty, "no", af));
}
-DEFUN_NOSH(ldp_exit_address_family,
+DEFPY_NOSH(ldp_exit_address_family,
ldp_exit_address_family_cmd,
"exit-address-family",
"Exit from Address Family configuration mode\n")
@@ -361,19 +349,13 @@ DEFPY (ldp_session_holdtime,
return (ldp_vty_af_session_holdtime(vty, no, holdtime));
}
-DEFUN_NOSH(ldp_interface,
+DEFPY_NOSH(ldp_interface,
ldp_interface_cmd,
- "interface IFNAME",
+ "interface IFNAME$ifname",
"Enable LDP on an interface and enter interface submode\n"
"Interface's name\n")
{
- int idx = 0;
- const char *ifname;
-
- argv_find(argv, argc, "IFNAME", &idx);
- ifname = argv[idx]->arg;
-
- return (ldp_vty_interface(vty, 0, ifname));
+ return (ldp_vty_interface(vty, NULL, ifname));
}
DEFPY (no_ldp_interface,
@@ -439,20 +421,14 @@ DEFPY (ldp_member_interface,
return (ldp_vty_l2vpn_interface(vty, no, ifname));
}
-DEFUN_NOSH(ldp_member_pseudowire,
+DEFPY_NOSH(ldp_member_pseudowire,
ldp_member_pseudowire_cmd,
- "member pseudowire IFNAME",
+ "member pseudowire IFNAME$ifname",
"L2VPN member configuration\n"
"Pseudowire interface\n"
"Interface's name\n")
{
- int idx = 0;
- const char *ifname;
-
- argv_find(argv, argc, "IFNAME", &idx);
- ifname = argv[idx]->arg;
-
- return (ldp_vty_l2vpn_pseudowire(vty, 0, ifname));
+ return (ldp_vty_l2vpn_pseudowire(vty, NULL, ifname));
}
DEFPY (no_ldp_member_pseudowire,
@@ -759,7 +735,7 @@ DEFPY (ldp_show_l2vpn_atom_vc,
return (ldp_vty_show_atom_vc(vty, peer_str, ifname, vcid_str, json));
}
-DEFUN_NOSH (ldp_show_debugging_mpls_ldp,
+DEFPY_NOSH (ldp_show_debugging_mpls_ldp,
ldp_show_debugging_mpls_ldp_cmd,
"show debugging [mpls ldp]",
"Show running system information\n"
diff --git a/ldpd/ldpd.c b/ldpd/ldpd.c
index b51ff82cea..e830263ded 100644
--- a/ldpd/ldpd.c
+++ b/ldpd/ldpd.c
@@ -42,6 +42,7 @@
#include "filter.h"
#include "qobj.h"
#include "libfrr.h"
+#include "lib_errors.h"
static void ldpd_shutdown(void);
static pid_t start_child(enum ldpd_process, char *, int, int);
@@ -483,8 +484,9 @@ start_child(enum ldpd_process p, char *argv0, int fd_async, int fd_sync)
nullfd = open("/dev/null", O_RDONLY | O_NOCTTY);
if (nullfd == -1) {
- zlog_err("%s: failed to open /dev/null: %s", __func__,
- safe_strerror(errno));
+ flog_err_sys(LIB_ERR_SYSTEM_CALL,
+ "%s: failed to open /dev/null: %s", __func__,
+ safe_strerror(errno));
} else {
dup2(nullfd, 0);
dup2(nullfd, 1);
diff --git a/ldpd/socket.c b/ldpd/socket.c
index aefa3461a8..bebd7a7d61 100644
--- a/ldpd/socket.c
+++ b/ldpd/socket.c
@@ -41,7 +41,6 @@ ldp_create_socket(int af, enum socket_type type)
#ifdef __OpenBSD__
int opt;
#endif
- int save_errno;
/* create socket */
switch (type) {
@@ -80,25 +79,18 @@ ldp_create_socket(int af, enum socket_type type)
sock_set_bindany(fd, 1);
break;
}
- if (ldpd_privs.change(ZPRIVS_RAISE))
- log_warn("%s: could not raise privs", __func__);
- if (sock_set_reuse(fd, 1) == -1) {
- if (ldpd_privs.change(ZPRIVS_LOWER))
- log_warn("%s: could not lower privs", __func__);
- close(fd);
- return (-1);
- }
- if (bind(fd, &local_su.sa, sockaddr_len(&local_su.sa)) == -1) {
- save_errno = errno;
- if (ldpd_privs.change(ZPRIVS_LOWER))
- log_warn("%s: could not lower privs", __func__);
- log_warnx("%s: error binding socket: %s", __func__,
- safe_strerror(save_errno));
- close(fd);
- return (-1);
+ frr_elevate_privs(&ldpd_privs) {
+ if (sock_set_reuse(fd, 1) == -1) {
+ close(fd);
+ return (-1);
+ }
+ if (bind(fd, &local_su.sa, sockaddr_len(&local_su.sa)) == -1) {
+ log_warnx("%s: error binding socket: %s", __func__,
+ safe_strerror(errno));
+ close(fd);
+ return (-1);
+ }
}
- if (ldpd_privs.change(ZPRIVS_LOWER))
- log_warn("%s: could not lower privs", __func__);
/* set options */
switch (af) {
@@ -262,17 +254,13 @@ int
sock_set_bindany(int fd, int enable)
{
#ifdef HAVE_SO_BINDANY
- if (ldpd_privs.change(ZPRIVS_RAISE))
- log_warn("%s: could not raise privs", __func__);
- if (setsockopt(fd, SOL_SOCKET, SO_BINDANY, &enable,
- sizeof(int)) < 0) {
- if (ldpd_privs.change(ZPRIVS_LOWER))
- log_warn("%s: could not lower privs", __func__);
- log_warn("%s: error setting SO_BINDANY", __func__);
- return (-1);
+ frr_elevate_privs(&ldpd_privs) {
+ if (setsockopt(fd, SOL_SOCKET, SO_BINDANY, &enable,
+ sizeof(int)) < 0) {
+ log_warn("%s: error setting SO_BINDANY", __func__);
+ return (-1);
+ }
}
- if (ldpd_privs.change(ZPRIVS_LOWER))
- log_warn("%s: could not lower privs", __func__);
return (0);
#elif defined(HAVE_IP_FREEBIND)
if (setsockopt(fd, IPPROTO_IP, IP_FREEBIND, &enable, sizeof(int)) < 0) {
@@ -306,14 +294,10 @@ sock_set_md5sig(int fd, int af, union ldpd_addr *addr, const char *password)
#if HAVE_DECL_TCP_MD5SIG
addr2sa(af, addr, 0, &su);
- if (ldpe_privs.change(ZPRIVS_RAISE)) {
- log_warn("%s: could not raise privs", __func__);
- return (-1);
+ frr_elevate_privs(&ldpe_privs) {
+ ret = sockopt_tcp_signature(fd, &su, password);
+ save_errno = errno;
}
- ret = sockopt_tcp_signature(fd, &su, password);
- save_errno = errno;
- if (ldpe_privs.change(ZPRIVS_LOWER))
- log_warn("%s: could not lower privs", __func__);
#endif /* HAVE_TCP_MD5SIG */
if (ret < 0)
log_warnx("%s: can't set TCP_MD5SIG option on fd %d: %s",
diff --git a/lib/agentx.c b/lib/agentx.c
index 302bbf0a42..8e6493d4d3 100644
--- a/lib/agentx.c
+++ b/lib/agentx.c
@@ -31,6 +31,7 @@
#include "memory.h"
#include "linklist.h"
#include "version.h"
+#include "lib_errors.h"
static int agentx_enabled = 0;
@@ -141,16 +142,20 @@ static int agentx_log_callback(int major, int minor, void *serverarg,
msg[strlen(msg) - 1] = '\0';
switch (slm->priority) {
case LOG_EMERG:
- zlog_err("snmp[emerg]: %s", msg ? msg : slm->msg);
+ flog_err(LIB_ERR_SNMP,
+ "snmp[emerg]: %s", msg ? msg : slm->msg);
break;
case LOG_ALERT:
- zlog_err("snmp[alert]: %s", msg ? msg : slm->msg);
+ flog_err(LIB_ERR_SNMP,
+ "snmp[alert]: %s", msg ? msg : slm->msg);
break;
case LOG_CRIT:
- zlog_err("snmp[crit]: %s", msg ? msg : slm->msg);
+ flog_err(LIB_ERR_SNMP,
+ "snmp[crit]: %s", msg ? msg : slm->msg);
break;
case LOG_ERR:
- zlog_err("snmp[err]: %s", msg ? msg : slm->msg);
+ flog_err(LIB_ERR_SNMP,
+ "snmp[err]: %s", msg ? msg : slm->msg);
break;
case LOG_WARNING:
zlog_warn("snmp[warning]: %s", msg ? msg : slm->msg);
diff --git a/lib/bfd.h b/lib/bfd.h
index 94430051a8..f824b0fd9b 100644
--- a/lib/bfd.h
+++ b/lib/bfd.h
@@ -24,6 +24,7 @@
#define _ZEBRA_BFD_H
#include "lib/json.h"
+#include "lib/zclient.h"
#define BFD_DEF_MIN_RX 300
#define BFD_MIN_MIN_RX 50
diff --git a/lib/buffer.c b/lib/buffer.c
index b573981c1b..0292c85dac 100644
--- a/lib/buffer.c
+++ b/lib/buffer.c
@@ -25,6 +25,8 @@
#include "buffer.h"
#include "log.h"
#include "network.h"
+#include "lib_errors.h"
+
#include <stddef.h>
DEFINE_MTYPE_STATIC(LIB, BUFFER, "Buffer")
@@ -341,7 +343,8 @@ buffer_status_t buffer_flush_window(struct buffer *b, int fd, int width,
iov_alloc * sizeof(*iov));
} else {
/* This should absolutely never occur. */
- zlog_err(
+ flog_err_sys(
+ LIB_ERR_SYSTEM_CALL,
"%s: corruption detected: iov_small overflowed; "
"head %p, tail %p, head->next %p",
__func__, (void *)b->head,
@@ -456,9 +459,9 @@ in one shot. */
while (written > 0) {
struct buffer_data *d;
if (!(d = b->head)) {
- zlog_err(
- "%s: corruption detected: buffer queue empty, "
- "but written is %lu",
+ flog_err(
+ LIB_ERR_DEVELOPMENT,
+ "%s: corruption detected: buffer queue empty, but written is %lu",
__func__, (unsigned long)written);
break;
}
diff --git a/lib/command.c b/lib/command.c
index 0bf856f248..1df6442107 100644
--- a/lib/command.c
+++ b/lib/command.c
@@ -45,6 +45,7 @@
#include "libfrr.h"
#include "jhash.h"
#include "hook.h"
+#include "lib_errors.h"
DEFINE_MTYPE(LIB, HOST, "Host config")
DEFINE_MTYPE(LIB, COMPLETION, "Completion item")
@@ -143,6 +144,8 @@ const char *node_names[] = {
*/
"bgp ipv6 flowspec", /* BGP_FLOWSPECV6_NODE
*/
+ "bfd", /* BFD_NODE */
+ "bfd peer", /* BFD_PEER_NODE */
};
/* clang-format on */
@@ -987,6 +990,9 @@ enum node_type node_parent(enum node_type node)
case LDP_PSEUDOWIRE_NODE:
ret = LDP_L2VPN_NODE;
break;
+ case BFD_PEER_NODE:
+ ret = BFD_NODE;
+ break;
default:
ret = CONFIG_NODE;
break;
@@ -1433,6 +1439,7 @@ void cmd_exit(struct vty *vty)
case RMAP_NODE:
case PBRMAP_NODE:
case VTY_NODE:
+ case BFD_NODE:
vty->node = CONFIG_NODE;
break;
case BGP_IPV4_NODE:
@@ -1474,6 +1481,9 @@ void cmd_exit(struct vty *vty)
case LINK_PARAMS_NODE:
vty->node = INTERFACE_NODE;
break;
+ case BFD_PEER_NODE:
+ vty->node = BFD_NODE;
+ break;
default:
break;
}
@@ -1544,6 +1554,8 @@ DEFUN (config_end,
case KEYCHAIN_KEY_NODE:
case VTY_NODE:
case LINK_PARAMS_NODE:
+ case BFD_NODE:
+ case BFD_PEER_NODE:
vty_config_unlock(vty);
vty->node = ENABLE_NODE;
break;
@@ -2405,15 +2417,12 @@ static int set_log_file(struct vty *vty, const char *fname, int loglevel)
cwd[MAXPATHLEN] = '\0';
if (getcwd(cwd, MAXPATHLEN) == NULL) {
- zlog_err("config_log_file: Unable to alloc mem!");
+ flog_err_sys(LIB_ERR_SYSTEM_CALL,
+ "config_log_file: Unable to alloc mem!");
return CMD_WARNING_CONFIG_FAILED;
}
- if ((p = XMALLOC(MTYPE_TMP, strlen(cwd) + strlen(fname) + 2))
- == NULL) {
- zlog_err("config_log_file: Unable to alloc mem!");
- return CMD_WARNING_CONFIG_FAILED;
- }
+ p = XMALLOC(MTYPE_TMP, strlen(cwd) + strlen(fname) + 2);
sprintf(p, "%s/%s", cwd, fname);
fullpath = p;
} else
diff --git a/lib/command.h b/lib/command.h
index a001a90e2e..75b69507ec 100644
--- a/lib/command.h
+++ b/lib/command.h
@@ -139,6 +139,8 @@ enum node_type {
connections.*/
BGP_FLOWSPECV4_NODE, /* BGP IPv4 FLOWSPEC Address-Family */
BGP_FLOWSPECV6_NODE, /* BGP IPv6 FLOWSPEC Address-Family */
+ BFD_NODE, /* BFD protocol mode. */
+ BFD_PEER_NODE, /* BFD peer configuration mode. */
NODE_TYPE_MAX, /* maximum */
};
@@ -220,6 +222,9 @@ struct cmd_node {
DEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, 0, 0) \
funcdecl_##funcname
+#define DEFPY_NOSH(funcname, cmdname, cmdstr, helpstr) \
+ DEFPY(funcname, cmdname, cmdstr, helpstr)
+
#define DEFPY_ATTR(funcname, cmdname, cmdstr, helpstr, attr) \
DEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, attr, 0) \
funcdecl_##funcname
@@ -302,6 +307,9 @@ struct cmd_node {
#define DEFPY(funcname, cmdname, cmdstr, helpstr) \
DEFUN(funcname, cmdname, cmdstr, helpstr)
+#define DEFPY_NOSH(funcname, cmdname, cmdstr, helpstr) \
+ DEFUN_NOSH(funcname, cmdname, cmdstr, helpstr)
+
#define DEFPY_ATTR(funcname, cmdname, cmdstr, helpstr, attr) \
DEFUN_ATTR(funcname, cmdname, cmdstr, helpstr, attr)
#endif /* VTYSH_EXTRACT_PL */
diff --git a/lib/command_parse.y b/lib/command_parse.y
index 0f3e42219e..1b304a98b2 100644
--- a/lib/command_parse.y
+++ b/lib/command_parse.y
@@ -404,8 +404,8 @@ yyerror (CMD_YYLTYPE *loc, struct parser_ctx *ctx, char const *msg)
char spacing[256];
int lineno = 0;
- zlog_err ("%s: FATAL parse error: %s", __func__, msg);
- zlog_err ("%s: %d:%d-%d of this command definition:", __func__, loc->first_line, loc->first_column, loc->last_column);
+ zlog_notice ("%s: FATAL parse error: %s", __func__, msg);
+ zlog_notice ("%s: %d:%d-%d of this command definition:", __func__, loc->first_line, loc->first_column, loc->last_column);
line = tmpstr;
do {
@@ -414,7 +414,7 @@ yyerror (CMD_YYLTYPE *loc, struct parser_ctx *ctx, char const *msg)
if (eol)
*eol++ = '\0';
- zlog_err ("%s: | %s", __func__, line);
+ zlog_notice ("%s: | %s", __func__, line);
if (lineno == loc->first_line && lineno == loc->last_line
&& loc->first_column < (int)sizeof(spacing) - 1
&& loc->last_column < (int)sizeof(spacing) - 1) {
@@ -426,7 +426,7 @@ yyerror (CMD_YYLTYPE *loc, struct parser_ctx *ctx, char const *msg)
memset(spacing, ' ', loc->first_column - 1);
memset(spacing + loc->first_column - 1, '^', len);
spacing[loc->first_column - 1 + len] = '\0';
- zlog_err ("%s: | %s", __func__, spacing);
+ zlog_notice ("%s: | %s", __func__, spacing);
}
} while ((line = eol));
free(tmpstr);
diff --git a/lib/defun_lex.l b/lib/defun_lex.l
index 9c995db266..d901c26a2e 100644
--- a/lib/defun_lex.l
+++ b/lib/defun_lex.l
@@ -132,6 +132,7 @@ SPECIAL [(),]
"DEFUN_NOSH" value = strdup(yytext); return DEFUNNY;
"DEFUN_HIDDEN" value = strdup(yytext); return DEFUNNY;
"DEFPY" value = strdup(yytext); return DEFUNNY;
+"DEFPY_NOSH" value = strdup(yytext); return DEFUNNY;
"DEFPY_ATTR" value = strdup(yytext); return DEFUNNY;
"DEFPY_HIDDEN" value = strdup(yytext); return DEFUNNY;
"ALIAS" value = strdup(yytext); return DEFUNNY;
diff --git a/lib/ferr.c b/lib/ferr.c
index d315cf843c..2fa5db6f34 100644
--- a/lib/ferr.c
+++ b/lib/ferr.c
@@ -19,14 +19,22 @@
#include <string.h>
#include <pthread.h>
#include <signal.h>
+#include <inttypes.h>
#include "ferr.h"
#include "vty.h"
#include "jhash.h"
#include "memory.h"
+#include "hash.h"
+#include "command.h"
+#include "json.h"
+#include "linklist.h"
DEFINE_MTYPE_STATIC(LIB, ERRINFO, "error information")
+/*
+ * Thread-specific key for temporary storage of allocated ferr.
+ */
static pthread_key_t errkey;
static void ferr_free(void *arg)
@@ -46,6 +54,160 @@ static void err_key_fini(void)
pthread_key_delete(errkey);
}
+/*
+ * Global shared hash table holding reference text for all defined errors.
+ */
+pthread_mutex_t refs_mtx = PTHREAD_MUTEX_INITIALIZER;
+struct hash *refs;
+
+static int ferr_hash_cmp(const void *a, const void *b)
+{
+ const struct log_ref *f_a = a;
+ const struct log_ref *f_b = b;
+
+ return f_a->code == f_b->code;
+}
+
+static inline unsigned int ferr_hash_key(void *a)
+{
+ struct log_ref *f = a;
+
+ return f->code;
+}
+
+void log_ref_add(struct log_ref *ref)
+{
+ uint32_t i = 0;
+
+ pthread_mutex_lock(&refs_mtx);
+ {
+ while (ref[i].code != END_FERR) {
+ hash_get(refs, &ref[i], hash_alloc_intern);
+ i++;
+ }
+ }
+ pthread_mutex_unlock(&refs_mtx);
+}
+
+struct log_ref *log_ref_get(uint32_t code)
+{
+ struct log_ref holder;
+ struct log_ref *ref;
+
+ holder.code = code;
+ pthread_mutex_lock(&refs_mtx);
+ {
+ ref = hash_lookup(refs, &holder);
+ }
+ pthread_mutex_unlock(&refs_mtx);
+
+ return ref;
+}
+
+void log_ref_display(struct vty *vty, uint32_t code, bool json)
+{
+ struct log_ref *ref;
+ struct json_object *top, *obj;
+ struct list *errlist;
+ struct listnode *ln;
+
+ if (json)
+ top = json_object_new_object();
+
+ pthread_mutex_lock(&refs_mtx);
+ {
+ errlist = code ? list_new() : hash_to_list(refs);
+ }
+ pthread_mutex_unlock(&refs_mtx);
+
+ if (code) {
+ ref = log_ref_get(code);
+ if (!ref) {
+ vty_out(vty, "Code %"PRIu32" - Unknown\n", code);
+ return;
+ }
+ listnode_add(errlist, ref);
+ }
+
+ for (ALL_LIST_ELEMENTS_RO(errlist, ln, ref)) {
+ if (json) {
+ char key[11];
+
+ snprintf(key, sizeof(key), "%"PRIu32, ref->code);
+ obj = json_object_new_object();
+ json_object_string_add(obj, "title", ref->title);
+ json_object_string_add(obj, "description",
+ ref->description);
+ json_object_string_add(obj, "suggestion",
+ ref->suggestion);
+ json_object_object_add(top, key, obj);
+ } else {
+ char pbuf[256];
+ char ubuf[256];
+
+ snprintf(pbuf, sizeof(pbuf), "\nError %"PRIu32" - %s",
+ code, ref->title);
+ memset(ubuf, '=', strlen(pbuf));
+ ubuf[sizeof(ubuf) - 1] = '\0';
+
+ vty_out(vty, "%s\n%s\n", pbuf, ubuf);
+ vty_out(vty, "Description:\n%s\n\n", ref->description);
+ vty_out(vty, "Recommendation:\n%s\n", ref->suggestion);
+ }
+ }
+
+ if (json) {
+ const char *str = json_object_to_json_string_ext(
+ top, JSON_C_TO_STRING_PRETTY);
+ vty_out(vty, "%s\n", str);
+ json_object_free(top);
+ }
+
+ list_delete_and_null(&errlist);
+}
+
+DEFUN_NOSH(show_error_code,
+ show_error_code_cmd,
+ "show error <(1-4294967296)|all> [json]",
+ SHOW_STR
+ "Information on errors\n"
+ "Error code to get info about\n"
+ "Information on all errors\n"
+ JSON_STR)
+{
+ bool json = strmatch(argv[argc-1]->text, "json");
+ uint32_t arg = 0;
+
+ if (!strmatch(argv[2]->text, "all"))
+ arg = strtoul(argv[2]->arg, NULL, 10);
+
+ log_ref_display(vty, arg, json);
+ return CMD_SUCCESS;
+}
+
+void log_ref_init(void)
+{
+ pthread_mutex_lock(&refs_mtx);
+ {
+ refs = hash_create(ferr_hash_key, ferr_hash_cmp,
+ "Error Reference Texts");
+ }
+ pthread_mutex_unlock(&refs_mtx);
+
+ install_element(VIEW_NODE, &show_error_code_cmd);
+}
+
+void log_ref_fini(void)
+{
+ pthread_mutex_lock(&refs_mtx);
+ {
+ hash_clean(refs, NULL);
+ hash_free(refs);
+ refs = NULL;
+ }
+ pthread_mutex_unlock(&refs_mtx);
+}
+
const struct ferr *ferr_get_last(ferr_r errval)
{
struct ferr *last_error = pthread_getspecific(errkey);
@@ -70,13 +232,6 @@ static ferr_r ferr_set_va(const char *file, int line, const char *func,
if (!error) {
error = XCALLOC(MTYPE_ERRINFO, sizeof(*error));
- if (!error) {
- /* we're screwed */
- zlog_err("out of memory while allocating error info");
- raise(SIGSEGV);
- abort(); /* raise() can return, but raise(SIGSEGV) shall
- not */
- }
pthread_setspecific(errkey, error);
}
diff --git a/lib/ferr.h b/lib/ferr.h
index 2f100c1b01..335875c166 100644
--- a/lib/ferr.h
+++ b/lib/ferr.h
@@ -25,6 +25,8 @@
#include <limits.h>
#include <errno.h>
+#include "vty.h"
+
/* return type when this error indication stuff is used.
*
* guaranteed to have boolean evaluation to "false" when OK, "true" when error
@@ -93,6 +95,66 @@ struct ferr {
char pathname[PATH_MAX];
};
+/* Numeric ranges assigned to daemons for use as error codes. */
+#define BABEL_FERR_START 0x01000001
+#define BABEL_FRRR_END 0x01FFFFFF
+#define BGP_FERR_START 0x02000001
+#define BGP_FERR_END 0x02FFFFFF
+#define EIGRP_FERR_START 0x03000001
+#define EIGRP_FERR_END 0x03FFFFFF
+#define ISIS_FERR_START 0x04000001
+#define ISIS_FERR_END 0x04FFFFFF
+#define LDP_FERR_START 0x05000001
+#define LDP_FERR_END 0x05FFFFFF
+#define LIB_FERR_START 0x06000001
+#define LIB_FERR_END 0x06FFFFFF
+#define NHRP_FERR_START 0x07000001
+#define NHRP_FERR_END 0x07FFFFFF
+#define OSPF_FERR_START 0x08000001
+#define OSPF_FERR_END 0x08FFFFFF
+#define OSPFV3_FERR_START 0x09000001
+#define OSPFV3_FERR_END 0x09FFFFFF
+#define PBR_FERR_START 0x0A000001
+#define PBR_FERR_END 0x0AFFFFFF
+#define PIM_FERR_START 0x0B000001
+#define PIM_FERR_STOP 0x0BFFFFFF
+#define RIP_FERR_START 0x0C000001
+#define RIP_FERR_STOP 0x0CFFFFFF
+#define RIPNG_FERR_START 0x0D000001
+#define RIPNG_FERR_STOP 0x0DFFFFFF
+#define SHARP_FERR_START 0x0E000001
+#define SHARP_FERR_END 0x0EFFFFFF
+#define VTYSH_FERR_START 0x0F000001
+#define VTYSH_FRR_END 0x0FFFFFFF
+#define WATCHFRR_FERR_START 0x10000001
+#define WATCHFRR_FERR_END 0x10FFFFFF
+#define ZEBRA_FERR_START 0xF1000001
+#define ZEBRA_FERR_END 0xF1FFFFFF
+#define END_FERR 0xFFFFFFFF
+
+struct log_ref {
+ /* Unique error code displayed to end user as a reference. -1 means
+ * this is an uncoded error that does not have reference material. */
+ uint32_t code;
+ /* Ultra brief title */
+ const char *title;
+ /* Brief description of error */
+ const char *description;
+ /* Remedial suggestion */
+ const char *suggestion;
+};
+
+void log_ref_add(struct log_ref *ref);
+struct log_ref *log_ref_get(uint32_t code);
+void log_ref_display(struct vty *vty, uint32_t code, bool json);
+
+/*
+ * This function should be called by the
+ * code in libfrr.c
+ */
+void log_ref_init(void);
+void log_ref_fini(void);
+
/* get error details.
*
* NB: errval/ferr_r does NOT carry the full error information. It's only
@@ -101,8 +163,10 @@ struct ferr {
*/
const struct ferr *ferr_get_last(ferr_r errval);
-/* can optionally be called at strategic locations.
- * always returns 0. */
+/*
+ * Can optionally be called at strategic locations.
+ * Always returns 0.
+ */
ferr_r ferr_clear(void);
/* do NOT call these functions directly. only for macro use! */
diff --git a/lib/frr_zmq.c b/lib/frr_zmq.c
index 3153e697fa..02d9b68bc1 100644
--- a/lib/frr_zmq.c
+++ b/lib/frr_zmq.c
@@ -24,6 +24,7 @@
#include "memory.h"
#include "frr_zmq.h"
#include "log.h"
+#include "lib_errors.h"
DEFINE_MTYPE_STATIC(LIB, ZEROMQ_CB, "ZeroMQ callback")
@@ -140,7 +141,8 @@ static int frrzmq_read_msg(struct thread *t)
return 0;
out_err:
- zlog_err("ZeroMQ read error: %s(%d)", strerror(errno), errno);
+ flog_err(LIB_ERR_ZMQ, "ZeroMQ read error: %s(%d)", strerror(errno),
+ errno);
if (cb->read.cb_error)
cb->read.cb_error(cb->read.arg, cb->zmqsock);
return 1;
@@ -253,7 +255,8 @@ static int frrzmq_write_msg(struct thread *t)
return 0;
out_err:
- zlog_err("ZeroMQ write error: %s(%d)", strerror(errno), errno);
+ flog_err(LIB_ERR_ZMQ, "ZeroMQ write error: %s(%d)", strerror(errno),
+ errno);
if (cb->write.cb_error)
cb->write.cb_error(cb->write.arg, cb->zmqsock);
return 1;
diff --git a/lib/if.c b/lib/if.c
index e31ccd8563..6023624dc1 100644
--- a/lib/if.c
+++ b/lib/if.c
@@ -23,6 +23,7 @@
#include "linklist.h"
#include "vector.h"
+#include "lib_errors.h"
#include "vty.h"
#include "command.h"
#include "vrf.h"
@@ -626,7 +627,7 @@ static struct interface *if_sunwzebra_get(char *name, vrf_id_t vrf_id)
}
#endif /* SUNOS_5 */
-DEFUN (interface,
+DEFUN_NOSH (interface,
interface_cmd,
"interface IFNAME [vrf NAME]",
"Select an interface to configure\n"
@@ -669,13 +670,13 @@ DEFUN (interface,
return CMD_SUCCESS;
}
-DEFUN_NOSH (no_interface,
- no_interface_cmd,
- "no interface IFNAME [vrf NAME]",
- NO_STR
- "Delete a pseudo interface's configuration\n"
- "Interface's name\n"
- VRF_CMD_HELP_STR)
+DEFUN (no_interface,
+ no_interface_cmd,
+ "no interface IFNAME [vrf NAME]",
+ NO_STR
+ "Delete a pseudo interface's configuration\n"
+ "Interface's name\n"
+ VRF_CMD_HELP_STR)
{
int idx_vrf = 4;
const char *ifname = argv[2]->arg;
diff --git a/lib/if.h b/lib/if.h
index 7b65bbd2e5..3a9c4af848 100644
--- a/lib/if.h
+++ b/lib/if.h
@@ -297,28 +297,32 @@ DECLARE_QOBJ_TYPE(interface)
#define IFNAME_RB_INSERT(vrf, ifp) \
if (RB_INSERT(if_name_head, &vrf->ifaces_by_name, (ifp))) \
- zlog_err( \
+ flog_err( \
+ LIB_ERR_INTERFACE, \
"%s(%s): corruption detected -- interface with this " \
"name exists already in VRF %u!", \
__func__, (ifp)->name, (ifp)->vrf_id);
#define IFNAME_RB_REMOVE(vrf, ifp) \
if (RB_REMOVE(if_name_head, &vrf->ifaces_by_name, (ifp)) == NULL) \
- zlog_err( \
+ flog_err( \
+ LIB_ERR_INTERFACE, \
"%s(%s): corruption detected -- interface with this " \
"name doesn't exist in VRF %u!", \
__func__, (ifp)->name, (ifp)->vrf_id);
#define IFINDEX_RB_INSERT(vrf, ifp) \
if (RB_INSERT(if_index_head, &vrf->ifaces_by_index, (ifp))) \
- zlog_err( \
+ flog_err( \
+ LIB_ERR_INTERFACE, \
"%s(%u): corruption detected -- interface with this " \
"ifindex exists already in VRF %u!", \
__func__, (ifp)->ifindex, (ifp)->vrf_id);
#define IFINDEX_RB_REMOVE(vrf, ifp) \
if (RB_REMOVE(if_index_head, &vrf->ifaces_by_index, (ifp)) == NULL) \
- zlog_err( \
+ flog_err( \
+ LIB_ERR_INTERFACE, \
"%s(%u): corruption detected -- interface with this " \
"ifindex doesn't exist in VRF %u!", \
__func__, (ifp)->ifindex, (ifp)->vrf_id);
diff --git a/lib/json.h b/lib/json.h
index 675d852af7..788d1d6efa 100644
--- a/lib/json.h
+++ b/lib/json.h
@@ -23,6 +23,20 @@
#if defined(HAVE_JSON_C_JSON_H)
#include <json-c/json.h>
+
+/*
+ * FRR style JSON iteration.
+ * Usage: JSON_FOREACH(...) { ... }
+ */
+#define JSON_FOREACH(jo, joi, join) \
+ /* struct json_object *jo; */ \
+ /* struct json_object_iterator joi; */ \
+ /* struct json_object_iterator join; */ \
+ for ((joi) = json_object_iter_begin((jo)), \
+ (join) = json_object_iter_end((jo)); \
+ json_object_iter_equal(&(joi), &(join)) == 0; \
+ json_object_iter_next(&(joi)))
+
#else
#include <json/json.h>
diff --git a/lib/lib_errors.c b/lib/lib_errors.c
new file mode 100644
index 0000000000..332a5b1d45
--- /dev/null
+++ b/lib/lib_errors.c
@@ -0,0 +1,118 @@
+/*
+ * Library-specific error messages.
+ * Copyright (C) 2018 Cumulus Networks, Inc.
+ * Donald Sharp
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This 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 "lib_errors.h"
+
+/* clang-format off */
+static struct log_ref ferr_lib_err[] = {
+ {
+ .code = LIB_ERR_PRIVILEGES,
+ .title = "Failure to raise or lower privileges",
+ .description = "FRR attempted to raise or lower its privileges and was unable to do so",
+ .suggestion = "Ensure that you are running FRR as the frr user and that the user has sufficient privileges to properly access root privileges"
+ },
+ {
+ .code = LIB_ERR_VRF_START,
+ .title = "VRF Failure on Start",
+ .description = "Upon startup FRR failed to properly initialize and startup the VRF subsystem",
+ .suggestion = "Ensure that there is sufficient memory to start processes and restart FRR",
+ },
+ {
+ .code = LIB_ERR_SOCKET,
+ .title = "Socket Error",
+ .description = "When attempting to access a socket a system error has occured and we were unable to properly complete the request",
+ .suggestion = "Ensure that there are sufficient system resources available and ensure that the frr user has sufficient permisions to work",
+ },
+ {
+ .code = LIB_ERR_ZAPI_MISSMATCH,
+ .title = "ZAPI Error",
+ .description = "A version miss-match has been detected between zebra and client protocol",
+ .suggestion = "Two different versions of FRR have been installed and the install is not properly setup. Completely stop FRR, remove it from the system and reinstall. Typically only developers should see this issue."
+ },
+ {
+ .code = LIB_ERR_ZAPI_ENCODE,
+ .title = "ZAPI Error",
+ .description = "The ZAPI subsystem has detected an encoding issue, between zebra and a client protocol",
+ .suggestion = "Restart FRR"
+ },
+ {
+ .code = LIB_ERR_ZAPI_SOCKET,
+ .title = "ZAPI Error",
+ .description = "The ZAPI subsystem has detected a socket error between zebra and a client",
+ .suggestion = "Restart FRR"
+ },
+ {
+ .code = LIB_ERR_SYSTEM_CALL,
+ .title = "System Call Error",
+ .description = "FRR has detected a error from using a vital system call and has probably already exited",
+ .suggestion = "Ensure permissions are correct for FRR files, users and groups are correct. Additionally check that sufficient system resources are available."
+ },
+ {
+ .code = LIB_ERR_VTY,
+ .title = "VTY Subsystem Error",
+ .description = "FRR has detected a problem with the specified configuration file",
+ .suggestion = "Ensure configuration file exists and has correct permissions for operations Additionally ensure that all config lines are correct as well",
+ },
+ {
+ .code = LIB_ERR_SNMP,
+ .title = "SNMP Subsystem Error",
+ .description = "FRR has detected a problem with the snmp library it uses A callback from this subsystem has indicated some error",
+ .suggestion = "Examine callback message and ensure snmp is properly setup and working"
+ },
+ {
+ .code = LIB_ERR_INTERFACE,
+ .title = "Interface Subsystem Error",
+ .description = "FRR has detected a problem with interface data from the kernel as it deviates from what we would expect to happen via normal netlink messaging",
+ .suggestion = "Open an Issue with all relevant log files and restart FRR"
+ },
+ {
+ .code = LIB_ERR_NS,
+ .title = "NameSpace Subsystem Error",
+ .description = "FRR has detected a problem with NameSpace data from the kernel as it deviates from what we would expect to happen via normal kernel messaging",
+ .suggestion = "Open an Issue with all relevant log files and restart FRR"
+ },
+ {
+ .code = LIB_ERR_DEVELOPMENT,
+ .title = "Developmental Escape Error",
+ .description = "FRR has detected an issue where new development has not properly updated all code paths.",
+ .suggestion = "Open an Issue with all relevant log files"
+ },
+ {
+ .code = LIB_ERR_ZMQ,
+ .title = "ZMQ Subsystem Error",
+ .description = "FRR has detected an issue with the Zero MQ subsystem and ZeroMQ is not working properly now",
+ .suggestion = "Open an Issue with all relevant log files and restart FRR"
+ },
+ {
+ .code = LIB_ERR_UNAVAILABLE,
+ .title = "Feature or system unavailable",
+ .description = "FRR was not compiled with support for a particular feature, or it is not available on the current platform",
+ .suggestion = "Recompile FRR with the feature enabled, or find out what platforms support the feature"
+ },
+ {
+ .code = END_FERR,
+ }
+};
+/* clang-format on */
+
+void lib_error_init(void)
+{
+ log_ref_add(ferr_lib_err);
+}
diff --git a/lib/lib_errors.h b/lib/lib_errors.h
new file mode 100644
index 0000000000..84f5b8dc10
--- /dev/null
+++ b/lib/lib_errors.h
@@ -0,0 +1,45 @@
+/*
+ * Library-specific error messages.
+ * Copyright (C) 2018 Cumulus Networks, Inc.
+ * Donald Sharp
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; see the file COPYING; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef __LIB_ERRORS_H__
+#define __LIB_ERRORS_H__
+
+#include "lib/ferr.h"
+
+enum lib_log_refs {
+ LIB_ERR_PRIVILEGES = LIB_FERR_START,
+ LIB_ERR_VRF_START,
+ LIB_ERR_SOCKET,
+ LIB_ERR_ZAPI_MISSMATCH,
+ LIB_ERR_ZAPI_ENCODE,
+ LIB_ERR_ZAPI_SOCKET,
+ LIB_ERR_SYSTEM_CALL,
+ LIB_ERR_VTY,
+ LIB_ERR_SNMP,
+ LIB_ERR_INTERFACE,
+ LIB_ERR_NS,
+ LIB_ERR_DEVELOPMENT,
+ LIB_ERR_ZMQ,
+ LIB_ERR_UNAVAILABLE,
+};
+
+extern void lib_error_init(void);
+
+#endif
diff --git a/lib/libfrr.c b/lib/libfrr.c
index 86a5bd29f8..821c57f37b 100644
--- a/lib/libfrr.c
+++ b/lib/libfrr.c
@@ -35,6 +35,7 @@
#include "log_int.h"
#include "module.h"
#include "network.h"
+#include "lib_errors.h"
DEFINE_HOOK(frr_late_init, (struct thread_master * tm), (tm))
DEFINE_KOOH(frr_early_fini, (), ())
@@ -598,6 +599,9 @@ struct thread_master *frr_init(void)
vty_init(master);
memory_init();
+ log_ref_init();
+ lib_error_init();
+
return master;
}
@@ -825,8 +829,9 @@ static void frr_terminal_close(int isexit)
nullfd = open("/dev/null", O_RDONLY | O_NOCTTY);
if (nullfd == -1) {
- zlog_err("%s: failed to open /dev/null: %s", __func__,
- safe_strerror(errno));
+ flog_err_sys(LIB_ERR_SYSTEM_CALL,
+ "%s: failed to open /dev/null: %s", __func__,
+ safe_strerror(errno));
} else {
dup2(nullfd, 0);
dup2(nullfd, 1);
@@ -897,8 +902,9 @@ void frr_run(struct thread_master *master)
} else if (di->daemon_mode) {
int nullfd = open("/dev/null", O_RDONLY | O_NOCTTY);
if (nullfd == -1) {
- zlog_err("%s: failed to open /dev/null: %s", __func__,
- safe_strerror(errno));
+ flog_err_sys(LIB_ERR_SYSTEM_CALL,
+ "%s: failed to open /dev/null: %s",
+ __func__, safe_strerror(errno));
} else {
dup2(nullfd, 0);
dup2(nullfd, 1);
@@ -935,6 +941,7 @@ void frr_fini(void)
/* memory_init -> nothing needed */
vty_terminate();
cmd_terminate();
+ log_ref_fini();
zprivs_terminate(di->privs);
/* signal_init -> nothing needed */
thread_master_free(master);
diff --git a/lib/linklist.c b/lib/linklist.c
index 86649dd495..effd384e46 100644
--- a/lib/linklist.c
+++ b/lib/linklist.c
@@ -70,6 +70,26 @@ void listnode_add(struct list *list, void *val)
list->count++;
}
+void listnode_add_head(struct list *list, void *val)
+{
+ struct listnode *node;
+
+ assert(val != NULL);
+
+ node = listnode_new();
+
+ node->next = list->head;
+ node->data = val;
+
+ if (list->head == NULL)
+ list->head = node;
+ else
+ list->head->prev = node;
+ list->head = node;
+
+ list->count++;
+}
+
void listnode_add_sort(struct list *list, void *val)
{
struct listnode *n;
diff --git a/lib/linklist.h b/lib/linklist.h
index cee6c1e505..f5cd44efb0 100644
--- a/lib/linklist.h
+++ b/lib/linklist.h
@@ -83,6 +83,19 @@ extern struct list *list_new(void);
extern void listnode_add(struct list *list, void *data);
/*
+ * Add a new element to the beginning of a list.
+ *
+ * Runtime is O(1).
+ *
+ * list
+ * list to operate on
+ *
+ * data
+ * element to add
+ */
+extern void listnode_add_head(struct list *list, void *data);
+
+/*
* Insert a new element into a list with insertion sort.
*
* If list->cmp is set, this function is used to determine the position to
diff --git a/lib/log.c b/lib/log.c
index 1345ff2fd1..e011a78f1c 100644
--- a/lib/log.c
+++ b/lib/log.c
@@ -28,6 +28,8 @@
#include "log_int.h"
#include "memory.h"
#include "command.h"
+#include "lib_errors.h"
+
#ifndef SUNOS_5
#include <sys/un.h>
#endif
@@ -631,7 +633,8 @@ void zlog_backtrace(int priority)
size = backtrace(array, array_size(array));
if (size <= 0 || (size_t)size > array_size(array)) {
- zlog_err(
+ flog_err_sys(
+ LIB_ERR_SYSTEM_CALL,
"Cannot get backtrace, returned invalid # of frames %d "
"(valid range is between 1 and %lu)",
size, (unsigned long)(array_size(array)));
@@ -639,7 +642,8 @@ void zlog_backtrace(int priority)
}
zlog(priority, "Backtrace for %d stack frames:", size);
if (!(strings = backtrace_symbols(array, size))) {
- zlog_err("Cannot get backtrace symbols (out of memory?)");
+ flog_err_sys(LIB_ERR_SYSTEM_CALL,
+ "Cannot get backtrace symbols (out of memory?)");
for (i = 0; i < size; i++)
zlog(priority, "[bt %d] %p", i, array[i]);
} else {
@@ -712,10 +716,10 @@ void _zlog_assert_failed(const char *assertion, const char *file,
void memory_oom(size_t size, const char *name)
{
- zlog_err(
- "out of memory: failed to allocate %zu bytes for %s"
- "object",
- size, name);
+ flog_err_sys(LIB_ERR_SYSTEM_CALL,
+ "out of memory: failed to allocate %zu bytes for %s"
+ "object",
+ size, name);
zlog_backtrace(LOG_ERR);
abort();
}
@@ -864,7 +868,8 @@ int zlog_rotate(void)
save_errno = errno;
umask(oldumask);
if (zl->fp == NULL) {
- zlog_err(
+ flog_err_sys(
+ LIB_ERR_SYSTEM_CALL,
"Log rotate failed: cannot open file %s for append: %s",
zl->filename, safe_strerror(save_errno));
ret = -1;
@@ -984,7 +989,8 @@ static const struct zebra_desc_table *zroute_lookup(unsigned int zroute)
unsigned int i;
if (zroute >= array_size(route_types)) {
- zlog_err("unknown zebra route type: %u", zroute);
+ flog_err(LIB_ERR_DEVELOPMENT, "unknown zebra route type: %u",
+ zroute);
return &unknown;
}
if (zroute == route_types[zroute].type)
@@ -998,7 +1004,9 @@ static const struct zebra_desc_table *zroute_lookup(unsigned int zroute)
return &route_types[i];
}
}
- zlog_err("internal error: cannot find route type %u in table!", zroute);
+ flog_err(LIB_ERR_DEVELOPMENT,
+ "internal error: cannot find route type %u in table!",
+ zroute);
return &unknown;
}
@@ -1015,7 +1023,8 @@ char zebra_route_char(unsigned int zroute)
const char *zserv_command_string(unsigned int command)
{
if (command >= array_size(command_types)) {
- zlog_err("unknown zserv command type: %u", command);
+ flog_err(LIB_ERR_DEVELOPMENT, "unknown zserv command type: %u",
+ command);
return unknown.string;
}
return command_types[command].string;
diff --git a/lib/log.h b/lib/log.h
index 07eb6d5bd5..980f3ddf4b 100644
--- a/lib/log.h
+++ b/lib/log.h
@@ -85,6 +85,13 @@ extern void zlog_info(const char *format, ...) PRINTF_ATTRIBUTE(1, 2);
extern void zlog_notice(const char *format, ...) PRINTF_ATTRIBUTE(1, 2);
extern void zlog_debug(const char *format, ...) PRINTF_ATTRIBUTE(1, 2);
+/* For logs which have error codes associated with them */
+#define flog_err(ferr_id, format, ...) \
+ zlog_err("[EC %d] " format, ferr_id, ##__VA_ARGS__)
+#define flog_err_sys(ferr_id, format, ...) \
+ flog_err(ferr_id, format, ##__VA_ARGS__)
+
+
extern void zlog_thread_info(int log_level);
/* Set logging level for the given destination. If the log_level
diff --git a/lib/memory.c b/lib/memory.c
index e279b17d12..87cba69fc5 100644
--- a/lib/memory.c
+++ b/lib/memory.c
@@ -17,6 +17,12 @@
#include <zebra.h>
#include <stdlib.h>
+#ifdef HAVE_MALLOC_H
+#include <malloc.h>
+#endif
+#ifdef HAVE_MALLOC_MALLOC_H
+#include <malloc/malloc.h>
+#endif
#include "memory.h"
#include "log.h"
@@ -28,7 +34,7 @@ DEFINE_MGROUP(LIB, "libfrr")
DEFINE_MTYPE(LIB, TMP, "Temporary memory")
DEFINE_MTYPE(LIB, PREFIX_FLOWSPEC, "Prefix Flowspec")
-static inline void mt_count_alloc(struct memtype *mt, size_t size)
+static inline void mt_count_alloc(struct memtype *mt, size_t size, void *ptr)
{
size_t oldsize;
@@ -41,12 +47,24 @@ static inline void mt_count_alloc(struct memtype *mt, size_t size)
if (oldsize != 0 && oldsize != size && oldsize != SIZE_VAR)
atomic_store_explicit(&mt->size, SIZE_VAR,
memory_order_relaxed);
+
+#ifdef HAVE_MALLOC_USABLE_SIZE
+ size_t mallocsz = malloc_usable_size(ptr);
+
+ atomic_fetch_add_explicit(&mt->total, mallocsz, memory_order_relaxed);
+#endif
}
-static inline void mt_count_free(struct memtype *mt)
+static inline void mt_count_free(struct memtype *mt, void *ptr)
{
assert(mt->n_alloc);
atomic_fetch_sub_explicit(&mt->n_alloc, 1, memory_order_relaxed);
+
+#ifdef HAVE_MALLOC_USABLE_SIZE
+ size_t mallocsz = malloc_usable_size(ptr);
+
+ atomic_fetch_sub_explicit(&mt->total, mallocsz, memory_order_relaxed);
+#endif
}
static inline void *mt_checkalloc(struct memtype *mt, void *ptr, size_t size)
@@ -58,7 +76,7 @@ static inline void *mt_checkalloc(struct memtype *mt, void *ptr, size_t size)
}
return NULL;
}
- mt_count_alloc(mt, size);
+ mt_count_alloc(mt, size, ptr);
return ptr;
}
@@ -75,7 +93,7 @@ void *qcalloc(struct memtype *mt, size_t size)
void *qrealloc(struct memtype *mt, void *ptr, size_t size)
{
if (ptr)
- mt_count_free(mt);
+ mt_count_free(mt, ptr);
return mt_checkalloc(mt, ptr ? realloc(ptr, size) : malloc(size), size);
}
@@ -87,7 +105,7 @@ void *qstrdup(struct memtype *mt, const char *str)
void qfree(struct memtype *mt, void *ptr)
{
if (ptr)
- mt_count_free(mt);
+ mt_count_free(mt, ptr);
free(ptr);
}
diff --git a/lib/memory.h b/lib/memory.h
index 1fbbbe4231..c39f34e3a7 100644
--- a/lib/memory.h
+++ b/lib/memory.h
@@ -24,12 +24,20 @@
#define array_size(ar) (sizeof(ar) / sizeof(ar[0]))
+#if defined(HAVE_MALLOC_SIZE) && !defined(HAVE_MALLOC_USABLE_SIZE)
+#define malloc_usable_size(x) malloc_size(x)
+#define HAVE_MALLOC_USABLE_SIZE
+#endif
+
#define SIZE_VAR ~0UL
struct memtype {
struct memtype *next, **ref;
const char *name;
_Atomic size_t n_alloc;
_Atomic size_t size;
+#ifdef HAVE_MALLOC_USABLE_SIZE
+ _Atomic size_t total;
+#endif
};
struct memgroup {
diff --git a/lib/memory_vty.c b/lib/memory_vty.c
index 972914bf24..9ee2e52ec7 100644
--- a/lib/memory_vty.c
+++ b/lib/memory_vty.c
@@ -21,9 +21,12 @@
#include <zebra.h>
/* malloc.h is generally obsolete, however GNU Libc mallinfo wants it. */
-#if (defined(GNU_LINUX) && defined(HAVE_MALLINFO))
+#ifdef HAVE_MALLOC_H
#include <malloc.h>
-#endif /* HAVE_MALLINFO */
+#endif
+#ifdef HAVE_MALLOC_MALLOC_H
+#include <malloc/malloc.h>
+#endif
#include <dlfcn.h>
#include <link.h>
@@ -76,12 +79,21 @@ static int qmem_walker(void *arg, struct memgroup *mg, struct memtype *mt)
if (mt->n_alloc != 0) {
char size[32];
snprintf(size, sizeof(size), "%6zu", mt->size);
- vty_out(vty, "%-30s: %10zu %s\n", mt->name,
+
+#ifdef HAVE_MALLOC_USABLE_SIZE
+#define TSTR " %9zu"
+#define TARG , mt->total
+#else
+#define TSTR ""
+#define TARG
+#endif
+ vty_out(vty, "%-30s: %10zu %-16s"TSTR"\n", mt->name,
mt->n_alloc,
mt->size == 0 ? ""
: mt->size == SIZE_VAR
? "(variably sized)"
- : size);
+ : size
+ TARG);
}
}
return 0;
diff --git a/lib/mpls.h b/lib/mpls.h
index ff6f1d6c98..c9dd60dce0 100644
--- a/lib/mpls.h
+++ b/lib/mpls.h
@@ -22,6 +22,7 @@
#ifndef _QUAGGA_MPLS_H
#define _QUAGGA_MPLS_H
+#include <zebra.h>
#include <arpa/inet.h>
#ifdef MPLS_LABEL_MAX
diff --git a/lib/netns_linux.c b/lib/netns_linux.c
index a80b51fa00..b8eaa72c22 100644
--- a/lib/netns_linux.c
+++ b/lib/netns_linux.c
@@ -35,10 +35,10 @@
#include "ns.h"
#include "log.h"
#include "memory.h"
-
#include "command.h"
#include "vty.h"
#include "vrf.h"
+#include "lib_errors.h"
DEFINE_MTYPE_STATIC(LIB, NS, "NetNS Context")
DEFINE_MTYPE_STATIC(LIB, NS_NAME, "NetNS Name")
@@ -219,15 +219,17 @@ static int ns_enable_internal(struct ns *ns, void (*func)(ns_id_t, void *))
}
if (!ns_is_enabled(ns)) {
- zlog_err("Can not enable NS %u: %s!", ns->ns_id,
- safe_strerror(errno));
+ flog_err_sys(LIB_ERR_SYSTEM_CALL,
+ "Can not enable NS %u: %s!", ns->ns_id,
+ safe_strerror(errno));
return 0;
}
/* Non default NS. leave */
if (ns->ns_id == NS_UNKNOWN) {
- zlog_err("Can not enable NS %s %u: Invalid NSID",
- ns->name, ns->ns_id);
+ flog_err(LIB_ERR_NS,
+ "Can not enable NS %s %u: Invalid NSID",
+ ns->name, ns->ns_id);
return 0;
}
if (func)
@@ -470,8 +472,9 @@ void ns_init(void)
if (have_netns_enabled < 0) {
ns_default_ns_fd = open(NS_DEFAULT_NAME, O_RDONLY);
if (ns_default_ns_fd == -1)
- zlog_err("NS initialization failure %d(%s)",
- errno, safe_strerror(errno));
+ flog_err(LIB_ERR_NS,
+ "NS initialization failure %d(%s)", errno,
+ safe_strerror(errno));
} else {
ns_default_ns_fd = -1;
default_ns = NULL;
@@ -492,7 +495,8 @@ void ns_init_management(ns_id_t default_ns_id, ns_id_t internal_ns)
ns_init();
default_ns = ns_get_created_internal(NULL, NULL, default_ns_id);
if (!default_ns) {
- zlog_err("%s: failed to create the default NS!", __func__);
+ flog_err(LIB_ERR_NS, "%s: failed to create the default NS!",
+ __func__);
exit(1);
}
if (have_netns()) {
@@ -509,7 +513,8 @@ void ns_init_management(ns_id_t default_ns_id, ns_id_t internal_ns)
/* Enable the default NS. */
if (!ns_enable(default_ns, NULL)) {
- zlog_err("%s: failed to enable the default NS!", __func__);
+ flog_err(LIB_ERR_NS, "%s: failed to enable the default NS!",
+ __func__);
exit(1);
}
}
diff --git a/lib/pid_output.c b/lib/pid_output.c
index 023a166f27..c6120de861 100644
--- a/lib/pid_output.c
+++ b/lib/pid_output.c
@@ -24,6 +24,7 @@
#include <log.h>
#include "version.h"
#include "network.h"
+#include "lib_errors.h"
#define PIDFILE_MASK 0644
@@ -41,8 +42,9 @@ pid_t pid_output(const char *path)
oldumask = umask(0777 & ~PIDFILE_MASK);
fd = open(path, O_RDWR | O_CREAT, PIDFILE_MASK);
if (fd < 0) {
- zlog_err("Can't create pid lock file %s (%s), exiting", path,
- safe_strerror(errno));
+ flog_err_sys(LIB_ERR_SYSTEM_CALL,
+ "Can't create pid lock file %s (%s), exiting",
+ path, safe_strerror(errno));
umask(oldumask);
exit(1);
} else {
@@ -57,19 +59,22 @@ pid_t pid_output(const char *path)
lock.l_whence = SEEK_SET;
if (fcntl(fd, F_SETLK, &lock) < 0) {
- zlog_err("Could not lock pid_file %s (%s), exiting",
- path, safe_strerror(errno));
+ flog_err_sys(LIB_ERR_SYSTEM_CALL,
+ "Could not lock pid_file %s (%s), exiting",
+ path, safe_strerror(errno));
exit(1);
}
sprintf(buf, "%d\n", (int)pid);
pidsize = strlen(buf);
if ((tmp = write(fd, buf, pidsize)) != (int)pidsize)
- zlog_err(
+ flog_err_sys(
+ LIB_ERR_SYSTEM_CALL,
"Could not write pid %d to pid_file %s, rc was %d: %s",
(int)pid, path, tmp, safe_strerror(errno));
else if (ftruncate(fd, pidsize) < 0)
- zlog_err(
+ flog_err_sys(
+ LIB_ERR_SYSTEM_CALL,
"Could not truncate pid_file %s to %u bytes: %s",
path, (unsigned int)pidsize,
safe_strerror(errno));
diff --git a/lib/prefix.c b/lib/prefix.c
index 751f20cb83..a7f4fda1b2 100644
--- a/lib/prefix.c
+++ b/lib/prefix.c
@@ -27,6 +27,7 @@
#include "memory.h"
#include "log.h"
#include "jhash.h"
+#include "lib_errors.h"
DEFINE_MTYPE_STATIC(LIB, PREFIX, "Prefix")
@@ -656,8 +657,9 @@ void prefix_copy(struct prefix *dest, const struct prefix *src)
memcpy((void *)dest->u.prefix_flowspec.ptr,
(void *)src->u.prefix_flowspec.ptr, len);
} else {
- zlog_err("prefix_copy(): Unknown address family %d",
- src->family);
+ flog_err(LIB_ERR_DEVELOPMENT,
+ "prefix_copy(): Unknown address family %d",
+ src->family);
assert(0);
}
}
diff --git a/lib/privs.c b/lib/privs.c
index 7c99742d34..34905ca480 100644
--- a/lib/privs.c
+++ b/lib/privs.c
@@ -696,6 +696,41 @@ static int getgrouplist(const char *user, gid_t group, gid_t *groups,
}
#endif /* HAVE_GETGROUPLIST */
+struct zebra_privs_t *_zprivs_raise(struct zebra_privs_t *privs,
+ const char *funcname)
+{
+ int save_errno = errno;
+
+ if (!privs)
+ return NULL;
+
+ errno = 0;
+ if (privs->change(ZPRIVS_RAISE)) {
+ zlog_err("%s: Failed to raise privileges (%s)",
+ funcname, safe_strerror(errno));
+ }
+ errno = save_errno;
+ privs->raised_in_funcname = funcname;
+ return privs;
+}
+
+void _zprivs_lower(struct zebra_privs_t **privs)
+{
+ int save_errno = errno;
+
+ if (!*privs)
+ return;
+
+ errno = 0;
+ if ((*privs)->change(ZPRIVS_LOWER)) {
+ zlog_err("%s: Failed to lower privileges (%s)",
+ (*privs)->raised_in_funcname, safe_strerror(errno));
+ }
+ errno = save_errno;
+ (*privs)->raised_in_funcname = NULL;
+ *privs = NULL;
+}
+
void zprivs_preinit(struct zebra_privs_t *zprivs)
{
struct passwd *pwentry = NULL;
diff --git a/lib/privs.h b/lib/privs.h
index 7fe59328b2..b061370b75 100644
--- a/lib/privs.h
+++ b/lib/privs.h
@@ -62,6 +62,7 @@ struct zebra_privs_t {
int (*change)(zebra_privs_ops_t); /* change privileges, 0 on success */
zebra_privs_current_t (*current_state)(
void); /* current privilege state */
+ const char *raised_in_funcname;
};
struct zprivs_ids_t {
@@ -81,4 +82,42 @@ extern void zprivs_terminate(struct zebra_privs_t *);
/* query for runtime uid's and gid's, eg vty needs this */
extern void zprivs_get_ids(struct zprivs_ids_t *);
+/*
+ * Wrapper around zprivs, to be used as:
+ * frr_elevate_privs(&privs) {
+ * ... code ...
+ * if (error)
+ * break; -- break can be used to get out of the block
+ * ... code ...
+ * }
+ *
+ * The argument to frr_elevate_privs() can be NULL to leave privileges as-is
+ * (mostly useful for conditional privilege-raising, i.e.:)
+ * frr_elevate_privs(cond ? &privs : NULL) {}
+ *
+ * NB: The code block is always executed, regardless of whether privileges
+ * could be raised or not, or whether NULL was given or not. This is fully
+ * intentional; the user may have configured some RBAC or similar that we
+ * are not aware of, but that allows our code to proceed without privileges.
+ *
+ * The point of this wrapper is to prevent accidental bugs where privileges
+ * are elevated but then not dropped. This can happen when, for example, a
+ * "return", "goto" or "break" in the middle of the elevated-privilege code
+ * skips past the privilege dropping call.
+ *
+ * The macro below uses variable cleanup to drop privileges as soon as the
+ * code block is left in any way (and thus the _privs variable goes out of
+ * scope.) _once is just a trick to run the loop exactly once.
+ */
+extern struct zebra_privs_t *_zprivs_raise(struct zebra_privs_t *privs,
+ const char *funcname);
+extern void _zprivs_lower(struct zebra_privs_t **privs);
+
+#define frr_elevate_privs(privs) \
+ for (struct zebra_privs_t *_once = NULL, \
+ *_privs __attribute__( \
+ (unused, cleanup(_zprivs_lower))) = \
+ _zprivs_raise(privs, __func__); \
+ _once == NULL; _once = (void *)1)
+
#endif /* _ZEBRA_PRIVS_H */
diff --git a/lib/route_types.txt b/lib/route_types.txt
index cfa55e468c..72f59a1b78 100644
--- a/lib/route_types.txt
+++ b/lib/route_types.txt
@@ -81,6 +81,7 @@ ZEBRA_ROUTE_BGP_DIRECT_EXT, bgp-direct-to-nve-groups, NULL, 'e', 0, 0, 0, "BGP2V
ZEBRA_ROUTE_BABEL, babel, babeld, 'A', 1, 1, 1, "Babel"
ZEBRA_ROUTE_SHARP, sharp, sharpd, 'D', 1, 1, 1, "SHARP"
ZEBRA_ROUTE_PBR, pbr, pbrd, 'F', 1, 1, 0, "PBR"
+ZEBRA_ROUTE_BFD, bfd, bfdd, '-', 0, 0, 0, "BFD"
ZEBRA_ROUTE_ALL, wildcard, none, '-', 0, 0, 0, "-"
@@ -107,3 +108,4 @@ ZEBRA_ROUTE_VNC_DIRECT, "VNC direct (not via zebra) routes"
ZEBRA_ROUTE_BABEL, "Babel routing protocol (Babel)"
ZEBRA_ROUTE_SHARP, "Super Happy Advanced Routing Protocol (sharpd)"
ZEBRA_ROUTE_PBR, "Policy Based Routing (PBR)"
+ZEBRA_ROUTE_BFD, "Bidirectional Fowarding Detection (BFD)"
diff --git a/lib/sigevent.c b/lib/sigevent.c
index 59eaa80370..0346027935 100644
--- a/lib/sigevent.c
+++ b/lib/sigevent.c
@@ -22,6 +22,7 @@
#include <sigevent.h>
#include <log.h>
#include <memory.h>
+#include <lib_errors.h>
#ifdef SA_SIGINFO
#ifdef HAVE_UCONTEXT_H
@@ -83,7 +84,8 @@ int quagga_sigevent_process(void)
sigdelset(&newmask, SIGKILL);
if ((sigprocmask(SIG_BLOCK, &newmask, &oldmask)) < 0) {
- zlog_err("quagga_signal_timer: couldnt block signals!");
+ flog_err_sys(LIB_ERR_SYSTEM_CALL,
+ "quagga_signal_timer: couldnt block signals!");
return -1;
}
#endif /* SIGEVENT_BLOCK_SIGNALS */
diff --git a/lib/skiplist.c b/lib/skiplist.c
index a546bb44c0..a36bf47139 100644
--- a/lib/skiplist.c
+++ b/lib/skiplist.c
@@ -60,6 +60,7 @@
#include "log.h"
#include "vty.h"
#include "skiplist.h"
+#include "lib_errors.h"
DEFINE_MTYPE_STATIC(LIB, SKIP_LIST, "Skip List")
DEFINE_MTYPE_STATIC(LIB, SKIP_LIST_NODE, "Skip Node")
@@ -182,7 +183,8 @@ int skiplist_insert(register struct skiplist *l, register void *key,
/* DEBUG */
if (!key) {
- zlog_err("%s: key is 0, value is %p", __func__, value);
+ flog_err(LIB_ERR_DEVELOPMENT, "%s: key is 0, value is %p",
+ __func__, value);
}
p = l->header;
diff --git a/lib/sockopt.c b/lib/sockopt.c
index e979bef174..878b5ae09d 100644
--- a/lib/sockopt.c
+++ b/lib/sockopt.c
@@ -27,6 +27,7 @@
#include "log.h"
#include "sockopt.h"
#include "sockunion.h"
+#include "lib_errors.h"
void setsockopt_so_recvbuf(int sock, int size)
{
@@ -61,8 +62,9 @@ int getsockopt_so_sendbuf(const int sock)
int ret = getsockopt(sock, SOL_SOCKET, SO_SNDBUF, (char *)&optval,
&optlen);
if (ret < 0) {
- zlog_err("fd %d: can't getsockopt SO_SNDBUF: %d (%s)", sock,
- errno, safe_strerror(errno));
+ flog_err_sys(LIB_ERR_SYSTEM_CALL,
+ "fd %d: can't getsockopt SO_SNDBUF: %d (%s)", sock,
+ errno, safe_strerror(errno));
return ret;
}
return optval;
@@ -73,7 +75,7 @@ static void *getsockopt_cmsg_data(struct msghdr *msgh, int level, int type)
struct cmsghdr *cmsg;
void *ptr = NULL;
- for (cmsg = ZCMSG_FIRSTHDR(msgh); cmsg != NULL;
+ for (cmsg = CMSG_FIRSTHDR(msgh); cmsg != NULL;
cmsg = CMSG_NXTHDR(msgh, cmsg))
if (cmsg->cmsg_level == level && cmsg->cmsg_type == type)
return (ptr = CMSG_DATA(cmsg));
@@ -670,8 +672,10 @@ int sockopt_tcp_signature(int sock, union sockunion *su, const char *password)
if (ENOENT == errno)
ret = 0;
else
- zlog_err("sockopt_tcp_signature: setsockopt(%d): %s",
- sock, safe_strerror(errno));
+ flog_err_sys(
+ LIB_ERR_SYSTEM_CALL,
+ "sockopt_tcp_signature: setsockopt(%d): %s",
+ sock, safe_strerror(errno));
}
return ret;
#else /* HAVE_TCP_MD5SIG */
diff --git a/lib/sockunion.c b/lib/sockunion.c
index 44378b5363..bbbfbfc424 100644
--- a/lib/sockunion.c
+++ b/lib/sockunion.c
@@ -26,6 +26,7 @@
#include "memory.h"
#include "log.h"
#include "jhash.h"
+#include "lib_errors.h"
DEFINE_MTYPE_STATIC(LIB, SOCKUNION, "Socket union")
@@ -365,14 +366,10 @@ int sockopt_mark_default(int sock, int mark, struct zebra_privs_t *cap)
#ifdef SO_MARK
int ret;
- if (cap->change(ZPRIVS_RAISE))
- zlog_err("routing_socket: Can't raise privileges");
-
- ret = setsockopt(sock, SOL_SOCKET, SO_MARK, &mark, sizeof(mark));
-
- if (cap->change(ZPRIVS_LOWER))
- zlog_err("routing_socket: Can't lower privileges");
-
+ frr_elevate_privs(cap) {
+ ret = setsockopt(sock, SOL_SOCKET, SO_MARK, &mark,
+ sizeof(mark));
+ }
return ret;
#else
return 0;
diff --git a/lib/subdir.am b/lib/subdir.am
index 9eaae59df8..b938dbcea3 100644
--- a/lib/subdir.am
+++ b/lib/subdir.am
@@ -35,6 +35,7 @@ lib_libfrr_la_SOURCES = \
lib/jhash.c \
lib/json.c \
lib/keychain.c \
+ lib/lib_errors.c \
lib/libfrr.c \
lib/linklist.c \
lib/log.c \
@@ -118,6 +119,7 @@ pkginclude_HEADERS += \
lib/jhash.h \
lib/json.h \
lib/keychain.h \
+ lib/lib_errors.h \
lib/libfrr.h \
lib/libospf.h \
lib/linklist.h \
diff --git a/lib/vrf.c b/lib/vrf.c
index ca50c1e70e..36111dfeae 100644
--- a/lib/vrf.c
+++ b/lib/vrf.c
@@ -35,6 +35,7 @@
#include "ns.h"
#include "privs.h"
#include "nexthop_group.h"
+#include "lib_errors.h"
/* default VRF ID value used when VRF backend is not NETNS */
#define VRF_DEFAULT_INTERNAL 0
@@ -466,13 +467,15 @@ void vrf_init(int (*create)(struct vrf *), int (*enable)(struct vrf *),
/* The default VRF always exists. */
default_vrf = vrf_get(VRF_DEFAULT, VRF_DEFAULT_NAME);
if (!default_vrf) {
- zlog_err("vrf_init: failed to create the default VRF!");
+ flog_err(LIB_ERR_VRF_START,
+ "vrf_init: failed to create the default VRF!");
exit(1);
}
/* Enable the default VRF. */
if (!vrf_enable(default_vrf)) {
- zlog_err("vrf_init: failed to enable the default VRF!");
+ flog_err(LIB_ERR_VRF_START,
+ "vrf_init: failed to enable the default VRF!");
exit(1);
}
@@ -542,20 +545,23 @@ int vrf_socket(int domain, int type, int protocol, vrf_id_t vrf_id,
ret = vrf_switch_to_netns(vrf_id);
if (ret < 0)
- zlog_err("%s: Can't switch to VRF %u (%s)", __func__, vrf_id,
- safe_strerror(errno));
+ flog_err_sys(LIB_ERR_SOCKET, "%s: Can't switch to VRF %u (%s)",
+ __func__, vrf_id, safe_strerror(errno));
+
if (ret > 0 && interfacename && vrf_default_accepts_vrf(type)) {
zlog_err("VRF socket not used since net.ipv4.%s_l3mdev_accept != 0",
(type == SOCK_STREAM ? "tcp" : "udp"));
errno = EEXIST; /* not sure if this is the best error... */
return -2;
}
+
ret = socket(domain, type, protocol);
save_errno = errno;
ret2 = vrf_switchback_to_initial();
if (ret2 < 0)
- zlog_err("%s: Can't switchback from VRF %u (%s)", __func__,
- vrf_id, safe_strerror(errno));
+ flog_err_sys(LIB_ERR_SOCKET,
+ "%s: Can't switchback from VRF %u (%s)", __func__,
+ vrf_id, safe_strerror(errno));
errno = save_errno;
if (ret <= 0)
return ret;
@@ -711,12 +717,12 @@ DEFUN_NOSH (vrf,
return vrf_handler_create(vty, vrfname, NULL);
}
-DEFUN_NOSH (no_vrf,
- no_vrf_cmd,
- "no vrf NAME",
- NO_STR
- "Delete a pseudo VRF's configuration\n"
- "VRF's name\n")
+DEFUN (no_vrf,
+ no_vrf_cmd,
+ "no vrf NAME",
+ NO_STR
+ "Delete a pseudo VRF's configuration\n"
+ "VRF's name\n")
{
const char *vrfname = argv[2]->arg;
@@ -744,7 +750,7 @@ DEFUN_NOSH (no_vrf,
struct cmd_node vrf_node = {VRF_NODE, "%s(config-vrf)# ", 1};
-DEFUN (vrf_netns,
+DEFUN_NOSH (vrf_netns,
vrf_netns_cmd,
"netns NAME",
"Attach VRF to a Namespace\n"
@@ -758,20 +764,14 @@ DEFUN (vrf_netns,
if (!pathname)
return CMD_WARNING_CONFIG_FAILED;
- if (vrf_daemon_privs &&
- vrf_daemon_privs->change(ZPRIVS_RAISE))
- zlog_err("%s: Can't raise privileges", __func__);
-
- ret = vrf_netns_handler_create(vty, vrf, pathname,
- NS_UNKNOWN, NS_UNKNOWN);
-
- if (vrf_daemon_privs &&
- vrf_daemon_privs->change(ZPRIVS_LOWER))
- zlog_err("%s: Can't lower privileges", __func__);
+ frr_elevate_privs(vrf_daemon_privs) {
+ ret = vrf_netns_handler_create(vty, vrf, pathname,
+ NS_UNKNOWN, NS_UNKNOWN);
+ }
return ret;
}
-DEFUN (no_vrf_netns,
+DEFUN_NOSH (no_vrf_netns,
no_vrf_netns_cmd,
"no netns [NAME]",
NO_STR
@@ -905,14 +905,15 @@ int vrf_getaddrinfo(const char *node, const char *service,
ret = vrf_switch_to_netns(vrf_id);
if (ret < 0)
- zlog_err("%s: Can't switch to VRF %u (%s)", __func__, vrf_id,
- safe_strerror(errno));
+ flog_err_sys(LIB_ERR_SOCKET, "%s: Can't switch to VRF %u (%s)",
+ __func__, vrf_id, safe_strerror(errno));
ret = getaddrinfo(node, service, hints, res);
save_errno = errno;
ret2 = vrf_switchback_to_initial();
if (ret2 < 0)
- zlog_err("%s: Can't switchback from VRF %u (%s)", __func__,
- vrf_id, safe_strerror(errno));
+ flog_err_sys(LIB_ERR_SOCKET,
+ "%s: Can't switchback from VRF %u (%s)", __func__,
+ vrf_id, safe_strerror(errno));
errno = save_errno;
return ret;
}
@@ -923,16 +924,17 @@ int vrf_ioctl(vrf_id_t vrf_id, int d, unsigned long request, char *params)
ret = vrf_switch_to_netns(vrf_id);
if (ret < 0) {
- zlog_err("%s: Can't switch to VRF %u (%s)", __func__, vrf_id,
- safe_strerror(errno));
+ flog_err_sys(LIB_ERR_SOCKET, "%s: Can't switch to VRF %u (%s)",
+ __func__, vrf_id, safe_strerror(errno));
return 0;
}
rc = ioctl(d, request, params);
saved_errno = errno;
ret = vrf_switchback_to_initial();
if (ret < 0)
- zlog_err("%s: Can't switchback from VRF %u (%s)", __func__,
- vrf_id, safe_strerror(errno));
+ flog_err_sys(LIB_ERR_SOCKET,
+ "%s: Can't switchback from VRF %u (%s)", __func__,
+ vrf_id, safe_strerror(errno));
errno = saved_errno;
return rc;
}
@@ -944,14 +946,15 @@ int vrf_sockunion_socket(const union sockunion *su, vrf_id_t vrf_id,
ret = vrf_switch_to_netns(vrf_id);
if (ret < 0)
- zlog_err("%s: Can't switch to VRF %u (%s)", __func__, vrf_id,
- safe_strerror(errno));
+ flog_err_sys(LIB_ERR_SOCKET, "%s: Can't switch to VRF %u (%s)",
+ __func__, vrf_id, safe_strerror(errno));
ret = sockunion_socket(su);
save_errno = errno;
ret2 = vrf_switchback_to_initial();
if (ret2 < 0)
- zlog_err("%s: Can't switchback from VRF %u (%s)", __func__,
- vrf_id, safe_strerror(errno));
+ flog_err_sys(LIB_ERR_SOCKET,
+ "%s: Can't switchback from VRF %u (%s)", __func__,
+ vrf_id, safe_strerror(errno));
errno = save_errno;
if (ret <= 0)
diff --git a/lib/vty.c b/lib/vty.c
index 073092dfb6..748c14f675 100644
--- a/lib/vty.c
+++ b/lib/vty.c
@@ -40,6 +40,7 @@
#include "network.h"
#include "libfrr.h"
#include "frrstr.h"
+#include "lib_errors.h"
#include <arpa/telnet.h>
#include <termios.h>
@@ -511,7 +512,7 @@ static int vty_command(struct vty *vty, char *buf)
vty_str);
/* now log the command */
- zlog_err("%s%s", prompt_str, buf);
+ zlog_notice("%s%s", prompt_str, buf);
}
#ifdef CONSUMED_TIME_CHECK
@@ -814,6 +815,8 @@ static void vty_end_config(struct vty *vty)
case KEYCHAIN_KEY_NODE:
case VTY_NODE:
case BGP_EVPN_VNI_NODE:
+ case BFD_NODE:
+ case BFD_PEER_NODE:
vty_config_unlock(vty);
vty->node = ENABLE_NODE;
break;
@@ -1210,6 +1213,8 @@ static void vty_stop_input(struct vty *vty)
case KEYCHAIN_NODE:
case KEYCHAIN_KEY_NODE:
case VTY_NODE:
+ case BFD_NODE:
+ case BFD_PEER_NODE:
vty_config_unlock(vty);
vty->node = ENABLE_NODE;
break;
@@ -1325,9 +1330,9 @@ static int vty_telnet_option(struct vty *vty, unsigned char *buf, int nbytes)
TELNET_NAWS_SB_LEN,
(unsigned long)vty->sb_len);
else if (sizeof(vty->sb_buf) < TELNET_NAWS_SB_LEN)
- zlog_err(
- "Bug detected: sizeof(vty->sb_buf) %lu < %d, "
- "too small to handle the telnet NAWS option",
+ flog_err(
+ LIB_ERR_DEVELOPMENT,
+ "Bug detected: sizeof(vty->sb_buf) %lu < %d, too small to handle the telnet NAWS option",
(unsigned long)sizeof(vty->sb_buf),
TELNET_NAWS_SB_LEN);
else {
@@ -1968,7 +1973,8 @@ static void vty_serv_sock_addrinfo(const char *hostname, unsigned short port)
ret = getaddrinfo(hostname, port_str, &req, &ainfo);
if (ret != 0) {
- zlog_err("getaddrinfo failed: %s", gai_strerror(ret));
+ flog_err_sys(LIB_ERR_SYSTEM_CALL, "getaddrinfo failed: %s",
+ gai_strerror(ret));
exit(1);
}
@@ -2028,8 +2034,9 @@ static void vty_serv_un(const char *path)
/* Make UNIX domain socket. */
sock = socket(AF_UNIX, SOCK_STREAM, 0);
if (sock < 0) {
- zlog_err("Cannot create unix stream socket: %s",
- safe_strerror(errno));
+ flog_err_sys(LIB_ERR_SOCKET,
+ "Cannot create unix stream socket: %s",
+ safe_strerror(errno));
return;
}
@@ -2047,15 +2054,16 @@ static void vty_serv_un(const char *path)
ret = bind(sock, (struct sockaddr *)&serv, len);
if (ret < 0) {
- zlog_err("Cannot bind path %s: %s", path, safe_strerror(errno));
+ flog_err_sys(LIB_ERR_SOCKET, "Cannot bind path %s: %s", path,
+ safe_strerror(errno));
close(sock); /* Avoid sd leak. */
return;
}
ret = listen(sock, 5);
if (ret < 0) {
- zlog_err("listen(fd %d) failed: %s", sock,
- safe_strerror(errno));
+ flog_err_sys(LIB_ERR_SOCKET, "listen(fd %d) failed: %s", sock,
+ safe_strerror(errno));
close(sock); /* Avoid sd leak. */
return;
}
@@ -2070,8 +2078,9 @@ static void vty_serv_un(const char *path)
if ((int)ids.gid_vty > 0) {
/* set group of socket */
if (chown(path, -1, ids.gid_vty)) {
- zlog_err("vty_serv_un: could chown socket, %s",
- safe_strerror(errno));
+ flog_err_sys(LIB_ERR_SYSTEM_CALL,
+ "vty_serv_un: could chown socket, %s",
+ safe_strerror(errno));
}
}
@@ -2303,9 +2312,9 @@ void vty_close(struct vty *vty)
* additionally, we'd need to replace these fds with /dev/null. */
if (vty->wfd > STDERR_FILENO && vty->wfd != vty->fd)
close(vty->wfd);
- if (vty->fd > STDERR_FILENO) {
+ if (vty->fd > STDERR_FILENO)
close(vty->fd);
- } else
+ if (vty->fd == STDIN_FILENO)
was_stdio = true;
if (vty->buf)
@@ -2402,8 +2411,9 @@ static void vty_read_file(FILE *confp)
nl = strchr(vty->error_buf, '\n');
if (nl)
*nl = '\0';
- zlog_err("ERROR: %s on config line %u: %s", message, line_num,
- vty->error_buf);
+ flog_err(LIB_ERR_VTY,
+ "ERROR: %s on config line %u: %s", message, line_num,
+ vty->error_buf);
}
vty_close(vty);
@@ -2476,7 +2486,8 @@ bool vty_read_config(const char *config_file, char *config_default_dir)
if (config_file != NULL) {
if (!IS_DIRECTORY_SEP(config_file[0])) {
if (getcwd(cwd, MAXPATHLEN) == NULL) {
- zlog_err(
+ flog_err_sys(
+ LIB_ERR_SYSTEM_CALL,
"Failure to determine Current Working Directory %d!",
errno);
exit(1);
@@ -2491,7 +2502,7 @@ bool vty_read_config(const char *config_file, char *config_default_dir)
confp = fopen(fullpath, "r");
if (confp == NULL) {
- zlog_err("%s: failed to open configuration file %s: %s",
+ zlog_warn("%s: failed to open configuration file %s: %s, checking backup",
__func__, fullpath, safe_strerror(errno));
confp = vty_use_backup_config(fullpath);
@@ -2499,8 +2510,9 @@ bool vty_read_config(const char *config_file, char *config_default_dir)
zlog_warn(
"WARNING: using backup configuration file!");
else {
- zlog_err("can't open configuration file [%s]",
- config_file);
+ flog_err(LIB_ERR_VTY,
+ "can't open configuration file [%s]",
+ config_file);
exit(1);
}
}
@@ -2536,9 +2548,9 @@ bool vty_read_config(const char *config_file, char *config_default_dir)
#endif /* VTYSH */
confp = fopen(config_default_dir, "r");
if (confp == NULL) {
- zlog_err("%s: failed to open configuration file %s: %s",
- __func__, config_default_dir,
- safe_strerror(errno));
+ zlog_warn("%s: failed to open configuration file %s: %s, checking backup",
+ __func__, config_default_dir,
+ safe_strerror(errno));
confp = vty_use_backup_config(config_default_dir);
if (confp) {
@@ -2546,8 +2558,9 @@ bool vty_read_config(const char *config_file, char *config_default_dir)
"WARNING: using backup configuration file!");
fullpath = config_default_dir;
} else {
- zlog_err("can't open configuration file [%s]",
- config_default_dir);
+ flog_err(LIB_ERR_VTY,
+ "can't open configuration file [%s]",
+ config_default_dir);
goto tmp_free_and_out;
}
} else
@@ -3060,12 +3073,14 @@ static void vty_save_cwd(void)
* Hence not worrying about it too much.
*/
if (!chdir(SYSCONFDIR)) {
- zlog_err("Failure to chdir to %s, errno: %d",
- SYSCONFDIR, errno);
+ flog_err_sys(LIB_ERR_SYSTEM_CALL,
+ "Failure to chdir to %s, errno: %d",
+ SYSCONFDIR, errno);
exit(-1);
}
if (getcwd(cwd, MAXPATHLEN) == NULL) {
- zlog_err("Failure to getcwd, errno: %d", errno);
+ flog_err_sys(LIB_ERR_SYSTEM_CALL,
+ "Failure to getcwd, errno: %d", errno);
exit(-1);
}
}
diff --git a/lib/workqueue.c b/lib/workqueue.c
index 39dd142afb..c927d5d714 100644
--- a/lib/workqueue.c
+++ b/lib/workqueue.c
@@ -81,9 +81,6 @@ struct work_queue *work_queue_new(struct thread_master *m,
new = XCALLOC(MTYPE_WORK_QUEUE, sizeof(struct work_queue));
- if (new == NULL)
- return new;
-
new->name = XSTRDUP(MTYPE_WORK_QUEUE_NAME, queue_name);
new->master = m;
SET_FLAG(new->flags, WQ_UNPLUGGED);
@@ -152,10 +149,7 @@ void work_queue_add(struct work_queue *wq, void *data)
assert(wq);
- if (!(item = work_queue_item_new(wq))) {
- zlog_err("%s: unable to get new queue item", __func__);
- return;
- }
+ item = work_queue_item_new(wq);
item->data = data;
work_queue_item_enqueue(wq, item);
diff --git a/lib/zclient.c b/lib/zclient.c
index 38a9e6c78e..cc91705ee2 100644
--- a/lib/zclient.c
+++ b/lib/zclient.c
@@ -38,6 +38,7 @@
#include "sockopt.h"
#include "pbr.h"
#include "nexthop_group.h"
+#include "lib_errors.h"
DEFINE_MTYPE_STATIC(LIB, ZCLIENT, "Zclient")
DEFINE_MTYPE_STATIC(LIB, REDIST_INST, "Redistribution instance IDs")
@@ -212,9 +213,9 @@ int zclient_socket_connect(struct zclient *zclient)
set_cloexec(sock);
- zclient->privs->change(ZPRIVS_RAISE);
- setsockopt_so_sendbuf(sock, 1048576);
- zclient->privs->change(ZPRIVS_LOWER);
+ frr_elevate_privs(zclient->privs) {
+ setsockopt_so_sendbuf(sock, 1048576);
+ }
/* Connect to zebra. */
ret = connect(sock, (struct sockaddr *)&zclient_addr, zclient_addr_len);
@@ -312,9 +313,9 @@ int zclient_read_header(struct stream *s, int sock, uint16_t *size,
STREAM_GETW(s, *cmd);
if (*version != ZSERV_VERSION || *marker != ZEBRA_HEADER_MARKER) {
- zlog_err(
- "%s: socket %d version mismatch, marker %d, version %d",
- __func__, sock, *marker, *version);
+ flog_err(LIB_ERR_ZAPI_MISSMATCH,
+ "%s: socket %d version mismatch, marker %d, version %d",
+ __func__, sock, *marker, *version);
return -1;
}
@@ -1045,12 +1046,12 @@ int zapi_route_encode(uint8_t cmd, struct stream *s, struct zapi_route *api)
char buf[PREFIX2STR_BUFFER];
prefix2str(&api->prefix, buf,
sizeof(buf));
- zlog_err(
- "%s: prefix %s: can't encode "
- "%u labels (maximum is %u)",
- __func__, buf,
- api_nh->label_num,
- MPLS_MAX_LABELS);
+ flog_err(LIB_ERR_ZAPI_ENCODE,
+ "%s: prefix %s: can't encode "
+ "%u labels (maximum is %u)",
+ __func__, buf,
+ api_nh->label_num,
+ MPLS_MAX_LABELS);
return -1;
}
@@ -1671,10 +1672,10 @@ static void link_params_set_value(struct stream *s, struct if_link_params *iflp)
for (i = 0; i < bwclassnum && i < MAX_CLASS_TYPE; i++)
iflp->unrsv_bw[i] = stream_getf(s);
if (i < bwclassnum)
- zlog_err(
- "%s: received %d > %d (MAX_CLASS_TYPE) bw entries"
- " - outdated library?",
- __func__, bwclassnum, MAX_CLASS_TYPE);
+ flog_err(LIB_ERR_ZAPI_MISSMATCH,
+ "%s: received %d > %d (MAX_CLASS_TYPE) bw entries"
+ " - outdated library?",
+ __func__, bwclassnum, MAX_CLASS_TYPE);
}
iflp->admin_grp = stream_getl(s);
iflp->rmt_as = stream_getl(s);
@@ -1703,8 +1704,9 @@ struct interface *zebra_interface_link_params_read(struct stream *s)
struct interface *ifp = if_lookup_by_index(ifindex, VRF_DEFAULT);
if (ifp == NULL) {
- zlog_err("%s: unknown ifindex %u, shouldn't happen", __func__,
- ifindex);
+ flog_err(LIB_ERR_ZAPI_ENCODE,
+ "%s: unknown ifindex %u, shouldn't happen", __func__,
+ ifindex);
return NULL;
}
@@ -2039,7 +2041,8 @@ static int zclient_read_sync_response(struct zclient *zclient,
size);
}
if (ret != 0) {
- zlog_err("%s: Invalid Sync Message Reply", __func__);
+ flog_err(LIB_ERR_ZAPI_ENCODE,
+ "%s: Invalid Sync Message Reply", __func__);
return -1;
}
@@ -2081,13 +2084,13 @@ int lm_label_manager_connect(struct zclient *zclient)
ret = writen(zclient->sock, s->data, stream_get_endp(s));
if (ret < 0) {
- zlog_err("Can't write to zclient sock");
+ flog_err(LIB_ERR_ZAPI_SOCKET, "Can't write to zclient sock");
close(zclient->sock);
zclient->sock = -1;
return -1;
}
if (ret == 0) {
- zlog_err("Zclient sock closed");
+ flog_err(LIB_ERR_ZAPI_SOCKET, "Zclient sock closed");
close(zclient->sock);
zclient->sock = -1;
return -1;
@@ -2108,13 +2111,13 @@ int lm_label_manager_connect(struct zclient *zclient)
/* sanity */
if (proto != zclient->redist_default)
- zlog_err(
- "Wrong proto (%u) in LM connect response. Should be %u",
- proto, zclient->redist_default);
+ flog_err(LIB_ERR_ZAPI_ENCODE,
+ "Wrong proto (%u) in LM connect response. Should be %u",
+ proto, zclient->redist_default);
if (instance != zclient->instance)
- zlog_err(
- "Wrong instId (%u) in LM connect response. Should be %u",
- instance, zclient->instance);
+ flog_err(LIB_ERR_ZAPI_ENCODE,
+ "Wrong instId (%u) in LM connect response. Should be %u",
+ instance, zclient->instance);
/* result code */
result = stream_getc(s);
@@ -2203,13 +2206,15 @@ int lm_get_label_chunk(struct zclient *zclient, uint8_t keep,
ret = writen(zclient->sock, s->data, stream_get_endp(s));
if (ret < 0) {
- zlog_err("Can't write to zclient sock");
+ flog_err(LIB_ERR_ZAPI_SOCKET,
+ "Can't write to zclient sock");
close(zclient->sock);
zclient->sock = -1;
return -1;
}
if (ret == 0) {
- zlog_err("Zclient sock closed");
+ flog_err(LIB_ERR_ZAPI_SOCKET,
+ "Zclient sock closed");
close(zclient->sock);
zclient->sock = -1;
return -1;
@@ -2230,11 +2235,13 @@ int lm_get_label_chunk(struct zclient *zclient, uint8_t keep,
/* sanities */
if (proto != zclient->redist_default)
- zlog_err("Wrong proto (%u) in get chunk response. Should be %u",
- proto, zclient->redist_default);
+ flog_err(LIB_ERR_ZAPI_ENCODE,
+ "Wrong proto (%u) in get chunk response. Should be %u",
+ proto, zclient->redist_default);
if (instance != zclient->instance)
- zlog_err("Wrong instId (%u) in get chunk response Should be %u",
- instance, zclient->instance);
+ flog_err(LIB_ERR_ZAPI_ENCODE,
+ "Wrong instId (%u) in get chunk response Should be %u",
+ instance, zclient->instance);
/* keep */
response_keep = stream_getc(s);
@@ -2244,14 +2251,15 @@ int lm_get_label_chunk(struct zclient *zclient, uint8_t keep,
/* not owning this response */
if (keep != response_keep) {
- zlog_err(
- "Invalid Label chunk: %u - %u, keeps mismatch %u != %u",
- *start, *end, keep, response_keep);
+ flog_err(LIB_ERR_ZAPI_ENCODE,
+ "Invalid Label chunk: %u - %u, keeps mismatch %u != %u",
+ *start, *end, keep, response_keep);
}
/* sanity */
if (*start > *end || *start < MPLS_LABEL_UNRESERVED_MIN
|| *end > MPLS_LABEL_UNRESERVED_MAX) {
- zlog_err("Invalid Label chunk: %u - %u", *start, *end);
+ flog_err(LIB_ERR_ZAPI_ENCODE,
+ "Invalid Label chunk: %u - %u", *start, *end);
return -1;
}
@@ -2301,13 +2309,14 @@ int lm_release_label_chunk(struct zclient *zclient, uint32_t start,
ret = writen(zclient->sock, s->data, stream_get_endp(s));
if (ret < 0) {
- zlog_err("Can't write to zclient sock");
+ flog_err(LIB_ERR_ZAPI_SOCKET, "Can't write to zclient sock");
close(zclient->sock);
zclient->sock = -1;
return -1;
}
if (ret == 0) {
- zlog_err("Zclient sock connection closed");
+ flog_err(LIB_ERR_ZAPI_SOCKET,
+ "Zclient sock connection closed");
close(zclient->sock);
zclient->sock = -1;
return -1;
@@ -2410,13 +2419,15 @@ int tm_get_table_chunk(struct zclient *zclient, uint32_t chunk_size,
ret = writen(zclient->sock, s->data, stream_get_endp(s));
if (ret < 0) {
- zlog_err("%s: can't write to zclient->sock", __func__);
+ flog_err(LIB_ERR_ZAPI_SOCKET,
+ "%s: can't write to zclient->sock", __func__);
close(zclient->sock);
zclient->sock = -1;
return -1;
}
if (ret == 0) {
- zlog_err("%s: zclient->sock connection closed", __func__);
+ flog_err(LIB_ERR_ZAPI_SOCKET,
+ "%s: zclient->sock connection closed", __func__);
close(zclient->sock);
zclient->sock = -1;
return -1;
@@ -2502,7 +2513,8 @@ int zebra_send_pw(struct zclient *zclient, int command, struct zapi_pw *pw)
stream_write(s, (uint8_t *)&pw->nexthop.ipv6, 16);
break;
default:
- zlog_err("%s: unknown af", __func__);
+ flog_err(LIB_ERR_ZAPI_ENCODE,
+ "%s: unknown af", __func__);
return -1;
}
@@ -2604,15 +2616,16 @@ static int zclient_read(struct thread *thread)
command = stream_getw(zclient->ibuf);
if (marker != ZEBRA_HEADER_MARKER || version != ZSERV_VERSION) {
- zlog_err(
- "%s: socket %d version mismatch, marker %d, version %d",
- __func__, zclient->sock, marker, version);
+ flog_err(LIB_ERR_ZAPI_MISSMATCH,
+ "%s: socket %d version mismatch, marker %d, version %d",
+ __func__, zclient->sock, marker, version);
return zclient_failed(zclient);
}
if (length < ZEBRA_HEADER_SIZE) {
- zlog_err("%s: socket %d message length %u is less than %d ",
- __func__, zclient->sock, length, ZEBRA_HEADER_SIZE);
+ flog_err(LIB_ERR_ZAPI_MISSMATCH,
+ "%s: socket %d message length %u is less than %d ",
+ __func__, zclient->sock, length, ZEBRA_HEADER_SIZE);
return zclient_failed(zclient);
}
diff --git a/lib/zclient.h b/lib/zclient.h
index 49419b3df3..962b1707c9 100644
--- a/lib/zclient.h
+++ b/lib/zclient.h
@@ -108,6 +108,7 @@ typedef enum {
ZEBRA_VRF_LABEL,
ZEBRA_INTERFACE_VRF_UPDATE,
ZEBRA_BFD_CLIENT_REGISTER,
+ ZEBRA_BFD_CLIENT_DEREGISTER,
ZEBRA_INTERFACE_ENABLE_RADV,
ZEBRA_INTERFACE_DISABLE_RADV,
ZEBRA_IPV4_NEXTHOP_LOOKUP_MRIB,
diff --git a/lib/zebra.h b/lib/zebra.h
index c2d135bbeb..b12f6616ba 100644
--- a/lib/zebra.h
+++ b/lib/zebra.h
@@ -242,23 +242,6 @@ size_t strlcpy(char *__restrict dest,
const char *__restrict src, size_t destsize);
#endif
-#ifdef HAVE_BROKEN_CMSG_FIRSTHDR
-/* This bug is present in Solaris 8 and pre-patch Solaris 9 <sys/socket.h>;
- please refer to http://bugzilla.quagga.net/show_bug.cgi?id=142 */
-
-/* Check that msg_controllen is large enough. */
-#define ZCMSG_FIRSTHDR(mhdr) \
- (((size_t)((mhdr)->msg_controllen) >= sizeof(struct cmsghdr)) \
- ? CMSG_FIRSTHDR(mhdr) \
- : (struct cmsghdr *)NULL)
-
-#warning "CMSG_FIRSTHDR is broken on this platform, using a workaround"
-
-#else /* HAVE_BROKEN_CMSG_FIRSTHDR */
-#define ZCMSG_FIRSTHDR(M) CMSG_FIRSTHDR(M)
-#endif /* HAVE_BROKEN_CMSG_FIRSTHDR */
-
-
/* GCC have printf type attribute check. */
#ifdef __GNUC__
#define PRINTF_ATTRIBUTE(a,b) __attribute__ ((__format__ (__printf__, a, b)))
diff --git a/nhrpd/nhrp_cache.c b/nhrpd/nhrp_cache.c
index ffc8b5a9bf..f3a33eb28f 100644
--- a/nhrpd/nhrp_cache.c
+++ b/nhrpd/nhrp_cache.c
@@ -48,17 +48,16 @@ static void *nhrp_cache_alloc(void *data)
struct nhrp_cache *p, *key = data;
p = XMALLOC(MTYPE_NHRP_CACHE, sizeof(struct nhrp_cache));
- if (p) {
- *p = (struct nhrp_cache){
- .cur.type = NHRP_CACHE_INVALID,
- .new.type = NHRP_CACHE_INVALID,
- .remote_addr = key->remote_addr,
- .ifp = key->ifp,
- .notifier_list =
- NOTIFIER_LIST_INITIALIZER(&p->notifier_list),
- };
- nhrp_cache_counts[p->cur.type]++;
- }
+
+ *p = (struct nhrp_cache){
+ .cur.type = NHRP_CACHE_INVALID,
+ .new.type = NHRP_CACHE_INVALID,
+ .remote_addr = key->remote_addr,
+ .ifp = key->ifp,
+ .notifier_list =
+ NOTIFIER_LIST_INITIALIZER(&p->notifier_list),
+ };
+ nhrp_cache_counts[p->cur.type]++;
return p;
}
diff --git a/nhrpd/nhrp_errors.c b/nhrpd/nhrp_errors.c
new file mode 100644
index 0000000000..c557ba8a66
--- /dev/null
+++ b/nhrpd/nhrp_errors.c
@@ -0,0 +1,49 @@
+/*
+ * NHRP-specific error messages.
+ * Copyright (C) 2018 Cumulus Networks, Inc.
+ * Donald Sharp
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This 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 "lib/ferr.h"
+#include "nhrp_errors.h"
+
+/* clang-format off */
+static struct log_ref ferr_nhrp_err[] = {
+ {
+ .code = NHRP_ERR_SWAN,
+ .title = "NHRP Strong Swan Error",
+ .description = "NHRP has detected a error with the Strongswan code",
+ .suggestion = "Ensure that StrongSwan is configured correctly. Restart StrongSwan and FRR"
+ },
+ {
+ .code = NHRP_ERR_RESOLVER,
+ .title = "NHRP DNS Resolution",
+ .description = "NHRP has detected an error in an attempt to resolve a hostname",
+ .suggestion = "Ensure that DNS is working properly and the hostname is configured in dns. If you are still seeing this error, open an issue"
+ },
+ {
+ .code = END_FERR,
+ }
+};
+/* clang-format on */
+
+void nhrp_error_init(void)
+{
+ log_ref_add(ferr_nhrp_err);
+}
diff --git a/nhrpd/nhrp_errors.h b/nhrpd/nhrp_errors.h
new file mode 100644
index 0000000000..c9e947eb2a
--- /dev/null
+++ b/nhrpd/nhrp_errors.h
@@ -0,0 +1,33 @@
+/*
+ * NHRP-specific error messages.
+ * Copyright (C) 2018 Cumulus Networks, Inc.
+ * Donald Sharp
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; see the file COPYING; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef __NHRP_ERRORS_H__
+#define __NHRP_ERRORS_H__
+
+#include "lib/ferr.h"
+
+enum nhrp_log_refs {
+ NHRP_ERR_SWAN = NHRP_FERR_START,
+ NHRP_ERR_RESOLVER,
+};
+
+extern void nhrp_error_init(void);
+
+#endif
diff --git a/nhrpd/nhrp_interface.c b/nhrpd/nhrp_interface.c
index 054a375cb8..3a42712748 100644
--- a/nhrpd/nhrp_interface.c
+++ b/nhrpd/nhrp_interface.c
@@ -25,8 +25,6 @@ static int nhrp_if_new_hook(struct interface *ifp)
afi_t afi;
nifp = XCALLOC(MTYPE_NHRP_IF, sizeof(struct nhrp_interface));
- if (!nifp)
- return 0;
ifp->info = nifp;
nifp->ifp = ifp;
diff --git a/nhrpd/nhrp_main.c b/nhrpd/nhrp_main.c
index ba1e00dedd..e9f44e8558 100644
--- a/nhrpd/nhrp_main.c
+++ b/nhrpd/nhrp_main.c
@@ -23,6 +23,7 @@
#include "nhrpd.h"
#include "netlink.h"
+#include "nhrp_errors.h"
DEFINE_MGROUP(NHRPD, "NHRP")
@@ -128,6 +129,7 @@ int main(int argc, char **argv)
/* Library inits. */
master = frr_init();
+ nhrp_error_init();
vrf_init(NULL, NULL, NULL, NULL);
nhrp_interface_init();
resolver_init();
diff --git a/nhrpd/nhrp_nhs.c b/nhrpd/nhrp_nhs.c
index a7a8c20191..360972c327 100644
--- a/nhrpd/nhrp_nhs.c
+++ b/nhrpd/nhrp_nhs.c
@@ -324,8 +324,6 @@ int nhrp_nhs_add(struct interface *ifp, afi_t afi, union sockunion *proto_addr,
}
nhs = XMALLOC(MTYPE_NHRP_NHS, sizeof(struct nhrp_nhs));
- if (!nhs)
- return NHRP_ERR_NO_MEMORY;
*nhs = (struct nhrp_nhs){
.afi = afi,
diff --git a/nhrpd/nhrp_peer.c b/nhrpd/nhrp_peer.c
index 8952a282e9..44271d68ac 100644
--- a/nhrpd/nhrp_peer.c
+++ b/nhrpd/nhrp_peer.c
@@ -165,18 +165,18 @@ static void *nhrp_peer_create(void *data)
struct nhrp_peer *p, *key = data;
p = XMALLOC(MTYPE_NHRP_PEER, sizeof(*p));
- if (p) {
- *p = (struct nhrp_peer){
- .ref = 0,
- .ifp = key->ifp,
- .vc = key->vc,
- .notifier_list =
- NOTIFIER_LIST_INITIALIZER(&p->notifier_list),
- };
- nhrp_vc_notify_add(p->vc, &p->vc_notifier, nhrp_peer_vc_notify);
- nhrp_interface_notify_add(p->ifp, &p->ifp_notifier,
- nhrp_peer_ifp_notify);
- }
+
+ *p = (struct nhrp_peer){
+ .ref = 0,
+ .ifp = key->ifp,
+ .vc = key->vc,
+ .notifier_list =
+ NOTIFIER_LIST_INITIALIZER(&p->notifier_list),
+ };
+ nhrp_vc_notify_add(p->vc, &p->vc_notifier, nhrp_peer_vc_notify);
+ nhrp_interface_notify_add(p->ifp, &p->ifp_notifier,
+ nhrp_peer_ifp_notify);
+
return p;
}
diff --git a/nhrpd/nhrp_vc.c b/nhrpd/nhrp_vc.c
index c373411d66..41a87d4adb 100644
--- a/nhrpd/nhrp_vc.c
+++ b/nhrpd/nhrp_vc.c
@@ -48,14 +48,13 @@ static void *nhrp_vc_alloc(void *data)
struct nhrp_vc *vc, *key = data;
vc = XMALLOC(MTYPE_NHRP_VC, sizeof(struct nhrp_vc));
- if (vc) {
- *vc = (struct nhrp_vc){
- .local.nbma = key->local.nbma,
- .remote.nbma = key->remote.nbma,
- .notifier_list =
- NOTIFIER_LIST_INITIALIZER(&vc->notifier_list),
- };
- }
+
+ *vc = (struct nhrp_vc){
+ .local.nbma = key->local.nbma,
+ .remote.nbma = key->remote.nbma,
+ .notifier_list =
+ NOTIFIER_LIST_INITIALIZER(&vc->notifier_list),
+ };
return vc;
}
@@ -118,8 +117,6 @@ int nhrp_vc_ipsec_updown(uint32_t child_id, struct nhrp_vc *vc)
return 0;
sa = XMALLOC(MTYPE_NHRP_VC, sizeof(struct child_sa));
- if (!sa)
- return 0;
*sa = (struct child_sa){
.id = child_id,
diff --git a/nhrpd/resolver.c b/nhrpd/resolver.c
index 415e7523de..dfa5dc3df0 100644
--- a/nhrpd/resolver.c
+++ b/nhrpd/resolver.c
@@ -12,7 +12,10 @@
#include "vector.h"
#include "thread.h"
+#include "lib_errors.h"
+
#include "nhrpd.h"
+#include "nhrp_errors.h"
struct resolver_state {
ares_channel channel;
@@ -191,9 +194,9 @@ void resolver_resolve(struct resolver_query *query, int af,
union sockunion *))
{
if (query->callback != NULL) {
- zlog_err(
- "Trying to resolve '%s', but previous query was not finished yet",
- hostname);
+ flog_err(NHRP_ERR_RESOLVER,
+ "Trying to resolve '%s', but previous query was not finished yet",
+ hostname);
return;
}
diff --git a/nhrpd/subdir.am b/nhrpd/subdir.am
index 5b06946c89..d66e968224 100644
--- a/nhrpd/subdir.am
+++ b/nhrpd/subdir.am
@@ -13,6 +13,7 @@ nhrpd_nhrpd_SOURCES = \
nhrpd/netlink_arp.c \
nhrpd/netlink_gre.c \
nhrpd/nhrp_cache.c \
+ nhrpd/nhrp_errors.c \
nhrpd/nhrp_event.c \
nhrpd/nhrp_interface.c \
nhrpd/nhrp_main.c \
@@ -34,6 +35,7 @@ noinst_HEADERS += \
nhrpd/debug.h \
nhrpd/list.h \
nhrpd/netlink.h \
+ nhrpd/nhrp_errors.h \
nhrpd/nhrp_protocol.h \
nhrpd/nhrpd.h \
nhrpd/os.h \
diff --git a/nhrpd/vici.c b/nhrpd/vici.c
index eb3827a12f..7cd703414a 100644
--- a/nhrpd/vici.c
+++ b/nhrpd/vici.c
@@ -14,9 +14,11 @@
#include "thread.h"
#include "zbuf.h"
#include "log.h"
-#include "nhrpd.h"
+#include "lib_errors.h"
+#include "nhrpd.h"
#include "vici.h"
+#include "nhrp_errors.h"
#define ERRNO_IO_RETRY(EN) (((EN) == EAGAIN) || ((EN) == EWOULDBLOCK) || ((EN) == EINTR))
@@ -212,9 +214,9 @@ static void parse_sa_message(struct vici_message_ctx *ctx,
if (str2sockunion(buf,
&sactx->local.host)
< 0)
- zlog_err(
- "VICI: bad strongSwan local-host: %s",
- buf);
+ flog_err(NHRP_ERR_SWAN,
+ "VICI: bad strongSwan local-host: %s",
+ buf);
} else if (blob_equal(key, "local-id")
&& ctx->nsections == 1) {
sactx->local.id = *val;
@@ -230,9 +232,9 @@ static void parse_sa_message(struct vici_message_ctx *ctx,
if (str2sockunion(buf,
&sactx->remote.host)
< 0)
- zlog_err(
- "VICI: bad strongSwan remote-host: %s",
- buf);
+ flog_err(NHRP_ERR_SWAN,
+ "VICI: bad strongSwan remote-host: %s",
+ buf);
} else if (blob_equal(key, "remote-id")
&& ctx->nsections == 1) {
sactx->remote.id = *val;
@@ -275,7 +277,7 @@ static void parse_cmd_response(struct vici_message_ctx *ctx,
case VICI_KEY_VALUE:
if (blob_equal(key, "errmsg")
&& blob2buf(val, buf, sizeof(buf)))
- zlog_err("VICI: strongSwan: %s", buf);
+ flog_err(NHRP_ERR_SWAN, "VICI: strongSwan: %s", buf);
break;
default:
break;
@@ -334,7 +336,7 @@ static void vici_recv_message(struct vici_conn *vici, struct zbuf *msg)
break;
case VICI_EVENT_UNKNOWN:
case VICI_CMD_UNKNOWN:
- zlog_err(
+ flog_err(NHRP_ERR_SWAN,
"VICI: StrongSwan does not support mandatory events (unpatched?)");
break;
case VICI_EVENT_CONFIRM:
diff --git a/nhrpd/zbuf.c b/nhrpd/zbuf.c
index 65232a3093..6e7cad8aec 100644
--- a/nhrpd/zbuf.c
+++ b/nhrpd/zbuf.c
@@ -25,8 +25,6 @@ struct zbuf *zbuf_alloc(size_t size)
struct zbuf *zb;
zb = XMALLOC(MTYPE_ZBUF_DATA, sizeof(*zb) + size);
- if (!zb)
- return NULL;
zbuf_init(zb, zb + 1, size, 0);
zb->allocated = 1;
diff --git a/ospf6d/ospf6_bfd.c b/ospf6d/ospf6_bfd.c
index 7955121365..e7284a6659 100644
--- a/ospf6d/ospf6_bfd.c
+++ b/ospf6d/ospf6_bfd.c
@@ -276,11 +276,14 @@ void ospf6_bfd_info_nbr_create(struct ospf6_interface *oi,
*/
void ospf6_bfd_write_config(struct vty *vty, struct ospf6_interface *oi)
{
+#if HAVE_BFDD == 0
struct bfd_info *bfd_info;
+#endif /* ! HAVE_BFDD */
if (!oi->bfd_info)
return;
+#if HAVE_BFDD == 0
bfd_info = (struct bfd_info *)oi->bfd_info;
if (CHECK_FLAG(bfd_info->flags, BFD_FLAG_PARAM_CFG))
@@ -288,6 +291,7 @@ void ospf6_bfd_write_config(struct vty *vty, struct ospf6_interface *oi)
bfd_info->detect_mult, bfd_info->required_min_rx,
bfd_info->desired_min_tx);
else
+#endif /* ! HAVE_BFDD */
vty_out(vty, " ipv6 ospf6 bfd\n");
}
@@ -329,7 +333,12 @@ DEFUN (ipv6_ospf6_bfd,
return CMD_SUCCESS;
}
-DEFUN (ipv6_ospf6_bfd_param,
+#if HAVE_BFDD > 0
+DEFUN_HIDDEN(
+#else
+DEFUN(
+#endif /* HAVE_BFDD */
+ ipv6_ospf6_bfd_param,
ipv6_ospf6_bfd_param_cmd,
"ipv6 ospf6 bfd (2-255) (50-60000) (50-60000)",
IP6_STR
diff --git a/ospf6d/ospf6_flood.c b/ospf6d/ospf6_flood.c
index ae26668c8a..2059d84868 100644
--- a/ospf6d/ospf6_flood.c
+++ b/ospf6d/ospf6_flood.c
@@ -347,7 +347,6 @@ void ospf6_flood_interface(struct ospf6_neighbor *from, struct ospf6_lsa *lsa,
"Received is newer, remove requesting");
if (req == on->last_ls_req) {
ospf6_lsa_unlock(req);
- req = NULL;
on->last_ls_req = NULL;
}
if (req)
diff --git a/ospf6d/ospf6_interface.c b/ospf6d/ospf6_interface.c
index 9178bf2f6a..9777a01ae6 100644
--- a/ospf6d/ospf6_interface.c
+++ b/ospf6d/ospf6_interface.c
@@ -180,12 +180,6 @@ struct ospf6_interface *ospf6_interface_create(struct interface *ifp)
oi = (struct ospf6_interface *)XCALLOC(MTYPE_OSPF6_IF,
sizeof(struct ospf6_interface));
- if (!oi) {
- zlog_err("Can't malloc ospf6_interface for ifindex %d",
- ifp->ifindex);
- return (struct ospf6_interface *)NULL;
- }
-
oi->area = (struct ospf6_area *)NULL;
oi->neighbor_list = list_new();
oi->neighbor_list->cmp = ospf6_neighbor_cmp;
diff --git a/ospf6d/ospf6_message.c b/ospf6d/ospf6_message.c
index c608a01102..228a525e76 100644
--- a/ospf6d/ospf6_message.c
+++ b/ospf6d/ospf6_message.c
@@ -26,6 +26,7 @@
#include "command.h"
#include "thread.h"
#include "linklist.h"
+#include "lib_errors.h"
#include "ospf6_proto.h"
#include "ospf6_lsa.h"
@@ -1503,14 +1504,6 @@ int ospf6_iobuf_size(unsigned int size)
recvnew = XMALLOC(MTYPE_OSPF6_MESSAGE, size);
sendnew = XMALLOC(MTYPE_OSPF6_MESSAGE, size);
- if (recvnew == NULL || sendnew == NULL) {
- if (recvnew)
- XFREE(MTYPE_OSPF6_MESSAGE, recvnew);
- if (sendnew)
- XFREE(MTYPE_OSPF6_MESSAGE, sendnew);
- zlog_debug("Could not allocate I/O buffer of size %d.", size);
- return iobuflen;
- }
if (recvbuf)
XFREE(MTYPE_OSPF6_MESSAGE, recvbuf);
@@ -1566,7 +1559,8 @@ int ospf6_receive(struct thread *thread)
/* receive message */
len = ospf6_recvmsg(&src, &dst, &ifindex, iovector);
if (len > iobuflen) {
- zlog_err("Excess message read");
+ flog_err(LIB_ERR_DEVELOPMENT,
+ "Excess message read");
return 0;
}
@@ -1714,7 +1708,7 @@ static void ospf6_send(struct in6_addr *src, struct in6_addr *dst,
/* send message */
len = ospf6_sendmsg(src, dst, &oi->interface->ifindex, iovector);
if (len != ntohs(oh->length))
- zlog_err("Could not send entire message");
+ flog_err(LIB_ERR_DEVELOPMENT, "Could not send entire message");
}
static uint32_t ospf6_packet_max(struct ospf6_interface *oi)
diff --git a/ospf6d/ospf6_neighbor.c b/ospf6d/ospf6_neighbor.c
index b5a1812ffa..0cc7294d67 100644
--- a/ospf6d/ospf6_neighbor.c
+++ b/ospf6d/ospf6_neighbor.c
@@ -84,10 +84,6 @@ struct ospf6_neighbor *ospf6_neighbor_create(uint32_t router_id,
on = (struct ospf6_neighbor *)XMALLOC(MTYPE_OSPF6_NEIGHBOR,
sizeof(struct ospf6_neighbor));
- if (on == NULL) {
- zlog_warn("neighbor: malloc failed");
- return NULL;
- }
memset(on, 0, sizeof(struct ospf6_neighbor));
inet_ntop(AF_INET, &router_id, buf, sizeof(buf));
diff --git a/ospf6d/ospf6_network.c b/ospf6d/ospf6_network.c
index 4790d8f01e..8988a53e5d 100644
--- a/ospf6d/ospf6_network.c
+++ b/ospf6d/ospf6_network.c
@@ -25,6 +25,7 @@
#include "sockunion.h"
#include "sockopt.h"
#include "privs.h"
+#include "lib_errors.h"
#include "libospf.h"
#include "ospf6_proto.h"
@@ -75,18 +76,14 @@ static void ospf6_set_checksum(void)
/* Make ospf6d's server socket. */
int ospf6_serv_sock(void)
{
- if (ospf6d_privs.change(ZPRIVS_RAISE))
- zlog_err("ospf6_serv_sock: could not raise privs");
-
- ospf6_sock = socket(AF_INET6, SOCK_RAW, IPPROTO_OSPFIGP);
- if (ospf6_sock < 0) {
- zlog_warn("Network: can't create OSPF6 socket.");
- if (ospf6d_privs.change(ZPRIVS_LOWER))
- zlog_err("ospf_sock_init: could not lower privs");
- return -1;
+ frr_elevate_privs(&ospf6d_privs) {
+
+ ospf6_sock = socket(AF_INET6, SOCK_RAW, IPPROTO_OSPFIGP);
+ if (ospf6_sock < 0) {
+ zlog_warn("Network: can't create OSPF6 socket.");
+ return -1;
+ }
}
- if (ospf6d_privs.change(ZPRIVS_LOWER))
- zlog_err("ospf_sock_init: could not lower privs");
/* set socket options */
#if 1
@@ -120,8 +117,10 @@ int ospf6_sso(ifindex_t ifindex, struct in6_addr *group, int option)
ret = setsockopt(ospf6_sock, IPPROTO_IPV6, option, &mreq6,
sizeof(mreq6));
if (ret < 0) {
- zlog_err("Network: setsockopt (%d) on ifindex %d failed: %s",
- option, ifindex, safe_strerror(errno));
+ flog_err_sys(
+ LIB_ERR_SOCKET,
+ "Network: setsockopt (%d) on ifindex %d failed: %s",
+ option, ifindex, safe_strerror(errno));
return ret;
}
diff --git a/ospf6d/ospf6_route.c b/ospf6d/ospf6_route.c
index 15d8eb6cf2..a099eead49 100644
--- a/ospf6d/ospf6_route.c
+++ b/ospf6d/ospf6_route.c
@@ -574,8 +574,8 @@ static void route_table_assert(struct ospf6_route_table *table)
if (link_error == 0 && num == table->count)
return;
- zlog_err("PANIC !!");
- zlog_err("Something has gone wrong with ospf6_route_table[%p]", table);
+ flog_err(LIB_ERR_DEVELOPMENT, "PANIC !!");
+ flog_err(LIB_ERR_DEVELOPMENT, "Something has gone wrong with ospf6_route_table[%p]", table);
zlog_debug("table count = %d, real number = %d", table->count, num);
zlog_debug("DUMP START");
for (r = ospf6_route_head(table); r; r = ospf6_route_next(r)) {
diff --git a/ospf6d/ospf6_spf.c b/ospf6d/ospf6_spf.c
index 5b6691e6bf..9c13c51b1f 100644
--- a/ospf6d/ospf6_spf.c
+++ b/ospf6d/ospf6_spf.c
@@ -30,6 +30,7 @@
#include "pqueue.h"
#include "linklist.h"
#include "thread.h"
+#include "lib_errors.h"
#include "ospf6_lsa.h"
#include "ospf6_lsdb.h"
@@ -272,7 +273,8 @@ static void ospf6_nexthop_calc(struct ospf6_vertex *w, struct ospf6_vertex *v,
ifindex = (VERTEX_IS_TYPE(NETWORK, v) ? ospf6_spf_get_ifindex_from_nh(v)
: ROUTER_LSDESC_GET_IFID(lsdesc));
if (ifindex == 0) {
- zlog_err("No nexthop ifindex at vertex %s", v->name);
+ flog_err(LIB_ERR_DEVELOPMENT,
+ "No nexthop ifindex at vertex %s", v->name);
return;
}
@@ -1012,16 +1014,10 @@ struct ospf6_lsa *ospf6_create_single_router_lsa(struct ospf6_area *area,
/* Allocate memory for this LSA */
new_header = XMALLOC(MTYPE_OSPF6_LSA_HEADER, total_lsa_length);
- if (!new_header)
- return NULL;
/* LSA information structure */
lsa = (struct ospf6_lsa *)XCALLOC(MTYPE_OSPF6_LSA,
sizeof(struct ospf6_lsa));
- if (!lsa) {
- free(new_header);
- return NULL;
- }
lsa->header = (struct ospf6_lsa_header *)new_header;
diff --git a/ospf6d/ospf6_zebra.c b/ospf6d/ospf6_zebra.c
index 8458d19952..06a84dcb93 100644
--- a/ospf6d/ospf6_zebra.c
+++ b/ospf6d/ospf6_zebra.c
@@ -28,6 +28,7 @@
#include "zclient.h"
#include "memory.h"
#include "lib/bfd.h"
+#include "lib_errors.h"
#include "ospf6_proto.h"
#include "ospf6_top.h"
@@ -362,9 +363,10 @@ static void ospf6_zebra_route_update(int type, struct ospf6_route *request)
ret = zclient_route_send(ZEBRA_ROUTE_ADD, zclient, &api);
if (ret < 0)
- zlog_err("zclient_route_send() %s failed: %s",
- (type == REM ? "delete" : "add"),
- safe_strerror(errno));
+ flog_err(LIB_ERR_ZAPI_SOCKET,
+ "zclient_route_send() %s failed: %s",
+ (type == REM ? "delete" : "add"),
+ safe_strerror(errno));
return;
}
diff --git a/ospfclient/ospf_apiclient.c b/ospfclient/ospf_apiclient.c
index 5b46059d78..db624ae074 100644
--- a/ospfclient/ospf_apiclient.c
+++ b/ospfclient/ospf_apiclient.c
@@ -570,10 +570,7 @@ static void ospf_apiclient_handle_lsa_update(struct ospf_apiclient *oclient,
/* Extract LSA from message */
lsalen = ntohs(cn->data.length);
lsa = XMALLOC(MTYPE_OSPF_APICLIENT, lsalen);
- if (!lsa) {
- fprintf(stderr, "LSA update: Cannot allocate memory for LSA\n");
- return;
- }
+
memcpy(lsa, &(cn->data), lsalen);
/* Invoke registered update callback function */
@@ -598,10 +595,7 @@ static void ospf_apiclient_handle_lsa_delete(struct ospf_apiclient *oclient,
/* Extract LSA from message */
lsalen = ntohs(cn->data.length);
lsa = XMALLOC(MTYPE_OSPF_APICLIENT, lsalen);
- if (!lsa) {
- fprintf(stderr, "LSA delete: Cannot allocate memory for LSA\n");
- return;
- }
+
memcpy(lsa, &(cn->data), lsalen);
/* Invoke registered update callback function */
diff --git a/ospfd/ospf_apiserver.c b/ospfd/ospf_apiserver.c
index 8f8900e147..c0ce971f0c 100644
--- a/ospfd/ospf_apiserver.c
+++ b/ospfd/ospf_apiserver.c
@@ -1176,13 +1176,11 @@ int ospf_apiserver_handle_register_event(struct ospf_apiserver *apiserv,
apiserv->filter =
XMALLOC(MTYPE_OSPF_APISERVER_MSGFILTER, ntohs(msg->hdr.msglen));
- if (apiserv->filter) {
- /* copy it over. */
- memcpy(apiserv->filter, &rmsg->filter, ntohs(msg->hdr.msglen));
- rc = OSPF_API_OK;
- } else {
- rc = OSPF_API_NOMEMORY;
- }
+
+ /* copy it over. */
+ memcpy(apiserv->filter, &rmsg->filter, ntohs(msg->hdr.msglen));
+ rc = OSPF_API_OK;
+
/* Send a reply back to client with return code */
rc = ospf_apiserver_send_reply(apiserv, seqnum, rc);
return rc;
diff --git a/ospfd/ospf_bfd.c b/ospfd/ospf_bfd.c
index 0f7fb50778..df41897660 100644
--- a/ospfd/ospf_bfd.c
+++ b/ospfd/ospf_bfd.c
@@ -290,17 +290,21 @@ void ospf_bfd_info_nbr_create(struct ospf_interface *oi,
void ospf_bfd_write_config(struct vty *vty, struct ospf_if_params *params)
{
+#if HAVE_BFDD == 0
struct bfd_info *bfd_info;
+#endif /* ! HAVE_BFDD */
if (!params->bfd_info)
return;
+#if HAVE_BFDD == 0
bfd_info = (struct bfd_info *)params->bfd_info;
if (CHECK_FLAG(bfd_info->flags, BFD_FLAG_PARAM_CFG))
vty_out(vty, " ip ospf bfd %d %d %d\n", bfd_info->detect_mult,
bfd_info->required_min_rx, bfd_info->desired_min_tx);
else
+#endif /* ! HAVE_BFDD */
vty_out(vty, " ip ospf bfd\n");
}
@@ -373,7 +377,12 @@ DEFUN (ip_ospf_bfd,
return CMD_SUCCESS;
}
-DEFUN (ip_ospf_bfd_param,
+#if HAVE_BFDD > 0
+DEFUN_HIDDEN(
+#else
+DEFUN(
+#endif /* HAVE_BFDD */
+ ip_ospf_bfd_param,
ip_ospf_bfd_param_cmd,
"ip ospf bfd (2-255) (50-60000) (50-60000)",
"IP Information\n"
@@ -407,14 +416,21 @@ DEFUN (ip_ospf_bfd_param,
DEFUN (no_ip_ospf_bfd,
no_ip_ospf_bfd_cmd,
+#if HAVE_BFDD > 0
+ "no ip ospf bfd",
+#else
"no ip ospf bfd [(2-255) (50-60000) (50-60000)]",
+#endif /* HAVE_BFDD */
NO_STR
"IP Information\n"
"OSPF interface commands\n"
"Disables BFD support\n"
+#if HAVE_BFDD == 0
"Detect Multiplier\n"
"Required min receive interval\n"
- "Desired min transmit interval\n")
+ "Desired min transmit interval\n"
+#endif /* !HAVE_BFDD */
+)
{
VTY_DECLVAR_CONTEXT(interface, ifp);
struct ospf_if_params *params;
diff --git a/ospfd/ospf_errors.c b/ospfd/ospf_errors.c
new file mode 100644
index 0000000000..2927f7cb14
--- /dev/null
+++ b/ospfd/ospf_errors.c
@@ -0,0 +1,84 @@
+/*
+ * OSPF-specific error messages.
+ * Copyright (C) 2018 Cumulus Networks, Inc.
+ * Chirag Shah
+ *
+ * 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 "lib/ferr.h"
+#include "ospf_errors.h"
+
+static struct log_ref ferr_ospf_err[] = {
+ {
+ .code = OSPF_ERR_PKT_PROCESS,
+ .title = "Failure to process a packet",
+ .description = "OSPF attempted to process a received packet but could not",
+ .suggestion = "Most likely a bug. If the problem persists, report the problem for troubleshooting"
+ },
+ {
+ .code = OSPF_ERR_ROUTER_LSA_MISMATCH,
+ .title = "Failure to process Router LSA",
+ .description = "OSPF attempted to process a Router LSA but Advertising ID mismatch with link id",
+ .suggestion = "Check OSPF network config for any config issue, If the problem persists, report the problem for troubleshooting"
+ },
+ {
+ .code = OSPF_ERR_DOMAIN_CORRUPT,
+ .title = "OSPF Domain Corruption",
+ .description = "OSPF attempted to process a Router LSA but Advertising ID mismatch with link id",
+ .suggestion = "Check OSPF network Database for corrupted LSA, If the problem persists, shutdown OSPF domain and report the problem for troubleshooting"
+ },
+ {
+ .code = OSPF_ERR_INIT_FAIL,
+ .title = "OSPF Initialization failure",
+ .description = "OSPF failed to initialized OSPF default insance",
+ .suggestion = "Ensure there is adequate memory on the device. If the problem persists, report the problem for troubleshooting"
+ },
+ {
+ .code = OSPF_ERR_SR_INVALID_DB,
+ .title = "OSPF SR Invalid DB",
+ .description = "OSPF Segment Routing Database is invalid",
+ .suggestion = "Most likely a bug. If the problem persists, report the problem for troubleshooting"
+ },
+ {
+ .code = OSPF_ERR_SR_NODE_CREATE,
+ .title = "OSPF SR hash node creation failed",
+ .description = "OSPF Segment Routing node creation failed",
+ .suggestion = "Most likely a bug. If the problem persists, report the problem for troubleshooting"
+ },
+ {
+ .code = OSPF_ERR_SR_INVALID_LSA_ID,
+ .title = "OSPF SR Invalid LSA ID",
+ .description = "OSPF Segment Routing invalid lsa id",
+ .suggestion = "Restart OSPF instance, If the problem persists, report the problem for troubleshooting"
+ },
+ {
+ .code = OSPF_ERR_SR_INVALID_ALGORITHM,
+ .title = "OSPF SR Invalid Algorithm",
+ .description = "OSPF Segment Routing invalid Algorithm",
+ .suggestion = "Most likely a bug. If the problem persists, report the problem for troubleshooting"
+ },
+
+ {
+ .code = END_FERR,
+ }
+};
+
+void ospf_error_init(void)
+{
+ log_ref_add(ferr_ospf_err);
+}
diff --git a/ospfd/ospf_errors.h b/ospfd/ospf_errors.h
new file mode 100644
index 0000000000..c3f1018550
--- /dev/null
+++ b/ospfd/ospf_errors.h
@@ -0,0 +1,39 @@
+/*
+ * OSPF-specific error messages.
+ * Copyright (C) 2018 Cumulus Networks, Inc.
+ * Chirag Shah
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; see the file COPYING; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef __OSPF_ERRORS_H__
+#define __OSPF_ERRORS_H__
+
+#include "lib/ferr.h"
+
+enum ospf_log_refs {
+ OSPF_ERR_PKT_PROCESS = OSPF_FERR_START,
+ OSPF_ERR_ROUTER_LSA_MISMATCH,
+ OSPF_ERR_DOMAIN_CORRUPT,
+ OSPF_ERR_INIT_FAIL,
+ OSPF_ERR_SR_INVALID_DB,
+ OSPF_ERR_SR_NODE_CREATE,
+ OSPF_ERR_SR_INVALID_LSA_ID,
+ OSPF_ERR_SR_INVALID_ALGORITHM,
+};
+
+extern void ospf_error_init(void);
+
+#endif
diff --git a/ospfd/ospf_ext.c b/ospfd/ospf_ext.c
index 331cba44a8..b8d14c351e 100644
--- a/ospfd/ospf_ext.c
+++ b/ospfd/ospf_ext.c
@@ -545,11 +545,6 @@ static int ospf_ext_link_new_if(struct interface *ifp)
}
new = XCALLOC(MTYPE_OSPF_EXT_PARAMS, sizeof(struct ext_itf));
- if (new == NULL) {
- zlog_warn("EXT (%s): XCALLOC: %s", __func__,
- safe_strerror(errno));
- return rc;
- }
/* initialize new information and link back the interface */
new->ifp = ifp;
diff --git a/ospfd/ospf_interface.c b/ospfd/ospf_interface.c
index 23353b3c30..24584f6713 100644
--- a/ospfd/ospf_interface.c
+++ b/ospfd/ospf_interface.c
@@ -523,9 +523,6 @@ static struct ospf_if_params *ospf_new_if_params(void)
oip = XCALLOC(MTYPE_OSPF_IF_PARAMS, sizeof(struct ospf_if_params));
- if (!oip)
- return NULL;
-
UNSET_IF_PARAM(oip, output_cost_cmd);
UNSET_IF_PARAM(oip, transmit_delay);
UNSET_IF_PARAM(oip, retransmit_interval);
diff --git a/ospfd/ospf_lsa.c b/ospfd/ospf_lsa.c
index 4165338834..2651cf717b 100644
--- a/ospfd/ospf_lsa.c
+++ b/ospfd/ospf_lsa.c
@@ -2912,24 +2912,17 @@ void ospf_lsa_maxage(struct ospf *ospf, struct ospf_lsa *lsa)
lsa_prefix.prefixlen = sizeof(lsa_prefix.u.ptr) * CHAR_BIT;
lsa_prefix.u.ptr = (uintptr_t)lsa;
- if ((rn = route_node_get(ospf->maxage_lsa,
- (struct prefix *)&lsa_prefix))
- != NULL) {
- if (rn->info != NULL) {
- if (IS_DEBUG_OSPF(lsa, LSA_FLOODING))
- zlog_debug(
- "LSA[%s]: found LSA (%p) in table for LSA %p %d",
- dump_lsa_key(lsa), rn->info,
- (void *)lsa, lsa_prefix.prefixlen);
- route_unlock_node(rn);
- } else {
- rn->info = ospf_lsa_lock(lsa);
- SET_FLAG(lsa->flags, OSPF_LSA_IN_MAXAGE);
- }
+ rn = route_node_get(ospf->maxage_lsa, (struct prefix *)&lsa_prefix);
+ if (rn->info != NULL) {
+ if (IS_DEBUG_OSPF(lsa, LSA_FLOODING))
+ zlog_debug(
+ "LSA[%s]: found LSA (%p) in table for LSA %p %d",
+ dump_lsa_key(lsa), rn->info,
+ (void *)lsa, lsa_prefix.prefixlen);
+ route_unlock_node(rn);
} else {
- zlog_err("Unable to allocate memory for maxage lsa %s\n",
- dump_lsa_key(lsa));
- assert(0);
+ rn->info = ospf_lsa_lock(lsa);
+ SET_FLAG(lsa->flags, OSPF_LSA_IN_MAXAGE);
}
if (IS_DEBUG_OSPF(lsa, LSA_FLOODING))
diff --git a/ospfd/ospf_main.c b/ospfd/ospf_main.c
index 5bf7ec1469..6dadc05bba 100644
--- a/ospfd/ospf_main.c
+++ b/ospfd/ospf_main.c
@@ -52,6 +52,7 @@
#include "ospfd/ospf_zebra.h"
#include "ospfd/ospf_vty.h"
#include "ospfd/ospf_bfd.h"
+#include "ospfd/ospf_errors.h"
/* ospfd privileges */
zebra_capabilities_t _caps_p[] = {ZCAP_NET_RAW, ZCAP_BIND, ZCAP_NET_ADMIN,
@@ -206,12 +207,16 @@ int main(int argc, char **argv)
ospf_route_map_init();
ospf_opaque_init();
+ /* OSPF errors init */
+ ospf_error_init();
+
/* Need to initialize the default ospf structure, so the interface mode
commands can be duly processed if they are received before 'router
ospf',
when quagga(ospfd) is restarted */
if (!ospf_get_instance(instance)) {
- zlog_err("OSPF instance init failed: %s", strerror(errno));
+ flog_err(OSPF_ERR_INIT_FAIL, "OSPF instance init failed: %s",
+ strerror(errno));
exit(1);
}
diff --git a/ospfd/ospf_network.c b/ospfd/ospf_network.c
index d7cca0f133..1fb930659e 100644
--- a/ospfd/ospf_network.c
+++ b/ospfd/ospf_network.c
@@ -29,6 +29,7 @@
#include "log.h"
#include "sockopt.h"
#include "privs.h"
+#include "lib_errors.h"
#include "ospfd/ospfd.h"
#include "ospfd/ospf_network.h"
@@ -185,66 +186,51 @@ int ospf_sock_init(struct ospf *ospf)
/* silently return since VRF is not ready */
return -1;
}
- if (ospfd_privs.change(ZPRIVS_RAISE)) {
- zlog_err("ospf_sock_init: could not raise privs, %s",
- safe_strerror(errno));
- }
-
- ospf_sock = vrf_socket(AF_INET, SOCK_RAW, IPPROTO_OSPFIGP, ospf->vrf_id,
- ospf->name);
- if (ospf_sock < 0) {
- int save_errno = errno;
-
- if (ospfd_privs.change(ZPRIVS_LOWER))
- zlog_err("ospf_sock_init: could not lower privs, %s",
+ frr_elevate_privs(&ospfd_privs) {
+ ospf_sock = vrf_socket(AF_INET, SOCK_RAW, IPPROTO_OSPFIGP,
+ ospf->vrf_id, ospf->name);
+ if (ospf_sock < 0) {
+ zlog_err("ospf_read_sock_init: socket: %s",
safe_strerror(errno));
- zlog_err("ospf_read_sock_init: socket: %s",
- safe_strerror(save_errno));
- exit(1);
- }
+ exit(1);
+ }
#ifdef IP_HDRINCL
- /* we will include IP header with packet */
- ret = setsockopt(ospf_sock, IPPROTO_IP, IP_HDRINCL, &hincl,
- sizeof(hincl));
- if (ret < 0) {
- int save_errno = errno;
-
- zlog_warn("Can't set IP_HDRINCL option for fd %d: %s",
- ospf_sock, safe_strerror(save_errno));
- close(ospf_sock);
- goto out;
- }
+ /* we will include IP header with packet */
+ ret = setsockopt(ospf_sock, IPPROTO_IP, IP_HDRINCL, &hincl,
+ sizeof(hincl));
+ if (ret < 0) {
+ zlog_warn("Can't set IP_HDRINCL option for fd %d: %s",
+ ospf_sock, safe_strerror(errno));
+ close(ospf_sock);
+ break;
+ }
#elif defined(IPTOS_PREC_INTERNETCONTROL)
#warning "IP_HDRINCL not available on this system"
#warning "using IPTOS_PREC_INTERNETCONTROL"
- ret = setsockopt_ipv4_tos(ospf_sock, IPTOS_PREC_INTERNETCONTROL);
- if (ret < 0) {
- int save_errno = errno;
-
- zlog_warn("can't set sockopt IP_TOS %d to socket %d: %s", tos,
- ospf_sock, safe_strerror(save_errno));
- close(ospf_sock); /* Prevent sd leak. */
- goto out;
- }
+ ret = setsockopt_ipv4_tos(ospf_sock,
+ IPTOS_PREC_INTERNETCONTROL);
+ if (ret < 0) {
+ zlog_warn("can't set sockopt IP_TOS %d to socket %d: %s",
+ tos, ospf_sock, safe_strerror(errno));
+ close(ospf_sock); /* Prevent sd leak. */
+ break;
+ }
#else /* !IPTOS_PREC_INTERNETCONTROL */
#warning "IP_HDRINCL not available, nor is IPTOS_PREC_INTERNETCONTROL"
- zlog_warn("IP_HDRINCL option not available");
+ zlog_warn("IP_HDRINCL option not available");
#endif /* IP_HDRINCL */
- ret = setsockopt_ifindex(AF_INET, ospf_sock, 1);
+ ret = setsockopt_ifindex(AF_INET, ospf_sock, 1);
- if (ret < 0)
- zlog_warn("Can't set pktinfo option for fd %d", ospf_sock);
+ if (ret < 0)
+ zlog_warn("Can't set pktinfo option for fd %d",
+ ospf_sock);
- setsockopt_so_sendbuf(ospf_sock, bufsize);
- setsockopt_so_recvbuf(ospf_sock, bufsize);
+ setsockopt_so_sendbuf(ospf_sock, bufsize);
+ setsockopt_so_recvbuf(ospf_sock, bufsize);
+ }
ospf->fd = ospf_sock;
-out:
- if (ospfd_privs.change(ZPRIVS_LOWER)) {
- zlog_err("ospf_sock_init: could not lower privs, %s",
- safe_strerror(errno));
- }
return ret;
}
diff --git a/ospfd/ospf_opaque.c b/ospfd/ospf_opaque.c
index 1ae9a29a1b..be62eb3906 100644
--- a/ospfd/ospf_opaque.c
+++ b/ospfd/ospf_opaque.c
@@ -399,13 +399,8 @@ int ospf_register_opaque_functab(
}
}
- if ((new = XCALLOC(MTYPE_OSPF_OPAQUE_FUNCTAB,
- sizeof(struct ospf_opaque_functab)))
- == NULL) {
- zlog_warn("ospf_register_opaque_functab: XMALLOC: %s",
- safe_strerror(errno));
- goto out;
- }
+ new = XCALLOC(MTYPE_OSPF_OPAQUE_FUNCTAB,
+ sizeof(struct ospf_opaque_functab));
new->opaque_type = opaque_type;
new->oipt = NULL;
@@ -554,13 +549,8 @@ register_opaque_info_per_type(struct ospf_opaque_functab *functab,
struct ospf *top;
struct opaque_info_per_type *oipt;
- if ((oipt = XCALLOC(MTYPE_OPAQUE_INFO_PER_TYPE,
- sizeof(struct opaque_info_per_type)))
- == NULL) {
- zlog_warn("register_opaque_info_per_type: XMALLOC: %s",
- safe_strerror(errno));
- goto out;
- }
+ oipt = XCALLOC(MTYPE_OPAQUE_INFO_PER_TYPE,
+ sizeof(struct opaque_info_per_type));
switch (new->data->type) {
case OSPF_OPAQUE_LINK_LSA:
@@ -711,13 +701,9 @@ register_opaque_info_per_id(struct opaque_info_per_type *oipt,
{
struct opaque_info_per_id *oipi;
- if ((oipi = XCALLOC(MTYPE_OPAQUE_INFO_PER_ID,
- sizeof(struct opaque_info_per_id)))
- == NULL) {
- zlog_warn("register_opaque_info_per_id: XMALLOC: %s",
- safe_strerror(errno));
- goto out;
- }
+ oipi = XCALLOC(MTYPE_OPAQUE_INFO_PER_ID,
+ sizeof(struct opaque_info_per_id));
+
oipi->opaque_id = GET_OPAQUE_ID(ntohl(new->data->id.s_addr));
oipi->t_opaque_lsa_self = NULL;
oipi->opqctl_type = oipt;
@@ -725,7 +711,6 @@ register_opaque_info_per_id(struct opaque_info_per_type *oipt,
listnode_add(oipt->id_list, oipi);
-out:
return oipi;
}
diff --git a/ospfd/ospf_packet.c b/ospfd/ospf_packet.c
index 486ef3335d..f1d4a39dba 100644
--- a/ospfd/ospf_packet.c
+++ b/ospfd/ospf_packet.c
@@ -35,6 +35,7 @@
#include "checksum.h"
#include "md5.h"
#include "vrf.h"
+#include "ospf_errors.h"
#include "ospfd/ospfd.h"
#include "ospfd/ospf_network.h"
@@ -230,7 +231,8 @@ void ospf_fifo_free(struct ospf_fifo *fifo)
void ospf_packet_add(struct ospf_interface *oi, struct ospf_packet *op)
{
if (!oi->obuf) {
- zlog_err(
+ flog_err(
+ OSPF_ERR_PKT_PROCESS,
"ospf_packet_add(interface %s in state %d [%s], packet type %s, "
"destination %s) called with NULL obuf, ignoring "
"(please report this bug)!\n",
@@ -253,7 +255,8 @@ static void ospf_packet_add_top(struct ospf_interface *oi,
struct ospf_packet *op)
{
if (!oi->obuf) {
- zlog_err(
+ flog_err(
+ OSPF_ERR_PKT_PROCESS,
"ospf_packet_add(interface %s in state %d [%s], packet type %s, "
"destination %s) called with NULL obuf, ignoring "
"(please report this bug)!\n",
@@ -1915,17 +1918,18 @@ static void ospf_ls_upd(struct ospf *ospf, struct ip *iph,
char buf2[INET_ADDRSTRLEN];
char buf3[INET_ADDRSTRLEN];
- zlog_err(
- "Incoming Router-LSA from %s with "
- "Adv-ID[%s] != LS-ID[%s]",
- inet_ntop(AF_INET, &ospfh->router_id,
- buf1, INET_ADDRSTRLEN),
- inet_ntop(AF_INET, &lsa->data->id, buf2,
- INET_ADDRSTRLEN),
- inet_ntop(AF_INET,
- &lsa->data->adv_router, buf3,
- INET_ADDRSTRLEN));
- zlog_err(
+ flog_err(OSPF_ERR_ROUTER_LSA_MISMATCH,
+ "Incoming Router-LSA from %s with "
+ "Adv-ID[%s] != LS-ID[%s]",
+ inet_ntop(AF_INET, &ospfh->router_id,
+ buf1, INET_ADDRSTRLEN),
+ inet_ntop(AF_INET, &lsa->data->id,
+ buf2, INET_ADDRSTRLEN),
+ inet_ntop(AF_INET,
+ &lsa->data->adv_router,
+ buf3, INET_ADDRSTRLEN));
+ flog_err(
+ OSPF_ERR_DOMAIN_CORRUPT,
"OSPF domain compromised by attack or corruption. "
"Verify correct operation of -ALL- OSPF routers.");
DISCARD_LSA(lsa, 0);
diff --git a/ospfd/ospf_spf.c b/ospfd/ospf_spf.c
index c6c16e7169..e3c729f65e 100644
--- a/ospfd/ospf_spf.c
+++ b/ospfd/ospf_spf.c
@@ -154,9 +154,6 @@ static struct vertex_parent *vertex_parent_new(struct vertex *v, int backlink,
new = XMALLOC(MTYPE_OSPF_VERTEX_PARENT, sizeof(struct vertex_parent));
- if (new == NULL)
- return NULL;
-
new->parent = v;
new->backlink = backlink;
new->nexthop = hop;
diff --git a/ospfd/ospf_sr.c b/ospfd/ospf_sr.c
index e5fc3e2954..6cb697f3ab 100644
--- a/ospfd/ospf_sr.c
+++ b/ospfd/ospf_sr.c
@@ -48,6 +48,7 @@
#include "vty.h"
#include "zclient.h"
#include <lib/json.h>
+#include "ospf_errors.h"
#include "ospfd/ospfd.h"
#include "ospfd/ospf_interface.h"
@@ -128,12 +129,6 @@ static struct sr_node *sr_node_new(struct in_addr *rid)
/* Allocate Segment Routing node memory */
new = XCALLOC(MTYPE_OSPF_SR_PARAMS, sizeof(struct sr_node));
- /* Sanity Check */
- if (new == NULL) {
- zlog_err("SR (%s): Abort! can't create new SR node", __func__);
- return NULL;
- }
-
/* Default Algorithm, SRGB and MSD */
for (int i = 0; i < ALGORITHM_COUNT; i++)
new->algo[i] = SR_ALGORITHM_UNSET;
@@ -735,9 +730,6 @@ static struct sr_link *get_ext_link_sid(struct tlv_header *tlvh)
srl = XCALLOC(MTYPE_OSPF_SR_PARAMS, sizeof(struct sr_link));
- if (srl == NULL)
- return NULL;
-
/* Initialize TLV browsing */
length = ntohs(tlvh->length) - EXT_TLV_LINK_SIZE;
sub_tlvh = (struct tlv_header *)((char *)(tlvh) + TLV_HDR_SIZE
@@ -820,9 +812,6 @@ static struct sr_prefix *get_ext_prefix_sid(struct tlv_header *tlvh)
srp = XCALLOC(MTYPE_OSPF_SR_PARAMS, sizeof(struct sr_prefix));
- if (srp == NULL)
- return NULL;
-
/* Initialize TLV browsing */
length = ntohs(tlvh->length) - EXT_TLV_PREFIX_SIZE;
sub_tlvh = (struct tlv_header *)((char *)(tlvh) + TLV_HDR_SIZE
@@ -832,8 +821,9 @@ static struct sr_prefix *get_ext_prefix_sid(struct tlv_header *tlvh)
case EXT_SUBTLV_PREFIX_SID:
psid = (struct ext_subtlv_prefix_sid *)sub_tlvh;
if (psid->algorithm != SR_ALGORITHM_SPF) {
- zlog_err("SR (%s): Unsupported Algorithm",
- __func__);
+ flog_err(OSPF_ERR_SR_INVALID_ALGORITHM,
+ "SR (%s): Unsupported Algorithm",
+ __func__);
XFREE(MTYPE_OSPF_SR_PARAMS, srp);
return NULL;
}
@@ -1112,7 +1102,8 @@ void ospf_sr_ri_lsa_update(struct ospf_lsa *lsa)
return;
if (OspfSR.neighbors == NULL) {
- zlog_err("SR (%s): Abort! no valid SR DataBase", __func__);
+ flog_err(OSPF_ERR_SR_INVALID_DB,
+ "SR (%s): Abort! no valid SR DataBase", __func__);
return;
}
@@ -1122,17 +1113,18 @@ void ospf_sr_ri_lsa_update(struct ospf_lsa *lsa)
/* Sanity check */
if (srn == NULL) {
- zlog_err("SR (%s): Abort! can't create SR node in hash table",
- __func__);
+ flog_err(OSPF_ERR_SR_NODE_CREATE,
+ "SR (%s): Abort! can't create SR node in hash table",
+ __func__);
return;
}
if ((srn->instance != 0) && (srn->instance != ntohl(lsah->id.s_addr))) {
- zlog_err(
- "SR (%s): Abort! Wrong "
- "LSA ID 4.0.0.%u for SR node %s/%u",
- __func__, GET_OPAQUE_ID(ntohl(lsah->id.s_addr)),
- inet_ntoa(lsah->adv_router), srn->instance);
+ flog_err(OSPF_ERR_SR_INVALID_LSA_ID,
+ "SR (%s): Abort! Wrong "
+ "LSA ID 4.0.0.%u for SR node %s/%u",
+ __func__, GET_OPAQUE_ID(ntohl(lsah->id.s_addr)),
+ inet_ntoa(lsah->adv_router), srn->instance);
return;
}
@@ -1221,7 +1213,8 @@ void ospf_sr_ri_lsa_delete(struct ospf_lsa *lsa)
/* Sanity check */
if (OspfSR.neighbors == NULL) {
- zlog_err("SR (%s): Abort! no valid SR Data Base", __func__);
+ flog_err(OSPF_ERR_SR_INVALID_DB,
+ "SR (%s): Abort! no valid SR Data Base", __func__);
return;
}
@@ -1230,15 +1223,18 @@ void ospf_sr_ri_lsa_delete(struct ospf_lsa *lsa)
/* Sanity check */
if (srn == NULL) {
- zlog_err("SR (%s): Abort! no entry in SRDB for SR Node %s",
- __func__, inet_ntoa(lsah->adv_router));
+ flog_err(OSPF_ERR_SR_NODE_CREATE,
+ "SR (%s): Abort! no entry in SRDB for SR Node %s",
+ __func__, inet_ntoa(lsah->adv_router));
return;
}
if ((srn->instance != 0) && (srn->instance != ntohl(lsah->id.s_addr))) {
- zlog_err("SR (%s): Abort! Wrong LSA ID 4.0.0.%u for SR node %s",
- __func__, GET_OPAQUE_ID(ntohl(lsah->id.s_addr)),
- inet_ntoa(lsah->adv_router));
+ flog_err(
+ OSPF_ERR_SR_INVALID_LSA_ID,
+ "SR (%s): Abort! Wrong LSA ID 4.0.0.%u for SR node %s",
+ __func__, GET_OPAQUE_ID(ntohl(lsah->id.s_addr)),
+ inet_ntoa(lsah->adv_router));
return;
}
@@ -1264,7 +1260,8 @@ void ospf_sr_ext_link_lsa_update(struct ospf_lsa *lsa)
/* Sanity check */
if (OspfSR.neighbors == NULL) {
- zlog_err("SR (%s): Abort! no valid SR DataBase", __func__);
+ flog_err(OSPF_ERR_SR_INVALID_DB,
+ "SR (%s): Abort! no valid SR DataBase", __func__);
return;
}
@@ -1275,8 +1272,9 @@ void ospf_sr_ext_link_lsa_update(struct ospf_lsa *lsa)
/* Sanity check */
if (srn == NULL) {
- zlog_err("SR (%s): Abort! can't create SR node in hash table",
- __func__);
+ flog_err(OSPF_ERR_SR_NODE_CREATE,
+ "SR (%s): Abort! can't create SR node in hash table",
+ __func__);
return;
}
@@ -1314,7 +1312,8 @@ void ospf_sr_ext_link_lsa_delete(struct ospf_lsa *lsa)
/* Sanity check */
if (OspfSR.neighbors == NULL) {
- zlog_err("SR (%s): Abort! no valid SR DataBase", __func__);
+ flog_err(OSPF_ERR_SR_INVALID_DB,
+ "SR (%s): Abort! no valid SR DataBase", __func__);
return;
}
@@ -1371,7 +1370,8 @@ void ospf_sr_ext_prefix_lsa_update(struct ospf_lsa *lsa)
/* Sanity check */
if (OspfSR.neighbors == NULL) {
- zlog_err("SR (%s): Abort! no valid SR DataBase", __func__);
+ flog_err(OSPF_ERR_SR_INVALID_DB,
+ "SR (%s): Abort! no valid SR DataBase", __func__);
return;
}
@@ -1382,8 +1382,9 @@ void ospf_sr_ext_prefix_lsa_update(struct ospf_lsa *lsa)
/* Sanity check */
if (srn == NULL) {
- zlog_err("SR (%s): Abort! can't create SR node in hash table",
- __func__);
+ flog_err(OSPF_ERR_SR_NODE_CREATE,
+ "SR (%s): Abort! can't create SR node in hash table",
+ __func__);
return;
}
@@ -1422,7 +1423,8 @@ void ospf_sr_ext_prefix_lsa_delete(struct ospf_lsa *lsa)
/* Sanity check */
if (OspfSR.neighbors == NULL) {
- zlog_err("SR (%s): Abort! no valid SR DataBase", __func__);
+ flog_err(OSPF_ERR_SR_INVALID_DB,
+ "SR (%s): Abort! no valid SR DataBase", __func__);
return;
}
diff --git a/ospfd/ospf_te.c b/ospfd/ospf_te.c
index 86125d0c76..cc2d9282fe 100644
--- a/ospfd/ospf_te.c
+++ b/ospfd/ospf_te.c
@@ -857,11 +857,6 @@ static int ospf_mpls_te_new_if(struct interface *ifp)
}
new = XCALLOC(MTYPE_OSPF_MPLS_TE, sizeof(struct mpls_te_link));
- if (new == NULL) {
- zlog_warn("ospf_mpls_te_new_if: XMALLOC: %s",
- safe_strerror(errno));
- return rc;
- }
new->instance = get_mpls_te_instance_value();
new->ifp = ifp;
diff --git a/ospfd/ospfd.c b/ospfd/ospfd.c
index 2298c2261a..ac8f0d92c3 100644
--- a/ospfd/ospfd.c
+++ b/ospfd/ospfd.c
@@ -38,6 +38,7 @@
#include "bfd.h"
#include "libfrr.h"
#include "defaults.h"
+#include "lib_errors.h"
#include "ospfd/ospfd.h"
#include "ospfd/ospf_network.h"
@@ -2087,25 +2088,17 @@ static int ospf_vrf_enable(struct vrf *vrf)
old_vrf_id);
if (old_vrf_id != ospf->vrf_id) {
- if (ospfd_privs.change(ZPRIVS_RAISE)) {
- zlog_err(
- "ospf_sock_init: could not raise privs, %s",
- safe_strerror(errno));
- }
-
- /* stop zebra redist to us for old vrf */
- zclient_send_dereg_requests(zclient, old_vrf_id);
+ frr_elevate_privs(&ospfd_privs) {
+ /* stop zebra redist to us for old vrf */
+ zclient_send_dereg_requests(zclient,
+ old_vrf_id);
- ospf_set_redist_vrf_bitmaps(ospf);
+ ospf_set_redist_vrf_bitmaps(ospf);
- /* start zebra redist to us for new vrf */
- ospf_zebra_vrf_register(ospf);
+ /* start zebra redist to us for new vrf */
+ ospf_zebra_vrf_register(ospf);
- ret = ospf_sock_init(ospf);
- if (ospfd_privs.change(ZPRIVS_LOWER)) {
- zlog_err(
- "ospf_sock_init: could not lower privs, %s",
- safe_strerror(errno));
+ ret = ospf_sock_init(ospf);
}
if (ret < 0 || ospf->fd <= 0)
return 0;
diff --git a/ospfd/subdir.am b/ospfd/subdir.am
index f2e292e186..cd659a9bc9 100644
--- a/ospfd/subdir.am
+++ b/ospfd/subdir.am
@@ -20,6 +20,7 @@ ospfd_libfrrospf_a_SOURCES = \
ospfd/ospf_bfd.c \
ospfd/ospf_dump.c \
ospfd/ospf_dump_api.c \
+ ospfd/ospf_errors.c \
ospfd/ospf_ext.c \
ospfd/ospf_flood.c \
ospfd/ospf_ia.c \
@@ -68,6 +69,7 @@ noinst_HEADERS += \
ospfd/ospf_apiserver.h \
ospfd/ospf_ase.h \
ospfd/ospf_bfd.h \
+ ospfd/ospf_errors.h \
ospfd/ospf_ext.h \
ospfd/ospf_flood.h \
ospfd/ospf_ia.h \
diff --git a/pbrd/pbr_vty.c b/pbrd/pbr_vty.c
index 44e14c5477..a4b87f99d9 100644
--- a/pbrd/pbr_vty.c
+++ b/pbrd/pbr_vty.c
@@ -580,6 +580,9 @@ static int pbr_interface_config_write(struct vty *vty)
vty_frame(vty, "interface %s vrf %s\n",
ifp->name, vrf->name);
+ if (ifp->desc)
+ vty_out(vty, " description %s\n", ifp->desc);
+
pbr_map_write_interfaces(vty, ifp);
vty_endframe(vty, "!\n");
diff --git a/pbrd/pbr_zebra.c b/pbrd/pbr_zebra.c
index 8d336c9d0d..25d64238bf 100644
--- a/pbrd/pbr_zebra.c
+++ b/pbrd/pbr_zebra.c
@@ -54,12 +54,6 @@ struct pbr_interface *pbr_if_new(struct interface *ifp)
pbr_ifp = XCALLOC(MTYPE_PBR_INTERFACE, sizeof(*pbr_ifp));
- if (!pbr_ifp) {
- zlog_err("%s: PBR XCALLOC(%zu) failure", __PRETTY_FUNCTION__,
- sizeof(*pbr_ifp));
- return 0;
- }
-
ifp->info = pbr_ifp;
return pbr_ifp;
}
diff --git a/pimd/pim_bfd.c b/pimd/pim_bfd.c
index 4a3cf715da..f7a217b514 100644
--- a/pimd/pim_bfd.c
+++ b/pimd/pim_bfd.c
@@ -51,10 +51,12 @@ void pim_bfd_write_config(struct vty *vty, struct interface *ifp)
if (!bfd_info)
return;
+#if HAVE_BFDD == 0
if (CHECK_FLAG(bfd_info->flags, BFD_FLAG_PARAM_CFG))
vty_out(vty, " ip pim bfd %d %d %d\n", bfd_info->detect_mult,
bfd_info->required_min_rx, bfd_info->desired_min_tx);
else
+#endif /* ! HAVE_BFDD */
vty_out(vty, " ip pim bfd\n");
}
diff --git a/pimd/pim_br.c b/pimd/pim_br.c
index 6184ea12c4..fc6a02ec93 100644
--- a/pimd/pim_br.c
+++ b/pimd/pim_br.c
@@ -64,7 +64,6 @@ void pim_br_set_pmbr(struct prefix_sg *sg, struct in_addr br)
if (!pim_br) {
pim_br = XCALLOC(MTYPE_PIM_BR, sizeof(*pim_br));
-
pim_br->sg = *sg;
listnode_add(pim_br_list, pim_br);
diff --git a/pimd/pim_cmd.c b/pimd/pim_cmd.c
index 460bbfeae7..6eb4303fb7 100644
--- a/pimd/pim_cmd.c
+++ b/pimd/pim_cmd.c
@@ -5106,11 +5106,6 @@ static int pim_rp_cmd_worker(struct pim_instance *pim, struct vty *vty,
result = pim_rp_new(pim, rp, group, plist);
- if (result == PIM_MALLOC_FAIL) {
- vty_out(vty, "%% Out of memory\n");
- return CMD_WARNING_CONFIG_FAILED;
- }
-
if (result == PIM_GROUP_BAD_ADDRESS) {
vty_out(vty, "%% Bad group address specified: %s\n", group);
return CMD_WARNING_CONFIG_FAILED;
@@ -7547,7 +7542,12 @@ DEFUN (no_ip_pim_bfd,
return CMD_SUCCESS;
}
-DEFUN (ip_pim_bfd_param,
+#if HAVE_BFDD > 0
+DEFUN_HIDDEN(
+#else
+DEFUN(
+#endif /* HAVE_BFDD */
+ ip_pim_bfd_param,
ip_pim_bfd_param_cmd,
"ip pim bfd (2-255) (50-60000) (50-60000)",
IP_STR
@@ -7585,12 +7585,14 @@ DEFUN (ip_pim_bfd_param,
return CMD_SUCCESS;
}
+#if HAVE_BFDD == 0
ALIAS(no_ip_pim_bfd, no_ip_pim_bfd_param_cmd,
"no ip pim bfd (2-255) (50-60000) (50-60000)", NO_STR IP_STR PIM_STR
"Enables BFD support\n"
"Detect Multiplier\n"
"Required min receive interval\n"
"Desired min transmit interval\n")
+#endif /* !HAVE_BFDD */
static int ip_msdp_peer_cmd_worker(struct pim_instance *pim, struct vty *vty,
const char *peer, const char *local)
@@ -8906,5 +8908,7 @@ void pim_cmd_init(void)
install_element(INTERFACE_NODE, &ip_pim_bfd_cmd);
install_element(INTERFACE_NODE, &ip_pim_bfd_param_cmd);
install_element(INTERFACE_NODE, &no_ip_pim_bfd_cmd);
+#if HAVE_BFDD == 0
install_element(INTERFACE_NODE, &no_ip_pim_bfd_param_cmd);
+#endif /* !HAVE_BFDD */
}
diff --git a/pimd/pim_errors.c b/pimd/pim_errors.c
new file mode 100644
index 0000000000..d154752bdc
--- /dev/null
+++ b/pimd/pim_errors.c
@@ -0,0 +1,49 @@
+/*
+ * PIM-specific error messages.
+ * Copyright (C) 2018 Cumulus Networks, Inc.
+ * Donald Sharp
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This 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 "lib/ferr.h"
+#include "pim_errors.h"
+
+/* clang-format off */
+static struct log_ref ferr_pim_err[] = {
+ {
+ .code = PIM_ERR_MSDP_PACKET,
+ .title = "PIM MSDP Packet Error",
+ .description = "PIM has received a packet from a peer that does not correctly decode",
+ .suggestion = "Check MSDP peer and ensure it is correctly working"
+ },
+ {
+ .code = PIM_ERR_CONFIG,
+ .title = "PIM Configuration Error",
+ .description = "PIM has detected a configuration error",
+ .suggestion = "Ensure the configuration is correct and apply correct configuration"
+ },
+ {
+ .code = END_FERR,
+ }
+};
+/* clang-format on */
+
+void pim_error_init(void)
+{
+ log_ref_add(ferr_pim_err);
+}
diff --git a/pimd/pim_errors.h b/pimd/pim_errors.h
new file mode 100644
index 0000000000..ad9c95a93d
--- /dev/null
+++ b/pimd/pim_errors.h
@@ -0,0 +1,33 @@
+/*
+ * PIM-specific error messages.
+ * Copyright (C) 2018 Cumulus Networks, Inc.
+ * Donald Sharp
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; see the file COPYING; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef __PIM_ERRORS_H__
+#define __PIM_ERRORS_H__
+
+#include "lib/ferr.h"
+
+enum pim_log_refs {
+ PIM_ERR_MSDP_PACKET = PIM_FERR_START,
+ PIM_ERR_CONFIG,
+};
+
+extern void pim_error_init(void);
+
+#endif
diff --git a/pimd/pim_ifchannel.c b/pimd/pim_ifchannel.c
index eb3307589e..92a78c4bb4 100644
--- a/pimd/pim_ifchannel.c
+++ b/pimd/pim_ifchannel.c
@@ -549,26 +549,6 @@ struct pim_ifchannel *pim_ifchannel_add(struct interface *ifp,
up = pim_upstream_add(pim_ifp->pim, sg, NULL, up_flags,
__PRETTY_FUNCTION__, ch);
- if (!up) {
- zlog_err(
- "%s: could not attach upstream (S,G)=%s on interface %s",
- __PRETTY_FUNCTION__, pim_str_sg_dump(sg), ifp->name);
-
- if (ch->parent)
- listnode_delete(ch->parent->sources, ch);
-
- pim_ifchannel_remove_children(ch);
- if (ch->sources)
- list_delete_and_null(&ch->sources);
-
- THREAD_OFF(ch->t_ifjoin_expiry_timer);
- THREAD_OFF(ch->t_ifjoin_prune_pending_timer);
- THREAD_OFF(ch->t_ifassert_timer);
-
- RB_REMOVE(pim_ifchannel_rb, &pim_ifp->ifchannel_rb, ch);
- XFREE(MTYPE_PIM_IFCHANNEL, ch);
- return NULL;
- }
ch->upstream = up;
listnode_add_sort(up->ifchannels, ch);
diff --git a/pimd/pim_igmp.c b/pimd/pim_igmp.c
index b46f1b5e9d..270f1e3f27 100644
--- a/pimd/pim_igmp.c
+++ b/pimd/pim_igmp.c
@@ -24,6 +24,7 @@
#include "if.h"
#include "hash.h"
#include "jhash.h"
+#include "lib_errors.h"
#include "pimd.h"
#include "pim_igmp.h"
@@ -96,7 +97,8 @@ static int igmp_sock_open(struct in_addr ifaddr, struct interface *ifp,
}
if (!join) {
- zlog_err(
+ flog_err_sys(
+ LIB_ERR_SOCKET,
"IGMP socket fd=%d could not join any group on interface address %s",
fd, inet_ntoa(ifaddr));
close(fd);
@@ -697,7 +699,8 @@ static void sock_close(struct igmp_sock *igmp)
THREAD_OFF(igmp->t_igmp_read);
if (close(igmp->fd)) {
- zlog_err(
+ flog_err(
+ LIB_ERR_SOCKET,
"Failure closing IGMP socket %s fd=%d on interface %s: errno=%d: %s",
inet_ntoa(igmp->ifaddr), igmp->fd,
igmp->interface->name, errno, safe_strerror(errno));
@@ -960,12 +963,6 @@ struct igmp_sock *pim_igmp_sock_add(struct list *igmp_sock_list,
}
igmp = igmp_sock_new(fd, ifaddr, ifp, mtrace_only);
- if (!igmp) {
- zlog_err("%s %s: igmp_sock_new() failure", __FILE__,
- __PRETTY_FUNCTION__);
- close(fd);
- return 0;
- }
igmp_read_on(igmp);
diff --git a/pimd/pim_igmpv3.c b/pimd/pim_igmpv3.c
index b32d71cc0d..7b21376c99 100644
--- a/pimd/pim_igmpv3.c
+++ b/pimd/pim_igmpv3.c
@@ -21,6 +21,7 @@
#include "log.h"
#include "memory.h"
#include "if.h"
+#include "lib_errors.h"
#include "pimd.h"
#include "pim_iface.h"
@@ -486,9 +487,6 @@ static struct igmp_source *add_source_by_addr(struct igmp_sock *igmp,
}
src = source_new(group, src_addr);
- if (!src) {
- return 0;
- }
return src;
}
@@ -579,10 +577,6 @@ static void isex_excl(struct igmp_group *group, int num_sources,
/* E.4: if not found, create source with timer=GMI:
* (A-X-Y) */
source = source_new(group, *src_addr);
- if (!source) {
- /* ugh, internal malloc failure, skip source */
- continue;
- }
zassert(!source->t_source_timer); /* timer == 0 */
igmp_source_reset_gmi(group->group_igmp_sock, group,
source);
@@ -637,10 +631,6 @@ static void isex_incl(struct igmp_group *group, int num_sources,
/* I.4: if not found, create source with timer=0 (B-A)
*/
source = source_new(group, *src_addr);
- if (!source) {
- /* ugh, internal malloc failure, skip source */
- continue;
- }
zassert(!source->t_source_timer); /* (B-A) timer=0 */
}
@@ -720,10 +710,6 @@ static void toin_incl(struct igmp_group *group, int num_sources,
} else {
/* If not found, create new source */
source = source_new(group, *src_addr);
- if (!source) {
- /* ugh, internal malloc failure, skip source */
- continue;
- }
}
/* (B)=GMI */
@@ -765,10 +751,6 @@ static void toin_excl(struct igmp_group *group, int num_sources,
} else {
/* If not found, create new source */
source = source_new(group, *src_addr);
- if (!source) {
- /* ugh, internal malloc failure, skip source */
- continue;
- }
}
/* (A)=GMI */
@@ -854,10 +836,6 @@ static void toex_incl(struct igmp_group *group, int num_sources,
/* If source not found, create source with timer=0:
* (B-A)=0 */
source = source_new(group, *src_addr);
- if (!source) {
- /* ugh, internal malloc failure, skip source */
- continue;
- }
zassert(!source->t_source_timer); /* (B-A) timer=0 */
}
@@ -917,10 +895,6 @@ static void toex_excl(struct igmp_group *group, int num_sources,
* (A-X-Y)=Group Timer */
long group_timer_msec;
source = source_new(group, *src_addr);
- if (!source) {
- /* ugh, internal malloc failure, skip source */
- continue;
- }
zassert(!source->t_source_timer); /* timer == 0 */
group_timer_msec = igmp_group_timer_remain_msec(group);
@@ -1431,10 +1405,6 @@ static void block_excl(struct igmp_group *group, int num_sources,
* (A-X-Y)=Group Timer */
long group_timer_msec;
source = source_new(group, *src_addr);
- if (!source) {
- /* ugh, internal malloc failure, skip source */
- continue;
- }
zassert(!source->t_source_timer); /* timer == 0 */
group_timer_msec = igmp_group_timer_remain_msec(group);
@@ -1614,7 +1584,8 @@ void igmp_v3_send_query(struct igmp_group *group, int fd, const char *ifname,
msg_size = IGMP_V3_SOURCES_OFFSET + (num_sources << 2);
if (msg_size > query_buf_size) {
- zlog_err(
+ flog_err(
+ LIB_ERR_DEVELOPMENT,
"%s %s: unable to send: msg_size=%zd larger than query_buf_size=%d",
__FILE__, __PRETTY_FUNCTION__, msg_size,
query_buf_size);
diff --git a/pimd/pim_instance.c b/pimd/pim_instance.c
index e664bf3062..8dc48cc004 100644
--- a/pimd/pim_instance.c
+++ b/pimd/pim_instance.c
@@ -22,6 +22,7 @@
#include "hash.h"
#include "vrf.h"
+#include "lib_errors.h"
#include "pimd.h"
#include "pim_ssm.h"
@@ -94,10 +95,6 @@ static struct pim_instance *pim_instance_init(struct vrf *vrf)
zlog_debug("%s: NHT rpf hash init ", __PRETTY_FUNCTION__);
pim->ssm_info = pim_ssm_init();
- if (!pim->ssm_info) {
- pim_instance_terminate(pim);
- return NULL;
- }
pim->static_routes = list_new();
pim->static_routes->del = (void (*)(void *))pim_static_route_free;
@@ -132,14 +129,6 @@ static int pim_vrf_new(struct vrf *vrf)
struct pim_instance *pim = pim_instance_init(vrf);
zlog_debug("VRF Created: %s(%u)", vrf->name, vrf->vrf_id);
- if (pim == NULL) {
- zlog_err("%s %s: pim class init failure ", __FILE__,
- __PRETTY_FUNCTION__);
- /*
- * We will crash and burn otherwise
- */
- exit(1);
- }
vrf->info = (void *)pim;
diff --git a/pimd/pim_main.c b/pimd/pim_main.c
index c4cab25ae9..578794086d 100644
--- a/pimd/pim_main.c
+++ b/pimd/pim_main.c
@@ -47,6 +47,7 @@
#include "pim_msdp.h"
#include "pim_iface.h"
#include "pim_bfd.h"
+#include "pim_errors.h"
extern struct host host;
@@ -108,6 +109,7 @@ int main(int argc, char **argv, char **envp)
/*
* Initializations
*/
+ pim_error_init();
pim_vrf_init();
access_list_init();
prefix_list_init();
diff --git a/pimd/pim_mroute.c b/pimd/pim_mroute.c
index dd30678405..c69e2939e4 100644
--- a/pimd/pim_mroute.c
+++ b/pimd/pim_mroute.c
@@ -25,6 +25,7 @@
#include "vty.h"
#include "plist.h"
#include "sockopt.h"
+#include "lib_errors.h"
#include "pimd.h"
#include "pim_rpf.h"
@@ -55,27 +56,22 @@ static int pim_mroute_set(struct pim_instance *pim, int enable)
* We need to create the VRF table for the pim mroute_socket
*/
if (pim->vrf_id != VRF_DEFAULT) {
- if (pimd_privs.change(ZPRIVS_RAISE))
- zlog_err(
- "pim_mroute_socket_enable: could not raise privs, %s",
- safe_strerror(errno));
+ frr_elevate_privs(&pimd_privs) {
- opt = pim->vrf->data.l.table_id;
- err = setsockopt(pim->mroute_socket, IPPROTO_IP, MRT_TABLE,
- &opt, opt_len);
- if (err) {
- zlog_warn(
- "%s %s: failure: setsockopt(fd=%d,IPPROTO_IP, MRT_TABLE=%d): errno=%d: %s",
- __FILE__, __PRETTY_FUNCTION__,
- pim->mroute_socket, opt, errno,
- safe_strerror(errno));
- return -1;
- }
+ opt = pim->vrf->data.l.table_id;
+ err = setsockopt(pim->mroute_socket, IPPROTO_IP,
+ MRT_TABLE,
+ &opt, opt_len);
+ if (err) {
+ zlog_warn(
+ "%s %s: failure: setsockopt(fd=%d,IPPROTO_IP, MRT_TABLE=%d): errno=%d: %s",
+ __FILE__, __PRETTY_FUNCTION__,
+ pim->mroute_socket, opt, errno,
+ safe_strerror(errno));
+ return -1;
+ }
- if (pimd_privs.change(ZPRIVS_LOWER))
- zlog_err(
- "pim_mroute_socket_enable: could not lower privs, %s",
- safe_strerror(errno));
+ }
}
opt = enable ? MRT_INIT : MRT_DONE;
@@ -708,32 +704,29 @@ int pim_mroute_socket_enable(struct pim_instance *pim)
{
int fd;
- if (pimd_privs.change(ZPRIVS_RAISE))
- zlog_err("pim_mroute_socket_enable: could not raise privs, %s",
- safe_strerror(errno));
+ frr_elevate_privs(&pimd_privs) {
- fd = socket(AF_INET, SOCK_RAW, IPPROTO_IGMP);
+ fd = socket(AF_INET, SOCK_RAW, IPPROTO_IGMP);
- if (fd < 0) {
- zlog_warn("Could not create mroute socket: errno=%d: %s", errno,
- safe_strerror(errno));
- return -2;
- }
+ if (fd < 0) {
+ zlog_warn("Could not create mroute socket: errno=%d: %s",
+ errno,
+ safe_strerror(errno));
+ return -2;
+ }
#ifdef SO_BINDTODEVICE
- if (pim->vrf->vrf_id != VRF_DEFAULT
- && setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, pim->vrf->name,
- strlen(pim->vrf->name))) {
- zlog_warn("Could not setsockopt SO_BINDTODEVICE: %s",
- safe_strerror(errno));
- close(fd);
- return -3;
- }
+ if (pim->vrf->vrf_id != VRF_DEFAULT
+ && setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE,
+ pim->vrf->name, strlen(pim->vrf->name))) {
+ zlog_warn("Could not setsockopt SO_BINDTODEVICE: %s",
+ safe_strerror(errno));
+ close(fd);
+ return -3;
+ }
#endif
- if (pimd_privs.change(ZPRIVS_LOWER))
- zlog_err("pim_mroute_socket_enable: could not lower privs, %s",
- safe_strerror(errno));
+ }
pim->mroute_socket = fd;
if (pim_mroute_set(pim, 1)) {
diff --git a/pimd/pim_msdp.c b/pimd/pim_msdp.c
index 4910cb8b38..7fcf42e8ce 100644
--- a/pimd/pim_msdp.c
+++ b/pimd/pim_msdp.c
@@ -28,6 +28,7 @@
#include <lib/thread.h>
#include <lib/vty.h>
#include <lib/plist.h>
+#include <lib/lib_errors.h>
#include "pimd.h"
#include "pim_cmd.h"
@@ -517,7 +518,8 @@ static void pim_msdp_sa_local_del_on_up_del(struct pim_instance *pim,
* the flow. Accounting for such cases requires lot of
* changes; perhaps
* address this in the next release? - XXX */
- zlog_err(
+ flog_err(
+ LIB_ERR_DEVELOPMENT,
"MSDP sa %s SPT teardown is causing the local entry to be removed",
sa->sg_str);
return;
diff --git a/pimd/pim_msdp_packet.c b/pimd/pim_msdp_packet.c
index 978d979245..65232aafa2 100644
--- a/pimd/pim_msdp_packet.c
+++ b/pimd/pim_msdp_packet.c
@@ -23,9 +23,11 @@
#include <lib/stream.h>
#include <lib/thread.h>
#include <lib/vty.h>
+#include <lib/lib_errors.h>
#include "pimd.h"
#include "pim_str.h"
+#include "pim_errors.h"
#include "pim_msdp.h"
#include "pim_msdp_packet.h"
@@ -145,7 +147,8 @@ static void pim_msdp_connect_check(struct pim_msdp_peer *mp)
/* If getsockopt is fail, this is fatal error. */
if (ret < 0) {
- zlog_err("can't get sockopt for nonblocking connect");
+ flog_err_sys(LIB_ERR_SOCKET,
+ "can't get sockopt for nonblocking connect");
pim_msdp_peer_reset_tcp_conn(mp, "connect-failed");
return;
}
@@ -481,8 +484,9 @@ static void pim_msdp_pkt_sa_rx_one(struct pim_msdp_peer *mp, struct in_addr rp)
if (prefix_len != 32) {
/* ignore SA update if the prefix length is not 32 */
- zlog_err("rxed sa update with invalid prefix length %d",
- prefix_len);
+ flog_err(PIM_ERR_MSDP_PACKET,
+ "rxed sa update with invalid prefix length %d",
+ prefix_len);
return;
}
if (PIM_DEBUG_MSDP_PACKETS) {
diff --git a/pimd/pim_msdp_socket.c b/pimd/pim_msdp_socket.c
index f245a04353..feac42cf53 100644
--- a/pimd/pim_msdp_socket.c
+++ b/pimd/pim_msdp_socket.c
@@ -26,9 +26,11 @@
#include <lib/vty.h>
#include <lib/if.h>
#include <lib/vrf.h>
+#include <lib/lib_errors.h>
#include "pimd.h"
#include "pim_sock.h"
+#include "pim_errors.h"
#include "pim_msdp.h"
#include "pim_msdp_socket.h"
@@ -41,16 +43,18 @@ static void pim_msdp_update_sock_send_buffer_size(int fd)
socklen_t optlen = sizeof(optval);
if (getsockopt(fd, SOL_SOCKET, SO_SNDBUF, &optval, &optlen) < 0) {
- zlog_err("getsockopt of SO_SNDBUF failed %s\n",
- safe_strerror(errno));
+ flog_err_sys(LIB_ERR_SOCKET,
+ "getsockopt of SO_SNDBUF failed %s\n",
+ safe_strerror(errno));
return;
}
if (optval < size) {
if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &size, sizeof(size))
< 0) {
- zlog_err("Couldn't increase send buffer: %s\n",
- safe_strerror(errno));
+ flog_err_sys(LIB_ERR_SOCKET,
+ "Couldn't increase send buffer: %s\n",
+ safe_strerror(errno));
}
}
}
@@ -70,7 +74,8 @@ static int pim_msdp_sock_accept(struct thread *thread)
/* re-register accept thread */
accept_sock = THREAD_FD(thread);
if (accept_sock < 0) {
- zlog_err("accept_sock is negative value %d", accept_sock);
+ flog_err(LIB_ERR_DEVELOPMENT,
+ "accept_sock is negative value %d", accept_sock);
return -1;
}
pim->msdp.listener.thread = NULL;
@@ -80,8 +85,8 @@ static int pim_msdp_sock_accept(struct thread *thread)
/* accept client connection. */
msdp_sock = sockunion_accept(accept_sock, &su);
if (msdp_sock < 0) {
- zlog_err("pim_msdp_sock_accept failed (%s)",
- safe_strerror(errno));
+ flog_err_sys(LIB_ERR_SOCKET, "pim_msdp_sock_accept failed (%s)",
+ safe_strerror(errno));
return -1;
}
@@ -90,8 +95,9 @@ static int pim_msdp_sock_accept(struct thread *thread)
if (!mp || !PIM_MSDP_PEER_IS_LISTENER(mp)) {
++pim->msdp.rejected_accepts;
if (PIM_DEBUG_MSDP_EVENTS) {
- zlog_err("msdp peer connection refused from %s",
- sockunion2str(&su, buf, SU_ADDRSTRLEN));
+ flog_err(PIM_ERR_MSDP_PACKET,
+ "msdp peer connection refused from %s",
+ sockunion2str(&su, buf, SU_ADDRSTRLEN));
}
close(msdp_sock);
return -1;
@@ -106,7 +112,7 @@ static int pim_msdp_sock_accept(struct thread *thread)
* with this one */
if (mp->fd >= 0) {
if (PIM_DEBUG_MSDP_EVENTS) {
- zlog_err(
+ zlog_notice(
"msdp peer new connection from %s stop old connection",
sockunion2str(&su, buf, SU_ADDRSTRLEN));
}
@@ -135,7 +141,8 @@ int pim_msdp_sock_listen(struct pim_instance *pim)
sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock < 0) {
- zlog_err("socket: %s", safe_strerror(errno));
+ flog_err_sys(LIB_ERR_SOCKET, "socket: %s",
+ safe_strerror(errno));
return sock;
}
@@ -154,42 +161,38 @@ int pim_msdp_sock_listen(struct pim_instance *pim)
struct interface *ifp =
if_lookup_by_name(pim->vrf->name, pim->vrf_id);
if (!ifp) {
- zlog_err("%s: Unable to lookup vrf interface: %s",
- __PRETTY_FUNCTION__, pim->vrf->name);
+ flog_err(LIB_ERR_INTERFACE,
+ "%s: Unable to lookup vrf interface: %s",
+ __PRETTY_FUNCTION__, pim->vrf->name);
close(sock);
return -1;
}
if (pim_socket_bind(sock, ifp)) {
- zlog_err("%s: Unable to bind to socket: %s",
- __PRETTY_FUNCTION__, safe_strerror(errno));
+ flog_err_sys(LIB_ERR_SOCKET,
+ "%s: Unable to bind to socket: %s",
+ __PRETTY_FUNCTION__, safe_strerror(errno));
close(sock);
return -1;
}
}
- if (pimd_privs.change(ZPRIVS_RAISE)) {
- zlog_err("pim_msdp_socket: could not raise privs, %s",
- safe_strerror(errno));
- }
-
- /* bind to well known TCP port */
- rc = bind(sock, (struct sockaddr *)&sin, socklen);
-
- if (pimd_privs.change(ZPRIVS_LOWER)) {
- zlog_err("pim_msdp_socket: could not lower privs, %s",
- safe_strerror(errno));
+ frr_elevate_privs(&pimd_privs) {
+ /* bind to well known TCP port */
+ rc = bind(sock, (struct sockaddr *)&sin, socklen);
}
if (rc < 0) {
- zlog_err("pim_msdp_socket bind to port %d: %s",
- ntohs(sin.sin_port), safe_strerror(errno));
+ flog_err_sys(LIB_ERR_SOCKET,
+ "pim_msdp_socket bind to port %d: %s",
+ ntohs(sin.sin_port), safe_strerror(errno));
close(sock);
return rc;
}
rc = listen(sock, 3 /* backlog */);
if (rc < 0) {
- zlog_err("pim_msdp_socket listen: %s", safe_strerror(errno));
+ flog_err_sys(LIB_ERR_SOCKET, "pim_msdp_socket listen: %s",
+ safe_strerror(errno));
close(sock);
return rc;
}
@@ -219,7 +222,7 @@ int pim_msdp_sock_connect(struct pim_msdp_peer *mp)
* with this one */
if (mp->fd >= 0) {
if (PIM_DEBUG_MSDP_EVENTS) {
- zlog_err(
+ zlog_notice(
"msdp duplicate connect to %s nuke old connection",
mp->key_str);
}
@@ -229,8 +232,9 @@ int pim_msdp_sock_connect(struct pim_msdp_peer *mp)
/* Make socket for the peer. */
mp->fd = sockunion_socket(&mp->su_peer);
if (mp->fd < 0) {
- zlog_err("pim_msdp_socket socket failure: %s",
- safe_strerror(errno));
+ flog_err_sys(LIB_ERR_SOCKET,
+ "pim_msdp_socket socket failure: %s",
+ safe_strerror(errno));
return -1;
}
@@ -238,13 +242,15 @@ int pim_msdp_sock_connect(struct pim_msdp_peer *mp)
struct interface *ifp =
if_lookup_by_name(mp->pim->vrf->name, mp->pim->vrf_id);
if (!ifp) {
- zlog_err("%s: Unable to lookup vrf interface: %s",
- __PRETTY_FUNCTION__, mp->pim->vrf->name);
+ flog_err(LIB_ERR_INTERFACE,
+ "%s: Unable to lookup vrf interface: %s",
+ __PRETTY_FUNCTION__, mp->pim->vrf->name);
return -1;
}
if (pim_socket_bind(mp->fd, ifp)) {
- zlog_err("%s: Unable to bind to socket: %s",
- __PRETTY_FUNCTION__, safe_strerror(errno));
+ flog_err_sys(LIB_ERR_SOCKET,
+ "%s: Unable to bind to socket: %s",
+ __PRETTY_FUNCTION__, safe_strerror(errno));
close(mp->fd);
mp->fd = -1;
return -1;
@@ -261,8 +267,9 @@ int pim_msdp_sock_connect(struct pim_msdp_peer *mp)
/* source bind */
rc = sockunion_bind(mp->fd, &mp->su_local, 0, &mp->su_local);
if (rc < 0) {
- zlog_err("pim_msdp_socket connect bind failure: %s",
- safe_strerror(errno));
+ flog_err_sys(LIB_ERR_SOCKET,
+ "pim_msdp_socket connect bind failure: %s",
+ safe_strerror(errno));
close(mp->fd);
mp->fd = -1;
return rc;
diff --git a/pimd/pim_neighbor.c b/pimd/pim_neighbor.c
index e73422331f..11d8476362 100644
--- a/pimd/pim_neighbor.c
+++ b/pimd/pim_neighbor.c
@@ -25,6 +25,7 @@
#include "if.h"
#include "vty.h"
#include "plist.h"
+#include "lib_errors.h"
#include "pimd.h"
#include "pim_neighbor.h"
@@ -799,7 +800,8 @@ void pim_neighbor_update(struct pim_neighbor *neigh,
if (neigh->prefix_list == addr_list) {
if (addr_list) {
- zlog_err(
+ flog_err(
+ LIB_ERR_DEVELOPMENT,
"%s: internal error: trying to replace same prefix list=%p",
__PRETTY_FUNCTION__, (void *)addr_list);
}
diff --git a/pimd/pim_pim.c b/pimd/pim_pim.c
index f506875282..b103da2e1b 100644
--- a/pimd/pim_pim.c
+++ b/pimd/pim_pim.c
@@ -38,6 +38,7 @@
#include "pim_assert.h"
#include "pim_msg.h"
#include "pim_register.h"
+#include "pim_errors.h"
static int on_pim_hello_send(struct thread *t);
static int pim_hello_send(struct interface *ifp, uint16_t holdtime);
@@ -115,8 +116,9 @@ void pim_sock_delete(struct interface *ifp, const char *delete_message)
delete_message);
if (!ifp->info) {
- zlog_err("%s: %s: but PIM not enabled on interface %s (!)",
- __PRETTY_FUNCTION__, delete_message, ifp->name);
+ flog_err(PIM_ERR_CONFIG,
+ "%s: %s: but PIM not enabled on interface %s (!)",
+ __PRETTY_FUNCTION__, delete_message, ifp->name);
return;
}
diff --git a/pimd/pim_rp.c b/pimd/pim_rp.c
index 783f931752..efcca65993 100644
--- a/pimd/pim_rp.c
+++ b/pimd/pim_rp.c
@@ -31,6 +31,7 @@
#include "plist.h"
#include "nexthop.h"
#include "table.h"
+#include "lib_errors.h"
#include "pimd.h"
#include "pim_vty.h"
@@ -102,24 +103,16 @@ void pim_rp_init(struct pim_instance *pim)
struct route_node *rn;
pim->rp_list = list_new();
- if (!pim->rp_list) {
- zlog_err("Unable to alloc rp_list");
- return;
- }
pim->rp_list->del = (void (*)(void *))pim_rp_info_free;
pim->rp_list->cmp = pim_rp_list_cmp;
pim->rp_table = route_table_init();
- if (!pim->rp_table) {
- zlog_err("Unable to alloc rp_table");
- list_delete_and_null(&pim->rp_list);
- return;
- }
rp_info = XCALLOC(MTYPE_PIM_RP, sizeof(*rp_info));
if (!str2prefix("224.0.0.0/4", &rp_info->group)) {
- zlog_err("Unable to convert 224.0.0.0/4 to prefix");
+ flog_err(LIB_ERR_DEVELOPMENT,
+ "Unable to convert 224.0.0.0/4 to prefix");
list_delete_and_null(&pim->rp_list);
route_table_finish(pim->rp_table);
XFREE(MTYPE_PIM_RP, rp_info);
@@ -133,14 +126,6 @@ void pim_rp_init(struct pim_instance *pim)
listnode_add(pim->rp_list, rp_info);
rn = route_node_get(pim->rp_table, &rp_info->group);
- if (!rn) {
- zlog_err("Failure to get route node for pim->rp_table");
- list_delete_and_null(&pim->rp_list);
- route_table_finish(pim->rp_table);
- XFREE(MTYPE_PIM_RP, rp_info);
- return;
- }
-
rn->info = rp_info;
if (PIM_DEBUG_TRACE)
zlog_debug(
@@ -248,7 +233,8 @@ static struct rp_info *pim_rp_find_match_group(struct pim_instance *pim,
rn = route_node_match(pim->rp_table, group);
if (!rn) {
- zlog_err(
+ flog_err(
+ LIB_ERR_DEVELOPMENT,
"%s: BUG We should have found default group information\n",
__PRETTY_FUNCTION__);
return best;
@@ -636,7 +622,9 @@ int pim_rp_del(struct pim_instance *pim, const char *rp,
rn = route_node_get(pim->rp_table, &rp_info->group);
if (rn) {
if (rn->info != rp_info)
- zlog_err("WTF matey");
+ flog_err(
+ LIB_ERR_DEVELOPMENT,
+ "Expected rn->info to be equal to rp_info");
if (PIM_DEBUG_TRACE) {
char buf[PREFIX_STRLEN];
diff --git a/pimd/pim_sock.c b/pimd/pim_sock.c
index fb0d6b5064..1f584a2f9a 100644
--- a/pimd/pim_sock.c
+++ b/pimd/pim_sock.c
@@ -33,6 +33,7 @@
#include "if.h"
#include "vrf.h"
#include "sockopt.h"
+#include "lib_errors.h"
#include "pimd.h"
#include "pim_mroute.h"
@@ -45,15 +46,11 @@ int pim_socket_raw(int protocol)
{
int fd;
- if (pimd_privs.change(ZPRIVS_RAISE))
- zlog_err("pim_sockek_raw: could not raise privs, %s",
- safe_strerror(errno));
+ frr_elevate_privs(&pimd_privs) {
- fd = socket(AF_INET, SOCK_RAW, protocol);
+ fd = socket(AF_INET, SOCK_RAW, protocol);
- if (pimd_privs.change(ZPRIVS_LOWER))
- zlog_err("pim_socket_raw: could not lower privs, %s",
- safe_strerror(errno));
+ }
if (fd < 0) {
zlog_warn("Could not create raw socket: errno=%d: %s", errno,
@@ -68,17 +65,13 @@ void pim_socket_ip_hdr(int fd)
{
const int on = 1;
- if (pimd_privs.change(ZPRIVS_RAISE))
- zlog_err("%s: could not raise privs, %s", __PRETTY_FUNCTION__,
- safe_strerror(errno));
+ frr_elevate_privs(&pimd_privs) {
- if (setsockopt(fd, IPPROTO_IP, IP_HDRINCL, &on, sizeof(on)))
- zlog_err("%s: Could not turn on IP_HDRINCL option: %s",
- __PRETTY_FUNCTION__, safe_strerror(errno));
+ if (setsockopt(fd, IPPROTO_IP, IP_HDRINCL, &on, sizeof(on)))
+ zlog_err("%s: Could not turn on IP_HDRINCL option: %s",
+ __PRETTY_FUNCTION__, safe_strerror(errno));
- if (pimd_privs.change(ZPRIVS_LOWER))
- zlog_err("%s: could not lower privs, %s", __PRETTY_FUNCTION__,
- safe_strerror(errno));
+ }
}
/*
@@ -90,16 +83,12 @@ int pim_socket_bind(int fd, struct interface *ifp)
int ret = 0;
#ifdef SO_BINDTODEVICE
- if (pimd_privs.change(ZPRIVS_RAISE))
- zlog_err("%s: could not raise privs, %s", __PRETTY_FUNCTION__,
- safe_strerror(errno));
+ frr_elevate_privs(&pimd_privs) {
- ret = setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, ifp->name,
- strlen(ifp->name));
+ ret = setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, ifp->name,
+ strlen(ifp->name));
- if (pimd_privs.change(ZPRIVS_LOWER))
- zlog_err("%s: could not lower privs, %s", __PRETTY_FUNCTION__,
- safe_strerror(errno));
+ }
#endif
return ret;
@@ -161,7 +150,8 @@ int pim_socket_mcast(int protocol, struct in_addr ifaddr, struct interface *ifp,
fd, errno, safe_strerror(errno));
}
#else
- zlog_err(
+ flog_err(
+ LIB_ERR_DEVELOPMENT,
"%s %s: Missing IP_PKTINFO and IP_RECVDSTADDR: unable to get dst addr from recvmsg()",
__FILE__, __PRETTY_FUNCTION__);
close(fd);
@@ -298,7 +288,8 @@ int pim_socket_join(int fd, struct in_addr group, struct in_addr ifaddr,
sizeof(ifaddr_str)))
sprintf(ifaddr_str, "<ifaddr?>");
- zlog_err(
+ flog_err(
+ LIB_ERR_SOCKET,
"Failure socket joining fd=%d group %s on interface address %s: errno=%d: %s",
fd, group_str, ifaddr_str, errno, safe_strerror(errno));
return ret;
diff --git a/pimd/pim_ssm.c b/pimd/pim_ssm.c
index 1f7cfcaa91..8347878d3f 100644
--- a/pimd/pim_ssm.c
+++ b/pimd/pim_ssm.c
@@ -24,6 +24,7 @@
#include <lib/vty.h>
#include <lib/vrf.h>
#include <lib/plist.h>
+#include <lib/lib_errors.h>
#include "pimd.h"
#include "pim_ssm.h"
@@ -72,8 +73,9 @@ static int pim_is_grp_standard_ssm(struct prefix *group)
if (first) {
if (!str2prefix(PIM_SSM_STANDARD_RANGE, &group_ssm))
- zlog_err("%s: Failure to Read Group Address: %s",
- __PRETTY_FUNCTION__, PIM_SSM_STANDARD_RANGE);
+ flog_err(LIB_ERR_DEVELOPMENT,
+ "%s: Failure to Read Group Address: %s",
+ __PRETTY_FUNCTION__, PIM_SSM_STANDARD_RANGE);
first = 0;
}
diff --git a/pimd/pim_ssmpingd.c b/pimd/pim_ssmpingd.c
index bdf303d5c5..be30d9c73e 100644
--- a/pimd/pim_ssmpingd.c
+++ b/pimd/pim_ssmpingd.c
@@ -24,6 +24,7 @@
#include "memory.h"
#include "sockopt.h"
#include "vrf.h"
+#include "lib_errors.h"
#include "pimd.h"
#include "pim_ssmpingd.h"
@@ -82,8 +83,9 @@ static int ssmpingd_socket(struct in_addr addr, int port, int mttl)
fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (fd < 0) {
- zlog_err("%s: could not create socket: errno=%d: %s",
- __PRETTY_FUNCTION__, errno, safe_strerror(errno));
+ flog_err_sys(LIB_ERR_SOCKET,
+ "%s: could not create socket: errno=%d: %s",
+ __PRETTY_FUNCTION__, errno, safe_strerror(errno));
return -1;
}
@@ -124,7 +126,8 @@ static int ssmpingd_socket(struct in_addr addr, int port, int mttl)
safe_strerror(errno));
}
#else
- zlog_err(
+ flog_err(
+ LIB_ERR_DEVELOPMENT,
"%s %s: missing IP_PKTINFO and IP_RECVDSTADDR: unable to get dst addr from recvmsg()",
__FILE__, __PRETTY_FUNCTION__);
close(fd);
diff --git a/pimd/pim_time.c b/pimd/pim_time.c
index 6f011da43e..029e551167 100644
--- a/pimd/pim_time.c
+++ b/pimd/pim_time.c
@@ -25,6 +25,7 @@
#include "log.h"
#include "thread.h"
+#include "lib_errors.h"
#include "pim_time.h"
@@ -34,8 +35,9 @@ static int gettime_monotonic(struct timeval *tv)
result = gettimeofday(tv, 0);
if (result) {
- zlog_err("%s: gettimeofday() failure: errno=%d: %s",
- __PRETTY_FUNCTION__, errno, safe_strerror(errno));
+ flog_err_sys(LIB_ERR_SYSTEM_CALL,
+ "%s: gettimeofday() failure: errno=%d: %s",
+ __PRETTY_FUNCTION__, errno, safe_strerror(errno));
}
return result;
@@ -50,8 +52,9 @@ int64_t pim_time_monotonic_sec()
struct timeval now_tv;
if (gettime_monotonic(&now_tv)) {
- zlog_err("%s: gettime_monotonic() failure: errno=%d: %s",
- __PRETTY_FUNCTION__, errno, safe_strerror(errno));
+ flog_err_sys(LIB_ERR_SYSTEM_CALL,
+ "%s: gettime_monotonic() failure: errno=%d: %s",
+ __PRETTY_FUNCTION__, errno, safe_strerror(errno));
return -1;
}
@@ -68,8 +71,9 @@ int64_t pim_time_monotonic_dsec()
int64_t now_dsec;
if (gettime_monotonic(&now_tv)) {
- zlog_err("%s: gettime_monotonic() failure: errno=%d: %s",
- __PRETTY_FUNCTION__, errno, safe_strerror(errno));
+ flog_err_sys(LIB_ERR_SYSTEM_CALL,
+ "%s: gettime_monotonic() failure: errno=%d: %s",
+ __PRETTY_FUNCTION__, errno, safe_strerror(errno));
return -1;
}
@@ -85,8 +89,9 @@ int64_t pim_time_monotonic_usec(void)
int64_t now_dsec;
if (gettime_monotonic(&now_tv)) {
- zlog_err("%s: gettime_monotonic() failure: errno=%d: %s",
- __PRETTY_FUNCTION__, errno, safe_strerror(errno));
+ flog_err_sys(LIB_ERR_SYSTEM_CALL,
+ "%s: gettime_monotonic() failure: errno=%d: %s",
+ __PRETTY_FUNCTION__, errno, safe_strerror(errno));
return -1;
}
diff --git a/pimd/pim_tlv.c b/pimd/pim_tlv.c
index 80bda336df..70700dd508 100644
--- a/pimd/pim_tlv.c
+++ b/pimd/pim_tlv.c
@@ -767,12 +767,6 @@ int pim_tlv_parse_addr_list(const char *ifname, struct in_addr src_addr,
{
struct prefix *p;
p = prefix_new();
- if (!p) {
- zlog_err("%s %s: failure: prefix_new()",
- __FILE__, __PRETTY_FUNCTION__);
- FREE_ADDR_LIST(*hello_option_addr_list);
- return -3;
- }
prefix_copy(p, &tmp);
listnode_add(*hello_option_addr_list, p);
}
diff --git a/pimd/pim_vty.c b/pimd/pim_vty.c
index f4d833c26f..88be195bee 100644
--- a/pimd/pim_vty.c
+++ b/pimd/pim_vty.c
@@ -258,6 +258,11 @@ int pim_interface_config_write(struct vty *vty)
ifp->name, vrf->name);
++writes;
+ if (ifp->desc) {
+ vty_out(vty, " description %s\n", ifp->desc);
+ ++writes;
+ }
+
if (ifp->info) {
struct pim_interface *pim_ifp = ifp->info;
diff --git a/pimd/pim_zlookup.c b/pimd/pim_zlookup.c
index fb616e1b0d..baa07a8ec6 100644
--- a/pimd/pim_zlookup.c
+++ b/pimd/pim_zlookup.c
@@ -28,6 +28,7 @@
#include "thread.h"
#include "prefix.h"
#include "vty.h"
+#include "lib_errors.h"
#include "pimd.h"
#include "pim_iface.h"
@@ -122,7 +123,8 @@ void zclient_lookup_new(void)
{
zlookup = zclient_new_notify(master, &zclient_options_default);
if (!zlookup) {
- zlog_err("%s: zclient_new() failure", __PRETTY_FUNCTION__);
+ flog_err(LIB_ERR_ZAPI_SOCKET, "%s: zclient_new() failure",
+ __PRETTY_FUNCTION__);
return;
}
@@ -168,8 +170,9 @@ static int zclient_read_nexthop(struct pim_instance *pim,
err = zclient_read_header(s, zlookup->sock, &length, &marker,
&version, &vrf_id, &command);
if (err < 0) {
- zlog_err("%s: zclient_read_header() failed",
- __PRETTY_FUNCTION__);
+ flog_err(LIB_ERR_ZAPI_MISSMATCH,
+ "%s: zclient_read_header() failed",
+ __PRETTY_FUNCTION__);
zclient_lookup_failed(zlookup);
return -1;
}
@@ -312,14 +315,15 @@ static int zclient_lookup_nexthop_once(struct pim_instance *pim,
/* Check socket. */
if (zlookup->sock < 0) {
- zlog_err("%s: zclient lookup socket is not connected",
- __PRETTY_FUNCTION__);
+ flog_err(LIB_ERR_ZAPI_SOCKET,
+ "%s: zclient lookup socket is not connected",
+ __PRETTY_FUNCTION__);
zclient_lookup_failed(zlookup);
return -1;
}
if (pim->vrf->vrf_id == VRF_UNKNOWN) {
- zlog_err(
+ zlog_notice(
"%s: VRF: %s does not fully exist yet, delaying lookup",
__PRETTY_FUNCTION__, pim->vrf->name);
return -1;
@@ -333,15 +337,17 @@ static int zclient_lookup_nexthop_once(struct pim_instance *pim,
ret = writen(zlookup->sock, s->data, stream_get_endp(s));
if (ret < 0) {
- zlog_err(
+ flog_err(
+ LIB_ERR_SOCKET,
"%s: writen() failure: %d writing to zclient lookup socket",
__PRETTY_FUNCTION__, errno);
zclient_lookup_failed(zlookup);
return -2;
}
if (ret == 0) {
- zlog_err("%s: connection closed on zclient lookup socket",
- __PRETTY_FUNCTION__);
+ flog_err_sys(LIB_ERR_SOCKET,
+ "%s: connection closed on zclient lookup socket",
+ __PRETTY_FUNCTION__);
zclient_lookup_failed(zlookup);
return -3;
}
@@ -509,7 +515,8 @@ int pim_zlookup_sg_statistics(struct channel_oil *c_oil)
count = stream_get_endp(s);
ret = writen(zlookup->sock, s->data, count);
if (ret <= 0) {
- zlog_err(
+ flog_err(
+ LIB_ERR_SOCKET,
"%s: writen() failure: %d writing to zclient lookup socket",
__PRETTY_FUNCTION__, errno);
return -1;
@@ -528,8 +535,9 @@ int pim_zlookup_sg_statistics(struct channel_oil *c_oil)
err = zclient_read_header(s, zlookup->sock, &length, &marker,
&version, &vrf_id, &command);
if (err < 0) {
- zlog_err("%s: zclient_read_header() failed",
- __PRETTY_FUNCTION__);
+ flog_err(LIB_ERR_ZAPI_MISSMATCH,
+ "%s: zclient_read_header() failed",
+ __PRETTY_FUNCTION__);
zclient_lookup_failed(zlookup);
return -1;
}
@@ -544,7 +552,8 @@ int pim_zlookup_sg_statistics(struct channel_oil *c_oil)
more.src = c_oil->oil.mfcc_origin;
more.grp = c_oil->oil.mfcc_mcastgrp;
- zlog_err(
+ flog_err(
+ LIB_ERR_ZAPI_MISSMATCH,
"%s: Received wrong %s(%s) information requested",
__PRETTY_FUNCTION__, pim_str_sg_dump(&more),
c_oil->pim->vrf->name);
diff --git a/pimd/pimd.c b/pimd/pimd.c
index cb7b8b589a..dd0c7e3c2a 100644
--- a/pimd/pimd.c
+++ b/pimd/pimd.c
@@ -28,6 +28,7 @@
#include "hash.h"
#include "jhash.h"
#include "vrf.h"
+#include "lib_errors.h"
#include "pimd.h"
#include "pim_cmd.h"
@@ -84,7 +85,8 @@ static void pim_free()
void pim_init()
{
if (!inet_aton(PIM_ALL_PIM_ROUTERS, &qpim_all_pim_routers_addr)) {
- zlog_err(
+ flog_err(
+ LIB_ERR_SOCKET,
"%s %s: could not solve %s to group address: errno=%d: %s",
__FILE__, __PRETTY_FUNCTION__, PIM_ALL_PIM_ROUTERS,
errno, safe_strerror(errno));
diff --git a/pimd/pimd.h b/pimd/pimd.h
index 840e0d7e34..1b11dc3f73 100644
--- a/pimd/pimd.h
+++ b/pimd/pimd.h
@@ -117,7 +117,6 @@
/* PIM error codes */
#define PIM_SUCCESS 0
-#define PIM_MALLOC_FAIL -1
#define PIM_GROUP_BAD_ADDRESS -2
#define PIM_GROUP_OVERLAP -3
#define PIM_GROUP_PFXLIST_OVERLAP -4
diff --git a/pimd/subdir.am b/pimd/subdir.am
index 0696d9b1e8..55d56ece97 100644
--- a/pimd/subdir.am
+++ b/pimd/subdir.am
@@ -15,6 +15,7 @@ pimd_libpim_a_SOURCES = \
pimd/pim_bfd.c \
pimd/pim_br.c \
pimd/pim_cmd.c \
+ pimd/pim_errors.c \
pimd/pim_hello.c \
pimd/pim_iface.c \
pimd/pim_ifchannel.c \
@@ -64,6 +65,7 @@ noinst_HEADERS += \
pimd/pim_bfd.h \
pimd/pim_br.h \
pimd/pim_cmd.h \
+ pimd/pim_errors.h \
pimd/pim_hello.h \
pimd/pim_iface.h \
pimd/pim_ifchannel.h \
diff --git a/redhat/daemons b/redhat/daemons
index f9dbffea4d..de708cf4fd 100644
--- a/redhat/daemons
+++ b/redhat/daemons
@@ -52,6 +52,8 @@ babeld=no
sharpd=no
pbrd=no
staticd=no
+bfdd=no
+
#
# Command line options for the daemons
#
@@ -70,6 +72,7 @@ babeld_options=("-A 127.0.0.1")
sharpd_options=("-A 127.0.0.1")
pbrd_options=("-A 127.0.0.1")
staticd_options=("-A 127.0.0.1")
+bfdd_options=("-A 127.0.0.1")
#
# If the vtysh_enable is yes, then the unified config is read
diff --git a/redhat/frr.init b/redhat/frr.init
index 740aa5b64d..2e33aee173 100755
--- a/redhat/frr.init
+++ b/redhat/frr.init
@@ -7,7 +7,7 @@
#
# chkconfig: 2345 15 85
#
-# description: FRRouting (FRR) is a routing suite for IP routing protocols
+# description: FRRouting (FRR) is a routing suite for IP routing protocols
# like BGP, OSPF, RIP and others. This script contols the main
# daemon "frr" as well as the individual protocol daemons.
#
@@ -20,7 +20,7 @@
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: Start/Stop the FRR Routing daemons
-# Description: FRRouting (FRR) is a routing suite for IP routing protocols
+# Description: FRRouting (FRR) is a routing suite for IP routing protocols
# like BGP, OSPF, RIP and others. This script contols the main
# daemon "frr" as well as the individual protocol daemons.
### END INIT INFO
@@ -33,7 +33,7 @@ V_PATH=/var/run/frr
# Local Daemon selection may be done by using /etc/frr/daemons.
# See /usr/share/doc/frr/README.Debian.gz for further information.
# Keep zebra first and do not list watchfrr!
-DAEMONS="zebra bgpd ripd ripngd ospfd ospf6d isisd pimd pbrd ldpd nhrpd eigrpd babeld staticd sharpd"
+DAEMONS="zebra bgpd ripd ripngd ospfd ospf6d isisd pimd pbrd ldpd nhrpd eigrpd babeld staticd sharpd bfdd"
MAX_INSTANCES=5
RELOAD_SCRIPT=/usr/lib/frr/frr-reload.py
diff --git a/redhat/frr.logrotate b/redhat/frr.logrotate
index 25a5587787..654d355fd7 100644
--- a/redhat/frr.logrotate
+++ b/redhat/frr.logrotate
@@ -86,3 +86,10 @@
endscript
}
+/var/log/frr/bfdd.log {
+ notifempty
+ missingok
+ postrotate
+ /bin/kill -USR1 `cat /var/run/frr/bfdd.pid 2> /dev/null` 2> /dev/null || true
+ endscript
+}
diff --git a/redhat/frr.spec.in b/redhat/frr.spec.in
index f5b116978e..25b48506a6 100644
--- a/redhat/frr.spec.in
+++ b/redhat/frr.spec.in
@@ -11,6 +11,7 @@
#################### FRRouting (FRR) configure options #####################
# with-feature options
%{!?with_babeld: %global with_babeld 1 }
+%{!?with_bfdd: %global with_bfdd 1 }
%{!?with_bgp_vnc: %global with_bgp_vnc 0 }
%{!?with_cumulus: %global with_cumulus 0 }
%{!?with_eigrpd: %global with_eigrpd 1 }
@@ -85,7 +86,7 @@
%{!?frr_gid: %global frr_gid 92 }
%{!?vty_gid: %global vty_gid 85 }
-%define daemon_list zebra ripd ospfd bgpd isisd ripngd ospf6d pbrd staticd
+%define daemon_list zebra ripd ospfd bgpd isisd ripngd ospf6d pbrd staticd bfdd
%if %{with_ldpd}
%define daemon_ldpd ldpd
@@ -129,7 +130,13 @@
%define daemon_watchfrr ""
%endif
-%define all_daemons %{daemon_list} %{daemon_ldpd} %{daemon_pimd} %{daemon_nhrpd} %{daemon_eigrpd} %{daemon_babeld} %{daemon_watchfrr} %{daemon_pbrd}
+%if %{with_bfdd}
+ %define daemon_bfdd bfdd
+%else
+ %define daemon_bfdd ""
+%endif
+
+%define all_daemons %{daemon_list} %{daemon_ldpd} %{daemon_pimd} %{daemon_nhrpd} %{daemon_eigrpd} %{daemon_babeld} %{daemon_watchfrr} %{daemon_pbrd} %{daemon_bfdd}
#release sub-revision (the two digits after the CONFDATE)
%{!?release_rev: %global release_rev 01 }
@@ -193,7 +200,7 @@ protocol. It takes multi-server and multi-thread approach to resolve
the current complexity of the Internet.
FRRouting supports BGP4, OSPFv2, OSPFv3, ISIS, RIP, RIPng, PIM, LDP
-NHRP, Babel, PBR and EIGRP.
+NHRP, Babel, PBR, EIGRP and BFD.
FRRouting is a fork of Quagga.
@@ -331,9 +338,14 @@ developing OSPF-API and frr applications.
--enable-systemd \
%endif
%if %{with_rpki}
- --enable-rpki
+ --enable-rpki \
+%else
+ --disable-rpki \
+%endif
+%if %{with_bfdd}
+ --enable-bfdd
%else
- --disable-rpki
+ --disable-bfdd
%endif
make %{?_smp_mflags} MAKEINFO="makeinfo --no-split" SPHINXBUILD=%{sphinx}
@@ -444,6 +456,9 @@ zebra_spec_add_service isisd 2608/tcp "ISISd vty"
%if %{with_eigrpd}
zebra_spec_add_service eigrpd 2613/tcp "EIGRPd vty"
%endif
+%if %{with_bfdd}
+ zebra_spec_add_service bfdd 2617/tcp "BFDd vty"
+%endif
%if "%{initsystem}" == "systemd"
for daemon in %all_daemons ; do
@@ -591,6 +606,9 @@ fi
%if %{with_babeld}
%{_sbindir}/babeld
%endif
+%if %{with_bfdd}
+ %{_sbindir}/bfdd
+%endif
%{_libdir}/lib*.so.0
%{_libdir}/lib*.so.0.*
%if %{with_fpm}
@@ -644,6 +662,9 @@ fi
%changelog
+* Sun May 28 2018 Rafael Zalamena <rzalamena@opensourcerouting.org> - %{version}
+- Add BFDd support
+
* Sun May 20 2018 Martin Winter <mwinter@opensourcerouting.org>
- Fixed RPKI RPM build
diff --git a/ripd/rip_errors.c b/ripd/rip_errors.c
new file mode 100644
index 0000000000..363b1b7fb5
--- /dev/null
+++ b/ripd/rip_errors.c
@@ -0,0 +1,41 @@
+/*
+ * RIP-specific error messages.
+ * Copyright (C) 2018 Cumulus Networks, Inc.
+ * Donald Sharp
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This 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 "lib/ferr.h"
+#include "rip_errors.h"
+
+static struct log_ref ferr_rip_err[] = {
+ {
+ .code = RIP_ERR_PACKET,
+ .title = "RIP Packet Error",
+ .description = "RIP has detected a packet encode/decode issue",
+ .suggestion = "Gather log files from both sides and open a Issue"
+ },
+ {
+ .code = END_FERR,
+ }
+};
+
+void rip_error_init(void)
+{
+ log_ref_add(ferr_rip_err);
+}
diff --git a/ripd/rip_errors.h b/ripd/rip_errors.h
new file mode 100644
index 0000000000..6b5f5c0169
--- /dev/null
+++ b/ripd/rip_errors.h
@@ -0,0 +1,33 @@
+/*
+ * RIP-specific error messages.
+ * Copyright (C) 2018 Cumulus Networks, Inc.
+ * Donald Sharp
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; see the file COPYING; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef __RIP_ERRORS_H__
+#define __RIP_ERRORS_H__
+
+#include "lib/ferr.h"
+
+enum rip_log_refs {
+ RIP_ERR_PACKET = RIP_FERR_START,
+ RIP_ERR_CONFIG,
+};
+
+extern void rip_error_init(void);
+
+#endif
diff --git a/ripd/rip_interface.c b/ripd/rip_interface.c
index 58247f1622..364e23c5e6 100644
--- a/ripd/rip_interface.c
+++ b/ripd/rip_interface.c
@@ -34,6 +34,7 @@
#include "filter.h"
#include "sockopt.h"
#include "privs.h"
+#include "lib_errors.h"
#include "zebra/connected.h"
@@ -864,8 +865,9 @@ static int rip_interface_wakeup(struct thread *t)
/* Join to multicast group. */
if (rip_multicast_join(ifp, rip->sock) < 0) {
- zlog_err("multicast join failed, interface %s not running",
- ifp->name);
+ flog_err_sys(LIB_ERR_SOCKET,
+ "multicast join failed, interface %s not running",
+ ifp->name);
return 0;
}
diff --git a/ripd/rip_main.c b/ripd/rip_main.c
index 0194e53128..e5a5c3e227 100644
--- a/ripd/rip_main.c
+++ b/ripd/rip_main.c
@@ -37,6 +37,7 @@
#include "libfrr.h"
#include "ripd/ripd.h"
+#include "ripd/rip_errors.h"
/* ripd options. */
#if CONFDATE > 20190521
@@ -167,6 +168,7 @@ int main(int argc, char **argv)
master = frr_init();
/* Library initialization. */
+ rip_error_init();
keychain_init();
vrf_init(NULL, NULL, NULL, NULL);
diff --git a/ripd/ripd.c b/ripd/ripd.c
index 8032cf2ec5..02ead6fde2 100644
--- a/ripd/ripd.c
+++ b/ripd/ripd.c
@@ -40,9 +40,11 @@
#include "md5.h"
#include "keychain.h"
#include "privs.h"
+#include "lib_errors.h"
#include "ripd/ripd.h"
#include "ripd/rip_debug.h"
+#include "ripd/rip_errors.h"
DEFINE_QOBJ_TYPE(rip)
@@ -1056,9 +1058,9 @@ static void rip_auth_md5_set(struct stream *s, struct rip_interface *ri,
/* Check packet length. */
if (len < (RIP_HEADER_SIZE + RIP_RTE_SIZE)) {
- zlog_err(
- "rip_auth_md5_set(): packet length %ld is less than minimum length.",
- len);
+ flog_err(RIP_ERR_PACKET,
+ "rip_auth_md5_set(): packet length %ld is less than minimum length.",
+ len);
return;
}
@@ -1339,7 +1341,8 @@ static int rip_create_socket(void)
/* Make datagram socket. */
sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (sock < 0) {
- zlog_err("Cannot create UDP socket: %s", safe_strerror(errno));
+ flog_err_sys(LIB_ERR_SOCKET, "Cannot create UDP socket: %s",
+ safe_strerror(errno));
exit(1);
}
@@ -1354,27 +1357,20 @@ static int rip_create_socket(void)
setsockopt_ipv4_tos(sock, IPTOS_PREC_INTERNETCONTROL);
#endif
- if (ripd_privs.change(ZPRIVS_RAISE))
- zlog_err("rip_create_socket: could not raise privs");
- setsockopt_so_recvbuf(sock, RIP_UDP_RCV_BUF);
- if ((ret = bind(sock, (struct sockaddr *)&addr, sizeof(addr))) < 0)
-
- {
- int save_errno = errno;
- if (ripd_privs.change(ZPRIVS_LOWER))
- zlog_err("rip_create_socket: could not lower privs");
-
- zlog_err("%s: Can't bind socket %d to %s port %d: %s", __func__,
- sock, inet_ntoa(addr.sin_addr),
- (int)ntohs(addr.sin_port), safe_strerror(save_errno));
-
- close(sock);
- return ret;
+ frr_elevate_privs(&ripd_privs) {
+ setsockopt_so_recvbuf(sock, RIP_UDP_RCV_BUF);
+ if ((ret = bind(sock, (struct sockaddr *)&addr, sizeof(addr)))
+ < 0) {
+ zlog_err("%s: Can't bind socket %d to %s port %d: %s",
+ __func__, sock, inet_ntoa(addr.sin_addr),
+ (int)ntohs(addr.sin_port),
+ safe_strerror(errno));
+
+ close(sock);
+ return ret;
+ }
}
- if (ripd_privs.change(ZPRIVS_LOWER))
- zlog_err("rip_create_socket: could not lower privs");
-
return sock;
}
@@ -2812,6 +2808,7 @@ DEFUN_NOSH (router_rip,
return CMD_WARNING_CONFIG_FAILED;
}
}
+
VTY_PUSH_CONTEXT(RIP_NODE, rip);
return CMD_SUCCESS;
diff --git a/ripd/subdir.am b/ripd/subdir.am
index 1c5167ef4a..612db1a7ab 100644
--- a/ripd/subdir.am
+++ b/ripd/subdir.am
@@ -13,6 +13,7 @@ endif
ripd_librip_a_SOURCES = \
ripd/rip_debug.c \
+ ripd/rip_errors.c \
ripd/rip_interface.c \
ripd/rip_memory.c \
ripd/rip_offset.c \
@@ -24,6 +25,7 @@ ripd_librip_a_SOURCES = \
noinst_HEADERS += \
ripd/rip_debug.h \
+ ripd/rip_errors.h \
ripd/rip_interface.h \
ripd/rip_memory.h \
ripd/ripd.h \
diff --git a/ripngd/ripng_interface.c b/ripngd/ripng_interface.c
index c463630b12..ef324b001a 100644
--- a/ripngd/ripng_interface.c
+++ b/ripngd/ripng_interface.c
@@ -35,6 +35,7 @@
#include "thread.h"
#include "privs.h"
#include "vrf.h"
+#include "lib_errors.h"
#include "ripngd/ripngd.h"
#include "ripngd/ripng_debug.h"
@@ -71,15 +72,14 @@ static int ripng_multicast_join(struct interface *ifp)
* While this is bogus, privs are available and easy to use
* for this call as a workaround.
*/
- if (ripngd_privs.change(ZPRIVS_RAISE))
- zlog_err("ripng_multicast_join: could not raise privs");
+ frr_elevate_privs(&ripngd_privs) {
- ret = setsockopt(ripng->sock, IPPROTO_IPV6, IPV6_JOIN_GROUP,
- (char *)&mreq, sizeof(mreq));
- save_errno = errno;
+ ret = setsockopt(ripng->sock, IPPROTO_IPV6,
+ IPV6_JOIN_GROUP,
+ (char *)&mreq, sizeof(mreq));
+ save_errno = errno;
- if (ripngd_privs.change(ZPRIVS_LOWER))
- zlog_err("ripng_multicast_join: could not lower privs");
+ }
if (ret < 0 && save_errno == EADDRINUSE) {
/*
@@ -642,8 +642,9 @@ static int ripng_interface_wakeup(struct thread *t)
/* Join to multicast group. */
if (ripng_multicast_join(ifp) < 0) {
- zlog_err("multicast join failed, interface %s not running",
- ifp->name);
+ flog_err_sys(LIB_ERR_SOCKET,
+ "multicast join failed, interface %s not running",
+ ifp->name);
return 0;
}
diff --git a/ripngd/ripngd.c b/ripngd/ripngd.c
index 565e151c53..934a87b075 100644
--- a/ripngd/ripngd.c
+++ b/ripngd/ripngd.c
@@ -35,6 +35,7 @@
#include "routemap.h"
#include "if_rmap.h"
#include "privs.h"
+#include "lib_errors.h"
#include "ripngd/ripngd.h"
#include "ripngd/ripng_route.h"
@@ -94,7 +95,7 @@ static int ripng_make_socket(void)
sock = socket(AF_INET6, SOCK_DGRAM, 0);
if (sock < 0) {
- zlog_err("Can't make ripng socket");
+ flog_err_sys(LIB_ERR_SOCKET, "Can't make ripng socket");
return sock;
}
@@ -124,18 +125,14 @@ static int ripng_make_socket(void)
#endif /* SIN6_LEN */
ripaddr.sin6_port = htons(RIPNG_PORT_DEFAULT);
- if (ripngd_privs.change(ZPRIVS_RAISE))
- zlog_err("ripng_make_socket: could not raise privs");
-
- ret = bind(sock, (struct sockaddr *)&ripaddr, sizeof(ripaddr));
- if (ret < 0) {
- zlog_err("Can't bind ripng socket: %s.", safe_strerror(errno));
- if (ripngd_privs.change(ZPRIVS_LOWER))
- zlog_err("ripng_make_socket: could not lower privs");
- goto error;
+ frr_elevate_privs(&ripngd_privs) {
+ ret = bind(sock, (struct sockaddr *)&ripaddr, sizeof(ripaddr));
+ if (ret < 0) {
+ zlog_err("Can't bind ripng socket: %s.",
+ safe_strerror(errno));
+ goto error;
+ }
}
- if (ripngd_privs.change(ZPRIVS_LOWER))
- zlog_err("ripng_make_socket: could not lower privs");
return sock;
error:
@@ -202,12 +199,14 @@ int ripng_send_packet(caddr_t buf, int bufsize, struct sockaddr_in6 *to,
if (ret < 0) {
if (to)
- zlog_err("RIPng send fail on %s to %s: %s", ifp->name,
- inet6_ntoa(to->sin6_addr),
- safe_strerror(errno));
+ flog_err_sys(LIB_ERR_SOCKET,
+ "RIPng send fail on %s to %s: %s",
+ ifp->name, inet6_ntoa(to->sin6_addr),
+ safe_strerror(errno));
else
- zlog_err("RIPng send fail on %s: %s", ifp->name,
- safe_strerror(errno));
+ flog_err_sys(LIB_ERR_SOCKET,
+ "RIPng send fail on %s: %s", ifp->name,
+ safe_strerror(errno));
}
return ret;
@@ -246,7 +245,7 @@ static int ripng_recv_packet(int sock, uint8_t *buf, int bufsize,
if (ret < 0)
return ret;
- for (cmsgptr = ZCMSG_FIRSTHDR(&msg); cmsgptr != NULL;
+ for (cmsgptr = CMSG_FIRSTHDR(&msg); cmsgptr != NULL;
cmsgptr = CMSG_NXTHDR(&msg, cmsgptr)) {
/* I want interface index which this packet comes from. */
if (cmsgptr->cmsg_level == IPPROTO_IPV6
diff --git a/snapcraft/README.usage.md b/snapcraft/README.usage.md
index 28d2395455..50711b13b7 100644
--- a/snapcraft/README.usage.md
+++ b/snapcraft/README.usage.md
@@ -18,7 +18,7 @@ ie for `ospf6d` (OSPFv3):
systemctl enable snap.frr.ospf6d.service
The daemons are: `ripd`, `ripngd`, `ospfd`, `ospf6d`, `isisd`, `bgpd`,
-`pimd`, `zebra`
+`pimd`, `ldpd`, `eigrpd`, `babeld`, `nhrpd`, `bfdd`, `zebra`
Commands defined by this snap
-----------------------------
@@ -53,7 +53,19 @@ depend on them). These are mainly intended to debug the Snap
- `frr.pimd-debug`:
Starts pimd daemon in foreground
- `frr.ldpd-debug`:
- Starts ldpd daemon in foreground
+ Starts ldpd daemon in foreground
+- `frr.nhrpd-debug`:
+ Starts nhrpd daemon in foreground
+- `frr.babeld-debug`:
+ Starts babeld daemon in foreground
+- `frr.eigrpd-debug`:
+ Starts eigrpd daemon in foreground
+- `frr.pbrd-debug`:
+ Starts pbrd daemon in foreground
+- `frr.staticd-debug`:
+ Starts staticd daemon in foreground
+- `frr.bfdd-debug`:
+ Starts bfdd daemon in foreground
MPLS (LDP)
----------
@@ -108,7 +120,7 @@ FAQ
- Define `VTYSH_PAGER` to `cat` (default is `more`). (Ie add
`export VTYSH_PAGER=cat` to the end of your `.profile`)
-- ospfd / ospf6d are not running after installation
+- bfdd / ospfd / ospf6d / nhrpd are not running after installation
- Installing a new snap starts the daemons, but at this time they
may not have the required privileged access. Make sure you
issue the `snap connect` command as given above (can be verified
diff --git a/snapcraft/defaults/bfdd.conf.default b/snapcraft/defaults/bfdd.conf.default
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/snapcraft/defaults/bfdd.conf.default
diff --git a/snapcraft/defaults/staticd.conf.default b/snapcraft/defaults/staticd.conf.default
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/snapcraft/defaults/staticd.conf.default
diff --git a/snapcraft/scripts/Makefile b/snapcraft/scripts/Makefile
index 110f4b2878..e3a7708f23 100644
--- a/snapcraft/scripts/Makefile
+++ b/snapcraft/scripts/Makefile
@@ -15,6 +15,8 @@ install:
install -D -m 0755 babeld-service $(DESTDIR)/bin/
install -D -m 0755 eigrpd-service $(DESTDIR)/bin/
install -D -m 0755 pbrd-service $(DESTDIR)/bin/
+ install -D -m 0755 staticd-service $(DESTDIR)/bin/
+ install -D -m 0755 bfdd-service $(DESTDIR)/bin/
install -D -m 0755 set-options $(DESTDIR)/bin/
install -D -m 0755 show_version $(DESTDIR)/bin/
diff --git a/snapcraft/scripts/bfdd-service b/snapcraft/scripts/bfdd-service
new file mode 100644
index 0000000000..f94a7abb4b
--- /dev/null
+++ b/snapcraft/scripts/bfdd-service
@@ -0,0 +1,14 @@
+#!/bin/sh
+
+set -e -x
+
+if ! [ -e $SNAP_DATA/bfdd.conf ]; then
+ cp $SNAP/etc/frr/bfdd.conf.default $SNAP_DATA/bfdd.conf
+fi
+exec $SNAP/sbin/bfdd \
+ -f $SNAP_DATA/bfdd.conf \
+ --pid_file $SNAP_DATA/bfdd.pid \
+ --socket $SNAP_DATA/zsock \
+ --vty_socket $SNAP_DATA \
+ --bfdctl $SNAP_DATA/bfdd.sock
+
diff --git a/snapcraft/scripts/staticd-service b/snapcraft/scripts/staticd-service
new file mode 100644
index 0000000000..3b22881640
--- /dev/null
+++ b/snapcraft/scripts/staticd-service
@@ -0,0 +1,20 @@
+#!/bin/sh
+
+set -e -x
+
+if ! [ -e $SNAP_DATA/staticd.conf ]; then
+ if [ -e $SNAP_DATA/zebra.conf ]; then
+ # if we have a zebra.conf, but no staticd conf, then we use
+ # this file as the default config for staticd
+ cp $SNAP_DATA/zebra.conf $SNAP_DATA/staticd.conf
+ else
+ # new config, start with template
+ cp $SNAP/etc/frr/staticd.conf $SNAP_DATA/staticd.conf
+ fi
+fi
+exec $SNAP/sbin/staticd \
+ -f $SNAP_DATA/staticd.conf \
+ --pid_file $SNAP_DATA/staticd.pid \
+ --socket $SNAP_DATA/zsock \
+ --vty_socket $SNAP_DATA
+
diff --git a/snapcraft/snapcraft.yaml.in b/snapcraft/snapcraft.yaml.in
index b4e1812c86..563a05c5a7 100644
--- a/snapcraft/snapcraft.yaml.in
+++ b/snapcraft/snapcraft.yaml.in
@@ -1,10 +1,10 @@
name: frr
version: @VERSION@
-summary: FRRouting BGP/OSPFv2/OSPFv3/ISIS/RIP/RIPng/PIM/LDP routing daemon
-description: BGP/OSPFv2/OSPFv3/ISIS/RIP/RIPng/PIM routing daemon
+summary: FRRouting BGP/OSPFv2/OSPFv3/ISIS/RIP/RIPng/PIM/LDP/EIGRP/BFD routing daemon
+description: BGP/OSPFv2/OSPFv3/ISIS/RIP/RIPng/PIM/LDP/EIGRP/BFD routing daemon
FRRouting (FRR) is free software which manages TCP/IP based routing
protocols. It supports BGP4, BGP4+, OSPFv2, OSPFv3, IS-IS, RIPv1, RIPv2,
- RIPng, PIM, LDP, Babel, EIGRP and PBR (Policy-based routing) as well as
+ RIPng, PIM, LDP, Babel, EIGRP, PBR (Policy-based routing) and BFD as well as
the IPv6 versions of these.
FRRouting (frr) is a fork of Quagga.
confinement: strict
@@ -113,6 +113,20 @@ apps:
- network
- network-bind
- network-control
+ staticd:
+ command: bin/staticd-service
+ daemon: simple
+ plugs:
+ - network
+ - network-bind
+ - network-control
+ bfdd:
+ command: bin/bfdd-service
+ daemon: simple
+ plugs:
+ - network
+ - network-bind
+ - network-control
set:
command: bin/set-options
zebra-debug:
@@ -193,6 +207,18 @@ apps:
- network
- network-bind
- network-control
+ staticd-debug:
+ command: sbin/staticd -f $SNAP_DATA/staticd.conf --pid_file $SNAP_DATA/staticd.pid --socket $SNAP_DATA/zsock --vty_socket $SNAP_DATA
+ plugs:
+ - network
+ - network-bind
+ - network-control
+ bfdd-debug:
+ command: sbin/bfdd -f $SNAP_DATA/bfdd.conf --pid_file $SNAP_DATA/bfdd.pid --socket $SNAP_DATA/zsock --vty_socket $SNAP_DATA --bfdctl $SNAP_DATA/bfdd.sock
+ plugs:
+ - network
+ - network-bind
+ - network-control
parts:
frr:
@@ -274,6 +300,7 @@ parts:
babeld.conf.default: etc/frr/babeld.conf.default
eigrpd.conf.default: etc/frr/eigrpd.conf.default
pbrd.conf.default: etc/frr/pbrd.conf.default
+ bfdd.conf.default: etc/frr/bfdd.conf.default
vtysh.conf.default: etc/frr/vtysh.conf.default
frr-scripts:
plugin: make
diff --git a/staticd/static_nht.c b/staticd/static_nht.c
index f9f937f905..c6e4587b6a 100644
--- a/staticd/static_nht.c
+++ b/staticd/static_nht.c
@@ -42,7 +42,7 @@ void static_nht_update(struct prefix *p, uint32_t nh_num,
vrf = vrf_lookup_by_id(vrf_id);
- if (!vrf->info)
+ if (!vrf || !vrf->info)
return;
svrf = vrf->info;
diff --git a/staticd/static_zebra.c b/staticd/static_zebra.c
index 27e126e2a6..f3175e91fa 100644
--- a/staticd/static_zebra.c
+++ b/staticd/static_zebra.c
@@ -119,7 +119,7 @@ static int interface_state_up(int command, struct zclient *zclient,
ifp = zebra_interface_if_lookup(zclient->ibuf);
- if (if_is_vrf(ifp)) {
+ if (ifp && if_is_vrf(ifp)) {
struct static_vrf *svrf = static_vrf_lookup_by_id(vrf_id);
static_fixup_vrf_ids(svrf);
diff --git a/tests/lib/test_heavy_thread.c b/tests/lib/test_heavy_thread.c
index 075bcb6daf..b3c6e4c2f7 100644
--- a/tests/lib/test_heavy_thread.c
+++ b/tests/lib/test_heavy_thread.c
@@ -110,16 +110,9 @@ DEFUN (clear_foo,
str = argv_concat(argv, argc, 0);
- if ((ws = XMALLOC(MTYPE_TMP, sizeof(*ws))) == NULL) {
- zlog_err("%s: unable to allocate work_state", __func__);
- return CMD_WARNING;
- }
+ ws = XMALLOC(MTYPE_TMP, sizeof(*ws));
- if (!(ws->str = XSTRDUP(MTYPE_TMP, str))) {
- zlog_err("%s: unable to xstrdup", __func__);
- XFREE(MTYPE_TMP, ws);
- return CMD_WARNING;
- }
+ ws->str = XSTRDUP(MTYPE_TMP, str);
ws->vty = vty;
ws->i = ITERS_FIRST;
diff --git a/tests/lib/test_heavy_wq.c b/tests/lib/test_heavy_wq.c
index 0f474dc5d2..00ddc836d7 100644
--- a/tests/lib/test_heavy_wq.c
+++ b/tests/lib/test_heavy_wq.c
@@ -60,18 +60,10 @@ static void heavy_wq_add(struct vty *vty, const char *str, int i)
{
struct heavy_wq_node *hn;
- if ((hn = XCALLOC(MTYPE_WQ_NODE, sizeof(struct heavy_wq_node)))
- == NULL) {
- zlog_err("%s: unable to allocate hn", __func__);
- return;
- }
+ hn = XCALLOC(MTYPE_WQ_NODE, sizeof(struct heavy_wq_node));
hn->i = i;
- if (!(hn->str = XSTRDUP(MTYPE_WQ_NODE_STR, str))) {
- zlog_err("%s: unable to xstrdup", __func__);
- XFREE(MTYPE_WQ_NODE, hn);
- return;
- }
+ hn->str = XSTRDUP(MTYPE_WQ_NODE_STR, str);
work_queue_add(heavy_wq, hn);
@@ -149,10 +141,7 @@ DEFUN (clear_foo,
static int heavy_wq_init()
{
- if (!(heavy_wq = work_queue_new(master, "heavy_work_queue"))) {
- zlog_err("%s: could not get new work queue!", __func__);
- return -1;
- }
+ heavy_wq = work_queue_new(master, "heavy_work_queue");
heavy_wq->spec.workfunc = &slow_func;
heavy_wq->spec.errorfunc = &slow_func_err;
diff --git a/tests/lib/test_privs.c b/tests/lib/test_privs.c
index 421c345436..e203da8f6e 100644
--- a/tests/lib/test_privs.c
+++ b/tests/lib/test_privs.c
@@ -113,10 +113,9 @@ int main(int argc, char **argv)
((test_privs.current_state() == ZPRIVS_RAISED) ? "Raised" : "Lowered")
printf("%s\n", PRIV_STATE());
- test_privs.change(ZPRIVS_RAISE);
-
- printf("%s\n", PRIV_STATE());
- test_privs.change(ZPRIVS_LOWER);
+ frr_elevate_privs(&test_privs) {
+ printf("%s\n", PRIV_STATE());
+ }
printf("%s\n", PRIV_STATE());
zprivs_get_ids(&ids);
@@ -126,10 +125,9 @@ int main(int argc, char **argv)
/* but these should continue to work... */
printf("%s\n", PRIV_STATE());
- test_privs.change(ZPRIVS_RAISE);
-
- printf("%s\n", PRIV_STATE());
- test_privs.change(ZPRIVS_LOWER);
+ frr_elevate_privs(&test_privs) {
+ printf("%s\n", PRIV_STATE());
+ }
printf("%s\n", PRIV_STATE());
zprivs_get_ids(&ids);
diff --git a/tools/checkpatch.pl b/tools/checkpatch.pl
index c1fab1029a..55b3e1e564 100755
--- a/tools/checkpatch.pl
+++ b/tools/checkpatch.pl
@@ -4181,7 +4181,9 @@ sub process {
} elsif ($op eq ',') {
my $rtrim_before = 0;
my $space_after = 0;
- if ($ctx =~ /Wx./) {
+ if ($line=~/\#\s*define/) {
+ # ignore , spacing in macros
+ } elsif ($ctx =~ /Wx./) {
if (ERROR("SPACING",
"space prohibited before that '$op' $at\n" . $hereptr)) {
$line_fixed = 1;
@@ -4847,6 +4849,7 @@ sub process {
my $ctx = '';
my $has_flow_statement = 0;
my $has_arg_concat = 0;
+ my $complex = 0;
($dstat, $dcond, $ln, $cnt, $off) =
ctx_statement_block($linenr, $realcnt, 0);
$ctx = $dstat;
@@ -4865,6 +4868,7 @@ sub process {
$define_args = substr($define_args, 1, length($define_args) - 2);
$define_args =~ s/\s*//g;
@def_args = split(",", $define_args);
+ $complex = 1;
}
$dstat =~ s/$;//g;
@@ -4932,7 +4936,7 @@ sub process {
} elsif ($dstat =~ /;/) {
ERROR("MULTISTATEMENT_MACRO_USE_DO_WHILE",
"Macros with multiple statements should be enclosed in a do - while loop\n" . "$herectx");
- } else {
+ } elsif ($complex) {
ERROR("COMPLEX_MACRO",
"Macros with complex values should be enclosed in parentheses\n" . "$herectx");
}
diff --git a/tools/etc/frr/daemons b/tools/etc/frr/daemons
index 9a96c0490a..474b299d90 100644
--- a/tools/etc/frr/daemons
+++ b/tools/etc/frr/daemons
@@ -35,3 +35,4 @@ eigrpd=no
babeld=no
sharpd=no
pbrd=no
+bfdd=no
diff --git a/tools/etc/frr/daemons.conf b/tools/etc/frr/daemons.conf
index 04a857f47d..640437f441 100644
--- a/tools/etc/frr/daemons.conf
+++ b/tools/etc/frr/daemons.conf
@@ -19,6 +19,7 @@ babeld_options=" --daemon -A 127.0.0.1"
sharpd_options=" --daemon -A 127.0.0.1"
pbrd_options=" --daemon -A 127.0.0.1"
staticd_options=" --daemon -A 127.0.0.1"
+bfdd_options=" --daemon -A 127.0.0.1"
# The list of daemons to watch is automatically generated by the init script.
watchfrr_enable=yes
diff --git a/tools/frr b/tools/frr
index 91c9091448..0b170d33fd 100755
--- a/tools/frr
+++ b/tools/frr
@@ -21,7 +21,7 @@ V_PATH=/var/run/frr
# Local Daemon selection may be done by using /etc/frr/daemons.
# See /usr/share/doc/frr/README.Debian.gz for further information.
# Keep zebra first and do not list watchfrr!
-DAEMONS="zebra bgpd ripd ripngd ospfd ospf6d isisd babeld pimd ldpd nhrpd eigrpd sharpd pbrd staticd"
+DAEMONS="zebra bgpd ripd ripngd ospfd ospf6d isisd babeld pimd ldpd nhrpd eigrpd sharpd pbrd staticd bfdd"
MAX_INSTANCES=5
RELOAD_SCRIPT=/usr/lib/frr/frr-reload.py
diff --git a/tools/frr-reload.py b/tools/frr-reload.py
index a9f183ed7b..9d1af27d6c 100755
--- a/tools/frr-reload.py
+++ b/tools/frr-reload.py
@@ -413,7 +413,7 @@ end
ctx_keys = []
current_context_lines = []
- elif line in ["exit-address-family", "exit", "exit-vnc", "exit-vni"]:
+ elif line in ["exit-address-family", "exit", "exit-vnc"]:
# if this exit is for address-family ipv4 unicast, ignore the pop
if main_ctx_key:
self.save_contexts(ctx_keys, current_context_lines)
@@ -423,6 +423,15 @@ end
current_context_lines = []
log.debug('LINE %-50s: popping from subcontext to ctx%-50s', line, ctx_keys)
+ elif line == "exit-vni":
+ if sub_main_ctx_key:
+ self.save_contexts(ctx_keys, current_context_lines)
+
+ # Start a new context
+ ctx_keys = copy.deepcopy(sub_main_ctx_key)
+ current_context_lines = []
+ log.debug('LINE %-50s: popping from sub-subcontext to ctx%-50s', line, ctx_keys)
+
elif new_ctx is True:
if not main_ctx_key:
ctx_keys = [line, ]
@@ -436,11 +445,7 @@ end
elif (line.startswith("address-family ") or
line.startswith("vnc defaults") or
line.startswith("vnc l2-group") or
- line.startswith("vnc nve-group") or
- (line.startswith("vni ") and
- len(ctx_keys) == 2 and
- ctx_keys[0].startswith('router bgp') and
- ctx_keys[1] == 'address-family l2vpn evpn')):
+ line.startswith("vnc nve-group")):
main_ctx_key = []
# Save old context first
@@ -458,6 +463,18 @@ end
else:
ctx_keys.append(line)
+ elif ((line.startswith("vni ") and
+ len(ctx_keys) == 2 and
+ ctx_keys[0].startswith('router bgp') and
+ ctx_keys[1] == 'address-family l2vpn evpn')):
+
+ # Save old context first
+ self.save_contexts(ctx_keys, current_context_lines)
+ current_context_lines = []
+ sub_main_ctx_key = copy.deepcopy(ctx_keys)
+ log.debug('LINE %-50s: entering sub-sub-context, append to ctx_keys', line)
+ ctx_keys.append(line)
+
else:
# Continuing in an existing context, add non-commented lines to it
current_context_lines.append(line)
diff --git a/tools/zprivs.cocci b/tools/zprivs.cocci
new file mode 100644
index 0000000000..76d13c3f0d
--- /dev/null
+++ b/tools/zprivs.cocci
@@ -0,0 +1,76 @@
+@@
+identifier change;
+identifier end;
+expression E, f, g;
+iterator name frr_elevate_privs;
+@@
+
+- if (E.change(ZPRIVS_RAISE))
+- f;
++ frr_elevate_privs(&E) {
+ <+...
+- goto end;
++ break;
+ ...+>
+- end:
+- if (E.change(ZPRIVS_LOWER))
+- g;
++ }
+
+@@
+identifier change, errno, safe_strerror, exit;
+expression E, f1, f2, f3, ret, fn;
+iterator name frr_elevate_privs;
+@@
+
+ if (E.change(ZPRIVS_RAISE))
+ f1;
+ ...
+ if (...) {
+- int save_errno = errno;
+ ...
+- if (E.change(ZPRIVS_LOWER))
+- f2;
+ ...
+- safe_strerror(save_errno)
++ safe_strerror(errno)
+ ...
+ \( return ret; \| exit(ret); \)
+ }
+ ...
+ if (E.change(ZPRIVS_LOWER))
+ f3;
+
+@@
+identifier change;
+expression E, f1, f2, f3, ret;
+iterator name frr_elevate_privs;
+@@
+
+ if (E.change(ZPRIVS_RAISE))
+ f1;
+ ...
+ if (...) {
+ ...
+- if (E.change(ZPRIVS_LOWER))
+- f2;
+ ...
+ return ret;
+ }
+ ...
+ if (E.change(ZPRIVS_LOWER))
+ f3;
+
+@@
+identifier change;
+expression E, f, g;
+iterator name frr_elevate_privs;
+@@
+
+- if (E.change(ZPRIVS_RAISE))
+- f;
++ frr_elevate_privs(&E) {
+ ...
+- if (E.change(ZPRIVS_LOWER))
+- g;
++ }
diff --git a/vtysh/Makefile.am b/vtysh/Makefile.am
index 6d0b4a8fdb..936640c83a 100644
--- a/vtysh/Makefile.am
+++ b/vtysh/Makefile.am
@@ -150,11 +150,15 @@ if STATICD
vtysh_scan += $(top_srcdir)/staticd/static_vty.c
endif
+if BFDD
+vtysh_scan += $(top_srcdir)/bfdd/bfdd_vty.c
+endif
+
vtysh_cmd_FILES = $(vtysh_scan) \
$(top_srcdir)/lib/keychain.c $(top_srcdir)/lib/routemap.c \
$(top_srcdir)/lib/filter.c $(top_srcdir)/lib/plist.c \
$(top_srcdir)/lib/distribute.c $(top_srcdir)/lib/if_rmap.c \
- $(top_srcdir)/lib/vrf.c \
+ $(top_srcdir)/lib/vrf.c $(top_srcdir)/lib/if.c \
$(top_srcdir)/lib/vty.c $(top_srcdir)/zebra/debug.c \
$(top_srcdir)/lib/logicalrouter.c \
$(top_srcdir)/lib/nexthop_group.c \
diff --git a/vtysh/extract.pl.in b/vtysh/extract.pl.in
index c0277b3d61..92b5686a94 100755
--- a/vtysh/extract.pl.in
+++ b/vtysh/extract.pl.in
@@ -85,7 +85,10 @@ foreach (@ARGV) {
$protocol = "VTYSH_RMAP";
}
elsif ($file =~ /lib\/vrf\.c$/) {
- $protocol = "VTYSH_ALL";
+ $protocol = "VTYSH_VRF";
+ }
+ elsif ($file =~ /lib\/if\.c$/) {
+ $protocol = "VTYSH_INTERFACE";
}
elsif ($file =~ /lib\/logicalrouter\.c$/) {
$protocol = "VTYSH_ALL";
diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c
index e25a576926..ef4d1a0835 100644
--- a/vtysh/vtysh.c
+++ b/vtysh/vtysh.c
@@ -45,6 +45,7 @@
#include "libfrr.h"
#include "command_graph.h"
#include "frrstr.h"
+#include "json.h"
DEFINE_MTYPE_STATIC(MVTYSH, VTYSH_CMD, "Vtysh cmd copy")
@@ -134,6 +135,7 @@ struct vtysh_client vtysh_client[] = {
{.fd = -1, .name = "watchfrr", .flag = VTYSH_WATCHFRR, .next = NULL},
{.fd = -1, .name = "pbrd", .flag = VTYSH_PBRD, .next = NULL},
{.fd = -1, .name = "staticd", .flag = VTYSH_STATICD, .next = NULL},
+ {.fd = -1, .name = "bfdd", .flag = VTYSH_BFDD, .next = NULL},
};
enum vtysh_write_integrated vtysh_write_integrated =
@@ -1254,6 +1256,18 @@ struct cmd_node link_params_node = {
static struct cmd_node rpki_node = {RPKI_NODE, "%s(config-rpki)# ", 1};
#endif
+#if HAVE_BFDD > 0
+static struct cmd_node bfd_node = {
+ BFD_NODE,
+ "%s(config-bfd)# ",
+};
+
+static struct cmd_node bfd_peer_node = {
+ BFD_PEER_NODE,
+ "%s(config-bfd-peer)# ",
+};
+#endif /* HAVE_BFDD */
+
/* Defined in lib/vty.c */
extern struct cmd_node vty_node;
@@ -1680,6 +1694,32 @@ DEFUNSH(VTYSH_PBRD, vtysh_pbr_map, vtysh_pbr_map_cmd,
return CMD_SUCCESS;
}
+#if HAVE_BFDD > 0
+DEFUNSH(VTYSH_BFDD, bfd_enter, bfd_enter_cmd, "bfd", "Configure BFD peers\n")
+{
+ vty->node = BFD_NODE;
+ return CMD_SUCCESS;
+}
+
+DEFUNSH(VTYSH_BFDD, bfd_peer_enter, bfd_peer_enter_cmd,
+ "peer <A.B.C.D|X:X::X:X> [{multihop|local-address <A.B.C.D|X:X::X:X>|interface IFNAME|vrf NAME}]",
+ "Configure peer\n"
+ "IPv4 peer address\n"
+ "IPv6 peer address\n"
+ "Configure multihop\n"
+ "Configure local address\n"
+ "IPv4 local address\n"
+ "IPv6 local address\n"
+ INTERFACE_STR
+ "Configure interface name to use\n"
+ "Configure VRF\n"
+ "Configure VRF name\n")
+{
+ vty->node = BFD_PEER_NODE;
+ return CMD_SUCCESS;
+}
+#endif /* HAVE_BFDD */
+
DEFSH(VTYSH_PBRD, vtysh_no_pbr_map_cmd, "no pbr-map WORD [seq (1-700)]",
NO_STR
"Delete pbr-map\n"
@@ -1749,6 +1789,7 @@ static int vtysh_exit(struct vty *vty)
case PBRMAP_NODE:
case VTY_NODE:
case KEYCHAIN_NODE:
+ case BFD_NODE:
vtysh_execute("end");
vtysh_execute("configure terminal");
vty->node = CONFIG_NODE;
@@ -1792,6 +1833,9 @@ static int vtysh_exit(struct vty *vty)
case LINK_PARAMS_NODE:
vty->node = INTERFACE_NODE;
break;
+ case BFD_PEER_NODE:
+ vty->node = BFD_NODE;
+ break;
default:
break;
}
@@ -1988,6 +2032,17 @@ DEFUNSH(VTYSH_ISISD, vtysh_quit_isisd, vtysh_quit_isisd_cmd, "quit",
return vtysh_exit_isisd(self, vty, argc, argv);
}
+#if HAVE_BFDD > 0
+DEFUNSH(VTYSH_BFDD, vtysh_exit_bfdd, vtysh_exit_bfdd_cmd, "exit",
+ "Exit current mode and down to previous mode\n")
+{
+ return vtysh_exit(vty);
+}
+
+ALIAS(vtysh_exit_bfdd, vtysh_quit_bfdd_cmd, "quit",
+ "Exit current mode and down to previous mode\n")
+#endif
+
DEFUNSH(VTYSH_ALL, vtysh_exit_line_vty, vtysh_exit_line_vty_cmd, "exit",
"Exit current mode and down to previous mode\n")
{
@@ -2018,18 +2073,6 @@ DEFUNSH(VTYSH_ZEBRA, vtysh_pseudowire, vtysh_pseudowire_cmd,
return CMD_SUCCESS;
}
-/* TODO Implement "no interface command in isisd. */
-DEFSH(VTYSH_ZEBRA | VTYSH_RIPD | VTYSH_RIPNGD | VTYSH_OSPFD | VTYSH_OSPF6D
- | VTYSH_EIGRPD,
- vtysh_no_interface_cmd, "no interface IFNAME", NO_STR
- "Delete a pseudo interface's configuration\n"
- "Interface's name\n")
-
-DEFSH(VTYSH_ZEBRA, vtysh_no_interface_vrf_cmd, "no interface IFNAME vrf NAME",
- NO_STR
- "Delete a pseudo interface's configuration\n"
- "Interface's name\n" VRF_CMD_HELP_STR)
-
DEFUNSH(VTYSH_ZEBRA, vtysh_logicalrouter, vtysh_logicalrouter_cmd,
"logical-router (1-65535) ns NAME",
"Enable a logical-router\n"
@@ -2070,9 +2113,16 @@ DEFUNSH(VTYSH_VRF, vtysh_vrf, vtysh_vrf_cmd, "vrf NAME",
return CMD_SUCCESS;
}
-DEFSH(VTYSH_ZEBRA, vtysh_no_vrf_cmd, "no vrf NAME", NO_STR
- "Delete a pseudo vrf's configuration\n"
- "VRF's name\n")
+DEFSH(VTYSH_ZEBRA, vtysh_vrf_netns_cmd,
+ "netns NAME",
+ "Attach VRF to a Namespace\n"
+ "The file name in " NS_RUN_DIR ", or a full pathname\n")
+
+DEFSH(VTYSH_ZEBRA, vtysh_no_vrf_netns_cmd,
+ "no netns [NAME]",
+ NO_STR
+ "Detach VRF from a Namespace\n"
+ "The file name in " NS_RUN_DIR ", or a full pathname\n")
DEFUNSH(VTYSH_NS, vtysh_exit_logicalrouter,
vtysh_exit_logicalrouter_cmd, "exit",
@@ -2112,19 +2162,6 @@ DEFUNSH(VTYSH_VRF, vtysh_quit_nexthop_group, vtysh_quit_nexthop_group_cmd,
return vtysh_exit_nexthop_group(self, vty, argc, argv);
}
-/*
- * TODO Implement interface description commands in ripngd, ospf6d
- * and isisd.
- */
-DEFSH(VTYSH_ZEBRA | VTYSH_RIPD | VTYSH_OSPFD | VTYSH_EIGRPD,
- vtysh_interface_desc_cmd, "description LINE...",
- "Interface specific description\n"
- "Characters describing this interface\n")
-
-DEFSH(VTYSH_ZEBRA | VTYSH_RIPD | VTYSH_OSPFD | VTYSH_EIGRPD,
- vtysh_no_interface_desc_cmd, "no description",
- NO_STR "Interface specific description\n")
-
DEFUNSH(VTYSH_INTERFACE, vtysh_exit_interface, vtysh_exit_interface_cmd, "exit",
"Exit current mode and down to previous mode\n")
{
@@ -2308,6 +2345,28 @@ DEFUN (vtysh_show_debugging_hashtable,
"Hashtable statistics for %s:\n");
}
+DEFUN (vtysh_show_error_code,
+ vtysh_show_error_code_cmd,
+ "show error <(1-4294967296)|all> [json]",
+ SHOW_STR
+ "Information on errors\n"
+ "Error code to get info about\n"
+ "Information on all errors\n"
+ JSON_STR)
+{
+ char *fcmd = argv_concat(argv, argc, 0);
+ char cmd[256];
+ int rv;
+
+ snprintf(cmd, sizeof(cmd), "do %s", fcmd);
+
+ /* FIXME: Needs to determine which daemon to send to via code ranges */
+ rv = show_per_daemon(cmd, "");
+
+ XFREE(MTYPE_TMP, fcmd);
+ return rv;
+}
+
/* Memory */
DEFUN (vtysh_show_memory,
vtysh_show_memory_cmd,
@@ -3440,6 +3499,10 @@ void vtysh_init_vty(void)
#if defined(HAVE_RPKI)
install_node(&rpki_node, NULL);
#endif
+#if HAVE_BFDD > 0
+ install_node(&bfd_node, NULL);
+ install_node(&bfd_peer_node, NULL);
+#endif /* HAVE_BFDD */
struct cmd_node *node;
for (unsigned int i = 0; i < vector_active(cmdvec); i++) {
@@ -3534,6 +3597,21 @@ void vtysh_init_vty(void)
install_element(RMAP_NODE, &vtysh_quit_rmap_cmd);
install_element(PBRMAP_NODE, &vtysh_exit_pbr_map_cmd);
install_element(PBRMAP_NODE, &vtysh_quit_pbr_map_cmd);
+#if HAVE_BFDD > 0
+ /* Enter node. */
+ install_element(CONFIG_NODE, &bfd_enter_cmd);
+ install_element(BFD_NODE, &bfd_peer_enter_cmd);
+
+ /* Exit/quit node. */
+ install_element(BFD_NODE, &vtysh_exit_bfdd_cmd);
+ install_element(BFD_NODE, &vtysh_quit_bfdd_cmd);
+ install_element(BFD_PEER_NODE, &vtysh_exit_bfdd_cmd);
+ install_element(BFD_PEER_NODE, &vtysh_quit_bfdd_cmd);
+
+ /* End/exit all. */
+ install_element(BFD_NODE, &vtysh_end_all_cmd);
+ install_element(BFD_PEER_NODE, &vtysh_end_all_cmd);
+#endif /* HAVE_BFDD */
install_element(VTY_NODE, &vtysh_exit_line_vty_cmd);
install_element(VTY_NODE, &vtysh_quit_line_vty_cmd);
@@ -3577,8 +3655,6 @@ void vtysh_init_vty(void)
install_element(PBRMAP_NODE, &vtysh_end_all_cmd);
install_element(VTY_NODE, &vtysh_end_all_cmd);
- install_element(INTERFACE_NODE, &vtysh_interface_desc_cmd);
- install_element(INTERFACE_NODE, &vtysh_no_interface_desc_cmd);
install_element(INTERFACE_NODE, &vtysh_end_all_cmd);
install_element(INTERFACE_NODE, &vtysh_exit_interface_cmd);
install_element(LINK_PARAMS_NODE, &exit_link_params_cmd);
@@ -3682,17 +3758,16 @@ void vtysh_init_vty(void)
install_element(KEYCHAIN_NODE, &key_chain_cmd);
install_element(KEYCHAIN_KEY_NODE, &key_chain_cmd);
install_element(CONFIG_NODE, &vtysh_interface_cmd);
- install_element(CONFIG_NODE, &vtysh_no_interface_cmd);
- install_element(CONFIG_NODE, &vtysh_no_interface_vrf_cmd);
install_element(CONFIG_NODE, &vtysh_pseudowire_cmd);
install_element(INTERFACE_NODE, &vtysh_link_params_cmd);
install_element(ENABLE_NODE, &vtysh_show_running_config_cmd);
install_element(ENABLE_NODE, &vtysh_copy_running_config_cmd);
+ install_element(CONFIG_NODE, &vtysh_vrf_cmd);
+ install_element(VRF_NODE, &vtysh_vrf_netns_cmd);
+ install_element(VRF_NODE, &vtysh_no_vrf_netns_cmd);
install_element(VRF_NODE, &exit_vrf_config_cmd);
- install_element(CONFIG_NODE, &vtysh_vrf_cmd);
- install_element(CONFIG_NODE, &vtysh_no_vrf_cmd);
install_element(CONFIG_NODE, &vtysh_no_nexthop_group_cmd);
/* "write terminal" command. */
@@ -3728,6 +3803,7 @@ void vtysh_init_vty(void)
/* debugging */
install_element(VIEW_NODE, &vtysh_show_debugging_cmd);
+ install_element(VIEW_NODE, &vtysh_show_error_code_cmd);
install_element(VIEW_NODE, &vtysh_show_debugging_hashtable_cmd);
install_element(ENABLE_NODE, &vtysh_debug_all_cmd);
install_element(CONFIG_NODE, &vtysh_debug_all_cmd);
diff --git a/vtysh/vtysh.h b/vtysh/vtysh.h
index e6ed5659cf..c8e4c025e0 100644
--- a/vtysh/vtysh.h
+++ b/vtysh/vtysh.h
@@ -24,22 +24,23 @@
#include "memory.h"
DECLARE_MGROUP(MVTYSH)
-#define VTYSH_ZEBRA 0x0001
-#define VTYSH_RIPD 0x0002
-#define VTYSH_RIPNGD 0x0004
-#define VTYSH_OSPFD 0x0008
-#define VTYSH_OSPF6D 0x0010
-#define VTYSH_BGPD 0x0020
-#define VTYSH_ISISD 0x0040
-#define VTYSH_PIMD 0x0080
-#define VTYSH_LDPD 0x0100
-#define VTYSH_WATCHFRR 0x0200
-#define VTYSH_NHRPD 0x0400
-#define VTYSH_EIGRPD 0x0800
-#define VTYSH_BABELD 0x1000
-#define VTYSH_SHARPD 0x2000
-#define VTYSH_PBRD 0x4000
-#define VTYSH_STATICD 0x8000
+#define VTYSH_ZEBRA 0x00001
+#define VTYSH_RIPD 0x00002
+#define VTYSH_RIPNGD 0x00004
+#define VTYSH_OSPFD 0x00008
+#define VTYSH_OSPF6D 0x00010
+#define VTYSH_BGPD 0x00020
+#define VTYSH_ISISD 0x00040
+#define VTYSH_PIMD 0x00080
+#define VTYSH_LDPD 0x00100
+#define VTYSH_WATCHFRR 0x00200
+#define VTYSH_NHRPD 0x00400
+#define VTYSH_EIGRPD 0x00800
+#define VTYSH_BABELD 0x01000
+#define VTYSH_SHARPD 0x02000
+#define VTYSH_PBRD 0x04000
+#define VTYSH_STATICD 0x08000
+#define VTYSH_BFDD 0x10000
#define VTYSH_WAS_ACTIVE (-2)
@@ -48,7 +49,7 @@ DECLARE_MGROUP(MVTYSH)
/* watchfrr is not in ALL since library CLI functions should not be
* run on it (logging & co. should stay in a fixed/frozen config, and
* things like prefix lists are not even initialised) */
-#define VTYSH_ALL VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_LDPD|VTYSH_BGPD|VTYSH_ISISD|VTYSH_PIMD|VTYSH_NHRPD|VTYSH_EIGRPD|VTYSH_BABELD|VTYSH_SHARPD|VTYSH_PBRD|VTYSH_STATICD
+#define VTYSH_ALL VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_LDPD|VTYSH_BGPD|VTYSH_ISISD|VTYSH_PIMD|VTYSH_NHRPD|VTYSH_EIGRPD|VTYSH_BABELD|VTYSH_SHARPD|VTYSH_PBRD|VTYSH_STATICD|VTYSH_BFDD
#define VTYSH_RMAP VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_BGPD|VTYSH_ISISD|VTYSH_PIMD|VTYSH_EIGRPD|VTYSH_SHARPD
#define VTYSH_INTERFACE VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_ISISD|VTYSH_PIMD|VTYSH_NHRPD|VTYSH_EIGRPD|VTYSH_BABELD|VTYSH_PBRD
#define VTYSH_NS VTYSH_ZEBRA
diff --git a/vtysh/vtysh_config.c b/vtysh/vtysh_config.c
index 52ab28dfda..42f08342c0 100644
--- a/vtysh/vtysh_config.c
+++ b/vtysh/vtysh_config.c
@@ -318,6 +318,8 @@ void vtysh_config_parse_line(void *arg, const char *line)
config = config_get(PROTOCOL_NODE, line);
else if (strncmp(line, "mpls", strlen("mpls")) == 0)
config = config_get(MPLS_NODE, line);
+ else if (strncmp(line, "bfd", strlen("bfd")) == 0)
+ config = config_get(BFD_NODE, line);
else {
if (strncmp(line, "log", strlen("log")) == 0
|| strncmp(line, "hostname", strlen("hostname"))
diff --git a/vtysh/vtysh_main.c b/vtysh/vtysh_main.c
index 7d882620e8..86fa62f474 100644
--- a/vtysh/vtysh_main.c
+++ b/vtysh/vtysh_main.c
@@ -356,7 +356,7 @@ int main(int argc, char **argv, char **env)
break;
case OPTION_CONFDIR:
ditch_suid = 1; /* option disables SUID */
- strlcpy(sysconfdir, optarg, sizeof(sysconfdir));
+ snprintf(sysconfdir, sizeof(sysconfdir), "%s/", optarg);
break;
case 'N':
if (strchr(optarg, '/') || strchr(optarg, '.')) {
diff --git a/watchfrr/subdir.am b/watchfrr/subdir.am
index aa1a4403bc..931f11ef63 100644
--- a/watchfrr/subdir.am
+++ b/watchfrr/subdir.am
@@ -8,10 +8,12 @@ endif
noinst_HEADERS += \
watchfrr/watchfrr.h \
+ watchfrr/watchfrr_errors.h \
# end
watchfrr_watchfrr_LDADD = lib/libfrr.la @LIBCAP@
watchfrr_watchfrr_SOURCES = \
watchfrr/watchfrr.c \
+ watchfrr/watchfrr_errors.c \
watchfrr/watchfrr_vty.c \
# end
diff --git a/watchfrr/watchfrr.c b/watchfrr/watchfrr.c
index ca388d807b..c6e7505979 100644
--- a/watchfrr/watchfrr.c
+++ b/watchfrr/watchfrr.c
@@ -27,6 +27,7 @@
#include "command.h"
#include "memory_vty.h"
#include "libfrr.h"
+#include "lib_errors.h"
#include <getopt.h>
#include <sys/un.h>
@@ -35,6 +36,7 @@
#include <systemd.h>
#include "watchfrr.h"
+#include "watchfrr_errors.h"
#ifndef MIN
#define MIN(X,Y) (((X) <= (Y)) ? (X) : (Y))
@@ -247,8 +249,9 @@ static pid_t run_background(char *shell_cmd)
switch (child = fork()) {
case -1:
- zlog_err("fork failed, cannot run command [%s]: %s", shell_cmd,
- safe_strerror(errno));
+ flog_err_sys(LIB_ERR_SYSTEM_CALL,
+ "fork failed, cannot run command [%s]: %s",
+ shell_cmd, safe_strerror(errno));
return -1;
case 0:
/* Child process. */
@@ -262,14 +265,16 @@ static pid_t run_background(char *shell_cmd)
char dashc[] = "-c";
char *const argv[4] = {shell, dashc, shell_cmd, NULL};
execv("/bin/sh", argv);
- zlog_err("execv(/bin/sh -c '%s') failed: %s", shell_cmd,
- safe_strerror(errno));
+ flog_err_sys(LIB_ERR_SYSTEM_CALL,
+ "execv(/bin/sh -c '%s') failed: %s",
+ shell_cmd, safe_strerror(errno));
_exit(127);
}
default:
/* Parent process: we will reap the child later. */
- zlog_err("Forked background command [pid %d]: %s", (int)child,
- shell_cmd);
+ flog_err_sys(LIB_ERR_SYSTEM_CALL,
+ "Forked background command [pid %d]: %s",
+ (int)child, shell_cmd);
return child;
}
}
@@ -326,7 +331,8 @@ static void sigchild(void)
switch (child = waitpid(-1, &status, WNOHANG)) {
case -1:
- zlog_err("waitpid failed: %s", safe_strerror(errno));
+ flog_err_sys(LIB_ERR_SYSTEM_CALL, "waitpid failed: %s",
+ safe_strerror(errno));
return;
case 0:
zlog_warn("SIGCHLD received, but waitpid did not reap a child");
@@ -349,7 +355,8 @@ static void sigchild(void)
* completed. */
gettimeofday(&restart->time, NULL);
} else {
- zlog_err(
+ flog_err_sys(
+ LIB_ERR_SYSTEM_CALL,
"waitpid returned status for an unknown child process %d",
(int)child);
name = "(unknown)";
@@ -370,8 +377,10 @@ static void sigchild(void)
zlog_debug("%s %s process %d exited normally", what,
name, (int)child);
} else
- zlog_err("cannot interpret %s %s process %d wait status 0x%x",
- what, name, (int)child, status);
+ flog_err_sys(
+ LIB_ERR_SYSTEM_CALL,
+ "cannot interpret %s %s process %d wait status 0x%x",
+ what, name, (int)child, status);
phase_check();
}
@@ -481,8 +490,9 @@ static int wakeup_init(struct thread *t_wakeup)
dmn->t_wakeup = NULL;
if (try_connect(dmn) < 0) {
SET_WAKEUP_DOWN(dmn);
- zlog_err("%s state -> down : initial connection attempt failed",
- dmn->name);
+ flog_err(WATCHFRR_ERR_CONNECTION,
+ "%s state -> down : initial connection attempt failed",
+ dmn->name);
dmn->state = DAEMON_DOWN;
}
return 0;
@@ -491,7 +501,8 @@ static int wakeup_init(struct thread *t_wakeup)
static void daemon_down(struct daemon *dmn, const char *why)
{
if (IS_UP(dmn) || (dmn->state == DAEMON_INIT))
- zlog_err("%s state -> down : %s", dmn->name, why);
+ flog_err(WATCHFRR_ERR_CONNECTION,
+ "%s state -> down : %s", dmn->name, why);
else if (gs.loglevel > LOG_DEBUG)
zlog_debug("%s still down : %s", dmn->name, why);
if (IS_UP(dmn))
@@ -684,21 +695,23 @@ static int try_connect(struct daemon *dmn)
of creating a socket. */
if (access(addr.sun_path, W_OK) < 0) {
if (errno != ENOENT)
- zlog_err("%s: access to socket %s denied: %s",
- dmn->name, addr.sun_path,
- safe_strerror(errno));
+ flog_err_sys(LIB_ERR_SYSTEM_CALL,
+ "%s: access to socket %s denied: %s",
+ dmn->name, addr.sun_path,
+ safe_strerror(errno));
return -1;
}
if ((sock = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
- zlog_err("%s(%s): cannot make socket: %s", __func__,
- addr.sun_path, safe_strerror(errno));
+ flog_err_sys(LIB_ERR_SOCKET, "%s(%s): cannot make socket: %s",
+ __func__, addr.sun_path, safe_strerror(errno));
return -1;
}
if (set_nonblocking(sock) < 0 || set_cloexec(sock) < 0) {
- zlog_err("%s(%s): set_nonblocking/cloexec(%d) failed", __func__,
- addr.sun_path, sock);
+ flog_err_sys(LIB_ERR_SYSTEM_CALL,
+ "%s(%s): set_nonblocking/cloexec(%d) failed",
+ __func__, addr.sun_path, sock);
close(sock);
return -1;
}
@@ -735,8 +748,9 @@ static int try_connect(struct daemon *dmn)
static int phase_hanging(struct thread *t_hanging)
{
gs.t_phase_hanging = NULL;
- zlog_err("Phase [%s] hanging for %ld seconds, aborting phased restart",
- phase_str[gs.phase], PHASE_TIMEOUT);
+ flog_err(WATCHFRR_ERR_CONNECTION,
+ "Phase [%s] hanging for %ld seconds, aborting phased restart",
+ phase_str[gs.phase], PHASE_TIMEOUT);
gs.phase = PHASE_NONE;
return 0;
}
@@ -850,10 +864,10 @@ static int wakeup_unresponsive(struct thread *t_wakeup)
dmn->t_wakeup = NULL;
if (dmn->state != DAEMON_UNRESPONSIVE)
- zlog_err(
- "%s: no longer unresponsive (now %s), "
- "wakeup should have been cancelled!",
- dmn->name, state_str[dmn->state]);
+ flog_err(WATCHFRR_ERR_CONNECTION,
+ "%s: no longer unresponsive (now %s), "
+ "wakeup should have been cancelled!",
+ dmn->name, state_str[dmn->state]);
else {
SET_WAKEUP_UNRESPONSIVE(dmn);
try_restart(dmn);
@@ -867,10 +881,10 @@ static int wakeup_no_answer(struct thread *t_wakeup)
dmn->t_wakeup = NULL;
dmn->state = DAEMON_UNRESPONSIVE;
- zlog_err(
- "%s state -> unresponsive : no response yet to ping "
- "sent %ld seconds ago",
- dmn->name, gs.timeout);
+ flog_err(WATCHFRR_ERR_CONNECTION,
+ "%s state -> unresponsive : no response yet to ping "
+ "sent %ld seconds ago",
+ dmn->name, gs.timeout);
SET_WAKEUP_UNRESPONSIVE(dmn);
try_restart(dmn);
return 0;
@@ -1149,6 +1163,7 @@ int main(int argc, char **argv)
gs.restart.interval = gs.min_restart_interval;
master = frr_init();
+ watchfrr_error_init();
zlog_set_level(ZLOG_DEST_MONITOR, ZLOG_DISABLED);
if (watchfrr_di.daemon_mode) {
diff --git a/watchfrr/watchfrr_errors.c b/watchfrr/watchfrr_errors.c
new file mode 100644
index 0000000000..662e7f654d
--- /dev/null
+++ b/watchfrr/watchfrr_errors.c
@@ -0,0 +1,43 @@
+/*
+ * Watchfrr-specific error messages.
+ * Copyright (C) 2018 Cumulus Networks, Inc.
+ * Donald Sharp
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This 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 "lib/ferr.h"
+#include "watchfrr_errors.h"
+
+/* clang-format off */
+static struct log_ref ferr_watchfrr_err[] = {
+ {
+ .code = WATCHFRR_ERR_CONNECTION,
+ .title = "WATCHFRR Connection Error",
+ .description = "WATCHFRR has detected a connectivity issue with one of the FRR daemons",
+ .suggestion = "Ensure that FRR is still running and if not please open an Issue"
+ },
+ {
+ .code = END_FERR,
+ }
+};
+/* clang-format on */
+
+void watchfrr_error_init(void)
+{
+ log_ref_add(ferr_watchfrr_err);
+}
diff --git a/watchfrr/watchfrr_errors.h b/watchfrr/watchfrr_errors.h
new file mode 100644
index 0000000000..4652f950f4
--- /dev/null
+++ b/watchfrr/watchfrr_errors.h
@@ -0,0 +1,32 @@
+/*
+ * Watchfrr-specific error messages.
+ * Copyright (C) 2018 Cumulus Networks, Inc.
+ * Donald Sharp
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; see the file COPYING; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef __WATCHFRR_ERRORS_H__
+#define __WATCHFRR_ERRORS_H__
+
+#include "lib/ferr.h"
+
+enum watchfrr_log_refs {
+ WATCHFRR_ERR_CONNECTION = WATCHFRR_FERR_START,
+};
+
+extern void watchfrr_error_init(void);
+
+#endif
diff --git a/zebra/connected.h b/zebra/connected.h
index 2a2b093395..75b6e05bda 100644
--- a/zebra/connected.h
+++ b/zebra/connected.h
@@ -22,6 +22,12 @@
#ifndef _ZEBRA_CONNECTED_H
#define _ZEBRA_CONNECTED_H
+#include <zebra.h>
+#include <stdint.h>
+
+#include "lib/if.h"
+#include "lib/prefix.h"
+
extern struct connected *connected_check(struct interface *ifp,
union prefixconstptr p);
extern struct connected *connected_check_ptp(struct interface *ifp,
diff --git a/zebra/debug.h b/zebra/debug.h
index 1c08459e26..e74afe476b 100644
--- a/zebra/debug.h
+++ b/zebra/debug.h
@@ -22,6 +22,8 @@
#ifndef _ZEBRA_DEBUG_H
#define _ZEBRA_DEBUG_H
+#include "lib/vty.h"
+
/* Debug flags. */
#define ZEBRA_DEBUG_EVENT 0x01
diff --git a/zebra/if_ioctl.c b/zebra/if_ioctl.c
index f5ed945527..d17a9cf498 100644
--- a/zebra/if_ioctl.c
+++ b/zebra/if_ioctl.c
@@ -33,6 +33,7 @@
#include "log.h"
#include "vrf.h"
#include "vty.h"
+#include "lib_errors.h"
#include "zebra/interface.h"
#include "zebra/rib.h"
@@ -175,13 +176,15 @@ static int if_getaddrs(void)
ret = getifaddrs(&ifap);
if (ret != 0) {
- zlog_err("getifaddrs(): %s", safe_strerror(errno));
+ flog_err_sys(LIB_ERR_SYSTEM_CALL, "getifaddrs(): %s",
+ safe_strerror(errno));
return -1;
}
for (ifapfree = ifap; ifap; ifap = ifap->ifa_next) {
if (ifap->ifa_addr == NULL) {
- zlog_err(
+ flog_err(
+ LIB_ERR_INTERFACE,
"%s: nonsensical ifaddr with NULL ifa_addr, ifname %s",
__func__,
(ifap->ifa_name ? ifap->ifa_name : "(null)"));
@@ -190,8 +193,9 @@ static int if_getaddrs(void)
ifp = if_lookup_by_name(ifap->ifa_name, VRF_DEFAULT);
if (ifp == NULL) {
- zlog_err("if_getaddrs(): Can't lookup interface %s\n",
- ifap->ifa_name);
+ flog_err(LIB_ERR_INTERFACE,
+ "if_getaddrs(): Can't lookup interface %s\n",
+ ifap->ifa_name);
continue;
}
diff --git a/zebra/if_ioctl_solaris.c b/zebra/if_ioctl_solaris.c
index 6cf98e85f5..5a58fe1751 100644
--- a/zebra/if_ioctl_solaris.c
+++ b/zebra/if_ioctl_solaris.c
@@ -34,6 +34,7 @@
#include "privs.h"
#include "vrf.h"
#include "vty.h"
+#include "lib_errors.h"
#include "zebra/interface.h"
#include "zebra/ioctl_solaris.h"
@@ -58,29 +59,26 @@ static int interface_list_ioctl(int af)
size_t needed, lastneeded = 0;
char *buf = NULL;
- if (zserv_privs.change(ZPRIVS_RAISE))
- zlog_err("Can't raise privileges");
+ frr_elevate_privs(&zserv_privs) {
+ sock = socket(af, SOCK_DGRAM, 0);
+ }
- sock = socket(af, SOCK_DGRAM, 0);
if (sock < 0) {
zlog_warn("Can't make %s socket stream: %s",
(af == AF_INET ? "AF_INET" : "AF_INET6"),
safe_strerror(errno));
-
- if (zserv_privs.change(ZPRIVS_LOWER))
- zlog_err("Can't lower privileges");
-
return -1;
}
-calculate_lifc_len: /* must hold privileges to enter here */
- lifn.lifn_family = af;
- lifn.lifn_flags = LIFC_NOXMIT; /* we want NOXMIT interfaces too */
- ret = ioctl(sock, SIOCGLIFNUM, &lifn);
- save_errno = errno;
+calculate_lifc_len:
+ frr_elevate_privs(&zserv_privs) {
+ lifn.lifn_family = af;
+ lifn.lifn_flags = LIFC_NOXMIT;
+ /* we want NOXMIT interfaces too */
+ ret = ioctl(sock, SIOCGLIFNUM, &lifn);
+ save_errno = errno;
- if (zserv_privs.change(ZPRIVS_LOWER))
- zlog_err("Can't lower privileges");
+ }
if (ret < 0) {
zlog_warn("interface_list_ioctl: SIOCGLIFNUM failed %s",
@@ -100,11 +98,7 @@ calculate_lifc_len: /* must hold privileges to enter here */
if (needed > lastneeded || needed < lastneeded / 2) {
if (buf != NULL)
XFREE(MTYPE_TMP, buf);
- if ((buf = XMALLOC(MTYPE_TMP, needed)) == NULL) {
- zlog_warn("interface_list_ioctl: malloc failed");
- close(sock);
- return -1;
- }
+ buf = XMALLOC(MTYPE_TMP, needed);
}
lastneeded = needed;
@@ -113,27 +107,18 @@ calculate_lifc_len: /* must hold privileges to enter here */
lifconf.lifc_len = needed;
lifconf.lifc_buf = buf;
- if (zserv_privs.change(ZPRIVS_RAISE))
- zlog_err("Can't raise privileges");
-
- ret = ioctl(sock, SIOCGLIFCONF, &lifconf);
+ frr_elevate_privs(&zserv_privs) {
+ ret = ioctl(sock, SIOCGLIFCONF, &lifconf);
+ }
if (ret < 0) {
if (errno == EINVAL)
- goto calculate_lifc_len; /* deliberately hold privileges
- */
+ goto calculate_lifc_len;
zlog_warn("SIOCGLIFCONF: %s", safe_strerror(errno));
-
- if (zserv_privs.change(ZPRIVS_LOWER))
- zlog_err("Can't lower privileges");
-
goto end;
}
- if (zserv_privs.change(ZPRIVS_LOWER))
- zlog_err("Can't lower privileges");
-
/* Allocate interface. */
lifreq = lifconf.lifc_req;
diff --git a/zebra/if_netlink.c b/zebra/if_netlink.c
index 56e27e6dc8..a15d914243 100644
--- a/zebra/if_netlink.c
+++ b/zebra/if_netlink.c
@@ -52,6 +52,7 @@
#include "vrf.h"
#include "vrf_int.h"
#include "mpls.h"
+#include "lib_errors.h"
#include "vty.h"
#include "zebra/zserv.h"
@@ -79,9 +80,9 @@ static void set_ifindex(struct interface *ifp, ifindex_t ifi_index,
if (((oifp = if_lookup_by_index_per_ns(zns, ifi_index)) != NULL)
&& (oifp != ifp)) {
if (ifi_index == IFINDEX_INTERNAL)
- zlog_err(
- "Netlink is setting interface %s ifindex to reserved "
- "internal value %u",
+ flog_err(
+ LIB_ERR_INTERFACE,
+ "Netlink is setting interface %s ifindex to reserved internal value %u",
ifp->name, ifi_index);
else {
if (IS_ZEBRA_DEBUG_KERNEL)
@@ -89,9 +90,9 @@ static void set_ifindex(struct interface *ifp, ifindex_t ifi_index,
"interface index %d was renamed from %s to %s",
ifi_index, oifp->name, ifp->name);
if (if_is_up(oifp))
- zlog_err(
- "interface rename detected on up interface: index %d "
- "was renamed from %s to %s, results are uncertain!",
+ flog_err(
+ LIB_ERR_INTERFACE,
+ "interface rename detected on up interface: index %d was renamed from %s to %s, results are uncertain!",
ifi_index, oifp->name, ifp->name);
if_delete_update(oifp);
}
@@ -309,8 +310,8 @@ static void netlink_vrf_change(struct nlmsghdr *h, struct rtattr *tb,
vrf = vrf_get((vrf_id_t)ifi->ifi_index,
name); // It would create vrf
if (!vrf) {
- zlog_err("VRF %s id %u not created", name,
- ifi->ifi_index);
+ flog_err(LIB_ERR_INTERFACE, "VRF %s id %u not created",
+ name, ifi->ifi_index);
return;
}
@@ -331,8 +332,9 @@ static void netlink_vrf_change(struct nlmsghdr *h, struct rtattr *tb,
/* Enable the created VRF. */
if (!vrf_enable(vrf)) {
- zlog_err("Failed to enable VRF %s id %u", name,
- ifi->ifi_index);
+ flog_err(LIB_ERR_INTERFACE,
+ "Failed to enable VRF %s id %u", name,
+ ifi->ifi_index);
return;
}
@@ -373,20 +375,20 @@ static int get_iflink_speed(struct interface *interface)
ifdata.ifr_data = (caddr_t)&ecmd;
/* use ioctl to get IP address of an interface */
- if (zserv_privs.change(ZPRIVS_RAISE))
- zlog_err("Can't raise privileges");
- sd = vrf_socket(PF_INET, SOCK_DGRAM, IPPROTO_IP, interface->vrf_id,
- NULL);
- if (sd < 0) {
- if (IS_ZEBRA_DEBUG_KERNEL)
- zlog_debug("Failure to read interface %s speed: %d %s",
- ifname, errno, safe_strerror(errno));
- return 0;
- }
+ frr_elevate_privs(&zserv_privs) {
+ sd = vrf_socket(PF_INET, SOCK_DGRAM, IPPROTO_IP,
+ interface->vrf_id,
+ NULL);
+ if (sd < 0) {
+ if (IS_ZEBRA_DEBUG_KERNEL)
+ zlog_debug("Failure to read interface %s speed: %d %s",
+ ifname, errno, safe_strerror(errno));
+ return 0;
+ }
/* Get the current link state for the interface */
- rc = vrf_ioctl(interface->vrf_id, sd, SIOCETHTOOL, (char *)&ifdata);
- if (zserv_privs.change(ZPRIVS_LOWER))
- zlog_err("Can't lower privileges");
+ rc = vrf_ioctl(interface->vrf_id, sd, SIOCETHTOOL,
+ (char *)&ifdata);
+ }
if (rc < 0) {
if (IS_ZEBRA_DEBUG_KERNEL)
zlog_debug(
@@ -915,7 +917,8 @@ int netlink_interface_addr(struct nlmsghdr *h, ns_id_t ns_id, int startup)
ifp = if_lookup_by_index_per_ns(zns, ifa->ifa_index);
if (ifp == NULL) {
- zlog_err(
+ flog_err(
+ LIB_ERR_INTERFACE,
"netlink_interface_addr can't find interface by index %d",
ifa->ifa_index);
return -1;
diff --git a/zebra/interface.c b/zebra/interface.c
index 4211155c27..763931d350 100644
--- a/zebra/interface.c
+++ b/zebra/interface.c
@@ -22,6 +22,7 @@
#include <zebra.h>
#include "if.h"
+#include "lib_errors.h"
#include "vty.h"
#include "sockunion.h"
#include "prefix.h"
@@ -718,7 +719,8 @@ void if_delete_update(struct interface *ifp)
struct zebra_if *zif;
if (if_is_up(ifp)) {
- zlog_err(
+ flog_err(
+ LIB_ERR_INTERFACE,
"interface %s vrf %u index %d is still up while being deleted.",
ifp->name, ifp->vrf_id, ifp->ifindex);
return;
diff --git a/zebra/ioctl.c b/zebra/ioctl.c
index a577b008d5..0469bc38c0 100644
--- a/zebra/ioctl.c
+++ b/zebra/ioctl.c
@@ -27,6 +27,7 @@
#include "ioctl.h"
#include "log.h"
#include "privs.h"
+#include "lib_errors.h"
#include "vty.h"
#include "zebra/rib.h"
@@ -54,22 +55,16 @@ int if_ioctl(unsigned long request, caddr_t buffer)
int ret;
int err = 0;
- if (zserv_privs.change(ZPRIVS_RAISE))
- zlog_err("Can't raise privileges");
- sock = socket(AF_INET, SOCK_DGRAM, 0);
- if (sock < 0) {
- int save_errno = errno;
-
- if (zserv_privs.change(ZPRIVS_LOWER))
- zlog_err("Can't lower privileges");
- zlog_err("Cannot create UDP socket: %s",
- safe_strerror(save_errno));
- exit(1);
+ frr_elevate_privs(&zserv_privs) {
+ sock = socket(AF_INET, SOCK_DGRAM, 0);
+ if (sock < 0) {
+ zlog_err("Cannot create UDP socket: %s",
+ safe_strerror(errno));
+ exit(1);
+ }
+ if ((ret = ioctl(sock, request, buffer)) < 0)
+ err = errno;
}
- if ((ret = ioctl(sock, request, buffer)) < 0)
- err = errno;
- if (zserv_privs.change(ZPRIVS_LOWER))
- zlog_err("Can't lower privileges");
close(sock);
if (ret < 0) {
@@ -86,23 +81,17 @@ int vrf_if_ioctl(unsigned long request, caddr_t buffer, vrf_id_t vrf_id)
int ret;
int err = 0;
- if (zserv_privs.change(ZPRIVS_RAISE))
- zlog_err("Can't raise privileges");
- sock = vrf_socket(AF_INET, SOCK_DGRAM, 0, vrf_id, NULL);
- if (sock < 0) {
- int save_errno = errno;
-
- if (zserv_privs.change(ZPRIVS_LOWER))
- zlog_err("Can't lower privileges");
- zlog_err("Cannot create UDP socket: %s",
- safe_strerror(save_errno));
- exit(1);
+ frr_elevate_privs(&zserv_privs) {
+ sock = vrf_socket(AF_INET, SOCK_DGRAM, 0, vrf_id, NULL);
+ if (sock < 0) {
+ zlog_err("Cannot create UDP socket: %s",
+ safe_strerror(errno));
+ exit(1);
+ }
+ ret = vrf_ioctl(vrf_id, sock, request, buffer);
+ if (ret < 0)
+ err = errno;
}
- ret = vrf_ioctl(vrf_id, sock, request, buffer);
- if (ret < 0)
- err = errno;
- if (zserv_privs.change(ZPRIVS_LOWER))
- zlog_err("Can't lower privileges");
close(sock);
if (ret < 0) {
@@ -119,23 +108,17 @@ static int if_ioctl_ipv6(unsigned long request, caddr_t buffer)
int ret;
int err = 0;
- if (zserv_privs.change(ZPRIVS_RAISE))
- zlog_err("Can't raise privileges");
- sock = socket(AF_INET6, SOCK_DGRAM, 0);
- if (sock < 0) {
- int save_errno = errno;
-
- if (zserv_privs.change(ZPRIVS_LOWER))
- zlog_err("Can't lower privileges");
- zlog_err("Cannot create IPv6 datagram socket: %s",
- safe_strerror(save_errno));
- exit(1);
- }
+ frr_elevate_privs(&zserv_privs) {
+ sock = socket(AF_INET6, SOCK_DGRAM, 0);
+ if (sock < 0) {
+ zlog_err("Cannot create IPv6 datagram socket: %s",
+ safe_strerror(errno));
+ exit(1);
+ }
- if ((ret = ioctl(sock, request, buffer)) < 0)
- err = errno;
- if (zserv_privs.change(ZPRIVS_LOWER))
- zlog_err("Can't lower privileges");
+ if ((ret = ioctl(sock, request, buffer)) < 0)
+ err = errno;
+ }
close(sock);
if (ret < 0) {
@@ -413,8 +396,9 @@ void if_get_flags(struct interface *ifp)
ret = vrf_if_ioctl(SIOCGIFFLAGS, (caddr_t)&ifreq, ifp->vrf_id);
if (ret < 0) {
- zlog_err("vrf_if_ioctl(SIOCGIFFLAGS) failed: %s",
- safe_strerror(errno));
+ flog_err_sys(LIB_ERR_SYSTEM_CALL,
+ "vrf_if_ioctl(SIOCGIFFLAGS) failed: %s",
+ safe_strerror(errno));
return;
}
#ifdef HAVE_BSD_LINK_DETECT /* Detect BSD link-state at start-up */
@@ -431,8 +415,9 @@ void if_get_flags(struct interface *ifp)
/* Seems not all interfaces implement this ioctl */
if (if_ioctl(SIOCGIFMEDIA, (caddr_t)&ifmr) < 0)
- zlog_err("if_ioctl(SIOCGIFMEDIA) failed: %s",
- safe_strerror(errno));
+ flog_err_sys(LIB_ERR_SYSTEM_CALL,
+ "if_ioctl(SIOCGIFMEDIA) failed: %s",
+ safe_strerror(errno));
else if (ifmr.ifm_status & IFM_AVALID) /* Link state is valid */
{
if (ifmr.ifm_status & IFM_ACTIVE)
diff --git a/zebra/ioctl_solaris.c b/zebra/ioctl_solaris.c
index eb68451f7c..260911ce67 100644
--- a/zebra/ioctl_solaris.c
+++ b/zebra/ioctl_solaris.c
@@ -31,6 +31,7 @@
#include "privs.h"
#include "vty.h"
#include "vrf.h"
+#include "lib_errors.h"
#include "zebra/rib.h"
#include "zebra/rt.h"
@@ -57,24 +58,19 @@ int if_ioctl(unsigned long request, caddr_t buffer)
int ret;
int err;
- if (zserv_privs.change(ZPRIVS_RAISE))
- zlog_err("Can't raise privileges");
-
- sock = socket(AF_INET, SOCK_DGRAM, 0);
- if (sock < 0) {
- int save_errno = errno;
- if (zserv_privs.change(ZPRIVS_LOWER))
- zlog_err("Can't lower privileges");
- zlog_err("Cannot create UDP socket: %s",
- safe_strerror(save_errno));
- exit(1);
- }
+ frr_elevate_privs(&zserv_privs) {
+
+ sock = socket(AF_INET, SOCK_DGRAM, 0);
+ if (sock < 0) {
+ zlog_err("Cannot create UDP socket: %s",
+ safe_strerror(errno));
+ exit(1);
+ }
- if ((ret = ioctl(sock, request, buffer)) < 0)
- err = errno;
+ if ((ret = ioctl(sock, request, buffer)) < 0)
+ err = errno;
- if (zserv_privs.change(ZPRIVS_LOWER))
- zlog_err("Can't lower privileges");
+ }
close(sock);
@@ -92,24 +88,19 @@ int if_ioctl_ipv6(unsigned long request, caddr_t buffer)
int ret;
int err;
- if (zserv_privs.change(ZPRIVS_RAISE))
- zlog_err("Can't raise privileges");
-
- sock = socket(AF_INET6, SOCK_DGRAM, 0);
- if (sock < 0) {
- int save_errno = errno;
- if (zserv_privs.change(ZPRIVS_LOWER))
- zlog_err("Can't lower privileges");
- zlog_err("Cannot create IPv6 datagram socket: %s",
- safe_strerror(save_errno));
- exit(1);
- }
+ frr_elevate_privs(&zserv_privs) {
+
+ sock = socket(AF_INET6, SOCK_DGRAM, 0);
+ if (sock < 0) {
+ zlog_err("Cannot create IPv6 datagram socket: %s",
+ safe_strerror(errno));
+ exit(1);
+ }
- if ((ret = ioctl(sock, request, buffer)) < 0)
- err = errno;
+ if ((ret = ioctl(sock, request, buffer)) < 0)
+ err = errno;
- if (zserv_privs.change(ZPRIVS_LOWER))
- zlog_err("Can't lower privileges");
+ }
close(sock);
diff --git a/zebra/ipforward_proc.c b/zebra/ipforward_proc.c
index f823ec4384..3a766b1ea9 100644
--- a/zebra/ipforward_proc.c
+++ b/zebra/ipforward_proc.c
@@ -25,6 +25,7 @@
#include "log.h"
#include "privs.h"
+#include "lib_errors.h"
#include "zebra/ipforward.h"
@@ -76,24 +77,19 @@ int ipforward_on(void)
{
FILE *fp;
- if (zserv_privs.change(ZPRIVS_RAISE))
- zlog_err("Can't raise privileges, %s", safe_strerror(errno));
+ frr_elevate_privs(&zserv_privs) {
- fp = fopen(proc_ipv4_forwarding, "w");
+ fp = fopen(proc_ipv4_forwarding, "w");
- if (fp == NULL) {
- if (zserv_privs.change(ZPRIVS_LOWER))
- zlog_err("Can't lower privileges, %s",
- safe_strerror(errno));
- return -1;
- }
+ if (fp == NULL) {
+ return -1;
+ }
- fprintf(fp, "1\n");
+ fprintf(fp, "1\n");
- fclose(fp);
+ fclose(fp);
- if (zserv_privs.change(ZPRIVS_LOWER))
- zlog_err("Can't lower privileges, %s", safe_strerror(errno));
+ }
return ipforward();
}
@@ -102,24 +98,19 @@ int ipforward_off(void)
{
FILE *fp;
- if (zserv_privs.change(ZPRIVS_RAISE))
- zlog_err("Can't raise privileges, %s", safe_strerror(errno));
+ frr_elevate_privs(&zserv_privs) {
- fp = fopen(proc_ipv4_forwarding, "w");
+ fp = fopen(proc_ipv4_forwarding, "w");
- if (fp == NULL) {
- if (zserv_privs.change(ZPRIVS_LOWER))
- zlog_err("Can't lower privileges, %s",
- safe_strerror(errno));
- return -1;
- }
+ if (fp == NULL) {
+ return -1;
+ }
- fprintf(fp, "0\n");
+ fprintf(fp, "0\n");
- fclose(fp);
+ fclose(fp);
- if (zserv_privs.change(ZPRIVS_LOWER))
- zlog_err("Can't lower privileges, %s", safe_strerror(errno));
+ }
return ipforward();
}
@@ -153,24 +144,19 @@ int ipforward_ipv6_on(void)
{
FILE *fp;
- if (zserv_privs.change(ZPRIVS_RAISE))
- zlog_err("Can't raise privileges, %s", safe_strerror(errno));
+ frr_elevate_privs(&zserv_privs) {
- fp = fopen(proc_ipv6_forwarding, "w");
+ fp = fopen(proc_ipv6_forwarding, "w");
- if (fp == NULL) {
- if (zserv_privs.change(ZPRIVS_LOWER))
- zlog_err("Can't lower privileges, %s",
- safe_strerror(errno));
- return -1;
- }
+ if (fp == NULL) {
+ return -1;
+ }
- fprintf(fp, "1\n");
+ fprintf(fp, "1\n");
- fclose(fp);
+ fclose(fp);
- if (zserv_privs.change(ZPRIVS_LOWER))
- zlog_err("Can't lower privileges, %s", safe_strerror(errno));
+ }
return ipforward_ipv6();
}
@@ -180,24 +166,19 @@ int ipforward_ipv6_off(void)
{
FILE *fp;
- if (zserv_privs.change(ZPRIVS_RAISE))
- zlog_err("Can't raise privileges, %s", safe_strerror(errno));
+ frr_elevate_privs(&zserv_privs) {
- fp = fopen(proc_ipv6_forwarding, "w");
+ fp = fopen(proc_ipv6_forwarding, "w");
- if (fp == NULL) {
- if (zserv_privs.change(ZPRIVS_LOWER))
- zlog_err("Can't lower privileges, %s",
- safe_strerror(errno));
- return -1;
- }
+ if (fp == NULL) {
+ return -1;
+ }
- fprintf(fp, "0\n");
+ fprintf(fp, "0\n");
- fclose(fp);
+ fclose(fp);
- if (zserv_privs.change(ZPRIVS_LOWER))
- zlog_err("Can't lower privileges, %s", safe_strerror(errno));
+ }
return ipforward_ipv6();
}
diff --git a/zebra/ipforward_solaris.c b/zebra/ipforward_solaris.c
index 123cf1bd08..b06baa04a9 100644
--- a/zebra/ipforward_solaris.c
+++ b/zebra/ipforward_solaris.c
@@ -25,6 +25,7 @@
#include "log.h"
#include "prefix.h"
+#include "lib_errors.h"
#include "privs.h"
#include "zebra/ipforward.h"
@@ -69,10 +70,10 @@ static int solaris_nd(const int cmd, const char *parameter, const int value)
else if (cmd == ND_GET)
snprintf(nd_buf, ND_BUFFER_SIZE, "%s", parameter);
else {
- zlog_err(
- "internal error - inappropriate command given to "
- "solaris_nd()%s:%d",
- __FILE__, __LINE__);
+ flog_err_sys(LIB_ERR_SYSTEM_CALL,
+ "internal error - inappropriate command given to "
+ "solaris_nd()%s:%d",
+ __FILE__, __LINE__);
return -1;
}
@@ -81,27 +82,21 @@ static int solaris_nd(const int cmd, const char *parameter, const int value)
strioctl.ic_len = ND_BUFFER_SIZE;
strioctl.ic_dp = nd_buf;
- if (zserv_privs.change(ZPRIVS_RAISE))
- zlog_err("solaris_nd: Can't raise privileges");
- if ((fd = open(device, O_RDWR)) < 0) {
- zlog_warn("failed to open device %s - %s", device,
- safe_strerror(errno));
- if (zserv_privs.change(ZPRIVS_LOWER))
- zlog_err("solaris_nd: Can't lower privileges");
- return -1;
- }
- if (ioctl(fd, I_STR, &strioctl) < 0) {
- int save_errno = errno;
- if (zserv_privs.change(ZPRIVS_LOWER))
- zlog_err("solaris_nd: Can't lower privileges");
+ frr_elevate_privs(&zserv_privs) {
+ if ((fd = open(device, O_RDWR)) < 0) {
+ zlog_warn("failed to open device %s - %s", device,
+ safe_strerror(errno));
+ return -1;
+ }
+ if (ioctl(fd, I_STR, &strioctl) < 0) {
+ close(fd);
+ zlog_warn("ioctl I_STR failed on device %s - %s",
+ device,
+ safe_strerror(errno));
+ return -1;
+ }
close(fd);
- zlog_warn("ioctl I_STR failed on device %s - %s", device,
- safe_strerror(save_errno));
- return -1;
}
- close(fd);
- if (zserv_privs.change(ZPRIVS_LOWER))
- zlog_err("solaris_nd: Can't lower privileges");
if (cmd == ND_GET) {
errno = 0;
diff --git a/zebra/ipforward_sysctl.c b/zebra/ipforward_sysctl.c
index cdf426b9b8..74a178e59c 100644
--- a/zebra/ipforward_sysctl.c
+++ b/zebra/ipforward_sysctl.c
@@ -26,6 +26,7 @@
#include "zebra/ipforward.h"
#include "log.h"
+#include "lib_errors.h"
#define MIB_SIZ 4
@@ -53,16 +54,12 @@ int ipforward_on(void)
int ipforwarding = 1;
len = sizeof ipforwarding;
- if (zserv_privs.change(ZPRIVS_RAISE))
- zlog_err("Can't raise privileges");
- if (sysctl(mib, MIB_SIZ, NULL, NULL, &ipforwarding, len) < 0) {
- if (zserv_privs.change(ZPRIVS_LOWER))
- zlog_err("Can't lower privileges");
- zlog_warn("Can't set ipforwarding on");
- return -1;
+ frr_elevate_privs(&zserv_privs) {
+ if (sysctl(mib, MIB_SIZ, NULL, NULL, &ipforwarding, len) < 0) {
+ zlog_warn("Can't set ipforwarding on");
+ return -1;
+ }
}
- if (zserv_privs.change(ZPRIVS_LOWER))
- zlog_err("Can't lower privileges");
return ipforwarding;
}
@@ -72,16 +69,12 @@ int ipforward_off(void)
int ipforwarding = 0;
len = sizeof ipforwarding;
- if (zserv_privs.change(ZPRIVS_RAISE))
- zlog_err("Can't raise privileges");
- if (sysctl(mib, MIB_SIZ, NULL, NULL, &ipforwarding, len) < 0) {
- if (zserv_privs.change(ZPRIVS_LOWER))
- zlog_err("Can't lower privileges");
- zlog_warn("Can't set ipforwarding on");
- return -1;
+ frr_elevate_privs(&zserv_privs) {
+ if (sysctl(mib, MIB_SIZ, NULL, NULL, &ipforwarding, len) < 0) {
+ zlog_warn("Can't set ipforwarding on");
+ return -1;
+ }
}
- if (zserv_privs.change(ZPRIVS_LOWER))
- zlog_err("Can't lower privileges");
return ipforwarding;
}
@@ -100,16 +93,12 @@ int ipforward_ipv6(void)
int ip6forwarding = 0;
len = sizeof ip6forwarding;
- if (zserv_privs.change(ZPRIVS_RAISE))
- zlog_err("Can't raise privileges");
- if (sysctl(mib_ipv6, MIB_SIZ, &ip6forwarding, &len, 0, 0) < 0) {
- if (zserv_privs.change(ZPRIVS_LOWER))
- zlog_err("Can't lower privileges");
- zlog_warn("can't get ip6forwarding value");
- return -1;
+ frr_elevate_privs(&zserv_privs) {
+ if (sysctl(mib_ipv6, MIB_SIZ, &ip6forwarding, &len, 0, 0) < 0) {
+ zlog_warn("can't get ip6forwarding value");
+ return -1;
+ }
}
- if (zserv_privs.change(ZPRIVS_LOWER))
- zlog_err("Can't lower privileges");
return ip6forwarding;
}
@@ -119,16 +108,13 @@ int ipforward_ipv6_on(void)
int ip6forwarding = 1;
len = sizeof ip6forwarding;
- if (zserv_privs.change(ZPRIVS_RAISE))
- zlog_err("Can't raise privileges");
- if (sysctl(mib_ipv6, MIB_SIZ, NULL, NULL, &ip6forwarding, len) < 0) {
- if (zserv_privs.change(ZPRIVS_LOWER))
- zlog_err("Can't lower privileges");
- zlog_warn("can't get ip6forwarding value");
- return -1;
+ frr_elevate_privs(&zserv_privs) {
+ if (sysctl(mib_ipv6, MIB_SIZ, NULL, NULL, &ip6forwarding, len)
+ < 0) {
+ zlog_warn("can't get ip6forwarding value");
+ return -1;
+ }
}
- if (zserv_privs.change(ZPRIVS_LOWER))
- zlog_err("Can't lower privileges");
return ip6forwarding;
}
@@ -138,16 +124,13 @@ int ipforward_ipv6_off(void)
int ip6forwarding = 0;
len = sizeof ip6forwarding;
- if (zserv_privs.change(ZPRIVS_RAISE))
- zlog_err("Can't raise privileges");
- if (sysctl(mib_ipv6, MIB_SIZ, NULL, NULL, &ip6forwarding, len) < 0) {
- if (zserv_privs.change(ZPRIVS_LOWER))
- zlog_err("Can't lower privileges");
- zlog_warn("can't get ip6forwarding value");
- return -1;
+ frr_elevate_privs(&zserv_privs) {
+ if (sysctl(mib_ipv6, MIB_SIZ, NULL, NULL, &ip6forwarding, len)
+ < 0) {
+ zlog_warn("can't get ip6forwarding value");
+ return -1;
+ }
}
- if (zserv_privs.change(ZPRIVS_LOWER))
- zlog_err("Can't lower privileges");
return ip6forwarding;
}
diff --git a/zebra/irdp_interface.c b/zebra/irdp_interface.c
index ca78404797..f02ba1fa2f 100644
--- a/zebra/irdp_interface.c
+++ b/zebra/irdp_interface.c
@@ -1,7 +1,13 @@
/*
*
- * Copyright (C) 2000 Robert Olsson.
- * Swedish University of Agricultural Sciences
+ * Copyright (C) 1997, 2000
+ * Portions:
+ * Swedish University of Agricultural Sciences
+ * Robert Olsson
+ * Kunihiro Ishiguro
+ *
+ * Thanks to Jens Laas at Swedish University of Agricultural Sciences
+ * for reviewing and tests.
*
* This file is part of GNU Zebra.
*
@@ -20,19 +26,6 @@
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
-/*
- * This work includes work with the following copywrite:
- *
- * Copyright (C) 1997, 2000 Kunihiro Ishiguro
- *
- */
-
-/*
- * Thanks to Jens Låås at Swedish University of Agricultural Sciences
- * for reviewing and tests.
- */
-
-
#include <zebra.h>
#include "if.h"
diff --git a/zebra/irdp_main.c b/zebra/irdp_main.c
index c2411d083f..771ae796e1 100644
--- a/zebra/irdp_main.c
+++ b/zebra/irdp_main.c
@@ -28,7 +28,7 @@
*/
/*
- * Thanks to Jens Låås at Swedish University of Agricultural Sciences
+ * Thanks to Jens Laas at Swedish University of Agricultural Sciences
* for reviewing and tests.
*/
@@ -51,6 +51,7 @@
#include "thread.h"
#include "privs.h"
#include "libfrr.h"
+#include "lib_errors.h"
#include "version.h"
#include "zebra/interface.h"
#include "zebra/rtadv.h"
@@ -80,16 +81,12 @@ int irdp_sock_init(void)
int save_errno;
int sock;
- if (zserv_privs.change(ZPRIVS_RAISE))
- zlog_err("irdp_sock_init: could not raise privs, %s",
- safe_strerror(errno));
+ frr_elevate_privs(&zserv_privs) {
- sock = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
- save_errno = errno;
+ sock = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
+ save_errno = errno;
- if (zserv_privs.change(ZPRIVS_LOWER))
- zlog_err("irdp_sock_init: could not lower privs, %s",
- safe_strerror(errno));
+ }
if (sock < 0) {
zlog_warn("IRDP: can't create irdp socket %s",
diff --git a/zebra/irdp_packet.c b/zebra/irdp_packet.c
index b0dde96cce..c36c958973 100644
--- a/zebra/irdp_packet.c
+++ b/zebra/irdp_packet.c
@@ -28,39 +28,39 @@
*/
/*
- * Thanks to Jens Låås at Swedish University of Agricultural Sciences
+ * Thanks to Jens Laas at Swedish University of Agricultural Sciences
* for reviewing and tests.
*/
#include <zebra.h>
+#include <netinet/ip_icmp.h>
-
-#include "if.h"
-#include "vty.h"
-#include "sockunion.h"
-#include "prefix.h"
+#include "checksum.h"
#include "command.h"
-#include "memory.h"
-#include "zebra_memory.h"
-#include "stream.h"
-#include "ioctl.h"
#include "connected.h"
+#include "if.h"
+#include "ioctl.h"
#include "log.h"
-#include "zclient.h"
+#include "log.h"
+#include "memory.h"
+#include "prefix.h"
+#include "sockopt.h"
+#include "sockunion.h"
+#include "sockunion.h"
+#include "stream.h"
#include "thread.h"
+#include "vty.h"
+#include "zclient.h"
+
+#include "zebra_memory.h"
#include "zebra/interface.h"
#include "zebra/rtadv.h"
#include "zebra/rib.h"
#include "zebra/zserv.h"
#include "zebra/redistribute.h"
#include "zebra/irdp.h"
-#include <netinet/ip_icmp.h>
-#include "if.h"
-#include "checksum.h"
-#include "sockunion.h"
-#include "log.h"
-#include "sockopt.h"
+#include "zebra/zebra_errors.h"
/* GLOBAL VARS */
@@ -95,13 +95,15 @@ static void parse_irdp_packet(char *p, int len, struct interface *ifp)
src = ip->ip_src;
if (len != iplen) {
- zlog_err("IRDP: RX length doesnt match IP length");
+ flog_err(ZEBRA_ERR_IRDP_LEN_MISMATCH,
+ "IRDP: RX length doesnt match IP length");
return;
}
if (iplen < ICMP_MINLEN) {
- zlog_err("IRDP: RX ICMP packet too short from %s\n",
- inet_ntoa(src));
+ flog_err(ZEBRA_ERR_IRDP_LEN_MISMATCH,
+ "IRDP: RX ICMP packet too short from %s\n",
+ inet_ntoa(src));
return;
}
@@ -110,8 +112,9 @@ static void parse_irdp_packet(char *p, int len, struct interface *ifp)
+
len of IP-header) 14+20 */
if (iplen > IRDP_RX_BUF - 34) {
- zlog_err("IRDP: RX ICMP packet too long from %s\n",
- inet_ntoa(src));
+ flog_err(ZEBRA_ERR_IRDP_LEN_MISMATCH,
+ "IRDP: RX ICMP packet too long from %s\n",
+ inet_ntoa(src));
return;
}
diff --git a/zebra/kernel_netlink.c b/zebra/kernel_netlink.c
index a5c2cd69f3..ef7c26c9df 100644
--- a/zebra/kernel_netlink.c
+++ b/zebra/kernel_netlink.c
@@ -41,6 +41,7 @@
#include "nexthop.h"
#include "vrf.h"
#include "mpls.h"
+#include "lib_errors.h"
#include "zebra/zserv.h"
#include "zebra/zebra_ns.h"
@@ -51,6 +52,7 @@
#include "zebra/rt_netlink.h"
#include "zebra/if_netlink.h"
#include "zebra/rule_netlink.h"
+#include "zebra/zebra_errors.h"
#ifndef SO_RCVBUFFORCE
#define SO_RCVBUFFORCE (33)
@@ -147,9 +149,8 @@ int netlink_talk_filter(struct nlmsghdr *h, ns_id_t ns_id, int startup)
* received some other message in an unexpected
* way.
*/
- zlog_err("%s: ignoring message type 0x%04x(%s) NS %u",
- __PRETTY_FUNCTION__, h->nlmsg_type,
- nl_msg_type_to_str(h->nlmsg_type), ns_id);
+ zlog_debug("%s: ignoring message type 0x%04x(%s) NS %u", __func__,
+ h->nlmsg_type, nl_msg_type_to_str(h->nlmsg_type), ns_id);
return 0;
}
@@ -162,31 +163,33 @@ static int netlink_recvbuf(struct nlsock *nl, uint32_t newsize)
ret = getsockopt(nl->sock, SOL_SOCKET, SO_RCVBUF, &oldsize, &oldlen);
if (ret < 0) {
- zlog_err("Can't get %s receive buffer size: %s", nl->name,
- safe_strerror(errno));
+ flog_err_sys(LIB_ERR_SOCKET,
+ "Can't get %s receive buffer size: %s", nl->name,
+ safe_strerror(errno));
return -1;
}
/* Try force option (linux >= 2.6.14) and fall back to normal set */
- if (zserv_privs.change(ZPRIVS_RAISE))
- zlog_err("routing_socket: Can't raise privileges");
- ret = setsockopt(nl->sock, SOL_SOCKET, SO_RCVBUFFORCE, &nl_rcvbufsize,
- sizeof(nl_rcvbufsize));
- if (zserv_privs.change(ZPRIVS_LOWER))
- zlog_err("routing_socket: Can't lower privileges");
+ frr_elevate_privs(&zserv_privs) {
+ ret = setsockopt(nl->sock, SOL_SOCKET, SO_RCVBUFFORCE,
+ &nl_rcvbufsize,
+ sizeof(nl_rcvbufsize));
+ }
if (ret < 0)
ret = setsockopt(nl->sock, SOL_SOCKET, SO_RCVBUF,
&nl_rcvbufsize, sizeof(nl_rcvbufsize));
if (ret < 0) {
- zlog_err("Can't set %s receive buffer size: %s", nl->name,
- safe_strerror(errno));
+ flog_err_sys(LIB_ERR_SOCKET,
+ "Can't set %s receive buffer size: %s", nl->name,
+ safe_strerror(errno));
return -1;
}
ret = getsockopt(nl->sock, SOL_SOCKET, SO_RCVBUF, &newsize, &newlen);
if (ret < 0) {
- zlog_err("Can't get %s receive buffer size: %s", nl->name,
- safe_strerror(errno));
+ flog_err_sys(LIB_ERR_SOCKET,
+ "Can't get %s receive buffer size: %s", nl->name,
+ safe_strerror(errno));
return -1;
}
@@ -203,33 +206,26 @@ static int netlink_socket(struct nlsock *nl, unsigned long groups,
struct sockaddr_nl snl;
int sock;
int namelen;
- int save_errno;
- if (zserv_privs.change(ZPRIVS_RAISE)) {
- zlog_err("Can't raise privileges");
- return -1;
- }
-
- sock = ns_socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE, ns_id);
- if (sock < 0) {
- zlog_err("Can't open %s socket: %s", nl->name,
- safe_strerror(errno));
- return -1;
- }
+ frr_elevate_privs(&zserv_privs) {
+ sock = ns_socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE, ns_id);
+ if (sock < 0) {
+ zlog_err("Can't open %s socket: %s", nl->name,
+ safe_strerror(errno));
+ return -1;
+ }
- memset(&snl, 0, sizeof snl);
- snl.nl_family = AF_NETLINK;
- snl.nl_groups = groups;
+ memset(&snl, 0, sizeof snl);
+ snl.nl_family = AF_NETLINK;
+ snl.nl_groups = groups;
- /* Bind the socket to the netlink structure for anything. */
- ret = bind(sock, (struct sockaddr *)&snl, sizeof snl);
- save_errno = errno;
- if (zserv_privs.change(ZPRIVS_LOWER))
- zlog_err("Can't lower privileges");
+ /* Bind the socket to the netlink structure for anything. */
+ ret = bind(sock, (struct sockaddr *)&snl, sizeof snl);
+ }
if (ret < 0) {
zlog_err("Can't bind %s socket to group 0x%x: %s", nl->name,
- snl.nl_groups, safe_strerror(save_errno));
+ snl.nl_groups, safe_strerror(errno));
close(sock);
return -1;
}
@@ -238,8 +234,8 @@ static int netlink_socket(struct nlsock *nl, unsigned long groups,
namelen = sizeof snl;
ret = getsockname(sock, (struct sockaddr *)&snl, (socklen_t *)&namelen);
if (ret < 0 || namelen != sizeof snl) {
- zlog_err("Can't get %s socket name: %s", nl->name,
- safe_strerror(errno));
+ flog_err_sys(LIB_ERR_SOCKET, "Can't get %s socket name: %s",
+ nl->name, safe_strerror(errno));
close(sock);
return -1;
}
@@ -290,9 +286,10 @@ static int netlink_information_fetch(struct nlmsghdr *h, ns_id_t ns_id,
* this message type or not ask for
* it to be sent up to us
*/
- zlog_err("Unknown netlink nlmsg_type %s(%d) vrf %u\n",
- nl_msg_type_to_str(h->nlmsg_type), h->nlmsg_type,
- ns_id);
+ flog_err(ZEBRA_ERR_UNKNOWN_NLMSG,
+ "Unknown netlink nlmsg_type %s(%d) vrf %u\n",
+ nl_msg_type_to_str(h->nlmsg_type), h->nlmsg_type,
+ ns_id);
break;
}
return 0;
@@ -335,15 +332,15 @@ static void netlink_write_incoming(const char *buf, const unsigned int size,
char fname[MAXPATHLEN];
FILE *f;
- zserv_privs.change(ZPRIVS_RAISE);
snprintf(fname, MAXPATHLEN, "%s/%s_%u", DAEMON_VTY_DIR, "netlink",
counter);
- f = fopen(fname, "w");
+ frr_elevate_privs(&zserv_privs) {
+ f = fopen(fname, "w");
+ }
if (f) {
fwrite(buf, 1, size, f);
fclose(f);
}
- zserv_privs.change(ZPRIVS_LOWER);
}
/**
@@ -358,8 +355,9 @@ static long netlink_read_file(char *buf, const char *fname)
FILE *f;
long file_bytes = -1;
- zserv_privs.change(ZPRIVS_RAISE);
- f = fopen(fname, "r");
+ frr_elevate_privs(&zserv_privs) {
+ f = fopen(fname, "r");
+ }
if (f) {
fseek(f, 0, SEEK_END);
file_bytes = ftell(f);
@@ -367,7 +365,6 @@ static long netlink_read_file(char *buf, const char *fname)
fread(buf, NL_RCV_PKT_BUF_SIZE, 1, f);
fclose(f);
}
- zserv_privs.change(ZPRIVS_LOWER);
return file_bytes;
}
@@ -699,8 +696,9 @@ int netlink_parse_info(int (*filter)(struct nlmsghdr *, ns_id_t, int),
continue;
if (errno == EWOULDBLOCK || errno == EAGAIN)
break;
- zlog_err("%s recvmsg overrun: %s", nl->name,
- safe_strerror(errno));
+ flog_err(ZEBRA_ERR_RECVMSG_OVERRUN,
+ "%s recvmsg overrun: %s", nl->name,
+ safe_strerror(errno));
/*
* In this case we are screwed.
* There is no good way to
@@ -711,13 +709,14 @@ int netlink_parse_info(int (*filter)(struct nlmsghdr *, ns_id_t, int),
}
if (status == 0) {
- zlog_err("%s EOF", nl->name);
+ flog_err_sys(LIB_ERR_SOCKET, "%s EOF", nl->name);
return -1;
}
if (msg.msg_namelen != sizeof snl) {
- zlog_err("%s sender address length error: length %d",
- nl->name, msg.msg_namelen);
+ flog_err(ZEBRA_ERR_NETLINK_LENGTH_ERROR,
+ "%s sender address length error: length %d",
+ nl->name, msg.msg_namelen);
return -1;
}
@@ -788,6 +787,15 @@ int netlink_parse_info(int (*filter)(struct nlmsghdr *, ns_id_t, int),
continue;
}
+ if (h->nlmsg_len
+ < NLMSG_LENGTH(sizeof(struct nlmsgerr))) {
+ flog_err(
+ ZEBRA_ERR_NETLINK_LENGTH_ERROR,
+ "%s error: message truncated",
+ nl->name);
+ return -1;
+ }
+
/* Deal with errors that occur because of races
* in link handling */
if (nl == &zns->netlink_cmd
@@ -836,7 +844,8 @@ int netlink_parse_info(int (*filter)(struct nlmsghdr *, ns_id_t, int),
err->msg.nlmsg_seq,
err->msg.nlmsg_pid);
} else
- zlog_err(
+ flog_err(
+ ZEBRA_ERR_UNEXPECTED_MESSAGE,
"%s error: %s, type=%s(%u), seq=%u, pid=%u",
nl->name,
safe_strerror(-errnum),
@@ -862,27 +871,28 @@ int netlink_parse_info(int (*filter)(struct nlmsghdr *, ns_id_t, int),
* other actors besides the kernel
*/
if (snl.nl_pid != 0) {
- zlog_err("Ignoring message from pid %u",
- snl.nl_pid);
+ zlog_debug("Ignoring message from pid %u",
+ snl.nl_pid);
continue;
}
error = (*filter)(h, zns->ns_id, startup);
if (error < 0) {
- zlog_err("%s filter function error", nl->name);
- zlog_backtrace(LOG_ERR);
+ zlog_warn("%s filter function error", nl->name);
ret = error;
}
}
/* After error care. */
if (msg.msg_flags & MSG_TRUNC) {
- zlog_err("%s error: message truncated", nl->name);
+ flog_err(ZEBRA_ERR_NETLINK_LENGTH_ERROR,
+ "%s error: message truncated", nl->name);
continue;
}
if (status) {
- zlog_err("%s error: data remnant size %d", nl->name,
- status);
+ flog_err(ZEBRA_ERR_NETLINK_LENGTH_ERROR,
+ "%s error: data remnant size %d", nl->name,
+ status);
return -1;
}
}
@@ -906,11 +916,11 @@ int netlink_talk(int (*filter)(struct nlmsghdr *, ns_id_t, int startup),
struct nlmsghdr *n, struct nlsock *nl, struct zebra_ns *zns,
int startup)
{
- int status;
+ int status = 0;
struct sockaddr_nl snl;
struct iovec iov;
struct msghdr msg;
- int save_errno;
+ int save_errno = 0;
memset(&snl, 0, sizeof snl);
memset(&iov, 0, sizeof iov);
@@ -936,12 +946,10 @@ int netlink_talk(int (*filter)(struct nlmsghdr *, ns_id_t, int startup),
n->nlmsg_flags);
/* Send message to netlink interface. */
- if (zserv_privs.change(ZPRIVS_RAISE))
- zlog_err("Can't raise privileges");
- status = sendmsg(nl->sock, &msg, 0);
- save_errno = errno;
- if (zserv_privs.change(ZPRIVS_LOWER))
- zlog_err("Can't lower privileges");
+ frr_elevate_privs(&zserv_privs) {
+ status = sendmsg(nl->sock, &msg, 0);
+ save_errno = errno;
+ }
if (IS_ZEBRA_DEBUG_KERNEL_MSGDUMP_SEND) {
zlog_debug("%s: >> netlink message dump [sent]", __func__);
@@ -949,8 +957,8 @@ int netlink_talk(int (*filter)(struct nlmsghdr *, ns_id_t, int startup),
}
if (status < 0) {
- zlog_err("netlink_talk sendmsg() error: %s",
- safe_strerror(save_errno));
+ flog_err_sys(LIB_ERR_SOCKET, "netlink_talk sendmsg() error: %s",
+ safe_strerror(save_errno));
return -1;
}
@@ -969,11 +977,11 @@ int netlink_request(struct nlsock *nl, struct nlmsghdr *n)
{
int ret;
struct sockaddr_nl snl;
- int save_errno;
/* Check netlink socket. */
if (nl->sock < 0) {
- zlog_err("%s socket isn't active.", nl->name);
+ flog_err_sys(LIB_ERR_SOCKET, "%s socket isn't active.",
+ nl->name);
return -1;
}
@@ -986,21 +994,14 @@ int netlink_request(struct nlsock *nl, struct nlmsghdr *n)
snl.nl_family = AF_NETLINK;
/* Raise capabilities and send message, then lower capabilities. */
- if (zserv_privs.change(ZPRIVS_RAISE)) {
- zlog_err("Can't raise privileges");
- return -1;
+ frr_elevate_privs(&zserv_privs) {
+ ret = sendto(nl->sock, (void *)n, n->nlmsg_len, 0,
+ (struct sockaddr *)&snl, sizeof snl);
}
- ret = sendto(nl->sock, (void *)n, n->nlmsg_len, 0,
- (struct sockaddr *)&snl, sizeof snl);
- save_errno = errno;
-
- if (zserv_privs.change(ZPRIVS_LOWER))
- zlog_err("Can't lower privileges");
-
if (ret < 0) {
zlog_err("%s sendto failed: %s", nl->name,
- safe_strerror(save_errno));
+ safe_strerror(errno));
return -1;
}
@@ -1074,8 +1075,8 @@ void kernel_init(struct zebra_ns *zns)
/* Register kernel socket. */
if (fcntl(zns->netlink.sock, F_SETFL, O_NONBLOCK) < 0)
- zlog_err("Can't set %s socket error: %s(%d)",
- zns->netlink.name, safe_strerror(errno), errno);
+ flog_err_sys(LIB_ERR_SOCKET, "Can't set %s socket flags: %s",
+ zns->netlink.name, safe_strerror(errno));
if (fcntl(zns->netlink_cmd.sock, F_SETFL, O_NONBLOCK) < 0)
zlog_err("Can't set %s socket error: %s(%d)",
diff --git a/zebra/kernel_socket.c b/zebra/kernel_socket.c
index 71d709e72d..78e25e7626 100644
--- a/zebra/kernel_socket.c
+++ b/zebra/kernel_socket.c
@@ -39,6 +39,7 @@
#include "rib.h"
#include "privs.h"
#include "vrf.h"
+#include "lib_errors.h"
#include "zebra/rt.h"
#include "zebra/interface.h"
@@ -46,6 +47,7 @@
#include "zebra/debug.h"
#include "zebra/kernel_socket.h"
#include "zebra/rib.h"
+#include "zebra/zebra_errors.h"
extern struct zebra_privs_t zserv_privs;
@@ -407,8 +409,9 @@ int ifm_read(struct if_msghdr *ifm)
/* paranoia: sanity check structure */
if (ifm->ifm_msglen < sizeof(struct if_msghdr)) {
- zlog_err("ifm_read: ifm->ifm_msglen %d too short\n",
- ifm->ifm_msglen);
+ flog_err(ZEBRA_ERR_NETLINK_LENGTH_ERROR,
+ "ifm_read: ifm->ifm_msglen %d too short\n",
+ ifm->ifm_msglen);
return -1;
}
@@ -1382,15 +1385,11 @@ static int kernel_read(struct thread *thread)
/* Make routing socket. */
static void routing_socket(struct zebra_ns *zns)
{
- if (zserv_privs.change(ZPRIVS_RAISE))
- zlog_err("routing_socket: Can't raise privileges");
-
- routing_sock =
- ns_socket(AF_ROUTE, SOCK_RAW, 0, zns->ns_id);
+ frr_elevate_privs(&zserv_privs) {
+ routing_sock = ns_socket(AF_ROUTE, SOCK_RAW, 0, zns->ns_id);
+ }
if (routing_sock < 0) {
- if (zserv_privs.change(ZPRIVS_LOWER))
- zlog_err("routing_socket: Can't lower privileges");
zlog_warn("Can't init kernel routing socket");
return;
}
@@ -1402,9 +1401,6 @@ static void routing_socket(struct zebra_ns *zns)
/*if (fcntl (routing_sock, F_SETFL, O_NONBLOCK) < 0)
zlog_warn ("Can't set O_NONBLOCK to routing socket");*/
- if (zserv_privs.change(ZPRIVS_LOWER))
- zlog_err("routing_socket: Can't lower privileges");
-
/* kernel_read needs rewrite. */
thread_add_read(zebrad.master, kernel_read, NULL, routing_sock, NULL);
}
diff --git a/zebra/label_manager.c b/zebra/label_manager.c
index b24a4b68dc..e53764c770 100644
--- a/zebra/label_manager.c
+++ b/zebra/label_manager.c
@@ -21,12 +21,11 @@
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
+#include <zebra.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
-#include "zebra.h"
-#include "zserv.h"
#include "lib/log.h"
#include "lib/memory.h"
#include "lib/mpls.h"
@@ -35,7 +34,9 @@
#include "lib/zclient.h"
#include "lib/libfrr.h"
-#include "label_manager.h"
+#include "zebra/zserv.h"
+#include "zebra/label_manager.h"
+#include "zebra/zebra_errors.h"
#define CONNECTION_DELAY 5
@@ -82,8 +83,9 @@ static int relay_response_back(void)
ret = zclient_read_header(src, zclient->sock, &size, &marker, &version,
&vrf_id, &resp_cmd);
if (ret < 0 && errno != EAGAIN) {
- zlog_err("Error reading Label Manager response: %s",
- strerror(errno));
+ flog_err(ZEBRA_ERR_LM_RESPONSE,
+ "Error reading Label Manager response: %s",
+ strerror(errno));
return -1;
}
zlog_debug("Label Manager response received, %d bytes", size);
@@ -101,7 +103,8 @@ static int relay_response_back(void)
/* lookup the client to relay the msg to */
zserv = zserv_find_client(proto, instance);
if (!zserv) {
- zlog_err(
+ flog_err(
+ ZEBRA_ERR_LM_NO_SUCH_CLIENT,
"Error relaying LM response: can't find client %s, instance %u",
proto_str, instance);
return -1;
@@ -116,8 +119,9 @@ static int relay_response_back(void)
/* send response back */
ret = writen(zserv->sock, dst->data, stream_get_endp(dst));
if (ret <= 0) {
- zlog_err("Error relaying LM response to %s instance %u: %s",
- proto_str, instance, strerror(errno));
+ flog_err(ZEBRA_ERR_LM_RELAY_FAILED,
+ "Error relaying LM response to %s instance %u: %s",
+ proto_str, instance, strerror(errno));
return -1;
}
zlog_debug("Relayed LM response (%d bytes) to %s instance %u", ret,
@@ -183,7 +187,8 @@ int zread_relay_label_manager_request(int cmd, struct zserv *zserv,
unsigned short instance;
if (zclient->sock < 0) {
- zlog_err("Unable to relay LM request: no socket");
+ flog_err(ZEBRA_ERR_LM_NO_SOCKET,
+ "Unable to relay LM request: no socket");
reply_error(cmd, zserv, vrf_id);
return -1;
}
@@ -211,8 +216,9 @@ int zread_relay_label_manager_request(int cmd, struct zserv *zserv,
/* check & set client instance if unset */
if (zserv->instance && zserv->instance != instance) {
- zlog_err("Client instance(%u) != msg instance(%u)",
- zserv->instance, instance);
+ flog_err(ZEBRA_ERR_LM_BAD_INSTANCE,
+ "Client instance(%u) != msg instance(%u)",
+ zserv->instance, instance);
return -1;
}
@@ -233,8 +239,9 @@ int zread_relay_label_manager_request(int cmd, struct zserv *zserv,
/* Send request to external label manager */
ret = writen(zclient->sock, dst->data, stream_get_endp(dst));
if (ret <= 0) {
- zlog_err("Error relaying LM request from %s instance %u: %s",
- proto_str, instance, strerror(errno));
+ flog_err(ZEBRA_ERR_LM_RELAY_FAILED,
+ "Error relaying LM request from %s instance %u: %s",
+ proto_str, instance, strerror(errno));
reply_error(cmd, zserv, vrf_id);
return -1;
}
@@ -262,7 +269,8 @@ static int lm_zclient_connect(struct thread *t)
return 0;
if (zclient_socket_connect(zclient) < 0) {
- zlog_err("Error connecting synchronous zclient!");
+ flog_err(ZEBRA_ERR_LM_CLIENT_CONNECTION_FAILED,
+ "Error connecting synchronous zclient!");
thread_add_timer(zebrad.master, lm_zclient_connect, zclient,
CONNECTION_DELAY, &zclient->t_connect);
return -1;
@@ -384,8 +392,6 @@ struct label_manager_chunk *assign_label_chunk(uint8_t proto,
}
/* otherwise create a new one */
lmc = XCALLOC(MTYPE_LM_CHUNK, sizeof(struct label_manager_chunk));
- if (!lmc)
- return NULL;
if (list_isempty(lbl_mgr.lc_list))
lmc->start = MPLS_LABEL_UNRESERVED_MIN;
@@ -395,8 +401,9 @@ struct label_manager_chunk *assign_label_chunk(uint8_t proto,
->end
+ 1;
if (lmc->start > MPLS_LABEL_UNRESERVED_MAX - size + 1) {
- zlog_err("Reached max labels. Start: %u, size: %u", lmc->start,
- size);
+ flog_err(ZEBRA_ERR_LM_EXHAUSTED_LABELS,
+ "Reached max labels. Start: %u, size: %u", lmc->start,
+ size);
XFREE(MTYPE_LM_CHUNK, lmc);
return NULL;
}
@@ -434,7 +441,8 @@ int release_label_chunk(uint8_t proto, unsigned short instance, uint32_t start,
if (lmc->end != end)
continue;
if (lmc->proto != proto || lmc->instance != instance) {
- zlog_err("%s: Daemon mismatch!!", __func__);
+ flog_err(ZEBRA_ERR_LM_DAEMON_MISMATCH,
+ "%s: Daemon mismatch!!", __func__);
continue;
}
lmc->proto = NO_PROTO;
@@ -444,7 +452,8 @@ int release_label_chunk(uint8_t proto, unsigned short instance, uint32_t start,
break;
}
if (ret != 0)
- zlog_err("%s: Label chunk not released!!", __func__);
+ flog_err(ZEBRA_ERR_LM_UNRELEASED_CHUNK,
+ "%s: Label chunk not released!!", __func__);
return ret;
}
diff --git a/zebra/main.c b/zebra/main.c
index 4eeba8549a..5e7c69382f 100644
--- a/zebra/main.c
+++ b/zebra/main.c
@@ -39,6 +39,7 @@
#include "routemap.h"
#include "frr_pthread.h"
+#include "zebra/zebra_errors.h"
#include "zebra/rib.h"
#include "zebra/zserv.h"
#include "zebra/debug.h"
@@ -288,7 +289,8 @@ int main(int argc, char **argv)
multipath_num = atoi(optarg);
if (multipath_num > MULTIPATH_NUM
|| multipath_num <= 0) {
- zlog_err(
+ flog_err(
+ ZEBRA_ERR_BAD_MULTIPATH_NUM,
"Multipath Number specified must be less than %d and greater than 0",
MULTIPATH_NUM);
return 1;
@@ -411,6 +413,9 @@ int main(int argc, char **argv)
/* RNH init */
zebra_rnh_init();
+
+ /* Error init */
+ zebra_error_init();
#if defined(HANDLE_ZAPI_FUZZING)
if (zapi_fuzzing) {
diff --git a/zebra/rt_socket.c b/zebra/rt_socket.c
index 346699198f..c0ad87ce39 100644
--- a/zebra/rt_socket.c
+++ b/zebra/rt_socket.c
@@ -33,6 +33,7 @@
#include "log.h"
#include "privs.h"
#include "vxlan.h"
+#include "lib_errors.h"
#include "zebra/debug.h"
#include "zebra/rib.h"
@@ -211,7 +212,8 @@ static int kernel_rtm_ipv4(int cmd, const struct prefix *p,
*/
case ZEBRA_ERR_RTEXIST:
if (cmd != RTM_ADD)
- zlog_err(
+ flog_err(
+ LIB_ERR_SYSTEM_CALL,
"%s: rtm_write() returned %d for command %d",
__func__, error, cmd);
continue;
@@ -224,7 +226,8 @@ static int kernel_rtm_ipv4(int cmd, const struct prefix *p,
case ZEBRA_ERR_RTNOEXIST:
case ZEBRA_ERR_RTUNREACH:
default:
- zlog_err(
+ flog_err(
+ LIB_ERR_SYSTEM_CALL,
"%s: %s: rtm_write() unexpectedly returned %d for command %s",
__func__,
prefix2str(p, prefix_buf,
@@ -396,21 +399,19 @@ enum dp_req_result kernel_route_rib(struct route_node *rn,
int route = 0;
if (src_p && src_p->prefixlen) {
- zlog_err("route add: IPv6 sourcedest routes unsupported!");
+ zlog_warn("%s: IPv6 sourcedest routes unsupported!", __func__);
return DP_REQUEST_FAILURE;
}
- if (zserv_privs.change(ZPRIVS_RAISE))
- zlog_err("Can't raise privileges");
+ frr_elevate_privs(&zserv_privs) {
- if (old)
- route |= kernel_rtm(RTM_DELETE, p, old);
+ if (old)
+ route |= kernel_rtm(RTM_DELETE, p, old);
- if (new)
- route |= kernel_rtm(RTM_ADD, p, new);
+ if (new)
+ route |= kernel_rtm(RTM_ADD, p, new);
- if (zserv_privs.change(ZPRIVS_LOWER))
- zlog_err("Can't lower privileges");
+ }
if (new) {
kernel_route_rib_pass_fail(
diff --git a/zebra/rtadv.c b/zebra/rtadv.c
index 49ffcdd490..43dfca10e6 100644
--- a/zebra/rtadv.c
+++ b/zebra/rtadv.c
@@ -35,6 +35,7 @@
#include "privs.h"
#include "vrf.h"
#include "ns.h"
+#include "lib_errors.h"
#include "zebra/interface.h"
#include "zebra/rtadv.h"
@@ -123,7 +124,7 @@ static int rtadv_recv_packet(struct zebra_ns *zns, int sock, uint8_t *buf,
if (ret < 0)
return ret;
- for (cmsgptr = ZCMSG_FIRSTHDR(&msg); cmsgptr != NULL;
+ for (cmsgptr = CMSG_FIRSTHDR(&msg); cmsgptr != NULL;
cmsgptr = CMSG_NXTHDR(&msg, cmsgptr)) {
/* I want interface index which this packet comes from. */
if (cmsgptr->cmsg_level == IPPROTO_IPV6
@@ -180,7 +181,7 @@ static void rtadv_send_packet(int sock, struct interface *ifp)
adata = calloc(1, CMSG_SPACE(sizeof(struct in6_pktinfo)));
if (adata == NULL) {
- zlog_err(
+ zlog_warn(
"rtadv_send_packet: can't malloc control data");
exit(-1);
}
@@ -362,7 +363,7 @@ static void rtadv_send_packet(int sock, struct interface *ifp)
iov.iov_base = buf;
iov.iov_len = len;
- cmsgptr = ZCMSG_FIRSTHDR(&msg);
+ cmsgptr = CMSG_FIRSTHDR(&msg);
cmsgptr->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
cmsgptr->cmsg_level = IPPROTO_IPV6;
cmsgptr->cmsg_type = IPV6_PKTINFO;
@@ -373,9 +374,10 @@ static void rtadv_send_packet(int sock, struct interface *ifp)
ret = sendmsg(sock, &msg, 0);
if (ret < 0) {
- zlog_err("%s(%u): Tx RA failed, socket %u error %d (%s)",
- ifp->name, ifp->ifindex, sock, errno,
- safe_strerror(errno));
+ flog_err_sys(LIB_ERR_SOCKET,
+ "%s(%u): Tx RA failed, socket %u error %d (%s)",
+ ifp->name, ifp->ifindex, sock, errno,
+ safe_strerror(errno));
} else
zif->ra_sent++;
}
@@ -624,19 +626,15 @@ static int rtadv_read(struct thread *thread)
static int rtadv_make_socket(ns_id_t ns_id)
{
- int sock;
+ int sock = -1;
int ret = 0;
struct icmp6_filter filter;
- if (zserv_privs.change(ZPRIVS_RAISE))
- zlog_err("rtadv_make_socket: could not raise privs, %s",
- safe_strerror(errno));
+ frr_elevate_privs(&zserv_privs) {
- sock = ns_socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6, ns_id);
+ sock = ns_socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6, ns_id);
- if (zserv_privs.change(ZPRIVS_LOWER))
- zlog_err("rtadv_make_socket: could not lower privs, %s",
- safe_strerror(errno));
+ }
if (sock < 0) {
return -1;
diff --git a/zebra/rule_socket.c b/zebra/rule_socket.c
index ecd642d807..620410de04 100644
--- a/zebra/rule_socket.c
+++ b/zebra/rule_socket.c
@@ -29,6 +29,7 @@
#include "if.h"
#include "prefix.h"
#include "vrf.h"
+#include "lib_errors.h"
#include "zebra/zserv.h"
#include "zebra/zebra_ns.h"
@@ -43,13 +44,15 @@
enum dp_req_result kernel_add_pbr_rule(struct zebra_pbr_rule *rule)
{
- zlog_err("%s not Implemented for this platform", __PRETTY_FUNCTION__);
+ flog_err(LIB_ERR_UNAVAILABLE, "%s not Implemented for this platform",
+ __PRETTY_FUNCTION__);
return DP_REQUEST_FAILURE;
}
enum dp_req_result kernel_del_pbr_rule(struct zebra_pbr_rule *rule)
{
- zlog_err("%s not Implemented for this platform", __PRETTY_FUNCTION__);
+ flog_err(LIB_ERR_UNAVAILABLE, "%s not Implemented for this platform",
+ __PRETTY_FUNCTION__);
return DP_REQUEST_FAILURE;
}
diff --git a/zebra/subdir.am b/zebra/subdir.am
index 73354ec38e..f44574b236 100644
--- a/zebra/subdir.am
+++ b/zebra/subdir.am
@@ -71,6 +71,7 @@ zebra_zebra_SOURCES = \
zebra/zebra_netns_notify.c \
zebra/table_manager.c \
zebra/zapi_msg.c \
+ zebra/zebra_errors.c \
# end
zebra/zebra_vty_clippy.c: $(CLIPPY_DEPS)
@@ -115,6 +116,7 @@ noinst_HEADERS += \
zebra/zebra_netns_notify.h \
zebra/table_manager.h \
zebra/zapi_msg.h \
+ zebra/zebra_errors.h \
# end
zebra_zebra_irdp_la_SOURCES = \
diff --git a/zebra/table_manager.c b/zebra/table_manager.c
index 5bcc2c40d6..43b5c7d59e 100644
--- a/zebra/table_manager.c
+++ b/zebra/table_manager.c
@@ -35,6 +35,7 @@
#include "zebra/zebra_vrf.h"
#include "zebra/label_manager.h" /* for NO_PROTO */
#include "zebra/table_manager.h"
+#include "zebra/zebra_errors.h"
/* routing table identifiers
*
@@ -146,8 +147,9 @@ struct table_manager_chunk *assign_table_chunk(uint8_t proto, uint16_t instance,
#endif /* SUNOS_5 */
tmc->start = start;
if (RT_TABLE_ID_UNRESERVED_MAX - size + 1 < start) {
- zlog_err("Reached max table id. Start/Size %u/%u",
- start, size);
+ flog_err(ZEBRA_ERR_TM_EXHAUSTED_IDS,
+ "Reached max table id. Start/Size %u/%u", start,
+ size);
XFREE(MTYPE_TM_CHUNK, tmc);
return NULL;
}
@@ -184,7 +186,8 @@ int release_table_chunk(uint8_t proto, uint16_t instance, uint32_t start,
if (tmc->end != end)
continue;
if (tmc->proto != proto || tmc->instance != instance) {
- zlog_err("%s: Daemon mismatch!!", __func__);
+ flog_err(ZEBRA_ERR_TM_DAEMON_MISMATCH,
+ "%s: Daemon mismatch!!", __func__);
continue;
}
tmc->proto = NO_PROTO;
@@ -193,7 +196,8 @@ int release_table_chunk(uint8_t proto, uint16_t instance, uint32_t start,
break;
}
if (ret != 0)
- zlog_err("%s: Table chunk not released!!", __func__);
+ flog_err(ZEBRA_ERR_TM_UNRELEASED_CHUNK,
+ "%s: Table chunk not released!!", __func__);
return ret;
}
diff --git a/zebra/zapi_msg.c b/zebra/zapi_msg.c
index ad574d7e8b..008fc8f066 100644
--- a/zebra/zapi_msg.c
+++ b/zebra/zapi_msg.c
@@ -1058,7 +1058,8 @@ static void zread_rnh_register(ZAPI_HANDLER_ARGS)
STREAM_GET(&p.u.prefix6, s, IPV6_MAX_BYTELEN);
l += IPV6_MAX_BYTELEN;
} else {
- zlog_err(
+ flog_err(
+ ZEBRA_ERR_UNKNOWN_FAMILY,
"rnh_register: Received unknown family type %d\n",
p.family);
return;
@@ -1136,7 +1137,8 @@ static void zread_rnh_unregister(ZAPI_HANDLER_ARGS)
STREAM_GET(&p.u.prefix6, s, IPV6_MAX_BYTELEN);
l += IPV6_MAX_BYTELEN;
} else {
- zlog_err(
+ flog_err(
+ ZEBRA_ERR_UNKNOWN_FAMILY,
"rnh_register: Received unknown family type %d\n",
p.family);
return;
@@ -1172,7 +1174,8 @@ static void zread_fec_register(ZAPI_HANDLER_ARGS)
* registration
*/
if (hdr->length < ZEBRA_MIN_FEC_LENGTH) {
- zlog_err(
+ flog_err(
+ ZEBRA_ERR_IRDP_LEN_MISMATCH,
"fec_register: Received a fec register of hdr->length %d, it is of insufficient size to properly decode",
hdr->length);
return;
@@ -1183,7 +1186,8 @@ static void zread_fec_register(ZAPI_HANDLER_ARGS)
memset(&p, 0, sizeof(p));
STREAM_GETW(s, p.family);
if (p.family != AF_INET && p.family != AF_INET6) {
- zlog_err(
+ flog_err(
+ ZEBRA_ERR_UNKNOWN_FAMILY,
"fec_register: Received unknown family type %d\n",
p.family);
return;
@@ -1230,7 +1234,8 @@ static void zread_fec_unregister(ZAPI_HANDLER_ARGS)
* fec unregistration
*/
if (hdr->length < ZEBRA_MIN_FEC_LENGTH) {
- zlog_err(
+ flog_err(
+ ZEBRA_ERR_IRDP_LEN_MISMATCH,
"fec_unregister: Received a fec unregister of hdr->length %d, it is of insufficient size to properly decode",
hdr->length);
return;
@@ -1244,7 +1249,8 @@ static void zread_fec_unregister(ZAPI_HANDLER_ARGS)
memset(&p, 0, sizeof(p));
STREAM_GETW(s, p.family);
if (p.family != AF_INET && p.family != AF_INET6) {
- zlog_err(
+ flog_err(
+ ZEBRA_ERR_UNKNOWN_FAMILY,
"fec_unregister: Received unknown family type %d\n",
p.family);
return;
@@ -2376,8 +2382,9 @@ static void zread_table_manager_connect(struct zserv *client,
/* accept only dynamic routing protocols */
if ((proto >= ZEBRA_ROUTE_MAX) || (proto <= ZEBRA_ROUTE_STATIC)) {
- zlog_err("client %d has wrong protocol %s", client->sock,
- zebra_route_string(proto));
+ flog_err(ZEBRA_ERR_TM_WRONG_PROTO,
+ "client %d has wrong protocol %s", client->sock,
+ zebra_route_string(proto));
zsend_table_manager_connect_response(client, vrf_id, 1);
return;
}
@@ -2415,8 +2422,9 @@ static void zread_label_manager_connect(struct zserv *client,
/* accept only dynamic routing protocols */
if ((proto >= ZEBRA_ROUTE_MAX) || (proto <= ZEBRA_ROUTE_STATIC)) {
- zlog_err("client %d has wrong protocol %s", client->sock,
- zebra_route_string(proto));
+ flog_err(ZEBRA_ERR_TM_WRONG_PROTO,
+ "client %d has wrong protocol %s", client->sock,
+ zebra_route_string(proto));
zsend_label_manager_connect_response(client, vrf_id, 1);
return;
}
@@ -2444,14 +2452,16 @@ static int msg_client_id_mismatch(const char *op, struct zserv *client,
uint8_t proto, unsigned int instance)
{
if (proto != client->proto) {
- zlog_err("%s: msg vs client proto mismatch, client=%u msg=%u",
- op, client->proto, proto);
+ flog_err(ZEBRA_ERR_PROTO_OR_INSTANCE_MISMATCH,
+ "%s: msg vs client proto mismatch, client=%u msg=%u",
+ op, client->proto, proto);
/* TODO: fail when BGP sets proto and instance */
/* return 1; */
}
if (instance != client->instance) {
- zlog_err(
+ flog_err(
+ ZEBRA_ERR_PROTO_OR_INSTANCE_MISMATCH,
"%s: msg vs client instance mismatch, client=%u msg=%u",
op, client->instance, instance);
/* TODO: fail when BGP sets proto and instance */
@@ -2486,7 +2496,8 @@ static void zread_get_label_chunk(struct zserv *client, struct stream *msg,
lmc = assign_label_chunk(client->proto, client->instance, keep, size);
if (!lmc)
- zlog_err(
+ flog_err(
+ ZEBRA_ERR_LM_CANNOT_ASSIGN_CHUNK,
"Unable to assign Label Chunk of size %u to %s instance %u",
size, zebra_route_string(client->proto),
client->instance);
@@ -2544,7 +2555,8 @@ static void zread_label_manager_request(ZAPI_HANDLER_ARGS)
else {
/* Sanity: don't allow 'unidentified' requests */
if (!client->proto) {
- zlog_err(
+ flog_err(
+ ZEBRA_ERR_LM_ALIENS,
"Got label request from an unidentified client");
return;
}
@@ -2572,8 +2584,9 @@ static void zread_get_table_chunk(struct zserv *client, struct stream *msg,
tmc = assign_table_chunk(client->proto, client->instance, size);
if (!tmc)
- zlog_err("%s: Unable to assign Table Chunk of size %u",
- __func__, size);
+ flog_err(ZEBRA_ERR_TM_CANNOT_ASSIGN_CHUNK,
+ "%s: Unable to assign Table Chunk of size %u",
+ __func__, size);
else
zlog_debug("Assigned Table Chunk %u - %u", tmc->start,
tmc->end);
@@ -2610,7 +2623,8 @@ static void zread_table_manager_request(ZAPI_HANDLER_ARGS)
else {
/* Sanity: don't allow 'unidentified' requests */
if (!client->proto) {
- zlog_err(
+ flog_err(
+ ZEBRA_ERR_TM_ALIENS,
"Got table request from an unidentified client");
return;
}
@@ -3015,6 +3029,9 @@ void (*zserv_handlers[])(ZAPI_HANDLER_ARGS) = {
[ZEBRA_BFD_DEST_UPDATE] = zebra_ptm_bfd_dst_register,
[ZEBRA_BFD_DEST_REGISTER] = zebra_ptm_bfd_dst_register,
[ZEBRA_BFD_DEST_DEREGISTER] = zebra_ptm_bfd_dst_deregister,
+#if HAVE_BFDD > 0
+ [ZEBRA_BFD_DEST_REPLAY] = zebra_ptm_bfd_dst_replay,
+#endif /* HAVE_BFDD */
[ZEBRA_VRF_UNREGISTER] = zread_vrf_unregister,
[ZEBRA_VRF_LABEL] = zread_vrf_label,
[ZEBRA_BFD_CLIENT_REGISTER] = zebra_ptm_bfd_client_register,
@@ -3070,12 +3087,13 @@ static void zserv_write_incoming(struct stream *orig, uint16_t command)
copy = stream_dup(orig);
stream_set_getp(copy, 0);
- zserv_privs.change(ZPRIVS_RAISE);
snprintf(fname, MAXPATHLEN, "%s/%u", DAEMON_VTY_DIR, command);
- fd = open(fname, O_CREAT | O_WRONLY | O_EXCL, 0644);
+
+ frr_elevate_privs(&zserv_privs) {
+ fd = open(fname, O_CREAT | O_WRONLY | O_EXCL, 0644);
+ }
stream_flush(copy, fd);
close(fd);
- zserv_privs.change(ZPRIVS_LOWER);
stream_free(copy);
}
#endif
diff --git a/zebra/zapi_msg.h b/zebra/zapi_msg.h
index 8289e33c6a..29fe59babf 100644
--- a/zebra/zapi_msg.h
+++ b/zebra/zapi_msg.h
@@ -28,6 +28,7 @@
#include "zebra/rib.h"
#include "zebra/zserv.h"
#include "zebra/zebra_pbr.h"
+#include "zebra/zebra_errors.h"
/*
* This is called to process inbound ZAPI messages.
diff --git a/zebra/zebra_errors.c b/zebra/zebra_errors.c
new file mode 100644
index 0000000000..198e1cce23
--- /dev/null
+++ b/zebra/zebra_errors.c
@@ -0,0 +1,278 @@
+/*
+ * Zebra-specific error messages.
+ * Copyright (C) 2018 Cumulus Networks, Inc.
+ * Quentin Young
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; see the file COPYING; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <zebra.h>
+
+#include "lib/ferr.h"
+#include "zebra_errors.h"
+
+/* clang-format off */
+static struct log_ref ferr_zebra_err[] = {
+ {
+ .code = ZEBRA_ERR_LM_RESPONSE,
+ .title = "Error reading response from label manager",
+ .description = "Zebra could not read the ZAPI header from the label manager",
+ .suggestion = "Wait for the error to resolve on its own. If it does not resolve, restart Zebra.",
+ },
+ {
+ .code = ZEBRA_ERR_LM_NO_SUCH_CLIENT,
+ .title = "Label manager could not find ZAPI client",
+ .description = "Zebra was unable to find a ZAPI client matching the given protocol and instance number.",
+ .suggestion = "Ensure clients which use the label manager are properly configured and running.",
+ },
+ {
+ .code = ZEBRA_ERR_LM_RELAY_FAILED,
+ .title = "Zebra could not relay label manager response",
+ .description = "Zebra found the client and instance to relay the label manager response or request to, but was not able to do so, possibly because the connection was closed.",
+ .suggestion = "Ensure clients which use the label manager are properly configured and running.",
+ },
+ {
+ .code = ZEBRA_ERR_LM_BAD_INSTANCE,
+ .title = "Mismatch between ZAPI instance and encoded message instance",
+ .description = "While relaying a request to the external label manager, Zebra noticed that the instance number encoded in the message did not match the client instance number.",
+ .suggestion = "Notify a developer.",
+ },
+ {
+ .code = ZEBRA_ERR_LM_EXHAUSTED_LABELS,
+ .title = "Zebra label manager used all available labels",
+ .description = "Zebra is unable to assign additional label chunks because it has exhausted its assigned label range.",
+ .suggestion = "Make the label range bigger and restart Zebra.",
+ },
+ {
+ .code = ZEBRA_ERR_LM_DAEMON_MISMATCH,
+ .title = "Daemon mismatch when releasing label chunks",
+ .description = "Zebra noticed a mismatch between a label chunk and a protocol daemon number or instance when releasing unused label chunks.",
+ .suggestion = "Ignore this error.",
+ },
+ {
+ .code = ZEBRA_ERR_LM_UNRELEASED_CHUNK,
+ .title = "Zebra did not free any label chunks",
+ .description = "Zebra's chunk cleanup procedure ran, but no label chunks were released.",
+ .suggestion = "Ignore this error.",
+ },
+ {
+ .code = ZEBRA_ERR_DP_INVALID_RC,
+ .title = "Dataplane returned invalid status code",
+ .description = "The underlying dataplane responded to a Zebra message or other interaction with an unrecognized, unknown or invalid status code.",
+ .suggestion = "Notify a developer.",
+ },
+ {
+ .code = ZEBRA_ERR_WQ_NONEXISTENT,
+ .title = "A necessary work queue does not exist.",
+ .description = "A necessary work queue does not exist.",
+ .suggestion = "Notify a developer.",
+ },
+ {
+ .code = ZEBRA_ERR_FEC_ADD_FAILED,
+ .title = "Failed to add FEC for MPLS client",
+ .description = "A client requested a label binding for a new FEC, but Zebra was unable to add the FEC to its internal table.",
+ .suggestion = "Notify a developer.",
+ },
+ {
+ .code = ZEBRA_ERR_FEC_RM_FAILED,
+ .title = "Failed to remove FEC for MPLS client",
+ .description = "Zebra was unable to find and remove a FEC in its internal table.",
+ .suggestion = "Notify a developer.",
+ },
+ {
+ .code = ZEBRA_ERR_IRDP_LEN_MISMATCH,
+ .title = "IRDP message length mismatch",
+ .description = "The length encoded in the IP TLV does not match the length of the packet received.",
+ .suggestion = "Notify a developer.",
+ },
+ {
+ .code = ZEBRA_ERR_RNH_UNKNOWN_FAMILY,
+ .title = "Attempted to perform nexthop update for unknown address family",
+ .description = "Zebra attempted to perform a nexthop update for unknown address family",
+ .suggestion = "Notify a developer.",
+ },
+ {
+ .code = ZEBRA_ERR_DP_INSTALL_FAIL,
+ .title = "Dataplane installation failure",
+ .description = "Installation of routes to underlying dataplane failed.",
+ .suggestion = "Check all configuration parameters for correctness.",
+ },
+ {
+ .code = ZEBRA_ERR_TABLE_LOOKUP_FAILED,
+ .title = "Zebra table lookup failed",
+ .description = "Zebra attempted to look up a table for a particular address family and subsequent address family, but didn't find anything.",
+ .suggestion = "If you entered a command to trigger this error, make sure you entered the arguments correctly. Check your config file for any potential errors. If these look correct, seek help.",
+ },
+ {
+ .code = ZEBRA_ERR_NETLINK_NOT_AVAILABLE,
+ .title = "Netlink backend not available",
+ .description = "FRR was not compiled with support for Netlink. Any operations that require Netlink will fail.",
+ .suggestion = "Recompile FRR with Netlink, or install a package that supports this feature.",
+ },
+ {
+ .code = ZEBRA_ERR_PROTOBUF_NOT_AVAILABLE,
+ .title = "Protocol Buffers backend not available",
+ .description = "FRR was not compiled with support for Protocol Buffers. Any operations that require Protobuf will fail.",
+ .suggestion = "Recompile FRR with Protobuf support, or install a package that supports this feature.",
+ },
+ {
+ .code = ZEBRA_ERR_TM_EXHAUSTED_IDS,
+ .title = "Table manager used all available IDs",
+ .description = "Zebra's table manager used up all IDs available to it and can't assign any more.",
+ .suggestion = "Reconfigure Zebra with a larger range of table IDs.",
+ },
+ {
+ .code = ZEBRA_ERR_TM_DAEMON_MISMATCH,
+ .title = "Daemon mismatch when releasing table chunks",
+ .description = "Zebra noticed a mismatch between a table ID chunk and a protocol daemon number instance when releasing unused table chunks.",
+ .suggestion = "Ignore this error.",
+ },
+ {
+ .code = ZEBRA_ERR_TM_UNRELEASED_CHUNK,
+ .title = "Zebra did not free any table chunks",
+ .description = "Zebra's table chunk cleanup procedure ran, but no table chunks were released.",
+ .suggestion = "Ignore this error.",
+ },
+ {
+ .code = ZEBRA_ERR_UNKNOWN_FAMILY,
+ .title = "Address family specifier unrecognized",
+ .description = "Zebra attempted to process information from somewhere that included an address family specifier, but did not recognize the provided specifier.",
+ .suggestion = "Ensure that your configuration is correct. If it is, notify a developer.",
+ },
+ {
+ .code = ZEBRA_ERR_TM_WRONG_PROTO,
+ .title = "Incorrect protocol for table manager client",
+ .description = "Zebra's table manager only accepts connections from daemons managing dynamic routing protocols, but received a connection attempt from a daemon that does not meet this criterion.",
+ .suggestion = "Notify a developer.",
+ },
+ {
+ .code = ZEBRA_ERR_PROTO_OR_INSTANCE_MISMATCH,
+ .title = "Mismatch between message and client protocol and/or instance",
+ .description = "Zebra detected a mismatch between a client's protocol and/or instance numbers versus those stored in a message transiting its socket.",
+ .suggestion = "Notify a developer.",
+ },
+ {
+ .code = ZEBRA_ERR_LM_CANNOT_ASSIGN_CHUNK,
+ .title = "Label manager unable to assign label chunk",
+ .description = "Zebra's label manager was unable to assign a label chunk to client.",
+ .suggestion = "Ensure that Zebra has a sufficient label range available and that there is not a range collision.",
+ },
+ {
+ .code = ZEBRA_ERR_LM_ALIENS,
+ .title = "Label request from unidentified client",
+ .description = "Zebra's label manager received a label request from an unidentified client.",
+ .suggestion = "Notify a developer.",
+ },
+ {
+ .code = ZEBRA_ERR_TM_CANNOT_ASSIGN_CHUNK,
+ .title = "Table manager unable to assign table chunk",
+ .description = "Zebra's table manager was unable to assign a table chunk to a client.",
+ .suggestion = "Ensure that Zebra has sufficient table ID range available and that there is not a range collision.",
+ },
+ {
+ .code = ZEBRA_ERR_TM_ALIENS,
+ .title = "Table request from unidentified client",
+ .description = "Zebra's table manager received a table request from an unidentified client.",
+ .suggestion = "Notify a developer.",
+ },
+ {
+ .code = ZEBRA_ERR_RECVBUF,
+ .title = "Cannot set receive buffer size",
+ .description = "Socket receive buffer size could not be set in the kernel",
+ .suggestion = "Ignore this error.",
+ },
+ {
+ .code = ZEBRA_ERR_UNKNOWN_NLMSG,
+ .title = "Unknown Netlink message type",
+ .description = "Zebra received a Netlink message with an unrecognized type field.",
+ .suggestion = "Verify that you are running the latest version of FRR to ensure kernel compatibility. If the problem persists, notify a developer.",
+ },
+ {
+ .code = ZEBRA_ERR_RECVMSG_OVERRUN,
+ .title = "Receive buffer overrun",
+ .description = "The kernel's buffer for a socket has been overrun, rendering the socket invalid.",
+ .suggestion = "Zebra will restart itself. Notify a developer if this issue shows up frequently.",
+ },
+ {
+ .code = ZEBRA_ERR_NETLINK_LENGTH_ERROR,
+ .title = "Netlink message length mismatch",
+ .description = "Zebra received a Netlink message with incorrect length fields.",
+ .suggestion = "Notify a developer.",
+ },
+ {
+ .code = ZEBRA_ERR_NETLINK_LENGTH_ERROR,
+ .title = "Netlink message length mismatch",
+ .description = "Zebra received a Netlink message with incorrect length fields.",
+ .suggestion = "Notify a developer.",
+ },
+ {
+ .code = ZEBRA_ERR_UNEXPECTED_MESSAGE,
+ .title = "Received unexpected response from kernel",
+ .description = "Received unexpected response from the kernel via Netlink.",
+ .suggestion = "Notify a developer.",
+ },
+ {
+ .code = ZEBRA_ERR_NETLINK_BAD_SEQUENCE,
+ .title = "Bad sequence number in Netlink message",
+ .description = "Zebra received a Netlink message with a bad sequence number.",
+ .suggestion = "Notify a developer.",
+ },
+ {
+ .code = ZEBRA_ERR_BAD_MULTIPATH_NUM,
+ .title = "Multipath number was out of valid range",
+ .description = "Multipath number specified to Zebra must be in the appropriate range",
+ .suggestion = "Provide a multipath number that is within its accepted range",
+ },
+ {
+ .code = ZEBRA_ERR_PREFIX_PARSE_ERROR,
+ .title = "String could not be parsed as IP prefix",
+ .description = "There was an attempt to parse a string as an IPv4 or IPv6 prefix, but the string could not be parsed and this operation failed.",
+ .suggestion = "Notify a developer.",
+ },
+ {
+ .code = ZEBRA_ERR_MAC_ADD_FAILED,
+ .title = "Failed to add MAC address to interface",
+ .description = "Zebra attempted to assign a MAC address to a vxlan interface but failed",
+ .suggestion = "Notify a developer.",
+ },
+ {
+ .code = ZEBRA_ERR_VNI_DEL_FAILED,
+ .title = "Failed to delete VNI",
+ .description = "Zebra attempted to delete a VNI entry and failed",
+ .suggestion = "Notify a developer.",
+ },
+ {
+ .code = ZEBRA_ERR_VTEP_ADD_FAILED,
+ .title = "Adding remote VTEP failed",
+ .description = "Zebra attempted to add a remote VTEP and failed.",
+ .suggestion = "Notify a developer.",
+ },
+ {
+ .code = ZEBRA_ERR_VNI_ADD_FAILED,
+ .title = "Adding VNI failed",
+ .description = "Zebra attempted to add a VNI hash to an interface and failed",
+ .suggestion = "Notify a developer.",
+ },
+ {
+ .code = END_FERR,
+ }
+};
+/* clang-format on */
+
+
+void zebra_error_init(void)
+{
+ log_ref_add(ferr_zebra_err);
+}
diff --git a/zebra/zebra_errors.h b/zebra/zebra_errors.h
new file mode 100644
index 0000000000..f8a00bce0d
--- /dev/null
+++ b/zebra/zebra_errors.h
@@ -0,0 +1,73 @@
+/*
+ * Zebra-specific error messages.
+ * Copyright (C) 2018 Cumulus Networks, Inc.
+ * Quentin Young
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; see the file COPYING; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef __ZEBRA_ERRORS_H__
+#define __ZEBRA_ERRORS_H__
+
+#include "lib/ferr.h"
+
+enum zebra_log_refs {
+ ZEBRA_ERR_LM_RESPONSE = ZEBRA_FERR_START,
+ ZEBRA_ERR_LM_NO_SUCH_CLIENT,
+ ZEBRA_ERR_LM_RELAY_FAILED,
+ ZEBRA_ERR_LM_NO_SOCKET,
+ ZEBRA_ERR_LM_BAD_INSTANCE,
+ ZEBRA_ERR_LM_RELAY_REQUEST_FAILED,
+ ZEBRA_ERR_LM_CLIENT_CONNECTION_FAILED,
+ ZEBRA_ERR_LM_EXHAUSTED_LABELS,
+ ZEBRA_ERR_LM_DAEMON_MISMATCH,
+ ZEBRA_ERR_LM_UNRELEASED_CHUNK,
+ ZEBRA_ERR_DP_INVALID_RC,
+ ZEBRA_ERR_WQ_NONEXISTENT,
+ ZEBRA_ERR_FEC_ADD_FAILED,
+ ZEBRA_ERR_FEC_RM_FAILED,
+ ZEBRA_ERR_IRDP_LEN_MISMATCH,
+ ZEBRA_ERR_RNH_UNKNOWN_FAMILY,
+ ZEBRA_ERR_DP_INSTALL_FAIL,
+ ZEBRA_ERR_TABLE_LOOKUP_FAILED,
+ ZEBRA_ERR_NETLINK_NOT_AVAILABLE,
+ ZEBRA_ERR_PROTOBUF_NOT_AVAILABLE,
+ ZEBRA_ERR_TM_EXHAUSTED_IDS,
+ ZEBRA_ERR_TM_DAEMON_MISMATCH,
+ ZEBRA_ERR_TM_UNRELEASED_CHUNK,
+ ZEBRA_ERR_UNKNOWN_FAMILY,
+ ZEBRA_ERR_TM_WRONG_PROTO,
+ ZEBRA_ERR_PROTO_OR_INSTANCE_MISMATCH,
+ ZEBRA_ERR_LM_CANNOT_ASSIGN_CHUNK,
+ ZEBRA_ERR_LM_ALIENS,
+ ZEBRA_ERR_TM_CANNOT_ASSIGN_CHUNK,
+ ZEBRA_ERR_TM_ALIENS,
+ ZEBRA_ERR_RECVBUF,
+ ZEBRA_ERR_UNKNOWN_NLMSG,
+ ZEBRA_ERR_RECVMSG_OVERRUN,
+ ZEBRA_ERR_NETLINK_LENGTH_ERROR,
+ ZEBRA_ERR_UNEXPECTED_MESSAGE,
+ ZEBRA_ERR_NETLINK_BAD_SEQUENCE,
+ ZEBRA_ERR_BAD_MULTIPATH_NUM,
+ ZEBRA_ERR_PREFIX_PARSE_ERROR,
+ ZEBRA_ERR_MAC_ADD_FAILED,
+ ZEBRA_ERR_VNI_DEL_FAILED,
+ ZEBRA_ERR_VTEP_ADD_FAILED,
+ ZEBRA_ERR_VNI_ADD_FAILED,
+};
+
+void zebra_error_init(void);
+
+#endif /* __ZEBRA_ERRORS_H__ */
diff --git a/zebra/zebra_fpm.c b/zebra/zebra_fpm.c
index 9d3133f55b..1cb14abbf9 100644
--- a/zebra/zebra_fpm.c
+++ b/zebra/zebra_fpm.c
@@ -35,6 +35,7 @@
#include "zebra/zserv.h"
#include "zebra/zebra_ns.h"
#include "zebra/zebra_vrf.h"
+#include "zebra/zebra_errors.h"
#include "fpm/fpm.h"
#include "zebra_fpm_private.h"
@@ -1517,7 +1518,9 @@ static inline void zfpm_init_message_format(const char *format)
if (!strcmp("netlink", format)) {
if (!have_netlink) {
- zlog_err("FPM netlink message format is not available");
+ flog_err(
+ ZEBRA_ERR_NETLINK_NOT_AVAILABLE,
+ "FPM netlink message format is not available");
return;
}
zfpm_g->message_format = ZFPM_MSG_FORMAT_NETLINK;
@@ -1526,7 +1529,8 @@ static inline void zfpm_init_message_format(const char *format)
if (!strcmp("protobuf", format)) {
if (!have_protobuf) {
- zlog_err(
+ flog_err(
+ ZEBRA_ERR_PROTOBUF_NOT_AVAILABLE,
"FPM protobuf message format is not available");
return;
}
diff --git a/zebra/zebra_mpls.c b/zebra/zebra_mpls.c
index cfe208d35b..cd41537a1b 100644
--- a/zebra/zebra_mpls.c
+++ b/zebra/zebra_mpls.c
@@ -45,6 +45,7 @@
#include "zebra/zebra_memory.h"
#include "zebra/zebra_vrf.h"
#include "zebra/zebra_mpls.h"
+#include "zebra/zebra_errors.h"
DEFINE_MTYPE_STATIC(ZEBRA, LSP, "MPLS LSP object")
DEFINE_MTYPE_STATIC(ZEBRA, FEC, "MPLS FEC object")
@@ -550,8 +551,6 @@ static zebra_fec_t *fec_add(struct route_table *table, struct prefix *p,
if (!fec) {
fec = XCALLOC(MTYPE_FEC, sizeof(zebra_fec_t));
- if (!fec)
- return NULL;
rn->info = fec;
fec->rn = rn;
@@ -919,7 +918,9 @@ static wq_item_status lsp_process(struct work_queue *wq, void *data)
UNSET_FLAG(lsp->flags, LSP_FLAG_CHANGED);
switch (kernel_add_lsp(lsp)) {
case DP_REQUEST_QUEUED:
- zlog_err("No current DataPlane interfaces can return this, please fix");
+ flog_err(
+ ZEBRA_ERR_DP_INVALID_RC,
+ "No current DataPlane interfaces can return this, please fix");
break;
case DP_REQUEST_FAILURE:
break;
@@ -934,7 +935,9 @@ static wq_item_status lsp_process(struct work_queue *wq, void *data)
switch (kernel_del_lsp(lsp)) {
case DP_REQUEST_QUEUED:
- zlog_err("No current DataPlane interfaces can return this, please fix");
+ flog_err(
+ ZEBRA_ERR_DP_INVALID_RC,
+ "No current DataPlane interfaces can return this, please fix");
break;
case DP_REQUEST_FAILURE:
break;
@@ -972,7 +975,9 @@ static wq_item_status lsp_process(struct work_queue *wq, void *data)
switch (kernel_upd_lsp(lsp)) {
case DP_REQUEST_QUEUED:
- zlog_err("No current DataPlane interfaces can return this, please fix");
+ flog_err(
+ ZEBRA_ERR_DP_INVALID_RC,
+ "No current DataPlane interfaces can return this, please fix");
break;
case DP_REQUEST_FAILURE:
break;
@@ -1050,7 +1055,8 @@ static int lsp_processq_add(zebra_lsp_t *lsp)
return 0;
if (zebrad.lsp_process_q == NULL) {
- zlog_err("%s: work_queue does not exist!", __func__);
+ flog_err(ZEBRA_ERR_WQ_NONEXISTENT,
+ "%s: work_queue does not exist!", __func__);
return -1;
}
@@ -1181,8 +1187,6 @@ static zebra_nhlfe_t *nhlfe_add(zebra_lsp_t *lsp, enum lsp_types_t lsp_type,
return NULL;
nhlfe = XCALLOC(MTYPE_NHLFE, sizeof(zebra_nhlfe_t));
- if (!nhlfe)
- return NULL;
nhlfe->lsp = lsp;
nhlfe->type = lsp_type;
@@ -1694,7 +1698,8 @@ static int mpls_processq_init(struct zebra_t *zebra)
{
zebra->lsp_process_q = work_queue_new(zebra->master, "LSP processing");
if (!zebra->lsp_process_q) {
- zlog_err("%s: could not initialise work queue!", __func__);
+ flog_err(ZEBRA_ERR_WQ_NONEXISTENT,
+ "%s: could not initialise work queue!", __func__);
return -1;
}
@@ -1829,7 +1834,8 @@ int zebra_mpls_fec_register(struct zebra_vrf *zvrf, struct prefix *p,
fec = fec_add(table, p, MPLS_INVALID_LABEL, 0, label_index);
if (!fec) {
prefix2str(p, buf, BUFSIZ);
- zlog_err(
+ flog_err(
+ ZEBRA_ERR_FEC_ADD_FAILED,
"Failed to add FEC %s upon register, client %s",
buf, zebra_route_string(client->proto));
return -1;
@@ -1909,8 +1915,9 @@ int zebra_mpls_fec_unregister(struct zebra_vrf *zvrf, struct prefix *p,
fec = fec_find(table, p);
if (!fec) {
prefix2str(p, buf, BUFSIZ);
- zlog_err("Failed to find FEC %s upon unregister, client %s",
- buf, zebra_route_string(client->proto));
+ flog_err(ZEBRA_ERR_FEC_RM_FAILED,
+ "Failed to find FEC %s upon unregister, client %s",
+ buf, zebra_route_string(client->proto));
return -1;
}
@@ -2040,7 +2047,8 @@ int zebra_mpls_static_fec_add(struct zebra_vrf *zvrf, struct prefix *p,
MPLS_INVALID_LABEL_INDEX);
if (!fec) {
prefix2str(p, buf, BUFSIZ);
- zlog_err("Failed to add FEC %s upon config", buf);
+ flog_err(ZEBRA_ERR_FEC_ADD_FAILED,
+ "Failed to add FEC %s upon config", buf);
return -1;
}
@@ -2087,7 +2095,8 @@ int zebra_mpls_static_fec_del(struct zebra_vrf *zvrf, struct prefix *p)
fec = fec_find(table, p);
if (!fec) {
prefix2str(p, buf, BUFSIZ);
- zlog_err("Failed to find FEC %s upon delete", buf);
+ flog_err(ZEBRA_ERR_FEC_RM_FAILED,
+ "Failed to find FEC %s upon delete", buf);
return -1;
}
diff --git a/zebra/zebra_mpls_openbsd.c b/zebra/zebra_mpls_openbsd.c
index 412fe7d3dd..542de27e83 100644
--- a/zebra/zebra_mpls_openbsd.c
+++ b/zebra/zebra_mpls_openbsd.c
@@ -31,6 +31,7 @@
#include "prefix.h"
#include "interface.h"
#include "log.h"
+#include "lib_errors.h"
extern struct zebra_privs_t zserv_privs;
@@ -116,14 +117,13 @@ static int kernel_send_rtmsg_v4(int action, mpls_label_t in_label,
hdr.rtm_mpls = MPLS_OP_SWAP;
}
- if (zserv_privs.change(ZPRIVS_RAISE))
- zlog_err("Can't raise privileges");
- ret = writev(kr_state.fd, iov, iovcnt);
- if (zserv_privs.change(ZPRIVS_LOWER))
- zlog_err("Can't lower privileges");
+ frr_elevate_privs(&zserv_privs) {
+ ret = writev(kr_state.fd, iov, iovcnt);
+ }
if (ret == -1)
- zlog_err("%s: %s", __func__, safe_strerror(errno));
+ flog_err_sys(LIB_ERR_SOCKET, "%s: %s", __func__,
+ safe_strerror(errno));
return ret;
}
@@ -224,14 +224,13 @@ static int kernel_send_rtmsg_v6(int action, mpls_label_t in_label,
hdr.rtm_mpls = MPLS_OP_SWAP;
}
- if (zserv_privs.change(ZPRIVS_RAISE))
- zlog_err("Can't raise privileges");
- ret = writev(kr_state.fd, iov, iovcnt);
- if (zserv_privs.change(ZPRIVS_LOWER))
- zlog_err("Can't lower privileges");
+ frr_elevate_privs(&zserv_privs) {
+ ret = writev(kr_state.fd, iov, iovcnt);
+ }
if (ret == -1)
- zlog_err("%s: %s", __func__, safe_strerror(errno));
+ flog_err_sys(LIB_ERR_SOCKET, "%s: %s", __func__,
+ safe_strerror(errno));
return ret;
}
@@ -360,8 +359,8 @@ static int kmpw_install(struct zebra_pw *pw)
imr.imr_type = IMR_TYPE_ETHERNET_TAGGED;
break;
default:
- zlog_err("%s: unhandled pseudowire type (%#X)", __func__,
- pw->type);
+ zlog_warn("%s: unhandled pseudowire type (%#X)", __func__,
+ pw->type);
return -1;
}
@@ -382,8 +381,8 @@ static int kmpw_install(struct zebra_pw *pw)
sa_in6->sin6_addr = pw->nexthop.ipv6;
break;
default:
- zlog_err("%s: unhandled pseudowire address-family (%u)",
- __func__, pw->af);
+ zlog_warn("%s: unhandled pseudowire address-family (%u)",
+ __func__, pw->af);
return -1;
}
memcpy(&imr.imr_nexthop, (struct sockaddr *)&ss,
@@ -398,7 +397,8 @@ static int kmpw_install(struct zebra_pw *pw)
strlcpy(ifr.ifr_name, pw->ifname, sizeof(ifr.ifr_name));
ifr.ifr_data = (caddr_t)&imr;
if (ioctl(kr_state.ioctl_fd, SIOCSETMPWCFG, &ifr) == -1) {
- zlog_err("ioctl SIOCSETMPWCFG: %s", safe_strerror(errno));
+ flog_err_sys(LIB_ERR_SYSTEM_CALL, "ioctl SIOCSETMPWCFG: %s",
+ safe_strerror(errno));
return -1;
}
@@ -415,7 +415,8 @@ static int kmpw_uninstall(struct zebra_pw *pw)
strlcpy(ifr.ifr_name, pw->ifname, sizeof(ifr.ifr_name));
ifr.ifr_data = (caddr_t)&imr;
if (ioctl(kr_state.ioctl_fd, SIOCSETMPWCFG, &ifr) == -1) {
- zlog_err("ioctl SIOCSETMPWCFG: %s", safe_strerror(errno));
+ flog_err_sys(LIB_ERR_SYSTEM_CALL, "ioctl SIOCSETMPWCFG: %s",
+ safe_strerror(errno));
return -1;
}
diff --git a/zebra/zebra_netns_id.c b/zebra/zebra_netns_id.c
index 96e6df34da..a3278c4780 100644
--- a/zebra/zebra_netns_id.c
+++ b/zebra/zebra_netns_id.c
@@ -22,6 +22,7 @@
#include "ns.h"
#include "vrf.h"
#include "log.h"
+#include "lib_errors.h"
#if defined(HAVE_NETLINK)
@@ -34,7 +35,8 @@
#include "kernel_netlink.h"
#endif /* defined(HAVE_NETLINK) */
-#include "zebra_netns_id.h"
+#include "zebra/zebra_netns_id.h"
+#include "zebra/zebra_errors.h"
/* default NS ID value used when VRF backend is not NETNS */
#define NS_DEFAULT_INTERNAL 0
@@ -86,8 +88,8 @@ static int send_receive(int sock, struct nlmsghdr *nlh, unsigned int seq,
ret = sendto(sock, (const void *)nlh, (size_t)nlh->nlmsg_len, 0,
(struct sockaddr *)&snl, (socklen_t)sizeof(snl));
if (ret < 0) {
- zlog_err("netlink( %u) sendmsg() error: %s", sock,
- safe_strerror(errno));
+ flog_err_sys(LIB_ERR_SOCKET, "netlink( %u) sendmsg() error: %s",
+ sock, safe_strerror(errno));
return -1;
}
@@ -107,16 +109,20 @@ static int send_receive(int sock, struct nlmsghdr *nlh, unsigned int seq,
};
ret = recvmsg(sock, &msg, 0);
if (ret < 0) {
- zlog_err("netlink recvmsg: error %d (errno %u)", ret, errno);
+ flog_err_sys(LIB_ERR_SOCKET,
+ "netlink recvmsg: error %d (errno %u)", ret,
+ errno);
return -1;
}
if (msg.msg_flags & MSG_TRUNC) {
- zlog_err("netlink recvmsg : error message truncated");
+ flog_err(ZEBRA_ERR_NETLINK_LENGTH_ERROR,
+ "netlink recvmsg : error message truncated");
return -1;
}
/* nlh already points to buf */
if (nlh->nlmsg_seq != seq) {
- zlog_err(
+ flog_err(
+ ZEBRA_ERR_NETLINK_BAD_SEQUENCE,
"netlink recvmsg: bad sequence number %x (expected %x)",
seq, nlh->nlmsg_seq);
return -1;
@@ -170,8 +176,8 @@ ns_id_t zebra_ns_id_get(const char *netnspath)
/* netlink socket */
sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
if (sock < 0) {
- zlog_err("netlink( %u) socket() error: %s", sock,
- safe_strerror(errno));
+ flog_err_sys(LIB_ERR_SOCKET, "netlink( %u) socket() error: %s",
+ sock, safe_strerror(errno));
close(fd);
return NS_UNKNOWN;
}
@@ -181,8 +187,9 @@ ns_id_t zebra_ns_id_get(const char *netnspath)
snl.nl_pid = 0; /* AUTO PID */
ret = bind(sock, (struct sockaddr *)&snl, sizeof(snl));
if (ret < 0) {
- zlog_err("netlink( %u) socket() bind error: %s", sock,
- safe_strerror(errno));
+ flog_err_sys(LIB_ERR_SOCKET,
+ "netlink( %u) socket() bind error: %s", sock,
+ safe_strerror(errno));
close(sock);
close(fd);
return NS_UNKNOWN;
@@ -255,7 +262,8 @@ ns_id_t zebra_ns_id_get(const char *netnspath)
if (ret <= 0) {
if (errno != EEXIST && ret != 0) {
- zlog_err(
+ flog_err(
+ LIB_ERR_SOCKET,
"netlink( %u) recvfrom() error 2 when reading: %s",
fd, safe_strerror(errno));
close(sock);
diff --git a/zebra/zebra_netns_notify.c b/zebra/zebra_netns_notify.c
index 2dd686fd0d..2b7bf04ec3 100644
--- a/zebra/zebra_netns_notify.c
+++ b/zebra/zebra_netns_notify.c
@@ -34,6 +34,7 @@
#include "ns.h"
#include "command.h"
#include "memory.h"
+#include "lib_errors.h"
#include "zserv.h"
#include "zebra_memory.h"
@@ -75,11 +76,9 @@ static void zebra_ns_notify_create_context_from_entry_name(const char *name)
if (netnspath == NULL)
return;
- if (zserv_privs.change(ZPRIVS_RAISE))
- zlog_err("Can't raise privileges");
- ns_id = zebra_ns_id_get(netnspath);
- if (zserv_privs.change(ZPRIVS_LOWER))
- zlog_err("Can't lower privileges");
+ frr_elevate_privs(&zserv_privs) {
+ ns_id = zebra_ns_id_get(netnspath);
+ }
if (ns_id == NS_UNKNOWN)
return;
ns_id_external = ns_map_nsid_with_external(ns_id, true);
@@ -96,12 +95,10 @@ static void zebra_ns_notify_create_context_from_entry_name(const char *name)
ns_map_nsid_with_external(ns_id, false);
return;
}
- if (zserv_privs.change(ZPRIVS_RAISE))
- zlog_err("Can't raise privileges");
- ret = vrf_netns_handler_create(NULL, vrf, netnspath,
- ns_id_external, ns_id);
- if (zserv_privs.change(ZPRIVS_LOWER))
- zlog_err("Can't lower privileges");
+ frr_elevate_privs(&zserv_privs) {
+ ret = vrf_netns_handler_create(NULL, vrf, netnspath,
+ ns_id_external, ns_id);
+ }
if (ret != CMD_SUCCESS) {
zlog_warn("NS notify : failed to create NS %s", netnspath);
ns_map_nsid_with_external(ns_id, false);
@@ -168,20 +165,16 @@ static int zebra_ns_ready_read(struct thread *t)
netnspath = zns_info->netnspath;
if (--zns_info->retries == 0)
stop_retry = 1;
- if (zserv_privs.change(ZPRIVS_RAISE))
- zlog_err("Can't raise privileges");
- err = ns_switch_to_netns(netnspath);
- if (zserv_privs.change(ZPRIVS_LOWER))
- zlog_err("Can't lower privileges");
+ frr_elevate_privs(&zserv_privs) {
+ err = ns_switch_to_netns(netnspath);
+ }
if (err < 0)
return zebra_ns_continue_read(zns_info, stop_retry);
/* go back to default ns */
- if (zserv_privs.change(ZPRIVS_RAISE))
- zlog_err("Can't raise privileges");
- err = ns_switchback_to_initial();
- if (zserv_privs.change(ZPRIVS_LOWER))
- zlog_err("Can't lower privileges");
+ frr_elevate_privs(&zserv_privs) {
+ err = ns_switchback_to_initial();
+ }
if (err < 0)
return zebra_ns_continue_read(zns_info, stop_retry);
diff --git a/zebra/zebra_ns.c b/zebra/zebra_ns.c
index 25e68cc081..456253cc30 100644
--- a/zebra/zebra_ns.c
+++ b/zebra/zebra_ns.c
@@ -26,6 +26,7 @@
#include "lib/logicalrouter.h"
#include "lib/prefix.h"
#include "lib/memory.h"
+#include "lib/lib_errors.h"
#include "rtadv.h"
#include "zebra_ns.h"
@@ -314,11 +315,9 @@ int zebra_ns_init(void)
dzns = zebra_ns_alloc();
- if (zserv_privs.change(ZPRIVS_RAISE))
- zlog_err("Can't raise privileges");
- ns_id = zebra_ns_id_get_default();
- if (zserv_privs.change(ZPRIVS_LOWER))
- zlog_err("Can't lower privileges");
+ frr_elevate_privs(&zserv_privs) {
+ ns_id = zebra_ns_id_get_default();
+ }
ns_id_external = ns_map_nsid_with_external(ns_id, true);
ns_init_management(ns_id_external, ns_id);
diff --git a/zebra/zebra_ptm.c b/zebra/zebra_ptm.c
index 5975c4058b..b71234be04 100644
--- a/zebra/zebra_ptm.c
+++ b/zebra/zebra_ptm.c
@@ -19,25 +19,38 @@
*/
#include <zebra.h>
+
#include <sys/un.h> /* for sockaddr_un */
#include <net/if.h>
+
+#include "bfd.h"
+#include "buffer.h"
+#include "command.h"
+#include "if.h"
+#include "network.h"
+#include "ptm_lib.h"
+#include "rib.h"
+#include "stream.h"
+#include "version.h"
+#include "vrf.h"
#include "vty.h"
-#include "zebra/zserv.h"
-#include "zebra/interface.h"
+
#include "zebra/debug.h"
+#include "zebra/interface.h"
+#include "zebra/zebra_errors.h"
#include "zebra/zebra_ptm.h"
-#include "if.h"
-#include "command.h"
-#include "stream.h"
-#include "ptm_lib.h"
-#include "network.h"
-#include "buffer.h"
#include "zebra/zebra_ptm_redistribute.h"
-#include "bfd.h"
-#include "vrf.h"
-#include "rib.h"
+#include "zebra/zserv.h"
#include "zebra_vrf.h"
-#include "version.h"
+
+/*
+ * Choose the BFD implementation that we'll use.
+ *
+ * There are two implementations:
+ * - PTM BFD: which uses an external daemon;
+ * - bfdd: FRR's own BFD daemon;
+ */
+#if HAVE_BFDD == 0
#define ZEBRA_PTM_RECONNECT_TIME_INITIAL 1 /* initial reconnect is 1s */
#define ZEBRA_PTM_RECONNECT_TIME_MAX 300
@@ -491,15 +504,17 @@ static int zebra_ptm_handle_bfd_msg(void *arg, void *in_ctxt,
dest_str, src_str);
if (str2prefix(dest_str, &dest_prefix) == 0) {
- zlog_err("%s: Peer addr %s not found", __func__, dest_str);
+ flog_err(ZEBRA_ERR_PREFIX_PARSE_ERROR,
+ "%s: Peer addr %s not found", __func__, dest_str);
return -1;
}
memset(&src_prefix, 0, sizeof(struct prefix));
if (strcmp(ZEBRA_PTM_INVALID_SRC_IP, src_str)) {
if (str2prefix(src_str, &src_prefix) == 0) {
- zlog_err("%s: Local addr %s not found", __func__,
- src_str);
+ flog_err(ZEBRA_ERR_PREFIX_PARSE_ERROR,
+ "%s: Local addr %s not found", __func__,
+ src_str);
return -1;
}
}
@@ -593,8 +608,8 @@ static int zebra_ptm_handle_msg_cb(void *arg, void *in_ctxt)
ifp = if_lookup_by_name_all_vrf(port_str);
if (!ifp) {
- zlog_err("%s: %s not found in interface list", __func__,
- port_str);
+ zlog_warn("%s: %s not found in interface list",
+ __func__, port_str);
return -1;
}
}
@@ -1017,8 +1032,8 @@ int zebra_ptm_bfd_client_deregister(struct zserv *client)
return 0;
if (IS_ZEBRA_DEBUG_EVENT)
- zlog_err("bfd_client_deregister msg for client %s",
- zebra_route_string(proto));
+ zlog_warn("bfd_client_deregister msg for client %s",
+ zebra_route_string(proto));
if (ptm_cb.ptm_sock == -1) {
ptm_cb.t_timer = NULL;
@@ -1141,3 +1156,432 @@ void zebra_ptm_if_write(struct vty *vty, struct zebra_if *zebra_ifp)
if (zebra_ifp->ptm_enable == ZEBRA_IF_PTM_ENABLE_OFF)
vty_out(vty, " no ptm-enable\n");
}
+
+#else /* HAVE_BFDD */
+
+#include "zebra/zebra_memory.h"
+
+/*
+ * Data structures.
+ */
+struct ptm_process {
+ struct zserv *pp_zs;
+ pid_t pp_pid;
+
+ TAILQ_ENTRY(ptm_process) pp_entry;
+};
+TAILQ_HEAD(ppqueue, ptm_process) ppqueue;
+
+DEFINE_MTYPE_STATIC(ZEBRA, ZEBRA_PTM_BFD_PROCESS,
+ "PTM BFD process registration table.");
+
+/*
+ * Prototypes.
+ */
+static struct ptm_process *pp_new(pid_t pid, struct zserv *zs);
+static struct ptm_process *pp_lookup_byzs(struct zserv *zs);
+static void pp_free(struct ptm_process *pp);
+static void pp_free_all(void);
+
+static void zebra_ptm_send_bfdd(struct stream *msg);
+static void zebra_ptm_send_clients(struct stream *msg);
+static int _zebra_ptm_bfd_client_deregister(struct zserv *zs);
+static void _zebra_ptm_reroute(struct zserv *zs, struct stream *msg,
+ uint32_t command);
+
+
+/*
+ * Process PID registration.
+ */
+static struct ptm_process *pp_new(pid_t pid, struct zserv *zs)
+{
+ struct ptm_process *pp;
+
+#ifdef PTM_DEBUG
+ /* Sanity check: more than one client can't have the same PID. */
+ TAILQ_FOREACH(pp, &ppqueue, pp_entry) {
+ if (pp->pp_pid == pid && pp->pp_zs != zs)
+ zlog_err("%s:%d pid and client pointer doesn't match",
+ __FILE__, __LINE__);
+ }
+#endif /* PTM_DEBUG */
+
+ /* Lookup for duplicates. */
+ pp = pp_lookup_byzs(zs);
+ if (pp != NULL)
+ return pp;
+
+ /* Allocate and register new process. */
+ pp = XCALLOC(MTYPE_ZEBRA_PTM_BFD_PROCESS, sizeof(*pp));
+ if (pp == NULL)
+ return NULL;
+
+ pp->pp_pid = pid;
+ pp->pp_zs = zs;
+ TAILQ_INSERT_HEAD(&ppqueue, pp, pp_entry);
+
+ return pp;
+}
+
+static struct ptm_process *pp_lookup_byzs(struct zserv *zs)
+{
+ struct ptm_process *pp;
+
+ TAILQ_FOREACH(pp, &ppqueue, pp_entry) {
+ if (pp->pp_zs != zs)
+ continue;
+
+ break;
+ }
+
+ return pp;
+}
+
+static void pp_free(struct ptm_process *pp)
+{
+ if (pp == NULL)
+ return;
+
+ TAILQ_REMOVE(&ppqueue, pp, pp_entry);
+ XFREE(MTYPE_ZEBRA_PTM_BFD_PROCESS, pp);
+}
+
+static void pp_free_all(void)
+{
+ struct ptm_process *pp;
+
+ while (!TAILQ_EMPTY(&ppqueue)) {
+ pp = TAILQ_FIRST(&ppqueue);
+ pp_free(pp);
+ }
+}
+
+
+/*
+ * Use the FRR's internal daemon implementation.
+ */
+static void zebra_ptm_send_bfdd(struct stream *msg)
+{
+ struct listnode *node;
+ struct zserv *client;
+ struct stream *msgc;
+
+ /* Create copy for replication. */
+ msgc = stream_dup(msg);
+ if (msgc == NULL) {
+ zlog_warn("%s: not enough memory", __func__);
+ return;
+ }
+
+ /* Send message to all running BFDd daemons. */
+ for (ALL_LIST_ELEMENTS_RO(zebrad.client_list, node, client)) {
+ if (client->proto != ZEBRA_ROUTE_BFD)
+ continue;
+
+ zserv_send_message(client, msg);
+
+ /* Allocate more messages. */
+ msg = stream_dup(msgc);
+ if (msg == NULL) {
+ zlog_warn("%s: not enough memory", __func__);
+ return;
+ }
+ }
+
+ stream_free(msgc);
+}
+
+static void zebra_ptm_send_clients(struct stream *msg)
+{
+ struct listnode *node;
+ struct zserv *client;
+ struct stream *msgc;
+
+ /* Create copy for replication. */
+ msgc = stream_dup(msg);
+ if (msgc == NULL) {
+ zlog_warn("%s: not enough memory", __func__);
+ return;
+ }
+
+ /* Send message to all running client daemons. */
+ for (ALL_LIST_ELEMENTS_RO(zebrad.client_list, node, client)) {
+ switch (client->proto) {
+ case ZEBRA_ROUTE_BGP:
+ case ZEBRA_ROUTE_OSPF:
+ case ZEBRA_ROUTE_OSPF6:
+ case ZEBRA_ROUTE_PIM:
+ break;
+
+ default:
+ /* NOTHING: skip this daemon. */
+ continue;
+ }
+
+ zserv_send_message(client, msg);
+
+ /* Allocate more messages. */
+ msg = stream_dup(msgc);
+ if (msg == NULL) {
+ zlog_warn("%s: not enough memory", __func__);
+ return;
+ }
+ }
+
+ stream_free(msgc);
+}
+
+static int _zebra_ptm_bfd_client_deregister(struct zserv *zs)
+{
+ struct stream *msg;
+ struct ptm_process *pp;
+
+ /* Filter daemons that must receive this treatment. */
+ switch (zs->proto) {
+ case ZEBRA_ROUTE_BGP:
+ case ZEBRA_ROUTE_OSPF:
+ case ZEBRA_ROUTE_OSPF6:
+ case ZEBRA_ROUTE_PIM:
+ break;
+
+ case ZEBRA_ROUTE_BFD:
+ /* Don't try to send BFDd messages to itself. */
+ return 0;
+
+ default:
+ /* Unsupported daemon. */
+ return 0;
+ }
+
+ /* Find daemon pid by zebra connection pointer. */
+ pp = pp_lookup_byzs(zs);
+ if (pp == NULL) {
+ zlog_err("%s:%d failed to find process pid registration",
+ __FILE__, __LINE__);
+ return -1;
+ }
+
+ /* Generate, send message and free() daemon related data. */
+ msg = stream_new(ZEBRA_MAX_PACKET_SIZ);
+ if (msg == NULL) {
+ zlog_warn("%s: not enough memory", __func__);
+ return 0;
+ }
+
+ /*
+ * The message type will be BFD_DEST_REPLY so we can use only
+ * one callback at the `bfdd` side, however the real command
+ * number will be included right after the zebra header.
+ */
+ zclient_create_header(msg, ZEBRA_BFD_DEST_REPLAY, 0);
+ stream_putl(msg, ZEBRA_BFD_CLIENT_DEREGISTER);
+
+ /* Put process PID. */
+ stream_putl(msg, pp->pp_pid);
+
+ /* Update the data pointers. */
+ stream_putw_at(msg, 0, stream_get_endp(msg));
+
+ zebra_ptm_send_bfdd(msg);
+
+ pp_free(pp);
+
+ return 0;
+}
+
+void zebra_ptm_init(void)
+{
+ /* Initialize the ptm process information list. */
+ TAILQ_INIT(&ppqueue);
+
+ /*
+ * Send deregistration messages to BFD daemon when some other
+ * daemon closes. This will help avoid sending daemons
+ * unnecessary notification messages.
+ */
+ hook_register(zserv_client_close, _zebra_ptm_bfd_client_deregister);
+}
+
+void zebra_ptm_finish(void)
+{
+ /* Remove the client disconnect hook and free all memory. */
+ hook_unregister(zserv_client_close, _zebra_ptm_bfd_client_deregister);
+ pp_free_all();
+}
+
+
+/*
+ * Message handling.
+ */
+static void _zebra_ptm_reroute(struct zserv *zs, struct stream *msg,
+ uint32_t command)
+{
+ struct stream *msgc;
+ size_t zmsglen, zhdrlen;
+ pid_t ppid;
+
+ /*
+ * Don't modify message in the zebra API. In order to do that we
+ * need to allocate a new message stream and copy the message
+ * provided by zebra.
+ */
+ msgc = stream_new(ZEBRA_MAX_PACKET_SIZ);
+ if (msgc == NULL) {
+ zlog_warn("%s: not enough memory", __func__);
+ return;
+ }
+
+ /* Calculate our header size plus the message contents. */
+ zhdrlen = ZEBRA_HEADER_SIZE + sizeof(uint32_t);
+ zmsglen = msg->endp - msg->getp;
+ memcpy(msgc->data + zhdrlen, msg->data + msg->getp, zmsglen);
+
+ /*
+ * The message type will be BFD_DEST_REPLY so we can use only
+ * one callback at the `bfdd` side, however the real command
+ * number will be included right after the zebra header.
+ */
+ zclient_create_header(msgc, ZEBRA_BFD_DEST_REPLAY, 0);
+ stream_putl(msgc, command);
+
+ /* Update the data pointers. */
+ msgc->getp = 0;
+ msgc->endp = zhdrlen + zmsglen;
+ stream_putw_at(msgc, 0, stream_get_endp(msgc));
+
+ zebra_ptm_send_bfdd(msgc);
+
+ /* Registrate process PID for shutdown hook. */
+ STREAM_GETL(msg, ppid);
+ pp_new(ppid, zs);
+
+ return;
+
+stream_failure:
+ zlog_err("%s:%d failed to registrate client pid", __FILE__, __LINE__);
+}
+
+void zebra_ptm_bfd_dst_register(ZAPI_HANDLER_ARGS)
+{
+ if (IS_ZEBRA_DEBUG_EVENT)
+ zlog_debug("bfd_dst_register msg from client %s: length=%d",
+ zebra_route_string(client->proto), hdr->length);
+
+ _zebra_ptm_reroute(client, msg, ZEBRA_BFD_DEST_REGISTER);
+}
+
+void zebra_ptm_bfd_dst_deregister(ZAPI_HANDLER_ARGS)
+{
+ if (IS_ZEBRA_DEBUG_EVENT)
+ zlog_debug("bfd_dst_deregister msg from client %s: length=%d",
+ zebra_route_string(client->proto), hdr->length);
+
+ _zebra_ptm_reroute(client, msg, ZEBRA_BFD_DEST_DEREGISTER);
+}
+
+void zebra_ptm_bfd_client_register(ZAPI_HANDLER_ARGS)
+{
+ if (IS_ZEBRA_DEBUG_EVENT)
+ zlog_debug("bfd_client_register msg from client %s: length=%d",
+ zebra_route_string(client->proto), hdr->length);
+
+ _zebra_ptm_reroute(client, msg, ZEBRA_BFD_CLIENT_REGISTER);
+}
+
+void zebra_ptm_bfd_dst_replay(ZAPI_HANDLER_ARGS)
+{
+ struct stream *msgc;
+ size_t zmsglen, zhdrlen;
+ uint32_t cmd;
+
+ /*
+ * NOTE:
+ * Replay messages with HAVE_BFDD are meant to be replayed to
+ * the client daemons. These messages are composed and
+ * originated from the `bfdd` daemon.
+ */
+ if (IS_ZEBRA_DEBUG_EVENT)
+ zlog_debug("bfd_dst_update msg from client %s: length=%d",
+ zebra_route_string(client->proto), hdr->length);
+
+ /*
+ * Client messages must be re-routed, otherwise do the `bfdd`
+ * special treatment.
+ */
+ if (client->proto != ZEBRA_ROUTE_BFD) {
+ _zebra_ptm_reroute(client, msg, ZEBRA_BFD_DEST_REPLAY);
+ return;
+ }
+
+ /* Figure out if this is an DEST_UPDATE or DEST_REPLAY. */
+ if (stream_getl2(msg, &cmd) == false) {
+ zlog_err("%s: expected at least 4 bytes (command)", __func__);
+ return;
+ }
+
+ /*
+ * Don't modify message in the zebra API. In order to do that we
+ * need to allocate a new message stream and copy the message
+ * provided by zebra.
+ */
+ msgc = stream_new(ZEBRA_MAX_PACKET_SIZ);
+ if (msgc == NULL) {
+ zlog_warn("%s: not enough memory", __func__);
+ return;
+ }
+
+ /* Calculate our header size plus the message contents. */
+ if (cmd != ZEBRA_BFD_DEST_REPLAY) {
+ zhdrlen = ZEBRA_HEADER_SIZE;
+ zmsglen = msg->endp - msg->getp;
+ memcpy(msgc->data + zhdrlen, msg->data + msg->getp, zmsglen);
+
+ zclient_create_header(msgc, cmd, zvrf_id(zvrf));
+
+ msgc->getp = 0;
+ msgc->endp = zhdrlen + zmsglen;
+ } else
+ zclient_create_header(msgc, cmd, zvrf_id(zvrf));
+
+ /* Update the data pointers. */
+ stream_putw_at(msgc, 0, stream_get_endp(msgc));
+
+ zebra_ptm_send_clients(msgc);
+}
+
+/*
+ * Unused functions.
+ */
+void zebra_ptm_if_init(struct zebra_if *zifp __attribute__((__unused__)))
+{
+ /* NOTHING */
+}
+
+int zebra_ptm_get_enable_state(void)
+{
+ return 1;
+}
+
+void zebra_ptm_show_status(struct vty *vty __attribute__((__unused__)),
+ struct interface *ifp __attribute__((__unused__)))
+{
+ /* NOTHING */
+}
+
+void zebra_ptm_write(struct vty *vty __attribute__((__unused__)))
+{
+ /* NOTHING */
+}
+
+void zebra_ptm_if_write(struct vty *vty __attribute__((__unused__)),
+ struct zebra_if *zifp __attribute__((__unused__)))
+{
+ /* NOTHING */
+}
+void zebra_ptm_if_set_ptm_state(struct interface *i __attribute__((__unused__)),
+ struct zebra_if *zi __attribute__((__unused__)))
+{
+ /* NOTHING */
+}
+
+#endif /* HAVE_BFDD */
diff --git a/zebra/zebra_ptm.h b/zebra/zebra_ptm.h
index 0e55574a02..ada4f7b4f7 100644
--- a/zebra/zebra_ptm.h
+++ b/zebra/zebra_ptm.h
@@ -69,6 +69,9 @@ int zebra_ptm_get_enable_state(void);
void zebra_ptm_bfd_dst_register(ZAPI_HANDLER_ARGS);
void zebra_ptm_bfd_dst_deregister(ZAPI_HANDLER_ARGS);
void zebra_ptm_bfd_client_register(ZAPI_HANDLER_ARGS);
+#if HAVE_BFDD > 0
+void zebra_ptm_bfd_dst_replay(ZAPI_HANDLER_ARGS);
+#endif /* HAVE_BFDD */
void zebra_ptm_show_status(struct vty *vty, struct interface *ifp);
void zebra_ptm_if_init(struct zebra_if *zebra_ifp);
diff --git a/zebra/zebra_pw.c b/zebra/zebra_pw.c
index bf76f7e86b..c6db1463f2 100644
--- a/zebra/zebra_pw.c
+++ b/zebra/zebra_pw.c
@@ -308,15 +308,14 @@ void zebra_pw_exit(struct zebra_vrf *zvrf)
DEFUN_NOSH (pseudowire_if,
pseudowire_if_cmd,
- "[no] pseudowire IFNAME",
- NO_STR
+ "pseudowire IFNAME",
"Static pseudowire configuration\n"
"Pseudowire name\n")
{
struct zebra_vrf *zvrf;
struct zebra_pw *pw;
- int idx = 0;
const char *ifname;
+ int idx = 0;
zvrf = vrf_info_lookup(VRF_DEFAULT);
if (!zvrf)
@@ -324,19 +323,13 @@ DEFUN_NOSH (pseudowire_if,
argv_find(argv, argc, "IFNAME", &idx);
ifname = argv[idx]->arg;
+
pw = zebra_pw_find(zvrf, ifname);
if (pw && pw->protocol != ZEBRA_ROUTE_STATIC) {
vty_out(vty, "%% Pseudowire is not static\n");
return CMD_WARNING;
}
- if (argv_find(argv, argc, "no", &idx)) {
- if (!pw)
- return CMD_SUCCESS;
- zebra_pw_del(zvrf, pw);
- return CMD_SUCCESS;
- }
-
if (!pw)
pw = zebra_pw_add(zvrf, ifname, ZEBRA_ROUTE_STATIC, NULL);
VTY_PUSH_CONTEXT(PW_NODE, pw);
@@ -344,6 +337,37 @@ DEFUN_NOSH (pseudowire_if,
return CMD_SUCCESS;
}
+DEFUN (no_pseudowire_if,
+ no_pseudowire_if_cmd,
+ "no pseudowire IFNAME",
+ NO_STR
+ "Static pseudowire configuration\n"
+ "Pseudowire name\n")
+{
+ struct zebra_vrf *zvrf;
+ struct zebra_pw *pw;
+ const char *ifname;
+ int idx = 0;
+
+ zvrf = vrf_info_lookup(VRF_DEFAULT);
+ if (!zvrf)
+ return CMD_WARNING;
+
+ argv_find(argv, argc, "IFNAME", &idx);
+ ifname = argv[idx]->arg;
+
+ pw = zebra_pw_find(zvrf, ifname);
+ if (pw) {
+ if (pw->protocol != ZEBRA_ROUTE_STATIC) {
+ vty_out(vty, "%% Pseudowire is not static\n");
+ return CMD_WARNING;
+ }
+ zebra_pw_del(zvrf, pw);
+ }
+
+ return CMD_SUCCESS;
+}
+
DEFUN (pseudowire_labels,
pseudowire_labels_cmd,
"[no] mpls label local (16-1048575) remote (16-1048575)",
@@ -531,6 +555,7 @@ void zebra_pw_vty_init(void)
install_default(PW_NODE);
install_element(CONFIG_NODE, &pseudowire_if_cmd);
+ install_element(CONFIG_NODE, &no_pseudowire_if_cmd);
install_element(PW_NODE, &pseudowire_labels_cmd);
install_element(PW_NODE, &pseudowire_neighbor_cmd);
install_element(PW_NODE, &pseudowire_control_word_cmd);
diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c
index 18bd6b6cbe..b477cd4706 100644
--- a/zebra/zebra_rib.c
+++ b/zebra/zebra_rib.c
@@ -20,37 +20,38 @@
#include <zebra.h>
-#include "if.h"
-#include "prefix.h"
-#include "table.h"
-#include "memory.h"
-#include "zebra_memory.h"
#include "command.h"
+#include "if.h"
+#include "linklist.h"
#include "log.h"
#include "log_int.h"
-#include "sockunion.h"
-#include "linklist.h"
-#include "thread.h"
-#include "workqueue.h"
+#include "memory.h"
+#include "mpls.h"
+#include "nexthop.h"
+#include "prefix.h"
#include "prefix.h"
#include "routemap.h"
-#include "nexthop.h"
-#include "vrf.h"
-#include "mpls.h"
+#include "sockunion.h"
#include "srcdest_table.h"
+#include "table.h"
+#include "thread.h"
+#include "vrf.h"
+#include "workqueue.h"
+#include "zebra/connected.h"
+#include "zebra/debug.h"
+#include "zebra/interface.h"
+#include "zebra/redistribute.h"
#include "zebra/rib.h"
#include "zebra/rt.h"
+#include "zebra/zapi_msg.h"
+#include "zebra/zebra_errors.h"
+#include "zebra/zebra_memory.h"
#include "zebra/zebra_ns.h"
-#include "zebra/zebra_vrf.h"
-#include "zebra/redistribute.h"
-#include "zebra/zebra_routemap.h"
-#include "zebra/debug.h"
#include "zebra/zebra_rnh.h"
-#include "zebra/interface.h"
-#include "zebra/connected.h"
+#include "zebra/zebra_routemap.h"
+#include "zebra/zebra_vrf.h"
#include "zebra/zebra_vxlan.h"
-#include "zebra/zapi_msg.h"
DEFINE_HOOK(rib_update, (struct route_node * rn, const char *reason),
(rn, reason))
@@ -1125,10 +1126,14 @@ void rib_install_kernel(struct route_node *rn, struct route_entry *re,
hook_call(rib_update, rn, "installing in kernel");
switch (kernel_route_rib(rn, p, src_p, old, re)) {
case DP_REQUEST_QUEUED:
- zlog_err("No current known DataPlane interfaces can return this, please fix");
+ flog_err(
+ ZEBRA_ERR_DP_INVALID_RC,
+ "No current known DataPlane interfaces can return this, please fix");
break;
case DP_REQUEST_FAILURE:
- zlog_err("No current known Rib Install Failure cases, please fix");
+ flog_err(
+ ZEBRA_ERR_DP_INSTALL_FAIL,
+ "No current known Rib Install Failure cases, please fix");
break;
case DP_REQUEST_SUCCESS:
zvrf->installs++;
@@ -1161,10 +1166,14 @@ void rib_uninstall_kernel(struct route_node *rn, struct route_entry *re)
hook_call(rib_update, rn, "uninstalling from kernel");
switch (kernel_route_rib(rn, p, src_p, re, NULL)) {
case DP_REQUEST_QUEUED:
- zlog_err("No current known DataPlane interfaces can return this, please fix");
+ flog_err(
+ ZEBRA_ERR_DP_INVALID_RC,
+ "No current known DataPlane interfaces can return this, please fix");
break;
case DP_REQUEST_FAILURE:
- zlog_err("No current known RIB Install Failure cases, please fix");
+ flog_err(
+ ZEBRA_ERR_DP_INSTALL_FAIL,
+ "No current known RIB Install Failure cases, please fix");
break;
case DP_REQUEST_SUCCESS:
if (zvrf)
@@ -1936,7 +1945,8 @@ void rib_queue_add(struct route_node *rn)
}
if (zebrad.ribq == NULL) {
- zlog_err("%s: work_queue does not exist!", __func__);
+ flog_err(ZEBRA_ERR_WQ_NONEXISTENT,
+ "%s: work_queue does not exist!", __func__);
return;
}
@@ -1965,7 +1975,6 @@ static struct meta_queue *meta_queue_new(void)
unsigned i;
new = XCALLOC(MTYPE_WORK_QUEUE, sizeof(struct meta_queue));
- assert(new);
for (i = 0; i < MQ_SIZE; i++) {
new->subq[i] = list_new();
@@ -1992,7 +2001,8 @@ static void rib_queue_init(struct zebra_t *zebra)
if (!(zebra->ribq =
work_queue_new(zebra->master, "route_node processing"))) {
- zlog_err("%s: could not initialise work queue!", __func__);
+ flog_err(ZEBRA_ERR_WQ_NONEXISTENT,
+ "%s: could not initialise work queue!", __func__);
return;
}
@@ -2005,7 +2015,8 @@ static void rib_queue_init(struct zebra_t *zebra)
zebra->ribq->spec.hold = ZEBRA_RIB_PROCESS_HOLD_TIME;
if (!(zebra->mq = meta_queue_new())) {
- zlog_err("%s: could not initialise meta queue!", __func__);
+ flog_err(ZEBRA_ERR_WQ_NONEXISTENT,
+ "%s: could not initialise meta queue!", __func__);
return;
}
return;
@@ -2232,8 +2243,9 @@ void rib_lookup_and_dump(struct prefix_ipv4 *p, vrf_id_t vrf_id)
/* Lookup table. */
table = zebra_vrf_table(AFI_IP, SAFI_UNICAST, vrf_id);
if (!table) {
- zlog_err("%s:%u zebra_vrf_table() returned NULL",
- __func__, vrf_id);
+ flog_err(ZEBRA_ERR_TABLE_LOOKUP_FAILED,
+ "%s:%u zebra_vrf_table() returned NULL", __func__,
+ vrf_id);
return;
}
@@ -2279,8 +2291,9 @@ void rib_lookup_and_pushup(struct prefix_ipv4 *p, vrf_id_t vrf_id)
rib_dest_t *dest;
if (NULL == (table = zebra_vrf_table(AFI_IP, SAFI_UNICAST, vrf_id))) {
- zlog_err("%s:%u zebra_vrf_table() returned NULL",
- __func__, vrf_id);
+ flog_err(ZEBRA_ERR_TABLE_LOOKUP_FAILED,
+ "%s:%u zebra_vrf_table() returned NULL", __func__,
+ vrf_id);
return;
}
@@ -2355,7 +2368,6 @@ int rib_add_multipath(afi_t afi, safi_t safi, struct prefix *p,
/* Lookup route node.*/
rn = srcdest_rnode_get(table, p, src_p);
- zlog_debug("Distance: %d", re->distance);
/*
* If same type of route are installed, treat it as a implicit
* withdraw.
@@ -2387,7 +2399,6 @@ int rib_add_multipath(afi_t afi, safi_t safi, struct prefix *p,
break;
}
- zlog_debug("same: %p distance: %d", same, same ? same->distance : -1);
/* If this route is kernel route, set FIB flag to the route. */
if (RIB_SYSTEM_ROUTE(re))
for (nexthop = re->ng.nexthop; nexthop; nexthop = nexthop->next)
diff --git a/zebra/zebra_rnh.c b/zebra/zebra_rnh.c
index 453f08a183..156600c105 100644
--- a/zebra/zebra_rnh.c
+++ b/zebra/zebra_rnh.c
@@ -47,6 +47,7 @@
#include "zebra/zebra_routemap.h"
#include "zebra/interface.h"
#include "zebra/zebra_memory.h"
+#include "zebra/zebra_errors.h"
static void free_state(vrf_id_t vrf_id, struct route_entry *re,
struct route_node *rn);
@@ -857,8 +858,9 @@ static int send_client(struct rnh *rnh, struct zserv *client, rnh_type_t type,
stream_put(s, &rn->p.u.prefix6, IPV6_MAX_BYTELEN);
break;
default:
- zlog_err("%s: Unknown family (%d) notification attempted\n",
- __FUNCTION__, rn->p.family);
+ flog_err(ZEBRA_ERR_RNH_UNKNOWN_FAMILY,
+ "%s: Unknown family (%d) notification attempted\n",
+ __FUNCTION__, rn->p.family);
break;
}
if (re) {
diff --git a/zebra/zebra_routemap.c b/zebra/zebra_routemap.c
index 0b48e87b1b..fc17ee3491 100644
--- a/zebra/zebra_routemap.c
+++ b/zebra/zebra_routemap.c
@@ -1098,9 +1098,6 @@ static void *route_match_address_prefix_len_compile(const char *arg)
prefix_len = XMALLOC(MTYPE_ROUTE_MAP_COMPILED, sizeof(uint32_t));
- if (!prefix_len)
- return prefix_len;
-
*prefix_len = tmpval;
return prefix_len;
}
diff --git a/zebra/zebra_vxlan.c b/zebra/zebra_vxlan.c
index 4955f3f77c..d979be4a36 100644
--- a/zebra/zebra_vxlan.c
+++ b/zebra/zebra_vxlan.c
@@ -22,33 +22,34 @@
#include <zebra.h>
+#include "hash.h"
#include "if.h"
-#include "prefix.h"
-#include "table.h"
-#include "memory.h"
-#include "log.h"
+#include "jhash.h"
#include "linklist.h"
+#include "log.h"
+#include "memory.h"
+#include "prefix.h"
#include "stream.h"
-#include "hash.h"
-#include "jhash.h"
+#include "table.h"
#include "vlan.h"
#include "vxlan.h"
#ifdef GNU_LINUX
#include <linux/neighbour.h>
#endif
+#include "zebra/debug.h"
+#include "zebra/interface.h"
#include "zebra/rib.h"
#include "zebra/rt.h"
+#include "zebra/rt_netlink.h"
+#include "zebra/zebra_errors.h"
+#include "zebra/zebra_l2.h"
+#include "zebra/zebra_memory.h"
#include "zebra/zebra_ns.h"
-#include "zebra/zserv.h"
-#include "zebra/debug.h"
-#include "zebra/interface.h"
#include "zebra/zebra_vrf.h"
-#include "zebra/rt_netlink.h"
-#include "zebra/zebra_vxlan_private.h"
#include "zebra/zebra_vxlan.h"
-#include "zebra/zebra_memory.h"
-#include "zebra/zebra_l2.h"
+#include "zebra/zebra_vxlan_private.h"
+#include "zebra/zserv.h"
DEFINE_MTYPE_STATIC(ZEBRA, HOST_PREFIX, "host prefix");
DEFINE_MTYPE_STATIC(ZEBRA, ZVNI, "VNI hash");
@@ -1492,14 +1493,13 @@ static void zvni_process_neigh_on_local_mac_del(zebra_vni_t *zvni,
zvni_neigh_send_del_to_client(zvni->vni, &n->ip,
&n->emac, 0);
}
- } else if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_REMOTE)) {
- if (IS_ZEBRA_DEBUG_VXLAN)
- zlog_err(
- "local MAC %s getting deleted on VNI %u has remote neigh %s",
- prefix_mac2str(&n->emac, buf,
- sizeof(buf)),
- zvni->vni,
- ipaddr2str(&n->ip, buf2, sizeof(buf2)));
+ } else if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_REMOTE)
+ && IS_ZEBRA_DEBUG_VXLAN) {
+ zlog_debug(
+ "local MAC %s getting deleted on VNI %u has remote neigh %s",
+ prefix_mac2str(&n->emac, buf, sizeof(buf)),
+ zvni->vni,
+ ipaddr2str(&n->ip, buf2, sizeof(buf2)));
}
}
}
@@ -1543,14 +1543,13 @@ static void zvni_process_neigh_on_remote_mac_del(zebra_vni_t *zvni,
char buf2[INET6_ADDRSTRLEN];
for (ALL_LIST_ELEMENTS_RO(zmac->neigh_list, node, n)) {
- if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_LOCAL)) {
- if (IS_ZEBRA_DEBUG_VXLAN)
- zlog_err(
- "remote MAC %s getting deleted on VNI %u has local neigh %s",
- prefix_mac2str(&n->emac, buf,
- sizeof(buf)),
- zvni->vni,
- ipaddr2str(&n->ip, buf2, sizeof(buf2)));
+ if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_LOCAL)
+ && IS_ZEBRA_DEBUG_VXLAN) {
+ zlog_debug(
+ "remote MAC %s getting deleted on VNI %u has local neigh %s",
+ prefix_mac2str(&n->emac, buf, sizeof(buf)),
+ zvni->vni,
+ ipaddr2str(&n->ip, buf2, sizeof(buf2)));
}
}
}
@@ -1628,8 +1627,8 @@ static int zvni_neigh_uninstall(zebra_vni_t *zvni, zebra_neigh_t *n)
return 0;
if (!zvni->vxlan_if) {
- zlog_err("VNI %u hash %p couldn't be uninstalled - no intf",
- zvni->vni, zvni);
+ zlog_warn("VNI %u hash %p couldn't be uninstalled - no intf",
+ zvni->vni, zvni);
return -1;
}
@@ -1803,9 +1802,10 @@ static int zvni_gw_macip_add(struct interface *ifp, zebra_vni_t *zvni,
if (!mac) {
mac = zvni_mac_add(zvni, macaddr);
if (!mac) {
- zlog_err("Failed to add MAC %s intf %s(%u) VID %u",
- prefix_mac2str(macaddr, buf, sizeof(buf)),
- ifp->name, ifp->ifindex, vxl->access_vlan);
+ flog_err(ZEBRA_ERR_MAC_ADD_FAILED,
+ "Failed to add MAC %s intf %s(%u) VID %u",
+ prefix_mac2str(macaddr, buf, sizeof(buf)),
+ ifp->name, ifp->ifindex, vxl->access_vlan);
return -1;
}
}
@@ -1822,7 +1822,8 @@ static int zvni_gw_macip_add(struct interface *ifp, zebra_vni_t *zvni,
if (!n) {
n = zvni_neigh_add(zvni, ip, macaddr);
if (!n) {
- zlog_err(
+ flog_err(
+ ZEBRA_ERR_MAC_ADD_FAILED,
"Failed to add neighbor %s MAC %s intf %s(%u) -> VNI %u",
ipaddr2str(ip, buf2, sizeof(buf2)),
prefix_mac2str(macaddr, buf, sizeof(buf)),
@@ -1875,9 +1876,9 @@ static int zvni_gw_macip_del(struct interface *ifp, zebra_vni_t *zvni,
/* mac entry should be present */
mac = zvni_mac_lookup(zvni, &n->emac);
if (!mac) {
- zlog_err("MAC %s doesnt exists for neigh %s on VNI %u",
- prefix_mac2str(&n->emac, buf1, sizeof(buf1)),
- ipaddr2str(ip, buf2, sizeof(buf2)), zvni->vni);
+ zlog_warn("MAC %s doesnt exists for neigh %s on VNI %u",
+ prefix_mac2str(&n->emac, buf1, sizeof(buf1)),
+ ipaddr2str(ip, buf2, sizeof(buf2)), zvni->vni);
return -1;
}
@@ -2085,7 +2086,8 @@ static int zvni_local_neigh_update(zebra_vni_t *zvni,
/* New neighbor - create */
n = zvni_neigh_add(zvni, ip, macaddr);
if (!n) {
- zlog_err(
+ flog_err(
+ ZEBRA_ERR_MAC_ADD_FAILED,
"Failed to add neighbor %s MAC %s intf %s(%u) -> VNI %u",
ipaddr2str(ip, buf2, sizeof(buf2)),
prefix_mac2str(macaddr, buf, sizeof(buf)),
@@ -2156,10 +2158,11 @@ static int zvni_remote_neigh_update(zebra_vni_t *zvni,
*/
zmac = zvni_mac_lookup(zvni, macaddr);
if (!zmac || !CHECK_FLAG(zmac->flags, ZEBRA_MAC_REMOTE)) {
- zlog_err("Ignore remote neigh %s (MAC %s) on L2-VNI %u - MAC unknown or local",
- ipaddr2str(&n->ip, buf2, sizeof(buf2)),
- prefix_mac2str(macaddr, buf, sizeof(buf)),
- zvni->vni);
+ zlog_warn(
+ "Ignore remote neigh %s (MAC %s) on L2-VNI %u - MAC unknown or local",
+ ipaddr2str(&n->ip, buf2, sizeof(buf2)),
+ prefix_mac2str(macaddr, buf, sizeof(buf)),
+ zvni->vni);
return -1;
}
@@ -2588,8 +2591,8 @@ static int zvni_mac_uninstall(zebra_vni_t *zvni, zebra_mac_t *mac, int local)
return 0;
if (!zvni->vxlan_if) {
- zlog_err("VNI %u hash %p couldn't be uninstalled - no intf",
- zvni->vni, zvni);
+ zlog_warn("VNI %u hash %p couldn't be uninstalled - no intf",
+ zvni->vni, zvni);
return -1;
}
@@ -2918,7 +2921,7 @@ static void zvni_build_hash_table()
/* VNI hash entry is not expected to exist. */
zvni = zvni_lookup(vni);
if (zvni) {
- zlog_err(
+ zlog_warn(
"VNI hash already present for IF %s(%u) L2-VNI %u",
ifp->name, ifp->ifindex, vni);
continue;
@@ -2926,7 +2929,7 @@ static void zvni_build_hash_table()
zvni = zvni_add(vni);
if (!zvni) {
- zlog_err(
+ zlog_warn(
"Failed to add VNI hash, IF %s(%u) L2-VNI %u",
ifp->name, ifp->ifindex, vni);
return;
@@ -2985,10 +2988,6 @@ static zebra_vtep_t *zvni_vtep_add(zebra_vni_t *zvni, struct in_addr *vtep_ip)
zebra_vtep_t *zvtep;
zvtep = XCALLOC(MTYPE_ZVNI_VTEP, sizeof(zebra_vtep_t));
- if (!zvtep) {
- zlog_err("Failed to alloc VTEP entry, VNI %u", zvni->vni);
- return NULL;
- }
zvtep->vtep_ip = *vtep_ip;
@@ -3053,8 +3052,8 @@ static int zvni_vtep_install(zebra_vni_t *zvni, struct in_addr *vtep_ip)
static int zvni_vtep_uninstall(zebra_vni_t *zvni, struct in_addr *vtep_ip)
{
if (!zvni->vxlan_if) {
- zlog_err("VNI %u hash %p couldn't be uninstalled - no intf",
- zvni->vni, zvni);
+ zlog_warn("VNI %u hash %p couldn't be uninstalled - no intf",
+ zvni->vni, zvni);
return -1;
}
@@ -3248,7 +3247,7 @@ static int zl3vni_rmac_uninstall(zebra_l3vni_t *zl3vni, zebra_mac_t *zrmac)
return 0;
if (!zl3vni->vxlan_if) {
- zlog_err(
+ zlog_warn(
"RMAC %s on L3-VNI %u hash %p couldn't be uninstalled - no vxlan_if",
prefix_mac2str(&zrmac->macaddr, buf, sizeof(buf)),
zl3vni->vni, zl3vni);
@@ -3904,8 +3903,9 @@ static int zebra_vxlan_handle_vni_transition(struct zebra_vrf *zvrf, vni_t vni,
/* Delete the hash entry. */
if (zvni_del(zvni)) {
- zlog_err("Failed to del VNI hash %p, VNI %u", zvni,
- zvni->vni);
+ flog_err(ZEBRA_ERR_VNI_DEL_FAILED,
+ "Failed to del VNI hash %p, VNI %u", zvni,
+ zvni->vni);
return -1;
}
} else {
@@ -4924,7 +4924,7 @@ int zebra_vxlan_handle_kernel_neigh_del(struct interface *ifp,
return 0;
if (!zvni->vxlan_if) {
- zlog_err(
+ zlog_warn(
"VNI %u hash %p doesn't have intf upon local neighbor DEL",
zvni->vni, zvni);
return -1;
@@ -4943,7 +4943,7 @@ int zebra_vxlan_handle_kernel_neigh_del(struct interface *ifp,
zmac = zvni_mac_lookup(zvni, &n->emac);
if (!zmac) {
if (IS_ZEBRA_DEBUG_VXLAN)
- zlog_err(
+ zlog_warn(
"Trying to del a neigh %s without a mac %s on VNI %u",
ipaddr2str(ip, buf, sizeof(buf)),
prefix_mac2str(&n->emac, buf2, sizeof(buf2)),
@@ -5090,7 +5090,7 @@ void zebra_vxlan_remote_macip_del(ZAPI_HANDLER_ARGS)
}
ifp = zvni->vxlan_if;
if (!ifp) {
- zlog_err(
+ zlog_warn(
"VNI %u hash %p doesn't have intf upon remote MACIP DEL",
vni, zvni);
continue;
@@ -5117,9 +5117,9 @@ void zebra_vxlan_remote_macip_del(ZAPI_HANDLER_ARGS)
n = zvni_neigh_lookup(zvni, &ip);
if (n && !mac) {
- zlog_err("Failed to locate MAC %s for neigh %s VNI %u",
- prefix_mac2str(&macaddr, buf, sizeof(buf)),
- ipaddr2str(&ip, buf1, sizeof(buf1)), vni);
+ zlog_warn("Failed to locate MAC %s for neigh %s VNI %u",
+ prefix_mac2str(&macaddr, buf, sizeof(buf)),
+ ipaddr2str(&ip, buf1, sizeof(buf1)), vni);
continue;
}
@@ -5133,7 +5133,7 @@ void zebra_vxlan_remote_macip_del(ZAPI_HANDLER_ARGS)
/* Ignore the delete if this mac is a gateway mac-ip */
if (mac && CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)
&& CHECK_FLAG(mac->flags, ZEBRA_MAC_DEF_GW)) {
- zlog_err(
+ zlog_warn(
"%u: Ignore Del for MAC %s neigh %s on VNI %u as it is configured as a default gateway",
zvrf_id(zvrf),
prefix_mac2str(&macaddr, buf, sizeof(buf)),
@@ -5252,14 +5252,14 @@ void zebra_vxlan_remote_macip_add(ZAPI_HANDLER_ARGS)
/* Locate VNI hash entry - expected to exist. */
zvni = zvni_lookup(vni);
if (!zvni) {
- zlog_err(
+ zlog_warn(
"Failed to locate VNI hash upon remote MACIP ADD, VNI %u",
vni);
continue;
}
ifp = zvni->vxlan_if;
if (!ifp) {
- zlog_err(
+ zlog_warn(
"VNI %u hash %p doesn't have intf upon remote MACIP add",
vni, zvni);
continue;
@@ -5279,7 +5279,8 @@ void zebra_vxlan_remote_macip_add(ZAPI_HANDLER_ARGS)
zvtep = zvni_vtep_find(zvni, &vtep_ip);
if (!zvtep) {
if (zvni_vtep_add(zvni, &vtep_ip) == NULL) {
- zlog_err(
+ flog_err(
+ ZEBRA_ERR_VTEP_ADD_FAILED,
"Failed to add remote VTEP, VNI %u zvni %p",
vni, zvni);
continue;
@@ -5552,8 +5553,8 @@ int zebra_vxlan_local_mac_del(struct interface *ifp, struct interface *br_if,
if (!zvni)
return 0;
if (!zvni->vxlan_if) {
- zlog_err("VNI %u hash %p doesn't have intf upon local MAC DEL",
- zvni->vni, zvni);
+ zlog_warn("VNI %u hash %p doesn't have intf upon local MAC DEL",
+ zvni->vni, zvni);
return -1;
}
@@ -5620,8 +5621,8 @@ int zebra_vxlan_local_mac_add_update(struct interface *ifp,
}
if (!zvni->vxlan_if) {
- zlog_err("VNI %u hash %p doesn't have intf upon local MAC ADD",
- zvni->vni, zvni);
+ zlog_warn("VNI %u hash %p doesn't have intf upon local MAC ADD",
+ zvni->vni, zvni);
return -1;
}
@@ -5686,9 +5687,10 @@ int zebra_vxlan_local_mac_add_update(struct interface *ifp,
if (!mac) {
mac = zvni_mac_add(zvni, macaddr);
if (!mac) {
- zlog_err("Failed to add MAC %s intf %s(%u) VID %u",
- prefix_mac2str(macaddr, buf, sizeof(buf)),
- ifp->name, ifp->ifindex, vid);
+ flog_err(ZEBRA_ERR_MAC_ADD_FAILED,
+ "Failed to add MAC %s intf %s(%u) VID %u",
+ prefix_mac2str(macaddr, buf, sizeof(buf)),
+ ifp->name, ifp->ifindex, vid);
return -1;
}
}
@@ -5738,8 +5740,8 @@ void zebra_vxlan_remote_vtep_del(ZAPI_HANDLER_ARGS)
}
if (zvrf_id(zvrf) != VRF_DEFAULT) {
- zlog_err("Recv MACIP DEL for non-default VRF %u",
- zvrf_id(zvrf));
+ zlog_warn("Recv MACIP DEL for non-default VRF %u",
+ zvrf_id(zvrf));
return;
}
@@ -5770,7 +5772,7 @@ void zebra_vxlan_remote_vtep_del(ZAPI_HANDLER_ARGS)
ifp = zvni->vxlan_if;
if (!ifp) {
- zlog_err(
+ zlog_warn(
"VNI %u hash %p doesn't have intf upon remote VTEP DEL",
zvni->vni, zvni);
continue;
@@ -5822,8 +5824,8 @@ void zebra_vxlan_remote_vtep_add(ZAPI_HANDLER_ARGS)
}
if (zvrf_id(zvrf) != VRF_DEFAULT) {
- zlog_err("Recv MACIP ADD for non-default VRF %u",
- zvrf_id(zvrf));
+ zlog_warn("Recv MACIP ADD for non-default VRF %u",
+ zvrf_id(zvrf));
return;
}
@@ -5844,7 +5846,8 @@ void zebra_vxlan_remote_vtep_add(ZAPI_HANDLER_ARGS)
/* Locate VNI hash entry - expected to exist. */
zvni = zvni_lookup(vni);
if (!zvni) {
- zlog_err(
+ flog_err(
+ ZEBRA_ERR_VTEP_ADD_FAILED,
"Failed to locate VNI hash upon remote VTEP ADD, VNI %u",
vni);
continue;
@@ -5852,7 +5855,8 @@ void zebra_vxlan_remote_vtep_add(ZAPI_HANDLER_ARGS)
ifp = zvni->vxlan_if;
if (!ifp) {
- zlog_err(
+ flog_err(
+ ZEBRA_ERR_VTEP_ADD_FAILED,
"VNI %u hash %p doesn't have intf upon remote VTEP ADD",
zvni->vni, zvni);
continue;
@@ -5870,8 +5874,9 @@ void zebra_vxlan_remote_vtep_add(ZAPI_HANDLER_ARGS)
continue;
if (zvni_vtep_add(zvni, &vtep_ip) == NULL) {
- zlog_err("Failed to add remote VTEP, VNI %u zvni %p",
- vni, zvni);
+ flog_err(ZEBRA_ERR_VTEP_ADD_FAILED,
+ "Failed to add remote VTEP, VNI %u zvni %p",
+ vni, zvni);
continue;
}
@@ -5922,8 +5927,8 @@ int zebra_vxlan_add_del_gw_macip(struct interface *ifp, struct prefix *p,
svi_if = if_lookup_by_index_per_ns(zebra_ns_lookup(NS_DEFAULT),
ifp_zif->link_ifindex);
if (!svi_if) {
- zlog_err("MACVLAN %s(%u) without link information",
- ifp->name, ifp->ifindex);
+ zlog_warn("MACVLAN %s(%u) without link information",
+ ifp->name, ifp->ifindex);
return -1;
}
@@ -5970,8 +5975,8 @@ int zebra_vxlan_add_del_gw_macip(struct interface *ifp, struct prefix *p,
return 0;
if (!zvni->vxlan_if) {
- zlog_err("VNI %u hash %p doesn't have intf upon MACVLAN up",
- zvni->vni, zvni);
+ zlog_warn("VNI %u hash %p doesn't have intf upon MACVLAN up",
+ zvni->vni, zvni);
return -1;
}
@@ -6067,8 +6072,9 @@ int zebra_vxlan_svi_up(struct interface *ifp, struct interface *link_if)
return 0;
if (!zvni->vxlan_if) {
- zlog_err("VNI %u hash %p doesn't have intf upon SVI up",
- zvni->vni, zvni);
+ zlog_warn(
+ "VNI %u hash %p doesn't have intf upon SVI up",
+ zvni->vni, zvni);
return -1;
}
@@ -6129,7 +6135,7 @@ int zebra_vxlan_if_down(struct interface *ifp)
/* Locate hash entry; it is expected to exist. */
zvni = zvni_lookup(vni);
if (!zvni) {
- zlog_err(
+ zlog_warn(
"Failed to locate VNI hash at DOWN, IF %s(%u) VNI %u",
ifp->name, ifp->ifindex, vni);
return -1;
@@ -6195,7 +6201,7 @@ int zebra_vxlan_if_up(struct interface *ifp)
/* Locate hash entry; it is expected to exist. */
zvni = zvni_lookup(vni);
if (!zvni) {
- zlog_err(
+ zlog_warn(
"Failed to locate VNI hash at UP, IF %s(%u) VNI %u",
ifp->name, ifp->ifindex, vni);
return -1;
@@ -6266,7 +6272,7 @@ int zebra_vxlan_if_del(struct interface *ifp)
/* Locate hash entry; it is expected to exist. */
zvni = zvni_lookup(vni);
if (!zvni) {
- zlog_err(
+ zlog_warn(
"Failed to locate VNI hash at del, IF %s(%u) VNI %u",
ifp->name, ifp->ifindex, vni);
return 0;
@@ -6289,8 +6295,9 @@ int zebra_vxlan_if_del(struct interface *ifp)
/* Delete the hash entry. */
if (zvni_del(zvni)) {
- zlog_err("Failed to del VNI hash %p, IF %s(%u) VNI %u",
- zvni, ifp->name, ifp->ifindex, zvni->vni);
+ flog_err(ZEBRA_ERR_VNI_DEL_FAILED,
+ "Failed to del VNI hash %p, IF %s(%u) VNI %u",
+ zvni, ifp->name, ifp->ifindex, zvni->vni);
return -1;
}
}
@@ -6376,7 +6383,7 @@ int zebra_vxlan_if_update(struct interface *ifp, uint16_t chgflags)
/* Update VNI hash. */
zvni = zvni_lookup(vni);
if (!zvni) {
- zlog_err(
+ zlog_warn(
"Failed to find L2-VNI hash on update, IF %s(%u) VNI %u",
ifp->name, ifp->ifindex, vni);
return -1;
@@ -6504,7 +6511,8 @@ int zebra_vxlan_if_add(struct interface *ifp)
if (!zvni) {
zvni = zvni_add(vni);
if (!zvni) {
- zlog_err(
+ flog_err(
+ ZEBRA_ERR_VNI_ADD_FAILED,
"Failed to add VNI hash, IF %s(%u) VNI %u",
ifp->name, ifp->ifindex, vni);
return -1;
@@ -6707,8 +6715,8 @@ void zebra_vxlan_advertise_subnet(ZAPI_HANDLER_ARGS)
struct interface *vlan_if = NULL;
if (zvrf_id(zvrf) != VRF_DEFAULT) {
- zlog_err("EVPN GW-MACIP Adv for non-default VRF %u",
- zvrf_id(zvrf));
+ zlog_warn("EVPN GW-MACIP Adv for non-default VRF %u",
+ zvrf_id(zvrf));
return;
}
@@ -6770,8 +6778,8 @@ void zebra_vxlan_advertise_gw_macip(ZAPI_HANDLER_ARGS)
struct interface *ifp = NULL;
if (zvrf_id(zvrf) != VRF_DEFAULT) {
- zlog_err("EVPN GW-MACIP Adv for non-default VRF %u",
- zvrf_id(zvrf));
+ zlog_warn("EVPN GW-MACIP Adv for non-default VRF %u",
+ zvrf_id(zvrf));
return;
}
@@ -6875,7 +6883,7 @@ void zebra_vxlan_advertise_all_vni(ZAPI_HANDLER_ARGS)
struct zebra_ns *zns = NULL;
if (zvrf_id(zvrf) != VRF_DEFAULT) {
- zlog_err("EVPN VNI Adv for non-default VRF %u", zvrf_id(zvrf));
+ zlog_warn("EVPN VNI Adv for non-default VRF %u", zvrf_id(zvrf));
return;
}
diff --git a/zebra/zserv.c b/zebra/zserv.c
index f76c2fabd6..174e010743 100644
--- a/zebra/zserv.c
+++ b/zebra/zserv.c
@@ -54,6 +54,7 @@
#include "lib/zclient.h" /* for zmsghdr, ZEBRA_HEADER_SIZE, ZEBRA... */
#include "lib/frr_pthread.h" /* for frr_pthread_new, frr_pthread_stop... */
#include "lib/frratomic.h" /* for atomic_load_explicit, atomic_stor... */
+#include "lib/lib_errors.h" /* for generic ferr ids */
#include "zebra/debug.h" /* for various debugging macros */
#include "zebra/rib.h" /* for rib_score_proto */
@@ -786,15 +787,14 @@ void zserv_start(char *path)
unlink(suna->sun_path);
}
- zserv_privs.change(ZPRIVS_RAISE);
- setsockopt_so_recvbuf(zebrad.sock, 1048576);
- setsockopt_so_sendbuf(zebrad.sock, 1048576);
- zserv_privs.change(ZPRIVS_LOWER);
-
- if (sa.ss_family != AF_UNIX && zserv_privs.change(ZPRIVS_RAISE))
- zlog_err("Can't raise privileges");
+ frr_elevate_privs(&zserv_privs) {
+ setsockopt_so_recvbuf(zebrad.sock, 1048576);
+ setsockopt_so_sendbuf(zebrad.sock, 1048576);
+ }
- ret = bind(zebrad.sock, (struct sockaddr *)&sa, sa_len);
+ frr_elevate_privs((sa.ss_family != AF_UNIX) ? &zserv_privs : NULL) {
+ ret = bind(zebrad.sock, (struct sockaddr *)&sa, sa_len);
+ }
if (ret < 0) {
zlog_warn("Can't bind zserv socket on %s: %s", path,
safe_strerror(errno));
@@ -804,8 +804,6 @@ void zserv_start(char *path)
zebrad.sock = -1;
return;
}
- if (sa.ss_family != AF_UNIX && zserv_privs.change(ZPRIVS_LOWER))
- zlog_err("Can't lower privileges");
ret = listen(zebrad.sock, 5);
if (ret < 0) {