aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJakub Ružička <jakub.ruzicka@nic.cz>2021-03-29 13:44:20 +0000
committerJakub Ružička <jakub.ruzicka@nic.cz>2021-03-29 13:44:20 +0000
commit775d9d26abd82367a4f5b58dd2964521b5ae399b (patch)
treed0e97b4657c79221618b0b31c9b5d7b6e989b44c
parentdd09ca301dec8c80426d2943591c89db994dd92a (diff)
parentdf3b50c14ca0bd9f06afa78e559345ab7a195ed0 (diff)
downloadbird-775d9d26abd82367a4f5b58dd2964521b5ae399b.tar.gz
Update upstream source from tag 'upstream/2.0.8'
Update to upstream version '2.0.8' with Debian dir 2c5e80c633911dcdc3b190c6eee1b8286d28ee1b
-rw-r--r--.gitlab-ci.yml415
-rw-r--r--ChangeLog1984
-rw-r--r--Makefile.in13
-rw-r--r--NEWS41
-rw-r--r--bird-gdb.py1
-rw-r--r--conf/cf-lex.l16
-rw-r--r--conf/conf.c10
-rw-r--r--conf/conf.h18
-rw-r--r--conf/confbase.Y6
-rw-r--r--conf/gen_keywords.m46
-rw-r--r--conf/gen_parser.m41
-rwxr-xr-xconfigure4196
-rw-r--r--configure.ac19
-rw-r--r--doc/bird.aux520
-rw-r--r--doc/bird.conf.example22
-rw-r--r--doc/bird.log472
-rw-r--r--doc/bird.pdfbin356743 -> 0 bytes
-rw-r--r--doc/bird.sgml352
-rw-r--r--doc/bird.toc70
-rw-r--r--doc/prog.aux87
-rw-r--r--doc/prog.log388
-rw-r--r--doc/prog.pdfbin456876 -> 0 bytes
-rw-r--r--doc/prog.sgml6868
-rw-r--r--doc/prog.toc55
-rw-r--r--filter/config.Y171
-rw-r--r--filter/data.c64
-rw-r--r--filter/data.h37
-rw-r--r--filter/decl.m4110
-rw-r--r--filter/f-inst.c315
-rw-r--r--filter/f-inst.h41
-rw-r--r--filter/filter.c5
-rw-r--r--filter/filter.h2
-rw-r--r--filter/filter_test.c50
-rw-r--r--filter/test.conf59
-rw-r--r--filter/test.conf21
-rw-r--r--filter/tree.c18
-rw-r--r--filter/trie.c291
-rw-r--r--filter/trie_test.c6
-rw-r--r--lib/Makefile4
-rw-r--r--lib/birdlib.h14
-rw-r--r--lib/bitmap.c197
-rw-r--r--lib/bitmap.h63
-rw-r--r--lib/bitmap_test.c186
-rw-r--r--lib/bitops.h3
-rw-r--r--lib/buffer.h2
-rw-r--r--lib/event.c56
-rw-r--r--lib/event.h3
-rw-r--r--lib/fletcher16_test.c31
-rw-r--r--lib/flowspec.c113
-rw-r--r--lib/flowspec.h11
-rw-r--r--lib/flowspec_test.c60
-rw-r--r--lib/ip.c5
-rw-r--r--lib/ip.h7
-rw-r--r--lib/ip_test.c37
-rw-r--r--lib/lists.c79
-rw-r--r--lib/lists_test.c13
-rw-r--r--lib/net.h4
-rw-r--r--lib/resource.c3
-rw-r--r--lib/resource.h1
-rw-r--r--lib/slab.c31
-rw-r--r--lib/socket.h4
-rw-r--r--lib/string.h9
-rw-r--r--lib/timer.c4
-rw-r--r--lib/timer.h4
-rw-r--r--nest/a-path.c77
-rw-r--r--nest/attrs.h5
-rw-r--r--nest/bfd.h22
-rw-r--r--nest/cli.c1
-rw-r--r--nest/cli.h3
-rw-r--r--nest/cmds.c1
-rw-r--r--nest/config.Y133
-rw-r--r--nest/iface.c10
-rw-r--r--nest/iface.h11
-rw-r--r--nest/neighbor.c120
-rw-r--r--nest/password.h2
-rw-r--r--nest/proto.c348
-rw-r--r--nest/protocol.h27
-rw-r--r--nest/route.h37
-rw-r--r--nest/rt-attr.c16
-rw-r--r--nest/rt-fib.c35
-rw-r--r--nest/rt-show.c35
-rw-r--r--nest/rt-table.c686
-rw-r--r--proto/babel/babel.c33
-rw-r--r--proto/babel/babel.h4
-rw-r--r--proto/babel/config.Y8
-rw-r--r--proto/babel/packets.c8
-rw-r--r--proto/bfd/bfd.c150
-rw-r--r--proto/bfd/bfd.h19
-rw-r--r--proto/bfd/config.Y22
-rw-r--r--proto/bfd/packets.c3
-rw-r--r--proto/bgp/attrs.c104
-rw-r--r--proto/bgp/bgp.c74
-rw-r--r--proto/bgp/bgp.h28
-rw-r--r--proto/bgp/config.Y21
-rw-r--r--proto/bgp/packets.c91
-rw-r--r--proto/mrt/mrt.c66
-rw-r--r--proto/mrt/mrt.h2
-rw-r--r--proto/ospf/config.Y10
-rw-r--r--proto/ospf/hello.c11
-rw-r--r--proto/ospf/iface.c40
-rw-r--r--proto/ospf/lsack.c1
-rw-r--r--proto/ospf/neighbor.c21
-rw-r--r--proto/ospf/ospf.c18
-rw-r--r--proto/ospf/ospf.h20
-rw-r--r--proto/ospf/packet.c30
-rw-r--r--proto/ospf/rt.c12
-rw-r--r--proto/ospf/topology.c26
-rw-r--r--proto/perf/perf.c67
-rw-r--r--proto/perf/perf.h3
-rw-r--r--proto/pipe/config.Y2
-rw-r--r--proto/pipe/pipe.c18
-rw-r--r--proto/radv/packets.c4
-rw-r--r--proto/radv/radv.c2
-rw-r--r--proto/radv/radv.h2
-rw-r--r--proto/rip/config.Y16
-rw-r--r--proto/rip/packets.c313
-rw-r--r--proto/rip/rip.c146
-rw-r--r--proto/rip/rip.h23
-rw-r--r--proto/rpki/config.Y7
-rw-r--r--proto/rpki/packets.c11
-rw-r--r--proto/rpki/rpki.c54
-rw-r--r--proto/rpki/rpki.h1
-rw-r--r--proto/rpki/ssh_transport.c14
-rw-r--r--proto/rpki/tcp_transport.c22
-rw-r--r--proto/rpki/transport.c25
-rw-r--r--proto/rpki/transport.h2
-rw-r--r--proto/static/config.Y2
-rw-r--r--proto/static/static.c166
-rw-r--r--proto/static/static.h2
-rw-r--r--sysdep/autoconf.h.in15
-rw-r--r--sysdep/bsd/krt-sock.c11
-rw-r--r--sysdep/bsd/krt-sys.h2
-rw-r--r--sysdep/bsd/setkey.h20
-rw-r--r--sysdep/bsd/sysio.h4
-rw-r--r--sysdep/config.h2
-rw-r--r--sysdep/linux/netlink.c130
-rw-r--r--sysdep/linux/sysio.h63
-rw-r--r--sysdep/unix/config.Y18
-rw-r--r--sysdep/unix/io.c11
-rw-r--r--sysdep/unix/krt.c234
-rw-r--r--sysdep/unix/krt.h21
-rw-r--r--sysdep/unix/log.c33
-rw-r--r--sysdep/unix/main.c40
-rw-r--r--sysdep/unix/unix.h14
-rw-r--r--test/birdtest.c16
-rw-r--r--test/birdtest.h8
-rw-r--r--test/bt-utils.c2
-rwxr-xr-xtools/gendist4
148 files changed, 8787 insertions, 12808 deletions
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
new file mode 100644
index 00000000..763e4405
--- /dev/null
+++ b/.gitlab-ci.yml
@@ -0,0 +1,415 @@
+variables:
+ DEBIAN_FRONTEND: noninteractive
+ LC_ALL: C
+ GIT_STRATEGY: fetch
+ DOCKER_CMD: docker --config="$HOME/.docker/$CI_JOB_ID/"
+ IMG_BASE: registry.labs.nic.cz/labs/bird
+ TOOLS_DIR: /var/lib/gitlab-runner/bird-tools
+
+stages:
+ - image
+ - build
+ - test
+
+.docker: &docker_build
+ stage: image
+ allow_failure: true
+ script:
+ - $DOCKER_CMD login -u gitlab-ci-token -p $CI_BUILD_TOKEN registry.labs.nic.cz
+ # Make sure we refresh the base image if it updates (eg. security updates, etc)
+ # If we do just the build, cache is always reused and the freshness of the
+ # base image is never checked. However, pull always asks and updates the
+ # image only if it changed ‒ therefore, the cache is used unless there's a
+ # change.
+ - $DOCKER_CMD pull `sed -ne 's/^FROM //p' "misc/docker/$IMG_NAME/Dockerfile"`
+ - $DOCKER_CMD build -t "bird:$IMG_NAME" "misc/docker/$IMG_NAME"
+ - $DOCKER_CMD tag "bird:$IMG_NAME" "$IMG_BASE:$IMG_NAME"
+ - $DOCKER_CMD push "$IMG_BASE:$IMG_NAME"
+ after_script:
+ - rm -f "$HOME/.docker/$CI_JOB_ID/" # cleanup the credentials
+ tags:
+ # That's Docker in Docker
+ - dind
+
+docker_debian-7-amd64:
+ variables:
+ IMG_NAME: "debian-7-amd64"
+ <<: *docker_build
+
+docker_debian-7-i386:
+ variables:
+ IMG_NAME: "debian-7-i386"
+ <<: *docker_build
+
+docker_debian-8-amd64:
+ variables:
+ IMG_NAME: "debian-8-amd64"
+ <<: *docker_build
+
+docker_debian-8-i386:
+ variables:
+ IMG_NAME: "debian-8-i386"
+ <<: *docker_build
+
+docker_debian-9-amd64:
+ variables:
+ IMG_NAME: "debian-9-amd64"
+ <<: *docker_build
+
+docker_debian-9-i386:
+ variables:
+ IMG_NAME: "debian-9-i386"
+ <<: *docker_build
+
+docker_debian-10-amd64:
+ variables:
+ IMG_NAME: "debian-10-amd64"
+ <<: *docker_build
+
+docker_debian-10-i386:
+ variables:
+ IMG_NAME: "debian-10-i386"
+ <<: *docker_build
+
+docker_debian-testing-amd64:
+ variables:
+ IMG_NAME: "debian-testing-amd64"
+ <<: *docker_build
+
+docker_debian-testing-i386:
+ variables:
+ IMG_NAME: "debian-testing-i386"
+ <<: *docker_build
+
+docker_fedora-25-amd64:
+ variables:
+ IMG_NAME: "fedora-25-amd64"
+ <<: *docker_build
+
+docker_fedora-26-amd64:
+ variables:
+ IMG_NAME: "fedora-26-amd64"
+ <<: *docker_build
+
+docker_fedora-27-amd64:
+ variables:
+ IMG_NAME: "fedora-27-amd64"
+ <<: *docker_build
+
+docker_fedora-28-amd64:
+ variables:
+ IMG_NAME: "fedora-28-amd64"
+ <<: *docker_build
+
+docker_fedora-29-amd64:
+ variables:
+ IMG_NAME: "fedora-29-amd64"
+ <<: *docker_build
+
+docker_fedora-30-amd64:
+ variables:
+ IMG_NAME: "fedora-30-amd64"
+ <<: *docker_build
+
+docker_fedora-31-amd64:
+ variables:
+ IMG_NAME: "fedora-31-amd64"
+ <<: *docker_build
+
+docker_centos-7-amd64:
+ variables:
+ IMG_NAME: "centos-7-amd64"
+ <<: *docker_build
+
+docker_centos-8-amd64:
+ variables:
+ IMG_NAME: "centos-8-amd64"
+ <<: *docker_build
+
+docker_ubuntu-14_04-amd64:
+ variables:
+ IMG_NAME: "ubuntu-14.04-amd64"
+ <<: *docker_build
+
+docker_ubuntu-16_04-amd64:
+ variables:
+ IMG_NAME: "ubuntu-16.04-amd64"
+ <<: *docker_build
+
+docker_ubuntu-18_04-amd64:
+ variables:
+ IMG_NAME: "ubuntu-18.04-amd64"
+ <<: *docker_build
+
+docker_ubuntu-19_10-amd64:
+ variables:
+ IMG_NAME: "ubuntu-19.10-amd64"
+ <<: *docker_build
+
+docker_opensuse-15.0-amd64:
+ variables:
+ IMG_NAME: "opensuse-15.0-amd64"
+ <<: *docker_build
+
+docker_opensuse-15.1-amd64:
+ variables:
+ IMG_NAME: "opensuse-15.1-amd64"
+ <<: *docker_build
+
+# TODO We want to copy these BSDs to our own virtual machines, to make sure
+# someone doesn't update them by accident.
+.freebsd-11-i386: &freebsd-11-i386_env
+ tags:
+ - freebsd
+ - i386
+ #only:
+ #- master
+ #- triggers
+ #- tags
+
+.freebsd-11-amd64: &freebsd-11-amd64_env
+ tags:
+ - freebsd
+ - amd64
+
+.build: &build-base
+ stage: build
+ script:
+ - autoreconf
+ - ./configure CPPFLAGS="$CPPFLAGS" LDFLAGS="$LDFLAGS"
+ # Detect which make is available
+ - MAKE=make
+ - which gmake 2>/dev/null >/dev/null && MAKE=gmake
+ - $MAKE
+ # Run tests if they are available
+ - $MAKE check
+
+.build-linux: &build-linux
+ <<: *build-base
+ tags:
+ - docker
+ - linux
+ - amd64
+
+build-debian-7-amd64:
+ <<: *build-linux
+ image: registry.labs.nic.cz/labs/bird:debian-7-amd64
+
+build-debian-7-i386:
+ <<: *build-linux
+ image: registry.labs.nic.cz/labs/bird:debian-7-i386
+
+build-debian-8-amd64:
+ <<: *build-linux
+ image: registry.labs.nic.cz/labs/bird:debian-8-amd64
+
+build-debian-8-i386:
+ <<: *build-linux
+ image: registry.labs.nic.cz/labs/bird:debian-8-i386
+
+build-debian-9-amd64:
+ <<: *build-linux
+ image: registry.labs.nic.cz/labs/bird:debian-9-amd64
+
+build-debian-9-i386:
+ <<: *build-linux
+ image: registry.labs.nic.cz/labs/bird:debian-9-i386
+
+build-debian-10-amd64:
+ <<: *build-linux
+ image: registry.labs.nic.cz/labs/bird:debian-10-amd64
+
+build-debian-10-i386:
+ <<: *build-linux
+ image: registry.labs.nic.cz/labs/bird:debian-10-i386
+
+build-debian-testing-amd64:
+ <<: *build-linux
+ image: registry.labs.nic.cz/labs/bird:debian-testing-amd64
+
+build-debian-testing-i386:
+ <<: *build-linux
+ image: registry.labs.nic.cz/labs/bird:debian-testing-i386
+
+build-fedora-25-amd64:
+ <<: *build-linux
+ image: registry.labs.nic.cz/labs/bird:fedora-25-amd64
+
+build-fedora-26-amd64:
+ <<: *build-linux
+ image: registry.labs.nic.cz/labs/bird:fedora-26-amd64
+
+build-fedora-27-amd64:
+ <<: *build-linux
+ image: registry.labs.nic.cz/labs/bird:fedora-27-amd64
+
+build-fedora-28-amd64:
+ <<: *build-linux
+ image: registry.labs.nic.cz/labs/bird:fedora-28-amd64
+
+build-fedora-29-amd64:
+ <<: *build-linux
+ image: registry.labs.nic.cz/labs/bird:fedora-29-amd64
+
+build-fedora-30-amd64:
+ <<: *build-linux
+ image: registry.labs.nic.cz/labs/bird:fedora-30-amd64
+
+build-fedora-31-amd64:
+ <<: *build-linux
+ image: registry.labs.nic.cz/labs/bird:fedora-31-amd64
+
+build-centos-7-amd64:
+ <<: *build-linux
+ image: registry.labs.nic.cz/labs/bird:centos-7-amd64
+
+build-centos-8-amd64:
+ <<: *build-linux
+ image: registry.labs.nic.cz/labs/bird:centos-8-amd64
+
+build-ubuntu-14_04-amd64:
+ <<: *build-linux
+ image: registry.labs.nic.cz/labs/bird:ubuntu-14.04-amd64
+
+build-ubuntu-16_04-amd64:
+ <<: *build-linux
+ image: registry.labs.nic.cz/labs/bird:ubuntu-16.04-amd64
+
+build-ubuntu-18_04-amd64:
+ <<: *build-linux
+ image: registry.labs.nic.cz/labs/bird:ubuntu-18.04-amd64
+
+build-ubuntu-19_04-amd64:
+ <<: *build-linux
+ image: registry.labs.nic.cz/labs/bird:ubuntu-19.04-amd64
+
+build-opensuse-15.0-amd64:
+ <<: *build-linux
+ image: registry.labs.nic.cz/labs/bird:opensuse-15.0-amd64
+
+build-opensuse-15.1-amd64:
+ <<: *build-linux
+ image: registry.labs.nic.cz/labs/bird:opensuse-15.1-amd64
+
+build-freebsd-11-amd64:
+ <<: *build-base
+ tags:
+ - freebsd
+ - amd64
+
+build-freebsd-11-i386:
+ <<: *build-base
+ tags:
+ - freebsd
+ - i386
+
+build-birdlab:
+ stage: build
+ tags:
+ - birdlab
+ - amd64
+ script:
+ - DIR=$(pwd)
+ - autoreconf
+ - ./configure
+ - make
+ - cd $TOOLS_DIR
+ - sudo git clean -fx
+ - git pull --ff-only
+ - mv $DIR/bird $DIR/birdc netlab/common
+
+.test: &test-base
+ stage: test
+ needs: [build-birdlab]
+ tags:
+ - birdlab
+ - amd64
+ script:
+ - cd $TOOLS_DIR/netlab
+ - sudo ./stop
+ - sudo ./runtest -m check $TEST_NAME
+
+test-ospf-base:
+ <<: *test-base
+ variables:
+ TEST_NAME: cf-ospf-base
+
+test-ospf-default:
+ <<: *test-base
+ variables:
+ TEST_NAME: cf-ospf-default
+
+test-ospf-priority:
+ <<: *test-base
+ variables:
+ TEST_NAME: cf-ospf-priority
+
+test-ospf-nbma:
+ <<: *test-base
+ variables:
+ TEST_NAME: cf-ospf-nbma
+
+test-ospf-ptmp:
+ <<: *test-base
+ variables:
+ TEST_NAME: cf-ospf-ptmp
+
+test-ospf-authentication:
+ <<: *test-base
+ variables:
+ TEST_NAME: cf-ospf-authentication
+
+test-ospf-bfd:
+ <<: *test-base
+ variables:
+ TEST_NAME: cf-ospf-bfd
+
+test-ospf-custom:
+ <<: *test-base
+ variables:
+ TEST_NAME: cf-ospf-custom
+
+test-ospf-vrf:
+ <<: *test-base
+ variables:
+ TEST_NAME: cf-ospf-vrf
+
+test-bgp-base:
+ <<: *test-base
+ variables:
+ TEST_NAME: cf-bgp-base
+
+test-bgp-auth:
+ <<: *test-base
+ variables:
+ TEST_NAME: cf-bgp-auth
+
+test-bgp-int:
+ <<: *test-base
+ variables:
+ TEST_NAME: cf-bgp-int
+
+test-bgp-merged:
+ <<: *test-base
+ variables:
+ TEST_NAME: cf-bgp-merged
+
+test-ebgp-loop:
+ <<: *test-base
+ variables:
+ TEST_NAME: cf-ebgp-loop
+
+test-ebgp-star:
+ <<: *test-base
+ variables:
+ TEST_NAME: cf-ebgp-star
+
+test-ibgp-loop:
+ <<: *test-base
+ variables:
+ TEST_NAME: cf-ibgp-loop
+
+test-ibgp-star:
+ <<: *test-base
+ variables:
+ TEST_NAME: cf-ibgp-flat
diff --git a/ChangeLog b/ChangeLog
index cb6fc4d0..02fcdaf2 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,1505 @@
+commit 82f19ba95e421f00a8e99a866a2b8d9bbdba6cdc
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Thu Mar 18 20:18:38 2021 +0100
+
+ NEWS and version update
+
+commit f1ffe6a23144a4b13f020194f23055ac8c20dea6
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Thu Mar 18 15:54:44 2021 +0100
+
+ Add new BGP tests
+
+commit 5a6e8380f89deb4fff21805a7879658d2352471a
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Thu Mar 18 15:44:04 2021 +0100
+
+ BGP: Do not show statistics
+
+ BGP statistics code was preliminary and i wanted to replace it by
+ separate 'show X stats' command. The patch hides the preliminary
+ output in 'show protocols all' so it is not part of the released
+ version.
+
+commit 454ae3044598466ca7c50c12c6882d84ea545afa
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Wed Mar 17 17:24:00 2021 +0100
+
+ RPKI: Improve error handling of DNS resolver
+
+commit 0a3db4c68040473ab45b974a7f9256c277c5d31c
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Wed Mar 17 15:56:12 2021 +0100
+
+ Minor fixes for restricted builds
+
+commit 2f981534902302cbd13cdb12d4f0c6e9a255687a
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Tue Mar 16 20:10:00 2021 +0100
+
+ Pipe: Propagate debug flags from protocol to channels
+
+ Pipe channels are kind-of implicit, so setting protocol debug flags
+ should also set pipe debug flags.
+
+commit ae9ae864d3fec20a74ce2567536e186ce178d032
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Tue Mar 16 16:34:42 2021 +0100
+
+ OSPFv3: Update neighbor authentication state from Hello packets
+
+ In OSPFv3, only Hello and DBDes packets contain flags specifying whether
+ RFC 7166 authentication trailer is used. Other packets are processed
+ based on stored authentication state in neighbor structure. Update this
+ state with each received Hello to handle authentication change from
+ reconfigurations.
+
+ Thanks to Joakim Tjernlund and Kenth Eriksson for the bugreport.
+
+commit 94abefc00bb22b93493831798391d5d5b21f9d4c
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Mon Mar 15 18:35:23 2021 +0100
+
+ Filter: Update 'gw' to handle IPv6 link-local addresses
+
+ When a link-local address is set, use the existing iface for scope.
+
+ Thanks to Marcel Krüger for the bugreport.
+
+commit 0d1a11cca3136828808b8e73f4d5e547cc787fb8
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Mon Mar 15 17:51:33 2021 +0100
+
+ Doc: Document automatic RPKI reload
+
+commit 6489a2450e0ab4aa63c25ac2f9be354fdbd711d2
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Mon Mar 15 16:16:32 2021 +0100
+
+ Doc: Document channel debug options
+
+commit 7be3af7fa662958782d2e23989d79cc2c652b6bf
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Fri Mar 12 15:35:56 2021 +0100
+
+ Rate-limit scheduling of work-events
+
+ In general, events are code handling some some condition, which is
+ scheduled when such condition happened and executed independently from
+ I/O loop. Work-events are a subgroup of events that are scheduled
+ repeatedly until some (often significant) work is done (e.g. feeding
+ routes to protocol). All scheduled events are executed during each
+ I/O loop iteration.
+
+ Separate work-events from regular events to a separate queue and
+ rate limit their execution to a fixed number per I/O loop iteration.
+ That should prevent excess latency when many work-events are
+ scheduled at one time (e.g. simultaneous reload of many BGP sessions).
+
+commit 9cf3d533110313d55b60d47c134f1b7050d6be78
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Wed Mar 10 15:07:19 2021 +0100
+
+ Static: Implement reload hook
+
+commit 211fe69c984c657095930d2831f46896197ec65b
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Mon Mar 8 20:45:22 2021 +0100
+
+ Nest: No automatic ROA reload on non-reloadable channels
+
+commit d3782c72b9243f4609e61edf5f29e6adeaa41e9c
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Fri Feb 12 05:05:18 2021 +0100
+
+ Nest: Add option to control automatic RPKI reload
+
+ Also, no automatic reload for BGP channels without import/export table.
+
+commit 77ce849ecf0f89455eeabefbe520c6b4888837b0
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Wed Feb 10 17:29:14 2021 +0100
+
+ Tests: Add missing mockup function to tests
+
+commit 714238716ef36f1dfc5721055e2ec4affd42ebfa
+Author: Vincent Bernat <vincent@bernat.ch>
+Date: Wed Feb 10 16:53:57 2021 +0100
+
+ BGP: Add support for BGP hostname capability
+
+ This is an implementation of draft-walton-bgp-hostname-capability-02.
+ It is implemented since quite some time for FRR and in datacenter, this
+ gives a nice output to avoid using IP addresses.
+
+ It is disabled by default. The hostname is retrieved from uname(2) and
+ can be overriden with "hostname" option. The domain name is never set
+ nor displayed.
+
+ Minor changes by committer.
+
+commit 00b85905b9f5081eb2fce0ed79542085278e9f42
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Wed Feb 10 03:09:57 2021 +0100
+
+ Nest: Automatic channel reloads based on RPKI changes
+
+ If there are roa_check() calls in channel filters, then the channel
+ subscribes to ROA table notifications, which are sent when ROA tables
+ are updated (subject to settle time) and trigger channel reload or
+ refeed.
+
+commit d06a875b042b608e61b2d5a2bb594641d3e1322f
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Sun Feb 7 19:21:42 2021 +0100
+
+ Filter: Recursive filter iteration code
+
+ Add macros for recursive filter iteration that allows to examine
+ all instructions reachable from a filter.
+
+commit 5d414309ec5a01024d4de4c4f9521f8daa5c06ff
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Fri Jan 22 04:34:15 2021 +0100
+
+ MRT: Fix MP-BGP next hops
+
+ Flag signalling that MP-BGP mode should be used got reset after first
+ batch of routes, so remaining routes were processed without that, leading
+ to missing MP_REACH_NLRI attribute.
+
+ Thanks to Piotr Wydrych for the bugreport.
+
+commit df83f626973fda1e67769d295c47d4d246e4c1c4
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Thu Jan 14 01:51:09 2021 +0100
+
+ Netlink: Ignore dead routes
+
+ With net.ipv4.conf.XXX.ignore_routes_with_linkdown sysctl, a user can
+ ensure the kernel does not use a route whose target interface is down.
+ Such route is marked with a 'dead' / RTNH_F_DEAD flag.
+
+ Ignore these routes or multipath nexthops during scan.
+
+ Thanks to Vincent Bernat for the original patch.
+
+commit a40ddf5c616465a93287e4ac41a98d04b4fb2b37
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Tue Jan 12 15:43:54 2021 +0100
+
+ Build: Fix tags generation
+
+commit d774f6d721b0e52ed800c4b9a3a482c8ce9dd074
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Tue Jan 12 15:37:01 2021 +0100
+
+ MRT: Fix IPv6 table dumps
+
+ Add fake MP_REACH_NLRI attribute with BGP next hop when encoding MRT
+ table dumps for IPv6 routes. That is necessary to encode next hop as
+ NEXT_HOP attribute is not used for MP-BGP.
+
+ Thanks to Santiago Aggio for the bugreport.
+
+commit 910adaa08bbd416288797505399ab47f990817e6
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Sun Jan 10 15:29:02 2021 +0100
+
+ BFD: Dispatch sessions also by interface index
+
+ Direct BFD sessions needs to be dispatched not only by IP addresses, but
+ also by interfaces, in order to avoid collisions between neighbors with
+ the same IPv6 link-local addresses.
+
+ Extend BFD session hash_ip key by interface index to handle that. Use 0
+ for multihop sessions.
+
+ Thanks to Sebastian Hahn for the original patch.
+
+commit 17663b6a7c505226cfe9ccc0671611075a3dff57
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Thu Jan 7 05:56:34 2021 +0100
+
+ RPKI: Remove port (and SSH username) from 'Cache server' output line
+
+ It was mixed-up if hostname is IPv6 address, and reporting separate
+ values (like port) on separate lines fits better into key-value style
+ of 'show protocols all' output. Also, the patch simplifies transport
+ identification formatting (although it is unused now).
+
+ Thanks to Alarig Le Lay for the suggestion.
+
+commit 2a8cc7259e236773f1b8423ef63305a5b8bfd652
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Thu Jan 7 01:56:00 2021 +0100
+
+ Kernel: Do not check templates
+
+ So one can define kernel protocol template without channels.
+ For other protocols, it is either irrelevant or already done.
+
+ Thanks to Clemens Schrimpe for the bugreport.
+
+commit a141959f0729b2381a90aaa9b7ed0e41a5f9513e
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Thu Jan 7 01:20:56 2021 +0100
+
+ Doc: Describe per-nexthop static route options
+
+ Also remove description of (no longer supported) per-route 'bfd' option,
+ and add examples of IPv6 routes with link-local nexthops.
+
+commit 7a1f4baac11cbfad82a2d09a130b3ae7bb48e9bd
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Wed Jan 6 14:51:49 2021 +0100
+
+ Nest: remove last_tx_filter_change
+
+ No longer needed after redesign of export handling.
+
+commit 4155104c90bc2f3fb680e8041e079ceb3d80a3b1
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Wed Jan 6 14:44:23 2021 +0100
+
+ BGP: Deprecate 'missing lladdr' option
+
+ The option is not implemented since transition to 2.0 and no plan to add it.
+ Also remove some deprecated RTS_* valus from documentation.
+
+ Thanks to Sébastien Parisot for notification.
+
+commit 21f9acd2a01306af01f19914105985a8a0f9bcba
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Wed Jan 6 05:25:59 2021 +0100
+
+ Kernel: Fix handling of krt_realm with ECMP routes
+
+ For ECMP routes, RTA_FLOW attribute must be set per-nexthop, not
+ per-route. Our corresponding krt_realm attribute is per-route.
+
+ Thanks to Mikhail Petrov for the bugreport.
+
+commit 455c13dc9971ae4aa701135b5c1709d61477bdec
+Author: James Lu <james@overdrivenetworks.com>
+Date: Tue Dec 29 02:23:54 2020 +0100
+
+ Nest: Read Babel metric as IGP metric
+
+ (Minor syntactic changes by committer)
+
+commit ea3c6c1a15ce9b93f583f96919c70f7a2fd34e98
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Mon Dec 28 21:19:27 2020 +0100
+
+ Static: Fix handling of 'net' attribute in per-route filters
+
+ We need to define 'net' field temporarily as it may be accessed by
+ per-route filters.
+
+ Thanks to Damian Zaremba for the bugreport.
+
+commit 9e2635505a08e3453eef487360e49b4b70987ceb
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Mon Dec 28 15:23:28 2020 +0100
+
+ Filter: Fix return on top-level
+
+ Broken detection of top-level case caused crash when return was called
+ from top-of-stack position. It should behave as reject/accept.
+
+ Thanks to Damian Zaremba for the bugreport.
+
+commit 61dae32b29cc57b9884a1c13e5d630096e157a38
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Mon Dec 7 22:19:40 2020 +0100
+
+ Nest: Per-channel debug flags
+
+ The patch add support for per-channel debug flags, currently just
+ 'states', 'routes', and 'filters'. Flag 'states' is used for channel
+ state changes, remaining two for routes passed through the channel.
+ The per-protocol debug flags 'routes'/'filters' still enable reporting
+ of routes for all channels, to keep existing behavior.
+
+ The patch causes minor changes in some log messages.
+
+commit 8cc5bb09e344038a1f8dff96946e05ec80607c93
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Wed Dec 2 05:02:26 2020 +0100
+
+ Filter: Add 'weight' route attribute
+
+ Add 'weight' route attribute that allows to get and set ECMP weight of
+ nexthops. Similar to 'gw' attribute, it is limited to the first nexthop,
+ but it is useful for handling BGP multipath, where an ECMP route is
+ merged from multiple regular routes.
+
+commit 246586771296d1c42a012c06bdc75b36a7ce0b4f
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Wed Nov 25 15:44:00 2020 +0100
+
+ BGP: Zero the newly allocated bucket structure
+
+ This fixes an issue with dirty node passed to add_tail().
+
+ Thanks to Andreas Rammhold for the initial patch.
+
+commit 62d57b9bdf82cc978f889f0118c8aa19ae999a3d
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Wed Nov 25 15:15:13 2020 +0100
+
+ Log: Fix locking during log reconfiguration
+
+ The log subsystem should be locked earlier, as default_log_list() may
+ internally manipulate with the current_log_list (if it is also a default
+ log list).
+
+commit 0ef082c51e5d905e9137e1484036b9d9b32e9a75
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Wed Nov 25 15:04:34 2020 +0100
+
+ Log: Reinitialize the static logging structures
+
+ The static logging structures are reused, we need to reinitialize them
+ otherwise add_tail() would fail in debug build. Reinitializing these
+ structures should be fine as the list they belong to is being
+ reinitialized on entry to the very same function.
+
+ Thanks to Andreas Rammhold and Mikael Magnusson for patches.
+
+commit 30b846826905b4da76f59a212a31928bd55e9783
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Tue Nov 24 04:09:11 2020 +0100
+
+ Minor cleanups with cfg_allocz()
+
+ Also fixes some more failed asserts due to add_tail().
+
+commit 1678bc07467e6d977fc2f6bf830274ca92e0a6e5
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Tue Nov 24 03:42:23 2020 +0100
+
+ Fix some failed asserts due to add_tail()
+
+ When config structures are copied due to template application,
+ we need to reset list node structure before calling add_tail().
+
+ Thanks to Mikael Magnusson for patches.
+
+commit c9ae81656f97bcc55910e80b6f00d3ee9383d848
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Tue Nov 24 03:21:44 2020 +0100
+
+ Some minor sl_allocz() cleanups
+
+commit db2d29073acfd4086fca18ba43a5ed6baccaa8ad
+Author: Toke Høiland-Jørgensen <toke@toke.dk>
+Date: Tue Nov 24 02:32:13 2020 +0100
+
+ lib/slab: introduce sl_allocz() function and use it in Babel
+
+ The babel protocol code was initialising objects returned from the slab
+ allocator by assigning to each of the struct members individually, but
+ wasn't touching the NODE member while doing so. This leads to warnings on
+ debug builds since commit:
+
+ baac7009063d ("List expensive check.")
+
+ To fix this, introduce an sl_allocz() variant of the slab allocator which
+ will zero out the memory before returning it, and switch all the babel call
+ sites to use this version. The overhead for doing this should be negligible
+ for small objects, and in the case of babel, the largest object being
+ allocated was being zeroed anyway, so we can drop the memset in
+ babel_read_tlv().
+
+commit 3347aaafec5b269637604d1ea5f5969797beadea
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Thu Nov 19 16:38:39 2020 +0100
+
+ Static: Support for multiple routes with the same network
+
+ Add support for proper handling of multiple routes with the same network
+ to the static protocol. Routes are distinguished by internal index, which
+ is assigned automatically (sequentially for routes within each network).
+ Having different route preference or igp_metric attribute is optional.
+
+commit df65d519d6a5a7511cc893d2be55399b38b838be
+Author: Nigel Kukard <nkukard@lbsd.net>
+Date: Wed Nov 18 18:00:12 2020 +0100
+
+ Doc: Added example of static routes with BGP large communities
+
+commit 00ddd18b02a4a4db973adecf6ef63a350c909cbd
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Wed Nov 18 17:37:29 2020 +0100
+
+ OSPFv3: Fix intra-area-prefix-LSA origination on DR
+
+ When a new link-LSA is originated, we need to notify intra-area-prefix-LSA
+ handling, like when a new link-LSA is received. Otherwise a new network
+ prefix added to a DR is not propagated immediately.
+
+ Thanks to Bala Sajja for the bugreport.
+
+commit 6ea8a46ccb540701dfe747566e6a5b7bc318db01
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Sun Nov 15 16:28:13 2020 +0100
+
+ Doc: Fix typo
+
+ Thanks to Hexhu for the bugreport.
+
+commit b962967e20f186f797c163f69c673b0ee4ef3b2b
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Sun Nov 15 16:01:19 2020 +0100
+
+ Nest: Fix crash in receive limit handling in import table
+
+ Logging as a result of triggered receive limit in import table code
+ accesset rte->net, which was not filed yet.
+
+ Thanks to Pier Carlo Chiodi for the bugreport.
+
+commit 4a42e7e92520e7d07e585d542ef54e1de302fb1d
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Thu Nov 12 04:50:45 2020 +0100
+
+ BFD: Update documentation about per-session options
+
+commit 3b56bf8849283977f2f4fa7b8f3dc62fdd8d7587
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Thu Nov 12 04:02:38 2020 +0100
+
+ BFD: Better handling of BFD options in BGP configs
+
+ Merge multiple BFD option blocks in BGP configs instead of using the last
+ one. That is necessary for proper handling of templates when BFD options
+ are used both in a BGP template and in a BGP protocol derived from that
+ template.
+
+commit 99ad208dd73d357156672a53f48b77dcf6515c30
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Thu Nov 12 02:37:42 2020 +0100
+
+ BFD: Fix superfluous reconfiguration of sessions
+
+commit 9d3fc3062b236f51b2c72a4c2c7b068f1946261d
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Sun Nov 8 15:33:22 2020 +0100
+
+ BFD: Allow per-request session options
+
+ BFD session options are configured per interface in BFD protocol. This
+ patch allows to specify them also per-request in protocols requesting
+ sessions (currently limited to BGP).
+
+commit fc1e3211b109400c0e96f889829c9f5145ac7226
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Sun Oct 11 00:53:19 2020 +0200
+
+ RPKI: Add 'ignore max length' option
+
+ Add 'ignore max length' option to RPKI protocol, which ignores received
+ max length in ROA records and instead uses max value (32 or 128). This
+ may be useful for implementing loose RPKI check for blackholes.
+
+commit 6c11dbcf28faa145cfb7310310a2a261fd4dd1f2
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Mon Oct 5 14:52:55 2020 +0200
+
+ Doc: Fix missing semicolons
+
+ Thanks to Marco Gartmann for the bugreport.
+
+commit 14ce8904e7b9f6ceeaf2587faeab200cd67401d9
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Mon Oct 5 14:45:01 2020 +0200
+
+ Doc: Fix typo
+
+ Thanks to Sergey Kulikov for the bugreport.
+
+commit 600eb695b1a273f8b3fd4f2c524d8eeef25483aa
+Author: Maria Matejka <mq@ucw.cz>
+Date: Mon Aug 31 15:41:39 2020 +0200
+
+ OSPF: Fixed a debug assert
+
+commit dc8d9dec4a3484f358d2117328fe860e8e7b16bb
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Wed Aug 12 19:42:44 2020 +0200
+
+ OSPF: Skip out-of-state packets earlier
+
+ Sometimes multicast OSPF packet is received when neighbor adjacency is
+ not established. Such packet should be ignored earlier in packet
+ processing as otherwise it causes strange error messages when OSPFv3
+ authentication is enabled.
+
+commit c0e1f534c95f5f395fda62b01ea1c245323e3aed
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Thu Jul 16 15:02:10 2020 +0200
+
+ Nest: Keep route ordering during route updates
+
+ Put new non-best routes to the end of list instead of the second
+ position. Put updated routes to their old position. Position is changed
+ just by best route selection.
+
+commit c26c6bc2d78a2fe76f27dcc9fbb5afc95c3a7626
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Thu May 14 03:48:17 2020 +0200
+
+ Show info from multiple protocols when protocol is not specified
+
+ Most commands like 'show ospf neighbors' fail when protocol is not
+ specified and there are multiple instances of given protocol type.
+ This is annoying in BIRD 2, as many protocols have IPv4 and IPv6
+ instances. The patch changes that by showing output from all protocol
+ instances of appropriate type.
+
+ Note that the patch also removes terminating cli_msg() call from these
+ commands and moves it to the common iterating code.
+
+commit a948cf9a5c338518773e6c98e895c829c469f56b
+Author: Kazuki Yamaguchi <k@rhe.jp>
+Date: Sun Jun 28 15:37:01 2020 +0200
+
+ Filter: Improve handling of sets in BGP path masks
+
+ Compare the content of PM_ASN_SET in path masks. A reconfiguration
+ was not properly triggering a reload of affected protocols when the
+ members of a set in a path mask change.
+
+ Also, update the printing code to so that it can display sets in a path
+ mask.
+
+commit 4ef0a966392672d04a567c25758462fe3bbb0fb4
+Author: Kazuki Yamaguchi <k@rhe.jp>
+Date: Sun Jun 28 15:33:26 2020 +0200
+
+ Filter: Fix comparison of BGP path mask
+
+ Add a missing return statement. Path masks with the same length were all
+ considered the same. Comparing two with different length would cause
+ out-of-bounds memory access.
+
+commit 82937b465b3a50bdcb00eff0b7aa6acb3fc21772
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Wed Jun 10 13:27:14 2020 +0200
+
+ OSPF: Fix bad header length test
+
+ Thanks to Slava Aseev for the thorough bugreport.
+
+commit 71e08edd942557ec333902bb45c57794f7a66bf8
+Author: Kenth Eriksson <kenth.eriksson@infinera.com>
+Date: Wed Jun 3 23:05:29 2020 +0200
+
+ Doc: Add 'ptp address' to OSPF doc overview
+
+commit 63451c19611b5972769ed519bd7eb6c1b995a8a0
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Wed Jun 3 16:15:29 2020 +0200
+
+ Test: Fix unit test mockups
+
+commit f1b5f179dbd8aaef5eca4936b557e753e377d818
+Author: Kazuki Yamaguchi <k@rhe.jp>
+Date: Wed Jun 3 15:18:02 2020 +0200
+
+ Netlink: Fix parsing of MPLS multipath routes
+
+ Add support for RTA_MULTIPATH attribute parsing for AF_MPLS routes.
+
+ BIRD is capable of installing a multipath route into kernel on Linux,
+ but it would not be seen because parsing fails. This made BIRD attempt
+ to install the same route repeatedly.
+
+ (The patch minorly updated by committer)
+
+commit 19f8f173202d6f5cbf97ca2a9f66fcea6b9bb44f
+Author: Kazuki Yamaguchi <k@rhe.jp>
+Date: Wed Jun 3 15:05:35 2020 +0200
+
+ RPKI: Fix unnecessary reconnection on reconfiguration
+
+ Compare the new timing parameters with the old configuration, not with
+ the temporary state of the current connection.
+
+ The timing values in struct rpki_cache is updated by a version 1 End Of
+ Data PDU, unless this behavior is suppressed by the configuration
+ explicitly by the "keep" keyword. Consequently, every reconfiguration
+ of BIRD triggers a reconnection even if it is not necessary.
+
+commit fae5448134dfec004be818d18ff1583cc61e5549
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Sun May 31 13:21:55 2020 +0200
+
+ Log: Do not open logfiles when parse-and-exit option is active
+
+ This is a quick workaround for an issue where configured logfiles are
+ opened/created during parsing of a config file even when parse-and-exit
+ option is active. We should later refactor the logging code to avoid
+ opening log during parsing altogether.
+
+commit eee8af4db2d36a5017eac4447075cac3346e8b23
+Author: Maria Matejka <mq@ucw.cz>
+Date: Tue Jun 2 16:58:06 2020 +0200
+
+ OSPF: setting list node to zero before enlisting
+
+commit 4e8f8afc68cc7ba09ca42d989e47dbfcb17d2772
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Tue May 26 23:43:13 2020 +0200
+
+ Babel: Set onlink flag for IPv4 routes with unreachable next hop
+
+ If the next hop of a route is not a reachable address, the route should be
+ installed as onlink. This enables a configuration common in mesh networks
+ where the mesh interface is assigned a /32 and babel handles the routing by
+ installing onlink routes.
+
+ Thanks to Toke Hoiland-Jorgensen for the patch.
+
+commit c1632ad0f39f7221d649a9e469cacc38105528e2
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Tue May 26 18:21:43 2020 +0200
+
+ OSPF: Fix handling of unnumbered PtPs
+
+ This issue has a long history. In 2012, we changed data field for
+ unnumbered PtP links from iface id (specified by RFC) to IP address based
+ on reports of bugs in Quagga that required it, and we used out-of-band
+ information to distinquish unnumberred PtPs with the same local IP
+ address.
+
+ Then with OSPF graceful restart implementation, we found that we can no
+ longer use out-of-band information, and we need to use only LSAdb info
+ for routing table calculation, but i forgot to finish handling of this
+ case, so multiple unnumbered PtPs with the same local IP addresses were
+ broken.
+
+ Considering that even recent Mikrotik RouterOS has broken next hop
+ calculation that depends on IP address in PtP link data field, we
+ cannot just switch back to the iface id for unnumbered PtP links.
+
+ The patch makes two changes: First, it goes back to use out-of-band
+ (position) info for distinguishing local interfaces in SPF when graceful
+ restart is not enabled, while still uses LSAdb-only approach for SPF
+ calculation when graceful restart is enabled.
+
+ Second, it adds OSPF interface option 'ptp address', which controls
+ whether IP address or iface id is used in data field. It is enabled
+ by default except for unnumbered PtP links with enabled graceful
+ restart.
+
+ Thanks to Kenth Eriksson for the bugreport and Joakim Tjernlund for
+ suggestions.
+
+commit 1ca7665fa4a9858a6d4c591ccff5b61e5e6aed13
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Tue May 19 02:50:47 2020 +0200
+
+ Nest: Allow key id 0
+
+ There is nothing in RFCs specifying that id 0 is not allowed. Some
+ implementations does not support it, while some other use key id 0 by
+ default. We allow it but start with key id 1 by default.
+
+ Thanks to Kenth Eriksson for the bugreport.
+
+commit b729e731f99aa6ece085597091618ed559a9f656
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Mon May 18 22:16:37 2020 +0200
+
+ RIP: Triggered RIP (demand circuit) documentation
+
+commit ec430a7feefd3b32ee39c641a48c44528d0eab25
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Mon May 18 16:25:08 2020 +0200
+
+ Nest: Implement BGP path mask loop operator
+
+ Implement regex-like '+' operator in BGP path masks to match previous
+ path mask item multiple times. This is useful as ASNs may appear
+ multiple times in paths due to path prepending for traffic engineering
+ purposes.
+
+commit 5fc8407177fd34f2d57441a8ff9a068f4162fbfb
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Tue May 12 03:46:47 2020 +0200
+
+ RIP: Fix handling of passive mode for demand circuit interfaces
+
+commit b8bbbbaf569799ab8faff0ee185528b6a2129154
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Mon May 11 04:29:36 2020 +0200
+
+ Nest: Fix neighbor handling for colliding ranges
+
+ Resolve neighbors using longest prefix match. Although interface ranges
+ should not generally collide, it may happen for unnumbered links.
+
+ Thanks to Kenth Eriksson for the bugreport.
+
+commit f7c34aa227693194e53ca0435dba52c2a839bae8
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Tue May 5 02:20:30 2020 +0200
+
+ Tests: Activate BGP-int test
+
+commit e6785c469b418785568c33241157d17107afd55c
+Author: Matous Holinka <matous.holinka@nic.cz>
+Date: Wed Apr 29 16:15:17 2020 +0200
+
+ Tests: Change unsupported Ubuntu 19.04 for supported version 19.10
+
+commit 82bfee76f0adfd50d51833343c63ba9e2afcb60e
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Wed Apr 29 15:07:33 2020 +0200
+
+ Filter: Remove quitbird command
+
+ No need for this debug filter command and it can be abused from CLI.
+
+commit b12442c985f2bd8c9fd47ca63151724962fabdc2
+Author: Maria Matejka <mq@ucw.cz>
+Date: Fri May 1 15:41:42 2020 +0200
+
+ Fixed a harmless warning in production build
+
+commit 048eb2ddf1ee9587d9fa30cbb3f87d6f650a2133
+Merge: 17de3a02 59238768
+Author: Maria Matejka <mq@ucw.cz>
+Date: Fri May 1 15:34:17 2020 +0200
+
+ Merge remote-tracking branch 'origin/mq-static-analysis'
+
+commit 59238768b3b05fa134348d2232b42537d0403994
+Author: Maria Matejka <mq@ucw.cz>
+Date: Mon Aug 19 14:43:14 2019 +0200
+
+ Slab: Init node in slab head to NULLs.
+
+commit ea259d6201973eb0f764cbb2bb6549b6ac79b316
+Author: Maria Matejka <mq@ucw.cz>
+Date: Sat Aug 17 16:09:29 2019 +0200
+
+ Timer: Adding missing initializer.
+
+commit 0c3b8ffe25f43e59dfe8b1aeb219ff1cb4c6aa2b
+Author: Maria Matejka <mq@ucw.cz>
+Date: Sat Aug 17 15:03:09 2019 +0200
+
+ Lexer: strtoul shall never set endptr to NULL; it should be an error
+
+commit cdde3550dc188f493daf82ef9d9acf8b85d9d722
+Author: Maria Matejka <mq@ucw.cz>
+Date: Sat Aug 17 14:57:41 2019 +0200
+
+ Unix socket: Path length check directly before copying the path.
+
+ This is not needed as the string is always short enough, anyway
+ it may be needed in future and one strlen during BIRD start is
+ cheap enough.
+
+commit 9ac13d7af25d6b26866bf4f4a4fab371925fb1df
+Author: Maria Matejka <mq@ucw.cz>
+Date: Mon Aug 19 14:36:51 2019 +0200
+
+ Lists: Replaced replace_node() by update_node() which is the only use of that function.
+
+commit e26a5195dd6c62e6f4b80d13b6ecd5f40ee68546
+Author: Maria Matejka <mq@ucw.cz>
+Date: Sat Aug 17 14:03:47 2019 +0200
+
+ Lists: fix a stupid sanitizer bug
+
+commit 3bb10b4d31d68a8139e284c27f7eb6fca897721d
+Author: Maria Matejka <mq@ucw.cz>
+Date: Sat Aug 17 14:18:41 2019 +0200
+
+ Uninitialized list nodes fixes
+
+commit 258be56539a3d4b47fe779f9658ca3d88761878d
+Author: Maria Matejka <mq@ucw.cz>
+Date: Sat Aug 17 13:36:36 2019 +0200
+
+ Nest: Added const to ea_show just to declare that this shouldn't really change anything
+
+commit a7d9b8f116d00194e94c7505cbc8ed7f8784eeab
+Author: Maria Matejka <mq@ucw.cz>
+Date: Sat Aug 17 10:28:55 2019 +0200
+
+ OSPF: Zero-initialization of a temporary neighbor
+
+commit 0fa8bf91cd474e393ded85b329fde30ba35f6a26
+Author: Maria Matejka <mq@ucw.cz>
+Date: Sat Aug 17 10:20:46 2019 +0200
+
+ Nest: Several assumptions to tame the static analyzer
+
+commit bbe49ae569534d0cf7ff226d19e729dcc764e606
+Author: Maria Matejka <mq@ucw.cz>
+Date: Sat Aug 17 08:59:06 2019 +0200
+
+ Nest: Assumption in rt-show for not-so-intuitive invariant.
+
+commit a08853a26989d343c507a41257dedcdea3befd73
+Author: Maria Matejka <mq@ucw.cz>
+Date: Sat Aug 17 08:54:08 2019 +0200
+
+ Static scanner and expensive debugging setup fix
+
+commit 5f60d14edeb48824d28e6393e7eb1aa50d5f2cd1
+Author: Maria Matejka <mq@ucw.cz>
+Date: Fri Aug 16 21:22:56 2019 +0200
+
+ RPKI: fixed rare va_list leak
+
+commit b7482209065a03c3186d74e5e4129539ce7a3ce4
+Author: Maria Matejka <mq@ucw.cz>
+Date: Fri Aug 16 21:15:49 2019 +0200
+
+ Static check: Don't report dead code
+
+commit 9e64ac4b7c23aa3b8b9149794c05305315cf31e5
+Author: Maria Matejka <mq@ucw.cz>
+Date: Fri Aug 16 14:04:53 2019 +0200
+
+ OSPF: Adding a note about a static analyzer result.
+
+commit dccee408262262ab9a63403141b74a0d937284bc
+Author: Maria Matejka <mq@ucw.cz>
+Date: Fri Aug 16 12:47:13 2019 +0200
+
+ OSPF: variable-length array of size 0 replaced by alloca()'d pointer
+
+ NULL pointer is safer than a random pointer onto stack if this function
+ gets changed and eventually broken.
+
+commit baac7009063d94799821422ecc63ea2af41561ea
+Author: Maria Matejka <mq@ucw.cz>
+Date: Wed Aug 14 16:23:58 2019 +0200
+
+ List expensive check.
+
+commit a0d0a71a1828cce725c3132f8c243bf0c537786f
+Author: Maria Matejka <mq@ucw.cz>
+Date: Wed Aug 14 16:22:39 2019 +0200
+
+ Expensive check declaration
+
+ Intended to be run at every operation with complex data structures
+ to check their consistency and validity.
+
+commit a1b61a271af40a9d6ef0837424ab2c98d29f1575
+Author: Maria Matejka <mq@ucw.cz>
+Date: Wed Aug 14 12:29:04 2019 +0200
+
+ IPv6 address parser: fail on incomplete addresses
+
+commit d65a926a67749f8e8ffb6df9b3e2e123669b0656
+Author: Maria Matejka <mq@ucw.cz>
+Date: Wed Aug 14 11:49:20 2019 +0200
+
+ Filter: Don't alloc varargs array if its length would be zero
+
+commit 30ba7c1661a13d665ae0aaa4e40cb5ed24023450
+Author: Maria Matejka <mq@ucw.cz>
+Date: Wed Aug 14 11:31:03 2019 +0200
+
+ Filter: Removed forgotten dead code
+
+commit bf9486bf20ee16af71e338ee690fc36805d98fe5
+Author: Maria Matejka <mq@jmq.cz>
+Date: Mon Apr 27 22:33:10 2020 +0200
+
+ Non-null function argument declaration
+
+commit 17de3a023f7bde293892b41bfafe5740c8553fc8
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Wed Apr 29 02:50:29 2020 +0200
+
+ BGP: Fix handling of strange IPv6 link-local-only next hops
+
+ There are three common ways how to encode IPv6 link-local-only next hops:
+ (:: ll), (ll), and (ll ll). We use the first one but we should accept all
+ three. The patch fixes handling of the last one.
+
+ Thanks to Sebastian Hahn for the bugreport.
+
+commit 8029ae527edde4d47a51b55efdbdea546296c5ef
+Author: Maria Matejka <mq@ucw.cz>
+Date: Thu Aug 1 14:25:01 2019 +0200
+
+ More assertion categories
+
+commit d607205486d7ea11f2cbf3dcc3d5e7e6b53f1d0f
+Author: Maria Matejka <mq@ucw.cz>
+Date: Wed Aug 14 10:28:23 2019 +0200
+
+ Not calling memcpy with n=0.
+
+commit 124d860f648f4c1c080e77b5f070b97d094f5285
+Author: Maria Matejka <mq@ucw.cz>
+Date: Wed Aug 14 11:06:49 2019 +0200
+
+ Filter: fixed omitted overflow check in EC constructor
+
+commit 59a86cbc7c5d5640b16ca9d8a99be979b11a4c68
+Author: Maria Matejka <mq@ucw.cz>
+Date: Wed Aug 14 10:14:15 2019 +0200
+
+ Makefile rule for static analyzer
+
+commit b465604eb13fc57ebe240556ebf0d4469690c906
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Tue Apr 28 14:58:43 2020 +0200
+
+ Tests: Activate BGP-auth test
+
+commit 716e11a58437498c09ffdb321b0de4e28a7383d8
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Tue Apr 28 03:52:47 2020 +0200
+
+ Tests: Activate OSPF-VRF test
+
+commit 3c838ad9fdc553c658ee2fbb466ab8ab4cd14805
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Wed Apr 22 16:03:37 2020 +0200
+
+ Tests: Activate BGP test
+
+commit a6548d5b5be1d0186dfab43b76790803f8c8625e
+Author: Nasato Goto <goto@mfeed.ad.jp>
+Date: Wed Apr 15 03:46:53 2020 +0200
+
+ BGP: Fix handling of 16bit-only ASN translation
+
+ The bug generated invalid AGGREGATOR attribute during translation of
+ 32bit ASN to 16bit-only BGP peer. The patch fixes that.
+
+commit fd9f0c0640fd02a26b96b4f9d3cbbffbb6544a84
+Author: Maria Matejka <mq@jmq.cz>
+Date: Wed Apr 8 22:25:15 2020 +0200
+
+ Configuration strings are constant.
+
+ This is merely a const propagation. There was no problem in there.
+
+commit a109056145a6bc8a6b498ecb6e309ebc143c8b3c
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Sat Mar 28 17:17:51 2020 +0100
+
+ Doc: Update prefix set comment
+
+commit 2928c5bcc7c3caaeb6de34a84ca63de9a12e1f1a
+Author: Maria Matejka <mq@jmq.cz>
+Date: Sun Apr 5 01:12:06 2020 +0200
+
+ Fletcher16 test fixed to work at bigendian architectures.
+
+ To be honest, it was wrong in concept, anyway it accidentally worked.
+
+commit c9d11e6230c49cdfd1f17829be0e877aba05e90b
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Thu Mar 26 04:53:23 2020 +0100
+
+ Filter: Remove mixed address tests and fix formatting
+
+commit 27550028907fd135051a43dda0abe76e9118b7e9
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Thu Mar 26 03:57:48 2020 +0100
+
+ Filter: Optimize IPv4 prefix sets
+
+ Use separate IPv4 and IPv6 implementation of prefix sets. Just this
+ change makes IPv4 prefix sets 60% smaller and 50% faster.
+
+commit d516c68ad838351fa5e20e3e10bd3fb2b3157618
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Sat Mar 14 17:04:49 2020 +0100
+
+ RIP: Improvements to demand circuit mode
+
+ Restart iface after changing demand circuit mode during reconfiguration.
+ Fix next_regular interval reset during reconfiguration. Send flushing
+ response when iface goes down.
+
+commit dc042d87cb68e44b49e9f4f153db444afaa00fba
+Author: Maria Matejka <mq@jmq.cz>
+Date: Mon Jan 27 17:42:11 2020 +0100
+
+ Perf: changed route update pattern to be more like common protocols
+
+commit e2630a494ebc90bee97729ebe92a1bb9fd8bb611
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Thu Mar 5 23:51:28 2020 +0100
+
+ Netlink: Handle interfaces with missing broadcast addresses
+
+commit 1ad98965c5eacd5c5f468beac146dfd0d63c83f2
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Thu Mar 5 22:01:30 2020 +0100
+
+ Tests: Enforce cleanup before running a test
+
+commit ead531ffefdad0f6b5d654330d0e4aba94757569
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Thu Mar 5 17:39:52 2020 +0100
+
+ Tests: Activate OSPF tests
+
+commit e6746da6de45bcacc42010cea828129eae38ba67
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Tue Mar 3 19:04:05 2020 +0100
+
+ Flowspec: Fix tests
+
+ Missing dst no longer generates error.
+
+commit 78e4a123bb937bb45f7eaebb0ea475095443bfd0
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Tue Mar 3 17:45:16 2020 +0100
+
+ BGP: Handle flowspec rules without dst part
+
+ The RFC 5575 does not explicitly reject flowspec rules without dst part,
+ it just requires dst part in validation procedure for feasibility, which
+ we do not implement anyway. Thus flow without dst prefix is syntactically
+ valid, but unfeasible (if feasibilty testing is done).
+
+ Thanks to Alex D. for the bugreport.
+
+commit 757cab18d6427d9246618ce48c158f2b05183838
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Thu Feb 27 16:16:48 2020 +0100
+
+ BGP: Support for MD5SIG together with remote range
+
+ When dynamic BGP with remote range is configured, MD5SIG needs to use
+ newer socket option (TCP_MD5SIG_EXT) to specify remote addres range for
+ listening socket.
+
+ Thanks to Adam Kułagowski for the suggestion.
+
+commit 22c3cf955dbbb65aa29e322efa70dabb749f0232
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Fri Feb 21 02:35:50 2020 +0100
+
+ RIP: Demand circuit support (RFC 2091)
+
+commit 3343088a7164a54b1e6c6cf9648d8036a61e9827
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Fri Feb 14 22:37:07 2020 +0100
+
+ RIP: Fix crash when interface is removed
+
+ Recent changes in neighbor code caused RIP to access neighbor field which
+ is NULL during interface/neighbor removal and caused crash when debug
+ messages are enabled. Use correct field to get iface from neighbor.
+
+commit ab089f4fb5e1ac762a9c95ed4638e2477803678e
+Author: Maria Matejka <mq@ucw.cz>
+Date: Tue Feb 4 10:34:46 2020 +0100
+
+ Conf: Better error message when reading iproute2 config
+
+ Reported by: Martin Weinelt <martin@darmstadt.freifunk.net>
+
+commit 027a3e66f786be8863784aefb043097b41090896
+Author: Maria Matejka <mq@ucw.cz>
+Date: Tue Feb 4 10:15:35 2020 +0100
+
+ RPKI: Allow build without libSSH
+
+commit 4bbc10614f3431c37e6352f5a6ea5c693c31021e
+Author: Maria Matejka <mq@ucw.cz>
+Date: Tue Feb 4 10:11:16 2020 +0100
+
+ Added missing extern
+
+ Thanks to Robert Scheck <bird@robert-scheck.de> who reported it
+ and Toke Høiland-Jørgensen <toke@toke.dk> who suggested this patch.
+
+commit 7f9adafc109d576d5249c25ef284606dbac4adfa
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Tue Jan 28 18:07:25 2020 +0100
+
+ BFD: Option to specify which class of BFD sessions are accepted
+
+ Allows to configure IPv4/IPv6-only or direct/multihop-only BFD protocol
+ instances.
+
+commit 9f2670277cc0d56d3364d4784348056174175aba
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Thu Jan 9 02:59:59 2020 +0100
+
+ OSPF: Fix bad initialization of tx_hdrlen field
+
+ Function ifa_tx_hdrlen() uses fields autype and passwords, so it must be
+ called after these are set.
+
+ Thanks to Kenth Eriksson for the bugreport.
+
+commit 7d767c5a3d001a6a1a5c3e800553202fd492190c
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Tue Jan 7 18:35:03 2020 +0100
+
+ KRT: Improve syncer code to avoid using temporary data in rtable
+
+ The old code stored route verdicts and temporary routes directly in
+ rtable. The new code do not store received routes (it immediately
+ compares them with exported routes and resolves conflicts) and uses
+ internal bitmap to keep track of which routes were received and which
+ needs to be reinstalled.
+
+ By not putting 'invalid' temporary routes to rtable, we keep rtable
+ in consistent state, therefore scan no longer needs to be atomic
+ operation and could be splitted to multiple events.
+
+commit ef8c45749c82e246d477ea4d7f749668a9c7e9ee
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Tue Jan 7 01:24:30 2020 +0100
+
+ Filter: Fix typecheck for AND/OR.
+
+ Do not apply dynamic type check for second argument of AND/OR, as it is
+ not evaluated immediately like regular argument would be.
+
+ Thanks to Mikael for the bugreport.
+
+commit cc75b3e1dc4a7440479d6f4d73e7e1b9ba65332f
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Thu Dec 19 16:34:35 2019 +0100
+
+ KRT: Remove KRF_SYNC_ERROR flag
+
+ This info is now stored in an internal bmap. Unfortunately, net.flags
+ is still needed for temporary kernel data.
+
+commit 90a9c97e38e3769b400b434723516213eccb3ab0
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Tue Dec 17 16:30:29 2019 +0100
+
+ KRT: Fix removal of KRF_INSTALLED
+
+ Use route id from net->routes to check export_map. Route received from
+ sysdep KRT code does not have proper id.
+
+commit 3dabf7b8d09c3188ea41b7e2f763397946943778
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Tue Dec 17 00:01:53 2019 +0100
+
+ Test: Improve filter_test
+
+ Initial parsing of test.conf must be done directly in filter_test main,
+ while reconfiguration is handled as a regular test. Also fix several
+ minor issues in test code.
+
+commit 3232d1718636eb7617fedc7b27378cd1d8f8691d
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Mon Dec 16 18:05:56 2019 +0100
+
+ Doc: Fix documentation of BGP gateway option
+
+ Thanks to Nico Schottelius for the bugreport.
+
+commit c132acae362b6106c2eecbef2d8c163acde84035
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Mon Dec 16 02:40:28 2019 +0100
+
+ KRT: Remove KRF_INSTALLED flag
+
+ The same information is stored in export_map of kernel protocol.
+
+commit d3aa4f2aeddf7f546b3c0c9bd5fc7958ecb3814a
+Author: Maria Matejka <mq@ucw.cz>
+Date: Thu Dec 12 15:42:29 2019 +0100
+
+ Filter: fix filter comparison test
+
+commit dfb3eb771683ae4cc5ae43a990352578ab20f0fa
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Tue Dec 10 18:53:16 2019 +0100
+
+ Filter: Fix function comparison
+
+ Check the SYM_FLAG_SAME in new symbols. The old code checked that
+ in old symbols (f2).
+
+commit 4ab54f1aefd6a3ecc5e2340cbc15d492444daff5
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Tue Dec 10 18:18:02 2019 +0100
+
+ Nest: Fix bitmap cleanup
+
+ Channel currently does not have independent pool and uses protocol pool,
+ which is freed when protocol changes state to down, while channel is
+ still in flushing. Move some some cleanup code to channel_do_flush()
+ so it is done before freeing of protocol pool.
+
+commit ff2ca10cba9c5a3be690ec1a77a068e23395ef20
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Mon Dec 9 04:23:01 2019 +0100
+
+ Filter: Add support for src/dst accessors for Flowspec and SADR
+
+commit 21d09632a524c0d2a7f44a51f877370ad07b983c
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Tue Dec 3 18:05:41 2019 +0100
+
+ BGP: Add some statistics
+
+ Add some statistic counters to BGP consistent with BGP MIB (RFC 4273),
+ including persistent 'FSM established transitions'.
+
+commit 92249894b333f7785e62b2f629dca1bbe6597c2f
+Author: Matous Holinka <matous.holinka@nic.cz>
+Date: Tue Nov 26 19:33:01 2019 +0100
+
+ CI: Add more build tests
+
+ Add more Docker images with distributions (CentOS 8, Debian 10,
+ Fedora 27-31, OpenSUSE 15.0 & 15.1, and Ubuntu 18.04 & 19.04).
+ Fix some issues with older ones.
+
+commit 0adfa0ec076196275a3cf034ba3ce82ffbcd2fbd
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Mon Nov 11 00:24:07 2019 +0100
+
+ CI: Cleanup of job templates
+
+ Env templates were used for separate IPv4/IPv6 build, that is no longer
+ needed.
+
+commit 6a314d26cbcc0e75c872d6c222f93661049466b7
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Sun Nov 10 22:58:23 2019 +0100
+
+ CI: Update new netlab location
+
+commit 148bd9ee92c55ba23be2d60a278dfa7ad0005971
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Sun Nov 10 03:43:30 2019 +0100
+
+ CI: Minor update
+
+commit faa43a755eba5194c50fae20dddc0e3837fe5dc5
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Sun Nov 10 03:02:58 2019 +0100
+
+ Apply relevant changes from branch mh-test-gitlab
+
+commit 5176455f1a4506e9397e23895e1de525c3c190c9
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Fri Nov 1 00:13:59 2019 +0100
+
+ Gitlab test
+
+commit 5ea39eaa96625ec8274703b1eb2c8f59042a8a32
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Mon Sep 9 02:55:32 2019 +0200
+
+ Nest: Use bitmaps to keep track of exported routes
+
+ Use a hierarchical bitmap in a routing table to assign ids to routes, and
+ then use bitmaps (indexed by route id) in channels to keep track whether
+ routes were exported. This avoids unreliable and inefficient re-evaluation
+ of filters for old routes in order to determine whether they were exported.
+
+commit af02b83b888c693c292960072195f0e1caf1d2a1
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Mon Sep 9 02:43:39 2019 +0200
+
+ Lib: Basic and hierarchical bitmaps
+
+ Basic bitmap is obvious. Hierarchical bitmap is structure of several
+ bitmaps, where higher levels are conjunctions of intervals on level
+ below, allowing for efficient lookup of first unset bit.
+
+commit d033e6327d1e63f5d212981fca785b5086491905
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Tue Nov 26 16:43:09 2019 +0100
+
+ CLI: Fix continuation lines after final one
+
+ Continuation lines may use short form (with space instead of message
+ number), but this should not be done when previous line is final.
+
+ Thanks to Kenth Eriksson for the bugreport and analysis.
+
+commit 0f88200247cc61175c7a1d98a3e935aedce93f3b
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Mon Nov 18 17:44:34 2019 +0100
+
+ BGP: Fix processing of IPv6 Flowspec
+
+ During NLRI parsing of IPv6 Flowspec, dst prefix was not properly
+ extracted from NLRI, therefore a received flow was stored in a different
+ position in flowspec routing table, and was not reachable by command
+ 'show route <flow>'.
+
+ Add proper prefix part accessors to flowspec code and use them from BGP
+ NLRI parsing code.
+
+ Thanks to Alex D. for the bugreport.
+
+commit 53401bef63013dfee01b65d071ffbd88e457539f
+Author: Ondrej Zajicek <santiago@crfreenet.org>
+Date: Tue Nov 12 18:13:21 2019 +0100
+
+ Netlink: Handle IPv4 routes with IPv6 nexthops
+
+ Accept RTA_VIA attribute in all cases. The old code always used
+ RTA_GATEWAY for IPv4 / IPv6 and RTA_VIA for MPLS. The new code uses
+ RTA_VIA in cases where AF of network and AF of nexthop differs.
+
+commit 0b228fca04c8a9a81af6a4973877ceba9aede3f0
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Sun Nov 10 02:06:07 2019 +0100
+
+ BGP: Add option to enforce first AS in AS_PATH
+
+ This is optional check described in RFC 4271. Although this can be also
+ done by filters, it is widely implemented option in BGP implementations.
+
+ Thanks to Eugene Bogomazov for the original patch.
+
+commit becda5638a8ff8b056ec04b5e156e86b168cb9ef
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Tue Nov 5 16:29:47 2019 +0100
+
+ Doc: Minor fix
+
+commit d54a69ac7f0a29846cd9dbc697d1d369f51988bb
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Tue Nov 5 16:00:25 2019 +0100
+
+ Doc: Add documentation for BGP option 'allow as sets'
+
+commit 10c4cd9677555e88a4ac8c95784aa281655e3326
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Tue Nov 5 15:14:57 2019 +0100
+
+ Filter: Add type info for more instructions
+
+commit 87512e97516160ec980e9d0621522ada405438fe
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Tue Nov 5 15:13:57 2019 +0100
+
+ Filter: Improve typecheck error messages
+
+commit c00c20a79941b2bbed9e957134259763dcbb29f0
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Wed Oct 23 22:56:23 2019 +0200
+
+ Filter: Better constant promotion
+
+ We use constant promotion from IPv4 to Router-ID values, as they have
+ same literals. Instead of ad-hoc code in filter instructions, add
+ constant promotion code to parse-time typecheck code.
+
+commit 26194bd684b2926740a74ebdfe73e6afc3c145b6
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Wed Oct 23 22:53:23 2019 +0200
+
+ Filter: Improved parse-time typechecks
+
+commit 6fbcd8914aa2b0e0f50c6f20a15cd6eb1ba44497
+Author: Ondrej Zajicek <santiago@crfreenet.org>
+Date: Tue Oct 22 19:19:36 2019 +0200
+
+ Filter: Parse-time typechecks
+
+ Most expressions can be type-validated in parse time. It is not
+ strong enough to eliminate runtime checks, but at least one gets
+ errors immediately during reconfigure.
+
+commit a52476c9be41e8d33e4a22e3dc733240ce791b42
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Mon Nov 4 22:07:03 2019 +0100
+
+ BGP: Add option to reject AS_SETs
+
+ There is a pending draft to make them obsolete
+
+commit 0edf0c8cd919a8b3fbf5bc036f27ea0b4ed0b91a
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Sun Nov 3 20:26:54 2019 +0100
+
+ Support for address family constants
+
+ We already had them defined on BGP level, but they are more general.
+
+commit 08c4c9a30b7ed61be39ddc71aebd69a0fea6a55a
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Sun Nov 3 20:25:42 2019 +0100
+
+ Nest: Fix bug in export table
+
+ For regular channels do not compare src in export table, as we want to
+ keep here only the best (exported) route per network.
+
+commit be7c1aef429092bb90167a7f1b5c33b74a8030c2
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Sat Oct 26 01:28:38 2019 +0200
+
+ BGP: RFC 8654 got released
+
+commit 498d8145c0984acf6b39d7e312950315571e7030
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Fri Oct 25 13:28:51 2019 +0200
+
+ Nest: Fix primary flag in show route
+
+ The route is changed by rte_make_tmp_attrs(), so we need to compare
+ net->routes to the original one.
+
+ Thanks to Kenth Eriksson for the bugreport.
+
+commit ec331acf48535211fb5b50c87e74bf1c8370283a
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Thu Oct 24 17:47:45 2019 +0200
+
+ BGP: Fix handling of transitive extended communities
+
+ Transitive extended communities should be removed on external sessions,
+ the old code them in all cases.
+
+ Thanks to Jean-Daniel Pauget for the original patch.
+
+commit 5ce881be82d6698c32e36add9ed6e1643150c3f3
+Author: Ondrej Zajicek <santiago@crfreenet.org>
+Date: Tue Oct 22 16:20:38 2019 +0200
+
+ Accept uppercase letters in iproute2 names
+
+ Names read from texfiles in /etc/iproute2/* are normalized by replacing
+ non-alphanumeric chars with underscore. The patch fixes handling of
+ uppercase letters, which were handled as non-alphanumberic.
+
+ Thanks to Igor Gavrilov for the bugreport.
+
+commit f9eb9b4cab65b850c61738dd56632bae0e7329ca
+Author: Fabrice Fontaine <fontaine.fabrice@gmail.com>
+Date: Sat Oct 19 12:50:27 2019 +0200
+
+ Nest: Fix build without protocols
+
+ (CHECK keyword added by commiter)
+
+commit 4e23b499696da81acf0ed5ad181573b94ccdb9a3
+Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
+Date: Sat Oct 19 03:37:43 2019 +0200
+
+ RPKI: Fix handling of IPv6 cache addresses
+
+ The old code used just sizeof(struct sockaddr) bytes of IP address.
+
commit b000a94275d7bb81868b9d6ad7582e5a3939532a
Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
Date: Fri Oct 11 00:18:38 2019 +0200
@@ -406,7 +1908,7 @@ Date: Thu Jul 25 14:24:16 2019 +0200
The formatting was broken due to longer date in 'since' column.
commit cec40a74679821513e627f93b924067a404f6475
-Merge: 18f70a6 8263690
+Merge: 18f70a62 8263690e
Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
Date: Wed Jul 24 15:38:32 2019 +0200
@@ -486,7 +1988,7 @@ Date: Mon Jul 15 16:23:18 2019 +0200
IPv6 ECMP handling.
commit 8263690e754a83b8f3c58bd0080a1628d6cba556
-Merge: efd7c87 1aec711
+Merge: efd7c87b 1aec7112
Author: Maria Matejka <mq@ucw.cz>
Date: Mon Jul 15 16:07:16 2019 +0200
@@ -562,7 +2064,7 @@ Date: Wed Jul 10 16:46:31 2019 +0200
Filter: Minor cleanups
commit b2a4feeb4c877ff56d9b2ebd8119225c53ea40db
-Merge: eac9250 422a933
+Merge: eac9250f 422a9334
Author: Maria Matejka <mq@ucw.cz>
Date: Wed Jul 10 11:27:08 2019 +0200
@@ -593,7 +2095,7 @@ Date: Tue Jul 9 15:25:40 2019 +0200
Doc: Fix typo in BGP dynamic names feature description
commit 74a38adb6b4b4bf2a67e7a779a7c95b0ef1b9894
-Merge: 1322e20 2872ab9
+Merge: 1322e205 2872ab92
Author: Maria Matejka <mq@ucw.cz>
Date: Tue Jul 9 14:53:15 2019 +0200
@@ -654,14 +2156,14 @@ Date: Thu Jul 4 13:34:42 2019 +0200
When priority is reconfigured locally, we need to trigger DR election.
commit eac9250fd5b10809830361b94438339b3b31b270
-Merge: 8816b6c 026bfed
+Merge: 8816b6cd 026bfedb
Author: Maria Matejka <mq@ucw.cz>
Date: Wed Jul 3 11:09:52 2019 +0200
Merge branch 'master' into mq-filter-stack
commit 8816b6cdd98d24535eece6b5e35730aac57cd9f7
-Merge: c376555 84ac62d
+Merge: c376555c 84ac62d3
Author: Maria Matejka <mq@ucw.cz>
Date: Wed Jul 3 08:44:42 2019 +0200
@@ -846,7 +2348,7 @@ Date: Thu Jun 27 15:55:48 2019 +0200
Filter: A little cleanup of M4 interpreter generator
commit a8ab54d18d3af8e7dc9811ab8e3ba9a105131a25
-Merge: 63e7620 2e07773
+Merge: 63e76204 2e077731
Author: Maria Matejka <mq@jmq.cz>
Date: Tue Jun 25 22:40:05 2019 +0200
@@ -1093,7 +2595,7 @@ Date: Fri Mar 15 20:54:01 2019 +0100
capabilities disabled, handle that as implicit IPv4 unicast.
commit 8d65add626b34256879a3e83855af3c0fa8ce4e7
-Merge: 2f02c25 5d51194
+Merge: 2f02c25e 5d511948
Author: Maria Matejka <mq@ucw.cz>
Date: Mon Mar 18 12:54:40 2019 +0100
@@ -1545,7 +3047,7 @@ Date: Sat Feb 9 16:15:01 2019 +0100
As we do not have much usage for it yet.
commit cd16538fc91778e31f8241f62ee47056f099c051
-Merge: 6e8fb66 f9b97f1
+Merge: 6e8fb668 f9b97f1c
Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
Date: Sat Feb 9 15:53:16 2019 +0100
@@ -1974,7 +3476,7 @@ Date: Mon Dec 10 02:11:42 2018 +0100
Thanks to Cybertinus for a bugreport.
commit 9a5ef043c11ad9fba00557dedcc0d7ae0d2794e9
-Merge: 0e49206 265419a
+Merge: 0e492063 265419a3
Author: Jan Maria Matejka <mq@ucw.cz>
Date: Thu Dec 6 09:55:34 2018 +0100
@@ -2072,35 +3574,35 @@ Date: Wed Feb 14 13:42:53 2018 +0100
Author: Martin Mares <mj@ucw.cz>
Date: Mon Apr 5 20:17:59 1999 +0000
- Added some new protocol hooks (look at the comments for better explanation):
+ Added some new protocol hooks (look at the comments for better explanation):
- make_tmp_attrs Convert inline attributes to ea_list
- store_tmp_attrs Convert ea_list to inline attributes
- import_control Pre-import decisions
+ make_tmp_attrs Convert inline attributes to ea_list
+ store_tmp_attrs Convert ea_list to inline attributes
+ import_control Pre-import decisions
commit 5056c559c4eb253a4eee10cf35b694faec5265eb
Author: Martin Mares <mj@ucw.cz>
Date: Mon Apr 5 20:15:31 1999 +0000
- Changed syntax of attaching filters to protocols to hopefully the final
- version:
+ Changed syntax of attaching filters to protocols to hopefully the final
+ version:
- EXPORT <filter-spec> for outbound routes (i.e., those announced
- by BIRD to the rest of the world).
- IMPORT <filter-spec> for inbound routes (i.e., those imported
- by BIRD from the rest of the world).
+ EXPORT <filter-spec> for outbound routes (i.e., those announced
+ by BIRD to the rest of the world).
+ IMPORT <filter-spec> for inbound routes (i.e., those imported
+ by BIRD from the rest of the world).
- where <filter-spec> is one of:
+ where <filter-spec> is one of:
- ALL pass all routes
- NONE drop all routes
- FILTER <name> use named filter
- FILTER { <filter> } use explicitly defined filter
+ ALL pass all routes
+ NONE drop all routes
+ FILTER <name> use named filter
+ FILTER { <filter> } use explicitly defined filter
- For all protocols, the default is IMPORT ALL, EXPORT NONE. This includes
- the kernel protocol, so that you need to add EXPORT ALL to get the previous
- configuration of kernel syncer (as usually, see doc/bird.conf.example for
- a bird.conf example :)).
+ For all protocols, the default is IMPORT ALL, EXPORT NONE. This includes
+ the kernel protocol, so that you need to add EXPORT ALL to get the previous
+ configuration of kernel syncer (as usually, see doc/bird.conf.example for
+ a bird.conf example :)).
Let's say RIP to this almost 19-years-old inconsistency. For now, if you
import a route, it is always from protocol to table. If you export a
@@ -2529,7 +4031,7 @@ Date: Tue Jun 19 16:16:08 2018 +0200
way too slow. The cached pointer is faster.
commit 1ef23f05ee00394e6a2748f658b73c20d3ff7c45
-Merge: 13c0be1 caa9d03
+Merge: 13c0be19 caa9d03d
Author: Jan Maria Matejka <mq@ucw.cz>
Date: Tue Jun 19 14:32:16 2018 +0200
@@ -2772,7 +4274,7 @@ Date: Thu Mar 22 13:30:10 2018 +0100
Date added.
commit 966602602a0f24942bee3ab0492bbb9197e71aa1
-Merge: 4406281 4841804
+Merge: 44062812 4841804f
Author: Ondrej Filip <feela@network.cz>
Date: Thu Mar 22 13:25:58 2018 +0100
@@ -2799,7 +4301,7 @@ Date: Tue Mar 20 19:28:26 2018 +0100
The old one does not work with 2.0.x.
commit 89ac4dd3c433cae865d5339efe5e682d4506044d
-Merge: bcb4af8 8a871e8
+Merge: bcb4af81 8a871e89
Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
Date: Mon Mar 19 13:29:39 2018 +0100
@@ -2834,7 +4336,7 @@ Date: Sat Mar 17 17:14:02 2018 +0100
Thanks to Joshua McQuistan for the bugreport.
commit 8a871e890a7198f7cbaff5c75033160ae3ad68f3
-Merge: e95705f e8bc64e
+Merge: e95705f0 e8bc64e3
Author: Jan Maria Matejka <mq@ucw.cz>
Date: Wed Mar 14 12:57:16 2018 +0100
@@ -2853,27 +4355,27 @@ Date: Wed Feb 28 16:57:50 2018 +0100
This led to strange behavior like rewriting bgpmasks when they shan't
be rewritten:
- function mask_generator(int as)
- {
- return [= * as * =];
- }
-
- function another()
- bgpmask m1;
- bgpmask m2;
- {
- m1 = mask_generator(10);
- m2 = mask_generator(20);
- if (m1 == m2) {
- print("strange"); # this would happen
- }
- }
+ function mask_generator(int as)
+ {
+ return [= * as * =];
+ }
+
+ function another()
+ bgpmask m1;
+ bgpmask m2;
+ {
+ m1 = mask_generator(10);
+ m2 = mask_generator(20);
+ if (m1 == m2) {
+ print("strange"); # this would happen
+ }
+ }
Moreover, sending this to CLI would cause stack overflow and knock down the
whole BIRD, as soon as there is at least one route to execute the given
filter on.
- show route filter bgpmask mmm; bgppath ppp; { ppp = +empty+; mmm = [= (ppp ~ mmm) =]; print(mmm); accept; }
+ show route filter bgpmask mmm; bgppath ppp; { ppp = +empty+; mmm = [= (ppp ~ mmm) =]; print(mmm); accept; }
The magic match operator (~) inside the bgpmask literal would try to
resolve mmm, which points to the same bgpmask so it would resolve
@@ -2884,7 +4386,7 @@ Date: Wed Feb 28 16:57:50 2018 +0100
convertible to ASN in BIRD.
commit e95705f00c9e297cd6dde1e8fa60bee4a4d539f2
-Merge: d1ba927 74bfd2f
+Merge: d1ba927b 74bfd2f9
Author: Jan Maria Matejka <mq@ucw.cz>
Date: Tue Mar 13 17:02:49 2018 +0100
@@ -2904,7 +4406,7 @@ Date: Tue Mar 13 12:08:37 2018 +0100
Date: Tue Mar 2 19:49:28 1999 +0000
commit d1ba927b369c91ddb2143b686ca4c1be53e46e64
-Merge: f2f5a7d 7c601e6
+Merge: f2f5a7d9 7c601e6b
Author: Jan Maria Matejka <mq@ucw.cz>
Date: Tue Mar 13 16:51:04 2018 +0100
@@ -2949,7 +4451,7 @@ Date: Tue Mar 6 16:03:35 2018 +0100
Config: Dropped the ipv4:netmask4 syntax for IPv4 prefixes.
commit d0f47327f81a278d6adb3d0a6c235ea715798d01
-Merge: 1561ee7 2d6d4b8
+Merge: 1561ee79 2d6d4b80
Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
Date: Wed Mar 7 17:41:49 2018 +0100
@@ -2966,7 +4468,7 @@ Date: Wed Mar 7 17:35:24 2018 +0100
Thanks to Leo Vandewoestijne for the bugreport.
commit 44062812600bd29f8edf30ebc871ff218069c5a2
-Merge: 6f46465 1561ee7
+Merge: 6f46465a 1561ee79
Author: Ondrej Filip <feela@network.cz>
Date: Tue Feb 27 06:08:03 2018 +0100
@@ -3063,7 +4565,7 @@ Date: Wed Jan 24 13:55:12 2018 +0100
Nest: remove duplicate function
commit 75d98b6013c19598b1d3ba5e05e8f84525e8678a
-Merge: ace3072 d6cf996
+Merge: ace3072e d6cf9961
Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
Date: Tue Jan 23 18:29:32 2018 +0100
@@ -3224,7 +4726,7 @@ Date: Wed Jan 3 14:12:00 2018 +0100
ROA: Fix reconfiguration
commit 9bd8cb7c3ca23524cb7d69ee503e24658ad2ee42
-Merge: d493d0f cce6ba4
+Merge: d493d0f1 cce6ba4d
Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
Date: Tue Jan 2 16:59:59 2018 +0100
@@ -3316,7 +4818,7 @@ Date: Wed Dec 13 14:49:55 2017 +0100
Lib: Minor fix
commit cb21c5ffa92494b1a4bf110605509de3326b6c3d
-Merge: 71c51aa 1e11918
+Merge: 71c51aa4 1e11918c
Author: Jan Maria Matejka <mq@ucw.cz>
Date: Wed Dec 13 10:29:10 2017 +0100
@@ -3455,21 +4957,21 @@ Date: Fri Dec 8 02:26:17 2017 +0100
BGP: Autoconfigure BGP next hops from preferred addresses
commit 830ba75e6dd369c3e64d122f0537cc85211e56e6
-Merge: 46434a3 1e8721e
+Merge: 46434a3c 1e8721e2
Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
Date: Thu Dec 7 21:54:47 2017 +0100
Merge commit '1e8721e2aeccfbc3f533e8b8abc07582cee77e9a' into int-new
commit 46434a3cad99260b5a659e5df874eab4615bcb36
-Merge: 4ff15a7 7b2c5f3
+Merge: 4ff15a75 7b2c5f3d
Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
Date: Thu Dec 7 18:35:46 2017 +0100
Merge commit '7b2c5f3d2826e3175bf31b1c36056c9efc587a2b' into int-new
commit 4ff15a75c56531fa2d3858d8250dcef1af4e75b6
-Merge: cd80c9b 98bb80a
+Merge: cd80c9b0 98bb80a2
Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
Date: Thu Dec 7 17:41:09 2017 +0100
@@ -3938,7 +5440,7 @@ Date: Mon Sep 4 22:32:45 2017 +0200
Thanks to Eugene Sevastyanov for the original patch.
commit 96eace1ea70d7c2bc13672fbeba104d34d8ede4c
-Merge: 08b6a61 5c4dfe0
+Merge: 08b6a617 5c4dfe0c
Author: Michal 'vorner' Vaner <michal.vaner@nic.cz>
Date: Mon Sep 4 13:30:13 2017 +0200
@@ -4034,7 +5536,7 @@ Date: Wed Aug 9 13:35:55 2017 +0200
A TODO file last updated 5 years ago is useless.
commit 69f73992477a0e29f939f9e2722f705c4ad72a38
-Merge: 5a41eed b3fae3a
+Merge: 5a41eed2 b3fae3a8
Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
Date: Wed Aug 9 12:46:27 2017 +0200
@@ -4181,7 +5683,7 @@ Date: Thu Jun 8 12:18:16 2017 +0200
Thanks to Toke Høiland-Jørgensen <toke@toke.dk> for the patch.
commit 801fd81efea5bf51fe459d951e4be95119798b2b
-Merge: 7781003 33f7fbc
+Merge: 77810030 33f7fbc4
Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
Date: Wed May 31 14:12:03 2017 +0200
@@ -4194,7 +5696,7 @@ Date: Wed May 31 13:31:03 2017 +0200
CLI: Fix bug in symbol handling introduced in previous patches
commit 77810030d2556e3af659d354a2b3d661f58dd735
-Merge: a1dc526 4fec430
+Merge: a1dc5267 4fec4306
Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
Date: Tue May 30 14:44:37 2017 +0200
@@ -4207,7 +5709,7 @@ Date: Tue May 30 14:43:49 2017 +0200
Workaround for older bisons
commit a1dc5267602062562f9adca7acfbbc2fee3b315e
-Merge: 4b2aef8 b7761af
+Merge: 4b2aef88 b7761af3
Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
Date: Thu May 25 23:37:50 2017 +0200
@@ -4224,7 +5726,7 @@ Date: Thu May 25 23:30:39 2017 +0200
according to needs.
commit 4b2aef8857a9ac23015e410930d2162d945892f0
-Merge: 6aaaa63 c72b660
+Merge: 6aaaa635 c72b660b
Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
Date: Tue May 23 18:45:33 2017 +0200
@@ -4283,7 +5785,7 @@ Date: Thu May 18 14:51:36 2017 +0200
When shift count >= width of type the behavior is undefined.
commit 5a9169e152779ac6f99e2eccb79a2a2f6e2c76b2
-Merge: 7d5e61a 78e4dac
+Merge: 7d5e61a6 78e4dac9
Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
Date: Thu May 18 14:28:03 2017 +0200
@@ -4312,7 +5814,7 @@ Date: Thu May 18 12:05:09 2017 +0200
Space in action branch breaks build on some platforms.
commit 9b701e69cc812260788eced3370c7e65cd0e25fe
-Merge: d19617f d6e01ff
+Merge: d19617f0 d6e01ff9
Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
Date: Wed May 17 17:37:27 2017 +0200
@@ -4337,14 +5839,14 @@ Date: Wed May 17 16:05:07 2017 +0200
Fix build on systems with dirty headers
commit d19617f06b4526bccc2fc5e5e15c43c754b99a4d
-Merge: 144c10f 3187478
+Merge: 144c10fa 31874783
Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
Date: Wed May 17 14:50:00 2017 +0200
Merge remote-tracking branch 'origin/int-new' into int-new
commit 144c10fad1ed6a2520abd1c43501ce00ea2699db
-Merge: 1c5b4c5 a01e951
+Merge: 1c5b4c5d a01e951d
Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
Date: Wed May 17 14:38:04 2017 +0200
@@ -4378,7 +5880,7 @@ Date: Tue May 16 10:35:10 2017 +0200
Bird readline client saves its history.
commit 1c5b4c5d5b937fe6bbc3a599296e40a05f022b33
-Merge: fd1f355 b845ea0
+Merge: fd1f355b b845ea09
Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
Date: Tue May 16 14:18:25 2017 +0200
@@ -4429,7 +5931,7 @@ Date: Mon May 15 12:10:51 2017 +0200
Nest: split route show into separate file
commit fd1f355b7b24f354f7d57f127911b4fd98354b34
-Merge: 525a88d 7165257
+Merge: 525a88d8 71652572
Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
Date: Tue May 9 17:37:38 2017 +0200
@@ -4442,7 +5944,7 @@ Date: Tue May 9 16:46:41 2017 +0200
Minor autoconf cleanup and documentation update
commit 525a88d87930d01d4301e2723dda3dca208cd3d4
-Merge: 95639d9 5d6dc93
+Merge: 95639d95 5d6dc930
Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
Date: Tue May 9 14:07:14 2017 +0200
@@ -4490,7 +5992,7 @@ Date: Sat Apr 29 00:36:35 2017 +0200
Minor fixes
commit e919601aaf29615edb2a231e58a358c2c5c9d286
-Merge: 5ca4bd5 33b6c29
+Merge: 5ca4bd5d 33b6c292
Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
Date: Fri Apr 28 11:19:12 2017 +0200
@@ -4515,7 +6017,7 @@ Date: Wed Apr 26 14:11:28 2017 +0200
Test: Fix broken test for filters
commit 69fddac0525b1b0c940d778a161ed3a0a742ed6f
-Merge: 93a3661 b294999
+Merge: 93a3661c b2949999
Author: Jan Moskyto Matejka <mq@ucw.cz>
Date: Wed Apr 26 12:30:22 2017 +0200
@@ -4646,7 +6148,7 @@ Date: Tue Mar 28 18:14:32 2017 +0200
Netlink: Fix device route delete
commit 5dbeb87ec96157ca95c84d881e014614dd3164a3
-Merge: 2282030 d1b8fe9
+Merge: 2282030b d1b8fe93
Author: Jan Moskyto Matejka <mq@ucw.cz>
Date: Tue Mar 28 17:35:57 2017 +0200
@@ -4696,7 +6198,7 @@ Date: Wed Mar 22 15:00:07 2017 +0100
Based on patches from Jan Matejka.
commit ead7b8f498ddefc0b7373cbba78f9a7ba1dddaa9
-Merge: da3cf9e 61e501d
+Merge: da3cf9ea 61e501da
Author: Jan Moskyto Matejka <mq@ucw.cz>
Date: Wed Mar 22 14:54:00 2017 +0100
@@ -4833,7 +6335,7 @@ Date: Wed Feb 22 12:02:28 2017 +0100
Babel post-merge fixes
commit c609d039860f97f400d2cf0e9ca2b4e87b3fd1cc
-Merge: 62e6490 2be9218
+Merge: 62e64905 2be9218a
Author: Jan Moskyto Matejka <mq@ucw.cz>
Date: Wed Feb 22 11:58:04 2017 +0100
@@ -4881,7 +6383,7 @@ Date: Fri Feb 17 22:54:06 2017 +0100
Thanks to Lennert Buytenhek for tracking and reporting the bug.
commit c259669fa33ca13b5c6ae60eb8ffa0874ddc01b2
-Merge: 82f42ea da65a3d
+Merge: 82f42ea0 da65a3d8
Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
Date: Wed Feb 8 14:34:48 2017 +0100
@@ -5117,7 +6619,7 @@ Date: Wed Dec 7 15:35:35 2016 +0100
RPKI: fixed some of the extended warnings
commit ad88b94bca78e010357a6c7806e1d5e01701d4a7
-Merge: d15b0b0 af62c0f
+Merge: d15b0b0a af62c0f9
Author: Jan Moskyto Matejka <mq@ucw.cz>
Date: Wed Dec 7 15:30:46 2016 +0100
@@ -5400,7 +6902,7 @@ Date: Wed Nov 9 16:36:34 2016 +0100
current int-new branch.
commit 8860e991f6650e47cfe6c1af595fe4fe92a4edfd
-Merge: cc5b93f c8cafc8
+Merge: cc5b93f7 c8cafc8e
Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
Date: Tue Nov 8 19:27:58 2016 +0100
@@ -5413,7 +6915,7 @@ Date: Tue Nov 8 17:46:29 2016 +0100
Minor code cleanups
commit cc5b93f72db80abd1262a0a5e1d8400ceef54385
-Merge: 5de0e84 f51b1f5
+Merge: 5de0e848 f51b1f55
Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
Date: Tue Nov 8 17:03:31 2016 +0100
@@ -5843,7 +7345,7 @@ Date: Tue Aug 30 12:43:46 2016 +0200
check.
commit 768d013267bd2a52bab70ba6d413f49365fb31e3
-Merge: 678c97f d107ef7
+Merge: 678c97f2 d107ef78
Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
Date: Tue Aug 23 17:35:26 2016 +0200
@@ -6146,7 +7648,7 @@ Date: Tue May 17 15:21:49 2016 +0200
SKF_V6ONLY are to be removed.
commit 5af7b59660be615fbbd7c20b92b71321c003c43a
-Merge: d39d41f b66a9e2
+Merge: d39d41fb b66a9e2f
Author: Jan Moskyto Matejka <mq@ucw.cz>
Date: Fri May 13 13:48:04 2016 +0200
@@ -6159,7 +7661,7 @@ Date: Fri May 13 13:46:46 2016 +0200
Hash: Fix of previous commit
commit b66a9e2f3376b4cb07ef4cc318f70a9c794f407a
-Merge: 659f80f 3f2c760
+Merge: 659f80f2 3f2c7600
Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
Date: Thu May 12 21:47:50 2016 +0200
@@ -6178,14 +7680,14 @@ Date: Thu May 12 21:29:04 2016 +0200
We don't need bvsnprintf() in BIRD client
commit 776d6b2c05fe8b14e5ec357eca24fe59c549bfa4
-Merge: af678af 54ac0be
+Merge: af678af0 54ac0bec
Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
Date: Thu May 12 18:11:12 2016 +0200
Merge remote-tracking branch 'origin/int-new' into int-new
commit af678af0d5c9ef3d8afdc0789b33dd0c40b6d6e5
-Merge: 286e201 8e433d6
+Merge: 286e2011 8e433d6a
Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
Date: Thu May 12 17:49:12 2016 +0200
@@ -6228,14 +7730,14 @@ Date: Tue May 10 16:45:35 2016 +0300
Signed-off-by: Stijn Tintel <stijn@linux-ipv6.be>
commit 0c6dfe52369a59d7f3da8ee6bc7c505e3da5c064
-Merge: 7a7ac65 92912f0
+Merge: 7a7ac656 92912f06
Author: Jan Moskyto Matejka <mq@ucw.cz>
Date: Tue May 10 14:30:49 2016 +0200
Merge branch 'int-new' into int-new-merged
commit 92912f063a94bd7c743a25628ca2073380e09ef4
-Merge: a8caff3 2003a18
+Merge: a8caff32 2003a184
Author: Jan Moskyto Matejka <mq@ucw.cz>
Date: Tue May 10 14:21:15 2016 +0200
@@ -6354,7 +7856,7 @@ Date: Fri Apr 8 13:08:03 2016 +0200
side of the route-creation routine.
commit 7a7ac656829223713f9e6bcef63d2b5a5efce7d2
-Merge: 4bdf188 06edbb6
+Merge: 4bdf1881 06edbb67
Author: Jan Moskyto Matejka <mq@ucw.cz>
Date: Fri Apr 8 12:09:31 2016 +0200
@@ -6376,7 +7878,7 @@ Date: Mon Apr 4 16:17:11 2016 +0200
Channelize: rt_notify arg conversion table -> channel
commit 0c8c8151fc1fb0dbfcd682153f50192ea1369884
-Merge: a815d62 1a7daab
+Merge: a815d62d 1a7daab1
Author: Jan Moskyto Matejka <mq@ucw.cz>
Date: Thu Apr 7 09:58:31 2016 +0200
@@ -6494,7 +7996,7 @@ Date: Wed Mar 9 17:37:44 2016 +0100
Thanks to Pavel Tvrdik for noticing it.
commit 62a4ad365760afae485ae61c5aab734012545be4
-Merge: 9036bbf 9c92f69
+Merge: 9036bbf2 9c92f692
Author: Jan Moskyto Matejka <mq@ucw.cz>
Date: Tue Mar 22 13:23:55 2016 +0100
@@ -6555,7 +8057,7 @@ Date: Tue Feb 2 18:14:53 2016 +0100
Fix typo
commit ce95af7a5f5159033e569a7ccedce0e20bb5d913
-Merge: b25509e e3f506f
+Merge: b25509e5 e3f506f9
Author: Jan Moskyto Matejka <mq@ucw.cz>
Date: Thu Feb 25 18:25:53 2016 +0100
@@ -6986,7 +8488,7 @@ Date: Wed Nov 25 15:52:58 2015 +0100
BGP: Update capability number from IANA for extended messages
commit 04ae8ddaa15b72c265dc7cf038b733d235198754
-Merge: d44e686 33b4f40
+Merge: d44e686e 33b4f40a
Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
Date: Wed Nov 25 14:24:35 2015 +0100
@@ -6999,7 +8501,7 @@ Date: Fri Nov 13 16:08:28 2015 +0100
MD5: Mormalize naming style
commit 90f78507f4a13673ccf0ba7c786b43d9e882fca7
-Merge: 8eb8e54 ad27615
+Merge: 8eb8e546 ad276157
Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
Date: Tue Nov 24 15:21:11 2015 +0100
@@ -7032,7 +8534,7 @@ Date: Tue Nov 24 13:47:28 2015 +0100
Minor changes to SHA hash functions
commit 12d752ef24ab507d249a60098ec98dcf28b70036
-Merge: 1e4891e f312a83
+Merge: 1e4891e4 f312a837
Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
Date: Mon Nov 23 11:32:18 2015 +0100
@@ -7160,7 +8662,7 @@ Date: Tue Nov 3 11:08:57 2015 +0100
Thanks to Alexander V. Chernikov for the patch.
commit 8eb8e546dc8cc647fcfa4a3a17dfa8ab36b00958
-Merge: 8465dcc acb04cf
+Merge: 8465dccb acb04cfd
Author: Ondrej Zajicek (work) <santiago@crfreenet.org>
Date: Sat Oct 17 14:44:34 2015 +0200
@@ -7676,7 +9178,7 @@ Date: Sat Feb 21 11:46:14 2015 +0100
Configurable fast shutdown of a BGP session when an interface loses link.
commit 7730553b7eeb33d21e5597f110334ca584ad532d
-Merge: 0da562a ec2194f
+Merge: 0da562a7 ec2194fa
Author: Ondrej Zajicek <santiago@crfreenet.org>
Date: Sat Feb 21 11:39:45 2015 +0100
@@ -7762,7 +9264,7 @@ Date: Thu Oct 16 18:05:54 2014 +0200
__attribute__((packed)) added. Thank to Maksim Tamarsky
commit 78342404ff573e85e396f0611014b90cea9b4c0a
-Merge: 178a197 cfdea7b
+Merge: 178a197a cfdea7b8
Author: Ondrej Zajicek <santiago@crfreenet.org>
Date: Tue Oct 14 17:23:34 2014 +0200
@@ -7932,7 +9434,7 @@ Date: Mon May 5 11:05:12 2014 +0200
Thanks to Sergey Popovich for the original patch.
commit 5a3905fe905ab1cc1a58fe9e6a4284f7d5057d13
-Merge: 66370ea 7d9ab86
+Merge: 66370eac 7d9ab86b
Author: Ondrej Zajicek <santiago@crfreenet.org>
Date: Sun May 4 11:59:50 2014 +0200
@@ -7977,7 +9479,7 @@ Date: Wed Apr 23 13:54:28 2014 +0200
Thanks to Peter Christensen for the original patch.
commit 4dd24f05f384ac14546d4bebbfcb0ecf9a976ec6
-Merge: 1cb0f83 6c6ebd6
+Merge: 1cb0f83d 6c6ebd64
Author: Ondrej Zajicek <santiago@crfreenet.org>
Date: Wed Apr 23 13:52:15 2014 +0200
@@ -8098,7 +9600,7 @@ Date: Mon Mar 24 12:56:56 2014 +0100
Reformat bird.sgml to have consistent line length.
commit c980f8002e0f0578d5e715d48d65d9fb9a0c5a70
-Merge: 2e84b4e 227af30
+Merge: 2e84b4e8 227af309
Author: Ondrej Zajicek <santiago@crfreenet.org>
Date: Mon Mar 24 12:41:43 2014 +0100
@@ -8170,7 +9672,7 @@ Date: Fri Feb 7 11:46:01 2014 +0100
Fixes autoconf check for ncurses.
commit 5c200e0a4d26d183e04fda43de16340521002c40
-Merge: 4a5eb28 080ed4d
+Merge: 4a5eb284 080ed4d8
Author: Ondrej Zajicek <santiago@crfreenet.org>
Date: Thu Feb 6 20:15:05 2014 +0100
@@ -8234,7 +9736,7 @@ Date: Thu Feb 6 17:46:01 2014 +0100
- Use ifa->ifname instead of ifa->iface->name
commit f48fa14214301382b2e6b134788a7506b61b664f
-Merge: 6601a14 300e400
+Merge: 6601a148 300e4008
Author: Ondrej Zajicek <santiago@crfreenet.org>
Date: Thu Feb 6 16:47:43 2014 +0100
@@ -8259,7 +9761,7 @@ Date: Tue Jan 21 23:43:22 2014 +0100
Small doc update.
commit 6601a14831cdd32fc671ebc9dc299d2be427e489
-Merge: 2d0b7e2 283c7df
+Merge: 2d0b7e24 283c7dfa
Author: Ondrej Zajicek <santiago@crfreenet.org>
Date: Tue Dec 10 22:30:46 2013 +0100
@@ -8292,7 +9794,7 @@ Date: Tue Nov 26 22:37:24 2013 +0100
Fixes some bugs and uses generic hash implementation.
commit 283c7dfada53a6dee6a8a17ecab492ffafd44b66
-Merge: 736e143 0bb4e37
+Merge: 736e143f 0bb4e37d
Author: Ondrej Zajicek <santiago@crfreenet.org>
Date: Mon Nov 25 18:42:47 2013 +0100
@@ -8403,7 +9905,7 @@ Date: Sat Nov 23 13:26:52 2013 +0100
Added a few sentences about symbol names.
commit 736e143fa50607fcd88132291e96089b899af979
-Merge: 094d2bd 2b3d52a
+Merge: 094d2bdb 2b3d52aa
Author: Ondrej Zajicek <santiago@crfreenet.org>
Date: Sat Nov 23 11:50:34 2013 +0100
@@ -8411,11 +9913,11 @@ Date: Sat Nov 23 11:50:34 2013 +0100
Conflicts:
- filter/filter.c
- nest/proto.c
- nest/rt-table.c
- proto/bgp/bgp.h
- proto/bgp/config.Y
+ filter/filter.c
+ nest/proto.c
+ nest/rt-table.c
+ proto/bgp/bgp.h
+ proto/bgp/config.Y
commit 2b3d52aa421ae1c31e30107beefd82fddbb42854
Author: Ondrej Zajicek <santiago@crfreenet.org>
@@ -8454,7 +9956,7 @@ Date: Fri Nov 22 18:45:57 2013 +0100
Adds check for buffer size in OSPF LSA flood.
commit 0aeac9cb7f9887374ce0258c8653f9518529bf08
-Merge: 8931425 7c9930f
+Merge: 8931425d 7c9930f9
Author: Ondrej Zajicek <santiago@crfreenet.org>
Date: Fri Nov 22 02:43:41 2013 +0100
@@ -8687,7 +10189,7 @@ Date: Tue Sep 10 12:58:24 2013 +0200
Thanks to Sergey Popovich for a bugreport.
commit d27e127aa996d500fed21be2bbbe888cafecb830
-Merge: bff9ce5 b0a8c7f
+Merge: bff9ce51 b0a8c7fc
Author: Ondrej Zajicek <santiago@crfreenet.org>
Date: Tue Sep 10 12:54:57 2013 +0200
@@ -8969,7 +10471,7 @@ Date: Mon Apr 29 22:08:05 2013 +0200
Thanks to Peter Christensen for the bugfix.
commit 32622d0ea366406f3afa14bb9edb4855d6979786
-Merge: efd6d12 a5e9f3d
+Merge: efd6d12b a5e9f3d2
Author: Ondrej Zajicek <santiago@crfreenet.org>
Date: Tue Apr 23 02:54:13 2013 +0200
@@ -9396,7 +10898,7 @@ Date: Wed Aug 8 14:10:31 2012 +0200
DragonFly support add - thanks to john@marino.st
commit 60c412b9368fd7c3b0a8df2200f02140adcb0cf3
-Merge: 3fe1d9e 94e2f1c
+Merge: 3fe1d9e4 94e2f1c1
Author: Ondrej Filip <feela@network.cz>
Date: Tue Aug 7 11:15:23 2012 +0200
@@ -9461,7 +10963,7 @@ Date: Wed Jul 18 19:29:33 2012 +0200
Thanks Kelly Cochran for suggestion and draft patch.
commit abced4a91495e27fe86b142bc1967cec53bab3dc
-Merge: fc06fb6 7617026
+Merge: fc06fb62 76170264
Author: Ondrej Zajicek <santiago@crfreenet.org>
Date: Mon Jul 16 14:44:45 2012 +0200
@@ -9469,12 +10971,12 @@ Date: Mon Jul 16 14:44:45 2012 +0200
Conflicts:
- nest/config.Y
- nest/rt-table.c
- proto/bgp/bgp.c
+ nest/config.Y
+ nest/rt-table.c
+ proto/bgp/bgp.c
commit 761702644397886bd3c1be10fd55c01485b7c454
-Merge: 26822d8 553e405
+Merge: 26822d8f 553e4054
Author: Ondrej Zajicek <santiago@crfreenet.org>
Date: Mon Jul 16 10:41:29 2012 +0200
@@ -9493,7 +10995,7 @@ Date: Sat Jul 7 10:40:00 2012 +0200
Implements RDNSS and DNSSL support for RAdv.
commit 3fe1d9e4a40663b93b59f5b6f9d61af9dc6a8ae6
-Merge: 72b2db8 95127cb
+Merge: 72b2db8d 95127cbb
Author: Ondrej Filip <feela@network.cz>
Date: Tue May 15 23:40:37 2012 +0200
@@ -9524,7 +11026,7 @@ Date: Fri May 11 12:01:27 2012 +0200
Fixes a bug in RA_ACCEPTED handling.
commit 72b2db8db7534c52e928618410ec1f18787752c8
-Merge: 2795700 95616c8
+Merge: 2795700c 95616c82
Author: Ondrej Filip <feela@network.cz>
Date: Fri May 11 00:01:29 2012 +0200
@@ -9558,7 +11060,7 @@ Date: Thu May 3 12:25:15 2012 +0200
Implements build options to specify socket dir and suffix.
commit 2795700c3158fa52b6cf957e9d0b9ad4a27c67a5
-Merge: 1f85226 bf42207
+Merge: 1f85226e bf422073
Author: Ondrej Filip <feela@network.cz>
Date: Wed May 2 11:10:40 2012 +0200
@@ -9635,7 +11137,7 @@ Date: Fri Apr 27 00:04:51 2012 +0200
Some minor fixes.
commit 1f85226ecb76d3803b8fe37eb0891c45a6557dcd
-Merge: 92f8f7e d9b77cc
+Merge: 92f8f7e3 d9b77cc2
Author: Ondrej Filip <feela@network.cz>
Date: Thu Apr 26 17:03:53 2012 +0200
@@ -9650,7 +11152,7 @@ Date: Tue Apr 24 23:39:57 2012 +0200
And also fixes some minor bugs in limits.
commit 3589546af4baa4d349409a318f8c9658dd11b3cc
-Merge: 7d0a31d cca9706
+Merge: 7d0a31de cca97066
Author: Ondrej Zajicek <santiago@crfreenet.org>
Date: Tue Apr 24 23:37:01 2012 +0200
@@ -9711,14 +11213,14 @@ Date: Sun Apr 15 15:28:29 2012 +0200
Thanks to Alexander V. Chernikov for the original patch.
commit 3e17e380598b9a512bb369f51a4cf55da269f608
-Merge: 00a09f3 ae8b300
+Merge: 00a09f3c ae8b3001
Author: Ondrej Zajicek <santiago@crfreenet.org>
Date: Sun Apr 15 15:17:03 2012 +0200
Merge branch 'master' into rt-accepted
commit ae8b300164a975597f9b6caea0b205af2e4db30b
-Merge: d360f12 ed7c4b0
+Merge: d360f129 ed7c4b0c
Author: Ondrej Zajicek <santiago@crfreenet.org>
Date: Sun Apr 15 15:15:05 2012 +0200
@@ -9743,7 +11245,7 @@ Date: Mon Apr 9 14:19:28 2012 +0200
Small bugfix in error message related to reconfiguration.
commit bf2abe2f515d7b7aaed5fb4f37af82169adcd2f2
-Merge: fb829de c0adf7e
+Merge: fb829de6 c0adf7e9
Author: Ondrej Zajicek <santiago@crfreenet.org>
Date: Fri Mar 30 11:04:12 2012 +0200
@@ -9751,8 +11253,8 @@ Date: Fri Mar 30 11:04:12 2012 +0200
Conflicts:
- nest/proto.c
- nest/rt-table.c
+ nest/proto.c
+ nest/rt-table.c
commit fb829de69052755a31d76d73e17525d050e5ff4d
Author: Ondrej Zajicek <santiago@crfreenet.org>
@@ -9765,7 +11267,7 @@ Date: Wed Mar 28 18:40:04 2012 +0200
maximum number of routes flushed in one step.
commit cb3cf95859d81c711337738f004675f43c8bbb0e
-Merge: c9df01d 16fc65a
+Merge: c9df01d3 16fc65ac
Author: Ondrej Zajicek <santiago@crfreenet.org>
Date: Sun Mar 25 20:59:13 2012 +0200
@@ -10445,7 +11947,7 @@ Date: Tue May 10 02:42:17 2011 +0200
linux capabilities CAP_NET_* are kept.
commit 46bb7e0d176a4dc0a47bb406988f92fb29cceaf4
-Merge: b8cc390 b7c4898
+Merge: b8cc390e b7c48981
Author: Ondrej Zajicek <santiago@crfreenet.org>
Date: Fri May 6 22:09:44 2011 +0200
@@ -10482,7 +11984,7 @@ Date: Sun May 1 17:16:05 2011 +0200
There may be more IP address records with the same IP.
commit 5964569c23829ec93fcf671a2582be01c8aebecf
-Merge: acc93ef d600909
+Merge: acc93efd d600909d
Author: Ondrej Zajicek <santiago@crfreenet.org>
Date: Fri Apr 29 19:03:19 2011 +0200
@@ -10531,7 +12033,7 @@ Date: Tue Apr 5 11:41:18 2011 +0200
Minor fixes.
commit bf27abd6d4a20448f5b4c80e9aa9258dc8670f62
-Merge: 4ef0950 a5b84ab
+Merge: 4ef09506 a5b84ab5
Author: Ondrej Zajicek <santiago@crfreenet.org>
Date: Fri Apr 1 13:56:42 2011 +0200
@@ -11221,7 +12723,7 @@ Date: Tue Apr 27 18:29:01 2010 +0200
A fix in OSPFv3 next_hop calculation.
commit 96599c957baa9c82bde91d610ce4f519aead05e9
-Merge: ba13017 9d1ee13
+Merge: ba130172 9d1ee138
Author: Ondrej Filip <feela@majklik.network.cz>
Date: Tue Apr 27 11:28:44 2010 +0200
@@ -11265,7 +12767,7 @@ Date: Sat Apr 24 15:18:21 2010 +0200
OSPFv2 and OSPFv3 (previously it displayed stubnets in OSPFv2).
commit 1d44ddf20f3ecef864d4bd20355251839fcd10ee
-Merge: 3b89a23 6bc414d
+Merge: 3b89a232 6bc414d6
Author: Ondrej Zajicek <santiago@crfreenet.org>
Date: Wed Apr 21 21:52:10 2010 +0200
@@ -11432,7 +12934,7 @@ Date: Mon Mar 29 19:29:03 2010 +0200
- Documentation updates.
commit eb0f129fcedcecbee85403095abad8f59b82683c
-Merge: b1c030b 48cff37
+Merge: b1c030b0 48cff379
Author: Ondrej Zajicek <santiago@crfreenet.org>
Date: Fri Mar 26 18:53:31 2010 +0100
@@ -11508,7 +13010,7 @@ Date: Wed Mar 17 12:19:22 2010 +0100
- Fixes socket name path check and other error handling in CLI init.
commit 4e3bfd9006ba3033a814a392f9bf4bbca060c8a9
-Merge: e8da1bd cda2dfb
+Merge: e8da1bd0 cda2dfb7
Author: Ondrej Zajicek <santiago@crfreenet.org>
Date: Mon Mar 15 00:39:45 2010 +0100
@@ -11527,7 +13029,7 @@ Date: Sun Mar 14 16:36:59 2010 +0100
Temporary OSPF commit - sockets.
commit 54305181f6ee3af57dd3d15d53ea2e851b36ed23
-Merge: e7b76b9 afa9f66
+Merge: e7b76b97 afa9f66c
Author: Ondrej Zajicek <santiago@crfreenet.org>
Date: Thu Mar 11 18:55:59 2010 +0100
@@ -11596,7 +13098,7 @@ Date: Sun Feb 21 14:34:53 2010 +0100
Fix configure to enable warnings and fix most of them.
commit 9e43ccf07b96597ef098955a07383d826938cd2d
-Merge: e285bd2 89534cd
+Merge: e285bd23 89534cda
Author: Ondrej Zajicek <santiago@crfreenet.org>
Date: Sun Feb 21 10:15:49 2010 +0100
@@ -11718,7 +13220,7 @@ Date: Wed Feb 10 16:18:17 2010 +0100
NEWS and version update.
commit fae9be7782a161bdf93c83884d62941a34cbe518
-Merge: 7d19666 0efd646
+Merge: 7d196668 0efd6462
Author: Ondrej Zajicek <santiago@crfreenet.org>
Date: Wed Feb 10 14:59:26 2010 +0100
@@ -11796,7 +13298,7 @@ Date: Tue Feb 2 00:03:46 2010 +0100
Because we don't want to have a limit on a function/filter length.
commit 1a7a4e59a22f903a0be791f229e86ab881593851
-Merge: 4167702 1960d20
+Merge: 41677025 1960d203
Author: Ondrej Zajicek <santiago@crfreenet.org>
Date: Thu Jan 28 16:00:16 2010 +0100
@@ -11838,7 +13340,7 @@ Date: Wed Jan 13 14:53:33 2010 +0100
Comment update.
commit 974363c172e026b00be5f78ec585dda1e402b6f6
-Merge: 99f5fc1 844e0f6
+Merge: 99f5fc14 844e0f65
Author: Ondrej Zajicek <santiago@crfreenet.org>
Date: Fri Jan 8 22:20:09 2010 +0100
@@ -11851,7 +13353,7 @@ Date: Fri Jan 8 22:19:41 2010 +0100
A partial vlink fix.
commit 844e0f65dbab98f71f2a5631277a720613d4d7a5
-Merge: 3242ab4 fc33143
+Merge: 3242ab43 fc33143f
Author: Ondrej Filip <feela@majklik.network.cz>
Date: Fri Jan 8 21:19:03 2010 +0100
@@ -11954,7 +13456,7 @@ Date: Tue Dec 22 10:49:39 2009 +0100
Show command cleanups.
commit 0ad19261bf551ef49a1565e21e384ec749ec16d4
-Merge: c4ae538 67b24e7
+Merge: c4ae5385 67b24e7c
Author: Ondrej Zajicek <santiago@crfreenet.org>
Date: Tue Dec 22 01:34:01 2009 +0100
@@ -11981,14 +13483,14 @@ Date: Mon Dec 21 11:50:42 2009 +0100
Change default LOCAL_PREF attribute to 100 (suggested value by RFC 4277).
commit ba9a122142a3d42137c129fabaef097702d44801
-Merge: 0225ea4 c4199e3
+Merge: 0225ea4e c4199e30
Author: Ondrej Zajicek <santiago@crfreenet.org>
Date: Sun Dec 20 22:57:44 2009 +0100
Merge branch 'ospf3' into new
commit c4199e30313c88c0911060a5b5f3cc181ceedb37
-Merge: f2d7da7 ea7ada3
+Merge: f2d7da74 ea7ada38
Author: Ondrej Zajicek <santiago@crfreenet.org>
Date: Sun Dec 20 22:56:09 2009 +0100
@@ -12021,7 +13523,7 @@ Date: Sat Dec 19 18:45:46 2009 +0100
NEWS and version update.
commit 0225ea4eddb44bd9dd4f112e512325cbf80134d3
-Merge: 43c1cec f2d7da7
+Merge: 43c1cecc f2d7da74
Author: Ondrej Zajicek <santiago@crfreenet.org>
Date: Tue Dec 15 00:32:13 2009 +0100
@@ -12052,7 +13554,7 @@ Date: Mon Dec 14 21:17:15 2009 +0100
Implements route reload for OSPF.
commit 63542845dfb6d2277f93f77ad9ca3ad8bbaddd09
-Merge: 34a877c 8a7fb88
+Merge: 34a877cc 8a7fb885
Author: Ondrej Zajicek <santiago@crfreenet.org>
Date: Mon Dec 14 20:37:32 2009 +0100
@@ -12060,9 +13562,9 @@ Date: Mon Dec 14 20:37:32 2009 +0100
Conflicts:
- proto/ospf/lsreq.c
- proto/ospf/lsupd.c
- proto/ospf/rt.c
+ proto/ospf/lsreq.c
+ proto/ospf/lsupd.c
+ proto/ospf/rt.c
commit 34a877ccac25d38172716d3d2488449c870cad0b
Author: Ondrej Zajicek <santiago@crfreenet.org>
@@ -12182,7 +13684,7 @@ Date: Thu Nov 26 20:47:59 2009 +0100
Implements BGP route refresh.
commit 5e6f568115511e2bcf43c60dfdcbd7a35cb04b93
-Merge: 069bfcb 1f8be1e
+Merge: 069bfcb5 1f8be1e4
Author: Ondrej Zajicek <santiago@crfreenet.org>
Date: Tue Nov 24 17:19:23 2009 +0100
@@ -12283,14 +13785,14 @@ Date: Mon Nov 9 23:22:53 2009 +0100
Use IPv6 checksums in OSPFv3.
commit 3f22fa9e74c8643d3e4f7e3a7b4f2aa992ad09f5
-Merge: a6bc04d b7c0e93
+Merge: a6bc04d5 b7c0e93e
Author: Ondrej Zajicek <santiago@crfreenet.org>
Date: Mon Nov 9 22:54:39 2009 +0100
Merge branch 'dev' into ospf3
commit b7c0e93ebd40cdc4f6e89067a3e5f7293263c7f9
-Merge: 7965e17 f1f1e89
+Merge: 7965e17d f1f1e899
Author: Ondrej Zajicek <santiago@crfreenet.org>
Date: Mon Nov 2 16:27:17 2009 +0100
@@ -12555,7 +14057,7 @@ Date: Sun Aug 23 23:03:31 2009 +0200
Version 1.1.2
commit 2ef58837dcb7b78edc193bc9ef1da316bba86998
-Merge: 86975e5 5516a66
+Merge: 86975e58 5516a66d
Author: Ondrej Zajicek <santiago@crfreenet.org>
Date: Fri Aug 21 09:46:49 2009 +0200
@@ -12668,7 +14170,7 @@ Date: Mon Aug 10 12:04:25 2009 +0200
Fixes typo in Makefile
commit b92c8e30191dd757c76239076eda82d0065f2348
-Merge: 54d70d3 71a9574
+Merge: 54d70d3e 71a9574a
Author: Ondrej Zajicek <santiago@crfreenet.org>
Date: Mon Aug 10 10:16:00 2009 +0200
@@ -12731,7 +14233,7 @@ Date: Thu Jul 9 15:42:39 2009 +0200
Fixed bug related to reconfiguration of BGP with MD5 passwords.
commit dd7b4a13848f5a92b403a563e8e27a3cbdfc937f
-Merge: d1abbea bffd4c0
+Merge: d1abbeac bffd4c0b
Author: Ondrej Zajicek <santiago@crfreenet.org>
Date: Mon Jul 6 23:10:33 2009 +0200
@@ -12800,7 +14302,7 @@ Date: Fri Jun 26 13:33:41 2009 +0200
nobody noticed it already.
commit 5004d02cb9df1f3ee231632a8e89929f4eb4f088
-Merge: 1876e18 99355da
+Merge: 1876e18d 99355da1
Author: Ondrej Zajicek <santiago@crfreenet.org>
Date: Fri Jun 26 01:06:12 2009 +0200
@@ -13043,7 +14545,7 @@ Date: Fri May 29 13:32:24 2009 +0200
Add 'primary' configuration option.
commit 7c3d06b087946cbea4affa4a814e72b7a3556833
-Merge: f571473 4c2507d
+Merge: f571473e 4c2507da
Author: Ondrej Zajicek <santiago@crfreenet.org>
Date: Thu May 28 13:58:51 2009 +0200
@@ -13129,7 +14631,7 @@ Date: Fri May 22 00:26:30 2009 +0200
Better checks for M4 in configure.
commit 6c84554b671fce473fe333ab3d8b548a0768882b
-Merge: f434d19 4d176e1
+Merge: f434d191 4d176e14
Author: Ondrej Zajicek <santiago@crfreenet.org>
Date: Thu May 21 09:26:59 2009 +0200
@@ -13898,7 +15400,7 @@ Date: Tue Oct 28 16:10:42 2008 +0100
Fixes some sloppiness of commit a3b70dc499b64f41aa776b5b4afee5c7bfb8dfa6.
commit a98fbf0f12b5e83e25afa0f585ca6a4d4ac5f6bf
-Merge: a3b70dc 1567ede
+Merge: a3b70dc4 1567edea
Author: Ondrej Zajicek <santiago@crfreenet.org>
Date: Mon Oct 27 00:20:22 2008 +0100
@@ -14567,17 +16069,17 @@ Author: Ondrej Filip <feela@network.cz>
Date: Fri Jun 25 16:39:53 2004 +0000
A lot of changes:
- - metric is 3 byte long now
- - summary lsa originating
- - more OSPF areas possible
- - virtual links
- - better E1/E2 routes handling
- - some bug fixes..
+ - metric is 3 byte long now
+ - summary lsa originating
+ - more OSPF areas possible
+ - virtual links
+ - better E1/E2 routes handling
+ - some bug fixes..
I have to do:
- - md5 auth (last mandatory item from rfc2328)
- - !!!!DEBUG!!!!! (mainly virtual link system has probably a lot of bugs)
- - 2328 appendig E
+ - md5 auth (last mandatory item from rfc2328)
+ - !!!!DEBUG!!!!! (mainly virtual link system has probably a lot of bugs)
+ - 2328 appendig E
commit 5ed68e46d781f8a14d3ef3ffd7fe3afc4a62260e
Author: Ondrej Filip <feela@network.cz>
@@ -16022,7 +17524,7 @@ Author: Ondrej Filip <feela@network.cz>
Date: Fri Aug 25 12:26:03 2000 +0000
Minor bug. It does not work on non RH systems. Thanx to
- Craig Bourne <cbourne@cbourne.com>
+ Craig Bourne <cbourne@cbourne.com>
commit 6cf7e97abe05ee8943f8a2d300e1c46038b95df1
Author: Ondrej Filip <feela@network.cz>
@@ -17020,7 +18522,7 @@ Date: Mon Jun 5 02:23:20 2000 +0000
Many bugfixes (I don't remember all of them):
Added link ID calculation for external routes with same prefix but
- different mask.
+ different mask.
Bugfix in NET lsa origination.
Bugfix in NET hashing.
Bugfix in LSA installing.
@@ -18155,11 +19657,11 @@ Date: Mon May 29 10:32:37 2000 +0000
Added skeleton for subchapters on all the protocols. Each subchapter should
contain:
- Introduction (brief intro to the protocol, where should it be used,
- references to the relevant standards)
- Configuration
- Attributes
- Example
+ Introduction (brief intro to the protocol, where should it be used,
+ references to the relevant standards)
+ Configuration
+ Attributes
+ Example
Added a more detailed description of RIP attributes.
@@ -19707,8 +21209,8 @@ Date: Sat Apr 29 15:45:30 2000 +0000
Mj, could you provide example of static config for ipv6 that is _not_
rejected by checks? I tried this and got rejected.
- route 62:168::/32 via 62:169::;
- route 1:2::/32 via 1:3::;
+ route 62:168::/32 via 62:169::;
+ route 1:2::/32 via 1:3::;
commit 46cdc7e20faaf922431a157bcb0f82a45b7aa2d2
Author: Martin Mares <mj@ucw.cz>
@@ -20652,10 +22154,10 @@ Date: Sat Apr 1 10:19:47 2000 +0000
set to EAP_xxx) and also a callback for naming and formatting of attributes.
The callback can return one of the following results:
- GA_UNKNOWN Attribute not recognized.
- GA_NAME Attribute name recognized and put to the buffer,
- generic code should format the value.
- GA_FULL Both attribute name and value put to the buffer.
+ GA_UNKNOWN Attribute not recognized.
+ GA_NAME Attribute name recognized and put to the buffer,
+ generic code should format the value.
+ GA_FULL Both attribute name and value put to the buffer.
Please update protocols generating dynamic attributes to provide
the attr_class and formatting hook.
@@ -21612,9 +23114,9 @@ Date: Mon Jan 17 11:52:50 2000 +0000
Separated `official protocol names' used in status dumps from name templates
used for automatic generation of instance names.
- protocol->name is the official name
- protocol->template is the name template (usually "name%d"),
- should be all lowercase.
+ protocol->name is the official name
+ protocol->template is the name template (usually "name%d"),
+ should be all lowercase.
Updated all protocols to define the templates, checked that their configuration
grammar includes proto_name which generates the name and interns it in the
@@ -22265,8 +23767,8 @@ Date: Wed Nov 17 12:14:44 1999 +0000
To define a new command, just add a new rule to the gramar:
CF_CLI(COMMAND NAME, arguments, help-args, help-text) {
- what-should-the-command-do
- } ;
+ what-should-the-command-do
+ } ;
where <arguments> are appended to the RHS of the rule, <help-args> is the
argument list as shown in the help and <help-text> is description of the
command for the help.
@@ -22284,8 +23786,8 @@ Date: Wed Nov 17 12:14:44 1999 +0000
Functions to call inside command handlers:
cli_printf(cli, code, printf-args) -- print text to CLI connection,
- <code> is message code as assigned in doc/reply_codes or a negative
- one if it's a continuation line.
+ <code> is message code as assigned in doc/reply_codes or a negative
+ one if it's a continuation line.
cli_msg(code, printf-args) -- the same for this_cli.
Use 'sock -x bird.ctl' for connecting to the CLI until a client is written.
@@ -22515,9 +24017,9 @@ Date: Sun Oct 31 17:47:47 1999 +0000
to exist). This macro automatically creates a skeleton rule for the command,
you only need to append arguments as in:
- CF_CLI(STEAL MONEY, <$>, [[Steal <$> US dollars or equivalent in any other currency]]): NUM {
- cli_msg(0, "%d$ stolen", $3);
- } ;
+ CF_CLI(STEAL MONEY, <$>, [[Steal <$> US dollars or equivalent in any other currency]]): NUM {
+ cli_msg(0, "%d$ stolen", $3);
+ } ;
Also don't forget to reset lexer state between inputs.
@@ -23515,12 +25017,12 @@ Date: Mon Apr 5 20:25:03 1999 +0000
-- instead use a pool pointer passed to all related functions.
o Split rte_update to three functions:
- rte_update The front end: handles all checking, inbound
- filtering and calls rte_recalculate() for the
- final version of the route.
- rte_recalculate Update the table according to already filtered route.
- rte_announce Announce routing table changes to all protocols,
- passing them through export filters and so on.
+ rte_update The front end: handles all checking, inbound
+ filtering and calls rte_recalculate() for the
+ final version of the route.
+ rte_recalculate Update the table according to already filtered route.
+ rte_announce Announce routing table changes to all protocols,
+ passing them through export filters and so on.
The interface has _not_ changed -- still call rte_update() and it will
do the rest for you automagically.
@@ -23532,9 +25034,9 @@ Date: Mon Apr 5 20:17:59 1999 +0000
Added some new protocol hooks (look at the comments for better explanation):
- make_tmp_attrs Convert inline attributes to ea_list
- store_tmp_attrs Convert ea_list to inline attributes
- import_control Pre-import decisions
+ make_tmp_attrs Convert inline attributes to ea_list
+ store_tmp_attrs Convert ea_list to inline attributes
+ import_control Pre-import decisions
commit 5056c559c4eb253a4eee10cf35b694faec5265eb
Author: Martin Mares <mj@ucw.cz>
@@ -23543,17 +25045,17 @@ Date: Mon Apr 5 20:15:31 1999 +0000
Changed syntax of attaching filters to protocols to hopefully the final
version:
- EXPORT <filter-spec> for outbound routes (i.e., those announced
- by BIRD to the rest of the world).
- IMPORT <filter-spec> for inbound routes (i.e., those imported
- by BIRD from the rest of the world).
+ EXPORT <filter-spec> for outbound routes (i.e., those announced
+ by BIRD to the rest of the world).
+ IMPORT <filter-spec> for inbound routes (i.e., those imported
+ by BIRD from the rest of the world).
where <filter-spec> is one of:
- ALL pass all routes
- NONE drop all routes
- FILTER <name> use named filter
- FILTER { <filter> } use explicitly defined filter
+ ALL pass all routes
+ NONE drop all routes
+ FILTER <name> use named filter
+ FILTER { <filter> } use explicitly defined filter
For all protocols, the default is IMPORT ALL, EXPORT NONE. This includes
the kernel protocol, so that you need to add EXPORT ALL to get the previous
@@ -23742,11 +25244,11 @@ Date: Sat Mar 27 22:51:05 1999 +0000
Available configurations:
o linux-20: Old Linux interface via /proc/net/route (selected by default
- on pre-2.1 kernels).
+ on pre-2.1 kernels).
o linux-21: Old Linux interface, but device routes handled by the
- kernel (selected by default for 2.1 and newer kernels).
+ kernel (selected by default for 2.1 and newer kernels).
o linux-22: Linux with Netlink (I play with it a lot yet, so it isn't
- a default).
+ a default).
o linux-ipv6: Prototype config for IPv6 on Linux. Not functional yet.
commit 7dc4827c968053e45bcb7f145e9986eeb20c993b
@@ -23923,7 +25425,7 @@ Date: Thu Mar 4 14:23:32 1999 +0000
To build BIRD with Netlink support, just configure it with
- ./configure --with-sysconfig=linux-21
+ ./configure --with-sysconfig=linux-21
After it will be tested well enough, I'll probably make it a default
for 2.2 kernels (and rename it to linux-22 :)).
@@ -24308,21 +25810,21 @@ Date: Thu Feb 11 21:18:26 1999 +0000
be linked in at most one event list. For most purposes, just use the
global event list handled by the following functions:
- ev_schedule Schedule event to be called at the next event
- scheduling point. If the event was already
- scheduled, it's just re-linked to the end of the list.
- ev_postpone Postpone an already scheduled event, so that it
- won't get called. Postponed events can be scheduled
- again by ev_schedule().
+ ev_schedule Schedule event to be called at the next event
+ scheduling point. If the event was already
+ scheduled, it's just re-linked to the end of the list.
+ ev_postpone Postpone an already scheduled event, so that it
+ won't get called. Postponed events can be scheduled
+ again by ev_schedule().
You can also create custom event lists to build your own synchronization
primitives. Just use:
- ev_init_list to initialize an event list
- ev_enqueue to schedule event on specified event list
- ev_postpone works as well for custom lists
- ev_run_list to run all events on your custom list
- ev_run to run a specific event and dequeue it
+ ev_init_list to initialize an event list
+ ev_enqueue to schedule event on specified event list
+ ev_postpone works as well for custom lists
+ ev_run_list to run all events on your custom list
+ ev_run to run a specific event and dequeue it
commit edf62ba13fa6a74447d7ad44b23acbee964731bc
Author: Pavel Machek <pavel@ucw.cz>
@@ -24511,16 +26013,16 @@ Date: Sat Jan 9 15:02:11 1999 +0000
To compile BIRD, you now need to do:
- autoconf # Create configure from configure.in
- ./configure # Run configure script
- make # Compile everything
+ autoconf # Create configure from configure.in
+ ./configure # Run configure script
+ make # Compile everything
Configuration files:
- sysdep/config.h Master config file
- sysdep/autoconf.h Parameters determined by configure script
- sysdep/cf/*.h Fixed system configuration we're unable
- to guess.
+ sysdep/config.h Master config file
+ sysdep/autoconf.h Parameters determined by configure script
+ sysdep/cf/*.h Fixed system configuration we're unable
+ to guess.
Makefiles are still the original ones, but this will change soon.
@@ -24643,9 +26145,9 @@ Date: Sat Dec 19 11:51:47 1998 +0000
we can use very simple function which is monotonic with respect
to re-hashing:
- n ^= n >> 16;
- n ^= n << 10;
- h = (n >> (16 - o)) & ((1 << o) - 1);
+ n ^= n >> 16;
+ n ^= n << 10;
+ h = (n >> (16 - o)) & ((1 << o) - 1);
where o is table order. Statistical analysis for both backbone routing
table and local OSPF routing tables gives values near theoretical
@@ -25292,7 +26794,7 @@ Date: Tue Oct 13 14:32:18 1998 +0000
I prefer to have broken drivers than completely stupid ones...
- Linus Torvalds
+ Linus Torvalds
Rip now uses main routing table properly: entries are stored directly
into main routing table and we are relying on core to call our's
@@ -25422,10 +26924,10 @@ Date: Wed Jun 17 14:31:36 1998 +0000
Added local version of sprintf (bsprintf and bvsprintf) offering few new
format strings:
- %I IP address
- %#I IP address in hexadecimal
- %1I IP address padded to full length
- %m strerror(errno)
+ %I IP address
+ %#I IP address in hexadecimal
+ %1I IP address padded to full length
+ %m strerror(errno)
commit 97d858c590998786d4d8a16b5c1f657800d74736
Author: Martin Mares <mj@ucw.cz>
diff --git a/Makefile.in b/Makefile.in
index e6dbd572..e0ff4a1d 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -184,11 +184,20 @@ check: tests tests_run
tests: $(tests_targets)
tests_run: $(tests_targets_ok)
+STATIC_CHECKERS_ENABLE := nullability.NullableDereferenced nullability.NullablePassedToNonnull nullability.NullableReturnedFromNonnull optin.portability.UnixAPI valist.CopyToSelf valist.Uninitialized valist.Unterminated
+STATIC_CHECKERS_DISABLE := deadcode.DeadStores
+STATIC_SCAN_FLAGS := -o $(objdir)/static-scan/ $(addprefix -enable-checker ,$(STATIC_CHECKERS_ENABLE)) $(addprefix -disable-checker ,$(STATIC_CHECKERS_DISABLE))
+
+static-scan:
+ $(E)echo Running static code analysis
+ $(Q)$(MAKE) clean
+ $(Q)scan-build $(STATIC_SCAN_FLAGS) $(MAKE) -$(MAKEFLAGS)
+
tags:
- cd $(srcdir) ; etags -lc `find $(dirs) -name *.[chY]`
+ cd $(srcdir) ; etags -lc `find $(dirs) -name '*.[chY]'`
cscope:
- cd $(srcdir) ; find $(dirs) -name *.[chY] > cscope.files ; cscope -b
+ cd $(srcdir) ; find $(dirs) -name '*.[chY]' > cscope.files ; cscope -b
# Install
diff --git a/NEWS b/NEWS
index bb115608..4a85c365 100644
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,44 @@
+Version 2.0.8 (2021-03-18)
+ o Automatic channel reloads based on RPKI changes
+ o Multiple static routes with the same network
+ o Use bitmaps to keep track of exported routes
+ o Per-channel debug flags
+ o CLI commands show info from multiple protocols
+ o Linux: IPv4 routes with IPv6 nexthops
+ o Filter: Optimized redesign of prefix sets
+ o Filter: Improved type checking of user filters
+ o Filter: New src/dst accessors for Flowspec and SADR
+ o Filter: New 'weight' route attribute
+ o Filter: BGP path mask loop operator
+ o Filter: Remove quitbird command
+ o RIP: Demand circuit support (RFC 2091)
+ o BGP: New 'allow as sets' and 'enforce first as' options
+ o BGP: Support for BGP hostname capability
+ o BGP: Support for MD5SIG with dynamic BGP
+ o BFD: Optional separation of IPv4 / IPv6 BFD instances
+ o BFD: Per-peer session options
+ o RPKI: Allow build without libSSH
+ o RPKI: New 'ignore max length' option
+ o OSPF: Redesign of handling of unnumbered PtPs
+ o OSPF: Allow key id 0 in authentication
+ o Babel: Use onlink flag for routes with unreachable next hop
+ o Many bugfixes
+
+ Notes:
+
+ Automatic channel reloads based on RPKI changes are enabled by default,
+ but require import table enabled when used in BGP import filter.
+
+ BIRD now uses bitmaps to keep track of exported routes instead of
+ re-evaluation of export filters. That should improve speed and accuracy in
+ route export handling during reconfiguration, but takes some more memory.
+
+ Per-channel debug logging and some CLI commands (like 'show ospf neighbors')
+ defaulting to all protocol instances lead to some minor changes in log and
+ CLI output. Caution is recommended when logs or CLI output are monitored by
+ scripts.
+
+
Version 2.0.7 (2019-10-11)
o BGP: Accumulated IGP metric (RFC 7311)
o Important filter reconfiguration bugfix
diff --git a/bird-gdb.py b/bird-gdb.py
index a85ef8c6..3cf65a9c 100644
--- a/bird-gdb.py
+++ b/bird-gdb.py
@@ -30,6 +30,7 @@ class BIRDFValPrinter(BIRDPrinter):
"T_ENUM_ROA": "i",
"T_ENUM_NETTYPE": "i",
"T_ENUM_RA_PREFERENCE": "i",
+ "T_ENUM_AF": "i",
"T_IP": "ip",
"T_NET": "net",
"T_STRING": "s",
diff --git a/conf/cf-lex.l b/conf/cf-lex.l
index 1d6cae2c..05288b1a 100644
--- a/conf/cf-lex.l
+++ b/conf/cf-lex.l
@@ -169,7 +169,7 @@ WHITE [ \t]
errno = 0;
l = bstrtoul10(yytext, &e);
- if (e && (*e != ':') || (errno == ERANGE) || (l >> 32))
+ if (!e || (*e != ':') || (errno == ERANGE) || (l >> 32))
cf_error("ASN out of range");
if (l >> 16)
@@ -187,7 +187,7 @@ WHITE [ \t]
errno = 0;
l = bstrtoul10(e+1, &e);
- if (e && *e || (errno == ERANGE) || (l >> len2))
+ if (!e || *e || (errno == ERANGE) || (l >> len2))
cf_error("Number out of range");
cf_lval.i64 |= l;
@@ -214,13 +214,13 @@ WHITE [ \t]
errno = 0;
l = bstrtoul10(yytext+2, &e);
- if (e && (*e != ':') || (errno == ERANGE) || (l >> len1))
+ if (!e || (*e != ':') || (errno == ERANGE) || (l >> len1))
cf_error("ASN out of range");
cf_lval.i64 |= ((u64) l) << len2;
errno = 0;
l = bstrtoul10(e+1, &e);
- if (e && *e || (errno == ERANGE) || (l >> len2))
+ if (!e || *e || (errno == ERANGE) || (l >> len2))
cf_error("Number out of range");
cf_lval.i64 |= l;
@@ -242,7 +242,7 @@ WHITE [ \t]
errno = 0;
l = bstrtoul10(e, &e);
- if (e && *e || (errno == ERANGE) || (l >> 16))
+ if (!e || *e || (errno == ERANGE) || (l >> 16))
cf_error("Number out of range");
cf_lval.i64 |= l;
@@ -266,7 +266,7 @@ WHITE [ \t]
unsigned long int l;
errno = 0;
l = bstrtoul16(yytext+2, &e);
- if (e && *e || errno == ERANGE || (unsigned long int)(unsigned int) l != l)
+ if (!e || *e || errno == ERANGE || (unsigned long int)(unsigned int) l != l)
cf_error("Number out of range");
cf_lval.i = l;
return NUM;
@@ -277,7 +277,7 @@ WHITE [ \t]
unsigned long int l;
errno = 0;
l = bstrtoul10(yytext, &e);
- if (e && *e || errno == ERANGE || (unsigned long int)(unsigned int) l != l)
+ if (!e || *e || errno == ERANGE || (unsigned long int)(unsigned int) l != l)
cf_error("Number out of range");
cf_lval.i = l;
return NUM;
@@ -737,7 +737,7 @@ cf_lex_init(int is_cli, struct config *c)
void
cf_push_scope(struct symbol *sym)
{
- struct sym_scope *s = cfg_alloc(sizeof(struct sym_scope));
+ struct sym_scope *s = cfg_allocz(sizeof(struct sym_scope));
s->next = conf_this_scope;
conf_this_scope = s;
diff --git a/conf/conf.c b/conf/conf.c
index b21d5213..58abcde1 100644
--- a/conf/conf.c
+++ b/conf/conf.c
@@ -55,6 +55,7 @@
#include "lib/timer.h"
#include "conf/conf.h"
#include "filter/filter.h"
+#include "sysdep/unix/unix.h"
static jmp_buf conf_jmpbuf;
@@ -217,6 +218,14 @@ config_del_obstacle(struct config *c)
static int
global_commit(struct config *new, struct config *old)
{
+ if (!new->hostname)
+ {
+ new->hostname = get_hostname(new->mem);
+
+ if (!new->hostname)
+ log(L_WARN "Cannot determine hostname");
+ }
+
if (!old)
return 0;
@@ -573,6 +582,7 @@ cfg_copy_list(list *dest, list *src, unsigned node_size)
{
dn = cfg_alloc(node_size);
memcpy(dn, sn, node_size);
+ memset(dn, 0, sizeof(node));
add_tail(dest, dn);
}
}
diff --git a/conf/conf.h b/conf/conf.h
index 21dc3fa1..860d267a 100644
--- a/conf/conf.h
+++ b/conf/conf.h
@@ -27,18 +27,20 @@ struct config {
list symbols; /* Configured symbols in config order */
int mrtdump_file; /* Configured MRTDump file (sysdep, fd in unix) */
- char *syslog_name; /* Name used for syslog (NULL -> no syslog) */
+ const char *syslog_name; /* Name used for syslog (NULL -> no syslog) */
struct rtable_config *def_tables[NET_MAX]; /* Default routing tables for each network */
struct iface_patt *router_id_from; /* Configured list of router ID iface patterns */
u32 router_id; /* Our Router ID */
- unsigned proto_default_debug; /* Default protocol debug mask */
- unsigned proto_default_mrtdump; /* Default protocol mrtdump mask */
+ u32 proto_default_debug; /* Default protocol debug mask */
+ u32 proto_default_mrtdump; /* Default protocol mrtdump mask */
+ u32 channel_default_debug; /* Default channel debug mask */
struct timeformat tf_route; /* Time format for 'show route' */
struct timeformat tf_proto; /* Time format for 'show protocol' */
struct timeformat tf_log; /* Time format for the logfile */
struct timeformat tf_base; /* Time format for other purposes */
u32 gr_wait; /* Graceful restart wait timeout (sec) */
+ const char *hostname; /* Hostname */
int cli_debug; /* Tracing of CLI connections and commands */
int latency_debug; /* I/O loop tracks duration of each event */
@@ -198,11 +200,11 @@ struct symbol *cf_localize_symbol(struct symbol *sym);
* Result: Pointer to the newly defined symbol. If we are in the top-level
* scope, it's the same @sym as passed to the function.
*/
-#define cf_define_symbol(sym_, type_, var_, def_) ({ \
- struct symbol *sym = cf_localize_symbol(sym_); \
- sym->class = type_; \
- sym->var_ = def_; \
- sym; })
+#define cf_define_symbol(osym_, type_, var_, def_) ({ \
+ struct symbol *sym_ = cf_localize_symbol(osym_); \
+ sym_->class = type_; \
+ sym_->var_ = def_; \
+ sym_; })
void cf_push_scope(struct symbol *);
void cf_pop_scope(void);
diff --git a/conf/confbase.Y b/conf/confbase.Y
index 75158927..d98f0fee 100644
--- a/conf/confbase.Y
+++ b/conf/confbase.Y
@@ -19,6 +19,7 @@ CF_HDR
#include "nest/protocol.h"
#include "nest/iface.h"
#include "nest/route.h"
+#include "nest/bfd.h"
#include "nest/cli.h"
#include "filter/filter.h"
@@ -60,9 +61,10 @@ CF_DECLS
net_addr net;
net_addr *net_ptr;
struct symbol *s;
- char *t;
+ const char *t;
struct rtable_config *r;
struct channel_config *cc;
+ struct channel *c;
struct f_inst *x;
struct {
struct f_inst *begin, *end;
@@ -147,7 +149,7 @@ conf: definition ;
definition:
DEFINE symbol '=' term ';' {
- struct f_val *val = cfg_alloc(sizeof(struct f_val));
+ struct f_val *val = cfg_allocz(sizeof(struct f_val));
if (f_eval(f_linearize($4), cfg_mem, val) > F_RETURN) cf_error("Runtime error");
cf_define_symbol($2, SYM_CONSTANT | val->type, val, val);
}
diff --git a/conf/gen_keywords.m4 b/conf/gen_keywords.m4
index cf3fb58e..0c1dc545 100644
--- a/conf/gen_keywords.m4
+++ b/conf/gen_keywords.m4
@@ -34,9 +34,11 @@ m4_define(CF_CLI, `CF_KEYWORDS(m4_translit($1, [[ ]], [[,]]))
')
# Enums are translated to C initializers: use CF_ENUM(typename, prefix, values)
-m4_define(CF_enum, `m4_divert(1){ "CF_enum_prefix[[]]$1", -((CF_enum_type<<16) | CF_enum_prefix[[]]$1), NULL },
+# For different prefix: CF_ENUM_PX(typename, external prefix, C prefix, values)
+m4_define(CF_enum, `m4_divert(1){ "CF_enum_prefix_ext[[]]$1", -((CF_enum_type<<16) | CF_enum_prefix_int[[]]$1), NULL },
m4_divert(-1)')
-m4_define(CF_ENUM, `m4_define([[CF_enum_type]],$1)m4_define([[CF_enum_prefix]],$2)CF_iterate([[CF_enum]], [[m4_shift(m4_shift($@))]])DNL')
+m4_define(CF_ENUM, `m4_define([[CF_enum_type]],$1)m4_define([[CF_enum_prefix_ext]],$2)m4_define([[CF_enum_prefix_int]],$2)CF_iterate([[CF_enum]], [[m4_shift(m4_shift($@))]])DNL')
+m4_define(CF_ENUM_PX, `m4_define([[CF_enum_type]],$1)m4_define([[CF_enum_prefix_ext]],$2)m4_define([[CF_enum_prefix_int]],$3)CF_iterate([[CF_enum]], [[m4_shift(m4_shift(m4_shift($@)))]])DNL')
# After all configuration templates end, we generate the
m4_m4wrap(`
diff --git a/conf/gen_parser.m4 b/conf/gen_parser.m4
index af43d96f..5b378a93 100644
--- a/conf/gen_parser.m4
+++ b/conf/gen_parser.m4
@@ -44,6 +44,7 @@ m4_define(CF_CLI_HELP, `')
# ENUM declarations are ignored
m4_define(CF_ENUM, `')
+m4_define(CF_ENUM_PX, `')
# After all configuration templates end, we finally generate the grammar file.
m4_m4wrap(`
diff --git a/configure b/configure
index e5d5eedf..0c9380bc 100755
--- a/configure
+++ b/configure
@@ -1,9 +1,9 @@
#! /bin/sh
# Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.69.
+# Generated by GNU Autoconf 2.69e.
#
#
-# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc.
+# Copyright (C) 1992-1996, 1998-2017, 2020 Free Software Foundation, Inc.
#
#
# This configure script is free software; the Free Software Foundation
@@ -14,14 +14,16 @@
# Be more Bourne compatible
DUALCASE=1; export DUALCASE # for MKS sh
-if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
+as_nop=:
+if test ${ZSH_VERSION+y} && (emulate sh) >/dev/null 2>&1
+then :
emulate sh
NULLCMD=:
# Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
# is contrary to our usage. Disable this feature.
alias -g '${1+"$@"}'='"$@"'
setopt NO_GLOB_SUBST
-else
+else $as_nop
case `(set -o) 2>/dev/null` in #(
*posix*) :
set -o posix ;; #(
@@ -31,46 +33,46 @@ esac
fi
+
+# Reset variables that may have inherited troublesome values from
+# the environment.
+
+# IFS needs to be set, to space, tab, and newline, in precisely that order.
+# (If _AS_PATH_WALK were called with IFS unset, it would have the
+# side effect of setting IFS to empty, thus disabling word splitting.)
+# Quoting is to prevent editors from complaining about space-tab.
as_nl='
'
export as_nl
-# Printing a long string crashes Solaris 7 /usr/bin/printf.
-as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
-as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
-as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
-# Prefer a ksh shell builtin over an external printf program on Solaris,
-# but without wasting forks for bash or zsh.
-if test -z "$BASH_VERSION$ZSH_VERSION" \
- && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then
- as_echo='print -r --'
- as_echo_n='print -rn --'
-elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
- as_echo='printf %s\n'
- as_echo_n='printf %s'
-else
- if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
- as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
- as_echo_n='/usr/ucb/echo -n'
- else
- as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
- as_echo_n_body='eval
- arg=$1;
- case $arg in #(
- *"$as_nl"*)
- expr "X$arg" : "X\\(.*\\)$as_nl";
- arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
- esac;
- expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
- '
- export as_echo_n_body
- as_echo_n='sh -c $as_echo_n_body as_echo'
- fi
- export as_echo_body
- as_echo='sh -c $as_echo_body as_echo'
-fi
+IFS=" "" $as_nl"
+
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# Ensure predictable behavior from utilities with locale-dependent output.
+LC_ALL=C
+export LC_ALL
+LANGUAGE=C
+export LANGUAGE
+
+# We cannot yet rely on "unset" to work, but we need these variables
+# to be unset--not just set to an empty or harmless value--now, to
+# avoid bugs in old shells (e.g. pre-3.0 UWIN ksh). This construct
+# also avoids known problems related to "unset" and subshell syntax
+# in other old shells (e.g. bash 2.01 and pdksh 5.2.14).
+for as_var in BASH_ENV ENV MAIL MAILPATH CDPATH
+do eval test \${$as_var+y} \
+ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
+done
+
+# Ensure that fds 0, 1, and 2 are open.
+if (exec 3>&0) 2>/dev/null; then :; else exec 0</dev/null; fi
+if (exec 3>&1) 2>/dev/null; then :; else exec 1>/dev/null; fi
+if (exec 3>&2) ; then :; else exec 2>/dev/null; fi
# The user is always right.
-if test "${PATH_SEPARATOR+set}" != set; then
+if ${PATH_SEPARATOR+false} :; then
PATH_SEPARATOR=:
(PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
(PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
@@ -79,13 +81,6 @@ if test "${PATH_SEPARATOR+set}" != set; then
fi
-# IFS
-# We need space, tab and new line, in precisely that order. Quoting is
-# there to prevent editors from complaining about space-tab.
-# (If _AS_PATH_WALK were called with IFS unset, it would disable word
-# splitting by setting IFS to empty value.)
-IFS=" "" $as_nl"
-
# Find who we are. Look in the path if we contain no directory separator.
as_myself=
case $0 in #((
@@ -94,8 +89,12 @@ case $0 in #((
for as_dir in $PATH
do
IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
- test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+ case $as_dir in #(((
+ '') as_dir=./ ;;
+ */) ;;
+ *) as_dir=$as_dir/ ;;
+ esac
+ test -r "$as_dir$0" && as_myself=$as_dir$0 && break
done
IFS=$as_save_IFS
@@ -107,30 +106,10 @@ if test "x$as_myself" = x; then
as_myself=$0
fi
if test ! -f "$as_myself"; then
- $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+ printf "%s\n" "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
exit 1
fi
-# Unset variables that we do not need and which cause bugs (e.g. in
-# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1"
-# suppresses any "Segmentation fault" message there. '((' could
-# trigger a bug in pdksh 5.2.14.
-for as_var in BASH_ENV ENV MAIL MAILPATH
-do eval test x\${$as_var+set} = xset \
- && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
-done
-PS1='$ '
-PS2='> '
-PS4='+ '
-
-# NLS nuisances.
-LC_ALL=C
-export LC_ALL
-LANGUAGE=C
-export LANGUAGE
-
-# CDPATH.
-(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
# Use a proper internal environment variable to ensure we don't fall
# into an infinite loop, continuously re-executing ourselves.
@@ -152,20 +131,22 @@ esac
exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"}
# Admittedly, this is quite paranoid, since all the known shells bail
# out after a failed `exec'.
-$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2
-as_fn_exit 255
+printf "%s\n" "$0: could not re-execute with $CONFIG_SHELL" >&2
+exit 255
fi
# We don't want this to propagate to other subprocesses.
{ _as_can_reexec=; unset _as_can_reexec;}
if test "x$CONFIG_SHELL" = x; then
- as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then :
+ as_bourne_compatible="as_nop=:
+if test \${ZSH_VERSION+y} && (emulate sh) >/dev/null 2>&1
+then :
emulate sh
NULLCMD=:
# Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which
# is contrary to our usage. Disable this feature.
alias -g '\${1+\"\$@\"}'='\"\$@\"'
setopt NO_GLOB_SUBST
-else
+else \$as_nop
case \`(set -o) 2>/dev/null\` in #(
*posix*) :
set -o posix ;; #(
@@ -185,42 +166,52 @@ as_fn_success || { exitcode=1; echo as_fn_success failed.; }
as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; }
as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; }
as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; }
-if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then :
+if ( set x; as_fn_ret_success y && test x = \"\$1\" )
+then :
-else
+else \$as_nop
exitcode=1; echo positional parameters were not saved.
fi
test x\$exitcode = x0 || exit 1
+blah=\$(echo \$(echo blah))
+test x\"\$blah\" = xblah || exit 1
test -x / || exit 1"
as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO
as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO
eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" &&
- test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1
-test \$(( 1 + 1 )) = 2 || exit 1"
- if (eval "$as_required") 2>/dev/null; then :
+ test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1"
+ if (eval "$as_required") 2>/dev/null
+then :
as_have_required=yes
-else
+else $as_nop
as_have_required=no
fi
- if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then :
+ if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null
+then :
-else
+else $as_nop
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
as_found=false
for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH
do
IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
+ case $as_dir in #(((
+ '') as_dir=./ ;;
+ */) ;;
+ *) as_dir=$as_dir/ ;;
+ esac
as_found=:
case $as_dir in #(
/*)
for as_base in sh bash ksh sh5; do
# Try only shells that exist, to save several forks.
- as_shell=$as_dir/$as_base
+ as_shell=$as_dir$as_base
if { test -f "$as_shell" || test -f "$as_shell.exe"; } &&
- { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then :
+ as_run=a "$as_shell" -c "$as_bourne_compatible""$as_required" 2>/dev/null
+then :
CONFIG_SHELL=$as_shell as_have_required=yes
- if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then :
+ if as_run=a "$as_shell" -c "$as_bourne_compatible""$as_suggested" 2>/dev/null
+then :
break 2
fi
fi
@@ -228,14 +219,21 @@ fi
esac
as_found=false
done
-$as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } &&
- { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then :
- CONFIG_SHELL=$SHELL as_have_required=yes
-fi; }
IFS=$as_save_IFS
+if $as_found
+then :
+
+else $as_nop
+ if { test -f "$SHELL" || test -f "$SHELL.exe"; } &&
+ as_run=a "$SHELL" -c "$as_bourne_compatible""$as_required" 2>/dev/null
+then :
+ CONFIG_SHELL=$SHELL as_have_required=yes
+fi
+fi
- if test "x$CONFIG_SHELL" != x; then :
+ if test "x$CONFIG_SHELL" != x
+then :
export CONFIG_SHELL
# We cannot yet assume a decent shell, so we have to provide a
# neutralization value for shells without unset; and this also
@@ -253,18 +251,19 @@ esac
exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"}
# Admittedly, this is quite paranoid, since all the known shells bail
# out after a failed `exec'.
-$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2
+printf "%s\n" "$0: could not re-execute with $CONFIG_SHELL" >&2
exit 255
fi
- if test x$as_have_required = xno; then :
- $as_echo "$0: This script requires a shell more modern than all"
- $as_echo "$0: the shells that I found on your system."
- if test x${ZSH_VERSION+set} = xset ; then
- $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should"
- $as_echo "$0: be upgraded to zsh 4.3.4 or later."
+ if test x$as_have_required = xno
+then :
+ printf "%s\n" "$0: This script requires a shell more modern than all"
+ printf "%s\n" "$0: the shells that I found on your system."
+ if test ${ZSH_VERSION+y} ; then
+ printf "%s\n" "$0: In particular, zsh $ZSH_VERSION has bugs and should"
+ printf "%s\n" "$0: be upgraded to zsh 4.3.4 or later."
else
- $as_echo "$0: Please tell bug-autoconf@gnu.org about your system,
+ printf "%s\n" "$0: Please tell bug-autoconf@gnu.org about your system,
$0: including any error possibly output before this
$0: message. Then install a modern shell, or manually run
$0: the script under such a shell if you do have one."
@@ -291,6 +290,7 @@ as_fn_unset ()
}
as_unset=as_fn_unset
+
# as_fn_set_status STATUS
# -----------------------
# Set $? to STATUS, without forking.
@@ -308,6 +308,14 @@ as_fn_exit ()
as_fn_set_status $1
exit $1
} # as_fn_exit
+# as_fn_nop
+# ---------
+# Do nothing but, unlike ":", preserve the value of $?.
+as_fn_nop ()
+{
+ return $?
+}
+as_nop=as_fn_nop
# as_fn_mkdir_p
# -------------
@@ -322,7 +330,7 @@ as_fn_mkdir_p ()
as_dirs=
while :; do
case $as_dir in #(
- *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
+ *\'*) as_qdir=`printf "%s\n" "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
*) as_qdir=$as_dir;;
esac
as_dirs="'$as_qdir' $as_dirs"
@@ -331,7 +339,7 @@ $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
X"$as_dir" : 'X\(//\)[^/]' \| \
X"$as_dir" : 'X\(//\)$' \| \
X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
-$as_echo X"$as_dir" |
+printf "%s\n" X"$as_dir" |
sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
s//\1/
q
@@ -370,12 +378,13 @@ as_fn_executable_p ()
# advantage of any shell optimizations that allow amortized linear growth over
# repeated appends, instead of the typical quadratic growth present in naive
# implementations.
-if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :
+if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null
+then :
eval 'as_fn_append ()
{
eval $1+=\$2
}'
-else
+else $as_nop
as_fn_append ()
{
eval $1=\$$1\$2
@@ -387,18 +396,27 @@ fi # as_fn_append
# Perform arithmetic evaluation on the ARGs, and store the result in the
# global $as_val. Take advantage of shells that can avoid forks. The arguments
# must be portable across $(()) and expr.
-if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
+if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null
+then :
eval 'as_fn_arith ()
{
as_val=$(( $* ))
}'
-else
+else $as_nop
as_fn_arith ()
{
as_val=`expr "$@" || test $? -eq 1`
}
fi # as_fn_arith
+# as_fn_nop
+# ---------
+# Do nothing but, unlike ":", preserve the value of $?.
+as_fn_nop ()
+{
+ return $?
+}
+as_nop=as_fn_nop
# as_fn_error STATUS ERROR [LINENO LOG_FD]
# ----------------------------------------
@@ -410,9 +428,9 @@ as_fn_error ()
as_status=$1; test $as_status -eq 0 && as_status=1
if test "$4"; then
as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
- $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
fi
- $as_echo "$as_me: error: $2" >&2
+ printf "%s\n" "$as_me: error: $2" >&2
as_fn_exit $as_status
} # as_fn_error
@@ -439,7 +457,7 @@ as_me=`$as_basename -- "$0" ||
$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
X"$0" : 'X\(//\)$' \| \
X"$0" : 'X\(/\)' \| . 2>/dev/null ||
-$as_echo X/"$0" |
+printf "%s\n" X/"$0" |
sed '/^.*\/\([^/][^/]*\)\/*$/{
s//\1/
q
@@ -483,7 +501,7 @@ as_cr_alnum=$as_cr_Letters$as_cr_digits
s/-\n.*//
' >$as_me.lineno &&
chmod +x "$as_me.lineno" ||
- { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; }
+ { printf "%s\n" "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; }
# If we had to re-execute with $CONFIG_SHELL, we're ensured to have
# already done that, so ensure we don't try to do so again and fall
@@ -497,6 +515,10 @@ as_cr_alnum=$as_cr_Letters$as_cr_digits
exit
}
+
+# Determine whether it's possible to make 'echo' print without a newline.
+# These variables are no longer used directly by Autoconf, but are AC_SUBSTed
+# for compatibility with existing Makefiles.
ECHO_C= ECHO_N= ECHO_T=
case `echo -n x` in #(((((
-n*)
@@ -510,6 +532,13 @@ case `echo -n x` in #(((((
ECHO_N='-n';;
esac
+# For backward compatibility with old third-party macros, we provide
+# the shell variables $as_echo and $as_echo_n. New code should use
+# AS_ECHO(["message"]) and AS_ECHO_N(["message"]), respectively.
+as_echo='printf %s\n'
+as_echo_n='printf %s'
+
+
rm -f conf$$ conf$$.exe conf$$.file
if test -d conf$$.dir; then
rm -f conf$$.dir/conf$$.file
@@ -575,38 +604,26 @@ MFLAGS=
MAKEFLAGS=
# Identity of this package.
-PACKAGE_NAME=
-PACKAGE_TARNAME=
-PACKAGE_VERSION=
-PACKAGE_STRING=
-PACKAGE_BUGREPORT=
-PACKAGE_URL=
+PACKAGE_NAME=''
+PACKAGE_TARNAME=''
+PACKAGE_VERSION=''
+PACKAGE_STRING=''
+PACKAGE_BUGREPORT=''
+PACKAGE_URL=''
ac_unique_file="conf/confbase.Y"
-ac_header_list=
# Factoring default headers for most tests.
ac_includes_default="\
+#include <stddef.h>
#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
#ifdef HAVE_SYS_TYPES_H
# include <sys/types.h>
#endif
#ifdef HAVE_SYS_STAT_H
# include <sys/stat.h>
#endif
-#ifdef STDC_HEADERS
-# include <stdlib.h>
-# include <stddef.h>
-#else
-# ifdef HAVE_STDLIB_H
-# include <stdlib.h>
-# endif
-#endif
-#ifdef HAVE_STRING_H
-# if !defined STDC_HEADERS && defined HAVE_MEMORY_H
-# include <memory.h>
-# endif
-# include <string.h>
-#endif
#ifdef HAVE_STRINGS_H
# include <strings.h>
#endif
@@ -620,12 +637,11 @@ ac_includes_default="\
# include <unistd.h>
#endif"
+ac_header_c_list=
ac_subst_vars='LTLIBOBJS
LIBOBJS
CLIENT_LIBS
CLIENT
-EGREP
-GREP
protocols
DAEMON_LIBS
iproutedir
@@ -705,6 +721,7 @@ enable_option_checking
enable_client
enable_debug
enable_debug_generated
+enable_debug_expensive
enable_memcheck
enable_pthreads
enable_libssh
@@ -794,8 +811,6 @@ do
*) ac_optarg=yes ;;
esac
- # Accept the important Cygnus configure options, so we can diagnose typos.
-
case $ac_dashdash$ac_option in
--)
ac_dashdash=yes ;;
@@ -836,9 +851,9 @@ do
ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'`
# Reject names that are not valid shell variable names.
expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
- as_fn_error $? "invalid feature name: $ac_useropt"
+ as_fn_error $? "invalid feature name: \`$ac_useropt'"
ac_useropt_orig=$ac_useropt
- ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'`
case $ac_user_opts in
*"
"enable_$ac_useropt"
@@ -862,9 +877,9 @@ do
ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'`
# Reject names that are not valid shell variable names.
expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
- as_fn_error $? "invalid feature name: $ac_useropt"
+ as_fn_error $? "invalid feature name: \`$ac_useropt'"
ac_useropt_orig=$ac_useropt
- ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'`
case $ac_user_opts in
*"
"enable_$ac_useropt"
@@ -1075,9 +1090,9 @@ do
ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'`
# Reject names that are not valid shell variable names.
expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
- as_fn_error $? "invalid package name: $ac_useropt"
+ as_fn_error $? "invalid package name: \`$ac_useropt'"
ac_useropt_orig=$ac_useropt
- ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'`
case $ac_user_opts in
*"
"with_$ac_useropt"
@@ -1091,9 +1106,9 @@ do
ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'`
# Reject names that are not valid shell variable names.
expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
- as_fn_error $? "invalid package name: $ac_useropt"
+ as_fn_error $? "invalid package name: \`$ac_useropt'"
ac_useropt_orig=$ac_useropt
- ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'`
case $ac_user_opts in
*"
"with_$ac_useropt"
@@ -1137,9 +1152,9 @@ Try \`$0 --help' for more information"
*)
# FIXME: should be removed in autoconf 3.0.
- $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2
+ printf "%s\n" "$as_me: WARNING: you should use --build, --host, --target" >&2
expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null &&
- $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2
+ printf "%s\n" "$as_me: WARNING: invalid host type: $ac_option" >&2
: "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}"
;;
@@ -1155,7 +1170,7 @@ if test -n "$ac_unrecognized_opts"; then
case $enable_option_checking in
no) ;;
fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;;
- *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;;
+ *) printf "%s\n" "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;;
esac
fi
@@ -1219,7 +1234,7 @@ $as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
X"$as_myself" : 'X\(//\)[^/]' \| \
X"$as_myself" : 'X\(//\)$' \| \
X"$as_myself" : 'X\(/\)' \| . 2>/dev/null ||
-$as_echo X"$as_myself" |
+printf "%s\n" X"$as_myself" |
sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
s//\1/
q
@@ -1352,9 +1367,12 @@ Optional Features:
--enable-debug enable internal debugging routines [no]
--enable-debug-generated
enable this to abstain from generating #line [no]
+ --enable-debug-expensive
+ enable expensive consistency checks (implies
+ --enable-debug) [no]
--enable-memcheck check memory allocations when debugging [yes]
--enable-pthreads enable POSIX threads support [try]
- --enable-libssh enable LibSSH support together with RPKI [try]
+ --enable-libssh enable LibSSH support in RPKI [try]
--enable-mpls-kernel enable MPLS support in kernel protocol [try]
Optional Packages:
@@ -1398,9 +1416,9 @@ if test "$ac_init_help" = "recursive"; then
case "$ac_dir" in
.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
*)
- ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
+ ac_dir_suffix=/`printf "%s\n" "$ac_dir" | sed 's|^\.[\\/]||'`
# A ".." for each directory in $ac_dir_suffix.
- ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
+ ac_top_builddir_sub=`printf "%s\n" "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
case $ac_top_builddir_sub in
"") ac_top_builddir_sub=. ac_top_build_prefix= ;;
*) ac_top_build_prefix=$ac_top_builddir_sub/ ;;
@@ -1428,7 +1446,8 @@ esac
ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
cd "$ac_dir" || { ac_status=$?; continue; }
- # Check for guested configure.
+ # Check for configure.gnu first; this name is used for a wrapper for
+ # Metaconfig's "Configure" on case-insensitive file systems.
if test -f "$ac_srcdir/configure.gnu"; then
echo &&
$SHELL "$ac_srcdir/configure.gnu" --help=recursive
@@ -1436,7 +1455,7 @@ ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
echo &&
$SHELL "$ac_srcdir/configure" --help=recursive
else
- $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2
+ printf "%s\n" "$as_me: WARNING: no configuration information is in $ac_dir" >&2
fi || ac_status=$?
cd "$ac_pwd" || { ac_status=$?; break; }
done
@@ -1446,9 +1465,9 @@ test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then
cat <<\_ACEOF
configure
-generated by GNU Autoconf 2.69
+generated by GNU Autoconf 2.69e
-Copyright (C) 2012 Free Software Foundation, Inc.
+Copyright (C) 2020 Free Software Foundation, Inc.
This configure script is free software; the Free Software Foundation
gives unlimited permission to copy, distribute and modify it.
_ACEOF
@@ -1465,14 +1484,14 @@ fi
ac_fn_c_try_compile ()
{
as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
- rm -f conftest.$ac_objext
+ rm -f conftest.$ac_objext conftest.beam
if { { ac_try="$ac_compile"
case "(($ac_try" in
*\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
*) ac_try_echo=$ac_try;;
esac
eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
-$as_echo "$ac_try_echo"; } >&5
+printf "%s\n" "$ac_try_echo"; } >&5
(eval "$ac_compile") 2>conftest.err
ac_status=$?
if test -s conftest.err; then
@@ -1480,14 +1499,15 @@ $as_echo "$ac_try_echo"; } >&5
cat conftest.er1 >&5
mv -f conftest.er1 conftest.err
fi
- $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; } && {
test -z "$ac_c_werror_flag" ||
test ! -s conftest.err
- } && test -s conftest.$ac_objext; then :
+ } && test -s conftest.$ac_objext
+then :
ac_retval=0
-else
- $as_echo "$as_me: failed program was:" >&5
+else $as_nop
+ printf "%s\n" "$as_me: failed program was:" >&5
sed 's/^/| /' conftest.$ac_ext >&5
ac_retval=1
@@ -1503,14 +1523,14 @@ fi
ac_fn_c_try_link ()
{
as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
- rm -f conftest.$ac_objext conftest$ac_exeext
+ rm -f conftest.$ac_objext conftest.beam conftest$ac_exeext
if { { ac_try="$ac_link"
case "(($ac_try" in
*\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
*) ac_try_echo=$ac_try;;
esac
eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
-$as_echo "$ac_try_echo"; } >&5
+printf "%s\n" "$ac_try_echo"; } >&5
(eval "$ac_link") 2>conftest.err
ac_status=$?
if test -s conftest.err; then
@@ -1518,17 +1538,18 @@ $as_echo "$ac_try_echo"; } >&5
cat conftest.er1 >&5
mv -f conftest.er1 conftest.err
fi
- $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; } && {
test -z "$ac_c_werror_flag" ||
test ! -s conftest.err
} && test -s conftest$ac_exeext && {
test "$cross_compiling" = yes ||
test -x conftest$ac_exeext
- }; then :
+ }
+then :
ac_retval=0
-else
- $as_echo "$as_me: failed program was:" >&5
+else $as_nop
+ printf "%s\n" "$as_me: failed program was:" >&5
sed 's/^/| /' conftest.$ac_ext >&5
ac_retval=1
@@ -1555,7 +1576,7 @@ case "(($ac_try" in
*) ac_try_echo=$ac_try;;
esac
eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
-$as_echo "$ac_try_echo"; } >&5
+printf "%s\n" "$ac_try_echo"; } >&5
(eval "$ac_cpp conftest.$ac_ext") 2>conftest.err
ac_status=$?
if test -s conftest.err; then
@@ -1563,14 +1584,15 @@ $as_echo "$ac_try_echo"; } >&5
cat conftest.er1 >&5
mv -f conftest.er1 conftest.err
fi
- $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; } > conftest.i && {
test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
test ! -s conftest.err
- }; then :
+ }
+then :
ac_retval=0
-else
- $as_echo "$as_me: failed program was:" >&5
+else $as_nop
+ printf "%s\n" "$as_me: failed program was:" >&5
sed 's/^/| /' conftest.$ac_ext >&5
ac_retval=1
@@ -1587,72 +1609,32 @@ fi
ac_fn_c_check_header_compile ()
{
as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
-$as_echo_n "checking for $2... " >&6; }
-if eval \${$3+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+printf %s "checking for $2... " >&6; }
+if eval test \${$3+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
$4
#include <$2>
_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
+if ac_fn_c_try_compile "$LINENO"
+then :
eval "$3=yes"
-else
+else $as_nop
eval "$3=no"
fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
fi
eval ac_res=\$$3
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
-$as_echo "$ac_res" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+printf "%s\n" "$ac_res" >&6; }
eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
} # ac_fn_c_check_header_compile
-# ac_fn_c_try_run LINENO
-# ----------------------
-# Try to link conftest.$ac_ext, and return whether this succeeded. Assumes
-# that executables *can* be run.
-ac_fn_c_try_run ()
-{
- as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
- if { { ac_try="$ac_link"
-case "(($ac_try" in
- *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
- *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
-$as_echo "$ac_try_echo"; } >&5
- (eval "$ac_link") 2>&5
- ac_status=$?
- $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
- test $ac_status = 0; } && { ac_try='./conftest$ac_exeext'
- { { case "(($ac_try" in
- *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
- *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
-$as_echo "$ac_try_echo"; } >&5
- (eval "$ac_try") 2>&5
- ac_status=$?
- $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
- test $ac_status = 0; }; }; then :
- ac_retval=0
-else
- $as_echo "$as_me: program exited with status $ac_status" >&5
- $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
- ac_retval=$ac_status
-fi
- rm -rf conftest.dSYM conftest_ipa8_conftest.oo
- eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
- as_fn_set_status $ac_retval
-
-} # ac_fn_c_try_run
-
# ac_fn_c_check_member LINENO AGGR MEMBER VAR INCLUDES
# ----------------------------------------------------
# Tries to find if the field MEMBER exists in type AGGR, after including
@@ -1660,16 +1642,17 @@ fi
ac_fn_c_check_member ()
{
as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2.$3" >&5
-$as_echo_n "checking for $2.$3... " >&6; }
-if eval \${$4+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $2.$3" >&5
+printf %s "checking for $2.$3... " >&6; }
+if eval test \${$4+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
$5
int
-main ()
+main (void)
{
static $2 ac_aggr;
if (ac_aggr.$3)
@@ -1678,14 +1661,15 @@ return 0;
return 0;
}
_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
+if ac_fn_c_try_compile "$LINENO"
+then :
eval "$4=yes"
-else
+else $as_nop
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
$5
int
-main ()
+main (void)
{
static $2 ac_aggr;
if (sizeof ac_aggr.$3)
@@ -1694,116 +1678,93 @@ return 0;
return 0;
}
_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
+if ac_fn_c_try_compile "$LINENO"
+then :
eval "$4=yes"
-else
+else $as_nop
eval "$4=no"
fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
fi
eval ac_res=\$$4
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
-$as_echo "$ac_res" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+printf "%s\n" "$ac_res" >&6; }
eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
} # ac_fn_c_check_member
-# ac_fn_c_check_header_mongrel LINENO HEADER VAR INCLUDES
-# -------------------------------------------------------
-# Tests whether HEADER exists, giving a warning if it cannot be compiled using
-# the include files in INCLUDES and setting the cache variable VAR
-# accordingly.
-ac_fn_c_check_header_mongrel ()
+# ac_fn_c_try_run LINENO
+# ----------------------
+# Try to run conftest.$ac_ext, and return whether this succeeded. Assumes that
+# executables *can* be run.
+ac_fn_c_try_run ()
{
as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
- if eval \${$3+:} false; then :
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
-$as_echo_n "checking for $2... " >&6; }
-if eval \${$3+:} false; then :
- $as_echo_n "(cached) " >&6
-fi
-eval ac_res=\$$3
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
-$as_echo "$ac_res" >&6; }
-else
- # Is the header compilable?
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 usability" >&5
-$as_echo_n "checking $2 usability... " >&6; }
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-$4
-#include <$2>
-_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
- ac_header_compiler=yes
-else
- ac_header_compiler=no
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_compiler" >&5
-$as_echo "$ac_header_compiler" >&6; }
-
-# Is the header present?
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 presence" >&5
-$as_echo_n "checking $2 presence... " >&6; }
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-#include <$2>
-_ACEOF
-if ac_fn_c_try_cpp "$LINENO"; then :
- ac_header_preproc=yes
-else
- ac_header_preproc=no
-fi
-rm -f conftest.err conftest.i conftest.$ac_ext
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5
-$as_echo "$ac_header_preproc" >&6; }
-
-# So? What about this header?
-case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in #((
- yes:no: )
- { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&5
-$as_echo "$as_me: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&2;}
- { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5
-$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;}
- ;;
- no:yes:* )
- { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: present but cannot be compiled" >&5
-$as_echo "$as_me: WARNING: $2: present but cannot be compiled" >&2;}
- { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: check for missing prerequisite headers?" >&5
-$as_echo "$as_me: WARNING: $2: check for missing prerequisite headers?" >&2;}
- { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: see the Autoconf documentation" >&5
-$as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;}
- { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&5
-$as_echo "$as_me: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&2;}
- { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5
-$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;}
- ;;
+ if { { ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
esac
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
-$as_echo_n "checking for $2... " >&6; }
-if eval \${$3+:} false; then :
- $as_echo_n "(cached) " >&6
-else
- eval "$3=\$ac_header_compiler"
-fi
-eval ac_res=\$$3
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
-$as_echo "$ac_res" >&6; }
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+printf "%s\n" "$ac_try_echo"; } >&5
+ (eval "$ac_link") 2>&5
+ ac_status=$?
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } && { ac_try='./conftest$ac_exeext'
+ { { case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+printf "%s\n" "$ac_try_echo"; } >&5
+ (eval "$ac_try") 2>&5
+ ac_status=$?
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; }
+then :
+ ac_retval=0
+else $as_nop
+ printf "%s\n" "$as_me: program exited with status $ac_status" >&5
+ printf "%s\n" "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_retval=$ac_status
fi
+ rm -rf conftest.dSYM conftest_ipa8_conftest.oo
eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+ as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_run
+ac_configure_args_raw=
+for ac_arg
+do
+ case $ac_arg in
+ *\'*)
+ ac_arg=`printf "%s\n" "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ esac
+ as_fn_append ac_configure_args_raw " '$ac_arg'"
+done
+
+case $ac_configure_args_raw in
+ *$as_nl*)
+ ac_safe_unquote= ;;
+ *)
+ ac_unsafe_z='|&;<>()$`\\"*?[ '' ' # This string ends in space, tab.
+ ac_unsafe_a="$ac_unsafe_z#~"
+ ac_safe_unquote="s/ '\\([^$ac_unsafe_a][^$ac_unsafe_z]*\\)'/ \\1/g"
+ ac_configure_args_raw=` printf "%s\n" "$ac_configure_args_raw" | sed "$ac_safe_unquote"`;;
+esac
-} # ac_fn_c_check_header_mongrel
cat >config.log <<_ACEOF
This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake.
It was created by $as_me, which was
-generated by GNU Autoconf 2.69. Invocation command line was
+generated by GNU Autoconf 2.69e. Invocation command line was
- $ $0 $@
+ $ $0$ac_configure_args_raw
_ACEOF
exec 5>>config.log
@@ -1836,8 +1797,12 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
- $as_echo "PATH: $as_dir"
+ case $as_dir in #(((
+ '') as_dir=./ ;;
+ */) ;;
+ *) as_dir=$as_dir/ ;;
+ esac
+ printf "%s\n" "PATH: $as_dir"
done
IFS=$as_save_IFS
@@ -1872,7 +1837,7 @@ do
| -silent | --silent | --silen | --sile | --sil)
continue ;;
*\'*)
- ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ ac_arg=`printf "%s\n" "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;;
esac
case $ac_pass in
1) as_fn_append ac_configure_args0 " '$ac_arg'" ;;
@@ -1907,11 +1872,13 @@ done
# WARNING: Use '\'' to represent an apostrophe within the trap.
# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug.
trap 'exit_status=$?
+ # Sanitize IFS.
+ IFS=" "" $as_nl"
# Save into config.log some information that might help in debugging.
{
echo
- $as_echo "## ---------------- ##
+ printf "%s\n" "## ---------------- ##
## Cache variables. ##
## ---------------- ##"
echo
@@ -1922,8 +1889,8 @@ trap 'exit_status=$?
case $ac_val in #(
*${as_nl}*)
case $ac_var in #(
- *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
-$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
+ *_cv_*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
+printf "%s\n" "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
esac
case $ac_var in #(
_ | IFS | as_nl) ;; #(
@@ -1947,7 +1914,7 @@ $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
)
echo
- $as_echo "## ----------------- ##
+ printf "%s\n" "## ----------------- ##
## Output variables. ##
## ----------------- ##"
echo
@@ -1955,14 +1922,14 @@ $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
do
eval ac_val=\$$ac_var
case $ac_val in
- *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+ *\'\''*) ac_val=`printf "%s\n" "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
esac
- $as_echo "$ac_var='\''$ac_val'\''"
+ printf "%s\n" "$ac_var='\''$ac_val'\''"
done | sort
echo
if test -n "$ac_subst_files"; then
- $as_echo "## ------------------- ##
+ printf "%s\n" "## ------------------- ##
## File substitutions. ##
## ------------------- ##"
echo
@@ -1970,15 +1937,15 @@ $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
do
eval ac_val=\$$ac_var
case $ac_val in
- *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+ *\'\''*) ac_val=`printf "%s\n" "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
esac
- $as_echo "$ac_var='\''$ac_val'\''"
+ printf "%s\n" "$ac_var='\''$ac_val'\''"
done | sort
echo
fi
if test -s confdefs.h; then
- $as_echo "## ----------- ##
+ printf "%s\n" "## ----------- ##
## confdefs.h. ##
## ----------- ##"
echo
@@ -1986,8 +1953,8 @@ $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
echo
fi
test "$ac_signal" != 0 &&
- $as_echo "$as_me: caught signal $ac_signal"
- $as_echo "$as_me: exit $exit_status"
+ printf "%s\n" "$as_me: caught signal $ac_signal"
+ printf "%s\n" "$as_me: exit $exit_status"
} >&5
rm -f core *.core core.conftest.* &&
rm -f -r conftest* confdefs* conf$$* $ac_clean_files &&
@@ -2001,63 +1968,48 @@ ac_signal=0
# confdefs.h avoids OS command line length limits that DEFS can exceed.
rm -f -r conftest* confdefs.h
-$as_echo "/* confdefs.h */" > confdefs.h
+printf "%s\n" "/* confdefs.h */" > confdefs.h
# Predefined preprocessor variables.
-cat >>confdefs.h <<_ACEOF
-#define PACKAGE_NAME "$PACKAGE_NAME"
-_ACEOF
+printf "%s\n" "#define PACKAGE_NAME \"$PACKAGE_NAME\"" >>confdefs.h
-cat >>confdefs.h <<_ACEOF
-#define PACKAGE_TARNAME "$PACKAGE_TARNAME"
-_ACEOF
+printf "%s\n" "#define PACKAGE_TARNAME \"$PACKAGE_TARNAME\"" >>confdefs.h
-cat >>confdefs.h <<_ACEOF
-#define PACKAGE_VERSION "$PACKAGE_VERSION"
-_ACEOF
+printf "%s\n" "#define PACKAGE_VERSION \"$PACKAGE_VERSION\"" >>confdefs.h
-cat >>confdefs.h <<_ACEOF
-#define PACKAGE_STRING "$PACKAGE_STRING"
-_ACEOF
+printf "%s\n" "#define PACKAGE_STRING \"$PACKAGE_STRING\"" >>confdefs.h
-cat >>confdefs.h <<_ACEOF
-#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT"
-_ACEOF
+printf "%s\n" "#define PACKAGE_BUGREPORT \"$PACKAGE_BUGREPORT\"" >>confdefs.h
-cat >>confdefs.h <<_ACEOF
-#define PACKAGE_URL "$PACKAGE_URL"
-_ACEOF
+printf "%s\n" "#define PACKAGE_URL \"$PACKAGE_URL\"" >>confdefs.h
# Let the site file select an alternate cache file if it wants to.
# Prefer an explicitly selected file to automatically selected ones.
-ac_site_file1=NONE
-ac_site_file2=NONE
if test -n "$CONFIG_SITE"; then
- # We do not want a PATH search for config.site.
- case $CONFIG_SITE in #((
- -*) ac_site_file1=./$CONFIG_SITE;;
- */*) ac_site_file1=$CONFIG_SITE;;
- *) ac_site_file1=./$CONFIG_SITE;;
- esac
+ ac_site_files="$CONFIG_SITE"
elif test "x$prefix" != xNONE; then
- ac_site_file1=$prefix/share/config.site
- ac_site_file2=$prefix/etc/config.site
+ ac_site_files="$prefix/share/config.site $prefix/etc/config.site"
else
- ac_site_file1=$ac_default_prefix/share/config.site
- ac_site_file2=$ac_default_prefix/etc/config.site
+ ac_site_files="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site"
fi
-for ac_site_file in "$ac_site_file1" "$ac_site_file2"
+
+for ac_site_file in $ac_site_files
do
- test "x$ac_site_file" = xNONE && continue
- if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5
-$as_echo "$as_me: loading site script $ac_site_file" >&6;}
+ case $ac_site_file in #(
+ */*) :
+ ;; #(
+ *) :
+ ac_site_file=./$ac_site_file ;;
+esac
+ if test -f "$ac_site_file" && test -r "$ac_site_file"; then
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5
+printf "%s\n" "$as_me: loading site script $ac_site_file" >&6;}
sed 's/^/| /' "$ac_site_file" >&5
. "$ac_site_file" \
- || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
-$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+ || { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;}
as_fn_error $? "failed to load site script $ac_site_file
See \`config.log' for more details" "$LINENO" 5; }
fi
@@ -2067,21 +2019,125 @@ if test -r "$cache_file"; then
# Some versions of bash will fail to source /dev/null (special files
# actually), so we avoid doing that. DJGPP emulates it as a regular file.
if test /dev/null != "$cache_file" && test -f "$cache_file"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5
-$as_echo "$as_me: loading cache $cache_file" >&6;}
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5
+printf "%s\n" "$as_me: loading cache $cache_file" >&6;}
case $cache_file in
[\\/]* | ?:[\\/]* ) . "$cache_file";;
*) . "./$cache_file";;
esac
fi
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5
-$as_echo "$as_me: creating cache $cache_file" >&6;}
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5
+printf "%s\n" "$as_me: creating cache $cache_file" >&6;}
>$cache_file
fi
-as_fn_append ac_header_list " alloca.h"
-as_fn_append ac_header_list " syslog.h"
+as_fn_append ac_header_c_list " sys/types.h sys_types_h HAVE_SYS_TYPES_H"
+as_fn_append ac_header_c_list " sys/stat.h sys_stat_h HAVE_SYS_STAT_H"
+as_fn_append ac_header_c_list " strings.h strings_h HAVE_STRINGS_H"
+as_fn_append ac_header_c_list " inttypes.h inttypes_h HAVE_INTTYPES_H"
+as_fn_append ac_header_c_list " stdint.h stdint_h HAVE_STDINT_H"
+as_fn_append ac_header_c_list " unistd.h unistd_h HAVE_UNISTD_H"
+as_fn_append ac_header_c_list " alloca.h alloca_h HAVE_ALLOCA_H"
+as_fn_append ac_header_c_list " syslog.h syslog_h HAVE_SYSLOG_H"
+
+# Auxiliary files required by this configure script.
+ac_aux_files="install-sh config.guess config.sub"
+
+# Locations in which to look for auxiliary files.
+ac_aux_dir_candidates="${srcdir}/tools"
+
+# Search for a directory containing all of the required auxiliary files,
+# $ac_aux_files, from the $PATH-style list $ac_aux_dir_candidates.
+# If we don't find one directory that contains all the files we need,
+# we report the set of missing files from the *first* directory in
+# $ac_aux_dir_candidates and give up.
+ac_missing_aux_files=""
+ac_first_candidate=:
+printf "%s\n" "$as_me:${as_lineno-$LINENO}: looking for aux files: $ac_aux_files" >&5
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+as_found=false
+for as_dir in $ac_aux_dir_candidates
+do
+ IFS=$as_save_IFS
+ case $as_dir in #(((
+ '') as_dir=./ ;;
+ */) ;;
+ *) as_dir=$as_dir/ ;;
+ esac
+ as_found=:
+
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: trying $as_dir" >&5
+ ac_aux_dir_found=yes
+ ac_install_sh=
+ for ac_aux in $ac_aux_files
+ do
+ # As a special case, if "install-sh" is required, that requirement
+ # can be satisfied by any of "install-sh", "install.sh", or "shtool",
+ # and $ac_install_sh is set appropriately for whichever one is found.
+ if test x"$ac_aux" = x"install-sh"
+ then
+ if test -f "${as_dir}install-sh"; then
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: ${as_dir}install-sh found" >&5
+ ac_install_sh="${as_dir}install-sh -c"
+ elif test -f "${as_dir}install.sh"; then
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: ${as_dir}install.sh found" >&5
+ ac_install_sh="${as_dir}install.sh -c"
+ elif test -f "${as_dir}shtool"; then
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: ${as_dir}shtool found" >&5
+ ac_install_sh="${as_dir}shtool install -c"
+ else
+ ac_aux_dir_found=no
+ if $ac_first_candidate; then
+ ac_missing_aux_files="${ac_missing_aux_files} install-sh"
+ else
+ break
+ fi
+ fi
+ else
+ if test -f "${as_dir}${ac_aux}"; then
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: ${as_dir}${ac_aux} found" >&5
+ else
+ ac_aux_dir_found=no
+ if $ac_first_candidate; then
+ ac_missing_aux_files="${ac_missing_aux_files} ${ac_aux}"
+ else
+ break
+ fi
+ fi
+ fi
+ done
+ if test "$ac_aux_dir_found" = yes; then
+ ac_aux_dir="$as_dir"
+ break
+ fi
+ ac_first_candidate=false
+
+ as_found=false
+done
+IFS=$as_save_IFS
+if $as_found
+then :
+
+else $as_nop
+ as_fn_error $? "cannot find required auxiliary files:$ac_missing_aux_files" "$LINENO" 5
+fi
+
+
+# These three variables are undocumented and unsupported,
+# and are intended to be withdrawn in a future Autoconf release.
+# They can cause serious problems if a builder's source tree is in a directory
+# whose full name contains unusual characters.
+if test -f "${ac_aux_dir}config.guess"; then
+ ac_config_guess="$SHELL ${ac_aux_dir}config.guess"
+fi
+if test -f "${ac_aux_dir}config.sub"; then
+ ac_config_sub="$SHELL ${ac_aux_dir}config.sub"
+fi
+if test -f "$ac_aux_dir/configure"; then
+ ac_configure="$SHELL ${ac_aux_dir}configure"
+fi
+
# Check that the precious variables saved in the cache have kept the same
# value.
ac_cache_corrupted=false
@@ -2092,12 +2148,12 @@ for ac_var in $ac_precious_vars; do
eval ac_new_val=\$ac_env_${ac_var}_value
case $ac_old_set,$ac_new_set in
set,)
- { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5
-$as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;}
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5
+printf "%s\n" "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;}
ac_cache_corrupted=: ;;
,set)
- { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5
-$as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;}
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5
+printf "%s\n" "$as_me: error: \`$ac_var' was not set in the previous run" >&2;}
ac_cache_corrupted=: ;;
,);;
*)
@@ -2106,24 +2162,24 @@ $as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;}
ac_old_val_w=`echo x $ac_old_val`
ac_new_val_w=`echo x $ac_new_val`
if test "$ac_old_val_w" != "$ac_new_val_w"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5
-$as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;}
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5
+printf "%s\n" "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;}
ac_cache_corrupted=:
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5
-$as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;}
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5
+printf "%s\n" "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;}
eval $ac_var=\$ac_old_val
fi
- { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5
-$as_echo "$as_me: former value: \`$ac_old_val'" >&2;}
- { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5
-$as_echo "$as_me: current value: \`$ac_new_val'" >&2;}
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5
+printf "%s\n" "$as_me: former value: \`$ac_old_val'" >&2;}
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5
+printf "%s\n" "$as_me: current value: \`$ac_new_val'" >&2;}
fi;;
esac
# Pass precious variables to config.status.
if test "$ac_new_set" = set; then
case $ac_new_val in
- *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;;
+ *\'*) ac_arg=$ac_var=`printf "%s\n" "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;;
*) ac_arg=$ac_var=$ac_new_val ;;
esac
case " $ac_configure_args " in
@@ -2133,11 +2189,12 @@ $as_echo "$as_me: current value: \`$ac_new_val'" >&2;}
fi
done
if $ac_cache_corrupted; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
-$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
- { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5
-$as_echo "$as_me: error: changes in the environment can compromise the build" >&2;}
- as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;}
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5
+printf "%s\n" "$as_me: error: changes in the environment can compromise the build" >&2;}
+ as_fn_error $? "run \`${MAKE-make} distclean' and/or \`rm $cache_file'
+ and start over" "$LINENO" 5
fi
## -------------------- ##
## Main body of script. ##
@@ -2151,94 +2208,83 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu
-ac_aux_dir=
-for ac_dir in tools "$srcdir"/tools; do
- if test -f "$ac_dir/install-sh"; then
- ac_aux_dir=$ac_dir
- ac_install_sh="$ac_aux_dir/install-sh -c"
- break
- elif test -f "$ac_dir/install.sh"; then
- ac_aux_dir=$ac_dir
- ac_install_sh="$ac_aux_dir/install.sh -c"
- break
- elif test -f "$ac_dir/shtool"; then
- ac_aux_dir=$ac_dir
- ac_install_sh="$ac_aux_dir/shtool install -c"
- break
- fi
-done
-if test -z "$ac_aux_dir"; then
- as_fn_error $? "cannot find install-sh, install.sh, or shtool in tools \"$srcdir\"/tools" "$LINENO" 5
-fi
-
-# These three variables are undocumented and unsupported,
-# and are intended to be withdrawn in a future Autoconf release.
-# They can cause serious problems if a builder's source tree is in a directory
-# whose full name contains unusual characters.
-ac_config_guess="$SHELL $ac_aux_dir/config.guess" # Please don't use this var.
-ac_config_sub="$SHELL $ac_aux_dir/config.sub" # Please don't use this var.
-ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var.
-
# Check whether --enable-client was given.
-if test "${enable_client+set}" = set; then :
+if test ${enable_client+y}
+then :
enableval=$enable_client;
-else
+else $as_nop
enable_client=yes
fi
# Check whether --enable-debug was given.
-if test "${enable_debug+set}" = set; then :
+if test ${enable_debug+y}
+then :
enableval=$enable_debug;
-else
+else $as_nop
enable_debug=no
fi
# Check whether --enable-debug-generated was given.
-if test "${enable_debug_generated+set}" = set; then :
+if test ${enable_debug_generated+y}
+then :
enableval=$enable_debug_generated;
-else
+else $as_nop
enable_debug_generated=no
fi
+# Check whether --enable-debug-expensive was given.
+if test ${enable_debug_expensive+y}
+then :
+ enableval=$enable_debug_expensive;
+else $as_nop
+ enable_debug_expensive=no
+
+fi
+
+
# Check whether --enable-memcheck was given.
-if test "${enable_memcheck+set}" = set; then :
+if test ${enable_memcheck+y}
+then :
enableval=$enable_memcheck;
-else
+else $as_nop
enable_memcheck=yes
fi
# Check whether --enable-pthreads was given.
-if test "${enable_pthreads+set}" = set; then :
+if test ${enable_pthreads+y}
+then :
enableval=$enable_pthreads;
-else
+else $as_nop
enable_pthreads=try
fi
# Check whether --enable-libssh was given.
-if test "${enable_libssh+set}" = set; then :
+if test ${enable_libssh+y}
+then :
enableval=$enable_libssh;
-else
+else $as_nop
enable_libssh=try
fi
# Check whether --enable-mpls-kernel was given.
-if test "${enable_mpls_kernel+set}" = set; then :
+if test ${enable_mpls_kernel+y}
+then :
enableval=$enable_mpls_kernel;
-else
+else $as_nop
enable_mpls_kernel=try
fi
@@ -2246,9 +2292,10 @@ fi
# Check whether --with-protocols was given.
-if test "${with_protocols+set}" = set; then :
+if test ${with_protocols+y}
+then :
withval=$with_protocols;
-else
+else $as_nop
with_protocols="all"
fi
@@ -2256,14 +2303,16 @@ fi
# Check whether --with-sysconfig was given.
-if test "${with_sysconfig+set}" = set; then :
+if test ${with_sysconfig+y}
+then :
withval=$with_sysconfig;
fi
# Check whether --with-runtimedir was given.
-if test "${with_runtimedir+set}" = set; then :
+if test ${with_runtimedir+y}
+then :
withval=$with_runtimedir; runstatedir="$with_runtimedir"
fi
@@ -2271,7 +2320,8 @@ fi
# Check whether --with-iproutedir was given.
-if test "${with_iproutedir+set}" = set; then :
+if test ${with_iproutedir+y}
+then :
withval=$with_iproutedir; given_iproutedir="yes"
fi
@@ -2281,6 +2331,9 @@ fi
+if test "$enable_debug_expensive" = yes; then
+ enable_debug=yes
+fi
if test "$srcdir" = . ; then
# Building in current directory => create obj directory holding all objects
@@ -2297,7 +2350,8 @@ exedir=.
# Workaround for older Autoconfs that do not define runstatedir
-if test -z "${runstatedir}"; then :
+if test -z "${runstatedir}"
+then :
runstatedir='${localstatedir}/run'
fi
@@ -2316,11 +2370,12 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu
if test -n "$ac_tool_prefix"; then
# Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args.
set dummy ${ac_tool_prefix}gcc; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_CC+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+printf %s "checking for $ac_word... " >&6; }
+if test ${ac_cv_prog_CC+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
if test -n "$CC"; then
ac_cv_prog_CC="$CC" # Let the user override the test.
else
@@ -2328,11 +2383,15 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
+ case $as_dir in #(((
+ '') as_dir=./ ;;
+ */) ;;
+ *) as_dir=$as_dir/ ;;
+ esac
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then
ac_cv_prog_CC="${ac_tool_prefix}gcc"
- $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5
break 2
fi
done
@@ -2343,11 +2402,11 @@ fi
fi
CC=$ac_cv_prog_CC
if test -n "$CC"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
-$as_echo "$CC" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+printf "%s\n" "$CC" >&6; }
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
fi
@@ -2356,11 +2415,12 @@ if test -z "$ac_cv_prog_CC"; then
ac_ct_CC=$CC
# Extract the first word of "gcc", so it can be a program name with args.
set dummy gcc; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_ac_ct_CC+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+printf %s "checking for $ac_word... " >&6; }
+if test ${ac_cv_prog_ac_ct_CC+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
if test -n "$ac_ct_CC"; then
ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
else
@@ -2368,11 +2428,15 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
+ case $as_dir in #(((
+ '') as_dir=./ ;;
+ */) ;;
+ *) as_dir=$as_dir/ ;;
+ esac
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then
ac_cv_prog_ac_ct_CC="gcc"
- $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5
break 2
fi
done
@@ -2383,11 +2447,11 @@ fi
fi
ac_ct_CC=$ac_cv_prog_ac_ct_CC
if test -n "$ac_ct_CC"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
-$as_echo "$ac_ct_CC" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
+printf "%s\n" "$ac_ct_CC" >&6; }
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
fi
if test "x$ac_ct_CC" = x; then
@@ -2395,8 +2459,8 @@ fi
else
case $cross_compiling:$ac_tool_warned in
yes:)
-{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
-$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
ac_tool_warned=yes ;;
esac
CC=$ac_ct_CC
@@ -2409,11 +2473,12 @@ if test -z "$CC"; then
if test -n "$ac_tool_prefix"; then
# Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args.
set dummy ${ac_tool_prefix}cc; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_CC+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+printf %s "checking for $ac_word... " >&6; }
+if test ${ac_cv_prog_CC+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
if test -n "$CC"; then
ac_cv_prog_CC="$CC" # Let the user override the test.
else
@@ -2421,11 +2486,15 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
+ case $as_dir in #(((
+ '') as_dir=./ ;;
+ */) ;;
+ *) as_dir=$as_dir/ ;;
+ esac
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then
ac_cv_prog_CC="${ac_tool_prefix}cc"
- $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5
break 2
fi
done
@@ -2436,11 +2505,11 @@ fi
fi
CC=$ac_cv_prog_CC
if test -n "$CC"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
-$as_echo "$CC" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+printf "%s\n" "$CC" >&6; }
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
fi
@@ -2449,11 +2518,12 @@ fi
if test -z "$CC"; then
# Extract the first word of "cc", so it can be a program name with args.
set dummy cc; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_CC+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+printf %s "checking for $ac_word... " >&6; }
+if test ${ac_cv_prog_CC+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
if test -n "$CC"; then
ac_cv_prog_CC="$CC" # Let the user override the test.
else
@@ -2462,15 +2532,19 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
+ case $as_dir in #(((
+ '') as_dir=./ ;;
+ */) ;;
+ *) as_dir=$as_dir/ ;;
+ esac
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
- if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then
+ if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then
+ if test "$as_dir$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then
ac_prog_rejected=yes
continue
fi
ac_cv_prog_CC="cc"
- $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5
break 2
fi
done
@@ -2486,18 +2560,18 @@ if test $ac_prog_rejected = yes; then
# However, it has the same basename, so the bogon will be chosen
# first if we set CC to just the basename; use the full file name.
shift
- ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@"
+ ac_cv_prog_CC="$as_dir$ac_word${1+' '}$@"
fi
fi
fi
fi
CC=$ac_cv_prog_CC
if test -n "$CC"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
-$as_echo "$CC" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+printf "%s\n" "$CC" >&6; }
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
fi
@@ -2508,11 +2582,12 @@ if test -z "$CC"; then
do
# Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
set dummy $ac_tool_prefix$ac_prog; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_CC+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+printf %s "checking for $ac_word... " >&6; }
+if test ${ac_cv_prog_CC+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
if test -n "$CC"; then
ac_cv_prog_CC="$CC" # Let the user override the test.
else
@@ -2520,11 +2595,15 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
+ case $as_dir in #(((
+ '') as_dir=./ ;;
+ */) ;;
+ *) as_dir=$as_dir/ ;;
+ esac
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then
ac_cv_prog_CC="$ac_tool_prefix$ac_prog"
- $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5
break 2
fi
done
@@ -2535,11 +2614,11 @@ fi
fi
CC=$ac_cv_prog_CC
if test -n "$CC"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
-$as_echo "$CC" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+printf "%s\n" "$CC" >&6; }
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
fi
@@ -2552,11 +2631,12 @@ if test -z "$CC"; then
do
# Extract the first word of "$ac_prog", so it can be a program name with args.
set dummy $ac_prog; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_ac_ct_CC+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+printf %s "checking for $ac_word... " >&6; }
+if test ${ac_cv_prog_ac_ct_CC+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
if test -n "$ac_ct_CC"; then
ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
else
@@ -2564,11 +2644,15 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
+ case $as_dir in #(((
+ '') as_dir=./ ;;
+ */) ;;
+ *) as_dir=$as_dir/ ;;
+ esac
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then
ac_cv_prog_ac_ct_CC="$ac_prog"
- $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5
break 2
fi
done
@@ -2579,11 +2663,11 @@ fi
fi
ac_ct_CC=$ac_cv_prog_ac_ct_CC
if test -n "$ac_ct_CC"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
-$as_echo "$ac_ct_CC" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
+printf "%s\n" "$ac_ct_CC" >&6; }
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
fi
@@ -2595,8 +2679,8 @@ done
else
case $cross_compiling:$ac_tool_warned in
yes:)
-{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
-$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
ac_tool_warned=yes ;;
esac
CC=$ac_ct_CC
@@ -2604,25 +2688,129 @@ esac
fi
fi
+if test -z "$CC"; then
+ if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}clang", so it can be a program name with args.
+set dummy ${ac_tool_prefix}clang; ac_word=$2
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+printf %s "checking for $ac_word... " >&6; }
+if test ${ac_cv_prog_CC+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ case $as_dir in #(((
+ '') as_dir=./ ;;
+ */) ;;
+ *) as_dir=$as_dir/ ;;
+ esac
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then
+ ac_cv_prog_CC="${ac_tool_prefix}clang"
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+printf "%s\n" "$CC" >&6; }
+else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+fi
-test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
-$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+
+fi
+if test -z "$ac_cv_prog_CC"; then
+ ac_ct_CC=$CC
+ # Extract the first word of "clang", so it can be a program name with args.
+set dummy clang; ac_word=$2
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+printf %s "checking for $ac_word... " >&6; }
+if test ${ac_cv_prog_ac_ct_CC+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
+ if test -n "$ac_ct_CC"; then
+ ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ case $as_dir in #(((
+ '') as_dir=./ ;;
+ */) ;;
+ *) as_dir=$as_dir/ ;;
+ esac
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_CC="clang"
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
+printf "%s\n" "$ac_ct_CC" >&6; }
+else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+fi
+
+ if test "x$ac_ct_CC" = x; then
+ CC=""
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ CC=$ac_ct_CC
+ fi
+else
+ CC="$ac_cv_prog_CC"
+fi
+
+fi
+
+
+test -z "$CC" && { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;}
as_fn_error $? "no acceptable C compiler found in \$PATH
See \`config.log' for more details" "$LINENO" 5; }
# Provide some information about the compiler.
-$as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5
+printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5
set X $ac_compile
ac_compiler=$2
-for ac_option in --version -v -V -qversion; do
+for ac_option in --version -v -V -qversion -version; do
{ { ac_try="$ac_compiler $ac_option >&5"
case "(($ac_try" in
*\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
*) ac_try_echo=$ac_try;;
esac
eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
-$as_echo "$ac_try_echo"; } >&5
+printf "%s\n" "$ac_try_echo"; } >&5
(eval "$ac_compiler $ac_option >&5") 2>conftest.err
ac_status=$?
if test -s conftest.err; then
@@ -2632,7 +2820,7 @@ $as_echo "$ac_try_echo"; } >&5
cat conftest.er1 >&5
fi
rm -f conftest.er1 conftest.err
- $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; }
done
@@ -2640,7 +2828,7 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
int
-main ()
+main (void)
{
;
@@ -2652,9 +2840,9 @@ ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out"
# Try to create an executable without -o first, disregard a.out.
# It will help us diagnose broken compilers, and finding out an intuition
# of exeext.
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5
-$as_echo_n "checking whether the C compiler works... " >&6; }
-ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'`
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5
+printf %s "checking whether the C compiler works... " >&6; }
+ac_link_default=`printf "%s\n" "$ac_link" | sed 's/ -o *conftest[^ ]*//'`
# The possible output files:
ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*"
@@ -2675,11 +2863,12 @@ case "(($ac_try" in
*) ac_try_echo=$ac_try;;
esac
eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
-$as_echo "$ac_try_echo"; } >&5
+printf "%s\n" "$ac_try_echo"; } >&5
(eval "$ac_link_default") 2>&5
ac_status=$?
- $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
- test $ac_status = 0; }; then :
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }
+then :
# Autoconf-2.13 could set the ac_cv_exeext variable to `no'.
# So ignore a value of `no', otherwise this would lead to `EXEEXT = no'
# in a Makefile. We should not override ac_cv_exeext if it was cached,
@@ -2696,7 +2885,7 @@ do
# certainly right.
break;;
*.* )
- if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no;
+ if test ${ac_cv_exeext+y} && test "$ac_cv_exeext" != no;
then :; else
ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
fi
@@ -2712,44 +2901,46 @@ do
done
test "$ac_cv_exeext" = no && ac_cv_exeext=
-else
+else $as_nop
ac_file=''
fi
-if test -z "$ac_file"; then :
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-$as_echo "$as_me: failed program was:" >&5
+if test -z "$ac_file"
+then :
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+printf "%s\n" "$as_me: failed program was:" >&5
sed 's/^/| /' conftest.$ac_ext >&5
-{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
-$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+{ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;}
as_fn_error 77 "C compiler cannot create executables
See \`config.log' for more details" "$LINENO" 5; }
-else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5
-$as_echo_n "checking for C compiler default output file name... " >&6; }
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5
-$as_echo "$ac_file" >&6; }
+else $as_nop
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
+fi
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5
+printf %s "checking for C compiler default output file name... " >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5
+printf "%s\n" "$ac_file" >&6; }
ac_exeext=$ac_cv_exeext
rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out
ac_clean_files=$ac_clean_files_save
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5
-$as_echo_n "checking for suffix of executables... " >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5
+printf %s "checking for suffix of executables... " >&6; }
if { { ac_try="$ac_link"
case "(($ac_try" in
*\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
*) ac_try_echo=$ac_try;;
esac
eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
-$as_echo "$ac_try_echo"; } >&5
+printf "%s\n" "$ac_try_echo"; } >&5
(eval "$ac_link") 2>&5
ac_status=$?
- $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
- test $ac_status = 0; }; then :
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }
+then :
# If both `conftest.exe' and `conftest' are `present' (well, observable)
# catch `conftest.exe'. For instance with Cygwin, `ls conftest' will
# work properly (i.e., refer to `conftest.exe'), while it won't with
@@ -2763,15 +2954,15 @@ for ac_file in conftest.exe conftest conftest.*; do
* ) break;;
esac
done
-else
- { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
-$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+else $as_nop
+ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;}
as_fn_error $? "cannot compute suffix of executables: cannot compile and link
See \`config.log' for more details" "$LINENO" 5; }
fi
rm -f conftest conftest$ac_cv_exeext
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5
-$as_echo "$ac_cv_exeext" >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5
+printf "%s\n" "$ac_cv_exeext" >&6; }
rm -f conftest.$ac_ext
EXEEXT=$ac_cv_exeext
@@ -2780,7 +2971,7 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <stdio.h>
int
-main ()
+main (void)
{
FILE *f = fopen ("conftest.out", "w");
return ferror (f) || fclose (f) != 0;
@@ -2792,8 +2983,8 @@ _ACEOF
ac_clean_files="$ac_clean_files conftest.out"
# Check that the compiler produces executables we can run. If not, either
# the compiler is broken, or we cross compile.
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5
-$as_echo_n "checking whether we are cross compiling... " >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5
+printf %s "checking whether we are cross compiling... " >&6; }
if test "$cross_compiling" != yes; then
{ { ac_try="$ac_link"
case "(($ac_try" in
@@ -2801,10 +2992,10 @@ case "(($ac_try" in
*) ac_try_echo=$ac_try;;
esac
eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
-$as_echo "$ac_try_echo"; } >&5
+printf "%s\n" "$ac_try_echo"; } >&5
(eval "$ac_link") 2>&5
ac_status=$?
- $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; }
if { ac_try='./conftest$ac_cv_exeext'
{ { case "(($ac_try" in
@@ -2812,39 +3003,40 @@ $as_echo "$ac_try_echo"; } >&5
*) ac_try_echo=$ac_try;;
esac
eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
-$as_echo "$ac_try_echo"; } >&5
+printf "%s\n" "$ac_try_echo"; } >&5
(eval "$ac_try") 2>&5
ac_status=$?
- $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; }; }; then
cross_compiling=no
else
if test "$cross_compiling" = maybe; then
cross_compiling=yes
else
- { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
-$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
-as_fn_error $? "cannot run C compiled programs.
+ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error 77 "cannot run C compiled programs.
If you meant to cross compile, use \`--host'.
See \`config.log' for more details" "$LINENO" 5; }
fi
fi
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5
-$as_echo "$cross_compiling" >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5
+printf "%s\n" "$cross_compiling" >&6; }
rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out
ac_clean_files=$ac_clean_files_save
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5
-$as_echo_n "checking for suffix of object files... " >&6; }
-if ${ac_cv_objext+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5
+printf %s "checking for suffix of object files... " >&6; }
+if test ${ac_cv_objext+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
int
-main ()
+main (void)
{
;
@@ -2858,11 +3050,12 @@ case "(($ac_try" in
*) ac_try_echo=$ac_try;;
esac
eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
-$as_echo "$ac_try_echo"; } >&5
+printf "%s\n" "$ac_try_echo"; } >&5
(eval "$ac_compile") 2>&5
ac_status=$?
- $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
- test $ac_status = 0; }; then :
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }
+then :
for ac_file in conftest.o conftest.obj conftest.*; do
test -f "$ac_file" || continue;
case $ac_file in
@@ -2871,31 +3064,32 @@ $as_echo "$ac_try_echo"; } >&5
break;;
esac
done
-else
- $as_echo "$as_me: failed program was:" >&5
+else $as_nop
+ printf "%s\n" "$as_me: failed program was:" >&5
sed 's/^/| /' conftest.$ac_ext >&5
-{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
-$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+{ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;}
as_fn_error $? "cannot compute suffix of object files: cannot compile
See \`config.log' for more details" "$LINENO" 5; }
fi
rm -f conftest.$ac_cv_objext conftest.$ac_ext
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5
-$as_echo "$ac_cv_objext" >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5
+printf "%s\n" "$ac_cv_objext" >&6; }
OBJEXT=$ac_cv_objext
ac_objext=$OBJEXT
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5
-$as_echo_n "checking whether we are using the GNU C compiler... " >&6; }
-if ${ac_cv_c_compiler_gnu+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports GNU C" >&5
+printf %s "checking whether the compiler supports GNU C... " >&6; }
+if test ${ac_cv_c_compiler_gnu+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
int
-main ()
+main (void)
{
#ifndef __GNUC__
choke me
@@ -2905,29 +3099,33 @@ main ()
return 0;
}
_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
+if ac_fn_c_try_compile "$LINENO"
+then :
ac_compiler_gnu=yes
-else
+else $as_nop
ac_compiler_gnu=no
fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
ac_cv_c_compiler_gnu=$ac_compiler_gnu
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5
-$as_echo "$ac_cv_c_compiler_gnu" >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5
+printf "%s\n" "$ac_cv_c_compiler_gnu" >&6; }
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
if test $ac_compiler_gnu = yes; then
GCC=yes
else
GCC=
fi
-ac_test_CFLAGS=${CFLAGS+set}
+ac_test_CFLAGS=${CFLAGS+y}
ac_save_CFLAGS=$CFLAGS
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5
-$as_echo_n "checking whether $CC accepts -g... " >&6; }
-if ${ac_cv_prog_cc_g+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5
+printf %s "checking whether $CC accepts -g... " >&6; }
+if test ${ac_cv_prog_cc_g+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
ac_save_c_werror_flag=$ac_c_werror_flag
ac_c_werror_flag=yes
ac_cv_prog_cc_g=no
@@ -2936,57 +3134,60 @@ else
/* end confdefs.h. */
int
-main ()
+main (void)
{
;
return 0;
}
_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
+if ac_fn_c_try_compile "$LINENO"
+then :
ac_cv_prog_cc_g=yes
-else
+else $as_nop
CFLAGS=""
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
int
-main ()
+main (void)
{
;
return 0;
}
_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
+if ac_fn_c_try_compile "$LINENO"
+then :
-else
+else $as_nop
ac_c_werror_flag=$ac_save_c_werror_flag
CFLAGS="-g"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
int
-main ()
+main (void)
{
;
return 0;
}
_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
+if ac_fn_c_try_compile "$LINENO"
+then :
ac_cv_prog_cc_g=yes
fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
ac_c_werror_flag=$ac_save_c_werror_flag
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5
-$as_echo "$ac_cv_prog_cc_g" >&6; }
-if test "$ac_test_CFLAGS" = set; then
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5
+printf "%s\n" "$ac_cv_prog_cc_g" >&6; }
+if test $ac_test_CFLAGS; then
CFLAGS=$ac_save_CFLAGS
elif test $ac_cv_prog_cc_g = yes; then
if test "$GCC" = yes; then
@@ -3001,790 +3202,254 @@ else
CFLAGS=
fi
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5
-$as_echo_n "checking for $CC option to accept ISO C89... " >&6; }
-if ${ac_cv_prog_cc_c89+:} false; then :
- $as_echo_n "(cached) " >&6
-else
- ac_cv_prog_cc_c89=no
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C11 features" >&5
+printf %s "checking for $CC option to enable C11 features... " >&6; }
+if test ${ac_cv_prog_cc_c11+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
+ ac_cv_prog_cc_c11=no
ac_save_CC=$CC
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <stdarg.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <wchar.h>
#include <stdio.h>
-struct stat;
-/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */
-struct buf { int x; };
-FILE * (*rcsopen) (struct buf *, struct stat *, int);
-static char *e (p, i)
- char **p;
- int i;
-{
- return p[i];
-}
-static char *f (char * (*g) (char **, int), char **p, ...)
-{
- char *s;
- va_list v;
- va_start (v,p);
- s = g (p, va_arg (v,int));
- va_end (v);
- return s;
-}
-
-/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has
- function prototypes and stuff, but not '\xHH' hex character constants.
- These don't provoke an error unfortunately, instead are silently treated
- as 'x'. The following induces an error, until -std is added to get
- proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an
- array size at least. It's necessary to write '\x00'==0 to get something
- that's true only with -std. */
-int osf4_cc_array ['\x00' == 0 ? 1 : -1];
-/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters
- inside strings and character constants. */
-#define FOO(x) 'x'
-int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1];
-
-int test (int i, double x);
-struct s1 {int (*f) (int a);};
-struct s2 {int (*f) (double a);};
-int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int);
-int argc;
-char **argv;
-int
-main ()
+// Check varargs macros. These examples are taken from C99 6.10.3.5.
+#define debug(...) fprintf (stderr, __VA_ARGS__)
+#define showlist(...) puts (#__VA_ARGS__)
+#define report(test,...) ((test) ? puts (#test) : printf (__VA_ARGS__))
+static void
+test_varargs_macros (void)
{
-return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1];
- ;
- return 0;
+ int x = 1234;
+ int y = 5678;
+ debug ("Flag");
+ debug ("X = %d\n", x);
+ showlist (The first, second, and third items.);
+ report (x>y, "x is %d but y is %d", x, y);
}
-_ACEOF
-for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \
- -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__"
-do
- CC="$ac_save_CC $ac_arg"
- if ac_fn_c_try_compile "$LINENO"; then :
- ac_cv_prog_cc_c89=$ac_arg
-fi
-rm -f core conftest.err conftest.$ac_objext
- test "x$ac_cv_prog_cc_c89" != "xno" && break
-done
-rm -f conftest.$ac_ext
-CC=$ac_save_CC
-fi
-# AC_CACHE_VAL
-case "x$ac_cv_prog_cc_c89" in
- x)
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5
-$as_echo "none needed" >&6; } ;;
- xno)
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5
-$as_echo "unsupported" >&6; } ;;
- *)
- CC="$CC $ac_cv_prog_cc_c89"
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5
-$as_echo "$ac_cv_prog_cc_c89" >&6; } ;;
-esac
-if test "x$ac_cv_prog_cc_c89" != xno; then :
-
-fi
+// Check long long types.
+#define BIG64 18446744073709551615ull
+#define BIG32 4294967295ul
+#define BIG_OK (BIG64 / BIG32 == 4294967297ull && BIG64 % BIG32 == 0)
+#if !BIG_OK
+ your preprocessor is broken;
+#endif
+#if BIG_OK
+#else
+ your preprocessor is broken;
+#endif
+static long long int bignum = -9223372036854775807LL;
+static unsigned long long int ubignum = BIG64;
-ac_ext=c
-ac_cpp='$CPP $CPPFLAGS'
-ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
-ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
-ac_compiler_gnu=$ac_cv_c_compiler_gnu
+struct incomplete_array
+{
+ int datasize;
+ double data[];
+};
+struct named_init {
+ int number;
+ const wchar_t *name;
+ double average;
+};
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing clock_gettime" >&5
-$as_echo_n "checking for library containing clock_gettime... " >&6; }
-if ${ac_cv_search_clock_gettime+:} false; then :
- $as_echo_n "(cached) " >&6
-else
- ac_func_search_save_LIBS=$LIBS
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
+typedef const char *ccp;
-/* Override any GCC internal prototype to avoid an error.
- Use char because int might match the return type of a GCC
- builtin and then its argument prototype would still apply. */
-#ifdef __cplusplus
-extern "C"
-#endif
-char clock_gettime ();
-int
-main ()
+static inline int
+test_restrict (ccp restrict text)
{
-return clock_gettime ();
- ;
+ // See if C++-style comments work.
+ // Iterate through items via the restricted pointer.
+ // Also check for declarations in for loops.
+ for (unsigned int i = 0; *(text+i) != '\0'; ++i)
+ continue;
return 0;
}
-_ACEOF
-for ac_lib in '' rt posix4; do
- if test -z "$ac_lib"; then
- ac_res="none required"
- else
- ac_res=-l$ac_lib
- LIBS="-l$ac_lib $ac_func_search_save_LIBS"
- fi
- if ac_fn_c_try_link "$LINENO"; then :
- ac_cv_search_clock_gettime=$ac_res
-fi
-rm -f core conftest.err conftest.$ac_objext \
- conftest$ac_exeext
- if ${ac_cv_search_clock_gettime+:} false; then :
- break
-fi
-done
-if ${ac_cv_search_clock_gettime+:} false; then :
-
-else
- ac_cv_search_clock_gettime=no
-fi
-rm conftest.$ac_ext
-LIBS=$ac_func_search_save_LIBS
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_clock_gettime" >&5
-$as_echo "$ac_cv_search_clock_gettime" >&6; }
-ac_res=$ac_cv_search_clock_gettime
-if test "$ac_res" != no; then :
- test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
-
-else
- as_fn_error $? "Function clock_gettime not available." "$LINENO" 5
-
-fi
-
-
-# Make sure we can run config.sub.
-$SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 ||
- as_fn_error $? "cannot run $SHELL $ac_aux_dir/config.sub" "$LINENO" 5
-
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking build system type" >&5
-$as_echo_n "checking build system type... " >&6; }
-if ${ac_cv_build+:} false; then :
- $as_echo_n "(cached) " >&6
-else
- ac_build_alias=$build_alias
-test "x$ac_build_alias" = x &&
- ac_build_alias=`$SHELL "$ac_aux_dir/config.guess"`
-test "x$ac_build_alias" = x &&
- as_fn_error $? "cannot guess build type; you must specify one" "$LINENO" 5
-ac_cv_build=`$SHELL "$ac_aux_dir/config.sub" $ac_build_alias` ||
- as_fn_error $? "$SHELL $ac_aux_dir/config.sub $ac_build_alias failed" "$LINENO" 5
-
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5
-$as_echo "$ac_cv_build" >&6; }
-case $ac_cv_build in
-*-*-*) ;;
-*) as_fn_error $? "invalid value of canonical build" "$LINENO" 5;;
-esac
-build=$ac_cv_build
-ac_save_IFS=$IFS; IFS='-'
-set x $ac_cv_build
-shift
-build_cpu=$1
-build_vendor=$2
-shift; shift
-# Remember, the first character of IFS is used to create $*,
-# except with old shells:
-build_os=$*
-IFS=$ac_save_IFS
-case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac
-
-
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking host system type" >&5
-$as_echo_n "checking host system type... " >&6; }
-if ${ac_cv_host+:} false; then :
- $as_echo_n "(cached) " >&6
-else
- if test "x$host_alias" = x; then
- ac_cv_host=$ac_cv_build
-else
- ac_cv_host=`$SHELL "$ac_aux_dir/config.sub" $host_alias` ||
- as_fn_error $? "$SHELL $ac_aux_dir/config.sub $host_alias failed" "$LINENO" 5
-fi
-
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5
-$as_echo "$ac_cv_host" >&6; }
-case $ac_cv_host in
-*-*-*) ;;
-*) as_fn_error $? "invalid value of canonical host" "$LINENO" 5;;
-esac
-host=$ac_cv_host
-ac_save_IFS=$IFS; IFS='-'
-set x $ac_cv_host
-shift
-host_cpu=$1
-host_vendor=$2
-shift; shift
-# Remember, the first character of IFS is used to create $*,
-# except with old shells:
-host_os=$*
-IFS=$ac_save_IFS
-case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac
-
-
-
-# Store this value because ac_test_CFLAGS is overwritten by AC_PROG_CC
-if test "$ac_test_CFLAGS" != set ; then
- bird_cflags_default=yes
-fi
-
-ac_ext=c
-ac_cpp='$CPP $CPPFLAGS'
-ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
-ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
-ac_compiler_gnu=$ac_cv_c_compiler_gnu
-if test -n "$ac_tool_prefix"; then
- # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args.
-set dummy ${ac_tool_prefix}gcc; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_CC+:} false; then :
- $as_echo_n "(cached) " >&6
-else
- if test -n "$CC"; then
- ac_cv_prog_CC="$CC" # Let the user override the test.
-else
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
- IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
- for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
- ac_cv_prog_CC="${ac_tool_prefix}gcc"
- $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
- break 2
- fi
-done
- done
-IFS=$as_save_IFS
-
-fi
-fi
-CC=$ac_cv_prog_CC
-if test -n "$CC"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
-$as_echo "$CC" >&6; }
-else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-fi
-
-
-fi
-if test -z "$ac_cv_prog_CC"; then
- ac_ct_CC=$CC
- # Extract the first word of "gcc", so it can be a program name with args.
-set dummy gcc; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_ac_ct_CC+:} false; then :
- $as_echo_n "(cached) " >&6
-else
- if test -n "$ac_ct_CC"; then
- ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
-else
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
- IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
- for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
- ac_cv_prog_ac_ct_CC="gcc"
- $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
- break 2
- fi
-done
- done
-IFS=$as_save_IFS
-
-fi
-fi
-ac_ct_CC=$ac_cv_prog_ac_ct_CC
-if test -n "$ac_ct_CC"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
-$as_echo "$ac_ct_CC" >&6; }
-else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-fi
-
- if test "x$ac_ct_CC" = x; then
- CC=""
- else
- case $cross_compiling:$ac_tool_warned in
-yes:)
-{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
-$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
-ac_tool_warned=yes ;;
-esac
- CC=$ac_ct_CC
- fi
-else
- CC="$ac_cv_prog_CC"
-fi
-
-if test -z "$CC"; then
- if test -n "$ac_tool_prefix"; then
- # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args.
-set dummy ${ac_tool_prefix}cc; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_CC+:} false; then :
- $as_echo_n "(cached) " >&6
-else
- if test -n "$CC"; then
- ac_cv_prog_CC="$CC" # Let the user override the test.
-else
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
- IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
- for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
- ac_cv_prog_CC="${ac_tool_prefix}cc"
- $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
- break 2
- fi
-done
- done
-IFS=$as_save_IFS
-
-fi
-fi
-CC=$ac_cv_prog_CC
-if test -n "$CC"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
-$as_echo "$CC" >&6; }
-else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-fi
-
-
- fi
-fi
-if test -z "$CC"; then
- # Extract the first word of "cc", so it can be a program name with args.
-set dummy cc; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_CC+:} false; then :
- $as_echo_n "(cached) " >&6
-else
- if test -n "$CC"; then
- ac_cv_prog_CC="$CC" # Let the user override the test.
-else
- ac_prog_rejected=no
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
- IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
- for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
- if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then
- ac_prog_rejected=yes
- continue
- fi
- ac_cv_prog_CC="cc"
- $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
- break 2
- fi
-done
- done
-IFS=$as_save_IFS
-
-if test $ac_prog_rejected = yes; then
- # We found a bogon in the path, so make sure we never use it.
- set dummy $ac_cv_prog_CC
- shift
- if test $# != 0; then
- # We chose a different compiler from the bogus one.
- # However, it has the same basename, so the bogon will be chosen
- # first if we set CC to just the basename; use the full file name.
- shift
- ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@"
- fi
-fi
-fi
-fi
-CC=$ac_cv_prog_CC
-if test -n "$CC"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
-$as_echo "$CC" >&6; }
-else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-fi
-
-
-fi
-if test -z "$CC"; then
- if test -n "$ac_tool_prefix"; then
- for ac_prog in cl.exe
- do
- # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
-set dummy $ac_tool_prefix$ac_prog; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_CC+:} false; then :
- $as_echo_n "(cached) " >&6
-else
- if test -n "$CC"; then
- ac_cv_prog_CC="$CC" # Let the user override the test.
-else
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
- IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
- for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
- ac_cv_prog_CC="$ac_tool_prefix$ac_prog"
- $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
- break 2
- fi
-done
- done
-IFS=$as_save_IFS
-
-fi
-fi
-CC=$ac_cv_prog_CC
-if test -n "$CC"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
-$as_echo "$CC" >&6; }
-else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-fi
-
-
- test -n "$CC" && break
- done
-fi
-if test -z "$CC"; then
- ac_ct_CC=$CC
- for ac_prog in cl.exe
-do
- # Extract the first word of "$ac_prog", so it can be a program name with args.
-set dummy $ac_prog; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_ac_ct_CC+:} false; then :
- $as_echo_n "(cached) " >&6
-else
- if test -n "$ac_ct_CC"; then
- ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
-else
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
- IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
- for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
- ac_cv_prog_ac_ct_CC="$ac_prog"
- $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
- break 2
- fi
-done
- done
-IFS=$as_save_IFS
-fi
-fi
-ac_ct_CC=$ac_cv_prog_ac_ct_CC
-if test -n "$ac_ct_CC"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
-$as_echo "$ac_ct_CC" >&6; }
-else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-fi
+// Check varargs and va_copy.
+static bool
+test_varargs (const char *format, ...)
+{
+ va_list args;
+ va_start (args, format);
+ va_list args_copy;
+ va_copy (args_copy, args);
+ const char *str = "";
+ int number = 0;
+ float fnumber = 0;
- test -n "$ac_ct_CC" && break
-done
+ while (*format)
+ {
+ switch (*format++)
+ {
+ case 's': // string
+ str = va_arg (args_copy, const char *);
+ break;
+ case 'd': // int
+ number = va_arg (args_copy, int);
+ break;
+ case 'f': // float
+ fnumber = va_arg (args_copy, double);
+ break;
+ default:
+ break;
+ }
+ }
+ va_end (args_copy);
+ va_end (args);
- if test "x$ac_ct_CC" = x; then
- CC=""
- else
- case $cross_compiling:$ac_tool_warned in
-yes:)
-{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
-$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
-ac_tool_warned=yes ;;
-esac
- CC=$ac_ct_CC
- fi
-fi
+ return *str && number && fnumber;
+}
+// Check _Alignas.
+char _Alignas (double) aligned_as_double;
+char _Alignas (0) no_special_alignment;
+extern char aligned_as_int;
+char _Alignas (0) _Alignas (int) aligned_as_int;
+
+// Check _Alignof.
+enum
+{
+ int_alignment = _Alignof (int),
+ int_array_alignment = _Alignof (int[100]),
+ char_alignment = _Alignof (char)
+};
+_Static_assert (0 < -_Alignof (int), "_Alignof is signed");
-fi
+// Check _Noreturn.
+int _Noreturn does_not_return (void) { for (;;) continue; }
+// Check _Static_assert.
+struct test_static_assert
+{
+ int x;
+ _Static_assert (sizeof (int) <= sizeof (long int),
+ "_Static_assert does not work in struct");
+ long int y;
+};
-test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
-$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
-as_fn_error $? "no acceptable C compiler found in \$PATH
-See \`config.log' for more details" "$LINENO" 5; }
+// Check UTF-8 literals.
+#define u8 syntax error!
+char const utf8_literal[] = u8"happens to be ASCII" "another string";
-# Provide some information about the compiler.
-$as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5
-set X $ac_compile
-ac_compiler=$2
-for ac_option in --version -v -V -qversion; do
- { { ac_try="$ac_compiler $ac_option >&5"
-case "(($ac_try" in
- *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
- *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
-$as_echo "$ac_try_echo"; } >&5
- (eval "$ac_compiler $ac_option >&5") 2>conftest.err
- ac_status=$?
- if test -s conftest.err; then
- sed '10a\
-... rest of stderr output deleted ...
- 10q' conftest.err >conftest.er1
- cat conftest.er1 >&5
- fi
- rm -f conftest.er1 conftest.err
- $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
- test $ac_status = 0; }
-done
-
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5
-$as_echo_n "checking whether we are using the GNU C compiler... " >&6; }
-if ${ac_cv_c_compiler_gnu+:} false; then :
- $as_echo_n "(cached) " >&6
-else
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
+// Check duplicate typedefs.
+typedef long *long_ptr;
+typedef long int *long_ptr;
+typedef long_ptr long_ptr;
-int
-main ()
+// Anonymous structures and unions -- taken from C11 6.7.2.1 Example 1.
+struct anonymous
{
-#ifndef __GNUC__
- choke me
-#endif
-
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
- ac_compiler_gnu=yes
-else
- ac_compiler_gnu=no
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-ac_cv_c_compiler_gnu=$ac_compiler_gnu
-
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5
-$as_echo "$ac_cv_c_compiler_gnu" >&6; }
-if test $ac_compiler_gnu = yes; then
- GCC=yes
-else
- GCC=
-fi
-ac_test_CFLAGS=${CFLAGS+set}
-ac_save_CFLAGS=$CFLAGS
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5
-$as_echo_n "checking whether $CC accepts -g... " >&6; }
-if ${ac_cv_prog_cc_g+:} false; then :
- $as_echo_n "(cached) " >&6
-else
- ac_save_c_werror_flag=$ac_c_werror_flag
- ac_c_werror_flag=yes
- ac_cv_prog_cc_g=no
- CFLAGS="-g"
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
+ union {
+ struct { int i; int j; };
+ struct { int k; long int l; } w;
+ };
+ int m;
+} v1;
int
-main ()
+main (void)
{
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
- ac_cv_prog_cc_g=yes
-else
- CFLAGS=""
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
+ // Check bool.
+ _Bool success = false;
-int
-main ()
-{
+ // Check restrict.
+ if (test_restrict ("String literal") == 0)
+ success = true;
+ char *restrict newvar = "Another string";
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
+ // Check varargs.
+ success &= test_varargs ("s, d' f .", "string", 65, 34.234);
+ test_varargs_macros ();
-else
- ac_c_werror_flag=$ac_save_c_werror_flag
- CFLAGS="-g"
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
+ // Check flexible array members.
+ struct incomplete_array *ia =
+ malloc (sizeof (struct incomplete_array) + (sizeof (double) * 10));
+ ia->datasize = 10;
+ for (int i = 0; i < ia->datasize; ++i)
+ ia->data[i] = i * 1.234;
-int
-main ()
-{
+ // Check named initializers.
+ struct named_init ni = {
+ .number = 34,
+ .name = L"Test wide string",
+ .average = 543.34343,
+ };
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
- ac_cv_prog_cc_g=yes
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
- ac_c_werror_flag=$ac_save_c_werror_flag
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5
-$as_echo "$ac_cv_prog_cc_g" >&6; }
-if test "$ac_test_CFLAGS" = set; then
- CFLAGS=$ac_save_CFLAGS
-elif test $ac_cv_prog_cc_g = yes; then
- if test "$GCC" = yes; then
- CFLAGS="-g -O2"
- else
- CFLAGS="-g"
- fi
-else
- if test "$GCC" = yes; then
- CFLAGS="-O2"
- else
- CFLAGS=
- fi
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5
-$as_echo_n "checking for $CC option to accept ISO C89... " >&6; }
-if ${ac_cv_prog_cc_c89+:} false; then :
- $as_echo_n "(cached) " >&6
-else
- ac_cv_prog_cc_c89=no
-ac_save_CC=$CC
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-#include <stdarg.h>
-#include <stdio.h>
-struct stat;
-/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */
-struct buf { int x; };
-FILE * (*rcsopen) (struct buf *, struct stat *, int);
-static char *e (p, i)
- char **p;
- int i;
-{
- return p[i];
-}
-static char *f (char * (*g) (char **, int), char **p, ...)
-{
- char *s;
- va_list v;
- va_start (v,p);
- s = g (p, va_arg (v,int));
- va_end (v);
- return s;
-}
+ ni.number = 58;
-/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has
- function prototypes and stuff, but not '\xHH' hex character constants.
- These don't provoke an error unfortunately, instead are silently treated
- as 'x'. The following induces an error, until -std is added to get
- proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an
- array size at least. It's necessary to write '\x00'==0 to get something
- that's true only with -std. */
-int osf4_cc_array ['\x00' == 0 ? 1 : -1];
+ int dynamic_array[ni.number];
+ dynamic_array[ni.number - 1] = 543;
-/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters
- inside strings and character constants. */
-#define FOO(x) 'x'
-int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1];
+ // work around unused variable warnings
+ return (!success || bignum == 0LL || ubignum == 0uLL || newvar[0] == 'x'
+ || dynamic_array[ni.number - 1] != 543);
+
+ v1.i = 2;
+ v1.w.k = 5;
+ _Static_assert ((offsetof (struct anonymous, i)
+ == offsetof (struct anonymous, w.k)),
+ "Anonymous union alignment botch");
-int test (int i, double x);
-struct s1 {int (*f) (int a);};
-struct s2 {int (*f) (double a);};
-int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int);
-int argc;
-char **argv;
-int
-main ()
-{
-return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1];
;
return 0;
}
_ACEOF
-for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \
- -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__"
+for ac_arg in '' -std=gnu11
do
CC="$ac_save_CC $ac_arg"
- if ac_fn_c_try_compile "$LINENO"; then :
- ac_cv_prog_cc_c89=$ac_arg
+ if ac_fn_c_try_compile "$LINENO"
+then :
+ ac_cv_prog_cc_c11=$ac_arg
fi
-rm -f core conftest.err conftest.$ac_objext
- test "x$ac_cv_prog_cc_c89" != "xno" && break
+rm -f core conftest.err conftest.$ac_objext conftest.beam
+ test "x$ac_cv_prog_cc_c11" != "xno" && break
done
rm -f conftest.$ac_ext
CC=$ac_save_CC
fi
# AC_CACHE_VAL
-case "x$ac_cv_prog_cc_c89" in
+ac_prog_cc_stdc_options=
+case "x$ac_cv_prog_cc_c11" in
x)
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5
-$as_echo "none needed" >&6; } ;;
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5
+printf "%s\n" "none needed" >&6; } ;;
xno)
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5
-$as_echo "unsupported" >&6; } ;;
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5
+printf "%s\n" "unsupported" >&6; } ;;
*)
- CC="$CC $ac_cv_prog_cc_c89"
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5
-$as_echo "$ac_cv_prog_cc_c89" >&6; } ;;
+ ac_prog_cc_stdc_options=" $ac_cv_prog_cc_c11"
+ CC=$CC$ac_prog_cc_stdc_options
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c11" >&5
+printf "%s\n" "$ac_cv_prog_cc_c11" >&6; } ;;
esac
-if test "x$ac_cv_prog_cc_c89" != xno; then :
-
-fi
-
-ac_ext=c
-ac_cpp='$CPP $CPPFLAGS'
-ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
-ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
-ac_compiler_gnu=$ac_cv_c_compiler_gnu
-
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C99" >&5
-$as_echo_n "checking for $CC option to accept ISO C99... " >&6; }
-if ${ac_cv_prog_cc_c99+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+if test "x$ac_cv_prog_cc_c11" != xno
+then :
+ ac_prog_cc_stdc=c11
+ ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c11
+else $as_nop
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C99 features" >&5
+printf %s "checking for $CC option to enable C99 features... " >&6; }
+if test ${ac_cv_prog_cc_c99+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
ac_cv_prog_cc_c99=no
ac_save_CC=$CC
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <stdarg.h>
#include <stdbool.h>
+#include <stddef.h>
#include <stdlib.h>
#include <wchar.h>
#include <stdio.h>
@@ -3844,7 +3509,7 @@ test_restrict (ccp restrict text)
}
// Check varargs and va_copy.
-static void
+static bool
test_varargs (const char *format, ...)
{
va_list args;
@@ -3852,9 +3517,9 @@ test_varargs (const char *format, ...)
va_list args_copy;
va_copy (args_copy, args);
- const char *str;
- int number;
- float fnumber;
+ const char *str = "";
+ int number = 0;
+ float fnumber = 0;
while (*format)
{
@@ -3875,10 +3540,11 @@ test_varargs (const char *format, ...)
}
va_end (args_copy);
va_end (args);
-}
+ return *str && number && fnumber;
+}
int
-main ()
+main (void)
{
// Check bool.
@@ -3890,7 +3556,7 @@ main ()
char *restrict newvar = "Another string";
// Check varargs.
- test_varargs ("s, d' f .", "string", 65, 34.234);
+ success &= test_varargs ("s, d' f .", "string", 65, 34.234);
test_varargs_macros ();
// Check flexible array members.
@@ -3920,13 +3586,14 @@ main ()
return 0;
}
_ACEOF
-for ac_arg in '' -std=gnu99 -std=c99 -c99 -AC99 -D_STDC_C99= -qlanglvl=extc99
+for ac_arg in '' -std=gnu99 -std=c99 -c99 -AC99 -D_STDC_C99= -qlanglvl=extc1x -qlanglvl=extc99
do
CC="$ac_save_CC $ac_arg"
- if ac_fn_c_try_compile "$LINENO"; then :
+ if ac_fn_c_try_compile "$LINENO"
+then :
ac_cv_prog_cc_c99=$ac_arg
fi
-rm -f core conftest.err conftest.$ac_objext
+rm -f core conftest.err conftest.$ac_objext conftest.beam
test "x$ac_cv_prog_cc_c99" != "xno" && break
done
rm -f conftest.$ac_ext
@@ -3934,33 +3601,293 @@ CC=$ac_save_CC
fi
# AC_CACHE_VAL
+ac_prog_cc_stdc_options=
case "x$ac_cv_prog_cc_c99" in
x)
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5
-$as_echo "none needed" >&6; } ;;
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5
+printf "%s\n" "none needed" >&6; } ;;
xno)
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5
-$as_echo "unsupported" >&6; } ;;
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5
+printf "%s\n" "unsupported" >&6; } ;;
*)
- CC="$CC $ac_cv_prog_cc_c99"
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c99" >&5
-$as_echo "$ac_cv_prog_cc_c99" >&6; } ;;
+ ac_prog_cc_stdc_options=" $ac_cv_prog_cc_c99"
+ CC=$CC$ac_prog_cc_stdc_options
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c99" >&5
+printf "%s\n" "$ac_cv_prog_cc_c99" >&6; } ;;
esac
-if test "x$ac_cv_prog_cc_c99" != xno; then :
+if test "x$ac_cv_prog_cc_c99" != xno
+then :
+ ac_prog_cc_stdc=c99
+ ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c99
+else $as_nop
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C89 features" >&5
+printf %s "checking for $CC option to enable C89 features... " >&6; }
+if test ${ac_cv_prog_cc_c89+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
+ ac_cv_prog_cc_c89=no
+ac_save_CC=$CC
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <stdarg.h>
+#include <stdio.h>
+struct stat;
+/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */
+struct buf { int x; };
+FILE * (*rcsopen) (struct buf *, struct stat *, int);
+static char *e (p, i)
+ char **p;
+ int i;
+{
+ return p[i];
+}
+static char *f (char * (*g) (char **, int), char **p, ...)
+{
+ char *s;
+ va_list v;
+ va_start (v,p);
+ s = g (p, va_arg (v,int));
+ va_end (v);
+ return s;
+}
+/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has
+ function prototypes and stuff, but not '\xHH' hex character constants.
+ These don't provoke an error unfortunately, instead are silently treated
+ as 'x'. The following induces an error, until -std is added to get
+ proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an
+ array size at least. It's necessary to write '\x00'==0 to get something
+ that's true only with -std. */
+int osf4_cc_array ['\x00' == 0 ? 1 : -1];
+
+/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters
+ inside strings and character constants. */
+#define FOO(x) 'x'
+int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1];
+
+int test (int i, double x);
+struct s1 {int (*f) (int a);};
+struct s2 {int (*f) (double a);};
+int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int);
+int argc;
+char **argv;
+int
+main (void)
+{
+return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1];
+ ;
+ return 0;
+}
+_ACEOF
+for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \
+ -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__"
+do
+ CC="$ac_save_CC $ac_arg"
+ if ac_fn_c_try_compile "$LINENO"
+then :
+ ac_cv_prog_cc_c89=$ac_arg
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam
+ test "x$ac_cv_prog_cc_c89" != "xno" && break
+done
+rm -f conftest.$ac_ext
+CC=$ac_save_CC
+
+fi
+# AC_CACHE_VAL
+ac_prog_cc_stdc_options=
+case "x$ac_cv_prog_cc_c89" in
+ x)
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5
+printf "%s\n" "none needed" >&6; } ;;
+ xno)
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5
+printf "%s\n" "unsupported" >&6; } ;;
+ *)
+ ac_prog_cc_stdc_options=" $ac_cv_prog_cc_c89"
+ CC=$CC$ac_prog_cc_stdc_options
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5
+printf "%s\n" "$ac_cv_prog_cc_c89" >&6; } ;;
+esac
+if test "x$ac_cv_prog_cc_c89" != xno
+then :
+ ac_prog_cc_stdc=c89
+ ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c89
+else $as_nop
+ ac_prog_cc_stdc=no
+ ac_cv_prog_cc_stdc=no
fi
+fi
+
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for library containing clock_gettime" >&5
+printf %s "checking for library containing clock_gettime... " >&6; }
+if test ${ac_cv_search_clock_gettime+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
+ ac_func_search_save_LIBS=$LIBS
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+char clock_gettime ();
+int
+main (void)
+{
+return clock_gettime ();
+ ;
+ return 0;
+}
+_ACEOF
+for ac_lib in '' rt posix4
+do
+ if test -z "$ac_lib"; then
+ ac_res="none required"
+ else
+ ac_res=-l$ac_lib
+ LIBS="-l$ac_lib $ac_func_search_save_LIBS"
+ fi
+ if ac_fn_c_try_link "$LINENO"
+then :
+ ac_cv_search_clock_gettime=$ac_res
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
+ conftest$ac_exeext
+ if test ${ac_cv_search_clock_gettime+y}
+then :
+ break
+fi
+done
+if test ${ac_cv_search_clock_gettime+y}
+then :
+
+else $as_nop
+ ac_cv_search_clock_gettime=no
+fi
+rm conftest.$ac_ext
+LIBS=$ac_func_search_save_LIBS
+fi
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_clock_gettime" >&5
+printf "%s\n" "$ac_cv_search_clock_gettime" >&6; }
+ac_res=$ac_cv_search_clock_gettime
+if test "$ac_res" != no
+then :
+ test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
+
+else $as_nop
+ as_fn_error $? "Function clock_gettime not available." "$LINENO" 5
+
+fi
+
+
+
+
+
+ # Make sure we can run config.sub.
+$SHELL "${ac_aux_dir}config.sub" sun4 >/dev/null 2>&1 ||
+ as_fn_error $? "cannot run $SHELL ${ac_aux_dir}config.sub" "$LINENO" 5
+
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking build system type" >&5
+printf %s "checking build system type... " >&6; }
+if test ${ac_cv_build+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
+ ac_build_alias=$build_alias
+test "x$ac_build_alias" = x &&
+ ac_build_alias=`$SHELL "${ac_aux_dir}config.guess"`
+test "x$ac_build_alias" = x &&
+ as_fn_error $? "cannot guess build type; you must specify one" "$LINENO" 5
+ac_cv_build=`$SHELL "${ac_aux_dir}config.sub" $ac_build_alias` ||
+ as_fn_error $? "$SHELL ${ac_aux_dir}config.sub $ac_build_alias failed" "$LINENO" 5
+
+fi
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5
+printf "%s\n" "$ac_cv_build" >&6; }
+case $ac_cv_build in
+*-*-*) ;;
+*) as_fn_error $? "invalid value of canonical build" "$LINENO" 5;;
+esac
+build=$ac_cv_build
+ac_save_IFS=$IFS; IFS='-'
+set x $ac_cv_build
+shift
+build_cpu=$1
+build_vendor=$2
+shift; shift
+# Remember, the first character of IFS is used to create $*,
+# except with old shells:
+build_os=$*
+IFS=$ac_save_IFS
+case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac
+
+
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking host system type" >&5
+printf %s "checking host system type... " >&6; }
+if test ${ac_cv_host+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
+ if test "x$host_alias" = x; then
+ ac_cv_host=$ac_cv_build
+else
+ ac_cv_host=`$SHELL "${ac_aux_dir}config.sub" $host_alias` ||
+ as_fn_error $? "$SHELL ${ac_aux_dir}config.sub $host_alias failed" "$LINENO" 5
+fi
+
+fi
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5
+printf "%s\n" "$ac_cv_host" >&6; }
+case $ac_cv_host in
+*-*-*) ;;
+*) as_fn_error $? "invalid value of canonical host" "$LINENO" 5;;
+esac
+host=$ac_cv_host
+ac_save_IFS=$IFS; IFS='-'
+set x $ac_cv_host
+shift
+host_cpu=$1
+host_vendor=$2
+shift; shift
+# Remember, the first character of IFS is used to create $*,
+# except with old shells:
+host_os=$*
+IFS=$ac_save_IFS
+case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac
+
+
+
+# Store this value because ac_test_CFLAGS is overwritten by AC_PROG_CC
+if test "$ac_test_CFLAGS" != set ; then
+ bird_cflags_default=yes
+fi
+
+
if test -z "$GCC" ; then
as_fn_error $? "This program requires the GNU C Compiler." "$LINENO" 5
fi
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether _Thread_local is known" >&5
-$as_echo_n "checking whether _Thread_local is known... " >&6; }
-if ${bird_cv_thread_local+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether _Thread_local is known" >&5
+printf %s "checking whether _Thread_local is known... " >&6; }
+if test ${bird_cv_thread_local+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
@@ -3968,7 +3895,7 @@ else
_Thread_local static int x = 42;
int
-main ()
+main (void)
{
@@ -3977,21 +3904,22 @@ main ()
}
_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
+if ac_fn_c_try_compile "$LINENO"
+then :
bird_cv_thread_local=yes
-else
+else $as_nop
bird_cv_thread_local=no
fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $bird_cv_thread_local" >&5
-$as_echo "$bird_cv_thread_local" >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $bird_cv_thread_local" >&5
+printf "%s\n" "$bird_cv_thread_local" >&6; }
if test "$bird_cv_thread_local" = yes ; then
-$as_echo "#define HAVE_THREAD_LOCAL 1" >>confdefs.h
+printf "%s\n" "#define HAVE_THREAD_LOCAL 1" >>confdefs.h
fi
@@ -4000,18 +3928,19 @@ if test "$enable_pthreads" != no ; then
bird_tmp_cflags="$CFLAGS"
CFLAGS="$CFLAGS -pthread"
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether POSIX threads are available" >&5
-$as_echo_n "checking whether POSIX threads are available... " >&6; }
-if ${bird_cv_lib_pthreads+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether POSIX threads are available" >&5
+printf %s "checking whether POSIX threads are available... " >&6; }
+if test ${bird_cv_lib_pthreads+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <pthread.h>
int
-main ()
+main (void)
{
pthread_t pt;
@@ -4025,26 +3954,27 @@ main ()
}
_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
+if ac_fn_c_try_link "$LINENO"
+then :
bird_cv_lib_pthreads=yes
-else
+else $as_nop
bird_cv_lib_pthreads=no
fi
-rm -f core conftest.err conftest.$ac_objext \
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
conftest$ac_exeext conftest.$ac_ext
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $bird_cv_lib_pthreads" >&5
-$as_echo "$bird_cv_lib_pthreads" >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $bird_cv_lib_pthreads" >&5
+printf "%s\n" "$bird_cv_lib_pthreads" >&6; }
CFLAGS="$bird_tmp_cflags"
if test "$bird_cv_lib_pthreads" = yes ; then
-$as_echo "#define USE_PTHREADS 1" >>confdefs.h
+printf "%s\n" "#define USE_PTHREADS 1" >>confdefs.h
CFLAGS="$CFLAGS -pthread"
LDFLAGS="$LDFLAGS -pthread"
@@ -4066,35 +3996,37 @@ if test "$bird_cflags_default" = yes ; then
bird_tmp_cflags="$CFLAGS"
CFLAGS="-Wall -Wno-pointer-sign"
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether CC supports -Wno-pointer-sign" >&5
-$as_echo_n "checking whether CC supports -Wno-pointer-sign... " >&6; }
-if ${bird_cv_c_option_wno_pointer_sign+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether CC supports -Wno-pointer-sign" >&5
+printf %s "checking whether CC supports -Wno-pointer-sign... " >&6; }
+if test ${bird_cv_c_option_wno_pointer_sign+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
int
-main ()
+main (void)
{
;
return 0;
}
_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
+if ac_fn_c_try_compile "$LINENO"
+then :
bird_cv_c_option_wno_pointer_sign=yes
-else
+else $as_nop
bird_cv_c_option_wno_pointer_sign=no
fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $bird_cv_c_option_wno_pointer_sign" >&5
-$as_echo "$bird_cv_c_option_wno_pointer_sign" >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $bird_cv_c_option_wno_pointer_sign" >&5
+printf "%s\n" "$bird_cv_c_option_wno_pointer_sign" >&6; }
CFLAGS="$bird_tmp_cflags"
@@ -4102,35 +4034,37 @@ $as_echo "$bird_cv_c_option_wno_pointer_sign" >&6; }
bird_tmp_cflags="$CFLAGS"
CFLAGS="-Wall -Wextra -Wno-missing-field-initializers"
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether CC supports -Wno-missing-field-initializers" >&5
-$as_echo_n "checking whether CC supports -Wno-missing-field-initializers... " >&6; }
-if ${bird_cv_c_option_wno_missing_init+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether CC supports -Wno-missing-field-initializers" >&5
+printf %s "checking whether CC supports -Wno-missing-field-initializers... " >&6; }
+if test ${bird_cv_c_option_wno_missing_init+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
int
-main ()
+main (void)
{
;
return 0;
}
_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
+if ac_fn_c_try_compile "$LINENO"
+then :
bird_cv_c_option_wno_missing_init=yes
-else
+else $as_nop
bird_cv_c_option_wno_missing_init=no
fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $bird_cv_c_option_wno_missing_init" >&5
-$as_echo "$bird_cv_c_option_wno_missing_init" >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $bird_cv_c_option_wno_missing_init" >&5
+printf "%s\n" "$bird_cv_c_option_wno_missing_init" >&6; }
CFLAGS="$bird_tmp_cflags"
@@ -4142,36 +4076,38 @@ $as_echo "$bird_cv_c_option_wno_missing_init" >&6; }
CFLAGS="-flto"
LDFLAGS="-flto=4"
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether link time optimizer is available" >&5
-$as_echo_n "checking whether link time optimizer is available... " >&6; }
-if ${bird_cv_c_lto+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether link time optimizer is available" >&5
+printf %s "checking whether link time optimizer is available... " >&6; }
+if test ${bird_cv_c_lto+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
int
-main ()
+main (void)
{
;
return 0;
}
_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
+if ac_fn_c_try_link "$LINENO"
+then :
bird_cv_c_lto=yes
-else
+else $as_nop
bird_cv_c_lto=no
fi
-rm -f core conftest.err conftest.$ac_objext \
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
conftest$ac_exeext conftest.$ac_ext
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $bird_cv_c_lto" >&5
-$as_echo "$bird_cv_c_lto" >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $bird_cv_c_lto" >&5
+printf "%s\n" "$bird_cv_c_lto" >&6; }
CFLAGS="$bird_tmp_cflags"
LDFLAGS="$bird_tmp_ldflags"
@@ -4199,55 +4135,51 @@ $as_echo "$bird_cv_c_lto" >&6; }
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking CFLAGS" >&5
-$as_echo_n "checking CFLAGS... " >&6; }
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $CFLAGS" >&5
-$as_echo "$CFLAGS" >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking CFLAGS" >&5
+printf %s "checking CFLAGS... " >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CFLAGS" >&5
+printf "%s\n" "$CFLAGS" >&6; }
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking LDFLAGS" >&5
-$as_echo_n "checking LDFLAGS... " >&6; }
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $LDFLAGS" >&5
-$as_echo "$LDFLAGS" >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking LDFLAGS" >&5
+printf %s "checking LDFLAGS... " >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $LDFLAGS" >&5
+printf "%s\n" "$LDFLAGS" >&6; }
ac_ext=c
ac_cpp='$CPP $CPPFLAGS'
ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
ac_compiler_gnu=$ac_cv_c_compiler_gnu
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5
-$as_echo_n "checking how to run the C preprocessor... " >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5
+printf %s "checking how to run the C preprocessor... " >&6; }
# On Suns, sometimes $CPP names a directory.
if test -n "$CPP" && test -d "$CPP"; then
CPP=
fi
if test -z "$CPP"; then
- if ${ac_cv_prog_CPP+:} false; then :
- $as_echo_n "(cached) " >&6
-else
- # Double quotes because CPP needs to be expanded
- for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp"
+ if test ${ac_cv_prog_CPP+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
+ # Double quotes because $CC needs to be expanded
+ for CPP in "$CC -E" "$CC -E -traditional-cpp" cpp /lib/cpp
do
ac_preproc_ok=false
for ac_c_preproc_warn_flag in '' yes
do
# Use a header file that comes with gcc, so configuring glibc
# with a fresh cross-compiler works.
- # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
- # <limits.h> exists even on freestanding compilers.
# On the NeXT, cc -E runs the code through the compiler's parser,
# not just through cpp. "Syntax error" is here to catch this case.
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
-#ifdef __STDC__
-# include <limits.h>
-#else
-# include <assert.h>
-#endif
+#include <limits.h>
Syntax error
_ACEOF
-if ac_fn_c_try_cpp "$LINENO"; then :
+if ac_fn_c_try_cpp "$LINENO"
+then :
-else
+else $as_nop
# Broken: fails on valid input.
continue
fi
@@ -4259,10 +4191,11 @@ rm -f conftest.err conftest.i conftest.$ac_ext
/* end confdefs.h. */
#include <ac_nonexistent.h>
_ACEOF
-if ac_fn_c_try_cpp "$LINENO"; then :
+if ac_fn_c_try_cpp "$LINENO"
+then :
# Broken: success on invalid input.
continue
-else
+else $as_nop
# Passes both tests.
ac_preproc_ok=:
break
@@ -4272,7 +4205,8 @@ rm -f conftest.err conftest.i conftest.$ac_ext
done
# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
rm -f conftest.i conftest.err conftest.$ac_ext
-if $ac_preproc_ok; then :
+if $ac_preproc_ok
+then :
break
fi
@@ -4284,29 +4218,24 @@ fi
else
ac_cv_prog_CPP=$CPP
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5
-$as_echo "$CPP" >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5
+printf "%s\n" "$CPP" >&6; }
ac_preproc_ok=false
for ac_c_preproc_warn_flag in '' yes
do
# Use a header file that comes with gcc, so configuring glibc
# with a fresh cross-compiler works.
- # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
- # <limits.h> exists even on freestanding compilers.
# On the NeXT, cc -E runs the code through the compiler's parser,
# not just through cpp. "Syntax error" is here to catch this case.
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
-#ifdef __STDC__
-# include <limits.h>
-#else
-# include <assert.h>
-#endif
+#include <limits.h>
Syntax error
_ACEOF
-if ac_fn_c_try_cpp "$LINENO"; then :
+if ac_fn_c_try_cpp "$LINENO"
+then :
-else
+else $as_nop
# Broken: fails on valid input.
continue
fi
@@ -4318,10 +4247,11 @@ rm -f conftest.err conftest.i conftest.$ac_ext
/* end confdefs.h. */
#include <ac_nonexistent.h>
_ACEOF
-if ac_fn_c_try_cpp "$LINENO"; then :
+if ac_fn_c_try_cpp "$LINENO"
+then :
# Broken: success on invalid input.
continue
-else
+else $as_nop
# Passes both tests.
ac_preproc_ok=:
break
@@ -4331,11 +4261,12 @@ rm -f conftest.err conftest.i conftest.$ac_ext
done
# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
rm -f conftest.i conftest.err conftest.$ac_ext
-if $ac_preproc_ok; then :
+if $ac_preproc_ok
+then :
-else
- { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
-$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+else $as_nop
+ { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;}
as_fn_error $? "C preprocessor \"$CPP\" fails sanity check
See \`config.log' for more details" "$LINENO" 5; }
fi
@@ -4346,7 +4277,8 @@ ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
ac_compiler_gnu=$ac_cv_c_compiler_gnu
-# Find a good install program. We prefer a C program (faster),
+
+ # Find a good install program. We prefer a C program (faster),
# so one script is as good as another. But avoid the broken or
# incompatible versions:
# SysV /etc/install, /usr/sbin/install
@@ -4360,20 +4292,25 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu
# OS/2's system install, which has a completely different semantic
# ./install, which can be erroneously created by make from ./install.sh.
# Reject install programs that cannot install multiple files.
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5
-$as_echo_n "checking for a BSD-compatible install... " >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5
+printf %s "checking for a BSD-compatible install... " >&6; }
if test -z "$INSTALL"; then
-if ${ac_cv_path_install+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+if test ${ac_cv_path_install+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
- # Account for people who put trailing slashes in PATH elements.
-case $as_dir/ in #((
- ./ | .// | /[cC]/* | \
+ case $as_dir in #(((
+ '') as_dir=./ ;;
+ */) ;;
+ *) as_dir=$as_dir/ ;;
+ esac
+ # Account for fact that we put trailing slashes in our PATH walk.
+case $as_dir in #((
+ ./ | /[cC]/* | \
/etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \
?:[\\/]os2[\\/]install[\\/]* | ?:[\\/]OS2[\\/]INSTALL[\\/]* | \
/usr/ucb/* ) ;;
@@ -4383,13 +4320,13 @@ case $as_dir/ in #((
# by default.
for ac_prog in ginstall scoinst install; do
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext"; then
+ if as_fn_executable_p "$as_dir$ac_prog$ac_exec_ext"; then
if test $ac_prog = install &&
- grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
+ grep dspmsg "$as_dir$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
# AIX install. It has an incompatible calling convention.
:
elif test $ac_prog = install &&
- grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
+ grep pwplus "$as_dir$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
# program-specific install script used by HP pwplus--don't use.
:
else
@@ -4397,12 +4334,12 @@ case $as_dir/ in #((
echo one > conftest.one
echo two > conftest.two
mkdir conftest.dir
- if "$as_dir/$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir" &&
+ if "$as_dir$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir/" &&
test -s conftest.one && test -s conftest.two &&
test -s conftest.dir/conftest.one &&
test -s conftest.dir/conftest.two
then
- ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c"
+ ac_cv_path_install="$as_dir$ac_prog$ac_exec_ext -c"
break 3
fi
fi
@@ -4418,7 +4355,7 @@ IFS=$as_save_IFS
rm -rf conftest.one conftest.two conftest.dir
fi
- if test "${ac_cv_path_install+set}" = set; then
+ if test ${ac_cv_path_install+y}; then
INSTALL=$ac_cv_path_install
else
# As a last resort, use the slow shell script. Don't cache a
@@ -4428,8 +4365,8 @@ fi
INSTALL=$ac_install_sh
fi
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5
-$as_echo "$INSTALL" >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5
+printf "%s\n" "$INSTALL" >&6; }
# Use test -z because SunOS4 sh mishandles braces in ${var-val}.
# It thinks the first close brace ends the variable substitution.
@@ -4442,11 +4379,12 @@ test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'
if test -n "$ac_tool_prefix"; then
# Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args.
set dummy ${ac_tool_prefix}ranlib; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_RANLIB+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+printf %s "checking for $ac_word... " >&6; }
+if test ${ac_cv_prog_RANLIB+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
if test -n "$RANLIB"; then
ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test.
else
@@ -4454,11 +4392,15 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
+ case $as_dir in #(((
+ '') as_dir=./ ;;
+ */) ;;
+ *) as_dir=$as_dir/ ;;
+ esac
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then
ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib"
- $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5
break 2
fi
done
@@ -4469,11 +4411,11 @@ fi
fi
RANLIB=$ac_cv_prog_RANLIB
if test -n "$RANLIB"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RANLIB" >&5
-$as_echo "$RANLIB" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $RANLIB" >&5
+printf "%s\n" "$RANLIB" >&6; }
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
fi
@@ -4482,11 +4424,12 @@ if test -z "$ac_cv_prog_RANLIB"; then
ac_ct_RANLIB=$RANLIB
# Extract the first word of "ranlib", so it can be a program name with args.
set dummy ranlib; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_ac_ct_RANLIB+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+printf %s "checking for $ac_word... " >&6; }
+if test ${ac_cv_prog_ac_ct_RANLIB+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
if test -n "$ac_ct_RANLIB"; then
ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test.
else
@@ -4494,11 +4437,15 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
+ case $as_dir in #(((
+ '') as_dir=./ ;;
+ */) ;;
+ *) as_dir=$as_dir/ ;;
+ esac
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then
ac_cv_prog_ac_ct_RANLIB="ranlib"
- $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5
break 2
fi
done
@@ -4509,11 +4456,11 @@ fi
fi
ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB
if test -n "$ac_ct_RANLIB"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RANLIB" >&5
-$as_echo "$ac_ct_RANLIB" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RANLIB" >&5
+printf "%s\n" "$ac_ct_RANLIB" >&6; }
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
fi
if test "x$ac_ct_RANLIB" = x; then
@@ -4521,8 +4468,8 @@ fi
else
case $cross_compiling:$ac_tool_warned in
yes:)
-{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
-$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
ac_tool_warned=yes ;;
esac
RANLIB=$ac_ct_RANLIB
@@ -4533,11 +4480,12 @@ fi
# Extract the first word of "flex", so it can be a program name with args.
set dummy flex; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_FLEX+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+printf %s "checking for $ac_word... " >&6; }
+if test ${ac_cv_prog_FLEX+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
if test -n "$FLEX"; then
ac_cv_prog_FLEX="$FLEX" # Let the user override the test.
else
@@ -4545,11 +4493,15 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
+ case $as_dir in #(((
+ '') as_dir=./ ;;
+ */) ;;
+ *) as_dir=$as_dir/ ;;
+ esac
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then
ac_cv_prog_FLEX="flex"
- $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5
break 2
fi
done
@@ -4560,21 +4512,22 @@ fi
fi
FLEX=$ac_cv_prog_FLEX
if test -n "$FLEX"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $FLEX" >&5
-$as_echo "$FLEX" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $FLEX" >&5
+printf "%s\n" "$FLEX" >&6; }
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
fi
# Extract the first word of "bison", so it can be a program name with args.
set dummy bison; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_BISON+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+printf %s "checking for $ac_word... " >&6; }
+if test ${ac_cv_prog_BISON+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
if test -n "$BISON"; then
ac_cv_prog_BISON="$BISON" # Let the user override the test.
else
@@ -4582,11 +4535,15 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
+ case $as_dir in #(((
+ '') as_dir=./ ;;
+ */) ;;
+ *) as_dir=$as_dir/ ;;
+ esac
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then
ac_cv_prog_BISON="bison"
- $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5
break 2
fi
done
@@ -4597,11 +4554,11 @@ fi
fi
BISON=$ac_cv_prog_BISON
if test -n "$BISON"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $BISON" >&5
-$as_echo "$BISON" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $BISON" >&5
+printf "%s\n" "$BISON" >&6; }
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
fi
@@ -4609,11 +4566,12 @@ for ac_prog in gm4 m4
do
# Extract the first word of "$ac_prog", so it can be a program name with args.
set dummy $ac_prog; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_M4+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+printf %s "checking for $ac_word... " >&6; }
+if test ${ac_cv_prog_M4+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
if test -n "$M4"; then
ac_cv_prog_M4="$M4" # Let the user override the test.
else
@@ -4621,11 +4579,15 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
for as_dir in $PATH
do
IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
+ case $as_dir in #(((
+ '') as_dir=./ ;;
+ */) ;;
+ *) as_dir=$as_dir/ ;;
+ esac
for ac_exec_ext in '' $ac_executable_extensions; do
- if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then
ac_cv_prog_M4="$ac_prog"
- $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5
break 2
fi
done
@@ -4636,11 +4598,11 @@ fi
fi
M4=$ac_cv_prog_M4
if test -n "$M4"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: $M4" >&5
-$as_echo "$M4" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $M4" >&5
+printf "%s\n" "$M4" >&6; }
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
fi
@@ -4652,8 +4614,8 @@ test -z "$FLEX" && as_fn_error $? "Flex is missing." "$LINENO" 5
test -z "$BISON" && as_fn_error $? "Bison is missing." "$LINENO" 5
test -z "$M4" && as_fn_error $? "M4 is missing." "$LINENO" 5
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking bison version" >&5
-$as_echo_n "checking bison version... " >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking bison version" >&5
+printf %s "checking bison version... " >&6; }
BISON_VERSION=`bison --version | ( read line; echo ${line##* } )`
case "$BISON_VERSION" in
@@ -4673,8 +4635,8 @@ $as_echo_n "checking bison version... " >&6; }
;;
esac
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $BISON_VERSION" >&5
-$as_echo "$BISON_VERSION" >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $BISON_VERSION" >&5
+printf "%s\n" "$BISON_VERSION" >&6; }
if test "$bird_bison_synclines" = yes && test "$enable_debug_generated" = no; then
M4FLAGS="$M4FLAGS -s"
fi
@@ -4743,25 +4705,23 @@ else
esac
sysdesc=$srcdir/sysdep/cf/$sysdesc.h
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking which OS configuration should we use" >&5
-$as_echo_n "checking which OS configuration should we use... " >&6; }
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $sysdesc" >&5
-$as_echo "$sysdesc" >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking which OS configuration should we use" >&5
+printf %s "checking which OS configuration should we use... " >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $sysdesc" >&5
+printf "%s\n" "$sysdesc" >&6; }
if ! test -f $sysdesc ; then
as_fn_error $? "The system configuration file is missing." "$LINENO" 5
fi
sysname=`echo $sysdesc | sed 's/\.h$//'`
-cat >>confdefs.h <<_ACEOF
-#define SYSCONF_INCLUDE "$sysdesc"
-_ACEOF
+printf "%s\n" "#define SYSCONF_INCLUDE \"$sysdesc\"" >>confdefs.h
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking system-dependent directories" >&5
-$as_echo_n "checking system-dependent directories... " >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking system-dependent directories" >&5
+printf %s "checking system-dependent directories... " >&6; }
sysdep_dirs="`sed <$sysdesc '/^Link: /!d;s/^Link: \(.*\)$/\1/' | tr '\012' ' '`"
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $sysdep_dirs" >&5
-$as_echo "$sysdep_dirs" >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $sysdep_dirs" >&5
+printf "%s\n" "$sysdep_dirs" >&6; }
if test "$with_iproutedir" = no ; then with_iproutedir= ; fi
@@ -4779,18 +4739,19 @@ DAEMON_LIBS=
if test "$enable_libssh" != no ; then
ac_fn_c_check_header_compile "$LINENO" "libssh/libssh.h" "ac_cv_header_libssh_libssh_h" "
"
-if test "x$ac_cv_header_libssh_libssh_h" = xyes; then :
+if test "x$ac_cv_header_libssh_libssh_h" = xyes
+then :
true
-else
+else $as_nop
fail=yes
fi
-
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ssh_connect in -lssh" >&5
-$as_echo_n "checking for ssh_connect in -lssh... " >&6; }
-if ${ac_cv_lib_ssh_ssh_connect+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for ssh_connect in -lssh" >&5
+printf %s "checking for ssh_connect in -lssh... " >&6; }
+if test ${ac_cv_lib_ssh_ssh_connect+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
ac_check_lib_save_LIBS=$LIBS
LIBS="-lssh $LIBS"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
@@ -4799,42 +4760,40 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* Override any GCC internal prototype to avoid an error.
Use char because int might match the return type of a GCC
builtin and then its argument prototype would still apply. */
-#ifdef __cplusplus
-extern "C"
-#endif
char ssh_connect ();
int
-main ()
+main (void)
{
return ssh_connect ();
;
return 0;
}
_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
+if ac_fn_c_try_link "$LINENO"
+then :
ac_cv_lib_ssh_ssh_connect=yes
-else
+else $as_nop
ac_cv_lib_ssh_ssh_connect=no
fi
-rm -f core conftest.err conftest.$ac_objext \
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
conftest$ac_exeext conftest.$ac_ext
LIBS=$ac_check_lib_save_LIBS
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ssh_ssh_connect" >&5
-$as_echo "$ac_cv_lib_ssh_ssh_connect" >&6; }
-if test "x$ac_cv_lib_ssh_ssh_connect" = xyes; then :
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ssh_ssh_connect" >&5
+printf "%s\n" "$ac_cv_lib_ssh_ssh_connect" >&6; }
+if test "x$ac_cv_lib_ssh_ssh_connect" = xyes
+then :
true
-else
+else $as_nop
fail=yes
fi
if test "$fail" != yes ; then
-$as_echo "#define HAVE_LIBSSH 1" >>confdefs.h
+printf "%s\n" "#define HAVE_LIBSSH 1" >>confdefs.h
DAEMON_LIBS="-lssh $DAEMON_LIBS"
- proto_rpki=rpki
enable_libssh=yes
else
if test "$enable_libssh" = yes ; then
@@ -4847,11 +4806,12 @@ fi
if test "$enable_mpls_kernel" != no ; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Linux MPLS headers" >&5
-$as_echo_n "checking for Linux MPLS headers... " >&6; }
-if ${bird_cv_mpls_kernel+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for Linux MPLS headers" >&5
+printf %s "checking for Linux MPLS headers... " >&6; }
+if test ${bird_cv_mpls_kernel+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
@@ -4864,7 +4824,7 @@ else
void t(int arg);
int
-main ()
+main (void)
{
t(AF_MPLS);
@@ -4881,23 +4841,24 @@ main ()
}
_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
+if ac_fn_c_try_compile "$LINENO"
+then :
bird_cv_mpls_kernel=yes
-else
+else $as_nop
bird_cv_mpls_kernel=no
fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $bird_cv_mpls_kernel" >&5
-$as_echo "$bird_cv_mpls_kernel" >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $bird_cv_mpls_kernel" >&5
+printf "%s\n" "$bird_cv_mpls_kernel" >&6; }
if test "$bird_cv_mpls_kernel" = yes ; then
-$as_echo "#define HAVE_MPLS_KERNEL 1" >>confdefs.h
+printf "%s\n" "#define HAVE_MPLS_KERNEL 1" >>confdefs.h
elif test "$enable_mpls_kernel" = yes ; then
as_fn_error $? "Kernel MPLS support not found." "$LINENO" 5
@@ -4908,7 +4869,7 @@ $as_echo "#define HAVE_MPLS_KERNEL 1" >>confdefs.h
fi
fi
-all_protocols="$proto_bfd babel bgp mrt ospf perf pipe radv rip $proto_rpki static"
+all_protocols="$proto_bfd babel bgp mrt ospf perf pipe radv rip rpki static"
all_protocols=`echo $all_protocols | sed 's/ /,/g'`
@@ -4927,14 +4888,14 @@ fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking protocols" >&5
-$as_echo_n "checking protocols... " >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking protocols" >&5
+printf %s "checking protocols... " >&6; }
protocols=`echo "$with_protocols" | sed 's/,/ /g'`
if test "$protocols" = no ; then protocols= ; fi
for a in $protocols ; do
if ! test -f $srcdir/proto/$a/Makefile ; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: result: failed" >&5
-$as_echo "failed" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: failed" >&5
+printf "%s\n" "failed" >&6; }
as_fn_error $? "Requested protocol $a not found" "$LINENO" 5
fi
cat >>confdefs.h <<_ACEOF
@@ -4942,8 +4903,8 @@ $as_echo "failed" >&6; }
_ACEOF
done
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: ok" >&5
-$as_echo "ok" >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: ok" >&5
+printf "%s\n" "ok" >&6; }
case $sysdesc in
@@ -4954,315 +4915,63 @@ case $sysdesc in
"
-if test "x$ac_cv_header_linux_rtnetlink_h" = xyes; then :
+if test "x$ac_cv_header_linux_rtnetlink_h" = xyes
+then :
-else
+else $as_nop
as_fn_error $? "Appropriate version of Linux kernel headers not found." "$LINENO" 5
fi
-
;;
esac
-
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5
-$as_echo_n "checking for grep that handles long lines and -e... " >&6; }
-if ${ac_cv_path_GREP+:} false; then :
- $as_echo_n "(cached) " >&6
-else
- if test -z "$GREP"; then
- ac_path_GREP_found=false
- # Loop through the user's path and test for each of PROGNAME-LIST
- as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
-do
- IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
- for ac_prog in grep ggrep; do
- for ac_exec_ext in '' $ac_executable_extensions; do
- ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext"
- as_fn_executable_p "$ac_path_GREP" || continue
-# Check for GNU ac_path_GREP and select it if it is found.
- # Check for GNU $ac_path_GREP
-case `"$ac_path_GREP" --version 2>&1` in
-*GNU*)
- ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;;
-*)
- ac_count=0
- $as_echo_n 0123456789 >"conftest.in"
- while :
- do
- cat "conftest.in" "conftest.in" >"conftest.tmp"
- mv "conftest.tmp" "conftest.in"
- cp "conftest.in" "conftest.nl"
- $as_echo 'GREP' >> "conftest.nl"
- "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break
- diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
- as_fn_arith $ac_count + 1 && ac_count=$as_val
- if test $ac_count -gt ${ac_path_GREP_max-0}; then
- # Best one so far, save it but keep looking for a better one
- ac_cv_path_GREP="$ac_path_GREP"
- ac_path_GREP_max=$ac_count
- fi
- # 10*(2^10) chars as input seems more than enough
- test $ac_count -gt 10 && break
- done
- rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
-esac
-
- $ac_path_GREP_found && break 3
- done
- done
- done
-IFS=$as_save_IFS
- if test -z "$ac_cv_path_GREP"; then
- as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5
- fi
-else
- ac_cv_path_GREP=$GREP
-fi
-
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5
-$as_echo "$ac_cv_path_GREP" >&6; }
- GREP="$ac_cv_path_GREP"
-
-
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5
-$as_echo_n "checking for egrep... " >&6; }
-if ${ac_cv_path_EGREP+:} false; then :
- $as_echo_n "(cached) " >&6
-else
- if echo a | $GREP -E '(a|b)' >/dev/null 2>&1
- then ac_cv_path_EGREP="$GREP -E"
- else
- if test -z "$EGREP"; then
- ac_path_EGREP_found=false
- # Loop through the user's path and test for each of PROGNAME-LIST
- as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
+ac_header= ac_cache=
+for ac_item in $ac_header_c_list
do
- IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
- for ac_prog in egrep; do
- for ac_exec_ext in '' $ac_executable_extensions; do
- ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext"
- as_fn_executable_p "$ac_path_EGREP" || continue
-# Check for GNU ac_path_EGREP and select it if it is found.
- # Check for GNU $ac_path_EGREP
-case `"$ac_path_EGREP" --version 2>&1` in
-*GNU*)
- ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;;
-*)
- ac_count=0
- $as_echo_n 0123456789 >"conftest.in"
- while :
- do
- cat "conftest.in" "conftest.in" >"conftest.tmp"
- mv "conftest.tmp" "conftest.in"
- cp "conftest.in" "conftest.nl"
- $as_echo 'EGREP' >> "conftest.nl"
- "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break
- diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
- as_fn_arith $ac_count + 1 && ac_count=$as_val
- if test $ac_count -gt ${ac_path_EGREP_max-0}; then
- # Best one so far, save it but keep looking for a better one
- ac_cv_path_EGREP="$ac_path_EGREP"
- ac_path_EGREP_max=$ac_count
+ if test $ac_cache; then
+ ac_fn_c_check_header_compile "$LINENO" $ac_header ac_cv_header_$ac_cache "$ac_includes_default"
+ if eval test \"x\$ac_cv_header_$ac_cache\" = xyes; then
+ printf "%s\n" "#define $ac_item 1" >> confdefs.h
fi
- # 10*(2^10) chars as input seems more than enough
- test $ac_count -gt 10 && break
- done
- rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
-esac
-
- $ac_path_EGREP_found && break 3
- done
- done
- done
-IFS=$as_save_IFS
- if test -z "$ac_cv_path_EGREP"; then
- as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5
+ ac_header= ac_cache=
+ elif test $ac_header; then
+ ac_cache=$ac_item
+ else
+ ac_header=$ac_item
fi
-else
- ac_cv_path_EGREP=$EGREP
-fi
-
- fi
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5
-$as_echo "$ac_cv_path_EGREP" >&6; }
- EGREP="$ac_cv_path_EGREP"
-
-
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5
-$as_echo_n "checking for ANSI C header files... " >&6; }
-if ${ac_cv_header_stdc+:} false; then :
- $as_echo_n "(cached) " >&6
-else
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-#include <stdlib.h>
-#include <stdarg.h>
-#include <string.h>
-#include <float.h>
-
-int
-main ()
-{
-
- ;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
- ac_cv_header_stdc=yes
-else
- ac_cv_header_stdc=no
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-
-if test $ac_cv_header_stdc = yes; then
- # SunOS 4.x string.h does not declare mem*, contrary to ANSI.
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-#include <string.h>
-
-_ACEOF
-if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
- $EGREP "memchr" >/dev/null 2>&1; then :
-
-else
- ac_cv_header_stdc=no
-fi
-rm -f conftest*
-
-fi
-
-if test $ac_cv_header_stdc = yes; then
- # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI.
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-#include <stdlib.h>
-
-_ACEOF
-if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
- $EGREP "free" >/dev/null 2>&1; then :
-
-else
- ac_cv_header_stdc=no
-fi
-rm -f conftest*
-
-fi
-
-if test $ac_cv_header_stdc = yes; then
- # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi.
- if test "$cross_compiling" = yes; then :
- :
-else
- cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h. */
-#include <ctype.h>
-#include <stdlib.h>
-#if ((' ' & 0x0FF) == 0x020)
-# define ISLOWER(c) ('a' <= (c) && (c) <= 'z')
-# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c))
-#else
-# define ISLOWER(c) \
- (('a' <= (c) && (c) <= 'i') \
- || ('j' <= (c) && (c) <= 'r') \
- || ('s' <= (c) && (c) <= 'z'))
-# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c))
-#endif
-
-#define XOR(e, f) (((e) && !(f)) || (!(e) && (f)))
-int
-main ()
-{
- int i;
- for (i = 0; i < 256; i++)
- if (XOR (islower (i), ISLOWER (i))
- || toupper (i) != TOUPPER (i))
- return 2;
- return 0;
-}
-_ACEOF
-if ac_fn_c_try_run "$LINENO"; then :
-
-else
- ac_cv_header_stdc=no
-fi
-rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
- conftest.$ac_objext conftest.beam conftest.$ac_ext
-fi
-
-fi
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5
-$as_echo "$ac_cv_header_stdc" >&6; }
-if test $ac_cv_header_stdc = yes; then
-
-$as_echo "#define STDC_HEADERS 1" >>confdefs.h
-
-fi
-
-# On IRIX 5.3, sys/types and inttypes.h are conflicting.
-for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \
- inttypes.h stdint.h unistd.h
-do :
- as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
-ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default
-"
-if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
- cat >>confdefs.h <<_ACEOF
-#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
-_ACEOF
-
-fi
-
done
- for ac_header in $ac_header_list
-do :
- as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
-ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default
-"
-if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
- cat >>confdefs.h <<_ACEOF
-#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
-_ACEOF
-
-fi
-done
+printf "%s\n" "#define HAVE_STDLIB_H 1" >>confdefs.h
+printf "%s\n" "#define HAVE_STRING_H 1" >>confdefs.h
+printf "%s\n" "#define STDC_HEADERS 1" >>confdefs.h
ac_fn_c_check_member "$LINENO" "struct sockaddr" "sa_len" "ac_cv_member_struct_sockaddr_sa_len" "#include <sys/socket.h>
"
-if test "x$ac_cv_member_struct_sockaddr_sa_len" = xyes; then :
+if test "x$ac_cv_member_struct_sockaddr_sa_len" = xyes
+then :
-cat >>confdefs.h <<_ACEOF
-#define HAVE_STRUCT_SOCKADDR_SA_LEN 1
-_ACEOF
+printf "%s\n" "#define HAVE_STRUCT_SOCKADDR_SA_LEN 1" >>confdefs.h
fi
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether byte ordering is bigendian" >&5
-$as_echo_n "checking whether byte ordering is bigendian... " >&6; }
-if ${ac_cv_c_bigendian+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether byte ordering is bigendian" >&5
+printf %s "checking whether byte ordering is bigendian... " >&6; }
+if test ${ac_cv_c_bigendian+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
ac_cv_c_bigendian=unknown
# See if we're dealing with a universal compiler.
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
@@ -5273,7 +4982,8 @@ else
typedef int dummy;
_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
+if ac_fn_c_try_compile "$LINENO"
+then :
# Check for potential -arch flags. It is not universal unless
# there are at least two -arch flags with different values.
@@ -5297,7 +5007,7 @@ if ac_fn_c_try_compile "$LINENO"; then :
fi
done
fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
if test $ac_cv_c_bigendian = unknown; then
# See if sys/param.h defines the BYTE_ORDER macro.
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
@@ -5306,7 +5016,7 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
#include <sys/param.h>
int
-main ()
+main (void)
{
#if ! (defined BYTE_ORDER && defined BIG_ENDIAN \
&& defined LITTLE_ENDIAN && BYTE_ORDER && BIG_ENDIAN \
@@ -5318,7 +5028,8 @@ main ()
return 0;
}
_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
+if ac_fn_c_try_compile "$LINENO"
+then :
# It does; now see whether it defined to BIG_ENDIAN or not.
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
@@ -5326,7 +5037,7 @@ if ac_fn_c_try_compile "$LINENO"; then :
#include <sys/param.h>
int
-main ()
+main (void)
{
#if BYTE_ORDER != BIG_ENDIAN
not big endian
@@ -5336,14 +5047,15 @@ main ()
return 0;
}
_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
+if ac_fn_c_try_compile "$LINENO"
+then :
ac_cv_c_bigendian=yes
-else
+else $as_nop
ac_cv_c_bigendian=no
fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
fi
if test $ac_cv_c_bigendian = unknown; then
# See if <limits.h> defines _LITTLE_ENDIAN or _BIG_ENDIAN (e.g., Solaris).
@@ -5352,7 +5064,7 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
#include <limits.h>
int
-main ()
+main (void)
{
#if ! (defined _LITTLE_ENDIAN || defined _BIG_ENDIAN)
bogus endian macros
@@ -5362,14 +5074,15 @@ main ()
return 0;
}
_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
+if ac_fn_c_try_compile "$LINENO"
+then :
# It does; now see whether it defined to _BIG_ENDIAN or not.
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <limits.h>
int
-main ()
+main (void)
{
#ifndef _BIG_ENDIAN
not big endian
@@ -5379,31 +5092,33 @@ main ()
return 0;
}
_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
+if ac_fn_c_try_compile "$LINENO"
+then :
ac_cv_c_bigendian=yes
-else
+else $as_nop
ac_cv_c_bigendian=no
fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
fi
if test $ac_cv_c_bigendian = unknown; then
# Compile a test program.
- if test "$cross_compiling" = yes; then :
+ if test "$cross_compiling" = yes
+then :
# Try to guess by grepping values from an object file.
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
-short int ascii_mm[] =
+unsigned short int ascii_mm[] =
{ 0x4249, 0x4765, 0x6E44, 0x6961, 0x6E53, 0x7953, 0 };
- short int ascii_ii[] =
+ unsigned short int ascii_ii[] =
{ 0x694C, 0x5454, 0x656C, 0x6E45, 0x6944, 0x6E61, 0 };
int use_ascii (int i) {
return ascii_mm[i] + ascii_ii[i];
}
- short int ebcdic_ii[] =
+ unsigned short int ebcdic_ii[] =
{ 0x89D3, 0xE3E3, 0x8593, 0x95C5, 0x89C4, 0x9581, 0 };
- short int ebcdic_mm[] =
+ unsigned short int ebcdic_mm[] =
{ 0xC2C9, 0xC785, 0x95C4, 0x8981, 0x95E2, 0xA8E2, 0 };
int use_ebcdic (int i) {
return ebcdic_mm[i] + ebcdic_ii[i];
@@ -5411,14 +5126,15 @@ short int ascii_mm[] =
extern int foo;
int
-main ()
+main (void)
{
return use_ascii (foo) == use_ebcdic (foo);
;
return 0;
}
_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
+if ac_fn_c_try_compile "$LINENO"
+then :
if grep BIGenDianSyS conftest.$ac_objext >/dev/null; then
ac_cv_c_bigendian=yes
fi
@@ -5431,13 +5147,13 @@ if ac_fn_c_try_compile "$LINENO"; then :
fi
fi
fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-else
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
+else $as_nop
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
$ac_includes_default
int
-main ()
+main (void)
{
/* Are we little or big endian? From Harbison&Steele. */
@@ -5453,9 +5169,10 @@ main ()
return 0;
}
_ACEOF
-if ac_fn_c_try_run "$LINENO"; then :
+if ac_fn_c_try_run "$LINENO"
+then :
ac_cv_c_bigendian=no
-else
+else $as_nop
ac_cv_c_bigendian=yes
fi
rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
@@ -5464,20 +5181,20 @@ fi
fi
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_bigendian" >&5
-$as_echo "$ac_cv_c_bigendian" >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_bigendian" >&5
+printf "%s\n" "$ac_cv_c_bigendian" >&6; }
case $ac_cv_c_bigendian in #(
yes)
-$as_echo "#define CPU_BIG_ENDIAN 1" >>confdefs.h
+printf "%s\n" "#define CPU_BIG_ENDIAN 1" >>confdefs.h
;; #(
no)
-$as_echo "#define CPU_LITTLE_ENDIAN 1" >>confdefs.h
+printf "%s\n" "#define CPU_LITTLE_ENDIAN 1" >>confdefs.h
;; #(
universal)
-$as_echo "#define AC_APPLE_UNIVERSAL_BUILD 1" >>confdefs.h
+printf "%s\n" "#define AC_APPLE_UNIVERSAL_BUILD 1" >>confdefs.h
;; #(
*)
@@ -5487,11 +5204,12 @@ $as_echo "#define AC_APPLE_UNIVERSAL_BUILD 1" >>confdefs.h
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for glob.h" >&5
-$as_echo_n "checking for glob.h... " >&6; }
-if ${bird_cv_lib_glob+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for glob.h" >&5
+printf %s "checking for glob.h... " >&6; }
+if test ${bird_cv_lib_glob+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
@@ -5500,7 +5218,7 @@ else
#include <stdlib.h>
int
-main ()
+main (void)
{
glob(NULL, 0, NULL, NULL);
@@ -5509,9 +5227,10 @@ main ()
}
_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
+if ac_fn_c_try_link "$LINENO"
+then :
bird_cv_lib_glob=yes
-else
+else $as_nop
bird_tmp_libs="$LIBS"
LIBS="$LIBS -landroid-glob"
@@ -5523,7 +5242,7 @@ else
#include <stdlib.h>
int
-main ()
+main (void)
{
glob(NULL, 0, NULL, NULL);
@@ -5532,24 +5251,25 @@ main ()
}
_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
+if ac_fn_c_try_link "$LINENO"
+then :
bird_cv_lib_glob=-landroid-glob
-else
+else $as_nop
bird_cv_lib_glob=no
fi
-rm -f core conftest.err conftest.$ac_objext \
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
conftest$ac_exeext conftest.$ac_ext
LIBS="$bird_tmp_libs"
fi
-rm -f core conftest.err conftest.$ac_objext \
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
conftest$ac_exeext conftest.$ac_ext
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $bird_cv_lib_glob" >&5
-$as_echo "$bird_cv_lib_glob" >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $bird_cv_lib_glob" >&5
+printf "%s\n" "$bird_cv_lib_glob" >&6; }
if test "$bird_cv_lib_glob" = no ; then
as_fn_error $? "glob.h not found." "$LINENO" 5
@@ -5558,17 +5278,18 @@ elif test "$bird_cv_lib_glob" != yes ; then
fi
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for syslog lib flags" >&5
-$as_echo_n "checking for syslog lib flags... " >&6; }
-if ${bird_cv_lib_log+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for syslog lib flags" >&5
+printf %s "checking for syslog lib flags... " >&6; }
+if test ${bird_cv_lib_log+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <sys/syslog.h>
int
-main ()
+main (void)
{
syslog(0, "");
@@ -5577,9 +5298,10 @@ main ()
}
_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
+if ac_fn_c_try_link "$LINENO"
+then :
bird_cv_lib_log=yes
-else
+else $as_nop
bird_tmp_libs="$LIBS"
LIBS="$LIBS -llog"
@@ -5588,7 +5310,7 @@ else
#include <sys/syslog.h>
int
-main ()
+main (void)
{
syslog(0, "");
@@ -5597,24 +5319,25 @@ main ()
}
_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
+if ac_fn_c_try_link "$LINENO"
+then :
bird_cv_lib_log=-llog
-else
+else $as_nop
bird_cv_lib_log=no
fi
-rm -f core conftest.err conftest.$ac_objext \
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
conftest$ac_exeext conftest.$ac_ext
LIBS="$bird_tmp_libs"
fi
-rm -f core conftest.err conftest.$ac_objext \
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
conftest$ac_exeext conftest.$ac_ext
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $bird_cv_lib_log" >&5
-$as_echo "$bird_cv_lib_log" >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $bird_cv_lib_log" >&5
+printf "%s\n" "$bird_cv_lib_log" >&6; }
if test "$bird_cv_lib_log" = no ; then
as_fn_error $? "don't know how to link syslog." "$LINENO" 5
@@ -5624,7 +5347,7 @@ fi
if test "$enable_debug" = yes ; then
-$as_echo "#define DEBUGGING 1" >>confdefs.h
+printf "%s\n" "#define DEBUGGING 1" >>confdefs.h
LDFLAGS="$LDFLAGS -rdynamic"
CFLAGS="$CFLAGS -O0 -ggdb -g3"
@@ -5633,35 +5356,37 @@ $as_echo "#define DEBUGGING 1" >>confdefs.h
bird_tmp_cflags="$CFLAGS"
CFLAGS=" -gdwarf-4"
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether CC supports -gdwarf-4" >&5
-$as_echo_n "checking whether CC supports -gdwarf-4... " >&6; }
-if ${bird_cv_c_option_dwarf4+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether CC supports -gdwarf-4" >&5
+printf %s "checking whether CC supports -gdwarf-4... " >&6; }
+if test ${bird_cv_c_option_dwarf4+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
int
-main ()
+main (void)
{
;
return 0;
}
_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
+if ac_fn_c_try_compile "$LINENO"
+then :
bird_cv_c_option_dwarf4=yes
-else
+else $as_nop
bird_cv_c_option_dwarf4=no
fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $bird_cv_c_option_dwarf4" >&5
-$as_echo "$bird_cv_c_option_dwarf4" >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $bird_cv_c_option_dwarf4" >&5
+printf "%s\n" "$bird_cv_c_option_dwarf4" >&6; }
CFLAGS="$bird_tmp_cflags"
@@ -5671,17 +5396,19 @@ $as_echo "$bird_cv_c_option_dwarf4" >&6; }
fi
- ac_fn_c_check_header_mongrel "$LINENO" "execinfo.h" "ac_cv_header_execinfo_h" "$ac_includes_default"
-if test "x$ac_cv_header_execinfo_h" = xyes; then :
+ ac_fn_c_check_header_compile "$LINENO" "execinfo.h" "ac_cv_header_execinfo_h" "$ac_includes_default"
+if test "x$ac_cv_header_execinfo_h" = xyes
+then :
-$as_echo "#define HAVE_EXECINFO_H 1" >>confdefs.h
+printf "%s\n" "#define HAVE_EXECINFO_H 1" >>confdefs.h
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing backtrace" >&5
-$as_echo_n "checking for library containing backtrace... " >&6; }
-if ${ac_cv_search_backtrace+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for library containing backtrace" >&5
+printf %s "checking for library containing backtrace... " >&6; }
+if test ${ac_cv_search_backtrace+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
ac_func_search_save_LIBS=$LIBS
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
@@ -5689,49 +5416,51 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* Override any GCC internal prototype to avoid an error.
Use char because int might match the return type of a GCC
builtin and then its argument prototype would still apply. */
-#ifdef __cplusplus
-extern "C"
-#endif
char backtrace ();
int
-main ()
+main (void)
{
return backtrace ();
;
return 0;
}
_ACEOF
-for ac_lib in '' execinfo; do
+for ac_lib in '' execinfo
+do
if test -z "$ac_lib"; then
ac_res="none required"
else
ac_res=-l$ac_lib
LIBS="-l$ac_lib $ac_func_search_save_LIBS"
fi
- if ac_fn_c_try_link "$LINENO"; then :
+ if ac_fn_c_try_link "$LINENO"
+then :
ac_cv_search_backtrace=$ac_res
fi
-rm -f core conftest.err conftest.$ac_objext \
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
conftest$ac_exeext
- if ${ac_cv_search_backtrace+:} false; then :
+ if test ${ac_cv_search_backtrace+y}
+then :
break
fi
done
-if ${ac_cv_search_backtrace+:} false; then :
+if test ${ac_cv_search_backtrace+y}
+then :
-else
+else $as_nop
ac_cv_search_backtrace=no
fi
rm conftest.$ac_ext
LIBS=$ac_func_search_save_LIBS
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_backtrace" >&5
-$as_echo "$ac_cv_search_backtrace" >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_backtrace" >&5
+printf "%s\n" "$ac_cv_search_backtrace" >&6; }
ac_res=$ac_cv_search_backtrace
-if test "$ac_res" != no; then :
+if test "$ac_res" != no
+then :
test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
-else
+else $as_nop
as_fn_error $? "Function backtrace not available." "$LINENO" 5
fi
@@ -5741,13 +5470,13 @@ fi
fi
-
if test "$enable_memcheck" = yes ; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dmalloc_debug in -ldmalloc" >&5
-$as_echo_n "checking for dmalloc_debug in -ldmalloc... " >&6; }
-if ${ac_cv_lib_dmalloc_dmalloc_debug+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for dmalloc_debug in -ldmalloc" >&5
+printf %s "checking for dmalloc_debug in -ldmalloc... " >&6; }
+if test ${ac_cv_lib_dmalloc_dmalloc_debug+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
ac_check_lib_save_LIBS=$LIBS
LIBS="-ldmalloc $LIBS"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
@@ -5756,44 +5485,42 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* Override any GCC internal prototype to avoid an error.
Use char because int might match the return type of a GCC
builtin and then its argument prototype would still apply. */
-#ifdef __cplusplus
-extern "C"
-#endif
char dmalloc_debug ();
int
-main ()
+main (void)
{
return dmalloc_debug ();
;
return 0;
}
_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
+if ac_fn_c_try_link "$LINENO"
+then :
ac_cv_lib_dmalloc_dmalloc_debug=yes
-else
+else $as_nop
ac_cv_lib_dmalloc_dmalloc_debug=no
fi
-rm -f core conftest.err conftest.$ac_objext \
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
conftest$ac_exeext conftest.$ac_ext
LIBS=$ac_check_lib_save_LIBS
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dmalloc_dmalloc_debug" >&5
-$as_echo "$ac_cv_lib_dmalloc_dmalloc_debug" >&6; }
-if test "x$ac_cv_lib_dmalloc_dmalloc_debug" = xyes; then :
- cat >>confdefs.h <<_ACEOF
-#define HAVE_LIBDMALLOC 1
-_ACEOF
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dmalloc_dmalloc_debug" >&5
+printf "%s\n" "$ac_cv_lib_dmalloc_dmalloc_debug" >&6; }
+if test "x$ac_cv_lib_dmalloc_dmalloc_debug" = xyes
+then :
+ printf "%s\n" "#define HAVE_LIBDMALLOC 1" >>confdefs.h
LIBS="-ldmalloc $LIBS"
fi
if test $ac_cv_lib_dmalloc_dmalloc_debug != yes ; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for malloc in -lefence" >&5
-$as_echo_n "checking for malloc in -lefence... " >&6; }
-if ${ac_cv_lib_efence_malloc+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for malloc in -lefence" >&5
+printf %s "checking for malloc in -lefence... " >&6; }
+if test ${ac_cv_lib_efence_malloc+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
ac_check_lib_save_LIBS=$LIBS
LIBS="-lefence $LIBS"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
@@ -5802,33 +5529,30 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* Override any GCC internal prototype to avoid an error.
Use char because int might match the return type of a GCC
builtin and then its argument prototype would still apply. */
-#ifdef __cplusplus
-extern "C"
-#endif
char malloc ();
int
-main ()
+main (void)
{
return malloc ();
;
return 0;
}
_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
+if ac_fn_c_try_link "$LINENO"
+then :
ac_cv_lib_efence_malloc=yes
-else
+else $as_nop
ac_cv_lib_efence_malloc=no
fi
-rm -f core conftest.err conftest.$ac_objext \
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
conftest$ac_exeext conftest.$ac_ext
LIBS=$ac_check_lib_save_LIBS
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_efence_malloc" >&5
-$as_echo "$ac_cv_lib_efence_malloc" >&6; }
-if test "x$ac_cv_lib_efence_malloc" = xyes; then :
- cat >>confdefs.h <<_ACEOF
-#define HAVE_LIBEFENCE 1
-_ACEOF
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_efence_malloc" >&5
+printf "%s\n" "$ac_cv_lib_efence_malloc" >&6; }
+if test "x$ac_cv_lib_efence_malloc" = xyes
+then :
+ printf "%s\n" "#define HAVE_LIBEFENCE 1" >>confdefs.h
LIBS="-lefence $LIBS"
@@ -5836,6 +5560,12 @@ fi
fi
fi
+
+ if test "enable_debug_expensive" = yes ; then
+
+printf "%s\n" "#define ENABLE_EXPENSIVE_CHECKS 1" >>confdefs.h
+
+ fi
fi
CLIENT=birdcl
@@ -5845,28 +5575,27 @@ if test "$enable_client" = yes ; then
BASE_LIBS="$LIBS"
LIBS=""
- for ac_header in curses.h
+ for ac_header in curses.h
do :
ac_fn_c_check_header_compile "$LINENO" "curses.h" "ac_cv_header_curses_h" "$ac_includes_default
"
-if test "x$ac_cv_header_curses_h" = xyes; then :
- cat >>confdefs.h <<_ACEOF
-#define HAVE_CURSES_H 1
-_ACEOF
+if test "x$ac_cv_header_curses_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_CURSES_H 1" >>confdefs.h
-else
+else $as_nop
as_fn_error $? "The client requires ncurses library. Either install the library or use --disable-client to compile without the client." "$LINENO" 5
fi
done
-
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing tgetent" >&5
-$as_echo_n "checking for library containing tgetent... " >&6; }
-if ${ac_cv_search_tgetent+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for library containing tgetent" >&5
+printf %s "checking for library containing tgetent... " >&6; }
+if test ${ac_cv_search_tgetent+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
ac_func_search_save_LIBS=$LIBS
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
@@ -5874,76 +5603,79 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* Override any GCC internal prototype to avoid an error.
Use char because int might match the return type of a GCC
builtin and then its argument prototype would still apply. */
-#ifdef __cplusplus
-extern "C"
-#endif
char tgetent ();
int
-main ()
+main (void)
{
return tgetent ();
;
return 0;
}
_ACEOF
-for ac_lib in '' tinfo tinfow ncurses curses termcap; do
+for ac_lib in '' tinfo tinfow ncurses curses termcap
+do
if test -z "$ac_lib"; then
ac_res="none required"
else
ac_res=-l$ac_lib
LIBS="-l$ac_lib $ac_func_search_save_LIBS"
fi
- if ac_fn_c_try_link "$LINENO"; then :
+ if ac_fn_c_try_link "$LINENO"
+then :
ac_cv_search_tgetent=$ac_res
fi
-rm -f core conftest.err conftest.$ac_objext \
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
conftest$ac_exeext
- if ${ac_cv_search_tgetent+:} false; then :
+ if test ${ac_cv_search_tgetent+y}
+then :
break
fi
done
-if ${ac_cv_search_tgetent+:} false; then :
+if test ${ac_cv_search_tgetent+y}
+then :
-else
+else $as_nop
ac_cv_search_tgetent=no
fi
rm conftest.$ac_ext
LIBS=$ac_func_search_save_LIBS
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_tgetent" >&5
-$as_echo "$ac_cv_search_tgetent" >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_tgetent" >&5
+printf "%s\n" "$ac_cv_search_tgetent" >&6; }
ac_res=$ac_cv_search_tgetent
-if test "$ac_res" != no; then :
+if test "$ac_res" != no
+then :
test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
TINFO_LIBS="$LIBS"; LIBS=""
-else
+else $as_nop
as_fn_error $? "The client requires ncurses library. Either install the library or use --disable-client to compile without the client." "$LINENO" 5
fi
- for ac_header in readline/readline.h readline/history.h
+ for ac_header in readline/readline.h readline/history.h
do :
- as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
+ as_ac_Header=`printf "%s\n" "ac_cv_header_$ac_header" | $as_tr_sh`
ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default
"
-if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
+if eval test \"x\$"$as_ac_Header"\" = x"yes"
+then :
cat >>confdefs.h <<_ACEOF
-#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
+#define `printf "%s\n" "HAVE_$ac_header" | $as_tr_cpp` 1
_ACEOF
-else
+else $as_nop
as_fn_error $? "The client requires GNU Readline library. Either install the library or use --disable-client to compile without the client." "$LINENO" 5
fi
done
-
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing rl_callback_read_char" >&5
-$as_echo_n "checking for library containing rl_callback_read_char... " >&6; }
-if ${ac_cv_search_rl_callback_read_char+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for library containing rl_callback_read_char" >&5
+printf %s "checking for library containing rl_callback_read_char... " >&6; }
+if test ${ac_cv_search_rl_callback_read_char+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
ac_func_search_save_LIBS=$LIBS
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
@@ -5951,19 +5683,17 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* Override any GCC internal prototype to avoid an error.
Use char because int might match the return type of a GCC
builtin and then its argument prototype would still apply. */
-#ifdef __cplusplus
-extern "C"
-#endif
char rl_callback_read_char ();
int
-main ()
+main (void)
{
return rl_callback_read_char ();
;
return 0;
}
_ACEOF
-for ac_lib in '' readline; do
+for ac_lib in '' readline
+do
if test -z "$ac_lib"; then
ac_res="none required"
else
@@ -5971,39 +5701,44 @@ for ac_lib in '' readline; do
LIBS="-l$ac_lib $TINFO_LIBS
$ac_func_search_save_LIBS"
fi
- if ac_fn_c_try_link "$LINENO"; then :
+ if ac_fn_c_try_link "$LINENO"
+then :
ac_cv_search_rl_callback_read_char=$ac_res
fi
-rm -f core conftest.err conftest.$ac_objext \
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
conftest$ac_exeext
- if ${ac_cv_search_rl_callback_read_char+:} false; then :
+ if test ${ac_cv_search_rl_callback_read_char+y}
+then :
break
fi
done
-if ${ac_cv_search_rl_callback_read_char+:} false; then :
+if test ${ac_cv_search_rl_callback_read_char+y}
+then :
-else
+else $as_nop
ac_cv_search_rl_callback_read_char=no
fi
rm conftest.$ac_ext
LIBS=$ac_func_search_save_LIBS
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_rl_callback_read_char" >&5
-$as_echo "$ac_cv_search_rl_callback_read_char" >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_rl_callback_read_char" >&5
+printf "%s\n" "$ac_cv_search_rl_callback_read_char" >&6; }
ac_res=$ac_cv_search_rl_callback_read_char
-if test "$ac_res" != no; then :
+if test "$ac_res" != no
+then :
test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
READLINE_LIBS="$LIBS"; LIBS=""
-else
+else $as_nop
as_fn_error $? "The client requires GNU Readline library. Either install the library or use --disable-client to compile without the client." "$LINENO" 5
fi
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for rl_crlf in -lreadline" >&5
-$as_echo_n "checking for rl_crlf in -lreadline... " >&6; }
-if ${ac_cv_lib_readline_rl_crlf+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for rl_crlf in -lreadline" >&5
+printf %s "checking for rl_crlf in -lreadline... " >&6; }
+if test ${ac_cv_lib_readline_rl_crlf+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
ac_check_lib_save_LIBS=$LIBS
LIBS="-lreadline $TINFO_LIBS
$LIBS"
@@ -6013,41 +5748,41 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* Override any GCC internal prototype to avoid an error.
Use char because int might match the return type of a GCC
builtin and then its argument prototype would still apply. */
-#ifdef __cplusplus
-extern "C"
-#endif
char rl_crlf ();
int
-main ()
+main (void)
{
return rl_crlf ();
;
return 0;
}
_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
+if ac_fn_c_try_link "$LINENO"
+then :
ac_cv_lib_readline_rl_crlf=yes
-else
+else $as_nop
ac_cv_lib_readline_rl_crlf=no
fi
-rm -f core conftest.err conftest.$ac_objext \
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
conftest$ac_exeext conftest.$ac_ext
LIBS=$ac_check_lib_save_LIBS
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_readline_rl_crlf" >&5
-$as_echo "$ac_cv_lib_readline_rl_crlf" >&6; }
-if test "x$ac_cv_lib_readline_rl_crlf" = xyes; then :
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_readline_rl_crlf" >&5
+printf "%s\n" "$ac_cv_lib_readline_rl_crlf" >&6; }
+if test "x$ac_cv_lib_readline_rl_crlf" = xyes
+then :
-$as_echo "#define HAVE_RL_CRLF 1" >>confdefs.h
+printf "%s\n" "#define HAVE_RL_CRLF 1" >>confdefs.h
fi
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for rl_ding in -lreadline" >&5
-$as_echo_n "checking for rl_ding in -lreadline... " >&6; }
-if ${ac_cv_lib_readline_rl_ding+:} false; then :
- $as_echo_n "(cached) " >&6
-else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for rl_ding in -lreadline" >&5
+printf %s "checking for rl_ding in -lreadline... " >&6; }
+if test ${ac_cv_lib_readline_rl_ding+y}
+then :
+ printf %s "(cached) " >&6
+else $as_nop
ac_check_lib_save_LIBS=$LIBS
LIBS="-lreadline $TINFO_LIBS
$LIBS"
@@ -6057,32 +5792,31 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* Override any GCC internal prototype to avoid an error.
Use char because int might match the return type of a GCC
builtin and then its argument prototype would still apply. */
-#ifdef __cplusplus
-extern "C"
-#endif
char rl_ding ();
int
-main ()
+main (void)
{
return rl_ding ();
;
return 0;
}
_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
+if ac_fn_c_try_link "$LINENO"
+then :
ac_cv_lib_readline_rl_ding=yes
-else
+else $as_nop
ac_cv_lib_readline_rl_ding=no
fi
-rm -f core conftest.err conftest.$ac_objext \
+rm -f core conftest.err conftest.$ac_objext conftest.beam \
conftest$ac_exeext conftest.$ac_ext
LIBS=$ac_check_lib_save_LIBS
fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_readline_rl_ding" >&5
-$as_echo "$ac_cv_lib_readline_rl_ding" >&6; }
-if test "x$ac_cv_lib_readline_rl_ding" = xyes; then :
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_readline_rl_ding" >&5
+printf "%s\n" "$ac_cv_lib_readline_rl_ding" >&6; }
+if test "x$ac_cv_lib_readline_rl_ding" = xyes
+then :
-$as_echo "#define HAVE_RL_DING 1" >>confdefs.h
+printf "%s\n" "#define HAVE_RL_DING 1" >>confdefs.h
fi
@@ -6125,8 +5859,8 @@ _ACEOF
case $ac_val in #(
*${as_nl}*)
case $ac_var in #(
- *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
-$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
+ *_cv_*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
+printf "%s\n" "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
esac
case $ac_var in #(
_ | IFS | as_nl) ;; #(
@@ -6156,15 +5890,15 @@ $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
/^ac_cv_env_/b end
t clear
:clear
- s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/
+ s/^\([^=]*\)=\(.*[{}].*\)$/test ${\1+y} || &/
t end
s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/
:end' >>confcache
if diff "$cache_file" confcache >/dev/null 2>&1; then :; else
if test -w "$cache_file"; then
if test "x$cache_file" != "x/dev/null"; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5
-$as_echo "$as_me: updating cache $cache_file" >&6;}
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5
+printf "%s\n" "$as_me: updating cache $cache_file" >&6;}
if test ! -f "$cache_file" || test -h "$cache_file"; then
cat confcache >"$cache_file"
else
@@ -6178,8 +5912,8 @@ $as_echo "$as_me: updating cache $cache_file" >&6;}
fi
fi
else
- { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5
-$as_echo "$as_me: not updating unwritable cache $cache_file" >&6;}
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5
+printf "%s\n" "$as_me: not updating unwritable cache $cache_file" >&6;}
fi
fi
rm -f confcache
@@ -6196,7 +5930,7 @@ U=
for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue
# 1. Remove the extension, and $U if already installed.
ac_script='s/\$U\././;s/\.o$//;s/\.obj$//'
- ac_i=`$as_echo "$ac_i" | sed "$ac_script"`
+ ac_i=`printf "%s\n" "$ac_i" | sed "$ac_script"`
# 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR
# will be set to the directory where LIBOBJS objects are built.
as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext"
@@ -6213,8 +5947,8 @@ LTLIBOBJS=$ac_ltlibobjs
ac_write_fail=0
ac_clean_files_save=$ac_clean_files
ac_clean_files="$ac_clean_files $CONFIG_STATUS"
-{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5
-$as_echo "$as_me: creating $CONFIG_STATUS" >&6;}
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5
+printf "%s\n" "$as_me: creating $CONFIG_STATUS" >&6;}
as_write_fail=0
cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1
#! $SHELL
@@ -6237,14 +5971,16 @@ cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1
# Be more Bourne compatible
DUALCASE=1; export DUALCASE # for MKS sh
-if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
+as_nop=:
+if test ${ZSH_VERSION+y} && (emulate sh) >/dev/null 2>&1
+then :
emulate sh
NULLCMD=:
# Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
# is contrary to our usage. Disable this feature.
alias -g '${1+"$@"}'='"$@"'
setopt NO_GLOB_SUBST
-else
+else $as_nop
case `(set -o) 2>/dev/null` in #(
*posix*) :
set -o posix ;; #(
@@ -6254,46 +5990,46 @@ esac
fi
+
+# Reset variables that may have inherited troublesome values from
+# the environment.
+
+# IFS needs to be set, to space, tab, and newline, in precisely that order.
+# (If _AS_PATH_WALK were called with IFS unset, it would have the
+# side effect of setting IFS to empty, thus disabling word splitting.)
+# Quoting is to prevent editors from complaining about space-tab.
as_nl='
'
export as_nl
-# Printing a long string crashes Solaris 7 /usr/bin/printf.
-as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
-as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
-as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
-# Prefer a ksh shell builtin over an external printf program on Solaris,
-# but without wasting forks for bash or zsh.
-if test -z "$BASH_VERSION$ZSH_VERSION" \
- && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then
- as_echo='print -r --'
- as_echo_n='print -rn --'
-elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
- as_echo='printf %s\n'
- as_echo_n='printf %s'
-else
- if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
- as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
- as_echo_n='/usr/ucb/echo -n'
- else
- as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
- as_echo_n_body='eval
- arg=$1;
- case $arg in #(
- *"$as_nl"*)
- expr "X$arg" : "X\\(.*\\)$as_nl";
- arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
- esac;
- expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
- '
- export as_echo_n_body
- as_echo_n='sh -c $as_echo_n_body as_echo'
- fi
- export as_echo_body
- as_echo='sh -c $as_echo_body as_echo'
-fi
+IFS=" "" $as_nl"
+
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# Ensure predictable behavior from utilities with locale-dependent output.
+LC_ALL=C
+export LC_ALL
+LANGUAGE=C
+export LANGUAGE
+
+# We cannot yet rely on "unset" to work, but we need these variables
+# to be unset--not just set to an empty or harmless value--now, to
+# avoid bugs in old shells (e.g. pre-3.0 UWIN ksh). This construct
+# also avoids known problems related to "unset" and subshell syntax
+# in other old shells (e.g. bash 2.01 and pdksh 5.2.14).
+for as_var in BASH_ENV ENV MAIL MAILPATH CDPATH
+do eval test \${$as_var+y} \
+ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
+done
+
+# Ensure that fds 0, 1, and 2 are open.
+if (exec 3>&0) 2>/dev/null; then :; else exec 0</dev/null; fi
+if (exec 3>&1) 2>/dev/null; then :; else exec 1>/dev/null; fi
+if (exec 3>&2) ; then :; else exec 2>/dev/null; fi
# The user is always right.
-if test "${PATH_SEPARATOR+set}" != set; then
+if ${PATH_SEPARATOR+false} :; then
PATH_SEPARATOR=:
(PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
(PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
@@ -6302,13 +6038,6 @@ if test "${PATH_SEPARATOR+set}" != set; then
fi
-# IFS
-# We need space, tab and new line, in precisely that order. Quoting is
-# there to prevent editors from complaining about space-tab.
-# (If _AS_PATH_WALK were called with IFS unset, it would disable word
-# splitting by setting IFS to empty value.)
-IFS=" "" $as_nl"
-
# Find who we are. Look in the path if we contain no directory separator.
as_myself=
case $0 in #((
@@ -6317,8 +6046,12 @@ case $0 in #((
for as_dir in $PATH
do
IFS=$as_save_IFS
- test -z "$as_dir" && as_dir=.
- test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+ case $as_dir in #(((
+ '') as_dir=./ ;;
+ */) ;;
+ *) as_dir=$as_dir/ ;;
+ esac
+ test -r "$as_dir$0" && as_myself=$as_dir$0 && break
done
IFS=$as_save_IFS
@@ -6330,30 +6063,10 @@ if test "x$as_myself" = x; then
as_myself=$0
fi
if test ! -f "$as_myself"; then
- $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+ printf "%s\n" "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
exit 1
fi
-# Unset variables that we do not need and which cause bugs (e.g. in
-# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1"
-# suppresses any "Segmentation fault" message there. '((' could
-# trigger a bug in pdksh 5.2.14.
-for as_var in BASH_ENV ENV MAIL MAILPATH
-do eval test x\${$as_var+set} = xset \
- && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
-done
-PS1='$ '
-PS2='> '
-PS4='+ '
-
-# NLS nuisances.
-LC_ALL=C
-export LC_ALL
-LANGUAGE=C
-export LANGUAGE
-
-# CDPATH.
-(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
# as_fn_error STATUS ERROR [LINENO LOG_FD]
@@ -6366,13 +6079,14 @@ as_fn_error ()
as_status=$1; test $as_status -eq 0 && as_status=1
if test "$4"; then
as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
- $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
+ printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
fi
- $as_echo "$as_me: error: $2" >&2
+ printf "%s\n" "$as_me: error: $2" >&2
as_fn_exit $as_status
} # as_fn_error
+
# as_fn_set_status STATUS
# -----------------------
# Set $? to STATUS, without forking.
@@ -6399,18 +6113,20 @@ as_fn_unset ()
{ eval $1=; unset $1;}
}
as_unset=as_fn_unset
+
# as_fn_append VAR VALUE
# ----------------------
# Append the text in VALUE to the end of the definition contained in VAR. Take
# advantage of any shell optimizations that allow amortized linear growth over
# repeated appends, instead of the typical quadratic growth present in naive
# implementations.
-if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :
+if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null
+then :
eval 'as_fn_append ()
{
eval $1+=\$2
}'
-else
+else $as_nop
as_fn_append ()
{
eval $1=\$$1\$2
@@ -6422,12 +6138,13 @@ fi # as_fn_append
# Perform arithmetic evaluation on the ARGs, and store the result in the
# global $as_val. Take advantage of shells that can avoid forks. The arguments
# must be portable across $(()) and expr.
-if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
+if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null
+then :
eval 'as_fn_arith ()
{
as_val=$(( $* ))
}'
-else
+else $as_nop
as_fn_arith ()
{
as_val=`expr "$@" || test $? -eq 1`
@@ -6458,7 +6175,7 @@ as_me=`$as_basename -- "$0" ||
$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
X"$0" : 'X\(//\)$' \| \
X"$0" : 'X\(/\)' \| . 2>/dev/null ||
-$as_echo X/"$0" |
+printf "%s\n" X/"$0" |
sed '/^.*\/\([^/][^/]*\)\/*$/{
s//\1/
q
@@ -6480,6 +6197,10 @@ as_cr_Letters=$as_cr_letters$as_cr_LETTERS
as_cr_digits='0123456789'
as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+# Determine whether it's possible to make 'echo' print without a newline.
+# These variables are no longer used directly by Autoconf, but are AC_SUBSTed
+# for compatibility with existing Makefiles.
ECHO_C= ECHO_N= ECHO_T=
case `echo -n x` in #(((((
-n*)
@@ -6493,6 +6214,12 @@ case `echo -n x` in #(((((
ECHO_N='-n';;
esac
+# For backward compatibility with old third-party macros, we provide
+# the shell variables $as_echo and $as_echo_n. New code should use
+# AS_ECHO(["message"]) and AS_ECHO_N(["message"]), respectively.
+as_echo='printf %s\n'
+as_echo_n='printf %s'
+
rm -f conf$$ conf$$.exe conf$$.file
if test -d conf$$.dir; then
rm -f conf$$.dir/conf$$.file
@@ -6534,7 +6261,7 @@ as_fn_mkdir_p ()
as_dirs=
while :; do
case $as_dir in #(
- *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
+ *\'*) as_qdir=`printf "%s\n" "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
*) as_qdir=$as_dir;;
esac
as_dirs="'$as_qdir' $as_dirs"
@@ -6543,7 +6270,7 @@ $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
X"$as_dir" : 'X\(//\)[^/]' \| \
X"$as_dir" : 'X\(//\)$' \| \
X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
-$as_echo X"$as_dir" |
+printf "%s\n" X"$as_dir" |
sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
s//\1/
q
@@ -6606,7 +6333,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
# values after options handling.
ac_log="
This file was extended by $as_me, which was
-generated by GNU Autoconf 2.69. Invocation command line was
+generated by GNU Autoconf 2.69e. Invocation command line was
CONFIG_FILES = $CONFIG_FILES
CONFIG_HEADERS = $CONFIG_HEADERS
@@ -6664,14 +6391,16 @@ $config_headers
Report bugs to the package provider."
_ACEOF
+ac_cs_config=`printf "%s\n" "$ac_configure_args" | sed "$ac_safe_unquote"`
+ac_cs_config_escaped=`printf "%s\n" "$ac_cs_config" | sed "s/^ //; s/'/'\\\\\\\\''/g"`
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
-ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
+ac_cs_config='$ac_cs_config_escaped'
ac_cs_version="\\
config.status
-configured by $0, generated by GNU Autoconf 2.69,
+configured by $0, generated by GNU Autoconf 2.69e,
with options \\"\$ac_cs_config\\"
-Copyright (C) 2012 Free Software Foundation, Inc.
+Copyright (C) 2020 Free Software Foundation, Inc.
This config.status script is free software; the Free Software Foundation
gives unlimited permission to copy, distribute and modify it."
@@ -6709,15 +6438,15 @@ do
-recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
ac_cs_recheck=: ;;
--version | --versio | --versi | --vers | --ver | --ve | --v | -V )
- $as_echo "$ac_cs_version"; exit ;;
+ printf "%s\n" "$ac_cs_version"; exit ;;
--config | --confi | --conf | --con | --co | --c )
- $as_echo "$ac_cs_config"; exit ;;
+ printf "%s\n" "$ac_cs_config"; exit ;;
--debug | --debu | --deb | --de | --d | -d )
debug=: ;;
--file | --fil | --fi | --f )
$ac_shift
case $ac_optarg in
- *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ *\'*) ac_optarg=`printf "%s\n" "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
'') as_fn_error $? "missing file argument" ;;
esac
as_fn_append CONFIG_FILES " '$ac_optarg'"
@@ -6725,7 +6454,7 @@ do
--header | --heade | --head | --hea )
$ac_shift
case $ac_optarg in
- *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ *\'*) ac_optarg=`printf "%s\n" "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
esac
as_fn_append CONFIG_HEADERS " '$ac_optarg'"
ac_need_defaults=false;;
@@ -6734,7 +6463,7 @@ do
as_fn_error $? "ambiguous option: \`$1'
Try \`$0 --help' for more information.";;
--help | --hel | -h )
- $as_echo "$ac_cs_usage"; exit ;;
+ printf "%s\n" "$ac_cs_usage"; exit ;;
-q | -quiet | --quiet | --quie | --qui | --qu | --q \
| -silent | --silent | --silen | --sile | --sil | --si | --s)
ac_cs_silent=: ;;
@@ -6762,7 +6491,7 @@ cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
if \$ac_cs_recheck; then
set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion
shift
- \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6
+ \printf "%s\n" "running CONFIG_SHELL=$SHELL \$*" >&6
CONFIG_SHELL='$SHELL'
export CONFIG_SHELL
exec "\$@"
@@ -6776,7 +6505,7 @@ exec 5>>config.log
sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX
## Running $as_me. ##
_ASBOX
- $as_echo "$ac_log"
+ printf "%s\n" "$ac_log"
} >&5
_ACEOF
@@ -6802,8 +6531,8 @@ done
# We use the long form for the default assignment because of an extremely
# bizarre bug on SunOS 4.1.3.
if $ac_need_defaults; then
- test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files
- test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers
+ test ${CONFIG_FILES+y} || CONFIG_FILES=$config_files
+ test ${CONFIG_HEADERS+y} || CONFIG_HEADERS=$config_headers
fi
# Have a temporary directory for convenience. Make it in the build tree
@@ -7139,7 +6868,7 @@ do
esac ||
as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;;
esac
- case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac
+ case $ac_f in *\'*) ac_f=`printf "%s\n" "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac
as_fn_append ac_file_inputs " '$ac_f'"
done
@@ -7147,17 +6876,17 @@ do
# use $as_me), people would be surprised to read:
# /* config.h. Generated by config.status. */
configure_input='Generated from '`
- $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g'
+ printf "%s\n" "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g'
`' by configure.'
if test x"$ac_file" != x-; then
configure_input="$ac_file. $configure_input"
- { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5
-$as_echo "$as_me: creating $ac_file" >&6;}
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5
+printf "%s\n" "$as_me: creating $ac_file" >&6;}
fi
# Neutralize special characters interpreted by sed in replacement strings.
case $configure_input in #(
*\&* | *\|* | *\\* )
- ac_sed_conf_input=`$as_echo "$configure_input" |
+ ac_sed_conf_input=`printf "%s\n" "$configure_input" |
sed 's/[\\\\&|]/\\\\&/g'`;; #(
*) ac_sed_conf_input=$configure_input;;
esac
@@ -7174,7 +6903,7 @@ $as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
X"$ac_file" : 'X\(//\)[^/]' \| \
X"$ac_file" : 'X\(//\)$' \| \
X"$ac_file" : 'X\(/\)' \| . 2>/dev/null ||
-$as_echo X"$ac_file" |
+printf "%s\n" X"$ac_file" |
sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
s//\1/
q
@@ -7198,9 +6927,9 @@ $as_echo X"$ac_file" |
case "$ac_dir" in
.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
*)
- ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
+ ac_dir_suffix=/`printf "%s\n" "$ac_dir" | sed 's|^\.[\\/]||'`
# A ".." for each directory in $ac_dir_suffix.
- ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
+ ac_top_builddir_sub=`printf "%s\n" "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
case $ac_top_builddir_sub in
"") ac_top_builddir_sub=. ac_top_build_prefix= ;;
*) ac_top_build_prefix=$ac_top_builddir_sub/ ;;
@@ -7257,8 +6986,8 @@ ac_sed_dataroot='
case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in
*datarootdir*) ac_datarootdir_seen=yes;;
*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*)
- { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5
-$as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;}
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5
+printf "%s\n" "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;}
_ACEOF
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
ac_datarootdir_hack='
@@ -7301,9 +7030,9 @@ test -z "$ac_datarootdir_hack$ac_datarootdir_seen" &&
{ ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } &&
{ ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \
"$ac_tmp/out"`; test -z "$ac_out"; } &&
- { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir'
which seems to be undefined. Please make sure it is defined" >&5
-$as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+printf "%s\n" "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir'
which seems to be undefined. Please make sure it is defined" >&2;}
rm -f "$ac_tmp/stdin"
@@ -7319,20 +7048,20 @@ which seems to be undefined. Please make sure it is defined" >&2;}
#
if test x"$ac_file" != x-; then
{
- $as_echo "/* $configure_input */" \
+ printf "%s\n" "/* $configure_input */" >&1 \
&& eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs"
} >"$ac_tmp/config.h" \
|| as_fn_error $? "could not create $ac_file" "$LINENO" 5
if diff "$ac_file" "$ac_tmp/config.h" >/dev/null 2>&1; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5
-$as_echo "$as_me: $ac_file is unchanged" >&6;}
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5
+printf "%s\n" "$as_me: $ac_file is unchanged" >&6;}
else
rm -f "$ac_file"
mv "$ac_tmp/config.h" "$ac_file" \
|| as_fn_error $? "could not create $ac_file" "$LINENO" 5
fi
else
- $as_echo "/* $configure_input */" \
+ printf "%s\n" "/* $configure_input */" >&1 \
&& eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" \
|| as_fn_error $? "could not create -" "$LINENO" 5
fi
@@ -7373,32 +7102,35 @@ if test "$no_create" != yes; then
$ac_cs_success || as_fn_exit 1
fi
if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5
-$as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;}
-fi
-
-
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: " >&5
-$as_echo "" >&6; }
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: BIRD was configured with the following options:" >&5
-$as_echo "BIRD was configured with the following options:" >&6; }
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: Source directory: $srcdir" >&5
-$as_echo " Source directory: $srcdir" >&6; }
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: Object directory: $objdir" >&5
-$as_echo " Object directory: $objdir" >&6; }
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: Iproute2 directory: $iproutedir" >&5
-$as_echo " Iproute2 directory: $iproutedir" >&6; }
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: System configuration: $sysdesc" >&5
-$as_echo " System configuration: $sysdesc" >&6; }
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: Debugging: $enable_debug" >&5
-$as_echo " Debugging: $enable_debug" >&6; }
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: POSIX threads: $enable_pthreads" >&5
-$as_echo " POSIX threads: $enable_pthreads" >&6; }
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: Routing protocols: $protocols" >&5
-$as_echo " Routing protocols: $protocols" >&6; }
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: Kernel MPLS support: $enable_mpls_kernel" >&5
-$as_echo " Kernel MPLS support: $enable_mpls_kernel" >&6; }
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: Client: $enable_client" >&5
-$as_echo " Client: $enable_client" >&6; }
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5
+printf "%s\n" "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;}
+fi
+
+
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: " >&5
+printf "%s\n" "" >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: BIRD was configured with the following options:" >&5
+printf "%s\n" "BIRD was configured with the following options:" >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: Source directory: $srcdir" >&5
+printf "%s\n" " Source directory: $srcdir" >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: Object directory: $objdir" >&5
+printf "%s\n" " Object directory: $objdir" >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: Iproute2 directory: $iproutedir" >&5
+printf "%s\n" " Iproute2 directory: $iproutedir" >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: System configuration: $sysdesc" >&5
+printf "%s\n" " System configuration: $sysdesc" >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: Debugging: $enable_debug" >&5
+printf "%s\n" " Debugging: $enable_debug" >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: POSIX threads: $enable_pthreads" >&5
+printf "%s\n" " POSIX threads: $enable_pthreads" >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: Routing protocols: $protocols" >&5
+printf "%s\n" " Routing protocols: $protocols" >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: LibSSH support in RPKI: $enable_libssh" >&5
+printf "%s\n" " LibSSH support in RPKI: $enable_libssh" >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: Kernel MPLS support: $enable_mpls_kernel" >&5
+printf "%s\n" " Kernel MPLS support: $enable_mpls_kernel" >&6; }
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: Client: $enable_client" >&5
+printf "%s\n" " Client: $enable_client" >&6; }
rm -f $objdir/.*-stamp
+
diff --git a/configure.ac b/configure.ac
index 40f021a1..eabb3d56 100644
--- a/configure.ac
+++ b/configure.ac
@@ -24,6 +24,12 @@ AC_ARG_ENABLE([debug-generated],
[enable_debug_generated=no]
)
+AC_ARG_ENABLE([debug-expensive],
+ [AS_HELP_STRING([--enable-debug-expensive], [enable expensive consistency checks (implies --enable-debug) @<:@no@:>@])],
+ [],
+ [enable_debug_expensive=no]
+)
+
AC_ARG_ENABLE([memcheck],
[AS_HELP_STRING([--enable-memcheck], [check memory allocations when debugging @<:@yes@:>@])],
[],
@@ -37,7 +43,7 @@ AC_ARG_ENABLE([pthreads],
)
AC_ARG_ENABLE([libssh],
- [AS_HELP_STRING([--enable-libssh], [enable LibSSH support together with RPKI @<:@try@:>@])],
+ [AS_HELP_STRING([--enable-libssh], [enable LibSSH support in RPKI @<:@try@:>@])],
[],
[enable_libssh=try]
)
@@ -72,6 +78,9 @@ AC_ARG_VAR([FLEX], [location of the Flex program])
AC_ARG_VAR([BISON], [location of the Bison program])
AC_ARG_VAR([M4], [location of the M4 program])
+if test "$enable_debug_expensive" = yes; then
+ enable_debug=yes
+fi
if test "$srcdir" = . ; then
# Building in current directory => create obj directory holding all objects
@@ -271,7 +280,6 @@ if test "$enable_libssh" != no ; then
if test "$fail" != yes ; then
AC_DEFINE([HAVE_LIBSSH], [1], [Define to 1 if you have the `ssh' library (-lssh).])
DAEMON_LIBS="-lssh $DAEMON_LIBS"
- proto_rpki=rpki
enable_libssh=yes
else
if test "$enable_libssh" = yes ; then
@@ -296,7 +304,7 @@ if test "$enable_mpls_kernel" != no ; then
fi
fi
-all_protocols="$proto_bfd babel bgp mrt ospf perf pipe radv rip $proto_rpki static"
+all_protocols="$proto_bfd babel bgp mrt ospf perf pipe radv rip rpki static"
all_protocols=`echo $all_protocols | sed 's/ /,/g'`
@@ -389,6 +397,10 @@ if test "$enable_debug" = yes ; then
AC_CHECK_LIB([efence], [malloc])
fi
fi
+
+ if test "enable_debug_expensive" = yes ; then
+ AC_DEFINE([ENABLE_EXPENSIVE_CHECKS], [1], [Define to 1 if you want to run expensive consistency checks.])
+ fi
fi
CLIENT=birdcl
@@ -453,6 +465,7 @@ AC_MSG_RESULT([ System configuration: $sysdesc])
AC_MSG_RESULT([ Debugging: $enable_debug])
AC_MSG_RESULT([ POSIX threads: $enable_pthreads])
AC_MSG_RESULT([ Routing protocols: $protocols])
+AC_MSG_RESULT([ LibSSH support in RPKI: $enable_libssh])
AC_MSG_RESULT([ Kernel MPLS support: $enable_mpls_kernel])
AC_MSG_RESULT([ Client: $enable_client])
diff --git a/doc/bird.aux b/doc/bird.aux
deleted file mode 100644
index 9b3333e8..00000000
--- a/doc/bird.aux
+++ /dev/null
@@ -1,520 +0,0 @@
-\relax
-\providecommand\HyperFirstAtBeginDocument{\AtBeginDocument}
-\HyperFirstAtBeginDocument{\ifx\hyper@anchor\@undefined
-\global\let\oldcontentsline\contentsline
-\gdef\contentsline#1#2#3#4{\oldcontentsline{#1}{#2}{#3}}
-\global\let\oldnewlabel\newlabel
-\gdef\newlabel#1#2{\newlabelxx{#1}#2}
-\gdef\newlabelxx#1#2#3#4#5#6{\oldnewlabel{#1}{{#2}{#3}}}
-\AtEndDocument{\ifx\hyper@anchor\@undefined
-\let\contentsline\oldcontentsline
-\let\newlabel\oldnewlabel
-\fi}
-\fi}
-\global\let\hyper@last\relax
-\gdef\HyperFirstAtBeginDocument#1{#1}
-\providecommand\HyField@AuxAddToFields[1]{}
-\@writefile{toc}{\contentsline {chapter}{\numberline {1}Introduction }{3}{chapter.1}}
-\@writefile{lof}{\addvspace {10\p@ }}
-\@writefile{lot}{\addvspace {10\p@ }}
-\newlabel{intro}{{1}{3}{Introduction\relax }{chapter.1}{}}
-\newlabel{what-is-bird}{{1.1}{3}{What is BIRD\relax }{section.1.1}{}}
-\@writefile{toc}{\contentsline {section}{\numberline {1.1}What is BIRD }{3}{section.1.1}}
-\newlabel{install}{{1.2}{4}{Installing BIRD\relax }{section.1.2}{}}
-\@writefile{toc}{\contentsline {section}{\numberline {1.2}Installing BIRD }{4}{section.1.2}}
-\newlabel{argv}{{1.3}{4}{Running BIRD\relax }{section.1.3}{}}
-\@writefile{toc}{\contentsline {section}{\numberline {1.3}Running BIRD }{4}{section.1.3}}
-\newlabel{argv-config}{{1.3}{4}{\ttfamily -c {\it config name\/}\relax }{section*.28}{}}
-\newlabel{argv-debug}{{1.3}{4}{\ttfamily -d\relax }{section*.31}{}}
-\newlabel{argv-log-file}{{1.3}{4}{\ttfamily -D {\it filename of debug log\/}\relax }{section*.34}{}}
-\newlabel{argv-foreground}{{1.3}{4}{\ttfamily -f\relax }{section*.37}{}}
-\newlabel{argv-group}{{1.3}{4}{\ttfamily -g {\it group\/}\relax }{section*.40}{}}
-\newlabel{argv-help}{{1.3}{4}{\ttfamily -h, --help\relax }{section*.43}{}}
-\newlabel{argv-local}{{1.3}{4}{\ttfamily -l\relax }{section*.46}{}}
-\newlabel{argv-parse}{{1.3}{4}{\ttfamily -p\relax }{section*.49}{}}
-\newlabel{argv-pid}{{1.3}{4}{\ttfamily -P {\it name of PID file\/}\relax }{section*.52}{}}
-\newlabel{argv-recovery}{{1.3}{4}{\ttfamily -R\relax }{section*.55}{}}
-\newlabel{argv-socket}{{1.3}{4}{\ttfamily -s {\it name of communication socket\/}\relax }{section*.58}{}}
-\newlabel{argv-user}{{1.3}{4}{\ttfamily -u {\it user\/}\relax }{section*.61}{}}
-\newlabel{argv-version}{{1.3}{4}{\ttfamily --version\relax }{section*.64}{}}
-\newlabel{privileges}{{1.4}{5}{Privileges\relax }{section.1.4}{}}
-\@writefile{toc}{\contentsline {section}{\numberline {1.4}Privileges }{5}{section.1.4}}
-\@writefile{toc}{\contentsline {chapter}{\numberline {2}About routing tables }{6}{chapter.2}}
-\@writefile{lof}{\addvspace {10\p@ }}
-\@writefile{lot}{\addvspace {10\p@ }}
-\newlabel{routing-tables}{{2}{6}{About routing tables\relax }{chapter.2}{}}
-\newlabel{dsc-table-sorted}{{2}{6}{About routing tables\relax }{section*.83}{}}
-\newlabel{graceful-restart}{{2.1}{6}{Graceful restart\relax }{section.2.1}{}}
-\@writefile{toc}{\contentsline {section}{\numberline {2.1}Graceful restart }{6}{section.2.1}}
-\@writefile{toc}{\contentsline {chapter}{\numberline {3}Configuration }{7}{chapter.3}}
-\@writefile{lof}{\addvspace {10\p@ }}
-\@writefile{lot}{\addvspace {10\p@ }}
-\newlabel{config}{{3}{7}{Configuration\relax }{chapter.3}{}}
-\newlabel{config-intro}{{3.1}{7}{Introduction\relax }{section.3.1}{}}
-\@writefile{toc}{\contentsline {section}{\numberline {3.1}Introduction }{7}{section.3.1}}
-\newlabel{global-opts}{{3.2}{7}{Global options\relax }{section.3.2}{}}
-\@writefile{toc}{\contentsline {section}{\numberline {3.2}Global options }{7}{section.3.2}}
-\newlabel{opt-include}{{3.2}{7}{\ttfamily include "{\it filename\/}"\relax }{section*.98}{}}
-\newlabel{opt-log}{{3.2}{7}{\ttfamily log "{\it filename\/}"$|$syslog {[}name {\it name\/}{]}$|$stderr all$|$$\{$ {\it list of classes\/} $\}$\relax }{section*.101}{}}
-\newlabel{opt-debug-protocols}{{3.2}{7}{\ttfamily debug protocols all$|$off$|$$\{$ states$|$routes$|$filters$|$interfaces$|$events$|$packets {[}, {\it ...\/}{]} $\}$\relax }{section*.104}{}}
-\newlabel{opt-debug-commands}{{3.2}{7}{\ttfamily debug commands {\it number\/}\relax }{section*.107}{}}
-\newlabel{opt-debug-latency}{{3.2}{8}{\ttfamily debug latency {\it switch\/}\relax }{section*.110}{}}
-\newlabel{opt-debug-latency-limit}{{3.2}{8}{\ttfamily debug latency limit {\it time\/}\relax }{section*.113}{}}
-\newlabel{opt-watchdog-warn}{{3.2}{8}{\ttfamily watchdog warning {\it time\/}\relax }{section*.116}{}}
-\newlabel{opt-watchdog-timeout}{{3.2}{8}{\ttfamily watchdog timeout {\it time\/}\relax }{section*.119}{}}
-\newlabel{opt-mrtdump}{{3.2}{8}{\ttfamily mrtdump "{\it filename\/}"\relax }{section*.122}{}}
-\newlabel{opt-mrtdump-protocols}{{3.2}{8}{\ttfamily mrtdump protocols all$|$off$|$$\{$ states$|$messages {[}, {\it ...\/}{]} $\}$\relax }{section*.125}{}}
-\newlabel{opt-filter}{{3.2}{8}{\ttfamily filter {\it name local variables\/}$\{$ {\it commands\/} $\}$\relax }{section*.128}{}}
-\newlabel{opt-function}{{3.2}{8}{\ttfamily function {\it name\/} ({\it parameters\/}) {\it local variables\/} $\{$ {\it commands\/} $\}$\relax }{section*.131}{}}
-\newlabel{opt-protocol}{{3.2}{8}{\ttfamily protocol rip$|$ospf$|$bgp$|${\it ...\/} {[}{\it name\/} {[}from {\it name2\/}{]}{]} $\{$ {\it protocol options\/} $\}$\relax }{section*.134}{}}
-\newlabel{opt-template}{{3.2}{8}{\ttfamily template rip$|$bgp$|${\it ...\/} {[}{\it name\/} {[}from {\it name2\/}{]}{]} $\{$ {\it protocol options\/} $\}$\relax }{section*.137}{}}
-\newlabel{opt-define}{{3.2}{8}{\ttfamily define {\it constant\/} = {\it expression\/}\relax }{section*.140}{}}
-\newlabel{opt-router-id}{{3.2}{8}{\ttfamily router id {\it IPv4 address\/}\relax }{section*.143}{}}
-\newlabel{opt-router-id-from}{{3.2}{8}{\ttfamily router id from {[}-{]} {[} "{\it mask\/}" {]} {[} {\it prefix\/} {]} {[}, {\it ...\/}{]}\relax }{section*.146}{}}
-\newlabel{opt-listen-bgp}{{3.2}{8}{\ttfamily listen bgp {[}address {\it address\/}{]} {[}port {\it port\/}{]} {[}dual{]}\relax }{section*.149}{}}
-\newlabel{opt-graceful-restart}{{3.2}{9}{\ttfamily graceful restart wait {\it number\/}\relax }{section*.152}{}}
-\newlabel{opt-timeformat}{{3.2}{9}{\ttfamily timeformat route$|$protocol$|$base$|$log "{\it format1\/}" {[}{\it limit\/} "{\it format2\/}"{]}\relax }{section*.155}{}}
-\newlabel{opt-table}{{3.2}{9}{\ttfamily table {\it name\/} {[}sorted{]}\relax }{section*.161}{}}
-\newlabel{opt-roa-table}{{3.2}{9}{\ttfamily roa table {\it name\/} {[} $\{$ {\it roa table options ...\/} $\}$ {]}\relax }{section*.164}{}}
-\newlabel{opt-eval}{{3.2}{9}{\ttfamily eval {\it expr\/}\relax }{section*.168}{}}
-\newlabel{protocol-opts}{{3.3}{9}{Protocol options\relax }{section.3.3}{}}
-\@writefile{toc}{\contentsline {section}{\numberline {3.3}Protocol options }{9}{section.3.3}}
-\newlabel{proto-preference}{{3.3}{9}{\ttfamily preference {\it expr\/}\relax }{section*.176}{}}
-\newlabel{proto-disabled}{{3.3}{9}{\ttfamily disabled {\it switch\/}\relax }{section*.179}{}}
-\newlabel{proto-debug}{{3.3}{10}{\ttfamily debug all$|$off$|$$\{$ states$|$routes$|$filters$|$interfaces$|$events$|$packets {[}, {\it ...\/}{]} $\}$\relax }{section*.182}{}}
-\newlabel{proto-mrtdump}{{3.3}{10}{\ttfamily mrtdump all$|$off$|$$\{$ states$|$messages {[}, {\it ...\/}{]} $\}$\relax }{section*.185}{}}
-\newlabel{proto-router-id}{{3.3}{10}{\ttfamily router id {\it IPv4 address\/}\relax }{section*.188}{}}
-\newlabel{proto-import}{{3.3}{10}{\ttfamily import all $|$ none $|$ filter {\it name\/} $|$ filter $\{$ {\it filter commands\/} $\}$ $|$ where {\it filter expression\/}\relax }{section*.191}{}}
-\newlabel{proto-export}{{3.3}{10}{\ttfamily export {\it filter\/}\relax }{section*.194}{}}
-\newlabel{proto-import-keep-filtered}{{3.3}{10}{\ttfamily import keep filtered {\it switch\/}\relax }{section*.197}{}}
-\newlabel{proto-import-limit}{{3.3}{10}{\ttfamily import limit {[}{\it number\/} $|$ off {]} {[}action warn $|$ block $|$ restart $|$ disable{]}\relax }{section*.200}{}}
-\newlabel{proto-receive-limit}{{3.3}{10}{\ttfamily receive limit {[}{\it number\/} $|$ off {]} {[}action warn $|$ block $|$ restart $|$ disable{]}\relax }{section*.203}{}}
-\newlabel{proto-export-limit}{{3.3}{10}{\ttfamily export limit {[} {\it number\/} $|$ off {]} {[}action warn $|$ block $|$ restart $|$ disable{]}\relax }{section*.206}{}}
-\newlabel{proto-description}{{3.3}{10}{\ttfamily description "{\it text\/}"\relax }{section*.209}{}}
-\newlabel{proto-table}{{3.3}{10}{\ttfamily table {\it name\/}\relax }{section*.212}{}}
-\newlabel{proto-vrf}{{3.3}{11}{\ttfamily vrf "{\it text\/}"$|$default\relax }{section*.215}{}}
-\newlabel{proto-iface}{{3.3}{11}{\ttfamily interface {[}-{]} {[} "{\it mask\/}" {]} {[} {\it prefix\/} {]} {[}, {\it ...\/}{]} {[} $\{$ {\it option\/}; {[}{\it ...\/}{]} $\}$ {]}\relax }{section*.222}{}}
-\newlabel{proto-tx-class}{{3.3}{11}{\ttfamily tx class$|$dscp {\it num\/}\relax }{section*.236}{}}
-\newlabel{proto-tx-priority}{{3.3}{11}{\ttfamily tx priority {\it num\/}\relax }{section*.239}{}}
-\newlabel{proto-pass}{{3.3}{12}{\ttfamily password "{\it password\/}" {[} $\{$ {\it password options\/} $\}$ {]}\relax }{section*.242}{}}
-\newlabel{proto-pass-id}{{3.3}{12}{\ttfamily id {\it num\/}\relax }{section*.248}{}}
-\newlabel{proto-pass-gen-from}{{3.3}{12}{\ttfamily generate from "{\it time\/}"\relax }{section*.251}{}}
-\newlabel{proto-pass-gen-to}{{3.3}{12}{\ttfamily generate to "{\it time\/}"\relax }{section*.254}{}}
-\newlabel{proto-pass-accept-from}{{3.3}{12}{\ttfamily accept from "{\it time\/}"\relax }{section*.257}{}}
-\newlabel{proto-pass-accept-to}{{3.3}{12}{\ttfamily accept to "{\it time\/}"\relax }{section*.260}{}}
-\newlabel{proto-pass-from}{{3.3}{12}{\ttfamily from "{\it time\/}"\relax }{section*.263}{}}
-\newlabel{proto-pass-to}{{3.3}{12}{\ttfamily to "{\it time\/}"\relax }{section*.266}{}}
-\newlabel{proto-pass-algorithm}{{3.3}{12}{\ttfamily algorithm ( keyed md5 $|$ keyed sha1 $|$ hmac sha1 $|$ hmac sha256 $|$ hmac sha384 $|$ hmac sha512 )\relax }{section*.269}{}}
-\@writefile{toc}{\contentsline {chapter}{\numberline {4}Remote control }{13}{chapter.4}}
-\@writefile{lof}{\addvspace {10\p@ }}
-\@writefile{lot}{\addvspace {10\p@ }}
-\newlabel{remote-control}{{4}{13}{Remote control\relax }{chapter.4}{}}
-\newlabel{cli-show-status}{{4}{13}{\ttfamily show status\relax }{section*.281}{}}
-\newlabel{cli-show-interfaces}{{4}{13}{\ttfamily show interfaces {[}summary{]}\relax }{section*.284}{}}
-\newlabel{cli-show-protocols}{{4}{13}{\ttfamily show protocols {[}all{]}\relax }{section*.287}{}}
-\newlabel{cli-show-ospf-iface}{{4}{13}{\ttfamily show ospf interface {[}{\it name\/}{]} {[}"{\it interface\/}"{]}\relax }{section*.290}{}}
-\newlabel{cli-show-ospf-neighbors}{{4}{13}{\ttfamily show ospf neighbors {[}{\it name\/}{]} {[}"{\it interface\/}"{]}\relax }{section*.293}{}}
-\newlabel{cli-show-ospf-state}{{4}{13}{\ttfamily show ospf state {[}all{]} {[}{\it name\/}{]}\relax }{section*.296}{}}
-\newlabel{cli-show-ospf-topology}{{4}{13}{\ttfamily show ospf topology {[}all{]} {[}{\it name\/}{]}\relax }{section*.299}{}}
-\newlabel{cli-show-ospf-lsadb}{{4}{13}{\ttfamily show ospf lsadb {[}global $|$ area {\it id\/} $|$ link{]} {[}type {\it num\/}{]} {[}lsid {\it id\/}{]} {[}self $|$ router {\it id\/}{]} {[}{\it name\/}{]}\relax }{section*.302}{}}
-\newlabel{cli-show-rip-interfaces}{{4}{13}{\ttfamily show rip interfaces {[}{\it name\/}{]} {[}"{\it interface\/}"{]}\relax }{section*.305}{}}
-\newlabel{cli-show-rip-neighbors}{{4}{13}{\ttfamily show rip neighbors {[}{\it name\/}{]} {[}"{\it interface\/}"{]}\relax }{section*.308}{}}
-\newlabel{cli-show-static}{{4}{13}{\ttfamily show static {[}{\it name\/}{]}\relax }{section*.311}{}}
-\newlabel{cli-show-bfd-sessions}{{4}{13}{\ttfamily show bfd sessions {[}{\it name\/}{]}\relax }{section*.314}{}}
-\newlabel{cli-show-symbols}{{4}{13}{\ttfamily show symbols {[}table$|$filter$|$function$|$protocol$|$template$|$roa$|${\it symbol\/}{]}\relax }{section*.317}{}}
-\newlabel{cli-show-route}{{4}{14}{\ttfamily show route {[}{[}for{]} {\it prefix\/}$|${\it IP\/}{]} {[}table {\it t\/}{]} {[}filter {\it f\/}$|$where {\it c\/}{]} {[}(export$|$preexport$|$noexport) {\it p\/}{]} {[}protocol {\it p\/}{]} {[}{\it options\/}{]}\relax }{section*.320}{}}
-\newlabel{cli-mrt-dump}{{4}{14}{\ttfamily mrt dump table {\it name\/}$|$"{\it pattern\/}" to "{\it filename\/}" {[}filter {\it f\/}$|$where {\it c\/}{]}\relax }{section*.334}{}}
-\newlabel{cli-show-roa}{{4}{14}{\ttfamily show roa {[}{\it prefix\/} $|$ in {\it prefix\/} $|$ for {\it prefix\/}{]} {[}as {\it num\/}{]} {[}table {\it t\/}{]}\relax }{section*.337}{}}
-\newlabel{cli-add-roa}{{4}{14}{\ttfamily add roa {\it prefix\/} max {\it num\/} as {\it num\/} {[}table {\it t\/}{]}\relax }{section*.340}{}}
-\newlabel{cli-delete-roa}{{4}{14}{\ttfamily delete roa {\it prefix\/} max {\it num\/} as {\it num\/} {[}table {\it t\/}{]}\relax }{section*.343}{}}
-\newlabel{cli-flush-roa}{{4}{14}{\ttfamily flush roa {[}table {\it t\/}{]}\relax }{section*.346}{}}
-\newlabel{cli-configure}{{4}{14}{\ttfamily configure {[}soft{]} {[}"{\it config file\/}"{]} {[}timeout {[}{\it num\/}{]}{]}\relax }{section*.349}{}}
-\newlabel{cli-configure-confirm}{{4}{14}{\ttfamily configure confirm\relax }{section*.354}{}}
-\newlabel{cli-configure-undo}{{4}{15}{\ttfamily configure undo\relax }{section*.357}{}}
-\newlabel{cli-configure-check}{{4}{15}{\ttfamily configure check {[}"{\it config file\/}"{]}\relax }{section*.360}{}}
-\newlabel{cli-enable-disable-restart}{{4}{15}{\ttfamily enable$|$disable$|$restart {\it name\/}$|$"{\it pattern\/}"$|$all\relax }{section*.363}{}}
-\newlabel{cli-reload}{{4}{15}{\ttfamily reload {[}in$|$out{]} {\it name\/}$|$"{\it pattern\/}"$|$all\relax }{section*.366}{}}
-\newlabel{cli-down}{{4}{15}{\ttfamily down\relax }{section*.371}{}}
-\newlabel{cli-debug}{{4}{15}{\ttfamily debug {\it protocol\/}$|${\it pattern\/}$|$all all$|$off$|$$\{$ states$|$routes$|$filters$|$events$|$packets {[}, {\it ...\/}{]} $\}$\relax }{section*.374}{}}
-\newlabel{cli-dump}{{4}{15}{\ttfamily dump resources$|$sockets$|$interfaces$|$neighbors$|$attributes$|$routes$|$protocols\relax }{section*.377}{}}
-\newlabel{cli-echo}{{4}{15}{\ttfamily echo all$|$off$|$$\{$ {\it list of log classes\/} $\}$ {[} {\it buffer-size\/} {]}\relax }{section*.380}{}}
-\newlabel{cli-eval}{{4}{15}{\ttfamily eval {\it expr\/}\relax }{section*.383}{}}
-\@writefile{toc}{\contentsline {chapter}{\numberline {5}Filters }{16}{chapter.5}}
-\@writefile{lof}{\addvspace {10\p@ }}
-\@writefile{lot}{\addvspace {10\p@ }}
-\newlabel{filters}{{5}{16}{Filters\relax }{chapter.5}{}}
-\newlabel{filters-intro}{{5.1}{16}{Introduction\relax }{section.5.1}{}}
-\@writefile{toc}{\contentsline {section}{\numberline {5.1}Introduction }{16}{section.5.1}}
-\newlabel{data-types}{{5.2}{17}{Data types\relax }{section.5.2}{}}
-\@writefile{toc}{\contentsline {section}{\numberline {5.2}Data types }{17}{section.5.2}}
-\newlabel{type-bool}{{5.2}{17}{\ttfamily bool\relax }{section*.407}{}}
-\newlabel{type-int}{{5.2}{17}{\ttfamily int\relax }{section*.410}{}}
-\newlabel{type-pair}{{5.2}{17}{\ttfamily pair\relax }{section*.413}{}}
-\newlabel{type-quad}{{5.2}{17}{\ttfamily quad\relax }{section*.416}{}}
-\newlabel{type-string}{{5.2}{17}{\ttfamily string\relax }{section*.419}{}}
-\newlabel{type-ip}{{5.2}{17}{\ttfamily ip\relax }{section*.422}{}}
-\newlabel{type-prefix}{{5.2}{17}{\ttfamily prefix\relax }{section*.425}{}}
-\newlabel{type-ec}{{5.2}{17}{\ttfamily ec\relax }{section*.428}{}}
-\newlabel{type-lc}{{5.2}{18}{\ttfamily lc\relax }{section*.431}{}}
-\newlabel{type-set}{{5.2}{18}{\ttfamily int$|$pair$|$quad$|$ip$|$prefix$|$ec$|$lc$|$enum set\relax }{section*.434}{}}
-\newlabel{type-enum}{{5.2}{18}{\ttfamily enum\relax }{section*.446}{}}
-\newlabel{type-bgppath}{{5.2}{19}{\ttfamily bgppath\relax }{section*.449}{}}
-\newlabel{type-bgpmask}{{5.2}{19}{\ttfamily bgpmask\relax }{section*.462}{}}
-\newlabel{type-clist}{{5.2}{19}{\ttfamily clist\relax }{section*.465}{}}
-\newlabel{type-eclist}{{5.2}{19}{\ttfamily eclist\relax }{section*.474}{}}
-\newlabel{operators}{{5.3}{20}{Operators\relax }{section.5.3}{}}
-\@writefile{toc}{\contentsline {section}{\numberline {5.3}Operators }{20}{section.5.3}}
-\newlabel{control-structures}{{5.4}{20}{Control structures\relax }{section.5.4}{}}
-\@writefile{toc}{\contentsline {section}{\numberline {5.4}Control structures }{20}{section.5.4}}
-\newlabel{route-attributes}{{5.5}{20}{Route attributes\relax }{section.5.5}{}}
-\@writefile{toc}{\contentsline {section}{\numberline {5.5}Route attributes }{20}{section.5.5}}
-\newlabel{rta-net}{{5.5}{21}{\ttfamily {\it prefix\/} net\relax }{section*.498}{}}
-\newlabel{rta-scope}{{5.5}{21}{\ttfamily {\it enum\/} scope\relax }{section*.501}{}}
-\newlabel{rta-preference}{{5.5}{21}{\ttfamily {\it int\/} preference\relax }{section*.504}{}}
-\newlabel{rta-from}{{5.5}{21}{\ttfamily {\it ip\/} from\relax }{section*.507}{}}
-\newlabel{rta-gw}{{5.5}{21}{\ttfamily {\it ip\/} gw\relax }{section*.510}{}}
-\newlabel{rta-proto}{{5.5}{21}{\ttfamily {\it string\/} proto\relax }{section*.513}{}}
-\newlabel{rta-source}{{5.5}{21}{\ttfamily {\it enum\/} source\relax }{section*.516}{}}
-\newlabel{rta-cast}{{5.5}{21}{\ttfamily {\it enum\/} cast\relax }{section*.519}{}}
-\newlabel{rta-dest}{{5.5}{21}{\ttfamily {\it enum\/} dest\relax }{section*.522}{}}
-\newlabel{rta-ifname}{{5.5}{21}{\ttfamily {\it string\/} ifname\relax }{section*.525}{}}
-\newlabel{rta-ifindex}{{5.5}{21}{\ttfamily {\it int\/} ifindex\relax }{section*.528}{}}
-\newlabel{rta-igp-metric}{{5.5}{21}{\ttfamily {\it int\/} igp\_metric\relax }{section*.531}{}}
-\newlabel{other-statements}{{5.6}{22}{Other statements\relax }{section.5.6}{}}
-\@writefile{toc}{\contentsline {section}{\numberline {5.6}Other statements }{22}{section.5.6}}
-\newlabel{assignment}{{5.6}{22}{\ttfamily {\it variable\/} = {\it expr\/}\relax }{section*.539}{}}
-\newlabel{filter-accept-reject}{{5.6}{22}{\ttfamily accept$|$reject {[} {\it expr\/} {]}\relax }{section*.542}{}}
-\newlabel{return}{{5.6}{22}{\ttfamily return {\it expr\/}\relax }{section*.545}{}}
-\newlabel{print}{{5.6}{22}{\ttfamily print$|$printn {\it expr\/} {[}{\it , expr...\/}{]}\relax }{section*.548}{}}
-\newlabel{quitbird}{{5.6}{22}{\ttfamily quitbird\relax }{section*.551}{}}
-\@writefile{toc}{\contentsline {chapter}{\numberline {6}Protocols }{23}{chapter.6}}
-\@writefile{lof}{\addvspace {10\p@ }}
-\@writefile{lot}{\addvspace {10\p@ }}
-\newlabel{protocols}{{6}{23}{Protocols\relax }{chapter.6}{}}
-\newlabel{babel}{{6.1}{23}{Babel\relax }{section.6.1}{}}
-\@writefile{toc}{\contentsline {section}{\numberline {6.1}Babel }{23}{section.6.1}}
-\newlabel{babel-intro}{{6.1.1}{23}{Introduction\relax }{subsection.6.1.1}{}}
-\@writefile{toc}{\contentsline {subsection}{\numberline {6.1.1}Introduction }{23}{subsection.6.1.1}}
-\newlabel{babel-config}{{6.1.2}{23}{Configuration\relax }{subsection.6.1.2}{}}
-\@writefile{toc}{\contentsline {subsection}{\numberline {6.1.2}Configuration }{23}{subsection.6.1.2}}
-\newlabel{babel-type}{{6.1.2}{23}{\ttfamily type wired$|$wireless\relax }{section*.564}{}}
-\newlabel{babel-rxcost}{{6.1.2}{23}{\ttfamily rxcost {\it num\/}\relax }{section*.567}{}}
-\newlabel{babel-hello}{{6.1.2}{23}{\ttfamily hello interval {\it num\/}\relax }{section*.570}{}}
-\newlabel{babel-update}{{6.1.2}{23}{\ttfamily update interval {\it num\/}\relax }{section*.573}{}}
-\newlabel{babel-port}{{6.1.2}{23}{\ttfamily port {\it number\/}\relax }{section*.576}{}}
-\newlabel{babel-tx-class}{{6.1.2}{24}{\ttfamily tx class$|$dscp$|$priority {\it number\/}\relax }{section*.579}{}}
-\newlabel{babel-rx-buffer}{{6.1.2}{24}{\ttfamily rx buffer {\it number\/}\relax }{section*.582}{}}
-\newlabel{babel-tx-length}{{6.1.2}{24}{\ttfamily tx length {\it number\/}\relax }{section*.585}{}}
-\newlabel{babel-check-link}{{6.1.2}{24}{\ttfamily check link {\it switch\/}\relax }{section*.588}{}}
-\newlabel{babel-attr}{{6.1.3}{24}{Attributes\relax }{subsection.6.1.3}{}}
-\@writefile{toc}{\contentsline {subsection}{\numberline {6.1.3}Attributes }{24}{subsection.6.1.3}}
-\newlabel{babel-exam}{{6.1.4}{24}{Example\relax }{subsection.6.1.4}{}}
-\@writefile{toc}{\contentsline {subsection}{\numberline {6.1.4}Example }{24}{subsection.6.1.4}}
-\newlabel{bfd}{{6.2}{24}{BFD\relax }{section.6.2}{}}
-\@writefile{toc}{\contentsline {section}{\numberline {6.2}BFD }{24}{section.6.2}}
-\newlabel{bfd-intro}{{6.2.1}{24}{Introduction\relax }{subsection.6.2.1}{}}
-\@writefile{toc}{\contentsline {subsection}{\numberline {6.2.1}Introduction }{24}{subsection.6.2.1}}
-\newlabel{bfd-config}{{6.2.2}{25}{Configuration\relax }{subsection.6.2.2}{}}
-\@writefile{toc}{\contentsline {subsection}{\numberline {6.2.2}Configuration }{25}{subsection.6.2.2}}
-\newlabel{bfd-iface}{{6.2.2}{26}{\ttfamily interface {\it pattern\/} {[}, {\it ...\/}{]} $\{$ {\it options\/} $\}$\relax }{section*.615}{}}
-\newlabel{bfd-multihop}{{6.2.2}{26}{\ttfamily multihop $\{$ {\it options\/} $\}$\relax }{section*.618}{}}
-\newlabel{bfd-neighbor}{{6.2.2}{26}{\ttfamily neighbor {\it ip\/} {[}dev "{\it interface\/}"{]} {[}local {\it ip\/}{]} {[}multihop {\it switch\/}{]}\relax }{section*.621}{}}
-\newlabel{bfd-interval}{{6.2.2}{26}{\ttfamily interval {\it time\/}\relax }{section*.627}{}}
-\newlabel{bfd-min-rx-interval}{{6.2.2}{26}{\ttfamily min rx interval {\it time\/}\relax }{section*.630}{}}
-\newlabel{bfd-min-tx-interval}{{6.2.2}{26}{\ttfamily min tx interval {\it time\/}\relax }{section*.633}{}}
-\newlabel{bfd-idle-tx-interval}{{6.2.2}{26}{\ttfamily idle tx interval {\it time\/}\relax }{section*.636}{}}
-\newlabel{bfd-multiplier}{{6.2.2}{26}{\ttfamily multiplier {\it num\/}\relax }{section*.639}{}}
-\newlabel{bfd-passive}{{6.2.2}{26}{\ttfamily passive {\it switch\/}\relax }{section*.642}{}}
-\newlabel{bfd-exam}{{6.2.3}{27}{Example\relax }{subsection.6.2.3}{}}
-\@writefile{toc}{\contentsline {subsection}{\numberline {6.2.3}Example }{27}{subsection.6.2.3}}
-\newlabel{bgp}{{6.3}{27}{BGP\relax }{section.6.3}{}}
-\@writefile{toc}{\contentsline {section}{\numberline {6.3}BGP }{27}{section.6.3}}
-\newlabel{bgp-route-select-rules}{{6.3.1}{28}{Route selection rules\relax }{subsection.6.3.1}{}}
-\@writefile{toc}{\contentsline {subsection}{\numberline {6.3.1}Route selection rules }{28}{subsection.6.3.1}}
-\newlabel{bgp-igp-routing-table}{{6.3.2}{28}{IGP routing table\relax }{subsection.6.3.2}{}}
-\@writefile{toc}{\contentsline {subsection}{\numberline {6.3.2}IGP routing table }{28}{subsection.6.3.2}}
-\newlabel{bgp-config}{{6.3.3}{28}{Configuration\relax }{subsection.6.3.3}{}}
-\@writefile{toc}{\contentsline {subsection}{\numberline {6.3.3}Configuration }{28}{subsection.6.3.3}}
-\newlabel{bgp-local}{{6.3.3}{28}{\ttfamily local {[}{\it ip\/}{]} as {\it number\/}\relax }{section*.679}{}}
-\newlabel{bgp-neighbor}{{6.3.3}{28}{\ttfamily neighbor {[}{\it ip\/}{]} {[}port {\it number\/}{]} {[}as {\it number\/}{]}\relax }{section*.682}{}}
-\newlabel{bgp-iface}{{6.3.3}{29}{\ttfamily interface {\it string\/}\relax }{section*.685}{}}
-\newlabel{bgp-direct}{{6.3.3}{29}{\ttfamily direct\relax }{section*.688}{}}
-\newlabel{bgp-multihop}{{6.3.3}{29}{\ttfamily multihop {[}{\it number\/}{]}\relax }{section*.691}{}}
-\newlabel{bgp-source-address}{{6.3.3}{29}{\ttfamily source address {\it ip\/}\relax }{section*.694}{}}
-\newlabel{bgp-next-hop-self}{{6.3.3}{29}{\ttfamily next hop self\relax }{section*.697}{}}
-\newlabel{bgp-next-hop-keep}{{6.3.3}{29}{\ttfamily next hop keep\relax }{section*.700}{}}
-\newlabel{bgp-missing-lladdr}{{6.3.3}{29}{\ttfamily missing lladdr self$|$drop$|$ignore\relax }{section*.703}{}}
-\newlabel{bgp-gateway}{{6.3.3}{29}{\ttfamily gateway direct$|$recursive\relax }{section*.706}{}}
-\newlabel{bgp-igp-table}{{6.3.3}{29}{\ttfamily igp table {\it name\/}\relax }{section*.710}{}}
-\newlabel{bgp-check-link}{{6.3.3}{30}{\ttfamily check link {\it switch\/}\relax }{section*.713}{}}
-\newlabel{bgp-bfd}{{6.3.3}{30}{\ttfamily bfd {\it switch\/}$|$graceful\relax }{section*.716}{}}
-\newlabel{bgp-ttl-security}{{6.3.3}{30}{\ttfamily ttl security {\it switch\/}\relax }{section*.719}{}}
-\newlabel{bgp-pass}{{6.3.3}{30}{\ttfamily password {\it string\/}\relax }{section*.722}{}}
-\newlabel{bgp-setkey}{{6.3.3}{30}{\ttfamily setkey {\it switch\/}\relax }{section*.725}{}}
-\newlabel{bgp-passive}{{6.3.3}{30}{\ttfamily passive {\it switch\/}\relax }{section*.728}{}}
-\newlabel{bgp-rr-client}{{6.3.3}{30}{\ttfamily rr client\relax }{section*.731}{}}
-\newlabel{bgp-rr-cluster-id}{{6.3.3}{30}{\ttfamily rr cluster id {\it IPv4 address\/}\relax }{section*.734}{}}
-\newlabel{bgp-rs-client}{{6.3.3}{30}{\ttfamily rs client\relax }{section*.737}{}}
-\newlabel{bgp-secondary}{{6.3.3}{30}{\ttfamily secondary {\it switch\/}\relax }{section*.740}{}}
-\newlabel{bgp-add-paths}{{6.3.3}{31}{\ttfamily add paths {\it switch\/}$|$rx$|$tx\relax }{section*.743}{}}
-\newlabel{bgp-allow-local-pref}{{6.3.3}{31}{\ttfamily allow bgp\_local\_pref {\it switch\/}\relax }{section*.746}{}}
-\newlabel{bgp-allow-local-as}{{6.3.3}{31}{\ttfamily allow local as {[}{\it number\/}{]}\relax }{section*.749}{}}
-\newlabel{bgp-enable-route-refresh}{{6.3.3}{31}{\ttfamily enable route refresh {\it switch\/}\relax }{section*.752}{}}
-\newlabel{bgp-graceful-restart}{{6.3.3}{31}{\ttfamily graceful restart {\it switch\/}$|$aware\relax }{section*.755}{}}
-\newlabel{bgp-graceful-restart-time}{{6.3.3}{31}{\ttfamily graceful restart time {\it number\/}\relax }{section*.758}{}}
-\newlabel{bgp-long-lived-graceful-restart}{{6.3.3}{31}{\ttfamily long lived graceful restart {\it switch\/}$|$aware\relax }{section*.761}{}}
-\newlabel{bgp-long-lived-stale-time}{{6.3.3}{31}{\ttfamily long lived stale time {\it number\/}\relax }{section*.764}{}}
-\newlabel{bgp-interpret-communities}{{6.3.3}{31}{\ttfamily interpret communities {\it switch\/}\relax }{section*.767}{}}
-\newlabel{bgp-enable-as4}{{6.3.3}{32}{\ttfamily enable as4 {\it switch\/}\relax }{section*.770}{}}
-\newlabel{bgp-enable-extended-messages}{{6.3.3}{32}{\ttfamily enable extended messages {\it switch\/}\relax }{section*.773}{}}
-\newlabel{bgp-capabilities}{{6.3.3}{32}{\ttfamily capabilities {\it switch\/}\relax }{section*.776}{}}
-\newlabel{bgp-advertise-ipv4}{{6.3.3}{32}{\ttfamily advertise ipv4 {\it switch\/}\relax }{section*.779}{}}
-\newlabel{bgp-route-limit}{{6.3.3}{32}{\ttfamily route limit {\it number\/}\relax }{section*.782}{}}
-\newlabel{bgp-disable-after-error}{{6.3.3}{32}{\ttfamily disable after error {\it switch\/}\relax }{section*.785}{}}
-\newlabel{bgp-disable-after-cease}{{6.3.3}{32}{\ttfamily disable after cease {\it switch\/}$|${\it set-of-flags\/}\relax }{section*.788}{}}
-\newlabel{bgp-hold-time}{{6.3.3}{32}{\ttfamily hold time {\it number\/}\relax }{section*.792}{}}
-\newlabel{bgp-startup-hold-time}{{6.3.3}{32}{\ttfamily startup hold time {\it number\/}\relax }{section*.795}{}}
-\newlabel{bgp-keepalive-time}{{6.3.3}{32}{\ttfamily keepalive time {\it number\/}\relax }{section*.798}{}}
-\newlabel{bgp-connect-delay-time}{{6.3.3}{33}{\ttfamily connect delay time {\it number\/}\relax }{section*.801}{}}
-\newlabel{bgp-connect-retry-time}{{6.3.3}{33}{\ttfamily connect retry time {\it number\/}\relax }{section*.804}{}}
-\newlabel{bgp-error-wait-time}{{6.3.3}{33}{\ttfamily error wait time {\it number\/},{\it number\/}\relax }{section*.807}{}}
-\newlabel{bgp-error-forget-time}{{6.3.3}{33}{\ttfamily error forget time {\it number\/}\relax }{section*.810}{}}
-\newlabel{bgp-path-metric}{{6.3.3}{33}{\ttfamily path metric {\it switch\/}\relax }{section*.813}{}}
-\newlabel{bgp-med-metric}{{6.3.3}{33}{\ttfamily med metric {\it switch\/}\relax }{section*.816}{}}
-\newlabel{bgp-deterministic-med}{{6.3.3}{33}{\ttfamily deterministic med {\it switch\/}\relax }{section*.819}{}}
-\newlabel{bgp-igp-metric}{{6.3.3}{33}{\ttfamily igp metric {\it switch\/}\relax }{section*.822}{}}
-\newlabel{bgp-prefer-older}{{6.3.3}{33}{\ttfamily prefer older {\it switch\/}\relax }{section*.825}{}}
-\newlabel{bgp-default-med}{{6.3.3}{33}{\ttfamily default bgp\_med {\it number\/}\relax }{section*.828}{}}
-\newlabel{bgp-default-local-pref}{{6.3.3}{33}{\ttfamily default bgp\_local\_pref {\it number\/}\relax }{section*.831}{}}
-\newlabel{bgp-attr}{{6.3.4}{33}{Attributes\relax }{subsection.6.3.4}{}}
-\@writefile{toc}{\contentsline {subsection}{\numberline {6.3.4}Attributes }{33}{subsection.6.3.4}}
-\newlabel{rta-bgp-path}{{6.3.4}{33}{\ttfamily bgppath bgp\_path\relax }{section*.836}{}}
-\newlabel{rta-bgp-local-pref}{{6.3.4}{34}{\ttfamily int bgp\_local\_pref {[}I{]}\relax }{section*.839}{}}
-\newlabel{rta-bgp-med}{{6.3.4}{34}{\ttfamily int bgp\_med {[}O{]}\relax }{section*.842}{}}
-\newlabel{rta-bgp-origin}{{6.3.4}{34}{\ttfamily enum bgp\_origin\relax }{section*.845}{}}
-\newlabel{rta-bgp-next-hop}{{6.3.4}{34}{\ttfamily ip bgp\_next\_hop\relax }{section*.848}{}}
-\newlabel{rta-bgp-atomic-aggr}{{6.3.4}{34}{\ttfamily void bgp\_atomic\_aggr {[}O{]}\relax }{section*.851}{}}
-\newlabel{rta-bgp-community}{{6.3.4}{34}{\ttfamily clist bgp\_community {[}O{]}\relax }{section*.854}{}}
-\newlabel{rta-bgp-ext-community}{{6.3.4}{34}{\ttfamily eclist bgp\_ext\_community {[}O{]}\relax }{section*.857}{}}
-\newlabel{rta-bgp-large-community}{{6.3.4}{34}{\ttfamily lclist bgp\_large\_community {[}O{]}\relax }{section*.860}{}}
-\newlabel{rta-bgp-originator-id}{{6.3.4}{34}{\ttfamily quad bgp\_originator\_id {[}I, O{]}\relax }{section*.863}{}}
-\newlabel{rta-bgp-cluster-list}{{6.3.4}{34}{\ttfamily clist bgp\_cluster\_list {[}I, O{]}\relax }{section*.866}{}}
-\newlabel{bgp-exam}{{6.3.5}{34}{Example\relax }{subsection.6.3.5}{}}
-\@writefile{toc}{\contentsline {subsection}{\numberline {6.3.5}Example }{34}{subsection.6.3.5}}
-\newlabel{device}{{6.4}{35}{Device\relax }{section.6.4}{}}
-\@writefile{toc}{\contentsline {section}{\numberline {6.4}Device }{35}{section.6.4}}
-\newlabel{device-config}{{6.4.1}{35}{Configuration\relax }{subsection.6.4.1}{}}
-\@writefile{toc}{\contentsline {subsection}{\numberline {6.4.1}Configuration }{35}{subsection.6.4.1}}
-\newlabel{device-scan-time}{{6.4.1}{35}{\ttfamily scan time {\it number\/}\relax }{section*.878}{}}
-\newlabel{device-primary}{{6.4.1}{35}{\ttfamily primary {[} "{\it mask\/}" {]} {\it prefix\/}\relax }{section*.881}{}}
-\newlabel{direct}{{6.5}{36}{Direct\relax }{section.6.5}{}}
-\@writefile{toc}{\contentsline {section}{\numberline {6.5}Direct }{36}{section.6.5}}
-\newlabel{direct-iface}{{6.5}{36}{\ttfamily interface {\it pattern\/} {[}, {\it ...\/}{]}\relax }{section*.900}{}}
-\newlabel{direct-check-link}{{6.5}{36}{\ttfamily check link {\it switch\/}\relax }{section*.903}{}}
-\newlabel{krt}{{6.6}{36}{Kernel\relax }{section.6.6}{}}
-\@writefile{toc}{\contentsline {section}{\numberline {6.6}Kernel }{36}{section.6.6}}
-\newlabel{krt-config}{{6.6.1}{37}{Configuration\relax }{subsection.6.6.1}{}}
-\@writefile{toc}{\contentsline {subsection}{\numberline {6.6.1}Configuration }{37}{subsection.6.6.1}}
-\newlabel{krt-persist}{{6.6.1}{37}{\ttfamily persist {\it switch\/}\relax }{section*.922}{}}
-\newlabel{krt-scan-time}{{6.6.1}{37}{\ttfamily scan time {\it number\/}\relax }{section*.925}{}}
-\newlabel{krt-learn}{{6.6.1}{37}{\ttfamily learn {\it switch\/}\relax }{section*.928}{}}
-\newlabel{krt-device-routes}{{6.6.1}{37}{\ttfamily device routes {\it switch\/}\relax }{section*.931}{}}
-\newlabel{krt-kernel-table}{{6.6.1}{37}{\ttfamily kernel table {\it number\/}\relax }{section*.934}{}}
-\newlabel{krt-metric}{{6.6.1}{37}{\ttfamily metric {\it number\/}\relax }{section*.937}{}}
-\newlabel{krt-graceful-restart}{{6.6.1}{37}{\ttfamily graceful restart {\it switch\/}\relax }{section*.940}{}}
-\newlabel{krt-merge-paths}{{6.6.1}{37}{\ttfamily merge paths {\it switch\/} {[}limit {\it number\/}{]}\relax }{section*.943}{}}
-\newlabel{krt-attr}{{6.6.2}{37}{Attributes\relax }{subsection.6.6.2}{}}
-\@writefile{toc}{\contentsline {subsection}{\numberline {6.6.2}Attributes }{37}{subsection.6.6.2}}
-\newlabel{rta-krt-source}{{6.6.2}{37}{\ttfamily int krt\_source\relax }{section*.948}{}}
-\newlabel{rta-krt-metric}{{6.6.2}{37}{\ttfamily int krt\_metric\relax }{section*.951}{}}
-\newlabel{rta-krt-prefsrc}{{6.6.2}{38}{\ttfamily ip krt\_prefsrc\relax }{section*.954}{}}
-\newlabel{rta-krt-realm}{{6.6.2}{38}{\ttfamily int krt\_realm\relax }{section*.957}{}}
-\newlabel{rta-krt-scope}{{6.6.2}{38}{\ttfamily int krt\_scope\relax }{section*.960}{}}
-\newlabel{krt-exam}{{6.6.3}{38}{Example\relax }{subsection.6.6.3}{}}
-\@writefile{toc}{\contentsline {subsection}{\numberline {6.6.3}Example }{38}{subsection.6.6.3}}
-\newlabel{mrt}{{6.7}{38}{MRT\relax }{section.6.7}{}}
-\@writefile{toc}{\contentsline {section}{\numberline {6.7}MRT }{38}{section.6.7}}
-\newlabel{mrt-intro}{{6.7.1}{38}{Introduction\relax }{subsection.6.7.1}{}}
-\@writefile{toc}{\contentsline {subsection}{\numberline {6.7.1}Introduction }{38}{subsection.6.7.1}}
-\newlabel{mrt-config}{{6.7.2}{39}{Configuration\relax }{subsection.6.7.2}{}}
-\@writefile{toc}{\contentsline {subsection}{\numberline {6.7.2}Configuration }{39}{subsection.6.7.2}}
-\newlabel{mrt-table}{{6.7.2}{39}{\ttfamily table {\it name\/} $|$ "{\it pattern\/}"\relax }{section*.980}{}}
-\newlabel{mrt-filter}{{6.7.2}{39}{\ttfamily filter $\{$ {\it filter commands\/} $\}$\relax }{section*.983}{}}
-\newlabel{mrt-where}{{6.7.2}{39}{\ttfamily where {\it filter expression\/}\relax }{section*.986}{}}
-\newlabel{mrt-filename}{{6.7.2}{39}{\ttfamily filename "{\it filename\/}"\relax }{section*.989}{}}
-\newlabel{mrt-period}{{6.7.2}{39}{\ttfamily period {\it number\/}\relax }{section*.992}{}}
-\newlabel{mrt-always-add-path}{{6.7.2}{39}{\ttfamily always add path {\it switch\/}\relax }{section*.995}{}}
-\newlabel{mrt-exam}{{6.7.3}{39}{Example\relax }{subsection.6.7.3}{}}
-\@writefile{toc}{\contentsline {subsection}{\numberline {6.7.3}Example }{39}{subsection.6.7.3}}
-\newlabel{ospf}{{6.8}{39}{OSPF\relax }{section.6.8}{}}
-\@writefile{toc}{\contentsline {section}{\numberline {6.8}OSPF }{39}{section.6.8}}
-\newlabel{ospf-intro}{{6.8.1}{39}{Introduction\relax }{subsection.6.8.1}{}}
-\@writefile{toc}{\contentsline {subsection}{\numberline {6.8.1}Introduction }{39}{subsection.6.8.1}}
-\newlabel{ospf-config}{{6.8.2}{40}{Configuration\relax }{subsection.6.8.2}{}}
-\@writefile{toc}{\contentsline {subsection}{\numberline {6.8.2}Configuration }{40}{subsection.6.8.2}}
-\newlabel{ospf-rfc1583compat}{{6.8.2}{42}{\ttfamily rfc1583compat {\it switch\/}\relax }{section*.1014}{}}
-\newlabel{ospf-instance-id}{{6.8.2}{42}{\ttfamily instance id {\it num\/}\relax }{section*.1017}{}}
-\newlabel{ospf-stub-router}{{6.8.2}{42}{\ttfamily stub router {\it switch\/}\relax }{section*.1020}{}}
-\newlabel{ospf-tick}{{6.8.2}{42}{\ttfamily tick {\it num\/}\relax }{section*.1023}{}}
-\newlabel{ospf-ecmp}{{6.8.2}{42}{\ttfamily ecmp {\it switch\/} {[}limit {\it number\/}{]}\relax }{section*.1026}{}}
-\newlabel{ospf-merge-external}{{6.8.2}{42}{\ttfamily merge external {\it switch\/}\relax }{section*.1029}{}}
-\newlabel{ospf-area}{{6.8.2}{42}{\ttfamily area {\it id\/}\relax }{section*.1032}{}}
-\newlabel{ospf-stub}{{6.8.2}{42}{\ttfamily stub\relax }{section*.1035}{}}
-\newlabel{ospf-nssa}{{6.8.2}{42}{\ttfamily nssa\relax }{section*.1038}{}}
-\newlabel{ospf-summary}{{6.8.2}{42}{\ttfamily summary {\it switch\/}\relax }{section*.1041}{}}
-\newlabel{ospf-default-nssa}{{6.8.2}{43}{\ttfamily default nssa {\it switch\/}\relax }{section*.1044}{}}
-\newlabel{ospf-default-cost}{{6.8.2}{43}{\ttfamily default cost {\it num\/}\relax }{section*.1047}{}}
-\newlabel{ospf-default-cost2}{{6.8.2}{43}{\ttfamily default cost2 {\it num\/}\relax }{section*.1050}{}}
-\newlabel{ospf-translator}{{6.8.2}{43}{\ttfamily translator {\it switch\/}\relax }{section*.1053}{}}
-\newlabel{ospf-translator-stability}{{6.8.2}{43}{\ttfamily translator stability {\it num\/}\relax }{section*.1056}{}}
-\newlabel{ospf-networks}{{6.8.2}{43}{\ttfamily networks $\{$ {\it set\/} $\}$\relax }{section*.1059}{}}
-\newlabel{ospf-external}{{6.8.2}{43}{\ttfamily external $\{$ {\it set\/} $\}$\relax }{section*.1062}{}}
-\newlabel{ospf-stubnet}{{6.8.2}{43}{\ttfamily stubnet {\it prefix\/} $\{$ {\it options\/} $\}$\relax }{section*.1065}{}}
-\newlabel{ospf-iface}{{6.8.2}{43}{\ttfamily interface {\it pattern\/} {[}instance {\it num\/}{]}\relax }{section*.1069}{}}
-\newlabel{ospf-virtual-link}{{6.8.2}{43}{\ttfamily virtual link {\it id\/} {[}instance {\it num\/}{]}\relax }{section*.1073}{}}
-\newlabel{ospf-cost}{{6.8.2}{43}{\ttfamily cost {\it num\/}\relax }{section*.1076}{}}
-\newlabel{ospf-stub-iface}{{6.8.2}{43}{\ttfamily stub {\it switch\/}\relax }{section*.1079}{}}
-\newlabel{ospf-hello}{{6.8.2}{44}{\ttfamily hello {\it num\/}\relax }{section*.1082}{}}
-\newlabel{ospf-poll}{{6.8.2}{44}{\ttfamily poll {\it num\/}\relax }{section*.1085}{}}
-\newlabel{ospf-retransmit}{{6.8.2}{44}{\ttfamily retransmit {\it num\/}\relax }{section*.1088}{}}
-\newlabel{ospf-transmit-delay}{{6.8.2}{44}{\ttfamily transmit delay {\it num\/}\relax }{section*.1091}{}}
-\newlabel{ospf-priority}{{6.8.2}{44}{\ttfamily priority {\it num\/}\relax }{section*.1094}{}}
-\newlabel{ospf-wait}{{6.8.2}{44}{\ttfamily wait {\it num\/}\relax }{section*.1097}{}}
-\newlabel{ospf-dead-count}{{6.8.2}{44}{\ttfamily dead count {\it num\/}\relax }{section*.1100}{}}
-\newlabel{ospf-dead}{{6.8.2}{44}{\ttfamily dead {\it num\/}\relax }{section*.1103}{}}
-\newlabel{ospf-secondary}{{6.8.2}{44}{\ttfamily secondary {\it switch\/}\relax }{section*.1106}{}}
-\newlabel{ospf-rx-buffer}{{6.8.2}{44}{\ttfamily rx buffer {\it num\/}\relax }{section*.1109}{}}
-\newlabel{ospf-tx-length}{{6.8.2}{44}{\ttfamily tx length {\it num\/}\relax }{section*.1112}{}}
-\newlabel{ospf-type-bcast}{{6.8.2}{44}{\ttfamily type broadcast$|$bcast\relax }{section*.1115}{}}
-\newlabel{ospf-type-ptp}{{6.8.2}{45}{\ttfamily type pointopoint$|$ptp\relax }{section*.1118}{}}
-\newlabel{ospf-type-nbma}{{6.8.2}{45}{\ttfamily type nonbroadcast$|$nbma\relax }{section*.1121}{}}
-\newlabel{ospf-type-ptmp}{{6.8.2}{45}{\ttfamily type pointomultipoint$|$ptmp\relax }{section*.1124}{}}
-\newlabel{ospf-link-lsa-suppression}{{6.8.2}{45}{\ttfamily link lsa suppression {\it switch\/}\relax }{section*.1127}{}}
-\newlabel{ospf-strict-nonbroadcast}{{6.8.2}{45}{\ttfamily strict nonbroadcast {\it switch\/}\relax }{section*.1130}{}}
-\newlabel{ospf-real-broadcast}{{6.8.2}{45}{\ttfamily real broadcast {\it switch\/}\relax }{section*.1133}{}}
-\newlabel{ospf-ptp-netmask}{{6.8.2}{45}{\ttfamily ptp netmask {\it switch\/}\relax }{section*.1136}{}}
-\newlabel{ospf-check-link}{{6.8.2}{45}{\ttfamily check link {\it switch\/}\relax }{section*.1139}{}}
-\newlabel{ospf-bfd}{{6.8.2}{45}{\ttfamily bfd {\it switch\/}\relax }{section*.1142}{}}
-\newlabel{ospf-ttl-security}{{6.8.2}{45}{\ttfamily ttl security {[}{\it switch\/} $|$ tx only{]}\relax }{section*.1145}{}}
-\newlabel{ospf-tx-class}{{6.8.2}{46}{\ttfamily tx class$|$dscp$|$priority {\it num\/}\relax }{section*.1149}{}}
-\newlabel{ospf-ecmp-weight}{{6.8.2}{46}{\ttfamily ecmp weight {\it num\/}\relax }{section*.1152}{}}
-\newlabel{ospf-auth-none}{{6.8.2}{46}{\ttfamily authentication none\relax }{section*.1155}{}}
-\newlabel{ospf-auth-simple}{{6.8.2}{46}{\ttfamily authentication simple\relax }{section*.1158}{}}
-\newlabel{ospf-auth-cryptographic}{{6.8.2}{46}{\ttfamily authentication cryptographic\relax }{section*.1161}{}}
-\newlabel{ospf-pass}{{6.8.2}{46}{\ttfamily password "{\it text\/}"\relax }{section*.1164}{}}
-\newlabel{ospf-neighbors}{{6.8.2}{46}{\ttfamily neighbors $\{$ {\it set\/} $\}$\relax }{section*.1167}{}}
-\newlabel{ospf-attr}{{6.8.3}{46}{Attributes\relax }{subsection.6.8.3}{}}
-\@writefile{toc}{\contentsline {subsection}{\numberline {6.8.3}Attributes }{46}{subsection.6.8.3}}
-\newlabel{ospf-exam}{{6.8.4}{46}{Example\relax }{subsection.6.8.4}{}}
-\@writefile{toc}{\contentsline {subsection}{\numberline {6.8.4}Example }{46}{subsection.6.8.4}}
-\newlabel{pipe}{{6.9}{47}{Pipe\relax }{section.6.9}{}}
-\@writefile{toc}{\contentsline {section}{\numberline {6.9}Pipe }{47}{section.6.9}}
-\newlabel{pipe-intro}{{6.9.1}{47}{Introduction\relax }{subsection.6.9.1}{}}
-\@writefile{toc}{\contentsline {subsection}{\numberline {6.9.1}Introduction }{47}{subsection.6.9.1}}
-\newlabel{pipe-config}{{6.9.2}{48}{Configuration\relax }{subsection.6.9.2}{}}
-\@writefile{toc}{\contentsline {subsection}{\numberline {6.9.2}Configuration }{48}{subsection.6.9.2}}
-\newlabel{pipe-peer-table}{{6.9.2}{48}{\ttfamily peer table {\it table\/}\relax }{section*.1188}{}}
-\newlabel{pipe-mode}{{6.9.2}{48}{\ttfamily mode opaque$|$transparent\relax }{section*.1191}{}}
-\newlabel{pipe-attr}{{6.9.3}{48}{Attributes\relax }{subsection.6.9.3}{}}
-\@writefile{toc}{\contentsline {subsection}{\numberline {6.9.3}Attributes }{48}{subsection.6.9.3}}
-\newlabel{pipe-exam}{{6.9.4}{48}{Example\relax }{subsection.6.9.4}{}}
-\@writefile{toc}{\contentsline {subsection}{\numberline {6.9.4}Example }{48}{subsection.6.9.4}}
-\newlabel{radv}{{6.10}{49}{RAdv\relax }{section.6.10}{}}
-\@writefile{toc}{\contentsline {section}{\numberline {6.10}RAdv }{49}{section.6.10}}
-\newlabel{radv-intro}{{6.10.1}{49}{Introduction\relax }{subsection.6.10.1}{}}
-\@writefile{toc}{\contentsline {subsection}{\numberline {6.10.1}Introduction }{49}{subsection.6.10.1}}
-\newlabel{radv-config}{{6.10.2}{49}{Configuration\relax }{subsection.6.10.2}{}}
-\@writefile{toc}{\contentsline {subsection}{\numberline {6.10.2}Configuration }{49}{subsection.6.10.2}}
-\newlabel{radv-iface}{{6.10.2}{49}{\ttfamily interface {\it pattern\/} {[}, {\it ...\/}{]} $\{$ {\it options\/} $\}$\relax }{section*.1206}{}}
-\newlabel{radv-prefix}{{6.10.2}{50}{\ttfamily prefix {\it prefix\/} $\{$ {\it options\/} $\}$\relax }{section*.1209}{}}
-\newlabel{radv-rdnss}{{6.10.2}{50}{\ttfamily rdnss $\{$ {\it options\/} $\}$\relax }{section*.1213}{}}
-\newlabel{radv-dnssl}{{6.10.2}{50}{\ttfamily dnssl $\{$ {\it options\/} $\}$\relax }{section*.1216}{}}
-\newlabel{radv-trigger}{{6.10.2}{50}{\ttfamily trigger {\it prefix\/}\relax }{section*.1219}{}}
-\newlabel{radv-propagate-routes}{{6.10.2}{50}{\ttfamily propagate routes {\it switch\/}\relax }{section*.1223}{}}
-\newlabel{radv-iface-max-ra-interval}{{6.10.2}{50}{\ttfamily max ra interval {\it expr\/}\relax }{section*.1229}{}}
-\newlabel{radv-iface-min-ra-interval}{{6.10.2}{50}{\ttfamily min ra interval {\it expr\/}\relax }{section*.1232}{}}
-\newlabel{radv-iface-min-delay}{{6.10.2}{50}{\ttfamily min delay {\it expr\/}\relax }{section*.1235}{}}
-\newlabel{radv-iface-managed}{{6.10.2}{50}{\ttfamily managed {\it switch\/}\relax }{section*.1238}{}}
-\newlabel{radv-iface-other-config}{{6.10.2}{51}{\ttfamily other config {\it switch\/}\relax }{section*.1241}{}}
-\newlabel{radv-iface-link-mtu}{{6.10.2}{51}{\ttfamily link mtu {\it expr\/}\relax }{section*.1244}{}}
-\newlabel{radv-iface-reachable-time}{{6.10.2}{51}{\ttfamily reachable time {\it expr\/}\relax }{section*.1247}{}}
-\newlabel{radv-iface-retrans-timer}{{6.10.2}{51}{\ttfamily retrans timer {\it expr\/}\relax }{section*.1250}{}}
-\newlabel{radv-iface-current-hop-limit}{{6.10.2}{51}{\ttfamily current hop limit {\it expr\/}\relax }{section*.1253}{}}
-\newlabel{radv-iface-default-lifetime}{{6.10.2}{51}{\ttfamily default lifetime {\it expr\/} {[}sensitive {\it switch\/}{]}\relax }{section*.1256}{}}
-\newlabel{radv-iface-default-preference}{{6.10.2}{51}{\ttfamily default preference low$|$medium$|$high\relax }{section*.1259}{}}
-\newlabel{radv-iface-route-lifetime}{{6.10.2}{51}{\ttfamily route lifetime {\it expr\/} {[}sensitive {\it switch\/}{]}\relax }{section*.1262}{}}
-\newlabel{radv-iface-route-preference}{{6.10.2}{51}{\ttfamily route preference low$|$medium$|$high\relax }{section*.1266}{}}
-\newlabel{radv-prefix-linger-time}{{6.10.2}{51}{\ttfamily prefix linger time {\it expr\/}\relax }{section*.1269}{}}
-\newlabel{radv-route-linger-time}{{6.10.2}{51}{\ttfamily route linger time {\it expr\/}\relax }{section*.1272}{}}
-\newlabel{radv-iface-rdnss-local}{{6.10.2}{51}{\ttfamily rdnss local {\it switch\/}\relax }{section*.1275}{}}
-\newlabel{radv-iface-dnssl-local}{{6.10.2}{51}{\ttfamily dnssl local {\it switch\/}\relax }{section*.1278}{}}
-\newlabel{radv-prefix-skip}{{6.10.2}{51}{\ttfamily skip {\it switch\/}\relax }{section*.1284}{}}
-\newlabel{radv-prefix-onlink}{{6.10.2}{52}{\ttfamily onlink {\it switch\/}\relax }{section*.1287}{}}
-\newlabel{radv-prefix-autonomous}{{6.10.2}{52}{\ttfamily autonomous {\it switch\/}\relax }{section*.1290}{}}
-\newlabel{radv-prefix-valid-lifetime}{{6.10.2}{52}{\ttfamily valid lifetime {\it expr\/} {[}sensitive {\it switch\/}{]}\relax }{section*.1293}{}}
-\newlabel{radv-prefix-preferred-lifetime}{{6.10.2}{52}{\ttfamily preferred lifetime {\it expr\/} {[}sensitive {\it switch\/}{]}\relax }{section*.1296}{}}
-\newlabel{radv-rdnss-ns}{{6.10.2}{52}{\ttfamily ns {\it address\/}\relax }{section*.1301}{}}
-\newlabel{radv-rdnss-lifetime}{{6.10.2}{52}{\ttfamily lifetime {[}mult{]} {\it expr\/}\relax }{section*.1304}{}}
-\newlabel{radv-dnssl-domain}{{6.10.2}{52}{\ttfamily domain {\it address\/}\relax }{section*.1310}{}}
-\newlabel{radv-dnssl-lifetime}{{6.10.2}{52}{\ttfamily lifetime {[}mult{]} {\it expr\/}\relax }{section*.1313}{}}
-\newlabel{radv-attr}{{6.10.3}{52}{Attributes\relax }{subsection.6.10.3}{}}
-\@writefile{toc}{\contentsline {subsection}{\numberline {6.10.3}Attributes }{52}{subsection.6.10.3}}
-\newlabel{rta-ra-preference}{{6.10.3}{52}{\ttfamily enum ra\_preference\relax }{section*.1318}{}}
-\newlabel{rta-ra-lifetime}{{6.10.3}{52}{\ttfamily int ra\_lifetime\relax }{section*.1321}{}}
-\newlabel{radv-exam}{{6.10.4}{52}{Example\relax }{subsection.6.10.4}{}}
-\@writefile{toc}{\contentsline {subsection}{\numberline {6.10.4}Example }{52}{subsection.6.10.4}}
-\newlabel{rip}{{6.11}{54}{RIP\relax }{section.6.11}{}}
-\@writefile{toc}{\contentsline {section}{\numberline {6.11}RIP }{54}{section.6.11}}
-\newlabel{rip-intro}{{6.11.1}{54}{Introduction\relax }{subsection.6.11.1}{}}
-\@writefile{toc}{\contentsline {subsection}{\numberline {6.11.1}Introduction }{54}{subsection.6.11.1}}
-\newlabel{rip-config}{{6.11.2}{54}{Configuration\relax }{subsection.6.11.2}{}}
-\@writefile{toc}{\contentsline {subsection}{\numberline {6.11.2}Configuration }{54}{subsection.6.11.2}}
-\newlabel{rip-infinity}{{6.11.2}{55}{\ttfamily infinity {\it number\/}\relax }{section*.1336}{}}
-\newlabel{rip-ecmp}{{6.11.2}{55}{\ttfamily ecmp {\it switch\/} {[}limit {\it number\/}{]}\relax }{section*.1339}{}}
-\newlabel{rip-iface}{{6.11.2}{55}{\ttfamily interface {\it pattern\/} {[}, {\it ...\/}{]} $\{$ {\it options\/} $\}$\relax }{section*.1342}{}}
-\newlabel{rip-iface-metric}{{6.11.2}{55}{\ttfamily metric {\it num\/}\relax }{section*.1347}{}}
-\newlabel{rip-iface-mode}{{6.11.2}{55}{\ttfamily mode multicast$|$broadcast\relax }{section*.1350}{}}
-\newlabel{rip-iface-passive}{{6.11.2}{55}{\ttfamily passive {\it switch\/}\relax }{section*.1353}{}}
-\newlabel{rip-iface-address}{{6.11.2}{55}{\ttfamily address {\it ip\/}\relax }{section*.1356}{}}
-\newlabel{rip-iface-port}{{6.11.2}{55}{\ttfamily port {\it number\/}\relax }{section*.1359}{}}
-\newlabel{rip-iface-version}{{6.11.2}{55}{\ttfamily version 1$|$2\relax }{section*.1362}{}}
-\newlabel{rip-iface-version-only}{{6.11.2}{55}{\ttfamily version only {\it switch\/}\relax }{section*.1365}{}}
-\newlabel{rip-iface-split-horizon}{{6.11.2}{55}{\ttfamily split horizon {\it switch\/}\relax }{section*.1368}{}}
-\newlabel{rip-iface-poison-reverse}{{6.11.2}{55}{\ttfamily poison reverse {\it switch\/}\relax }{section*.1371}{}}
-\newlabel{rip-iface-check-zero}{{6.11.2}{56}{\ttfamily check zero {\it switch\/}\relax }{section*.1374}{}}
-\newlabel{rip-iface-update-time}{{6.11.2}{56}{\ttfamily update time {\it number\/}\relax }{section*.1377}{}}
-\newlabel{rip-iface-timeout-time}{{6.11.2}{56}{\ttfamily timeout time {\it number\/}\relax }{section*.1380}{}}
-\newlabel{rip-iface-garbage-time}{{6.11.2}{56}{\ttfamily garbage time {\it number\/}\relax }{section*.1383}{}}
-\newlabel{rip-iface-ecmp-weight}{{6.11.2}{56}{\ttfamily ecmp weight {\it number\/}\relax }{section*.1386}{}}
-\newlabel{rip-iface-auth}{{6.11.2}{56}{\ttfamily authentication none$|$plaintext$|$cryptographic\relax }{section*.1389}{}}
-\newlabel{rip-iface-pass}{{6.11.2}{56}{\ttfamily password "{\it text\/}"\relax }{section*.1392}{}}
-\newlabel{rip-iface-ttl-security}{{6.11.2}{56}{\ttfamily ttl security {[}{\it switch\/} $|$ tx only{]}\relax }{section*.1395}{}}
-\newlabel{rip-iface-tx-class}{{6.11.2}{56}{\ttfamily tx class$|$dscp$|$priority {\it number\/}\relax }{section*.1400}{}}
-\newlabel{rip-iface-rx-buffer}{{6.11.2}{56}{\ttfamily rx buffer {\it number\/}\relax }{section*.1403}{}}
-\newlabel{rip-iface-tx-length}{{6.11.2}{56}{\ttfamily tx length {\it number\/}\relax }{section*.1406}{}}
-\newlabel{rip-iface-check-link}{{6.11.2}{56}{\ttfamily check link {\it switch\/}\relax }{section*.1409}{}}
-\newlabel{rip-attr}{{6.11.3}{57}{Attributes\relax }{subsection.6.11.3}{}}
-\@writefile{toc}{\contentsline {subsection}{\numberline {6.11.3}Attributes }{57}{subsection.6.11.3}}
-\newlabel{rta-rip-metric}{{6.11.3}{57}{\ttfamily int rip\_metric\relax }{section*.1414}{}}
-\newlabel{rta-rip-tag}{{6.11.3}{57}{\ttfamily int rip\_tag\relax }{section*.1417}{}}
-\newlabel{rip-exam}{{6.11.4}{57}{Example\relax }{subsection.6.11.4}{}}
-\@writefile{toc}{\contentsline {subsection}{\numberline {6.11.4}Example }{57}{subsection.6.11.4}}
-\newlabel{static}{{6.12}{57}{Static\relax }{section.6.12}{}}
-\@writefile{toc}{\contentsline {section}{\numberline {6.12}Static }{57}{section.6.12}}
-\newlabel{static-check-link}{{6.12}{57}{\ttfamily check link {\it switch\/}\relax }{section*.1433}{}}
-\newlabel{static-igp-table}{{6.12}{58}{\ttfamily igp table {\it name\/}\relax }{section*.1436}{}}
-\newlabel{static-route-via-ip}{{6.12}{58}{\ttfamily route {\it prefix\/} via {\it ip\/}\relax }{section*.1441}{}}
-\newlabel{static-route-via-mpath}{{6.12}{58}{\ttfamily route {\it prefix\/} multipath via {\it ip\/} {[}weight {\it num\/}{]} {[}bfd {\it switch\/}{]} {[}via {\it ...\/}{]}\relax }{section*.1444}{}}
-\newlabel{static-route-via-iface}{{6.12}{58}{\ttfamily route {\it prefix\/} via {\it "interface"\/}\relax }{section*.1447}{}}
-\newlabel{static-route-recursive}{{6.12}{58}{\ttfamily route {\it prefix\/} recursive {\it ip\/}\relax }{section*.1450}{}}
-\newlabel{static-route-drop}{{6.12}{58}{\ttfamily route {\it prefix\/} blackhole$|$unreachable$|$prohibit\relax }{section*.1453}{}}
-\newlabel{static-route-bfd}{{6.12}{58}{\ttfamily bfd {\it switch\/}\relax }{section*.1458}{}}
-\newlabel{static-route-filter}{{6.12}{58}{\ttfamily \it filter expression\/\relax }{section*.1462}{}}
-\@writefile{toc}{\contentsline {chapter}{\numberline {7}Conclusions }{60}{chapter.7}}
-\@writefile{lof}{\addvspace {10\p@ }}
-\@writefile{lot}{\addvspace {10\p@ }}
-\newlabel{conclusion}{{7}{60}{Conclusions\relax }{chapter.7}{}}
-\newlabel{future-work}{{7.1}{60}{Future work\relax }{section.7.1}{}}
-\@writefile{toc}{\contentsline {section}{\numberline {7.1}Future work }{60}{section.7.1}}
-\newlabel{help}{{7.2}{60}{Getting more help\relax }{section.7.2}{}}
-\@writefile{toc}{\contentsline {section}{\numberline {7.2}Getting more help }{60}{section.7.2}}
diff --git a/doc/bird.conf.example2 b/doc/bird.conf.example2
index 815651c7..0f9b4714 100644
--- a/doc/bird.conf.example2
+++ b/doc/bird.conf.example2
@@ -1,5 +1,5 @@
/*
- * This is an example configuration file for MB-BGP setting
+ * This is an example configuration file for MP-BGP setting
*/
diff --git a/doc/bird.log b/doc/bird.log
deleted file mode 100644
index 34724fb7..00000000
--- a/doc/bird.log
+++ /dev/null
@@ -1,472 +0,0 @@
-This is pdfTeX, Version 3.1415926-2.4-1.40.13 (TeX Live 2012/Debian) (format=pdflatex 2014.8.6) 11 SEP 2019 20:40
-entering extended mode
- restricted \write18 enabled.
- %&-line parsing enabled.
-**bird.tex
-(./bird.tex
-LaTeX2e <2011/06/27>
-Babel <v3.8m> and hyphenation patterns for english, dumylang, nohyphenation, cr
-oatian, bulgarian, ukrainian, russian, slovak, czech, danish, dutch, finnish, f
-rench, basque, ngerman, german, swissgerman, ngerman-x-2012-05-30, german-x-201
-2-05-30, monogreek, greek, ibycus, ancientgreek, hungarian, italian, latin, mon
-golian, mongolianlmc, nynorsk, bokmal, indonesian, esperanto, coptic, welsh, ir
-ish, interlingua, serbian, serbianc, slovenian, friulan, romansh, estonian, rom
-anian, armenian, uppersorbian, turkish, afrikaans, icelandic, kurmanji, polish,
- portuguese, galician, catalan, spanish, swedish, thai, loaded.
-(/usr/share/texlive/texmf-dist/tex/latex/base/book.cls
-Document Class: book 2007/10/19 v1.4h Standard LaTeX document class
-(/usr/share/texlive/texmf-dist/tex/latex/base/bk10.clo
-File: bk10.clo 2007/10/19 v1.4h Standard LaTeX file (size option)
-)
-\c@part=\count79
-\c@chapter=\count80
-\c@section=\count81
-\c@subsection=\count82
-\c@subsubsection=\count83
-\c@paragraph=\count84
-\c@subparagraph=\count85
-\c@figure=\count86
-\c@table=\count87
-\abovecaptionskip=\skip41
-\belowcaptionskip=\skip42
-\bibindent=\dimen102
-)
-(/usr/share/texlive/texmf-dist/tex/latex/hyperref/hyperref.sty
-Package: hyperref 2012/05/13 v6.82q Hypertext links for LaTeX
-
-(/usr/share/texlive/texmf-dist/tex/generic/oberdiek/hobsub-hyperref.sty
-Package: hobsub-hyperref 2012/05/28 v1.13 Bundle oberdiek, subset hyperref (HO)
-
-
-(/usr/share/texlive/texmf-dist/tex/generic/oberdiek/hobsub-generic.sty
-Package: hobsub-generic 2012/05/28 v1.13 Bundle oberdiek, subset generic (HO)
-Package: hobsub 2012/05/28 v1.13 Construct package bundles (HO)
-Package: infwarerr 2010/04/08 v1.3 Providing info/warning/error messages (HO)
-Package: ltxcmds 2011/11/09 v1.22 LaTeX kernel commands for general use (HO)
-Package: ifluatex 2010/03/01 v1.3 Provides the ifluatex switch (HO)
-Package ifluatex Info: LuaTeX not detected.
-Package: ifvtex 2010/03/01 v1.5 Detect VTeX and its facilities (HO)
-Package ifvtex Info: VTeX not detected.
-Package: intcalc 2007/09/27 v1.1 Expandable calculations with integers (HO)
-Package: ifpdf 2011/01/30 v2.3 Provides the ifpdf switch (HO)
-Package ifpdf Info: pdfTeX in PDF mode is detected.
-Package: etexcmds 2011/02/16 v1.5 Avoid name clashes with e-TeX commands (HO)
-Package etexcmds Info: Could not find \expanded.
-(etexcmds) That can mean that you are not using pdfTeX 1.50 or
-(etexcmds) that some package has redefined \expanded.
-(etexcmds) In the latter case, load this package earlier.
-Package: kvsetkeys 2012/04/25 v1.16 Key value parser (HO)
-Package: kvdefinekeys 2011/04/07 v1.3 Define keys (HO)
-Package: pdftexcmds 2011/11/29 v0.20 Utility functions of pdfTeX for LuaTeX (HO
-)
-Package pdftexcmds Info: LuaTeX not detected.
-Package pdftexcmds Info: \pdf@primitive is available.
-Package pdftexcmds Info: \pdf@ifprimitive is available.
-Package pdftexcmds Info: \pdfdraftmode found.
-Package: pdfescape 2011/11/25 v1.13 Implements pdfTeX's escape features (HO)
-Package: bigintcalc 2012/04/08 v1.3 Expandable calculations on big integers (HO
-)
-Package: bitset 2011/01/30 v1.1 Handle bit-vector datatype (HO)
-Package: uniquecounter 2011/01/30 v1.2 Provide unlimited unique counter (HO)
-)
-Package hobsub Info: Skipping package `hobsub' (already loaded).
-Package: letltxmacro 2010/09/02 v1.4 Let assignment for LaTeX macros (HO)
-Package: hopatch 2012/05/28 v1.2 Wrapper for package hooks (HO)
-Package: xcolor-patch 2011/01/30 xcolor patch
-Package: atveryend 2011/06/30 v1.8 Hooks at the very end of document (HO)
-Package atveryend Info: \enddocument detected (standard20110627).
-Package: atbegshi 2011/10/05 v1.16 At begin shipout hook (HO)
-Package: refcount 2011/10/16 v3.4 Data extraction from label references (HO)
-Package: hycolor 2011/01/30 v1.7 Color options for hyperref/bookmark (HO)
-)
-(/usr/share/texlive/texmf-dist/tex/latex/graphics/keyval.sty
-Package: keyval 1999/03/16 v1.13 key=value parser (DPC)
-\KV@toks@=\toks14
-)
-(/usr/share/texlive/texmf-dist/tex/generic/ifxetex/ifxetex.sty
-Package: ifxetex 2010/09/12 v0.6 Provides ifxetex conditional
-)
-(/usr/share/texlive/texmf-dist/tex/latex/oberdiek/kvoptions.sty
-Package: kvoptions 2011/06/30 v3.11 Key value format for package options (HO)
-)
-\@linkdim=\dimen103
-\Hy@linkcounter=\count88
-\Hy@pagecounter=\count89
-
-(/usr/share/texlive/texmf-dist/tex/latex/hyperref/pd1enc.def
-File: pd1enc.def 2012/05/13 v6.82q Hyperref: PDFDocEncoding definition (HO)
-)
-\Hy@SavedSpaceFactor=\count90
-
-(/usr/share/texlive/texmf-dist/tex/latex/latexconfig/hyperref.cfg
-File: hyperref.cfg 2002/06/06 v1.2 hyperref configuration of TeXLive
-)
-Package hyperref Info: Option `colorlinks' set `true' on input line 3941.
-Package hyperref Info: Hyper figures OFF on input line 4062.
-Package hyperref Info: Link nesting OFF on input line 4067.
-Package hyperref Info: Hyper index ON on input line 4070.
-Package hyperref Info: Plain pages OFF on input line 4077.
-Package hyperref Info: Backreferencing OFF on input line 4082.
-Package hyperref Info: Implicit mode ON; LaTeX internals redefined.
-Package hyperref Info: Bookmarks ON on input line 4300.
-\c@Hy@tempcnt=\count91
-
-(/usr/share/texlive/texmf-dist/tex/latex/url/url.sty
-\Urlmuskip=\muskip10
-Package: url 2006/04/12 ver 3.3 Verb mode for urls, etc.
-)
-LaTeX Info: Redefining \url on input line 4653.
-\Fld@menulength=\count92
-\Field@Width=\dimen104
-\Fld@charsize=\dimen105
-Package hyperref Info: Hyper figures OFF on input line 5773.
-Package hyperref Info: Link nesting OFF on input line 5778.
-Package hyperref Info: Hyper index ON on input line 5781.
-Package hyperref Info: backreferencing OFF on input line 5788.
-Package hyperref Info: Link coloring ON on input line 5791.
-Package hyperref Info: Link coloring with OCG OFF on input line 5798.
-Package hyperref Info: PDF/A mode OFF on input line 5803.
-LaTeX Info: Redefining \ref on input line 5843.
-LaTeX Info: Redefining \pageref on input line 5847.
-\Hy@abspage=\count93
-\c@Item=\count94
-\c@Hfootnote=\count95
-)
-
-Package hyperref Message: Driver (autodetected): hpdftex.
-
-(/usr/share/texlive/texmf-dist/tex/latex/hyperref/hpdftex.def
-File: hpdftex.def 2012/05/13 v6.82q Hyperref driver for pdfTeX
-\Fld@listcount=\count96
-\c@bookmark@seq@number=\count97
-
-(/usr/share/texlive/texmf-dist/tex/latex/oberdiek/rerunfilecheck.sty
-Package: rerunfilecheck 2011/04/15 v1.7 Rerun checks for auxiliary files (HO)
-Package uniquecounter Info: New unique counter `rerunfilecheck' on input line 2
-82.
-)
-\Hy@SectionHShift=\skip43
-)
-(/usr/share/texlive/texmf-dist/tex/latex/enumitem/enumitem.sty
-Package: enumitem 2011/09/28 v3.5.2 Customized lists
-\labelindent=\skip44
-\enit@outerparindent=\dimen106
-\enit@toks=\toks15
-\enit@inbox=\box26
-\enitdp@description=\count98
-)
-(/home/feela/src/git/bird/doc/tex/birddoc.sty
-Package: birddoc
-)
-(/usr/share/texmf/tex/latex/misc/qwertz.sty
-\c@definition=\count99
-\c@proposition=\count100
-\c@lemma=\count101
-\c@corollary=\count102
-\c@theorem=\count103
-)
-(/usr/share/texlive/texmf-dist/tex/latex/base/inputenc.sty
-Package: inputenc 2008/03/30 v1.1d Input encoding file
-\inpenc@prehook=\toks16
-\inpenc@posthook=\toks17
-
-(/usr/share/texlive/texmf-dist/tex/latex/base/latin1.def
-File: latin1.def 2008/03/30 v1.1d Input encoding file
-))
-(/usr/share/texlive/texmf-dist/tex/latex/graphics/epsfig.sty
-Package: epsfig 1999/02/16 v1.7a (e)psfig emulation (SPQR)
-
-(/usr/share/texlive/texmf-dist/tex/latex/graphics/graphicx.sty
-Package: graphicx 1999/02/16 v1.0f Enhanced LaTeX Graphics (DPC,SPQR)
-
-(/usr/share/texlive/texmf-dist/tex/latex/graphics/graphics.sty
-Package: graphics 2009/02/05 v1.0o Standard LaTeX Graphics (DPC,SPQR)
-
-(/usr/share/texlive/texmf-dist/tex/latex/graphics/trig.sty
-Package: trig 1999/03/16 v1.09 sin cos tan (DPC)
-)
-(/usr/share/texlive/texmf-dist/tex/latex/latexconfig/graphics.cfg
-File: graphics.cfg 2010/04/23 v1.9 graphics configuration of TeX Live
-)
-Package graphics Info: Driver file: pdftex.def on input line 91.
-
-(/usr/share/texlive/texmf-dist/tex/latex/pdftex-def/pdftex.def
-File: pdftex.def 2011/05/27 v0.06d Graphics/color for pdfTeX
-\Gread@gobject=\count104
-))
-\Gin@req@height=\dimen107
-\Gin@req@width=\dimen108
-)
-\epsfxsize=\dimen109
-\epsfysize=\dimen110
-)
-(/usr/share/texmf/tex/latex/misc/null.sty) (./bird.aux)
-\openout1 = `bird.aux'.
-
-LaTeX Font Info: Checking defaults for OML/cmm/m/it on input line 20.
-LaTeX Font Info: ... okay on input line 20.
-LaTeX Font Info: Checking defaults for T1/cmr/m/n on input line 20.
-LaTeX Font Info: ... okay on input line 20.
-LaTeX Font Info: Checking defaults for OT1/cmr/m/n on input line 20.
-LaTeX Font Info: ... okay on input line 20.
-LaTeX Font Info: Checking defaults for OMS/cmsy/m/n on input line 20.
-LaTeX Font Info: ... okay on input line 20.
-LaTeX Font Info: Checking defaults for OMX/cmex/m/n on input line 20.
-LaTeX Font Info: ... okay on input line 20.
-LaTeX Font Info: Checking defaults for U/cmr/m/n on input line 20.
-LaTeX Font Info: ... okay on input line 20.
-LaTeX Font Info: Checking defaults for PD1/pdf/m/n on input line 20.
-LaTeX Font Info: ... okay on input line 20.
-\AtBeginShipoutBox=\box27
-
-(/usr/share/texlive/texmf-dist/tex/latex/graphics/color.sty
-Package: color 2005/11/14 v1.0j Standard LaTeX Color (DPC)
-
-(/usr/share/texlive/texmf-dist/tex/latex/latexconfig/color.cfg
-File: color.cfg 2007/01/18 v1.5 color configuration of teTeX/TeXLive
-)
-Package color Info: Driver file: pdftex.def on input line 130.
-)
-Package hyperref Info: Link coloring ON on input line 20.
-
-(/usr/share/texlive/texmf-dist/tex/latex/hyperref/nameref.sty
-Package: nameref 2010/04/30 v2.40 Cross-referencing by name of section
-
-(/usr/share/texlive/texmf-dist/tex/generic/oberdiek/gettitlestring.sty
-Package: gettitlestring 2010/12/03 v1.4 Cleanup title references (HO)
-)
-\c@section@level=\count105
-)
-LaTeX Info: Redefining \ref on input line 20.
-LaTeX Info: Redefining \pageref on input line 20.
-LaTeX Info: Redefining \nameref on input line 20.
-
-(./bird.out) (./bird.out)
-\@outlinefile=\write3
-\openout3 = `bird.out'.
-
-
-(/usr/share/texlive/texmf-dist/tex/context/base/supp-pdf.mkii
-[Loading MPS to PDF converter (version 2006.09.02).]
-\scratchcounter=\count106
-\scratchdimen=\dimen111
-\scratchbox=\box28
-\nofMPsegments=\count107
-\nofMParguments=\count108
-\everyMPshowfont=\toks18
-\MPscratchCnt=\count109
-\MPscratchDim=\dimen112
-\MPnumerator=\count110
-\makeMPintoPDFobject=\count111
-\everyMPtoPDFconversion=\toks19
-) (/usr/share/texlive/texmf-dist/tex/latex/oberdiek/epstopdf-base.sty
-Package: epstopdf-base 2010/02/09 v2.5 Base part for package epstopdf
-
-(/usr/share/texlive/texmf-dist/tex/latex/oberdiek/grfext.sty
-Package: grfext 2010/08/19 v1.1 Manage graphics extensions (HO)
-)
-Package grfext Info: Graphics extension search list:
-(grfext) [.png,.pdf,.jpg,.mps,.jpeg,.jbig2,.jb2,.PNG,.PDF,.JPG,.JPE
-G,.JBIG2,.JB2,.eps]
-(grfext) \AppendGraphicsExtensions on input line 452.
-
-(/usr/share/texlive/texmf-dist/tex/latex/latexconfig/epstopdf-sys.cfg
-File: epstopdf-sys.cfg 2010/07/13 v1.3 Configuration of (r)epstopdf for TeX Liv
-e
-))
-LaTeX Font Info: External font `cmex10' loaded for size
-(Font) <7> on input line 21.
-LaTeX Font Info: External font `cmex10' loaded for size
-(Font) <5> on input line 21.
-
-Underfull \hbox (badness 10000) in paragraph at lines 21--21
-
- []
-
-[1
-
-{/var/lib/texmf/fonts/map/pdftex/updmap/pdftex.map}] (./bird.toc)
-\tf@toc=\write4
-\openout4 = `bird.toc'.
-
- [2
-
-]
-Chapter 1.
-LaTeX Font Info: Try loading font information for OMS+cmr on input line 81.
-(/usr/share/texlive/texmf-dist/tex/latex/base/omscmr.fd
-File: omscmr.fd 1999/05/25 v2.5h Standard LaTeX font definitions
-)
-LaTeX Font Info: Font shape `OMS/cmr/m/n' in size <10> not available
-(Font) Font shape `OMS/cmsy/m/n' tried instead on input line 81.
- [3
-
-]
-LaTeX Font Info: Font shape `OT1/cmtt/bx/n' in size <10> not available
-(Font) Font shape `OT1/cmtt/m/n' tried instead on input line 164.
- [4] [5]
-Chapter 2.
-[6
-
-]
-Chapter 3.
-[7
-
-] [8] [9] [10] [11] [12]
-Chapter 4.
-
-Underfull \hbox (badness 10000) in paragraph at lines 1046--1050
- [] []\OT1/cmtt/m/n/10 show route [[for] \OT1/cmr/m/it/10 pre-fix$\OMS/cmsy/m
-/n/10 j$\OT1/cmr/m/it/10 IP\OT1/cmtt/m/n/10 ] [table \OT1/cmr/m/it/10 t\OT1/cmt
-t/m/n/10 ] [filter \OT1/cmr/m/it/10 f$\OMS/cmsy/m/n/10 j$\OT1/cmtt/m/n/10 where
- \OT1/cmr/m/it/10 c\OT1/cmtt/m/n/10 ] [(export$\OMS/cmsy/m/n/10 j$\OT1/cmtt/m/n
-/10 preexport$\OMS/cmsy/m/n/10 j$\OT1/cmtt/m/n/10 noexport) \OT1/cmr/m/it/10 p\
-OT1/cmtt/m/n/10 ]
- []
-
-[13
-
-] [14] [15]
-Chapter 5.
-[16
-
-] [17]
-Underfull \hbox (badness 5050) in paragraph at lines 1449--1456
-[]\OT1/cmr/m/n/10 For pair sets, ex-pres-sions like \OT1/cmtt/m/n/10 (123,*) \O
-T1/cmr/m/n/10 can be used to de-note ranges (in that case
- []
-
-
-Overfull \hbox (27.12624pt too wide) in paragraph at lines 1486--1486
- [] \OT1/cmtt/m/n/10 es = [ (rt, myas, 3*10), (rt, myas+one, 0..16*16*1
-6-1), (ro, myas+2, *) ];[]
- []
-
-
-Underfull \hbox (badness 2393) in paragraph at lines 1502--1510
-[]\OT1/cmr/m/n/10 There are also two short-hands for pre-fix pat-terns: \OT1/cm
-r/m/it/10 ad-dress\OT1/cmtt/m/n/10 /\OT1/cmr/m/it/10 len\OT1/cmtt/m/n/10 + \OT1
-/cmr/m/n/10 is a short-hand for \OT1/cmr/m/it/10 ad-
- []
-
-
-Underfull \hbox (badness 7486) in paragraph at lines 1511--1519
-[]\OT1/cmr/m/n/10 For ex-am-ple, \OT1/cmtt/m/n/10 [ 1.0.0.0/8, 2.0.0.0/8+, 3.0.
-0.0/8-, 4.0.0.0/8$\OMS/cmsy/m/n/10 f$\OT1/cmtt/m/n/10 16,24$\OMS/cmsy/m/n/10 g$
- \OT1/cmtt/m/n/10 ] \OT1/cmr/m/n/10 matches pre-fix
- []
-
-
-Underfull \hbox (badness 10000) in paragraph at lines 1520--1524
-\OT1/cmtt/m/n/10 192.168.0.0/16 le 24 \OT1/cmr/m/n/10 as \OT1/cmtt/m/n/10 192.1
-68.0.0/16$\OMS/cmsy/m/n/10 f$\OT1/cmtt/m/n/10 16,24$\OMS/cmsy/m/n/10 g$ \OT1/cm
-r/m/n/10 and \OT1/cmtt/m/n/10 192.168.0.0/16 ge 24 \OT1/cmr/m/n/10 as
- []
-
-[18] [19] [20] [21] [22]
-Chapter 6.
-[23
-
-] [24] [25] [26] [27] [28] [29] [30] [31] [32] [33] [34] [35] [36] [37]
-Underfull \hbox (badness 10000) in paragraph at lines 3435--3442
-[]\OT1/cmtt/m/n/10 krt[]mtu\OT1/cmr/m/n/10 , \OT1/cmtt/m/n/10 krt[]lock[]mtu\OT
-1/cmr/m/n/10 , \OT1/cmtt/m/n/10 krt[]window\OT1/cmr/m/n/10 , \OT1/cmtt/m/n/10 k
-rt[]lock[]window\OT1/cmr/m/n/10 , \OT1/cmtt/m/n/10 krt[]rtt\OT1/cmr/m/n/10 , \O
-T1/cmtt/m/n/10 krt[]lock[]rtt\OT1/cmr/m/n/10 , \OT1/cmtt/m/n/10 krt[]rttvar\OT1
-/cmr/m/n/10 ,
- []
-
-
-Underfull \hbox (badness 10000) in paragraph at lines 3435--3442
-\OT1/cmtt/m/n/10 krt[]lock[]rttvar\OT1/cmr/m/n/10 , \OT1/cmtt/m/n/10 krt[]sstre
-sh\OT1/cmr/m/n/10 , \OT1/cmtt/m/n/10 krt[]lock[]sstresh\OT1/cmr/m/n/10 , \OT1/c
-mtt/m/n/10 krt[]cwnd\OT1/cmr/m/n/10 , \OT1/cmtt/m/n/10 krt[]lock[]cwnd\OT1/cmr/
-m/n/10 , \OT1/cmtt/m/n/10 krt[]advmss\OT1/cmr/m/n/10 ,
- []
-
-
-Underfull \hbox (badness 10000) in paragraph at lines 3435--3442
-\OT1/cmtt/m/n/10 krt[]lock[]advmss\OT1/cmr/m/n/10 , \OT1/cmtt/m/n/10 krt[]reord
-ering\OT1/cmr/m/n/10 , \OT1/cmtt/m/n/10 krt[]lock[]reordering\OT1/cmr/m/n/10 ,
-\OT1/cmtt/m/n/10 krt[]hoplimit\OT1/cmr/m/n/10 , \OT1/cmtt/m/n/10 krt[]lock[]hop
-limit\OT1/cmr/m/n/10 ,
- []
-
-
-Underfull \hbox (badness 6364) in paragraph at lines 3435--3442
-\OT1/cmtt/m/n/10 krt[]rto[]min\OT1/cmr/m/n/10 , \OT1/cmtt/m/n/10 krt[]lock[]rto
-[]min\OT1/cmr/m/n/10 , \OT1/cmtt/m/n/10 krt[]initcwnd\OT1/cmr/m/n/10 , \OT1/cmt
-t/m/n/10 krt[]initrwnd\OT1/cmr/m/n/10 , \OT1/cmtt/m/n/10 krt[]quickack\OT1/cmr/
-m/n/10 , \OT1/cmtt/m/n/10 krt[]feature[]ecn\OT1/cmr/m/n/10 ,
- []
-
-[38] [39] [40]
-Overfull \hbox (212.12437pt too wide) in paragraph at lines 3755--3755
- [] \OT1/cmtt/m/n/10 algorithm ( keyed md5 | key
-ed sha1 | hmac sha1 | hmac sha256 | hmac sha384 | hmac sha512 );[]
- []
-
-
-Overfull \hbox (212.12437pt too wide) in paragraph at lines 3755--3755
- [] \OT1/cmtt/m/n/10 algorithm ( keyed md5 | key
-ed sha1 | hmac sha1 | hmac sha256 | hmac sha384 | hmac sha512 );[]
- []
-
-[41] [42] [43] [44] [45] [46] [47] [48] [49] [50] [51]
-Underfull \hbox (badness 1354) in paragraph at lines 4812--4817
-[]\OT1/cmr/m/n/10 The pref-er-ence of the route. The value can be \OT1/cmr/m/it
-/10 RA[]PREF[]LOW\OT1/cmr/m/n/10 , \OT1/cmr/m/it/10 RA[]PREF[]MEDIUM \OT1/cmr/m
-/n/10 or
- []
-
-[52]
-Overfull \hbox (33.62593pt too wide) in paragraph at lines 4890--4890
- [] \OT1/cmtt/m/n/10 propagate routes yes; # Propagate the rou
-tes from the radv_routes table[]
- []
-
-[53]
-Overfull \hbox (170.12474pt too wide) in paragraph at lines 4978--4978
- [] \OT1/cmtt/m/n/10 algorithm ( keyed md5 | keyed sha1
-| hmac sha1 | hmac sha256 | hmac sha384 | hmac sha512 );[]
- []
-
-[54] [55] [56] [57] [58] [59]
-Chapter 7.
-Package atveryend Info: Empty hook `BeforeClearDocument' on input line 5479.
-[60
-
-]
-Package atveryend Info: Empty hook `AfterLastShipout' on input line 5479.
- (./bird.aux)
-Package atveryend Info: Executing hook `AtVeryEndDocument' on input line 5479.
-Package atveryend Info: Executing hook `AtEndAfterFileList' on input line 5479.
-
-Package rerunfilecheck Info: File `bird.out' has not changed.
-(rerunfilecheck) Checksum: B14A01EC1E86A3E81F3A2A7767C357FA;1952.
-Package atveryend Info: Empty hook `AtVeryVeryEnd' on input line 5479.
- )
-Here is how much of TeX's memory you used:
- 7520 strings out of 493620
- 108009 string characters out of 3148703
- 215898 words of memory out of 3000000
- 9146 multiletter control sequences out of 15000+200000
- 6889 words of font info for 25 fonts, out of 3000000 for 9000
- 935 hyphenation exceptions out of 8191
- 33i,6n,28p,455b,443s stack positions out of 5000i,500n,10000p,200000b,50000s
-</usr/share/texlive/texmf-dist/fonts/type1/public/amsfonts/cm/cmbx10.pfb></us
-r/share/texlive/texmf-dist/fonts/type1/public/amsfonts/cm/cmbx12.pfb></usr/shar
-e/texlive/texmf-dist/fonts/type1/public/amsfonts/cm/cmmi10.pfb></usr/share/texl
-ive/texmf-dist/fonts/type1/public/amsfonts/cm/cmr10.pfb></usr/share/texlive/tex
-mf-dist/fonts/type1/public/amsfonts/cm/cmss10.pfb></usr/share/texlive/texmf-dis
-t/fonts/type1/public/amsfonts/cm/cmss17.pfb></usr/share/texlive/texmf-dist/font
-s/type1/public/amsfonts/cm/cmsy10.pfb></usr/share/texlive/texmf-dist/fonts/type
-1/public/amsfonts/cm/cmti10.pfb></usr/share/texlive/texmf-dist/fonts/type1/publ
-ic/amsfonts/cm/cmtt10.pfb>
-Output written on bird.pdf (60 pages, 356743 bytes).
-PDF statistics:
- 2435 PDF objects out of 2487 (max. 8388607)
- 2340 compressed objects within 24 object streams
- 1614 named destinations out of 1728 (max. 500000)
- 281 words of extra memory for PDF output out of 10000 (max. 10000000)
-
diff --git a/doc/bird.pdf b/doc/bird.pdf
deleted file mode 100644
index 331f4347..00000000
--- a/doc/bird.pdf
+++ /dev/null
Binary files differ
diff --git a/doc/bird.sgml b/doc/bird.sgml
index d20687be..e4ddded2 100644
--- a/doc/bird.sgml
+++ b/doc/bird.sgml
@@ -504,8 +504,14 @@ include "tablename.conf";;
command-line option.
<tag><label id="opt-debug-protocols">debug protocols all|off|{ states|routes|filters|interfaces|events|packets [, <m/.../] }</tag>
- Set global defaults of protocol debugging options. See <cf/debug/ in the
- following section. Default: off.
+ Set global defaults of protocol debugging options.
+ See <ref id="proto-debug" name="debug"> in the following section.
+ Default: off.
+
+ <tag><label id="opt-debug-channels">debug channels all|off|{ states|routes|filters|events [, <m/.../] }</tag>
+ Set global defaults of channel debugging options.
+ See <ref id="channel-debug" name="debug"> in the channel section.
+ Default: off.
<tag><label id="opt-debug-commands">debug commands <m/number/</tag>
Control logging of client connections (0 for no logging, 1 for logging
@@ -585,6 +591,9 @@ include "tablename.conf";;
See <ref id="proto-iface" name="interface"> section for detailed
description of interface patterns with extended clauses.
+ <tag><label id="opt-hostname">hostname "<m/name/"</tag>
+ Set hostname. Default: node name as returned by `uname -n'.
+
<tag><label id="opt-graceful-restart">graceful restart wait <m/number/</tag>
During graceful restart recovery, BIRD waits for convergence of routing
protocols. This option allows to specify a timeout for the recovery to
@@ -654,12 +663,14 @@ agreement").
Set protocol debugging options. If asked, each protocol is capable of
writing trace messages about its work to the log (with category
<cf/trace/). You can either request printing of <cf/all/ trace messages
- or only of the types selected: <cf/states/ for protocol state changes
+ or only of the selected types: <cf/states/ for protocol state changes
(protocol going up, down, starting, stopping etc.), <cf/routes/ for
routes exchanged with the routing table, <cf/filters/ for details on
- route filtering, <cf/interfaces/ for interface change events sent to the
- protocol, <cf/events/ for events internal to the protocol and <cf/packets/
- for packets sent and received by the protocol. Default: off.
+ route filtering, <cf/interfaces/ for interface change events sent to
+ the protocol, <cf/events/ for events internal to the protocol and
+ <cf/packets/ for packets sent and received by the protocol. Classes
+ <cf/routes/ and <cf/filters/ can be also set per-channel using
+ <ref id="channel-debug" name="channel debugging option">) Default: off.
<tag><label id="proto-mrtdump">mrtdump all|off|{ states|messages [, <m/.../] }</tag>
Set protocol MRTdump flags. MRTdump is a standard binary format for
@@ -783,11 +794,12 @@ agreement").
<descrip>
<tag><label id="proto-pass-id">id <M>num</M></tag>
- ID of the password, (1-255). If it is not used, BIRD will choose ID based
- on an order of the password item in the interface. For example, second
- password item in one interface will have default ID 2. ID is used by
- some routing protocols to identify which password was used to
- authenticate protocol packets.
+ ID of the password, (0-255). If it is not specified, BIRD will choose ID
+ based on an order of the password item in the interface, starting from
+ 1. For example, second password item in one interface will have default
+ ID 2. ID 0 is allowed by BIRD, but some other implementations may not
+ allow it. ID is used by some routing protocols to identify which
+ password was used to authenticate protocol packets.
<tag><label id="proto-pass-gen-from">generate from "<m/time/"</tag>
The start time of the usage of the password for packet signing.
@@ -827,6 +839,16 @@ templates. Multiple definitions of the same channel are forbidden, but channels
inherited from templates can be updated by new definitions.
<descrip>
+ <tag><label id="channel-debug">debug all|off|{ states|routes|filters [, <m/.../] }</tag>
+ Set channel debugging options. Like in <ref id="proto-debug"
+ name="protocol debugging">, channels are capable of writing trace
+ messages about its work to the log (with category <cf/trace/). You can
+ either request printing of <cf/all/ trace messages or only of the
+ selected types: <cf/states/ for channel state changes (channel going up,
+ down, feeding, reloading etc.), <cf/routes/ for routes propagated
+ through the channel, <cf/filters/ for details on route filtering,
+ remaining debug flags are not used in channel debug. Default: off.
+
<tag><label id="proto-table">table <m/name/</tag>
Specify a table to which the channel is connected. Default: the first
table of given nettype.
@@ -853,6 +875,19 @@ inherited from templates can be updated by new definitions.
possible to show them using <cf/show route filtered/. Note that this
option does not work for the pipe protocol. Default: off.
+ <tag><label id="proto-rpki-reload">rpki reload <m/switch/</tag>
+ Import or export filters may depend on route RPKI status (using
+ <cf/roa_check()/ operator). In contrast to to other filter operators,
+ this status for the same route may change as the content of ROA tables
+ changes. When this option is active, BIRD activates automatic reload of
+ affected channels whenever ROA tables are updated (after a short settle
+ time). When disabled, route reloads have to be requested manually. The
+ option is ignored if <cf/roa_check()/ is not used in channel filters.
+ Note that for BGP channels, automatic reload requires
+ <ref id="bgp-import-table" name="import table"> or
+ <ref id="bgp-export-table" name="export table"> (for respective
+ direction). Default: on.
+
<tag><label id="proto-import-limit">import limit [<m/number/ | off ] [action warn | block | restart | disable]</tag>
Specify an import route limit (a maximum number of routes imported from
the protocol) and optionally the action to be taken when the limit is
@@ -1271,7 +1306,7 @@ in the foot).
<tag><label id="type-ip">ip</tag>
This type can hold a single IP address. The IPv4 addresses are stored as
IPv4-Mapped IPv6 addresses so one data type for both of them is used.
- Whether the address is IPv4 or not may be checked by <cf>.is_ip4</cf>
+ Whether the address is IPv4 or not may be checked by <cf>.is_v4</cf>
which returns a <cf/bool/. IP addresses are written in the standard
notation (<cf/10.20.30.40/ or <cf/fec0:3:4::1/). You can apply special
operator <cf>.mask(<M>num</M>)</cf> on values of type ip. It masks out
@@ -1295,7 +1330,9 @@ in the foot).
prefix. The literals are written as <cf><m/ipaddress//<m/pxlen/ from
<m/ipaddress//<m/pxlen/</cf>, where the first part is the destination
prefix and the second art is the source prefix. They support the same
- operators as IP prefixes, but just for the destination part.
+ operators as IP prefixes, but just for the destination part. They also
+ support <cf/.src/ and <cf/.dst/ operators to get respective parts of the
+ address as separate <cf/NET_IP6/ values.
<cf/NET_VPN4/ and <cf/NET_VPN6/ prefixes hold an IP prefix with VPN
Route Distinguisher (<rfc id="4364">). They support the same special
@@ -1309,7 +1346,9 @@ in the foot).
and <cf/.asn/ which extracts the ASN.
<cf/NET_FLOW4/ and <cf/NET_FLOW6/ hold an IP prefix together with a
- flowspec rule. Filters currently don't support flowspec parsing.
+ flowspec rule. Filters currently do not support much flowspec parsing,
+ only <cf/.src/ and <cf/.dst/ operators to get source and destination
+ parts of the flowspec as separate <cf/NET_IP4/ / <cf/NET_IP6/ values.
<cf/NET_MPLS/ holds a single MPLS label and its handling is currently
not implemented.
@@ -1415,9 +1454,10 @@ in the foot).
<cf>192.168.0.0/16{16,24}</cf> and <cf>192.168.0.0/16 ge 24</cf> as
<cf>192.168.0.0/16{24,32}</cf>.
- It is possible to mix IPv4 and IPv6 prefixes/addresses in a prefix/ip set
- but its behavior may change between versions without any warning; don't do
- it unless you are more than sure what you are doing. (Really, don't do it.)
+ It is not possible to mix IPv4 and IPv6 prefixes in a prefix set. It is
+ currently possible to mix IPv4 and IPv6 addresses in an ip set, but that
+ behavior may change between versions without any warning; don't do it
+ unless you are more than sure what you are doing. (Really, don't do it.)
<tag><label id="type-enum">enum</tag>
Enumeration types are fixed sets of possibilities. You can't define your
@@ -1466,11 +1506,16 @@ in the foot).
<cf/*/ matches any (even empty) sequence of arbitrary AS numbers and
<cf/?/ matches one arbitrary AS number. For example, if <cf>bgp_path</cf>
is 4 3 2 1, then: <tt>bgp_path &tilde; [= * 4 3 * =]</tt> is true,
- but <tt>bgp_path &tilde; [= * 4 5 * =]</tt> is false. BGP mask
- expressions can also contain integer expressions enclosed in parenthesis
- and integer variables, for example <tt>[= * 4 (1+2) a =]</tt>. You can
- also use ranges (e.g. <tt>[= * 3..5 2 100..200 * =]</tt>) and sets
- (e.g. <tt>[= 1 2 [3, 5, 7] * =]</tt>).
+ but <tt>bgp_path &tilde; [= * 4 5 * =]</tt> is false. There is also
+ <cf/+/ operator which matches one or multiple instances of previous
+ expression, e.g. <tt>[= 1 2+ 3 =]</tt> matches both path 1 2 3 and path
+ 1 2 2 2 3, but not 1 3 nor 1 2 4 3. Note that while <cf/*/ and <cf/?/
+ are wildcard-style operators, <cf/+/ is regex-style operator.
+
+ BGP mask expressions can also contain integer expressions enclosed in
+ parenthesis and integer variables, for example <tt>[= * 4 (1+2) a =]</tt>.
+ You can also use ranges (e.g. <tt>[= * 3..5 2 100..200 * =]</tt>)
+ and sets (e.g. <tt>[= 1 2 [3, 5, 7] * =]</tt>).
<tag><label id="type-clist">clist</tag>
Clist is similar to a set, except that unlike other sets, it can be
@@ -1636,9 +1681,8 @@ Common route attributes are:
<tag><label id="rta-source"><m/enum/ source</tag>
what protocol has told me about this route. Possible values:
<cf/RTS_DUMMY/, <cf/RTS_STATIC/, <cf/RTS_INHERIT/, <cf/RTS_DEVICE/,
- <cf/RTS_STATIC_DEVICE/, <cf/RTS_REDIRECT/, <cf/RTS_RIP/, <cf/RTS_OSPF/,
- <cf/RTS_OSPF_IA/, <cf/RTS_OSPF_EXT1/, <cf/RTS_OSPF_EXT2/, <cf/RTS_BGP/,
- <cf/RTS_PIPE/, <cf/RTS_BABEL/.
+ <cf/RTS_RIP/, <cf/RTS_OSPF/, <cf/RTS_OSPF_IA/, <cf/RTS_OSPF_EXT1/,
+ <cf/RTS_OSPF_EXT2/, <cf/RTS_BGP/, <cf/RTS_PIPE/, <cf/RTS_BABEL/.
<tag><label id="rta-dest"><m/enum/ dest</tag>
Type of destination the packets should be sent to
@@ -1663,6 +1707,15 @@ Common route attributes are:
creation/removal. Zero is returned for routes with undefined outgoing
interfaces. Read-only.
+ <tag><label id="rta-weight"><m/int/ weight</tag>
+ Multipath weight of route next hops. Valid values are 1-256. Reading
+ returns the weight of the first next hop, setting it sets weights of all
+ next hops to the specified value. Therefore, this attribute is not much
+ useful for manipulating individual next hops of an ECMP route, but can
+ be used in BGP multipath setup to set weights of individual routes that
+ are merged to one ECMP route during export to the Kernel protocol
+ (with active <ref id="krt-merge-paths" name="marge paths"> option).
+
<tag><label id="rta-igp-metric"><m/int/ igp_metric</tag>
The optional attribute that can be used to specify a distance to the
network for routes that do not have a native protocol metric attribute
@@ -1693,9 +1746,6 @@ protocol sections.
<tag><label id="print">print|printn <m/expr/ [<m/, expr.../]</tag>
Prints given expressions; useful mainly while debugging filters. The
<cf/printn/ variant does not terminate the line.
-
- <tag><label id="quitbird">quitbird</tag>
- Terminates BIRD. Useful when debugging the filter interpreter.
</descrip>
@@ -1935,6 +1985,8 @@ configuration is often sufficient.
<p>Note that to use BFD for other protocols like OSPF or BGP, these protocols
also have to be configured to request BFD sessions, usually by <cf/bfd/ option.
+In BGP case, it is also possible to specify per-peer BFD session options (e.g.
+rx/tx intervals) as a part of the <cf/bfd/ option.
<p>A BFD instance not associated with any VRF handles session requests from all
other protocols, even ones associated with a VRF. Such setup would work for
@@ -1951,6 +2003,7 @@ milliseconds.
<code>
protocol bfd [&lt;name&gt;] {
+ accept [ipv4|ipv6] [direct|multihop];
interface &lt;interface pattern&gt; {
interval &lt;time&gt;;
min rx interval &lt;time&gt;;
@@ -1985,6 +2038,14 @@ protocol bfd [&lt;name&gt;] {
</code>
<descrip>
+ <tag><label id="bfd-accept">accept [ipv4|ipv6] [direct|multihop]</tag>
+ A BFD protocol instance accepts (by default) all BFD session requests
+ (with regard to VRF restrictions, see above). This option controls
+ whether IPv4 / IPv6 and direct / multihop session requests are accepted
+ (and which listening sockets are opened). It can be used, for example,
+ to configure separate BFD protocol instances for IPv4 and for IPv6
+ sessions.
+
<tag><label id="bfd-iface">interface <m/pattern/ [, <m/.../] { <m/options/ }</tag>
Interface definitions allow to specify options for sessions associated
with such interfaces and also may contain interface specific options.
@@ -2298,14 +2359,17 @@ using the following configuration parameters:
immediately shut down. Note that this option cannot be used with
multihop BGP. Default: enabled for direct BGP, disabled otherwise.
- <tag><label id="bgp-bfd">bfd <M>switch</M>|graceful</tag>
+ <tag><label id="bgp-bfd">bfd <M>switch</M>|graceful| { <m/options/ }</tag>
BGP could use BFD protocol as an advisory mechanism for neighbor
liveness and failure detection. If enabled, BIRD setups a BFD session
for the BGP neighbor and tracks its liveness by it. This has an
advantage of an order of magnitude lower detection times in case of
failure. When a neighbor failure is detected, the BGP session is
restarted. Optionally, it can be configured (by <cf/graceful/ argument)
- to trigger graceful restart instead of regular restart. Note that BFD
+ to trigger graceful restart instead of regular restart. It is also
+ possible to specify section with per-peer BFD session options instead of
+ just switch argument. Most BFD session specific options are allowed here
+ with the exception of authentication options. here Note that BFD
protocol also has to be configured, see <ref id="bfd" name="BFD">
section for details. Default: disabled.
@@ -2395,6 +2459,25 @@ using the following configuration parameters:
completely disabled and you should ensure loop-free behavior by some
other means. Default: 0 (no local AS number allowed).
+ <tag><label id="bgp-allow-as-sets">allow as sets [<m/switch/]</tag>
+ AS path attribute received with BGP routes may contain not only
+ sequences of AS numbers, but also sets of AS numbers. These rarely used
+ artifacts are results of inter-AS route aggregation. AS sets are
+ deprecated (<rfc id="6472">), and likely to be rejected in the future,
+ as they complicate security features like RPKI validation. When this
+ option is disabled, then received AS paths with AS sets are rejected as
+ malformed and corresponding BGP updates are treated as withdraws.
+ Default: on.
+
+ <tag><label id="bgp-enforce-first-as">enforce first as [<m/switch/]</tag>
+ Routes received from an EBGP neighbor are generally expected to have the
+ first (leftmost) AS number in their AS path equal to the neighbor AS
+ number. This is not enforced by default as there are legitimate cases
+ where it is not true, e.g. connections to route servers. When this
+ option is enabled, routes with non-matching first AS number are rejected
+ and corresponding updates are treated as withdraws. The option is valid
+ on EBGP sessions only. Default: off.
+
<tag><label id="bgp-enable-route-refresh">enable route refresh <m/switch/</tag>
After the initial route exchange, BGP protocol uses incremental updates
to keep BGP speakers synchronized. Sometimes (e.g., if BGP speaker
@@ -2469,8 +2552,8 @@ using the following configuration parameters:
<tag><label id="bgp-enable-extended-messages">enable extended messages <m/switch/</tag>
The BGP protocol uses maximum message length of 4096 bytes. This option
- provides an extension to allow extended messages with length up
- to 65535 bytes. Default: off.
+ provides an extension (<rfc id="8654">) to allow extended messages with
+ length up to 65535 bytes. Default: off.
<tag><label id="bgp-capabilities">capabilities <m/switch/</tag>
Use capability advertisement to advertise optional capabilities. This is
@@ -2487,6 +2570,9 @@ using the following configuration parameters:
This option is relevant to IPv4 mode with enabled capability
advertisement only. Default: on.
+ <tag><label id="bgp-advertise-hostname">advertise hostname <m/switch/</tag>
+ Advertise hostname capability along with the hostname. Default: off.
+
<tag><label id="bgp-disable-after-error">disable after error <m/switch/</tag>
When an error is encountered (either locally or by the other side),
disable the instance automatically and wait for an administrator to fix
@@ -2655,30 +2741,15 @@ be used in explicit configuration.
BGP session (if acceptable), or the preferred address of an associated
interface.
- <tag><label id="bgp-missing-lladdr">missing lladdr self|drop|ignore</tag>
- Next Hop attribute in BGP-IPv6 sometimes contains just the global IPv6
- address, but sometimes it has to contain both global and link-local IPv6
- addresses. This option specifies what to do if BIRD have to send both
- addresses but does not know link-local address. This situation might
- happen when routes from other protocols are exported to BGP, or when
- improper updates are received from BGP peers. <cf/self/ means that BIRD
- advertises its own local address instead. <cf/drop/ means that BIRD
- skips that prefixes and logs error. <cf/ignore/ means that BIRD ignores
- the problem and sends just the global address (and therefore forms
- improper BGP update). Default: <cf/self/, unless BIRD is configured as a
- route server (option <cf/rs client/), in that case default is <cf/ignore/,
- because route servers usually do not forward packets themselves.
-
<tag><label id="bgp-gateway">gateway direct|recursive</tag>
For received routes, their <cf/gw/ (immediate next hop) attribute is
computed from received <cf/bgp_next_hop/ attribute. This option
specifies how it is computed. Direct mode means that the IP address from
- <cf/bgp_next_hop/ is used if it is directly reachable, otherwise the
- neighbor IP address is used. Recursive mode means that the gateway is
- computed by an IGP routing table lookup for the IP address from
- <cf/bgp_next_hop/. Note that there is just one level of indirection in
- recursive mode - the route obtained by the lookup must not be recursive
- itself, to prevent mutually recursive routes.
+ <cf/bgp_next_hop/ is used and must be directly reachable. Recursive mode
+ means that the gateway is computed by an IGP routing table lookup for
+ the IP address from <cf/bgp_next_hop/. Note that there is just one level
+ of indirection in recursive mode - the route obtained by the lookup must
+ not be recursive itself, to prevent mutually recursive routes.
Recursive mode is the behavior specified by the BGP
standard. Direct mode is simpler, does not require any routes in a
@@ -3358,18 +3429,18 @@ protocol ospf [v2|v3] &lt;name&gt; {
networks {
&lt;prefix&gt;;
&lt;prefix&gt; hidden;
- }
+ };
external {
&lt;prefix&gt;;
&lt;prefix&gt; hidden;
&lt;prefix&gt; tag &lt;num&gt;;
- }
+ };
stubnet &lt;prefix&gt;;
stubnet &lt;prefix&gt; {
hidden &lt;switch&gt;;
summary &lt;switch&gt;;
cost &lt;num&gt;;
- }
+ };
interface &lt;interface pattern&gt; [instance &lt;num&gt;] {
cost &lt;num&gt;;
stub &lt;switch&gt;;
@@ -3389,6 +3460,7 @@ protocol ospf [v2|v3] &lt;name&gt; {
strict nonbroadcast &lt;switch&gt;;
real broadcast &lt;switch&gt;;
ptp netmask &lt;switch&gt;;
+ ptp address &lt;switch&gt;;
check link &lt;switch&gt;;
bfd &lt;switch&gt;;
ecmp weight &lt;num&gt;;
@@ -3725,11 +3797,28 @@ protocol ospf [v2|v3] &lt;name&gt; {
In <cf/type ptp/ network configurations, OSPFv2 implementations should
ignore received netmask field in hello packets and should send hello
packets with zero netmask field on unnumbered PtP links. But some OSPFv2
- implementations perform netmask checking even for PtP links. This option
- specifies whether real netmask will be used in hello packets on <cf/type
- ptp/ interfaces. You should ignore this option unless you meet some
- compatibility problems related to this issue. Default value is no for
- unnumbered PtP links, yes otherwise.
+ implementations perform netmask checking even for PtP links.
+
+ This option specifies whether real netmask will be used in hello packets
+ on <cf/type ptp/ interfaces. You should ignore this option unless you
+ meet some compatibility problems related to this issue. Default value is
+ no for unnumbered PtP links, yes otherwise.
+
+ <tag><label id="ospf-ptp-address">ptp address <m/switch/</tag>
+ In <cf/type ptp/ network configurations, OSPFv2 implementations should
+ use IP address for regular PtP links and interface id for unnumbered PtP
+ links in data field of link description records in router LSA. This data
+ field has only local meaning for PtP links, but some broken OSPFv2
+ implementations assume there is an IP address and use it as a next hop
+ in SPF calculations. Note that interface id for unnumbered PtP links is
+ necessary when graceful restart is enabled to distinguish PtP links with
+ the same local IP address.
+
+ This option specifies whether an IP address will be used in data field
+ for <cf/type ptp/ interfaces, it is ignored for other interfaces. You
+ should ignore this option unless you meet some compatibility problems
+ related to this issue. Default value is no for unnumbered PtP links when
+ graceful restart is enabled, yes otherwise.
<tag><label id="ospf-check-link">check link <M>switch</M></tag>
If set, a hardware link state (reported by OS) is taken into consideration.
@@ -3876,7 +3965,7 @@ protocol ospf MyOSPF {
networks {
172.16.1.0/24;
172.16.2.0/24 hidden;
- }
+ };
interface "-arc0" , "arc*" {
type nonbroadcast;
authentication none;
@@ -4409,7 +4498,8 @@ you can't use RIP on networks where maximal distance is higher than 15
hosts.
<p>BIRD supports RIPv1 (<rfc id="1058">), RIPv2 (<rfc id="2453">), RIPng (<rfc
-id="2080">), and RIP cryptographic authentication (<rfc id="4822">).
+id="2080">), Triggered RIP for demand circuits (<rfc id="2091">), and RIP
+cryptographic authentication (<rfc id="4822">).
<p>RIP is a very simple protocol, and it has a lot of shortcomings. Slow
convergence, big network load and inability to handle larger networks makes it
@@ -4439,6 +4529,7 @@ protocol rip [ng] [&lt;name&gt;] {
version 1|2;
split horizon &lt;switch&gt;;
poison reverse &lt;switch&gt;;
+ demand circuit &lt;switch&gt;;
check zero &lt;switch&gt;;
update time &lt;number&gt;;
timeout time &lt;number&gt;;
@@ -4543,6 +4634,16 @@ protocol rip [ng] [&lt;name&gt;] {
used. The poisoned reverse has some advantages in faster convergence,
but uses more network traffic. Default: yes.
+ <tag><label id="rip-iface-demand-circuit">demand circuit <m/switch/</tag>
+ Regular RIP sends periodic full updates on an interface. There is the
+ Triggered RIP extension for demand circuits (<rfc id="2091">), which
+ removes periodic updates and introduces update acknowledgments. When
+ enabled, there is no RIP communication in steady-state network. Note
+ that in order to work, it must be enabled on both sides. As there are
+ no hello packets, it depends on hardware link state to detect neighbor
+ failures. Also, it is designed for PtP links and it does not work
+ properly with multiple RIP neighbors on an interface. Default: no.
+
<tag><label id="rip-iface-check-zero">check zero <m/switch/</tag>
Received RIPv1 packets with non-zero values in reserved fields should
be discarded. This option specifies whether the check is performed or
@@ -4673,21 +4774,21 @@ protocol rip {
<sect1>Introduction
<p>The Resource Public Key Infrastructure (RPKI) is mechanism for origin
-validation of BGP routes (RFC 6480). BIRD supports only so-called RPKI-based
-origin validation. There is implemented RPKI to Router (RPKI-RTR) protocol (RFC
-6810). It uses some of the RPKI data to allow a router to verify that the
-autonomous system announcing an IP address prefix is in fact authorized to do
-so. This is not crypto checked so can be violated. But it should prevent the
-vast majority of accidental hijackings on the Internet today, e.g. the famous
-Pakastani accidental announcement of YouTube's address space.
+validation of BGP routes (<rfc id="6480">). BIRD supports only so-called
+RPKI-based origin validation. There is implemented RPKI to Router (RPKI-RTR)
+protocol (<rfc id="6810">). It uses some of the RPKI data to allow a router to
+verify that the autonomous system announcing an IP address prefix is in fact
+authorized to do so. This is not crypto checked so can be violated. But it
+should prevent the vast majority of accidental hijackings on the Internet today,
+e.g. the famous Pakistani accidental announcement of YouTube's address space.
<p>The RPKI-RTR protocol receives and maintains a set of ROAs from a cache
-server (also called validator). You can validate routes (RFC 6483) using
-function <cf/roa_check()/ in filter and set it as import filter at the BGP
-protocol. BIRD should re-validate all of affected routes after RPKI update by
-RFC 6811, but we don't support it yet! You can use a BIRD's client command
-<cf>reload in <m/bgp_protocol_name/</cf> for manual call of revalidation of all
-routes.
+server (also called validator). You can validate routes (<rfc id="6483">,
+<rfc id="6811">) using function <cf/roa_check()/ in filter and set it as import
+filter at the BGP protocol. BIRD offers crude automatic re-validating of
+affected routes after RPKI update, see option <ref id="proto-rpki-reload"
+name="rpki reload">. Or you can use a BIRD client command <cf>reload in
+<m/bgp_protocol_name/</cf> for manual call of revalidation of all routes.
<sect1>Supported transports
<p>
@@ -4761,6 +4862,11 @@ specify both channels.
suppresses updating this value by a cache server.
Default: 7200 seconds
+ <tag>ignore max length <m/switch/</tag>
+ Ignore received max length in ROA records and use max value (32 or 128)
+ instead. This may be useful for implementing loose RPKI check for
+ blackholes. Default: disabled.
+
<tag>transport tcp</tag> Unprotected transport over TCP. It's a default
transport. Should be used only on secure private networks.
Default: tcp
@@ -4863,8 +4969,15 @@ default route to prevent routing loops).
<p>There are three classes of definitions in Static protocol configuration --
global options, static route definitions, and per-route options. Usually, the
-definition of the protocol contains mainly a list of static routes.
-Static routes have no specific attributes.
+definition of the protocol contains mainly a list of static routes. Static
+routes have no specific attributes, but <ref id="rta-igp-metric" name="igp_metric">
+attribute is used to compare static routes with the same preference.
+
+<p>The list of static routes may contain multiple routes for the same network
+(usually, but not necessary, distinquished by <cf/preference/ or <cf/igp_metric/),
+but only routes of the same network type are allowed, as the static protocol
+has just one channel. E.g., to have both IPv4 and IPv6 static routes, define two
+static protocols, each with appropriate routes and channel.
<p>Global options:
@@ -4889,8 +5002,8 @@ Static routes have no specific attributes.
<ref id="type-prefix" name="dependent on network type">.
<descrip>
- <tag>route <m/prefix/ via <m/ip/|<m/"interface"/ [mpls <m/num/[/<m/num/[/<m/num/[...]]]]</tag>
- Next hop routes may bear one or more <ref id="route-next-hop" name="next hops">.
+ <tag>route <m/prefix/ via <m/ip/|<m/"interface"/ [<m/per-nexthop options/] [via ...]</tag>
+ Regular routes may bear one or more <ref id="route-next-hop" name="next hops">.
Every next hop is preceded by <cf/via/ and configured as shown.
<tag>route <m/prefix/ recursive <m/ip/ [mpls <m/num/[/<m/num/[/<m/num/[...]]]]</tag>
@@ -4909,6 +5022,46 @@ the next hop of the route is not a neighbor at the moment), Static just
uninstalls the route from the table it is connected to and adds it again as soon
as the destination becomes adjacent again.
+<sect2>Per-nexthop options
+
+<p>There are several options that in a case of multipath route are per-nexthop
+(i.e., they can be used multiple times for a route, one time for each nexthop).
+Syntactically, they are not separate options but just parts of <cf/route/
+statement after each <cf/via/ statement, not separated by semicolons. E.g.,
+statement <cf/route 10.0.0.0/8 via 192.0.2.1 bfd weight 1 via 192.0.2.2 weight
+2;/ describes a route with two nexthops, the first nexthop has two per-nexthop
+options (<cf/bfd/ and <cf/weight 1/), the second nexthop has just <cf/weight 2/.
+
+<descrip>
+ <tag><label id="static-route-bfd">bfd <m/switch/</tag>
+ The Static protocol could use BFD protocol for next hop liveness
+ detection. If enabled, a BFD session to the route next hop is created
+ and the static route is BFD-controlled -- the static route is announced
+ only if the next hop liveness is confirmed by BFD. If the BFD session
+ fails, the static route (or just the affected nexthop from multiple
+ ones) is removed. Note that this is a bit different compared to other
+ protocols, which may use BFD as an advisory mechanism for fast failure
+ detection but ignore it if a BFD session is not even established. Note
+ that BFD protocol also has to be configured, see <ref id="bfd" name="BFD">
+ section for details. Default value is no.
+
+ <tag><label id="static-route-mpls">mpls <m/num/[/<m/num/[/<m/num/[...]]]</tag>
+ MPLS labels that should be pushed to packets forwarded by the route.
+ The option could be used for both IP routes (on MPLS ingress routers)
+ and MPLS switching rules (on MPLS transit routers). Default value is
+ no labels.
+
+ <tag><label id="static-route-onlink">onlink <m/switch/</tag>
+ Onlink flag means that the specified nexthop is accessible on the
+ (specified) interface regardless of IP prefixes of the interface. The
+ interface must be attached to nexthop IP address using link-local-scope
+ format (e.g. <cf/192.0.2.1%eth0/). Default value is no.
+
+ <tag><label id="static-route-weight">weight <m/switch/</tag>
+ For multipath routes, this value specifies a relative weight of the
+ nexthop. Allowed values are 1-256. Default value is 1.
+</descrip>
+
<sect1>Route Origin Authorization
<p>The ROA config is just <cf>route <m/prefix/ max <m/int/ as <m/int/</cf> with no nexthop.
@@ -5047,21 +5200,6 @@ protocol static {
<sect1>Per-route options
<p>
<descrip>
- <tag><label id="static-route-bfd">bfd <m/switch/</tag>
- The Static protocol could use BFD protocol for next hop liveness
- detection. If enabled, a BFD session to the route next hop is created
- and the static route is BFD-controlled -- the static route is announced
- only if the next hop liveness is confirmed by BFD. If the BFD session
- fails, the static route is removed. Note that this is a bit different
- compared to other protocols, which may use BFD as an advisory mechanism
- for fast failure detection but ignores it if a BFD session is not even
- established.
-
- This option can be used for static routes with a direct next hop, or
- also for for individual next hops in a static multipath route (see
- above). Note that BFD protocol also has to be configured, see
- <ref id="bfd" name="BFD"> section for details. Default value is no.
-
<tag><label id="static-route-filter"><m/filter expression/</tag>
This is a special option that allows filter expressions to be configured
on per-route basis. Can be used multiple times. These expressions are
@@ -5071,7 +5209,8 @@ protocol static {
exported to the OSPF protocol.
</descrip>
-<sect1>Example static config
+<sect1>Example static configs
+<label id="static-example">
<p><code>
protocol static {
@@ -5082,16 +5221,29 @@ protocol static {
via 198.51.100.10 weight 2
via 198.51.100.20 bfd # BFD-controlled next hop
via 192.0.2.1;
- route 203.0.113.0/24 unreachable; # Sink route
+ route 203.0.113.0/24 blackhole; # Sink route
route 10.2.0.0/24 via "arc0"; # Secondary network
route 192.168.10.0/24 via 198.51.100.100 {
ospf_metric1 = 20; # Set extended attribute
- }
- route 192.168.10.0/24 via 198.51.100.100 {
+ };
+ route 192.168.11.0/24 via 198.51.100.100 {
ospf_metric2 = 100; # Set extended attribute
ospf_tag = 2; # Set extended attribute
- bfd; # BFD-controlled route
- }
+ };
+ route 192.168.12.0/24 via 198.51.100.100 {
+ bgp_community.add((65535, 65281)); # Set extended BGP attribute
+ bgp_large_community.add((64512, 1, 1)); # Set extended BGP attribute
+ };
+}
+
+protocol static {
+ ipv6; # Channel is mandatory
+ route 2001:db8:10::/48 via 2001:db8:1::1; # Route with global nexthop
+ route 2001:db8:20::/48 via fe80::10%eth0; # Route with link-local nexthop
+ route 2001:db8:30::/48 via fe80::20%'eth1.60'; # Iface with non-alphanumeric characters
+ route 2001:db8:40::/48 via "eth2"; # Direct route to eth2
+ route 2001:db8::/32 unreachable; # Unreachable route
+ route ::/0 via 2001:db8:1::1 bfd; # BFD-controlled default route
}
</code>
diff --git a/doc/bird.toc b/doc/bird.toc
deleted file mode 100644
index c366fbc5..00000000
--- a/doc/bird.toc
+++ /dev/null
@@ -1,70 +0,0 @@
-\contentsline {chapter}{\numberline {1}Introduction }{3}{chapter.1}
-\contentsline {section}{\numberline {1.1}What is BIRD }{3}{section.1.1}
-\contentsline {section}{\numberline {1.2}Installing BIRD }{4}{section.1.2}
-\contentsline {section}{\numberline {1.3}Running BIRD }{4}{section.1.3}
-\contentsline {section}{\numberline {1.4}Privileges }{5}{section.1.4}
-\contentsline {chapter}{\numberline {2}About routing tables }{6}{chapter.2}
-\contentsline {section}{\numberline {2.1}Graceful restart }{6}{section.2.1}
-\contentsline {chapter}{\numberline {3}Configuration }{7}{chapter.3}
-\contentsline {section}{\numberline {3.1}Introduction }{7}{section.3.1}
-\contentsline {section}{\numberline {3.2}Global options }{7}{section.3.2}
-\contentsline {section}{\numberline {3.3}Protocol options }{9}{section.3.3}
-\contentsline {chapter}{\numberline {4}Remote control }{13}{chapter.4}
-\contentsline {chapter}{\numberline {5}Filters }{16}{chapter.5}
-\contentsline {section}{\numberline {5.1}Introduction }{16}{section.5.1}
-\contentsline {section}{\numberline {5.2}Data types }{17}{section.5.2}
-\contentsline {section}{\numberline {5.3}Operators }{20}{section.5.3}
-\contentsline {section}{\numberline {5.4}Control structures }{20}{section.5.4}
-\contentsline {section}{\numberline {5.5}Route attributes }{20}{section.5.5}
-\contentsline {section}{\numberline {5.6}Other statements }{22}{section.5.6}
-\contentsline {chapter}{\numberline {6}Protocols }{23}{chapter.6}
-\contentsline {section}{\numberline {6.1}Babel }{23}{section.6.1}
-\contentsline {subsection}{\numberline {6.1.1}Introduction }{23}{subsection.6.1.1}
-\contentsline {subsection}{\numberline {6.1.2}Configuration }{23}{subsection.6.1.2}
-\contentsline {subsection}{\numberline {6.1.3}Attributes }{24}{subsection.6.1.3}
-\contentsline {subsection}{\numberline {6.1.4}Example }{24}{subsection.6.1.4}
-\contentsline {section}{\numberline {6.2}BFD }{24}{section.6.2}
-\contentsline {subsection}{\numberline {6.2.1}Introduction }{24}{subsection.6.2.1}
-\contentsline {subsection}{\numberline {6.2.2}Configuration }{25}{subsection.6.2.2}
-\contentsline {subsection}{\numberline {6.2.3}Example }{27}{subsection.6.2.3}
-\contentsline {section}{\numberline {6.3}BGP }{27}{section.6.3}
-\contentsline {subsection}{\numberline {6.3.1}Route selection rules }{28}{subsection.6.3.1}
-\contentsline {subsection}{\numberline {6.3.2}IGP routing table }{28}{subsection.6.3.2}
-\contentsline {subsection}{\numberline {6.3.3}Configuration }{28}{subsection.6.3.3}
-\contentsline {subsection}{\numberline {6.3.4}Attributes }{33}{subsection.6.3.4}
-\contentsline {subsection}{\numberline {6.3.5}Example }{34}{subsection.6.3.5}
-\contentsline {section}{\numberline {6.4}Device }{35}{section.6.4}
-\contentsline {subsection}{\numberline {6.4.1}Configuration }{35}{subsection.6.4.1}
-\contentsline {section}{\numberline {6.5}Direct }{36}{section.6.5}
-\contentsline {section}{\numberline {6.6}Kernel }{36}{section.6.6}
-\contentsline {subsection}{\numberline {6.6.1}Configuration }{37}{subsection.6.6.1}
-\contentsline {subsection}{\numberline {6.6.2}Attributes }{37}{subsection.6.6.2}
-\contentsline {subsection}{\numberline {6.6.3}Example }{38}{subsection.6.6.3}
-\contentsline {section}{\numberline {6.7}MRT }{38}{section.6.7}
-\contentsline {subsection}{\numberline {6.7.1}Introduction }{38}{subsection.6.7.1}
-\contentsline {subsection}{\numberline {6.7.2}Configuration }{39}{subsection.6.7.2}
-\contentsline {subsection}{\numberline {6.7.3}Example }{39}{subsection.6.7.3}
-\contentsline {section}{\numberline {6.8}OSPF }{39}{section.6.8}
-\contentsline {subsection}{\numberline {6.8.1}Introduction }{39}{subsection.6.8.1}
-\contentsline {subsection}{\numberline {6.8.2}Configuration }{40}{subsection.6.8.2}
-\contentsline {subsection}{\numberline {6.8.3}Attributes }{46}{subsection.6.8.3}
-\contentsline {subsection}{\numberline {6.8.4}Example }{46}{subsection.6.8.4}
-\contentsline {section}{\numberline {6.9}Pipe }{47}{section.6.9}
-\contentsline {subsection}{\numberline {6.9.1}Introduction }{47}{subsection.6.9.1}
-\contentsline {subsection}{\numberline {6.9.2}Configuration }{48}{subsection.6.9.2}
-\contentsline {subsection}{\numberline {6.9.3}Attributes }{48}{subsection.6.9.3}
-\contentsline {subsection}{\numberline {6.9.4}Example }{48}{subsection.6.9.4}
-\contentsline {section}{\numberline {6.10}RAdv }{49}{section.6.10}
-\contentsline {subsection}{\numberline {6.10.1}Introduction }{49}{subsection.6.10.1}
-\contentsline {subsection}{\numberline {6.10.2}Configuration }{49}{subsection.6.10.2}
-\contentsline {subsection}{\numberline {6.10.3}Attributes }{52}{subsection.6.10.3}
-\contentsline {subsection}{\numberline {6.10.4}Example }{52}{subsection.6.10.4}
-\contentsline {section}{\numberline {6.11}RIP }{54}{section.6.11}
-\contentsline {subsection}{\numberline {6.11.1}Introduction }{54}{subsection.6.11.1}
-\contentsline {subsection}{\numberline {6.11.2}Configuration }{54}{subsection.6.11.2}
-\contentsline {subsection}{\numberline {6.11.3}Attributes }{57}{subsection.6.11.3}
-\contentsline {subsection}{\numberline {6.11.4}Example }{57}{subsection.6.11.4}
-\contentsline {section}{\numberline {6.12}Static }{57}{section.6.12}
-\contentsline {chapter}{\numberline {7}Conclusions }{60}{chapter.7}
-\contentsline {section}{\numberline {7.1}Future work }{60}{section.7.1}
-\contentsline {section}{\numberline {7.2}Getting more help }{60}{section.7.2}
diff --git a/doc/prog.aux b/doc/prog.aux
deleted file mode 100644
index 260870ff..00000000
--- a/doc/prog.aux
+++ /dev/null
@@ -1,87 +0,0 @@
-\relax
-\providecommand\HyperFirstAtBeginDocument{\AtBeginDocument}
-\HyperFirstAtBeginDocument{\ifx\hyper@anchor\@undefined
-\global\let\oldcontentsline\contentsline
-\gdef\contentsline#1#2#3#4{\oldcontentsline{#1}{#2}{#3}}
-\global\let\oldnewlabel\newlabel
-\gdef\newlabel#1#2{\newlabelxx{#1}#2}
-\gdef\newlabelxx#1#2#3#4#5#6{\oldnewlabel{#1}{{#2}{#3}}}
-\AtEndDocument{\ifx\hyper@anchor\@undefined
-\let\contentsline\oldcontentsline
-\let\newlabel\oldnewlabel
-\fi}
-\fi}
-\global\let\hyper@last\relax
-\gdef\HyperFirstAtBeginDocument#1{#1}
-\providecommand\HyField@AuxAddToFields[1]{}
-\@writefile{toc}{\contentsline {chapter}{\numberline {1}BIRD Design}{4}{chapter.1}}
-\@writefile{lof}{\addvspace {10\p@ }}
-\@writefile{lot}{\addvspace {10\p@ }}
-\@writefile{toc}{\contentsline {section}{\numberline {1.1}Introduction}{4}{section.1.1}}
-\@writefile{toc}{\contentsline {section}{\numberline {1.2}Design goals}{4}{section.1.2}}
-\@writefile{toc}{\contentsline {section}{\numberline {1.3}Architecture}{5}{section.1.3}}
-\@writefile{toc}{\contentsline {section}{\numberline {1.4}Implementation}{5}{section.1.4}}
-\@writefile{toc}{\contentsline {chapter}{\numberline {2}Core}{7}{chapter.2}}
-\@writefile{lof}{\addvspace {10\p@ }}
-\@writefile{lot}{\addvspace {10\p@ }}
-\@writefile{toc}{\contentsline {section}{\numberline {2.1}Forwarding Information Base}{7}{section.2.1}}
-\@writefile{toc}{\contentsline {section}{\numberline {2.2}Routing tables}{9}{section.2.2}}
-\@writefile{toc}{\contentsline {section}{\numberline {2.3}Route attribute cache}{15}{section.2.3}}
-\@writefile{toc}{\contentsline {section}{\numberline {2.4}Routing protocols}{20}{section.2.4}}
-\@writefile{toc}{\contentsline {subsection}{\numberline {2.4.1}Introduction}{20}{subsection.2.4.1}}
-\@writefile{toc}{\contentsline {subsection}{\numberline {2.4.2}Protocol states}{21}{subsection.2.4.2}}
-\@writefile{toc}{\contentsline {subsection}{\numberline {2.4.3}Functions of the protocol module}{21}{subsection.2.4.3}}
-\@writefile{toc}{\contentsline {section}{\numberline {2.5}Graceful restart recovery}{24}{section.2.5}}
-\@writefile{toc}{\contentsline {section}{\numberline {2.6}Protocol hooks}{27}{section.2.6}}
-\@writefile{toc}{\contentsline {section}{\numberline {2.7}Interfaces}{34}{section.2.7}}
-\@writefile{toc}{\contentsline {section}{\numberline {2.8}Neighbor cache}{36}{section.2.8}}
-\@writefile{toc}{\contentsline {section}{\numberline {2.9}Command line interface}{38}{section.2.9}}
-\@writefile{toc}{\contentsline {section}{\numberline {2.10}Object locks}{40}{section.2.10}}
-\@writefile{toc}{\contentsline {chapter}{\numberline {3}Configuration}{41}{chapter.3}}
-\@writefile{lof}{\addvspace {10\p@ }}
-\@writefile{lot}{\addvspace {10\p@ }}
-\@writefile{toc}{\contentsline {section}{\numberline {3.1}Configuration manager}{41}{section.3.1}}
-\@writefile{toc}{\contentsline {section}{\numberline {3.2}Lexical analyzer}{44}{section.3.2}}
-\@writefile{toc}{\contentsline {section}{\numberline {3.3}Parser}{46}{section.3.3}}
-\@writefile{toc}{\contentsline {chapter}{\numberline {4}Filters}{47}{chapter.4}}
-\@writefile{lof}{\addvspace {10\p@ }}
-\@writefile{lot}{\addvspace {10\p@ }}
-\@writefile{toc}{\contentsline {section}{\numberline {4.1}Filters}{47}{section.4.1}}
-\@writefile{toc}{\contentsline {section}{\numberline {4.2}Trie for prefix sets}{49}{section.4.2}}
-\@writefile{toc}{\contentsline {chapter}{\numberline {5}Protocols}{52}{chapter.5}}
-\@writefile{lof}{\addvspace {10\p@ }}
-\@writefile{lot}{\addvspace {10\p@ }}
-\@writefile{toc}{\contentsline {section}{\numberline {5.1}The Babel protocol}{52}{section.5.1}}
-\@writefile{toc}{\contentsline {section}{\numberline {5.2}Bidirectional Forwarding Detection}{55}{section.5.2}}
-\@writefile{toc}{\contentsline {section}{\numberline {5.3}Border Gateway Protocol}{56}{section.5.3}}
-\@writefile{toc}{\contentsline {section}{\numberline {5.4}Multi-Threaded Routing Toolkit (MRT) protocol}{63}{section.5.4}}
-\@writefile{toc}{\contentsline {section}{\numberline {5.5}Open Shortest Path First (OSPF)}{63}{section.5.5}}
-\@writefile{toc}{\contentsline {section}{\numberline {5.6}Pipe}{70}{section.5.6}}
-\@writefile{toc}{\contentsline {section}{\numberline {5.7}Routing Information Protocol (RIP)}{70}{section.5.7}}
-\@writefile{toc}{\contentsline {section}{\numberline {5.8}Router Advertisements}{73}{section.5.8}}
-\@writefile{toc}{\contentsline {section}{\numberline {5.9}Static}{73}{section.5.9}}
-\@writefile{toc}{\contentsline {section}{\numberline {5.10}Direct}{74}{section.5.10}}
-\@writefile{toc}{\contentsline {chapter}{\numberline {6}System dependent parts}{75}{chapter.6}}
-\@writefile{lof}{\addvspace {10\p@ }}
-\@writefile{lot}{\addvspace {10\p@ }}
-\@writefile{toc}{\contentsline {section}{\numberline {6.1}Introduction}{75}{section.6.1}}
-\@writefile{toc}{\contentsline {section}{\numberline {6.2}Logging}{75}{section.6.2}}
-\@writefile{toc}{\contentsline {section}{\numberline {6.3}Kernel synchronization}{76}{section.6.3}}
-\@writefile{toc}{\contentsline {chapter}{\numberline {7}Library functions}{78}{chapter.7}}
-\@writefile{lof}{\addvspace {10\p@ }}
-\@writefile{lot}{\addvspace {10\p@ }}
-\@writefile{toc}{\contentsline {section}{\numberline {7.1}IP addresses}{78}{section.7.1}}
-\@writefile{toc}{\contentsline {section}{\numberline {7.2}Linked lists}{82}{section.7.2}}
-\@writefile{toc}{\contentsline {section}{\numberline {7.3}Miscellaneous functions.}{84}{section.7.3}}
-\@writefile{toc}{\contentsline {section}{\numberline {7.4}Message authentication codes}{88}{section.7.4}}
-\@writefile{toc}{\contentsline {chapter}{\numberline {8}Resources}{91}{chapter.8}}
-\@writefile{lof}{\addvspace {10\p@ }}
-\@writefile{lot}{\addvspace {10\p@ }}
-\@writefile{toc}{\contentsline {section}{\numberline {8.1}Introduction}{91}{section.8.1}}
-\@writefile{toc}{\contentsline {section}{\numberline {8.2}Resource pools}{91}{section.8.2}}
-\@writefile{toc}{\contentsline {section}{\numberline {8.3}Memory blocks}{93}{section.8.3}}
-\@writefile{toc}{\contentsline {section}{\numberline {8.4}Linear memory pools}{94}{section.8.4}}
-\@writefile{toc}{\contentsline {section}{\numberline {8.5}Slabs}{95}{section.8.5}}
-\@writefile{toc}{\contentsline {section}{\numberline {8.6}Events}{96}{section.8.6}}
-\@writefile{toc}{\contentsline {section}{\numberline {8.7}Timers}{97}{section.8.7}}
-\@writefile{toc}{\contentsline {section}{\numberline {8.8}Sockets}{99}{section.8.8}}
diff --git a/doc/prog.log b/doc/prog.log
deleted file mode 100644
index fc64221c..00000000
--- a/doc/prog.log
+++ /dev/null
@@ -1,388 +0,0 @@
-This is pdfTeX, Version 3.1415926-2.4-1.40.13 (TeX Live 2012/Debian) (format=pdflatex 2014.8.6) 11 SEP 2019 20:40
-entering extended mode
- restricted \write18 enabled.
- %&-line parsing enabled.
-**prog.tex
-(./prog.tex
-LaTeX2e <2011/06/27>
-Babel <v3.8m> and hyphenation patterns for english, dumylang, nohyphenation, cr
-oatian, bulgarian, ukrainian, russian, slovak, czech, danish, dutch, finnish, f
-rench, basque, ngerman, german, swissgerman, ngerman-x-2012-05-30, german-x-201
-2-05-30, monogreek, greek, ibycus, ancientgreek, hungarian, italian, latin, mon
-golian, mongolianlmc, nynorsk, bokmal, indonesian, esperanto, coptic, welsh, ir
-ish, interlingua, serbian, serbianc, slovenian, friulan, romansh, estonian, rom
-anian, armenian, uppersorbian, turkish, afrikaans, icelandic, kurmanji, polish,
- portuguese, galician, catalan, spanish, swedish, thai, loaded.
-(/usr/share/texlive/texmf-dist/tex/latex/base/book.cls
-Document Class: book 2007/10/19 v1.4h Standard LaTeX document class
-(/usr/share/texlive/texmf-dist/tex/latex/base/bk10.clo
-File: bk10.clo 2007/10/19 v1.4h Standard LaTeX file (size option)
-)
-\c@part=\count79
-\c@chapter=\count80
-\c@section=\count81
-\c@subsection=\count82
-\c@subsubsection=\count83
-\c@paragraph=\count84
-\c@subparagraph=\count85
-\c@figure=\count86
-\c@table=\count87
-\abovecaptionskip=\skip41
-\belowcaptionskip=\skip42
-\bibindent=\dimen102
-)
-(/usr/share/texlive/texmf-dist/tex/latex/hyperref/hyperref.sty
-Package: hyperref 2012/05/13 v6.82q Hypertext links for LaTeX
-
-(/usr/share/texlive/texmf-dist/tex/generic/oberdiek/hobsub-hyperref.sty
-Package: hobsub-hyperref 2012/05/28 v1.13 Bundle oberdiek, subset hyperref (HO)
-
-
-(/usr/share/texlive/texmf-dist/tex/generic/oberdiek/hobsub-generic.sty
-Package: hobsub-generic 2012/05/28 v1.13 Bundle oberdiek, subset generic (HO)
-Package: hobsub 2012/05/28 v1.13 Construct package bundles (HO)
-Package: infwarerr 2010/04/08 v1.3 Providing info/warning/error messages (HO)
-Package: ltxcmds 2011/11/09 v1.22 LaTeX kernel commands for general use (HO)
-Package: ifluatex 2010/03/01 v1.3 Provides the ifluatex switch (HO)
-Package ifluatex Info: LuaTeX not detected.
-Package: ifvtex 2010/03/01 v1.5 Detect VTeX and its facilities (HO)
-Package ifvtex Info: VTeX not detected.
-Package: intcalc 2007/09/27 v1.1 Expandable calculations with integers (HO)
-Package: ifpdf 2011/01/30 v2.3 Provides the ifpdf switch (HO)
-Package ifpdf Info: pdfTeX in PDF mode is detected.
-Package: etexcmds 2011/02/16 v1.5 Avoid name clashes with e-TeX commands (HO)
-Package etexcmds Info: Could not find \expanded.
-(etexcmds) That can mean that you are not using pdfTeX 1.50 or
-(etexcmds) that some package has redefined \expanded.
-(etexcmds) In the latter case, load this package earlier.
-Package: kvsetkeys 2012/04/25 v1.16 Key value parser (HO)
-Package: kvdefinekeys 2011/04/07 v1.3 Define keys (HO)
-Package: pdftexcmds 2011/11/29 v0.20 Utility functions of pdfTeX for LuaTeX (HO
-)
-Package pdftexcmds Info: LuaTeX not detected.
-Package pdftexcmds Info: \pdf@primitive is available.
-Package pdftexcmds Info: \pdf@ifprimitive is available.
-Package pdftexcmds Info: \pdfdraftmode found.
-Package: pdfescape 2011/11/25 v1.13 Implements pdfTeX's escape features (HO)
-Package: bigintcalc 2012/04/08 v1.3 Expandable calculations on big integers (HO
-)
-Package: bitset 2011/01/30 v1.1 Handle bit-vector datatype (HO)
-Package: uniquecounter 2011/01/30 v1.2 Provide unlimited unique counter (HO)
-)
-Package hobsub Info: Skipping package `hobsub' (already loaded).
-Package: letltxmacro 2010/09/02 v1.4 Let assignment for LaTeX macros (HO)
-Package: hopatch 2012/05/28 v1.2 Wrapper for package hooks (HO)
-Package: xcolor-patch 2011/01/30 xcolor patch
-Package: atveryend 2011/06/30 v1.8 Hooks at the very end of document (HO)
-Package atveryend Info: \enddocument detected (standard20110627).
-Package: atbegshi 2011/10/05 v1.16 At begin shipout hook (HO)
-Package: refcount 2011/10/16 v3.4 Data extraction from label references (HO)
-Package: hycolor 2011/01/30 v1.7 Color options for hyperref/bookmark (HO)
-)
-(/usr/share/texlive/texmf-dist/tex/latex/graphics/keyval.sty
-Package: keyval 1999/03/16 v1.13 key=value parser (DPC)
-\KV@toks@=\toks14
-)
-(/usr/share/texlive/texmf-dist/tex/generic/ifxetex/ifxetex.sty
-Package: ifxetex 2010/09/12 v0.6 Provides ifxetex conditional
-)
-(/usr/share/texlive/texmf-dist/tex/latex/oberdiek/kvoptions.sty
-Package: kvoptions 2011/06/30 v3.11 Key value format for package options (HO)
-)
-\@linkdim=\dimen103
-\Hy@linkcounter=\count88
-\Hy@pagecounter=\count89
-
-(/usr/share/texlive/texmf-dist/tex/latex/hyperref/pd1enc.def
-File: pd1enc.def 2012/05/13 v6.82q Hyperref: PDFDocEncoding definition (HO)
-)
-\Hy@SavedSpaceFactor=\count90
-
-(/usr/share/texlive/texmf-dist/tex/latex/latexconfig/hyperref.cfg
-File: hyperref.cfg 2002/06/06 v1.2 hyperref configuration of TeXLive
-)
-Package hyperref Info: Option `colorlinks' set `true' on input line 3941.
-Package hyperref Info: Hyper figures OFF on input line 4062.
-Package hyperref Info: Link nesting OFF on input line 4067.
-Package hyperref Info: Hyper index ON on input line 4070.
-Package hyperref Info: Plain pages OFF on input line 4077.
-Package hyperref Info: Backreferencing OFF on input line 4082.
-Package hyperref Info: Implicit mode ON; LaTeX internals redefined.
-Package hyperref Info: Bookmarks ON on input line 4300.
-\c@Hy@tempcnt=\count91
-
-(/usr/share/texlive/texmf-dist/tex/latex/url/url.sty
-\Urlmuskip=\muskip10
-Package: url 2006/04/12 ver 3.3 Verb mode for urls, etc.
-)
-LaTeX Info: Redefining \url on input line 4653.
-\Fld@menulength=\count92
-\Field@Width=\dimen104
-\Fld@charsize=\dimen105
-Package hyperref Info: Hyper figures OFF on input line 5773.
-Package hyperref Info: Link nesting OFF on input line 5778.
-Package hyperref Info: Hyper index ON on input line 5781.
-Package hyperref Info: backreferencing OFF on input line 5788.
-Package hyperref Info: Link coloring ON on input line 5791.
-Package hyperref Info: Link coloring with OCG OFF on input line 5798.
-Package hyperref Info: PDF/A mode OFF on input line 5803.
-LaTeX Info: Redefining \ref on input line 5843.
-LaTeX Info: Redefining \pageref on input line 5847.
-\Hy@abspage=\count93
-\c@Item=\count94
-\c@Hfootnote=\count95
-)
-
-Package hyperref Message: Driver (autodetected): hpdftex.
-
-(/usr/share/texlive/texmf-dist/tex/latex/hyperref/hpdftex.def
-File: hpdftex.def 2012/05/13 v6.82q Hyperref driver for pdfTeX
-\Fld@listcount=\count96
-\c@bookmark@seq@number=\count97
-
-(/usr/share/texlive/texmf-dist/tex/latex/oberdiek/rerunfilecheck.sty
-Package: rerunfilecheck 2011/04/15 v1.7 Rerun checks for auxiliary files (HO)
-Package uniquecounter Info: New unique counter `rerunfilecheck' on input line 2
-82.
-)
-\Hy@SectionHShift=\skip43
-)
-(/usr/share/texlive/texmf-dist/tex/latex/enumitem/enumitem.sty
-Package: enumitem 2011/09/28 v3.5.2 Customized lists
-\labelindent=\skip44
-\enit@outerparindent=\dimen106
-\enit@toks=\toks15
-\enit@inbox=\box26
-\enitdp@description=\count98
-)
-(/home/feela/src/git/bird/doc/tex/birddoc.sty
-Package: birddoc
-)
-(/usr/share/texmf/tex/latex/misc/qwertz.sty
-\c@definition=\count99
-\c@proposition=\count100
-\c@lemma=\count101
-\c@corollary=\count102
-\c@theorem=\count103
-)
-(/usr/share/texlive/texmf-dist/tex/latex/base/inputenc.sty
-Package: inputenc 2008/03/30 v1.1d Input encoding file
-\inpenc@prehook=\toks16
-\inpenc@posthook=\toks17
-
-(/usr/share/texlive/texmf-dist/tex/latex/base/latin1.def
-File: latin1.def 2008/03/30 v1.1d Input encoding file
-))
-(/usr/share/texlive/texmf-dist/tex/latex/graphics/epsfig.sty
-Package: epsfig 1999/02/16 v1.7a (e)psfig emulation (SPQR)
-
-(/usr/share/texlive/texmf-dist/tex/latex/graphics/graphicx.sty
-Package: graphicx 1999/02/16 v1.0f Enhanced LaTeX Graphics (DPC,SPQR)
-
-(/usr/share/texlive/texmf-dist/tex/latex/graphics/graphics.sty
-Package: graphics 2009/02/05 v1.0o Standard LaTeX Graphics (DPC,SPQR)
-
-(/usr/share/texlive/texmf-dist/tex/latex/graphics/trig.sty
-Package: trig 1999/03/16 v1.09 sin cos tan (DPC)
-)
-(/usr/share/texlive/texmf-dist/tex/latex/latexconfig/graphics.cfg
-File: graphics.cfg 2010/04/23 v1.9 graphics configuration of TeX Live
-)
-Package graphics Info: Driver file: pdftex.def on input line 91.
-
-(/usr/share/texlive/texmf-dist/tex/latex/pdftex-def/pdftex.def
-File: pdftex.def 2011/05/27 v0.06d Graphics/color for pdfTeX
-\Gread@gobject=\count104
-))
-\Gin@req@height=\dimen107
-\Gin@req@width=\dimen108
-)
-\epsfxsize=\dimen109
-\epsfysize=\dimen110
-)
-(/usr/share/texmf/tex/latex/misc/null.sty) (./prog.aux)
-\openout1 = `prog.aux'.
-
-LaTeX Font Info: Checking defaults for OML/cmm/m/it on input line 21.
-LaTeX Font Info: ... okay on input line 21.
-LaTeX Font Info: Checking defaults for T1/cmr/m/n on input line 21.
-LaTeX Font Info: ... okay on input line 21.
-LaTeX Font Info: Checking defaults for OT1/cmr/m/n on input line 21.
-LaTeX Font Info: ... okay on input line 21.
-LaTeX Font Info: Checking defaults for OMS/cmsy/m/n on input line 21.
-LaTeX Font Info: ... okay on input line 21.
-LaTeX Font Info: Checking defaults for OMX/cmex/m/n on input line 21.
-LaTeX Font Info: ... okay on input line 21.
-LaTeX Font Info: Checking defaults for U/cmr/m/n on input line 21.
-LaTeX Font Info: ... okay on input line 21.
-LaTeX Font Info: Checking defaults for PD1/pdf/m/n on input line 21.
-LaTeX Font Info: ... okay on input line 21.
-\AtBeginShipoutBox=\box27
-
-(/usr/share/texlive/texmf-dist/tex/latex/graphics/color.sty
-Package: color 2005/11/14 v1.0j Standard LaTeX Color (DPC)
-
-(/usr/share/texlive/texmf-dist/tex/latex/latexconfig/color.cfg
-File: color.cfg 2007/01/18 v1.5 color configuration of teTeX/TeXLive
-)
-Package color Info: Driver file: pdftex.def on input line 130.
-)
-Package hyperref Info: Link coloring ON on input line 21.
-
-(/usr/share/texlive/texmf-dist/tex/latex/hyperref/nameref.sty
-Package: nameref 2010/04/30 v2.40 Cross-referencing by name of section
-
-(/usr/share/texlive/texmf-dist/tex/generic/oberdiek/gettitlestring.sty
-Package: gettitlestring 2010/12/03 v1.4 Cleanup title references (HO)
-)
-\c@section@level=\count105
-)
-LaTeX Info: Redefining \ref on input line 21.
-LaTeX Info: Redefining \pageref on input line 21.
-LaTeX Info: Redefining \nameref on input line 21.
-
-(./prog.out) (./prog.out)
-\@outlinefile=\write3
-\openout3 = `prog.out'.
-
-
-(/usr/share/texlive/texmf-dist/tex/context/base/supp-pdf.mkii
-[Loading MPS to PDF converter (version 2006.09.02).]
-\scratchcounter=\count106
-\scratchdimen=\dimen111
-\scratchbox=\box28
-\nofMPsegments=\count107
-\nofMParguments=\count108
-\everyMPshowfont=\toks18
-\MPscratchCnt=\count109
-\MPscratchDim=\dimen112
-\MPnumerator=\count110
-\makeMPintoPDFobject=\count111
-\everyMPtoPDFconversion=\toks19
-) (/usr/share/texlive/texmf-dist/tex/latex/oberdiek/epstopdf-base.sty
-Package: epstopdf-base 2010/02/09 v2.5 Base part for package epstopdf
-
-(/usr/share/texlive/texmf-dist/tex/latex/oberdiek/grfext.sty
-Package: grfext 2010/08/19 v1.1 Manage graphics extensions (HO)
-)
-Package grfext Info: Graphics extension search list:
-(grfext) [.png,.pdf,.jpg,.mps,.jpeg,.jbig2,.jb2,.PNG,.PDF,.JPG,.JPE
-G,.JBIG2,.JB2,.eps]
-(grfext) \AppendGraphicsExtensions on input line 452.
-
-(/usr/share/texlive/texmf-dist/tex/latex/latexconfig/epstopdf-sys.cfg
-File: epstopdf-sys.cfg 2010/07/13 v1.3 Configuration of (r)epstopdf for TeX Liv
-e
-))
-LaTeX Font Info: External font `cmex10' loaded for size
-(Font) <7> on input line 22.
-LaTeX Font Info: External font `cmex10' loaded for size
-(Font) <5> on input line 22.
-
-Underfull \hbox (badness 10000) in paragraph at lines 22--22
-
- []
-
-[1
-
-{/var/lib/texmf/fonts/map/pdftex/updmap/pdftex.map}] (./prog.toc [2
-
-])
-\tf@toc=\write4
-\openout4 = `prog.toc'.
-
-
-[3]
-Chapter 1.
-LaTeX Font Info: Try loading font information for OMS+cmr on input line 60.
-(/usr/share/texlive/texmf-dist/tex/latex/base/omscmr.fd
-File: omscmr.fd 1999/05/25 v2.5h Standard LaTeX font definitions
-)
-LaTeX Font Info: Font shape `OMS/cmr/m/n' in size <10> not available
-(Font) Font shape `OMS/cmsy/m/n' tried instead on input line 60.
- [4
-
-] [5] [6]
-Chapter 2.
-[7
-
-] [8] [9] [10] [11] [12] [13] [14] [15] [16] [17] [18] [19] [20]
-LaTeX Font Info: Font shape `OT1/cmtt/bx/n' in size <10> not available
-(Font) Font shape `OT1/cmtt/m/n' tried instead on input line 1684.
-
- [21]
-Underfull \hbox (badness 1442) in paragraph at lines 1804--1810
-\OT1/cmr/m/n/10 and \OT1/cmr/m/it/10 proto[]want[]export[]down()\OT1/cmr/m/n/10
- ) and they are au-to-mat-i-cally freed af-ter the pro-to-col is flushed (in
- []
-
-[22] [23] [24] [25] [26] [27] [28] [29] [30] [31] [32] [33] [34] [35] [36]
-[37] [38] [39] [40]
-Chapter 3.
-[41
-
-] [42] [43] [44] [45] [46]
-Chapter 4.
-[47
-
-] [48] [49] [50] [51]
-Chapter 5.
-[52
-
-] [53] [54] [55] [56] [57] [58] [59] [60] [61] [62] [63] [64] [65] [66]
-[67] [68] [69] [70] [71] [72]
-Underfull \hbox (badness 5036) in paragraph at lines 6818--6824
-[]\OT1/cmr/m/n/10 The func-tion ac-ti-vates an up-date ses-sion and starts send
--ing rout-ing up-date pack-ets (us-ing
- []
-
-[73] [74]
-Chapter 6.
-[75
-
-] [76] [77]
-Chapter 7.
-[78
-
-] [79] [80] [81] [82] [83] [84] [85] [86] [87] [88] [89] [90]
-Chapter 8.
-[91
-
-] [92] [93] [94] [95] [96] [97] [98] [99] [100] [101] [102]
-Package atveryend Info: Empty hook `BeforeClearDocument' on input line 9736.
- [103]
-Package atveryend Info: Empty hook `AfterLastShipout' on input line 9736.
-
-(./prog.aux)
-Package atveryend Info: Executing hook `AtVeryEndDocument' on input line 9736.
-Package atveryend Info: Executing hook `AtEndAfterFileList' on input line 9736.
-
-Package rerunfilecheck Info: File `prog.out' has not changed.
-(rerunfilecheck) Checksum: BEE51873EF6F5D9B1D9C10BFD379D973;3164.
-Package atveryend Info: Empty hook `AtVeryVeryEnd' on input line 9736.
- )
-Here is how much of TeX's memory you used:
- 7869 strings out of 493620
- 110782 string characters out of 3148703
- 172281 words of memory out of 3000000
- 8740 multiletter control sequences out of 15000+200000
- 6889 words of font info for 25 fonts, out of 3000000 for 9000
- 935 hyphenation exceptions out of 8191
- 33i,6n,28p,326b,449s stack positions out of 5000i,500n,10000p,200000b,50000s
-</usr/share/texlive/texmf-dist/fonts/type1/public/amsfonts/cm/cmbx10.pfb></us
-r/share/texlive/texmf-dist/fonts/type1/public/amsfonts/cm/cmbx12.pfb></usr/shar
-e/texlive/texmf-dist/fonts/type1/public/amsfonts/cm/cmmi10.pfb></usr/share/texl
-ive/texmf-dist/fonts/type1/public/amsfonts/cm/cmr10.pfb></usr/share/texlive/tex
-mf-dist/fonts/type1/public/amsfonts/cm/cmr7.pfb></usr/share/texlive/texmf-dist/
-fonts/type1/public/amsfonts/cm/cmss10.pfb></usr/share/texlive/texmf-dist/fonts/
-type1/public/amsfonts/cm/cmss17.pfb></usr/share/texlive/texmf-dist/fonts/type1/
-public/amsfonts/cm/cmsy10.pfb></usr/share/texlive/texmf-dist/fonts/type1/public
-/amsfonts/cm/cmti10.pfb></usr/share/texlive/texmf-dist/fonts/type1/public/amsfo
-nts/cm/cmtt10.pfb>
-Output written on prog.pdf (103 pages, 456876 bytes).
-PDF statistics:
- 3463 PDF objects out of 3580 (max. 8388607)
- 3314 compressed objects within 34 object streams
- 2369 named destinations out of 2487 (max. 500000)
- 417 words of extra memory for PDF output out of 10000 (max. 10000000)
-
diff --git a/doc/prog.pdf b/doc/prog.pdf
deleted file mode 100644
index e523b246..00000000
--- a/doc/prog.pdf
+++ /dev/null
Binary files differ
diff --git a/doc/prog.sgml b/doc/prog.sgml
deleted file mode 100644
index 82c04bc6..00000000
--- a/doc/prog.sgml
+++ /dev/null
@@ -1,6868 +0,0 @@
-<!doctype birddoc system>
-
-<!--
- BIRD: Programmer's Documentation
-
- Copyright (c) 2000 Martin Mares <mj@ucw.cz>
- -->
-
-<book>
-<progdoc>
-
-<title>BIRD Programmer's Documentation
-<author>
-Ondrej Filip <it/&lt;feela@network.cz&gt;/,
-Pavel Machek <it/&lt;pavel@ucw.cz&gt;/,
-Martin Mares <it/&lt;mj@ucw.cz&gt;/,
-Ondrej Zajicek <it/&lt;santiago@crfreenet.org&gt;/
-</author>
-
-<abstract>
-This document contains programmer's documentation for the BIRD Internet Routing Daemon project.
-</abstract>
-
-<!-- Table of contents -->
-<toc>
-
-<!-- Begin the document -->
-<chapt>BIRD Design
-
-<sect>Introduction
-
-<p>This document describes the internal workings of BIRD, its architecture,
-design decisions and rationale behind them. It also contains documentation on
-all the essential components of the system and their interfaces.
-
-<p>Routing daemons are complicated things which need to act in real time
-to complex sequences of external events, respond correctly even to the most erroneous behavior
-of their environment and still handle enormous amount of data with reasonable
-speed. Due to all of this, their design is very tricky as one needs to carefully
-balance between efficiency, stability and (last, but not least) simplicity of
-the program and it would be possible to write literally hundreds of pages about
-all of these issues. In accordance to the famous quote of Anton Chekhov "Shortness
-is a sister of talent", we've tried to write a much shorter document highlighting
-the most important stuff and leaving the boring technical details better explained
-by the program source itself together with comments contained therein.
-
-<sect>Design goals
-
-<p>When planning the architecture of BIRD, we've taken a close look at the other existing routing
-daemons and also at some of the operating systems used on dedicated routers, gathered all important
-features and added lots of new ones to overcome their shortcomings and to better match the requirements
-of routing in today's Internet: IPv6, policy routing, route filtering and so on. From this
-planning, the following set of design goals has arisen:
-
-<itemize>
-
-<item><it>Support all the standard routing protocols and make it easy to add new ones.</it>
-This leads to modularity and clean separation between the core and the protocols.
-
-<item><it>Support both IPv4 and IPv6 in the same source tree, re-using most of the code.</it>
-This leads to abstraction of IP addresses and operations on them.
-
-<item><it>Minimize OS dependent code to make porting as easy as possible.</it>
-Unfortunately, such code cannot be avoided at all as the details of communication with
-the IP stack differ from OS to OS and they often vary even between different
-versions of the same OS. But we can isolate such code in special modules and
-do the porting by changing or replacing just these modules.
-Also, don't rely on specific features of various operating systems, but be able
-to make use of them if they are available.
-
-<item><it>Allow multiple routing tables.</it>
-Easily solvable by abstracting out routing tables and the corresponding operations.
-
-<item><it>Offer powerful route filtering.</it>
-There already were several attempts to incorporate route filters to a dynamic router,
-but most of them have used simple sequences of filtering rules which were very inflexible
-and hard to use for non-trivial filters. We've decided to employ a simple loop-free
-programming language having access to all the route attributes and being able to
-modify the most of them.
-
-<item><it>Support easy configuration and re-configuration.</it>
-Most routers use a simple configuration language designed ad hoc with no structure at all
-and allow online changes of configuration by using their command-line interface, thus
-any complex re-configurations are hard to achieve without replacing the configuration
-file and restarting the whole router. We've decided to use a more general approach: to
-have a configuration defined in a context-free language with blocks and nesting, to
-perform all configuration changes by editing the configuration file, but to be able
-to read the new configuration and smoothly adapt to it without disturbing parts of
-the routing process which are not affected by the change.
-
-<item><it>Be able to be controlled online.</it>
-In addition to the online reconfiguration, a routing daemon should be able to communicate
-with the user and with many other programs (primarily scripts used for network maintenance)
-in order to make it possible to inspect contents of routing tables, status of all
-routing protocols and also to control their behavior (disable, enable or reset a protocol without restarting all the others). To achieve
-this, we implement a simple command-line protocol based on those used by FTP and SMTP
-(that is textual commands and textual replies accompanied by a numeric code which makes
-them both readable to a human and easy to recognize in software).
-
-<item><it>Respond to all events in real time.</it>
-A typical solution to this problem is to use lots of threads to separate the workings
-of all the routing protocols and also of the user interface parts and to hope that
-the scheduler will assign time to them in a fair enough manner. This is surely a good
-solution, but we have resisted the temptation and preferred to avoid the overhead of threading
-and the large number of locks involved and preferred a event driven architecture with
-our own scheduling of events. An unpleasant consequence of such an approach
-is that long lasting tasks must be split to more parts linked by special
-events or timers to make the CPU available for other tasks as well.
-
-</itemize>
-
-<sect>Architecture
-
-<p>The requirements set above have lead to a simple modular architecture containing
-the following types of modules:
-
-<descrip>
-
-<tagp>Core modules</tagp> implement the core functions of BIRD: taking care
-of routing tables, keeping protocol status, interacting with the user using
-the Command-Line Interface (to be called CLI in the rest of this document)
-etc.
-
-<tagp>Library modules</tagp> form a large set of various library functions
-implementing several data abstractions, utility functions and also functions
-which are a part of the standard libraries on some systems, but missing on other
-ones.
-
-<tagp>Resource management modules</tagp> take care of resources, their allocation
-and automatic freeing when the module having requested shuts itself down.
-
-<tagp>Configuration modules</tagp> are fragments of lexical analyzer,
-grammar rules and the corresponding snippets of C code. For each group
-of code modules (core, each protocol, filters) there exist a configuration
-module taking care of all the related configuration stuff.
-
-<tagp>The filter</tagp> implements the route filtering language.
-
-<tagp>Protocol modules</tagp> implement the individual routing protocols.
-
-<tagp>System-dependent modules</tagp> implement the interface between BIRD
-and specific operating systems.
-
-<tagp>The client</tagp> is a simple program providing an easy, though friendly
-interface to the CLI.
-
-</descrip>
-
-<sect>Implementation
-
-<p>BIRD has been written in GNU C. We've considered using C++, but we've
-preferred the simplicity and straightforward nature of C which gives us fine
-control over all implementation details and on the other hand enough
-instruments to build the abstractions we need.
-
-<p>The modules are statically linked to produce a single executable file
-(except for the client which stands on its own).
-
-<p>The building process is controlled by a set of Makefiles for GNU Make,
-intermixed with several Perl and shell scripts.
-
-<p>The initial configuration of the daemon, detection of system features
-and selection of the right modules to include for the particular OS
-and the set of protocols the user has chosen is performed by a configure
-script generated by GNU Autoconf.
-
-<p>The parser of the configuration is generated by the GNU Bison.
-
-<p>The documentation is generated using <file/SGMLtools/ with our own DTD
-and mapping rules which produce both an online version in HTML and
-a neatly formatted one for printing (first converted
-from SGML to &latex; and then processed by &tex; and <file/dvips/ to
-get a PostScript file).
-
-<p>The comments from C sources which form a part of the programmer's
-documentation are extracted using a modified version of the <file/kernel-doc/
-tool.
-
-<p>If you want to work on BIRD, it's highly recommended to configure it
-with a <tt/--enable-debug/ switch which enables some internal consistency
-checks and it also links BIRD with a memory allocation checking library
-if you have one (either <tt/efence/ or <tt/dmalloc/).
-
-<!--
-LocalWords: IPv IP CLI snippets Perl Autoconf SGMLtools DTD SGML dvips
-LocalWords: PostScript
- -->
-<chapt>Core
-<sect>Forwarding Information Base
-<p>
- <p>
- FIB is a data structure designed for storage of routes indexed by their
- network prefixes. It supports insertion, deletion, searching by prefix,
- `routing' (in CIDR sense, that is searching for a longest prefix matching
- a given IP address) and (which makes the structure very tricky to implement)
- asynchronous reading, that is enumerating the contents of a FIB while other
- modules add, modify or remove entries.
- <p>
- Internally, each FIB is represented as a collection of nodes of type <struct/fib_node/
- indexed using a sophisticated hashing mechanism.
- We use two-stage hashing where we calculate a 16-bit primary hash key independent
- on hash table size and then we just divide the primary keys modulo table size
- to get a real hash key used for determining the bucket containing the node.
- The lists of nodes in each bucket are sorted according to the primary hash
- key, hence if we keep the total number of buckets to be a power of two,
- re-hashing of the structure keeps the relative order of the nodes.
- <p>
- To get the asynchronous reading consistent over node deletions, we need to
- keep a list of readers for each node. When a node gets deleted, its readers
- are automatically moved to the next node in the table.
- <p>
- Basic FIB operations are performed by functions defined by this module,
- enumerating of FIB contents is accomplished by using the <func/FIB_WALK()/ macro
- or <func/FIB_ITERATE_START()/ if you want to do it asynchronously.
- <p>
- For simple iteration just place the body of the loop between <func/FIB_WALK()/ and
- <func/FIB_WALK_END()/. You can't modify the FIB during the iteration (you can modify
- data in the node, but not add or remove nodes).
- <p>
- If you need more freedom, you can use the FIB_ITERATE_*() group of macros.
- First, you initialize an iterator with <func/FIB_ITERATE_INIT()/. Then you can put
- the loop body in between <func/FIB_ITERATE_START()/ and <func/FIB_ITERATE_END()/. In
- addition, the iteration can be suspended by calling <func/FIB_ITERATE_PUT()/.
- This'll link the iterator inside the FIB. While suspended, you may modify the
- FIB, exit the current function, etc. To resume the iteration, enter the loop
- again. You can use <func/FIB_ITERATE_UNLINK()/ to unlink the iterator (while
- iteration is suspended) in cases like premature end of FIB iteration.
- <p>
- Note that the iterator must not be destroyed when the iteration is suspended,
- the FIB would then contain a pointer to invalid memory. Therefore, after each
- <func/FIB_ITERATE_INIT()/ or <func/FIB_ITERATE_PUT()/ there must be either
- <func/FIB_ITERATE_START()/ or <func/FIB_ITERATE_UNLINK()/ before the iterator is destroyed.
-
-
-<function><p><type>void</type>
-<funcdef>fib_init</funcdef>
-(<type>struct fib *</type> <param>f</param>, <type>pool *</type> <param>p</param>, <type>unsigned</type> <param>node_size</param>, <type>unsigned</type> <param>hash_order</param>, <type>fib_init_func</type> <param>init</param>) -- initialize a new FIB
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>struct fib *</type> <param>f</param></tagp>
- the FIB to be initialized (the structure itself being allocated by the caller)
-<tagp><type>pool *</type> <param>p</param></tagp>
- pool to allocate the nodes in
-<tagp><type>unsigned</type> <param>node_size</param></tagp>
- node size to be used (each node consists of a standard header <struct/fib_node/
- followed by user data)
-<tagp><type>unsigned</type> <param>hash_order</param></tagp>
- initial hash order (a binary logarithm of hash table size), 0 to use default order
- (recommended)
-<tagp><type>fib_init_func</type> <param>init</param></tagp>
- pointer a function to be called to initialize a newly created node
-</descrip>
-<funcsect>Description
-<p>
- This function initializes a newly allocated FIB and prepares it for use.
-</function>
-<function><p><type>void *</type>
-<funcdef>fib_find</funcdef>
-(<type>struct fib *</type> <param>f</param>, <type>ip_addr *</type> <param>a</param>, <type>int</type> <param>len</param>) -- search for FIB node by prefix
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>struct fib *</type> <param>f</param></tagp>
- FIB to search in
-<tagp><type>ip_addr *</type> <param>a</param></tagp>
- pointer to IP address of the prefix
-<tagp><type>int</type> <param>len</param></tagp>
- prefix length
-</descrip>
-<funcsect>Description
-<p>
- Search for a FIB node corresponding to the given prefix, return
- a pointer to it or <const/NULL/ if no such node exists.
-</function>
-<function><p><type>void *</type>
-<funcdef>fib_get</funcdef>
-(<type>struct fib *</type> <param>f</param>, <type>ip_addr *</type> <param>a</param>, <type>int</type> <param>len</param>) -- find or create a FIB node
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>struct fib *</type> <param>f</param></tagp>
- FIB to work with
-<tagp><type>ip_addr *</type> <param>a</param></tagp>
- pointer to IP address of the prefix
-<tagp><type>int</type> <param>len</param></tagp>
- prefix length
-</descrip>
-<funcsect>Description
-<p>
- Search for a FIB node corresponding to the given prefix and
- return a pointer to it. If no such node exists, create it.
-</function>
-<function><p><type>void *</type>
-<funcdef>fib_route</funcdef>
-(<type>struct fib *</type> <param>f</param>, <type>ip_addr</type> <param>a</param>, <type>int</type> <param>len</param>) -- CIDR routing lookup
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>struct fib *</type> <param>f</param></tagp>
- FIB to search in
-<tagp><type>ip_addr</type> <param>a</param></tagp>
- pointer to IP address of the prefix
-<tagp><type>int</type> <param>len</param></tagp>
- prefix length
-</descrip>
-<funcsect>Description
-<p>
- Search for a FIB node with longest prefix matching the given
- network, that is a node which a CIDR router would use for routing
- that network.
-</function>
-<function><p><type>void</type>
-<funcdef>fib_delete</funcdef>
-(<type>struct fib *</type> <param>f</param>, <type>void *</type> <param>E</param>) -- delete a FIB node
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>struct fib *</type> <param>f</param></tagp>
- FIB to delete from
-<tagp><type>void *</type> <param>E</param></tagp>
- entry to delete
-</descrip>
-<funcsect>Description
-<p>
- This function removes the given entry from the FIB,
- taking care of all the asynchronous readers by shifting
- them to the next node in the canonical reading order.
-</function>
-<function><p><type>void</type>
-<funcdef>fib_free</funcdef>
-(<type>struct fib *</type> <param>f</param>) -- delete a FIB
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>struct fib *</type> <param>f</param></tagp>
- FIB to be deleted
-</descrip>
-<funcsect>Description
-<p>
- This function deletes a FIB -- it frees all memory associated
- with it and all its entries.
-</function>
-<function><p><type>void</type>
-<funcdef>fib_check</funcdef>
-(<type>struct fib *</type> <param>f</param>) -- audit a FIB
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>struct fib *</type> <param>f</param></tagp>
- FIB to be checked
-</descrip>
-<funcsect>Description
-<p>
- This debugging function audits a FIB by checking its internal consistency.
- Use when you suspect somebody of corrupting innocent data structures.
-</function>
-<sect>Routing tables
-<p>
- <p>
- Routing tables are probably the most important structures BIRD uses. They
- hold all the information about known networks, the associated routes and
- their attributes.
- <p>
- There are multiple routing tables (a primary one together with any
- number of secondary ones if requested by the configuration). Each table
- is basically a FIB containing entries describing the individual
- destination networks. For each network (represented by structure <struct/net/),
- there is a one-way linked list of route entries (<struct/rte/), the first entry
- on the list being the best one (i.e., the one we currently use
- for routing), the order of the other ones is undetermined.
- <p>
- The <struct/rte/ contains information specific to the route (preference, protocol
- metrics, time of last modification etc.) and a pointer to a <struct/rta/ structure
- (see the route attribute module for a precise explanation) holding the
- remaining route attributes which are expected to be shared by multiple
- routes in order to conserve memory.
-
-
-<function><p><type>rte *</type>
-<funcdef>rte_find</funcdef>
-(<type>net *</type> <param>net</param>, <type>struct rte_src *</type> <param>src</param>) -- find a route
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>net *</type> <param>net</param></tagp>
- network node
-<tagp><type>struct rte_src *</type> <param>src</param></tagp>
- route source
-</descrip>
-<funcsect>Description
-<p>
- The <func/rte_find()/ function returns a route for destination <param/net/
- which is from route source <param/src/.
-</function>
-<function><p><type>rte *</type>
-<funcdef>rte_get_temp</funcdef>
-(<type>rta *</type> <param>a</param>) -- get a temporary <struct/rte/
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>rta *</type> <param>a</param></tagp>
- attributes to assign to the new route (a <struct/rta/; in case it's
- un-cached, <func/rte_update()/ will create a cached copy automatically)
-</descrip>
-<funcsect>Description
-<p>
- Create a temporary <struct/rte/ and bind it with the attributes <param/a/.
- Also set route preference to the default preference set for
- the protocol.
-</function>
-<function><p><type>rte *</type>
-<funcdef>rte_cow_rta</funcdef>
-(<type>rte *</type> <param>r</param>, <type>linpool *</type> <param>lp</param>) -- get a private writable copy of <struct/rte/ with writable <struct/rta/
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>rte *</type> <param>r</param></tagp>
- a route entry to be copied
-<tagp><type>linpool *</type> <param>lp</param></tagp>
- a linpool from which to allocate <struct/rta/
-</descrip>
-<funcsect>Description
-<p>
- <func/rte_cow_rta()/ takes a <struct/rte/ and prepares it and associated <struct/rta/ for
- modification. There are three possibilities: First, both <struct/rte/ and <struct/rta/ are
- private copies, in that case they are returned unchanged. Second, <struct/rte/ is
- private copy, but <struct/rta/ is cached, in that case <struct/rta/ is duplicated using
- <func/rta_do_cow()/. Third, both <struct/rte/ is shared and <struct/rta/ is cached, in that case
- both structures are duplicated by <func/rte_do_cow()/ and <func/rta_do_cow()/.
- <p>
- Note that in the second case, cached <struct/rta/ loses one reference, while private
- copy created by <func/rta_do_cow()/ is a shallow copy sharing indirect data (eattrs,
- nexthops, ...) with it. To work properly, original shared <struct/rta/ should have
- another reference during the life of created private copy.
-<funcsect>Result
-<p>
- a pointer to the new writable <struct/rte/ with writable <struct/rta/.
-</function>
-<function><p><type>void</type>
-<funcdef>rte_announce</funcdef>
-(<type>rtable *</type> <param>tab</param>, <type>unsigned</type> <param>type</param>, <type>net *</type> <param>net</param>, <type>rte *</type> <param>new</param>, <type>rte *</type> <param>old</param>, <type>rte *</type> <param>new_best</param>, <type>rte *</type> <param>old_best</param>, <type>rte *</type> <param>before_old</param>) -- announce a routing table change
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>rtable *</type> <param>tab</param></tagp>
- table the route has been added to
-<tagp><type>unsigned</type> <param>type</param></tagp>
- type of route announcement (RA_OPTIMAL or RA_ANY)
-<tagp><type>net *</type> <param>net</param></tagp>
- network in question
-<tagp><type>rte *</type> <param>new</param></tagp>
- the new route to be announced
-<tagp><type>rte *</type> <param>old</param></tagp>
- the previous route for the same network
-<tagp><type>rte *</type> <param>new_best</param></tagp>
- the new best route for the same network
-<tagp><type>rte *</type> <param>old_best</param></tagp>
- the previous best route for the same network
-<tagp><type>rte *</type> <param>before_old</param></tagp>
- The previous route before <param/old/ for the same network.
- If <param/before_old/ is NULL <param/old/ was the first.
-</descrip>
-<funcsect>Description
-<p>
- This function gets a routing table update and announces it
- to all protocols that acccepts given type of route announcement
- and are connected to the same table by their announcement hooks.
- <p>
- Route announcement of type <const/RA_OPTIMAL/ si generated when optimal
- route (in routing table <param/tab/) changes. In that case <param/old/ stores the
- old optimal route.
- <p>
- Route announcement of type <const/RA_ANY/ si generated when any route (in
- routing table <param/tab/) changes In that case <param/old/ stores the old route
- from the same protocol.
- <p>
- For each appropriate protocol, we first call its <func/import_control()/
- hook which performs basic checks on the route (each protocol has a
- right to veto or force accept of the route before any filter is
- asked) and adds default values of attributes specific to the new
- protocol (metrics, tags etc.). Then it consults the protocol's
- export filter and if it accepts the route, the <func/rt_notify()/ hook of
- the protocol gets called.
-</function>
-<function><p><type>void</type>
-<funcdef>rte_free</funcdef>
-(<type>rte *</type> <param>e</param>) -- delete a <struct/rte/
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>rte *</type> <param>e</param></tagp>
- <struct/rte/ to be deleted
-</descrip>
-<funcsect>Description
-<p>
- <func/rte_free()/ deletes the given <struct/rte/ from the routing table it's linked to.
-</function>
-<function><p><type>void</type>
-<funcdef>rte_update2</funcdef>
-(<type>struct announce_hook *</type> <param>ah</param>, <type>net *</type> <param>net</param>, <type>rte *</type> <param>new</param>, <type>struct rte_src *</type> <param>src</param>) -- enter a new update to a routing table
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>struct announce_hook *</type> <param>ah</param></tagp>
- pointer to table announce hook
-<tagp><type>net *</type> <param>net</param></tagp>
- network node
-<tagp><type>rte *</type> <param>new</param></tagp>
- a <struct/rte/ representing the new route or <const/NULL/ for route removal.
-<tagp><type>struct rte_src *</type> <param>src</param></tagp>
- protocol originating the update
-</descrip>
-<funcsect>Description
-<p>
- This function is called by the routing protocols whenever they discover
- a new route or wish to update/remove an existing route. The right announcement
- sequence is to build route attributes first (either un-cached with <param/aflags/ set
- to zero or a cached one using <func/rta_lookup()/; in this case please note that
- you need to increase the use count of the attributes yourself by calling
- <func/rta_clone()/), call <func/rte_get_temp()/ to obtain a temporary <struct/rte/, fill in all
- the appropriate data and finally submit the new <struct/rte/ by calling <func/rte_update()/.
- <p>
- <param/src/ specifies the protocol that originally created the route and the meaning
- of protocol-dependent data of <param/new/. If <param/new/ is not <const/NULL/, <param/src/ have to be the
- same value as <param/new/-&gt;attrs-&gt;proto. <param/p/ specifies the protocol that called
- <func/rte_update()/. In most cases it is the same protocol as <param/src/. <func/rte_update()/
- stores <param/p/ in <param/new/-&gt;sender;
- <p>
- When <func/rte_update()/ gets any route, it automatically validates it (checks,
- whether the network and next hop address are valid IP addresses and also
- whether a normal routing protocol doesn't try to smuggle a host or link
- scope route to the table), converts all protocol dependent attributes stored
- in the <struct/rte/ to temporary extended attributes, consults import filters of the
- protocol to see if the route should be accepted and/or its attributes modified,
- stores the temporary attributes back to the <struct/rte/.
- <p>
- Now, having a "public" version of the route, we
- automatically find any old route defined by the protocol <param/src/
- for network <param/n/, replace it by the new one (or removing it if <param/new/ is <const/NULL/),
- recalculate the optimal route for this destination and finally broadcast
- the change (if any) to all routing protocols by calling <func/rte_announce()/.
- <p>
- All memory used for attribute lists and other temporary allocations is taken
- from a special linear pool <param/rte_update_pool/ and freed when <func/rte_update()/
- finishes.
-</function>
-<function><p><type>void</type>
-<funcdef>rt_refresh_begin</funcdef>
-(<type>rtable *</type> <param>t</param>, <type>struct announce_hook *</type> <param>ah</param>) -- start a refresh cycle
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>rtable *</type> <param>t</param></tagp>
- related routing table
-<tagp><type>struct announce_hook *</type> <param>ah</param></tagp>
- related announce hook
-</descrip>
-<funcsect>Description
-<p>
- This function starts a refresh cycle for given routing table and announce
- hook. The refresh cycle is a sequence where the protocol sends all its valid
- routes to the routing table (by <func/rte_update()/). After that, all protocol
- routes (more precisely routes with <param/ah/ as <param/sender/) not sent during the
- refresh cycle but still in the table from the past are pruned. This is
- implemented by marking all related routes as stale by REF_STALE flag in
- <func/rt_refresh_begin()/, then marking all related stale routes with REF_DISCARD
- flag in <func/rt_refresh_end()/ and then removing such routes in the prune loop.
-</function>
-<function><p><type>void</type>
-<funcdef>rt_refresh_end</funcdef>
-(<type>rtable *</type> <param>t</param>, <type>struct announce_hook *</type> <param>ah</param>) -- end a refresh cycle
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>rtable *</type> <param>t</param></tagp>
- related routing table
-<tagp><type>struct announce_hook *</type> <param>ah</param></tagp>
- related announce hook
-</descrip>
-<funcsect>Description
-<p>
- This function starts a refresh cycle for given routing table and announce
- hook. See <func/rt_refresh_begin()/ for description of refresh cycles.
-</function>
-<function><p><type>void</type>
-<funcdef>rte_dump</funcdef>
-(<type>rte *</type> <param>e</param>) -- dump a route
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>rte *</type> <param>e</param></tagp>
- <struct/rte/ to be dumped
-</descrip>
-<funcsect>Description
-<p>
- This functions dumps contents of a <struct/rte/ to debug output.
-</function>
-<function><p><type>void</type>
-<funcdef>rt_dump</funcdef>
-(<type>rtable *</type> <param>t</param>) -- dump a routing table
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>rtable *</type> <param>t</param></tagp>
- routing table to be dumped
-</descrip>
-<funcsect>Description
-<p>
- This function dumps contents of a given routing table to debug output.
-</function>
-<function><p><type>void</type>
-<funcdef>rt_dump_all</funcdef>
-(<param>void</param>) -- dump all routing tables
-
-<funcsect>Description
-<p>
- <p>
- This function dumps contents of all routing tables to debug output.
-</function>
-<function><p><type>void</type>
-<funcdef>rt_init</funcdef>
-(<param>void</param>) -- initialize routing tables
-
-<funcsect>Description
-<p>
- <p>
- This function is called during BIRD startup. It initializes the
- routing table module.
-</function>
-<function><p><type>int</type>
-<funcdef>rt_prune_table</funcdef>
-(<type>rtable *</type> <param>tab</param>) -- prune a routing table
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>rtable *</type> <param>tab</param></tagp>
- a routing table for pruning
-</descrip>
-<funcsect>Description
-<p>
- This function scans the routing table <param/tab/ and removes routes belonging to
- flushing protocols, discarded routes and also stale network entries, in a
- similar fashion like <func/rt_prune_loop()/. Returns 1 when all such routes are
- pruned. Contrary to <func/rt_prune_loop()/, this function is not a part of the
- protocol flushing loop, but it is called from <func/rt_event()/ for just one routing
- table.
- <p>
- Note that <func/rt_prune_table()/ and <func/rt_prune_loop()/ share (for each table) the
- prune state (<param/prune_state/) and also the pruning iterator (<param/prune_fit/).
-</function>
-<function><p><type>int</type>
-<funcdef>rt_prune_loop</funcdef>
-(<param>void</param>) -- prune routing tables
-
-<funcsect>Description
-<p>
- <p>
- The prune loop scans routing tables and removes routes belonging to flushing
- protocols, discarded routes and also stale network entries. Returns 1 when
- all such routes are pruned. It is a part of the protocol flushing loop.
-</function>
-<function><p><type>void</type>
-<funcdef>rt_lock_table</funcdef>
-(<type>rtable *</type> <param>r</param>) -- lock a routing table
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>rtable *</type> <param>r</param></tagp>
- routing table to be locked
-</descrip>
-<funcsect>Description
-<p>
- Lock a routing table, because it's in use by a protocol,
- preventing it from being freed when it gets undefined in a new
- configuration.
-</function>
-<function><p><type>void</type>
-<funcdef>rt_unlock_table</funcdef>
-(<type>rtable *</type> <param>r</param>) -- unlock a routing table
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>rtable *</type> <param>r</param></tagp>
- routing table to be unlocked
-</descrip>
-<funcsect>Description
-<p>
- Unlock a routing table formerly locked by <func/rt_lock_table()/,
- that is decrease its use count and delete it if it's scheduled
- for deletion by configuration changes.
-</function>
-<function><p><type>void</type>
-<funcdef>rt_commit</funcdef>
-(<type>struct config *</type> <param>new</param>, <type>struct config *</type> <param>old</param>) -- commit new routing table configuration
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>struct config *</type> <param>new</param></tagp>
- new configuration
-<tagp><type>struct config *</type> <param>old</param></tagp>
- original configuration or <const/NULL/ if it's boot time config
-</descrip>
-<funcsect>Description
-<p>
- Scan differences between <param/old/ and <param/new/ configuration and modify
- the routing tables according to these changes. If <param/new/ defines a
- previously unknown table, create it, if it omits a table existing
- in <param/old/, schedule it for deletion (it gets deleted when all protocols
- disconnect from it by calling <func/rt_unlock_table()/), if it exists
- in both configurations, leave it unchanged.
-</function>
-<function><p><type>int</type>
-<funcdef>rt_feed_baby</funcdef>
-(<type>struct proto *</type> <param>p</param>) -- advertise routes to a new protocol
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>struct proto *</type> <param>p</param></tagp>
- protocol to be fed
-</descrip>
-<funcsect>Description
-<p>
- This function performs one pass of advertisement of routes to a newly
- initialized protocol. It's called by the protocol code as long as it
- has something to do. (We avoid transferring all the routes in single
- pass in order not to monopolize CPU time.)
-</function>
-<function><p><type>void</type>
-<funcdef>rt_feed_baby_abort</funcdef>
-(<type>struct proto *</type> <param>p</param>) -- abort protocol feeding
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>struct proto *</type> <param>p</param></tagp>
- protocol
-</descrip>
-<funcsect>Description
-<p>
- This function is called by the protocol code when the protocol
- stops or ceases to exist before the last iteration of <func/rt_feed_baby()/
- has finished.
-</function>
-<function><p><type>net *</type>
-<funcdef>net_find</funcdef>
-(<type>rtable *</type> <param>tab</param>, <type>ip_addr</type> <param>addr</param>, <type>unsigned</type> <param>len</param>) -- find a network entry
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>rtable *</type> <param>tab</param></tagp>
- a routing table
-<tagp><type>ip_addr</type> <param>addr</param></tagp>
- address of the network
-<tagp><type>unsigned</type> <param>len</param></tagp>
- length of the network prefix
-</descrip>
-<funcsect>Description
-<p>
- <func/net_find()/ looks up the given network in routing table <param/tab/ and
- returns a pointer to its <struct/net/ entry or <const/NULL/ if no such network
- exists.
-</function>
-<function><p><type>net *</type>
-<funcdef>net_get</funcdef>
-(<type>rtable *</type> <param>tab</param>, <type>ip_addr</type> <param>addr</param>, <type>unsigned</type> <param>len</param>) -- obtain a network entry
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>rtable *</type> <param>tab</param></tagp>
- a routing table
-<tagp><type>ip_addr</type> <param>addr</param></tagp>
- address of the network
-<tagp><type>unsigned</type> <param>len</param></tagp>
- length of the network prefix
-</descrip>
-<funcsect>Description
-<p>
- <func/net_get()/ looks up the given network in routing table <param/tab/ and
- returns a pointer to its <struct/net/ entry. If no such entry exists, it's
- created.
-</function>
-<function><p><type>rte *</type>
-<funcdef>rte_cow</funcdef>
-(<type>rte *</type> <param>r</param>) -- copy a route for writing
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>rte *</type> <param>r</param></tagp>
- a route entry to be copied
-</descrip>
-<funcsect>Description
-<p>
- <func/rte_cow()/ takes a <struct/rte/ and prepares it for modification. The exact action
- taken depends on the flags of the <struct/rte/ -- if it's a temporary entry, it's
- just returned unchanged, else a new temporary entry with the same contents
- is created.
- <p>
- The primary use of this function is inside the filter machinery -- when
- a filter wants to modify <struct/rte/ contents (to change the preference or to
- attach another set of attributes), it must ensure that the <struct/rte/ is not
- shared with anyone else (and especially that it isn't stored in any routing
- table).
-<funcsect>Result
-<p>
- a pointer to the new writable <struct/rte/.
-</function>
-<sect>Route attribute cache
-<p>
- <p>
- Each route entry carries a set of route attributes. Several of them
- vary from route to route, but most attributes are usually common
- for a large number of routes. To conserve memory, we've decided to
- store only the varying ones directly in the <struct/rte/ and hold the rest
- in a special structure called <struct/rta/ which is shared among all the
- <struct/rte/'s with these attributes.
- <p>
- Each <struct/rta/ contains all the static attributes of the route (i.e.,
- those which are always present) as structure members and a list of
- dynamic attributes represented by a linked list of <struct/ea_list/
- structures, each of them consisting of an array of <struct/eattr/'s containing
- the individual attributes. An attribute can be specified more than once
- in the <struct/ea_list/ chain and in such case the first occurrence overrides
- the others. This semantics is used especially when someone (for example
- a filter) wishes to alter values of several dynamic attributes, but
- it wants to preserve the original attribute lists maintained by
- another module.
- <p>
- Each <struct/eattr/ contains an attribute identifier (split to protocol ID and
- per-protocol attribute ID), protocol dependent flags, a type code (consisting
- of several bit fields describing attribute characteristics) and either an
- embedded 32-bit value or a pointer to a <struct/adata/ structure holding attribute
- contents.
- <p>
- There exist two variants of <struct/rta/'s -- cached and un-cached ones. Un-cached
- <struct/rta/'s can have arbitrarily complex structure of <struct/ea_list/'s and they
- can be modified by any module in the route processing chain. Cached
- <struct/rta/'s have their attribute lists normalized (that means at most one
- <struct/ea_list/ is present and its values are sorted in order to speed up
- searching), they are stored in a hash table to make fast lookup possible
- and they are provided with a use count to allow sharing.
- <p>
- Routing tables always contain only cached <struct/rta/'s.
-
-
-<function><p><type>struct mpnh *</type>
-<funcdef>mpnh_merge</funcdef>
-(<type>struct mpnh *</type> <param>x</param>, <type>struct mpnh *</type> <param>y</param>, <type>int</type> <param>rx</param>, <type>int</type> <param>ry</param>, <type>int</type> <param>max</param>, <type>linpool *</type> <param>lp</param>) -- merge nexthop lists
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>struct mpnh *</type> <param>x</param></tagp>
- list 1
-<tagp><type>struct mpnh *</type> <param>y</param></tagp>
- list 2
-<tagp><type>int</type> <param>rx</param></tagp>
- reusability of list <param/x/
-<tagp><type>int</type> <param>ry</param></tagp>
- reusability of list <param/y/
-<tagp><type>int</type> <param>max</param></tagp>
- max number of nexthops
-<tagp><type>linpool *</type> <param>lp</param></tagp>
- linpool for allocating nexthops
-</descrip>
-<funcsect>Description
-<p>
- The <func/mpnh_merge()/ function takes two nexthop lists <param/x/ and <param/y/ and merges them,
- eliminating possible duplicates. The input lists must be sorted and the
- result is sorted too. The number of nexthops in result is limited by <param/max/.
- New nodes are allocated from linpool <param/lp/.
- <p>
- The arguments <param/rx/ and <param/ry/ specify whether corresponding input lists may be
- consumed by the function (i.e. their nodes reused in the resulting list), in
- that case the caller should not access these lists after that. To eliminate
- issues with deallocation of these lists, the caller should use some form of
- bulk deallocation (e.g. stack or linpool) to free these nodes when the
- resulting list is no longer needed. When reusability is not set, the
- corresponding lists are not modified nor linked from the resulting list.
-</function>
-<function><p><type>eattr *</type>
-<funcdef>ea_find</funcdef>
-(<type>ea_list *</type> <param>e</param>, <type>unsigned</type> <param>id</param>) -- find an extended attribute
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>ea_list *</type> <param>e</param></tagp>
- attribute list to search in
-<tagp><type>unsigned</type> <param>id</param></tagp>
- attribute ID to search for
-</descrip>
-<funcsect>Description
-<p>
- Given an extended attribute list, <func/ea_find()/ searches for a first
- occurrence of an attribute with specified ID, returning either a pointer
- to its <struct/eattr/ structure or <const/NULL/ if no such attribute exists.
-</function>
-<function><p><type>eattr *</type>
-<funcdef>ea_walk</funcdef>
-(<type>struct ea_walk_state *</type> <param>s</param>, <type>uint</type> <param>id</param>, <type>uint</type> <param>max</param>) -- walk through extended attributes
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>struct ea_walk_state *</type> <param>s</param></tagp>
- walk state structure
-<tagp><type>uint</type> <param>id</param></tagp>
- start of attribute ID interval
-<tagp><type>uint</type> <param>max</param></tagp>
- length of attribute ID interval
-</descrip>
-<funcsect>Description
-<p>
- Given an extended attribute list, <func/ea_walk()/ walks through the list looking
- for first occurrences of attributes with ID in specified interval from <param/id/ to
- (<param/id/ + <param/max/ - 1), returning pointers to found <struct/eattr/ structures, storing its
- walk state in <param/s/ for subsequent calls.
- <p>
- The function <func/ea_walk()/ is supposed to be called in a loop, with initially
- zeroed walk state structure <param/s/ with filled the initial extended attribute
- list, returning one found attribute in each call or <const/NULL/ when no other
- attribute exists. The extended attribute list or the arguments should not be
- modified between calls. The maximum value of <param/max/ is 128.
-</function>
-<function><p><type>int</type>
-<funcdef>ea_get_int</funcdef>
-(<type>ea_list *</type> <param>e</param>, <type>unsigned</type> <param>id</param>, <type>int</type> <param>def</param>) -- fetch an integer attribute
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>ea_list *</type> <param>e</param></tagp>
- attribute list
-<tagp><type>unsigned</type> <param>id</param></tagp>
- attribute ID
-<tagp><type>int</type> <param>def</param></tagp>
- default value
-</descrip>
-<funcsect>Description
-<p>
- This function is a shortcut for retrieving a value of an integer attribute
- by calling <func/ea_find()/ to find the attribute, extracting its value or returning
- a provided default if no such attribute is present.
-</function>
-<function><p><type>void</type>
-<funcdef>ea_sort</funcdef>
-(<type>ea_list *</type> <param>e</param>) -- sort an attribute list
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>ea_list *</type> <param>e</param></tagp>
- list to be sorted
-</descrip>
-<funcsect>Description
-<p>
- This function takes a <struct/ea_list/ chain and sorts the attributes
- within each of its entries.
- <p>
- If an attribute occurs multiple times in a single <struct/ea_list/,
- <func/ea_sort()/ leaves only the first (the only significant) occurrence.
-</function>
-<function><p><type>unsigned</type>
-<funcdef>ea_scan</funcdef>
-(<type>ea_list *</type> <param>e</param>) -- estimate attribute list size
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>ea_list *</type> <param>e</param></tagp>
- attribute list
-</descrip>
-<funcsect>Description
-<p>
- This function calculates an upper bound of the size of
- a given <struct/ea_list/ after merging with <func/ea_merge()/.
-</function>
-<function><p><type>void</type>
-<funcdef>ea_merge</funcdef>
-(<type>ea_list *</type> <param>e</param>, <type>ea_list *</type> <param>t</param>) -- merge segments of an attribute list
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>ea_list *</type> <param>e</param></tagp>
- attribute list
-<tagp><type>ea_list *</type> <param>t</param></tagp>
- buffer to store the result to
-</descrip>
-<funcsect>Description
-<p>
- This function takes a possibly multi-segment attribute list
- and merges all of its segments to one.
- <p>
- The primary use of this function is for <struct/ea_list/ normalization:
- first call <func/ea_scan()/ to determine how much memory will the result
- take, then allocate a buffer (usually using <func/alloca()/), merge the
- segments with <func/ea_merge()/ and finally sort and prune the result
- by calling <func/ea_sort()/.
-</function>
-<function><p><type>int</type>
-<funcdef>ea_same</funcdef>
-(<type>ea_list *</type> <param>x</param>, <type>ea_list *</type> <param>y</param>) -- compare two <struct/ea_list/'s
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>ea_list *</type> <param>x</param></tagp>
- attribute list
-<tagp><type>ea_list *</type> <param>y</param></tagp>
- attribute list
-</descrip>
-<funcsect>Description
-<p>
- <func/ea_same()/ compares two normalized attribute lists <param/x/ and <param/y/ and returns
- 1 if they contain the same attributes, 0 otherwise.
-</function>
-<function><p><type>void</type>
-<funcdef>ea_show</funcdef>
-(<type>struct cli *</type> <param>c</param>, <type>eattr *</type> <param>e</param>) -- print an <struct/eattr/ to CLI
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>struct cli *</type> <param>c</param></tagp>
- destination CLI
-<tagp><type>eattr *</type> <param>e</param></tagp>
- attribute to be printed
-</descrip>
-<funcsect>Description
-<p>
- This function takes an extended attribute represented by its <struct/eattr/
- structure and prints it to the CLI according to the type information.
- <p>
- If the protocol defining the attribute provides its own
- <func/get_attr()/ hook, it's consulted first.
-</function>
-<function><p><type>void</type>
-<funcdef>ea_dump</funcdef>
-(<type>ea_list *</type> <param>e</param>) -- dump an extended attribute
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>ea_list *</type> <param>e</param></tagp>
- attribute to be dumped
-</descrip>
-<funcsect>Description
-<p>
- <func/ea_dump()/ dumps contents of the extended attribute given to
- the debug output.
-</function>
-<function><p><type>uint</type>
-<funcdef>ea_hash</funcdef>
-(<type>ea_list *</type> <param>e</param>) -- calculate an <struct/ea_list/ hash key
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>ea_list *</type> <param>e</param></tagp>
- attribute list
-</descrip>
-<funcsect>Description
-<p>
- <func/ea_hash()/ takes an extended attribute list and calculated a hopefully
- uniformly distributed hash value from its contents.
-</function>
-<function><p><type>ea_list *</type>
-<funcdef>ea_append</funcdef>
-(<type>ea_list *</type> <param>to</param>, <type>ea_list *</type> <param>what</param>) -- concatenate <struct/ea_list/'s
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>ea_list *</type> <param>to</param></tagp>
- destination list (can be <const/NULL/)
-<tagp><type>ea_list *</type> <param>what</param></tagp>
- list to be appended (can be <const/NULL/)
-</descrip>
-<funcsect>Description
-<p>
- This function appends the <struct/ea_list/ <param/what/ at the end of
- <struct/ea_list/ <param/to/ and returns a pointer to the resulting list.
-</function>
-<function><p><type>rta *</type>
-<funcdef>rta_lookup</funcdef>
-(<type>rta *</type> <param>o</param>) -- look up a <struct/rta/ in attribute cache
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>rta *</type> <param>o</param></tagp>
- a un-cached <struct/rta/
-</descrip>
-<funcsect>Description
-<p>
- <func/rta_lookup()/ gets an un-cached <struct/rta/ structure and returns its cached
- counterpart. It starts with examining the attribute cache to see whether
- there exists a matching entry. If such an entry exists, it's returned and
- its use count is incremented, else a new entry is created with use count
- set to 1.
- <p>
- The extended attribute lists attached to the <struct/rta/ are automatically
- converted to the normalized form.
-</function>
-<function><p><type>void</type>
-<funcdef>rta_dump</funcdef>
-(<type>rta *</type> <param>a</param>) -- dump route attributes
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>rta *</type> <param>a</param></tagp>
- attribute structure to dump
-</descrip>
-<funcsect>Description
-<p>
- This function takes a <struct/rta/ and dumps its contents to the debug output.
-</function>
-<function><p><type>void</type>
-<funcdef>rta_dump_all</funcdef>
-(<param>void</param>) -- dump attribute cache
-
-<funcsect>Description
-<p>
- <p>
- This function dumps the whole contents of route attribute cache
- to the debug output.
-</function>
-<function><p><type>void</type>
-<funcdef>rta_init</funcdef>
-(<param>void</param>) -- initialize route attribute cache
-
-<funcsect>Description
-<p>
- <p>
- This function is called during initialization of the routing
- table module to set up the internals of the attribute cache.
-</function>
-<function><p><type>rta *</type>
-<funcdef>rta_clone</funcdef>
-(<type>rta *</type> <param>r</param>) -- clone route attributes
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>rta *</type> <param>r</param></tagp>
- a <struct/rta/ to be cloned
-</descrip>
-<funcsect>Description
-<p>
- <func/rta_clone()/ takes a cached <struct/rta/ and returns its identical cached
- copy. Currently it works by just returning the original <struct/rta/ with
- its use count incremented.
-</function>
-<function><p><type>void</type>
-<funcdef>rta_free</funcdef>
-(<type>rta *</type> <param>r</param>) -- free route attributes
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>rta *</type> <param>r</param></tagp>
- a <struct/rta/ to be freed
-</descrip>
-<funcsect>Description
-<p>
- If you stop using a <struct/rta/ (for example when deleting a route which uses
- it), you need to call <func/rta_free()/ to notify the attribute cache the
- attribute is no longer in use and can be freed if you were the last
- user (which <func/rta_free()/ tests by inspecting the use count).
-</function>
-<!--
- BIRD Programmer's Guide: Protocols
-
- (c) 2000 Martin Mares <mj@ucw.cz>
--->
-
-<sect>Routing protocols
-
-<sect1>Introduction
-
-<p>The routing protocols are the bird's heart and a fine amount of code
-is dedicated to their management and for providing support functions to them.
-(-: Actually, this is the reason why the directory with sources of the core
-code is called <tt/nest/ :-).
-
-<p>When talking about protocols, one need to distinguish between <em/protocols/
-and protocol <em/instances/. A protocol exists exactly once, not depending on whether
-it's configured or not and it can have an arbitrary number of instances corresponding
-to its "incarnations" requested by the configuration file. Each instance is completely
-autonomous, has its own configuration, its own status, its own set of routes and its
-own set of interfaces it works on.
-
-<p>A protocol is represented by a <struct/protocol/ structure containing all the basic
-information (protocol name, default settings and pointers to most of the protocol
-hooks). All these structures are linked in the <param/protocol_list/ list.
-
-<p>Each instance has its own <struct/proto/ structure describing all its properties: protocol
-type, configuration, a resource pool where all resources belonging to the instance
-live, various protocol attributes (take a look at the declaration of <struct/proto/ in
-<tt/protocol.h/), protocol states (see below for what do they mean), connections
-to routing tables, filters attached to the protocol
-and finally a set of pointers to the rest of protocol hooks (they
-are the same for all instances of the protocol, but in order to avoid extra
-indirections when calling the hooks from the fast path, they are stored directly
-in <struct/proto/). The instance is always linked in both the global instance list
-(<param/proto_list/) and a per-status list (either <param/active_proto_list/ for
-running protocols, <param/initial_proto_list/ for protocols being initialized or
-<param/flush_proto_list/ when the protocol is being shut down).
-
-<p>The protocol hooks are described in the next chapter, for more information about
-configuration of protocols, please refer to the configuration chapter and also
-to the description of the <func/proto_commit/ function.
-
-<sect1>Protocol states
-
-<p>As startup and shutdown of each protocol are complex processes which can be affected
-by lots of external events (user's actions, reconfigurations, behavior of neighboring routers etc.),
-we have decided to supervise them by a pair of simple state machines -- the protocol
-state machine and a core state machine.
-
-<p>The <em/protocol state machine/ corresponds to internal state of the protocol
-and the protocol can alter its state whenever it wants to. There are
-the following states:
-
-<descrip>
- <tag/PS_DOWN/ The protocol is down and waits for being woken up by calling its
- start() hook.
- <tag/PS_START/ The protocol is waiting for connection with the rest of the
- network. It's active, it has resources allocated, but it still doesn't want
- any routes since it doesn't know what to do with them.
- <tag/PS_UP/ The protocol is up and running. It communicates with the core,
- delivers routes to tables and wants to hear announcement about route changes.
- <tag/PS_STOP/ The protocol has been shut down (either by being asked by the
- core code to do so or due to having encountered a protocol error).
-</descrip>
-
-<p>Unless the protocol is in the <tt/PS_DOWN/ state, it can decide to change
-its state by calling the <func/proto_notify_state/ function.
-
-<p>At any time, the core code can ask the protocol to shut itself down by calling its stop() hook.
-
-<p>The <em/core state machine/ takes care of the core view of protocol state.
-The states are traversed according to changes of the protocol state machine, but
-sometimes the transitions are delayed if the core needs to finish some actions
-(for example sending of new routes to the protocol) before proceeding to the
-new state. There are the following core states:
-
-<descrip>
- <tag/FS_HUNGRY/ The protocol is down, it doesn't have any routes and
- doesn't want them.
- <tag/FS_FEEDING/ The protocol has reached the <tt/PS_UP/ state, but
- we are still busy sending the initial set of routes to it.
- <tag/FS_HAPPY/ The protocol is up and has complete routing information.
- <tag/FS_FLUSHING/ The protocol is shutting down (it's in either <tt/PS_STOP/
- or <tt/PS_DOWN/ state) and we're flushing all of its routes from the
- routing tables.
-</descrip>
-
-<sect1>Functions of the protocol module
-
-<p>The protocol module provides the following functions:
-<function><p><type>void *</type>
-<funcdef>proto_new</funcdef>
-(<type>struct proto_config *</type> <param>c</param>, <type>unsigned</type> <param>size</param>) -- create a new protocol instance
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>struct proto_config *</type> <param>c</param></tagp>
- protocol configuration
-<tagp><type>unsigned</type> <param>size</param></tagp>
- size of protocol data structure (each protocol instance is represented by
-a structure starting with generic part [struct <struct/proto/] and continued
-with data specific to the protocol)
-</descrip>
-<funcsect>Description
-<p>
-When a new configuration has been read in, the core code starts
-initializing all the protocol instances configured by calling their
-<func/init()/ hooks with the corresponding instance configuration. The initialization
-code of the protocol is expected to create a new instance according to the
-configuration by calling this function and then modifying the default settings
-to values wanted by the protocol.
-</function>
-<function><p><type>struct announce_hook *</type>
-<funcdef>proto_add_announce_hook</funcdef>
-(<type>struct proto *</type> <param>p</param>, <type>struct rtable *</type> <param>t</param>, <type>struct proto_stats *</type> <param>stats</param>) -- connect protocol to a routing table
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>struct proto *</type> <param>p</param></tagp>
- protocol instance
-<tagp><type>struct rtable *</type> <param>t</param></tagp>
- routing table to connect to
-<tagp><type>struct proto_stats *</type> <param>stats</param></tagp>
- per-table protocol statistics
-</descrip>
-<funcsect>Description
-<p>
-This function creates a connection between the protocol instance <param/p/ and the
-routing table <param/t/, making the protocol hear all changes in the table.
-<p>
-The announce hook is linked in the protocol ahook list. Announce hooks are
-allocated from the routing table resource pool and when protocol accepts
-routes also in the table ahook list. The are linked to the table ahook list
-and unlinked from it depending on export_state (in <func/proto_want_export_up()/ and
-<func/proto_want_export_down()/) and they are automatically freed after the protocol
-is flushed (in <func/proto_fell_down()/).
-<p>
-Unless you want to listen to multiple routing tables (as the Pipe protocol
-does), you needn't to worry about this function since the connection to the
-protocol's primary routing table is initialized automatically by the core
-code.
-</function>
-<function><p><type>struct announce_hook *</type>
-<funcdef>proto_find_announce_hook</funcdef>
-(<type>struct proto *</type> <param>p</param>, <type>struct rtable *</type> <param>t</param>) -- find announce hooks
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>struct proto *</type> <param>p</param></tagp>
- protocol instance
-<tagp><type>struct rtable *</type> <param>t</param></tagp>
- routing table
-</descrip>
-<funcsect>Description
-<p>
-Returns pointer to announce hook or NULL
-</function>
-<function><p><type>void *</type>
-<funcdef>proto_config_new</funcdef>
-(<type>struct protocol *</type> <param>pr</param>, <type>int</type> <param>class</param>) -- create a new protocol configuration
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>struct protocol *</type> <param>pr</param></tagp>
- protocol the configuration will belong to
-<tagp><type>int</type> <param>class</param></tagp>
- SYM_PROTO or SYM_TEMPLATE
-</descrip>
-<funcsect>Description
-<p>
-Whenever the configuration file says that a new instance
-of a routing protocol should be created, the parser calls
-<func/proto_config_new()/ to create a configuration entry for this
-instance (a structure staring with the <struct/proto_config/ header
-containing all the generic items followed by protocol-specific
-ones). Also, the configuration entry gets added to the list
-of protocol instances kept in the configuration.
-<p>
-The function is also used to create protocol templates (when class
-SYM_TEMPLATE is specified), the only difference is that templates
-are not added to the list of protocol instances and therefore not
-initialized during <func/protos_commit()/).
-</function>
-<function><p><type>void</type>
-<funcdef>proto_copy_config</funcdef>
-(<type>struct proto_config *</type> <param>dest</param>, <type>struct proto_config *</type> <param>src</param>) -- copy a protocol configuration
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>struct proto_config *</type> <param>dest</param></tagp>
- destination protocol configuration
-<tagp><type>struct proto_config *</type> <param>src</param></tagp>
- source protocol configuration
-</descrip>
-<funcsect>Description
-<p>
-Whenever a new instance of a routing protocol is created from the
-template, <func/proto_copy_config()/ is called to copy a content of
-the source protocol configuration to the new protocol configuration.
-Name, class and a node in protos list of <param/dest/ are kept intact.
-<func/copy_config()/ protocol hook is used to copy protocol-specific data.
-</function>
-<function><p><type>void</type>
-<funcdef>protos_preconfig</funcdef>
-(<type>struct config *</type> <param>c</param>) -- pre-configuration processing
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>struct config *</type> <param>c</param></tagp>
- new configuration
-</descrip>
-<funcsect>Description
-<p>
-This function calls the <func/preconfig()/ hooks of all routing
-protocols available to prepare them for reading of the new
-configuration.
-</function>
-<function><p><type>void</type>
-<funcdef>protos_postconfig</funcdef>
-(<type>struct config *</type> <param>c</param>) -- post-configuration processing
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>struct config *</type> <param>c</param></tagp>
- new configuration
-</descrip>
-<funcsect>Description
-<p>
-This function calls the <func/postconfig()/ hooks of all protocol
-instances specified in configuration <param/c/. The hooks are not
-called for protocol templates.
-</function>
-<function><p><type>void</type>
-<funcdef>protos_commit</funcdef>
-(<type>struct config *</type> <param>new</param>, <type>struct config *</type> <param>old</param>, <type>int</type> <param>force_reconfig</param>, <type>int</type> <param>type</param>) -- commit new protocol configuration
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>struct config *</type> <param>new</param></tagp>
- new configuration
-<tagp><type>struct config *</type> <param>old</param></tagp>
- old configuration or <const/NULL/ if it's boot time config
-<tagp><type>int</type> <param>force_reconfig</param></tagp>
- force restart of all protocols (used for example
-when the router ID changes)
-<tagp><type>int</type> <param>type</param></tagp>
- type of reconfiguration (RECONFIG_SOFT or RECONFIG_HARD)
-</descrip>
-<funcsect>Description
-<p>
-Scan differences between <param/old/ and <param/new/ configuration and adjust all
-protocol instances to conform to the new configuration.
-<p>
-When a protocol exists in the new configuration, but it doesn't in the
-original one, it's immediately started. When a collision with the other
-running protocol would arise, the new protocol will be temporarily stopped
-by the locking mechanism.
-<p>
-When a protocol exists in the old configuration, but it doesn't in the
-new one, it's shut down and deleted after the shutdown completes.
-<p>
-When a protocol exists in both configurations, the core decides
-whether it's possible to reconfigure it dynamically - it checks all
-the core properties of the protocol (changes in filters are ignored
-if type is RECONFIG_SOFT) and if they match, it asks the
-<func/reconfigure()/ hook of the protocol to see if the protocol is able
-to switch to the new configuration. If it isn't possible, the
-protocol is shut down and a new instance is started with the new
-configuration after the shutdown is completed.
-</function>
-<sect>Graceful restart recovery
-<p>
- <p>
- Graceful restart of a router is a process when the routing plane (e.g. BIRD)
- restarts but both the forwarding plane (e.g kernel routing table) and routing
- neighbors keep proper routes, and therefore uninterrupted packet forwarding
- is maintained.
- <p>
- BIRD implements graceful restart recovery by deferring export of routes to
- protocols until routing tables are refilled with the expected content. After
- start, protocols generate routes as usual, but routes are not propagated to
- them, until protocols report that they generated all routes. After that,
- graceful restart recovery is finished and the export (and the initial feed)
- to protocols is enabled.
- <p>
- When graceful restart recovery need is detected during initialization, then
- enabled protocols are marked with <param/gr_recovery/ flag before start. Such
- protocols then decide how to proceed with graceful restart, participation is
- voluntary. Protocols could lock the recovery by <func/proto_graceful_restart_lock()/
- (stored in <param/gr_lock/ flag), which means that they want to postpone the end of
- the recovery until they converge and then unlock it. They also could set
- <param/gr_wait/ before advancing to <const/PS_UP/, which means that the core should defer
- route export to that protocol until the end of the recovery. This should be
- done by protocols that expect their neigbors to keep the proper routes
- (kernel table, BGP sessions with BGP graceful restart capability).
- <p>
- The graceful restart recovery is finished when either all graceful restart
- locks are unlocked or when graceful restart wait timer fires.
-
-
-<function><p><type>void</type>
-<funcdef>graceful_restart_recovery</funcdef>
-(<param>void</param>) -- request initial graceful restart recovery
-
-<funcsect>Graceful restart recovery
-<p>
- <p>
- Called by the platform initialization code if the need for recovery
- after graceful restart is detected during boot. Have to be called
- before <func/protos_commit()/.
-</function>
-<function><p><type>void</type>
-<funcdef>graceful_restart_init</funcdef>
-(<param>void</param>) -- initialize graceful restart
-
-<funcsect>Description
-<p>
- <p>
- When graceful restart recovery was requested, the function starts an active
- phase of the recovery and initializes graceful restart wait timer. The
- function have to be called after <func/protos_commit()/.
-</function>
-<function><p><type>void</type>
-<funcdef>graceful_restart_done</funcdef>
-(<type>struct timer *t</type> <param>UNUSED</param>) -- finalize graceful restart
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>struct timer *t</type> <param>UNUSED</param></tagp>
- -- undescribed --
-</descrip>
-<funcsect>Description
-<p>
- When there are no locks on graceful restart, the functions finalizes the
- graceful restart recovery. Protocols postponing route export until the end of
- the recovery are awakened and the export to them is enabled. All other
- related state is cleared. The function is also called when the graceful
- restart wait timer fires (but there are still some locks).
-</function>
-<function><p><type>void</type>
-<funcdef>proto_graceful_restart_lock</funcdef>
-(<type>struct proto *</type> <param>p</param>) -- lock graceful restart by protocol
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>struct proto *</type> <param>p</param></tagp>
- protocol instance
-</descrip>
-<funcsect>Description
-<p>
- This function allows a protocol to postpone the end of graceful restart
- recovery until it converges. The lock is removed when the protocol calls
- <func/proto_graceful_restart_unlock()/ or when the protocol is stopped.
- <p>
- The function have to be called during the initial phase of graceful restart
- recovery and only for protocols that are part of graceful restart (i.e. their
- <param/gr_recovery/ is set), which means it should be called from protocol start
- hooks.
-</function>
-<function><p><type>void</type>
-<funcdef>proto_graceful_restart_unlock</funcdef>
-(<type>struct proto *</type> <param>p</param>) -- unlock graceful restart by protocol
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>struct proto *</type> <param>p</param></tagp>
- protocol instance
-</descrip>
-<funcsect>Description
-<p>
- This function unlocks a lock from <func/proto_graceful_restart_lock()/. It is also
- automatically called when the lock holding protocol went down.
-</function>
-<function><p><type>void</type>
-<funcdef>protos_dump_all</funcdef>
-(<param>void</param>) -- dump status of all protocols
-
-<funcsect>Description
-<p>
- <p>
- This function dumps status of all existing protocol instances to the
- debug output. It involves printing of general status information
- such as protocol states, its position on the protocol lists
- and also calling of a <func/dump()/ hook of the protocol to print
- the internals.
-</function>
-<function><p><type>void</type>
-<funcdef>proto_build</funcdef>
-(<type>struct protocol *</type> <param>p</param>) -- make a single protocol available
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>struct protocol *</type> <param>p</param></tagp>
- the protocol
-</descrip>
-<funcsect>Description
-<p>
- After the platform specific initialization code uses <func/protos_build()/
- to add all the standard protocols, it should call <func/proto_build()/ for
- all platform specific protocols to inform the core that they exist.
-</function>
-<function><p><type>void</type>
-<funcdef>protos_build</funcdef>
-(<param>void</param>) -- build a protocol list
-
-<funcsect>Description
-<p>
- <p>
- This function is called during BIRD startup to insert
- all standard protocols to the global protocol list. Insertion
- of platform specific protocols (such as the kernel syncer)
- is in the domain of competence of the platform dependent
- startup code.
-</function>
-<function><p><type>void</type>
-<funcdef>proto_set_message</funcdef>
-(<type>struct proto *</type> <param>p</param>, <type>char *</type> <param>msg</param>, <type>int</type> <param>len</param>) -- set administrative message to protocol
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>struct proto *</type> <param>p</param></tagp>
- protocol
-<tagp><type>char *</type> <param>msg</param></tagp>
- message
-<tagp><type>int</type> <param>len</param></tagp>
- message length (-1 for NULL-terminated string)
-</descrip>
-<funcsect>Description
-<p>
- The function sets administrative message (string) related to protocol state
- change. It is called by the nest code for manual enable/disable/restart
- commands all routes to the protocol, and by protocol-specific code when the
- protocol state change is initiated by the protocol. Using NULL message clears
- the last message. The message string may be either NULL-terminated or with an
- explicit length.
-</function>
-<function><p><type>void</type>
-<funcdef>proto_request_feeding</funcdef>
-(<type>struct proto *</type> <param>p</param>) -- request feeding routes to the protocol
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>struct proto *</type> <param>p</param></tagp>
- given protocol
-</descrip>
-<funcsect>Description
-<p>
- Sometimes it is needed to send again all routes to the
- protocol. This is called feeding and can be requested by this
- function. This would cause protocol export state transition
- to ES_FEEDING (during feeding) and when completed, it will
- switch back to ES_READY. This function can be called even
- when feeding is already running, in that case it is restarted.
-</function>
-<function><p><type>void</type>
-<funcdef>proto_notify_limit</funcdef>
-(<type>struct announce_hook *</type> <param>ah</param>, <type>struct proto_limit *</type> <param>l</param>, <type>int</type> <param>dir</param>, <type>u32</type> <param>rt_count</param>)
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>struct announce_hook *</type> <param>ah</param></tagp>
- announce hook
-<tagp><type>struct proto_limit *</type> <param>l</param></tagp>
- limit being hit
-<tagp><type>int</type> <param>dir</param></tagp>
- limit direction (PLD_*)
-<tagp><type>u32</type> <param>rt_count</param></tagp>
- the number of routes
-</descrip>
-<funcsect>Description
-<p>
- The function is called by the route processing core when limit <param/l/
- is breached. It activates the limit and tooks appropriate action
- according to <param/l/-&gt;action.
-</function>
-<function><p><type>void</type>
-<funcdef>proto_notify_state</funcdef>
-(<type>struct proto *</type> <param>p</param>, <type>unsigned</type> <param>ps</param>) -- notify core about protocol state change
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>struct proto *</type> <param>p</param></tagp>
- protocol the state of which has changed
-<tagp><type>unsigned</type> <param>ps</param></tagp>
- the new status
-</descrip>
-<funcsect>Description
-<p>
- Whenever a state of a protocol changes due to some event internal
- to the protocol (i.e., not inside a <func/start()/ or <func/shutdown()/ hook),
- it should immediately notify the core about the change by calling
- <func/proto_notify_state()/ which will write the new state to the <struct/proto/
- structure and take all the actions necessary to adapt to the new
- state. State change to PS_DOWN immediately frees resources of protocol
- and might execute start callback of protocol; therefore,
- it should be used at tail positions of protocol callbacks.
-</function>
-<sect>Protocol hooks
-<p>
- <p>
- Each protocol can provide a rich set of hook functions referred to by pointers
- in either the <struct/proto/ or <struct/protocol/ structure. They are called by the core whenever
- it wants the protocol to perform some action or to notify the protocol about
- any change of its environment. All of the hooks can be set to <const/NULL/ which means
- to ignore the change or to take a default action.
-
-
-<function><p><type>void</type>
-<funcdef>preconfig</funcdef>
-(<type>struct protocol *</type> <param>p</param>, <type>struct config *</type> <param>c</param>) -- protocol preconfiguration
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>struct protocol *</type> <param>p</param></tagp>
- a routing protocol
-<tagp><type>struct config *</type> <param>c</param></tagp>
- new configuration
-</descrip>
-<funcsect>Description
-<p>
- The <func/preconfig()/ hook is called before parsing of a new configuration.
-</function>
-<function><p><type>void</type>
-<funcdef>postconfig</funcdef>
-(<type>struct proto_config *</type> <param>c</param>) -- instance post-configuration
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>struct proto_config *</type> <param>c</param></tagp>
- instance configuration
-</descrip>
-<funcsect>Description
-<p>
- The <func/postconfig()/ hook is called for each configured instance after
- parsing of the new configuration is finished.
-</function>
-<function><p><type>struct proto *</type>
-<funcdef>init</funcdef>
-(<type>struct proto_config *</type> <param>c</param>) -- initialize an instance
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>struct proto_config *</type> <param>c</param></tagp>
- instance configuration
-</descrip>
-<funcsect>Description
-<p>
- The <func/init()/ hook is called by the core to create a protocol instance
- according to supplied protocol configuration.
-<funcsect>Result
-<p>
- a pointer to the instance created
-</function>
-<function><p><type>int</type>
-<funcdef>reconfigure</funcdef>
-(<type>struct proto *</type> <param>p</param>, <type>struct proto_config *</type> <param>c</param>) -- request instance reconfiguration
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>struct proto *</type> <param>p</param></tagp>
- an instance
-<tagp><type>struct proto_config *</type> <param>c</param></tagp>
- new configuration
-</descrip>
-<funcsect>Description
-<p>
- The core calls the <func/reconfigure()/ hook whenever it wants to ask the
- protocol for switching to a new configuration. If the reconfiguration
- is possible, the hook returns 1. Otherwise, it returns 0 and the core
- will shut down the instance and start a new one with the new configuration.
- <p>
- After the protocol confirms reconfiguration, it must no longer keep any
- references to the old configuration since the memory it's stored in can
- be re-used at any time.
-</function>
-<function><p><type>void</type>
-<funcdef>dump</funcdef>
-(<type>struct proto *</type> <param>p</param>) -- dump protocol state
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>struct proto *</type> <param>p</param></tagp>
- an instance
-</descrip>
-<funcsect>Description
-<p>
- This hook dumps the complete state of the instance to the
- debug output.
-</function>
-<function><p><type>void</type>
-<funcdef>dump_attrs</funcdef>
-(<type>rte *</type> <param>e</param>) -- dump protocol-dependent attributes
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>rte *</type> <param>e</param></tagp>
- a route entry
-</descrip>
-<funcsect>Description
-<p>
- This hook dumps all attributes in the <struct/rte/ which belong to this
- protocol to the debug output.
-</function>
-<function><p><type>int</type>
-<funcdef>start</funcdef>
-(<type>struct proto *</type> <param>p</param>) -- request instance startup
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>struct proto *</type> <param>p</param></tagp>
- protocol instance
-</descrip>
-<funcsect>Description
-<p>
- The <func/start()/ hook is called by the core when it wishes to start
- the instance. Multitable protocols should lock their tables here.
-<funcsect>Result
-<p>
- new protocol state
-</function>
-<function><p><type>int</type>
-<funcdef>shutdown</funcdef>
-(<type>struct proto *</type> <param>p</param>) -- request instance shutdown
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>struct proto *</type> <param>p</param></tagp>
- protocol instance
-</descrip>
-<funcsect>Description
-<p>
- The <func/stop()/ hook is called by the core when it wishes to shut
- the instance down for some reason.
-<funcsect>Returns
-<p>
- new protocol state
-</function>
-<function><p><type>void</type>
-<funcdef>cleanup</funcdef>
-(<type>struct proto *</type> <param>p</param>) -- request instance cleanup
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>struct proto *</type> <param>p</param></tagp>
- protocol instance
-</descrip>
-<funcsect>Description
-<p>
- The <func/cleanup()/ hook is called by the core when the protocol became
- hungry/down, i.e. all protocol ahooks and routes are flushed.
- Multitable protocols should unlock their tables here.
-</function>
-<function><p><type>void</type>
-<funcdef>get_status</funcdef>
-(<type>struct proto *</type> <param>p</param>, <type>byte *</type> <param>buf</param>) -- get instance status
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>struct proto *</type> <param>p</param></tagp>
- protocol instance
-<tagp><type>byte *</type> <param>buf</param></tagp>
- buffer to be filled with the status string
-</descrip>
-<funcsect>Description
-<p>
- This hook is called by the core if it wishes to obtain an brief one-line user friendly
- representation of the status of the instance to be printed by the &lt;cf/show protocols/
- command.
-</function>
-<function><p><type>void</type>
-<funcdef>get_route_info</funcdef>
-(<type>rte *</type> <param>e</param>, <type>byte *</type> <param>buf</param>, <type>ea_list *</type> <param>attrs</param>) -- get route information
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>rte *</type> <param>e</param></tagp>
- a route entry
-<tagp><type>byte *</type> <param>buf</param></tagp>
- buffer to be filled with the resulting string
-<tagp><type>ea_list *</type> <param>attrs</param></tagp>
- extended attributes of the route
-</descrip>
-<funcsect>Description
-<p>
- This hook is called to fill the buffer <param/buf/ with a brief user friendly
- representation of metrics of a route belonging to this protocol.
-</function>
-<function><p><type>int</type>
-<funcdef>get_attr</funcdef>
-(<type>eattr *</type> <param>a</param>, <type>byte *</type> <param>buf</param>, <type>int</type> <param>buflen</param>) -- get attribute information
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>eattr *</type> <param>a</param></tagp>
- an extended attribute
-<tagp><type>byte *</type> <param>buf</param></tagp>
- buffer to be filled with attribute information
-<tagp><type>int</type> <param>buflen</param></tagp>
- a length of the <param/buf/ parameter
-</descrip>
-<funcsect>Description
-<p>
- The <func/get_attr()/ hook is called by the core to obtain a user friendly
- representation of an extended route attribute. It can either leave
- the whole conversion to the core (by returning <const/GA_UNKNOWN/), fill
- in only attribute name (and let the core format the attribute value
- automatically according to the type field; by returning <const/GA_NAME/)
- or doing the whole conversion (used in case the value requires extra
- care; return <const/GA_FULL/).
-</function>
-<function><p><type>void</type>
-<funcdef>if_notify</funcdef>
-(<type>struct proto *</type> <param>p</param>, <type>unsigned</type> <param>flags</param>, <type>struct iface *</type> <param>i</param>) -- notify instance about interface changes
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>struct proto *</type> <param>p</param></tagp>
- protocol instance
-<tagp><type>unsigned</type> <param>flags</param></tagp>
- interface change flags
-<tagp><type>struct iface *</type> <param>i</param></tagp>
- the interface in question
-</descrip>
-<funcsect>Description
-<p>
- This hook is called whenever any network interface changes its status.
- The change is described by a combination of status bits (<const/IF_CHANGE_xxx/)
- in the <param/flags/ parameter.
-</function>
-<function><p><type>void</type>
-<funcdef>ifa_notify</funcdef>
-(<type>struct proto *</type> <param>p</param>, <type>unsigned</type> <param>flags</param>, <type>struct ifa *</type> <param>a</param>) -- notify instance about interface address changes
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>struct proto *</type> <param>p</param></tagp>
- protocol instance
-<tagp><type>unsigned</type> <param>flags</param></tagp>
- address change flags
-<tagp><type>struct ifa *</type> <param>a</param></tagp>
- the interface address
-</descrip>
-<funcsect>Description
-<p>
- This hook is called to notify the protocol instance about an interface
- acquiring or losing one of its addresses. The change is described by
- a combination of status bits (<const/IF_CHANGE_xxx/) in the <param/flags/ parameter.
-</function>
-<function><p><type>void</type>
-<funcdef>rt_notify</funcdef>
-(<type>struct proto *</type> <param>p</param>, <type>net *</type> <param>net</param>, <type>rte *</type> <param>new</param>, <type>rte *</type> <param>old</param>, <type>ea_list *</type> <param>attrs</param>) -- notify instance about routing table change
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>struct proto *</type> <param>p</param></tagp>
- protocol instance
-<tagp><type>net *</type> <param>net</param></tagp>
- a network entry
-<tagp><type>rte *</type> <param>new</param></tagp>
- new route for the network
-<tagp><type>rte *</type> <param>old</param></tagp>
- old route for the network
-<tagp><type>ea_list *</type> <param>attrs</param></tagp>
- extended attributes associated with the <param/new/ entry
-</descrip>
-<funcsect>Description
-<p>
- The <func/rt_notify()/ hook is called to inform the protocol instance about
- changes in the connected routing table <param/table/, that is a route <param/old/
- belonging to network <param/net/ being replaced by a new route <param/new/ with
- extended attributes <param/attrs/. Either <param/new/ or <param/old/ or both can be <const/NULL/
- if the corresponding route doesn't exist.
- <p>
- If the type of route announcement is RA_OPTIMAL, it is an
- announcement of optimal route change, <param/new/ stores the new optimal
- route and <param/old/ stores the old optimal route.
- <p>
- If the type of route announcement is RA_ANY, it is an announcement
- of any route change, <param/new/ stores the new route and <param/old/ stores the
- old route from the same protocol.
- <p>
- <param/p/-&gt;accept_ra_types specifies which kind of route announcements
- protocol wants to receive.
-</function>
-<function><p><type>void</type>
-<funcdef>neigh_notify</funcdef>
-(<type>neighbor *</type> <param>neigh</param>) -- notify instance about neighbor status change
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>neighbor *</type> <param>neigh</param></tagp>
- a neighbor cache entry
-</descrip>
-<funcsect>Description
-<p>
- The <func/neigh_notify()/ hook is called by the neighbor cache whenever
- a neighbor changes its state, that is it gets disconnected or a
- sticky neighbor gets connected.
-</function>
-<function><p><type>ea_list *</type>
-<funcdef>make_tmp_attrs</funcdef>
-(<type>rte *</type> <param>e</param>, <type>struct linpool *</type> <param>pool</param>) -- convert embedded attributes to temporary ones
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>rte *</type> <param>e</param></tagp>
- route entry
-<tagp><type>struct linpool *</type> <param>pool</param></tagp>
- linear pool to allocate attribute memory in
-</descrip>
-<funcsect>Description
-<p>
- This hook is called by the routing table functions if they need
- to convert the protocol attributes embedded directly in the <struct/rte/
- to temporary extended attributes in order to distribute them
- to other protocols or to filters. <func/make_tmp_attrs()/ creates
- an <struct/ea_list/ in the linear pool <param/pool/, fills it with values of the
- temporary attributes and returns a pointer to it.
-</function>
-<function><p><type>void</type>
-<funcdef>store_tmp_attrs</funcdef>
-(<type>rte *</type> <param>e</param>, <type>ea_list *</type> <param>attrs</param>) -- convert temporary attributes to embedded ones
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>rte *</type> <param>e</param></tagp>
- route entry
-<tagp><type>ea_list *</type> <param>attrs</param></tagp>
- temporary attributes to be converted
-</descrip>
-<funcsect>Description
-<p>
- This hook is an exact opposite of <func/make_tmp_attrs()/ -- it takes
- a list of extended attributes and converts them to attributes
- embedded in the <struct/rte/ corresponding to this protocol.
- <p>
- You must be prepared for any of the attributes being missing
- from the list and use default values instead.
-</function>
-<function><p><type>int</type>
-<funcdef>import_control</funcdef>
-(<type>struct proto *</type> <param>p</param>, <type>rte **</type> <param>e</param>, <type>ea_list **</type> <param>attrs</param>, <type>struct linpool *</type> <param>pool</param>) -- pre-filtering decisions on route import
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>struct proto *</type> <param>p</param></tagp>
- protocol instance the route is going to be imported to
-<tagp><type>rte **</type> <param>e</param></tagp>
- the route in question
-<tagp><type>ea_list **</type> <param>attrs</param></tagp>
- extended attributes of the route
-<tagp><type>struct linpool *</type> <param>pool</param></tagp>
- linear pool for allocation of all temporary data
-</descrip>
-<funcsect>Description
-<p>
- The <func/import_control()/ hook is called as the first step of a exporting
- a route from a routing table to the protocol instance. It can modify
- route attributes and force acceptance or rejection of the route regardless
- of user-specified filters. See <func/rte_announce()/ for a complete description
- of the route distribution process.
- <p>
- The standard use of this hook is to reject routes having originated
- from the same instance and to set default values of the protocol's metrics.
-<funcsect>Result
-<p>
- 1 if the route has to be accepted, -1 if rejected and 0 if it
- should be passed to the filters.
-</function>
-<function><p><type>int</type>
-<funcdef>rte_recalculate</funcdef>
-(<type>struct rtable *</type> <param>table</param>, <type>struct network *</type> <param>net</param>, <type>struct rte *</type> <param>new</param>, <type>struct rte *</type> <param>old</param>, <type>struct rte *</type> <param>old_best</param>) -- prepare routes for comparison
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>struct rtable *</type> <param>table</param></tagp>
- a routing table
-<tagp><type>struct network *</type> <param>net</param></tagp>
- a network entry
-<tagp><type>struct rte *</type> <param>new</param></tagp>
- new route for the network
-<tagp><type>struct rte *</type> <param>old</param></tagp>
- old route for the network
-<tagp><type>struct rte *</type> <param>old_best</param></tagp>
- old best route for the network (may be NULL)
-</descrip>
-<funcsect>Description
-<p>
- This hook is called when a route change (from <param/old/ to <param/new/ for a
- <param/net/ entry) is propagated to a <param/table/. It may be used to prepare
- routes for comparison by <func/rte_better()/ in the best route
- selection. <param/new/ may or may not be in <param/net/-&gt;routes list,
- <param/old/ is not there.
-<funcsect>Result
-<p>
- 1 if the ordering implied by <func/rte_better()/ changes enough
- that full best route calculation have to be done, 0 otherwise.
-</function>
-<function><p><type>int</type>
-<funcdef>rte_better</funcdef>
-(<type>rte *</type> <param>new</param>, <type>rte *</type> <param>old</param>) -- compare metrics of two routes
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>rte *</type> <param>new</param></tagp>
- the new route
-<tagp><type>rte *</type> <param>old</param></tagp>
- the original route
-</descrip>
-<funcsect>Description
-<p>
- This hook gets called when the routing table contains two routes
- for the same network which have originated from different instances
- of a single protocol and it wants to select which one is preferred
- over the other one. Protocols usually decide according to route metrics.
-<funcsect>Result
-<p>
- 1 if <param/new/ is better (more preferred) than <param/old/, 0 otherwise.
-</function>
-<function><p><type>int</type>
-<funcdef>rte_same</funcdef>
-(<type>rte *</type> <param>e1</param>, <type>rte *</type> <param>e2</param>) -- compare two routes
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>rte *</type> <param>e1</param></tagp>
- route
-<tagp><type>rte *</type> <param>e2</param></tagp>
- route
-</descrip>
-<funcsect>Description
-<p>
- The <func/rte_same()/ hook tests whether the routes <param/e1/ and <param/e2/ belonging
- to the same protocol instance have identical contents. Contents of
- <struct/rta/, all the extended attributes and <struct/rte/ preference are checked
- by the core code, no need to take care of them here.
-<funcsect>Result
-<p>
- 1 if <param/e1/ is identical to <param/e2/, 0 otherwise.
-</function>
-<function><p><type>void</type>
-<funcdef>rte_insert</funcdef>
-(<type>net *</type> <param>n</param>, <type>rte *</type> <param>e</param>) -- notify instance about route insertion
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>net *</type> <param>n</param></tagp>
- network
-<tagp><type>rte *</type> <param>e</param></tagp>
- route
-</descrip>
-<funcsect>Description
-<p>
- This hook is called whenever a <struct/rte/ belonging to the instance
- is accepted for insertion to a routing table.
- <p>
- Please avoid using this function in new protocols.
-</function>
-<function><p><type>void</type>
-<funcdef>rte_remove</funcdef>
-(<type>net *</type> <param>n</param>, <type>rte *</type> <param>e</param>) -- notify instance about route removal
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>net *</type> <param>n</param></tagp>
- network
-<tagp><type>rte *</type> <param>e</param></tagp>
- route
-</descrip>
-<funcsect>Description
-<p>
- This hook is called whenever a <struct/rte/ belonging to the instance
- is removed from a routing table.
- <p>
- Please avoid using this function in new protocols.
-</function>
-<sect>Interfaces
-<p>
- <p>
- The interface module keeps track of all network interfaces in the
- system and their addresses.
- <p>
- Each interface is represented by an <struct/iface/ structure which carries
- interface capability flags (<const/IF_MULTIACCESS/, <const/IF_BROADCAST/ etc.),
- MTU, interface name and index and finally a linked list of network
- prefixes assigned to the interface, each one represented by
- struct <struct/ifa/.
- <p>
- The interface module keeps a `soft-up' state for each <struct/iface/ which
- is a conjunction of link being up, the interface being of a `sane'
- type and at least one IP address assigned to it.
-
-
-<function><p><type>void</type>
-<funcdef>ifa_dump</funcdef>
-(<type>struct ifa *</type> <param>a</param>) -- dump interface address
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>struct ifa *</type> <param>a</param></tagp>
- interface address descriptor
-</descrip>
-<funcsect>Description
-<p>
- This function dumps contents of an <struct/ifa/ to the debug output.
-</function>
-<function><p><type>void</type>
-<funcdef>if_dump</funcdef>
-(<type>struct iface *</type> <param>i</param>) -- dump interface
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>struct iface *</type> <param>i</param></tagp>
- interface to dump
-</descrip>
-<funcsect>Description
-<p>
- This function dumps all information associated with a given
- network interface to the debug output.
-</function>
-<function><p><type>void</type>
-<funcdef>if_dump_all</funcdef>
-(<param>void</param>) -- dump all interfaces
-
-<funcsect>Description
-<p>
- <p>
- This function dumps information about all known network
- interfaces to the debug output.
-</function>
-<function><p><type>void</type>
-<funcdef>if_delete</funcdef>
-(<type>struct iface *</type> <param>old</param>) -- remove interface
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>struct iface *</type> <param>old</param></tagp>
- interface
-</descrip>
-<funcsect>Description
-<p>
- This function is called by the low-level platform dependent code
- whenever it notices an interface disappears. It is just a shorthand
- for <func/if_update()/.
-</function>
-<function><p><type>struct iface *</type>
-<funcdef>if_update</funcdef>
-(<type>struct iface *</type> <param>new</param>) -- update interface status
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>struct iface *</type> <param>new</param></tagp>
- new interface status
-</descrip>
-<funcsect>Description
-<p>
- <func/if_update()/ is called by the low-level platform dependent code
- whenever it notices an interface change.
- <p>
- There exist two types of interface updates -- synchronous and asynchronous
- ones. In the synchronous case, the low-level code calls <func/if_start_update()/,
- scans all interfaces reported by the OS, uses <func/if_update()/ and <func/ifa_update()/
- to pass them to the core and then it finishes the update sequence by
- calling <func/if_end_update()/. When working asynchronously, the sysdep code
- calls <func/if_update()/ and <func/ifa_update()/ whenever it notices a change.
- <p>
- <func/if_update()/ will automatically notify all other modules about the change.
-</function>
-<function><p><type>void</type>
-<funcdef>if_feed_baby</funcdef>
-(<type>struct proto *</type> <param>p</param>) -- advertise interfaces to a new protocol
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>struct proto *</type> <param>p</param></tagp>
- protocol to feed
-</descrip>
-<funcsect>Description
-<p>
- When a new protocol starts, this function sends it a series
- of notifications about all existing interfaces.
-</function>
-<function><p><type>struct iface *</type>
-<funcdef>if_find_by_index</funcdef>
-(<type>unsigned</type> <param>idx</param>) -- find interface by ifindex
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>unsigned</type> <param>idx</param></tagp>
- ifindex
-</descrip>
-<funcsect>Description
-<p>
- This function finds an <struct/iface/ structure corresponding to an interface
- of the given index <param/idx/. Returns a pointer to the structure or <const/NULL/
- if no such structure exists.
-</function>
-<function><p><type>struct iface *</type>
-<funcdef>if_find_by_name</funcdef>
-(<type>char *</type> <param>name</param>) -- find interface by name
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>char *</type> <param>name</param></tagp>
- interface name
-</descrip>
-<funcsect>Description
-<p>
- This function finds an <struct/iface/ structure corresponding to an interface
- of the given name <param/name/. Returns a pointer to the structure or <const/NULL/
- if no such structure exists.
-</function>
-<function><p><type>struct ifa *</type>
-<funcdef>ifa_update</funcdef>
-(<type>struct ifa *</type> <param>a</param>) -- update interface address
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>struct ifa *</type> <param>a</param></tagp>
- new interface address
-</descrip>
-<funcsect>Description
-<p>
- This function adds address information to a network
- interface. It's called by the platform dependent code during
- the interface update process described under <func/if_update()/.
-</function>
-<function><p><type>void</type>
-<funcdef>ifa_delete</funcdef>
-(<type>struct ifa *</type> <param>a</param>) -- remove interface address
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>struct ifa *</type> <param>a</param></tagp>
- interface address
-</descrip>
-<funcsect>Description
-<p>
- This function removes address information from a network
- interface. It's called by the platform dependent code during
- the interface update process described under <func/if_update()/.
-</function>
-<function><p><type>void</type>
-<funcdef>if_init</funcdef>
-(<param>void</param>) -- initialize interface module
-
-<funcsect>Description
-<p>
- <p>
- This function is called during BIRD startup to initialize
- all data structures of the interface module.
-</function>
-<sect>Neighbor cache
-<p>
- <p>
- Most routing protocols need to associate their internal state data with
- neighboring routers, check whether an address given as the next hop
- attribute of a route is really an address of a directly connected host
- and which interface is it connected through. Also, they often need to
- be notified when a neighbor ceases to exist or when their long awaited
- neighbor becomes connected. The neighbor cache is there to solve all
- these problems.
- <p>
- The neighbor cache maintains a collection of neighbor entries. Each
- entry represents one IP address corresponding to either our directly
- connected neighbor or our own end of the link (when the scope of the
- address is set to <const/SCOPE_HOST/) together with per-neighbor data belonging to a
- single protocol.
- <p>
- Active entries represent known neighbors and are stored in a hash
- table (to allow fast retrieval based on the IP address of the node) and
- two linked lists: one global and one per-interface (allowing quick
- processing of interface change events). Inactive entries exist only
- when the protocol has explicitly requested it via the <const/NEF_STICKY/
- flag because it wishes to be notified when the node will again become
- a neighbor. Such entries are enqueued in a special list which is walked
- whenever an interface changes its state to up. Neighbor entry VRF
- association is implied by respective protocol.
- <p>
- When a neighbor event occurs (a neighbor gets disconnected or a sticky
- inactive neighbor becomes connected), the protocol hook <func/neigh_notify()/
- is called to advertise the change.
-
-
-<function><p><type>neighbor *</type>
-<funcdef>neigh_find</funcdef>
-(<type>struct proto *</type> <param>p</param>, <type>ip_addr *</type> <param>a</param>, <type>unsigned</type> <param>flags</param>) -- find or create a neighbor entry.
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>struct proto *</type> <param>p</param></tagp>
- protocol which asks for the entry.
-<tagp><type>ip_addr *</type> <param>a</param></tagp>
- pointer to IP address of the node to be searched for.
-<tagp><type>unsigned</type> <param>flags</param></tagp>
- 0 or <const/NEF_STICKY/ if you want to create a sticky entry.
-</descrip>
-<funcsect>Description
-<p>
- Search the neighbor cache for a node with given IP address. If
- it's found, a pointer to the neighbor entry is returned. If no
- such entry exists and the node is directly connected on
- one of our active interfaces, a new entry is created and returned
- to the caller with protocol-dependent fields initialized to zero.
- If the node is not connected directly or *<param/a/ is not a valid unicast
- IP address, <func/neigh_find()/ returns <const/NULL/.
-</function>
-<function><p><type>void</type>
-<funcdef>neigh_dump</funcdef>
-(<type>neighbor *</type> <param>n</param>) -- dump specified neighbor entry.
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>neighbor *</type> <param>n</param></tagp>
- the entry to dump
-</descrip>
-<funcsect>Description
-<p>
- This functions dumps the contents of a given neighbor entry
- to debug output.
-</function>
-<function><p><type>void</type>
-<funcdef>neigh_dump_all</funcdef>
-(<param>void</param>) -- dump all neighbor entries.
-
-<funcsect>Description
-<p>
- <p>
- This function dumps the contents of the neighbor cache to
- debug output.
-</function>
-<function><p><type>void</type>
-<funcdef>neigh_if_up</funcdef>
-(<type>struct iface *</type> <param>i</param>)
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>struct iface *</type> <param>i</param></tagp>
- interface in question
-</descrip>
-<funcsect>Description
-<p>
- Tell the neighbor cache that a new interface became up.
- <p>
- The neighbor cache wakes up all inactive sticky neighbors with
- addresses belonging to prefixes of the interface <param/i/.
-</function>
-<function><p><type>void</type>
-<funcdef>neigh_if_down</funcdef>
-(<type>struct iface *</type> <param>i</param>) -- notify neighbor cache about interface down event
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>struct iface *</type> <param>i</param></tagp>
- the interface in question
-</descrip>
-<funcsect>Description
-<p>
- Notify the neighbor cache that an interface has ceased to exist.
- <p>
- It causes all entries belonging to neighbors connected to this interface
- to be flushed.
-</function>
-<function><p><type>void</type>
-<funcdef>neigh_if_link</funcdef>
-(<type>struct iface *</type> <param>i</param>) -- notify neighbor cache about interface link change
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>struct iface *</type> <param>i</param></tagp>
- the interface in question
-</descrip>
-<funcsect>Description
-<p>
- Notify the neighbor cache that an interface changed link state.
- All owners of neighbor entries connected to this interface are
- notified.
-</function>
-<function><p><type>void</type>
-<funcdef>neigh_ifa_update</funcdef>
-(<type>struct ifa *</type> <param>a</param>)
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>struct ifa *</type> <param>a</param></tagp>
- interface address in question
-</descrip>
-<funcsect>Description
-<p>
- Tell the neighbor cache that an address was added or removed.
- <p>
- The neighbor cache wakes up all inactive sticky neighbors with
- addresses belonging to prefixes of the interface belonging to <param/ifa/
- and causes all unreachable neighbors to be flushed.
-</function>
-<function><p><type>void</type>
-<funcdef>neigh_prune</funcdef>
-(<param>void</param>) -- prune neighbor cache
-
-<funcsect>Description
-<p>
- <p>
- <func/neigh_prune()/ examines all neighbor entries cached and removes those
- corresponding to inactive protocols. It's called whenever a protocol
- is shut down to get rid of all its heritage.
-</function>
-<function><p><type>void</type>
-<funcdef>neigh_init</funcdef>
-(<type>pool *</type> <param>if_pool</param>) -- initialize the neighbor cache.
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>pool *</type> <param>if_pool</param></tagp>
- resource pool to be used for neighbor entries.
-</descrip>
-<funcsect>Description
-<p>
- This function is called during BIRD startup to initialize
- the neighbor cache module.
-</function>
-<sect>Command line interface
-<p>
- <p>
- This module takes care of the BIRD's command-line interface (CLI).
- The CLI exists to provide a way to control BIRD remotely and to inspect
- its status. It uses a very simple textual protocol over a stream
- connection provided by the platform dependent code (on UNIX systems,
- it's a UNIX domain socket).
- <p>
- Each session of the CLI consists of a sequence of request and replies,
- slightly resembling the FTP and SMTP protocols.
- Requests are commands encoded as a single line of text, replies are
- sequences of lines starting with a four-digit code followed by either
- a space (if it's the last line of the reply) or a minus sign (when the
- reply is going to continue with the next line), the rest of the line
- contains a textual message semantics of which depends on the numeric
- code. If a reply line has the same code as the previous one and it's
- a continuation line, the whole prefix can be replaced by a single
- white space character.
- <p>
- Reply codes starting with 0 stand for `action successfully completed' messages,
- 1 means `table entry', 8 `runtime error' and 9 `syntax error'.
- <p>
- Each CLI session is internally represented by a <struct/cli/ structure and a
- resource pool containing all resources associated with the connection,
- so that it can be easily freed whenever the connection gets closed, not depending
- on the current state of command processing.
- <p>
- The CLI commands are declared as a part of the configuration grammar
- by using the <tt>CF_CLI</tt> macro. When a command is received, it is processed
- by the same lexical analyzer and parser as used for the configuration, but
- it's switched to a special mode by prepending a fake token to the text,
- so that it uses only the CLI command rules. Then the parser invokes
- an execution routine corresponding to the command, which either constructs
- the whole reply and returns it back or (in case it expects the reply will be long)
- it prints a partial reply and asks the CLI module (using the <param/cont/ hook)
- to call it again when the output is transferred to the user.
- <p>
- The <param/this_cli/ variable points to a <struct/cli/ structure of the session being
- currently parsed, but it's of course available only in command handlers
- not entered using the <param/cont/ hook.
- <p>
- TX buffer management works as follows: At cli.tx_buf there is a
- list of TX buffers (struct cli_out), cli.tx_write is the buffer
- currently used by the producer (<func/cli_printf()/, <func/cli_alloc_out()/) and
- cli.tx_pos is the buffer currently used by the consumer
- (<func/cli_write()/, in system dependent code). The producer uses
- cli_out.wpos ptr as the current write position and the consumer
- uses cli_out.outpos ptr as the current read position. When the
- producer produces something, it calls <func/cli_write_trigger()/. If there
- is not enough space in the current buffer, the producer allocates
- the new one. When the consumer processes everything in the buffer
- queue, it calls <func/cli_written()/, tha frees all buffers (except the
- first one) and schedules cli.event .
-
-
-<function><p><type>void</type>
-<funcdef>cli_printf</funcdef>
-(<type>cli *</type> <param>c</param>, <type>int</type> <param>code</param>, <type>char *</type> <param>msg</param>, <type>...</type> <param>...</param>) -- send reply to a CLI connection
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>cli *</type> <param>c</param></tagp>
- CLI connection
-<tagp><type>int</type> <param>code</param></tagp>
- numeric code of the reply, negative for continuation lines
-<tagp><type>char *</type> <param>msg</param></tagp>
- a <func/printf()/-like formatting string.
-<tagp><type>...</type> <param>...</param></tagp>
- variable arguments
-</descrip>
-<funcsect>Description
-<p>
- This function send a single line of reply to a given CLI connection.
- In works in all aspects like <func/bsprintf()/ except that it automatically
- prepends the reply line prefix.
- <p>
- Please note that if the connection can be already busy sending some
- data in which case <func/cli_printf()/ stores the output to a temporary buffer,
- so please avoid sending a large batch of replies without waiting
- for the buffers to be flushed.
- <p>
- If you want to write to the current CLI output, you can use the <func/cli_msg()/
- macro instead.
-</function>
-<function><p><type>void</type>
-<funcdef>cli_init</funcdef>
-(<param>void</param>) -- initialize the CLI module
-
-<funcsect>Description
-<p>
- <p>
- This function is called during BIRD startup to initialize
- the internal data structures of the CLI module.
-</function>
-<sect>Object locks
-<p>
- <p>
- The lock module provides a simple mechanism for avoiding conflicts between
- various protocols which would like to use a single physical resource (for
- example a network port). It would be easy to say that such collisions can
- occur only when the user specifies an invalid configuration and therefore
- he deserves to get what he has asked for, but unfortunately they can also
- arise legitimately when the daemon is reconfigured and there exists (although
- for a short time period only) an old protocol instance being shut down and a new one
- willing to start up on the same interface.
- <p>
- The solution is very simple: when any protocol wishes to use a network port
- or some other non-shareable resource, it asks the core to lock it and it doesn't
- use the resource until it's notified that it has acquired the lock.
- <p>
- Object locks are represented by <struct/object_lock/ structures which are in turn a
- kind of resource. Lockable resources are uniquely determined by resource type
- (<const/OBJLOCK_UDP/ for a UDP port etc.), IP address (usually a broadcast or
- multicast address the port is bound to), port number, interface and optional
- instance ID.
-
-
-<function><p><type>struct object_lock *</type>
-<funcdef>olock_new</funcdef>
-(<type>pool *</type> <param>p</param>) -- create an object lock
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>pool *</type> <param>p</param></tagp>
- resource pool to create the lock in.
-</descrip>
-<funcsect>Description
-<p>
- The <func/olock_new()/ function creates a new resource of type <struct/object_lock/
- and returns a pointer to it. After filling in the structure, the caller
- should call <func/olock_acquire()/ to do the real locking.
-</function>
-<function><p><type>void</type>
-<funcdef>olock_acquire</funcdef>
-(<type>struct object_lock *</type> <param>l</param>) -- acquire a lock
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>struct object_lock *</type> <param>l</param></tagp>
- the lock to acquire
-</descrip>
-<funcsect>Description
-<p>
- This function attempts to acquire exclusive access to the non-shareable
- resource described by the lock <param/l/. It returns immediately, but as soon
- as the resource becomes available, it calls the <func/hook()/ function set up
- by the caller.
- <p>
- When you want to release the resource, just <func/rfree()/ the lock.
-</function>
-<function><p><type>void</type>
-<funcdef>olock_init</funcdef>
-(<param>void</param>) -- initialize the object lock mechanism
-
-<funcsect>Description
-<p>
- <p>
- This function is called during BIRD startup. It initializes
- all the internal data structures of the lock module.
-</function>
-<chapt>Configuration
-<sect>Configuration manager
-<p>
- <p>
- Configuration of BIRD is complex, yet straightforward. There are three
- modules taking care of the configuration: config manager (which takes care
- of storage of the config information and controls switching between configs),
- lexical analyzer and parser.
- <p>
- The configuration manager stores each config as a <struct/config/ structure
- accompanied by a linear pool from which all information associated
- with the config and pointed to by the <struct/config/ structure is allocated.
- <p>
- There can exist up to four different configurations at one time: an active
- one (pointed to by <param/config/), configuration we are just switching from
- (<param/old_config/), one queued for the next reconfiguration (<param/future_config/; if
- there is one and the user wants to reconfigure once again, we just free the
- previous queued config and replace it with the new one) and finally a config
- being parsed (<param/new_config/). The stored <param/old_config/ is also used for undo
- reconfiguration, which works in a similar way. Reconfiguration could also
- have timeout (using <param/config_timer/) and undo is automatically called if the
- new configuration is not confirmed later. The new config (<param/new_config/) and
- associated linear pool (<param/cfg_mem/) is non-NULL only during parsing.
- <p>
- Loading of new configuration is very simple: just call <func/config_alloc()/ to get
- a new <struct/config/ structure, then use <func/config_parse()/ to parse a configuration
- file and fill all fields of the structure and finally ask the config manager
- to switch to the new config by calling <func/config_commit()/.
- <p>
- CLI commands are parsed in a very similar way -- there is also a stripped-down
- <struct/config/ structure associated with them and they are lex-ed and parsed by the
- same functions, only a special fake token is prepended before the command
- text to make the parser recognize only the rules corresponding to CLI commands.
-
-
-<function><p><type>struct config *</type>
-<funcdef>config_alloc</funcdef>
-(<type>const byte *</type> <param>name</param>) -- allocate a new configuration
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>const byte *</type> <param>name</param></tagp>
- name of the config
-</descrip>
-<funcsect>Description
-<p>
- This function creates new <struct/config/ structure, attaches a resource
- pool and a linear memory pool to it and makes it available for
- further use. Returns a pointer to the structure.
-</function>
-<function><p><type>int</type>
-<funcdef>config_parse</funcdef>
-(<type>struct config *</type> <param>c</param>) -- parse a configuration
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>struct config *</type> <param>c</param></tagp>
- configuration
-</descrip>
-<funcsect>Description
-<p>
- <func/config_parse()/ reads input by calling a hook function pointed to
- by <param/cf_read_hook/ and parses it according to the configuration
- grammar. It also calls all the preconfig and postconfig hooks
- before, resp. after parsing.
-<funcsect>Result
-<p>
- 1 if the config has been parsed successfully, 0 if any
- error has occurred (such as anybody calling <func/cf_error()/) and
- the <param/err_msg/ field has been set to the error message.
-</function>
-<function><p><type>int</type>
-<funcdef>cli_parse</funcdef>
-(<type>struct config *</type> <param>c</param>) -- parse a CLI command
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>struct config *</type> <param>c</param></tagp>
- temporary config structure
-</descrip>
-<funcsect>Description
-<p>
- <func/cli_parse()/ is similar to <func/config_parse()/, but instead of a configuration,
- it parses a CLI command. See the CLI module for more information.
-</function>
-<function><p><type>void</type>
-<funcdef>config_free</funcdef>
-(<type>struct config *</type> <param>c</param>) -- free a configuration
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>struct config *</type> <param>c</param></tagp>
- configuration to be freed
-</descrip>
-<funcsect>Description
-<p>
- This function takes a <struct/config/ structure and frees all resources
- associated with it.
-</function>
-<function><p><type>int</type>
-<funcdef>config_commit</funcdef>
-(<type>struct config *</type> <param>c</param>, <type>int</type> <param>type</param>, <type>int</type> <param>timeout</param>) -- commit a configuration
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>struct config *</type> <param>c</param></tagp>
- new configuration
-<tagp><type>int</type> <param>type</param></tagp>
- type of reconfiguration (RECONFIG_SOFT or RECONFIG_HARD)
-<tagp><type>int</type> <param>timeout</param></tagp>
- timeout for undo (or 0 for no timeout)
-</descrip>
-<funcsect>Description
-<p>
- When a configuration is parsed and prepared for use, the
- <func/config_commit()/ function starts the process of reconfiguration.
- It checks whether there is already a reconfiguration in progress
- in which case it just queues the new config for later processing.
- Else it notifies all modules about the new configuration by calling
- their <func/commit()/ functions which can either accept it immediately
- or call <func/config_add_obstacle()/ to report that they need some time
- to complete the reconfiguration. After all such obstacles are removed
- using <func/config_del_obstacle()/, the old configuration is freed and
- everything runs according to the new one.
- <p>
- When <param/timeout/ is nonzero, the undo timer is activated with given
- timeout. The timer is deactivated when <func/config_commit()/,
- <func/config_confirm()/ or <func/config_undo()/ is called.
-<funcsect>Result
-<p>
- <const/CONF_DONE/ if the configuration has been accepted immediately,
- <const/CONF_PROGRESS/ if it will take some time to switch to it, <const/CONF_QUEUED/
- if it's been queued due to another reconfiguration being in progress now
- or <const/CONF_SHUTDOWN/ if BIRD is in shutdown mode and no new configurations
- are accepted.
-</function>
-<function><p><type>int</type>
-<funcdef>config_confirm</funcdef>
-(<param>void</param>) -- confirm a commited configuration
-
-<funcsect>Description
-<p>
- <p>
- When the undo timer is activated by <func/config_commit()/ with nonzero timeout,
- this function can be used to deactivate it and therefore confirm
- the current configuration.
-<funcsect>Result
-<p>
- <const/CONF_CONFIRM/ when the current configuration is confirmed,
- <const/CONF_NONE/ when there is nothing to confirm (i.e. undo timer is not active).
-</function>
-<function><p><type>int</type>
-<funcdef>config_undo</funcdef>
-(<param>void</param>) -- undo a configuration
-
-<funcsect>Description
-<p>
- <p>
- Function <func/config_undo()/ can be used to change the current
- configuration back to stored <const/old_config/. If no reconfiguration is
- running, this stored configuration is commited in the same way as a
- new configuration in <func/config_commit()/. If there is already a
- reconfiguration in progress and no next reconfiguration is
- scheduled, then the undo is scheduled for later processing as
- usual, but if another reconfiguration is already scheduled, then
- such reconfiguration is removed instead (i.e. undo is applied on
- the last commit that scheduled it).
-<funcsect>Result
-<p>
- <const/CONF_DONE/ if the configuration has been accepted immediately,
- <const/CONF_PROGRESS/ if it will take some time to switch to it, <const/CONF_QUEUED/
- if it's been queued due to another reconfiguration being in progress now,
- <const/CONF_UNQUEUED/ if a scheduled reconfiguration is removed, <const/CONF_NOTHING/
- if there is no relevant configuration to undo (the previous config request
- was <func/config_undo()/ too) or <const/CONF_SHUTDOWN/ if BIRD is in shutdown mode and
- no new configuration changes are accepted.
-</function>
-<function><p><type>void</type>
-<funcdef>order_shutdown</funcdef>
-(<param>void</param>) -- order BIRD shutdown
-
-<funcsect>Description
-<p>
- <p>
- This function initiates shutdown of BIRD. It's accomplished by asking
- for switching to an empty configuration.
-</function>
-<function><p><type>void</type>
-<funcdef>cf_error</funcdef>
-(<type>char *</type> <param>msg</param>, <type>...</type> <param>...</param>) -- report a configuration error
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>char *</type> <param>msg</param></tagp>
- printf-like format string
-<tagp><type>...</type> <param>...</param></tagp>
- variable arguments
-</descrip>
-<funcsect>Description
-<p>
- <func/cf_error()/ can be called during execution of <func/config_parse()/, that is
- from the parser, a preconfig hook or a postconfig hook, to report an
- error in the configuration.
-</function>
-<function><p><type>char *</type>
-<funcdef>cfg_strdup</funcdef>
-(<type>const char *</type> <param>c</param>) -- copy a string to config memory
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>const char *</type> <param>c</param></tagp>
- string to copy
-</descrip>
-<funcsect>Description
-<p>
- <func/cfg_strdup()/ creates a new copy of the string in the memory
- pool associated with the configuration being currently parsed.
- It's often used when a string literal occurs in the configuration
- and we want to preserve it for further use.
-</function>
-<sect>Lexical analyzer
-<p>
- <p>
- The lexical analyzer used for configuration files and CLI commands
- is generated using the <tt>flex</tt> tool accompanied by a couple of
- functions maintaining the hash tables containing information about
- symbols and keywords.
- <p>
- Each symbol is represented by a <struct/symbol/ structure containing name
- of the symbol, its lexical scope, symbol class (<const/SYM_PROTO/ for a
- name of a protocol, <const/SYM_CONSTANT/ for a constant etc.) and class
- dependent data. When an unknown symbol is encountered, it's
- automatically added to the symbol table with class <const/SYM_VOID/.
- <p>
- The keyword tables are generated from the grammar templates
- using the <tt>gen_keywords.m4</tt> script.
-
-
-<function><p><type>void</type>
-<funcdef>cf_lex_unwind</funcdef>
-(<param>void</param>) -- unwind lexer state during error
-
-<funcsect>Lexical analyzer
-<p>
- <p>
- <func/cf_lex_unwind()/ frees the internal state on IFS stack when the lexical
- analyzer is terminated by <func/cf_error()/.
-</function>
-<function><p><type>struct symbol *</type>
-<funcdef>cf_find_symbol</funcdef>
-(<type>struct config *</type> <param>cfg</param>, <type>byte *</type> <param>c</param>) -- find a symbol by name
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>struct config *</type> <param>cfg</param></tagp>
- specificed config
-<tagp><type>byte *</type> <param>c</param></tagp>
- symbol name
-</descrip>
-<funcsect>Description
-<p>
- This functions searches the symbol table in the config <param/cfg/ for a symbol of
- given name. First it examines the current scope, then the second recent one
- and so on until it either finds the symbol and returns a pointer to its
- <struct/symbol/ structure or reaches the end of the scope chain and returns <const/NULL/ to
- signify no match.
-</function>
-<function><p><type>struct symbol *</type>
-<funcdef>cf_get_symbol</funcdef>
-(<type>byte *</type> <param>c</param>) -- get a symbol by name
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>byte *</type> <param>c</param></tagp>
- symbol name
-</descrip>
-<funcsect>Description
-<p>
- This functions searches the symbol table of the currently parsed config
- (<param/new_config/) for a symbol of given name. It returns either the already
- existing symbol or a newly allocated undefined (<const/SYM_VOID/) symbol if no
- existing symbol is found.
-</function>
-<function><p><type>struct symbol *</type>
-<funcdef>cf_define_symbol</funcdef>
-(<type>struct symbol *</type> <param>sym</param>, <type>int</type> <param>type</param>, <type>void *</type> <param>def</param>) -- define meaning of a symbol
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>struct symbol *</type> <param>sym</param></tagp>
- symbol to be defined
-<tagp><type>int</type> <param>type</param></tagp>
- symbol class to assign
-<tagp><type>void *</type> <param>def</param></tagp>
- class dependent data
-</descrip>
-<funcsect>Description
-<p>
- Defines new meaning of a symbol. If the symbol is an undefined
- one (<const/SYM_VOID/), it's just re-defined to the new type. If it's defined
- in different scope, a new symbol in current scope is created and the
- meaning is assigned to it. If it's already defined in the current scope,
- an error is reported via <func/cf_error()/.
-<funcsect>Result
-<p>
- Pointer to the newly defined symbol. If we are in the top-level
- scope, it's the same <param/sym/ as passed to the function.
-</function>
-<function><p><type>void</type>
-<funcdef>cf_lex_init</funcdef>
-(<type>int</type> <param>is_cli</param>, <type>struct config *</type> <param>c</param>) -- initialize the lexer
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>int</type> <param>is_cli</param></tagp>
- true if we're going to parse CLI command, false for configuration
-<tagp><type>struct config *</type> <param>c</param></tagp>
- configuration structure
-</descrip>
-<funcsect>Description
-<p>
- <func/cf_lex_init()/ initializes the lexical analyzer and prepares it for
- parsing of a new input.
-</function>
-<function><p><type>void</type>
-<funcdef>cf_push_scope</funcdef>
-(<type>struct symbol *</type> <param>sym</param>) -- enter new scope
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>struct symbol *</type> <param>sym</param></tagp>
- symbol representing scope name
-</descrip>
-<funcsect>Description
-<p>
- If we want to enter a new scope to process declarations inside
- a nested block, we can just call <func/cf_push_scope()/ to push a new
- scope onto the scope stack which will cause all new symbols to be
- defined in this scope and all existing symbols to be sought for
- in all scopes stored on the stack.
-</function>
-<function><p><type>void</type>
-<funcdef>cf_pop_scope</funcdef>
-(<param>void</param>) -- leave a scope
-
-<funcsect>Description
-<p>
- <p>
- <func/cf_pop_scope()/ pops the topmost scope from the scope stack,
- leaving all its symbols in the symbol table, but making them
- invisible to the rest of the config.
-</function>
-<function><p><type>char *</type>
-<funcdef>cf_symbol_class_name</funcdef>
-(<type>struct symbol *</type> <param>sym</param>) -- get name of a symbol class
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>struct symbol *</type> <param>sym</param></tagp>
- symbol
-</descrip>
-<funcsect>Description
-<p>
- This function returns a string representing the class
- of the given symbol.
-</function>
-<sect>Parser
-<p>
- <p>
- Both the configuration and CLI commands are analyzed using a syntax
- driven parser generated by the <tt>bison</tt> tool from a grammar which
- is constructed from information gathered from grammar snippets by
- the <tt>gen_parser.m4</tt> script.
- <p>
- Grammar snippets are files (usually with extension <tt>.Y</tt>) contributed
- by various BIRD modules in order to provide information about syntax of their
- configuration and their CLI commands. Each snipped consists of several
- sections, each of them starting with a special keyword: <tt>CF_HDR</tt> for
- a list of <tt>#include</tt> directives needed by the C code, <tt>CF_DEFINES</tt>
- for a list of C declarations, <tt>CF_DECLS</tt> for <tt>bison</tt> declarations
- including keyword definitions specified as <tt>CF_KEYWORDS</tt>, <tt>CF_GRAMMAR</tt>
- for the grammar rules, <tt>CF_CODE</tt> for auxiliary C code and finally
- <tt>CF_END</tt> at the end of the snippet.
- <p>
- To create references between the snippets, it's possible to define
- multi-part rules by utilizing the <tt>CF_ADDTO</tt> macro which adds a new
- alternative to a multi-part rule.
- <p>
- CLI commands are defined using a <tt>CF_CLI</tt> macro. Its parameters are:
- the list of keywords determining the command, the list of parameters,
- help text for the parameters and help text for the command.
- <p>
- Values of <tt>enum</tt> filter types can be defined using <tt>CF_ENUM</tt> with
- the following parameters: name of filter type, prefix common for all
- literals of this type and names of all the possible values.
-
-
-<chapt>Filters
-<sect>Filters
-<p>
- <p>
- You can find sources of the filter language in <tt>filter/</tt>
- directory. File <tt>filter/config.Y</tt> contains filter grammar and basically translates
- the source from user into a tree of <struct/f_inst/ structures. These trees are
- later interpreted using code in <tt>filter/filter.c</tt>.
- <p>
- A filter is represented by a tree of <struct/f_inst/ structures, one structure per
- "instruction". Each <struct/f_inst/ contains <param/code/, <param/aux/ value which is
- usually the data type this instruction operates on and two generic
- arguments (<param/a1/, <param/a2/). Some instructions contain pointer(s) to other
- instructions in their (<param/a1/, <param/a2/) fields.
- <p>
- Filters use a <struct/f_val/ structure for their data. Each <struct/f_val/
- contains type and value (types are constants prefixed with <const/T_/). Few
- of the types are special; <const/T_RETURN/ can be or-ed with a type to indicate
- that return from a function or from the whole filter should be
- forced. Important thing about <struct/f_val/'s is that they may be copied
- with a simple <tt>=</tt>. That's fine for all currently defined types: strings
- are read-only (and therefore okay), paths are copied for each
- operation (okay too).
-
-
-<function><p><type>int</type>
-<funcdef>val_compare</funcdef>
-(<type>struct f_val</type> <param>v1</param>, <type>struct f_val</type> <param>v2</param>) -- compare two values
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>struct f_val</type> <param>v1</param></tagp>
- first value
-<tagp><type>struct f_val</type> <param>v2</param></tagp>
- second value
-</descrip>
-<funcsect>Description
-<p>
- Compares two values and returns -1, 0, 1 on &lt;, =, &gt; or CMP_ERROR on
- error. Tree module relies on this giving consistent results so
- that it can be used for building balanced trees.
-</function>
-<function><p><type>int</type>
-<funcdef>val_same</funcdef>
-(<type>struct f_val</type> <param>v1</param>, <type>struct f_val</type> <param>v2</param>) -- compare two values
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>struct f_val</type> <param>v1</param></tagp>
- first value
-<tagp><type>struct f_val</type> <param>v2</param></tagp>
- second value
-</descrip>
-<funcsect>Description
-<p>
- Compares two values and returns 1 if they are same and 0 if not.
- Comparison of values of different types is valid and returns 0.
-</function>
-<function><p><type>int</type>
-<funcdef>val_in_range</funcdef>
-(<type>struct f_val</type> <param>v1</param>, <type>struct f_val</type> <param>v2</param>) -- implement <tt>~</tt> operator
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>struct f_val</type> <param>v1</param></tagp>
- element
-<tagp><type>struct f_val</type> <param>v2</param></tagp>
- set
-</descrip>
-<funcsect>Description
-<p>
- Checks if <param/v1/ is element (<tt>~</tt> operator) of <param/v2/.
-</function>
-<function><p><type>struct f_val</type>
-<funcdef>interpret</funcdef>
-(<type>struct f_inst *</type> <param>what</param>)
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>struct f_inst *</type> <param>what</param></tagp>
- filter to interpret
-</descrip>
-<funcsect>Description
-<p>
- Interpret given tree of filter instructions. This is core function
- of filter system and does all the hard work.
-<funcsect>Each instruction has 4 fields
-<p>
- code (which is instruction code),
- aux (which is extension to instruction code, typically type),
- arg1 and arg2 - arguments. Depending on instruction, arguments
- are either integers, or pointers to instruction trees. Common
- instructions like +, that have two expressions as arguments use
- TWOARGS macro to get both of them evaluated.
- <p>
- <struct/f_val/ structures are copied around, so there are no problems with
- memory managment.
-</function>
-<function><p><type>int</type>
-<funcdef>f_run</funcdef>
-(<type>struct filter *</type> <param>filter</param>, <type>struct rte **</type> <param>rte</param>, <type>struct ea_list **</type> <param>tmp_attrs</param>, <type>struct linpool *</type> <param>tmp_pool</param>, <type>int</type> <param>flags</param>) -- run a filter for a route
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>struct filter *</type> <param>filter</param></tagp>
- filter to run
-<tagp><type>struct rte **</type> <param>rte</param></tagp>
- route being filtered, may be modified
-<tagp><type>struct ea_list **</type> <param>tmp_attrs</param></tagp>
- temporary attributes, prepared by caller or generated by <func/f_run()/
-<tagp><type>struct linpool *</type> <param>tmp_pool</param></tagp>
- all filter allocations go from this pool
-<tagp><type>int</type> <param>flags</param></tagp>
- flags
-</descrip>
-<funcsect>Description
-<p>
- If filter needs to modify the route, there are several
- posibilities. <param/rte/ might be read-only (with REF_COW flag), in that
- case rw copy is obtained by <func/rte_cow()/ and <param/rte/ is replaced. If
- <param/rte/ is originally rw, it may be directly modified (and it is never
- copied).
- <p>
- The returned rte may reuse the (possibly cached, cloned) rta, or
- (if rta was modificied) contains a modified uncached rta, which
- uses parts allocated from <param/tmp_pool/ and parts shared from original
- rta. There is one exception - if <param/rte/ is rw but contains a cached
- rta and that is modified, rta in returned rte is also cached.
- <p>
- Ownership of cached rtas is consistent with rte, i.e.
- if a new rte is returned, it has its own clone of cached rta
- (and cached rta of read-only source rte is intact), if rte is
- modified in place, old cached rta is possibly freed.
-</function>
-<function><p><type>int</type>
-<funcdef>filter_same</funcdef>
-(<type>struct filter *</type> <param>new</param>, <type>struct filter *</type> <param>old</param>) -- compare two filters
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>struct filter *</type> <param>new</param></tagp>
- first filter to be compared
-<tagp><type>struct filter *</type> <param>old</param></tagp>
- second filter to be compared, notice that this filter is
- damaged while comparing.
-</descrip>
-<funcsect>Description
-<p>
- Returns 1 in case filters are same, otherwise 0. If there are
- underlying bugs, it will rather say 0 on same filters than say
- 1 on different.
-</function>
-<function><p><type>struct f_tree *</type>
-<funcdef>find_tree</funcdef>
-(<type>struct f_tree *</type> <param>t</param>, <type>struct f_val</type> <param>val</param>)
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>struct f_tree *</type> <param>t</param></tagp>
- tree to search in
-<tagp><type>struct f_val</type> <param>val</param></tagp>
- value to find
-</descrip>
-<funcsect>Description
-<p>
-Search for given value in the tree. I relies on fact that sorted tree is populated
-by <struct/f_val/ structures (that can be compared by <func/val_compare()/). In each node of tree,
-either single value (then t-&gt;from==t-&gt;to) or range is present.
-<p>
-Both set matching and <tt><func/switch()/ { }</tt> construction is implemented using this function,
-thus both are as fast as they can be.
-</function>
-<function><p><type>struct f_tree *</type>
-<funcdef>build_tree</funcdef>
-(<type>struct f_tree *</type> <param>from</param>)
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>struct f_tree *</type> <param>from</param></tagp>
- degenerated tree (linked by <param/tree/-&gt;left) to be transformed into form suitable for <func/find_tree()/
-</descrip>
-<funcsect>Description
-<p>
-Transforms degenerated tree into balanced tree.
-</function>
-<function><p><type>int</type>
-<funcdef>same_tree</funcdef>
-(<type>struct f_tree *</type> <param>t1</param>, <type>struct f_tree *</type> <param>t2</param>)
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>struct f_tree *</type> <param>t1</param></tagp>
- first tree to be compared
-<tagp><type>struct f_tree *</type> <param>t2</param></tagp>
- second one
-</descrip>
-<funcsect>Description
-<p>
-Compares two trees and returns 1 if they are same
-</function>
-<sect>Trie for prefix sets
-<p>
- <p>
- We use a (compressed) trie to represent prefix sets. Every node
- in the trie represents one prefix (<struct/addr//<struct/plen/) and <struct/plen/ also
- indicates the index of the bit in the address that is used to
- branch at the node. If we need to represent just a set of
- prefixes, it would be simple, but we have to represent a
- set of prefix patterns. Each prefix pattern consists of
- <struct/ppaddr//<struct/pplen/ and two integers: <struct/low/ and <struct/high/, and a prefix
- <struct/paddr//<struct/plen/ matches that pattern if the first MIN(<struct/plen/, <struct/pplen/)
- bits of <struct/paddr/ and <struct/ppaddr/ are the same and <struct/low/ &lt;= <struct/plen/ &lt;= <struct/high/.
- <p>
- We use a bitmask (<struct/accept/) to represent accepted prefix lengths
- at a node. As there are 33 prefix lengths (0..32 for IPv4), but
- there is just one prefix of zero length in the whole trie so we
- have <struct/zero/ flag in <struct/f_trie/ (indicating whether the trie accepts
- prefix 0.0.0.0/0) as a special case, and <struct/accept/ bitmask
- represents accepted prefix lengths from 1 to 32.
- <p>
- There are two cases in prefix matching - a match when the length
- of the prefix is smaller that the length of the prefix pattern,
- (<struct/plen/ &lt; <struct/pplen/) and otherwise. The second case is simple - we
- just walk through the trie and look at every visited node
- whether that prefix accepts our prefix length (<struct/plen/). The
- first case is tricky - we don't want to examine every descendant
- of a final node, so (when we create the trie) we have to propagate
- that information from nodes to their ascendants.
- <p>
- Suppose that we have two masks (M1 and M2) for a node. Mask M1
- represents accepted prefix lengths by just the node and mask M2
- represents accepted prefix lengths by the node or any of its
- descendants. Therefore M2 is a bitwise or of M1 and children's
- M2 and this is a maintained invariant during trie building.
- Basically, when we want to match a prefix, we walk through the trie,
- check mask M1 for our prefix length and when we came to
- final node, we check mask M2.
- <p>
- There are two differences in the real implementation. First,
- we use a compressed trie so there is a case that we skip our
- final node (if it is not in the trie) and we came to node that
- is either extension of our prefix, or completely out of path
- In the first case, we also have to check M2.
- <p>
- Second, we really need not to maintain two separate bitmasks.
- Checks for mask M1 are always larger than <struct/applen/ and we need
- just the first <struct/pplen/ bits of mask M2 (if trie compression
- hadn't been used it would suffice to know just $applen-th bit),
- so we have to store them together in <struct/accept/ mask - the first
- <struct/pplen/ bits of mask M2 and then mask M1.
- <p>
- There are four cases when we walk through a trie:
- <p>
- - we are in NULL
- - we are out of path (prefixes are inconsistent)
- - we are in the wanted (final) node (node length == <struct/plen/)
- - we are beyond the end of path (node length &gt; <struct/plen/)
- - we are still on path and keep walking (node length &lt; <struct/plen/)
- <p>
- The walking code in <func/trie_match_prefix()/ is structured according to
- these cases.
-
-
-<function><p><type>struct f_trie *</type>
-<funcdef>f_new_trie</funcdef>
-(<type>linpool *</type> <param>lp</param>, <type>uint</type> <param>node_size</param>) -- allocates and returns a new empty trie
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>linpool *</type> <param>lp</param></tagp>
- linear pool to allocate items from
-<tagp><type>uint</type> <param>node_size</param></tagp>
- node size to be used (<struct/f_trie_node/ and user data)
-</descrip>
-</function>
-<function><p><type>void *</type>
-<funcdef>trie_add_prefix</funcdef>
-(<type>struct f_trie *</type> <param>t</param>, <type>ip_addr</type> <param>px</param>, <type>int</type> <param>plen</param>, <type>int</type> <param>l</param>, <type>int</type> <param>h</param>)
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>struct f_trie *</type> <param>t</param></tagp>
- trie to add to
-<tagp><type>ip_addr</type> <param>px</param></tagp>
- prefix address
-<tagp><type>int</type> <param>plen</param></tagp>
- prefix length
-<tagp><type>int</type> <param>l</param></tagp>
- prefix lower bound
-<tagp><type>int</type> <param>h</param></tagp>
- prefix upper bound
-</descrip>
-<funcsect>Description
-<p>
- Adds prefix (prefix pattern) <param/px//<param/plen/ to trie <param/t/. <param/l/ and <param/h/ are lower
- and upper bounds on accepted prefix lengths, both inclusive.
- 0 &lt;= l, h &lt;= 32 (128 for IPv6).
- <p>
- Returns a pointer to the allocated node. The function can return a pointer to
- an existing node if <param/px/ and <param/plen/ are the same. If px/plen == 0/0 (or ::/0),
- a pointer to the root node is returned.
-</function>
-<function><p><type>int</type>
-<funcdef>trie_match_prefix</funcdef>
-(<type>struct f_trie *</type> <param>t</param>, <type>ip_addr</type> <param>px</param>, <type>int</type> <param>plen</param>)
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>struct f_trie *</type> <param>t</param></tagp>
- trie
-<tagp><type>ip_addr</type> <param>px</param></tagp>
- prefix address
-<tagp><type>int</type> <param>plen</param></tagp>
- prefix length
-</descrip>
-<funcsect>Description
-<p>
- Tries to find a matching prefix pattern in the trie such that
- prefix <param/px//<param/plen/ matches that prefix pattern. Returns 1 if there
- is such prefix pattern in the trie.
-</function>
-<function><p><type>int</type>
-<funcdef>trie_same</funcdef>
-(<type>struct f_trie *</type> <param>t1</param>, <type>struct f_trie *</type> <param>t2</param>)
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>struct f_trie *</type> <param>t1</param></tagp>
- first trie to be compared
-<tagp><type>struct f_trie *</type> <param>t2</param></tagp>
- second one
-</descrip>
-<funcsect>Description
-<p>
- Compares two tries and returns 1 if they are same
-</function>
-<function><p><type>void</type>
-<funcdef>trie_format</funcdef>
-(<type>struct f_trie *</type> <param>t</param>, <type>buffer *</type> <param>buf</param>)
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>struct f_trie *</type> <param>t</param></tagp>
- trie to be formatted
-<tagp><type>buffer *</type> <param>buf</param></tagp>
- destination buffer
-</descrip>
-<funcsect>Description
-<p>
- Prints the trie to the supplied buffer.
-</function>
-<chapt>Protocols
-<sect>The Babel protocol
-<p>
- <p>
- Babel (RFC6126) is a loop-avoiding distance-vector routing protocol that is
- robust and efficient both in ordinary wired networks and in wireless mesh
- networks.
- <p>
- The Babel protocol keeps state for each neighbour in a <struct/babel_neighbor/
- struct, tracking received Hello and I Heard You (IHU) messages. A
- <struct/babel_interface/ struct keeps hello and update times for each interface, and
- a separate hello seqno is maintained for each interface.
- <p>
- For each prefix, Babel keeps track of both the possible routes (with next hop
- and router IDs), as well as the feasibility distance for each prefix and
- router id. The prefix itself is tracked in a <struct/babel_entry/ struct, while the
- possible routes for the prefix are tracked as <struct/babel_route/ entries and the
- feasibility distance is maintained through <struct/babel_source/ structures.
- <p>
- The main route selection is done in <func/babel_select_route()/. This is called when
- an entry is updated by receiving updates from the network or when modified by
- internal timers. It performs feasibility checks on the available routes for
- the prefix and selects the one with the lowest metric to be announced to the
- core.
-
-
-<function><p><type>void</type>
-<funcdef>babel_announce_rte</funcdef>
-(<type>struct babel_proto *</type> <param>p</param>, <type>struct babel_entry *</type> <param>e</param>) -- announce selected route to the core
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>struct babel_proto *</type> <param>p</param></tagp>
- Babel protocol instance
-<tagp><type>struct babel_entry *</type> <param>e</param></tagp>
- Babel route entry to announce
-</descrip>
-<funcsect>Description
-<p>
- This function announces a Babel entry to the core if it has a selected
- incoming path, and retracts it otherwise. If the selected entry has infinite
- metric, the route is announced as unreachable.
-</function>
-<function><p><type>void</type>
-<funcdef>babel_select_route</funcdef>
-(<type>struct babel_entry *</type> <param>e</param>) -- select best route for given route entry
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>struct babel_entry *</type> <param>e</param></tagp>
- Babel entry to select the best route for
-</descrip>
-<funcsect>Description
-<p>
- Select the best feasible route for a given prefix among the routes received
- from peers, and propagate it to the nest. This just selects the feasible
- route with the lowest metric.
- <p>
- If no feasible route is available for a prefix that previously had a route
- selected, a seqno request is sent to try to get a valid route. In the
- meantime, the route is marked as infeasible in the nest (to blackhole packets
- going to it, as per the RFC).
- <p>
- If no feasible route is available, and no previous route is selected, the
- route is removed from the nest entirely.
-</function>
-<function><p><type>void</type>
-<funcdef>babel_send_update</funcdef>
-(<type>struct babel_iface *</type> <param>ifa</param>, <type>bird_clock_t</type> <param>changed</param>) -- send route table updates
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>struct babel_iface *</type> <param>ifa</param></tagp>
- Interface to transmit on
-<tagp><type>bird_clock_t</type> <param>changed</param></tagp>
- Only send entries changed since this time
-</descrip>
-<funcsect>Description
-<p>
- This function produces update TLVs for all entries changed since the time
- indicated by the <struct/changed/ parameter and queues them for transmission on the
- selected interface. During the process, the feasibility distance for each
- transmitted entry is updated.
-</function>
-<function><p><type>void</type>
-<funcdef>babel_handle_update</funcdef>
-(<type>union babel_msg *</type> <param>m</param>, <type>struct babel_iface *</type> <param>ifa</param>) -- handle incoming route updates
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>union babel_msg *</type> <param>m</param></tagp>
- Incoming update TLV
-<tagp><type>struct babel_iface *</type> <param>ifa</param></tagp>
- Interface the update was received on
-</descrip>
-<funcsect>Description
-<p>
- This function is called as a handler for update TLVs and handles the updating
- and maintenance of route entries in Babel's internal routing cache. The
- handling follows the actions described in the Babel RFC, and at the end of
- each update handling, <func/babel_select_route()/ is called on the affected entry to
- optionally update the selected routes and propagate them to the core.
-</function>
-<function><p><type>void</type>
-<funcdef>babel_iface_timer</funcdef>
-(<type>timer *</type> <param>t</param>) -- Babel interface timer handler
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>timer *</type> <param>t</param></tagp>
- Timer
-</descrip>
-<funcsect>Description
-<p>
- This function is called by the per-interface timer and triggers sending of
- periodic Hello's and both triggered and periodic updates. Periodic Hello's
- and updates are simply handled by setting the next_{hello,regular} variables
- on the interface, and triggering an update (and resetting the variable)
- whenever 'now' exceeds that value.
- <p>
- For triggered updates, <func/babel_trigger_iface_update()/ will set the
- want_triggered field on the interface to a timestamp value. If this is set
- (and the next_triggered time has passed; this is a rate limiting mechanism),
- <func/babel_send_update()/ will be called with this timestamp as the second
- parameter. This causes updates to be send consisting of only the routes that
- have changed since the time saved in want_triggered.
- <p>
- Mostly when an update is triggered, the route being modified will be set to
- the value of 'now' at the time of the trigger; the &gt;= comparison for
- selecting which routes to send in the update will make sure this is included.
-</function>
-<function><p><type>void</type>
-<funcdef>babel_timer</funcdef>
-(<type>timer *</type> <param>t</param>) -- global timer hook
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>timer *</type> <param>t</param></tagp>
- Timer
-</descrip>
-<funcsect>Description
-<p>
- This function is called by the global protocol instance timer and handles
- expiration of routes and neighbours as well as pruning of the seqno request
- cache.
-</function>
-<function><p><type>uint</type>
-<funcdef>babel_write_queue</funcdef>
-(<type>struct babel_iface *</type> <param>ifa</param>, <type>list *</type> <param>queue</param>) -- Write a TLV queue to a transmission buffer
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>struct babel_iface *</type> <param>ifa</param></tagp>
- Interface holding the transmission buffer
-<tagp><type>list *</type> <param>queue</param></tagp>
- TLV queue to write (containing internal-format TLVs)
-</descrip>
-<funcsect>Description
-<p>
-This function writes a packet to the interface transmission buffer with as
-many TLVs from the <struct/queue/ as will fit in the buffer. It returns the number of
-bytes written (NOT counting the packet header). The function is called by
-<func/babel_send_queue()/ and <func/babel_send_unicast()/ to construct packets for
-transmission, and uses per-TLV helper functions to convert the
-internal-format TLVs to their wire representations.
-<p>
-The TLVs in the queue are freed after they are written to the buffer.
-</function>
-<function><p><type>void</type>
-<funcdef>babel_send_unicast</funcdef>
-(<type>union babel_msg *</type> <param>msg</param>, <type>struct babel_iface *</type> <param>ifa</param>, <type>ip_addr</type> <param>dest</param>) -- send a single TLV via unicast to a destination
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>union babel_msg *</type> <param>msg</param></tagp>
- TLV to send
-<tagp><type>struct babel_iface *</type> <param>ifa</param></tagp>
- Interface to send via
-<tagp><type>ip_addr</type> <param>dest</param></tagp>
- Destination of the TLV
-</descrip>
-<funcsect>Description
-<p>
-This function is used to send a single TLV via unicast to a designated
-receiver. This is used for replying to certain incoming requests, and for
-sending unicast requests to refresh routes before they expire.
-</function>
-<function><p><type>void</type>
-<funcdef>babel_enqueue</funcdef>
-(<type>union babel_msg *</type> <param>msg</param>, <type>struct babel_iface *</type> <param>ifa</param>) -- enqueue a TLV for transmission on an interface
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>union babel_msg *</type> <param>msg</param></tagp>
- TLV to enqueue (in internal TLV format)
-<tagp><type>struct babel_iface *</type> <param>ifa</param></tagp>
- Interface to enqueue to
-</descrip>
-<funcsect>Description
-<p>
-This function is called to enqueue a TLV for subsequent transmission on an
-interface. The transmission event is triggered whenever a TLV is enqueued;
-this ensures that TLVs will be transmitted in a timely manner, but that TLVs
-which are enqueued in rapid succession can be transmitted together in one
-packet.
-</function>
-<function><p><type>void</type>
-<funcdef>babel_process_packet</funcdef>
-(<type>struct babel_pkt_header *</type> <param>pkt</param>, <type>int</type> <param>len</param>, <type>ip_addr</type> <param>saddr</param>, <type>struct babel_iface *</type> <param>ifa</param>) -- process incoming data packet
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>struct babel_pkt_header *</type> <param>pkt</param></tagp>
- Pointer to the packet data
-<tagp><type>int</type> <param>len</param></tagp>
- Length of received packet
-<tagp><type>ip_addr</type> <param>saddr</param></tagp>
- Address of packet sender
-<tagp><type>struct babel_iface *</type> <param>ifa</param></tagp>
- Interface packet was received on.
-</descrip>
-<funcsect>Description
-<p>
-This function is the main processing hook of incoming Babel packets. It
-checks that the packet header is well-formed, then processes the TLVs
-contained in the packet. This is done in two passes: First all TLVs are
-parsed into the internal TLV format. If a TLV parser fails, processing of the
-rest of the packet is aborted.
-<p>
-After the parsing step, the TLV handlers are called for each parsed TLV in
-order.
-</function>
-<sect>Bidirectional Forwarding Detection
-<p>
- <p>
- The BFD protocol is implemented in three files: <tt>bfd.c</tt> containing the
- protocol logic and the protocol glue with BIRD core, <tt>packets.c</tt> handling BFD
- packet processing, RX, TX and protocol sockets. <tt>io.c</tt> then contains generic
- code for the event loop, threads and event sources (sockets, microsecond
- timers). This generic code will be merged to the main BIRD I/O code in the
- future.
- <p>
- The BFD implementation uses a separate thread with an internal event loop for
- handling the protocol logic, which requires high-res and low-latency timing,
- so it is not affected by the rest of BIRD, which has several low-granularity
- hooks in the main loop, uses second-based timers and cannot offer good
- latency. The core of BFD protocol (the code related to BFD sessions,
- interfaces and packets) runs in the BFD thread, while the rest (the code
- related to BFD requests, BFD neighbors and the protocol glue) runs in the
- main thread.
- <p>
- BFD sessions are represented by structure <struct/bfd_session/ that contains a state
- related to the session and two timers (TX timer for periodic packets and hold
- timer for session timeout). These sessions are allocated from <param/session_slab/
- and are accessible by two hash tables, <param/session_hash_id/ (by session ID) and
- <param/session_hash_ip/ (by IP addresses of neighbors). Slab and both hashes are in
- the main protocol structure <struct/bfd_proto/. The protocol logic related to BFD
- sessions is implemented in internal functions bfd_session_*(), which are
- expected to be called from the context of BFD thread, and external functions
- <func/bfd_add_session()/, <func/bfd_remove_session()/ and <func/bfd_reconfigure_session()/, which
- form an interface to the BFD core for the rest and are expected to be called
- from the context of main thread.
- <p>
- Each BFD session has an associated BFD interface, represented by structure
- <struct/bfd_iface/. A BFD interface contains a socket used for TX (the one for RX is
- shared in <struct/bfd_proto/), an interface configuration and reference counter.
- Compared to interface structures of other protocols, these structures are not
- created and removed based on interface notification events, but according to
- the needs of BFD sessions. When a new session is created, it requests a
- proper BFD interface by function <func/bfd_get_iface()/, which either finds an
- existing one in <struct/iface_list/ (from <struct/bfd_proto/) or allocates a new one. When a
- session is removed, an associated iface is discharged by <func/bfd_free_iface()/.
- <p>
- BFD requests are the external API for the other protocols. When a protocol
- wants a BFD session, it calls <func/bfd_request_session()/, which creates a
- structure <struct/bfd_request/ containing approprite information and an notify hook.
- This structure is a resource associated with the caller's resource pool. When
- a BFD protocol is available, a BFD request is submitted to the protocol, an
- appropriate BFD session is found or created and the request is attached to
- the session. When a session changes state, all attached requests (and related
- protocols) are notified. Note that BFD requests do not depend on BFD protocol
- running. When the BFD protocol is stopped or removed (or not available from
- beginning), related BFD requests are stored in <param/bfd_wait_list/, where waits
- for a new protocol.
- <p>
- BFD neighbors are just a way to statically configure BFD sessions without
- requests from other protocol. Structures <struct/bfd_neighbor/ are part of BFD
- configuration (like static routes in the static protocol). BFD neighbors are
- handled by BFD protocol like it is a BFD client -- when a BFD neighbor is
- ready, the protocol just creates a BFD request like any other protocol.
- <p>
- The protocol uses a new generic event loop (structure <struct/birdloop/) from <tt>io.c</tt>,
- which supports sockets, timers and events like the main loop. Timers
- (structure <struct/timer2/) are new microsecond based timers, while sockets and
- events are the same. A birdloop is associated with a thread (field <param/thread/)
- in which event hooks are executed. Most functions for setting event sources
- (like <func/sk_start()/ or <func/tm2_start()/) must be called from the context of that
- thread. Birdloop allows to temporarily acquire the context of that thread for
- the main thread by calling <func/birdloop_enter()/ and then <func/birdloop_leave()/, which
- also ensures mutual exclusion with all event hooks. Note that resources
- associated with a birdloop (like timers) should be attached to the
- independent resource pool, detached from the main resource tree.
- <p>
- There are two kinds of interaction between the BFD core (running in the BFD
- thread) and the rest of BFD (running in the main thread). The first kind are
- configuration calls from main thread to the BFD thread (like <func/bfd_add_session()/).
- These calls are synchronous and use <func/birdloop_enter()/ mechanism for mutual
- exclusion. The second kind is a notification about session changes from the
- BFD thread to the main thread. This is done in an asynchronous way, sesions
- with pending notifications are linked (in the BFD thread) to <param/notify_list/ in
- <struct/bfd_proto/, and then <func/bfd_notify_hook()/ in the main thread is activated using
- <func/bfd_notify_kick()/ and a pipe. The hook then processes scheduled sessions and
- calls hooks from associated BFD requests. This <param/notify_list/ (and state fields
- in structure <struct/bfd_session/) is protected by a spinlock in <struct/bfd_proto/ and
- functions <func/bfd_lock_sessions()/ / <func/bfd_unlock_sessions()/.
- <p>
- There are few data races (accessing <param/p/-&gt;p.debug from <func/TRACE()/ from the BFD
- thread and accessing some some private fields of <const/bfd_session/ from
- <func/bfd_show_sessions()/ from the main thread, but these are harmless (i hope).
- <p>
- TODO: document functions and access restrictions for fields in BFD structures.
- <p>
- Supported standards:
- - RFC 5880 - main BFD standard
- - RFC 5881 - BFD for IP links
- - RFC 5882 - generic application of BFD
- - RFC 5883 - BFD for multihop paths
-
-
-<sect>Border Gateway Protocol
-<p>
- <p>
- The BGP protocol is implemented in three parts: <tt>bgp.c</tt> which takes care of the
- connection and most of the interface with BIRD core, <tt>packets.c</tt> handling
- both incoming and outgoing BGP packets and <tt>attrs.c</tt> containing functions for
- manipulation with BGP attribute lists.
- <p>
- As opposed to the other existing routing daemons, BIRD has a sophisticated core
- architecture which is able to keep all the information needed by BGP in the
- primary routing table, therefore no complex data structures like a central
- BGP table are needed. This increases memory footprint of a BGP router with
- many connections, but not too much and, which is more important, it makes
- BGP much easier to implement.
- <p>
- Each instance of BGP (corresponding to a single BGP peer) is described by a <struct/bgp_proto/
- structure to which are attached individual connections represented by <struct/bgp_connection/
- (usually, there exists only one connection, but during BGP session setup, there
- can be more of them). The connections are handled according to the BGP state machine
- defined in the RFC with all the timers and all the parameters configurable.
- <p>
- In incoming direction, we listen on the connection's socket and each time we receive
- some input, we pass it to <func/bgp_rx()/. It decodes packet headers and the markers and
- passes complete packets to <func/bgp_rx_packet()/ which distributes the packet according
- to its type.
- <p>
- In outgoing direction, we gather all the routing updates and sort them to buckets
- (<struct/bgp_bucket/) according to their attributes (we keep a hash table for fast comparison
- of <struct/rta/'s and a <struct/fib/ which helps us to find if we already have another route for
- the same destination queued for sending, so that we can replace it with the new one
- immediately instead of sending both updates). There also exists a special bucket holding
- all the route withdrawals which cannot be queued anywhere else as they don't have any
- attributes. If we have any packet to send (due to either new routes or the connection
- tracking code wanting to send a Open, Keepalive or Notification message), we call
- <func/bgp_schedule_packet()/ which sets the corresponding bit in a <param/packet_to_send/
- bit field in <struct/bgp_conn/ and as soon as the transmit socket buffer becomes empty,
- we call <func/bgp_fire_tx()/. It inspects state of all the packet type bits and calls
- the corresponding <func/bgp_create_xx()/ functions, eventually rescheduling the same packet
- type if we have more data of the same type to send.
- <p>
- The processing of attributes consists of two functions: <func/bgp_decode_attrs()/ for checking
- of the attribute blocks and translating them to the language of BIRD's extended attributes
- and <func/bgp_encode_attrs()/ which does the converse. Both functions are built around a
- <param/bgp_attr_table/ array describing all important characteristics of all known attributes.
- Unknown transitive attributes are attached to the route as <const/EAF_TYPE_OPAQUE/ byte streams.
- <p>
- BGP protocol implements graceful restart in both restarting (local restart)
- and receiving (neighbor restart) roles. The first is handled mostly by the
- graceful restart code in the nest, BGP protocol just handles capabilities,
- sets <param/gr_wait/ and locks graceful restart until end-of-RIB mark is received.
- The second is implemented by internal restart of the BGP state to <const/BS_IDLE/
- and protocol state to <const/PS_START/, but keeping the protocol up from the core
- point of view and therefore maintaining received routes. Routing table
- refresh cycle (<func/rt_refresh_begin()/, <func/rt_refresh_end()/) is used for removing
- stale routes after reestablishment of BGP session during graceful restart.
-
-
-<function><p><type>int</type>
-<funcdef>bgp_open</funcdef>
-(<type>struct bgp_proto *</type> <param>p</param>) -- open a BGP instance
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>struct bgp_proto *</type> <param>p</param></tagp>
- BGP instance
-</descrip>
-<funcsect>Description
-<p>
- This function allocates and configures shared BGP resources.
- Should be called as the last step during initialization
- (when lock is acquired and neighbor is ready).
- When error, state changed to PS_DOWN, -1 is returned and caller
- should return immediately.
-</function>
-<function><p><type>void</type>
-<funcdef>bgp_close</funcdef>
-(<type>struct bgp_proto *</type> <param>p</param>, <type>int</type> <param>apply_md5</param>) -- close a BGP instance
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>struct bgp_proto *</type> <param>p</param></tagp>
- BGP instance
-<tagp><type>int</type> <param>apply_md5</param></tagp>
- 0 to disable unsetting MD5 auth
-</descrip>
-<funcsect>Description
-<p>
- This function frees and deconfigures shared BGP resources.
- <param/apply_md5/ is set to 0 when bgp_close is called as a cleanup
- from failed <func/bgp_open()/.
-</function>
-<function><p><type>void</type>
-<funcdef>bgp_start_timer</funcdef>
-(<type>timer *</type> <param>t</param>, <type>int</type> <param>value</param>) -- start a BGP timer
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>timer *</type> <param>t</param></tagp>
- timer
-<tagp><type>int</type> <param>value</param></tagp>
- time to fire (0 to disable the timer)
-</descrip>
-<funcsect>Description
-<p>
- This functions calls <func/tm_start()/ on <param/t/ with time <param/value/ and the
- amount of randomization suggested by the BGP standard. Please use
- it for all BGP timers.
-</function>
-<function><p><type>void</type>
-<funcdef>bgp_close_conn</funcdef>
-(<type>struct bgp_conn *</type> <param>conn</param>) -- close a BGP connection
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>struct bgp_conn *</type> <param>conn</param></tagp>
- connection to close
-</descrip>
-<funcsect>Description
-<p>
- This function takes a connection described by the <struct/bgp_conn/ structure,
- closes its socket and frees all resources associated with it.
-</function>
-<function><p><type>void</type>
-<funcdef>bgp_update_startup_delay</funcdef>
-(<type>struct bgp_proto *</type> <param>p</param>) -- update a startup delay
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>struct bgp_proto *</type> <param>p</param></tagp>
- BGP instance
-</descrip>
-<funcsect>Description
-<p>
- This function updates a startup delay that is used to postpone next BGP connect.
- It also handles disable_after_error and might stop BGP instance when error
- happened and disable_after_error is on.
- <p>
- It should be called when BGP protocol error happened.
-</function>
-<function><p><type>void</type>
-<funcdef>bgp_handle_graceful_restart</funcdef>
-(<type>struct bgp_proto *</type> <param>p</param>) -- handle detected BGP graceful restart
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>struct bgp_proto *</type> <param>p</param></tagp>
- BGP instance
-</descrip>
-<funcsect>Description
-<p>
- This function is called when a BGP graceful restart of the neighbor is
- detected (when the TCP connection fails or when a new TCP connection
- appears). The function activates processing of the restart - starts routing
- table refresh cycle and activates BGP restart timer. The protocol state goes
- back to <const/PS_START/, but changing BGP state back to <const/BS_IDLE/ is left for the
- caller.
-</function>
-<function><p><type>void</type>
-<funcdef>bgp_graceful_restart_done</funcdef>
-(<type>struct bgp_proto *</type> <param>p</param>) -- finish active BGP graceful restart
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>struct bgp_proto *</type> <param>p</param></tagp>
- BGP instance
-</descrip>
-<funcsect>Description
-<p>
- This function is called when the active BGP graceful restart of the neighbor
- should be finished - either successfully (the neighbor sends all paths and
- reports end-of-RIB on the new session) or unsuccessfully (the neighbor does
- not support BGP graceful restart on the new session). The function ends
- routing table refresh cycle and stops BGP restart timer.
-</function>
-<function><p><type>void</type>
-<funcdef>bgp_graceful_restart_timeout</funcdef>
-(<type>timer *</type> <param>t</param>) -- timeout of graceful restart 'restart timer'
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>timer *</type> <param>t</param></tagp>
- timer
-</descrip>
-<funcsect>Description
-<p>
- This function is a timeout hook for <param/gr_timer/, implementing BGP restart time
- limit for reestablisment of the BGP session after the graceful restart. When
- fired, we just proceed with the usual protocol restart.
-</function>
-<function><p><type>void</type>
-<funcdef>bgp_refresh_begin</funcdef>
-(<type>struct bgp_proto *</type> <param>p</param>) -- start incoming enhanced route refresh sequence
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>struct bgp_proto *</type> <param>p</param></tagp>
- BGP instance
-</descrip>
-<funcsect>Description
-<p>
- This function is called when an incoming enhanced route refresh sequence is
- started by the neighbor, demarcated by the BoRR packet. The function updates
- the load state and starts the routing table refresh cycle. Note that graceful
- restart also uses routing table refresh cycle, but RFC 7313 and load states
- ensure that these two sequences do not overlap.
-</function>
-<function><p><type>void</type>
-<funcdef>bgp_refresh_end</funcdef>
-(<type>struct bgp_proto *</type> <param>p</param>) -- finish incoming enhanced route refresh sequence
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>struct bgp_proto *</type> <param>p</param></tagp>
- BGP instance
-</descrip>
-<funcsect>Description
-<p>
- This function is called when an incoming enhanced route refresh sequence is
- finished by the neighbor, demarcated by the EoRR packet. The function updates
- the load state and ends the routing table refresh cycle. Routes not received
- during the sequence are removed by the nest.
-</function>
-<function><p><type>void</type>
-<funcdef>bgp_connect</funcdef>
-(<type>struct bgp_proto *</type> <param>p</param>) -- initiate an outgoing connection
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>struct bgp_proto *</type> <param>p</param></tagp>
- BGP instance
-</descrip>
-<funcsect>Description
-<p>
- The <func/bgp_connect()/ function creates a new <struct/bgp_conn/ and initiates
- a TCP connection to the peer. The rest of connection setup is governed
- by the BGP state machine as described in the standard.
-</function>
-<function><p><type>struct bgp_proto *</type>
-<funcdef>bgp_find_proto</funcdef>
-(<type>sock *</type> <param>sk</param>) -- find existing proto for incoming connection
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>sock *</type> <param>sk</param></tagp>
- TCP socket
-</descrip>
-</function>
-<function><p><type>int</type>
-<funcdef>bgp_incoming_connection</funcdef>
-(<type>sock *</type> <param>sk</param>, <type>uint dummy</type> <param>UNUSED</param>) -- handle an incoming connection
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>sock *</type> <param>sk</param></tagp>
- TCP socket
-<tagp><type>uint dummy</type> <param>UNUSED</param></tagp>
- -- undescribed --
-</descrip>
-<funcsect>Description
-<p>
- This function serves as a socket hook for accepting of new BGP
- connections. It searches a BGP instance corresponding to the peer
- which has connected and if such an instance exists, it creates a
- <struct/bgp_conn/ structure, attaches it to the instance and either sends
- an Open message or (if there already is an active connection) it
- closes the new connection by sending a Notification message.
-</function>
-<function><p><type>void</type>
-<funcdef>bgp_error</funcdef>
-(<type>struct bgp_conn *</type> <param>c</param>, <type>unsigned</type> <param>code</param>, <type>unsigned</type> <param>subcode</param>, <type>byte *</type> <param>data</param>, <type>int</type> <param>len</param>) -- report a protocol error
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>struct bgp_conn *</type> <param>c</param></tagp>
- connection
-<tagp><type>unsigned</type> <param>code</param></tagp>
- error code (according to the RFC)
-<tagp><type>unsigned</type> <param>subcode</param></tagp>
- error sub-code
-<tagp><type>byte *</type> <param>data</param></tagp>
- data to be passed in the Notification message
-<tagp><type>int</type> <param>len</param></tagp>
- length of the data
-</descrip>
-<funcsect>Description
-<p>
- <func/bgp_error()/ sends a notification packet to tell the other side that a protocol
- error has occurred (including the data considered erroneous if possible) and
- closes the connection.
-</function>
-<function><p><type>void</type>
-<funcdef>bgp_store_error</funcdef>
-(<type>struct bgp_proto *</type> <param>p</param>, <type>struct bgp_conn *</type> <param>c</param>, <type>u8</type> <param>class</param>, <type>u32</type> <param>code</param>) -- store last error for status report
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>struct bgp_proto *</type> <param>p</param></tagp>
- BGP instance
-<tagp><type>struct bgp_conn *</type> <param>c</param></tagp>
- connection
-<tagp><type>u8</type> <param>class</param></tagp>
- error class (BE_xxx constants)
-<tagp><type>u32</type> <param>code</param></tagp>
- error code (class specific)
-</descrip>
-<funcsect>Description
-<p>
- <func/bgp_store_error()/ decides whether given error is interesting enough
- and store that error to last_error variables of <param/p/
-</function>
-<function><p><type>int</type>
-<funcdef>bgp_fire_tx</funcdef>
-(<type>struct bgp_conn *</type> <param>conn</param>) -- transmit packets
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>struct bgp_conn *</type> <param>conn</param></tagp>
- connection
-</descrip>
-<funcsect>Description
-<p>
-Whenever the transmit buffers of the underlying TCP connection
-are free and we have any packets queued for sending, the socket functions
-call <func/bgp_fire_tx()/ which takes care of selecting the highest priority packet
-queued (Notification &gt; Keepalive &gt; Open &gt; Update), assembling its header
-and body and sending it to the connection.
-</function>
-<function><p><type>void</type>
-<funcdef>bgp_schedule_packet</funcdef>
-(<type>struct bgp_conn *</type> <param>conn</param>, <type>int</type> <param>type</param>) -- schedule a packet for transmission
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>struct bgp_conn *</type> <param>conn</param></tagp>
- connection
-<tagp><type>int</type> <param>type</param></tagp>
- packet type
-</descrip>
-<funcsect>Description
-<p>
-Schedule a packet of type <param/type/ to be sent as soon as possible.
-</function>
-<function><p><type>const char *</type>
-<funcdef>bgp_error_dsc</funcdef>
-(<type>unsigned</type> <param>code</param>, <type>unsigned</type> <param>subcode</param>) -- return BGP error description
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>unsigned</type> <param>code</param></tagp>
- BGP error code
-<tagp><type>unsigned</type> <param>subcode</param></tagp>
- BGP error subcode
-</descrip>
-<funcsect>Description
-<p>
-<func/bgp_error_dsc()/ returns error description for BGP errors
-which might be static string or given temporary buffer.
-</function>
-<function><p><type>void</type>
-<funcdef>bgp_rx_packet</funcdef>
-(<type>struct bgp_conn *</type> <param>conn</param>, <type>byte *</type> <param>pkt</param>, <type>unsigned</type> <param>len</param>) -- handle a received packet
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>struct bgp_conn *</type> <param>conn</param></tagp>
- BGP connection
-<tagp><type>byte *</type> <param>pkt</param></tagp>
- start of the packet
-<tagp><type>unsigned</type> <param>len</param></tagp>
- packet size
-</descrip>
-<funcsect>Description
-<p>
-<func/bgp_rx_packet()/ takes a newly received packet and calls the corresponding
-packet handler according to the packet type.
-</function>
-<function><p><type>int</type>
-<funcdef>bgp_rx</funcdef>
-(<type>sock *</type> <param>sk</param>, <type>uint</type> <param>size</param>) -- handle received data
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>sock *</type> <param>sk</param></tagp>
- socket
-<tagp><type>uint</type> <param>size</param></tagp>
- amount of data received
-</descrip>
-<funcsect>Description
-<p>
-<func/bgp_rx()/ is called by the socket layer whenever new data arrive from
-the underlying TCP connection. It assembles the data fragments to packets,
-checks their headers and framing and passes complete packets to
-<func/bgp_rx_packet()/.
-</function>
-<function><p><type>uint</type>
-<funcdef>bgp_encode_attrs</funcdef>
-(<type>struct bgp_proto *</type> <param>p</param>, <type>byte *</type> <param>w</param>, <type>ea_list *</type> <param>attrs</param>, <type>int</type> <param>remains</param>) -- encode BGP attributes
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>struct bgp_proto *</type> <param>p</param></tagp>
- BGP instance (or NULL)
-<tagp><type>byte *</type> <param>w</param></tagp>
- buffer
-<tagp><type>ea_list *</type> <param>attrs</param></tagp>
- a list of extended attributes
-<tagp><type>int</type> <param>remains</param></tagp>
- remaining space in the buffer
-</descrip>
-<funcsect>Description
-<p>
-The <func/bgp_encode_attrs()/ function takes a list of extended attributes
-and converts it to its BGP representation (a part of an Update message).
-<funcsect>Result
-<p>
- Length of the attribute block generated or -1 if not enough space.
-</function>
-<function><p><type>struct rta *</type>
-<funcdef>bgp_decode_attrs</funcdef>
-(<type>struct bgp_conn *</type> <param>conn</param>, <type>byte *</type> <param>attr</param>, <type>uint</type> <param>len</param>, <type>struct linpool *</type> <param>pool</param>, <type>int</type> <param>mandatory</param>) -- check and decode BGP attributes
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>struct bgp_conn *</type> <param>conn</param></tagp>
- connection
-<tagp><type>byte *</type> <param>attr</param></tagp>
- start of attribute block
-<tagp><type>uint</type> <param>len</param></tagp>
- length of attribute block
-<tagp><type>struct linpool *</type> <param>pool</param></tagp>
- linear pool to make all the allocations in
-<tagp><type>int</type> <param>mandatory</param></tagp>
- 1 iff presence of mandatory attributes has to be checked
-</descrip>
-<funcsect>Description
-<p>
-This function takes a BGP attribute block (a part of an Update message), checks
-its consistency and converts it to a list of BIRD route attributes represented
-by a <struct/rta/.
-</function>
-<sect>Multi-Threaded Routing Toolkit (MRT) protocol
-<p>
- <p>
- The MRT protocol is implemented in just one file: <tt>mrt.c</tt>. It contains of
- several parts: Generic functions for preparing MRT messages in a buffer,
- functions for MRT table dump (called from timer or CLI), functions for MRT
- BGP4MP dump (called from BGP), and the usual protocol glue. For the MRT table
- dump, the key structure is struct mrt_table_dump_state, which contains all
- necessary data and created when the MRT dump cycle is started for the
- duration of the MRT dump. The MBGP4MP dump is currently not bound to MRT
- protocol instance and uses the config-&gt;mrtdump_file fd.
- <p>
- The protocol is simple, just periodically scans routing table and export it
- to a file. It does not use the regular update mechanism, but a direct access
- in order to handle iteration through multiple routing tables. The table dump
- needs to dump all peers first and then use indexes to address the peers, we
- use a hash table (<param/peer_hash/) to find peer index based on BGP protocol key
- attributes.
- <p>
- One thing worth documenting is the locking. During processing, the currently
- processed table (<param/table/ field in the state structure) is locked and also the
- explicitly named table is locked (<param/table_ptr/ field in the state structure) if
- specified. Between dumps no table is locked. Also the current config is
- locked (by <func/config_add_obstacle()/) during table dumps as some data (strings,
- filters) are shared from the config and the running table dump may be
- interrupted by reconfiguration.
- <p>
- Supported standards:
- - RFC 6396 - MRT format standard
- - RFC 8050 - ADD_PATH extension
-
-
-<sect>Open Shortest Path First (OSPF)
-<p>
- <p>
- The OSPF protocol is quite complicated and its complex implemenation is split
- to many files. In <tt>ospf.c</tt>, you will find mainly the interface for
- communication with the core (e.g., reconfiguration hooks, shutdown and
- initialisation and so on). File <tt>iface.c</tt> contains the interface state
- machine and functions for allocation and deallocation of OSPF's interface
- data structures. Source <tt>neighbor.c</tt> includes the neighbor state machine and
- functions for election of Designated Router and Backup Designated router. In
- <tt>packet.c</tt>, you will find various functions for sending and receiving generic
- OSPF packets. There are also routines for authentication and checksumming.
- In <tt>hello.c</tt>, there are routines for sending and receiving of hello packets
- as well as functions for maintaining wait times and the inactivity timer.
- Files <tt>lsreq.c</tt>, <tt>lsack.c</tt>, <tt>dbdes.c</tt> contain functions for sending and
- receiving of link-state requests, link-state acknowledgements and database
- descriptions respectively. In <tt>lsupd.c</tt>, there are functions for sending and
- receiving of link-state updates and also the flooding algorithm. Source
- <tt>topology.c</tt> is a place where routines for searching LSAs in the link-state
- database, adding and deleting them reside, there also are functions for
- originating of various types of LSAs (router LSA, net LSA, external LSA).
- File <tt>rt.c</tt> contains routines for calculating the routing table. <tt>lsalib.c</tt>
- is a set of various functions for working with the LSAs (endianity
- conversions, calculation of checksum etc.).
- <p>
- One instance of the protocol is able to hold LSA databases for multiple OSPF
- areas, to exchange routing information between multiple neighbors and to
- calculate the routing tables. The core structure is <struct/ospf_proto/ to which
- multiple <struct/ospf_area/ and <struct/ospf_iface/ structures are connected. <struct/ospf_proto/ is
- also connected to <struct/top_hash_graph/ which is a dynamic hashing structure that
- describes the link-state database. It allows fast search, addition and
- deletion. Each LSA is kept in two pieces: header and body. Both of them are
- kept in the endianity of the CPU.
- <p>
- In OSPFv2 specification, it is implied that there is one IP prefix for each
- physical network/interface (unless it is an ptp link). But in modern systems,
- there might be more independent IP prefixes associated with an interface. To
- handle this situation, we have one <struct/ospf_iface/ for each active IP prefix
- (instead for each active iface); This behaves like virtual interface for the
- purpose of OSPF. If we receive packet, we associate it with a proper virtual
- interface mainly according to its source address.
- <p>
- OSPF keeps one socket per <struct/ospf_iface/. This allows us (compared to one socket
- approach) to evade problems with a limit of multicast groups per socket and
- with sending multicast packets to appropriate interface in a portable way.
- The socket is associated with underlying physical iface and should not
- receive packets received on other ifaces (unfortunately, this is not true on
- BSD). Generally, one packet can be received by more sockets (for example, if
- there are more <struct/ospf_iface/ on one physical iface), therefore we explicitly
- filter received packets according to src/dst IP address and received iface.
- <p>
- Vlinks are implemented using particularly degenerate form of <struct/ospf_iface/,
- which has several exceptions: it does not have its iface or socket (it copies
- these from 'parent' <struct/ospf_iface/) and it is present in iface list even when
- down (it is not freed in <func/ospf_iface_down()/).
- <p>
- The heart beat of ospf is <func/ospf_disp()/. It is called at regular intervals
- (<struct/ospf_proto/-&gt;tick). It is responsible for aging and flushing of LSAs in the
- database, updating topology information in LSAs and for routing table
- calculation.
- <p>
- To every <struct/ospf_iface/, we connect one or more <struct/ospf_neighbor/'s -- a structure
- containing many timers and queues for building adjacency and for exchange of
- routing messages.
- <p>
- BIRD's OSPF implementation respects RFC2328 in every detail, but some of
- internal algorithms do differ. The RFC recommends making a snapshot of the
- link-state database when a new adjacency is forming and sending the database
- description packets based on the information in this snapshot. The database
- can be quite large in some networks, so rather we walk through a <struct/slist/
- structure which allows us to continue even if the actual LSA we were working
- with is deleted. New LSAs are added at the tail of this <struct/slist/.
- <p>
- We also do not keep a separate OSPF routing table, because the core helps us
- by being able to recognize when a route is updated to an identical one and it
- suppresses the update automatically. Due to this, we can flush all the routes
- we have recalculated and also those we have deleted to the core's routing
- table and the core will take care of the rest. This simplifies the process
- and conserves memory.
- <p>
- Supported standards:
- - RFC 2328 - main OSPFv2 standard
- - RFC 5340 - main OSPFv3 standard
- - RFC 3101 - OSPFv2 NSSA areas
- - RFC 6549 - OSPFv2 multi-instance extensions
- - RFC 6987 - OSPF stub router advertisement
-
-
-<function><p><type>void</type>
-<funcdef>ospf_disp</funcdef>
-(<type>timer *</type> <param>timer</param>) -- invokes routing table calculation, aging and also <func/area_disp()/
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>timer *</type> <param>timer</param></tagp>
- timer usually called every <param/ospf_proto/-&gt;tick second, <param/timer/-&gt;data
- point to <param/ospf_proto/
-</descrip>
-</function>
-<function><p><type>int</type>
-<funcdef>ospf_import_control</funcdef>
-(<type>struct proto *</type> <param>P</param>, <type>rte **</type> <param>new</param>, <type>ea_list **</type> <param>attrs</param>, <type>struct linpool *</type> <param>pool</param>) -- accept or reject new route from nest's routing table
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>struct proto *</type> <param>P</param></tagp>
- OSPF protocol instance
-<tagp><type>rte **</type> <param>new</param></tagp>
- the new route
-<tagp><type>ea_list **</type> <param>attrs</param></tagp>
- list of attributes
-<tagp><type>struct linpool *</type> <param>pool</param></tagp>
- pool for allocation of attributes
-</descrip>
-<funcsect>Description
-<p>
- Its quite simple. It does not accept our own routes and leaves the decision on
- import to the filters.
-</function>
-<function><p><type>int</type>
-<funcdef>ospf_shutdown</funcdef>
-(<type>struct proto *</type> <param>P</param>) -- Finish of OSPF instance
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>struct proto *</type> <param>P</param></tagp>
- OSPF protocol instance
-</descrip>
-<funcsect>Description
-<p>
- RFC does not define any action that should be taken before router
- shutdown. To make my neighbors react as fast as possible, I send
- them hello packet with empty neighbor list. They should start
- their neighbor state machine with event <const/NEIGHBOR_1WAY/.
-</function>
-<function><p><type>int</type>
-<funcdef>ospf_reconfigure</funcdef>
-(<type>struct proto *</type> <param>P</param>, <type>struct proto_config *</type> <param>c</param>) -- reconfiguration hook
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>struct proto *</type> <param>P</param></tagp>
- current instance of protocol (with old configuration)
-<tagp><type>struct proto_config *</type> <param>c</param></tagp>
- new configuration requested by user
-</descrip>
-<funcsect>Description
-<p>
- This hook tries to be a little bit intelligent. Instance of OSPF
- will survive change of many constants like hello interval,
- password change, addition or deletion of some neighbor on
- nonbroadcast network, cost of interface, etc.
-</function>
-<function><p><type>struct top_hash_entry *</type>
-<funcdef>ospf_install_lsa</funcdef>
-(<type>struct ospf_proto *</type> <param>p</param>, <type>struct ospf_lsa_header *</type> <param>lsa</param>, <type>u32</type> <param>type</param>, <type>u32</type> <param>domain</param>, <type>void *</type> <param>body</param>) -- install new LSA into database
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>struct ospf_proto *</type> <param>p</param></tagp>
- OSPF protocol instance
-<tagp><type>struct ospf_lsa_header *</type> <param>lsa</param></tagp>
- LSA header
-<tagp><type>u32</type> <param>type</param></tagp>
- type of LSA
-<tagp><type>u32</type> <param>domain</param></tagp>
- domain of LSA
-<tagp><type>void *</type> <param>body</param></tagp>
- pointer to LSA body
-</descrip>
-<funcsect>Description
-<p>
-This function ensures installing new LSA received in LS update into LSA
-database. Old instance is replaced. Several actions are taken to detect if
-new routing table calculation is necessary. This is described in 13.2 of RFC
-2328. This function is for received LSA only, locally originated LSAs are
-installed by <func/ospf_originate_lsa()/.
-<p>
-The LSA body in <param/body/ is expected to be mb_allocated by the caller and its
-ownership is transferred to the LSA entry structure.
-</function>
-<function><p><type>void</type>
-<funcdef>ospf_advance_lsa</funcdef>
-(<type>struct ospf_proto *</type> <param>p</param>, <type>struct top_hash_entry *</type> <param>en</param>, <type>struct ospf_lsa_header *</type> <param>lsa</param>, <type>u32</type> <param>type</param>, <type>u32</type> <param>domain</param>, <type>void *</type> <param>body</param>) -- handle received unexpected self-originated LSA
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>struct ospf_proto *</type> <param>p</param></tagp>
- OSPF protocol instance
-<tagp><type>struct top_hash_entry *</type> <param>en</param></tagp>
- current LSA entry or NULL
-<tagp><type>struct ospf_lsa_header *</type> <param>lsa</param></tagp>
- new LSA header
-<tagp><type>u32</type> <param>type</param></tagp>
- type of LSA
-<tagp><type>u32</type> <param>domain</param></tagp>
- domain of LSA
-<tagp><type>void *</type> <param>body</param></tagp>
- pointer to LSA body
-</descrip>
-<funcsect>Description
-<p>
-This function handles received unexpected self-originated LSA (<param/lsa/, <param/body/)
-by either advancing sequence number of the local LSA instance (<param/en/) and
-propagating it, or installing the received LSA and immediately flushing it
-(if there is no local LSA; i.e., <param/en/ is NULL or MaxAge).
-<p>
-The LSA body in <param/body/ is expected to be mb_allocated by the caller and its
-ownership is transferred to the LSA entry structure or it is freed.
-</function>
-<function><p><type>struct top_hash_entry *</type>
-<funcdef>ospf_originate_lsa</funcdef>
-(<type>struct ospf_proto *</type> <param>p</param>, <type>struct ospf_new_lsa *</type> <param>lsa</param>) -- originate new LSA
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>struct ospf_proto *</type> <param>p</param></tagp>
- OSPF protocol instance
-<tagp><type>struct ospf_new_lsa *</type> <param>lsa</param></tagp>
- New LSA specification
-</descrip>
-<funcsect>Description
-<p>
-This function prepares a new LSA, installs it into the LSA database and
-floods it. If the new LSA cannot be originated now (because the old instance
-was originated within MinLSInterval, or because the LSA seqnum is currently
-wrapping), the origination is instead scheduled for later. If the new LSA is
-equivalent to the current LSA, the origination is skipped. In all cases, the
-corresponding LSA entry is returned. The new LSA is based on the LSA
-specification (<param/lsa/) and the LSA body from lsab buffer of <param/p/, which is
-emptied after the call. The opposite of this function is <func/ospf_flush_lsa()/.
-</function>
-<function><p><type>void</type>
-<funcdef>ospf_flush_lsa</funcdef>
-(<type>struct ospf_proto *</type> <param>p</param>, <type>struct top_hash_entry *</type> <param>en</param>) -- flush LSA from OSPF domain
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>struct ospf_proto *</type> <param>p</param></tagp>
- OSPF protocol instance
-<tagp><type>struct top_hash_entry *</type> <param>en</param></tagp>
- LSA entry to flush
-</descrip>
-<funcsect>Description
-<p>
-This function flushes <param/en/ from the OSPF domain by setting its age to
-<const/LSA_MAXAGE/ and flooding it. That also triggers subsequent events in LSA
-lifecycle leading to removal of the LSA from the LSA database (e.g. the LSA
-content is freed when flushing is acknowledged by neighbors). The function
-does nothing if the LSA is already being flushed. LSA entries are not
-immediately removed when being flushed, the caller may assume that <param/en/ still
-exists after the call. The function is the opposite of <func/ospf_originate_lsa()/
-and is supposed to do the right thing even in cases of postponed
-origination.
-</function>
-<function><p><type>void</type>
-<funcdef>ospf_update_lsadb</funcdef>
-(<type>struct ospf_proto *</type> <param>p</param>) -- update LSA database
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>struct ospf_proto *</type> <param>p</param></tagp>
- OSPF protocol instance
-</descrip>
-<funcsect>Description
-<p>
-This function is periodicaly invoked from <func/ospf_disp()/. It does some periodic
-or postponed processing related to LSA entries. It originates postponed LSAs
-scheduled by <func/ospf_originate_lsa()/, It continues in flushing processes started
-by <func/ospf_flush_lsa()/. It also periodically refreshs locally originated LSAs --
-when the current instance is older <const/LSREFRESHTIME/, a new instance is originated.
-Finally, it also ages stored LSAs and flushes ones that reached <const/LSA_MAXAGE/.
-<p>
-The RFC 2328 says that a router should periodically check checksums of all
-stored LSAs to detect hardware problems. This is not implemented.
-</function>
-<function><p><type>void</type>
-<funcdef>ospf_originate_ext_lsa</funcdef>
-(<type>struct ospf_proto *</type> <param>p</param>, <type>struct ospf_area *</type> <param>oa</param>, <type>ort *</type> <param>nf</param>, <type>u8</type> <param>mode</param>, <type>u32</type> <param>metric</param>, <type>u32</type> <param>ebit</param>, <type>ip_addr</type> <param>fwaddr</param>, <type>u32</type> <param>tag</param>, <type>int</type> <param>pbit</param>) -- new route received from nest and filters
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>struct ospf_proto *</type> <param>p</param></tagp>
- OSPF protocol instance
-<tagp><type>struct ospf_area *</type> <param>oa</param></tagp>
- ospf_area for which LSA is originated
-<tagp><type>ort *</type> <param>nf</param></tagp>
- network prefix and mask
-<tagp><type>u8</type> <param>mode</param></tagp>
- the mode of the LSA (LSA_M_EXPORT or LSA_M_RTCALC)
-<tagp><type>u32</type> <param>metric</param></tagp>
- the metric of a route
-<tagp><type>u32</type> <param>ebit</param></tagp>
- E-bit for route metric (bool)
-<tagp><type>ip_addr</type> <param>fwaddr</param></tagp>
- the forwarding address
-<tagp><type>u32</type> <param>tag</param></tagp>
- the route tag
-<tagp><type>int</type> <param>pbit</param></tagp>
- P-bit for NSSA LSAs (bool), ignored for external LSAs
-</descrip>
-<funcsect>Description
-<p>
-If I receive a message that new route is installed, I try to originate an
-external LSA. If <param/oa/ is an NSSA area, NSSA-LSA is originated instead.
-<param/oa/ should not be a stub area. <param/src/ does not specify whether the LSA
-is external or NSSA, but it specifies the source of origination -
-the export from <func/ospf_rt_notify()/, or the NSSA-EXT translation.
-</function>
-<function><p><type>struct top_graph *</type>
-<funcdef>ospf_top_new</funcdef>
-(<type>struct ospf_proto *p UNUSED4</type> <param>UNUSED6</param>, <type>pool *</type> <param>pool</param>) -- allocated new topology database
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>struct ospf_proto *p UNUSED4</type> <param>UNUSED6</param></tagp>
--- undescribed --
-<tagp><type>pool *</type> <param>pool</param></tagp>
- pool for allocation
-</descrip>
-<funcsect>Description
-<p>
-This dynamically hashed structure is used for keeping LSAs. Mainly it is used
-for the LSA database of the OSPF protocol, but also for LSA retransmission
-and request lists of OSPF neighbors.
-</function>
-<function><p><type>void</type>
-<funcdef>ospf_neigh_chstate</funcdef>
-(<type>struct ospf_neighbor *</type> <param>n</param>, <type>u8</type> <param>state</param>) -- handles changes related to new or lod state of neighbor
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>struct ospf_neighbor *</type> <param>n</param></tagp>
- OSPF neighbor
-<tagp><type>u8</type> <param>state</param></tagp>
- new state
-</descrip>
-<funcsect>Description
-<p>
-Many actions have to be taken acording to a change of state of a neighbor. It
-starts rxmt timers, call interface state machine etc.
-</function>
-<function><p><type>void</type>
-<funcdef>ospf_neigh_sm</funcdef>
-(<type>struct ospf_neighbor *</type> <param>n</param>, <type>int</type> <param>event</param>) -- ospf neighbor state machine
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>struct ospf_neighbor *</type> <param>n</param></tagp>
- neighor
-<tagp><type>int</type> <param>event</param></tagp>
- actual event
-</descrip>
-<funcsect>Description
-<p>
-This part implements the neighbor state machine as described in 10.3 of
-RFC 2328. The only difference is that state <const/NEIGHBOR_ATTEMPT/ is not
-used. We discover neighbors on nonbroadcast networks in the
-same way as on broadcast networks. The only difference is in
-sending hello packets. These are sent to IPs listed in
-<param/ospf_iface/-&gt;nbma_list .
-</function>
-<function><p><type>void</type>
-<funcdef>ospf_dr_election</funcdef>
-(<type>struct ospf_iface *</type> <param>ifa</param>) -- (Backup) Designed Router election
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>struct ospf_iface *</type> <param>ifa</param></tagp>
- actual interface
-</descrip>
-<funcsect>Description
-<p>
-When the wait timer fires, it is time to elect (Backup) Designated Router.
-Structure describing me is added to this list so every electing router has
-the same list. Backup Designated Router is elected before Designated
-Router. This process is described in 9.4 of RFC 2328. The function is
-supposed to be called only from <func/ospf_iface_sm()/ as a part of the interface
-state machine.
-</function>
-<function><p><type>void</type>
-<funcdef>ospf_iface_chstate</funcdef>
-(<type>struct ospf_iface *</type> <param>ifa</param>, <type>u8</type> <param>state</param>) -- handle changes of interface state
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>struct ospf_iface *</type> <param>ifa</param></tagp>
- OSPF interface
-<tagp><type>u8</type> <param>state</param></tagp>
- new state
-</descrip>
-<funcsect>Description
-<p>
-Many actions must be taken according to interface state changes. New network
-LSAs must be originated, flushed, new multicast sockets to listen for messages for
-<const/ALLDROUTERS/ have to be opened, etc.
-</function>
-<function><p><type>void</type>
-<funcdef>ospf_iface_sm</funcdef>
-(<type>struct ospf_iface *</type> <param>ifa</param>, <type>int</type> <param>event</param>) -- OSPF interface state machine
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>struct ospf_iface *</type> <param>ifa</param></tagp>
- OSPF interface
-<tagp><type>int</type> <param>event</param></tagp>
- event comming to state machine
-</descrip>
-<funcsect>Description
-<p>
-This fully respects 9.3 of RFC 2328 except we have slightly
-different handling of <const/DOWN/ and <const/LOOP/ state. We remove intefaces
-that are <const/DOWN/. <const/DOWN/ state is used when an interface is waiting
-for a lock. <const/LOOP/ state is used when an interface does not have a
-link.
-</function>
-<function><p><type>int</type>
-<funcdef>ospf_rx_hook</funcdef>
-(<type>sock *</type> <param>sk</param>, <type>uint</type> <param>len</param>)
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>sock *</type> <param>sk</param></tagp>
- socket we received the packet.
-<tagp><type>uint</type> <param>len</param></tagp>
- size of the packet
-</descrip>
-<funcsect>Description
-<p>
-This is the entry point for messages from neighbors. Many checks (like
-authentication, checksums, size) are done before the packet is passed to
-non generic functions.
-</function>
-<function><p><type>int</type>
-<funcdef>lsa_validate</funcdef>
-(<type>struct ospf_lsa_header *</type> <param>lsa</param>, <type>u32</type> <param>lsa_type</param>, <type>int</type> <param>ospf2</param>, <type>void *</type> <param>body</param>) -- check whether given LSA is valid
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>struct ospf_lsa_header *</type> <param>lsa</param></tagp>
- LSA header
-<tagp><type>u32</type> <param>lsa_type</param></tagp>
- one of <const/LSA_T_xxx/
-<tagp><type>int</type> <param>ospf2</param></tagp>
- <const/true/ means OSPF version 2, <const/false/ means OSPF version 3
-<tagp><type>void *</type> <param>body</param></tagp>
- pointer to LSA body
-</descrip>
-<funcsect>Description
-<p>
-Checks internal structure of given LSA body (minimal length,
-consistency). Returns true if valid.
-</function>
-<function><p><type>void</type>
-<funcdef>ospf_send_dbdes</funcdef>
-(<type>struct ospf_proto *</type> <param>p</param>, <type>struct ospf_neighbor *</type> <param>n</param>) -- transmit database description packet
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>struct ospf_proto *</type> <param>p</param></tagp>
- OSPF protocol instance
-<tagp><type>struct ospf_neighbor *</type> <param>n</param></tagp>
- neighbor
-</descrip>
-<funcsect>Description
-<p>
-Sending of a database description packet is described in 10.8 of RFC 2328.
-Reception of each packet is acknowledged in the sequence number of another.
-When I send a packet to a neighbor I keep a copy in a buffer. If the neighbor
-does not reply, I don't create a new packet but just send the content
-of the buffer.
-</function>
-<function><p><type>void</type>
-<funcdef>ospf_rt_spf</funcdef>
-(<type>struct ospf_proto *</type> <param>p</param>) -- calculate internal routes
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>struct ospf_proto *</type> <param>p</param></tagp>
- OSPF protocol instance
-</descrip>
-<funcsect>Description
-<p>
-Calculation of internal paths in an area is described in 16.1 of RFC 2328.
-It's based on Dijkstra's shortest path tree algorithms.
-This function is invoked from <func/ospf_disp()/.
-</function>
-<sect>Pipe
-<p>
- <p>
- The Pipe protocol is very simple. It just connects to two routing tables
- using <func/proto_add_announce_hook()/ and whenever it receives a <func/rt_notify()/
- about a change in one of the tables, it converts it to a <func/rte_update()/
- in the other one.
- <p>
- To avoid pipe loops, Pipe keeps a `being updated' flag in each routing
- table.
- <p>
- A pipe has two announce hooks, the first connected to the main
- table, the second connected to the peer table. When a new route is
- announced on the main table, it gets checked by an export filter in
- ahook 1, and, after that, it is announced to the peer table via
- <func/rte_update()/, an import filter in ahook 2 is called. When a new
- route is announced in the peer table, an export filter in ahook2
- and an import filter in ahook 1 are used. Oviously, there is no
- need in filtering the same route twice, so both import filters are
- set to accept, while user configured 'import' and 'export' filters
- are used as export filters in ahooks 2 and 1. Route limits are
- handled similarly, but on the import side of ahooks.
-
-
-<sect>Routing Information Protocol (RIP)
-<p>
- <p>
- The RIP protocol is implemented in two files: <tt>rip.c</tt> containing the protocol
- logic, route management and the protocol glue with BIRD core, and <tt>packets.c</tt>
- handling RIP packet processing, RX, TX and protocol sockets.
- <p>
- Each instance of RIP is described by a structure <struct/rip_proto/, which contains
- an internal RIP routing table, a list of protocol interfaces and the main
- timer responsible for RIP routing table cleanup.
- <p>
- RIP internal routing table contains incoming and outgoing routes. For each
- network (represented by structure <struct/rip_entry/) there is one outgoing route
- stored directly in <struct/rip_entry/ and an one-way linked list of incoming routes
- (structures <struct/rip_rte/). The list contains incoming routes from different RIP
- neighbors, but only routes with the lowest metric are stored (i.e., all
- stored incoming routes have the same metric).
- <p>
- Note that RIP itself does not select outgoing route, that is done by the core
- routing table. When a new incoming route is received, it is propagated to the
- RIP table by <func/rip_update_rte()/ and possibly stored in the list of incoming
- routes. Then the change may be propagated to the core by <func/rip_announce_rte()/.
- The core selects the best route and propagate it to RIP by <func/rip_rt_notify()/,
- which updates outgoing route part of <struct/rip_entry/ and possibly triggers route
- propagation by <func/rip_trigger_update()/.
- <p>
- RIP interfaces are represented by structures <struct/rip_iface/. A RIP interface
- contains a per-interface socket, a list of associated neighbors, interface
- configuration, and state information related to scheduled interface events
- and running update sessions. RIP interfaces are added and removed based on
- core interface notifications.
- <p>
- There are two RIP interface events - regular updates and triggered updates.
- Both are managed from the RIP interface timer (<func/rip_iface_timer()/). Regular
- updates are called at fixed interval and propagate the whole routing table,
- while triggered updates are scheduled by <func/rip_trigger_update()/ due to some
- routing table change and propagate only the routes modified since the time
- they were scheduled. There are also unicast-destined requested updates, but
- these are sent directly as a reaction to received RIP request message. The
- update session is started by <func/rip_send_table()/. There may be at most one
- active update session per interface, as the associated state (including the
- fib iterator) is stored directly in <struct/rip_iface/ structure.
- <p>
- RIP neighbors are represented by structures <struct/rip_neighbor/. Compared to
- neighbor handling in other routing protocols, RIP does not have explicit
- neighbor discovery and adjacency maintenance, which makes the <struct/rip_neighbor/
- related code a bit peculiar. RIP neighbors are interlinked with core neighbor
- structures (<struct/neighbor/) and use core neighbor notifications to ensure that RIP
- neighbors are timely removed. RIP neighbors are added based on received route
- notifications and removed based on core neighbor and RIP interface events.
- <p>
- RIP neighbors are linked by RIP routes and use counter to track the number of
- associated routes, but when these RIP routes timeout, associated RIP neighbor
- is still alive (with zero counter). When RIP neighbor is removed but still
- has some associated routes, it is not freed, just changed to detached state
- (core neighbors and RIP ifaces are unlinked), then during the main timer
- cleanup phase the associated routes are removed and the <struct/rip_neighbor/
- structure is finally freed.
- <p>
- Supported standards:
- - RFC 1058 - RIPv1
- - RFC 2453 - RIPv2
- - RFC 2080 - RIPng
- - RFC 4822 - RIP cryptographic authentication
-
-
-<function><p><type>void</type>
-<funcdef>rip_announce_rte</funcdef>
-(<type>struct rip_proto *</type> <param>p</param>, <type>struct rip_entry *</type> <param>en</param>) -- announce route from RIP routing table to the core
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>struct rip_proto *</type> <param>p</param></tagp>
- RIP instance
-<tagp><type>struct rip_entry *</type> <param>en</param></tagp>
- related network
-</descrip>
-<funcsect>Description
-<p>
- The function takes a list of incoming routes from <param/en/, prepare appropriate
- <struct/rte/ for the core and propagate it by <func/rte_update()/.
-</function>
-<function><p><type>void</type>
-<funcdef>rip_update_rte</funcdef>
-(<type>struct rip_proto *</type> <param>p</param>, <type>ip_addr *</type> <param>prefix</param>, <type>int</type> <param>pxlen</param>, <type>struct rip_rte *</type> <param>new</param>) -- enter a route update to RIP routing table
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>struct rip_proto *</type> <param>p</param></tagp>
- RIP instance
-<tagp><type>ip_addr *</type> <param>prefix</param></tagp>
- network prefix
-<tagp><type>int</type> <param>pxlen</param></tagp>
- network prefix length
-<tagp><type>struct rip_rte *</type> <param>new</param></tagp>
- a <struct/rip_rte/ representing the new route
-</descrip>
-<funcsect>Description
-<p>
- The function is called by the RIP packet processing code whenever it receives
- a reachable route. The appropriate routing table entry is found and the list
- of incoming routes is updated. Eventually, the change is also propagated to
- the core by <func/rip_announce_rte()/. Note that for unreachable routes,
- <func/rip_withdraw_rte()/ should be called instead of <func/rip_update_rte()/.
-</function>
-<function><p><type>void</type>
-<funcdef>rip_withdraw_rte</funcdef>
-(<type>struct rip_proto *</type> <param>p</param>, <type>ip_addr *</type> <param>prefix</param>, <type>int</type> <param>pxlen</param>, <type>struct rip_neighbor *</type> <param>from</param>) -- enter a route withdraw to RIP routing table
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>struct rip_proto *</type> <param>p</param></tagp>
- RIP instance
-<tagp><type>ip_addr *</type> <param>prefix</param></tagp>
- network prefix
-<tagp><type>int</type> <param>pxlen</param></tagp>
- network prefix length
-<tagp><type>struct rip_neighbor *</type> <param>from</param></tagp>
- a <struct/rip_neighbor/ propagating the withdraw
-</descrip>
-<funcsect>Description
-<p>
- The function is called by the RIP packet processing code whenever it receives
- an unreachable route. The incoming route for given network from nbr <param/from/ is
- removed. Eventually, the change is also propagated by <func/rip_announce_rte()/.
-</function>
-<function><p><type>void</type>
-<funcdef>rip_timer</funcdef>
-(<type>timer *</type> <param>t</param>) -- RIP main timer hook
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>timer *</type> <param>t</param></tagp>
- timer
-</descrip>
-<funcsect>Description
-<p>
- The RIP main timer is responsible for routing table maintenance. Invalid or
- expired routes (<struct/rip_rte/) are removed and garbage collection of stale routing
- table entries (<struct/rip_entry/) is done. Changes are propagated to core tables,
- route reload is also done here. Note that garbage collection uses a maximal
- GC time, while interfaces maintain an illusion of per-interface GC times in
- <func/rip_send_response()/.
- <p>
- Keeping incoming routes and the selected outgoing route are two independent
- functions, therefore after garbage collection some entries now considered
- invalid (RIP_ENTRY_DUMMY) still may have non-empty list of incoming routes,
- while some valid entries (representing an outgoing route) may have that list
- empty.
- <p>
- The main timer is not scheduled periodically but it uses the time of the
- current next event and the minimal interval of any possible event to compute
- the time of the next run.
-</function>
-<function><p><type>void</type>
-<funcdef>rip_iface_timer</funcdef>
-(<type>timer *</type> <param>t</param>) -- RIP interface timer hook
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>timer *</type> <param>t</param></tagp>
- timer
-</descrip>
-<funcsect>Description
-<p>
- RIP interface timers are responsible for scheduling both regular and
- triggered updates. Fixed, delay-independent period is used for regular
- updates, while minimal separating interval is enforced for triggered updates.
- The function also ensures that a new update is not started when the old one
- is still running.
-</function>
-<function><p><type>void</type>
-<funcdef>rip_send_table</funcdef>
-(<type>struct rip_proto *</type> <param>p</param>, <type>struct rip_iface *</type> <param>ifa</param>, <type>ip_addr</type> <param>addr</param>, <type>bird_clock_t</type> <param>changed</param>) -- RIP interface timer hook
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>struct rip_proto *</type> <param>p</param></tagp>
- RIP instance
-<tagp><type>struct rip_iface *</type> <param>ifa</param></tagp>
- RIP interface
-<tagp><type>ip_addr</type> <param>addr</param></tagp>
- destination IP address
-<tagp><type>bird_clock_t</type> <param>changed</param></tagp>
- time limit for triggered updates
-</descrip>
-<funcsect>Description
-<p>
-The function activates an update session and starts sending routing update
-packets (using <func/rip_send_response()/). The session may be finished during the
-call or may continue in <func/rip_tx_hook()/ until all appropriate routes are
-transmitted. Note that there may be at most one active update session per
-interface, the function will terminate the old active session before
-activating the new one.
-</function>
-<sect>Router Advertisements
-<p>
- <p>
- The RAdv protocol is implemented in two files: <tt>radv.c</tt> containing the
- interface with BIRD core and the protocol logic and <tt>packets.c</tt> handling low
- level protocol stuff (RX, TX and packet formats). The protocol does not
- export any routes.
- <p>
- The RAdv is structured in the usual way - for each handled interface there is
- a structure <struct/radv_iface/ that contains a state related to that interface
- together with its resources (a socket, a timer). There is also a prepared RA
- stored in a TX buffer of the socket associated with an iface. These iface
- structures are created and removed according to iface events from BIRD core
- handled by <func/radv_if_notify()/ callback.
- <p>
- The main logic of RAdv consists of two functions: <func/radv_iface_notify()/, which
- processes asynchronous events (specified by RA_EV_* codes), and <func/radv_timer()/,
- which triggers sending RAs and computes the next timeout.
- <p>
- The RAdv protocol could receive routes (through <func/radv_import_control()/ and
- <func/radv_rt_notify()/), but only the configured trigger route is tracked (in
- <struct/active/ var). When a radv protocol is reconfigured, the connected routing
- table is examined (in <func/radv_check_active()/) to have proper <struct/active/ value in
- case of the specified trigger prefix was changed.
- <p>
- Supported standards:
- - RFC 4861 - main RA standard
- - RFC 4191 - Default Router Preferences and More-Specific Routes
- - RFC 6106 - DNS extensions (RDDNS, DNSSL)
-
-
-<sect>Static
-<p>
- <p>
- The Static protocol is implemented in a straightforward way. It keeps
- two lists of static routes: one containing interface routes and one
- holding the remaining ones. Interface routes are inserted and removed according
- to interface events received from the core via the <func/if_notify()/ hook. Routes
- pointing to a neighboring router use a sticky node in the neighbor cache
- to be notified about gaining or losing the neighbor. Special
- routes like black holes or rejects are inserted all the time.
- <p>
- Multipath routes are tricky. Because these routes depends on
- several neighbors we need to integrate that to the neighbor
- notification handling, we use dummy static_route nodes, one for
- each nexthop. Therefore, a multipath route consists of a master
- static_route node (of dest RTD_MULTIPATH), which specifies prefix
- and is used in most circumstances, and a list of dummy static_route
- nodes (of dest RTD_NONE), which stores info about nexthops and are
- connected to neighbor entries and neighbor notifications. Dummy
- nodes are chained using mp_next, they aren't in other_routes list,
- and abuse some fields (masklen, if_name) for other purposes.
- <p>
- The only other thing worth mentioning is that when asked for reconfiguration,
- Static not only compares the two configurations, but it also calculates
- difference between the lists of static routes and it just inserts the
- newly added routes and removes the obsolete ones.
-
-
-<sect>Direct
-<p>
- <p>
- The Direct protocol works by converting all <func/ifa_notify()/ events it receives
- to <func/rte_update()/ calls for the corresponding network.
-
-
-<!--
- BIRD Programmer's Guide: Sysdeps
-
- (c) 2000 Martin Mares <mj@ucw.cz>
--->
-
-<chapt>System dependent parts
-
-<sect>Introduction
-
-<p>We've tried to make BIRD as portable as possible, but unfortunately
-communication with the network stack differs from one OS to another,
-so we need at least some OS specific code. The good news is that this
-code is isolated in a small set of modules:
-
-<descrip>
-<tagp><tt/config.h/</tagp> is a header file with configuration information,
-definition of the standard set of types and so on.
-<tagp/Startup module/ controls BIRD startup. Common for a family of OS's (e.g.,
-for all Unices).
-<tagp/Logging module/ manages the system logs. [per OS family]
-<tagp/IO module/ gives an implementation of sockets, timers and the
-global event queue. [per OS family]
-<tagp/KRT module/ implements the Kernel and Device protocols. This
-is the most arcane part of the system dependent stuff and some
-functions differ even between various releases of a single OS.
-</descrip>
-<sect>Logging
-<p>
- <p>
- The Logging module offers a simple set of functions for writing
- messages to system logs and to the debug output. Message classes
- used by this module are described in <tt>birdlib.h</tt> and also in the
- user's manual.
-
-
-<function><p><type>void</type>
-<funcdef>log_commit</funcdef>
-(<type>int</type> <param>class</param>, <type>buffer *</type> <param>buf</param>) -- commit a log message
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>int</type> <param>class</param></tagp>
- message class information (<const/L_DEBUG/ to <const/L_BUG/, see <tt>lib/birdlib.h</tt>)
-<tagp><type>buffer *</type> <param>buf</param></tagp>
- message to write
-</descrip>
-<funcsect>Description
-<p>
- This function writes a message prepared in the log buffer to the
- log file (as specified in the configuration). The log buffer is
- reset after that. The log message is a full line, <func/log_commit()/
- terminates it.
- <p>
- The message class is an integer, not a first char of a string like
- in <func/log()/, so it should be written like *L_INFO.
-</function>
-<function><p><type>void</type>
-<funcdef>log_msg</funcdef>
-(<type>const char *</type> <param>msg</param>, <type>...</type> <param>...</param>) -- log a message
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>const char *</type> <param>msg</param></tagp>
- printf-like formatting string with message class information
- prepended (<const/L_DEBUG/ to <const/L_BUG/, see <tt>lib/birdlib.h</tt>)
-<tagp><type>...</type> <param>...</param></tagp>
- variable arguments
-</descrip>
-<funcsect>Description
-<p>
- This function formats a message according to the format string <param/msg/
- and writes it to the corresponding log file (as specified in the
- configuration). Please note that the message is automatically
- formatted as a full line, no need to include <tt>\n</tt> inside.
- It is essentially a sequence of <func/log_reset()/, <func/logn()/ and <func/log_commit()/.
-</function>
-<function><p><type>void</type>
-<funcdef>bug</funcdef>
-(<type>const char *</type> <param>msg</param>, <type>...</type> <param>...</param>) -- report an internal error
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>const char *</type> <param>msg</param></tagp>
- a printf-like error message
-<tagp><type>...</type> <param>...</param></tagp>
- variable arguments
-</descrip>
-<funcsect>Description
-<p>
- This function logs an internal error and aborts execution
- of the program.
-</function>
-<function><p><type>void</type>
-<funcdef>die</funcdef>
-(<type>const char *</type> <param>msg</param>, <type>...</type> <param>...</param>) -- report a fatal error
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>const char *</type> <param>msg</param></tagp>
- a printf-like error message
-<tagp><type>...</type> <param>...</param></tagp>
- variable arguments
-</descrip>
-<funcsect>Description
-<p>
- This function logs a fatal error and aborts execution
- of the program.
-</function>
-<function><p><type>void</type>
-<funcdef>debug</funcdef>
-(<type>const char *</type> <param>msg</param>, <type>...</type> <param>...</param>) -- write to debug output
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>const char *</type> <param>msg</param></tagp>
- a printf-like message
-<tagp><type>...</type> <param>...</param></tagp>
- variable arguments
-</descrip>
-<funcsect>Description
-<p>
- This function formats the message <param/msg/ and prints it out
- to the debugging output. No newline character is appended.
-</function>
-<sect>Kernel synchronization
-<p>
- <p>
- This system dependent module implements the Kernel and Device protocol,
- that is synchronization of interface lists and routing tables with the
- OS kernel.
- <p>
- The whole kernel synchronization is a bit messy and touches some internals
- of the routing table engine, because routing table maintenance is a typical
- example of the proverbial compatibility between different Unices and we want
- to keep the overhead of our KRT business as low as possible and avoid maintaining
- a local routing table copy.
- <p>
- The kernel syncer can work in three different modes (according to system config header):
- Either with a single routing table and single KRT protocol [traditional UNIX]
- or with many routing tables and separate KRT protocols for all of them
- or with many routing tables, but every scan including all tables, so we start
- separate KRT protocols which cooperate with each other [Linux].
- In this case, we keep only a single scan timer.
- <p>
- We use FIB node flags in the routing table to keep track of route
- synchronization status. We also attach temporary <struct/rte/'s to the routing table,
- but it cannot do any harm to the rest of BIRD since table synchronization is
- an atomic process.
- <p>
- When starting up, we cheat by looking if there is another
- KRT instance to be initialized later and performing table scan
- only once for all the instances.
- <p>
- The code uses OS-dependent parts for kernel updates and scans. These parts are
- in more specific sysdep directories (e.g. sysdep/linux) in functions krt_sys_*
- and kif_sys_* (and some others like <func/krt_replace_rte()/) and krt-sys.h header file.
- This is also used for platform specific protocol options and route attributes.
- <p>
- There was also an old code that used traditional UNIX ioctls for these tasks.
- It was unmaintained and later removed. For reference, see sysdep/krt-* files
- in commit 396dfa9042305f62da1f56589c4b98fac57fc2f6
-
-
-<chapt>Library functions
-<sect>IP addresses
-<p>
- <p>
- BIRD uses its own abstraction of IP address in order to share the same
- code for both IPv4 and IPv6. IP addresses are represented as entities
- of type <struct/ip_addr/ which are never to be treated as numbers and instead
- they must be manipulated using the following functions and macros.
-
-
-<function><p><type>char *</type>
-<funcdef>ip_scope_text</funcdef>
-(<type>uint</type> <param>scope</param>) -- get textual representation of address scope
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>uint</type> <param>scope</param></tagp>
- scope (<const/SCOPE_xxx/)
-</descrip>
-<funcsect>Description
-<p>
- Returns a pointer to a textual name of the scope given.
-</function>
-<function><p><type>int</type>
-<funcdef>ipa_equal</funcdef>
-(<type>ip_addr</type> <param>x</param>, <type>ip_addr</type> <param>y</param>) -- compare two IP addresses for equality
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>ip_addr</type> <param>x</param></tagp>
- IP address
-<tagp><type>ip_addr</type> <param>y</param></tagp>
- IP address
-</descrip>
-<funcsect>Description
-<p>
- <func/ipa_equal()/ returns 1 if <param/x/ and <param/y/ represent the same IP address, else 0.
-</function>
-<function><p><type>int</type>
-<funcdef>ipa_nonzero</funcdef>
-(<type>ip_addr</type> <param>x</param>) -- test if an IP address is defined
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>ip_addr</type> <param>x</param></tagp>
- IP address
-</descrip>
-<funcsect>Description
-<p>
- ipa_nonzero returns 1 if <param/x/ is a defined IP address (not all bits are zero),
- else 0.
- <p>
- The undefined all-zero address is reachable as a <tt>IPA_NONE</tt> macro.
-</function>
-<function><p><type>ip_addr</type>
-<funcdef>ipa_and</funcdef>
-(<type>ip_addr</type> <param>x</param>, <type>ip_addr</type> <param>y</param>) -- compute bitwise and of two IP addresses
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>ip_addr</type> <param>x</param></tagp>
- IP address
-<tagp><type>ip_addr</type> <param>y</param></tagp>
- IP address
-</descrip>
-<funcsect>Description
-<p>
- This function returns a bitwise and of <param/x/ and <param/y/. It's primarily
- used for network masking.
-</function>
-<function><p><type>ip_addr</type>
-<funcdef>ipa_or</funcdef>
-(<type>ip_addr</type> <param>x</param>, <type>ip_addr</type> <param>y</param>) -- compute bitwise or of two IP addresses
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>ip_addr</type> <param>x</param></tagp>
- IP address
-<tagp><type>ip_addr</type> <param>y</param></tagp>
- IP address
-</descrip>
-<funcsect>Description
-<p>
- This function returns a bitwise or of <param/x/ and <param/y/.
-</function>
-<function><p><type>ip_addr</type>
-<funcdef>ipa_xor</funcdef>
-(<type>ip_addr</type> <param>x</param>, <type>ip_addr</type> <param>y</param>) -- compute bitwise xor of two IP addresses
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>ip_addr</type> <param>x</param></tagp>
- IP address
-<tagp><type>ip_addr</type> <param>y</param></tagp>
- IP address
-</descrip>
-<funcsect>Description
-<p>
- This function returns a bitwise xor of <param/x/ and <param/y/.
-</function>
-<function><p><type>ip_addr</type>
-<funcdef>ipa_not</funcdef>
-(<type>ip_addr</type> <param>x</param>) -- compute bitwise negation of two IP addresses
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>ip_addr</type> <param>x</param></tagp>
- IP address
-</descrip>
-<funcsect>Description
-<p>
- This function returns a bitwise negation of <param/x/.
-</function>
-<function><p><type>ip_addr</type>
-<funcdef>ipa_mkmask</funcdef>
-(<type>int</type> <param>x</param>) -- create a netmask
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>int</type> <param>x</param></tagp>
- prefix length
-</descrip>
-<funcsect>Description
-<p>
- This function returns an <struct/ip_addr/ corresponding of a netmask
- of an address prefix of size <param/x/.
-</function>
-<function><p><type>int</type>
-<funcdef>ipa_masklen</funcdef>
-(<type>ip_addr</type> <param>x</param>) -- calculate netmask length
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>ip_addr</type> <param>x</param></tagp>
- IP address
-</descrip>
-<funcsect>Description
-<p>
- This function checks whether <param/x/ represents a valid netmask and
- returns the size of the associate network prefix or -1 for invalid
- mask.
-</function>
-<function><p><type>int</type>
-<funcdef>ipa_hash</funcdef>
-(<type>ip_addr</type> <param>x</param>) -- hash IP addresses
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>ip_addr</type> <param>x</param></tagp>
- IP address
-</descrip>
-<funcsect>Description
-<p>
- <func/ipa_hash()/ returns a 16-bit hash value of the IP address <param/x/.
-</function>
-<function><p><type>void</type>
-<funcdef>ipa_hton</funcdef>
-(<type>ip_addr</type> <param>x</param>) -- convert IP address to network order
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>ip_addr</type> <param>x</param></tagp>
- IP address
-</descrip>
-<funcsect>Description
-<p>
- Converts the IP address <param/x/ to the network byte order.
- <p>
- Beware, this is a macro and it alters the argument!
-</function>
-<function><p><type>void</type>
-<funcdef>ipa_ntoh</funcdef>
-(<type>ip_addr</type> <param>x</param>) -- convert IP address to host order
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>ip_addr</type> <param>x</param></tagp>
- IP address
-</descrip>
-<funcsect>Description
-<p>
- Converts the IP address <param/x/ from the network byte order.
- <p>
- Beware, this is a macro and it alters the argument!
-</function>
-<function><p><type>int</type>
-<funcdef>ipa_classify</funcdef>
-(<type>ip_addr</type> <param>x</param>) -- classify an IP address
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>ip_addr</type> <param>x</param></tagp>
- IP address
-</descrip>
-<funcsect>Description
-<p>
- <func/ipa_classify()/ returns an address class of <param/x/, that is a bitwise or
- of address type (<const/IADDR_INVALID/, <const/IADDR_HOST/, <const/IADDR_BROADCAST/, <const/IADDR_MULTICAST/)
- with address scope (<const/SCOPE_HOST/ to <const/SCOPE_UNIVERSE/) or -1 (<const/IADDR_INVALID/)
- for an invalid address.
-</function>
-<function><p><type>ip4_addr</type>
-<funcdef>ip4_class_mask</funcdef>
-(<type>ip4_addr</type> <param>x</param>) -- guess netmask according to address class
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>ip4_addr</type> <param>x</param></tagp>
- IPv4 address
-</descrip>
-<funcsect>Description
-<p>
- This function (available in IPv4 version only) returns a
- network mask according to the address class of <param/x/. Although
- classful addressing is nowadays obsolete, there still live
- routing protocols transferring no prefix lengths nor netmasks
- and this function could be useful to them.
-</function>
-<function><p><type>u32</type>
-<funcdef>ipa_from_u32</funcdef>
-(<type>ip_addr</type> <param>x</param>) -- convert IPv4 address to an integer
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>ip_addr</type> <param>x</param></tagp>
- IP address
-</descrip>
-<funcsect>Description
-<p>
- This function takes an IPv4 address and returns its numeric
- representation.
-</function>
-<function><p><type>ip_addr</type>
-<funcdef>ipa_to_u32</funcdef>
-(<type>u32</type> <param>x</param>) -- convert integer to IPv4 address
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>u32</type> <param>x</param></tagp>
- a 32-bit integer
-</descrip>
-<funcsect>Description
-<p>
- <func/ipa_to_u32()/ takes a numeric representation of an IPv4 address
- and converts it to the corresponding <struct/ip_addr/.
-</function>
-<function><p><type>int</type>
-<funcdef>ipa_compare</funcdef>
-(<type>ip_addr</type> <param>x</param>, <type>ip_addr</type> <param>y</param>) -- compare two IP addresses for order
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>ip_addr</type> <param>x</param></tagp>
- IP address
-<tagp><type>ip_addr</type> <param>y</param></tagp>
- IP address
-</descrip>
-<funcsect>Description
-<p>
- The <func/ipa_compare()/ function takes two IP addresses and returns
- -1 if <param/x/ is less than <param/y/ in canonical ordering (lexicographical
- order of the bit strings), 1 if <param/x/ is greater than <param/y/ and 0
- if they are the same.
-</function>
-<function><p><type>ip_addr</type>
-<funcdef>ipa_build6</funcdef>
-(<type>u32</type> <param>a1</param>, <type>u32</type> <param>a2</param>, <type>u32</type> <param>a3</param>, <type>u32</type> <param>a4</param>) -- build an IPv6 address from parts
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>u32</type> <param>a1</param></tagp>
- part #1
-<tagp><type>u32</type> <param>a2</param></tagp>
- part #2
-<tagp><type>u32</type> <param>a3</param></tagp>
- part #3
-<tagp><type>u32</type> <param>a4</param></tagp>
- part #4
-</descrip>
-<funcsect>Description
-<p>
- <func/ipa_build()/ takes <param/a1/ to <param/a4/ and assembles them to a single IPv6
- address. It's used for example when a protocol wants to bind its
- socket to a hard-wired multicast address.
-</function>
-<function><p><type>char *</type>
-<funcdef>ip_ntop</funcdef>
-(<type>ip_addr</type> <param>a</param>, <type>char *</type> <param>buf</param>) -- convert IP address to textual representation
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>ip_addr</type> <param>a</param></tagp>
- IP address
-<tagp><type>char *</type> <param>buf</param></tagp>
- buffer of size at least <const/STD_ADDRESS_P_LENGTH/
-</descrip>
-<funcsect>Description
-<p>
- This function takes an IP address and creates its textual
- representation for presenting to the user.
-</function>
-<function><p><type>char *</type>
-<funcdef>ip_ntox</funcdef>
-(<type>ip_addr</type> <param>a</param>, <type>char *</type> <param>buf</param>) -- convert IP address to hexadecimal representation
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>ip_addr</type> <param>a</param></tagp>
- IP address
-<tagp><type>char *</type> <param>buf</param></tagp>
- buffer of size at least <const/STD_ADDRESS_P_LENGTH/
-</descrip>
-<funcsect>Description
-<p>
- This function takes an IP address and creates its hexadecimal
- textual representation. Primary use: debugging dumps.
-</function>
-<function><p><type>int</type>
-<funcdef>ip_pton</funcdef>
-(<type>char *</type> <param>a</param>, <type>ip_addr *</type> <param>o</param>) -- parse textual representation of IP address
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>char *</type> <param>a</param></tagp>
- textual representation
-<tagp><type>ip_addr *</type> <param>o</param></tagp>
- where to put the resulting address
-</descrip>
-<funcsect>Description
-<p>
- This function parses a textual IP address representation and
- stores the decoded address to a variable pointed to by <param/o/.
- Returns 0 if a parse error has occurred, else 0.
-</function>
-<sect>Linked lists
-<p>
- <p>
- The BIRD library provides a set of functions for operating on linked
- lists. The lists are internally represented as standard doubly linked
- lists with synthetic head and tail which makes all the basic operations
- run in constant time and contain no extra end-of-list checks. Each list
- is described by a <struct/list/ structure, nodes can have any format as long
- as they start with a <struct/node/ structure. If you want your nodes to belong
- to multiple lists at once, you can embed multiple <struct/node/ structures in them
- and use the <func/SKIP_BACK()/ macro to calculate a pointer to the start of the
- structure from a <struct/node/ pointer, but beware of obscurity.
- <p>
- There also exist safe linked lists (<struct/slist/, <struct/snode/ and all functions
- being prefixed with <tt>s_</tt>) which support asynchronous walking very
- similar to that used in the <struct/fib/ structure.
-
-
-<function><p><type>LIST_INLINE void</type>
-<funcdef>add_tail</funcdef>
-(<type>list *</type> <param>l</param>, <type>node *</type> <param>n</param>) -- append a node to a list
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>list *</type> <param>l</param></tagp>
- linked list
-<tagp><type>node *</type> <param>n</param></tagp>
- list node
-</descrip>
-<funcsect>Description
-<p>
- <func/add_tail()/ takes a node <param/n/ and appends it at the end of the list <param/l/.
-</function>
-<function><p><type>LIST_INLINE void</type>
-<funcdef>add_head</funcdef>
-(<type>list *</type> <param>l</param>, <type>node *</type> <param>n</param>) -- prepend a node to a list
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>list *</type> <param>l</param></tagp>
- linked list
-<tagp><type>node *</type> <param>n</param></tagp>
- list node
-</descrip>
-<funcsect>Description
-<p>
- <func/add_head()/ takes a node <param/n/ and prepends it at the start of the list <param/l/.
-</function>
-<function><p><type>LIST_INLINE void</type>
-<funcdef>insert_node</funcdef>
-(<type>node *</type> <param>n</param>, <type>node *</type> <param>after</param>) -- insert a node to a list
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>node *</type> <param>n</param></tagp>
- a new list node
-<tagp><type>node *</type> <param>after</param></tagp>
- a node of a list
-</descrip>
-<funcsect>Description
-<p>
- Inserts a node <param/n/ to a linked list after an already inserted
- node <param/after/.
-</function>
-<function><p><type>LIST_INLINE void</type>
-<funcdef>rem_node</funcdef>
-(<type>node *</type> <param>n</param>) -- remove a node from a list
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>node *</type> <param>n</param></tagp>
- node to be removed
-</descrip>
-<funcsect>Description
-<p>
- Removes a node <param/n/ from the list it's linked in. Afterwards, node <param/n/ is cleared.
-</function>
-<function><p><type>LIST_INLINE void</type>
-<funcdef>replace_node</funcdef>
-(<type>node *</type> <param>old</param>, <type>node *</type> <param>new</param>) -- replace a node in a list with another one
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>node *</type> <param>old</param></tagp>
- node to be removed
-<tagp><type>node *</type> <param>new</param></tagp>
- node to be inserted
-</descrip>
-<funcsect>Description
-<p>
- Replaces node <param/old/ in the list it's linked in with node <param/new/. Node
- <param/old/ may be a copy of the original node, which is not accessed
- through the list. The function could be called with <param/old/ == <param/new/,
- which just fixes neighbors' pointers in the case that the node
- was reallocated.
-</function>
-<function><p><type>LIST_INLINE void</type>
-<funcdef>init_list</funcdef>
-(<type>list *</type> <param>l</param>) -- create an empty list
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>list *</type> <param>l</param></tagp>
- list
-</descrip>
-<funcsect>Description
-<p>
- <func/init_list()/ takes a <struct/list/ structure and initializes its
- fields, so that it represents an empty list.
-</function>
-<function><p><type>LIST_INLINE void</type>
-<funcdef>add_tail_list</funcdef>
-(<type>list *</type> <param>to</param>, <type>list *</type> <param>l</param>) -- concatenate two lists
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>list *</type> <param>to</param></tagp>
- destination list
-<tagp><type>list *</type> <param>l</param></tagp>
- source list
-</descrip>
-<funcsect>Description
-<p>
- This function appends all elements of the list <param/l/ to
- the list <param/to/ in constant time.
-</function>
-<sect>Miscellaneous functions.
-<p>
-
-
-<function><p><type>int</type>
-<funcdef>ipsum_verify</funcdef>
-(<type>void *</type> <param>frag</param>, <type>uint</type> <param>len</param>, <type>...</type> <param>...</param>) -- verify an IP checksum
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>void *</type> <param>frag</param></tagp>
- first packet fragment
-<tagp><type>uint</type> <param>len</param></tagp>
- length in bytes
-<tagp><type>...</type> <param>...</param></tagp>
- variable arguments
-</descrip>
-<funcsect>Description
-<p>
- This function verifies whether a given fragmented packet
- has correct one's complement checksum as used by the IP
- protocol.
- <p>
- It uses all the clever tricks described in RFC 1071 to speed
- up checksum calculation as much as possible.
-<funcsect>Result
-<p>
- 1 if the checksum is correct, 0 else.
-</function>
-<function><p><type>u16</type>
-<funcdef>ipsum_calculate</funcdef>
-(<type>void *</type> <param>frag</param>, <type>uint</type> <param>len</param>, <type>...</type> <param>...</param>) -- compute an IP checksum
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>void *</type> <param>frag</param></tagp>
- first packet fragment
-<tagp><type>uint</type> <param>len</param></tagp>
- length in bytes
-<tagp><type>...</type> <param>...</param></tagp>
- variable arguments
-</descrip>
-<funcsect>Description
-<p>
- This function calculates a one's complement checksum of a given fragmented
- packet.
- <p>
- It uses all the clever tricks described in RFC 1071 to speed
- up checksum calculation as much as possible.
-</function>
-<function><p><type>u32</type>
-<funcdef>u32_mkmask</funcdef>
-(<type>uint</type> <param>n</param>) -- create a bit mask
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>uint</type> <param>n</param></tagp>
- number of bits
-</descrip>
-<funcsect>Description
-<p>
- <func/u32_mkmask()/ returns an unsigned 32-bit integer which binary
- representation consists of <param/n/ ones followed by zeroes.
-</function>
-<function><p><type>int</type>
-<funcdef>u32_masklen</funcdef>
-(<type>u32</type> <param>x</param>) -- calculate length of a bit mask
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>u32</type> <param>x</param></tagp>
- bit mask
-</descrip>
-<funcsect>Description
-<p>
- This function checks whether the given integer <param/x/ represents
- a valid bit mask (binary representation contains first ones, then
- zeroes) and returns the number of ones or -1 if the mask is invalid.
-</function>
-<function><p><type>u32</type>
-<funcdef>u32_log2</funcdef>
-(<type>u32</type> <param>v</param>) -- compute a binary logarithm.
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>u32</type> <param>v</param></tagp>
- number
-</descrip>
-<funcsect>Description
-<p>
- This function computes a integral part of binary logarithm of given
- integer <param/v/ and returns it. The computed value is also an index of the
- most significant non-zero bit position.
-</function>
-<function><p><type>int</type>
-<funcdef>patmatch</funcdef>
-(<type>byte *</type> <param>p</param>, <type>byte *</type> <param>s</param>) -- match shell-like patterns
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>byte *</type> <param>p</param></tagp>
- pattern
-<tagp><type>byte *</type> <param>s</param></tagp>
- string
-</descrip>
-<funcsect>Description
-<p>
- <func/patmatch()/ returns whether given string <param/s/ matches the given shell-like
- pattern <param/p/. The patterns consist of characters (which are matched literally),
- question marks which match any single character, asterisks which match any
- (possibly empty) string of characters and backslashes which are used to
- escape any special characters and force them to be treated literally.
- <p>
- The matching process is not optimized with respect to time, so please
- avoid using this function for complex patterns.
-</function>
-<function><p><type>int</type>
-<funcdef>bvsnprintf</funcdef>
-(<type>char *</type> <param>buf</param>, <type>int</type> <param>size</param>, <type>const char *</type> <param>fmt</param>, <type>va_list</type> <param>args</param>) -- BIRD's <func/vsnprintf()/
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>char *</type> <param>buf</param></tagp>
- destination buffer
-<tagp><type>int</type> <param>size</param></tagp>
- size of the buffer
-<tagp><type>const char *</type> <param>fmt</param></tagp>
- format string
-<tagp><type>va_list</type> <param>args</param></tagp>
- a list of arguments to be formatted
-</descrip>
-<funcsect>Description
-<p>
- This functions acts like ordinary <func/sprintf()/ except that it checks
- available space to avoid buffer overflows and it allows some more
-<funcsect>format specifiers
-<p>
- <tt><const/I/</tt> for formatting of IP addresses (any non-zero
- width is automatically replaced by standard IP address width which
- depends on whether we use IPv4 or IPv6; <tt>%#I</tt> gives hexadecimal format),
- <tt><const/R/</tt> for Router / Network ID (u32 value printed as IPv4 address)
- <tt><const/lR/</tt> for 64bit Router / Network ID (u64 value printed as eight :-separated octets)
- and <tt><const/m/</tt> resp. <tt><const/M/</tt> for error messages (uses <func/strerror()/ to translate <param/errno/ code to
- message text). On the other hand, it doesn't support floating
- point numbers.
-<funcsect>Result
-<p>
- number of characters of the output string or -1 if
- the buffer space was insufficient.
-</function>
-<function><p><type>int</type>
-<funcdef>bvsprintf</funcdef>
-(<type>char *</type> <param>buf</param>, <type>const char *</type> <param>fmt</param>, <type>va_list</type> <param>args</param>) -- BIRD's <func/vsprintf()/
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>char *</type> <param>buf</param></tagp>
- buffer
-<tagp><type>const char *</type> <param>fmt</param></tagp>
- format string
-<tagp><type>va_list</type> <param>args</param></tagp>
- a list of arguments to be formatted
-</descrip>
-<funcsect>Description
-<p>
- This function is equivalent to <func/bvsnprintf()/ with an infinite
- buffer size. Please use carefully only when you are absolutely
- sure the buffer won't overflow.
-</function>
-<function><p><type>int</type>
-<funcdef>bsprintf</funcdef>
-(<type>char *</type> <param>buf</param>, <type>const char *</type> <param>fmt</param>, <type>...</type> <param>...</param>) -- BIRD's <func/sprintf()/
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>char *</type> <param>buf</param></tagp>
- buffer
-<tagp><type>const char *</type> <param>fmt</param></tagp>
- format string
-<tagp><type>...</type> <param>...</param></tagp>
- variable arguments
-</descrip>
-<funcsect>Description
-<p>
- This function is equivalent to <func/bvsnprintf()/ with an infinite
- buffer size and variable arguments instead of a <struct/va_list/.
- Please use carefully only when you are absolutely
- sure the buffer won't overflow.
-</function>
-<function><p><type>int</type>
-<funcdef>bsnprintf</funcdef>
-(<type>char *</type> <param>buf</param>, <type>int</type> <param>size</param>, <type>const char *</type> <param>fmt</param>, <type>...</type> <param>...</param>) -- BIRD's <func/snprintf()/
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>char *</type> <param>buf</param></tagp>
- buffer
-<tagp><type>int</type> <param>size</param></tagp>
- buffer size
-<tagp><type>const char *</type> <param>fmt</param></tagp>
- format string
-<tagp><type>...</type> <param>...</param></tagp>
- variable arguments
-</descrip>
-<funcsect>Description
-<p>
- This function is equivalent to <func/bsnprintf()/ with variable arguments instead of a <struct/va_list/.
-</function>
-<function><p><type>void *</type>
-<funcdef>xmalloc</funcdef>
-(<type>uint</type> <param>size</param>) -- malloc with checking
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>uint</type> <param>size</param></tagp>
- block size
-</descrip>
-<funcsect>Description
-<p>
- This function is equivalent to <func/malloc()/ except that in case of
- failure it calls <func/die()/ to quit the program instead of returning
- a <const/NULL/ pointer.
- <p>
- Wherever possible, please use the memory resources instead.
-</function>
-<function><p><type>void *</type>
-<funcdef>xrealloc</funcdef>
-(<type>void *</type> <param>ptr</param>, <type>uint</type> <param>size</param>) -- realloc with checking
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>void *</type> <param>ptr</param></tagp>
- original memory block
-<tagp><type>uint</type> <param>size</param></tagp>
- block size
-</descrip>
-<funcsect>Description
-<p>
- This function is equivalent to <func/realloc()/ except that in case of
- failure it calls <func/die()/ to quit the program instead of returning
- a <const/NULL/ pointer.
- <p>
- Wherever possible, please use the memory resources instead.
-</function>
-<sect>Message authentication codes
-<p>
- <p>
- MAC algorithms are simple cryptographic tools for message authentication.
- They use shared a secret key a and message text to generate authentication
- code, which is then passed with the message to the other side, where the code
- is verified. There are multiple families of MAC algorithms based on different
- cryptographic primitives, BIRD implements two MAC families which use hash
- functions.
- <p>
- The first family is simply a cryptographic hash camouflaged as MAC algorithm.
- Originally supposed to be (m|k)-hash (message is concatenated with key, and
- that is hashed), but later it turned out that a raw hash is more practical.
- This is used for cryptographic authentication in OSPFv2, RIP and BFD.
- <p>
- The second family is the standard HMAC (RFC 2104), using inner and outer hash
- to process key and message. HMAC (with SHA) is used in advanced OSPF and RIP
- authentication (RFC 5709, RFC 4822).
-
-
-<function><p><type>void</type>
-<funcdef>mac_init</funcdef>
-(<type>struct mac_context *</type> <param>ctx</param>, <type>uint</type> <param>id</param>, <type>const byte *</type> <param>key</param>, <type>uint</type> <param>keylen</param>) -- initialize MAC algorithm
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>struct mac_context *</type> <param>ctx</param></tagp>
- context to initialize
-<tagp><type>uint</type> <param>id</param></tagp>
- MAC algorithm ID
-<tagp><type>const byte *</type> <param>key</param></tagp>
- MAC key
-<tagp><type>uint</type> <param>keylen</param></tagp>
- MAC key length
-</descrip>
-<funcsect>Description
-<p>
- Initialize MAC context <param/ctx/ for algorithm <param/id/ (e.g., <const/ALG_HMAC_SHA1/), with
- key <param/key/ of length <param/keylen/. After that, message data could be added using
- <func/mac_update()/ function.
-</function>
-<function><p><type>void</type>
-<funcdef>mac_update</funcdef>
-(<type>struct mac_context *</type> <param>ctx</param>, <type>const byte *</type> <param>data</param>, <type>uint</type> <param>datalen</param>) -- add more data to MAC algorithm
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>struct mac_context *</type> <param>ctx</param></tagp>
- MAC context
-<tagp><type>const byte *</type> <param>data</param></tagp>
- data to add
-<tagp><type>uint</type> <param>datalen</param></tagp>
- length of data
-</descrip>
-<funcsect>Description
-<p>
- Push another <param/datalen/ bytes of data pointed to by <param/data/ into the MAC
- algorithm currently in <param/ctx/. Can be called multiple times for the same MAC
- context. It has the same effect as concatenating all the data together and
- passing them at once.
-</function>
-<function><p><type>byte *</type>
-<funcdef>mac_final</funcdef>
-(<type>struct mac_context *</type> <param>ctx</param>) -- finalize MAC algorithm
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>struct mac_context *</type> <param>ctx</param></tagp>
- MAC context
-</descrip>
-<funcsect>Description
-<p>
- Finish MAC computation and return a pointer to the result. No more
- <param/mac_update/() calls could be done, but the context may be reinitialized
- later.
- <p>
- Note that the returned pointer points into data in the <param/ctx/ context. If it
- ceases to exist, the pointer becomes invalid.
-</function>
-<function><p><type>void</type>
-<funcdef>mac_cleanup</funcdef>
-(<type>struct mac_context *</type> <param>ctx</param>) -- cleanup MAC context
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>struct mac_context *</type> <param>ctx</param></tagp>
- MAC context
-</descrip>
-<funcsect>Description
-<p>
- Cleanup MAC context after computation (by filling with zeros). Not strictly
- necessary, just to erase sensitive data from stack. This also invalidates the
- pointer returned by <param/mac_final/().
-</function>
-<function><p><type>void</type>
-<funcdef>mac_fill</funcdef>
-(<type>uint</type> <param>id</param>, <type>const byte *</type> <param>key</param>, <type>uint</type> <param>keylen</param>, <type>const byte *</type> <param>data</param>, <type>uint</type> <param>datalen</param>, <type>byte *</type> <param>mac</param>) -- compute and fill MAC
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>uint</type> <param>id</param></tagp>
- MAC algorithm ID
-<tagp><type>const byte *</type> <param>key</param></tagp>
- secret key
-<tagp><type>uint</type> <param>keylen</param></tagp>
- key length
-<tagp><type>const byte *</type> <param>data</param></tagp>
- message data
-<tagp><type>uint</type> <param>datalen</param></tagp>
- message length
-<tagp><type>byte *</type> <param>mac</param></tagp>
- place to fill MAC
-</descrip>
-<funcsect>Description
-<p>
- Compute MAC for specified key <param/key/ and message <param/data/ using algorithm <param/id/ and
- copy it to buffer <param/mac/. <func/mac_fill()/ is a shortcut function doing all usual
- steps for transmitted messages.
-</function>
-<function><p><type>int</type>
-<funcdef>mac_verify</funcdef>
-(<type>uint</type> <param>id</param>, <type>const byte *</type> <param>key</param>, <type>uint</type> <param>keylen</param>, <type>const byte *</type> <param>data</param>, <type>uint</type> <param>datalen</param>, <type>const byte *</type> <param>mac</param>) -- compute and verify MAC
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>uint</type> <param>id</param></tagp>
- MAC algorithm ID
-<tagp><type>const byte *</type> <param>key</param></tagp>
- secret key
-<tagp><type>uint</type> <param>keylen</param></tagp>
- key length
-<tagp><type>const byte *</type> <param>data</param></tagp>
- message data
-<tagp><type>uint</type> <param>datalen</param></tagp>
- message length
-<tagp><type>const byte *</type> <param>mac</param></tagp>
- received MAC
-</descrip>
-<funcsect>Description
-<p>
- Compute MAC for specified key <param/key/ and message <param/data/ using algorithm <param/id/ and
- compare it with received <param/mac/, return whether they are the same. <func/mac_verify()/
- is a shortcut function doing all usual steps for received messages.
-</function>
-<!--
- BIRD Programmer's Guide: Resources
-
- (c) 2000 Martin Mares <mj@ucw.cz>
--->
-
-<chapt>Resources
-
-<sect>Introduction
-
-<p>Most large software projects implemented in classical procedural
-programming languages usually end up with lots of code taking care
-of resource allocation and deallocation. Bugs in such code are often
-very difficult to find, because they cause only `resource leakage',
-that is keeping a lot of memory and other resources which nobody
-references to.
-
-<p>We've tried to solve this problem by employing a resource tracking
-system which keeps track of all the resources allocated by all the
-modules of BIRD, deallocates everything automatically when a module
-shuts down and it is able to print out the list of resources and
-the corresponding modules they are allocated by.
-
-<p>Each allocated resource (from now we'll speak about allocated
-resources only) is represented by a structure starting with a standard
-header (struct <struct/resource/) consisting of a list node (resources are
-often linked to various lists) and a pointer to <struct/resclass/ -- a resource
-class structure pointing to functions implementing generic resource
-operations (such as freeing of the resource) for the particular resource
-type.
-
-<p>There exist the following types of resources:
-
-<itemize>
-<item><it/Resource pools/ (<struct/pool/)
-<item><it/Memory blocks/
-<item><it/Linear memory pools/ (<struct/linpool/)
-<item><it/Slabs/ (<struct/slab/)
-<item><it/Events/ (<struct/event/)
-<item><it/Timers/ (<struct/timer/)
-<item><it/Sockets/ (<struct/socket/)
-</itemize>
-<sect>Resource pools
-<p>
- <p>
- Resource pools (<struct/pool/) are just containers holding a list of
- other resources. Freeing a pool causes all the listed resources
- to be freed as well. Each existing <struct/resource/ is linked to some pool
- except for a root pool which isn't linked anywhere, so all the
- resources form a tree structure with internal nodes corresponding
- to pools and leaves being the other resources.
- <p>
- Example: Almost all modules of BIRD have their private pool which
- is freed upon shutdown of the module.
-
-
-<function><p><type>pool *</type>
-<funcdef>rp_new</funcdef>
-(<type>pool *</type> <param>p</param>, <type>char *</type> <param>name</param>) -- create a resource pool
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>pool *</type> <param>p</param></tagp>
- parent pool
-<tagp><type>char *</type> <param>name</param></tagp>
- pool name (to be included in debugging dumps)
-</descrip>
-<funcsect>Description
-<p>
- <func/rp_new()/ creates a new resource pool inside the specified
- parent pool.
-</function>
-<function><p><type>void</type>
-<funcdef>rmove</funcdef>
-(<type>void *</type> <param>res</param>, <type>pool *</type> <param>p</param>) -- move a resource
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>void *</type> <param>res</param></tagp>
- resource
-<tagp><type>pool *</type> <param>p</param></tagp>
- pool to move the resource to
-</descrip>
-<funcsect>Description
-<p>
- <func/rmove()/ moves a resource from one pool to another.
-</function>
-<function><p><type>void</type>
-<funcdef>rfree</funcdef>
-(<type>void *</type> <param>res</param>) -- free a resource
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>void *</type> <param>res</param></tagp>
- resource
-</descrip>
-<funcsect>Description
-<p>
- <func/rfree()/ frees the given resource and all information associated
- with it. In case it's a resource pool, it also frees all the objects
- living inside the pool.
- <p>
- It works by calling a class-specific freeing function.
-</function>
-<function><p><type>void</type>
-<funcdef>rdump</funcdef>
-(<type>void *</type> <param>res</param>) -- dump a resource
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>void *</type> <param>res</param></tagp>
- resource
-</descrip>
-<funcsect>Description
-<p>
- This function prints out all available information about the given
- resource to the debugging output.
- <p>
- It works by calling a class-specific dump function.
-</function>
-<function><p><type>void *</type>
-<funcdef>ralloc</funcdef>
-(<type>pool *</type> <param>p</param>, <type>struct resclass *</type> <param>c</param>) -- create a resource
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>pool *</type> <param>p</param></tagp>
- pool to create the resource in
-<tagp><type>struct resclass *</type> <param>c</param></tagp>
- class of the new resource
-</descrip>
-<funcsect>Description
-<p>
- This function is called by the resource classes to create a new
- resource of the specified class and link it to the given pool.
- Allocated memory is zeroed. Size of the resource structure is taken
- from the <param/size/ field of the <struct/resclass/.
-</function>
-<function><p><type>void</type>
-<funcdef>rlookup</funcdef>
-(<type>unsigned long</type> <param>a</param>) -- look up a memory location
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>unsigned long</type> <param>a</param></tagp>
- memory address
-</descrip>
-<funcsect>Description
-<p>
- This function examines all existing resources to see whether
- the address <param/a/ is inside any resource. It's used for debugging
- purposes only.
- <p>
- It works by calling a class-specific lookup function for each
- resource.
-</function>
-<function><p><type>void</type>
-<funcdef>resource_init</funcdef>
-(<param>void</param>) -- initialize the resource manager
-
-<funcsect>Description
-<p>
- <p>
- This function is called during BIRD startup. It initializes
- all data structures of the resource manager and creates the
- root pool.
-</function>
-<sect>Memory blocks
-<p>
- <p>
- Memory blocks are pieces of contiguous allocated memory.
- They are a bit non-standard since they are represented not by a pointer
- to <struct/resource/, but by a void pointer to the start of data of the
- memory block. All memory block functions know how to locate the header
- given the data pointer.
- <p>
- Example: All "unique" data structures such as hash tables are allocated
- as memory blocks.
-
-
-<function><p><type>void *</type>
-<funcdef>mb_alloc</funcdef>
-(<type>pool *</type> <param>p</param>, <type>unsigned</type> <param>size</param>) -- allocate a memory block
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>pool *</type> <param>p</param></tagp>
- pool
-<tagp><type>unsigned</type> <param>size</param></tagp>
- size of the block
-</descrip>
-<funcsect>Description
-<p>
- <func/mb_alloc()/ allocates memory of a given size and creates
- a memory block resource representing this memory chunk
- in the pool <param/p/.
- <p>
- Please note that <func/mb_alloc()/ returns a pointer to the memory
- chunk, not to the resource, hence you have to free it using
- <func/mb_free()/, not <func/rfree()/.
-</function>
-<function><p><type>void *</type>
-<funcdef>mb_allocz</funcdef>
-(<type>pool *</type> <param>p</param>, <type>unsigned</type> <param>size</param>) -- allocate and clear a memory block
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>pool *</type> <param>p</param></tagp>
- pool
-<tagp><type>unsigned</type> <param>size</param></tagp>
- size of the block
-</descrip>
-<funcsect>Description
-<p>
- <func/mb_allocz()/ allocates memory of a given size, initializes it to
- zeroes and creates a memory block resource representing this memory
- chunk in the pool <param/p/.
- <p>
- Please note that <func/mb_allocz()/ returns a pointer to the memory
- chunk, not to the resource, hence you have to free it using
- <func/mb_free()/, not <func/rfree()/.
-</function>
-<function><p><type>void *</type>
-<funcdef>mb_realloc</funcdef>
-(<type>void *</type> <param>m</param>, <type>unsigned</type> <param>size</param>) -- reallocate a memory block
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>void *</type> <param>m</param></tagp>
- memory block
-<tagp><type>unsigned</type> <param>size</param></tagp>
- new size of the block
-</descrip>
-<funcsect>Description
-<p>
- <func/mb_realloc()/ changes the size of the memory block <param/m/ to a given size.
- The contents will be unchanged to the minimum of the old and new sizes;
- newly allocated memory will be uninitialized. Contrary to <func/realloc()/
- behavior, <param/m/ must be non-NULL, because the resource pool is inherited
- from it.
- <p>
- Like <func/mb_alloc()/, <func/mb_realloc()/ also returns a pointer to the memory
- chunk, not to the resource, hence you have to free it using
- <func/mb_free()/, not <func/rfree()/.
-</function>
-<function><p><type>void</type>
-<funcdef>mb_free</funcdef>
-(<type>void *</type> <param>m</param>) -- free a memory block
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>void *</type> <param>m</param></tagp>
- memory block
-</descrip>
-<funcsect>Description
-<p>
- <func/mb_free()/ frees all memory associated with the block <param/m/.
-</function>
-<sect>Linear memory pools
-<p>
- <p>
- Linear memory pools are collections of memory blocks which
- support very fast allocation of new blocks, but are able to free only
- the whole collection at once.
- <p>
- Example: Each configuration is described by a complex system of structures,
- linked lists and function trees which are all allocated from a single linear
- pool, thus they can be freed at once when the configuration is no longer used.
-
-
-<function><p><type>linpool *</type>
-<funcdef>lp_new</funcdef>
-(<type>pool *</type> <param>p</param>, <type>uint</type> <param>blk</param>) -- create a new linear memory pool
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>pool *</type> <param>p</param></tagp>
- pool
-<tagp><type>uint</type> <param>blk</param></tagp>
- block size
-</descrip>
-<funcsect>Description
-<p>
- <func/lp_new()/ creates a new linear memory pool resource inside the pool <param/p/.
- The linear pool consists of a list of memory chunks of size at least
- <param/blk/.
-</function>
-<function><p><type>void *</type>
-<funcdef>lp_alloc</funcdef>
-(<type>linpool *</type> <param>m</param>, <type>uint</type> <param>size</param>) -- allocate memory from a <struct/linpool/
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>linpool *</type> <param>m</param></tagp>
- linear memory pool
-<tagp><type>uint</type> <param>size</param></tagp>
- amount of memory
-</descrip>
-<funcsect>Description
-<p>
- <func/lp_alloc()/ allocates <param/size/ bytes of memory from a <struct/linpool/ <param/m/
- and it returns a pointer to the allocated memory.
- <p>
- It works by trying to find free space in the last memory chunk
- associated with the <struct/linpool/ and creating a new chunk of the standard
- size (as specified during <func/lp_new()/) if the free space is too small
- to satisfy the allocation. If <param/size/ is too large to fit in a standard
- size chunk, an "overflow" chunk is created for it instead.
-</function>
-<function><p><type>void *</type>
-<funcdef>lp_allocu</funcdef>
-(<type>linpool *</type> <param>m</param>, <type>uint</type> <param>size</param>) -- allocate unaligned memory from a <struct/linpool/
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>linpool *</type> <param>m</param></tagp>
- linear memory pool
-<tagp><type>uint</type> <param>size</param></tagp>
- amount of memory
-</descrip>
-<funcsect>Description
-<p>
- <func/lp_allocu()/ allocates <param/size/ bytes of memory from a <struct/linpool/ <param/m/
- and it returns a pointer to the allocated memory. It doesn't
- attempt to align the memory block, giving a very efficient way
- how to allocate strings without any space overhead.
-</function>
-<function><p><type>void *</type>
-<funcdef>lp_allocz</funcdef>
-(<type>linpool *</type> <param>m</param>, <type>uint</type> <param>size</param>) -- allocate cleared memory from a <struct/linpool/
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>linpool *</type> <param>m</param></tagp>
- linear memory pool
-<tagp><type>uint</type> <param>size</param></tagp>
- amount of memory
-</descrip>
-<funcsect>Description
-<p>
- This function is identical to <func/lp_alloc()/ except that it
- clears the allocated memory block.
-</function>
-<function><p><type>void</type>
-<funcdef>lp_flush</funcdef>
-(<type>linpool *</type> <param>m</param>) -- flush a linear memory pool
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>linpool *</type> <param>m</param></tagp>
- linear memory pool
-</descrip>
-<funcsect>Description
-<p>
- This function frees the whole contents of the given <struct/linpool/ <param/m/,
- but leaves the pool itself.
-</function>
-<sect>Slabs
-<p>
- <p>
- Slabs are collections of memory blocks of a fixed size.
- They support very fast allocation and freeing of such blocks, prevent memory
- fragmentation and optimize L2 cache usage. Slabs have been invented by Jeff Bonwick
- and published in USENIX proceedings as `The Slab Allocator: An Object-Caching Kernel
- Memory Allocator'. Our implementation follows this article except that we don't use
- constructors and destructors.
- <p>
- When the <tt>DEBUGGING</tt> switch is turned on, we automatically fill all
- newly allocated and freed blocks with a special pattern to make detection
- of use of uninitialized or already freed memory easier.
- <p>
- Example: Nodes of a FIB are allocated from a per-FIB Slab.
-
-
-<function><p><type>slab *</type>
-<funcdef>sl_new</funcdef>
-(<type>pool *</type> <param>p</param>, <type>uint</type> <param>size</param>) -- create a new Slab
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>pool *</type> <param>p</param></tagp>
- resource pool
-<tagp><type>uint</type> <param>size</param></tagp>
- block size
-</descrip>
-<funcsect>Description
-<p>
- This function creates a new Slab resource from which
- objects of size <param/size/ can be allocated.
-</function>
-<function><p><type>void *</type>
-<funcdef>sl_alloc</funcdef>
-(<type>slab *</type> <param>s</param>) -- allocate an object from Slab
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>slab *</type> <param>s</param></tagp>
- slab
-</descrip>
-<funcsect>Description
-<p>
- <func/sl_alloc()/ allocates space for a single object from the
- Slab and returns a pointer to the object.
-</function>
-<function><p><type>void</type>
-<funcdef>sl_free</funcdef>
-(<type>slab *</type> <param>s</param>, <type>void *</type> <param>oo</param>) -- return a free object back to a Slab
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>slab *</type> <param>s</param></tagp>
- slab
-<tagp><type>void *</type> <param>oo</param></tagp>
- object returned by <func/sl_alloc()/
-</descrip>
-<funcsect>Description
-<p>
- This function frees memory associated with the object <param/oo/
- and returns it back to the Slab <param/s/.
-</function>
-<sect>Events
-<p>
- <p>
- Events are there to keep track of deferred execution.
- Since BIRD is single-threaded, it requires long lasting tasks to be split to smaller
- parts, so that no module can monopolize the CPU. To split such a task, just create
- an <struct/event/ resource, point it to the function you want to have called and call <func/ev_schedule()/
- to ask the core to run the event when nothing more important requires attention.
- <p>
- You can also define your own event lists (the <struct/event_list/ structure), enqueue your
- events in them and explicitly ask to run them.
-
-
-<function><p><type>event *</type>
-<funcdef>ev_new</funcdef>
-(<type>pool *</type> <param>p</param>) -- create a new event
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>pool *</type> <param>p</param></tagp>
- resource pool
-</descrip>
-<funcsect>Description
-<p>
- This function creates a new event resource. To use it,
- you need to fill the structure fields and call <func/ev_schedule()/.
-</function>
-<function><p><type>void</type>
-<funcdef>ev_run</funcdef>
-(<type>event *</type> <param>e</param>) -- run an event
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>event *</type> <param>e</param></tagp>
- an event
-</descrip>
-<funcsect>Description
-<p>
- This function explicitly runs the event <param/e/ (calls its hook
- function) and removes it from an event list if it's linked to any.
- <p>
- From the hook function, you can call <func/ev_enqueue()/ or <func/ev_schedule()/
- to re-add the event.
-</function>
-<function><p><type>void</type>
-<funcdef>ev_enqueue</funcdef>
-(<type>event_list *</type> <param>l</param>, <type>event *</type> <param>e</param>) -- enqueue an event
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>event_list *</type> <param>l</param></tagp>
- an event list
-<tagp><type>event *</type> <param>e</param></tagp>
- an event
-</descrip>
-<funcsect>Description
-<p>
- <func/ev_enqueue()/ stores the event <param/e/ to the specified event
- list <param/l/ which can be run by calling <func/ev_run_list()/.
-</function>
-<function><p><type>void</type>
-<funcdef>ev_schedule</funcdef>
-(<type>event *</type> <param>e</param>) -- schedule an event
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>event *</type> <param>e</param></tagp>
- an event
-</descrip>
-<funcsect>Description
-<p>
- This function schedules an event by enqueueing it to a system-wide
- event list which is run by the platform dependent code whenever
- appropriate.
-</function>
-<function><p><type>int</type>
-<funcdef>ev_run_list</funcdef>
-(<type>event_list *</type> <param>l</param>) -- run an event list
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>event_list *</type> <param>l</param></tagp>
- an event list
-</descrip>
-<funcsect>Description
-<p>
- This function calls <func/ev_run()/ for all events enqueued in the list <param/l/.
-</function>
-<sect>Timers
-<p>
- <p>
- Timers are resources which represent a wish of a module to call
- a function at the specified time. The platform dependent code
- doesn't guarantee exact timing, only that a timer function
- won't be called before the requested time.
- <p>
- In BIRD, time is represented by values of the <struct/bird_clock_t/ type
- which are integral numbers interpreted as a relative number of seconds since
- some fixed time point in past. The current time can be read
- from variable <param/now/ with reasonable accuracy and is monotonic. There is also
- a current 'absolute' time in variable <param/now_real/ reported by OS.
- <p>
- Each timer is described by a <struct/timer/ structure containing a pointer
- to the handler function (<param/hook/), data private to this function (<param/data/),
- time the function should be called at (<param/expires/, 0 for inactive timers),
- for the other fields see <tt>timer.h</tt>.
-
-
-<function><p><type>timer *</type>
-<funcdef>tm_new</funcdef>
-(<type>pool *</type> <param>p</param>) -- create a timer
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>pool *</type> <param>p</param></tagp>
- pool
-</descrip>
-<funcsect>Description
-<p>
- This function creates a new timer resource and returns
- a pointer to it. To use the timer, you need to fill in
- the structure fields and call <func/tm_start()/ to start timing.
-</function>
-<function><p><type>void</type>
-<funcdef>tm_start</funcdef>
-(<type>timer *</type> <param>t</param>, <type>unsigned</type> <param>after</param>) -- start a timer
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>timer *</type> <param>t</param></tagp>
- timer
-<tagp><type>unsigned</type> <param>after</param></tagp>
- number of seconds the timer should be run after
-</descrip>
-<funcsect>Description
-<p>
- This function schedules the hook function of the timer to
- be called after <param/after/ seconds. If the timer has been already
- started, it's <param/expire/ time is replaced by the new value.
- <p>
- You can have set the <param/randomize/ field of <param/t/, the timeout
- will be increased by a random number of seconds chosen
- uniformly from range 0 .. <param/randomize/.
- <p>
- You can call <func/tm_start()/ from the handler function of the timer
- to request another run of the timer. Also, you can set the <param/recurrent/
- field to have the timer re-added automatically with the same timeout.
-</function>
-<function><p><type>void</type>
-<funcdef>tm_stop</funcdef>
-(<type>timer *</type> <param>t</param>) -- stop a timer
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>timer *</type> <param>t</param></tagp>
- timer
-</descrip>
-<funcsect>Description
-<p>
- This function stops a timer. If the timer is already stopped,
- nothing happens.
-</function>
-<function><p><type>bird_clock_t</type>
-<funcdef>tm_parse_datetime</funcdef>
-(<type>char *</type> <param>x</param>) -- parse a date and time
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>char *</type> <param>x</param></tagp>
- datetime string
-</descrip>
-<funcsect>Description
-<p>
- <func/tm_parse_datetime()/ takes a textual representation of
- a date and time (dd-mm-yyyy hh:mm:ss)
- and converts it to the corresponding value of type <struct/bird_clock_t/.
-</function>
-<function><p><type>bird_clock_t</type>
-<funcdef>tm_parse_date</funcdef>
-(<type>char *</type> <param>x</param>) -- parse a date
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>char *</type> <param>x</param></tagp>
- date string
-</descrip>
-<funcsect>Description
-<p>
- <func/tm_parse_date()/ takes a textual representation of a date (dd-mm-yyyy)
- and converts it to the corresponding value of type <struct/bird_clock_t/.
-</function>
-<function><p><type>void</type>
-<funcdef>tm_format_datetime</funcdef>
-(<type>char *</type> <param>x</param>, <type>struct timeformat *</type> <param>fmt_spec</param>, <type>bird_clock_t</type> <param>t</param>) -- convert date and time to textual representation
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>char *</type> <param>x</param></tagp>
- destination buffer of size <const/TM_DATETIME_BUFFER_SIZE/
-<tagp><type>struct timeformat *</type> <param>fmt_spec</param></tagp>
- specification of resulting textual representation of the time
-<tagp><type>bird_clock_t</type> <param>t</param></tagp>
- time
-</descrip>
-<funcsect>Description
-<p>
- This function formats the given relative time value <param/t/ to a textual
- date/time representation (dd-mm-yyyy hh:mm:ss) in real time.
-</function>
-<sect>Sockets
-<p>
- <p>
- Socket resources represent network connections. Their data structure (<struct/socket/)
- contains a lot of fields defining the exact type of the socket, the local and
- remote addresses and ports, pointers to socket buffers and finally pointers to
- hook functions to be called when new data have arrived to the receive buffer
- (<param/rx_hook/), when the contents of the transmit buffer have been transmitted
- (<param/tx_hook/) and when an error or connection close occurs (<param/err_hook/).
- <p>
- Freeing of sockets from inside socket hooks is perfectly safe.
-
-
-<function><p><type>int</type>
-<funcdef>sk_setup_multicast</funcdef>
-(<type>sock *</type> <param>s</param>) -- enable multicast for given socket
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>sock *</type> <param>s</param></tagp>
- socket
-</descrip>
-<funcsect>Description
-<p>
- Prepare transmission of multicast packets for given datagram socket.
- The socket must have defined <param/iface/.
-<funcsect>Result
-<p>
- 0 for success, -1 for an error.
-</function>
-<function><p><type>int</type>
-<funcdef>sk_join_group</funcdef>
-(<type>sock *</type> <param>s</param>, <type>ip_addr</type> <param>maddr</param>) -- join multicast group for given socket
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>sock *</type> <param>s</param></tagp>
- socket
-<tagp><type>ip_addr</type> <param>maddr</param></tagp>
- multicast address
-</descrip>
-<funcsect>Description
-<p>
- Join multicast group for given datagram socket and associated interface.
- The socket must have defined <param/iface/.
-<funcsect>Result
-<p>
- 0 for success, -1 for an error.
-</function>
-<function><p><type>int</type>
-<funcdef>sk_leave_group</funcdef>
-(<type>sock *</type> <param>s</param>, <type>ip_addr</type> <param>maddr</param>) -- leave multicast group for given socket
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>sock *</type> <param>s</param></tagp>
- socket
-<tagp><type>ip_addr</type> <param>maddr</param></tagp>
- multicast address
-</descrip>
-<funcsect>Description
-<p>
- Leave multicast group for given datagram socket and associated interface.
- The socket must have defined <param/iface/.
-<funcsect>Result
-<p>
- 0 for success, -1 for an error.
-</function>
-<function><p><type>int</type>
-<funcdef>sk_setup_broadcast</funcdef>
-(<type>sock *</type> <param>s</param>) -- enable broadcast for given socket
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>sock *</type> <param>s</param></tagp>
- socket
-</descrip>
-<funcsect>Description
-<p>
- Allow reception and transmission of broadcast packets for given datagram
- socket. The socket must have defined <param/iface/. For transmission, packets should
- be send to <param/brd/ address of <param/iface/.
-<funcsect>Result
-<p>
- 0 for success, -1 for an error.
-</function>
-<function><p><type>int</type>
-<funcdef>sk_set_ttl</funcdef>
-(<type>sock *</type> <param>s</param>, <type>int</type> <param>ttl</param>) -- set transmit TTL for given socket
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>sock *</type> <param>s</param></tagp>
- socket
-<tagp><type>int</type> <param>ttl</param></tagp>
- TTL value
-</descrip>
-<funcsect>Description
-<p>
- Set TTL for already opened connections when TTL was not set before. Useful
- for accepted connections when different ones should have different TTL.
-<funcsect>Result
-<p>
- 0 for success, -1 for an error.
-</function>
-<function><p><type>int</type>
-<funcdef>sk_set_min_ttl</funcdef>
-(<type>sock *</type> <param>s</param>, <type>int</type> <param>ttl</param>) -- set minimal accepted TTL for given socket
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>sock *</type> <param>s</param></tagp>
- socket
-<tagp><type>int</type> <param>ttl</param></tagp>
- TTL value
-</descrip>
-<funcsect>Description
-<p>
- Set minimal accepted TTL for given socket. Can be used for TTL security.
- implementations.
-<funcsect>Result
-<p>
- 0 for success, -1 for an error.
-</function>
-<function><p><type>int</type>
-<funcdef>sk_set_md5_auth</funcdef>
-(<type>sock *</type> <param>s</param>, <type>ip_addr</type> <param>local</param>, <type>ip_addr</type> <param>remote</param>, <type>struct iface *</type> <param>ifa</param>, <type>char *</type> <param>passwd</param>, <type>int</type> <param>setkey</param>) -- add / remove MD5 security association for given socket
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>sock *</type> <param>s</param></tagp>
- socket
-<tagp><type>ip_addr</type> <param>local</param></tagp>
- IP address of local side
-<tagp><type>ip_addr</type> <param>remote</param></tagp>
- IP address of remote side
-<tagp><type>struct iface *</type> <param>ifa</param></tagp>
- Interface for link-local IP address
-<tagp><type>char *</type> <param>passwd</param></tagp>
- Password used for MD5 authentication
-<tagp><type>int</type> <param>setkey</param></tagp>
- Update also system SA/SP database
-</descrip>
-<funcsect>Description
-<p>
- In TCP MD5 handling code in kernel, there is a set of security associations
- used for choosing password and other authentication parameters according to
- the local and remote address. This function is useful for listening socket,
- for active sockets it may be enough to set s-&gt;password field.
- <p>
- When called with passwd != NULL, the new pair is added,
- When called with passwd == NULL, the existing pair is removed.
- <p>
- Note that while in Linux, the MD5 SAs are specific to socket, in BSD they are
- stored in global SA/SP database (but the behavior also must be enabled on
- per-socket basis). In case of multiple sockets to the same neighbor, the
- socket-specific state must be configured for each socket while global state
- just once per src-dst pair. The <param/setkey/ argument controls whether the global
- state (SA/SP database) is also updated.
-<funcsect>Result
-<p>
- 0 for success, -1 for an error.
-</function>
-<function><p><type>int</type>
-<funcdef>sk_set_ipv6_checksum</funcdef>
-(<type>sock *</type> <param>s</param>, <type>int</type> <param>offset</param>) -- specify IPv6 checksum offset for given socket
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>sock *</type> <param>s</param></tagp>
- socket
-<tagp><type>int</type> <param>offset</param></tagp>
- offset
-</descrip>
-<funcsect>Description
-<p>
- Specify IPv6 checksum field offset for given raw IPv6 socket. After that, the
- kernel will automatically fill it for outgoing packets and check it for
- incoming packets. Should not be used on ICMPv6 sockets, where the position is
- known to the kernel.
-<funcsect>Result
-<p>
- 0 for success, -1 for an error.
-</function>
-<function><p><type>sock *</type>
-<funcdef>sock_new</funcdef>
-(<type>pool *</type> <param>p</param>) -- create a socket
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>pool *</type> <param>p</param></tagp>
- pool
-</descrip>
-<funcsect>Description
-<p>
- This function creates a new socket resource. If you want to use it,
- you need to fill in all the required fields of the structure and
- call <func/sk_open()/ to do the actual opening of the socket.
- <p>
- The real function name is <func/sock_new()/, <func/sk_new()/ is a macro wrapper
- to avoid collision with OpenSSL.
-</function>
-<function><p><type>int</type>
-<funcdef>sk_open</funcdef>
-(<type>sock *</type> <param>s</param>) -- open a socket
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>sock *</type> <param>s</param></tagp>
- socket
-</descrip>
-<funcsect>Description
-<p>
- This function takes a socket resource created by <func/sk_new()/ and
- initialized by the user and binds a corresponding network connection
- to it.
-<funcsect>Result
-<p>
- 0 for success, -1 for an error.
-</function>
-<function><p><type>int</type>
-<funcdef>sk_send</funcdef>
-(<type>sock *</type> <param>s</param>, <type>unsigned</type> <param>len</param>) -- send data to a socket
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>sock *</type> <param>s</param></tagp>
- socket
-<tagp><type>unsigned</type> <param>len</param></tagp>
- number of bytes to send
-</descrip>
-<funcsect>Description
-<p>
- This function sends <param/len/ bytes of data prepared in the
- transmit buffer of the socket <param/s/ to the network connection.
- If the packet can be sent immediately, it does so and returns
- 1, else it queues the packet for later processing, returns 0
- and calls the <param/tx_hook/ of the socket when the tranmission
- takes place.
-</function>
-<function><p><type>int</type>
-<funcdef>sk_send_to</funcdef>
-(<type>sock *</type> <param>s</param>, <type>unsigned</type> <param>len</param>, <type>ip_addr</type> <param>addr</param>, <type>unsigned</type> <param>port</param>) -- send data to a specific destination
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>sock *</type> <param>s</param></tagp>
- socket
-<tagp><type>unsigned</type> <param>len</param></tagp>
- number of bytes to send
-<tagp><type>ip_addr</type> <param>addr</param></tagp>
- IP address to send the packet to
-<tagp><type>unsigned</type> <param>port</param></tagp>
- port to send the packet to
-</descrip>
-<funcsect>Description
-<p>
- This is a <func/sk_send()/ replacement for connection-less packet sockets
- which allows destination of the packet to be chosen dynamically.
- Raw IP sockets should use 0 for <param/port/.
-</function>
-<function><p><type>void</type>
-<funcdef>io_log_event</funcdef>
-(<type>void *</type> <param>hook</param>, <type>void *</type> <param>data</param>) -- mark approaching event into event log
-
-<funcsect>Arguments
-<p><descrip>
-<tagp><type>void *</type> <param>hook</param></tagp>
- event hook address
-<tagp><type>void *</type> <param>data</param></tagp>
- event data address
-</descrip>
-<funcsect>Description
-<p>
- Store info (hook, data, timestamp) about the following internal event into
- a circular event log (<param/event_log/). When latency tracking is enabled, the log
- entry is kept open (in <param/event_open/) so the duration can be filled later.
-</function>
-
-</book>
diff --git a/doc/prog.toc b/doc/prog.toc
deleted file mode 100644
index d523433f..00000000
--- a/doc/prog.toc
+++ /dev/null
@@ -1,55 +0,0 @@
-\contentsline {chapter}{\numberline {1}BIRD Design}{4}{chapter.1}
-\contentsline {section}{\numberline {1.1}Introduction}{4}{section.1.1}
-\contentsline {section}{\numberline {1.2}Design goals}{4}{section.1.2}
-\contentsline {section}{\numberline {1.3}Architecture}{5}{section.1.3}
-\contentsline {section}{\numberline {1.4}Implementation}{5}{section.1.4}
-\contentsline {chapter}{\numberline {2}Core}{7}{chapter.2}
-\contentsline {section}{\numberline {2.1}Forwarding Information Base}{7}{section.2.1}
-\contentsline {section}{\numberline {2.2}Routing tables}{9}{section.2.2}
-\contentsline {section}{\numberline {2.3}Route attribute cache}{15}{section.2.3}
-\contentsline {section}{\numberline {2.4}Routing protocols}{20}{section.2.4}
-\contentsline {subsection}{\numberline {2.4.1}Introduction}{20}{subsection.2.4.1}
-\contentsline {subsection}{\numberline {2.4.2}Protocol states}{21}{subsection.2.4.2}
-\contentsline {subsection}{\numberline {2.4.3}Functions of the protocol module}{21}{subsection.2.4.3}
-\contentsline {section}{\numberline {2.5}Graceful restart recovery}{24}{section.2.5}
-\contentsline {section}{\numberline {2.6}Protocol hooks}{27}{section.2.6}
-\contentsline {section}{\numberline {2.7}Interfaces}{34}{section.2.7}
-\contentsline {section}{\numberline {2.8}Neighbor cache}{36}{section.2.8}
-\contentsline {section}{\numberline {2.9}Command line interface}{38}{section.2.9}
-\contentsline {section}{\numberline {2.10}Object locks}{40}{section.2.10}
-\contentsline {chapter}{\numberline {3}Configuration}{41}{chapter.3}
-\contentsline {section}{\numberline {3.1}Configuration manager}{41}{section.3.1}
-\contentsline {section}{\numberline {3.2}Lexical analyzer}{44}{section.3.2}
-\contentsline {section}{\numberline {3.3}Parser}{46}{section.3.3}
-\contentsline {chapter}{\numberline {4}Filters}{47}{chapter.4}
-\contentsline {section}{\numberline {4.1}Filters}{47}{section.4.1}
-\contentsline {section}{\numberline {4.2}Trie for prefix sets}{49}{section.4.2}
-\contentsline {chapter}{\numberline {5}Protocols}{52}{chapter.5}
-\contentsline {section}{\numberline {5.1}The Babel protocol}{52}{section.5.1}
-\contentsline {section}{\numberline {5.2}Bidirectional Forwarding Detection}{55}{section.5.2}
-\contentsline {section}{\numberline {5.3}Border Gateway Protocol}{56}{section.5.3}
-\contentsline {section}{\numberline {5.4}Multi-Threaded Routing Toolkit (MRT) protocol}{63}{section.5.4}
-\contentsline {section}{\numberline {5.5}Open Shortest Path First (OSPF)}{63}{section.5.5}
-\contentsline {section}{\numberline {5.6}Pipe}{70}{section.5.6}
-\contentsline {section}{\numberline {5.7}Routing Information Protocol (RIP)}{70}{section.5.7}
-\contentsline {section}{\numberline {5.8}Router Advertisements}{73}{section.5.8}
-\contentsline {section}{\numberline {5.9}Static}{73}{section.5.9}
-\contentsline {section}{\numberline {5.10}Direct}{74}{section.5.10}
-\contentsline {chapter}{\numberline {6}System dependent parts}{75}{chapter.6}
-\contentsline {section}{\numberline {6.1}Introduction}{75}{section.6.1}
-\contentsline {section}{\numberline {6.2}Logging}{75}{section.6.2}
-\contentsline {section}{\numberline {6.3}Kernel synchronization}{76}{section.6.3}
-\contentsline {chapter}{\numberline {7}Library functions}{78}{chapter.7}
-\contentsline {section}{\numberline {7.1}IP addresses}{78}{section.7.1}
-\contentsline {section}{\numberline {7.2}Linked lists}{82}{section.7.2}
-\contentsline {section}{\numberline {7.3}Miscellaneous functions.}{84}{section.7.3}
-\contentsline {section}{\numberline {7.4}Message authentication codes}{88}{section.7.4}
-\contentsline {chapter}{\numberline {8}Resources}{91}{chapter.8}
-\contentsline {section}{\numberline {8.1}Introduction}{91}{section.8.1}
-\contentsline {section}{\numberline {8.2}Resource pools}{91}{section.8.2}
-\contentsline {section}{\numberline {8.3}Memory blocks}{93}{section.8.3}
-\contentsline {section}{\numberline {8.4}Linear memory pools}{94}{section.8.4}
-\contentsline {section}{\numberline {8.5}Slabs}{95}{section.8.5}
-\contentsline {section}{\numberline {8.6}Events}{96}{section.8.6}
-\contentsline {section}{\numberline {8.7}Timers}{97}{section.8.7}
-\contentsline {section}{\numberline {8.8}Sockets}{99}{section.8.8}
diff --git a/filter/config.Y b/filter/config.Y
index 340053ba..5cd52e40 100644
--- a/filter/config.Y
+++ b/filter/config.Y
@@ -185,159 +185,6 @@ f_generate_empty(struct f_dynamic_attr dyn)
return f_new_inst(FI_EA_SET, f_new_inst(FI_CONSTANT, empty), dyn);
}
-#if 0
-
-static inline struct f_inst *
-f_generate_dpair(struct f_inst *t1, struct f_inst *t2)
-{
- struct f_inst *rv;
-
- if ((t1->fi_code == FI_CONSTANT) && (t2->fi_code == FI_CONSTANT)) {
- if ((t1->val.type != T_INT) || (t2->val.type != T_INT))
- cf_error( "Can't operate with value of non-integer type in pair constructor");
-
- check_u16(t1->a[1].i);
- check_u16(t2->a[1].i);
-
- rv = f_new_inst(FI_CONSTANT);
- rv->val = (struct f_val) {
- .type = T_PAIR,
- .val.i = pair(t1->a[1].i, t2->a[1].i),
- };
- }
- else {
- rv = f_new_inst(FI_PAIR_CONSTRUCT);
- rv->a[0].p = t1;
- rv->a[1].p = t2;
- }
-
- return rv;
-}
-
-static inline struct f_inst *
-f_generate_ec(u16 kind, struct f_inst *tk, struct f_inst *tv)
-{
- struct f_inst *rv;
- int c1 = 0, c2 = 0, ipv4_used = 0;
- u32 key = 0, val2 = 0;
-
- if (tk->fi_code == FI_CONSTANT) {
- c1 = 1;
- struct f_val *val = &(tk->val);
-
- if (val->type == T_INT) {
- ipv4_used = 0; key = val->val.i;
- }
- else if (tk->val.type == T_QUAD) {
- ipv4_used = 1; key = val->val.i;
- }
- else if ((val->type == T_IP) && ipa_is_ip4(val->val.ip)) {
- ipv4_used = 1; key = ipa_to_u32(val->val.ip);
- }
- else
- cf_error("Can't operate with key of non-integer/IPv4 type in EC constructor");
- }
-
- if (tv->fi_code == FI_CONSTANT) {
- if (tv->val.type != T_INT)
- cf_error("Can't operate with value of non-integer type in EC constructor");
- c2 = 1;
- val2 = tv->val.val.i;
- }
-
- if (c1 && c2) {
- u64 ec;
-
- if (kind == EC_GENERIC) {
- ec = ec_generic(key, val2);
- }
- else if (ipv4_used) {
- check_u16(val2);
- ec = ec_ip4(kind, key, val2);
- }
- else if (key < 0x10000) {
- ec = ec_as2(kind, key, val2);
- }
- else {
- check_u16(val2);
- ec = ec_as4(kind, key, val2);
- }
-
- rv = f_new_inst(FI_CONSTANT);
- rv->val = (struct f_val) {
- .type = T_EC,
- .val.ec = ec,
- };
- }
- else {
- rv = f_new_inst(FI_EC_CONSTRUCT);
- rv->aux = kind;
- rv->a[0].p = tk;
- rv->a[1].p = tv;
- }
-
- return rv;
-}
-
-static inline struct f_inst *
-f_generate_lc(struct f_inst *t1, struct f_inst *t2, struct f_inst *t3)
-{
- struct f_inst *rv;
-
- if ((t1->fi_code == FI_CONSTANT) && (t2->fi_code == FI_CONSTANT) && (t3->fi_code == FI_CONSTANT)) {
- if ((t1->val.type != T_INT) || (t2->val.type != T_INT) || (t3->val.type != T_INT))
- cf_error( "LC - Can't operate with value of non-integer type in tuple constructor");
-
- rv = f_new_inst(FI_CONSTANT);
- rv->val = (struct f_val) {
- .type = T_LC,
- .val.lc = (lcomm) { t1->a[1].i, t2->a[1].i, t3->a[1].i },
- };
- }
- else
- {
- rv = f_new_inst(FI_LC_CONSTRUCT);
- rv->a[0].p = t1;
- rv->a[1].p = t2;
- rv->a[2].p = t3;
- }
-
- return rv;
-}
-
-static inline struct f_inst *
-f_generate_path_mask(struct f_inst *t)
-{
- uint len = 0;
- uint dyn = 0;
- for (const struct f_inst *tt = t; tt; tt = tt->next) {
- if (tt->fi_code != FI_CONSTANT)
- dyn++;
- len++;
- }
-
- if (dyn) {
- struct f_inst *pmc = f_new_inst(FI_PATHMASK_CONSTRUCT);
- pmc->a[0].p = t;
- pmc->a[1].i = len;
- return pmc;
- }
-
- struct f_path_mask *pm = cfg_allocz(sizeof(struct f_path_mask) + len * sizeof(struct f_path_mask_item));
-
- uint i = 0;
- for (const struct f_inst *tt = t; tt; tt = tt->next)
- pm->item[i++] = tt->val.val.pmi;
-
- pm->len = i;
- struct f_inst *pmc = f_new_inst(FI_CONSTANT);
- pmc->val = (struct f_val) { .type = T_PATH_MASK, .val.path_mask = pm, };
-
- return pmc;
-}
-
-#endif
-
/*
* Remove all new lines and doubled whitespaces
* and convert all tabulators to spaces
@@ -426,14 +273,14 @@ assert_assign(struct f_lval *lval, struct f_inst *expr, const char *start, const
CF_DECLS
CF_KEYWORDS(FUNCTION, PRINT, PRINTN, UNSET, RETURN,
- ACCEPT, REJECT, ERROR, QUITBIRD,
+ ACCEPT, REJECT, ERROR,
INT, BOOL, IP, TYPE, PREFIX, RD, PAIR, QUAD, EC, LC,
SET, STRING, BGPMASK, BGPPATH, CLIST, ECLIST, LCLIST,
IF, THEN, ELSE, CASE,
TRUE, FALSE, RT, RO, UNKNOWN, GENERIC,
- FROM, GW, NET, MASK, PROTO, SOURCE, SCOPE, DEST, IFNAME, IFINDEX,
+ FROM, GW, NET, MASK, PROTO, SOURCE, SCOPE, DEST, IFNAME, IFINDEX, WEIGHT,
PREFERENCE,
- ROA_CHECK, ASN, SRC,
+ ROA_CHECK, ASN, SRC, DST,
IS_V4, IS_V6,
LEN, MAXLEN,
DEFINED,
@@ -775,8 +622,8 @@ fprefix:
;
fprefix_set:
- fprefix { $$ = f_new_trie(cfg_mem, sizeof(struct f_trie_node)); trie_add_prefix($$, &($1.net), $1.lo, $1.hi); }
- | fprefix_set ',' fprefix { $$ = $1; trie_add_prefix($$, &($3.net), $3.lo, $3.hi); }
+ fprefix { $$ = f_new_trie(cfg_mem, 0); trie_add_prefix($$, &($1.net), $1.lo, $1.hi); }
+ | fprefix_set ',' fprefix { $$ = $1; if (!trie_add_prefix($$, &($3.net), $3.lo, $3.hi)) cf_error("Mixed IPv4/IPv6 prefixes in prefix set"); }
;
switch_body: /* EMPTY */ { $$ = NULL; }
@@ -815,6 +662,7 @@ bgp_path_tail:
}
| '*' bgp_path_tail { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_PATH_MASK_ITEM, .val.pmi = { .kind = PM_ASTERISK }, }); $$->next = $2; }
| '?' bgp_path_tail { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_PATH_MASK_ITEM, .val.pmi = { .kind = PM_QUESTION }, }); $$->next = $2; }
+ | '+' bgp_path_tail { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_PATH_MASK_ITEM, .val.pmi = { .kind = PM_LOOP }, }); $$->next = $2; }
| bgp_path_expr bgp_path_tail { $$ = $1; $$->next = $2; }
| { $$ = NULL; }
;
@@ -902,6 +750,7 @@ static_attr:
| DEST { $$ = f_new_static_attr(T_ENUM_RTD, SA_DEST, 0); }
| IFNAME { $$ = f_new_static_attr(T_STRING, SA_IFNAME, 0); }
| IFINDEX { $$ = f_new_static_attr(T_INT, SA_IFINDEX, 1); }
+ | WEIGHT { $$ = f_new_static_attr(T_INT, SA_WEIGHT, 0); }
;
term:
@@ -940,7 +789,8 @@ term:
| term '.' LEN { $$ = f_new_inst(FI_LENGTH, $1); }
| term '.' MAXLEN { $$ = f_new_inst(FI_ROA_MAXLEN, $1); }
| term '.' ASN { $$ = f_new_inst(FI_ROA_ASN, $1); }
- | term '.' SRC { $$ = f_new_inst(FI_SADR_SRC, $1); }
+ | term '.' SRC { $$ = f_new_inst(FI_NET_SRC, $1); }
+ | term '.' DST { $$ = f_new_inst(FI_NET_DST, $1); }
| term '.' MASK '(' term ')' { $$ = f_new_inst(FI_IP_MASK, $1, $5); }
| term '.' FIRST { $$ = f_new_inst(FI_AS_PATH_FIRST, $1); }
| term '.' LAST { $$ = f_new_inst(FI_AS_PATH_LAST, $1); }
@@ -974,8 +824,7 @@ term:
;
break_command:
- QUITBIRD { $$ = F_QUITBIRD; }
- | ACCEPT { $$ = F_ACCEPT; }
+ ACCEPT { $$ = F_ACCEPT; }
| REJECT { $$ = F_REJECT; }
| ERROR { $$ = F_ERROR; }
;
diff --git a/filter/data.c b/filter/data.c
index db55070f..7c33d2cb 100644
--- a/filter/data.c
+++ b/filter/data.c
@@ -25,6 +25,49 @@
#include "filter/f-inst.h"
#include "filter/data.h"
+static const char * const f_type_str[] = {
+ [T_VOID] = "void",
+
+ [T_INT] = "int",
+ [T_BOOL] = "bool",
+ [T_PAIR] = "pair",
+ [T_QUAD] = "quad",
+
+ [T_ENUM_RTS] = "enum rts",
+ [T_ENUM_BGP_ORIGIN] = "enum bgp_origin",
+ [T_ENUM_SCOPE] = "enum scope",
+ [T_ENUM_RTC] = "enum rtc",
+ [T_ENUM_RTD] = "enum rtd",
+ [T_ENUM_ROA] = "enum roa",
+ [T_ENUM_NETTYPE] = "enum nettype",
+ [T_ENUM_RA_PREFERENCE] = "enum ra_preference",
+ [T_ENUM_AF] = "enum af",
+
+ [T_IP] = "ip",
+ [T_NET] = "prefix",
+ [T_STRING] = "string",
+ [T_PATH_MASK] = "bgpmask",
+ [T_PATH] = "bgppath",
+ [T_CLIST] = "clist",
+ [T_EC] = "ec",
+ [T_ECLIST] = "eclist",
+ [T_LC] = "lc",
+ [T_LCLIST] = "lclist",
+ [T_RD] = "rd",
+};
+
+const char *
+f_type_name(enum f_type t)
+{
+ if (t < ARRAY_SIZE(f_type_str))
+ return f_type_str[t] ?: "?";
+
+ if ((t == T_SET) || (t == T_PREFIX_SET))
+ return "set";
+
+ return "?";
+}
+
const struct f_val f_const_empty_path = {
.type = T_PATH,
.val.ad = &null_adata,
@@ -50,6 +93,8 @@ adata_empty(struct linpool *pool, int l)
static void
pm_format(const struct f_path_mask *p, buffer *buf)
{
+ int loop = 0;
+
buffer_puts(buf, "[= ");
for (uint i=0; i<p->len; i++)
@@ -68,14 +113,28 @@ pm_format(const struct f_path_mask *p, buffer *buf)
buffer_puts(buf, "* ");
break;
+ case PM_LOOP:
+ loop = 1;
+ break;
+
case PM_ASN_RANGE:
buffer_print(buf, "%u..%u ", p->item[i].from, p->item[i].to);
break;
+ case PM_ASN_SET:
+ tree_format(p->item[i].set, buf);
+ buffer_puts(buf, " ");
+ break;
+
case PM_ASN_EXPR:
ASSERT(0);
}
+ if (loop && (p->item[i].kind != PM_LOOP))
+ {
+ buffer_puts(buf, "+ ");
+ loop = 0;
+ }
}
buffer_puts(buf, "=]");
@@ -167,6 +226,10 @@ pmi_same(const struct f_path_mask_item *mi1, const struct f_path_mask_item *mi2)
if (mi1->to != mi2->to)
return 0;
break;
+ case PM_ASN_SET:
+ if (!same_tree(mi1->set, mi2->set))
+ return 0;
+ break;
}
return 1;
@@ -176,6 +239,7 @@ static int
pm_same(const struct f_path_mask *m1, const struct f_path_mask *m2)
{
if (m1->len != m2->len)
+ return 0;
for (uint i=0; i<m1->len; i++)
if (!pmi_same(&(m1->item[i]), &(m2->item[i])))
diff --git a/filter/data.h b/filter/data.h
index 083595f4..61cdb43e 100644
--- a/filter/data.h
+++ b/filter/data.h
@@ -38,6 +38,7 @@ enum f_type {
T_ENUM_ROA = 0x35,
T_ENUM_NETTYPE = 0x36,
T_ENUM_RA_PREFERENCE = 0x37,
+ T_ENUM_AF = 0x38,
/* new enums go here */
T_ENUM_EMPTY = 0x3f, /* Special hack for atomic_aggr */
@@ -71,7 +72,7 @@ struct f_val {
lcomm lc;
ip_addr ip;
const net_addr *net;
- char *s;
+ const char *s;
const struct f_tree *t;
const struct f_trie *ti;
const struct adata *ad;
@@ -98,6 +99,7 @@ enum f_sa_code {
SA_DEST,
SA_IFNAME,
SA_IFINDEX,
+ SA_WEIGHT,
} PACKED;
/* Static attribute definition (members of struct rta) */
@@ -137,19 +139,35 @@ struct f_tree {
void *data;
};
-struct f_trie_node
+struct f_trie_node4
+{
+ ip4_addr addr, mask, accept;
+ uint plen;
+ struct f_trie_node4 *c[2];
+};
+
+struct f_trie_node6
{
- ip_addr addr, mask, accept;
+ ip6_addr addr, mask, accept;
uint plen;
- struct f_trie_node *c[2];
+ struct f_trie_node6 *c[2];
+};
+
+struct f_trie_node
+{
+ union {
+ struct f_trie_node4 v4;
+ struct f_trie_node6 v6;
+ };
};
struct f_trie
{
linpool *lp;
- int zero;
- uint node_size;
- struct f_trie_node root[0]; /* Root trie node follows */
+ u8 zero;
+ s8 ipv4; /* -1 for undefined / empty */
+ u16 data_size; /* Additional data for each trie node */
+ struct f_trie_node root; /* Root trie node */
};
struct f_tree *f_new_tree(void);
@@ -157,8 +175,9 @@ struct f_tree *build_tree(struct f_tree *);
const struct f_tree *find_tree(const struct f_tree *t, const struct f_val *val);
int same_tree(const struct f_tree *t0, const struct f_tree *t2);
void tree_format(const struct f_tree *t, buffer *buf);
+void tree_walk(const struct f_tree *t, void (*hook)(const struct f_tree *, void *), void *data);
-struct f_trie *f_new_trie(linpool *lp, uint node_size);
+struct f_trie *f_new_trie(linpool *lp, uint data_size);
void *trie_add_prefix(struct f_trie *t, const net_addr *n, uint l, uint h);
int trie_match_net(const struct f_trie *t, const net_addr *n);
int trie_same(const struct f_trie *t1, const struct f_trie *t2);
@@ -166,6 +185,8 @@ void trie_format(const struct f_trie *t, buffer *buf);
#define F_CMP_ERROR 999
+const char *f_type_name(enum f_type t);
+
int val_same(const struct f_val *v1, const struct f_val *v2);
int val_compare(const struct f_val *v1, const struct f_val *v2);
void val_format(const struct f_val *v, buffer *buf);
diff --git a/filter/decl.m4 b/filter/decl.m4
index 4d5b70dc..5242c04c 100644
--- a/filter/decl.m4
+++ b/filter/decl.m4
@@ -40,6 +40,7 @@ m4_divert(-1)m4_dnl
# 106 comparator body
# 107 struct f_line_item content
# 108 interpreter body
+# 109 iterator body
#
# Here are macros to allow you to _divert to the right directions.
m4_define(FID_STRUCT_IN, `m4_divert(101)')
@@ -50,6 +51,7 @@ m4_define(FID_LINEARIZE_BODY, `m4_divert(105)')
m4_define(FID_SAME_BODY, `m4_divert(106)')
m4_define(FID_LINE_IN, `m4_divert(107)')
m4_define(FID_INTERPRET_BODY, `m4_divert(108)')
+m4_define(FID_ITERATE_BODY, `m4_divert(109)')
# Sometimes you want slightly different code versions in different
# outputs.
@@ -104,7 +106,7 @@ FID_STRUCT_IN()m4_dnl
struct f_inst * f$1;
FID_NEW_ARGS()m4_dnl
, struct f_inst * f$1
-FID_NEW_BODY
+FID_NEW_BODY()m4_dnl
whati->f$1 = f$1;
for (const struct f_inst *child = f$1; child; child = child->next) {
what->size += child->size;
@@ -138,7 +140,7 @@ FID_IFCONST([[
}
FID_IFCONST([[
const struct f_inst **items = NULL;
- if (constargs) {
+ if (constargs && whati->varcount) {
items = alloca(whati->varcount * sizeof(struct f_inst *));
const struct f_inst *child = fvar;
for (uint i=0; child; i++)
@@ -160,9 +162,28 @@ FID_HIC(,[[
')
# Some arguments need to check their type. After that, ARG_ANY is called.
-m4_define(ARG, `ARG_ANY($1)
+m4_define(ARG, `ARG_ANY($1) ARG_TYPE($1,$2)')
+m4_define(ARG_TYPE, `ARG_TYPE_STATIC($1,$2) ARG_TYPE_DYNAMIC($1,$2)')
+
+m4_define(ARG_TYPE_STATIC, `
+FID_NEW_BODY()m4_dnl
+if (f$1->type && (f$1->type != ($2)) && !f_const_promotion(f$1, ($2)))
+ cf_error("Argument $1 of %s must be of type %s, got type %s",
+ f_instruction_name(what->fi_code), f_type_name($2), f_type_name(f$1->type));
+FID_INTERPRET_BODY()')
+
+m4_define(ARG_TYPE_DYNAMIC, `
FID_INTERPRET_EXEC()m4_dnl
-if (v$1.type != $2) runtime("Argument $1 of instruction %s must be of type $2, got 0x%02x", f_instruction_name(what->fi_code), v$1.type)m4_dnl
+if (v$1.type != ($2))
+ runtime("Argument $1 of %s must be of type %s, got type %s",
+ f_instruction_name(what->fi_code), f_type_name($2), f_type_name(v$1.type));
+FID_INTERPRET_BODY()')
+
+m4_define(ARG_SAME_TYPE, `
+FID_NEW_BODY()m4_dnl
+if (f$1->type && f$2->type && (f$1->type != f$2->type) &&
+ !f_const_promotion(f$2, f$1->type) && !f_const_promotion(f$1, f$2->type))
+ cf_error("Arguments $1 and $2 of %s must be of the same type", f_instruction_name(what->fi_code));
FID_INTERPRET_BODY()')
# Executing another filter line. This replaces the recursion
@@ -192,6 +213,8 @@ FID_LINEARIZE_BODY()m4_dnl
item->fl$1 = f_linearize(whati->f$1);
FID_SAME_BODY()m4_dnl
if (!f_same(f1->fl$1, f2->fl$1)) return 0;
+FID_ITERATE_BODY()m4_dnl
+if (whati->fl$1) BUFFER_PUSH(fit->lines) = whati->fl$1;
FID_INTERPRET_EXEC()m4_dnl
do { if (whati->fl$1) {
LINEX_(whati->fl$1);
@@ -202,11 +225,27 @@ FID_INTERPRET_BODY()')
# Some of the instructions have a result. These constructions
# state the result and put it to the right place.
-m4_define(RESULT, `RESULT_VAL([[ (struct f_val) { .type = $1, .val.$2 = $3 } ]])')
+m4_define(RESULT, `RESULT_TYPE([[$1]]) RESULT_([[$1]],[[$2]],[[$3]])')
+m4_define(RESULT_, `RESULT_VAL([[ (struct f_val) { .type = $1, .val.$2 = $3 } ]])')
m4_define(RESULT_VAL, `FID_HIC(, [[do { res = $1; fstk->vcnt++; } while (0)]],
[[return fi_constant(what, $1)]])')
m4_define(RESULT_VOID, `RESULT_VAL([[ (struct f_val) { .type = T_VOID } ]])')
+m4_define(ERROR,
+ `m4_errprint(m4___file__:m4___line__: $*
+ )m4_m4exit(1)')
+
+# This macro specifies result type and makes there are no conflicting definitions
+m4_define(RESULT_TYPE,
+ `m4_ifdef([[INST_RESULT_TYPE]],
+ [[m4_ifelse(INST_RESULT_TYPE,$1,,[[ERROR([[Multiple type definitons]])]])]],
+ [[m4_define(INST_RESULT_TYPE,$1) RESULT_TYPE_($1)]])')
+
+m4_define(RESULT_TYPE_, `
+FID_NEW_BODY()m4_dnl
+what->type = $1;
+FID_INTERPRET_BODY()')
+
# Some common filter instruction members
m4_define(SYMBOL, `FID_MEMBER(struct symbol *, sym, [[strcmp(f1->sym->name, f2->sym->name) || (f1->sym->class != f2->sym->class)]], "symbol %s", item->sym->name)')
m4_define(RTC, `FID_MEMBER(struct rtable_config *, rtc, [[strcmp(f1->rtc->name, f2->rtc->name)]], "route table %s", item->rtc->name)')
@@ -230,6 +269,7 @@ m4_define(ACCESS_RTE, `FID_HIC(,[[do { if (!fs->rte) runtime("No route to access
# 7 dump line item callers
# 8 linearize
# 9 same (filter comparator)
+# 10 iterate
# 1 union in struct f_inst
# 3 constructors + interpreter
#
@@ -250,6 +290,7 @@ m4_define(FID_DUMP, `FID_ZONE(6, Dump line)')
m4_define(FID_DUMP_CALLER, `FID_ZONE(7, Dump line caller)')
m4_define(FID_LINEARIZE, `FID_ZONE(8, Linearize)')
m4_define(FID_SAME, `FID_ZONE(9, Comparison)')
+m4_define(FID_ITERATE, `FID_ZONE(10, Iteration)')
# This macro does all the code wrapping. See inline comments.
m4_define(INST_FLUSH, `m4_ifdef([[INST_NAME]], [[
@@ -337,14 +378,22 @@ m4_undivert(106)m4_dnl
#undef f2
break;
+FID_ITERATE()m4_dnl The iterator
+case INST_NAME():
+#define whati (&(what->i_]]INST_NAME()[[))
+m4_undivert(109)m4_dnl
+#undef whati
+break;
+
m4_divert(-1)FID_FLUSH(101,200)m4_dnl And finally this flushes all the unused diversions
]])')
m4_define(INST, `m4_dnl This macro is called on beginning of each instruction.
INST_FLUSH()m4_dnl First, old data is flushed
m4_define([[INST_NAME]], [[$1]])m4_dnl Then we store instruction name,
-m4_define([[INST_INVAL]], [[$2]])m4_dnl instruction input value count
-m4_undefine([[INST_NEVER_CONSTANT]])m4_dnl and reset NEVER_CONSTANT trigger.
+m4_define([[INST_INVAL]], [[$2]])m4_dnl instruction input value count,
+m4_undefine([[INST_NEVER_CONSTANT]])m4_dnl reset NEVER_CONSTANT trigger,
+m4_undefine([[INST_RESULT_TYPE]])m4_dnl and reset RESULT_TYPE value.
FID_INTERPRET_BODY()m4_dnl By default, every code is interpreter code.
')
@@ -404,7 +453,7 @@ FID_WR_PUT(5)
};
const char *
-f_instruction_name(enum f_instruction_code fi)
+f_instruction_name_(enum f_instruction_code fi)
{
if (fi < (sizeof(f_instruction_name_str) / sizeof(f_instruction_name_str[0])))
return f_instruction_name_str[fi];
@@ -430,6 +479,25 @@ fi_constant(struct f_inst *what, struct f_val val)
return what;
}
+static int
+f_const_promotion(struct f_inst *arg, enum f_type want)
+{
+ if (arg->fi_code != FI_CONSTANT)
+ return 0;
+
+ struct f_val *c = &arg->i_FI_CONSTANT.val;
+
+ if ((c->type == T_IP) && ipa_is_ip4(c->val.ip) && (want == T_QUAD)) {
+ *c = (struct f_val) {
+ .type = T_QUAD,
+ .val.i = ipa_to_u32(c->val.ip),
+ };
+ return 1;
+ }
+
+ return 0;
+}
+
#define v1 whati->f1->i_FI_CONSTANT.val
#define v2 whati->f2->i_FI_CONSTANT.val
#define v3 whati->f3->i_FI_CONSTANT.val
@@ -459,7 +527,7 @@ void f_dump_line(const struct f_line *dest, uint indent)
debug("%sFilter line %p (len=%u)\n", INDENT, dest, dest->len);
for (uint i=0; i<dest->len; i++) {
const struct f_line_item *item = &dest->items[i];
- debug("%sInstruction %s at line %u\n", INDENT, f_instruction_name(item->fi_code), item->lineno);
+ debug("%sInstruction %s at line %u\n", INDENT, f_instruction_name_(item->fi_code), item->lineno);
switch (item->fi_code) {
FID_WR_PUT(7)
default: bug("Unknown instruction %x in f_dump_line", item->fi_code);
@@ -494,7 +562,7 @@ f_linearize_concat(const struct f_inst * const inst[], uint count)
for (uint i=0; i<count; i++)
out->len = linearize(out, inst[i], out->len);
-#if DEBUGGING
+#ifdef LOCAL_DEBUG
f_dump_line(out, 0);
#endif
return out;
@@ -527,6 +595,27 @@ FID_WR_PUT(9)
return 1;
}
+
+/* Part of FI_SWITCH filter iterator */
+static void
+f_add_tree_lines(const struct f_tree *t, void *fit_)
+{
+ struct filter_iterator * fit = fit_;
+
+ if (t->data)
+ BUFFER_PUSH(fit->lines) = t->data;
+}
+
+/* Filter line iterator */
+void
+f_add_lines(const struct f_line_item *what, struct filter_iterator *fit)
+{
+ switch(what->fi_code) {
+FID_WR_PUT(10)
+ }
+}
+
+
#if defined(__GNUC__) && __GNUC__ >= 6
#pragma GCC diagnostic pop
#endif
@@ -541,6 +630,7 @@ FID_WR_PUT(4)m4_dnl
struct f_inst {
struct f_inst *next; /* Next instruction */
enum f_instruction_code fi_code; /* Instruction code */
+ enum f_type type; /* Type of returned value, if known */
int size; /* How many instructions are underneath */
int lineno; /* Line number */
union {
diff --git a/filter/f-inst.c b/filter/f-inst.c
index 385d18d0..1378fe4a 100644
--- a/filter/f-inst.c
+++ b/filter/f-inst.c
@@ -104,7 +104,7 @@
* m4_dnl (103) [[ put it here ]]
* m4_dnl ...
* m4_dnl if (all arguments are constant)
- * m4_dnl (108) [[ put it here ]]
+ * m4_dnl (108) [[ put it here ]]
* m4_dnl }
* m4_dnl For writing directly to constructor argument list, use FID_NEW_ARGS.
* m4_dnl For computing something in constructor (103), use FID_NEW_BODY.
@@ -172,6 +172,22 @@
* m4_dnl use macros f1 and f2.
* m4_dnl For writing directly here, use FID_SAME_BODY.
*
+ * m4_dnl f_add_lines(...)
+ * m4_dnl {
+ * m4_dnl switch (what_->fi_code) {
+ * m4_dnl case FI_EXAMPLE:
+ * m4_dnl (109) [[ put it here ]]
+ * m4_dnl break;
+ * m4_dnl }
+ * m4_dnl }
+ * m4_dnl This code adds new filter lines reachable from the instruction
+ * m4_dnl to the filter iterator line buffer. This is for instructions
+ * m4_dnl that changes conrol flow, like FI_CONDITION or FI_CALL, most
+ * m4_dnl instructions do not need to update it. It is used in generic
+ * m4_dnl filter iteration code (FILTER_ITERATE*). For accessing your
+ * m4_dnl custom instruction data, use macros f1 and f2. For writing
+ * m4_dnl directly here, use FID_ITERATE_BODY.
+ *
* m4_dnl interpret(...)
* m4_dnl {
* m4_dnl switch (what->fi_code) {
@@ -226,6 +242,9 @@
}
INST(FI_AND, 1, 1) {
ARG(1,T_BOOL);
+ ARG_TYPE_STATIC(2,T_BOOL);
+ RESULT_TYPE(T_BOOL);
+
if (v1.val.i)
LINE(2,0);
else
@@ -233,6 +252,9 @@
}
INST(FI_OR, 1, 1) {
ARG(1,T_BOOL);
+ ARG_TYPE_STATIC(2,T_BOOL);
+ RESULT_TYPE(T_BOOL);
+
if (!v1.val.i)
LINE(2,0);
else
@@ -255,7 +277,7 @@
FID_MEMBER(enum ec_subtype, ecs, f1->ecs != f2->ecs, "ec subtype %s", ec_subtype_str(item->ecs));
- int check, ipv4_used;
+ int ipv4_used;
u32 key, val;
if (v1.type == T_INT) {
@@ -273,21 +295,20 @@
val = v2.val.i;
- if (ecs == EC_GENERIC) {
- check = 0; RESULT(T_EC, ec, ec_generic(key, val));
- }
- else if (ipv4_used) {
- check = 1; RESULT(T_EC, ec, ec_ip4(ecs, key, val));
- }
- else if (key < 0x10000) {
- check = 0; RESULT(T_EC, ec, ec_as2(ecs, key, val));
- }
- else {
- check = 1; RESULT(T_EC, ec, ec_as4(ecs, key, val));
- }
-
- if (check && (val > 0xFFFF))
- runtime("Value %u > %u out of bounds in EC constructor", val, 0xFFFF);
+ if (ecs == EC_GENERIC)
+ RESULT(T_EC, ec, ec_generic(key, val));
+ else if (ipv4_used)
+ if (val <= 0xFFFF)
+ RESULT(T_EC, ec, ec_ip4(ecs, key, val));
+ else
+ runtime("4-byte value %u can't be used with IP-address key in extended community", val);
+ else if (key < 0x10000)
+ RESULT(T_EC, ec, ec_as2(ecs, key, val));
+ else
+ if (val <= 0xFFFF)
+ RESULT(T_EC, ec, ec_as4(ecs, key, val));
+ else
+ runtime("4-byte value %u can't be used with 4-byte ASN in extended community", val);
}
INST(FI_LC_CONSTRUCT, 3, 1) {
@@ -306,6 +327,17 @@
for (uint i=0; i<whati->varcount; i++) {
switch (vv(i).type) {
case T_PATH_MASK_ITEM:
+ if (vv(i).val.pmi.kind == PM_LOOP)
+ {
+ if (i == 0)
+ runtime("Path mask iterator '+' cannot be first");
+
+ /* We want PM_LOOP as prefix operator */
+ pm->item[i] = pm->item[i - 1];
+ pm->item[i - 1] = vv(i).val.pmi;
+ break;
+ }
+
pm->item[i] = vv(i).val.pmi;
break;
@@ -351,6 +383,8 @@
INST(FI_LT, 2, 1) {
ARG_ANY(1);
ARG_ANY(2);
+ ARG_SAME_TYPE(1, 2);
+
int i = val_compare(&v1, &v2);
if (i == F_CMP_ERROR)
runtime( "Can't compare values of incompatible types" );
@@ -360,6 +394,8 @@
INST(FI_LTE, 2, 1) {
ARG_ANY(1);
ARG_ANY(2);
+ ARG_SAME_TYPE(1, 2);
+
int i = val_compare(&v1, &v2);
if (i == F_CMP_ERROR)
runtime( "Can't compare values of incompatible types" );
@@ -416,18 +452,7 @@
NEVER_CONSTANT;
ARG_ANY(1);
SYMBOL;
-
- if ((sym->class != (SYM_VARIABLE | v1.type)) && (v1.type != T_VOID))
- {
- /* IP->Quad implicit conversion */
- if ((sym->class == (SYM_VARIABLE | T_QUAD)) && val_is_ip4(&v1))
- v1 = (struct f_val) {
- .type = T_QUAD,
- .val.i = ipa_to_u32(v1.val.ip),
- };
- else
- runtime( "Assigning to variable of incompatible type" );
- }
+ ARG_TYPE(1, sym->class & 0xff);
fstk->vstk[curline.vbase + sym->offset] = v1;
}
@@ -435,6 +460,7 @@
INST(FI_VAR_GET, 0, 1) {
SYMBOL;
NEVER_CONSTANT;
+ RESULT_TYPE(sym->class & 0xff);
RESULT_VAL(fstk->vstk[curline.vbase + sym->offset]);
}
@@ -447,6 +473,7 @@
val_dump(&(item->val))
);
+ RESULT_TYPE(val.type);
RESULT_VAL(val);
}
@@ -479,8 +506,6 @@
FID_MEMBER(enum filter_return, fret, f1->fret != f2->fret, "%s", filter_return_str(item->fret));
switch (whati->fret) {
- case F_QUITBIRD:
- die( "Filter asked me to die" );
case F_ACCEPT: /* Should take care about turning ACCEPT into MODIFY */
case F_ERROR:
case F_REJECT: /* Maybe print complete route along with reason to reject route? */
@@ -507,6 +532,7 @@
case SA_DEST: RESULT(sa.f_type, i, rta->dest); break;
case SA_IFNAME: RESULT(sa.f_type, s, rta->nh.iface ? rta->nh.iface->name : ""); break;
case SA_IFINDEX: RESULT(sa.f_type, i, rta->nh.iface ? rta->nh.iface->index : 0); break;
+ case SA_WEIGHT: RESULT(sa.f_type, i, rta->nh.weight + 1); break;
default:
bug("Invalid static attribute access (%u/%u)", sa.f_type, sa.sa_code);
@@ -518,8 +544,7 @@
ACCESS_RTE;
ARG_ANY(1);
STATIC_ATTR;
- if (sa.f_type != v1.type)
- runtime( "Attempt to set static attribute to incompatible type" );
+ ARG_TYPE(1, sa.f_type);
f_rta_cow(fs);
{
@@ -534,7 +559,8 @@
case SA_GW:
{
ip_addr ip = v1.val.ip;
- neighbor *n = neigh_find(rta->src->proto, ip, NULL, 0);
+ struct iface *ifa = ipa_is_link_local(ip) ? rta->nh.iface : NULL;
+ neighbor *n = neigh_find(rta->src->proto, ip, ifa, 0);
if (!n || (n->scope == SCOPE_HOST))
runtime( "Invalid gw address" );
@@ -578,6 +604,20 @@
}
break;
+ case SA_WEIGHT:
+ {
+ int i = v1.val.i;
+ if (i < 1 || i > 256)
+ runtime( "Setting weight value out of bounds" );
+ if (rta->dest != RTD_UNICAST)
+ runtime( "Setting weight needs regular nexthop " );
+
+ /* Set weight on all next hops */
+ for (struct nexthop *nh = &rta->nh; nh; nh = nh->next)
+ nh->weight = i - 1;
+ }
+ break;
+
default:
bug("Invalid static attribute access (%u/%u)", sa.f_type, sa.sa_code);
}
@@ -588,31 +628,32 @@
DYNAMIC_ATTR;
ACCESS_RTE;
ACCESS_EATTRS;
+ RESULT_TYPE(da.f_type);
{
eattr *e = ea_find(*fs->eattrs, da.ea_code);
if (!e) {
/* A special case: undefined as_path looks like empty as_path */
if (da.type == EAF_TYPE_AS_PATH) {
- RESULT(T_PATH, ad, &null_adata);
+ RESULT_(T_PATH, ad, &null_adata);
break;
}
/* The same special case for int_set */
if (da.type == EAF_TYPE_INT_SET) {
- RESULT(T_CLIST, ad, &null_adata);
+ RESULT_(T_CLIST, ad, &null_adata);
break;
}
/* The same special case for ec_set */
if (da.type == EAF_TYPE_EC_SET) {
- RESULT(T_ECLIST, ad, &null_adata);
+ RESULT_(T_ECLIST, ad, &null_adata);
break;
}
/* The same special case for lc_set */
if (da.type == EAF_TYPE_LC_SET) {
- RESULT(T_LCLIST, ad, &null_adata);
+ RESULT_(T_LCLIST, ad, &null_adata);
break;
}
@@ -623,31 +664,31 @@
switch (e->type & EAF_TYPE_MASK) {
case EAF_TYPE_INT:
- RESULT(da.f_type, i, e->u.data);
+ RESULT_(da.f_type, i, e->u.data);
break;
case EAF_TYPE_ROUTER_ID:
- RESULT(T_QUAD, i, e->u.data);
+ RESULT_(T_QUAD, i, e->u.data);
break;
case EAF_TYPE_OPAQUE:
- RESULT(T_ENUM_EMPTY, i, 0);
+ RESULT_(T_ENUM_EMPTY, i, 0);
break;
case EAF_TYPE_IP_ADDRESS:
- RESULT(T_IP, ip, *((ip_addr *) e->u.ptr->data));
+ RESULT_(T_IP, ip, *((ip_addr *) e->u.ptr->data));
break;
case EAF_TYPE_AS_PATH:
- RESULT(T_PATH, ad, e->u.ptr);
+ RESULT_(T_PATH, ad, e->u.ptr);
break;
case EAF_TYPE_BITFIELD:
- RESULT(T_BOOL, i, !!(e->u.data & (1u << da.bit)));
+ RESULT_(T_BOOL, i, !!(e->u.data & (1u << da.bit)));
break;
case EAF_TYPE_INT_SET:
- RESULT(T_CLIST, ad, e->u.ptr);
+ RESULT_(T_CLIST, ad, e->u.ptr);
break;
case EAF_TYPE_EC_SET:
- RESULT(T_ECLIST, ad, e->u.ptr);
+ RESULT_(T_ECLIST, ad, e->u.ptr);
break;
case EAF_TYPE_LC_SET:
- RESULT(T_LCLIST, ad, e->u.ptr);
+ RESULT_(T_LCLIST, ad, e->u.ptr);
break;
case EAF_TYPE_UNDEF:
RESULT_VOID;
@@ -663,6 +704,7 @@
ACCESS_EATTRS;
ARG_ANY(1);
DYNAMIC_ATTR;
+ ARG_TYPE(1, da.f_type);
{
struct ea_list *l = lp_alloc(fs->pool, sizeof(struct ea_list) + sizeof(eattr));
@@ -675,20 +717,7 @@
switch (da.type) {
case EAF_TYPE_INT:
- if (v1.type != da.f_type)
- runtime( "Setting int attribute to non-int value" );
- l->attrs[0].u.data = v1.val.i;
- break;
-
case EAF_TYPE_ROUTER_ID:
- /* IP->Quad implicit conversion */
- if (val_is_ip4(&v1)) {
- l->attrs[0].u.data = ipa_to_u32(v1.val.ip);
- break;
- }
- /* T_INT for backward compatibility */
- if ((v1.type != T_QUAD) && (v1.type != T_INT))
- runtime( "Setting quad attribute to non-quad value" );
l->attrs[0].u.data = v1.val.i;
break;
@@ -696,9 +725,7 @@
runtime( "Setting opaque attribute is not allowed" );
break;
- case EAF_TYPE_IP_ADDRESS:
- if (v1.type != T_IP)
- runtime( "Setting ip attribute to non-ip value" );
+ case EAF_TYPE_IP_ADDRESS:;
int len = sizeof(ip_addr);
struct adata *ad = lp_alloc(fs->pool, sizeof(struct adata) + len);
ad->length = len;
@@ -707,14 +734,13 @@
break;
case EAF_TYPE_AS_PATH:
- if (v1.type != T_PATH)
- runtime( "Setting path attribute to non-path value" );
+ case EAF_TYPE_INT_SET:
+ case EAF_TYPE_EC_SET:
+ case EAF_TYPE_LC_SET:
l->attrs[0].u.ptr = v1.val.ad;
break;
case EAF_TYPE_BITFIELD:
- if (v1.type != T_BOOL)
- runtime( "Setting bit in bitfield attribute to non-bool value" );
{
/* First, we have to find the old value */
eattr *e = ea_find(*fs->eattrs, da.ea_code);
@@ -727,24 +753,6 @@
}
break;
- case EAF_TYPE_INT_SET:
- if (v1.type != T_CLIST)
- runtime( "Setting clist attribute to non-clist value" );
- l->attrs[0].u.ptr = v1.val.ad;
- break;
-
- case EAF_TYPE_EC_SET:
- if (v1.type != T_ECLIST)
- runtime( "Setting eclist attribute to non-eclist value" );
- l->attrs[0].u.ptr = v1.val.ad;
- break;
-
- case EAF_TYPE_LC_SET:
- if (v1.type != T_LCLIST)
- runtime( "Setting lclist attribute to non-lclist value" );
- l->attrs[0].u.ptr = v1.val.ad;
- break;
-
default:
bug("Unknown dynamic attribute type");
}
@@ -803,18 +811,76 @@
}
}
- INST(FI_SADR_SRC, 1, 1) { /* Get SADR src prefix */
+ INST(FI_NET_SRC, 1, 1) { /* Get src prefix */
ARG(1, T_NET);
- if (!net_is_sadr(v1.val.net))
- runtime( "SADR expected" );
- net_addr_ip6_sadr *net = (void *) v1.val.net;
+ net_addr_union *net = (void *) v1.val.net;
net_addr *src = falloc(sizeof(net_addr_ip6));
- net_fill_ip6(src, net->src_prefix, net->src_pxlen);
+ const byte *part;
+
+ switch(v1.val.net->type) {
+ case NET_FLOW4:
+ part = flow4_get_part(&net->flow4, FLOW_TYPE_SRC_PREFIX);
+ if (part)
+ net_fill_ip4(src, flow_read_ip4_part(part), flow_read_pxlen(part));
+ else
+ net_fill_ip4(src, IP4_NONE, 0);
+ break;
+
+ case NET_FLOW6:
+ part = flow6_get_part(&net->flow6, FLOW_TYPE_SRC_PREFIX);
+ if (part)
+ net_fill_ip6(src, flow_read_ip6_part(part), flow_read_pxlen(part));
+ else
+ net_fill_ip6(src, IP6_NONE, 0);
+ break;
+
+ case NET_IP6_SADR:
+ net_fill_ip6(src, net->ip6_sadr.src_prefix, net->ip6_sadr.src_pxlen);
+ break;
+
+ default:
+ runtime( "Flow or SADR expected" );
+ }
RESULT(T_NET, net, src);
}
+ INST(FI_NET_DST, 1, 1) { /* Get dst prefix */
+ ARG(1, T_NET);
+
+ net_addr_union *net = (void *) v1.val.net;
+ net_addr *dst = falloc(sizeof(net_addr_ip6));
+ const byte *part;
+
+ switch(v1.val.net->type) {
+ case NET_FLOW4:
+ part = flow4_get_part(&net->flow4, FLOW_TYPE_DST_PREFIX);
+ if (part)
+ net_fill_ip4(dst, flow_read_ip4_part(part), flow_read_pxlen(part));
+ else
+ net_fill_ip4(dst, IP4_NONE, 0);
+ break;
+
+ case NET_FLOW6:
+ part = flow6_get_part(&net->flow6, FLOW_TYPE_DST_PREFIX);
+ if (part)
+ net_fill_ip6(dst, flow_read_ip6_part(part), flow_read_pxlen(part));
+ else
+ net_fill_ip6(dst, IP6_NONE, 0);
+ break;
+
+ case NET_IP6_SADR:
+ net_fill_ip6(dst, net->ip6_sadr.dst_prefix, net->ip6_sadr.dst_pxlen);
+ break;
+
+ default:
+ runtime( "Flow or SADR expected" );
+ }
+
+ RESULT(T_NET, net, dst);
+ }
+
INST(FI_ROA_MAXLEN, 1, 1) { /* Get ROA max prefix length */
ARG(1, T_NET);
if (!net_is_roa(v1.val.net))
@@ -849,14 +915,14 @@
INST(FI_AS_PATH_FIRST, 1, 1) { /* Get first ASN from AS PATH */
ARG(1, T_PATH);
- int as = 0;
+ u32 as = 0;
as_path_get_first(v1.val.ad, &as);
RESULT(T_INT, i, as);
}
INST(FI_AS_PATH_LAST, 1, 1) { /* Get last ASN from AS PATH */
ARG(1, T_PATH);
- int as = 0;
+ u32 as = 0;
as_path_get_last(v1.val.ad, &as);
RESULT(T_INT, i, as);
}
@@ -873,18 +939,17 @@
uint retpos = fstk->vcnt;
/* Drop every sub-block including ourselves */
- while ((fstk->ecnt-- > 0) && !(fstk->estk[fstk->ecnt].emask & FE_RETURN))
- ;
+ do fstk->ecnt--;
+ while ((fstk->ecnt > 0) && !(fstk->estk[fstk->ecnt].emask & FE_RETURN));
/* Now we are at the caller frame; if no such, try to convert to accept/reject. */
if (!fstk->ecnt)
+ {
if (fstk->vstk[retpos].type == T_BOOL)
- if (fstk->vstk[retpos].val.i)
- return F_ACCEPT;
- else
- return F_REJECT;
+ return (fstk->vstk[retpos].val.i) ? F_ACCEPT : F_REJECT;
else
runtime("Can't return non-bool from non-function");
+ }
/* Set the value stack position, overwriting the former implicit void */
fstk->vcnt = fstk->estk[fstk->ecnt].ventry - 1;
@@ -898,8 +963,12 @@
SYMBOL;
FID_SAME_BODY()
- if (!(f2->sym->flags & SYM_FLAG_SAME))
+ if (!(f1->sym->flags & SYM_FLAG_SAME))
return 0;
+
+ FID_ITERATE_BODY()
+ BUFFER_PUSH(fit->lines) = whati->sym->function;
+
FID_INTERPRET_BODY()
/* Push the body on stack */
@@ -929,6 +998,10 @@
FID_MEMBER(struct f_tree *, tree, [[!same_tree(f1->tree, f2->tree)]], "tree %p", item->tree);
+ FID_ITERATE_BODY()
+ tree_walk(whati->tree, f_add_tree_lines, fit);
+
+ FID_INTERPRET_BODY()
const struct f_tree *t = find_tree(tree, &v1);
if (!t) {
v1.type = T_VOID;
@@ -960,6 +1033,8 @@
INST(FI_CLIST_ADD, 2, 1) { /* (Extended) Community list add */
ARG_ANY(1);
ARG_ANY(2);
+ RESULT_TYPE(f1->type);
+
if (v1.type == T_PATH)
runtime("Can't add to path");
@@ -969,14 +1044,14 @@
struct f_val dummy;
if ((v2.type == T_PAIR) || (v2.type == T_QUAD))
- RESULT(T_CLIST, ad, [[ int_set_add(fpool, v1.val.ad, v2.val.i) ]]);
+ RESULT_(T_CLIST, ad, [[ int_set_add(fpool, v1.val.ad, v2.val.i) ]]);
/* IP->Quad implicit conversion */
else if (val_is_ip4(&v2))
- RESULT(T_CLIST, ad, [[ int_set_add(fpool, v1.val.ad, ipa_to_u32(v2.val.ip)) ]]);
+ RESULT_(T_CLIST, ad, [[ int_set_add(fpool, v1.val.ad, ipa_to_u32(v2.val.ip)) ]]);
else if ((v2.type == T_SET) && clist_set_type(v2.val.t, &dummy))
runtime("Can't add set");
else if (v2.type == T_CLIST)
- RESULT(T_CLIST, ad, [[ int_set_union(fpool, v1.val.ad, v2.val.ad) ]]);
+ RESULT_(T_CLIST, ad, [[ int_set_union(fpool, v1.val.ad, v2.val.ad) ]]);
else
runtime("Can't add non-pair");
}
@@ -987,11 +1062,11 @@
if ((v2.type == T_SET) && eclist_set_type(v2.val.t))
runtime("Can't add set");
else if (v2.type == T_ECLIST)
- RESULT(T_ECLIST, ad, [[ ec_set_union(fpool, v1.val.ad, v2.val.ad) ]]);
+ RESULT_(T_ECLIST, ad, [[ ec_set_union(fpool, v1.val.ad, v2.val.ad) ]]);
else if (v2.type != T_EC)
runtime("Can't add non-ec");
else
- RESULT(T_ECLIST, ad, [[ ec_set_add(fpool, v1.val.ad, v2.val.ec) ]]);
+ RESULT_(T_ECLIST, ad, [[ ec_set_add(fpool, v1.val.ad, v2.val.ec) ]]);
}
else if (v1.type == T_LCLIST)
@@ -1000,11 +1075,11 @@
if ((v2.type == T_SET) && lclist_set_type(v2.val.t))
runtime("Can't add set");
else if (v2.type == T_LCLIST)
- RESULT(T_LCLIST, ad, [[ lc_set_union(fpool, v1.val.ad, v2.val.ad) ]]);
+ RESULT_(T_LCLIST, ad, [[ lc_set_union(fpool, v1.val.ad, v2.val.ad) ]]);
else if (v2.type != T_LC)
runtime("Can't add non-lc");
else
- RESULT(T_LCLIST, ad, [[ lc_set_add(fpool, v1.val.ad, v2.val.lc) ]]);
+ RESULT_(T_LCLIST, ad, [[ lc_set_add(fpool, v1.val.ad, v2.val.lc) ]]);
}
@@ -1015,6 +1090,8 @@
INST(FI_CLIST_DEL, 2, 1) { /* (Extended) Community list add or delete */
ARG_ANY(1);
ARG_ANY(2);
+ RESULT_TYPE(f1->type);
+
if (v1.type == T_PATH)
{
const struct f_tree *set = NULL;
@@ -1027,7 +1104,7 @@
else
runtime("Can't delete non-integer (set)");
- RESULT(T_PATH, ad, [[ as_path_filter(fpool, v1.val.ad, set, key, 0) ]]);
+ RESULT_(T_PATH, ad, [[ as_path_filter(fpool, v1.val.ad, set, key, 0) ]]);
}
else if (v1.type == T_CLIST)
@@ -1036,12 +1113,12 @@
struct f_val dummy;
if ((v2.type == T_PAIR) || (v2.type == T_QUAD))
- RESULT(T_CLIST, ad, [[ int_set_del(fpool, v1.val.ad, v2.val.i) ]]);
+ RESULT_(T_CLIST, ad, [[ int_set_del(fpool, v1.val.ad, v2.val.i) ]]);
/* IP->Quad implicit conversion */
else if (val_is_ip4(&v2))
- RESULT(T_CLIST, ad, [[ int_set_del(fpool, v1.val.ad, ipa_to_u32(v2.val.ip)) ]]);
+ RESULT_(T_CLIST, ad, [[ int_set_del(fpool, v1.val.ad, ipa_to_u32(v2.val.ip)) ]]);
else if ((v2.type == T_SET) && clist_set_type(v2.val.t, &dummy) || (v2.type == T_CLIST))
- RESULT(T_CLIST, ad, [[ clist_filter(fpool, v1.val.ad, &v2, 0) ]]);
+ RESULT_(T_CLIST, ad, [[ clist_filter(fpool, v1.val.ad, &v2, 0) ]]);
else
runtime("Can't delete non-pair");
}
@@ -1050,22 +1127,22 @@
{
/* v2.val is either EC or EC-set */
if ((v2.type == T_SET) && eclist_set_type(v2.val.t) || (v2.type == T_ECLIST))
- RESULT(T_ECLIST, ad, [[ eclist_filter(fpool, v1.val.ad, &v2, 0) ]]);
+ RESULT_(T_ECLIST, ad, [[ eclist_filter(fpool, v1.val.ad, &v2, 0) ]]);
else if (v2.type != T_EC)
runtime("Can't delete non-ec");
else
- RESULT(T_ECLIST, ad, [[ ec_set_del(fpool, v1.val.ad, v2.val.ec) ]]);
+ RESULT_(T_ECLIST, ad, [[ ec_set_del(fpool, v1.val.ad, v2.val.ec) ]]);
}
else if (v1.type == T_LCLIST)
{
/* v2.val is either LC or LC-set */
if ((v2.type == T_SET) && lclist_set_type(v2.val.t) || (v2.type == T_LCLIST))
- RESULT(T_LCLIST, ad, [[ lclist_filter(fpool, v1.val.ad, &v2, 0) ]]);
+ RESULT_(T_LCLIST, ad, [[ lclist_filter(fpool, v1.val.ad, &v2, 0) ]]);
else if (v2.type != T_LC)
runtime("Can't delete non-lc");
else
- RESULT(T_LCLIST, ad, [[ lc_set_del(fpool, v1.val.ad, v2.val.lc) ]]);
+ RESULT_(T_LCLIST, ad, [[ lc_set_del(fpool, v1.val.ad, v2.val.lc) ]]);
}
else
@@ -1075,12 +1152,14 @@
INST(FI_CLIST_FILTER, 2, 1) { /* (Extended) Community list add or delete */
ARG_ANY(1);
ARG_ANY(2);
+ RESULT_TYPE(f1->type);
+
if (v1.type == T_PATH)
{
u32 key = 0;
if ((v2.type == T_SET) && (v2.val.t->from.type == T_INT))
- RESULT(T_PATH, ad, [[ as_path_filter(fpool, v1.val.ad, v2.val.t, key, 1) ]]);
+ RESULT_(T_PATH, ad, [[ as_path_filter(fpool, v1.val.ad, v2.val.t, key, 1) ]]);
else
runtime("Can't filter integer");
}
@@ -1091,7 +1170,7 @@
struct f_val dummy;
if ((v2.type == T_SET) && clist_set_type(v2.val.t, &dummy) || (v2.type == T_CLIST))
- RESULT(T_CLIST, ad, [[ clist_filter(fpool, v1.val.ad, &v2, 1) ]]);
+ RESULT_(T_CLIST, ad, [[ clist_filter(fpool, v1.val.ad, &v2, 1) ]]);
else
runtime("Can't filter pair");
}
@@ -1100,7 +1179,7 @@
{
/* v2.val is either EC or EC-set */
if ((v2.type == T_SET) && eclist_set_type(v2.val.t) || (v2.type == T_ECLIST))
- RESULT(T_ECLIST, ad, [[ eclist_filter(fpool, v1.val.ad, &v2, 1) ]]);
+ RESULT_(T_ECLIST, ad, [[ eclist_filter(fpool, v1.val.ad, &v2, 1) ]]);
else
runtime("Can't filter ec");
}
@@ -1109,7 +1188,7 @@
{
/* v2.val is either LC or LC-set */
if ((v2.type == T_SET) && lclist_set_type(v2.val.t) || (v2.type == T_LCLIST))
- RESULT(T_LCLIST, ad, [[ lclist_filter(fpool, v1.val.ad, &v2, 1) ]]);
+ RESULT_(T_LCLIST, ad, [[ lclist_filter(fpool, v1.val.ad, &v2, 1) ]]);
else
runtime("Can't filter lc");
}
diff --git a/filter/f-inst.h b/filter/f-inst.h
index 33fcf4a9..df45f88e 100644
--- a/filter/f-inst.h
+++ b/filter/f-inst.h
@@ -17,6 +17,8 @@
#include "conf/conf.h"
#include "filter/filter.h"
#include "filter/data.h"
+#include "lib/buffer.h"
+#include "lib/flowspec.h"
/* Flags for instructions */
enum f_instruction_flags {
@@ -29,7 +31,9 @@ enum f_instruction_flags {
#define f_new_inst(...) MACRO_CONCAT_AFTER(f_new_inst_, MACRO_FIRST(__VA_ARGS__))(__VA_ARGS__)
/* Convert the instruction back to the enum name */
-const char *f_instruction_name(enum f_instruction_code fi);
+const char *f_instruction_name_(enum f_instruction_code fi);
+static inline const char *f_instruction_name(enum f_instruction_code fi)
+{ return f_instruction_name_(fi) + 3; }
/* Filter structures for execution */
/* Line of instructions to be unconditionally executed one after another */
@@ -47,6 +51,41 @@ static inline struct f_line *f_linearize(const struct f_inst *root)
void f_dump_line(const struct f_line *, uint indent);
+
+/* Recursive iteration over filter instructions */
+
+struct filter_iterator {
+ BUFFER_(const struct f_line *) lines;
+};
+
+void f_add_lines(const struct f_line_item *what, struct filter_iterator *fit);
+
+#define FILTER_ITERATE_INIT(fit, filter, pool) \
+ ({ \
+ BUFFER_INIT((fit)->lines, (pool), 32); \
+ BUFFER_PUSH((fit)->lines) = (filter)->root; \
+ })
+
+#define FILTER_ITERATE(fit, fi) ({ \
+ const struct f_line *fl_; \
+ while (!BUFFER_EMPTY((fit)->lines)) \
+ { \
+ BUFFER_POP((fit)->lines); \
+ fl_ = (fit)->lines.data[(fit)->lines.used]; \
+ for (uint i_ = 0; i_ < fl_->len; i_++) \
+ { \
+ const struct f_line_item *fi = &fl_->items[i_]; \
+ f_add_lines(fi, (fit));
+
+#define FILTER_ITERATE_END } } })
+
+#define FILTER_ITERATE_CLEANUP(fit) \
+ ({ \
+ mb_free((fit)->lines.data); \
+ memset((fit), 0, sizeof(struct filter_iterator)); \
+ })
+
+
struct filter *f_new_where(struct f_inst *);
static inline struct f_dynamic_attr f_new_dynamic_attr(u8 type, enum f_type f_type, uint code) /* Type as core knows it, type as filters know it, and code of dynamic attribute */
{ return (struct f_dynamic_attr) { .type = type, .f_type = f_type, .ea_code = code }; } /* f_type currently unused; will be handy for static type checking */
diff --git a/filter/filter.c b/filter/filter.c
index 60e351f9..e505d570 100644
--- a/filter/filter.c
+++ b/filter/filter.c
@@ -32,8 +32,9 @@
#include "lib/socket.h"
#include "lib/string.h"
#include "lib/unaligned.h"
-#include "lib/net.h"
#include "lib/ip.h"
+#include "lib/net.h"
+#include "lib/flowspec.h"
#include "nest/route.h"
#include "nest/protocol.h"
#include "nest/iface.h"
@@ -174,7 +175,7 @@ interpret(struct filter_state *fs, const struct f_line *line, struct f_val *val)
#define curline fstk->estk[fstk->ecnt-1]
-#if DEBUGGING
+#ifdef LOCAL_DEBUG
debug("Interpreting line.");
f_dump_line(line, 1);
#endif
diff --git a/filter/filter.h b/filter/filter.h
index 9d997efb..26c1037b 100644
--- a/filter/filter.h
+++ b/filter/filter.h
@@ -24,7 +24,6 @@ enum filter_return {
F_ACCEPT, /* Need to preserve ordering: accepts < rejects! */
F_REJECT,
F_ERROR,
- F_QUITBIRD,
};
static inline const char *filter_return_str(const enum filter_return fret) {
@@ -36,7 +35,6 @@ static inline const char *filter_return_str(const enum filter_return fret) {
FRS(F_ACCEPT);
FRS(F_REJECT);
FRS(F_ERROR);
- FRS(F_QUITBIRD);
#undef FRS
default: bug("This shall not happen");
}
diff --git a/filter/filter_test.c b/filter/filter_test.c
index 3abe095b..7e4af092 100644
--- a/filter/filter_test.c
+++ b/filter/filter_test.c
@@ -24,21 +24,18 @@
#define BT_CONFIG_FILE "filter/test.conf"
-struct parse_config_file_arg {
- struct config **cp;
- const char *filename;
-};
-
static int
-parse_config_file(const void *argv)
+t_reconfig(void)
{
- const struct parse_config_file_arg *arg = argv;
- size_t fn_size = strlen(arg->filename) + 1;
- char *filename = alloca(fn_size);
- memcpy(filename, arg->filename, fn_size);
-
- *(arg->cp) = bt_config_file_parse(filename);
- return !!*(arg->cp);
+ if (!bt_config_file_parse(BT_CONFIG_FILE))
+ return 0;
+
+ struct symbol *s;
+ WALK_LIST(s, config->symbols)
+ if ((s->class == SYM_FUNCTION) || (s->class == SYM_FILTER))
+ bt_assert_msg((s->flags & SYM_FLAG_SAME), "Symbol %s same check", s->name);
+
+ return 1;
}
static int
@@ -49,12 +46,6 @@ run_function(const void *arg)
if (t->cmp)
return t->result == f_same(t->fn, t->cmp);
- if (!f_same(t->fn, t->fn)) {
- bt_result = bt_suite_result = 0;
- bt_log_suite_case_result(0, "The function doesn't compare to itself as the same");
- return 0;
- }
-
linpool *tmp = lp_new_default(&root_pool);
enum filter_return fret = f_eval(t->fn, tmp, NULL);
rfree(tmp);
@@ -82,22 +73,19 @@ main(int argc, char *argv[])
{
bt_init(argc, argv);
bt_bird_init();
-
+
bt_assert_hook = bt_assert_filter;
- struct config *c = NULL;
- struct parse_config_file_arg pcfa = { .cp = &c, .filename = BT_CONFIG_FILE };
- bt_test_suite_base(parse_config_file, "conf", (const void *) &pcfa, 0, 0, "parse config file");
- bt_test_suite_base(parse_config_file, "reconf", (const void *) &pcfa, 0, 0, "reconfigure with the same file");
+ /* Initial test.conf parsing, must be done here */
+ if (!bt_config_file_parse(BT_CONFIG_FILE))
+ abort();
- bt_bird_cleanup();
+ bt_test_suite(t_reconfig, "Testing reconfiguration");
- if (c)
- {
- struct f_bt_test_suite *t;
- WALK_LIST(t, c->tests)
- bt_test_suite_base(run_function, t->fn_name, t, BT_FORKING, BT_TIMEOUT, "%s", t->dsc);
- }
+ struct f_bt_test_suite *t;
+ WALK_LIST(t, config->tests)
+ bt_test_suite_base(run_function, t->fn_name, t, BT_FORKING, BT_TIMEOUT, "%s", t->dsc);
+ bt_bird_cleanup();
return bt_exit_value();
}
diff --git a/filter/test.conf b/filter/test.conf
index b1342819..63af25bb 100644
--- a/filter/test.conf
+++ b/filter/test.conf
@@ -63,8 +63,8 @@ bool b;
bt_assert(! false && ! false && true);
bt_assert(1 < 2 && 1 != 3);
bt_assert(true && true && ! false);
- bt_assert(true || 1+"a");
- bt_assert(!(false && 1+"a"));
+ # bt_assert(true || 1+"a");
+ # bt_assert(!(false && 1+"a"));
bt_assert(!(true && false));
}
@@ -380,6 +380,9 @@ function t_enum()
{
bt_assert(format(RTS_DUMMY) = "(enum 30)0");
bt_assert(format(RTS_STATIC) = "(enum 30)1");
+ bt_assert(format(NET_IP4) = "(enum 36)1");
+ bt_assert(format(NET_VPN6) = "(enum 36)4");
+
bt_assert(RTS_STATIC ~ [RTS_STATIC, RTS_DEVICE]);
bt_assert(RTS_BGP !~ [RTS_STATIC, RTS_DEVICE]);
}
@@ -458,7 +461,8 @@ function t_prefix_set()
prefix set pxs;
{
pxs = [ 1.2.0.0/16, 1.4.0.0/16+, 44.66.88.64/30{24,28}, 12.34.56.0/24{8,16} ];
- bt_assert(format(pxs) = "[1.2.0.0/112{::0.1.0.0}, 1.4.0.0/112{::0.1.255.255}, 12.34.0.0/112{::1.255.0.0}, 44.66.88.64/124{::1f0}]");
+ bt_assert(format(pxs) = "[1.2.0.0/16{0.1.0.0}, 1.4.0.0/16{0.1.255.255}, 12.34.0.0/16{1.255.0.0}, 44.66.88.64/28{0.0.1.240}]");
+
bt_assert(1.2.0.0/16 ~ pxs);
bt_assert(1.4.0.0/16 ~ pxs);
bt_assert(1.4.0.0/18 ~ pxs);
@@ -642,7 +646,6 @@ int set set12;
bt_assert(delete(p2, 3) = prepend(prepend(prepend(prepend(+empty+, 1), 2), 4), 5));
bt_assert(filter(p2, [1..3]) = prepend(prepend(prepend(+empty+, 1), 2), 3));
- pm1 = [= 1 2 * 3 4 5 =];
p2 = prepend( + empty +, 5 );
p2 = prepend( p2, 4 );
p2 = prepend( p2, 3 );
@@ -650,9 +653,17 @@ int set set12;
p2 = prepend( p2, 2 );
p2 = prepend( p2, 1 );
- bt_assert(p2 ~ pm1);
+ bt_assert(p2 !~ [= 1 2 3 4 5 =]);
+ bt_assert(p2 ~ [= 1 2 * 4 5 =]);
+ bt_assert(p2 ~ [= 1 2 * 3 4 5 =]);
+ bt_assert(p2 ~ [= 1 2 3+ 4 5 =]);
+ bt_assert(p2 ~ [= 1 2 3+ 4+ 5 =]);
+ bt_assert(p2 !~ [= 1 2 3+ 5+ 4 5 =]);
+ bt_assert(p2 !~ [= 1 2 3 3 5+ 4 5 =]);
bt_assert(delete(p2, 3) = prepend(prepend(prepend(prepend(+empty+, 5), 4), 2), 1));
bt_assert(delete(p2, [4..5]) = prepend(prepend(prepend(prepend(+empty+, 3), 3), 2), 1));
+
+ bt_assert(format([= 1 2+ 3 =]) = "[= 1 2 + 3 =]");
}
bt_test_suite(t_path, "Testing paths");
@@ -1038,6 +1049,7 @@ rd x;
bt_assert(x != 2:12345:20000);
bt_assert(!(x > 12345:200010));
+ bt_assert(format(0:1:2) = "1:2");
bt_assert(format(10.0.0.1:1000) = "10.0.0.1:1000");
bt_assert(format(100000:20000) = "100000:20000");
bt_assert(format(2:100000:20000) = "100000:20000");
@@ -1247,7 +1259,7 @@ int j;
filter roa_filter
{
- if net ~ [ 10.0.0.0/8{16,24}, 2000::/3{16,96} ] then {
+ if net ~ [ 10.0.0.0/8{16,24} ] || net ~ [ 2000::/3{16,96} ] then {
accept;
}
reject;
@@ -1271,10 +1283,9 @@ protocol static
route 2001:0db8:85a3:8a2e::/64 max 96 as 1000;
}
-function test_roa_check()
+function t_roa_check()
prefix pfx;
{
- # cannot be tested in __startup(), sorry
bt_assert(roa_check(r4, 10.10.0.0/16, 1000) = ROA_UNKNOWN);
bt_assert(roa_check(r4, 10.0.0.0/8, 1000) = ROA_UNKNOWN);
bt_assert(roa_check(r4, 10.110.0.0/16, 1000) = ROA_VALID);
@@ -1329,39 +1340,9 @@ prefix pfx;
bt_assert(pfx.asn = 1234);
}
-bt_test_suite(test_roa_check, "Testing ROA");
-
-/*
- * Testing Mixed Net Types
- * -----------------------
- */
+bt_test_suite(t_roa_check, "Testing ROA");
-function t_mixed_prefix()
-prefix set pxs;
-prefix set pxt;
-{
- pxs = [ 98.45.0.0/16, 128.128.0.0/12+, 2200::/42-, ::ffff:d000:0/100{98,102}];
- bt_assert(format(pxs) = "[::/0, ::/2{c000::}, 98.45.0.0/112{::0.1.0.0}, 128.128.0.0/108{::0.31.255.255}, 208.0.0.0/100{::124.0.0.0}, 2200::/42{ffff:ffff:ffc0::}]");
- bt_assert(::fe00:0:0/88 !~ pxs);
- bt_assert(::fffe:0:0/95 !~ pxs);
- bt_assert(::ffff:d800:0/101 ~ pxs);
- bt_assert(216.0.0.0/5 ~ pxs);
- bt_assert(212.0.0.0/6 ~ pxs);
- bt_assert(212.0.0.0/7 !~ pxs);
- bt_assert(::ffff:8080:8080/121 ~ pxs);
- bt_assert(::/0 ~ pxs);
- bt_assert(0.0.0.0/0 !~ pxs);
- bt_assert(128.135.64.17/32 ~ pxs);
-
-# pxt = [ 0:1:2 10.1.10.0/24, 0:5:10000 10.1.10.0/24 ];
-# print pxt;
-
- bt_assert(format(NET_IP4) = "(enum 36)1"); ## if (net.type = NET_IP4) ...
- bt_assert(format(NET_VPN6) = "(enum 36)4");
- bt_assert(format(0:1:2) = "1:2");
-}
-bt_test_suite(t_mixed_prefix, "Testing mixed net types");
filter vpn_filter
diff --git a/filter/test.conf2 b/filter/test.conf2
index 48515020..e95f9563 100644
--- a/filter/test.conf2
+++ b/filter/test.conf2
@@ -43,7 +43,6 @@ protocol static {
print scope;
if !(scope ~ [ SCOPE_HOST, SCOPE_SITE ]) then {
print "Failed in test";
- quitbird;
}
preference = 15;
diff --git a/filter/tree.c b/filter/tree.c
index 46d6e529..5da86b9d 100644
--- a/filter/tree.c
+++ b/filter/tree.c
@@ -103,12 +103,7 @@ build_tree(struct f_tree *from)
struct f_tree *
f_new_tree(void)
{
- struct f_tree * ret;
- ret = cfg_alloc(sizeof(struct f_tree));
- ret->left = ret->right = NULL;
- ret->from.type = ret->to.type = T_VOID;
- ret->from.val.i = ret->to.val.i = 0;
- ret->data = NULL;
+ struct f_tree *ret = cfg_allocz(sizeof(struct f_tree));
return ret;
}
@@ -175,3 +170,14 @@ tree_format(const struct f_tree *t, buffer *buf)
buffer_puts(buf, "]");
}
+
+void
+tree_walk(const struct f_tree *t, void (*hook)(const struct f_tree *, void *), void *data)
+{
+ if (!t)
+ return;
+
+ tree_walk(t->left, hook, data);
+ hook(t, data);
+ tree_walk(t->right, hook, data);
+}
diff --git a/filter/trie.c b/filter/trie.c
index 3038f5ec..1a4e1ac3 100644
--- a/filter/trie.c
+++ b/filter/trie.c
@@ -77,9 +77,10 @@
/*
- * In the trie code, the prefix length is internally treated as for the whole
- * ip_addr, regardless whether it contains an IPv4 or IPv6 address. Therefore,
- * remaining definitions make sense.
+ * In the trie_add_prefix(), we use ip_addr (assuming that it is the same as
+ * ip6_addr) to handle both IPv4 and IPv6 prefixes. In contrast to rest of the
+ * BIRD, IPv4 addresses are just zero-padded from right. That is why we have
+ * ipt_from_ip4() and ipt_to_ip4() macros below.
*/
#define ipa_mkmask(x) ip6_mkmask(x)
@@ -87,26 +88,41 @@
#define ipa_pxlen(x,y) ip6_pxlen(x,y)
#define ipa_getbit(x,n) ip6_getbit(x,n)
+#define ipt_from_ip4(x) _MI6(_I(x), 0, 0, 0)
+#define ipt_to_ip4(x) _MI4(_I0(x))
+
/**
* f_new_trie - allocates and returns a new empty trie
* @lp: linear pool to allocate items from
- * @node_size: node size to be used (&f_trie_node and user data)
+ * @data_size: user data attached to node
*/
struct f_trie *
-f_new_trie(linpool *lp, uint node_size)
+f_new_trie(linpool *lp, uint data_size)
{
struct f_trie * ret;
- ret = lp_allocz(lp, sizeof(struct f_trie) + node_size);
+ ret = lp_allocz(lp, sizeof(struct f_trie) + data_size);
ret->lp = lp;
- ret->node_size = node_size;
+ ret->ipv4 = -1;
+ ret->data_size = data_size;
return ret;
}
-static inline struct f_trie_node *
-new_node(struct f_trie *t, int plen, ip_addr paddr, ip_addr pmask, ip_addr amask)
+static inline struct f_trie_node4 *
+new_node4(struct f_trie *t, int plen, ip4_addr paddr, ip4_addr pmask, ip4_addr amask)
+{
+ struct f_trie_node4 *n = lp_allocz(t->lp, sizeof(struct f_trie_node4) + t->data_size);
+ n->plen = plen;
+ n->addr = paddr;
+ n->mask = pmask;
+ n->accept = amask;
+ return n;
+}
+
+static inline struct f_trie_node6 *
+new_node6(struct f_trie *t, int plen, ip6_addr paddr, ip6_addr pmask, ip6_addr amask)
{
- struct f_trie_node *n = lp_allocz(t->lp, t->node_size);
+ struct f_trie_node6 *n = lp_allocz(t->lp, sizeof(struct f_trie_node6) + t->data_size);
n->plen = plen;
n->addr = paddr;
n->mask = pmask;
@@ -114,12 +130,40 @@ new_node(struct f_trie *t, int plen, ip_addr paddr, ip_addr pmask, ip_addr amask
return n;
}
+static inline struct f_trie_node *
+new_node(struct f_trie *t, int plen, ip_addr paddr, ip_addr pmask, ip_addr amask)
+{
+ if (t->ipv4)
+ return (struct f_trie_node *) new_node4(t, plen, ipt_to_ip4(paddr), ipt_to_ip4(pmask), ipt_to_ip4(amask));
+ else
+ return (struct f_trie_node *) new_node6(t, plen, ipa_to_ip6(paddr), ipa_to_ip6(pmask), ipa_to_ip6(amask));
+}
+
static inline void
-attach_node(struct f_trie_node *parent, struct f_trie_node *child)
+attach_node4(struct f_trie_node4 *parent, struct f_trie_node4 *child)
{
- parent->c[ipa_getbit(child->addr, parent->plen) ? 1 : 0] = child;
+ parent->c[ip4_getbit(child->addr, parent->plen) ? 1 : 0] = child;
}
+static inline void
+attach_node6(struct f_trie_node6 *parent, struct f_trie_node6 *child)
+{
+ parent->c[ip6_getbit(child->addr, parent->plen) ? 1 : 0] = child;
+}
+
+static inline void
+attach_node(struct f_trie_node *parent, struct f_trie_node *child, int v4)
+{
+ if (v4)
+ attach_node4(&parent->v4, &child->v4);
+ else
+ attach_node6(&parent->v6, &child->v6);
+}
+
+#define GET_ADDR(N,F,X) ((X) ? ipt_from_ip4((N)->v4.F) : ipa_from_ip6((N)->v6.F))
+#define SET_ADDR(N,F,X,V) ({ if (X) (N)->v4.F =ipt_to_ip4(V); else (N)->v6.F =ipa_to_ip6(V); })
+
+#define GET_CHILD(N,F,X,I) ((X) ? (struct f_trie_node *) (N)->v4.c[I] : (struct f_trie_node *) (N)->v6.c[I])
/**
* trie_add_prefix
* @t: trie to add to
@@ -133,21 +177,30 @@ attach_node(struct f_trie_node *parent, struct f_trie_node *child)
*
* Returns a pointer to the allocated node. The function can return a pointer to
* an existing node if @px and @plen are the same. If px/plen == 0/0 (or ::/0),
- * a pointer to the root node is returned.
+ * a pointer to the root node is returned. Returns NULL when called with
+ * mismatched IPv4/IPv6 net type.
*/
void *
trie_add_prefix(struct f_trie *t, const net_addr *net, uint l, uint h)
{
- ip_addr px = net_prefix(net);
uint plen = net_pxlen(net);
+ ip_addr px;
+ int v4;
- if (net->type == NET_IP4)
+ switch (net->type)
{
- const uint delta = IP6_MAX_PREFIX_LENGTH - IP4_MAX_PREFIX_LENGTH;
- plen += delta;
- l += delta;
- h += delta;
+ case NET_IP4: px = ipt_from_ip4(net4_prefix(net)); v4 = 1; break;
+ case NET_IP6: px = ipa_from_ip6(net6_prefix(net)); v4 = 0; break;
+ default: bug("invalid type");
+ }
+
+ if (t->ipv4 != v4)
+ {
+ if (t->ipv4 < 0)
+ t->ipv4 = v4;
+ else
+ return NULL;
}
if (l == 0)
@@ -162,95 +215,136 @@ trie_add_prefix(struct f_trie *t, const net_addr *net, uint l, uint h)
ip_addr pmask = ipa_mkmask(plen);
ip_addr paddr = ipa_and(px, pmask);
struct f_trie_node *o = NULL;
- struct f_trie_node *n = t->root;
+ struct f_trie_node *n = &t->root;
while (n)
{
- ip_addr cmask = ipa_and(n->mask, pmask);
-
- if (ipa_compare(ipa_and(paddr, cmask), ipa_and(n->addr, cmask)))
- {
+ ip_addr naddr = GET_ADDR(n, addr, v4);
+ ip_addr nmask = GET_ADDR(n, mask, v4);
+ ip_addr accept = GET_ADDR(n, accept, v4);
+ ip_addr cmask = ipa_and(nmask, pmask);
+ uint nlen = v4 ? n->v4.plen : n->v6.plen;
+
+ if (ipa_compare(ipa_and(paddr, cmask), ipa_and(naddr, cmask)))
+ {
/* We are out of path - we have to add branching node 'b'
between node 'o' and node 'n', and attach new node 'a'
as the other child of 'b'. */
- int blen = ipa_pxlen(paddr, n->addr);
+ int blen = ipa_pxlen(paddr, naddr);
ip_addr bmask = ipa_mkmask(blen);
ip_addr baddr = ipa_and(px, bmask);
/* Merge accept masks from children to get accept mask for node 'b' */
- ip_addr baccm = ipa_and(ipa_or(amask, n->accept), bmask);
+ ip_addr baccm = ipa_and(ipa_or(amask, accept), bmask);
struct f_trie_node *a = new_node(t, plen, paddr, pmask, amask);
struct f_trie_node *b = new_node(t, blen, baddr, bmask, baccm);
- attach_node(o, b);
- attach_node(b, n);
- attach_node(b, a);
+ attach_node(o, b, v4);
+ attach_node(b, n, v4);
+ attach_node(b, a, v4);
return a;
}
- if (plen < n->plen)
+ if (plen < nlen)
{
/* We add new node 'a' between node 'o' and node 'n' */
- amask = ipa_or(amask, ipa_and(n->accept, pmask));
+ amask = ipa_or(amask, ipa_and(accept, pmask));
struct f_trie_node *a = new_node(t, plen, paddr, pmask, amask);
- attach_node(o, a);
- attach_node(a, n);
+ attach_node(o, a, v4);
+ attach_node(a, n, v4);
return a;
}
- if (plen == n->plen)
+ if (plen == nlen)
{
/* We already found added node in trie. Just update accept mask */
- n->accept = ipa_or(n->accept, amask);
+ accept = ipa_or(accept, amask);
+ SET_ADDR(n, accept, v4, accept);
return n;
}
/* Update accept mask part M2 and go deeper */
- n->accept = ipa_or(n->accept, ipa_and(amask, n->mask));
+ accept = ipa_or(accept, ipa_and(amask, nmask));
+ SET_ADDR(n, accept, v4, accept);
/* n->plen < plen and plen <= 32 (128) */
o = n;
- n = n->c[ipa_getbit(paddr, n->plen) ? 1 : 0];
+ n = GET_CHILD(n, c, v4, ipa_getbit(paddr, nlen) ? 1 : 0);
}
/* We add new tail node 'a' after node 'o' */
struct f_trie_node *a = new_node(t, plen, paddr, pmask, amask);
- attach_node(o, a);
+ attach_node(o, a, v4);
return a;
}
static int
-trie_match_prefix(const struct f_trie *t, ip_addr px, uint plen)
+trie_match_net4(const struct f_trie *t, ip4_addr px, uint plen)
{
- ip_addr pmask = ipa_mkmask(plen);
- ip_addr paddr = ipa_and(px, pmask);
+ ip4_addr pmask = ip4_mkmask(plen);
+ ip4_addr paddr = ip4_and(px, pmask);
if (plen == 0)
return t->zero;
int plentest = plen - 1;
- const struct f_trie_node *n = t->root;
+ const struct f_trie_node4 *n = &t->root.v4;
- while(n)
- {
- ip_addr cmask = ipa_and(n->mask, pmask);
+ while (n)
+ {
+ ip4_addr cmask = ip4_and(n->mask, pmask);
- /* We are out of path */
- if (ipa_compare(ipa_and(paddr, cmask), ipa_and(n->addr, cmask)))
- return 0;
+ /* We are out of path */
+ if (ip4_compare(ip4_and(paddr, cmask), ip4_and(n->addr, cmask)))
+ return 0;
- /* Check accept mask */
- if (ipa_getbit(n->accept, plentest))
- return 1;
+ /* Check accept mask */
+ if (ip4_getbit(n->accept, plentest))
+ return 1;
- /* We finished trie walk and still no match */
- if (plen <= n->plen)
- return 0;
+ /* We finished trie walk and still no match */
+ if (plen <= n->plen)
+ return 0;
- /* Choose children */
- n = n->c[(ipa_getbit(paddr, n->plen)) ? 1 : 0];
- }
+ /* Choose children */
+ n = n->c[(ip4_getbit(paddr, n->plen)) ? 1 : 0];
+ }
+
+ return 0;
+}
+
+static int
+trie_match_net6(const struct f_trie *t, ip6_addr px, uint plen)
+{
+ ip6_addr pmask = ip6_mkmask(plen);
+ ip6_addr paddr = ip6_and(px, pmask);
+
+ if (plen == 0)
+ return t->zero;
+
+ int plentest = plen - 1;
+ const struct f_trie_node6 *n = &t->root.v6;
+
+ while (n)
+ {
+ ip6_addr cmask = ip6_and(n->mask, pmask);
+
+ /* We are out of path */
+ if (ip6_compare(ip6_and(paddr, cmask), ip6_and(n->addr, cmask)))
+ return 0;
+
+ /* Check accept mask */
+ if (ip6_getbit(n->accept, plentest))
+ return 1;
+
+ /* We finished trie walk and still no match */
+ if (plen <= n->plen)
+ return 0;
+
+ /* Choose children */
+ n = n->c[(ip6_getbit(paddr, n->plen)) ? 1 : 0];
+ }
return 0;
}
@@ -267,20 +361,42 @@ trie_match_prefix(const struct f_trie *t, ip_addr px, uint plen)
int
trie_match_net(const struct f_trie *t, const net_addr *n)
{
- uint add = 0;
+ switch (n->type)
+ {
+ case NET_IP4:
+ case NET_VPN4:
+ case NET_ROA4:
+ return t->ipv4 ? trie_match_net4(t, net4_prefix(n), net_pxlen(n)) : 0;
+
+ case NET_IP6:
+ case NET_VPN6:
+ case NET_ROA6:
+ return !t->ipv4 ? trie_match_net6(t, net6_prefix(n), net_pxlen(n)) : 0;
- switch (n->type) {
- case NET_IP4:
- case NET_VPN4:
- case NET_ROA4:
- add = IP6_MAX_PREFIX_LENGTH - IP4_MAX_PREFIX_LENGTH;
+ default:
+ return 0;
}
+}
- return trie_match_prefix(t, net_prefix(n), net_pxlen(n) + add);
+static int
+trie_node_same4(const struct f_trie_node4 *t1, const struct f_trie_node4 *t2)
+{
+ if ((t1 == NULL) && (t2 == NULL))
+ return 1;
+
+ if ((t1 == NULL) || (t2 == NULL))
+ return 0;
+
+ if ((t1->plen != t2->plen) ||
+ (! ip4_equal(t1->addr, t2->addr)) ||
+ (! ip4_equal(t1->accept, t2->accept)))
+ return 0;
+
+ return trie_node_same4(t1->c[0], t2->c[0]) && trie_node_same4(t1->c[1], t2->c[1]);
}
static int
-trie_node_same(const struct f_trie_node *t1, const struct f_trie_node *t2)
+trie_node_same6(const struct f_trie_node6 *t1, const struct f_trie_node6 *t2)
{
if ((t1 == NULL) && (t2 == NULL))
return 1;
@@ -289,11 +405,11 @@ trie_node_same(const struct f_trie_node *t1, const struct f_trie_node *t2)
return 0;
if ((t1->plen != t2->plen) ||
- (! ipa_equal(t1->addr, t2->addr)) ||
- (! ipa_equal(t1->accept, t2->accept)))
+ (! ip6_equal(t1->addr, t2->addr)) ||
+ (! ip6_equal(t1->accept, t2->accept)))
return 0;
- return trie_node_same(t1->c[0], t2->c[0]) && trie_node_same(t1->c[1], t2->c[1]);
+ return trie_node_same6(t1->c[0], t2->c[0]) && trie_node_same6(t1->c[1], t2->c[1]);
}
/**
@@ -306,20 +422,39 @@ trie_node_same(const struct f_trie_node *t1, const struct f_trie_node *t2)
int
trie_same(const struct f_trie *t1, const struct f_trie *t2)
{
- return (t1->zero == t2->zero) && trie_node_same(t1->root, t2->root);
+ if ((t1->zero != t2->zero) || (t1->ipv4 != t2->ipv4))
+ return 0;
+
+ if (t1->ipv4)
+ return trie_node_same4(&t1->root.v4, &t2->root.v4);
+ else
+ return trie_node_same6(&t1->root.v6, &t2->root.v6);
}
static void
-trie_node_format(const struct f_trie_node *t, buffer *buf)
+trie_node_format4(const struct f_trie_node4 *t, buffer *buf)
{
if (t == NULL)
return;
- if (ipa_nonzero(t->accept))
- buffer_print(buf, "%I/%d{%I}, ", t->addr, t->plen, t->accept);
+ if (ip4_nonzero(t->accept))
+ buffer_print(buf, "%I4/%d{%I4}, ", t->addr, t->plen, t->accept);
- trie_node_format(t->c[0], buf);
- trie_node_format(t->c[1], buf);
+ trie_node_format4(t->c[0], buf);
+ trie_node_format4(t->c[1], buf);
+}
+
+static void
+trie_node_format6(const struct f_trie_node6 *t, buffer *buf)
+{
+ if (t == NULL)
+ return;
+
+ if (ip6_nonzero(t->accept))
+ buffer_print(buf, "%I6/%d{%I6}, ", t->addr, t->plen, t->accept);
+
+ trie_node_format6(t->c[0], buf);
+ trie_node_format6(t->c[1], buf);
}
/**
@@ -335,8 +470,12 @@ trie_format(const struct f_trie *t, buffer *buf)
buffer_puts(buf, "[");
if (t->zero)
- buffer_print(buf, "%I/%d, ", IPA_NONE, 0);
- trie_node_format(t->root, buf);
+ buffer_print(buf, "%I/%d, ", t->ipv4 ? IPA_NONE4 : IPA_NONE6, 0);
+
+ if (t->ipv4)
+ trie_node_format4(&t->root.v4, buf);
+ else
+ trie_node_format6(&t->root.v6, buf);
if (buf->pos == buf->end)
return;
diff --git a/filter/trie_test.c b/filter/trie_test.c
index 38c387b0..b2b36716 100644
--- a/filter/trie_test.c
+++ b/filter/trie_test.c
@@ -103,7 +103,7 @@ t_match_net(void)
{
list prefixes; /* of structs f_extended_prefix */
init_list(&prefixes);
- struct f_trie *trie = f_new_trie(config->mem, sizeof(struct f_trie_node));
+ struct f_trie *trie = f_new_trie(config->mem, 0);
generate_random_ipv6_prefixes(&prefixes);
struct f_prefix_node *n;
@@ -143,8 +143,8 @@ t_trie_same(void)
int round;
for (round = 0; round < TESTS_NUM*4; round++)
{
- struct f_trie * trie1 = f_new_trie(config->mem, sizeof(struct f_trie_node));
- struct f_trie * trie2 = f_new_trie(config->mem, sizeof(struct f_trie_node));
+ struct f_trie * trie1 = f_new_trie(config->mem, 0);
+ struct f_trie * trie2 = f_new_trie(config->mem, 0);
list prefixes; /* a list of f_extended_prefix structures */
init_list(&prefixes);
diff --git a/lib/Makefile b/lib/Makefile
index 18816bb3..5c78b2a9 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -1,7 +1,7 @@
-src := bitops.c checksum.c event.c flowspec.c idm.c ip.c lists.c mac.c md5.c mempool.c net.c patmatch.c printf.c resource.c sha1.c sha256.c sha512.c slab.c slists.c strtoul.c tbf.c timer.c xmalloc.c
+src := bitmap.c bitops.c checksum.c event.c flowspec.c idm.c ip.c lists.c mac.c md5.c mempool.c net.c patmatch.c printf.c resource.c sha1.c sha256.c sha512.c slab.c slists.c strtoul.c tbf.c timer.c xmalloc.c
obj := $(src-o-files)
$(all-daemon)
-tests_src := heap_test.c buffer_test.c event_test.c flowspec_test.c bitops_test.c patmatch_test.c fletcher16_test.c slist_test.c checksum_test.c lists_test.c mac_test.c ip_test.c hash_test.c printf_test.c
+tests_src := bitmap_test.c heap_test.c buffer_test.c event_test.c flowspec_test.c bitops_test.c patmatch_test.c fletcher16_test.c slist_test.c checksum_test.c lists_test.c mac_test.c ip_test.c hash_test.c printf_test.c
tests_targets := $(tests_targets) $(tests-target-files)
tests_objs := $(tests_objs) $(src-o-files)
diff --git a/lib/birdlib.h b/lib/birdlib.h
index 5202b0c8..23036c1b 100644
--- a/lib/birdlib.h
+++ b/lib/birdlib.h
@@ -72,6 +72,7 @@ static inline int u64_cmp(u64 i1, u64 i2)
#define NORET __attribute__((noreturn))
#define UNUSED __attribute__((unused))
#define PACKED __attribute__((packed))
+#define NONNULL(...) __attribute__((nonnull((__VA_ARGS__))))
#ifndef HAVE_THREAD_LOCAL
#define _Thread_local
@@ -162,12 +163,23 @@ void debug(const char *msg, ...); /* Printf to debug output */
#define DBG(x, y...) do { } while(0)
#endif
+#define ASSERT_DIE(x) do { if (!(x)) bug("Assertion '%s' failed at %s:%d", #x, __FILE__, __LINE__); } while(0)
+
+#define EXPENSIVE_CHECK(x) /* intentionally left blank */
+
#ifdef DEBUGGING
-#define ASSERT(x) do { if (!(x)) bug("Assertion '%s' failed at %s:%d", #x, __FILE__, __LINE__); } while(0)
+#define ASSERT(x) ASSERT_DIE(x)
+#define ASSUME(x) ASSERT_DIE(x)
+#ifdef ENABLE_EXPENSIVE_CHECKS
+#undef EXPENSIVE_CHECK
+#define EXPENSIVE_CHECK(x) ASSERT_DIE(x)
+#endif
#else
#define ASSERT(x) do { if (!(x)) log(L_BUG "Assertion '%s' failed at %s:%d", #x, __FILE__, __LINE__); } while(0)
+#define ASSUME(x) /* intentionally left blank */
#endif
+
#ifdef DEBUGGING
asm(
".pushsection \".debug_gdb_scripts\", \"MS\",@progbits,1\n"
diff --git a/lib/bitmap.c b/lib/bitmap.c
new file mode 100644
index 00000000..b6ea5a38
--- /dev/null
+++ b/lib/bitmap.c
@@ -0,0 +1,197 @@
+/*
+ * BIRD Library -- Bitmaps
+ *
+ * (c) 2019 Ondrej Zajicek <santiago@crfreenet.org>
+ * (c) 2019 CZ.NIC z.s.p.o.
+ *
+ * Can be freely distributed and used under the terms of the GNU GPL.
+ */
+
+#include <stdlib.h>
+
+#include "nest/bird.h"
+#include "lib/bitmap.h"
+#include "lib/bitops.h"
+#include "lib/resource.h"
+
+
+/*
+ * Basic bitmap
+ */
+
+void
+bmap_init(struct bmap *b, pool *p, uint size)
+{
+ b->size = BIRD_ALIGN(size, 4);
+ b->data = mb_allocz(p, b->size);
+}
+
+void
+bmap_reset(struct bmap *b, uint size)
+{
+ b->size = BIRD_ALIGN(size, 4);
+ memset(b->data, 0, b->size);
+}
+
+void
+bmap_grow(struct bmap *b, uint need)
+{
+ uint size = b->size * 2;
+ while (size < need)
+ size *= 2;
+
+ uint old_size = b->size;
+ b->size = size;
+ b->data = mb_realloc(b->data, b->size);
+
+ ASSERT(size >= old_size);
+ memset(b->data + (old_size / 4), 0, size - old_size);
+}
+
+void
+bmap_free(struct bmap *b)
+{
+ mb_free(b->data);
+ b->size = 0;
+ b->data = NULL;
+}
+
+
+
+/*
+ * Hierarchical bitmap
+ */
+
+#define B256_SIZE(b) BIRD_ALIGN(b, 32)
+#define B256_STEP(b) (BIRD_ALIGN(b, 8192) >> 8)
+
+void
+hmap_init(struct hmap *b, pool *p, uint size)
+{
+ b->size[0] = B256_SIZE(size);
+ b->size[1] = B256_STEP(b->size[0]);
+ b->size[2] = B256_STEP(b->size[1]);
+ b->size[3] = sizeof(b->root);
+
+ b->data[0] = mb_allocz(p, b->size[0]);
+ b->data[1] = mb_allocz(p, b->size[1]);
+ b->data[2] = mb_allocz(p, b->size[2]);
+ b->data[3] = b->root;
+
+ memset(b->root, 0, sizeof(b->root));
+}
+
+static void
+hmap_grow(struct hmap *b, uint need)
+{
+ uint size = b->size[0] * 2;
+ while (size < need)
+ size *= 2;
+
+ for (uint i = 0; i < 3; i++)
+ {
+ uint old_size = b->size[i];
+ b->size[i] = size;
+ b->data[i] = mb_realloc(b->data[i], b->size[i]);
+
+ ASSERT(size >= old_size);
+ memset(b->data[i] + (old_size / 4), 0, size - old_size);
+
+ size = B256_STEP(size);
+ }
+}
+
+void
+hmap_free(struct hmap *b)
+{
+ mb_free(b->data[0]);
+ mb_free(b->data[1]);
+ mb_free(b->data[2]);
+
+ memset(b, 0, sizeof(struct hmap));
+}
+
+static inline int
+b256_and(u32 *p)
+{
+ for (int i = 0; i < 8; i++)
+ if (~p[i])
+ return 0;
+
+ return 1;
+}
+
+void
+hmap_set(struct hmap *b, uint n)
+{
+ if (n >= hmap_max(b))
+ hmap_grow(b, n/8 + 1);
+
+ for (int i = 0; i < 4; i++)
+ {
+ BIT32_SET(b->data[i], n);
+ n = n >> 8;
+
+ /* Continue if all bits in 256-bit block are set */
+ if (! b256_and(b->data[i] + 8*n))
+ break;
+ }
+}
+
+void
+hmap_clear(struct hmap *b, uint n)
+{
+ if (n >= hmap_max(b))
+ return;
+
+ for (int i = 0; i < 4; i++)
+ {
+ BIT32_CLR(b->data[i], n);
+ n = n >> 8;
+ }
+}
+
+static inline int
+b256_first_zero(u32 *p)
+{
+ for (int i = 0; i < 8; i++)
+ if (~p[i])
+ return 32*i + u32_ctz(~p[i]);
+
+ return 256;
+}
+
+u32
+hmap_first_zero(struct hmap *b)
+{
+ u32 n = 0;
+
+ for (int i = 3; i >= 0; i--)
+ {
+ if (32*n >= b->size[i])
+ return hmap_max(b);
+
+ u32 *p = b->data[i] + 8*n;
+
+ n = (n << 8) + b256_first_zero(p);
+ }
+
+ return n;
+}
+
+void
+hmap_check(struct hmap *b)
+{
+ for (int i = 0; i < 2; i++)
+ {
+ int max = b->size[i] / 32;
+
+ for (int j = 0; j < max; j++)
+ {
+ int x = b256_and(b->data[i] + 8*j);
+ int y = !!BIT32_TEST(b->data[i+1], j);
+ if (x != y)
+ bug("Inconsistent data on %d:%d (%d vs %d)", i, j, x, y);
+ }
+ }
+}
diff --git a/lib/bitmap.h b/lib/bitmap.h
new file mode 100644
index 00000000..0093cd18
--- /dev/null
+++ b/lib/bitmap.h
@@ -0,0 +1,63 @@
+/*
+ * BIRD Library -- Bitmaps
+ *
+ * (c) 2019 Ondrej Zajicek <santiago@crfreenet.org>
+ * (c) 2019 CZ.NIC z.s.p.o.
+ *
+ * Can be freely distributed and used under the terms of the GNU GPL.
+ */
+
+#ifndef _BIRD_BITMAP_H_
+#define _BIRD_BITMAP_H_
+
+struct bmap
+{
+ u32 size;
+ u32 *data;
+};
+
+void bmap_init(struct bmap *b, pool *p, uint size);
+void bmap_reset(struct bmap *b, uint size);
+void bmap_grow(struct bmap *b, uint need);
+void bmap_free(struct bmap *b);
+
+static inline uint bmap_max(struct bmap *b)
+{ return 8 * b->size; }
+
+static inline int bmap_test(struct bmap *b, uint n)
+{ return (n < bmap_max(b)) && BIT32_TEST(b->data, n); }
+
+static inline void bmap_set(struct bmap *b, uint n)
+{
+ if (n >= bmap_max(b)) bmap_grow(b, n/8 + 1);
+ BIT32_SET(b->data, n);
+}
+
+static inline void bmap_clear(struct bmap *b, uint n)
+{
+ if (n >= bmap_max(b)) return;
+ BIT32_CLR(b->data, n);
+}
+
+
+struct hmap
+{
+ u32 size[4];
+ u32 *data[4];
+ u32 root[8];
+};
+
+static inline uint hmap_max(struct hmap *b)
+{ return 8 * b->size[0]; }
+
+static inline int hmap_test(struct hmap *b, uint n)
+{ return (n < hmap_max(b)) && BIT32_TEST(b->data[0], n); }
+
+void hmap_init(struct hmap *b, pool *p, uint size);
+void hmap_free(struct hmap *b);
+void hmap_set(struct hmap *b, uint n);
+void hmap_clear(struct hmap *b, uint n);
+u32 hmap_first_zero(struct hmap *b);
+void hmap_check(struct hmap *b);
+
+#endif
diff --git a/lib/bitmap_test.c b/lib/bitmap_test.c
new file mode 100644
index 00000000..0595a4d0
--- /dev/null
+++ b/lib/bitmap_test.c
@@ -0,0 +1,186 @@
+/*
+ * BIRD Library -- Bitmap Tests
+ *
+ * (c) 2019 Ondrej Zajicek <santiago@crfreenet.org>
+ * (c) 2019 CZ.NIC z.s.p.o.
+ *
+ * Can be freely distributed and used under the terms of the GNU GPL.
+ */
+
+#include "test/birdtest.h"
+#include "sysdep/config.h"
+#include "lib/bitmap.h"
+
+#define MAX_NUM (1 << 20)
+#define MAX_SET (1 << 19)
+#define MAX_CLR (1 << 17)
+
+#define STEP_NUM 1000
+#define STEP_SET 1000
+#define STEP_CLR 500
+
+static int
+t_bmap_set_clear_random(void)
+{
+ struct bmap b;
+
+ resource_init();
+ bmap_init(&b, &root_pool, 1024);
+
+ char expected[MAX_NUM] = {};
+ uint i, n;
+
+ for (i = 0; i < MAX_SET; i++)
+ {
+ do n = bt_random() % MAX_NUM;
+ while (expected[n]);
+
+ bmap_set(&b, n);
+ expected[n] = 1;
+ }
+
+ for (i = 0; i < MAX_CLR; i++)
+ {
+ do n = bt_random() % MAX_NUM;
+ while (!expected[n]);
+
+ bmap_clear(&b, n);
+ expected[n] = 0;
+ }
+
+ for (i = 0; i < MAX_NUM; i++)
+ if (bmap_test(&b, i) != expected[i])
+ bt_abort_msg("Bitmap mismatch on %d (should be %d %d)", i, bmap_test(&b, i), expected[i]);
+
+ return 1;
+}
+
+static int
+t_hmap_set_clear_random(void)
+{
+ struct hmap b;
+
+ resource_init();
+ hmap_init(&b, &root_pool, 1024);
+
+ char expected[MAX_NUM] = {};
+ uint i, n;
+
+ for (i = 0; i < MAX_SET; i++)
+ {
+ do n = bt_random() % MAX_NUM;
+ while (expected[n]);
+
+ hmap_set(&b, n);
+ expected[n] = 1;
+ }
+
+ hmap_check(&b);
+
+ for (i = 0; i < MAX_CLR; i++)
+ {
+ do n = bt_random() % MAX_NUM;
+ while (!expected[n]);
+
+ hmap_clear(&b, n);
+ expected[n] = 0;
+ }
+
+ hmap_check(&b);
+
+ for (i = 0; i < MAX_NUM; i++)
+ if (hmap_test(&b, i) != expected[i])
+ bt_abort_msg("Bitmap mismatch on %d (should be %d %d)", i, hmap_test(&b, i), expected[i]);
+
+ for (i = 0; 1; i++)
+ {
+ n = hmap_first_zero(&b);
+ bt_assert(n >= i);
+ bt_assert(n <= MAX_NUM);
+
+ for (; i < n; i++)
+ bt_assert(expected[i]);
+
+ if (n == MAX_NUM)
+ break;
+
+ bt_assert(!expected[i]);
+
+ hmap_set(&b, n);
+ }
+
+ hmap_check(&b);
+
+ return 1;
+}
+
+static int
+t_hmap_set_clear_fill(void)
+{
+ struct hmap b;
+
+ resource_init();
+ hmap_init(&b, &root_pool, 1024);
+
+ char expected[MAX_NUM] = {};
+ uint i, j, n, max = 0;
+
+ for (i = 0; i < STEP_NUM; i++)
+ {
+ uint last = 0;
+ uint step_set = bt_random() % STEP_SET;
+ uint step_clr = bt_random() % STEP_CLR;
+
+ for (j = 0; j < step_set; j++)
+ {
+ n = hmap_first_zero(&b);
+ bt_assert(n > last || !last);
+ bt_assert(n < MAX_NUM);
+
+ if (!last)
+ last = n;
+
+ for (; last < n; last++)
+ bt_assert(expected[last]);
+
+ bt_assert(!expected[n]);
+
+ hmap_set(&b, n);
+ expected[n] = 1;
+ max = MAX(max, n);
+ }
+
+ for (j = 0; j < step_clr; j++)
+ {
+ uint k = 0;
+ do n = bt_random() % max;
+ while (!expected[n] && (k++ < 8));
+
+ if (!expected[n])
+ continue;
+
+ hmap_clear(&b, n);
+ expected[n] = 0;
+ }
+ }
+
+ for (i = 0; i < MAX_NUM; i++)
+ if (hmap_test(&b, i) != expected[i])
+ bt_abort_msg("Bitmap mismatch on %d (should be %d %d)", i, hmap_test(&b, i), expected[i]);
+
+ hmap_check(&b);
+
+ return 1;
+}
+
+int
+main(int argc, char *argv[])
+{
+ bt_init(argc, argv);
+
+ bt_test_suite(t_bmap_set_clear_random, "BMap - random sequence of sets / clears");
+ bt_test_suite(t_hmap_set_clear_random, "HMap - random sequence of sets / clears");
+ bt_test_suite(t_hmap_set_clear_fill, "HMap - linear sets and random clears");
+
+ return bt_exit_value();
+}
diff --git a/lib/bitops.h b/lib/bitops.h
index 39ade388..a4c48a10 100644
--- a/lib/bitops.h
+++ b/lib/bitops.h
@@ -29,6 +29,9 @@ static inline u32 u32_hash(u32 v) { return v * 2902958171u; }
static inline u8 u32_popcount(u32 v) { return __builtin_popcount(v); }
+static inline int u32_clz(u32 v) { return __builtin_clz(v); }
+static inline int u32_ctz(u32 v) { return __builtin_ctz(v); }
+
static inline int uint_is_pow2(uint n) { return n && !(n & (n-1)); }
#endif
diff --git a/lib/buffer.h b/lib/buffer.h
index cd9bab86..fd40baa0 100644
--- a/lib/buffer.h
+++ b/lib/buffer.h
@@ -50,6 +50,8 @@
#define BUFFER_FLUSH(v) ({ (v).used = 0; })
+#define BUFFER_EMPTY(v) ({ (v).used == 0; })
+
#define BUFFER_WALK(v,n) \
for (BUFFER_TYPE(v) *_n = (v).data, n; _n < ((v).data + (v).used) && (n = *_n, 1); _n++)
diff --git a/lib/event.c b/lib/event.c
index c33e0ffc..273447e0 100644
--- a/lib/event.c
+++ b/lib/event.c
@@ -23,6 +23,7 @@
#include "lib/event.h"
event_list global_event_list;
+event_list global_work_list;
inline void
ev_postpone(event *e)
@@ -114,6 +115,22 @@ ev_schedule(event *e)
ev_enqueue(&global_event_list, e);
}
+/**
+ * ev_schedule_work - schedule a work-event.
+ * @e: an event
+ *
+ * This function schedules an event by enqueueing it to a system-wide work-event
+ * list which is run by the platform dependent code whenever appropriate. This
+ * is designated for work-events instead of regular events. They are executed
+ * less often in order to not clog I/O loop.
+ */
+void
+ev_schedule_work(event *e)
+{
+ if (!ev_active(e))
+ add_tail(&global_work_list, &e->n);
+}
+
void io_log_event(void *hook, void *data);
/**
@@ -136,10 +153,47 @@ ev_run_list(event_list *l)
event *e = SKIP_BACK(event, n, n);
/* This is ugly hack, we want to log just events executed from the main I/O loop */
- if (l == &global_event_list)
+ if ((l == &global_event_list) || (l == &global_work_list))
io_log_event(e->hook, e->data);
ev_run(e);
}
+
+ return !EMPTY_LIST(*l);
+}
+
+int
+ev_run_list_limited(event_list *l, uint limit)
+{
+ node *n;
+ list tmp_list;
+
+ init_list(&tmp_list);
+ add_tail_list(&tmp_list, l);
+ init_list(l);
+
+ WALK_LIST_FIRST(n, tmp_list)
+ {
+ event *e = SKIP_BACK(event, n, n);
+
+ if (!limit)
+ break;
+
+ /* This is ugly hack, we want to log just events executed from the main I/O loop */
+ if ((l == &global_event_list) || (l == &global_work_list))
+ io_log_event(e->hook, e->data);
+
+ ev_run(e);
+ limit--;
+ }
+
+ if (!EMPTY_LIST(tmp_list))
+ {
+ /* Attach new items after the unprocessed old items */
+ add_tail_list(&tmp_list, l);
+ init_list(l);
+ add_tail_list(l, &tmp_list);
+ }
+
return !EMPTY_LIST(*l);
}
diff --git a/lib/event.h b/lib/event.h
index 03735c3f..5f3b78d8 100644
--- a/lib/event.h
+++ b/lib/event.h
@@ -21,14 +21,17 @@ typedef struct event {
typedef list event_list;
extern event_list global_event_list;
+extern event_list global_work_list;
event *ev_new(pool *);
void ev_run(event *);
#define ev_init_list(el) init_list(el)
void ev_enqueue(event_list *, event *);
void ev_schedule(event *);
+void ev_schedule_work(event *);
void ev_postpone(event *);
int ev_run_list(event_list *);
+int ev_run_list_limited(event_list *, uint);
static inline int
ev_active(event *e)
diff --git a/lib/fletcher16_test.c b/lib/fletcher16_test.c
index 1020e6ec..3cd4c302 100644
--- a/lib/fletcher16_test.c
+++ b/lib/fletcher16_test.c
@@ -24,24 +24,33 @@ straightforward_fletcher16_compute(const char *data)
sum2 = (sum2 + sum1) % 255;
}
- return (sum2 << 8) | sum1;
+ sum2 = (sum2 + sum1) % 255;
+ sum2 = (sum2 + sum1) % 255;
+
+ return (sum1 << 8) | sum2;
}
static u16
straightforward_fletcher16_checksum(const char *data)
{
u16 csum;
- u8 c0,c1,f0,f1;
+ u16 c0,c1,x,y;
csum = straightforward_fletcher16_compute(data);
- f0 = csum & 0xff;
- f1 = (csum >> 8) & 0xff;
- c0 = 0xff - ((f0 + f1) % 0xff);
- c1 = 0xff - ((f0 + c0) % 0xff);
+ c0 = (csum >> 8) & 0xff;
+ c1 = csum & 0xff;
+
+ x = (255 + c0 - c1) % 255;
+ y = (510 - 2*c0 + c1) % 255;
- return (c1 << 8) | c0;
+ if (!x) x = 255;
+ if (!y) y = 255;
+
+ return (x << 8) | y;
}
+const u8 zero16[2] = {};
+
static int
test_fletcher16(void *out_, const void *in_, const void *expected_out_)
{
@@ -53,7 +62,8 @@ test_fletcher16(void *out_, const void *in_, const void *expected_out_)
fletcher16_init(&ctxt);
fletcher16_update(&ctxt, in, strlen(in));
- put_u16(out, fletcher16_compute(&ctxt));
+ fletcher16_update(&ctxt, zero16, 2);
+ *out = fletcher16_compute(&ctxt);
return *out == *expected_out;
}
@@ -70,7 +80,8 @@ test_fletcher16_checksum(void *out_, const void *in_, const void *expected_out_)
fletcher16_init(&ctxt);
fletcher16_update(&ctxt, in, len);
- put_u16(out, fletcher16_final(&ctxt, len, len));
+ fletcher16_update(&ctxt, zero16, 2);
+ *out = fletcher16_final(&ctxt, len+2, len);
return *out == *expected_out;
}
@@ -81,7 +92,7 @@ t_fletcher16_compute(void)
struct bt_pair test_vectors[] = {
{
.in = "\001\002",
- .out = & (const u16) { 0x0403 },
+ .out = & ((const u16) { straightforward_fletcher16_compute("\001\002") }),
},
{
.in = "",
diff --git a/lib/flowspec.c b/lib/flowspec.c
index 87ce0206..42770c50 100644
--- a/lib/flowspec.c
+++ b/lib/flowspec.c
@@ -112,7 +112,6 @@ get_value_length(const byte *op)
}
-
/*
* Flowspec iterators
*/
@@ -244,6 +243,69 @@ flow6_next_part(const byte *pos, const byte *end)
return flow_next_part(pos, end, 1);
}
+static const byte *
+flow_get_part(const byte *data, uint dlen, uint type, int ipv6)
+{
+ const byte *part;
+
+ for (part = flow_first_part(data);
+ part && (part[0] <= type);
+ part = flow_next_part(part, data+dlen, ipv6))
+ if (part[0] == type)
+ return part;
+
+ return NULL;
+}
+
+const byte *
+flow4_get_part(const net_addr_flow4 *f, uint type)
+{
+ return flow_get_part(f->data, f->length - sizeof(net_addr_flow4), type, 0);
+}
+
+const byte *
+flow6_get_part(const net_addr_flow6 *f, uint type)
+{
+ return flow_get_part(f->data, f->length - sizeof(net_addr_flow6), type, 1);
+}
+
+
+/*
+ * Flowspec accessors
+ */
+
+static inline ip4_addr
+flow_read_ip4(const byte *px, uint pxlen)
+{
+ ip4_addr ip = IP4_NONE;
+ memcpy(&ip, px, BYTES(pxlen));
+ return ip4_ntoh(ip);
+}
+
+ip4_addr
+flow_read_ip4_part(const byte *part)
+{
+ return flow_read_ip4(part + 2, part[1]);
+}
+
+static inline ip6_addr
+flow_read_ip6(const byte *px, uint pxlen, uint pxoffset)
+{
+ uint floor_offset = BYTES(pxoffset - (pxoffset % 8));
+ uint ceil_len = BYTES(pxlen);
+ ip6_addr ip = IP6_NONE;
+
+ memcpy(((byte *) &ip) + floor_offset, px, ceil_len - floor_offset);
+
+ return ip6_ntoh(ip);
+}
+
+ip6_addr
+flow_read_ip6_part(const byte *part)
+{
+ return flow_read_ip6(part + 3, part[1], part[2]);
+}
+
/*
* Flowspec validation
@@ -374,7 +436,6 @@ flow_validate(const byte *nlri, uint len, int ipv6)
enum flow_type type = 0;
const byte *pos = nlri;
const byte *end = nlri + len;
- int met_dst_pfx = 0;
while (pos < end)
{
@@ -386,8 +447,6 @@ flow_validate(const byte *nlri, uint len, int ipv6)
switch (type)
{
case FLOW_TYPE_DST_PREFIX:
- met_dst_pfx = 1;
- /* Fall through */
case FLOW_TYPE_SRC_PREFIX:
{
uint pxlen = *pos++;
@@ -494,9 +553,6 @@ flow_validate(const byte *nlri, uint len, int ipv6)
if (pos != end)
return FLOW_ST_NOT_COMPLETE;
- if (!ipv6 && !met_dst_pfx)
- return FLOW_ST_DEST_PREFIX_REQUIRED;
-
return FLOW_ST_VALID;
}
@@ -779,26 +835,6 @@ flow_builder_set_type(struct flow_builder *fb, enum flow_type type)
fb->this_type = type;
}
-static ip4_addr
-flow_read_ip4(const byte *px, uint pxlen)
-{
- ip4_addr ip = IP4_NONE;
- memcpy(&ip, px, BYTES(pxlen));
- return ip4_ntoh(ip);
-}
-
-static ip6_addr
-flow_read_ip6(const byte *px, uint pxlen, uint pxoffset)
-{
- uint floor_offset = BYTES(pxoffset - (pxoffset % 8));
- uint ceil_len = BYTES(pxlen);
- ip6_addr ip = IP6_NONE;
-
- memcpy(((byte *) &ip) + floor_offset, px, ceil_len - floor_offset);
-
- return ip6_ntoh(ip);
-}
-
static void
builder_write_parts(struct flow_builder *fb, byte *buf)
{
@@ -831,9 +867,9 @@ flow_builder4_finalize(struct flow_builder *fb, linpool *lpool)
if (fb->parts[FLOW_TYPE_DST_PREFIX].length)
{
- byte *p = fb->data.data + fb->parts[FLOW_TYPE_DST_PREFIX].offset + 1;
- pxlen = *p++;
- prefix = flow_read_ip4(p, pxlen);
+ byte *part = fb->data.data + fb->parts[FLOW_TYPE_DST_PREFIX].offset;
+ prefix = flow_read_ip4_part(part);
+ pxlen = flow_read_pxlen(part);
}
*f = NET_ADDR_FLOW4(prefix, pxlen, data_len);
@@ -861,10 +897,9 @@ flow_builder6_finalize(struct flow_builder *fb, linpool *lpool)
if (fb->parts[FLOW_TYPE_DST_PREFIX].length)
{
- byte *p = fb->data.data + fb->parts[FLOW_TYPE_DST_PREFIX].offset + 1;
- pxlen = *p++;
- uint pxoffset = *p++;
- prefix = flow_read_ip6(p, pxlen, pxoffset);
+ byte *part = fb->data.data + fb->parts[FLOW_TYPE_DST_PREFIX].offset;
+ prefix = flow_read_ip6_part(part);
+ pxlen = flow_read_pxlen(part);
}
*n = NET_ADDR_FLOW6(prefix, pxlen, data_len);
@@ -947,18 +982,18 @@ fragment_val_str(u8 val)
static void
net_format_flow_ip(buffer *b, const byte *part, int ipv6)
{
- uint pxlen = *(part+1);
+ uint pxlen = part[1];
if (ipv6)
{
- uint pxoffset = *(part+2);
+ uint pxoffset = part[2];
if (pxoffset)
- buffer_print(b, "%I6/%u offset %u; ", flow_read_ip6(part+3,pxlen,pxoffset), pxlen, pxoffset);
+ buffer_print(b, "%I6/%u offset %u; ", flow_read_ip6_part(part), pxlen, pxoffset);
else
- buffer_print(b, "%I6/%u; ", flow_read_ip6(part+3,pxlen,0), pxlen);
+ buffer_print(b, "%I6/%u; ", flow_read_ip6_part(part), pxlen);
}
else
{
- buffer_print(b, "%I4/%u; ", flow_read_ip4(part+2,pxlen), pxlen);
+ buffer_print(b, "%I4/%u; ", flow_read_ip4_part(part), pxlen);
}
}
diff --git a/lib/flowspec.h b/lib/flowspec.h
index fa90c70d..9bafc52e 100644
--- a/lib/flowspec.h
+++ b/lib/flowspec.h
@@ -83,6 +83,17 @@ const byte *flow4_first_part(const net_addr_flow4 *f);
const byte *flow6_first_part(const net_addr_flow6 *f);
const byte *flow4_next_part(const byte *pos, const byte *end);
const byte *flow6_next_part(const byte *pos, const byte *end);
+const byte *flow4_get_part(const net_addr_flow4 *f, uint type);
+const byte *flow6_get_part(const net_addr_flow6 *f, uint type);
+
+
+/*
+ * Flowspec accessors
+ */
+
+ip4_addr flow_read_ip4_part(const byte *part);
+ip6_addr flow_read_ip6_part(const byte *part);
+static inline int flow_read_pxlen(const byte *part) { return part[1]; }
/*
diff --git a/lib/flowspec_test.c b/lib/flowspec_test.c
index dd71dc7b..b6b4d7b8 100644
--- a/lib/flowspec_test.c
+++ b/lib/flowspec_test.c
@@ -137,7 +137,7 @@ static int
t_iterators6(void)
{
net_addr_flow6 *f;
- NET_ADDR_FLOW6_(f, ip6_build(0,0,0x12345678,0x9a000000), 64, ((byte[]) {
+ NET_ADDR_FLOW6_(f, ip6_build(0,0,0x12345678,0x9a000000), 0x68, ((byte[]) {
26, /* Length */
FLOW_TYPE_DST_PREFIX, 0x68, 0x40, 0x12, 0x34, 0x56, 0x78, 0x9a,
FLOW_TYPE_SRC_PREFIX, 0x08, 0x0, 0xc0,
@@ -167,6 +167,56 @@ t_iterators6(void)
}
static int
+t_accessors4(void)
+{
+ net_addr_flow4 *f;
+ NET_ADDR_FLOW4_(f, ip4_build(5,6,7,0), 24, ((byte[]) {
+ 25, /* Length */
+ FLOW_TYPE_DST_PREFIX, 24, 5, 6, 7,
+ FLOW_TYPE_SRC_PREFIX, 32, 10, 11, 12, 13,
+ FLOW_TYPE_IP_PROTOCOL, 0x81, 0x06,
+ FLOW_TYPE_PORT, 0x03, 0x89, 0x45, 0x8b, 0x91, 0x1f, 0x90,
+ FLOW_TYPE_TCP_FLAGS, 0x80, 0x55,
+ }));
+
+ const byte *p1_dst_px = &f->data[1];
+ const ip4_addr p1_dst_addr = ip4_build(5,6,7,0);
+
+ const byte *p2_src_px = &f->data[6];
+ const ip4_addr p2_src_addr = ip4_build(10,11,12,13);
+
+ bt_assert(ip4_equal(flow_read_ip4_part(p1_dst_px), p1_dst_addr));
+ bt_assert(ip4_equal(flow_read_ip4_part(p2_src_px), p2_src_addr));
+
+ return 1;
+}
+
+static int
+t_accessors6(void)
+{
+ net_addr_flow6 *f;
+ NET_ADDR_FLOW6_(f, ip6_build(0,0,0x12345678,0x9a000000), 0x68, ((byte[]) {
+ 26, /* Length */
+ FLOW_TYPE_DST_PREFIX, 0x68, 0x40, 0x12, 0x34, 0x56, 0x78, 0x9a,
+ FLOW_TYPE_SRC_PREFIX, 0x08, 0x0, 0xc0,
+ FLOW_TYPE_NEXT_HEADER, 0x81, 0x06,
+ FLOW_TYPE_PORT, 0x03, 0x89, 0x45, 0x8b, 0x91, 0x1f, 0x90,
+ FLOW_TYPE_LABEL, 0x80, 0x55,
+ }));
+
+ const byte *p1_dst_px = &f->data[1];
+ const ip6_addr p1_dst_addr = ip6_build(0,0,0x12345678,0x9a000000);
+
+ const byte *p2_src_px = &f->data[9];
+ const ip6_addr p2_src_addr = ip6_build(0xc0000000, 0, 0, 0);
+
+ bt_assert(ip6_equal(flow_read_ip6_part(p1_dst_px), p1_dst_addr));
+ bt_assert(ip6_equal(flow_read_ip6_part(p2_src_px), p2_src_addr));
+
+ return 1;
+}
+
+static int
t_validation4(void)
{
enum flow_validated_state res;
@@ -179,11 +229,9 @@ t_validation4(void)
FLOW_TYPE_TCP_FLAGS, 0x80, 0x55,
};
- /* Isn't included destination prefix */
+ /* Empty NLRI */
res = flow4_validate(nlri1, 0);
- bt_assert(res == FLOW_ST_DEST_PREFIX_REQUIRED);
- res = flow4_validate(&nlri1[5], sizeof(nlri1)-5);
- bt_assert(res == FLOW_ST_DEST_PREFIX_REQUIRED);
+ bt_assert(res == FLOW_ST_VALID);
/* Valid / Not Complete testing */
uint valid_sizes[] = {5, 11, 14, 22, 25, 0};
@@ -628,6 +676,8 @@ main(int argc, char *argv[])
bt_test_suite(t_first_part, "Searching first part in net_addr_flow");
bt_test_suite(t_iterators4, "Testing iterators (IPv4)");
bt_test_suite(t_iterators6, "Testing iterators (IPv6)");
+ bt_test_suite(t_accessors4, "Testing accessors (IPv4)");
+ bt_test_suite(t_accessors6, "Testing accessors (IPv6)");
bt_test_suite(t_validation4, "Testing validation (IPv4)");
bt_test_suite(t_validation6, "Testing validation (IPv6)");
bt_test_suite(t_builder4, "Inserting components into existing Flow Specification (IPv4)");
diff --git a/lib/ip.c b/lib/ip.c
index 2d195160..fcc72caf 100644
--- a/lib/ip.c
+++ b/lib/ip.c
@@ -264,6 +264,9 @@ ip6_pton(const char *a, ip6_addr *o)
int i, j, k, l, hfil;
const char *start;
+ if (!a[0]) /* Empty string check */
+ return 0;
+
if (a[0] == ':') /* Leading :: */
{
if (a[1] != ':')
@@ -333,6 +336,8 @@ ip6_pton(const char *a, ip6_addr *o)
for (; i>=hfil; i--)
words[i] = 0;
}
+ else if (i != 8) /* Incomplete address */
+ return 0;
/* Convert the address to ip6_addr format */
for (i=0; i<4; i++)
diff --git a/lib/ip.h b/lib/ip.h
index 945f2893..f3b1cc31 100644
--- a/lib/ip.h
+++ b/lib/ip.h
@@ -48,6 +48,13 @@
#define UDP_HEADER_LENGTH 8
+/* IANA Address Family Numbers */
+/* https://www.iana.org/assignments/address-family-numbers/address-family-numbers.xhtml */
+/* Would use AF_ prefix, but that collides with POSIX address family numbers */
+#define AFI_IPV4 1
+#define AFI_IPV6 2
+
+
#ifdef DEBUGGING
typedef struct ip4_addr {
diff --git a/lib/ip_test.c b/lib/ip_test.c
index fd70c957..36d10d68 100644
--- a/lib/ip_test.c
+++ b/lib/ip_test.c
@@ -13,25 +13,38 @@
#define IP4_MAX_LEN 16
static int
-test_ipa_pton(void *out_, const void *in_, const void *expected_out_)
+test_ip4_pton(void *out_, const void *in_, const void *expected_out_)
{
ip_addr *out = out_;
const char *in = in_;
const ip_addr *expected_out = expected_out_;
+ ip4_addr ip4;
- if (ipa_is_ip4(*expected_out))
+ if (expected_out)
{
- ip4_addr ip4;
bt_assert(ip4_pton(in, &ip4));
*out = ipa_from_ip4(ip4);
+ return ipa_equal(*out, *expected_out);
}
else
+ return !ip4_pton(in, &ip4);
+
+}
+
+static int
+test_ip6_pton(void *out_, const void *in_, const void *expected_out_)
+{
+ ip_addr *out = out_;
+ const char *in = in_;
+ const ip_addr *expected_out = expected_out_;
+
+ if (expected_out)
{
bt_assert(ip6_pton(in, out));
- /* ip_addr == ip6_addr */
+ return ipa_equal(*out, *expected_out);
}
-
- return ipa_equal(*out, *expected_out);
+ else
+ return !ip6_pton(in, out);
}
static int
@@ -52,7 +65,7 @@ t_ip4_pton(void)
},
};
- return bt_assert_batch(test_vectors, test_ipa_pton, bt_fmt_str, bt_fmt_ipa);
+ return bt_assert_batch(test_vectors, test_ip4_pton, bt_fmt_str, bt_fmt_ipa);
}
static int
@@ -87,9 +100,17 @@ t_ip6_pton(void)
.in = "2605:2700:0:3::4713:93e3",
.out = & ipa_build6(0x26052700, 0x00000003, 0x00000000, 0x471393E3),
},
+ {
+ .in = "2605:2700:0:3:4713:93e3",
+ .out = NULL,
+ },
+ {
+ .in = "2",
+ .out = NULL,
+ },
};
- return bt_assert_batch(test_vectors, test_ipa_pton, bt_fmt_str, bt_fmt_ipa);
+ return bt_assert_batch(test_vectors, test_ip6_pton, bt_fmt_str, bt_fmt_ipa);
}
static int
diff --git a/lib/lists.c b/lib/lists.c
index 4a48d3b7..200576cf 100644
--- a/lib/lists.c
+++ b/lib/lists.c
@@ -29,6 +29,42 @@
#include "nest/bird.h"
#include "lib/lists.h"
+LIST_INLINE int
+check_list(list *l, node *n)
+{
+ if (!l)
+ {
+ ASSERT_DIE(n);
+ ASSERT_DIE(n->prev);
+
+ do { n = n->prev; } while (n->prev);
+
+ l = SKIP_BACK(list, head_node, n);
+ }
+
+ int seen = 0;
+
+ ASSERT_DIE(l->null == NULL);
+ ASSERT_DIE(l->head != NULL);
+ ASSERT_DIE(l->tail != NULL);
+
+ node *prev = &l->head_node, *cur = l->head, *next = l->head->next;
+ while (next)
+ {
+ if (cur == n)
+ seen++;
+ ASSERT_DIE(cur->prev == prev);
+ prev = cur;
+ cur = next;
+ next = next->next;
+ }
+
+ ASSERT_DIE(cur == &(l->tail_node));
+ ASSERT_DIE(!n || (seen == 1));
+
+ return 1;
+}
+
/**
* add_tail - append a node to a list
* @l: linked list
@@ -39,6 +75,10 @@
LIST_INLINE void
add_tail(list *l, node *n)
{
+ EXPENSIVE_CHECK(check_list(l, NULL));
+ ASSUME(n->prev == NULL);
+ ASSUME(n->next == NULL);
+
node *z = l->tail;
n->next = &l->tail_node;
@@ -57,6 +97,10 @@ add_tail(list *l, node *n)
LIST_INLINE void
add_head(list *l, node *n)
{
+ EXPENSIVE_CHECK(check_list(l, NULL));
+ ASSUME(n->prev == NULL);
+ ASSUME(n->next == NULL);
+
node *z = l->head;
n->next = z;
@@ -76,6 +120,10 @@ add_head(list *l, node *n)
LIST_INLINE void
insert_node(node *n, node *after)
{
+ EXPENSIVE_CHECK(check_list(l, after));
+ ASSUME(n->prev == NULL);
+ ASSUME(n->next == NULL);
+
node *z = after->next;
n->next = z;
@@ -93,6 +141,8 @@ insert_node(node *n, node *after)
LIST_INLINE void
rem_node(node *n)
{
+ EXPENSIVE_CHECK(check_list(NULL, n));
+
node *z = n->prev;
node *x = n->next;
@@ -103,24 +153,20 @@ rem_node(node *n)
}
/**
- * replace_node - replace a node in a list with another one
- * @old: node to be removed
- * @new: node to be inserted
+ * update_node - update node after calling realloc on it
+ * @n: node to be updated
*
- * Replaces node @old in the list it's linked in with node @new. Node
- * @old may be a copy of the original node, which is not accessed
- * through the list. The function could be called with @old == @new,
- * which just fixes neighbors' pointers in the case that the node
- * was reallocated.
+ * Fixes neighbor pointers.
*/
LIST_INLINE void
-replace_node(node *old, node *new)
+update_node(node *n)
{
- old->next->prev = new;
- old->prev->next = new;
+ ASSUME(n->next->prev == n->prev->next);
- new->prev = old->prev;
- new->next = old->next;
+ n->next->prev = n;
+ n->prev->next = n;
+
+ EXPENSIVE_CHECK(check_list(NULL, n));
}
/**
@@ -149,6 +195,9 @@ init_list(list *l)
LIST_INLINE void
add_tail_list(list *to, list *l)
{
+ EXPENSIVE_CHECK(check_list(to, NULL));
+ EXPENSIVE_CHECK(check_list(l, NULL));
+
node *p = to->tail;
node *q = l->head;
@@ -157,6 +206,8 @@ add_tail_list(list *to, list *l)
q = l->tail;
q->next = &to->tail_node;
to->tail = q;
+
+ EXPENSIVE_CHECK(check_list(to, NULL));
}
LIST_INLINE uint
@@ -165,6 +216,8 @@ list_length(list *l)
uint len = 0;
node *n;
+ EXPENSIVE_CHECK(check_list(l, NULL));
+
WALK_LIST(n, *l)
len++;
diff --git a/lib/lists_test.c b/lib/lists_test.c
index f26a88e2..cf0021fe 100644
--- a/lib/lists_test.c
+++ b/lib/lists_test.c
@@ -222,26 +222,29 @@ t_remove_node(void)
}
static int
-t_replace_node(void)
+t_update_node(void)
{
node head, inside, tail;
init_list_();
fill_list();
- replace_node(&nodes[0], &head);
+ head = nodes[0];
+ update_node(&head);
bt_assert(l.head == &head);
bt_assert(head.prev == NODE &l.head);
bt_assert(head.next == &nodes[1]);
bt_assert(nodes[1].prev == &head);
- replace_node(&nodes[MAX_NUM/2], &inside);
+ inside = nodes[MAX_NUM/2];
+ update_node(&inside);
bt_assert(nodes[MAX_NUM/2-1].next == &inside);
bt_assert(nodes[MAX_NUM/2+1].prev == &inside);
bt_assert(inside.prev == &nodes[MAX_NUM/2-1]);
bt_assert(inside.next == &nodes[MAX_NUM/2+1]);
- replace_node(&nodes[MAX_NUM-1], &tail);
+ tail = nodes[MAX_NUM-1];
+ update_node(&tail);
bt_assert(l.tail == &tail);
bt_assert(tail.prev == &nodes[MAX_NUM-2]);
bt_assert(tail.next == NODE &l.null);
@@ -280,7 +283,7 @@ main(int argc, char *argv[])
bt_test_suite(t_add_head, "Adding nodes to head of list");
bt_test_suite(t_insert_node, "Inserting nodes to list");
bt_test_suite(t_remove_node, "Removing nodes from list");
- bt_test_suite(t_replace_node, "Replacing nodes in list");
+ bt_test_suite(t_update_node, "Updating nodes in list");
bt_test_suite(t_add_tail_list, "At the tail of a list adding the another list");
return bt_exit_value();
diff --git a/lib/net.h b/lib/net.h
index 0cd5f735..8eb4c7b9 100644
--- a/lib/net.h
+++ b/lib/net.h
@@ -174,10 +174,10 @@ extern const u16 net_max_text_length[];
((net_addr_roa6) { NET_ROA6, pxlen, sizeof(net_addr_roa6), prefix, max_pxlen, asn })
#define NET_ADDR_FLOW4(prefix,pxlen,dlen) \
- ((net_addr_flow4) { NET_FLOW4, pxlen, sizeof(net_addr_ip4) + dlen, prefix })
+ ((net_addr_flow4) { NET_FLOW4, pxlen, sizeof(net_addr_flow4) + dlen, prefix })
#define NET_ADDR_FLOW6(prefix,pxlen,dlen) \
- ((net_addr_flow6) { NET_FLOW6, pxlen, sizeof(net_addr_ip6) + dlen, prefix })
+ ((net_addr_flow6) { NET_FLOW6, pxlen, sizeof(net_addr_flow6) + dlen, prefix })
#define NET_ADDR_IP6_SADR(dst_prefix,dst_pxlen,src_prefix,src_pxlen) \
((net_addr_ip6_sadr) { NET_IP6_SADR, dst_pxlen, sizeof(net_addr_ip6_sadr), dst_prefix, src_pxlen, src_prefix })
diff --git a/lib/resource.c b/lib/resource.c
index ab8c800f..5589373e 100644
--- a/lib/resource.c
+++ b/lib/resource.c
@@ -340,6 +340,7 @@ mb_alloc(pool *p, unsigned size)
struct mblock *b = xmalloc(sizeof(struct mblock) + size);
b->r.class = &mb_class;
+ b->r.n = (node) {};
add_tail(&p->inside, &b->r.n);
b->size = size;
return b->data;
@@ -387,7 +388,7 @@ mb_realloc(void *m, unsigned size)
struct mblock *b = SKIP_BACK(struct mblock, data, m);
b = xrealloc(b, sizeof(struct mblock) + size);
- replace_node(&b->r.n, &b->r.n);
+ update_node(&b->r.n);
b->size = size;
return b->data;
}
diff --git a/lib/resource.h b/lib/resource.h
index ad17d9ed..b56bcff5 100644
--- a/lib/resource.h
+++ b/lib/resource.h
@@ -83,6 +83,7 @@ typedef struct slab slab;
slab *sl_new(pool *, unsigned size);
void *sl_alloc(slab *);
+void *sl_allocz(slab *);
void sl_free(slab *, void *);
/*
diff --git a/lib/slab.c b/lib/slab.c
index 5c414f9e..f31355e0 100644
--- a/lib/slab.c
+++ b/lib/slab.c
@@ -88,6 +88,14 @@ sl_alloc(slab *s)
return o->data;
}
+void *
+sl_allocz(slab *s)
+{
+ void *obj = sl_alloc(s);
+ memset(obj, 0, s->size);
+ return obj;
+}
+
void
sl_free(slab *s, void *oo)
{
@@ -216,8 +224,11 @@ sl_new_head(slab *s)
struct sl_obj *no;
uint n = s->objs_per_slab;
- h->first_free = o;
- h->num_full = 0;
+ *h = (struct sl_head) {
+ .first_free = o,
+ .num_full = 0,
+ };
+
while (n--)
{
o->slab = h;
@@ -276,6 +287,22 @@ no_partial:
}
/**
+ * sl_allocz - allocate an object from Slab and zero it
+ * @s: slab
+ *
+ * sl_allocz() allocates space for a single object from the
+ * Slab and returns a pointer to the object after zeroing out
+ * the object memory.
+ */
+void *
+sl_allocz(slab *s)
+{
+ void *obj = sl_alloc(s);
+ memset(obj, 0, s->data_size);
+ return obj;
+}
+
+/**
* sl_free - return a free object back to a Slab
* @s: slab
* @oo: object returned by sl_alloc()
diff --git a/lib/socket.h b/lib/socket.h
index 03c15dcd..96fedeeb 100644
--- a/lib/socket.h
+++ b/lib/socket.h
@@ -76,7 +76,7 @@ typedef struct birdsock {
int rcv_ttl; /* TTL of last received datagram */
node n;
void *rbuf_alloc, *tbuf_alloc;
- char *password; /* Password for MD5 authentication */
+ const char *password; /* Password for MD5 authentication */
const char *err; /* Error message */
struct ssh_sock *ssh; /* Used in SK_SSH */
} sock;
@@ -106,7 +106,7 @@ int sk_leave_group(sock *s, ip_addr maddr); /* Leave multicast group on sk iface
int sk_setup_broadcast(sock *s);
int sk_set_ttl(sock *s, int ttl); /* Set transmit TTL for given socket */
int sk_set_min_ttl(sock *s, int ttl); /* Set minimal accepted TTL for given socket */
-int sk_set_md5_auth(sock *s, ip_addr local, ip_addr remote, struct iface *ifa, char *passwd, int setkey);
+int sk_set_md5_auth(sock *s, ip_addr local, ip_addr remote, int pxlen, struct iface *ifa, const char *passwd, int setkey);
int sk_set_ipv6_checksum(sock *s, int offset);
int sk_set_icmp6_filter(sock *s, int p1, int p2);
void sk_log_error(sock *s, const char *p);
diff --git a/lib/string.h b/lib/string.h
index d6ae5ef7..0f650178 100644
--- a/lib/string.h
+++ b/lib/string.h
@@ -72,6 +72,15 @@ bstrcmp(const char *s1, const char *s2)
return !s2 - !s1;
}
+static inline void *
+bmemcpy(void *dest, const void *src, size_t n)
+{
+ if (n)
+ return memcpy(dest, src, n);
+ else
+ return dest;
+}
+
#define ROUTER_ID_64_LENGTH 23
#endif
diff --git a/lib/timer.c b/lib/timer.c
index ddf41340..a5abbcc4 100644
--- a/lib/timer.c
+++ b/lib/timer.c
@@ -253,9 +253,9 @@ timer_init(void)
* type &btime.
*/
btime
-tm_parse_time(char *x)
+tm_parse_time(const char *x)
{
- struct tm tm;
+ struct tm tm = {};
int usec, n1, n2, n3, r;
r = sscanf(x, "%d-%d-%d%n %d:%d:%d%n.%d%n",
diff --git a/lib/timer.h b/lib/timer.h
index 3b99825f..c5ea430c 100644
--- a/lib/timer.h
+++ b/lib/timer.h
@@ -106,7 +106,7 @@ void timer_init(void);
struct timeformat {
- char *fmt1, *fmt2;
+ const char *fmt1, *fmt2;
btime limit;
};
@@ -120,7 +120,7 @@ struct timeformat {
#define TM_DATETIME_BUFFER_SIZE 32 /* Buffer size required by tm_format_time() */
-btime tm_parse_time(char *x);
+btime tm_parse_time(const char *x);
void tm_format_time(char *x, struct timeformat *fmt, btime t);
int tm_format_real_time(char *x, size_t max, const char *fmt, btime t);
diff --git a/nest/a-path.c b/nest/a-path.c
index b6a30f54..2e34a3d1 100644
--- a/nest/a-path.c
+++ b/nest/a-path.c
@@ -25,7 +25,7 @@
#define BAD(DSC, VAL) ({ err_dsc = DSC; err_val = VAL; goto bad; })
int
-as_path_valid(byte *data, uint len, int bs, int confed, char *err, uint elen)
+as_path_valid(byte *data, uint len, int bs, int sets, int confed, char *err, uint elen)
{
byte *pos = data;
char *err_dsc = NULL;
@@ -46,13 +46,21 @@ as_path_valid(byte *data, uint len, int bs, int confed, char *err, uint elen)
switch (type)
{
case AS_PATH_SET:
+ if (!sets)
+ BAD("AS_SET segment", type);
+ break;
+
case AS_PATH_SEQUENCE:
break;
case AS_PATH_CONFED_SEQUENCE:
- case AS_PATH_CONFED_SET:
if (!confed)
- BAD("AS_CONFED* segment", type);
+ BAD("AS_CONFED_SEQUENCE segment", type);
+ break;
+
+ case AS_PATH_CONFED_SET:
+ if (!sets || !confed)
+ BAD("AS_CONFED_SET segment", type);
break;
default:
@@ -719,7 +727,7 @@ parse_path(const struct adata *path, struct pm_pos *pp)
}
static int
-pm_match(struct pm_pos *pos, u32 asn, u32 asn2)
+pm_match_val(const struct pm_pos *pos, u32 asn, u32 asn2)
{
u32 gas;
if (! pos->set)
@@ -741,7 +749,7 @@ pm_match(struct pm_pos *pos, u32 asn, u32 asn2)
}
static int
-pm_match_set(struct pm_pos *pos, const struct f_tree *set)
+pm_match_set(const struct pm_pos *pos, const struct f_tree *set)
{
struct f_val asn = { .type = T_INT };
@@ -765,25 +773,34 @@ pm_match_set(struct pm_pos *pos, const struct f_tree *set)
return 0;
}
+static inline int
+pm_match(const struct pm_pos *pos, const struct f_path_mask_item *mask, u32 asn, u32 asn2)
+{
+ return ((mask->kind == PM_QUESTION) ||
+ ((mask->kind != PM_ASN_SET) ?
+ pm_match_val(pos, asn, asn2) :
+ pm_match_set(pos, mask->set)));
+}
+
static void
-pm_mark(struct pm_pos *pos, int i, int plen, int *nl, int *nh)
+pm_mark(struct pm_pos *pos, int *i, int plen, int *nl, int *nh)
{
- int j;
+ int j = *i;
- if (pos[i].set)
- pos[i].mark = 1;
+ if (pos[j].set)
+ do { pos[j].mark = 1; j++; }
+ while ((j < plen) && pos[j].set);
+ else
+ j++;
- for (j = i + 1; (j < plen) && pos[j].set && (! pos[j].mark); j++)
- pos[j].mark = 1;
pos[j].mark = 1;
- /* We are going downwards, therefore every mark is
- new low and just the first mark is new high */
+ /* Update low, high based on first and last marked pos */
+ int l = pos[*i].set ? *i : j;
- *nl = i + (pos[i].set ? 0 : 1);
-
- if (*nh < 0)
- *nh = j;
+ *nl = (*nl < 0) ? l : MIN(*nl, l);
+ *nh = MAX(*nh, j);
+ *i = j;
}
/* AS path matching is nontrivial. Because AS path can
@@ -813,7 +830,7 @@ as_path_match(const struct adata *path, const struct f_path_mask *mask)
{
struct pm_pos pos[2048 + 1];
int plen = parse_path(path, pos);
- int l, h, i, nh, nl;
+ int l, h, i, nh, nl, last, loop;
u32 val = 0;
u32 val2 = 0;
@@ -823,7 +840,7 @@ as_path_match(const struct adata *path, const struct f_path_mask *mask)
pos[plen].set = 0;
pos[plen].mark = 0;
- l = h = 0;
+ l = h = loop = 0;
pos[0].mark = 1;
for (uint m=0; m < mask->len; m++)
@@ -839,6 +856,10 @@ as_path_match(const struct adata *path, const struct f_path_mask *mask)
h = plen;
break;
+ case PM_LOOP:
+ loop = 1;
+ break;
+
case PM_ASN: /* Define single ASN as ASN..ASN - very narrow interval */
val2 = val = mask->item[m].asn;
goto step;
@@ -852,15 +873,22 @@ as_path_match(const struct adata *path, const struct f_path_mask *mask)
case PM_ASN_SET:
step:
nh = nl = -1;
+ last = plen;
for (i = h; i >= l; i--)
if (pos[i].mark)
{
pos[i].mark = 0;
- if ((mask->item[m].kind == PM_QUESTION) ||
- ((mask->item[m].kind != PM_ASN_SET) ?
- pm_match(pos + i, val, val2) :
- pm_match_set(pos + i, mask->item[m].set)))
- pm_mark(pos, i, plen, &nl, &nh);
+ int j = i;
+
+ match:
+ if (pm_match(pos + j, &mask->item[m], val, val2))
+ {
+ pm_mark(pos, &j, plen, &nl, &nh);
+ if (loop && (j < last))
+ goto match;
+ }
+
+ last = i;
}
if (nh < 0)
@@ -868,6 +896,7 @@ as_path_match(const struct adata *path, const struct f_path_mask *mask)
h = nh;
l = nl;
+ loop = 0;
break;
}
}
diff --git a/nest/attrs.h b/nest/attrs.h
index 6fb0a8fa..50da817b 100644
--- a/nest/attrs.h
+++ b/nest/attrs.h
@@ -30,7 +30,7 @@
struct f_tree;
-int as_path_valid(byte *data, uint len, int bs, int confed, char *err, uint elen);
+int as_path_valid(byte *data, uint len, int bs, int sets, int confed, char *err, uint elen);
int as_path_16to32(byte *dst, const byte *src, uint len);
int as_path_32to16(byte *dst, const byte *src, uint len);
int as_path_contains_as4(const struct adata *path);
@@ -61,6 +61,7 @@ static inline struct adata *as_path_prepend(struct linpool *pool, const struct a
#define PM_ASN_EXPR 3
#define PM_ASN_RANGE 4
#define PM_ASN_SET 5
+#define PM_LOOP 6
struct f_path_mask_item {
union {
@@ -111,7 +112,7 @@ static inline struct adata *
aggregator_to_old(struct linpool *pool, const struct adata *a)
{
struct adata *d = lp_alloc_adata(pool, 8);
- put_u32(d->data, 0xFFFF);
+ put_u32(d->data, AS_TRANS);
memcpy(d->data + 4, a->data + 4, 4);
return d;
}
diff --git a/nest/bfd.h b/nest/bfd.h
index 36add991..37561266 100644
--- a/nest/bfd.h
+++ b/nest/bfd.h
@@ -9,9 +9,20 @@
#include "lib/lists.h"
#include "lib/resource.h"
+#include "conf/conf.h"
struct bfd_session;
+struct bfd_options {
+ u32 min_rx_int;
+ u32 min_tx_int;
+ u32 idle_tx_int;
+ u8 multiplier;
+ u8 passive;
+ u8 passive_set;
+ u8 mode;
+};
+
struct bfd_request {
resource r;
node n;
@@ -20,6 +31,7 @@ struct bfd_request {
ip_addr local;
struct iface *iface;
struct iface *vrf;
+ struct bfd_options opts;
void (*hook)(struct bfd_request *);
void *data;
@@ -32,6 +44,7 @@ struct bfd_request {
u8 down;
};
+#define BGP_BFD_GRACEFUL 2 /* BFD down triggers graceful restart */
#define BFD_STATE_ADMIN_DOWN 0
#define BFD_STATE_DOWN 1
@@ -39,15 +52,20 @@ struct bfd_request {
#define BFD_STATE_UP 3
+static inline struct bfd_options * bfd_new_options(void)
+{ return cfg_allocz(sizeof(struct bfd_options)); }
+
#ifdef CONFIG_BFD
-struct bfd_request * bfd_request_session(pool *p, ip_addr addr, ip_addr local, struct iface *iface, struct iface *vrf, void (*hook)(struct bfd_request *), void *data);
+struct bfd_request * bfd_request_session(pool *p, ip_addr addr, ip_addr local, struct iface *iface, struct iface *vrf, void (*hook)(struct bfd_request *), void *data, const struct bfd_options *opts);
+void bfd_update_request(struct bfd_request *req, const struct bfd_options *opts);
static inline void cf_check_bfd(int use UNUSED) { }
#else
-static inline struct bfd_request * bfd_request_session(pool *p UNUSED, ip_addr addr UNUSED, ip_addr local UNUSED, struct iface *iface UNUSED, struct iface *vrf UNUSED, void (*hook)(struct bfd_request *) UNUSED, void *data UNUSED) { return NULL; }
+static inline struct bfd_request * bfd_request_session(pool *p UNUSED, ip_addr addr UNUSED, ip_addr local UNUSED, struct iface *iface UNUSED, struct iface *vrf UNUSED, void (*hook)(struct bfd_request *) UNUSED, void *data UNUSED, const struct bfd_options *opts UNUSED) { return NULL; }
+static inline void bfd_update_request(struct bfd_request *req UNUSED, const struct bfd_options *opts UNUSED) { };
static inline void cf_check_bfd(int use) { if (use) cf_error("BFD not available"); }
diff --git a/nest/cli.c b/nest/cli.c
index 24962f10..b54a0d76 100644
--- a/nest/cli.c
+++ b/nest/cli.c
@@ -143,6 +143,7 @@ cli_printf(cli *c, int code, char *msg, ...)
{
size = bsprintf(buf, "%04d ", cd);
errcode = 8000;
+ cd = 0; /* Final message - no more continuation lines */
}
c->last_reply = cd;
diff --git a/nest/cli.h b/nest/cli.h
index 6040be91..8a3294c5 100644
--- a/nest/cli.h
+++ b/nest/cli.h
@@ -58,6 +58,9 @@ void cli_printf(cli *, int, char *, ...);
#define cli_msg(x...) cli_printf(this_cli, x)
void cli_set_log_echo(cli *, uint mask, uint size);
+static inline void cli_separator(cli *c)
+{ if (c->last_reply) cli_printf(c, -c->last_reply, ""); };
+
/* Functions provided to sysdep layer */
cli *cli_new(void *);
diff --git a/nest/cmds.c b/nest/cmds.c
index da4015cf..18f39eb5 100644
--- a/nest/cmds.c
+++ b/nest/cmds.c
@@ -27,6 +27,7 @@ cmd_show_status(void)
cli_msg(-1000, "BIRD " BIRD_VERSION);
tm_format_time(tim, &config->tf_base, current_time());
cli_msg(-1011, "Router ID is %R", config->router_id);
+ cli_msg(-1011, "Hostname is %s", config->hostname);
cli_msg(-1011, "Current server time is %s", tim);
tm_format_time(tim, &config->tf_base, boot_time);
cli_msg(-1011, "Last reboot on %s", tim);
diff --git a/nest/config.Y b/nest/config.Y
index c62501a3..7b7f12cc 100644
--- a/nest/config.Y
+++ b/nest/config.Y
@@ -25,6 +25,7 @@ static struct iface_patt_node *this_ipn;
static list *this_p_list;
static struct password_item *this_p_item;
static int password_id;
+static struct bfd_options *this_bfd_opts;
static void
iface_patt_check(void)
@@ -51,6 +52,28 @@ get_passwords(void)
return rv;
}
+static inline void
+init_bfd_opts(struct bfd_options **opts)
+{
+ cf_check_bfd(1);
+
+ if (! *opts)
+ *opts = bfd_new_options();
+}
+
+static inline void
+open_bfd_opts(struct bfd_options **opts)
+{
+ init_bfd_opts(opts);
+ this_bfd_opts = *opts;
+}
+
+static inline void
+close_bfd_opts(void)
+{
+ this_bfd_opts = NULL;
+}
+
static void
proto_postconfig(void)
{
@@ -64,17 +87,19 @@ proto_postconfig(void)
CF_DECLS
-CF_KEYWORDS(ROUTER, ID, PROTOCOL, TEMPLATE, PREFERENCE, DISABLED, DEBUG, ALL, OFF, DIRECT)
+CF_KEYWORDS(ROUTER, ID, HOSTNAME, PROTOCOL, TEMPLATE, PREFERENCE, DISABLED, DEBUG, ALL, OFF, DIRECT)
CF_KEYWORDS(INTERFACE, IMPORT, EXPORT, FILTER, NONE, VRF, DEFAULT, TABLE, STATES, ROUTES, FILTERS)
CF_KEYWORDS(IPV4, IPV6, VPN4, VPN6, ROA4, ROA6, FLOW4, FLOW6, SADR, MPLS)
-CF_KEYWORDS(RECEIVE, LIMIT, ACTION, WARN, BLOCK, RESTART, DISABLE, KEEP, FILTERED)
-CF_KEYWORDS(PASSWORD, FROM, PASSIVE, TO, ID, EVENTS, PACKETS, PROTOCOLS, INTERFACES)
+CF_KEYWORDS(RECEIVE, LIMIT, ACTION, WARN, BLOCK, RESTART, DISABLE, KEEP, FILTERED, RPKI)
+CF_KEYWORDS(PASSWORD, FROM, PASSIVE, TO, ID, EVENTS, PACKETS, PROTOCOLS, CHANNELS, INTERFACES)
CF_KEYWORDS(ALGORITHM, KEYED, HMAC, MD5, SHA1, SHA256, SHA384, SHA512)
-CF_KEYWORDS(PRIMARY, STATS, COUNT, BY, FOR, COMMANDS, PREEXPORT, NOEXPORT, GENERATE)
+CF_KEYWORDS(PRIMARY, STATS, COUNT, BY, FOR, COMMANDS, PREEXPORT, NOEXPORT, EXPORTED, GENERATE)
CF_KEYWORDS(BGP, PASSWORDS, DESCRIPTION, SORTED)
CF_KEYWORDS(RELOAD, IN, OUT, MRTDUMP, MESSAGES, RESTRICT, MEMORY, IGP_METRIC, CLASS, DSCP)
CF_KEYWORDS(TIMEFORMAT, ISO, SHORT, LONG, ROUTE, PROTOCOL, BASE, LOG, S, MS, US)
CF_KEYWORDS(GRACEFUL, RESTART, WAIT, MAX, FLUSH, AS)
+CF_KEYWORDS(MIN, IDLE, RX, TX, INTERVAL, MULTIPLIER, PASSIVE)
+CF_KEYWORDS(CHECK, LINK)
/* For r_args_channel */
CF_KEYWORDS(IPV4, IPV4_MC, IPV4_MPLS, IPV6, IPV6_MC, IPV6_MPLS, IPV6_SADR, VPN4, VPN4_MC, VPN4_MPLS, VPN6, VPN6_MC, VPN6_MPLS, ROA4, ROA6, FLOW4, FLOW6, MPLS, PRI, SEC)
@@ -84,6 +109,7 @@ CF_ENUM(T_ENUM_RTS, RTS_, DUMMY, STATIC, INHERIT, DEVICE, STATIC_DEVICE, REDIREC
CF_ENUM(T_ENUM_SCOPE, SCOPE_, HOST, LINK, SITE, ORGANIZATION, UNIVERSE, UNDEFINED)
CF_ENUM(T_ENUM_RTD, RTD_, UNICAST, BLACKHOLE, UNREACHABLE, PROHIBIT)
CF_ENUM(T_ENUM_ROA, ROA_, UNKNOWN, VALID, INVALID)
+CF_ENUM_PX(T_ENUM_AF, AF_, AFI_, IPV4, IPV6)
%type <i32> idval
%type <f> imexport
@@ -97,7 +123,8 @@ CF_ENUM(T_ENUM_ROA, ROA_, UNKNOWN, VALID, INVALID)
%type <cl> limit_spec
%type <net> r_args_for_val
%type <net_ptr> r_args_for
-%type <t> r_args_channel
+%type <t> channel_sym
+%type <c> channel_arg
CF_GRAMMAR
@@ -124,6 +151,10 @@ idval:
}
;
+conf: hostname_override ;
+
+hostname_override: HOSTNAME text ';' { new_config->hostname = $2; } ;
+
conf: gr_opts ;
gr_opts: GRACEFUL RESTART WAIT expr ';' { new_config->gr_wait = $4; } ;
@@ -221,7 +252,7 @@ channel_start: net_type
$$ = this_channel = channel_config_get(NULL, net_label[$1], $1, this_proto);
};
-channel_item:
+channel_item_:
TABLE rtable {
if (this_channel->net_type && ($2->addr_type != this_channel->net_type))
cf_error("Incompatible table type");
@@ -234,6 +265,13 @@ channel_item:
| EXPORT LIMIT limit_spec { this_channel->out_limit = $3; }
| PREFERENCE expr { this_channel->preference = $2; check_u16($2); }
| IMPORT KEEP FILTERED bool { this_channel->in_keep_filtered = $4; }
+ | RPKI RELOAD bool { this_channel->rpki_reload = $3; }
+ ;
+
+/* To avoid grammar collision in Pipe protocol */
+channel_item:
+ channel_item_
+ | DEBUG debug_mask { this_channel->debug = $2; }
;
channel_opts:
@@ -284,6 +322,7 @@ conf: debug_default ;
debug_default:
DEBUG PROTOCOLS debug_mask { new_config->proto_default_debug = $3; }
+ | DEBUG CHANNELS debug_mask { new_config->channel_default_debug = $3; }
| DEBUG COMMANDS expr { new_config->cli_debug = $3; }
;
@@ -453,11 +492,11 @@ password_item:
password_item_begin:
PASSWORD text {
if (!this_p_list) {
- this_p_list = cfg_alloc(sizeof(list));
+ this_p_list = cfg_allocz(sizeof(list));
init_list(this_p_list);
password_id = 1;
}
- this_p_item = cfg_alloc(sizeof (struct password_item));
+ this_p_item = cfg_allocz(sizeof(struct password_item));
this_p_item->password = $2;
this_p_item->length = strlen($2);
this_p_item->genfrom = 0;
@@ -478,7 +517,7 @@ password_item_params:
| ACCEPT TO time ';' password_item_params { this_p_item->accto = $3; }
| FROM time ';' password_item_params { this_p_item->genfrom = this_p_item->accfrom = $2; }
| TO time ';' password_item_params { this_p_item->gento = this_p_item->accto = $2; }
- | ID expr ';' password_item_params { this_p_item->id = $2; if ($2 <= 0) cf_error("Password ID has to be greated than zero."); }
+ | ID expr ';' password_item_params { this_p_item->id = $2; if ($2 > 255) cf_error("Password ID must be in range 0-255"); }
| ALGORITHM password_algorithm ';' password_item_params { this_p_item->alg = $2; }
;
@@ -495,6 +534,28 @@ password_algorithm:
| HMAC SHA512 { $$ = ALG_HMAC_SHA512; }
;
+
+/* BFD options */
+
+bfd_item:
+ INTERVAL expr_us { this_bfd_opts->min_rx_int = this_bfd_opts->min_tx_int = $2; }
+ | MIN RX INTERVAL expr_us { this_bfd_opts->min_rx_int = $4; }
+ | MIN TX INTERVAL expr_us { this_bfd_opts->min_tx_int = $4; }
+ | IDLE TX INTERVAL expr_us { this_bfd_opts->idle_tx_int = $4; }
+ | MULTIPLIER expr { this_bfd_opts->multiplier = $2; }
+ | PASSIVE bool { this_bfd_opts->passive = $2; this_bfd_opts->passive_set = 1; }
+ | GRACEFUL { this_bfd_opts->mode = BGP_BFD_GRACEFUL; }
+ ;
+
+bfd_items:
+ /* empty */
+ | bfd_items bfd_item ';'
+ ;
+
+bfd_opts:
+ '{' bfd_items '}'
+ ;
+
/* Core commands */
CF_CLI_HELP(SHOW, ..., [[Show status information]])
@@ -556,26 +617,14 @@ r_args:
rt_show_add_table($$, t->table);
$$->tables_defined_by = RSD_TDB_ALL;
}
- | r_args IMPORT TABLE CF_SYM_KNOWN '.' r_args_channel {
- cf_assert_symbol($4, SYM_PROTO);
- $$ = $1;
- struct proto_config *cf = $4->proto;
- if (!cf->proto) cf_error("%s is not a protocol", $4->name);
- struct channel *c = proto_find_channel_by_name(cf->proto, $6);
- if (!c) cf_error("Channel %s.%s not found", $4->name, $6);
- if (!c->in_table) cf_error("No import table in channel %s.%s", $4->name, $6);
- rt_show_add_table($$, c->in_table);
+ | r_args IMPORT TABLE channel_arg {
+ if (!$4->in_table) cf_error("No import table in channel %s.%s", $4->proto->name, $4->name);
+ rt_show_add_table($$, $4->in_table);
$$->tables_defined_by = RSD_TDB_DIRECT;
}
- | r_args EXPORT TABLE CF_SYM_KNOWN '.' r_args_channel {
- cf_assert_symbol($4, SYM_PROTO);
- $$ = $1;
- struct proto_config *cf = $4->proto;
- if (!cf->proto) cf_error("%s is not a protocol", $4->name);
- struct channel *c = proto_find_channel_by_name(cf->proto, $6);
- if (!c) cf_error("Channel %s.%s not found", $4->name, $6);
- if (!c->out_table) cf_error("No export table in channel %s.%s", $4->name, $6);
- rt_show_add_table($$, c->out_table);
+ | r_args EXPORT TABLE channel_arg {
+ if (!$4->out_table) cf_error("No export table in channel %s.%s", $4->proto->name, $4->name);
+ rt_show_add_table($$, $4->out_table);
$$->tables_defined_by = RSD_TDB_DIRECT;
}
| r_args FILTER filter {
@@ -610,15 +659,11 @@ r_args:
$$->export_protocol = c->proto;
$$->tables_defined_by = RSD_TDB_INDIRECT;
}
- | r_args export_mode CF_SYM_KNOWN '.' r_args_channel {
- cf_assert_symbol($3, SYM_PROTO);
- struct proto_config *c = (struct proto_config *) $3->proto;
+ | r_args export_mode channel_arg {
$$ = $1;
if ($$->export_mode) cf_error("Export specified twice");
- if (!c->proto) cf_error("%s is not a protocol", $3->name);
$$->export_mode = $2;
- $$->export_channel = proto_find_channel_by_name(c->proto, $5);
- if (!$$->export_channel) cf_error("Export channel not found");
+ $$->export_channel = $3;
$$->tables_defined_by = RSD_TDB_INDIRECT;
}
| r_args PROTOCOL CF_SYM_KNOWN {
@@ -683,10 +728,11 @@ export_mode:
PREEXPORT { $$ = RSEM_PREEXPORT; }
| EXPORT { $$ = RSEM_EXPORT; }
| NOEXPORT { $$ = RSEM_NOEXPORT; }
+ | EXPORTED { $$ = RSEM_EXPORTED; }
;
/* This is ugly hack */
-r_args_channel:
+channel_sym:
IPV4 { $$ = "ipv4"; }
| IPV4_MC { $$ = "ipv4-mc"; }
| IPV4_MPLS { $$ = "ipv4-mpls"; }
@@ -709,6 +755,16 @@ r_args_channel:
| SEC { $$ = "sec"; }
;
+channel_arg:
+ CF_SYM_KNOWN '.' channel_sym {
+ cf_assert_symbol($1, SYM_PROTO);
+ struct proto *p = $1->proto->proto;
+ if (!p) cf_error("%s is not a protocol", $1->name);
+ $$ = proto_find_channel_by_name(p, $3);
+ if (!$$) cf_error("Channel %s.%s not found", $1->name, $3);
+ }
+ ;
+
CF_CLI_HELP(SHOW SYMBOLS, ..., [[Show all known symbolic names]])
CF_CLI(SHOW SYMBOLS, sym_args, [table|filter|function|protocol|template|<symbol>], [[Show all known symbolic names]])
{ cmd_show_symbols($3); } ;
@@ -783,8 +839,13 @@ CF_CLI(RELOAD OUT, proto_patt, <protocol> | \"<pattern>\" | all, [[Reload protoc
{ proto_apply_cmd($3, proto_cmd_reload, 1, CMD_RELOAD_OUT); } ;
CF_CLI_HELP(DEBUG, ..., [[Control protocol debugging via BIRD logs]])
-CF_CLI(DEBUG, proto_patt debug_mask, (<protocol> | \"<pattern>\" | all) (all | off | { states|routes|filters|interfaces|events|packets [, ...] }), [[Control protocol debugging via BIRD logs]])
-{ proto_apply_cmd($2, proto_cmd_debug, 1, $3); } ;
+CF_CLI(DEBUG, debug_args, (<protocol> | <channel> | \"<pattern>\" | all) (all | off | { states|routes|filters|interfaces|events|packets [, ...] }), [[Control protocol debugging via BIRD logs]])
+{ /* Done in debug_args */ };
+
+debug_args:
+ proto_patt debug_mask { proto_apply_cmd($1, proto_cmd_debug, 1, $2); }
+ | channel_arg debug_mask { channel_cmd_debug($1, $2); }
+ ;
CF_CLI_HELP(MRTDUMP, ..., [[Control protocol debugging via MRTdump files]])
CF_CLI(MRTDUMP, proto_patt mrtdump_mask, (<protocol> | \"<pattern>\" | all) (all | off | { states|messages [, ...] }), [[Control protocol debugging via MRTdump format]])
diff --git a/nest/iface.c b/nest/iface.c
index 00dfc2ca..83a633a3 100644
--- a/nest/iface.c
+++ b/nest/iface.c
@@ -172,12 +172,12 @@ static inline void
ifa_notify_change(unsigned c, struct ifa *a)
{
if (c & IF_CHANGE_DOWN)
- neigh_ifa_update(a);
+ neigh_ifa_down(a);
ifa_notify_change_(c, a);
if (c & IF_CHANGE_UP)
- neigh_ifa_update(a);
+ neigh_ifa_up(a);
}
static inline void
@@ -444,7 +444,7 @@ if_find_by_index(unsigned idx)
* if no such structure exists.
*/
struct iface *
-if_find_by_name(char *name)
+if_find_by_name(const char *name)
{
struct iface *i;
@@ -455,7 +455,7 @@ if_find_by_name(char *name)
}
struct iface *
-if_get_by_name(char *name)
+if_get_by_name(const char *name)
{
struct iface *i;
@@ -725,7 +725,7 @@ iface_patt_match(struct iface_patt *ifp, struct iface *i, struct ifa *a)
WALK_LIST(p, ifp->ipn_list)
{
- char *t = p->pattern;
+ const char *t = p->pattern;
int pos = p->positive;
if (t)
diff --git a/nest/iface.h b/nest/iface.h
index 0eb277cd..1189cdd4 100644
--- a/nest/iface.h
+++ b/nest/iface.h
@@ -115,15 +115,15 @@ void if_end_update(void);
void if_flush_ifaces(struct proto *p);
void if_feed_baby(struct proto *);
struct iface *if_find_by_index(unsigned);
-struct iface *if_find_by_name(char *);
-struct iface *if_get_by_name(char *);
+struct iface *if_find_by_name(const char *);
+struct iface *if_get_by_name(const char *);
void if_recalc_all_preferred_addresses(void);
/* The Neighbor Cache */
typedef struct neighbor {
- node n; /* Node in global neighbor list */
+ node n; /* Node in neighbor hash table chain */
node if_n; /* Node in per-interface neighbor list */
ip_addr addr; /* Address of the neighbor */
struct ifa *ifa; /* Ifa on related iface */
@@ -150,7 +150,8 @@ void neigh_prune(void);
void neigh_if_up(struct iface *);
void neigh_if_down(struct iface *);
void neigh_if_link(struct iface *);
-void neigh_ifa_update(struct ifa *);
+void neigh_ifa_up(struct ifa *a);
+void neigh_ifa_down(struct ifa *a);
void neigh_init(struct pool *);
/*
@@ -160,7 +161,7 @@ void neigh_init(struct pool *);
struct iface_patt_node {
node n;
int positive;
- byte *pattern;
+ const byte *pattern;
net_addr prefix;
};
diff --git a/nest/neighbor.c b/nest/neighbor.c
index 00a8e8a5..1a31fb79 100644
--- a/nest/neighbor.c
+++ b/nest/neighbor.c
@@ -66,10 +66,32 @@ neigh_hash(struct proto *p, ip_addr a, struct iface *i)
return (p->hash_key ^ ipa_hash(a) ^ ptr_hash(i)) >> NEIGH_HASH_OFFSET;
}
+static inline int
+ifa_better(struct ifa *a, struct ifa *b)
+{
+ return a && (!b || (a->prefix.pxlen > b->prefix.pxlen));
+}
+
+static inline int
+scope_better(int sa, int sb)
+{
+ /* Order per preference: -1 unknown, 0 for remote, 1 for local */
+ sa = (sa < 0) ? sa : !sa;
+ sb = (sb < 0) ? sb : !sb;
+
+ return sa > sb;
+}
+
+static inline int
+scope_remote(int sa, int sb)
+{
+ return (sa > SCOPE_HOST) && (sb > SCOPE_HOST);
+}
+
static int
if_connected(ip_addr a, struct iface *i, struct ifa **ap, uint flags)
{
- struct ifa *b;
+ struct ifa *b, *addr = NULL;
/* Handle iface pseudo-neighbors */
if (flags & NEF_IFACE)
@@ -89,12 +111,12 @@ if_connected(ip_addr a, struct iface *i, struct ifa **ap, uint flags)
{
if (b->flags & IA_PEER)
{
- if (ipa_equal(a, b->opposite))
- return *ap = b, b->scope;
+ if (ipa_equal(a, b->opposite) && ifa_better(b, addr))
+ addr = b;
}
else
{
- if (ipa_in_netX(a, &b->prefix))
+ if (ipa_in_netX(a, &b->prefix) && ifa_better(b, addr))
{
/* Do not allow IPv4 network and broadcast addresses */
if (ipa_is_ip4(a) &&
@@ -103,11 +125,15 @@ if_connected(ip_addr a, struct iface *i, struct ifa **ap, uint flags)
ipa_equal(a, b->brd))) /* Broadcast */
return *ap = NULL, -1;
- return *ap = b, b->scope;
+ addr = b;
}
}
}
+ /* Return found address */
+ if (addr)
+ return *ap = addr, addr->scope;
+
/* Handle ONLINK flag */
if (flags & NEF_ONLINK)
return *ap = NULL, ipa_classify(a) & IADDR_SCOPE_MASK;
@@ -125,10 +151,10 @@ if_connected_any(ip_addr a, struct iface *vrf, uint vrf_set, struct iface **ifac
*iface = NULL;
*addr = NULL;
- /* Get first match, but prefer SCOPE_HOST to other matches */
+ /* Prefer SCOPE_HOST or longer prefix */
WALK_LIST(i, iface_list)
if ((!vrf_set || vrf == i->master) && ((s = if_connected(a, i, &b, flags)) >= 0))
- if ((scope < 0) || ((scope > SCOPE_HOST) && (s == SCOPE_HOST)))
+ if (scope_better(s, scope) || (scope_remote(s, scope) && ifa_better(b, *addr)))
{
*iface = i;
*addr = b;
@@ -138,6 +164,33 @@ if_connected_any(ip_addr a, struct iface *vrf, uint vrf_set, struct iface **ifac
return scope;
}
+/* Is ifa @a subnet of any ifa on iface @ib ? */
+static inline int
+ifa_intersect(struct ifa *a, struct iface *ib)
+{
+ struct ifa *b;
+
+ WALK_LIST(b, ib->addrs)
+ if (net_in_netX(&a->prefix, &b->prefix))
+ return 1;
+
+ return 0;
+}
+
+/* Is any ifa of iface @ia subnet of any ifa on iface @ib ? */
+static inline int
+if_intersect(struct iface *ia, struct iface *ib)
+{
+ struct ifa *a, *b;
+
+ WALK_LIST(a, ia->addrs)
+ WALK_LIST(b, ib->addrs)
+ if (net_in_netX(&a->prefix, &b->prefix))
+ return 1;
+
+ return 0;
+}
+
/**
* neigh_find - find or create a neighbor entry
* @p: protocol which asks for the entry
@@ -200,9 +253,7 @@ neigh_find(struct proto *p, ip_addr a, struct iface *iface, uint flags)
if ((scope < 0) && !(flags & NEF_STICKY))
return NULL;
- n = sl_alloc(neigh_slab);
- memset(n, 0, sizeof(neighbor));
-
+ n = sl_allocz(neigh_slab);
add_tail(&neigh_hash_table[h], &n->n);
add_tail((scope >= 0) ? &iface->neighbors : &sticky_neigh_list, &n->if_n);
n->addr = a;
@@ -323,9 +374,20 @@ neigh_update(neighbor *n, struct iface *iface)
scope = if_connected(n->addr, iface, &ifa, n->flags);
- /* When neighbor is going down, try to respawn it on other ifaces */
- if ((scope < 0) && (n->scope >= 0) && !n->ifreq && (n->flags & NEF_STICKY))
- scope = if_connected_any(n->addr, p->vrf, p->vrf_set, &iface, &ifa, n->flags);
+ /* Update about already assigned iface, or some other iface */
+ if (iface == n->iface)
+ {
+ /* When neighbor is going down, try to respawn it on other ifaces */
+ if ((scope < 0) && (n->scope >= 0) && !n->ifreq && (n->flags & NEF_STICKY))
+ scope = if_connected_any(n->addr, p->vrf, p->vrf_set, &iface, &ifa, n->flags);
+ }
+ else
+ {
+ /* Continue only if the new variant is better than the existing one */
+ if (! (scope_better(scope, n->scope) ||
+ (scope_remote(scope, n->scope) && ifa_better(ifa, n->ifa))))
+ return;
+ }
/* No change or minor change - ignore or notify */
if ((scope == n->scope) && (iface == n->iface))
@@ -367,9 +429,16 @@ neigh_update(neighbor *n, struct iface *iface)
void
neigh_if_up(struct iface *i)
{
+ struct iface *ii;
neighbor *n;
node *x, *y;
+ /* Update neighbors that might be better off with the new iface */
+ WALK_LIST(ii, iface_list)
+ if (!EMPTY_LIST(ii->neighbors) && (ii != i) && if_intersect(i, ii))
+ WALK_LIST2_DELSAFE(n, x, y, ii->neighbors, if_n)
+ neigh_update(n, i);
+
WALK_LIST2_DELSAFE(n, x, y, sticky_neigh_list, if_n)
neigh_update(n, i);
}
@@ -420,21 +489,36 @@ neigh_if_link(struct iface *i)
* and causes all unreachable neighbors to be flushed.
*/
void
-neigh_ifa_update(struct ifa *a)
+neigh_ifa_up(struct ifa *a)
{
- struct iface *i = a->iface;
+ struct iface *i = a->iface, *ii;
neighbor *n;
node *x, *y;
- /* Update all neighbors whose scope has changed */
- WALK_LIST2_DELSAFE(n, x, y, i->neighbors, if_n)
- neigh_update(n, i);
+ /* Update neighbors that might be better off with the new ifa */
+ WALK_LIST(ii, iface_list)
+ if (!EMPTY_LIST(ii->neighbors) && ifa_intersect(a, ii))
+ WALK_LIST2_DELSAFE(n, x, y, ii->neighbors, if_n)
+ neigh_update(n, i);
/* Wake up all sticky neighbors that are reachable now */
WALK_LIST2_DELSAFE(n, x, y, sticky_neigh_list, if_n)
neigh_update(n, i);
}
+void
+neigh_ifa_down(struct ifa *a)
+{
+ struct iface *i = a->iface;
+ neighbor *n;
+ node *x, *y;
+
+ /* Update all neighbors whose scope has changed */
+ WALK_LIST2_DELSAFE(n, x, y, i->neighbors, if_n)
+ if (n->ifa == a)
+ neigh_update(n, i);
+}
+
static inline void
neigh_prune_one(neighbor *n)
{
diff --git a/nest/password.h b/nest/password.h
index c4017848..8a0da223 100644
--- a/nest/password.h
+++ b/nest/password.h
@@ -12,7 +12,7 @@
struct password_item {
node n;
- char *password; /* Key data, null terminated */
+ const char *password; /* Key data, null terminated */
uint length; /* Key length, without null */
uint id; /* Key ID */
uint alg; /* MAC algorithm */
diff --git a/nest/proto.c b/nest/proto.c
index 6beca56d..1c27e638 100644
--- a/nest/proto.c
+++ b/nest/proto.c
@@ -20,6 +20,7 @@
#include "nest/iface.h"
#include "nest/cli.h"
#include "filter/filter.h"
+#include "filter/f-inst.h"
pool *proto_pool;
list proto_list;
@@ -27,7 +28,8 @@ list proto_list;
static list protocol_list;
struct protocol *class_to_protocol[PROTOCOL__MAX];
-#define PD(pr, msg, args...) do { if (pr->debug & D_STATES) { log(L_TRACE "%s: " msg, pr->name , ## args); } } while(0)
+#define CD(c, msg, args...) ({ if (c->debug & D_STATES) log(L_TRACE "%s.%s: " msg, c->proto->name, c->name ?: "?", ## args); })
+#define PD(p, msg, args...) ({ if (p->debug & D_STATES) log(L_TRACE "%s: " msg, p->name, ## args); })
static timer *proto_shutdown_timer;
static timer *gr_wait_timer;
@@ -42,9 +44,11 @@ static u32 graceful_restart_locks;
static char *p_states[] = { "DOWN", "START", "UP", "STOP" };
static char *c_states[] = { "DOWN", "START", "UP", "FLUSHING" };
+static char *e_states[] = { "DOWN", "FEEDING", "READY" };
extern struct protocol proto_unix_iface;
+static void channel_request_reload(struct channel *c);
static void proto_shutdown_loop(timer *);
static void proto_rethink_goal(struct proto *p);
static char *proto_state_name(struct proto *p);
@@ -58,6 +62,18 @@ static inline int proto_is_done(struct proto *p)
static inline int channel_is_active(struct channel *c)
{ return (c->channel_state == CS_START) || (c->channel_state == CS_UP); }
+static inline int channel_reloadable(struct channel *c)
+{ return c->proto->reload_routes && c->reloadable; }
+
+static inline void
+channel_log_state_change(struct channel *c)
+{
+ if (c->export_state)
+ CD(c, "State changed to %s/%s", c_states[c->channel_state], e_states[c->export_state]);
+ else
+ CD(c, "State changed to %s", c_states[c->channel_state]);
+}
+
static void
proto_log_state_change(struct proto *p)
{
@@ -159,30 +175,33 @@ proto_add_channel(struct proto *p, struct channel_config *cf)
c->net_type = cf->net_type;
c->ra_mode = cf->ra_mode;
c->preference = cf->preference;
+ c->debug = cf->debug;
c->merge_limit = cf->merge_limit;
c->in_keep_filtered = cf->in_keep_filtered;
+ c->rpki_reload = cf->rpki_reload;
c->channel_state = CS_DOWN;
c->export_state = ES_DOWN;
c->last_state_change = current_time();
- c->last_tx_filter_change = current_time();
c->reloadable = 1;
+ init_list(&c->roa_subscriptions);
+
CALL(c->channel->init, c, cf);
add_tail(&p->channels, &c->n);
- PD(p, "Channel %s connected to table %s", c->name, c->table->name);
+ CD(c, "Connected to table %s", c->table->name);
return c;
}
void
-proto_remove_channel(struct proto *p, struct channel *c)
+proto_remove_channel(struct proto *p UNUSED, struct channel *c)
{
ASSERT(c->channel_state == CS_DOWN);
- PD(p, "Channel %s removed", c->name);
+ CD(c, "Removed", c->name);
rem_node(&c->n);
mb_free(c);
@@ -233,7 +252,7 @@ channel_schedule_feed(struct channel *c, int initial)
c->export_state = ES_FEEDING;
c->refeeding = !initial;
- ev_schedule(c->feed_event);
+ ev_schedule_work(c->feed_event);
}
static void
@@ -244,27 +263,188 @@ channel_feed_loop(void *ptr)
if (c->export_state != ES_FEEDING)
return;
+ /* Start feeding */
if (!c->feed_active)
+ {
if (c->proto->feed_begin)
c->proto->feed_begin(c, !c->refeeding);
+ c->refeed_pending = 0;
+ }
+
// DBG("Feeding protocol %s continued\n", p->name);
if (!rt_feed_channel(c))
{
- ev_schedule(c->feed_event);
+ ev_schedule_work(c->feed_event);
+ return;
+ }
+
+ /* Reset export limit if the feed ended with acceptable number of exported routes */
+ struct channel_limit *l = &c->out_limit;
+ if (c->refeeding &&
+ (l->state == PLS_BLOCKED) &&
+ (c->refeed_count <= l->limit) &&
+ (c->stats.exp_routes <= l->limit))
+ {
+ log(L_INFO "Protocol %s resets route export limit (%u)", c->proto->name, l->limit);
+ channel_reset_limit(&c->out_limit);
+
+ /* Continue in feed - it will process routing table again from beginning */
+ c->refeed_count = 0;
+ ev_schedule_work(c->feed_event);
return;
}
// DBG("Feeding protocol %s finished\n", p->name);
c->export_state = ES_READY;
- // proto_log_state_change(p);
+ channel_log_state_change(c);
if (c->proto->feed_end)
c->proto->feed_end(c);
+
+ /* Restart feeding */
+ if (c->refeed_pending)
+ channel_request_feeding(c);
+}
+
+
+static void
+channel_roa_in_changed(struct rt_subscription *s)
+{
+ struct channel *c = s->data;
+ int active = c->reload_event && ev_active(c->reload_event);
+
+ CD(c, "Reload triggered by RPKI change%s", active ? " - already active" : "");
+
+ if (!active)
+ channel_request_reload(c);
+ else
+ c->reload_pending = 1;
+}
+
+static void
+channel_roa_out_changed(struct rt_subscription *s)
+{
+ struct channel *c = s->data;
+ int active = (c->export_state == ES_FEEDING);
+
+ CD(c, "Feeding triggered by RPKI change%s", active ? " - already active" : "");
+
+ if (!active)
+ channel_request_feeding(c);
+ else
+ c->refeed_pending = 1;
+}
+
+/* Temporary code, subscriptions should be changed to resources */
+struct roa_subscription {
+ struct rt_subscription s;
+ node roa_node;
+};
+
+static int
+channel_roa_is_subscribed(struct channel *c, rtable *tab, int dir)
+{
+ void (*hook)(struct rt_subscription *) =
+ dir ? channel_roa_in_changed : channel_roa_out_changed;
+
+ struct roa_subscription *s;
+ node *n;
+
+ WALK_LIST2(s, n, c->roa_subscriptions, roa_node)
+ if ((s->s.tab == tab) && (s->s.hook == hook))
+ return 1;
+
+ return 0;
}
static void
+channel_roa_subscribe(struct channel *c, rtable *tab, int dir)
+{
+ if (channel_roa_is_subscribed(c, tab, dir))
+ return;
+
+ struct roa_subscription *s = mb_allocz(c->proto->pool, sizeof(struct roa_subscription));
+
+ s->s.hook = dir ? channel_roa_in_changed : channel_roa_out_changed;
+ s->s.data = c;
+ rt_subscribe(tab, &s->s);
+
+ add_tail(&c->roa_subscriptions, &s->roa_node);
+}
+
+static void
+channel_roa_unsubscribe(struct roa_subscription *s)
+{
+ rt_unsubscribe(&s->s);
+ rem_node(&s->roa_node);
+ mb_free(s);
+}
+
+static void
+channel_roa_subscribe_filter(struct channel *c, int dir)
+{
+ const struct filter *f = dir ? c->in_filter : c->out_filter;
+ struct rtable *tab;
+ int valid = 1, found = 0;
+
+ if ((f == FILTER_ACCEPT) || (f == FILTER_REJECT))
+ return;
+
+ /* No automatic reload for non-reloadable channels */
+ if (dir && !channel_reloadable(c))
+ valid = 0;
+
+#ifdef CONFIG_BGP
+ /* No automatic reload for BGP channels without in_table / out_table */
+ if (c->channel == &channel_bgp)
+ valid = dir ? !!c->in_table : !!c->out_table;
+#endif
+
+ struct filter_iterator fit;
+ FILTER_ITERATE_INIT(&fit, f, c->proto->pool);
+
+ FILTER_ITERATE(&fit, fi)
+ {
+ switch (fi->fi_code)
+ {
+ case FI_ROA_CHECK_IMPLICIT:
+ tab = fi->i_FI_ROA_CHECK_IMPLICIT.rtc->table;
+ if (valid) channel_roa_subscribe(c, tab, dir);
+ found = 1;
+ break;
+
+ case FI_ROA_CHECK_EXPLICIT:
+ tab = fi->i_FI_ROA_CHECK_EXPLICIT.rtc->table;
+ if (valid) channel_roa_subscribe(c, tab, dir);
+ found = 1;
+ break;
+
+ default:
+ break;
+ }
+ }
+ FILTER_ITERATE_END;
+
+ FILTER_ITERATE_CLEANUP(&fit);
+
+ if (!valid && found)
+ log(L_WARN "%s.%s: Automatic RPKI reload not active for %s",
+ c->proto->name, c->name ?: "?", dir ? "import" : "export");
+}
+
+static void
+channel_roa_unsubscribe_all(struct channel *c)
+{
+ struct roa_subscription *s;
+ node *n, *x;
+
+ WALK_LIST2_DELSAFE(s, n, x, c->roa_subscriptions, roa_node)
+ channel_roa_unsubscribe(s);
+}
+
+static void
channel_start_export(struct channel *c)
{
ASSERT(c->channel_state == CS_UP);
@@ -282,6 +462,7 @@ channel_stop_export(struct channel *c)
c->export_state = ES_DOWN;
c->stats.exp_routes = 0;
+ bmap_reset(&c->export_map, 1024);
}
@@ -292,7 +473,7 @@ channel_schedule_reload(struct channel *c)
ASSERT(c->channel_state == CS_UP);
rt_reload_channel_abort(c);
- ev_schedule(c->reload_event);
+ ev_schedule_work(c->reload_event);
}
static void
@@ -300,11 +481,19 @@ channel_reload_loop(void *ptr)
{
struct channel *c = ptr;
+ /* Start reload */
+ if (!c->reload_active)
+ c->reload_pending = 0;
+
if (!rt_reload_channel(c))
{
- ev_schedule(c->reload_event);
+ ev_schedule_work(c->reload_event);
return;
}
+
+ /* Restart reload */
+ if (c->reload_pending)
+ channel_request_reload(c);
}
static void
@@ -360,6 +549,9 @@ channel_do_start(struct channel *c)
c->feed_event = ev_new_init(c->proto->pool, channel_feed_loop, c);
+ bmap_init(&c->export_map, c->proto->pool, 1024);
+ memset(&c->stats, 0, sizeof(struct proto_stats));
+
channel_reset_limit(&c->rx_limit);
channel_reset_limit(&c->in_limit);
channel_reset_limit(&c->out_limit);
@@ -368,6 +560,17 @@ channel_do_start(struct channel *c)
}
static void
+channel_do_up(struct channel *c)
+{
+ /* Register RPKI/ROA subscriptions */
+ if (c->rpki_reload)
+ {
+ channel_roa_subscribe_filter(c, 1);
+ channel_roa_subscribe_filter(c, 0);
+ }
+}
+
+static void
channel_do_flush(struct channel *c)
{
rt_schedule_prune(c->table);
@@ -377,6 +580,14 @@ channel_do_flush(struct channel *c)
channel_graceful_restart_unlock(c);
CALL(c->channel->shutdown, c);
+
+ /* This have to be done in here, as channel pool is freed before channel_do_down() */
+ bmap_free(&c->export_map);
+ c->in_table = NULL;
+ c->reload_event = NULL;
+ c->out_table = NULL;
+
+ channel_roa_unsubscribe_all(c);
}
static void
@@ -391,6 +602,7 @@ channel_do_down(struct channel *c)
if ((c->stats.imp_routes + c->stats.filt_routes) != 0)
log(L_ERR "%s: Channel %s is down but still has some routes", c->proto->name, c->name);
+ // bmap_free(&c->export_map);
memset(&c->stats, 0, sizeof(struct proto_stats));
c->in_table = NULL;
@@ -445,6 +657,7 @@ channel_set_state(struct channel *c, uint state)
if (!c->gr_wait && c->proto->rt_notify)
channel_start_export(c);
+ channel_do_up(c);
break;
case CS_FLUSHING:
@@ -471,7 +684,8 @@ channel_set_state(struct channel *c, uint state)
default:
ASSERT(0);
}
- // XXXX proto_log_state_change(c);
+
+ channel_log_state_change(c);
}
/**
@@ -489,6 +703,8 @@ channel_request_feeding(struct channel *c)
{
ASSERT(c->channel_state == CS_UP);
+ CD(c, "Feeding requested");
+
/* Do nothing if we are still waiting for feeding */
if (c->export_state == ES_DOWN)
return;
@@ -503,19 +719,11 @@ channel_request_feeding(struct channel *c)
rt_feed_channel_abort(c);
}
- channel_reset_limit(&c->out_limit);
-
- /* Hack: reset exp_routes during refeed, and do not decrease it later */
- c->stats.exp_routes = 0;
+ /* Track number of exported routes during refeed */
+ c->refeed_count = 0;
channel_schedule_feed(c, 0); /* Sets ES_FEEDING */
- // proto_log_state_change(c);
-}
-
-static inline int
-channel_reloadable(struct channel *c)
-{
- return c->proto->reload_routes && c->reloadable;
+ channel_log_state_change(c);
}
static void
@@ -524,6 +732,8 @@ channel_request_reload(struct channel *c)
ASSERT(c->channel_state == CS_UP);
ASSERT(channel_reloadable(c));
+ CD(c, "Reload requested");
+
c->proto->reload_routes(c);
/*
@@ -569,6 +779,8 @@ channel_config_new(const struct channel_class *cc, const char *name, uint net_ty
cf->net_type = net_type;
cf->ra_mode = RA_OPTIMAL;
cf->preference = proto->protocol->preference;
+ cf->debug = new_config->channel_default_debug;
+ cf->rpki_reload = 1;
add_tail(&proto->channels, &cf->n);
@@ -601,6 +813,7 @@ channel_copy_config(struct channel_config *src, struct proto_config *proto)
struct channel_config *dst = cfg_alloc(src->channel->config_size);
memcpy(dst, src, src->channel->config_size);
+ memset(&dst->n, 0, sizeof(node));
add_tail(&proto->channels, &dst->n);
CALL(src->channel->copy_config, dst, src);
@@ -620,6 +833,7 @@ channel_reconfigure(struct channel *c, struct channel_config *cf)
/* Note that filter_same() requires arguments in (new, old) order */
int import_changed = !filter_same(cf->in_filter, c->in_filter);
int export_changed = !filter_same(cf->out_filter, c->out_filter);
+ int rpki_reload_changed = (cf->rpki_reload != c->rpki_reload);
if (c->preference != cf->preference)
import_changed = 1;
@@ -637,20 +851,31 @@ channel_reconfigure(struct channel *c, struct channel_config *cf)
// c->ra_mode = cf->ra_mode;
c->merge_limit = cf->merge_limit;
c->preference = cf->preference;
+ c->debug = cf->debug;
c->in_keep_filtered = cf->in_keep_filtered;
+ c->rpki_reload = cf->rpki_reload;
channel_verify_limits(c);
- if (export_changed)
- c->last_tx_filter_change = current_time();
-
/* Execute channel-specific reconfigure hook */
if (c->channel->reconfigure && !c->channel->reconfigure(c, cf, &import_changed, &export_changed))
return 0;
/* If the channel is not open, it has no routes and we cannot reload it anyways */
if (c->channel_state != CS_UP)
- return 1;
+ goto done;
+
+ /* Update RPKI/ROA subscriptions */
+ if (import_changed || export_changed || rpki_reload_changed)
+ {
+ channel_roa_unsubscribe_all(c);
+
+ if (c->rpki_reload)
+ {
+ channel_roa_subscribe_filter(c, 1);
+ channel_roa_subscribe_filter(c, 0);
+ }
+ }
if (reconfigure_type == RECONFIG_SOFT)
{
@@ -660,7 +885,7 @@ channel_reconfigure(struct channel *c, struct channel_config *cf)
if (export_changed)
log(L_INFO "Channel %s.%s changed export", c->proto->name, c->name);
- return 1;
+ goto done;
}
/* Route reload may be not supported */
@@ -676,6 +901,8 @@ channel_reconfigure(struct channel *c, struct channel_config *cf)
if (export_changed)
channel_request_feeding(c);
+done:
+ CD(c, "Reconfigured");
return 1;
}
@@ -868,7 +1095,7 @@ proto_copy_config(struct proto_config *dest, struct proto_config *src)
struct channel_config *cc;
node old_node;
int old_class;
- char *old_name;
+ const char *old_name;
if (dest->protocol != src->protocol)
cf_error("Can't copy configuration from a different protocol type");
@@ -1837,6 +2064,16 @@ channel_show_info(struct channel *c)
}
void
+channel_cmd_debug(struct channel *c, uint mask)
+{
+ if (cli_access_restricted())
+ return;
+
+ c->debug = mask;
+ cli_msg(0, "");
+}
+
+void
proto_cmd_show(struct proto *p, uintptr_t verbose, int cnt)
{
byte buf[256], tbuf[TM_DATETIME_BUFFER_SIZE];
@@ -1975,10 +2212,17 @@ proto_cmd_reload(struct proto *p, uintptr_t dir, int cnt UNUSED)
cli_msg(-15, "%s: reloading", p->name);
}
+extern void pipe_update_debug(struct proto *P);
+
void
proto_cmd_debug(struct proto *p, uintptr_t mask, int cnt UNUSED)
{
p->debug = mask;
+
+#ifdef CONFIG_PIPE
+ if (p->proto == &proto_pipe)
+ pipe_update_debug(p);
+#endif
}
void
@@ -1988,7 +2232,7 @@ proto_cmd_mrtdump(struct proto *p, uintptr_t mask, int cnt UNUSED)
}
static void
-proto_apply_cmd_symbol(struct symbol *s, void (* cmd)(struct proto *, uintptr_t, int), uintptr_t arg)
+proto_apply_cmd_symbol(const struct symbol *s, void (* cmd)(struct proto *, uintptr_t, int), uintptr_t arg)
{
if (s->class != SYM_PROTO)
{
@@ -2001,7 +2245,7 @@ proto_apply_cmd_symbol(struct symbol *s, void (* cmd)(struct proto *, uintptr_t,
}
static void
-proto_apply_cmd_patt(char *patt, void (* cmd)(struct proto *, uintptr_t, int), uintptr_t arg)
+proto_apply_cmd_patt(const char *patt, void (* cmd)(struct proto *, uintptr_t, int), uintptr_t arg)
{
struct proto *p;
int cnt = 0;
@@ -2059,3 +2303,47 @@ proto_get_named(struct symbol *sym, struct protocol *pr)
return p;
}
+
+struct proto *
+proto_iterate_named(struct symbol *sym, struct protocol *proto, struct proto *old)
+{
+ if (sym)
+ {
+ /* Just the first pass */
+ if (old)
+ {
+ cli_msg(0, "");
+ return NULL;
+ }
+
+ if (sym->class != SYM_PROTO)
+ cf_error("%s: Not a protocol", sym->name);
+
+ struct proto *p = sym->proto->proto;
+ if (!p || (p->proto != proto))
+ cf_error("%s: Not a %s protocol", sym->name, proto->name);
+
+ return p;
+ }
+ else
+ {
+ for (struct proto *p = !old ? HEAD(proto_list) : NODE_NEXT(old);
+ NODE_VALID(p);
+ p = NODE_NEXT(p))
+ {
+ if ((p->proto == proto) && (p->proto_state != PS_DOWN))
+ {
+ cli_separator(this_cli);
+ return p;
+ }
+ }
+
+ /* Not found anything during first pass */
+ if (!old)
+ cf_error("There is no %s protocol running", proto->name);
+
+ /* No more items */
+ cli_msg(0, "");
+ return NULL;
+ }
+}
diff --git a/nest/protocol.h b/nest/protocol.h
index c664c1e6..48eb01d2 100644
--- a/nest/protocol.h
+++ b/nest/protocol.h
@@ -80,7 +80,7 @@ struct protocol {
void (*cleanup)(struct proto *); /* Called after shutdown when protocol became hungry/down */
void (*get_status)(struct proto *, byte *buf); /* Get instance status (for `show protocols' command) */
void (*get_route_info)(struct rte *, byte *buf); /* Get route information (for `show route' command) */
- int (*get_attr)(struct eattr *, byte *buf, int buflen); /* ASCIIfy dynamic attribute (returns GA_*) */
+ int (*get_attr)(const struct eattr *, byte *buf, int buflen); /* ASCIIfy dynamic attribute (returns GA_*) */
void (*show_proto_info)(struct proto *); /* Show protocol info (for `show protocols all' command) */
void (*copy_config)(struct proto_config *, struct proto_config *); /* Copy config from given protocol instance */
};
@@ -115,8 +115,8 @@ struct proto_config {
struct protocol *protocol; /* Protocol */
struct proto *proto; /* Instance we've created */
struct proto_config *parent; /* Parent proto_config for dynamic protocols */
- char *name;
- char *dsc;
+ const char *name;
+ const char *dsc;
int class; /* SYM_PROTO or SYM_TEMPLATE */
u8 net_type; /* Protocol network type (NET_*), 0 for undefined */
u8 disabled; /* Protocol enabled/disabled by default */
@@ -171,7 +171,7 @@ struct proto {
struct rte_src *main_source; /* Primary route source */
struct iface *vrf; /* Related VRF instance, NULL if global */
- char *name; /* Name of this instance (== cf->name) */
+ const char *name; /* Name of this instance (== cf->name) */
u32 debug; /* Debugging flags */
u32 mrtdump; /* MRTDump flags */
uint active_channels; /* Number of active channels */
@@ -245,7 +245,7 @@ struct proto {
};
struct proto_spec {
- void *ptr;
+ const void *ptr;
int patt;
};
@@ -281,6 +281,7 @@ void channel_graceful_restart_unlock(struct channel *c);
void channel_show_limit(struct channel_limit *l, const char *dsc);
void channel_show_info(struct channel *c);
+void channel_cmd_debug(struct channel *c, uint mask);
void proto_cmd_show(struct proto *, uintptr_t, int);
void proto_cmd_disable(struct proto *, uintptr_t, int);
@@ -292,6 +293,10 @@ void proto_cmd_mrtdump(struct proto *, uintptr_t, int);
void proto_apply_cmd(struct proto_spec ps, void (* cmd)(struct proto *, uintptr_t, int), int restricted, uintptr_t arg);
struct proto *proto_get_named(struct symbol *, struct protocol *);
+struct proto *proto_iterate_named(struct symbol *sym, struct protocol *proto, struct proto *old);
+
+#define PROTO_WALK_CMD(sym,pr,p) for(struct proto *p = NULL; p = proto_iterate_named(sym, pr, p); )
+
#define CMD_RELOAD 0
#define CMD_RELOAD_IN 1
@@ -492,8 +497,10 @@ struct channel_config {
u8 net_type; /* Routing table network type (NET_*), 0 for undefined */
u8 ra_mode; /* Mode of received route advertisements (RA_*) */
u16 preference; /* Default route preference */
+ u32 debug; /* Debugging flags (D_*) */
u8 merge_limit; /* Maximal number of nexthops for RA_MERGED */
u8 in_keep_filtered; /* Routes rejected in import filter are kept */
+ u8 rpki_reload; /* RPKI changes trigger channel reload */
};
struct channel {
@@ -507,6 +514,7 @@ struct channel {
struct rtable *table;
const struct filter *in_filter; /* Input filter */
const struct filter *out_filter; /* Output filter */
+ struct bmap export_map; /* Keeps track which routes passed export filter */
struct channel_limit rx_limit; /* Receive limit (for in_keep_filtered) */
struct channel_limit in_limit; /* Input limit */
struct channel_limit out_limit; /* Output limit */
@@ -514,10 +522,12 @@ struct channel {
struct event *feed_event; /* Event responsible for feeding */
struct fib_iterator feed_fit; /* Routing table iterator used during feeding */
struct proto_stats stats; /* Per-channel protocol statistics */
+ u32 refeed_count; /* Number of routes exported during refeed regardless of out_limit */
u8 net_type; /* Routing table network type (NET_*), 0 for undefined */
u8 ra_mode; /* Mode of received route advertisements (RA_*) */
u16 preference; /* Default route preference */
+ u32 debug; /* Debugging flags (D_*) */
u8 merge_limit; /* Maximal number of nexthops for RA_MERGED */
u8 in_keep_filtered; /* Routes rejected in import filter are kept */
u8 disabled;
@@ -533,7 +543,6 @@ struct channel {
u8 gr_wait; /* Route export to channel is postponed until graceful restart */
btime last_state_change; /* Time of last state transition */
- btime last_tx_filter_change;
struct rtable *in_table; /* Internal table for received routes */
struct event *reload_event; /* Event responsible for reloading from in_table */
@@ -541,7 +550,13 @@ struct channel {
struct rte *reload_next_rte; /* Route iterator in in_table used during reloading */
u8 reload_active; /* Iterator reload_fit is linked */
+ u8 reload_pending; /* Reloading and another reload is scheduled */
+ u8 refeed_pending; /* Refeeding and another refeed is scheduled */
+ u8 rpki_reload; /* RPKI changes trigger channel reload */
+
struct rtable *out_table; /* Internal table for exported routes */
+
+ list roa_subscriptions; /* List of active ROA table subscriptions based on filters roa_check() */
};
diff --git a/nest/route.h b/nest/route.h
index cd4b75db..53cdcee8 100644
--- a/nest/route.h
+++ b/nest/route.h
@@ -10,6 +10,7 @@
#define _BIRD_ROUTE_H_
#include "lib/lists.h"
+#include "lib/bitmap.h"
#include "lib/resource.h"
#include "lib/net.h"
@@ -18,6 +19,7 @@ struct protocol;
struct proto;
struct rte_src;
struct symbol;
+struct timer;
struct filter;
struct cli;
@@ -36,7 +38,6 @@ struct cli;
struct fib_node {
struct fib_node *next; /* Next in hash chain */
struct fib_iterator *readers; /* List of readers of this node */
- byte flags; /* User-defined, will be removed */
net_addr addr[0];
};
@@ -84,6 +85,8 @@ void fit_init(struct fib_iterator *, struct fib *); /* Internal functions, don't
struct fib_node *fit_get(struct fib *, struct fib_iterator *);
void fit_put(struct fib_iterator *, struct fib_node *);
void fit_put_next(struct fib *f, struct fib_iterator *i, struct fib_node *n, uint hpos);
+void fit_put_end(struct fib_iterator *i);
+void fit_copy(struct fib *f, struct fib_iterator *dst, struct fib_iterator *src);
#define FIB_WALK(fib, type, z) do { \
@@ -118,8 +121,12 @@ void fit_put_next(struct fib *f, struct fib_iterator *i, struct fib_node *n, uin
#define FIB_ITERATE_PUT_NEXT(it, fib) fit_put_next(fib, it, fn_, hpos_)
+#define FIB_ITERATE_PUT_END(it) fit_put_end(it)
+
#define FIB_ITERATE_UNLINK(it, fib) fit_get(fib, it)
+#define FIB_ITERATE_COPY(dst, src, fib) fit_copy(fib, dst, src)
+
/*
* Master Routing Tables. Generally speaking, each of them contains a FIB
@@ -141,6 +148,8 @@ struct rtable_config {
int gc_max_ops; /* Maximum number of operations before GC is run */
int gc_min_time; /* Minimum time between two consecutive GC runs */
byte sorted; /* Routes of network are sorted according to rte_better() */
+ btime min_settle_time; /* Minimum settle time for notifications */
+ btime max_settle_time; /* Maximum settle time for notifications */
};
typedef struct rtable {
@@ -152,6 +161,7 @@ typedef struct rtable {
int pipe_busy; /* Pipe loop detection */
int use_count; /* Number of protocols using this table */
u32 rt_count; /* Number of routes in the table */
+ struct hmap id_map;
struct hostcache *hostcache;
struct rtable_config *config; /* Configuration of this table */
struct config *deleted; /* Table doesn't exist in current configuration,
@@ -159,6 +169,8 @@ typedef struct rtable {
* obstacle from this routing table.
*/
struct event *rt_event; /* Routing table event */
+ btime last_rt_change; /* Last time when route changed */
+ btime base_settle_time; /* Start time of rtable settling interval */
btime gc_time; /* Time of last GC */
int gc_counter; /* Number of operations since last GC */
byte prune_state; /* Table prune state, 1 -> scheduled, 2-> running */
@@ -166,8 +178,18 @@ typedef struct rtable {
byte nhu_state; /* Next Hop Update state */
struct fib_iterator prune_fit; /* Rtable prune FIB iterator */
struct fib_iterator nhu_fit; /* Next Hop Update FIB iterator */
+
+ list subscribers; /* Subscribers for notifications */
+ struct timer *settle_timer; /* Settle time for notifications */
} rtable;
+struct rt_subscription {
+ node n;
+ rtable *tab;
+ void (*hook)(struct rt_subscription *b);
+ void *data;
+};
+
#define NHU_CLEAN 0
#define NHU_SCHEDULED 1
#define NHU_RUNNING 2
@@ -210,6 +232,7 @@ typedef struct rte {
net *net; /* Network this RTE belongs to */
struct channel *sender; /* Channel used to send the route to the routing table */
struct rta *attrs; /* Attributes of this route */
+ u32 id; /* Table specific route id */
byte flags; /* Flags (REF_...) */
byte pflags; /* Protocol-specific flags */
word pref; /* Route preference */
@@ -286,6 +309,8 @@ void rt_preconfig(struct config *);
void rt_commit(struct config *new, struct config *old);
void rt_lock_table(rtable *);
void rt_unlock_table(rtable *);
+void rt_subscribe(rtable *tab, struct rt_subscription *s);
+void rt_unsubscribe(struct rt_subscription *s);
void rt_setup(pool *, rtable *, struct rtable_config *);
static inline net *net_find(rtable *tab, const net_addr *addr) { return (net *) fib_find(&tab->fib, addr); }
static inline net *net_find_valid(rtable *tab, const net_addr *addr)
@@ -345,6 +370,7 @@ struct rt_show_data {
struct proto *export_protocol;
struct channel *export_channel;
struct config *running_on_config;
+ struct krt_proto *kernel;
int export_mode, primary_only, filtered, stats, show_for;
int table_open; /* Iteration (fit) is open */
@@ -369,6 +395,7 @@ struct rt_show_data_rtable * rt_show_add_table(struct rt_show_data *d, rtable *t
#define RSEM_PREEXPORT 1 /* Routes ready for export, before filtering */
#define RSEM_EXPORT 2 /* Routes accepted by export filter */
#define RSEM_NOEXPORT 3 /* Routes rejected by export filter */
+#define RSEM_EXPORTED 4 /* Routes marked in export map */
/*
* Route Attributes
@@ -448,17 +475,13 @@ typedef struct rta {
#define RTD_PROHIBIT 4 /* Administratively prohibited */
#define RTD_MAX 5
- /* Flags for net->n.flags, used by kernel syncer */
-#define KRF_INSTALLED 0x80 /* This route should be installed in the kernel */
-#define KRF_SYNC_ERROR 0x40 /* Error during kernel table synchronization */
-
#define RTAF_CACHED 1 /* This is a cached rta */
#define IGP_METRIC_UNKNOWN 0x80000000 /* Default igp_metric used when no other
protocol-specific metric is availabe */
-const char * rta_dest_names[RTD_MAX];
+extern const char * rta_dest_names[RTD_MAX];
static inline const char *rta_dest_name(uint n)
{ return (n < RTD_MAX) ? rta_dest_names[n] : "???"; }
@@ -571,7 +594,7 @@ void ea_merge(ea_list *from, ea_list *to); /* Merge sub-lists to allocated buffe
int ea_same(ea_list *x, ea_list *y); /* Test whether two ea_lists are identical */
uint ea_hash(ea_list *e); /* Calculate 16-bit hash value */
ea_list *ea_append(ea_list *to, ea_list *what);
-void ea_format_bitfield(struct eattr *a, byte *buf, int bufsize, const char **names, int min, int max);
+void ea_format_bitfield(const struct eattr *a, byte *buf, int bufsize, const char **names, int min, int max);
#define ea_normalize(ea) do { \
if (ea->next) { \
diff --git a/nest/rt-attr.c b/nest/rt-attr.c
index 8620d321..25e39488 100644
--- a/nest/rt-attr.c
+++ b/nest/rt-attr.c
@@ -135,7 +135,7 @@ rt_get_source(struct proto *p, u32 id)
if (src)
return src;
- src = sl_alloc(rte_src_slab);
+ src = sl_allocz(rte_src_slab);
src->proto = p;
src->private_id = id;
src->global_id = idm_alloc(&src_ids);
@@ -202,7 +202,7 @@ nexthop__same(struct nexthop *x, struct nexthop *y)
}
static int
-nexthop_compare_node(const struct nexthop *x, const struct nexthop *y)
+nexthop_compare_node(const struct nexthop *x, const struct nexthop *y)
{
int r;
@@ -278,18 +278,22 @@ nexthop_merge(struct nexthop *x, struct nexthop *y, int rx, int ry, int max, lin
while ((x || y) && max--)
{
int cmp = nexthop_compare_node(x, y);
+
if (cmp < 0)
{
+ ASSUME(x);
*n = rx ? x : nexthop_copy_node(x, lp);
x = x->next;
}
else if (cmp > 0)
{
+ ASSUME(y);
*n = ry ? y : nexthop_copy_node(y, lp);
y = y->next;
}
else
{
+ ASSUME(x && y);
*n = rx ? x : (ry ? y : nexthop_copy_node(x, lp));
x = x->next;
y = y->next;
@@ -362,7 +366,7 @@ nexthop_copy(struct nexthop *o)
for (; o; o = o->next)
{
- struct nexthop *n = sl_alloc(nexthop_slab(o));
+ struct nexthop *n = sl_allocz(nexthop_slab(o));
n->gw = o->gw;
n->iface = o->iface;
n->next = NULL;
@@ -786,7 +790,7 @@ ea_free(ea_list *o)
}
static int
-get_generic_attr(eattr *a, byte **buf, int buflen UNUSED)
+get_generic_attr(const eattr *a, byte **buf, int buflen UNUSED)
{
if (a->id == EA_GEN_IGP_METRIC)
{
@@ -798,7 +802,7 @@ get_generic_attr(eattr *a, byte **buf, int buflen UNUSED)
}
void
-ea_format_bitfield(struct eattr *a, byte *buf, int bufsize, const char **names, int min, int max)
+ea_format_bitfield(const struct eattr *a, byte *buf, int bufsize, const char **names, int min, int max)
{
byte *bound = buf + bufsize - 32;
u32 data = a->u.data;
@@ -894,7 +898,7 @@ ea_show_lc_set(struct cli *c, const struct adata *ad, byte *pos, byte *buf, byte
* get_attr() hook, it's consulted first.
*/
void
-ea_show(struct cli *c, eattr *e)
+ea_show(struct cli *c, const eattr *e)
{
struct protocol *p;
int status = GA_UNKNOWN;
diff --git a/nest/rt-fib.c b/nest/rt-fib.c
index a8800b65..a7f70371 100644
--- a/nest/rt-fib.c
+++ b/nest/rt-fib.c
@@ -327,7 +327,6 @@ fib_get(struct fib *f, const net_addr *a)
struct fib_node *e = fib_user_to_node(f, b);
e->readers = NULL;
- e->flags = 0;
fib_insert(f, a, e);
memset(b, 0, f->node_offset);
@@ -585,6 +584,40 @@ found:
fit_put(i, n);
}
+void
+fit_put_end(struct fib_iterator *i)
+{
+ i->prev = i->next = NULL;
+ i->node = NULL;
+ i->hash = ~0 - 1;
+}
+
+void
+fit_copy(struct fib *f, struct fib_iterator *dst, struct fib_iterator *src)
+{
+ struct fib_iterator *nxt = src->next;
+
+ fit_get(f, dst);
+
+ if (!src->prev)
+ {
+ /* We are at the end */
+ fit_put_end(dst);
+ return;
+ }
+
+ src->next = dst;
+ dst->prev = src;
+
+ dst->next = nxt;
+ if (nxt)
+ nxt->prev = dst;
+
+ dst->node = src->node;
+ dst->hash = src->hash;
+}
+
+
#ifdef DEBUGGING
/**
diff --git a/nest/rt-show.c b/nest/rt-show.c
index 002a6039..7691878d 100644
--- a/nest/rt-show.c
+++ b/nest/rt-show.c
@@ -15,6 +15,7 @@
#include "nest/cli.h"
#include "nest/iface.h"
#include "filter/filter.h"
+#include "sysdep/unix/krt.h"
static void
rt_show_table(struct cli *c, struct rt_show_data *d)
@@ -28,14 +29,20 @@ rt_show_table(struct cli *c, struct rt_show_data *d)
d->last_table = d->tab;
}
+static inline struct krt_proto *
+rt_show_get_kernel(struct rt_show_data *d)
+{
+ struct proto_config *krt = d->tab->table->config->krt_attached;
+ return krt ? (struct krt_proto *) krt->proto : NULL;
+}
+
static void
-rt_show_rte(struct cli *c, byte *ia, rte *e, struct rt_show_data *d)
+rt_show_rte(struct cli *c, byte *ia, rte *e, struct rt_show_data *d, int primary)
{
byte from[IPA_MAX_TEXT_LENGTH+8];
byte tm[TM_DATETIME_BUFFER_SIZE], info[256];
rta *a = e->attrs;
- int primary = (e->net->routes == e);
- int sync_error = (e->net->n.flags & KRF_SYNC_ERROR);
+ int sync_error = d->kernel ? krt_get_sync_error(d->kernel, e) : 0;
void (*get_route_info)(struct rte *, byte *buf);
struct nexthop *nh;
@@ -97,6 +104,11 @@ rt_show_net(struct cli *c, net *n, struct rt_show_data *d)
rte *e, *ee;
byte ia[NET_MAX_TEXT_LENGTH+1];
struct channel *ec = d->tab->export_channel;
+
+ /* The Clang static analyzer complains that ec may be NULL.
+ * It should be ensured to be not NULL by rt_show_prepare_tables() */
+ ASSUME(!d->export_mode || ec);
+
int first = 1;
int pass = 0;
@@ -121,9 +133,17 @@ rt_show_net(struct cli *c, net *n, struct rt_show_data *d)
if (ec && (ec->export_state == ES_DOWN))
goto skip;
- /* Special case for merged export */
- if ((d->export_mode == RSEM_EXPORT) && (ec->ra_mode == RA_MERGED))
+ if (d->export_mode == RSEM_EXPORTED)
+ {
+ if (!bmap_test(&ec->export_map, ee->id))
+ goto skip;
+
+ // if (ec->ra_mode != RA_ANY)
+ // pass = 1;
+ }
+ else if ((d->export_mode == RSEM_EXPORT) && (ec->ra_mode == RA_MERGED))
{
+ /* Special case for merged export */
rte *rt_free;
e = rt_export_merged(ec, n, &rt_free, c->show_pool, 1);
pass = 1;
@@ -167,7 +187,7 @@ rt_show_net(struct cli *c, net *n, struct rt_show_data *d)
goto skip;
if (d->stats < 2)
- rt_show_rte(c, ia, e, d);
+ rt_show_rte(c, ia, e, d, (e->net->routes == ee));
d->show_counter++;
ia[0] = 0;
@@ -223,6 +243,7 @@ rt_show_cont(struct cli *c)
FIB_ITERATE_INIT(&d->fit, &d->tab->table->fib);
d->table_open = 1;
d->table_counter++;
+ d->kernel = rt_show_get_kernel(d);
d->show_counter_last = d->show_counter;
d->rt_counter_last = d->rt_counter;
@@ -253,6 +274,7 @@ rt_show_cont(struct cli *c)
d->net_counter - d->net_counter_last, d->tab->table->name);
}
+ d->kernel = NULL;
d->table_open = 0;
d->tab = NODE_NEXT(d->tab);
@@ -396,6 +418,7 @@ rt_show(struct rt_show_data *d)
WALK_LIST(tab, d->tables)
{
d->tab = tab;
+ d->kernel = rt_show_get_kernel(d);
if (d->show_for)
n = net_route(tab->table, d->addr);
diff --git a/nest/rt-table.c b/nest/rt-table.c
index 0844070d..626c2fb8 100644
--- a/nest/rt-table.c
+++ b/nest/rt-table.c
@@ -36,6 +36,7 @@
#include "nest/iface.h"
#include "lib/resource.h"
#include "lib/event.h"
+#include "lib/timer.h"
#include "lib/string.h"
#include "conf/conf.h"
#include "filter/filter.h"
@@ -60,6 +61,7 @@ static void rt_notify_hostcache(rtable *tab, net *net);
static void rt_update_hostcache(rtable *tab);
static void rt_next_hop_update(rtable *tab);
static inline void rt_prune_table(rtable *tab);
+static inline void rt_schedule_notify(rtable *tab);
/* Like fib_route(), but skips empty net entries */
@@ -282,6 +284,7 @@ rte_get_temp(rta *a)
rte *e = sl_alloc(rte_slab);
e->attrs = a;
+ e->id = 0;
e->flags = 0;
e->pref = 0;
return e;
@@ -549,23 +552,25 @@ rte_mergable(rte *pri, rte *sec)
}
static void
-rte_trace(struct proto *p, rte *e, int dir, char *msg)
+rte_trace(struct channel *c, rte *e, int dir, char *msg)
{
- log(L_TRACE "%s %c %s %N %s", p->name, dir, msg, e->net->n.addr, rta_dest_name(e->attrs->dest));
+ log(L_TRACE "%s.%s %c %s %N %s",
+ c->proto->name, c->name ?: "?", dir, msg, e->net->n.addr,
+ rta_dest_name(e->attrs->dest));
}
static inline void
-rte_trace_in(uint flag, struct proto *p, rte *e, char *msg)
+rte_trace_in(uint flag, struct channel *c, rte *e, char *msg)
{
- if (p->debug & flag)
- rte_trace(p, e, '>', msg);
+ if ((c->debug & flag) || (c->proto->debug & flag))
+ rte_trace(c, e, '>', msg);
}
static inline void
-rte_trace_out(uint flag, struct proto *p, rte *e, char *msg)
+rte_trace_out(uint flag, struct channel *c, rte *e, char *msg)
{
- if (p->debug & flag)
- rte_trace(p, e, '<', msg);
+ if ((c->debug & flag) || (c->proto->debug & flag))
+ rte_trace(c, e, '<', msg);
}
static rte *
@@ -588,13 +593,13 @@ export_filter_(struct channel *c, rte *rt0, rte **rt_free, linpool *pool, int si
stats->exp_updates_rejected++;
if (v == RIC_REJECT)
- rte_trace_out(D_FILTERS, p, rt, "rejected by protocol");
+ rte_trace_out(D_FILTERS, c, rt, "rejected by protocol");
goto reject;
}
if (v > 0)
{
if (!silent)
- rte_trace_out(D_FILTERS, p, rt, "forced accept by protocol");
+ rte_trace_out(D_FILTERS, c, rt, "forced accept by protocol");
goto accept;
}
@@ -609,7 +614,7 @@ export_filter_(struct channel *c, rte *rt0, rte **rt_free, linpool *pool, int si
goto reject;
stats->exp_updates_filtered++;
- rte_trace_out(D_FILTERS, p, rt, "filtered out");
+ rte_trace_out(D_FILTERS, c, rt, "filtered out");
goto reject;
}
@@ -637,51 +642,25 @@ do_rt_notify(struct channel *c, net *net, rte *new, rte *old, int refeed)
struct proto *p = c->proto;
struct proto_stats *stats = &c->stats;
- /*
- * First, apply export limit.
- *
- * Export route limits has several problems. Because exp_routes
- * counter is reset before refeed, we don't really know whether
- * limit is breached and whether the update is new or not. Therefore
- * the number of really exported routes may exceed the limit
- * temporarily (routes exported before and new routes in refeed).
- *
- * Minor advantage is that if the limit is decreased and refeed is
- * requested, the number of exported routes really decrease.
- *
- * Second problem is that with export limits, we don't know whether
- * old was really exported (it might be blocked by limit). When a
- * withdraw is exported, we announce it even when the previous
- * update was blocked. This is not a big issue, but the same problem
- * is in updating exp_routes counter. Therefore, to be consistent in
- * increases and decreases of exp_routes, we count exported routes
- * regardless of blocking by limits.
- *
- * Similar problem is in handling updates - when a new route is
- * received and blocking is active, the route would be blocked, but
- * when an update for the route will be received later, the update
- * would be propagated (as old != NULL). Therefore, we have to block
- * also non-new updates (contrary to import blocking).
- */
+ if (refeed && new)
+ c->refeed_count++;
+ /* Apply export limit */
struct channel_limit *l = &c->out_limit;
- if (l->action && new)
- {
- if ((!old || refeed) && (stats->exp_routes >= l->limit))
- channel_notify_limit(c, l, PLD_OUT, stats->exp_routes);
-
- if (l->state == PLS_BLOCKED)
- {
- stats->exp_routes++; /* see note above */
- stats->exp_updates_rejected++;
- rte_trace_out(D_FILTERS, p, new, "rejected [limit]");
- new = NULL;
+ if (l->action && !old && new)
+ {
+ if (stats->exp_routes >= l->limit)
+ channel_notify_limit(c, l, PLD_OUT, stats->exp_routes);
- if (!old)
- return;
- }
+ if (l->state == PLS_BLOCKED)
+ {
+ stats->exp_updates_rejected++;
+ rte_trace_out(D_FILTERS, c, new, "rejected [limit]");
+ return;
}
+ }
+ /* Apply export table */
if (c->out_table && !rte_update_out(c, net->n.addr, new, old, refeed))
return;
@@ -690,236 +669,132 @@ do_rt_notify(struct channel *c, net *net, rte *new, rte *old, int refeed)
else
stats->exp_withdraws_accepted++;
- /* Hack: We do not decrease exp_routes during refeed, we instead
- reset exp_routes at the start of refeed. */
+ if (old)
+ {
+ bmap_clear(&c->export_map, old->id);
+ stats->exp_routes--;
+ }
+
if (new)
+ {
+ bmap_set(&c->export_map, new->id);
stats->exp_routes++;
- if (old && !refeed)
- stats->exp_routes--;
+ }
if (p->debug & D_ROUTES)
- {
- if (new && old)
- rte_trace_out(D_ROUTES, p, new, "replaced");
- else if (new)
- rte_trace_out(D_ROUTES, p, new, "added");
- else if (old)
- rte_trace_out(D_ROUTES, p, old, "removed");
- }
+ {
+ if (new && old)
+ rte_trace_out(D_ROUTES, c, new, "replaced");
+ else if (new)
+ rte_trace_out(D_ROUTES, c, new, "added");
+ else if (old)
+ rte_trace_out(D_ROUTES, c, old, "removed");
+ }
+
p->rt_notify(p, c, net, new, old);
}
static void
-rt_notify_basic(struct channel *c, net *net, rte *new0, rte *old0, int refeed)
+rt_notify_basic(struct channel *c, net *net, rte *new, rte *old, int refeed)
{
- struct proto *p = c->proto;
-
- rte *new = new0;
- rte *old = old0;
+ // struct proto *p = c->proto;
rte *new_free = NULL;
- rte *old_free = NULL;
if (new)
c->stats.exp_updates_received++;
else
c->stats.exp_withdraws_received++;
- /*
- * This is a tricky part - we don't know whether route 'old' was exported to
- * protocol 'p' or was filtered by the export filter. We try to run the export
- * filter to know this to have a correct value in 'old' argument of rte_update
- * (and proper filter value).
- *
- * This is broken because 'configure soft' may change filters but keep routes.
- * Refeed cycle is expected to be called after change of the filters and with
- * old == new, therefore we do not even try to run the filter on an old route.
- * This may lead to 'spurious withdraws' but ensure that there are no 'missing
- * withdraws'.
- *
- * This is not completely safe as there is a window between reconfiguration
- * and the end of refeed - if a newly filtered route disappears during this
- * period, proper withdraw is not sent (because old would be also filtered)
- * and the route is not refeeded (because it disappeared before that).
- * This is handled below as a special case.
- */
-
if (new)
new = export_filter(c, new, &new_free, 0);
- if (old && !refeed)
- old = export_filter(c, old, &old_free, 1);
+ if (old && !bmap_test(&c->export_map, old->id))
+ old = NULL;
if (!new && !old)
- {
- /*
- * As mentioned above, 'old' value may be incorrect in some race conditions.
- * We generally ignore it with two exceptions:
- *
- * First, withdraw to pipe protocol. In that case we rather propagate
- * unfiltered withdraws regardless of export filters to ensure that when a
- * protocol is flushed, its routes are removed from all tables. Possible
- * spurious unfiltered withdraws are not problem here as they are ignored if
- * there is no corresponding route at the other end of the pipe.
- *
- * Second, recent filter change. If old route is older than filter change,
- * then it was previously evaluated by a different filter and we do not know
- * whether it was really propagated. In that case we rather send spurious
- * withdraw than do nothing and possibly cause phantom routes.
- *
- * In both cases wqe directly call rt_notify() hook instead of
- * do_rt_notify() to avoid logging and stat counters.
- */
-
- int pipe_withdraw = 0, filter_change = 0;
-#ifdef CONFIG_PIPE
- pipe_withdraw = (p->proto == &proto_pipe) && !new0;
-#endif
- filter_change = old0 && (old0->lastmod <= c->last_tx_filter_change);
-
- if ((pipe_withdraw || filter_change) && (p != old0->sender->proto))
- {
- c->stats.exp_withdraws_accepted++;
- p->rt_notify(p, c, net, NULL, old0);
- }
-
return;
- }
do_rt_notify(c, net, new, old, refeed);
- /* Discard temporary rte's */
+ /* Discard temporary rte */
if (new_free)
rte_free(new_free);
- if (old_free)
- rte_free(old_free);
}
static void
-rt_notify_accepted(struct channel *c, net *net, rte *new_changed, rte *old_changed, rte *before_old, int feed)
+rt_notify_accepted(struct channel *c, net *net, rte *new_changed, rte *old_changed, int refeed)
{
- struct proto *p = c->proto;
-
- rte *r;
+ // struct proto *p = c->proto;
rte *new_best = NULL;
rte *old_best = NULL;
rte *new_free = NULL;
- rte *old_free = NULL;
+ int new_first = 0;
- /* Used to track whether we met old_changed position. If before_old is NULL
- old_changed was the first and we met it implicitly before current best route. */
- int old_meet = old_changed && !before_old;
-
- /* Note that before_old is either NULL or valid (not rejected) route.
- If old_changed is valid, before_old have to be too. If old changed route
- was not valid, caller must use NULL for both old_changed and before_old. */
+ /*
+ * We assume that there are no changes in net route order except (added)
+ * new_changed and (removed) old_changed. Therefore, the function is not
+ * compatible with deterministic_med (where nontrivial reordering can happen
+ * as a result of a route change) and with recomputation of recursive routes
+ * due to next hop update (where many routes can be changed in one step).
+ *
+ * Note that we need this assumption just for optimizations, we could just
+ * run full new_best recomputation otherwise.
+ *
+ * There are three cases:
+ * feed or old_best is old_changed -> we need to recompute new_best
+ * old_best is before new_changed -> new_best is old_best, ignore
+ * old_best is after new_changed -> try new_changed, otherwise old_best
+ */
- if (new_changed)
+ if (net->routes)
c->stats.exp_updates_received++;
else
c->stats.exp_withdraws_received++;
- /* First, find the new_best route - first accepted by filters */
- for (r=net->routes; rte_is_valid(r); r=r->next)
+ /* Find old_best - either old_changed, or route for net->routes */
+ if (old_changed && bmap_test(&c->export_map, old_changed->id))
+ old_best = old_changed;
+ else
+ {
+ for (rte *r = net->routes; rte_is_valid(r); r = r->next)
{
- if (new_best = export_filter(c, r, &new_free, 0))
+ if (bmap_test(&c->export_map, r->id))
+ {
+ old_best = r;
break;
+ }
- /* Note if we walked around the position of old_changed route */
- if (r == before_old)
- old_meet = 1;
- }
-
- /*
- * Second, handle the feed case. That means we do not care for
- * old_best. It is NULL for feed, and the new_best for refeed.
- * For refeed, there is a hack similar to one in rt_notify_basic()
- * to ensure withdraws in case of changed filters
- */
- if (feed)
- {
- if (feed == 2) /* refeed */
- old_best = new_best ? new_best :
- (rte_is_valid(net->routes) ? net->routes : NULL);
- else
- old_best = NULL;
-
- if (!new_best && !old_best)
- return;
-
- goto found;
- }
-
- /*
- * Now, we find the old_best route. Generally, it is the same as the
- * new_best, unless new_best is the same as new_changed or
- * old_changed is accepted before new_best.
- *
- * There are four cases:
- *
- * - We would find and accept old_changed before new_best, therefore
- * old_changed is old_best. In remaining cases we suppose this
- * is not true.
- *
- * - We found no new_best, therefore there is also no old_best and
- * we ignore this withdraw.
- *
- * - We found new_best different than new_changed, therefore
- * old_best is the same as new_best and we ignore this update.
- *
- * - We found new_best the same as new_changed, therefore it cannot
- * be old_best and we have to continue search for old_best.
- *
- * There is also a hack to ensure consistency in case of changed filters.
- * It does not find the proper old_best, just selects a non-NULL route.
- */
-
- /* Hack for changed filters */
- if (old_changed &&
- (p != old_changed->sender->proto) &&
- (old_changed->lastmod <= c->last_tx_filter_change))
- {
- old_best = old_changed;
- goto found;
+ /* Note if new_changed found before old_best */
+ if (r == new_changed)
+ new_first = 1;
}
+ }
- /* First case */
- if (old_meet)
- if (old_best = export_filter(c, old_changed, &old_free, 1))
- goto found;
-
- /* Second case */
- if (!new_best)
- return;
-
- /* Third case, we use r instead of new_best, because export_filter() could change it */
- if (r != new_changed)
- {
- if (new_free)
- rte_free(new_free);
+ /* Find new_best */
+ if ((new_changed == old_changed) || (old_best == old_changed))
+ {
+ /* Feed or old_best changed -> find first accepted by filters */
+ for (rte *r = net->routes; rte_is_valid(r); r = r->next)
+ if (new_best = export_filter(c, r, &new_free, 0))
+ break;
+ }
+ else
+ {
+ /* Other cases -> either new_changed, or old_best (and nothing changed) */
+ if (new_first && (new_changed = export_filter(c, new_changed, &new_free, 0)))
+ new_best = new_changed;
+ else
return;
- }
-
- /* Fourth case */
- for (r=r->next; rte_is_valid(r); r=r->next)
- {
- if (old_best = export_filter(c, r, &old_free, 1))
- goto found;
-
- if (r == before_old)
- if (old_best = export_filter(c, old_changed, &old_free, 1))
- goto found;
- }
+ }
- /* Implicitly, old_best is NULL and new_best is non-NULL */
+ if (!new_best && !old_best)
+ return;
- found:
- do_rt_notify(c, net, new_best, old_best, (feed == 2));
+ do_rt_notify(c, net, new_best, old_best, refeed);
- /* Discard temporary rte's */
+ /* Discard temporary rte */
if (new_free)
rte_free(new_free);
- if (old_free)
- rte_free(old_free);
}
@@ -984,14 +859,10 @@ rt_export_merged(struct channel *c, net *net, rte **rt_free, linpool *pool, int
static void
rt_notify_merged(struct channel *c, net *net, rte *new_changed, rte *old_changed,
- rte *new_best, rte*old_best, int refeed)
+ rte *new_best, rte *old_best, int refeed)
{
// struct proto *p = c->proto;
-
- rte *new_best_free = NULL;
- rte *old_best_free = NULL;
- rte *new_changed_free = NULL;
- rte *old_changed_free = NULL;
+ rte *new_free = NULL;
/* We assume that all rte arguments are either NULL or rte_is_valid() */
@@ -1000,17 +871,11 @@ rt_notify_merged(struct channel *c, net *net, rte *new_changed, rte *old_changed
return;
/* Check whether the change is relevant to the merged route */
- if ((new_best == old_best) && !refeed)
- {
- new_changed = rte_mergable(new_best, new_changed) ?
- export_filter(c, new_changed, &new_changed_free, 1) : NULL;
-
- old_changed = rte_mergable(old_best, old_changed) ?
- export_filter(c, old_changed, &old_changed_free, 1) : NULL;
-
- if (!new_changed && !old_changed)
- return;
- }
+ if ((new_best == old_best) &&
+ (new_changed != old_changed) &&
+ !rte_mergable(new_best, new_changed) &&
+ !rte_mergable(old_best, old_changed))
+ return;
if (new_best)
c->stats.exp_updates_received++;
@@ -1019,69 +884,71 @@ rt_notify_merged(struct channel *c, net *net, rte *new_changed, rte *old_changed
/* Prepare new merged route */
if (new_best)
- new_best = rt_export_merged(c, net, &new_best_free, rte_update_pool, 0);
+ new_best = rt_export_merged(c, net, &new_free, rte_update_pool, 0);
+
+ /* Check old merged route */
+ if (old_best && !bmap_test(&c->export_map, old_best->id))
+ old_best = NULL;
- /* Prepare old merged route (without proper merged next hops) */
- /* There are some issues with running filter on old route - see rt_notify_basic() */
- if (old_best && !refeed)
- old_best = export_filter(c, old_best, &old_best_free, 1);
+ if (!new_best && !old_best)
+ return;
- if (new_best || old_best)
- do_rt_notify(c, net, new_best, old_best, refeed);
+ do_rt_notify(c, net, new_best, old_best, refeed);
- /* Discard temporary rte's */
- if (new_best_free)
- rte_free(new_best_free);
- if (old_best_free)
- rte_free(old_best_free);
- if (new_changed_free)
- rte_free(new_changed_free);
- if (old_changed_free)
- rte_free(old_changed_free);
+ /* Discard temporary rte */
+ if (new_free)
+ rte_free(new_free);
}
/**
* rte_announce - announce a routing table change
* @tab: table the route has been added to
- * @type: type of route announcement (RA_OPTIMAL or RA_ANY)
+ * @type: type of route announcement (RA_UNDEF or RA_ANY)
* @net: network in question
- * @new: the new route to be announced
- * @old: the previous route for the same network
+ * @new: the new or changed route
+ * @old: the previous route replaced by the new one
* @new_best: the new best route for the same network
* @old_best: the previous best route for the same network
- * @before_old: The previous route before @old for the same network.
- * If @before_old is NULL @old was the first.
*
- * This function gets a routing table update and announces it
- * to all protocols that acccepts given type of route announcement
- * and are connected to the same table by their announcement hooks.
+ * This function gets a routing table update and announces it to all protocols
+ * that are connected to the same table by their channels.
+ *
+ * There are two ways of how routing table changes are announced. First, there
+ * is a change of just one route in @net (which may caused a change of the best
+ * route of the network). In this case @new and @old describes the changed route
+ * and @new_best and @old_best describes best routes. Other routes are not
+ * affected, but in sorted table the order of other routes might change.
+ *
+ * Second, There is a bulk change of multiple routes in @net, with shared best
+ * route selection. In such case separate route changes are described using
+ * @type of %RA_ANY, with @new and @old specifying the changed route, while
+ * @new_best and @old_best are NULL. After that, another notification is done
+ * where @new_best and @old_best are filled (may be the same), but @new and @old
+ * are NULL.
*
- * Route announcement of type %RA_OPTIMAL si generated when optimal
- * route (in routing table @tab) changes. In that case @old stores the
- * old optimal route.
+ * The function announces the change to all associated channels. For each
+ * channel, an appropriate preprocessing is done according to channel &ra_mode.
+ * For example, %RA_OPTIMAL channels receive just changes of best routes.
*
- * Route announcement of type %RA_ANY si generated when any route (in
- * routing table @tab) changes In that case @old stores the old route
- * from the same protocol.
+ * In general, we first call preexport() hook of a protocol, which performs
+ * basic checks on the route (each protocol has a right to veto or force accept
+ * of the route before any filter is asked). Then we consult an export filter
+ * of the channel and verify the old route in an export map of the channel.
+ * Finally, the rt_notify() hook of the protocol gets called.
*
- * For each appropriate protocol, we first call its preexport()
- * hook which performs basic checks on the route (each protocol has a
- * right to veto or force accept of the route before any filter is
- * asked) and adds default values of attributes specific to the new
- * protocol (metrics, tags etc.). Then it consults the protocol's
- * export filter and if it accepts the route, the rt_notify() hook of
- * the protocol gets called.
+ * Note that there are also calls of rt_notify() hooks due to feed, but that is
+ * done outside of scope of rte_announce().
*/
static void
-rte_announce(rtable *tab, unsigned type, net *net, rte *new, rte *old,
- rte *new_best, rte *old_best, rte *before_old)
+rte_announce(rtable *tab, uint type, net *net, rte *new, rte *old,
+ rte *new_best, rte *old_best)
{
if (!rte_is_valid(new))
new = NULL;
if (!rte_is_valid(old))
- old = before_old = NULL;
+ old = NULL;
if (!rte_is_valid(new_best))
new_best = NULL;
@@ -1089,34 +956,52 @@ rte_announce(rtable *tab, unsigned type, net *net, rte *new, rte *old,
if (!rte_is_valid(old_best))
old_best = NULL;
- if (!old && !new)
+ if (!new && !old && !new_best && !old_best)
return;
- if (type == RA_OPTIMAL)
+ if (new_best != old_best)
{
- if (new)
- new->sender->stats.pref_routes++;
- if (old)
- old->sender->stats.pref_routes--;
+ if (new_best)
+ new_best->sender->stats.pref_routes++;
+ if (old_best)
+ old_best->sender->stats.pref_routes--;
if (tab->hostcache)
rt_notify_hostcache(tab, net);
}
+ rt_schedule_notify(tab);
+
struct channel *c; node *n;
WALK_LIST2(c, n, tab->channels, table_node)
+ {
+ if (c->export_state == ES_DOWN)
+ continue;
+
+ if (type && (type != c->ra_mode))
+ continue;
+
+ switch (c->ra_mode)
{
- if (c->export_state == ES_DOWN)
- continue;
+ case RA_OPTIMAL:
+ if (new_best != old_best)
+ rt_notify_basic(c, net, new_best, old_best, 0);
+ break;
+
+ case RA_ANY:
+ if (new != old)
+ rt_notify_basic(c, net, new, old, 0);
+ break;
- if (c->ra_mode == type)
- if (type == RA_ACCEPTED)
- rt_notify_accepted(c, net, new, old, before_old, 0);
- else if (type == RA_MERGED)
- rt_notify_merged(c, net, new, old, new_best, old_best, 0);
- else
- rt_notify_basic(c, net, new, old, 0);
+ case RA_ACCEPTED:
+ rt_notify_accepted(c, net, new, old, 0);
+ break;
+
+ case RA_MERGED:
+ rt_notify_merged(c, net, new, old, new_best, old_best, 0);
+ break;
}
+ }
}
static inline int
@@ -1240,7 +1125,7 @@ rte_recalculate(struct channel *c, net *net, rte *new, struct rte_src *src)
if (!rte_is_filtered(new))
{
stats->imp_updates_ignored++;
- rte_trace_in(D_ROUTES, p, new, "ignored");
+ rte_trace_in(D_ROUTES, c, new, "ignored");
}
rte_free_quick(new);
@@ -1254,6 +1139,9 @@ rte_recalculate(struct channel *c, net *net, rte *new, struct rte_src *src)
before_old = old;
}
+ /* Save the last accessed position */
+ rte **pos = k;
+
if (!old)
before_old = NULL;
@@ -1280,7 +1168,7 @@ rte_recalculate(struct channel *c, net *net, rte *new, struct rte_src *src)
we just free new and exit like nothing happened */
stats->imp_updates_ignored++;
- rte_trace_in(D_FILTERS, p, new, "ignored [limit]");
+ rte_trace_in(D_FILTERS, c, new, "ignored [limit]");
rte_free_quick(new);
return;
}
@@ -1302,7 +1190,7 @@ rte_recalculate(struct channel *c, net *net, rte *new, struct rte_src *src)
already handled. */
stats->imp_updates_ignored++;
- rte_trace_in(D_FILTERS, p, new, "ignored [limit]");
+ rte_trace_in(D_FILTERS, c, new, "ignored [limit]");
if (c->in_keep_filtered)
new->flags |= REF_FILTERED;
@@ -1327,6 +1215,9 @@ rte_recalculate(struct channel *c, net *net, rte *new, struct rte_src *src)
else
stats->imp_withdraws_ignored++;
+ if (old_ok || new_ok)
+ table->last_rt_change = current_time();
+
skip_stats1:
if (new)
@@ -1350,6 +1241,7 @@ rte_recalculate(struct channel *c, net *net, rte *new, struct rte_src *src)
new->next = *k;
*k = new;
+
table->rt_count++;
}
}
@@ -1368,6 +1260,7 @@ rte_recalculate(struct channel *c, net *net, rte *new, struct rte_src *src)
new->next = net->routes;
net->routes = new;
+
table->rt_count++;
}
else if (old == old_best)
@@ -1382,8 +1275,9 @@ rte_recalculate(struct channel *c, net *net, rte *new, struct rte_src *src)
/* Add the new route to the list */
if (new)
{
- new->next = net->routes;
- net->routes = new;
+ new->next = *pos;
+ *pos = new;
+
table->rt_count++;
}
@@ -1407,42 +1301,47 @@ rte_recalculate(struct channel *c, net *net, rte *new, struct rte_src *src)
/* The third case - the new route is not better than the old
best route (therefore old_best != NULL) and the old best
route was not removed (therefore old_best == net->routes).
- We just link the new route after the old best route. */
+ We just link the new route to the old/last position. */
+
+ new->next = *pos;
+ *pos = new;
- ASSERT(net->routes != NULL);
- new->next = net->routes->next;
- net->routes->next = new;
table->rt_count++;
}
/* The fourth (empty) case - suboptimal route was removed, nothing to do */
}
if (new)
- new->lastmod = current_time();
+ {
+ new->lastmod = current_time();
+
+ if (!old)
+ {
+ new->id = hmap_first_zero(&table->id_map);
+ hmap_set(&table->id_map, new->id);
+ }
+ else
+ new->id = old->id;
+ }
/* Log the route change */
- if (p->debug & D_ROUTES)
+ if ((c->debug & D_ROUTES) || (p->debug & D_ROUTES))
{
if (new_ok)
- rte_trace(p, new, '>', new == net->routes ? "added [best]" : "added");
+ rte_trace(c, new, '>', new == net->routes ? "added [best]" : "added");
else if (old_ok)
{
if (old != old_best)
- rte_trace(p, old, '>', "removed");
+ rte_trace(c, old, '>', "removed");
else if (rte_is_ok(net->routes))
- rte_trace(p, old, '>', "removed [replaced]");
+ rte_trace(c, old, '>', "removed [replaced]");
else
- rte_trace(p, old, '>', "removed [sole]");
+ rte_trace(c, old, '>', "removed [sole]");
}
}
/* Propagate the route change */
- rte_announce(table, RA_ANY, net, new, old, NULL, NULL, NULL);
- if (net->routes != old_best)
- rte_announce(table, RA_OPTIMAL, net, net->routes, old_best, NULL, NULL, NULL);
- if (table->config->sorted)
- rte_announce(table, RA_ACCEPTED, net, new, old, NULL, NULL, before_old);
- rte_announce(table, RA_MERGED, net, new, old, net->routes, old_best, NULL);
+ rte_announce(table, RA_UNDEF, net, new, old, net->routes, old_best);
if (!net->routes &&
(table->gc_counter++ >= table->config->gc_max_ops) &&
@@ -1455,7 +1354,12 @@ rte_recalculate(struct channel *c, net *net, rte *new, struct rte_src *src)
p->rte_insert(net, new);
if (old)
- rte_free_quick(old);
+ {
+ if (!new)
+ hmap_clear(&table->id_map, old->id);
+
+ rte_free_quick(old);
+ }
}
static int rte_update_nest_cnt; /* Nesting counter to allow recursive updates */
@@ -1538,7 +1442,7 @@ rte_unhide_dummy_routes(net *net, rte **dummy)
void
rte_update2(struct channel *c, const net_addr *n, rte *new, struct rte_src *src)
{
- struct proto *p = c->proto;
+ // struct proto *p = c->proto;
struct proto_stats *stats = &c->stats;
const struct filter *filter = c->in_filter;
rte *dummy = NULL;
@@ -1563,7 +1467,7 @@ rte_update2(struct channel *c, const net_addr *n, rte *new, struct rte_src *src)
stats->imp_updates_received++;
if (!rte_validate(new))
{
- rte_trace_in(D_FILTERS, p, new, "invalid");
+ rte_trace_in(D_FILTERS, c, new, "invalid");
stats->imp_updates_invalid++;
goto drop;
}
@@ -1571,7 +1475,7 @@ rte_update2(struct channel *c, const net_addr *n, rte *new, struct rte_src *src)
if (filter == FILTER_REJECT)
{
stats->imp_updates_filtered++;
- rte_trace_in(D_FILTERS, p, new, "filtered out");
+ rte_trace_in(D_FILTERS, c, new, "filtered out");
if (! c->in_keep_filtered)
goto drop;
@@ -1588,7 +1492,7 @@ rte_update2(struct channel *c, const net_addr *n, rte *new, struct rte_src *src)
if (fr > F_ACCEPT)
{
stats->imp_updates_filtered++;
- rte_trace_in(D_FILTERS, p, new, "filtered out");
+ rte_trace_in(D_FILTERS, c, new, "filtered out");
if (! c->in_keep_filtered)
{
@@ -1642,11 +1546,11 @@ rte_update2(struct channel *c, const net_addr *n, rte *new, struct rte_src *src)
/* Independent call to rte_announce(), used from next hop
recalculation, outside of rte_update(). new must be non-NULL */
static inline void
-rte_announce_i(rtable *tab, unsigned type, net *net, rte *new, rte *old,
+rte_announce_i(rtable *tab, uint type, net *net, rte *new, rte *old,
rte *new_best, rte *old_best)
{
rte_update_lock();
- rte_announce(tab, type, net, new, old, new_best, old_best, NULL);
+ rte_announce(tab, type, net, new, old, new_best, old_best);
rte_update_unlock();
}
@@ -1798,7 +1702,7 @@ rte_dump(rte *e)
{
net *n = e->net;
debug("%-1N ", n->n.addr);
- debug("KF=%02x PF=%02x pref=%d ", n->n.flags, e->pflags, e->pref);
+ debug("PF=%02x pref=%d ", e->pflags, e->pref);
rta_dump(e->attrs);
if (e->attrs->src->proto->proto->dump_attrs)
e->attrs->src->proto->proto->dump_attrs(e);
@@ -1895,6 +1799,78 @@ rt_event(void *ptr)
rt_unlock_table(tab);
}
+
+static inline btime
+rt_settled_time(rtable *tab)
+{
+ ASSUME(tab->base_settle_time != 0);
+
+ return MIN(tab->last_rt_change + tab->config->min_settle_time,
+ tab->base_settle_time + tab->config->max_settle_time);
+}
+
+static void
+rt_settle_timer(timer *t)
+{
+ rtable *tab = t->data;
+
+ if (!tab->base_settle_time)
+ return;
+
+ btime settled_time = rt_settled_time(tab);
+ if (current_time() < settled_time)
+ {
+ tm_set(tab->settle_timer, settled_time);
+ return;
+ }
+
+ /* Settled */
+ tab->base_settle_time = 0;
+
+ struct rt_subscription *s;
+ WALK_LIST(s, tab->subscribers)
+ s->hook(s);
+}
+
+static void
+rt_kick_settle_timer(rtable *tab)
+{
+ tab->base_settle_time = current_time();
+
+ if (!tab->settle_timer)
+ tab->settle_timer = tm_new_init(rt_table_pool, rt_settle_timer, tab, 0, 0);
+
+ if (!tm_active(tab->settle_timer))
+ tm_set(tab->settle_timer, rt_settled_time(tab));
+}
+
+static inline void
+rt_schedule_notify(rtable *tab)
+{
+ if (EMPTY_LIST(tab->subscribers))
+ return;
+
+ if (tab->base_settle_time)
+ return;
+
+ rt_kick_settle_timer(tab);
+}
+
+void
+rt_subscribe(rtable *tab, struct rt_subscription *s)
+{
+ s->tab = tab;
+ rt_lock_table(tab);
+ add_tail(&tab->subscribers, &s->n);
+}
+
+void
+rt_unsubscribe(struct rt_subscription *s)
+{
+ rem_node(&s->n);
+ rt_unlock_table(s->tab);
+}
+
void
rt_setup(pool *p, rtable *t, struct rtable_config *cf)
{
@@ -1905,8 +1881,13 @@ rt_setup(pool *p, rtable *t, struct rtable_config *cf)
fib_init(&t->fib, p, t->addr_type, sizeof(net), OFFSETOF(net, n), 0, NULL);
init_list(&t->channels);
+ hmap_init(&t->id_map, p, 1024);
+ hmap_set(&t->id_map, 0);
+
t->rt_event = ev_new_init(p, rt_event, t);
- t->gc_time = current_time();
+ t->last_rt_change = t->gc_time = current_time();
+
+ init_list(&t->subscribers);
}
/**
@@ -2200,8 +2181,8 @@ rt_next_hop_update_net(rtable *tab, net *n)
new = rt_next_hop_update_rte(tab, e);
*k = new;
+ rte_trace_in(D_ROUTES, new->sender, new, "updated");
rte_announce_i(tab, RA_ANY, n, new, e, NULL, NULL);
- rte_trace_in(D_ROUTES, new->sender->proto, new, "updated");
/* Call a pre-comparison hook */
/* Not really an efficient way to compute this */
@@ -2239,13 +2220,10 @@ rt_next_hop_update_net(rtable *tab, net *n)
/* Announce the new best route */
if (new != old_best)
- {
- rte_announce_i(tab, RA_OPTIMAL, n, new, old_best, NULL, NULL);
- rte_trace_in(D_ROUTES, new->sender->proto, new, "updated [best]");
- }
+ rte_trace_in(D_ROUTES, new->sender, new, "updated [best]");
- /* FIXME: Better announcement of merged routes */
- rte_announce_i(tab, RA_MERGED, n, new, old_best, new, old_best);
+ /* Propagate changes */
+ rte_announce_i(tab, RA_UNDEF, n, NULL, NULL, n->routes, old_best);
if (free_old_best)
rte_free_quick(old_best);
@@ -2307,6 +2285,8 @@ rt_new_table(struct symbol *s, uint addr_type)
c->addr_type = addr_type;
c->gc_max_ops = 1000;
c->gc_min_time = 5;
+ c->min_settle_time = 1 S;
+ c->max_settle_time = 20 S;
add_tail(&new_config->tables, &c->n);
@@ -2351,7 +2331,9 @@ rt_unlock_table(rtable *r)
rt_free_hostcache(r);
rem_node(&r->n);
fib_free(&r->fib);
+ hmap_free(&r->id_map);
rfree(r->rt_event);
+ rfree(r->settle_timer);
mb_free(r);
config_del_obstacle(conf);
}
@@ -2414,7 +2396,7 @@ rt_commit(struct config *new, struct config *old)
WALK_LIST(r, new->tables)
if (!r->table)
{
- rtable *t = mb_alloc(rt_table_pool, sizeof(struct rtable));
+ rtable *t = mb_allocz(rt_table_pool, sizeof(struct rtable));
DBG("\t%s: created\n", r->name);
rt_setup(rt_table_pool, t, r);
add_tail(&routing_tables, &t->n);
@@ -2428,11 +2410,11 @@ do_feed_channel(struct channel *c, net *n, rte *e)
{
rte_update_lock();
if (c->ra_mode == RA_ACCEPTED)
- rt_notify_accepted(c, n, e, NULL, NULL, c->refeeding ? 2 : 1);
+ rt_notify_accepted(c, n, NULL, NULL, c->refeeding);
else if (c->ra_mode == RA_MERGED)
- rt_notify_merged(c, n, NULL, NULL, e, c->refeeding ? e : NULL, c->refeeding);
+ rt_notify_merged(c, n, NULL, NULL, e, e, c->refeeding);
else /* RA_BASIC */
- rt_notify_basic(c, n, e, c->refeeding ? e : NULL, c->refeeding);
+ rt_notify_basic(c, n, e, e, c->refeeding);
rte_update_unlock();
}
@@ -2468,8 +2450,6 @@ rt_feed_channel(struct channel *c)
return 0;
}
- /* FIXME: perhaps we should change feed for RA_ACCEPTED to not use 'new' */
-
if ((c->ra_mode == RA_OPTIMAL) ||
(c->ra_mode == RA_ACCEPTED) ||
(c->ra_mode == RA_MERGED))
@@ -2596,7 +2576,10 @@ rte_update_in(struct channel *c, const net_addr *n, rte *new, struct rte_src *sr
if (l->state == PLS_BLOCKED)
{
- rte_trace_in(D_FILTERS, c->proto, new, "ignored [limit]");
+ /* Required by rte_trace_in() */
+ new->net = net;
+
+ rte_trace_in(D_FILTERS, c, new, "ignored [limit]");
goto drop_update;
}
}
@@ -2737,7 +2720,7 @@ rte_update_out(struct channel *c, const net_addr *n, rte *new, rte *old0, int re
/* Find the old rte */
for (pos = &net->routes; old = *pos; pos = &old->next)
- if (old->attrs->src == src)
+ if ((c->ra_mode != RA_ANY) || (old->attrs->src == src))
{
if (new && rte_same(old, new))
{
@@ -2901,7 +2884,7 @@ rt_init_hostcache(rtable *tab)
hc->slab = sl_new(rt_table_pool, sizeof(struct hostentry));
hc->lp = lp_new(rt_table_pool, LP_GOOD_SIZE(1024));
- hc->trie = f_new_trie(hc->lp, sizeof(struct f_trie_node));
+ hc->trie = f_new_trie(hc->lp, 0);
tab->hostcache = hc;
}
@@ -2979,6 +2962,11 @@ rt_get_igp_metric(rte *rt)
}
#endif
+#ifdef CONFIG_BABEL
+ if (a->source == RTS_BABEL)
+ return rt->u.babel.metric;
+#endif
+
if (a->source == RTS_DEVICE)
return 0;
@@ -3055,7 +3043,7 @@ rt_update_hostcache(rtable *tab)
/* Reset the trie */
lp_flush(hc->lp);
- hc->trie = f_new_trie(hc->lp, sizeof(struct f_trie_node));
+ hc->trie = f_new_trie(hc->lp, 0);
WALK_LIST_DELSAFE(n, x, hc->hostentries)
{
diff --git a/proto/babel/babel.c b/proto/babel/babel.c
index 177ff3a3..4b6b9d7f 100644
--- a/proto/babel/babel.c
+++ b/proto/babel/babel.c
@@ -113,7 +113,7 @@ babel_get_source(struct babel_proto *p, struct babel_entry *e, u64 router_id)
if (s)
return s;
- s = sl_alloc(p->source_slab);
+ s = sl_allocz(p->source_slab);
s->router_id = router_id;
s->expires = current_time() + BABEL_GARBAGE_INTERVAL;
s->seqno = 0;
@@ -159,8 +159,7 @@ babel_get_route(struct babel_proto *p, struct babel_entry *e, struct babel_neigh
if (r)
return r;
- r = sl_alloc(p->route_slab);
- memset(r, 0, sizeof(*r));
+ r = sl_allocz(p->route_slab);
r->e = e;
r->neigh = nbr;
@@ -323,7 +322,7 @@ babel_add_seqno_request(struct babel_proto *p, struct babel_entry *e,
}
/* No entries found */
- sr = sl_alloc(p->seqno_slab);
+ sr = sl_allocz(p->seqno_slab);
found:
sr->router_id = router_id;
@@ -640,6 +639,14 @@ babel_announce_rte(struct babel_proto *p, struct babel_entry *e)
.nh.iface = r->neigh->ifa->iface,
};
+ /*
+ * If we cannot find a reachable neighbour, set the entry to be onlink. This
+ * makes it possible to, e.g., assign /32 addresses on a mesh interface and
+ * have routing work.
+ */
+ if (!neigh_find(&p->p, r->next_hop, r->neigh->ifa->iface, 0))
+ a0.nh.flags = RNF_ONLINK;
+
rta *a = rta_lookup(&a0);
rte *rte = rte_get_temp(a);
rte->u.babel.seqno = r->seqno;
@@ -1852,7 +1859,7 @@ babel_get_route_info(rte *rte, byte *buf)
}
static int
-babel_get_attr(eattr *a, byte *buf, int buflen UNUSED)
+babel_get_attr(const eattr *a, byte *buf, int buflen UNUSED)
{
switch (a->id)
{
@@ -1874,7 +1881,7 @@ babel_get_attr(eattr *a, byte *buf, int buflen UNUSED)
}
void
-babel_show_interfaces(struct proto *P, char *iff)
+babel_show_interfaces(struct proto *P, const char *iff)
{
struct babel_proto *p = (void *) P;
struct babel_iface *ifa = NULL;
@@ -1883,7 +1890,6 @@ babel_show_interfaces(struct proto *P, char *iff)
if (p->p.proto_state != PS_UP)
{
cli_msg(-1023, "%s: is not up", p->p.name);
- cli_msg(0, "");
return;
}
@@ -1907,12 +1913,10 @@ babel_show_interfaces(struct proto *P, char *iff)
ifa->cf->rxcost, nbrs, MAX(timer, 0),
ifa->next_hop_ip4, ifa->next_hop_ip6);
}
-
- cli_msg(0, "");
}
void
-babel_show_neighbors(struct proto *P, char *iff)
+babel_show_neighbors(struct proto *P, const char *iff)
{
struct babel_proto *p = (void *) P;
struct babel_iface *ifa = NULL;
@@ -1922,7 +1926,6 @@ babel_show_neighbors(struct proto *P, char *iff)
if (p->p.proto_state != PS_UP)
{
cli_msg(-1024, "%s: is not up", p->p.name);
- cli_msg(0, "");
return;
}
@@ -1947,8 +1950,6 @@ babel_show_neighbors(struct proto *P, char *iff)
n->addr, ifa->iface->name, n->cost, rts, hellos, MAX(timer, 0));
}
}
-
- cli_msg(0, "");
}
static void
@@ -1990,7 +1991,6 @@ babel_show_entries(struct proto *P)
if (p->p.proto_state != PS_UP)
{
cli_msg(-1025, "%s: is not up", p->p.name);
- cli_msg(0, "");
return;
}
@@ -2000,8 +2000,6 @@ babel_show_entries(struct proto *P)
babel_show_entries_(p, &p->ip4_rtable);
babel_show_entries_(p, &p->ip6_rtable);
-
- cli_msg(0, "");
}
static void
@@ -2033,7 +2031,6 @@ babel_show_routes(struct proto *P)
if (p->p.proto_state != PS_UP)
{
cli_msg(-1025, "%s: is not up", p->p.name);
- cli_msg(0, "");
return;
}
@@ -2043,8 +2040,6 @@ babel_show_routes(struct proto *P)
babel_show_routes_(p, &p->ip4_rtable);
babel_show_routes_(p, &p->ip6_rtable);
-
- cli_msg(0, "");
}
diff --git a/proto/babel/babel.h b/proto/babel/babel.h
index 14765c60..e075024c 100644
--- a/proto/babel/babel.h
+++ b/proto/babel/babel.h
@@ -368,8 +368,8 @@ void babel_handle_update(union babel_msg *msg, struct babel_iface *ifa);
void babel_handle_route_request(union babel_msg *msg, struct babel_iface *ifa);
void babel_handle_seqno_request(union babel_msg *msg, struct babel_iface *ifa);
-void babel_show_interfaces(struct proto *P, char *iff);
-void babel_show_neighbors(struct proto *P, char *iff);
+void babel_show_interfaces(struct proto *P, const char *iff);
+void babel_show_neighbors(struct proto *P, const char *iff);
void babel_show_entries(struct proto *P);
void babel_show_routes(struct proto *P);
diff --git a/proto/babel/config.Y b/proto/babel/config.Y
index b6bc70fa..2f3b637b 100644
--- a/proto/babel/config.Y
+++ b/proto/babel/config.Y
@@ -130,16 +130,16 @@ dynamic_attr: BABEL_METRIC { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_BAB
CF_CLI_HELP(SHOW BABEL, ..., [[Show information about Babel protocol]]);
CF_CLI(SHOW BABEL INTERFACES, optproto opttext, [<name>] [\"<interface>\"], [[Show information about Babel interfaces]])
-{ babel_show_interfaces(proto_get_named($4, &proto_babel), $5); };
+{ PROTO_WALK_CMD($4, &proto_babel, p) babel_show_interfaces(p, $5); };
CF_CLI(SHOW BABEL NEIGHBORS, optproto opttext, [<name>] [\"<interface>\"], [[Show information about Babel neighbors]])
-{ babel_show_neighbors(proto_get_named($4, &proto_babel), $5); };
+{ PROTO_WALK_CMD($4, &proto_babel, p) babel_show_neighbors(p, $5); };
CF_CLI(SHOW BABEL ENTRIES, optproto opttext, [<name>], [[Show information about Babel prefix entries]])
-{ babel_show_entries(proto_get_named($4, &proto_babel)); };
+{ PROTO_WALK_CMD($4, &proto_babel, p) babel_show_entries(p); };
CF_CLI(SHOW BABEL ROUTES, optproto opttext, [<name>], [[Show information about Babel route entries]])
-{ babel_show_routes(proto_get_named($4, &proto_babel)); };
+{ PROTO_WALK_CMD($4, &proto_babel, p) babel_show_routes(p); };
CF_CODE
diff --git a/proto/babel/packets.c b/proto/babel/packets.c
index d4ecf649..415ac3f9 100644
--- a/proto/babel/packets.c
+++ b/proto/babel/packets.c
@@ -1144,7 +1144,6 @@ babel_read_tlv(struct babel_tlv *hdr,
return PARSE_ERROR;
state->current_tlv_endpos = tlv_data[hdr->type].min_length;
- memset(msg, 0, sizeof(*msg));
int res = tlv_data[hdr->type].read_tlv(hdr, msg, state);
if (res != PARSE_SUCCESS)
@@ -1278,7 +1277,7 @@ babel_send_unicast(union babel_msg *msg, struct babel_iface *ifa, ip_addr dest)
struct babel_msg_node *msgn = sl_alloc(p->msg_slab);
list queue;
- msgn->msg = *msg;
+ *msgn = (struct babel_msg_node) { .msg = *msg };
init_list(&queue);
add_tail(&queue, NODE msgn);
babel_write_queue(ifa, &queue);
@@ -1305,7 +1304,8 @@ babel_enqueue(union babel_msg *msg, struct babel_iface *ifa)
{
struct babel_proto *p = ifa->proto;
struct babel_msg_node *msgn = sl_alloc(p->msg_slab);
- msgn->msg = *msg;
+
+ *msgn = (struct babel_msg_node) { .msg = *msg };
add_tail(&ifa->msg_queue, NODE msgn);
babel_kick_queue(ifa);
}
@@ -1386,7 +1386,7 @@ babel_process_packet(struct babel_pkt_header *pkt, int len,
break;
}
- msg = sl_alloc(p->msg_slab);
+ msg = sl_allocz(p->msg_slab);
res = babel_read_tlv(tlv, &msg->msg, &state);
if (res == PARSE_SUCCESS)
{
diff --git a/proto/bfd/bfd.c b/proto/bfd/bfd.c
index a3e6d01c..dac184c5 100644
--- a/proto/bfd/bfd.c
+++ b/proto/bfd/bfd.c
@@ -27,13 +27,13 @@
* related to the session and two timers (TX timer for periodic packets and hold
* timer for session timeout). These sessions are allocated from @session_slab
* and are accessible by two hash tables, @session_hash_id (by session ID) and
- * @session_hash_ip (by IP addresses of neighbors). Slab and both hashes are in
- * the main protocol structure &bfd_proto. The protocol logic related to BFD
- * sessions is implemented in internal functions bfd_session_*(), which are
- * expected to be called from the context of BFD thread, and external functions
- * bfd_add_session(), bfd_remove_session() and bfd_reconfigure_session(), which
- * form an interface to the BFD core for the rest and are expected to be called
- * from the context of main thread.
+ * @session_hash_ip (by IP addresses of neighbors and associated interfaces).
+ * Slab and both hashes are in the main protocol structure &bfd_proto. The
+ * protocol logic related to BFD sessions is implemented in internal functions
+ * bfd_session_*(), which are expected to be called from the context of BFD
+ * thread, and external functions bfd_add_session(), bfd_remove_session() and
+ * bfd_reconfigure_session(), which form an interface to the BFD core for the
+ * rest and are expected to be called from the context of main thread.
*
* Each BFD session has an associated BFD interface, represented by structure
* &bfd_iface. A BFD interface contains a socket used for TX (the one for RX is
@@ -108,10 +108,10 @@
#define HASH_ID_EQ(a,b) a == b
#define HASH_ID_FN(k) k
-#define HASH_IP_KEY(n) n->addr
+#define HASH_IP_KEY(n) n->addr, n->ifindex
#define HASH_IP_NEXT(n) n->next_ip
-#define HASH_IP_EQ(a,b) ipa_equal(a,b)
-#define HASH_IP_FN(k) ipa_hash(k)
+#define HASH_IP_EQ(a1,n1,a2,n2) ipa_equal(a1, a2) && n1 == n2
+#define HASH_IP_FN(a,n) ipa_hash(a) ^ u32_hash(n)
static list bfd_proto_list;
static list bfd_wait_list;
@@ -128,6 +128,18 @@ static inline void bfd_notify_kick(struct bfd_proto *p);
* BFD sessions
*/
+static inline struct bfd_session_config
+bfd_merge_options(const struct bfd_iface_config *cf, const struct bfd_options *opts)
+{
+ return (struct bfd_session_config) {
+ .min_rx_int = opts->min_rx_int ?: cf->min_rx_int,
+ .min_tx_int = opts->min_tx_int ?: cf->min_tx_int,
+ .idle_tx_int = opts->idle_tx_int ?: cf->idle_tx_int,
+ .multiplier = opts->multiplier ?: cf->multiplier,
+ .passive = opts->passive_set ? opts->passive : cf->passive
+ };
+}
+
static void
bfd_session_update_state(struct bfd_session *s, uint state, uint diag)
{
@@ -152,10 +164,10 @@ bfd_session_update_state(struct bfd_session *s, uint state, uint diag)
bfd_unlock_sessions(p);
if (state == BFD_STATE_UP)
- bfd_session_set_min_tx(s, s->ifa->cf->min_tx_int);
+ bfd_session_set_min_tx(s, s->cf.min_tx_int);
if (old_state == BFD_STATE_UP)
- bfd_session_set_min_tx(s, s->ifa->cf->idle_tx_int);
+ bfd_session_set_min_tx(s, s->cf.idle_tx_int);
if (notify)
bfd_notify_kick(p);
@@ -373,9 +385,9 @@ bfd_find_session_by_id(struct bfd_proto *p, u32 id)
}
struct bfd_session *
-bfd_find_session_by_addr(struct bfd_proto *p, ip_addr addr)
+bfd_find_session_by_addr(struct bfd_proto *p, ip_addr addr, uint ifindex)
{
- return HASH_FIND(p->session_hash_ip, HASH_IP, addr);
+ return HASH_FIND(p->session_hash_ip, HASH_IP, addr, ifindex);
}
static void
@@ -405,31 +417,31 @@ bfd_get_free_id(struct bfd_proto *p)
}
static struct bfd_session *
-bfd_add_session(struct bfd_proto *p, ip_addr addr, ip_addr local, struct iface *iface)
+bfd_add_session(struct bfd_proto *p, ip_addr addr, ip_addr local, struct iface *iface, struct bfd_options *opts)
{
birdloop_enter(p->loop);
struct bfd_iface *ifa = bfd_get_iface(p, local, iface);
- struct bfd_session *s = sl_alloc(p->session_slab);
- bzero(s, sizeof(struct bfd_session));
-
+ struct bfd_session *s = sl_allocz(p->session_slab);
s->addr = addr;
s->ifa = ifa;
+ s->ifindex = iface ? iface->index : 0;
s->loc_id = bfd_get_free_id(p);
HASH_INSERT(p->session_hash_id, HASH_ID, s);
HASH_INSERT(p->session_hash_ip, HASH_IP, s);
+ s->cf = bfd_merge_options(ifa->cf, opts);
/* Initialization of state variables - see RFC 5880 6.8.1 */
s->loc_state = BFD_STATE_DOWN;
s->rem_state = BFD_STATE_DOWN;
- s->des_min_tx_int = s->des_min_tx_new = ifa->cf->idle_tx_int;
- s->req_min_rx_int = s->req_min_rx_new = ifa->cf->min_rx_int;
+ s->des_min_tx_int = s->des_min_tx_new = s->cf.idle_tx_int;
+ s->req_min_rx_int = s->req_min_rx_new = s->cf.min_rx_int;
s->rem_min_rx_int = 1;
- s->detect_mult = ifa->cf->multiplier;
- s->passive = ifa->cf->passive;
+ s->detect_mult = s->cf.multiplier;
+ s->passive = s->cf.passive;
s->tx_csn = random_u32();
s->tx_timer = tm_new_init(p->tpool, bfd_tx_timer_hook, s, 0, 0);
@@ -506,15 +518,19 @@ bfd_remove_session(struct bfd_proto *p, struct bfd_session *s)
static void
bfd_reconfigure_session(struct bfd_proto *p, struct bfd_session *s)
{
+ if (EMPTY_LIST(s->request_list))
+ return;
+
birdloop_enter(p->loop);
- struct bfd_iface_config *cf = s->ifa->cf;
+ struct bfd_request *req = SKIP_BACK(struct bfd_request, n, HEAD(s->request_list));
+ s->cf = bfd_merge_options(s->ifa->cf, &req->opts);
- u32 tx = (s->loc_state == BFD_STATE_UP) ? cf->min_tx_int : cf->idle_tx_int;
+ u32 tx = (s->loc_state == BFD_STATE_UP) ? s->cf.min_tx_int : s->cf.idle_tx_int;
bfd_session_set_min_tx(s, tx);
- bfd_session_set_min_rx(s, cf->min_rx_int);
- s->detect_mult = cf->multiplier;
- s->passive = cf->passive;
+ bfd_session_set_min_rx(s, s->cf.min_rx_int);
+ s->detect_mult = s->cf.multiplier;
+ s->passive = s->cf.passive;
bfd_session_control_tx_timer(s, 0);
@@ -590,12 +606,20 @@ bfd_free_iface(struct bfd_iface *ifa)
static void
bfd_reconfigure_iface(struct bfd_proto *p, struct bfd_iface *ifa, struct bfd_config *nc)
{
- struct bfd_iface_config *nic = bfd_find_iface_config(nc, ifa->iface);
- ifa->changed = !!memcmp(nic, ifa->cf, sizeof(struct bfd_iface_config));
+ struct bfd_iface_config *new = bfd_find_iface_config(nc, ifa->iface);
+ struct bfd_iface_config *old = ifa->cf;
+
+ /* Check options that are handled in bfd_reconfigure_session() */
+ ifa->changed =
+ (new->min_rx_int != old->min_rx_int) ||
+ (new->min_tx_int != old->min_tx_int) ||
+ (new->idle_tx_int != old->idle_tx_int) ||
+ (new->multiplier != old->multiplier) ||
+ (new->passive != old->passive);
/* This should be probably changed to not access ifa->cf from the BFD thread */
birdloop_enter(p->loop);
- ifa->cf = nic;
+ ifa->cf = new;
birdloop_leave(p->loop);
}
@@ -624,14 +648,23 @@ bfd_request_notify(struct bfd_request *req, u8 state, u8 diag)
static int
bfd_add_request(struct bfd_proto *p, struct bfd_request *req)
{
+ struct bfd_config *cf = (struct bfd_config *) (p->p.cf);
+
if (p->p.vrf_set && (p->p.vrf != req->vrf))
return 0;
- struct bfd_session *s = bfd_find_session_by_addr(p, req->addr);
+ if (ipa_is_ip4(req->addr) ? !cf->accept_ipv4 : !cf->accept_ipv6)
+ return 0;
+
+ if (req->iface ? !cf->accept_direct : !cf->accept_multihop)
+ return 0;
+
+ uint ifindex = req->iface ? req->iface->index : 0;
+ struct bfd_session *s = bfd_find_session_by_addr(p, req->addr, ifindex);
u8 state, diag;
if (!s)
- s = bfd_add_session(p, req->addr, req->local, req->iface);
+ s = bfd_add_session(p, req->addr, req->local, req->iface, &req->opts);
rem_node(&req->n);
add_tail(&s->request_list, &req->n);
@@ -690,7 +723,8 @@ static struct resclass bfd_request_class;
struct bfd_request *
bfd_request_session(pool *p, ip_addr addr, ip_addr local,
struct iface *iface, struct iface *vrf,
- void (*hook)(struct bfd_request *), void *data)
+ void (*hook)(struct bfd_request *), void *data,
+ const struct bfd_options *opts)
{
struct bfd_request *req = ralloc(p, &bfd_request_class);
@@ -702,6 +736,9 @@ bfd_request_session(pool *p, ip_addr addr, ip_addr local,
req->iface = iface;
req->vrf = vrf;
+ if (opts)
+ req->opts = *opts;
+
bfd_submit_request(req);
req->hook = hook;
@@ -710,6 +747,20 @@ bfd_request_session(pool *p, ip_addr addr, ip_addr local,
return req;
}
+void
+bfd_update_request(struct bfd_request *req, const struct bfd_options *opts)
+{
+ struct bfd_session *s = req->session;
+
+ if (!memcmp(opts, &req->opts, sizeof(const struct bfd_options)))
+ return;
+
+ req->opts = *opts;
+
+ if (s)
+ bfd_reconfigure_session(s->ifa->bfd, s);
+}
+
static void
bfd_request_free(resource *r)
{
@@ -759,7 +810,7 @@ bfd_neigh_notify(struct neighbor *nb)
if ((nb->scope > 0) && !n->req)
{
ip_addr local = ipa_nonzero(n->local) ? n->local : nb->ifa->ip;
- n->req = bfd_request_session(p->p.pool, n->addr, local, nb->iface, p->p.vrf, NULL, NULL);
+ n->req = bfd_request_session(p->p.pool, n->addr, local, nb->iface, p->p.vrf, NULL, NULL, NULL);
}
if ((nb->scope <= 0) && n->req)
@@ -776,7 +827,7 @@ bfd_start_neighbor(struct bfd_proto *p, struct bfd_neighbor *n)
if (n->multihop)
{
- n->req = bfd_request_session(p->p.pool, n->addr, n->local, NULL, p->p.vrf, NULL, NULL);
+ n->req = bfd_request_session(p->p.pool, n->addr, n->local, NULL, p->p.vrf, NULL, NULL, NULL);
return;
}
@@ -986,10 +1037,19 @@ bfd_start(struct proto *P)
add_tail(&bfd_proto_list, &p->bfd_node);
birdloop_enter(p->loop);
- p->rx4_1 = bfd_open_rx_sk(p, 0, SK_IPV4);
- p->rx4_m = bfd_open_rx_sk(p, 1, SK_IPV4);
- p->rx6_1 = bfd_open_rx_sk(p, 0, SK_IPV6);
- p->rx6_m = bfd_open_rx_sk(p, 1, SK_IPV6);
+
+ if (cf->accept_ipv4 && cf->accept_direct)
+ p->rx4_1 = bfd_open_rx_sk(p, 0, SK_IPV4);
+
+ if (cf->accept_ipv4 && cf->accept_multihop)
+ p->rx4_m = bfd_open_rx_sk(p, 1, SK_IPV4);
+
+ if (cf->accept_ipv6 && cf->accept_direct)
+ p->rx6_1 = bfd_open_rx_sk(p, 0, SK_IPV6);
+
+ if (cf->accept_ipv6 && cf->accept_multihop)
+ p->rx6_m = bfd_open_rx_sk(p, 1, SK_IPV6);
+
birdloop_leave(p->loop);
bfd_take_requests(p);
@@ -1034,10 +1094,17 @@ static int
bfd_reconfigure(struct proto *P, struct proto_config *c)
{
struct bfd_proto *p = (struct bfd_proto *) P;
- // struct bfd_config *old = (struct bfd_config *) (P->cf);
+ struct bfd_config *old = (struct bfd_config *) (P->cf);
struct bfd_config *new = (struct bfd_config *) c;
struct bfd_iface *ifa;
+ /* TODO: Improve accept reconfiguration */
+ if ((new->accept_ipv4 != old->accept_ipv4) ||
+ (new->accept_ipv6 != old->accept_ipv6) ||
+ (new->accept_direct != old->accept_direct) ||
+ (new->accept_multihop != old->accept_multihop))
+ return 0;
+
birdloop_mask_wakeups(p->loop);
WALK_LIST(ifa, p->iface_list)
@@ -1080,7 +1147,6 @@ bfd_show_sessions(struct proto *P)
if (p->p.proto_state != PS_UP)
{
cli_msg(-1020, "%s: is not up", p->p.name);
- cli_msg(0, "");
return;
}
@@ -1105,8 +1171,6 @@ bfd_show_sessions(struct proto *P)
s->addr, ifname, bfd_state_names[state], tbuf, tx_int, timeout);
}
HASH_WALK_END;
-
- cli_msg(0, "");
}
diff --git a/proto/bfd/bfd.h b/proto/bfd/bfd.h
index bc4fe969..91fdaa60 100644
--- a/proto/bfd/bfd.h
+++ b/proto/bfd/bfd.h
@@ -43,6 +43,10 @@ struct bfd_config
list patt_list; /* List of iface configs (struct bfd_iface_config) */
list neigh_list; /* List of configured neighbors (struct bfd_neighbor) */
struct bfd_iface_config *multihop; /* Multihop pseudoiface config */
+ u8 accept_ipv4;
+ u8 accept_ipv6;
+ u8 accept_direct;
+ u8 accept_multihop;
};
struct bfd_iface_config
@@ -57,6 +61,15 @@ struct bfd_iface_config
list *passwords; /* Passwords for authentication */
};
+struct bfd_session_config
+{
+ u32 min_rx_int;
+ u32 min_tx_int;
+ u32 idle_tx_int;
+ u8 multiplier;
+ u8 passive;
+};
+
struct bfd_neighbor
{
node n;
@@ -126,6 +139,9 @@ struct bfd_session
u8 rem_diag;
u32 loc_id; /* Local session ID (local discriminator) */
u32 rem_id; /* Remote session ID (remote discriminator) */
+
+ struct bfd_session_config cf; /* Static configuration parameters */
+
u32 des_min_tx_int; /* Desired min rx interval, local option */
u32 des_min_tx_new; /* Used for des_min_tx_int change */
u32 req_min_rx_int; /* Required min tx interval, local option */
@@ -137,6 +153,7 @@ struct bfd_session
u8 detect_mult; /* Announced detect_mult, local option */
u8 rem_detect_mult; /* Last received detect_mult */
+ uint ifindex; /* Iface index, for hashing in bfd.session_hash_ip */
btime last_tx; /* Time of last sent periodic control packet */
btime last_rx; /* Time of last received valid control packet */
@@ -197,7 +214,7 @@ static inline void bfd_unlock_sessions(struct bfd_proto *p) { pthread_spin_unloc
/* bfd.c */
struct bfd_session * bfd_find_session_by_id(struct bfd_proto *p, u32 id);
-struct bfd_session * bfd_find_session_by_addr(struct bfd_proto *p, ip_addr addr);
+struct bfd_session * bfd_find_session_by_addr(struct bfd_proto *p, ip_addr addr, uint ifindex);
void bfd_session_process_ctl(struct bfd_session *s, u8 flags, u32 old_tx_int, u32 old_rx_int);
void bfd_show_sessions(struct proto *P);
diff --git a/proto/bfd/config.Y b/proto/bfd/config.Y
index ed416f25..df1cba42 100644
--- a/proto/bfd/config.Y
+++ b/proto/bfd/config.Y
@@ -23,7 +23,7 @@ CF_DECLS
CF_KEYWORDS(BFD, MIN, IDLE, RX, TX, INTERVAL, MULTIPLIER, PASSIVE,
INTERFACE, MULTIHOP, NEIGHBOR, DEV, LOCAL, AUTHENTICATION,
- NONE, SIMPLE, METICULOUS, KEYED, MD5, SHA1)
+ NONE, SIMPLE, METICULOUS, KEYED, MD5, SHA1, IPV4, IPV6, DIRECT)
%type <iface> bfd_neigh_iface
%type <a> bfd_neigh_local
@@ -38,10 +38,13 @@ bfd_proto_start: proto_start BFD
this_proto = proto_config_new(&proto_bfd, $1);
init_list(&BFD_CFG->patt_list);
init_list(&BFD_CFG->neigh_list);
+ BFD_CFG->accept_ipv4 = BFD_CFG->accept_ipv6 = 1;
+ BFD_CFG->accept_direct = BFD_CFG->accept_multihop = 1;
};
bfd_proto_item:
proto_item
+ | ACCEPT bfd_accept
| INTERFACE bfd_iface
| MULTIHOP bfd_multihop
| NEIGHBOR bfd_neighbor
@@ -56,6 +59,21 @@ bfd_proto:
bfd_proto_start proto_name '{' bfd_proto_opts '}';
+bfd_accept_item:
+ IPV4 { BFD_CFG->accept_ipv4 = 1; BFD_CFG->accept_ipv6 = 0; }
+ | IPV6 { BFD_CFG->accept_ipv4 = 0; BFD_CFG->accept_ipv6 = 1; }
+ | DIRECT { BFD_CFG->accept_direct = 1; BFD_CFG->accept_multihop = 0; }
+ | MULTIHOP { BFD_CFG->accept_direct = 0; BFD_CFG->accept_multihop = 1; }
+ ;
+
+bfd_accept:
+ {
+ BFD_CFG->accept_ipv4 = BFD_CFG->accept_ipv6 = 1;
+ BFD_CFG->accept_direct = BFD_CFG->accept_multihop = 1;
+ }
+ | bfd_accept bfd_accept_item
+
+
bfd_iface_start:
{
this_ipatt = cfg_allocz(sizeof(struct bfd_iface_config));
@@ -164,7 +182,7 @@ bfd_neighbor: ipa bfd_neigh_iface bfd_neigh_local bfd_neigh_multihop
CF_CLI_HELP(SHOW BFD, ..., [[Show information about BFD protocol]]);
CF_CLI(SHOW BFD SESSIONS, optproto, [<name>], [[Show information about BFD sessions]])
-{ bfd_show_sessions(proto_get_named($4, &proto_bfd)); };
+{ PROTO_WALK_CMD($4, &proto_bfd, p) bfd_show_sessions(p); };
CF_CODE
diff --git a/proto/bfd/packets.c b/proto/bfd/packets.c
index 703c6e28..7618e20f 100644
--- a/proto/bfd/packets.c
+++ b/proto/bfd/packets.c
@@ -366,7 +366,8 @@ bfd_rx_hook(sock *sk, uint len)
if (ps > BFD_STATE_DOWN)
DROP("invalid init state", ps);
- s = bfd_find_session_by_addr(p, sk->faddr);
+ uint ifindex = (sk->sport == BFD_CONTROL_PORT) ? sk->lifindex : 0;
+ s = bfd_find_session_by_addr(p, sk->faddr, ifindex);
/* FIXME: better session matching and message */
if (!s)
diff --git a/proto/bgp/attrs.c b/proto/bgp/attrs.c
index b8921363..6752cb7f 100644
--- a/proto/bgp/attrs.c
+++ b/proto/bgp/attrs.c
@@ -72,7 +72,7 @@ struct bgp_attr_desc {
void (*export)(struct bgp_export_state *s, eattr *a);
int (*encode)(struct bgp_write_state *s, eattr *a, byte *buf, uint size);
void (*decode)(struct bgp_parse_state *s, uint code, uint flags, byte *data, uint len, ea_list **to);
- void (*format)(eattr *ea, byte *buf, uint size);
+ void (*format)(const eattr *ea, byte *buf, uint size);
};
static const struct bgp_attr_desc bgp_attr_table[];
@@ -396,7 +396,7 @@ bgp_decode_origin(struct bgp_parse_state *s, uint code UNUSED, uint flags, byte
}
static void
-bgp_format_origin(eattr *a, byte *buf, uint size UNUSED)
+bgp_format_origin(const eattr *a, byte *buf, uint size UNUSED)
{
static const char *bgp_origin_names[] = { "IGP", "EGP", "Incomplete" };
@@ -404,6 +404,15 @@ bgp_format_origin(eattr *a, byte *buf, uint size UNUSED)
}
+static inline int
+bgp_as_path_first_as_equal(const byte *data, uint len, u32 asn)
+{
+ return (len >= 6) &&
+ ((data[0] == AS_PATH_SEQUENCE) || (data[0] == AS_PATH_CONFED_SEQUENCE)) &&
+ (data[1] > 0) &&
+ (get_u32(data+2) == asn);
+}
+
static int
bgp_encode_as_path(struct bgp_write_state *s, eattr *a, byte *buf, uint size)
{
@@ -426,17 +435,13 @@ bgp_decode_as_path(struct bgp_parse_state *s, uint code UNUSED, uint flags, byte
{
struct bgp_proto *p = s->proto;
int as_length = s->as4_session ? 4 : 2;
+ int as_sets = p->cf->allow_as_sets;
int as_confed = p->cf->confederation && p->is_interior;
char err[128];
- if (!as_path_valid(data, len, as_length, as_confed, err, sizeof(err)))
+ if (!as_path_valid(data, len, as_length, as_sets, as_confed, err, sizeof(err)))
WITHDRAW("Malformed AS_PATH attribute - %s", err);
- /* In some circumstances check for initial AS_CONFED_SEQUENCE; RFC 5065 5.0 */
- if (p->is_interior && !p->is_internal &&
- ((len < 2) || (data[0] != AS_PATH_CONFED_SEQUENCE)))
- WITHDRAW("Malformed AS_PATH attribute - %s", "missing initial AS_CONFED_SEQUENCE");
-
if (!s->as4_session)
{
/* Prepare 32-bit AS_PATH (from 16-bit one) in a temporary buffer */
@@ -445,6 +450,16 @@ bgp_decode_as_path(struct bgp_parse_state *s, uint code UNUSED, uint flags, byte
len = as_path_16to32(data, src, len);
}
+ /* In some circumstances check for initial AS_CONFED_SEQUENCE; RFC 5065 5.0 */
+ if (p->is_interior && !p->is_internal &&
+ ((len < 2) || (data[0] != AS_PATH_CONFED_SEQUENCE)))
+ WITHDRAW("Malformed AS_PATH attribute - %s", "missing initial AS_CONFED_SEQUENCE");
+
+ /* Reject routes with first AS in AS_PATH not matching neighbor AS; RFC 4271 6.3 */
+ if (!p->is_internal && p->cf->enforce_first_as &&
+ !bgp_as_path_first_as_equal(data, len, p->remote_as))
+ WITHDRAW("Malformed AS_PATH attribute - %s", "First AS differs from neigbor AS");
+
bgp_set_attr_data(to, s->pool, BA_AS_PATH, flags, data, len);
}
@@ -495,7 +510,7 @@ bgp_decode_next_hop(struct bgp_parse_state *s, uint code UNUSED, uint flags UNUS
/* TODO: This function should use AF-specific hook */
static void
-bgp_format_next_hop(eattr *a, byte *buf, uint size UNUSED)
+bgp_format_next_hop(const eattr *a, byte *buf, uint size UNUSED)
{
ip_addr *nh = (void *) a->u.ptr->data;
uint len = a->u.ptr->length;
@@ -562,6 +577,7 @@ bgp_encode_aggregator(struct bgp_write_state *s, eattr *a, byte *buf, uint size)
/* Prepare 16-bit AGGREGATOR (from 32-bit one) in a temporary buffer */
byte *dst = alloca(6);
len = aggregator_32to16(dst, data);
+ data = dst;
}
return bgp_put_attr(buf, size, BA_AGGREGATOR, a->flags, data, len);
@@ -585,7 +601,7 @@ bgp_decode_aggregator(struct bgp_parse_state *s, uint code UNUSED, uint flags, b
}
static void
-bgp_format_aggregator(eattr *a, byte *buf, uint size UNUSED)
+bgp_format_aggregator(const eattr *a, byte *buf, uint size UNUSED)
{
const byte *data = a->u.ptr->data;
@@ -660,13 +676,44 @@ bgp_decode_cluster_list(struct bgp_parse_state *s, uint code UNUSED, uint flags,
}
static void
-bgp_format_cluster_list(eattr *a, byte *buf, uint size)
+bgp_format_cluster_list(const eattr *a, byte *buf, uint size)
{
/* Truncates cluster lists larger than buflen, probably not a problem */
int_set_format(a->u.ptr, 0, -1, buf, size);
}
+int
+bgp_encode_mp_reach_mrt(struct bgp_write_state *s UNUSED, eattr *a, byte *buf, uint size)
+{
+ /*
+ * Limited version of MP_REACH_NLRI used for MRT table dumps (IPv6 only):
+ *
+ * 3 B MP_REACH_NLRI header
+ * 1 B MP_REACH_NLRI data - Length of Next Hop Network Address
+ * var MP_REACH_NLRI data - Network Address of Next Hop
+ */
+
+ ip_addr *nh = (void *) a->u.ptr->data;
+ uint len = a->u.ptr->length;
+
+ ASSERT((len == 16) || (len == 32));
+
+ if (size < (3+1+len))
+ return -1;
+
+ bgp_put_attr_hdr3(buf, BA_MP_REACH_NLRI, BAF_OPTIONAL, 1+len);
+ buf[3] = len;
+ buf += 4;
+
+ put_ip6(buf, ipa_to_ip6(nh[0]));
+
+ if (len == 32)
+ put_ip6(buf+16, ipa_to_ip6(nh[1]));
+
+ return 3+1+len;
+}
+
static inline u32
get_af3(byte *buf)
{
@@ -717,13 +764,23 @@ bgp_decode_mp_unreach_nlri(struct bgp_parse_state *s, uint code UNUSED, uint fla
static void
bgp_export_ext_community(struct bgp_export_state *s, eattr *a)
{
- struct adata *ad = ec_set_del_nontrans(s->pool, a->u.ptr);
+ if (!s->proto->is_interior)
+ {
+ struct adata *ad = ec_set_del_nontrans(s->pool, a->u.ptr);
- if (ad->length == 0)
- UNSET(a);
+ if (ad->length == 0)
+ UNSET(a);
- ec_set_sort_x(ad);
- a->u.ptr = ad;
+ ec_set_sort_x(ad);
+ a->u.ptr = ad;
+ }
+ else
+ {
+ if (a->u.ptr->length == 0)
+ UNSET(a);
+
+ a->u.ptr = ec_set_sort(s->pool, a->u.ptr);
+ }
}
static void
@@ -753,6 +810,9 @@ bgp_decode_as4_aggregator(struct bgp_parse_state *s, uint code UNUSED, uint flag
static void
bgp_decode_as4_path(struct bgp_parse_state *s, uint code UNUSED, uint flags, byte *data, uint len, ea_list **to)
{
+ struct bgp_proto *p = s->proto;
+ int sets = p->cf->allow_as_sets;
+
char err[128];
if (s->as4_session)
@@ -761,7 +821,7 @@ bgp_decode_as4_path(struct bgp_parse_state *s, uint code UNUSED, uint flags, byt
if (len < 6)
DISCARD(BAD_LENGTH, "AS4_PATH", len);
- if (!as_path_valid(data, len, 4, 1, err, sizeof(err)))
+ if (!as_path_valid(data, len, 4, sets, 1, err, sizeof(err)))
DISCARD("Malformed AS4_PATH attribute - %s", err);
struct adata *a = lp_alloc_adata(s->pool, len);
@@ -802,7 +862,7 @@ bgp_decode_aigp(struct bgp_parse_state *s, uint code UNUSED, uint flags, byte *d
}
static void
-bgp_format_aigp(eattr *a, byte *buf, uint size UNUSED)
+bgp_format_aigp(const eattr *a, byte *buf, uint size UNUSED)
{
const byte *b = bgp_aigp_get_tlv(a->u.ptr, BGP_AIGP_METRIC);
@@ -880,7 +940,7 @@ bgp_decode_mpls_label_stack(struct bgp_parse_state *s, uint code UNUSED, uint fl
}
static void
-bgp_format_mpls_label_stack(eattr *a, byte *buf, uint size)
+bgp_format_mpls_label_stack(const eattr *a, byte *buf, uint size)
{
u32 *labels = (u32 *) a->u.ptr->data;
uint lnum = a->u.ptr->length / 4;
@@ -1448,6 +1508,7 @@ bgp_get_bucket(struct bgp_channel *c, ea_list *new)
/* Create the bucket */
b = mb_alloc(c->pool, size);
+ *b = (struct bgp_bucket) { };
init_list(&b->prefixes);
b->hash = hash;
@@ -1572,8 +1633,7 @@ bgp_get_prefix(struct bgp_channel *c, net_addr *net, u32 path_id)
else
px = mb_alloc(c->pool, sizeof(struct bgp_prefix) + net->length);
- px->buck_node.next = NULL;
- px->buck_node.prev = NULL;
+ *px = (struct bgp_prefix) { };
px->hash = hash;
px->path_id = path_id;
net_copy(px->net, net);
@@ -2264,7 +2324,7 @@ bgp_process_as4_attrs(ea_list **attrs, struct linpool *pool)
}
int
-bgp_get_attr(eattr *a, byte *buf, int buflen)
+bgp_get_attr(const eattr *a, byte *buf, int buflen)
{
uint i = EA_ID(a->id);
const struct bgp_attr_desc *d;
diff --git a/proto/bgp/bgp.c b/proto/bgp/bgp.c
index e33d53f5..1adb930d 100644
--- a/proto/bgp/bgp.c
+++ b/proto/bgp/bgp.c
@@ -100,9 +100,10 @@
* RFC 8092 - BGP Large Communities Attribute
* RFC 8203 - BGP Administrative Shutdown Communication
* RFC 8212 - Default EBGP Route Propagation Behavior without Policies
- * draft-ietf-idr-bgp-extended-messages-27
+ * RFC 8654 - Extended Message Support for BGP
* draft-ietf-idr-ext-opt-param-07
* draft-uttaro-idr-bgp-persistence-04
+ * draft-walton-bgp-hostname-capability-02
*/
#undef LOCAL_DEBUG
@@ -134,7 +135,7 @@ static void bgp_active(struct bgp_proto *p);
static void bgp_setup_conn(struct bgp_proto *p, struct bgp_conn *conn);
static void bgp_setup_sk(struct bgp_conn *conn, sock *s);
static void bgp_send_open(struct bgp_conn *conn);
-static void bgp_update_bfd(struct bgp_proto *p, int use_bfd);
+static void bgp_update_bfd(struct bgp_proto *p, const struct bfd_options *bfd);
static int bgp_incoming_connection(sock *sk, uint dummy UNUSED);
static void bgp_listen_sock_err(sock *sk UNUSED, int err);
@@ -247,8 +248,17 @@ bgp_setup_auth(struct bgp_proto *p, int enable)
{
if (p->cf->password)
{
+ ip_addr prefix = p->cf->remote_ip;
+ int pxlen = -1;
+
+ if (p->cf->remote_range)
+ {
+ prefix = net_prefix(p->cf->remote_range);
+ pxlen = net_pxlen(p->cf->remote_range);
+ }
+
int rv = sk_set_md5_auth(p->sock->sk,
- p->cf->local_ip, p->cf->remote_ip, p->cf->iface,
+ p->cf->local_ip, prefix, pxlen, p->cf->iface,
enable ? p->cf->password : NULL, p->cf->setkey);
if (rv < 0)
@@ -545,6 +555,8 @@ bgp_conn_enter_established_state(struct bgp_conn *conn)
struct bgp_channel *c;
BGP_TRACE(D_EVENTS, "BGP session established");
+ p->last_established = current_time();
+ p->stats.fsm_established_transitions++;
/* For multi-hop BGP sessions */
if (ipa_zero(p->local_ip))
@@ -685,6 +697,7 @@ static void
bgp_conn_leave_established_state(struct bgp_proto *p)
{
BGP_TRACE(D_EVENTS, "BGP session closed");
+ p->last_established = current_time();
p->conn = NULL;
if (p->p.proto_state == PS_UP)
@@ -1345,7 +1358,7 @@ bgp_bfd_notify(struct bfd_request *req)
BGP_TRACE(D_EVENTS, "BFD session down");
bgp_store_error(p, NULL, BE_MISC, BEM_BFD_DOWN);
- if (p->cf->bfd == BGP_BFD_GRACEFUL)
+ if (req->opts.mode == BGP_BFD_GRACEFUL)
{
/* Trigger graceful restart */
if (p->conn && (p->conn->state == BS_ESTABLISHED) && p->gr_ready)
@@ -1368,14 +1381,17 @@ bgp_bfd_notify(struct bfd_request *req)
}
static void
-bgp_update_bfd(struct bgp_proto *p, int use_bfd)
+bgp_update_bfd(struct bgp_proto *p, const struct bfd_options *bfd)
{
- if (use_bfd && !p->bfd_req && !bgp_is_dynamic(p))
+ if (bfd && p->bfd_req)
+ bfd_update_request(p->bfd_req, bfd);
+
+ if (bfd && !p->bfd_req && !bgp_is_dynamic(p))
p->bfd_req = bfd_request_session(p->p.pool, p->remote_ip, p->local_ip,
p->cf->multihop ? NULL : p->neigh->iface,
- p->p.vrf, bgp_bfd_notify, p);
+ p->p.vrf, bgp_bfd_notify, p, bfd);
- if (!use_bfd && p->bfd_req)
+ if (!bfd && p->bfd_req)
{
rfree(p->bfd_req);
p->bfd_req = NULL;
@@ -1520,6 +1536,12 @@ bgp_start(struct proto *P)
p->gr_ready = 0;
p->gr_active_num = 0;
+ /* Reset some stats */
+ p->stats.rx_messages = p->stats.tx_messages = 0;
+ p->stats.rx_updates = p->stats.tx_updates = 0;
+ p->stats.rx_bytes = p->stats.tx_bytes = 0;
+ p->last_rx_update = 0;
+
p->event = ev_new_init(p->p.pool, bgp_decision, p);
p->startup_timer = tm_new_init(p->p.pool, bgp_startup_timeout, p, 0, 0);
p->gr_timer = tm_new_init(p->p.pool, bgp_graceful_restart_timeout, p, 0, 0);
@@ -1936,6 +1958,9 @@ bgp_postconfig(struct proto_config *CF)
if (!cf->gr_mode && cf->llgr_mode)
cf_error("Long-lived graceful restart requires basic graceful restart");
+ if (internal && cf->enforce_first_as)
+ cf_error("Enforce first AS check is requires EBGP sessions");
+
struct bgp_channel_config *cc;
WALK_LIST(cc, CF->channels)
@@ -1962,10 +1987,6 @@ bgp_postconfig(struct proto_config *CF)
if (cc->next_hop_keep == 0xff)
cc->next_hop_keep = cf->rr_client ? NH_IBGP : (cf->rs_client ? NH_ALL : NH_NO);
- /* Different default based on rs_client */
- if (!cc->missing_lladdr)
- cc->missing_lladdr = cf->rs_client ? MLL_IGNORE : MLL_SELF;
-
/* Different default for gw_mode */
if (!cc->gw_mode)
cc->gw_mode = cf->multihop ? GW_RECURSIVE : GW_DIRECT;
@@ -2107,7 +2128,6 @@ bgp_channel_reconfigure(struct channel *C, struct channel_config *CC, int *impor
if (!ipa_equal(new->next_hop_addr, old->next_hop_addr) ||
(new->next_hop_self != old->next_hop_self) ||
(new->next_hop_keep != old->next_hop_keep) ||
- (new->missing_lladdr != old->missing_lladdr) ||
(new->aigp != old->aigp) ||
(new->aigp_originate != old->aigp_originate))
*export_changed = 1;
@@ -2117,9 +2137,18 @@ bgp_channel_reconfigure(struct channel *C, struct channel_config *CC, int *impor
}
static void
-bgp_copy_config(struct proto_config *dest UNUSED, struct proto_config *src UNUSED)
+bgp_copy_config(struct proto_config *dest, struct proto_config *src)
{
- /* Just a shallow copy */
+ struct bgp_config *d = (void *) dest;
+ struct bgp_config *s = (void *) src;
+
+ /* Copy BFD options */
+ if (s->bfd)
+ {
+ struct bfd_options *opts = cfg_alloc(sizeof(struct bfd_options));
+ memcpy(opts, s->bfd, sizeof(struct bfd_options));
+ d->bfd = opts;
+ }
}
@@ -2387,6 +2416,9 @@ bgp_show_capabilities(struct bgp_proto *p UNUSED, struct bgp_caps *caps)
bgp_show_afis(-1006, " AF supported:", afl1, afn1);
bgp_show_afis(-1006, " AF preserved:", afl2, afn2);
}
+
+ if (caps->hostname)
+ cli_msg(-1006, " Hostname: %s", caps->hostname);
}
static void
@@ -2445,6 +2477,18 @@ bgp_show_proto_info(struct proto *P)
tm_remains(p->conn->keepalive_timer), p->conn->keepalive_time);
}
+#if 0
+ struct bgp_stats *s = &p->stats;
+ cli_msg(-1006, " FSM established transitions: %u",
+ s->fsm_established_transitions);
+ cli_msg(-1006, " Rcvd messages: %u total / %u updates / %lu bytes",
+ s->rx_messages, s->rx_updates, s->rx_bytes);
+ cli_msg(-1006, " Sent messages: %u total / %u updates / %lu bytes",
+ s->tx_messages, s->tx_updates, s->tx_bytes);
+ cli_msg(-1006, " Last rcvd update elapsed time: %t s",
+ p->last_rx_update ? (current_time() - p->last_rx_update) : 0);
+#endif
+
if ((p->last_error_class != BE_NONE) &&
(p->last_error_class != BE_MAN_DOWN))
{
diff --git a/proto/bgp/bgp.h b/proto/bgp/bgp.h
index d3e8f2ff..cca4b448 100644
--- a/proto/bgp/bgp.h
+++ b/proto/bgp/bgp.h
@@ -98,6 +98,7 @@ struct bgp_config {
int enable_refresh; /* Enable local support for route refresh [RFC 2918] */
int enable_as4; /* Enable local support for 4B AS numbers [RFC 6793] */
int enable_extended_messages; /* Enable local support for extended messages [draft] */
+ int enable_hostname; /* Enable local support for hostname [draft] */
u32 rr_cluster_id; /* Route reflector cluster ID, if different from local ID */
int rr_client; /* Whether neighbor is RR client of me */
int rs_client; /* Whether neighbor is RS client of me */
@@ -107,6 +108,8 @@ struct bgp_config {
int interpret_communities; /* Hardwired handling of well-known communities */
int allow_local_as; /* Allow that number of local ASNs in incoming AS_PATHs */
int allow_local_pref; /* Allow LOCAL_PREF in EBGP sessions */
+ int allow_as_sets; /* Allow AS_SETs in incoming AS_PATHs */
+ int enforce_first_as; /* Enable check for neighbor AS as first AS in AS_PATH */
int gr_mode; /* Graceful restart mode (BGP_GR_*) */
int llgr_mode; /* Long-lived graceful restart mode (BGP_LLGR_*) */
int setkey; /* Set MD5 password to system SA/SP database */
@@ -123,12 +126,12 @@ struct bgp_config {
unsigned disable_after_error; /* Disable the protocol when error is detected */
u32 disable_after_cease; /* Disable it when cease is received, bitfield */
- char *password; /* Password used for MD5 authentication */
+ const char *password; /* Password used for MD5 authentication */
net_addr *remote_range; /* Allowed neighbor range for dynamic BGP */
- char *dynamic_name; /* Name pattern for dynamic BGP */
+ const char *dynamic_name; /* Name pattern for dynamic BGP */
int dynamic_name_digits; /* Minimum number of digits for dynamic names */
int check_link; /* Use iface link state for liveness detection */
- int bfd; /* Use BFD for liveness detection */
+ struct bfd_options *bfd; /* Use BFD for liveness detection */
};
struct bgp_channel_config {
@@ -141,7 +144,6 @@ struct bgp_channel_config {
u8 next_hop_self; /* Always set next hop to local IP address (NH_*) */
u8 next_hop_keep; /* Do not modify next hop attribute (NH_*) */
u8 mandatory; /* Channel is mandatory in capability negotiation */
- u8 missing_lladdr; /* What we will do when we don' know link-local addr, see MLL_* */
u8 gw_mode; /* How we compute route gateway from next_hop attr, see GW_* */
u8 secondary; /* Accept also non-best routes (i.e. RA_ACCEPTED) */
u8 gr_able; /* Allow full graceful restart for the channel */
@@ -227,6 +229,8 @@ struct bgp_caps {
u8 any_ext_next_hop; /* Bitwise OR of per-AF ext_next_hop */
u8 any_add_path; /* Bitwise OR of per-AF add_path */
+ const char *hostname; /* Hostname, RFC draft */
+
u16 af_count; /* Number of af_data items */
u16 length; /* Length of capabilities in OPEN msg */
@@ -243,6 +247,14 @@ struct bgp_socket {
u32 uc; /* Use count */
};
+struct bgp_stats {
+ uint rx_messages, tx_messages;
+ uint rx_updates, tx_updates;
+ u64 rx_bytes, tx_bytes;
+
+ uint fsm_established_transitions;
+};
+
struct bgp_conn {
struct bgp_proto *bgp;
struct birdsock *sk;
@@ -301,6 +313,9 @@ struct bgp_proto {
struct bgp_socket *sock; /* Shared listening socket */
struct bfd_request *bfd_req; /* BFD request, if BFD is used */
struct birdsock *postponed_sk; /* Postponed incoming socket for dynamic BGP */
+ struct bgp_stats stats; /* BGP statistics */
+ btime last_established; /* Last time of enter/leave of established state */
+ btime last_rx_update; /* Last time of RX update */
ip_addr link_addr; /* Link-local version of local_ip */
event *event; /* Event for respawning and shutting process */
timer *startup_timer; /* Timer used to delay protocol startup due to previous errors (startup_delay) */
@@ -539,7 +554,7 @@ static inline void
bgp_set_attr_data(ea_list **to, struct linpool *pool, uint code, uint flags, void *data, uint len)
{
struct adata *a = lp_alloc_adata(pool, len);
- memcpy(a->data, data, len);
+ bmemcpy(a->data, data, len);
bgp_set_attr(to, pool, code, flags, (uintptr_t) a);
}
@@ -547,6 +562,7 @@ static inline void
bgp_unset_attr(ea_list **to, struct linpool *pool, uint code)
{ eattr *e = bgp_set_attr(to, pool, code, 0, 0); e->type = EAF_TYPE_UNDEF; }
+int bgp_encode_mp_reach_mrt(struct bgp_write_state *s, eattr *a, byte *buf, uint size);
int bgp_encode_attrs(struct bgp_write_state *s, ea_list *attrs, byte *buf, byte *end);
ea_list * bgp_decode_attrs(struct bgp_parse_state *s, byte *data, uint len);
@@ -568,7 +584,7 @@ int bgp_rte_recalculate(rtable *table, net *net, rte *new, rte *old, rte *old_be
struct rte *bgp_rte_modify_stale(struct rte *r, struct linpool *pool);
void bgp_rt_notify(struct proto *P, struct channel *C, net *n, rte *new, rte *old);
int bgp_preexport(struct proto *, struct rte **, struct linpool *);
-int bgp_get_attr(struct eattr *e, byte *buf, int buflen);
+int bgp_get_attr(const struct eattr *e, byte *buf, int buflen);
void bgp_get_route_info(struct rte *, byte *buf);
int bgp_total_aigp_metric_(rte *e, u64 *metric, const struct adata **ad);
diff --git a/proto/bgp/config.Y b/proto/bgp/config.Y
index 692854cf..2dfbdca9 100644
--- a/proto/bgp/config.Y
+++ b/proto/bgp/config.Y
@@ -29,8 +29,9 @@ CF_KEYWORDS(BGP, LOCAL, NEIGHBOR, AS, HOLD, TIME, CONNECT, RETRY, KEEPALIVE,
SECURITY, DETERMINISTIC, SECONDARY, ALLOW, BFD, ADD, PATHS, RX, TX,
GRACEFUL, RESTART, AWARE, CHECK, LINK, PORT, EXTENDED, MESSAGES, SETKEY,
STRICT, BIND, CONFEDERATION, MEMBER, MULTICAST, FLOW4, FLOW6, LONG,
- LIVED, STALE, IMPORT, IBGP, EBGP, MANDATORY, INTERNAL, EXTERNAL,
- DYNAMIC, RANGE, NAME, DIGITS, BGP_AIGP, AIGP, ORIGINATE, COST)
+ LIVED, STALE, IMPORT, IBGP, EBGP, MANDATORY, INTERNAL, EXTERNAL, SETS,
+ DYNAMIC, RANGE, NAME, DIGITS, BGP_AIGP, AIGP, ORIGINATE, COST, ENFORCE,
+ FIRST)
%type <i> bgp_nh
%type <i32> bgp_afi
@@ -61,8 +62,10 @@ bgp_proto_start: proto_start BGP {
BGP_CFG->error_delay_time_max = 300;
BGP_CFG->enable_refresh = 1;
BGP_CFG->enable_as4 = 1;
+ BGP_CFG->enable_hostname = 0;
BGP_CFG->capabilities = 2;
BGP_CFG->interpret_communities = 1;
+ BGP_CFG->allow_as_sets = 1;
BGP_CFG->default_local_pref = 100;
BGP_CFG->gr_mode = BGP_GR_AWARE;
BGP_CFG->gr_time = 120;
@@ -171,6 +174,7 @@ bgp_proto:
| bgp_proto ENABLE ROUTE REFRESH bool ';' { BGP_CFG->enable_refresh = $5; }
| bgp_proto ENABLE AS4 bool ';' { BGP_CFG->enable_as4 = $4; }
| bgp_proto ENABLE EXTENDED MESSAGES bool ';' { BGP_CFG->enable_extended_messages = $5; }
+ | bgp_proto ADVERTISE HOSTNAME bool ';' { BGP_CFG->enable_hostname = $4; }
| bgp_proto CAPABILITIES bool ';' { BGP_CFG->capabilities = $3; }
| bgp_proto PASSWORD text ';' { BGP_CFG->password = $3; }
| bgp_proto SETKEY bool ';' { BGP_CFG->setkey = $3; }
@@ -179,6 +183,7 @@ bgp_proto:
| bgp_proto ALLOW LOCAL AS ';' { BGP_CFG->allow_local_as = -1; }
| bgp_proto ALLOW LOCAL AS expr ';' { BGP_CFG->allow_local_as = $5; }
| bgp_proto ALLOW BGP_LOCAL_PREF bool ';' { BGP_CFG->allow_local_pref = $4; }
+ | bgp_proto ALLOW AS SETS bool ';' { BGP_CFG->allow_as_sets = $5; }
| bgp_proto GRACEFUL RESTART bool ';' { BGP_CFG->gr_mode = $4; }
| bgp_proto GRACEFUL RESTART AWARE ';' { BGP_CFG->gr_mode = BGP_GR_AWARE; }
| bgp_proto GRACEFUL RESTART TIME expr ';' { BGP_CFG->gr_time = $5; }
@@ -187,8 +192,10 @@ bgp_proto:
| bgp_proto LONG LIVED STALE TIME expr ';' { BGP_CFG->llgr_time = $6; }
| bgp_proto TTL SECURITY bool ';' { BGP_CFG->ttl_security = $4; }
| bgp_proto CHECK LINK bool ';' { BGP_CFG->check_link = $4; }
- | bgp_proto BFD bool ';' { BGP_CFG->bfd = $3; cf_check_bfd($3); }
- | bgp_proto BFD GRACEFUL ';' { BGP_CFG->bfd = BGP_BFD_GRACEFUL; cf_check_bfd(1); }
+ | bgp_proto BFD bool ';' { if ($3) init_bfd_opts(&BGP_CFG->bfd); else BGP_CFG->bfd = NULL; }
+ | bgp_proto BFD GRACEFUL ';' { init_bfd_opts(&BGP_CFG->bfd); BGP_CFG->bfd->mode = BGP_BFD_GRACEFUL; }
+ | bgp_proto BFD { open_bfd_opts(&BGP_CFG->bfd); } bfd_opts { close_bfd_opts(); } ';'
+ | bgp_proto ENFORCE FIRST AS bool ';' { BGP_CFG->enforce_first_as = $5; }
;
bgp_afi:
@@ -236,15 +243,15 @@ bgp_nh:
| IBGP { $$ = NH_IBGP; }
| EBGP { $$ = NH_EBGP; }
+bgp_lladdr: SELF | DROP | IGNORE;
+
bgp_channel_item:
channel_item
| NEXT HOP ADDRESS ipa { BGP_CC->next_hop_addr = $4; }
| NEXT HOP SELF bgp_nh { BGP_CC->next_hop_self = $4; }
| NEXT HOP KEEP bgp_nh { BGP_CC->next_hop_keep = $4; }
| MANDATORY bool { BGP_CC->mandatory = $2; }
- | MISSING LLADDR SELF { BGP_CC->missing_lladdr = MLL_SELF; }
- | MISSING LLADDR DROP { BGP_CC->missing_lladdr = MLL_DROP; }
- | MISSING LLADDR IGNORE { BGP_CC->missing_lladdr = MLL_IGNORE; }
+ | MISSING LLADDR bgp_lladdr { log(L_WARN "%s.%s: Missing lladdr option is deprecated and ignored, remove it", this_proto->name, this_channel->name); }
| GATEWAY DIRECT { BGP_CC->gw_mode = GW_DIRECT; }
| GATEWAY RECURSIVE { BGP_CC->gw_mode = GW_RECURSIVE; }
| SECONDARY bool { BGP_CC->secondary = $2; }
diff --git a/proto/bgp/packets.c b/proto/bgp/packets.c
index c3bd600a..b16ee242 100644
--- a/proto/bgp/packets.c
+++ b/proto/bgp/packets.c
@@ -252,6 +252,14 @@ bgp_prepare_capabilities(struct bgp_conn *conn)
if (p->cf->llgr_mode)
caps->llgr_aware = 1;
+ if (p->cf->enable_hostname && config->hostname)
+ {
+ size_t length = strlen(config->hostname);
+ char *hostname = mb_allocz(p->p.pool, length+1);
+ memcpy(hostname, config->hostname, length+1);
+ caps->hostname = hostname;
+ }
+
/* Allocate and fill per-AF fields */
WALK_LIST(c, p->p.channels)
{
@@ -412,6 +420,24 @@ bgp_write_capabilities(struct bgp_conn *conn, byte *buf)
data[-1] = buf - data;
}
+ if (caps->hostname)
+ {
+ *buf++ = 73; /* Capability 73: Hostname */
+ *buf++ = 0; /* Capability data length */
+ data = buf;
+
+ /* Hostname */
+ size_t length = strlen(caps->hostname);
+ *buf++ = length;
+ memcpy(buf, caps->hostname, length);
+ buf += length;
+
+ /* Domain, not implemented */
+ *buf++ = 0;
+
+ data[-1] = buf - data;
+ }
+
caps->length = buf - buf_head;
return buf;
@@ -573,6 +599,21 @@ bgp_read_capabilities(struct bgp_conn *conn, byte *pos, int len)
}
break;
+ case 73: /* Hostname, RFC draft */
+ if ((cl < 2) || (cl < 2 + pos[2]))
+ goto err;
+
+ int length = pos[2];
+ char *hostname = mb_allocz(p->p.pool, length+1);
+ memcpy(hostname, pos + 3, length);
+ hostname[length] = 0;
+
+ for (i = 0; i < length; i++)
+ if (hostname[i] < ' ')
+ hostname[i] = ' ';
+
+ caps->hostname = hostname;
+
/* We can safely ignore all other capabilities */
}
@@ -1157,7 +1198,10 @@ bgp_decode_next_hop_ip(struct bgp_parse_state *s, byte *data, uint len, rta *a)
nh[0] = ipa_from_ip6(get_ip6(data));
nh[1] = ipa_from_ip6(get_ip6(data+16));
- if (ipa_is_ip4(nh[0]) || !ip6_is_link_local(nh[1]))
+ if (ipa_is_link_local(nh[0]))
+ { nh[1] = nh[0]; nh[0] = IPA_NONE; }
+
+ if (ipa_is_ip4(nh[0]) || !ipa_is_link_local(nh[1]))
nh[1] = IPA_NONE;
}
else
@@ -1824,19 +1868,15 @@ bgp_decode_nlri_flow4(struct bgp_parse_state *s, byte *pos, uint len, rta *a)
bgp_parse_error(s, 1);
}
- if (data[0] != FLOW_TYPE_DST_PREFIX)
- {
- log(L_REMOTE "%s: No dst prefix at first pos", s->proto->p.name);
- bgp_parse_error(s, 1);
- }
-
- /* Decode dst prefix */
ip4_addr px = IP4_NONE;
- uint pxlen = data[1];
+ uint pxlen = 0;
- // FIXME: Use some generic function
- memcpy(&px, data+2, BYTES(pxlen));
- px = ip4_and(ip4_ntoh(px), ip4_mkmask(pxlen));
+ /* Decode dst prefix */
+ if (data[0] == FLOW_TYPE_DST_PREFIX)
+ {
+ px = flow_read_ip4_part(data);
+ pxlen = flow_read_pxlen(data);
+ }
/* Prepare the flow */
net_addr *n = alloca(sizeof(struct net_addr_flow4) + flen);
@@ -1916,19 +1956,15 @@ bgp_decode_nlri_flow6(struct bgp_parse_state *s, byte *pos, uint len, rta *a)
bgp_parse_error(s, 1);
}
- if (data[0] != FLOW_TYPE_DST_PREFIX)
- {
- log(L_REMOTE "%s: No dst prefix at first pos", s->proto->p.name);
- bgp_parse_error(s, 1);
- }
-
- /* Decode dst prefix */
ip6_addr px = IP6_NONE;
- uint pxlen = data[1];
+ uint pxlen = 0;
- // FIXME: Use some generic function
- memcpy(&px, data+2, BYTES(pxlen));
- px = ip6_and(ip6_ntoh(px), ip6_mkmask(pxlen));
+ /* Decode dst prefix */
+ if (data[0] == FLOW_TYPE_DST_PREFIX)
+ {
+ px = flow_read_ip6_part(data);
+ pxlen = flow_read_pxlen(data);
+ }
/* Prepare the flow */
net_addr *n = alloca(sizeof(struct net_addr_flow6) + flen);
@@ -2308,6 +2344,7 @@ again: ;
done:
BGP_TRACE_RL(&rl_snd_update, D_PACKETS, "Sending UPDATE");
+ p->stats.tx_updates++;
lp_flush(s.pool);
return res;
@@ -2343,6 +2380,7 @@ bgp_create_end_mark(struct bgp_channel *c, byte *buf)
struct bgp_proto *p = (void *) c->c.proto;
BGP_TRACE(D_PACKETS, "Sending END-OF-RIB");
+ p->stats.tx_updates++;
return (c->afi == BGP_AF_IPV4) ?
bgp_create_ip_end_mark(c, buf):
@@ -2423,6 +2461,8 @@ bgp_rx_update(struct bgp_conn *conn, byte *pkt, uint len)
ea_list *ea = NULL;
BGP_TRACE_RL(&rl_rcv_update, D_PACKETS, "Got UPDATE");
+ p->last_rx_update = current_time();
+ p->stats.rx_updates++;
/* Workaround for some BGP implementations that skip initial KEEPALIVE */
if (conn->state == BS_OPENCONFIRM)
@@ -2710,6 +2750,9 @@ bgp_send(struct bgp_conn *conn, uint type, uint len)
sock *sk = conn->sk;
byte *buf = sk->tbuf;
+ conn->bgp->stats.tx_messages++;
+ conn->bgp->stats.tx_bytes += len;
+
memset(buf, 0xff, 16); /* Marker */
put_u16(buf+16, len);
buf[18] = type;
@@ -3083,6 +3126,8 @@ bgp_rx_packet(struct bgp_conn *conn, byte *pkt, uint len)
byte type = pkt[18];
DBG("BGP: Got packet %02x (%d bytes)\n", type, len);
+ conn->bgp->stats.rx_messages++;
+ conn->bgp->stats.rx_bytes += len;
if (conn->bgp->p.mrtdump & MD_MESSAGES)
bgp_dump_message(conn, pkt, len);
diff --git a/proto/mrt/mrt.c b/proto/mrt/mrt.c
index 7a396a84..838360c2 100644
--- a/proto/mrt/mrt.c
+++ b/proto/mrt/mrt.c
@@ -244,7 +244,6 @@ mrt_next_table(struct mrt_table_dump_state *s)
s->table = tab;
s->ipv4 = tab ? (tab->addr_type == NET_IP4) : 0;
- s->bws->mp_reach = !s->ipv4;
if (s->table)
rt_lock_table(s->table);
@@ -417,6 +416,51 @@ mrt_rib_table_header(struct mrt_table_dump_state *s, net_addr *n)
mrt_put_u16(b, 0);
}
+#ifdef CONFIG_BGP
+static void
+mrt_rib_table_entry_bgp_attrs(struct mrt_table_dump_state *s, rte *r)
+{
+ struct ea_list *eattrs = r->attrs->eattrs;
+ buffer *b = &s->buf;
+
+ if (!eattrs)
+ return;
+
+ /* Attribute list must be normalized for bgp_encode_attrs() */
+ if (!rta_is_cached(r->attrs))
+ ea_normalize(eattrs);
+
+ mrt_buffer_need(b, MRT_ATTR_BUFFER_SIZE);
+ byte *pos = b->pos;
+
+ s->bws->mp_reach = !s->ipv4;
+ s->bws->mp_next_hop = NULL;
+
+ /* Encode BGP attributes */
+ int len = bgp_encode_attrs(s->bws, eattrs, pos, b->end);
+ if (len < 0)
+ goto fail;
+ pos += len;
+
+ /* Encode IPv6 next hop separately as fake MP_REACH_NLRI attribute */
+ if (s->bws->mp_next_hop)
+ {
+ len = bgp_encode_mp_reach_mrt(s->bws, s->bws->mp_next_hop, pos, b->end - pos);
+ if (len < 0)
+ goto fail;
+ pos += len;
+ }
+
+ /* Update attribute length and advance buffer pos */
+ put_u16(b->pos - 2, pos - b->pos);
+ b->pos = pos;
+ return;
+
+fail:
+ mrt_log(s, "Attribute list too long for %N", r->net->n.addr);
+}
+#endif
+
static void
mrt_rib_table_entry(struct mrt_table_dump_state *s, rte *r)
{
@@ -447,25 +491,7 @@ mrt_rib_table_entry(struct mrt_table_dump_state *s, rte *r)
mrt_put_u16(b, 0);
#ifdef CONFIG_BGP
- if (r->attrs->eattrs)
- {
- struct ea_list *eattrs = r->attrs->eattrs;
-
- if (!rta_is_cached(r->attrs))
- ea_normalize(eattrs);
-
- mrt_buffer_need(b, MRT_ATTR_BUFFER_SIZE);
- int alen = bgp_encode_attrs(s->bws, eattrs, b->pos, b->end);
-
- if (alen < 0)
- {
- mrt_log(s, "Attribute list too long for %N", r->net->n.addr);
- alen = 0;
- }
-
- put_u16(b->pos - 2, alen);
- b->pos += alen;
- }
+ mrt_rib_table_entry_bgp_attrs(s, r);
#endif
s->entry_count++;
diff --git a/proto/mrt/mrt.h b/proto/mrt/mrt.h
index 4dfb1b19..4ff94c12 100644
--- a/proto/mrt/mrt.h
+++ b/proto/mrt/mrt.h
@@ -42,7 +42,7 @@ struct mrt_dump_data {
const char *table_expr;
struct rtable *table_ptr;
const struct filter *filter;
- char *filename;
+ const char *filename;
};
struct mrt_peer_entry {
diff --git a/proto/ospf/config.Y b/proto/ospf/config.Y
index f631a649..fd2cfe8a 100644
--- a/proto/ospf/config.Y
+++ b/proto/ospf/config.Y
@@ -199,7 +199,7 @@ CF_KEYWORDS(ELIGIBLE, POLL, NETWORKS, HIDDEN, VIRTUAL, CHECK, LINK, ONLY, BFD)
CF_KEYWORDS(RX, BUFFER, LARGE, NORMAL, STUBNET, HIDDEN, SUMMARY, TAG, EXTERNAL)
CF_KEYWORDS(WAIT, DELAY, LSADB, ECMP, LIMIT, WEIGHT, NSSA, TRANSLATOR, STABILITY)
CF_KEYWORDS(GLOBAL, LSID, ROUTER, SELF, INSTANCE, REAL, NETMASK, TX, PRIORITY, LENGTH)
-CF_KEYWORDS(MERGE, LSA, SUPPRESSION, MULTICAST, RFC5838, VPN, PE)
+CF_KEYWORDS(MERGE, LSA, SUPPRESSION, MULTICAST, RFC5838, VPN, PE, ADDRESS)
CF_KEYWORDS(GRACEFUL, RESTART, AWARE, TIME)
%type <ld> lsadb_args
@@ -396,6 +396,7 @@ ospf_iface_item:
| TYPE PTMP { OSPF_PATT->type = OSPF_IT_PTMP ; }
| REAL BROADCAST bool { OSPF_PATT->real_bcast = $3; if (!ospf_cfg_is_v2()) cf_error("Real broadcast option requires OSPFv2"); }
| PTP NETMASK bool { OSPF_PATT->ptp_netmask = $3; if (!ospf_cfg_is_v2()) cf_error("PtP netmask option requires OSPFv2"); }
+ | PTP ADDRESS bool { OSPF_PATT->ptp_address = $3; if (!ospf_cfg_is_v2()) cf_error("PtP address option requires OSPFv2"); }
| TRANSMIT DELAY expr { OSPF_PATT->inftransdelay = $3 ; if (($3<=0) || ($3>65535)) cf_error("Transmit delay must be in range 1-65535"); }
| PRIORITY expr { OSPF_PATT->priority = $2 ; if ($2>255) cf_error("Priority must be in range 0-255"); }
| STRICT NONBROADCAST bool { OSPF_PATT->strictnbma = $3 ; }
@@ -475,6 +476,7 @@ ospf_iface_start:
init_list(&OSPF_PATT->nbma_list);
OSPF_PATT->check_link = 1;
OSPF_PATT->ptp_netmask = 2; /* not specified */
+ OSPF_PATT->ptp_address = 2; /* not specified */
OSPF_PATT->tx_tos = IP_PREC_INTERNET_CONTROL;
OSPF_PATT->tx_priority = sk_priority_control;
reset_passwords();
@@ -511,13 +513,13 @@ dynamic_attr: OSPF_ROUTER_ID { $$ = f_new_dynamic_attr(EAF_TYPE_ROUTER_ID, T_QUA
CF_CLI_HELP(SHOW OSPF, ..., [[Show information about OSPF protocol]]);
CF_CLI(SHOW OSPF, optproto, [<name>], [[Show information about OSPF protocol]])
-{ ospf_sh(proto_get_named($3, &proto_ospf)); };
+{ PROTO_WALK_CMD($3, &proto_ospf, p) ospf_sh(p); };
CF_CLI(SHOW OSPF NEIGHBORS, optproto opttext, [<name>] [\"<interface>\"], [[Show information about OSPF neighbors]])
-{ ospf_sh_neigh(proto_get_named($4, &proto_ospf), $5); };
+{ PROTO_WALK_CMD($4, &proto_ospf, p) ospf_sh_neigh(p, $5); };
CF_CLI(SHOW OSPF INTERFACE, optproto opttext, [<name>] [\"<interface>\"], [[Show information about interface]])
-{ ospf_sh_iface(proto_get_named($4, &proto_ospf), $5); };
+{ PROTO_WALK_CMD($4, &proto_ospf, p) ospf_sh_iface(p, $5); };
CF_CLI_HELP(SHOW OSPF TOPOLOGY, [all] [<name>], [[Show information about OSPF network topology]])
diff --git a/proto/ospf/hello.c b/proto/ospf/hello.c
index d094f934..1c987e54 100644
--- a/proto/ospf/hello.c
+++ b/proto/ospf/hello.c
@@ -294,6 +294,14 @@ ospf_receive_hello(struct ospf_packet *pkt, struct ospf_iface *ifa,
n->ip = faddr;
}
}
+
+ /* Update RFC 7166 authentication trailer flag */
+ if (ospf_is_v3(p) && ((rcv_options ^ n->options) & OPT_AT))
+ {
+ OSPF_TRACE(D_EVENTS, "Neighbor %R on %s %s authentication",
+ n->rid, ifa->ifname, (rcv_options & OPT_AT) ? "enabled" : "disabled");
+ n->options = (n->options & ~OPT_AT) | (rcv_options & OPT_AT);
+ }
}
if (!n)
@@ -326,6 +334,9 @@ ospf_receive_hello(struct ospf_packet *pkt, struct ospf_iface *ifa,
n->priority = rcv_priority;
n->iface_id = rcv_iface_id;
+ if (ospf_is_v3(p))
+ n->options = rcv_options & OPT_AT;
+
if (n->ifa->cf->bfd)
ospf_neigh_update_bfd(n, n->ifa->bfd);
}
diff --git a/proto/ospf/iface.c b/proto/ospf/iface.c
index 6e7e498f..666140b5 100644
--- a/proto/ospf/iface.c
+++ b/proto/ospf/iface.c
@@ -586,8 +586,6 @@ ospf_iface_new(struct ospf_area *oa, struct ifa *addr, struct ospf_iface_patt *i
ifa->deadint = ip->deadint;
ifa->stub = ospf_iface_stubby(ip, addr);
ifa->ioprob = OSPF_I_OK;
- ifa->tx_length = ifa_tx_length(ifa);
- ifa->tx_hdrlen = ifa_tx_hdrlen(ifa);
ifa->check_link = ip->check_link;
ifa->ecmp_weight = ip->ecmp_weight;
ifa->check_ttl = (ip->ttl_security == 1);
@@ -596,10 +594,19 @@ ospf_iface_new(struct ospf_area *oa, struct ifa *addr, struct ospf_iface_patt *i
ifa->passwords = ip->passwords;
ifa->instance_id = ip->instance_id;
+ /* This must be done after relevant fields are set */
+ ifa->tx_length = ifa_tx_length(ifa);
+ ifa->tx_hdrlen = ifa_tx_hdrlen(ifa);
+
ifa->ptp_netmask = !(addr->flags & IA_PEER);
if (ip->ptp_netmask < 2)
ifa->ptp_netmask = ip->ptp_netmask;
+ /* For compatibility, we may use ptp_address even for unnumbered links */
+ ifa->ptp_address = !(addr->flags & IA_PEER) || (p->gr_mode != OSPF_GR_ABLE);
+ if (ip->ptp_address < 2)
+ ifa->ptp_address = ip->ptp_address;
+
ifa->drip = ifa->bdrip = ospf_is_v2(p) ? IPA_NONE4 : IPA_NONE6;
ifa->type = ospf_iface_classify(ip->type, addr);
@@ -698,12 +705,14 @@ ospf_iface_new_vlink(struct ospf_proto *p, struct ospf_iface_patt *ip)
ifa->waitint = ip->waitint;
ifa->deadint = ip->deadint;
ifa->inftransdelay = ip->inftransdelay;
- ifa->tx_length = ospf_is_v2(p) ? IP4_MIN_MTU : IP6_MIN_MTU;
- ifa->tx_hdrlen = ifa_tx_hdrlen(ifa);
ifa->autype = ip->autype;
ifa->passwords = ip->passwords;
ifa->instance_id = ip->instance_id;
+ /* This must be done after relevant fields are set */
+ ifa->tx_length = ospf_is_v2(p) ? IP4_MIN_MTU : IP6_MIN_MTU;
+ ifa->tx_hdrlen = ifa_tx_hdrlen(ifa);
+
ifa->type = OSPF_IT_VLINK;
ifa->state = OSPF_IS_DOWN;
@@ -1000,6 +1009,29 @@ ospf_iface_reconfigure(struct ospf_iface *ifa, struct ospf_iface_patt *new)
ospf_notify_link_lsa(ifa);
}
+ /* PtP netmask */
+ int new_ptp_netmask = (new->ptp_netmask < 2) ? new->ptp_netmask :
+ !(ifa->addr->flags & IA_PEER);
+ if (ifa->ptp_netmask != new_ptp_netmask)
+ {
+ OSPF_TRACE(D_EVENTS, "Changing PtP netmask option of %s from %d to %d",
+ ifname, ifa->ptp_netmask, new_ptp_netmask);
+ ifa->ptp_netmask = new_ptp_netmask;
+ }
+
+ /* PtP address */
+ int new_ptp_address = (new->ptp_address < 2) ? new->ptp_address :
+ (!(ifa->addr->flags & IA_PEER) || (p->gr_mode != OSPF_GR_ABLE));
+ if (ifa->ptp_address != new_ptp_address)
+ {
+ /* Keep it silent for implicit changes */
+ if (new->ptp_address < 2)
+ OSPF_TRACE(D_EVENTS, "Changing PtP address option of %s from %d to %d",
+ ifname, ifa->ptp_address, new_ptp_address);
+
+ ifa->ptp_address = new_ptp_address;
+ }
+
/* BFD */
if (ifa->bfd != new->bfd)
{
diff --git a/proto/ospf/lsack.c b/proto/ospf/lsack.c
index 9198dd92..5318e50c 100644
--- a/proto/ospf/lsack.c
+++ b/proto/ospf/lsack.c
@@ -59,6 +59,7 @@ ospf_enqueue_lsack(struct ospf_neighbor *n, struct ospf_lsa_header *h_n, int que
{
/* Note that h_n is in network endianity */
struct lsa_node *no = mb_alloc(n->pool, sizeof(struct lsa_node));
+ no->n = (node) {};
memcpy(&no->lsa, h_n, sizeof(struct ospf_lsa_header));
add_tail(&n->ackl[queue], NODE no);
DBG("Adding %s ack for %R, ID: %R, RT: %R, Type: %u\n",
diff --git a/proto/ospf/neighbor.c b/proto/ospf/neighbor.c
index 30e80640..ca369819 100644
--- a/proto/ospf/neighbor.c
+++ b/proto/ospf/neighbor.c
@@ -650,19 +650,20 @@ void
ospf_dr_election(struct ospf_iface *ifa)
{
struct ospf_proto *p = ifa->oa->po;
- struct ospf_neighbor *neigh, *ndr, *nbdr, me;
+ struct ospf_neighbor *neigh, *ndr, *nbdr;
u32 myid = p->router_id;
DBG("(B)DR election.\n");
- me.state = NEIGHBOR_2WAY;
- me.rid = myid;
- me.priority = ifa->priority;
- me.ip = ifa->addr->ip;
-
- me.dr = ospf_is_v2(p) ? ipa_to_u32(ifa->drip) : ifa->drid;
- me.bdr = ospf_is_v2(p) ? ipa_to_u32(ifa->bdrip) : ifa->bdrid;
- me.iface_id = ifa->iface_id;
+ struct ospf_neighbor me = {
+ .state = NEIGHBOR_2WAY,
+ .rid = myid,
+ .priority = ifa->priority,
+ .ip = ifa->addr->ip,
+ .dr = ospf_is_v2(p) ? ipa_to_u32(ifa->drip) : ifa->drid,
+ .bdr = ospf_is_v2(p) ? ipa_to_u32(ifa->bdrip) : ifa->bdrid,
+ .iface_id = ifa->iface_id,
+ };
add_tail(&ifa->neigh_list, NODE & me);
@@ -776,7 +777,7 @@ ospf_neigh_update_bfd(struct ospf_neighbor *n, int use_bfd)
if (use_bfd && !n->bfd_req)
n->bfd_req = bfd_request_session(n->pool, n->ip, n->ifa->addr->ip,
n->ifa->iface, p->p.vrf,
- ospf_neigh_bfd_hook, n);
+ ospf_neigh_bfd_hook, n, NULL);
if (!use_bfd && n->bfd_req)
{
diff --git a/proto/ospf/ospf.c b/proto/ospf/ospf.c
index 63ff9e56..ba8c2e2b 100644
--- a/proto/ospf/ospf.c
+++ b/proto/ospf/ospf.c
@@ -620,7 +620,7 @@ ospf_get_route_info(rte * rte, byte * buf)
}
static int
-ospf_get_attr(eattr * a, byte * buf, int buflen UNUSED)
+ospf_get_attr(const eattr * a, byte * buf, int buflen UNUSED)
{
switch (a->id)
{
@@ -791,7 +791,7 @@ ospf_reconfigure(struct proto *P, struct proto_config *CF)
void
-ospf_sh_neigh(struct proto *P, char *iff)
+ospf_sh_neigh(struct proto *P, const char *iff)
{
struct ospf_proto *p = (struct ospf_proto *) P;
struct ospf_iface *ifa = NULL;
@@ -800,7 +800,6 @@ ospf_sh_neigh(struct proto *P, char *iff)
if (p->p.proto_state != PS_UP)
{
cli_msg(-1013, "%s: is not up", p->p.name);
- cli_msg(0, "");
return;
}
@@ -811,7 +810,6 @@ ospf_sh_neigh(struct proto *P, char *iff)
if ((iff == NULL) || patmatch(iff, ifa->ifname))
WALK_LIST(n, ifa->neigh_list)
ospf_sh_neigh_info(n);
- cli_msg(0, "");
}
void
@@ -826,7 +824,6 @@ ospf_sh(struct proto *P)
if (p->p.proto_state != PS_UP)
{
cli_msg(-1014, "%s: is not up", p->p.name);
- cli_msg(0, "");
return;
}
@@ -896,11 +893,10 @@ ospf_sh(struct proto *P)
FIB_WALK_END;
}
- cli_msg(0, "");
}
void
-ospf_sh_iface(struct proto *P, char *iff)
+ospf_sh_iface(struct proto *P, const char *iff)
{
struct ospf_proto *p = (struct ospf_proto *) P;
struct ospf_iface *ifa = NULL;
@@ -908,7 +904,6 @@ ospf_sh_iface(struct proto *P, char *iff)
if (p->p.proto_state != PS_UP)
{
cli_msg(-1015, "%s: is not up", p->p.name);
- cli_msg(0, "");
return;
}
@@ -916,7 +911,6 @@ ospf_sh_iface(struct proto *P, char *iff)
WALK_LIST(ifa, p->iface_list)
if ((iff == NULL) || patmatch(iff, ifa->ifname))
ospf_iface_info(ifa);
- cli_msg(0, "");
}
/* lsa_compare_for_state() - Compare function for 'show ospf state'
@@ -1244,7 +1238,7 @@ ospf_sh_state(struct proto *P, int verbose, int reachable)
uint num = p->gr->hash_entries;
struct top_hash_entry *hea[num];
- struct top_hash_entry *hex[verbose ? num : 0];
+ struct top_hash_entry **hex = verbose ? alloca(num * sizeof(struct top_hash_entry *)) : NULL;
struct top_hash_entry *he;
struct top_hash_entry *cnode = NULL;
@@ -1289,7 +1283,9 @@ ospf_sh_state(struct proto *P, int verbose, int reachable)
lsa_compare_ospf3 = !ospf2;
qsort(hea, j1, sizeof(struct top_hash_entry *), lsa_compare_for_state);
- qsort(hex, jx, sizeof(struct top_hash_entry *), ext_compare_for_state);
+
+ if (verbose)
+ qsort(hex, jx, sizeof(struct top_hash_entry *), ext_compare_for_state);
/*
* This code is a bit tricky, we have a primary LSAs (router and
diff --git a/proto/ospf/ospf.h b/proto/ospf/ospf.h
index 8318ee95..db55aa6a 100644
--- a/proto/ospf/ospf.h
+++ b/proto/ospf/ospf.h
@@ -191,6 +191,7 @@ struct ospf_iface_patt
u8 link_lsa_suppression;
u8 real_bcast; /* Not really used in OSPFv3 */
u8 ptp_netmask; /* bool + 2 for unspecified */
+ u8 ptp_address; /* bool + 2 for unspecified */
u8 ttl_security; /* bool + 2 for TX only */
u8 bfd;
list *passwords;
@@ -348,6 +349,7 @@ struct ospf_iface
u8 ecmp_weight; /* Weight used for ECMP */
u8 link_lsa_suppression; /* Suppression of Link-LSA origination */
u8 ptp_netmask; /* Send real netmask for P2P */
+ u8 ptp_address; /* Send IP address in data field for PtP */
u8 check_ttl; /* Check incoming packets for TTL 255 */
u8 bfd; /* Use BFD on iface */
};
@@ -990,9 +992,9 @@ static inline int oa_is_nssa(struct ospf_area *oa)
void ospf_stop_gr_recovery(struct ospf_proto *p);
-void ospf_sh_neigh(struct proto *P, char *iff);
+void ospf_sh_neigh(struct proto *P, const char *iff);
void ospf_sh(struct proto *P);
-void ospf_sh_iface(struct proto *P, char *iff);
+void ospf_sh_iface(struct proto *P, const char *iff);
void ospf_sh_state(struct proto *P, int verbose, int reachable);
void ospf_sh_lsadb(struct lsadb_show_data *ld);
@@ -1018,6 +1020,20 @@ struct nbma_node *find_nbma_node_(list *nnl, ip_addr ip);
static inline struct nbma_node * find_nbma_node(struct ospf_iface *ifa, ip_addr ip)
{ return find_nbma_node_(&ifa->nbma_list, ip); }
+static inline u32 ospf_iface_get_data(struct ospf_iface *ifa)
+{
+ /*
+ * Return expected value of the link data field in Rt-LSA for given iface.
+ * It should be ifa->iface_id for unnumbered PtP links, IP address otherwise
+ * (see RFC 2328 12.4.1.1). It is controlled by ifa->ptp_address field so it
+ * can be overriden for compatibility purposes.
+ */
+
+ return ((ifa->type == OSPF_IT_PTP) && !ifa->ptp_address) ?
+ ifa->iface_id :
+ ipa_to_u32(ifa->addr->ip);
+}
+
/* neighbor.c */
struct ospf_neighbor *ospf_neighbor_new(struct ospf_iface *ifa);
void ospf_neigh_sm(struct ospf_neighbor *n, int event);
diff --git a/proto/ospf/packet.c b/proto/ospf/packet.c
index 599f3094..85cbbdf0 100644
--- a/proto/ospf/packet.c
+++ b/proto/ospf/packet.c
@@ -14,6 +14,14 @@
#include "lib/mac.h"
#include "lib/socket.h"
+const char * const ospf_pkt_names[] = {
+ [HELLO_P] = "HELLO",
+ [DBDES_P] = "DBDES",
+ [LSREQ_P] = "LSREQ",
+ [LSUPD_P] = "LSUPD",
+ [LSACK_P] = "LSACK",
+};
+
void
ospf_pkt_fill_hdr(struct ospf_iface *ifa, void *buf, u8 h_type)
{
@@ -441,7 +449,8 @@ ospf_rx_hook(sock *sk, uint len)
DROP("version mismatch", pkt->version);
uint plen = ntohs(pkt->length);
- if ((plen < sizeof(struct ospf_packet)) || ((plen % 4) != 0))
+ uint hlen = sizeof(struct ospf_packet) + (ospf_is_v2(p) ? sizeof(union ospf_auth2) : 0);
+ if ((plen < hlen) || ((plen % 4) != 0))
DROP("invalid length", plen);
if (sk->flags & SKF_TRUNCATED)
@@ -462,9 +471,8 @@ ospf_rx_hook(sock *sk, uint len)
if (ospf_is_v2(p) && (pkt->autype != OSPF_AUTH_CRYPT))
{
- uint hlen = sizeof(struct ospf_packet) + sizeof(union ospf_auth2);
- uint blen = plen - hlen;
void *body = ((void *) pkt) + hlen;
+ uint blen = plen - hlen;
if (!ipsum_verify(pkt, sizeof(struct ospf_packet), body, blen, NULL))
DROP("invalid checksum", ntohs(pkt->checksum));
@@ -550,6 +558,10 @@ found:
if (rid == 0)
DROP1("zero router ID");
+ /* Check packet type here, ospf_pkt_checkauth3() expects valid values */
+ if (pkt->type < HELLO_P || pkt->type > LSACK_P)
+ DROP("invalid packet type", pkt->type);
+
/* In OSPFv2, neighbors are identified by either IP or Router ID, based on network type */
uint t = ifa->type;
struct ospf_neighbor *n;
@@ -565,11 +577,15 @@ found:
return 1;
}
- /* Check packet type here, ospf_pkt_checkauth3() expects valid values */
- if (pkt->type < HELLO_P || pkt->type > LSACK_P)
- DROP("invalid packet type", pkt->type);
+ /* We need to ignore out-of-state packets before ospf_pkt_checkauth3() */
+ if ((pkt->type > DBDES_P) && (n->state < NEIGHBOR_EXCHANGE))
+ {
+ OSPF_TRACE(D_PACKETS, "%s packet ignored - lesser state than Exchange",
+ ospf_pkt_names[pkt->type]);
+ return 1;
+ }
- /* ospf_pkt_checkauth() has its own error logging */
+ /* ospf_pkt_checkauthX() has its own error logging */
if ((ospf_is_v2(p) ?
!ospf_pkt_checkauth2(n, ifa, pkt, len) :
!ospf_pkt_checkauth3(n, ifa, pkt, len, sk->faddr)))
diff --git a/proto/ospf/rt.c b/proto/ospf/rt.c
index b5787b54..b3e49a11 100644
--- a/proto/ospf/rt.c
+++ b/proto/ospf/rt.c
@@ -395,12 +395,10 @@ px_pos_to_ifa(struct ospf_area *oa, int pos)
static inline struct ospf_iface *
rt_find_iface2(struct ospf_area *oa, uint data)
{
- ip_addr addr = ipa_from_u32(data);
-
/* We should handle it differently for unnumbered PTP links */
struct ospf_iface *ifa;
WALK_LIST(ifa, oa->po->iface_list)
- if ((ifa->oa == oa) && ifa->addr && (ipa_equal(ifa->addr->ip, addr)))
+ if ((ifa->oa == oa) && ifa->addr && (ospf_iface_get_data(ifa) == data))
return ifa;
return NULL;
@@ -420,7 +418,13 @@ rt_find_iface3(struct ospf_area *oa, uint lif)
static struct ospf_iface *
rt_find_iface(struct ospf_area *oa, int pos, uint data, uint lif)
{
- if (0)
+ /*
+ * We can use both position based lookup (which is more reliable) and data/lif
+ * based lookup (which works even during graceful restart). We will prefer the
+ * first approach, but use the second one for GR-enabled instances.
+ */
+
+ if (oa->po->gr_mode != OSPF_GR_ABLE)
return rt_pos_to_ifa(oa, pos);
else
return ospf_is_v2(oa->po) ? rt_find_iface2(oa, data) : rt_find_iface3(oa, lif);
diff --git a/proto/ospf/topology.c b/proto/ospf/topology.c
index 2e9c3965..52c2a0ce 100644
--- a/proto/ospf/topology.c
+++ b/proto/ospf/topology.c
@@ -329,6 +329,14 @@ ospf_originate_lsa(struct ospf_proto *p, struct ospf_new_lsa *lsa)
en->next_lsa_opts = 0;
}
+ /* The static analyzer complains here that en->lsa_body may be NULL.
+ * Yes, it may if ospf_hash_get() creates a new struct top_hash_entry.
+ * In this case, also en->lsa.length must be 0 and lsa_length is never
+ * equal to 0 while sizeof(struct ospf_lsa_header) is non-zero.
+ * Therefore memcmp() is never executed with NULL here.
+ * */
+ ASSUME(en->lsa.age >= LSA_MAXAGE || (en->lsa.length == 0) == (en->lsa_body == NULL));
+
/* Ignore the the new LSA if is the same as the current one */
if ((en->lsa.age < LSA_MAXAGE) &&
(lsa_length == en->lsa.length) &&
@@ -789,14 +797,11 @@ prepare_rt2_lsa_body(struct ospf_proto *p, struct ospf_area *oa)
if (neigh->state == NEIGHBOR_FULL)
{
/*
- * ln->data should be ifa->iface_id in case of no/ptp
- * address (ifa->addr->flags & IA_PEER) on PTP link (see
- * RFC 2328 12.4.1.1.), but the iface ID value has no use,
- * while using IP address even in this case is here for
- * compatibility with some broken implementations that use
- * this address as a next-hop.
+ * ln->data field should be ifa->iface_id for unnumbered PtP links,
+ * IP address otherwise (see RFC 2328 12.4.1.1). This is controlled
+ * by ifa->ptp_address field.
*/
- add_rt2_lsa_link(p, LSART_PTP, neigh->rid, ipa_to_u32(ifa->addr->ip), link_cost);
+ add_rt2_lsa_link(p, LSART_PTP, neigh->rid, ospf_iface_get_data(ifa), link_cost);
i++;
}
break;
@@ -1450,6 +1455,9 @@ ospf_originate_link_lsa(struct ospf_proto *p, struct ospf_iface *ifa)
prepare_link_lsa_body(p, ifa);
ifa->link_lsa = ospf_originate_lsa(p, &lsa);
+
+ /* RFC 5340 4.4.3 Events 6+7 - new Link LSA is locally originated */
+ ospf_notify_net_lsa(ifa);
}
@@ -2100,9 +2108,7 @@ ospf_hash_get(struct top_graph *f, u32 domain, u32 lsa, u32 rtr, u32 type)
if (e)
return e;
- e = sl_alloc(f->hash_slab);
- bzero(e, sizeof(struct top_hash_entry));
-
+ e = sl_allocz(f->hash_slab);
e->color = OUTSPF;
e->dist = LSINFINITY;
e->lsa.type_raw = type;
diff --git a/proto/perf/perf.c b/proto/perf/perf.c
index dfbd0884..ba401a8a 100644
--- a/proto/perf/perf.c
+++ b/proto/perf/perf.c
@@ -85,12 +85,11 @@ random_net_ip4(void)
}
struct perf_random_routes {
+ struct rta *a;
net_addr net;
- rte *ep;
- struct rta a;
};
-static const uint perf_random_routes_size = sizeof(struct perf_random_routes) + (RTA_MAX_SIZE - sizeof(struct rta));
+//static const uint perf_random_routes_size = sizeof(struct perf_random_routes) + (RTA_MAX_SIZE - sizeof(struct rta));
static inline s64 timediff(struct timespec *begin, struct timespec *end)
{ return (end->tv_sec - begin->tv_sec) * (s64) 1000000000 + end->tv_nsec - begin->tv_nsec; }
@@ -126,12 +125,10 @@ perf_loop(void *data)
struct perf_proto *p = data;
const uint N = 1U << p->exp;
- const uint offset = perf_random_routes_size;
if (!p->run) {
ASSERT(p->data == NULL);
- p->data = xmalloc(offset * N);
- bzero(p->data, offset * N);
+ p->data = xmalloc(sizeof(struct perf_random_routes) * N);
p->stop = 1;
}
@@ -141,49 +138,40 @@ perf_loop(void *data)
clock_gettime(CLOCK_MONOTONIC, &ts_begin);
- struct rta *a = NULL;
-
for (uint i=0; i<N; i++) {
- struct perf_random_routes *prr = p->data + offset * i;
- *((net_addr_ip4 *) &prr->net) = random_net_ip4();
+ *((net_addr_ip4 *) &(p->data[i].net)) = random_net_ip4();
if (!p->attrs_per_rte || !(i % p->attrs_per_rte)) {
- a = &prr->a;
- bzero(a, RTA_MAX_SIZE);
-
- a->src = p->p.main_source;
- a->source = RTS_PERF;
- a->scope = SCOPE_UNIVERSE;
- a->dest = RTD_UNICAST;
-
- a->nh.iface = p->ifa->iface;
- a->nh.gw = gw;
- a->nh.weight = 1;
-
- if (p->attrs_per_rte)
- a = rta_lookup(a);
+ struct rta a0 = {
+ .src = p->p.main_source,
+ .source = RTS_PERF,
+ .scope = SCOPE_UNIVERSE,
+ .dest = RTD_UNICAST,
+ .nh.iface = p->ifa->iface,
+ .nh.gw = gw,
+ .nh.weight = 1,
+ };
+
+ p->data[i].a = rta_lookup(&a0);
}
-
- ASSERT(a);
-
- prr->ep = rte_get_temp(a);
- prr->ep->pflags = 0;
+ else
+ p->data[i].a = rta_clone(p->data[i-1].a);
}
clock_gettime(CLOCK_MONOTONIC, &ts_generated);
for (uint i=0; i<N; i++) {
- struct perf_random_routes *prr = p->data + offset * i;
- rte_update(P, &prr->net, prr->ep);
+ rte *e = rte_get_temp(p->data[i].a);
+ e->pflags = 0;
+
+ rte_update(P, &(p->data[i].net), e);
}
clock_gettime(CLOCK_MONOTONIC, &ts_update);
if (!p->keep)
- for (uint i=0; i<N; i++) {
- struct perf_random_routes *prr = p->data + offset * i;
- rte_update(P, &prr->net, NULL);
- }
+ for (uint i=0; i<N; i++)
+ rte_update(P, &(p->data[i].net), NULL);
clock_gettime(CLOCK_MONOTONIC, &ts_withdraw);
@@ -229,10 +217,10 @@ perf_feed_begin(struct channel *c, int initial UNUSED)
struct perf_proto *p = (struct perf_proto *) c->proto;
p->run++;
- p->data = xmalloc(sizeof(struct timespec));
+ p->feed_begin = xmalloc(sizeof(struct timespec));
p->exp = 0;
- clock_gettime(CLOCK_MONOTONIC, p->data);
+ clock_gettime(CLOCK_MONOTONIC, p->feed_begin);
}
static void
@@ -242,10 +230,13 @@ perf_feed_end(struct channel *c)
struct timespec ts_end;
clock_gettime(CLOCK_MONOTONIC, &ts_end);
- s64 feedtime = timediff(p->data, &ts_end);
+ s64 feedtime = timediff(p->feed_begin, &ts_end);
PLOG("feed n=%lu time=%lu", p->exp, feedtime);
+ xfree(p->feed_begin);
+ p->feed_begin = NULL;
+
if (p->run < p->repeat)
channel_request_feeding(c);
else
diff --git a/proto/perf/perf.h b/proto/perf/perf.h
index 8fde01bd..8b5fa914 100644
--- a/proto/perf/perf.h
+++ b/proto/perf/perf.h
@@ -29,7 +29,8 @@ struct perf_config {
struct perf_proto {
struct proto p;
struct ifa *ifa;
- void *data;
+ struct perf_random_routes *data;
+ struct timespec *feed_begin;
event *loop;
btime threshold_min;
btime threshold_max;
diff --git a/proto/pipe/config.Y b/proto/pipe/config.Y
index 18e1d0fc..1202c169 100644
--- a/proto/pipe/config.Y
+++ b/proto/pipe/config.Y
@@ -39,7 +39,7 @@ proto_name
pipe_proto:
pipe_proto_start '{'
| pipe_proto proto_item ';'
- | pipe_proto channel_item ';'
+ | pipe_proto channel_item_ ';'
| pipe_proto PEER TABLE rtable ';' { PIPE_CFG->peer = $4; }
;
diff --git a/proto/pipe/pipe.c b/proto/pipe/pipe.c
index efb992ca..3532f114 100644
--- a/proto/pipe/pipe.c
+++ b/proto/pipe/pipe.c
@@ -141,6 +141,8 @@ pipe_postconfig(struct proto_config *CF)
if (cc->in_keep_filtered)
cf_error("Pipe protocol prohibits keeping filtered routes");
+
+ cc->debug = cf->c.debug;
}
static int
@@ -154,7 +156,9 @@ pipe_configure_channels(struct pipe_proto *p, struct pipe_config *cf)
.table = cc->table,
.out_filter = cc->out_filter,
.in_limit = cc->in_limit,
- .ra_mode = RA_ANY
+ .ra_mode = RA_ANY,
+ .debug = cc->debug,
+ .rpki_reload = cc->rpki_reload,
};
struct channel_config sec_cf = {
@@ -163,7 +167,9 @@ pipe_configure_channels(struct pipe_proto *p, struct pipe_config *cf)
.table = cf->peer,
.out_filter = cc->in_filter,
.in_limit = cc->out_limit,
- .ra_mode = RA_ANY
+ .ra_mode = RA_ANY,
+ .debug = cc->debug,
+ .rpki_reload = cc->rpki_reload,
};
return
@@ -276,6 +282,14 @@ pipe_show_proto_info(struct proto *P)
pipe_show_stats(p);
}
+void
+pipe_update_debug(struct proto *P)
+{
+ struct pipe_proto *p = (void *) P;
+
+ p->pri->debug = p->sec->debug = p->p.debug;
+}
+
struct protocol proto_pipe = {
.name = "Pipe",
diff --git a/proto/radv/packets.c b/proto/radv/packets.c
index 3139d321..5cd8b2de 100644
--- a/proto/radv/packets.c
+++ b/proto/radv/packets.c
@@ -173,8 +173,8 @@ radv_process_domain(struct radv_dnssl_config *cf)
{
/* Format of domain in search list is <size> <label> <size> <label> ... 0 */
- char *dom = cf->domain;
- char *dom_end = dom; /* Just to */
+ const char *dom = cf->domain;
+ const char *dom_end = dom; /* Just to */
u8 *dlen_save = &cf->dlen_first;
uint len;
diff --git a/proto/radv/radv.c b/proto/radv/radv.c
index 622b3c3c..b4235917 100644
--- a/proto/radv/radv.c
+++ b/proto/radv/radv.c
@@ -740,7 +740,7 @@ radv_pref_str(u32 pref)
/* The buffer has some minimal size */
static int
-radv_get_attr(eattr *a, byte *buf, int buflen UNUSED)
+radv_get_attr(const eattr *a, byte *buf, int buflen UNUSED)
{
switch (a->id)
{
diff --git a/proto/radv/radv.h b/proto/radv/radv.h
index 2c8ad7d4..14d40f8a 100644
--- a/proto/radv/radv.h
+++ b/proto/radv/radv.h
@@ -119,7 +119,7 @@ struct radv_dnssl_config
u16 lifetime_mult; /* Lifetime specified as multiple of max_ra_int */
u8 dlen_first; /* Length of first label in domain */
u8 dlen_all; /* Both dlen_ filled in radv_process_domain() */
- char *domain; /* Domain for DNS search list, in processed form */
+ const char *domain; /* Domain for DNS search list, in processed form */
};
/*
diff --git a/proto/rip/config.Y b/proto/rip/config.Y
index 5b5f94a0..28ee9609 100644
--- a/proto/rip/config.Y
+++ b/proto/rip/config.Y
@@ -33,10 +33,11 @@ rip_check_auth(void)
CF_DECLS
CF_KEYWORDS(RIP, NG, ECMP, LIMIT, WEIGHT, INFINITY, METRIC, UPDATE, TIMEOUT,
- GARBAGE, PORT, ADDRESS, MODE, BROADCAST, MULTICAST, PASSIVE,
- VERSION, SPLIT, HORIZON, POISON, REVERSE, CHECK, ZERO, TIME, BFD,
- AUTHENTICATION, NONE, PLAINTEXT, CRYPTOGRAPHIC, MD5, TTL, SECURITY,
- RX, TX, BUFFER, LENGTH, PRIORITY, ONLY, LINK, RIP_METRIC, RIP_TAG)
+ GARBAGE, RETRANSMIT, PORT, ADDRESS, MODE, BROADCAST, MULTICAST,
+ PASSIVE, VERSION, SPLIT, HORIZON, POISON, REVERSE, CHECK, ZERO,
+ TIME, BFD, AUTHENTICATION, NONE, PLAINTEXT, CRYPTOGRAPHIC, MD5,
+ TTL, SECURITY, RX, TX, BUFFER, LENGTH, PRIORITY, ONLY, LINK,
+ DEMAND, CIRCUIT, RIP_METRIC, RIP_TAG)
%type <i> rip_variant rip_auth
@@ -102,6 +103,7 @@ rip_iface_start:
RIP_IFACE->update_time = RIP_DEFAULT_UPDATE_TIME;
RIP_IFACE->timeout_time = RIP_DEFAULT_TIMEOUT_TIME;
RIP_IFACE->garbage_time = RIP_DEFAULT_GARBAGE_TIME;
+ RIP_IFACE->rxmt_time = RIP_DEFAULT_RXMT_TIME;
};
rip_iface_finish:
@@ -149,9 +151,11 @@ rip_iface_item:
| SPLIT HORIZON bool { RIP_IFACE->split_horizon = $3; }
| POISON REVERSE bool { RIP_IFACE->poison_reverse = $3; }
| CHECK ZERO bool { RIP_IFACE->check_zero = $3; }
+ | DEMAND CIRCUIT bool { RIP_IFACE->demand_circuit = $3; }
| UPDATE TIME expr { RIP_IFACE->update_time = $3 S_; if ($3<=0) cf_error("Update time must be positive"); }
| TIMEOUT TIME expr { RIP_IFACE->timeout_time = $3 S_; if ($3<=0) cf_error("Timeout time must be positive"); }
| GARBAGE TIME expr { RIP_IFACE->garbage_time = $3 S_; if ($3<=0) cf_error("Garbage time must be positive"); }
+ | RETRANSMIT TIME expr_us { RIP_IFACE->rxmt_time = $3; if ($3<=0) cf_error("Retransmit time must be positive"); }
| ECMP WEIGHT expr { RIP_IFACE->ecmp_weight = $3 - 1; if (($3<1) || ($3>256)) cf_error("ECMP weight must be in range 1-256"); }
| RX BUFFER expr { RIP_IFACE->rx_buffer = $3; if (($3<256) || ($3>65535)) cf_error("RX length must be in range 256-65535"); }
| TX LENGTH expr { RIP_IFACE->tx_length = $3; if (($3<256) || ($3>65535)) cf_error("TX length must be in range 256-65535"); }
@@ -192,10 +196,10 @@ dynamic_attr: RIP_TAG { $$ = f_new_dynamic_attr(EAF_TYPE_INT, T_INT, EA_RIP_TAG)
CF_CLI_HELP(SHOW RIP, ..., [[Show information about RIP protocol]]);
CF_CLI(SHOW RIP INTERFACES, optproto opttext, [<name>] [\"<interface>\"], [[Show information about RIP interfaces]])
-{ rip_show_interfaces(proto_get_named($4, &proto_rip), $5); };
+{ PROTO_WALK_CMD($4, &proto_rip, p) rip_show_interfaces(p, $5); };
CF_CLI(SHOW RIP NEIGHBORS, optproto opttext, [<name>] [\"<interface>\"], [[Show information about RIP neighbors]])
-{ rip_show_neighbors(proto_get_named($4, &proto_rip), $5); };
+{ PROTO_WALK_CMD($4, &proto_rip, p) rip_show_neighbors(p, $5); };
CF_CODE
diff --git a/proto/rip/packets.c b/proto/rip/packets.c
index 59ffd7c2..9c3bd7a3 100644
--- a/proto/rip/packets.c
+++ b/proto/rip/packets.c
@@ -18,12 +18,18 @@
#define RIP_CMD_REQUEST 1 /* want info */
#define RIP_CMD_RESPONSE 2 /* responding to request */
+#define RIP_CMD_UPDATE_REQUEST 9
+#define RIP_CMD_UPDATE_RESPONSE 10
+#define RIP_CMD_UPDATE_ACK 11
+
#define RIP_BLOCK_LENGTH 20
#define RIP_PASSWD_LENGTH 16
#define RIP_AF_IPV4 2
#define RIP_AF_AUTH 0xffff
+#define RIP_UPDATE_VERSION 1
+
/* RIP packet header */
struct rip_packet
@@ -33,6 +39,14 @@ struct rip_packet
u16 unused;
};
+/* Triggered RIP update header (RFC 2091) */
+struct rip_update_hdr
+{
+ u8 version;
+ u8 flush;
+ u16 seqnum;
+};
+
/* RTE block for RIPv2 */
struct rip_block_v2
{
@@ -89,6 +103,8 @@ struct rip_block
ip_addr next_hop;
};
+static int
+rip_send_ack(struct rip_proto *p, struct rip_iface *ifa, uint flush, uint seqnum);
#define DROP(DSC,VAL) do { err_dsc = DSC; err_val = VAL; goto drop; } while(0)
#define DROP1(DSC) do { err_dsc = DSC; goto drop; } while(0)
@@ -107,8 +123,27 @@ struct rip_block
static inline void * rip_tx_buffer(struct rip_iface *ifa)
{ return ifa->sk->tbuf; }
-static inline uint rip_pkt_hdrlen(struct rip_iface *ifa)
-{ return sizeof(struct rip_packet) + (ifa->cf->auth_type ? RIP_BLOCK_LENGTH : 0); }
+static inline uint
+rip_pkt_hdrlen(struct rip_iface *ifa)
+{
+ return sizeof(struct rip_packet) +
+ (ifa->cf->demand_circuit ? sizeof(struct rip_update_hdr) : 0) +
+ (ifa->cf->auth_type ? RIP_BLOCK_LENGTH : 0);
+}
+
+static inline struct rip_update_hdr *
+rip_get_update_hdr(struct rip_packet *pkt)
+{
+ return (void *) ((byte *) pkt + sizeof(struct rip_packet));
+}
+
+static inline struct rip_block_auth *
+rip_get_auth_block(struct rip_iface *ifa, struct rip_packet *pkt)
+{
+ return (void *) ((byte *) pkt + sizeof(struct rip_packet) +
+ (ifa->cf->demand_circuit ? sizeof(struct rip_update_hdr) : 0));
+}
+
static inline void
rip_put_block(struct rip_proto *p, byte *pos, struct rip_block *rte)
@@ -199,10 +234,31 @@ rip_update_csn(struct rip_proto *p UNUSED, struct rip_iface *ifa)
}
}
+static inline void
+rip_fill_header(struct rip_iface *ifa, struct rip_packet *pkt, uint cmd)
+{
+ *pkt = (struct rip_packet) {
+ .command = cmd,
+ .version = ifa->cf->version
+ };
+}
+
+static inline void
+rip_fill_update_hdr(struct rip_packet *pkt, uint flush, uint seqnum)
+{
+ struct rip_update_hdr *hdr = rip_get_update_hdr(pkt);
+
+ *hdr = (struct rip_update_hdr) {
+ .version = RIP_UPDATE_VERSION,
+ .flush = flush,
+ .seqnum = htons(seqnum)
+ };
+}
+
static void
rip_fill_authentication(struct rip_proto *p, struct rip_iface *ifa, struct rip_packet *pkt, uint *plen)
{
- struct rip_block_auth *auth = (void *) (pkt + 1);
+ struct rip_block_auth *auth = rip_get_auth_block(ifa, pkt);
struct password_item *pass = password_find(ifa->cf->passwords, 0);
if (!pass)
@@ -271,16 +327,16 @@ rip_fill_authentication(struct rip_proto *p, struct rip_iface *ifa, struct rip_p
}
static int
-rip_check_authentication(struct rip_proto *p, struct rip_iface *ifa, struct rip_packet *pkt, uint *plen, struct rip_neighbor *n)
+rip_check_authentication(struct rip_proto *p, struct rip_iface *ifa, struct rip_packet *pkt, uint *plen, uint hdr_len, struct rip_neighbor *n)
{
- struct rip_block_auth *auth = (void *) (pkt + 1);
+ struct rip_block_auth *auth = (void *) ((byte *) pkt + hdr_len);
struct password_item *pass = NULL;
const char *err_dsc = NULL;
uint err_val = 0;
uint auth_type = 0;
/* Check for authentication entry */
- if ((*plen >= (sizeof(struct rip_packet) + sizeof(struct rip_block_auth))) &&
+ if ((*plen >= (hdr_len + sizeof(struct rip_block_auth))) &&
(auth->must_be_ffff == htons(0xffff)))
auth_type = ntohs(auth->auth_type);
@@ -376,17 +432,31 @@ rip_send_to(struct rip_proto *p, struct rip_iface *ifa, struct rip_packet *pkt,
return sk_send_to(ifa->sk, plen, dst, 0);
}
+static inline void
+rip_kick_rxmt_timer(struct rip_iface *ifa)
+{
+ if (! tm_active(ifa->rxmt_timer))
+ tm_start(ifa->rxmt_timer, ifa->cf->rxmt_time);
+}
+
void
rip_send_request(struct rip_proto *p, struct rip_iface *ifa)
{
- byte *pos = rip_tx_buffer(ifa);
+ struct rip_packet *pkt = rip_tx_buffer(ifa);
+ byte *pos = (byte *) pkt + rip_pkt_hdrlen(ifa);
- struct rip_packet *pkt = (void *) pos;
- pkt->command = RIP_CMD_REQUEST;
- pkt->version = ifa->cf->version;
- pkt->unused = 0;
- pos += rip_pkt_hdrlen(ifa);
+ rip_fill_header(ifa, pkt, RIP_CMD_REQUEST);
+
+ if (ifa->cf->demand_circuit)
+ {
+ pkt->command = RIP_CMD_UPDATE_REQUEST;
+ rip_fill_update_hdr(pkt, 0, 0);
+
+ /* Must be acknowledged by update response */
+ ifa->req_pending = 1;
+ rip_kick_rxmt_timer(ifa);
+ }
struct rip_block b = { .no_af = 1, .metric = p->infinity };
rip_put_block(p, pos, &b);
@@ -437,18 +507,25 @@ rip_send_response(struct rip_proto *p, struct rip_iface *ifa)
if (! ifa->tx_active)
return 0;
- byte *pos = rip_tx_buffer(ifa);
- byte *max = rip_tx_buffer(ifa) + ifa->tx_plen -
+ /* In demand circuit mode, we may wait for ACK */
+ if (ifa->tx_pending)
+ return 0;
+
+ struct rip_packet *pkt = rip_tx_buffer(ifa);
+ byte *pos = (byte *) pkt + rip_pkt_hdrlen(ifa);
+ byte *max = (byte *) pkt + ifa->tx_plen -
(rip_is_v2(p) ? RIP_BLOCK_LENGTH : 2*RIP_BLOCK_LENGTH);
ip_addr last_next_hop = IPA_NONE;
btime now_ = current_time();
int send = 0;
- struct rip_packet *pkt = (void *) pos;
- pkt->command = RIP_CMD_RESPONSE;
- pkt->version = ifa->cf->version;
- pkt->unused = 0;
- pos += rip_pkt_hdrlen(ifa);
+ rip_fill_header(ifa, pkt, RIP_CMD_RESPONSE);
+
+ if (ifa->cf->demand_circuit)
+ {
+ pkt->command = RIP_CMD_UPDATE_RESPONSE;
+ rip_fill_update_hdr(pkt, ifa->tx_flush, ifa->tx_seqnum);
+ }
FIB_ITERATE_START(&p->rtable, &ifa->tx_fit, struct rip_entry, en)
{
@@ -469,7 +546,7 @@ rip_send_response(struct rip_proto *p, struct rip_iface *ifa)
if (pos > max)
{
FIB_ITERATE_PUT(&ifa->tx_fit);
- goto break_loop;
+ goto send_pkt;
}
struct rip_block rte = {
@@ -522,13 +599,31 @@ rip_send_response(struct rip_proto *p, struct rip_iface *ifa)
next_entry: ;
}
FIB_ITERATE_END;
- ifa->tx_active = 0;
+
+ if (send)
+ {
+ FIB_ITERATE_PUT_END(&ifa->tx_fit);
+ goto send_pkt;
+ }
/* Do not send empty packet */
- if (!send)
- return 0;
-break_loop:
+ ifa->tx_active = 0;
+
+ /* Unlink second iterator */
+ FIB_ITERATE_UNLINK(&ifa->tx_done, &p->rtable);
+
+ return 0;
+
+send_pkt:
+
+ /* Waiting for ack or timeout */
+ if (ifa->cf->demand_circuit)
+ {
+ ifa->tx_pending = 1;
+ rip_kick_rxmt_timer(ifa);
+ }
+
TRACE(D_PACKETS, "Sending response via %s", ifa->iface->name);
return rip_send_to(p, ifa, pkt, pos - (byte *) pkt, ifa->tx_addr);
}
@@ -558,6 +653,10 @@ rip_send_table(struct rip_proto *p, struct rip_iface *ifa, ip_addr addr, btime c
ifa->tx_addr = addr;
ifa->tx_changed = changed;
FIB_ITERATE_INIT(&ifa->tx_fit, &p->rtable);
+ FIB_ITERATE_INIT(&ifa->tx_done, &p->rtable);
+
+ if (ifa->cf->demand_circuit)
+ ifa->tx_flush = ! changed;
rip_update_csn(p, ifa);
@@ -597,9 +696,27 @@ rip_receive_response(struct rip_proto *p, struct rip_iface *ifa, struct rip_pack
TRACE(D_PACKETS, "Response received from %I on %s", from->nbr->addr, ifa->iface->name);
- byte *pos = (byte *) pkt + sizeof(struct rip_packet);
+ byte *pos = (byte *) pkt + rip_pkt_hdrlen(ifa);
byte *end = (byte *) pkt + plen;
- btime now_ = current_time();
+
+ btime expires = current_time() + ifa->cf->timeout_time;
+
+ if (pkt->command == RIP_CMD_UPDATE_RESPONSE)
+ {
+ struct rip_update_hdr *hdr = rip_get_update_hdr(pkt);
+ rip_send_ack(p, ifa, hdr->flush, ntohs(hdr->seqnum));
+ expires = TIME_INFINITY;
+
+ /* Handle flush bit */
+ if (hdr->flush)
+ {
+ /* Flush old routes */
+ rip_flush_table(p, from);
+
+ /* Acknowledge pending request */
+ ifa->req_pending = 0;
+ }
+ }
for (; pos < end; pos += RIP_BLOCK_LENGTH)
{
@@ -647,7 +764,7 @@ rip_receive_response(struct rip_proto *p, struct rip_iface *ifa, struct rip_pack
.next_hop = ipa_nonzero(rte.next_hop) ? rte.next_hop : from->nbr->addr,
.metric = rte.metric,
.tag = rte.tag,
- .expires = now_ + ifa->cf->timeout_time
+ .expires = expires
};
rip_update_rte(p, &rte.net, &new);
@@ -663,6 +780,104 @@ rip_receive_response(struct rip_proto *p, struct rip_iface *ifa, struct rip_pack
}
}
+int
+rip_send_flush(struct rip_proto *p, struct rip_iface *ifa)
+{
+ /* Caller should handle cleanup of pending response */
+ if (ifa->tx_pending)
+ return 0;
+
+ struct rip_packet *pkt = rip_tx_buffer(ifa);
+
+ rip_fill_header(ifa, pkt, RIP_CMD_UPDATE_RESPONSE);
+ rip_fill_update_hdr(pkt, 1, ifa->tx_seqnum);
+
+ /* We suppose that iface is going down, so we do not expect ACK */
+ ifa->tx_seqnum++;
+
+ TRACE(D_PACKETS, "Sending response via %s", ifa->iface->name);
+ return rip_send_to(p, ifa, pkt, rip_pkt_hdrlen(ifa), ifa->tx_addr);
+}
+
+
+static int
+rip_send_ack(struct rip_proto *p, struct rip_iface *ifa, uint flush, uint seqnum)
+{
+ struct rip_packet *pkt = rip_tx_buffer(ifa);
+
+ rip_fill_header(ifa, pkt, RIP_CMD_UPDATE_ACK);
+ rip_fill_update_hdr(pkt, flush, seqnum);
+
+ TRACE(D_PACKETS, "Sending acknowledge via %s", ifa->iface->name);
+ return rip_send_to(p, ifa, pkt, rip_pkt_hdrlen(ifa), ifa->tx_addr);
+}
+
+static void
+rip_receive_ack(struct rip_proto *p, struct rip_iface *ifa, struct rip_packet *pkt, uint plen UNUSED, struct rip_neighbor *from)
+{
+ TRACE(D_PACKETS, "Acknowledge received from %I on %s", from->nbr->addr, ifa->iface->name);
+
+ struct rip_update_hdr *hdr = rip_get_update_hdr(pkt);
+ uint seqnum = ntohs(hdr->seqnum);
+
+ if (! ifa->tx_active || ! ifa->tx_pending)
+ {
+ LOG_PKT("Bad acknowledge packet from %I via %s - no pending response",
+ from->nbr->addr, ifa->iface->name);
+ return;
+ }
+
+ if (seqnum != ifa->tx_seqnum)
+ {
+ LOG_PKT("Bad acknowledge packet from %I via %s - "
+ "mismatched sequence number (rcv %u, old %u)",
+ from->nbr->addr, ifa->iface->name, seqnum, (uint) ifa->tx_seqnum);
+ return;
+ }
+
+ /* Move acked position */
+ FIB_ITERATE_COPY(&ifa->tx_done, &ifa->tx_fit, &p->rtable);
+
+ /* Packet is no longer pending */
+ ifa->tx_pending = 0;
+ ifa->tx_seqnum++;
+
+ /* Next one does not have flush bit */
+ ifa->tx_flush = 0;
+
+ rip_send_response(p, ifa);
+}
+
+/**
+ * rip_rxmt_timeout - RIP retransmission timer hook
+ * @t: timer
+ *
+ * In Demand Circuit mode, update packets must be acknowledged to ensure
+ * reliability. If they are not acknowledged, we need to retransmit them.
+ */
+void
+rip_rxmt_timeout(timer *t)
+{
+ struct rip_iface *ifa = t->data;
+ struct rip_proto *p = ifa->rip;
+
+ if (ifa->req_pending)
+ rip_send_request(p, ifa);
+
+ if (ifa->tx_pending)
+ {
+ /* Revert to acked position */
+ FIB_ITERATE_COPY(&ifa->tx_fit, &ifa->tx_done, &p->rtable);
+
+ /* Packet is no longer pending */
+ ifa->tx_pending = 0;
+ ifa->tx_seqnum++;
+
+ rip_send_response(p, ifa);
+ }
+}
+
+
static int
rip_rx_hook(sock *sk, uint len)
{
@@ -702,17 +917,43 @@ rip_rx_hook(sock *sk, uint len)
DROP("truncated", len);
struct rip_packet *pkt = (struct rip_packet *) sk->rbuf;
- uint plen = len;
+ uint pkt_len = len;
+ uint hdr_len = sizeof(struct rip_packet);
+ uint update_msg = 0;
if (!pkt->version || (ifa->cf->version_only && (pkt->version != ifa->cf->version)))
DROP("wrong version", pkt->version);
+ /* Update packets (RFC 2091) have additional header even before auth data */
+ if ((pkt->command == RIP_CMD_UPDATE_REQUEST) ||
+ (pkt->command == RIP_CMD_UPDATE_RESPONSE) ||
+ (pkt->command == RIP_CMD_UPDATE_ACK))
+ {
+ hdr_len += sizeof(struct rip_update_hdr);
+
+ if (len < hdr_len)
+ DROP("too short", len);
+
+ struct rip_update_hdr *hdr = rip_get_update_hdr(pkt);
+
+ if (hdr->version != RIP_UPDATE_VERSION)
+ DROP("wrong update header version", hdr->version);
+
+ if (hdr->flush > 1)
+ DROP("wrong flush value", hdr->flush);
+
+ update_msg = 1;
+ }
+
/* rip_check_authentication() has its own error logging */
- if (rip_is_v2(p) && !rip_check_authentication(p, ifa, pkt, &plen, n))
+ if (rip_is_v2(p) && !rip_check_authentication(p, ifa, pkt, &pkt_len, hdr_len, n))
return 1;
- if ((plen - sizeof(struct rip_packet)) % RIP_BLOCK_LENGTH)
- DROP("invalid length", plen);
+ if ((pkt_len - hdr_len) % RIP_BLOCK_LENGTH)
+ DROP("invalid length", pkt_len);
+
+ if (update_msg != ifa->cf->demand_circuit)
+ DROP("demand circuit mode mismatch", update_msg);
n->last_seen = current_time();
rip_update_bfd(p, n);
@@ -720,11 +961,17 @@ rip_rx_hook(sock *sk, uint len)
switch (pkt->command)
{
case RIP_CMD_REQUEST:
- rip_receive_request(p, ifa, pkt, plen, n);
+ case RIP_CMD_UPDATE_REQUEST:
+ rip_receive_request(p, ifa, pkt, pkt_len, n);
break;
case RIP_CMD_RESPONSE:
- rip_receive_response(p, ifa, pkt, plen, n);
+ case RIP_CMD_UPDATE_RESPONSE:
+ rip_receive_response(p, ifa, pkt, pkt_len, n);
+ break;
+
+ case RIP_CMD_UPDATE_ACK:
+ rip_receive_ack(p, ifa, pkt, pkt_len, n);
break;
default:
diff --git a/proto/rip/rip.c b/proto/rip/rip.c
index 4559310e..8b4719f7 100644
--- a/proto/rip/rip.c
+++ b/proto/rip/rip.c
@@ -69,10 +69,11 @@
* structure is finally freed.
*
* Supported standards:
- * - RFC 1058 - RIPv1
- * - RFC 2453 - RIPv2
- * - RFC 2080 - RIPng
- * - RFC 4822 - RIP cryptographic authentication
+ * RFC 1058 - RIPv1
+ * RFC 2453 - RIPv2
+ * RFC 2080 - RIPng
+ * RFC 2091 - Triggered RIP for demand circuits
+ * RFC 4822 - RIP cryptographic authentication
*/
#include <stdlib.h>
@@ -167,7 +168,7 @@ rip_announce_rte(struct rip_proto *p, struct rip_entry *en)
struct nexthop *nh = allocz(sizeof(struct nexthop));
nh->gw = rt->next_hop;
- nh->iface = rt->from->nbr->iface;
+ nh->iface = rt->from->ifa->iface;
nh->weight = rt->from->ifa->cf->ecmp_weight;
nexthop_insert(&nhs, nh);
@@ -184,7 +185,7 @@ rip_announce_rte(struct rip_proto *p, struct rip_entry *en)
/* Unipath route */
a0.from = rt->from->nbr->addr;
a0.nh.gw = rt->next_hop;
- a0.nh.iface = rt->from->nbr->iface;
+ a0.nh.iface = rt->from->ifa->iface;
}
rta *a = rta_lookup(&a0);
@@ -368,6 +369,20 @@ rip_rt_notify(struct proto *P, struct channel *ch UNUSED, struct network *net, s
}
}
+void
+rip_flush_table(struct rip_proto *p, struct rip_neighbor *n)
+{
+ btime expires = current_time() + n->ifa->cf->timeout_time;
+
+ FIB_WALK(&p->rtable, struct rip_entry, en)
+ {
+ for (struct rip_rte *e = en->routes; e; e = e->next)
+ if ((e->from == n) && (e->expires == TIME_INFINITY))
+ e->expires = expires;
+ }
+ FIB_WALK_END;
+}
+
/*
* RIP neighbors
@@ -402,7 +417,7 @@ rip_remove_neighbor(struct rip_proto *p, struct rip_neighbor *n)
{
neighbor *nbr = n->nbr;
- TRACE(D_EVENTS, "Removing neighbor %I on %s", nbr->addr, nbr->iface->name);
+ TRACE(D_EVENTS, "Removing neighbor %I on %s", nbr->addr, nbr->ifreq->name);
rem_node(NODE n);
n->ifa = NULL;
@@ -484,7 +499,7 @@ rip_update_bfd(struct rip_proto *p, struct rip_neighbor *n)
ip_addr saddr = rip_is_v2(p) ? n->ifa->sk->saddr : n->nbr->ifa->ip;
n->bfd_req = bfd_request_session(p->p.pool, n->nbr->addr, saddr,
n->nbr->iface, p->p.vrf,
- rip_bfd_notify, n);
+ rip_bfd_notify, n, NULL);
}
if (!use_bfd && n->bfd_req)
@@ -506,14 +521,23 @@ rip_iface_start(struct rip_iface *ifa)
TRACE(D_EVENTS, "Starting interface %s", ifa->iface->name);
- ifa->next_regular = current_time() + (random() % ifa->cf->update_time) + 100 MS;
- ifa->next_triggered = current_time(); /* Available immediately */
- ifa->want_triggered = 1; /* All routes in triggered update */
- tm_start(ifa->timer, 100 MS);
+ if (! ifa->cf->demand_circuit)
+ {
+ ifa->next_regular = current_time() + (random() % ifa->cf->update_time) + 100 MS;
+ tm_set(ifa->timer, ifa->next_regular);
+ }
+ else
+ {
+ ifa->next_regular = TIME_INFINITY;
+ }
+
ifa->up = 1;
- if (!ifa->cf->passive)
- rip_send_request(ifa->rip, ifa);
+ if (ifa->cf->passive)
+ return;
+
+ rip_send_request(p, ifa);
+ rip_send_table(p, ifa, ifa->addr, 0);
}
static void
@@ -526,10 +550,24 @@ rip_iface_stop(struct rip_iface *ifa)
rip_reset_tx_session(p, ifa);
+ ifa->next_regular = 0;
+ ifa->next_triggered = 0;
+ ifa->want_triggered = 0;
+
+ if (ifa->tx_pending)
+ ifa->tx_seqnum++;
+
+ ifa->tx_pending = 0;
+ ifa->req_pending = 0;
+
+ if (ifa->cf->demand_circuit && !ifa->cf->passive)
+ rip_send_flush(p, ifa);
+
WALK_LIST_FIRST(n, ifa->neigh_list)
rip_remove_neighbor(p, n);
tm_stop(ifa->timer);
+ tm_stop(ifa->rxmt_timer);
ifa->up = 0;
}
@@ -643,6 +681,7 @@ rip_add_iface(struct rip_proto *p, struct iface *iface, struct rip_iface_config
add_tail(&p->iface_list, NODE ifa);
ifa->timer = tm_new_init(p->p.pool, rip_iface_timer, ifa, 0, 0);
+ ifa->rxmt_timer = tm_new_init(p->p.pool, rip_rxmt_timeout, ifa, 0, 0);
struct object_lock *lock = olock_new(p->p.pool);
lock->type = OBJLOCK_UDP;
@@ -681,7 +720,8 @@ rip_reconfigure_iface(struct rip_proto *p, struct rip_iface *ifa, struct rip_ifa
(new->port != old->port) ||
(new->tx_tos != old->tx_tos) ||
(new->tx_priority != old->tx_priority) ||
- (new->ttl_security != old->ttl_security))
+ (new->ttl_security != old->ttl_security) ||
+ (new->demand_circuit != old->demand_circuit))
return 0;
TRACE(D_EVENTS, "Reconfiguring interface %s", ifa->iface->name);
@@ -690,9 +730,21 @@ rip_reconfigure_iface(struct rip_proto *p, struct rip_iface *ifa, struct rip_ifa
rip_iface_update_buffers(ifa);
- if (ifa->next_regular > (current_time() + new->update_time))
+ if ((! ifa->cf->demand_circuit) &&
+ (ifa->next_regular > (current_time() + new->update_time)))
ifa->next_regular = current_time() + (random() % new->update_time) + 100 MS;
+ if (ifa->up && new->demand_circuit && (new->passive != old->passive))
+ {
+ if (new->passive)
+ rip_send_flush(p, ifa);
+ else
+ {
+ rip_send_request(p, ifa);
+ rip_send_table(p, ifa, ifa->addr, 0);
+ }
+ }
+
if (new->check_link != old->check_link)
rip_iface_update_state(ifa);
@@ -885,6 +937,11 @@ rip_timer(timer *t)
/* Handling neighbor expiration */
WALK_LIST(ifa, p->iface_list)
+ {
+ /* No expiration for demand circuit ifaces */
+ if (ifa->cf->demand_circuit)
+ continue;
+
WALK_LIST_DELSAFE(n, nn, ifa->neigh_list)
if (n->last_seen)
{
@@ -895,6 +952,7 @@ rip_timer(timer *t)
else
next = MIN(next, expires);
}
+ }
tm_start(p->timer, MAX(next - now_, 100 MS));
}
@@ -902,7 +960,7 @@ rip_timer(timer *t)
static inline void
rip_kick_timer(struct rip_proto *p)
{
- if (p->timer->expires > (current_time() + 100 MS))
+ if ((p->timer->expires > (current_time() + 100 MS)))
tm_start(p->timer, 100 MS);
}
@@ -931,11 +989,8 @@ rip_iface_timer(timer *t)
if (ifa->tx_active)
{
- if (now_ < (ifa->next_regular + period))
- { tm_start(ifa->timer, 100 MS); return; }
-
- /* We are too late, reset is done by rip_send_table() */
- log(L_WARN "%s: Too slow update on %s, resetting", p->p.name, ifa->iface->name);
+ tm_start(ifa->timer, 100 MS);
+ return;
}
if (now_ >= ifa->next_regular)
@@ -957,13 +1012,17 @@ rip_iface_timer(timer *t)
p->triggered = 0;
}
- tm_start(ifa->timer, ifa->want_triggered ? (1 S) : (ifa->next_regular - now_));
+ if (ifa->want_triggered && (ifa->next_triggered < ifa->next_regular))
+ tm_set(ifa->timer, ifa->next_triggered);
+ else if (ifa->next_regular != TIME_INFINITY)
+ tm_set(ifa->timer, ifa->next_regular);
}
+
static inline void
rip_iface_kick_timer(struct rip_iface *ifa)
{
- if (ifa->timer->expires > (current_time() + 100 MS))
+ if ((! tm_active(ifa->timer)) || (ifa->timer->expires > (current_time() + 100 MS)))
tm_start(ifa->timer, 100 MS);
}
@@ -987,9 +1046,8 @@ rip_trigger_update(struct rip_proto *p)
TRACE(D_EVENTS, "Scheduling triggered updates for %s", ifa->iface->name);
ifa->want_triggered = current_time();
rip_iface_kick_timer(ifa);
+ p->triggered = 1;
}
-
- p->triggered = 1;
}
@@ -1096,6 +1154,20 @@ rip_start(struct proto *P)
}
static int
+rip_shutdown(struct proto *P)
+{
+ struct rip_proto *p = (void *) P;
+
+ TRACE(D_EVENTS, "Shutdown requested");
+
+ struct rip_iface *ifa;
+ WALK_LIST(ifa, p->iface_list)
+ rip_iface_stop(ifa);
+
+ return PS_DOWN;
+}
+
+static int
rip_reconfigure(struct proto *P, struct proto_config *CF)
{
struct rip_proto *p = (void *) P;
@@ -1133,7 +1205,7 @@ rip_get_route_info(rte *rte, byte *buf)
}
static int
-rip_get_attr(eattr *a, byte *buf, int buflen UNUSED)
+rip_get_attr(const eattr *a, byte *buf, int buflen UNUSED)
{
switch (a->id)
{
@@ -1151,7 +1223,7 @@ rip_get_attr(eattr *a, byte *buf, int buflen UNUSED)
}
void
-rip_show_interfaces(struct proto *P, char *iff)
+rip_show_interfaces(struct proto *P, const char *iff)
{
struct rip_proto *p = (void *) P;
struct rip_iface *ifa = NULL;
@@ -1160,7 +1232,6 @@ rip_show_interfaces(struct proto *P, char *iff)
if (p->p.proto_state != PS_UP)
{
cli_msg(-1021, "%s: is not up", p->p.name);
- cli_msg(0, "");
return;
}
@@ -1179,16 +1250,15 @@ rip_show_interfaces(struct proto *P, char *iff)
nbrs++;
btime now_ = current_time();
- btime timer = (ifa->next_regular > now_) ? (ifa->next_regular - now_) : 0;
+ btime timer = ((ifa->next_regular < TIME_INFINITY) && (ifa->next_regular > now_)) ?
+ (ifa->next_regular - now_) : 0;
cli_msg(-1021, "%-10s %-6s %6u %6u %7t",
ifa->iface->name, (ifa->up ? "Up" : "Down"), ifa->cf->metric, nbrs, timer);
}
-
- cli_msg(0, "");
}
void
-rip_show_neighbors(struct proto *P, char *iff)
+rip_show_neighbors(struct proto *P, const char *iff)
{
struct rip_proto *p = (void *) P;
struct rip_iface *ifa = NULL;
@@ -1197,7 +1267,6 @@ rip_show_neighbors(struct proto *P, char *iff)
if (p->p.proto_state != PS_UP)
{
cli_msg(-1022, "%s: is not up", p->p.name);
- cli_msg(0, "");
return;
}
@@ -1220,8 +1289,6 @@ rip_show_neighbors(struct proto *P, char *iff)
n->nbr->addr, ifa->iface->name, ifa->cf->metric, n->uc, timer);
}
}
-
- cli_msg(0, "");
}
static void
@@ -1235,8 +1302,12 @@ rip_dump(struct proto *P)
FIB_WALK(&p->rtable, struct rip_entry, en)
{
debug("RIP: entry #%d: %N via %I dev %s valid %d metric %d age %t\n",
- i++, en->n.addr, en->next_hop, en->iface->name,
+ i++, en->n.addr, en->next_hop, en->iface ? en->iface->name : "(null)",
en->valid, en->metric, current_time() - en->changed);
+
+ for (struct rip_rte *e = en->routes; e; e = e->next)
+ debug("RIP: via %I metric %d expires %t\n",
+ e->next_hop, e->metric, e->expires - current_time());
}
FIB_WALK_END;
@@ -1262,6 +1333,7 @@ struct protocol proto_rip = {
.init = rip_init,
.dump = rip_dump,
.start = rip_start,
+ .shutdown = rip_shutdown,
.reconfigure = rip_reconfigure,
.get_route_info = rip_get_route_info,
.get_attr = rip_get_attr
diff --git a/proto/rip/rip.h b/proto/rip/rip.h
index 2dc34862..8d347000 100644
--- a/proto/rip/rip.h
+++ b/proto/rip/rip.h
@@ -41,6 +41,7 @@
#define RIP_DEFAULT_UPDATE_TIME (30 S_)
#define RIP_DEFAULT_TIMEOUT_TIME (180 S_)
#define RIP_DEFAULT_GARBAGE_TIME (120 S_)
+#define RIP_DEFAULT_RXMT_TIME (1 S_)
struct rip_config
@@ -73,6 +74,7 @@ struct rip_iface_config
u8 auth_type; /* Authentication type (RIP_AUTH_*) */
u8 ttl_security; /* bool + 2 for TX only (send, but do not check on RX) */
u8 check_link; /* Whether iface link change is used */
+ u8 demand_circuit; /* Use demand circuit extensions (RFC 2091) */
u8 bfd; /* Use BFD on iface */
u16 rx_buffer; /* RX buffer size, 0 for MTU */
u16 tx_length; /* TX packet length limit (including headers), 0 for MTU */
@@ -81,6 +83,7 @@ struct rip_iface_config
btime update_time; /* Periodic update interval */
btime timeout_time; /* Route expiration timeout */
btime garbage_time; /* Unreachable entry GC timeout */
+ btime rxmt_time; /* Retransmit timeout for demand circuit */
list *passwords; /* Passwords for authentication */
};
@@ -110,6 +113,7 @@ struct rip_iface
struct rip_iface_config *cf; /* Related config, must be updated in reconfigure */
struct object_lock *lock; /* Interface lock */
timer *timer; /* Interface timer */
+ timer *rxmt_timer; /* Retransmission timer */
sock *sk; /* UDP socket */
u8 up; /* Interface is active */
@@ -126,9 +130,18 @@ struct rip_iface
/* Active update */
int tx_active; /* Update session is active */
+ int tx_waiting;
ip_addr tx_addr; /* Update session destination address */
btime tx_changed; /* Minimal changed time for triggered update */
struct fib_iterator tx_fit; /* FIB iterator in RIP routing table (p.rtable) */
+ struct fib_iterator tx_done; /* FIB iterator for acked routes (p.rtable) */
+
+ /* Update message */
+ u8 tx_pending;
+ u8 tx_flush;
+ u16 tx_seqnum;
+
+ u8 req_pending;
};
struct rip_neighbor
@@ -149,7 +162,7 @@ struct rip_entry
u8 valid; /* Entry validity state (RIP_ENTRY_*) */
u8 metric; /* Outgoing route metric */
u16 tag; /* Outgoing route tag */
- struct iface *from; /* Outgoing route from, NULL if from proto */
+ struct iface *from; /* Outgoing route from, NULL if from proto */
struct iface *iface; /* Outgoing route iface (for next hop) */
ip_addr next_hop; /* Outgoing route next hop */
@@ -197,6 +210,7 @@ rip_reset_tx_session(struct rip_proto *p, struct rip_iface *ifa)
if (ifa->tx_active)
{
FIB_ITERATE_UNLINK(&ifa->tx_fit, &p->rtable);
+ FIB_ITERATE_UNLINK(&ifa->tx_done, &p->rtable);
ifa->tx_active = 0;
}
}
@@ -204,14 +218,17 @@ rip_reset_tx_session(struct rip_proto *p, struct rip_iface *ifa)
/* rip.c */
void rip_update_rte(struct rip_proto *p, net_addr *n, struct rip_rte *new);
void rip_withdraw_rte(struct rip_proto *p, net_addr *n, struct rip_neighbor *from);
+void rip_flush_table(struct rip_proto *p, struct rip_neighbor *n);
struct rip_neighbor * rip_get_neighbor(struct rip_proto *p, ip_addr *a, struct rip_iface *ifa);
void rip_update_bfd(struct rip_proto *p, struct rip_neighbor *n);
-void rip_show_interfaces(struct proto *P, char *iff);
-void rip_show_neighbors(struct proto *P, char *iff);
+void rip_show_interfaces(struct proto *P, const char *iff);
+void rip_show_neighbors(struct proto *P, const char *iff);
/* packets.c */
void rip_send_request(struct rip_proto *p, struct rip_iface *ifa);
void rip_send_table(struct rip_proto *p, struct rip_iface *ifa, ip_addr addr, btime changed);
+int rip_send_flush(struct rip_proto *p, struct rip_iface *ifa);
+void rip_rxmt_timeout(timer *t);
int rip_open_socket(struct rip_iface *ifa);
diff --git a/proto/rpki/config.Y b/proto/rpki/config.Y
index 63c7105c..d6d326b8 100644
--- a/proto/rpki/config.Y
+++ b/proto/rpki/config.Y
@@ -32,7 +32,7 @@ rpki_check_unused_transport(void)
CF_DECLS
CF_KEYWORDS(RPKI, REMOTE, BIRD, PRIVATE, PUBLIC, KEY, TCP, SSH, TRANSPORT, USER,
- RETRY, REFRESH, EXPIRE, KEEP)
+ RETRY, REFRESH, EXPIRE, KEEP, IGNORE, MAX, LENGTH)
%type <i> rpki_keep_interval
@@ -79,6 +79,7 @@ rpki_proto_item:
RPKI_CFG->expire_interval = $3;
RPKI_CFG->keep_expire_interval = $2;
}
+ | IGNORE MAX LENGTH bool { RPKI_CFG->ignore_max_length = $4; }
;
rpki_keep_interval:
@@ -117,9 +118,13 @@ rpki_transport_tcp_init:
rpki_transport_ssh_init:
{
+#if HAVE_LIBSSH
rpki_check_unused_transport();
RPKI_CFG->tr_config.spec = cfg_allocz(sizeof(struct rpki_tr_ssh_config));
RPKI_CFG->tr_config.type = RPKI_TR_SSH;
+#else
+ cf_error("This build doesn't support SSH");
+#endif
};
rpki_transport_ssh_opts:
diff --git a/proto/rpki/packets.c b/proto/rpki/packets.c
index 59a5efaf..dd11f997 100644
--- a/proto/rpki/packets.c
+++ b/proto/rpki/packets.c
@@ -729,12 +729,22 @@ rpki_prefix_pdu_2_net_addr(const struct pdu_header *pdu, net_addr_union *n)
static int
rpki_handle_prefix_pdu(struct rpki_cache *cache, const struct pdu_header *pdu)
{
+ const struct rpki_config *cf = (void *) cache->p->p.cf;
+
const enum pdu_type type = pdu->type;
ASSERT(type == IPV4_PREFIX || type == IPV6_PREFIX);
net_addr_union addr = {};
rpki_prefix_pdu_2_net_addr(pdu, &addr);
+ if (cf->ignore_max_length)
+ {
+ if (type == IPV4_PREFIX)
+ addr.roa4.max_pxlen = IP4_MAX_PREFIX_LENGTH;
+ else
+ addr.roa6.max_pxlen = IP6_MAX_PREFIX_LENGTH;
+ }
+
struct channel *channel = NULL;
if (type == IPV4_PREFIX)
@@ -1011,6 +1021,7 @@ rpki_send_error_pdu(struct rpki_cache *cache, const enum pdu_error_type error_co
{
va_start(args, fmt);
msg_len = bvsnprintf(msg, sizeof(msg), fmt, args) + 1;
+ va_end(args);
}
u32 pdu_size = 16 + err_pdu_len + msg_len;
diff --git a/proto/rpki/rpki.c b/proto/rpki/rpki.c
index 70cd0cdd..799cb877 100644
--- a/proto/rpki/rpki.c
+++ b/proto/rpki/rpki.c
@@ -579,7 +579,9 @@ rpki_init_cache(struct rpki_proto *p, struct rpki_config *cf)
switch (cf->tr_config.type)
{
case RPKI_TR_TCP: rpki_tr_tcp_init(cache->tr_sock); break;
+#if HAVE_LIBSSH
case RPKI_TR_SSH: rpki_tr_ssh_init(cache->tr_sock); break;
+#endif
};
CACHE_DBG(cache, "Connection object created");
@@ -637,18 +639,6 @@ rpki_shutdown(struct proto *P)
* RPKI Reconfiguration
*/
-static int
-rpki_try_fast_reconnect(struct rpki_cache *cache)
-{
- if (cache->state == RPKI_CS_ESTABLISHED)
- {
- rpki_cache_change_state(cache, RPKI_CS_FAST_RECONNECT);
- return SUCCESSFUL_RECONF;
- }
-
- return NEED_RESTART;
-}
-
/**
* rpki_reconfigure_cache - a cache reconfiguration
* @p: RPKI protocol instance
@@ -664,6 +654,7 @@ rpki_try_fast_reconnect(struct rpki_cache *cache)
static int
rpki_reconfigure_cache(struct rpki_proto *p UNUSED, struct rpki_cache *cache, struct rpki_config *new, struct rpki_config *old)
{
+ u8 try_reset = 0;
u8 try_fast_reconnect = 0;
if (strcmp(old->hostname, new->hostname) != 0)
@@ -683,6 +674,14 @@ rpki_reconfigure_cache(struct rpki_proto *p UNUSED, struct rpki_cache *cache, st
CACHE_TRACE(D_EVENTS, cache, "Transport type changed");
return NEED_RESTART;
}
+
+ if (old->ignore_max_length != new->ignore_max_length)
+ {
+ CACHE_TRACE(D_EVENTS, cache, "Ignore max length changed");
+ try_reset = 1;
+ }
+
+#if HAVE_LIBSSH
else if (new->tr_config.type == RPKI_TR_SSH)
{
struct rpki_tr_ssh_config *ssh_old = (void *) old->tr_config.spec;
@@ -695,9 +694,10 @@ rpki_reconfigure_cache(struct rpki_proto *p UNUSED, struct rpki_cache *cache, st
try_fast_reconnect = 1;
}
}
+#endif
#define TEST_INTERVAL(name, Name) \
- if (cache->name##_interval != new->name##_interval || \
+ if (old->name##_interval != new->name##_interval || \
old->keep_##name##_interval != new->keep_##name##_interval) \
{ \
cache->name##_interval = new->name##_interval; \
@@ -709,8 +709,26 @@ rpki_reconfigure_cache(struct rpki_proto *p UNUSED, struct rpki_cache *cache, st
TEST_INTERVAL(expire, Expire);
#undef TEST_INTERVAL
- if (try_fast_reconnect)
- return rpki_try_fast_reconnect(cache);
+ if (try_reset || try_fast_reconnect)
+ {
+ if (cache->state != RPKI_CS_ESTABLISHED)
+ return NEED_RESTART;
+
+ if (try_reset && !try_fast_reconnect)
+ rpki_cache_change_state(cache, RPKI_CS_RESET);
+
+ if (try_fast_reconnect)
+ {
+ if (try_reset)
+ {
+ /* Force reset during reconnect */
+ cache->request_session_id = 1;
+ cache->serial_num = 0;
+ }
+
+ rpki_cache_change_state(cache, RPKI_CS_FAST_RECONNECT);
+ }
+ }
return SUCCESSFUL_RECONF;
}
@@ -813,11 +831,13 @@ rpki_show_proto_info(struct proto *P)
switch (cf->tr_config.type)
{
+#if HAVE_LIBSSH
case RPKI_TR_SSH: transport_name = "SSHv2"; break;
+#endif
case RPKI_TR_TCP: transport_name = "Unprotected over TCP"; break;
};
- cli_msg(-1006, " Cache server: %s", rpki_get_cache_ident(cache));
+ cli_msg(-1006, " Cache server: %s", cf->hostname);
cli_msg(-1006, " Status: %s", rpki_cache_state_to_str(cache->state));
cli_msg(-1006, " Transport: %s", transport_name);
cli_msg(-1006, " Protocol version: %u", cache->version);
@@ -887,9 +907,11 @@ rpki_check_config(struct rpki_config *cf)
/* Set default port numbers */
switch (cf->tr_config.type)
{
+#if HAVE_LIBSSH
case RPKI_TR_SSH:
cf->port = RPKI_SSH_PORT;
break;
+#endif
default:
cf->port = RPKI_TCP_PORT;
}
diff --git a/proto/rpki/rpki.h b/proto/rpki/rpki.h
index 8972b33a..8a5c38fd 100644
--- a/proto/rpki/rpki.h
+++ b/proto/rpki/rpki.h
@@ -125,6 +125,7 @@ struct rpki_config {
u8 keep_refresh_interval:1; /* Do not overwrite refresh interval by cache server update */
u8 keep_retry_interval:1; /* Do not overwrite retry interval by cache server update */
u8 keep_expire_interval:1; /* Do not overwrite expire interval by cache server update */
+ u8 ignore_max_length:1; /* Ignore received max length and use MAX_PREFIX_LENGTH instead */
};
void rpki_check_config(struct rpki_config *cf);
diff --git a/proto/rpki/ssh_transport.c b/proto/rpki/ssh_transport.c
index 13e061fc..6333f367 100644
--- a/proto/rpki/ssh_transport.c
+++ b/proto/rpki/ssh_transport.c
@@ -17,6 +17,8 @@
#include "rpki.h"
+#if HAVE_LIBSSH
+
static int
rpki_tr_ssh_open(struct rpki_tr_sock *tr)
{
@@ -45,17 +47,15 @@ rpki_tr_ssh_ident(struct rpki_tr_sock *tr)
struct rpki_cache *cache = tr->cache;
struct rpki_config *cf = (void *) cache->p->p.cf;
struct rpki_tr_ssh_config *ssh_cf = (void *) cf->tr_config.spec;
+ const char *username = ssh_cf->user;
if (tr->ident != NULL)
return tr->ident;
- const char *username = ssh_cf->user;
- const char *host = cf->hostname;
- u16 port = cf->port;
-
- size_t len = strlen(username) + 1 + strlen(host) + 1 + 5 + 1; /* <user> + '@' + <host> + ':' + <port> + '\0' */
+ /* Length: <user> + '@' + <host> + ' port ' + <port> + '\0' */
+ size_t len = strlen(username) + 1 + strlen(cf->hostname) + 1 + 5 + 1;
char *ident = mb_alloc(cache->pool, len);
- bsnprintf(ident, len, "%s@%s:%u", username, host, port);
+ bsnprintf(ident, len, "%s@%s:%u", username, cf->hostname, cf->port);
tr->ident = ident;
return tr->ident;
@@ -71,3 +71,5 @@ rpki_tr_ssh_init(struct rpki_tr_sock *tr)
tr->open_fp = &rpki_tr_ssh_open;
tr->ident_fp = &rpki_tr_ssh_ident;
}
+
+#endif
diff --git a/proto/rpki/tcp_transport.c b/proto/rpki/tcp_transport.c
index 0d3c7e99..132f8e2d 100644
--- a/proto/rpki/tcp_transport.c
+++ b/proto/rpki/tcp_transport.c
@@ -43,24 +43,12 @@ rpki_tr_tcp_ident(struct rpki_tr_sock *tr)
if (tr->ident != NULL)
return tr->ident;
- const char *host = cf->hostname;
- ip_addr ip = cf->ip;
- u16 port = cf->port;
-
- size_t colon_and_port_len = 6; /* max ":65535" */
- size_t ident_len;
- if (host)
- ident_len = strlen(host) + colon_and_port_len + 1;
- else
- ident_len = IPA_MAX_TEXT_LENGTH + colon_and_port_len + 1;
-
- char *ident = mb_alloc(cache->pool, ident_len);
- if (host)
- bsnprintf(ident, ident_len, "%s:%u", host, port);
- else
- bsnprintf(ident, ident_len, "%I:%u", ip, port);
-
+ /* Length: <host> + ':' + <port> + '\0' */
+ size_t len = strlen(cf->hostname) + 1 + 5 + 1;
+ char *ident = mb_alloc(cache->pool, len);
+ bsnprintf(ident, len, "%s:%u", cf->hostname, cf->port);
tr->ident = ident;
+
return tr->ident;
}
diff --git a/proto/rpki/transport.c b/proto/rpki/transport.c
index 182667be..a1ac7587 100644
--- a/proto/rpki/transport.c
+++ b/proto/rpki/transport.c
@@ -19,14 +19,14 @@
/**
* rpki_hostname_autoresolv - auto-resolve an IP address from a hostname
* @host: domain name of host, e.g. "rpki-validator.realmv6.org"
+ * @err_msg: error message returned in case of errors
*
* This function resolves an IP address from a hostname.
* Returns &ip_addr structure with IP address or |IPA_NONE|.
*/
static ip_addr
-rpki_hostname_autoresolv(const char *host)
+rpki_hostname_autoresolv(const char *host, const char **err_msg)
{
- ip_addr addr = {};
struct addrinfo *res;
struct addrinfo hints = {
.ai_family = AF_UNSPEC,
@@ -34,22 +34,22 @@ rpki_hostname_autoresolv(const char *host)
.ai_flags = AI_ADDRCONFIG,
};
+ *err_msg = NULL;
+
if (!host)
return IPA_NONE;
int err_code = getaddrinfo(host, NULL, &hints, &res);
if (err_code != 0)
{
- log(L_DEBUG "getaddrinfo failed: %s", gai_strerror(err_code));
+ *err_msg = gai_strerror(err_code);
return IPA_NONE;
}
- sockaddr sa = {
- .sa = *res->ai_addr,
- };
-
+ ip_addr addr = IPA_NONE;
uint unused;
- sockaddr_read(&sa, res->ai_family, &addr, NULL, &unused);
+
+ sockaddr_read((sockaddr *) res->ai_addr, res->ai_family, &addr, NULL, &unused);
freeaddrinfo(res);
return addr;
@@ -86,12 +86,15 @@ rpki_tr_open(struct rpki_tr_sock *tr)
sk->tbsize = RPKI_TX_BUFFER_SIZE;
sk->tos = IP_PREC_INTERNET_CONTROL;
- if (ipa_zero2(sk->daddr) && sk->host)
+ if (ipa_zero(sk->daddr) && sk->host)
{
- sk->daddr = rpki_hostname_autoresolv(sk->host);
+ const char *err_msg;
+
+ sk->daddr = rpki_hostname_autoresolv(sk->host, &err_msg);
if (ipa_zero(sk->daddr))
{
- CACHE_TRACE(D_EVENTS, cache, "Cannot resolve the hostname '%s'", sk->host);
+ log(L_ERR "%s: Cannot resolve hostname '%s': %s",
+ cache->p->p.name, sk->host, err_msg);
return RPKI_TR_ERROR;
}
}
diff --git a/proto/rpki/transport.h b/proto/rpki/transport.h
index f90b7e42..bb8d41eb 100644
--- a/proto/rpki/transport.h
+++ b/proto/rpki/transport.h
@@ -51,7 +51,9 @@ const char *rpki_tr_ident(struct rpki_tr_sock *tr);
/* Types of supported transports */
enum rpki_tr_type {
RPKI_TR_TCP, /* Unprotected transport over TCP */
+#if HAVE_LIBSSH
RPKI_TR_SSH, /* Protected transport by SSHv2 connection */
+#endif
};
/* Common configure structure for transports */
diff --git a/proto/static/config.Y b/proto/static/config.Y
index 6e410879..41e10dbf 100644
--- a/proto/static/config.Y
+++ b/proto/static/config.Y
@@ -158,7 +158,7 @@ stat_route_opt_list:
CF_CLI(SHOW STATIC, optproto, [<name>], [[Show details of static protocol]])
-{ static_show(proto_get_named($3, &proto_static)); } ;
+{ PROTO_WALK_CMD($3, &proto_static, p) static_show(p); } ;
CF_CODE
diff --git a/proto/static/static.c b/proto/static/static.c
index c899cc87..661f1aac 100644
--- a/proto/static/static.c
+++ b/proto/static/static.c
@@ -49,11 +49,14 @@
static linpool *static_lp;
+static inline struct rte_src * static_get_source(struct static_proto *p, uint i)
+{ return i ? rt_get_source(&p->p, i) : p->p.main_source; }
+
static void
static_announce_rte(struct static_proto *p, struct static_route *r)
{
rta *a = allocz(RTA_MAX_SIZE);
- a->src = p->p.main_source;
+ a->src = static_get_source(p, r->index);
a->source = RTS_STATIC;
a->scope = SCOPE_UNIVERSE;
a->dest = r->dest;
@@ -103,9 +106,20 @@ static_announce_rte(struct static_proto *p, struct static_route *r)
e->pflags = 0;
if (r->cmds)
+ {
+ /* Create a temporary table node */
+ e->net = alloca(sizeof(net) + r->net->length);
+ memset(e->net, 0, sizeof(net) + r->net->length);
+ net_copy(e->net->n.addr, r->net);
+
+ /* Evaluate the filter */
f_eval_rte(r->cmds, &e, static_lp);
- rte_update(&p->p, r->net, e);
+ /* Remove the temporary node */
+ e->net = NULL;
+ }
+
+ rte_update2(p->p.main_channel, r->net, e, a->src);
r->state = SRS_CLEAN;
if (r->cmds)
@@ -117,7 +131,7 @@ withdraw:
if (r->state == SRS_DOWN)
return;
- rte_update(&p->p, r->net, NULL);
+ rte_update2(p->p.main_channel, r->net, NULL, a->src);
r->state = SRS_DOWN;
}
@@ -135,14 +149,47 @@ static_mark_rte(struct static_proto *p, struct static_route *r)
}
static void
+static_mark_all(struct static_proto *p)
+{
+ struct static_config *cf = (void *) p->p.cf;
+ struct static_route *r;
+
+ /* We want to reload all routes, mark them as dirty */
+
+ WALK_LIST(r, cf->routes)
+ if (r->state == SRS_CLEAN)
+ r->state = SRS_DIRTY;
+
+ p->marked_all = 1;
+ BUFFER_FLUSH(p->marked);
+
+ if (!ev_active(p->event))
+ ev_schedule(p->event);
+}
+
+
+static void
static_announce_marked(void *P)
{
struct static_proto *p = P;
+ struct static_config *cf = (void *) p->p.cf;
+ struct static_route *r;
- BUFFER_WALK(p->marked, r)
- static_announce_rte(P, r);
+ if (p->marked_all)
+ {
+ WALK_LIST(r, cf->routes)
+ if (r->state == SRS_DIRTY)
+ static_announce_rte(p, r);
- BUFFER_FLUSH(p->marked);
+ p->marked_all = 0;
+ }
+ else
+ {
+ BUFFER_WALK(p->marked, r)
+ static_announce_rte(p, r);
+
+ BUFFER_FLUSH(p->marked);
+ }
}
static void
@@ -161,7 +208,7 @@ static_update_bfd(struct static_proto *p, struct static_route *r)
// ip_addr local = ipa_nonzero(r->local) ? r->local : nb->ifa->ip;
r->bfd_req = bfd_request_session(p->p.pool, r->via, nb->ifa->ip,
nb->iface, p->p.vrf,
- static_bfd_notify, r);
+ static_bfd_notify, r, NULL);
}
if (!bfd_up && r->bfd_req)
@@ -250,7 +297,7 @@ static void
static_remove_rte(struct static_proto *p, struct static_route *r)
{
if (r->state)
- rte_update(&p->p, r->net, NULL);
+ rte_update2(p->p.main_channel, r->net, NULL, static_get_source(p, r->index));
static_reset_rte(p, r);
}
@@ -353,12 +400,33 @@ static_bfd_notify(struct bfd_request *req)
static_mark_rte(p, r->mp_head);
}
+static void
+static_reload_routes(struct channel *C)
+{
+ struct static_proto *p = (void *) C->proto;
+
+ TRACE(D_EVENTS, "Scheduling route reload");
+
+ static_mark_all(p);
+}
+
static int
-static_rte_mergable(rte *pri UNUSED, rte *sec UNUSED)
+static_rte_better(rte *new, rte *old)
{
- return 1;
+ u32 n = ea_get_int(new->attrs->eattrs, EA_GEN_IGP_METRIC, IGP_METRIC_UNKNOWN);
+ u32 o = ea_get_int(old->attrs->eattrs, EA_GEN_IGP_METRIC, IGP_METRIC_UNKNOWN);
+ return n < o;
+}
+
+static int
+static_rte_mergable(rte *pri, rte *sec)
+{
+ u32 a = ea_get_int(pri->attrs->eattrs, EA_GEN_IGP_METRIC, IGP_METRIC_UNKNOWN);
+ u32 b = ea_get_int(sec->attrs->eattrs, EA_GEN_IGP_METRIC, IGP_METRIC_UNKNOWN);
+ return a == b;
}
+static void static_index_routes(struct static_config *cf);
static void
static_postconfig(struct proto_config *CF)
@@ -382,6 +450,8 @@ static_postconfig(struct proto_config *CF)
WALK_LIST(r, cf->routes)
if (r->net && (r->net->type != CF->net_type))
cf_error("Route %N incompatible with channel type", r->net);
+
+ static_index_routes(cf);
}
static struct proto *
@@ -394,6 +464,8 @@ static_init(struct proto_config *CF)
P->main_channel = proto_add_channel(P, proto_cf_main_channel(CF));
P->neigh_notify = static_neigh_notify;
+ P->reload_routes = static_reload_routes;
+ P->rte_better = static_rte_better;
P->rte_mergable = static_rte_mergable;
if (cf->igp_table_ip4)
@@ -463,7 +535,7 @@ static_cleanup(struct proto *P)
static void
static_dump_rte(struct static_route *r)
{
- debug("%-1N: ", r->net);
+ debug("%-1N (%u): ", r->net, r->index);
if (r->dest == RTD_UNICAST)
if (r->iface && ipa_zero(r->via))
debug("dev %s\n", r->iface->name);
@@ -486,11 +558,48 @@ static_dump(struct proto *P)
#define IGP_TABLE(cf, sym) ((cf)->igp_table_##sym ? (cf)->igp_table_##sym ->table : NULL )
-static inline int
-static_cmp_rte(const void *X, const void *Y)
+static inline int srt_equal(const struct static_route *a, const struct static_route *b)
+{ return net_equal(a->net, b->net) && (a->index == b->index); }
+
+static inline int srt_compare(const struct static_route *a, const struct static_route *b)
+{ return net_compare(a->net, b->net) ?: uint_cmp(a->index, b->index); }
+
+static inline int srt_compare_qsort(const void *A, const void *B)
+{
+ return srt_compare(*(const struct static_route * const *)A,
+ *(const struct static_route * const *)B);
+}
+
+static void
+static_index_routes(struct static_config *cf)
{
- struct static_route *x = *(void **)X, *y = *(void **)Y;
- return net_compare(x->net, y->net);
+ struct static_route *rt, **buf;
+ uint num, i, v;
+
+ num = list_length(&cf->routes);
+ buf = xmalloc(num * sizeof(void *));
+
+ /* Initialize with sequential indexes to ensure stable sorting */
+ i = 0;
+ WALK_LIST(rt, cf->routes)
+ {
+ buf[i] = rt;
+ rt->index = i++;
+ }
+
+ qsort(buf, num, sizeof(struct static_route *), srt_compare_qsort);
+
+ /* Compute proper indexes - sequential for routes with same network */
+ for (i = 0, v = 0, rt = NULL; i < num; i++, v++)
+ {
+ if (rt && !net_equal(buf[i]->net, rt->net))
+ v = 0;
+
+ rt = buf[i];
+ rt->index = v;
+ }
+
+ xfree(buf);
}
static int
@@ -519,7 +628,7 @@ static_reconfigure(struct proto *P, struct proto_config *CF)
/* Reconfigure initial matching sequence */
for (or = HEAD(o->routes), nr = HEAD(n->routes);
- NODE_VALID(or) && NODE_VALID(nr) && net_equal(or->net, nr->net);
+ NODE_VALID(or) && NODE_VALID(nr) && srt_equal(or, nr);
or = NODE_NEXT(or), nr = NODE_NEXT(nr))
static_reconfigure_rte(p, or, nr);
@@ -545,12 +654,12 @@ static_reconfigure(struct proto *P, struct proto_config *CF)
for (i = 0, nr2 = nr; i < nrnum; i++, nr2 = NODE_NEXT(nr2))
nrbuf[i] = nr2;
- qsort(orbuf, ornum, sizeof(struct static_route *), static_cmp_rte);
- qsort(nrbuf, nrnum, sizeof(struct static_route *), static_cmp_rte);
+ qsort(orbuf, ornum, sizeof(struct static_route *), srt_compare_qsort);
+ qsort(nrbuf, nrnum, sizeof(struct static_route *), srt_compare_qsort);
while ((orpos < ornum) && (nrpos < nrnum))
{
- int x = net_compare(orbuf[orpos]->net, nrbuf[nrpos]->net);
+ int x = srt_compare(orbuf[orpos], nrbuf[nrpos]);
if (x < 0)
static_remove_rte(p, orbuf[orpos++]);
else if (x > 0)
@@ -568,6 +677,10 @@ static_reconfigure(struct proto *P, struct proto_config *CF)
xfree(orbuf);
xfree(nrbuf);
+ /* All dirty routes were announced anyways */
+ BUFFER_FLUSH(p->marked);
+ p->marked_all = 0;
+
return 1;
}
@@ -589,6 +702,7 @@ static_copy_config(struct proto_config *dest, struct proto_config *src)
{
dnh = cfg_alloc(sizeof(struct static_route));
memcpy(dnh, snh, sizeof(struct static_route));
+ memset(&dnh->n, 0, sizeof(node));
if (!drt)
add_tail(&d->routes, &(dnh->n));
@@ -603,6 +717,16 @@ static_copy_config(struct proto_config *dest, struct proto_config *src)
}
static void
+static_get_route_info(rte *rte, byte *buf)
+{
+ eattr *a = ea_find(rte->attrs->eattrs, EA_GEN_IGP_METRIC);
+ if (a)
+ buf += bsprintf(buf, " (%d/%u)", rte->pref, a->u.data);
+ else
+ buf += bsprintf(buf, " (%d)", rte->pref);
+}
+
+static void
static_show_rt(struct static_route *r)
{
switch (r->dest)
@@ -647,7 +771,6 @@ static_show(struct proto *P)
WALK_LIST(r, c->routes)
static_show_rt(r);
- cli_msg(0, "");
}
@@ -666,5 +789,6 @@ struct protocol proto_static = {
.shutdown = static_shutdown,
.cleanup = static_cleanup,
.reconfigure = static_reconfigure,
- .copy_config = static_copy_config
+ .copy_config = static_copy_config,
+ .get_route_info = static_get_route_info,
};
diff --git a/proto/static/static.h b/proto/static/static.h
index f736996c..fc91f71c 100644
--- a/proto/static/static.h
+++ b/proto/static/static.h
@@ -26,6 +26,7 @@ struct static_proto {
struct event *event; /* Event for announcing updated routes */
BUFFER_(struct static_route *) marked; /* Routes marked for reannouncement */
+ int marked_all; /* All routes are marked */
rtable *igp_table_ip4; /* Table for recursive IPv4 next hop lookups */
rtable *igp_table_ip6; /* Table for recursive IPv6 next hop lookups */
};
@@ -40,6 +41,7 @@ struct static_route {
struct static_route *mp_head; /* First nexthop of this route */
struct static_route *mp_next; /* Nexthops for multipath routes */
struct f_line *cmds; /* List of commands for setting attributes */
+ uint index; /* Distinguish different routes with same net */
byte dest; /* Destination type (RTD_*) */
byte state; /* State of route announcement (SRS_*) */
byte active; /* Next hop is active (nbr/iface/BFD available) */
diff --git a/sysdep/autoconf.h.in b/sysdep/autoconf.h.in
index a424e020..1856967d 100644
--- a/sysdep/autoconf.h.in
+++ b/sysdep/autoconf.h.in
@@ -42,6 +42,9 @@
/* Define to 1 if debugging is enabled */
#undef DEBUGGING
+/* Define to 1 if you want to run expensive consistency checks. */
+#undef ENABLE_EXPENSIVE_CHECKS
+
/* Define to 1 if you have the <alloca.h> header file. */
#undef HAVE_ALLOCA_H
@@ -63,9 +66,6 @@
/* Define to 1 if you have the `ssh' library (-lssh). */
#undef HAVE_LIBSSH
-/* Define to 1 if you have the <memory.h> header file. */
-#undef HAVE_MEMORY_H
-
/* Define to 1 if kernel is MPLS capable */
#undef HAVE_MPLS_KERNEL
@@ -84,13 +84,15 @@
/* Define to 1 if you have the <stdint.h> header file. */
#undef HAVE_STDINT_H
-/* Define to 1 if you have the <stdlib.h> header file. */
+/* Always define to 1, for backward compatibility. You can assume <stdlib.h>
+ exists. */
#undef HAVE_STDLIB_H
/* Define to 1 if you have the <strings.h> header file. */
#undef HAVE_STRINGS_H
-/* Define to 1 if you have the <string.h> header file. */
+/* Always define to 1, for backward compatibility. You can assume <string.h>
+ exists. */
#undef HAVE_STRING_H
/* Define to 1 if `sa_len' is a member of `struct sockaddr'. */
@@ -129,7 +131,8 @@
/* Define to the version of this package. */
#undef PACKAGE_VERSION
-/* Define to 1 if you have the ANSI C header files. */
+/* Always define to 1, for backward compatibility. You can assume the C90
+ standard headers exist. */
#undef STDC_HEADERS
/* Which sysdep header to include */
diff --git a/sysdep/bsd/krt-sock.c b/sysdep/bsd/krt-sock.c
index e646c414..c2faa23d 100644
--- a/sysdep/bsd/krt-sock.c
+++ b/sysdep/bsd/krt-sock.c
@@ -357,10 +357,13 @@ krt_replace_rte(struct krt_proto *p, net *n, rte *new, rte *old)
if (new)
err = krt_send_route(p, RTM_ADD, new);
- if (err < 0)
- n->n.flags |= KRF_SYNC_ERROR;
- else
- n->n.flags &= ~KRF_SYNC_ERROR;
+ if (new)
+ {
+ if (err < 0)
+ bmap_clear(&p->sync_map, new->id);
+ else
+ bmap_set(&p->sync_map, new->id);
+ }
}
#define SKIP(ARG...) do { DBG("KRT: Ignoring route - " ARG); return; } while(0)
diff --git a/sysdep/bsd/krt-sys.h b/sysdep/bsd/krt-sys.h
index aa6cc72e..57501884 100644
--- a/sysdep/bsd/krt-sys.h
+++ b/sysdep/bsd/krt-sys.h
@@ -46,7 +46,7 @@ static inline void krt_sys_io_init(void) { }
static inline void krt_sys_init(struct krt_proto *p UNUSED) { }
static inline void krt_sys_postconfig(struct krt_config *x UNUSED) { }
-static inline int krt_sys_get_attr(eattr *a UNUSED, byte *buf UNUSED, int buflen UNUSED) { return GA_UNKNOWN; }
+static inline int krt_sys_get_attr(const eattr *a UNUSED, byte *buf UNUSED, int buflen UNUSED) { return GA_UNKNOWN; }
#endif
diff --git a/sysdep/bsd/setkey.h b/sysdep/bsd/setkey.h
index 8a1bc9ad..b7a11283 100644
--- a/sysdep/bsd/setkey.h
+++ b/sysdep/bsd/setkey.h
@@ -63,7 +63,7 @@ setkey_send(struct sadb_msg *msg, uint len)
* operations to implement replace.
*/
static int
-setkey_md5(sockaddr *src, sockaddr *dst, uint pxlen, char *passwd, uint type)
+setkey_md5(sockaddr *src, uint slen, sockaddr *dst, uint dlen, const char *passwd, uint type)
{
uint passwd_len = passwd ? strlen(passwd) : 0;
@@ -122,7 +122,7 @@ setkey_md5(sockaddr *src, sockaddr *dst, uint pxlen, char *passwd, uint type)
saddr->sadb_address_len = PFKEY_UNIT64(len);
saddr->sadb_address_exttype = SADB_EXT_ADDRESS_SRC;
saddr->sadb_address_proto = IPSEC_ULPROTO_ANY;
- saddr->sadb_address_prefixlen = pxlen;
+ saddr->sadb_address_prefixlen = slen;
memcpy(pos + sizeof(struct sadb_address), &src->sa, src->sa.sa_len);
pos += len;
@@ -132,7 +132,7 @@ setkey_md5(sockaddr *src, sockaddr *dst, uint pxlen, char *passwd, uint type)
daddr->sadb_address_len = PFKEY_UNIT64(len);
daddr->sadb_address_exttype = SADB_EXT_ADDRESS_DST;
daddr->sadb_address_proto = IPSEC_ULPROTO_ANY;
- daddr->sadb_address_prefixlen = pxlen;
+ daddr->sadb_address_prefixlen = dlen;
memcpy(pos + sizeof(struct sadb_address), &dst->sa, dst->sa.sa_len);
pos += len;
@@ -146,13 +146,15 @@ setkey_md5(sockaddr *src, sockaddr *dst, uint pxlen, char *passwd, uint type)
* Manipulation with the IPsec SA/SP database
*/
static int
-sk_set_md5_in_sasp_db(sock *s, ip_addr local, ip_addr remote, struct iface *ifa, char *passwd)
+sk_set_md5_in_sasp_db(sock *s, ip_addr local, ip_addr remote, int pxlen, struct iface *ifa, const char *passwd)
{
sockaddr src, dst;
sockaddr_fill(&src, s->af, local, ifa, 0);
sockaddr_fill(&dst, s->af, remote, ifa, 0);
- uint pxlen = (s->af == AF_INET) ? IP4_MAX_PREFIX_LENGTH : IP6_MAX_PREFIX_LENGTH;
+ uint maxlen = (s->af == AF_INET) ? IP4_MAX_PREFIX_LENGTH : IP6_MAX_PREFIX_LENGTH;
+ uint slen = maxlen;
+ uint dlen = (pxlen < 0) ? maxlen : pxlen;
if (passwd && *passwd)
{
@@ -160,14 +162,14 @@ sk_set_md5_in_sasp_db(sock *s, ip_addr local, ip_addr remote, struct iface *ifa,
if (len > TCP_KEYLEN_MAX)
ERR_MSG("The password for TCP MD5 Signature is too long");
- if ((setkey_md5(&src, &dst, pxlen, passwd, SADB_ADD) < 0) ||
- (setkey_md5(&dst, &src, pxlen, passwd, SADB_ADD) < 0))
+ if ((setkey_md5(&src, slen, &dst, dlen, passwd, SADB_ADD) < 0) ||
+ (setkey_md5(&dst, dlen, &src, slen, passwd, SADB_ADD) < 0))
ERR_MSG("Cannot add TCP-MD5 password into the IPsec SA/SP database");
}
else
{
- if ((setkey_md5(&src, &dst, pxlen, NULL, SADB_DELETE) < 0) ||
- (setkey_md5(&dst, &src, pxlen, NULL, SADB_DELETE) < 0))
+ if ((setkey_md5(&src, slen, &dst, dlen, NULL, SADB_DELETE) < 0) ||
+ (setkey_md5(&dst, dlen, &src, slen, NULL, SADB_DELETE) < 0))
ERR_MSG("Cannot delete TCP-MD5 password from the IPsec SA/SP database");
}
return 0;
diff --git a/sysdep/bsd/sysio.h b/sysdep/bsd/sysio.h
index a5d161ba..c757960a 100644
--- a/sysdep/bsd/sysio.h
+++ b/sysdep/bsd/sysio.h
@@ -210,11 +210,11 @@ sk_prepare_ip_header(sock *s, void *hdr, int dlen)
#endif
int
-sk_set_md5_auth(sock *s, ip_addr local UNUSED, ip_addr remote UNUSED, struct iface *ifa UNUSED, char *passwd, int setkey UNUSED)
+sk_set_md5_auth(sock *s, ip_addr local UNUSED, ip_addr remote UNUSED, int pxlen UNUSED, struct iface *ifa UNUSED, const char *passwd, int setkey UNUSED)
{
#ifdef USE_MD5SIG_SETKEY
if (setkey)
- if (sk_set_md5_in_sasp_db(s, local, remote, ifa, passwd) < 0)
+ if (sk_set_md5_in_sasp_db(s, local, remote, pxlen, ifa, passwd) < 0)
return -1;
#endif
diff --git a/sysdep/config.h b/sysdep/config.h
index fee1e7d1..55be90f0 100644
--- a/sysdep/config.h
+++ b/sysdep/config.h
@@ -13,7 +13,7 @@
#ifdef GIT_LABEL
#define BIRD_VERSION XSTR1(GIT_LABEL)
#else
-#define BIRD_VERSION "2.0.7"
+#define BIRD_VERSION "2.0.8"
#endif
/* Include parameters determined by configure script */
diff --git a/sysdep/linux/netlink.c b/sysdep/linux/netlink.c
index 10e9a18b..fdf3f2db 100644
--- a/sysdep/linux/netlink.c
+++ b/sysdep/linux/netlink.c
@@ -113,6 +113,8 @@ struct nl_parse_state
u8 krt_type;
u8 krt_proto;
u32 krt_metric;
+
+ u32 rta_flow; /* Used during parsing */
};
/*
@@ -171,6 +173,7 @@ nl_send(struct nl_sock *nl, struct nlmsghdr *nh)
sa.nl_family = AF_NETLINK;
nh->nlmsg_pid = 0;
nh->nlmsg_seq = ++(nl->seq);
+ nh->nlmsg_len = NLMSG_ALIGN(nh->nlmsg_len);
if (sendto(nl->fd, nh, nh->nlmsg_len, 0, (struct sockaddr *)&sa, sizeof(sa)) < 0)
die("rtnetlink sendto: %m");
nl->last_hdr = NULL;
@@ -343,17 +346,26 @@ static struct nl_want_attrs ifa_attr_want6[BIRD_IFA_MAX] = {
static struct nl_want_attrs nexthop_attr_want4[BIRD_RTA_MAX] = {
[RTA_GATEWAY] = { 1, 1, sizeof(ip4_addr) },
+ [RTA_VIA] = { 1, 0, 0 },
+ [RTA_FLOW] = { 1, 1, sizeof(u32) },
[RTA_ENCAP_TYPE]= { 1, 1, sizeof(u16) },
[RTA_ENCAP] = { 1, 0, 0 },
};
static struct nl_want_attrs nexthop_attr_want6[BIRD_RTA_MAX] = {
[RTA_GATEWAY] = { 1, 1, sizeof(ip6_addr) },
+ [RTA_VIA] = { 1, 0, 0 },
+ [RTA_FLOW] = { 1, 1, sizeof(u32) },
[RTA_ENCAP_TYPE]= { 1, 1, sizeof(u16) },
[RTA_ENCAP] = { 1, 0, 0 },
};
#ifdef HAVE_MPLS_KERNEL
+static struct nl_want_attrs nexthop_attr_want_mpls[BIRD_RTA_MAX] = {
+ [RTA_VIA] = { 1, 0, 0 },
+ [RTA_NEWDST] = { 1, 0, 0 },
+};
+
static struct nl_want_attrs encap_mpls_want[BIRD_RTA_MAX] = {
[RTA_DST] = { 1, 0, 0 },
};
@@ -369,6 +381,7 @@ static struct nl_want_attrs rtm_attr_want4[BIRD_RTA_MAX] = {
[RTA_MULTIPATH] = { 1, 0, 0 },
[RTA_FLOW] = { 1, 1, sizeof(u32) },
[RTA_TABLE] = { 1, 1, sizeof(u32) },
+ [RTA_VIA] = { 1, 0, 0 },
[RTA_ENCAP_TYPE]= { 1, 1, sizeof(u16) },
[RTA_ENCAP] = { 1, 0, 0 },
};
@@ -385,6 +398,7 @@ static struct nl_want_attrs rtm_attr_want6[BIRD_RTA_MAX] = {
[RTA_MULTIPATH] = { 1, 0, 0 },
[RTA_FLOW] = { 1, 1, sizeof(u32) },
[RTA_TABLE] = { 1, 1, sizeof(u32) },
+ [RTA_VIA] = { 1, 0, 0 },
[RTA_ENCAP_TYPE]= { 1, 1, sizeof(u16) },
[RTA_ENCAP] = { 1, 0, 0 },
};
@@ -396,6 +410,7 @@ static struct nl_want_attrs rtm_attr_want_mpls[BIRD_RTA_MAX] = {
[RTA_OIF] = { 1, 1, sizeof(u32) },
[RTA_PRIORITY] = { 1, 1, sizeof(u32) },
[RTA_METRICS] = { 1, 0, 0 },
+ [RTA_MULTIPATH] = { 1, 0, 0 },
[RTA_FLOW] = { 1, 1, sizeof(u32) },
[RTA_TABLE] = { 1, 1, sizeof(u32) },
[RTA_VIA] = { 1, 0, 0 },
@@ -622,10 +637,12 @@ nl_add_nexthop(struct nlmsghdr *h, uint bufsize, struct nexthop *nh, int af UNUS
nl_add_attr_mpls_encap(h, bufsize, nh->labels, nh->label);
if (ipa_nonzero(nh->gw))
- if (af == AF_MPLS)
- nl_add_attr_via(h, bufsize, nh->gw);
- else
+ {
+ if (af == (ipa_is_ip4(nh->gw) ? AF_INET : AF_INET6))
nl_add_attr_ipa(h, bufsize, RTA_GATEWAY, nh->gw);
+ else
+ nl_add_attr_via(h, bufsize, nh->gw);
+ }
#else
if (ipa_nonzero(nh->gw))
@@ -634,9 +651,10 @@ nl_add_nexthop(struct nlmsghdr *h, uint bufsize, struct nexthop *nh, int af UNUS
}
static void
-nl_add_multipath(struct nlmsghdr *h, uint bufsize, struct nexthop *nh, int af)
+nl_add_multipath(struct nlmsghdr *h, uint bufsize, struct nexthop *nh, int af, ea_list *eattrs)
{
struct rtattr *a = nl_open_attr(h, bufsize, RTA_MULTIPATH);
+ eattr *flow = ea_find(eattrs, EA_KRT_REALM);
for (; nh; nh = nh->next)
{
@@ -651,6 +669,11 @@ nl_add_multipath(struct nlmsghdr *h, uint bufsize, struct nexthop *nh, int af)
if (nh->flags & RNF_ONLINK)
rtnh->rtnh_flags |= RTNH_F_ONLINK;
+ /* Our KRT_REALM is per-route, but kernel RTA_FLOW is per-nexthop.
+ Therefore, we need to attach the same attribute to each nexthop. */
+ if (flow)
+ nl_add_attr_u32(h, bufsize, RTA_FLOW, flow->u.data);
+
nl_close_nexthop(h, rtnh);
}
@@ -674,6 +697,9 @@ nl_parse_multipath(struct nl_parse_state *s, struct krt_proto *p, struct rtattr
if ((len < sizeof(*nh)) || (len < nh->rtnh_len))
return NULL;
+ if (nh->rtnh_flags & RTNH_F_DEAD)
+ goto next;
+
*last = rv = lp_allocz(s->pool, NEXTHOP_MAX_SIZE);
last = &(rv->next);
@@ -696,14 +722,34 @@ nl_parse_multipath(struct nl_parse_state *s, struct krt_proto *p, struct rtattr
return NULL;
break;
+#ifdef HAVE_MPLS_KERNEL
+ case AF_MPLS:
+ if (!nl_parse_attrs(RTNH_DATA(nh), nexthop_attr_want_mpls, a, sizeof(a)))
+ return NULL;
+
+ if (a[RTA_NEWDST])
+ rv->labels = rta_get_mpls(a[RTA_NEWDST], rv->label);
+
+ break;
+#endif
+
default:
return NULL;
}
if (a[RTA_GATEWAY])
- {
- rv->gw = rta_get_ipa(a[RTA_GATEWAY]);
+ rv->gw = rta_get_ipa(a[RTA_GATEWAY]);
+
+ if (a[RTA_FLOW])
+ s->rta_flow = rta_get_u32(a[RTA_FLOW]);
+#ifdef HAVE_MPLS_KERNEL
+ if (a[RTA_VIA])
+ rv->gw = rta_get_via(a[RTA_VIA]);
+#endif
+
+ if (ipa_nonzero(rv->gw))
+ {
if (nh->rtnh_flags & RTNH_F_ONLINK)
rv->flags |= RNF_ONLINK;
@@ -713,8 +759,6 @@ nl_parse_multipath(struct nl_parse_state *s, struct krt_proto *p, struct rtattr
if (!nbr || (nbr->scope == SCOPE_HOST))
return NULL;
}
- else
- rv->gw = IPA_NONE;
#ifdef HAVE_MPLS_KERNEL
if (a[RTA_ENCAP] && a[RTA_ENCAP_TYPE])
@@ -731,7 +775,7 @@ nl_parse_multipath(struct nl_parse_state *s, struct krt_proto *p, struct rtattr
}
#endif
-
+ next:
len -= NLMSG_ALIGN(nh->rtnh_len);
nh = RTNH_NEXT(nh);
}
@@ -942,18 +986,15 @@ nl_parse_addr4(struct ifaddrmsg *i, int scan, int new)
if (i->ifa_prefixlen == IP4_MAX_PREFIX_LENGTH - 2)
ifa.opposite = ipa_opposite_m2(ifa.ip);
- if ((ifi->flags & IF_BROADCAST) && a[IFA_BROADCAST])
- {
- ip4_addr xbrd = rta_get_ip4(a[IFA_BROADCAST]);
- ip4_addr ybrd = ip4_or(ipa_to_ip4(ifa.ip), ip4_not(ip4_mkmask(i->ifa_prefixlen)));
-
- if (ip4_equal(xbrd, net4_prefix(&ifa.prefix)) || ip4_equal(xbrd, ybrd))
- ifa.brd = ipa_from_ip4(xbrd);
- else if (ifi->flags & IF_TMP_DOWN) /* Complain only during the first scan */
- {
- log(L_ERR "KIF: Invalid broadcast address %I4 for %s", xbrd, ifi->name);
- ifa.brd = ipa_from_ip4(ybrd);
- }
+ if (ifi->flags & IF_BROADCAST)
+ {
+ /* If kernel offers us a broadcast address, we trust it */
+ if (a[IFA_BROADCAST])
+ ifa.brd = ipa_from_ip4(rta_get_ip4(a[IFA_BROADCAST]));
+ /* Otherwise we create one (except for /31) */
+ else if (i->ifa_prefixlen < (IP4_MAX_PREFIX_LENGTH - 1))
+ ifa.brd = ipa_from_ip4(ip4_or(ipa_to_ip4(ifa.ip),
+ ip4_not(ip4_mkmask(i->ifa_prefixlen))));
}
}
@@ -1314,7 +1355,7 @@ dest:
case RTD_UNICAST:
r->r.rtm_type = RTN_UNICAST;
if (nh->next && !krt_ecmp6(p))
- nl_add_multipath(&r->h, rsize, nh, p->af);
+ nl_add_multipath(&r->h, rsize, nh, p->af, eattrs);
else
{
nl_add_attr_u32(&r->h, rsize, RTA_OIF, nh->iface->index);
@@ -1388,7 +1429,7 @@ nl_replace_rte(struct krt_proto *p, rte *e)
void
-krt_replace_rte(struct krt_proto *p, net *n, rte *new, rte *old)
+krt_replace_rte(struct krt_proto *p, net *n UNUSED, rte *new, rte *old)
{
int err = 0;
@@ -1417,10 +1458,13 @@ krt_replace_rte(struct krt_proto *p, net *n, rte *new, rte *old)
err = nl_add_rte(p, new);
}
- if (err < 0)
- n->n.flags |= KRF_SYNC_ERROR;
- else
- n->n.flags &= ~KRF_SYNC_ERROR;
+ if (new)
+ {
+ if (err < 0)
+ bmap_clear(&p->sync_map, new->id);
+ else
+ bmap_set(&p->sync_map, new->id);
+ }
}
static int
@@ -1619,6 +1663,11 @@ nl_parse_route(struct nl_parse_state *s, struct nlmsghdr *h)
ra->source = RTS_INHERIT;
ra->scope = SCOPE_UNIVERSE;
+ if (a[RTA_FLOW])
+ s->rta_flow = rta_get_u32(a[RTA_FLOW]);
+ else
+ s->rta_flow = 0;
+
switch (i->rtm_type)
{
case RTN_UNICAST:
@@ -1637,6 +1686,9 @@ nl_parse_route(struct nl_parse_state *s, struct nlmsghdr *h)
break;
}
+ if (i->rtm_flags & RTNH_F_DEAD)
+ return;
+
ra->nh.iface = if_find_by_index(oif);
if (!ra->nh.iface)
{
@@ -1644,19 +1696,16 @@ nl_parse_route(struct nl_parse_state *s, struct nlmsghdr *h)
return;
}
- if ((i->rtm_family != AF_MPLS) && a[RTA_GATEWAY]
-#ifdef HAVE_MPLS_KERNEL
- || (i->rtm_family == AF_MPLS) && a[RTA_VIA]
-#endif
- )
- {
+ if (a[RTA_GATEWAY])
+ ra->nh.gw = rta_get_ipa(a[RTA_GATEWAY]);
+
#ifdef HAVE_MPLS_KERNEL
- if (i->rtm_family == AF_MPLS)
- ra->nh.gw = rta_get_via(a[RTA_VIA]);
- else
+ if (a[RTA_VIA])
+ ra->nh.gw = rta_get_via(a[RTA_VIA]);
#endif
- ra->nh.gw = rta_get_ipa(a[RTA_GATEWAY]);
+ if (ipa_nonzero(ra->nh.gw))
+ {
/* Silently skip strange 6to4 routes */
const net_addr_ip6 sit = NET_ADDR_IP6(IP6_NONE, 96);
if ((i->rtm_family == AF_INET6) && ipa_in_netX(ra->nh.gw, (net_addr *) &sit))
@@ -1748,7 +1797,8 @@ nl_parse_route(struct nl_parse_state *s, struct nlmsghdr *h)
ea->attrs[0].u.ptr = ad;
}
- if (a[RTA_FLOW])
+ /* Can be set per-route or per-nexthop */
+ if (s->rta_flow)
{
ea_list *ea = lp_alloc(s->pool, sizeof(ea_list) + sizeof(eattr));
ea->next = ra->eattrs;
@@ -1758,7 +1808,7 @@ nl_parse_route(struct nl_parse_state *s, struct nlmsghdr *h)
ea->attrs[0].id = EA_KRT_REALM;
ea->attrs[0].flags = 0;
ea->attrs[0].type = EAF_TYPE_INT;
- ea->attrs[0].u.data = rta_get_u32(a[RTA_FLOW]);
+ ea->attrs[0].u.data = s->rta_flow;
}
if (a[RTA_METRICS])
@@ -2057,7 +2107,7 @@ static const char *krt_features_names[KRT_FEATURES_MAX] = {
};
int
-krt_sys_get_attr(eattr *a, byte *buf, int buflen UNUSED)
+krt_sys_get_attr(const eattr *a, byte *buf, int buflen UNUSED)
{
switch (a->id)
{
diff --git a/sysdep/linux/sysio.h b/sysdep/linux/sysio.h
index b1cc25dc..e21ff487 100644
--- a/sysdep/linux/sysio.h
+++ b/sysdep/linux/sysio.h
@@ -6,35 +6,28 @@
* Can be freely distributed and used under the terms of the GNU GPL.
*/
-
-#ifndef IP_MINTTL
-#define IP_MINTTL 21
-#endif
-
-#ifndef IPV6_TCLASS
-#define IPV6_TCLASS 67
-#endif
-
#ifndef IPV6_MINHOPCOUNT
#define IPV6_MINHOPCOUNT 73
#endif
+#ifndef TCP_MD5SIG_EXT
+#define TCP_MD5SIG_EXT 32
+#endif
-#ifndef TCP_MD5SIG
-
-#define TCP_MD5SIG 14
-#define TCP_MD5SIG_MAXKEYLEN 80
+#ifndef TCP_MD5SIG_FLAG_PREFIX
+#define TCP_MD5SIG_FLAG_PREFIX 1
+#endif
-struct tcp_md5sig {
- struct sockaddr_storage tcpm_addr; /* address associated */
- u16 __tcpm_pad1; /* zero */
- u16 tcpm_keylen; /* key length */
- u32 __tcpm_pad2; /* zero */
- u8 tcpm_key[TCP_MD5SIG_MAXKEYLEN]; /* key (binary) */
+/* We redefine the tcp_md5sig structure with different name to avoid collision with older headers */
+struct tcp_md5sig_ext {
+ struct sockaddr_storage tcpm_addr; /* Address associated */
+ u8 tcpm_flags; /* Extension flags */
+ u8 tcpm_prefixlen; /* Address prefix */
+ u16 tcpm_keylen; /* Key length */
+ u32 __tcpm_pad2; /* Zero */
+ u8 tcpm_key[TCP_MD5SIG_MAXKEYLEN]; /* Key (binary) */
};
-#endif
-
/* Linux does not care if sa_len is larger than needed */
#define SA_LEN(x) sizeof(sockaddr)
@@ -169,9 +162,9 @@ sk_prepare_cmsgs4(sock *s, struct msghdr *msg, void *cbuf, size_t cbuflen)
*/
int
-sk_set_md5_auth(sock *s, ip_addr local UNUSED, ip_addr remote, struct iface *ifa, char *passwd, int setkey UNUSED)
+sk_set_md5_auth(sock *s, ip_addr local UNUSED, ip_addr remote, int pxlen, struct iface *ifa, const char *passwd, int setkey UNUSED)
{
- struct tcp_md5sig md5;
+ struct tcp_md5sig_ext md5;
memset(&md5, 0, sizeof(md5));
sockaddr_fill((sockaddr *) &md5.tcpm_addr, s->af, remote, ifa, 0);
@@ -187,12 +180,26 @@ sk_set_md5_auth(sock *s, ip_addr local UNUSED, ip_addr remote, struct iface *ifa
memcpy(&md5.tcpm_key, passwd, len);
}
- if (setsockopt(s->fd, SOL_TCP, TCP_MD5SIG, &md5, sizeof(md5)) < 0)
+ if (pxlen < 0)
{
- if (errno == ENOPROTOOPT)
- ERR_MSG("Kernel does not support TCP MD5 signatures");
- else
- ERR("TCP_MD5SIG");
+ if (setsockopt(s->fd, SOL_TCP, TCP_MD5SIG, &md5, sizeof(md5)) < 0)
+ if (errno == ENOPROTOOPT)
+ ERR_MSG("Kernel does not support TCP MD5 signatures");
+ else
+ ERR("TCP_MD5SIG");
+ }
+ else
+ {
+ md5.tcpm_flags = TCP_MD5SIG_FLAG_PREFIX;
+ md5.tcpm_prefixlen = pxlen;
+
+ if (setsockopt(s->fd, SOL_TCP, TCP_MD5SIG_EXT, &md5, sizeof(md5)) < 0)
+ {
+ if (errno == ENOPROTOOPT)
+ ERR_MSG("Kernel does not support extended TCP MD5 signatures");
+ else
+ ERR("TCP_MD5SIG_EXT");
+ }
}
return 0;
diff --git a/sysdep/unix/config.Y b/sysdep/unix/config.Y
index af82e5bd..5c4b5bef 100644
--- a/sysdep/unix/config.Y
+++ b/sysdep/unix/config.Y
@@ -50,9 +50,12 @@ log_limit:
log_file:
text log_limit {
- this_log->rf = rf_open(new_config->pool, $1, "a");
- if (!this_log->rf) cf_error("Unable to open log file '%s': %m", $1);
- this_log->fh = rf_file(this_log->rf);
+ if (!parse_and_exit)
+ {
+ this_log->rf = rf_open(new_config->pool, $1, "a");
+ if (!this_log->rf) cf_error("Unable to open log file '%s': %m", $1);
+ this_log->fh = rf_file(this_log->rf);
+ }
this_log->pos = -1;
this_log->filename = $1;
}
@@ -88,9 +91,12 @@ conf: mrtdump_base ;
mrtdump_base:
MRTDUMP PROTOCOLS mrtdump_mask ';' { new_config->proto_default_mrtdump = $3; }
| MRTDUMP text ';' {
- struct rfile *f = rf_open(new_config->pool, $2, "a");
- if (!f) cf_error("Unable to open MRTDump file '%s': %m", $2);
- new_config->mrtdump_file = rf_fileno(f);
+ if (!parse_and_exit)
+ {
+ struct rfile *f = rf_open(new_config->pool, $2, "a");
+ if (!f) cf_error("Unable to open MRTDump file '%s': %m", $2);
+ new_config->mrtdump_file = rf_fileno(f);
+ }
}
;
diff --git a/sysdep/unix/io.c b/sysdep/unix/io.c
index 5e4d9573..3d67d0a7 100644
--- a/sysdep/unix/io.c
+++ b/sysdep/unix/io.c
@@ -91,7 +91,7 @@ static struct resclass rf_class = {
};
struct rfile *
-rf_open(pool *p, char *name, char *mode)
+rf_open(pool *p, const char *name, const char *mode)
{
FILE *f = fopen(name, mode);
@@ -1442,7 +1442,7 @@ sk_open(sock *s)
}
if (s->password)
- if (sk_set_md5_auth(s, s->saddr, s->daddr, s->iface, s->password, 0) < 0)
+ if (sk_set_md5_auth(s, s->saddr, s->daddr, -1, s->iface, s->password, 0) < 0)
goto err;
switch (s->type)
@@ -1495,7 +1495,9 @@ sk_open_unix(sock *s, char *name)
if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0)
return -1;
- /* Path length checked in test_old_bird() */
+ /* Path length checked in test_old_bird() but we may need unix sockets for other reasons in future */
+ ASSERT_DIE(strlen(name) < sizeof(sa.sun_path));
+
sa.sun_family = AF_UNIX;
strcpy(sa.sun_path, name);
@@ -2159,6 +2161,7 @@ io_init(void)
{
init_list(&sock_list);
init_list(&global_event_list);
+ init_list(&global_work_list);
krt_io_init();
// XXX init_times();
// XXX update_times();
@@ -2170,6 +2173,7 @@ io_init(void)
static int short_loops = 0;
#define SHORT_LOOP_MAX 10
+#define WORK_EVENTS_MAX 10
void
io_loop(void)
@@ -2187,6 +2191,7 @@ io_loop(void)
{
times_update(&main_timeloop);
events = ev_run_list(&global_event_list);
+ events = ev_run_list_limited(&global_work_list, WORK_EVENTS_MAX) || events;
timers_fire(&main_timeloop);
io_close_event();
diff --git a/sysdep/unix/krt.c b/sysdep/unix/krt.c
index 27868fab..c00c660d 100644
--- a/sysdep/unix/krt.c
+++ b/sysdep/unix/krt.c
@@ -539,6 +539,12 @@ krt_dump_attrs(rte *e)
* Routes
*/
+static inline int
+krt_is_installed(struct krt_proto *p, net *n)
+{
+ return n->routes && bmap_test(&p->p.main_channel->export_map, n->routes->id);
+}
+
static void
krt_flush_routes(struct krt_proto *p)
{
@@ -547,12 +553,10 @@ krt_flush_routes(struct krt_proto *p)
KRT_TRACE(p, D_EVENTS, "Flushing kernel routes");
FIB_WALK(&t->fib, net, n)
{
- rte *e = n->routes;
- if (rte_is_valid(e) && (n->n.flags & KRF_INSTALLED))
+ if (krt_is_installed(p, n))
{
/* FIXME: this does not work if gw is changed in export filter */
- krt_replace_rte(p, e->net, NULL, e);
- n->n.flags &= ~KRF_INSTALLED;
+ krt_replace_rte(p, n, NULL, n->routes);
}
}
FIB_WALK_END;
@@ -579,7 +583,7 @@ krt_export_net(struct krt_proto *p, net *net, rte **rt_free)
rte_make_tmp_attrs(&rt, krt_filter_lp, NULL);
- /* We could run krt_preexport() here, but it is already handled by KRF_INSTALLED */
+ /* We could run krt_preexport() here, but it is already handled by krt_is_installed() */
if (filter == FILTER_ACCEPT)
goto accept;
@@ -621,19 +625,17 @@ krt_same_dest(rte *k, rte *e)
void
krt_got_route(struct krt_proto *p, rte *e)
{
- net *net = e->net;
- int verdict;
+ rte *new = NULL, *rt_free = NULL;
+ net *n = e->net;
#ifdef KRT_ALLOW_LEARN
switch (e->u.krt.src)
{
case KRT_SRC_KERNEL:
- verdict = KRF_IGNORE;
- goto sentenced;
+ goto ignore;
case KRT_SRC_REDIRECT:
- verdict = KRF_DELETE;
- goto sentenced;
+ goto delete;
case KRT_SRC_ALIEN:
if (KRT_CF->learn)
@@ -648,58 +650,68 @@ krt_got_route(struct krt_proto *p, rte *e)
#endif
/* The rest is for KRT_SRC_BIRD (or KRT_SRC_UNKNOWN) */
- if (net->n.flags & KRF_VERDICT_MASK)
- {
- /* Route to this destination was already seen. Strange, but it happens... */
- krt_trace_in(p, e, "already seen");
- rte_free(e);
- return;
- }
+ /* We wait for the initial feed to have correct installed state */
if (!p->ready)
- {
- /* We wait for the initial feed to have correct KRF_INSTALLED flag */
- verdict = KRF_IGNORE;
- goto sentenced;
- }
+ goto ignore;
- if (net->n.flags & KRF_INSTALLED)
- {
- rte *new, *rt_free;
+ if (!krt_is_installed(p, n))
+ goto delete;
- new = krt_export_net(p, net, &rt_free);
+ new = krt_export_net(p, n, &rt_free);
- /* TODO: There also may be changes in route eattrs, we ignore that for now. */
+ /* Rejected by filters */
+ if (!new)
+ goto delete;
- if (!new)
- verdict = KRF_DELETE;
- else if ((net->n.flags & KRF_SYNC_ERROR) || !krt_same_dest(e, new))
- verdict = KRF_UPDATE;
- else
- verdict = KRF_SEEN;
+ /* Route to this destination was already seen. Strange, but it happens... */
+ if (bmap_test(&p->seen_map, new->id))
+ goto aseen;
- if (rt_free)
- rte_free(rt_free);
+ /* Mark route as seen */
+ bmap_set(&p->seen_map, new->id);
- lp_flush(krt_filter_lp);
- }
- else
- verdict = KRF_DELETE;
+ /* TODO: There also may be changes in route eattrs, we ignore that for now. */
+ if (!bmap_test(&p->sync_map, new->id) || !krt_same_dest(e, new))
+ goto update;
- sentenced:
- krt_trace_in(p, e, ((char *[]) { "?", "seen", "will be updated", "will be removed", "ignored" }) [verdict]);
- net->n.flags = (net->n.flags & ~KRF_VERDICT_MASK) | verdict;
- if (verdict == KRF_UPDATE || verdict == KRF_DELETE)
- {
- /* Get a cached copy of attributes and temporarily link the route */
- rta *a = e->attrs;
- a->source = RTS_DUMMY;
- e->attrs = rta_lookup(a);
- e->next = net->routes;
- net->routes = e;
- }
- else
- rte_free(e);
+ goto seen;
+
+seen:
+ krt_trace_in(p, e, "seen");
+ goto done;
+
+aseen:
+ krt_trace_in(p, e, "already seen");
+ goto done;
+
+ignore:
+ krt_trace_in(p, e, "ignored");
+ goto done;
+
+update:
+ krt_trace_in(p, new, "updating");
+ krt_replace_rte(p, n, new, e);
+ goto done;
+
+delete:
+ krt_trace_in(p, e, "deleting");
+ krt_replace_rte(p, n, NULL, e);
+ goto done;
+
+done:
+ rte_free(e);
+
+ if (rt_free)
+ rte_free(rt_free);
+
+ lp_flush(krt_filter_lp);
+}
+
+static void
+krt_init_scan(struct krt_proto *p)
+{
+ bmap_reset(&p->seen_map, 1024);
}
static void
@@ -709,62 +721,24 @@ krt_prune(struct krt_proto *p)
KRT_TRACE(p, D_EVENTS, "Pruning table %s", t->name);
FIB_WALK(&t->fib, net, n)
+ {
+ if (p->ready && krt_is_installed(p, n) && !bmap_test(&p->seen_map, n->routes->id))
{
- int verdict = n->n.flags & KRF_VERDICT_MASK;
- rte *new, *old, *rt_free = NULL;
+ rte *rt_free = NULL;
+ rte *new = krt_export_net(p, n, &rt_free);
- if (verdict == KRF_UPDATE || verdict == KRF_DELETE)
- {
- /* Get a dummy route from krt_got_route() */
- old = n->routes;
- n->routes = old->next;
- }
- else
- old = NULL;
-
- if (verdict == KRF_CREATE || verdict == KRF_UPDATE)
- {
- /* We have to run export filter to get proper 'new' route */
- new = krt_export_net(p, n, &rt_free);
-
- if (!new)
- verdict = (verdict == KRF_CREATE) ? KRF_IGNORE : KRF_DELETE;
- }
- else
- new = NULL;
-
- switch (verdict)
- {
- case KRF_CREATE:
- if (new && (n->n.flags & KRF_INSTALLED))
- {
- krt_trace_in(p, new, "reinstalling");
- krt_replace_rte(p, n, new, NULL);
- }
- break;
- case KRF_SEEN:
- case KRF_IGNORE:
- /* Nothing happens */
- break;
- case KRF_UPDATE:
- krt_trace_in(p, new, "updating");
- krt_replace_rte(p, n, new, old);
- break;
- case KRF_DELETE:
- krt_trace_in(p, old, "deleting");
- krt_replace_rte(p, n, NULL, old);
- break;
- default:
- bug("krt_prune: invalid route status");
- }
+ if (new)
+ {
+ krt_trace_in(p, new, "installing");
+ krt_replace_rte(p, n, new, NULL);
+ }
- if (old)
- rte_free(old);
if (rt_free)
rte_free(rt_free);
+
lp_flush(krt_filter_lp);
- n->n.flags &= ~KRF_VERDICT_MASK;
}
+ }
FIB_WALK_END;
#ifdef KRT_ALLOW_LEARN
@@ -822,6 +796,7 @@ static void
krt_scan(timer *t UNUSED)
{
struct krt_proto *p;
+ node *n;
kif_force_scan();
@@ -829,14 +804,13 @@ krt_scan(timer *t UNUSED)
p = SKIP_BACK(struct krt_proto, krt_node, HEAD(krt_proto_list));
KRT_TRACE(p, D_EVENTS, "Scanning routing table");
+ WALK_LIST2(p, n, krt_proto_list, krt_node)
+ krt_init_scan(p);
+
krt_do_scan(NULL);
- void *q;
- WALK_LIST(q, krt_proto_list)
- {
- p = SKIP_BACK(struct krt_proto, krt_node, q);
+ WALK_LIST2(p, n, krt_proto_list, krt_node)
krt_prune(p);
- }
}
static void
@@ -878,6 +852,7 @@ krt_scan(timer *t)
kif_force_scan();
KRT_TRACE(p, D_EVENTS, "Scanning routing table");
+ krt_init_scan(p);
krt_do_scan(p);
krt_prune(p);
}
@@ -933,22 +908,7 @@ krt_preexport(struct proto *P, rte **new, struct linpool *pool UNUSED)
rte *e = *new;
if (e->attrs->src->proto == P)
- {
-#ifdef CONFIG_SINGLE_ROUTE
- /*
- * Implicit withdraw - when the imported kernel route becomes the best one,
- * we know that the previous one exported to the kernel was already removed,
- * but if we processed the update as usual, we would send withdraw to the
- * kernel, which would remove the new imported route instead.
- *
- * We will remove KRT_INSTALLED flag, which stops such withdraw to be
- * processed in krt_rt_notify() and krt_replace_rte().
- */
- if (e == e->net->routes)
- e->net->n.flags &= ~KRF_INSTALLED;
-#endif
return -1;
- }
if (!krt_capable(e))
return -1;
@@ -964,12 +924,19 @@ krt_rt_notify(struct proto *P, struct channel *ch UNUSED, net *net,
if (config->shutdown)
return;
- if (!(net->n.flags & KRF_INSTALLED))
- old = NULL;
- if (new)
- net->n.flags |= KRF_INSTALLED;
- else
- net->n.flags &= ~KRF_INSTALLED;
+
+#ifdef CONFIG_SINGLE_ROUTE
+ /*
+ * Implicit withdraw - when the imported kernel route becomes the best one,
+ * we know that the previous one exported to the kernel was already removed,
+ * but if we processed the update as usual, we would send withdraw to the
+ * kernel, which would remove the new imported route instead.
+ */
+ rte *best = net->routes;
+ if (!new && best && (best->attrs->src->proto == P))
+ return;
+#endif
+
if (p->initialized) /* Before first scan we don't touch the routes */
krt_replace_rte(p, net, new, old);
}
@@ -1041,6 +1008,10 @@ krt_postconfig(struct proto_config *CF)
{
struct krt_config *cf = (void *) CF;
+ /* Do not check templates at all */
+ if (cf->c.class == SYM_TEMPLATE)
+ return;
+
if (EMPTY_LIST(CF->channels))
cf_error("Channel not specified");
@@ -1101,6 +1072,8 @@ krt_start(struct proto *P)
default: log(L_ERR "KRT: Tried to start with strange net type: %d", p->p.net_type); return PS_START; break;
}
+ bmap_init(&p->sync_map, p->p.pool, 1024);
+ bmap_init(&p->seen_map, p->p.pool, 1024);
add_tail(&krt_proto_list, &p->krt_node);
#ifdef KRT_ALLOW_LEARN
@@ -1140,6 +1113,7 @@ krt_shutdown(struct proto *P)
krt_sys_shutdown(p);
rem_node(&p->krt_node);
+ bmap_free(&p->sync_map);
return PS_DOWN;
}
@@ -1186,7 +1160,7 @@ krt_copy_config(struct proto_config *dest, struct proto_config *src)
}
static int
-krt_get_attr(eattr *a, byte *buf, int buflen)
+krt_get_attr(const eattr *a, byte *buf, int buflen)
{
switch (a->id)
{
diff --git a/sysdep/unix/krt.h b/sysdep/unix/krt.h
index 6ace2a86..4a5d10d2 100644
--- a/sysdep/unix/krt.h
+++ b/sysdep/unix/krt.h
@@ -19,15 +19,6 @@ struct kif_proto;
#include "sysdep/config.h"
#include CONFIG_INCLUDE_KRTSYS_H
-/* Flags stored in net->n.flags, rest are in nest/route.h */
-
-#define KRF_VERDICT_MASK 0x0f
-#define KRF_CREATE 0 /* Not seen in kernel table */
-#define KRF_SEEN 1 /* Seen in kernel table during last scan */
-#define KRF_UPDATE 2 /* Need to update this entry */
-#define KRF_DELETE 3 /* Should be deleted */
-#define KRF_IGNORE 4 /* To be ignored */
-
#define KRT_DEFAULT_ECMP_LIMIT 16
#define EA_KRT_SOURCE EA_CODE(PROTOCOL_KERNEL, 0)
@@ -65,6 +56,8 @@ struct krt_proto {
timer *scan_timer;
#endif
+ struct bmap sync_map; /* Keeps track which exported routes were successfully written to kernel */
+ struct bmap seen_map; /* Routes seen during last periodic scan */
node krt_node; /* Node in krt_proto_list */
byte af; /* Kernel address family (AF_*) */
byte ready; /* Initial feed has been finished */
@@ -86,6 +79,14 @@ void kif_request_scan(void);
void krt_got_route(struct krt_proto *p, struct rte *e);
void krt_got_route_async(struct krt_proto *p, struct rte *e, int new);
+static inline int
+krt_get_sync_error(struct krt_proto *p, struct rte *e)
+{
+ return (p->p.proto_state == PS_UP) &&
+ bmap_test(&p->p.main_channel->export_map, e->id) &&
+ !bmap_test(&p->sync_map, e->id);
+}
+
/* Values for rte->u.krt_sync.src */
#define KRT_SRC_UNKNOWN -1 /* Nobody knows */
#define KRT_SRC_BIRD 0 /* Our route (not passed in async mode) */
@@ -140,7 +141,7 @@ void krt_sys_copy_config(struct krt_config *, struct krt_config *);
int krt_capable(rte *e);
void krt_do_scan(struct krt_proto *);
void krt_replace_rte(struct krt_proto *p, net *n, rte *new, rte *old);
-int krt_sys_get_attr(eattr *a, byte *buf, int buflen);
+int krt_sys_get_attr(const eattr *a, byte *buf, int buflen);
/* kif sysdep */
diff --git a/sysdep/unix/log.c b/sysdep/unix/log.c
index 18894f98..14d18c01 100644
--- a/sysdep/unix/log.c
+++ b/sysdep/unix/log.c
@@ -332,7 +332,7 @@ debug(const char *msg, ...)
}
static list *
-default_log_list(int initial, char **syslog_name)
+default_log_list(int initial, const char **syslog_name)
{
static list log_list;
init_list(&log_list);
@@ -341,7 +341,11 @@ default_log_list(int initial, char **syslog_name)
#ifdef HAVE_SYSLOG_H
if (!dbgf)
{
- static struct log_config lc_syslog = { .mask = ~0 };
+ static struct log_config lc_syslog;
+ lc_syslog = (struct log_config){
+ .mask = ~0
+ };
+
add_tail(&log_list, &lc_syslog.n);
*syslog_name = bird_name;
}
@@ -349,15 +353,24 @@ default_log_list(int initial, char **syslog_name)
if (dbgf && (dbgf != stderr))
{
- static struct log_config lc_debug = { .mask = ~0 };
- lc_debug.fh = dbgf;
+ static struct log_config lc_debug;
+ lc_debug = (struct log_config){
+ .mask = ~0,
+ .fh = dbgf
+ };
+
add_tail(&log_list, &lc_debug.n);
}
if (initial || (dbgf == stderr))
{
- static struct log_config lc_stderr = { .mask = ~0, .terminal_flag = 1};
- lc_stderr.fh = stderr;
+ static struct log_config lc_stderr;
+ lc_stderr = (struct log_config){
+ .mask = ~0,
+ .terminal_flag = 1,
+ .fh = stderr
+ };
+
add_tail(&log_list, &lc_stderr.n);
}
@@ -365,16 +378,16 @@ default_log_list(int initial, char **syslog_name)
}
void
-log_switch(int initial, list *logs, char *new_syslog_name)
+log_switch(int initial, list *logs, const char *new_syslog_name)
{
struct log_config *l;
+ /* We should not manipulate with log list when other threads may use it */
+ log_lock();
+
if (!logs || EMPTY_LIST(*logs))
logs = default_log_list(initial, &new_syslog_name);
- /* We shouldn't close the logs when other threads may use them */
- log_lock();
-
/* Close the logs to avoid pinning them on disk when deleted */
if (current_log_list)
WALK_LIST(l, *current_log_list)
diff --git a/sysdep/unix/main.c b/sysdep/unix/main.c
index 282afae2..67e76655 100644
--- a/sysdep/unix/main.c
+++ b/sysdep/unix/main.c
@@ -20,6 +20,7 @@
#include <pwd.h>
#include <grp.h>
#include <sys/stat.h>
+#include <sys/utsname.h>
#include <libgen.h>
#include "nest/bird.h"
@@ -89,17 +90,36 @@ drop_gid(gid_t gid)
}
/*
+ * Hostname
+ */
+
+char *
+get_hostname(linpool *lp)
+{
+ struct utsname uts = {};
+
+ if (uname(&uts) < 0)
+ return NULL;
+
+ return lp_strdup(lp, uts.nodename);
+}
+
+/*
* Reading the Configuration
*/
#ifdef PATH_IPROUTE_DIR
static inline void
-add_num_const(char *name, int val)
+add_num_const(char *name, int val, const char *file, const uint line)
{
struct f_val *v = cfg_alloc(sizeof(struct f_val));
*v = (struct f_val) { .type = T_INT, .val.i = val };
- cf_define_symbol(cf_get_symbol(name), SYM_CONSTANT | T_INT, val, v);
+ struct symbol *sym = cf_get_symbol(name);
+ if (sym->class && (sym->scope == conf_this_scope))
+ cf_error("Error reading value for %s from %s:%d: already defined", name, file, line);
+
+ cf_define_symbol(sym, SYM_CONSTANT | T_INT, val, v);
}
/* the code of read_iproute_table() is based on
@@ -119,7 +139,7 @@ read_iproute_table(char *file, char *prefix, int max)
if (!fp)
return;
- while (fgets(buf, sizeof(buf), fp))
+ for (uint line = 1; fgets(buf, sizeof(buf), fp); line++)
{
char *p = buf;
@@ -139,10 +159,10 @@ read_iproute_table(char *file, char *prefix, int max)
continue;
for(p = name; *p; p++)
- if ((*p < 'a' || *p > 'z') && (*p < '0' || *p > '9') && (*p != '_'))
+ if ((*p < 'a' || *p > 'z') && (*p < 'A' || *p > 'Z') && (*p < '0' || *p > '9') && (*p != '_'))
*p = '_';
- add_num_const(namebuf, val);
+ add_num_const(namebuf, val, file, line);
}
fclose(fp);
@@ -186,7 +206,7 @@ sysdep_commit(struct config *new, struct config *old UNUSED)
}
static int
-unix_read_config(struct config **cp, char *name)
+unix_read_config(struct config **cp, const char *name)
{
struct config *conf = config_alloc(name);
int ret;
@@ -236,7 +256,7 @@ async_config(void)
}
static struct config *
-cmd_read_config(char *name)
+cmd_read_config(const char *name)
{
struct config *conf;
@@ -258,7 +278,7 @@ cmd_read_config(char *name)
}
void
-cmd_check_config(char *name)
+cmd_check_config(const char *name)
{
struct config *conf = cmd_read_config(name);
if (!conf)
@@ -299,7 +319,7 @@ cmd_reconfig_undo_notify(void)
}
void
-cmd_reconfig(char *name, int type, uint timeout)
+cmd_reconfig(const char *name, int type, uint timeout)
{
if (cli_access_restricted())
return;
@@ -654,7 +674,7 @@ signal_init(void)
*/
static char *opt_list = "bc:dD:ps:P:u:g:flRh";
-static int parse_and_exit;
+int parse_and_exit;
char *bird_name;
static char *use_user;
static char *use_group;
diff --git a/sysdep/unix/unix.h b/sysdep/unix/unix.h
index bd817bf2..ad85d1ea 100644
--- a/sysdep/unix/unix.h
+++ b/sysdep/unix/unix.h
@@ -20,11 +20,13 @@ struct rfile;
/* main.c */
extern char *bird_name;
+extern int parse_and_exit;
void async_config(void);
void async_dump(void);
void async_shutdown(void);
-void cmd_check_config(char *name);
-void cmd_reconfig(char *name, int type, uint timeout);
+char *get_hostname(linpool *lp);
+void cmd_check_config(const char *name);
+void cmd_reconfig(const char *name, int type, uint timeout);
void cmd_reconfig_confirm(void);
void cmd_reconfig_undo(void);
void cmd_reconfig_status(void);
@@ -106,7 +108,7 @@ void io_init(void);
void io_loop(void);
void io_log_dump(void);
int sk_open_unix(struct birdsock *s, char *name);
-struct rfile *rf_open(struct pool *, char *name, char *mode);
+struct rfile *rf_open(struct pool *, const char *name, const char *mode);
void *rf_file(struct rfile *f);
int rf_fileno(struct rfile *f);
void test_old_bird(char *path);
@@ -119,15 +121,15 @@ void krt_io_init(void);
void main_thread_init(void);
void log_init_debug(char *); /* Initialize debug dump to given file (NULL=stderr, ""=off) */
-void log_switch(int initial, list *l, char *);
+void log_switch(int initial, list *l, const char *);
struct log_config {
node n;
uint mask; /* Classes to log */
void *fh; /* FILE to log to, NULL=syslog */
struct rfile *rf; /* Resource for log file */
- char *filename; /* Log filename */
- char *backup; /* Secondary filename (for log rotation) */
+ const char *filename; /* Log filename */
+ const char *backup; /* Secondary filename (for log rotation) */
off_t pos; /* Position/size of current log */
off_t limit; /* Log size limit */
int terminal_flag;
diff --git a/test/birdtest.c b/test/birdtest.c
index 9e258c80..a1da078f 100644
--- a/test/birdtest.c
+++ b/test/birdtest.c
@@ -117,6 +117,7 @@ bt_init(int argc, char *argv[])
}
clock_gettime(CLOCK_MONOTONIC, &bt_begin);
+ bt_suite_case_begin = bt_suite_begin = bt_begin;
return;
@@ -198,14 +199,13 @@ bt_log_result(int result, u64 time, const char *fmt, va_list argptr)
static char msg_buf[BT_BUFFER_SIZE];
char *pos;
- snprintf(msg_buf, sizeof(msg_buf), "%s%s%s%s %" PRIu64 ".%09" PRIu64 "s",
+ snprintf(msg_buf, sizeof(msg_buf), "%s%s%s %" PRIu64 ".%09" PRIu64 "s%s",
bt_filename,
bt_test_id ? ": " : "",
bt_test_id ? bt_test_id : "",
- (fmt && strlen(fmt) > 0) ? ": " : "",
time / 1000000000,
- time % 1000000000
- );
+ time % 1000000000,
+ (fmt && strlen(fmt) > 0) ? ": " : "");
pos = msg_buf + strlen(msg_buf);
if (fmt)
@@ -339,6 +339,7 @@ bt_test_suite_base(int (*fn)(const void *), const char *id, const void *fn_arg,
bt_log("Starting");
clock_gettime(CLOCK_MONOTONIC, &bt_suite_begin);
+ bt_suite_case_begin = bt_suite_begin;
if (!forked)
{
@@ -494,7 +495,10 @@ void
bt_fmt_ipa(char *buf, size_t size, const void *data)
{
const ip_addr *ip = data;
- bsnprintf(buf, size, "%I", *ip);
+ if (data)
+ bsnprintf(buf, size, "%I", *ip);
+ else
+ bsnprintf(buf, size, "(null)");
}
int
@@ -507,10 +511,12 @@ bt_is_char(byte c)
* Mock-ups of all necessary public functions in main.c
*/
+int parse_and_exit;
char *bird_name;
void async_config(void) {}
void async_dump(void) {}
void async_shutdown(void) {}
+char *get_hostname(linpool *lp UNUSED) { return NULL; }
void cmd_check_config(char *name UNUSED) {}
void cmd_reconfig(char *name UNUSED, int type UNUSED, int timeout UNUSED) {}
void cmd_reconfig_confirm(void) {}
diff --git a/test/birdtest.h b/test/birdtest.h
index dacfb095..caec529b 100644
--- a/test/birdtest.h
+++ b/test/birdtest.h
@@ -101,12 +101,12 @@ static inline int bt_test_fn_noarg(const void *cp) { return ((int (*)(void)) cp)
#define bt_assert_msg(test, format, ...) \
do \
{ \
- int bt_suit_case_result = 1; \
+ int bt_suit_case_result = 1; \
if ((test) == 0) \
{ \
- bt_result = 0; \
- bt_suite_result = 0; \
- bt_suit_case_result = 0; \
+ bt_result = 0; \
+ bt_suite_result = 0; \
+ bt_suit_case_result = 0; \
} \
bt_log_suite_case_result(bt_suit_case_result, format, ##__VA_ARGS__); \
} while (0)
diff --git a/test/bt-utils.c b/test/bt-utils.c
index 7653abf6..cbca3a6b 100644
--- a/test/bt-utils.c
+++ b/test/bt-utils.c
@@ -154,7 +154,7 @@ bt_config_parse__(struct config *cfg)
if (cfg->err_msg)
{
- bt_debug("Parse error %s, line %d: %s\n", cfg->err_file_name, cfg->err_lino, cfg->err_msg);
+ bt_log("Parse error %s, line %d: %s", cfg->err_file_name, cfg->err_lino, cfg->err_msg);
bt_show_cfg_error(cfg);
return NULL;
}
diff --git a/tools/gendist b/tools/gendist
index 2ac59030..2d915a9f 100755
--- a/tools/gendist
+++ b/tools/gendist
@@ -33,8 +33,8 @@ rm -rf `find $T/$REL -name CVS -o -name tmp` $T/$REL/{misc,rfc,doc/slides,doc/sl
rm -rf $T/$REL $T/$DREL
echo -n "OK? "
read OK
-echo Uploading to Atrey...
-scp $T/$REL.tar.gz $T/$DREL.tar.gz atrey.karlin.mff.cuni.cz:~ftp/pub/bird/
+#echo Uploading to Atrey...
+#scp $T/$REL.tar.gz $T/$DREL.tar.gz atrey.karlin.mff.cuni.cz:~ftp/pub/bird/
echo Uploading to Trubka...
scp $T/$REL.tar.gz $T/$DREL.tar.gz bird.network.cz:~ftp/pub/bird/
echo Done.