mirror of
https://github.com/kiddin9/op-packages.git
synced 2026-11-03 08:43:56 +08:00
⛅ Sync 2026-08-05 21:58:21
This commit is contained in:
1 parent
61841aa371
commit
6e0b600ecd
734 files changed
+225296
-28
No files matched your search
@@ -0,0 +1,112 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# ----------------------------------------------------------------------
|
||||
# Copyright © 2011-2013, RedJack, LLC.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Please see the LICENSE.txt file in this distribution for license
|
||||
# details.
|
||||
# ----------------------------------------------------------------------
|
||||
|
||||
cmake_minimum_required(VERSION 2.6)
|
||||
set(PROJECT_NAME ipset)
|
||||
set(RELEASE_DATE 2013-12-11)
|
||||
project(${PROJECT_NAME})
|
||||
|
||||
set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
|
||||
find_package(CTargets)
|
||||
|
||||
#-----------------------------------------------------------------------
|
||||
# Retrieve the current version number
|
||||
|
||||
#-----------------------------------------------------------------------
|
||||
# Check for building on Tilera
|
||||
# If the Tilera environment is installed, then $TILERA_ROOT is defined
|
||||
# as the path to the active MDE.
|
||||
|
||||
if(DEFINED ENV{TILERA_ROOT})
|
||||
set(TILERA TRUE)
|
||||
set(TILERA_ROOT $ENV{TILERA_ROOT})
|
||||
message("-- Configuring for Tilera MDE ${TILERA_ROOT}")
|
||||
set(ENV{PKG_CONFIG_PATH}
|
||||
"${TILERA_ROOT}/tile/usr/lib/pkgconfig:${TILERA_ROOT}/tile/usr/local/lib/pkgconfig:$ENV{PKG_CONFIG_PATH}"
|
||||
)
|
||||
set(CMAKE_SYSTEM_NAME "Tilera")
|
||||
set(CMAKE_SYSTEM_PROCESSOR "tilegx")
|
||||
set(CMAKE_C_COMPILER "${TILERA_ROOT}/bin/tile-gcc")
|
||||
set(CMAKE_LINKER "${TILERA_ROOT}/bin/tile-ld")
|
||||
set(TILERA_MONITOR "${TILERA_ROOT}/bin/tile-monitor")
|
||||
#add_definitions(-std=gnu99)
|
||||
set(CMAKE_FIND_ROOT_PATH "${TILERA_ROOT}/tile")
|
||||
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM ONLY)
|
||||
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
|
||||
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
|
||||
endif()
|
||||
|
||||
#-----------------------------------------------------------------------
|
||||
# Check for prerequisite libraries
|
||||
|
||||
include_directories(${libcork_include_dirs})
|
||||
|
||||
#-----------------------------------------------------------------------
|
||||
# Set some options
|
||||
|
||||
if(APPLE)
|
||||
if (NOT CMAKE_INSTALL_NAME_DIR)
|
||||
set(CMAKE_INSTALL_NAME_DIR "${CMAKE_INSTALL_PREFIX}/lib")
|
||||
endif (NOT CMAKE_INSTALL_NAME_DIR)
|
||||
endif(APPLE)
|
||||
|
||||
if(NOT CMAKE_BUILD_TYPE)
|
||||
set(CMAKE_BUILD_TYPE Release CACHE STRING
|
||||
"Choose the type of build, options are: None Debug Release RelWithDebInfo MinSizeRel."
|
||||
FORCE)
|
||||
endif(NOT CMAKE_BUILD_TYPE)
|
||||
|
||||
if(CMAKE_C_COMPILER_ID STREQUAL "GNU")
|
||||
add_definitions(-Wall -Werror)
|
||||
elseif(CMAKE_C_COMPILER_ID STREQUAL "Clang")
|
||||
add_definitions(-Wall -Werror)
|
||||
elseif(CMAKE_C_COMPILER_ID STREQUAL "Intel")
|
||||
add_definitions(-Wall -Werror)
|
||||
endif(CMAKE_C_COMPILER_ID STREQUAL "GNU")
|
||||
|
||||
#-----------------------------------------------------------------------
|
||||
# Include our subdirectories
|
||||
|
||||
#add_subdirectory(src)
|
||||
|
||||
add_c_library(
|
||||
libipset
|
||||
OUTPUT_NAME ipset
|
||||
PKGCONFIG_NAME libipset
|
||||
VERSION 1.1.0
|
||||
SOURCES
|
||||
general.c
|
||||
bdd/assignments.c
|
||||
bdd/basics.c
|
||||
bdd/bdd-iterator.c
|
||||
bdd/expanded.c
|
||||
bdd/reachable.c
|
||||
bdd/read.c
|
||||
bdd/write.c
|
||||
map/allocation.c
|
||||
map/inspection.c
|
||||
map/ipv4_map.c
|
||||
map/ipv6_map.c
|
||||
map/storage.c
|
||||
set/allocation.c
|
||||
set/inspection.c
|
||||
set/ipv4_set.c
|
||||
set/ipv6_set.c
|
||||
set/iterator.c
|
||||
set/storage.c
|
||||
|
||||
LOCAL_LIBRARIES
|
||||
libcork
|
||||
)
|
||||
|
||||
set(libipset_include_dirs
|
||||
${PROJECT_SOURCE_DIR}/include
|
||||
${PROJECT_BINARY_DIR}/include
|
||||
CACHE INTERNAL "libipset library" FORCE
|
||||
)
|
||||
@@ -0,0 +1,30 @@
|
||||
Copyright © 2009-2013, RedJack, LLC.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
• Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
• 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.
|
||||
|
||||
• Neither the name of RedJack Software, LLC 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 COPYRIGHT HOLDERS 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 COPYRIGHT
|
||||
HOLDER 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.
|
||||
@@ -0,0 +1,13 @@
|
||||
noinst_LTLIBRARIES = libipset.la
|
||||
|
||||
bdd_src = bdd/assignments.c bdd/basics.c bdd/bdd-iterator.c bdd/expanded.c \
|
||||
bdd/reachable.c bdd/read.c bdd/write.c
|
||||
map_src = map/allocation.c map/inspection.c map/ipv4_map.c map/ipv6_map.c \
|
||||
map/storage.c
|
||||
set_src = set/allocation.c set/inspection.c set/ipv4_set.c set/ipv6_set.c \
|
||||
set/iterator.c set/storage.c
|
||||
|
||||
libipset_la_SOURCES = general.c ${bdd_src} ${map_src} ${set_src}
|
||||
libipset_la_CFLAGS = -I$(top_srcdir)/libipset/include -I$(top_srcdir)/libcork/include
|
||||
|
||||
libipset_la_LDFLAGS = -static
|
||||
@@ -0,0 +1,852 @@
|
||||
# Makefile.in generated by automake 1.15 from Makefile.am.
|
||||
# @configure_input@
|
||||
|
||||
# Copyright (C) 1994-2014 Free Software Foundation, Inc.
|
||||
|
||||
# This Makefile.in is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
# with or without modifications, as long as this notice is preserved.
|
||||
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
|
||||
# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||
# PARTICULAR PURPOSE.
|
||||
|
||||
@SET_MAKE@
|
||||
|
||||
VPATH = @srcdir@
|
||||
am__is_gnu_make = { \
|
||||
if test -z '$(MAKELEVEL)'; then \
|
||||
false; \
|
||||
elif test -n '$(MAKE_HOST)'; then \
|
||||
true; \
|
||||
elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
|
||||
true; \
|
||||
else \
|
||||
false; \
|
||||
fi; \
|
||||
}
|
||||
am__make_running_with_option = \
|
||||
case $${target_option-} in \
|
||||
?) ;; \
|
||||
*) echo "am__make_running_with_option: internal error: invalid" \
|
||||
"target option '$${target_option-}' specified" >&2; \
|
||||
exit 1;; \
|
||||
esac; \
|
||||
has_opt=no; \
|
||||
sane_makeflags=$$MAKEFLAGS; \
|
||||
if $(am__is_gnu_make); then \
|
||||
sane_makeflags=$$MFLAGS; \
|
||||
else \
|
||||
case $$MAKEFLAGS in \
|
||||
*\\[\ \ ]*) \
|
||||
bs=\\; \
|
||||
sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
|
||||
| sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
|
||||
esac; \
|
||||
fi; \
|
||||
skip_next=no; \
|
||||
strip_trailopt () \
|
||||
{ \
|
||||
flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
|
||||
}; \
|
||||
for flg in $$sane_makeflags; do \
|
||||
test $$skip_next = yes && { skip_next=no; continue; }; \
|
||||
case $$flg in \
|
||||
*=*|--*) continue;; \
|
||||
-*I) strip_trailopt 'I'; skip_next=yes;; \
|
||||
-*I?*) strip_trailopt 'I';; \
|
||||
-*O) strip_trailopt 'O'; skip_next=yes;; \
|
||||
-*O?*) strip_trailopt 'O';; \
|
||||
-*l) strip_trailopt 'l'; skip_next=yes;; \
|
||||
-*l?*) strip_trailopt 'l';; \
|
||||
-[dEDm]) skip_next=yes;; \
|
||||
-[JT]) skip_next=yes;; \
|
||||
esac; \
|
||||
case $$flg in \
|
||||
*$$target_option*) has_opt=yes; break;; \
|
||||
esac; \
|
||||
done; \
|
||||
test $$has_opt = yes
|
||||
am__make_dryrun = (target_option=n; $(am__make_running_with_option))
|
||||
am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
|
||||
pkgdatadir = $(datadir)/@PACKAGE@
|
||||
pkgincludedir = $(includedir)/@PACKAGE@
|
||||
pkglibdir = $(libdir)/@PACKAGE@
|
||||
pkglibexecdir = $(libexecdir)/@PACKAGE@
|
||||
am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
|
||||
install_sh_DATA = $(install_sh) -c -m 644
|
||||
install_sh_PROGRAM = $(install_sh) -c
|
||||
install_sh_SCRIPT = $(install_sh) -c
|
||||
INSTALL_HEADER = $(INSTALL_DATA)
|
||||
transform = $(program_transform_name)
|
||||
NORMAL_INSTALL = :
|
||||
PRE_INSTALL = :
|
||||
POST_INSTALL = :
|
||||
NORMAL_UNINSTALL = :
|
||||
PRE_UNINSTALL = :
|
||||
POST_UNINSTALL = :
|
||||
build_triplet = @build@
|
||||
host_triplet = @host@
|
||||
subdir = libipset
|
||||
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
|
||||
am__aclocal_m4_deps = $(top_srcdir)/m4/ax_pthread.m4 \
|
||||
$(top_srcdir)/m4/ax_tls.m4 $(top_srcdir)/m4/inet_ntop.m4 \
|
||||
$(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
|
||||
$(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
|
||||
$(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/mbedtls.m4 \
|
||||
$(top_srcdir)/m4/openssl.m4 $(top_srcdir)/m4/pcre.m4 \
|
||||
$(top_srcdir)/m4/polarssl.m4 \
|
||||
$(top_srcdir)/m4/stack-protector.m4 $(top_srcdir)/m4/zlib.m4 \
|
||||
$(top_srcdir)/libev/libev.m4 $(top_srcdir)/configure.ac
|
||||
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
|
||||
$(ACLOCAL_M4)
|
||||
DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
|
||||
mkinstalldirs = $(install_sh) -d
|
||||
CONFIG_HEADER = $(top_builddir)/config.h
|
||||
CONFIG_CLEAN_FILES =
|
||||
CONFIG_CLEAN_VPATH_FILES =
|
||||
LTLIBRARIES = $(noinst_LTLIBRARIES)
|
||||
libipset_la_LIBADD =
|
||||
am__dirstamp = $(am__leading_dot)dirstamp
|
||||
am__objects_1 = bdd/libipset_la-assignments.lo \
|
||||
bdd/libipset_la-basics.lo bdd/libipset_la-bdd-iterator.lo \
|
||||
bdd/libipset_la-expanded.lo bdd/libipset_la-reachable.lo \
|
||||
bdd/libipset_la-read.lo bdd/libipset_la-write.lo
|
||||
am__objects_2 = map/libipset_la-allocation.lo \
|
||||
map/libipset_la-inspection.lo map/libipset_la-ipv4_map.lo \
|
||||
map/libipset_la-ipv6_map.lo map/libipset_la-storage.lo
|
||||
am__objects_3 = set/libipset_la-allocation.lo \
|
||||
set/libipset_la-inspection.lo set/libipset_la-ipv4_set.lo \
|
||||
set/libipset_la-ipv6_set.lo set/libipset_la-iterator.lo \
|
||||
set/libipset_la-storage.lo
|
||||
am_libipset_la_OBJECTS = libipset_la-general.lo $(am__objects_1) \
|
||||
$(am__objects_2) $(am__objects_3)
|
||||
libipset_la_OBJECTS = $(am_libipset_la_OBJECTS)
|
||||
AM_V_lt = $(am__v_lt_@AM_V@)
|
||||
am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
|
||||
am__v_lt_0 = --silent
|
||||
am__v_lt_1 =
|
||||
libipset_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
|
||||
$(LIBTOOLFLAGS) --mode=link $(CCLD) $(libipset_la_CFLAGS) \
|
||||
$(CFLAGS) $(libipset_la_LDFLAGS) $(LDFLAGS) -o $@
|
||||
AM_V_P = $(am__v_P_@AM_V@)
|
||||
am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
|
||||
am__v_P_0 = false
|
||||
am__v_P_1 = :
|
||||
AM_V_GEN = $(am__v_GEN_@AM_V@)
|
||||
am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
|
||||
am__v_GEN_0 = @echo " GEN " $@;
|
||||
am__v_GEN_1 =
|
||||
AM_V_at = $(am__v_at_@AM_V@)
|
||||
am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
|
||||
am__v_at_0 = @
|
||||
am__v_at_1 =
|
||||
DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
|
||||
depcomp = $(SHELL) $(top_srcdir)/auto/depcomp
|
||||
am__depfiles_maybe = depfiles
|
||||
am__mv = mv -f
|
||||
COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
|
||||
$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
|
||||
LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
|
||||
$(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
|
||||
$(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
|
||||
$(AM_CFLAGS) $(CFLAGS)
|
||||
AM_V_CC = $(am__v_CC_@AM_V@)
|
||||
am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
|
||||
am__v_CC_0 = @echo " CC " $@;
|
||||
am__v_CC_1 =
|
||||
CCLD = $(CC)
|
||||
LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
|
||||
$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
|
||||
$(AM_LDFLAGS) $(LDFLAGS) -o $@
|
||||
AM_V_CCLD = $(am__v_CCLD_@AM_V@)
|
||||
am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
|
||||
am__v_CCLD_0 = @echo " CCLD " $@;
|
||||
am__v_CCLD_1 =
|
||||
SOURCES = $(libipset_la_SOURCES)
|
||||
DIST_SOURCES = $(libipset_la_SOURCES)
|
||||
am__can_run_installinfo = \
|
||||
case $$AM_UPDATE_INFO_DIR in \
|
||||
n|no|NO) false;; \
|
||||
*) (install-info --version) >/dev/null 2>&1;; \
|
||||
esac
|
||||
am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
|
||||
# Read a list of newline-separated strings from the standard input,
|
||||
# and print each of them once, without duplicates. Input order is
|
||||
# *not* preserved.
|
||||
am__uniquify_input = $(AWK) '\
|
||||
BEGIN { nonempty = 0; } \
|
||||
{ items[$$0] = 1; nonempty = 1; } \
|
||||
END { if (nonempty) { for (i in items) print i; }; } \
|
||||
'
|
||||
# Make sure the list of sources is unique. This is necessary because,
|
||||
# e.g., the same source file might be shared among _SOURCES variables
|
||||
# for different programs/libraries.
|
||||
am__define_uniq_tagged_files = \
|
||||
list='$(am__tagged_files)'; \
|
||||
unique=`for i in $$list; do \
|
||||
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
|
||||
done | $(am__uniquify_input)`
|
||||
ETAGS = etags
|
||||
CTAGS = ctags
|
||||
am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/auto/depcomp
|
||||
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
|
||||
ACLOCAL = @ACLOCAL@
|
||||
AMTAR = @AMTAR@
|
||||
AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
|
||||
AR = @AR@
|
||||
ASCIIDOC = @ASCIIDOC@
|
||||
AUTOCONF = @AUTOCONF@
|
||||
AUTOHEADER = @AUTOHEADER@
|
||||
AUTOMAKE = @AUTOMAKE@
|
||||
AWK = @AWK@
|
||||
CC = @CC@
|
||||
CCDEPMODE = @CCDEPMODE@
|
||||
CFLAGS = @CFLAGS@
|
||||
CPP = @CPP@
|
||||
CPPFLAGS = @CPPFLAGS@
|
||||
CYGPATH_W = @CYGPATH_W@
|
||||
DEFS = @DEFS@
|
||||
DEPDIR = @DEPDIR@
|
||||
DLLTOOL = @DLLTOOL@
|
||||
DSYMUTIL = @DSYMUTIL@
|
||||
DUMPBIN = @DUMPBIN@
|
||||
ECHO_C = @ECHO_C@
|
||||
ECHO_N = @ECHO_N@
|
||||
ECHO_T = @ECHO_T@
|
||||
EGREP = @EGREP@
|
||||
EXEEXT = @EXEEXT@
|
||||
FGREP = @FGREP@
|
||||
GREP = @GREP@
|
||||
GZIP = @GZIP@
|
||||
INET_NTOP_LIB = @INET_NTOP_LIB@
|
||||
INSTALL = @INSTALL@
|
||||
INSTALL_DATA = @INSTALL_DATA@
|
||||
INSTALL_PROGRAM = @INSTALL_PROGRAM@
|
||||
INSTALL_SCRIPT = @INSTALL_SCRIPT@
|
||||
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
|
||||
LD = @LD@
|
||||
LDFLAGS = @LDFLAGS@
|
||||
LIBOBJS = @LIBOBJS@
|
||||
LIBPCRE = @LIBPCRE@
|
||||
LIBS = @LIBS@
|
||||
LIBTOOL = @LIBTOOL@
|
||||
LIPO = @LIPO@
|
||||
LN_S = @LN_S@
|
||||
LTLIBOBJS = @LTLIBOBJS@
|
||||
MAINT = @MAINT@
|
||||
MAKEINFO = @MAKEINFO@
|
||||
MANIFEST_TOOL = @MANIFEST_TOOL@
|
||||
MKDIR_P = @MKDIR_P@
|
||||
MV = @MV@
|
||||
NM = @NM@
|
||||
NMEDIT = @NMEDIT@
|
||||
OBJDUMP = @OBJDUMP@
|
||||
OBJEXT = @OBJEXT@
|
||||
OTOOL = @OTOOL@
|
||||
OTOOL64 = @OTOOL64@
|
||||
PACKAGE = @PACKAGE@
|
||||
PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
|
||||
PACKAGE_NAME = @PACKAGE_NAME@
|
||||
PACKAGE_STRING = @PACKAGE_STRING@
|
||||
PACKAGE_TARNAME = @PACKAGE_TARNAME@
|
||||
PACKAGE_URL = @PACKAGE_URL@
|
||||
PACKAGE_VERSION = @PACKAGE_VERSION@
|
||||
PATH_SEPARATOR = @PATH_SEPARATOR@
|
||||
PCRE_CONFIG = @PCRE_CONFIG@
|
||||
PTHREAD_CC = @PTHREAD_CC@
|
||||
PTHREAD_CFLAGS = @PTHREAD_CFLAGS@
|
||||
PTHREAD_LIBS = @PTHREAD_LIBS@
|
||||
RANLIB = @RANLIB@
|
||||
SED = @SED@
|
||||
SET_MAKE = @SET_MAKE@
|
||||
SHELL = @SHELL@
|
||||
STRIP = @STRIP@
|
||||
VERSION = @VERSION@
|
||||
XMLTO = @XMLTO@
|
||||
abs_builddir = @abs_builddir@
|
||||
abs_srcdir = @abs_srcdir@
|
||||
abs_top_builddir = @abs_top_builddir@
|
||||
abs_top_srcdir = @abs_top_srcdir@
|
||||
ac_ct_AR = @ac_ct_AR@
|
||||
ac_ct_CC = @ac_ct_CC@
|
||||
ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
|
||||
am__include = @am__include@
|
||||
am__leading_dot = @am__leading_dot@
|
||||
am__quote = @am__quote@
|
||||
am__tar = @am__tar@
|
||||
am__untar = @am__untar@
|
||||
ax_pthread_config = @ax_pthread_config@
|
||||
bindir = @bindir@
|
||||
build = @build@
|
||||
build_alias = @build_alias@
|
||||
build_cpu = @build_cpu@
|
||||
build_os = @build_os@
|
||||
build_vendor = @build_vendor@
|
||||
builddir = @builddir@
|
||||
datadir = @datadir@
|
||||
datarootdir = @datarootdir@
|
||||
docdir = @docdir@
|
||||
dvidir = @dvidir@
|
||||
exec_prefix = @exec_prefix@
|
||||
host = @host@
|
||||
host_alias = @host_alias@
|
||||
host_cpu = @host_cpu@
|
||||
host_os = @host_os@
|
||||
host_vendor = @host_vendor@
|
||||
htmldir = @htmldir@
|
||||
includedir = @includedir@
|
||||
infodir = @infodir@
|
||||
install_sh = @install_sh@
|
||||
libdir = @libdir@
|
||||
libexecdir = @libexecdir@
|
||||
localedir = @localedir@
|
||||
localstatedir = @localstatedir@
|
||||
mandir = @mandir@
|
||||
mkdir_p = @mkdir_p@
|
||||
oldincludedir = @oldincludedir@
|
||||
pcre_pcreh = @pcre_pcreh@
|
||||
pcreh = @pcreh@
|
||||
pdfdir = @pdfdir@
|
||||
prefix = @prefix@
|
||||
program_transform_name = @program_transform_name@
|
||||
psdir = @psdir@
|
||||
runstatedir = @runstatedir@
|
||||
sbindir = @sbindir@
|
||||
sharedstatedir = @sharedstatedir@
|
||||
srcdir = @srcdir@
|
||||
subdirs = @subdirs@
|
||||
sysconfdir = @sysconfdir@
|
||||
target_alias = @target_alias@
|
||||
top_build_prefix = @top_build_prefix@
|
||||
top_builddir = @top_builddir@
|
||||
top_srcdir = @top_srcdir@
|
||||
noinst_LTLIBRARIES = libipset.la
|
||||
bdd_src = bdd/assignments.c bdd/basics.c bdd/bdd-iterator.c bdd/expanded.c \
|
||||
bdd/reachable.c bdd/read.c bdd/write.c
|
||||
|
||||
map_src = map/allocation.c map/inspection.c map/ipv4_map.c map/ipv6_map.c \
|
||||
map/storage.c
|
||||
|
||||
set_src = set/allocation.c set/inspection.c set/ipv4_set.c set/ipv6_set.c \
|
||||
set/iterator.c set/storage.c
|
||||
|
||||
libipset_la_SOURCES = general.c ${bdd_src} ${map_src} ${set_src}
|
||||
libipset_la_CFLAGS = -I$(top_srcdir)/libipset/include -I$(top_srcdir)/libcork/include
|
||||
libipset_la_LDFLAGS = -static
|
||||
all: all-am
|
||||
|
||||
.SUFFIXES:
|
||||
.SUFFIXES: .c .lo .o .obj
|
||||
$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
|
||||
@for dep in $?; do \
|
||||
case '$(am__configure_deps)' in \
|
||||
*$$dep*) \
|
||||
( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
|
||||
&& { if test -f $@; then exit 0; else break; fi; }; \
|
||||
exit 1;; \
|
||||
esac; \
|
||||
done; \
|
||||
echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign libipset/Makefile'; \
|
||||
$(am__cd) $(top_srcdir) && \
|
||||
$(AUTOMAKE) --foreign libipset/Makefile
|
||||
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
|
||||
@case '$?' in \
|
||||
*config.status*) \
|
||||
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
|
||||
*) \
|
||||
echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
|
||||
cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
|
||||
esac;
|
||||
|
||||
$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
|
||||
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
|
||||
|
||||
$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
|
||||
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
|
||||
$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
|
||||
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
|
||||
$(am__aclocal_m4_deps):
|
||||
|
||||
clean-noinstLTLIBRARIES:
|
||||
-test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES)
|
||||
@list='$(noinst_LTLIBRARIES)'; \
|
||||
locs=`for p in $$list; do echo $$p; done | \
|
||||
sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
|
||||
sort -u`; \
|
||||
test -z "$$locs" || { \
|
||||
echo rm -f $${locs}; \
|
||||
rm -f $${locs}; \
|
||||
}
|
||||
bdd/$(am__dirstamp):
|
||||
@$(MKDIR_P) bdd
|
||||
@: > bdd/$(am__dirstamp)
|
||||
bdd/$(DEPDIR)/$(am__dirstamp):
|
||||
@$(MKDIR_P) bdd/$(DEPDIR)
|
||||
@: > bdd/$(DEPDIR)/$(am__dirstamp)
|
||||
bdd/libipset_la-assignments.lo: bdd/$(am__dirstamp) \
|
||||
bdd/$(DEPDIR)/$(am__dirstamp)
|
||||
bdd/libipset_la-basics.lo: bdd/$(am__dirstamp) \
|
||||
bdd/$(DEPDIR)/$(am__dirstamp)
|
||||
bdd/libipset_la-bdd-iterator.lo: bdd/$(am__dirstamp) \
|
||||
bdd/$(DEPDIR)/$(am__dirstamp)
|
||||
bdd/libipset_la-expanded.lo: bdd/$(am__dirstamp) \
|
||||
bdd/$(DEPDIR)/$(am__dirstamp)
|
||||
bdd/libipset_la-reachable.lo: bdd/$(am__dirstamp) \
|
||||
bdd/$(DEPDIR)/$(am__dirstamp)
|
||||
bdd/libipset_la-read.lo: bdd/$(am__dirstamp) \
|
||||
bdd/$(DEPDIR)/$(am__dirstamp)
|
||||
bdd/libipset_la-write.lo: bdd/$(am__dirstamp) \
|
||||
bdd/$(DEPDIR)/$(am__dirstamp)
|
||||
map/$(am__dirstamp):
|
||||
@$(MKDIR_P) map
|
||||
@: > map/$(am__dirstamp)
|
||||
map/$(DEPDIR)/$(am__dirstamp):
|
||||
@$(MKDIR_P) map/$(DEPDIR)
|
||||
@: > map/$(DEPDIR)/$(am__dirstamp)
|
||||
map/libipset_la-allocation.lo: map/$(am__dirstamp) \
|
||||
map/$(DEPDIR)/$(am__dirstamp)
|
||||
map/libipset_la-inspection.lo: map/$(am__dirstamp) \
|
||||
map/$(DEPDIR)/$(am__dirstamp)
|
||||
map/libipset_la-ipv4_map.lo: map/$(am__dirstamp) \
|
||||
map/$(DEPDIR)/$(am__dirstamp)
|
||||
map/libipset_la-ipv6_map.lo: map/$(am__dirstamp) \
|
||||
map/$(DEPDIR)/$(am__dirstamp)
|
||||
map/libipset_la-storage.lo: map/$(am__dirstamp) \
|
||||
map/$(DEPDIR)/$(am__dirstamp)
|
||||
set/$(am__dirstamp):
|
||||
@$(MKDIR_P) set
|
||||
@: > set/$(am__dirstamp)
|
||||
set/$(DEPDIR)/$(am__dirstamp):
|
||||
@$(MKDIR_P) set/$(DEPDIR)
|
||||
@: > set/$(DEPDIR)/$(am__dirstamp)
|
||||
set/libipset_la-allocation.lo: set/$(am__dirstamp) \
|
||||
set/$(DEPDIR)/$(am__dirstamp)
|
||||
set/libipset_la-inspection.lo: set/$(am__dirstamp) \
|
||||
set/$(DEPDIR)/$(am__dirstamp)
|
||||
set/libipset_la-ipv4_set.lo: set/$(am__dirstamp) \
|
||||
set/$(DEPDIR)/$(am__dirstamp)
|
||||
set/libipset_la-ipv6_set.lo: set/$(am__dirstamp) \
|
||||
set/$(DEPDIR)/$(am__dirstamp)
|
||||
set/libipset_la-iterator.lo: set/$(am__dirstamp) \
|
||||
set/$(DEPDIR)/$(am__dirstamp)
|
||||
set/libipset_la-storage.lo: set/$(am__dirstamp) \
|
||||
set/$(DEPDIR)/$(am__dirstamp)
|
||||
|
||||
libipset.la: $(libipset_la_OBJECTS) $(libipset_la_DEPENDENCIES) $(EXTRA_libipset_la_DEPENDENCIES)
|
||||
$(AM_V_CCLD)$(libipset_la_LINK) $(libipset_la_OBJECTS) $(libipset_la_LIBADD) $(LIBS)
|
||||
|
||||
mostlyclean-compile:
|
||||
-rm -f *.$(OBJEXT)
|
||||
-rm -f bdd/*.$(OBJEXT)
|
||||
-rm -f bdd/*.lo
|
||||
-rm -f map/*.$(OBJEXT)
|
||||
-rm -f map/*.lo
|
||||
-rm -f set/*.$(OBJEXT)
|
||||
-rm -f set/*.lo
|
||||
|
||||
distclean-compile:
|
||||
-rm -f *.tab.c
|
||||
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libipset_la-general.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@bdd/$(DEPDIR)/libipset_la-assignments.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@bdd/$(DEPDIR)/libipset_la-basics.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@bdd/$(DEPDIR)/libipset_la-bdd-iterator.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@bdd/$(DEPDIR)/libipset_la-expanded.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@bdd/$(DEPDIR)/libipset_la-reachable.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@bdd/$(DEPDIR)/libipset_la-read.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@bdd/$(DEPDIR)/libipset_la-write.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@map/$(DEPDIR)/libipset_la-allocation.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@map/$(DEPDIR)/libipset_la-inspection.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@map/$(DEPDIR)/libipset_la-ipv4_map.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@map/$(DEPDIR)/libipset_la-ipv6_map.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@map/$(DEPDIR)/libipset_la-storage.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@set/$(DEPDIR)/libipset_la-allocation.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@set/$(DEPDIR)/libipset_la-inspection.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@set/$(DEPDIR)/libipset_la-ipv4_set.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@set/$(DEPDIR)/libipset_la-ipv6_set.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@set/$(DEPDIR)/libipset_la-iterator.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@set/$(DEPDIR)/libipset_la-storage.Plo@am__quote@
|
||||
|
||||
.c.o:
|
||||
@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\
|
||||
@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
|
||||
@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
|
||||
|
||||
.c.obj:
|
||||
@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\
|
||||
@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\
|
||||
@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
|
||||
|
||||
.c.lo:
|
||||
@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\
|
||||
@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
|
||||
@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Plo
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
|
||||
|
||||
libipset_la-general.lo: general.c
|
||||
@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libipset_la_CFLAGS) $(CFLAGS) -MT libipset_la-general.lo -MD -MP -MF $(DEPDIR)/libipset_la-general.Tpo -c -o libipset_la-general.lo `test -f 'general.c' || echo '$(srcdir)/'`general.c
|
||||
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libipset_la-general.Tpo $(DEPDIR)/libipset_la-general.Plo
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='general.c' object='libipset_la-general.lo' libtool=yes @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libipset_la_CFLAGS) $(CFLAGS) -c -o libipset_la-general.lo `test -f 'general.c' || echo '$(srcdir)/'`general.c
|
||||
|
||||
bdd/libipset_la-assignments.lo: bdd/assignments.c
|
||||
@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libipset_la_CFLAGS) $(CFLAGS) -MT bdd/libipset_la-assignments.lo -MD -MP -MF bdd/$(DEPDIR)/libipset_la-assignments.Tpo -c -o bdd/libipset_la-assignments.lo `test -f 'bdd/assignments.c' || echo '$(srcdir)/'`bdd/assignments.c
|
||||
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) bdd/$(DEPDIR)/libipset_la-assignments.Tpo bdd/$(DEPDIR)/libipset_la-assignments.Plo
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='bdd/assignments.c' object='bdd/libipset_la-assignments.lo' libtool=yes @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libipset_la_CFLAGS) $(CFLAGS) -c -o bdd/libipset_la-assignments.lo `test -f 'bdd/assignments.c' || echo '$(srcdir)/'`bdd/assignments.c
|
||||
|
||||
bdd/libipset_la-basics.lo: bdd/basics.c
|
||||
@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libipset_la_CFLAGS) $(CFLAGS) -MT bdd/libipset_la-basics.lo -MD -MP -MF bdd/$(DEPDIR)/libipset_la-basics.Tpo -c -o bdd/libipset_la-basics.lo `test -f 'bdd/basics.c' || echo '$(srcdir)/'`bdd/basics.c
|
||||
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) bdd/$(DEPDIR)/libipset_la-basics.Tpo bdd/$(DEPDIR)/libipset_la-basics.Plo
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='bdd/basics.c' object='bdd/libipset_la-basics.lo' libtool=yes @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libipset_la_CFLAGS) $(CFLAGS) -c -o bdd/libipset_la-basics.lo `test -f 'bdd/basics.c' || echo '$(srcdir)/'`bdd/basics.c
|
||||
|
||||
bdd/libipset_la-bdd-iterator.lo: bdd/bdd-iterator.c
|
||||
@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libipset_la_CFLAGS) $(CFLAGS) -MT bdd/libipset_la-bdd-iterator.lo -MD -MP -MF bdd/$(DEPDIR)/libipset_la-bdd-iterator.Tpo -c -o bdd/libipset_la-bdd-iterator.lo `test -f 'bdd/bdd-iterator.c' || echo '$(srcdir)/'`bdd/bdd-iterator.c
|
||||
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) bdd/$(DEPDIR)/libipset_la-bdd-iterator.Tpo bdd/$(DEPDIR)/libipset_la-bdd-iterator.Plo
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='bdd/bdd-iterator.c' object='bdd/libipset_la-bdd-iterator.lo' libtool=yes @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libipset_la_CFLAGS) $(CFLAGS) -c -o bdd/libipset_la-bdd-iterator.lo `test -f 'bdd/bdd-iterator.c' || echo '$(srcdir)/'`bdd/bdd-iterator.c
|
||||
|
||||
bdd/libipset_la-expanded.lo: bdd/expanded.c
|
||||
@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libipset_la_CFLAGS) $(CFLAGS) -MT bdd/libipset_la-expanded.lo -MD -MP -MF bdd/$(DEPDIR)/libipset_la-expanded.Tpo -c -o bdd/libipset_la-expanded.lo `test -f 'bdd/expanded.c' || echo '$(srcdir)/'`bdd/expanded.c
|
||||
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) bdd/$(DEPDIR)/libipset_la-expanded.Tpo bdd/$(DEPDIR)/libipset_la-expanded.Plo
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='bdd/expanded.c' object='bdd/libipset_la-expanded.lo' libtool=yes @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libipset_la_CFLAGS) $(CFLAGS) -c -o bdd/libipset_la-expanded.lo `test -f 'bdd/expanded.c' || echo '$(srcdir)/'`bdd/expanded.c
|
||||
|
||||
bdd/libipset_la-reachable.lo: bdd/reachable.c
|
||||
@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libipset_la_CFLAGS) $(CFLAGS) -MT bdd/libipset_la-reachable.lo -MD -MP -MF bdd/$(DEPDIR)/libipset_la-reachable.Tpo -c -o bdd/libipset_la-reachable.lo `test -f 'bdd/reachable.c' || echo '$(srcdir)/'`bdd/reachable.c
|
||||
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) bdd/$(DEPDIR)/libipset_la-reachable.Tpo bdd/$(DEPDIR)/libipset_la-reachable.Plo
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='bdd/reachable.c' object='bdd/libipset_la-reachable.lo' libtool=yes @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libipset_la_CFLAGS) $(CFLAGS) -c -o bdd/libipset_la-reachable.lo `test -f 'bdd/reachable.c' || echo '$(srcdir)/'`bdd/reachable.c
|
||||
|
||||
bdd/libipset_la-read.lo: bdd/read.c
|
||||
@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libipset_la_CFLAGS) $(CFLAGS) -MT bdd/libipset_la-read.lo -MD -MP -MF bdd/$(DEPDIR)/libipset_la-read.Tpo -c -o bdd/libipset_la-read.lo `test -f 'bdd/read.c' || echo '$(srcdir)/'`bdd/read.c
|
||||
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) bdd/$(DEPDIR)/libipset_la-read.Tpo bdd/$(DEPDIR)/libipset_la-read.Plo
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='bdd/read.c' object='bdd/libipset_la-read.lo' libtool=yes @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libipset_la_CFLAGS) $(CFLAGS) -c -o bdd/libipset_la-read.lo `test -f 'bdd/read.c' || echo '$(srcdir)/'`bdd/read.c
|
||||
|
||||
bdd/libipset_la-write.lo: bdd/write.c
|
||||
@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libipset_la_CFLAGS) $(CFLAGS) -MT bdd/libipset_la-write.lo -MD -MP -MF bdd/$(DEPDIR)/libipset_la-write.Tpo -c -o bdd/libipset_la-write.lo `test -f 'bdd/write.c' || echo '$(srcdir)/'`bdd/write.c
|
||||
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) bdd/$(DEPDIR)/libipset_la-write.Tpo bdd/$(DEPDIR)/libipset_la-write.Plo
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='bdd/write.c' object='bdd/libipset_la-write.lo' libtool=yes @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libipset_la_CFLAGS) $(CFLAGS) -c -o bdd/libipset_la-write.lo `test -f 'bdd/write.c' || echo '$(srcdir)/'`bdd/write.c
|
||||
|
||||
map/libipset_la-allocation.lo: map/allocation.c
|
||||
@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libipset_la_CFLAGS) $(CFLAGS) -MT map/libipset_la-allocation.lo -MD -MP -MF map/$(DEPDIR)/libipset_la-allocation.Tpo -c -o map/libipset_la-allocation.lo `test -f 'map/allocation.c' || echo '$(srcdir)/'`map/allocation.c
|
||||
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) map/$(DEPDIR)/libipset_la-allocation.Tpo map/$(DEPDIR)/libipset_la-allocation.Plo
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='map/allocation.c' object='map/libipset_la-allocation.lo' libtool=yes @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libipset_la_CFLAGS) $(CFLAGS) -c -o map/libipset_la-allocation.lo `test -f 'map/allocation.c' || echo '$(srcdir)/'`map/allocation.c
|
||||
|
||||
map/libipset_la-inspection.lo: map/inspection.c
|
||||
@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libipset_la_CFLAGS) $(CFLAGS) -MT map/libipset_la-inspection.lo -MD -MP -MF map/$(DEPDIR)/libipset_la-inspection.Tpo -c -o map/libipset_la-inspection.lo `test -f 'map/inspection.c' || echo '$(srcdir)/'`map/inspection.c
|
||||
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) map/$(DEPDIR)/libipset_la-inspection.Tpo map/$(DEPDIR)/libipset_la-inspection.Plo
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='map/inspection.c' object='map/libipset_la-inspection.lo' libtool=yes @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libipset_la_CFLAGS) $(CFLAGS) -c -o map/libipset_la-inspection.lo `test -f 'map/inspection.c' || echo '$(srcdir)/'`map/inspection.c
|
||||
|
||||
map/libipset_la-ipv4_map.lo: map/ipv4_map.c
|
||||
@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libipset_la_CFLAGS) $(CFLAGS) -MT map/libipset_la-ipv4_map.lo -MD -MP -MF map/$(DEPDIR)/libipset_la-ipv4_map.Tpo -c -o map/libipset_la-ipv4_map.lo `test -f 'map/ipv4_map.c' || echo '$(srcdir)/'`map/ipv4_map.c
|
||||
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) map/$(DEPDIR)/libipset_la-ipv4_map.Tpo map/$(DEPDIR)/libipset_la-ipv4_map.Plo
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='map/ipv4_map.c' object='map/libipset_la-ipv4_map.lo' libtool=yes @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libipset_la_CFLAGS) $(CFLAGS) -c -o map/libipset_la-ipv4_map.lo `test -f 'map/ipv4_map.c' || echo '$(srcdir)/'`map/ipv4_map.c
|
||||
|
||||
map/libipset_la-ipv6_map.lo: map/ipv6_map.c
|
||||
@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libipset_la_CFLAGS) $(CFLAGS) -MT map/libipset_la-ipv6_map.lo -MD -MP -MF map/$(DEPDIR)/libipset_la-ipv6_map.Tpo -c -o map/libipset_la-ipv6_map.lo `test -f 'map/ipv6_map.c' || echo '$(srcdir)/'`map/ipv6_map.c
|
||||
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) map/$(DEPDIR)/libipset_la-ipv6_map.Tpo map/$(DEPDIR)/libipset_la-ipv6_map.Plo
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='map/ipv6_map.c' object='map/libipset_la-ipv6_map.lo' libtool=yes @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libipset_la_CFLAGS) $(CFLAGS) -c -o map/libipset_la-ipv6_map.lo `test -f 'map/ipv6_map.c' || echo '$(srcdir)/'`map/ipv6_map.c
|
||||
|
||||
map/libipset_la-storage.lo: map/storage.c
|
||||
@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libipset_la_CFLAGS) $(CFLAGS) -MT map/libipset_la-storage.lo -MD -MP -MF map/$(DEPDIR)/libipset_la-storage.Tpo -c -o map/libipset_la-storage.lo `test -f 'map/storage.c' || echo '$(srcdir)/'`map/storage.c
|
||||
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) map/$(DEPDIR)/libipset_la-storage.Tpo map/$(DEPDIR)/libipset_la-storage.Plo
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='map/storage.c' object='map/libipset_la-storage.lo' libtool=yes @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libipset_la_CFLAGS) $(CFLAGS) -c -o map/libipset_la-storage.lo `test -f 'map/storage.c' || echo '$(srcdir)/'`map/storage.c
|
||||
|
||||
set/libipset_la-allocation.lo: set/allocation.c
|
||||
@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libipset_la_CFLAGS) $(CFLAGS) -MT set/libipset_la-allocation.lo -MD -MP -MF set/$(DEPDIR)/libipset_la-allocation.Tpo -c -o set/libipset_la-allocation.lo `test -f 'set/allocation.c' || echo '$(srcdir)/'`set/allocation.c
|
||||
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) set/$(DEPDIR)/libipset_la-allocation.Tpo set/$(DEPDIR)/libipset_la-allocation.Plo
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='set/allocation.c' object='set/libipset_la-allocation.lo' libtool=yes @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libipset_la_CFLAGS) $(CFLAGS) -c -o set/libipset_la-allocation.lo `test -f 'set/allocation.c' || echo '$(srcdir)/'`set/allocation.c
|
||||
|
||||
set/libipset_la-inspection.lo: set/inspection.c
|
||||
@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libipset_la_CFLAGS) $(CFLAGS) -MT set/libipset_la-inspection.lo -MD -MP -MF set/$(DEPDIR)/libipset_la-inspection.Tpo -c -o set/libipset_la-inspection.lo `test -f 'set/inspection.c' || echo '$(srcdir)/'`set/inspection.c
|
||||
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) set/$(DEPDIR)/libipset_la-inspection.Tpo set/$(DEPDIR)/libipset_la-inspection.Plo
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='set/inspection.c' object='set/libipset_la-inspection.lo' libtool=yes @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libipset_la_CFLAGS) $(CFLAGS) -c -o set/libipset_la-inspection.lo `test -f 'set/inspection.c' || echo '$(srcdir)/'`set/inspection.c
|
||||
|
||||
set/libipset_la-ipv4_set.lo: set/ipv4_set.c
|
||||
@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libipset_la_CFLAGS) $(CFLAGS) -MT set/libipset_la-ipv4_set.lo -MD -MP -MF set/$(DEPDIR)/libipset_la-ipv4_set.Tpo -c -o set/libipset_la-ipv4_set.lo `test -f 'set/ipv4_set.c' || echo '$(srcdir)/'`set/ipv4_set.c
|
||||
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) set/$(DEPDIR)/libipset_la-ipv4_set.Tpo set/$(DEPDIR)/libipset_la-ipv4_set.Plo
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='set/ipv4_set.c' object='set/libipset_la-ipv4_set.lo' libtool=yes @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libipset_la_CFLAGS) $(CFLAGS) -c -o set/libipset_la-ipv4_set.lo `test -f 'set/ipv4_set.c' || echo '$(srcdir)/'`set/ipv4_set.c
|
||||
|
||||
set/libipset_la-ipv6_set.lo: set/ipv6_set.c
|
||||
@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libipset_la_CFLAGS) $(CFLAGS) -MT set/libipset_la-ipv6_set.lo -MD -MP -MF set/$(DEPDIR)/libipset_la-ipv6_set.Tpo -c -o set/libipset_la-ipv6_set.lo `test -f 'set/ipv6_set.c' || echo '$(srcdir)/'`set/ipv6_set.c
|
||||
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) set/$(DEPDIR)/libipset_la-ipv6_set.Tpo set/$(DEPDIR)/libipset_la-ipv6_set.Plo
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='set/ipv6_set.c' object='set/libipset_la-ipv6_set.lo' libtool=yes @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libipset_la_CFLAGS) $(CFLAGS) -c -o set/libipset_la-ipv6_set.lo `test -f 'set/ipv6_set.c' || echo '$(srcdir)/'`set/ipv6_set.c
|
||||
|
||||
set/libipset_la-iterator.lo: set/iterator.c
|
||||
@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libipset_la_CFLAGS) $(CFLAGS) -MT set/libipset_la-iterator.lo -MD -MP -MF set/$(DEPDIR)/libipset_la-iterator.Tpo -c -o set/libipset_la-iterator.lo `test -f 'set/iterator.c' || echo '$(srcdir)/'`set/iterator.c
|
||||
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) set/$(DEPDIR)/libipset_la-iterator.Tpo set/$(DEPDIR)/libipset_la-iterator.Plo
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='set/iterator.c' object='set/libipset_la-iterator.lo' libtool=yes @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libipset_la_CFLAGS) $(CFLAGS) -c -o set/libipset_la-iterator.lo `test -f 'set/iterator.c' || echo '$(srcdir)/'`set/iterator.c
|
||||
|
||||
set/libipset_la-storage.lo: set/storage.c
|
||||
@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libipset_la_CFLAGS) $(CFLAGS) -MT set/libipset_la-storage.lo -MD -MP -MF set/$(DEPDIR)/libipset_la-storage.Tpo -c -o set/libipset_la-storage.lo `test -f 'set/storage.c' || echo '$(srcdir)/'`set/storage.c
|
||||
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) set/$(DEPDIR)/libipset_la-storage.Tpo set/$(DEPDIR)/libipset_la-storage.Plo
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='set/storage.c' object='set/libipset_la-storage.lo' libtool=yes @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libipset_la_CFLAGS) $(CFLAGS) -c -o set/libipset_la-storage.lo `test -f 'set/storage.c' || echo '$(srcdir)/'`set/storage.c
|
||||
|
||||
mostlyclean-libtool:
|
||||
-rm -f *.lo
|
||||
|
||||
clean-libtool:
|
||||
-rm -rf .libs _libs
|
||||
-rm -rf bdd/.libs bdd/_libs
|
||||
-rm -rf map/.libs map/_libs
|
||||
-rm -rf set/.libs set/_libs
|
||||
|
||||
ID: $(am__tagged_files)
|
||||
$(am__define_uniq_tagged_files); mkid -fID $$unique
|
||||
tags: tags-am
|
||||
TAGS: tags
|
||||
|
||||
tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
|
||||
set x; \
|
||||
here=`pwd`; \
|
||||
$(am__define_uniq_tagged_files); \
|
||||
shift; \
|
||||
if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
|
||||
test -n "$$unique" || unique=$$empty_fix; \
|
||||
if test $$# -gt 0; then \
|
||||
$(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
|
||||
"$$@" $$unique; \
|
||||
else \
|
||||
$(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
|
||||
$$unique; \
|
||||
fi; \
|
||||
fi
|
||||
ctags: ctags-am
|
||||
|
||||
CTAGS: ctags
|
||||
ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
|
||||
$(am__define_uniq_tagged_files); \
|
||||
test -z "$(CTAGS_ARGS)$$unique" \
|
||||
|| $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
|
||||
$$unique
|
||||
|
||||
GTAGS:
|
||||
here=`$(am__cd) $(top_builddir) && pwd` \
|
||||
&& $(am__cd) $(top_srcdir) \
|
||||
&& gtags -i $(GTAGS_ARGS) "$$here"
|
||||
cscopelist: cscopelist-am
|
||||
|
||||
cscopelist-am: $(am__tagged_files)
|
||||
list='$(am__tagged_files)'; \
|
||||
case "$(srcdir)" in \
|
||||
[\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
|
||||
*) sdir=$(subdir)/$(srcdir) ;; \
|
||||
esac; \
|
||||
for i in $$list; do \
|
||||
if test -f "$$i"; then \
|
||||
echo "$(subdir)/$$i"; \
|
||||
else \
|
||||
echo "$$sdir/$$i"; \
|
||||
fi; \
|
||||
done >> $(top_builddir)/cscope.files
|
||||
|
||||
distclean-tags:
|
||||
-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
|
||||
|
||||
distdir: $(DISTFILES)
|
||||
@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
|
||||
topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
|
||||
list='$(DISTFILES)'; \
|
||||
dist_files=`for file in $$list; do echo $$file; done | \
|
||||
sed -e "s|^$$srcdirstrip/||;t" \
|
||||
-e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
|
||||
case $$dist_files in \
|
||||
*/*) $(MKDIR_P) `echo "$$dist_files" | \
|
||||
sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
|
||||
sort -u` ;; \
|
||||
esac; \
|
||||
for file in $$dist_files; do \
|
||||
if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
|
||||
if test -d $$d/$$file; then \
|
||||
dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
|
||||
if test -d "$(distdir)/$$file"; then \
|
||||
find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
|
||||
fi; \
|
||||
if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
|
||||
cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
|
||||
find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
|
||||
fi; \
|
||||
cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
|
||||
else \
|
||||
test -f "$(distdir)/$$file" \
|
||||
|| cp -p $$d/$$file "$(distdir)/$$file" \
|
||||
|| exit 1; \
|
||||
fi; \
|
||||
done
|
||||
check-am: all-am
|
||||
check: check-am
|
||||
all-am: Makefile $(LTLIBRARIES)
|
||||
installdirs:
|
||||
install: install-am
|
||||
install-exec: install-exec-am
|
||||
install-data: install-data-am
|
||||
uninstall: uninstall-am
|
||||
|
||||
install-am: all-am
|
||||
@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
|
||||
|
||||
installcheck: installcheck-am
|
||||
install-strip:
|
||||
if test -z '$(STRIP)'; then \
|
||||
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
|
||||
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
|
||||
install; \
|
||||
else \
|
||||
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
|
||||
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
|
||||
"INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
|
||||
fi
|
||||
mostlyclean-generic:
|
||||
|
||||
clean-generic:
|
||||
|
||||
distclean-generic:
|
||||
-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
|
||||
-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
|
||||
-rm -f bdd/$(DEPDIR)/$(am__dirstamp)
|
||||
-rm -f bdd/$(am__dirstamp)
|
||||
-rm -f map/$(DEPDIR)/$(am__dirstamp)
|
||||
-rm -f map/$(am__dirstamp)
|
||||
-rm -f set/$(DEPDIR)/$(am__dirstamp)
|
||||
-rm -f set/$(am__dirstamp)
|
||||
|
||||
maintainer-clean-generic:
|
||||
@echo "This command is intended for maintainers to use"
|
||||
@echo "it deletes files that may require special tools to rebuild."
|
||||
clean: clean-am
|
||||
|
||||
clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \
|
||||
mostlyclean-am
|
||||
|
||||
distclean: distclean-am
|
||||
-rm -rf ./$(DEPDIR) bdd/$(DEPDIR) map/$(DEPDIR) set/$(DEPDIR)
|
||||
-rm -f Makefile
|
||||
distclean-am: clean-am distclean-compile distclean-generic \
|
||||
distclean-tags
|
||||
|
||||
dvi: dvi-am
|
||||
|
||||
dvi-am:
|
||||
|
||||
html: html-am
|
||||
|
||||
html-am:
|
||||
|
||||
info: info-am
|
||||
|
||||
info-am:
|
||||
|
||||
install-data-am:
|
||||
|
||||
install-dvi: install-dvi-am
|
||||
|
||||
install-dvi-am:
|
||||
|
||||
install-exec-am:
|
||||
|
||||
install-html: install-html-am
|
||||
|
||||
install-html-am:
|
||||
|
||||
install-info: install-info-am
|
||||
|
||||
install-info-am:
|
||||
|
||||
install-man:
|
||||
|
||||
install-pdf: install-pdf-am
|
||||
|
||||
install-pdf-am:
|
||||
|
||||
install-ps: install-ps-am
|
||||
|
||||
install-ps-am:
|
||||
|
||||
installcheck-am:
|
||||
|
||||
maintainer-clean: maintainer-clean-am
|
||||
-rm -rf ./$(DEPDIR) bdd/$(DEPDIR) map/$(DEPDIR) set/$(DEPDIR)
|
||||
-rm -f Makefile
|
||||
maintainer-clean-am: distclean-am maintainer-clean-generic
|
||||
|
||||
mostlyclean: mostlyclean-am
|
||||
|
||||
mostlyclean-am: mostlyclean-compile mostlyclean-generic \
|
||||
mostlyclean-libtool
|
||||
|
||||
pdf: pdf-am
|
||||
|
||||
pdf-am:
|
||||
|
||||
ps: ps-am
|
||||
|
||||
ps-am:
|
||||
|
||||
uninstall-am:
|
||||
|
||||
.MAKE: install-am install-strip
|
||||
|
||||
.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \
|
||||
clean-libtool clean-noinstLTLIBRARIES cscopelist-am ctags \
|
||||
ctags-am distclean distclean-compile distclean-generic \
|
||||
distclean-libtool distclean-tags distdir dvi dvi-am html \
|
||||
html-am info info-am install install-am install-data \
|
||||
install-data-am install-dvi install-dvi-am install-exec \
|
||||
install-exec-am install-html install-html-am install-info \
|
||||
install-info-am install-man install-pdf install-pdf-am \
|
||||
install-ps install-ps-am install-strip installcheck \
|
||||
installcheck-am installdirs maintainer-clean \
|
||||
maintainer-clean-generic mostlyclean mostlyclean-compile \
|
||||
mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
|
||||
tags tags-am uninstall uninstall-am
|
||||
|
||||
.PRECIOUS: Makefile
|
||||
|
||||
|
||||
# Tell versions [3.59,3.63) of GNU make to not export all variables.
|
||||
# Otherwise a system limit (for SysV at least) may be exceeded.
|
||||
.NOEXPORT:
|
||||
@@ -0,0 +1,10 @@
|
||||
# ipset
|
||||
|
||||
The ipset library provides C data types for storing sets of IP
|
||||
addresses, and maps of IP addresses to integers. It supports both
|
||||
IPv4 and IPv6 addresses. It's implemented using [Binary Decision
|
||||
Diagrams](http://en.wikipedia.org/wiki/Binary_decision_diagram)
|
||||
(BDDs), which (we hypothesize) makes it space efficient for large
|
||||
sets.
|
||||
|
||||
Please see the INSTALL file for installation instructions.
|
||||
@@ -0,0 +1,30 @@
|
||||
# This file is part of libasyncns.
|
||||
#
|
||||
# Copyright 2005-2008 Lennart Poettering
|
||||
#
|
||||
# libasyncns is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser General Public License as
|
||||
# published by the Free Software Foundation, either version 2.1 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# libasyncns is distributed in the hope that it will be useful, but
|
||||
# WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
# Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public
|
||||
# License along with libasyncns. If not, see
|
||||
# <http://www.gnu.org/licenses/>.
|
||||
|
||||
noinst_LTLIBRARIES = libipset.la
|
||||
|
||||
bdd_src = bdd/assignments.c bdd/basics.c bdd/bdd-iterator.c bdd/expanded.c \
|
||||
bdd/reachable.c bdd/read.c bdd/write.c
|
||||
map_src = map/allocation.c map/inspection.c map/ipv4_map.c map/ipv6_map.c \
|
||||
map/storage.c
|
||||
set_src = set/allocation.c set/inspection.c set/ipv4_set.c set/ipv6_set.c \
|
||||
set/iterator.c set/storage.c
|
||||
|
||||
libipset_la_SOURCES = ${bdd_src} ${map_src} ${set_src}
|
||||
|
||||
libipset_la_LDFLAGS = -static
|
||||
Whitespace-only changes.
@@ -0,0 +1,134 @@
|
||||
/* -*- coding: utf-8 -*-
|
||||
* ----------------------------------------------------------------------
|
||||
* Copyright © 2010-2012, RedJack, LLC.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Please see the LICENSE.txt file in this distribution for license
|
||||
* details.
|
||||
* ----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#include <libcork/core.h>
|
||||
|
||||
#include "ipset/bdd/nodes.h"
|
||||
|
||||
|
||||
struct ipset_assignment *
|
||||
ipset_assignment_new()
|
||||
{
|
||||
struct ipset_assignment *assignment = cork_new(struct ipset_assignment);
|
||||
cork_array_init(&assignment->values);
|
||||
return assignment;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ipset_assignment_free(struct ipset_assignment *assignment)
|
||||
{
|
||||
cork_array_done(&assignment->values);
|
||||
free(assignment);
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
ipset_assignment_equal(const struct ipset_assignment *assignment1,
|
||||
const struct ipset_assignment *assignment2)
|
||||
{
|
||||
/* Identical pointers are trivially equal. */
|
||||
if (assignment1 == assignment2) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Otherwise we compare the assignments piecewise up through the end
|
||||
* of the smaller vector. */
|
||||
unsigned int size1 = cork_array_size(&assignment1->values);
|
||||
unsigned int size2 = cork_array_size(&assignment2->values);
|
||||
unsigned int smaller_size = (size1 < size2)? size1: size2;
|
||||
|
||||
unsigned int i;
|
||||
for (i = 0; i < smaller_size; i++) {
|
||||
if (cork_array_at(&assignment1->values, i) !=
|
||||
cork_array_at(&assignment2->values, i)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/* If one of the assignment vectors is longer, any remaining
|
||||
* elements must be indeterminate. */
|
||||
if (size1 > smaller_size) {
|
||||
for (i = smaller_size; i < size1; i++) {
|
||||
if (cork_array_at(&assignment1->values, i) != IPSET_EITHER) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (size2 > smaller_size) {
|
||||
for (i = smaller_size; i < size2; i++) {
|
||||
if (cork_array_at(&assignment2->values, i) != IPSET_EITHER) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* If we make it through all of that, the two assignments are equal. */
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ipset_assignment_cut(struct ipset_assignment *assignment,
|
||||
ipset_variable var)
|
||||
{
|
||||
if (var < cork_array_size(&assignment->values)) {
|
||||
assignment->values.size = var;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ipset_assignment_clear(struct ipset_assignment *assignment)
|
||||
{
|
||||
ipset_assignment_cut(assignment, 0);
|
||||
}
|
||||
|
||||
|
||||
enum ipset_tribool
|
||||
ipset_assignment_get(struct ipset_assignment *assignment, ipset_variable var)
|
||||
{
|
||||
if (var < cork_array_size(&assignment->values)) {
|
||||
/* If the requested variable is in the range of the values
|
||||
* array, return whatever is stored there. */
|
||||
return cork_array_at(&assignment->values, var);
|
||||
} else {
|
||||
/* Variables htat aren't in the values array are always EITHER. */
|
||||
return IPSET_EITHER;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ipset_assignment_set(struct ipset_assignment *assignment,
|
||||
ipset_variable var, enum ipset_tribool value)
|
||||
{
|
||||
/* Ensure that the vector is big enough to hold this variable
|
||||
* assignment, inserting new EITHERs if needed. */
|
||||
if (var >= cork_array_size(&assignment->values)) {
|
||||
unsigned int old_len = cork_array_size(&assignment->values);
|
||||
|
||||
/* Expand the array. */
|
||||
cork_array_ensure_size(&assignment->values, var+1);
|
||||
assignment->values.size = var+1;
|
||||
|
||||
/* Fill in EITHERs in the newly allocated elements. */
|
||||
if (var != old_len) {
|
||||
unsigned int i;
|
||||
for (i = old_len; i < var; i++) {
|
||||
cork_array_at(&assignment->values, i) = IPSET_EITHER;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Assign the desired value. */
|
||||
cork_array_at(&assignment->values, var) = value;
|
||||
}
|
||||
@@ -0,0 +1,467 @@
|
||||
/* -*- coding: utf-8 -*-
|
||||
* ----------------------------------------------------------------------
|
||||
* Copyright © 2010-2013, RedJack, LLC.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Please see the LICENSE.txt file in this distribution for license
|
||||
* details.
|
||||
* ----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <libcork/core.h>
|
||||
|
||||
#include "ipset/bdd/nodes.h"
|
||||
#include "ipset/bits.h"
|
||||
#include "ipset/logging.h"
|
||||
|
||||
|
||||
void
|
||||
ipset_node_fprint(FILE *stream, struct ipset_node *node)
|
||||
{
|
||||
fprintf(stream,
|
||||
"nonterminal(x%u? " IPSET_NODE_ID_FORMAT
|
||||
": " IPSET_NODE_ID_FORMAT ")",
|
||||
node->variable,
|
||||
IPSET_NODE_ID_VALUES(node->high),
|
||||
IPSET_NODE_ID_VALUES(node->low));
|
||||
}
|
||||
|
||||
|
||||
static cork_hash
|
||||
ipset_node_hash(void *user_data, const void *key)
|
||||
{
|
||||
const struct ipset_node *node = key;
|
||||
/* Hash of "ipset_node" */
|
||||
cork_hash hash = 0xf3b7dc44;
|
||||
hash = cork_hash_variable(hash, node->variable);
|
||||
hash = cork_hash_variable(hash, node->low);
|
||||
hash = cork_hash_variable(hash, node->high);
|
||||
return hash;
|
||||
}
|
||||
|
||||
static bool
|
||||
ipset_node_equals(void *user_data, const void *key1, const void *key2)
|
||||
{
|
||||
const struct ipset_node *node1 = key1;
|
||||
const struct ipset_node *node2 = key2;
|
||||
|
||||
if (node1 == node2) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return
|
||||
(node1->variable == node2->variable) &&
|
||||
(node1->low == node2->low) &&
|
||||
(node1->high == node2->high);
|
||||
}
|
||||
|
||||
|
||||
/* The free list in an ipset_node_cache is represented by a
|
||||
* singly-linked list of indices into the chunk array. Since the
|
||||
* ipset_node instance is unused for nodes in the free list, we reuse
|
||||
* the refcount field to store the "next" index. */
|
||||
|
||||
#define IPSET_NULL_INDEX ((ipset_variable) -1)
|
||||
|
||||
struct ipset_node_cache *
|
||||
ipset_node_cache_new()
|
||||
{
|
||||
struct ipset_node_cache *cache = cork_new(struct ipset_node_cache);
|
||||
cork_array_init(&cache->chunks);
|
||||
cache->largest_index = 0;
|
||||
cache->free_list = IPSET_NULL_INDEX;
|
||||
cache->node_cache = cork_hash_table_new(0, 0);
|
||||
cork_hash_table_set_hash
|
||||
(cache->node_cache, (cork_hash_f) ipset_node_hash);
|
||||
cork_hash_table_set_equals
|
||||
(cache->node_cache, (cork_equals_f) ipset_node_equals);
|
||||
return cache;
|
||||
}
|
||||
|
||||
void
|
||||
ipset_node_cache_free(struct ipset_node_cache *cache)
|
||||
{
|
||||
size_t i;
|
||||
for (i = 0; i < cork_array_size(&cache->chunks); i++) {
|
||||
free(cork_array_at(&cache->chunks, i));
|
||||
}
|
||||
cork_array_done(&cache->chunks);
|
||||
cork_hash_table_free(cache->node_cache);
|
||||
free(cache);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the index of a new ipset_node instance.
|
||||
*/
|
||||
static ipset_value
|
||||
ipset_node_cache_alloc_node(struct ipset_node_cache *cache)
|
||||
{
|
||||
if (cache->free_list == IPSET_NULL_INDEX) {
|
||||
/* Nothing in the free list; need to allocate a new node. */
|
||||
ipset_value next_index = cache->largest_index++;
|
||||
ipset_value chunk_index = next_index >> IPSET_BDD_NODE_CACHE_BIT_SIZE;
|
||||
if (chunk_index >= cork_array_size(&cache->chunks)) {
|
||||
/* We've filled up all of the existing chunks, and need to
|
||||
* create a new one. */
|
||||
DEBUG(" (allocating chunk %zu)",
|
||||
cork_array_size(&cache->chunks));
|
||||
struct ipset_node *new_chunk = cork_calloc
|
||||
(IPSET_BDD_NODE_CACHE_SIZE, sizeof(struct ipset_node));
|
||||
cork_array_append(&cache->chunks, new_chunk);
|
||||
}
|
||||
return next_index;
|
||||
} else {
|
||||
/* Reuse a recently freed node. */
|
||||
ipset_value next_index = cache->free_list;
|
||||
struct ipset_node *node =
|
||||
ipset_node_cache_get_nonterminal_by_index(cache, next_index);
|
||||
cache->free_list = node->refcount;
|
||||
return next_index;
|
||||
}
|
||||
}
|
||||
|
||||
ipset_node_id
|
||||
ipset_node_incref(struct ipset_node_cache *cache, ipset_node_id node_id)
|
||||
{
|
||||
if (ipset_node_get_type(node_id) == IPSET_NONTERMINAL_NODE) {
|
||||
struct ipset_node *node =
|
||||
ipset_node_cache_get_nonterminal(cache, node_id);
|
||||
DEBUG(" [incref " IPSET_NODE_ID_FORMAT "]",
|
||||
IPSET_NODE_ID_VALUES(node_id));
|
||||
node->refcount++;
|
||||
}
|
||||
return node_id;
|
||||
}
|
||||
|
||||
void
|
||||
ipset_node_decref(struct ipset_node_cache *cache, ipset_node_id node_id)
|
||||
{
|
||||
if (ipset_node_get_type(node_id) == IPSET_NONTERMINAL_NODE) {
|
||||
struct ipset_node *node =
|
||||
ipset_node_cache_get_nonterminal(cache, node_id);
|
||||
DEBUG(" [decref " IPSET_NODE_ID_FORMAT "]",
|
||||
IPSET_NODE_ID_VALUES(node_id));
|
||||
if (--node->refcount == 0) {
|
||||
DEBUG(" [free " IPSET_NODE_ID_FORMAT "]",
|
||||
IPSET_NODE_ID_VALUES(node_id));
|
||||
ipset_node_decref(cache, node->low);
|
||||
ipset_node_decref(cache, node->high);
|
||||
cork_hash_table_delete(cache->node_cache, node, NULL, NULL);
|
||||
|
||||
/* Add the node to the free list */
|
||||
node->refcount = cache->free_list;
|
||||
cache->free_list = ipset_nonterminal_value(node_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
ipset_node_cache_nodes_equal(const struct ipset_node_cache *cache1,
|
||||
ipset_node_id node_id1,
|
||||
const struct ipset_node_cache *cache2,
|
||||
ipset_node_id node_id2)
|
||||
{
|
||||
struct ipset_node *node1;
|
||||
struct ipset_node *node2;
|
||||
|
||||
if (ipset_node_get_type(node_id1) != ipset_node_get_type(node_id2)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ipset_node_get_type(node_id1) == IPSET_TERMINAL_NODE) {
|
||||
return node_id1 == node_id2;
|
||||
}
|
||||
|
||||
node1 = ipset_node_cache_get_nonterminal(cache1, node_id1);
|
||||
node2 = ipset_node_cache_get_nonterminal(cache2, node_id2);
|
||||
return
|
||||
(node1->variable == node2->variable) &&
|
||||
ipset_node_cache_nodes_equal(cache1, node1->low, cache2, node2->low) &&
|
||||
ipset_node_cache_nodes_equal(cache1, node1->high, cache2, node2->high);
|
||||
}
|
||||
|
||||
ipset_node_id
|
||||
ipset_node_cache_nonterminal(struct ipset_node_cache *cache,
|
||||
ipset_variable variable,
|
||||
ipset_node_id low, ipset_node_id high)
|
||||
{
|
||||
/* Don't allow any nonterminals whose low and high subtrees are the
|
||||
* same, since the nonterminal would be redundant. */
|
||||
if (CORK_UNLIKELY(low == high)) {
|
||||
DEBUG(" [ SKIP nonterminal(x%u? "
|
||||
IPSET_NODE_ID_FORMAT ": " IPSET_NODE_ID_FORMAT ")]",
|
||||
variable, IPSET_NODE_ID_VALUES(high), IPSET_NODE_ID_VALUES(low));
|
||||
ipset_node_decref(cache, high);
|
||||
return low;
|
||||
}
|
||||
|
||||
/* Check to see if there's already a nonterminal with these contents
|
||||
* in the cache. */
|
||||
DEBUG(" [search nonterminal(x%u? "
|
||||
IPSET_NODE_ID_FORMAT ": " IPSET_NODE_ID_FORMAT ")]",
|
||||
variable, IPSET_NODE_ID_VALUES(high), IPSET_NODE_ID_VALUES(low));
|
||||
|
||||
struct ipset_node search_node;
|
||||
search_node.variable = variable;
|
||||
search_node.low = low;
|
||||
search_node.high = high;
|
||||
|
||||
bool is_new;
|
||||
struct cork_hash_table_entry *entry =
|
||||
cork_hash_table_get_or_create
|
||||
(cache->node_cache, &search_node, &is_new);
|
||||
|
||||
if (!is_new) {
|
||||
/* There's already a node with these contents, so return its ID. */
|
||||
ipset_node_id node_id = (uintptr_t) entry->value;
|
||||
DEBUG(" [reuse " IPSET_NODE_ID_FORMAT "]",
|
||||
IPSET_NODE_ID_VALUES(node_id));
|
||||
ipset_node_incref(cache, node_id);
|
||||
ipset_node_decref(cache, low);
|
||||
ipset_node_decref(cache, high);
|
||||
return node_id;
|
||||
} else {
|
||||
/* This node doesn't exist yet. Allocate a permanent copy of
|
||||
* the node, add it to the cache, and then return its ID. */
|
||||
ipset_value new_index = ipset_node_cache_alloc_node(cache);
|
||||
ipset_node_id new_node_id = ipset_nonterminal_node_id(new_index);
|
||||
struct ipset_node *real_node =
|
||||
ipset_node_cache_get_nonterminal_by_index(cache, new_index);
|
||||
real_node->refcount = 1;
|
||||
real_node->variable = variable;
|
||||
real_node->low = low;
|
||||
real_node->high = high;
|
||||
entry->key = real_node;
|
||||
entry->value = (void *) (uintptr_t) new_node_id;
|
||||
DEBUG(" [new " IPSET_NODE_ID_FORMAT "]",
|
||||
IPSET_NODE_ID_VALUES(new_node_id));
|
||||
return new_node_id;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
ipset_bool_array_assignment(const void *user_data, ipset_variable variable)
|
||||
{
|
||||
const bool *bool_array = (const bool *) user_data;
|
||||
return bool_array[variable];
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
ipset_bit_array_assignment(const void *user_data, ipset_variable variable)
|
||||
{
|
||||
return IPSET_BIT_GET(user_data, variable);
|
||||
}
|
||||
|
||||
|
||||
ipset_value
|
||||
ipset_node_evaluate(const struct ipset_node_cache *cache, ipset_node_id node_id,
|
||||
ipset_assignment_func assignment, const void *user_data)
|
||||
{
|
||||
ipset_node_id curr_node_id = node_id;
|
||||
DEBUG("Evaluating BDD node " IPSET_NODE_ID_FORMAT,
|
||||
IPSET_NODE_ID_VALUES(node_id));
|
||||
|
||||
/* As long as the current node is a nonterminal, we have to check
|
||||
* the value of the current variable. */
|
||||
while (ipset_node_get_type(curr_node_id) == IPSET_NONTERMINAL_NODE) {
|
||||
/* We have to look up this variable in the assignment. */
|
||||
struct ipset_node *node =
|
||||
ipset_node_cache_get_nonterminal(cache, curr_node_id);
|
||||
bool this_value = assignment(user_data, node->variable);
|
||||
DEBUG("[%3u] Nonterminal " IPSET_NODE_ID_FORMAT,
|
||||
node->variable, IPSET_NODE_ID_VALUES(curr_node_id));
|
||||
DEBUG("[%3u] x%u = %s",
|
||||
node->variable, node->variable, this_value? "TRUE": "FALSE");
|
||||
|
||||
if (this_value) {
|
||||
/* This node's variable is true in the assignment vector, so
|
||||
* trace down the high subtree. */
|
||||
curr_node_id = node->high;
|
||||
} else {
|
||||
/* This node's variable is false in the assignment vector,
|
||||
* so trace down the low subtree. */
|
||||
curr_node_id = node->low;
|
||||
}
|
||||
}
|
||||
|
||||
/* Once we find a terminal node, we've got the final result. */
|
||||
DEBUG("Evaluated result is %u", ipset_terminal_value(curr_node_id));
|
||||
return ipset_terminal_value(curr_node_id);
|
||||
}
|
||||
|
||||
|
||||
/* A “fake” BDD node given by an assignment. */
|
||||
struct ipset_fake_node {
|
||||
ipset_variable current_var;
|
||||
ipset_variable var_count;
|
||||
ipset_assignment_func assignment;
|
||||
const void *user_data;
|
||||
ipset_value value;
|
||||
};
|
||||
|
||||
/* A fake BDD node representing the terminal 0 value. */
|
||||
static struct ipset_fake_node fake_terminal_0 = { 0, 0, NULL, 0, 0 };
|
||||
|
||||
/* We set elements in a map using the if-then-else (ITE) operator:
|
||||
*
|
||||
* new_set = new_element? new_value: old_set
|
||||
*
|
||||
* The below is a straight copy of the standard trinary APPLY from the BDD
|
||||
* literature, but without the caching of the results. And also with the
|
||||
* wrinkle that the F argument to ITE (i.e., new_element) is given by an
|
||||
* assignment, and not by a BDD node. (This lets us skip constructing the BDD
|
||||
* for the assignment, saving us a few cycles.)
|
||||
*/
|
||||
|
||||
static ipset_node_id
|
||||
ipset_apply_ite(struct ipset_node_cache *cache, struct ipset_fake_node *f,
|
||||
ipset_value g, ipset_node_id h)
|
||||
{
|
||||
ipset_node_id h_low;
|
||||
ipset_node_id h_high;
|
||||
ipset_node_id result_low;
|
||||
ipset_node_id result_high;
|
||||
|
||||
/* If F is a terminal, then we're in one of the following two
|
||||
* cases:
|
||||
*
|
||||
* 1? G: H == G
|
||||
* 0? G: H == H
|
||||
*/
|
||||
if (f->current_var == f->var_count) {
|
||||
ipset_node_id result;
|
||||
DEBUG("[%3u] F is terminal (value %u)", f->current_var, f->value);
|
||||
|
||||
if (f->value == 0) {
|
||||
DEBUG("[%3u] 0? " IPSET_NODE_ID_FORMAT ": " IPSET_NODE_ID_FORMAT
|
||||
" = " IPSET_NODE_ID_FORMAT,
|
||||
f->current_var,
|
||||
IPSET_NODE_ID_VALUES(ipset_terminal_node_id(g)),
|
||||
IPSET_NODE_ID_VALUES(h), IPSET_NODE_ID_VALUES(h));
|
||||
result = ipset_node_incref(cache, h);
|
||||
} else {
|
||||
result = ipset_terminal_node_id(g);
|
||||
DEBUG("[%3u] 1? " IPSET_NODE_ID_FORMAT ": " IPSET_NODE_ID_FORMAT
|
||||
" = " IPSET_NODE_ID_FORMAT,
|
||||
f->current_var, IPSET_NODE_ID_VALUES(result),
|
||||
IPSET_NODE_ID_VALUES(h), IPSET_NODE_ID_VALUES(result));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/* F? G: G == G */
|
||||
if (h == ipset_terminal_node_id(g)) {
|
||||
DEBUG("[%3u] F? " IPSET_NODE_ID_FORMAT ": " IPSET_NODE_ID_FORMAT
|
||||
" = " IPSET_NODE_ID_FORMAT,
|
||||
f->current_var, IPSET_NODE_ID_VALUES(h),
|
||||
IPSET_NODE_ID_VALUES(h), IPSET_NODE_ID_VALUES(h));
|
||||
return h;
|
||||
}
|
||||
|
||||
/* From here to the end of the function, we know that F is a
|
||||
* nonterminal. */
|
||||
DEBUG("[%3u] F is nonterminal", f->current_var);
|
||||
|
||||
/* We're going to do two recursive calls, a “low” one and a “high” one. For
|
||||
* each nonterminal that has the minimum variable number, we use its low and
|
||||
* high pointers in the respective recursive call. For all other
|
||||
* nonterminals, and for all terminals, we use the operand itself. */
|
||||
|
||||
if (ipset_node_get_type(h) == IPSET_NONTERMINAL_NODE) {
|
||||
struct ipset_node *h_node =
|
||||
ipset_node_cache_get_nonterminal(cache, h);
|
||||
|
||||
DEBUG("[%3u] H is nonterminal (variable %u)",
|
||||
f->current_var, h_node->variable);
|
||||
|
||||
if (h_node->variable < f->current_var) {
|
||||
/* var(F) > var(H), so we only recurse down the H branches. */
|
||||
DEBUG("[%3u] Recursing only down H", f->current_var);
|
||||
DEBUG("[%3u] Recursing high", f->current_var);
|
||||
result_high = ipset_apply_ite(cache, f, g, h_node->high);
|
||||
DEBUG("[%3u] Back from high recursion", f->current_var);
|
||||
DEBUG("[%3u] Recursing low", f->current_var);
|
||||
result_low = ipset_apply_ite(cache, f, g, h_node->low);
|
||||
DEBUG("[%3u] Back from low recursion", f->current_var);
|
||||
return ipset_node_cache_nonterminal
|
||||
(cache, h_node->variable, result_low, result_high);
|
||||
} else if (h_node->variable == f->current_var) {
|
||||
/* var(F) == var(H), so we recurse down both branches. */
|
||||
DEBUG("[%3u] Recursing down both F and H", f->current_var);
|
||||
h_low = h_node->low;
|
||||
h_high = h_node->high;
|
||||
} else {
|
||||
/* var(F) < var(H), so we only recurse down the F branches. */
|
||||
DEBUG("[%3u] Recursing only down F", f->current_var);
|
||||
h_low = h;
|
||||
h_high = h;
|
||||
}
|
||||
} else {
|
||||
/* H in nonterminal, so we only recurse down the F branches. */
|
||||
DEBUG("[%3u] H is terminal (value %u)",
|
||||
f->current_var, ipset_terminal_value(h));
|
||||
DEBUG("[%3u] Recursing only down F", f->current_var);
|
||||
h_low = h;
|
||||
h_high = h;
|
||||
}
|
||||
|
||||
/* F is a “fake” nonterminal node, since it comes from our assignment. One
|
||||
* of its branches will be the 0 terminal, and the other will be the fake
|
||||
* nonterminal for the next variable in the assignment. (Which one is low
|
||||
* and which one is high depends on the value of the current variable in the
|
||||
* assignment.) */
|
||||
|
||||
if (f->assignment(f->user_data, f->current_var)) {
|
||||
/* The current variable is set in F. The low branch is terminal 0; the
|
||||
* high branch is the next variable in F. */
|
||||
DEBUG("[%3u] x[%u] is set", f->current_var, f->current_var);
|
||||
DEBUG("[%3u] Recursing high", f->current_var);
|
||||
f->current_var++;
|
||||
result_high = ipset_apply_ite(cache, f, g, h_high);
|
||||
f->current_var--;
|
||||
DEBUG("[%3u] Back from high recursion: " IPSET_NODE_ID_FORMAT,
|
||||
f->current_var, IPSET_NODE_ID_VALUES(result_high));
|
||||
DEBUG("[%3u] Recursing low", f->current_var);
|
||||
fake_terminal_0.current_var = f->var_count;
|
||||
fake_terminal_0.var_count = f->var_count;
|
||||
result_low = ipset_apply_ite(cache, &fake_terminal_0, g, h_low);
|
||||
DEBUG("[%3u] Back from low recursion: " IPSET_NODE_ID_FORMAT,
|
||||
f->current_var, IPSET_NODE_ID_VALUES(result_low));
|
||||
} else {
|
||||
/* The current variable is NOT set in F. The high branch is terminal 0;
|
||||
* the low branch is the next variable in F. */
|
||||
DEBUG("[%3u] x[%u] is NOT set", f->current_var, f->current_var);
|
||||
DEBUG("[%3u] Recursing high", f->current_var);
|
||||
fake_terminal_0.current_var = f->var_count;
|
||||
fake_terminal_0.var_count = f->var_count;
|
||||
result_high = ipset_apply_ite(cache, &fake_terminal_0, g, h_high);
|
||||
DEBUG("[%3u] Back from high recursion: " IPSET_NODE_ID_FORMAT,
|
||||
f->current_var, IPSET_NODE_ID_VALUES(result_high));
|
||||
DEBUG("[%3u] Recursing low", f->current_var);
|
||||
f->current_var++;
|
||||
result_low = ipset_apply_ite(cache, f, g, h_low);
|
||||
f->current_var--;
|
||||
DEBUG("[%3u] Back from low recursion: " IPSET_NODE_ID_FORMAT,
|
||||
f->current_var, IPSET_NODE_ID_VALUES(result_low));
|
||||
}
|
||||
|
||||
return ipset_node_cache_nonterminal
|
||||
(cache, f->current_var, result_low, result_high);
|
||||
}
|
||||
|
||||
ipset_node_id
|
||||
ipset_node_insert(struct ipset_node_cache *cache, ipset_node_id node,
|
||||
ipset_assignment_func assignment, const void *user_data,
|
||||
ipset_variable var_count, ipset_value value)
|
||||
{
|
||||
struct ipset_fake_node f = { 0, var_count, assignment, user_data, 1 };
|
||||
DEBUG("Inserting new element");
|
||||
return ipset_apply_ite(cache, &f, value, node);
|
||||
}
|
||||
@@ -0,0 +1,129 @@
|
||||
/* -*- coding: utf-8 -*-
|
||||
* ----------------------------------------------------------------------
|
||||
* Copyright © 2010-2012, RedJack, LLC.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Please see the LICENSE.txt file in this distribution for license
|
||||
* details.
|
||||
* ----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#include <libcork/core.h>
|
||||
|
||||
#include "ipset/bdd/nodes.h"
|
||||
#include "ipset/logging.h"
|
||||
|
||||
|
||||
/**
|
||||
* Add the given node ID to the node stack, and trace down from it
|
||||
* until we find a terminal node. Assign values to the variables for
|
||||
* each nonterminal that encounter along the way. We check low edges
|
||||
* first, so each new variable we encounter will be assigned FALSE.
|
||||
* (The high edges will be checked eventually by a call to the
|
||||
* ipset_bdd_iterator_advance() function.)
|
||||
*/
|
||||
static void
|
||||
add_node(struct ipset_bdd_iterator *iterator, ipset_node_id node_id)
|
||||
{
|
||||
/* Keep tracing down low edges until we reach a terminal. */
|
||||
while (ipset_node_get_type(node_id) == IPSET_NONTERMINAL_NODE) {
|
||||
/* Add this nonterminal node to the stack, and trace down
|
||||
* further into the tree. We check low edges first, so set the
|
||||
* node's variable to FALSE in the assignment. */
|
||||
struct ipset_node *node =
|
||||
ipset_node_cache_get_nonterminal(iterator->cache, node_id);
|
||||
|
||||
cork_array_append(&iterator->stack, node_id);
|
||||
ipset_assignment_set(iterator->assignment, node->variable, false);
|
||||
|
||||
node_id = node->low;
|
||||
}
|
||||
|
||||
/* Once we find a terminal node, save it away in the iterator result
|
||||
* and return. */
|
||||
iterator->value = ipset_terminal_value(node_id);
|
||||
}
|
||||
|
||||
|
||||
struct ipset_bdd_iterator *
|
||||
ipset_node_iterate(struct ipset_node_cache *cache, ipset_node_id root)
|
||||
{
|
||||
/* First allocate the iterator itself, and all of its contained
|
||||
* fields. */
|
||||
|
||||
struct ipset_bdd_iterator *iterator =
|
||||
cork_new(struct ipset_bdd_iterator);
|
||||
iterator->finished = false;
|
||||
iterator->cache = cache;
|
||||
cork_array_init(&iterator->stack);
|
||||
iterator->assignment = ipset_assignment_new();
|
||||
|
||||
/* Then add the root node to the iterator, tracing down until we
|
||||
* find the first terminal node. */
|
||||
add_node(iterator, root);
|
||||
return iterator;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ipset_bdd_iterator_free(struct ipset_bdd_iterator *iterator)
|
||||
{
|
||||
cork_array_done(&iterator->stack);
|
||||
ipset_assignment_free(iterator->assignment);
|
||||
free(iterator);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ipset_bdd_iterator_advance(struct ipset_bdd_iterator *iterator)
|
||||
{
|
||||
/* If we're already at the end of the iterator, don't do anything. */
|
||||
if (CORK_UNLIKELY(iterator->finished)) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* We look at the last node in the stack. If it's currently
|
||||
* assigned a false value, then we track down its true branch. If
|
||||
* it's got a true branch, then we pop it off and check the next to
|
||||
* last node. */
|
||||
|
||||
DEBUG("Advancing BDD iterator");
|
||||
|
||||
while (cork_array_size(&iterator->stack) > 0) {
|
||||
ipset_node_id last_node_id =
|
||||
cork_array_at
|
||||
(&iterator->stack, cork_array_size(&iterator->stack) - 1);
|
||||
|
||||
struct ipset_node *last_node =
|
||||
ipset_node_cache_get_nonterminal(iterator->cache, last_node_id);
|
||||
|
||||
enum ipset_tribool current_value =
|
||||
ipset_assignment_get(iterator->assignment, last_node->variable);
|
||||
|
||||
/* The current value can't be EITHER, because we definitely
|
||||
* assign a TRUE or FALSE to the variables of the nodes that we
|
||||
* encounter. */
|
||||
if (current_value == IPSET_TRUE) {
|
||||
/* We've checked both outgoing edges for this node, so pop
|
||||
* it off and look at its parent. */
|
||||
iterator->stack.size--;
|
||||
|
||||
/* Before continuing, reset this node's variable to
|
||||
* indeterminate in the assignment. */
|
||||
ipset_assignment_set
|
||||
(iterator->assignment, last_node->variable, IPSET_EITHER);
|
||||
} else {
|
||||
/* We've checked this node's low edge, but not its high
|
||||
* edge. Set the variable to TRUE in the assignment, and
|
||||
* add the high edge's node to the node stack. */
|
||||
ipset_assignment_set
|
||||
(iterator->assignment, last_node->variable, IPSET_TRUE);
|
||||
add_node(iterator, last_node->high);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* If we fall through then we ran out of nodes to check. That means
|
||||
* the iterator is done! */
|
||||
iterator->finished = true;
|
||||
}
|
||||
@@ -0,0 +1,138 @@
|
||||
/* -*- coding: utf-8 -*-
|
||||
* ----------------------------------------------------------------------
|
||||
* Copyright © 2010-2012, RedJack, LLC.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Please see the LICENSE.txt file in this distribution for license
|
||||
* details.
|
||||
* ----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include <libcork/core.h>
|
||||
|
||||
#include "ipset/bdd/nodes.h"
|
||||
#include "ipset/bits.h"
|
||||
#include "ipset/logging.h"
|
||||
|
||||
|
||||
static void
|
||||
initialize(struct ipset_expanded_assignment *exp,
|
||||
const struct ipset_assignment *assignment,
|
||||
ipset_variable var_count)
|
||||
{
|
||||
/* First loop through all of the variables in the assignment vector,
|
||||
* making sure not to go further than the caller requested. */
|
||||
|
||||
ipset_variable last_assignment = cork_array_size(&assignment->values);
|
||||
if (var_count < last_assignment) {
|
||||
last_assignment = var_count;
|
||||
}
|
||||
|
||||
ipset_variable var;
|
||||
for (var = 0; var < last_assignment; var++) {
|
||||
enum ipset_tribool curr_value =
|
||||
cork_array_at(&assignment->values, var);
|
||||
|
||||
if (curr_value == IPSET_EITHER) {
|
||||
/* If this variable is EITHER, start it off as FALSE, and
|
||||
* add it to the eithers list. */
|
||||
DEBUG("Variable %u is EITHER", var);
|
||||
|
||||
IPSET_BIT_SET(exp->values.buf, var, false);
|
||||
cork_array_append(&exp->eithers, var);
|
||||
} else {
|
||||
/* Otherwise set the variable to the same value in the
|
||||
* expanded assignment as it is in the non-expanded one. */
|
||||
|
||||
DEBUG("Variable %u is %s", var, curr_value? "true": "false");
|
||||
IPSET_BIT_SET(exp->values.buf, var, curr_value);
|
||||
}
|
||||
}
|
||||
|
||||
/* If the caller requested more variables than there are in the
|
||||
* assignment vector, add them to the eithers list. */
|
||||
for (var = last_assignment; var < var_count; var++) {
|
||||
DEBUG("Variable %u is implicitly EITHER", var);
|
||||
cork_array_append(&exp->eithers, var);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
struct ipset_expanded_assignment *
|
||||
ipset_assignment_expand(const struct ipset_assignment *assignment,
|
||||
ipset_variable var_count)
|
||||
{
|
||||
/* First allocate the iterator itself, and all of its contained
|
||||
* fields. */
|
||||
|
||||
struct ipset_expanded_assignment *exp;
|
||||
unsigned int values_size = (var_count / 8) + ((var_count % 8) != 0);
|
||||
|
||||
exp = cork_new(struct ipset_expanded_assignment);
|
||||
exp->finished = false;
|
||||
cork_buffer_init(&exp->values);
|
||||
cork_buffer_ensure_size(&exp->values, values_size);
|
||||
memset(exp->values.buf, 0, values_size);
|
||||
cork_array_init(&exp->eithers);
|
||||
|
||||
/* Then initialize the values and eithers fields. */
|
||||
initialize(exp, assignment, var_count);
|
||||
return exp;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ipset_expanded_assignment_free(struct ipset_expanded_assignment *exp)
|
||||
{
|
||||
if (exp == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
cork_buffer_done(&exp->values);
|
||||
cork_array_done(&exp->eithers);
|
||||
free(exp);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ipset_expanded_assignment_advance(struct ipset_expanded_assignment *exp)
|
||||
{
|
||||
/* If we're already at the end of the iterator, don't do anything. */
|
||||
if (CORK_UNLIKELY(exp->finished)) {
|
||||
return;
|
||||
}
|
||||
|
||||
DEBUG("Advancing iterator");
|
||||
|
||||
/* Look at the last EITHER bit in the assignment. If it's 0, then
|
||||
* set it to 1 and return. Otherwise we set it to 0 and carry up to
|
||||
* the previous indeterminate bit. */
|
||||
|
||||
size_t i;
|
||||
for (i = cork_array_size(&exp->eithers); i > 0; i--) {
|
||||
size_t idx = i - 1;
|
||||
ipset_variable either_var = cork_array_at(&exp->eithers, idx);
|
||||
DEBUG("Checking EITHER variable %u", either_var);
|
||||
|
||||
if (IPSET_BIT_GET(exp->values.buf, either_var)) {
|
||||
/* This variable is currently true, so set it back to false
|
||||
* and carry. */
|
||||
DEBUG(" Variable %u is true, changing to false and carrying",
|
||||
either_var);
|
||||
IPSET_BIT_SET(exp->values.buf, either_var, false);
|
||||
} else {
|
||||
/* This variable is currently false, so set it to true and
|
||||
* return. */
|
||||
DEBUG(" Variable %u is false, changing to true",
|
||||
either_var);
|
||||
IPSET_BIT_SET(exp->values.buf, either_var, true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* If we fall through then we've made it through all of the expanded
|
||||
* assignments. */
|
||||
exp->finished = true;
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
/* -*- coding: utf-8 -*-
|
||||
* ----------------------------------------------------------------------
|
||||
* Copyright © 2010-2013, RedJack, LLC.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Please see the LICENSE.txt file in this distribution for license
|
||||
* details.
|
||||
* ----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#include <libcork/core.h>
|
||||
#include <libcork/ds.h>
|
||||
|
||||
#include "ipset/bdd/nodes.h"
|
||||
#include "ipset/logging.h"
|
||||
|
||||
|
||||
size_t
|
||||
ipset_node_reachable_count(const struct ipset_node_cache *cache,
|
||||
ipset_node_id node)
|
||||
{
|
||||
/* Create a set to track when we've visited a given node. */
|
||||
struct cork_hash_table *visited = cork_pointer_hash_table_new(0, 0);
|
||||
|
||||
/* And a queue of nodes to check. */
|
||||
cork_array(ipset_node_id) queue;
|
||||
cork_array_init(&queue);
|
||||
|
||||
if (ipset_node_get_type(node) == IPSET_NONTERMINAL_NODE) {
|
||||
DEBUG("Adding node %u to queue", node);
|
||||
cork_array_append(&queue, node);
|
||||
}
|
||||
|
||||
/* And somewhere to store the result. */
|
||||
size_t node_count = 0;
|
||||
|
||||
/* Check each node in turn. */
|
||||
while (!cork_array_is_empty(&queue)) {
|
||||
ipset_node_id curr = cork_array_at(&queue, --queue.size);
|
||||
|
||||
/* We don't have to do anything if this node is already in the
|
||||
* visited set. */
|
||||
if (cork_hash_table_get(visited, (void *) (uintptr_t) curr) == NULL) {
|
||||
DEBUG("Visiting node %u for the first time", curr);
|
||||
|
||||
/* Add the node to the visited set. */
|
||||
cork_hash_table_put
|
||||
(visited, (void *) (uintptr_t) curr,
|
||||
(void *) (uintptr_t) true, NULL, NULL, NULL);
|
||||
|
||||
/* Increase the node count. */
|
||||
node_count++;
|
||||
|
||||
/* And add the node's nonterminal children to the visit
|
||||
* queue. */
|
||||
struct ipset_node *node =
|
||||
ipset_node_cache_get_nonterminal(cache, curr);
|
||||
|
||||
if (ipset_node_get_type(node->low) == IPSET_NONTERMINAL_NODE) {
|
||||
DEBUG("Adding node %u to queue", node->low);
|
||||
cork_array_append(&queue, node->low);
|
||||
}
|
||||
|
||||
if (ipset_node_get_type(node->high) == IPSET_NONTERMINAL_NODE) {
|
||||
DEBUG("Adding node %u to queue", node->high);
|
||||
cork_array_append(&queue, node->high);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Return the result, freeing everything before we go. */
|
||||
cork_hash_table_free(visited);
|
||||
cork_array_done(&queue);
|
||||
return node_count;
|
||||
}
|
||||
|
||||
|
||||
size_t
|
||||
ipset_node_memory_size(const struct ipset_node_cache *cache,
|
||||
ipset_node_id node)
|
||||
{
|
||||
return ipset_node_reachable_count(cache, node) * sizeof(struct ipset_node);
|
||||
}
|
||||
@@ -0,0 +1,350 @@
|
||||
/* -*- coding: utf-8 -*-
|
||||
* ----------------------------------------------------------------------
|
||||
* Copyright © 2010-2013, RedJack, LLC.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Please see the LICENSE.txt file in this distribution for license
|
||||
* details.
|
||||
* ----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <libcork/core.h>
|
||||
#include <libcork/ds.h>
|
||||
#include <libcork/helpers/errors.h>
|
||||
|
||||
#include "ipset/bdd/nodes.h"
|
||||
#include "ipset/errors.h"
|
||||
#include "ipset/logging.h"
|
||||
|
||||
|
||||
static const char MAGIC_NUMBER[] = "IP set";
|
||||
static const size_t MAGIC_NUMBER_LENGTH = sizeof(MAGIC_NUMBER) - 1;
|
||||
|
||||
|
||||
/**
|
||||
* On disk, we use a different node ID scheme than we do in memory.
|
||||
* Terminal node IDs are non-negative, and are equal to the terminal
|
||||
* value. Nonterminal node IDs are negative, starting with -1.
|
||||
* Nonterminal -1 appears first on disk, then nonterminal -2, and so on.
|
||||
*/
|
||||
|
||||
typedef int serialized_id;
|
||||
|
||||
|
||||
/**
|
||||
* Sets a libcork error based on the contents of errno.
|
||||
*/
|
||||
static void
|
||||
create_errno_error(FILE *stream)
|
||||
{
|
||||
if (ferror(stream)) {
|
||||
cork_error_set(IPSET_ERROR, IPSET_IO_ERROR, "%s", strerror(errno));
|
||||
} else {
|
||||
cork_unknown_error();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Read in a big-endian uint8 from a stream. If we can't read the
|
||||
* integer for some reason, return an error.
|
||||
*/
|
||||
static int
|
||||
read_uint8(FILE *stream, uint8_t *dest)
|
||||
{
|
||||
size_t num_read = fread(dest, sizeof(uint8_t), 1, stream);
|
||||
if (num_read != 1) {
|
||||
create_errno_error(stream);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* for a byte, we don't need to endian-swap */
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Read in a big-endian uint16 from a stream. If we can't read the
|
||||
* integer for some reason, return an error.
|
||||
*/
|
||||
static uint16_t
|
||||
read_uint16(FILE *stream, uint16_t *dest)
|
||||
{
|
||||
size_t num_read = fread(dest, sizeof(uint16_t), 1, stream);
|
||||
if (num_read != 1) {
|
||||
create_errno_error(stream);
|
||||
return -1;
|
||||
}
|
||||
|
||||
CORK_UINT16_BIG_TO_HOST_IN_PLACE(*dest);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Read in a big-endian uint32 from a stream. If we can't read the
|
||||
* integer for some reason, return an error.
|
||||
*/
|
||||
static uint32_t
|
||||
read_uint32(FILE *stream, uint32_t *dest)
|
||||
{
|
||||
size_t num_read = fread(dest, sizeof(uint32_t), 1, stream);
|
||||
if (num_read != 1) {
|
||||
create_errno_error(stream);
|
||||
return -1;
|
||||
}
|
||||
|
||||
CORK_UINT32_BIG_TO_HOST_IN_PLACE(*dest);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Read in a big-endian uint64 from a stream. If we can't read the
|
||||
* integer for some reason, return an error.
|
||||
*/
|
||||
static uint64_t
|
||||
read_uint64(FILE *stream, uint64_t *dest)
|
||||
{
|
||||
size_t num_read = fread(dest, sizeof(uint64_t), 1, stream);
|
||||
if (num_read != 1) {
|
||||
create_errno_error(stream);
|
||||
return -1;
|
||||
}
|
||||
|
||||
CORK_UINT64_BIG_TO_HOST_IN_PLACE(*dest);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* A helper function that verifies that we've read exactly as many bytes
|
||||
* as we should, returning an error otherwise.
|
||||
*/
|
||||
static int
|
||||
verify_cap(size_t bytes_read, size_t cap)
|
||||
{
|
||||
if (bytes_read < cap) {
|
||||
/* There's extra data at the end of the stream. */
|
||||
cork_error_set
|
||||
(IPSET_ERROR, IPSET_PARSE_ERROR,
|
||||
"Malformed set: extra data at end of stream.");
|
||||
return -1;
|
||||
} else if (bytes_read > cap) {
|
||||
/* We read more data than we were supposed to. */
|
||||
cork_error_set
|
||||
(IPSET_ERROR, IPSET_PARSE_ERROR,
|
||||
"Malformed set: read too much data.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* A helper function for reading a version 1 BDD stream.
|
||||
*/
|
||||
static ipset_node_id
|
||||
load_v1(FILE *stream, struct ipset_node_cache *cache)
|
||||
{
|
||||
DEBUG("Stream contains v1 IP set");
|
||||
ipset_node_id result;
|
||||
struct cork_hash_table *cache_ids = cork_pointer_hash_table_new(0, 0);
|
||||
|
||||
/* We've already read in the magic number and version. Next should
|
||||
* be the length of the encoded set. */
|
||||
uint64_t length;
|
||||
DEBUG("Reading encoded length");
|
||||
ei_check(read_uint64(stream, &length));
|
||||
|
||||
/* The length includes the magic number, version number, and the
|
||||
* length field itself. Remove those to get the cap on the
|
||||
* remaining stream. */
|
||||
|
||||
size_t bytes_read = 0;
|
||||
size_t cap = length -
|
||||
MAGIC_NUMBER_LENGTH -
|
||||
sizeof(uint16_t) -
|
||||
sizeof(uint64_t);
|
||||
|
||||
DEBUG("Length cap is %zu bytes.", cap);
|
||||
|
||||
/* Read in the number of nonterminals. */
|
||||
|
||||
uint32_t nonterminal_count;
|
||||
DEBUG("Reading number of nonterminals");
|
||||
ei_check(read_uint32(stream, &nonterminal_count));
|
||||
bytes_read += sizeof(uint32_t);
|
||||
|
||||
/* If there are no nonterminals, then there's only a single terminal
|
||||
* left to read. */
|
||||
|
||||
if (nonterminal_count == 0) {
|
||||
uint32_t value;
|
||||
DEBUG("Reading single terminal value");
|
||||
ei_check(read_uint32(stream, &value));
|
||||
bytes_read += sizeof(uint32_t);
|
||||
|
||||
/* We should have reached the end of the encoded set. */
|
||||
ei_check(verify_cap(bytes_read, cap));
|
||||
|
||||
/* Create a terminal node for this value and return it. */
|
||||
cork_hash_table_free(cache_ids);
|
||||
return ipset_terminal_node_id(value);
|
||||
}
|
||||
|
||||
/* Otherwise, read in each nonterminal. We need to keep track of a
|
||||
* mapping between each nonterminal's ID in the stream (which are
|
||||
* number consecutively from -1), and its ID in the node cache
|
||||
* (which could be anything). */
|
||||
|
||||
size_t i;
|
||||
for (i = 0; i < nonterminal_count; i++) {
|
||||
serialized_id serialized_id = -(i+1);
|
||||
|
||||
/* Each serialized node consists of a variable index, a low
|
||||
* pointer, and a high pointer. */
|
||||
|
||||
uint8_t variable;
|
||||
ei_check(read_uint8(stream, &variable));
|
||||
bytes_read += sizeof(uint8_t);
|
||||
|
||||
int32_t low;
|
||||
ei_check(read_uint32(stream, (uint32_t *) &low));
|
||||
bytes_read += sizeof(int32_t);
|
||||
|
||||
int32_t high;
|
||||
ei_check(read_uint32(stream, (uint32_t *) &high));
|
||||
bytes_read += sizeof(int32_t);
|
||||
|
||||
DEBUG("Read serialized node %d = (x%d? %" PRId32 ": %" PRId32 ")",
|
||||
serialized_id, variable, high, low);
|
||||
|
||||
/* Turn the low pointer into a node ID. If the pointer is >= 0,
|
||||
* it's a terminal value. Otherwise, its a nonterminal ID,
|
||||
* indexing into the serialized nonterminal array.*/
|
||||
|
||||
ipset_node_id low_id;
|
||||
|
||||
if (low >= 0) {
|
||||
low_id = ipset_terminal_node_id(low);
|
||||
} else {
|
||||
/* The file format guarantees that any node reference points
|
||||
* to a node earlier in the serialized array. That means we
|
||||
* can assume that cache_ids has already been filled in for
|
||||
* this node. */
|
||||
|
||||
low_id = (ipset_node_id) (uintptr_t)
|
||||
cork_hash_table_get(cache_ids, (void *) (intptr_t) low);
|
||||
|
||||
DEBUG(" Serialized ID %" PRId32 " is internal ID %u",
|
||||
low, low_id);
|
||||
}
|
||||
|
||||
/* Do the same for the high pointer. */
|
||||
|
||||
ipset_node_id high_id;
|
||||
|
||||
if (high >= 0) {
|
||||
high_id = ipset_terminal_node_id(high);
|
||||
} else {
|
||||
/* The file format guarantees that any node reference points
|
||||
* to a node earlier in the serialized array. That means we
|
||||
* can assume that cache_ids has already been filled in for
|
||||
* this node. */
|
||||
|
||||
high_id = (ipset_node_id) (uintptr_t)
|
||||
cork_hash_table_get(cache_ids, (void *) (intptr_t) high);
|
||||
|
||||
DEBUG(" Serialized ID %" PRId32 " is internal ID %u",
|
||||
high, high_id);
|
||||
}
|
||||
|
||||
/* Create a nonterminal node in the node cache. */
|
||||
result = ipset_node_cache_nonterminal
|
||||
(cache, variable, low_id, high_id);
|
||||
|
||||
DEBUG("Internal node %u = nonterminal(x%d? %u: %u)",
|
||||
result, (int) variable, high_id, low_id);
|
||||
|
||||
/* Remember the internal node ID for this new node, in case any
|
||||
* later serialized nodes point to it. */
|
||||
|
||||
cork_hash_table_put
|
||||
(cache_ids, (void *) (intptr_t) serialized_id,
|
||||
(void *) (uintptr_t) result, NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
/* We should have reached the end of the encoded set. */
|
||||
ei_check(verify_cap(bytes_read, cap));
|
||||
|
||||
/* The last node is the nonterminal for the entire set. */
|
||||
cork_hash_table_free(cache_ids);
|
||||
return result;
|
||||
|
||||
error:
|
||||
/* If there's an error, clean up the objects that we've created
|
||||
* before returning. */
|
||||
|
||||
cork_hash_table_free(cache_ids);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
ipset_node_id
|
||||
ipset_node_cache_load(FILE *stream, struct ipset_node_cache *cache)
|
||||
{
|
||||
size_t bytes_read;
|
||||
|
||||
/* First, read in the magic number from the stream to ensure that
|
||||
* this is an IP set. */
|
||||
|
||||
uint8_t magic[MAGIC_NUMBER_LENGTH];
|
||||
|
||||
DEBUG("Reading IP set magic number");
|
||||
bytes_read = fread(magic, 1, MAGIC_NUMBER_LENGTH, stream);
|
||||
|
||||
if (ferror(stream)) {
|
||||
create_errno_error(stream);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (bytes_read != MAGIC_NUMBER_LENGTH) {
|
||||
/* We reached EOF before reading the entire magic number. */
|
||||
cork_error_set
|
||||
(IPSET_ERROR, IPSET_PARSE_ERROR,
|
||||
"Unexpected end of file");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (memcmp(magic, MAGIC_NUMBER, MAGIC_NUMBER_LENGTH) != 0) {
|
||||
/* The magic number doesn't match, so this isn't a BDD. */
|
||||
cork_error_set
|
||||
(IPSET_ERROR, IPSET_PARSE_ERROR,
|
||||
"Magic number doesn't match; this isn't an IP set.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Read in the version number and dispatch to the right reading
|
||||
* function. */
|
||||
|
||||
uint16_t version;
|
||||
DEBUG("Reading IP set version");
|
||||
xi_check(0, read_uint16(stream, &version));
|
||||
|
||||
switch (version) {
|
||||
case 0x0001:
|
||||
return load_v1(stream, cache);
|
||||
|
||||
default:
|
||||
/* We don't know how to read this version number. */
|
||||
cork_error_set
|
||||
(IPSET_ERROR, IPSET_PARSE_ERROR,
|
||||
"Unknown version number %" PRIu16, version);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,557 @@
|
||||
/* -*- coding: utf-8 -*-
|
||||
* ----------------------------------------------------------------------
|
||||
* Copyright © 2010-2013, RedJack, LLC.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Please see the LICENSE.txt file in this distribution for license
|
||||
* details.
|
||||
* ----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#include <libcork/core.h>
|
||||
#include <libcork/helpers/errors.h>
|
||||
|
||||
#include "ipset/bdd/nodes.h"
|
||||
#include "ipset/logging.h"
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
* Generic saving logic
|
||||
*/
|
||||
|
||||
/**
|
||||
* On disk, we use a different node ID scheme than we do in memory.
|
||||
* Terminal node IDs are non-negative, and are equal to the terminal
|
||||
* value. Nonterminal node IDs are negative, starting with -1.
|
||||
* Nonterminal -1 appears first on disk, then nonterminal -2, and so
|
||||
* on.
|
||||
*/
|
||||
|
||||
typedef int serialized_id;
|
||||
|
||||
|
||||
/* forward declaration */
|
||||
struct save_data;
|
||||
|
||||
|
||||
/**
|
||||
* A callback that outputs any necessary header. Should return an int
|
||||
* status code indicating whether the write was successful.
|
||||
*/
|
||||
|
||||
typedef int
|
||||
(*write_header_func)(struct save_data *save_data,
|
||||
struct ipset_node_cache *cache,
|
||||
ipset_node_id root);
|
||||
|
||||
|
||||
/**
|
||||
* A callback that outputs any necessary footer. Should return an int
|
||||
* status code indicating whether the write was successful.
|
||||
*/
|
||||
|
||||
typedef int
|
||||
(*write_footer_func)(struct save_data *save_data,
|
||||
struct ipset_node_cache *cache,
|
||||
ipset_node_id root);
|
||||
|
||||
|
||||
/**
|
||||
* A callback that actually outputs a terminal node to disk. Should
|
||||
* return an int status code indicating whether the write was successful.
|
||||
*/
|
||||
|
||||
typedef int
|
||||
(*write_terminal_func)(struct save_data *save_data,
|
||||
ipset_value terminal_value);
|
||||
|
||||
|
||||
/**
|
||||
* A callback that actually outputs a nonterminal node to disk.
|
||||
* Should return an int status code indicating whether the write was
|
||||
* successful.
|
||||
*/
|
||||
|
||||
typedef int
|
||||
(*write_nonterminal_func)(struct save_data *save_data,
|
||||
serialized_id serialized_node,
|
||||
ipset_variable variable,
|
||||
serialized_id serialized_low,
|
||||
serialized_id serialized_high);
|
||||
|
||||
|
||||
/**
|
||||
* A helper struct containing all of the persistent data items needed
|
||||
* during the execution of a save.
|
||||
*/
|
||||
|
||||
struct save_data {
|
||||
/* The node cache that we're saving nodes from. */
|
||||
struct ipset_node_cache *cache;
|
||||
|
||||
/* The output stream to save the data to. */
|
||||
struct cork_stream_consumer *stream;
|
||||
|
||||
/* The cache of serialized IDs for any nonterminals that we've
|
||||
* encountered so far. */
|
||||
struct cork_hash_table *serialized_ids;
|
||||
|
||||
/* The serialized ID to use for the next nonterminal that we
|
||||
* encounter. */
|
||||
serialized_id next_serialized_id;
|
||||
|
||||
/* The callback used to write the file header to the stream. */
|
||||
write_header_func write_header;
|
||||
|
||||
/* The callback used to write the file footer to the stream. */
|
||||
write_footer_func write_footer;
|
||||
|
||||
/* The callback used to write terminals to the stream. */
|
||||
write_terminal_func write_terminal;
|
||||
|
||||
/* The callback used to write nonterminals to the stream. */
|
||||
write_nonterminal_func write_nonterminal;
|
||||
|
||||
/* A pointer to any additional data needed by the callbacks. */
|
||||
void *user_data;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* A helper function for ipset_node_save(). Outputs a nonterminal
|
||||
* node in a BDD tree, if we haven't done so already. Ensures that
|
||||
* the children of the nonterminal are output before the nonterminal
|
||||
* is. Returns the serialized ID of this node.
|
||||
*/
|
||||
|
||||
static int
|
||||
save_visit_node(struct save_data *save_data,
|
||||
ipset_node_id node_id, serialized_id *dest)
|
||||
{
|
||||
/* Check whether we've already serialized this node. */
|
||||
|
||||
struct cork_hash_table_entry *entry;
|
||||
bool is_new;
|
||||
entry = cork_hash_table_get_or_create
|
||||
(save_data->serialized_ids, (void *) (uintptr_t) node_id, &is_new);
|
||||
|
||||
if (!is_new) {
|
||||
*dest = (intptr_t) entry->value;
|
||||
return 0;
|
||||
} else {
|
||||
if (ipset_node_get_type(node_id) == IPSET_TERMINAL_NODE) {
|
||||
/* For terminals, there isn't really anything to do — we
|
||||
* just output the terminal node and use its value as the
|
||||
* serialized ID. */
|
||||
|
||||
ipset_value value = ipset_terminal_value(node_id);
|
||||
|
||||
DEBUG("Writing terminal(%d)", value);
|
||||
rii_check(save_data->write_terminal(save_data, value));
|
||||
entry->value = (void *) (intptr_t) value;
|
||||
*dest = value;
|
||||
return 0;
|
||||
} else {
|
||||
/* For nonterminals, we drill down into the node's children
|
||||
* first, then output the nonterminal node. */
|
||||
|
||||
struct ipset_node *node =
|
||||
ipset_node_cache_get_nonterminal(save_data->cache, node_id);
|
||||
DEBUG("Visiting node %u nonterminal(x%u? %u: %u)",
|
||||
node_id, node->variable, node->high, node->low);
|
||||
|
||||
/* Output the node's nonterminal children before we output
|
||||
* the node itself. */
|
||||
serialized_id serialized_low;
|
||||
serialized_id serialized_high;
|
||||
rii_check(save_visit_node(save_data, node->low, &serialized_low));
|
||||
rii_check(save_visit_node(save_data, node->high, &serialized_high));
|
||||
|
||||
/* Output the nonterminal */
|
||||
serialized_id result = save_data->next_serialized_id--;
|
||||
DEBUG("Writing node %u as serialized node %d = (x%u? %d: %d)",
|
||||
node_id, result,
|
||||
node->variable, serialized_low, serialized_high);
|
||||
|
||||
entry->value = (void *) (intptr_t) result;
|
||||
*dest = result;
|
||||
return save_data->write_nonterminal
|
||||
(save_data, result, node->variable,
|
||||
serialized_low, serialized_high);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
save_bdd(struct save_data *save_data,
|
||||
struct ipset_node_cache *cache, ipset_node_id root)
|
||||
{
|
||||
/* First, output the file header. */
|
||||
|
||||
DEBUG("Writing file header");
|
||||
rii_check(save_data->write_header(save_data, cache, root));
|
||||
|
||||
/* The serialized node IDs are different than the in-memory node
|
||||
* IDs. This means that, for our nonterminal nodes, we need a
|
||||
* mapping from internal node ID to serialized node ID. */
|
||||
|
||||
DEBUG("Creating file caches");
|
||||
save_data->serialized_ids = cork_pointer_hash_table_new(0, 0);
|
||||
save_data->next_serialized_id = -1;
|
||||
|
||||
/* Trace down through the BDD tree, outputting each terminal and
|
||||
* nonterminal node as they're encountered. */
|
||||
|
||||
DEBUG("Writing nodes");
|
||||
|
||||
serialized_id last_serialized_id;
|
||||
ei_check(save_visit_node(save_data, root, &last_serialized_id));
|
||||
|
||||
/* Finally, output the file footer and cleanup. */
|
||||
|
||||
DEBUG("Writing file footer");
|
||||
ei_check(save_data->write_footer(save_data, cache, root));
|
||||
|
||||
DEBUG("Freeing file caches");
|
||||
cork_hash_table_free(save_data->serialized_ids);
|
||||
return 0;
|
||||
|
||||
error:
|
||||
/* If there's an error, clean up the objects that we've created
|
||||
* before returning. */
|
||||
cork_hash_table_free(save_data->serialized_ids);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
* Helper functions
|
||||
*/
|
||||
|
||||
/**
|
||||
* Write a NUL-terminated string to a stream. If we can't write the
|
||||
* string for some reason, return an error.
|
||||
*/
|
||||
static int
|
||||
write_string(struct cork_stream_consumer *stream, const char *str)
|
||||
{
|
||||
size_t len = strlen(str);
|
||||
return cork_stream_consumer_data(stream, str, len, false);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Write a big-endian uint8 to a stream. If we can't write the
|
||||
* integer for some reason, return an error.
|
||||
*/
|
||||
static int
|
||||
write_uint8(struct cork_stream_consumer *stream, uint8_t val)
|
||||
{
|
||||
/* for a byte, we don't need to endian-swap */
|
||||
return cork_stream_consumer_data(stream, &val, sizeof(uint8_t), false);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Write a big-endian uint16 to a stream. If we can't write the
|
||||
* integer for some reason, return an error.
|
||||
*/
|
||||
static int
|
||||
write_uint16(struct cork_stream_consumer *stream, uint16_t val)
|
||||
{
|
||||
CORK_UINT16_HOST_TO_BIG_IN_PLACE(val);
|
||||
return cork_stream_consumer_data(stream, &val, sizeof(uint16_t), false);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Write a big-endian uint32 to a stream. If we can't write the
|
||||
* integer for some reason, return an error.
|
||||
*/
|
||||
|
||||
static int
|
||||
write_uint32(struct cork_stream_consumer *stream, uint32_t val)
|
||||
{
|
||||
CORK_UINT32_HOST_TO_BIG_IN_PLACE(val);
|
||||
return cork_stream_consumer_data(stream, &val, sizeof(uint32_t), false);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Write a big-endian uint64 to a stream. If we can't write the
|
||||
* integer for some reason, return an error.
|
||||
*/
|
||||
|
||||
static int
|
||||
write_uint64(struct cork_stream_consumer *stream, uint64_t val)
|
||||
{
|
||||
CORK_UINT64_HOST_TO_BIG_IN_PLACE(val);
|
||||
return cork_stream_consumer_data(stream, &val, sizeof(uint64_t), false);
|
||||
}
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
* V1 BDD file
|
||||
*/
|
||||
|
||||
static const char MAGIC_NUMBER[] = "IP set";
|
||||
static const size_t MAGIC_NUMBER_LENGTH = sizeof(MAGIC_NUMBER) - 1;
|
||||
|
||||
|
||||
static int
|
||||
write_header_v1(struct save_data *save_data,
|
||||
struct ipset_node_cache *cache, ipset_node_id root)
|
||||
{
|
||||
/* Output the magic number for an IP set, and the file format
|
||||
* version that we're going to write. */
|
||||
rii_check(cork_stream_consumer_data(save_data->stream, NULL, 0, true));
|
||||
rii_check(write_string(save_data->stream, MAGIC_NUMBER));
|
||||
rii_check(write_uint16(save_data->stream, 0x0001));
|
||||
|
||||
/* Determine how many reachable nodes there are, to calculate the
|
||||
* size of the set. */
|
||||
size_t nonterminal_count = ipset_node_reachable_count(cache, root);
|
||||
size_t set_size =
|
||||
MAGIC_NUMBER_LENGTH + /* magic number */
|
||||
sizeof(uint16_t) + /* version number */
|
||||
sizeof(uint64_t) + /* length of set */
|
||||
sizeof(uint32_t) + /* number of nonterminals */
|
||||
(nonterminal_count * /* for each nonterminal: */
|
||||
(sizeof(uint8_t) + /* variable number */
|
||||
sizeof(uint32_t) + /* low pointer */
|
||||
sizeof(uint32_t) /* high pointer */
|
||||
));
|
||||
|
||||
/* If the root is a terminal, we need to add 4 bytes to the set
|
||||
* size, for storing the terminal value. */
|
||||
if (ipset_node_get_type(root) == IPSET_TERMINAL_NODE) {
|
||||
set_size += sizeof(uint32_t);
|
||||
}
|
||||
|
||||
rii_check(write_uint64(save_data->stream, set_size));
|
||||
rii_check(write_uint32(save_data->stream, nonterminal_count));
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
write_footer_v1(struct save_data *save_data,
|
||||
struct ipset_node_cache *cache, ipset_node_id root)
|
||||
{
|
||||
/* If the root is a terminal node, then we output the terminal value
|
||||
* in place of the (nonexistent) list of nonterminal nodes. */
|
||||
|
||||
if (ipset_node_get_type(root) == IPSET_TERMINAL_NODE) {
|
||||
ipset_value value = ipset_terminal_value(root);
|
||||
return write_uint32(save_data->stream, value);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
write_terminal_v1(struct save_data *save_data, ipset_value terminal_value)
|
||||
{
|
||||
/* We don't have to write anything out for a terminal in a V1 file,
|
||||
* since the terminal's value will be encoded into the node ID
|
||||
* wherever it's used. */
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
write_nonterminal_v1(struct save_data *save_data,
|
||||
serialized_id serialized_node,
|
||||
ipset_variable variable,
|
||||
serialized_id serialized_low,
|
||||
serialized_id serialized_high)
|
||||
{
|
||||
rii_check(write_uint8(save_data->stream, variable));
|
||||
rii_check(write_uint32(save_data->stream, serialized_low));
|
||||
rii_check(write_uint32(save_data->stream, serialized_high));
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
ipset_node_cache_save(struct cork_stream_consumer *stream, struct ipset_node_cache *cache,
|
||||
ipset_node_id node)
|
||||
{
|
||||
struct save_data save_data;
|
||||
save_data.cache = cache;
|
||||
save_data.stream = stream;
|
||||
save_data.write_header = write_header_v1;
|
||||
save_data.write_footer = write_footer_v1;
|
||||
save_data.write_terminal = write_terminal_v1;
|
||||
save_data.write_nonterminal = write_nonterminal_v1;
|
||||
return save_bdd(&save_data, cache, node);
|
||||
}
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
* GraphViz dot file
|
||||
*/
|
||||
|
||||
static const char *GRAPHVIZ_HEADER =
|
||||
"strict digraph bdd {\n";
|
||||
|
||||
static const char *GRAPHVIZ_FOOTER =
|
||||
"}\n";
|
||||
|
||||
|
||||
struct dot_data {
|
||||
/* The terminal value to leave out of the dot file. This should be
|
||||
* the default value of the set or map. */
|
||||
ipset_value default_value;
|
||||
|
||||
/* A scratch buffer */
|
||||
struct cork_buffer scratch;
|
||||
};
|
||||
|
||||
|
||||
static int
|
||||
write_header_dot(struct save_data *save_data,
|
||||
struct ipset_node_cache *cache, ipset_node_id root)
|
||||
{
|
||||
/* Output the opening clause of the GraphViz script. */
|
||||
rii_check(cork_stream_consumer_data(save_data->stream, NULL, 0, true));
|
||||
return write_string(save_data->stream, GRAPHVIZ_HEADER);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
write_footer_dot(struct save_data *save_data,
|
||||
struct ipset_node_cache *cache, ipset_node_id root)
|
||||
{
|
||||
/* Output the closing clause of the GraphViz script. */
|
||||
return write_string(save_data->stream, GRAPHVIZ_FOOTER);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
write_terminal_dot(struct save_data *save_data, ipset_value terminal_value)
|
||||
{
|
||||
struct dot_data *dot_data = save_data->user_data;
|
||||
|
||||
/* If this terminal has the default value, skip it. */
|
||||
if (terminal_value == dot_data->default_value) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Output a node for the terminal value. */
|
||||
cork_buffer_printf
|
||||
(&dot_data->scratch,
|
||||
" t%d [shape=box, label=%d];\n",
|
||||
terminal_value, terminal_value);
|
||||
return write_string(save_data->stream, dot_data->scratch.buf);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
write_nonterminal_dot(struct save_data *save_data,
|
||||
serialized_id serialized_node,
|
||||
ipset_variable variable,
|
||||
serialized_id serialized_low,
|
||||
serialized_id serialized_high)
|
||||
{
|
||||
struct dot_data *dot_data = save_data->user_data;
|
||||
|
||||
/* Include a node for the nonterminal value. */
|
||||
cork_buffer_printf
|
||||
(&dot_data->scratch,
|
||||
" n%d [shape=circle,label=%u];\n",
|
||||
(-serialized_node), variable);
|
||||
|
||||
/* Include an edge for the low pointer. */
|
||||
if (serialized_low < 0) {
|
||||
/* The low pointer is a nonterminal. */
|
||||
cork_buffer_append_printf
|
||||
(&dot_data->scratch,
|
||||
" n%d -> n%d",
|
||||
(-serialized_node), (-serialized_low));
|
||||
} else {
|
||||
/* The low pointer is a terminal. */
|
||||
ipset_value low_value = (ipset_value) serialized_low;
|
||||
|
||||
if (low_value == dot_data->default_value) {
|
||||
/* The terminal is the default value, so instead of a real
|
||||
* terminal, connect this pointer to a dummy circle node. */
|
||||
cork_buffer_append_printf
|
||||
(&dot_data->scratch,
|
||||
" low%d [shape=circle,label=\"\"]\n"
|
||||
" n%d -> low%d",
|
||||
(-serialized_node), (-serialized_node), (-serialized_node));
|
||||
} else {
|
||||
/* The terminal isn't a default, so go ahead and output it. */
|
||||
cork_buffer_append_printf
|
||||
(&dot_data->scratch,
|
||||
" n%d -> t%d",
|
||||
(-serialized_node), serialized_low);
|
||||
}
|
||||
}
|
||||
|
||||
cork_buffer_append_printf
|
||||
(&dot_data->scratch, " [style=dashed,color=red]\n");
|
||||
|
||||
/* Include an edge for the high pointer. */
|
||||
if (serialized_high < 0) {
|
||||
/* The high pointer is a nonterminal. */
|
||||
cork_buffer_append_printf
|
||||
(&dot_data->scratch,
|
||||
" n%d -> n%d",
|
||||
(-serialized_node), (-serialized_high));
|
||||
} else {
|
||||
/* The high pointer is a terminal. */
|
||||
ipset_value high_value = (ipset_value) serialized_high;
|
||||
|
||||
if (high_value == dot_data->default_value) {
|
||||
/* The terminal is the default value, so instead of a real
|
||||
* terminal, connect this pointer to a dummy circle node. */
|
||||
cork_buffer_append_printf
|
||||
(&dot_data->scratch,
|
||||
" high%d "
|
||||
"[shape=circle,"
|
||||
"fixedsize=true,"
|
||||
"height=0.25,"
|
||||
"width=0.25,"
|
||||
"label=\"\"]\n"
|
||||
" n%d -> high%d",
|
||||
(-serialized_node), (-serialized_node), (-serialized_node));
|
||||
} else {
|
||||
/* The terminal isn't a default, so go ahead and output it. */
|
||||
cork_buffer_append_printf
|
||||
(&dot_data->scratch,
|
||||
" n%d -> t%d",
|
||||
(-serialized_node), serialized_high);
|
||||
}
|
||||
}
|
||||
|
||||
cork_buffer_append_printf
|
||||
(&dot_data->scratch, " [style=solid,color=black]\n");
|
||||
|
||||
/* Output the clauses to the stream. */
|
||||
return write_string(save_data->stream, dot_data->scratch.buf);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
ipset_node_cache_save_dot(struct cork_stream_consumer *stream,
|
||||
struct ipset_node_cache *cache, ipset_node_id node)
|
||||
{
|
||||
struct dot_data dot_data = {
|
||||
0, /* default value */
|
||||
{NULL, 0, 0}
|
||||
};
|
||||
|
||||
struct save_data save_data;
|
||||
save_data.cache = cache;
|
||||
save_data.stream = stream;
|
||||
save_data.write_header = write_header_dot;
|
||||
save_data.write_footer = write_footer_dot;
|
||||
save_data.write_terminal = write_terminal_dot;
|
||||
save_data.write_nonterminal = write_nonterminal_dot;
|
||||
save_data.user_data = &dot_data;
|
||||
return save_bdd(&save_data, cache, node);
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# ----------------------------------------------------------------------
|
||||
# Copyright © 2015, RedJack, LLC.
|
||||
# All rights reserved.
|
||||
#
|
||||
# Please see the COPYING file in this distribution for license details.
|
||||
# ----------------------------------------------------------------------
|
||||
|
||||
|
||||
#-----------------------------------------------------------------------
|
||||
# Library, with options to build both shared and static versions
|
||||
|
||||
function(target_add_static_libraries TARGET_NAME LIBRARIES LOCAL_LIBRARIES)
|
||||
foreach(lib ${LIBRARIES})
|
||||
string(REPLACE "-" "_" lib ${lib})
|
||||
string(TOUPPER ${lib} upperlib)
|
||||
target_link_libraries(
|
||||
${TARGET_NAME}
|
||||
${${upperlib}_STATIC_LDFLAGS}
|
||||
)
|
||||
endforeach(lib)
|
||||
foreach(lib ${LOCAL_LIBRARIES})
|
||||
target_link_libraries(${TARGET_NAME} ${lib})
|
||||
endforeach(lib)
|
||||
endfunction(target_add_static_libraries)
|
||||
|
||||
set_property(GLOBAL PROPERTY ALL_LOCAL_LIBRARIES "")
|
||||
|
||||
function(add_c_library __TARGET_NAME)
|
||||
set(options)
|
||||
set(one_args OUTPUT_NAME PKGCONFIG_NAME VERSION)
|
||||
set(multi_args LIBRARIES LOCAL_LIBRARIES SOURCES)
|
||||
cmake_parse_arguments(_ "${options}" "${one_args}" "${multi_args}" ${ARGN})
|
||||
|
||||
if (__VERSION MATCHES "^([0-9]+)\\.([0-9]+)\\.([0-9]+)(-dev)?$")
|
||||
set(__VERSION_CURRENT "${CMAKE_MATCH_1}")
|
||||
set(__VERSION_REVISION "${CMAKE_MATCH_2}")
|
||||
set(__VERSION_AGE "${CMAKE_MATCH_3}")
|
||||
else (__VERSION MATCHES "^([0-9]+)\\.([0-9]+)\\.([0-9]+)(-dev)?$")
|
||||
message(FATAL_ERROR "Invalid library version number: ${__VERSION}")
|
||||
endif (__VERSION MATCHES "^([0-9]+)\\.([0-9]+)\\.([0-9]+)(-dev)?$")
|
||||
|
||||
math(EXPR __SOVERSION "${__VERSION_CURRENT} - ${__VERSION_AGE}")
|
||||
|
||||
get_property(ALL_LOCAL_LIBRARIES GLOBAL PROPERTY ALL_LOCAL_LIBRARIES)
|
||||
list(APPEND ALL_LOCAL_LIBRARIES ${__TARGET_NAME})
|
||||
set_property(GLOBAL PROPERTY ALL_LOCAL_LIBRARIES "${ALL_LOCAL_LIBRARIES}")
|
||||
|
||||
include_directories(
|
||||
${PROJECT_SOURCE_DIR}/include
|
||||
${PROJECT_BINARY_DIR}/include
|
||||
)
|
||||
add_library(${__TARGET_NAME} STATIC ${__SOURCES})
|
||||
|
||||
set_target_properties(
|
||||
${__TARGET_NAME} PROPERTIES
|
||||
OUTPUT_NAME ${__OUTPUT_NAME}
|
||||
CLEAN_DIRECT_OUTPUT 1
|
||||
)
|
||||
|
||||
target_include_directories(
|
||||
${__TARGET_NAME} PUBLIC
|
||||
${CMAKE_SOURCE_DIR}/include
|
||||
${CMAKE_BINARY_DIR}/include
|
||||
)
|
||||
|
||||
|
||||
target_add_static_libraries(
|
||||
${__TARGET_NAME}
|
||||
"${__LIBRARIES}"
|
||||
"${__LOCAL_LIBRARIES}"
|
||||
)
|
||||
endfunction(add_c_library)
|
||||
@@ -0,0 +1,21 @@
|
||||
/* -*- coding: utf-8 -*-
|
||||
* ----------------------------------------------------------------------
|
||||
* Copyright © 2009-2012, RedJack, LLC.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Please see the LICENSE.txt file in this distribution for license
|
||||
* details.
|
||||
* ----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#include <libcork/core.h>
|
||||
|
||||
#include "ipset/bdd/nodes.h"
|
||||
#include "ipset/ipset.h"
|
||||
|
||||
|
||||
int
|
||||
ipset_init_library()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,536 @@
|
||||
/* -*- coding: utf-8 -*-
|
||||
* ----------------------------------------------------------------------
|
||||
* Copyright © 2010-2013, RedJack, LLC.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Please see the LICENSE.txt file in this distribution for license
|
||||
* details.
|
||||
* ----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#ifndef IPSET_BDD_NODES_H
|
||||
#define IPSET_BDD_NODES_H
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <libcork/core.h>
|
||||
#include <libcork/ds.h>
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
* Preliminaries
|
||||
*/
|
||||
|
||||
/**
|
||||
* Each variable in a BDD is referred to by number.
|
||||
*/
|
||||
typedef unsigned int ipset_variable;
|
||||
|
||||
|
||||
/**
|
||||
* Each BDD terminal represents an integer value. The integer must be
|
||||
* non-negative, but must be within the range of the <i>signed</i>
|
||||
* integer type.
|
||||
*/
|
||||
typedef unsigned int ipset_value;
|
||||
|
||||
|
||||
/**
|
||||
* An identifier for each distinct node in a BDD.
|
||||
*
|
||||
* Internal implementation note. Since pointers are aligned to at
|
||||
* least two bytes, the ID of a terminal node has its LSB set to 1,
|
||||
* and has the terminal value stored in the remaining bits. The ID of
|
||||
* a nonterminal node is simply a pointer to the node struct.
|
||||
*/
|
||||
typedef unsigned int ipset_node_id;
|
||||
|
||||
|
||||
/**
|
||||
* Nodes can either be terminal or nonterminal.
|
||||
*/
|
||||
enum ipset_node_type {
|
||||
IPSET_NONTERMINAL_NODE = 0,
|
||||
IPSET_TERMINAL_NODE = 1
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Return the type of node represented by a particular node ID.
|
||||
*/
|
||||
#define ipset_node_get_type(node_id) ((node_id) & 0x01)
|
||||
|
||||
#define IPSET_NODE_ID_FORMAT "%s%u"
|
||||
#define IPSET_NODE_ID_VALUES(node_id) \
|
||||
(ipset_node_get_type((node_id)) == IPSET_NONTERMINAL_NODE? "s": ""), \
|
||||
((node_id) >> 1)
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
* Terminal nodes
|
||||
*/
|
||||
|
||||
/**
|
||||
* Return the value of a terminal node. The result is undefined if
|
||||
* the node ID represents a nonterminal.
|
||||
*/
|
||||
#define ipset_terminal_value(node_id) ((node_id) >> 1)
|
||||
|
||||
/**
|
||||
* Creates a terminal node ID from a terminal value.
|
||||
*/
|
||||
#define ipset_terminal_node_id(value) \
|
||||
(((value) << 1) | IPSET_TERMINAL_NODE)
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
* Nonterminal nodes
|
||||
*/
|
||||
|
||||
/**
|
||||
* A nonterminal BDD node. This is an inner node of the BDD tree.
|
||||
* The node represents one variable in an overall variable assignment.
|
||||
* The node has two children: a “low” child and a “high” child. The
|
||||
* low child is the subtree that applies when the node's variable is
|
||||
* false or 0; the high child is the subtree that applies when it's
|
||||
* true or 1.
|
||||
*
|
||||
* This type does not take care of ensuring that all BDD nodes are
|
||||
* reduced; that is handled by the node_cache class.
|
||||
*/
|
||||
struct ipset_node {
|
||||
/** The reference count for this node. */
|
||||
unsigned int refcount;
|
||||
/** The variable that this node represents. */
|
||||
ipset_variable variable;
|
||||
/** The subtree node for when the variable is false. */
|
||||
ipset_node_id low;
|
||||
/** The subtree node for when the variable is true. */
|
||||
ipset_node_id high;
|
||||
};
|
||||
|
||||
/**
|
||||
* Return the "value" of a nonterminal node. The value of a nonterminal
|
||||
* is the index into the node array of the cache that the node belongs
|
||||
* to.
|
||||
*/
|
||||
#define ipset_nonterminal_value(node_id) ((node_id) >> 1)
|
||||
|
||||
/**
|
||||
* Creates a nonterminal node ID from a nonterminal value.
|
||||
*/
|
||||
#define ipset_nonterminal_node_id(value) \
|
||||
(((value) << 1) | IPSET_NONTERMINAL_NODE)
|
||||
|
||||
/**
|
||||
* Print out a node object.
|
||||
*/
|
||||
void
|
||||
ipset_node_fprint(FILE *stream, struct ipset_node *node);
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
* Node caches
|
||||
*/
|
||||
|
||||
/**
|
||||
* The log2 of the size of each chunk of BDD nodes.
|
||||
*/
|
||||
/* 16K elements per cache */
|
||||
#define IPSET_BDD_NODE_CACHE_BIT_SIZE 6
|
||||
#define IPSET_BDD_NODE_CACHE_SIZE (1 << IPSET_BDD_NODE_CACHE_BIT_SIZE)
|
||||
#define IPSET_BDD_NODE_CACHE_MASK (IPSET_BDD_NODE_CACHE_SIZE - 1)
|
||||
|
||||
/**
|
||||
* A cache for BDD nodes. By creating and retrieving nodes through
|
||||
* the cache, we ensure that a BDD is reduced.
|
||||
*/
|
||||
struct ipset_node_cache {
|
||||
/** The storage for the nodes managed by this cache. */
|
||||
cork_array(struct ipset_node *) chunks;
|
||||
/** The largest nonterminal index that has been handed out. */
|
||||
ipset_value largest_index;
|
||||
/** The index of the first node in the free list. */
|
||||
ipset_value free_list;
|
||||
/** A cache of the nonterminal nodes, keyed by their contents. */
|
||||
struct cork_hash_table *node_cache;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the index of the chunk that the given nonterminal lives in.
|
||||
*/
|
||||
#define ipset_nonterminal_chunk_index(index) \
|
||||
((index) >> IPSET_BDD_NODE_CACHE_BIT_SIZE)
|
||||
|
||||
/**
|
||||
* Returns the offset of the given nonterminal within its chunk.
|
||||
*/
|
||||
#define ipset_nonterminal_chunk_offset(index) \
|
||||
((index) & IPSET_BDD_NODE_CACHE_MASK)
|
||||
|
||||
/**
|
||||
* Returns a pointer to the ipset_node for a given nonterminal index.
|
||||
*/
|
||||
#define ipset_node_cache_get_nonterminal_by_index(cache, index) \
|
||||
(&cork_array_at(&(cache)->chunks, ipset_nonterminal_chunk_index((index))) \
|
||||
[ipset_nonterminal_chunk_offset((index))])
|
||||
|
||||
/**
|
||||
* Returns the ipset_node for a given nonterminal node ID.
|
||||
*/
|
||||
#define ipset_node_cache_get_nonterminal(cache, node_id) \
|
||||
(ipset_node_cache_get_nonterminal_by_index \
|
||||
((cache), ipset_nonterminal_value((node_id))))
|
||||
|
||||
/**
|
||||
* Create a new node cache.
|
||||
*/
|
||||
struct ipset_node_cache *
|
||||
ipset_node_cache_new(void);
|
||||
|
||||
/**
|
||||
* Free a node cache.
|
||||
*/
|
||||
void
|
||||
ipset_node_cache_free(struct ipset_node_cache *cache);
|
||||
|
||||
/**
|
||||
* Create a new nonterminal node with the given contents, returning
|
||||
* its ID. This function ensures that there is only one node with the
|
||||
* given contents in this cache.
|
||||
*
|
||||
* Steals references to low and high.
|
||||
*/
|
||||
ipset_node_id
|
||||
ipset_node_cache_nonterminal(struct ipset_node_cache *cache,
|
||||
ipset_variable variable,
|
||||
ipset_node_id low, ipset_node_id high);
|
||||
|
||||
|
||||
/**
|
||||
* Increment the reference count of a nonterminal node. (This is a
|
||||
* no-op for terminal nodes.)
|
||||
*/
|
||||
ipset_node_id
|
||||
ipset_node_incref(struct ipset_node_cache *cache, ipset_node_id node);
|
||||
|
||||
/**
|
||||
* Decrement the reference count of a nonterminal node. If the
|
||||
* reference count reaches 0, the storage for the node will be
|
||||
* reclaimed. (This is a no-op for terminal nodes.)
|
||||
*/
|
||||
void
|
||||
ipset_node_decref(struct ipset_node_cache *cache, ipset_node_id node);
|
||||
|
||||
|
||||
/**
|
||||
* Return the number of nodes that are reachable from the given node.
|
||||
* This does not include duplicates if a node is reachable via more
|
||||
* than one path.
|
||||
*/
|
||||
size_t
|
||||
ipset_node_reachable_count(const struct ipset_node_cache *cache,
|
||||
ipset_node_id node);
|
||||
|
||||
|
||||
/**
|
||||
* Return the amount of memory used by the nodes in the given BDD.
|
||||
*/
|
||||
size_t
|
||||
ipset_node_memory_size(const struct ipset_node_cache *cache,
|
||||
ipset_node_id node);
|
||||
|
||||
|
||||
/**
|
||||
* Load a BDD from an input stream. The error field is filled in with
|
||||
* an error condition is the BDD can't be read for any reason.
|
||||
*/
|
||||
ipset_node_id
|
||||
ipset_node_cache_load(FILE *stream, struct ipset_node_cache *cache);
|
||||
|
||||
|
||||
/**
|
||||
* Save a BDD to an output stream. This encodes the set using only
|
||||
* those nodes that are reachable from the BDD's root node.
|
||||
*/
|
||||
int
|
||||
ipset_node_cache_save(struct cork_stream_consumer *stream,
|
||||
struct ipset_node_cache *cache, ipset_node_id node);
|
||||
|
||||
|
||||
/**
|
||||
* Compare two BDD nodes, possibly from different caches, for equality.
|
||||
*/
|
||||
bool
|
||||
ipset_node_cache_nodes_equal(const struct ipset_node_cache *cache1,
|
||||
ipset_node_id node1,
|
||||
const struct ipset_node_cache *cache2,
|
||||
ipset_node_id node2);
|
||||
|
||||
|
||||
/**
|
||||
* Save a GraphViz dot graph for a BDD. The graph script is written
|
||||
* to the given output stream. This graph only includes those nodes
|
||||
* that are reachable from the BDD's root node.
|
||||
*/
|
||||
int
|
||||
ipset_node_cache_save_dot(struct cork_stream_consumer *stream,
|
||||
struct ipset_node_cache *cache, ipset_node_id node);
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
* BDD operators
|
||||
*/
|
||||
|
||||
/**
|
||||
* A function that provides the value for each variable in a BDD.
|
||||
*/
|
||||
typedef bool
|
||||
(*ipset_assignment_func)(const void *user_data,
|
||||
ipset_variable variable);
|
||||
|
||||
/**
|
||||
* An assignment function that gets the variable values from an array
|
||||
* of gbooleans.
|
||||
*/
|
||||
bool
|
||||
ipset_bool_array_assignment(const void *user_data,
|
||||
ipset_variable variable);
|
||||
|
||||
/**
|
||||
* An assignment function that gets the variable values from an array
|
||||
* of bits.
|
||||
*/
|
||||
bool
|
||||
ipset_bit_array_assignment(const void *user_data,
|
||||
ipset_variable variable);
|
||||
|
||||
/**
|
||||
* Evaluate a BDD given a particular assignment of variables.
|
||||
*/
|
||||
ipset_value
|
||||
ipset_node_evaluate(const struct ipset_node_cache *cache, ipset_node_id node,
|
||||
ipset_assignment_func assignment,
|
||||
const void *user_data);
|
||||
|
||||
/**
|
||||
* Add an assignment to the BDD.
|
||||
*/
|
||||
ipset_node_id
|
||||
ipset_node_insert(struct ipset_node_cache *cache, ipset_node_id node,
|
||||
ipset_assignment_func assignment,
|
||||
const void *user_data, ipset_variable variable_count,
|
||||
ipset_value value);
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
* Variable assignments
|
||||
*/
|
||||
|
||||
/**
|
||||
* Each variable in the input to a Boolean function can be true or
|
||||
* false; it can also be EITHER, which means that the variable can be
|
||||
* either true or false in a particular assignment without affecting
|
||||
* the result of the function.
|
||||
*/
|
||||
enum ipset_tribool {
|
||||
IPSET_FALSE = 0,
|
||||
IPSET_TRUE = 1,
|
||||
IPSET_EITHER = 2
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* An assignment is a mapping of variable numbers to Boolean values.
|
||||
* It represents an input to a Boolean function that maps to a
|
||||
* particular output value. Each variable in the input to a Boolean
|
||||
* function can be true or false; it can also be EITHER, which means
|
||||
* that the variable can be either true or false in a particular
|
||||
* assignment without affecting the result of the function.
|
||||
*/
|
||||
|
||||
struct ipset_assignment {
|
||||
/**
|
||||
* The underlying variable assignments are stored in a vector of
|
||||
* tribools. Every variable that has a true or false value must
|
||||
* appear in the vector. Variables that are EITHER only have to
|
||||
* appear to prevent gaps in the vector. Any variables outside
|
||||
* the range of the vector are assumed to be EITHER.
|
||||
*/
|
||||
cork_array(enum ipset_tribool) values;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Create a new assignment where all variables are indeterminite.
|
||||
*/
|
||||
struct ipset_assignment *
|
||||
ipset_assignment_new();
|
||||
|
||||
|
||||
/**
|
||||
* Free an assignment.
|
||||
*/
|
||||
void
|
||||
ipset_assignment_free(struct ipset_assignment *assignment);
|
||||
|
||||
|
||||
/**
|
||||
* Compare two assignments for equality.
|
||||
*/
|
||||
bool
|
||||
ipset_assignment_equal(const struct ipset_assignment *assignment1,
|
||||
const struct ipset_assignment *assignment2);
|
||||
|
||||
|
||||
/**
|
||||
* Set the given variable, and all higher variables, to the EITHER
|
||||
* value.
|
||||
*/
|
||||
void
|
||||
ipset_assignment_cut(struct ipset_assignment *assignment, ipset_variable var);
|
||||
|
||||
|
||||
/**
|
||||
* Clear the assignment, setting all variables to the EITHER value.
|
||||
*/
|
||||
void
|
||||
ipset_assignment_clear(struct ipset_assignment *assignment);
|
||||
|
||||
|
||||
/**
|
||||
* Return the value assigned to a particular variable.
|
||||
*/
|
||||
enum ipset_tribool
|
||||
ipset_assignment_get(struct ipset_assignment *assignment, ipset_variable var);
|
||||
|
||||
|
||||
/**
|
||||
* Set the value assigned to a particular variable.
|
||||
*/
|
||||
void
|
||||
ipset_assignment_set(struct ipset_assignment *assignment,
|
||||
ipset_variable var, enum ipset_tribool value);
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
* Expanded assignments
|
||||
*/
|
||||
|
||||
/**
|
||||
* An iterator for expanding a variable assignment. For each EITHER
|
||||
* variable in the assignment, the iterator yields a result with both
|
||||
* values.
|
||||
*/
|
||||
struct ipset_expanded_assignment {
|
||||
/** Whether there are any more assignments in this iterator. */
|
||||
bool finished;
|
||||
|
||||
/**
|
||||
* The variable values in the current expanded assignment. Since
|
||||
* there won't be any EITHERs in the expanded assignment, we can
|
||||
* use a byte array, and represent each variable by a single bit.
|
||||
*/
|
||||
struct cork_buffer values;
|
||||
|
||||
/**
|
||||
* An array containing all of the variables that are EITHER in the
|
||||
* original assignment.
|
||||
*/
|
||||
cork_array(ipset_variable) eithers;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Return an iterator that expands a variable assignment. For each
|
||||
* variable that's EITHER in the assignment, the iterator yields a
|
||||
* result with both values. The iterator will ensure that the
|
||||
* specified number of variables are given concrete values.
|
||||
*/
|
||||
struct ipset_expanded_assignment *
|
||||
ipset_assignment_expand(const struct ipset_assignment *assignment,
|
||||
ipset_variable var_count);
|
||||
|
||||
|
||||
/**
|
||||
* Free an expanded assignment iterator.
|
||||
*/
|
||||
void
|
||||
ipset_expanded_assignment_free(struct ipset_expanded_assignment *exp);
|
||||
|
||||
|
||||
/**
|
||||
* Advance the iterator to the next assignment.
|
||||
*/
|
||||
void
|
||||
ipset_expanded_assignment_advance(struct ipset_expanded_assignment *exp);
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
* BDD iterators
|
||||
*/
|
||||
|
||||
/**
|
||||
* An iterator for walking through the assignments for a given BDD
|
||||
* node.
|
||||
*
|
||||
* The iterator walks through each path in the BDD tree, stopping at
|
||||
* each terminal node. Each time we reach a terminal node, we yield a
|
||||
* new ipset_assignment object representing the assignment of variables
|
||||
* along the current path.
|
||||
*
|
||||
* We maintain a stack of nodes leading to the current terminal, which
|
||||
* allows us to backtrack up the path to find the next terminal when
|
||||
* we increment the iterator.
|
||||
*/
|
||||
struct ipset_bdd_iterator {
|
||||
/** Whether there are any more assignments in this iterator. */
|
||||
bool finished;
|
||||
|
||||
/** The node cache that we're iterating through. */
|
||||
struct ipset_node_cache *cache;
|
||||
|
||||
/**
|
||||
* The sequence of nonterminal nodes leading to the current
|
||||
* terminal.
|
||||
*/
|
||||
cork_array(ipset_node_id) stack;
|
||||
|
||||
/** The current assignment. */
|
||||
struct ipset_assignment *assignment;
|
||||
|
||||
/**
|
||||
* The value of the BDD's function when applied to the current
|
||||
* assignment.
|
||||
*/
|
||||
ipset_value value;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Return an iterator that yields all of the assignments in the given
|
||||
* BDD. The iterator contains two items of interest. The first is an
|
||||
* ipset_assignment providing the value that each variable takes, while
|
||||
* the second is the terminal value that is the result of the BDD's
|
||||
* function when applied to that variable assignment.
|
||||
*/
|
||||
struct ipset_bdd_iterator *
|
||||
ipset_node_iterate(struct ipset_node_cache *cache, ipset_node_id root);
|
||||
|
||||
|
||||
/**
|
||||
* Free a BDD iterator.
|
||||
*/
|
||||
void
|
||||
ipset_bdd_iterator_free(struct ipset_bdd_iterator *iterator);
|
||||
|
||||
|
||||
/**
|
||||
* Advance the iterator to the next assignment.
|
||||
*/
|
||||
void
|
||||
ipset_bdd_iterator_advance(struct ipset_bdd_iterator *iterator);
|
||||
|
||||
|
||||
#endif /* IPSET_BDD_NODES_H */
|
||||
@@ -0,0 +1,58 @@
|
||||
/* -*- coding: utf-8 -*-
|
||||
* ----------------------------------------------------------------------
|
||||
* Copyright © 2012, RedJack, LLC.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Please see the LICENSE.txt file in this distribution for license
|
||||
* details.
|
||||
* ----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#ifndef IPSET_BITS_H
|
||||
#define IPSET_BITS_H
|
||||
|
||||
#include <libcork/core.h>
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
* Bit arrays
|
||||
*/
|
||||
|
||||
/**
|
||||
* Extract the byte that contains a particular bit in an array.
|
||||
*/
|
||||
#define IPSET_BIT_GET_BYTE(array, i) \
|
||||
(((uint8_t *) (array))[(i) / 8])
|
||||
|
||||
/**
|
||||
* Create a bit mask that extracts a particular bit from the byte that
|
||||
* it lives in.
|
||||
*/
|
||||
#define IPSET_BIT_ON_MASK(i) \
|
||||
(0x80 >> ((i) % 8))
|
||||
|
||||
/**
|
||||
* Create a bit mask that extracts everything except for a particular
|
||||
* bit from the byte that it lives in.
|
||||
*/
|
||||
#define IPSET_BIT_NEG_MASK(i) \
|
||||
(~IPSET_BIT_ON_MASK(i))
|
||||
|
||||
/**
|
||||
* Return whether a particular bit is set in a byte array. Bits are
|
||||
* numbered from 0, in a big-endian order.
|
||||
*/
|
||||
#define IPSET_BIT_GET(array, i) \
|
||||
((IPSET_BIT_GET_BYTE(array, i) & \
|
||||
IPSET_BIT_ON_MASK(i)) != 0)
|
||||
|
||||
/**
|
||||
* Set (or unset) a particular bit is set in a byte array. Bits are
|
||||
* numbered from 0, in a big-endian order.
|
||||
*/
|
||||
#define IPSET_BIT_SET(array, i, val) \
|
||||
(IPSET_BIT_GET_BYTE(array, i) = \
|
||||
(IPSET_BIT_GET_BYTE(array, i) & IPSET_BIT_NEG_MASK(i)) \
|
||||
| ((val)? IPSET_BIT_ON_MASK(i): 0))
|
||||
|
||||
|
||||
#endif /* IPSET_BITS_H */
|
||||
@@ -0,0 +1,31 @@
|
||||
/* -*- coding: utf-8 -*-
|
||||
* ----------------------------------------------------------------------
|
||||
* Copyright © 2012, RedJack, LLC.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Please see the LICENSE.txt file in this distribution for license
|
||||
* details.
|
||||
* ----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#ifndef IPSET_ERRORS_H
|
||||
#define IPSET_ERRORS_H
|
||||
|
||||
|
||||
#include <libcork/core.h>
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
* Error reporting
|
||||
*/
|
||||
|
||||
/* Hash of "ipset.h" */
|
||||
#define IPSET_ERROR 0xf2000181
|
||||
|
||||
enum ipset_error {
|
||||
IPSET_IO_ERROR,
|
||||
IPSET_PARSE_ERROR
|
||||
};
|
||||
|
||||
|
||||
#endif /* IPSET_ERRORS_H */
|
||||
@@ -0,0 +1,265 @@
|
||||
/* -*- coding: utf-8 -*-
|
||||
* ----------------------------------------------------------------------
|
||||
* Copyright © 2009-2012, RedJack, LLC.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Please see the LICENSE.txt file in this distribution for license
|
||||
* details.
|
||||
* ----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#ifndef IPSET_IPSET_H
|
||||
#define IPSET_IPSET_H
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <libcork/core.h>
|
||||
#include <libcork/ds.h>
|
||||
|
||||
#include <ipset/bdd/nodes.h>
|
||||
|
||||
|
||||
struct ip_set {
|
||||
struct ipset_node_cache *cache;
|
||||
ipset_node_id set_bdd;
|
||||
};
|
||||
|
||||
|
||||
struct ip_map {
|
||||
struct ipset_node_cache *cache;
|
||||
ipset_node_id map_bdd;
|
||||
ipset_node_id default_bdd;
|
||||
};
|
||||
|
||||
|
||||
/*---------------------------------------------------------------------
|
||||
* General functions
|
||||
*/
|
||||
|
||||
int
|
||||
ipset_init_library(void);
|
||||
|
||||
|
||||
/*---------------------------------------------------------------------
|
||||
* IP set functions
|
||||
*/
|
||||
|
||||
void
|
||||
ipset_init(struct ip_set *set);
|
||||
|
||||
void
|
||||
ipset_done(struct ip_set *set);
|
||||
|
||||
struct ip_set *
|
||||
ipset_new(void);
|
||||
|
||||
void
|
||||
ipset_free(struct ip_set *set);
|
||||
|
||||
bool
|
||||
ipset_is_empty(const struct ip_set *set);
|
||||
|
||||
bool
|
||||
ipset_is_equal(const struct ip_set *set1, const struct ip_set *set2);
|
||||
|
||||
size_t
|
||||
ipset_memory_size(const struct ip_set *set);
|
||||
|
||||
int
|
||||
ipset_save(FILE *stream, const struct ip_set *set);
|
||||
|
||||
int
|
||||
ipset_save_to_stream(struct cork_stream_consumer *stream,
|
||||
const struct ip_set *set);
|
||||
|
||||
int
|
||||
ipset_save_dot(FILE *stream, const struct ip_set *set);
|
||||
|
||||
struct ip_set *
|
||||
ipset_load(FILE *stream);
|
||||
|
||||
bool
|
||||
ipset_ipv4_add(struct ip_set *set, struct cork_ipv4 *elem);
|
||||
|
||||
bool
|
||||
ipset_ipv4_add_network(struct ip_set *set, struct cork_ipv4 *elem,
|
||||
unsigned int cidr_prefix);
|
||||
|
||||
bool
|
||||
ipset_ipv4_remove(struct ip_set *set, struct cork_ipv4 *elem);
|
||||
|
||||
bool
|
||||
ipset_ipv4_remove_network(struct ip_set *set, struct cork_ipv4 *elem,
|
||||
unsigned int cidr_prefix);
|
||||
|
||||
bool
|
||||
ipset_contains_ipv4(const struct ip_set *set, struct cork_ipv4 *elem);
|
||||
|
||||
bool
|
||||
ipset_ipv6_add(struct ip_set *set, struct cork_ipv6 *elem);
|
||||
|
||||
bool
|
||||
ipset_ipv6_add_network(struct ip_set *set, struct cork_ipv6 *elem,
|
||||
unsigned int cidr_prefix);
|
||||
|
||||
bool
|
||||
ipset_ipv6_remove(struct ip_set *set, struct cork_ipv6 *elem);
|
||||
|
||||
bool
|
||||
ipset_ipv6_remove_network(struct ip_set *set, struct cork_ipv6 *elem,
|
||||
unsigned int cidr_prefix);
|
||||
|
||||
bool
|
||||
ipset_contains_ipv6(const struct ip_set *set, struct cork_ipv6 *elem);
|
||||
|
||||
bool
|
||||
ipset_ip_add(struct ip_set *set, struct cork_ip *addr);
|
||||
|
||||
bool
|
||||
ipset_ip_add_network(struct ip_set *set, struct cork_ip *addr,
|
||||
unsigned int cidr_prefix);
|
||||
|
||||
bool
|
||||
ipset_ip_remove(struct ip_set *set, struct cork_ip *addr);
|
||||
|
||||
bool
|
||||
ipset_ip_remove_network(struct ip_set *set, struct cork_ip *addr,
|
||||
unsigned int cidr_prefix);
|
||||
|
||||
bool
|
||||
ipset_contains_ip(const struct ip_set *set, struct cork_ip *elem);
|
||||
|
||||
|
||||
/* An internal state type used by the ipset_iterator_multiple_expansion_state
|
||||
* field. */
|
||||
enum ipset_iterator_state {
|
||||
IPSET_ITERATOR_NORMAL = 0,
|
||||
IPSET_ITERATOR_MULTIPLE_IPV4,
|
||||
IPSET_ITERATOR_MULTIPLE_IPV6
|
||||
};
|
||||
|
||||
|
||||
/* An iterator that returns all of the IP addresses that have a given value in
|
||||
* an IP set or map. */
|
||||
struct ipset_iterator {
|
||||
/* The address of the current IP network in the iterator. */
|
||||
struct cork_ip addr;
|
||||
|
||||
/* The netmask of the current IP network in the iterator, given as a
|
||||
* CIDR prefix. For a single IP address, this will be 32 or 128. */
|
||||
unsigned int cidr_prefix;
|
||||
|
||||
/* Whether the current assignment needs to be expanded a second
|
||||
* time.
|
||||
*
|
||||
* We have to expand IPv4 and IPv6 assignments separately, since the
|
||||
* set of variables to turn into address bits is different.
|
||||
* Unfortunately, a BDD assignment can contain both IPv4 and IPv6
|
||||
* addresses, if variable 0 is EITHER. (This is trivially true for
|
||||
* the empty set, for instance.) In this case, we have to
|
||||
* explicitly set variable 0 to TRUE, expand it as IPv4, and then
|
||||
* set it to FALSE, and expand it as IPv6. This variable tells us
|
||||
* whether we're in an assignment that needs to be expanded twice,
|
||||
* and if so, which expansion we're currently in.
|
||||
*/
|
||||
enum ipset_iterator_state multiple_expansion_state;
|
||||
|
||||
/* An iterator for retrieving each assignment in the set's BDD. */
|
||||
struct ipset_bdd_iterator *bdd_iterator;
|
||||
|
||||
/* An iterator for expanding each assignment into individual IP
|
||||
* addresses. */
|
||||
struct ipset_expanded_assignment *assignment_iterator;
|
||||
|
||||
/* Whether there are any more IP addresses in this iterator. */
|
||||
bool finished;
|
||||
|
||||
/* The desired value for each IP address. */
|
||||
bool desired_value;
|
||||
|
||||
/* Whether to summarize the contents of the IP set as networks,
|
||||
* where possible. */
|
||||
bool summarize;
|
||||
};
|
||||
|
||||
|
||||
struct ipset_iterator *
|
||||
ipset_iterate(struct ip_set *set, bool desired_value);
|
||||
|
||||
struct ipset_iterator *
|
||||
ipset_iterate_networks(struct ip_set *set, bool desired_value);
|
||||
|
||||
void
|
||||
ipset_iterator_free(struct ipset_iterator *iterator);
|
||||
|
||||
void
|
||||
ipset_iterator_advance(struct ipset_iterator *iterator);
|
||||
|
||||
|
||||
/*---------------------------------------------------------------------
|
||||
* IP map functions
|
||||
*/
|
||||
|
||||
void
|
||||
ipmap_init(struct ip_map *map, int default_value);
|
||||
|
||||
void
|
||||
ipmap_done(struct ip_map *map);
|
||||
|
||||
struct ip_map *
|
||||
ipmap_new(int default_value);
|
||||
|
||||
void
|
||||
ipmap_free(struct ip_map *map);
|
||||
|
||||
bool
|
||||
ipmap_is_empty(const struct ip_map *map);
|
||||
|
||||
bool
|
||||
ipmap_is_equal(const struct ip_map *map1, const struct ip_map *map2);
|
||||
|
||||
size_t
|
||||
ipmap_memory_size(const struct ip_map *map);
|
||||
|
||||
int
|
||||
ipmap_save(FILE *stream, const struct ip_map *map);
|
||||
|
||||
int
|
||||
ipmap_save_to_stream(struct cork_stream_consumer *stream,
|
||||
const struct ip_map *map);
|
||||
|
||||
struct ip_map *
|
||||
ipmap_load(FILE *stream);
|
||||
|
||||
void
|
||||
ipmap_ipv4_set(struct ip_map *map, struct cork_ipv4 *elem, int value);
|
||||
|
||||
void
|
||||
ipmap_ipv4_set_network(struct ip_map *map, struct cork_ipv4 *elem,
|
||||
unsigned int cidr_prefix, int value);
|
||||
|
||||
int
|
||||
ipmap_ipv4_get(struct ip_map *map, struct cork_ipv4 *elem);
|
||||
|
||||
void
|
||||
ipmap_ipv6_set(struct ip_map *map, struct cork_ipv6 *elem, int value);
|
||||
|
||||
void
|
||||
ipmap_ipv6_set_network(struct ip_map *map, struct cork_ipv6 *elem,
|
||||
unsigned int cidr_prefix, int value);
|
||||
|
||||
int
|
||||
ipmap_ipv6_get(struct ip_map *map, struct cork_ipv6 *elem);
|
||||
|
||||
void
|
||||
ipmap_ip_set(struct ip_map *map, struct cork_ip *addr, int value);
|
||||
|
||||
void
|
||||
ipmap_ip_set_network(struct ip_map *map, struct cork_ip *addr,
|
||||
unsigned int cidr_prefix, int value);
|
||||
|
||||
int
|
||||
ipmap_ip_get(struct ip_map *map, struct cork_ip *addr);
|
||||
|
||||
|
||||
#endif /* IPSET_IPSET_H */
|
||||
@@ -0,0 +1,31 @@
|
||||
/* -*- coding: utf-8 -*-
|
||||
* ----------------------------------------------------------------------
|
||||
* Copyright © 2010-2012, RedJack, LLC.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Please see the LICENSE.txt file in this distribution for license
|
||||
* details.
|
||||
* ----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#ifndef IPSET_LOGGING_H
|
||||
#define IPSET_LOGGING_H
|
||||
|
||||
|
||||
#if !defined(IPSET_DEBUG)
|
||||
#define IPSET_DEBUG 0
|
||||
#endif
|
||||
|
||||
#if IPSET_DEBUG
|
||||
#include <stdio.h>
|
||||
#define DEBUG(...) \
|
||||
do { \
|
||||
fprintf(stderr, __VA_ARGS__); \
|
||||
fprintf(stderr, "\n"); \
|
||||
} while (0)
|
||||
#else
|
||||
#define DEBUG(...) /* no debug messages */
|
||||
#endif
|
||||
|
||||
|
||||
#endif /* IPSET_LOGGING_H */
|
||||
@@ -0,0 +1,30 @@
|
||||
# This file is part of libasyncns.
|
||||
#
|
||||
# Copyright 2005-2008 Lennart Poettering
|
||||
#
|
||||
# libasyncns is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser General Public License as
|
||||
# published by the Free Software Foundation, either version 2.1 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# libasyncns is distributed in the hope that it will be useful, but
|
||||
# WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
# Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public
|
||||
# License along with libasyncns. If not, see
|
||||
# <http://www.gnu.org/licenses/>.
|
||||
|
||||
noinst_LTLIBRARIES = libipset.la
|
||||
|
||||
bdd_src = bdd/assignments.c bdd/basics.c bdd/bdd-iterator.c bdd/expanded.c \
|
||||
bdd/reachable.c bdd/read.c bdd/write.c
|
||||
map_src = map/allocation.c map/inspection.c map/ipv4_map.c map/ipv6_map.c \
|
||||
map/storage.c
|
||||
set_src = set/allocation.c set/inspection.c set/ipv4_set.c set/ipv6_set.c \
|
||||
set/iterator.c set/storage.c
|
||||
|
||||
libipset_la_SOURCES = ${bdd_src} ${map_src} ${set_src}
|
||||
|
||||
libipset_la_LDFLAGS = -static
|
||||
Whitespace-only changes.
@@ -0,0 +1,50 @@
|
||||
/* -*- coding: utf-8 -*-
|
||||
* ----------------------------------------------------------------------
|
||||
* Copyright © 2009-2012, RedJack, LLC.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Please see the LICENSE.txt file in this distribution for license
|
||||
* details.
|
||||
* ----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#include <libcork/core.h>
|
||||
|
||||
#include "ipset/bdd/nodes.h"
|
||||
#include "ipset/ipset.h"
|
||||
|
||||
|
||||
void
|
||||
ipmap_init(struct ip_map *map, int default_value)
|
||||
{
|
||||
/* The map starts empty, so every value assignment should yield the
|
||||
* default. */
|
||||
map->cache = ipset_node_cache_new();
|
||||
map->default_bdd = ipset_terminal_node_id(default_value);
|
||||
map->map_bdd = map->default_bdd;
|
||||
}
|
||||
|
||||
|
||||
struct ip_map *
|
||||
ipmap_new(int default_value)
|
||||
{
|
||||
struct ip_map *result = cork_new(struct ip_map);
|
||||
ipmap_init(result, default_value);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ipmap_done(struct ip_map *map)
|
||||
{
|
||||
ipset_node_decref(map->cache, map->map_bdd);
|
||||
ipset_node_cache_free(map->cache);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ipmap_free(struct ip_map *map)
|
||||
{
|
||||
ipmap_done(map);
|
||||
free(map);
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
/* -*- coding: utf-8 -*-
|
||||
* ----------------------------------------------------------------------
|
||||
* Copyright © 2009-2012, RedJack, LLC.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Please see the LICENSE.txt file in this distribution for license
|
||||
* details.
|
||||
* ----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#include <libcork/core.h>
|
||||
|
||||
#include "ipset/bdd/nodes.h"
|
||||
#include "ipset/bits.h"
|
||||
#include "ipset/errors.h"
|
||||
#include "ipset/ipset.h"
|
||||
|
||||
|
||||
/**
|
||||
* Given a BDD variable number, return the index of the corresponding
|
||||
* bit in an IP address. IPv4 addresses use variables 1-32; IPv6
|
||||
* addresses use 1-128. (Variable 0 is used to identify the kind of
|
||||
* address — TRUE for IPv4, FALSE for IPv6.)
|
||||
*/
|
||||
|
||||
static unsigned int
|
||||
IPMAP_NAME(bit_for_var)(ipset_variable var)
|
||||
{
|
||||
return (var - 1);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* An assignment function that can be used to evaluate an IP map BDD.
|
||||
*/
|
||||
|
||||
static bool
|
||||
IPMAP_NAME(assignment)(const void *addr, ipset_variable var)
|
||||
{
|
||||
if (var == 0) {
|
||||
return IP_DISCRIMINATOR_VALUE;
|
||||
} else {
|
||||
unsigned int bit = IPMAP_NAME(bit_for_var)(var);
|
||||
return IPSET_BIT_GET(addr, bit);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
IPMAP_NAME(get)(struct ip_map *map, CORK_IP *elem)
|
||||
{
|
||||
return ipset_node_evaluate
|
||||
(map->cache, map->map_bdd, IPMAP_NAME(assignment), elem);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
IPMAP_NAME(set_network)(struct ip_map *map, CORK_IP *elem,
|
||||
unsigned int cidr_prefix, int value)
|
||||
{
|
||||
/* Special case — the BDD for a netmask that's out of range never
|
||||
* evaluates to true. */
|
||||
if (cidr_prefix > IP_BIT_SIZE) {
|
||||
cork_error_set
|
||||
(IPSET_ERROR, IPSET_PARSE_ERROR,
|
||||
"CIDR block %u out of range [0..%u]", cidr_prefix, IP_BIT_SIZE);
|
||||
return;
|
||||
}
|
||||
|
||||
ipset_node_id new_bdd =
|
||||
ipset_node_insert
|
||||
(map->cache, map->map_bdd,
|
||||
IPMAP_NAME(assignment), elem, cidr_prefix + 1, value);
|
||||
ipset_node_decref(map->cache, map->map_bdd);
|
||||
map->map_bdd = new_bdd;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
IPMAP_NAME(set)(struct ip_map *map, CORK_IP *elem, int value)
|
||||
{
|
||||
ipset_node_id new_bdd =
|
||||
ipset_node_insert
|
||||
(map->cache, map->map_bdd,
|
||||
IPMAP_NAME(assignment), elem, IP_BIT_SIZE + 1, value);
|
||||
ipset_node_decref(map->cache, map->map_bdd);
|
||||
map->map_bdd = new_bdd;
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
/* -*- coding: utf-8 -*-
|
||||
* ----------------------------------------------------------------------
|
||||
* Copyright © 2009-2012, RedJack, LLC.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Please see the LICENSE.txt file in this distribution for license
|
||||
* details.
|
||||
* ----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#include <libcork/core.h>
|
||||
|
||||
#include "ipset/bdd/nodes.h"
|
||||
#include "ipset/ipset.h"
|
||||
|
||||
bool
|
||||
ipmap_is_empty(const struct ip_map *map)
|
||||
{
|
||||
/* Since BDDs are unique, any map that maps all addresses to the
|
||||
* default value is “empty”. */
|
||||
return (map->map_bdd == map->default_bdd);
|
||||
}
|
||||
|
||||
bool
|
||||
ipmap_is_equal(const struct ip_map *map1, const struct ip_map *map2)
|
||||
{
|
||||
return ipset_node_cache_nodes_equal
|
||||
(map1->cache, map1->map_bdd, map2->cache, map2->map_bdd);
|
||||
}
|
||||
|
||||
size_t
|
||||
ipmap_memory_size(const struct ip_map *map)
|
||||
{
|
||||
return ipset_node_memory_size(map->cache, map->map_bdd);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ipmap_ip_set(struct ip_map *map, struct cork_ip *addr, int value)
|
||||
{
|
||||
if (addr->version == 4) {
|
||||
ipmap_ipv4_set(map, &addr->ip.v4, value);
|
||||
} else {
|
||||
ipmap_ipv6_set(map, &addr->ip.v6, value);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ipmap_ip_set_network(struct ip_map *map, struct cork_ip *addr,
|
||||
unsigned int cidr_prefix, int value)
|
||||
{
|
||||
if (addr->version == 4) {
|
||||
ipmap_ipv4_set_network(map, &addr->ip.v4, cidr_prefix, value);
|
||||
} else {
|
||||
ipmap_ipv6_set_network(map, &addr->ip.v6, cidr_prefix, value);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
ipmap_ip_get(struct ip_map *map, struct cork_ip *addr)
|
||||
{
|
||||
if (addr->version == 4) {
|
||||
return ipmap_ipv4_get(map, &addr->ip.v4);
|
||||
} else {
|
||||
return ipmap_ipv6_get(map, &addr->ip.v6);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/* -*- coding: utf-8 -*-
|
||||
* ----------------------------------------------------------------------
|
||||
* Copyright © 2009-2012, RedJack, LLC.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Please see the LICENSE.txt file in this distribution for license
|
||||
* details.
|
||||
* ----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/*
|
||||
* The IPv4 and IPv6 map types are basically identical, except for the
|
||||
* names of the functions, and the size of the values that are being
|
||||
* stored. Rather than having two mostly duplicate definitions of each
|
||||
* function, we define “template functions” where anything that depends
|
||||
* on the size of the IP address is defined using the following macros.
|
||||
*/
|
||||
|
||||
|
||||
/* The name of the cork_ipvX type. */
|
||||
#define CORK_IP struct cork_ipv4
|
||||
|
||||
/* The number of bits in an IPvX address. */
|
||||
#define IP_BIT_SIZE 32
|
||||
|
||||
/* The value of the discriminator variable for an IPvX address. */
|
||||
#define IP_DISCRIMINATOR_VALUE true
|
||||
|
||||
/* Creates a identifier of the form “ipset_ipv4_<basename>”. */
|
||||
#define IPSET_NAME(basename) ipset_ipv4_##basename
|
||||
|
||||
/* Creates a identifier of the form “ipmap_ipv4_<basename>”. */
|
||||
#define IPMAP_NAME(basename) ipmap_ipv4_##basename
|
||||
|
||||
|
||||
/* Now include all of the templates. */
|
||||
#include "inspection-template.c.in"
|
||||
@@ -0,0 +1,37 @@
|
||||
/* -*- coding: utf-8 -*-
|
||||
* ----------------------------------------------------------------------
|
||||
* Copyright © 2009-2012, RedJack, LLC.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Please see the LICENSE.txt file in this distribution for license
|
||||
* details.
|
||||
* ----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/*
|
||||
* The IPv4 and IPv6 map types are basically identical, except for the
|
||||
* names of the functions, and the size of the values that are being
|
||||
* stored. Rather than having two mostly duplicate definitions of each
|
||||
* function, we define “template functions” where anything that depends
|
||||
* on the size of the IP address is defined using the following macros.
|
||||
*/
|
||||
|
||||
|
||||
/* The name of the cork_ipvX type. */
|
||||
#define CORK_IP struct cork_ipv6
|
||||
|
||||
/* The number of bits in an IPvX address. */
|
||||
#define IP_BIT_SIZE 128
|
||||
|
||||
/* The value of the discriminator variable for an IPvX address. */
|
||||
#define IP_DISCRIMINATOR_VALUE false
|
||||
|
||||
/* Creates a identifier of the form “ipset_ipv6_<basename>”. */
|
||||
#define IPSET_NAME(basename) ipset_ipv6_##basename
|
||||
|
||||
/* Creates a identifier of the form “ipmap_ipv6_<basename>”. */
|
||||
#define IPMAP_NAME(basename) ipmap_ipv6_##basename
|
||||
|
||||
|
||||
/* Now include all of the templates. */
|
||||
#include "inspection-template.c.in"
|
||||
@@ -0,0 +1,101 @@
|
||||
/* -*- coding: utf-8 -*-
|
||||
* ----------------------------------------------------------------------
|
||||
* Copyright © 2009-2012, RedJack, LLC.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Please see the LICENSE.txt file in this distribution for license
|
||||
* details.
|
||||
* ----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <libcork/core.h>
|
||||
|
||||
#include "ipset/bdd/nodes.h"
|
||||
#include "ipset/errors.h"
|
||||
#include "ipset/ipset.h"
|
||||
|
||||
|
||||
static void
|
||||
create_errno_error(FILE *stream)
|
||||
{
|
||||
if (ferror(stream)) {
|
||||
cork_error_set(IPSET_ERROR, IPSET_IO_ERROR, "%s", strerror(errno));
|
||||
} else {
|
||||
cork_unknown_error();
|
||||
}
|
||||
}
|
||||
|
||||
struct file_consumer {
|
||||
/* file_consumer is a subclass of cork_stream_consumer */
|
||||
struct cork_stream_consumer parent;
|
||||
/* the file to write the data into */
|
||||
FILE *fp;
|
||||
};
|
||||
|
||||
static int
|
||||
file_consumer_data(struct cork_stream_consumer *vself,
|
||||
const void *buf, size_t size, bool is_first)
|
||||
{
|
||||
struct file_consumer *self =
|
||||
cork_container_of(vself, struct file_consumer, parent);
|
||||
size_t bytes_written = fwrite(buf, 1, size, self->fp);
|
||||
/* If there was an error writing to the file, then signal this to
|
||||
* the producer */
|
||||
if (bytes_written == size) {
|
||||
return 0;
|
||||
} else {
|
||||
create_errno_error(self->fp);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
file_consumer_eof(struct cork_stream_consumer *vself)
|
||||
{
|
||||
/* We don't close the file, so there's nothing special to do at
|
||||
* end-of-stream. */
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
ipmap_save_to_stream(struct cork_stream_consumer *stream,
|
||||
const struct ip_map *map)
|
||||
{
|
||||
return ipset_node_cache_save(stream, map->cache, map->map_bdd);
|
||||
}
|
||||
|
||||
int
|
||||
ipmap_save(FILE *fp, const struct ip_map *map)
|
||||
{
|
||||
struct file_consumer stream = {
|
||||
{ file_consumer_data, file_consumer_eof, NULL }, fp
|
||||
};
|
||||
return ipmap_save_to_stream(&stream.parent, map);
|
||||
}
|
||||
|
||||
|
||||
struct ip_map *
|
||||
ipmap_load(FILE *stream)
|
||||
{
|
||||
struct ip_map *map;
|
||||
ipset_node_id new_bdd;
|
||||
|
||||
/* It doesn't matter what default value we use here, because we're
|
||||
* going to replace it with the default BDD we load in from the
|
||||
* file. */
|
||||
map = ipmap_new(0);
|
||||
new_bdd = ipset_node_cache_load(stream, map->cache);
|
||||
if (cork_error_occurred()) {
|
||||
ipmap_free(map);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
map->map_bdd = new_bdd;
|
||||
return map;
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
# This file is part of libasyncns.
|
||||
#
|
||||
# Copyright 2005-2008 Lennart Poettering
|
||||
#
|
||||
# libasyncns is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser General Public License as
|
||||
# published by the Free Software Foundation, either version 2.1 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# libasyncns is distributed in the hope that it will be useful, but
|
||||
# WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
# Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public
|
||||
# License along with libasyncns. If not, see
|
||||
# <http://www.gnu.org/licenses/>.
|
||||
|
||||
noinst_LTLIBRARIES = libipset.la
|
||||
|
||||
bdd_src = bdd/assignments.c bdd/basics.c bdd/bdd-iterator.c bdd/expanded.c \
|
||||
bdd/reachable.c bdd/read.c bdd/write.c
|
||||
map_src = map/allocation.c map/inspection.c map/ipv4_map.c map/ipv6_map.c \
|
||||
map/storage.c
|
||||
set_src = set/allocation.c set/inspection.c set/ipv4_set.c set/ipv6_set.c \
|
||||
set/iterator.c set/storage.c
|
||||
|
||||
libipset_la_SOURCES = ${bdd_src} ${map_src} ${set_src}
|
||||
|
||||
libipset_la_LDFLAGS = -static
|
||||
Whitespace-only changes.
@@ -0,0 +1,49 @@
|
||||
/* -*- coding: utf-8 -*-
|
||||
* ----------------------------------------------------------------------
|
||||
* Copyright © 2009-2012, RedJack, LLC.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Please see the LICENSE.txt file in this distribution for license
|
||||
* details.
|
||||
* ----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#include <libcork/core.h>
|
||||
|
||||
#include "ipset/bdd/nodes.h"
|
||||
#include "ipset/ipset.h"
|
||||
|
||||
|
||||
void
|
||||
ipset_init(struct ip_set *set)
|
||||
{
|
||||
/* The set starts empty, so every value assignment should yield
|
||||
* false. */
|
||||
set->cache = ipset_node_cache_new();
|
||||
set->set_bdd = ipset_terminal_node_id(false);
|
||||
}
|
||||
|
||||
|
||||
struct ip_set *
|
||||
ipset_new(void)
|
||||
{
|
||||
struct ip_set *result = cork_new(struct ip_set);
|
||||
ipset_init(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ipset_done(struct ip_set *set)
|
||||
{
|
||||
ipset_node_decref(set->cache, set->set_bdd);
|
||||
ipset_node_cache_free(set->cache);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ipset_free(struct ip_set *set)
|
||||
{
|
||||
ipset_done(set);
|
||||
free(set);
|
||||
}
|
||||
@@ -0,0 +1,130 @@
|
||||
/* -*- coding: utf-8 -*-
|
||||
* ----------------------------------------------------------------------
|
||||
* Copyright © 2012, RedJack, LLC.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Please see the LICENSE.txt file in this distribution for license
|
||||
* details.
|
||||
* ----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#include <libcork/core.h>
|
||||
|
||||
#include "ipset/bdd/nodes.h"
|
||||
#include "ipset/bits.h"
|
||||
#include "ipset/errors.h"
|
||||
#include "ipset/ipset.h"
|
||||
|
||||
|
||||
/**
|
||||
* Given a BDD variable number, return the index of the corresponding
|
||||
* bit in an IP address. IPv4 addresses use variables 1-32; IPv6
|
||||
* addresses use 1-128. (Variable 0 is used to identify the kind of
|
||||
* address — TRUE for IPv4, FALSE for IPv6.)
|
||||
*/
|
||||
|
||||
static unsigned int
|
||||
IPSET_NAME(bit_for_var)(ipset_variable var)
|
||||
{
|
||||
return (var - 1);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* An assignment function that can be used to evaluate an IP set BDD.
|
||||
*/
|
||||
|
||||
static bool
|
||||
IPSET_NAME(assignment)(const void *addr, ipset_variable var)
|
||||
{
|
||||
if (var == 0) {
|
||||
return IP_DISCRIMINATOR_VALUE;
|
||||
} else {
|
||||
unsigned int bit = IPSET_NAME(bit_for_var)(var);
|
||||
return IPSET_BIT_GET(addr, bit);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
IPSET_PRENAME(contains)(const struct ip_set *set, CORK_IP *elem)
|
||||
{
|
||||
return ipset_node_evaluate
|
||||
(set->cache, set->set_bdd, IPSET_NAME(assignment), elem);
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
IPSET_NAME(add_network)(struct ip_set *set, CORK_IP *elem,
|
||||
unsigned int cidr_prefix)
|
||||
{
|
||||
/* Special case — the BDD for a netmask that's out of range never
|
||||
* evaluates to true. */
|
||||
if (cidr_prefix > IP_BIT_SIZE) {
|
||||
cork_error_set
|
||||
(IPSET_ERROR, IPSET_PARSE_ERROR,
|
||||
"CIDR block %u out of range [0..%u]", cidr_prefix, IP_BIT_SIZE);
|
||||
return false;
|
||||
}
|
||||
|
||||
ipset_node_id new_bdd =
|
||||
ipset_node_insert
|
||||
(set->cache, set->set_bdd,
|
||||
IPSET_NAME(assignment), elem, cidr_prefix + 1, 1);
|
||||
bool result = (new_bdd == set->set_bdd);
|
||||
ipset_node_decref(set->cache, set->set_bdd);
|
||||
set->set_bdd = new_bdd;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
IPSET_NAME(add)(struct ip_set *set, CORK_IP *elem)
|
||||
{
|
||||
ipset_node_id new_bdd =
|
||||
ipset_node_insert
|
||||
(set->cache, set->set_bdd,
|
||||
IPSET_NAME(assignment), elem, IP_BIT_SIZE + 1, 1);
|
||||
bool result = (new_bdd == set->set_bdd);
|
||||
ipset_node_decref(set->cache, set->set_bdd);
|
||||
set->set_bdd = new_bdd;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
IPSET_NAME(remove)(struct ip_set *set, CORK_IP *elem)
|
||||
{
|
||||
ipset_node_id new_bdd =
|
||||
ipset_node_insert
|
||||
(set->cache, set->set_bdd,
|
||||
IPSET_NAME(assignment), elem, IP_BIT_SIZE + 1, 0);
|
||||
bool result = (new_bdd == set->set_bdd);
|
||||
ipset_node_decref(set->cache, set->set_bdd);
|
||||
set->set_bdd = new_bdd;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
IPSET_NAME(remove_network)(struct ip_set *set, CORK_IP *elem,
|
||||
unsigned int cidr_prefix)
|
||||
{
|
||||
/* Special case — the BDD for a netmask that's out of range never
|
||||
* evaluates to true. */
|
||||
if (cidr_prefix > IP_BIT_SIZE) {
|
||||
cork_error_set
|
||||
(IPSET_ERROR, IPSET_PARSE_ERROR,
|
||||
"CIDR block %u out of range [0..%u]", cidr_prefix, IP_BIT_SIZE);
|
||||
return false;
|
||||
}
|
||||
|
||||
ipset_node_id new_bdd =
|
||||
ipset_node_insert
|
||||
(set->cache, set->set_bdd,
|
||||
IPSET_NAME(assignment), elem, cidr_prefix + 1, 0);
|
||||
bool result = (new_bdd == set->set_bdd);
|
||||
ipset_node_decref(set->cache, set->set_bdd);
|
||||
set->set_bdd = new_bdd;
|
||||
return result;
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
/* -*- coding: utf-8 -*-
|
||||
* ----------------------------------------------------------------------
|
||||
* Copyright © 2009-2012, RedJack, LLC.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Please see the LICENSE.txt file in this distribution for license
|
||||
* details.
|
||||
* ----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#include <libcork/core.h>
|
||||
|
||||
#include "ipset/bdd/nodes.h"
|
||||
#include "ipset/ipset.h"
|
||||
|
||||
bool
|
||||
ipset_is_empty(const struct ip_set *set)
|
||||
{
|
||||
/* Since BDDs are unique, the only empty set is the “false” BDD. */
|
||||
return (set->set_bdd == ipset_terminal_node_id(false));
|
||||
}
|
||||
|
||||
bool
|
||||
ipset_is_equal(const struct ip_set *set1, const struct ip_set *set2)
|
||||
{
|
||||
return ipset_node_cache_nodes_equal
|
||||
(set1->cache, set1->set_bdd, set2->cache, set2->set_bdd);
|
||||
}
|
||||
|
||||
size_t
|
||||
ipset_memory_size(const struct ip_set *set)
|
||||
{
|
||||
return ipset_node_memory_size(set->cache, set->set_bdd);
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
ipset_ip_add(struct ip_set *set, struct cork_ip *addr)
|
||||
{
|
||||
if (addr->version == 4) {
|
||||
return ipset_ipv4_add(set, &addr->ip.v4);
|
||||
} else {
|
||||
return ipset_ipv6_add(set, &addr->ip.v6);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
ipset_ip_add_network(struct ip_set *set, struct cork_ip *addr,
|
||||
unsigned int cidr_prefix)
|
||||
{
|
||||
if (addr->version == 4) {
|
||||
return ipset_ipv4_add_network(set, &addr->ip.v4, cidr_prefix);
|
||||
} else {
|
||||
return ipset_ipv6_add_network(set, &addr->ip.v6, cidr_prefix);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
ipset_ip_remove(struct ip_set *set, struct cork_ip *addr)
|
||||
{
|
||||
if (addr->version == 4) {
|
||||
return ipset_ipv4_remove(set, &addr->ip.v4);
|
||||
} else {
|
||||
return ipset_ipv6_remove(set, &addr->ip.v6);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
ipset_ip_remove_network(struct ip_set *set, struct cork_ip *addr,
|
||||
unsigned int cidr_prefix)
|
||||
{
|
||||
if (addr->version == 4) {
|
||||
return ipset_ipv4_remove_network(set, &addr->ip.v4, cidr_prefix);
|
||||
} else {
|
||||
return ipset_ipv6_remove_network(set, &addr->ip.v6, cidr_prefix);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
ipset_contains_ip(const struct ip_set *set, struct cork_ip *addr)
|
||||
{
|
||||
if (addr->version == 4) {
|
||||
return ipset_contains_ipv4(set, &addr->ip.v4);
|
||||
} else {
|
||||
return ipset_contains_ipv6(set, &addr->ip.v6);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/* -*- coding: utf-8 -*-
|
||||
* ----------------------------------------------------------------------
|
||||
* Copyright © 2009-2012, RedJack, LLC.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Please see the LICENSE.txt file in this distribution for license
|
||||
* details.
|
||||
* ----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/*
|
||||
* The IPv4 and IPv6 set types are basically identical, except for the
|
||||
* names of the functions, and the size of the values that are being
|
||||
* stored. Rather than having two mostly duplicate definitions of each
|
||||
* function, we define “template functions” where anything that depends
|
||||
* on the size of the IP address is defined using the following macros.
|
||||
*/
|
||||
|
||||
|
||||
/* The name of the cork_ipvX type. */
|
||||
#define CORK_IP struct cork_ipv4
|
||||
|
||||
/* The number of bits in an IPvX address. */
|
||||
#define IP_BIT_SIZE 32
|
||||
|
||||
/* The value of the discriminator variable for an IPvX address. */
|
||||
#define IP_DISCRIMINATOR_VALUE true
|
||||
|
||||
/* Creates a identifier of the form “ipset_ipv4_<basename>”. */
|
||||
#define IPSET_NAME(basename) ipset_ipv4_##basename
|
||||
|
||||
/* Creates a identifier of the form “ipset_<basename>_ipv4”. */
|
||||
#define IPSET_PRENAME(basename) ipset_##basename##_ipv4
|
||||
|
||||
|
||||
/* Now include all of the templates. */
|
||||
#include "inspection-template.c.in"
|
||||
@@ -0,0 +1,38 @@
|
||||
/* -*- coding: utf-8 -*-
|
||||
* ----------------------------------------------------------------------
|
||||
* Copyright © 2009-2012, RedJack, LLC.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Please see the LICENSE.txt file in this distribution for license
|
||||
* details.
|
||||
* ----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/*
|
||||
* The IPv4 and IPv6 set types are basically identical, except for the
|
||||
* names of the functions, and the size of the values that are being
|
||||
* stored. Rather than having two mostly duplicate definitions of
|
||||
* each function, we define “template functions” where anything that
|
||||
* depends on the size of the IP address is defined using the
|
||||
* following macros.
|
||||
*/
|
||||
|
||||
|
||||
/* The name of the cork_ipvX type. */
|
||||
#define CORK_IP struct cork_ipv6
|
||||
|
||||
/* The number of bits in an IPvX address. */
|
||||
#define IP_BIT_SIZE 128
|
||||
|
||||
/* The value of the discriminator variable for an IPvX address. */
|
||||
#define IP_DISCRIMINATOR_VALUE false
|
||||
|
||||
/* Creates a identifier of the form “ipset_ipv6_<basename>”. */
|
||||
#define IPSET_NAME(basename) ipset_ipv6_##basename
|
||||
|
||||
/* Creates a identifier of the form “ipset_<basename>_ipv6”. */
|
||||
#define IPSET_PRENAME(basename) ipset_##basename##_ipv6
|
||||
|
||||
|
||||
/* Now include all of the templates. */
|
||||
#include "inspection-template.c.in"
|
||||
@@ -0,0 +1,342 @@
|
||||
/* -*- coding: utf-8 -*-
|
||||
* ----------------------------------------------------------------------
|
||||
* Copyright © 2010-2012, RedJack, LLC.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Please see the LICENSE.txt file in this distribution for license
|
||||
* details.
|
||||
* ----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include <libcork/core.h>
|
||||
|
||||
#include "ipset/bdd/nodes.h"
|
||||
#include "ipset/bits.h"
|
||||
#include "ipset/ipset.h"
|
||||
#include "ipset/logging.h"
|
||||
|
||||
|
||||
#define IPV4_BIT_SIZE 32
|
||||
#define IPV6_BIT_SIZE 128
|
||||
|
||||
|
||||
/* Forward declarations */
|
||||
|
||||
static void
|
||||
process_assignment(struct ipset_iterator *iterator);
|
||||
|
||||
static void
|
||||
expand_ipv6(struct ipset_iterator *iterator);
|
||||
|
||||
|
||||
/**
|
||||
* Find the highest non-EITHER bit in an assignment, starting from the
|
||||
* given bit index.
|
||||
*/
|
||||
static unsigned int
|
||||
find_last_non_either_bit(struct ipset_assignment *assignment,
|
||||
unsigned int starting_bit)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = starting_bit; i >= 1; i--) {
|
||||
enum ipset_tribool value = ipset_assignment_get(assignment, i);
|
||||
if (value != IPSET_EITHER) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create a generic IP address object from the current expanded
|
||||
* assignment.
|
||||
*/
|
||||
static void
|
||||
create_ip_address(struct ipset_iterator *iterator)
|
||||
{
|
||||
struct cork_ip *addr = &iterator->addr;
|
||||
struct ipset_expanded_assignment *exp = iterator->assignment_iterator;
|
||||
|
||||
/* Initialize the address to all 0 bits. */
|
||||
memset(addr, 0, sizeof(struct cork_ip));
|
||||
|
||||
/* Check variable 0 to see if this is an IPv4 or IPv6 address. */
|
||||
addr->version = IPSET_BIT_GET(exp->values.buf, 0)? 4: 6;
|
||||
|
||||
/* Copy bits from the expanded assignment. The number of bits to
|
||||
* copy is given as the current netmask. We'll have calculated that
|
||||
* already based on the non-expanded assignment. */
|
||||
unsigned int i;
|
||||
for (i = 0; i < iterator->cidr_prefix; i++) {
|
||||
IPSET_BIT_SET(&addr->ip, i, IPSET_BIT_GET(exp->values.buf, i+1));
|
||||
}
|
||||
|
||||
#if IPSET_DEBUG
|
||||
char buf[CORK_IP_STRING_LENGTH];
|
||||
cork_ip_to_raw_string(addr, buf);
|
||||
DEBUG("Current IP address is %s/%u", buf, iterator->cidr_prefix);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Advance the BDD iterator, taking into account that some assignments
|
||||
* need to be expanded twice.
|
||||
*/
|
||||
static void
|
||||
advance_assignment(struct ipset_iterator *iterator)
|
||||
{
|
||||
/* Check the current state of the iterator to determine how to
|
||||
* advance. */
|
||||
|
||||
/* In most cases, the assignment we just finished only needed to be
|
||||
* expanded once. So we move on to the next assignment and process
|
||||
* it. */
|
||||
if (CORK_LIKELY(iterator->multiple_expansion_state ==
|
||||
IPSET_ITERATOR_NORMAL))
|
||||
{
|
||||
ipset_bdd_iterator_advance(iterator->bdd_iterator);
|
||||
process_assignment(iterator);
|
||||
return;
|
||||
}
|
||||
|
||||
/* If the assignment needs to be expanded twice, we'll do the IPv4
|
||||
* expansion first. If that's what we've just finished, do the IPv6
|
||||
* expansion next. */
|
||||
|
||||
if (iterator->multiple_expansion_state == IPSET_ITERATOR_MULTIPLE_IPV4) {
|
||||
DEBUG("Expanding IPv6 second");
|
||||
|
||||
iterator->multiple_expansion_state = IPSET_ITERATOR_MULTIPLE_IPV6;
|
||||
ipset_assignment_set
|
||||
(iterator->bdd_iterator->assignment, 0, IPSET_FALSE);
|
||||
expand_ipv6(iterator);
|
||||
return;
|
||||
}
|
||||
|
||||
/* If we've just finished the IPv6 expansion, then we've finished
|
||||
* with this assignment. Before moving on to the next one, we have
|
||||
* to reset variable 0 to EITHER (which it was before we started
|
||||
* this whole mess). */
|
||||
|
||||
if (iterator->multiple_expansion_state == IPSET_ITERATOR_MULTIPLE_IPV6) {
|
||||
DEBUG("Finished both expansions");
|
||||
|
||||
ipset_assignment_set
|
||||
(iterator->bdd_iterator->assignment, 0, IPSET_EITHER);
|
||||
ipset_bdd_iterator_advance(iterator->bdd_iterator);
|
||||
process_assignment(iterator);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Process the current expanded assignment in the current BDD
|
||||
* assignment.
|
||||
*/
|
||||
static void
|
||||
process_expanded_assignment(struct ipset_iterator *iterator)
|
||||
{
|
||||
if (iterator->assignment_iterator->finished) {
|
||||
/* If there isn't anything in the expanded assignment, advance
|
||||
* to the next BDD assignment. */
|
||||
|
||||
DEBUG("Expanded assignment is finished");
|
||||
ipset_expanded_assignment_free(iterator->assignment_iterator);
|
||||
iterator->assignment_iterator = NULL;
|
||||
advance_assignment(iterator);
|
||||
} else {
|
||||
/* Otherwise, we've found a fully expanded assignment, so create
|
||||
* an IP address for it and return. */
|
||||
create_ip_address(iterator);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Expand the current assignment as IPv4 addresses.
|
||||
*/
|
||||
static void
|
||||
expand_ipv4(struct ipset_iterator *iterator)
|
||||
{
|
||||
unsigned int last_bit;
|
||||
|
||||
if (iterator->summarize) {
|
||||
last_bit = find_last_non_either_bit
|
||||
(iterator->bdd_iterator->assignment, IPV4_BIT_SIZE);
|
||||
DEBUG("Last non-either bit is %u", last_bit);
|
||||
} else {
|
||||
last_bit = IPV4_BIT_SIZE;
|
||||
}
|
||||
|
||||
iterator->assignment_iterator =
|
||||
ipset_assignment_expand
|
||||
(iterator->bdd_iterator->assignment, last_bit + 1);
|
||||
iterator->cidr_prefix = last_bit;
|
||||
|
||||
process_expanded_assignment(iterator);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Expand the current assignment as IPv4 addresses.
|
||||
*/
|
||||
static void
|
||||
expand_ipv6(struct ipset_iterator *iterator)
|
||||
{
|
||||
unsigned int last_bit;
|
||||
|
||||
if (iterator->summarize) {
|
||||
last_bit = find_last_non_either_bit
|
||||
(iterator->bdd_iterator->assignment, IPV6_BIT_SIZE);
|
||||
DEBUG("Last non-either bit is %u", last_bit);
|
||||
} else {
|
||||
last_bit = IPV6_BIT_SIZE;
|
||||
}
|
||||
|
||||
iterator->assignment_iterator =
|
||||
ipset_assignment_expand
|
||||
(iterator->bdd_iterator->assignment, last_bit + 1);
|
||||
iterator->cidr_prefix = last_bit;
|
||||
|
||||
process_expanded_assignment(iterator);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Process the current assignment in the BDD iterator.
|
||||
*/
|
||||
|
||||
static void
|
||||
process_assignment(struct ipset_iterator *iterator)
|
||||
{
|
||||
while (!iterator->bdd_iterator->finished) {
|
||||
if (iterator->bdd_iterator->value == iterator->desired_value) {
|
||||
/* If the BDD iterator hasn't finished, and the result of
|
||||
* the function with this assignment matches what the caller
|
||||
* wants, then we've found an assignment to generate IP
|
||||
* addresses from.
|
||||
*
|
||||
* Try to expand this assignment, and process the first
|
||||
* expanded assignment. We want 32 + 1 variables if the
|
||||
* current address is IPv4; 128 + 1 if it's IPv6. */
|
||||
|
||||
DEBUG("Got a matching BDD assignment");
|
||||
enum ipset_tribool address_type = ipset_assignment_get
|
||||
(iterator->bdd_iterator->assignment, 0);
|
||||
|
||||
if (address_type == IPSET_FALSE) {
|
||||
/* FALSE means IPv6*/
|
||||
DEBUG("Assignment is IPv6");
|
||||
iterator->multiple_expansion_state = IPSET_ITERATOR_NORMAL;
|
||||
expand_ipv6(iterator);
|
||||
return;
|
||||
} else if (address_type == IPSET_TRUE) {
|
||||
/* TRUE means IPv4*/
|
||||
DEBUG("Assignment is IPv4");
|
||||
iterator->multiple_expansion_state = IPSET_ITERATOR_NORMAL;
|
||||
expand_ipv4(iterator);
|
||||
return;
|
||||
} else {
|
||||
/* EITHER means that this assignment contains both IPv4
|
||||
* and IPv6 addresses. Expand it as IPv4 first. */
|
||||
DEBUG("Assignment is both IPv4 and IPv6");
|
||||
DEBUG("Expanding IPv4 first");
|
||||
iterator->multiple_expansion_state =
|
||||
IPSET_ITERATOR_MULTIPLE_IPV4;
|
||||
ipset_assignment_set
|
||||
(iterator->bdd_iterator->assignment, 0, IPSET_TRUE);
|
||||
expand_ipv4(iterator);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* The BDD iterator has a value, but it doesn't match the one we
|
||||
* want. Advance the BDD iterator and try again. */
|
||||
DEBUG("Value is %d, skipping", iterator->bdd_iterator->value);
|
||||
ipset_bdd_iterator_advance(iterator->bdd_iterator);
|
||||
}
|
||||
|
||||
/* If we fall through, then the BDD iterator has finished. That
|
||||
* means there's nothing left for the set iterator. */
|
||||
|
||||
DEBUG("Set iterator is finished");
|
||||
ipset_expanded_assignment_free(iterator->assignment_iterator);
|
||||
iterator->assignment_iterator = NULL;
|
||||
|
||||
ipset_bdd_iterator_free(iterator->bdd_iterator);
|
||||
iterator->bdd_iterator = NULL;
|
||||
iterator->finished = true;
|
||||
}
|
||||
|
||||
|
||||
static struct ipset_iterator *
|
||||
create_iterator(struct ip_set *set, bool desired_value, bool summarize)
|
||||
{
|
||||
/* First allocate the iterator itself. */
|
||||
struct ipset_iterator *iterator = cork_new(struct ipset_iterator);
|
||||
iterator->finished = false;
|
||||
iterator->assignment_iterator = NULL;
|
||||
iterator->desired_value = desired_value;
|
||||
iterator->summarize = summarize;
|
||||
|
||||
/* Then create the iterator that returns each BDD assignment. */
|
||||
DEBUG("Iterating set");
|
||||
iterator->bdd_iterator = ipset_node_iterate(set->cache, set->set_bdd);
|
||||
|
||||
/* Then drill down from the current BDD assignment, creating an
|
||||
* expanded assignment for it. */
|
||||
process_assignment(iterator);
|
||||
return iterator;
|
||||
}
|
||||
|
||||
|
||||
struct ipset_iterator *
|
||||
ipset_iterate(struct ip_set *set, bool desired_value)
|
||||
{
|
||||
return create_iterator(set, desired_value, false);
|
||||
}
|
||||
|
||||
|
||||
struct ipset_iterator *
|
||||
ipset_iterate_networks(struct ip_set *set, bool desired_value)
|
||||
{
|
||||
return create_iterator(set, desired_value, true);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ipset_iterator_free(struct ipset_iterator *iterator)
|
||||
{
|
||||
if (iterator->bdd_iterator != NULL) {
|
||||
ipset_bdd_iterator_free(iterator->bdd_iterator);
|
||||
}
|
||||
if (iterator->assignment_iterator != NULL) {
|
||||
ipset_expanded_assignment_free(iterator->assignment_iterator);
|
||||
}
|
||||
free(iterator);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ipset_iterator_advance(struct ipset_iterator *iterator)
|
||||
{
|
||||
/* If we're already at the end of the iterator, don't do anything. */
|
||||
|
||||
if (CORK_UNLIKELY(iterator->finished)) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Otherwise, advance the expanded assignment iterator to the next
|
||||
* assignment, and then drill down into it. */
|
||||
|
||||
DEBUG("Advancing set iterator");
|
||||
ipset_expanded_assignment_advance(iterator->assignment_iterator);
|
||||
process_expanded_assignment(iterator);
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
/* -*- coding: utf-8 -*-
|
||||
* ----------------------------------------------------------------------
|
||||
* Copyright © 2010-2012, RedJack, LLC.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Please see the LICENSE.txt file in this distribution for license
|
||||
* details.
|
||||
* ----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <libcork/core.h>
|
||||
|
||||
#include "ipset/bdd/nodes.h"
|
||||
#include "ipset/errors.h"
|
||||
#include "ipset/ipset.h"
|
||||
|
||||
|
||||
static void
|
||||
create_errno_error(FILE *stream)
|
||||
{
|
||||
if (ferror(stream)) {
|
||||
cork_error_set(IPSET_ERROR, IPSET_IO_ERROR, "%s", strerror(errno));
|
||||
} else {
|
||||
cork_unknown_error();
|
||||
}
|
||||
}
|
||||
|
||||
struct file_consumer {
|
||||
/* file_consumer is a subclass of cork_stream_consumer */
|
||||
struct cork_stream_consumer parent;
|
||||
/* the file to write the data into */
|
||||
FILE *fp;
|
||||
};
|
||||
|
||||
static int
|
||||
file_consumer_data(struct cork_stream_consumer *vself,
|
||||
const void *buf, size_t size, bool is_first)
|
||||
{
|
||||
struct file_consumer *self =
|
||||
cork_container_of(vself, struct file_consumer, parent);
|
||||
size_t bytes_written = fwrite(buf, 1, size, self->fp);
|
||||
/* If there was an error writing to the file, then signal this to
|
||||
* the producer */
|
||||
if (bytes_written == size) {
|
||||
return 0;
|
||||
} else {
|
||||
create_errno_error(self->fp);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
file_consumer_eof(struct cork_stream_consumer *vself)
|
||||
{
|
||||
/* We don't close the file, so there's nothing special to do at
|
||||
* end-of-stream. */
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
ipset_save_to_stream(struct cork_stream_consumer *stream,
|
||||
const struct ip_set *set)
|
||||
{
|
||||
return ipset_node_cache_save(stream, set->cache, set->set_bdd);
|
||||
}
|
||||
|
||||
int
|
||||
ipset_save(FILE *fp, const struct ip_set *set)
|
||||
{
|
||||
struct file_consumer stream = {
|
||||
{ file_consumer_data, file_consumer_eof, NULL }, fp
|
||||
};
|
||||
return ipset_save_to_stream(&stream.parent, set);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
ipset_save_dot(FILE *fp, const struct ip_set *set)
|
||||
{
|
||||
struct file_consumer stream = {
|
||||
{ file_consumer_data, file_consumer_eof, NULL }, fp
|
||||
};
|
||||
return ipset_node_cache_save_dot(&stream.parent, set->cache, set->set_bdd);
|
||||
}
|
||||
|
||||
|
||||
struct ip_set *
|
||||
ipset_load(FILE *stream)
|
||||
{
|
||||
struct ip_set *set;
|
||||
ipset_node_id new_bdd;
|
||||
|
||||
set = ipset_new();
|
||||
new_bdd = ipset_node_cache_load(stream, set->cache);
|
||||
if (cork_error_occurred()) {
|
||||
ipset_free(set);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
set->set_bdd = new_bdd;
|
||||
return set;
|
||||
}
|
||||
Reference in new issue
Block a user