105 Commits
0.0.4 ... 1.0

Author SHA1 Message Date
Job Snijders
a6792d2495 bump version 2021-08-19 08:20:32 +00:00
Caleb Xu
af202a821b compat: don't build when strlcpy is present (#47) 2021-08-19 08:19:44 +00:00
Job Snijders
ed8ee8368d Additionally add copyright file in the root directory. 2021-08-18 20:54:46 +00:00
Job Snijders
bf5f10def9 Rework where newlines are inserted 2021-08-18 16:56:13 +00:00
Job Snijders
1f7572c2f1 KNF 2021-08-18 12:28:57 +00:00
Job Snijders
34cc813446 Remove reference to bgpq4.spec 2021-08-18 10:57:49 +00:00
Job Snijders
5c57bb2bb6 Remove old spec file 2021-08-18 09:49:04 +00:00
Job Snijders
e6bf77058a remove sx_slentry.h 2021-08-18 02:05:40 +00:00
Job Snijders
139e0d972b include stdio 2021-08-18 02:01:03 +00:00
Job Snijders
99f036b186 KNF 2021-08-18 01:58:47 +00:00
Job Snijders
cb98214f0c remove stale comment 2021-08-18 01:38:47 +00:00
Job Snijders
ed28cf6734 Update README 2021-08-18 01:31:25 +00:00
Job Snijders
9ac2087d24 KNF 2021-08-18 01:16:29 +00:00
Job Snijders
58adb550bd KNF 2021-08-18 00:50:22 +00:00
Job Snijders
773849fc3a Release 0.0.9 2021-08-18 00:46:52 +00:00
Job Snijders
40656fbbbf Clean up comments 2021-08-18 00:40:02 +00:00
Job Snijders
4a8dc682fd Add more free() to counter memory errors 2021-08-18 00:38:44 +00:00
Job Snijders
450286a010 plug memory leaks 2021-08-18 00:18:26 +00:00
Job Snijders
a055f6f2ee Adding a free(), KNF 2021-08-17 23:51:18 +00:00
Job Snijders
c4c5866fa3 Fold freeall functions into expander.c 2021-08-17 23:03:29 +00:00
Job Snijders
6074f816e0 rename main program and add AM conditional 2021-08-17 23:00:06 +00:00
Job Snijders
cb15aea505 Release 0.0.8 2021-08-17 22:54:15 +00:00
Job Snijders
f1a339985a Fix SX_TEST_EBITS 2021-08-17 22:51:22 +00:00
Job Snijders
24daa48a67 Style fixes 2021-08-17 22:33:04 +00:00
Job Snijders
b21c8b30ca remove unused includes 2021-08-17 22:23:33 +00:00
Job Snijders
270e04dd23 The string returned by inet_ntoa() resides in a static memory area 2021-08-17 22:20:16 +00:00
Job Snijders
32a3520e62 Fix -Wstrict-aliasing messages
Moving from uint32 -> struct in_addr
2021-08-17 22:16:56 +00:00
Job Snijders
b816c1023b Fix more warnings 2021-08-17 20:19:17 +00:00
Job Snijders
85d833ca48 Fix style and compiler warnings 2021-08-17 19:34:30 +00:00
Job Snijders
791f3d7790 Fixing style and compiler warnings 2021-08-17 18:03:03 +00:00
Job Snijders
6a4207f940 rename headerfile 2021-08-17 17:26:10 +00:00
Job Snijders
af10798afd Move to Brent Cooks portable 2021-08-17 17:18:59 +00:00
Job Snijders
81112ec2de install libtool 2021-08-17 14:36:30 +00:00
Job Snijders
08801e2068 Change macro for manpage 2021-08-17 14:30:18 +00:00
Job Snijders
b1a9f4f089 Add 0.0.7 changelog 2021-08-17 14:27:06 +00:00
Job Snijders
408b7d8852 add _null.h to include Makefile 2021-08-17 14:25:47 +00:00
Job Snijders
3754a01a2b No need for -O0 libcompat 2021-08-17 14:22:33 +00:00
Job Snijders
8bc07f3cb0 use portability shim for string.h 2021-08-17 14:19:10 +00:00
Job Snijders
bbcd4ae18f set libcompat_la 2021-08-17 12:52:14 +00:00
Job Snijders
f1e9242814 define bgpq4_LDADD 2021-08-17 12:50:08 +00:00
Job Snijders
222b89e631 add types.h 2021-08-17 12:36:33 +00:00
Job Snijders
ea95e6d27a add types.h 2021-08-17 12:34:21 +00:00
Job Snijders
dc0e8c32f7 Use OpenBSD string.h 2021-08-17 12:33:00 +00:00
Job Snijders
21b574fc91 Current OpenBSD queue.h has STAILQ_ 2021-08-17 12:23:50 +00:00
Job Snijders
757dc33bb0 Add compat dir to AM flags 2021-08-17 12:19:29 +00:00
Job Snijders
82146e291b Add _null.h from OpenBSD 2021-08-17 12:14:07 +00:00
Job Snijders
ac93dcfeef include local headers too 2021-08-17 12:11:05 +00:00
Job Snijders
e6d488ca5b Sync with latest OpenBSD tree.h/queue.h 2021-08-17 12:11:05 +00:00
Job Snijders
dee79b0408 Sync to latest strlcpy() from OpenBSD 2021-08-17 12:11:05 +00:00
Job Snijders
6f7a8db6aa Add m4/ dir to cleanup list 2021-08-17 12:11:05 +00:00
Job Snijders
276b2cfc52 clean up maintainer files 2021-08-17 12:11:05 +00:00
Job Snijders
82b44b1304 Add license to each individual file 2021-08-17 12:11:05 +00:00
Job Snijders
4eb9566de8 Reorganize automake 2021-08-17 12:11:05 +00:00
Job Snijders
f473454ff7 Reorganize compat dir 2021-08-17 12:11:05 +00:00
Job Snijders
16fd7f7668 move .h into include dir 2021-08-17 12:11:05 +00:00
Job Snijders
a0b9343551 Move strlcpy into compat dir 2021-08-17 12:11:05 +00:00
Job Snijders
d998a73652 KNF 2021-08-17 12:11:05 +00:00
Job Snijders
0b554d4aa1 KNF 2021-08-17 10:12:40 +00:00
Job Snijders
406b984aa4 KNF 2021-08-12 08:25:36 +00:00
Stefan Marti
c2223849fc Huawei aspath bugfix (#44)
* bugfix huawei input as-path

* bgpq4_print_huawei_oaspath bug fix
2021-07-13 11:10:22 +00:00
Tony Lee
56432d3c74 Update bgpq4_printer.c (#43)
Correction Juniper route filter list ouput.
2021-07-03 18:41:45 +02:00
Robert Scheck
65f157581b Remove unused markdown check (no more bgpq4.html) (#41) 2021-04-26 23:33:25 +00:00
Robert Scheck
d103cc6e3b Bump version to 0.0.7 to match GitHub tags (#42) 2021-04-26 23:33:02 +00:00
Melchior Aelmans
d4b53ba67e Update README.md (#40)
"data data" is one time "data" too much.
2021-03-30 14:42:51 +00:00
Job Snijders
9498d7f368 Revert conditional clauses around XR prefix list generation
This fixes #39

Thank you Octavio & Lukas
2021-03-16 09:57:43 +00:00
Job Snijders
5f5ce4cff3 Remove select, use system default
Remove not-needed shutdown()

Thanks Theo
2020-12-29 20:03:12 +00:00
Job Snijders
f29576d973 remove readme.header 2020-12-23 15:18:46 +00:00
Brooks Swinnerton
d000627465 Arista EOS Support (#35)
Add Arista EOS support

Thanks Brooks!

This adds support for Arista EOS using a new flag: -e. EOS shares a lot of similarities with IOS,
but there is a difference in the syntax of prefix-lists that I wanted to fix.

The difference can be seen with bgpq4 -S ARIN -4 -s AS36459, which returns:

no ip prefix-list NN
ip prefix-list NN seq 1 permit 192.30.252.0/22
ip prefix-list NN seq 2 permit 192.30.252.0/23
ip prefix-list NN seq 3 permit 192.30.252.0/24
ip prefix-list NN seq 4 permit 192.30.253.0/24
ip prefix-list NN seq 5 permit 192.30.254.0/24
ip prefix-list NN seq 6 permit 192.30.255.0/24

Interestingly, this syntax works fine in EOS, but EOS isn't able to handle the same syntax for ipv6
prefix-lists. Instead, the seq and permit/deny that compose the rule needs to be inside the prefix-list
block.

Now bgpq4 -S ARIN -4 -e AS36459 generates:

no ip prefix-list NN
ip prefix-list NN
    seq 1 permit 192.30.252.0/22
    seq 2 permit 192.30.252.0/23
    seq 3 permit 192.30.252.0/24
    seq 4 permit 192.30.253.0/24
    seq 5 permit 192.30.254.0/24
    seq 6 permit 192.30.255.0/24
2020-12-23 15:07:23 +00:00
Job Snijders
884a982718 Update contact 2020-12-23 15:01:51 +00:00
Job Snijders
71cbcf7019 more cleanup 2020-12-23 15:01:32 +00:00
Job Snijders
03bc8d47dc Remove bgpq4.html 2020-12-23 14:59:34 +00:00
Job Snijders
b361671c45 Improve manpage 2020-12-23 13:49:50 +00:00
Job Snijders
a624dc9649 Merge pull request #26 from robert-scheck/man
Avoid man page macro warnings
2020-12-23 14:41:40 +01:00
Job Snijders
fd6150a2dd update contact info 2020-12-23 13:40:37 +00:00
Job Snijders
c05dea14a7 Merge pull request #34 from bswinnerton/respect-sequence-when-no-results
Respect -s when there are no prefix lists
2020-12-23 13:55:07 +01:00
Brooks Swinnerton
12da3fc231 Respect -s when there are no prefix lists
This commit fixes a bug with when there are no prefix list results but
the `-s` argument is passed.
2020-12-20 17:47:40 -05:00
Job Snijders
e21b687467 Merge pull request #29 from mxsasha/patch-1
Add Arch Linux package to readme
2020-09-22 09:06:08 +02:00
Sasha Romijn
7c483de7d3 Add Arch Linux package to readme 2020-09-22 08:52:56 +02:00
Job Snijders
78825a18cf Merge pull request #27 from DamianZaremba/feature/dzaremba/increase-select-timeout
bgpq_expander - Increase the read select timeout to 30 seconds
2020-06-29 15:25:45 +00:00
Damian Zaremba
95edf74de7 bgpq_expander - Increase the read select timeout to 30 seconds
With the current 10 second timeout I have observed intermittent failures reporting `FATAL ERROR:select timeout` when querying large objects.

This has only been observed when using IRRD instances supporting `A` queries which led me down a path of investigating the server side timeout, the default of which in irrd4 is 30 seconds, thus 30 seconds was chosen as the read timeout (bgpq4 currently has no option to pass `!T`).

The increased timeout has been running as a local patch in my environment for more than two months with no observed failures, testing the upstream version locally still results in intermittent failures.

Commentary on the Github issue indicated ~9 second response times from Europe, which could be related to the higher latency (150ms+) cross region.
2020-06-29 16:12:56 +02:00
Robert Scheck
a3f0cd39e2 Avoid man page macro warnings
$ LC_ALL=en_US.UTF-8 MANROFFSEQ='' MANWIDTH=80 man --warnings -E UTF-8 -l -Tutf8 -Z bgpq4.8 > /dev/null
<standard input>:137: warning: macro `RS' not defined
<standard input>:157: warning: macro `RE' not defined
$
2020-06-29 00:34:34 +02:00
Job Snijders
a3053a34b7 Merge pull request #25 from robert-scheck/autotools
AM_CONFIG_HEADER is superseded by AC_CONFIG_HEADERS since July 2002
2020-06-28 22:05:27 +00:00
Robert Scheck
2d96ae5ff8 AM_CONFIG_HEADER is superseded by AC_CONFIG_HEADERS since July 2002
See: https://lists.gnu.org/archive/html/automake/2012-12/msg00038.html
2020-06-29 00:00:03 +02:00
Job Snijders
a3ca5cbcc9 Update README.md 2020-04-26 16:01:31 +02:00
Job Snijders
bb775897d8 Merge pull request #22 from 5u623l20/5u623l20-patch-FreeBSD
Add information about FreeBSD installation
2020-03-29 12:08:07 +02:00
Moin
521aa51262 Add information about FreeBSD installation
bgpq4 has been ported into FreeBSD.
https://svnweb.freebsd.org/ports?view=revision&revision=529782
2020-03-29 15:38:46 +06:00
Job Snijders
d9a2ee92a6 Release 0.0.6 2020-03-12 13:24:44 +01:00
Job Snijders
62b2a56af7 Merge pull request #21 from ccaputo/master
Various for consideration...
2020-03-11 18:09:09 +01:00
Chris Caputo
92d52b9133 Fix totally broken final newline code with '-F'. 2020-03-11 16:22:46 +00:00
Chris Caputo
1d5b375cc3 Enable aggregate support with '-F' (user-defined). 2020-03-11 16:22:46 +00:00
Chris Caputo
e4d72f0505 Fix user-defined format stack-smash ability.
'-F' option: Avoids risk of stack-smashing which was ever so present,
by just fprintf'ing directly to output stream.
2020-03-11 16:22:46 +00:00
Chris Caputo
b71aa3f21d Compiler warning fixes and improved error handling.
Fixes multiple:
  warning: ignoring return value of 'read', declared with attribute warn_unused_result [-Wunused-result]
  warning: ignoring return value of 'write', declared with attribute warn_unused_result [-Wunused-result]

Improves some error messages.
2020-03-08 22:57:45 +00:00
Chris Caputo
d8fbae0643 Make A query test only be performed when needed.
Saves an RTT.
2020-03-08 22:51:37 +00:00
Job Snijders
b8e92b5456 update readme 2020-01-03 15:43:29 +01:00
Job Snijders
20d04b5d54 Release 0.0.5 2020-01-01 19:19:35 +01:00
Job Snijders
de3c94ac9d Unbreak -G
(And some formatting changes)

Thanks for reporting sthen@openbsd.org!
2020-01-01 17:49:28 +01:00
Job Snijders
0a49b8a6ea Move -S to Input filter 2019-12-31 14:47:41 +01:00
Job Snijders
cfa1a00433 Add -v version command line option 2019-12-31 14:36:44 +01:00
Job Snijders
ef9889dda3 Move -L to input filters 2019-12-31 14:24:01 +01:00
Job Snijders
fb6fde65c8 Rework usage() 2019-12-31 14:19:12 +01:00
Job Snijders
e9f4eeaa57 Update usage() 2019-12-31 14:04:26 +01:00
Job Snijders
f5ba86dfa5 Change prompt in docs 2019-12-31 13:29:05 +01:00
Job Snijders
425e8dbdb4 Make the -3 command line option a no-op 2019-12-31 13:24:12 +01:00
Job Snijders
d3eb845c9b Remove -3 option from docs 2019-12-31 13:11:18 +01:00
Job Snijders
8b5459cf05 Add additional debug lines 2019-12-31 11:32:25 +01:00
37 changed files with 2733 additions and 2112 deletions

View File

@@ -4,7 +4,7 @@ FROM $image
# Install dependencies
RUN yum update -y
RUN yum groupinstall -y 'Development Tools'
RUN yum install -y autoconf automake findutils
RUN yum install -y autoconf automake findutils libtool
# Add source code
ADD . /src

View File

@@ -7,7 +7,10 @@ RUN apt-get update && apt-get install -y locales && rm -rf /var/lib/apt/lists/*
ENV LANG en_US.utf8
# Install dependencies
RUN apt-get update && apt-get dist-upgrade -y && apt-get install -y build-essential autoconf automake markdown && rm -rf /var/lib/apt/lists/*
RUN apt-get update \
&& apt-get dist-upgrade -y \
&& apt-get install -y build-essential autoconf libtool automake markdown \
&& rm -rf /var/lib/apt/lists/*
# Add source code
ADD . /src

37
.gitignore vendored
View File

@@ -1,37 +0,0 @@
CVS/
Makefile
config.h
*.o
bgpq4
bgpq4.html
Makefile.in
.deps
/bgpq4-*.tar.gz
/ar-lib
/mdate-sh
/py-compile
/test-driver
/ylwrap
autom4te.cache
/autoscan.log
/autoscan-*.log
/aclocal.m4
/compile
/config.guess
/config.h.in
/config.log
/config.status
/config.sub
/configure
/configure.scan
/depcomp
/install-sh
/missing
/stamp-h1
/ltmain.sh
/texinfo.tex
m4/libtool.m4
m4/ltoptions.m4
m4/ltsugar.m4
m4/ltversion.m4
m4/lt~obsolete.m4

14
CHANGES
View File

@@ -1,3 +1,17 @@
0.0.9 (2021-08-18)
- Fix various memory errors
0.0.8 (2021-08-17)
- Reorganize automake files and includes
- Normalize code to adhere to KNF
- Fix all compiler warnings
0.0.6 (2020-03-12):
- Bugfixes - Thanks Chris Caputo!
0.0.5 (2020-01-01):
- Bugfixes
0.0.4 (2019-12-31):
- Remove the '-3' command line option, assume all devices are
32-bit ASN safe

View File

@@ -1,5 +1,4 @@
/*-
* Copyright (c) 2019 Job Snijders <job@ntt.net>
* Copyright (c) 2007-2019 Alexandre Snarskii <snar@snar.spb.ru>
* All rights reserved.
*

View File

@@ -1,19 +1,35 @@
SUBDIRS = include
ACLOCAL_AMFLAGS = -I m4
AM_CPPFLAGS = -I$(top_srcdir)/include
AM_CPPFLAGS += -I$(top_srcdir)/compat
AUTOMAKE_OPTIONS=foreign subdir-objects
bin_PROGRAMS=bgpq4
bgpq4_SOURCES=bgpq4.c bgpq4.h config.h bgpq4_printer.c bgpq_expander.c \
expander_freeall.c expander_freeall.h strlcpy.c sx_maxsockbuf.c \
sx_maxsockbuf.h sx_prefix.c sx_prefix.h sx_report.c sx_report.h \
sx_slentry.c sx_slentry.h sys_queue.h sys_tree.h
dist_doc_DATA=bgpq4.html
dist_man8_MANS=bgpq4.8
EXTRA_DIST=bootstrap readme.header README.md CHANGES COPYRIGHT bgpq4.spec
CLEANFILES=bgpq4.html
bgpq4_LDADD = $(PLATFORM_LDADD) $(PROG_LDADD)
if !HAVE_STRLCPY
SUBDIRS += compat
bgpq4_LDADD += $(top_builddir)/compat/libcompat.la
endif
bgpq4_SOURCES=main.c extern.h printer.c expander.c \
sx_maxsockbuf.c \
sx_prefix.c sx_prefix.h \
sx_report.c sx_report.h \
sx_slentry.c
EXTRA_DIST=bootstrap README.md CHANGES
MAINTAINERCLEANFILES=configure aclocal.m4 compile \
install-sh missing Makefile.in depcomp \
stamp-h1 config.h.in
bgpq4.html: readme.header README.md
cat readme.header README.md | @MARKDOWN@ > bgpq4.html
stamp-h1 compat/Makefile.in \
config.guess config.sub include/Makefile.in \
ltmain.sh
maintainer-clean-local:
-rm -rf autom4te.cache config.h.in~
-rm -rf m4 autom4te.cache

View File

@@ -3,11 +3,14 @@ NAME
`bgpq4` - bgp filtering automation tool
The `bgpq4` utility queries IRRd and then generates IRR and/or RPKI based
filters formatted for a wide assortment of BGP implementations.
SYNOPSIS
--------
```
bgpq4 [-h host[:port]] [-S sources] [-Ez] [-f asn | -F fmt | -G asn | -t] [-46ABbDdJjNnpsUX] [-a asn] [-r len] [-R len] [-m max] [-W len] OBJECTS [...] EXCEPT OBJECTS
bgpq4 [-h host[:port]] [-S sources] [-Ez] [-f asn | -F fmt | -G asn | -t] [-46ABbDdeJjNnpsUX] [-a asn] [-r len] [-R len] [-m max] [-W len] OBJECTS [...] EXCEPT OBJECTS
```
DESCRIPTION
@@ -15,7 +18,7 @@ DESCRIPTION
The bgpq4 utility used to generate configuration (prefix-lists,
extended access-lists, policy-statement terms and as-path lists)
based on RADB data.
based on IRR routing data.
The options are as follows:
@@ -54,6 +57,10 @@ Generate extended access-list (Cisco) or policy-statement term using
route-filters (Juniper), [ip|ipv6]-prefix-list (Nokia) or prefix-filter
(OpenBGPD)
#### -e
Generate output in Arista EOS format.
#### -f `AS number`
Generate input as-path access-list for adjacent as `AS number`.
@@ -135,7 +142,7 @@ Generate as-sets for OpenBGPD (OpenBSD 6.4+), BIRD and JSON formats.
#### -T
Disable pipelining. (not recommended)
Disable pipelining (not recommended).
#### -U
@@ -167,7 +174,7 @@ EXAMPLES
--------
Generating prefix filter for MikroTik for `AS20597`:
user@host:~>./bgpq4 -Kl eltel-v4 AS20597
$ ./bgpq4 -Kl eltel-v4 AS20597
/routing filter add action=accept chain="eltel-v4" prefix=81.9.0.0/20
/routing filter add action=accept chain="eltel-v4" prefix=81.9.32.0/20
/routing filter add action=accept chain="eltel-v4" prefix=81.9.96.0/20
@@ -181,7 +188,7 @@ Generating prefix filter for MikroTik for `AS20597`:
Generating named Juniper prefix-filter for `AS20597`:
user@host:~>bgpq4 -Jl eltel-v4 AS20597
$ bgpq4 -Jl eltel-v4 AS20597
policy-options {
replace:
prefix-list eltel-v4 {
@@ -204,7 +211,7 @@ Generating named Juniper prefix-filter for `AS20597`:
For Cisco we can use aggregation (-A) flag to make this prefix-filter
more compact:
user@host:~>bgpq4 -Al eltel-v4 AS20597
$ bgpq4 -Al eltel-v4 AS20597
no ip prefix-list eltel-v4
ip prefix-list eltel-v4 permit 81.9.0.0/20
ip prefix-list eltel-v4 permit 81.9.32.0/20
@@ -227,7 +234,7 @@ Well, for Juniper we can generate even more interesting policy-statement,
using `-M <extra match conditions>`, `-r <len>`, `-R <len>` and hierarchical
names:
user@host:~>bgpq4 -AJEl eltel/specifics -r 29 -R 32 -M "community blackhole" AS20597
$ bgpq4 -AJEl eltel/specifics -r 29 -R 32 -M "community blackhole" AS20597
policy-options {
policy-statement eltel {
term specifics {
@@ -255,15 +262,15 @@ generated policy-option term now allows more-specific routes in range
Of course, `bgpq4` supports IPv6 (-6):
user@host:~>bgpq4 -6l as-retn-v6 AS-RETN6
$ bgpq4 -6l as-retn-v6 AS-RETN6
no ipv6 prefix-list as-retn-v6
ipv6 prefix-list as-retn-v6 permit 2001:7fb:fe00::/48
ipv6 prefix-list as-retn-v6 permit 2001:7fb:fe01::/48
[....]
and ASN32
and assumes your device supports 32-bit ASNs
user@host:~>bgpq4 -J3f 112 AS-SPACENET
$ bgpq4 -Jf 112 AS-SPACENET
policy-options {
replace:
as-path-group NN {
@@ -274,22 +281,7 @@ and ASN32
}
}
see `AS196611` in the end of the list ? That's `AS3.3` in 'asplain' notation.
If your router does not support ASN32 (yet) you should not use switch -3,
and the result will be next:
user@host:~>bgpq4 -f 112 AS-SPACENET
no ip as-path access-list NN
ip as-path access-list NN permit ^112( 112)*$
ip as-path access-list NN permit ^112( [0-9]+)* (1898|5539|8495|8763)$
ip as-path access-list NN permit ^112( [0-9]+)* (8878|12136|12931|15909)$
ip as-path access-list NN permit ^112( [0-9]+)* (21358|23456|23600|24151)$
ip as-path access-list NN permit ^112( [0-9]+)* (25152|31529|34127|34906)$
ip as-path access-list NN permit ^112( [0-9]+)* (35052|41720|43628|44450)$
`AS196611` is no more in the list, however, `AS23456` (transition AS) would
have been added to list if it were not present.
see `AS196611` in the end of the list ? That's a 32-bit ASN.
USER-DEFINED FORMAT
-------------------
@@ -298,20 +290,21 @@ If you want to generate configuration not for routers, but for some
other programs/systems, you may use user-defined formatting, like in
example below:
user@host:~>bgpq4 -F "ipfw add pass all from %n/%l to any\\n" as3254
$ bgpq4 -F "ipfw add pass all from %n/%l to any\\n" as3254
ipfw add pass all from 62.244.0.0/18 to any
ipfw add pass all from 91.219.29.0/24 to any
ipfw add pass all from 91.219.30.0/24 to any
ipfw add pass all from 193.193.192.0/19 to any
Recognized format characters: '%n' - network, '%l' - mask length,
'%a' - aggregate low mask length, '%A' - aggregate high mask length,
'%N' - object name, '%m' - object mask and '%i' - inversed mask.
Recognized escape characters: '\n' - new line, '\t' - tabulation.
Please note that no new lines inserted automatically after each sentence,
you have to add them into format string manually, elsewhere output will
be in one line (sometimes it makes sense):
user@host:~>bgpq4 -6F "%n/%l; " as-eltel
$ bgpq4 -6F "%n/%l; " as-eltel
2001:1b00::/32; 2620:4f:8000::/48; 2a04:bac0::/29; 2a05:3a80::/48;
DIAGNOSTICS
@@ -339,11 +332,6 @@ Linux can be tuned in the following way:
sysctl -w net.ipv4.tcp_rmem="4096 87380 2097152"
sysctl -w net.ipv4.tcp_wmem="4096 65536 2097152"
Please note that generated prefix-lists may not fit your router's
limitations. For example, JunOS supports only 85,325 prefixes in
each prefix-list [4](http://www.juniper.net/techpubs/en_US/junos11.4/topics/reference/configuration-statement/prefix-list-edit-policy-options.html).
BUILDING
--------
@@ -367,13 +355,42 @@ In order to create a distribution archive, run:
make dist
PACKAGE INSTALLATION
--------------------
In FreeBSD binary package can be installed using
```shell
pkg install bgpq4
```
Or from ports with `portmaster`
```shell
portmaster net-mgmt/bgpq4
```
On Arch Linux, BGPQ4 is [available in AUR](https://aur.archlinux.org/packages/bgpq4/):
```shell
yay -S bgpq4
```
On OpenBSD:
```shell
pkg_add bgpq4
```
MAILING LIST
------------
Users and interested parties can subscribe to the BGPQ4 mailing list [bgpq4@tcp0.com](https://tcp0.com/cgi-bin/mailman/listinfo/bgpq4).
SEE ALSO
--------
1. [Routing Arbiter](http://www.radb.net/)
2. [Cisco documentation](http://www.cisco.com/en/US/prod/collateral/iosswrel/ps6537/ps6554/ps6599/data_sheet_C78-521821.html)
for information on Cisco implementation of ASN32.
3. [JunOS prefix-lists limitation](http://www.juniper.net/techpubs/en_US/junos11.4/topics/reference/configuration-statement/prefix-list-edit-policy-options.html)
NLNOG's [BGP Filter Guide](http://bgpfilterguide.nlnog.net/)
AUTHORS
-------
@@ -385,7 +402,7 @@ and contributions from many others.
Project
-------
BGPQ4 is maintained by Job Snijders `<job@ntt.net>`.
BGPQ4 is maintained by Job Snijders `<job@sobornost.net>`.
[https://github.com/bgp/bgpq4](https://github.com/bgp/bgpq4)

1
VERSION Normal file
View File

@@ -0,0 +1 @@
1.0

117
bgpq4.8
View File

@@ -22,7 +22,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
.Dd Dec 1, 2019
.Dd December 23, 2020
.Dt BGPQ4 8
.Os
.Sh NAME
@@ -36,7 +36,7 @@
.Oo
.Fl f Ar asn |
.Fl F Ar fmt |
.Fl G Ar asn
.Fl G Ar asn
.Fl t
.Oc
.Op Fl 46ABbDdJjNnsXU
@@ -50,15 +50,15 @@
.Op EXCEPT OBJECTS
.Sh DESCRIPTION
The
.Nm
.Nm
utility used to generate configurations (prefix-lists, extended
access-lists, policy-statement terms and as-path lists) based on RADB data.
.Pp
The options are as follows:
The options are as follows:
.Bl -tag -width Ds
.It Fl 4
.It Fl 4
generate IPv4 prefix/access-lists (default).
.It Fl 6
.It Fl 6
generate IPv6 prefix/access-lists (IPv4 by default).
.It Fl A
try to aggregate prefix-lists as much as possible (not all output
@@ -71,6 +71,8 @@ generate output in OpenBGPD format (default: Cisco)
generate output in BIRD format (default: Cisco).
.It Fl d
enable some debugging output.
.It Fl e
generate output in Arista EOS format (default: Cisco).
.It Fl E
generate extended access-list (Cisco), policy-statement term using
route-filters (Juniper), [ip|ipv6]-prefix-list (Nokia) or prefix-sets
@@ -89,14 +91,14 @@ generate config for Juniper (default: Cisco).
generate output in JSON format (default: Cisco).
.It Fl K
generate config for Mikrotik (default: Cisco).
.It Fl l Ar name
.It Fl l Ar name
name of generated entry.
.It Fl L Ar limit
limit recursion depth when expanding as-sets.
.It Fl m Ar len
maximum prefix-length of accepted prefixes (default: 32 for IPv4 and
maximum prefix-length of accepted prefixes (default: 32 for IPv4 and
128 for IPv6).
.It Fl M Ar match
.It Fl M Ar match
extra match conditions for Juniper route-filters.
.It Fl n
generate config for Nokia SR OS MD-CLI (Cisco IOS by default)
@@ -107,17 +109,17 @@ accept routes registered for private ASNs (default: disabled)
.It Fl P
generate prefix-list (default, backward compatibility).
.It Fl r Ar len
allow more specific routes starting with specified masklen too.
allow more specific routes starting with specified masklen too.
.It Fl R Ar len
allow more specific routes up to specified masklen too.
allow more specific routes up to specified masklen too.
.It Fl s
generate sequence numbers in IOS-style prefix-lists.
.It Fl S Ar sources
use specified sources only (recommended: RADB,RIPE,APNIC).
.It Fl t
generate as-sets for OpenBGPD (OpenBSD 6.4+), BIRD and JSON formats.
generate as-sets for OpenBGPd, BIRD and JSON formats.
.It Fl T
disable pipelining.
disable pipelining (not recommended).
.It Fl W Ar len
generate as-path strings of no more than len items (use 0 for inifinity).
.It Fl U
@@ -126,16 +128,16 @@ generate config for Huawei devices (Cisco IOS by default)
generate config for Cisco IOS XR devices (plain IOS by default).
.It Fl z
generate route-filter-lists (JunOS 16.2+).
.It Ar OBJECTS
.It Ar OBJECTS
means networks (in prefix format), autonomous systems, as-sets and route-sets.
.It Ar EXCEPT OBJECTS
those objects will be excluded from expansion.
.El
.Sh EXAMPLES
Generating named juniper prefix-filter for AS20597:
Generating named juniper prefix-filter for AS20597:
.nf
.RS
~>bgpq4 -Jl eltel AS20597
.Bd -literal
$ bgpq4 -Jl eltel AS20597
policy-options {
replace:
prefix-list eltel {
@@ -154,14 +156,14 @@ replace:
217.170.80.0/20;
}
}
.RE
.Ed
.fi
.Pp
For Cisco we can use aggregation (-A) flag to make this prefix-filter
more compact:
more compact:
.nf
.RS
~>bgpq4 -Al eltel AS20597
.Bd -literal
$ bgpq4 -Al eltel AS20597
no ip prefix-list eltel
ip prefix-list eltel permit 81.9.0.0/20
ip prefix-list eltel permit 81.9.32.0/20
@@ -174,16 +176,16 @@ ip prefix-list eltel permit 89.112.0.0/18 ge 19 le 19
ip prefix-list eltel permit 89.112.4.0/22
ip prefix-list eltel permit 89.112.64.0/19
ip prefix-list eltel permit 217.170.64.0/19 ge 20 le 20
.RE
.Ed
.fi
- you see, prefixes 89.112.0.0/19 and 89.112.32.0/19 now aggregated
into single entry 89.112.0.0/18 ge 19 le 19.
into single entry 89.112.0.0/18 ge 19 le 19.
.Pp
Well, for Juniper we can generate even more interesting policy-options,
using -M <extra match conditions>, -R <len> and hierarchical names:
using -M <extra match conditions>, -R <len> and hierarchical names:
.nf
.RS
~>bgpq4 -AJEl eltel/specifics -r 29 -R 32 -M "community blackhole" AS20597
.Bd -literal
$ bgpq4 -AJEl eltel/specifics -r 29 -R 32 -M "community blackhole" AS20597
policy-options {
policy-statement eltel {
term specifics {
@@ -203,26 +205,26 @@ replace:
}
}
}
.RE
.Ed
.fi
generated policy-option term now allows all specifics with prefix-length
between /29 and /32 for eltel networks if they match with special community
between /29 and /32 for eltel networks if they match with special community
blackhole (defined elsewhere in configuration).
.Pp
Of course, this version supports IPv6 (-6):
Of course, this version supports IPv6 (-6):
.nf
.RS
~>bgpq4 -6l as-retn-6 AS-RETN6
.Bd -literal
$ bgpq4 -6l as-retn-6 AS-RETN6
no ipv6 prefix-list as-retn-6
ipv6 prefix-list as-retn-6 permit 2001:7fb:fe00::/48
ipv6 prefix-list as-retn-6 permit 2001:7fb:fe01::/48
[....]
.RE
.Ed
.fi
and support for ASN 32 is also here
and assumes your device supports 32-bit ASNs
.nf
.RS
~>bgpq4 -J3f 112 AS-SPACENET
.Bd -literal
$ bgpq4 -Jf 112 AS-SPACENET
policy-options {
replace:
as-path-group NN {
@@ -232,61 +234,44 @@ replace:
as-path a3 "^112(.)*(35052|41720|43628|44450|196611)$";
}
}
.RE
.Ed
.fi
see AS196611 in the end of the list ? That's AS3.3 in 'asplain' notation.
.Pp
For non-ASN32 capable routers you should not use switch -3,
and the result will be next:
.nf
.RS
~>bgpq4 -f 112 AS-SPACENET
no ip as-path access-list NN
ip as-path access-list NN permit ^112(_112)*$
ip as-path access-list NN permit ^112(_[0-9]+)*_(1898|5539|8495|8763)$
ip as-path access-list NN permit ^112(_[0-9]+)*_(8878|12136|12931|15909)$
ip as-path access-list NN permit ^112(_[0-9]+)*_(21358|23456|23600|24151)$
ip as-path access-list NN permit ^112(_[0-9]+)*_(25152|31529|34127|34906)$
ip as-path access-list NN permit ^112(_[0-9]+)*_(35052|41720|43628|44450)$
.RE
.fi
.Pp
AS196611 is no more in the list, however, AS23456 (transition AS)
would be added to list if it were not present.
see `AS196611` in the end of the list ? That's a 32-bit ASN.
.Sh USER-DEFINED FORMAT
If you want to generate configuration not for routers, but for some
other programs/systems, you may use user-defined formatting, like in
example below:
.nf
.RS
user@host:~>bgpq4 -F "ipfw add pass all from %n/%l to any\\n" as3254
.Bd -literal
$ bgpq4 -F "ipfw add pass all from %n/%l to any\\n" as3254
ipfw add pass all from 62.244.0.0/18 to any
ipfw add pass all from 91.219.29.0/24 to any
ipfw add pass all from 91.219.30.0/24 to any
ipfw add pass all from 193.193.192.0/19 to any
.RE
.Ed
.fi
.Pp
Recognized format characters: %n - network, %l - mask length,
%a - aggregate low mask length, %A - aggregate high mask length,
%N - object name, %m - object mask and %i - inversed mask.
Recognized escape characters: \\n - new line, \\t - tabulation.
Please note that no new lines inserted automatically after each sentence,
you have to add them into format string manually, elsewhere output will
be in one line (sometimes it makes sense):
.nf
.RS
user@host:~>bgpq4 -6F "%n/%l; " as-eltel
.Bd -literal
$ bgpq4 -6F "%n/%l; " as-eltel
2001:1b00::/32; 2620:4f:8000::/48; 2a04:bac0::/29; 2a05:3a80::/48;
.RE
.Ed
.fi
.Sh DIAGNOSTICS
When everything is OK,
When everything is OK,
.Nm
generates access-list to standard output and exits with status == 0.
In case of errors they are printed to stderr and program exits with
non-zero status.
generates access-list to standard output and exits with status == 0.
In case of errors they are printed to stderr and program exits with
non-zero status.
.Sh SEE ALSO
.Sy https://github.com/bgp/bgpq4
BGPQ4 on Github.
.Sh PROJECT MAINTAINER
.An Job Snijders Aq job@ntt.net
.An Job Snijders Aq job@sobornost.net

97
bgpq4.h
View File

@@ -1,97 +0,0 @@
#ifndef BGPQ4_H_
#define BGPQ4_H_
#if HAVE_SYS_QUEUE_H && HAVE_STAILQ_IN_SYS_QUEUE
#include <sys/queue.h>
#else
#include "sys_queue.h"
#endif
#include "sx_prefix.h"
#include "sx_slentry.h"
typedef enum {
V_CISCO = 0,
V_JUNIPER,
V_CISCO_XR,
V_JSON,
V_BIRD,
V_OPENBGPD,
V_FORMAT,
V_NOKIA,
V_HUAWEI,
V_MIKROTIK,
V_NOKIA_MD
} bgpq_vendor_t;
typedef enum {
T_NONE = 0,
T_ASPATH,
T_OASPATH,
T_ASSET,
T_PREFIXLIST,
T_EACL,
T_ROUTE_FILTER_LIST
} bgpq_gen_t;
struct bgpq_expander;
struct bgpq_request {
STAILQ_ENTRY(bgpq_request) next;
char* request;
int size, offset;
int (*callback)(char*, struct bgpq_expander*, struct bgpq_request*);
void *udata;
unsigned depth;
};
struct bgpq_expander {
struct sx_radix_tree* tree;
STAILQ_HEAD(sx_slentries, sx_slentry) macroses, rsets;
RB_HEAD(tentree, sx_tentry) already, stoplist;
int family;
char* sources;
uint32_t asnumber;
int aswidth;
char* name;
bgpq_vendor_t vendor;
bgpq_gen_t generation;
int identify;
int sequence;
int maxdepth;
int validate_asns;
unsigned char* asn32s[65536];
struct bgpq_prequest* firstpipe, *lastpipe;
int piped;
char* match;
char* server;
char* port;
char* format;
unsigned maxlen;
STAILQ_HEAD(bgpq_requests, bgpq_request) wq, rq;
int fd, cdepth;
};
int bgpq_expander_init(struct bgpq_expander* b, int af);
int bgpq_expander_add_asset(struct bgpq_expander* b, char* set);
int bgpq_expander_add_rset(struct bgpq_expander* b, char* set);
int bgpq_expander_add_as(struct bgpq_expander* b, char* as);
int bgpq_expander_add_prefix(struct bgpq_expander* b, char* prefix);
int bgpq_expander_add_prefix_range(struct bgpq_expander* b, char* prefix);
int bgpq_expander_add_stop(struct bgpq_expander* b, char* object);
int bgpq_expand(struct bgpq_expander* b);
int bgpq4_print_prefixlist(FILE* f, struct bgpq_expander* b);
int bgpq4_print_eacl(FILE* f, struct bgpq_expander* b);
int bgpq4_print_aspath(FILE* f, struct bgpq_expander* b);
int bgpq4_print_asset(FILE* f, struct bgpq_expander* b);
int bgpq4_print_oaspath(FILE* f, struct bgpq_expander* b);
int bgpq4_print_route_filter_list(FILE* f, struct bgpq_expander* b);
#ifndef HAVE_STRLCPY
size_t strlcpy(char* dst, const char* src, size_t size);
#endif
#endif

View File

@@ -1,82 +0,0 @@
Name: bgpq4
Version: 0.0.4
Release: 0%{?dist}
Group: System/Utilities
Summary: Generate BGP filters based on routing database information
URL: https://github.com/bgp/bgpq4
License: BSD
Source0: https://github.com/bgp/bgpq4
BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
%description
You are running BGP in your network and want to automate filter generation for your routers? Well, with BGPQ4 it's easy.
%prep
%setup -q
%global debug_package %{nil}
%build
./configure --prefix=$RPM_BUILD_ROOT%{_prefix} --mandir=%{_mandir}
make
%install
rm -rf $RPM_BUILD_ROOT
mkdir -p $RPM_BUILD_ROOT/usr/bin
make install
%files
%defattr(-,root,root,-)
/usr/bin/bgpq4
/usr/man/man8/bgpq4.8.gz
%doc COPYRIGHT CHANGES
%clean
rm -rf $RPM_BUILD_ROOT
%changelog
* Tue Dec 31 2019 Job Snijders <job@ntt.net> 0.0.4
- Remove '-3' command line option, assume all devices are 32-bit ASN safe
* Mon Dec 30 2019 Job Snijders <job@ntt.net> 0.0.3
- Remove the '-2' command line option
- Significant code reformating
- Improve performance by using IRRd 4's A query when available
* Sat Dec 14 2019 Job Snijders <job@ntt.net> 0.0.2
- Add Mikrotik support
- Remove ASDDOT support
* Sat Dec 14 2019 Job Snijders <job@ntt.net> 0.0.1
- Fork from bgpq3
* Tue Nov 30 2018 Alexandre Snarskii <snar@snar.spb.ru> 0.1.35
- Version updated
* Fri Oct 14 2016 Alexandre Snarskii <snar@snar.spb.ru> 0.1.33
- Version updated
* Tue Jun 23 Alexandre Snarskii <snar@snar.spb.ru> 0.1.31
- Version updated
* Tue Mar 10 Alexandre Snarskii <snar@snar.spb.ru> 0.1.28
- Version updated
* Wed Oct 29 Alexandre Snarskii <snar@snar.spb.ru> 0.1.25
- Version updated
* Thu Jun 5 2014 Alexandre Snarskii <snar@snar.spb.ru> 0.1.21-0.snar
- Version updated
* Thu May 9 2013 Alexandre Snarskii <snar@snar.spb.ru> 0.1.19-0.snar
- Version updated
* Sun Feb 24 2013 Alexandre Snarskii <snar@snar.spb.ru> 0.1.18-3.snar
- License corrected
* Wed Feb 20 2013 Arnoud Vermeer <arnoud@tumblr.com> 0.1.18-2.tumblr
- Adding missing group info (arnoud@tumblr.com)
* Wed Feb 20 2013 Arnoud Vermeer <arnoud@tumblr.com> 0.1.18-1.tumblr
- new package built with tito

7
compat/Makefile.am Normal file
View File

@@ -0,0 +1,7 @@
AM_CPPFLAGS = -I$(top_srcdir)/include
noinst_LTLIBRARIES = libcompat.la
libcompat_la_LIBADD = $(PLATFORM_LDADD)
libcompat_la_SOURCES = strlcpy.c

50
compat/strlcpy.c Normal file
View File

@@ -0,0 +1,50 @@
/* $OpenBSD: strlcpy.c,v 1.16 2019/01/25 00:19:25 millert Exp $ */
/*
* Copyright (c) 1998, 2015 Todd C. Miller <millert@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <sys/types.h>
#include <string.h>
/*
* Copy string src to buffer dst of size dsize. At most dsize-1
* chars will be copied. Always NUL terminates (unless dsize == 0).
* Returns strlen(src); if retval >= dsize, truncation occurred.
*/
size_t
strlcpy(char *dst, const char *src, size_t dsize)
{
const char *osrc = src;
size_t nleft = dsize;
/* Copy as many bytes as will fit. */
if (nleft != 0) {
while (--nleft != 0) {
if ((*dst++ = *src++) == '\0')
break;
}
}
/* Not enough room in dst, add NUL and traverse rest of src. */
if (nleft == 0) {
if (dsize != 0)
*dst = '\0'; /* NUL-terminate dst */
while (*src++)
;
}
return(src - osrc - 1); /* count does not include NUL */
}

View File

@@ -1,34 +1,103 @@
AC_INIT(bgpq4,0.0.4,job@ntt.net)
AM_INIT_AUTOMAKE
AC_PACKAGE_URL(https://github.com/bgp/bgpq4)
AM_CONFIG_HEADER(config.h)
AM_SILENT_RULES([yes])
#
# Copyright (c) 2019 Brent Cook
#
# Permission to use, copy, modify, and distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
AC_INIT([bgpq4], m4_esyscmd([tr -d '\n' < VERSION]), job@sobornost.net)
AC_CANONICAL_HOST
AM_INIT_AUTOMAKE([subdir-objects foreign])
AC_CONFIG_MACRO_DIR([m4])
m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
AC_PROG_CC([cc gcc])
case $host_os in
*darwin*)
HOST_OS=darwin
AC_DEFINE([SPT_TYPE], [SPT_REUSEARGV])
;;
*freebsd*)
HOST_OS=freebsd
;;
*linux*)
HOST_OS=linux
CFLAGS="$CFLAGS -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_GNU_SOURCE"
AC_DEFINE([SPT_TYPE], [SPT_REUSEARGV])
;;
*netbsd*)
HOST_OS=netbsd
;;
*openbsd*)
HOST_OS=openbsd
AC_DEFINE([HAVE_ATTRIBUTE__BOUNDED__], [1], [OpenBSD has __bounded__])
AC_DEFINE([HAVE_ATTRIBUTE__DEAD], [1], [OpenBSD has __dead])
;;
*solaris*)
HOST_OS=solaris
CFLAGS="$CFLAGS -D__EXTENSIONS__ -D_XOPEN_SOURCE=600 -DBSD_COMP"
;;
*) ;;
esac
AM_CONDITIONAL([HOST_DARWIN], [test x$HOST_OS = xdarwin])
AM_CONDITIONAL([HOST_FREEBSD], [test x$HOST_OS = xfreebsd])
AM_CONDITIONAL([HOST_LINUX], [test x$HOST_OS = xlinux])
AM_CONDITIONAL([HOST_NETBSD], [test x$HOST_OS = xnetbsd])
AM_CONDITIONAL([HOST_SOLARIS], [test x$HOST_OS = xsolaris])
AC_PROG_CC
CC=cc
CFLAGS="${CFLAGS} -std=gnu11"
AC_PROG_CC_STDC
AM_PROG_CC_C_O
AC_PROG_LIBTOOL
AC_PROG_INSTALL
AC_CHECK_HEADERS([sys/cdefs.h sys/queue.h sys/tree.h sys/select.h])
AC_ARG_ENABLE(warnings,
AS_HELP_STRING([--disable-warnings],
[ enable compiler warnings [default=enabled]]),
[case $enableval in
yes) enable_warnings=yes;;
no) enable_warnings=no;;
*) enable_warnings=yes;; esac],
enable_warnings=yes)
AC_MSG_CHECKING([for STAILQ_ interface in queue.h])
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([
#if HAVE_SYS_QUEUE_H
#include <sys/queue.h>
#else
#include "sys_queue.h"
if test "$enable_warnings" = yes; then
AM_CFLAGS="$AM_CFLAGS -Wall -Wstrict-prototypes -Wmissing-prototypes -Wmissing-declarations -Wshadow -Wpointer-arith -Wsign-compare -Werror-implicit-function-declaration"
save_cflags="$CFLAGS"
CFLAGS=-Wno-pointer-sign
AC_MSG_CHECKING([whether CC supports -Wno-pointer-sign])
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([])],
[AC_MSG_RESULT([yes])]
[WARN_CFLAGS=-Wno-pointer-sign],
[AC_MSG_RESULT([no])]
)
AM_CFLAGS="$AM_CFLAGS $WARN_CFLAGS"
CFLAGS="$save_cflags"
fi
AC_MSG_CHECKING([if compiling with clang])
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([], [[
#ifndef __clang__
not clang
#endif
struct blah {
STAILQ_ENTRY(blah) next;
};
])],
[AC_MSG_RESULT(yes)
AC_DEFINE([HAVE_STAILQ_IN_SYS_QUEUE], [1], [sys/queue.h have STAILQ_])],
[AC_MSG_RESULT(no)])
AC_CHECK_PROGS([MARKDOWN], [markdown_py markdown2 markdown], [echo])
]])],
[AC_MSG_RESULT([yes])]
[CLANG_FLAGS=-Qunused-arguments],
[AC_MSG_RESULT([no])]
)
AM_CFLAGS="$AM_CFLAGS $CLANG_FLAGS"
AM_LDFLAGS="$LDFLAGS $CLANG_FLAGS"
AC_SUBST(AM_CFLAGS)
AC_SUBST(AM_LDFLAGS)
AC_CHECK_FUNCS(strlcpy)
AC_CHECK_FUNCS(pledge)
@@ -36,5 +105,15 @@ AC_CHECK_FUNCS(pledge)
AC_CHECK_LIB(socket,socket)
AC_CHECK_LIB(nsl,getaddrinfo)
AC_OUTPUT(Makefile)
AC_CHECK_HEADERS([sys/cdefs.h sys/queue.h sys/tree.h sys/select.h])
AM_CONDITIONAL([HAVE_PLEDGE], [test "x$ac_cv_func_pledge" = xyes])
AM_CONDITIONAL([HAVE_STRLCPY], [test "x$ac_cv_func_strlcpy" = xyes])
AC_CONFIG_FILES([
Makefile
include/Makefile
compat/Makefile
])
AC_OUTPUT

