summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--babeld/message.c4
-rw-r--r--bfdd/bfd_packet.c14
-rw-r--r--bgpd/bgp_mpath.c5
-rw-r--r--bgpd/rfapi/rfapi_import.c5
-rwxr-xr-xconfigure.ac129
-rw-r--r--doc/developer/building-frr-for-centos6.rst5
-rw-r--r--doc/developer/building-frr-for-debian8.rst4
-rw-r--r--doc/developer/building-frr-for-debian9.rst4
-rw-r--r--doc/developer/building-frr-for-fedora.rst4
-rw-r--r--doc/developer/building-frr-for-freebsd10.rst2
-rw-r--r--doc/developer/building-frr-for-freebsd11.rst2
-rw-r--r--doc/developer/building-frr-for-freebsd9.rst4
-rw-r--r--doc/developer/building-frr-for-netbsd6.rst9
-rw-r--r--doc/developer/building-frr-for-netbsd7.rst9
-rw-r--r--doc/developer/building-frr-for-ubuntu1404.rst2
-rw-r--r--doc/developer/building-frr-for-ubuntu1604.rst2
-rw-r--r--doc/developer/building-frr-for-ubuntu1804.rst2
-rw-r--r--doc/developer/packaging-redhat.rst2
-rw-r--r--doc/subdir.am11
-rw-r--r--doc/user/installation.rst21
-rw-r--r--eigrpd/eigrp_routemap.c24
-rw-r--r--eigrpd/eigrp_vty.c4
-rw-r--r--lib/vty.c2
-rw-r--r--m4/.gitignore1
-rw-r--r--m4/ax_python.m4284
-rw-r--r--nhrpd/vici.c4
-rw-r--r--redhat/frr.spec.in8
-rw-r--r--ripngd/ripng_interface.c3
-rw-r--r--tests/subdir.am2
-rw-r--r--tests/topotests/lib/topotest.py27
-rw-r--r--tests/topotests/ospf6-topo1/r1/ospf6d.conf-pre-v427
-rw-r--r--tests/topotests/ospf6-topo1/r1/show_ipv6_route.ref18
-rw-r--r--tests/topotests/ospf6-topo1/r1/zebra.conf3
-rw-r--r--tests/topotests/ospf6-topo1/r2/ospf6d.conf-pre-v427
-rw-r--r--tests/topotests/ospf6-topo1/r2/show_ipv6_route.ref18
-rw-r--r--tests/topotests/ospf6-topo1/r2/zebra.conf3
-rw-r--r--tests/topotests/ospf6-topo1/r3/ospf6d.conf-pre-v431
-rw-r--r--tests/topotests/ospf6-topo1/r3/show_ipv6_route.ref18
-rw-r--r--tests/topotests/ospf6-topo1/r3/zebra.conf3
-rw-r--r--tests/topotests/ospf6-topo1/r4/ospf6d.conf-pre-v427
-rw-r--r--tests/topotests/ospf6-topo1/r4/show_ipv6_route.ref18
-rw-r--r--tests/topotests/ospf6-topo1/r4/zebra.conf3
-rwxr-xr-xtests/topotests/ospf6-topo1/test_ospf6_topo1.py384
43 files changed, 663 insertions, 516 deletions
diff --git a/babeld/message.c b/babeld/message.c
index 794b6e9976..d88790824c 100644
--- a/babeld/message.c
+++ b/babeld/message.c
@@ -1115,7 +1115,9 @@ really_send_update(struct interface *ifp,
if(channels_len >= 0) {
accumulate_byte(ifp, 2);
accumulate_byte(ifp, channels_len);
- accumulate_bytes(ifp, channels, channels_len);
+
+ if (channels && channels_len > 0)
+ accumulate_bytes(ifp, channels, channels_len);
}
end_message(ifp, MESSAGE_UPDATE, 10 + (real_plen + 7) / 8 - omit +
channels_size);
diff --git a/bfdd/bfd_packet.c b/bfdd/bfd_packet.c
index f3acfa4167..d68a1ad5fd 100644
--- a/bfdd/bfd_packet.c
+++ b/bfdd/bfd_packet.c
@@ -435,16 +435,18 @@ ssize_t bfd_recv_ipv6(int sd, uint8_t *msgbuf, size_t msgbuflen, uint8_t *ttl,
#endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */
*ifindex = pi6->ipi6_ifindex;
+
+ /* Set scope ID for link local addresses. */
+ if (IN6_IS_ADDR_LINKLOCAL(
+ &peer->sa_sin6.sin6_addr))
+ peer->sa_sin6.sin6_scope_id = *ifindex;
+ if (IN6_IS_ADDR_LINKLOCAL(
+ &local->sa_sin6.sin6_addr))
+ local->sa_sin6.sin6_scope_id = *ifindex;
}
}
}
- /* Set scope ID for link local addresses. */
- if (IN6_IS_ADDR_LINKLOCAL(&peer->sa_sin6.sin6_addr))
- peer->sa_sin6.sin6_scope_id = *ifindex;
- if (IN6_IS_ADDR_LINKLOCAL(&local->sa_sin6.sin6_addr))
- local->sa_sin6.sin6_scope_id = *ifindex;
-
return mlen;
}
diff --git a/bgpd/bgp_mpath.c b/bgpd/bgp_mpath.c
index d5b3d6b197..648c3be47e 100644
--- a/bgpd/bgp_mpath.c
+++ b/bgpd/bgp_mpath.c
@@ -294,6 +294,10 @@ static struct bgp_path_info_mpath *
bgp_path_info_mpath_get(struct bgp_path_info *path)
{
struct bgp_path_info_mpath *mpath;
+
+ if (!path)
+ return NULL;
+
if (!path->mpath) {
mpath = bgp_path_info_mpath_new();
if (!mpath)
@@ -523,6 +527,7 @@ void bgp_path_info_mpath_update(struct bgp_node *rn,
list_delete_node(mp_list, mp_node);
bgp_path_info_mpath_dequeue(cur_mpath);
if ((mpath_count < maxpaths)
+ && prev_mpath
&& bgp_path_info_nexthop_cmp(prev_mpath,
cur_mpath)) {
bgp_path_info_mpath_enqueue(prev_mpath,
diff --git a/bgpd/rfapi/rfapi_import.c b/bgpd/rfapi/rfapi_import.c
index b6d32d36ea..583adcda77 100644
--- a/bgpd/rfapi/rfapi_import.c
+++ b/bgpd/rfapi/rfapi_import.c
@@ -1143,6 +1143,9 @@ static int rfapiVpnBiSamePtUn(struct bgp_path_info *bpi1,
break;
}
+ memset(&pfx_un1, 0, sizeof(pfx_un1));
+ memset(&pfx_un2, 0, sizeof(pfx_un2));
+
/*
* UN address comparisons
*/
@@ -1184,7 +1187,7 @@ static int rfapiVpnBiSamePtUn(struct bgp_path_info *bpi1,
}
}
- if (!pfx_un1.family || !pfx_un2.family)
+ if (pfx_un1.family == 0 || pfx_un2.family == 0)
return 0;
if (pfx_un1.family != pfx_un2.family)
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/vty.c b/lib/vty.c
index 639307b507..e306e69b87 100644
--- a/lib/vty.c
+++ b/lib/vty.c
@@ -151,7 +151,7 @@ int vty_out(struct vty *vty, const char *format, ...)
va_list args;
ssize_t len;
char buf[1024];
- char *p = buf;
+ char *p = NULL;
char *filtered;
if (vty->frame_pos) {
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/nhrpd/vici.c b/nhrpd/vici.c
index 3de4609a2b..d6105b71d4 100644
--- a/nhrpd/vici.c
+++ b/nhrpd/vici.c
@@ -207,7 +207,7 @@ static void parse_sa_message(struct vici_message_ctx *ctx,
}
break;
default:
- if (!key)
+ if (!key || !key->ptr)
break;
switch (key->ptr[0]) {
@@ -550,7 +550,7 @@ int sock_open_unix(const char *path)
memset(&addr, 0, sizeof(struct sockaddr_un));
addr.sun_family = AF_UNIX;
- strncpy(addr.sun_path, path, sizeof(addr.sun_path) - 1);
+ strlcpy(addr.sun_path, path, sizeof(addr.sun_path));
ret = connect(fd, (struct sockaddr *)&addr,
sizeof(addr.sun_family) + strlen(addr.sun_path));
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/ripngd/ripng_interface.c b/ripngd/ripng_interface.c
index 5a4087b177..d83f4d2791 100644
--- a/ripngd/ripng_interface.c
+++ b/ripngd/ripng_interface.c
@@ -184,7 +184,8 @@ static int ripng_if_down(struct interface *ifp)
zlog_debug("turn off %s", ifp->name);
/* Leave from multicast group. */
- ripng_multicast_leave(ifp, ripng->sock);
+ if (ripng)
+ ripng_multicast_leave(ifp, ripng->sock);
ri->running = 0;
}
diff --git a/tests/subdir.am b/tests/subdir.am
index 99f5f87fac..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 \
diff --git a/tests/topotests/lib/topotest.py b/tests/topotests/lib/topotest.py
index e0da20e07f..2acb04fb0e 100644
--- a/tests/topotests/lib/topotest.py
+++ b/tests/topotests/lib/topotest.py
@@ -429,6 +429,33 @@ def ip4_route_zebra(node, vrf_name=None):
lines = lines[1:]
return '\n'.join(lines)
+def ip6_route_zebra(node, vrf_name=None):
+ """
+ Retrieves the output of 'show ipv6 route [vrf vrf_name]', then
+ canonicalizes it by eliding link-locals.
+ """
+
+ if vrf_name == None:
+ tmp = node.vtysh_cmd('show ipv6 route')
+ else:
+ tmp = node.vtysh_cmd('show ipv6 route vrf {0}'.format(vrf_name))
+
+ # Mask out timestamp
+ output = re.sub(r" [0-2][0-9]:[0-5][0-9]:[0-5][0-9]", " XX:XX:XX", tmp)
+
+ # Mask out the link-local addresses
+ output = re.sub(r'fe80::[^ ]+,', 'fe80::XXXX:XXXX:XXXX:XXXX,', output)
+
+ lines = output.splitlines()
+ header_found = False
+ while lines and (not lines[0].strip() or not header_found):
+ if '> - selected route' in lines[0]:
+ header_found = True
+ lines = lines[1:]
+
+ return '\n'.join(lines)
+
+
def proto_name_to_number(protocol):
return {
'bgp': '186',
diff --git a/tests/topotests/ospf6-topo1/r1/ospf6d.conf-pre-v4 b/tests/topotests/ospf6-topo1/r1/ospf6d.conf-pre-v4
deleted file mode 100644
index c4b382171d..0000000000
--- a/tests/topotests/ospf6-topo1/r1/ospf6d.conf-pre-v4
+++ /dev/null
@@ -1,27 +0,0 @@
-hostname r1
-log file ospf6d.log
-!
-debug ospf6 message all
-debug ospf6 lsa unknown
-debug ospf6 zebra
-debug ospf6 interface
-debug ospf6 neighbor
-debug ospf6 route table
-debug ospf6 flooding
-!
-interface r1-stubnet
- ipv6 ospf6 network broadcast
-!
-interface r1-sw5
- ipv6 ospf6 network broadcast
-!
-router ospf6
- router-id 10.0.0.1
- log-adjacency-changes detail
- redistribute static
- interface r1-stubnet area 0.0.0.0
- interface r1-sw5 area 0.0.0.0
-!
-line vty
- exec-timeout 0 0
-!
diff --git a/tests/topotests/ospf6-topo1/r1/show_ipv6_route.ref b/tests/topotests/ospf6-topo1/r1/show_ipv6_route.ref
index c961512bd9..2db6f620f9 100644
--- a/tests/topotests/ospf6-topo1/r1/show_ipv6_route.ref
+++ b/tests/topotests/ospf6-topo1/r1/show_ipv6_route.ref
@@ -1,9 +1,9 @@
-O fc00:1:1:1::/64 [110/10] is directly connected, r1-stubnet
-O>* fc00:2:2:2::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r1-sw5
-O>* fc00:3:3:3::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r1-sw5
-O>* fc00:4:4:4::/64 [110/30] via fe80::XXXX:XXXX:XXXX:XXXX, r1-sw5
-O fc00:a:a:a::/64 [110/10] is directly connected, r1-sw5
-O>* fc00:b:b:b::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r1-sw5
-O>* fc00:2222:2222:2222::/64 [110/10] via fe80::XXXX:XXXX:XXXX:XXXX, r1-sw5
-O>* fc00:3333:3333:3333::/64 [110/10] via fe80::XXXX:XXXX:XXXX:XXXX, r1-sw5
-O>* fc00:4444:4444:4444::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r1-sw5
+O fc00:1:1:1::/64 [110/10] is directly connected, r1-stubnet, XX:XX:XX
+O>* fc00:2:2:2::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r1-sw5, XX:XX:XX
+O>* fc00:3:3:3::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r1-sw5, XX:XX:XX
+O>* fc00:4:4:4::/64 [110/30] via fe80::XXXX:XXXX:XXXX:XXXX, r1-sw5, XX:XX:XX
+O fc00:a:a:a::/64 [110/10] is directly connected, r1-sw5, XX:XX:XX
+O>* fc00:b:b:b::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r1-sw5, XX:XX:XX
+O>* fc00:2222:2222:2222::/64 [110/10] via fe80::XXXX:XXXX:XXXX:XXXX, r1-sw5, XX:XX:XX
+O>* fc00:3333:3333:3333::/64 [110/10] via fe80::XXXX:XXXX:XXXX:XXXX, r1-sw5, XX:XX:XX
+O>* fc00:4444:4444:4444::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r1-sw5, XX:XX:XX
diff --git a/tests/topotests/ospf6-topo1/r1/zebra.conf b/tests/topotests/ospf6-topo1/r1/zebra.conf
index de298f40e1..dfbcea8d21 100644
--- a/tests/topotests/ospf6-topo1/r1/zebra.conf
+++ b/tests/topotests/ospf6-topo1/r1/zebra.conf
@@ -2,6 +2,9 @@
hostname r1
log file zebra.log
!
+debug zebra events
+debug zebra rib
+!
interface r1-stubnet
ipv6 address fc00:1:1:1::1/64
!
diff --git a/tests/topotests/ospf6-topo1/r2/ospf6d.conf-pre-v4 b/tests/topotests/ospf6-topo1/r2/ospf6d.conf-pre-v4
deleted file mode 100644
index bb9958d173..0000000000
--- a/tests/topotests/ospf6-topo1/r2/ospf6d.conf-pre-v4
+++ /dev/null
@@ -1,27 +0,0 @@
-hostname r2
-log file ospf6d.log
-!
-debug ospf6 message all
-debug ospf6 lsa unknown
-debug ospf6 zebra
-debug ospf6 interface
-debug ospf6 neighbor
-debug ospf6 route table
-debug ospf6 flooding
-!
-interface r2-stubnet
- ipv6 ospf6 network broadcast
-!
-interface r2-sw5
- ipv6 ospf6 network broadcast
-!
-router ospf6
- router-id 10.0.0.2
- log-adjacency-changes detail
- redistribute static
- interface r2-stubnet area 0.0.0.0
- interface r2-sw5 area 0.0.0.0
-!
-line vty
- exec-timeout 0 0
-!
diff --git a/tests/topotests/ospf6-topo1/r2/show_ipv6_route.ref b/tests/topotests/ospf6-topo1/r2/show_ipv6_route.ref
index 014eddbcb6..9060b0739f 100644
--- a/tests/topotests/ospf6-topo1/r2/show_ipv6_route.ref
+++ b/tests/topotests/ospf6-topo1/r2/show_ipv6_route.ref
@@ -1,10 +1,10 @@
-O>* fc00:1:1:1::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r2-sw5
-O fc00:2:2:2::/64 [110/10] is directly connected, r2-stubnet
-O>* fc00:3:3:3::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r2-sw5
-O>* fc00:4:4:4::/64 [110/30] via fe80::XXXX:XXXX:XXXX:XXXX, r2-sw5
-O fc00:a:a:a::/64 [110/10] is directly connected, r2-sw5
-O>* fc00:b:b:b::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r2-sw5
-O>* fc00:1111:1111:1111::/64 [110/10] via fe80::XXXX:XXXX:XXXX:XXXX, r2-sw5
-O>* fc00:3333:3333:3333::/64 [110/10] via fe80::XXXX:XXXX:XXXX:XXXX, r2-sw5
-O>* fc00:4444:4444:4444::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r2-sw5
+O>* fc00:1:1:1::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r2-sw5, XX:XX:XX
+O fc00:2:2:2::/64 [110/10] is directly connected, r2-stubnet, XX:XX:XX
+O>* fc00:3:3:3::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r2-sw5, XX:XX:XX
+O>* fc00:4:4:4::/64 [110/30] via fe80::XXXX:XXXX:XXXX:XXXX, r2-sw5, XX:XX:XX
+O fc00:a:a:a::/64 [110/10] is directly connected, r2-sw5, XX:XX:XX
+O>* fc00:b:b:b::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r2-sw5, XX:XX:XX
+O>* fc00:1111:1111:1111::/64 [110/10] via fe80::XXXX:XXXX:XXXX:XXXX, r2-sw5, XX:XX:XX
+O>* fc00:3333:3333:3333::/64 [110/10] via fe80::XXXX:XXXX:XXXX:XXXX, r2-sw5, XX:XX:XX
+O>* fc00:4444:4444:4444::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r2-sw5, XX:XX:XX
diff --git a/tests/topotests/ospf6-topo1/r2/zebra.conf b/tests/topotests/ospf6-topo1/r2/zebra.conf
index d5345fede6..f05d1a60ff 100644
--- a/tests/topotests/ospf6-topo1/r2/zebra.conf
+++ b/tests/topotests/ospf6-topo1/r2/zebra.conf
@@ -2,6 +2,9 @@
hostname r2
log file zebra.log
!
+debug zebra events
+debug zebra rib
+!
interface r2-stubnet
ipv6 address fc00:2:2:2::2/64
!
diff --git a/tests/topotests/ospf6-topo1/r3/ospf6d.conf-pre-v4 b/tests/topotests/ospf6-topo1/r3/ospf6d.conf-pre-v4
deleted file mode 100644
index d2dbc4a41c..0000000000
--- a/tests/topotests/ospf6-topo1/r3/ospf6d.conf-pre-v4
+++ /dev/null
@@ -1,31 +0,0 @@
-hostname r3
-log file ospf6d.log
-!
-debug ospf6 message all
-debug ospf6 lsa unknown
-debug ospf6 zebra
-debug ospf6 interface
-debug ospf6 neighbor
-debug ospf6 route table
-debug ospf6 flooding
-!
-interface r3-stubnet
- ipv6 ospf6 network broadcast
-!
-interface r3-sw5
- ipv6 ospf6 network broadcast
-!
-interface r3-sw6
- ipv6 ospf6 network broadcast
-!
-router ospf6
- router-id 10.0.0.3
- log-adjacency-changes detail
- redistribute static
- interface r3-stubnet area 0.0.0.0
- interface r3-sw5 area 0.0.0.0
- interface r3-sw6 area 0.0.0.1
-!
-line vty
- exec-timeout 0 0
-!
diff --git a/tests/topotests/ospf6-topo1/r3/show_ipv6_route.ref b/tests/topotests/ospf6-topo1/r3/show_ipv6_route.ref
index 1ac7cbd6b4..9406f41e94 100644
--- a/tests/topotests/ospf6-topo1/r3/show_ipv6_route.ref
+++ b/tests/topotests/ospf6-topo1/r3/show_ipv6_route.ref
@@ -1,10 +1,10 @@
-O>* fc00:1:1:1::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r3-sw5
-O>* fc00:2:2:2::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r3-sw5
-O fc00:3:3:3::/64 [110/10] is directly connected, r3-stubnet
-O>* fc00:4:4:4::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r3-sw6
-O fc00:a:a:a::/64 [110/10] is directly connected, r3-sw5
-O fc00:b:b:b::/64 [110/10] is directly connected, r3-sw6
-O>* fc00:1111:1111:1111::/64 [110/10] via fe80::XXXX:XXXX:XXXX:XXXX, r3-sw5
-O>* fc00:2222:2222:2222::/64 [110/10] via fe80::XXXX:XXXX:XXXX:XXXX, r3-sw5
-O>* fc00:4444:4444:4444::/64 [110/10] via fe80::XXXX:XXXX:XXXX:XXXX, r3-sw6
+O>* fc00:1:1:1::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r3-sw5, XX:XX:XX
+O>* fc00:2:2:2::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r3-sw5, XX:XX:XX
+O fc00:3:3:3::/64 [110/10] is directly connected, r3-stubnet, XX:XX:XX
+O>* fc00:4:4:4::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r3-sw6, XX:XX:XX
+O fc00:a:a:a::/64 [110/10] is directly connected, r3-sw5, XX:XX:XX
+O fc00:b:b:b::/64 [110/10] is directly connected, r3-sw6, XX:XX:XX
+O>* fc00:1111:1111:1111::/64 [110/10] via fe80::XXXX:XXXX:XXXX:XXXX, r3-sw5, XX:XX:XX
+O>* fc00:2222:2222:2222::/64 [110/10] via fe80::XXXX:XXXX:XXXX:XXXX, r3-sw5, XX:XX:XX
+O>* fc00:4444:4444:4444::/64 [110/10] via fe80::XXXX:XXXX:XXXX:XXXX, r3-sw6, XX:XX:XX
diff --git a/tests/topotests/ospf6-topo1/r3/zebra.conf b/tests/topotests/ospf6-topo1/r3/zebra.conf
index 11f1ff59f2..d8051c350d 100644
--- a/tests/topotests/ospf6-topo1/r3/zebra.conf
+++ b/tests/topotests/ospf6-topo1/r3/zebra.conf
@@ -2,6 +2,9 @@
hostname r3
log file zebra.log
!
+debug zebra events
+debug zebra rib
+!
interface r3-stubnet
ipv6 address fc00:3:3:3::3/64
!
diff --git a/tests/topotests/ospf6-topo1/r4/ospf6d.conf-pre-v4 b/tests/topotests/ospf6-topo1/r4/ospf6d.conf-pre-v4
deleted file mode 100644
index 6f9c30d75a..0000000000
--- a/tests/topotests/ospf6-topo1/r4/ospf6d.conf-pre-v4
+++ /dev/null
@@ -1,27 +0,0 @@
-hostname r4
-log file ospf6d.log
-!
-debug ospf6 message all
-debug ospf6 lsa unknown
-debug ospf6 zebra
-debug ospf6 interface
-debug ospf6 neighbor
-debug ospf6 route table
-debug ospf6 flooding
-!
-interface r4-stubnet
- ipv6 ospf6 network broadcast
-!
-interface r4-sw6
- ipv6 ospf6 network broadcast
-!
-router ospf6
- router-id 10.0.0.4
- log-adjacency-changes detail
- redistribute static
- interface r4-stubnet area 0.0.0.1
- interface r4-sw6 area 0.0.0.1
-!
-line vty
- exec-timeout 0 0
-!
diff --git a/tests/topotests/ospf6-topo1/r4/show_ipv6_route.ref b/tests/topotests/ospf6-topo1/r4/show_ipv6_route.ref
index 698dea6c7b..9bf032b5e7 100644
--- a/tests/topotests/ospf6-topo1/r4/show_ipv6_route.ref
+++ b/tests/topotests/ospf6-topo1/r4/show_ipv6_route.ref
@@ -1,9 +1,9 @@
-O>* fc00:1:1:1::/64 [110/30] via fe80::XXXX:XXXX:XXXX:XXXX, r4-sw6
-O>* fc00:2:2:2::/64 [110/30] via fe80::XXXX:XXXX:XXXX:XXXX, r4-sw6
-O>* fc00:3:3:3::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r4-sw6
-O fc00:4:4:4::/64 [110/10] is directly connected, r4-stubnet
-O>* fc00:a:a:a::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r4-sw6
-O fc00:b:b:b::/64 [110/10] is directly connected, r4-sw6
-O>* fc00:1111:1111:1111::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r4-sw6
-O>* fc00:2222:2222:2222::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r4-sw6
-O>* fc00:3333:3333:3333::/64 [110/10] via fe80::XXXX:XXXX:XXXX:XXXX, r4-sw6
+O>* fc00:1:1:1::/64 [110/30] via fe80::XXXX:XXXX:XXXX:XXXX, r4-sw6, XX:XX:XX
+O>* fc00:2:2:2::/64 [110/30] via fe80::XXXX:XXXX:XXXX:XXXX, r4-sw6, XX:XX:XX
+O>* fc00:3:3:3::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r4-sw6, XX:XX:XX
+O fc00:4:4:4::/64 [110/10] is directly connected, r4-stubnet, XX:XX:XX
+O>* fc00:a:a:a::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r4-sw6, XX:XX:XX
+O fc00:b:b:b::/64 [110/10] is directly connected, r4-sw6, XX:XX:XX
+O>* fc00:1111:1111:1111::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r4-sw6, XX:XX:XX
+O>* fc00:2222:2222:2222::/64 [110/20] via fe80::XXXX:XXXX:XXXX:XXXX, r4-sw6, XX:XX:XX
+O>* fc00:3333:3333:3333::/64 [110/10] via fe80::XXXX:XXXX:XXXX:XXXX, r4-sw6, XX:XX:XX
diff --git a/tests/topotests/ospf6-topo1/r4/zebra.conf b/tests/topotests/ospf6-topo1/r4/zebra.conf
index 4b0a8a1f92..cada58bd01 100644
--- a/tests/topotests/ospf6-topo1/r4/zebra.conf
+++ b/tests/topotests/ospf6-topo1/r4/zebra.conf
@@ -2,6 +2,9 @@
hostname r4
log file zebra.log
!
+debug zebra events
+debug zebra rib
+!
interface r4-stubnet
ipv6 address fc00:4:4:4::4/64
!
diff --git a/tests/topotests/ospf6-topo1/test_ospf6_topo1.py b/tests/topotests/ospf6-topo1/test_ospf6_topo1.py
index 5da04b6449..b70ae02266 100755
--- a/tests/topotests/ospf6-topo1/test_ospf6_topo1.py
+++ b/tests/topotests/ospf6-topo1/test_ospf6_topo1.py
@@ -76,20 +76,19 @@ import sys
import pytest
from time import sleep
-from mininet.topo import Topo
-from mininet.net import Mininet
-from mininet.node import Node, OVSSwitch, Host
-from mininet.log import setLogLevel, info
-from mininet.cli import CLI
-from mininet.link import Intf
-
from functools import partial
-sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
-from lib import topotest
+from mininet.topo import Topo
+# Save the Current Working Directory to find configuration files later.
+CWD = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join(CWD, '../'))
-fatal_error = ""
+# pylint: disable=C0413
+# Import topogen and topotest helpers
+from lib import topotest
+from lib.topogen import Topogen, TopoRouter, get_topogen
+from lib.topolog import logger
#####################################################
@@ -102,34 +101,45 @@ class NetworkTopo(Topo):
"OSPFv3 (IPv6) Test Topology 1"
def build(self, **_opts):
- #
- # Define Switches first
- #
- switch = {}
- for i in range(1, 7):
- switch[i] = self.addSwitch('SW%s' % i,
- dpid=topotest.int2dpid(i),
- cls=topotest.LegacySwitch)
- #
- # Define FRR/Quagga Routers
- #
- router = {}
- for i in range(1, 5):
- router[i] = topotest.addRouter(self, 'r%s' % i)
+ "Build function"
+
+ tgen = get_topogen(self)
+
+ # Create 4 routers
+ for routern in range(1, 5):
+ tgen.add_router('r{}'.format(routern))
#
# Wire up the switches and routers
+ # Note that we specify the link names so we match the config files
#
- # Stub nets
- for i in range(1, 5):
- self.addLink(switch[i], router[i], intfName2='r%s-stubnet' % i)
- # Switch 5
- self.addLink(switch[5], router[1], intfName2='r1-sw5')
- self.addLink(switch[5], router[2], intfName2='r2-sw5')
- self.addLink(switch[5], router[3], intfName2='r3-sw5')
- # Switch 6
- self.addLink(switch[6], router[3], intfName2='r3-sw6')
- self.addLink(switch[6], router[4], intfName2='r4-sw6')
+
+ # Create a empty network for router 1
+ switch = tgen.add_switch('s1')
+ switch.add_link(tgen.gears['r1'], nodeif='r1-stubnet')
+
+ # Create a empty network for router 2
+ switch = tgen.add_switch('s2')
+ switch.add_link(tgen.gears['r2'], nodeif='r2-stubnet')
+
+ # Create a empty network for router 3
+ switch = tgen.add_switch('s3')
+ switch.add_link(tgen.gears['r3'], nodeif='r3-stubnet')
+
+ # Create a empty network for router 4
+ switch = tgen.add_switch('s4')
+ switch.add_link(tgen.gears['r4'], nodeif='r4-stubnet')
+
+ # Interconnect routers 1, 2, and 3
+ switch = tgen.add_switch('s5')
+ switch.add_link(tgen.gears['r1'], nodeif='r1-sw5')
+ switch.add_link(tgen.gears['r2'], nodeif='r2-sw5')
+ switch.add_link(tgen.gears['r3'], nodeif='r3-sw5')
+
+ # Interconnect routers 3 and 4
+ switch = tgen.add_switch('s6')
+ switch.add_link(tgen.gears['r3'], nodeif='r3-sw6')
+ switch.add_link(tgen.gears['r4'], nodeif='r4-sw6')
#####################################################
@@ -138,192 +148,178 @@ class NetworkTopo(Topo):
##
#####################################################
-def setup_module(module):
- global topo, net
+def setup_module(mod):
+ "Sets up the pytest environment"
- print("\n\n** %s: Setup Topology" % module.__name__)
- print("******************************************\n")
+ tgen = Topogen(NetworkTopo, mod.__name__)
+ tgen.start_topology()
- print("Cleanup old Mininet runs")
- os.system('sudo mn -c > /dev/null 2>&1')
+ logger.info("** %s: Setup Topology" % mod.__name__)
+ logger.info("******************************************")
- thisDir = os.path.dirname(os.path.realpath(__file__))
- topo = NetworkTopo()
+ # For debugging after starting net, but before starting FRR,
+ # uncomment the next line
+ # tgen.mininet_cli()
- net = Mininet(controller=None, topo=topo)
- net.start()
+ router_list = tgen.routers()
+ for rname, router in router_list.iteritems():
+ router.load_config(
+ TopoRouter.RD_ZEBRA,
+ os.path.join(CWD, '{}/zebra.conf'.format(rname))
+ )
+ router.load_config(
+ TopoRouter.RD_OSPF6,
+ os.path.join(CWD, '{}/ospf6d.conf'.format(rname))
+ )
- # For debugging after starting net, but before starting FRR/Quagga, uncomment the next line
- # CLI(net)
+ # Initialize all routers.
+ tgen.start_router()
- ospf_config = 'ospf6d.conf'
- if net['r1'].checkRouterVersion('<', '4.0'):
- ospf_config = 'ospf6d.conf-pre-v4'
+ # For debugging after starting FRR daemons, uncomment the next line
+ # tgen.mininet_cli()
- # Starting Routers
- for i in range(1, 5):
- net['r%s' % i].loadConf('zebra', '%s/r%s/zebra.conf' % (thisDir, i))
- net['r%s' % i].loadConf('ospf6d', '%s/r%s/%s' % (thisDir, i, ospf_config))
- net['r%s' % i].startRouter()
- # For debugging after starting FRR/Quagga daemons, uncomment the next line
- # CLI(net)
+def teardown_module(mod):
+ "Teardown the pytest environment"
+ tgen = get_topogen()
+ tgen.stop_topology()
-def teardown_module(module):
- global net
+def test_ospf6_converged():
- print("\n\n** %s: Shutdown Topology" % module.__name__)
- print("******************************************\n")
+ tgen = get_topogen()
- # End - Shutdown network
- net.stop()
+ # Don't run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+ # For debugging, uncomment the next line
+ #tgen.mininet_cli()
-def test_router_running():
- global fatal_error
- global net
+ # Wait for OSPF6 to converge (All Neighbors in either Full or TwoWay State)
+ logger.info("Waiting for OSPF6 convergence")
- # Skip if previous fatal error condition is raised
- if (fatal_error != ""):
- pytest.skip(fatal_error)
+ # Set up for regex
+ pat1 = re.compile('^[0-9]')
+ pat2 = re.compile('Full')
- print("\n\n** Check if FRR/Quagga is running on each Router node")
- print("******************************************\n")
- sleep(5)
+ timeout = 60
+ while timeout > 0:
+ logger.info("Timeout in %s: " % timeout),
+ sys.stdout.flush()
- # Make sure that all daemons are running
- for i in range(1, 5):
- fatal_error = net['r%s' % i].checkRouterRunning()
- assert fatal_error == "", fatal_error
+ # Look for any node not yet converged
+ for router, rnode in tgen.routers().iteritems():
+ resStr = rnode.vtysh_cmd('show ipv6 ospf neigh')
- # For debugging after starting FRR/Quagga daemons, uncomment the next line
- # CLI(net)
+ isConverged = False
-def test_ospf6_converged():
- global fatal_error
- global net
+ for line in resStr.splitlines():
+ res1 = pat1.match(line)
+ if res1:
+ isConverged = True
+ res2 = pat2.search(line)
- # Skip if previous fatal error condition is raised
- if (fatal_error != ""):
- pytest.skip(fatal_error)
+ if res2 == None:
+ isConverged = False
+ break
- # Wait for OSPF6 to converge (All Neighbors in either Full or TwoWay State)
- print("\n\n** Verify OSPF6 daemons to converge")
- print("******************************************\n")
- timeout = 60
- while timeout > 0:
- print("Timeout in %s: " % timeout),
- sys.stdout.flush()
- # Look for any node not yet converged
- for i in range(1, 5):
- notConverged = net['r%s' % i].cmd('vtysh -c "show ipv6 ospf neigh" 2> /dev/null | grep ^[0-9] | grep -v Full')
- if notConverged:
- print('Waiting for r%s' %i)
+ if isConverged == False:
+ logger.info('Waiting for {}'.format(router))
sys.stdout.flush()
break
- if notConverged:
+
+ if isConverged:
+ logger.info('Done')
+ break
+ else:
sleep(5)
timeout -= 5
- else:
- print('Done')
- print(notConverged)
- break
- else:
+
+ if timeout == 0:
# Bail out with error if a router fails to converge
- ospfStatus = net['r%s' % i].cmd('vtysh -c "show ipv6 ospf neigh"')
- fatal_error = "OSPFv6 did not converge"
- assert False, "OSPFv6 did not converge:\n%s" % ospfStatus
+ ospfStatus = rnode.vtysh_cmd('show ipv6 ospf neigh')
+ assert False, "OSPFv6 did not converge:\n{}".format(ospfStatus)
- print("OSPFv3 converged.")
+ logger.info("OSPFv3 converged.")
- if timeout < 60:
- # Only wait if we actually went through a convergence
- print("\nwaiting 15s for routes to populate")
- sleep(15)
+ # For debugging, uncomment the next line
+ # tgen.mininet_cli()
# Make sure that all daemons are still running
- for i in range(1, 5):
- fatal_error = net['r%s' % i].checkRouterRunning()
- assert fatal_error == "", fatal_error
+ if tgen.routers_have_failure():
+ assert tgen.errors == "", tgen.errors
-def test_ospfv3_routingTable():
- global fatal_error
- global net
+def compare_show_ipv6(rname, expected):
+ """
+ Calls 'show ipv6 route' for router `rname` and compare the obtained
+ result with the expected output.
+ """
+ tgen = get_topogen()
- # Skip if previous fatal error condition is raised
- if (fatal_error != ""):
- pytest.skip(fatal_error)
+ # Use the vtysh output, with some masking to make comparison easy
+ current = topotest.ip6_route_zebra(tgen.gears[rname])
- thisDir = os.path.dirname(os.path.realpath(__file__))
+ # Use just the 'O'spf lines of the output
+ linearr = []
+ for line in current.splitlines():
+ if re.match('^O', line):
+ linearr.append(line)
- # Verify OSPFv3 Routing Table
- print("\n\n** Verifying OSPFv3 Routing Table")
- print("******************************************\n")
- failures = 0
- for i in range(1, 5):
- refTableFile = '%s/r%s/show_ipv6_route.ref' % (thisDir, i)
- if os.path.isfile(refTableFile):
- # Read expected result from file
- expected = open(refTableFile).read().rstrip()
- # Fix newlines (make them all the same)
- expected = ('\n'.join(expected.splitlines()) + '\n').splitlines(1)
+ current = '\n'.join(linearr)
- # Actual output from router
- actual = net['r%s' % i].cmd('vtysh -c "show ipv6 route" 2> /dev/null | grep "^O"').rstrip()
- # Mask out Link-Local mac address portion. They are random...
- actual = re.sub(r" fe80::[0-9a-f:]+", " fe80::XXXX:XXXX:XXXX:XXXX", actual)
- # Drop timers on end of line (older Quagga Versions)
- actual = re.sub(r", [0-2][0-9]:[0-5][0-9]:[0-5][0-9]", "", actual)
- # Fix newlines (make them all the same)
- actual = ('\n'.join(actual.splitlines()) + '\n').splitlines(1)
+ return topotest.difflines(topotest.normalize_text(current),
+ topotest.normalize_text(expected),
+ title1="Current output",
+ title2="Expected output")
- # Generate Diff
- diff = topotest.get_textdiff(actual, expected,
- title1="actual OSPFv3 IPv6 routing table",
- title2="expected OSPFv3 IPv6 routing table")
+def test_ospfv3_routingTable():
- # Empty string if it matches, otherwise diff contains unified diff
- if diff:
- sys.stderr.write('r%s failed OSPFv3 (IPv6) Routing Table Check:\n%s\n' % (i, diff))
- failures += 1
- else:
- print("r%s ok" % i)
+ tgen = get_topogen()
+ if tgen.routers_have_failure():
+ pytest.skip('skipped because of router(s) failure')
- assert failures == 0, "OSPFv3 (IPv6) Routing Table verification failed for router r%s:\n%s" % (i, diff)
+ # For debugging, uncomment the next line
+ # tgen.mininet_cli()
- # Make sure that all daemons are still running
- for i in range(1, 5):
- fatal_error = net['r%s' % i].checkRouterRunning()
- assert fatal_error == "", fatal_error
+ # Verify OSPFv3 Routing Table
+ for router, rnode in tgen.routers().iteritems():
+ logger.info('Waiting for router "%s" convergence', router)
+
+ # Load expected results from the command
+ reffile = os.path.join(CWD, '{}/show_ipv6_route.ref'.format(router))
+ expected = open(reffile).read()
+
+ # Run test function until we get an result. Wait at most 60 seconds.
+ test_func = partial(
+ compare_show_ipv6, router, expected)
+ result, diff = topotest.run_and_expect(test_func, '',
+ count=120, wait=0.5)
+ assert result, 'OSPFv3 did not converge on {}:\n{}'.format(router, diff)
- # For debugging after starting FRR/Quagga daemons, uncomment the next line
- # CLI(net)
def test_linux_ipv6_kernel_routingTable():
- global fatal_error
- global net
- # Skip if previous fatal error condition is raised
- if (fatal_error != ""):
- pytest.skip(fatal_error)
+ tgen = get_topogen()
- thisDir = os.path.dirname(os.path.realpath(__file__))
+ if tgen.routers_have_failure():
+ pytest.skip('skipped because of router(s) failure')
# Verify Linux Kernel Routing Table
- print("\n\n** Verifying Linux IPv6 Kernel Routing Table")
- print("******************************************\n")
+ logger.info("Verifying Linux IPv6 Kernel Routing Table")
+
failures = 0
# Get a list of all current link-local addresses first as they change for
# each run and we need to translate them
linklocals = []
for i in range(1, 5):
- linklocals += net['r%s' % i].get_ipv6_linklocal()
+ linklocals += tgen.net['r{}'.format(i)].get_ipv6_linklocal()
+
+ # Now compare the routing tables (after substituting link-local addresses)
- # Now compare the routing tables (after substituting link-local addresses)
for i in range(1, 5):
- refTableFile = '%s/r%s/ip_6_address.ref' % (thisDir, i)
+ refTableFile = os.path.join(CWD, 'r{}/ip_6_address.ref'.format(i))
if os.path.isfile(refTableFile):
expected = open(refTableFile).read().rstrip()
@@ -331,7 +327,7 @@ def test_linux_ipv6_kernel_routingTable():
expected = ('\n'.join(expected.splitlines())).splitlines(1)
# Actual output from router
- actual = net['r%s' % i].cmd('ip -6 route').rstrip()
+ actual = tgen.gears['r{}'.format(i)].run('ip -6 route').rstrip()
# Mask out Link-Local mac addresses
for ll in linklocals:
actual = actual.replace(ll[1], "fe80::__(%s)__" % ll[0])
@@ -354,9 +350,9 @@ def test_linux_ipv6_kernel_routingTable():
actual = '\n'.join(filtered_lines).splitlines(1)
# Print Actual table
- # print("Router r%s table" % i)
+ # logger.info("Router r%s table" % i)
# for line in actual:
- # print(line.rstrip())
+ # logger.info(line.rstrip())
# Generate Diff
diff = topotest.get_textdiff(actual, expected,
@@ -368,64 +364,60 @@ def test_linux_ipv6_kernel_routingTable():
sys.stderr.write('r%s failed Linux IPv6 Kernel Routing Table Check:\n%s\n' % (i, diff))
failures += 1
else:
- print("r%s ok" % i)
+ logger.info("r%s ok" % i)
assert failures == 0, "Linux Kernel IPv6 Routing Table verification failed for router r%s:\n%s" % (i, diff)
- # For debugging after starting FRR/Quagga daemons, uncomment the next line
- # CLI(net)
-
def test_shutdown_check_stderr():
- global fatal_error
- global net
- # Skip if previous fatal error condition is raised
- if (fatal_error != ""):
- pytest.skip(fatal_error)
+ tgen = get_topogen()
+
+ if tgen.routers_have_failure():
+ pytest.skip('skipped because of router(s) failure')
if os.environ.get('TOPOTESTS_CHECK_STDERR') is None:
- print("SKIPPED final check on StdErr output: Disabled (TOPOTESTS_CHECK_STDERR undefined)\n")
+ logger.info("SKIPPED final check on StdErr output: Disabled (TOPOTESTS_CHECK_STDERR undefined)\n")
pytest.skip('Skipping test for Stderr output')
- thisDir = os.path.dirname(os.path.realpath(__file__))
+ net = tgen.net
- print("\n\n** Verifying unexpected STDERR output from daemons")
- print("******************************************\n")
+ logger.info("\n\n** Verifying unexpected STDERR output from daemons")
+ logger.info("******************************************")
for i in range(1, 5):
net['r%s' % i].stopRouter()
log = net['r%s' % i].getStdErr('ospf6d')
if log:
- print("\nRouter r%s OSPF6d StdErr Log:\n%s" % (i, log))
+ logger.info("\nRouter r%s OSPF6d StdErr Log:\n%s" % (i, log))
log = net['r%s' % i].getStdErr('zebra')
if log:
- print("\nRouter r%s Zebra StdErr Log:\n%s" % (i, log))
+ logger.info("\nRouter r%s Zebra StdErr Log:\n%s" % (i, log))
def test_shutdown_check_memleak():
- global fatal_error
- global net
-
- # Skip if previous fatal error condition is raised
- if (fatal_error != ""):
- pytest.skip(fatal_error)
+ "Run the memory leak test and report results."
if os.environ.get('TOPOTESTS_CHECK_MEMLEAK') is None:
- print("SKIPPED final check on Memory leaks: Disabled (TOPOTESTS_CHECK_MEMLEAK undefined)\n")
+ logger.info("SKIPPED final check on Memory leaks: Disabled (TOPOTESTS_CHECK_MEMLEAK undefined)")
pytest.skip('Skipping test for memory leaks')
-
- thisDir = os.path.dirname(os.path.realpath(__file__))
+
+ tgen = get_topogen()
+
+ net = tgen.net
for i in range(1, 5):
net['r%s' % i].stopRouter()
- net['r%s' % i].report_memory_leaks(os.environ.get('TOPOTESTS_CHECK_MEMLEAK'), os.path.basename(__file__))
+ net['r%s' % i].report_memory_leaks(
+ os.environ.get('TOPOTESTS_CHECK_MEMLEAK'),
+ os.path.basename(__file__))
if __name__ == '__main__':
- setLogLevel('info')
- # To suppress tracebacks, either use the following pytest call or add "--tb=no" to cli
+ # To suppress tracebacks, either use the following pytest call or
+ # add "--tb=no" to cli
# retval = pytest.main(["-s", "--tb=no"])
+
retval = pytest.main(["-s"])
sys.exit(retval)