diff options
| -rw-r--r-- | Makefile.am | 3 | ||||
| -rw-r--r-- | bgpd/bgp_updgrp_adv.c | 2 | ||||
| -rwxr-xr-x | buildtest.sh | 2 | ||||
| -rw-r--r-- | configure.ac | 27 | ||||
| -rw-r--r-- | doc/developer/building-frr-for-centos6.rst | 1 | ||||
| -rw-r--r-- | doc/developer/building-frr-for-centos7.rst | 1 | ||||
| -rw-r--r-- | doc/developer/building-frr-for-centos8.rst | 1 | ||||
| -rw-r--r-- | doc/developer/building-frr-for-debian8.rst | 1 | ||||
| -rw-r--r-- | doc/developer/building-frr-for-debian9.rst | 1 | ||||
| -rw-r--r-- | doc/developer/building-frr-for-netbsd6.rst | 1 | ||||
| -rw-r--r-- | doc/developer/building-frr-for-netbsd7.rst | 1 | ||||
| -rw-r--r-- | doc/developer/include-compile.rst | 1 | ||||
| -rw-r--r-- | doc/developer/topotests.rst | 1 | ||||
| -rw-r--r-- | doc/user/basic.rst | 33 | ||||
| -rw-r--r-- | doc/user/installation.rst | 24 | ||||
| -rw-r--r-- | isisd/isis_nb_config.c | 131 | ||||
| -rw-r--r-- | lib/command.c | 30 | ||||
| -rw-r--r-- | lib/subdir.am | 3 | ||||
| -rw-r--r-- | lib/thread.c | 184 | ||||
| -rw-r--r-- | lib/thread.h | 11 | ||||
| -rw-r--r-- | lib/vty.c | 54 | ||||
| -rw-r--r-- | python/xrelfo.py | 6 | ||||
| -rw-r--r-- | tests/topotests/bgp_route_map/test_route_map_topo1.py | 103 | ||||
| -rw-r--r-- | vtysh/vtysh.c | 4 |
24 files changed, 388 insertions, 238 deletions
diff --git a/Makefile.am b/Makefile.am index a38029dcfa..8c9d7df77c 100644 --- a/Makefile.am +++ b/Makefile.am @@ -109,8 +109,6 @@ CLEANFILES = DISTCLEANFILES = SUFFIXES = -examplesdir = $(exampledir) - bin_PROGRAMS = sbin_PROGRAMS = sbin_SCRIPTS = @@ -122,7 +120,6 @@ lib_LTLIBRARIES = module_LTLIBRARIES = pkginclude_HEADERS = nodist_pkginclude_HEADERS = -dist_examples_DATA = dist_yangmodels_DATA = man_MANS = vtysh_scan = diff --git a/bgpd/bgp_updgrp_adv.c b/bgpd/bgp_updgrp_adv.c index 4dd7597e5f..18829aa747 100644 --- a/bgpd/bgp_updgrp_adv.c +++ b/bgpd/bgp_updgrp_adv.c @@ -839,6 +839,8 @@ void subgroup_default_originate(struct update_subgroup *subgrp, int withdraw) bgp_dest_get_prefix(dest), &tmp_pi); if (ret == RMAP_DENYMATCH) { + /* The aspath belongs to 'attr' */ + tmp_attr.aspath = NULL; bgp_attr_flush(&tmp_attr); continue; } else { diff --git a/buildtest.sh b/buildtest.sh index b4b02d10bf..eeae82fc44 100755 --- a/buildtest.sh +++ b/buildtest.sh @@ -4,7 +4,7 @@ # builds some git commit of FRR in some different configurations # usage: buildtest.sh [commit [configurations...]] -basecfg="--prefix=/usr --enable-user=frr --enable-group=frr --enable-vty-group=frr --enable-configfile-mask=0660 --enable-logfile-mask=0640 --enable-vtysh --sysconfdir=/etc/frr --enable-exampledir=/etc/frr/samples --localstatedir=/var/run/frr --libdir=/usr/lib64/frr --enable-rtadv --disable-static --enable-isisd --enable-multipath=0 --enable-pimd --enable-werror" +basecfg="--prefix=/usr --enable-user=frr --enable-group=frr --enable-vty-group=frr --enable-configfile-mask=0660 --enable-logfile-mask=0640 --enable-vtysh --sysconfdir=/etc/frr --localstatedir=/var/run/frr --libdir=/usr/lib64/frr --enable-rtadv --disable-static --enable-isisd --enable-multipath=0 --enable-pimd --enable-werror" configs_base="gcc|$basecfg" diff --git a/configure.ac b/configure.ac index 96bacc9ed4..0ea209bbfa 100644 --- a/configure.ac +++ b/configure.ac @@ -114,15 +114,6 @@ AC_PATH_PROG([PERL], [perl]) PKG_PROG_PKG_CONFIG dnl default is to match previous behavior -exampledir=${sysconfdir} -AC_ARG_ENABLE([exampledir], - AS_HELP_STRING([--enable-exampledir], - [specify alternate directory for examples]), - exampledir="$enableval",) -dnl XXX add --exampledir to autoconf standard directory list somehow -AC_SUBST([exampledir]) - -dnl default is to match previous behavior pkgsrcrcdir="" AC_ARG_ENABLE([pkgsrcrcdir], AS_HELP_STRING([--enable-pkgsrcrcdir], @@ -663,8 +654,6 @@ AC_ARG_ENABLE([irdp], AS_HELP_STRING([--disable-irdp], [disable IRDP server support in zebra (enabled by default if supported)])) AC_ARG_ENABLE([capabilities], AS_HELP_STRING([--disable-capabilities], [disable using POSIX capabilities])) -AC_ARG_ENABLE([rusage], - AS_HELP_STRING([--disable-rusage], [disable using getrusage])) AC_ARG_ENABLE([gcc_ultra_verbose], AS_HELP_STRING([--enable-gcc-ultra-verbose], [enable ultra verbose GCC warnings])) AC_ARG_ENABLE([backtrace], @@ -794,7 +783,6 @@ fi if test "$enable_datacenter" = "yes" ; then AC_DEFINE([HAVE_DATACENTER], [1], [Compile extensions for a DataCenter]) - AC_MSG_WARN([The --enable-datacenter compile time option is deprecated. Please modify the init script to pass -F datacenter to the daemons instead.]) DFLT_NAME="datacenter" else DFLT_NAME="traditional" @@ -2241,6 +2229,10 @@ AC_CHECK_DECL([CLOCK_MONOTONIC], AC_DEFINE([HAVE_CLOCK_MONOTONIC], [1], [Have monotonic clock]) ], [AC_MSG_RESULT([no])], [FRR_INCLUDES]) +AC_CHECK_DECL([CLOCK_THREAD_CPUTIME_ID], [ + AC_DEFINE([HAVE_CLOCK_THREAD_CPUTIME_ID], [1], [Have cpu-time clock]) +], [AC_MSG_RESULT([no])], [FRR_INCLUDES]) + AC_SEARCH_LIBS([clock_nanosleep], [rt], [ AC_DEFINE([HAVE_CLOCK_NANOSLEEP], [1], [Have clock_nanosleep()]) ]) @@ -2693,7 +2685,6 @@ make : ${MAKE-make} linker flags : ${LDFLAGS} ${SAN_FLAGS} ${LIBS} ${LIBCAP} ${LIBREADLINE} ${LIBM} state file directory : ${frr_statedir} config file directory : `eval echo \`echo ${sysconfdir}\`` -example directory : `eval echo \`echo ${exampledir}\`` module directory : ${CFG_MODULE} script directory : ${CFG_SCRIPT} user to run as : ${enable_user} @@ -2707,6 +2698,16 @@ vici socket path : ${vici_socket} The above user and group must have read/write access to the state file directory and to the config files in the config file directory." +if test -n "$enable_datacenter"; then + AC_MSG_WARN([The --enable-datacenter compile time option is deprecated. Please modify the init script to pass -F datacenter to the daemons instead.]) +fi +if test -n "$enable_time_check"; then + AC_MSG_WARN([The --enable-time-check compile time option is deprecated. Please use the service cputime-stats configuration option instead.]) +fi +if test -n "$enable_cpu_time"; then + AC_MSG_WARN([The --enable-cpu-time compile time option is deprecated. Please use the service cputime-warning NNN configuration option instead.]) +fi + if test "$enable_doc" != "no" -a "$frr_py_mod_sphinx" = "false"; then AC_MSG_WARN([sphinx is missing but required to build documentation]) fi diff --git a/doc/developer/building-frr-for-centos6.rst b/doc/developer/building-frr-for-centos6.rst index 5d3be492de..7a7af42119 100644 --- a/doc/developer/building-frr-for-centos6.rst +++ b/doc/developer/building-frr-for-centos6.rst @@ -172,7 +172,6 @@ an example.) --enable-user=frr \ --enable-group=frr \ --enable-vty-group=frrvty \ - --disable-exampledir \ --disable-ldpd \ --enable-fpm \ --with-pkg-git-version \ diff --git a/doc/developer/building-frr-for-centos7.rst b/doc/developer/building-frr-for-centos7.rst index 8d0aea943c..93b9993a38 100644 --- a/doc/developer/building-frr-for-centos7.rst +++ b/doc/developer/building-frr-for-centos7.rst @@ -67,7 +67,6 @@ an example.) --enable-group=frr \ --enable-vty-group=frrvty \ --enable-systemd=yes \ - --disable-exampledir \ --disable-ldpd \ --enable-fpm \ --with-pkg-git-version \ diff --git a/doc/developer/building-frr-for-centos8.rst b/doc/developer/building-frr-for-centos8.rst index 77fe489358..65c93286b7 100644 --- a/doc/developer/building-frr-for-centos8.rst +++ b/doc/developer/building-frr-for-centos8.rst @@ -60,7 +60,6 @@ an example.) --enable-group=frr \ --enable-vty-group=frrvty \ --enable-systemd=yes \ - --disable-exampledir \ --disable-ldpd \ --enable-fpm \ --with-pkg-git-version \ diff --git a/doc/developer/building-frr-for-debian8.rst b/doc/developer/building-frr-for-debian8.rst index 51dd07c42a..475e0303fc 100644 --- a/doc/developer/building-frr-for-debian8.rst +++ b/doc/developer/building-frr-for-debian8.rst @@ -57,7 +57,6 @@ an example.) cd frr ./bootstrap.sh ./configure \ - --enable-exampledir=/usr/share/doc/frr/examples/ \ --localstatedir=/var/run/frr \ --sbindir=/usr/lib/frr \ --sysconfdir=/etc/frr \ diff --git a/doc/developer/building-frr-for-debian9.rst b/doc/developer/building-frr-for-debian9.rst index 919b010314..1981127b3d 100644 --- a/doc/developer/building-frr-for-debian9.rst +++ b/doc/developer/building-frr-for-debian9.rst @@ -44,7 +44,6 @@ an example.) cd frr ./bootstrap.sh ./configure \ - --enable-exampledir=/usr/share/doc/frr/examples/ \ --localstatedir=/var/opt/frr \ --sbindir=/usr/lib/frr \ --sysconfdir=/etc/frr \ diff --git a/doc/developer/building-frr-for-netbsd6.rst b/doc/developer/building-frr-for-netbsd6.rst index e50d11130a..a78f8b3c2f 100644 --- a/doc/developer/building-frr-for-netbsd6.rst +++ b/doc/developer/building-frr-for-netbsd6.rst @@ -64,7 +64,6 @@ an example) export CPPFLAGS="-I/usr/pkg/include" ./configure \ --sysconfdir=/usr/pkg/etc/frr \ - --enable-exampledir=/usr/pkg/share/examples/frr \ --enable-pkgsrcrcdir=/usr/pkg/share/examples/rc.d \ --localstatedir=/var/run/frr \ --enable-multipath=64 \ diff --git a/doc/developer/building-frr-for-netbsd7.rst b/doc/developer/building-frr-for-netbsd7.rst index 32d1145edc..a52ece19a1 100644 --- a/doc/developer/building-frr-for-netbsd7.rst +++ b/doc/developer/building-frr-for-netbsd7.rst @@ -55,7 +55,6 @@ an example) export CPPFLAGS="-I/usr/pkg/include" ./configure \ --sysconfdir=/usr/pkg/etc/frr \ - --enable-exampledir=/usr/pkg/share/examples/frr \ --enable-pkgsrcrcdir=/usr/pkg/share/examples/rc.d \ --localstatedir=/var/run/frr \ --enable-multipath=64 \ diff --git a/doc/developer/include-compile.rst b/doc/developer/include-compile.rst index 0ff0ae3ffe..d9fa260221 100644 --- a/doc/developer/include-compile.rst +++ b/doc/developer/include-compile.rst @@ -15,7 +15,6 @@ obtained by running ``./configure -h``. The options shown below are examples. ./configure \ --prefix=/usr \ --includedir=\${prefix}/include \ - --enable-exampledir=\${prefix}/share/doc/frr/examples \ --bindir=\${prefix}/bin \ --sbindir=\${prefix}/lib/frr \ --libdir=\${prefix}/lib/frr \ diff --git a/doc/developer/topotests.rst b/doc/developer/topotests.rst index ba03aa9045..18317cd33c 100644 --- a/doc/developer/topotests.rst +++ b/doc/developer/topotests.rst @@ -221,7 +221,6 @@ for ``master`` branch: --prefix=/usr/lib/frr --sysconfdir=/etc/frr \ --localstatedir=/var/run/frr \ --sbindir=/usr/lib/frr --bindir=/usr/lib/frr \ - --enable-exampledir=/usr/lib/frr/examples \ --with-moduledir=/usr/lib/frr/modules \ --enable-multipath=0 --enable-rtadv \ --enable-tcp-zebra --enable-fpm --enable-pimd \ diff --git a/doc/user/basic.rst b/doc/user/basic.rst index 6a0249f316..92357bec83 100644 --- a/doc/user/basic.rst +++ b/doc/user/basic.rst @@ -80,6 +80,39 @@ Basic Config Commands Set enable password. The ``no`` form of the command deletes the enable password. +.. clicmd:: service cputime-stats + + Collect CPU usage statistics for individual FRR event handlers and CLI + commands. This is enabled by default and can be disabled if the extra + overhead causes a noticeable slowdown on your system. + + Disabling these statistics will also make the + :clicmd:`service cputime-warning (1-4294967295)` limit non-functional. + +.. clicmd:: service cputime-warning (1-4294967295) + + Warn if the CPU usage of an event handler or CLI command exceeds the + specified limit (in milliseconds.) Such warnings are generally indicative + of some routine in FRR mistakenly blocking/hogging the processing loop and + should be reported as a FRR bug. + + The default limit is 5 seconds (i.e. 5000), but this can be changed by the + deprecated ``--enable-time-check=...`` compile-time option. + + This command has no effect if :clicmd:`service cputime-stats` is disabled. + +.. clicmd:: service walltime-warning (1-4294967295) + + Warn if the total wallclock time spent handling an event or executing a CLI + command exceeds the specified limit (in milliseconds.) This includes time + spent waiting for I/O or other tasks executing and may produce excessive + warnings if the system is overloaded. (This may still be useful to + provide an immediate sign that FRR is not operating correctly due to + externally caused starvation.) + + The default limit is 5 seconds as above, including the same deprecated + ``--enable-time-check=...`` compile-time option. + .. clicmd:: log trap LEVEL These commands are deprecated and are present only for historical diff --git a/doc/user/installation.rst b/doc/user/installation.rst index f7e45a6231..63254555d9 100644 --- a/doc/user/installation.rst +++ b/doc/user/installation.rst @@ -199,6 +199,10 @@ options from the list below. .. option:: --enable-datacenter + This option is deprecated as it is superseded by the `-F` (profile) command + line option which allows adjusting the setting at startup rather than + compile time. + Enable system defaults to work as if in a Data Center. See defaults.h for what is changed by this configure option. @@ -343,20 +347,17 @@ options from the list below. .. option:: --enable-time-check XXX - When this is enabled with a XXX value in microseconds, any thread that - runs for over this value will cause a warning to be issued to the log. - If you do not specify any value or don't include this option then - the default time is 5 seconds. If --disable-time-check is specified - then no warning is issued for any thread run length. + This option is deprecated as it was replaced by the + :clicmd:`service cputime-stats` CLI command, which may be adjusted at + runtime rather than being a compile-time setting. See there for further + detail. .. option:: --disable-cpu-time - Disable cpu process accounting, this command also disables the `show thread cpu` - command. If this option is disabled, --enable-time-check is ignored. This - disabling of cpu time effectively means that the getrusage call is skipped. - Since this is a process switch into the kernel, systems with high FRR - load might see improvement in behavior. Be aware that `show thread cpu` - is considered a good data gathering tool from the perspective of developers. + This option is deprecated as it was replaced by the + :clicmd:`service cputime-warning NNN` CLI command, which may be adjusted at + runtime rather than being a compile-time setting. See there for further + detail. .. option:: --enable-pcreposix @@ -561,7 +562,6 @@ the options you chose: ./configure \ --prefix=/usr \ - --enable-exampledir=/usr/share/doc/frr/examples/ \ --localstatedir=/var/run/frr \ --sbindir=/usr/lib/frr \ --sysconfdir=/etc/frr \ diff --git a/isisd/isis_nb_config.c b/isisd/isis_nb_config.c index 2622c5b51b..4a01c728f0 100644 --- a/isisd/isis_nb_config.c +++ b/isisd/isis_nb_config.c @@ -111,6 +111,28 @@ int isis_instance_is_type_modify(struct nb_cb_modify_args *args) return NB_OK; } +struct sysid_iter { + struct area_addr *addr; + bool same; +}; + +static int sysid_iter_cb(const struct lyd_node *dnode, void *arg) +{ + struct sysid_iter *iter = arg; + struct area_addr addr; + const char *net; + + net = yang_dnode_get_string(dnode, NULL); + addr.addr_len = dotformat2buff(addr.area_addr, net); + + if (memcmp(GETSYSID(iter->addr), GETSYSID((&addr)), ISIS_SYS_ID_LEN)) { + iter->same = false; + return YANG_ITER_STOP; + } + + return YANG_ITER_CONTINUE; +} + /* * XPath: /frr-isisd:isis/instance/area-address */ @@ -119,14 +141,12 @@ int isis_instance_area_address_create(struct nb_cb_create_args *args) struct isis_area *area; struct area_addr addr, *addrr = NULL, *addrp = NULL; struct listnode *node; + struct sysid_iter iter; uint8_t buff[255]; const char *net_title = yang_dnode_get_string(args->dnode, NULL); switch (args->event) { case NB_EV_VALIDATE: - area = nb_running_get_entry(args->dnode, NULL, false); - if (area == NULL) - return NB_ERR_VALIDATION; addr.addr_len = dotformat2buff(buff, net_title); memcpy(addr.area_addr, buff, addr.addr_len); if (addr.area_addr[addr.addr_len - 1] != 0) { @@ -135,15 +155,18 @@ int isis_instance_area_address_create(struct nb_cb_create_args *args) "nsel byte (last byte) in area address must be 0"); return NB_ERR_VALIDATION; } - if (area->isis->sysid_set) { - /* Check that the SystemID portions match */ - if (memcmp(area->isis->sysid, GETSYSID((&addr)), - ISIS_SYS_ID_LEN)) { - snprintf( - args->errmsg, args->errmsg_len, - "System ID must not change when defining additional area addresses"); - return NB_ERR_VALIDATION; - } + + iter.addr = &addr; + iter.same = true; + + yang_dnode_iterate(sysid_iter_cb, &iter, args->dnode, + "../area-address"); + + if (!iter.same) { + snprintf( + args->errmsg, args->errmsg_len, + "System ID must not change when defining additional area addresses"); + return NB_ERR_VALIDATION; } break; case NB_EV_PREPARE: @@ -2360,14 +2383,14 @@ int isis_instance_segment_routing_prefix_sid_map_prefix_sid_n_flag_clear_modify( int isis_instance_mpls_ldp_sync_create(struct nb_cb_create_args *args) { struct isis_area *area; + const char *vrfname; switch (args->event) { case NB_EV_VALIDATE: - area = nb_running_get_entry(args->dnode, NULL, false); - if (area == NULL || area->isis == NULL) - return NB_ERR_VALIDATION; + vrfname = yang_dnode_get_string( + lyd_parent(lyd_parent(args->dnode)), "./vrf"); - if (area->isis->vrf_id != VRF_DEFAULT) { + if (strcmp(vrfname, VRF_DEFAULT_NAME)) { snprintf(args->errmsg, args->errmsg_len, "LDP-Sync only runs on Default VRF"); return NB_ERR_VALIDATION; @@ -2404,14 +2427,15 @@ int isis_instance_mpls_ldp_sync_holddown_modify(struct nb_cb_modify_args *args) { struct isis_area *area; uint16_t holddown; + const char *vrfname; switch (args->event) { case NB_EV_VALIDATE: - area = nb_running_get_entry(args->dnode, NULL, false); - if (area == NULL || area->isis == NULL) - return NB_ERR_VALIDATION; + vrfname = yang_dnode_get_string( + lyd_parent(lyd_parent(lyd_parent(args->dnode))), + "./vrf"); - if (area->isis->vrf_id != VRF_DEFAULT) { + if (strcmp(vrfname, VRF_DEFAULT_NAME)) { snprintf(args->errmsg, args->errmsg_len, "LDP-Sync only runs on Default VRF"); return NB_ERR_VALIDATION; @@ -3180,26 +3204,14 @@ int lib_interface_isis_mpls_ldp_sync_modify(struct nb_cb_modify_args *args) struct isis_circuit *circuit; struct ldp_sync_info *ldp_sync_info; bool ldp_sync_enable; - struct interface *ifp; + const char *vrfname; switch (args->event) { case NB_EV_VALIDATE: - ifp = nb_running_get_entry( - lyd_parent(lyd_parent(lyd_parent(args->dnode))), NULL, - false); - if (ifp == NULL) - return NB_ERR_VALIDATION; - if (if_is_loopback(ifp)) { - snprintf(args->errmsg, args->errmsg_len, - "LDP-Sync does not run on loopback interface"); - return NB_ERR_VALIDATION; - } - - circuit = nb_running_get_entry(args->dnode, NULL, false); - if (circuit == NULL || circuit->area == NULL) - break; - - if (circuit->isis->vrf_id != VRF_DEFAULT) { + vrfname = yang_dnode_get_string( + lyd_parent(lyd_parent(lyd_parent(args->dnode))), + "./vrf"); + if (strcmp(vrfname, VRF_DEFAULT_NAME)) { snprintf(args->errmsg, args->errmsg_len, "LDP-Sync only runs on Default VRF"); return NB_ERR_VALIDATION; @@ -3236,27 +3248,14 @@ int lib_interface_isis_mpls_holddown_modify(struct nb_cb_modify_args *args) struct isis_circuit *circuit; struct ldp_sync_info *ldp_sync_info; uint16_t holddown; - struct interface *ifp; + const char *vrfname; switch (args->event) { case NB_EV_VALIDATE: - - ifp = nb_running_get_entry( - lyd_parent(lyd_parent(lyd_parent(args->dnode))), NULL, - false); - if (ifp == NULL) - return NB_ERR_VALIDATION; - if (if_is_loopback(ifp)) { - snprintf(args->errmsg, args->errmsg_len, - "LDP-Sync does not run on loopback interface"); - return NB_ERR_VALIDATION; - } - - circuit = nb_running_get_entry(args->dnode, NULL, false); - if (circuit == NULL || circuit->area == NULL) - break; - - if (circuit->isis->vrf_id != VRF_DEFAULT) { + vrfname = yang_dnode_get_string( + lyd_parent(lyd_parent(lyd_parent(args->dnode))), + "./vrf"); + if (strcmp(vrfname, VRF_DEFAULT_NAME)) { snprintf(args->errmsg, args->errmsg_len, "LDP-Sync only runs on Default VRF"); return NB_ERR_VALIDATION; @@ -3282,26 +3281,14 @@ int lib_interface_isis_mpls_holddown_destroy(struct nb_cb_destroy_args *args) { struct isis_circuit *circuit; struct ldp_sync_info *ldp_sync_info; - struct interface *ifp; + const char *vrfname; switch (args->event) { case NB_EV_VALIDATE: - ifp = nb_running_get_entry( - lyd_parent(lyd_parent(lyd_parent(args->dnode))), NULL, - false); - if (ifp == NULL) - return NB_ERR_VALIDATION; - if (if_is_loopback(ifp)) { - snprintf(args->errmsg, args->errmsg_len, - "LDP-Sync does not run on loopback interface"); - return NB_ERR_VALIDATION; - } - - circuit = nb_running_get_entry(args->dnode, NULL, false); - if (circuit == NULL || circuit->area == NULL) - break; - - if (circuit->isis->vrf_id != VRF_DEFAULT) { + vrfname = yang_dnode_get_string( + lyd_parent(lyd_parent(lyd_parent(args->dnode))), + "./vrf"); + if (strcmp(vrfname, VRF_DEFAULT_NAME)) { snprintf(args->errmsg, args->errmsg_len, "LDP-Sync only runs on Default VRF"); return NB_ERR_VALIDATION; diff --git a/lib/command.c b/lib/command.c index 7be54907ed..e00d84a051 100644 --- a/lib/command.c +++ b/lib/command.c @@ -434,6 +434,36 @@ static int config_write_host(struct vty *vty) } log_config_write(vty); + /* print disable always, but enable only if default is flipped + * => prep for future removal of compile-time knob + */ + if (!cputime_enabled) + vty_out(vty, "no service cputime-stats\n"); +#ifdef EXCLUDE_CPU_TIME + else + vty_out(vty, "service cputime-stats\n"); +#endif + + if (!cputime_threshold) + vty_out(vty, "no service cputime-warning\n"); +#if defined(CONSUMED_TIME_CHECK) && CONSUMED_TIME_CHECK != 5000000 + else /* again, always print non-default */ +#else + else if (cputime_threshold != 5000000) +#endif + vty_out(vty, "service cputime-warning %lu\n", + cputime_threshold); + + if (!walltime_threshold) + vty_out(vty, "no service walltime-warning\n"); +#if defined(CONSUMED_TIME_CHECK) && CONSUMED_TIME_CHECK != 5000000 + else /* again, always print non-default */ +#else + else if (walltime_threshold != 5000000) +#endif + vty_out(vty, "service walltime-warning %lu\n", + walltime_threshold); + if (host.advanced) vty_out(vty, "service advanced-vty\n"); diff --git a/lib/subdir.am b/lib/subdir.am index 4015c67ea8..90301d800a 100644 --- a/lib/subdir.am +++ b/lib/subdir.am @@ -168,6 +168,7 @@ clippy_scan += \ lib/northbound_cli.c \ lib/plist.c \ lib/routemap_cli.c \ + lib/thread.c \ lib/vty.c \ # end @@ -463,7 +464,7 @@ endif SUFFIXES += .xref %.xref: % $(CLIPPY) - $(AM_V_XRELFO) $(CLIPPY) $(top_srcdir)/python/xrelfo.py $(XRELFO_FLAGS) -o $@ $< + $(AM_V_XRELFO) $(CLIPPY) $(top_srcdir)/python/xrelfo.py $(WERROR) $(XRELFO_FLAGS) -o $@ $< # dependencies added in python/makefile.py frr.xref: diff --git a/lib/thread.c b/lib/thread.c index 3af89fad5a..835aa38115 100644 --- a/lib/thread.c +++ b/lib/thread.c @@ -90,7 +90,22 @@ static struct list *masters; static void thread_free(struct thread_master *master, struct thread *thread); +#ifndef EXCLUDE_CPU_TIME +#define EXCLUDE_CPU_TIME 0 +#endif +#ifndef CONSUMED_TIME_CHECK +#define CONSUMED_TIME_CHECK 0 +#endif + +bool cputime_enabled = !EXCLUDE_CPU_TIME; +unsigned long cputime_threshold = CONSUMED_TIME_CHECK; +unsigned long walltime_threshold = CONSUMED_TIME_CHECK; + /* CLI start ---------------------------------------------------------------- */ +#ifndef VTYSH_EXTRACT_PL +#include "lib/thread_clippy.c" +#endif + static unsigned int cpu_record_hash_key(const struct cpu_thread_history *a) { int size = sizeof(a->func); @@ -120,7 +135,6 @@ static void cpu_record_hash_free(void *a) XFREE(MTYPE_THREAD_STATS, hist); } -#ifndef EXCLUDE_CPU_TIME static void vty_out_cpu_thread_history(struct vty *vty, struct cpu_thread_history *a) { @@ -187,6 +201,14 @@ static void cpu_record_print(struct vty *vty, uint8_t filter) struct thread_master *m; struct listnode *ln; + if (!cputime_enabled) + vty_out(vty, + "\n" + "Collecting CPU time statistics is currently disabled. Following statistics\n" + "will be zero or may display data from when collection was enabled. Use the\n" + " \"service cputime-stats\" command to start collecting data.\n" + "\nCounters and wallclock times are always maintained and should be accurate.\n"); + memset(&tmp, 0, sizeof(tmp)); tmp.funcname = "TOTAL"; tmp.types = filter; @@ -236,7 +258,6 @@ static void cpu_record_print(struct vty *vty, uint8_t filter) if (tmp.total_calls > 0) vty_out_cpu_thread_history(vty, &tmp); } -#endif static void cpu_record_hash_clear(struct hash_bucket *bucket, void *args[]) { @@ -306,7 +327,6 @@ static uint8_t parse_filter(const char *filterstr) return filter; } -#ifndef EXCLUDE_CPU_TIME DEFUN_NOSH (show_thread_cpu, show_thread_cpu_cmd, "show thread cpu [FILTER]", @@ -331,7 +351,61 @@ DEFUN_NOSH (show_thread_cpu, cpu_record_print(vty, filter); return CMD_SUCCESS; } -#endif + +DEFPY (service_cputime_stats, + service_cputime_stats_cmd, + "[no] service cputime-stats", + NO_STR + "Set up miscellaneous service\n" + "Collect CPU usage statistics\n") +{ + cputime_enabled = !no; + return CMD_SUCCESS; +} + +DEFPY (service_cputime_warning, + service_cputime_warning_cmd, + "[no] service cputime-warning (1-4294967295)", + NO_STR + "Set up miscellaneous service\n" + "Warn for tasks exceeding CPU usage threshold\n" + "Warning threshold in milliseconds\n") +{ + if (no) + cputime_threshold = 0; + else + cputime_threshold = cputime_warning * 1000; + return CMD_SUCCESS; +} + +ALIAS (service_cputime_warning, + no_service_cputime_warning_cmd, + "no service cputime-warning", + NO_STR + "Set up miscellaneous service\n" + "Warn for tasks exceeding CPU usage threshold\n") + +DEFPY (service_walltime_warning, + service_walltime_warning_cmd, + "[no] service walltime-warning (1-4294967295)", + NO_STR + "Set up miscellaneous service\n" + "Warn for tasks exceeding total wallclock threshold\n" + "Warning threshold in milliseconds\n") +{ + if (no) + walltime_threshold = 0; + else + walltime_threshold = walltime_warning * 1000; + return CMD_SUCCESS; +} + +ALIAS (service_walltime_warning, + no_service_walltime_warning_cmd, + "no service walltime-warning", + NO_STR + "Set up miscellaneous service\n" + "Warn for tasks exceeding total wallclock threshold\n") static void show_thread_poll_helper(struct vty *vty, struct thread_master *m) { @@ -421,11 +495,15 @@ DEFUN (clear_thread_cpu, void thread_cmd_init(void) { -#ifndef EXCLUDE_CPU_TIME install_element(VIEW_NODE, &show_thread_cpu_cmd); -#endif install_element(VIEW_NODE, &show_thread_poll_cmd); install_element(ENABLE_NODE, &clear_thread_cpu_cmd); + + install_element(CONFIG_NODE, &service_cputime_stats_cmd); + install_element(CONFIG_NODE, &service_cputime_warning_cmd); + install_element(CONFIG_NODE, &no_service_cputime_warning_cmd); + install_element(CONFIG_NODE, &service_walltime_warning_cmd); + install_element(CONFIG_NODE, &no_service_walltime_warning_cmd); } /* CLI end ------------------------------------------------------------------ */ @@ -1743,9 +1821,14 @@ static unsigned long timeval_elapsed(struct timeval a, struct timeval b) unsigned long thread_consumed_time(RUSAGE_T *now, RUSAGE_T *start, unsigned long *cputime) { +#ifdef HAVE_CLOCK_THREAD_CPUTIME_ID + *cputime = (now->cpu.tv_sec - start->cpu.tv_sec) * TIMER_SECOND_MICRO + + (now->cpu.tv_nsec - start->cpu.tv_nsec) / 1000; +#else /* This is 'user + sys' time. */ *cputime = timeval_elapsed(now->cpu.ru_utime, start->cpu.ru_utime) + timeval_elapsed(now->cpu.ru_stime, start->cpu.ru_stime); +#endif return timeval_elapsed(now->real, start->real); } @@ -1778,13 +1861,23 @@ void thread_set_yield_time(struct thread *thread, unsigned long yield_time) void thread_getrusage(RUSAGE_T *r) { + monotime(&r->real); + if (!cputime_enabled) { + memset(&r->cpu, 0, sizeof(r->cpu)); + return; + } + +#ifdef HAVE_CLOCK_THREAD_CPUTIME_ID + /* not currently implemented in Linux's vDSO, but maybe at some point + * in the future? + */ + clock_gettime(CLOCK_THREAD_CPUTIME_ID, &r->cpu); +#else /* !HAVE_CLOCK_THREAD_CPUTIME_ID */ #if defined RUSAGE_THREAD #define FRR_RUSAGE RUSAGE_THREAD #else #define FRR_RUSAGE RUSAGE_SELF #endif - monotime(&r->real); -#ifndef EXCLUDE_CPU_TIME getrusage(FRR_RUSAGE, &(r->cpu)); #endif } @@ -1802,13 +1895,14 @@ void thread_getrusage(RUSAGE_T *r) */ void thread_call(struct thread *thread) { -#ifndef EXCLUDE_CPU_TIME - _Atomic unsigned long realtime, cputime; - unsigned long exp; - unsigned long helper; -#endif RUSAGE_T before, after; + /* if the thread being called is the CLI, it may change cputime_enabled + * ("service cputime-stats" command), which can result in nonsensical + * and very confusing warnings + */ + bool cputime_enabled_here = cputime_enabled; + if (thread->master->ready_run_loop) before = thread->master->last_getrusage; else @@ -1828,43 +1922,45 @@ void thread_call(struct thread *thread) GETRUSAGE(&after); thread->master->last_getrusage = after; -#ifndef EXCLUDE_CPU_TIME - realtime = thread_consumed_time(&after, &before, &helper); - cputime = helper; + unsigned long walltime, cputime; + unsigned long exp; + + walltime = thread_consumed_time(&after, &before, &cputime); - /* update realtime */ - atomic_fetch_add_explicit(&thread->hist->real.total, realtime, + /* update walltime */ + atomic_fetch_add_explicit(&thread->hist->real.total, walltime, memory_order_seq_cst); exp = atomic_load_explicit(&thread->hist->real.max, memory_order_seq_cst); - while (exp < realtime + while (exp < walltime && !atomic_compare_exchange_weak_explicit( - &thread->hist->real.max, &exp, realtime, - memory_order_seq_cst, memory_order_seq_cst)) + &thread->hist->real.max, &exp, walltime, + memory_order_seq_cst, memory_order_seq_cst)) ; - /* update cputime */ - atomic_fetch_add_explicit(&thread->hist->cpu.total, cputime, - memory_order_seq_cst); - exp = atomic_load_explicit(&thread->hist->cpu.max, - memory_order_seq_cst); - while (exp < cputime - && !atomic_compare_exchange_weak_explicit( - &thread->hist->cpu.max, &exp, cputime, - memory_order_seq_cst, memory_order_seq_cst)) - ; + if (cputime_enabled_here && cputime_enabled) { + /* update cputime */ + atomic_fetch_add_explicit(&thread->hist->cpu.total, cputime, + memory_order_seq_cst); + exp = atomic_load_explicit(&thread->hist->cpu.max, + memory_order_seq_cst); + while (exp < cputime + && !atomic_compare_exchange_weak_explicit( + &thread->hist->cpu.max, &exp, cputime, + memory_order_seq_cst, memory_order_seq_cst)) + ; + } atomic_fetch_add_explicit(&thread->hist->total_calls, 1, memory_order_seq_cst); atomic_fetch_or_explicit(&thread->hist->types, 1 << thread->add_type, memory_order_seq_cst); -#ifdef CONSUMED_TIME_CHECK - if (cputime > CONSUMED_TIME_CHECK) { + if (cputime_enabled_here && cputime_enabled && cputime_threshold + && cputime > cputime_threshold) { /* - * We have a CPU Hog on our hands. The time FRR - * has spent doing actual work ( not sleeping ) - * is greater than 5 seconds. + * We have a CPU Hog on our hands. The time FRR has spent + * doing actual work (not sleeping) is greater than 5 seconds. * Whinge about it now, so we're aware this is yet another task * to fix. */ @@ -1874,13 +1970,13 @@ void thread_call(struct thread *thread) EC_LIB_SLOW_THREAD_CPU, "CPU HOG: task %s (%lx) ran for %lums (cpu time %lums)", thread->xref->funcname, (unsigned long)thread->func, - realtime / 1000, cputime / 1000); - } else if (realtime > CONSUMED_TIME_CHECK) { + walltime / 1000, cputime / 1000); + + } else if (walltime_threshold && walltime > walltime_threshold) { /* - * The runtime for a task is greater than 5 seconds, but - * the cpu time is under 5 seconds. Let's whine - * about this because this could imply some sort of - * scheduling issue. + * The runtime for a task is greater than 5 seconds, but the + * cpu time is under 5 seconds. Let's whine about this because + * this could imply some sort of scheduling issue. */ atomic_fetch_add_explicit(&thread->hist->total_wall_warn, 1, memory_order_seq_cst); @@ -1888,10 +1984,8 @@ void thread_call(struct thread *thread) EC_LIB_SLOW_THREAD_WALL, "STARVATION: task %s (%lx) ran for %lums (cpu time %lums)", thread->xref->funcname, (unsigned long)thread->func, - realtime / 1000, cputime / 1000); + walltime / 1000, cputime / 1000); } -#endif /* CONSUMED_TIME_CHECK */ -#endif /* Exclude CPU Time */ } /* Execute thread */ diff --git a/lib/thread.h b/lib/thread.h index fee728dbf9..abd94ff4f0 100644 --- a/lib/thread.h +++ b/lib/thread.h @@ -33,8 +33,19 @@ extern "C" { #endif +extern bool cputime_enabled; +extern unsigned long cputime_threshold; +/* capturing wallclock time is always enabled since it is fast (reading + * hardware TSC w/o syscalls) + */ +extern unsigned long walltime_threshold; + struct rusage_t { +#ifdef HAVE_CLOCK_THREAD_CPUTIME_ID + struct timespec cpu; +#else struct rusage cpu; +#endif struct timeval real; }; #define RUSAGE_T struct rusage_t @@ -502,37 +502,37 @@ static int vty_command(struct vty *vty, char *buf) zlog_notice("%s%s", prompt_str, buf); } -#ifdef CONSUMED_TIME_CHECK - { - RUSAGE_T before; - RUSAGE_T after; - unsigned long realtime, cputime; + RUSAGE_T before; + RUSAGE_T after; + unsigned long walltime, cputime; - GETRUSAGE(&before); -#endif /* CONSUMED_TIME_CHECK */ + /* cmd_execute() may change cputime_enabled if we're executing the + * "service cputime-stats" command, which can result in nonsensical + * and very confusing warnings + */ + bool cputime_enabled_here = cputime_enabled; - ret = cmd_execute(vty, buf, NULL, 0); + GETRUSAGE(&before); - /* Get the name of the protocol if any */ - protocolname = frr_protoname; + ret = cmd_execute(vty, buf, NULL, 0); -#ifdef CONSUMED_TIME_CHECK - GETRUSAGE(&after); - realtime = thread_consumed_time(&after, &before, &cputime); - if (cputime > CONSUMED_TIME_CHECK) { - /* Warn about CPU hog that must be fixed. */ - flog_warn( - EC_LIB_SLOW_THREAD_CPU, - "CPU HOG: command took %lums (cpu time %lums): %s", - realtime / 1000, cputime / 1000, buf); - } else if (realtime > CONSUMED_TIME_CHECK) { - flog_warn( - EC_LIB_SLOW_THREAD_WALL, - "STARVATION: command took %lums (cpu time %lums): %s", - realtime / 1000, cputime / 1000, buf); - } - } -#endif /* CONSUMED_TIME_CHECK */ + GETRUSAGE(&after); + + walltime = thread_consumed_time(&after, &before, &cputime); + + if (cputime_enabled_here && cputime_enabled && cputime_threshold + && cputime > cputime_threshold) + /* Warn about CPU hog that must be fixed. */ + flog_warn(EC_LIB_SLOW_THREAD_CPU, + "CPU HOG: command took %lums (cpu time %lums): %s", + walltime / 1000, cputime / 1000, buf); + else if (walltime_threshold && walltime > walltime_threshold) + flog_warn(EC_LIB_SLOW_THREAD_WALL, + "STARVATION: command took %lums (cpu time %lums): %s", + walltime / 1000, cputime / 1000, buf); + + /* Get the name of the protocol if any */ + protocolname = frr_protoname; if (ret != CMD_SUCCESS) switch (ret) { diff --git a/python/xrelfo.py b/python/xrelfo.py index 0ecd008579..17262da8d9 100644 --- a/python/xrelfo.py +++ b/python/xrelfo.py @@ -357,6 +357,7 @@ def main(): argp.add_argument('--out-by-file', type=str, help='write by-file JSON output') argp.add_argument('-Wlog-format', action='store_const', const=True) argp.add_argument('-Wlog-args', action='store_const', const=True) + argp.add_argument('-Werror', action='store_const', const=True) argp.add_argument('--profile', action='store_const', const=True) argp.add_argument('binaries', metavar='BINARY', nargs='+', type=str, help='files to read (ELF files or libtool objects)') args = argp.parse_args() @@ -380,9 +381,12 @@ def _main(args): traceback.print_exc() for option in dir(args): - if option.startswith('W'): + if option.startswith('W') and option != 'Werror': checks = sorted(xrelfo.check(args)) sys.stderr.write(''.join([c[-1] for c in checks])) + + if args.Werror and len(checks) > 0: + errors += 1 break diff --git a/tests/topotests/bgp_route_map/test_route_map_topo1.py b/tests/topotests/bgp_route_map/test_route_map_topo1.py index 0158e24d31..74172501db 100644 --- a/tests/topotests/bgp_route_map/test_route_map_topo1.py +++ b/tests/topotests/bgp_route_map/test_route_map_topo1.py @@ -20,47 +20,6 @@ # OF THIS SOFTWARE. # -################################# -# TOPOLOGY -################################# -""" - - +-------+ - +------- | R2 | - | +-------+ - | | - +-------+ | - | R1 | | - +-------+ | - | | - | +-------+ +-------+ - +---------- | R3 |----------| R4 | - +-------+ +-------+ - -""" - -################################# -# TEST SUMMARY -################################# -""" -Following tests are covered to test route-map functionality: -TC_34: - Verify if route-maps is applied in both inbound and - outbound direction to same neighbor/interface. -TC_36: - Test permit/deny statements operation in route-maps with a - permutation and combination of permit/deny in prefix-lists -TC_35: - Test multiple sequence numbers in a single route-map for different - match/set clauses. -TC_37: - Test add/remove route-maps with multiple set - clauses and without any match statement.(Set only) -TC_38: - Test add/remove route-maps with multiple match - clauses and without any set statement.(Match only) -""" - import sys import json import time @@ -91,6 +50,7 @@ from lib.common_config import ( create_bgp_community_lists, interface_status, create_route_maps, + create_static_routes, create_prefix_lists, verify_route_maps, check_address_types, @@ -107,6 +67,46 @@ from lib.bgp import ( ) from lib.topojson import build_topo_from_json, build_config_from_json +################################# +# TOPOLOGY +################################# +""" + + +-------+ + +------- | R2 | + | +-------+ + | | + +-------+ | + | R1 | | + +-------+ | + | | + | +-------+ +-------+ + +---------- | R3 |----------| R4 | + +-------+ +-------+ + +""" + +################################# +# TEST SUMMARY +################################# +""" +Following tests are covered to test route-map functionality: +TC_34: + Verify if route-maps is applied in both inbound and + outbound direction to same neighbor/interface. +TC_36: + Test permit/deny statements operation in route-maps with a + permutation and combination of permit/deny in prefix-lists +TC_35: + Test multiple sequence numbers in a single route-map for different + match/set clauses. +TC_37: + Test add/remove route-maps with multiple set + clauses and without any match statement.(Set only) +TC_38: + Test add/remove route-maps with multiple match + clauses and without any set statement.(Match only) +""" # Global variables bgp_convergence = False @@ -475,8 +475,8 @@ def test_route_map_inbound_outbound_same_neighbor_p0(request): result = verify_rib( tgen, adt, dut, input_dict_2, protocol=protocol, expected=False ) - assert result is not True, "Testcase {} : Failed \n" - "routes are not present in rib \n Error: {}".format(tc_name, result) + assert result is not True, ("Testcase {} : Failed \n" + "routes are not present in rib \n Error: {}".format(tc_name, result)) logger.info("Expected behaviour: {}".format(result)) # Verifying RIB routes @@ -495,8 +495,8 @@ def test_route_map_inbound_outbound_same_neighbor_p0(request): result = verify_rib( tgen, adt, dut, input_dict, protocol=protocol, expected=False ) - assert result is not True, "Testcase {} : Failed \n " - "routes are not present in rib \n Error: {}".format(tc_name, result) + assert result is not True, ("Testcase {} : Failed \n " + "routes are not present in rib \n Error: {}".format(tc_name, result)) logger.info("Expected behaviour: {}".format(result)) write_test_footer(tc_name) @@ -687,14 +687,17 @@ def test_route_map_with_action_values_combination_of_prefix_action_p0( } # tgen.mininet_cli() - result = verify_rib( - tgen, adt, dut, input_dict_2, protocol=protocol, expected=False - ) if "deny" in [prefix_action, rmap_action]: - assert result is not True, "Testcase {} : Failed \n " - "Routes are still present \n Error: {}".format(tc_name, result) + result = verify_rib( + tgen, adt, dut, input_dict_2, protocol=protocol, expected=False + ) + assert result is not True, ("Testcase {} : Failed \n " + "Routes are still present \n Error: {}".format(tc_name, result)) logger.info("Expected behaviour: {}".format(result)) else: + result = verify_rib( + tgen, adt, dut, input_dict_2, protocol=protocol + ) assert result is True, "Testcase {} : Failed \n Error: {}".format( tc_name, result ) diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c index 41b7bc8a10..507c6ce882 100644 --- a/vtysh/vtysh.c +++ b/vtysh/vtysh.c @@ -2851,7 +2851,6 @@ DEFUN (vtysh_show_poll, return show_per_daemon(vty, argv, argc, "Thread statistics for %s:\n"); } -#ifndef EXCLUDE_CPU_TIME DEFUN (vtysh_show_thread, vtysh_show_thread_cmd, "show thread cpu [FILTER]", @@ -2862,7 +2861,6 @@ DEFUN (vtysh_show_thread, { return show_per_daemon(vty, argv, argc, "Thread statistics for %s:\n"); } -#endif DEFUN (vtysh_show_work_queues, vtysh_show_work_queues_cmd, @@ -4567,9 +4565,7 @@ void vtysh_init_vty(void) install_element(VIEW_NODE, &vtysh_show_modules_cmd); install_element(VIEW_NODE, &vtysh_show_work_queues_cmd); install_element(VIEW_NODE, &vtysh_show_work_queues_daemon_cmd); -#ifndef EXCLUDE_CPU_TIME install_element(VIEW_NODE, &vtysh_show_thread_cmd); -#endif install_element(VIEW_NODE, &vtysh_show_poll_cmd); /* Logging */ |