View File

@@ -1,46 +1,67 @@
#if HAVE_CONFIG_H
#include "config.h"
#endif
/*
* Copyright (c) 2019-2021 Job Snijders <job@sobornost.net>
* Copyright (c) 2018 Peter Schoenmaker <pds@ntt.net>
* Copyright (c) 2007-2019 Alexandre Snarskii <snar@snar.spb.ru>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <sys/types.h>
#include <sys/socket.h>
#if HAVE_SYS_SELECT_H
#include <sys/select.h>
#endif
#include <assert.h>
#include <fcntl.h>
#include <inttypes.h>
#include <ctype.h>
#include <errno.h>
#include <netdb.h>
#include <err.h>
#include <fcntl.h>
#include <inttypes.h>
#include <limits.h>
#include <string.h>
#include <strings.h>
#include <netdb.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <unistd.h>
#include "bgpq4.h"
#include "extern.h"
#include "sx_report.h"
#include "sx_maxsockbuf.h"
#include "expander_freeall.h"
int debug_expander = 0;
int pipelining = 1;
int expand_special_asn = 0;
static inline int
tentry_cmp(struct sx_tentry* a, struct sx_tentry* b)
tentry_cmp(struct sx_tentry *a, struct sx_tentry *b)
{
return strcasecmp(a->text, b->text);
}
RB_GENERATE(tentree, sx_tentry, entry, tentry_cmp);
RB_GENERATE_STATIC(tentree, sx_tentry, entries, tentry_cmp);
int
bgpq_expander_init(struct bgpq_expander* b, int af)
bgpq_expander_init(struct bgpq_expander *b, int af)
{
if (!af)
af = AF_INET;
@@ -93,24 +114,24 @@ fixups:
}
int
bgpq_expander_add_asset(struct bgpq_expander* b, char* as)
bgpq_expander_add_asset(struct bgpq_expander *b, char *as)
{
struct sx_slentry* le;
struct sx_slentry *le;
if (!b || !as)
return 0;
le = sx_slentry_new(as);
STAILQ_INSERT_TAIL(&b->macroses, le, next);
STAILQ_INSERT_TAIL(&b->macroses, le, entries);
return 1;
}
int
bgpq_expander_add_rset(struct bgpq_expander* b, char* rs)
bgpq_expander_add_rset(struct bgpq_expander *b, char *rs)
{
struct sx_slentry* le;
struct sx_slentry *le;
if (!b || !rs)
return 0;
@@ -120,15 +141,16 @@ bgpq_expander_add_rset(struct bgpq_expander* b, char* rs)
if (!le)
return 0;
STAILQ_INSERT_TAIL(&b->rsets, le, next);
STAILQ_INSERT_TAIL(&b->rsets, le, entries);
return 1;
}
int
bgpq_expander_add_already(struct bgpq_expander* b, char* rs)
static int
bgpq_expander_add_already(struct bgpq_expander *b, char *rs)
{
struct sx_tentry* le, lkey;
struct sx_tentry *le, lkey;
lkey.text = rs;
if (RB_FIND(tentree, &b->already, &lkey))
@@ -142,9 +164,10 @@ bgpq_expander_add_already(struct bgpq_expander* b, char* rs)
}
int
bgpq_expander_add_stop(struct bgpq_expander* b, char* rs)
bgpq_expander_add_stop(struct bgpq_expander *b, char *rs)
{
struct sx_tentry* le, lkey;
struct sx_tentry *le, lkey;
lkey.text = rs;
if (RB_FIND(tentree, &b->stoplist, &lkey))
@@ -158,11 +181,11 @@ bgpq_expander_add_stop(struct bgpq_expander* b, char* rs)
}
int
bgpq_expander_add_as(struct bgpq_expander* b, char* as)
bgpq_expander_add_as(struct bgpq_expander *b, char *as)
{
char* eoa;
uint32_t asn1 = 0, asn2 = 0;
uint32_t asno = 0;
char *eoa;
uint32_t asn1 = 0, asn2 = 0;
uint32_t asno = 0;
if (!b || !as)
return 0;
@@ -205,9 +228,10 @@ bgpq_expander_add_as(struct bgpq_expander* b, char* as)
}
int
bgpq_expander_add_prefix(struct bgpq_expander* b, char* prefix)
bgpq_expander_add_prefix(struct bgpq_expander *b, char *prefix)
{
struct sx_prefix *p = sx_prefix_alloc(NULL);
if (!sx_prefix_parse(p, 0, prefix)) {
sx_report(SX_ERROR, "Unable to parse prefix %s\n", prefix);
return 0;
@@ -221,7 +245,7 @@ bgpq_expander_add_prefix(struct bgpq_expander* b, char* prefix)
" masklen %u\n", prefix, p->masklen, b->maxlen);
return 0;
}
sx_radix_tree_insert(b->tree,p);
sx_radix_tree_insert(b->tree, p);
if (p)
sx_prefix_destroy(p);
@@ -230,42 +254,43 @@ bgpq_expander_add_prefix(struct bgpq_expander* b, char* prefix)
}
int
bgpq_expander_add_prefix_range(struct bgpq_expander* b, char* prefix)
bgpq_expander_add_prefix_range(struct bgpq_expander *b, char *prefix)
{
return sx_prefix_range_parse(b->tree, b->family, b->maxlen, prefix);
}
int
bgpq_expanded_macro(char* as, struct bgpq_expander* ex,
struct bgpq_request* req)
static int
bgpq_expanded_macro(char *as, struct bgpq_expander *ex,
struct bgpq_request *req)
{
bgpq_expander_add_as(ex, as);
return 1;
}
struct bgpq_request* bgpq_pipeline(struct bgpq_expander* b,
int (*callback)(char*, struct bgpq_expander* b, struct bgpq_request* req),
void* udata, char* fmt, ...);
int bgpq_expand_irrd(struct bgpq_expander* b,
int (*callback)(char*, struct bgpq_expander* b, struct bgpq_request* req),
void* udata, char* fmt, ...);
struct bgpq_request *bgpq_pipeline(struct bgpq_expander *b,
int (*callback)(char *, struct bgpq_expander *b, struct bgpq_request *req),
void *udata, char *fmt, ...);
int
bgpq_expanded_macro_limit(char* as, struct bgpq_expander* b,
struct bgpq_request* req)
int bgpq_expand_irrd(struct bgpq_expander *b,
int (*callback)(char*, struct bgpq_expander *b, struct bgpq_request *req),
void *udata, char *fmt, ...);
static int
bgpq_expanded_macro_limit(char *as, struct bgpq_expander *b,
struct bgpq_request *req)
{
if (!strncasecmp(as, "AS-", 3) || strchr(as, '-') || strchr(as, ':')) {
struct sx_tentry tkey = { .text = as };
if (RB_FIND(tentree, &b->already, &tkey)) {
SX_DEBUG(debug_expander>2, "%s is already expanding, "
SX_DEBUG(debug_expander > 2, "%s is already expanding, "
"ignore\n", as);
return 0;
}
if (RB_FIND(tentree, &b->stoplist, &tkey)) {
SX_DEBUG(debug_expander>2, "%s is in the stoplist, "
SX_DEBUG(debug_expander > 2, "%s is in the stoplist, "
"ignore\n", as);
return 0;
}
@@ -275,10 +300,10 @@ bgpq_expanded_macro_limit(char* as, struct bgpq_expander* b,
req->depth + 1 < b->maxdepth)) {
bgpq_expander_add_already(b, as);
if (pipelining) {
struct bgpq_request* req1 = bgpq_pipeline(b,
bgpq_expanded_macro_limit, NULL, "!i%s\n",
as);
req1->depth = req->depth+1;
struct bgpq_request *req1 = bgpq_pipeline(b,
bgpq_expanded_macro_limit, NULL, "!i%s",
as);
req1->depth = req->depth + 1;
} else {
b->cdepth++;
bgpq_expand_irrd(b, bgpq_expanded_macro_limit,
@@ -286,7 +311,7 @@ bgpq_expanded_macro_limit(char* as, struct bgpq_expander* b,
b->cdepth--;
}
} else {
SX_DEBUG(debug_expander>2, "ignoring %s at depth %i\n",
SX_DEBUG(debug_expander > 2, "ignoring %s at depth %i\n",
as,
b->cdepth ? (b->cdepth + 1) : (req->depth + 1));
}
@@ -316,11 +341,11 @@ bgpq_expanded_macro_limit(char* as, struct bgpq_expander* b,
return 1;
}
int
bgpq_expanded_prefix(char* as, struct bgpq_expander* ex,
struct bgpq_request* req __attribute__((unused)))
static int
bgpq_expanded_prefix(char *as, struct bgpq_expander *ex,
struct bgpq_request *req __attribute__((unused)))
{
char* d = strchr(as, '^');
char *d = strchr(as, '^');
if (!d)
bgpq_expander_add_prefix(ex, as);
@@ -330,11 +355,11 @@ bgpq_expanded_prefix(char* as, struct bgpq_expander* ex,
return 1;
}
int
bgpq_expanded_v6prefix(char* prefix, struct bgpq_expander* ex,
struct bgpq_request* req)
static int
bgpq_expanded_v6prefix(char *prefix, struct bgpq_expander *ex,
struct bgpq_request *req)
{
char* d = strchr(prefix, '^');
char *d = strchr(prefix, '^');
if (!d)
bgpq_expander_add_prefix(ex, prefix);
@@ -344,13 +369,13 @@ bgpq_expanded_v6prefix(char* prefix, struct bgpq_expander* ex,
return 1;
}
int bgpq_pipeline_dequeue(int fd, struct bgpq_expander* b);
int bgpq_pipeline_dequeue(int fd, struct bgpq_expander *b);
static struct bgpq_request*
bgpq_request_alloc(char* request, int (*callback)(char*, struct bgpq_expander*,
struct bgpq_request*), void* udata)
static struct bgpq_request *
bgpq_request_alloc(char *request, int (*callback)(char *, struct bgpq_expander *,
struct bgpq_request *), void *udata)
{
struct bgpq_request* bp = malloc(sizeof(struct bgpq_request));
struct bgpq_request *bp = malloc(sizeof(struct bgpq_request));
if (!bp)
return NULL;
@@ -366,7 +391,7 @@ bgpq_request_alloc(char* request, int (*callback)(char*, struct bgpq_expander*,
}
static void
bgpq_request_free(struct bgpq_request* req)
bgpq_request_free(struct bgpq_request *req)
{
if (req->request)
free(req->request);
@@ -374,15 +399,15 @@ bgpq_request_free(struct bgpq_request* req)
free(req);
}
struct bgpq_request*
bgpq_pipeline(struct bgpq_expander* b,
int (*callback)(char*, struct bgpq_expander*, struct bgpq_request*),
void* udata, char* fmt, ...)
struct bgpq_request *
bgpq_pipeline(struct bgpq_expander *b,
int (*callback)(char *, struct bgpq_expander *, struct bgpq_request *),
void *udata, char *fmt, ...)
{
char request[128];
int ret;
struct bgpq_request* bp = NULL;
va_list ap;
char request[128];
int ret;
struct bgpq_request *bp = NULL;
va_list ap;
va_start(ap, fmt);
vsnprintf(request, sizeof(request), fmt, ap);
@@ -422,10 +447,10 @@ bgpq_pipeline(struct bgpq_expander* b,
}
static void
bgpq_expander_invalidate_asn(struct bgpq_expander* b, const char* q)
bgpq_expander_invalidate_asn(struct bgpq_expander *b, const char *q)
{
if (!strncmp(q, "!gas", 4) || !strncmp(q, "!6as", 4)) {
char* eptr;
char *eptr;
unsigned long asn = strtoul(q+4, &eptr, 10), asn0, asn1 = 0;
if (!asn || asn == ULONG_MAX || asn >= 4294967295
|| (eptr && *eptr != '\n')) {
@@ -436,7 +461,7 @@ bgpq_expander_invalidate_asn(struct bgpq_expander* b, const char* q)
asn1 = asn % 65536;
asn0 = asn / 65536;
if (!b->asn32s[asn0] ||
!(b->asn32s[asn0][asn1/8] & (0x80 >> (asn1 % 8)))) {
!(b->asn32s[asn0][asn1/8] & (0x80 >> (asn1 % 8)))) {
sx_report(SX_NOTICE, "strange, invalidating inactive "
"asn %lu(%s)\n", asn, q);
} else {
@@ -446,12 +471,12 @@ bgpq_expander_invalidate_asn(struct bgpq_expander* b, const char* q)
}
static void
bgpq_write(struct bgpq_expander* b)
bgpq_write(struct bgpq_expander *b)
{
while(!STAILQ_EMPTY(&b->wq)) {
struct bgpq_request* req = STAILQ_FIRST(&b->wq);
struct bgpq_request *req = STAILQ_FIRST(&b->wq);
int ret = write(b->fd, req->request+req->offset,
int ret = write(b->fd, req->request + req->offset,
req->size-req->offset);
if (ret < 0) {
@@ -473,11 +498,10 @@ bgpq_write(struct bgpq_expander* b)
}
static int
bgpq_selread(struct bgpq_expander* b, char* buffer, int size)
bgpq_selread(struct bgpq_expander *b, char *buffer, int size)
{
fd_set rfd, wfd;
int ret;
struct timeval timeout = {10, 0};
repeat:
FD_ZERO(&rfd);
@@ -487,10 +511,10 @@ repeat:
if (!STAILQ_EMPTY(&b->wq))
FD_SET(b->fd, &wfd);
ret = select(b->fd + 1, &rfd, &wfd, NULL, &timeout);
ret = select(b->fd + 1, &rfd, &wfd, NULL, NULL);
if (ret == 0)
sx_report(SX_FATAL, "select timeout\n");
sx_report(SX_FATAL, "select failed\n");
else if (ret == -1 && errno == EINTR)
goto repeat;
else if (ret == -1)
@@ -506,8 +530,8 @@ repeat:
goto repeat;
}
int
bgpq_read(struct bgpq_expander* b)
static int
bgpq_read(struct bgpq_expander *b)
{
static char response[256];
static int off = 0;
@@ -516,11 +540,12 @@ bgpq_read(struct bgpq_expander* b)
bgpq_write(b);
while(!STAILQ_EMPTY(&b->rq)) {
struct bgpq_request* req = STAILQ_FIRST(&b->rq);
int ret = 0;
char *cres;
struct bgpq_request *req = STAILQ_FIRST(&b->rq);
SX_DEBUG(debug_expander > 2, "waiting for answer to %s,"
"init %i '%.*s'\n", req->request, off, off, response);
int ret = 0;
char* cres;
if ((cres=strchr(response, '\n')) != NULL)
goto have;
@@ -545,10 +570,10 @@ have:
response);
if (response[0] == 'A') {
char* eon, *c;
unsigned long togot = strtoul(response+1,&eon,10);
char* recvbuffer = malloc(togot+2);
int offset = 0;
char *eon, *c;
unsigned long offset = 0;
unsigned long togot = strtoul(response + 1, &eon, 10);
char *recvbuffer = malloc(togot + 2);
if (!recvbuffer) {
sx_report(SX_FATAL, "error allocating %lu "
@@ -564,7 +589,7 @@ have:
exit(1);
}
if (off - ((eon + 1) - response) > togot) {
if ((unsigned)(off - ((eon + 1) - response)) > togot) {
// full response and more data is already in buffer
memcpy(recvbuffer, eon + 1, togot);
offset = togot;
@@ -582,9 +607,9 @@ have:
off = 0;
}
SX_DEBUG(debug_expander>5,
SX_DEBUG(debug_expander > 5,
"starting read with ready '%.*s', waiting for "
"%lu\n", offset, recvbuffer, togot-offset);
"%lu\n", (int)offset, recvbuffer, togot - offset);
if (off > 0)
goto have3;
@@ -593,7 +618,7 @@ have:
reread:
ret = bgpq_selread(b, recvbuffer + offset, togot-offset);
ret = bgpq_selread(b, recvbuffer + offset, togot - offset);
if (ret < 0) {
if (errno == EAGAIN)
goto reread;
@@ -608,7 +633,7 @@ reread:
recvbuffer + offset);
offset += ret;
if (offset < togot) {
SX_DEBUG(debug_expander>5, "expected %lu, got "
SX_DEBUG(debug_expander > 5, "expected %lu, got "
"%lu expanding %s", togot,
strlen(recvbuffer), req->request);
goto reread;
@@ -694,16 +719,17 @@ have3:
}
int
bgpq_expand_irrd(struct bgpq_expander* b,
int (*callback)(char*, struct bgpq_expander*, struct bgpq_request* ),
void* udata, char* fmt, ...)
bgpq_expand_irrd(struct bgpq_expander *b,
int (*callback)(char *, struct bgpq_expander *, struct bgpq_request *),
void *udata, char *fmt, ...)
{
char request[128], response[128];
va_list ap;
int ret, off = 0;
struct bgpq_request *req;
char request[128], response[128];
va_list ap;
ssize_t ret;
int off = 0;
struct bgpq_request *req;
va_start(ap,fmt);
va_start(ap, fmt);
vsnprintf(request, sizeof(request), fmt, ap);
va_end(ap);
@@ -711,12 +737,13 @@ bgpq_expand_irrd(struct bgpq_expander* b,
SX_DEBUG(debug_expander, "expander: sending '%s'\n", request);
ret=write(b->fd, request, strlen(request));
if (ret != strlen(request)) {
sx_report(SX_FATAL,"Partial write to IRRd, only %i bytes "
"written: %s\n", ret, strerror(errno));
exit(1);
}
if ((ret = write(b->fd, request, strlen(request)) == 0) || ret == -1)
err(1, "write");
// push the button by sending a newline
if ((ret = write(b->fd, "\n", 1) == 0) || ret == -1)
err(1, "write");
memset(response, 0, sizeof(response));
repeat:
@@ -739,10 +766,10 @@ repeat:
"'%s'\n", (unsigned long)strlen(response), response);
if (response[0] == 'A') {
char* eon, *c;
long togot = strtoul(response+1, &eon, 10);
char *recvbuffer = malloc(togot + 2);
int offset = 0;
char *eon, *c;
long togot = strtoul(response+1, &eon, 10);
char *recvbuffer = malloc(togot + 2);
int offset = 0;
if (!recvbuffer) {
sx_report(SX_FATAL, "Error allocating %lu bytes: %s\n",
@@ -751,7 +778,7 @@ repeat:
if (eon && *eon != '\n') {
sx_report(SX_ERROR,"A-code finised with wrong char "
"'%c' (%s)\n", *eon,response);
"'%c' (%s)\n", *eon, response);
exit(1);
}
@@ -803,7 +830,7 @@ have3:
if (!strchr(response, '\n'))
goto reread2;
SX_DEBUG(debug_expander>2,"expander: final reply of %lu bytes,"
SX_DEBUG(debug_expander > 2,"expander: final reply of %lu bytes,"
" %.*sreturn code %.*s",
(unsigned long)strlen(recvbuffer), offset, recvbuffer, off,
response);
@@ -842,12 +869,13 @@ have3:
}
int
bgpq_expand(struct bgpq_expander* b)
bgpq_expand(struct bgpq_expander *b)
{
int fd = -1, err, ret, aquery = 0;
struct sx_slentry* mc;
struct addrinfo hints, *res=NULL, *rp;
struct linger sl;
int fd = -1, err, ret, aquery = 0;
struct sx_slentry *mc;
struct addrinfo hints, *res = NULL, *rp;
struct linger sl;
sl.l_onoff = 1;
sl.l_linger = 5;
@@ -866,7 +894,7 @@ bgpq_expand(struct bgpq_expander* b)
for (rp=res; rp; rp = rp->ai_next) {
fd = socket(rp->ai_family, rp->ai_socktype, 0);
if (fd == -1) {
if (errno==EPROTONOSUPPORT || errno==EAFNOSUPPORT)
if (errno == EPROTONOSUPPORT || errno == EAFNOSUPPORT)
continue;
sx_report(SX_ERROR,"Unable to create socket: %s\n",
strerror(errno));
@@ -876,13 +904,11 @@ bgpq_expand(struct bgpq_expander* b)
sizeof(struct linger))) {
sx_report(SX_ERROR,"Unable to set linger on socket: "
"%s\n", strerror(errno));
shutdown(fd, SHUT_RDWR);
close(fd);
exit(1);
}
err = connect(fd, rp->ai_addr, rp->ai_addrlen);
if (err) {
shutdown(fd, SHUT_RDWR);
close(fd);
fd = -1;
continue;
@@ -892,7 +918,6 @@ bgpq_expand(struct bgpq_expander* b)
SX_DEBUG(debug_expander, "Acquired sendbuf of %i "
"bytes\n", err);
} else {
shutdown(fd, SHUT_RDWR);
close(fd);
fd = -1;
continue;
@@ -911,32 +936,61 @@ bgpq_expand(struct bgpq_expander* b)
b->fd = fd;
SX_DEBUG(debug_expander, "Sending '!!' to server to request for the"
" connection to remain open\n");
if ((ret = write(fd, "!!\n", 3)) != 3) {
sx_report(SX_ERROR,"Partial write to IRRd: %i bytes, %s\n",
ret, strerror(errno));
sx_report(SX_ERROR, "Partial write of multiple command mode "
"to IRRd: %i bytes, %s\n", ret, strerror(errno));
exit(1);
}
if (b->identify) {
SX_DEBUG(debug_expander, "b->identify: Sending '!n "
PACKAGE_STRING "' to server.\n");
char ident[128];
snprintf(ident, sizeof(ident), "!n" PACKAGE_STRING "\n");
write(fd, ident, strlen(ident));
read(fd, ident, sizeof(ident));
int ilen = snprintf(ident, sizeof(ident), "!n" PACKAGE_STRING "\n");
if (ilen > 0) {
if ((ret = write(fd, ident, ilen)) != ilen) {
sx_report(SX_ERROR, "Partial write of "
"identifier to IRRd: %i bytes, %s\n",
ret, strerror(errno));
exit(1);
}
memset(ident, 0, sizeof(ident));
if (0 < read(fd, ident, sizeof(ident))) {
SX_DEBUG(debug_expander, "Got answer %s", ident);
} else {
sx_report(SX_ERROR, "ident, failed read from IRRd\n");
exit(1);
}
} else {
sx_report(SX_ERROR, "snprintf(ident) failed\n");
exit(1);
}
}
/* Test whether the server has support for the A query */
if (b->generation >= T_PREFIXLIST) {
if (b->generation >= T_PREFIXLIST && !STAILQ_EMPTY(&b->macroses)) {
char aret[128];
char aresp[] = "F Missing required set name for A query";
SX_DEBUG(debug_expander, "Testing support for A queries\n");
write(fd, "!a\n", 3);
if ((ret = write(fd, "!a\n", 3)) != 3) {
sx_report(SX_ERROR, "Partial write of '!a' test query "
"to IRRd: %i bytes, %s\n", ret, strerror(errno));
exit(1);
}
memset(aret, 0, sizeof(aret));
read(fd, aret, sizeof(aret));
if (strncmp(aret, aresp, strlen(aresp)) == 0) {
SX_DEBUG(debug_expander, "Server supports A query\n");
aquery = 1;
} else
SX_DEBUG(debug_expander, "No support for A queries\n");
if (0 < read(fd, aret, sizeof(aret))) {
if (strncmp(aret, aresp, strlen(aresp)) == 0) {
SX_DEBUG(debug_expander, "Server supports A query\n");
aquery = 1;
} else {
SX_DEBUG(debug_expander, "No support for A query\n");
}
} else {
sx_report(SX_ERROR, "A query test failed read from IRRd\n");
exit(1);
}
}
if (b->sources && b->sources[0] != 0) {
@@ -944,15 +998,28 @@ bgpq_expand(struct bgpq_expander* b)
if (slen < 128)
slen = 128;
char sources[slen];
snprintf(sources, sizeof(sources), "!s%s\n", b->sources);
SX_DEBUG(debug_expander, "Requesting sources %s", sources);
write(fd, sources, strlen(sources));
memset(sources, 0, slen);
read(fd, sources, slen);
SX_DEBUG(debug_expander,"Got answer %s", sources);
if (sources[0] != 'C') {
sx_report(SX_ERROR, "Invalid source(s) '%s': %s\n",
b->sources, sources);
slen = snprintf(sources, sizeof(sources), "!s%s\n", b->sources);
if (slen > 0) {
SX_DEBUG(debug_expander, "Requesting sources %s", sources);
if ((ret = write(fd, sources, slen)) != slen) {
sx_report(SX_ERROR, "Partial write of sources to "
"IRRd: %i bytes, %s\n", ret, strerror(errno));
exit(1);
}
memset(sources, 0, sizeof(sources));
if (0 < read(fd, sources, sizeof(sources))) {
SX_DEBUG(debug_expander, "Got answer %s", sources);
if (sources[0] != 'C') {
sx_report(SX_ERROR, "Invalid source(s) "
"'%s': %s\n", b->sources, sources);
exit(1);
}
} else {
sx_report(SX_ERROR, "failed to read sources\n");
exit(1);
}
} else {
sx_report(SX_ERROR, "snprintf(sources) failed\n");
exit(1);
}
}
@@ -960,24 +1027,24 @@ bgpq_expand(struct bgpq_expander* b)
if (pipelining)
fcntl(fd, F_SETFL, O_NONBLOCK|(fcntl(fd, F_GETFL)));
STAILQ_FOREACH(mc, &b->macroses, next) {
STAILQ_FOREACH(mc, &b->macroses, entries) {
if (!b->maxdepth && RB_EMPTY(&b->stoplist)) {
if (aquery)
bgpq_expand_irrd(b, bgpq_expanded_prefix, b,
"!a%s%s\n",
"!a%s%s",
b->family == AF_INET ? "4" : "6",
mc->text);
else
bgpq_expand_irrd(b, bgpq_expanded_macro, b,
"!i%s,1\n", mc->text);
"!i%s,1", mc->text);
} else {
bgpq_expander_add_already(b,mc->text);
bgpq_expander_add_already(b, mc->text);
if (pipelining)
bgpq_pipeline(b, bgpq_expanded_macro_limit,
NULL, "!i%s\n", mc->text);
NULL, "!i%s", mc->text);
else
bgpq_expand_irrd(b, bgpq_expanded_macro_limit,
NULL, "!i%s\n", mc->text);
NULL, "!i%s", mc->text);
}
}
@@ -990,15 +1057,15 @@ bgpq_expand(struct bgpq_expander* b)
if (b->generation >= T_PREFIXLIST || b->validate_asns) {
uint32_t i, j, k;
STAILQ_FOREACH(mc, &b->rsets, next) {
STAILQ_FOREACH(mc, &b->rsets, entries) {
if (b->family == AF_INET)
bgpq_expand_irrd(b, bgpq_expanded_prefix,
NULL, "!i%s,1\n", mc->text);
NULL, "!i%s,1", mc->text);
else
bgpq_expand_irrd(b, bgpq_expanded_v6prefix,
NULL, "!i%s,1\n", mc->text);
NULL, "!i%s,1", mc->text);
}
for (k=0; k < sizeof(b->asn32s) / sizeof(unsigned char*); k++) {
for (k=0; k < sizeof(b->asn32s) / sizeof(unsigned char *); k++) {
if (!b->asn32s[k])
continue;
for (i=0; i<8192; i++) {
@@ -1007,18 +1074,18 @@ bgpq_expand(struct bgpq_expander* b)
if (b->family == AF_INET6) {
if (!pipelining) {
bgpq_expand_irrd(b, bgpq_expanded_v6prefix,
NULL, "!6as%" PRIu32 "\n", ( k << 16) + i * 8 + j);
NULL, "!6as%" PRIu32, ( k << 16) + i * 8 + j);
} else {
bgpq_pipeline(b, bgpq_expanded_v6prefix,
NULL, "!6as%" PRIu32 "\n", (k << 16) + i * 8 + j);
NULL, "!6as%" PRIu32, (k << 16) + i * 8 + j);
}
} else {
if (!pipelining) {
bgpq_expand_irrd(b, bgpq_expanded_prefix,
NULL, "!gas%" PRIu32 "\n", (k << 16) + i * 8 + j);
NULL, "!gas%" PRIu32, (k << 16) + i * 8 + j);
} else {
bgpq_pipeline(b, bgpq_expanded_prefix,
NULL, "!gas%" PRIu32 "\n", ( k<< 16) + i* 8 + j);
NULL, "!gas%" PRIu32, ( k<< 16) + i* 8 + j);
}
}
}
@@ -1033,15 +1100,94 @@ bgpq_expand(struct bgpq_expander* b)
}
}
write(fd, "!q\n",3);
if ((ret = write(fd, "!q\n", 3)) != 3) {
sx_report(SX_ERROR, "Partial write of quit to IRRd: %i bytes, %s\n",
ret, strerror(errno));
// not worth exiting due to this
}
if (pipelining) {
int fl = fcntl(fd, F_GETFL);
fl &= ~O_NONBLOCK;
fcntl(fd, F_SETFL, fl);
}
shutdown(fd, SHUT_RDWR);
close(fd);
return 1;
}
void
sx_radix_node_freeall(struct sx_radix_node *n) {
if (n->l != NULL)
sx_radix_node_freeall(n->l);
if (n->r != NULL)
sx_radix_node_freeall(n->r);
if (n->son != NULL)
sx_radix_node_freeall(n->son);
if (n->payload)
free(n->payload);
sx_prefix_destroy(n->prefix);
free(n);
}
void
sx_radix_tree_freeall(struct sx_radix_tree *t) {
if (t->head != NULL)
sx_radix_node_freeall(t->head);
free(t);
}
void
bgpq_prequest_freeall(struct bgpq_prequest *bpr) {
}
void
expander_freeall(struct bgpq_expander *expander) {
struct sx_tentry *var, *nxt;
while (!STAILQ_EMPTY(&expander->macroses)) {
struct sx_slentry *n1 = STAILQ_FIRST(&expander->macroses);
STAILQ_REMOVE_HEAD(&expander->macroses, entries);
free(n1->text);
free(n1);
}
while (!STAILQ_EMPTY(&expander->rsets)) {
struct sx_slentry *n1 = STAILQ_FIRST(&expander->rsets);
STAILQ_REMOVE_HEAD(&expander->rsets, entries);
free(n1->text);
free(n1);
}
for (var = RB_MIN(tentree, &expander->already); var != NULL; var = nxt) {
nxt = RB_NEXT(tentree, &expander->already, var);
RB_REMOVE(tentree, &expander->already, var);
free(var->text);
free(var);
}
for (var = RB_MIN(tentree, &expander->stoplist); var != NULL; var = nxt) {
nxt = RB_NEXT(tentree, &expander->stoplist, var);
RB_REMOVE(tentree, &expander->stoplist, var);
free(var->text);
free(var);
}
for (int i = 0; i < 65536; i++) {
if (expander->asn32s[i] != NULL) {
free(expander->asn32s[i]);
}
}
sx_radix_tree_freeall(expander->tree);
bgpq_prequest_freeall(expander->firstpipe);
bgpq_prequest_freeall(expander->lastpipe);
}

