summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bgpd/bgp_aspath.c2
-rw-r--r--bgpd/bgp_attr.c3
-rw-r--r--bgpd/bgp_clist.c5
-rw-r--r--bgpd/bgp_io.c7
-rw-r--r--bgpd/bgp_nexthop.c4
-rw-r--r--bgpd/bgp_route.c12
-rw-r--r--bgpd/bgp_updgrp_packet.c2
-rw-r--r--bgpd/bgp_vpn.c2
-rw-r--r--bgpd/bgp_vty.c1
-rw-r--r--bgpd/rfapi/bgp_rfapi_cfg.c3
-rw-r--r--doc/user/basic.rst12
-rw-r--r--eigrpd/eigrp_fsm.c8
-rw-r--r--eigrpd/eigrp_interface.c3
-rw-r--r--eigrpd/eigrp_topology.c14
-rw-r--r--include/linux/netlink.h247
-rw-r--r--include/subdir.am1
-rw-r--r--isisd/isis_te.c2
-rw-r--r--isisd/isisd.c2
-rw-r--r--ldpd/ldp_debug.c3
-rw-r--r--ldpd/ldp_vty_conf.c51
-rw-r--r--ldpd/ldpd.c19
-rw-r--r--lib/command.c33
-rw-r--r--lib/command.h1
-rw-r--r--lib/command_match.c1
-rw-r--r--lib/imsg.c5
-rw-r--r--lib/libfrr.c47
-rw-r--r--lib/libfrr.h5
-rw-r--r--lib/plist.c5
-rw-r--r--lib/sockopt.c9
-rw-r--r--lib/sockunion.c3
-rw-r--r--lib/vty.c10
-rw-r--r--lib/vty.h2
-rw-r--r--ospf6d/ospf6_flood.c1
-rw-r--r--ospf6d/ospf6_spf.c8
-rw-r--r--ospfd/ospf_apiserver.c2
-rw-r--r--ospfd/ospf_vty.c8
-rw-r--r--pimd/mtracebis.c2
-rw-r--r--pimd/pim_cmd.c4
-rw-r--r--pimd/pim_pim.c2
-rw-r--r--tests/Makefile.am5
-rw-r--r--tools/start-stop-daemon.c6
-rw-r--r--vtysh/vtysh.c5
-rw-r--r--zebra/kernel_netlink.c117
-rw-r--r--zebra/zebra_netns_notify.c1
44 files changed, 610 insertions, 75 deletions
diff --git a/bgpd/bgp_aspath.c b/bgpd/bgp_aspath.c
index e02617691f..05e67baa8a 100644
--- a/bgpd/bgp_aspath.c
+++ b/bgpd/bgp_aspath.c
@@ -1632,7 +1632,7 @@ struct aspath *aspath_reconcile_as4(struct aspath *aspath,
struct aspath *newpath = NULL, *mergedpath;
int hops, cpasns = 0;
- if (!aspath)
+ if (!aspath || !as4path)
return NULL;
seg = aspath->segments;
diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c
index 2c52b57b36..6596e7cfa2 100644
--- a/bgpd/bgp_attr.c
+++ b/bgpd/bgp_attr.c
@@ -1513,6 +1513,9 @@ bgp_attr_munge_as4_attrs(struct peer *const peer, struct attr *const attr,
if (!ignore_as4_path
&& (attr->flag & (ATTR_FLAG_BIT(BGP_ATTR_AS4_PATH)))) {
newpath = aspath_reconcile_as4(attr->aspath, as4_path);
+ if (!newpath)
+ return BGP_ATTR_PARSE_ERROR;
+
aspath_unintern(&attr->aspath);
attr->aspath = aspath_intern(newpath);
}
diff --git a/bgpd/bgp_clist.c b/bgpd/bgp_clist.c
index 7cf1477549..0ffbe174ed 100644
--- a/bgpd/bgp_clist.c
+++ b/bgpd/bgp_clist.c
@@ -1054,6 +1054,9 @@ int extcommunity_list_set(struct community_list_handler *ch, const char *name,
struct ecommunity *ecom = NULL;
regex_t *regex = NULL;
+ if (str == NULL)
+ return COMMUNITY_LIST_ERR_MALFORMED_VAL;
+
entry = NULL;
/* Get community list. */
@@ -1089,7 +1092,7 @@ int extcommunity_list_set(struct community_list_handler *ch, const char *name,
entry = community_entry_new();
entry->direct = direct;
entry->style = style;
- entry->any = (str ? 0 : 1);
+ entry->any = 0;
if (ecom)
entry->config = ecommunity_ecom2str(
ecom, ECOMMUNITY_FORMAT_COMMUNITY_LIST, 0);
diff --git a/bgpd/bgp_io.c b/bgpd/bgp_io.c
index 69c92e829c..c8d5b1daa1 100644
--- a/bgpd/bgp_io.c
+++ b/bgpd/bgp_io.c
@@ -174,7 +174,6 @@ static int bgp_process_reads(struct thread *thread)
bool more = true; // whether we got more data
bool fatal = false; // whether fatal error occurred
bool added_pkt = false; // whether we pushed onto ->ibuf
- bool header_valid = true; // whether header is valid
/* clang-format on */
peer = THREAD_ARG(thread);
@@ -214,10 +213,8 @@ static int bgp_process_reads(struct thread *thread)
if (ringbuf_remain(ibw) < BGP_HEADER_SIZE)
break;
- /* validate header */
- header_valid = validate_header(peer);
-
- if (!header_valid) {
+ /* check that header is valid */
+ if (!validate_header(peer)) {
fatal = true;
break;
}
diff --git a/bgpd/bgp_nexthop.c b/bgpd/bgp_nexthop.c
index fd8d894878..32011d210b 100644
--- a/bgpd/bgp_nexthop.c
+++ b/bgpd/bgp_nexthop.c
@@ -438,7 +438,7 @@ int bgp_subgrp_multiaccess_check_v4(struct in_addr nexthop,
struct bgp_node *rn1, *rn2;
struct peer_af *paf;
struct prefix p, np;
- struct bgp *bgp = NULL;
+ struct bgp *bgp;
np.family = AF_INET;
np.prefixlen = IPV4_MAX_BITLEN;
@@ -447,7 +447,7 @@ int bgp_subgrp_multiaccess_check_v4(struct in_addr nexthop,
p.family = AF_INET;
p.prefixlen = IPV4_MAX_BITLEN;
- rn1 = rn2 = NULL;
+ rn2 = NULL;
bgp = SUBGRP_INST(subgrp);
rn1 = bgp_node_match(bgp->connected_table[AFI_IP], &np);
diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c
index 95e7def8fb..0b1deba517 100644
--- a/bgpd/bgp_route.c
+++ b/bgpd/bgp_route.c
@@ -1318,6 +1318,8 @@ void bgp_attr_add_gshut_community(struct attr *attr)
old = attr->community;
gshut = community_str2com("graceful-shutdown");
+ assert(gshut);
+
if (old) {
merge = community_merge(community_dup(old), gshut);
@@ -6564,14 +6566,8 @@ void route_vty_out(struct vty *vty, struct prefix *p, struct bgp_info *binfo,
} else {
char buf[BUFSIZ];
- if ((safi == SAFI_MPLS_VPN) || (safi == SAFI_EVPN))
- snprintf(buf, sizeof(buf), "%s%s",
- inet_ntoa(attr->mp_nexthop_global_in),
- vrf_id_str);
- else
- snprintf(buf, sizeof(buf), "%s%s",
- inet_ntoa(attr->nexthop),
- vrf_id_str);
+ snprintf(buf, sizeof(buf), "%s%s",
+ inet_ntoa(attr->nexthop), vrf_id_str);
vty_out(vty, "%-16s", buf);
}
}
diff --git a/bgpd/bgp_updgrp_packet.c b/bgpd/bgp_updgrp_packet.c
index cabd5b5cbd..34ddbfcd14 100644
--- a/bgpd/bgp_updgrp_packet.c
+++ b/bgpd/bgp_updgrp_packet.c
@@ -397,7 +397,7 @@ struct stream *bpacket_reformat_for_peer(struct bpacket *pkt,
vec = &pkt->arr.entries[BGP_ATTR_VEC_NH];
if (CHECK_FLAG(vec->flags, BPKT_ATTRVEC_FLAGS_UPDATED)) {
uint8_t nhlen;
- afi_t nhafi = AFI_MAX; /* NH AFI is based on nhlen! */
+ afi_t nhafi;
int route_map_sets_nh;
nhlen = stream_getc_from(s, vec->offset);
if (peer_cap_enhe(peer, paf->afi, paf->safi))
diff --git a/bgpd/bgp_vpn.c b/bgpd/bgp_vpn.c
index cc05194703..a771eedf0f 100644
--- a/bgpd/bgp_vpn.c
+++ b/bgpd/bgp_vpn.c
@@ -125,7 +125,7 @@ int show_adj_route_vpn(struct vty *vty, struct peer *peer,
if (rd_header) {
uint16_t type;
- struct rd_as rd_as;
+ struct rd_as rd_as = {0};
struct rd_ip rd_ip = {0};
#if ENABLE_BGP_VNC
struct rd_vnc_eth rd_vnc_eth = {
diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c
index 4e0f7155ba..d98104a9fa 100644
--- a/bgpd/bgp_vty.c
+++ b/bgpd/bgp_vty.c
@@ -11409,7 +11409,6 @@ DEFUN (show_ip_bgp_peer_groups,
"Peer group name\n")
{
char *vrf, *pg;
- vrf = pg = NULL;
int idx = 0;
vrf = argv_find(argv, argc, "VIEWVRFNAME", &idx) ? argv[idx]->arg
diff --git a/bgpd/rfapi/bgp_rfapi_cfg.c b/bgpd/rfapi/bgp_rfapi_cfg.c
index 72255e54fb..491741a35b 100644
--- a/bgpd/rfapi/bgp_rfapi_cfg.c
+++ b/bgpd/rfapi/bgp_rfapi_cfg.c
@@ -1426,7 +1426,8 @@ DEFUN (vnc_export_nvegroup,
if (rfg_new == NULL) {
rfg_new = bgp_rfapi_cfg_match_byname(bgp, argv[5]->arg,
RFAPI_GROUP_CFG_VRF);
- vnc_add_vrf_opener(bgp, rfg_new);
+ if (rfg_new)
+ vnc_add_vrf_opener(bgp, rfg_new);
}
if (rfg_new == NULL) {
diff --git a/doc/user/basic.rst b/doc/user/basic.rst
index a75017c442..cb46080055 100644
--- a/doc/user/basic.rst
+++ b/doc/user/basic.rst
@@ -405,6 +405,18 @@ These options apply to all |PACKAGE_NAME| daemons.
Print program version.
+.. option:: --log <stdout|syslog|file:/path/to/log/file>
+
+ When initializing the daemon, setup the log to go to either stdout,
+ syslog or to a file. These values will be displayed as part of
+ a show run. Additionally they can be overridden at runtime if
+ desired via the normal log commands.
+
+.. option:: --log-level <emergencies|alerts|critical|errors|warnings|notifications|informational|debugging>
+
+ When initializing the daemon, allow the specification of a default
+ log level at startup from one of the specified levels.
+
.. _loadable-module-support:
Loadable Module Support
diff --git a/eigrpd/eigrp_fsm.c b/eigrpd/eigrp_fsm.c
index 4107d44090..eeefc51968 100644
--- a/eigrpd/eigrp_fsm.c
+++ b/eigrpd/eigrp_fsm.c
@@ -486,6 +486,7 @@ int eigrp_fsm_event_q_fcn(struct eigrp_fsm_action_message *msg)
int eigrp_fsm_event_keep_state(struct eigrp_fsm_action_message *msg)
{
+ struct eigrp *eigrp;
struct eigrp_prefix_entry *prefix = msg->prefix;
struct eigrp_nexthop_entry *ne = listnode_head(prefix->entries);
@@ -498,9 +499,10 @@ int eigrp_fsm_event_keep_state(struct eigrp_fsm_action_message *msg)
if (msg->packet_type == EIGRP_OPC_QUERY)
eigrp_send_reply(msg->adv_router, prefix);
prefix->req_action |= EIGRP_FSM_NEED_UPDATE;
- listnode_add(
- (eigrp_lookup())->topology_changes_internalIPV4,
- prefix);
+ eigrp = eigrp_lookup();
+ assert(eigrp);
+ listnode_add(eigrp->topology_changes_internalIPV4,
+ prefix);
}
eigrp_topology_update_node_flags(prefix);
eigrp_update_routing_table(prefix);
diff --git a/eigrpd/eigrp_interface.c b/eigrpd/eigrp_interface.c
index cd459fdc42..cd62811fdf 100644
--- a/eigrpd/eigrp_interface.c
+++ b/eigrpd/eigrp_interface.c
@@ -336,6 +336,9 @@ void eigrp_if_free(struct eigrp_interface *ei, int source)
struct eigrp_prefix_entry *pe;
struct eigrp *eigrp = eigrp_lookup();
+ if (!eigrp)
+ return;
+
if (source == INTERFACE_DOWN_BY_VTY) {
THREAD_OFF(ei->t_hello);
eigrp_hello_send(ei, EIGRP_HELLO_GRACEFUL_SHUTDOWN, NULL);
diff --git a/eigrpd/eigrp_topology.c b/eigrpd/eigrp_topology.c
index becb29a95f..4e26446ebe 100644
--- a/eigrpd/eigrp_topology.c
+++ b/eigrpd/eigrp_topology.c
@@ -182,6 +182,9 @@ void eigrp_prefix_entry_delete(struct route_table *table,
struct eigrp *eigrp = eigrp_lookup();
struct route_node *rn;
+ if (!eigrp)
+ return;
+
rn = route_node_lookup(table, pe->destination);
if (!rn)
return;
@@ -426,6 +429,9 @@ void eigrp_topology_update_all_node_flags(struct eigrp *eigrp)
struct eigrp_prefix_entry *pe;
struct route_node *rn;
+ if (!eigrp)
+ return;
+
for (rn = route_top(eigrp->topology_table); rn; rn = route_next(rn)) {
pe = rn->info;
@@ -471,11 +477,15 @@ void eigrp_topology_update_node_flags(struct eigrp_prefix_entry *dest)
void eigrp_update_routing_table(struct eigrp_prefix_entry *prefix)
{
struct eigrp *eigrp = eigrp_lookup();
- struct list *successors =
- eigrp_topology_get_successor_max(prefix, eigrp->max_paths);
+ struct list *successors;
struct listnode *node;
struct eigrp_nexthop_entry *entry;
+ if (!eigrp)
+ return;
+
+ successors = eigrp_topology_get_successor_max(prefix, eigrp->max_paths);
+
if (successors) {
eigrp_zebra_route_add(prefix->destination, successors);
for (ALL_LIST_ELEMENTS_RO(successors, node, entry))
diff --git a/include/linux/netlink.h b/include/linux/netlink.h
new file mode 100644
index 0000000000..0b2c29bd08
--- /dev/null
+++ b/include/linux/netlink.h
@@ -0,0 +1,247 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+#ifndef __LINUX_NETLINK_H
+#define __LINUX_NETLINK_H
+
+#include <linux/kernel.h>
+#include <linux/socket.h> /* for __kernel_sa_family_t */
+#include <linux/types.h>
+
+#define NETLINK_ROUTE 0 /* Routing/device hook */
+#define NETLINK_UNUSED 1 /* Unused number */
+#define NETLINK_USERSOCK 2 /* Reserved for user mode socket protocols */
+#define NETLINK_FIREWALL 3 /* Unused number, formerly ip_queue */
+#define NETLINK_SOCK_DIAG 4 /* socket monitoring */
+#define NETLINK_NFLOG 5 /* netfilter/iptables ULOG */
+#define NETLINK_XFRM 6 /* ipsec */
+#define NETLINK_SELINUX 7 /* SELinux event notifications */
+#define NETLINK_ISCSI 8 /* Open-iSCSI */
+#define NETLINK_AUDIT 9 /* auditing */
+#define NETLINK_FIB_LOOKUP 10
+#define NETLINK_CONNECTOR 11
+#define NETLINK_NETFILTER 12 /* netfilter subsystem */
+#define NETLINK_IP6_FW 13
+#define NETLINK_DNRTMSG 14 /* DECnet routing messages */
+#define NETLINK_KOBJECT_UEVENT 15 /* Kernel messages to userspace */
+#define NETLINK_GENERIC 16
+/* leave room for NETLINK_DM (DM Events) */
+#define NETLINK_SCSITRANSPORT 18 /* SCSI Transports */
+#define NETLINK_ECRYPTFS 19
+#define NETLINK_RDMA 20
+#define NETLINK_CRYPTO 21 /* Crypto layer */
+#define NETLINK_SMC 22 /* SMC monitoring */
+
+#define NETLINK_INET_DIAG NETLINK_SOCK_DIAG
+
+#define MAX_LINKS 32
+
+struct sockaddr_nl {
+ __kernel_sa_family_t nl_family; /* AF_NETLINK */
+ unsigned short nl_pad; /* zero */
+ __u32 nl_pid; /* port ID */
+ __u32 nl_groups; /* multicast groups mask */
+};
+
+struct nlmsghdr {
+ __u32 nlmsg_len; /* Length of message including header */
+ __u16 nlmsg_type; /* Message content */
+ __u16 nlmsg_flags; /* Additional flags */
+ __u32 nlmsg_seq; /* Sequence number */
+ __u32 nlmsg_pid; /* Sending process port ID */
+};
+
+/* Flags values */
+
+#define NLM_F_REQUEST 0x01 /* It is request message. */
+#define NLM_F_MULTI 0x02 /* Multipart message, terminated by NLMSG_DONE */
+#define NLM_F_ACK 0x04 /* Reply with ack, with zero or error code */
+#define NLM_F_ECHO 0x08 /* Echo this request */
+#define NLM_F_DUMP_INTR 0x10 /* Dump was inconsistent due to sequence change */
+#define NLM_F_DUMP_FILTERED 0x20 /* Dump was filtered as requested */
+
+/* Modifiers to GET request */
+#define NLM_F_ROOT 0x100 /* specify tree root */
+#define NLM_F_MATCH 0x200 /* return all matching */
+#define NLM_F_ATOMIC 0x400 /* atomic GET */
+#define NLM_F_DUMP (NLM_F_ROOT|NLM_F_MATCH)
+
+/* Modifiers to NEW request */
+#define NLM_F_REPLACE 0x100 /* Override existing */
+#define NLM_F_EXCL 0x200 /* Do not touch, if it exists */
+#define NLM_F_CREATE 0x400 /* Create, if it does not exist */
+#define NLM_F_APPEND 0x800 /* Add to end of list */
+
+/* Modifiers to DELETE request */
+#define NLM_F_NONREC 0x100 /* Do not delete recursively */
+
+/* Flags for ACK message */
+#define NLM_F_CAPPED 0x100 /* request was capped */
+#define NLM_F_ACK_TLVS 0x200 /* extended ACK TVLs were included */
+
+/*
+ 4.4BSD ADD NLM_F_CREATE|NLM_F_EXCL
+ 4.4BSD CHANGE NLM_F_REPLACE
+
+ True CHANGE NLM_F_CREATE|NLM_F_REPLACE
+ Append NLM_F_CREATE
+ Check NLM_F_EXCL
+ */
+
+#define NLMSG_ALIGNTO 4U
+#define NLMSG_ALIGN(len) ( ((len)+NLMSG_ALIGNTO-1) & ~(NLMSG_ALIGNTO-1) )
+#define NLMSG_HDRLEN ((int) NLMSG_ALIGN(sizeof(struct nlmsghdr)))
+#define NLMSG_LENGTH(len) ((len) + NLMSG_HDRLEN)
+#define NLMSG_SPACE(len) NLMSG_ALIGN(NLMSG_LENGTH(len))
+#define NLMSG_DATA(nlh) ((void*)(((char*)nlh) + NLMSG_LENGTH(0)))
+#define NLMSG_NEXT(nlh,len) ((len) -= NLMSG_ALIGN((nlh)->nlmsg_len), \
+ (struct nlmsghdr*)(((char*)(nlh)) + NLMSG_ALIGN((nlh)->nlmsg_len)))
+#define NLMSG_OK(nlh,len) ((len) >= (int)sizeof(struct nlmsghdr) && \
+ (nlh)->nlmsg_len >= sizeof(struct nlmsghdr) && \
+ (nlh)->nlmsg_len <= (len))
+#define NLMSG_PAYLOAD(nlh,len) ((nlh)->nlmsg_len - NLMSG_SPACE((len)))
+
+#define NLMSG_NOOP 0x1 /* Nothing. */
+#define NLMSG_ERROR 0x2 /* Error */
+#define NLMSG_DONE 0x3 /* End of a dump */
+#define NLMSG_OVERRUN 0x4 /* Data lost */
+
+#define NLMSG_MIN_TYPE 0x10 /* < 0x10: reserved control messages */
+
+struct nlmsgerr {
+ int error;
+ struct nlmsghdr msg;
+ /*
+ * followed by the message contents unless NETLINK_CAP_ACK was set
+ * or the ACK indicates success (error == 0)
+ * message length is aligned with NLMSG_ALIGN()
+ */
+ /*
+ * followed by TLVs defined in enum nlmsgerr_attrs
+ * if NETLINK_EXT_ACK was set
+ */
+};
+
+/**
+ * enum nlmsgerr_attrs - nlmsgerr attributes
+ * @NLMSGERR_ATTR_UNUSED: unused
+ * @NLMSGERR_ATTR_MSG: error message string (string)
+ * @NLMSGERR_ATTR_OFFS: offset of the invalid attribute in the original
+ * message, counting from the beginning of the header (u32)
+ * @NLMSGERR_ATTR_COOKIE: arbitrary subsystem specific cookie to
+ * be used - in the success case - to identify a created
+ * object or operation or similar (binary)
+ * @__NLMSGERR_ATTR_MAX: number of attributes
+ * @NLMSGERR_ATTR_MAX: highest attribute number
+ */
+enum nlmsgerr_attrs {
+ NLMSGERR_ATTR_UNUSED,
+ NLMSGERR_ATTR_MSG,
+ NLMSGERR_ATTR_OFFS,
+ NLMSGERR_ATTR_COOKIE,
+
+ __NLMSGERR_ATTR_MAX,
+ NLMSGERR_ATTR_MAX = __NLMSGERR_ATTR_MAX - 1
+};
+
+#define NETLINK_ADD_MEMBERSHIP 1
+#define NETLINK_DROP_MEMBERSHIP 2
+#define NETLINK_PKTINFO 3
+#define NETLINK_BROADCAST_ERROR 4
+#define NETLINK_NO_ENOBUFS 5
+#define NETLINK_RX_RING 6
+#define NETLINK_TX_RING 7
+#define NETLINK_LISTEN_ALL_NSID 8
+#define NETLINK_LIST_MEMBERSHIPS 9
+#define NETLINK_CAP_ACK 10
+#define NETLINK_EXT_ACK 11
+
+struct nl_pktinfo {
+ __u32 group;
+};
+
+struct nl_mmap_req {
+ unsigned int nm_block_size;
+ unsigned int nm_block_nr;
+ unsigned int nm_frame_size;
+ unsigned int nm_frame_nr;
+};
+
+struct nl_mmap_hdr {
+ unsigned int nm_status;
+ unsigned int nm_len;
+ __u32 nm_group;
+ /* credentials */
+ __u32 nm_pid;
+ __u32 nm_uid;
+ __u32 nm_gid;
+};
+
+enum nl_mmap_status {
+ NL_MMAP_STATUS_UNUSED,
+ NL_MMAP_STATUS_RESERVED,
+ NL_MMAP_STATUS_VALID,
+ NL_MMAP_STATUS_COPY,
+ NL_MMAP_STATUS_SKIP,
+};
+
+#define NL_MMAP_MSG_ALIGNMENT NLMSG_ALIGNTO
+#define NL_MMAP_MSG_ALIGN(sz) __ALIGN_KERNEL(sz, NL_MMAP_MSG_ALIGNMENT)
+#define NL_MMAP_HDRLEN NL_MMAP_MSG_ALIGN(sizeof(struct nl_mmap_hdr))
+
+#define NET_MAJOR 36 /* Major 36 is reserved for networking */
+
+enum {
+ NETLINK_UNCONNECTED = 0,
+ NETLINK_CONNECTED,
+};
+
+/*
+ * <------- NLA_HDRLEN ------> <-- NLA_ALIGN(payload)-->
+ * +---------------------+- - -+- - - - - - - - - -+- - -+
+ * | Header | Pad | Payload | Pad |
+ * | (struct nlattr) | ing | | ing |
+ * +---------------------+- - -+- - - - - - - - - -+- - -+
+ * <-------------- nlattr->nla_len -------------->
+ */
+
+struct nlattr {
+ __u16 nla_len;
+ __u16 nla_type;
+};
+
+/*
+ * nla_type (16 bits)
+ * +---+---+-------------------------------+
+ * | N | O | Attribute Type |
+ * +---+---+-------------------------------+
+ * N := Carries nested attributes
+ * O := Payload stored in network byte order
+ *
+ * Note: The N and O flag are mutually exclusive.
+ */
+#define NLA_F_NESTED (1 << 15)
+#define NLA_F_NET_BYTEORDER (1 << 14)
+#define NLA_TYPE_MASK ~(NLA_F_NESTED | NLA_F_NET_BYTEORDER)
+
+#define NLA_ALIGNTO 4
+#define NLA_ALIGN(len) (((len) + NLA_ALIGNTO - 1) & ~(NLA_ALIGNTO - 1))
+#define NLA_HDRLEN ((int) NLA_ALIGN(sizeof(struct nlattr)))
+
+/* Generic 32 bitflags attribute content sent to the kernel.
+ *
+ * The value is a bitmap that defines the values being set
+ * The selector is a bitmask that defines which value is legit
+ *
+ * Examples:
+ * value = 0x0, and selector = 0x1
+ * implies we are selecting bit 1 and we want to set its value to 0.
+ *
+ * value = 0x2, and selector = 0x2
+ * implies we are selecting bit 2 and we want to set its value to 1.
+ *
+ */
+struct nla_bitfield32 {
+ __u32 value;
+ __u32 selector;
+};
+
+#endif /* __LINUX_NETLINK_H */
diff --git a/include/subdir.am b/include/subdir.am
index db5ed06c61..731785d4b4 100644
--- a/include/subdir.am
+++ b/include/subdir.am
@@ -4,6 +4,7 @@ noinst_HEADERS += \
include/linux/lwtunnel.h \
include/linux/mpls_iptunnel.h \
include/linux/neighbour.h \
+ include/linux/netlink.h \
include/linux/rtnetlink.h \
include/linux/socket.h \
include/linux/net_namespace.h \
diff --git a/isisd/isis_te.c b/isisd/isis_te.c
index 6834f52a82..8e53df3b61 100644
--- a/isisd/isis_te.c
+++ b/isisd/isis_te.c
@@ -884,7 +884,7 @@ static uint8_t print_subtlv_use_bw(struct sbuf *buf, int indent,
static uint8_t print_unknown_tlv(struct sbuf *buf, int indent,
struct subtlv_header *tlvh)
{
- int i, rtn = 1;
+ int i, rtn;
uint8_t *v = (uint8_t *)tlvh;
if (tlvh->length != 0) {
diff --git a/isisd/isisd.c b/isisd/isisd.c
index 6f04d72082..cecaa0693d 100644
--- a/isisd/isisd.c
+++ b/isisd/isisd.c
@@ -1373,7 +1373,7 @@ static int show_isis_database(struct vty *vty, const char *argv, int ui_level)
struct isis_area *area;
struct isis_lsp *lsp;
struct isis_dynhn *dynhn;
- const char *pos = argv;
+ const char *pos;
uint8_t lspid[ISIS_SYS_ID_LEN + 2];
char sysid[255];
uint8_t number[3];
diff --git a/ldpd/ldp_debug.c b/ldpd/ldp_debug.c
index 39e20ef7c8..ec70ef510a 100644
--- a/ldpd/ldp_debug.c
+++ b/ldpd/ldp_debug.c
@@ -41,6 +41,9 @@ int
ldp_vty_debug(struct vty *vty, const char *negate, const char *type_str,
const char *dir_str, const char *all)
{
+ if (type_str == NULL)
+ return (CMD_WARNING_CONFIG_FAILED);
+
if (strcmp(type_str, "discovery") == 0) {
if (dir_str == NULL)
return (CMD_WARNING_CONFIG_FAILED);
diff --git a/ldpd/ldp_vty_conf.c b/ldpd/ldp_vty_conf.c
index 382b006884..e5832c5086 100644
--- a/ldpd/ldp_vty_conf.c
+++ b/ldpd/ldp_vty_conf.c
@@ -428,6 +428,9 @@ ldp_vty_address_family(struct vty *vty, const char *negate, const char *af_str)
struct ldpd_af_conf *af_conf;
int af;
+ if (af_str == NULL)
+ return (CMD_WARNING_CONFIG_FAILED);
+
if (strcmp(af_str, "ipv4") == 0) {
af = AF_INET;
af_conf = &vty_conf->ipv4;
@@ -709,6 +712,11 @@ ldp_vty_interface(struct vty *vty, const char *negate, const char *ifname)
struct iface *iface;
struct iface_af *ia;
+ if (ifname == NULL) {
+ vty_out (vty, "%% Missing IF name\n");
+ return (CMD_WARNING_CONFIG_FAILED);
+ }
+
af = ldp_vty_get_af(vty);
iface = if_lookup_name(vty_conf, ifname);
@@ -776,8 +784,9 @@ ldp_vty_trans_addr(struct vty *vty, const char *negate, const char *addr_str)
if (negate)
memset(&af_conf->trans_addr, 0, sizeof(af_conf->trans_addr));
else {
- if (inet_pton(af, addr_str, &af_conf->trans_addr) != 1 ||
- bad_addr(af, &af_conf->trans_addr)) {
+ if (addr_str == NULL
+ || inet_pton(af, addr_str, &af_conf->trans_addr) != 1
+ || bad_addr(af, &af_conf->trans_addr)) {
vty_out (vty, "%% Malformed address\n");
return (CMD_SUCCESS);
}
@@ -797,7 +806,7 @@ ldp_vty_neighbor_targeted(struct vty *vty, const char *negate, const char *addr_
af = ldp_vty_get_af(vty);
- if (inet_pton(af, addr_str, &addr) != 1 ||
+ if (addr_str == NULL || inet_pton(af, addr_str, &addr) != 1 ||
bad_addr(af, &addr)) {
vty_out (vty, "%% Malformed address\n");
return (CMD_WARNING_CONFIG_FAILED);
@@ -1018,6 +1027,11 @@ ldp_vty_neighbor_password(struct vty *vty, const char *negate, struct in_addr ls
size_t password_len;
struct nbr_params *nbrp;
+ if (password_str == NULL) {
+ vty_out (vty, "%% Missing password\n");
+ return (CMD_WARNING_CONFIG_FAILED);
+ }
+
if (bad_addr_v4(lsr_id)) {
vty_out (vty, "%% Malformed address\n");
return (CMD_WARNING_CONFIG_FAILED);
@@ -1113,6 +1127,11 @@ ldp_vty_l2vpn(struct vty *vty, const char *negate, const char *name_str)
struct l2vpn_if *lif;
struct l2vpn_pw *pw;
+ if (name_str == NULL) {
+ vty_out (vty, "%% Missing name\n");
+ return (CMD_WARNING_CONFIG_FAILED);
+ }
+
l2vpn = l2vpn_find(vty_conf, name_str);
if (negate) {
@@ -1158,8 +1177,13 @@ ldp_vty_l2vpn_bridge(struct vty *vty, const char *negate, const char *ifname)
if (negate)
memset(l2vpn->br_ifname, 0, sizeof(l2vpn->br_ifname));
- else
+ else {
+ if (ifname == NULL) {
+ vty_out (vty, "%% Missing IF name\n");
+ return (CMD_WARNING_CONFIG_FAILED);
+ }
strlcpy(l2vpn->br_ifname, ifname, sizeof(l2vpn->br_ifname));
+ }
ldp_config_apply(vty, vty_conf);
@@ -1187,6 +1211,11 @@ ldp_vty_l2vpn_pwtype(struct vty *vty, const char *negate, const char *type_str)
VTY_DECLVAR_CONTEXT(l2vpn, l2vpn);
int pw_type;
+ if (type_str == NULL) {
+ vty_out (vty, "%% Missing type\n");
+ return (CMD_WARNING_CONFIG_FAILED);
+ }
+
if (strcmp(type_str, "ethernet") == 0)
pw_type = PW_TYPE_ETHERNET;
else
@@ -1208,6 +1237,11 @@ ldp_vty_l2vpn_interface(struct vty *vty, const char *negate, const char *ifname)
VTY_DECLVAR_CONTEXT(l2vpn, l2vpn);
struct l2vpn_if *lif;
+ if (ifname == NULL) {
+ vty_out (vty, "%% Missing IF name\n");
+ return (CMD_WARNING_CONFIG_FAILED);
+ }
+
lif = l2vpn_if_find(l2vpn, ifname);
if (negate) {
@@ -1246,6 +1280,11 @@ ldp_vty_l2vpn_pseudowire(struct vty *vty, const char *negate, const char *ifname
VTY_DECLVAR_CONTEXT(l2vpn, l2vpn);
struct l2vpn_pw *pw;
+ if (ifname == NULL) {
+ vty_out (vty, "%% Missing IF name\n");
+ return (CMD_WARNING_CONFIG_FAILED);
+ }
+
pw = l2vpn_pw_find(l2vpn, ifname);
if (negate) {
@@ -1294,6 +1333,10 @@ ldp_vty_l2vpn_pw_cword(struct vty *vty, const char *negate, const char *preferen
if (negate)
pw->flags |= F_PW_CWORD_CONF;
else {
+ if (!preference_str) {
+ vty_out (vty, "%% Missing preference\n");
+ return (CMD_WARNING_CONFIG_FAILED);
+ }
if (preference_str[0] == 'e')
pw->flags &= ~F_PW_CWORD_CONF;
else
diff --git a/ldpd/ldpd.c b/ldpd/ldpd.c
index b265c98dae..b51ff82cea 100644
--- a/ldpd/ldpd.c
+++ b/ldpd/ldpd.c
@@ -187,6 +187,22 @@ FRR_DAEMON_INFO(ldpd, LDP,
.privs = &ldpd_privs,
)
+static int ldp_config_fork_apply(struct thread *t)
+{
+ /*
+ * So the frr_config_fork() function schedules
+ * the read of the vty config( if there is a
+ * non-integrated config ) to be after the
+ * end of startup and we are starting the
+ * main process loop. We need to schedule
+ * the application of this if necessary
+ * after the read in of the config.
+ */
+ ldp_config_apply(NULL, vty_conf);
+
+ return 0;
+}
+
int
main(int argc, char *argv[])
{
@@ -195,6 +211,7 @@ main(int argc, char *argv[])
int pipe_parent2ldpe[2], pipe_parent2ldpe_sync[2];
int pipe_parent2lde[2], pipe_parent2lde_sync[2];
char *ctl_sock_name;
+ struct thread *thread = NULL;
ldpd_process = PROC_MAIN;
log_procname = log_procnames[ldpd_process];
@@ -331,7 +348,7 @@ main(int argc, char *argv[])
frr_config_fork();
/* apply configuration */
- ldp_config_apply(NULL, vty_conf);
+ thread_add_event(master, ldp_config_fork_apply, NULL, 0, &thread);
/* setup pipes to children */
if ((iev_ldpe = calloc(1, sizeof(struct imsgev))) == NULL ||
diff --git a/lib/command.c b/lib/command.c
index a8e61c6bb4..4ab47e5fc2 100644
--- a/lib/command.c
+++ b/lib/command.c
@@ -2429,7 +2429,8 @@ static int set_log_file(struct vty *vty, const char *fname, int loglevel)
XFREE(MTYPE_TMP, p);
if (!ret) {
- vty_out(vty, "can't open logfile %s\n", fname);
+ if (vty)
+ vty_out(vty, "can't open logfile %s\n", fname);
return CMD_WARNING_CONFIG_FAILED;
}
@@ -2445,6 +2446,36 @@ static int set_log_file(struct vty *vty, const char *fname, int loglevel)
return CMD_SUCCESS;
}
+void command_setup_early_logging(const char *dest, const char *level)
+{
+ char *token;
+
+ if (level) {
+ int nlevel = level_match(level);
+
+ if (nlevel != ZLOG_DISABLED)
+ zlog_default->default_lvl = nlevel;
+ }
+
+ if (!dest)
+ return;
+
+ if (strcmp(dest, "stdout") == 0) {
+ zlog_set_level(ZLOG_DEST_STDOUT, zlog_default->default_lvl);
+ return;
+ }
+
+ if (strcmp(dest, "syslog") == 0) {
+ zlog_set_level(ZLOG_DEST_SYSLOG, zlog_default->default_lvl);
+ return;
+ }
+
+ token = strstr(dest, ":");
+ token++;
+
+ set_log_file(NULL, token, zlog_default->default_lvl);
+}
+
DEFUN (config_log_file,
config_log_file_cmd,
"log file FILENAME [<emergencies|alerts|critical|errors|warnings|notifications|informational|debugging>]",
diff --git a/lib/command.h b/lib/command.h
index 9bf482f41b..395c971c55 100644
--- a/lib/command.h
+++ b/lib/command.h
@@ -479,4 +479,5 @@ extern void
cmd_variable_handler_register(const struct cmd_variable_handler *cvh);
extern char *cmd_variable_comp2str(vector comps, unsigned short cols);
+extern void command_setup_early_logging(const char *dest, const char *level);
#endif /* _ZEBRA_COMMAND_H */
diff --git a/lib/command_match.c b/lib/command_match.c
index 99ec03e0c2..4893ead042 100644
--- a/lib/command_match.c
+++ b/lib/command_match.c
@@ -609,6 +609,7 @@ static struct list *disambiguate(struct list *first, struct list *second,
vector vline, unsigned int n)
{
// doesn't make sense for these to be inequal length
+ assert(first && second);
assert(first->count == second->count);
assert(first->count == vector_active(vline) - n + 1);
diff --git a/lib/imsg.c b/lib/imsg.c
index 6419f805ab..5424140720 100644
--- a/lib/imsg.c
+++ b/lib/imsg.c
@@ -77,7 +77,7 @@ ssize_t imsg_read(struct imsgbuf *ibuf)
char buf[CMSG_SPACE(sizeof(int) * 1)];
} cmsgbuf;
struct iovec iov;
- ssize_t n = -1;
+ ssize_t n;
int fd;
struct imsg_fd *ifd;
@@ -110,7 +110,8 @@ again:
return (-1);
}
- if ((n = recvmsg(ibuf->fd, &msg, 0)) == -1) {
+ n = recvmsg(ibuf->fd, &msg, 0);
+ if (n == -1) {
if (errno == EINTR)
goto again;
goto fail;
diff --git a/lib/libfrr.c b/lib/libfrr.c
index 88203fbeb6..505bea9b18 100644
--- a/lib/libfrr.c
+++ b/lib/libfrr.c
@@ -78,6 +78,8 @@ static void opt_extend(const struct optspec *os)
#define OPTION_VTYSOCK 1000
#define OPTION_MODULEDIR 1002
+#define OPTION_LOG 1003
+#define OPTION_LOGLEVEL 1004
static const struct option lo_always[] = {
{"help", no_argument, NULL, 'h'},
@@ -86,6 +88,8 @@ static const struct option lo_always[] = {
{"module", no_argument, NULL, 'M'},
{"vty_socket", required_argument, NULL, OPTION_VTYSOCK},
{"moduledir", required_argument, NULL, OPTION_MODULEDIR},
+ {"log", required_argument, NULL, OPTION_LOG},
+ {"log-level", required_argument, NULL, OPTION_LOGLEVEL},
{NULL}};
static const struct optspec os_always = {
"hvdM:",
@@ -94,7 +98,9 @@ static const struct optspec os_always = {
" -d, --daemon Runs in daemon mode\n"
" -M, --module Load specified module\n"
" --vty_socket Override vty socket path\n"
- " --moduledir Override modules directory\n",
+ " --moduledir Override modules directory\n"
+ " --log Set Logging to stdout, syslog, or file:<name>\n"
+ " --log-level Set Logging Level to use, debug, info, warn, etc\n",
lo_always};
@@ -444,6 +450,12 @@ static int frr_opt(int opt)
return 1;
di->privs->group = optarg;
break;
+ case OPTION_LOG:
+ di->early_logging = optarg;
+ break;
+ case OPTION_LOGLEVEL:
+ di->early_loglevel = optarg;
+ break;
default:
return 1;
}
@@ -543,9 +555,8 @@ struct thread_master *frr_init(void)
openzlog(di->progname, di->logname, di->instance,
LOG_CONS | LOG_NDELAY | LOG_PID, LOG_DAEMON);
-#if defined(HAVE_CUMULUS)
- zlog_set_level(ZLOG_DEST_SYSLOG, zlog_default->default_lvl);
-#endif
+
+ command_setup_early_logging(di->early_logging, di->early_loglevel);
if (!frr_zclient_addr(&zclient_addr, &zclient_addr_len,
frr_zclientpath)) {
@@ -721,15 +732,37 @@ static void frr_daemonize(void)
frr_daemon_wait(fds[0]);
}
+/*
+ * Why is this a thread?
+ *
+ * The read in of config for integrated config happens *after*
+ * thread execution starts( because it is passed in via a vtysh -b -n )
+ * While if you are not using integrated config we want the ability
+ * to read the config in after thread execution starts, so that
+ * we can match this behavior.
+ */
+static int frr_config_read_in(struct thread *t)
+{
+ if (!vty_read_config(di->config_file, config_default) &&
+ di->backup_config_file) {
+ zlog_info("Attempting to read backup config file: %s specified",
+ di->backup_config_file);
+ vty_read_config(di->backup_config_file, config_default);
+ }
+ return 0;
+}
+
void frr_config_fork(void)
{
hook_call(frr_late_init, master);
- vty_read_config(di->config_file, config_default);
-
/* Don't start execution if we are in dry-run mode */
- if (di->dryrun)
+ if (di->dryrun) {
+ frr_config_read_in(NULL);
exit(0);
+ }
+
+ thread_add_event(master, frr_config_read_in, NULL, 0, &di->read_in);
if (di->daemon_mode || di->terminal)
frr_daemonize();
diff --git a/lib/libfrr.h b/lib/libfrr.h
index 7ffa780bfb..d255279906 100644
--- a/lib/libfrr.h
+++ b/lib/libfrr.h
@@ -50,11 +50,16 @@ struct frr_daemon_info {
bool dryrun;
bool daemon_mode;
bool terminal;
+
+ struct thread *read_in;
const char *config_file;
+ const char *backup_config_file;
const char *pid_file;
const char *vty_path;
const char *module_path;
const char *pathspace;
+ const char *early_logging;
+ const char *early_loglevel;
const char *proghelp;
void (*printhelp)(FILE *target);
diff --git a/lib/plist.c b/lib/plist.c
index 5ed1589f45..056b737f54 100644
--- a/lib/plist.c
+++ b/lib/plist.c
@@ -850,6 +850,11 @@ static int vty_prefix_list_install(struct vty *vty, afi_t afi, const char *name,
int lenum = 0;
int genum = 0;
+ if (name == NULL || prefix == NULL || typestr == NULL) {
+ vty_out(vty, "%% Missing prefix or type\n");
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+
/* Sequential number. */
if (seq)
seqnum = (int64_t)atol(seq);
diff --git a/lib/sockopt.c b/lib/sockopt.c
index 1d8d9990df..815be86c2e 100644
--- a/lib/sockopt.c
+++ b/lib/sockopt.c
@@ -457,8 +457,7 @@ int setsockopt_ifindex(int af, int sock, ifindex_t val)
*/
static ifindex_t getsockopt_ipv4_ifindex(struct msghdr *msgh)
{
- /* XXX: initialize to zero? (Always overwritten, so just cosmetic.) */
- ifindex_t ifindex = -1;
+ ifindex_t ifindex;
#if defined(IP_PKTINFO)
/* Linux pktinfo based ifindex retrieval */
@@ -466,7 +465,11 @@ static ifindex_t getsockopt_ipv4_ifindex(struct msghdr *msgh)
pktinfo = (struct in_pktinfo *)getsockopt_cmsg_data(msgh, IPPROTO_IP,
IP_PKTINFO);
- /* XXX Can pktinfo be NULL? Clean up post 0.98. */
+
+ /* getsockopt_ifindex() will forward this, being 0 "not found" */
+ if (pktinfo == NULL)
+ return 0;
+
ifindex = pktinfo->ipi_ifindex;
#elif defined(IP_RECVIF)
diff --git a/lib/sockunion.c b/lib/sockunion.c
index 28a7f647cb..44378b5363 100644
--- a/lib/sockunion.c
+++ b/lib/sockunion.c
@@ -46,6 +46,9 @@ int str2sockunion(const char *str, union sockunion *su)
{
int ret;
+ if (str == NULL)
+ return -1;
+
memset(su, 0, sizeof(union sockunion));
ret = inet_pton(AF_INET, str, &su->sin.sin_addr);
diff --git a/lib/vty.c b/lib/vty.c
index 280b2ace51..e9d1f2e323 100644
--- a/lib/vty.c
+++ b/lib/vty.c
@@ -2462,12 +2462,13 @@ static FILE *vty_use_backup_config(const char *fullpath)
}
/* Read up configuration file from file_name. */
-void vty_read_config(const char *config_file, char *config_default_dir)
+bool vty_read_config(const char *config_file, char *config_default_dir)
{
char cwd[MAXPATHLEN];
FILE *confp = NULL;
const char *fullpath;
char *tmp = NULL;
+ bool read_success = false;
/* If -f flag specified. */
if (config_file != NULL) {
@@ -2525,8 +2526,10 @@ void vty_read_config(const char *config_file, char *config_default_dir)
if (strstr(config_default_dir, "vtysh") == NULL) {
ret = stat(integrate_default, &conf_stat);
- if (ret >= 0)
+ if (ret >= 0) {
+ read_success = true;
goto tmp_free_and_out;
+ }
}
#endif /* VTYSH */
confp = fopen(config_default_dir, "r");
@@ -2550,6 +2553,7 @@ void vty_read_config(const char *config_file, char *config_default_dir)
}
vty_read_file(confp);
+ read_success = true;
fclose(confp);
@@ -2558,6 +2562,8 @@ void vty_read_config(const char *config_file, char *config_default_dir)
tmp_free_and_out:
if (tmp)
XFREE(MTYPE_TMP, tmp);
+
+ return read_success;
}
/* Small utility function which output log to the VTY. */
diff --git a/lib/vty.h b/lib/vty.h
index d14ddf5908..b55abf2204 100644
--- a/lib/vty.h
+++ b/lib/vty.h
@@ -242,7 +242,7 @@ extern void vty_frame(struct vty *, const char *, ...) PRINTF_ATTRIBUTE(2, 3);
extern void vty_endframe(struct vty *, const char *);
bool vty_set_include(struct vty *vty, const char *regexp);
-extern void vty_read_config(const char *, char *);
+extern bool vty_read_config(const char *, char *);
extern void vty_time_print(struct vty *, int);
extern void vty_serv_sock(const char *, unsigned short, const char *);
extern void vty_close(struct vty *);
diff --git a/ospf6d/ospf6_flood.c b/ospf6d/ospf6_flood.c
index 2059d84868..ae26668c8a 100644
--- a/ospf6d/ospf6_flood.c
+++ b/ospf6d/ospf6_flood.c
@@ -347,6 +347,7 @@ 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_spf.c b/ospf6d/ospf6_spf.c
index 28c3459825..5b6691e6bf 100644
--- a/ospf6d/ospf6_spf.c
+++ b/ospf6d/ospf6_spf.c
@@ -677,6 +677,10 @@ void ospf6_spf_schedule(struct ospf6 *ospf6, unsigned int reason)
{
unsigned long delay, elapsed, ht;
+ /* OSPF instance does not exist. */
+ if (ospf6 == NULL)
+ return;
+
ospf6_set_spf_reason(ospf6, reason);
if (IS_OSPF6_DEBUG_SPF(PROCESS) || IS_OSPF6_DEBUG_SPF(TIME)) {
@@ -686,10 +690,6 @@ void ospf6_spf_schedule(struct ospf6 *ospf6, unsigned int reason)
rbuf);
}
- /* OSPF instance does not exist. */
- if (ospf6 == NULL)
- return;
-
/* SPF calculation timer is already scheduled. */
if (ospf6->t_spf_calc) {
if (IS_OSPF6_DEBUG_SPF(PROCESS) || IS_OSPF6_DEBUG_SPF(TIME))
diff --git a/ospfd/ospf_apiserver.c b/ospfd/ospf_apiserver.c
index 37735e3611..92e2a3dcb9 100644
--- a/ospfd/ospf_apiserver.c
+++ b/ospfd/ospf_apiserver.c
@@ -1741,6 +1741,8 @@ struct ospf_lsa *ospf_apiserver_lsa_refresher(struct ospf_lsa *lsa)
struct ospf_lsa *new = NULL;
struct ospf *ospf;
+ assert(lsa);
+
ospf = ospf_lookup_by_vrf_id(VRF_DEFAULT);
assert(ospf);
diff --git a/ospfd/ospf_vty.c b/ospfd/ospf_vty.c
index 31cffea7f2..7d748419fa 100644
--- a/ospfd/ospf_vty.c
+++ b/ospfd/ospf_vty.c
@@ -2412,8 +2412,8 @@ DEFUN (ospf_neighbor_poll_interval,
int idx_poll = 3;
int idx_pri = 5;
struct in_addr nbr_addr;
- unsigned int priority = OSPF_NEIGHBOR_PRIORITY_DEFAULT;
- unsigned int interval = OSPF_POLL_INTERVAL_DEFAULT;
+ unsigned int priority;
+ unsigned int interval;
if (!inet_aton(argv[idx_ipv4]->arg, &nbr_addr)) {
vty_out(vty, "Please specify Neighbor ID by A.B.C.D\n");
@@ -2422,8 +2422,8 @@ DEFUN (ospf_neighbor_poll_interval,
interval = strtoul(argv[idx_poll]->arg, NULL, 10);
- if (argc > 4)
- priority = strtoul(argv[idx_pri]->arg, NULL, 10);
+ priority = argc > 4 ? strtoul(argv[idx_pri]->arg, NULL, 10)
+ : OSPF_NEIGHBOR_PRIORITY_DEFAULT;
ospf_nbr_nbma_set(ospf, nbr_addr);
ospf_nbr_nbma_poll_interval_set(ospf, nbr_addr, interval);
diff --git a/pimd/mtracebis.c b/pimd/mtracebis.c
index 731fdb1beb..c63a6eeca9 100644
--- a/pimd/mtracebis.c
+++ b/pimd/mtracebis.c
@@ -336,7 +336,7 @@ static int wait_for_response(int fd, int *hops, struct igmp_mtrace *mtrace,
{
fd_set readfds;
struct timeval timeout;
- int ret = -1;
+ int ret;
long msec, rmsec, tmsec;
FD_ZERO(&readfds);
diff --git a/pimd/pim_cmd.c b/pimd/pim_cmd.c
index 55222ecddb..123c47568c 100644
--- a/pimd/pim_cmd.c
+++ b/pimd/pim_cmd.c
@@ -4504,8 +4504,8 @@ static void show_mroute(struct pim_instance *pim, struct vty *vty, bool fill,
json_object *json_source = NULL;
json_object *json_oil = NULL;
json_object *json_ifp_out = NULL;
- int found_oif = 0;
- int first = 1;
+ int found_oif;
+ int first;
char grp_str[INET_ADDRSTRLEN];
char src_str[INET_ADDRSTRLEN];
char in_ifname[INTERFACE_NAMSIZ + 1];
diff --git a/pimd/pim_pim.c b/pimd/pim_pim.c
index de09b070f4..f506875282 100644
--- a/pimd/pim_pim.c
+++ b/pimd/pim_pim.c
@@ -521,7 +521,7 @@ int pim_msg_send(int fd, struct in_addr src, struct in_addr dst,
socklen_t tolen;
unsigned char buffer[10000];
unsigned char *msg_start;
- uint8_t ttl = MAXTTL;
+ uint8_t ttl;
struct pim_msg_header *header;
struct ip *ip;
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 9b60312cef..32d2db768a 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -102,8 +102,6 @@ lib/cli/test_commands_defun.c: ../vtysh/vtysh_cmd.c
isisd/test_fuzz_isis_tlv_tests.h: $(top_srcdir)/tests/isisd/test_fuzz_isis_tlv_tests.h.gz
gzip -d < $(top_srcdir)/tests/isisd/test_fuzz_isis_tlv_tests.h.gz > "$@"
-isisd/isisd_test_fuzz_isis_tlv-test_fuzz_isis_tlv.$(OBJEXT): \
- isisd/test_fuzz_isis_tlv_tests.h
noinst_HEADERS = \
./helpers/c/prng.h \
@@ -146,6 +144,9 @@ bgpd_test_ecommunity_SOURCES = bgpd/test_ecommunity.c
bgpd_test_mp_attr_SOURCES = bgpd/test_mp_attr.c
bgpd_test_mpath_SOURCES = bgpd/test_mpath.c
isisd_test_fuzz_isis_tlv_SOURCES = isisd/test_fuzz_isis_tlv.c
+nodist_isisd_test_fuzz_isis_tlv_SOURCES = isisd/test_fuzz_isis_tlv_tests.h
+BUILT_SOURCES=isisd/test_fuzz_isis_tlv_tests.h
+CLEANFILES=isisd/test_fuzz_isis_tlv_tests.h
isisd_test_fuzz_isis_tlv_CPPFLAGS = $(AM_CPPFLAGS) -I$(top_builddir)/tests/isisd
isisd_test_isis_vertex_queue_SOURCES = isisd/test_isis_vertex_queue.c
diff --git a/tools/start-stop-daemon.c b/tools/start-stop-daemon.c
index 8c3fe0c3c5..de58e0a20e 100644
--- a/tools/start-stop-daemon.c
+++ b/tools/start-stop-daemon.c
@@ -1024,8 +1024,10 @@ int main(int argc, char **argv)
close(i);
/* change tty */
fd = open("/dev/tty", O_RDWR);
- ioctl(fd, TIOCNOTTY, 0);
- close(fd);
+ if (fd >= 0) {
+ ioctl(fd, TIOCNOTTY, 0);
+ close(fd);
+ }
chdir("/");
umask(022); /* set a default for dumb programs */
setpgid(0, 0); /* set the process group */
diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c
index a64e568daa..66b49800dd 100644
--- a/vtysh/vtysh.c
+++ b/vtysh/vtysh.c
@@ -2415,10 +2415,11 @@ DEFUNSH(VTYSH_ALL, vtysh_log_syslog, vtysh_log_syslog_cmd,
}
DEFUNSH(VTYSH_ALL, no_vtysh_log_syslog, no_vtysh_log_syslog_cmd,
- "no log syslog [LEVEL]", NO_STR
+ "no log syslog [<emergencies|alerts|critical|errors|warnings|notifications|informational|debugging>]",
+ NO_STR
"Logging control\n"
"Cancel logging to syslog\n"
- "Logging level\n")
+ LOG_LEVEL_DESC)
{
return CMD_SUCCESS;
}
diff --git a/zebra/kernel_netlink.c b/zebra/kernel_netlink.c
index 0e79b82533..6d164cfdab 100644
--- a/zebra/kernel_netlink.c
+++ b/zebra/kernel_netlink.c
@@ -498,6 +498,76 @@ const char *nl_rttype_to_str(uint8_t rttype)
return lookup_msg(rttype_str, rttype, "");
}
+#define NL_OK(nla, len) \
+ ((len) >= (int)sizeof(struct nlattr) \
+ && (nla)->nla_len >= sizeof(struct nlattr) \
+ && (nla)->nla_len <= (len))
+#define NL_NEXT(nla, attrlen) \
+ ((attrlen) -= RTA_ALIGN((nla)->nla_len), \
+ (struct nlattr *)(((char *)(nla)) + RTA_ALIGN((nla)->nla_len)))
+#define NL_RTA(r) \
+ ((struct nlattr *)(((char *)(r)) \
+ + NLMSG_ALIGN(sizeof(struct nlmsgerr))))
+
+static void netlink_parse_nlattr(struct nlattr **tb, int max,
+ struct nlattr *nla, int len)
+{
+ while (NL_OK(nla, len)) {
+ if (nla->nla_type <= max)
+ tb[nla->nla_type] = nla;
+ nla = NL_NEXT(nla, len);
+ }
+}
+
+static void netlink_parse_extended_ack(struct nlmsghdr *h)
+{
+ struct nlattr *tb[NLMSGERR_ATTR_MAX + 1];
+ const struct nlmsgerr *err =
+ (const struct nlmsgerr *)((uint8_t *)h
+ + NLMSG_ALIGN(
+ sizeof(struct nlmsghdr)));
+ const struct nlmsghdr *err_nlh = NULL;
+ uint32_t hlen = sizeof(*err);
+ const char *msg = NULL;
+ uint32_t off = 0;
+
+ if (!(h->nlmsg_flags & NLM_F_CAPPED))
+ hlen += h->nlmsg_len - NLMSG_ALIGN(sizeof(struct nlmsghdr));
+
+ memset(tb, 0, sizeof(tb));
+ netlink_parse_nlattr(tb, NLMSGERR_ATTR_MAX, NL_RTA(h), hlen);
+
+ if (tb[NLMSGERR_ATTR_MSG])
+ msg = (const char *)RTA_DATA(tb[NLMSGERR_ATTR_MSG]);
+
+ if (tb[NLMSGERR_ATTR_OFFS]) {
+ off = *(uint32_t *)RTA_DATA(tb[NLMSGERR_ATTR_OFFS]);
+
+ if (off > h->nlmsg_len) {
+ zlog_err("Invalid offset for NLMSGERR_ATTR_OFFS\n");
+ off = 0;
+ } else if (!(h->nlmsg_flags & NLM_F_CAPPED)) {
+ /*
+ * Header of failed message
+ * we are not doing anything currently with it
+ * but noticing it for later.
+ */
+ err_nlh = &err->msg;
+ zlog_warn("%s: Received %d extended Ack",
+ __PRETTY_FUNCTION__, err_nlh->nlmsg_type);
+ }
+ }
+
+ if (msg && *msg != '\0') {
+ bool is_err = !!err->error;
+
+ if (is_err)
+ zlog_err("Extended Error: %s", msg);
+ else
+ zlog_warn("Extended Warning: %s", msg);
+ }
+}
+
/*
* netlink_parse_info
*
@@ -582,6 +652,23 @@ int netlink_parse_info(int (*filter)(struct nlmsghdr *, ns_id_t, int),
int errnum = err->error;
int msg_type = err->msg.nlmsg_type;
+ if (h->nlmsg_len
+ < NLMSG_LENGTH(sizeof(struct nlmsgerr))) {
+ zlog_err("%s error: message truncated",
+ nl->name);
+ return -1;
+ }
+
+ /*
+ * Parse the extended information before
+ * we actually handle it.
+ * At this point in time we do not
+ * do anything other than report the
+ * issue.
+ */
+ if (h->nlmsg_flags & NLM_F_ACK_TLVS)
+ netlink_parse_extended_ack(h);
+
/* If the error field is zero, then this is an
* ACK */
if (err->error == 0) {
@@ -603,13 +690,6 @@ int netlink_parse_info(int (*filter)(struct nlmsghdr *, ns_id_t, int),
continue;
}
- if (h->nlmsg_len
- < NLMSG_LENGTH(sizeof(struct nlmsgerr))) {
- zlog_err("%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,6 +916,9 @@ int netlink_request(struct nlsock *nl, struct nlmsghdr *n)
void kernel_init(struct zebra_ns *zns)
{
unsigned long groups;
+#if defined SOL_NETLINK
+ int one, ret;
+#endif
/*
* Initialize netlink sockets
@@ -866,6 +949,25 @@ void kernel_init(struct zebra_ns *zns)
zns->netlink_cmd.sock = -1;
netlink_socket(&zns->netlink_cmd, 0, zns->ns_id);
+ /*
+ * SOL_NETLINK is not available on all platforms yet
+ * apparently. It's in bits/socket.h which I am not
+ * sure that we want to pull into our build system.
+ */
+#if defined SOL_NETLINK
+ /*
+ * Let's tell the kernel that we want to receive extended
+ * ACKS over our command socket
+ */
+ one = 1;
+ ret = setsockopt(zns->netlink_cmd.sock, SOL_NETLINK, NETLINK_EXT_ACK,
+ &one, sizeof(one));
+
+ if (ret < 0)
+ zlog_notice("Registration for extended ACK failed : %d %s",
+ errno, safe_strerror(errno));
+#endif
+
/* Register kernel socket. */
if (zns->netlink.sock > 0) {
/* Only want non-blocking on the netlink event socket */
@@ -880,6 +982,7 @@ void kernel_init(struct zebra_ns *zns)
netlink_install_filter(zns->netlink.sock,
zns->netlink_cmd.snl.nl_pid);
zns->t_netlink = NULL;
+
thread_add_read(zebrad.master, kernel_read, zns,
zns->netlink.sock, &zns->t_netlink);
}
diff --git a/zebra/zebra_netns_notify.c b/zebra/zebra_netns_notify.c
index bb6a565211..5feb87b59d 100644
--- a/zebra/zebra_netns_notify.c
+++ b/zebra/zebra_netns_notify.c
@@ -216,7 +216,6 @@ static int zebra_ns_notify_read(struct thread *t)
zlog_err("NS notify read: buffer underflow");
break;
}
- event->name[event->len] = 0;
netnspath = ns_netns_pathname(NULL, event->name);
if (!netnspath)
continue;