63 Commits
0.0.7 ... 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
34 changed files with 2354 additions and 1860 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

View File

@@ -1,3 +1,11 @@
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!

View File

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

View File

@@ -1,14 +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_man8_MANS=bgpq4.8
EXTRA_DIST=bootstrap README.md CHANGES COPYRIGHT bgpq4.spec
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
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,6 +3,9 @@ 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
--------
@@ -329,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
--------
@@ -378,6 +376,12 @@ On Arch Linux, BGPQ4 is [available in AUR](https://aur.archlinux.org/packages/bg
yay -S bgpq4
```
On OpenBSD:
```shell
pkg_add bgpq4
```
MAILING LIST
------------

1
VERSION Normal file
View File

@@ -0,0 +1 @@
1.0

98
bgpq4.h
View File

@@ -1,98 +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,
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;
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,88 +0,0 @@
Name: bgpq4
Version: 0.0.6
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
* Thu Mar 12 2020 Job Snijders <job@ntt.net> 0.0.6:
- bugfixes (Thanks Chris Caputo!)
* Wed Jan 01 2020 Job Snijders <job@ntt.net> 0.0.5:
- bugfixes
* 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.6,job@sobornost.net)
AM_INIT_AUTOMAKE
AC_PACKAGE_URL(https://github.com/bgp/bgpq4)
AC_CONFIG_HEADERS([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,7 +498,7 @@ 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;
@@ -505,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;
@@ -515,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;
@@ -544,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 "
@@ -563,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;
@@ -581,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;
@@ -592,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;
@@ -607,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;
@@ -693,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);
@@ -710,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:
@@ -738,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",
@@ -750,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);
}
@@ -802,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);
@@ -841,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;
@@ -865,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));
@@ -908,10 +937,10 @@ 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");
" connection to remain open\n");
if ((ret = write(fd, "!!\n", 3)) != 3) {
sx_report(SX_ERROR, "Partial write of multiple command mode 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);
}
@@ -922,7 +951,8 @@ bgpq_expand(struct bgpq_expander* b)
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",
sx_report(SX_ERROR, "Partial write of "
"identifier to IRRd: %i bytes, %s\n",
ret, strerror(errno));
exit(1);
}
@@ -930,7 +960,7 @@ bgpq_expand(struct bgpq_expander* b)
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");
sx_report(SX_ERROR, "ident, failed read from IRRd\n");
exit(1);
}
} else {
@@ -945,8 +975,8 @@ bgpq_expand(struct bgpq_expander* b)
char aresp[] = "F Missing required set name for A query";
SX_DEBUG(debug_expander, "Testing support for A queries\n");
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));
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));
@@ -955,10 +985,10 @@ bgpq_expand(struct bgpq_expander* b)
SX_DEBUG(debug_expander, "Server supports A query\n");
aquery = 1;
} else {
SX_DEBUG(debug_expander, "No support for A queries\n");
SX_DEBUG(debug_expander, "No support for A query\n");
}
} else {
sx_report(SX_ERROR, "'!a' query test - failed read from IRRd\n");
sx_report(SX_ERROR, "A query test failed read from IRRd\n");
exit(1);
}
}
@@ -972,20 +1002,20 @@ bgpq_expand(struct bgpq_expander* b)
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));
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);
sx_report(SX_ERROR, "Invalid source(s) "
"'%s': %s\n", b->sources, sources);
exit(1);
}
} else {
sx_report(SX_ERROR, "sources - failed read from IRRd\n");
sx_report(SX_ERROR, "failed to read sources\n");
exit(1);
}
} else {
@@ -997,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);
}
}
@@ -1027,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++) {
@@ -1044,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);
}
}
}
@@ -1085,3 +1115,79 @@ bgpq_expand(struct bgpq_expander* b)
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,16 +41,15 @@
#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>"
@@ -85,8 +111,8 @@ usage(int ecode)
exit(ecode);
}
void
version()
static void
version(void)
{
printf(PACKAGE_NAME " - a versatile utility to generate BGP filters\n"
"version: " PACKAGE_VERSION "\n"
@@ -95,16 +121,16 @@ version()
exit(0);
}
void
exclusive()
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),"
@@ -113,36 +139,37 @@ vendor_exclusive()
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;
@@ -169,7 +196,8 @@ main(int argc, char* argv[])
if (getenv("IRRD_SOURCES"))
expander.sources=getenv("IRRD_SOURCES");
while ((c = getopt(argc,argv,"346a:AbBdDEeF:S:jJKf:l:L:m:M:NnW:pr:R:G:tTh:UwXsvz"))
while ((c = getopt(argc, argv,
"346a:AbBdDEeF:S:jJKf:l:L:m:M:NnW:pr:R:G:tTh:UwXsvz"))
!=EOF) {
switch (c) {
case '3':
@@ -311,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':
@@ -414,99 +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.vendor == V_ARISTA) {
expander.aswidth = 4;
}
} 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) {
case V_JUNIPER:
case V_NOKIA:
case V_NOKIA_MD:
expander.aswidth = 8;
} else if (expander.vendor == V_NOKIA ||
expander.vendor == V_NOKIA_MD) {
expander.aswidth = 8;
} else if (expander.vendor == V_ARISTA) {
expander.aswidth = 5;
}
}
}
if (!expander.generation) {
if (!expander.generation)
expander.generation = T_PREFIXLIST;
}
if (expander.vendor == V_CISCO_XR && expander.generation != T_PREFIXLIST &&
expander.generation != T_ASPATH && expander.generation != T_OASPATH) {
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");
}
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_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_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");
@@ -519,7 +562,8 @@ main(int argc, char* argv[])
exit(1);
}
if (expander.sequence && (expander.vendor != V_CISCO && expander.vendor != V_ARISTA)) {
if (expander.sequence
&& (expander.vendor != V_CISCO && expander.vendor != V_ARISTA)) {
sx_report(SX_FATAL, "Sorry, prefix-lists sequencing (-s) supported"
" only for IOS and EOS\n");
exit(1);
@@ -538,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) {
@@ -573,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);
}
}
}
@@ -597,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) {
@@ -634,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,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,23 +417,22 @@ 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, "/");
}
void
sx_prefix_snprintf_fmt(struct sx_prefix* p, FILE* f,
const char* name, const char* format,
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);
char prefix[128];
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':
@@ -484,7 +506,7 @@ sx_prefix_snprintf_fmt(struct sx_prefix* p, FILE* f,
}
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];
@@ -500,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;
@@ -512,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;
@@ -533,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;
@@ -561,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);
@@ -571,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)
@@ -603,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 {
@@ -621,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;
@@ -647,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;
@@ -711,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;
}
@@ -735,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);
@@ -762,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 {
@@ -811,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 {
@@ -824,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);
@@ -839,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);
@@ -1019,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);
@@ -1028,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;
@@ -1036,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;
@@ -1079,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);
@@ -1088,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) {
@@ -1148,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);
@@ -1159,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);
@@ -1214,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,59 +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*);
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);
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_ */