View File

@@ -1,83 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <bgpq4.h>
void
sx_radix_node_freeall(struct sx_radix_node *n) {
if (n->l != NULL)
sx_radix_node_freeall(n->l);
if (n->r != NULL)
sx_radix_node_freeall(n->r);
if (n->son != NULL)
sx_radix_node_freeall(n->son);
if (n->payload)
free(n->payload);
sx_prefix_destroy(n->prefix);
free(n);
}
void
sx_radix_tree_freeall(struct sx_radix_tree *t) {
if (t->head != NULL)
sx_radix_node_freeall(t->head);
free(t);
}
void
bgpq_prequest_freeall(struct bgpq_prequest *bpr) {
}
void
expander_freeall(struct bgpq_expander *expander) {
// printf("starting to free all\n");
// seg fault here
// if (expander->sources != NULL) {
// printf("freeing soruces\n");
// free(expander->sources);
//}
// if (expander->name != NULL) {
// printf("freeing name\n");
// free(expander->name);
//}
// printf("freeing asn32s\n");
for (int i = 0; i < 65536; i++) {
if (expander->asn32s[i] != NULL) {
free(expander->asn32s[i]);
}
}
// if (expander->match != NULL) {
// printf("freeing match\n");
// free(expander->match);
//}
//if (expander->server != NULL) {
// printf("freeing server\n");
// free(expander->server);
//}
//if (expander->port != NULL) {
// printf("freeing port\n");
// free(expander->port);
//}
//if (expander->format != NULL) {
// printf("freeing format\n");
// free(expander->format);
//}
sx_radix_tree_freeall(expander->tree);
bgpq_prequest_freeall(expander->firstpipe);
bgpq_prequest_freeall(expander->lastpipe);
// printf("finished freeing all\n");
}

