diff options
53 files changed, 871 insertions, 329 deletions
diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index 7dc3f02b0d..43d0d93520 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -217,6 +217,10 @@ int argv_find_and_parse_afi(struct cmd_token **argv, int argc, int *index, ret = 1; if (afi) *afi = AFI_IP6; + } else if (argv_find(argv, argc, "l2vpn", index)) { + ret = 1; + if (afi) + *afi = AFI_L2VPN; } return ret; } @@ -260,6 +264,10 @@ int argv_find_and_parse_safi(struct cmd_token **argv, int argc, int *index, ret = 1; if (safi) *safi = SAFI_MPLS_VPN; + } else if (argv_find(argv, argc, "evpn", index)) { + ret = 1; + if (safi) + *safi = SAFI_EVPN; } else if (argv_find(argv, argc, "flowspec", index)) { ret = 1; if (safi) diff --git a/configure.ac b/configure.ac index e94cb541ec..77d5ee1555 100755 --- a/configure.ac +++ b/configure.ac @@ -183,15 +183,17 @@ AC_DEFUN([AC_LINK_IFELSE_FLAGS], [{ AC_LINK_IFELSE( [$3], [ - AC_MSG_RESULT([yes]) CFLAGS="$ac_cflags_save" LIBS="$ac_libs_save" - $5 + m4_default([$5], [ + AC_MSG_RESULT([yes]) + ]) ], [ - AC_MSG_RESULT([no]) CFLAGS="$ac_cflags_save" LIBS="$ac_libs_save" - $4 + m4_default([$4], [ + AC_MSG_RESULT([no]) + ]) ]) AC_LANG_POP([C]) }]) @@ -609,92 +611,30 @@ AM_CONDITIONAL([FPM], [test "x$enable_fpm" = "xyes"]) # Python for clippy # -AC_DEFUN([FRR_PYTHON_CHECK_WORKING], [ - AC_MSG_CHECKING([whether we found a working Python version]) - AC_LINK_IFELSE_FLAGS([$PYTHON_CFLAGS], [$PYTHON_LIBS], [AC_LANG_PROGRAM([ -#include <Python.h> -#if PY_VERSION_HEX < 0x02070000 -#error python too old -#endif -int main(void); -], -[ -{ - Py_Initialize(); - return 0; -} -])], [ - # some python installs are missing the zlib dependency... - PYTHON_LIBS="${PYTHON_LIBS} -lz" - AC_LINK_IFELSE_FLAGS([$PYTHON_CFLAGS], [$PYTHON_LIBS], [AC_LANG_PROGRAM([ -#include <Python.h> -#if PY_VERSION_HEX < 0x02070000 -#error python too old -#endif -int main(void); -], -[ -{ - Py_Initialize(); - return 0; -} -])], [ - m4_if([$1], [], [ - PYTHONCONFIG="" - unset PYTHON_LIBS - unset PYTHON_CFLAGS - ], [$1]) - ]) - ]) -]) - AS_IF([test "$host" = "$build"], [ - PYTHONCONFIG="" - - # ordering: - # 1. try python3, but respect the user's preference on which minor ver - # 2. try python, which might be py3 or py2 again on the user's preference - # 3. try python2 (can really only be 2.7 but eh) - # 4. try 3.6 > 3.5 > 3.4 > 3.3 > 3.2 > 2.7 through pkg-config (no user pref) - # - # (AX_PYTHON_DEVEL has no clue about py3 vs py2) - # (AX_PYTHON does not do what we need) - - AC_CHECK_TOOLS([PYTHONCONFIG], [ \ - python3-config \ - python-config \ - python2-config \ - python3.6-config \ - python3.5-config \ - python3.4-config \ - python3.3-config \ - python3.2-config \ - python2.7-config ]) - if test -n "$PYTHONCONFIG"; then - PYTHON_CFLAGS="`\"${PYTHONCONFIG}\" --includes`" - PYTHON_LIBS="`\"${PYTHONCONFIG}\" --ldflags`" - - FRR_PYTHON_CHECK_WORKING([]) - fi + FRR_PYTHON_DEV +], [ + FRR_PYTHON +]) - if test -z "$PYTHONCONFIG"; then - PKG_CHECK_MODULES([PYTHON], [python-3.6], [], [ - PKG_CHECK_MODULES([PYTHON], [python-3.5], [], [ - PKG_CHECK_MODULES([PYTHON], [python-3.4], [], [ - PKG_CHECK_MODULES([PYTHON], [python-3.3], [], [ - PKG_CHECK_MODULES([PYTHON], [python-3.2], [], [ - PKG_CHECK_MODULES([PYTHON], [python-2.7], [], [ - AC_MSG_FAILURE([could not find python-config or pkg-config python, please install Python development files from libpython-dev or similar]) - ])])])])])]) +FRR_PYTHON_MODULES([pytest]) +if test "${enable_doc}" != "no"; then + FRR_PYTHON_MODULES([sphinx], , [ + if test "${enable_doc}" = "yes"; then + AC_MSG_ERROR([Documentation was explicitly requested with --enable-doc but sphinx is not available for $PYTHON. Please disable docs or install sphinx.]) + fi + ]) +fi +AM_CONDITIONAL([DOC], [test "${enable_doc}" != "no" -a "$frr_py_mod_sphinx" != "false"]) +AM_CONDITIONAL([DOC_HTML], [test "${enable_doc_html}" = "yes"]) - FRR_PYTHON_CHECK_WORKING([ - AC_MSG_FAILURE([could not find python-config or pkg-config python, please install Python development files from libpython-dev or similar]) - ]) - fi +FRR_PYTHON_MOD_EXEC([sphinx], [--version], [ + PYSPHINX="-m sphinx" +], [ + PYSPHINX="-c 'import sys; from sphinx import main; sys.exit(main(sys.argv))'" ]) -AC_SUBST([PYTHON_CFLAGS]) -AC_SUBST([PYTHON_LIBS]) +AC_SUBST([PYSPHINX]) # # Logic for protobuf support. @@ -1507,16 +1447,6 @@ FRR_INCLUDES #endif ])dnl -dnl disable doc check -AC_CHECK_PROGS([SPHINXBUILD], [sphinx-build sphinx-build3 sphinx-build2], [/bin/false]) -if test "$SPHINXBUILD" = "/bin/false"; then - if test "${enable_doc}" = "yes"; then - AC_MSG_ERROR([Documentation was explicitly requested with --enable-doc but sphinx-build is not available. Please disable docs or install sphinx.]) - fi -fi -AM_CONDITIONAL([DOC], [test "${enable_doc}" != "no" -a "$SPHINXBUILD" != "/bin/false"]) -AM_CONDITIONAL([DOC_HTML], [test "${enable_doc_html}" = "yes"]) - dnl -------------------- dnl Daemon disable check dnl -------------------- @@ -1666,6 +1596,7 @@ int main(void); return 0; } ])], [ + AC_MSG_RESULT([no]) AC_MSG_ERROR([--enable-snmp given but not usable])]) case "${enable_snmp}" in yes) @@ -2356,7 +2287,9 @@ zebra protobuf enabled : ${enable_protobuf:-no} 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 "${enable_doc}" != "no";then - AS_IF([test "$SPHINXBUILD" = /bin/false], - AC_MSG_WARN([sphinx-build is missing but required to build documentation])) +if test "${enable_doc}" != "no" -a "$frr_py_mod_sphinx" = false; then + AC_MSG_WARN([sphinx is missing but required to build documentation]) +fi +if test "$frr_py_mod_pytest" = false; then + AC_MSG_WARN([pytest is missing, unit tests cannot be performed]) fi diff --git a/doc/developer/building-frr-for-centos6.rst b/doc/developer/building-frr-for-centos6.rst index f1ec2ad3ea..ee0ffc2bf7 100644 --- a/doc/developer/building-frr-for-centos6.rst +++ b/doc/developer/building-frr-for-centos6.rst @@ -163,10 +163,9 @@ an example.) --disable-ldpd \ --enable-fpm \ --with-pkg-git-version \ - --with-pkg-extra-version=-MyOwnFRRVersion \ - SPHINXBUILD=sphinx-build2.7 + --with-pkg-extra-version=-MyOwnFRRVersion make - make check PYTHON=/usr/bin/python2.7 + make check sudo make install Create empty FRR configuration files diff --git a/doc/developer/building-frr-for-debian8.rst b/doc/developer/building-frr-for-debian8.rst index a26d055bc2..76f927853d 100644 --- a/doc/developer/building-frr-for-debian8.rst +++ b/doc/developer/building-frr-for-debian8.rst @@ -16,7 +16,7 @@ Add packages: :: sudo apt-get install git autoconf automake libtool make \ - libreadline-dev texinfo libjson-c-dev pkg-config bison flex python-pip \ + libreadline-dev texinfo libjson-c-dev pkg-config bison flex python3-pip \ libc-ares-dev python3-dev python3-sphinx build-essential libsystemd-dev \ libsnmp-dev @@ -24,7 +24,7 @@ Install newer pytest (>3.0) from pip :: - sudo pip install pytest + sudo pip3 install pytest .. include:: building-libyang.rst diff --git a/doc/developer/building-frr-for-debian9.rst b/doc/developer/building-frr-for-debian9.rst index 2c5a9681af..e58c59f451 100644 --- a/doc/developer/building-frr-for-debian9.rst +++ b/doc/developer/building-frr-for-debian9.rst @@ -9,8 +9,8 @@ Add packages: :: sudo apt-get install git autoconf automake libtool make \ - libreadline-dev texinfo libjson-c-dev pkg-config bison flex python-pip \ - libc-ares-dev python3-dev python-pytest python3-sphinx build-essential \ + libreadline-dev texinfo libjson-c-dev pkg-config bison flex \ + libc-ares-dev python3-dev python3-pytest python3-sphinx build-essential \ libsnmp-dev libsystemd-dev .. include:: building-libyang.rst diff --git a/doc/developer/building-frr-for-fedora.rst b/doc/developer/building-frr-for-fedora.rst index 204c185f56..d11da2d647 100644 --- a/doc/developer/building-frr-for-fedora.rst +++ b/doc/developer/building-frr-for-fedora.rst @@ -13,8 +13,8 @@ Installing Dependencies sudo dnf install git autoconf automake libtool make \ readline-devel texinfo net-snmp-devel groff pkgconfig json-c-devel \ - pam-devel pytest bison flex c-ares-devel python3-devel python2-sphinx \ - perl-core patch + pam-devel python3-pytest bison flex c-ares-devel python3-devel \ + python3-sphinx perl-core patch .. include:: building-libyang.rst diff --git a/doc/developer/building-frr-for-freebsd10.rst b/doc/developer/building-frr-for-freebsd10.rst index 86c44f4d90..e85cb80053 100644 --- a/doc/developer/building-frr-for-freebsd10.rst +++ b/doc/developer/building-frr-for-freebsd10.rst @@ -17,7 +17,7 @@ is first package install and asked) :: pkg install git autoconf automake libtool gmake json-c pkgconf \ - bison flex py27-pytest c-ares python3 py-sphinx + bison flex py36-pytest c-ares python3.6 py36-sphinx Make sure there is no /usr/bin/flex preinstalled (and use the newly installed in /usr/local/bin): (FreeBSD frequently provides a older flex diff --git a/doc/developer/building-frr-for-freebsd11.rst b/doc/developer/building-frr-for-freebsd11.rst index 5e56c8cd7a..b97538b763 100644 --- a/doc/developer/building-frr-for-freebsd11.rst +++ b/doc/developer/building-frr-for-freebsd11.rst @@ -17,7 +17,7 @@ is first package install and asked) .. code-block:: shell pkg install git autoconf automake libtool gmake json-c pkgconf \ - bison flex py27-pytest c-ares python3 py36-sphinx texinfo + bison flex py36-pytest c-ares python3.6 py36-sphinx texinfo Make sure there is no /usr/bin/flex preinstalled (and use the newly installed in /usr/local/bin): (FreeBSD frequently provides a older flex diff --git a/doc/developer/building-frr-for-freebsd9.rst b/doc/developer/building-frr-for-freebsd9.rst index 59241d1d13..1e97749795 100644 --- a/doc/developer/building-frr-for-freebsd9.rst +++ b/doc/developer/building-frr-for-freebsd9.rst @@ -17,8 +17,8 @@ is first package install and asked) :: pkg install -y git autoconf automake libtool gmake \ - pkgconf texinfo json-c bison flex py27-pytest c-ares \ - python3 py-sphinx libexecinfo + pkgconf texinfo json-c bison flex py36-pytest c-ares \ + python3 py36-sphinx libexecinfo Make sure there is no /usr/bin/flex preinstalled (and use the newly installed in /usr/local/bin): (FreeBSD frequently provides a older flex diff --git a/doc/developer/building-frr-for-netbsd6.rst b/doc/developer/building-frr-for-netbsd6.rst index 49091c49b4..e50d11130a 100644 --- a/doc/developer/building-frr-for-netbsd6.rst +++ b/doc/developer/building-frr-for-netbsd6.rst @@ -23,7 +23,7 @@ Add packages: :: sudo pkg_add git autoconf automake libtool gmake openssl \ - pkg-config json-c python27 py27-test python35 py-sphinx + pkg-config json-c py36-test python36 py36-sphinx Install SSL Root Certificates (for git https access): @@ -33,13 +33,6 @@ Install SSL Root Certificates (for git https access): sudo touch /etc/openssl/openssl.cnf sudo mozilla-rootcerts install -Select default Python and py.test - -:: - - sudo ln -s /usr/pkg/bin/python2.7 /usr/bin/python - sudo ln -s /usr/pkg/bin/py.test-2.7 /usr/bin/py.test - .. include:: building-libyang.rst Get FRR, compile it and install it (from Git) diff --git a/doc/developer/building-frr-for-netbsd7.rst b/doc/developer/building-frr-for-netbsd7.rst index 64c462a5c8..32d1145edc 100644 --- a/doc/developer/building-frr-for-netbsd7.rst +++ b/doc/developer/building-frr-for-netbsd7.rst @@ -14,7 +14,7 @@ Install required packages :: sudo pkgin install git autoconf automake libtool gmake openssl \ - pkg-config json-c python27 py27-test python35 py-sphinx + pkg-config json-c python36 py36-test py36-sphinx Install SSL Root Certificates (for git https access): @@ -24,13 +24,6 @@ Install SSL Root Certificates (for git https access): sudo touch /etc/openssl/openssl.cnf sudo mozilla-rootcerts install -Select default Python and py.test - -:: - - sudo ln -s /usr/pkg/bin/python2.7 /usr/bin/python - sudo ln -s /usr/pkg/bin/py.test-2.7 /usr/bin/py.test - .. include:: building-libyang.rst Get FRR, compile it and install it (from Git) diff --git a/doc/developer/building-frr-for-ubuntu1404.rst b/doc/developer/building-frr-for-ubuntu1404.rst index 6e2765c1c8..569b3bded1 100644 --- a/doc/developer/building-frr-for-ubuntu1404.rst +++ b/doc/developer/building-frr-for-ubuntu1404.rst @@ -12,7 +12,7 @@ Installing Dependencies apt-get update apt-get install \ git autoconf automake libtool make libreadline-dev texinfo \ - pkg-config libpam0g-dev libjson-c-dev bison flex python-pytest \ + pkg-config libpam0g-dev libjson-c-dev bison flex python3-pytest \ libc-ares-dev python3-dev python3-sphinx install-info build-essential \ libsnmp-dev perl diff --git a/doc/developer/building-frr-for-ubuntu1604.rst b/doc/developer/building-frr-for-ubuntu1604.rst index a9a0a2f733..03852a62aa 100644 --- a/doc/developer/building-frr-for-ubuntu1604.rst +++ b/doc/developer/building-frr-for-ubuntu1604.rst @@ -12,7 +12,7 @@ Installing Dependencies apt-get update apt-get install \ git autoconf automake libtool make libreadline-dev texinfo \ - pkg-config libpam0g-dev libjson-c-dev bison flex python-pytest \ + pkg-config libpam0g-dev libjson-c-dev bison flex python3-pytest \ libc-ares-dev python3-dev libsystemd-dev python-ipaddress python3-sphinx \ install-info build-essential libsystemd-dev libsnmp-dev perl diff --git a/doc/developer/building-frr-for-ubuntu1804.rst b/doc/developer/building-frr-for-ubuntu1804.rst index 8bdc2b9c76..96c0efe02a 100644 --- a/doc/developer/building-frr-for-ubuntu1804.rst +++ b/doc/developer/building-frr-for-ubuntu1804.rst @@ -12,7 +12,7 @@ Installing Dependencies sudo apt update sudo apt-get install \ git autoconf automake libtool make libreadline-dev texinfo \ - pkg-config libpam0g-dev libjson-c-dev bison flex python-pytest \ + pkg-config libpam0g-dev libjson-c-dev bison flex python3-pytest \ libc-ares-dev python3-dev libsystemd-dev python-ipaddress python3-sphinx \ install-info build-essential libsystemd-dev libsnmp-dev perl diff --git a/doc/developer/packaging-redhat.rst b/doc/developer/packaging-redhat.rst index f6b9931156..d344046148 100644 --- a/doc/developer/packaging-redhat.rst +++ b/doc/developer/packaging-redhat.rst @@ -32,7 +32,7 @@ Tested on CentOS 6, CentOS 7 and Fedora 24. cd frr ./bootstrap.sh - ./configure --with-pkg-extra-version=-MyRPMVersion SPHINXBUILD=sphinx-build2.7 + ./configure --with-pkg-extra-version=-MyRPMVersion make dist .. note:: diff --git a/doc/subdir.am b/doc/subdir.am index 7d3792bf2b..a1297a4f81 100644 --- a/doc/subdir.am +++ b/doc/subdir.am @@ -4,7 +4,6 @@ # You can set these variables from the command line. SPHINXOPTS ?= -SPHINXBUILD ?= sphinx-build PAPER ?= # Internal variables. @@ -32,20 +31,20 @@ am__v_MAKEINFO_1 = doc/%/_build/.doctrees/environment.pickle: $(AM_V_SPHINX) ( \ subdoc="$@"; subdoc="$${subdoc#doc/}"; subdoc="doc/$${subdoc%%/*}"; \ - $(SPHINXBUILD) -a -q -b text -d "$${subdoc}/_build/.doctrees" \ + $(PYTHON) $(PYSPHINX) -a -q -b text -d "$${subdoc}/_build/.doctrees" \ $(ALLSPHINXOPTS) "$(top_srcdir)/$${subdoc}" "$${subdoc}/_build/text" \ ) doc/%/_build/html/.buildinfo: doc/%/_build/.doctrees/environment.pickle $(AM_V_SPHINX) ( \ subdoc="$@"; subdoc="$${subdoc#doc/}"; subdoc="doc/$${subdoc%%/*}"; \ - $(SPHINXBUILD) -q -b html -d "$${subdoc}/_build/.doctrees" \ + $(PYTHON) $(PYSPHINX) -q -b html -d "$${subdoc}/_build/.doctrees" \ $(ALLSPHINXOPTS) "$(top_srcdir)/$${subdoc}" "$${subdoc}/_build/html" \ ) .PRECIOUS: doc/%/_build/texinfo/frr.texi doc/%/_build/texinfo/frr.texi: doc/%/_build/.doctrees/environment.pickle $(AM_V_SPHINX) ( \ subdoc="$@"; subdoc="$${subdoc#doc/}"; subdoc="doc/$${subdoc%%/*}"; \ - $(SPHINXBUILD) -q -b texinfo -d "$${subdoc}/_build/.doctrees" \ + $(PYTHON) $(PYSPHINX) -q -b texinfo -d "$${subdoc}/_build/.doctrees" \ $(ALLSPHINXOPTS) "$(top_srcdir)/$${subdoc}" "$${subdoc}/_build/texinfo" \ ) doc/%/_build/texinfo/frr.info: doc/%/_build/texinfo/frr.texi @@ -54,7 +53,7 @@ doc/%/_build/man/man.stamp: doc/%/_build/.doctrees/environment.pickle $(AM_V_SPHINX) ( \ subdoc="$@"; subdoc="$${subdoc#doc/}"; subdoc="doc/$${subdoc%%/*}"; \ $(MKDIR_P) "$${subdoc}/_build/man"; touch $@.tmp; \ - $(SPHINXBUILD) -a -q -b man -d "$${subdoc}/_build/.doctrees" \ + $(PYTHON) $(PYSPHINX) -a -q -b man -d "$${subdoc}/_build/.doctrees" \ $(ALLSPHINXOPTS) "$(top_srcdir)/$${subdoc}" "$${subdoc}/_build/man" && \ mv -f $@.tmp $@ \ ) @@ -80,7 +79,7 @@ $(M_SPHINXTARGETS): doc/%/_build/.doctrees/environment.pickle builder="$${target##*/}"; \ subdoc="$${target#doc/}"; subdoc="doc/$${subdoc%%/*}"; \ rm -rf "$@"; \ - $(SPHINXBUILD) -q -b $${builder} -d $${subdoc}/_build/.doctrees \ + $(PYTHON) $(PYSPHINX) -q -b $${builder} -d $${subdoc}/_build/.doctrees \ $(ALLSPHINXOPTS) $(top_srcdir)/$${subdoc} $@ \ ) diff --git a/doc/user/installation.rst b/doc/user/installation.rst index 964297292f..6438c11413 100644 --- a/doc/user/installation.rst +++ b/doc/user/installation.rst @@ -347,6 +347,27 @@ compile directory: ./configure --with-libyang-pluginsdir="`pwd`/yang/libyang_plugins/.libs" \ --with-yangmodelsdir="`pwd`/yang" +Python dependency, documentation and tests +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +FRR's documentation and basic unit tests heavily use code written in Python. +Additionally, FRR ships Python extensions written in C which are used during +its build process. + +To this extent, FRR needs the following: + +* an installation of CPython, preferably version 3.2 or newer (2.7 works but + is end of life and will stop working at some point.) +* development files (mostly headers) for that version of CPython +* an installation of `sphinx` for that version of CPython, to build the + documentation +* an installation of `pytest` for that version of CPython, to run the unit + tests + +The `sphinx` and `pytest` dependencies can be avoided by not building +documentation / not running ``make check``, but the CPython dependency is a +hard dependency of the FRR build process (for the `clippy` tool.) + .. _least-privilege-support: Least-Privilege Support diff --git a/eigrpd/eigrp_routemap.c b/eigrpd/eigrp_routemap.c index 0a00497d5a..f080ba4876 100644 --- a/eigrpd/eigrp_routemap.c +++ b/eigrpd/eigrp_routemap.c @@ -764,7 +764,7 @@ static struct route_map_rule_cmd route_set_tag_cmd = { DEFUN (match_metric, match_metric_cmd, - "match metric <0-4294967295>", + "match metric (0-4294967295)", MATCH_STR "Match metric of route\n" "Metric value\n") @@ -787,7 +787,7 @@ DEFUN (no_match_metric, } ALIAS(no_match_metric, no_match_metric_val_cmd, - "no match metric <0-4294967295>", NO_STR MATCH_STR + "no match metric (0-4294967295)", NO_STR MATCH_STR "Match metric of route\n" "Metric value\n") @@ -822,7 +822,7 @@ ALIAS(no_match_interface, no_match_interface_val_cmd, "no match interface WORD", DEFUN (match_ip_next_hop, match_ip_next_hop_cmd, - "match ip next-hop (<1-199>|<1300-2699>|WORD)", + "match ip next-hop ((1-199)|(1300-2699)|WORD)", MATCH_STR IP_STR "Match next-hop address of route\n" @@ -850,7 +850,7 @@ DEFUN (no_match_ip_next_hop, } ALIAS(no_match_ip_next_hop, no_match_ip_next_hop_val_cmd, - "no match ip next-hop (<1-199>|<1300-2699>|WORD)", NO_STR MATCH_STR IP_STR + "no match ip next-hop ((1-199)|(1300-2699)|WORD)", NO_STR MATCH_STR IP_STR "Match next-hop address of route\n" "IP access-list number\n" "IP access-list number (expanded range)\n" @@ -895,7 +895,7 @@ ALIAS(no_match_ip_next_hop_prefix_list, DEFUN (match_ip_address, match_ip_address_cmd, - "match ip address (<1-199>|<1300-2699>|WORD)", + "match ip address ((1-199)|(1300-2699)|WORD)", MATCH_STR IP_STR "Match address of route\n" @@ -922,7 +922,7 @@ DEFUN (no_match_ip_address, } ALIAS(no_match_ip_address, no_match_ip_address_val_cmd, - "no match ip address (<1-199>|<1300-2699>|WORD)", NO_STR MATCH_STR IP_STR + "no match ip address ((1-199)|(1300-2699)|WORD)", NO_STR MATCH_STR IP_STR "Match address of route\n" "IP access-list number\n" "IP access-list number (expanded range)\n" @@ -966,7 +966,7 @@ ALIAS(no_match_ip_address_prefix_list, no_match_ip_address_prefix_list_val_cmd, DEFUN (match_tag, match_tag_cmd, - "match tag <0-65535>", + "match tag (0-65535)", MATCH_STR "Match tag of route\n" "Metric value\n") @@ -987,7 +987,7 @@ DEFUN (no_match_tag, return eigrp_route_match_delete(vty, vty->index, "tag", argv[0]); } -ALIAS(no_match_tag, no_match_tag_val_cmd, "no match tag <0-65535>", +ALIAS(no_match_tag, no_match_tag_val_cmd, "no match tag (0-65535)", NO_STR MATCH_STR "Match tag of route\n" "Metric value\n") @@ -996,7 +996,7 @@ ALIAS(no_match_tag, no_match_tag_val_cmd, "no match tag <0-65535>", DEFUN (set_metric, set_metric_cmd, - "set metric <0-4294967295>", + "set metric (0-4294967295)", SET_STR "Metric value for destination routing protocol\n" "Metric value\n") @@ -1022,7 +1022,7 @@ DEFUN (no_set_metric, } ALIAS(no_set_metric, no_set_metric_val_cmd, - "no set metric (<0-4294967295>|<+/-metric>)", NO_STR SET_STR + "no set metric ((0-4294967295)|<+/-metric>)", NO_STR SET_STR "Metric value for destination routing protocol\n" "Metric value\n" "Add or subtract metric\n") @@ -1069,7 +1069,7 @@ ALIAS(no_set_ip_nexthop, no_set_ip_nexthop_val_cmd, DEFUN (set_tag, set_tag_cmd, - "set tag <0-65535>", + "set tag (0-65535)", SET_STR "Tag value for routing protocol\n" "Tag value\n") @@ -1090,7 +1090,7 @@ DEFUN (no_set_tag, return eigrp_route_set_delete(vty, vty->index, "tag", argv[0]); } -ALIAS(no_set_tag, no_set_tag_val_cmd, "no set tag <0-65535>", NO_STR SET_STR +ALIAS(no_set_tag, no_set_tag_val_cmd, "no set tag (0-65535)", NO_STR SET_STR "Tag value for routing protocol\n" "Tag value\n") diff --git a/eigrpd/eigrp_vty.c b/eigrpd/eigrp_vty.c index fc5bdbdbc5..1a1634ca91 100644 --- a/eigrpd/eigrp_vty.c +++ b/eigrpd/eigrp_vty.c @@ -370,7 +370,7 @@ DEFUN (eigrp_metric_weights, DEFUN (no_eigrp_metric_weights, no_eigrp_metric_weights_cmd, - "no metric weights <0-255> <0-255> <0-255> <0-255> <0-255>", + "no metric weights (0-255) (0-255) (0-255) (0-255) (0-255)", NO_STR "Modify metrics and parameters for advertisement\n" "Modify metric coefficients\n" @@ -1209,7 +1209,7 @@ DEFUN (eigrp_maximum_paths, DEFUN (no_eigrp_maximum_paths, no_eigrp_maximum_paths_cmd, - "no maximum-paths <1-32>", + "no maximum-paths (1-32)", NO_STR "Forward packets over multiple paths\n" "Number of paths\n") diff --git a/lib/compiler.h b/lib/compiler.h index 7509428220..9ce91e3361 100644 --- a/lib/compiler.h +++ b/lib/compiler.h @@ -33,6 +33,9 @@ extern "C" { #endif # define _CONSTRUCTOR(x) constructor(x) # define _DEPRECATED(x) deprecated(x) +# if __has_builtin(assume) +# define assume(x) __builtin_assume(x) +# endif #elif defined(__GNUC__) #if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 9) # define _RET_NONNULL , returns_nonnull @@ -44,12 +47,28 @@ extern "C" { #endif #if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5) # define _DEPRECATED(x) deprecated(x) +# define assume(x) do { if (!(x)) __builtin_unreachable(); } while (0) +#endif +#if __GNUC__ < 5 +# define __has_attribute(x) 0 #endif #if __GNUC__ >= 7 # define _FALLTHROUGH __attribute__((fallthrough)); #endif #endif +#if __has_attribute(hot) +# define _OPTIMIZE_HOT __attribute__((hot)) +#else +# define _OPTIMIZE_HOT +#endif +#if __has_attribute(optimize) +# define _OPTIMIZE_O3 __attribute__((optimize("3"))) +#else +# define _OPTIMIZE_O3 +#endif +#define OPTIMIZE _OPTIMIZE_O3 _OPTIMIZE_HOT + #if !defined(__GNUC__) #error module code needs GCC visibility extensions #elif __GNUC__ < 4 @@ -85,6 +104,9 @@ extern "C" { #ifndef _DEPRECATED #define _DEPRECATED(x) deprecated #endif +#ifndef assume +#define assume(x) +#endif /* pure = function does not modify memory & return value is the same if * memory hasn't changed (=> allows compiler to optimize) @@ -154,6 +154,25 @@ extern void zlog_hexdump(const void *mem, unsigned int len); extern const char *zlog_sanitize(char *buf, size_t bufsz, const void *in, size_t inlen); +/* Note: whenever a new route-type or zserv-command is added the + * corresponding {command,route}_types[] table in lib/log.c MUST be + * updated! */ + +/* Map a route type to a string. For example, ZEBRA_ROUTE_RIPNG -> "ripng". */ +extern const char *zebra_route_string(unsigned int route_type); +/* Map a route type to a char. For example, ZEBRA_ROUTE_RIPNG -> 'R'. */ +extern char zebra_route_char(unsigned int route_type); +/* Map a zserv command type to the same string, + * e.g. ZEBRA_INTERFACE_ADD -> "ZEBRA_INTERFACE_ADD" */ +/* Map a protocol name to its number. e.g. ZEBRA_ROUTE_BGP->9*/ +extern int proto_name2num(const char *s); +/* Map redistribute X argument to protocol number. + * unlike proto_name2num, this accepts shorthands and takes + * an AFI value to restrict input */ +extern int proto_redistnum(int afi, const char *s); + +extern const char *zserv_command_string(unsigned int command); + extern int vzlog_test(int priority); diff --git a/lib/nexthop_group.c b/lib/nexthop_group.c index ed22f64494..10f610db37 100644 --- a/lib/nexthop_group.c +++ b/lib/nexthop_group.c @@ -308,7 +308,7 @@ static void nhgc_delete(struct nexthop_group_cmd *nhgc) DEFINE_QOBJ_TYPE(nexthop_group_cmd) -DEFUN_NOSH(nexthop_group, nexthop_group_cmd, "nexthop-group NAME", +DEFUN_NOSH(nexthop_group, nexthop_group_cmd, "nexthop-group NHGNAME", "Enter into the nexthop-group submode\n" "Specify the NAME of the nexthop-group\n") { @@ -321,7 +321,7 @@ DEFUN_NOSH(nexthop_group, nexthop_group_cmd, "nexthop-group NAME", return CMD_SUCCESS; } -DEFUN_NOSH(no_nexthop_group, no_nexthop_group_cmd, "no nexthop-group NAME", +DEFUN_NOSH(no_nexthop_group, no_nexthop_group_cmd, "no nexthop-group NHGNAME", NO_STR "Delete the nexthop-group\n" "Specify the NAME of the nexthop-group\n") @@ -714,6 +714,19 @@ void nexthop_group_interface_state_change(struct interface *ifp, } } +static void nhg_name_autocomplete(vector comps, struct cmd_token *token) +{ + struct nexthop_group_cmd *nhgc; + + RB_FOREACH (nhgc, nhgc_entry_head, &nhgc_entries) { + vector_set(comps, XSTRDUP(MTYPE_COMPLETION, nhgc->name)); + } +} + +static const struct cmd_variable_handler nhg_name_handlers[] = { + {.tokenname = "NHGNAME", .completions = nhg_name_autocomplete}, + {.completions = NULL}}; + void nexthop_group_init(void (*new)(const char *name), void (*add_nexthop)(const struct nexthop_group_cmd *nhg, const struct nexthop *nhop), @@ -723,6 +736,8 @@ void nexthop_group_init(void (*new)(const char *name), { RB_INIT(nhgc_entry_head, &nhgc_entries); + cmd_variable_handler_register(nhg_name_handlers); + install_node(&nexthop_group_node, nexthop_group_write); install_element(CONFIG_NODE, &nexthop_group_cmd); install_element(CONFIG_NODE, &no_nexthop_group_cmd); diff --git a/lib/ntop.c b/lib/ntop.c new file mode 100644 index 0000000000..d47a0b697a --- /dev/null +++ b/lib/ntop.c @@ -0,0 +1,174 @@ +/* + * optimized ntop, about 10x faster than libc versions [as of 2019] + * + * Copyright (c) 2019 David Lamparter, for NetDEF, Inc. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <stdio.h> +#include <stdint.h> +#include <stdbool.h> +#include <string.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> + +#include "compiler.h" + +#define pos (*posx) + +static inline void putbyte(uint8_t bytex, char **posx) + __attribute__((always_inline)) OPTIMIZE; + +static inline void putbyte(uint8_t bytex, char **posx) +{ + bool zero = false; + int byte = bytex, tmp, a, b; + + if ((tmp = byte - 200) >= 0) { + *pos++ = '2'; + zero = true; + byte = tmp; + } else if ((tmp = byte - 100) >= 0) { + *pos++ = '1'; + zero = true; + byte = tmp; + } + + /* make sure the compiler knows the value range of "byte" */ + assume(byte < 100 && byte >= 0); + + b = byte % 10; + a = byte / 10; + if (a || zero) { + *pos++ = '0' + a; + *pos++ = '0' + b; + } else + *pos++ = '0' + b; +} + +static inline void puthex(uint16_t word, char **posx) + __attribute__((always_inline)) OPTIMIZE; + +static inline void puthex(uint16_t word, char **posx) +{ + const char *digits = "0123456789abcdef"; + if (word >= 0x1000) + *pos++ = digits[(word >> 12) & 0xf]; + if (word >= 0x100) + *pos++ = digits[(word >> 8) & 0xf]; + if (word >= 0x10) + *pos++ = digits[(word >> 4) & 0xf]; + *pos++ = digits[word & 0xf]; +} + +#undef pos + +const char *frr_inet_ntop(int af, const void * restrict src, + char * restrict dst, socklen_t size) + __attribute__((flatten)) DSO_SELF OPTIMIZE; + +const char *frr_inet_ntop(int af, const void * restrict src, + char * restrict dst, socklen_t size) +{ + const uint8_t *b = src; + /* 8 * "abcd:" for IPv6 + * note: the IPv4-embedded IPv6 syntax is only used for ::A.B.C.D, + * which isn't longer than 40 chars either. even with ::ffff:A.B.C.D + * it's shorter. + */ + char buf[8 * 5], *o = buf; + size_t best = 0, bestlen = 0, curlen = 0, i; + + switch (af) { + case AF_INET: +inet4: + putbyte(b[0], &o); + *o++ = '.'; + putbyte(b[1], &o); + *o++ = '.'; + putbyte(b[2], &o); + *o++ = '.'; + putbyte(b[3], &o); + *o++ = '\0'; + break; + case AF_INET6: + for (i = 0; i < 8; i++) { + if (b[i * 2] || b[i * 2 + 1]) { + if (curlen && curlen > bestlen) { + best = i - curlen; + bestlen = curlen; + } + curlen = 0; + continue; + } + curlen++; + } + if (curlen && curlen > bestlen) { + best = i - curlen; + bestlen = curlen; + } + /* do we want ::ffff:A.B.C.D? */ + if (best == 0 && bestlen == 6) { + *o++ = ':'; + *o++ = ':'; + b += 12; + goto inet4; + } + if (bestlen == 1) + bestlen = 0; + + for (i = 0; i < 8; i++) { + if (bestlen && i == best) { + if (i == 0) + *o++ = ':'; + *o++ = ':'; + continue; + } + if (i > best && i < best + bestlen) { + continue; + } + puthex((b[i * 2] << 8) | b[i * 2 + 1], &o); + + if (i < 7) + *o++ = ':'; + } + *o++ = '\0'; + break; + default: + return NULL; + } + + i = o - buf; + if (i > size) + return NULL; + /* compiler might inline memcpy if it knows the length is short, + * although neither gcc nor clang actually do this currently [2019] + */ + assume(i <= 8 * 5); + memcpy(dst, buf, i); + return dst; +} + +#ifndef INET_NTOP_NO_OVERRIDE +/* we want to override libc inet_ntop, but make sure it shows up in backtraces + * as frr_inet_ntop (to avoid confusion while debugging) + */ +const char *inet_ntop(int af, const void *src, char *dst, socklen_t size) + __attribute__((alias ("frr_inet_ntop"))) DSO_SELF; +#endif diff --git a/lib/plist.c b/lib/plist.c index 9957ff1f51..54ea742c66 100644 --- a/lib/plist.c +++ b/lib/plist.c @@ -1009,7 +1009,7 @@ static int vty_prefix_list_uninstall(struct vty *vty, afi_t afi, if (pentry == NULL) { vty_out(vty, - "%% Can't find prefix-list %s with sequence number %lu\n", + "%% Can't find prefix-list %s with sequence number %" PRIu64 "\n", name, seqnum); return CMD_WARNING_CONFIG_FAILED; } diff --git a/lib/printf/printf-pos.c b/lib/printf/printf-pos.c index 399573e6c1..1f5f283e82 100644 --- a/lib/printf/printf-pos.c +++ b/lib/printf/printf-pos.c @@ -54,6 +54,7 @@ #include <stdio.h> #include <stdlib.h> #include <string.h> +#include <strings.h> #include <wchar.h> #include "printflocal.h" diff --git a/lib/sockopt.c b/lib/sockopt.c index 89f3d5b594..8e38a29278 100644 --- a/lib/sockopt.c +++ b/lib/sockopt.c @@ -701,6 +701,12 @@ int sockopt_tcp_signature_ext(int sock, union sockunion *su, uint16_t prefixlen, } return ret; #endif /* HAVE_TCP_MD5SIG */ + + /* + * Making compiler happy. If we get to this point we probably + * have done something really really wrong. + */ + return -2; } int sockopt_tcp_signature(int sock, union sockunion *su, const char *password) diff --git a/lib/subdir.am b/lib/subdir.am index 50ff1feecc..4e6adced74 100644 --- a/lib/subdir.am +++ b/lib/subdir.am @@ -56,6 +56,7 @@ lib_libfrr_la_SOURCES = \ lib/northbound.c \ lib/northbound_cli.c \ lib/northbound_db.c \ + lib/ntop.c \ lib/openbsd-tree.c \ lib/pid_output.c \ lib/plist.c \ diff --git a/lib/thread.c b/lib/thread.c index d3fb2cdf36..3879e936a1 100644 --- a/lib/thread.c +++ b/lib/thread.c @@ -95,7 +95,7 @@ static void cpu_record_hash_free(void *a) static void vty_out_cpu_thread_history(struct vty *vty, struct cpu_thread_history *a) { - vty_out(vty, "%5zu %10zu.%03lu %9zu %8zu %9zu %8lu %9lu", + vty_out(vty, "%5zu %10zu.%03zu %9zu %8zu %9zu %8zu %9zu", a->total_active, a->cpu.total / 1000, a->cpu.total % 1000, a->total_calls, a->cpu.total / a->total_calls, a->cpu.max, a->real.total / a->total_calls, a->real.max); diff --git a/lib/zclient.h b/lib/zclient.h index c61c8d4226..d651738687 100644 --- a/lib/zclient.h +++ b/lib/zclient.h @@ -38,6 +38,15 @@ #include "mlag.h" +/* Zebra types. Used in Zserv message header. */ +typedef uint16_t zebra_size_t; + +/* Marker value used in new Zserv, in the byte location corresponding + * the command value in the old zserv header. To allow old and new + * Zserv headers to be distinguished from each other. + */ +#define ZEBRA_HEADER_MARKER 254 + /* For input/output buffer to zebra. */ #define ZEBRA_MAX_PACKET_SIZ 16384U @@ -322,6 +331,41 @@ struct zapi_route { unsigned short instance; uint32_t flags; +/* + * Cause Zebra to consider this routes nexthops recursively + */ +#define ZEBRA_FLAG_ALLOW_RECURSION 0x01 +/* + * This is a route that is read in on startup that was left around + * from a previous run of FRR + */ +#define ZEBRA_FLAG_SELFROUTE 0x02 +/* + * This flag is used to tell Zebra that the BGP route being passed + * down is a IBGP route + */ +#define ZEBRA_FLAG_IBGP 0x04 +/* + * This is a route that has been selected for FIB installation. + * This flag is set in zebra and can be passed up to routing daemons + */ +#define ZEBRA_FLAG_SELECTED 0x08 +/* + * This is a route that we are telling Zebra that this route *must* + * win and will be installed even over ZEBRA_FLAG_SELECTED + */ +#define ZEBRA_FLAG_FIB_OVERRIDE 0x10 +/* + * This flag tells Zebra that the route is a EVPN route and should + * be treated specially + */ +#define ZEBRA_FLAG_EVPN_ROUTE 0x20 +/* + * This flag tells Zebra that it should treat the distance passed + * down as an additional discriminator for route selection of the + * route entry. This mainly is used for backup static routes. + */ +#define ZEBRA_FLAG_RR_USE_DISTANCE 0x40 uint8_t message; diff --git a/lib/zebra.h b/lib/zebra.h index 3e1eefdb2e..2f9ada09be 100644 --- a/lib/zebra.h +++ b/lib/zebra.h @@ -202,18 +202,12 @@ typedef unsigned char uint8_t; /* Some systems do not define UINT32_MAX, etc.. from inttypes.h * e.g. this makes life easier for FBSD 4.11 users. */ -#ifndef INT8_MAX -#define INT8_MAX (127) -#endif #ifndef INT16_MAX #define INT16_MAX (32767) #endif #ifndef INT32_MAX #define INT32_MAX (2147483647) #endif -#ifndef UINT8_MAX -#define UINT8_MAX (255U) -#endif #ifndef UINT16_MAX #define UINT16_MAX (65535U) #endif @@ -343,12 +337,6 @@ struct in_pktinfo { /* default zebra TCP port for zclient */ #define ZEBRA_PORT 2600 -/* Marker value used in new Zserv, in the byte location corresponding - * the command value in the old zserv header. To allow old and new - * Zserv headers to be distinguished from each other. - */ -#define ZEBRA_HEADER_MARKER 254 - /* * The compiler.h header is used for anyone using the CPP_NOTICE * since this is universally needed, let's add it to zebra.h @@ -358,65 +346,8 @@ struct in_pktinfo { /* Zebra route's types are defined in route_types.h */ #include "route_types.h" -/* Note: whenever a new route-type or zserv-command is added the - * corresponding {command,route}_types[] table in lib/log.c MUST be - * updated! */ - -/* Map a route type to a string. For example, ZEBRA_ROUTE_RIPNG -> "ripng". */ -extern const char *zebra_route_string(unsigned int route_type); -/* Map a route type to a char. For example, ZEBRA_ROUTE_RIPNG -> 'R'. */ -extern char zebra_route_char(unsigned int route_type); -/* Map a zserv command type to the same string, - * e.g. ZEBRA_INTERFACE_ADD -> "ZEBRA_INTERFACE_ADD" */ -/* Map a protocol name to its number. e.g. ZEBRA_ROUTE_BGP->9*/ -extern int proto_name2num(const char *s); -/* Map redistribute X argument to protocol number. - * unlike proto_name2num, this accepts shorthands and takes - * an AFI value to restrict input */ -extern int proto_redistnum(int afi, const char *s); - -extern const char *zserv_command_string(unsigned int command); - #define strmatch(a,b) (!strcmp((a), (b))) -/* Zebra message flags */ - -/* - * Cause Zebra to consider this routes nexthops recursively - */ -#define ZEBRA_FLAG_ALLOW_RECURSION 0x01 -/* - * This is a route that is read in on startup that was left around - * from a previous run of FRR - */ -#define ZEBRA_FLAG_SELFROUTE 0x02 -/* - * This flag is used to tell Zebra that the BGP route being passed - * down is a IBGP route - */ -#define ZEBRA_FLAG_IBGP 0x04 -/* - * This is a route that has been selected for FIB installation. - * This flag is set in zebra and can be passed up to routing daemons - */ -#define ZEBRA_FLAG_SELECTED 0x08 -/* - * This is a route that we are telling Zebra that this route *must* - * win and will be installed even over ZEBRA_FLAG_SELECTED - */ -#define ZEBRA_FLAG_FIB_OVERRIDE 0x10 -/* - * This flag tells Zebra that the route is a EVPN route and should - * be treated specially - */ -#define ZEBRA_FLAG_EVPN_ROUTE 0x20 -/* - * This flag tells Zebra that it should treat the distance passed - * down as an additional discriminator for route selection of the - * route entry. This mainly is used for backup static routes. - */ -#define ZEBRA_FLAG_RR_USE_DISTANCE 0x40 - #ifndef INADDR_LOOPBACK #define INADDR_LOOPBACK 0x7f000001 /* Internet address 127.0.0.1. */ #endif @@ -501,10 +432,6 @@ typedef enum { #define RESET_FLAG_ATOMIC(PV) \ ((atomic_store_explicit(PV, 0, memory_order_seq_cst))) -/* Zebra types. Used in Zserv message header. */ -typedef uint16_t zebra_size_t; -typedef uint16_t zebra_command_t; - /* VRF ID type. */ typedef uint32_t vrf_id_t; diff --git a/m4/.gitignore b/m4/.gitignore index 2c04163659..cc778b9e99 100644 --- a/m4/.gitignore +++ b/m4/.gitignore @@ -4,6 +4,7 @@ !ax_compare_version.m4 !ax_prog_perl_modules.m4 !ax_pthread.m4 +!ax_python.m4 !ax_sys_weak_alias.m4 !ax_sys_weak_alias.m4 !pkg.m4 diff --git a/m4/ax_python.m4 b/m4/ax_python.m4 new file mode 100644 index 0000000000..32043c81ae --- /dev/null +++ b/m4/ax_python.m4 @@ -0,0 +1,284 @@ +dnl FRR Python autoconf magic +dnl 2019 David Lamparter for NetDEF, Inc. +dnl SPDX-License-Identifier: GPL-2.0-or-later + +dnl the _ at the beginning will be cut off (to support the empty version string) +m4_define_default([_FRR_PY_VERS], [_3 _ _2 _3.7 _3.6 _3.5 _3.4 _3.3 _3.2 _2.7]) + +dnl check basic interpreter properties (py2/py3) +dnl doubles as simple check whether the interpreter actually works +dnl also swaps in the full path to the interpreter +dnl arg1: if-true, arg2: if-false +AC_DEFUN([_FRR_PYTHON_INTERP], [dnl +AC_ARG_VAR([PYTHON], [Python interpreter to use])dnl + AC_MSG_CHECKING([python interpreter $PYTHON]) + AC_RUN_LOG(["$PYTHON" -c 'import sys; open("conftest.pyver", "w").write(sys.executable or ""); sys.exit(not (sys.version_info.major == 2 and sys.version_info.minor >= 7))']) + py2=$ac_status + _py2_full="`cat conftest.pyver 2>/dev/null`" + rm -f "conftest.pyver" >/dev/null 2>/dev/null + + AC_RUN_LOG(["$PYTHON" -c 'import sys; open("conftest.pyver", "w").write(sys.executable or ""); sys.exit(not ((sys.version_info.major == 3 and sys.version_info.minor >= 2) or sys.version_info.major > 3))']) + py3=$ac_status + _py3_full="`cat conftest.pyver 2>/dev/null`" + rm -f "conftest.pyver" >/dev/null 2>/dev/null + + case "p${py2}p${py3}" in + p0p1) frr_cv_python=python2 + _python_full="$_py2_full" ;; + p1p0) frr_cv_python=python3 + _python_full="$_py3_full" ;; + *) frr_cv_python=none ;; + esac + + if test "$frr_cv_python" = none; then + AC_MSG_RESULT([not working]) + $2 + else + test -n "$_python_full" -a -x "$_python_full" && PYTHON="$_python_full" + AC_MSG_RESULT([$PYTHON ($frr_cv_python)]) + $1 + fi + + dnl return value + test "$frr_cv_python" != none +]) + +dnl check whether $PYTHON has modules available +dnl arg1: list of modules (space separated) +dnl arg2: if all true, arg3: if any missing +dnl also sets frr_py_mod_<name> to "true" or "false" +AC_DEFUN([FRR_PYTHON_MODULES], [ + result=true + for pymod in $1; do + AC_MSG_CHECKING([whether $PYTHON module $pymod is available]) + AC_RUN_LOG(["$PYTHON" -c "import $pymod"]) + sane="`echo \"$pymod\" | tr -c '[a-zA-Z0-9\n]' '_'`" + if test "$ac_status" -eq 0; then + AC_MSG_RESULT([yes]) + eval frr_py_mod_$sane=true + else + AC_MSG_RESULT([no]) + eval frr_py_mod_$sane=false + result=false + fi + done + if $result; then + m4_default([$2], [:]) + else + m4_default([$3], [:]) + fi + $result +]) + +dnl check whether $PYTHON has modules available +dnl arg1: list of modules (space separated) +dnl arg2: command line parameters for executing +dnl arg3: if all true, arg4: if any missing +dnl also sets frr_py_modexec_<name> to "true" or "false" +AC_DEFUN([FRR_PYTHON_MOD_EXEC], [ + result=true + for pymod in $1; do + AC_MSG_CHECKING([whether $PYTHON module $pymod is executable]) + AC_RUN_LOG(["$PYTHON" -m "$pymod" $2 > /dev/null]) + sane="`echo \"$pymod\" | tr -c '[a-zA-Z0-9\n]' '_'`" + if test "$ac_status" -eq 0; then + AC_MSG_RESULT([yes]) + eval frr_py_modexec_$sane=true + else + AC_MSG_RESULT([no]) + eval frr_py_modexec_$sane=false + result=false + fi + done + if $result; then + m4_default([$3], [:]) + else + m4_default([$4], [:]) + fi + $result +]) + +dnl check whether we can build & link python bits +dnl input: PYTHON_CFLAGS and PYTHON_LIBS +AC_DEFUN([_FRR_PYTHON_DEVENV], [ + result=true + AC_LINK_IFELSE_FLAGS([$PYTHON_CFLAGS], [$PYTHON_LIBS], [AC_LANG_PROGRAM([ +#include <Python.h> +#if PY_VERSION_HEX < 0x02070000 +#error python too old +#endif +int main(void); +], +[ +{ + Py_Initialize(); + return 0; +} +])], [ + # some python installs are missing the zlib dependency... + PYTHON_LIBS="${PYTHON_LIBS} -lz" + AC_LINK_IFELSE_FLAGS([$PYTHON_CFLAGS], [$PYTHON_LIBS], [AC_LANG_PROGRAM([ +#include <Python.h> +#if PY_VERSION_HEX < 0x02070000 +#error python too old +#endif +int main(void); +], +[ +{ + Py_Initialize(); + return 0; +} +])], [ + result=false + AC_MSG_RESULT([no]) + ], [:]) + ], [:]) + + if $result; then + AC_LINK_IFELSE_FLAGS([$PYTHON_CFLAGS], [$PYTHON_LIBS], [AC_LANG_PROGRAM([ +#include <Python.h> +#if PY_VERSION_HEX != $1 +#error python version mismatch +#endif +int main(void); +], +[ +{ + Py_Initialize(); + return 0; +} +])], [ + result=false + AC_MSG_RESULT([version mismatch]) + ], [ + AC_MSG_RESULT([yes]) + ]) + fi + + if $result; then + m4_default([$2], [:]) + else + m4_default([$3], [ + unset PYTHON_LIBS + unset PYTHON_CFLAGS + ]) + fi +]) + +AC_DEFUN([_FRR_PYTHON_GETDEV], [dnl +AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl + + py_abi="` \"$1\" -c \"import sys; print(getattr(sys, 'abiflags', ''))\"`" + py_hex="` \"$1\" -c \"import sys; print(hex(sys.hexversion))\"`" + py_ldver="` \"$1\" -c \"import sysconfig; print(sysconfig.get_config_var('LDVERSION') or '')\"`" + py_ver="` \"$1\" -c \"import sysconfig; print(sysconfig.get_config_var('VERSION') or '')\"`" + py_bindir="`\"$1\" -c \"import sysconfig; print(sysconfig.get_config_var('BINDIR') or '')\"`" + test -z "$py_bindir" || py_bindir="$py_bindir/" + echo "py_abi=${py_abi} py_ldver=${py_ldver} py_ver=${py_ver} py_bindir=${py_bindir}" >&AS_MESSAGE_LOG_FD + + py_found=false + + for tryver in "${py_ldver}" "${py_ver}"; do + pycfg="${py_bindir}python${tryver}-config" + AC_MSG_CHECKING([whether ${pycfg} is available]) + if "$pycfg" --configdir >/dev/null 2>/dev/null; then + AC_MSG_RESULT([yes]) + + PYTHON_CFLAGS="`\"$pycfg\" --includes`" + PYTHON_LIBS="`\"$pycfg\" --ldflags`" + + AC_MSG_CHECKING([whether ${pycfg} provides a working build environment]) + _FRR_PYTHON_DEVENV([$py_hex], [ + py_found=true + break + ]) + else + AC_MSG_RESULT([no]) + fi + + pkg_failed=no + AC_MSG_CHECKING([whether pkg-config python-${tryver} is available]) + unset PYTHON_CFLAGS + unset PYTHON_LIBS + pkg="python-${tryver}" + pkg="${pkg%-}" + _PKG_CONFIG([PYTHON_CFLAGS], [cflags], [${pkg}]) + _PKG_CONFIG([PYTHON_LIBS], [libs], [${pkg}]) + if test $pkg_failed = no; then + AC_MSG_RESULT([yes]) + + PYTHON_CFLAGS=$pkg_cv_PYTHON_CFLAGS + PYTHON_LIBS=$pkg_cv_PYTHON_LIBS + + AC_MSG_CHECKING([whether pkg-config python-${tryver} provides a working build environment]) + _FRR_PYTHON_DEVENV([$py_hex], [ + py_found=true + break + ]) + else + AC_MSG_RESULT([no]) + fi + done + + if $py_found; then + m4_default([$2], [:]) + else + unset PYTHON_CFLAGS + unset PYTHON_LIBS + m4_default([$3], [:]) + fi +]) + +dnl just find python without checking headers/libs +AC_DEFUN([FRR_PYTHON], [ + dnl user override + if test "x$PYTHON" != "x"; then + _FRR_PYTHON_INTERP([], [ + AC_MSG_ERROR([PYTHON ($PYTHON) explicitly specified but not working]) + ]) + else + for frr_pyver in _FRR_PY_VERS; do + PYTHON="python${frr_pyver#_}" + _FRR_PYTHON_INTERP([break]) + PYTHON=":" + done + if test "$PYTHON" = ":"; then + AC_MSG_ERROR([no working python version found]) + fi + fi + AC_SUBST([PYTHON]) +]) + +dnl find python with checking headers/libs +AC_DEFUN([FRR_PYTHON_DEV], [dnl +AC_ARG_VAR([PYTHON_CFLAGS], [C compiler flags for Python])dnl +AC_ARG_VAR([PYTHON_LIBS], [linker flags for Python])dnl + + dnl user override + if test "x$PYTHON" != "x"; then + _FRR_PYTHON_INTERP([], [ + AC_MSG_ERROR([PYTHON ($PYTHON) explicitly specified but not working]) + ]) + _FRR_PYTHON_GETDEV([$PYTHON], [], [ + AC_MSG_ERROR([PYTHON ($PYTHON) explicitly specified but development environment not working]) + ]) + else + for frr_pyver in _FRR_PY_VERS; do + PYTHON="python${frr_pyver#_}" + _FRR_PYTHON_INTERP([ + _FRR_PYTHON_GETDEV([$PYTHON], [ + break + ]) + ]) + PYTHON=":" + done + if test "$PYTHON" = ":"; then + AC_MSG_ERROR([no working python version found]) + fi + fi + + AC_SUBST([PYTHON_CFLAGS]) + AC_SUBST([PYTHON_LIBS]) + AC_SUBST([PYTHON]) +]) diff --git a/pbrd/pbr_nht.c b/pbrd/pbr_nht.c index fc78b8ed1f..22dd6f1a38 100644 --- a/pbrd/pbr_nht.c +++ b/pbrd/pbr_nht.c @@ -66,6 +66,8 @@ static void *pbr_nhrc_hash_alloc(void *p) { struct nhrc *nhrc = XCALLOC(MTYPE_PBR_NHG, sizeof(struct nhrc)); nhrc->nexthop = *(struct nexthop *)p; + nhrc->nexthop.next = NULL; + nhrc->nexthop.prev = NULL; return nhrc; } @@ -712,10 +714,30 @@ static void pbr_nht_individual_nexthop_update_lookup(struct hash_bucket *b, pnhi->valid += 1; } +static void pbr_nexthop_group_cache_iterate_to_group(struct hash_bucket *b, + void *data) +{ + struct pbr_nexthop_cache *pnhc = b->data; + struct nexthop_group *nhg = data; + struct nexthop *nh = NULL; + + copy_nexthops(&nh, pnhc->nexthop, NULL); + + nexthop_add(&nhg->nexthop, nh); +} + +static void +pbr_nexthop_group_cache_to_nexthop_group(struct nexthop_group *nhg, + struct pbr_nexthop_group_cache *pnhgc) +{ + hash_iterate(pnhgc->nhh, pbr_nexthop_group_cache_iterate_to_group, nhg); +} + static void pbr_nht_nexthop_update_lookup(struct hash_bucket *b, void *data) { struct pbr_nexthop_group_cache *pnhgc = b->data; struct pbr_nht_individual pnhi; + struct nexthop_group nhg = {}; bool old_valid; old_valid = pnhgc->valid; @@ -730,6 +752,13 @@ static void pbr_nht_nexthop_update_lookup(struct hash_bucket *b, void *data) */ pnhgc->valid = !!pnhi.valid; + if (pnhgc->valid) { + pbr_nexthop_group_cache_to_nexthop_group(&nhg, pnhgc); + pbr_nht_install_nexthop_group(pnhgc, nhg); + /* Don't need copied nexthops anymore */ + nexthops_free(nhg.nexthop); + } + if (old_valid != pnhgc->valid) pbr_map_check_nh_group_change(pnhgc->name); } diff --git a/pbrd/pbr_vty.c b/pbrd/pbr_vty.c index 067d5c01fd..a71c712ea7 100644 --- a/pbrd/pbr_vty.c +++ b/pbrd/pbr_vty.c @@ -38,7 +38,7 @@ #include "pbrd/pbr_vty_clippy.c" #endif -DEFUN_NOSH(pbr_map, pbr_map_cmd, "pbr-map WORD seq (1-700)", +DEFUN_NOSH(pbr_map, pbr_map_cmd, "pbr-map PBRMAP seq (1-700)", "Create pbr-map or enter pbr-map command mode\n" "The name of the PBR MAP\n" "Sequence to insert in existing pbr-map entry\n" @@ -54,7 +54,7 @@ DEFUN_NOSH(pbr_map, pbr_map_cmd, "pbr-map WORD seq (1-700)", return CMD_SUCCESS; } -DEFUN_NOSH(no_pbr_map, no_pbr_map_cmd, "no pbr-map WORD [seq (1-700)]", +DEFUN_NOSH(no_pbr_map, no_pbr_map_cmd, "no pbr-map PBRMAP [seq (1-700)]", NO_STR "Delete pbr-map\n" "The name of the PBR MAP\n" @@ -172,7 +172,7 @@ DEFPY(pbr_map_match_dst, pbr_map_match_dst_cmd, } DEFPY(pbr_map_nexthop_group, pbr_map_nexthop_group_cmd, - "[no] set nexthop-group NAME$name", + "[no] set nexthop-group NHGNAME$name", NO_STR "Set for the PBR-MAP\n" "nexthop-group to use\n" @@ -348,7 +348,7 @@ DEFPY(pbr_map_nexthop, pbr_map_nexthop_cmd, DEFPY (pbr_policy, pbr_policy_cmd, - "[no] pbr-policy NAME$mapname", + "[no] pbr-policy PBRMAP$mapname", NO_STR "Policy to use\n" "Name of the pbr-map to apply\n") @@ -661,8 +661,27 @@ static int pbr_vty_map_config_write(struct vty *vty) return 1; } +static void pbr_map_completer(vector comps, struct cmd_token *token) +{ + struct pbr_map *pbrm; + + RB_FOREACH (pbrm, pbr_map_entry_head, &pbr_maps) + vector_set(comps, XSTRDUP(MTYPE_COMPLETION, pbrm->name)); +} + +static const struct cmd_variable_handler pbr_map_name[] = { + { + .tokenname = "PBRMAP", .completions = pbr_map_completer, + }, + { + .completions = NULL + } +}; + void pbr_vty_init(void) { + cmd_variable_handler_register(pbr_map_name); + install_node(&interface_node, pbr_interface_config_write); if_cmd_init(); diff --git a/pimd/mtracebis.c b/pimd/mtracebis.c index 65c495eff0..dd95762754 100644 --- a/pimd/mtracebis.c +++ b/pimd/mtracebis.c @@ -17,9 +17,7 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif +#include <zebra.h> #ifdef __linux__ diff --git a/pimd/pim_cmd.c b/pimd/pim_cmd.c index 7788191454..6591bdc32e 100644 --- a/pimd/pim_cmd.c +++ b/pimd/pim_cmd.c @@ -1536,7 +1536,7 @@ static void pim_show_interface_traffic(struct pim_instance *pim, json_object_object_add(json, ifp->name, json_row); } else { vty_out(vty, - "%-16s %8u/%-8u %7u/%-7u %7u/%-7u %7u/%-7u %7u/%-7u %7u/%-7u %7lu/%-7lu \n", + "%-16s %8u/%-8u %7u/%-7u %7u/%-7u %7u/%-7u %7u/%-7u %7u/%-7u %7" PRIu64 "/%-7" PRIu64 "\n", ifp->name, pim_ifp->pim_ifstat_hello_recv, pim_ifp->pim_ifstat_hello_sent, pim_ifp->pim_ifstat_join_recv, @@ -1629,7 +1629,7 @@ static void pim_show_interface_traffic_single(struct pim_instance *pim, json_object_object_add(json, ifp->name, json_row); } else { vty_out(vty, - "%-16s %8u/%-8u %7u/%-7u %7u/%-7u %7u/%-7u %7u/%-7u %7u/%-7u %7lu/%-7lu \n", + "%-16s %8u/%-8u %7u/%-7u %7u/%-7u %7u/%-7u %7u/%-7u %7u/%-7u %7" PRIu64 "/%-7" PRIu64 "\n", ifp->name, pim_ifp->pim_ifstat_hello_recv, pim_ifp->pim_ifstat_hello_sent, pim_ifp->pim_ifstat_join_recv, @@ -3238,9 +3238,11 @@ static void pim_show_statistics(struct pim_instance *pim, struct vty *vty, } else { vty_out(vty, "BSM Statistics :\n"); vty_out(vty, "----------------\n"); - vty_out(vty, "Number of Received BSMs : %ld\n", pim->bsm_rcvd); - vty_out(vty, "Number of Forwared BSMs : %ld\n", pim->bsm_sent); - vty_out(vty, "Number of Dropped BSMs : %ld\n", + vty_out(vty, "Number of Received BSMs : %" PRIu64 "\n", + pim->bsm_rcvd); + vty_out(vty, "Number of Forwared BSMs : %" PRIu64 "\n", + pim->bsm_sent); + vty_out(vty, "Number of Dropped BSMs : %" PRIu64 "\n", pim->bsm_dropped); } diff --git a/pimd/pim_mroute.c b/pimd/pim_mroute.c index 866a19fc98..ca05824347 100644 --- a/pimd/pim_mroute.c +++ b/pimd/pim_mroute.c @@ -897,11 +897,11 @@ int pim_mroute_add(struct channel_oil *c_oil, const char *name) int err; int orig = 0; int orig_iif_vif = 0; - struct pim_interface *pim_reg_ifp; - int orig_pimreg_ttl; + struct pim_interface *pim_reg_ifp = NULL; + int orig_pimreg_ttl = 0; bool pimreg_ttl_reset = false; - struct pim_interface *vxlan_ifp; - int orig_term_ttl; + struct pim_interface *vxlan_ifp = NULL; + int orig_term_ttl = 0; bool orig_term_ttl_reset = false; pim->mroute_add_last = pim_time_monotonic_sec(); @@ -985,9 +985,11 @@ int pim_mroute_add(struct channel_oil *c_oil, const char *name) if (c_oil->oil.mfcc_origin.s_addr == INADDR_ANY) c_oil->oil.mfcc_ttls[c_oil->oil.mfcc_parent] = orig; - if (pimreg_ttl_reset) + if (pimreg_ttl_reset) { + assert(pim_reg_ifp); c_oil->oil.mfcc_ttls[pim_reg_ifp->mroute_vif_index] = orig_pimreg_ttl; + } if (orig_term_ttl_reset) c_oil->oil.mfcc_ttls[vxlan_ifp->mroute_vif_index] = diff --git a/pimd/pim_nht.c b/pimd/pim_nht.c index 1a2f451524..65ea858cb6 100644 --- a/pimd/pim_nht.c +++ b/pimd/pim_nht.c @@ -447,7 +447,7 @@ static int pim_update_upstream_nh_helper(struct hash_bucket *bucket, void *arg) struct pim_rpf old; old.source_nexthop.interface = up->rpf.source_nexthop.interface; - rpf_result = pim_rpf_update(pim, up, &old, 0); + rpf_result = pim_rpf_update(pim, up, &old); if (rpf_result == PIM_RPF_FAILURE) { pim_upstream_rpf_clear(pim, up); return HASHWALK_CONTINUE; diff --git a/pimd/pim_rp.c b/pimd/pim_rp.c index ca865d28c3..35c040c64c 100644 --- a/pimd/pim_rp.c +++ b/pimd/pim_rp.c @@ -381,7 +381,7 @@ void pim_upstream_update(struct pim_instance *pim, struct pim_upstream *up) old_rpf.source_nexthop.interface = up->rpf.source_nexthop.interface; - rpf_result = pim_rpf_update(pim, up, &old_rpf, 1); + rpf_result = pim_rpf_update(pim, up, &old_rpf); if (rpf_result == PIM_RPF_FAILURE) pim_mroute_del(up->channel_oil, __PRETTY_FUNCTION__); diff --git a/pimd/pim_rpf.c b/pimd/pim_rpf.c index d388802454..b1a2e717d6 100644 --- a/pimd/pim_rpf.c +++ b/pimd/pim_rpf.c @@ -195,8 +195,7 @@ static int nexthop_mismatch(const struct pim_nexthop *nh1, } enum pim_rpf_result pim_rpf_update(struct pim_instance *pim, - struct pim_upstream *up, struct pim_rpf *old, - uint8_t is_new) + struct pim_upstream *up, struct pim_rpf *old) { struct pim_rpf *rpf = &up->rpf; struct pim_rpf saved; @@ -216,14 +215,6 @@ enum pim_rpf_result pim_rpf_update(struct pim_instance *pim, saved.source_nexthop = rpf->source_nexthop; saved.rpf_addr = rpf->rpf_addr; - if (is_new && PIM_DEBUG_ZEBRA) { - char source_str[INET_ADDRSTRLEN]; - pim_inet4_dump("<source?>", up->upstream_addr, source_str, - sizeof(source_str)); - zlog_debug("%s: NHT Register upstream %s addr %s with Zebra.", - __PRETTY_FUNCTION__, up->sg_str, source_str); - } - /* Register addr with Zebra NHT */ nht_p.family = AF_INET; nht_p.prefixlen = IPV4_MAX_BITLEN; nht_p.u.prefix4.s_addr = up->upstream_addr.s_addr; diff --git a/pimd/pim_rpf.h b/pimd/pim_rpf.h index 1172acb4b2..df7b249289 100644 --- a/pimd/pim_rpf.h +++ b/pimd/pim_rpf.h @@ -62,8 +62,8 @@ bool pim_rpf_equal(const void *arg1, const void *arg2); bool pim_nexthop_lookup(struct pim_instance *pim, struct pim_nexthop *nexthop, struct in_addr addr, int neighbor_needed); enum pim_rpf_result pim_rpf_update(struct pim_instance *pim, - struct pim_upstream *up, struct pim_rpf *old, - uint8_t is_new); + struct pim_upstream *up, + struct pim_rpf *old); void pim_upstream_rpf_clear(struct pim_instance *pim, struct pim_upstream *up); int pim_rpf_addr_is_inaddr_none(struct pim_rpf *rpf); diff --git a/pimd/pim_upstream.c b/pimd/pim_upstream.c index 44b8ecbfea..50c68c66bd 100644 --- a/pimd/pim_upstream.c +++ b/pimd/pim_upstream.c @@ -749,7 +749,7 @@ static struct pim_upstream *pim_upstream_new(struct pim_instance *pim, up->channel_oil = pim_channel_oil_add(pim, &up->sg, MAXVIFS); } else { - rpf_result = pim_rpf_update(pim, up, NULL, 1); + rpf_result = pim_rpf_update(pim, up, NULL); if (rpf_result == PIM_RPF_FAILURE) { if (PIM_DEBUG_TRACE) zlog_debug( @@ -1625,7 +1625,7 @@ void pim_upstream_find_new_rpf(struct pim_instance *pim) zlog_debug( "%s: Upstream %s without a path to send join, checking", __PRETTY_FUNCTION__, up->sg_str); - pim_rpf_update(pim, up, NULL, 1); + pim_rpf_update(pim, up, NULL); } } } diff --git a/pimd/pim_vxlan.c b/pimd/pim_vxlan.c index 09669e206e..d2648fad50 100644 --- a/pimd/pim_vxlan.c +++ b/pimd/pim_vxlan.c @@ -245,7 +245,7 @@ static void pim_vxlan_orig_mr_up_del(struct pim_vxlan_sg *vxlan_sg) * for nht */ if (up) - pim_rpf_update(vxlan_sg->pim, up, NULL, 1 /* is_new */); + pim_rpf_update(vxlan_sg->pim, up, NULL); } } diff --git a/pimd/pim_zlookup.c b/pimd/pim_zlookup.c index 6d93a40b91..77526281d1 100644 --- a/pimd/pim_zlookup.c +++ b/pimd/pim_zlookup.c @@ -37,8 +37,10 @@ #include "pim_zlookup.h" static struct zclient *zlookup = NULL; +struct thread *zlookup_read; static void zclient_lookup_sched(struct zclient *zlookup, int delay); +static int zclient_lookup_read_pipe(struct thread *thread); /* Connect to zebra for nexthop lookup. */ static int zclient_lookup_connect(struct thread *t) @@ -65,6 +67,8 @@ static int zclient_lookup_connect(struct thread *t) return -1; } + thread_add_timer(router->master, zclient_lookup_read_pipe, zlookup, 60, + &zlookup_read); return 0; } @@ -113,6 +117,7 @@ static void zclient_lookup_failed(struct zclient *zlookup) void zclient_lookup_free(void) { + thread_cancel(zlookup_read); zclient_stop(zlookup); zclient_free(zlookup); zlookup = NULL; @@ -357,6 +362,20 @@ static int zclient_lookup_nexthop_once(struct pim_instance *pim, return zclient_read_nexthop(pim, zlookup, nexthop_tab, tab_size, addr); } +int zclient_lookup_read_pipe(struct thread *thread) +{ + struct zclient *zlookup = THREAD_ARG(thread); + struct pim_instance *pim = pim_get_pim_instance(VRF_DEFAULT); + struct pim_zlookup_nexthop nexthop_tab[10]; + struct in_addr l = {.s_addr = INADDR_ANY}; + + zclient_lookup_nexthop_once(pim, nexthop_tab, 10, l); + thread_add_timer(router->master, zclient_lookup_read_pipe, zlookup, 60, + &zlookup_read); + + return 1; +} + int zclient_lookup_nexthop(struct pim_instance *pim, struct pim_zlookup_nexthop nexthop_tab[], const int tab_size, struct in_addr addr, diff --git a/redhat/frr.spec.in b/redhat/frr.spec.in index ebd9ac3f47..27042e197c 100644 --- a/redhat/frr.spec.in +++ b/redhat/frr.spec.in @@ -44,12 +44,6 @@ # defines for configure %define rundir %{_localstatedir}/run/%{name} -# define for sphinx-build binary -%if 0%{?rhel} && 0%{?rhel} < 7 - %define sphinx sphinx-build2.7 -%else - %define sphinx sphinx-build -%endif ############################################################################ #### Version String tweak @@ -360,7 +354,7 @@ developing OSPF-API and frr applications. %else --disable-bfdd \ %endif - SPHINXBUILD=%{sphinx} + # end make %{?_smp_mflags} MAKEINFO="makeinfo --no-split" diff --git a/sharpd/sharp_vty.c b/sharpd/sharp_vty.c index fbcbbe3fdc..dad09dd992 100644 --- a/sharpd/sharp_vty.c +++ b/sharpd/sharp_vty.c @@ -150,14 +150,14 @@ DEFPY (install_routes_data_dump, sg.r.total_routes, sg.r.installed_routes, sg.r.removed_routes, - r.tv_sec, r.tv_usec); + r.tv_sec, (long int)r.tv_usec); return CMD_SUCCESS; } DEFPY (install_routes, install_routes_cmd, - "sharp install routes [vrf NAME$name] <A.B.C.D$start4|X:X::X:X$start6> <nexthop <A.B.C.D$nexthop4|X:X::X:X$nexthop6>|nexthop-group NAME$nexthop_group> (1-1000000)$routes [instance (0-255)$instance] [repeat (2-1000)$rpt]", + "sharp install routes [vrf NAME$name] <A.B.C.D$start4|X:X::X:X$start6> <nexthop <A.B.C.D$nexthop4|X:X::X:X$nexthop6>|nexthop-group NHGNAME$nexthop_group> (1-1000000)$routes [instance (0-255)$instance] [repeat (2-1000)$rpt]", "Sharp routing Protocol\n" "install some routes\n" "Routes to install\n" diff --git a/sharpd/sharp_zebra.c b/sharpd/sharp_zebra.c index 19c7e556ca..7447076993 100644 --- a/sharpd/sharp_zebra.c +++ b/sharpd/sharp_zebra.c @@ -213,7 +213,7 @@ static int route_notify_owner(ZAPI_CALLBACK_ARGS) monotime(&sg.r.t_end); timersub(&sg.r.t_end, &sg.r.t_start, &r); zlog_debug("Installed All Items %ld.%ld", r.tv_sec, - r.tv_usec); + (long int)r.tv_usec); handle_repeated(true); } break; @@ -229,7 +229,7 @@ static int route_notify_owner(ZAPI_CALLBACK_ARGS) monotime(&sg.r.t_end); timersub(&sg.r.t_end, &sg.r.t_start, &r); zlog_debug("Removed all Items %ld.%ld", r.tv_sec, - r.tv_usec); + (long int)r.tv_usec); handle_repeated(false); } break; diff --git a/tests/.gitignore b/tests/.gitignore index 7177165e4a..4c6a51d475 100644 --- a/tests/.gitignore +++ b/tests/.gitignore @@ -30,6 +30,7 @@ /lib/test_idalloc /lib/test_memory /lib/test_nexthop_iter +/lib/test_ntop /lib/test_printfrr /lib/test_privs /lib/test_ringbuf diff --git a/tests/lib/test_ntop.c b/tests/lib/test_ntop.c new file mode 100644 index 0000000000..1806059963 --- /dev/null +++ b/tests/lib/test_ntop.c @@ -0,0 +1,87 @@ +/* + * frr_inet_ntop() unit test + * Copyright (C) 2019 David Lamparter + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; see the file COPYING; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <assert.h> + +#include "tests/helpers/c/prng.h" + +/* NB: libfrr is NOT linked for this unit test! */ + +#define INET_NTOP_NO_OVERRIDE +#include "lib/ntop.c" + +int main(int argc, char **argv) +{ + size_t i, j, k, l; + struct in_addr i4; + struct in6_addr i6, i6check; + char buf1[64], buf2[64]; + const char *rv; + struct prng *prng; + + prng = prng_new(0); + /* IPv4 */ + for (i = 0; i < 1000; i++) { + i4.s_addr = prng_rand(prng); + assert(frr_inet_ntop(AF_INET, &i4, buf1, sizeof(buf1))); + assert(inet_ntop(AF_INET, &i4, buf2, sizeof(buf2))); + assert(!strcmp(buf1, buf2)); + } + + /* check size limit */ + for (i = 0; i < sizeof(buf1); i++) { + memset(buf2, 0xcc, sizeof(buf2)); + rv = frr_inet_ntop(AF_INET, &i4, buf2, i); + if (i < strlen(buf1) + 1) + assert(!rv); + else + assert(rv && !strcmp(buf1, buf2)); + } + + /* IPv6 */ + for (i = 0; i < 10000; i++) { + uint16_t *i6w = (uint16_t *)&i6; + for (j = 0; j < 8; j++) + i6w[j] = prng_rand(prng); + + /* clear some words */ + l = prng_rand(prng) & 7; + for (j = 0; j < l; j++) { + uint32_t num = __builtin_ctz(prng_rand(prng)); + uint32_t where = prng_rand(prng) & 7; + + for (k = where; k < where + num && k < 8; k++) + i6w[k] = 0; + } + + assert(frr_inet_ntop(AF_INET6, &i6, buf1, sizeof(buf1))); + assert(inet_ntop(AF_INET6, &i6, buf2, sizeof(buf2))); + if (strcmp(buf1, buf2)) + printf("%-40s (FRR) != (SYS) %-40s\n", buf1, buf2); + + assert(inet_pton(AF_INET6, buf1, &i6check)); + assert(!memcmp(&i6, &i6check, sizeof(i6))); + assert(strlen(buf1) <= strlen(buf2)); + } + return 0; +} diff --git a/tests/lib/test_ntop.py b/tests/lib/test_ntop.py new file mode 100644 index 0000000000..2526f53db5 --- /dev/null +++ b/tests/lib/test_ntop.py @@ -0,0 +1,6 @@ +import frrtest + +class TestNtop(frrtest.TestMultiOut): + program = './test_ntop' + +TestNtop.exit_cleanly() diff --git a/tests/subdir.am b/tests/subdir.am index bbab8cd86a..41f1a4873b 100644 --- a/tests/subdir.am +++ b/tests/subdir.am @@ -2,8 +2,6 @@ # tests # -PYTHON ?= python - if BGPD TESTS_BGPD = \ tests/bgpd/test_aspath \ @@ -56,6 +54,7 @@ check_PROGRAMS = \ tests/lib/test_idalloc \ tests/lib/test_memory \ tests/lib/test_nexthop_iter \ + tests/lib/test_ntop \ tests/lib/test_printfrr \ tests/lib/test_privs \ tests/lib/test_ringbuf \ @@ -233,6 +232,10 @@ tests_lib_test_nexthop_iter_CFLAGS = $(TESTS_CFLAGS) tests_lib_test_nexthop_iter_CPPFLAGS = $(TESTS_CPPFLAGS) tests_lib_test_nexthop_iter_LDADD = $(ALL_TESTS_LDADD) tests_lib_test_nexthop_iter_SOURCES = tests/lib/test_nexthop_iter.c tests/helpers/c/prng.c +tests_lib_test_ntop_CFLAGS = $(TESTS_CFLAGS) +tests_lib_test_ntop_CPPFLAGS = $(TESTS_CPPFLAGS) +tests_lib_test_ntop_LDADD = # none +tests_lib_test_ntop_SOURCES = tests/lib/test_ntop.c tests/helpers/c/prng.c tests_lib_test_printfrr_CFLAGS = $(TESTS_CFLAGS) tests_lib_test_printfrr_CPPFLAGS = $(TESTS_CPPFLAGS) tests_lib_test_printfrr_LDADD = $(ALL_TESTS_LDADD) @@ -324,6 +327,7 @@ EXTRA_DIST += \ tests/lib/northbound/test_oper_data.refout \ tests/lib/test_atomlist.py \ tests/lib/test_nexthop_iter.py \ + tests/lib/test_ntop.py \ tests/lib/test_printfrr.py \ tests/lib/test_ringbuf.py \ tests/lib/test_srcdest_table.py \ diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c index baf77d1cb7..c3aeb27eb9 100644 --- a/vtysh/vtysh.c +++ b/vtysh/vtysh.c @@ -1678,7 +1678,7 @@ DEFUNSH(VTYSH_RMAP, vtysh_route_map, vtysh_route_map_cmd, } DEFUNSH(VTYSH_PBRD, vtysh_pbr_map, vtysh_pbr_map_cmd, - "pbr-map NAME seq (1-700)", + "pbr-map PBRMAP seq (1-700)", "Create pbr-map or enter pbr-map command mode\n" "The name of the PBR MAP\n" "Sequence to insert to/delete from existing pbr-map entry\n" @@ -1714,7 +1714,7 @@ DEFUNSH(VTYSH_BFDD, bfd_peer_enter, bfd_peer_enter_cmd, } #endif /* HAVE_BFDD */ -DEFSH(VTYSH_PBRD, vtysh_no_pbr_map_cmd, "no pbr-map WORD [seq (1-700)]", +DEFSH(VTYSH_PBRD, vtysh_no_pbr_map_cmd, "no pbr-map PBRMAP [seq (1-700)]", NO_STR "Delete pbr-map\n" "The name of the PBR MAP\n" @@ -2114,7 +2114,7 @@ DEFSH(VTYSH_ZEBRA, vtysh_no_logicalrouter_cmd, "The file name in " NS_RUN_DIR ", or a full pathname\n") DEFUNSH(VTYSH_PBRD | VTYSH_SHARPD, vtysh_nexthop_group, vtysh_nexthop_group_cmd, - "nexthop-group NAME", + "nexthop-group NHGNAME", "Nexthop Group configuration\n" "Name of the Nexthop Group\n") { @@ -2123,7 +2123,7 @@ DEFUNSH(VTYSH_PBRD | VTYSH_SHARPD, vtysh_nexthop_group, vtysh_nexthop_group_cmd, } DEFSH(VTYSH_PBRD | VTYSH_SHARPD, vtysh_no_nexthop_group_cmd, - "no nexthop-group NAME", + "no nexthop-group NHGNAME", NO_STR "Nexthop Group Configuration\n" "Name of the Nexthop Group\n") diff --git a/zebra/zebra_rnh.c b/zebra/zebra_rnh.c index a63d015716..1024f3a052 100644 --- a/zebra/zebra_rnh.c +++ b/zebra/zebra_rnh.c @@ -592,54 +592,6 @@ static void zebra_rnh_notify_protocol_clients(struct zebra_vrf *zvrf, afi_t afi, zebra_rnh_clear_nexthop_rnh_filters(re); } -static void zebra_rnh_process_pbr_tables(afi_t afi, struct route_node *nrn, - struct rnh *rnh, - struct route_node *prn, - struct route_entry *re) -{ - struct zebra_router_table *zrt; - struct route_entry *o_re; - struct route_node *o_rn; - struct listnode *node; - struct zserv *client; - - /* - * We are only concerned about nexthops that change for - * anyone using PBR - */ - for (ALL_LIST_ELEMENTS_RO(rnh->client_list, node, client)) { - if (client->proto == ZEBRA_ROUTE_PBR) - break; - } - - if (!client) - return; - - RB_FOREACH (zrt, zebra_router_table_head, &zrouter.tables) { - if (afi != zrt->afi) - continue; - - for (o_rn = route_top(zrt->table); o_rn; - o_rn = srcdest_route_next(o_rn)) { - RNODE_FOREACH_RE (o_rn, o_re) { - if (o_re->type == ZEBRA_ROUTE_PBR) - break; - - } - - /* - * If we have a PBR route and a nexthop changes - * just rethink it. Yes this is a hammer, but - * a small one - */ - if (o_re) { - SET_FLAG(o_re->status, ROUTE_ENTRY_CHANGED); - rib_queue_add(o_rn); - } - } - } -} - /* * Utility to determine whether a candidate nexthop is useable. We make this * check in a couple of places, so this is a single home for the logic we @@ -834,8 +786,6 @@ static void zebra_rnh_eval_nexthop_entry(struct zebra_vrf *zvrf, afi_t afi, zebra_rnh_notify_protocol_clients(zvrf, afi, nrn, rnh, prn, rnh->state); - zebra_rnh_process_pbr_tables(afi, nrn, rnh, prn, rnh->state); - /* Process pseudowires attached to this nexthop */ zebra_rnh_process_pseudowires(zvrf->vrf->vrf_id, rnh); } |
