diff options
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); @@ -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. */ @@ -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; |