View File

@@ -1,5 +0,0 @@
void sx_radix_node_freeall(struct sx_radix_node *n);
void sx_radix_tree_freeall(struct sx_radix_tree *t);
void bgpq_prequest_freeall(struct bgpq_prequest *bpr);
void expander_freeall(struct bgpq_expander *expander);

138
extern.h Normal file
View File

@@ -0,0 +1,138 @@
/*
* Copyright (c) 2007-2019 Alexandre Snarskii <snar@snar.spb.ru>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <sys/queue.h>
#include <sys/tree.h>
#include "sx_prefix.h"
struct sx_slentry {
STAILQ_ENTRY(sx_slentry) entries;
char* text;
};
struct sx_slentry* sx_slentry_new(char* text);
struct sx_tentry {
RB_ENTRY(sx_tentry) entries;
char* text;
};
struct sx_tentry* sx_tentry_new(char* text);
typedef enum {
V_CISCO = 0,
V_JUNIPER,
V_CISCO_XR,
V_JSON,
V_BIRD,
V_OPENBGPD,
V_FORMAT,
V_NOKIA,
V_HUAWEI,
V_MIKROTIK,
V_NOKIA_MD,
V_ARISTA
} bgpq_vendor_t;
typedef enum {
T_NONE = 0,
T_ASPATH,
T_OASPATH,
T_ASSET,
T_PREFIXLIST,
T_EACL,
T_ROUTE_FILTER_LIST
} bgpq_gen_t;
struct bgpq_expander;
struct bgpq_request {
STAILQ_ENTRY(bgpq_request) next;
char *request;
int size, offset;
void *udata;
unsigned int depth;
int (*callback)(char *, struct bgpq_expander *,
struct bgpq_request *);
};
struct bgpq_expander {
struct sx_radix_tree *tree;
STAILQ_HEAD(sx_slentries, sx_slentry) macroses, rsets;
RB_HEAD(tentree, sx_tentry) already, stoplist;
int family;
char *sources;
uint32_t asnumber;
int aswidth;
char *name;
bgpq_vendor_t vendor;
bgpq_gen_t generation;
int identify;
int sequence;
unsigned int maxdepth;
unsigned int cdepth;
int validate_asns;
unsigned char *asn32s[65536];
struct bgpq_prequest *firstpipe, *lastpipe;
int piped;
char *match;
char *server;
char *port;
char *format;
unsigned int maxlen;
STAILQ_HEAD(bgpq_requests, bgpq_request) wq, rq;
int fd;
};
int bgpq_expander_init(struct bgpq_expander *b, int af);
int bgpq_expander_add_asset(struct bgpq_expander *b, char *set);
int bgpq_expander_add_rset(struct bgpq_expander *b, char *set);
int bgpq_expander_add_as(struct bgpq_expander *b, char *as);
int bgpq_expander_add_prefix(struct bgpq_expander *b, char *prefix);
int bgpq_expander_add_prefix_range(struct bgpq_expander *b, char *prefix);
int bgpq_expander_add_stop(struct bgpq_expander *b, char *object);
int bgpq_expand(struct bgpq_expander *b);
int bgpq4_print_prefixlist(FILE *f, struct bgpq_expander *b);
int bgpq4_print_eacl(FILE *f, struct bgpq_expander *b);
int bgpq4_print_aspath(FILE *f, struct bgpq_expander *b);
int bgpq4_print_asset(FILE *f, struct bgpq_expander *b);
int bgpq4_print_oaspath(FILE *f, struct bgpq_expander *b);
int bgpq4_print_route_filter_list(FILE *f, struct bgpq_expander *b);
void sx_radix_node_freeall(struct sx_radix_node *n);
void sx_radix_tree_freeall(struct sx_radix_tree *t);
void bgpq_prequest_freeall(struct bgpq_prequest *bpr);
void expander_freeall(struct bgpq_expander *expander);
/* s - number of opened socket, dir is either SO_SNDBUF or SO_RCVBUF */
int sx_maxsockbuf(int s, int dir);
#ifndef HAVE_STRLCPY
size_t strlcpy(char* dst, const char* src, size_t size);
#endif

6
include/Makefile.am Normal file
View File

@@ -0,0 +1,6 @@
noinst_HEADERS =
noinst_HEADERS += sys/_null.h
noinst_HEADERS += sys/queue.h
noinst_HEADERS += sys/tree.h
noinst_HEADERS += sys/types.h
noinst_HEADERS += string.h

24
include/string.h Normal file
View File

@@ -0,0 +1,24 @@
/*
* Public domain
* string.h compatibility shim
*/
#include_next <string.h>
#ifndef LIBCOMPAT_STRING_H
#define LIBCOMPAT_STRING_H
#include <sys/types.h>
#if defined(__sun) || defined(__hpux)
/* Some functions historically defined in string.h were placed in strings.h by
* SUS. Use the same hack as OS X and FreeBSD use to work around on Solaris and HPUX.
*/
#include <strings.h>
#endif
#ifndef HAVE_STRLCPY
size_t strlcpy(char *dst, const char *src, size_t siz);
#endif
#endif

18
include/sys/_null.h Normal file
View File

@@ -0,0 +1,18 @@
/* $OpenBSD: _null.h,v 1.2 2016/09/09 22:07:58 millert Exp $ */
/*
* Written by Todd C. Miller, September 9, 2016
* Public domain.
*/
#ifndef NULL
#if !defined(__cplusplus)
#define NULL ((void *)0)
#elif __cplusplus >= 201103L
#define NULL nullptr
#elif defined(__GNUG__)
#define NULL __null
#else
#define NULL 0L
#endif
#endif

633
include/sys/queue.h Normal file
View File

@@ -0,0 +1,633 @@
/* $OpenBSD: queue.h,v 1.46 2020/12/30 13:33:12 millert Exp $ */
/* $NetBSD: queue.h,v 1.11 1996/05/16 05:17:14 mycroft Exp $ */
/*
* Copyright (c) 1991, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)queue.h 8.5 (Berkeley) 8/20/94
*/
#ifndef _SYS_QUEUE_H_
#define _SYS_QUEUE_H_
#include <sys/_null.h>
/*
* This file defines five types of data structures: singly-linked lists,
* lists, simple queues, tail queues and XOR simple queues.
*
*
* A singly-linked list is headed by a single forward pointer. The elements
* are singly linked for minimum space and pointer manipulation overhead at
* the expense of O(n) removal for arbitrary elements. New elements can be
* added to the list after an existing element or at the head of the list.
* Elements being removed from the head of the list should use the explicit
* macro for this purpose for optimum efficiency. A singly-linked list may
* only be traversed in the forward direction. Singly-linked lists are ideal
* for applications with large datasets and few or no removals or for
* implementing a LIFO queue.
*
* A list is headed by a single forward pointer (or an array of forward
* pointers for a hash table header). The elements are doubly linked
* so that an arbitrary element can be removed without a need to
* traverse the list. New elements can be added to the list before
* or after an existing element or at the head of the list. A list
* may only be traversed in the forward direction.
*
* A simple queue is headed by a pair of pointers, one to the head of the
* list and the other to the tail of the list. The elements are singly
* linked to save space, so elements can only be removed from the
* head of the list. New elements can be added to the list before or after
* an existing element, at the head of the list, or at the end of the
* list. A simple queue may only be traversed in the forward direction.
*
* A tail queue is headed by a pair of pointers, one to the head of the
* list and the other to the tail of the list. The elements are doubly
* linked so that an arbitrary element can be removed without a need to
* traverse the list. New elements can be added to the list before or
* after an existing element, at the head of the list, or at the end of
* the list. A tail queue may be traversed in either direction.
*
* An XOR simple queue is used in the same way as a regular simple queue.
* The difference is that the head structure also includes a "cookie" that
* is XOR'd with the queue pointer (first, last or next) to generate the
* real pointer value.
*
* For details on the use of these macros, see the queue(3) manual page.
*/
#if defined(QUEUE_MACRO_DEBUG) || (defined(_KERNEL) && defined(DIAGNOSTIC))
#define _Q_INVALID ((void *)-1)
#define _Q_INVALIDATE(a) (a) = _Q_INVALID
#else
#define _Q_INVALIDATE(a)
#endif
/*
* Singly-linked List definitions.
*/
#define SLIST_HEAD(name, type) \
struct name { \
struct type *slh_first; /* first element */ \
}
#define SLIST_HEAD_INITIALIZER(head) \
{ NULL }
#define SLIST_ENTRY(type) \
struct { \
struct type *sle_next; /* next element */ \
}
/*
* Singly-linked List access methods.
*/
#define SLIST_FIRST(head) ((head)->slh_first)
#define SLIST_END(head) NULL
#define SLIST_EMPTY(head) (SLIST_FIRST(head) == SLIST_END(head))
#define SLIST_NEXT(elm, field) ((elm)->field.sle_next)
#define SLIST_FOREACH(var, head, field) \
for((var) = SLIST_FIRST(head); \
(var) != SLIST_END(head); \
(var) = SLIST_NEXT(var, field))
#define SLIST_FOREACH_SAFE(var, head, field, tvar) \
for ((var) = SLIST_FIRST(head); \
(var) && ((tvar) = SLIST_NEXT(var, field), 1); \
(var) = (tvar))
/*
* Singly-linked List functions.
*/
#define SLIST_INIT(head) { \
SLIST_FIRST(head) = SLIST_END(head); \
}
#define SLIST_INSERT_AFTER(slistelm, elm, field) do { \
(elm)->field.sle_next = (slistelm)->field.sle_next; \
(slistelm)->field.sle_next = (elm); \
} while (0)
#define SLIST_INSERT_HEAD(head, elm, field) do { \
(elm)->field.sle_next = (head)->slh_first; \
(head)->slh_first = (elm); \
} while (0)
#define SLIST_REMOVE_AFTER(elm, field) do { \
(elm)->field.sle_next = (elm)->field.sle_next->field.sle_next; \
} while (0)
#define SLIST_REMOVE_HEAD(head, field) do { \
(head)->slh_first = (head)->slh_first->field.sle_next; \
} while (0)
#define SLIST_REMOVE(head, elm, type, field) do { \
if ((head)->slh_first == (elm)) { \
SLIST_REMOVE_HEAD((head), field); \
} else { \
struct type *curelm = (head)->slh_first; \
\
while (curelm->field.sle_next != (elm)) \
curelm = curelm->field.sle_next; \
curelm->field.sle_next = \
curelm->field.sle_next->field.sle_next; \
} \
_Q_INVALIDATE((elm)->field.sle_next); \
} while (0)
/*
* List definitions.
*/
#define LIST_HEAD(name, type) \
struct name { \
struct type *lh_first; /* first element */ \
}
#define LIST_HEAD_INITIALIZER(head) \
{ NULL }
#define LIST_ENTRY(type) \
struct { \
struct type *le_next; /* next element */ \
struct type **le_prev; /* address of previous next element */ \
}
/*
* List access methods.
*/
#define LIST_FIRST(head) ((head)->lh_first)
#define LIST_END(head) NULL
#define LIST_EMPTY(head) (LIST_FIRST(head) == LIST_END(head))
#define LIST_NEXT(elm, field) ((elm)->field.le_next)
#define LIST_FOREACH(var, head, field) \
for((var) = LIST_FIRST(head); \
(var)!= LIST_END(head); \
(var) = LIST_NEXT(var, field))
#define LIST_FOREACH_SAFE(var, head, field, tvar) \
for ((var) = LIST_FIRST(head); \
(var) && ((tvar) = LIST_NEXT(var, field), 1); \
(var) = (tvar))
/*
* List functions.
*/
#define LIST_INIT(head) do { \
LIST_FIRST(head) = LIST_END(head); \
} while (0)
#define LIST_INSERT_AFTER(listelm, elm, field) do { \
if (((elm)->field.le_next = (listelm)->field.le_next) != NULL) \
(listelm)->field.le_next->field.le_prev = \
&(elm)->field.le_next; \
(listelm)->field.le_next = (elm); \
(elm)->field.le_prev = &(listelm)->field.le_next; \
} while (0)
#define LIST_INSERT_BEFORE(listelm, elm, field) do { \
(elm)->field.le_prev = (listelm)->field.le_prev; \
(elm)->field.le_next = (listelm); \
*(listelm)->field.le_prev = (elm); \
(listelm)->field.le_prev = &(elm)->field.le_next; \
} while (0)
#define LIST_INSERT_HEAD(head, elm, field) do { \
if (((elm)->field.le_next = (head)->lh_first) != NULL) \
(head)->lh_first->field.le_prev = &(elm)->field.le_next;\
(head)->lh_first = (elm); \
(elm)->field.le_prev = &(head)->lh_first; \
} while (0)
#define LIST_REMOVE(elm, field) do { \
if ((elm)->field.le_next != NULL) \
(elm)->field.le_next->field.le_prev = \
(elm)->field.le_prev; \
*(elm)->field.le_prev = (elm)->field.le_next; \
_Q_INVALIDATE((elm)->field.le_prev); \
_Q_INVALIDATE((elm)->field.le_next); \
} while (0)
#define LIST_REPLACE(elm, elm2, field) do { \
if (((elm2)->field.le_next = (elm)->field.le_next) != NULL) \
(elm2)->field.le_next->field.le_prev = \
&(elm2)->field.le_next; \
(elm2)->field.le_prev = (elm)->field.le_prev; \
*(elm2)->field.le_prev = (elm2); \
_Q_INVALIDATE((elm)->field.le_prev); \
_Q_INVALIDATE((elm)->field.le_next); \
} while (0)
/*
* Simple queue definitions.
*/
#define SIMPLEQ_HEAD(name, type) \
struct name { \
struct type *sqh_first; /* first element */ \
struct type **sqh_last; /* addr of last next element */ \
}
#define SIMPLEQ_HEAD_INITIALIZER(head) \
{ NULL, &(head).sqh_first }
#define SIMPLEQ_ENTRY(type) \
struct { \
struct type *sqe_next; /* next element */ \
}
/*
* Simple queue access methods.
*/
#define SIMPLEQ_FIRST(head) ((head)->sqh_first)
#define SIMPLEQ_END(head) NULL
#define SIMPLEQ_EMPTY(head) (SIMPLEQ_FIRST(head) == SIMPLEQ_END(head))
#define SIMPLEQ_NEXT(elm, field) ((elm)->field.sqe_next)
#define SIMPLEQ_FOREACH(var, head, field) \
for((var) = SIMPLEQ_FIRST(head); \
(var) != SIMPLEQ_END(head); \
(var) = SIMPLEQ_NEXT(var, field))
#define SIMPLEQ_FOREACH_SAFE(var, head, field, tvar) \
for ((var) = SIMPLEQ_FIRST(head); \
(var) && ((tvar) = SIMPLEQ_NEXT(var, field), 1); \
(var) = (tvar))
/*
* Simple queue functions.
*/
#define SIMPLEQ_INIT(head) do { \
(head)->sqh_first = NULL; \
(head)->sqh_last = &(head)->sqh_first; \
} while (0)
#define SIMPLEQ_INSERT_HEAD(head, elm, field) do { \
if (((elm)->field.sqe_next = (head)->sqh_first) == NULL) \
(head)->sqh_last = &(elm)->field.sqe_next; \
(head)->sqh_first = (elm); \
} while (0)
#define SIMPLEQ_INSERT_TAIL(head, elm, field) do { \
(elm)->field.sqe_next = NULL; \
*(head)->sqh_last = (elm); \
(head)->sqh_last = &(elm)->field.sqe_next; \
} while (0)
#define SIMPLEQ_INSERT_AFTER(head, listelm, elm, field) do { \
if (((elm)->field.sqe_next = (listelm)->field.sqe_next) == NULL)\
(head)->sqh_last = &(elm)->field.sqe_next; \
(listelm)->field.sqe_next = (elm); \
} while (0)
#define SIMPLEQ_REMOVE_HEAD(head, field) do { \
if (((head)->sqh_first = (head)->sqh_first->field.sqe_next) == NULL) \
(head)->sqh_last = &(head)->sqh_first; \
} while (0)
#define SIMPLEQ_REMOVE_AFTER(head, elm, field) do { \
if (((elm)->field.sqe_next = (elm)->field.sqe_next->field.sqe_next) \
== NULL) \
(head)->sqh_last = &(elm)->field.sqe_next; \
} while (0)
#define SIMPLEQ_CONCAT(head1, head2) do { \
if (!SIMPLEQ_EMPTY((head2))) { \
*(head1)->sqh_last = (head2)->sqh_first; \
(head1)->sqh_last = (head2)->sqh_last; \
SIMPLEQ_INIT((head2)); \
} \
} while (0)
/*
* XOR Simple queue definitions.
*/
#define XSIMPLEQ_HEAD(name, type) \
struct name { \
struct type *sqx_first; /* first element */ \
struct type **sqx_last; /* addr of last next element */ \
unsigned long sqx_cookie; \
}
#define XSIMPLEQ_ENTRY(type) \
struct { \
struct type *sqx_next; /* next element */ \
}
/*
* XOR Simple queue access methods.
*/
#define XSIMPLEQ_XOR(head, ptr) ((__typeof(ptr))((head)->sqx_cookie ^ \
(unsigned long)(ptr)))
#define XSIMPLEQ_FIRST(head) XSIMPLEQ_XOR(head, ((head)->sqx_first))
#define XSIMPLEQ_END(head) NULL
#define XSIMPLEQ_EMPTY(head) (XSIMPLEQ_FIRST(head) == XSIMPLEQ_END(head))
#define XSIMPLEQ_NEXT(head, elm, field) XSIMPLEQ_XOR(head, ((elm)->field.sqx_next))
#define XSIMPLEQ_FOREACH(var, head, field) \
for ((var) = XSIMPLEQ_FIRST(head); \
(var) != XSIMPLEQ_END(head); \
(var) = XSIMPLEQ_NEXT(head, var, field))
#define XSIMPLEQ_FOREACH_SAFE(var, head, field, tvar) \
for ((var) = XSIMPLEQ_FIRST(head); \
(var) && ((tvar) = XSIMPLEQ_NEXT(head, var, field), 1); \
(var) = (tvar))
/*
* XOR Simple queue functions.
*/
#define XSIMPLEQ_INIT(head) do { \
arc4random_buf(&(head)->sqx_cookie, sizeof((head)->sqx_cookie)); \
(head)->sqx_first = XSIMPLEQ_XOR(head, NULL); \
(head)->sqx_last = XSIMPLEQ_XOR(head, &(head)->sqx_first); \
} while (0)
#define XSIMPLEQ_INSERT_HEAD(head, elm, field) do { \
if (((elm)->field.sqx_next = (head)->sqx_first) == \
XSIMPLEQ_XOR(head, NULL)) \
(head)->sqx_last = XSIMPLEQ_XOR(head, &(elm)->field.sqx_next); \
(head)->sqx_first = XSIMPLEQ_XOR(head, (elm)); \
} while (0)
#define XSIMPLEQ_INSERT_TAIL(head, elm, field) do { \
(elm)->field.sqx_next = XSIMPLEQ_XOR(head, NULL); \
*(XSIMPLEQ_XOR(head, (head)->sqx_last)) = XSIMPLEQ_XOR(head, (elm)); \
(head)->sqx_last = XSIMPLEQ_XOR(head, &(elm)->field.sqx_next); \
} while (0)
#define XSIMPLEQ_INSERT_AFTER(head, listelm, elm, field) do { \
if (((elm)->field.sqx_next = (listelm)->field.sqx_next) == \
XSIMPLEQ_XOR(head, NULL)) \
(head)->sqx_last = XSIMPLEQ_XOR(head, &(elm)->field.sqx_next); \
(listelm)->field.sqx_next = XSIMPLEQ_XOR(head, (elm)); \
} while (0)
#define XSIMPLEQ_REMOVE_HEAD(head, field) do { \
if (((head)->sqx_first = XSIMPLEQ_XOR(head, \
(head)->sqx_first)->field.sqx_next) == XSIMPLEQ_XOR(head, NULL)) \
(head)->sqx_last = XSIMPLEQ_XOR(head, &(head)->sqx_first); \
} while (0)
#define XSIMPLEQ_REMOVE_AFTER(head, elm, field) do { \
if (((elm)->field.sqx_next = XSIMPLEQ_XOR(head, \
(elm)->field.sqx_next)->field.sqx_next) \
== XSIMPLEQ_XOR(head, NULL)) \
(head)->sqx_last = \
XSIMPLEQ_XOR(head, &(elm)->field.sqx_next); \
} while (0)
/*
* Tail queue definitions.
*/
#define TAILQ_HEAD(name, type) \
struct name { \
struct type *tqh_first; /* first element */ \
struct type **tqh_last; /* addr of last next element */ \
}
#define TAILQ_HEAD_INITIALIZER(head) \
{ NULL, &(head).tqh_first }
#define TAILQ_ENTRY(type) \
struct { \
struct type *tqe_next; /* next element */ \
struct type **tqe_prev; /* address of previous next element */ \
}
/*
* Tail queue access methods.
*/
#define TAILQ_FIRST(head) ((head)->tqh_first)
#define TAILQ_END(head) NULL
#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next)
#define TAILQ_LAST(head, headname) \
(*(((struct headname *)((head)->tqh_last))->tqh_last))
/* XXX */
#define TAILQ_PREV(elm, headname, field) \
(*(((struct headname *)((elm)->field.tqe_prev))->tqh_last))
#define TAILQ_EMPTY(head) \
(TAILQ_FIRST(head) == TAILQ_END(head))
#define TAILQ_FOREACH(var, head, field) \
for((var) = TAILQ_FIRST(head); \
(var) != TAILQ_END(head); \
(var) = TAILQ_NEXT(var, field))
#define TAILQ_FOREACH_SAFE(var, head, field, tvar) \
for ((var) = TAILQ_FIRST(head); \
(var) != TAILQ_END(head) && \
((tvar) = TAILQ_NEXT(var, field), 1); \
(var) = (tvar))
#define TAILQ_FOREACH_REVERSE(var, head, headname, field) \
for((var) = TAILQ_LAST(head, headname); \
(var) != TAILQ_END(head); \
(var) = TAILQ_PREV(var, headname, field))
#define TAILQ_FOREACH_REVERSE_SAFE(var, head, headname, field, tvar) \
for ((var) = TAILQ_LAST(head, headname); \
(var) != TAILQ_END(head) && \
((tvar) = TAILQ_PREV(var, headname, field), 1); \
(var) = (tvar))
/*
* Tail queue functions.
*/
#define TAILQ_INIT(head) do { \
(head)->tqh_first = NULL; \
(head)->tqh_last = &(head)->tqh_first; \
} while (0)
#define TAILQ_INSERT_HEAD(head, elm, field) do { \
if (((elm)->field.tqe_next = (head)->tqh_first) != NULL) \
(head)->tqh_first->field.tqe_prev = \
&(elm)->field.tqe_next; \
else \
(head)->tqh_last = &(elm)->field.tqe_next; \
(head)->tqh_first = (elm); \
(elm)->field.tqe_prev = &(head)->tqh_first; \
} while (0)
#define TAILQ_INSERT_TAIL(head, elm, field) do { \
(elm)->field.tqe_next = NULL; \
(elm)->field.tqe_prev = (head)->tqh_last; \
*(head)->tqh_last = (elm); \
(head)->tqh_last = &(elm)->field.tqe_next; \
} while (0)
#define TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \
if (((elm)->field.tqe_next = (listelm)->field.tqe_next) != NULL)\
(elm)->field.tqe_next->field.tqe_prev = \
&(elm)->field.tqe_next; \
else \
(head)->tqh_last = &(elm)->field.tqe_next; \
(listelm)->field.tqe_next = (elm); \
(elm)->field.tqe_prev = &(listelm)->field.tqe_next; \
} while (0)
#define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \
(elm)->field.tqe_prev = (listelm)->field.tqe_prev; \
(elm)->field.tqe_next = (listelm); \
*(listelm)->field.tqe_prev = (elm); \
(listelm)->field.tqe_prev = &(elm)->field.tqe_next; \
} while (0)
#define TAILQ_REMOVE(head, elm, field) do { \
if (((elm)->field.tqe_next) != NULL) \
(elm)->field.tqe_next->field.tqe_prev = \
(elm)->field.tqe_prev; \
else \
(head)->tqh_last = (elm)->field.tqe_prev; \
*(elm)->field.tqe_prev = (elm)->field.tqe_next; \
_Q_INVALIDATE((elm)->field.tqe_prev); \
_Q_INVALIDATE((elm)->field.tqe_next); \
} while (0)
#define TAILQ_REPLACE(head, elm, elm2, field) do { \
if (((elm2)->field.tqe_next = (elm)->field.tqe_next) != NULL) \
(elm2)->field.tqe_next->field.tqe_prev = \
&(elm2)->field.tqe_next; \
else \
(head)->tqh_last = &(elm2)->field.tqe_next; \
(elm2)->field.tqe_prev = (elm)->field.tqe_prev; \
*(elm2)->field.tqe_prev = (elm2); \
_Q_INVALIDATE((elm)->field.tqe_prev); \
_Q_INVALIDATE((elm)->field.tqe_next); \
} while (0)
#define TAILQ_CONCAT(head1, head2, field) do { \
if (!TAILQ_EMPTY(head2)) { \
*(head1)->tqh_last = (head2)->tqh_first; \
(head2)->tqh_first->field.tqe_prev = (head1)->tqh_last; \
(head1)->tqh_last = (head2)->tqh_last; \
TAILQ_INIT((head2)); \
} \
} while (0)
/*
* Singly-linked Tail queue declarations.
*/
#define STAILQ_HEAD(name, type) \
struct name { \
struct type *stqh_first; /* first element */ \
struct type **stqh_last; /* addr of last next element */ \
}
#define STAILQ_HEAD_INITIALIZER(head) \
{ NULL, &(head).stqh_first }
#define STAILQ_ENTRY(type) \
struct { \
struct type *stqe_next; /* next element */ \
}
/*
* Singly-linked Tail queue access methods.
*/
#define STAILQ_FIRST(head) ((head)->stqh_first)
#define STAILQ_END(head) NULL
#define STAILQ_EMPTY(head) (STAILQ_FIRST(head) == STAILQ_END(head))
#define STAILQ_NEXT(elm, field) ((elm)->field.stqe_next)
#define STAILQ_FOREACH(var, head, field) \
for ((var) = STAILQ_FIRST(head); \
(var) != STAILQ_END(head); \
(var) = STAILQ_NEXT(var, field))
#define STAILQ_FOREACH_SAFE(var, head, field, tvar) \
for ((var) = STAILQ_FIRST(head); \
(var) && ((tvar) = STAILQ_NEXT(var, field), 1); \
(var) = (tvar))
/*
* Singly-linked Tail queue functions.
*/
#define STAILQ_INIT(head) do { \
STAILQ_FIRST((head)) = NULL; \
(head)->stqh_last = &STAILQ_FIRST((head)); \
} while (0)
#define STAILQ_INSERT_HEAD(head, elm, field) do { \
if ((STAILQ_NEXT((elm), field) = STAILQ_FIRST((head))) == NULL) \
(head)->stqh_last = &STAILQ_NEXT((elm), field); \
STAILQ_FIRST((head)) = (elm); \
} while (0)
#define STAILQ_INSERT_TAIL(head, elm, field) do { \
STAILQ_NEXT((elm), field) = NULL; \
*(head)->stqh_last = (elm); \
(head)->stqh_last = &STAILQ_NEXT((elm), field); \
} while (0)
#define STAILQ_INSERT_AFTER(head, listelm, elm, field) do { \
if ((STAILQ_NEXT((elm), field) = STAILQ_NEXT((elm), field)) == NULL)\
(head)->stqh_last = &STAILQ_NEXT((elm), field); \
STAILQ_NEXT((elm), field) = (elm); \
} while (0)
#define STAILQ_REMOVE_HEAD(head, field) do { \
if ((STAILQ_FIRST((head)) = \
STAILQ_NEXT(STAILQ_FIRST((head)), field)) == NULL) \
(head)->stqh_last = &STAILQ_FIRST((head)); \
} while (0)
#define STAILQ_REMOVE_AFTER(head, elm, field) do { \
if ((STAILQ_NEXT(elm, field) = \
STAILQ_NEXT(STAILQ_NEXT(elm, field), field)) == NULL) \
(head)->stqh_last = &STAILQ_NEXT((elm), field); \
} while (0)
#define STAILQ_REMOVE(head, elm, type, field) do { \
if (STAILQ_FIRST((head)) == (elm)) { \
STAILQ_REMOVE_HEAD((head), field); \
} else { \
struct type *curelm = (head)->stqh_first; \
while (STAILQ_NEXT(curelm, field) != (elm)) \
curelm = STAILQ_NEXT(curelm, field); \
STAILQ_REMOVE_AFTER(head, curelm, field); \
} \
} while (0)
#define STAILQ_CONCAT(head1, head2) do { \
if (!STAILQ_EMPTY((head2))) { \
*(head1)->stqh_last = (head2)->stqh_first; \
(head1)->stqh_last = (head2)->stqh_last; \
STAILQ_INIT((head2)); \
} \
} while (0)
#define STAILQ_LAST(head, type, field) \
(STAILQ_EMPTY((head)) ? NULL : \
((struct type *)(void *) \
((char *)((head)->stqh_last) - offsetof(struct type, field))))
#endif /* !_SYS_QUEUE_H_ */

View File

@@ -1,8 +1,5 @@
/* $NetBSD: tree.h,v 1.8 2004/03/28 19:38:30 provos Exp $ */
/* $OpenBSD: tree.h,v 1.7 2002/10/17 21:51:54 art Exp $ */
/* $FreeBSD: stable/10/sys/sys/tree.h 189204 2009-03-01 04:57:23Z bms $ */
/*-
/* $OpenBSD: tree.h,v 1.30 2020/10/10 18:03:41 otto Exp $ */
/*
* Copyright 2002 Niels Provos <provos@citi.umich.edu>
* All rights reserved.
*
@@ -30,9 +27,7 @@
#ifndef _SYS_TREE_H_
#define _SYS_TREE_H_
#if HAVE_SYS_CDEFS_H
#include <sys/cdefs.h>
#endif
#include <sys/_null.h>
/*
* This file defines data structures for different types of trees:
@@ -71,7 +66,7 @@ struct name { \
#define SPLAY_INIT(root) do { \
(root)->sph_root = NULL; \
} while (/*CONSTCOND*/ 0)
} while (0)
#define SPLAY_ENTRY(type) \
struct { \
@@ -89,32 +84,32 @@ struct { \
SPLAY_LEFT((head)->sph_root, field) = SPLAY_RIGHT(tmp, field); \
SPLAY_RIGHT(tmp, field) = (head)->sph_root; \
(head)->sph_root = tmp; \
} while (/*CONSTCOND*/ 0)
} while (0)
#define SPLAY_ROTATE_LEFT(head, tmp, field) do { \
SPLAY_RIGHT((head)->sph_root, field) = SPLAY_LEFT(tmp, field); \
SPLAY_LEFT(tmp, field) = (head)->sph_root; \
(head)->sph_root = tmp; \
} while (/*CONSTCOND*/ 0)
} while (0)
#define SPLAY_LINKLEFT(head, tmp, field) do { \
SPLAY_LEFT(tmp, field) = (head)->sph_root; \
tmp = (head)->sph_root; \
(head)->sph_root = SPLAY_LEFT((head)->sph_root, field); \
} while (/*CONSTCOND*/ 0)
} while (0)
#define SPLAY_LINKRIGHT(head, tmp, field) do { \
SPLAY_RIGHT(tmp, field) = (head)->sph_root; \
tmp = (head)->sph_root; \
(head)->sph_root = SPLAY_RIGHT((head)->sph_root, field); \
} while (/*CONSTCOND*/ 0)
} while (0)
#define SPLAY_ASSEMBLE(head, node, left, right, field) do { \
SPLAY_RIGHT(left, field) = SPLAY_LEFT((head)->sph_root, field); \
SPLAY_LEFT(right, field) = SPLAY_RIGHT((head)->sph_root, field);\
SPLAY_LEFT((head)->sph_root, field) = SPLAY_RIGHT(node, field); \
SPLAY_RIGHT((head)->sph_root, field) = SPLAY_LEFT(node, field); \
} while (/*CONSTCOND*/ 0)
} while (0)
/* Generates prototypes and inline functions */
@@ -125,7 +120,7 @@ struct type *name##_SPLAY_INSERT(struct name *, struct type *); \
struct type *name##_SPLAY_REMOVE(struct name *, struct type *); \
\
/* Finds the node with the same key as elm */ \
static __inline struct type * \
static __unused __inline struct type * \
name##_SPLAY_FIND(struct name *head, struct type *elm) \
{ \
if (SPLAY_EMPTY(head)) \
@@ -136,7 +131,7 @@ name##_SPLAY_FIND(struct name *head, struct type *elm) \
return (NULL); \
} \
\
static __inline struct type * \
static __unused __inline struct type * \
name##_SPLAY_NEXT(struct name *head, struct type *elm) \
{ \
name##_SPLAY(head, elm); \
@@ -150,7 +145,7 @@ name##_SPLAY_NEXT(struct name *head, struct type *elm) \
return (elm); \
} \
\
static __inline struct type * \
static __unused __inline struct type * \
name##_SPLAY_MIN_MAX(struct name *head, int val) \
{ \
name##_SPLAY_MINMAX(head, val); \
@@ -215,7 +210,7 @@ name##_SPLAY(struct name *head, struct type *elm) \
SPLAY_LEFT(&__node, field) = SPLAY_RIGHT(&__node, field) = NULL;\
__left = __right = &__node; \
\
while ((__comp = (cmp)(elm, (head)->sph_root)) != 0) { \
while ((__comp = (cmp)(elm, (head)->sph_root))) { \
if (__comp < 0) { \
__tmp = SPLAY_LEFT((head)->sph_root, field); \
if (__tmp == NULL) \
@@ -305,7 +300,7 @@ struct name { \
#define RB_INIT(root) do { \
(root)->rbh_root = NULL; \
} while (/*CONSTCOND*/ 0)
} while (0)
#define RB_BLACK 0
#define RB_RED 1
@@ -328,12 +323,12 @@ struct { \
RB_PARENT(elm, field) = parent; \
RB_LEFT(elm, field) = RB_RIGHT(elm, field) = NULL; \
RB_COLOR(elm, field) = RB_RED; \
} while (/*CONSTCOND*/ 0)
} while (0)
#define RB_SET_BLACKRED(black, red, field) do { \
RB_COLOR(black, field) = RB_BLACK; \
RB_COLOR(red, field) = RB_RED; \
} while (/*CONSTCOND*/ 0)
} while (0)
#ifndef RB_AUGMENT
#define RB_AUGMENT(x) do {} while (0)
@@ -341,11 +336,11 @@ struct { \
#define RB_ROTATE_LEFT(head, elm, tmp, field) do { \
(tmp) = RB_RIGHT(elm, field); \
if ((RB_RIGHT(elm, field) = RB_LEFT(tmp, field)) != NULL) { \
if ((RB_RIGHT(elm, field) = RB_LEFT(tmp, field))) { \
RB_PARENT(RB_LEFT(tmp, field), field) = (elm); \
} \
RB_AUGMENT(elm); \
if ((RB_PARENT(tmp, field) = RB_PARENT(elm, field)) != NULL) { \
if ((RB_PARENT(tmp, field) = RB_PARENT(elm, field))) { \
if ((elm) == RB_LEFT(RB_PARENT(elm, field), field)) \
RB_LEFT(RB_PARENT(elm, field), field) = (tmp); \
else \
@@ -357,15 +352,15 @@ struct { \
RB_AUGMENT(tmp); \
if ((RB_PARENT(tmp, field))) \
RB_AUGMENT(RB_PARENT(tmp, field)); \
} while (/*CONSTCOND*/ 0)
} while (0)
#define RB_ROTATE_RIGHT(head, elm, tmp, field) do { \
(tmp) = RB_LEFT(elm, field); \
if ((RB_LEFT(elm, field) = RB_RIGHT(tmp, field)) != NULL) { \
if ((RB_LEFT(elm, field) = RB_RIGHT(tmp, field))) { \
RB_PARENT(RB_RIGHT(tmp, field), field) = (elm); \
} \
RB_AUGMENT(elm); \
if ((RB_PARENT(tmp, field) = RB_PARENT(elm, field)) != NULL) { \
if ((RB_PARENT(tmp, field) = RB_PARENT(elm, field))) { \
if ((elm) == RB_LEFT(RB_PARENT(elm, field), field)) \
RB_LEFT(RB_PARENT(elm, field), field) = (tmp); \
else \
@@ -377,13 +372,13 @@ struct { \
RB_AUGMENT(tmp); \
if ((RB_PARENT(tmp, field))) \
RB_AUGMENT(RB_PARENT(tmp, field)); \
} while (/*CONSTCOND*/ 0)
} while (0)
/* Generates prototypes and inline functions */
#define RB_PROTOTYPE(name, type, field, cmp) \
RB_PROTOTYPE_INTERNAL(name, type, field, cmp,)
#define RB_PROTOTYPE_STATIC(name, type, field, cmp) \
RB_PROTOTYPE_INTERNAL(name, type, field, cmp, __unused static)
RB_PROTOTYPE_INTERNAL(name, type, field, cmp, __attribute__((__unused__)) static)
#define RB_PROTOTYPE_INTERNAL(name, type, field, cmp, attr) \
attr void name##_RB_INSERT_COLOR(struct name *, struct type *); \
attr void name##_RB_REMOVE_COLOR(struct name *, struct type *, struct type *);\
@@ -402,13 +397,13 @@ attr struct type *name##_RB_MINMAX(struct name *, int); \
#define RB_GENERATE(name, type, field, cmp) \
RB_GENERATE_INTERNAL(name, type, field, cmp,)
#define RB_GENERATE_STATIC(name, type, field, cmp) \
RB_GENERATE_INTERNAL(name, type, field, cmp, __unused static)
RB_GENERATE_INTERNAL(name, type, field, cmp, __attribute__((__unused__)) static)
#define RB_GENERATE_INTERNAL(name, type, field, cmp, attr) \
attr void \
name##_RB_INSERT_COLOR(struct name *head, struct type *elm) \
{ \
struct type *parent, *gparent, *tmp; \
while ((parent = RB_PARENT(elm, field)) != NULL && \
while ((parent = RB_PARENT(elm, field)) && \
RB_COLOR(parent, field) == RB_RED) { \
gparent = RB_PARENT(parent, field); \
if (parent == RB_LEFT(gparent, field)) { \
@@ -472,8 +467,7 @@ name##_RB_REMOVE_COLOR(struct name *head, struct type *parent, struct type *elm)
if (RB_RIGHT(tmp, field) == NULL || \
RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK) {\
struct type *oleft; \
if ((oleft = RB_LEFT(tmp, field)) \
!= NULL) \
if ((oleft = RB_LEFT(tmp, field)))\
RB_COLOR(oleft, field) = RB_BLACK;\
RB_COLOR(tmp, field) = RB_RED; \
RB_ROTATE_RIGHT(head, tmp, oleft, field);\
@@ -505,8 +499,7 @@ name##_RB_REMOVE_COLOR(struct name *head, struct type *parent, struct type *elm)
if (RB_LEFT(tmp, field) == NULL || \
RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) {\
struct type *oright; \
if ((oright = RB_RIGHT(tmp, field)) \
!= NULL) \
if ((oright = RB_RIGHT(tmp, field)))\
RB_COLOR(oright, field) = RB_BLACK;\
RB_COLOR(tmp, field) = RB_RED; \
RB_ROTATE_LEFT(head, tmp, oright, field);\
@@ -538,7 +531,7 @@ name##_RB_REMOVE(struct name *head, struct type *elm) \
else { \
struct type *left; \
elm = RB_RIGHT(elm, field); \
while ((left = RB_LEFT(elm, field)) != NULL) \
while ((left = RB_LEFT(elm, field))) \
elm = left; \
child = RB_RIGHT(elm, field); \
parent = RB_PARENT(elm, field); \
@@ -571,7 +564,7 @@ name##_RB_REMOVE(struct name *head, struct type *elm) \
left = parent; \
do { \
RB_AUGMENT(left); \
} while ((left = RB_PARENT(left, field)) != NULL); \
} while ((left = RB_PARENT(left, field))); \
} \
goto color; \
} \
@@ -739,14 +732,9 @@ name##_RB_MINMAX(struct name *head, int val) \
(x) != NULL; \
(x) = name##_RB_NEXT(x))
#define RB_FOREACH_FROM(x, name, y) \
for ((x) = (y); \
((x) != NULL) && ((y) = name##_RB_NEXT(x), (x) != NULL); \
(x) = (y))
#define RB_FOREACH_SAFE(x, name, head, y) \
for ((x) = RB_MIN(name, head); \
((x) != NULL) && ((y) = name##_RB_NEXT(x), (x) != NULL); \
((x) != NULL) && ((y) = name##_RB_NEXT(x), 1); \
(x) = (y))
#define RB_FOREACH_REVERSE(x, name, head) \
@@ -754,14 +742,265 @@ name##_RB_MINMAX(struct name *head, int val) \
(x) != NULL; \
(x) = name##_RB_PREV(x))
#define RB_FOREACH_REVERSE_FROM(x, name, y) \
for ((x) = (y); \
((x) != NULL) && ((y) = name##_RB_PREV(x), (x) != NULL); \
(x) = (y))
#define RB_FOREACH_REVERSE_SAFE(x, name, head, y) \
for ((x) = RB_MAX(name, head); \
((x) != NULL) && ((y) = name##_RB_PREV(x), (x) != NULL); \
((x) != NULL) && ((y) = name##_RB_PREV(x), 1); \
(x) = (y))
/*
* Copyright (c) 2016 David Gwynne <dlg@openbsd.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
struct rb_type {
int (*t_compare)(const void *, const void *);
void (*t_augment)(void *);
unsigned int t_offset; /* offset of rb_entry in type */
};
struct rb_tree {
struct rb_entry *rbt_root;
};
struct rb_entry {
struct rb_entry *rbt_parent;
struct rb_entry *rbt_left;
struct rb_entry *rbt_right;
unsigned int rbt_color;
};
#define RBT_HEAD(_name, _type) \
struct _name { \
struct rb_tree rbh_root; \
}
#define RBT_ENTRY(_type) struct rb_entry
static inline void
_rb_init(struct rb_tree *rbt)
{
rbt->rbt_root = NULL;
}
static inline int
_rb_empty(struct rb_tree *rbt)
{
return (rbt->rbt_root == NULL);
}
void *_rb_insert(const struct rb_type *, struct rb_tree *, void *);
void *_rb_remove(const struct rb_type *, struct rb_tree *, void *);
void *_rb_find(const struct rb_type *, struct rb_tree *, const void *);
void *_rb_nfind(const struct rb_type *, struct rb_tree *, const void *);
void *_rb_root(const struct rb_type *, struct rb_tree *);
void *_rb_min(const struct rb_type *, struct rb_tree *);
void *_rb_max(const struct rb_type *, struct rb_tree *);
void *_rb_next(const struct rb_type *, void *);
void *_rb_prev(const struct rb_type *, void *);
void *_rb_left(const struct rb_type *, void *);
void *_rb_right(const struct rb_type *, void *);
void *_rb_parent(const struct rb_type *, void *);
void _rb_set_left(const struct rb_type *, void *, void *);
void _rb_set_right(const struct rb_type *, void *, void *);
void _rb_set_parent(const struct rb_type *, void *, void *);
void _rb_poison(const struct rb_type *, void *, unsigned long);
int _rb_check(const struct rb_type *, void *, unsigned long);
#define RBT_INITIALIZER(_head) { { NULL } }
#define RBT_PROTOTYPE(_name, _type, _field, _cmp) \
extern const struct rb_type *const _name##_RBT_TYPE; \
\
__unused static inline void \
_name##_RBT_INIT(struct _name *head) \
{ \
_rb_init(&head->rbh_root); \
} \
\
__unused static inline struct _type * \
_name##_RBT_INSERT(struct _name *head, struct _type *elm) \
{ \
return _rb_insert(_name##_RBT_TYPE, &head->rbh_root, elm); \
} \
\
__unused static inline struct _type * \
_name##_RBT_REMOVE(struct _name *head, struct _type *elm) \
{ \
return _rb_remove(_name##_RBT_TYPE, &head->rbh_root, elm); \
} \
\
__unused static inline struct _type * \
_name##_RBT_FIND(struct _name *head, const struct _type *key) \
{ \
return _rb_find(_name##_RBT_TYPE, &head->rbh_root, key); \
} \
\
__unused static inline struct _type * \
_name##_RBT_NFIND(struct _name *head, const struct _type *key) \
{ \
return _rb_nfind(_name##_RBT_TYPE, &head->rbh_root, key); \
} \
\
__unused static inline struct _type * \
_name##_RBT_ROOT(struct _name *head) \
{ \
return _rb_root(_name##_RBT_TYPE, &head->rbh_root); \
} \
\
__unused static inline int \
_name##_RBT_EMPTY(struct _name *head) \
{ \
return _rb_empty(&head->rbh_root); \
} \
\
__unused static inline struct _type * \
_name##_RBT_MIN(struct _name *head) \
{ \
return _rb_min(_name##_RBT_TYPE, &head->rbh_root); \
} \
\
__unused static inline struct _type * \
_name##_RBT_MAX(struct _name *head) \
{ \
return _rb_max(_name##_RBT_TYPE, &head->rbh_root); \
} \
\
__unused static inline struct _type * \
_name##_RBT_NEXT(struct _type *elm) \
{ \
return _rb_next(_name##_RBT_TYPE, elm); \
} \
\
__unused static inline struct _type * \
_name##_RBT_PREV(struct _type *elm) \
{ \
return _rb_prev(_name##_RBT_TYPE, elm); \
} \
\
__unused static inline struct _type * \
_name##_RBT_LEFT(struct _type *elm) \
{ \
return _rb_left(_name##_RBT_TYPE, elm); \
} \
\
__unused static inline struct _type * \
_name##_RBT_RIGHT(struct _type *elm) \
{ \
return _rb_right(_name##_RBT_TYPE, elm); \
} \
\
__unused static inline struct _type * \
_name##_RBT_PARENT(struct _type *elm) \
{ \
return _rb_parent(_name##_RBT_TYPE, elm); \
} \
\
__unused static inline void \
_name##_RBT_SET_LEFT(struct _type *elm, struct _type *left) \
{ \
_rb_set_left(_name##_RBT_TYPE, elm, left); \
} \
\
__unused static inline void \
_name##_RBT_SET_RIGHT(struct _type *elm, struct _type *right) \
{ \
_rb_set_right(_name##_RBT_TYPE, elm, right); \
} \
\
__unused static inline void \
_name##_RBT_SET_PARENT(struct _type *elm, struct _type *parent) \
{ \
_rb_set_parent(_name##_RBT_TYPE, elm, parent); \
} \
\
__unused static inline void \
_name##_RBT_POISON(struct _type *elm, unsigned long poison) \
{ \
_rb_poison(_name##_RBT_TYPE, elm, poison); \
} \
\
__unused static inline int \
_name##_RBT_CHECK(struct _type *elm, unsigned long poison) \
{ \
return _rb_check(_name##_RBT_TYPE, elm, poison); \
}
#define RBT_GENERATE_INTERNAL(_name, _type, _field, _cmp, _aug) \
static int \
_name##_RBT_COMPARE(const void *lptr, const void *rptr) \
{ \
const struct _type *l = lptr, *r = rptr; \
return _cmp(l, r); \
} \
static const struct rb_type _name##_RBT_INFO = { \
_name##_RBT_COMPARE, \
_aug, \
offsetof(struct _type, _field), \
}; \
const struct rb_type *const _name##_RBT_TYPE = &_name##_RBT_INFO
#define RBT_GENERATE_AUGMENT(_name, _type, _field, _cmp, _aug) \
static void \
_name##_RBT_AUGMENT(void *ptr) \
{ \
struct _type *p = ptr; \
return _aug(p); \
} \
RBT_GENERATE_INTERNAL(_name, _type, _field, _cmp, _name##_RBT_AUGMENT)
#define RBT_GENERATE(_name, _type, _field, _cmp) \
RBT_GENERATE_INTERNAL(_name, _type, _field, _cmp, NULL)
#define RBT_INIT(_name, _head) _name##_RBT_INIT(_head)
#define RBT_INSERT(_name, _head, _elm) _name##_RBT_INSERT(_head, _elm)
#define RBT_REMOVE(_name, _head, _elm) _name##_RBT_REMOVE(_head, _elm)
#define RBT_FIND(_name, _head, _key) _name##_RBT_FIND(_head, _key)
#define RBT_NFIND(_name, _head, _key) _name##_RBT_NFIND(_head, _key)
#define RBT_ROOT(_name, _head) _name##_RBT_ROOT(_head)
#define RBT_EMPTY(_name, _head) _name##_RBT_EMPTY(_head)
#define RBT_MIN(_name, _head) _name##_RBT_MIN(_head)
#define RBT_MAX(_name, _head) _name##_RBT_MAX(_head)
#define RBT_NEXT(_name, _elm) _name##_RBT_NEXT(_elm)
#define RBT_PREV(_name, _elm) _name##_RBT_PREV(_elm)
#define RBT_LEFT(_name, _elm) _name##_RBT_LEFT(_elm)
#define RBT_RIGHT(_name, _elm) _name##_RBT_RIGHT(_elm)
#define RBT_PARENT(_name, _elm) _name##_RBT_PARENT(_elm)
#define RBT_SET_LEFT(_name, _elm, _l) _name##_RBT_SET_LEFT(_elm, _l)
#define RBT_SET_RIGHT(_name, _elm, _r) _name##_RBT_SET_RIGHT(_elm, _r)
#define RBT_SET_PARENT(_name, _elm, _p) _name##_RBT_SET_PARENT(_elm, _p)
#define RBT_POISON(_name, _elm, _p) _name##_RBT_POISON(_elm, _p)
#define RBT_CHECK(_name, _elm, _p) _name##_RBT_CHECK(_elm, _p)
#define RBT_FOREACH(_e, _name, _head) \
for ((_e) = RBT_MIN(_name, (_head)); \
(_e) != NULL; \
(_e) = RBT_NEXT(_name, (_e)))
#define RBT_FOREACH_SAFE(_e, _name, _head, _n) \
for ((_e) = RBT_MIN(_name, (_head)); \
(_e) != NULL && ((_n) = RBT_NEXT(_name, (_e)), 1); \
(_e) = (_n))
#define RBT_FOREACH_REVERSE(_e, _name, _head) \
for ((_e) = RBT_MAX(_name, (_head)); \
(_e) != NULL; \
(_e) = RBT_PREV(_name, (_e)))
#define RBT_FOREACH_REVERSE_SAFE(_e, _name, _head, _n) \
for ((_e) = RBT_MAX(_name, (_head)); \
(_e) != NULL && ((_n) = RBT_PREV(_name, (_e)), 1); \
(_e) = (_n))
#endif /* _SYS_TREE_H_ */

25
include/sys/types.h Normal file
View File

@@ -0,0 +1,25 @@
/*
* Public domain
* sys/types.h compatibility shim
*/
#include_next <sys/types.h>
#ifndef LIBCOMPAT_SYS_TYPES_H
#define LIBCOMPAT_SYS_TYPES_H
#include <stdint.h>
#ifdef __MINGW32__
#include <_bsd_types.h>
#endif
#if !defined(HAVE_ATTRIBUTE__DEAD) && !defined(__dead)
#define __dead __attribute__((__noreturn__))
#endif
#if !defined(HAVE_ATTRIBUTE__BOUNDED__) && !defined(__bounded__)
# define __bounded__(x, y, z)
#endif
#endif

View File

@@ -1,3 +1,30 @@
/*
* Copyright (c) 2019-2021 Job Snijders <job@sobornost.net>
* Copyright (c) 2007-2019 Alexandre Snarskii <snar@snar.spb.ru>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if HAVE_CONFIG_H
#include <config.h>
#endif
@@ -14,112 +41,135 @@
#include <strings.h>
#include <unistd.h>
#include "bgpq4.h"
#include "extern.h"
#include "sx_report.h"
#include "expander_freeall.h"
extern int debug_expander;
extern int debug_aggregation;
extern int pipelining;
extern int expand_special_asn;
int
static int
usage(int ecode)
{
printf("\nUsage: bgpq4 [-h host[:port]] [-S sources] [-E|G <num>"
"|f <num>|t] [-46ABbdJjKNnwXz] [-R len] <OBJECTS>...\n");
"|f <num>|t] [-46ABbdJjKNnwXz] [-R len] <OBJECTS> ... "
"[EXCEPT <OBJECTS> ...]\n");
printf("\nVendor targets:\n");
printf(" no option : Cisco IOS Classic (default)\n");
printf(" -X : Cisco IOS XR\n");
printf(" -U : Huawei\n");
printf(" -j : JSON\n");
printf(" -J : Juniper Junos\n");
printf(" -K : MikroTik RouterOS\n");
printf(" -b : NIC.CZ BIRD\n");
printf(" -N : Nokia SR OS (Classic CLI)\n");
printf(" -n : Nokia SR OS (MD-CLI)\n");
printf(" -B : OpenBSD OpenBGPD\n");
printf(" -e : Arista EOS\n");
printf(" -F fmt : User defined format (example: '-F %%n/%%l')\n");
printf("\nInput filters:\n");
printf(" -4 : generate IPv4 prefix-lists (default)\n");
printf(" -6 : generate IPv6 prefix-lists\n");
printf(" -A : try to aggregate prefix-lists/route-filters\n");
printf(" -B : generate OpenBGPD output\n");
printf(" -b : generate BIRD output\n");
printf(" -d : generate some debugging output\n");
printf(" -E : generate extended access-list(Cisco), "
"route-filter (Juniper)\n"
" [ip|ipv6]-prefix-list (Nokia) or prefix-set "
"(OpenBGPD)\n");
printf(" -F fmt : generate output in user-defined format\n");
printf(" -f number : generate input as-path access-list\n");
printf(" -G number : generate output as-path access-list\n");
printf(" -h host : host running IRRD software (rr.ntt.net by "
"default)\n"
" (use host:port to specify alternate port)\n");
printf(" -J : generate config for JunOS\n");
printf(" -j : generate JSON output\n");
printf(" -K : generate config for MikroTik RouterOS\n");
printf(" -M match : extra match conditions for JunOS route-filters\n");
printf(" -m len : maximum prefix length (default: 32 for IPv4, "
"128 for IPv6)\n");
printf(" -L depth : limit recursion depth (default: unlimited)\n"),
printf(" -l name : use specified name for generated access/prefix/.."
" list\n");
printf(" -N : generate config for Nokia SR OS classic CLI\n");
printf(" -n : generate config for Nokia SR OS MD-CLI\n");
printf(" -R len : allow more specific routes up to specified masklen\n");
printf(" -r len : allow more specific routes from masklen specified\n");
printf(" -S sources: use only specified sources (recommended:"
" RADB,RIPE,APNIC)\n");
printf(" -s : generate sequence numbers in prefix-lists (IOS only)\n");
printf(" -T : disable pipelining (experimental, faster mode)\n");
printf(" -t : generate as-sets for OpenBGPD (OpenBSD 6.4+), BIRD "
"and JSON formats\n");
printf(" -U : generate config for Huawei\n");
printf(" -W len : specify max-entries on as-path line (use 0 for "
"infinity)\n");
printf(" -S sources: only use specified IRR sources, in the specified "
"order (comma separated)\n");
printf(" -w : 'validate' AS numbers: accept only ones with "
"registered routes\n");
printf(" -X : generate Cisco IOS XR output\n");
printf("\n" PACKAGE_NAME " version: " PACKAGE_VERSION "\n");
printf("\nOutput modifiers:\n");
printf(" -A : try to aggregate prefix-lists/route-filters\n");
printf(" -E : generate extended access-list (Cisco), "
"route-filter (Juniper)\n"
" [ip|ipv6]-prefix-list (Nokia) or prefix-set "
"(OpenBGPD)\n");
printf(" -f number : generate input as-path access-list\n");
printf(" -G number : generate output as-path access-list\n");
printf(" -M match : extra match conditions for JunOS route-filters\n");
printf(" -l name : use specified name for generated access/prefix/.."
" list\n");
printf(" -R len : allow more specific routes up to specified masklen\n");
printf(" -r len : allow more specific routes from masklen specified\n");
printf(" -s : generate sequence numbers in prefix-lists (IOS only)\n");
printf(" -t : generate as-sets for OpenBGPD (OpenBGPD 6.4+), BIRD "
"and JSON formats\n");
printf(" -z : generate route-filter-list (Junos only)\n");
printf(" -W len : specify max-entries on as-path line (use 0 for "
"infinity)\n");
printf("\nUtility operations:\n");
printf(" -d : generate some debugging output\n");
printf(" -h host : host running IRRD software (default: rr.ntt.net)\n"
" use 'host:port' to specify alternate port\n");
printf(" -T : disable pipelining (not recommended)\n");
printf(" -v : print version and exit\n");
printf("\n" PACKAGE_NAME " version: " PACKAGE_VERSION " "
"(https://github.com/bgp/bgpq4)\n");
exit(ecode);
}
void
exclusive()
static void
version(void)
{
printf(PACKAGE_NAME " - a versatile utility to generate BGP filters\n"
"version: " PACKAGE_VERSION "\n"
"website: https://github.com/bgp/bgpq4\n"
"maintainer: Job Snijders <job@sobornost.net>\n");
exit(0);
}
static void
exclusive(void)
{
fprintf(stderr,"-E, -f <asnum>, -G <asnum>, and -t are mutually "
"exclusive\n");
exit(1);
}
void
vendor_exclusive()
static void
vendor_exclusive(void)
{
fprintf(stderr, "-b (BIRD), -B (OpenBGPD), -F (formatted), -J (Junos),"
" -j (JSON), -N (Nokia SR OS Classic), -n (Nokia SR OS MD-CLI),"
" -U (Huawei) and -X (IOS XR) options are mutually exclusive\n");
" -U (Huawei), -e (Arista) and -X (IOS XR) options are mutually"
" exclusive\n");
exit(1);
}
int
parseasnumber(struct bgpq_expander* expander, char* optarg)
static int
parseasnumber(struct bgpq_expander *expander, char *asnstr)
{
char* eon=NULL;
expander->asnumber=strtoul(optarg,&eon, 10);
char *eon = NULL;
expander->asnumber = strtoul(asnstr, &eon, 10);
if (expander->asnumber < 1 || expander->asnumber > (65535ul * 65535)) {
sx_report(SX_FATAL,"Invalid AS number: %s\n", optarg);
sx_report(SX_FATAL, "Invalid AS number: %s\n", asnstr);
exit(1);
}
if(eon && *eon == '.') {
if (eon && *eon == '.') {
/* -f 3.3, for example */
uint32_t loas = strtoul(eon+1, &eon, 10);
if(expander->asnumber > 65535) {
uint32_t loas = strtoul(eon + 1, &eon, 10);
if (expander->asnumber > 65535) {
/* should prevent incorrect numbers like 65537.1 */
sx_report(SX_FATAL,"Invalid AS number: %s\n", optarg);
sx_report(SX_FATAL,"Invalid AS number: %s\n", asnstr);
exit(1);
}
if(loas < 1 || loas > 65535) {
sx_report(SX_FATAL,"Invalid AS number: %s\n", optarg);
if (loas < 1 || loas > 65535) {
sx_report(SX_FATAL,"Invalid AS number: %s\n", asnstr);
exit(1);
}
if (eon && *eon) {
sx_report(SX_FATAL,"Invalid symbol in AS number: "
"%c (%s)\n", *eon, optarg);
"%c (%s)\n", *eon, asnstr);
exit(1);
}
expander->asnumber=(expander->asnumber << 16) + loas;
} else if (eon && *eon) {
sx_report(SX_FATAL,"Invalid symbol in AS number: %c (%s)\n",
*eon, optarg);
*eon, asnstr);
exit(1);
}
return 0;
@@ -146,9 +196,15 @@ main(int argc, char* argv[])
if (getenv("IRRD_SOURCES"))
expander.sources=getenv("IRRD_SOURCES");
while ((c = getopt(argc,argv,"46a:AbBdDEF:S:jJKf:l:L:m:M:NnW:pr:R:G:tTh:UwXsz"))
while ((c = getopt(argc, argv,
"346a:AbBdDEeF:S:jJKf:l:L:m:M:NnW:pr:R:G:tTh:UwXsvz"))
!=EOF) {
switch (c) {
case '3':
/*
* No-op, left for backwards compatibility with bgpq3
*/
break;
case '4':
/* do nothing, expander already configured for IPv4 */
if (expander.family == AF_INET6) {
@@ -194,6 +250,12 @@ main(int argc, char* argv[])
exclusive();
expander.generation = T_EACL;
break;
case 'e':
if (expander.vendor)
vendor_exclusive();
expander.vendor = V_ARISTA;
expander.sequence = 1;
break;
case 'F':
if (expander.vendor)
exclusive();
@@ -277,44 +339,44 @@ main(int argc, char* argv[])
break;
case 'M':
{
char* c, *d;
char *mc, *md;
expander.match = strdup(optarg);
c = d = expander.match;
while (*c) {
if (*c == '\\') {
if (*(c+1) == '\n') {
*d = '\n';
d++;
c += 2;
} else if (*(c + 1) == 'r') {
*d = '\r';
d++;
c += 2;
} else if (*(c + 1) == 't') {
*d = '\t';
d++;
c += 2;
} else if (*(c + 1) == '\\') {
*d = '\\';
d++;
c += 2;
mc = md = expander.match;
while (*mc) {
if (*mc == '\\') {
if (*(mc+1) == '\n') {
*md = '\n';
md++;
mc += 2;
} else if (*(mc + 1) == 'r') {
*md = '\r';
md++;
mc += 2;
} else if (*(mc + 1) == 't') {
*md = '\t';
md++;
mc += 2;
} else if (*(mc + 1) == '\\') {
*md = '\\';
md++;
mc += 2;
} else {
sx_report(SX_FATAL, "Unsupported"
" escape \%c (0x%2.2x) in "
"'%s'\n",
isprint(*c) ? *c : 20,
*c, optarg);
isprint(*mc) ? *mc : 20,
*mc, optarg);
exit(1);
}
} else {
if (c != d) {
*d = *c;
if (mc != md) {
*md = *mc;
}
d++;
c++;
md++;
mc++;
}
}
*d = 0;
*md = 0;
}
break;
case 'N':
@@ -363,6 +425,9 @@ main(int argc, char* argv[])
vendor_exclusive();
expander.vendor = V_CISCO_XR;
break;
case 'v':
version();
break;
case 'z':
if (expander.generation)
exclusive();
@@ -377,107 +442,114 @@ main(int argc, char* argv[])
argv += optind;
if (!widthSet) {
if (expander.generation==T_ASPATH) {
if (expander.vendor == V_CISCO) {
if (expander.generation == T_ASPATH) {
int vendor = expander.vendor;
switch (vendor) {
case V_ARISTA:
case V_CISCO:
case V_MIKROTIK:
expander.aswidth = 4;
} else if (expander.vendor == V_CISCO_XR) {
case V_CISCO_XR:
expander.aswidth = 6;
} else if (expander.vendor == V_JUNIPER) {
case V_JUNIPER:
case V_NOKIA:
case V_NOKIA_MD:
expander.aswidth = 8;
} else if (expander.vendor == V_MIKROTIK) {
expander.aswidth = 4;
} else if (expander.vendor == V_BIRD) {
case V_BIRD:
expander.aswidth = 10;
} else if (expander.vendor == V_NOKIA ||
expander.vendor == V_NOKIA_MD) {
expander.aswidth = 8;
}
} else if (expander.generation == T_OASPATH) {
if (expander.vendor == V_CISCO) {
int vendor = expander.vendor;
switch (vendor) {
case V_ARISTA:
case V_CISCO:
expander.aswidth = 5;
} else if (expander.vendor == V_CISCO_XR) {
case V_CISCO_XR:
expander.aswidth = 7;
} else if (expander.vendor==V_JUNIPER) {
expander.aswidth = 8;
} else if (expander.vendor == V_NOKIA ||
expander.vendor == V_NOKIA_MD) {
case V_JUNIPER:
case V_NOKIA:
case V_NOKIA_MD:
expander.aswidth = 8;
}
}
}
if (!expander.generation) {
if (!expander.generation)
expander.generation = T_PREFIXLIST;
}
if (expander.generation != (T_PREFIXLIST & T_ASPATH & T_OASPATH) &&
expander.vendor == V_CISCO_XR) {
if (expander.vendor == V_CISCO_XR
&& expander.generation != T_PREFIXLIST
&& expander.generation != T_ASPATH
&& expander.generation != T_OASPATH) {
sx_report(SX_FATAL, "Sorry, only prefix-sets and as-paths "
"supported for IOS XR\n");
"supported for IOS XR\n");
}
if (expander.vendor == V_BIRD && expander.generation != T_PREFIXLIST &&
expander.generation != T_ASPATH && expander.generation != T_ASSET) {
if (expander.vendor == V_BIRD
&& expander.generation != T_PREFIXLIST
&& expander.generation != T_ASPATH
&& expander.generation != T_ASSET) {
sx_report(SX_FATAL, "Sorry, only prefix-lists and as-paths/as-sets "
"supported for BIRD output\n");
}
if (expander.vendor == V_JSON && expander.generation != T_PREFIXLIST &&
expander.generation != T_ASPATH && expander.generation != T_ASSET) {
if (expander.vendor == V_JSON
&& expander.generation != T_PREFIXLIST
&& expander.generation != T_ASPATH
&& expander.generation != T_ASSET) {
sx_report(SX_FATAL, "Sorry, only prefix-lists and as-paths/as-sets "
"supported for JSON output\n");
}
if (expander.vendor == V_FORMAT && expander.generation != T_PREFIXLIST)
if (expander.vendor == V_FORMAT
&& expander.generation != T_PREFIXLIST)
sx_report(SX_FATAL, "Sorry, only prefix-lists supported in formatted "
"output\n");
if (expander.vendor == V_FORMAT && (refine || refineLow)) {
sx_report(SX_FATAL, "Sorry, formatted output (-F <fmt>) in not "
"compatible with -R/-r options\n");
exit(1);
}
if (expander.vendor == V_HUAWEI && expander.generation != T_ASPATH &&
expander.generation != T_OASPATH && expander.generation != T_PREFIXLIST)
if (expander.vendor == V_HUAWEI
&& expander.generation != T_ASPATH
&& expander.generation != T_OASPATH
&& expander.generation != T_PREFIXLIST)
sx_report(SX_FATAL, "Sorry, only as-paths and prefix-lists supported "
"for Huawei output\n");
if (expander.generation == T_ROUTE_FILTER_LIST && expander.vendor != V_JUNIPER)
if (expander.generation == T_ROUTE_FILTER_LIST
&& expander.vendor != V_JUNIPER)
sx_report(SX_FATAL, "Route-filter-lists (-z) supported for Juniper (-J)"
" output only\n");
if (expander.generation == T_ASSET && expander.vendor != V_JSON &&
expander.vendor != V_OPENBGPD && expander.vendor != V_BIRD)
if (expander.generation == T_ASSET
&& expander.vendor != V_JSON
&& expander.vendor != V_OPENBGPD
&& expander.vendor != V_BIRD)
sx_report(SX_FATAL, "As-Sets (-t) supported for JSON (-j), OpenBGPD "
"(-B) and BIRD (-b) output only\n");
if (aggregate && expander.vendor == V_JUNIPER && expander.generation == T_PREFIXLIST) {
if (aggregate
&& expander.vendor == V_JUNIPER
&& expander.generation == T_PREFIXLIST) {
sx_report(SX_FATAL, "Sorry, aggregation (-A) does not work in"
" Juniper prefix-lists\nYou can try route-filters (-E) "
"or route-filter-lists (-z) instead of prefix-lists\n.");
exit(1);
}
if(aggregate && expander.vendor == V_FORMAT) {
sx_report(SX_FATAL, "Sorry, aggregation (-A) is not compatible with "
"formatted output (-F <fmt>)\n");
exit(1);
}
if (aggregate && (expander.vendor == V_NOKIA_MD || expander.vendor == V_NOKIA)
if (aggregate
&& (expander.vendor == V_NOKIA_MD || expander.vendor == V_NOKIA)
&& expander.generation != T_PREFIXLIST) {
sx_report(SX_FATAL, "Sorry, aggregation (-A) is not supported with "
"ip-prefix-lists (-E) on Nokia.\n");
exit(1);
}
if (refine && (expander.vendor == V_NOKIA_MD || expander.vendor == V_NOKIA)
if (refine
&& (expander.vendor == V_NOKIA_MD || expander.vendor == V_NOKIA)
&& expander.generation != T_PREFIXLIST) {
sx_report(SX_FATAL, "Sorry, more-specifics (-R) is not supported with "
"ip-prefix-lists (-E) on Nokia.\n");
exit(1);
}
if (refineLow && (expander.vendor == V_NOKIA_MD || expander.vendor == V_NOKIA)
if (refineLow
&& (expander.vendor == V_NOKIA_MD || expander.vendor == V_NOKIA)
&& expander.generation != T_PREFIXLIST) {
sx_report(SX_FATAL, "Sorry, more-specifics (-r) is not supported with "
"ip-prefix-lists (-E) on Nokia.\n");
@@ -490,9 +562,10 @@ main(int argc, char* argv[])
exit(1);
}
if (expander.sequence && expander.vendor != V_CISCO) {
if (expander.sequence
&& (expander.vendor != V_CISCO && expander.vendor != V_ARISTA)) {
sx_report(SX_FATAL, "Sorry, prefix-lists sequencing (-s) supported"
" only for IOS\n");
" only for IOS and EOS\n");
exit(1);
}
@@ -509,10 +582,9 @@ main(int argc, char* argv[])
refine = 128;
}
if (refineLow && refineLow > refine) {
if (refineLow && refineLow > refine)
sx_report(SX_FATAL, "Incompatible values for -r %u and -R %u\n",
refineLow, refine);
}
if (refine || refineLow) {
if (expander.family == AF_INET6 && refine > 128) {
@@ -544,13 +616,12 @@ main(int argc, char* argv[])
}
if (expander.generation < T_PREFIXLIST) {
if (refine) {
if (refine)
sx_report(SX_FATAL, "Sorry, more-specific filter (-R %u) "
"supported only with prefix-list generation\n", refine);
} else {
else
sx_report(SX_FATAL, "Sorry, more-specific filter (-r %u) "
"supported only with prefix-list generation\n", refineLow);
}
}
}
@@ -568,11 +639,10 @@ main(int argc, char* argv[])
*/
expander.maxlen = maxlen;
}
} else if (expander.family == AF_INET) {
} else if (expander.family == AF_INET)
expander.maxlen = 32;
} else if (expander.family == AF_INET6) {
else if (expander.family == AF_INET6)
expander.maxlen = 128;
}
if (expander.generation == T_EACL && expander.vendor == V_CISCO
&& expander.family == AF_INET6) {
@@ -605,32 +675,33 @@ main(int argc, char* argv[])
if (!strcmp(argv[0], "EXCEPT")) {
exceptmode = 1;
} else if (exceptmode) {
bgpq_expander_add_stop(&expander,argv[0]);
bgpq_expander_add_stop(&expander, argv[0]);
} else if (!strncasecmp(argv[0], "AS-", 3)) {
bgpq_expander_add_asset(&expander,argv[0]);
bgpq_expander_add_asset(&expander, argv[0]);
} else if (!strncasecmp(argv[0], "RS-", 3)) {
bgpq_expander_add_rset(&expander,argv[0]);
bgpq_expander_add_rset(&expander, argv[0]);
} else if (!strncasecmp(argv[0], "AS", 2)) {
char* c;
if ((c = strchr(argv[0], ':'))) {
if (!strncasecmp(c + 1, "AS-", 3)) {
char *ec;
if ((ec = strchr(argv[0], ':'))) {
if (!strncasecmp(ec + 1, "AS-", 3)) {
bgpq_expander_add_asset(&expander, argv[0]);
} else if (!strncasecmp(c + 1, "RS-", 3)) {
} else if (!strncasecmp(ec + 1, "RS-", 3)) {
bgpq_expander_add_rset(&expander, argv[0]);
} else {
SX_DEBUG(debug_expander,"Unknown sub-as"
" object %s\n", argv[0]);
}
} else {
bgpq_expander_add_as(&expander,argv[0]);
bgpq_expander_add_as(&expander, argv[0]);
}
} else {
char* c = strchr(argv[0], '^');
if (!c && !bgpq_expander_add_prefix(&expander, argv[0])) {
char *ec = strchr(argv[0], '^');
if (!ec && !bgpq_expander_add_prefix(&expander, argv[0])) {
sx_report(SX_ERROR, "Unable to add prefix %s "
"(bad prefix or address-family)\n", argv[0]);
exit(1);
} else if (c && !bgpq_expander_add_prefix_range(&expander, argv[0])){
} else if (ec && !bgpq_expander_add_prefix_range(&expander,
argv[0])) {
sx_report(SX_ERROR, "Unable to add prefix-range "
"%s (bad range or address-family)\n",
argv[0]);

File diff suppressed because it is too large Load Diff

View File

@@ -1,13 +0,0 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.or
g/TR/html4/loose.dtd">
<html><head><style type='text/css'>
h1 { color: #3c78b5; border-bottom: 3px solid #3c78b5; font-size: 180%; }
h2 { color: #3c78b5; border-bottom: 2px solid #3c78b5; font-size: 140%; }
h3 { color: #3c78b5; border-bottom: 1px dotted #3c78b5; font-size: 129%; }
em { color: #0000FF; }
code { font-size:12px; background-color:#f8f8ff; border:1px; }
pre { border: 1px dotted #3c78b5; background-color: #f8f8ff; margin: 1em 1em;}
body { width: 80%; margin: 0 3em; }
ul { list-style: none; }
</style></head><body>

View File

@@ -1,72 +0,0 @@
/* $OpenBSD: strlcpy.c,v 1.4 1999/05/01 18:56:41 millert Exp $ */
/*
* Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#if HAVE_CONFIG_H
#include "config.h"
#endif
#ifndef HAVE_STRLCPY
#include <sys/types.h>
#include <string.h>
/*
* Copy src to string dst of size siz. At most siz-1 characters
* will be copied. Always NUL terminates (unless siz == 0).
* Returns strlen(src); if retval >= siz, truncation occurred.
*/
size_t
strlcpy(dst, src, siz)
char *dst;
const char *src;
size_t siz;
{
char *d = dst;
const char *s = src;
size_t n = siz;
/* Copy as many bytes as will fit */
if (n != 0 && --n != 0) {
do {
if ((*d++ = *s++) == 0)
break;
} while (--n != 0);
}
/* Not enough room in dst, add NUL and traverse rest of src */
if (n == 0) {
if (siz != 0)
*d = '\0'; /* NUL-terminate dst */
while (*s++)
;
}
return(s - src - 1); /* count does not include NUL */
}
#endif

View File

@@ -1,3 +1,30 @@
/*
* Copyright (c) 2019-2020 Job Snijders <job@sobornost.net>
* Copyright (c) 2007-2019 Alexandre Snarskii <snar@snar.spb.ru>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
@@ -9,21 +36,22 @@
#include <string.h>
#include <unistd.h>
#include "extern.h"
#include "sx_report.h"
#ifndef SX_MAXSOCKBUF_MAX
#define SX_MAXSOCKBUF_MAX (2*1024*1024)
#define SX_MAXSOCKBUF_MAX (2 * 1024 * 1024)
#endif
int
sx_maxsockbuf(int s, int dir)
{
int optval = 0, voptval;
int hiconf = -1, loconf = -1;
unsigned int voptlen;
int phase = 0, iterations = 0;
int optval = 0, voptval;
int hiconf = -1, loconf = -1;
unsigned int voptlen;
int phase = 0, iterations = 0;
if (s<0) {
if (s < 0) {
sx_report(SX_FATAL,"Unable to maximize sockbuf on invalid "
"socket %i\n", s);
exit(1);

View File

@@ -1,8 +0,0 @@
#ifndef SX_MAXSOCKBUF_H_
#define SX_MAXSOCKBUF_H_
/* s - number of opened socket, dir is either SO_SNDBUF or SO_RCVBUF */
int sx_maxsockbuf(int s, int dir);
#endif

View File

@@ -1,6 +1,29 @@
#if HAVE_CONFIG_H
#include "config.h"
#endif
/*
* Copyright (c) 2019-2020 Job Snijders <job@sobornost.net>
* Copyright (c) 2007-2019 Alexandre Snarskii <snar@snar.spb.ru>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <ctype.h>
#include <errno.h>
@@ -12,13 +35,13 @@
#include "sx_prefix.h"
#include "sx_report.h"
int debug_aggregation=0;
int debug_aggregation = 0;
extern int debug_expander;
struct sx_prefix*
sx_prefix_alloc(struct sx_prefix* p)
sx_prefix_alloc(struct sx_prefix *p)
{
struct sx_prefix* sp = malloc(sizeof(struct sx_prefix));
struct sx_prefix *sp = malloc(sizeof(struct sx_prefix));
if (!sp)
return NULL;
@@ -32,7 +55,7 @@ sx_prefix_alloc(struct sx_prefix* p)
}
void
sx_prefix_destroy(struct sx_prefix* p)
sx_prefix_destroy(struct sx_prefix *p)
{
if (p)
free(p);
@@ -53,16 +76,16 @@ sx_radix_node_destroy(struct sx_radix_node *n)
}
void
sx_prefix_adjust_masklen(struct sx_prefix* p)
sx_prefix_adjust_masklen(struct sx_prefix *p)
{
int nbytes = (p->family == AF_INET ? 4 : 16);
int i;
unsigned int nbytes = (p->family == AF_INET ? 4 : 16);
unsigned int i;
if (p->masklen == nbytes * 8)
return; /* mask is all ones */
for (i = nbytes -1; i > p->masklen / 8; i--) {
p->addr.addrs[i]=0;
p->addr.addrs[i] = 0;
}
for (i = 1; i <= 8 - p->masklen % 8; i++) {
@@ -70,10 +93,10 @@ sx_prefix_adjust_masklen(struct sx_prefix* p)
}
}
void
sx_prefix_mask(struct sx_prefix* p, struct sx_prefix* q)
static void
sx_prefix_mask(struct sx_prefix *p, struct sx_prefix *q)
{
int i;
unsigned int i;
memset(q->addr.addrs, 0, sizeof(q->addr.addrs));
@@ -87,10 +110,10 @@ sx_prefix_mask(struct sx_prefix* p, struct sx_prefix* q)
q->addr.addrs[p->masklen / 8] |= (1 << (8 - i));
}
void
sx_prefix_imask(struct sx_prefix* p, struct sx_prefix* q)
static void
sx_prefix_imask(struct sx_prefix *p, struct sx_prefix *q)
{
int i;
unsigned int i;
memset(q->addr.addrs, 0xff, sizeof(q->addr.addrs));
@@ -106,11 +129,11 @@ sx_prefix_imask(struct sx_prefix* p, struct sx_prefix* q)
int
sx_prefix_parse(struct sx_prefix* p, int af, char* text)
sx_prefix_parse(struct sx_prefix *p, int af, char *text)
{
char* c = NULL;
int masklen, ret;
char mtext[INET6_ADDRSTRLEN+5];
char *c = NULL;
int masklen, ret;
char mtext[INET6_ADDRSTRLEN+5];
strlcpy(mtext, text, sizeof(mtext));
@@ -169,7 +192,7 @@ sx_prefix_parse(struct sx_prefix* p, int af, char* text)
if (masklen == -1)
p->masklen = 32;
else {
if(masklen < 0 || masklen > 32) {
if (masklen < 0 || masklen > 32) {
p->masklen = 32;
} else {
p->masklen = masklen;
@@ -202,10 +225,10 @@ fixups:
return 0;
}
int
sx_prefix_isbitset(struct sx_prefix* p, int n)
static int
sx_prefix_isbitset(struct sx_prefix *p, int n)
{
unsigned char s;
unsigned char s;
/* bits outside the prefix considered unset */
if (p->family == AF_INET && (n < 0 || n > 32))
@@ -217,10 +240,10 @@ sx_prefix_isbitset(struct sx_prefix* p, int n)
return (s & (0x80 >> ((n - 1) % 8))) ? 1 : 0;
}
void
sx_prefix_setbit(struct sx_prefix* p, int n)
static void
sx_prefix_setbit(struct sx_prefix *p, int n)
{
unsigned char* s;
unsigned char *s;
if (p->family == AF_INET && (n < 0 || n > 32))
return;
@@ -233,8 +256,8 @@ sx_prefix_setbit(struct sx_prefix* p, int n)
}
int
sx_radix_tree_insert_specifics(struct sx_radix_tree* t, struct sx_prefix *p,
static int
sx_radix_tree_insert_specifics(struct sx_radix_tree *t, struct sx_prefix *p,
unsigned min, unsigned max)
{
struct sx_prefix *np;
@@ -258,12 +281,12 @@ sx_radix_tree_insert_specifics(struct sx_radix_tree* t, struct sx_prefix *p,
}
int
sx_prefix_range_parse(struct sx_radix_tree* tree, int af, int maxlen,
char* text)
sx_prefix_range_parse(struct sx_radix_tree *tree, int af, unsigned int maxlen,
char *text)
{
char* d = strchr(text, '^');
struct sx_prefix *p;
unsigned long min, max;
char *d = strchr(text, '^');
struct sx_prefix *p;
unsigned long min, max = 0;
p = sx_prefix_alloc(NULL);
@@ -299,7 +322,7 @@ sx_prefix_range_parse(struct sx_radix_tree* tree, int af, int maxlen,
min = p->masklen;
max = maxlen;
} else if (isdigit(d[1])) {
char* dm = NULL;
char *dm = NULL;
min = strtoul(d+1, &dm, 10);
if (dm && *dm == '-' && isdigit(dm[1])) {
max = strtoul(dm + 1, NULL, 10);
@@ -340,10 +363,10 @@ sx_prefix_range_parse(struct sx_radix_tree* tree, int af, int maxlen,
return 1;
}
struct sx_prefix*
sx_prefix_new(int af, char* text)
struct sx_prefix *
sx_prefix_new(int af, char *text)
{
struct sx_prefix* p = NULL;
struct sx_prefix *p = NULL;
if (!text)
return NULL;
@@ -362,7 +385,7 @@ sx_prefix_new(int af, char* text)
}
int
sx_prefix_fprint(FILE* f, struct sx_prefix* p)
sx_prefix_fprint(FILE *f, struct sx_prefix *p)
{
char buffer[128];
@@ -376,7 +399,7 @@ sx_prefix_fprint(FILE* f, struct sx_prefix* p)
}
int
sx_prefix_snprintf_sep(struct sx_prefix* p, char* rbuffer, int srb, char* sep)
sx_prefix_snprintf_sep(struct sx_prefix *p, char *rbuffer, int srb, char *sep)
{
char buffer[128];
@@ -394,83 +417,96 @@ sx_prefix_snprintf_sep(struct sx_prefix* p, char* rbuffer, int srb, char* sep)
}
int
sx_prefix_snprintf(struct sx_prefix* p, char* rbuffer, int srb)
sx_prefix_snprintf(struct sx_prefix *p, char *rbuffer, int srb)
{
return sx_prefix_snprintf_sep(p, rbuffer, srb, "/");
}
int
sx_prefix_snprintf_fmt(struct sx_prefix* p, char* buffer, int size,
const char* name, const char* format)
void
sx_prefix_snprintf_fmt(struct sx_prefix *p, FILE *f,
const char *name, const char *format,
unsigned int aggregateLow, unsigned int aggregateHi)
{
unsigned off = 0;
const char* c = format;
struct sx_prefix *q = sx_prefix_alloc(NULL);
const char *c = format;
struct sx_prefix *q = sx_prefix_alloc(NULL);
char prefix[128];
while (*c) {
if(*c == '%') {
if (*c == '%') {
switch (*(c + 1)) {
case 'r':
case 'n':
inet_ntop(p->family, &p->addr, buffer+off, size-off);
off = strlen(buffer);
if (NULL != inet_ntop(p->family, &p->addr, prefix, sizeof(prefix))) {
fprintf(f, "%s", prefix);
} else {
sx_report(SX_ERROR, "inet_ntop failed\n");
return;
}
break;
case 'l':
off += snprintf(buffer + off, size - off,
"%i", p->masklen);
fprintf(f, "%i", p->masklen);
break;
case 'a':
fprintf(f, "%u", aggregateLow);
break;
case 'A':
fprintf(f, "%u", aggregateHi);
break;
case '%':
buffer[off++] = '%';
fprintf(f, "%%");
break;
case 'N':
off += snprintf(buffer + off, size - off,
"%s", name);
fprintf(f, "%s", name);
break;
case 'm':
sx_prefix_mask(p, q);
inet_ntop(p->family, &q->addr, buffer + off,
size - off);
off = strlen(buffer);
if (NULL != inet_ntop(p->family, &q->addr, prefix, sizeof(prefix))) {
fprintf(f, "%s", prefix);
} else {
sx_report(SX_ERROR, "inet_ntop failed\n");
return;
}
break;
case 'i':
sx_prefix_imask(p, q);
inet_ntop(p->family, &q->addr, buffer + off,
size - off);
off = strlen(buffer);
if (NULL != inet_ntop(p->family, &q->addr, prefix, sizeof(prefix))) {
fprintf(f, "%s", prefix);
} else {
sx_report(SX_ERROR, "inet_ntop failed\n");
return;
}
break;
default :
sx_report(SX_ERROR, "Unknown format char "
"'%c'\n", *(c + 1));
return 0;
return;
}
c += 2;
} else if (*c == '\\') {
switch(*(c+1)) {
case 'n':
buffer[off++] = '\n';
fprintf(f, "\n");
break;
case 't':
buffer[off++] = '\t';
fprintf(f, "\t");
break;
case '\\':
buffer[off++] = '\\';
fprintf(f, "\\");
break;
default:
buffer[off++] = *(c + 1);
fprintf(f, "%c", *(c + 1));
break;
}
c += 2;
} else {
buffer[off++] = *c;
fprintf(f, "%c", *c);
c++;
}
}
return strlen(buffer);
}
int
sx_prefix_jsnprintf(struct sx_prefix* p, char* rbuffer, int srb)
sx_prefix_jsnprintf(struct sx_prefix *p, char *rbuffer, int srb)
{
char buffer[128];
@@ -486,7 +522,7 @@ sx_prefix_jsnprintf(struct sx_prefix* p, char* rbuffer, int srb)
struct sx_radix_tree*
sx_radix_tree_new(int af)
{
struct sx_radix_tree* rt = malloc(sizeof(struct sx_radix_tree));
struct sx_radix_tree *rt = malloc(sizeof(struct sx_radix_tree));
if (!rt)
return NULL;
@@ -498,15 +534,15 @@ sx_radix_tree_new(int af)
}
int
sx_radix_tree_empty(struct sx_radix_tree* t)
sx_radix_tree_empty(struct sx_radix_tree *t)
{
return t->head == NULL;
}
struct sx_radix_node*
sx_radix_node_new(struct sx_prefix* prefix)
sx_radix_node_new(struct sx_prefix *prefix)
{
struct sx_radix_node* rn = malloc(sizeof(struct sx_radix_node));
struct sx_radix_node *rn = malloc(sizeof(struct sx_radix_node));
if (!rn)
return NULL;
@@ -519,20 +555,20 @@ sx_radix_node_new(struct sx_prefix* prefix)
return rn;
}
int
sx_prefix_eqbits(struct sx_prefix* a, struct sx_prefix* b)
static int
sx_prefix_eqbits(struct sx_prefix *a, struct sx_prefix *b)
{
int i;
int nbytes = (a->family == AF_INET ? 4 : 16);
unsigned int i;
unsigned int nbytes = (a->family == AF_INET ? 4 : 16);
for (i = 0; i < nbytes; i++) {
if (a->addr.addrs[i] == b->addr.addrs[i])
continue;
else {
int j;
unsigned int j;
for (j = 0; j < 8 && i * 8 + j <= a->masklen
&& i * 8 + j<= b->masklen; j++) {
&& i * 8 + j <= b->masklen; j++) {
if ((a->addr.addrs[i] & (0x80 >> j))
!= (b->addr.addrs[i] & (0x80 >> j)))
return i * 8 + j;
@@ -547,9 +583,9 @@ sx_prefix_eqbits(struct sx_prefix* a, struct sx_prefix* b)
}
struct sx_prefix*
sx_prefix_overlay(struct sx_prefix* p, int n)
sx_prefix_overlay(struct sx_prefix *p, int n)
{
struct sx_prefix* sp = sx_prefix_alloc(p);
struct sx_prefix *sp = sx_prefix_alloc(p);
sp->masklen = n;
sx_prefix_adjust_masklen(sp);
@@ -557,7 +593,7 @@ sx_prefix_overlay(struct sx_prefix* p, int n)
}
void
sx_radix_tree_unlink(struct sx_radix_tree* tree, struct sx_radix_node* node)
sx_radix_tree_unlink(struct sx_radix_tree *tree, struct sx_radix_node *node)
{
next:
if (node->r && node->l)
@@ -589,14 +625,14 @@ next:
if (node->parent->r == node) {
node->parent->r = node->l;
node->l->parent = node->parent;
} else if(node->parent->l==node) {
} else if (node->parent->l==node) {
node->parent->l=node->l;
node->l->parent=node->parent;
} else {
sx_report(SX_ERROR,"Unlinking node which is not descendant "
"of its parent\n");
}
} else if(tree->head==node) {
} else if (tree->head==node) {
tree->head=node->l;
node->l->parent=NULL;
} else {
@@ -607,7 +643,7 @@ next:
} else {
/* the only case - node does not have descendants */
if (node->parent) {
if(node->parent->l == node)
if (node->parent->l == node)
node->parent->l = NULL;
else if (node->parent->r == node)
node->parent->r=NULL;
@@ -633,10 +669,10 @@ next:
struct sx_radix_node*
sx_radix_tree_lookup(struct sx_radix_tree* tree, struct sx_prefix* prefix)
sx_radix_tree_lookup(struct sx_radix_tree *tree, struct sx_prefix *prefix)
{
int eb;
struct sx_radix_node* candidate = NULL, *chead;
unsigned int eb;
struct sx_radix_node *candidate = NULL, *chead;
if (!tree || !prefix)
return NULL;
@@ -697,19 +733,19 @@ next:
struct sx_radix_node*
sx_radix_tree_insert(struct sx_radix_tree* tree, struct sx_prefix* prefix)
sx_radix_tree_insert(struct sx_radix_tree *tree, struct sx_prefix *prefix)
{
int eb;
struct sx_radix_node** candidate=NULL, *chead;
unsigned int eb;
struct sx_radix_node **candidate=NULL, *chead;
if (!tree || !prefix)
return NULL;
if (tree->family!=prefix->family)
if (tree->family != prefix->family)
return NULL;
if (!tree->head) {
tree->head=sx_radix_node_new(prefix);
tree->head = sx_radix_node_new(prefix);
return tree->head;
}
@@ -721,7 +757,7 @@ next:
if (eb < prefix->masklen && eb < chead->prefix->masklen) {
struct sx_prefix *neoRoot = sx_prefix_alloc(prefix);
struct sx_radix_node* rn, *ret=sx_radix_node_new(prefix);
struct sx_radix_node *rn, *ret=sx_radix_node_new(prefix);
neoRoot->masklen = eb;
sx_prefix_adjust_masklen(neoRoot);
rn=sx_radix_node_new(neoRoot);
@@ -748,7 +784,7 @@ next:
*candidate = rn;
return ret;
} else if (eb == prefix->masklen && eb < chead->prefix->masklen) {
struct sx_radix_node* ret = sx_radix_node_new(prefix);
struct sx_radix_node *ret = sx_radix_node_new(prefix);
if (sx_prefix_isbitset(chead->prefix, eb + 1)) {
ret->r = chead;
} else {
@@ -797,10 +833,11 @@ next:
}
void
sx_radix_node_fprintf(struct sx_radix_node* node, void* udata)
sx_radix_node_fprintf(struct sx_radix_node *node, void *udata)
{
FILE* out = (udata?udata:stdout);
char buffer[128];
FILE *out = (udata?udata:stdout);
char buffer[128];
if (!node) {
fprintf(out, "(null)\n");
} else {
@@ -810,10 +847,10 @@ sx_radix_node_fprintf(struct sx_radix_node* node, void* udata)
}
int
sx_radix_node_foreach(struct sx_radix_node* node,
void (*func)(struct sx_radix_node*, void*), void* udata)
sx_radix_node_foreach(struct sx_radix_node *node,
void (*func)(struct sx_radix_node*, void*), void *udata)
{
func(node,udata);
func(node, udata);
if (node->l)
sx_radix_node_foreach(node->l, func, udata);
@@ -825,25 +862,27 @@ sx_radix_node_foreach(struct sx_radix_node* node,
}
int
sx_radix_tree_foreach(struct sx_radix_tree* tree,
void (*func)(struct sx_radix_node*, void*), void* udata)
sx_radix_tree_foreach(struct sx_radix_tree *tree,
void (*func)(struct sx_radix_node *, void *), void *udata)
{
if(!func || !tree || !tree->head) return 0;
sx_radix_node_foreach(tree->head,func,udata);
if (!func || !tree || !tree->head)
return 0;
sx_radix_node_foreach(tree->head, func, udata);
return 0;
}
int
sx_radix_node_aggregate(struct sx_radix_node* node)
static int
sx_radix_node_aggregate(struct sx_radix_node *node)
{
if(node->l)
if (node->l)
sx_radix_node_aggregate(node->l);
if(node->r)
if (node->r)
sx_radix_node_aggregate(node->r);
if(debug_aggregation) {
if (debug_aggregation) {
printf("Aggregating on node: ");
sx_prefix_fprint(stdout,node->prefix);
sx_prefix_fprint(stdout, node->prefix);
printf(" %s%s%u,%u\n", node->isGlue?"Glue ":"",
node->isAggregate?"Aggregate ":"",node->aggregateLow,
node->aggregateHi);
@@ -1005,7 +1044,7 @@ sx_radix_node_aggregate(struct sx_radix_node* node)
}
int
sx_radix_tree_aggregate(struct sx_radix_tree* tree)
sx_radix_tree_aggregate(struct sx_radix_tree *tree)
{
if (tree && tree->head)
return sx_radix_node_aggregate(tree->head);
@@ -1014,7 +1053,7 @@ sx_radix_tree_aggregate(struct sx_radix_tree* tree)
}
static void
setGlueUpTo(struct sx_radix_node* node, void* udata)
setGlueUpTo(struct sx_radix_node *node, void *udata)
{
unsigned refine = *(unsigned*)udata;
@@ -1022,8 +1061,8 @@ setGlueUpTo(struct sx_radix_node* node, void* udata)
node->isGlue = 1;
}
int
sx_radix_node_refine(struct sx_radix_node* node, unsigned refine)
static int
sx_radix_node_refine(struct sx_radix_node *node, unsigned refine)
{
if (!node->isGlue && node->prefix->masklen<refine) {
node->isAggregate = 1;
@@ -1065,7 +1104,7 @@ sx_radix_node_refine(struct sx_radix_node* node, unsigned refine)
}
int
sx_radix_tree_refine(struct sx_radix_tree* tree, unsigned refine)
sx_radix_tree_refine(struct sx_radix_tree *tree, unsigned refine)
{
if (tree && tree->head)
return sx_radix_node_refine(tree->head, refine);
@@ -1074,16 +1113,16 @@ sx_radix_tree_refine(struct sx_radix_tree* tree, unsigned refine)
}
static void
setGlueFrom(struct sx_radix_node* node, void* udata)
setGlueFrom(struct sx_radix_node *node, void *udata)
{
unsigned refine = *(unsigned*)udata;
if (node && node->prefix->masklen <= refine)
node->isGlue=1;
node->isGlue = 1;
}
static int
sx_radix_node_refineLow(struct sx_radix_node* node, unsigned refineLow)
sx_radix_node_refineLow(struct sx_radix_node *node, unsigned refineLow)
{
if (!node->isGlue && node->prefix->masklen<=refineLow) {
@@ -1134,7 +1173,7 @@ sx_radix_node_refineLow(struct sx_radix_node* node, unsigned refineLow)
}
int
sx_radix_tree_refineLow(struct sx_radix_tree* tree, unsigned refineLow)
sx_radix_tree_refineLow(struct sx_radix_tree *tree, unsigned refineLow)
{
if (tree && tree->head)
return sx_radix_node_refineLow(tree->head, refineLow);
@@ -1145,10 +1184,10 @@ sx_radix_tree_refineLow(struct sx_radix_tree* tree, unsigned refineLow)
#if SX_PTREE_TEST
int
main() {
struct sx_prefix* p;
int n;
struct sx_radix_tree* tree;
struct sx_radix_node* node;
struct sx_prefix *p;
struct sx_radix_tree *tree;
struct sx_radix_node *node;
int n;
p = sx_prefix_new(0, "10.11.12.13/24");
sx_prefix_fprint(stdout, p);
@@ -1200,14 +1239,12 @@ main() {
sx_prefix_fprint(stdout, p);
printf("\n");
#define SX_TEST_EBITS(a,b,susp) n = sx_prefix_eqbits(sx_prefix_new(0,a)),\
sx_prefix_new(0,b))); \
if (n != susp) \
printf("FAILED: %s eqbits %s=%i, not %i\n", a, b, n,
susp);\
else
printf("OK, %s eqbits %s = %i, as suspected\n", a, b,
n);
#define SX_TEST_EBITS(a, b, susp) \
n = sx_prefix_eqbits(sx_prefix_new(0, a), sx_prefix_new(0, b)); \
if (n != susp) \
printf("FAILED: %s eqbits %s=%i, not %i\n", a, b, n, susp); \
else \
printf("OK, %s eqbits %s = %i, as suspected\n", a, b, n);
SX_TEST_EBITS("192.168.0.0/24", "192.168.1.0/24", 23);
SX_TEST_EBITS("192.168.0.0/32", "192.168.0.1/32", 31);
#if SX_LIBPTREE_IPV6

View File

@@ -1,3 +1,29 @@
/*
* Copyright (c) 2007-2019 Alexandre Snarskii <snar@snar.spb.ru>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifndef _SX_PREFIX_H_
#define _SX_PREFIX_H_
@@ -8,7 +34,7 @@
typedef struct sx_prefix {
int family;
int masklen;
unsigned int masklen;
union {
struct in_addr addr;
struct in6_addr addr6;
@@ -17,58 +43,59 @@ typedef struct sx_prefix {
} sx_prefix_t;
typedef struct sx_radix_node {
struct sx_radix_node* parent, *l, *r, *son;
void* payload;
unsigned int isGlue:1;
unsigned int isAggregated:1;
unsigned int isAggregate:1;
unsigned int aggregateLow;
unsigned int aggregateHi;
struct sx_prefix *prefix;
struct sx_radix_node *parent, *l, *r, *son;
void *payload;
unsigned int isGlue:1;
unsigned int isAggregated:1;
unsigned int isAggregate:1;
unsigned int aggregateLow;
unsigned int aggregateHi;
struct sx_prefix *prefix;
} sx_radix_node_t;
typedef struct sx_radix_tree {
int family;
struct sx_radix_node* head;
int family;
struct sx_radix_node *head;
} sx_radix_tree_t;
/* most common operations with the tree is to: lookup/insert/unlink */
struct sx_radix_node* sx_radix_tree_lookup(struct sx_radix_tree* tree,
struct sx_prefix* prefix);
struct sx_radix_node* sx_radix_tree_insert(struct sx_radix_tree* tree,
struct sx_prefix* prefix);
void sx_radix_tree_unlink(struct sx_radix_tree* t, struct sx_radix_node* n);
struct sx_radix_node* sx_radix_tree_lookup_exact(struct sx_radix_tree* tree,
struct sx_prefix* prefix);
struct sx_radix_node *sx_radix_tree_lookup(struct sx_radix_tree *tree,
struct sx_prefix *prefix);
struct sx_radix_node *sx_radix_tree_insert(struct sx_radix_tree *tree,
struct sx_prefix *prefix);
void sx_radix_tree_unlink(struct sx_radix_tree *t, struct sx_radix_node *n);
struct sx_radix_node *sx_radix_tree_lookup_exact(struct sx_radix_tree *tree,
struct sx_prefix *prefix);
struct sx_prefix* sx_prefix_alloc(struct sx_prefix* p);
void sx_prefix_destroy(struct sx_prefix* p);
void sx_radix_node_destroy(struct sx_radix_node* p);
void sx_prefix_adjust_masklen(struct sx_prefix* p);
struct sx_prefix* sx_prefix_new(int af, char* text);
int sx_prefix_parse(struct sx_prefix* p, int af, char* text);
int sx_prefix_range_parse(struct sx_radix_tree* t, int af, int ml, char* text);
int sx_prefix_fprint(FILE* f, struct sx_prefix* p);
int sx_prefix_snprintf(struct sx_prefix* p, char* rbuffer, int srb);
int sx_prefix_snprintf_sep(struct sx_prefix* p, char* rbuffer, int srb, char*);
int sx_prefix_snprintf_fmt(struct sx_prefix* p, char* rbuffer, int srb,
const char* name, const char* fmt);
int sx_prefix_jsnprintf(struct sx_prefix* p, char* rbuffer, int srb);
struct sx_radix_tree* sx_radix_tree_new(int af);
struct sx_radix_node* sx_radix_node_new(struct sx_prefix* prefix);
struct sx_prefix* sx_prefix_overlay(struct sx_prefix* p, int n);
int sx_radix_tree_empty(struct sx_radix_tree* t);
void sx_radix_node_fprintf(struct sx_radix_node* node, void* udata);
int sx_radix_node_foreach(struct sx_radix_node* node,
void (*func)(struct sx_radix_node*, void*), void* udata);
int sx_radix_tree_foreach(struct sx_radix_tree* tree,
void (*func)(struct sx_radix_node*, void*), void* udata);
int sx_radix_tree_aggregate(struct sx_radix_tree* tree);
int sx_radix_tree_refine(struct sx_radix_tree* tree, unsigned refine);
int sx_radix_tree_refineLow(struct sx_radix_tree* tree, unsigned refineLow);
struct sx_prefix *sx_prefix_alloc(struct sx_prefix *p);
void sx_prefix_destroy(struct sx_prefix *p);
void sx_radix_node_destroy(struct sx_radix_node *p);
void sx_prefix_adjust_masklen(struct sx_prefix *p);
struct sx_prefix *sx_prefix_new(int af, char *text);
int sx_prefix_parse(struct sx_prefix *p, int af, char *text);
int sx_prefix_range_parse(struct sx_radix_tree *t, int af, unsigned int ml, char *text);
int sx_prefix_fprint(FILE *f, struct sx_prefix *p);
int sx_prefix_snprintf(struct sx_prefix *p, char *rbuffer, int srb);
int sx_prefix_snprintf_sep(struct sx_prefix *p, char *rbuffer, int srb, char *);
void sx_prefix_snprintf_fmt(struct sx_prefix *p, FILE *f,
const char *name, const char *fmt, unsigned int aggregateLow,
unsigned int aggregateHi);
int sx_prefix_jsnprintf(struct sx_prefix *p, char *rbuffer, int srb);
struct sx_radix_tree *sx_radix_tree_new(int af);
struct sx_radix_node *sx_radix_node_new(struct sx_prefix *prefix);
struct sx_prefix *sx_prefix_overlay(struct sx_prefix *p, int n);
int sx_radix_tree_empty(struct sx_radix_tree *t);
void sx_radix_node_fprintf(struct sx_radix_node *node, void *udata);
int sx_radix_node_foreach(struct sx_radix_node *node,
void (*func)(struct sx_radix_node *, void *), void *udata);
int sx_radix_tree_foreach(struct sx_radix_tree *tree,
void (*func)(struct sx_radix_node *, void *), void *udata);
int sx_radix_tree_aggregate(struct sx_radix_tree *tree);
int sx_radix_tree_refine(struct sx_radix_tree *tree, unsigned refine);
int sx_radix_tree_refineLow(struct sx_radix_tree *tree, unsigned refineLow);
#ifndef HAVE_STRLCPY
size_t strlcpy(char* dst, const char* src, size_t size);
size_t strlcpy(char *dst, const char *src, size_t size);
#endif
#endif

View File

@@ -1,6 +1,28 @@
#if HAVE_CONFIG_H
#include <config.h>
#endif
/*
* Copyright (c) 2007-2019 Alexandre Snarskii <snar@snar.spb.ru>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <errno.h>
#include <inttypes.h>

View File

@@ -1,3 +1,29 @@
/*
* Copyright (c) 2007-2019 Alexandre Snarskii <snar@snar.spb.ru>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifndef SX_REPORT_H_
#define SX_REPORT_H_

View File

@@ -1,35 +1,61 @@
/*
* Copyright (c) 2007-2019 Alexandre Snarskii <snar@snar.spb.ru>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include "sx_slentry.h"
#include "extern.h"
struct sx_slentry*
sx_slentry_new(char* t)
struct sx_slentry *
sx_slentry_new(char *t)
{
struct sx_slentry* e = malloc(sizeof(struct sx_slentry));
struct sx_slentry *e = malloc(sizeof(struct sx_slentry));
if (!e)
return NULL;
memset(e, 0, sizeof(struct sx_slentry));
if (t)
e->text = strdup(t);
e->text = strdup(t);
return e;
}
struct sx_tentry*
sx_tentry_new(char* t)
struct sx_tentry *
sx_tentry_new(char *t)
{
struct sx_tentry* te = malloc(sizeof(struct sx_tentry));
struct sx_tentry *te = malloc(sizeof(struct sx_tentry));
if (!te)
return NULL;
memset(te, 0, sizeof(struct sx_tentry));
te->text = strdup(t);
return te;

View File

@@ -1,30 +0,0 @@
#ifndef SX_SLENTRY_H_
#define SX_SLENTRY_H_
#if HAVE_SYS_QUEUE_H && HAVE_STAILQ_IN_SYS_QUEUE
#include <sys/queue.h>
#else
#include "sys_queue.h"
#endif
#if HAVE_SYS_TREE_H
#include <sys/tree.h>
#else
#include "sys_tree.h"
#endif
struct sx_slentry {
STAILQ_ENTRY(sx_slentry) next;
char* text;
};
struct sx_slentry* sx_slentry_new(char* text);
struct sx_tentry {
RB_ENTRY(sx_tentry) entry;
char* text;
};
struct sx_tentry* sx_tentry_new(char* text);
#endif

View File

@@ -1,696 +0,0 @@
/*-
* Copyright (c) 1991, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)queue.h 8.5 (Berkeley) 8/20/94
* $FreeBSD: stable/10/sys/sys/queue.h 251887 2013-06-18 02:57:56Z lstewart $
*/
#ifndef _SYS_QUEUE_H_
#define _SYS_QUEUE_H_
#if HAVE_SYS_CDEFS_H
#include <sys/cdefs.h>
#endif
/*
* This file defines four types of data structures: singly-linked lists,
* singly-linked tail queues, lists and tail queues.
*
* A singly-linked list is headed by a single forward pointer. The elements
* are singly linked for minimum space and pointer manipulation overhead at
* the expense of O(n) removal for arbitrary elements. New elements can be
* added to the list after an existing element or at the head of the list.
* Elements being removed from the head of the list should use the explicit
* macro for this purpose for optimum efficiency. A singly-linked list may
* only be traversed in the forward direction. Singly-linked lists are ideal
* for applications with large datasets and few or no removals or for
* implementing a LIFO queue.
*
* A singly-linked tail queue is headed by a pair of pointers, one to the
* head of the list and the other to the tail of the list. The elements are
* singly linked for minimum space and pointer manipulation overhead at the
* expense of O(n) removal for arbitrary elements. New elements can be added
* to the list after an existing element, at the head of the list, or at the
* end of the list. Elements being removed from the head of the tail queue
* should use the explicit macro for this purpose for optimum efficiency.
* A singly-linked tail queue may only be traversed in the forward direction.
* Singly-linked tail queues are ideal for applications with large datasets
* and few or no removals or for implementing a FIFO queue.
*
* A list is headed by a single forward pointer (or an array of forward
* pointers for a hash table header). The elements are doubly linked
* so that an arbitrary element can be removed without a need to
* traverse the list. New elements can be added to the list before
* or after an existing element or at the head of the list. A list
* may be traversed in either direction.
*
* A tail queue is headed by a pair of pointers, one to the head of the
* list and the other to the tail of the list. The elements are doubly
* linked so that an arbitrary element can be removed without a need to
* traverse the list. New elements can be added to the list before or
* after an existing element, at the head of the list, or at the end of
* the list. A tail queue may be traversed in either direction.
*
* For details on the use of these macros, see the queue(3) manual page.
*
*
* SLIST LIST STAILQ TAILQ
* _HEAD + + + +
* _HEAD_INITIALIZER + + + +
* _ENTRY + + + +
* _INIT + + + +
* _EMPTY + + + +
* _FIRST + + + +
* _NEXT + + + +
* _PREV - + - +
* _LAST - - + +
* _FOREACH + + + +
* _FOREACH_FROM + + + +
* _FOREACH_SAFE + + + +
* _FOREACH_FROM_SAFE + + + +
* _FOREACH_REVERSE - - - +
* _FOREACH_REVERSE_FROM - - - +
* _FOREACH_REVERSE_SAFE - - - +
* _FOREACH_REVERSE_FROM_SAFE - - - +
* _INSERT_HEAD + + + +
* _INSERT_BEFORE - + - +
* _INSERT_AFTER + + + +
* _INSERT_TAIL - - + +
* _CONCAT - - + +
* _REMOVE_AFTER + - + -
* _REMOVE_HEAD + - + -
* _REMOVE + + + +
* _SWAP + + + +
*
*/
#ifdef QUEUE_MACRO_DEBUG
/* Store the last 2 places the queue element or head was altered */
struct qm_trace {
unsigned long lastline;
unsigned long prevline;
const char *lastfile;
const char *prevfile;
};
#define TRACEBUF struct qm_trace trace;
#define TRACEBUF_INITIALIZER { __FILE__, __LINE__, NULL, 0 } ,
#define TRASHIT(x) do {(x) = (void *)-1;} while (0)
#define QMD_SAVELINK(name, link) void **name = (void *)&(link)
#define QMD_TRACE_HEAD(head) do { \
(head)->trace.prevline = (head)->trace.lastline; \
(head)->trace.prevfile = (head)->trace.lastfile; \
(head)->trace.lastline = __LINE__; \
(head)->trace.lastfile = __FILE__; \
} while (0)
#define QMD_TRACE_ELEM(elem) do { \
(elem)->trace.prevline = (elem)->trace.lastline; \
(elem)->trace.prevfile = (elem)->trace.lastfile; \
(elem)->trace.lastline = __LINE__; \
(elem)->trace.lastfile = __FILE__; \
} while (0)
#else
#define QMD_TRACE_ELEM(elem)
#define QMD_TRACE_HEAD(head)
#define QMD_SAVELINK(name, link)
#define TRACEBUF
#define TRACEBUF_INITIALIZER
#define TRASHIT(x)
#endif /* QUEUE_MACRO_DEBUG */
/*
* Singly-linked List declarations.
*/
#define SLIST_HEAD(name, type) \
struct name { \
struct type *slh_first; /* first element */ \
}
#define SLIST_HEAD_INITIALIZER(head) \
{ NULL }
#define SLIST_ENTRY(type) \
struct { \
struct type *sle_next; /* next element */ \
}
/*
* Singly-linked List functions.
*/
#define SLIST_EMPTY(head) ((head)->slh_first == NULL)
#define SLIST_FIRST(head) ((head)->slh_first)
#define SLIST_FOREACH(var, head, field) \
for ((var) = SLIST_FIRST((head)); \
(var); \
(var) = SLIST_NEXT((var), field))
#define SLIST_FOREACH_FROM(var, head, field) \
for ((var) = ((var) ? (var) : SLIST_FIRST((head))); \
(var); \
(var) = SLIST_NEXT((var), field))
#define SLIST_FOREACH_SAFE(var, head, field, tvar) \
for ((var) = SLIST_FIRST((head)); \
(var) && ((tvar) = SLIST_NEXT((var), field), 1); \
(var) = (tvar))
#define SLIST_FOREACH_FROM_SAFE(var, head, field, tvar) \
for ((var) = ((var) ? (var) : SLIST_FIRST((head))); \
(var) && ((tvar) = SLIST_NEXT((var), field), 1); \
(var) = (tvar))
#define SLIST_FOREACH_PREVPTR(var, varp, head, field) \
for ((varp) = &SLIST_FIRST((head)); \
((var) = *(varp)) != NULL; \
(varp) = &SLIST_NEXT((var), field))
#define SLIST_INIT(head) do { \
SLIST_FIRST((head)) = NULL; \
} while (0)
#define SLIST_INSERT_AFTER(slistelm, elm, field) do { \
SLIST_NEXT((elm), field) = SLIST_NEXT((slistelm), field); \
SLIST_NEXT((slistelm), field) = (elm); \
} while (0)
#define SLIST_INSERT_HEAD(head, elm, field) do { \
SLIST_NEXT((elm), field) = SLIST_FIRST((head)); \
SLIST_FIRST((head)) = (elm); \
} while (0)
#define SLIST_NEXT(elm, field) ((elm)->field.sle_next)
#define SLIST_REMOVE(head, elm, type, field) do { \
QMD_SAVELINK(oldnext, (elm)->field.sle_next); \
if (SLIST_FIRST((head)) == (elm)) { \
SLIST_REMOVE_HEAD((head), field); \
} \
else { \
struct type *curelm = SLIST_FIRST((head)); \
while (SLIST_NEXT(curelm, field) != (elm)) \
curelm = SLIST_NEXT(curelm, field); \
SLIST_REMOVE_AFTER(curelm, field); \
} \
TRASHIT(*oldnext); \
} while (0)
#define SLIST_REMOVE_AFTER(elm, field) do { \
SLIST_NEXT(elm, field) = \
SLIST_NEXT(SLIST_NEXT(elm, field), field); \
} while (0)
#define SLIST_REMOVE_HEAD(head, field) do { \
SLIST_FIRST((head)) = SLIST_NEXT(SLIST_FIRST((head)), field); \
} while (0)
#define SLIST_SWAP(head1, head2, type) do { \
struct type *swap_first = SLIST_FIRST(head1); \
SLIST_FIRST(head1) = SLIST_FIRST(head2); \
SLIST_FIRST(head2) = swap_first; \
} while (0)
/*
* Singly-linked Tail queue declarations.
*/
#define STAILQ_HEAD(name, type) \
struct name { \
struct type *stqh_first;/* first element */ \
struct type **stqh_last;/* addr of last next element */ \
}
#define STAILQ_HEAD_INITIALIZER(head) \
{ NULL, &(head).stqh_first }
#define STAILQ_ENTRY(type) \
struct { \
struct type *stqe_next; /* next element */ \
}
/*
* Singly-linked Tail queue functions.
*/
#define STAILQ_CONCAT(head1, head2) do { \
if (!STAILQ_EMPTY((head2))) { \
*(head1)->stqh_last = (head2)->stqh_first; \
(head1)->stqh_last = (head2)->stqh_last; \
STAILQ_INIT((head2)); \
} \
} while (0)
#define STAILQ_EMPTY(head) ((head)->stqh_first == NULL)
#define STAILQ_FIRST(head) ((head)->stqh_first)
#define STAILQ_FOREACH(var, head, field) \
for((var) = STAILQ_FIRST((head)); \
(var); \
(var) = STAILQ_NEXT((var), field))
#define STAILQ_FOREACH_FROM(var, head, field) \
for ((var) = ((var) ? (var) : STAILQ_FIRST((head))); \
(var); \
(var) = STAILQ_NEXT((var), field))
#define STAILQ_FOREACH_SAFE(var, head, field, tvar) \
for ((var) = STAILQ_FIRST((head)); \
(var) && ((tvar) = STAILQ_NEXT((var), field), 1); \
(var) = (tvar))
#define STAILQ_FOREACH_FROM_SAFE(var, head, field, tvar) \
for ((var) = ((var) ? (var) : STAILQ_FIRST((head))); \
(var) && ((tvar) = STAILQ_NEXT((var), field), 1); \
(var) = (tvar))
#define STAILQ_INIT(head) do { \
STAILQ_FIRST((head)) = NULL; \
(head)->stqh_last = &STAILQ_FIRST((head)); \
} while (0)
#define STAILQ_INSERT_AFTER(head, tqelm, elm, field) do { \
if ((STAILQ_NEXT((elm), field) = STAILQ_NEXT((tqelm), field)) == NULL)\
(head)->stqh_last = &STAILQ_NEXT((elm), field); \
STAILQ_NEXT((tqelm), field) = (elm); \
} while (0)
#define STAILQ_INSERT_HEAD(head, elm, field) do { \
if ((STAILQ_NEXT((elm), field) = STAILQ_FIRST((head))) == NULL) \
(head)->stqh_last = &STAILQ_NEXT((elm), field); \
STAILQ_FIRST((head)) = (elm); \
} while (0)
#define STAILQ_INSERT_TAIL(head, elm, field) do { \
STAILQ_NEXT((elm), field) = NULL; \
*(head)->stqh_last = (elm); \
(head)->stqh_last = &STAILQ_NEXT((elm), field); \
} while (0)
#define STAILQ_LAST(head, type, field) \
(STAILQ_EMPTY((head)) ? NULL : \
__containerof((head)->stqh_last, struct type, field.stqe_next))
#define STAILQ_NEXT(elm, field) ((elm)->field.stqe_next)
#define STAILQ_REMOVE(head, elm, type, field) do { \
QMD_SAVELINK(oldnext, (elm)->field.stqe_next); \
if (STAILQ_FIRST((head)) == (elm)) { \
STAILQ_REMOVE_HEAD((head), field); \
} \
else { \
struct type *curelm = STAILQ_FIRST((head)); \
while (STAILQ_NEXT(curelm, field) != (elm)) \
curelm = STAILQ_NEXT(curelm, field); \
STAILQ_REMOVE_AFTER(head, curelm, field); \
} \
TRASHIT(*oldnext); \
} while (0)
#define STAILQ_REMOVE_AFTER(head, elm, field) do { \
if ((STAILQ_NEXT(elm, field) = \
STAILQ_NEXT(STAILQ_NEXT(elm, field), field)) == NULL) \
(head)->stqh_last = &STAILQ_NEXT((elm), field); \
} while (0)
#define STAILQ_REMOVE_HEAD(head, field) do { \
if ((STAILQ_FIRST((head)) = \
STAILQ_NEXT(STAILQ_FIRST((head)), field)) == NULL) \
(head)->stqh_last = &STAILQ_FIRST((head)); \
} while (0)
#define STAILQ_SWAP(head1, head2, type) do { \
struct type *swap_first = STAILQ_FIRST(head1); \
struct type **swap_last = (head1)->stqh_last; \
STAILQ_FIRST(head1) = STAILQ_FIRST(head2); \
(head1)->stqh_last = (head2)->stqh_last; \
STAILQ_FIRST(head2) = swap_first; \
(head2)->stqh_last = swap_last; \
if (STAILQ_EMPTY(head1)) \
(head1)->stqh_last = &STAILQ_FIRST(head1); \
if (STAILQ_EMPTY(head2)) \
(head2)->stqh_last = &STAILQ_FIRST(head2); \
} while (0)
/*
* List declarations.
*/
#define LIST_HEAD(name, type) \
struct name { \
struct type *lh_first; /* first element */ \
}
#define LIST_HEAD_INITIALIZER(head) \
{ NULL }
#define LIST_ENTRY(type) \
struct { \
struct type *le_next; /* next element */ \
struct type **le_prev; /* address of previous next element */ \
}
/*
* List functions.
*/
#if (defined(_KERNEL) && defined(INVARIANTS))
#define QMD_LIST_CHECK_HEAD(head, field) do { \
if (LIST_FIRST((head)) != NULL && \
LIST_FIRST((head))->field.le_prev != \
&LIST_FIRST((head))) \
panic("Bad list head %p first->prev != head", (head)); \
} while (0)
#define QMD_LIST_CHECK_NEXT(elm, field) do { \
if (LIST_NEXT((elm), field) != NULL && \
LIST_NEXT((elm), field)->field.le_prev != \
&((elm)->field.le_next)) \
panic("Bad link elm %p next->prev != elm", (elm)); \
} while (0)
#define QMD_LIST_CHECK_PREV(elm, field) do { \
if (*(elm)->field.le_prev != (elm)) \
panic("Bad link elm %p prev->next != elm", (elm)); \
} while (0)
#else
#define QMD_LIST_CHECK_HEAD(head, field)
#define QMD_LIST_CHECK_NEXT(elm, field)
#define QMD_LIST_CHECK_PREV(elm, field)
#endif /* (_KERNEL && INVARIANTS) */
#define LIST_EMPTY(head) ((head)->lh_first == NULL)
#define LIST_FIRST(head) ((head)->lh_first)
#define LIST_FOREACH(var, head, field) \
for ((var) = LIST_FIRST((head)); \
(var); \
(var) = LIST_NEXT((var), field))
#define LIST_FOREACH_FROM(var, head, field) \
for ((var) = ((var) ? (var) : LIST_FIRST((head))); \
(var); \
(var) = LIST_NEXT((var), field))
#define LIST_FOREACH_SAFE(var, head, field, tvar) \
for ((var) = LIST_FIRST((head)); \
(var) && ((tvar) = LIST_NEXT((var), field), 1); \
(var) = (tvar))
#define LIST_FOREACH_FROM_SAFE(var, head, field, tvar) \
for ((var) = ((var) ? (var) : LIST_FIRST((head))); \
(var) && ((tvar) = LIST_NEXT((var), field), 1); \
(var) = (tvar))
#define LIST_INIT(head) do { \
LIST_FIRST((head)) = NULL; \
} while (0)
#define LIST_INSERT_AFTER(listelm, elm, field) do { \
QMD_LIST_CHECK_NEXT(listelm, field); \
if ((LIST_NEXT((elm), field) = LIST_NEXT((listelm), field)) != NULL)\
LIST_NEXT((listelm), field)->field.le_prev = \
&LIST_NEXT((elm), field); \
LIST_NEXT((listelm), field) = (elm); \
(elm)->field.le_prev = &LIST_NEXT((listelm), field); \
} while (0)
#define LIST_INSERT_BEFORE(listelm, elm, field) do { \
QMD_LIST_CHECK_PREV(listelm, field); \
(elm)->field.le_prev = (listelm)->field.le_prev; \
LIST_NEXT((elm), field) = (listelm); \
*(listelm)->field.le_prev = (elm); \
(listelm)->field.le_prev = &LIST_NEXT((elm), field); \
} while (0)
#define LIST_INSERT_HEAD(head, elm, field) do { \
QMD_LIST_CHECK_HEAD((head), field); \
if ((LIST_NEXT((elm), field) = LIST_FIRST((head))) != NULL) \
LIST_FIRST((head))->field.le_prev = &LIST_NEXT((elm), field);\
LIST_FIRST((head)) = (elm); \
(elm)->field.le_prev = &LIST_FIRST((head)); \
} while (0)
#define LIST_NEXT(elm, field) ((elm)->field.le_next)
#define LIST_PREV(elm, head, type, field) \
((elm)->field.le_prev == &LIST_FIRST((head)) ? NULL : \
__containerof((elm)->field.le_prev, struct type, field.le_next))
#define LIST_REMOVE(elm, field) do { \
QMD_SAVELINK(oldnext, (elm)->field.le_next); \
QMD_SAVELINK(oldprev, (elm)->field.le_prev); \
QMD_LIST_CHECK_NEXT(elm, field); \
QMD_LIST_CHECK_PREV(elm, field); \
if (LIST_NEXT((elm), field) != NULL) \
LIST_NEXT((elm), field)->field.le_prev = \
(elm)->field.le_prev; \
*(elm)->field.le_prev = LIST_NEXT((elm), field); \
TRASHIT(*oldnext); \
TRASHIT(*oldprev); \
} while (0)
#define LIST_SWAP(head1, head2, type, field) do { \
struct type *swap_tmp = LIST_FIRST((head1)); \
LIST_FIRST((head1)) = LIST_FIRST((head2)); \
LIST_FIRST((head2)) = swap_tmp; \
if ((swap_tmp = LIST_FIRST((head1))) != NULL) \
swap_tmp->field.le_prev = &LIST_FIRST((head1)); \
if ((swap_tmp = LIST_FIRST((head2))) != NULL) \
swap_tmp->field.le_prev = &LIST_FIRST((head2)); \
} while (0)
/*
* Tail queue declarations.
*/
#define TAILQ_HEAD(name, type) \
struct name { \
struct type *tqh_first; /* first element */ \
struct type **tqh_last; /* addr of last next element */ \
TRACEBUF \
}
#define TAILQ_HEAD_INITIALIZER(head) \
{ NULL, &(head).tqh_first, TRACEBUF_INITIALIZER }
#define TAILQ_ENTRY(type) \
struct { \
struct type *tqe_next; /* next element */ \
struct type **tqe_prev; /* address of previous next element */ \
TRACEBUF \
}
/*
* Tail queue functions.
*/
#if (defined(_KERNEL) && defined(INVARIANTS))
#define QMD_TAILQ_CHECK_HEAD(head, field) do { \
if (!TAILQ_EMPTY(head) && \
TAILQ_FIRST((head))->field.tqe_prev != \
&TAILQ_FIRST((head))) \
panic("Bad tailq head %p first->prev != head", (head)); \
} while (0)
#define QMD_TAILQ_CHECK_TAIL(head, field) do { \
if (*(head)->tqh_last != NULL) \
panic("Bad tailq NEXT(%p->tqh_last) != NULL", (head)); \
} while (0)
#define QMD_TAILQ_CHECK_NEXT(elm, field) do { \
if (TAILQ_NEXT((elm), field) != NULL && \
TAILQ_NEXT((elm), field)->field.tqe_prev != \
&((elm)->field.tqe_next)) \
panic("Bad link elm %p next->prev != elm", (elm)); \
} while (0)
#define QMD_TAILQ_CHECK_PREV(elm, field) do { \
if (*(elm)->field.tqe_prev != (elm)) \
panic("Bad link elm %p prev->next != elm", (elm)); \
} while (0)
#else
#define QMD_TAILQ_CHECK_HEAD(head, field)
#define QMD_TAILQ_CHECK_TAIL(head, headname)
#define QMD_TAILQ_CHECK_NEXT(elm, field)
#define QMD_TAILQ_CHECK_PREV(elm, field)
#endif /* (_KERNEL && INVARIANTS) */
#define TAILQ_CONCAT(head1, head2, field) do { \
if (!TAILQ_EMPTY(head2)) { \
*(head1)->tqh_last = (head2)->tqh_first; \
(head2)->tqh_first->field.tqe_prev = (head1)->tqh_last; \
(head1)->tqh_last = (head2)->tqh_last; \
TAILQ_INIT((head2)); \
QMD_TRACE_HEAD(head1); \
QMD_TRACE_HEAD(head2); \
} \
} while (0)
#define TAILQ_EMPTY(head) ((head)->tqh_first == NULL)
#define TAILQ_FIRST(head) ((head)->tqh_first)
#define TAILQ_FOREACH(var, head, field) \
for ((var) = TAILQ_FIRST((head)); \
(var); \
(var) = TAILQ_NEXT((var), field))
#define TAILQ_FOREACH_FROM(var, head, field) \
for ((var) = ((var) ? (var) : TAILQ_FIRST((head))); \
(var); \
(var) = TAILQ_NEXT((var), field))
#define TAILQ_FOREACH_SAFE(var, head, field, tvar) \
for ((var) = TAILQ_FIRST((head)); \
(var) && ((tvar) = TAILQ_NEXT((var), field), 1); \
(var) = (tvar))
#define TAILQ_FOREACH_FROM_SAFE(var, head, field, tvar) \
for ((var) = ((var) ? (var) : TAILQ_FIRST((head))); \
(var) && ((tvar) = TAILQ_NEXT((var), field), 1); \
(var) = (tvar))
#define TAILQ_FOREACH_REVERSE(var, head, headname, field) \
for ((var) = TAILQ_LAST((head), headname); \
(var); \
(var) = TAILQ_PREV((var), headname, field))
#define TAILQ_FOREACH_REVERSE_FROM(var, head, headname, field) \
for ((var) = ((var) ? (var) : TAILQ_LAST((head), headname)); \
(var); \
(var) = TAILQ_PREV((var), headname, field))
#define TAILQ_FOREACH_REVERSE_SAFE(var, head, headname, field, tvar) \
for ((var) = TAILQ_LAST((head), headname); \
(var) && ((tvar) = TAILQ_PREV((var), headname, field), 1); \
(var) = (tvar))
#define TAILQ_FOREACH_REVERSE_FROM_SAFE(var, head, headname, field, tvar) \
for ((var) = ((var) ? (var) : TAILQ_LAST((head), headname)); \
(var) && ((tvar) = TAILQ_PREV((var), headname, field), 1); \
(var) = (tvar))
#define TAILQ_INIT(head) do { \
TAILQ_FIRST((head)) = NULL; \
(head)->tqh_last = &TAILQ_FIRST((head)); \
QMD_TRACE_HEAD(head); \
} while (0)
#define TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \
QMD_TAILQ_CHECK_NEXT(listelm, field); \
if ((TAILQ_NEXT((elm), field) = TAILQ_NEXT((listelm), field)) != NULL)\
TAILQ_NEXT((elm), field)->field.tqe_prev = \
&TAILQ_NEXT((elm), field); \
else { \
(head)->tqh_last = &TAILQ_NEXT((elm), field); \
QMD_TRACE_HEAD(head); \
} \
TAILQ_NEXT((listelm), field) = (elm); \
(elm)->field.tqe_prev = &TAILQ_NEXT((listelm), field); \
QMD_TRACE_ELEM(&(elm)->field); \
QMD_TRACE_ELEM(&listelm->field); \
} while (0)
#define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \
QMD_TAILQ_CHECK_PREV(listelm, field); \
(elm)->field.tqe_prev = (listelm)->field.tqe_prev; \
TAILQ_NEXT((elm), field) = (listelm); \
*(listelm)->field.tqe_prev = (elm); \
(listelm)->field.tqe_prev = &TAILQ_NEXT((elm), field); \
QMD_TRACE_ELEM(&(elm)->field); \
QMD_TRACE_ELEM(&listelm->field); \
} while (0)
#define TAILQ_INSERT_HEAD(head, elm, field) do { \
QMD_TAILQ_CHECK_HEAD(head, field); \
if ((TAILQ_NEXT((elm), field) = TAILQ_FIRST((head))) != NULL) \
TAILQ_FIRST((head))->field.tqe_prev = \
&TAILQ_NEXT((elm), field); \
else \
(head)->tqh_last = &TAILQ_NEXT((elm), field); \
TAILQ_FIRST((head)) = (elm); \
(elm)->field.tqe_prev = &TAILQ_FIRST((head)); \
QMD_TRACE_HEAD(head); \
QMD_TRACE_ELEM(&(elm)->field); \
} while (0)
#define TAILQ_INSERT_TAIL(head, elm, field) do { \
QMD_TAILQ_CHECK_TAIL(head, field); \
TAILQ_NEXT((elm), field) = NULL; \
(elm)->field.tqe_prev = (head)->tqh_last; \
*(head)->tqh_last = (elm); \
(head)->tqh_last = &TAILQ_NEXT((elm), field); \
QMD_TRACE_HEAD(head); \
QMD_TRACE_ELEM(&(elm)->field); \
} while (0)
#define TAILQ_LAST(head, headname) \
(*(((struct headname *)((head)->tqh_last))->tqh_last))
#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next)
#define TAILQ_PREV(elm, headname, field) \
(*(((struct headname *)((elm)->field.tqe_prev))->tqh_last))
#define TAILQ_REMOVE(head, elm, field) do { \
QMD_SAVELINK(oldnext, (elm)->field.tqe_next); \
QMD_SAVELINK(oldprev, (elm)->field.tqe_prev); \
QMD_TAILQ_CHECK_NEXT(elm, field); \
QMD_TAILQ_CHECK_PREV(elm, field); \
if ((TAILQ_NEXT((elm), field)) != NULL) \
TAILQ_NEXT((elm), field)->field.tqe_prev = \
(elm)->field.tqe_prev; \
else { \
(head)->tqh_last = (elm)->field.tqe_prev; \
QMD_TRACE_HEAD(head); \
} \
*(elm)->field.tqe_prev = TAILQ_NEXT((elm), field); \
TRASHIT(*oldnext); \
TRASHIT(*oldprev); \
QMD_TRACE_ELEM(&(elm)->field); \
} while (0)
#define TAILQ_SWAP(head1, head2, type, field) do { \
struct type *swap_first = (head1)->tqh_first; \
struct type **swap_last = (head1)->tqh_last; \
(head1)->tqh_first = (head2)->tqh_first; \
(head1)->tqh_last = (head2)->tqh_last; \
(head2)->tqh_first = swap_first; \
(head2)->tqh_last = swap_last; \
if ((swap_first = (head1)->tqh_first) != NULL) \
swap_first->field.tqe_prev = &(head1)->tqh_first; \
else \
(head1)->tqh_last = &(head1)->tqh_first; \
if ((swap_first = (head2)->tqh_first) != NULL) \
swap_first->field.tqe_prev = &(head2)->tqh_first; \
else \
(head2)->tqh_last = &(head2)->tqh_first; \
} while (0)
#endif /* !_SYS_QUEUE_H_ */