core-4.8/0000775000175000017500000000000012534330007007315 500000000000000core-4.8/config/0000775000175000017500000000000012534330007010562 500000000000000core-4.8/config/install-sh0000755000175000017500000003325512534327777012540 00000000000000#!/bin/sh # install - install a program, script, or datafile scriptversion=2011-11-20.07; # UTC # This originates from X11R5 (mit/util/scripts/install.sh), which was # later released in X11R6 (xc/config/util/install.sh) with the # following copyright and license. # # Copyright (C) 1994 X Consortium # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to # deal in the Software without restriction, including without limitation the # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or # sell copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN # AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC- # TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # # Except as contained in this notice, the name of the X Consortium shall not # be used in advertising or otherwise to promote the sale, use or other deal- # ings in this Software without prior written authorization from the X Consor- # tium. # # # FSF changes to this file are in the public domain. # # Calling this script install-sh is preferred over install.sh, to prevent # 'make' implicit rules from creating a file called install from it # when there is no Makefile. # # This script is compatible with the BSD install script, but was written # from scratch. nl=' ' IFS=" "" $nl" # set DOITPROG to echo to test this script # Don't use :- since 4.3BSD and earlier shells don't like it. doit=${DOITPROG-} if test -z "$doit"; then doit_exec=exec else doit_exec=$doit fi # Put in absolute file names if you don't have them in your path; # or use environment vars. chgrpprog=${CHGRPPROG-chgrp} chmodprog=${CHMODPROG-chmod} chownprog=${CHOWNPROG-chown} cmpprog=${CMPPROG-cmp} cpprog=${CPPROG-cp} mkdirprog=${MKDIRPROG-mkdir} mvprog=${MVPROG-mv} rmprog=${RMPROG-rm} stripprog=${STRIPPROG-strip} posix_glob='?' initialize_posix_glob=' test "$posix_glob" != "?" || { if (set -f) 2>/dev/null; then posix_glob= else posix_glob=: fi } ' posix_mkdir= # Desired mode of installed file. mode=0755 chgrpcmd= chmodcmd=$chmodprog chowncmd= mvcmd=$mvprog rmcmd="$rmprog -f" stripcmd= src= dst= dir_arg= dst_arg= copy_on_change=false no_target_directory= usage="\ Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE or: $0 [OPTION]... SRCFILES... DIRECTORY or: $0 [OPTION]... -t DIRECTORY SRCFILES... or: $0 [OPTION]... -d DIRECTORIES... In the 1st form, copy SRCFILE to DSTFILE. In the 2nd and 3rd, copy all SRCFILES to DIRECTORY. In the 4th, create DIRECTORIES. Options: --help display this help and exit. --version display version info and exit. -c (ignored) -C install only if different (preserve the last data modification time) -d create directories instead of installing files. -g GROUP $chgrpprog installed files to GROUP. -m MODE $chmodprog installed files to MODE. -o USER $chownprog installed files to USER. -s $stripprog installed files. -t DIRECTORY install into DIRECTORY. -T report an error if DSTFILE is a directory. Environment variables override the default commands: CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG RMPROG STRIPPROG " while test $# -ne 0; do case $1 in -c) ;; -C) copy_on_change=true;; -d) dir_arg=true;; -g) chgrpcmd="$chgrpprog $2" shift;; --help) echo "$usage"; exit $?;; -m) mode=$2 case $mode in *' '* | *' '* | *' '* | *'*'* | *'?'* | *'['*) echo "$0: invalid mode: $mode" >&2 exit 1;; esac shift;; -o) chowncmd="$chownprog $2" shift;; -s) stripcmd=$stripprog;; -t) dst_arg=$2 # Protect names problematic for 'test' and other utilities. case $dst_arg in -* | [=\(\)!]) dst_arg=./$dst_arg;; esac shift;; -T) no_target_directory=true;; --version) echo "$0 $scriptversion"; exit $?;; --) shift break;; -*) echo "$0: invalid option: $1" >&2 exit 1;; *) break;; esac shift done if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then # When -d is used, all remaining arguments are directories to create. # When -t is used, the destination is already specified. # Otherwise, the last argument is the destination. Remove it from $@. for arg do if test -n "$dst_arg"; then # $@ is not empty: it contains at least $arg. set fnord "$@" "$dst_arg" shift # fnord fi shift # arg dst_arg=$arg # Protect names problematic for 'test' and other utilities. case $dst_arg in -* | [=\(\)!]) dst_arg=./$dst_arg;; esac done fi if test $# -eq 0; then if test -z "$dir_arg"; then echo "$0: no input file specified." >&2 exit 1 fi # It's OK to call 'install-sh -d' without argument. # This can happen when creating conditional directories. exit 0 fi if test -z "$dir_arg"; then do_exit='(exit $ret); exit $ret' trap "ret=129; $do_exit" 1 trap "ret=130; $do_exit" 2 trap "ret=141; $do_exit" 13 trap "ret=143; $do_exit" 15 # Set umask so as not to create temps with too-generous modes. # However, 'strip' requires both read and write access to temps. case $mode in # Optimize common cases. *644) cp_umask=133;; *755) cp_umask=22;; *[0-7]) if test -z "$stripcmd"; then u_plus_rw= else u_plus_rw='% 200' fi cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;; *) if test -z "$stripcmd"; then u_plus_rw= else u_plus_rw=,u+rw fi cp_umask=$mode$u_plus_rw;; esac fi for src do # Protect names problematic for 'test' and other utilities. case $src in -* | [=\(\)!]) src=./$src;; esac if test -n "$dir_arg"; then dst=$src dstdir=$dst test -d "$dstdir" dstdir_status=$? else # Waiting for this to be detected by the "$cpprog $src $dsttmp" command # might cause directories to be created, which would be especially bad # if $src (and thus $dsttmp) contains '*'. if test ! -f "$src" && test ! -d "$src"; then echo "$0: $src does not exist." >&2 exit 1 fi if test -z "$dst_arg"; then echo "$0: no destination specified." >&2 exit 1 fi dst=$dst_arg # If destination is a directory, append the input filename; won't work # if double slashes aren't ignored. if test -d "$dst"; then if test -n "$no_target_directory"; then echo "$0: $dst_arg: Is a directory" >&2 exit 1 fi dstdir=$dst dst=$dstdir/`basename "$src"` dstdir_status=0 else # Prefer dirname, but fall back on a substitute if dirname fails. dstdir=` (dirname "$dst") 2>/dev/null || expr X"$dst" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$dst" : 'X\(//\)[^/]' \| \ X"$dst" : 'X\(//\)$' \| \ X"$dst" : 'X\(/\)' \| . 2>/dev/null || echo X"$dst" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q' ` test -d "$dstdir" dstdir_status=$? fi fi obsolete_mkdir_used=false if test $dstdir_status != 0; then case $posix_mkdir in '') # Create intermediate dirs using mode 755 as modified by the umask. # This is like FreeBSD 'install' as of 1997-10-28. umask=`umask` case $stripcmd.$umask in # Optimize common cases. *[2367][2367]) mkdir_umask=$umask;; .*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;; *[0-7]) mkdir_umask=`expr $umask + 22 \ - $umask % 100 % 40 + $umask % 20 \ - $umask % 10 % 4 + $umask % 2 `;; *) mkdir_umask=$umask,go-w;; esac # With -d, create the new directory with the user-specified mode. # Otherwise, rely on $mkdir_umask. if test -n "$dir_arg"; then mkdir_mode=-m$mode else mkdir_mode= fi posix_mkdir=false case $umask in *[123567][0-7][0-7]) # POSIX mkdir -p sets u+wx bits regardless of umask, which # is incompatible with FreeBSD 'install' when (umask & 300) != 0. ;; *) tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$ trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0 if (umask $mkdir_umask && exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/dev/null 2>&1 then if test -z "$dir_arg" || { # Check for POSIX incompatibilities with -m. # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or # other-writable bit of parent directory when it shouldn't. # FreeBSD 6.1 mkdir -m -p sets mode of existing directory. ls_ld_tmpdir=`ls -ld "$tmpdir"` case $ls_ld_tmpdir in d????-?r-*) different_mode=700;; d????-?--*) different_mode=755;; *) false;; esac && $mkdirprog -m$different_mode -p -- "$tmpdir" && { ls_ld_tmpdir_1=`ls -ld "$tmpdir"` test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1" } } then posix_mkdir=: fi rmdir "$tmpdir/d" "$tmpdir" else # Remove any dirs left behind by ancient mkdir implementations. rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null fi trap '' 0;; esac;; esac if $posix_mkdir && ( umask $mkdir_umask && $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir" ) then : else # The umask is ridiculous, or mkdir does not conform to POSIX, # or it failed possibly due to a race condition. Create the # directory the slow way, step by step, checking for races as we go. case $dstdir in /*) prefix='/';; [-=\(\)!]*) prefix='./';; *) prefix='';; esac eval "$initialize_posix_glob" oIFS=$IFS IFS=/ $posix_glob set -f set fnord $dstdir shift $posix_glob set +f IFS=$oIFS prefixes= for d do test X"$d" = X && continue prefix=$prefix$d if test -d "$prefix"; then prefixes= else if $posix_mkdir; then (umask=$mkdir_umask && $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break # Don't fail if two instances are running concurrently. test -d "$prefix" || exit 1 else case $prefix in *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;; *) qprefix=$prefix;; esac prefixes="$prefixes '$qprefix'" fi fi prefix=$prefix/ done if test -n "$prefixes"; then # Don't fail if two instances are running concurrently. (umask $mkdir_umask && eval "\$doit_exec \$mkdirprog $prefixes") || test -d "$dstdir" || exit 1 obsolete_mkdir_used=true fi fi fi if test -n "$dir_arg"; then { test -z "$chowncmd" || $doit $chowncmd "$dst"; } && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } && { test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false || test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1 else # Make a couple of temp file names in the proper directory. dsttmp=$dstdir/_inst.$$_ rmtmp=$dstdir/_rm.$$_ # Trap to clean up those temp files at exit. trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0 # Copy the file name to the temp name. (umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") && # and set any options; do chmod last to preserve setuid bits. # # If any of these fail, we abort the whole thing. If we want to # ignore errors from any of these, just make sure not to ignore # errors from the above "$doit $cpprog $src $dsttmp" command. # { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } && { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } && { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } && # If -C, don't bother to copy if it wouldn't change the file. if $copy_on_change && old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` && new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` && eval "$initialize_posix_glob" && $posix_glob set -f && set X $old && old=:$2:$4:$5:$6 && set X $new && new=:$2:$4:$5:$6 && $posix_glob set +f && test "$old" = "$new" && $cmpprog "$dst" "$dsttmp" >/dev/null 2>&1 then rm -f "$dsttmp" else # Rename the file to the real destination. $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null || # The rename failed, perhaps because mv can't rename something else # to itself, or perhaps because mv is so ancient that it does not # support -f. { # Now remove or move aside any old file at destination location. # We try this two ways since rm can't unlink itself on some # systems and the destination file might be busy for other # reasons. In this case, the final cleanup might fail but the new # file should still install successfully. { test ! -f "$dst" || $doit $rmcmd -f "$dst" 2>/dev/null || { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null && { $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; } } || { echo "$0: cannot unlink or rename $dst" >&2 (exit 1); exit 1 } } && # Now rename the file to the real destination. $doit $mvcmd "$dsttmp" "$dst" } fi || exit 1 trap '' 0 fi done # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC" # time-stamp-end: "; # UTC" # End: core-4.8/config/missing0000755000175000017500000001533112534327777012126 00000000000000#! /bin/sh # Common wrapper for a few potentially missing GNU programs. scriptversion=2012-06-26.16; # UTC # Copyright (C) 1996-2013 Free Software Foundation, Inc. # Originally written by Fran,cois Pinard , 1996. # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # This program 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 General Public License for more details. # You should have received a copy of the GNU General Public License # along with this program. If not, see . # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. if test $# -eq 0; then echo 1>&2 "Try '$0 --help' for more information" exit 1 fi case $1 in --is-lightweight) # Used by our autoconf macros to check whether the available missing # script is modern enough. exit 0 ;; --run) # Back-compat with the calling convention used by older automake. shift ;; -h|--h|--he|--hel|--help) echo "\ $0 [OPTION]... PROGRAM [ARGUMENT]... Run 'PROGRAM [ARGUMENT]...', returning a proper advice when this fails due to PROGRAM being missing or too old. Options: -h, --help display this help and exit -v, --version output version information and exit Supported PROGRAM values: aclocal autoconf autoheader autom4te automake makeinfo bison yacc flex lex help2man Version suffixes to PROGRAM as well as the prefixes 'gnu-', 'gnu', and 'g' are ignored when checking the name. Send bug reports to ." exit $? ;; -v|--v|--ve|--ver|--vers|--versi|--versio|--version) echo "missing $scriptversion (GNU Automake)" exit $? ;; -*) echo 1>&2 "$0: unknown '$1' option" echo 1>&2 "Try '$0 --help' for more information" exit 1 ;; esac # Run the given program, remember its exit status. "$@"; st=$? # If it succeeded, we are done. test $st -eq 0 && exit 0 # Also exit now if we it failed (or wasn't found), and '--version' was # passed; such an option is passed most likely to detect whether the # program is present and works. case $2 in --version|--help) exit $st;; esac # Exit code 63 means version mismatch. This often happens when the user # tries to use an ancient version of a tool on a file that requires a # minimum version. if test $st -eq 63; then msg="probably too old" elif test $st -eq 127; then # Program was missing. msg="missing on your system" else # Program was found and executed, but failed. Give up. exit $st fi perl_URL=http://www.perl.org/ flex_URL=http://flex.sourceforge.net/ gnu_software_URL=http://www.gnu.org/software program_details () { case $1 in aclocal|automake) echo "The '$1' program is part of the GNU Automake package:" echo "<$gnu_software_URL/automake>" echo "It also requires GNU Autoconf, GNU m4 and Perl in order to run:" echo "<$gnu_software_URL/autoconf>" echo "<$gnu_software_URL/m4/>" echo "<$perl_URL>" ;; autoconf|autom4te|autoheader) echo "The '$1' program is part of the GNU Autoconf package:" echo "<$gnu_software_URL/autoconf/>" echo "It also requires GNU m4 and Perl in order to run:" echo "<$gnu_software_URL/m4/>" echo "<$perl_URL>" ;; esac } give_advice () { # Normalize program name to check for. normalized_program=`echo "$1" | sed ' s/^gnu-//; t s/^gnu//; t s/^g//; t'` printf '%s\n' "'$1' is $msg." configure_deps="'configure.ac' or m4 files included by 'configure.ac'" case $normalized_program in autoconf*) echo "You should only need it if you modified 'configure.ac'," echo "or m4 files included by it." program_details 'autoconf' ;; autoheader*) echo "You should only need it if you modified 'acconfig.h' or" echo "$configure_deps." program_details 'autoheader' ;; automake*) echo "You should only need it if you modified 'Makefile.am' or" echo "$configure_deps." program_details 'automake' ;; aclocal*) echo "You should only need it if you modified 'acinclude.m4' or" echo "$configure_deps." program_details 'aclocal' ;; autom4te*) echo "You might have modified some maintainer files that require" echo "the 'automa4te' program to be rebuilt." program_details 'autom4te' ;; bison*|yacc*) echo "You should only need it if you modified a '.y' file." echo "You may want to install the GNU Bison package:" echo "<$gnu_software_URL/bison/>" ;; lex*|flex*) echo "You should only need it if you modified a '.l' file." echo "You may want to install the Fast Lexical Analyzer package:" echo "<$flex_URL>" ;; help2man*) echo "You should only need it if you modified a dependency" \ "of a man page." echo "You may want to install the GNU Help2man package:" echo "<$gnu_software_URL/help2man/>" ;; makeinfo*) echo "You should only need it if you modified a '.texi' file, or" echo "any other file indirectly affecting the aspect of the manual." echo "You might want to install the Texinfo package:" echo "<$gnu_software_URL/texinfo/>" echo "The spurious makeinfo call might also be the consequence of" echo "using a buggy 'make' (AIX, DU, IRIX), in which case you might" echo "want to install GNU make:" echo "<$gnu_software_URL/make/>" ;; *) echo "You might have modified some files without having the proper" echo "tools for further handling them. Check the 'README' file, it" echo "often tells you about the needed prerequisites for installing" echo "this package. You may also peek at any GNU archive site, in" echo "case some other package contains this missing '$1' program." ;; esac } give_advice "$1" | sed -e '1s/^/WARNING: /' \ -e '2,$s/^/ /' >&2 # Propagate the correct exit status (expected to be 127 for a program # not found, 63 for a program that failed due to version mismatch). exit $st # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC" # time-stamp-end: "; # UTC" # End: core-4.8/config/depcomp0000755000175000017500000005601612534330000012056 00000000000000#! /bin/sh # depcomp - compile a program generating dependencies as side-effects scriptversion=2013-05-30.07; # UTC # Copyright (C) 1999-2013 Free Software Foundation, Inc. # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # This program 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 General Public License for more details. # You should have received a copy of the GNU General Public License # along with this program. If not, see . # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # Originally written by Alexandre Oliva . case $1 in '') echo "$0: No command. Try '$0 --help' for more information." 1>&2 exit 1; ;; -h | --h*) cat <<\EOF Usage: depcomp [--help] [--version] PROGRAM [ARGS] Run PROGRAMS ARGS to compile a file, generating dependencies as side-effects. Environment variables: depmode Dependency tracking mode. source Source file read by 'PROGRAMS ARGS'. object Object file output by 'PROGRAMS ARGS'. DEPDIR directory where to store dependencies. depfile Dependency file to output. tmpdepfile Temporary file to use when outputting dependencies. libtool Whether libtool is used (yes/no). Report bugs to . EOF exit $? ;; -v | --v*) echo "depcomp $scriptversion" exit $? ;; esac # Get the directory component of the given path, and save it in the # global variables '$dir'. Note that this directory component will # be either empty or ending with a '/' character. This is deliberate. set_dir_from () { case $1 in */*) dir=`echo "$1" | sed -e 's|/[^/]*$|/|'`;; *) dir=;; esac } # Get the suffix-stripped basename of the given path, and save it the # global variable '$base'. set_base_from () { base=`echo "$1" | sed -e 's|^.*/||' -e 's/\.[^.]*$//'` } # If no dependency file was actually created by the compiler invocation, # we still have to create a dummy depfile, to avoid errors with the # Makefile "include basename.Plo" scheme. make_dummy_depfile () { echo "#dummy" > "$depfile" } # Factor out some common post-processing of the generated depfile. # Requires the auxiliary global variable '$tmpdepfile' to be set. aix_post_process_depfile () { # If the compiler actually managed to produce a dependency file, # post-process it. if test -f "$tmpdepfile"; then # Each line is of the form 'foo.o: dependency.h'. # Do two passes, one to just change these to # $object: dependency.h # and one to simply output # dependency.h: # which is needed to avoid the deleted-header problem. { sed -e "s,^.*\.[$lower]*:,$object:," < "$tmpdepfile" sed -e "s,^.*\.[$lower]*:[$tab ]*,," -e 's,$,:,' < "$tmpdepfile" } > "$depfile" rm -f "$tmpdepfile" else make_dummy_depfile fi } # A tabulation character. tab=' ' # A newline character. nl=' ' # Character ranges might be problematic outside the C locale. # These definitions help. upper=ABCDEFGHIJKLMNOPQRSTUVWXYZ lower=abcdefghijklmnopqrstuvwxyz digits=0123456789 alpha=${upper}${lower} if test -z "$depmode" || test -z "$source" || test -z "$object"; then echo "depcomp: Variables source, object and depmode must be set" 1>&2 exit 1 fi # Dependencies for sub/bar.o or sub/bar.obj go into sub/.deps/bar.Po. depfile=${depfile-`echo "$object" | sed 's|[^\\/]*$|'${DEPDIR-.deps}'/&|;s|\.\([^.]*\)$|.P\1|;s|Pobj$|Po|'`} tmpdepfile=${tmpdepfile-`echo "$depfile" | sed 's/\.\([^.]*\)$/.T\1/'`} rm -f "$tmpdepfile" # Avoid interferences from the environment. gccflag= dashmflag= # Some modes work just like other modes, but use different flags. We # parameterize here, but still list the modes in the big case below, # to make depend.m4 easier to write. Note that we *cannot* use a case # here, because this file can only contain one case statement. if test "$depmode" = hp; then # HP compiler uses -M and no extra arg. gccflag=-M depmode=gcc fi if test "$depmode" = dashXmstdout; then # This is just like dashmstdout with a different argument. dashmflag=-xM depmode=dashmstdout fi cygpath_u="cygpath -u -f -" if test "$depmode" = msvcmsys; then # This is just like msvisualcpp but w/o cygpath translation. # Just convert the backslash-escaped backslashes to single forward # slashes to satisfy depend.m4 cygpath_u='sed s,\\\\,/,g' depmode=msvisualcpp fi if test "$depmode" = msvc7msys; then # This is just like msvc7 but w/o cygpath translation. # Just convert the backslash-escaped backslashes to single forward # slashes to satisfy depend.m4 cygpath_u='sed s,\\\\,/,g' depmode=msvc7 fi if test "$depmode" = xlc; then # IBM C/C++ Compilers xlc/xlC can output gcc-like dependency information. gccflag=-qmakedep=gcc,-MF depmode=gcc fi case "$depmode" in gcc3) ## gcc 3 implements dependency tracking that does exactly what ## we want. Yay! Note: for some reason libtool 1.4 doesn't like ## it if -MD -MP comes after the -MF stuff. Hmm. ## Unfortunately, FreeBSD c89 acceptance of flags depends upon ## the command line argument order; so add the flags where they ## appear in depend2.am. Note that the slowdown incurred here ## affects only configure: in makefiles, %FASTDEP% shortcuts this. for arg do case $arg in -c) set fnord "$@" -MT "$object" -MD -MP -MF "$tmpdepfile" "$arg" ;; *) set fnord "$@" "$arg" ;; esac shift # fnord shift # $arg done "$@" stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile" exit $stat fi mv "$tmpdepfile" "$depfile" ;; gcc) ## Note that this doesn't just cater to obsosete pre-3.x GCC compilers. ## but also to in-use compilers like IMB xlc/xlC and the HP C compiler. ## (see the conditional assignment to $gccflag above). ## There are various ways to get dependency output from gcc. Here's ## why we pick this rather obscure method: ## - Don't want to use -MD because we'd like the dependencies to end ## up in a subdir. Having to rename by hand is ugly. ## (We might end up doing this anyway to support other compilers.) ## - The DEPENDENCIES_OUTPUT environment variable makes gcc act like ## -MM, not -M (despite what the docs say). Also, it might not be ## supported by the other compilers which use the 'gcc' depmode. ## - Using -M directly means running the compiler twice (even worse ## than renaming). if test -z "$gccflag"; then gccflag=-MD, fi "$@" -Wp,"$gccflag$tmpdepfile" stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" echo "$object : \\" > "$depfile" # The second -e expression handles DOS-style file names with drive # letters. sed -e 's/^[^:]*: / /' \ -e 's/^['$alpha']:\/[^:]*: / /' < "$tmpdepfile" >> "$depfile" ## This next piece of magic avoids the "deleted header file" problem. ## The problem is that when a header file which appears in a .P file ## is deleted, the dependency causes make to die (because there is ## typically no way to rebuild the header). We avoid this by adding ## dummy dependencies for each header file. Too bad gcc doesn't do ## this for us directly. ## Some versions of gcc put a space before the ':'. On the theory ## that the space means something, we add a space to the output as ## well. hp depmode also adds that space, but also prefixes the VPATH ## to the object. Take care to not repeat it in the output. ## Some versions of the HPUX 10.20 sed can't process this invocation ## correctly. Breaking it into two sed invocations is a workaround. tr ' ' "$nl" < "$tmpdepfile" \ | sed -e 's/^\\$//' -e '/^$/d' -e "s|.*$object$||" -e '/:$/d' \ | sed -e 's/$/ :/' >> "$depfile" rm -f "$tmpdepfile" ;; hp) # This case exists only to let depend.m4 do its work. It works by # looking at the text of this script. This case will never be run, # since it is checked for above. exit 1 ;; sgi) if test "$libtool" = yes; then "$@" "-Wp,-MDupdate,$tmpdepfile" else "$@" -MDupdate "$tmpdepfile" fi stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" if test -f "$tmpdepfile"; then # yes, the sourcefile depend on other files echo "$object : \\" > "$depfile" # Clip off the initial element (the dependent). Don't try to be # clever and replace this with sed code, as IRIX sed won't handle # lines with more than a fixed number of characters (4096 in # IRIX 6.2 sed, 8192 in IRIX 6.5). We also remove comment lines; # the IRIX cc adds comments like '#:fec' to the end of the # dependency line. tr ' ' "$nl" < "$tmpdepfile" \ | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' \ | tr "$nl" ' ' >> "$depfile" echo >> "$depfile" # The second pass generates a dummy entry for each header file. tr ' ' "$nl" < "$tmpdepfile" \ | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \ >> "$depfile" else make_dummy_depfile fi rm -f "$tmpdepfile" ;; xlc) # This case exists only to let depend.m4 do its work. It works by # looking at the text of this script. This case will never be run, # since it is checked for above. exit 1 ;; aix) # The C for AIX Compiler uses -M and outputs the dependencies # in a .u file. In older versions, this file always lives in the # current directory. Also, the AIX compiler puts '$object:' at the # start of each line; $object doesn't have directory information. # Version 6 uses the directory in both cases. set_dir_from "$object" set_base_from "$object" if test "$libtool" = yes; then tmpdepfile1=$dir$base.u tmpdepfile2=$base.u tmpdepfile3=$dir.libs/$base.u "$@" -Wc,-M else tmpdepfile1=$dir$base.u tmpdepfile2=$dir$base.u tmpdepfile3=$dir$base.u "$@" -M fi stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" exit $stat fi for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" do test -f "$tmpdepfile" && break done aix_post_process_depfile ;; tcc) # tcc (Tiny C Compiler) understand '-MD -MF file' since version 0.9.26 # FIXME: That version still under development at the moment of writing. # Make that this statement remains true also for stable, released # versions. # It will wrap lines (doesn't matter whether long or short) with a # trailing '\', as in: # # foo.o : \ # foo.c \ # foo.h \ # # It will put a trailing '\' even on the last line, and will use leading # spaces rather than leading tabs (at least since its commit 0394caf7 # "Emit spaces for -MD"). "$@" -MD -MF "$tmpdepfile" stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" # Each non-empty line is of the form 'foo.o : \' or ' dep.h \'. # We have to change lines of the first kind to '$object: \'. sed -e "s|.*:|$object :|" < "$tmpdepfile" > "$depfile" # And for each line of the second kind, we have to emit a 'dep.h:' # dummy dependency, to avoid the deleted-header problem. sed -n -e 's|^ *\(.*\) *\\$|\1:|p' < "$tmpdepfile" >> "$depfile" rm -f "$tmpdepfile" ;; ## The order of this option in the case statement is important, since the ## shell code in configure will try each of these formats in the order ## listed in this file. A plain '-MD' option would be understood by many ## compilers, so we must ensure this comes after the gcc and icc options. pgcc) # Portland's C compiler understands '-MD'. # Will always output deps to 'file.d' where file is the root name of the # source file under compilation, even if file resides in a subdirectory. # The object file name does not affect the name of the '.d' file. # pgcc 10.2 will output # foo.o: sub/foo.c sub/foo.h # and will wrap long lines using '\' : # foo.o: sub/foo.c ... \ # sub/foo.h ... \ # ... set_dir_from "$object" # Use the source, not the object, to determine the base name, since # that's sadly what pgcc will do too. set_base_from "$source" tmpdepfile=$base.d # For projects that build the same source file twice into different object # files, the pgcc approach of using the *source* file root name can cause # problems in parallel builds. Use a locking strategy to avoid stomping on # the same $tmpdepfile. lockdir=$base.d-lock trap " echo '$0: caught signal, cleaning up...' >&2 rmdir '$lockdir' exit 1 " 1 2 13 15 numtries=100 i=$numtries while test $i -gt 0; do # mkdir is a portable test-and-set. if mkdir "$lockdir" 2>/dev/null; then # This process acquired the lock. "$@" -MD stat=$? # Release the lock. rmdir "$lockdir" break else # If the lock is being held by a different process, wait # until the winning process is done or we timeout. while test -d "$lockdir" && test $i -gt 0; do sleep 1 i=`expr $i - 1` done fi i=`expr $i - 1` done trap - 1 2 13 15 if test $i -le 0; then echo "$0: failed to acquire lock after $numtries attempts" >&2 echo "$0: check lockdir '$lockdir'" >&2 exit 1 fi if test $stat -ne 0; then rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" # Each line is of the form `foo.o: dependent.h', # or `foo.o: dep1.h dep2.h \', or ` dep3.h dep4.h \'. # Do two passes, one to just change these to # `$object: dependent.h' and one to simply `dependent.h:'. sed "s,^[^:]*:,$object :," < "$tmpdepfile" > "$depfile" # Some versions of the HPUX 10.20 sed can't process this invocation # correctly. Breaking it into two sed invocations is a workaround. sed 's,^[^:]*: \(.*\)$,\1,;s/^\\$//;/^$/d;/:$/d' < "$tmpdepfile" \ | sed -e 's/$/ :/' >> "$depfile" rm -f "$tmpdepfile" ;; hp2) # The "hp" stanza above does not work with aCC (C++) and HP's ia64 # compilers, which have integrated preprocessors. The correct option # to use with these is +Maked; it writes dependencies to a file named # 'foo.d', which lands next to the object file, wherever that # happens to be. # Much of this is similar to the tru64 case; see comments there. set_dir_from "$object" set_base_from "$object" if test "$libtool" = yes; then tmpdepfile1=$dir$base.d tmpdepfile2=$dir.libs/$base.d "$@" -Wc,+Maked else tmpdepfile1=$dir$base.d tmpdepfile2=$dir$base.d "$@" +Maked fi stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile1" "$tmpdepfile2" exit $stat fi for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" do test -f "$tmpdepfile" && break done if test -f "$tmpdepfile"; then sed -e "s,^.*\.[$lower]*:,$object:," "$tmpdepfile" > "$depfile" # Add 'dependent.h:' lines. sed -ne '2,${ s/^ *// s/ \\*$// s/$/:/ p }' "$tmpdepfile" >> "$depfile" else make_dummy_depfile fi rm -f "$tmpdepfile" "$tmpdepfile2" ;; tru64) # The Tru64 compiler uses -MD to generate dependencies as a side # effect. 'cc -MD -o foo.o ...' puts the dependencies into 'foo.o.d'. # At least on Alpha/Redhat 6.1, Compaq CCC V6.2-504 seems to put # dependencies in 'foo.d' instead, so we check for that too. # Subdirectories are respected. set_dir_from "$object" set_base_from "$object" if test "$libtool" = yes; then # Libtool generates 2 separate objects for the 2 libraries. These # two compilations output dependencies in $dir.libs/$base.o.d and # in $dir$base.o.d. We have to check for both files, because # one of the two compilations can be disabled. We should prefer # $dir$base.o.d over $dir.libs/$base.o.d because the latter is # automatically cleaned when .libs/ is deleted, while ignoring # the former would cause a distcleancheck panic. tmpdepfile1=$dir$base.o.d # libtool 1.5 tmpdepfile2=$dir.libs/$base.o.d # Likewise. tmpdepfile3=$dir.libs/$base.d # Compaq CCC V6.2-504 "$@" -Wc,-MD else tmpdepfile1=$dir$base.d tmpdepfile2=$dir$base.d tmpdepfile3=$dir$base.d "$@" -MD fi stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" exit $stat fi for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" do test -f "$tmpdepfile" && break done # Same post-processing that is required for AIX mode. aix_post_process_depfile ;; msvc7) if test "$libtool" = yes; then showIncludes=-Wc,-showIncludes else showIncludes=-showIncludes fi "$@" $showIncludes > "$tmpdepfile" stat=$? grep -v '^Note: including file: ' "$tmpdepfile" if test $stat -ne 0; then rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" echo "$object : \\" > "$depfile" # The first sed program below extracts the file names and escapes # backslashes for cygpath. The second sed program outputs the file # name when reading, but also accumulates all include files in the # hold buffer in order to output them again at the end. This only # works with sed implementations that can handle large buffers. sed < "$tmpdepfile" -n ' /^Note: including file: *\(.*\)/ { s//\1/ s/\\/\\\\/g p }' | $cygpath_u | sort -u | sed -n ' s/ /\\ /g s/\(.*\)/'"$tab"'\1 \\/p s/.\(.*\) \\/\1:/ H $ { s/.*/'"$tab"'/ G p }' >> "$depfile" echo >> "$depfile" # make sure the fragment doesn't end with a backslash rm -f "$tmpdepfile" ;; msvc7msys) # This case exists only to let depend.m4 do its work. It works by # looking at the text of this script. This case will never be run, # since it is checked for above. exit 1 ;; #nosideeffect) # This comment above is used by automake to tell side-effect # dependency tracking mechanisms from slower ones. dashmstdout) # Important note: in order to support this mode, a compiler *must* # always write the preprocessed file to stdout, regardless of -o. "$@" || exit $? # Remove the call to Libtool. if test "$libtool" = yes; then while test "X$1" != 'X--mode=compile'; do shift done shift fi # Remove '-o $object'. IFS=" " for arg do case $arg in -o) shift ;; $object) shift ;; *) set fnord "$@" "$arg" shift # fnord shift # $arg ;; esac done test -z "$dashmflag" && dashmflag=-M # Require at least two characters before searching for ':' # in the target name. This is to cope with DOS-style filenames: # a dependency such as 'c:/foo/bar' could be seen as target 'c' otherwise. "$@" $dashmflag | sed "s|^[$tab ]*[^:$tab ][^:][^:]*:[$tab ]*|$object: |" > "$tmpdepfile" rm -f "$depfile" cat < "$tmpdepfile" > "$depfile" # Some versions of the HPUX 10.20 sed can't process this sed invocation # correctly. Breaking it into two sed invocations is a workaround. tr ' ' "$nl" < "$tmpdepfile" \ | sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' \ | sed -e 's/$/ :/' >> "$depfile" rm -f "$tmpdepfile" ;; dashXmstdout) # This case only exists to satisfy depend.m4. It is never actually # run, as this mode is specially recognized in the preamble. exit 1 ;; makedepend) "$@" || exit $? # Remove any Libtool call if test "$libtool" = yes; then while test "X$1" != 'X--mode=compile'; do shift done shift fi # X makedepend shift cleared=no eat=no for arg do case $cleared in no) set ""; shift cleared=yes ;; esac if test $eat = yes; then eat=no continue fi case "$arg" in -D*|-I*) set fnord "$@" "$arg"; shift ;; # Strip any option that makedepend may not understand. Remove # the object too, otherwise makedepend will parse it as a source file. -arch) eat=yes ;; -*|$object) ;; *) set fnord "$@" "$arg"; shift ;; esac done obj_suffix=`echo "$object" | sed 's/^.*\././'` touch "$tmpdepfile" ${MAKEDEPEND-makedepend} -o"$obj_suffix" -f"$tmpdepfile" "$@" rm -f "$depfile" # makedepend may prepend the VPATH from the source file name to the object. # No need to regex-escape $object, excess matching of '.' is harmless. sed "s|^.*\($object *:\)|\1|" "$tmpdepfile" > "$depfile" # Some versions of the HPUX 10.20 sed can't process the last invocation # correctly. Breaking it into two sed invocations is a workaround. sed '1,2d' "$tmpdepfile" \ | tr ' ' "$nl" \ | sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' \ | sed -e 's/$/ :/' >> "$depfile" rm -f "$tmpdepfile" "$tmpdepfile".bak ;; cpp) # Important note: in order to support this mode, a compiler *must* # always write the preprocessed file to stdout. "$@" || exit $? # Remove the call to Libtool. if test "$libtool" = yes; then while test "X$1" != 'X--mode=compile'; do shift done shift fi # Remove '-o $object'. IFS=" " for arg do case $arg in -o) shift ;; $object) shift ;; *) set fnord "$@" "$arg" shift # fnord shift # $arg ;; esac done "$@" -E \ | sed -n -e '/^# [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \ -e '/^#line [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \ | sed '$ s: \\$::' > "$tmpdepfile" rm -f "$depfile" echo "$object : \\" > "$depfile" cat < "$tmpdepfile" >> "$depfile" sed < "$tmpdepfile" '/^$/d;s/^ //;s/ \\$//;s/$/ :/' >> "$depfile" rm -f "$tmpdepfile" ;; msvisualcpp) # Important note: in order to support this mode, a compiler *must* # always write the preprocessed file to stdout. "$@" || exit $? # Remove the call to Libtool. if test "$libtool" = yes; then while test "X$1" != 'X--mode=compile'; do shift done shift fi IFS=" " for arg do case "$arg" in -o) shift ;; $object) shift ;; "-Gm"|"/Gm"|"-Gi"|"/Gi"|"-ZI"|"/ZI") set fnord "$@" shift shift ;; *) set fnord "$@" "$arg" shift shift ;; esac done "$@" -E 2>/dev/null | sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::\1:p' | $cygpath_u | sort -u > "$tmpdepfile" rm -f "$depfile" echo "$object : \\" > "$depfile" sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::'"$tab"'\1 \\:p' >> "$depfile" echo "$tab" >> "$depfile" sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::\1\::p' >> "$depfile" rm -f "$tmpdepfile" ;; msvcmsys) # This case exists only to let depend.m4 do its work. It works by # looking at the text of this script. This case will never be run, # since it is checked for above. exit 1 ;; none) exec "$@" ;; *) echo "Unknown depmode $depmode" 1>&2 exit 1 ;; esac exit 0 # Local Variables: # mode: shell-script # sh-indentation: 2 # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC" # time-stamp-end: "; # UTC" # End: core-4.8/daemon/0000775000175000017500000000000012534330007010560 500000000000000core-4.8/daemon/core/0000775000175000017500000000000012534330005011506 500000000000000core-4.8/daemon/core/constants.py.in0000664000175000017500000000143012534327775014443 00000000000000# Constants created by autoconf ./configure script COREDPY_VERSION = "@COREDPY_VERSION@" CORE_STATE_DIR = "@CORE_STATE_DIR@" CORE_CONF_DIR = "@CORE_CONF_DIR@" CORE_DATA_DIR = "@CORE_DATA_DIR@" CORE_LIB_DIR = "@CORE_LIB_DIR@" CORE_SBIN_DIR = "@SBINDIR@" BRCTL_BIN = "@brctl_path@/brctl" SYSCTL_BIN = "@sysctl_path@/sysctl" IP_BIN = "@ip_path@/ip" TC_BIN = "@tc_path@/tc" EBTABLES_BIN = "@ebtables_path@/ebtables" IFCONFIG_BIN = "@ifconfig_path@/ifconfig" NGCTL_BIN = "@ngctl_path@/ngctl" VIMAGE_BIN = "@vimage_path@/vimage" QUAGGA_STATE_DIR = "@CORE_STATE_DIR@/run/quagga" MOUNT_BIN = "@mount_path@/mount" UMOUNT_BIN = "@umount_path@/umount" core-4.8/daemon/core/.gitignore0000664000175000017500000000001512534327775013436 00000000000000constants.py core-4.8/daemon/core/__init__.py0000664000175000017500000000103312534327775013560 00000000000000# Copyright (c)2010-2012 the Boeing Company. # See the LICENSE file included in this distribution. """core Top-level Python package containing CORE components. See http://www.nrl.navy.mil/itd/ncs/products/core and http://code.google.com/p/coreemu/ for more information on CORE. Pieces can be imported individually, for example import core.netns.vnode or everything listed in __all__ can be imported using from core import * """ __all__ = [] # Automatically import all add-ons listed in addons.__all__ from addons import * core-4.8/daemon/core/addons/0000775000175000017500000000000012534327775013002 500000000000000core-4.8/daemon/core/addons/__init__.py0000664000175000017500000000024012534327775015027 00000000000000"""Optional add-ons Add on files can be put in this directory. Everything listed in __all__ is automatically loaded by the main core module. """ __all__ = [] core-4.8/daemon/core/api/0000775000175000017500000000000012534327775012303 500000000000000core-4.8/daemon/core/api/__init__.py0000664000175000017500000000000012534327775014322 00000000000000core-4.8/daemon/core/api/coreapi.py0000664000175000017500000004653412534327775014233 00000000000000# # CORE # Copyright (c)2010-2013 the Boeing Company. # See the LICENSE file included in this distribution. # # authors: Tom Goff # Jeff Ahrenholz # ''' coreapi.py: uses coreapi_data for Message and TLV types, and defines TLV data types and objects used for parsing and building CORE API messages. ''' import struct from core.api.data import * from core.misc.ipaddr import * class CoreTlvData(object): datafmt = None datatype = None padlen = None @classmethod def pack(cls, value): "return: (tlvlen, tlvdata)" tmp = struct.pack(cls.datafmt, value) return len(tmp) - cls.padlen, tmp @classmethod def unpack(cls, data): return struct.unpack(cls.datafmt, data)[0] @classmethod def packstring(cls, strvalue): return cls.pack(cls.fromstring(strvalue)) @classmethod def fromstring(cls, s): return cls.datatype(s) class CoreTlvDataObj(CoreTlvData): @classmethod def pack(cls, obj): "return: (tlvlen, tlvdata)" tmp = struct.pack(cls.datafmt, cls.getvalue(obj)) return len(tmp) - cls.padlen, tmp @classmethod def unpack(cls, data): return cls.newobj(struct.unpack(cls.datafmt, data)[0]) @staticmethod def getvalue(obj): raise NotImplementedError @staticmethod def newobj(obj): raise NotImplementedError class CoreTlvDataUint16(CoreTlvData): datafmt = "!H" datatype = int padlen = 0 class CoreTlvDataUint32(CoreTlvData): datafmt = "!2xI" datatype = int padlen = 2 class CoreTlvDataUint64(CoreTlvData): datafmt = "!2xQ" datatype = long padlen = 2 class CoreTlvDataString(CoreTlvData): datatype = str @staticmethod def pack(value): if not isinstance(value, str): raise ValueError, "value not a string: %s" % value if len(value) < 256: hdrsiz = CoreTlv.hdrsiz else: hdrsiz = CoreTlv.longhdrsiz padlen = -(hdrsiz + len(value)) % 4 return len(value), value + '\0' * padlen @staticmethod def unpack(data): return data.rstrip('\0') class CoreTlvDataUint16List(CoreTlvData): ''' List of unsigned 16-bit values. ''' datatype = tuple @staticmethod def pack(values): if not isinstance(values, tuple): raise ValueError, "value not a tuple: %s" % values data = "" for v in values: data += struct.pack("!H", v) padlen = -(CoreTlv.hdrsiz + len(data)) % 4 return len(data), data + '\0' * padlen @staticmethod def unpack(data): datafmt = "!%dH" % (len(data)/2) return struct.unpack(datafmt, data) @classmethod def fromstring(cls, s): return tuple(map(lambda(x): int(x), s.split())) class CoreTlvDataIPv4Addr(CoreTlvDataObj): datafmt = "!2x4s" datatype = IPAddr.fromstring padlen = 2 @staticmethod def getvalue(obj): return obj.addr @staticmethod def newobj(value): return IPAddr(af = AF_INET, addr = value) class CoreTlvDataIPv6Addr(CoreTlvDataObj): datafmt = "!16s2x" datatype = IPAddr.fromstring padlen = 2 @staticmethod def getvalue(obj): return obj.addr @staticmethod def newobj(value): return IPAddr(af = AF_INET6, addr = value) class CoreTlvDataMacAddr(CoreTlvDataObj): datafmt = "!2x8s" datatype = MacAddr.fromstring padlen = 2 @staticmethod def getvalue(obj): return '\0\0' + obj.addr # extend to 64 bits @staticmethod def newobj(value): return MacAddr(addr = value[2:]) # only use 48 bits class CoreTlv(object): hdrfmt = "!BB" hdrsiz = struct.calcsize(hdrfmt) longhdrfmt = "!BBH" longhdrsiz = struct.calcsize(longhdrfmt) tlvtypemap = {} tlvdataclsmap = {} def __init__(self, tlvtype, tlvdata): self.tlvtype = tlvtype if tlvdata: try: self.value = self.tlvdataclsmap[self.tlvtype].unpack(tlvdata) except KeyError: self.value = tlvdata else: self.value = None @classmethod def unpack(cls, data): "parse data and return (tlv, remainingdata)" tlvtype, tlvlen = struct.unpack(cls.hdrfmt, data[:cls.hdrsiz]) hdrsiz = cls.hdrsiz if tlvlen == 0: tlvtype, zero, tlvlen = struct.unpack(cls.longhdrfmt, data[:cls.longhdrsiz]) hdrsiz = cls.longhdrsiz tlvsiz = hdrsiz + tlvlen tlvsiz += -tlvsiz % 4 # for 32-bit alignment return cls(tlvtype, data[hdrsiz:tlvsiz]), data[tlvsiz:] @classmethod def pack(cls, tlvtype, value): try: tlvlen, tlvdata = cls.tlvdataclsmap[tlvtype].pack(value) except Exception, e: raise ValueError, "TLV packing error type=%s: %s" % (tlvtype, e) if tlvlen < 256: hdr = struct.pack(cls.hdrfmt, tlvtype, tlvlen) else: hdr = struct.pack(cls.longhdrfmt, tlvtype, 0, tlvlen) return hdr + tlvdata @classmethod def packstring(cls, tlvtype, value): return cls.pack(tlvtype, cls.tlvdataclsmap[tlvtype].fromstring(value)) def typestr(self): try: return self.tlvtypemap[self.tlvtype] except KeyError: return "unknown tlv type: %s" % str(self.tlvtype) def __str__(self): return "%s " % \ (self.__class__.__name__, self.typestr(), self.value) class CoreNodeTlv(CoreTlv): tlvtypemap = node_tlvs tlvdataclsmap = { CORE_TLV_NODE_NUMBER: CoreTlvDataUint32, CORE_TLV_NODE_TYPE: CoreTlvDataUint32, CORE_TLV_NODE_NAME: CoreTlvDataString, CORE_TLV_NODE_IPADDR: CoreTlvDataIPv4Addr, CORE_TLV_NODE_MACADDR: CoreTlvDataMacAddr, CORE_TLV_NODE_IP6ADDR: CoreTlvDataIPv6Addr, CORE_TLV_NODE_MODEL: CoreTlvDataString, CORE_TLV_NODE_EMUSRV: CoreTlvDataString, CORE_TLV_NODE_SESSION: CoreTlvDataString, CORE_TLV_NODE_XPOS: CoreTlvDataUint16, CORE_TLV_NODE_YPOS: CoreTlvDataUint16, CORE_TLV_NODE_CANVAS: CoreTlvDataUint16, CORE_TLV_NODE_EMUID: CoreTlvDataUint32, CORE_TLV_NODE_NETID: CoreTlvDataUint32, CORE_TLV_NODE_SERVICES: CoreTlvDataString, CORE_TLV_NODE_LAT: CoreTlvDataString, CORE_TLV_NODE_LONG: CoreTlvDataString, CORE_TLV_NODE_ALT: CoreTlvDataString, CORE_TLV_NODE_ICON: CoreTlvDataString, CORE_TLV_NODE_OPAQUE: CoreTlvDataString, } class CoreLinkTlv(CoreTlv): tlvtypemap = link_tlvs tlvdataclsmap = { CORE_TLV_LINK_N1NUMBER: CoreTlvDataUint32, CORE_TLV_LINK_N2NUMBER: CoreTlvDataUint32, CORE_TLV_LINK_DELAY: CoreTlvDataUint64, CORE_TLV_LINK_BW: CoreTlvDataUint64, CORE_TLV_LINK_PER: CoreTlvDataString, CORE_TLV_LINK_DUP: CoreTlvDataString, CORE_TLV_LINK_JITTER: CoreTlvDataUint64, CORE_TLV_LINK_MER: CoreTlvDataUint16, CORE_TLV_LINK_BURST: CoreTlvDataUint16, CORE_TLV_LINK_SESSION: CoreTlvDataString, CORE_TLV_LINK_MBURST: CoreTlvDataUint16, CORE_TLV_LINK_TYPE: CoreTlvDataUint32, CORE_TLV_LINK_GUIATTR: CoreTlvDataString, CORE_TLV_LINK_UNI: CoreTlvDataUint16, CORE_TLV_LINK_EMUID: CoreTlvDataUint32, CORE_TLV_LINK_NETID: CoreTlvDataUint32, CORE_TLV_LINK_KEY: CoreTlvDataUint32, CORE_TLV_LINK_IF1NUM: CoreTlvDataUint16, CORE_TLV_LINK_IF1IP4: CoreTlvDataIPv4Addr, CORE_TLV_LINK_IF1IP4MASK: CoreTlvDataUint16, CORE_TLV_LINK_IF1MAC: CoreTlvDataMacAddr, CORE_TLV_LINK_IF1IP6: CoreTlvDataIPv6Addr, CORE_TLV_LINK_IF1IP6MASK: CoreTlvDataUint16, CORE_TLV_LINK_IF2NUM: CoreTlvDataUint16, CORE_TLV_LINK_IF2IP4: CoreTlvDataIPv4Addr, CORE_TLV_LINK_IF2IP4MASK: CoreTlvDataUint16, CORE_TLV_LINK_IF2MAC: CoreTlvDataMacAddr, CORE_TLV_LINK_IF2IP6: CoreTlvDataIPv6Addr, CORE_TLV_LINK_IF2IP6MASK: CoreTlvDataUint16, CORE_TLV_LINK_OPAQUE: CoreTlvDataString, } class CoreExecTlv(CoreTlv): tlvtypemap = exec_tlvs tlvdataclsmap = { CORE_TLV_EXEC_NODE: CoreTlvDataUint32, CORE_TLV_EXEC_NUM: CoreTlvDataUint32, CORE_TLV_EXEC_TIME: CoreTlvDataUint32, CORE_TLV_EXEC_CMD: CoreTlvDataString, CORE_TLV_EXEC_RESULT: CoreTlvDataString, CORE_TLV_EXEC_STATUS: CoreTlvDataUint32, CORE_TLV_EXEC_SESSION: CoreTlvDataString, } class CoreRegTlv(CoreTlv): tlvtypemap = reg_tlvs tlvdataclsmap = { CORE_TLV_REG_WIRELESS: CoreTlvDataString, CORE_TLV_REG_MOBILITY: CoreTlvDataString, CORE_TLV_REG_UTILITY: CoreTlvDataString, CORE_TLV_REG_EXECSRV: CoreTlvDataString, CORE_TLV_REG_GUI: CoreTlvDataString, CORE_TLV_REG_EMULSRV: CoreTlvDataString, CORE_TLV_REG_SESSION: CoreTlvDataString, } class CoreConfTlv(CoreTlv): tlvtypemap = conf_tlvs tlvdataclsmap = { CORE_TLV_CONF_NODE: CoreTlvDataUint32, CORE_TLV_CONF_OBJ: CoreTlvDataString, CORE_TLV_CONF_TYPE: CoreTlvDataUint16, CORE_TLV_CONF_DATA_TYPES: CoreTlvDataUint16List, CORE_TLV_CONF_VALUES: CoreTlvDataString, CORE_TLV_CONF_CAPTIONS: CoreTlvDataString, CORE_TLV_CONF_BITMAP: CoreTlvDataString, CORE_TLV_CONF_POSSIBLE_VALUES: CoreTlvDataString, CORE_TLV_CONF_GROUPS: CoreTlvDataString, CORE_TLV_CONF_SESSION: CoreTlvDataString, CORE_TLV_CONF_NETID: CoreTlvDataUint32, CORE_TLV_CONF_OPAQUE: CoreTlvDataString, } class CoreFileTlv(CoreTlv): tlvtypemap = file_tlvs tlvdataclsmap = { CORE_TLV_FILE_NODE: CoreTlvDataUint32, CORE_TLV_FILE_NAME: CoreTlvDataString, CORE_TLV_FILE_MODE: CoreTlvDataString, CORE_TLV_FILE_NUM: CoreTlvDataUint16, CORE_TLV_FILE_TYPE: CoreTlvDataString, CORE_TLV_FILE_SRCNAME: CoreTlvDataString, CORE_TLV_FILE_SESSION: CoreTlvDataString, CORE_TLV_FILE_DATA: CoreTlvDataString, CORE_TLV_FILE_CMPDATA: CoreTlvDataString, } class CoreIfaceTlv(CoreTlv): tlvtypemap = iface_tlvs tlvdataclsmap = { CORE_TLV_IFACE_NODE: CoreTlvDataUint32, CORE_TLV_IFACE_NUM: CoreTlvDataUint16, CORE_TLV_IFACE_NAME: CoreTlvDataString, CORE_TLV_IFACE_IPADDR: CoreTlvDataIPv4Addr, CORE_TLV_IFACE_MASK: CoreTlvDataUint16, CORE_TLV_IFACE_MACADDR: CoreTlvDataMacAddr, CORE_TLV_IFACE_IP6ADDR: CoreTlvDataIPv6Addr, CORE_TLV_IFACE_IP6MASK: CoreTlvDataUint16, CORE_TLV_IFACE_TYPE: CoreTlvDataUint16, CORE_TLV_IFACE_SESSION: CoreTlvDataString, CORE_TLV_IFACE_STATE: CoreTlvDataUint16, CORE_TLV_IFACE_EMUID: CoreTlvDataUint32, CORE_TLV_IFACE_NETID: CoreTlvDataUint32, } class CoreEventTlv(CoreTlv): tlvtypemap = event_tlvs tlvdataclsmap = { CORE_TLV_EVENT_NODE: CoreTlvDataUint32, CORE_TLV_EVENT_TYPE: CoreTlvDataUint32, CORE_TLV_EVENT_NAME: CoreTlvDataString, CORE_TLV_EVENT_DATA: CoreTlvDataString, CORE_TLV_EVENT_TIME: CoreTlvDataString, CORE_TLV_EVENT_SESSION: CoreTlvDataString, } class CoreSessionTlv(CoreTlv): tlvtypemap = session_tlvs tlvdataclsmap = { CORE_TLV_SESS_NUMBER: CoreTlvDataString, CORE_TLV_SESS_NAME: CoreTlvDataString, CORE_TLV_SESS_FILE: CoreTlvDataString, CORE_TLV_SESS_NODECOUNT: CoreTlvDataString, CORE_TLV_SESS_DATE: CoreTlvDataString, CORE_TLV_SESS_THUMB: CoreTlvDataString, CORE_TLV_SESS_USER: CoreTlvDataString, CORE_TLV_SESS_OPAQUE: CoreTlvDataString, } class CoreExceptionTlv(CoreTlv): tlvtypemap = exception_tlvs tlvdataclsmap = { CORE_TLV_EXCP_NODE: CoreTlvDataUint32, CORE_TLV_EXCP_SESSION: CoreTlvDataString, CORE_TLV_EXCP_LEVEL: CoreTlvDataUint16, CORE_TLV_EXCP_SOURCE: CoreTlvDataString, CORE_TLV_EXCP_DATE: CoreTlvDataString, CORE_TLV_EXCP_TEXT: CoreTlvDataString, CORE_TLV_EXCP_OPAQUE: CoreTlvDataString, } class CoreMessage(object): hdrfmt = "!BBH" hdrsiz = struct.calcsize(hdrfmt) msgtype = None flagmap = {} tlvcls = CoreTlv def __init__(self, flags, hdr, data): self.rawmsg = hdr + data self.flags = flags self.tlvdata = {} self.parsedata(data) @classmethod def unpackhdr(cls, data): "parse data and return (msgtype, msgflags, msglen)" msgtype, msgflags, msglen = struct.unpack(cls.hdrfmt, data[:cls.hdrsiz]) return msgtype, msgflags, msglen @classmethod def pack(cls, msgflags, tlvdata): hdr = struct.pack(cls.hdrfmt, cls.msgtype, msgflags, len(tlvdata)) return hdr + tlvdata def addtlvdata(self, k, v): if k in self.tlvdata: raise KeyError, "key already exists: %s (val=%s)" % (k, v) self.tlvdata[k] = v def gettlv(self, tlvtype): if tlvtype in self.tlvdata: return self.tlvdata[tlvtype] else: return None def parsedata(self, data): while data: tlv, data = self.tlvcls.unpack(data) self.addtlvdata(tlv.tlvtype, tlv.value) def packtlvdata(self): ''' Opposite of parsedata(). Return packed TLV data using self.tlvdata dict. Used by repack(). ''' tlvdata = "" keys = sorted(self.tlvdata.keys()) for k in keys: v = self.tlvdata[k] tlvdata += self.tlvcls.pack(k, v) return tlvdata def repack(self): ''' Invoke after updating self.tlvdata[] to rebuild self.rawmsg. Useful for modifying a message that has been parsed, before sending the raw data again. ''' tlvdata = self.packtlvdata() self.rawmsg = self.pack(self.flags, tlvdata) def typestr(self): try: return message_types[self.msgtype] except KeyError: return "unknown message type: %s" % str(self.msgtype) def flagstr(self): msgflags = [] flag = 1L while True: if (self.flags & flag): try: msgflags.append(self.flagmap[flag]) except KeyError: msgflags.append("0x%x" % flag) flag <<= 1 if not (self.flags & ~(flag - 1)): break return "0x%x <%s>" % (self.flags, " | ".join(msgflags)) def __str__(self): tmp = "%s " % \ (self.__class__.__name__, self.typestr(), self.flagstr()) for k, v in self.tlvdata.iteritems(): if k in self.tlvcls.tlvtypemap: tlvtype = self.tlvcls.tlvtypemap[k] else: tlvtype = "tlv type %s" % k tmp += "\n %s: %s" % (tlvtype, v) return tmp def nodenumbers(self): ''' Return a list of node numbers included in this message. ''' n = None n2 = None # not all messages have node numbers if self.msgtype == CORE_API_NODE_MSG: n = self.gettlv(CORE_TLV_NODE_NUMBER) elif self.msgtype == CORE_API_LINK_MSG: n = self.gettlv(CORE_TLV_LINK_N1NUMBER) n2 = self.gettlv(CORE_TLV_LINK_N2NUMBER) elif self.msgtype == CORE_API_EXEC_MSG: n = self.gettlv(CORE_TLV_EXEC_NODE) elif self.msgtype == CORE_API_CONF_MSG: n = self.gettlv(CORE_TLV_CONF_NODE) elif self.msgtype == CORE_API_FILE_MSG: n = self.gettlv(CORE_TLV_FILE_NODE) elif self.msgtype == CORE_API_IFACE_MSG: n = self.gettlv(CORE_TLV_IFACE_NODE) elif self.msgtype == CORE_API_EVENT_MSG: n = self.gettlv(CORE_TLV_EVENT_NODE) r = [] if n is not None: r.append(n) if n2 is not None: r.append(n2) return r def sessionnumbers(self): ''' Return a list of session numbers included in this message. ''' r = [] if self.msgtype == CORE_API_SESS_MSG: s = self.gettlv(CORE_TLV_SESS_NUMBER) elif self.msgtype == CORE_API_EXCP_MSG: s = self.gettlv(CORE_TLV_EXCP_SESSION) else: # All other messages share TLV number 0xA for the session number(s). s = self.gettlv(CORE_TLV_NODE_SESSION) if s is not None: for sid in s.split('|'): r.append(int(sid)) return r class CoreNodeMessage(CoreMessage): msgtype = CORE_API_NODE_MSG flagmap = message_flags tlvcls = CoreNodeTlv class CoreLinkMessage(CoreMessage): msgtype = CORE_API_LINK_MSG flagmap = message_flags tlvcls = CoreLinkTlv class CoreExecMessage(CoreMessage): msgtype = CORE_API_EXEC_MSG flagmap = message_flags tlvcls = CoreExecTlv class CoreRegMessage(CoreMessage): msgtype = CORE_API_REG_MSG flagmap = message_flags tlvcls = CoreRegTlv class CoreConfMessage(CoreMessage): msgtype = CORE_API_CONF_MSG flagmap = message_flags tlvcls = CoreConfTlv class CoreFileMessage(CoreMessage): msgtype = CORE_API_FILE_MSG flagmap = message_flags tlvcls = CoreFileTlv class CoreIfaceMessage(CoreMessage): msgtype = CORE_API_IFACE_MSG flagmap = message_flags tlvcls = CoreIfaceTlv class CoreEventMessage(CoreMessage): msgtype = CORE_API_EVENT_MSG flagmap = message_flags tlvcls = CoreEventTlv class CoreSessionMessage(CoreMessage): msgtype = CORE_API_SESS_MSG flagmap = message_flags tlvcls = CoreSessionTlv class CoreExceptionMessage(CoreMessage): msgtype = CORE_API_EXCP_MSG flagmap = message_flags tlvcls = CoreExceptionTlv msgclsmap = { CORE_API_NODE_MSG: CoreNodeMessage, CORE_API_LINK_MSG: CoreLinkMessage, CORE_API_EXEC_MSG: CoreExecMessage, CORE_API_REG_MSG: CoreRegMessage, CORE_API_CONF_MSG: CoreConfMessage, CORE_API_FILE_MSG: CoreFileMessage, CORE_API_IFACE_MSG: CoreIfaceMessage, CORE_API_EVENT_MSG: CoreEventMessage, CORE_API_SESS_MSG: CoreSessionMessage, CORE_API_EXCP_MSG: CoreExceptionMessage, } def msg_class(msgtypeid): global msgclsmap return msgclsmap[msgtypeid] nodeclsmap = {} def add_node_class(name, nodetypeid, nodecls, change = False): global nodeclsmap if nodetypeid in nodeclsmap: if not change: raise ValueError, \ "node class already exists for nodetypeid %s" % nodetypeid nodeclsmap[nodetypeid] = nodecls if nodetypeid not in node_types: node_types[nodetypeid] = name exec "%s = %s" % (name, nodetypeid) in globals() elif name != node_types[nodetypeid]: raise ValueError, "node type already exists for '%s'" % name else: pass def change_node_class(name, nodetypeid, nodecls): return add_node_class(name, nodetypeid, nodecls, change = True) def node_class(nodetypeid): global nodeclsmap return nodeclsmap[nodetypeid] def str_to_list(s): ''' Helper to convert pipe-delimited string ("a|b|c") into a list (a, b, c) ''' if s is None: return None return s.split("|") def state_name(n): ''' Helper to convert state number into state name using event types. ''' if n in event_types: eventname = event_types[n] name = eventname.split('_')[2] else: name = "unknown" return name core-4.8/daemon/core/api/data.py0000664000175000017500000001733012534327775013512 00000000000000# # CORE # Copyright (c)2010-2013 the Boeing Company. # See the LICENSE file included in this distribution. # # author: Tom Goff # ''' data.py: constant definitions for the CORE API, enumerating the different message and TLV types (these constants are also found in coreapi.h) ''' def enumdict(d): for k, v in d.iteritems(): exec "%s = %s" % (v, k) in globals() # Constants CORE_API_VER = "1.23" CORE_API_PORT = 4038 # Message types message_types = { 0x01: "CORE_API_NODE_MSG", 0x02: "CORE_API_LINK_MSG", 0x03: "CORE_API_EXEC_MSG", 0x04: "CORE_API_REG_MSG", 0x05: "CORE_API_CONF_MSG", 0x06: "CORE_API_FILE_MSG", 0x07: "CORE_API_IFACE_MSG", 0x08: "CORE_API_EVENT_MSG", 0x09: "CORE_API_SESS_MSG", 0x0A: "CORE_API_EXCP_MSG", 0x0B: "CORE_API_MSG_MAX", } enumdict(message_types) # Generic Message Flags message_flags = { 0x01: "CORE_API_ADD_FLAG", 0x02: "CORE_API_DEL_FLAG", 0x04: "CORE_API_CRI_FLAG", 0x08: "CORE_API_LOC_FLAG", 0x10: "CORE_API_STR_FLAG", 0x20: "CORE_API_TXT_FLAG", 0x40: "CORE_API_TTY_FLAG", } enumdict(message_flags) # Node Message TLV Types node_tlvs = { 0x01: "CORE_TLV_NODE_NUMBER", 0x02: "CORE_TLV_NODE_TYPE", 0x03: "CORE_TLV_NODE_NAME", 0x04: "CORE_TLV_NODE_IPADDR", 0x05: "CORE_TLV_NODE_MACADDR", 0x06: "CORE_TLV_NODE_IP6ADDR", 0x07: "CORE_TLV_NODE_MODEL", 0x08: "CORE_TLV_NODE_EMUSRV", 0x0A: "CORE_TLV_NODE_SESSION", 0x20: "CORE_TLV_NODE_XPOS", 0x21: "CORE_TLV_NODE_YPOS", 0x22: "CORE_TLV_NODE_CANVAS", 0x23: "CORE_TLV_NODE_EMUID", 0x24: "CORE_TLV_NODE_NETID", 0x25: "CORE_TLV_NODE_SERVICES", 0x30: "CORE_TLV_NODE_LAT", 0x31: "CORE_TLV_NODE_LONG", 0x32: "CORE_TLV_NODE_ALT", 0x42: "CORE_TLV_NODE_ICON", 0x50: "CORE_TLV_NODE_OPAQUE", } enumdict(node_tlvs) node_types = dict(enumerate([ "CORE_NODE_DEF", "CORE_NODE_PHYS", "CORE_NODE_XEN", "CORE_NODE_TBD", "CORE_NODE_SWITCH", "CORE_NODE_HUB", "CORE_NODE_WLAN", "CORE_NODE_RJ45", "CORE_NODE_TUNNEL", "CORE_NODE_KTUNNEL", "CORE_NODE_EMANE", ])) enumdict(node_types) rj45_models = dict(enumerate([ "RJ45_MODEL_LINKED", "RJ45_MODEL_WIRELESS", "RJ45_MODEL_INSTALLED", ])) enumdict(rj45_models) # Link Message TLV Types link_tlvs = { 0x01: "CORE_TLV_LINK_N1NUMBER", 0x02: "CORE_TLV_LINK_N2NUMBER", 0x03: "CORE_TLV_LINK_DELAY", 0x04: "CORE_TLV_LINK_BW", 0x05: "CORE_TLV_LINK_PER", 0x06: "CORE_TLV_LINK_DUP", 0x07: "CORE_TLV_LINK_JITTER", 0x08: "CORE_TLV_LINK_MER", 0x09: "CORE_TLV_LINK_BURST", CORE_TLV_NODE_SESSION: "CORE_TLV_LINK_SESSION", 0x10: "CORE_TLV_LINK_MBURST", 0x20: "CORE_TLV_LINK_TYPE", 0x21: "CORE_TLV_LINK_GUIATTR", 0x22: "CORE_TLV_LINK_UNI", 0x23: "CORE_TLV_LINK_EMUID", 0x24: "CORE_TLV_LINK_NETID", 0x25: "CORE_TLV_LINK_KEY", 0x30: "CORE_TLV_LINK_IF1NUM", 0x31: "CORE_TLV_LINK_IF1IP4", 0x32: "CORE_TLV_LINK_IF1IP4MASK", 0x33: "CORE_TLV_LINK_IF1MAC", 0x34: "CORE_TLV_LINK_IF1IP6", 0x35: "CORE_TLV_LINK_IF1IP6MASK", 0x36: "CORE_TLV_LINK_IF2NUM", 0x37: "CORE_TLV_LINK_IF2IP4", 0x38: "CORE_TLV_LINK_IF2IP4MASK", 0x39: "CORE_TLV_LINK_IF2MAC", 0x40: "CORE_TLV_LINK_IF2IP6", 0x41: "CORE_TLV_LINK_IF2IP6MASK", 0x50: "CORE_TLV_LINK_OPAQUE", } enumdict(link_tlvs) link_types = dict(enumerate([ "CORE_LINK_WIRELESS", "CORE_LINK_WIRED", ])) enumdict(link_types) # Execute Message TLV Types exec_tlvs = { 0x01: "CORE_TLV_EXEC_NODE", 0x02: "CORE_TLV_EXEC_NUM", 0x03: "CORE_TLV_EXEC_TIME", 0x04: "CORE_TLV_EXEC_CMD", 0x05: "CORE_TLV_EXEC_RESULT", 0x06: "CORE_TLV_EXEC_STATUS", CORE_TLV_NODE_SESSION: "CORE_TLV_EXEC_SESSION", } enumdict(exec_tlvs) # Register Message TLV Types reg_tlvs = { 0x01: "CORE_TLV_REG_WIRELESS", 0x02: "CORE_TLV_REG_MOBILITY", 0x03: "CORE_TLV_REG_UTILITY", 0x04: "CORE_TLV_REG_EXECSRV", 0x05: "CORE_TLV_REG_GUI", 0x06: "CORE_TLV_REG_EMULSRV", CORE_TLV_NODE_SESSION: "CORE_TLV_REG_SESSION", } enumdict(reg_tlvs) # Configuration Message TLV Types conf_tlvs = { 0x01: "CORE_TLV_CONF_NODE", 0x02: "CORE_TLV_CONF_OBJ", 0x03: "CORE_TLV_CONF_TYPE", 0x04: "CORE_TLV_CONF_DATA_TYPES", 0x05: "CORE_TLV_CONF_VALUES", 0x06: "CORE_TLV_CONF_CAPTIONS", 0x07: "CORE_TLV_CONF_BITMAP", 0x08: "CORE_TLV_CONF_POSSIBLE_VALUES", 0x09: "CORE_TLV_CONF_GROUPS", CORE_TLV_NODE_SESSION: "CORE_TLV_CONF_SESSION", CORE_TLV_NODE_NETID: "CORE_TLV_CONF_NETID", 0x50: "CORE_TLV_CONF_OPAQUE", } enumdict(conf_tlvs) conf_flags = { 0x00: "CONF_TYPE_FLAGS_NONE", 0x01: "CONF_TYPE_FLAGS_REQUEST", 0x02: "CONF_TYPE_FLAGS_UPDATE", 0x03: "CONF_TYPE_FLAGS_RESET", } enumdict(conf_flags) conf_data_types = { 0x01: "CONF_DATA_TYPE_UINT8", 0x02: "CONF_DATA_TYPE_UINT16", 0x03: "CONF_DATA_TYPE_UINT32", 0x04: "CONF_DATA_TYPE_UINT64", 0x05: "CONF_DATA_TYPE_INT8", 0x06: "CONF_DATA_TYPE_INT16", 0x07: "CONF_DATA_TYPE_INT32", 0x08: "CONF_DATA_TYPE_INT64", 0x09: "CONF_DATA_TYPE_FLOAT", 0x0A: "CONF_DATA_TYPE_STRING", 0x0B: "CONF_DATA_TYPE_BOOL", } enumdict(conf_data_types) # File Message TLV Types file_tlvs = { 0x01: "CORE_TLV_FILE_NODE", 0x02: "CORE_TLV_FILE_NAME", 0x03: "CORE_TLV_FILE_MODE", 0x04: "CORE_TLV_FILE_NUM", 0x05: "CORE_TLV_FILE_TYPE", 0x06: "CORE_TLV_FILE_SRCNAME", CORE_TLV_NODE_SESSION: "CORE_TLV_FILE_SESSION", 0x10: "CORE_TLV_FILE_DATA", 0x11: "CORE_TLV_FILE_CMPDATA", } enumdict(file_tlvs) # Interface Message TLV Types iface_tlvs = { 0x01: "CORE_TLV_IFACE_NODE", 0x02: "CORE_TLV_IFACE_NUM", 0x03: "CORE_TLV_IFACE_NAME", 0x04: "CORE_TLV_IFACE_IPADDR", 0x05: "CORE_TLV_IFACE_MASK", 0x06: "CORE_TLV_IFACE_MACADDR", 0x07: "CORE_TLV_IFACE_IP6ADDR", 0x08: "CORE_TLV_IFACE_IP6MASK", 0x09: "CORE_TLV_IFACE_TYPE", CORE_TLV_NODE_SESSION: "CORE_TLV_IFACE_SESSION", 0x0B: "CORE_TLV_IFACE_STATE", CORE_TLV_NODE_EMUID: "CORE_TLV_IFACE_EMUID", CORE_TLV_NODE_NETID: "CORE_TLV_IFACE_NETID", } enumdict(iface_tlvs) # Event Message TLV Types event_tlvs = { 0x01: "CORE_TLV_EVENT_NODE", 0x02: "CORE_TLV_EVENT_TYPE", 0x03: "CORE_TLV_EVENT_NAME", 0x04: "CORE_TLV_EVENT_DATA", 0x05: "CORE_TLV_EVENT_TIME", CORE_TLV_NODE_SESSION: "CORE_TLV_EVENT_SESSION", } enumdict(event_tlvs) event_types = dict(enumerate([ "CORE_EVENT_NONE", "CORE_EVENT_DEFINITION_STATE", "CORE_EVENT_CONFIGURATION_STATE", "CORE_EVENT_INSTANTIATION_STATE", "CORE_EVENT_RUNTIME_STATE", "CORE_EVENT_DATACOLLECT_STATE", "CORE_EVENT_SHUTDOWN_STATE", "CORE_EVENT_START", "CORE_EVENT_STOP", "CORE_EVENT_PAUSE", "CORE_EVENT_RESTART", "CORE_EVENT_FILE_OPEN", "CORE_EVENT_FILE_SAVE", "CORE_EVENT_SCHEDULED", "CORE_EVENT_RECONFIGURE", ])) enumdict(event_types) # Session Message TLV Types session_tlvs = { 0x01: "CORE_TLV_SESS_NUMBER", 0x02: "CORE_TLV_SESS_NAME", 0x03: "CORE_TLV_SESS_FILE", 0x04: "CORE_TLV_SESS_NODECOUNT", 0x05: "CORE_TLV_SESS_DATE", 0x06: "CORE_TLV_SESS_THUMB", 0x07: "CORE_TLV_SESS_USER", 0x0A: "CORE_TLV_SESS_OPAQUE", } enumdict(session_tlvs) # Exception Message TLV Types exception_tlvs = { 0x01: "CORE_TLV_EXCP_NODE", 0x02: "CORE_TLV_EXCP_SESSION", 0x03: "CORE_TLV_EXCP_LEVEL", 0x04: "CORE_TLV_EXCP_SOURCE", 0x05: "CORE_TLV_EXCP_DATE", 0x06: "CORE_TLV_EXCP_TEXT", 0x0A: "CORE_TLV_EXCP_OPAQUE", } enumdict(exception_tlvs) exception_levels = dict(enumerate([ "CORE_EXCP_LEVEL_NONE", "CORE_EXCP_LEVEL_FATAL", "CORE_EXCP_LEVEL_ERROR", "CORE_EXCP_LEVEL_WARNING", "CORE_EXCP_LEVEL_NOTICE", ])) enumdict(exception_levels) del enumdict core-4.8/daemon/core/broker.py0000664000175000017500000010634012534327775013314 00000000000000# # CORE # Copyright (c)2010-2013 the Boeing Company. # See the LICENSE file included in this distribution. # # author: Jeff Ahrenholz # ''' broker.py: definition of CoreBroker class that is part of the pycore session object. Handles distributing parts of the emulation out to other emulation servers. The broker is consulted during the CoreRequestHandler.handlemsg() loop to determine if messages should be handled locally or forwarded on to another emulation server. ''' import os, socket, select, threading, sys from core.api import coreapi from core.coreobj import PyCoreNode, PyCoreNet from core.emane.nodes import EmaneNet from core.netns.nodes import CtrlNet from core.phys.pnodes import PhysicalNode from core.misc.ipaddr import IPAddr from core.conf import ConfigurableManager if os.uname()[0] == "Linux": from core.netns.vif import GreTap from core.netns.vnet import GreTapBridge class CoreBroker(ConfigurableManager): ''' Member of pycore session class for handling global emulation server data. ''' _name = "broker" _type = coreapi.CORE_TLV_REG_UTILITY def __init__(self, session, verbose = False): ConfigurableManager.__init__(self, session) self.session_id_master = None self.myip = None self.verbose = verbose # dict containing tuples of (host, port, sock) self.servers = {} self.servers_lock = threading.Lock() self.addserver("localhost", None, None) # dict containing node number to server name mapping self.nodemap = {} # this lock also protects self.nodecounts self.nodemap_lock = threading.Lock() # reference counts of nodes on servers self.nodecounts = { } self.bootcount = 0 # list of node numbers that are link-layer nodes (networks) self.nets = [] # list of node numbers that are PhysicalNode nodes self.phys = [] # allows for other message handlers to process API messages (e.g. EMANE) self.handlers = () # dict with tunnel key to tunnel device mapping self.tunnels = {} self.dorecvloop = False self.recvthread = None def startup(self): ''' Build tunnels between network-layer nodes now that all node and link information has been received; called when session enters the instantation state. ''' self.addnettunnels() self.writeservers() def shutdown(self): ''' Close all active sockets; called when the session enters the data collect state ''' with self.servers_lock: while len(self.servers) > 0: (server, v) = self.servers.popitem() (host, port, sock) = v if sock is None: continue if self.verbose: self.session.info("closing connection with %s @ %s:%s" % \ (server, host, port)) sock.close() self.reset() self.dorecvloop = False if self.recvthread is not None: self.recvthread.join() def reset(self): ''' Reset to initial state. ''' self.nodemap_lock.acquire() self.nodemap.clear() for server in self.nodecounts: if self.nodecounts[server] < 1: self.delserver(server) self.nodecounts.clear() self.bootcount = 0 self.nodemap_lock.release() del self.nets[:] del self.phys[:] while len(self.tunnels) > 0: (key, gt) = self.tunnels.popitem() gt.shutdown() def startrecvloop(self): ''' Spawn the recvloop() thread if it hasn't been already started. ''' if self.recvthread is not None: if self.recvthread.isAlive(): return else: self.recvthread.join() # start reading data from connected sockets self.dorecvloop = True self.recvthread = threading.Thread(target = self.recvloop) self.recvthread.daemon = True self.recvthread.start() def recvloop(self): ''' Thread target that receives messages from server sockets. ''' self.dorecvloop = True # note: this loop continues after emulation is stopped, # even with 0 servers while self.dorecvloop: rlist = [] with self.servers_lock: # build a socket list for select call for name in self.servers: (h, p, sock) = self.servers[name] if sock is not None: rlist.append(sock.fileno()) r, w, x = select.select(rlist, [], [], 1.0) for sockfd in r: try: (h, p, sock, name) = self.getserverbysock(sockfd) except KeyError: # servers may have changed; loop again break rcvlen = self.recv(sock, h) if rcvlen == 0: if self.verbose: self.session.info("connection with %s @ %s:%s" \ " has closed" % (name, h, p)) self.servers[name] = (h, p, None) def recv(self, sock, host): ''' Receive data on an emulation server socket and broadcast it to all connected session handlers. Returns the length of data recevied and forwarded. Return value of zero indicates the socket has closed and should be removed from the self.servers dict. ''' msghdr = sock.recv(coreapi.CoreMessage.hdrsiz) if len(msghdr) == 0: # server disconnected sock.close() return 0 if len(msghdr) != coreapi.CoreMessage.hdrsiz: if self.verbose: self.session.info("warning: broker received not enough data " \ "len=%s" % len(msghdr)) return len(msghdr) msgtype, msgflags, msglen = coreapi.CoreMessage.unpackhdr(msghdr) msgdata = sock.recv(msglen) data = msghdr + msgdata count = None # snoop exec response for remote interactive TTYs if msgtype == coreapi.CORE_API_EXEC_MSG and \ msgflags & coreapi.CORE_API_TTY_FLAG: data = self.fixupremotetty(msghdr, msgdata, host) elif msgtype == coreapi.CORE_API_NODE_MSG: # snoop node delete response to decrement node counts if msgflags & coreapi.CORE_API_DEL_FLAG: msg = coreapi.CoreNodeMessage(msgflags, msghdr, msgdata) nodenum = msg.gettlv(coreapi.CORE_TLV_NODE_NUMBER) if nodenum is not None: count = self.delnodemap(sock, nodenum) # snoop node add response to increment booted node count # (only CoreNodes send these response messages) elif msgflags & \ (coreapi.CORE_API_ADD_FLAG | coreapi.CORE_API_LOC_FLAG): self.incrbootcount() self.session.checkruntime() elif msgtype == coreapi.CORE_API_LINK_MSG: # this allows green link lines for remote WLANs msg = coreapi.CoreLinkMessage(msgflags, msghdr, msgdata) self.session.sdt.handledistributed(msg) self.session.broadcastraw(None, data) if count is not None and count < 1: return 0 else: return len(data) def addserver(self, name, host, port): ''' Add a new server, and try to connect to it. If we're already connected to this (host, port), then leave it alone. When host,port is None, do not try to connect. ''' self.servers_lock.acquire() if name in self.servers: (oldhost, oldport, sock) = self.servers[name] if host == oldhost or port == oldport: # leave this socket connected if sock is not None: self.servers_lock.release() return if self.verbose and host is not None and sock is not None: self.session.info("closing connection with %s @ %s:%s" % \ (name, host, port)) if sock is not None: sock.close() self.servers_lock.release() if self.verbose and host is not None: self.session.info("adding server %s @ %s:%s" % (name, host, port)) if host is None: sock = None else: sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) #sock.setblocking(0) #error = sock.connect_ex((host, port)) try: sock.connect((host, port)) self.startrecvloop() except Exception, e: self.session.warn("error connecting to server %s:%s:\n\t%s" % \ (host, port, e)) sock.close() sock = None self.servers_lock.acquire() self.servers[name] = (host, port, sock) self.servers_lock.release() def delserver(self, name): ''' Remove a server and hang up any connection. ''' self.servers_lock.acquire() if name not in self.servers: self.servers_lock.release() return (host, port, sock) = self.servers.pop(name) if sock is not None: if self.verbose: self.session.info("closing connection with %s @ %s:%s" % \ (name, host, port)) sock.close() self.servers_lock.release() def getserver(self, name): ''' Return the (host, port, sock) tuple, or raise a KeyError exception. ''' if name not in self.servers: raise KeyError, "emulation server %s not found" % name return self.servers[name] def getserverbysock(self, sockfd): ''' Return a (host, port, sock, name) tuple based on socket file descriptor, or raise a KeyError exception. ''' with self.servers_lock: for name in self.servers: (host, port, sock) = self.servers[name] if sock is None: continue if sock.fileno() == sockfd: return (host, port, sock, name) raise KeyError, "socket fd %s not found" % sockfd def getserverlist(self): ''' Return the list of server names (keys from self.servers). ''' with self.servers_lock: serverlist = sorted(self.servers.keys()) return serverlist def tunnelkey(self, n1num, n2num): ''' Compute a 32-bit key used to uniquely identify a GRE tunnel. The hash(n1num), hash(n2num) values are used, so node numbers may be None or string values (used for e.g. "ctrlnet"). ''' sid = self.session_id_master if sid is None: # this is the master session sid = self.session.sessionid key = (sid << 16) ^ hash(n1num) ^ (hash(n2num) << 8) return key & 0xFFFFFFFF def addtunnel(self, remoteip, n1num, n2num, localnum): ''' Add a new GreTapBridge between nodes on two different machines. ''' key = self.tunnelkey(n1num, n2num) if localnum == n2num: remotenum = n1num else: remotenum = n2num if key in self.tunnels.keys(): self.session.warn("tunnel with key %s (%s-%s) already exists!" % \ (key, n1num, n2num)) else: objid = key & ((1<<16)-1) self.session.info("Adding tunnel for %s-%s to %s with key %s" % \ (n1num, n2num, remoteip, key)) if localnum in self.phys: # no bridge is needed on physical nodes; use the GreTap directly gt = GreTap(node=None, name=None, session=self.session, remoteip=remoteip, key=key) else: gt = self.session.addobj(cls = GreTapBridge, objid = objid, policy="ACCEPT", remoteip=remoteip, key = key) gt.localnum = localnum gt.remotenum = remotenum self.tunnels[key] = gt def addnettunnels(self): ''' Add GreTaps between network devices on different machines. The GreTapBridge is not used since that would add an extra bridge. ''' for n in self.nets: self.addnettunnel(n) def addnettunnel(self, n): try: net = self.session.obj(n) except KeyError: raise KeyError, "network node %s not found" % n # add other nets here that do not require tunnels if isinstance(net, EmaneNet): return None if isinstance(net, CtrlNet): if hasattr(net, 'serverintf'): if net.serverintf is not None: return None servers = self.getserversbynode(n) if len(servers) < 2: return None hosts = [] for server in servers: (host, port, sock) = self.getserver(server) if host is None: continue hosts.append(host) if len(hosts) == 0: # get IP address from API message sender (master) self.session._handlerslock.acquire() for h in self.session._handlers: if h.client_address != "": hosts.append(h.client_address[0]) self.session._handlerslock.release() r = [] for host in hosts: if self.myip: # we are the remote emulation server myip = self.myip else: # we are the session master myip = host key = self.tunnelkey(n, IPAddr.toint(myip)) if key in self.tunnels.keys(): continue self.session.info("Adding tunnel for net %s to %s with key %s" % \ (n, host, key)) gt = GreTap(node=None, name=None, session=self.session, remoteip=host, key=key) self.tunnels[key] = gt r.append(gt) # attaching to net will later allow gt to be destroyed # during net.shutdown() net.attach(gt) return r def deltunnel(self, n1num, n2num): ''' Cleanup of the GreTapBridge. ''' key = self.tunnelkey(n1num, n2num) try: gt = self.tunnels.pop(key) except KeyError: gt = None if gt: self.session.delobj(gt.objid) del gt def gettunnel(self, n1num, n2num): ''' Return the GreTap between two nodes if it exists. ''' key = self.tunnelkey(n1num, n2num) if key in self.tunnels.keys(): return self.tunnels[key] else: return None def addnodemap(self, server, nodenum): ''' Record a node number to emulation server mapping. ''' self.nodemap_lock.acquire() if nodenum in self.nodemap: if server in self.nodemap[nodenum]: self.nodemap_lock.release() return self.nodemap[nodenum].append(server) else: self.nodemap[nodenum] = [server,] if server in self.nodecounts: self.nodecounts[server] += 1 else: self.nodecounts[server] = 1 self.nodemap_lock.release() def delnodemap(self, sock, nodenum): ''' Remove a node number to emulation server mapping. Return the number of nodes left on this server. ''' self.nodemap_lock.acquire() count = None if nodenum not in self.nodemap: self.nodemap_lock.release() return count found = False for server in self.nodemap[nodenum]: (host, port, srvsock) = self.getserver(server) if srvsock == sock: found = True break if server in self.nodecounts: count = self.nodecounts[server] if found: self.nodemap[nodenum].remove(server) if server in self.nodecounts: count -= 1 self.nodecounts[server] = count self.nodemap_lock.release() return count def incrbootcount(self): ''' Count a node that has booted. ''' self.bootcount += 1 return self.bootcount def getbootcount(self): ''' Return the number of booted nodes. ''' return self.bootcount def getserversbynode(self, nodenum): ''' Retrieve a list of emulation servers given a node number. ''' self.nodemap_lock.acquire() if nodenum not in self.nodemap: self.nodemap_lock.release() return [] r = self.nodemap[nodenum] self.nodemap_lock.release() return r def addnet(self, nodenum): ''' Add a node number to the list of link-layer nodes. ''' if nodenum not in self.nets: self.nets.append(nodenum) def addphys(self, nodenum): ''' Add a node number to the list of physical nodes. ''' if nodenum not in self.phys: self.phys.append(nodenum) def configure_reset(self, msg): ''' Ignore reset messages, because node delete responses may still arrive and require the use of nodecounts. ''' return None def configure_values(self, msg, values): ''' Receive configuration message with a list of server:host:port combinations that we'll need to connect with. ''' objname = msg.gettlv(coreapi.CORE_TLV_CONF_OBJ) conftype = msg.gettlv(coreapi.CORE_TLV_CONF_TYPE) if values is None: self.session.info("emulation server data missing") return None values = values.split('|') # string of "server:ip:port,server:ip:port,..." serverstrings = values[0] server_list = serverstrings.split(',') for server in server_list: server_items = server.split(':') (name, host, port) = server_items[:3] if host == '': host = None if port == '': port = None else: port = int(port) sid = msg.gettlv(coreapi.CORE_TLV_CONF_SESSION) if sid is not None: # receive session ID and my IP from master self.session_id_master = int(sid.split('|')[0]) self.myip = host host = None port = None # this connects to the server immediately; maybe we should wait # or spin off a new "client" thread here self.addserver(name, host, port) self.setupserver(name) return None def handlemsg(self, msg): ''' Handle an API message. Determine whether this needs to be handled by the local server or forwarded on to another one. Returns True when message does not need to be handled locally, and performs forwarding if required. Returning False indicates this message should be handled locally. ''' serverlist = [] handle_locally = False # Do not forward messages when in definition state # (for e.g. configuring services) if self.session.getstate() == coreapi.CORE_EVENT_DEFINITION_STATE: handle_locally = True return not handle_locally # Decide whether message should be handled locally or forwarded, or both if msg.msgtype == coreapi.CORE_API_NODE_MSG: (handle_locally, serverlist) = self.handlenodemsg(msg) elif msg.msgtype == coreapi.CORE_API_EVENT_MSG: # broadcast events everywhere serverlist = self.getserverlist() elif msg.msgtype == coreapi.CORE_API_CONF_MSG: # broadcast location and services configuration everywhere confobj = msg.gettlv(coreapi.CORE_TLV_CONF_OBJ) if confobj == "location" or confobj == "services" or \ confobj == "session" or confobj == "all": serverlist = self.getserverlist() elif msg.msgtype == coreapi.CORE_API_FILE_MSG: # broadcast hook scripts and custom service files everywhere filetype = msg.gettlv(coreapi.CORE_TLV_FILE_TYPE) if filetype is not None and \ (filetype[:5] == "hook:" or filetype[:8] == "service:"): serverlist = self.getserverlist() if msg.msgtype == coreapi.CORE_API_LINK_MSG: # prepare a serverlist from two node numbers in link message (handle_locally, serverlist, msg) = self.handlelinkmsg(msg) elif len(serverlist) == 0: # check for servers based on node numbers in all messages but link nn = msg.nodenumbers() if len(nn) == 0: return False serverlist = self.getserversbynode(nn[0]) if len(serverlist) == 0: handle_locally = True # allow other handlers to process this message # (this is used by e.g. EMANE to use the link add message to keep counts # of interfaces on other servers) for handler in self.handlers: handler(msg) # Perform any message forwarding handle_locally = self.forwardmsg(msg, serverlist, handle_locally) return not handle_locally def setupserver(self, server): ''' Send the appropriate API messages for configuring the specified emulation server. ''' (host, port, sock) = self.getserver(server) if host is None or sock is None: return # communicate this session's current state to the server tlvdata = coreapi.CoreEventTlv.pack(coreapi.CORE_TLV_EVENT_TYPE, self.session.getstate()) msg = coreapi.CoreEventMessage.pack(0, tlvdata) sock.send(msg) # send a Configuration message for the broker object and inform the # server of its local name tlvdata = "" tlvdata += coreapi.CoreConfTlv.pack(coreapi.CORE_TLV_CONF_OBJ, "broker") tlvdata += coreapi.CoreConfTlv.pack(coreapi.CORE_TLV_CONF_TYPE, coreapi.CONF_TYPE_FLAGS_UPDATE) tlvdata += coreapi.CoreConfTlv.pack(coreapi.CORE_TLV_CONF_DATA_TYPES, (coreapi.CONF_DATA_TYPE_STRING,)) tlvdata += coreapi.CoreConfTlv.pack(coreapi.CORE_TLV_CONF_VALUES, "%s:%s:%s" % (server, host, port)) tlvdata += coreapi.CoreConfTlv.pack(coreapi.CORE_TLV_CONF_SESSION, "%s" % self.session.sessionid) msg = coreapi.CoreConfMessage.pack(0, tlvdata) sock.send(msg) @staticmethod def fixupremotetty(msghdr, msgdata, host): ''' When an interactive TTY request comes from the GUI, snoop the reply and add an SSH command to the appropriate remote server. ''' msgtype, msgflags, msglen = coreapi.CoreMessage.unpackhdr(msghdr) msgcls = coreapi.msg_class(msgtype) msg = msgcls(msgflags, msghdr, msgdata) nodenum = msg.gettlv(coreapi.CORE_TLV_EXEC_NODE) execnum = msg.gettlv(coreapi.CORE_TLV_EXEC_NUM) cmd = msg.gettlv(coreapi.CORE_TLV_EXEC_CMD) res = msg.gettlv(coreapi.CORE_TLV_EXEC_RESULT) tlvdata = "" tlvdata += coreapi.CoreExecTlv.pack(coreapi.CORE_TLV_EXEC_NODE, nodenum) tlvdata += coreapi.CoreExecTlv.pack(coreapi.CORE_TLV_EXEC_NUM, execnum) tlvdata += coreapi.CoreExecTlv.pack(coreapi.CORE_TLV_EXEC_CMD, cmd) title = "\\\"CORE: n%s @ %s\\\"" % (nodenum, host) res = "ssh -X -f " + host + " xterm -e " + res tlvdata += coreapi.CoreExecTlv.pack(coreapi.CORE_TLV_EXEC_RESULT, res) return coreapi.CoreExecMessage.pack(msgflags, tlvdata) def handlenodemsg(self, msg): ''' Determine and return the servers to which this node message should be forwarded. Also keep track of link-layer nodes and the mapping of nodes to servers. ''' serverlist = [] handle_locally = False serverfiletxt = None # snoop Node Message for emulation server TLV and record mapping n = msg.tlvdata[coreapi.CORE_TLV_NODE_NUMBER] # replicate link-layer nodes on all servers nodetype = msg.gettlv(coreapi.CORE_TLV_NODE_TYPE) if nodetype is not None: try: nodecls = coreapi.node_class(nodetype) except KeyError: self.session.warn("broker invalid node type %s" % nodetype) return (False, serverlist) if nodecls is None: self.session.warn("broker unimplemented node type %s" % nodetype) return (False, serverlist) if issubclass(nodecls, PyCoreNet) and \ nodetype != coreapi.CORE_NODE_WLAN: # network node replicated on all servers; could be optimized # don't replicate WLANs, because ebtables rules won't work serverlist = self.getserverlist() handle_locally = True self.addnet(n) for server in serverlist: self.addnodemap(server, n) # do not record server name for networks since network # nodes are replicated across all server return (handle_locally, serverlist) if issubclass(nodecls, PyCoreNet) and \ nodetype == coreapi.CORE_NODE_WLAN: # special case where remote WLANs not in session._objs, and no # node response message received, so they are counted here if msg.gettlv(coreapi.CORE_TLV_NODE_EMUSRV) is not None: self.incrbootcount() elif issubclass(nodecls, PyCoreNode): name = msg.gettlv(coreapi.CORE_TLV_NODE_NAME) if name: serverfiletxt = "%s %s %s" % (n, name, nodecls) if issubclass(nodecls, PhysicalNode): # remember physical nodes self.addphys(n) # emulation server TLV specifies server server = msg.gettlv(coreapi.CORE_TLV_NODE_EMUSRV) if server is not None: self.addnodemap(server, n) if server not in serverlist: serverlist.append(server) if serverfiletxt and self.session.master: self.writenodeserver(serverfiletxt, server) # hook to update coordinates of physical nodes if n in self.phys: self.session.mobility.physnodeupdateposition(msg) return (handle_locally, serverlist) def handlelinkmsg(self, msg): ''' Determine and return the servers to which this link message should be forwarded. Also build tunnels between different servers or add opaque data to the link message before forwarding. ''' serverlist = [] handle_locally = False # determine link message destination using non-network nodes nn = msg.nodenumbers() if nn[0] in self.nets: if nn[1] in self.nets: # two network nodes linked together - prevent loops caused by # the automatic tunnelling handle_locally = True else: serverlist = self.getserversbynode(nn[1]) elif nn[1] in self.nets: serverlist = self.getserversbynode(nn[0]) else: serverset1 = set(self.getserversbynode(nn[0])) serverset2 = set(self.getserversbynode(nn[1])) # nodes are on two different servers, build tunnels as needed if serverset1 != serverset2: localn = None if len(serverset1) == 0 or len(serverset2) == 0: handle_locally = True serverlist = list(serverset1 | serverset2) host = None # get the IP of remote server and decide which node number # is for a local node for server in serverlist: (host, port, sock) = self.getserver(server) if host is None: # named server is local handle_locally = True if server in serverset1: localn = nn[0] else: localn = nn[1] if handle_locally and localn is None: # having no local node at this point indicates local node is # the one with the empty serverset if len(serverset1) == 0: localn = nn[0] elif len(serverset2) == 0: localn = nn[1] if host is None: host = self.getlinkendpoint(msg, localn == nn[0]) if localn is None: msg = self.addlinkendpoints(msg, serverset1, serverset2) elif msg.flags & coreapi.CORE_API_ADD_FLAG: self.addtunnel(host, nn[0], nn[1], localn) elif msg.flags & coreapi.CORE_API_DEL_FLAG: self.deltunnel(nn[0], nn[1]) handle_locally = False else: serverlist = list(serverset1 | serverset2) return (handle_locally, serverlist, msg) def addlinkendpoints(self, msg, serverset1, serverset2): ''' For a link message that is not handled locally, inform the remote servers of the IP addresses used as tunnel endpoints by adding opaque data to the link message. ''' ip1 = "" for server in serverset1: (host, port, sock) = self.getserver(server) if host is not None: ip1 = host ip2 = "" for server in serverset2: (host, port, sock) = self.getserver(server) if host is not None: ip2 = host tlvdata = msg.rawmsg[coreapi.CoreMessage.hdrsiz:] tlvdata += coreapi.CoreLinkTlv.pack(coreapi.CORE_TLV_LINK_OPAQUE, "%s:%s" % (ip1, ip2)) newraw = coreapi.CoreLinkMessage.pack(msg.flags, tlvdata) msghdr = newraw[:coreapi.CoreMessage.hdrsiz] return coreapi.CoreLinkMessage(msg.flags, msghdr, tlvdata) def getlinkendpoint(self, msg, first_is_local): ''' A link message between two different servers has been received, and we need to determine the tunnel endpoint. First look for opaque data in the link message, otherwise use the IP of the message sender (the master server). ''' host = None opaque = msg.gettlv(coreapi.CORE_TLV_LINK_OPAQUE) if opaque is not None: if first_is_local: host = opaque.split(':')[1] else: host = opaque.split(':')[0] if host == "": host = None if host is None: # get IP address from API message sender (master) self.session._handlerslock.acquire() for h in self.session._handlers: if h.client_address != "": host = h.client_address[0] self.session._handlerslock.release() return host def handlerawmsg(self, msg): ''' Helper to invoke handlemsg() using raw (packed) message bytes. ''' hdr = msg[:coreapi.CoreMessage.hdrsiz] msgtype, flags, msglen = coreapi.CoreMessage.unpackhdr(hdr) msgcls = coreapi.msg_class(msgtype) return self.handlemsg(msgcls(flags, hdr, msg[coreapi.CoreMessage.hdrsiz:])) def forwardmsg(self, msg, serverlist, handle_locally): ''' Forward API message to all servers in serverlist; if an empty host/port is encountered, set the handle_locally flag. Returns the value of the handle_locally flag, which may be unchanged. ''' for server in serverlist: try: (host, port, sock) = self.getserver(server) except KeyError: # server not found, don't handle this message locally self.session.info("broker could not find server %s, message " \ "with type %s dropped" % \ (server, msg.msgtype)) continue if host is None and port is None: # local emulation server, handle this locally handle_locally = True else: if sock is None: self.session.info("server %s @ %s:%s is disconnected" % \ (server, host, port)) else: sock.send(msg.rawmsg) return handle_locally def writeservers(self): ''' Write the server list to a text file in the session directory upon startup: /tmp/pycore.nnnnn/servers ''' filename = os.path.join(self.session.sessiondir, "servers") try: f = open(filename, "w") master = self.session_id_master if master is None: master = self.session.sessionid f.write("master=%s\n" % master) self.servers_lock.acquire() for name in sorted(self.servers.keys()): if name == "localhost": continue (host, port, sock) = self.servers[name] try: (lhost, lport) = sock.getsockname() except: lhost, lport = None, None f.write("%s %s %s %s %s\n" % (name, host, port, lhost, lport)) f.close() except Exception, e: self.session.warn("Error writing server list to the file: %s\n%s" \ % (filename, e)) finally: self.servers_lock.release() def writenodeserver(self, nodestr, server): ''' Creates a /tmp/pycore.nnnnn/nX.conf/server file having the node and server info. This may be used by scripts for accessing nodes on other machines, much like local nodes may be accessed via the VnodeClient class. ''' (host, port, sock) = self.getserver(server) serverstr = "%s %s %s" % (server, host, port) name = nodestr.split()[1] dirname = os.path.join(self.session.sessiondir, name + ".conf") filename = os.path.join(dirname, "server") try: os.makedirs(dirname) except OSError: # directory may already exist from previous distributed run pass try: f = open(filename, "w") f.write("%s\n%s\n" % (serverstr, nodestr)) f.close() return True except Exception, e: msg = "Error writing server file '%s'" % filename msg += "for node %s:\n%s" % (name, e) self.session.warn(msg) return False core-4.8/daemon/core/bsd/0000775000175000017500000000000012534327775012302 500000000000000core-4.8/daemon/core/bsd/__init__.py0000664000175000017500000000000012534327775014321 00000000000000core-4.8/daemon/core/bsd/netgraph.py0000664000175000017500000000430312534327775014404 00000000000000# # CORE # Copyright (c)2010-2012 the Boeing Company. # See the LICENSE file included in this distribution. # # authors: core-dev@pf.itd.nrl.navy.mil # ''' netgraph.py: Netgraph helper functions; for now these are wrappers around ngctl commands. ''' import subprocess from core.misc.utils import * from core.constants import * checkexec([NGCTL_BIN]) def createngnode(type, hookstr, name=None): ''' Create a new Netgraph node of type and optionally assign name. The hook string hookstr should contain two names. This is a string so other commands may be inserted after the two names. Return the name and netgraph ID of the new node. ''' hook1 = hookstr.split()[0] ngcmd = "mkpeer %s %s \n show .%s" % (type, hookstr, hook1) cmd = [NGCTL_BIN, "-f", "-"] cmdid = subprocess.Popen(cmd, stdin = subprocess.PIPE, stdout = subprocess.PIPE, stderr = subprocess.PIPE) cmdid.stdin.write(ngcmd) cmdid.stdin.close() result = cmdid.stdout.read() result += cmdid.stderr.read() cmdid.stdout.close() cmdid.stderr.close() status = cmdid.wait() if status > 0: raise Exception, "error creating Netgraph node %s (%s): %s" % \ (type, ngcmd, result) results = result.split() ngname = results[1] ngid = results[5] if name: check_call([NGCTL_BIN, "name", "[0x%s]:" % ngid, name]) return (ngname, ngid) def destroyngnode(name): ''' Shutdown a Netgraph node having the given name. ''' check_call([NGCTL_BIN, "shutdown", "%s:" % name]) def connectngnodes(name1, name2, hook1, hook2): ''' Connect two hooks of two Netgraph nodes given by their names. ''' node1 = "%s:" % name1 node2 = "%s:" % name2 check_call([NGCTL_BIN, "connect", node1, node2, hook1, hook2]) def ngmessage(name, msg): ''' Send a Netgraph message to the node named name. ''' cmd = [NGCTL_BIN, "msg", "%s:" % name] + msg check_call(cmd) def ngloadkernelmodule(name): ''' Load a kernel module by invoking kldstat. This is needed for the ng_ether module which automatically creates Netgraph nodes when loaded. ''' mutecall(["kldload", name]) core-4.8/daemon/core/bsd/nodes.py0000664000175000017500000001707212534327775013713 00000000000000# # CORE # Copyright (c)2010-2013 the Boeing Company. # See the LICENSE file included in this distribution. # # author: core-dev@pf.itd.nrl.navy.mil # ''' nodes.py: definition of CoreNode classes and other node classes that inherit from the CoreNode, implementing specific node types. ''' from vnode import * from vnet import * from core.constants import * from core.misc.ipaddr import * from core.api import coreapi from core.bsd.netgraph import ngloadkernelmodule checkexec([IFCONFIG_BIN]) class CoreNode(JailNode): apitype = coreapi.CORE_NODE_DEF class PtpNet(NetgraphPipeNet): def tonodemsg(self, flags): ''' Do not generate a Node Message for point-to-point links. They are built using a link message instead. ''' pass def tolinkmsgs(self, flags): ''' Build CORE API TLVs for a point-to-point link. One Link message describes this network. ''' tlvdata = "" if len(self._netif) != 2: return tlvdata (if1, if2) = self._netif.items() if1 = if1[1] if2 = if2[1] tlvdata += coreapi.CoreLinkTlv.pack(coreapi.CORE_TLV_LINK_N1NUMBER, if1.node.objid) tlvdata += coreapi.CoreLinkTlv.pack(coreapi.CORE_TLV_LINK_N2NUMBER, if2.node.objid) delay = if1.getparam('delay') bw = if1.getparam('bw') loss = if1.getparam('loss') duplicate = if1.getparam('duplicate') jitter = if1.getparam('jitter') if delay is not None: tlvdata += coreapi.CoreLinkTlv.pack(coreapi.CORE_TLV_LINK_DELAY, delay) if bw is not None: tlvdata += coreapi.CoreLinkTlv.pack(coreapi.CORE_TLV_LINK_BW, bw) if loss is not None: tlvdata += coreapi.CoreLinkTlv.pack(coreapi.CORE_TLV_LINK_PER, str(loss)) if duplicate is not None: tlvdata += coreapi.CoreLinkTlv.pack(coreapi.CORE_TLV_LINK_DUP, str(duplicate)) if jitter is not None: tlvdata += coreapi.CoreLinkTlv.pack(coreapi.CORE_TLV_LINK_JITTER, jitter) tlvdata += coreapi.CoreLinkTlv.pack(coreapi.CORE_TLV_LINK_TYPE, self.linktype) tlvdata += coreapi.CoreLinkTlv.pack(coreapi.CORE_TLV_LINK_IF1NUM, \ if1.node.getifindex(if1)) if if1.hwaddr: tlvdata += coreapi.CoreLinkTlv.pack(coreapi.CORE_TLV_LINK_IF1MAC, if1.hwaddr) for addr in if1.addrlist: (ip, sep, mask) = addr.partition('/') mask = int(mask) if isIPv4Address(ip): family = AF_INET tlvtypeip = coreapi.CORE_TLV_LINK_IF1IP4 tlvtypemask = coreapi.CORE_TLV_LINK_IF1IP4MASK else: family = AF_INET6 tlvtypeip = coreapi.CORE_TLV_LINK_IF1IP6 tlvtypemask = coreapi.CORE_TLV_LINK_IF1IP6MASK ipl = socket.inet_pton(family, ip) tlvdata += coreapi.CoreLinkTlv.pack(tlvtypeip, IPAddr(af=family, addr=ipl)) tlvdata += coreapi.CoreLinkTlv.pack(tlvtypemask, mask) tlvdata += coreapi.CoreLinkTlv.pack(coreapi.CORE_TLV_LINK_IF2NUM, \ if2.node.getifindex(if2)) if if2.hwaddr: tlvdata += coreapi.CoreLinkTlv.pack(coreapi.CORE_TLV_LINK_IF2MAC, if2.hwaddr) for addr in if2.addrlist: (ip, sep, mask) = addr.partition('/') mask = int(mask) if isIPv4Address(ip): family = AF_INET tlvtypeip = coreapi.CORE_TLV_LINK_IF2IP4 tlvtypemask = coreapi.CORE_TLV_LINK_IF2IP4MASK else: family = AF_INET6 tlvtypeip = coreapi.CORE_TLV_LINK_IF2IP6 tlvtypemask = coreapi.CORE_TLV_LINK_IF2IP6MASK ipl = socket.inet_pton(family, ip) tlvdata += coreapi.CoreLinkTlv.pack(tlvtypeip, IPAddr(af=family, addr=ipl)) tlvdata += coreapi.CoreLinkTlv.pack(tlvtypemask, mask) msg = coreapi.CoreLinkMessage.pack(flags, tlvdata) return [msg,] class SwitchNode(NetgraphNet): ngtype = "bridge" nghooks = "link0 link0\nmsg .link0 setpersistent" apitype = coreapi.CORE_NODE_SWITCH policy = "ACCEPT" class HubNode(NetgraphNet): ngtype = "hub" nghooks = "link0 link0\nmsg .link0 setpersistent" apitype = coreapi.CORE_NODE_HUB policy = "ACCEPT" class WlanNode(NetgraphNet): ngtype = "wlan" nghooks = "anchor anchor" apitype = coreapi.CORE_NODE_WLAN linktype = coreapi.CORE_LINK_WIRELESS policy = "DROP" def __init__(self, session, objid = None, name = None, verbose = False, start = True, policy = None): NetgraphNet.__init__(self, session, objid, name, verbose, start, policy) # wireless model such as basic range self.model = None # mobility model such as scripted self.mobility = None def attach(self, netif): NetgraphNet.attach(self, netif) if self.model: netif.poshook = self.model._positioncallback if netif.node is None: return (x,y,z) = netif.node.position.get() netif.poshook(netif, x, y, z) def setmodel(self, model, config): ''' Mobility and wireless model. ''' if (self.verbose): self.info("adding model %s" % model._name) if model._type == coreapi.CORE_TLV_REG_WIRELESS: self.model = model(session=self.session, objid=self.objid, verbose=self.verbose, values=config) if self.model._positioncallback: for netif in self.netifs(): netif.poshook = self.model._positioncallback if netif.node is not None: (x,y,z) = netif.node.position.get() netif.poshook(netif, x, y, z) self.model.setlinkparams() elif model._type == coreapi.CORE_TLV_REG_MOBILITY: self.mobility = model(session=self.session, objid=self.objid, verbose=self.verbose, values=config) class RJ45Node(NetgraphPipeNet): apitype = coreapi.CORE_NODE_RJ45 policy = "ACCEPT" def __init__(self, session, objid, name, verbose, start = True): if start: ngloadkernelmodule("ng_ether") NetgraphPipeNet.__init__(self, session, objid, name, verbose, start) if start: self.setpromisc(True) def shutdown(self): self.setpromisc(False) NetgraphPipeNet.shutdown(self) def setpromisc(self, promisc): p = "promisc" if not promisc: p = "-" + p check_call([IFCONFIG_BIN, self.name, "up", p]) def attach(self, netif): if len(self._netif) > 0: raise ValueError, \ "RJ45 networks support at most 1 network interface" NetgraphPipeNet.attach(self, netif) connectngnodes(self.ngname, self.name, self.gethook(), "lower") class TunnelNode(NetgraphNet): ngtype = "pipe" nghooks = "upper lower" apitype = coreapi.CORE_NODE_TUNNEL policy = "ACCEPT" core-4.8/daemon/core/bsd/vnet.py0000664000175000017500000001667212534327775013564 00000000000000# # CORE # Copyright (c)2010-2012 the Boeing Company. # See the LICENSE file included in this distribution. # # authors: core-dev@pf.itd.nrl.navy.mil # ''' vnet.py: NetgraphNet and NetgraphPipeNet classes that implement virtual networks using the FreeBSD Netgraph subsystem. ''' import sys, threading from core.misc.utils import * from core.constants import * from core.coreobj import PyCoreNet, PyCoreObj from core.bsd.netgraph import * from core.bsd.vnode import VEth class NetgraphNet(PyCoreNet): ngtype = None nghooks = () def __init__(self, session, objid = None, name = None, verbose = False, start = True, policy = None): PyCoreNet.__init__(self, session, objid, name) if name is None: name = str(self.objid) if policy is not None: self.policy = policy self.name = name self.ngname = "n_%s_%s" % (str(self.objid), self.session.sessionid) self.ngid = None self.verbose = verbose self._netif = {} self._linked = {} self.up = False if start: self.startup() def startup(self): tmp, self.ngid = createngnode(type=self.ngtype, hookstr=self.nghooks, name=self.ngname) self.up = True def shutdown(self): if not self.up: return self.up = False while self._netif: k, netif = self._netif.popitem() if netif.pipe: pipe = netif.pipe netif.pipe = None pipe.shutdown() else: netif.shutdown() self._netif.clear() self._linked.clear() del self.session destroyngnode(self.ngname) def attach(self, netif): ''' Attach an interface to this netgraph node. Create a pipe between the interface and the hub/switch/wlan node. (Note that the PtpNet subclass overrides this method.) ''' if self.up: pipe = self.session.addobj(cls = NetgraphPipeNet, verbose = self.verbose, start = True) pipe.attach(netif) hook = "link%d" % len(self._netif) pipe.attachnet(self, hook) PyCoreNet.attach(self, netif) def detach(self, netif): if self.up: pass PyCoreNet.detach(self, netif) def linked(self, netif1, netif2): # check if the network interfaces are attached to this network if self._netif[netif1] != netif1: raise ValueError, "inconsistency for netif %s" % netif1.name if self._netif[netif2] != netif2: raise ValueError, "inconsistency for netif %s" % netif2.name try: linked = self._linked[netif1][netif2] except KeyError: linked = False self._linked[netif1][netif2] = linked return linked def unlink(self, netif1, netif2): if not self.linked(netif1, netif2): return msg = ["unlink", "{", "node1=0x%s" % netif1.pipe.ngid] msg += ["node2=0x%s" % netif2.pipe.ngid, "}"] ngmessage(self.ngname, msg) self._linked[netif1][netif2] = False def link(self, netif1, netif2): if self.linked(netif1, netif2): return msg = ["link", "{", "node1=0x%s" % netif1.pipe.ngid] msg += ["node2=0x%s" % netif2.pipe.ngid, "}"] ngmessage(self.ngname, msg) self._linked[netif1][netif2] = True def linknet(self, net): ''' Link this bridge with another by creating a veth pair and installing each device into each bridge. ''' raise NotImplementedError def linkconfig(self, netif, bw = None, delay = None, loss = None, duplicate = None, jitter = None, netif2=None): ''' Set link effects by modifying the pipe connected to an interface. ''' if not netif.pipe: self.warn("linkconfig for %s but interface %s has no pipe" % \ (self.name, netif.name)) return return netif.pipe.linkconfig(netif, bw, delay, loss, duplicate, jitter, netif2) class NetgraphPipeNet(NetgraphNet): ngtype = "pipe" nghooks = "upper lower" def __init__(self, session, objid = None, name = None, verbose = False, start = True, policy = None): NetgraphNet.__init__(self, session, objid, name, verbose, start, policy) if start: # account for Ethernet header ngmessage(self.ngname, ["setcfg", "{", "header_offset=14", "}"]) def attach(self, netif): ''' Attach an interface to this pipe node. The first interface is connected to the "upper" hook, the second connected to the "lower" hook. ''' if len(self._netif) > 1: raise ValueError, \ "Netgraph pipes support at most 2 network interfaces" if self.up: hook = self.gethook() connectngnodes(self.ngname, netif.localname, hook, netif.hook) if netif.pipe: raise ValueError, \ "Interface %s already attached to pipe %s" % \ (netif.name, netif.pipe.name) netif.pipe = self self._netif[netif] = netif self._linked[netif] = {} def attachnet(self, net, hook): ''' Attach another NetgraphNet to this pipe node. ''' localhook = self.gethook() connectngnodes(self.ngname, net.ngname, localhook, hook) def gethook(self): ''' Returns the first hook (e.g. "upper") then the second hook (e.g. "lower") based on the number of connections. ''' hooks = self.nghooks.split() if len(self._netif) == 0: return hooks[0] else: return hooks[1] def linkconfig(self, netif, bw = None, delay = None, loss = None, duplicate = None, jitter = None, netif2 = None): ''' Set link effects by sending a Netgraph setcfg message to the pipe. ''' netif.setparam('bw', bw) netif.setparam('delay', delay) netif.setparam('loss', loss) netif.setparam('duplicate', duplicate) netif.setparam('jitter', jitter) if not self.up: return params = [] upstream = [] downstream = [] if bw is not None: if str(bw)=="0": bw="-1" params += ["bandwidth=%s" % bw,] if delay is not None: if str(delay)=="0": delay="-1" params += ["delay=%s" % delay,] if loss is not None: if str(loss)=="0": loss="-1" upstream += ["BER=%s" % loss,] downstream += ["BER=%s" % loss,] if duplicate is not None: if str(duplicate)=="0": duplicate="-1" upstream += ["duplicate=%s" % duplicate,] downstream += ["duplicate=%s" % duplicate,] if jitter: self.warn("jitter parameter ignored for link %s" % self.name) if len(params) > 0 or len(upstream) > 0 or len(downstream) > 0: setcfg = ["setcfg", "{",] + params if len(upstream) > 0: setcfg += ["upstream={",] + upstream + ["}",] if len(downstream) > 0: setcfg += ["downstream={",] + downstream + ["}",] setcfg += ["}",] ngmessage(self.ngname, setcfg) core-4.8/daemon/core/bsd/vnode.py0000664000175000017500000003171512534327775013716 00000000000000# # CORE # Copyright (c)2010-2012 the Boeing Company. # See the LICENSE file included in this distribution. # # authors: core-dev@pf.itd.nrl.navy.mil # ''' vnode.py: SimpleJailNode and JailNode classes that implement the FreeBSD jail-based virtual node. ''' import os, signal, sys, subprocess, threading, string import random, time from core.misc.utils import * from core.constants import * from core.coreobj import PyCoreObj, PyCoreNode, PyCoreNetIf, Position from core.emane.nodes import EmaneNode from core.bsd.netgraph import * checkexec([IFCONFIG_BIN, VIMAGE_BIN]) class VEth(PyCoreNetIf): def __init__(self, node, name, localname, mtu = 1500, net = None, start = True): PyCoreNetIf.__init__(self, node = node, name = name, mtu = mtu) # name is the device name (e.g. ngeth0, ngeth1, etc.) before it is # installed in a node; the Netgraph name is renamed to localname # e.g. before install: name = ngeth0 localname = n0_0_123 # after install: name = eth0 localname = n0_0_123 self.localname = localname self.ngid = None self.net = None self.pipe = None self.addrlist = [] self.hwaddr = None self.up = False self.hook = "ether" if start: self.startup() def startup(self): hookstr = "%s %s" % (self.hook, self.hook) ngname, ngid = createngnode(type="eiface", hookstr=hookstr, name=self.localname) self.name = ngname self.ngid = ngid check_call([IFCONFIG_BIN, ngname, "up"]) self.up = True def shutdown(self): if not self.up: return destroyngnode(self.localname) self.up = False def attachnet(self, net): if self.net: self.detachnet() self.net = None net.attach(self) self.net = net def detachnet(self): if self.net is not None: self.net.detach(self) def addaddr(self, addr): self.addrlist.append(addr) def deladdr(self, addr): self.addrlist.remove(addr) def sethwaddr(self, addr): self.hwaddr = addr class TunTap(PyCoreNetIf): '''TUN/TAP virtual device in TAP mode''' def __init__(self, node, name, localname, mtu = None, net = None, start = True): raise NotImplementedError class SimpleJailNode(PyCoreNode): def __init__(self, session, objid = None, name = None, nodedir = None, verbose = False): PyCoreNode.__init__(self, session, objid, name) self.nodedir = nodedir self.verbose = verbose self.pid = None self.up = False self.lock = threading.RLock() self._mounts = [] def startup(self): if self.up: raise Exception, "already up" vimg = [VIMAGE_BIN, "-c", self.name] try: os.spawnlp(os.P_WAIT, VIMAGE_BIN, *vimg) except OSError: raise Exception, ("vimage command not found while running: %s" % \ vimg) self.info("bringing up loopback interface") self.cmd([IFCONFIG_BIN, "lo0", "127.0.0.1"]) self.info("setting hostname: %s" % self.name) self.cmd(["hostname", self.name]) self.cmd([SYSCTL_BIN, "vfs.morphing_symlinks=1"]) self.up = True def shutdown(self): if not self.up: return for netif in self.netifs(): netif.shutdown() self._netif.clear() del self.session vimg = [VIMAGE_BIN, "-d", self.name] try: os.spawnlp(os.P_WAIT, VIMAGE_BIN, *vimg) except OSError: raise Exception, ("vimage command not found while running: %s" % \ vimg) self.up = False def cmd(self, args, wait = True): if wait: mode = os.P_WAIT else: mode = os.P_NOWAIT tmp = call([VIMAGE_BIN, self.name] + args, cwd=self.nodedir) if not wait: tmp = None if tmp: self.warn("cmd exited with status %s: %s" % (tmp, str(args))) return tmp def cmdresult(self, args, wait = True): cmdid, cmdin, cmdout, cmderr = self.popen(args) result = cmdout.read() result += cmderr.read() cmdin.close() cmdout.close() cmderr.close() if wait: status = cmdid.wait() else: status = 0 return (status, result) def popen(self, args): cmd = [VIMAGE_BIN, self.name] cmd.extend(args) tmp = subprocess.Popen(cmd, stdin = subprocess.PIPE, stdout = subprocess.PIPE, stderr = subprocess.PIPE, cwd=self.nodedir) return tmp, tmp.stdin, tmp.stdout, tmp.stderr def icmd(self, args): return os.spawnlp(os.P_WAIT, VIMAGE_BIN, VIMAGE_BIN, self.name, *args) def term(self, sh = "/bin/sh"): return os.spawnlp(os.P_WAIT, "xterm", "xterm", "-ut", "-title", self.name, "-e", VIMAGE_BIN, self.name, sh) def termcmdstring(self, sh = "/bin/sh"): ''' We add 'sudo' to the command string because the GUI runs as a normal user. ''' return "cd %s && sudo %s %s %s" % (self.nodedir, VIMAGE_BIN, self.name, sh) def shcmd(self, cmdstr, sh = "/bin/sh"): return self.cmd([sh, "-c", cmdstr]) def boot(self): pass def mount(self, source, target): source = os.path.abspath(source) self.info("mounting %s at %s" % (source, target)) self.addsymlink(path=target, file=None) def umount(self, target): self.info("unmounting '%s'" % target) def newveth(self, ifindex = None, ifname = None, net = None): self.lock.acquire() try: if ifindex is None: ifindex = self.newifindex() if ifname is None: ifname = "eth%d" % ifindex sessionid = self.session.shortsessionid() name = "n%s_%s_%s" % (self.objid, ifindex, sessionid) localname = name ifclass = VEth veth = ifclass(node = self, name = name, localname = localname, mtu = 1500, net = net, start = self.up) if self.up: # install into jail check_call([IFCONFIG_BIN, veth.name, "vnet", self.name]) # rename from "ngeth0" to "eth0" self.cmd([IFCONFIG_BIN, veth.name, "name", ifname]) veth.name = ifname try: self.addnetif(veth, ifindex) except: veth.shutdown() del veth raise return ifindex finally: self.lock.release() def sethwaddr(self, ifindex, addr): self._netif[ifindex].sethwaddr(addr) if self.up: self.cmd([IFCONFIG_BIN, self.ifname(ifindex), "link", str(addr)]) def addaddr(self, ifindex, addr): if self.up: if ':' in addr: family = "inet6" else: family = "inet" self.cmd([IFCONFIG_BIN, self.ifname(ifindex), family, "alias", str(addr)]) self._netif[ifindex].addaddr(addr) def deladdr(self, ifindex, addr): try: self._netif[ifindex].deladdr(addr) except ValueError: self.warn("trying to delete unknown address: %s" % addr) if self.up: if ':' in addr: family = "inet6" else: family = "inet" self.cmd([IFCONFIG_BIN, self.ifname(ifindex), family, "-alias", str(addr)]) valid_deladdrtype = ("inet", "inet6", "inet6link") def delalladdr(self, ifindex, addrtypes = valid_deladdrtype): addr = self.getaddr(self.ifname(ifindex), rescan = True) for t in addrtypes: if t not in self.valid_deladdrtype: raise ValueError, "addr type must be in: " + \ " ".join(self.valid_deladdrtype) for a in addr[t]: self.deladdr(ifindex, a) # update cached information self.getaddr(self.ifname(ifindex), rescan = True) def ifup(self, ifindex): if self.up: self.cmd([IFCONFIG_BIN, self.ifname(ifindex), "up"]) def newnetif(self, net = None, addrlist = [], hwaddr = None, ifindex = None, ifname = None): self.lock.acquire() try: ifindex = self.newveth(ifindex = ifindex, ifname = ifname, net = net) if net is not None: self.attachnet(ifindex, net) if hwaddr: self.sethwaddr(ifindex, hwaddr) for addr in maketuple(addrlist): self.addaddr(ifindex, addr) self.ifup(ifindex) return ifindex finally: self.lock.release() def attachnet(self, ifindex, net): self._netif[ifindex].attachnet(net) def detachnet(self, ifindex): self._netif[ifindex].detachnet() def addfile(self, srcname, filename): shcmd = "mkdir -p $(dirname '%s') && mv '%s' '%s' && sync" % \ (filename, srcname, filename) self.shcmd(shcmd) def getaddr(self, ifname, rescan = False): return None #return self.vnodeclient.getaddr(ifname = ifname, rescan = rescan) def addsymlink(self, path, file): ''' Create a symbolic link from /path/name/file -> /tmp/pycore.nnnnn/@.conf/path.name/file ''' dirname = path if dirname and dirname[0] == "/": dirname = dirname[1:] dirname = dirname.replace("/", ".") if file: pathname = os.path.join(path, file) sym = os.path.join(self.session.sessiondir, "@.conf", dirname, file) else: pathname = path sym = os.path.join(self.session.sessiondir, "@.conf", dirname) if os.path.islink(pathname): if os.readlink(pathname) == sym: # this link already exists - silently return return os.unlink(pathname) else: if os.path.exists(pathname): self.warn("did not create symlink for %s since path " \ "exists on host" % pathname) return self.info("creating symlink %s -> %s" % (pathname, sym)) os.symlink(sym, pathname) class JailNode(SimpleJailNode): def __init__(self, session, objid = None, name = None, nodedir = None, bootsh = "boot.sh", verbose = False, start = True): super(JailNode, self).__init__(session = session, objid = objid, name = name, nodedir = nodedir, verbose = verbose) self.bootsh = bootsh if not start: return # below here is considered node startup/instantiation code self.makenodedir() self.startup() def boot(self): self.session.services.bootnodeservices(self) def validate(self): self.session.services.validatenodeservices(self) def startup(self): self.lock.acquire() try: super(JailNode, self).startup() #self.privatedir("/var/run") #self.privatedir("/var/log") finally: self.lock.release() def shutdown(self): if not self.up: return self.lock.acquire() # services are instead stopped when session enters datacollect state #self.session.services.stopnodeservices(self) try: super(JailNode, self).shutdown() finally: self.rmnodedir() self.lock.release() def privatedir(self, path): if path[0] != "/": raise ValueError, "path not fully qualified: " + path hostpath = os.path.join(self.nodedir, path[1:].replace("/", ".")) try: os.mkdir(hostpath) except OSError: pass except Exception, e: raise Exception, e self.mount(hostpath, path) def opennodefile(self, filename, mode = "w"): dirname, basename = os.path.split(filename) #self.addsymlink(path=dirname, file=basename) if not basename: raise ValueError, "no basename for filename: " + filename if dirname and dirname[0] == "/": dirname = dirname[1:] dirname = dirname.replace("/", ".") dirname = os.path.join(self.nodedir, dirname) if not os.path.isdir(dirname): os.makedirs(dirname, mode = 0755) hostfilename = os.path.join(dirname, basename) return open(hostfilename, mode) def nodefile(self, filename, contents, mode = 0644): f = self.opennodefile(filename, "w") f.write(contents) os.chmod(f.name, mode) f.close() self.info("created nodefile: '%s'; mode: 0%o" % (f.name, mode)) core-4.8/daemon/core/conf.py0000664000175000017500000003363212534327775012760 00000000000000# # CORE # Copyright (c)2012 the Boeing Company. # See the LICENSE file included in this distribution. # # authors: Jeff Ahrenholz # ''' conf.py: common support for configurable objects ''' import string from core.api import coreapi class ConfigurableManager(object): ''' A generic class for managing Configurables. This class can register with a session to receive Config Messages for setting some parameters for itself or for the Configurables that it manages. ''' # name corresponds to configuration object field _name = "" # type corresponds with register message types _type = None def __init__(self, session=None): self.session = session self.session.addconfobj(self._name, self._type, self.configure) # Configurable key=values, indexed by node number self.configs = {} def configure(self, session, msg): ''' Handle configure messages. The configuration message sent to a ConfigurableManager usually is used to: 1. Request a list of Configurables (request flag) 2. Reset manager and clear configs (reset flag) 3. Send values that configure the manager or one of its Configurables Returns any reply messages. ''' objname = msg.gettlv(coreapi.CORE_TLV_CONF_OBJ) conftype = msg.gettlv(coreapi.CORE_TLV_CONF_TYPE) if conftype == coreapi.CONF_TYPE_FLAGS_REQUEST: return self.configure_request(msg) elif conftype == coreapi.CONF_TYPE_FLAGS_RESET: if objname == "all" or objname == self._name: return self.configure_reset(msg) else: return self.configure_values(msg, msg.gettlv(coreapi.CORE_TLV_CONF_VALUES)) def configure_request(self, msg): ''' Request configuration data. ''' return None def configure_reset(self, msg): ''' By default, resets this manager to clear configs. ''' return self.reset() def configure_values(self, msg, values): ''' Values have been sent to this manager. ''' return None def configure_values_keyvalues(self, msg, values, target, keys): ''' Helper that can be used for configure_values for parsing in 'key=value' strings from a values field. The key name must be in the keys list, and target.key=value is set. ''' if values is None: return None kvs = values.split('|') for kv in kvs: try: # key=value (key, value) = kv.split('=', 1) if value is not None and not value.strip(): value = None except ValueError: # value only key = keys[kvs.index(kv)] value = kv if key not in keys: raise ValueError, "invalid key: %s" % key if value is not None: setattr(target, key, value) return None def reset(self): return None def setconfig(self, nodenum, conftype, values): ''' add configuration values for a node to a dictionary; values are usually received from a Configuration Message, and may refer to a node for which no object exists yet ''' conflist = [] if nodenum in self.configs: oldlist = self.configs[nodenum] found = False for (t, v) in oldlist: if (t == conftype): # replace existing config found = True conflist.append((conftype, values)) else: conflist.append((t, v)) if not found: conflist.append((conftype, values)) else: conflist.append((conftype, values)) self.configs[nodenum] = conflist def getconfig(self, nodenum, conftype, defaultvalues): ''' get configuration values for a node; if the values don't exist in our dictionary then return the default values supplied ''' if nodenum in self.configs: # return configured values conflist = self.configs[nodenum] for (t, v) in conflist: if (conftype is None) or (t == conftype): return (t, v) # return default values provided (may be None) return (conftype, defaultvalues) def getallconfigs(self, use_clsmap=True): ''' Return (nodenum, conftype, values) tuples for all stored configs. Used when reconnecting to a session. ''' r = [] for nodenum in self.configs: for (t, v) in self.configs[nodenum]: if use_clsmap: t = self._modelclsmap[t] r.append( (nodenum, t, v) ) return r def clearconfig(self, nodenum): ''' remove configuration values for the specified node; when nodenum is None, remove all configuration values ''' if nodenum is None: self.configs = {} return if nodenum in self.configs: self.configs.pop(nodenum) def setconfig_keyvalues(self, nodenum, conftype, keyvalues): ''' keyvalues list of tuples ''' if conftype not in self._modelclsmap: self.warn("Unknown model type '%s'" % (conftype)) return model = self._modelclsmap[conftype] keys = model.getnames() # defaults are merged with supplied values here values = list(model.getdefaultvalues()) for key, value in keyvalues: if key not in keys: self.warn("Skipping unknown configuration key for %s: '%s'" % \ (conftype, key)) continue i = keys.index(key) values[i] = value self.setconfig(nodenum, conftype, values) def getmodels(self, n): ''' Return a list of model classes and values for a net if one has been configured. This is invoked when exporting a session to XML. This assumes self.configs contains an iterable of (model-names, values) and a self._modelclsmapdict exists. ''' r = [] if n.objid in self.configs: v = self.configs[n.objid] for model in v: cls = self._modelclsmap[model[0]] vals = model[1] r.append((cls, vals)) return r def info(self, msg): self.session.info(msg) def warn(self, msg): self.session.warn(msg) class Configurable(object): ''' A generic class for managing configuration parameters. Parameters are sent via Configuration Messages, which allow the GUI to build dynamic dialogs depending on what is being configured. ''' _name = "" # Configuration items: # ('name', 'type', 'default', 'possible-value-list', 'caption') _confmatrix = [] _confgroups = None _bitmap = None def __init__(self, session=None, objid=None): self.session = session self.objid = objid def reset(self): pass def register(self): pass @classmethod def getdefaultvalues(cls): return tuple( map(lambda x: x[2], cls._confmatrix) ) @classmethod def getnames(cls): return tuple( map( lambda x: x[0], cls._confmatrix) ) @classmethod def configure(cls, mgr, msg): ''' Handle configuration messages for this object. ''' reply = None nodenum = msg.gettlv(coreapi.CORE_TLV_CONF_NODE) objname = msg.gettlv(coreapi.CORE_TLV_CONF_OBJ) conftype = msg.gettlv(coreapi.CORE_TLV_CONF_TYPE) if mgr.verbose: mgr.info("received configure message for %s" % cls._name) if conftype == coreapi.CONF_TYPE_FLAGS_REQUEST: if mgr.verbose: mgr.info("replying to configure request for %s model" % cls._name) # when object name is "all", the reply to this request may be None # if this node has not been configured for this model; otherwise we # reply with the defaults for this model if objname == "all": defaults = None typeflags = coreapi.CONF_TYPE_FLAGS_UPDATE else: defaults = cls.getdefaultvalues() typeflags = coreapi.CONF_TYPE_FLAGS_NONE values = mgr.getconfig(nodenum, cls._name, defaults)[1] if values is None: # node has no active config for this model (don't send defaults) return None # reply with config options reply = cls.toconfmsg(0, nodenum, typeflags, values) elif conftype == coreapi.CONF_TYPE_FLAGS_RESET: if objname == "all": mgr.clearconfig(nodenum) #elif conftype == coreapi.CONF_TYPE_FLAGS_UPDATE: else: # store the configuration values for later use, when the node # object has been created if objname is None: mgr.info("no configuration object for node %s" % nodenum) return None values_str = msg.gettlv(coreapi.CORE_TLV_CONF_VALUES) defaults = cls.getdefaultvalues() if values_str is None: # use default or preconfigured values values = mgr.getconfig(nodenum, cls._name, defaults)[1] else: # use new values supplied from the conf message values = values_str.split('|') # determine new or old style config new = cls.haskeyvalues(values) if new: new_values = list(defaults) keys = cls.getnames() for v in values: key, value = v.split('=', 1) try: new_values[keys.index(key)] = value except ValueError: mgr.info("warning: ignoring invalid key '%s'" % key) values = new_values mgr.setconfig(nodenum, objname, values) return reply @classmethod def toconfmsg(cls, flags, nodenum, typeflags, values): ''' Convert this class to a Config API message. Some TLVs are defined by the class, but node number, conf type flags, and values must be passed in. ''' keys = cls.getnames() keyvalues = map(lambda a,b: "%s=%s" % (a,b), keys, values) values_str = string.join(keyvalues, '|') tlvdata = "" if nodenum is not None: tlvdata += coreapi.CoreConfTlv.pack(coreapi.CORE_TLV_CONF_NODE, nodenum) tlvdata += coreapi.CoreConfTlv.pack(coreapi.CORE_TLV_CONF_OBJ, cls._name) tlvdata += coreapi.CoreConfTlv.pack(coreapi.CORE_TLV_CONF_TYPE, typeflags) datatypes = tuple( map(lambda x: x[1], cls._confmatrix) ) tlvdata += coreapi.CoreConfTlv.pack(coreapi.CORE_TLV_CONF_DATA_TYPES, datatypes) tlvdata += coreapi.CoreConfTlv.pack(coreapi.CORE_TLV_CONF_VALUES, values_str) captions = reduce( lambda a,b: a + '|' + b, \ map(lambda x: x[4], cls._confmatrix)) tlvdata += coreapi.CoreConfTlv.pack(coreapi.CORE_TLV_CONF_CAPTIONS, captions) possiblevals = reduce( lambda a,b: a + '|' + b, \ map(lambda x: x[3], cls._confmatrix)) tlvdata += coreapi.CoreConfTlv.pack( coreapi.CORE_TLV_CONF_POSSIBLE_VALUES, possiblevals) if cls._bitmap is not None: tlvdata += coreapi.CoreConfTlv.pack(coreapi.CORE_TLV_CONF_BITMAP, cls._bitmap) if cls._confgroups is not None: tlvdata += coreapi.CoreConfTlv.pack(coreapi.CORE_TLV_CONF_GROUPS, cls._confgroups) msg = coreapi.CoreConfMessage.pack(flags, tlvdata) return msg @staticmethod def booltooffon(value): ''' Convenience helper turns bool into on (True) or off (False) string. ''' if value == "1" or value == "true" or value == "on": return "on" else: return "off" @staticmethod def offontobool(value): if type(value) == str: if value.lower() == "on": return 1 elif value.lower() == "off": return 0 return value @classmethod def valueof(cls, name, values): ''' Helper to return a value by the name defined in confmatrix. Checks if it is boolean''' i = cls.getnames().index(name) if cls._confmatrix[i][1] == coreapi.CONF_DATA_TYPE_BOOL and \ values[i] != "": return cls.booltooffon(values[i]) else: return values[i] @staticmethod def haskeyvalues(values): ''' Helper to check for list of key=value pairs versus a plain old list of values. Returns True if all elements are "key=value". ''' if len(values) == 0: return False for v in values: if "=" not in v: return False return True def getkeyvaluelist(self): ''' Helper to return a list of (key, value) tuples. Keys come from self._confmatrix and values are instance attributes. ''' r = [] for k in self.getnames(): if hasattr(self, k): r.append((k, getattr(self, k))) return r core-4.8/daemon/core/coreobj.py0000664000175000017500000004277712534327775013470 00000000000000# # CORE # Copyright (c)2010-2013 the Boeing Company. # See the LICENSE file included in this distribution. # # authors: Tom Goff # Jeff Ahrenholz # ''' coreobj.py: defines the basic objects for emulation: the PyCoreObj base class, along with PyCoreNode, PyCoreNet, and PyCoreNetIf ''' import sys, threading, os, shutil from core.api import coreapi from core.misc.ipaddr import * class Position(object): ''' Helper class for Cartesian coordinate position ''' def __init__(self, x = None, y = None, z = None): self.x = None self.y = None self.z = None self.set(x, y, z) def set(self, x = None, y = None, z = None): ''' Returns True if the position has actually changed. ''' if self.x == x and self.y == y and self.z == z: return False self.x = x self.y = y self.z = z return True def get(self): ''' Fetch the (x,y,z) position tuple. ''' return (self.x, self.y, self.z) class PyCoreObj(object): ''' Base class for pycore objects (nodes and nets) ''' apitype = None def __init__(self, session, objid = None, name = None, verbose = False, start = True): self.session = session if objid is None: objid = session.getobjid() self.objid = objid if name is None: name = "o%s" % self.objid self.name = name # ifindex is key, PyCoreNetIf instance is value self._netif = {} self.ifindex = 0 self.canvas = None self.icon = None self.opaque = None self.verbose = verbose self.position = Position() def startup(self): ''' Each object implements its own startup method. ''' raise NotImplementedError def shutdown(self): ''' Each object implements its own shutdown method. ''' raise NotImplementedError def setposition(self, x = None, y = None, z = None): ''' Set the (x,y,z) position of the object. ''' return self.position.set(x = x, y = y, z = z) def getposition(self): ''' Return an (x,y,z) tuple representing this object's position. ''' return self.position.get() def ifname(self, ifindex): return self.netif(ifindex).name def netifs(self, sort=False): ''' Iterate over attached network interfaces. ''' if sort: return map(lambda k: self._netif[k], sorted(self._netif.keys())) else: return self._netif.itervalues() def numnetif(self): ''' Return the attached interface count. ''' return len(self._netif) def getifindex(self, netif): for ifindex in self._netif: if self._netif[ifindex] is netif: return ifindex return -1 def newifindex(self): while self.ifindex in self._netif: self.ifindex += 1 ifindex = self.ifindex self.ifindex += 1 return ifindex def tonodemsg(self, flags): ''' Build a CORE API Node Message for this object. Both nodes and networks can be represented by a Node Message. ''' if self.apitype is None: return None tlvdata = "" (x, y, z) = self.getposition() tlvdata += coreapi.CoreNodeTlv.pack(coreapi.CORE_TLV_NODE_NUMBER, self.objid) tlvdata += coreapi.CoreNodeTlv.pack(coreapi.CORE_TLV_NODE_TYPE, self.apitype) tlvdata += coreapi.CoreNodeTlv.pack(coreapi.CORE_TLV_NODE_NAME, self.name) if hasattr(self, "type") and self.type is not None: tlvdata += coreapi.CoreNodeTlv.pack(coreapi.CORE_TLV_NODE_MODEL, self.type) if hasattr(self, "server") and self.server is not None: tlvdata += coreapi.CoreNodeTlv.pack(coreapi.CORE_TLV_NODE_EMUSRV, self.server) if hasattr(self, "services") and len(self.services) != 0: nodeservices = [] for s in self.services: nodeservices.append(s._name) tlvdata += coreapi.CoreNodeTlv.pack(coreapi.CORE_TLV_NODE_SERVICES, "|".join(nodeservices)) if x is not None: tlvdata += coreapi.CoreNodeTlv.pack(coreapi.CORE_TLV_NODE_XPOS, x) if y is not None: tlvdata += coreapi.CoreNodeTlv.pack(coreapi.CORE_TLV_NODE_YPOS, y) if self.canvas is not None: tlvdata += coreapi.CoreNodeTlv.pack(coreapi.CORE_TLV_NODE_CANVAS, self.canvas) tlvdata += coreapi.CoreNodeTlv.pack(coreapi.CORE_TLV_NODE_EMUID, self.objid) if self.icon is not None: tlvdata += coreapi.CoreNodeTlv.pack(coreapi.CORE_TLV_NODE_ICON, self.icon) if self.opaque is not None: tlvdata += coreapi.CoreNodeTlv.pack(coreapi.CORE_TLV_NODE_OPAQUE, self.opaque) msg = coreapi.CoreNodeMessage.pack(flags, tlvdata) return msg def tolinkmsgs(self, flags): ''' Build CORE API Link Messages for this object. There is no default method for PyCoreObjs as PyCoreNodes do not implement this but PyCoreNets do. ''' return [] def info(self, msg): ''' Utility method for printing informational messages when verbose is turned on. ''' if self.verbose: print "%s: %s" % (self.name, msg) sys.stdout.flush() def warn(self, msg): ''' Utility method for printing warning/error messages ''' print >> sys.stderr, "%s: %s" % (self.name, msg) sys.stderr.flush() def exception(self, level, source, text): ''' Generate an Exception Message for this session, providing this object number. ''' if self.session: id = None if isinstance(self.objid, int): id = self.objid elif isinstance(self.objid, str) and self.objid.isdigit(): id = int(self.objid) self.session.exception(level, source, id, text) class PyCoreNode(PyCoreObj): ''' Base class for nodes ''' def __init__(self, session, objid = None, name = None, verbose = False, start = True): ''' Initialization for node objects. ''' PyCoreObj.__init__(self, session, objid, name, verbose=verbose, start=start) self.services = [] if not hasattr(self, "type"): self.type = None self.nodedir = None def nodeid(self): return self.objid def addservice(self, service): if service is not None: self.services.append(service) def makenodedir(self): if self.nodedir is None: self.nodedir = \ os.path.join(self.session.sessiondir, self.name + ".conf") os.makedirs(self.nodedir) self.tmpnodedir = True else: self.tmpnodedir = False def rmnodedir(self): if hasattr(self.session.options, 'preservedir'): if self.session.options.preservedir == '1': return if self.tmpnodedir: shutil.rmtree(self.nodedir, ignore_errors = True) def addnetif(self, netif, ifindex): if ifindex in self._netif: raise ValueError, "ifindex %s already exists" % ifindex self._netif[ifindex] = netif def delnetif(self, ifindex): if ifindex not in self._netif: raise ValueError, "ifindex %s does not exist" % ifindex netif = self._netif.pop(ifindex) netif.shutdown() del netif def netif(self, ifindex, net = None): if ifindex in self._netif: return self._netif[ifindex] else: return None def attachnet(self, ifindex, net): if ifindex not in self._netif: raise ValueError, "ifindex %s does not exist" % ifindex self._netif[ifindex].attachnet(net) def detachnet(self, ifindex): if ifindex not in self._netif: raise ValueError, "ifindex %s does not exist" % ifindex self._netif[ifindex].detachnet() def setposition(self, x = None, y = None, z = None): changed = PyCoreObj.setposition(self, x = x, y = y, z = z) if not changed: # save extra interface range calculations return for netif in self.netifs(sort=True): netif.setposition(x, y, z) def commonnets(self, obj, want_ctrl=False): ''' Given another node or net object, return common networks between this node and that object. A list of tuples is returned, with each tuple consisting of (network, interface1, interface2). ''' r = [] for netif1 in self.netifs(): if not want_ctrl and hasattr(netif1, 'control'): continue for netif2 in obj.netifs(): if netif1.net == netif2.net: r += (netif1.net, netif1, netif2), return r class PyCoreNet(PyCoreObj): ''' Base class for networks ''' linktype = coreapi.CORE_LINK_WIRED def __init__(self, session, objid, name, verbose = False, start = True): ''' Initialization for network objects. ''' PyCoreObj.__init__(self, session, objid, name, verbose=verbose, start=start) self._linked = {} self._linked_lock = threading.Lock() def attach(self, netif): i = self.newifindex() self._netif[i] = netif netif.netifi = i with self._linked_lock: self._linked[netif] = {} def detach(self, netif): del self._netif[netif.netifi] netif.netifi = None with self._linked_lock: del self._linked[netif] def netifparamstolink(self, netif): ''' Helper for tolinkmsgs() to build TLVs having link parameters from interface parameters. ''' tlvdata = "" delay = netif.getparam('delay') bw = netif.getparam('bw') loss = netif.getparam('loss') duplicate = netif.getparam('duplicate') jitter = netif.getparam('jitter') if delay is not None: tlvdata += coreapi.CoreLinkTlv.pack(coreapi.CORE_TLV_LINK_DELAY, delay) if bw is not None: tlvdata += coreapi.CoreLinkTlv.pack(coreapi.CORE_TLV_LINK_BW, bw) if loss is not None: tlvdata += coreapi.CoreLinkTlv.pack(coreapi.CORE_TLV_LINK_PER, str(loss)) if duplicate is not None: tlvdata += coreapi.CoreLinkTlv.pack(coreapi.CORE_TLV_LINK_DUP, str(duplicate)) if jitter is not None: tlvdata += coreapi.CoreLinkTlv.pack(coreapi.CORE_TLV_LINK_JITTER, jitter) return tlvdata def tolinkmsgs(self, flags): ''' Build CORE API Link Messages for this network. Each link message describes a link between this network and a node. ''' msgs = [] # build a link message from this network node to each node having a # connected interface for netif in self.netifs(sort=True): if not hasattr(netif, "node"): continue otherobj = netif.node uni = False if otherobj is None: # two layer-2 switches/hubs linked together via linknet() if not hasattr(netif, "othernet"): continue otherobj = netif.othernet if otherobj.objid == self.objid: continue netif.swapparams('_params_up') upstream_params = netif.getparams() netif.swapparams('_params_up') if netif.getparams() != upstream_params: uni = True tlvdata = "" tlvdata += coreapi.CoreLinkTlv.pack(coreapi.CORE_TLV_LINK_N1NUMBER, self.objid) tlvdata += coreapi.CoreLinkTlv.pack(coreapi.CORE_TLV_LINK_N2NUMBER, otherobj.objid) tlvdata += self.netifparamstolink(netif) tlvdata += coreapi.CoreLinkTlv.pack(coreapi.CORE_TLV_LINK_TYPE, self.linktype) if uni: tlvdata += coreapi.CoreLinkTlv.pack(coreapi.CORE_TLV_LINK_UNI, 1) tlvdata += coreapi.CoreLinkTlv.pack(coreapi.CORE_TLV_LINK_IF2NUM, otherobj.getifindex(netif)) if netif.hwaddr: tlvdata += \ coreapi.CoreLinkTlv.pack(coreapi.CORE_TLV_LINK_IF2MAC, netif.hwaddr) for addr in netif.addrlist: (ip, sep, mask) = addr.partition('/') mask = int(mask) if isIPv4Address(ip): family = AF_INET tlvtypeip = coreapi.CORE_TLV_LINK_IF2IP4 tlvtypemask = coreapi.CORE_TLV_LINK_IF2IP4MASK else: family = AF_INET6 tlvtypeip = coreapi.CORE_TLV_LINK_IF2IP6 tlvtypemask = coreapi.CORE_TLV_LINK_IF2IP6MASK ipl = socket.inet_pton(family, ip) tlvdata += coreapi.CoreLinkTlv.pack(tlvtypeip, \ IPAddr(af=family, addr=ipl)) tlvdata += coreapi.CoreLinkTlv.pack(tlvtypemask, mask) msg = coreapi.CoreLinkMessage.pack(flags, tlvdata) msgs.append(msg) if not uni: continue # build a 2nd link message for any upstream link parameters tlvdata = "" tlvdata += coreapi.CoreLinkTlv.pack(coreapi.CORE_TLV_LINK_N1NUMBER, otherobj.objid) tlvdata += coreapi.CoreLinkTlv.pack(coreapi.CORE_TLV_LINK_N2NUMBER, self.objid) netif.swapparams('_params_up') tlvdata += self.netifparamstolink(netif) netif.swapparams('_params_up') tlvdata += coreapi.CoreLinkTlv.pack(coreapi.CORE_TLV_LINK_UNI, 1) msg = coreapi.CoreLinkMessage.pack(0, tlvdata) msgs.append(msg) return msgs class PyCoreNetIf(object): ''' Base class for interfaces. ''' def __init__(self, node, name, mtu): self.node = node self.name = name if not isinstance(mtu, (int, long)): raise ValueError self.mtu = mtu self.net = None self._params = {} self.addrlist = [] self.hwaddr = None self.poshook = None # used with EMANE self.transport_type = None # interface index on the network self.netindex = None def startup(self): pass def shutdown(self): pass def attachnet(self, net): if self.net: self.detachnet() self.net = None net.attach(self) self.net = net def detachnet(self): if self.net is not None: self.net.detach(self) def addaddr(self, addr): self.addrlist.append(addr) def deladdr(self, addr): self.addrlist.remove(addr) def sethwaddr(self, addr): self.hwaddr = addr def getparam(self, key): ''' Retrieve a parameter from the _params dict, or None if the parameter does not exist. ''' if key not in self._params: return None return self._params[key] def getparams(self): ''' Return (key, value) pairs from the _params dict. ''' r = [] for k in sorted(self._params.keys()): r.append((k, self._params[k])) return r def setparam(self, key, value): ''' Set a parameter in the _params dict. Returns True if the parameter has changed. ''' if key in self._params: if self._params[key] == value: return False elif self._params[key] <= 0 and value <= 0: # treat None and 0 as unchanged values return False self._params[key] = value return True def swapparams(self, name): ''' Swap out the _params dict for name. If name does not exist, intialize it. This is for supporting separate upstream/downstream parameters when two layer-2 nodes are linked together. ''' tmp = self._params if not hasattr(self, name): setattr(self, name, {}) self._params = getattr(self, name) setattr(self, name, tmp) def setposition(self, x, y, z): ''' Dispatch to any position hook (self.poshook) handler. ''' if self.poshook is not None: self.poshook(self, x, y, z) core-4.8/daemon/core/emane/0000775000175000017500000000000012534327775012617 500000000000000core-4.8/daemon/core/emane/__init__.py0000664000175000017500000000000012534327775014636 00000000000000core-4.8/daemon/core/emane/bypass.py0000664000175000017500000000431312534327775014413 00000000000000# # CORE # Copyright (c)2011-2012 the Boeing Company. # See the LICENSE file included in this distribution. # # author: Jeff Ahrenholz # ''' bypass.py: EMANE Bypass model for CORE ''' import sys import string from core.api import coreapi from core.constants import * from emane import EmaneModel class EmaneBypassModel(EmaneModel): def __init__(self, session, objid = None, verbose = False): EmaneModel.__init__(self, session, objid, verbose) _name = "emane_bypass" _confmatrix = [ ("none",coreapi.CONF_DATA_TYPE_BOOL, '0', 'True,False','There are no parameters for the bypass model.'), ] # value groupings _confgroups = "Bypass Parameters:1-1" def buildnemxmlfiles(self, e, ifc): ''' Build the necessary nem, mac, and phy XMLs in the given path. If an individual NEM has a nonstandard config, we need to build that file also. Otherwise the WLAN-wide nXXemane_bypassnem.xml, nXXemane_bypassmac.xml, nXXemane_bypassphy.xml are used. ''' values = e.getifcconfig(self.objid, self._name, self.getdefaultvalues(), ifc) if values is None: return nemdoc = e.xmldoc("nem") nem = nemdoc.getElementsByTagName("nem").pop() nem.setAttribute("name", "BYPASS NEM") e.appendtransporttonem(nemdoc, nem, self.objid, ifc) mactag = nemdoc.createElement("mac") mactag.setAttribute("definition", self.macxmlname(ifc)) nem.appendChild(mactag) phytag = nemdoc.createElement("phy") phytag.setAttribute("definition", self.phyxmlname(ifc)) nem.appendChild(phytag) e.xmlwrite(nemdoc, self.nemxmlname(ifc)) macdoc = e.xmldoc("mac") mac = macdoc.getElementsByTagName("mac").pop() mac.setAttribute("name", "BYPASS MAC") mac.setAttribute("library", "bypassmaclayer") e.xmlwrite(macdoc, self.macxmlname(ifc)) phydoc = e.xmldoc("phy") phy = phydoc.getElementsByTagName("phy").pop() phy.setAttribute("name", "BYPASS PHY") phy.setAttribute("library", "bypassphylayer") e.xmlwrite(phydoc, self.phyxmlname(ifc)) core-4.8/daemon/core/emane/commeffect.py0000664000175000017500000001231712534327775015225 00000000000000# # CORE # Copyright (c)2010-2014 the Boeing Company. # See the LICENSE file included in this distribution. # # authors: Jeff Ahrenholz # Randy Charland # ''' commeffect.py: EMANE CommEffect model for CORE ''' import sys import string try: from emanesh.events import EventService except: pass from core.api import coreapi from core.constants import * from emane import EmaneModel try: import emaneeventservice import emaneeventcommeffect except Exception, e: pass class EmaneCommEffectModel(EmaneModel): def __init__(self, session, objid = None, verbose = False): EmaneModel.__init__(self, session, objid, verbose) # model name _name = "emane_commeffect" # CommEffect parameters _confmatrix_shim_base = [ ("filterfile", coreapi.CONF_DATA_TYPE_STRING, '', '', 'filter file'), ("groupid", coreapi.CONF_DATA_TYPE_UINT32, '0', '', 'NEM Group ID'), ("enablepromiscuousmode", coreapi.CONF_DATA_TYPE_BOOL, '0', 'On,Off', 'enable promiscuous mode'), ("receivebufferperiod", coreapi.CONF_DATA_TYPE_FLOAT, '1.0', '', 'receivebufferperiod'), ] _confmatrix_shim_081 = [ ("defaultconnectivity", coreapi.CONF_DATA_TYPE_BOOL, '0', 'On,Off', 'defaultconnectivity'), ("enabletighttimingmode", coreapi.CONF_DATA_TYPE_BOOL, '0', 'On,Off', 'enable tight timing mode'), ] _confmatrix_shim_091 = [ ("defaultconnectivitymode", coreapi.CONF_DATA_TYPE_BOOL, '0', 'On,Off', 'defaultconnectivity'), ] if 'EventService' in globals(): _confmatrix_shim = _confmatrix_shim_base + _confmatrix_shim_091 else: _confmatrix_shim = _confmatrix_shim_base + _confmatrix_shim_081 _confmatrix = _confmatrix_shim # value groupings _confgroups = "CommEffect SHIM Parameters:1-%d" \ % len(_confmatrix_shim) def buildnemxmlfiles(self, e, ifc): ''' Build the necessary nem and commeffect XMLs in the given path. If an individual NEM has a nonstandard config, we need to build that file also. Otherwise the WLAN-wide nXXemane_commeffectnem.xml, nXXemane_commeffectshim.xml are used. ''' values = e.getifcconfig(self.objid, self._name, self.getdefaultvalues(), ifc) if values is None: return shimdoc = e.xmldoc("shim") shim = shimdoc.getElementsByTagName("shim").pop() shim.setAttribute("name", "commeffect SHIM") shim.setAttribute("library", "commeffectshim") names = self.getnames() shimnames = list(names[:len(self._confmatrix_shim)]) shimnames.remove("filterfile") # append all shim options (except filterfile) to shimdoc map( lambda n: shim.appendChild(e.xmlparam(shimdoc, n, \ self.valueof(n, values))), shimnames) # empty filterfile is not allowed ff = self.valueof("filterfile", values) if ff.strip() != '': shim.appendChild(e.xmlparam(shimdoc, "filterfile", ff)) e.xmlwrite(shimdoc, self.shimxmlname(ifc)) nemdoc = e.xmldoc("nem") nem = nemdoc.getElementsByTagName("nem").pop() nem.setAttribute("name", "commeffect NEM") nem.setAttribute("type", "unstructured") e.appendtransporttonem(nemdoc, nem, self.objid, ifc) nem.appendChild(e.xmlshimdefinition(nemdoc, self.shimxmlname(ifc))) e.xmlwrite(nemdoc, self.nemxmlname(ifc)) def linkconfig(self, netif, bw = None, delay = None, loss = None, duplicate = None, jitter = None, netif2 = None): ''' Generate CommEffect events when a Link Message is received having link parameters. ''' if self.session.emane.version >= self.session.emane.EMANE091: raise NotImplementedError, \ "CommEffect linkconfig() not implemented for EMANE 0.9.1+" def z(x): ''' Helper to use 0 for None values. ''' if type(x) is str: x = float(x) if x is None: return 0 else: return int(x) service = self.session.emane.service if service is None: self.session.warn("%s: EMANE event service unavailable" % \ self._name) return if netif is None or netif2 is None: self.session.warn("%s: missing NEM information" % self._name) return # TODO: batch these into multiple events per transmission # TODO: may want to split out seconds portion of delay and jitter event = emaneeventcommeffect.EventCommEffect(1) index = 0 e = self.session.obj(self.objid) nemid = e.getnemid(netif) nemid2 = e.getnemid(netif2) mbw = bw event.set(index, nemid, 0, z(delay), 0, z(jitter), z(loss), z(duplicate), long(z(bw)), long(z(mbw))) service.publish(emaneeventcommeffect.EVENT_ID, emaneeventservice.PLATFORMID_ANY, nemid2, emaneeventservice.COMPONENTID_ANY, event.export()) core-4.8/daemon/core/emane/emane.py0000664000175000017500000016270012534327775014204 00000000000000# # CORE # Copyright (c)2010-2014 the Boeing Company. # See the LICENSE file included in this distribution. # # author: Jeff Ahrenholz # ''' emane.py: definition of an Emane class for implementing configuration control of an EMANE emulation. ''' import sys, os, threading, subprocess, time, string from xml.dom.minidom import parseString, Document from core.constants import * from core.api import coreapi from core.misc.ipaddr import MacAddr from core.misc.utils import maketuplefromstr, cmdresult from core.misc.xmlutils import addtextelementsfromtuples, addparamlisttoparent from core.conf import ConfigurableManager, Configurable from core.mobility import WirelessModel from core.emane.nodes import EmaneNode # EMANE 0.7.4/0.8.1 try: import emaneeventservice import emaneeventlocation except Exception, e: pass # EMANE 0.9.1+ try: from emanesh.events import EventService from emanesh.events import LocationEvent except Exception, e: pass class Emane(ConfigurableManager): ''' EMANE controller object. Lives in a Session instance and is used for building EMANE config files from all of the EmaneNode objects in this emulation, and for controlling the EMANE daemons. ''' _name = "emane" _type = coreapi.CORE_TLV_REG_EMULSRV _hwaddr_prefix = "02:02" (SUCCESS, NOT_NEEDED, NOT_READY) = (0, 1, 2) EVENTCFGVAR = 'LIBEMANEEVENTSERVICECONFIG' # possible self.version values (EMANEUNK, EMANE074, EMANE081, EMANE091, EMANE092) = (0, 7, 8, 91, 92) DEFAULT_LOG_LEVEL = 3 def __init__(self, session): ConfigurableManager.__init__(self, session) self.verbose = self.session.getcfgitembool('verbose', False) self._objs = {} self._objslock = threading.Lock() self._ifccounts = {} self._ifccountslock = threading.Lock() self._modelclsmap = {} # Port numbers are allocated from these counters self.platformport = self.session.getcfgitemint('emane_platform_port', 8100) self.transformport = self.session.getcfgitemint('emane_transform_port', 8200) self.doeventloop = False self.eventmonthread = None self.detectversion() # model for global EMANE configuration options self.emane_config = EmaneGlobalModel(session, None, self.verbose) session.broker.handlers += (self.handledistributed, ) self.loadmodels() self.service = None def detectversion(self): ''' Detects the installed EMANE version and sets self.version. ''' self.version, self.versionstr = self.detectversionfromcmd() if self.verbose: self.info("detected EMANE version: %s" % self.versionstr) @classmethod def detectversionfromcmd(cls): ''' Runs 'emane --version' locally to determine version number. ''' # for further study: different EMANE versions on distributed machines try: # TODO: fix BUG here -- killall may kill this process too status, result = cmdresult(['emane', '--version']) except OSError: status = -1 result = "" v = cls.EMANEUNK if status == 0: if result[:5] == "0.7.4": v = cls.EMANE074 elif result[:5] == "0.8.1": v = cls.EMANE081 elif result[:5] == "0.9.1": v = cls.EMANE091 elif result[:5] == "0.9.2": v = cls.EMANE092 return v, result.strip() def initeventservice(self, filename=None, shutdown=False): ''' (Re-)initialize the EMANE Event service. The multicast group and/or port may be configured. - For versions < 0.9.1 this can be changed via XML config file and an environment variable pointing to that file. - For version >= 0.9.1 this is passed into the EventService constructor. ''' if hasattr(self, 'service'): del self.service self.service = None # EMANE 0.9.1+ does not require event service XML config if self.version >= self.EMANE091: if shutdown: return #Get the control network to be used for events values = self.getconfig(None, "emane", self.emane_config.getdefaultvalues())[1] group, port = self.emane_config.valueof('eventservicegroup', values).split(':') eventdev = self.emane_config.valueof('eventservicedevice', values) eventnetidx = self.session.getctrlnetidx(eventdev) if self.version > self.EMANE091: if eventnetidx < 0: msg = "Invalid Event Service device provided: %s" % eventdev self.session.exception(coreapi.CORE_EXCP_LEVEL_ERROR, "Emane.initeventservice()", None, msg) self.info(msg) return False # Make sure the event control network is in place eventnet = self.session.addremovectrlnet(netidx=eventnetidx, remove=False, conf_reqd=False) if eventnet is not None: # direct EMANE events towards control net bridge eventdev = eventnet.brname eventchannel = (group, int(port), eventdev) # disabled otachannel for event service # only needed for e.g. antennaprofile events xmit by models self.info("Using %s for event service traffic" % eventdev) try: self.service = EventService(eventchannel=eventchannel, otachannel=None) except Exception, e: msg = "Error instantiating EMANE event service: %s" % e self.session.exception(coreapi.CORE_EXCP_LEVEL_ERROR, "Emane.initeventservice()", None, msg) return True if filename is not None: tmp = os.getenv(self.EVENTCFGVAR) os.environ.update( {self.EVENTCFGVAR: filename} ) rc = True try: self.service = emaneeventservice.EventService() except: self.service = None rc = False if filename is not None: os.environ.pop(self.EVENTCFGVAR) if tmp is not None: os.environ.update( {self.EVENTCFGVAR: tmp} ) return rc def loadmodels(self): ''' dynamically load EMANE models that were specified in the config file ''' self._modelclsmap.clear() self._modelclsmap[self.emane_config._name] = self.emane_config emane_models = self.session.getcfgitem('emane_models') if emane_models is None: return emane_models = emane_models.split(',') for model in emane_models: model = model.strip() try: modelfile = "%s" % model.lower() clsname = "Emane%sModel" % model importcmd = "from %s import %s" % (modelfile, clsname) exec(importcmd) except Exception, e: warntxt = "unable to load the EMANE model '%s'" % modelfile warntxt += " specified in the config file (%s)" % e self.session.exception(coreapi.CORE_EXCP_LEVEL_WARNING, "emane", None, warntxt) self.warn(warntxt) continue # record the model name to class name mapping # this should match clsname._name confname = "emane_%s" % model.lower() self._modelclsmap[confname] = eval(clsname) # each EmaneModel must have ModelName.configure() defined confmethod = eval("%s.configure_emane" % clsname) self.session.addconfobj(confname, coreapi.CORE_TLV_REG_WIRELESS, confmethod) def addobj(self, obj): ''' add a new EmaneNode object to this Emane controller object ''' self._objslock.acquire() if obj.objid in self._objs: self._objslock.release() raise KeyError, "non-unique EMANE object id %s for %s" % \ (obj.objid, obj) self._objs[obj.objid] = obj self._objslock.release() def getnodes(self): ''' Return a set of CoreNodes that are linked to an EmaneNode, e.g. containers having one or more radio interfaces. ''' # assumes self._objslock already held r = set() for e in self._objs.values(): for netif in e.netifs(): r.add(netif.node) return r def getmodels(self, n): ''' Used with XML export; see ConfigurableManager.getmodels() ''' r = ConfigurableManager.getmodels(self, n) # EMANE global params are stored with first EMANE node (if non-default # values are configured) sorted_ids = sorted(self.configs.keys()) if None in self.configs and len(sorted_ids) > 1 and \ n.objid == sorted_ids[1]: v = self.configs[None] for model in v: cls = self._modelclsmap[model[0]] vals = model[1] r.append((cls, vals)) return r def getifcconfig(self, nodenum, conftype, defaultvalues, ifc): # use the network-wide config values or interface(NEM)-specific values? if ifc is None: return self.getconfig(nodenum, conftype, defaultvalues)[1] else: # don't use default values when interface config is the same as net # note here that using ifc.node.objid as key allows for only one type # of each model per node; TODO: use both node and interface as key values = self.getconfig(ifc.node.objid, conftype, None)[1] if not values and self.version > self.EMANE091: # with EMANE 0.9.2+, we need an extra NEM XML from # model.buildnemxmlfiles(), so defaults are returned here if ifc.transport_type == "raw": values = self.getconfig(nodenum, conftype, defaultvalues)[1] return values def setup(self): ''' Populate self._objs with EmaneNodes; perform distributed setup; associate models with EmaneNodes from self.config. Returns Emane.(SUCCESS, NOT_NEEDED, NOT_READY) in order to delay session instantiation. ''' with self.session._objslock: for obj in self.session.objs(): if isinstance(obj, EmaneNode): self.addobj(obj) if len(self._objs) == 0: return Emane.NOT_NEEDED if self.versionstr == "": self.detectversion() # control network bridge required for EMANE 0.9.2 # - needs to be configured before checkdistributed() for distributed # - needs to exist when eventservice binds to it (initeventservice) if self.version > self.EMANE091 and self.session.master: values = self.getconfig(None, "emane", self.emane_config.getdefaultvalues())[1] otadev = self.emane_config.valueof('otamanagerdevice', values) netidx = self.session.getctrlnetidx(otadev) if netidx < 0: msg = "EMANE cannot be started. "\ "Invalid OTA device provided: %s. Check core.conf." % otadev self.session.exception(coreapi.CORE_EXCP_LEVEL_ERROR, "Emane.setup()", None, msg) self.info(msg) return Emane.NOT_READY ctrlnet = self.session.addremovectrlnet(netidx=netidx, remove=False, conf_reqd=False) self.distributedctrlnet(ctrlnet) eventdev = self.emane_config.valueof('eventservicedevice', values) if eventdev != otadev: netidx = self.session.getctrlnetidx(eventdev) if netidx < 0: msg = "EMANE cannot be started."\ "Invalid Event Service device provided: %s. Check core.conf." % eventdev self.session.exception(coreapi.CORE_EXCP_LEVEL_ERROR, "Emane.setup()", None, msg) self.info(msg) return Emane.NOT_READY ctrlnet = self.session.addremovectrlnet(netidx=netidx, remove=False, conf_reqd=False) self.distributedctrlnet(ctrlnet) if self.checkdistributed(): # we are slave, but haven't received a platformid yet cfgval = self.getconfig(None, self.emane_config._name, self.emane_config.getdefaultvalues())[1] i = self.emane_config.getnames().index('platform_id_start') if cfgval[i] == self.emane_config.getdefaultvalues()[i]: return Emane.NOT_READY self.setnodemodels() return Emane.SUCCESS def startup(self): ''' After all the EmaneNode objects have been added, build XML files and start the daemons. Returns Emane.(SUCCESS, NOT_NEEDED, or NOT_READY) which is used to delay session instantiation. ''' self.reset() r = self.setup() if r != Emane.SUCCESS: return r # NOT_NEEDED or NOT_READY if self.versionstr == "": raise ValueError, "EMANE version not properly detected" with self._objslock: if self.version < self.EMANE092: self.buildxml() self.initeventservice() self.starteventmonitor() if self.numnems() > 0: # TODO: check and return failure for these methods self.startdaemons() self.installnetifs() else: self.buildxml2() self.initeventservice() self.starteventmonitor() if self.numnems() > 0: self.startdaemons2() self.installnetifs(do_netns=False) return Emane.SUCCESS def poststartup(self): ''' Retransmit location events now that all NEMs are active. ''' if self.doeventmonitor(): return with self._objslock: for n in sorted(self._objs.keys()): e = self._objs[n] for netif in e.netifs(): (x, y, z) = netif.node.position.get() e.setnemposition(netif, x, y, z) def reset(self): ''' remove all EmaneNode objects from the dictionary, reset port numbers and nem id counters ''' with self._objslock: self._objs.clear() # don't clear self._ifccounts here; NEM counts are needed for buildxml self.platformport = self.session.getcfgitemint('emane_platform_port', 8100) self.transformport = self.session.getcfgitemint('emane_transform_port', 8200) def shutdown(self): ''' stop all EMANE daemons ''' self._ifccountslock.acquire() self._ifccounts.clear() self._ifccountslock.release() self._objslock.acquire() if len(self._objs) == 0: self._objslock.release() return self.info("Stopping EMANE daemons.") self.deinstallnetifs() self.stopdaemons() self.stopeventmonitor() self._objslock.release() def handledistributed(self, msg): ''' Broker handler for processing CORE API messages as they are received. This is used to snoop the Link add messages to get NEM counts of NEMs that exist on other servers. ''' if msg.msgtype == coreapi.CORE_API_LINK_MSG and \ msg.flags & coreapi.CORE_API_ADD_FLAG: nn = msg.nodenumbers() # first node is always link layer node in Link add message if nn[0] in self.session.broker.nets: serverlist = self.session.broker.getserversbynode(nn[1]) for server in serverlist: self._ifccountslock.acquire() if server not in self._ifccounts: self._ifccounts[server] = 1 else: self._ifccounts[server] += 1 self._ifccountslock.release() def checkdistributed(self): ''' Check for EMANE nodes that exist on multiple emulation servers and coordinate the NEM id and port number space. If we are the master EMANE node, return False so initialization will proceed as normal; otherwise slaves return True here and initialization is deferred. ''' # check with the session if we are the "master" Emane object? master = False self._objslock.acquire() if len(self._objs) > 0: master = self.session.master self.info("Setup EMANE with master=%s." % master) self._objslock.release() # we are not the master Emane object, wait for nem id and ports if not master: return True cfgval = self.getconfig(None, self.emane_config._name, self.emane_config.getdefaultvalues())[1] values = list(cfgval) nemcount = 0 self._objslock.acquire() for n in self._objs: emanenode = self._objs[n] nemcount += emanenode.numnetif() nemid = int(self.emane_config.valueof("nem_id_start", values)) nemid += nemcount platformid = int(self.emane_config.valueof("platform_id_start", values)) names = list(self.emane_config.getnames()) # build an ordered list of servers so platform ID is deterministic servers = [] for n in sorted(self._objs): for s in self.session.broker.getserversbynode(n): if s not in servers: servers.append(s) self._objslock.release() for server in servers: if server == "localhost": continue (host, port, sock) = self.session.broker.getserver(server) if sock is None: continue platformid += 1 typeflags = coreapi.CONF_TYPE_FLAGS_UPDATE values[names.index("platform_id_start")] = str(platformid) values[names.index("nem_id_start")] = str(nemid) msg = EmaneGlobalModel.toconfmsg(flags=0, nodenum=None, typeflags=typeflags, values=values) sock.send(msg) # increment nemid for next server by number of interfaces self._ifccountslock.acquire() if server in self._ifccounts: nemid += self._ifccounts[server] self._ifccountslock.release() return False def buildxml(self): ''' Build all of the XML files required to run EMANE on the host. NEMs run in a single host emane process, with TAP devices pushed into namespaces. ''' # assume self._objslock is already held here if self.verbose: self.info("Emane.buildxml()") self.buildplatformxml() self.buildnemxml() self.buildtransportxml() self.buildeventservicexml() def buildxml2(self): ''' Build XML files required to run EMANE on each node. NEMs run inside containers using the control network for passing events and data. ''' # assume self._objslock is already held here if self.verbose: self.info("Emane.buildxml2()") # on master, control network bridge added earlier in startup() ctrlnet = self.session.addremovectrlnet(netidx=0, remove=False, conf_reqd=False) self.buildplatformxml2(ctrlnet) self.buildnemxml() self.buildeventservicexml() def distributedctrlnet(self, ctrlnet): ''' Distributed EMANE requires multiple control network prefixes to be configured. This generates configuration for slave control nets using the default list of prefixes. ''' session = self.session if not session.master: return # slave server servers = session.broker.getserverlist() if len(servers) < 2: return # not distributed prefix = session.cfg.get('controlnet') prefix = getattr(session.options, 'controlnet', prefix) prefixes = prefix.split() if len(prefixes) >= len(servers): return # normal Config messaging will distribute controlnets # this generates a config message having controlnet prefix assignments self.info("Setting up default controlnet prefixes for distributed " \ "(%d configured)" % len(prefixes)) prefixes = ctrlnet.DEFAULT_PREFIX_LIST[0] vals = "controlnet='%s'" % prefixes tlvdata = "" tlvdata += coreapi.CoreConfTlv.pack(coreapi.CORE_TLV_CONF_OBJ, "session") tlvdata += coreapi.CoreConfTlv.pack(coreapi.CORE_TLV_CONF_TYPE, 0) tlvdata += coreapi.CoreConfTlv.pack(coreapi.CORE_TLV_CONF_VALUES, vals) rawmsg = coreapi.CoreConfMessage.pack(0, tlvdata) msghdr = rawmsg[:coreapi.CoreMessage.hdrsiz] msg = coreapi.CoreConfMessage(flags=0, hdr=msghdr, data=rawmsg[coreapi.CoreMessage.hdrsiz:]) self.session.broker.handlemsg(msg) def xmldoc(self, doctype): ''' Returns an XML xml.minidom.Document with a DOCTYPE tag set to the provided doctype string, and an initial element having the same name. ''' # we hack in the DOCTYPE using the parser docstr = """ <%s/>""" % (doctype, doctype, doctype) # normally this would be: doc = Document() return parseString(docstr) def xmlparam(self, doc, name, value): ''' Convenience function for building a parameter tag of the format: ''' p = doc.createElement("param") p.setAttribute("name", name) p.setAttribute("value", value) return p def xmlshimdefinition(self, doc, name): ''' Convenience function for building a definition tag of the format: ''' p = doc.createElement("shim") p.setAttribute("definition", name) return p def xmlwrite(self, doc, filename): ''' Write the given XML document to the specified filename. ''' #self.info("%s" % doc.toprettyxml(indent=" ")) pathname = os.path.join(self.session.sessiondir, filename) f = open(pathname, "w") doc.writexml(writer=f, indent="", addindent=" ", newl="\n", \ encoding="UTF-8") f.close() def setnodemodels(self): ''' Associate EmaneModel classes with EmaneNode nodes. The model configurations are stored in self.configs. ''' for n in self._objs: self.setnodemodel(n) def setnodemodel(self, n): emanenode = self._objs[n] if n not in self.configs: return False for (t, v) in self.configs[n]: if t is None: continue if t == self.emane_config._name: continue # only use the first valid EmaneModel # convert model name to class (e.g. emane_rfpipe -> EmaneRfPipe) cls = self._modelclsmap[t] emanenode.setmodel(cls, v) return True # no model has been configured for this EmaneNode return False def nemlookup(self, nemid): ''' Look for the given numerical NEM ID and return the first matching EmaneNode and NEM interface. ''' emanenode = None netif = None for n in self._objs: emanenode = self._objs[n] netif = emanenode.getnemnetif(nemid) if netif is not None: break else: emanenode = None return (emanenode, netif) def numnems(self): ''' Return the number of NEMs emulated locally. ''' count = 0 for o in self._objs.values(): count += len(o.netifs()) return count def buildplatformxml(self): ''' Build a platform.xml file now that all nodes are configured. ''' values = self.getconfig(None, "emane", self.emane_config.getdefaultvalues())[1] doc = self.xmldoc("platform") plat = doc.getElementsByTagName("platform").pop() if self.version < self.EMANE091: platformid = self.emane_config.valueof("platform_id_start", values) plat.setAttribute("name", "Platform %s" % platformid) plat.setAttribute("id", platformid) names = list(self.emane_config.getnames()) platform_names = names[:len(self.emane_config._confmatrix_platform)] platform_names.remove('platform_id_start') # append all platform options (except starting id) to doc map( lambda n: plat.appendChild(self.xmlparam(doc, n, \ self.emane_config.valueof(n, values))), platform_names) nemid = int(self.emane_config.valueof("nem_id_start", values)) # assume self._objslock is already held here for n in sorted(self._objs.keys()): emanenode = self._objs[n] nems = emanenode.buildplatformxmlentry(doc) for netif in sorted(nems, key=lambda n: n.node.objid): # set ID, endpoints here nementry = nems[netif] nementry.setAttribute("id", "%d" % nemid) if self.version < self.EMANE092: # insert nem options (except nem id) to doc trans_addr = self.emane_config.valueof("transportendpoint", \ values) nementry.insertBefore(self.xmlparam(doc, "transportendpoint", \ "%s:%d" % (trans_addr, self.transformport)), nementry.firstChild) platform_addr = self.emane_config.valueof("platformendpoint", \ values) nementry.insertBefore(self.xmlparam(doc, "platformendpoint", \ "%s:%d" % (platform_addr, self.platformport)), nementry.firstChild) plat.appendChild(nementry) emanenode.setnemid(netif, nemid) # NOTE: MAC address set before here is incorrect, including the one # sent from the GUI via link message # MAC address determined by NEM ID: 02:02:00:00:nn:nn" macstr = self._hwaddr_prefix + ":00:00:" macstr += "%02X:%02X" % ((nemid >> 8) & 0xFF, nemid & 0xFF) netif.sethwaddr(MacAddr.fromstring(macstr)) # increment counters used to manage IDs, endpoint port numbers nemid += 1 self.platformport += 1 self.transformport += 1 self.xmlwrite(doc, "platform.xml") def newplatformxmldoc(self, values, otadev=None, eventdev=None): ''' Start a new platform XML file. Use global EMANE config values as keys. Override OTA manager and event service devices if specified (in order to support Raw Transport). ''' doc = self.xmldoc("platform") plat = doc.getElementsByTagName("platform").pop() names = list(self.emane_config.getnames()) platform_names = names[:len(self.emane_config._confmatrix_platform)] platform_names.remove('platform_id_start') platform_values = list(values) if otadev: i = platform_names.index('otamanagerdevice') platform_values[i] = otadev if eventdev: i = platform_names.index('eventservicedevice') platform_values[i] = eventdev # append all platform options (except starting id) to doc map( lambda n: plat.appendChild(self.xmlparam(doc, n, \ self.emane_config.valueof(n, platform_values))), \ platform_names) return doc def buildplatformxml2(self, ctrlnet): ''' Build a platform.xml file now that all nodes are configured. ''' values = self.getconfig(None, "emane", self.emane_config.getdefaultvalues())[1] nemid = int(self.emane_config.valueof("nem_id_start", values)) platformxmls = {} # assume self._objslock is already held here for n in sorted(self._objs.keys()): emanenode = self._objs[n] nems = emanenode.buildplatformxmlentry(self.xmldoc("platform")) for netif in sorted(nems, key=lambda n: n.node.objid): nementry = nems[netif] nementry.setAttribute("id", "%d" % nemid) k = netif.node.objid if netif.transport_type == "raw": k = 'host' otadev = ctrlnet.brname eventdev = ctrlnet.brname else: otadev = None eventdev = None if k not in platformxmls: platformxmls[k] = self.newplatformxmldoc(values, otadev, eventdev) doc = platformxmls[k] plat = doc.getElementsByTagName("platform").pop() plat.appendChild(nementry) emanenode.setnemid(netif, nemid) macstr = self._hwaddr_prefix + ":00:00:" macstr += "%02X:%02X" % ((nemid >> 8) & 0xFF, nemid & 0xFF) netif.sethwaddr(MacAddr.fromstring(macstr)) nemid += 1 for k in sorted(platformxmls.keys()): if k == 'host': self.xmlwrite(platformxmls['host'], "platform.xml") continue self.xmlwrite(platformxmls[k], "platform%d.xml" % k) def buildnemxml(self): ''' Builds the xxxnem.xml, xxxmac.xml, and xxxphy.xml files which are defined on a per-EmaneNode basis. ''' for n in sorted(self._objs.keys()): emanenode = self._objs[n] nems = emanenode.buildnemxmlfiles(self) def appendtransporttonem(self, doc, nem, nodenum, ifc=None): ''' Given a nem XML node and EMANE WLAN node number, append a tag to the NEM definition, required for using EMANE's internal transport. ''' if self.version < self.EMANE092: return emanenode = self._objs[nodenum] transtag = doc.createElement("transport") transtypestr = "virtual" if ifc and ifc.transport_type == "raw": transtypestr = "raw" transtag.setAttribute("definition", emanenode.transportxmlname(transtypestr)) nem.appendChild(transtag) def buildtransportxml(self): ''' Calls emanegentransportxml using a platform.xml file to build the transportdaemon*.xml. ''' try: subprocess.check_call(["emanegentransportxml", "platform.xml"], \ cwd=self.session.sessiondir) except Exception, e: self.info("error running emanegentransportxml: %s" % e) def buildeventservicexml(self): ''' Build the libemaneeventservice.xml file if event service options were changed in the global config. ''' defaults = self.emane_config.getdefaultvalues() values = self.getconfig(None, "emane", self.emane_config.getdefaultvalues())[1] need_xml = False keys = ('eventservicegroup', 'eventservicedevice') for k in keys: a = self.emane_config.valueof(k, defaults) b = self.emane_config.valueof(k, values) if a != b: need_xml = True if not need_xml: # reset to using default config self.initeventservice() return try: group, port = self.emane_config.valueof('eventservicegroup', values).split(':') except ValueError: self.warn("invalid eventservicegroup in EMANE config") return dev = self.emane_config.valueof('eventservicedevice', values) doc = self.xmldoc("emaneeventmsgsvc") es = doc.getElementsByTagName("emaneeventmsgsvc").pop() kvs = ( ('group', group), ('port', port), ('device', dev), ('mcloop', '1'), ('ttl', '32') ) addtextelementsfromtuples(doc, es, kvs) filename = 'libemaneeventservice.xml' self.xmlwrite(doc, filename) pathname = os.path.join(self.session.sessiondir, filename) self.initeventservice(filename=pathname) def startdaemons(self): ''' Start the appropriate EMANE daemons. The transport daemon will bind to the TAP interfaces. ''' if self.verbose: self.info("Emane.startdaemons()") path = self.session.sessiondir loglevel = str(self.DEFAULT_LOG_LEVEL) cfgloglevel = self.session.getcfgitemint("emane_log_level") realtime = self.session.getcfgitembool("emane_realtime", True) if cfgloglevel: self.info("setting user-defined EMANE log level: %d" % cfgloglevel) loglevel = str(cfgloglevel) emanecmd = ["emane", "-d", "--logl", loglevel, "-f", \ os.path.join(path, "emane.log")] if realtime: emanecmd += "-r", try: cmd = emanecmd + [os.path.join(path, "platform.xml")] if self.verbose: self.info("Emane.startdaemons() running %s" % str(cmd)) subprocess.check_call(cmd, cwd=path) except Exception, e: errmsg = "error starting emane: %s" % e self.session.exception(coreapi.CORE_EXCP_LEVEL_FATAL, "emane", None, errmsg) self.info(errmsg) # start one transport daemon per transportdaemon*.xml file transcmd = ["emanetransportd", "-d", "--logl", loglevel, "-f", \ os.path.join(path, "emanetransportd.log")] if realtime: transcmd += "-r", files = os.listdir(path) for file in files: if file[-3:] == "xml" and file[:15] == "transportdaemon": cmd = transcmd + [os.path.join(path, file)] try: if self.verbose: self.info("Emane.startdaemons() running %s" % str(cmd)) subprocess.check_call(cmd, cwd=path) except Exception, e: errmsg = "error starting emanetransportd: %s" % e self.session.exception(coreapi.CORE_EXCP_LEVEL_FATAL, "emane", None, errmsg) self.info(errmsg) def startdaemons2(self): ''' Start one EMANE daemon per node having a radio. Add a control network even if the user has not configured one. ''' if self.verbose: self.info("Emane.startdaemons()") loglevel = str(self.DEFAULT_LOG_LEVEL) cfgloglevel = self.session.getcfgitemint("emane_log_level") realtime = self.session.getcfgitembool("emane_realtime", True) if cfgloglevel: self.info("setting user-defined EMANE log level: %d" % cfgloglevel) loglevel = str(cfgloglevel) emanecmd = ["emane", "-d", "--logl", loglevel] if realtime: emanecmd += "-r", values = self.getconfig(None, "emane", self.emane_config.getdefaultvalues())[1] otagroup, otaport = self.emane_config.valueof('otamanagergroup', values).split(':') otadev = self.emane_config.valueof('otamanagerdevice', values) otanetidx = self.session.getctrlnetidx(otadev) eventgroup, eventport = self.emane_config.valueof('eventservicegroup', values).split(':') eventdev = self.emane_config.valueof('eventservicedevice', values) eventservicenetidx = self.session.getctrlnetidx(eventdev) run_emane_on_host = False for node in self.getnodes(): if hasattr(node, 'transport_type') and \ node.transport_type == "raw": run_emane_on_host = True continue path = self.session.sessiondir n = node.objid # control network not yet started here self.session.addremovectrlif(node, 0, remove=False, conf_reqd=False) if otanetidx > 0: self.info("adding ota device ctrl%d" % otanetidx) self.session.addremovectrlif(node, otanetidx, remove=False, conf_reqd=False) if eventservicenetidx >= 0: self.info("adding event service device ctrl%d" % eventservicenetidx) self.session.addremovectrlif(node, eventservicenetidx, remove=False, conf_reqd=False) # multicast route is needed for OTA data cmd = [IP_BIN, "route", "add", otagroup, "dev", otadev] #rc = node.cmd(cmd, wait=True) node.cmd(cmd, wait=True) # multicast route is also needed for event data if on control network if eventservicenetidx >= 0 and eventgroup != otagroup: cmd = [IP_BIN, "route", "add", eventgroup, "dev", eventdev] node.cmd(cmd, wait=True) try: cmd = emanecmd + ["-f", os.path.join(path, "emane%d.log" % n), os.path.join(path, "platform%d.xml" % n)] if self.verbose: self.info("Emane.startdaemons2() running %s" % str(cmd)) status = node.cmd(cmd, wait=True) if self.verbose: self.info("Emane.startdaemons2() return code %d" % status) except Exception, e: errmsg = "error starting emane: %s" % e self.session.exception(coreapi.CORE_EXCP_LEVEL_FATAL, "emane", n, errmsg) self.info(errmsg) if not run_emane_on_host: return path = self.session.sessiondir try: emanecmd += ["-f", os.path.join(path, "emane.log")] cmd = emanecmd + [os.path.join(path, "platform.xml")] if self.verbose: self.info("Emane.startdaemons2() running %s" % str(cmd)) subprocess.check_call(cmd, cwd=path) except Exception, e: errmsg = "error starting emane: %s" % e self.session.exception(coreapi.CORE_EXCP_LEVEL_FATAL, "emane", None, errmsg) self.info(errmsg) def stopdaemons(self): ''' Kill the appropriate EMANE daemons. ''' # TODO: we may want to improve this if we had the PIDs from the # specific EMANE daemons that we've started cmd = ["killall", "-q", "emane"] stop_emane_on_host = False if self.version > self.EMANE091: for node in self.getnodes(): if hasattr(node, 'transport_type') and \ node.transport_type == "raw": stop_emane_on_host = True continue if node.up: node.cmd(cmd, wait=False) # TODO: RJ45 node else: stop_emane_on_host = True if stop_emane_on_host: subprocess.call(cmd) subprocess.call(["killall", "-q", "emanetransportd"]) def installnetifs(self, do_netns=True): ''' Install TUN/TAP virtual interfaces into their proper namespaces now that the EMANE daemons are running. ''' for n in sorted(self._objs.keys()): emanenode = self._objs[n] if self.verbose: self.info("Emane.installnetifs() for node %d" % n) emanenode.installnetifs(do_netns) def deinstallnetifs(self): ''' Uninstall TUN/TAP virtual interfaces. ''' for n in sorted(self._objs.keys()): emanenode = self._objs[n] emanenode.deinstallnetifs() def configure(self, session, msg): ''' Handle configuration messages for global EMANE config. ''' r = self.emane_config.configure_emane(session, msg) # extra logic to start slave Emane object after nemid has been # configured from the master conftype = msg.gettlv(coreapi.CORE_TLV_CONF_TYPE) if conftype == coreapi.CONF_TYPE_FLAGS_UPDATE and \ self.session.master == False: # instantiation was previously delayed by self.setup() # returning Emane.NOT_READY h = None with self.session._handlerslock: for h in self.session._handlers: break self.session.instantiate(handler=h) return r def doeventmonitor(self): ''' Returns boolean whether or not EMANE events will be monitored. ''' # this support must be explicitly turned on; by default, CORE will # generate the EMANE events when nodes are moved return self.session.getcfgitembool('emane_event_monitor', False) def starteventmonitor(self): ''' Start monitoring EMANE location events if configured to do so. ''' if self.verbose: self.info("Emane.starteventmonitor()") if not self.doeventmonitor(): return if self.service is None: errmsg = "Warning: EMANE events will not be generated " \ "because the emaneeventservice\n binding was " \ "unable to load " \ "(install the python-emaneeventservice bindings)" self.session.exception(coreapi.CORE_EXCP_LEVEL_WARNING, "emane", None, errmsg) self.warn(errmsg) return self.doeventloop = True self.eventmonthread = threading.Thread(target = self.eventmonitorloop) self.eventmonthread.daemon = True self.eventmonthread.start() def stopeventmonitor(self): ''' Stop monitoring EMANE location events. ''' self.doeventloop = False if self.service is not None: self.service.breakloop() # reset the service, otherwise nextEvent won't work self.initeventservice(shutdown=True) if self.eventmonthread is not None: if self.version >= self.EMANE091: self.eventmonthread._Thread__stop() self.eventmonthread.join() self.eventmonthread = None def eventmonitorloop(self): ''' Thread target that monitors EMANE location events. ''' if self.service is None: return self.info("Subscribing to EMANE location events (not generating them). " \ "(%s) " % threading.currentThread().getName()) while self.doeventloop is True: if self.version >= self.EMANE091: (uuid, seq, events) = self.service.nextEvent() if not self.doeventloop: break # this occurs with 0.9.1 event service for event in events: (nem, eid, data) = event if eid == LocationEvent.IDENTIFIER: self.handlelocationevent2(nem, eid, data) else: (event, platform, nem, cmp, data) = self.service.nextEvent() if event == emaneeventlocation.EVENT_ID: self.handlelocationevent(event, platform, nem, cmp, data) self.info("Unsubscribing from EMANE location events. (%s) " % \ threading.currentThread().getName()) def handlelocationevent(self, event, platform, nem, component, data): ''' Handle an EMANE location event (EMANE 0.8.1 and earlier). ''' event = emaneeventlocation.EventLocation(data) entries = event.entries() for e in entries.values(): # yaw,pitch,roll,azimuth,elevation,velocity are unhandled (nemid, lat, long, alt) = e[:4] self.handlelocationeventtoxyz(nemid, lat, long, alt) def handlelocationevent2(self, rxnemid, eid, data): ''' Handle an EMANE location event (EMANE 0.9.1+). ''' events = LocationEvent() events.restore(data) for event in events: (txnemid, attrs) = event if 'latitude' not in attrs or 'longitude' not in attrs or \ 'altitude' not in attrs: self.warn("dropped invalid location event") continue # yaw,pitch,roll,azimuth,elevation,velocity are unhandled lat = attrs['latitude'] long = attrs['longitude'] alt = attrs['altitude'] self.handlelocationeventtoxyz(txnemid, lat, long, alt) def handlelocationeventtoxyz(self, nemid, lat, long, alt): ''' Convert the (NEM ID, lat, long, alt) from a received location event into a node and x,y,z coordinate values, sending a Node Message. Returns True if successfully parsed and a Node Message was sent. ''' # convert nemid to node number (emanenode, netif) = self.nemlookup(nemid) if netif is None: if self.verbose: self.info("location event for unknown NEM %s" % nemid) return False n = netif.node.objid # convert from lat/long/alt to x,y,z coordinates (x, y, z) = self.session.location.getxyz(lat, long, alt) x = int(x) y = int(y) z = int(z) if self.verbose: self.info("location event NEM %s (%s, %s, %s) -> (%s, %s, %s)" \ % (nemid, lat, long, alt, x, y, z)) try: if (x.bit_length() > 16) or (y.bit_length() > 16) or \ (z.bit_length() > 16) or (x < 0) or (y < 0) or (z < 0): warntxt = "Unable to build node location message since " \ "received lat/long/alt exceeds coordinate " \ "space: NEM %s (%d, %d, %d)" % (nemid, x, y, z) self.info(warntxt) self.session.exception(coreapi.CORE_EXCP_LEVEL_ERROR, "emane", None, warntxt) return False except AttributeError: # int.bit_length() not present on Python 2.6 pass # generate a node message for this location update try: node = self.session.obj(n) except KeyError: self.warn("location event NEM %s has no corresponding node %s" \ % (nemid, n)) return False # don't use node.setposition(x,y,z) which generates an event node.position.set(x,y,z) msg = node.tonodemsg(flags=0) self.session.broadcastraw(None, msg) self.session.sdt.updatenodegeo(node.objid, lat, long, alt) return True class EmaneModel(WirelessModel): ''' EMANE models inherit from this parent class, which takes care of handling configuration messages based on the _confmatrix list of configurable parameters. Helper functions also live here. ''' _prefix = {'y': 1e-24, # yocto 'z': 1e-21, # zepto 'a': 1e-18, # atto 'f': 1e-15, # femto 'p': 1e-12, # pico 'n': 1e-9, # nano 'u': 1e-6, # micro 'm': 1e-3, # mili 'c': 1e-2, # centi 'd': 1e-1, # deci 'k': 1e3, # kilo 'M': 1e6, # mega 'G': 1e9, # giga 'T': 1e12, # tera 'P': 1e15, # peta 'E': 1e18, # exa 'Z': 1e21, # zetta 'Y': 1e24, # yotta } @classmethod def configure_emane(cls, session, msg): ''' Handle configuration messages for setting up a model. Pass the Emane object as the manager object. ''' return cls.configure(session.emane, msg) @classmethod def emane074_fixup(cls, value, div=1.0): ''' Helper for converting 0.8.1 and newer values to EMANE 0.7.4 compatible values. NOTE: This should be removed when support for 0.7.4 has been deprecated. ''' if div == 0: return "0" if type(value) is not str: return str(value / div) if value.endswith(tuple(cls._prefix.keys())): suffix = value[-1] value = float(value[:-1]) * cls._prefix[suffix] return str(int(value / div)) def buildnemxmlfiles(self, e, ifc): ''' Build the necessary nem, mac, and phy XMLs in the given path. ''' raise NotImplementedError def buildplatformxmlnementry(self, doc, n, ifc): ''' Build the NEM definition that goes into the platform.xml file. This returns an XML element that will be added to the element. This default method supports per-interface config (e.g. or per-EmaneNode config (e.g. . This can be overriden by a model for NEM flexibility; n is the EmaneNode. ''' nem = doc.createElement("nem") nem.setAttribute("name", ifc.localname) # if this netif contains a non-standard (per-interface) config, # then we need to use a more specific xml file here nem.setAttribute("definition", self.nemxmlname(ifc)) return nem def buildplatformxmltransportentry(self, doc, n, ifc): ''' Build the transport definition that goes into the platform.xml file. This returns an XML element that will added to the nem definition. This default method supports raw and virtual transport types, but may be overriden by a model to support the e.g. pluggable virtual transport. n is the EmaneNode. ''' ttype = ifc.transport_type if not ttype: self.session.info("warning: %s interface type unsupported!" % ifc.name) ttype = "raw" trans = doc.createElement("transport") trans.setAttribute("definition", n.transportxmlname(ttype)) if self.session.emane.version < self.session.emane.EMANE092: trans.setAttribute("group", "1") param = doc.createElement("param") param.setAttribute("name", "device") if ttype == "raw": # raw RJ45 name e.g. 'eth0' param.setAttribute("value", ifc.name) else: # virtual TAP name e.g. 'n3.0.17' param.setAttribute("value", ifc.localname) if self.session.emane.version > self.session.emane.EMANE091: param.setAttribute("value", ifc.name) trans.appendChild(param) return trans def basename(self, ifc = None): ''' Return the string that other names are based on. If a specific config is stored for a node's interface, a unique filename is needed; otherwise the name of the EmaneNode is used. ''' emane = self.session.emane name = "n%s" % self.objid if ifc is not None: nodenum = ifc.node.objid if emane.getconfig(nodenum, self._name, None)[1] is not None: name = ifc.localname.replace('.','_') return "%s%s" % (name, self._name) def nemxmlname(self, ifc = None): ''' Return the string name for the NEM XML file, e.g. 'n3rfpipenem.xml' ''' append = "" if self.session.emane.version > self.session.emane.EMANE091: if ifc and ifc.transport_type == "raw": append = "_raw" return "%snem%s.xml" % (self.basename(ifc), append) def shimxmlname(self, ifc = None): ''' Return the string name for the SHIM XML file, e.g. 'commeffectshim.xml' ''' return "%sshim.xml" % self.basename(ifc) def macxmlname(self, ifc = None): ''' Return the string name for the MAC XML file, e.g. 'n3rfpipemac.xml' ''' return "%smac.xml" % self.basename(ifc) def phyxmlname(self, ifc = None): ''' Return the string name for the PHY XML file, e.g. 'n3rfpipephy.xml' ''' return "%sphy.xml" % self.basename(ifc) def update(self, moved, moved_netifs): ''' invoked from MobilityModel when nodes are moved; this causes EMANE location events to be generated for the nodes in the moved list, making EmaneModels compatible with Ns2ScriptedMobility ''' try: wlan = self.session.obj(self.objid) except KeyError: return wlan.setnempositions(moved_netifs) def linkconfig(self, netif, bw = None, delay = None, loss = None, duplicate = None, jitter = None, netif2 = None): ''' Invoked when a Link Message is received. Default is unimplemented. ''' warntxt = "EMANE model %s does not support link " % self._name warntxt += "configuration, dropping Link Message" self.session.warn(warntxt) @staticmethod def valuestrtoparamlist(dom, name, value): ''' Helper to convert a parameter to a paramlist. Returns a an XML paramlist, or None if the value does not expand to multiple values. ''' try: values = maketuplefromstr(value, str) except SyntaxError: return None if not hasattr(values, '__iter__'): return None if len(values) < 2: return None return addparamlisttoparent(dom, parent=None, name=name, values=values) # EMANE 0.9.2 detected upon module load to support class vars try: HAVE092 = (Emane.detectversionfromcmd()[0] >= Emane.EMANE092) except Exception, e: HAVE092 = False class EmaneGlobalModel(EmaneModel): ''' Global EMANE configuration options. ''' def __init__(self, session, objid = None, verbose = False): EmaneModel.__init__(self, session, objid, verbose) # Over-The-Air channel required for EMANE 0.9.2 _DEFAULT_OTA = '0' _DEFAULT_DEV = 'lo' if HAVE092: _DEFAULT_OTA = '1' _DEFAULT_DEV = 'ctrl0' _name = "emane" _confmatrix_platform_base = [ ("otamanagerchannelenable", coreapi.CONF_DATA_TYPE_BOOL, _DEFAULT_OTA, 'on,off', 'enable OTA Manager channel'), ("otamanagergroup", coreapi.CONF_DATA_TYPE_STRING, '224.1.2.8:45702', '', 'OTA Manager group'), ("otamanagerdevice", coreapi.CONF_DATA_TYPE_STRING, _DEFAULT_DEV, '', 'OTA Manager device'), ("eventservicegroup", coreapi.CONF_DATA_TYPE_STRING, '224.1.2.8:45703', '', 'Event Service group'), ("eventservicedevice", coreapi.CONF_DATA_TYPE_STRING, _DEFAULT_DEV, '', 'Event Service device'), ("platform_id_start", coreapi.CONF_DATA_TYPE_INT32, '1', '', 'starting Platform ID'), ] _confmatrix_platform_081 = [ ("debugportenable", coreapi.CONF_DATA_TYPE_BOOL, '0', 'on,off', 'enable debug port'), ("debugport", coreapi.CONF_DATA_TYPE_UINT16, '47000', '', 'debug port number'), ] _confmatrix_platform_091 = [ ("controlportendpoint", coreapi.CONF_DATA_TYPE_STRING, '0.0.0.0:47000', '', 'Control port address'), ("antennaprofilemanifesturi", coreapi.CONF_DATA_TYPE_STRING, '', '','antenna profile manifest URI'), ] _confmatrix_nem = [ ("transportendpoint", coreapi.CONF_DATA_TYPE_STRING, 'localhost', '', 'Transport endpoint address (port is automatic)'), ("platformendpoint", coreapi.CONF_DATA_TYPE_STRING, 'localhost', '', 'Platform endpoint address (port is automatic)'), ("nem_id_start", coreapi.CONF_DATA_TYPE_INT32, '1', '', 'starting NEM ID'), ] _confmatrix_nem_092 = [ ("nem_id_start", coreapi.CONF_DATA_TYPE_INT32, '1', '', 'starting NEM ID'), ] if 'EventService' in globals(): _confmatrix_platform = _confmatrix_platform_base + \ _confmatrix_platform_091 if HAVE092: _confmatrix_nem = _confmatrix_nem_092 else: _confmatrix_platform = _confmatrix_platform_base + \ _confmatrix_platform_081 _confmatrix = _confmatrix_platform + _confmatrix_nem _confgroups = "Platform Attributes:1-%d|NEM Parameters:%d-%d" % \ (len(_confmatrix_platform), len(_confmatrix_platform) + 1, len(_confmatrix)) core-4.8/daemon/core/emane/ieee80211abg.py0000664000175000017500000001571412534327775015076 00000000000000# # CORE # Copyright (c)2010-2014 the Boeing Company. # See the LICENSE file included in this distribution. # # author: Jeff Ahrenholz # ''' ieee80211abg.py: EMANE IEEE 802.11abg model for CORE ''' import sys import string try: from emanesh.events import EventService except: pass from core.api import coreapi from core.constants import * from emane import EmaneModel from universal import EmaneUniversalModel class EmaneIeee80211abgModel(EmaneModel): def __init__(self, session, objid = None, verbose = False): EmaneModel.__init__(self, session, objid, verbose) # model name _name = "emane_ieee80211abg" _80211rates = '1 1 Mbps,2 2 Mbps,3 5.5 Mbps,4 11 Mbps,5 6 Mbps,' + \ '6 9 Mbps,7 12 Mbps,8 18 Mbps,9 24 Mbps,10 36 Mbps,11 48 Mbps,' + \ '12 54 Mbps' if 'EventService' in globals(): xml_path = '/usr/share/emane/xml/models/mac/ieee80211abg' else: xml_path = "/usr/share/emane/models/ieee80211abg/xml" # MAC parameters _confmatrix_mac_base = [ ("mode", coreapi.CONF_DATA_TYPE_UINT8, '0', '0 802.11b (DSSS only),1 802.11b (DSSS only),' + \ '2 802.11a or g (OFDM),3 802.11b/g (DSSS and OFDM)', 'mode'), ("enablepromiscuousmode", coreapi.CONF_DATA_TYPE_BOOL, '0', 'On,Off', 'enable promiscuous mode'), ("distance", coreapi.CONF_DATA_TYPE_UINT32, '1000', '', 'max distance (m)'), ("unicastrate", coreapi.CONF_DATA_TYPE_UINT8, '4', _80211rates, 'unicast rate (Mbps)'), ("multicastrate", coreapi.CONF_DATA_TYPE_UINT8, '1', _80211rates, 'multicast rate (Mbps)'), ("rtsthreshold", coreapi.CONF_DATA_TYPE_UINT16, '0', '', 'RTS threshold (bytes)'), ("pcrcurveuri", coreapi.CONF_DATA_TYPE_STRING, '%s/ieee80211pcr.xml' % xml_path, '', 'SINR/PCR curve file'), ("flowcontrolenable", coreapi.CONF_DATA_TYPE_BOOL, '0', 'On,Off', 'enable traffic flow control'), ("flowcontroltokens", coreapi.CONF_DATA_TYPE_UINT16, '10', '', 'number of flow control tokens'), ] # mac parameters introduced in EMANE 0.8.1 # Note: The entry format for category queue parameters (queuesize, aifs, etc) were changed in # EMANE 9.x, but are being preserved for the time being due to space constraints in the # CORE GUI. A conversion function (get9xmacparamequivalent) has been defined to support this. _confmatrix_mac_extended = [ ("wmmenable", coreapi.CONF_DATA_TYPE_BOOL, '0', 'On,Off', 'WiFi Multimedia (WMM)'), ("queuesize", coreapi.CONF_DATA_TYPE_STRING, '0:255 1:255 2:255 3:255', '', 'queue size (0-4:size)'), ("cwmin", coreapi.CONF_DATA_TYPE_STRING, '0:32 1:32 2:16 3:8', '', 'min contention window (0-4:minw)'), ("cwmax", coreapi.CONF_DATA_TYPE_STRING, '0:1024 1:1024 2:64 3:16', '', 'max contention window (0-4:maxw)'), ("aifs", coreapi.CONF_DATA_TYPE_STRING, '0:2 1:2 2:2 3:1', '', 'arbitration inter frame space (0-4:aifs)'), ("txop", coreapi.CONF_DATA_TYPE_STRING, '0:0 1:0 2:0 3:0', '', 'txop (0-4:usec)'), ("retrylimit", coreapi.CONF_DATA_TYPE_STRING, '0:3 1:3 2:3 3:3', '', 'retry limit (0-4:numretries)'), ] _confmatrix_mac = _confmatrix_mac_base + _confmatrix_mac_extended # PHY parameters from Universal PHY _confmatrix_phy = EmaneUniversalModel._confmatrix _confmatrix = _confmatrix_mac + _confmatrix_phy # value groupings _confgroups = "802.11 MAC Parameters:1-%d|Universal PHY Parameters:%d-%d" \ % (len(_confmatrix_mac), len(_confmatrix_mac) + 1, len(_confmatrix)) def buildnemxmlfiles(self, e, ifc): ''' Build the necessary nem, mac, and phy XMLs in the given path. If an individual NEM has a nonstandard config, we need to build that file also. Otherwise the WLAN-wide nXXemane_ieee80211abgnem.xml, nXXemane_ieee80211abgemac.xml, nXXemane_ieee80211abgphy.xml are used. ''' values = e.getifcconfig(self.objid, self._name, self.getdefaultvalues(), ifc) if values is None: return nemdoc = e.xmldoc("nem") nem = nemdoc.getElementsByTagName("nem").pop() nem.setAttribute("name", "ieee80211abg NEM") e.appendtransporttonem(nemdoc, nem, self.objid, ifc) mactag = nemdoc.createElement("mac") mactag.setAttribute("definition", self.macxmlname(ifc)) nem.appendChild(mactag) phytag = nemdoc.createElement("phy") phytag.setAttribute("definition", self.phyxmlname(ifc)) nem.appendChild(phytag) e.xmlwrite(nemdoc, self.nemxmlname(ifc)) macdoc = e.xmldoc("mac") mac = macdoc.getElementsByTagName("mac").pop() mac.setAttribute("name", "ieee80211abg MAC") mac.setAttribute("library", "ieee80211abgmaclayer") names = self.getnames() macnames = names[:len(self._confmatrix_mac)] phynames = names[len(self._confmatrix_mac):] # append all MAC options to macdoc if 'EventService' in globals(): for macname in macnames: mac9xnvpairlist = self.get9xmacparamequivalent(macname, values) for nvpair in mac9xnvpairlist: mac.appendChild(e.xmlparam(macdoc, nvpair[0], nvpair[1])) else: map( lambda n: mac.appendChild(e.xmlparam(macdoc, n, \ self.valueof(n, values))), macnames) e.xmlwrite(macdoc, self.macxmlname(ifc)) phydoc = EmaneUniversalModel.getphydoc(e, self, values, phynames) e.xmlwrite(phydoc, self.phyxmlname(ifc)) # # TEMP HACK: Account for parameter convention change in EMANE 9.x # This allows CORE to preserve the entry layout for the mac 'category' parameters # and work with EMANE 9.x onwards. # def get9xmacparamequivalent(self, macname, values): ''' Generate a list of 80211abg mac parameters in 0.9.x layout for a given mac parameter in 8.x layout.For mac category parameters, the list returned will contain the four equivalent 9.x parameter and value pairs. Otherwise, the list returned will only contain a single name and value pair. ''' nvpairlist = [] macparmval = self.valueof(macname, values) if macname in ["queuesize","aifs","cwmin","cwmax","txop","retrylimit"]: for catval in macparmval.split(): idx_and_val = catval.split(":") idx = int(idx_and_val[0]) val = idx_and_val[1] # aifs and tx are in microseconds. Convert to seconds. if macname in ["aifs","txop"]: val = "%f" % (float(val)*(1e-6)) name9x = "%s%d" % (macname, idx) nvpairlist.append([name9x, val]) else: nvpairlist.append([macname, macparmval]) return nvpairlist core-4.8/daemon/core/emane/nodes.py0000664000175000017500000003077312534327775014233 00000000000000# # CORE # Copyright (c)2010-2014 the Boeing Company. # See the LICENSE file included in this distribution. # # author: Jeff Ahrenholz # ''' nodes.py: definition of an EmaneNode class for implementing configuration control of an EMANE emulation. An EmaneNode has several attached NEMs that share the same MAC+PHY model. ''' import sys import os.path from core.api import coreapi from core.coreobj import PyCoreNet try: from emanesh.events import EventService from emanesh.events import LocationEvent except Exception, e: pass try: import emaneeventservice import emaneeventlocation except Exception, e: ''' Don't require all CORE users to have EMANE libeventservice and its Python bindings installed. ''' pass class EmaneNet(PyCoreNet): ''' EMANE network base class. ''' apitype = coreapi.CORE_NODE_EMANE linktype = coreapi.CORE_LINK_WIRELESS type = "wlan" # icon used class EmaneNode(EmaneNet): ''' EMANE node contains NEM configuration and causes connected nodes to have TAP interfaces (instead of VEth). These are managed by the Emane controller object that exists in a session. ''' def __init__(self, session, objid = None, name = None, verbose = False, start = True): PyCoreNet.__init__(self, session, objid, name, verbose, start) self.verbose = verbose self.conf = "" self.up = False self.nemidmap = {} self.model = None self.mobility = None def linkconfig(self, netif, bw = None, delay = None, loss = None, duplicate = None, jitter = None, netif2 = None): ''' The CommEffect model supports link configuration. ''' if not self.model: return return self.model.linkconfig(netif=netif, bw=bw, delay=delay, loss=loss, duplicate=duplicate, jitter=jitter, netif2=netif2) def config(self, conf): #print "emane", self.name, "got config:", conf self.conf = conf def shutdown(self): pass def link(self, netif1, netif2): pass def unlink(self, netif1, netif2): pass def setmodel(self, model, config): ''' set the EmaneModel associated with this node ''' if (self.verbose): self.info("adding model %s" % model._name) if model._type == coreapi.CORE_TLV_REG_WIRELESS: # EmaneModel really uses values from ConfigurableManager # when buildnemxml() is called, not during init() self.model = model(session=self.session, objid=self.objid, verbose=self.verbose) elif model._type == coreapi.CORE_TLV_REG_MOBILITY: self.mobility = model(session=self.session, objid=self.objid, verbose=self.verbose, values=config) def setnemid(self, netif, nemid): ''' Record an interface to numerical ID mapping. The Emane controller object manages and assigns these IDs for all NEMs. ''' self.nemidmap[netif] = nemid def getnemid(self, netif): ''' Given an interface, return its numerical ID. ''' if netif not in self.nemidmap: return None else: return self.nemidmap[netif] def getnemnetif(self, nemid): ''' Given a numerical NEM ID, return its interface. This returns the first interface that matches the given NEM ID. ''' for netif in self.nemidmap: if self.nemidmap[netif] == nemid: return netif return None def netifs(self, sort=True): ''' Retrieve list of linked interfaces sorted by node number. ''' return sorted(self._netif.values(), key=lambda ifc: ifc.node.objid) def buildplatformxmlentry(self, doc): ''' Return a dictionary of XML elements describing the NEMs connected to this EmaneNode for inclusion in the platform.xml file. ''' ret = {} if self.model is None: self.info("warning: EmaneNode %s has no associated model" % \ self.name) return ret for netif in self.netifs(): # nementry = self.model.buildplatformxmlnementry(doc, self, netif) # # # trans = self.model.buildplatformxmltransportentry(doc, self, netif) nementry.appendChild(trans) ret[netif] = nementry return ret def buildnemxmlfiles(self, emane): ''' Let the configured model build the necessary nem, mac, and phy XMLs. ''' if self.model is None: return # build XML for overall network (EmaneNode) configs self.model.buildnemxmlfiles(emane, ifc=None) # build XML for specific interface (NEM) configs need_virtual = False need_raw = False vtype = "virtual" rtype = "raw" for netif in self.netifs(): self.model.buildnemxmlfiles(emane, netif) if "virtual" in netif.transport_type: need_virtual = True vtype = netif.transport_type else: need_raw = True rtype = netif.transport_type # build transport XML files depending on type of interfaces involved if need_virtual: self.buildtransportxml(emane, vtype) if need_raw: self.buildtransportxml(emane, rtype) def buildtransportxml(self, emane, type): ''' Write a transport XML file for the Virtual or Raw Transport. ''' transdoc = emane.xmldoc("transport") trans = transdoc.getElementsByTagName("transport").pop() trans.setAttribute("name", "%s Transport" % type.capitalize()) trans.setAttribute("library", "trans%s" % type.lower()) trans.appendChild(emane.xmlparam(transdoc, "bitrate", "0")) flowcontrol = False names = self.model.getnames() values = emane.getconfig(self.objid, self.model._name, self.model.getdefaultvalues())[1] if "flowcontrolenable" in names and values: i = names.index("flowcontrolenable") if self.model.booltooffon(values[i]) == "on": flowcontrol = True if "virtual" in type.lower(): if os.path.exists("/dev/net/tun_flowctl"): trans.appendChild(emane.xmlparam(transdoc, "devicepath", "/dev/net/tun_flowctl")) else: trans.appendChild(emane.xmlparam(transdoc, "devicepath", "/dev/net/tun")) if flowcontrol: trans.appendChild(emane.xmlparam(transdoc, "flowcontrolenable", "on")) emane.xmlwrite(transdoc, self.transportxmlname(type.lower())) def transportxmlname(self, type): ''' Return the string name for the Transport XML file, e.g. 'n3transvirtual.xml' ''' return "n%strans%s.xml" % (self.objid, type) def installnetifs(self, do_netns=True): ''' Install TAP devices into their namespaces. This is done after EMANE daemons have been started, because that is their only chance to bind to the TAPs. ''' if not self.session.emane.doeventmonitor() and \ self.session.emane.service is None: warntxt = "unable to publish EMANE events because the eventservice " warntxt += "Python bindings failed to load" self.session.exception(coreapi.CORE_EXCP_LEVEL_ERROR, self.name, self.objid, warntxt) for netif in self.netifs(): if do_netns and "virtual" in netif.transport_type.lower(): netif.install() netif.setaddrs() # if we are listening for EMANE events, don't generate them if self.session.emane.doeventmonitor(): netif.poshook = None continue # at this point we register location handlers for generating # EMANE location events netif.poshook = self.setnemposition (x,y,z) = netif.node.position.get() self.setnemposition(netif, x, y, z) def deinstallnetifs(self): ''' Uninstall TAP devices. This invokes their shutdown method for any required cleanup; the device may be actually removed when emanetransportd terminates. ''' for netif in self.netifs(): if "virtual" in netif.transport_type.lower(): netif.shutdown() netif.poshook = None def setnemposition(self, netif, x, y, z): ''' Publish a NEM location change event using the EMANE event service. ''' if self.session.emane.service is None: if self.verbose: self.info("position service not available") return nemid = self.getnemid(netif) ifname = netif.localname if nemid is None: self.info("nemid for %s is unknown" % ifname) return (lat, long, alt) = self.session.location.getgeo(x, y, z) if self.verbose: self.info("setnemposition %s (%s) x,y,z=(%d,%d,%s)" "(%.6f,%.6f,%.6f)" % \ (ifname, nemid, x, y, z, lat, long, alt)) if self.session.emane.version >= self.session.emane.EMANE091: event = LocationEvent() else: event = emaneeventlocation.EventLocation(1) # altitude must be an integer or warning is printed # unused: yaw, pitch, roll, azimuth, elevation, velocity alt = int(round(alt)) if self.session.emane.version >= self.session.emane.EMANE091: event.append(nemid, latitude=lat, longitude=long, altitude=alt) self.session.emane.service.publish(0, event) else: event.set(0, nemid, lat, long, alt) self.session.emane.service.publish(emaneeventlocation.EVENT_ID, emaneeventservice.PLATFORMID_ANY, emaneeventservice.NEMID_ANY, emaneeventservice.COMPONENTID_ANY, event.export()) def setnempositions(self, moved_netifs): ''' Several NEMs have moved, from e.g. a WaypointMobilityModel calculation. Generate an EMANE Location Event having several entries for each netif that has moved. ''' if len(moved_netifs) == 0: return if self.session.emane.service is None: if self.verbose: self.info("position service not available") return if self.session.emane.version >= self.session.emane.EMANE091: event = LocationEvent() else: event = emaneeventlocation.EventLocation(len(moved_netifs)) i = 0 for netif in moved_netifs: nemid = self.getnemid(netif) ifname = netif.localname if nemid is None: self.info("nemid for %s is unknown" % ifname) continue (x, y, z) = netif.node.getposition() (lat, long, alt) = self.session.location.getgeo(x, y, z) if self.verbose: self.info("setnempositions %d %s (%s) x,y,z=(%d,%d,%s)" "(%.6f,%.6f,%.6f)" % \ (i, ifname, nemid, x, y, z, lat, long, alt)) # altitude must be an integer or warning is printed alt = int(round(alt)) if self.session.emane.version >= self.session.emane.EMANE091: event.append(nemid, latitude=lat, longitude=long, altitude=alt) else: event.set(i, nemid, lat, long, alt) i += 1 if self.session.emane.version >= self.session.emane.EMANE091: self.session.emane.service.publish(0, event) else: self.session.emane.service.publish(emaneeventlocation.EVENT_ID, emaneeventservice.PLATFORMID_ANY, emaneeventservice.NEMID_ANY, emaneeventservice.COMPONENTID_ANY, event.export()) core-4.8/daemon/core/emane/rfpipe.py0000664000175000017500000001152112534327775014376 00000000000000# # CORE # Copyright (c)2010-2014 the Boeing Company. # See the LICENSE file included in this distribution. # # authors: Jeff Ahrenholz # Harry Bullen # ''' rfpipe.py: EMANE RF-PIPE model for CORE ''' import sys import string try: from emanesh.events import EventService except: pass from core.api import coreapi from core.constants import * from emane import EmaneModel from universal import EmaneUniversalModel class EmaneRfPipeModel(EmaneModel): def __init__(self, session, objid = None, verbose = False): EmaneModel.__init__(self, session, objid, verbose) # model name _name = "emane_rfpipe" if 'EventService' in globals(): xml_path = '/usr/share/emane/xml/models/mac/rfpipe' else: xml_path = "/usr/share/emane/models/rfpipe/xml" # configuration parameters are # ( 'name', 'type', 'default', 'possible-value-list', 'caption') # MAC parameters _confmatrix_mac_base = [ ("enablepromiscuousmode", coreapi.CONF_DATA_TYPE_BOOL, '0', 'True,False', 'enable promiscuous mode'), ("datarate", coreapi.CONF_DATA_TYPE_UINT32, '1M', '', 'data rate (bps)'), ("flowcontrolenable", coreapi.CONF_DATA_TYPE_BOOL, '0', 'On,Off', 'enable traffic flow control'), ("flowcontroltokens", coreapi.CONF_DATA_TYPE_UINT16, '10', '', 'number of flow control tokens'), ("pcrcurveuri", coreapi.CONF_DATA_TYPE_STRING, '%s/rfpipepcr.xml' % xml_path, '', 'SINR/PCR curve file'), ] _confmatrix_mac_081 = [ ("jitter", coreapi.CONF_DATA_TYPE_FLOAT, '0.0', '', 'transmission jitter (usec)'), ("delay", coreapi.CONF_DATA_TYPE_FLOAT, '0.0', '', 'transmission delay (usec)'), ("transmissioncontrolmap", coreapi.CONF_DATA_TYPE_STRING, '', '', 'tx control map (nem:rate:freq:tx_dBm)'), ("enabletighttiming", coreapi.CONF_DATA_TYPE_BOOL, '0', 'On,Off', 'enable tight timing for pkt delay'), ] _confmatrix_mac_091 = [ ("jitter", coreapi.CONF_DATA_TYPE_FLOAT, '0.0', '', 'transmission jitter (sec)'), ("delay", coreapi.CONF_DATA_TYPE_FLOAT, '0.0', '', 'transmission delay (sec)'), ] if 'EventService' in globals(): _confmatrix_mac = _confmatrix_mac_base + _confmatrix_mac_091 else: _confmatrix_mac = _confmatrix_mac_base + _confmatrix_mac_081 # PHY parameters from Universal PHY _confmatrix_phy = EmaneUniversalModel._confmatrix _confmatrix = _confmatrix_mac + _confmatrix_phy # value groupings _confgroups = "RF-PIPE MAC Parameters:1-%d|Universal PHY Parameters:%d-%d" \ % ( len(_confmatrix_mac), len(_confmatrix_mac) + 1, len(_confmatrix)) def buildnemxmlfiles(self, e, ifc): ''' Build the necessary nem, mac, and phy XMLs in the given path. If an individual NEM has a nonstandard config, we need to build that file also. Otherwise the WLAN-wide nXXemane_rfpipenem.xml, nXXemane_rfpipemac.xml, nXXemane_rfpipephy.xml are used. ''' values = e.getifcconfig(self.objid, self._name, self.getdefaultvalues(), ifc) if values is None: return nemdoc = e.xmldoc("nem") nem = nemdoc.getElementsByTagName("nem").pop() nem.setAttribute("name", "RF-PIPE NEM") e.appendtransporttonem(nemdoc, nem, self.objid, ifc) mactag = nemdoc.createElement("mac") mactag.setAttribute("definition", self.macxmlname(ifc)) nem.appendChild(mactag) phytag = nemdoc.createElement("phy") phytag.setAttribute("definition", self.phyxmlname(ifc)) nem.appendChild(phytag) e.xmlwrite(nemdoc, self.nemxmlname(ifc)) names = list(self.getnames()) macnames = names[:len(self._confmatrix_mac)] phynames = names[len(self._confmatrix_mac):] macdoc = e.xmldoc("mac") mac = macdoc.getElementsByTagName("mac").pop() mac.setAttribute("name", "RF-PIPE MAC") mac.setAttribute("library", "rfpipemaclayer") if e.version < e.EMANE091 and \ self.valueof("transmissioncontrolmap", values) is "": macnames.remove("transmissioncontrolmap") # EMANE 0.7.4 support if e.version == e.EMANE074: # convert datarate from bps to kbps i = names.index('datarate') values = list(values) values[i] = self.emane074_fixup(values[i], 1000) # append MAC options to macdoc map( lambda n: mac.appendChild(e.xmlparam(macdoc, n, \ self.valueof(n, values))), macnames) e.xmlwrite(macdoc, self.macxmlname(ifc)) phydoc = EmaneUniversalModel.getphydoc(e, self, values, phynames) e.xmlwrite(phydoc, self.phyxmlname(ifc)) core-4.8/daemon/core/emane/universal.py0000664000175000017500000001326212534327775015125 00000000000000# # CORE # Copyright (c)2010-2014 the Boeing Company. # See the LICENSE file included in this distribution. # # author: Jeff Ahrenholz # ''' universal.py: EMANE Universal PHY model for CORE. Enumerates configuration items used for the Universal PHY. ''' import sys import string try: from emanesh.events import EventService except: pass from core.api import coreapi from core.constants import * from emane import EmaneModel class EmaneUniversalModel(EmaneModel): ''' This Univeral PHY model is meant to be imported by other models, not instantiated. ''' def __init__(self, session, objid = None, verbose = False): raise SyntaxError _name = "emane_universal" _xmlname = "universalphy" _xmllibrary = "universalphylayer" # universal PHY parameters _confmatrix_base = [ ("bandwidth", coreapi.CONF_DATA_TYPE_UINT64, '1M', '', 'rf bandwidth (hz)'), ("frequency", coreapi.CONF_DATA_TYPE_UINT64, '2.347G', '','frequency (Hz)'), ("frequencyofinterest", coreapi.CONF_DATA_TYPE_UINT64, '2.347G', '','frequency of interest (Hz)'), ("subid", coreapi.CONF_DATA_TYPE_UINT16, '1', '','subid'), ("systemnoisefigure", coreapi.CONF_DATA_TYPE_FLOAT, '4.0', '','system noise figure (dB)'), ("txpower", coreapi.CONF_DATA_TYPE_FLOAT, '0.0', '','transmit power (dBm)'), ] _confmatrix_081 = [ ("antennagain", coreapi.CONF_DATA_TYPE_FLOAT, '0.0', '','antenna gain (dBi)'), ("antennaazimuth", coreapi.CONF_DATA_TYPE_FLOAT, '0.0', '','antenna azimuth (deg)'), ("antennaelevation", coreapi.CONF_DATA_TYPE_FLOAT, '0.0', '','antenna elevation (deg)'), ("antennaprofileid", coreapi.CONF_DATA_TYPE_STRING, '1', '','antenna profile ID'), ("antennaprofilemanifesturi", coreapi.CONF_DATA_TYPE_STRING, '', '','antenna profile manifest URI'), ("antennaprofileenable", coreapi.CONF_DATA_TYPE_BOOL, '0', 'On,Off','antenna profile mode'), ("defaultconnectivitymode", coreapi.CONF_DATA_TYPE_BOOL, '1', 'On,Off','default connectivity'), ("frequencyofinterestfilterenable", coreapi.CONF_DATA_TYPE_BOOL, '1', 'On,Off','frequency of interest filter enable'), ("noiseprocessingmode", coreapi.CONF_DATA_TYPE_BOOL, '0', 'On,Off','enable noise processing'), ("pathlossmode", coreapi.CONF_DATA_TYPE_STRING, '2ray', 'pathloss,2ray,freespace','path loss mode'), ] _confmatrix_091 = [ ("fixedantennagain", coreapi.CONF_DATA_TYPE_FLOAT, '0.0', '','antenna gain (dBi)'), ("fixedantennagainenable", coreapi.CONF_DATA_TYPE_BOOL, '1', 'On,Off','enable fixed antenna gain'), ("noisemode", coreapi.CONF_DATA_TYPE_STRING, 'none', 'none,all,outofband','noise processing mode'), ("noisebinsize", coreapi.CONF_DATA_TYPE_UINT64, '20', '','noise bin size in microseconds'), ("propagationmodel", coreapi.CONF_DATA_TYPE_STRING, '2ray', 'precomputed,2ray,freespace','path loss mode'), ] if 'EventService' in globals(): _confmatrix = _confmatrix_base + _confmatrix_091 else: _confmatrix = _confmatrix_base + _confmatrix_081 # old parameters _confmatrix_ver074 = [ ("antennaazimuthbeamwidth", coreapi.CONF_DATA_TYPE_FLOAT, '360.0', '','azimith beam width (deg)'), ("antennaelevationbeamwidth", coreapi.CONF_DATA_TYPE_FLOAT, '180.0', '','elevation beam width (deg)'), ("antennatype", coreapi.CONF_DATA_TYPE_STRING, 'omnidirectional', 'omnidirectional,unidirectional','antenna type'), ] # parameters that require unit conversion for 0.7.4 _update_ver074 = ("bandwidth", "frequency", "frequencyofinterest") # parameters that should be removed for 0.7.4 _remove_ver074 = ("antennaprofileenable", "antennaprofileid", "antennaprofilemanifesturi", "frequencyofinterestfilterenable") @classmethod def getphydoc(cls, e, mac, values, phynames): phydoc = e.xmldoc("phy") phy = phydoc.getElementsByTagName("phy").pop() phy.setAttribute("name", cls._xmlname) if e.version < e.EMANE091: phy.setAttribute("library", cls._xmllibrary) # EMANE 0.7.4 suppport - to be removed when 0.7.4 support is deprecated if e.version == e.EMANE074: names = mac.getnames() values = list(values) phynames = list(phynames) # update units for some parameters for p in cls._update_ver074: i = names.index(p) # these all happen to be KHz, so 1000 is used values[i] = cls.emane074_fixup(values[i], 1000) # remove new incompatible options for p in cls._remove_ver074: phynames.remove(p) # insert old options with their default values for old in cls._confmatrix_ver074: phy.appendChild(e.xmlparam(phydoc, old[0], old[2])) frequencies = None if e.version >= e.EMANE091: name = "frequencyofinterest" value = mac.valueof(name, values) frequencies = cls.valuestrtoparamlist(phydoc, name, value) if frequencies: phynames = list(phynames) phynames.remove("frequencyofinterest") # append all PHY options to phydoc map( lambda n: phy.appendChild(e.xmlparam(phydoc, n, \ mac.valueof(n, values))), phynames) if frequencies: phy.appendChild(frequencies) return phydoc core-4.8/daemon/core/location.py0000664000175000017500000002404012534327775013634 00000000000000# # CORE # Copyright (c)2010-2013 the Boeing Company. # See the LICENSE file included in this distribution. # # author: Jeff Ahrenholz # ''' location.py: definition of CoreLocation class that is a member of the Session object. Provides conversions between Cartesian and geographic coordinate systems. Depends on utm contributed module, from https://pypi.python.org/pypi/utm (version 0.3.0). ''' from core.conf import ConfigurableManager from core.api import coreapi from core.misc import utm class CoreLocation(ConfigurableManager): ''' Member of session class for handling global location data. This keeps track of a latitude/longitude/altitude reference point and scale in order to convert between X,Y and geo coordinates. TODO: this could be updated to use more generic Configurable/ConfigurableManager code like other Session objects ''' _name = "location" _type = coreapi.CORE_TLV_REG_UTILITY def __init__(self, session): ConfigurableManager.__init__(self, session) self.reset() self.zonemap = {} for n, l in utm.ZONE_LETTERS: self.zonemap[l] = n def reset(self): ''' Reset to initial state. ''' # (x, y, z) coordinates of the point given by self.refgeo self.refxyz = (0.0, 0.0, 0.0) # decimal latitude, longitude, and altitude at the point (x, y, z) self.setrefgeo(0.0, 0.0, 0.0) # 100 pixels equals this many meters self.refscale = 1.0 # cached distance to refpt in other zones self.zoneshifts = {} def configure_values(self, msg, values): ''' Receive configuration message for setting the reference point and scale. ''' if values is None: self.session.info("location data missing") return None values = values.split('|') # Cartesian coordinate reference point refx,refy = map(lambda x: float(x), values[0:2]) refz = 0.0 self.refxyz = (refx, refy, refz) # Geographic reference point lat,long,alt = map(lambda x: float(x), values[2:5]) self.setrefgeo(lat, long, alt) self.refscale = float(values[5]) self.session.info("location configured: (%.2f,%.2f,%.2f) = " "(%.5f,%.5f,%.5f) scale=%.2f" % (self.refxyz[0], self.refxyz[1], self.refxyz[2], self.refgeo[0], self.refgeo[1], self.refgeo[2], self.refscale)) self.session.info("location configured: UTM(%.5f,%.5f,%.5f)" % (self.refutm[1], self.refutm[2], self.refutm[3])) def px2m(self, val): ''' Convert the specified value in pixels to meters using the configured scale. The scale is given as s, where 100 pixels = s meters. ''' return (val / 100.0) * self.refscale def m2px(self, val): ''' Convert the specified value in meters to pixels using the configured scale. The scale is given as s, where 100 pixels = s meters. ''' if self.refscale == 0.0: return 0.0 return 100.0 * (val / self.refscale) def setrefgeo(self, lat, lon, alt): ''' Record the geographical reference point decimal (lat, lon, alt) and convert and store its UTM equivalent for later use. ''' self.refgeo = (lat, lon, alt) # easting, northing, zone (e, n, zonen, zonel) = utm.from_latlon(lat, lon) self.refutm = ( (zonen, zonel), e, n, alt) def getgeo(self, x, y, z): ''' Given (x, y, z) Cartesian coordinates, convert them to latitude, longitude, and altitude based on the configured reference point and scale. ''' # shift (x,y,z) over to reference point (x,y,z) x = x - self.refxyz[0] y = -(y - self.refxyz[1]) if z is None: z = self.refxyz[2] else: z = z - self.refxyz[2] # use UTM coordinates since unit is meters zone = self.refutm[0] if zone == "": raise ValueError, "reference point not configured" e = self.refutm[1] + self.px2m(x) n = self.refutm[2] + self.px2m(y) alt = self.refutm[3] + self.px2m(z) (e, n, zone) = self.getutmzoneshift(e, n) try: lat, lon = utm.to_latlon(e, n, zone[0], zone[1]) except utm.OutOfRangeError: self.info("UTM out of range error for e=%s n=%s zone=%s" \ "xyz=(%s,%s,%s)" % (e, n, zone, x, y, z)) (lat, lon) = self.refgeo[:2] #self.info("getgeo(%s,%s,%s) e=%s n=%s zone=%s lat,lon,alt=" \ # "%.3f,%.3f,%.3f" % (x, y, z, e, n, zone, lat, lon, alt)) return (lat, lon, alt) def getxyz(self, lat, lon, alt): ''' Given latitude, longitude, and altitude location data, convert them to (x, y, z) Cartesian coordinates based on the configured reference point and scale. Lat/lon is converted to UTM meter coordinates, UTM zones are accounted for, and the scale turns meters to pixels. ''' # convert lat/lon to UTM coordinates in meters (e, n, zonen, zonel) = utm.from_latlon(lat, lon) (rlat, rlon, ralt) = self.refgeo xshift = self.geteastingshift(zonen, zonel) if xshift is None: xm = e - self.refutm[1] else: xm = e + xshift yshift = self.getnorthingshift(zonen, zonel) if yshift is None: ym = n - self.refutm[2] else: ym = n + yshift zm = alt - ralt # shift (x,y,z) over to reference point (x,y,z) x = self.m2px(xm) + self.refxyz[0] y = -(self.m2px(ym) + self.refxyz[1]) z = self.m2px(zm) + self.refxyz[2] return (x, y, z) def geteastingshift(self, zonen, zonel): ''' If the lat, lon coordinates being converted are located in a different UTM zone than the canvas reference point, the UTM meters may need to be shifted. This picks a reference point in the same longitudinal band (UTM zone number) as the provided zone, to calculate the shift in meters for the x coordinate. ''' rzonen = int(self.refutm[0][0]) if zonen == rzonen: return None # same zone number, no x shift required z = (zonen, zonel) if z in self.zoneshifts and self.zoneshifts[z][0] is not None: return self.zoneshifts[z][0] # x shift already calculated, cached (rlat, rlon, ralt) = self.refgeo lon2 = rlon + 6*(zonen - rzonen) # ea. zone is 6deg band (e2, n2, zonen2, zonel2) = utm.from_latlon(rlat, lon2) # ignore northing # NOTE: great circle distance used here, not reference ellipsoid! xshift = utm.haversine(rlon, rlat, lon2, rlat) - e2 # cache the return value yshift = None if z in self.zoneshifts: yshift = self.zoneshifts[z][1] self.zoneshifts[z] = (xshift, yshift) return xshift def getnorthingshift(self, zonen, zonel): ''' If the lat, lon coordinates being converted are located in a different UTM zone than the canvas reference point, the UTM meters may need to be shifted. This picks a reference point in the same latitude band (UTM zone letter) as the provided zone, to calculate the shift in meters for the y coordinate. ''' rzonel = self.refutm[0][1] if zonel == rzonel: return None # same zone letter, no y shift required z = (zonen, zonel) if z in self.zoneshifts and self.zoneshifts[z][1] is not None: return self.zoneshifts[z][1] # y shift already calculated, cached (rlat, rlon, ralt) = self.refgeo # zonemap is used to calculate degrees difference between zone letters latshift = self.zonemap[zonel] - self.zonemap[rzonel] lat2 = rlat + latshift # ea. latitude band is 8deg high (e2, n2, zonen2, zonel2) = utm.from_latlon(lat2, rlon) # NOTE: great circle distance used here, not reference ellipsoid yshift = -(utm.haversine(rlon, rlat, rlon, lat2) + n2) # cache the return value xshift = None if z in self.zoneshifts: xshift = self.zoneshifts[z][0] self.zoneshifts[z] = (xshift, yshift) return yshift def getutmzoneshift(self, e, n): ''' Given UTM easting and northing values, check if they fall outside the reference point's zone boundary. Return the UTM coordinates in a different zone and the new zone if they do. Zone lettering is only changed when the reference point is in the opposite hemisphere. ''' zone = self.refutm[0] (rlat, rlon, ralt) = self.refgeo if e > 834000 or e < 166000: num_zones = (int(e) - 166000) / (utm.R/10) # estimate number of zones to shift, E (positive) or W (negative) rlon2 = self.refgeo[1] + (num_zones * 6) (e2, n2, zonen2, zonel2) = utm.from_latlon(rlat, rlon2) xshift = utm.haversine(rlon, rlat, rlon2, rlat) # after >3 zones away from refpt, the above estimate won't work # (the above estimate could be improved) if not 100000 <= (e - xshift) < 1000000: # move one more zone away num_zones = (abs(num_zones)+1) * (abs(num_zones)/num_zones) rlon2 = self.refgeo[1] + (num_zones * 6) (e2, n2, zonen2, zonel2) = utm.from_latlon(rlat, rlon2) xshift = utm.haversine(rlon, rlat, rlon2, rlat) e = e - xshift zone = (zonen2, zonel2) if n < 0: # refpt in northern hemisphere and we crossed south of equator n += 10000000 zone = (zone[0], 'M') elif n > 10000000: # refpt in southern hemisphere and we crossed north of equator n -= 10000000 zone = (zone[0], 'N') return (e, n, zone) core-4.8/daemon/core/misc/0000775000175000017500000000000012534327775012465 500000000000000core-4.8/daemon/core/misc/LatLongUTMconversion.py0000775000175000017500000002040712534327775017021 00000000000000#!/usr/bin/env python # this file is from http://pygps.org/ # Lat Long - UTM, UTM - Lat Long conversions from math import pi, sin, cos, tan, sqrt #LatLong- UTM conversion..h #definitions for lat/long to UTM and UTM to lat/lng conversions #include _deg2rad = pi / 180.0 _rad2deg = 180.0 / pi _EquatorialRadius = 2 _eccentricitySquared = 3 _ellipsoid = [ # id, Ellipsoid name, Equatorial Radius, square of eccentricity # first once is a placeholder only, To allow array indices to match id numbers [ -1, "Placeholder", 0, 0], [ 1, "Airy", 6377563, 0.00667054], [ 2, "Australian National", 6378160, 0.006694542], [ 3, "Bessel 1841", 6377397, 0.006674372], [ 4, "Bessel 1841 (Nambia] ", 6377484, 0.006674372], [ 5, "Clarke 1866", 6378206, 0.006768658], [ 6, "Clarke 1880", 6378249, 0.006803511], [ 7, "Everest", 6377276, 0.006637847], [ 8, "Fischer 1960 (Mercury] ", 6378166, 0.006693422], [ 9, "Fischer 1968", 6378150, 0.006693422], [ 10, "GRS 1967", 6378160, 0.006694605], [ 11, "GRS 1980", 6378137, 0.00669438], [ 12, "Helmert 1906", 6378200, 0.006693422], [ 13, "Hough", 6378270, 0.00672267], [ 14, "International", 6378388, 0.00672267], [ 15, "Krassovsky", 6378245, 0.006693422], [ 16, "Modified Airy", 6377340, 0.00667054], [ 17, "Modified Everest", 6377304, 0.006637847], [ 18, "Modified Fischer 1960", 6378155, 0.006693422], [ 19, "South American 1969", 6378160, 0.006694542], [ 20, "WGS 60", 6378165, 0.006693422], [ 21, "WGS 66", 6378145, 0.006694542], [ 22, "WGS-72", 6378135, 0.006694318], [ 23, "WGS-84", 6378137, 0.00669438] ] #Reference ellipsoids derived from Peter H. Dana's website- #http://www.utexas.edu/depts/grg/gcraft/notes/datum/elist.html #Department of Geography, University of Texas at Austin #Internet: pdana@mail.utexas.edu #3/22/95 #Source #Defense Mapping Agency. 1987b. DMA Technical Report: Supplement to Department of Defense World Geodetic System #1984 Technical Report. Part I and II. Washington, DC: Defense Mapping Agency #def LLtoUTM(int ReferenceEllipsoid, const double Lat, const double Long, # double &UTMNorthing, double &UTMEasting, char* UTMZone) def LLtoUTM(ReferenceEllipsoid, Lat, Long, zone = None): """converts lat/long to UTM coords. Equations from USGS Bulletin 1532 East Longitudes are positive, West longitudes are negative. North latitudes are positive, South latitudes are negative Lat and Long are in decimal degrees Written by Chuck Gantz- chuck.gantz@globalstar.com""" a = _ellipsoid[ReferenceEllipsoid][_EquatorialRadius] eccSquared = _ellipsoid[ReferenceEllipsoid][_eccentricitySquared] k0 = 0.9996 #Make sure the longitude is between -180.00 .. 179.9 LongTemp = (Long+180)-int((Long+180)/360)*360-180 # -180.00 .. 179.9 LatRad = Lat*_deg2rad LongRad = LongTemp*_deg2rad if zone is None: ZoneNumber = int((LongTemp + 180)/6) + 1 else: ZoneNumber = zone if Lat >= 56.0 and Lat < 64.0 and LongTemp >= 3.0 and LongTemp < 12.0: ZoneNumber = 32 # Special zones for Svalbard if Lat >= 72.0 and Lat < 84.0: if LongTemp >= 0.0 and LongTemp < 9.0:ZoneNumber = 31 elif LongTemp >= 9.0 and LongTemp < 21.0: ZoneNumber = 33 elif LongTemp >= 21.0 and LongTemp < 33.0: ZoneNumber = 35 elif LongTemp >= 33.0 and LongTemp < 42.0: ZoneNumber = 37 LongOrigin = (ZoneNumber - 1)*6 - 180 + 3 #+3 puts origin in middle of zone LongOriginRad = LongOrigin * _deg2rad #compute the UTM Zone from the latitude and longitude UTMZone = "%d%c" % (ZoneNumber, _UTMLetterDesignator(Lat)) eccPrimeSquared = (eccSquared)/(1-eccSquared) N = a/sqrt(1-eccSquared*sin(LatRad)*sin(LatRad)) T = tan(LatRad)*tan(LatRad) C = eccPrimeSquared*cos(LatRad)*cos(LatRad) A = cos(LatRad)*(LongRad-LongOriginRad) M = a*((1 - eccSquared/4 - 3*eccSquared*eccSquared/64 - 5*eccSquared*eccSquared*eccSquared/256)*LatRad - (3*eccSquared/8 + 3*eccSquared*eccSquared/32 + 45*eccSquared*eccSquared*eccSquared/1024)*sin(2*LatRad) + (15*eccSquared*eccSquared/256 + 45*eccSquared*eccSquared*eccSquared/1024)*sin(4*LatRad) - (35*eccSquared*eccSquared*eccSquared/3072)*sin(6*LatRad)) UTMEasting = (k0*N*(A+(1-T+C)*A*A*A/6 + (5-18*T+T*T+72*C-58*eccPrimeSquared)*A*A*A*A*A/120) + 500000.0) UTMNorthing = (k0*(M+N*tan(LatRad)*(A*A/2+(5-T+9*C+4*C*C)*A*A*A*A/24 + (61 -58*T +T*T +600*C -330*eccPrimeSquared)*A*A*A*A*A*A/720))) if Lat < 0: UTMNorthing = UTMNorthing + 10000000.0; #10000000 meter offset for southern hemisphere return (UTMZone, UTMEasting, UTMNorthing) def _UTMLetterDesignator(Lat): """This routine determines the correct UTM letter designator for the given latitude returns 'Z' if latitude is outside the UTM limits of 84N to 80S Written by Chuck Gantz- chuck.gantz@globalstar.com""" if 84 >= Lat >= 72: return 'X' elif 72 > Lat >= 64: return 'W' elif 64 > Lat >= 56: return 'V' elif 56 > Lat >= 48: return 'U' elif 48 > Lat >= 40: return 'T' elif 40 > Lat >= 32: return 'S' elif 32 > Lat >= 24: return 'R' elif 24 > Lat >= 16: return 'Q' elif 16 > Lat >= 8: return 'P' elif 8 > Lat >= 0: return 'N' elif 0 > Lat >= -8: return 'M' elif -8> Lat >= -16: return 'L' elif -16 > Lat >= -24: return 'K' elif -24 > Lat >= -32: return 'J' elif -32 > Lat >= -40: return 'H' elif -40 > Lat >= -48: return 'G' elif -48 > Lat >= -56: return 'F' elif -56 > Lat >= -64: return 'E' elif -64 > Lat >= -72: return 'D' elif -72 > Lat >= -80: return 'C' else: return 'Z' # if the Latitude is outside the UTM limits #void UTMtoLL(int ReferenceEllipsoid, const double UTMNorthing, const double UTMEasting, const char* UTMZone, # double& Lat, double& Long ) def UTMtoLL(ReferenceEllipsoid, northing, easting, zone): """converts UTM coords to lat/long. Equations from USGS Bulletin 1532 East Longitudes are positive, West longitudes are negative. North latitudes are positive, South latitudes are negative Lat and Long are in decimal degrees. Written by Chuck Gantz- chuck.gantz@globalstar.com Converted to Python by Russ Nelson """ k0 = 0.9996 a = _ellipsoid[ReferenceEllipsoid][_EquatorialRadius] eccSquared = _ellipsoid[ReferenceEllipsoid][_eccentricitySquared] e1 = (1-sqrt(1-eccSquared))/(1+sqrt(1-eccSquared)) #NorthernHemisphere; //1 for northern hemispher, 0 for southern x = easting - 500000.0 #remove 500,000 meter offset for longitude y = northing ZoneLetter = zone[-1] ZoneNumber = int(zone[:-1]) if ZoneLetter >= 'N': NorthernHemisphere = 1 # point is in northern hemisphere else: NorthernHemisphere = 0 # point is in southern hemisphere y -= 10000000.0 # remove 10,000,000 meter offset used for southern hemisphere LongOrigin = (ZoneNumber - 1)*6 - 180 + 3 # +3 puts origin in middle of zone eccPrimeSquared = (eccSquared)/(1-eccSquared) M = y / k0 mu = M/(a*(1-eccSquared/4-3*eccSquared*eccSquared/64-5*eccSquared*eccSquared*eccSquared/256)) phi1Rad = (mu + (3*e1/2-27*e1*e1*e1/32)*sin(2*mu) + (21*e1*e1/16-55*e1*e1*e1*e1/32)*sin(4*mu) +(151*e1*e1*e1/96)*sin(6*mu)) phi1 = phi1Rad*_rad2deg; N1 = a/sqrt(1-eccSquared*sin(phi1Rad)*sin(phi1Rad)) T1 = tan(phi1Rad)*tan(phi1Rad) C1 = eccPrimeSquared*cos(phi1Rad)*cos(phi1Rad) R1 = a*(1-eccSquared)/pow(1-eccSquared*sin(phi1Rad)*sin(phi1Rad), 1.5) D = x/(N1*k0) Lat = phi1Rad - (N1*tan(phi1Rad)/R1)*(D*D/2-(5+3*T1+10*C1-4*C1*C1-9*eccPrimeSquared)*D*D*D*D/24 +(61+90*T1+298*C1+45*T1*T1-252*eccPrimeSquared-3*C1*C1)*D*D*D*D*D*D/720) Lat = Lat * _rad2deg Long = (D-(1+2*T1+C1)*D*D*D/6+(5-2*C1+28*T1-3*C1*C1+8*eccPrimeSquared+24*T1*T1) *D*D*D*D*D/120)/cos(phi1Rad) Long = LongOrigin + Long * _rad2deg return (Lat, Long) if __name__ == '__main__': (z, e, n) = LLtoUTM(23, 45.00, -75.00) print z, e, n print UTMtoLL(23, n, e, z) core-4.8/daemon/core/misc/__init__.py0000664000175000017500000000000012534327775014504 00000000000000core-4.8/daemon/core/misc/event.py0000664000175000017500000001047312534327775014105 00000000000000# # CORE # Copyright (c)2012 the Boeing Company. # See the LICENSE file included in this distribution. # # authors: Tom Goff # ''' event.py: event loop implementation using a heap queue and threads. ''' import time import threading import heapq class EventLoop(object): class Event(object): def __init__(self, eventnum, time, func, *args, **kwds): self.eventnum = eventnum self.time = time self.func = func self.args = args self.kwds = kwds self.canceled = False def __cmp__(self, other): tmp = cmp(self.time, other.time) if tmp == 0: tmp = cmp(self.eventnum, other.eventnum) return tmp def run(self): if self.canceled: return self.func(*self.args, **self.kwds) def cancel(self): self.canceled = True # XXX not thread-safe def __init__(self): self.lock = threading.RLock() self.queue = [] self.eventnum = 0 self.timer = None self.running = False self.start = None def __del__(self): self.stop() def __run_events(self): schedule = False while True: with self.lock: if not self.running or not self.queue: break now = time.time() if self.queue[0].time > now: schedule = True break event = heapq.heappop(self.queue) assert event.time <= now event.run() with self.lock: self.timer = None if schedule: self.__schedule_event() def __schedule_event(self): with self.lock: assert self.running if not self.queue: return delay = self.queue[0].time - time.time() assert self.timer is None self.timer = threading.Timer(delay, self.__run_events) self.timer.daemon = True self.timer.start() def run(self): with self.lock: if self.running: return self.running = True self.start = time.time() for event in self.queue: event.time += self.start self.__schedule_event() def stop(self): with self.lock: if not self.running: return self.queue = [] self.eventnum = 0 if self.timer is not None: self.timer.cancel() self.timer = None self.running = False self.start = None def add_event(self, delaysec, func, *args, **kwds): with self.lock: eventnum = self.eventnum self.eventnum += 1 evtime = float(delaysec) if self.running: evtime += time.time() event = self.Event(eventnum, evtime, func, *args, **kwds) if self.queue: prevhead = self.queue[0] else: prevhead = None heapq.heappush(self.queue, event) head = self.queue[0] if prevhead is not None and prevhead != head: if self.timer is not None and not self.timer.is_alive(): self.timer.cancel() self.timer = None if self.running and self.timer is None: self.__schedule_event() return event def example(): loop = EventLoop() def msg(arg): delta = time.time() - loop.start print delta, 'arg:', arg def repeat(interval, count): count -= 1 msg('repeat: interval: %s; remaining: %s' % (interval, count)) if count > 0: loop.add_event(interval, repeat, interval, count) def sleep(delay): msg('sleep %s' % delay) time.sleep(delay) msg('sleep done') def stop(arg): msg(arg) loop.stop() loop.add_event(0, msg, 'start') loop.add_event(0, msg, 'time zero') for delay in 5, 4, 10, -1, 0, 9, 3, 7, 3.14: loop.add_event(delay, msg, 'time %s' % delay) loop.run() loop.add_event(0, repeat, 1, 5) loop.add_event(12, sleep, 10) loop.add_event(15.75, stop, 'stop time: 15.75') core-4.8/daemon/core/misc/ipaddr.py0000664000175000017500000001551112534327775014225 00000000000000# # CORE # Copyright (c)2010-2012 the Boeing Company. # See the LICENSE file included in this distribution. # # author: Tom Goff # ''' ipaddr.py: helper objects for dealing with IPv4/v6 addresses. ''' import socket import struct import random AF_INET = socket.AF_INET AF_INET6 = socket.AF_INET6 class MacAddr(object): def __init__(self, addr): self.addr = addr def __str__(self): return ":".join(map(lambda x: ("%02x" % ord(x)), self.addr)) def tolinklocal(self): ''' Convert the MAC address to a IPv6 link-local address, using EUI 48 to EUI 64 conversion process per RFC 5342. ''' if not self.addr: return IPAddr.fromstring("::") tmp = struct.unpack("!Q", '\x00\x00' + self.addr)[0] nic = long(tmp) & 0x000000FFFFFFL oui = long(tmp) & 0xFFFFFF000000L # toggle U/L bit oui ^= 0x020000000000L # append EUI-48 octets oui = (oui << 16) | 0xFFFE000000L return IPAddr(AF_INET6, struct.pack("!QQ", 0xfe80 << 48, oui | nic)) @classmethod def fromstring(cls, s): addr = "".join(map(lambda x: chr(int(x, 16)), s.split(":"))) return cls(addr) @classmethod def random(cls): tmp = random.randint(0, 0xFFFFFF) tmp |= 0x00163E << 24 # use the Xen OID 00:16:3E tmpbytes = struct.pack("!Q", tmp) return cls(tmpbytes[2:]) class IPAddr(object): def __init__(self, af, addr): # check if (af, addr) is valid if not socket.inet_ntop(af, addr): raise ValueError, "invalid af/addr" self.af = af self.addr = addr def isIPv4(self): return self.af == AF_INET def isIPv6(self): return self.af == AF_INET6 def __str__(self): return socket.inet_ntop(self.af, self.addr) def __eq__(self, other): try: return other.af == self.af and other.addr == self.addr except: return False def __add__(self, other): try: carry = int(other) except: return NotImplemented tmp = map(lambda x: ord(x), self.addr) for i in xrange(len(tmp) - 1, -1, -1): x = tmp[i] + carry tmp[i] = x & 0xff carry = x >> 8 if carry == 0: break addr = "".join(map(lambda x: chr(x), tmp)) return self.__class__(self.af, addr) def __sub__(self, other): try: tmp = -int(other) except: return NotImplemented return self.__add__(tmp) @classmethod def fromstring(cls, s): for af in AF_INET, AF_INET6: try: return cls(af, socket.inet_pton(af, s)) except Exception, e: pass raise e @staticmethod def toint(s): ''' convert IPv4 string to 32-bit integer ''' bin = socket.inet_pton(AF_INET, s) return(struct.unpack('!I', bin)[0]) class IPPrefix(object): def __init__(self, af, prefixstr): "prefixstr format: address/prefixlen" tmp = prefixstr.split("/") if len(tmp) > 2: raise ValueError, "invalid prefix: '%s'" % prefixstr self.af = af if self.af == AF_INET: self.addrlen = 32 elif self.af == AF_INET6: self.addrlen = 128 else: raise ValueError, "invalid address family: '%s'" % self.af if len(tmp) == 2: self.prefixlen = int(tmp[1]) else: self.prefixlen = self.addrlen self.prefix = socket.inet_pton(self.af, tmp[0]) if self.addrlen > self.prefixlen: addrbits = self.addrlen - self.prefixlen netmask = ((1L << self.prefixlen) - 1) << addrbits prefix = "" for i in xrange(-1, -(addrbits >> 3) - 2, -1): prefix = chr(ord(self.prefix[i]) & (netmask & 0xff)) + prefix netmask >>= 8 self.prefix = self.prefix[:i] + prefix def __str__(self): return "%s/%s" % (socket.inet_ntop(self.af, self.prefix), self.prefixlen) def __eq__(self, other): try: return other.af == self.af and \ other.prefixlen == self.prefixlen and \ other.prefix == self.prefix except: return False def __add__(self, other): try: tmp = int(other) except: return NotImplemented a = IPAddr(self.af, self.prefix) + \ (tmp << (self.addrlen - self.prefixlen)) prefixstr = "%s/%s" % (a, self.prefixlen) if self.__class__ == IPPrefix: return self.__class__(self.af, prefixstr) else: return self.__class__(prefixstr) def __sub__(self, other): try: tmp = -int(other) except: return NotImplemented return self.__add__(tmp) def addr(self, hostid): tmp = int(hostid) if (tmp == 1 or tmp == 0 or tmp == -1) and self.addrlen == self.prefixlen: return IPAddr(self.af, self.prefix) if tmp == 0 or \ tmp > (1 << (self.addrlen - self.prefixlen)) - 1 or \ (self.af == AF_INET and tmp == (1 << (self.addrlen - self.prefixlen)) - 1): raise ValueError, "invalid hostid for prefix %s: %s" % (self, hostid) addr = "" for i in xrange(-1, -(self.addrlen >> 3) - 1, -1): addr = chr(ord(self.prefix[i]) | (tmp & 0xff)) + addr tmp >>= 8 if not tmp: break addr = self.prefix[:i] + addr return IPAddr(self.af, addr) def minaddr(self): return self.addr(1) def maxaddr(self): if self.af == AF_INET: return self.addr((1 << (self.addrlen - self.prefixlen)) - 2) else: return self.addr((1 << (self.addrlen - self.prefixlen)) - 1) def numaddr(self): return max(0, (1 << (self.addrlen - self.prefixlen)) - 2) def prefixstr(self): return "%s" % socket.inet_ntop(self.af, self.prefix) def netmaskstr(self): addrbits = self.addrlen - self.prefixlen netmask = ((1L << self.prefixlen) - 1) << addrbits netmaskbytes = struct.pack("!L", netmask) return IPAddr(af=AF_INET, addr=netmaskbytes).__str__() class IPv4Prefix(IPPrefix): def __init__(self, prefixstr): IPPrefix.__init__(self, AF_INET, prefixstr) class IPv6Prefix(IPPrefix): def __init__(self, prefixstr): IPPrefix.__init__(self, AF_INET6, prefixstr) def isIPAddress(af, addrstr): try: tmp = socket.inet_pton(af, addrstr) return True except: return False def isIPv4Address(addrstr): return isIPAddress(AF_INET, addrstr) def isIPv6Address(addrstr): return isIPAddress(AF_INET6, addrstr) core-4.8/daemon/core/misc/quagga.py0000664000175000017500000000603412534327775014227 00000000000000# # CORE # Copyright (c)2010-2012 the Boeing Company. # See the LICENSE file included in this distribution. # # author: Tom Goff # ''' quagga.py: helper class for generating Quagga configuration. ''' import os.path from string import Template def maketuple(obj): if hasattr(obj, "__iter__"): return tuple(obj) else: return (obj,) class NetIf(object): def __init__(self, name, addrlist = []): self.name = name self.addrlist = addrlist class Conf(object): def __init__(self, **kwds): self.kwds = kwds def __str__(self): tmp = self.template.substitute(**self.kwds) if tmp[-1] == '\n': tmp = tmp[:-1] return tmp class QuaggaOSPF6Interface(Conf): AF_IPV6_ID = 0 AF_IPV4_ID = 65 template = Template("""\ interface $interface $addr ipv6 ospf6 instance-id $instanceid ipv6 ospf6 hello-interval 2 ipv6 ospf6 dead-interval 11 ipv6 ospf6 retransmit-interval 5 ipv6 ospf6 network $network ipv6 ospf6 diffhellos ipv6 ospf6 adjacencyconnectivity uniconnected ipv6 ospf6 lsafullness mincostlsa """) # ip address $ipaddr/32 # ipv6 ospf6 simhelloLLtoULRecv :$simhelloport # !$ipaddr:$simhelloport def __init__(self, netif, instanceid = AF_IPV4_ID, network = "manet-designated-router", **kwds): self.netif = netif def addrstr(x): if x.find(".") >= 0: return "ip address %s" % x elif x.find(":") >= 0: return "ipv6 address %s" % x else: raise Value, "invalid address: %s", x addr = "\n ".join(map(addrstr, netif.addrlist)) self.instanceid = instanceid self.network = network Conf.__init__(self, interface = netif.name, addr = addr, instanceid = instanceid, network = network, **kwds) def name(self): return self.netif.name class QuaggaOSPF6(Conf): template = Template("""\ $interfaces ! router ospf6 router-id $routerid $ospfifs $redistribute """) def __init__(self, ospf6ifs, area, routerid, redistribute = "! no redistribute"): ospf6ifs = maketuple(ospf6ifs) interfaces = "\n!\n".join(map(str, ospf6ifs)) ospfifs = "\n ".join(map(lambda x: "interface %s area %s" % \ (x.name(), area), ospf6ifs)) Conf.__init__(self, interfaces = interfaces, routerid = routerid, ospfifs = ospfifs, redistribute = redistribute) class QuaggaConf(Conf): template = Template("""\ log file $logfile $debugs ! $routers ! $forwarding """) def __init__(self, routers, logfile, debugs = ()): routers = "\n!\n".join(map(str, maketuple(routers))) if debugs: debugs = "\n".join(maketuple(debugs)) else: debugs = "! no debugs" forwarding = "ip forwarding\nipv6 forwarding" Conf.__init__(self, logfile = logfile, debugs = debugs, routers = routers, forwarding = forwarding) core-4.8/daemon/core/misc/utils.py0000664000175000017500000002033112534327775014116 00000000000000# # CORE # Copyright (c)2010-2012 the Boeing Company. # See the LICENSE file included in this distribution. # # authors: Tom Goff # Jeff Ahrenholz # ''' utils.py: miscellaneous utility functions, wrappers around some subprocess procedures. ''' import subprocess, os, ast def checkexec(execlist): for bin in execlist: if which(bin) is None: raise EnvironmentError, "executable not found: %s" % bin def which(program): ''' From: http://stackoverflow.com/questions/377017/test-if-executable-exists-in-python ''' def is_exe(fpath): return os.path.isfile(fpath) and os.access(fpath, os.X_OK) fpath, fname = os.path.split(program) if fpath: if is_exe(program): return program else: for path in os.environ["PATH"].split(os.pathsep): path = path.strip('"') exe_file = os.path.join(path, program) if is_exe(exe_file): return exe_file return None def ensurepath(pathlist): searchpath = os.environ["PATH"].split(":") for p in set(pathlist): if p not in searchpath: os.environ["PATH"] += ":" + p def maketuple(obj): if hasattr(obj, "__iter__"): return tuple(obj) else: return (obj,) def maketuplefromstr(s, type): s.replace('\\', '\\\\') return ast.literal_eval(s) #return tuple(type(i) for i in s[1:-1].split(',')) #r = () #for i in s.strip("()").split(','): # r += (i.strip("' "), ) # chop empty last element from "('a',)" strings #if r[-1] == '': # r = r[:-1] #return r def call(*args, **kwds): return subprocess.call(*args, **kwds) def mutecall(*args, **kwds): kwds["stdout"] = open(os.devnull, "w") kwds["stderr"] = subprocess.STDOUT return call(*args, **kwds) def check_call(*args, **kwds): return subprocess.check_call(*args, **kwds) def mutecheck_call(*args, **kwds): kwds["stdout"] = open(os.devnull, "w") kwds["stderr"] = subprocess.STDOUT return subprocess.check_call(*args, **kwds) def spawn(*args, **kwds): return subprocess.Popen(*args, **kwds).pid def mutespawn(*args, **kwds): kwds["stdout"] = open(os.devnull, "w") kwds["stderr"] = subprocess.STDOUT return subprocess.Popen(*args, **kwds).pid def detachinit(): if os.fork(): os._exit(0) # parent exits os.setsid() def detach(*args, **kwds): kwds["preexec_fn"] = detachinit return subprocess.Popen(*args, **kwds).pid def mutedetach(*args, **kwds): kwds["preexec_fn"] = detachinit kwds["stdout"] = open(os.devnull, "w") kwds["stderr"] = subprocess.STDOUT return subprocess.Popen(*args, **kwds).pid def cmdresult(args): ''' Execute a command on the host and return a tuple containing the exit status and result string. stderr output is folded into the stdout result string. ''' cmdid = subprocess.Popen(args, stdin = subprocess.PIPE, stdout = subprocess.PIPE, stderr = subprocess.PIPE) cmdid.stdin.close() result = cmdid.stdout.read() result += cmdid.stderr.read() cmdid.stdout.close() cmdid.stderr.close() status = cmdid.wait() return (status, result) def hexdump(s, bytes_per_word = 2, words_per_line = 8): dump = "" count = 0 bytes = bytes_per_word * words_per_line while s: line = s[:bytes] s = s[bytes:] tmp = map(lambda x: ("%02x" * bytes_per_word) % x, zip(*[iter(map(ord, line))] * bytes_per_word)) if len(line) % 2: tmp.append("%x" % ord(line[-1])) dump += "0x%08x: %s\n" % (count, " ".join(tmp)) count += len(line) return dump[:-1] def filemunge(pathname, header, text): ''' Insert text at the end of a file, surrounded by header comments. ''' filedemunge(pathname, header) # prevent duplicates f = open(pathname, 'a') f.write("# BEGIN %s\n" % header) f.write(text) f.write("# END %s\n" % header) f.close() def filedemunge(pathname, header): ''' Remove text that was inserted in a file surrounded by header comments. ''' f = open(pathname, 'r') lines = f.readlines() f.close() start = None end = None for i in range(len(lines)): if lines[i] == "# BEGIN %s\n" % header: start = i elif lines[i] == "# END %s\n" % header: end = i + 1 if start is None or end is None: return f = open(pathname, 'w') lines = lines[:start] + lines[end:] f.write("".join(lines)) f.close() def expandcorepath(pathname, session=None, node=None): ''' Expand a file path given session information. ''' if session is not None: pathname = pathname.replace('~', "/home/%s" % session.user) pathname = pathname.replace('%SESSION%', str(session.sessionid)) pathname = pathname.replace('%SESSION_DIR%', session.sessiondir) pathname = pathname.replace('%SESSION_USER%', session.user) if node is not None: pathname = pathname.replace('%NODE%', str(node.objid)) pathname = pathname.replace('%NODENAME%', node.name) return pathname def sysctldevname(devname): ''' Translate a device name to the name used with sysctl. ''' if devname is None: return None return devname.replace(".", "/") def daemonize(rootdir = "/", umask = 0, close_fds = False, dontclose = (), stdin = os.devnull, stdout = os.devnull, stderr = os.devnull, stdoutmode = 0644, stderrmode = 0644, pidfilename = None, defaultmaxfd = 1024): ''' Run the background process as a daemon. ''' if not hasattr(dontclose, "__contains__"): if not isinstance(dontclose, int): raise TypeError, "dontclose must be an integer" dontclose = (int(dontclose),) else: for fd in dontclose: if not isinstance(fd, int): raise TypeError, "dontclose must contain only integers" # redirect stdin if stdin: fd = os.open(stdin, os.O_RDONLY) os.dup2(fd, 0) os.close(fd) # redirect stdout if stdout: fd = os.open(stdout, os.O_WRONLY | os.O_CREAT | os.O_APPEND, stdoutmode) os.dup2(fd, 1) if (stdout == stderr): os.dup2(1, 2) os.close(fd) # redirect stderr if stderr and (stderr != stdout): fd = os.open(stderr, os.O_WRONLY | os.O_CREAT | os.O_APPEND, stderrmode) os.dup2(fd, 2) os.close(fd) if os.fork(): os._exit(0) # parent exits os.setsid() pid = os.fork() if pid: if pidfilename: try: f = open(pidfilename, "w") f.write("%s\n" % pid) f.close() except: pass os._exit(0) # parent exits if rootdir: os.chdir(rootdir) os.umask(umask) if close_fds: try: maxfd = resource.getrlimit(resource.RLIMIT_NOFILE)[1] if maxfd == resource.RLIM_INFINITY: raise ValueError except: maxfd = defaultmaxfd for fd in xrange(3, maxfd): if fd in dontclose: continue try: os.close(fd) except: pass def readfileintodict(filename, d): ''' Read key=value pairs from a file, into a dict. Skip comments; strip newline characters and spacing. ''' with open(filename, 'r') as f: lines = f.readlines() for l in lines: if l[:1] == '#': continue try: key, value = l.split('=', 1) d[key] = value.strip() except ValueError: pass def checkforkernelmodule(name): ''' Return a string if a Linux kernel module is loaded, None otherwise. The string is the line from /proc/modules containing the module name, memory size (bytes), number of loaded instances, dependencies, state, and kernel memory offset. ''' with open('/proc/modules', 'r') as f: for line in f: if line[:len(name)] == name: return line return None core-4.8/daemon/core/misc/utm.py0000664000175000017500000001631512534327775013572 00000000000000""" utm === .. image:: https://travis-ci.org/Turbo87/utm.png Bidirectional UTM-WGS84 converter for python Usage ----- :: import utm Convert a (latitude, longitude) tuple into an UTM coordinate:: utm.from_latlon(51.2, 7.5) >>> (395201.3103811303, 5673135.241182375, 32, 'U') Convert an UTM coordinate into a (latitude, longitude) tuple:: utm.to_latlon(340000, 5710000, 32, 'U') >>> (51.51852098408468, 6.693872395145327) Speed ----- The library has been compared to the more generic pyproj library by running the unit test suite through pyproj instead of utm. These are the results: * with pyproj (without projection cache): 4.0 - 4.5 sec * with pyproj (with projection cache): 0.9 - 1.0 sec * with utm: 0.4 - 0.5 sec Authors ------- * Tobias Bieniek License ------- Copyright (C) 2012 Tobias Bieniek Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. """ import math __all__ = ['to_latlon', 'from_latlon'] class OutOfRangeError(ValueError): pass K0 = 0.9996 E = 0.00669438 E2 = E * E E3 = E2 * E E_P2 = E / (1.0 - E) SQRT_E = math.sqrt(1 - E) _E = (1 - SQRT_E) / (1 + SQRT_E) _E3 = _E * _E * _E _E4 = _E3 * _E M1 = (1 - E / 4 - 3 * E2 / 64 - 5 * E3 / 256) M2 = (3 * E / 8 + 3 * E2 / 32 + 45 * E3 / 1024) M3 = (15 * E2 / 256 + 45 * E3 / 1024) M4 = (35 * E3 / 3072) P2 = (3 * _E / 2 - 27 * _E3 / 32) P3 = (21 * _E3 / 16 - 55 * _E4 / 32) P4 = (151 * _E3 / 96) R = 6378137 ZONE_LETTERS = [ (84, None), (72, 'X'), (64, 'W'), (56, 'V'), (48, 'U'), (40, 'T'), (32, 'S'), (24, 'R'), (16, 'Q'), (8, 'P'), (0, 'N'), (-8, 'M'), (-16, 'L'), (-24, 'K'), (-32, 'J'), (-40, 'H'), (-48, 'G'), (-56, 'F'), (-64, 'E'), (-72, 'D'), (-80, 'C') ] def to_latlon(easting, northing, zone_number, zone_letter): zone_letter = zone_letter.upper() if not 100000 <= easting < 1000000: raise OutOfRangeError('easting out of range (must be between 100.000 m and 999.999 m)') if not 0 <= northing <= 10000000: raise OutOfRangeError('northing out of range (must be between 0 m and 10.000.000 m)') if not 1 <= zone_number <= 60: raise OutOfRangeError('zone number out of range (must be between 1 and 60)') if not 'C' <= zone_letter <= 'X' or zone_letter in ['I', 'O']: raise OutOfRangeError('zone letter out of range (must be between C and X)') x = easting - 500000 y = northing if zone_letter < 'N': y -= 10000000 m = y / K0 mu = m / (R * M1) p_rad = (mu + P2 * math.sin(2 * mu) + P3 * math.sin(4 * mu) + P4 * math.sin(6 * mu)) p_sin = math.sin(p_rad) p_sin2 = p_sin * p_sin p_cos = math.cos(p_rad) p_tan = p_sin / p_cos p_tan2 = p_tan * p_tan p_tan4 = p_tan2 * p_tan2 ep_sin = 1 - E * p_sin2 ep_sin_sqrt = math.sqrt(1 - E * p_sin2) n = R / ep_sin_sqrt r = (1 - E) / ep_sin c = _E * p_cos**2 c2 = c * c d = x / (n * K0) d2 = d * d d3 = d2 * d d4 = d3 * d d5 = d4 * d d6 = d5 * d latitude = (p_rad - (p_tan / r) * (d2 / 2 - d4 / 24 * (5 + 3 * p_tan2 + 10 * c - 4 * c2 - 9 * E_P2)) + d6 / 720 * (61 + 90 * p_tan2 + 298 * c + 45 * p_tan4 - 252 * E_P2 - 3 * c2)) longitude = (d - d3 / 6 * (1 + 2 * p_tan2 + c) + d5 / 120 * (5 - 2 * c + 28 * p_tan2 - 3 * c2 + 8 * E_P2 + 24 * p_tan4)) / p_cos return (math.degrees(latitude), math.degrees(longitude) + zone_number_to_central_longitude(zone_number)) def from_latlon(latitude, longitude): if not -80.0 <= latitude <= 84.0: raise OutOfRangeError('latitude out of range (must be between 80 deg S and 84 deg N)') if not -180.0 <= longitude <= 180.0: raise OutOfRangeError('northing out of range (must be between 180 deg W and 180 deg E)') lat_rad = math.radians(latitude) lat_sin = math.sin(lat_rad) lat_cos = math.cos(lat_rad) lat_tan = lat_sin / lat_cos lat_tan2 = lat_tan * lat_tan lat_tan4 = lat_tan2 * lat_tan2 lon_rad = math.radians(longitude) zone_number = latlon_to_zone_number(latitude, longitude) central_lon = zone_number_to_central_longitude(zone_number) central_lon_rad = math.radians(central_lon) zone_letter = latitude_to_zone_letter(latitude) n = R / math.sqrt(1 - E * lat_sin**2) c = E_P2 * lat_cos**2 a = lat_cos * (lon_rad - central_lon_rad) a2 = a * a a3 = a2 * a a4 = a3 * a a5 = a4 * a a6 = a5 * a m = R * (M1 * lat_rad - M2 * math.sin(2 * lat_rad) + M3 * math.sin(4 * lat_rad) - M4 * math.sin(6 * lat_rad)) easting = K0 * n * (a + a3 / 6 * (1 - lat_tan2 + c) + a5 / 120 * (5 - 18 * lat_tan2 + lat_tan4 + 72 * c - 58 * E_P2)) + 500000 northing = K0 * (m + n * lat_tan * (a2 / 2 + a4 / 24 * (5 - lat_tan2 + 9 * c + 4 * c**2) + a6 / 720 * (61 - 58 * lat_tan2 + lat_tan4 + 600 * c - 330 * E_P2))) if latitude < 0: northing += 10000000 return easting, northing, zone_number, zone_letter def latitude_to_zone_letter(latitude): for lat_min, zone_letter in ZONE_LETTERS: if latitude >= lat_min: return zone_letter return None def latlon_to_zone_number(latitude, longitude): if 56 <= latitude <= 64 and 3 <= longitude <= 12: return 32 if 72 <= latitude <= 84 and longitude >= 0: if longitude <= 9: return 31 elif longitude <= 21: return 33 elif longitude <= 33: return 35 elif longitude <= 42: return 37 return int((longitude + 180) / 6) + 1 def zone_number_to_central_longitude(zone_number): return (zone_number - 1) * 6 - 180 + 3 def haversine(lon1, lat1, lon2, lat2): """ Calculate the great circle distance between two points on the earth (specified in decimal degrees) """ # convert decimal degrees to radians lon1, lat1, lon2, lat2 = map(math.radians, [lon1, lat1, lon2, lat2]) # haversine formula dlon = lon2 - lon1 dlat = lat2 - lat1 a = math.sin(dlat/2)**2 + math.cos(lat1) * math.cos(lat2) * math.sin(dlon/2)**2 c = 2 * math.asin(math.sqrt(a)) m = 6367000 * c return m core-4.8/daemon/core/misc/xmldeployment.py0000664000175000017500000001475212534327775015671 00000000000000import socket import subprocess import os import xmlutils from core.netns import nodes from core.misc import ipaddr from core import constants class CoreDeploymentWriter(object): def __init__(self, dom, root, session): self.dom = dom self.root = root self.session = session self.hostname = socket.gethostname() if self.session.emane.version < self.session.emane.EMANE092: self.transport = None self.platform = None @staticmethod def get_ipv4_addresses(hostname): if hostname == 'localhost': addr_list = [] cmd = (constants.IP_BIN, '-o', '-f', 'inet', 'addr', 'show') output = subprocess.check_output(cmd) for line in output.split(os.linesep): split = line.split() if not split: continue addr = split[3] if not addr.startswith('127.'): addr_list.append(addr) return addr_list else: # TODO: handle other hosts raise NotImplementedError @staticmethod def find_device(scenario, name): tagName = ('device', 'host', 'router') for d in xmlutils.iterDescendantsWithAttribute(scenario, tagName, 'name', name): return d return None @staticmethod def find_interface(device, name): for i in xmlutils.iterDescendantsWithAttribute(device, 'interface', 'name', name): return i return None def add_deployment(self): testbed = self.dom.createElement('container') testbed.setAttribute('name', 'TestBed') testbed.setAttribute('id', 'TestBed') self.root.baseEle.appendChild(testbed) nodelist = [] for obj in self.session.objs(): if isinstance(obj, nodes.PyCoreNode): nodelist.append(obj) name = self.hostname ipv4_addresses = self.get_ipv4_addresses('localhost') testhost = self.add_physical_host(testbed, name, ipv4_addresses) for n in nodelist: self.add_virtual_host(testhost, n) # TODO: handle other servers # servers = self.session.broker.getserverlist() # servers.remove('localhost') def add_child_element(self, parent, tagName): el = self.dom.createElement(tagName) parent.appendChild(el) return el def add_child_element_with_nameattr(self, parent, tagName, name, setid = True): el = self.add_child_element(parent, tagName) el.setAttribute('name', name) if setid: el.setAttribute('id', '%s/%s' % (parent.getAttribute('id'), name)) return el def add_address(self, parent, address_type, address_str): el = self.add_child_element(parent, 'address') el.setAttribute('type', address_type) el.appendChild(self.dom.createTextNode(address_str)) return el def add_type(self, parent, type_str): el = self.add_child_element(parent, 'type') el.appendChild(self.dom.createTextNode(type_str)) return el def add_platform(self, parent, name): el = self.add_child_element_with_nameattr(parent, 'emanePlatform', name) return el def add_transport(self, parent, name): el = self.add_child_element_with_nameattr(parent, 'transport', name) return el def add_nem(self, parent, name): el = self.add_child_element_with_nameattr(parent, 'nem', name) return el def add_parameter(self, parent, name, val): el = self.add_child_element_with_nameattr(parent, 'parameter', name, False) el.appendChild(self.dom.createTextNode(val)) return el def add_mapping(self, parent, maptype, mapref): el = self.add_child_element(parent, 'mapping') el.setAttribute('type', maptype) el.setAttribute('ref', mapref) return el def add_host(self, parent, name): el = self.add_child_element_with_nameattr(parent, 'testHost', name) return el def add_physical_host(self, parent, name, ipv4_addresses): el = self.add_host(parent, name) self.add_type(el, 'physical') for addr in ipv4_addresses: self.add_address(el, 'IPv4', addr) return el def add_virtual_host(self, parent, obj): assert isinstance(obj, nodes.PyCoreNode) el = self.add_host(parent, obj.name) device = self.find_device(self.root.baseEle, obj.name) self.add_mapping(device, 'testHost', el.getAttribute('id')) self.add_type(el, 'virtual') for netif in obj.netifs(): for address in netif.addrlist: addr, slash, prefixlen= address.partition('/') if ipaddr.isIPv4Address(addr): addr_type = 'IPv4' elif ipaddr.isIPv6Address(addr): addr_type = 'IPv6' else: raise NotImplementedError self.add_address(el, addr_type, address) if isinstance(netif.net, nodes.EmaneNode): nem = self.add_emane_interface(parent, el, netif) interface = self.find_interface(device, netif.name) self.add_mapping(interface, 'nem', nem.getAttribute('id')) return el def add_emane_interface(self, physical_host, virtual_host, netif, platform_name = 'p1', transport_name = 't1'): nemid = netif.net.nemidmap[netif] if self.session.emane.version < self.session.emane.EMANE092: if self.platform is None: self.platform = \ self.add_platform(physical_host, name = platform_name) platform = self.platform if self.transport is None: self.transport = \ self.add_transport(physical_host, name = transport_name) transport = self.transport else: platform = self.add_platform(virtual_host, name = platform_name) transport = self.add_transport(virtual_host, name = transport_name) nem_name = 'nem%s' % nemid nem = self.add_nem(platform, nem_name) self.add_parameter(nem, 'nemid', str(nemid)) self.add_mapping(transport, 'nem', nem.getAttribute('id')) return nem core-4.8/daemon/core/misc/xmlparser.py0000664000175000017500000000321112534327775014771 00000000000000# CORE # Copyright (c) 2014 The Boeing Company. # See the LICENSE file included in this distribution. from xml.dom.minidom import parse from xmlutils import getFirstChildByTagName from xmlparser0 import CoreDocumentParser0 from xmlparser1 import CoreDocumentParser1 class CoreVersionParser(object): DEFAULT_SCENARIO_VERSION = '1.0' '''\ Helper class to check the version of Network Plan document. This simply looks for a "Scenario" element; when present, this indicates a 0.0 version document. The dom member is set in order to prevent parsing a file twice (it can be passed to the appropriate CoreDocumentParser class.) ''' def __init__(self, filename, options={}): if 'dom' in options: self.dom = options['dom'] else: self.dom = parse(filename) scenario = getFirstChildByTagName(self.dom, 'scenario') if scenario: version = scenario.getAttribute('version') if not version: version = self.DEFAULT_SCENARIO_VERSION self.version = version elif getFirstChildByTagName(self.dom, 'Scenario'): self.version = '0.0' else: self.version = 'unknown' def core_document_parser(session, filename, options): vp = CoreVersionParser(filename, options) if 'dom' not in options: options['dom'] = vp.dom if vp.version == '0.0': doc = CoreDocumentParser0(session, filename, options) elif vp.version == '1.0': doc = CoreDocumentParser1(session, filename, options) else: raise ValueError, 'unsupported document version: %s' % vp.version return doc core-4.8/daemon/core/misc/xmlparser0.py0000664000175000017500000004022512534327775015057 00000000000000# # CORE # Copyright (c)2011-2014 the Boeing Company. # See the LICENSE file included in this distribution. # # author: Jeff Ahrenholz # from core.netns import nodes from xml.dom.minidom import parse from xmlutils import * class CoreDocumentParser0(object): def __init__(self, session, filename, options): self.session = session self.verbose = self.session.getcfgitembool('verbose', False) self.filename = filename if 'dom' in options: # this prevents parsing twice when detecting file versions self.dom = options['dom'] else: self.dom = parse(filename) self.start = options['start'] self.nodecls = options['nodecls'] self.np = getoneelement(self.dom, "NetworkPlan") if self.np is None: raise ValueError, "missing NetworkPlan!" self.mp = getoneelement(self.dom, "MotionPlan") self.sp = getoneelement(self.dom, "ServicePlan") self.meta = getoneelement(self.dom, "CoreMetaData") self.coords = self.getmotiondict(self.mp) # link parameters parsed in parsenets(), applied in parsenodes() self.linkparams = {} self.parsedefaultservices() self.parseorigin() self.parsenets() self.parsenodes() self.parseservices() self.parsemeta() def warn(self, msg): if self.session: warnstr = "XML parsing '%s':" % (self.filename) self.session.warn("%s %s" % (warnstr, msg)) def getmotiondict(self, mp): ''' Parse a MotionPlan into a dict with node names for keys and coordinates for values. ''' if mp is None: return {} coords = {} for node in mp.getElementsByTagName("Node"): nodename = str(node.getAttribute("name")) if nodename == '': continue for m in node.getElementsByTagName("motion"): if m.getAttribute("type") != "stationary": continue point = m.getElementsByTagName("point") if len(point) == 0: continue txt = point[0].firstChild if txt is None: continue xyz = map(int, txt.nodeValue.split(',')) z = None x, y = xyz[0:2] if (len(xyz) == 3): z = xyz[2] coords[nodename] = (x, y, z) return coords @staticmethod def getcommonattributes(obj): ''' Helper to return tuple of attributes common to nodes and nets. ''' id = int(obj.getAttribute("id")) name = str(obj.getAttribute("name")) type = str(obj.getAttribute("type")) return(id, name, type) def parsenets(self): linkednets = [] for net in self.np.getElementsByTagName("NetworkDefinition"): id, name, type = self.getcommonattributes(net) nodecls = xmltypetonodeclass(self.session, type) if not nodecls: self.warn("skipping unknown network node '%s' type '%s'" % \ (name, type)) continue n = self.session.addobj(cls = nodecls, objid = id, name = name, start = self.start) if name in self.coords: x, y, z = self.coords[name] n.setposition(x, y, z) getparamssetattrs(net, ("icon", "canvas", "opaque"), n) if hasattr(n, "canvas") and n.canvas is not None: n.canvas = int(n.canvas) # links between two nets (e.g. switch-switch) for ifc in net.getElementsByTagName("interface"): netid = str(ifc.getAttribute("net")) ifcname = str(ifc.getAttribute("name")) linkednets.append((n, netid, ifcname)) self.parsemodels(net, n) # link networks together now that they all have been parsed for (n, netid, ifcname) in linkednets: try: n2 = n.session.objbyname(netid) except KeyError: n.warn("skipping net %s interface: unknown net %s" % \ (n.name, netid)) continue upstream = False netif = n.getlinknetif(n2) if netif is None: netif = n2.linknet(n) else: netif.swapparams('_params_up') upstream = True key = (n2.name, ifcname) if key in self.linkparams: for (k, v) in self.linkparams[key]: netif.setparam(k, v) if upstream: netif.swapparams('_params_up') def parsenodes(self): for node in self.np.getElementsByTagName("Node"): id, name, type = self.getcommonattributes(node) if type == "rj45": nodecls = nodes.RJ45Node else: nodecls = self.nodecls n = self.session.addobj(cls = nodecls, objid = id, name = name, start = self.start) if name in self.coords: x, y, z = self.coords[name] n.setposition(x, y, z) n.type = type getparamssetattrs(node, ("icon", "canvas", "opaque"), n) if hasattr(n, "canvas") and n.canvas is not None: n.canvas = int(n.canvas) for ifc in node.getElementsByTagName("interface"): self.parseinterface(n, ifc) def parseinterface(self, n, ifc): ''' Parse a interface block such as:
00:00:00:aa:00:01
10.0.0.2/24
2001::2/64
''' name = str(ifc.getAttribute("name")) netid = str(ifc.getAttribute("net")) hwaddr = None addrlist = [] try: net = n.session.objbyname(netid) except KeyError: n.warn("skipping node %s interface %s: unknown net %s" % \ (n.name, name, netid)) return for addr in ifc.getElementsByTagName("address"): addrstr = gettextchild(addr) if addrstr is None: continue if addr.getAttribute("type") == "mac": hwaddr = addrstr else: addrlist.append(addrstr) i = n.newnetif(net, addrlist = addrlist, hwaddr = hwaddr, ifindex = None, ifname = name) for model in ifc.getElementsByTagName("model"): self.parsemodel(model, n, n.objid) key = (n.name, name) if key in self.linkparams: netif = n.netif(i) for (k, v) in self.linkparams[key]: netif.setparam(k, v) def parsemodels(self, dom, obj): ''' Mobility/wireless model config is stored in a ConfigurableManager's config dict. ''' nodenum = int(dom.getAttribute("id")) for model in dom.getElementsByTagName("model"): self.parsemodel(model, obj, nodenum) def parsemodel(self, model, obj, nodenum): ''' Mobility/wireless model config is stored in a ConfigurableManager's config dict. ''' name = model.getAttribute("name") if name == '': return type = model.getAttribute("type") # convert child text nodes into key=value pairs kvs = gettextelementstolist(model) mgr = self.session.mobility # TODO: the session.confobj() mechanism could be more generic; # it only allows registering Conf Message callbacks, but here # we want access to the ConfigurableManager, not the callback if name[:5] == "emane": mgr = self.session.emane elif name[:5] == "netem": mgr = None self.parsenetem(model, obj, kvs) elif name[:3] == "xen": mgr = self.session.xen # TODO: assign other config managers here if mgr: mgr.setconfig_keyvalues(nodenum, name, kvs) def parsenetem(self, model, obj, kvs): ''' Determine interface and invoke setparam() using the parsed (key, value) pairs. ''' ifname = model.getAttribute("netif") peer = model.getAttribute("peer") key = (peer, ifname) # nodes and interfaces do not exist yet, at this point of the parsing, # save (key, value) pairs for later try: #kvs = map(lambda(k, v): (int(v)), kvs) kvs = map(self.numericvalue, kvs) except ValueError: self.warn("error parsing link parameters for '%s' on '%s'" % \ (ifname, peer)) self.linkparams[key] = kvs @staticmethod def numericvalue(keyvalue): (key, value) = keyvalue if '.' in str(value): value = float(value) else: value = int(value) return (key, value) def parseorigin(self): ''' Parse any origin tag from the Mobility Plan and set the CoreLocation reference point appropriately. ''' origin = getoneelement(self.mp, "origin") if not origin: return location = self.session.location geo = [] attrs = ("lat","lon","alt") for i in xrange(3): a = origin.getAttribute(attrs[i]) if a is not None: a = float(a) geo.append(a) location.setrefgeo(geo[0], geo[1], geo[2]) scale = origin.getAttribute("scale100") if scale is not None: location.refscale = float(scale) point = getoneelement(origin, "point") if point is not None and point.firstChild is not None: xyz = point.firstChild.nodeValue.split(',') if len(xyz) == 2: xyz.append('0.0') if len(xyz) == 3: xyz = map(lambda(x): float(x), xyz) location.refxyz = (xyz[0], xyz[1], xyz[2]) def parsedefaultservices(self): ''' Prior to parsing nodes, use session.services manager to store default services for node types ''' for node in self.sp.getElementsByTagName("Node"): type = node.getAttribute("type") if type == '': continue # node-specific service config services = [] for service in node.getElementsByTagName("Service"): services.append(str(service.getAttribute("name"))) self.session.services.defaultservices[type] = services self.session.info("default services for type %s set to %s" % \ (type, services)) def parseservices(self): ''' After node objects exist, parse service customizations and add them to the nodes. ''' svclists = {} # parse services and store configs into session.services.configs for node in self.sp.getElementsByTagName("Node"): name = node.getAttribute("name") if name == '': continue # node type without name n = self.session.objbyname(name) if n is None: self.warn("skipping service config for unknown node '%s'" % \ name) continue for service in node.getElementsByTagName("Service"): svcname = service.getAttribute("name") if self.parseservice(service, n): if n.objid in svclists: svclists[n.objid] += "|" + svcname else: svclists[n.objid] = svcname # nodes in NetworkPlan but not in ServicePlan use the # default services for their type for node in self.np.getElementsByTagName("Node"): id, name, type = self.getcommonattributes(node) if id in svclists: continue # custom config exists else: svclists[int(id)] = None # use defaults # associate nodes with services for objid in sorted(svclists.keys()): n = self.session.obj(objid) self.session.services.addservicestonode(node=n, nodetype=n.type, services_str=svclists[objid], verbose=self.verbose) def parseservice(self, service, n): ''' Use session.services manager to store service customizations before they are added to a node. ''' name = service.getAttribute("name") svc = self.session.services.getservicebyname(name) if svc is None: return False values = [] startup_idx = service.getAttribute("startup_idx") if startup_idx is not None: values.append("startidx=%s" % startup_idx) startup_time = service.getAttribute("start_time") if startup_time is not None: values.append("starttime=%s" % startup_time) dirs = [] for dir in service.getElementsByTagName("Directory"): dirname = dir.getAttribute("name") dirs.append(dirname) if len(dirs): values.append("dirs=%s" % dirs) startup = [] shutdown = [] validate = [] for cmd in service.getElementsByTagName("Command"): type = cmd.getAttribute("type") cmdstr = gettextchild(cmd) if cmdstr is None: continue if type == "start": startup.append(cmdstr) elif type == "stop": shutdown.append(cmdstr) elif type == "validate": validate.append(cmdstr) if len(startup): values.append("cmdup=%s" % startup) if len(shutdown): values.append("cmddown=%s" % shutdown) if len(validate): values.append("cmdval=%s" % validate) files = [] for file in service.getElementsByTagName("File"): filename = file.getAttribute("name") files.append(filename) data = gettextchild(file) typestr = "service:%s:%s" % (name, filename) self.session.services.setservicefile(nodenum=n.objid, type=typestr, filename=filename, srcname=None, data=data) if len(files): values.append("files=%s" % files) if not bool(service.getAttribute("custom")): return True self.session.services.setcustomservice(n.objid, svc, values) return True def parsehooks(self, hooks): ''' Parse hook scripts from XML into session._hooks. ''' for hook in hooks.getElementsByTagName("Hook"): filename = hook.getAttribute("name") state = hook.getAttribute("state") data = gettextchild(hook) if data is None: data = "" # allow for empty file type = "hook:%s" % state self.session.sethook(type, filename=filename, srcname=None, data=data) def parsemeta(self): opt = getoneelement(self.meta, "SessionOptions") if opt: for param in opt.getElementsByTagName("param"): k = str(param.getAttribute("name")) v = str(param.getAttribute("value")) if v == '': v = gettextchild(param) # allow attribute/text for newlines setattr(self.session.options, k, v) hooks = getoneelement(self.meta, "Hooks") if hooks: self.parsehooks(hooks) meta = getoneelement(self.meta, "MetaData") if meta: for param in meta.getElementsByTagName("param"): k = str(param.getAttribute("name")) v = str(param.getAttribute("value")) if v == '': v = gettextchild(param) self.session.metadata.additem(k, v) core-4.8/daemon/core/misc/xmlparser1.py0000664000175000017500000011101312534327775015052 00000000000000# # CORE # Copyright (c) 2015 the Boeing Company. # See the LICENSE file included in this distribution. # import sys import random from core.netns import nodes from core import constants from core.misc.ipaddr import MacAddr from xml.dom.minidom import parse from xmlutils import * class CoreDocumentParser1(object): layer2_device_types = 'hub', 'switch' layer3_device_types = 'host', 'router' device_types = layer2_device_types + layer3_device_types # TODO: support CORE interface classes: # RJ45Node # TunnelNode def __init__(self, session, filename, options): self.session = session self.verbose = self.session.getcfgitembool('verbose', False) self.filename = filename if 'dom' in options: # this prevents parsing twice when detecting file versions self.dom = options['dom'] else: self.dom = parse(filename) self.start = options['start'] self.nodecls = options['nodecls'] self.scenario = self.get_scenario(self.dom) self.location_refgeo_set = False self.location_refxyz_set = False # saved link parameters saved when parsing networks and applied later self.link_params = {} # map from id-string to objid, for files having node names but # not node numbers self.objidmap = {} self.objids = set() self.default_services = {} if self.scenario: self.parse_scenario() def info(self, msg): s = 'XML parsing \'%s\': %s' % (self.filename, msg) if self.session: self.session.info(s) else: sys.stdout.write(s + '\n') def warn(self, msg): s = 'WARNING XML parsing \'%s\': %s' % (self.filename, msg) if self.session: self.session.warn(s) else: sys.stderr.write(s + '\n') @staticmethod def get_scenario(dom): scenario = getFirstChildByTagName(dom, 'scenario') if not scenario: raise ValueError, 'no scenario element found' version = scenario.getAttribute('version') if version and version != '1.0': raise ValueError, \ 'unsupported scenario version found: \'%s\'' % version return scenario def parse_scenario(self): self.parse_default_services() self.parse_session_config() self.parse_network_plan() def assign_id(self, idstr, idval): if idstr in self.objidmap: assert self.objidmap[idstr] == idval and idval in self.objids return self.objidmap[idstr] = idval self.objids.add(idval) def rand_id(self): while True: x = random.randint(0, 0xffff) if x not in self.objids: return x def get_id(self, idstr): '''\ Get a, possibly new, object id (node number) corresponding to the given XML string id. ''' if not idstr: idn = self.rand_id() self.objids.add(idn) return idn elif idstr in self.objidmap: return self.objidmap[idstr] else: try: idn = int(idstr) except ValueError: idn = self.rand_id() self.assign_id(idstr, idn) return idn def get_common_attributes(self, node): '''\ Return id, name attributes for the given XML element. These attributes are common to nodes and networks. ''' idstr = node.getAttribute('id') # use an explicit set COREID if it exists coreid = self.find_core_id(node) if coreid: idn = int(coreid) if idstr: self.assign_id(idstr, idn) else: idn = self.get_id(idstr) # TODO: consider supporting unicode; for now convert to an # ascii string namestr = str(node.getAttribute('name')) return idn, namestr def iter_network_member_devices(self, element): # element can be a network or a channel for interface in iterChildrenWithAttribute(element, 'member', 'type', 'interface'): if_id = getChildTextTrim(interface) assert if_id # XXX for testing if not if_id: continue device, if_name = self.find_device_with_interface(if_id) assert device, 'no device for if_id: %s' % if_id # XXX for testing if device: yield device, if_name def network_class(self, network, network_type): '''\ Return the corresponding CORE network class for the given network/network_type. ''' if network_type == 'ethernet': return nodes.PtpNet elif network_type == 'satcom': return nodes.PtpNet elif network_type == 'wireless': channel = getFirstChildByTagName(network, 'channel') if channel: # use an explicit CORE type if it exists coretype = getFirstChildTextTrimWithAttribute(channel, 'type', 'domain', 'CORE') if coretype: if coretype == 'basic_range': return nodes.WlanNode elif coretype.startswith('emane'): return nodes.EmaneNode else: self.warn('unknown network type: \'%s\'' % coretype) return xmltypetonodeclass(self.session, coretype) return nodes.WlanNode self.warn('unknown network type: \'%s\'' % network_type) return None def create_core_object(self, objcls, objid, objname, element, node_type): obj = self.session.addobj(cls = objcls, objid = objid, name = objname, start = self.start) if self.verbose: self.info('added object objid=%s name=%s cls=%s' % \ (objid, objname, objcls)) self.set_object_position(obj, element) self.set_object_presentation(obj, element, node_type) return obj def get_core_object(self, idstr): if idstr and idstr in self.objidmap: objid = self.objidmap[idstr] return self.session.obj(objid) return None def parse_network_plan(self): # parse the scenario in the following order: # 1. layer-2 devices # 2. other networks (ptp/wlan) # 3. layer-3 devices self.parse_layer2_devices() self.parse_networks() self.parse_layer3_devices() def set_ethernet_link_parameters(self, channel, link_params, mobility_model_name, mobility_params): # save link parameters for later use, indexed by the tuple # (device_id, interface_name) for dev, if_name in self.iter_network_member_devices(channel): if self.device_type(dev) in self.device_types: dev_id = dev.getAttribute('id') key = (dev_id, if_name) self.link_params[key] = link_params if mobility_model_name or mobility_params: raise NotImplementedError def set_wireless_link_parameters(self, channel, link_params, mobility_model_name, mobility_params): network = self.find_channel_network(channel) network_id = network.getAttribute('id') if network_id in self.objidmap: nodenum = self.objidmap[network_id] else: self.warn('unknown network: %s' % network.toxml('utf-8')) assert False # XXX for testing return model_name = getFirstChildTextTrimWithAttribute(channel, 'type', 'domain', 'CORE') if not model_name: model_name = 'basic_range' if model_name == 'basic_range': mgr = self.session.mobility elif model_name.startswith('emane'): mgr = self.session.emane elif model_name.startswith('xen'): mgr = self.session.xen else: # TODO: any other config managers? raise NotImplementedError mgr.setconfig_keyvalues(nodenum, model_name, link_params.items()) if mobility_model_name and mobility_params: mgr.setconfig_keyvalues(nodenum, mobility_model_name, mobility_params.items()) def link_layer2_devices(self, device1, ifname1, device2, ifname2): '''\ Link two layer-2 devices together. ''' devid1 = device1.getAttribute('id') dev1 = self.get_core_object(devid1) devid2 = device2.getAttribute('id') dev2 = self.get_core_object(devid2) assert dev1 and dev2 # XXX for testing if dev1 and dev2: # TODO: review this if isinstance(dev2, nodes.RJ45Node): # RJ45 nodes have different linknet() netif = dev2.linknet(dev1) else: netif = dev1.linknet(dev2) self.set_wired_link_parameters(dev1, netif, devid1, ifname1) @classmethod def parse_xml_value(cls, valtext): if not valtext: return None try: if not valtext.translate(None, '0123456789'): val = int(valtext) else: val = float(valtext) except ValueError: val = str(valtext) return val @classmethod def parse_parameter_children(cls, parent): params = {} for parameter in iterChildrenWithName(parent, 'parameter'): param_name = parameter.getAttribute('name') assert param_name # XXX for testing if not param_name: continue # TODO: consider supporting unicode; for now convert # to an ascii string param_name = str(param_name) param_val = cls.parse_xml_value(getChildTextTrim(parameter)) # TODO: check if the name already exists? if param_name and param_val: params[param_name] = param_val return params def parse_network_channel(self, channel): element = self.search_for_element(channel, 'type', lambda x: not x.hasAttributes()) channel_type = getChildTextTrim(element) link_params = self.parse_parameter_children(channel) mobility = getFirstChildByTagName(channel, 'CORE:mobility') if mobility: mobility_model_name = \ getFirstChildTextTrimByTagName(mobility, 'type') mobility_params = self.parse_parameter_children(mobility) else: mobility_model_name = None mobility_params = None if channel_type == 'wireless': self.set_wireless_link_parameters(channel, link_params, mobility_model_name, mobility_params) elif channel_type == 'ethernet': # TODO: maybe this can be done in the loop below to avoid # iterating through channel members multiple times self.set_ethernet_link_parameters(channel, link_params, mobility_model_name, mobility_params) else: raise NotImplementedError layer2_device = [] for dev, if_name in self.iter_network_member_devices(channel): if self.device_type(dev) in self.layer2_device_types: layer2_device.append((dev, if_name)) assert len(layer2_device) <= 2 if len(layer2_device) == 2: self.link_layer2_devices(layer2_device[0][0], layer2_device[0][1], layer2_device[1][0], layer2_device[1][1]) def parse_network(self, network): '''\ Each network element should have an 'id' and 'name' attribute and include the following child elements: type (one) member (zero or more with type="interface" or type="channel") channel (zero or more) ''' layer2_members = set() layer3_members = 0 for dev, if_name in self.iter_network_member_devices(network): if not dev: continue devtype = self.device_type(dev) if devtype in self.layer2_device_types: layer2_members.add(dev) elif devtype in self.layer3_device_types: layer3_members += 1 else: raise NotImplementedError if len(layer2_members) == 0: net_type = getFirstChildTextTrimByTagName(network, 'type') if not net_type: msg = 'no network type found for network: \'%s\'' % \ network.toxml('utf-8') self.warn(msg) assert False # XXX for testing return net_cls = self.network_class(network, net_type) objid, net_name = self.get_common_attributes(network) if self.verbose: self.info('parsing network: %s %s' % (net_name, objid)) if objid in self.session._objs: return n = self.create_core_object(net_cls, objid, net_name, network, None) # handle channel parameters for channel in iterChildrenWithName(network, 'channel'): self.parse_network_channel(channel) def parse_networks(self): '''\ Parse all 'network' elements. ''' for network in iterDescendantsWithName(self.scenario, 'network'): self.parse_network(network) def parse_addresses(self, interface): mac = [] ipv4 = [] ipv6= [] hostname = [] for address in iterChildrenWithName(interface, 'address'): addr_type = address.getAttribute('type') if not addr_type: msg = 'no type attribute found for address ' \ 'in interface: \'%s\'' % interface.toxml('utf-8') self.warn(msg) assert False # XXX for testing continue addr_text = getChildTextTrim(address) if not addr_text: msg = 'no text found for address ' \ 'in interface: \'%s\'' % interface.toxml('utf-8') self.warn(msg) assert False # XXX for testing continue if addr_type == 'mac': mac.append(addr_text) elif addr_type == 'IPv4': ipv4.append(addr_text) elif addr_type == 'IPv6': ipv6.append(addr_text) elif addr_type == 'hostname': hostname.append(addr_text) else: msg = 'skipping unknown address type \'%s\' in ' \ 'interface: \'%s\'' % (addr_type, interface.toxml('utf-8')) self.warn(msg) assert False # XXX for testing continue return mac, ipv4, ipv6, hostname def parse_interface(self, node, device_id, interface): '''\ Each interface can have multiple 'address' elements. ''' if_name = interface.getAttribute('name') network = self.find_interface_network_object(interface) if not network: msg = 'skipping node \'%s\' interface \'%s\': ' \ 'unknown network' % (node.name, if_name) self.warn(msg) assert False # XXX for testing return mac, ipv4, ipv6, hostname = self.parse_addresses(interface) if mac: hwaddr = MacAddr.fromstring(mac[0]) else: hwaddr = None ifindex = node.newnetif(network, addrlist = ipv4 + ipv6, hwaddr = hwaddr, ifindex = None, ifname = if_name) # TODO: 'hostname' addresses are unused if self.verbose: msg = 'node \'%s\' interface \'%s\' connected ' \ 'to network \'%s\'' % (node.name, if_name, network.name) self.info(msg) # set link parameters for wired links if isinstance(network, (nodes.HubNode, nodes.PtpNet, nodes.SwitchNode)): netif = node.netif(ifindex) self.set_wired_link_parameters(network, netif, device_id) def set_wired_link_parameters(self, network, netif, device_id, netif_name = None): if netif_name is None: netif_name = netif.name key = (device_id, netif_name) if key in self.link_params: link_params = self.link_params[key] if self.start: bw = link_params.get('bw') delay = link_params.get('delay') loss = link_params.get('loss') duplicate = link_params.get('duplicate') jitter = link_params.get('jitter') network.linkconfig(netif, bw = bw, delay = delay, loss = loss, duplicate = duplicate, jitter = jitter) else: for k, v in link_params.iteritems(): netif.setparam(k, v) @staticmethod def search_for_element(node, tagName, match = None): '''\ Search the given node and all ancestors for an element named tagName that satisfies the given matching function. ''' while True: for child in iterChildren(node, Node.ELEMENT_NODE): if child.tagName == tagName and \ (match is None or match(child)): return child node = node.parentNode if not node: break return None @classmethod def find_core_id(cls, node): def match(x): domain = x.getAttribute('domain') return domain == 'COREID' alias = cls.search_for_element(node, 'alias', match) if alias: return getChildTextTrim(alias) return None @classmethod def find_point(cls, node): return cls.search_for_element(node, 'point') @staticmethod def find_channel_network(channel): p = channel.parentNode if p and p.tagName == 'network': return p return None def find_interface_network_object(self, interface): network_id = getFirstChildTextTrimWithAttribute(interface, 'member', 'type', 'network') if not network_id: # support legacy notation: # ''' Helpers for loading and saving XML files. savesessionxml(session, filename) is the main public interface here. ''' import os.path from core.netns import nodes from xmlparser import core_document_parser from xmlwriter import core_document_writer def opensessionxml(session, filename, start=False, nodecls=nodes.CoreNode): ''' Import a session from the EmulationScript XML format. ''' options = {'start': start, 'nodecls': nodecls} doc = core_document_parser(session, filename, options) if start: session.name = os.path.basename(filename) session.filename = filename session.node_count = str(session.getnodecount()) session.instantiate() def savesessionxml(session, filename, version): ''' Export a session to the EmulationScript XML format. ''' doc = core_document_writer(session, version) doc.writexml(filename) core-4.8/daemon/core/misc/xmlutils.py0000664000175000017500000002335212534327775014645 00000000000000# # CORE # Copyright (c)2011-2013 the Boeing Company. # See the LICENSE file included in this distribution. # # author: Jeff Ahrenholz # from core.netns import nodes from xml.dom.minidom import Node def addelementsfromlist(dom, parent, iterable, name, attr_name): ''' XML helper to iterate through a list and add items to parent using tags of the given name and the item value as an attribute named attr_name. Example: addelementsfromlist(dom, parent, ('a','b','c'), "letter", "value") ''' for item in iterable: element = dom.createElement(name) element.setAttribute(attr_name, item) parent.appendChild(element) def addtextelementsfromlist(dom, parent, iterable, name, attrs): ''' XML helper to iterate through a list and add items to parent using tags of the given name, attributes specified in the attrs tuple, and having the text of the item within the tags. Example: addtextelementsfromlist(dom, parent, ('a','b','c'), "letter", (('show','True'),)) a b c ''' for item in iterable: element = dom.createElement(name) for k,v in attrs: element.setAttribute(k, v) parent.appendChild(element) txt = dom.createTextNode(item) element.appendChild(txt) def addtextelementsfromtuples(dom, parent, iterable, attrs=()): ''' XML helper to iterate through a list of tuples and add items to parent using tags named for the first tuple element, attributes specified in the attrs tuple, and having the text of second tuple element. Example: addtextelementsfromtuples(dom, parent, (('first','a'),('second','b'),('third','c')), (('show','True'),)) a b c ''' for name, value in iterable: element = dom.createElement(name) for k,v in attrs: element.setAttribute(k, v) parent.appendChild(element) txt = dom.createTextNode(value) element.appendChild(txt) def gettextelementstolist(parent): ''' XML helper to parse child text nodes from the given parent and return a list of (key, value) tuples. ''' r = [] for n in parent.childNodes: if n.nodeType != Node.ELEMENT_NODE: continue k = str(n.nodeName) v = '' # sometimes want None here? for c in n.childNodes: if c.nodeType != Node.TEXT_NODE: continue v = str(c.nodeValue) break r.append((k,v)) return r def addparamtoparent(dom, parent, name, value): ''' XML helper to add a tag to the parent element, when value is not None. ''' if value is None: return None p = dom.createElement("param") parent.appendChild(p) p.setAttribute("name", name) p.setAttribute("value", "%s" % value) return p def addtextparamtoparent(dom, parent, name, value): ''' XML helper to add a value tag to the parent element, when value is not None. ''' if value is None: return None p = dom.createElement("param") parent.appendChild(p) p.setAttribute("name", name) txt = dom.createTextNode(value) p.appendChild(txt) return p def addparamlisttoparent(dom, parent, name, values): ''' XML helper to return a parameter list and optionally add it to the parent element: ''' if values is None: return None p = dom.createElement("paramlist") if parent: parent.appendChild(p) p.setAttribute("name", name) for v in values: item = dom.createElement("item") item.setAttribute("value", str(v)) p.appendChild(item) return p def getoneelement(dom, name): e = dom.getElementsByTagName(name) if len(e) == 0: return None return e[0] def iterDescendants(dom, max_depth = 0): '''\ Iterate over all descendant element nodes in breadth first order. Only consider nodes up to max_depth deep when max_depth is greater than zero. ''' nodes = [dom] depth = 0 current_depth_nodes = 1 next_depth_nodes = 0 while nodes: n = nodes.pop(0) for child in n.childNodes: if child.nodeType == Node.ELEMENT_NODE: yield child nodes.append(child) next_depth_nodes += 1 current_depth_nodes -= 1 if current_depth_nodes == 0: depth += 1 if max_depth > 0 and depth == max_depth: return current_depth_nodes = next_depth_nodes next_depth_nodes = 0 def iterMatchingDescendants(dom, matchFunction, max_depth = 0): '''\ Iterate over descendant elements where matchFunction(descendant) returns true. Only consider nodes up to max_depth deep when max_depth is greater than zero. ''' for d in iterDescendants(dom, max_depth): if matchFunction(d): yield d def iterDescendantsWithName(dom, tagName, max_depth = 0): '''\ Iterate over descendant elements whose name is contained in tagName (or is named tagName if tagName is a string). Only consider nodes up to max_depth deep when max_depth is greater than zero. ''' if isinstance(tagName, basestring): tagName = (tagName,) def match(d): return d.tagName in tagName return iterMatchingDescendants(dom, match, max_depth) def iterDescendantsWithAttribute(dom, tagName, attrName, attrValue, max_depth = 0): '''\ Iterate over descendant elements whose name is contained in tagName (or is named tagName if tagName is a string) and have an attribute named attrName with value attrValue. Only consider nodes up to max_depth deep when max_depth is greater than zero. ''' if isinstance(tagName, basestring): tagName = (tagName,) def match(d): return d.tagName in tagName and \ d.getAttribute(attrName) == attrValue return iterMatchingDescendants(dom, match, max_depth) def iterChildren(dom, nodeType): '''\ Iterate over all child elements of the given type. ''' for child in dom.childNodes: if child.nodeType == nodeType: yield child def gettextchild(dom): '''\ Return the text node of the given element. ''' for child in iterChildren(dom, Node.TEXT_NODE): return str(child.nodeValue) return None def getChildTextTrim(dom): text = gettextchild(dom) if text: text = text.strip() return text def getparamssetattrs(dom, param_names, target): ''' XML helper to get tags and set the attribute in the target object. String type is used. Target object attribute is unchanged if the XML attribute is not present. ''' params = dom.getElementsByTagName("param") for param in params: param_name = param.getAttribute("name") value = param.getAttribute("value") if value is None: continue # never reached? if param_name in param_names: setattr(target, param_name, str(value)) def xmltypetonodeclass(session, type): ''' Helper to convert from a type string to a class name in nodes.*. ''' if hasattr(nodes, type): return eval("nodes.%s" % type) else: return None def iterChildrenWithName(dom, tagName): return iterDescendantsWithName(dom, tagName, 1) def iterChildrenWithAttribute(dom, tagName, attrName, attrValue): return iterDescendantsWithAttribute(dom, tagName, attrName, attrValue, 1) def getFirstChildByTagName(dom, tagName): '''\ Return the first child element whose name is contained in tagName (or is named tagName if tagName is a string). ''' for child in iterChildrenWithName(dom, tagName): return child return None def getFirstChildTextByTagName(dom, tagName): '''\ Return the corresponding text of the first child element whose name is contained in tagName (or is named tagName if tagName is a string). ''' child = getFirstChildByTagName(dom, tagName) if child: return gettextchild(child) return None def getFirstChildTextTrimByTagName(dom, tagName): text = getFirstChildTextByTagName(dom, tagName) if text: text = text.strip() return text def getFirstChildWithAttribute(dom, tagName, attrName, attrValue): '''\ Return the first child element whose name is contained in tagName (or is named tagName if tagName is a string) that has an attribute named attrName with value attrValue. ''' for child in \ iterChildrenWithAttribute(dom, tagName, attrName, attrValue): return child return None def getFirstChildTextWithAttribute(dom, tagName, attrName, attrValue): '''\ Return the corresponding text of the first child element whose name is contained in tagName (or is named tagName if tagName is a string) that has an attribute named attrName with value attrValue. ''' child = getFirstChildWithAttribute(dom, tagName, attrName, attrValue) if child: return gettextchild(child) return None def getFirstChildTextTrimWithAttribute(dom, tagName, attrName, attrValue): text = getFirstChildTextWithAttribute(dom, tagName, attrName, attrValue) if text: text = text.strip() return text core-4.8/daemon/core/misc/xmlwriter.py0000664000175000017500000000072412534327775015017 00000000000000# CORE # Copyright (c) 2015 The Boeing Company. # See the LICENSE file included in this distribution. from xmlwriter0 import CoreDocumentWriter0 from xmlwriter1 import CoreDocumentWriter1 def core_document_writer(session, version): if version == '0.0': doc = CoreDocumentWriter0(session) elif version == '1.0': doc = CoreDocumentWriter1(session) else: raise ValueError, 'unsupported document version: %s' % version return doc core-4.8/daemon/core/misc/xmlwriter0.py0000664000175000017500000003511112534327775015075 00000000000000# # CORE # Copyright (c)2011-2013 the Boeing Company. # See the LICENSE file included in this distribution. # # author: Jeff Ahrenholz # import os import pwd from core.netns import nodes from core.api import coreapi from xml.dom.minidom import Document from xmlutils import * class CoreDocumentWriter0(Document): ''' Utility class for writing a CoreSession to XML. The init method builds an xml.dom.minidom.Document, and the writexml() method saves the XML file. ''' def __init__(self, session): ''' Create an empty Scenario XML Document, then populate it with objects from the given session. ''' Document.__init__(self) self.session = session self.scenario = self.createElement("Scenario") self.np = self.createElement("NetworkPlan") self.mp = self.createElement("MotionPlan") self.sp = self.createElement("ServicePlan") self.meta = self.createElement("CoreMetaData") self.appendChild(self.scenario) self.scenario.appendChild(self.np) self.scenario.appendChild(self.mp) self.scenario.appendChild(self.sp) self.scenario.appendChild(self.meta) self.populatefromsession() def populatefromsession(self): self.session.emane.setup() # not during runtime? self.addorigin() self.adddefaultservices() self.addnets() self.addnodes() self.addmetadata() def writexml(self, filename): self.session.info("saving session XML file %s" % filename) f = open(filename, "w") Document.writexml(self, writer=f, indent="", addindent=" ", newl="\n", \ encoding="UTF-8") f.close() if self.session.user is not None: uid = pwd.getpwnam(self.session.user).pw_uid gid = os.stat(self.session.sessiondir).st_gid os.chown(filename, uid, gid) def addnets(self): ''' Add PyCoreNet objects as NetworkDefinition XML elements. ''' with self.session._objslock: for net in self.session.objs(): if not isinstance(net, nodes.PyCoreNet): continue self.addnet(net) def addnet(self, net): ''' Add one PyCoreNet object as a NetworkDefinition XML element. ''' n = self.createElement("NetworkDefinition") self.np.appendChild(n) n.setAttribute("name", net.name) # could use net.brname n.setAttribute("id", "%s" % net.objid) n.setAttribute("type", "%s" % net.__class__.__name__) self.addnetinterfaces(n, net) # key used with tunnel node if hasattr(net, 'grekey') and net.grekey is not None: n.setAttribute("key", "%s" % net.grekey) # link parameters for netif in net.netifs(sort=True): self.addnetem(n, netif) # wireless/mobility models modelconfigs = net.session.mobility.getmodels(net) modelconfigs += net.session.emane.getmodels(net) self.addmodels(n, modelconfigs) self.addposition(net) def addnetem(self, n, netif): ''' Similar to addmodels(); used for writing netem link effects parameters. TODO: Interface parameters should be moved to the model construct, then this separate method shouldn't be required. ''' params = netif.getparams() if len(params) == 0: return model = self.createElement("model") model.setAttribute("name", "netem") model.setAttribute("netif", netif.name) if hasattr(netif, "node") and netif.node is not None: model.setAttribute("peer", netif.node.name) # link between switches uses one veth interface elif hasattr(netif, "othernet") and netif.othernet is not None: if netif.othernet.name == n.getAttribute("name"): model.setAttribute("peer", netif.net.name) else: model.setAttribute("peer", netif.othernet.name) model.setAttribute("netif", netif.localname) # hack used for upstream parameters for link between switches # (see LxBrNet.linknet()) if netif.othernet.objid == int(n.getAttribute("id")): netif.swapparams('_params_up') params = netif.getparams() netif.swapparams('_params_up') has_params = False for k, v in params: # default netem parameters are 0 or None if v is None or v == 0: continue if k == "has_netem" or k == "has_tbf": continue key = self.createElement(k) key.appendChild(self.createTextNode("%s" % v)) model.appendChild(key) has_params = True if has_params: n.appendChild(model) def addmodels(self, n, configs): ''' Add models from a list of model-class, config values tuples. ''' for (m, conf) in configs: model = self.createElement("model") n.appendChild(model) model.setAttribute("name", m._name) type = "wireless" if m._type == coreapi.CORE_TLV_REG_MOBILITY: type = "mobility" model.setAttribute("type", type) for i, k in enumerate(m.getnames()): key = self.createElement(k) value = conf[i] if value is None: value = "" key.appendChild(self.createTextNode("%s" % value)) model.appendChild(key) def addnodes(self): ''' Add PyCoreNode objects as node XML elements. ''' with self.session._objslock: for node in self.session.objs(): if not isinstance(node, nodes.PyCoreNode): continue self.addnode(node) def addnode(self, node): ''' Add a PyCoreNode object as node XML elements. ''' n = self.createElement("Node") self.np.appendChild(n) n.setAttribute("name", node.name) n.setAttribute("id", "%s" % node.nodeid()) if node.type: n.setAttribute("type", node.type) self.addinterfaces(n, node) self.addposition(node) addparamtoparent(self, n, "icon", node.icon) addparamtoparent(self, n, "canvas", node.canvas) self.addservices(node) def addinterfaces(self, n, node): ''' Add PyCoreNetIfs to node XML elements. ''' for ifc in node.netifs(sort=True): i = self.createElement("interface") n.appendChild(i) i.setAttribute("name", ifc.name) netmodel = None if ifc.net: i.setAttribute("net", ifc.net.name) if hasattr(ifc.net, "model"): netmodel = ifc.net.model if ifc.mtu and ifc.mtu != 1500: i.setAttribute("mtu", "%s" % ifc.mtu) # could use ifc.params, transport_type self.addaddresses(i, ifc) # per-interface models if netmodel and netmodel._name[:6] == "emane_": cfg = self.session.emane.getifcconfig(node.objid, netmodel._name, None, ifc) if cfg: self.addmodels(i, ((netmodel, cfg),) ) def addnetinterfaces(self, n, net): ''' Similar to addinterfaces(), but only adds interface elements to the supplied XML node that would not otherwise appear in the Node elements. These are any interfaces that link two switches/hubs together. ''' for ifc in net.netifs(sort=True): if not hasattr(ifc, "othernet") or not ifc.othernet: continue i = self.createElement("interface") n.appendChild(i) if net.objid == ifc.net.objid: i.setAttribute("name", ifc.localname) i.setAttribute("net", ifc.othernet.name) else: i.setAttribute("name", ifc.name) i.setAttribute("net", ifc.net.name) def addposition(self, node): ''' Add object coordinates as location XML element. ''' (x,y,z) = node.position.get() if x is None or y is None: return # mpn = self.createElement("Node") mpn.setAttribute("name", node.name) self.mp.appendChild(mpn) # motion = self.createElement("motion") motion.setAttribute("type", "stationary") mpn.appendChild(motion) # $X$,$Y$,$Z$ pt = self.createElement("point") motion.appendChild(pt) coordstxt = "%s,%s" % (x,y) if z: coordstxt += ",%s" % z coords = self.createTextNode(coordstxt) pt.appendChild(coords) def addorigin(self): ''' Add origin to Motion Plan using canvas reference point. The CoreLocation class maintains this reference point. ''' refgeo = self.session.location.refgeo origin = self.createElement("origin") attrs = ("lat","lon","alt") have_origin = False for i in xrange(3): if refgeo[i] is not None: origin.setAttribute(attrs[i], str(refgeo[i])) have_origin = True if not have_origin: return if self.session.location.refscale != 1.0: # 100 pixels = refscale m origin.setAttribute("scale100", str(self.session.location.refscale)) if self.session.location.refxyz != (0.0, 0.0, 0.0): pt = self.createElement("point") origin.appendChild(pt) x,y,z = self.session.location.refxyz coordstxt = "%s,%s" % (x,y) if z: coordstxt += ",%s" % z coords = self.createTextNode(coordstxt) pt.appendChild(coords) self.mp.appendChild(origin) def adddefaultservices(self): ''' Add default services and node types to the ServicePlan. ''' for type in self.session.services.defaultservices: defaults = self.session.services.getdefaultservices(type) spn = self.createElement("Node") spn.setAttribute("type", type) self.sp.appendChild(spn) for svc in defaults: s = self.createElement("Service") spn.appendChild(s) s.setAttribute("name", str(svc._name)) def addservices(self, node): ''' Add services and their customizations to the ServicePlan. ''' if len(node.services) == 0: return defaults = self.session.services.getdefaultservices(node.type) if node.services == defaults: return spn = self.createElement("Node") spn.setAttribute("name", node.name) self.sp.appendChild(spn) for svc in node.services: s = self.createElement("Service") spn.appendChild(s) s.setAttribute("name", str(svc._name)) s.setAttribute("startup_idx", str(svc._startindex)) if svc._starttime != "": s.setAttribute("start_time", str(svc._starttime)) # only record service names if not a customized service if not svc._custom: continue s.setAttribute("custom", str(svc._custom)) addelementsfromlist(self, s, svc._dirs, "Directory", "name") for fn in svc._configs: if len(fn) == 0: continue f = self.createElement("File") f.setAttribute("name", fn) # all file names are added to determine when a file has been deleted s.appendChild(f) data = self.session.services.getservicefiledata(svc, fn) if data is None: # this includes only customized file contents and skips # the auto-generated files continue txt = self.createTextNode(data) f.appendChild(txt) addtextelementsfromlist(self, s, svc._startup, "Command", (("type","start"),)) addtextelementsfromlist(self, s, svc._shutdown, "Command", (("type","stop"),)) addtextelementsfromlist(self, s, svc._validate, "Command", (("type","validate"),)) def addaddresses(self, i, netif): ''' Add MAC and IP addresses to interface XML elements. ''' if netif.hwaddr: h = self.createElement("address") i.appendChild(h) h.setAttribute("type", "mac") htxt = self.createTextNode("%s" % netif.hwaddr) h.appendChild(htxt) for addr in netif.addrlist: a = self.createElement("address") i.appendChild(a) # a.setAttribute("type", ) atxt = self.createTextNode("%s" % addr) a.appendChild(atxt) def addhooks(self): ''' Add hook script XML elements to the metadata tag. ''' hooks = self.createElement("Hooks") for state in sorted(self.session._hooks.keys()): for (filename, data) in self.session._hooks[state]: hook = self.createElement("Hook") hook.setAttribute("name", filename) hook.setAttribute("state", str(state)) txt = self.createTextNode(data) hook.appendChild(txt) hooks.appendChild(hook) if hooks.hasChildNodes(): self.meta.appendChild(hooks) def addmetadata(self): ''' Add CORE-specific session meta-data XML elements. ''' # options options = self.createElement("SessionOptions") defaults = self.session.options.getdefaultvalues() for i, (k, v) in enumerate(self.session.options.getkeyvaluelist()): if str(v) != str(defaults[i]): addtextparamtoparent(self, options, k, v) #addparamtoparent(self, options, k, v) if options.hasChildNodes(): self.meta.appendChild(options) # hook scripts self.addhooks() # meta meta = self.createElement("MetaData") self.meta.appendChild(meta) for (k, v) in self.session.metadata.items(): addtextparamtoparent(self, meta, k, v) #addparamtoparent(self, meta, k, v) core-4.8/daemon/core/misc/xmlwriter1.py0000664000175000017500000011145312534327775015102 00000000000000# # CORE # Copyright (c)2011-2015 the Boeing Company. # See the LICENSE file included in this distribution. # # Created on Dec 18, 2014 # # @author: santiago # import os import pwd import collections from core.netns import nodes from core.api import coreapi from core.misc.ipaddr import * from xml.dom.minidom import Document from xmlutils import * from xmldeployment import CoreDeploymentWriter def enum(**enums): return type('Enum', (), enums) class Attrib(object): ''' scenario plan attribute constants ''' NetType = enum(WIRELESS = 'wireless', ETHERNET = 'ethernet', PTP_WIRED = 'point-to-point-wired', PTP_WIRELESS = 'point-to-point-wireless') MembType = enum(INTERFACE = 'interface', CHANNEL = 'channel', SWITCH = 'switch', HUB = 'hub', TUNNEL = 'tunnel', NETWORK = "network") DevType = enum(HOST = 'host', ROUTER = 'router', SWITCH = 'switch', HUB = 'hub') NodeType = enum(ROUTER = 'router', HOST = 'host', MDR = 'mdr', PC = 'PC', RJ45 = 'rj45') Alias = enum(ID = "COREID") ''' A link endpoint in CORE net: the network that the endpoint belongs to netif: the network interface at this end id: the identifier for the endpoint l2devport: if the other end is a layer 2 device, this is the assigned port in that device params: link/interface parameters ''' Endpoint = collections.namedtuple('Endpoint', ['net', 'netif', 'type', 'id', 'l2devport', 'params']) class CoreDocumentWriter1(Document): ''' Utility class for writing a CoreSession to XML in the NMF scenPlan schema. The init method builds an xml.dom.minidom.Document, and the writexml() method saves the XML file. ''' def __init__(self, session): ''' Create an empty Scenario XML Document, then populate it with objects from the given session. ''' Document.__init__(self) session.info('Exporting to NMF XML version 1.0') with session._objslock: self.scenarioPlan = ScenarioPlan(self, session) if session.getstate() == coreapi.CORE_EVENT_RUNTIME_STATE: deployment = CoreDeploymentWriter(self, self.scenarioPlan, session) deployment.add_deployment() self.scenarioPlan.setAttribute('deployed', 'true') def writexml(self, filename): ''' Commit to file ''' self.scenarioPlan.coreSession.info("saving session XML file %s" % filename) f = open(filename, "w") Document.writexml(self, writer=f, indent="", addindent=" ", newl="\n", \ encoding="UTF-8") f.close() if self.scenarioPlan.coreSession.user is not None: uid = pwd.getpwnam(self.scenarioPlan.coreSession.user).pw_uid gid = os.stat(self.scenarioPlan.coreSession.sessiondir).st_gid os.chown(filename, uid, gid) class XmlElement(object): ''' The base class for all XML elements in the scenario plan. Includes convenience functions. ''' def __init__(self, document, parent, elementType): self.document = document self.parent = parent self.baseEle = document.createElement("%s" % elementType) if self.parent is not None: self.parent.appendChild(self.baseEle) def createElement(self, elementTag): return self.document.createElement(elementTag) def getTagName(self): return self.baseEle.tagName def createTextNode(self, nodeTag): return self.document.createTextNode(nodeTag) def appendChild(self, child): if isinstance(child, XmlElement): self.baseEle.appendChild(child.baseEle) else: self.baseEle.appendChild(child) @staticmethod def add_parameter(doc, parent, key, value): if key and value: parm = doc.createElement("parameter") parm.setAttribute("name", str(key)) parm.appendChild(doc.createTextNode(str(value))) parent.appendChild(parm) def addParameter(self, key, value): ''' Add a parameter to the xml element ''' self.add_parameter(self.document, self, key, value) def setAttribute(self, name, val): self.baseEle.setAttribute(name, val) def getAttribute(self, name): return self.baseEle.getAttribute(name) class NamedXmlElement(XmlElement): ''' The base class for all "named" xml elements. Named elements are xml elements in the scenario plan that have an id and a name attribute. ''' def __init__(self, scenPlan, parent, elementType, elementName): XmlElement.__init__(self, scenPlan.document, parent, elementType) self.scenPlan = scenPlan self.coreSession = scenPlan.coreSession elementPath = '' self.id=None if self.parent is not None and isinstance(self.parent, XmlElement) and self.parent.getTagName() != "scenario": elementPath="%s/" % self.parent.getAttribute("id") self.id = "%s%s" % (elementPath,elementName) self.setAttribute("name", elementName) self.setAttribute("id", self.id) def addPoint(self, coreObj): ''' Add position to an object ''' (x,y,z) = coreObj.position.get() if x is None or y is None: return lat, lon, alt = self.coreSession.location.getgeo(x, y, z) pt = self.createElement("point") pt.setAttribute("type", "gps") pt.setAttribute("lat", "%s" % lat) pt.setAttribute("lon", "%s" % lon) if z: pt.setAttribute("z", "%s" % alt) self.appendChild(pt) def createAlias(self, domain, valueStr): ''' Create an alias element for CORE specific information ''' a = self.createElement("alias") a.setAttribute("domain", "%s" % domain) a.appendChild(self.createTextNode(valueStr)) return a class ScenarioPlan(XmlElement): ''' Container class for ScenarioPlan. ''' def __init__(self, document, session): XmlElement.__init__(self, document, parent=document, elementType='scenario') self.coreSession = session self.setAttribute('version', '1.0') self.setAttribute("name", "%s" % session.name) self.setAttribute('xmlns', 'nmfPlan') self.setAttribute('xmlns:CORE', 'coreSpecific') self.setAttribute('compiled', 'true') self.allChannelMembers = dict() self.lastNetIdx = 0 self.addNetworks() self.addDevices() # XXX Do we need these? #self.session.emane.setup() # not during runtime? #self.addorigin() self.addDefaultServices() self.addSessionConfiguration() def addNetworks(self): ''' Add networks in the session to the scenPlan. ''' for net in self.coreSession.objs(): if not isinstance(net, nodes.PyCoreNet): continue if isinstance(net, nodes.CtrlNet): continue # Do not add switches and hubs that belong to another network if isinstance(net, (nodes.SwitchNode, nodes.HubNode)): if inOtherNetwork(net): continue try: NetworkElement(self, self, net) except: if hasattr(net, "name") and net.name: self.coreSession.warn('Unsupported net: %s' % net.name) else: self.coreSession.warn('Unsupported net: %s' % net.__class__.__name__) def addDevices(self): ''' Add device elements to the scenario plan. ''' for node in self.coreSession.objs(): if not isinstance(node, (nodes.PyCoreNode)): continue try: DeviceElement(self, self, node) except: if hasattr(node, "name") and node.name: self.coreSession.warn('Unsupported device: %s' % node.name) else: self.coreSession.warn('Unsupported device: %s' % node.__class__.__name__) def addDefaultServices(self): ''' Add default services and node types to the ServicePlan. ''' defaultservices = self.createElement("CORE:defaultservices") for type in self.coreSession.services.defaultservices: defaults = self.coreSession.services.getdefaultservices(type) spn = self.createElement("device") spn.setAttribute("type", type) defaultservices.appendChild(spn) for svc in defaults: s = self.createElement("service") spn.appendChild(s) s.setAttribute("name", str(svc._name)) if defaultservices.hasChildNodes(): self.appendChild(defaultservices) def addSessionConfiguration(self): ''' Add CORE-specific session configuration XML elements. ''' config = self.createElement("CORE:sessionconfig") # origin: geolocation of cartesian coordinate 0,0,0 refgeo = self.coreSession.location.refgeo origin = self.createElement("origin") attrs = ("lat","lon","alt") have_origin = False for i in xrange(3): if refgeo[i] is not None: origin.setAttribute(attrs[i], str(refgeo[i])) have_origin = True if have_origin: if self.coreSession.location.refscale != 1.0: # 100 pixels = refscale m origin.setAttribute("scale100", str(self.coreSession.location.refscale)) if self.coreSession.location.refxyz != (0.0, 0.0, 0.0): pt = self.createElement("point") origin.appendChild(pt) x,y,z = self.coreSession.location.refxyz coordstxt = "%s,%s" % (x,y) if z: coordstxt += ",%s" % z coords = self.createTextNode(coordstxt) pt.appendChild(coords) config.appendChild(origin) # options options = self.createElement("options") defaults = self.coreSession.options.getdefaultvalues() for i, (k, v) in enumerate(self.coreSession.options.getkeyvaluelist()): if str(v) != str(defaults[i]): XmlElement.add_parameter(self.document, options, k, v) if options.hasChildNodes(): config.appendChild(options) # hook scripts hooks = self.createElement("hooks") for state in sorted(self.coreSession._hooks.keys()): for (filename, data) in self.coreSession._hooks[state]: hook = self.createElement("hook") hook.setAttribute("name", filename) hook.setAttribute("state", str(state)) txt = self.createTextNode(data) hook.appendChild(txt) hooks.appendChild(hook) if hooks.hasChildNodes(): config.appendChild(hooks) # metadata meta = self.createElement("metadata") for (k, v) in self.coreSession.metadata.items(): XmlElement.add_parameter(self.document, meta, k, v) if meta.hasChildNodes(): config.appendChild(meta) if config.hasChildNodes(): self.appendChild(config) class NetworkElement(NamedXmlElement): def __init__(self, scenPlan, parent, netObj): ''' Add one PyCoreNet object as one network XML element. ''' elementName = self.getNetworkName(scenPlan, netObj) NamedXmlElement.__init__(self, scenPlan, parent, "network", elementName) self.scenPlan = scenPlan self.addPoint(netObj) netType = None if isinstance(netObj, (nodes.WlanNode, nodes.EmaneNode)): netType = Attrib.NetType.WIRELESS elif isinstance(netObj, (nodes.SwitchNode, nodes.HubNode, nodes.PtpNet, nodes.TunnelNode)): netType = Attrib.NetType.ETHERNET else: netType ="%s" % netObj.__class__.__name__ typeEle = self.createElement("type") typeEle.appendChild(self.createTextNode(netType)) self.appendChild(typeEle) # Gather all endpoints belonging to this network self.endpoints = getEndpoints(netObj) # Special case for a network of switches and hubs createAlias = True self.l2devices = [] if isinstance(netObj, (nodes.SwitchNode, nodes.HubNode)): createAlias = False self.appendChild(typeEle) self.addL2Devices(netObj) if createAlias: a = self.createAlias(Attrib.Alias.ID, "%d" % int(netObj.objid)) self.appendChild(a) # XXXX TODO: Move this to channel? # key used with tunnel node if hasattr(netObj, 'grekey') and netObj.grekey is not None: a = self.createAlias("COREGREKEY", "%s" % netObj.grekey) self.appendChild(a) self.addNetMembers(netObj) self.addChannels(netObj) presentationEle = self.createElement("CORE:presentation") addPresentationEle = False if netObj.icon and not netObj.icon.isspace(): presentationEle.setAttribute("icon", netObj.icon) addPresentationEle = True if netObj.canvas: presentationEle.setAttribute("canvas", str(netObj.canvas)) addPresentationEle = True if addPresentationEle: self.appendChild(presentationEle) def getNetworkName(self, scenPlan, netObj): ''' Determine the name to use for this network element ''' if isinstance(netObj, (nodes.PtpNet, nodes.TunnelNode)): name = "net%s" % scenPlan.lastNetIdx scenPlan.lastNetIdx += 1 elif netObj.name: name = str(netObj.name) # could use net.brname for bridges? elif isinstance(netObj, (nodes.SwitchNode, nodes.HubNode)): name = "lan%s" % netObj.objid else: name = '' return name def addL2Devices(self, netObj): ''' Add switches and hubs ''' # Add the netObj as a device self.l2devices.append(DeviceElement(self.scenPlan, self, netObj)) # Add downstream switches/hubs l2devs = [] neweps = [] for ep in self.endpoints: if ep.type and ep.net.objid != netObj.objid: l2s, eps = getDowmstreamL2Devices(ep.net) l2devs.extend(l2s) neweps.extend(eps) for l2dev in l2devs: self.l2devices.append(DeviceElement(self.scenPlan, self, l2dev)) self.endpoints.extend(neweps) # XXX: Optimize later def addNetMembers(self, netObj): ''' Add members to a network XML element. ''' for ep in self.endpoints: if ep.type: MemberElement(self.scenPlan, self, referencedType=ep.type, referencedId=ep.id) if ep.l2devport: MemberElement(self.scenPlan, self, referencedType=Attrib.MembType.INTERFACE, referencedId="%s/%s" % (self.id,ep.l2devport)) # XXX Revisit this # Create implied members given the network type if isinstance(netObj, nodes.TunnelNode): MemberElement(self.scenPlan, self, referencedType=Attrib.MembType.TUNNEL, referencedId="%s/%s" % (netObj.name, netObj.name)) # XXX: Optimize later def addChannels(self, netObj): ''' Add channels to a network XML element ''' if isinstance(netObj, (nodes.WlanNode, nodes.EmaneNode)): modelconfigs = netObj.session.mobility.getmodels(netObj) modelconfigs += netObj.session.emane.getmodels(netObj) chan = None for (model, conf) in modelconfigs: # Handle mobility parameters below if model._type == coreapi.CORE_TLV_REG_MOBILITY: continue # Create the channel if chan is None: name = "wireless" chan = ChannelElement(self.scenPlan, self, netObj, channelType=model._name, channelName=name, channelDomain="CORE") # Add wireless model parameters for i, key in enumerate(model.getnames()): value = conf[i] if value is not None: chan.addParameter(key, model.valueof(key, conf)) for (model, conf) in modelconfigs: if model._type == coreapi.CORE_TLV_REG_MOBILITY: # Add wireless mobility parameters mobility = XmlElement(self.scenPlan, chan, "CORE:mobility") # Add a type child typeEle = self.createElement("type") typeEle.appendChild(self.createTextNode(model._name)) mobility.appendChild(typeEle) for i, key in enumerate(model.getnames()): value = conf[i] if value is not None: mobility.addParameter(key, value) # Add members to the channel if chan is not None: chan.addChannelMembers(self.endpoints) self.appendChild(chan.baseEle) elif isinstance(netObj, nodes.PtpNet) : if len(self.endpoints) < 2: if len(self.endpoints) == 1: self.coreSession.warn('Pt2Pt network with only 1 endpoint: %s' % self.endpoints[0].id) else: self.coreSession.warn('Pt2Pt network with no endpoints encountered in %s' % netObj.name) return name = "chan%d" % (0) chan = ChannelElement(self.scenPlan, self, netObj, channelType=Attrib.NetType.ETHERNET, channelName=name) # Add interface parameters if self.endpoints[0].params != self.endpoints[1].params: self.coreSession.warn('Pt2Pt Endpoint parameters do not match in %s' % netObj.name) for key, value in self.endpoints[0].params: # XXX lifted from original addnetem function. revisit this. # default netem parameters are 0 or None if value is None or value == 0: continue if key == "has_netem" or key == "has_tbf": continue chan.addParameter(key, value) # Add members to the channel chan.addChannelMembers(self.endpoints) self.appendChild(chan) elif isinstance(netObj, (nodes.SwitchNode, nodes.HubNode, nodes.TunnelNode)): cidx=0 channels = [] for ep in self.endpoints: # Create one channel member per ep if ep.type: name = "chan%d" % (cidx) chan = ChannelElement(self.scenPlan, self, netObj, channelType=Attrib.NetType.ETHERNET, channelName=name) # Add interface parameters for key, value in ep.params: # XXX lifted from original addnetem function. revisit this. # default netem parameters are 0 or None if value is None or value == 0: continue if key == "has_netem" or key == "has_tbf": continue chan.addParameter(key, value) # Add members to the channel chan.addChannelMembers(ep) channels.append(chan) cidx += 1 for chan in channels: self.appendChild(chan) class DeviceElement(NamedXmlElement): ''' A device element in the scenario plan. ''' def __init__(self, scenPlan, parent, devObj): ''' Add a PyCoreNode object as a device element. ''' devType = None coreDevType = None if hasattr(devObj, "type") and devObj.type: coreDevType = devObj.type if devObj.type == Attrib.NodeType.ROUTER: devType = Attrib.DevType.ROUTER elif devObj.type == Attrib.NodeType.MDR: devType = Attrib.DevType.ROUTER elif devObj.type == Attrib.NodeType.HOST: devType = Attrib.DevType.HOST elif devObj.type == Attrib.NodeType.PC: devType = Attrib.DevType.HOST elif devObj.type == Attrib.NodeType.RJ45: devType = Attrib.DevType.HOST nodeId = "EMULATOR-HOST" else: # Default custom types (defined in ~/.core/nodes.conf) to HOST devType = Attrib.DevType.HOST if devType is None: if isinstance(devObj, nodes.HubNode): devType = Attrib.DevType.HUB elif isinstance(devObj, nodes.SwitchNode): devType = Attrib.DevType.SWITCH if devType is None: raise Exception NamedXmlElement.__init__(self, scenPlan, parent, devType, devObj.name) if coreDevType is not None: typeEle = self.createElement("type") typeEle.setAttribute("domain", "CORE") typeEle.appendChild(self.createTextNode("%s" % coreDevType)) self.appendChild(typeEle) self.interfaces = [] self.addInterfaces(devObj) alias = self.createAlias(Attrib.Alias.ID, "%s" % devObj.objid) self.appendChild(alias) self.addPoint(devObj) self.addServices(devObj) presentationEle = self.createElement("CORE:presentation") addPresentationEle = False if devObj.icon and not devObj.icon.isspace(): presentationEle.setAttribute("icon", devObj.icon) addPresentationEle = True if devObj.canvas: presentationEle.setAttribute("canvas", str(devObj.canvas)) addPresentationEle = True if addPresentationEle: self.appendChild(presentationEle) def addInterfaces(self, devObj): ''' Add interfaces to a device element. ''' idx=0 for ifcObj in devObj.netifs(sort=True): if ifcObj.net and isinstance(ifcObj.net, nodes.CtrlNet): continue if isinstance(devObj, nodes.PyCoreNode): ifcEle = InterfaceElement(self.scenPlan, self, devObj, ifcObj) else: # isinstance(node, (nodes.HubNode nodes.SwitchNode)): ifcEle = InterfaceElement(self.scenPlan, self, devObj, ifcObj, idx) idx += 1 netmodel = None if ifcObj.net: if hasattr(ifcObj.net, "model"): netmodel = ifcObj.net.model if ifcObj.mtu and ifcObj.mtu != 1500: ifcEle.setAttribute("mtu", "%s" % ifcObj.mtu) # The interfaces returned for Switches and Hubs are the interfaces of the nodes connected to them. # The addresses are for those interfaces. Don't include them here. if isinstance(devObj, nodes.PyCoreNode): # could use ifcObj.params, transport_type ifcEle.addAddresses(ifcObj) # per-interface models # XXX Remove??? if netmodel and netmodel._name[:6] == "emane_": cfg = self.coreSession.emane.getifcconfig(devObj.objid, netmodel._name, None, ifcObj) if cfg: ifcEle.addModels(((netmodel, cfg),) ) self.interfaces.append(ifcEle) def addServices(self, devObj): ''' Add services and their customizations to the ServicePlan. ''' if not hasattr(devObj, "services") : return if len(devObj.services) == 0: return defaults = self.coreSession.services.getdefaultservices(devObj.type) if devObj.services == defaults: return spn = self.createElement("CORE:services") spn.setAttribute("name", devObj.name) self.appendChild(spn) for svc in devObj.services: s = self.createElement("service") spn.appendChild(s) s.setAttribute("name", str(svc._name)) s.setAttribute("startup_idx", str(svc._startindex)) if svc._starttime != "": s.setAttribute("start_time", str(svc._starttime)) # only record service names if not a customized service if not svc._custom: continue s.setAttribute("custom", str(svc._custom)) addelementsfromlist(self, s, svc._dirs, "directory", "name") for fn in svc._configs: if len(fn) == 0: continue f = self.createElement("file") f.setAttribute("name", fn) # all file names are added to determine when a file has been deleted s.appendChild(f) data = self.coreSession.services.getservicefiledata(svc, fn) if data is None: # this includes only customized file contents and skips # the auto-generated files continue txt = self.createTextNode("\n" + data) f.appendChild(txt) addtextelementsfromlist(self, s, svc._startup, "command", (("type","start"),)) addtextelementsfromlist(self, s, svc._shutdown, "command", (("type","stop"),)) addtextelementsfromlist(self, s, svc._validate, "command", (("type","validate"),)) class ChannelElement(NamedXmlElement): ''' A channel element in the scenario plan ''' def __init__(self, scenPlan, parent, netObj, channelType, channelName, channelDomain=None): NamedXmlElement.__init__(self, scenPlan, parent, "channel", channelName) ''' Create a channel element and append a member child referencing this channel element in the parent element. ''' # Create a member element for this channel in the parent MemberElement(self.scenPlan, parent, referencedType=Attrib.MembType.CHANNEL, referencedId=self.id) # Add a type child typeEle = self.createElement("type") if channelDomain is not None: typeEle.setAttribute("domain", "%s" % channelDomain) typeEle.appendChild(self.createTextNode(channelType)) self.appendChild(typeEle) def addChannelMembers(self, endpoints): ''' Add network channel members referencing interfaces in the channel ''' if isinstance(endpoints, list): # A list of endpoints is given. Create one channel member per endpoint idx = 0 for ep in endpoints: self.addChannelMember(ep.type, ep.id, idx) idx += 1 else: # A single endpoint is given. Create one channel member for the endpoint, # and if the endpoint is associated with a Layer 2 device port, add the # port as a second member ep = endpoints self.addChannelMember(ep.type, ep.id, 0) if ep.l2devport is not None: memId = "%s/%s" % (self.parent.getAttribute("id"), ep.l2devport) self.addChannelMember(ep.type, memId, 1) def addChannelMember(self, memIfcType, memIfcId, memIdx): ''' add a member to a given channel ''' m = MemberElement(self.scenPlan, self, referencedType=memIfcType, referencedId=memIfcId, index=memIdx) self.scenPlan.allChannelMembers[memIfcId] = m class InterfaceElement(NamedXmlElement): ''' A network interface element ''' def __init__(self, scenPlan, parent, devObj, ifcObj, ifcIdx=None): ''' Create a network interface element with references to channel that this interface is used. ''' elementName=None if ifcIdx is not None: elementName = "e%d" % ifcIdx else: elementName = ifcObj.name NamedXmlElement.__init__(self, scenPlan, parent, "interface", elementName) self.ifcObj = ifcObj self.addChannelReference() def addChannelReference(self): ''' Add a reference to the channel that uses this interface ''' try: cm = self.scenPlan.allChannelMembers[self.id] if cm is not None: ch = cm.baseEle.parentNode if ch is not None: net = ch.parentNode if net is not None: MemberElement(self.scenPlan, self, referencedType=Attrib.MembType.CHANNEL, referencedId=ch.getAttribute("id"), index=int(cm.getAttribute("index"))) MemberElement(self.scenPlan, self, referencedType=Attrib.MembType.NETWORK, referencedId=net.getAttribute("id")) except KeyError: pass # Not an error. This occurs when an interface belongs to a switch or a hub within a network and the channel is yet to be defined def addAddresses(self, ifcObj): ''' Add MAC and IP addresses to interface XML elements. ''' if ifcObj.hwaddr: h = self.createElement("address") self.appendChild(h) h.setAttribute("type", "mac") htxt = self.createTextNode("%s" % ifcObj.hwaddr) h.appendChild(htxt) for addr in ifcObj.addrlist: a = self.createElement("address") self.appendChild(a) (ip, sep, mask) = addr.partition('/') # mask = int(mask) XXX? if isIPv4Address(ip): a.setAttribute("type", "IPv4") else: a.setAttribute("type", "IPv6") # a.setAttribute("type", ) atxt = self.createTextNode("%s" % addr) a.appendChild(atxt) # XXX Remove? def addModels(self, configs): ''' Add models from a list of model-class, config values tuples. ''' for (m, conf) in configs: modelEle = self.createElement("model") modelEle.setAttribute("name", m._name) typeStr = "wireless" if m._type == coreapi.CORE_TLV_REG_MOBILITY: typeStr = "mobility" modelEle.setAttribute("type", typeStr) for i, k in enumerate(m.getnames()): key = self.createElement(k) value = conf[i] if value is None: value = "" key.appendChild(self.createTextNode("%s" % value)) modelEle.appendChild(key) self.appendChild(modelEle) class MemberElement(XmlElement): ''' Member elements are references to other elements in the network plan elements of the scenario. They are used in networks to reference channels, in channels to reference interfaces, and in interfaces to reference networks/channels. Member elements provided allow bi-directional traversal of network plan components. ''' def __init__(self, scenPlan, parent, referencedType, referencedId, index=None): ''' Create a member element ''' XmlElement.__init__(self, scenPlan.document, parent, "member") self.setAttribute("type", "%s" % referencedType) # See'Understanding the Network Modeling Framework document' if index is not None: self.setAttribute("index", "%d" % index) self.appendChild(self.createTextNode("%s" % referencedId)) # # ======================================================================================= # Helpers # ======================================================================================= def getEndpoint(netObj, ifcObj): ''' Create an Endpoint object given the network and the interface of interest ''' ep = None l2devport=None # if ifcObj references an interface of a node and is part of this network if ifcObj.net.objid == netObj.objid and hasattr(ifcObj,'node') and ifcObj.node: params = ifcObj.getparams() if isinstance(ifcObj.net, (nodes.HubNode, nodes.SwitchNode)): l2devport="%s/e%d" % (ifcObj.net.name, ifcObj.net.getifindex(ifcObj)) ep = Endpoint(netObj, ifcObj, type = Attrib.MembType.INTERFACE, id="%s/%s" % (ifcObj.node.name, ifcObj.name), l2devport=l2devport, params=params) # else if ifcObj references another node and is connected to this network elif hasattr(ifcObj,"othernet"): if ifcObj.othernet.objid == netObj.objid: # #hack used for upstream parameters for link between switches # #(see LxBrNet.linknet()) ifcObj.swapparams('_params_up') params = ifcObj.getparams() ifcObj.swapparams('_params_up') owner = ifcObj.net l2devport="%s/e%d" % (ifcObj.othernet.name, ifcObj.othernet.getifindex(ifcObj)) # Create the endpoint. # XXX the interface index might not match what is shown in the gui. For switches and hubs, # The gui assigns its index but doesn't pass it to the daemon and vice versa. # The gui stores it's index in the IMN file, which it reads and writes without daemon intervention. # Fix this! ep = Endpoint(owner, ifcObj, type = Attrib.MembType.INTERFACE, id="%s/%s/e%d" % (netObj.name, owner.name, owner.getifindex(ifcObj)), l2devport=l2devport, params=params) # else this node has an interface that belongs to another network # i.e. a switch/hub interface connected to another switch/hub and CORE has the other switch/hub # as the containing network else : ep = Endpoint(netObj, ifcObj,type=None, id=None, l2devport=None, params=None) return ep def getEndpoints(netObj): ''' Gather all endpoints of the given network ''' # Get all endpoints endpoints = [] # XXX TODO: How to represent physical interfaces. # # NOTE: The following code works except it would be missing physical (rj45) interfaces from Pt2pt links # TODO: Fix data in net.netifs to include Pt2Pt physical interfaces # # Iterate through all the nodes in the scenario, then iterate through all the interface for each node, # and check if the interface is connected to this network. for ifcObj in netObj.netifs(sort=True): try: ep = getEndpoint(netObj, ifcObj) if ep is not None: endpoints.append(ep) except Exception: pass return endpoints def getDowmstreamL2Devices(netObj): ''' Helper function for getting a list of all downstream layer 2 devices from the given netObj ''' l2devObjs = [netObj] allendpoints = [] myendpoints = getEndpoints(netObj) allendpoints.extend(myendpoints) for ep in myendpoints: if ep.type and ep.net.objid != netObj.objid: l2s, eps = getDowmstreamL2Devices(ep.net) l2devObjs.extend(l2s) allendpoints.extend(eps) return l2devObjs, allendpoints def getAllNetworkInterfaces(session): ''' Gather all network interfacecs in the session ''' netifs = [] for node in session.objs(): for netif in node.netifs(sort=True): if netif not in netifs: netifs.append(netif) return netifs def inOtherNetwork(netObj): ''' Determine if CORE considers a given network object to be part of another network. Note: CORE considers layer 2 devices to be their own networks. However, if a l2 device is connected to another device, it is possible that one of its ports belong to the other l2 device's network (thus, "othernet"). ''' for netif in netObj.netifs(sort=True): if hasattr(netif,"othernet"): if netif.othernet.objid != netObj.objid: return True return False core-4.8/daemon/core/mobility.py0000664000175000017500000011320312534327775013654 00000000000000# # CORE # Copyright (c)2011-2012 the Boeing Company. # See the LICENSE file included in this distribution. # # author: Jeff Ahrenholz # ''' mobility.py: mobility helpers for moving nodes and calculating wireless range. ''' import sys, os, time, string, math, threading import heapq from core.api import coreapi from core.conf import ConfigurableManager, Configurable from core.coreobj import PyCoreNode from core.misc.utils import check_call from core.misc.ipaddr import IPAddr class MobilityManager(ConfigurableManager): ''' Member of session class for handling configuration data for mobility and range models. ''' _name = "MobilityManager" _type = coreapi.CORE_TLV_REG_WIRELESS def __init__(self, session): ConfigurableManager.__init__(self, session) self.verbose = self.session.getcfgitembool('verbose', False) # configurations for basic range, indexed by WLAN node number, are # stored in self.configs # mapping from model names to their classes self._modelclsmap = {} # dummy node objects for tracking position of nodes on other servers self.phys = {} self.physnets = {} self.session.broker.handlers += (self.physnodehandlelink, ) self.register() def startup(self, nodenums=None): ''' Session is transitioning from instantiation to runtime state. Instantiate any mobility models that have been configured for a WLAN. ''' if nodenums is None: nodenums = self.configs.keys() for nodenum in nodenums: try: n = self.session.obj(nodenum) except KeyError: self.session.warn("Skipping mobility configuration for unknown" "node %d." % nodenum) continue if nodenum not in self.configs: self.session.warn("Missing mobility configuration for node " "%d." % nodenum) continue v = self.configs[nodenum] for model in v: try: cls = self._modelclsmap[model[0]] except KeyError: self.session.warn("Skipping mobility configuration for " "unknown model '%s'" % model[0]) continue n.setmodel(cls, model[1]) if self.session.master: self.installphysnodes(n) if n.mobility: self.session.evq.add_event(0.0, n.mobility.startup) return () def reset(self): ''' Reset all configs. ''' self.clearconfig(nodenum=None) def setconfig(self, nodenum, conftype, values): ''' Normal setconfig() with check for run-time updates for WLANs. ''' super(MobilityManager, self).setconfig(nodenum, conftype, values) if self.session is None: return if self.session.getstate() == coreapi.CORE_EVENT_RUNTIME_STATE: try: n = self.session.obj(nodenum) except KeyError: self.session.warn("Skipping mobility configuration for unknown" "node %d." % nodenum) n.updatemodel(conftype, values) def register(self): ''' Register models as configurable object(s) with the Session object. ''' models = [BasicRangeModel, Ns2ScriptedMobility] for m in models: self.session.addconfobj(m._name, m._type, m.configure_mob) self._modelclsmap[m._name] = m def handleevent(self, msg): ''' Handle an Event Message used to start, stop, or pause mobility scripts for a given WlanNode. ''' eventtype = msg.gettlv(coreapi.CORE_TLV_EVENT_TYPE) nodenum = msg.gettlv(coreapi.CORE_TLV_EVENT_NODE) name = msg.gettlv(coreapi.CORE_TLV_EVENT_NAME) try: node = self.session.obj(nodenum) except KeyError: self.session.warn("Ignoring event for model '%s', unknown node " \ "'%s'" % (name, nodenum)) return # name is e.g. "mobility:ns2script" models = name[9:].split(',') for m in models: try: cls = self._modelclsmap[m] except KeyError: self.session.warn("Ignoring event for unknown model '%s'" % m) continue _name = "waypoint" if cls._type == coreapi.CORE_TLV_REG_WIRELESS: model = node.mobility elif cls._type == coreapi.CORE_TLV_REG_MOBILITY: model = node.mobility else: continue if model is None: self.session.warn("Ignoring event, %s has no model" % node.name) continue if cls._name != model._name: self.session.warn("Ignoring event for %s wrong model %s,%s" % \ (node.name, cls._name, model._name)) continue if eventtype == coreapi.CORE_EVENT_STOP or \ eventtype == coreapi.CORE_EVENT_RESTART: model.stop(move_initial=True) if eventtype == coreapi.CORE_EVENT_START or \ eventtype == coreapi.CORE_EVENT_RESTART: model.start() if eventtype == coreapi.CORE_EVENT_PAUSE: model.pause() def sendevent(self, model): ''' Send an event message on behalf of a mobility model. This communicates the current and end (max) times to the GUI. ''' if model.state == model.STATE_STOPPED: eventtype = coreapi.CORE_EVENT_STOP elif model.state == model.STATE_RUNNING: eventtype = coreapi.CORE_EVENT_START elif model.state == model.STATE_PAUSED: eventtype = coreapi.CORE_EVENT_PAUSE data = "start=%d" % int(model.lasttime - model.timezero) data += " end=%d" % int(model.endtime) tlvdata = "" tlvdata += coreapi.CoreEventTlv.pack(coreapi.CORE_TLV_EVENT_NODE, model.objid) tlvdata += coreapi.CoreEventTlv.pack(coreapi.CORE_TLV_EVENT_TYPE, eventtype) tlvdata += coreapi.CoreEventTlv.pack(coreapi.CORE_TLV_EVENT_NAME, "mobility:%s" % model._name) tlvdata += coreapi.CoreEventTlv.pack(coreapi.CORE_TLV_EVENT_DATA, data) tlvdata += coreapi.CoreEventTlv.pack(coreapi.CORE_TLV_EVENT_TIME, "%s" % time.time()) msg = coreapi.CoreEventMessage.pack(0, tlvdata) try: self.session.broadcastraw(None, msg) except Exception, e: self.warn("Error sending Event Message: %s" % e) def updatewlans(self, moved, moved_netifs): ''' A mobility script has caused nodes in the 'moved' list to move. Update every WlanNode. This saves range calculations if the model were to recalculate for each individual node movement. ''' for nodenum in self.configs: try: n = self.session.obj(nodenum) except KeyError: continue if n.model: n.model.update(moved, moved_netifs) def addphys(self, netnum, node): ''' Keep track of PhysicalNodes and which network they belong to. ''' nodenum = node.objid self.phys[nodenum] = node if netnum not in self.physnets: self.physnets[netnum] = [nodenum,] else: self.physnets[netnum].append(nodenum) def physnodehandlelink(self, msg): ''' Broker handler. Snoop Link add messages to get node numbers of PhyiscalNodes and their nets. Physical nodes exist only on other servers, but a shadow object is created here for tracking node position. ''' if msg.msgtype == coreapi.CORE_API_LINK_MSG and \ msg.flags & coreapi.CORE_API_ADD_FLAG: nn = msg.nodenumbers() # first node is always link layer node in Link add message if nn[0] not in self.session.broker.nets: return if nn[1] in self.session.broker.phys: # record the fact that this PhysicalNode is linked to a net dummy = PyCoreNode(session=self.session, objid=nn[1], name="n%d" % nn[1], start=False) self.addphys(nn[0], dummy) def physnodeupdateposition(self, msg): ''' Snoop node messages belonging to physical nodes. The dummy object in self.phys[] records the node position. ''' nodenum = msg.nodenumbers()[0] try: dummy = self.phys[nodenum] nodexpos = msg.gettlv(coreapi.CORE_TLV_NODE_XPOS) nodeypos = msg.gettlv(coreapi.CORE_TLV_NODE_YPOS) dummy.setposition(nodexpos, nodeypos, None) except KeyError: pass def installphysnodes(self, net): ''' After installing a mobility model on a net, include any physical nodes that we have recorded. Use the GreTap tunnel to the physical node as the node's interface. ''' try: nodenums = self.physnets[net.objid] except KeyError: return for nodenum in nodenums: node = self.phys[nodenum] servers = self.session.broker.getserversbynode(nodenum) (host, port, sock) = self.session.broker.getserver(servers[0]) netif = self.session.broker.gettunnel(net.objid, IPAddr.toint(host)) node.addnetif(netif, 0) netif.node = node (x,y,z) = netif.node.position.get() netif.poshook(netif, x, y, z) class WirelessModel(Configurable): ''' Base class used by EMANE models and the basic range model. Used for managing arbitrary configuration parameters. ''' _type = coreapi.CORE_TLV_REG_WIRELESS _bitmap = None _positioncallback = None def __init__(self, session, objid, verbose = False, values = None): Configurable.__init__(self, session, objid) self.verbose = verbose # 'values' can be retrieved from a ConfigurableManager, or used here # during initialization, depending on the model. def tolinkmsgs(self, flags): ''' May be used if the model can populate the GUI with wireless (green) link lines. ''' return [] def update(self, moved, moved_netifs): raise NotImplementedError def updateconfig(self, values): ''' For run-time updates of model config. Returns True when self._positioncallback() and self.setlinkparams() should be invoked. ''' return False class BasicRangeModel(WirelessModel): ''' Basic Range wireless model, calculates range between nodes and links and unlinks nodes based on this distance. This was formerly done from the GUI. ''' _name = "basic_range" # configuration parameters are # ( 'name', 'type', 'default', 'possible-value-list', 'caption') _confmatrix = [ ("range", coreapi.CONF_DATA_TYPE_UINT32, '275', '', 'wireless range (pixels)'), ("bandwidth", coreapi.CONF_DATA_TYPE_UINT32, '54000', '', 'bandwidth (bps)'), ("jitter", coreapi.CONF_DATA_TYPE_FLOAT, '0.0', '', 'transmission jitter (usec)'), ("delay", coreapi.CONF_DATA_TYPE_FLOAT, '5000.0', '', 'transmission delay (usec)'), ("error", coreapi.CONF_DATA_TYPE_FLOAT, '0.0', '', 'error rate (%)'), ] # value groupings _confgroups = "Basic Range Parameters:1-%d" % len(_confmatrix) def __init__(self, session, objid, verbose = False, values=None): ''' Range model is only instantiated during runtime. ''' super(BasicRangeModel, self).__init__(session = session, objid = objid, verbose = verbose) self.wlan = session.obj(objid) self._netifs = {} self._netifslock = threading.Lock() if values is None: values = session.mobility.getconfig(objid, self._name, self.getdefaultvalues())[1] self.range = float(self.valueof("range", values)) if self.verbose: self.session.info("Basic range model configured for WLAN %d using" \ " range %d" % (objid, self.range)) self.valuestolinkparams(values) def valuestolinkparams(self, values): self.bw = int(self.valueof("bandwidth", values)) if self.bw == 0.0: self.bw = None self.delay = float(self.valueof("delay", values)) if self.delay == 0.0: self.delay = None self.loss = float(self.valueof("error", values)) if self.loss == 0.0: self.loss = None self.jitter = float(self.valueof("jitter", values)) if self.jitter == 0.0: self.jitter = None @classmethod def configure_mob(cls, session, msg): ''' Handle configuration messages for setting up a model. Pass the MobilityManager object as the manager object. ''' return cls.configure(session.mobility, msg) def setlinkparams(self): ''' Apply link parameters to all interfaces. This is invoked from WlanNode.setmodel() after the position callback has been set. ''' with self._netifslock: for netif in self._netifs: self.wlan.linkconfig(netif, bw=self.bw, delay=self.delay, loss=self.loss, duplicate=None, jitter=self.jitter) def get_position(self, netif): with self._netifslock: return self._netifs[netif] def set_position(self, netif, x = None, y = None, z = None): ''' A node has moved; given an interface, a new (x,y,z) position has been set; calculate the new distance between other nodes and link or unlink node pairs based on the configured range. ''' #print "set_position(%s, x=%s, y=%s, z=%s)" % (netif.localname, x, y, z) self._netifslock.acquire() self._netifs[netif] = (x, y, z) if x is None or y is None: self._netifslock.release() return for netif2 in self._netifs: self.calclink(netif, netif2) self._netifslock.release() _positioncallback = set_position def update(self, moved, moved_netifs): ''' Node positions have changed without recalc. Update positions from node.position, then re-calculate links for those that have moved. Assumes bidirectional links, with one calculation per node pair, where one of the nodes has moved. ''' with self._netifslock: while len(moved_netifs): netif = moved_netifs.pop() (nx, ny, nz) = netif.node.getposition() if netif in self._netifs: self._netifs[netif] = (nx, ny, nz) for netif2 in self._netifs: if netif2 in moved_netifs: continue self.calclink(netif, netif2) def calclink(self, netif, netif2): ''' Helper used by set_position() and update() to calculate distance between two interfaces and perform linking/unlinking. Sends link/unlink messages and updates the WlanNode's linked dict. ''' if netif == netif2: return try: (x, y, z) = self._netifs[netif] (x2, y2, z2) = self._netifs[netif2] except KeyError: return if x2 is None or y2 is None: return d = self.calcdistance( (x,y,z), (x2,y2,z2) ) # ordering is important, to keep the wlan._linked dict organized a = min(netif, netif2) b = max(netif, netif2) try: self.wlan._linked_lock.acquire() linked = self.wlan.linked(a, b) except KeyError: return finally: self.wlan._linked_lock.release() if d > self.range: if linked: self.wlan.unlink(a, b) self.sendlinkmsg(a, b, unlink=True) else: if not linked: self.wlan.link(a, b) self.sendlinkmsg(a, b) @staticmethod def calcdistance(p1, p2): ''' Calculate the distance between two three-dimensional points. ''' a = p1[0] - p2[0] b = p1[1] - p2[1] c = 0 if p1[2] is not None and p2[2] is not None: c = p1[2] - p2[2] return math.hypot(math.hypot(a, b), c) def updateconfig(self, values): ''' Configuration has changed during runtime. MobilityManager.setconfig() -> WlanNode.updatemodel() -> WirelessModel.updateconfig() ''' self.valuestolinkparams(values) self.range = float(self.valueof("range", values)) return True def linkmsg(self, netif, netif2, flags): ''' Create a wireless link/unlink API message. ''' n1 = netif.localname.split('.')[0] n2 = netif2.localname.split('.')[0] tlvdata = coreapi.CoreLinkTlv.pack(coreapi.CORE_TLV_LINK_N1NUMBER, netif.node.objid) tlvdata += coreapi.CoreLinkTlv.pack(coreapi.CORE_TLV_LINK_N2NUMBER, netif2.node.objid) tlvdata += coreapi.CoreLinkTlv.pack(coreapi.CORE_TLV_LINK_NETID, self.wlan.objid) #tlvdata += coreapi.CoreLinkTlv.pack(coreapi.CORE_TLV_LINK_IF1NUM, # netif.index) #tlvdata += coreapi.CoreLinkTlv.pack(coreapi.CORE_TLV_LINK_IF2NUM, # netif2.index) tlvdata += coreapi.CoreLinkTlv.pack(coreapi.CORE_TLV_LINK_TYPE, coreapi.CORE_LINK_WIRELESS) return coreapi.CoreLinkMessage.pack(flags, tlvdata) def sendlinkmsg(self, netif, netif2, unlink=False): ''' Send a wireless link/unlink API message to the GUI. ''' if unlink: flags = coreapi.CORE_API_DEL_FLAG else: flags = coreapi.CORE_API_ADD_FLAG msg = self.linkmsg(netif, netif2, flags) self.session.broadcastraw(src=None, data=msg) self.session.sdt.updatelink(netif.node.objid, netif2.node.objid, flags, wireless=True) def tolinkmsgs(self, flags): ''' Return a list of wireless link messages for when the GUI reconnects. ''' r = [] with self.wlan._linked_lock: for a in self.wlan._linked: for b in self.wlan._linked[a]: if self.wlan._linked[a][b]: r.append(self.linkmsg(a, b, flags)) return r class WayPointMobility(WirelessModel): ''' Abstract class for mobility models that set node waypoints. ''' _name = "waypoint" _type = coreapi.CORE_TLV_REG_MOBILITY STATE_STOPPED = 0 STATE_RUNNING = 1 STATE_PAUSED = 2 class WayPoint(object): def __init__(self, time, nodenum, coords, speed): self.time = time self.nodenum = nodenum self.coords = coords self.speed = speed def __cmp__(self, other): tmp = cmp(self.time, other.time) if tmp == 0: tmp = cmp(self.nodenum, other.nodenum) return tmp def __init__(self, session, objid, verbose = False, values = None): super(WayPointMobility, self).__init__(session = session, objid = objid, verbose = verbose, values = values) self.state = self.STATE_STOPPED self.queue = [] self.queue_copy = [] self.points = {} self.initial = {} self.lasttime = None self.endtime = None self.wlan = session.obj(objid) # these are really set in child class via confmatrix self.loop = False self.refresh_ms = 50 # flag whether to stop scheduling when queue is empty # (ns-3 sets this to False as new waypoints may be added from trace) self.empty_queue_stop = True def runround(self): ''' Advance script time and move nodes. ''' if self.state != self.STATE_RUNNING: return t = self.lasttime self.lasttime = time.time() now = self.lasttime - self.timezero dt = self.lasttime - t #print "runround(now=%.2f, dt=%.2f)" % (now, dt) # keep current waypoints up-to-date self.updatepoints(now) if not len(self.points): if len(self.queue): # more future waypoints, allow time for self.lasttime update nexttime = self.queue[0].time - now if nexttime > (0.001 * self.refresh_ms): nexttime -= (0.001 * self.refresh_ms) self.session.evq.add_event(nexttime, self.runround) return else: # no more waypoints or queued items, loop? if not self.empty_queue_stop: # keep running every refresh_ms, even with empty queue self.session.evq.add_event(0.001 * self.refresh_ms, self.runround) return if not self.loopwaypoints(): return self.stop(move_initial=False) if not len(self.queue): # prevent busy loop return return self.run() # only move netifs attached to self.wlan, or all nodenum in script? moved = [] moved_netifs = [] for netif in self.wlan.netifs(): node = netif.node if self.movenode(node, dt): moved.append(node) moved_netifs.append(netif) # calculate all ranges after moving nodes; this saves calculations #self.wlan.model.update(moved) self.session.mobility.updatewlans(moved, moved_netifs) # TODO: check session state self.session.evq.add_event(0.001 * self.refresh_ms, self.runround) def run(self): self.timezero = time.time() self.lasttime = self.timezero - (0.001 * self.refresh_ms) self.movenodesinitial() self.runround() self.session.mobility.sendevent(self) def movenode(self, node, dt): ''' Calculate next node location and update its coordinates. Returns True if the node's position has changed. ''' if node.objid not in self.points: return False x1, y1, z1 = node.getposition() x2, y2, z2 = self.points[node.objid].coords speed = self.points[node.objid].speed # instantaneous move (prevents dx/dy == 0.0 below) if speed == 0: self.setnodeposition(node, x2, y2, z2) del self.points[node.objid] return True # speed can be a velocity vector (ns3 mobility) or speed value if isinstance(speed, (float, int)): # linear speed value alpha = math.atan2(y2 - y1, x2 - x1) sx = speed * math.cos(alpha) sy = speed * math.sin(alpha) else: # velocity vector sx = speed[0] sy = speed[1] # calculate dt * speed = distance moved dx = sx * dt dy = sy * dt # prevent overshoot if abs(dx) > abs(x2 - x1): dx = x2 - x1 if abs(dy) > abs(y2 - y1): dy = y2 - y1 if dx == 0.0 and dy == 0.0: if self.endtime < (self.lasttime - self.timezero): # the last node to reach the last waypoint determines this # script's endtime self.endtime = self.lasttime - self.timezero del self.points[node.objid] return False #print "node %s dx,dy= <%s, %d>" % (node.name, dx, dy) if (x1 + dx) < 0.0: dx = 0.0 - x1 if (y1 + dy) < 0.0: dy = 0.0 - y1 self.setnodeposition(node, x1 + dx, y1 + dy, z1) return True def movenodesinitial(self): ''' Move nodes to their initial positions. Then calculate the ranges. ''' moved = [] moved_netifs = [] for netif in self.wlan.netifs(): node = netif.node if node.objid not in self.initial: continue (x, y, z) = self.initial[node.objid].coords self.setnodeposition(node, x, y, z) moved.append(node) moved_netifs.append(netif) #self.wlan.model.update(moved) self.session.mobility.updatewlans(moved, moved_netifs) def addwaypoint(self, time, nodenum, x, y, z, speed): ''' Waypoints are pushed to a heapq, sorted by time. ''' #print "addwaypoint: %s %s %s,%s,%s %s" % (time, nodenum, x, y, z, speed) wp = self.WayPoint(time, nodenum, coords=(x,y,z), speed=speed) heapq.heappush(self.queue, wp) def addinitial(self, nodenum, x, y, z): ''' Record initial position in a dict. ''' wp = self.WayPoint(0, nodenum, coords=(x,y,z), speed=0) self.initial[nodenum] = wp def updatepoints(self, now): ''' Move items from self.queue to self.points when their time has come. ''' while len(self.queue): if self.queue[0].time > now: break wp = heapq.heappop(self.queue) self.points[wp.nodenum] = wp def copywaypoints(self): ''' Store backup copy of waypoints for looping and stopping. ''' self.queue_copy = list(self.queue) def loopwaypoints(self): ''' Restore backup copy of waypoints when looping. ''' self.queue = list(self.queue_copy) return self.loop def setnodeposition(self, node, x, y, z): ''' Helper to move a node, notify any GUI (connected session handlers), without invoking the interface poshook callback that may perform range calculation. ''' # this would cause PyCoreNetIf.poshook() callback (range calculation) #node.setposition(x, y, z) node.position.set(x, y, z) msg = node.tonodemsg(flags=0) self.session.broadcastraw(None, msg) self.session.sdt.updatenode(node.objid, flags=0, x=x, y=y, z=z) def setendtime(self): ''' Set self.endtime to the time of the last waypoint in the queue of waypoints. This is just an estimate. The endtime will later be adjusted, after one round of the script has run, to be the time that the last moving node has reached its final waypoint. ''' try: self.endtime = self.queue[-1].time except IndexError: self.endtime = 0 def start(self): ''' Run the script from the beginning or unpause from where it was before. ''' laststate = self.state self.state = self.STATE_RUNNING if laststate == self.STATE_STOPPED or laststate == self.STATE_RUNNING: self.loopwaypoints() self.timezero = 0 self.lasttime = 0 self.run() elif laststate == self.STATE_PAUSED: now = time.time() self.timezero += now - self.lasttime self.lasttime = now - (0.001 * self.refresh_ms) self.runround() def stop(self, move_initial=True): ''' Stop the script and move nodes to initial positions. ''' self.state = self.STATE_STOPPED self.loopwaypoints() self.timezero = 0 self.lasttime = 0 if move_initial: self.movenodesinitial() self.session.mobility.sendevent(self) def pause(self): ''' Pause the script; pause time is stored to self.lasttime. ''' self.state = self.STATE_PAUSED self.lasttime = time.time() class Ns2ScriptedMobility(WayPointMobility): ''' Handles the ns-2 script format, generated by scengen/setdest or BonnMotion. ''' _name = "ns2script" _confmatrix = [ ("file", coreapi.CONF_DATA_TYPE_STRING, '', '', 'mobility script file'), ("refresh_ms", coreapi.CONF_DATA_TYPE_UINT32, '50', '', 'refresh time (ms)'), ("loop", coreapi.CONF_DATA_TYPE_BOOL, '1', 'On,Off', 'loop'), ("autostart", coreapi.CONF_DATA_TYPE_STRING, '', '', 'auto-start seconds (0.0 for runtime)'), ("map", coreapi.CONF_DATA_TYPE_STRING, '', '', 'node mapping (optional, e.g. 0:1,1:2,2:3)'), ("script_start", coreapi.CONF_DATA_TYPE_STRING, '', '', 'script file to run upon start'), ("script_pause", coreapi.CONF_DATA_TYPE_STRING, '', '', 'script file to run upon pause'), ("script_stop", coreapi.CONF_DATA_TYPE_STRING, '', '', 'script file to run upon stop'), ] _confgroups = "ns-2 Mobility Script Parameters:1-%d" % len(_confmatrix) def __init__(self, session, objid, verbose = False, values = None): ''' ''' super(Ns2ScriptedMobility, self).__init__(session = session, objid = objid, verbose = verbose, values = values) self._netifs = {} self._netifslock = threading.Lock() if values is None: values = session.mobility.getconfig(objid, self._name, self.getdefaultvalues())[1] self.file = self.valueof("file", values) self.refresh_ms = int(self.valueof("refresh_ms", values)) self.loop = (self.valueof("loop", values).lower() == "on") self.autostart = self.valueof("autostart", values) self.parsemap(self.valueof("map", values)) self.script_start = self.valueof("script_start", values) self.script_pause = self.valueof("script_pause", values) self.script_stop = self.valueof("script_stop", values) if self.verbose: self.session.info("ns-2 scripted mobility configured for WLAN %d" \ " using file: %s" % (objid, self.file)) self.readscriptfile() self.copywaypoints() self.setendtime() @classmethod def configure_mob(cls, session, msg): ''' Handle configuration messages for setting up a model. Pass the MobilityManager object as the manager object. ''' return cls.configure(session.mobility, msg) def readscriptfile(self): ''' Read in mobility script from a file. This adds waypoints to a priority queue, sorted by waypoint time. Initial waypoints are stored in a separate dict. ''' filename = self.findfile(self.file) try: f = open(filename, 'r') except IOError, e: self.session.warn("ns-2 scripted mobility failed to load file " \ " '%s' (%s)" % (self.file, e)) return if self.verbose: self.session.info("reading ns-2 script file: %s" % filename) ln = 0 ix = iy = iz = None inodenum = None for line in f: ln += 1 if line[:2] != '$n': continue try: if line[:8] == "$ns_ at ": if ix is not None and iy is not None: self.addinitial(self.map(inodenum), ix, iy, iz) ix = iy = iz = None # waypoints: # $ns_ at 1.00 "$node_(6) setdest 500.0 178.0 25.0" parts = line.split() time = float(parts[2]) nodenum = parts[3][1+parts[3].index('('):parts[3].index(')')] x = float(parts[5]) y = float(parts[6]) z = None speed = float(parts[7].strip('"')) self.addwaypoint(time, self.map(nodenum), x, y, z, speed) elif line[:7] == "$node_(": # initial position (time=0, speed=0): # $node_(6) set X_ 780.0 parts = line.split() time = 0.0 nodenum = parts[0][1+parts[0].index('('):parts[0].index(')')] if parts[2] == 'X_': if ix is not None and iy is not None: self.addinitial(self.map(inodenum), ix, iy, iz) ix = iy = iz = None ix = float(parts[3]) elif parts[2] == 'Y_': iy = float(parts[3]) elif parts[2] == 'Z_': iz = float(parts[3]) self.addinitial(self.map(nodenum), ix, iy, iz) ix = iy = iz = None inodenum = nodenum else: raise ValueError except ValueError, e: self.session.warn("skipping line %d of file %s '%s' (%s)" % \ (ln, self.file, line, e)) continue if ix is not None and iy is not None: self.addinitial(self.map(inodenum), ix, iy, iz) def findfile(self, fn): ''' Locate a script file. If the specified file doesn't exist, look in the same directory as the scenario file (session.filename), or in the default configs directory (~/.core/configs). This allows for sample files without absolute pathnames. ''' if os.path.exists(fn): return fn if self.session.filename is not None: d = os.path.dirname(self.session.filename) sessfn = os.path.join(d, fn) if (os.path.exists(sessfn)): return sessfn if self.session.user is not None: userfn = os.path.join('/home', self.session.user, '.core', 'configs', fn) if (os.path.exists(userfn)): return userfn return fn def parsemap(self, mapstr): ''' Parse a node mapping string, given as a configuration parameter. ''' self.nodemap = {} if mapstr.strip() == '': return for pair in mapstr.split(','): parts = pair.split(':') try: if len(parts) != 2: raise ValueError self.nodemap[int(parts[0])] = int(parts[1]) except ValueError: self.session.warn("ns-2 mobility node map error") return def map(self, nodenum): ''' Map one node number (from a script file) to another. ''' nodenum = int(nodenum) try: return self.nodemap[nodenum] except KeyError: return nodenum def startup(self): ''' Start running the script if autostart is enabled. Move node to initial positions when any autostart time is specified. Ignore the script if autostart is an empty string (can still be started via GUI controls). ''' if self.autostart == '': if self.verbose: self.session.info("not auto-starting ns-2 script for %s" % \ self.wlan.name) return try: t = float(self.autostart) except ValueError: self.session.warn("Invalid auto-start seconds specified '%s' for " \ "%s" % (self.autostart, self.wlan.name)) return self.movenodesinitial() if self.verbose: self.session.info("scheduling ns-2 script for %s autostart at %s" \ % (self.wlan.name, t)) self.state = self.STATE_RUNNING self.session.evq.add_event(t, self.run) def start(self): ''' Handle the case when un-paused. ''' laststate = self.state super(Ns2ScriptedMobility, self).start() if laststate == self.STATE_PAUSED: self.statescript("unpause") def run(self): ''' Start is pressed or autostart is triggered. ''' super(Ns2ScriptedMobility, self).run() self.statescript("run") def pause(self): super(Ns2ScriptedMobility, self).pause() self.statescript("pause") def stop(self, move_initial=True): super(Ns2ScriptedMobility, self).stop(move_initial=move_initial) self.statescript("stop") def statescript(self, typestr): filename = None if typestr == "run" or typestr == "unpause": filename = self.script_start elif typestr == "pause": filename = self.script_pause elif typestr == "stop": filename = self.script_stop if filename is None or filename == '': return filename = self.findfile(filename) try: check_call(["/bin/sh", filename, typestr], cwd=self.session.sessiondir, env=self.session.getenviron()) except Exception, e: self.session.warn("Error running script '%s' for WLAN state %s: " \ "%s" % (filename, typestr, e)) core-4.8/daemon/core/netns/0000775000175000017500000000000012534327775012661 500000000000000core-4.8/daemon/core/netns/__init__.py0000664000175000017500000000000012534327775014700 00000000000000core-4.8/daemon/core/netns/nodes.py0000664000175000017500000004577512534327775014305 00000000000000# # CORE # Copyright (c)2010-2013 the Boeing Company. # See the LICENSE file included in this distribution. # # authors: Tom Goff # Jeff Ahrenholz # ''' nodes.py: definition of an LxcNode and CoreNode classes, and other node classes that inherit from the CoreNode, implementing specific node types. ''' from vnode import * from vnet import * from core.misc.ipaddr import * from core.api import coreapi from core.coreobj import PyCoreNode class CtrlNet(LxBrNet): policy = "ACCEPT" CTRLIF_IDX_BASE = 99 # base control interface index DEFAULT_PREFIX_LIST = ["172.16.0.0/24 172.16.1.0/24 172.16.2.0/24 172.16.3.0/24 172.16.4.0/24", "172.17.0.0/24 172.17.1.0/24 172.17.2.0/24 172.17.3.0/24 172.17.4.0/24", "172.18.0.0/24 172.18.1.0/24 172.18.2.0/24 172.18.3.0/24 172.18.4.0/24", "172.19.0.0/24 172.19.1.0/24 172.19.2.0/24 172.19.3.0/24 172.19.4.0/24"] def __init__(self, session, objid = "ctrlnet", name = None, verbose = False, prefix = None, hostid = None, start = True, assign_address = True, updown_script = None, serverintf = None): self.prefix = IPv4Prefix(prefix) self.hostid = hostid self.assign_address = assign_address self.updown_script = updown_script self.serverintf = serverintf LxBrNet.__init__(self, session, objid = objid, name = name, verbose = verbose, start = start) def startup(self): if self.detectoldbridge(): return LxBrNet.startup(self) if self.hostid: addr = self.prefix.addr(self.hostid) else: addr = self.prefix.maxaddr() msg = "Added control network bridge: %s %s" % \ (self.brname, self.prefix) addrlist = ["%s/%s" % (addr, self.prefix.prefixlen)] if self.assign_address: self.addrconfig(addrlist = addrlist) msg += " address %s" % addr self.session.info(msg) if self.updown_script is not None: self.info("interface %s updown script '%s startup' called" % \ (self.brname, self.updown_script)) check_call([self.updown_script, self.brname, "startup"]) if self.serverintf is not None: try: check_call([BRCTL_BIN, "addif", self.brname, self.serverintf]) check_call([IP_BIN, "link", "set", self.serverintf, "up"]) except Exception, e: self.exception(coreapi.CORE_EXCP_LEVEL_FATAL, self.brname, "Error joining server interface %s to controlnet bridge %s: %s" % \ (self.serverintf, self.brname, e)) def detectoldbridge(self): ''' Occassionally, control net bridges from previously closed sessions are not cleaned up. Check if there are old control net bridges and delete them ''' retstat, retstr = cmdresult([BRCTL_BIN,'show']) if retstat != 0: self.exception(coreapi.CORE_EXCP_LEVEL_FATAL, None, "Unable to retrieve list of installed bridges") lines = retstr.split('\n') for line in lines[1:]: cols = line.split('\t') oldbr = cols[0] flds = cols[0].split('.') if len(flds) == 3: if flds[0] == 'b' and flds[1] == self.objid: self.session.exception(coreapi.CORE_EXCP_LEVEL_FATAL, "CtrlNet.startup()", None, "Error: An active control net bridge (%s) found. "\ "An older session might still be running. " \ "Stop all sessions and, if needed, delete %s to continue." % \ (oldbr, oldbr)) return True ''' # Do this if we want to delete the old bridge self.warn("Warning: Old %s bridge found: %s" % (self.objid, oldbr)) try: check_call([BRCTL_BIN, 'delbr', oldbr]) except Exception, e: self.exception(coreapi.CORE_EXCP_LEVEL_ERROR, oldbr, "Error deleting old bridge %s" % oldbr) self.info("Deleted %s" % oldbr) ''' return False def shutdown(self): if self.serverintf is not None: try: check_call([BRCTL_BIN, "delif", self.brname, self.serverintf]) except Exception, e: self.exception(coreapi.CORE_EXCP_LEVEL_ERROR, self.brname, "Error deleting server interface %s to controlnet bridge %s: %s" % \ (self.serverintf, self.brname, e)) if self.updown_script is not None: self.info("interface %s updown script '%s shutdown' called" % \ (self.brname, self.updown_script)) check_call([self.updown_script, self.brname, "shutdown"]) LxBrNet.shutdown(self) def tolinkmsgs(self, flags): ''' Do not include CtrlNet in link messages describing this session. ''' return [] class CoreNode(LxcNode): apitype = coreapi.CORE_NODE_DEF class PtpNet(LxBrNet): policy = "ACCEPT" def attach(self, netif): if len(self._netif) > 1: raise ValueError, \ "Point-to-point links support at most 2 network interfaces" LxBrNet.attach(self, netif) def tonodemsg(self, flags): ''' Do not generate a Node Message for point-to-point links. They are built using a link message instead. ''' pass def tolinkmsgs(self, flags): ''' Build CORE API TLVs for a point-to-point link. One Link message describes this network. ''' tlvdata = "" if len(self._netif) != 2: return tlvdata (if1, if2) = self._netif.items() if1 = if1[1] if2 = if2[1] tlvdata += coreapi.CoreLinkTlv.pack(coreapi.CORE_TLV_LINK_N1NUMBER, if1.node.objid) tlvdata += coreapi.CoreLinkTlv.pack(coreapi.CORE_TLV_LINK_N2NUMBER, if2.node.objid) uni = False if if1.getparams() != if2.getparams(): uni = True tlvdata += self.netifparamstolink(if1) tlvdata += coreapi.CoreLinkTlv.pack(coreapi.CORE_TLV_LINK_TYPE, self.linktype) if uni: tlvdata += coreapi.CoreLinkTlv.pack(coreapi.CORE_TLV_LINK_UNI, 1) tlvdata += coreapi.CoreLinkTlv.pack(coreapi.CORE_TLV_LINK_IF1NUM, \ if1.node.getifindex(if1)) if if1.hwaddr: tlvdata += coreapi.CoreLinkTlv.pack(coreapi.CORE_TLV_LINK_IF1MAC, if1.hwaddr) for addr in if1.addrlist: (ip, sep, mask) = addr.partition('/') mask = int(mask) if isIPv4Address(ip): family = AF_INET tlvtypeip = coreapi.CORE_TLV_LINK_IF1IP4 tlvtypemask = coreapi.CORE_TLV_LINK_IF1IP4MASK else: family = AF_INET6 tlvtypeip = coreapi.CORE_TLV_LINK_IF1IP6 tlvtypemask = coreapi.CORE_TLV_LINK_IF1IP6MASK ipl = socket.inet_pton(family, ip) tlvdata += coreapi.CoreLinkTlv.pack(tlvtypeip, IPAddr(af=family, addr=ipl)) tlvdata += coreapi.CoreLinkTlv.pack(tlvtypemask, mask) tlvdata += coreapi.CoreLinkTlv.pack(coreapi.CORE_TLV_LINK_IF2NUM, \ if2.node.getifindex(if2)) if if2.hwaddr: tlvdata += coreapi.CoreLinkTlv.pack(coreapi.CORE_TLV_LINK_IF2MAC, if2.hwaddr) for addr in if2.addrlist: (ip, sep, mask) = addr.partition('/') mask = int(mask) if isIPv4Address(ip): family = AF_INET tlvtypeip = coreapi.CORE_TLV_LINK_IF2IP4 tlvtypemask = coreapi.CORE_TLV_LINK_IF2IP4MASK else: family = AF_INET6 tlvtypeip = coreapi.CORE_TLV_LINK_IF2IP6 tlvtypemask = coreapi.CORE_TLV_LINK_IF2IP6MASK ipl = socket.inet_pton(family, ip) tlvdata += coreapi.CoreLinkTlv.pack(tlvtypeip, IPAddr(af=family, addr=ipl)) tlvdata += coreapi.CoreLinkTlv.pack(tlvtypemask, mask) msg = coreapi.CoreLinkMessage.pack(flags, tlvdata) if not uni: return [msg,] # build a 2nd link message for the upstream link parameters # (swap if1 and if2) tlvdata = "" tlvdata += coreapi.CoreLinkTlv.pack(coreapi.CORE_TLV_LINK_N1NUMBER, if2.node.objid) tlvdata += coreapi.CoreLinkTlv.pack(coreapi.CORE_TLV_LINK_N2NUMBER, if1.node.objid) tlvdata += self.netifparamstolink(if2) tlvdata += coreapi.CoreLinkTlv.pack(coreapi.CORE_TLV_LINK_UNI, 1) tlvdata += coreapi.CoreLinkTlv.pack(coreapi.CORE_TLV_LINK_IF1NUM, \ if2.node.getifindex(if2)) tlvdata += coreapi.CoreLinkTlv.pack(coreapi.CORE_TLV_LINK_IF2NUM, \ if1.node.getifindex(if1)) msg2 = coreapi.CoreLinkMessage.pack(0, tlvdata) return [msg, msg2] class SwitchNode(LxBrNet): apitype = coreapi.CORE_NODE_SWITCH policy = "ACCEPT" type = "lanswitch" class HubNode(LxBrNet): apitype = coreapi.CORE_NODE_HUB policy = "ACCEPT" type = "hub" def __init__(self, session, objid = None, name = None, verbose = False, start = True): ''' the Hub node forwards packets to all bridge ports by turning off the MAC address learning ''' LxBrNet.__init__(self, session, objid, name, verbose, start) if start: check_call([BRCTL_BIN, "setageing", self.brname, "0"]) class WlanNode(LxBrNet): apitype = coreapi.CORE_NODE_WLAN linktype = coreapi.CORE_LINK_WIRELESS policy = "DROP" type = "wlan" def __init__(self, session, objid = None, name = None, verbose = False, start = True, policy = None): LxBrNet.__init__(self, session, objid, name, verbose, start, policy) # wireless model such as basic range self.model = None # mobility model such as scripted self.mobility = None def attach(self, netif): LxBrNet.attach(self, netif) if self.model: netif.poshook = self.model._positioncallback if netif.node is None: return (x,y,z) = netif.node.position.get() # invokes any netif.poshook netif.setposition(x, y, z) #self.model.setlinkparams() def setmodel(self, model, config): ''' Mobility and wireless model. ''' if (self.verbose): self.info("adding model %s" % model._name) if model._type == coreapi.CORE_TLV_REG_WIRELESS: self.model = model(session=self.session, objid=self.objid, verbose=self.verbose, values=config) if self.model._positioncallback: for netif in self.netifs(): netif.poshook = self.model._positioncallback if netif.node is not None: (x,y,z) = netif.node.position.get() netif.poshook(netif, x, y, z) self.model.setlinkparams() elif model._type == coreapi.CORE_TLV_REG_MOBILITY: self.mobility = model(session=self.session, objid=self.objid, verbose=self.verbose, values=config) def updatemodel(self, model_name, values): ''' Allow for model updates during runtime (similar to setmodel().) ''' if (self.verbose): self.info("updating model %s" % model_name) if self.model is None or self.model._name != model_name: return model = self.model if model._type == coreapi.CORE_TLV_REG_WIRELESS: if not model.updateconfig(values): return if self.model._positioncallback: for netif in self.netifs(): netif.poshook = self.model._positioncallback if netif.node is not None: (x,y,z) = netif.node.position.get() netif.poshook(netif, x, y, z) self.model.setlinkparams() def tolinkmsgs(self, flags): msgs = LxBrNet.tolinkmsgs(self, flags) if self.model: msgs += self.model.tolinkmsgs(flags) return msgs class RJ45Node(PyCoreNode, PyCoreNetIf): ''' RJ45Node is a physical interface on the host linked to the emulated network. ''' apitype = coreapi.CORE_NODE_RJ45 type = "rj45" def __init__(self, session, objid = None, name = None, mtu = 1500, verbose = False, start = True): PyCoreNode.__init__(self, session, objid, name, verbose=verbose, start=start) # this initializes net, params, poshook PyCoreNetIf.__init__(self, node=self, name=name, mtu = mtu) self.up = False self.lock = threading.RLock() self.ifindex = None # the following are PyCoreNetIf attributes self.transport_type = "raw" self.localname = name if start: self.startup() def startup(self): ''' Set the interface in the up state. ''' # interface will also be marked up during net.attach() self.savestate() try: check_call([IP_BIN, "link", "set", self.localname, "up"]) except: self.warn("Failed to run command: %s link set %s up" % \ (IP_BIN, self.localname)) return self.up = True def shutdown(self): ''' Bring the interface down. Remove any addresses and queuing disciplines. ''' if not self.up: return check_call([IP_BIN, "link", "set", self.localname, "down"]) check_call([IP_BIN, "addr", "flush", "dev", self.localname]) mutecall([TC_BIN, "qdisc", "del", "dev", self.localname, "root"]) self.up = False self.restorestate() def attachnet(self, net): PyCoreNetIf.attachnet(self, net) def detachnet(self): PyCoreNetIf.detachnet(self) def newnetif(self, net = None, addrlist = [], hwaddr = None, ifindex = None, ifname = None): ''' This is called when linking with another node. Since this node represents an interface, we do not create another object here, but attach ourselves to the given network. ''' self.lock.acquire() try: if ifindex is None: ifindex = 0 if self.net is not None: raise ValueError, \ "RJ45 nodes support at most 1 network interface" self._netif[ifindex] = self self.node = self # PyCoreNetIf.node is self self.ifindex = ifindex if net is not None: self.attachnet(net) for addr in maketuple(addrlist): self.addaddr(addr) return ifindex finally: self.lock.release() def delnetif(self, ifindex): if ifindex is None: ifindex = 0 if ifindex not in self._netif: raise ValueError, "ifindex %s does not exist" % ifindex self._netif.pop(ifindex) if ifindex == self.ifindex: self.shutdown() else: raise ValueError, "ifindex %s does not exist" % ifindex def netif(self, ifindex, net=None): ''' This object is considered the network interface, so we only return self here. This keeps the RJ45Node compatible with real nodes. ''' if net is not None and net == self.net: return self if ifindex is None: ifindex = 0 if ifindex == self.ifindex: return self return None def getifindex(self, netif): if netif != self: return None return self.ifindex def addaddr(self, addr): if self.up: check_call([IP_BIN, "addr", "add", str(addr), "dev", self.name]) PyCoreNetIf.addaddr(self, addr) def deladdr(self, addr): if self.up: check_call([IP_BIN, "addr", "del", str(addr), "dev", self.name]) PyCoreNetIf.deladdr(self, addr) def savestate(self): ''' Save the addresses and other interface state before using the interface for emulation purposes. TODO: save/restore the PROMISC flag ''' self.old_up = False self.old_addrs = [] cmd = [IP_BIN, "addr", "show", "dev", self.localname] try: tmp = subprocess.Popen(cmd, stdout = subprocess.PIPE) except OSError: self.warn("Failed to run %s command: %s" % (IP_BIN, cmd)) if tmp.wait(): self.warn("Command failed: %s" % cmd) return lines = tmp.stdout.read() tmp.stdout.close() for l in lines.split('\n'): items = l.split() if len(items) < 2: continue if items[1] == "%s:" % self.localname: flags = items[2][1:-1].split(',') if "UP" in flags: self.old_up = True elif items[0] == "inet": self.old_addrs.append((items[1], items[3])) elif items[0] == "inet6": if items[1][:4] == "fe80": continue self.old_addrs.append((items[1], None)) def restorestate(self): ''' Restore the addresses and other interface state after using it. ''' for addr in self.old_addrs: if addr[1] is None: check_call([IP_BIN, "addr", "add", addr[0], "dev", self.localname]) else: check_call([IP_BIN, "addr", "add", addr[0], "brd", addr[1], "dev", self.localname]) if self.old_up: check_call([IP_BIN, "link", "set", self.localname, "up"]) def setposition(self, x=None, y=None, z=None): ''' Use setposition() from both parent classes. ''' PyCoreObj.setposition(self, x, y, z) # invoke any poshook PyCoreNetIf.setposition(self, x, y, z) class TunnelNode(GreTapBridge): apitype = coreapi.CORE_NODE_TUNNEL policy = "ACCEPT" type = "tunnel" core-4.8/daemon/core/netns/vif.py0000664000175000017500000001553712534327775013752 00000000000000# # CORE # Copyright (c)2011-2014 the Boeing Company. # See the LICENSE file included in this distribution. # # authors: Tom Goff # Jeff Ahrenholz # ''' vif.py: PyCoreNetIf classes that implement the interfaces available under Linux. ''' import os, signal, shutil, sys, subprocess, vnodeclient, threading, string import random, time from core.api import coreapi from core.misc.utils import * from core.constants import * from core.coreobj import PyCoreObj, PyCoreNode, PyCoreNetIf, Position from core.emane.nodes import EmaneNode checkexec([IP_BIN]) class VEth(PyCoreNetIf): def __init__(self, node, name, localname, mtu = 1500, net = None, start = True): # note that net arg is ignored PyCoreNetIf.__init__(self, node = node, name = name, mtu = mtu) self.localname = localname self.up = False if start: self.startup() def startup(self): check_call([IP_BIN, "link", "add", "name", self.localname, "type", "veth", "peer", "name", self.name]) check_call([IP_BIN, "link", "set", self.localname, "up"]) self.up = True def shutdown(self): if not self.up: return if self.node: self.node.cmd([IP_BIN, "-6", "addr", "flush", "dev", self.name]) if self.localname: mutedetach([IP_BIN, "link", "delete", self.localname]) self.up = False class TunTap(PyCoreNetIf): ''' TUN/TAP virtual device in TAP mode ''' def __init__(self, node, name, localname, mtu = 1500, net = None, start = True): PyCoreNetIf.__init__(self, node = node, name = name, mtu = mtu) self.localname = localname self.up = False self.transport_type = "virtual" if start: self.startup() def startup(self): # TODO: more sophisticated TAP creation here # Debian does not support -p (tap) option, RedHat does. # For now, this is disabled to allow the TAP to be created by another # system (e.g. EMANE's emanetransportd) #check_call(["tunctl", "-t", self.name]) # self.install() self.up = True def shutdown(self): if not self.up: return self.node.cmd([IP_BIN, "-6", "addr", "flush", "dev", self.name]) #if self.name: # mutedetach(["tunctl", "-d", self.localname]) self.up = False def waitfor(self, func, attempts = 10, maxretrydelay = 0.25): '''\ Wait for func() to return zero with exponential backoff ''' delay = 0.01 for i in xrange(1, attempts + 1): r = func() if r == 0: return msg = 'attempt %s failed with nonzero exit status %s' % (i, r) if i < attempts + 1: msg += ', retrying...' self.node.info(msg) time.sleep(delay) delay = delay + delay if delay > maxretrydelay: delay = maxretrydelay else: msg += ', giving up' self.node.info(msg) raise RuntimeError, 'command failed after %s attempts' % attempts def waitfordevicelocal(self): '''\ Check for presence of a local device - tap device may not appear right away waits ''' def localdevexists(): cmd = (IP_BIN, 'link', 'show', self.localname) return mutecall(cmd) self.waitfor(localdevexists) def waitfordevicenode(self): '''\ Check for presence of a node device - tap device may not appear right away waits ''' def nodedevexists(): cmd = (IP_BIN, 'link', 'show', self.name) return self.node.cmd(cmd) self.waitfor(nodedevexists) def install(self): ''' Install this TAP into its namespace. This is not done from the startup() method but called at a later time when a userspace program (running on the host) has had a chance to open the socket end of the TAP. ''' self.waitfordevicelocal() netns = str(self.node.pid) try: check_call([IP_BIN, "link", "set", self.localname, "netns", netns]) except Exception, e: msg = "error installing TAP interface %s, command:" % self.localname msg += "ip link set %s netns %s" % (self.localname, netns) self.node.exception(coreapi.CORE_EXCP_LEVEL_ERROR, self.localname, msg) self.node.warn(msg) return self.node.cmd([IP_BIN, "link", "set", self.localname, "name", self.name]) self.node.cmd([IP_BIN, "link", "set", self.name, "up"]) def setaddrs(self): ''' Set interface addresses based on self.addrlist. ''' self.waitfordevicenode() for addr in self.addrlist: self.node.cmd([IP_BIN, "addr", "add", str(addr), "dev", self.name]) class GreTap(PyCoreNetIf): ''' GRE TAP device for tunneling between emulation servers. Uses the "gretap" tunnel device type from Linux which is a GRE device having a MAC address. The MAC address is required for bridging. ''' def __init__(self, node = None, name = None, session = None, mtu = 1458, remoteip = None, objid = None, localip = None, ttl = 255, key = None, start = True): PyCoreNetIf.__init__(self, node = node, name = name, mtu = mtu) self.session = session if objid is None: # from PyCoreObj objid = (((id(self) >> 16) ^ (id(self) & 0xffff)) & 0xffff) self.objid = objid sessionid = self.session.shortsessionid() # interface name on the local host machine self.localname = "gt.%s.%s" % (self.objid, sessionid) self.transport_type = "raw" if not start: self.up = False return if remoteip is None: raise ValueError, "missing remote IP required for GRE TAP device" cmd = ("ip", "link", "add", self.localname, "type", "gretap", "remote", str(remoteip)) if localip: cmd += ("local", str(localip)) if ttl: cmd += ("ttl", str(ttl)) if key: cmd += ("key", str(key)) check_call(cmd) cmd = ("ip", "link", "set", self.localname, "up") check_call(cmd) self.up = True def shutdown(self): if self.localname: cmd = ("ip", "link", "set", self.localname, "down") check_call(cmd) cmd = ("ip", "link", "del", self.localname) check_call(cmd) self.localname = None def tonodemsg(self, flags): return None def tolinkmsgs(self, flags): return [] core-4.8/daemon/core/netns/vnet.py0000664000175000017500000004770712534327775014146 00000000000000# # CORE # Copyright (c)2010-2012 the Boeing Company. # See the LICENSE file included in this distribution. # # authors: Tom Goff # Jeff Ahrenholz # ''' vnet.py: PyCoreNet and LxBrNet classes that implement virtual networks using Linux Ethernet bridging and ebtables rules. ''' import os, sys, threading, time, subprocess from core.api import coreapi from core.misc.utils import * from core.constants import * from core.coreobj import PyCoreNet, PyCoreObj from core.netns.vif import VEth, GreTap checkexec([BRCTL_BIN, IP_BIN, EBTABLES_BIN, TC_BIN]) ebtables_lock = threading.Lock() class EbtablesQueue(object): ''' Helper class for queuing up ebtables commands into rate-limited atomic commits. This improves performance and reliability when there are many WLAN link updates. ''' # update rate is every 300ms rate = 0.3 # ebtables atomic_file = "/tmp/pycore.ebtables.atomic" def __init__(self): ''' Initialize the helper class, but don't start the update thread until a WLAN is instantiated. ''' self.doupdateloop = False self.updatethread = None # this lock protects cmds and updates lists self.updatelock = threading.Lock() # list of pending ebtables commands self.cmds = [] # list of WLANs requiring update self.updates = [] # timestamps of last WLAN update; this keeps track of WLANs that are # using this queue self.last_update_time = {} def startupdateloop(self, wlan): ''' Kick off the update loop; only needs to be invoked once. ''' self.updatelock.acquire() self.last_update_time[wlan] = time.time() self.updatelock.release() if self.doupdateloop: return self.doupdateloop = True self.updatethread = threading.Thread(target = self.updateloop) self.updatethread.daemon = True self.updatethread.start() def stopupdateloop(self, wlan): ''' Kill the update loop thread if there are no more WLANs using it. ''' self.updatelock.acquire() try: del self.last_update_time[wlan] except KeyError: pass self.updatelock.release() if len(self.last_update_time) > 0: return self.doupdateloop = False if self.updatethread: self.updatethread.join() self.updatethread = None def ebatomiccmd(self, cmd): ''' Helper for building ebtables atomic file command list. ''' r = [EBTABLES_BIN, "--atomic-file", self.atomic_file] if cmd: r.extend(cmd) return r def lastupdate(self, wlan): ''' Return the time elapsed since this WLAN was last updated. ''' try: elapsed = time.time() - self.last_update_time[wlan] except KeyError: self.last_update_time[wlan] = time.time() elapsed = 0.0 return elapsed def updated(self, wlan): ''' Keep track of when this WLAN was last updated. ''' self.last_update_time[wlan] = time.time() self.updates.remove(wlan) def updateloop(self): ''' Thread target that looks for WLANs needing update, and rate limits the amount of ebtables activity. Only one userspace program should use ebtables at any given time, or results can be unpredictable. ''' while self.doupdateloop: self.updatelock.acquire() for wlan in self.updates: if self.lastupdate(wlan) > self.rate: self.buildcmds(wlan) #print "ebtables commit %d rules" % len(self.cmds) self.ebcommit(wlan) self.updated(wlan) self.updatelock.release() time.sleep(self.rate) def ebcommit(self, wlan): ''' Perform ebtables atomic commit using commands built in the self.cmds list. ''' # save kernel ebtables snapshot to a file cmd = self.ebatomiccmd(["--atomic-save",]) try: check_call(cmd) except Exception, e: self.eberror(wlan, "atomic-save (%s)" % cmd, e) # no atomic file, exit return # modify the table file using queued ebtables commands for c in self.cmds: cmd = self.ebatomiccmd(c) try: check_call(cmd) except Exception, e: self.eberror(wlan, "cmd=%s" % cmd, e) pass self.cmds = [] # commit the table file to the kernel cmd = self.ebatomiccmd(["--atomic-commit",]) try: check_call(cmd) os.unlink(self.atomic_file) except Exception, e: self.eberror(wlan, "atomic-commit (%s)" % cmd, e) def ebchange(self, wlan): ''' Flag a change to the given WLAN's _linked dict, so the ebtables chain will be rebuilt at the next interval. ''' self.updatelock.acquire() if wlan not in self.updates: self.updates.append(wlan) self.updatelock.release() def buildcmds(self, wlan): ''' Inspect a _linked dict from a wlan, and rebuild the ebtables chain for that WLAN. ''' wlan._linked_lock.acquire() # flush the chain self.cmds.extend([["-F", wlan.brname],]) # rebuild the chain for (netif1, v) in wlan._linked.items(): for (netif2, linked) in v.items(): if wlan.policy == "DROP" and linked: self.cmds.extend([["-A", wlan.brname, "-i", netif1.localname, "-o", netif2.localname, "-j", "ACCEPT"], ["-A", wlan.brname, "-o", netif1.localname, "-i", netif2.localname, "-j", "ACCEPT"]]) elif wlan.policy == "ACCEPT" and not linked: self.cmds.extend([["-A", wlan.brname, "-i", netif1.localname, "-o", netif2.localname, "-j", "DROP"], ["-A", wlan.brname, "-o", netif1.localname, "-i", netif2.localname, "-j", "DROP"]]) wlan._linked_lock.release() def eberror(self, wlan, source, error): ''' Log an ebtables command error and send an exception. ''' if not wlan: return wlan.exception(coreapi.CORE_EXCP_LEVEL_ERROR, wlan.brname, "ebtables command error: %s\n%s\n" % (source, error)) # a global object because all WLANs share the same queue # cannot have multiple threads invoking the ebtables commnd ebq = EbtablesQueue() def ebtablescmds(call, cmds): ebtables_lock.acquire() try: for cmd in cmds: call(cmd) finally: ebtables_lock.release() class LxBrNet(PyCoreNet): policy = "DROP" def __init__(self, session, objid = None, name = None, verbose = False, start = True, policy = None): PyCoreNet.__init__(self, session, objid, name, verbose, start) if name is None: name = str(self.objid) if policy is not None: self.policy = policy self.name = name sessionid = self.session.shortsessionid() self.brname = "b.%s.%s" % (str(self.objid), sessionid) self.up = False if start: self.startup() ebq.startupdateloop(self) def startup(self): try: check_call([BRCTL_BIN, "addbr", self.brname]) except Exception, e: self.exception(coreapi.CORE_EXCP_LEVEL_FATAL, self.brname, "Error adding bridge: %s" % e) try: # turn off spanning tree protocol and forwarding delay check_call([BRCTL_BIN, "stp", self.brname, "off"]) check_call([BRCTL_BIN, "setfd", self.brname, "0"]) check_call([IP_BIN, "link", "set", self.brname, "up"]) # create a new ebtables chain for this bridge ebtablescmds(check_call, [ [EBTABLES_BIN, "-N", self.brname, "-P", self.policy], [EBTABLES_BIN, "-A", "FORWARD", "--logical-in", self.brname, "-j", self.brname]]) # turn off multicast snooping so mcast forwarding occurs w/o IGMP joins snoop = "/sys/devices/virtual/net/%s/bridge/multicast_snooping" % \ self.brname if os.path.exists(snoop): open(snoop, "w").write('0') except Exception, e: self.exception(coreapi.CORE_EXCP_LEVEL_WARNING, self.brname, "Error setting bridge parameters: %s" % e) self.up = True def shutdown(self): if not self.up: return ebq.stopupdateloop(self) mutecall([IP_BIN, "link", "set", self.brname, "down"]) mutecall([BRCTL_BIN, "delbr", self.brname]) ebtablescmds(mutecall, [ [EBTABLES_BIN, "-D", "FORWARD", "--logical-in", self.brname, "-j", self.brname], [EBTABLES_BIN, "-X", self.brname]]) for netif in self.netifs(): # removes veth pairs used for bridge-to-bridge connections netif.shutdown() self._netif.clear() self._linked.clear() del self.session self.up = False def attach(self, netif): if self.up: try: check_call([BRCTL_BIN, "addif", self.brname, netif.localname]) check_call([IP_BIN, "link", "set", netif.localname, "up"]) except Exception, e: self.exception(coreapi.CORE_EXCP_LEVEL_ERROR, self.brname, "Error joining interface %s to bridge %s: %s" % \ (netif.localname, self.brname, e)) return PyCoreNet.attach(self, netif) def detach(self, netif): if self.up: try: check_call([BRCTL_BIN, "delif", self.brname, netif.localname]) except Exception, e: self.exception(coreapi.CORE_EXCP_LEVEL_ERROR, self.brname, "Error removing interface %s from bridge %s: %s" % \ (netif.localname, self.brname, e)) return PyCoreNet.detach(self, netif) def linked(self, netif1, netif2): # check if the network interfaces are attached to this network if self._netif[netif1.netifi] != netif1: raise ValueError, "inconsistency for netif %s" % netif1.name if self._netif[netif2.netifi] != netif2: raise ValueError, "inconsistency for netif %s" % netif2.name try: linked = self._linked[netif1][netif2] except KeyError: if self.policy == "ACCEPT": linked = True elif self.policy == "DROP": linked = False else: raise Exception, "unknown policy: %s" % self.policy self._linked[netif1][netif2] = linked return linked def unlink(self, netif1, netif2): ''' Unlink two PyCoreNetIfs, resulting in adding or removing ebtables filtering rules. ''' self._linked_lock.acquire() if not self.linked(netif1, netif2): self._linked_lock.release() return self._linked[netif1][netif2] = False self._linked_lock.release() ebq.ebchange(self) def link(self, netif1, netif2): ''' Link two PyCoreNetIfs together, resulting in adding or removing ebtables filtering rules. ''' self._linked_lock.acquire() if self.linked(netif1, netif2): self._linked_lock.release() return self._linked[netif1][netif2] = True self._linked_lock.release() ebq.ebchange(self) def linkconfig(self, netif, bw = None, delay = None, loss = None, duplicate = None, jitter = None, netif2 = None, devname = None): ''' Configure link parameters by applying tc queuing disciplines on the interface. ''' if devname is None: devname = netif.localname tc = [TC_BIN, "qdisc", "replace", "dev", devname] parent = ["root"] changed = False if netif.setparam('bw', bw): # from tc-tbf(8): minimum value for burst is rate / kernel_hz if bw is not None: burst = max(2 * netif.mtu, bw / 1000) limit = 0xffff # max IP payload tbf = ["tbf", "rate", str(bw), "burst", str(burst), "limit", str(limit)] if bw > 0: if self.up: if (self.verbose): self.info("linkconfig: %s" % \ ([tc + parent + ["handle", "1:"] + tbf],)) check_call(tc + parent + ["handle", "1:"] + tbf) netif.setparam('has_tbf', True) changed = True elif netif.getparam('has_tbf') and bw <= 0: tcd = [] + tc tcd[2] = "delete" if self.up: check_call(tcd + parent) netif.setparam('has_tbf', False) # removing the parent removes the child netif.setparam('has_netem', False) changed = True if netif.getparam('has_tbf'): parent = ["parent", "1:1"] netem = ["netem"] changed = max(changed, netif.setparam('delay', delay)) if loss is not None: loss = float(loss) changed = max(changed, netif.setparam('loss', loss)) if duplicate is not None: duplicate = float(duplicate) changed = max(changed, netif.setparam('duplicate', duplicate)) changed = max(changed, netif.setparam('jitter', jitter)) if not changed: return # jitter and delay use the same delay statement if delay is not None: netem += ["delay", "%sus" % delay] if jitter is not None: if delay is None: netem += ["delay", "0us", "%sus" % jitter, "25%"] else: netem += ["%sus" % jitter, "25%"] if loss is not None: netem += ["loss", "%s%%" % min(loss, 100)] if duplicate is not None: netem += ["duplicate", "%s%%" % min(duplicate, 100)] if delay <= 0 and jitter <= 0 and loss <= 0 and duplicate <= 0: # possibly remove netem if it exists and parent queue wasn't removed if not netif.getparam('has_netem'): return tc[2] = "delete" if self.up: if self.verbose: self.info("linkconfig: %s" % \ ([tc + parent + ["handle", "10:"]],)) check_call(tc + parent + ["handle", "10:"]) netif.setparam('has_netem', False) elif len(netem) > 1: if self.up: if self.verbose: self.info("linkconfig: %s" % \ ([tc + parent + ["handle", "10:"] + netem],)) check_call(tc + parent + ["handle", "10:"] + netem) netif.setparam('has_netem', True) def linknet(self, net): ''' Link this bridge with another by creating a veth pair and installing each device into each bridge. ''' sessionid = self.session.shortsessionid() try: self_objid = '%x' % self.objid except TypeError: self_objid = '%s' % self.objid try: net_objid = '%x' % net.objid except TypeError: net_objid = '%s' % net.objid localname = 'veth%s.%s.%s' % (self_objid, net_objid, sessionid) if len(localname) >= 16: raise ValueError, "interface local name '%s' too long" % \ localname name = 'veth%s.%s.%s' % (net_objid, self_objid, sessionid) if len(name) >= 16: raise ValueError, "interface name '%s' too long" % name netif = VEth(node = None, name = name, localname = localname, mtu = 1500, net = self, start = self.up) self.attach(netif) if net.up: # this is similar to net.attach() but uses netif.name instead # of localname check_call([BRCTL_BIN, "addif", net.brname, netif.name]) check_call([IP_BIN, "link", "set", netif.name, "up"]) i = net.newifindex() net._netif[i] = netif with net._linked_lock: net._linked[netif] = {} netif.net = self netif.othernet = net return netif def getlinknetif(self, net): ''' Return the interface of that links this net with another net (that were linked using linknet()). ''' for netif in self.netifs(): if hasattr(netif, 'othernet') and netif.othernet == net: return netif return None def addrconfig(self, addrlist): ''' Set addresses on the bridge. ''' if not self.up: return for addr in addrlist: try: check_call([IP_BIN, "addr", "add", str(addr), "dev", self.brname]) except Exception, e: self.exception(coreapi.CORE_EXCP_LEVEL_ERROR, self.brname, "Error adding IP address: %s" % e) class GreTapBridge(LxBrNet): ''' A network consisting of a bridge with a gretap device for tunneling to another system. ''' def __init__(self, session, remoteip = None, objid = None, name = None, policy = "ACCEPT", localip = None, ttl = 255, key = None, verbose = False, start = True): LxBrNet.__init__(self, session = session, objid = objid, name = name, verbose = verbose, policy = policy, start = False) self.grekey = key if self.grekey is None: self.grekey = self.session.sessionid ^ self.objid self.localnum = None self.remotenum = None self.remoteip = remoteip self.localip = localip self.ttl = ttl if remoteip is None: self.gretap = None else: self.gretap = GreTap(node = self, name = None, session = session, remoteip = remoteip, objid = None, localip = localip, ttl = ttl, key = self.grekey) if start: self.startup() def startup(self): ''' Creates a bridge and adds the gretap device to it. ''' LxBrNet.startup(self) if self.gretap: self.attach(self.gretap) def shutdown(self): ''' Detach the gretap device and remove the bridge. ''' if self.gretap: self.detach(self.gretap) self.gretap.shutdown() self.gretap = None LxBrNet.shutdown(self) def addrconfig(self, addrlist): ''' Set the remote tunnel endpoint. This is a one-time method for creating the GreTap device, which requires the remoteip at startup. The 1st address in the provided list is remoteip, 2nd optionally specifies localip. ''' if self.gretap: raise ValueError, "gretap already exists for %s" % self.name remoteip = addrlist[0].split('/')[0] localip = None if len(addrlist) > 1: localip = addrlist[1].split('/')[0] self.gretap = GreTap(session = self.session, remoteip = remoteip, objid = None, name = None, localip = localip, ttl = self.ttl, key = self.grekey) self.attach(self.gretap) def setkey(self, key): ''' Set the GRE key used for the GreTap device. This needs to be set prior to instantiating the GreTap device (before addrconfig). ''' self.grekey = key core-4.8/daemon/core/netns/vnode.py0000664000175000017500000003607112534327775014275 00000000000000# # CORE # Copyright (c)2010-2012 the Boeing Company. # See the LICENSE file included in this distribution. # # authors: Tom Goff # Jeff Ahrenholz # ''' vnode.py: PyCoreNode and LxcNode classes that implement the network namespace virtual node. ''' import os, signal, sys, subprocess, vnodeclient, threading, string, shutil import random, time from core.api import coreapi from core.misc.utils import * from core.constants import * from core.coreobj import PyCoreObj, PyCoreNode, PyCoreNetIf, Position from core.netns.vif import VEth, TunTap from core.emane.nodes import EmaneNode checkexec([IP_BIN]) class SimpleLxcNode(PyCoreNode): def __init__(self, session, objid = None, name = None, nodedir = None, verbose = False, start = True): PyCoreNode.__init__(self, session, objid, name, verbose=verbose, start=start) self.nodedir = nodedir self.ctrlchnlname = \ os.path.abspath(os.path.join(self.session.sessiondir, self.name)) self.vnodeclient = None self.pid = None self.up = False self.lock = threading.RLock() self._mounts = [] def alive(self): try: os.kill(self.pid, 0) except OSError: return False return True def startup(self): ''' Start a new namespace node by invoking the vnoded process that allocates a new namespace. Bring up the loopback device and set the hostname. ''' if self.up: raise Exception, "already up" vnoded = ["%s/vnoded" % CORE_SBIN_DIR, "-v", "-c", self.ctrlchnlname, "-l", self.ctrlchnlname + ".log", "-p", self.ctrlchnlname + ".pid"] if self.nodedir: vnoded += ["-C", self.nodedir] env = self.session.getenviron(state=False) env['NODE_NUMBER'] = str(self.objid) env['NODE_NAME'] = str(self.name) try: tmp = subprocess.Popen(vnoded, stdout = subprocess.PIPE, env = env) except OSError, e: msg = "error running vnoded command: %s (%s)" % (vnoded, e) self.exception(coreapi.CORE_EXCP_LEVEL_FATAL, "SimpleLxcNode.startup()", msg) raise Exception, msg try: self.pid = int(tmp.stdout.read()) tmp.stdout.close() except Exception: msg = "vnoded failed to create a namespace; " msg += "check kernel support and user priveleges" self.exception(coreapi.CORE_EXCP_LEVEL_FATAL, "SimpleLxcNode.startup()", msg) if tmp.wait(): raise Exception, ("command failed: %s" % vnoded) self.vnodeclient = vnodeclient.VnodeClient(self.name, self.ctrlchnlname) self.info("bringing up loopback interface") self.cmd([IP_BIN, "link", "set", "lo", "up"]) self.info("setting hostname: %s" % self.name) self.cmd(["hostname", self.name]) self.up = True def shutdown(self): if not self.up: return while self._mounts: source, target = self._mounts.pop(-1) self.umount(target) #print "XXX del vnodeclient:", self.vnodeclient # XXX XXX XXX this causes a serious crash #del self.vnodeclient for netif in self.netifs(): netif.shutdown() try: os.kill(self.pid, signal.SIGTERM) os.waitpid(self.pid, 0) except OSError: pass try: os.unlink(self.ctrlchnlname) except OSError: pass self._netif.clear() #del self.session # print "XXX del vnodeclient:", self.vnodeclient del self.vnodeclient self.up = False def cmd(self, args, wait = True): return self.vnodeclient.cmd(args, wait) def cmdresult(self, args): return self.vnodeclient.cmdresult(args) def popen(self, args): return self.vnodeclient.popen(args) def icmd(self, args): return self.vnodeclient.icmd(args) def redircmd(self, infd, outfd, errfd, args, wait = True): return self.vnodeclient.redircmd(infd, outfd, errfd, args, wait) def term(self, sh = "/bin/sh"): return self.vnodeclient.term(sh = sh) def termcmdstring(self, sh = "/bin/sh"): return self.vnodeclient.termcmdstring(sh = sh) def shcmd(self, cmdstr, sh = "/bin/sh"): return self.vnodeclient.shcmd(cmdstr, sh = sh) def boot(self): pass def mount(self, source, target): source = os.path.abspath(source) self.info("mounting %s at %s" % (source, target)) try: shcmd = "mkdir -p '%s' && %s -n --bind '%s' '%s'" % \ (target, MOUNT_BIN, source, target) self.shcmd(shcmd) self._mounts.append((source, target)) except: self.warn("mounting failed for %s at %s" % (source, target)) def umount(self, target): self.info("unmounting '%s'" % target) try: self.cmd([UMOUNT_BIN, "-n", "-l", target]) except: self.warn("unmounting failed for %s" % target) def newifindex(self): with self.lock: return PyCoreNode.newifindex(self) def newveth(self, ifindex = None, ifname = None, net = None): self.lock.acquire() try: if ifindex is None: ifindex = self.newifindex() if ifname is None: ifname = "eth%d" % ifindex sessionid = self.session.shortsessionid() try: suffix = '%x.%s.%s' % (self.objid, ifindex, sessionid) except TypeError: suffix = '%s.%s.%s' % (self.objid, ifindex, sessionid) localname = 'veth' + suffix if len(localname) >= 16: raise ValueError, "interface local name '%s' too long" % \ localname name = localname + 'p' if len(name) >= 16: raise ValueError, "interface name '%s' too long" % name ifclass = VEth veth = ifclass(node = self, name = name, localname = localname, mtu = 1500, net = net, start = self.up) if self.up: check_call([IP_BIN, "link", "set", veth.name, "netns", str(self.pid)]) self.cmd([IP_BIN, "link", "set", veth.name, "name", ifname]) veth.name = ifname try: self.addnetif(veth, ifindex) except: veth.shutdown() del veth raise return ifindex finally: self.lock.release() def newtuntap(self, ifindex = None, ifname = None, net = None): self.lock.acquire() try: if ifindex is None: ifindex = self.newifindex() if ifname is None: ifname = "eth%d" % ifindex sessionid = self.session.shortsessionid() localname = "tap%s.%s.%s" % (self.objid, ifindex, sessionid) name = ifname ifclass = TunTap tuntap = ifclass(node = self, name = name, localname = localname, mtu = 1500, net = net, start = self.up) try: self.addnetif(tuntap, ifindex) except: tuntap.shutdown() del tuntap raise return ifindex finally: self.lock.release() def sethwaddr(self, ifindex, addr): self._netif[ifindex].sethwaddr(addr) if self.up: (status, result) = self.cmdresult([IP_BIN, "link", "set", "dev", self.ifname(ifindex), "address", str(addr)]) if status: self.exception(coreapi.CORE_EXCP_LEVEL_ERROR, "SimpleLxcNode.sethwaddr()", "error setting MAC address %s" % str(addr)) def addaddr(self, ifindex, addr): if self.up: self.cmd([IP_BIN, "addr", "add", str(addr), "dev", self.ifname(ifindex)]) self._netif[ifindex].addaddr(addr) def deladdr(self, ifindex, addr): try: self._netif[ifindex].deladdr(addr) except ValueError: self.warn("trying to delete unknown address: %s" % addr) if self.up: self.cmd([IP_BIN, "addr", "del", str(addr), "dev", self.ifname(ifindex)]) valid_deladdrtype = ("inet", "inet6", "inet6link") def delalladdr(self, ifindex, addrtypes = valid_deladdrtype): addr = self.getaddr(self.ifname(ifindex), rescan = True) for t in addrtypes: if t not in self.valid_deladdrtype: raise ValueError, "addr type must be in: " + \ " ".join(self.valid_deladdrtype) for a in addr[t]: self.deladdr(ifindex, a) # update cached information self.getaddr(self.ifname(ifindex), rescan = True) def ifup(self, ifindex): if self.up: self.cmd([IP_BIN, "link", "set", self.ifname(ifindex), "up"]) def newnetif(self, net = None, addrlist = [], hwaddr = None, ifindex = None, ifname = None): self.lock.acquire() try: if isinstance(net, EmaneNode): ifindex = self.newtuntap(ifindex = ifindex, ifname = ifname, net = net) # TUN/TAP is not ready for addressing yet; the device may # take some time to appear, and installing it into a # namespace after it has been bound removes addressing; # save addresses with the interface now self.attachnet(ifindex, net) netif = self.netif(ifindex) netif.sethwaddr(hwaddr) for addr in maketuple(addrlist): netif.addaddr(addr) return ifindex else: ifindex = self.newveth(ifindex = ifindex, ifname = ifname, net = net) if net is not None: self.attachnet(ifindex, net) if hwaddr: self.sethwaddr(ifindex, hwaddr) for addr in maketuple(addrlist): self.addaddr(ifindex, addr) self.ifup(ifindex) return ifindex finally: self.lock.release() def connectnode(self, ifname, othernode, otherifname): tmplen = 8 tmp1 = "tmp." + "".join([random.choice(string.ascii_lowercase) for x in xrange(tmplen)]) tmp2 = "tmp." + "".join([random.choice(string.ascii_lowercase) for x in xrange(tmplen)]) check_call([IP_BIN, "link", "add", "name", tmp1, "type", "veth", "peer", "name", tmp2]) check_call([IP_BIN, "link", "set", tmp1, "netns", str(self.pid)]) self.cmd([IP_BIN, "link", "set", tmp1, "name", ifname]) self.addnetif(PyCoreNetIf(self, ifname), self.newifindex()) check_call([IP_BIN, "link", "set", tmp2, "netns", str(othernode.pid)]) othernode.cmd([IP_BIN, "link", "set", tmp2, "name", otherifname]) othernode.addnetif(PyCoreNetIf(othernode, otherifname), othernode.newifindex()) def addfile(self, srcname, filename): shcmd = "mkdir -p $(dirname '%s') && mv '%s' '%s' && sync" % \ (filename, srcname, filename) self.shcmd(shcmd) def getaddr(self, ifname, rescan = False): return self.vnodeclient.getaddr(ifname = ifname, rescan = rescan) def netifstats(self, ifname = None): return self.vnodeclient.netifstats(ifname = ifname) class LxcNode(SimpleLxcNode): def __init__(self, session, objid = None, name = None, nodedir = None, bootsh = "boot.sh", verbose = False, start = True): super(LxcNode, self).__init__(session = session, objid = objid, name = name, nodedir = nodedir, verbose = verbose, start = start) self.bootsh = bootsh if start: self.startup() def boot(self): self.session.services.bootnodeservices(self) def validate(self): self.session.services.validatenodeservices(self) def startup(self): self.lock.acquire() try: self.makenodedir() super(LxcNode, self).startup() self.privatedir("/var/run") self.privatedir("/var/log") except OSError, e: self.warn("Error with LxcNode.startup(): %s" % e) self.exception(coreapi.CORE_EXCP_LEVEL_ERROR, "LxcNode.startup()", "%s" % e) finally: self.lock.release() def shutdown(self): if not self.up: return self.lock.acquire() # services are instead stopped when session enters datacollect state #self.session.services.stopnodeservices(self) try: super(LxcNode, self).shutdown() finally: self.rmnodedir() self.lock.release() def privatedir(self, path): if path[0] != "/": raise ValueError, "path not fully qualified: " + path hostpath = os.path.join(self.nodedir, path[1:].replace("/", ".")) try: os.mkdir(hostpath) except OSError: pass except Exception, e: raise Exception, e self.mount(hostpath, path) def hostfilename(self, filename): ''' Return the name of a node's file on the host filesystem. ''' dirname, basename = os.path.split(filename) if not basename: raise ValueError, "no basename for filename: " + filename if dirname and dirname[0] == "/": dirname = dirname[1:] dirname = dirname.replace("/", ".") dirname = os.path.join(self.nodedir, dirname) return os.path.join(dirname, basename) def opennodefile(self, filename, mode = "w"): hostfilename = self.hostfilename(filename) dirname, basename = os.path.split(hostfilename) if not os.path.isdir(dirname): os.makedirs(dirname, mode = 0755) return open(hostfilename, mode) def nodefile(self, filename, contents, mode = 0644): f = self.opennodefile(filename, "w") f.write(contents) os.chmod(f.name, mode) f.close() self.info("created nodefile: '%s'; mode: 0%o" % (f.name, mode)) def nodefilecopy(self, filename, srcfilename, mode = None): ''' Copy a file to a node, following symlinks and preserving metadata. Change file mode if specified. ''' hostfilename = self.hostfilename(filename) shutil.copy2(srcfilename, hostfilename) if mode is not None: os.chmod(hostfilename, mode) self.info("copied nodefile: '%s'; mode: %s" % (hostfilename, mode)) core-4.8/daemon/core/netns/vnodeclient.py0000664000175000017500000001737312534327775015500 00000000000000# # CORE # Copyright (c)2010-2012 the Boeing Company. # See the LICENSE file included in this distribution. # # author: Tom Goff # ''' vnodeclient.py: implementation of the VnodeClient class for issuing commands over a control channel to the vnoded process running in a network namespace. The control channel can be accessed via calls to the vcmd Python module or by invoking the vcmd shell command. ''' import os, stat, sys from core.constants import * USE_VCMD_MODULE = True if USE_VCMD_MODULE: import vcmd else: import subprocess VCMD = os.path.join(CORE_SBIN_DIR, "vcmd") class VnodeClient(object): def __init__(self, name, ctrlchnlname): self.name = name self.ctrlchnlname = ctrlchnlname if USE_VCMD_MODULE: self.cmdchnl = vcmd.VCmd(self.ctrlchnlname) else: self.cmdchnl = None self._addr = {} def warn(self, msg): print >> sys.stderr, "%s: %s" % (self.name, msg) def connected(self): if USE_VCMD_MODULE: return self.cmdchnl.connected() else: return True def cmd(self, args, wait = True): ''' Execute a command on a node and return the status (return code). ''' if USE_VCMD_MODULE: if not self.cmdchnl.connected(): raise ValueError, "self.cmdchnl not connected" tmp = self.cmdchnl.qcmd(args) if not wait: return tmp tmp = tmp.wait() else: if wait: mode = os.P_WAIT else: mode = os.P_NOWAIT tmp = os.spawnlp(mode, VCMD, VCMD, "-c", self.ctrlchnlname, "-q", "--", *args) if not wait: return tmp if tmp: self.warn("cmd exited with status %s: %s" % (tmp, str(args))) return tmp def cmdresult(self, args): ''' Execute a command on a node and return a tuple containing the exit status and result string. stderr output is folded into the stdout result string. ''' cmdid, cmdin, cmdout, cmderr = self.popen(args) result = cmdout.read() result += cmderr.read() cmdin.close() cmdout.close() cmderr.close() status = cmdid.wait() return (status, result) def popen(self, args): if USE_VCMD_MODULE: if not self.cmdchnl.connected(): raise ValueError, "self.cmdchnl not connected" return self.cmdchnl.popen(args) else: cmd = [VCMD, "-c", self.ctrlchnlname, "--"] cmd.extend(args) tmp = subprocess.Popen(cmd, stdin = subprocess.PIPE, stdout = subprocess.PIPE, stderr = subprocess.PIPE) return tmp, tmp.stdin, tmp.stdout, tmp.stderr def icmd(self, args): return os.spawnlp(os.P_WAIT, VCMD, VCMD, "-c", self.ctrlchnlname, "--", *args) def redircmd(self, infd, outfd, errfd, args, wait = True): ''' Execute a command on a node with standard input, output, and error redirected according to the given file descriptors. ''' if not USE_VCMD_MODULE: raise NotImplementedError if not self.cmdchnl.connected(): raise ValueError, "self.cmdchnl not connected" tmp = self.cmdchnl.redircmd(infd, outfd, errfd, args) if not wait: return tmp tmp = tmp.wait() if tmp: self.warn("cmd exited with status %s: %s" % (tmp, str(args))) return tmp def term(self, sh = "/bin/sh"): cmd = ("xterm", "-ut", "-title", self.name, "-e", VCMD, "-c", self.ctrlchnlname, "--", sh) if "SUDO_USER" in os.environ: cmd = ("su", "-s", "/bin/sh", "-c", "exec " + " ".join(map(lambda x: "'%s'" % x, cmd)), os.environ["SUDO_USER"]) return os.spawnvp(os.P_NOWAIT, cmd[0], cmd) def termcmdstring(self, sh = "/bin/sh"): return "%s -c %s -- %s" % (VCMD, self.ctrlchnlname, sh) def shcmd(self, cmdstr, sh = "/bin/sh"): return self.cmd([sh, "-c", cmdstr]) def getaddr(self, ifname, rescan = False): if ifname in self._addr and not rescan: return self._addr[ifname] tmp = {"ether": [], "inet": [], "inet6": [], "inet6link": []} cmd = [IP_BIN, "addr", "show", "dev", ifname] cmdid, cmdin, cmdout, cmderr = self.popen(cmd) cmdin.close() for line in cmdout: line = line.strip().split() if line[0] == "link/ether": tmp["ether"].append(line[1]) elif line[0] == "inet": tmp["inet"].append(line[1]) elif line[0] == "inet6": if line[3] == "global": tmp["inet6"].append(line[1]) elif line[3] == "link": tmp["inet6link"].append(line[1]) else: self.warn("unknown scope: %s" % line[3]) else: pass err = cmderr.read() cmdout.close() cmderr.close() status = cmdid.wait() if status: self.warn("nonzero exist status (%s) for cmd: %s" % (status, cmd)) if err: self.warn("error output: %s" % err) self._addr[ifname] = tmp return tmp def netifstats(self, ifname = None): stats = {} cmd = ["cat", "/proc/net/dev"] cmdid, cmdin, cmdout, cmderr = self.popen(cmd) cmdin.close() # ignore first line cmdout.readline() # second line has count names tmp = cmdout.readline().strip().split("|") rxkeys = tmp[1].split() txkeys = tmp[2].split() for line in cmdout: line = line.strip().split() devname, tmp = line[0].split(":") if tmp: line.insert(1, tmp) stats[devname] = {"rx": {}, "tx": {}} field = 1 for count in rxkeys: stats[devname]["rx"][count] = int(line[field]) field += 1 for count in txkeys: stats[devname]["tx"][count] = int(line[field]) field += 1 err = cmderr.read() cmdout.close() cmderr.close() status = cmdid.wait() if status: self.warn("nonzero exist status (%s) for cmd: %s" % (status, cmd)) if err: self.warn("error output: %s" % err) if ifname is not None: return stats[ifname] else: return stats def createclients(sessiondir, clientcls = VnodeClient, cmdchnlfilterfunc = None): direntries = map(lambda x: os.path.join(sessiondir, x), os.listdir(sessiondir)) cmdchnls = filter(lambda x: stat.S_ISSOCK(os.stat(x).st_mode), direntries) if cmdchnlfilterfunc: cmdchnls = filter(cmdchnlfilterfunc, cmdchnls) cmdchnls.sort() return map(lambda x: clientcls(os.path.basename(x), x), cmdchnls) def createremoteclients(sessiondir, clientcls = VnodeClient, filterfunc = None): ''' Creates remote VnodeClients, for nodes emulated on other machines. The session.Broker writes a n1.conf/server file having the server's info. ''' direntries = map(lambda x: os.path.join(sessiondir, x), os.listdir(sessiondir)) nodedirs = filter(lambda x: stat.S_ISDIR(os.stat(x).st_mode), direntries) nodedirs = filter(lambda x: os.path.exists(os.path.join(x, "server")), nodedirs) if filterfunc: nodedirs = filter(filterfunc, nodedirs) nodedirs.sort() return map(lambda x: clientcls(x), nodedirs) core-4.8/daemon/core/phys/0000775000175000017500000000000012534327775012515 500000000000000core-4.8/daemon/core/phys/__init__.py0000664000175000017500000000000012534327775014534 00000000000000core-4.8/daemon/core/phys/pnodes.py0000664000175000017500000002246012534327775014303 00000000000000# # CORE # Copyright (c)2011-2012 the Boeing Company. # See the LICENSE file included in this distribution. # # author: Jeff Ahrenholz # ''' PhysicalNode class for including real systems in the emulated network. ''' import os, threading, subprocess from core.misc.ipaddr import * from core.misc.utils import * from core.constants import * from core.api import coreapi from core.coreobj import PyCoreNode, PyCoreNetIf from core.emane.nodes import EmaneNode if os.uname()[0] == "Linux": from core.netns.vnet import LxBrNet from core.netns.vif import GreTap elif os.uname()[0] == "FreeBSD": from core.bsd.vnet import NetgraphNet class PhysicalNode(PyCoreNode): def __init__(self, session, objid = None, name = None, nodedir = None, verbose = False, start = True): PyCoreNode.__init__(self, session, objid, name, verbose=verbose, start=start) self.nodedir = nodedir self.up = start self.lock = threading.RLock() self._mounts = [] if start: self.startup() def boot(self): self.session.services.bootnodeservices(self) def validate(self): self.session.services.validatenodeservices(self) def startup(self): self.lock.acquire() try: self.makenodedir() #self.privatedir("/var/run") #self.privatedir("/var/log") except OSError, e: self.exception(coreapi.CORE_EXCP_LEVEL_ERROR, "PhysicalNode.startup()", e) finally: self.lock.release() def shutdown(self): if not self.up: return self.lock.acquire() while self._mounts: source, target = self._mounts.pop(-1) self.umount(target) for netif in self.netifs(): netif.shutdown() self.rmnodedir() self.lock.release() def termcmdstring(self, sh = "/bin/sh"): ''' The broker will add the appropriate SSH command to open a terminal on this physical node. ''' return sh def cmd(self, args, wait = True): ''' run a command on the physical node ''' os.chdir(self.nodedir) try: if wait: # os.spawnlp(os.P_WAIT, args) subprocess.call(args) else: # os.spawnlp(os.P_NOWAIT, args) subprocess.Popen(args) except CalledProcessError, e: self.warn("cmd exited with status %s: %s" % (e, str(args))) def cmdresult(self, args): ''' run a command on the physical node and get the result ''' os.chdir(self.nodedir) # in Python 2.7 we can use subprocess.check_output() here tmp = subprocess.Popen(args, stdin = subprocess.PIPE, stdout = subprocess.PIPE, stderr = subprocess.PIPE) result = tmp.stdout.read() result += tmp.stderr.read() tmp.stdin.close() tmp.stdout.close() tmp.stderr.close() status = tmp.wait() return (status, result) def shcmd(self, cmdstr, sh = "/bin/sh"): return self.cmd([sh, "-c", cmdstr]) def sethwaddr(self, ifindex, addr): ''' same as SimpleLxcNode.sethwaddr() ''' self._netif[ifindex].sethwaddr(addr) ifname = self.ifname(ifindex) if self.up: (status, result) = self.cmdresult([IP_BIN, "link", "set", "dev", ifname, "address", str(addr)]) if status: self.exception(coreapi.CORE_EXCP_LEVEL_ERROR, "PhysicalNode.sethwaddr()", "error setting MAC address %s" % str(addr)) def addaddr(self, ifindex, addr): ''' same as SimpleLxcNode.addaddr() ''' if self.up: self.cmd([IP_BIN, "addr", "add", str(addr), "dev", self.ifname(ifindex)]) self._netif[ifindex].addaddr(addr) def deladdr(self, ifindex, addr): ''' same as SimpleLxcNode.deladdr() ''' try: self._netif[ifindex].deladdr(addr) except ValueError: self.warn("trying to delete unknown address: %s" % addr) if self.up: self.cmd([IP_BIN, "addr", "del", str(addr), "dev", self.ifname(ifindex)]) def adoptnetif(self, netif, ifindex, hwaddr, addrlist): ''' The broker builds a GreTap tunnel device to this physical node. When a link message is received linking this node to another part of the emulation, no new interface is created; instead, adopt the GreTap netif as the node interface. ''' netif.name = "gt%d" % ifindex netif.node = self self.addnetif(netif, ifindex) # use a more reasonable name, e.g. "gt0" instead of "gt.56286.150" if self.up: self.cmd([IP_BIN, "link", "set", "dev", netif.localname, "down"]) self.cmd([IP_BIN, "link", "set", netif.localname, "name", netif.name]) netif.localname = netif.name if hwaddr: self.sethwaddr(ifindex, hwaddr) for addr in maketuple(addrlist): self.addaddr(ifindex, addr) if self.up: self.cmd([IP_BIN, "link", "set", "dev", netif.localname, "up"]) def linkconfig(self, netif, bw = None, delay = None, loss = None, duplicate = None, jitter = None, netif2 = None): ''' Apply tc queing disciplines using LxBrNet.linkconfig() ''' if os.uname()[0] == "Linux": netcls = LxBrNet elif os.uname()[0] == "FreeBSD": netcls = NetgraphNet else: raise NotImplementedError, "unsupported platform" # borrow the tc qdisc commands from LxBrNet.linkconfig() tmp = netcls(session=self.session, start=False) tmp.up = True tmp.linkconfig(netif, bw=bw, delay=delay, loss=loss, duplicate=duplicate, jitter=jitter, netif2=netif2) del tmp def newifindex(self): self.lock.acquire() try: while self.ifindex in self._netif: self.ifindex += 1 ifindex = self.ifindex self.ifindex += 1 return ifindex finally: self.lock.release() def newnetif(self, net = None, addrlist = [], hwaddr = None, ifindex = None, ifname = None): if self.up and net is None: raise NotImplementedError if ifindex is None: ifindex = self.newifindex() if self.up: # this is reached when this node is linked to a network node # tunnel to net not built yet, so build it now and adopt it gt = self.session.broker.addnettunnel(net.objid) if gt is None or len(gt) != 1: self.session.warn("Error building tunnel from PhysicalNode." "newnetif()") gt = gt[0] net.detach(gt) self.adoptnetif(gt, ifindex, hwaddr, addrlist) return ifindex # this is reached when configuring services (self.up=False) if ifname is None: ifname = "gt%d" % ifindex netif = GreTap(node = self, name = ifname, session = self.session, start = False) self.adoptnetif(netif, ifindex, hwaddr, addrlist) return ifindex def privatedir(self, path): if path[0] != "/": raise ValueError, "path not fully qualified: " + path hostpath = os.path.join(self.nodedir, path[1:].replace("/", ".")) try: os.mkdir(hostpath) except OSError: pass except Exception, e: raise Exception, e self.mount(hostpath, path) def mount(self, source, target): source = os.path.abspath(source) self.info("mounting %s at %s" % (source, target)) try: os.makedirs(target) except OSError: pass try: self.cmd([MOUNT_BIN, "--bind", source, target]) self._mounts.append((source, target)) except: self.warn("mounting failed for %s at %s" % (source, target)) def umount(self, target): self.info("unmounting '%s'" % target) try: self.cmd([UMOUNT_BIN, "-l", target]) except: self.warn("unmounting failed for %s" % target) def opennodefile(self, filename, mode = "w"): dirname, basename = os.path.split(filename) if not basename: raise ValueError, "no basename for filename: " + filename if dirname and dirname[0] == "/": dirname = dirname[1:] dirname = dirname.replace("/", ".") dirname = os.path.join(self.nodedir, dirname) if not os.path.isdir(dirname): os.makedirs(dirname, mode = 0755) hostfilename = os.path.join(dirname, basename) return open(hostfilename, mode) def nodefile(self, filename, contents, mode = 0644): f = self.opennodefile(filename, "w") f.write(contents) os.chmod(f.name, mode) f.close() self.info("created nodefile: '%s'; mode: 0%o" % (f.name, mode)) core-4.8/daemon/core/pycore.py0000664000175000017500000000112212534327775013321 00000000000000# Copyright (c)2010-2012 the Boeing Company. # See the LICENSE file included in this distribution. """ This is a convenience module that imports a set of platform-dependent defaults. """ from misc.utils import ensurepath ensurepath(["/sbin", "/bin", "/usr/sbin", "/usr/bin"]) del ensurepath from session import Session import os if os.uname()[0] == "Linux": from netns import nodes try: from xen import xen except ImportError: #print "Xen support disabled." pass elif os.uname()[0] == "FreeBSD": from bsd import nodes from phys import pnodes del os core-4.8/daemon/core/sdt.py0000664000175000017500000003416712534327775012631 00000000000000# # CORE # Copyright (c)2012-2013 the Boeing Company. # See the LICENSE file included in this distribution. # # author: Jeff Ahrenholz # ''' sdt.py: Scripted Display Tool (SDT3D) helper ''' from core.constants import * from core.api import coreapi from coreobj import PyCoreNet, PyCoreObj from core.netns import nodes from urlparse import urlparse import socket class Sdt(object): ''' Helper class for exporting session objects to NRL's SDT3D. The connect() method initializes the display, and can be invoked when a node position or link has changed. ''' DEFAULT_SDT_URL = "tcp://127.0.0.1:50000/" # default altitude (in meters) for flyto view DEFAULT_ALT = 2500 # TODO: read in user's nodes.conf here; below are default node types # from the GUI DEFAULT_SPRITES = [('router', 'router.gif'), ('host', 'host.gif'), ('PC', 'pc.gif'), ('mdr', 'mdr.gif'), ('prouter', 'router_green.gif'), ('xen', 'xen.gif'), ('hub', 'hub.gif'), ('lanswitch','lanswitch.gif'), ('wlan', 'wlan.gif'), ('rj45','rj45.gif'), ('tunnel','tunnel.gif'), ] class Bunch: ''' Helper class for recording a collection of attributes. ''' def __init__(self, **kwds): self.__dict__.update(kwds) def __init__(self, session): self.session = session self.sock = None self.connected = False self.showerror = True self.url = self.DEFAULT_SDT_URL self.verbose = self.session.getcfgitembool('verbose', False) # node information for remote nodes not in session._objs # local nodes also appear here since their obj may not exist yet self.remotes = {} session.broker.handlers += (self.handledistributed, ) def is_enabled(self): ''' Check for 'enablesdt' session option. Return False by default if the option is missing. ''' if not hasattr(self.session.options, 'enablesdt'): return False enabled = self.session.options.enablesdt if enabled in ('1', 'true', 1, True): return True return False def seturl(self): ''' Read 'sdturl' from session options, or use the default value. Set self.url, self.address, self.protocol ''' url = None if hasattr(self.session.options,'sdturl'): if self.session.options.sdturl != "": url = self.session.options.sdturl if url is None or url == "": url = self.DEFAULT_SDT_URL self.url = urlparse(url) self.address = (self.url.hostname, self.url.port) self.protocol = self.url.scheme def connect(self, flags=0): ''' Connect to the SDT address/port if enabled. ''' if not self.is_enabled(): return False if self.connected: return True if self.session.getstate() == coreapi.CORE_EVENT_SHUTDOWN_STATE: return False self.seturl() if self.showerror: self.session.info("connecting to SDT at %s://%s" \ % (self.protocol, self.address)) if self.sock is None: try: if (self.protocol.lower() == 'udp'): self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) self.sock.connect(self.address) else: # Default to tcp self.sock = socket.create_connection(self.address, 5) except Exception, e: if self.showerror: self.session.warn("SDT socket connect error: %s" % e) self.showerror = False return False if not self.initialize(): return False self.connected = True # refresh all objects in SDT3D when connecting after session start if not flags & coreapi.CORE_API_ADD_FLAG: if not self.sendobjs(): return False return True def initialize(self): ''' Load icon sprites, and fly to the reference point location on the virtual globe. ''' if not self.cmd('path "%s/icons/normal"' % CORE_DATA_DIR): return False # send node type to icon mappings for (type, icon) in self.DEFAULT_SPRITES: if not self.cmd('sprite %s image %s' % (type, icon)): return False (lat, long) = self.session.location.refgeo[:2] return self.cmd('flyto %.6f,%.6f,%d' % (long, lat, self.DEFAULT_ALT)) def disconnect(self): try: self.sock.close() except: pass self.sock = None self.connected = False def shutdown(self): ''' Invoked from Session.shutdown() and Session.checkshutdown(). ''' self.cmd('clear all') self.disconnect() self.showerror = True def cmd(self, cmdstr): ''' Send an SDT command over a UDP socket. socket.sendall() is used as opposed to socket.sendto() because an exception is raised when there is no socket listener. ''' if self.sock is None: return False try: if self.verbose: self.session.info("sdt: %s" % cmdstr) self.sock.sendall("%s\n" % cmdstr) return True except Exception, e: if self.showerror: self.session.warn("SDT connection error: %s" % e) self.showerror = False self.sock = None self.connected = False return False def updatenode(self, nodenum, flags, x, y, z, name=None, type=None, icon=None): ''' Node is updated from a Node Message or mobility script. ''' if not self.connect(): return if flags & coreapi.CORE_API_DEL_FLAG: self.cmd('delete node,%d' % nodenum) return if x is None or y is None: return (lat, long, alt) = self.session.location.getgeo(x, y, z) pos = "pos %.6f,%.6f,%.6f" % (long, lat, alt) if flags & coreapi.CORE_API_ADD_FLAG: if icon is not None: type = name icon = icon.replace("$CORE_DATA_DIR", CORE_DATA_DIR) icon = icon.replace("$CORE_CONF_DIR", CORE_CONF_DIR) self.cmd('sprite %s image %s' % (type, icon)) self.cmd('node %d type %s label on,"%s" %s' % \ (nodenum, type, name, pos)) else: self.cmd('node %d %s' % (nodenum, pos)) def updatenodegeo(self, nodenum, lat, long, alt): ''' Node is updated upon receiving an EMANE Location Event. TODO: received Node Message with lat/long/alt. ''' if not self.connect(): return pos = "pos %.6f,%.6f,%.6f" % (long, lat, alt) self.cmd('node %d %s' % (nodenum, pos)) def updatelink(self, node1num, node2num, flags, wireless=False): ''' Link is updated from a Link Message or by a wireless model. ''' if node1num is None or node2num is None: return if not self.connect(): return if flags & coreapi.CORE_API_DEL_FLAG: self.cmd('delete link,%s,%s' % (node1num, node2num)) elif flags & coreapi.CORE_API_ADD_FLAG: attr = "" if wireless: attr = " line green,2" else: attr = " line red,2" self.cmd('link %s,%s%s' % (node1num, node2num, attr)) def sendobjs(self): ''' Session has already started, and the SDT3D GUI later connects. Send all node and link objects for display. Otherwise, nodes and links will only be drawn when they have been updated (e.g. moved). ''' nets = [] with self.session._objslock: for obj in self.session.objs(): if isinstance(obj, PyCoreNet): nets.append(obj) if not isinstance(obj, PyCoreObj): continue (x, y, z) = obj.getposition() if x is None or y is None: continue self.updatenode(obj.objid, coreapi.CORE_API_ADD_FLAG, x, y, z, obj.name, obj.type, obj.icon) for nodenum in sorted(self.remotes.keys()): r = self.remotes[nodenum] (x, y, z) = r.pos self.updatenode(nodenum, coreapi.CORE_API_ADD_FLAG, x, y, z, r.name, r.type, r.icon) for net in nets: # use tolinkmsgs() to handle various types of links msgs = net.tolinkmsgs(flags = coreapi.CORE_API_ADD_FLAG) for msg in msgs: msghdr = msg[:coreapi.CoreMessage.hdrsiz] flags = coreapi.CoreMessage.unpackhdr(msghdr)[1] m = coreapi.CoreLinkMessage(flags, msghdr, msg[coreapi.CoreMessage.hdrsiz:]) n1num = m.gettlv(coreapi.CORE_TLV_LINK_N1NUMBER) n2num = m.gettlv(coreapi.CORE_TLV_LINK_N2NUMBER) link_msg_type = m.gettlv(coreapi.CORE_TLV_LINK_TYPE) if isinstance(net, nodes.WlanNode) or \ isinstance(net, nodes.EmaneNode): if (n1num == net.objid): continue wl = (link_msg_type == coreapi.CORE_LINK_WIRELESS) self.updatelink(n1num, n2num, coreapi.CORE_API_ADD_FLAG, wl) for n1num in sorted(self.remotes.keys()): r = self.remotes[n1num] for (n2num, wl) in r.links: self.updatelink(n1num, n2num, coreapi.CORE_API_ADD_FLAG, wl) def handledistributed(self, msg): ''' Broker handler for processing CORE API messages as they are received. This is used to snoop the Node messages and update node positions. ''' if msg.msgtype == coreapi.CORE_API_LINK_MSG: return self.handlelinkmsg(msg) elif msg.msgtype == coreapi.CORE_API_NODE_MSG: return self.handlenodemsg(msg) def handlenodemsg(self, msg): ''' Process a Node Message to add/delete or move a node on the SDT display. Node properties are found in session._objs or self.remotes for remote nodes (or those not yet instantiated). ''' # for distributed sessions to work properly, the SDT option should be # enabled prior to starting the session if not self.is_enabled(): return False # node.(objid, type, icon, name) are used. nodenum = msg.gettlv(coreapi.CORE_TLV_NODE_NUMBER) if not nodenum: return x = msg.gettlv(coreapi.CORE_TLV_NODE_XPOS) y = msg.gettlv(coreapi.CORE_TLV_NODE_YPOS) z = None name = msg.gettlv(coreapi.CORE_TLV_NODE_NAME) nodetype = msg.gettlv(coreapi.CORE_TLV_NODE_TYPE) model = msg.gettlv(coreapi.CORE_TLV_NODE_MODEL) icon = msg.gettlv(coreapi.CORE_TLV_NODE_ICON) net = False if nodetype == coreapi.CORE_NODE_DEF or \ nodetype == coreapi.CORE_NODE_PHYS or \ nodetype == coreapi.CORE_NODE_XEN: if model is None: model = "router" type = model elif nodetype != None: type = coreapi.node_class(nodetype).type net = True else: type = None try: node = self.session.obj(nodenum) except KeyError: node = None if node: self.updatenode(node.objid, msg.flags, x, y, z, node.name, node.type, node.icon) else: if nodenum in self.remotes: remote = self.remotes[nodenum] if name is None: name = remote.name if type is None: type = remote.type if icon is None: icon = remote.icon else: remote = self.Bunch(objid=nodenum, type=type, icon=icon, name=name, net=net, links=set()) self.remotes[nodenum] = remote remote.pos = (x, y, z) self.updatenode(nodenum, msg.flags, x, y, z, name, type, icon) def handlelinkmsg(self, msg): ''' Process a Link Message to add/remove links on the SDT display. Links are recorded in the remotes[nodenum1].links set for updating the SDT display at a later time. ''' if not self.is_enabled(): return False nodenum1 = msg.gettlv(coreapi.CORE_TLV_LINK_N1NUMBER) nodenum2 = msg.gettlv(coreapi.CORE_TLV_LINK_N2NUMBER) link_msg_type = msg.gettlv(coreapi.CORE_TLV_LINK_TYPE) # this filters out links to WLAN and EMANE nodes which are not drawn if self.wlancheck(nodenum1): return wl = (link_msg_type == coreapi.CORE_LINK_WIRELESS) if nodenum1 in self.remotes: r = self.remotes[nodenum1] if msg.flags & coreapi.CORE_API_DEL_FLAG: if (nodenum2, wl) in r.links: r.links.remove((nodenum2, wl)) else: r.links.add((nodenum2, wl)) self.updatelink(nodenum1, nodenum2, msg.flags, wireless=wl) def wlancheck(self, nodenum): ''' Helper returns True if a node number corresponds to a WlanNode or EmaneNode. ''' if nodenum in self.remotes: type = self.remotes[nodenum].type if type in ("wlan", "emane"): return True else: try: n = self.session.obj(nodenum) except KeyError: return False if isinstance(n, (nodes.WlanNode, nodes.EmaneNode)): return True return False core-4.8/daemon/core/service.py0000664000175000017500000010176412534327775013475 00000000000000# # CORE # Copyright (c)2010-2012 the Boeing Company. # See the LICENSE file included in this distribution. # # author: Jeff Ahrenholz # ''' service.py: definition of CoreService class that is subclassed to define startup services and routing for nodes. A service is typically a daemon program launched when a node starts that provides some sort of service. The CoreServices class handles configuration messages for sending a list of available services to the GUI and for configuring individual services. ''' import sys, os, shlex from itertools import repeat from core.api import coreapi from core.conf import ConfigurableManager, Configurable from core.misc.utils import maketuplefromstr, expandcorepath servicelist = [] def addservice(service): global servicelist i = 0 found = -1 for s in servicelist: if s._group == service._group: found = i elif (found >= 0): # insert service into list next to existing group i = found + 1 break i += 1 servicelist.insert(i, service) class CoreServices(ConfigurableManager): ''' Class for interacting with a list of available startup services for nodes. Mostly used to convert a CoreService into a Config API message. This class lives in the Session object and remembers the default services configured for each node type, and any custom service configuration. A CoreService is not a Configurable. ''' _name = "services" _type = coreapi.CORE_TLV_REG_UTILITY _invalid_custom_names = ('core', 'addons', 'api', 'bsd', 'emane', 'misc', 'netns', 'phys', 'services', 'xen') def __init__(self, session): ConfigurableManager.__init__(self, session) # dict of default services tuples, key is node type self.defaultservices = {} # dict of tuple of service objects, key is node number self.customservices = {} importcmd = "from core.services import *" exec(importcmd) paths = self.session.getcfgitem('custom_services_dir') if paths: for path in paths.split(','): path = path.strip() self.importcustom(path) def importcustom(self, path): ''' Import services from a myservices directory. ''' if not path or len(path) == 0: return if not os.path.isdir(path): self.session.warn("invalid custom service directory specified" \ ": %s" % path) return try: parentdir, childdir = os.path.split(path) if childdir in self._invalid_custom_names: raise ValueError, "use a unique custom services dir name, " \ "not '%s'" % childdir if not parentdir in sys.path: sys.path.append(parentdir) exec("from %s import *" % childdir) except Exception, e: self.session.warn("error importing custom services from " \ "%s:\n%s" % (path, e)) def reset(self): ''' Called when config message with reset flag is received ''' self.defaultservices.clear() self.customservices.clear() def get(self): ''' Get the list of available services. ''' global servicelist return servicelist def getservicebyname(self, name): ''' Get a service class from the global servicelist given its name. Returns None when the name is not found. ''' global servicelist for s in servicelist: if s._name == name: return s return None def getdefaultservices(self, type): ''' Get the list of default services that should be enabled for a node for the given node type. ''' r = [] if type in self.defaultservices: defaults = self.defaultservices[type] for name in defaults: s = self.getservicebyname(name) if s is None: self.session.warn("default service %s is unknown" % name) else: r.append(s) return r def getcustomservice(self, objid, service): ''' Get any custom service configured for the given node that matches the specified service name. If no custom service is found, return the specified service. ''' if objid in self.customservices: for s in self.customservices[objid]: if s._name == service._name: return s return service def setcustomservice(self, objid, service, values): ''' Store service customizations in an instantiated service object using a list of values that came from a config message. ''' if service._custom: s = service else: # instantiate the class, for storing config customization s = service() # values are new key=value format; not all keys need to be present # a missing key means go with the default if Configurable.haskeyvalues(values): for v in values: key, value = v.split('=', 1) s.setvalue(key, value) # old-style config, list of values else: s.fromvaluelist(values) # assume custom service already in dict if service._custom: return # add the custom service to dict if objid in self.customservices: self.customservices[objid] += (s, ) else: self.customservices[objid] = (s, ) def addservicestonode(self, node, nodetype, services_str, verbose): ''' Populate the node.service list using (1) the list of services requested from the services TLV, (2) using any custom service configuration, or (3) using the default services for this node type. ''' if services_str is not None: services = services_str.split('|') for name in services: s = self.getservicebyname(name) if s is None: self.session.warn("configured service %s for node %s is " \ "unknown" % (name, node.name)) continue if verbose: self.session.info("adding configured service %s to " \ "node %s" % (s._name, node.name)) s = self.getcustomservice(node.objid, s) node.addservice(s) else: services = self.getdefaultservices(nodetype) for s in services: if verbose: self.session.info("adding default service %s to node %s" % \ (s._name, node.name)) s = self.getcustomservice(node.objid, s) node.addservice(s) def getallconfigs(self): ''' Return (nodenum, service) tuples for all stored configs. Used when reconnecting to a session or opening XML. ''' r = [] for nodenum in self.customservices: for s in self.customservices[nodenum]: r.append( (nodenum, s) ) return r def getallfiles(self, service): ''' Return all customized files stored with a service. Used when reconnecting to a session or opening XML. ''' r = [] if not service._custom: return r for filename in service._configs: data = self.getservicefiledata(service, filename) if data is None: continue r.append( (filename, data) ) return r def bootnodeservices(self, node): ''' Start all services on a node. ''' services = sorted(node.services, key=lambda service: service._startindex) for s in services: if len(str(s._starttime)) > 0: try: t = float(s._starttime) if t > 0.0: fn = self.bootnodeservice self.session.evq.add_event(t, fn, node, s, services) continue except ValueError: pass self.bootnodeservice(node, s, services) def bootnodeservice(self, node, s, services): ''' Start a service on a node. Create private dirs, generate config files, and execute startup commands. ''' if s._custom: self.bootnodecustomservice(node, s, services) return if node.verbose: node.info("starting service %s (%s)" % (s._name, s._startindex)) for d in s._dirs: try: node.privatedir(d) except Exception, e: node.warn("Error making node %s dir %s: %s" % \ (node.name, d, e)) for filename in s.getconfigfilenames(node.objid, services): cfg = s.generateconfig(node, filename, services) node.nodefile(filename, cfg) for cmd in s.getstartup(node, services): try: # NOTE: this wait=False can be problematic! node.cmd(shlex.split(cmd), wait = False) except Exception, e: node.warn("error starting command %s: %s" % (cmd, e)) def bootnodecustomservice(self, node, s, services): ''' Start a custom service on a node. Create private dirs, use supplied config files, and execute supplied startup commands. ''' if node.verbose: node.info("starting service %s (%s)(custom)" % (s._name, s._startindex)) for d in s._dirs: try: node.privatedir(d) except Exception, e: node.warn("Error making node %s dir %s: %s" % \ (node.name, d, e)) for i, filename in enumerate(s._configs): if len(filename) == 0: continue cfg = self.getservicefiledata(s, filename) if cfg is None: cfg = s.generateconfig(node, filename, services) # cfg may have a file:/// url for copying from a file try: if self.copyservicefile(node, filename, cfg): continue except IOError, e: node.warn("Error copying service file %s" % filename) node.exception(coreapi.CORE_EXCP_LEVEL_ERROR, "service:%s" % s._name, "error copying service file '%s': %s" % (filename, e)) continue node.nodefile(filename, cfg) for cmd in s._startup: try: # NOTE: this wait=False can be problematic! node.cmd(shlex.split(cmd), wait = False) except Exception, e: node.warn("error starting command %s: %s" % (cmd, e)) def copyservicefile(self, node, filename, cfg): ''' Given a configured service filename and config, determine if the config references an existing file that should be copied. Returns True for local files, False for generated. ''' if cfg[:7] == 'file://': src = cfg[7:] src = src.split('\n')[0] src = expandcorepath(src, node.session, node) # TODO: glob here node.nodefilecopy(filename, src, mode = 0644) return True return False def validatenodeservices(self, node): ''' Run validation commands for all services on a node. ''' services = sorted(node.services, key=lambda service: service._startindex) for s in services: self.validatenodeservice(node, s, services) def validatenodeservice(self, node, s, services): ''' Run the validation command(s) for a service. ''' if node.verbose: node.info("validating service %s (%s)" % (s._name, s._startindex)) if s._custom: validate_cmds = s._validate else: validate_cmds = s.getvalidate(node, services) if len(validate_cmds) == 0: # doesn't have a validate command status = 0 else: for cmd in validate_cmds: if node.verbose: node.info("validating service %s using: %s" % (s._name, cmd)) try: (status, result) = node.cmdresult(shlex.split(cmd)) if status != 0: raise ValueError, "non-zero exit status" except: node.warn("validation command '%s' failed" % cmd) node.exception(coreapi.CORE_EXCP_LEVEL_ERROR, "service:%s" % s._name, "validate command failed: %s" % cmd) status = -1 return status def stopnodeservices(self, node): ''' Stop all services on a node. ''' services = sorted(node.services, key=lambda service: service._startindex) for s in services: self.stopnodeservice(node, s) def stopnodeservice(self, node, s): ''' Stop a service on a node. ''' status = "" if len(s._shutdown) == 0: # doesn't have a shutdown command status += "0" else: for cmd in s._shutdown: try: tmp = node.cmd(shlex.split(cmd), wait = True) status += "%s" % (tmp) except: node.warn("error running stop command %s" % cmd) status += "-1" return status def configure_request(self, msg): ''' Receive configuration message for configuring services. With a request flag set, a list of services has been requested. When the opaque field is present, a specific service is being configured or requested. ''' objname = msg.gettlv(coreapi.CORE_TLV_CONF_OBJ) conftype = msg.gettlv(coreapi.CORE_TLV_CONF_TYPE) nodenum = msg.gettlv(coreapi.CORE_TLV_CONF_NODE) sessionnum = msg.gettlv(coreapi.CORE_TLV_CONF_SESSION) opaque = msg.gettlv(coreapi.CORE_TLV_CONF_OPAQUE) # send back a list of available services if opaque is None: global servicelist tf = coreapi.CONF_TYPE_FLAGS_NONE datatypes = tuple(repeat(coreapi.CONF_DATA_TYPE_BOOL, len(servicelist))) vals = "|".join(repeat('0', len(servicelist))) names = map(lambda x: x._name, servicelist) captions = "|".join(names) possiblevals = "" for s in servicelist: if s._custom_needed: possiblevals += '1' possiblevals += '|' groups = self.buildgroups(servicelist) # send back the properties for this service else: if nodenum is None: return None n = self.session.obj(nodenum) if n is None: self.session.warn("Request to configure service %s for " \ "unknown node %s" % (svc._name, nodenum)) return None servicesstring = opaque.split(':') services,unknown = self.servicesfromopaque(opaque, n.objid) for u in unknown: self.session.warn("Request for unknown service '%s'" % u) if len(services) < 1: return None if len(servicesstring) == 3: # a file request: e.g. "service:zebra:quagga.conf" return self.getservicefile(services, n, servicesstring[2]) # the first service in the list is the one being configured svc = services[0] # send back: # dirs, configs, startindex, startup, shutdown, metadata, config tf = coreapi.CONF_TYPE_FLAGS_UPDATE datatypes = tuple(repeat(coreapi.CONF_DATA_TYPE_STRING, len(svc.keys))) vals = svc.tovaluelist(n, services) captions = None possiblevals = None groups = None tlvdata = "" if nodenum is not None: tlvdata += coreapi.CoreConfTlv.pack(coreapi.CORE_TLV_CONF_NODE, nodenum) tlvdata += coreapi.CoreConfTlv.pack(coreapi.CORE_TLV_CONF_OBJ, self._name) tlvdata += coreapi.CoreConfTlv.pack(coreapi.CORE_TLV_CONF_TYPE, tf) tlvdata += coreapi.CoreConfTlv.pack(coreapi.CORE_TLV_CONF_DATA_TYPES, datatypes) tlvdata += coreapi.CoreConfTlv.pack(coreapi.CORE_TLV_CONF_VALUES, vals) if captions: tlvdata += coreapi.CoreConfTlv.pack(coreapi.CORE_TLV_CONF_CAPTIONS, captions) if possiblevals: tlvdata += coreapi.CoreConfTlv.pack( coreapi.CORE_TLV_CONF_POSSIBLE_VALUES, possiblevals) if groups: tlvdata += coreapi.CoreConfTlv.pack(coreapi.CORE_TLV_CONF_GROUPS, groups) if sessionnum is not None: tlvdata += coreapi.CoreConfTlv.pack( coreapi.CORE_TLV_CONF_SESSION, sessionnum) if opaque: tlvdata += coreapi.CoreConfTlv.pack(coreapi.CORE_TLV_CONF_OPAQUE, opaque) return coreapi.CoreConfMessage.pack(0, tlvdata) def configure_values(self, msg, values): ''' Receive configuration message for configuring services. With a request flag set, a list of services has been requested. When the opaque field is present, a specific service is being configured or requested. ''' nodenum = msg.gettlv(coreapi.CORE_TLV_CONF_NODE) opaque = msg.gettlv(coreapi.CORE_TLV_CONF_OPAQUE) errmsg = "services config message that I don't know how to handle" if values is None: self.session.info(errmsg) return None else: values = values.split('|') if opaque is None: # store default services for a node type in self.defaultservices[] data_types = msg.gettlv(coreapi.CORE_TLV_CONF_DATA_TYPES) if values is None or data_types is None or \ data_types[0] != coreapi.CONF_DATA_TYPE_STRING: self.session.info(errmsg) return None key = values.pop(0) self.defaultservices[key] = values self.session.info("default services for type %s set to %s" % \ (key, values)) else: # store service customized config in self.customservices[] if nodenum is None: return None services,unknown = self.servicesfromopaque(opaque, nodenum) for u in unknown: self.session.warn("Request for unknown service '%s'" % u) if len(services) < 1: return None svc = services[0] self.setcustomservice(nodenum, svc, values) return None def servicesfromopaque(self, opaque, objid): ''' Build a list of services from an opaque data string. ''' services = [] unknown = [] servicesstring = opaque.split(':') if servicesstring[0] != "service": return [] servicenames = servicesstring[1].split(',') for name in servicenames: s = self.getservicebyname(name) s = self.getcustomservice(objid, s) if s is None: unknown.append(name) else: services.append(s) return services,unknown def buildgroups(self, servicelist): ''' Build a string of groups for use in a configuration message given a list of services. The group list string has the format "title1:1-5|title2:6-9|10-12", where title is an optional group title and i-j is a numeric range of value indices; groups are separated by commas. ''' i = 0 r = "" lastgroup = "" for service in servicelist: i += 1 group = service._group if group != lastgroup: lastgroup = group # finish previous group if i > 1: r += "-%d|" % (i -1) # optionally include group title if group == "": r += "%d" % i else: r += "%s:%d" % (group, i) # finish the last group list if i > 0: r += "-%d" % i return r def getservicefile(self, services, node, filename): ''' Send a File Message when the GUI has requested a service file. The file data is either auto-generated or comes from an existing config. ''' svc = services[0] # get the filename and determine the config file index if svc._custom: cfgfiles = svc._configs else: cfgfiles = svc.getconfigfilenames(node.objid, services) if filename not in cfgfiles: self.session.warn("Request for unknown file '%s' for service '%s'" \ % (filename, services[0])) return None # get the file data data = self.getservicefiledata(svc, filename) if data is None: data = "%s" % (svc.generateconfig(node, filename, services)) else: data = "%s" % data filetypestr = "service:%s" % svc._name # send a file message flags = coreapi.CORE_API_ADD_FLAG tlvdata = coreapi.CoreFileTlv.pack(coreapi.CORE_TLV_FILE_NODE, node.objid) tlvdata += coreapi.CoreFileTlv.pack(coreapi.CORE_TLV_FILE_NAME, filename) tlvdata += coreapi.CoreFileTlv.pack(coreapi.CORE_TLV_FILE_TYPE, filetypestr) tlvdata += coreapi.CoreFileTlv.pack(coreapi.CORE_TLV_FILE_DATA, data) reply = coreapi.CoreFileMessage.pack(flags, tlvdata) return reply def getservicefiledata(self, service, filename): ''' Get the customized file data associated with a service. Return None for invalid filenames or missing file data. ''' try: i = service._configs.index(filename) except ValueError: return None if i >= len(service._configtxt) or service._configtxt[i] is None: return None return service._configtxt[i] def setservicefile(self, nodenum, type, filename, srcname, data): ''' Receive a File Message from the GUI and store the customized file in the service config. The filename must match one from the list of config files in the service. ''' if len(type.split(':')) < 2: self.session.warn("Received file type did not contain service info.") return if srcname is not None: raise NotImplementedError (svcid, svcname) = type.split(':')[:2] svc = self.getservicebyname(svcname) svc = self.getcustomservice(nodenum, svc) if svc is None: self.session.warn("Received filename for unknown service '%s'" % \ svcname) return cfgfiles = svc._configs if filename not in cfgfiles: self.session.warn("Received unknown file '%s' for service '%s'" \ % (filename, svcname)) return i = cfgfiles.index(filename) configtxtlist = list(svc._configtxt) numitems = len(configtxtlist) if numitems < i+1: # add empty elements to list to support index assignment for j in range(1, (i + 2) - numitems): configtxtlist += None, configtxtlist[i] = data svc._configtxt = configtxtlist def handleevent(self, msg): ''' Handle an Event Message used to start, stop, restart, or validate a service on a given node. ''' eventtype = msg.gettlv(coreapi.CORE_TLV_EVENT_TYPE) nodenum = msg.gettlv(coreapi.CORE_TLV_EVENT_NODE) name = msg.gettlv(coreapi.CORE_TLV_EVENT_NAME) try: node = self.session.obj(nodenum) except KeyError: self.session.warn("Ignoring event for service '%s', unknown node " \ "'%s'" % (name, nodenum)) return fail = "" services,unknown = self.servicesfromopaque(name, nodenum) for s in services: if eventtype == coreapi.CORE_EVENT_STOP or \ eventtype == coreapi.CORE_EVENT_RESTART: status = self.stopnodeservice(node, s) if status != "0": fail += "Stop %s," % (s._name) if eventtype == coreapi.CORE_EVENT_START or \ eventtype == coreapi.CORE_EVENT_RESTART: if s._custom: cmds = s._startup else: cmds = s.getstartup(node, services) if len(cmds) > 0: for cmd in cmds: try: #node.cmd(shlex.split(cmd), wait = False) status = node.cmd(shlex.split(cmd), wait = True) if status != 0: fail += "Start %s(%s)," % (s._name, cmd) except: node.warn("error starting command %s" % cmd) fail += "Start %s," % (s._name) if eventtype == coreapi.CORE_EVENT_PAUSE: status = self.validatenodeservice(node, s, services) if status != 0: fail += "%s," % (s._name) if eventtype == coreapi.CORE_EVENT_RECONFIGURE: if s._custom: cfgfiles = s._configs else: cfgfiles = s.getconfigfilenames(node.objid, services) if len(cfgfiles) > 0: for filename in cfgfiles: if filename[:7] == "file:///": raise NotImplementedError # TODO cfg = self.getservicefiledata(s, filename) if cfg is None: cfg = s.generateconfig(node, filename, services) try: node.nodefile(filename, cfg) except: self.warn("error in configure file: %s" % filename) fail += "%s," % (s._name) fdata = "" if len(fail) > 0: fdata += "Fail:" + fail udata = "" num = len(unknown) if num > 0: for u in unknown: udata += u if num > 1: udata += ", " num -= 1 self.session.warn("Event requested for unknown service(s): %s" % udata); udata = "Unknown:" + udata tlvdata = "" tlvdata += coreapi.CoreEventTlv.pack(coreapi.CORE_TLV_EVENT_NODE, nodenum) tlvdata += coreapi.CoreEventTlv.pack(coreapi.CORE_TLV_EVENT_TYPE, eventtype) tlvdata += coreapi.CoreEventTlv.pack(coreapi.CORE_TLV_EVENT_NAME, name) tlvdata += coreapi.CoreEventTlv.pack(coreapi.CORE_TLV_EVENT_DATA, fdata + ";" + udata) msg = coreapi.CoreEventMessage.pack(0, tlvdata) try: self.session.broadcastraw(None, msg) except Exception, e: self.warn("Error sending Event Message: %s" % e) class CoreService(object): ''' Parent class used for defining services. ''' # service name should not include spaces _name = "" # group string allows grouping services together _group = "" # list name(s) of services that this service depends upon _depends = () keys = ["dirs","files","startidx","cmdup","cmddown","cmdval","meta","starttime"] # private, per-node directories required by this service _dirs = () # config files written by this service _configs = () # index used to determine start order with other services _startindex = 0 # time in seconds after runtime to run startup commands _starttime = "" # list of startup commands _startup = () # list of shutdown commands _shutdown = () # list of validate commands _validate = () # metadata associated with this service _meta = "" # custom configuration text _configtxt = () _custom = False _custom_needed = False def __init__(self): ''' Services are not necessarily instantiated. Classmethods may be used against their config. Services are instantiated when a custom configuration is used to override their default parameters. ''' self._custom = True @classmethod def getconfigfilenames(cls, nodenum, services): ''' Return the tuple of configuration file filenames. This default method returns the cls._configs tuple, but this method may be overriden to provide node-specific filenames that may be based on other services. ''' return cls._configs @classmethod def generateconfig(cls, node, filename, services): ''' Generate configuration file given a node object. The filename is provided to allow for multiple config files. The other services are provided to allow interdependencies (e.g. zebra and OSPF). Return the configuration string to be written to a file or sent to the GUI for customization. ''' raise NotImplementedError @classmethod def getstartup(cls, node, services): ''' Return the tuple of startup commands. This default method returns the cls._startup tuple, but this method may be overriden to provide node-specific commands that may be based on other services. ''' return cls._startup @classmethod def getvalidate(cls, node, services): ''' Return the tuple of validate commands. This default method returns the cls._validate tuple, but this method may be overriden to provide node-specific commands that may be based on other services. ''' return cls._validate @classmethod def tovaluelist(cls, node, services): ''' Convert service properties into a string list of key=value pairs, separated by "|". ''' valmap = [cls._dirs, cls._configs, cls._startindex, cls._startup, cls._shutdown, cls._validate, cls._meta, cls._starttime] if not cls._custom: # this is always reached due to classmethod valmap[valmap.index(cls._configs)] = \ cls.getconfigfilenames(node.objid, services) valmap[valmap.index(cls._startup)] = \ cls.getstartup(node, services) vals = map( lambda a,b: "%s=%s" % (a, str(b)), cls.keys, valmap) return "|".join(vals) def fromvaluelist(self, values): ''' Convert list of values into properties for this instantiated (customized) service. ''' # TODO: support empty value? e.g. override default meta with '' for key in self.keys: try: self.setvalue(key, values[self.keys.index(key)]) except IndexError: # old config does not need to have new keys pass def setvalue(self, key, value): if key not in self.keys: raise ValueError # this handles data conversion to int, string, and tuples if value: if key == "startidx": value = int(value) elif key == "meta": value = str(value) else: value = maketuplefromstr(value, str) if key == "dirs": self._dirs = value elif key == "files": self._configs = value elif key == "startidx": self._startindex = value elif key == "cmdup": self._startup = value elif key == "cmddown": self._shutdown = value elif key == "cmdval": self._validate = value elif key == "meta": self._meta = value elif key == "starttime": self._starttime = value core-4.8/daemon/core/services/0000775000175000017500000000000012534327775013355 500000000000000core-4.8/daemon/core/services/__init__.py0000664000175000017500000000036312534327775015410 00000000000000"""Services Services available to nodes can be put in this directory. Everything listed in __all__ is automatically loaded by the main core module. """ __all__ = ["quagga", "nrl", "xorp", "bird", "utility", "security", "ucarp", "dockersvc"] core-4.8/daemon/core/services/bird.py0000664000175000017500000001601312534327775014570 00000000000000# # CORE # Copyright (c)2012 Jean-Tiare Le Bigot. # See the LICENSE file included in this distribution. # # authors: Jean-Tiare Le Bigot # Jeff Ahrenholz # ''' bird.py: defines routing services provided by the BIRD Internet Routing Daemon. ''' import os from core.service import CoreService, addservice from core.misc.ipaddr import IPv4Prefix from core.constants import * class Bird(CoreService): ''' Bird router support ''' _name = "bird" _group = "BIRD" _depends = () _dirs = ("/etc/bird",) _configs = ("/etc/bird/bird.conf",) _startindex = 35 _startup = ("bird -c %s" % (_configs[0]),) _shutdown = ("killall bird", ) _validate = ("pidof bird", ) @classmethod def generateconfig(cls, node, filename, services): ''' Return the bird.conf file contents. ''' if filename == cls._configs[0]: return cls.generateBirdConf(node, services) else: raise ValueError @staticmethod def routerid(node): ''' Helper to return the first IPv4 address of a node as its router ID. ''' for ifc in node.netifs(): if hasattr(ifc, 'control') and ifc.control == True: continue for a in ifc.addrlist: if a.find(".") >= 0: return a .split('/') [0] #raise ValueError, "no IPv4 address found for router ID" return "0.0.0.0" @classmethod def generateBirdConf(cls, node, services): ''' Returns configuration file text. Other services that depend on bird will have generatebirdifcconfig() and generatebirdconfig() hooks that are invoked here. ''' cfg = """\ /* Main configuration file for BIRD. This is ony a template, * you will *need* to customize it according to your needs * Beware that only double quotes \'"\' are valid. No singles. */ log "/var/log/%s.log" all; #debug protocols all; #debug commands 2; router id %s; # Mandatory for IPv6, may be automatic for IPv4 protocol kernel { persist; # Don\'t remove routes on BIRD shutdown scan time 200; # Scan kernel routing table every 200 seconds export all; import all; } protocol device { scan time 10; # Scan interfaces every 10 seconds } """ % (cls._name, cls.routerid(node)) # Generate protocol specific configurations for s in services: if cls._name not in s._depends: continue cfg += s.generatebirdconfig(node) return cfg class BirdService(CoreService): ''' Parent class for Bird services. Defines properties and methods common to Bird's routing daemons. ''' _name = "BirdDaemon" _group = "BIRD" _depends = ("bird", ) _dirs = () _configs = () _startindex = 40 _startup = () _shutdown = () _meta = "The config file for this service can be found in the bird service." @classmethod def generatebirdconfig(cls, node): return "" @classmethod def generatebirdifcconfig(cls, node): ''' Use only bare interfaces descriptions in generated protocol configurations. This has the slight advantage of being the same everywhere. ''' cfg = "" for ifc in node.netifs(): if hasattr(ifc, 'control') and ifc.control == True: continue cfg += ' interface "%s";\n'% ifc.name return cfg class BirdBgp(BirdService): '''BGP BIRD Service (configuration generation)''' _name = "BIRD_BGP" _custom_needed = True @classmethod def generatebirdconfig(cls, node): return """ /* This is a sample config that should be customized with appropriate AS numbers * and peers; add one section like this for each neighbor */ protocol bgp { local as 65000; # Customize your AS number neighbor 198.51.100.130 as 64496; # Customize neighbor AS number && IP export filter { # We use non-trivial export rules # This is an example. You should advertise only *your routes* if (source = RTS_DEVICE) || (source = RTS_OSPF) then { # bgp_community.add((65000,64501)); # Assign our community accept; } reject; }; import all; } """ class BirdOspf(BirdService): '''OSPF BIRD Service (configuration generation)''' _name = "BIRD_OSPFv2" @classmethod def generatebirdconfig(cls, node): cfg = 'protocol ospf {\n' cfg += ' export filter {\n' cfg += ' if source = RTS_BGP then {\n' cfg += ' ospf_metric1 = 100;\n' cfg += ' accept;\n' cfg += ' }\n' cfg += ' accept;\n' cfg += ' };\n' cfg += ' area 0.0.0.0 {\n' cfg += cls.generatebirdifcconfig(node) cfg += ' };\n' cfg += '}\n\n' return cfg class BirdRadv(BirdService): '''RADV BIRD Service (configuration generation)''' _name = "BIRD_RADV" @classmethod def generatebirdconfig(cls, node): cfg = '/* This is a sample config that must be customized */\n' cfg += 'protocol radv {\n' cfg += ' # auto configuration on all interfaces\n' cfg += cls.generatebirdifcconfig(node) cfg += ' # Advertise DNS\n' cfg += ' rdnss {\n' cfg += '# lifetime mult 10;\n' cfg += '# lifetime mult 10;\n' cfg += '# ns 2001:0DB8:1234::11;\n' cfg += '# ns 2001:0DB8:1234::11;\n' cfg += '# ns 2001:0DB8:1234::12;\n' cfg += '# ns 2001:0DB8:1234::12;\n' cfg += ' };\n' cfg += '}\n\n' return cfg class BirdRip(BirdService): '''RIP BIRD Service (configuration generation)''' _name = "BIRD_RIP" @classmethod def generatebirdconfig(cls, node): cfg = 'protocol rip {\n' cfg += ' period 10;\n' cfg += ' garbage time 60;\n' cfg += cls.generatebirdifcconfig(node) cfg += ' honor neighbor;\n' cfg += ' authentication none;\n' cfg += ' import all;\n' cfg += ' export all;\n' cfg += '}\n\n' return cfg class BirdStatic(BirdService): '''Static Bird Service (configuration generation)''' _name = "BIRD_static" _custom_needed = True @classmethod def generatebirdconfig(cls, node): cfg = '/* This is a sample config that must be customized */\n' cfg += 'protocol static {\n' cfg += '# route 0.0.0.0/0 via 198.51.100.130; # Default route. Do NOT advertise on BGP !\n' cfg += '# route 203.0.113.0/24 reject; # Sink route\n' cfg += '# route 10.2.0.0/24 via "arc0"; # Secondary network\n' cfg += '}\n\n' return cfg # Register all protocols addservice(Bird) addservice(BirdOspf) addservice(BirdBgp) #addservice(BirdRadv) # untested addservice(BirdRip) addservice(BirdStatic) core-4.8/daemon/core/services/dockersvc.py0000664000175000017500000001611612534327775015637 00000000000000# # CORE # Copyright (c)2014 the Boeing Company. # See the LICENSE file included in this distribution. # # authors: Stuart Marsden # Jeff Ahrenholz # ''' Docker service allows running docker containers within CORE nodes. The running of Docker within a CORE node allows for additional extensibility to the CORE services. This allows network applications and protocols to be easily packaged and run on any node. This service that will add a new group to the services list. This will have a service called Docker which will just start the docker service within the node but not run anything. It will also scan all docker images on the host machine. If any are tagged with 'core' then they will be added as a service to the Docker group. The image will then be auto run if that service is selected. This requires a recent version of Docker. This was tested using a PPA on Ubuntu with version 1.2.0. The version in the standard Ubuntu repo is to old for this purpose (we need --net host). It also requires docker-py (https://pypi.python.org/pypi/docker-py) which can be installed with 'pip install docker-py'. This is used to interface with Docker from the python service. An example use case is to pull an image from Docker.com. A test image has been uploaded for this purpose: sudo docker pull stuartmarsden/multicastping This downloads an image which is based on Ubuntu 14.04 with python and twisted. It runs a simple program that sends a multicast ping and listens and records any it receives. In order for this to appear as a docker service it must be tagged with core. Find out the id by running 'sudo docker images'. You should see all installed images and the one you want looks like this: stuartmarsden/multicastping latest 4833487e66d2 20 hours ago 487 MB The id will be different on your machine so use it in the following command: sudo docker tag 4833487e66d2 stuartmarsden/multicastping:core This image will be listed in the services after we restart the core-daemon: sudo service core-daemon restart You can set up a simple network with a number of PCs connected to a switch. Set the stuartmarsden/multicastping service for all the PCs. When started they will all begin sending Multicast pings. In order to see what is happening you can go in to the terminal of a node and look at the docker log. Easy shorthand is: docker logs $(docker ps -q) Which just shows the log of the running docker container (usually just one per node). I have added this as an observer node to my setup: Name: docker logs Command: bash -c 'docker logs $(docker ps -q) | tail -20' So I can just hover over to see the log which looks like this: Datagram 'Client: Ping' received from ('10.0.0.20', 8005) Datagram 'Client: Ping' received from ('10.0.5.21', 8005) Datagram 'Client: Ping' received from ('10.0.3.20', 8005) Datagram 'Client: Ping' received from ('10.0.4.20', 8005) Datagram 'Client: Ping' received from ('10.0.4.20', 8005) Datagram 'Client: Ping' received from ('10.0.1.21', 8005) Datagram 'Client: Ping' received from ('10.0.4.21', 8005) Datagram 'Client: Ping' received from ('10.0.4.21', 8005) Datagram 'Client: Ping' received from ('10.0.5.20', 8005) Datagram 'Client: Ping' received from ('10.0.0.21', 8005) Datagram 'Client: Ping' received from ('10.0.3.21', 8005) Datagram 'Client: Ping' received from ('10.0.0.20', 8005) Datagram 'Client: Ping' received from ('10.0.5.21', 8005) Datagram 'Client: Ping' received from ('10.0.3.20', 8005) Datagram 'Client: Ping' received from ('10.0.4.20', 8005) Datagram 'Client: Ping' received from ('10.0.4.20', 8005) Datagram 'Client: Ping' received from ('10.0.1.21', 8005) Datagram 'Client: Ping' received from ('10.0.4.21', 8005) Datagram 'Client: Ping' received from ('10.0.4.21', 8005) Datagram 'Client: Ping' received from ('10.0.5.20', 8005) Limitations: 1. Docker images must be downloaded on the host as usually a CORE node does not have access to the internet. 2. Each node isolates running containers (keeps things simple) 3. Recent version of docker needed so that --net host can be used. This does not further abstract the network within a node and allows multicast which is not enabled within Docker containers at the moment. 4. The core-daemon must be restarted for new images to show up. 5. A Docker-daemon is run within each node but the images are shared. This does mean that the daemon attempts to access an SQLlite database within the host. At startup all the nodes will try to access this and it will be locked for most due to contention. The service just does a hackish wait for 1 second and retry. This means all the docker containers can take a while to come up depending on how many nodes you have. ''' import os import sys try: from docker import Client except Exception: pass from core.service import CoreService, addservice from core.misc.ipaddr import IPv4Prefix, IPv6Prefix class DockerService(CoreService): ''' This is a service which will allow running docker containers in a CORE node. ''' _name = "Docker" _group = "Docker" _depends = () _dirs = ('/var/lib/docker/containers/', '/run/shm', '/run/resolvconf',) _configs = ('docker.sh', ) _startindex = 50 _startup = ('sh docker.sh',) _shutdown = ('service docker stop', ) # Container image to start _image = "" @classmethod def generateconfig(cls, node, filename, services): ''' Returns a string having contents of a docker.sh script that can be modified to start a specific docker image. ''' cfg = "#!/bin/sh\n" cfg += "# auto-generated by Docker (docker.py)\n" # Docker likes to think it has DNS set up or it complains. # Unless your network was attached to the Internet this is # non-functional but hides error messages. cfg += 'echo "nameserver 8.8.8.8" > /run/resolvconf/resolv.conf\n' # Starts the docker service. In Ubuntu this is docker.io; in other # distros may just be docker cfg += 'service docker start\n' cfg += "# you could add a command to start a image here eg:\n" if not cls._image: cfg += "# docker run -d --net host --name coreDock \n" else: cfg += """\ result=1 until [ $result -eq 0 ]; do docker run -d --net host --name coreDock %s result=$? # this is to alleviate contention to docker's SQLite database sleep 0.3 done """ % (cls._image, ) return cfg addservice(DockerService) # This auto-loads Docker images having a :core tag, adding them to the list # of services under the "Docker" group. if 'Client' in globals(): client = Client(version='1.10') images = client.images() del client else: images = [] for image in images: if u'' in image['RepoTags'][0]: continue for repo in image['RepoTags']: if u':core' not in repo: continue dockerid = repo.encode('ascii','ignore').split(':')[0] SubClass = type('SubClass', (DockerService,), {'_name': dockerid, '_image': dockerid}) addservice(SubClass) del images core-4.8/daemon/core/services/nrl.py0000664000175000017500000005141312534327775014446 00000000000000# # CORE # Copyright (c)2010-2012 the Boeing Company. # See the LICENSE file included in this distribution. # # author: Jeff Ahrenholz # ''' nrl.py: defines services provided by NRL protolib tools hosted here: http://www.nrl.navy.mil/itd/ncs/products ''' from core.service import CoreService, addservice from core.misc.ipaddr import IPv4Prefix, IPv6Prefix from core.misc.utils import * from core.constants import * class NrlService(CoreService): ''' Parent class for NRL services. Defines properties and methods common to NRL's routing daemons. ''' _name = "Protean" _group = "ProtoSvc" _depends = () _dirs = () _configs = () _startindex = 45 _startup = () _shutdown = () @classmethod def generateconfig(cls, node, filename, services): return "" @staticmethod def firstipv4prefix(node, prefixlen=24): ''' Similar to QuaggaService.routerid(). Helper to return the first IPv4 prefix of a node, using the supplied prefix length. This ignores the interface's prefix length, so e.g. '/32' can turn into '/24'. ''' for ifc in node.netifs(): if hasattr(ifc, 'control') and ifc.control == True: continue for a in ifc.addrlist: if a.find(".") >= 0: addr = a.split('/')[0] pre = IPv4Prefix("%s/%s" % (addr, prefixlen)) return str(pre) #raise ValueError, "no IPv4 address found" return "0.0.0.0/%s" % prefixlen class MgenSinkService(NrlService): _name = "MGEN_Sink" _configs = ("sink.mgen", ) _startindex = 5 _startup = ("mgen input sink.mgen", ) _validate = ("pidof mgen", ) _shutdown = ("killall mgen", ) @classmethod def generateconfig(cls, node, filename, services): cfg = "0.0 LISTEN UDP 5000\n" for ifc in node.netifs(): name = sysctldevname(ifc.name) cfg += "0.0 Join 224.225.1.2 INTERFACE %s\n" % name return cfg @classmethod def getstartup(cls, node, services): cmd =cls._startup[0] cmd += " output /tmp/mgen_%s.log" % node.name return (cmd, ) addservice(MgenSinkService) class NrlNhdp(NrlService): ''' NeighborHood Discovery Protocol for MANET networks. ''' _name = "NHDP" _startup = ("nrlnhdp", ) _shutdown = ("killall nrlnhdp", ) _validate = ("pidof nrlnhdp", ) @classmethod def getstartup(cls, node, services): ''' Generate the appropriate command-line based on node interfaces. ''' cmd = cls._startup[0] cmd += " -l /var/log/nrlnhdp.log" cmd += " -rpipe %s_nhdp" % node.name servicenames = map(lambda x: x._name, services) if "SMF" in servicenames: cmd += " -flooding ecds" cmd += " -smfClient %s_smf" % node.name netifs = filter(lambda x: not getattr(x, 'control', False), \ node.netifs()) if len(netifs) > 0: interfacenames = map(lambda x: x.name, netifs) cmd += " -i " cmd += " -i ".join(interfacenames) return (cmd, ) addservice(NrlNhdp) class NrlSmf(NrlService): ''' Simplified Multicast Forwarding for MANET networks. ''' _name = "SMF" _startup = ("sh startsmf.sh", ) _shutdown = ("killall nrlsmf", ) _validate = ("pidof nrlsmf", ) _configs = ("startsmf.sh", ) @classmethod def generateconfig(cls, node, filename, services): ''' Generate a startup script for SMF. Because nrlsmf does not daemonize, it can cause problems in some situations when launched directly using vcmd. ''' cfg = "#!/bin/sh\n" cfg += "# auto-generated by nrl.py:NrlSmf.generateconfig()\n" comments = "" cmd = "nrlsmf instance %s_smf" % (node.name) servicenames = map(lambda x: x._name, services) netifs = filter(lambda x: not getattr(x, 'control', False), \ node.netifs()) if len(netifs) == 0: return () if "arouted" in servicenames: comments += "# arouted service is enabled\n" cmd += " tap %s_tap" % (node.name,) cmd += " unicast %s" % cls.firstipv4prefix(node, 24) cmd += " push lo,%s resequence on" % netifs[0].name if len(netifs) > 0: if "NHDP" in servicenames: comments += "# NHDP service is enabled\n" cmd += " ecds " elif "OLSR" in servicenames: comments += "# OLSR service is enabled\n" cmd += " smpr " else: cmd += " cf " interfacenames = map(lambda x: x.name, netifs) cmd += ",".join(interfacenames) cmd += " hash MD5" cmd += " log /var/log/nrlsmf.log" cfg += comments + cmd + " < /dev/null > /dev/null 2>&1 &\n\n" return cfg addservice(NrlSmf) class NrlOlsr(NrlService): ''' Optimized Link State Routing protocol for MANET networks. ''' _name = "OLSR" _startup = ("nrlolsrd", ) _shutdown = ("killall nrlolsrd", ) _validate = ("pidof nrlolsrd", ) @classmethod def getstartup(cls, node, services): ''' Generate the appropriate command-line based on node interfaces. ''' cmd = cls._startup[0] # are multiple interfaces supported? No. netifs = list(node.netifs()) if len(netifs) > 0: ifc = netifs[0] cmd += " -i %s" % ifc.name cmd += " -l /var/log/nrlolsrd.log" cmd += " -rpipe %s_olsr" % node.name servicenames = map(lambda x: x._name, services) if "SMF" in servicenames and not "NHDP" in servicenames: cmd += " -flooding s-mpr" cmd += " -smfClient %s_smf" % node.name if "zebra" in servicenames: cmd += " -z" return (cmd, ) addservice(NrlOlsr) class NrlOlsrv2(NrlService): ''' Optimized Link State Routing protocol version 2 for MANET networks. ''' _name = "OLSRv2" _startup = ("nrlolsrv2", ) _shutdown = ("killall nrlolsrv2", ) _validate = ("pidof nrlolsrv2", ) @classmethod def getstartup(cls, node, services): ''' Generate the appropriate command-line based on node interfaces. ''' cmd = cls._startup[0] cmd += " -l /var/log/nrlolsrv2.log" cmd += " -rpipe %s_olsrv2" % node.name servicenames = map(lambda x: x._name, services) if "SMF" in servicenames: cmd += " -flooding ecds" cmd += " -smfClient %s_smf" % node.name cmd += " -p olsr" netifs = filter(lambda x: not getattr(x, 'control', False), \ node.netifs()) if len(netifs) > 0: interfacenames = map(lambda x: x.name, netifs) cmd += " -i " cmd += " -i ".join(interfacenames) return (cmd, ) addservice(NrlOlsrv2) class OlsrOrg(NrlService): ''' Optimized Link State Routing protocol from olsr.org for MANET networks. ''' _name = "OLSRORG" _configs = ("/etc/olsrd/olsrd.conf",) _dirs = ("/etc/olsrd",) _startup = ("olsrd", ) _shutdown = ("killall olsrd", ) _validate = ("pidof olsrd", ) @classmethod def getstartup(cls, node, services): ''' Generate the appropriate command-line based on node interfaces. ''' cmd = cls._startup[0] netifs = filter(lambda x: not getattr(x, 'control', False), \ node.netifs()) if len(netifs) > 0: interfacenames = map(lambda x: x.name, netifs) cmd += " -i " cmd += " -i ".join(interfacenames) return (cmd, ) @classmethod def generateconfig(cls, node, filename, services): ''' Generate a default olsrd config file to use the broadcast address of 255.255.255.255. ''' cfg = """\ # # OLSR.org routing daemon config file # This file contains the usual options for an ETX based # stationary network without fisheye # (for other options see olsrd.conf.default.full) # # Lines starting with a # are discarded # #### ATTENTION for IPv6 users #### # Because of limitations in the parser IPv6 addresses must NOT # begin with a ":", so please add a "0" as a prefix. ########################### ### Basic configuration ### ########################### # keep this settings at the beginning of your first configuration file # Debug level (0-9) # If set to 0 the daemon runs in the background, unless "NoFork" is set to true # (Default is 1) # DebugLevel 1 # IP version to use (4 or 6) # (Default is 4) # IpVersion 4 ################################# ### OLSRd agent configuration ### ################################# # this parameters control the settings of the routing agent which are not # related to the OLSR protocol and it's extensions # FIBMetric controls the metric value of the host-routes OLSRd sets. # - "flat" means that the metric value is always 2. This is the preferred value # because it helps the linux kernel routing to clean up older routes # - "correct" use the hopcount as the metric value. # - "approx" use the hopcount as the metric value too, but does only update the # hopcount if the nexthop changes too # (Default is "flat") # FIBMetric "flat" ####################################### ### Linux specific OLSRd extensions ### ####################################### # these parameters are only working on linux at the moment, but might become # useful on BSD in the future # SrcIpRoutes tells OLSRd to set the Src flag of host routes to the originator-ip # of the node. In addition to this an additional localhost device is created # to make sure the returning traffic can be received. # (Default is "no") # SrcIpRoutes no # Specify the proto tag to be used for routes olsr inserts into kernel # currently only implemented for linux # valid values under linux are 1 .. 254 # 1 gets remapped by olsrd to 0 UNSPECIFIED (1 is reserved for ICMP redirects) # 2 KERNEL routes (not very wise to use) # 3 BOOT (should in fact not be used by routing daemons) # 4 STATIC # 8 .. 15 various routing daemons (gated, zebra, bird, & co) # (defaults to 0 which gets replaced by an OS-specific default value # under linux 3 (BOOT) (for backward compatibility) # RtProto 0 # Activates (in IPv6 mode) the automatic use of NIIT # (see README-Olsr-Extensions) # (default is "yes") # UseNiit yes # Activates the smartgateway ipip tunnel feature. # See README-Olsr-Extensions for a description of smartgateways. # (default is "no") # SmartGateway no # Signals that the server tunnel must always be removed on shutdown, # irrespective of the interface up/down state during startup. # (default is "no") # SmartGatewayAlwaysRemoveServerTunnel no # Determines the maximum number of gateways that can be in use at any given # time. This setting is used to mitigate the effects of breaking connections # (due to the selection of a new gateway) on a dynamic network. # (default is 1) # SmartGatewayUseCount 1 # Determines the take-down percentage for a non-current smart gateway tunnel. # If the cost of the current smart gateway tunnel is less than this percentage # of the cost of the non-current smart gateway tunnel, then the non-current smart # gateway tunnel is taken down because it is then presumed to be 'too expensive'. # This setting is only relevant when SmartGatewayUseCount is larger than 1; # a value of 0 will result in the tunnels not being taken down proactively. # (default is 0) # SmartGatewayTakeDownPercentage 0 # Determines the policy routing script that is executed during startup and # shutdown of olsrd. The script is only executed when SmartGatewayUseCount # is set to a value larger than 1. The script must setup policy routing # rules such that multi-gateway mode works. A sample script is included. # (default is not set) # SmartGatewayPolicyRoutingScript "" # Determines the egress interfaces that are part of the multi-gateway setup and # therefore only relevant when SmartGatewayUseCount is larger than 1 (in which # case it must be explicitly set). # (default is not set) # SmartGatewayEgressInterfaces "" # Determines the routing tables offset for multi-gateway policy routing tables # See the policy routing script for an explanation. # (default is 90) # SmartGatewayTablesOffset 90 # Determines the policy routing rules offset for multi-gateway policy routing # rules. See the policy routing script for an explanation. # (default is 0, which indicates that the rules and tables should be aligned and # puts this value at SmartGatewayTablesOffset - # egress interfaces - # # olsr interfaces) # SmartGatewayRulesOffset 87 # Allows the selection of a smartgateway with NAT (only for IPv4) # (default is "yes") # SmartGatewayAllowNAT yes # Determines the period (in milliseconds) on which a new smart gateway # selection is performed. # (default is 10000 milliseconds) # SmartGatewayPeriod 10000 # Determines the number of times the link state database must be stable # before a new smart gateway is selected. # (default is 6) # SmartGatewayStableCount 6 # When another gateway than the current one has a cost of less than the cost # of the current gateway multiplied by SmartGatewayThreshold then the smart # gateway is switched to the other gateway. The unit is percentage. # (defaults to 0) # SmartGatewayThreshold 0 # The weighing factor for the gateway uplink bandwidth (exit link, uplink). # See README-Olsr-Extensions for a description of smart gateways. # (default is 1) # SmartGatewayWeightExitLinkUp 1 # The weighing factor for the gateway downlink bandwidth (exit link, downlink). # See README-Olsr-Extensions for a description of smart gateways. # (default is 1) # SmartGatewayWeightExitLinkDown 1 # The weighing factor for the ETX costs. # See README-Olsr-Extensions for a description of smart gateways. # (default is 1) # SmartGatewayWeightEtx 1 # The divider for the ETX costs. # See README-Olsr-Extensions for a description of smart gateways. # (default is 0) # SmartGatewayDividerEtx 0 # Defines what kind of Uplink this node will publish as a # smartgateway. The existence of the uplink is detected by # a route to 0.0.0.0/0, ::ffff:0:0/96 and/or 2000::/3. # possible values are "none", "ipv4", "ipv6", "both" # (default is "both") # SmartGatewayUplink "both" # Specifies if the local ipv4 uplink use NAT # (default is "yes") # SmartGatewayUplinkNAT yes # Specifies the speed of the uplink in kilobit/s. # First parameter is upstream, second parameter is downstream # (default is 128/1024) # SmartGatewaySpeed 128 1024 # Specifies the EXTERNAL ipv6 prefix of the uplink. A prefix # length of more than 64 is not allowed. # (default is 0::/0 # SmartGatewayPrefix 0::/0 ############################## ### OLSR protocol settings ### ############################## # HNA (Host network association) allows the OLSR to announce # additional IPs or IP subnets to the net that are reachable # through this node. # Syntax for HNA4 is "network-address network-mask" # Syntax for HNA6 is "network-address prefix-length" # (default is no HNA) Hna4 { # Internet gateway # 0.0.0.0 0.0.0.0 # specific small networks reachable through this node # 15.15.0.0 255.255.255.0 } Hna6 { # Internet gateway # 0:: 0 # specific small networks reachable through this node # fec0:2200:106:0:0:0:0:0 48 } ################################ ### OLSR protocol extensions ### ################################ # Link quality algorithm (only for lq level 2) # (see README-Olsr-Extensions) # - "etx_float", a floating point ETX with exponential aging # - "etx_fpm", same as ext_float, but with integer arithmetic # - "etx_ff" (ETX freifunk), an etx variant which use all OLSR # traffic (instead of only hellos) for ETX calculation # - "etx_ffeth", an incompatible variant of etx_ff that allows # ethernet links with ETX 0.1. # (defaults to "etx_ff") # LinkQualityAlgorithm "etx_ff" # Fisheye mechanism for TCs (0 meansoff, 1 means on) # (default is 1) LinkQualityFishEye 0 ##################################### ### Example plugin configurations ### ##################################### # Olsrd plugins to load # This must be the absolute path to the file # or the loader will use the following scheme: # - Try the paths in the LD_LIBRARY_PATH # environment variable. # - The list of libraries cached in /etc/ld.so.cache # - /lib, followed by /usr/lib # # the examples in this list are for linux, so check if the plugin is # available if you use windows/BSD. # each plugin should have a README file in it's lib subfolder # LoadPlugin "olsrd_txtinfo.dll" #LoadPlugin "olsrd_txtinfo.so.0.1" #{ # the default port is 2006 but you can change it like this: #PlParam "port" "8080" # You can set a "accept" single address to allow to connect to # txtinfo. If no address is specified, then localhost (127.0.0.1) # is allowed by default. txtinfo will only use the first "accept" # parameter specified and will ignore the rest. # to allow a specific host: #PlParam "accept" "172.29.44.23" # if you set it to 0.0.0.0, it will accept all connections #PlParam "accept" "0.0.0.0" #} ############################################# ### OLSRD default interface configuration ### ############################################# # the default interface section can have the same values as the following # interface configuration. It will allow you so set common options for all # interfaces. InterfaceDefaults { Ip4Broadcast 255.255.255.255 } ###################################### ### OLSRd Interfaces configuration ### ###################################### # multiple interfaces can be specified for a single configuration block # multiple configuration blocks can be specified # WARNING, don't forget to insert your interface names here ! #Interface "" "" #{ # Interface Mode is used to prevent unnecessary # packet forwarding on switched ethernet interfaces # valid Modes are "mesh" and "ether" # (default is "mesh") # Mode "mesh" #} """ return cfg addservice(OlsrOrg) class MgenActor(NrlService): ''' ZpcMgenActor. ''' # a unique name is required, without spaces _name = "MgenActor" # you can create your own group here _group = "ProtoSvc" # list of other services this service depends on _depends = () # per-node directories _dirs = () # generated files (without a full path this file goes in the node's dir, # e.g. /tmp/pycore.12345/n1.conf/) _configs = ('start_mgen_actor.sh', ) # this controls the starting order vs other enabled services _startindex = 50 # list of startup commands, also may be generated during startup _startup = ("sh start_mgen_actor.sh", ) # list of validation commands _validate = ("pidof mgen", ) # list of shutdown commands _shutdown = ("killall mgen", ) @classmethod def generateconfig(cls, node, filename, services): ''' Generate a startup script for MgenActor. Because mgenActor does not daemonize, it can cause problems in some situations when launched directly using vcmd. ''' cfg = "#!/bin/sh\n" cfg += "# auto-generated by nrl.py:MgenActor.generateconfig()\n" comments = "" cmd = "python /usr/local/bin/mgenBasicActor.py -n %s -a 0.0.0.0 -p 5555" % (node.name) servicenames = map(lambda x: x._name, services) netifs = filter(lambda x: not getattr(x, 'control', False), \ node.netifs()) if len(netifs) == 0: return () cfg += comments + cmd + " < /dev/null > /dev/null 2>&1 &\n\n" return cfg # this line is required to add the above class to the list of available services addservice(MgenActor) class Arouted(NrlService): ''' Adaptive Routing ''' _name = "arouted" _configs = ("startarouted.sh", ) _startindex = NrlService._startindex + 10 _startup = ("sh startarouted.sh", ) _shutdown = ("pkill arouted", ) _validate = ("pidof arouted", ) @classmethod def generateconfig(cls, node, filename, services): ''' Return the Quagga.conf or quaggaboot.sh file contents. ''' cfg = """ #!/bin/sh for f in "/tmp/%s_smf"; do count=1 until [ -e "$f" ]; do if [ $count -eq 10 ]; then echo "ERROR: nrlmsf pipe not found: $f" >&2 exit 1 fi sleep 0.1 count=$(($count + 1)) done done """ % (node.name) cfg += "ip route add %s dev lo\n" % cls.firstipv4prefix(node, 24) cfg += "arouted instance %s_smf tap %s_tap" % (node.name, node.name) cfg += " stability 10" # seconds to consider a new route valid cfg += " 2>&1 > /var/log/arouted.log &\n\n" return cfg # experimental #addservice(Arouted) core-4.8/daemon/core/services/quagga.py0000664000175000017500000004177512534327775015132 00000000000000# # CORE # Copyright (c)2010-2012 the Boeing Company. # See the LICENSE file included in this distribution. # # author: Jeff Ahrenholz # ''' quagga.py: defines routing services provided by Quagga. ''' import os if os.uname()[0] == "Linux": from core.netns import nodes elif os.uname()[0] == "FreeBSD": from core.bsd import nodes from core.service import CoreService, addservice from core.misc.ipaddr import IPv4Prefix, isIPv4Address, isIPv6Address from core.api import coreapi from core.constants import * QUAGGA_USER="root" QUAGGA_GROUP="root" if os.uname()[0] == "FreeBSD": QUAGGA_GROUP="wheel" class Zebra(CoreService): ''' ''' _name = "zebra" _group = "Quagga" _depends = ("vtysh", ) _dirs = ("/usr/local/etc/quagga", "/var/run/quagga") _configs = ("/usr/local/etc/quagga/Quagga.conf", "quaggaboot.sh","/usr/local/etc/quagga/vtysh.conf") _startindex = 35 _startup = ("sh quaggaboot.sh zebra",) _shutdown = ("killall zebra", ) _validate = ("pidof zebra", ) @classmethod def generateconfig(cls, node, filename, services): ''' Return the Quagga.conf or quaggaboot.sh file contents. ''' if filename == cls._configs[0]: return cls.generateQuaggaConf(node, services) elif filename == cls._configs[1]: return cls.generateQuaggaBoot(node, services) elif filename == cls._configs[2]: return cls.generateVtyshConf(node, services) else: raise ValueError @classmethod def generateVtyshConf(cls, node, services): ''' Returns configuration file text. ''' return "service integrated-vtysh-config" @classmethod def generateQuaggaConf(cls, node, services): ''' Returns configuration file text. Other services that depend on zebra will have generatequaggaifcconfig() and generatequaggaconfig() hooks that are invoked here. ''' # we could verify here that filename == Quagga.conf cfg = "" for ifc in node.netifs(): cfg += "interface %s\n" % ifc.name # include control interfaces in addressing but not routing daemons if hasattr(ifc, 'control') and ifc.control == True: cfg += " " cfg += "\n ".join(map(cls.addrstr, ifc.addrlist)) cfg += "\n" continue cfgv4 = "" cfgv6 = "" want_ipv4 = False want_ipv6 = False for s in services: if cls._name not in s._depends: continue ifccfg = s.generatequaggaifcconfig(node, ifc) if s._ipv4_routing: want_ipv4 = True if s._ipv6_routing: want_ipv6 = True cfgv6 += ifccfg else: cfgv4 += ifccfg if want_ipv4: ipv4list = filter(lambda x: isIPv4Address(x.split('/')[0]), ifc.addrlist) cfg += " " cfg += "\n ".join(map(cls.addrstr, ipv4list)) cfg += "\n" cfg += cfgv4 if want_ipv6: ipv6list = filter(lambda x: isIPv6Address(x.split('/')[0]), ifc.addrlist) cfg += " " cfg += "\n ".join(map(cls.addrstr, ipv6list)) cfg += "\n" cfg += cfgv6 cfg += "!\n" for s in services: if cls._name not in s._depends: continue cfg += s.generatequaggaconfig(node) return cfg @staticmethod def addrstr(x): ''' helper for mapping IP addresses to zebra config statements ''' if x.find(".") >= 0: return "ip address %s" % x elif x.find(":") >= 0: return "ipv6 address %s" % x else: raise Value, "invalid address: %s", x @classmethod def generateQuaggaBoot(cls, node, services): ''' Generate a shell script used to boot the Quagga daemons. ''' try: quagga_bin_search = node.session.cfg['quagga_bin_search'] quagga_sbin_search = node.session.cfg['quagga_sbin_search'] except KeyError: quagga_bin_search = '"/usr/local/bin /usr/bin /usr/lib/quagga"' quagga_sbin_search = '"/usr/local/sbin /usr/sbin /usr/lib/quagga"' return """\ #!/bin/sh # auto-generated by zebra service (quagga.py) QUAGGA_CONF=%s QUAGGA_SBIN_SEARCH=%s QUAGGA_BIN_SEARCH=%s QUAGGA_STATE_DIR=%s QUAGGA_USER=%s QUAGGA_GROUP=%s searchforprog() { prog=$1 searchpath=$@ ret= for p in $searchpath; do if [ -x $p/$prog ]; then ret=$p break fi done echo $ret } confcheck() { CONF_DIR=`dirname $QUAGGA_CONF` # if /etc/quagga exists, point /etc/quagga/Quagga.conf -> CONF_DIR if [ "$CONF_DIR" != "/etc/quagga" ] && [ -d /etc/quagga ] && [ ! -e /etc/quagga/Quagga.conf ]; then ln -s $CONF_DIR/Quagga.conf /etc/quagga/Quagga.conf fi # if /etc/quagga exists, point /etc/quagga/vtysh.conf -> CONF_DIR if [ "$CONF_DIR" != "/etc/quagga" ] && [ -d /etc/quagga ] && [ ! -e /etc/quagga/vtysh.conf ]; then ln -s $CONF_DIR/vtysh.conf /etc/quagga/vtysh.conf fi } waitforvtyfiles() { for f in "$@"; do count=1 until [ -e $QUAGGA_STATE_DIR/$f ]; do if [ $count -eq 10 ]; then echo "ERROR: vty file not found: $QUAGGA_STATE_DIR/$f" >&2 return 1 fi sleep 0.1 count=$(($count + 1)) done done } bootdaemon() { QUAGGA_SBIN_DIR=$(searchforprog $1 $QUAGGA_SBIN_SEARCH) if [ "z$QUAGGA_SBIN_DIR" = "z" ]; then echo "ERROR: Quagga's '$1' daemon not found in search path:" echo " $QUAGGA_SBIN_SEARCH" return 1 fi if [ "$1" != "zebra" ]; then waitforvtyfiles zebra.vty fi $QUAGGA_SBIN_DIR/$1 -u $QUAGGA_USER -g $QUAGGA_GROUP -d } bootvtysh() { QUAGGA_BIN_DIR=$(searchforprog $1 $QUAGGA_BIN_SEARCH) if [ "z$QUAGGA_BIN_DIR" = "z" ]; then echo "ERROR: Quagga's '$1' daemon not found in search path:" echo " $QUAGGA_SBIN_SEARCH" return 1 fi vtyfiles="zebra.vty" for r in rip ripng ospf6 ospf bgp babel; do if grep -q "^router \<${r}\>" $QUAGGA_CONF; then vtyfiles="$vtyfiles ${r}d.vty" fi done # wait for Quagga daemon vty files to appear before invoking vtysh waitforvtyfiles $vtyfiles $QUAGGA_BIN_DIR/vtysh -b } confcheck if [ "x$1" = "x" ]; then echo "ERROR: missing the name of the Quagga daemon to boot" exit 1 elif [ "$1" = "vtysh" ]; then bootvtysh $1 else bootdaemon $1 fi """ % (cls._configs[0], quagga_sbin_search, quagga_bin_search, \ QUAGGA_STATE_DIR, QUAGGA_USER, QUAGGA_GROUP) addservice(Zebra) class QuaggaService(CoreService): ''' Parent class for Quagga services. Defines properties and methods common to Quagga's routing daemons. ''' _name = "QuaggaDaemon" _group = "Quagga" _depends = ("zebra", ) _dirs = () _configs = () _startindex = 40 _startup = () _shutdown = () _meta = "The config file for this service can be found in the Zebra service." _ipv4_routing = False _ipv6_routing = False @staticmethod def routerid(node): ''' Helper to return the first IPv4 address of a node as its router ID. ''' for ifc in node.netifs(): if hasattr(ifc, 'control') and ifc.control == True: continue for a in ifc.addrlist: if a.find(".") >= 0: return a .split('/') [0] #raise ValueError, "no IPv4 address found for router ID" return "0.0.0.0" @staticmethod def rj45check(ifc): ''' Helper to detect whether interface is connected an external RJ45 link. ''' if ifc.net: for peerifc in ifc.net.netifs(): if peerifc == ifc: continue if isinstance(peerifc, nodes.RJ45Node): return True return False @classmethod def generateconfig(cls, node, filename, services): return "" @classmethod def generatequaggaifcconfig(cls, node, ifc): return "" @classmethod def generatequaggaconfig(cls, node): return "" class Ospfv2(QuaggaService): ''' The OSPFv2 service provides IPv4 routing for wired networks. It does not build its own configuration file but has hooks for adding to the unified Quagga.conf file. ''' _name = "OSPFv2" _startup = ("sh quaggaboot.sh ospfd",) _shutdown = ("killall ospfd", ) _validate = ("pidof ospfd", ) _ipv4_routing = True @staticmethod def mtucheck(ifc): ''' Helper to detect MTU mismatch and add the appropriate OSPF mtu-ignore command. This is needed when e.g. a node is linked via a GreTap device. ''' if ifc.mtu != 1500: # a workaround for PhysicalNode GreTap, which has no knowledge of # the other nodes/nets return " ip ospf mtu-ignore\n" if not ifc.net: return "" for i in ifc.net.netifs(): if i.mtu != ifc.mtu: return " ip ospf mtu-ignore\n" return "" @staticmethod def ptpcheck(ifc): ''' Helper to detect whether interface is connected to a notional point-to-point link. ''' if isinstance(ifc.net, nodes.PtpNet): return " ip ospf network point-to-point\n" return "" @classmethod def generatequaggaconfig(cls, node): cfg = "router ospf\n" rtrid = cls.routerid(node) cfg += " router-id %s\n" % rtrid # network 10.0.0.0/24 area 0 for ifc in node.netifs(): if hasattr(ifc, 'control') and ifc.control == True: continue for a in ifc.addrlist: if a.find(".") < 0: continue net = IPv4Prefix(a) cfg += " network %s area 0\n" % net cfg += "!\n" return cfg @classmethod def generatequaggaifcconfig(cls, node, ifc): return cls.mtucheck(ifc) #cfg = cls.mtucheck(ifc) # external RJ45 connections will use default OSPF timers #if cls.rj45check(ifc): # return cfg #cfg += cls.ptpcheck(ifc) #return cfg + """\ # ip ospf hello-interval 2 # ip ospf dead-interval 6 # ip ospf retransmit-interval 5 #""" addservice(Ospfv2) class Ospfv3(QuaggaService): ''' The OSPFv3 service provides IPv6 routing for wired networks. It does not build its own configuration file but has hooks for adding to the unified Quagga.conf file. ''' _name = "OSPFv3" _startup = ("sh quaggaboot.sh ospf6d",) _shutdown = ("killall ospf6d", ) _validate = ("pidof ospf6d", ) _ipv4_routing = True _ipv6_routing = True @staticmethod def minmtu(ifc): ''' Helper to discover the minimum MTU of interfaces linked with the given interface. ''' mtu = ifc.mtu if not ifc.net: return mtu for i in ifc.net.netifs(): if i.mtu < mtu: mtu = i.mtu return mtu @classmethod def mtucheck(cls, ifc): ''' Helper to detect MTU mismatch and add the appropriate OSPFv3 ifmtu command. This is needed when e.g. a node is linked via a GreTap device. ''' minmtu = cls.minmtu(ifc) if minmtu < ifc.mtu: return " ipv6 ospf6 ifmtu %d\n" % minmtu else: return "" @staticmethod def ptpcheck(ifc): ''' Helper to detect whether interface is connected to a notional point-to-point link. ''' if isinstance(ifc.net, nodes.PtpNet): return " ipv6 ospf6 network point-to-point\n" return "" @classmethod def generatequaggaconfig(cls, node): cfg = "router ospf6\n" rtrid = cls.routerid(node) cfg += " router-id %s\n" % rtrid for ifc in node.netifs(): if hasattr(ifc, 'control') and ifc.control == True: continue cfg += " interface %s area 0.0.0.0\n" % ifc.name cfg += "!\n" return cfg @classmethod def generatequaggaifcconfig(cls, node, ifc): return cls.mtucheck(ifc) #cfg = cls.mtucheck(ifc) # external RJ45 connections will use default OSPF timers #if cls.rj45check(ifc): # return cfg #cfg += cls.ptpcheck(ifc) #return cfg + """\ # ipv6 ospf6 hello-interval 2 # ipv6 ospf6 dead-interval 6 # ipv6 ospf6 retransmit-interval 5 #""" addservice(Ospfv3) class Ospfv3mdr(Ospfv3): ''' The OSPFv3 MANET Designated Router (MDR) service provides IPv6 routing for wireless networks. It does not build its own configuration file but has hooks for adding to the unified Quagga.conf file. ''' _name = "OSPFv3MDR" _ipv4_routing = True @classmethod def generatequaggaifcconfig(cls, node, ifc): cfg = cls.mtucheck(ifc) cfg += " ipv6 ospf6 instance-id 65\n" if ifc.net is not None and \ isinstance(ifc.net, (nodes.WlanNode, nodes.EmaneNode)): return cfg + """\ ipv6 ospf6 hello-interval 2 ipv6 ospf6 dead-interval 6 ipv6 ospf6 retransmit-interval 5 ipv6 ospf6 network manet-designated-router ipv6 ospf6 diffhellos ipv6 ospf6 adjacencyconnectivity uniconnected ipv6 ospf6 lsafullness mincostlsa """ else: return cfg addservice(Ospfv3mdr) class Bgp(QuaggaService): '''' The BGP service provides interdomain routing. Peers must be manually configured, with a full mesh for those having the same AS number. ''' _name = "BGP" _startup = ("sh quaggaboot.sh bgpd",) _shutdown = ("killall bgpd", ) _validate = ("pidof bgpd", ) _custom_needed = True _ipv4_routing = True _ipv6_routing = True @classmethod def generatequaggaconfig(cls, node): cfg = "!\n! BGP configuration\n!\n" cfg += "! You should configure the AS number below,\n" cfg += "! along with this router's peers.\n!\n" cfg += "router bgp %s\n" % node.objid rtrid = cls.routerid(node) cfg += " bgp router-id %s\n" % rtrid cfg += " redistribute connected\n" cfg += "! neighbor 1.2.3.4 remote-as 555\n!\n" return cfg addservice(Bgp) class Rip(QuaggaService): ''' The RIP service provides IPv4 routing for wired networks. ''' _name = "RIP" _startup = ("sh quaggaboot.sh ripd",) _shutdown = ("killall ripd", ) _validate = ("pidof ripd", ) _ipv4_routing = True @classmethod def generatequaggaconfig(cls, node): cfg = """\ router rip redistribute static redistribute connected redistribute ospf network 0.0.0.0/0 ! """ return cfg addservice(Rip) class Ripng(QuaggaService): ''' The RIP NG service provides IPv6 routing for wired networks. ''' _name = "RIPNG" _startup = ("sh quaggaboot.sh ripngd",) _shutdown = ("killall ripngd", ) _validate = ("pidof ripngd", ) _ipv6_routing = True @classmethod def generatequaggaconfig(cls, node): cfg = """\ router ripng redistribute static redistribute connected redistribute ospf6 network ::/0 ! """ return cfg addservice(Ripng) class Babel(QuaggaService): ''' The Babel service provides a loop-avoiding distance-vector routing protocol for IPv6 and IPv4 with fast convergence properties. ''' _name = "Babel" _startup = ("sh quaggaboot.sh babeld",) _shutdown = ("killall babeld", ) _validate = ("pidof babeld", ) _ipv6_routing = True @classmethod def generatequaggaconfig(cls, node): cfg = "router babel\n" for ifc in node.netifs(): if hasattr(ifc, 'control') and ifc.control == True: continue cfg += " network %s\n" % ifc.name cfg += " redistribute static\n redistribute connected\n" return cfg @classmethod def generatequaggaifcconfig(cls, node, ifc): type = "wired" if ifc.net and ifc.net.linktype == coreapi.CORE_LINK_WIRELESS: return " babel wireless\n no babel split-horizon\n" else: return " babel wired\n babel split-horizon\n" addservice(Babel) class Vtysh(CoreService): ''' Simple service to run vtysh -b (boot) after all Quagga daemons have started. ''' _name = "vtysh" _group = "Quagga" _startindex = 45 _startup = ("sh quaggaboot.sh vtysh",) _shutdown = () @classmethod def generateconfig(cls, node, filename, services): return "" addservice(Vtysh) core-4.8/daemon/core/services/security.py0000664000175000017500000000733612534327775015527 00000000000000# # CORE - define security services : vpnclient, vpnserver, ipsec and firewall # # Copyright (c)2011-2012 the Boeing Company. # See the LICENSE file included in this distribution. # ''' security.py: defines security services (vpnclient, vpnserver, ipsec and firewall) ''' import os from core.service import CoreService, addservice from core.constants import * class VPNClient(CoreService): ''' ''' _name = "VPNClient" _group = "Security" _configs = ('vpnclient.sh', ) _startindex = 60 _startup = ('sh vpnclient.sh',) _shutdown = ("killall openvpn",) _validate = ("pidof openvpn", ) _custom_needed = True @classmethod def generateconfig(cls, node, filename, services): ''' Return the client.conf and vpnclient.sh file contents to ''' cfg = "#!/bin/sh\n" cfg += "# custom VPN Client configuration for service (security.py)\n" fname = "%s/examples/services/sampleVPNClient" % CORE_DATA_DIR try: cfg += open(fname, "rb").read() except e: print "Error opening VPN client configuration template (%s): %s" % \ (fname, e) return cfg # this line is required to add the above class to the list of available services addservice(VPNClient) class VPNServer(CoreService): ''' ''' _name = "VPNServer" _group = "Security" _configs = ('vpnserver.sh', ) _startindex = 50 _startup = ('sh vpnserver.sh',) _shutdown = ("killall openvpn",) _validate = ("pidof openvpn", ) _custom_needed = True @classmethod def generateconfig(cls, node, filename, services): ''' Return the sample server.conf and vpnserver.sh file contents to GUI for user customization. ''' cfg = "#!/bin/sh\n" cfg += "# custom VPN Server Configuration for service (security.py)\n" fname = "%s/examples/services/sampleVPNServer" % CORE_DATA_DIR try: cfg += open(fname, "rb").read() except e: print "Error opening VPN server configuration template (%s): %s" % \ (fname, e) return cfg addservice(VPNServer) class IPsec(CoreService): ''' ''' _name = "IPsec" _group = "Security" _configs = ('ipsec.sh', ) _startindex = 60 _startup = ('sh ipsec.sh',) _shutdown = ("killall racoon",) _custom_needed = True @classmethod def generateconfig(cls, node, filename, services): ''' Return the ipsec.conf and racoon.conf file contents to GUI for user customization. ''' cfg = "#!/bin/sh\n" cfg += "# set up static tunnel mode security assocation for service " cfg += "(security.py)\n" fname = "%s/examples/services/sampleIPsec" % CORE_DATA_DIR try: cfg += open(fname, "rb").read() except e: print "Error opening IPsec configuration template (%s): %s" % \ (fname, e) return cfg addservice(IPsec) class Firewall(CoreService): ''' ''' _name = "Firewall" _group = "Security" _configs = ('firewall.sh', ) _startindex = 20 _startup = ('sh firewall.sh',) _custom_needed = True @classmethod def generateconfig(cls, node, filename, services): ''' Return the firewall rule examples to GUI for user customization. ''' cfg = "#!/bin/sh\n" cfg += "# custom node firewall rules for service (security.py)\n" fname = "%s/examples/services/sampleFirewall" % CORE_DATA_DIR try: cfg += open(fname, "rb").read() except e: print "Error opening Firewall configuration template (%s): %s" % \ (fname, e) return cfg addservice(Firewall) core-4.8/daemon/core/services/ucarp.py0000664000175000017500000001117112534327775014762 00000000000000# # CORE configuration for UCARP # Copyright (c) 2012 Jonathan deBoer # See the LICENSE file included in this distribution. # # # author: Jonathan deBoer # ''' ucarp.py: defines high-availability IP address controlled by ucarp ''' import os from core.service import CoreService, addservice from core.misc.ipaddr import IPv4Prefix from core.constants import * UCARP_ETC="/usr/local/etc/ucarp" class Ucarp(CoreService): ''' ''' _name = "ucarp" _group = "Utility" _depends = ( ) _dirs = (UCARP_ETC, ) _configs = (UCARP_ETC + "/default.sh", UCARP_ETC + "/default-up.sh", UCARP_ETC + "/default-down.sh", "ucarpboot.sh",) _startindex = 65 _startup = ("sh ucarpboot.sh",) _shutdown = ("killall ucarp", ) _validate = ("pidof ucarp", ) @classmethod def generateconfig(cls, node, filename, services): ''' Return the default file contents ''' if filename == cls._configs[0]: return cls.generateUcarpConf(node, services) elif filename == cls._configs[1]: return cls.generateVipUp(node, services) elif filename == cls._configs[2]: return cls.generateVipDown(node, services) elif filename == cls._configs[3]: return cls.generateUcarpBoot(node, services) else: raise ValueError @classmethod def generateUcarpConf(cls, node, services): ''' Returns configuration file text. ''' try: ucarp_bin = node.session.cfg['ucarp_bin'] except KeyError: ucarp_bin = "/usr/sbin/ucarp" return """\ #!/bin/sh # Location of UCARP executable UCARP_EXEC=%s # Location of the UCARP config directory UCARP_CFGDIR=%s # Logging Facility FACILITY=daemon # Instance ID # Any number from 1 to 255 INSTANCE_ID=1 # Password # Master and Backup(s) need to be the same PASSWORD="changeme" # The failover application address VIRTUAL_ADDRESS=127.0.0.254 VIRTUAL_NET=8 # Interface for IP Address INTERFACE=lo # Maintanence address of the local machine SOURCE_ADDRESS=127.0.0.1 # The ratio number to be considered before marking the node as dead DEAD_RATIO=3 # UCARP base, lower number will be preferred master # set to same to have master stay as long as possible UCARP_BASE=1 SKEW=0 # UCARP options # -z run shutdown script on exit # -P force preferred master # -n don't run down script at start up when we are backup # -M use broadcast instead of multicast # -S ignore interface state OPTIONS="-z -n -M" # Send extra parameter to down and up scripts #XPARAM="-x " XPARAM="-x ${VIRTUAL_NET}" # The start and stop scripts START_SCRIPT=${UCARP_CFGDIR}/default-up.sh STOP_SCRIPT=${UCARP_CFGDIR}/default-down.sh # These line should not need to be touched UCARP_OPTS="$OPTIONS -b $UCARP_BASE -k $SKEW -i $INTERFACE -v $INSTANCE_ID -p $PASSWORD -u $START_SCRIPT -d $STOP_SCRIPT -a $VIRTUAL_ADDRESS -s $SOURCE_ADDRESS -f $FACILITY $XPARAM" ${UCARP_EXEC} -B ${UCARP_OPTS} """ % (ucarp_bin, UCARP_ETC) @classmethod def generateUcarpBoot(cls, node, services): ''' Generate a shell script used to boot the Ucarp daemons. ''' try: ucarp_bin = node.session.cfg['ucarp_bin'] except KeyError: ucarp_bin = "/usr/sbin/ucarp" return """\ #!/bin/sh # Location of the UCARP config directory UCARP_CFGDIR=%s chmod a+x ${UCARP_CFGDIR}/*.sh # Start the default ucarp daemon configuration ${UCARP_CFGDIR}/default.sh """ % (UCARP_ETC) @classmethod def generateVipUp(cls, node, services): ''' Generate a shell script used to start the virtual ip ''' try: ucarp_bin = node.session.cfg['ucarp_bin'] except KeyError: ucarp_bin = "/usr/sbin/ucarp" return """\ #!/bin/bash # Should be invoked as "default-up.sh " exec 2> /dev/null IP="${2}" NET="${3}" if [ -z "$NET" ]; then NET="24" fi /sbin/ip addr add ${IP}/${NET} dev "$1" """ @classmethod def generateVipDown(cls, node, services): ''' Generate a shell script used to stop the virtual ip ''' try: ucarp_bin = node.session.cfg['ucarp_bin'] except KeyError: ucarp_bin = "/usr/sbin/ucarp" return """\ #!/bin/bash # Should be invoked as "default-down.sh " exec 2> /dev/null IP="${2}" NET="${3}" if [ -z "$NET" ]; then NET="24" fi /sbin/ip addr del ${IP}/${NET} dev "$1" """ addservice(Ucarp) core-4.8/daemon/core/services/utility.py0000664000175000017500000005200112534327775015350 00000000000000# # CORE # Copyright (c)2010-2014 the Boeing Company. # See the LICENSE file included in this distribution. # # author: Jeff Ahrenholz # ''' utility.py: defines miscellaneous utility services. ''' import os from core.service import CoreService, addservice from core.misc.ipaddr import IPv4Prefix, IPv6Prefix from core.misc.utils import * from core.constants import * class UtilService(CoreService): ''' Parent class for utility services. ''' _name = "UtilityProcess" _group = "Utility" _depends = () _dirs = () _configs = () _startindex = 80 _startup = () _shutdown = () @classmethod def generateconfig(cls, node, filename, services): return "" class IPForwardService(UtilService): _name = "IPForward" _configs = ("ipforward.sh", ) _startindex = 5 _startup = ("sh ipforward.sh", ) @classmethod def generateconfig(cls, node, filename, services): if os.uname()[0] == "Linux": return cls.generateconfiglinux(node, filename, services) elif os.uname()[0] == "FreeBSD": return cls.generateconfigbsd(node, filename, services) else: raise Exception, "unknown platform" @classmethod def generateconfiglinux(cls, node, filename, services): cfg = """\ #!/bin/sh # auto-generated by IPForward service (utility.py) %s -w net.ipv4.conf.all.forwarding=1 %s -w net.ipv6.conf.all.forwarding=1 %s -w net.ipv4.conf.all.send_redirects=0 %s -w net.ipv4.conf.all.rp_filter=0 %s -w net.ipv4.conf.default.rp_filter=0 """ % (SYSCTL_BIN, SYSCTL_BIN, SYSCTL_BIN, SYSCTL_BIN, SYSCTL_BIN) for ifc in node.netifs(): name = sysctldevname(ifc.name) cfg += "%s -w net.ipv4.conf.%s.forwarding=1\n" % (SYSCTL_BIN, name) cfg += "%s -w net.ipv4.conf.%s.send_redirects=0\n" % \ (SYSCTL_BIN, name) cfg += "%s -w net.ipv4.conf.%s.rp_filter=0\n" % (SYSCTL_BIN, name) return cfg @classmethod def generateconfigbsd(cls, node, filename, services): return """\ #!/bin/sh # auto-generated by IPForward service (utility.py) %s -w net.inet.ip.forwarding=1 %s -w net.inet6.ip6.forwarding=1 %s -w net.inet.icmp.bmcastecho=1 %s -w net.inet.icmp.icmplim=0 """ % (SYSCTL_BIN, SYSCTL_BIN, SYSCTL_BIN, SYSCTL_BIN) addservice(IPForwardService) class DefaultRouteService(UtilService): _name = "DefaultRoute" _configs = ("defaultroute.sh",) _startup = ("sh defaultroute.sh",) @classmethod def generateconfig(cls, node, filename, services): cfg = "#!/bin/sh\n" cfg += "# auto-generated by DefaultRoute service (utility.py)\n" for ifc in node.netifs(): if hasattr(ifc, 'control') and ifc.control == True: continue cfg += "\n".join(map(cls.addrstr, ifc.addrlist)) cfg += "\n" return cfg @staticmethod def addrstr(x): if x.find(":") >= 0: net = IPv6Prefix(x) fam = "inet6 ::" else: net = IPv4Prefix(x) fam = "inet 0.0.0.0" if net.maxaddr() == net.minaddr(): return "" else: if os.uname()[0] == "Linux": rtcmd = "ip route add default via" elif os.uname()[0] == "FreeBSD": rtcmd = "route add -%s" % fam else: raise Exception, "unknown platform" return "%s %s" % (rtcmd, net.minaddr()) addservice(DefaultRouteService) class DefaultMulticastRouteService(UtilService): _name = "DefaultMulticastRoute" _configs = ("defaultmroute.sh",) _startup = ("sh defaultmroute.sh",) @classmethod def generateconfig(cls, node, filename, services): cfg = "#!/bin/sh\n" cfg += "# auto-generated by DefaultMulticastRoute service (utility.py)\n" cfg += "# the first interface is chosen below; please change it " cfg += "as needed\n" for ifc in node.netifs(): if hasattr(ifc, 'control') and ifc.control == True: continue if os.uname()[0] == "Linux": rtcmd = "ip route add 224.0.0.0/4 dev" elif os.uname()[0] == "FreeBSD": rtcmd = "route add 224.0.0.0/4 -iface" else: raise Exception, "unknown platform" cfg += "%s %s\n" % (rtcmd, ifc.name) cfg += "\n" break return cfg addservice(DefaultMulticastRouteService) class StaticRouteService(UtilService): _name = "StaticRoute" _configs = ("staticroute.sh",) _startup = ("sh staticroute.sh",) _custom_needed = True @classmethod def generateconfig(cls, node, filename, services): cfg = "#!/bin/sh\n" cfg += "# auto-generated by StaticRoute service (utility.py)\n#\n" cfg += "# NOTE: this service must be customized to be of any use\n" cfg += "# Below are samples that you can uncomment and edit.\n#\n" for ifc in node.netifs(): if hasattr(ifc, 'control') and ifc.control == True: continue cfg += "\n".join(map(cls.routestr, ifc.addrlist)) cfg += "\n" return cfg @staticmethod def routestr(x): if x.find(":") >= 0: net = IPv6Prefix(x) fam = "inet6" dst = "3ffe:4::/64" else: net = IPv4Prefix(x) fam = "inet" dst = "10.9.8.0/24" if net.maxaddr() == net.minaddr(): return "" else: if os.uname()[0] == "Linux": rtcmd = "#/sbin/ip route add %s via" % dst elif os.uname()[0] == "FreeBSD": rtcmd = "#/sbin/route add -%s %s" % (fam, dst) else: raise Exception, "unknown platform" return "%s %s" % (rtcmd, net.minaddr()) addservice(StaticRouteService) class SshService(UtilService): _name = "SSH" if os.uname()[0] == "FreeBSD": _configs = ("startsshd.sh", "sshd_config",) _dirs = () else: _configs = ("startsshd.sh", "/etc/ssh/sshd_config",) _dirs = ("/etc/ssh", "/var/run/sshd",) _startup = ("sh startsshd.sh",) _shutdown = ("killall sshd",) _validate = () @classmethod def generateconfig(cls, node, filename, services): ''' Use a startup script for launching sshd in order to wait for host key generation. ''' if os.uname()[0] == "FreeBSD": sshcfgdir = node.nodedir sshstatedir = node.nodedir sshlibdir = "/usr/libexec" else: sshcfgdir = cls._dirs[0] sshstatedir = cls._dirs[1] sshlibdir = "/usr/lib/openssh" if filename == "startsshd.sh": return """\ #!/bin/sh # auto-generated by SSH service (utility.py) ssh-keygen -q -t rsa -N "" -f %s/ssh_host_rsa_key chmod 655 %s # wait until RSA host key has been generated to launch sshd /usr/sbin/sshd -f %s/sshd_config """ % (sshcfgdir, sshstatedir, sshcfgdir) else: return """\ # auto-generated by SSH service (utility.py) Port 22 Protocol 2 HostKey %s/ssh_host_rsa_key UsePrivilegeSeparation yes PidFile %s/sshd.pid KeyRegenerationInterval 3600 ServerKeyBits 768 SyslogFacility AUTH LogLevel INFO LoginGraceTime 120 PermitRootLogin yes StrictModes yes RSAAuthentication yes PubkeyAuthentication yes IgnoreRhosts yes RhostsRSAAuthentication no HostbasedAuthentication no PermitEmptyPasswords no ChallengeResponseAuthentication no X11Forwarding yes X11DisplayOffset 10 PrintMotd no PrintLastLog yes TCPKeepAlive yes AcceptEnv LANG LC_* Subsystem sftp %s/sftp-server UsePAM yes UseDNS no """ % (sshcfgdir, sshstatedir, sshlibdir) addservice(SshService) class DhcpService(UtilService): _name = "DHCP" _configs = ("/etc/dhcp/dhcpd.conf",) _dirs = ("/etc/dhcp",) _startup = ("dhcpd",) _shutdown = ("killall dhcpd",) _validate = ("pidof dhcpd",) @classmethod def generateconfig(cls, node, filename, services): ''' Generate a dhcpd config file using the network address of each interface. ''' cfg = """\ # auto-generated by DHCP service (utility.py) # NOTE: move these option lines into the desired pool { } block(s) below #option domain-name "test.com"; #option domain-name-servers 10.0.0.1; #option routers 10.0.0.1; log-facility local6; default-lease-time 600; max-lease-time 7200; ddns-update-style none; """ for ifc in node.netifs(): if hasattr(ifc, 'control') and ifc.control == True: continue cfg += "\n".join(map(cls.subnetentry, ifc.addrlist)) cfg += "\n" return cfg @staticmethod def subnetentry(x): ''' Generate a subnet declaration block given an IPv4 prefix string for inclusion in the dhcpd3 config file. ''' if x.find(":") >= 0: return "" else: addr = x.split("/")[0] net = IPv4Prefix(x) # divide the address space in half rangelow = net.addr(net.numaddr() / 2) rangehigh = net.maxaddr() return """ subnet %s netmask %s { pool { range %s %s; default-lease-time 600; option routers %s; } } """ % (net.prefixstr(), net.netmaskstr(), rangelow, rangehigh, addr) addservice(DhcpService) class DhcpClientService(UtilService): ''' Use a DHCP client for all interfaces for addressing. ''' _name = "DHCPClient" _configs = ("startdhcpclient.sh",) _startup = ("sh startdhcpclient.sh",) _shutdown = ("killall dhclient",) _validate = ("pidof dhclient",) @classmethod def generateconfig(cls, node, filename, services): ''' Generate a script to invoke dhclient on all interfaces. ''' cfg = "#!/bin/sh\n" cfg += "# auto-generated by DHCPClient service (utility.py)\n" cfg += "# uncomment this mkdir line and symlink line to enable client-" cfg += "side DNS\n# resolution based on the DHCP server response.\n" cfg += "#mkdir -p /var/run/resolvconf/interface\n" for ifc in node.netifs(): if hasattr(ifc, 'control') and ifc.control == True: continue cfg += "#ln -s /var/run/resolvconf/interface/%s.dhclient" % ifc.name cfg += " /var/run/resolvconf/resolv.conf\n" cfg += "/sbin/dhclient -nw -pf /var/run/dhclient-%s.pid" % ifc.name cfg += " -lf /var/run/dhclient-%s.lease %s\n" % (ifc.name, ifc.name) return cfg addservice(DhcpClientService) class FtpService(UtilService): ''' Start a vsftpd server. ''' _name = "FTP" _configs = ("vsftpd.conf",) _dirs = ("/var/run/vsftpd/empty", "/var/ftp",) _startup = ("vsftpd ./vsftpd.conf",) _shutdown = ("killall vsftpd",) _validate = ("pidof vsftpd",) @classmethod def generateconfig(cls, node, filename, services): ''' Generate a vsftpd.conf configuration file. ''' return """\ # vsftpd.conf auto-generated by FTP service (utility.py) listen=YES anonymous_enable=YES local_enable=YES dirmessage_enable=YES use_localtime=YES xferlog_enable=YES connect_from_port_20=YES xferlog_file=/var/log/vsftpd.log ftpd_banner=Welcome to the CORE FTP service secure_chroot_dir=/var/run/vsftpd/empty anon_root=/var/ftp """ addservice(FtpService) class HttpService(UtilService): ''' Start an apache server. ''' _name = "HTTP" _configs = ("/etc/apache2/apache2.conf", "/etc/apache2/envvars", "/var/www/index.html",) _dirs = ("/etc/apache2", "/var/run/apache2", "/var/log/apache2", "/run/lock", "/var/lock/apache2", "/var/www", ) _startup = ("chown www-data /var/lock/apache2", "apache2ctl start",) _shutdown = ("apache2ctl stop",) _validate = ("pidof apache2",) APACHEVER22, APACHEVER24 = (22, 24) @classmethod def generateconfig(cls, node, filename, services): ''' Generate an apache2.conf configuration file. ''' if filename == cls._configs[0]: return cls.generateapache2conf(node, filename, services) elif filename == cls._configs[1]: return cls.generateenvvars(node, filename, services) elif filename == cls._configs[2]: return cls.generatehtml(node, filename, services) else: return "" @classmethod def detectversionfromcmd(cls): ''' Detect the apache2 version using the 'a2query' command. ''' try: status, result = cmdresult(['a2query', '-v']) except Exception: status = -1 if status == 0 and result[:3] == '2.4': return cls.APACHEVER24 return cls.APACHEVER22 @classmethod def generateapache2conf(cls, node, filename, services): lockstr = { cls.APACHEVER22: 'LockFile ${APACHE_LOCK_DIR}/accept.lock\n', cls.APACHEVER24: 'Mutex file:${APACHE_LOCK_DIR} default\n', } mpmstr = { cls.APACHEVER22: '', cls.APACHEVER24: 'LoadModule mpm_worker_module /usr/lib/apache2/modules/mod_mpm_worker.so\n', } permstr = { cls.APACHEVER22: ' Order allow,deny\n Deny from all\n Satisfy all\n', cls.APACHEVER24: ' Require all denied\n', } authstr = { cls.APACHEVER22: 'LoadModule authz_default_module /usr/lib/apache2/modules/mod_authz_default.so\n', cls.APACHEVER24: 'LoadModule authz_core_module /usr/lib/apache2/modules/mod_authz_core.so\n', } permstr2 = { cls.APACHEVER22: '\t\tOrder allow,deny\n\t\tallow from all\n', cls.APACHEVER24: '\t\tRequire all granted\n', } version = cls.detectversionfromcmd() cfg ="# apache2.conf generated by utility.py:HttpService\n" cfg += lockstr[version] cfg += """\ PidFile ${APACHE_PID_FILE} Timeout 300 KeepAlive On MaxKeepAliveRequests 100 KeepAliveTimeout 5 """ cfg += mpmstr[version] cfg += """\ StartServers 5 MinSpareServers 5 MaxSpareServers 10 MaxClients 150 MaxRequestsPerChild 0 StartServers 2 MinSpareThreads 25 MaxSpareThreads 75 ThreadLimit 64 ThreadsPerChild 25 MaxClients 150 MaxRequestsPerChild 0 StartServers 2 MinSpareThreads 25 MaxSpareThreads 75 ThreadLimit 64 ThreadsPerChild 25 MaxClients 150 MaxRequestsPerChild 0 User ${APACHE_RUN_USER} Group ${APACHE_RUN_GROUP} AccessFileName .htaccess """ cfg += permstr[version] cfg += """\ DefaultType None HostnameLookups Off ErrorLog ${APACHE_LOG_DIR}/error.log LogLevel warn #Include mods-enabled/*.load #Include mods-enabled/*.conf LoadModule alias_module /usr/lib/apache2/modules/mod_alias.so LoadModule auth_basic_module /usr/lib/apache2/modules/mod_auth_basic.so """ cfg += authstr[version] cfg += """\ LoadModule authz_host_module /usr/lib/apache2/modules/mod_authz_host.so LoadModule authz_user_module /usr/lib/apache2/modules/mod_authz_user.so LoadModule autoindex_module /usr/lib/apache2/modules/mod_autoindex.so LoadModule dir_module /usr/lib/apache2/modules/mod_dir.so LoadModule env_module /usr/lib/apache2/modules/mod_env.so NameVirtualHost *:80 Listen 80 Listen 443 Listen 443 LogFormat "%v:%p %h %l %u %t \\"%r\\" %>s %O \\"%{Referer}i\\" \\"%{User-Agent}i\\"" vhost_combined LogFormat "%h %l %u %t \\"%r\\" %>s %O \\"%{Referer}i\\" \\"%{User-Agent}i\\"" combined LogFormat "%h %l %u %t \\"%r\\" %>s %O" common LogFormat "%{Referer}i -> %U" referer LogFormat "%{User-agent}i" agent ServerTokens OS ServerSignature On TraceEnable Off ServerAdmin webmaster@localhost DocumentRoot /var/www Options FollowSymLinks AllowOverride None Options Indexes FollowSymLinks MultiViews AllowOverride None """ cfg += permstr2[version] cfg += """\ ErrorLog ${APACHE_LOG_DIR}/error.log LogLevel warn CustomLog ${APACHE_LOG_DIR}/access.log combined """ return cfg @classmethod def generateenvvars(cls, node, filename, services): return """\ # this file is used by apache2ctl - generated by utility.py:HttpService # these settings come from a default Ubuntu apache2 installation export APACHE_RUN_USER=www-data export APACHE_RUN_GROUP=www-data export APACHE_PID_FILE=/var/run/apache2.pid export APACHE_RUN_DIR=/var/run/apache2 export APACHE_LOCK_DIR=/var/lock/apache2 export APACHE_LOG_DIR=/var/log/apache2 export LANG=C export LANG """ @classmethod def generatehtml(cls, node, filename, services): body = """\

%s web server

This is the default web page for this server.

The web server software is running but no content has been added, yet.

""" % node.name for ifc in node.netifs(): if hasattr(ifc, 'control') and ifc.control == True: continue body += "
  • %s - %s
  • \n" % (ifc.name, ifc.addrlist) return "%s" % body addservice(HttpService) class PcapService(UtilService): ''' Pcap service for logging packets. ''' _name = "pcap" _configs = ("pcap.sh", ) _dirs = () _startindex = 1 _startup = ("sh pcap.sh start",) _shutdown = ("sh pcap.sh stop",) _validate = ("pidof tcpdump",) _meta = "logs network traffic to pcap packet capture files" @classmethod def generateconfig(cls, node, filename, services): ''' Generate a startpcap.sh traffic logging script. ''' cfg = """ #!/bin/sh # set tcpdump options here (see 'man tcpdump' for help) # (-s snap length, -C limit pcap file length, -n disable name resolution) DUMPOPTS="-s 12288 -C 10 -n" if [ "x$1" = "xstart" ]; then """ for ifc in node.netifs(): if hasattr(ifc, 'control') and ifc.control == True: cfg += '# ' redir = "< /dev/null" cfg += "tcpdump ${DUMPOPTS} -w %s.%s.pcap -i %s %s &\n" % \ (node.name, ifc.name, ifc.name, redir) cfg += """ elif [ "x$1" = "xstop" ]; then mkdir -p ${SESSION_DIR}/pcap mv *.pcap ${SESSION_DIR}/pcap fi; """ return cfg addservice(PcapService) class RadvdService(UtilService): _name = "radvd" _configs = ("/etc/radvd/radvd.conf",) _dirs = ("/etc/radvd",) _startup = ("radvd -C /etc/radvd/radvd.conf -m logfile -l /var/log/radvd.log",) _shutdown = ("pkill radvd",) _validate = ("pidof radvd",) @classmethod def generateconfig(cls, node, filename, services): ''' Generate a RADVD router advertisement daemon config file using the network address of each interface. ''' cfg = "# auto-generated by RADVD service (utility.py)\n" for ifc in node.netifs(): if hasattr(ifc, 'control') and ifc.control == True: continue prefixes = map(cls.subnetentry, ifc.addrlist) if len(prefixes) < 1: continue cfg += """\ interface %s { AdvSendAdvert on; MinRtrAdvInterval 3; MaxRtrAdvInterval 10; AdvDefaultPreference low; AdvHomeAgentFlag off; """ % ifc.name for prefix in prefixes: if prefix == "": continue cfg += """\ prefix %s { AdvOnLink on; AdvAutonomous on; AdvRouterAddr on; }; """ % prefix cfg += "};\n" return cfg @staticmethod def subnetentry(x): ''' Generate a subnet declaration block given an IPv6 prefix string for inclusion in the RADVD config file. ''' if x.find(":") >= 0: net = IPv6Prefix(x) return str(net) else: return "" addservice(RadvdService) class AtdService(UtilService): ''' Atd service for scheduling at jobs ''' _name = "atd" _configs = ("startatd.sh",) _dirs = ("/var/spool/cron/atjobs", "/var/spool/cron/atspool") _startup = ("sh startatd.sh", ) _shutdown = ("pkill atd", ) @classmethod def generateconfig(cls, node, filename, services): return """ #!/bin/sh echo 00001 > /var/spool/cron/atjobs/.SEQ chown -R daemon /var/spool/cron/* chmod -R 700 /var/spool/cron/* atd """ addservice(AtdService) class UserDefinedService(UtilService): ''' Dummy service allowing customization of anything. ''' _name = "UserDefined" _startindex = 50 _meta = "Customize this service to do anything upon startup." addservice(UserDefinedService) core-4.8/daemon/core/services/xorp.py0000664000175000017500000003467112534327775014652 00000000000000# # CORE # Copyright (c)2011-2012 the Boeing Company. # See the LICENSE file included in this distribution. # # author: Jeff Ahrenholz # ''' xorp.py: defines routing services provided by the XORP routing suite. ''' import os from core.service import CoreService, addservice from core.misc.ipaddr import IPv4Prefix from core.constants import * class XorpRtrmgr(CoreService): ''' XORP router manager service builds a config.boot file based on other enabled XORP services, and launches necessary daemons upon startup. ''' _name = "xorp_rtrmgr" _group = "XORP" _depends = () _dirs = ("/etc/xorp",) _configs = ("/etc/xorp/config.boot",) _startindex = 35 _startup = ("xorp_rtrmgr -d -b %s -l /var/log/%s.log -P /var/run/%s.pid" % (_configs[0], _name, _name),) _shutdown = ("killall xorp_rtrmgr", ) _validate = ("pidof xorp_rtrmgr", ) @classmethod def generateconfig(cls, node, filename, services): ''' Returns config.boot configuration file text. Other services that depend on this will have generatexorpconfig() hooks that are invoked here. Filename currently ignored. ''' cfg = "interfaces {\n" for ifc in node.netifs(): cfg += " interface %s {\n" % ifc.name cfg += "\tvif %s {\n" % ifc.name cfg += "".join(map(cls.addrstr, ifc.addrlist)) cfg += cls.lladdrstr(ifc) cfg += "\t}\n" cfg += " }\n" cfg += "}\n\n" for s in services: try: s._depends.index(cls._name) cfg += s.generatexorpconfig(node) except ValueError: pass return cfg @staticmethod def addrstr(x): ''' helper for mapping IP addresses to XORP config statements ''' try: (addr, plen) = x.split("/") except Exception: raise ValueError, "invalid address" cfg = "\t address %s {\n" % addr cfg += "\t\tprefix-length: %s\n" % plen cfg +="\t }\n" return cfg @staticmethod def lladdrstr(ifc): ''' helper for adding link-local address entries (required by OSPFv3) ''' cfg = "\t address %s {\n" % ifc.hwaddr.tolinklocal() cfg += "\t\tprefix-length: 64\n" cfg += "\t }\n" return cfg addservice(XorpRtrmgr) class XorpService(CoreService): ''' Parent class for XORP services. Defines properties and methods common to XORP's routing daemons. ''' _name = "XorpDaemon" _group = "XORP" _depends = ("xorp_rtrmgr", ) _dirs = () _configs = () _startindex = 40 _startup = () _shutdown = () _meta = "The config file for this service can be found in the xorp_rtrmgr service." @staticmethod def fea(forwarding): ''' Helper to add a forwarding engine entry to the config file. ''' cfg = "fea {\n" cfg += " %s {\n" % forwarding cfg += "\tdisable:false\n" cfg += " }\n" cfg += "}\n" return cfg @staticmethod def mfea(forwarding, ifcs): ''' Helper to add a multicast forwarding engine entry to the config file. ''' names = [] for ifc in ifcs: if hasattr(ifc, 'control') and ifc.control == True: continue names.append(ifc.name) names.append("register_vif") cfg = "plumbing {\n" cfg += " %s {\n" % forwarding for name in names: cfg += "\tinterface %s {\n" % name cfg += "\t vif %s {\n" % name cfg += "\t\tdisable: false\n" cfg += "\t }\n" cfg += "\t}\n" cfg += " }\n" cfg += "}\n" return cfg @staticmethod def policyexportconnected(): ''' Helper to add a policy statement for exporting connected routes. ''' cfg = "policy {\n" cfg += " policy-statement export-connected {\n" cfg += "\tterm 100 {\n" cfg += "\t from {\n" cfg += "\t\tprotocol: \"connected\"\n" cfg += "\t }\n" cfg += "\t}\n" cfg += " }\n" cfg += "}\n" return cfg @staticmethod def routerid(node): ''' Helper to return the first IPv4 address of a node as its router ID. ''' for ifc in node.netifs(): if hasattr(ifc, 'control') and ifc.control == True: continue for a in ifc.addrlist: if a.find(".") >= 0: return a.split('/')[0] #raise ValueError, "no IPv4 address found for router ID" return "0.0.0.0" @classmethod def generateconfig(cls, node, filename, services): return "" @classmethod def generatexorpconfig(cls, node): return "" class XorpOspfv2(XorpService): ''' The OSPFv2 service provides IPv4 routing for wired networks. It does not build its own configuration file but has hooks for adding to the unified XORP configuration file. ''' _name = "XORP_OSPFv2" @classmethod def generatexorpconfig(cls, node): cfg = cls.fea("unicast-forwarding4") rtrid = cls.routerid(node) cfg += "\nprotocols {\n" cfg += " ospf4 {\n" cfg += "\trouter-id: %s\n" % rtrid cfg += "\tarea 0.0.0.0 {\n" for ifc in node.netifs(): if hasattr(ifc, 'control') and ifc.control == True: continue cfg += "\t interface %s {\n" % ifc.name cfg += "\t\tvif %s {\n" % ifc.name for a in ifc.addrlist: if a.find(".") < 0: continue addr = a.split("/")[0] cfg += "\t\t address %s {\n" % addr cfg += "\t\t }\n" cfg += "\t\t}\n" cfg += "\t }\n" cfg += "\t}\n" cfg += " }\n" cfg += "}\n" return cfg addservice(XorpOspfv2) class XorpOspfv3(XorpService): ''' The OSPFv3 service provides IPv6 routing. It does not build its own configuration file but has hooks for adding to the unified XORP configuration file. ''' _name = "XORP_OSPFv3" @classmethod def generatexorpconfig(cls, node): cfg = cls.fea("unicast-forwarding6") rtrid = cls.routerid(node) cfg += "\nprotocols {\n" cfg += " ospf6 0 { /* Instance ID 0 */\n" cfg += "\trouter-id: %s\n" % rtrid cfg += "\tarea 0.0.0.0 {\n" for ifc in node.netifs(): if hasattr(ifc, 'control') and ifc.control == True: continue cfg += "\t interface %s {\n" % ifc.name cfg += "\t\tvif %s {\n" % ifc.name cfg += "\t\t}\n" cfg += "\t }\n" cfg += "\t}\n" cfg += " }\n" cfg += "}\n" return cfg addservice(XorpOspfv3) class XorpBgp(XorpService): ''' IPv4 inter-domain routing. AS numbers and peers must be customized. ''' _name = "XORP_BGP" _custom_needed = True @classmethod def generatexorpconfig(cls, node): cfg = "/* This is a sample config that should be customized with\n" cfg += " appropriate AS numbers and peers */\n" cfg += cls.fea("unicast-forwarding4") cfg += cls.policyexportconnected() rtrid = cls.routerid(node) cfg += "\nprotocols {\n" cfg += " bgp {\n" cfg += "\tbgp-id: %s\n" % rtrid cfg += "\tlocal-as: 65001 /* change this */\n" cfg += "\texport: \"export-connected\"\n" cfg += "\tpeer 10.0.1.1 { /* change this */\n" cfg += "\t local-ip: 10.0.1.1\n" cfg += "\t as: 65002\n" cfg += "\t next-hop: 10.0.0.2\n" cfg += "\t}\n" cfg += " }\n" cfg += "}\n" return cfg addservice(XorpBgp) class XorpRip(XorpService): ''' RIP IPv4 unicast routing. ''' _name = "XORP_RIP" @classmethod def generatexorpconfig(cls, node): cfg = cls.fea("unicast-forwarding4") cfg += cls.policyexportconnected() cfg += "\nprotocols {\n" cfg += " rip {\n" cfg += "\texport: \"export-connected\"\n" for ifc in node.netifs(): if hasattr(ifc, 'control') and ifc.control == True: continue cfg += "\tinterface %s {\n" % ifc.name cfg += "\t vif %s {\n" % ifc.name for a in ifc.addrlist: if a.find(".") < 0: continue addr = a.split("/")[0] cfg += "\t\taddress %s {\n" % addr cfg += "\t\t disable: false\n" cfg += "\t\t}\n" cfg += "\t }\n" cfg += "\t}\n" cfg += " }\n" cfg += "}\n" return cfg addservice(XorpRip) class XorpRipng(XorpService): ''' RIP NG IPv6 unicast routing. ''' _name = "XORP_RIPNG" @classmethod def generatexorpconfig(cls, node): cfg = cls.fea("unicast-forwarding6") cfg += cls.policyexportconnected() cfg += "\nprotocols {\n" cfg += " ripng {\n" cfg += "\texport: \"export-connected\"\n" for ifc in node.netifs(): if hasattr(ifc, 'control') and ifc.control == True: continue cfg += "\tinterface %s {\n" % ifc.name cfg += "\t vif %s {\n" % ifc.name # for a in ifc.addrlist: # if a.find(":") < 0: # continue # addr = a.split("/")[0] # cfg += "\t\taddress %s {\n" % addr # cfg += "\t\t disable: false\n" # cfg += "\t\t}\n" cfg += "\t\taddress %s {\n" % ifc.hwaddr.tolinklocal() cfg += "\t\t disable: false\n" cfg += "\t\t}\n" cfg += "\t }\n" cfg += "\t}\n" cfg += " }\n" cfg += "}\n" return cfg addservice(XorpRipng) class XorpPimSm4(XorpService): ''' PIM Sparse Mode IPv4 multicast routing. ''' _name = "XORP_PIMSM4" @classmethod def generatexorpconfig(cls, node): cfg = cls.mfea("mfea4", node.netifs()) cfg += "\nprotocols {\n" cfg += " igmp {\n" names = [] for ifc in node.netifs(): if hasattr(ifc, 'control') and ifc.control == True: continue names.append(ifc.name) cfg += "\tinterface %s {\n" % ifc.name cfg += "\t vif %s {\n" % ifc.name cfg += "\t\tdisable: false\n" cfg += "\t }\n" cfg += "\t}\n" cfg += " }\n" cfg += "}\n" cfg += "\nprotocols {\n" cfg += " pimsm4 {\n" names.append("register_vif") for name in names: cfg += "\tinterface %s {\n" % name cfg += "\t vif %s {\n" % name cfg += "\t\tdr-priority: 1\n" cfg += "\t }\n" cfg += "\t}\n" cfg += "\tbootstrap {\n" cfg += "\t cand-bsr {\n" cfg += "\t\tscope-zone 224.0.0.0/4 {\n" cfg += "\t\t cand-bsr-by-vif-name: \"%s\"\n" % names[0] cfg += "\t\t}\n" cfg += "\t }\n" cfg += "\t cand-rp {\n" cfg += "\t\tgroup-prefix 224.0.0.0/4 {\n" cfg += "\t\t cand-rp-by-vif-name: \"%s\"\n" % names[0] cfg += "\t\t}\n" cfg += "\t }\n" cfg += "\t}\n" cfg += " }\n" cfg += "}\n" cfg += "\nprotocols {\n" cfg += " fib2mrib {\n" cfg += "\tdisable: false\n" cfg += " }\n" cfg += "}\n" return cfg addservice(XorpPimSm4) class XorpPimSm6(XorpService): ''' PIM Sparse Mode IPv6 multicast routing. ''' _name = "XORP_PIMSM6" @classmethod def generatexorpconfig(cls, node): cfg = cls.mfea("mfea6", node.netifs()) cfg += "\nprotocols {\n" cfg += " mld {\n" names = [] for ifc in node.netifs(): if hasattr(ifc, 'control') and ifc.control == True: continue names.append(ifc.name) cfg += "\tinterface %s {\n" % ifc.name cfg += "\t vif %s {\n" % ifc.name cfg += "\t\tdisable: false\n" cfg += "\t }\n" cfg += "\t}\n" cfg += " }\n" cfg += "}\n" cfg += "\nprotocols {\n" cfg += " pimsm6 {\n" names.append("register_vif") for name in names: cfg += "\tinterface %s {\n" % name cfg += "\t vif %s {\n" % name cfg += "\t\tdr-priority: 1\n" cfg += "\t }\n" cfg += "\t}\n" cfg += "\tbootstrap {\n" cfg += "\t cand-bsr {\n" cfg += "\t\tscope-zone ff00::/8 {\n" cfg += "\t\t cand-bsr-by-vif-name: \"%s\"\n" % names[0] cfg += "\t\t}\n" cfg += "\t }\n" cfg += "\t cand-rp {\n" cfg += "\t\tgroup-prefix ff00::/8 {\n" cfg += "\t\t cand-rp-by-vif-name: \"%s\"\n" % names[0] cfg += "\t\t}\n" cfg += "\t }\n" cfg += "\t}\n" cfg += " }\n" cfg += "}\n" cfg += "\nprotocols {\n" cfg += " fib2mrib {\n" cfg += "\tdisable: false\n" cfg += " }\n" cfg += "}\n" return cfg addservice(XorpPimSm6) class XorpOlsr(XorpService): ''' OLSR IPv4 unicast MANET routing. ''' _name = "XORP_OLSR" @classmethod def generatexorpconfig(cls, node): cfg = cls.fea("unicast-forwarding4") rtrid = cls.routerid(node) cfg += "\nprotocols {\n" cfg += " olsr4 {\n" cfg += "\tmain-address: %s\n" % rtrid for ifc in node.netifs(): if hasattr(ifc, 'control') and ifc.control == True: continue cfg += "\tinterface %s {\n" % ifc.name cfg += "\t vif %s {\n" % ifc.name for a in ifc.addrlist: if a.find(".") < 0: continue addr = a.split("/")[0] cfg += "\t\taddress %s {\n" % addr cfg += "\t\t}\n" cfg += "\t }\n" cfg += "\t}\n" cfg += " }\n" cfg += "}\n" return cfg addservice(XorpOlsr) core-4.8/daemon/core/session.py0000664000175000017500000014006412534327775013514 00000000000000# # CORE # Copyright (c)2010-2013 the Boeing Company. # See the LICENSE file included in this distribution. # # authors: Tom Goff # Jeff Ahrenholz # ''' session.py: defines the Session class used by the core-daemon daemon program that manages a CORE session. ''' import os, sys, tempfile, shutil, shlex, atexit, gc, pwd import threading, time, random from core.api import coreapi if os.uname()[0] == "Linux": from core.netns import nodes from core.netns.vnet import GreTapBridge elif os.uname()[0] == "FreeBSD": from core.bsd import nodes from core.emane import emane from core.misc.utils import check_call, mutedetach, readfileintodict, \ filemunge, filedemunge from core.conf import ConfigurableManager, Configurable from core.location import CoreLocation from core.service import CoreServices from core.broker import CoreBroker from core.mobility import MobilityManager from core.sdt import Sdt from core.misc.ipaddr import MacAddr from core.misc.event import EventLoop from core.constants import * from core.misc.xmlsession import savesessionxml from core.xen import xenconfig class Session(object): # sessions that get automatically shutdown when the process # terminates normally __sessions = set() ''' CORE session manager. ''' def __init__(self, sessionid = None, cfg = {}, server = None, persistent = False, mkdir = True): if sessionid is None: # try to keep this short since it's used to construct # network interface names pid = os.getpid() sessionid = ((pid >> 16) ^ (pid & ((1 << 16) - 1))) sessionid ^= ((id(self) >> 16) ^ (id(self) & ((1 << 16) - 1))) sessionid &= 0xffff self.sessionid = sessionid self.sessiondir = os.path.join(tempfile.gettempdir(), "pycore.%s" % self.sessionid) if mkdir: os.mkdir(self.sessiondir) self.name = None self.filename = None self.thumbnail = None self.user = None self.node_count = None self._time = time.time() self.evq = EventLoop() # dict of objects: all nodes and nets self._objs = {} self._objslock = threading.Lock() # dict of configurable objects self._confobjs = {} self._confobjslock = threading.Lock() self._handlers = set() self._handlerslock = threading.Lock() self._state = None self._hooks = {} self._state_hooks = {} # dict of configuration items from /etc/core/core.conf config file self.cfg = cfg self.add_state_hook(coreapi.CORE_EVENT_RUNTIME_STATE, self.runtime_state_hook) self.setstate(state=coreapi.CORE_EVENT_DEFINITION_STATE, info=False, sendevent=False) self.server = server if not persistent: self.addsession(self) self.master = False self.broker = CoreBroker(session=self, verbose=True) self.location = CoreLocation(self) self.mobility = MobilityManager(self) self.services = CoreServices(self) self.emane = emane.Emane(self) self.xen = xenconfig.XenConfigManager(self) self.sdt = Sdt(self) # future parameters set by the GUI may go here self.options = SessionConfig(self) self.metadata = SessionMetaData(self) @classmethod def addsession(cls, session): cls.__sessions.add(session) @classmethod def delsession(cls, session): try: cls.__sessions.remove(session) except KeyError: pass @classmethod def atexit(cls): while cls.__sessions: s = cls.__sessions.pop() print >> sys.stderr, "WARNING: automatically shutting down " \ "non-persistent session %s" % s.sessionid s.shutdown() def __del__(self): # note: there is no guarantee this will ever run self.shutdown() def shutdown(self): ''' Shut down all emulation objects and remove the session directory. ''' if hasattr(self, 'emane'): self.emane.shutdown() if hasattr(self, 'broker'): self.broker.shutdown() if hasattr(self, 'sdt'): self.sdt.shutdown() self.delobjs() preserve = False if hasattr(self.options, 'preservedir'): if self.options.preservedir == '1': preserve = True if not preserve: shutil.rmtree(self.sessiondir, ignore_errors = True) if self.server: self.server.delsession(self) self.delsession(self) def isconnected(self): ''' Returns true if this session has a request handler. ''' with self._handlerslock: if len(self._handlers) == 0: return False else: return True def connect(self, handler): ''' Set the request handler for this session, making it connected. ''' # the master flag will only be set after a GUI has connected with the # handler, e.g. not during normal startup if handler.master is True: self.master = True with self._handlerslock: self._handlers.add(handler) def disconnect(self, handler): ''' Disconnect a request handler from this session. Shutdown this session if there is no running emulation. ''' with self._handlerslock: try: self._handlers.remove(handler) except KeyError: raise ValueError, \ "Handler %s not associated with this session" % handler num_handlers = len(self._handlers) if num_handlers == 0: # shut down this session unless we are instantiating, running, # or collecting final data if self.getstate() < coreapi.CORE_EVENT_INSTANTIATION_STATE or \ self.getstate() > coreapi.CORE_EVENT_DATACOLLECT_STATE: self.shutdown() def broadcast(self, src, msg): ''' Send Node and Link CORE API messages to all handlers connected to this session. ''' self._handlerslock.acquire() for handler in self._handlers: if handler == src: continue if isinstance(msg, coreapi.CoreNodeMessage) or \ isinstance(msg, coreapi.CoreLinkMessage): try: handler.sendall(msg.rawmsg) except Exception, e: self.warn("sendall() error: %s" % e) self._handlerslock.release() def broadcastraw(self, src, data): ''' Broadcast raw data to all handlers except src. ''' self._handlerslock.acquire() for handler in self._handlers: if handler == src: continue try: handler.sendall(data) except Exception, e: self.warn("sendall() error: %s" % e) self._handlerslock.release() def gethandler(self): ''' Get one of the connected handlers, preferrably the master. ''' with self._handlerslock: if len(self._handlers) == 0: return None for handler in self._handlers: if handler.master: return handler for handler in self._handlers: return handler def setstate(self, state, info = False, sendevent = False, returnevent = False): ''' Set the session state. When info is true, log the state change event using the session handler's info method. When sendevent is true, generate a CORE API Event Message and send to the connected entity. ''' if state == self._state: return [] self._time = time.time() self._state = state self.run_state_hooks(state) replies = [] if self.isconnected() and info: statename = coreapi.state_name(state) with self._handlerslock: for handler in self._handlers: handler.info("SESSION %s STATE %d: %s at %s" % \ (self.sessionid, state, statename, time.ctime())) self.writestate(state) self.runhook(state) if sendevent: tlvdata = "" tlvdata += coreapi.CoreEventTlv.pack(coreapi.CORE_TLV_EVENT_TYPE, state) msg = coreapi.CoreEventMessage.pack(0, tlvdata) # send Event Message to connected handlers (e.g. GUI) if self.isconnected(): try: if returnevent: replies.append(msg) else: self.broadcastraw(None, msg) except Exception, e: self.warn("Error sending Event Message: %s" % e) # also inform slave servers tmp = self.broker.handlerawmsg(msg) return replies def getstate(self): ''' Retrieve the current state of the session. ''' return self._state def writestate(self, state): ''' Write the current state to a state file in the session dir. ''' try: f = open(os.path.join(self.sessiondir, "state"), "w") f.write("%d %s\n" % (state, coreapi.state_name(state))) f.close() except Exception, e: self.warn("Error writing state file: %s" % e) def runhook(self, state, hooks=None): ''' Run hook scripts upon changing states. If hooks is not specified, run all hooks in the given state. ''' if state not in self._hooks: return if hooks is None: hooks = self._hooks[state] for (filename, data) in hooks: try: f = open(os.path.join(self.sessiondir, filename), "w") f.write(data) f.close() except Exception, e: self.warn("Error writing hook '%s': %s" % (filename, e)) self.info("Running hook %s for state %s" % (filename, state)) try: check_call(["/bin/sh", filename], cwd=self.sessiondir, env=self.getenviron()) except Exception, e: self.warn("Error running hook '%s' for state %s: %s" % (filename, state, e)) def sethook(self, type, filename, srcname, data): ''' Store a hook from a received File Message. ''' if srcname is not None: raise NotImplementedError (hookid, state) = type.split(':')[:2] if not state.isdigit(): self.warn("Error setting hook having state '%s'" % state) return state = int(state) hook = (filename, data) if state not in self._hooks: self._hooks[state] = [hook,] else: self._hooks[state] += hook # immediately run a hook if it is in the current state # (this allows hooks in the definition and configuration states) if self.getstate() == state: self.runhook(state, hooks = [hook,]) def delhooks(self): ''' Clear the hook scripts dict. ''' self._hooks = {} def run_state_hooks(self, state): if state not in self._state_hooks: return for hook in self._state_hooks[state]: try: hook(state) except Exception, e: self.warn("ERROR: exception occured when running %s state " "hook: %s: %s" % (coreapi.state_name(state), hook, e)) def add_state_hook(self, state, hook): try: hooks = self._state_hooks[state] assert hook not in hooks hooks.append(hook) except KeyError: self._state_hooks[state] = [hook] if self._state == state: hook(state) def del_state_hook(self, state, hook): try: hooks = self._state_hooks[state] self._state_hooks[state] = filter(lambda x: x != hook, hooks) except KeyError: pass def runtime_state_hook(self, state): if state == coreapi.CORE_EVENT_RUNTIME_STATE: self.emane.poststartup() xmlfilever = self.cfg['xmlfilever'] if xmlfilever in ('1.0',): xmlfilename = os.path.join(self.sessiondir, 'session-deployed.xml') savesessionxml(self, xmlfilename, xmlfilever) def getenviron(self, state=True): ''' Get an environment suitable for a subprocess.Popen call. This is the current process environment with some session-specific variables. ''' env = os.environ.copy() env['SESSION'] = "%s" % self.sessionid env['SESSION_SHORT'] = "%s" % self.shortsessionid() env['SESSION_DIR'] = "%s" % self.sessiondir env['SESSION_NAME'] = "%s" % self.name env['SESSION_FILENAME'] = "%s" % self.filename env['SESSION_USER'] = "%s" % self.user env['SESSION_NODE_COUNT'] = "%s" % self.node_count if state: env['SESSION_STATE'] = "%s" % self.getstate() try: readfileintodict(os.path.join(CORE_CONF_DIR, "environment"), env) except IOError: pass if self.user: try: readfileintodict(os.path.join('/home', self.user, ".core", "environment"), env) except IOError: pass return env def setthumbnail(self, thumbfile): ''' Set the thumbnail filename. Move files from /tmp to session dir. ''' if not os.path.exists(thumbfile): self.thumbnail = None return dstfile = os.path.join(self.sessiondir, os.path.basename(thumbfile)) shutil.move(thumbfile, dstfile) #print "thumbnail: %s -> %s" % (thumbfile, dstfile) self.thumbnail = dstfile def setuser(self, user): ''' Set the username for this session. Update the permissions of the session dir to allow the user write access. ''' if user is not None: try: uid = pwd.getpwnam(user).pw_uid gid = os.stat(self.sessiondir).st_gid os.chown(self.sessiondir, uid, gid) except Exception, e: self.warn("Failed to set permission on %s: %s" % (self.sessiondir, e)) self.user = user def objs(self): ''' Return iterator over the emulation object dictionary. ''' return self._objs.itervalues() def getobjid(self): ''' Return a unique, random object id. ''' self._objslock.acquire() while True: id = random.randint(1, 0xFFFF) if id not in self._objs: break self._objslock.release() return id def addobj(self, cls, *clsargs, **clskwds): ''' Add an emulation object. ''' obj = cls(self, *clsargs, **clskwds) self._objslock.acquire() if obj.objid in self._objs: self._objslock.release() obj.shutdown() raise KeyError, "non-unique object id %s for %s" % (obj.objid, obj) self._objs[obj.objid] = obj self._objslock.release() return obj def obj(self, objid): ''' Get an emulation object. ''' if objid not in self._objs: raise KeyError, "unknown object id %s" % (objid) return self._objs[objid] def objbyname(self, name): ''' Get an emulation object using its name attribute. ''' with self._objslock: for obj in self.objs(): if hasattr(obj, "name") and obj.name == name: return obj raise KeyError, "unknown object with name %s" % (name) def delobj(self, objid): ''' Remove an emulation object. ''' self._objslock.acquire() try: o = self._objs.pop(objid) except KeyError: o = None self._objslock.release() if o: o.shutdown() del o gc.collect() # print "gc count:", gc.get_count() # for o in gc.get_objects(): # if isinstance(o, PyCoreObj): # print "XXX XXX XXX PyCoreObj:", o # for r in gc.get_referrers(o): # print "XXX XXX XXX referrer:", gc.get_referrers(o) def delobjs(self): ''' Clear the _objs dictionary, and call each obj.shutdown() routine. ''' self._objslock.acquire() while self._objs: k, o = self._objs.popitem() o.shutdown() self._objslock.release() def writeobjs(self): ''' Write objects to a 'nodes' file in the session dir. The 'nodes' file lists: number, name, api-type, class-type ''' try: f = open(os.path.join(self.sessiondir, "nodes"), "w") with self._objslock: for objid in sorted(self._objs.keys()): o = self._objs[objid] f.write("%s %s %s %s\n" % (objid, o.name, o.apitype, type(o))) f.close() except Exception, e: self.warn("Error writing nodes file: %s" % e) def addconfobj(self, objname, type, callback): ''' Objects can register configuration objects that are included in the Register Message and may be configured via the Configure Message. The callback is invoked when receiving a Configure Message. ''' if type not in coreapi.reg_tlvs: raise Exception, "invalid configuration object type" self._confobjslock.acquire() self._confobjs[objname] = (type, callback) self._confobjslock.release() def confobj(self, objname, session, msg): ''' Invoke the callback for an object upon receipt of a Configure Message for that object. A no-op if the object doesn't exist. ''' replies = [] self._confobjslock.acquire() if objname == "all": for objname in self._confobjs: (type, callback) = self._confobjs[objname] reply = callback(session, msg) if reply is not None: replies.append(reply) self._confobjslock.release() return replies if objname in self._confobjs: (type, callback) = self._confobjs[objname] self._confobjslock.release() reply = callback(session, msg) if reply is not None: replies.append(reply) return replies else: self.info("session object doesn't own model '%s', ignoring" % \ objname) self._confobjslock.release() return replies def confobjs_to_tlvs(self): ''' Turn the configuration objects into a list of Register Message TLVs. ''' tlvdata = "" self._confobjslock.acquire() for objname in self._confobjs: (type, callback) = self._confobjs[objname] # type must be in coreapi.reg_tlvs tlvdata += coreapi.CoreRegTlv.pack(type, objname) self._confobjslock.release() return tlvdata def info(self, msg): ''' Utility method for writing output to stdout. ''' print msg sys.stdout.flush() def warn(self, msg): ''' Utility method for writing output to stderr. ''' print >> sys.stderr, msg sys.stderr.flush() def dumpsession(self): ''' Debug print this session. ''' self.info("session id=%s name=%s state=%s connected=%s" % \ (self.sessionid, self.name, self._state, self.isconnected())) num = len(self._objs) self.info(" file=%s thumb=%s nc=%s/%s" % \ (self.filename, self.thumbnail, self.node_count, num)) def exception(self, level, source, objid, text): ''' Generate an Exception Message ''' vals = (objid, str(self.sessionid), level, source, time.ctime(), text) types = ("NODE", "SESSION", "LEVEL", "SOURCE", "DATE", "TEXT") tlvdata = "" for (t,v) in zip(types, vals): if v is not None: tlvdata += coreapi.CoreExceptionTlv.pack( eval("coreapi.CORE_TLV_EXCP_%s" % t), v) msg = coreapi.CoreExceptionMessage.pack(0, tlvdata) self.warn("exception: %s (%s) %s" % (source, objid, text)) # send Exception Message to connected handlers (e.g. GUI) self.broadcastraw(None, msg) def getcfgitem(self, cfgname): ''' Return an entry from the configuration dictionary that comes from command-line arguments and/or the core.conf config file. ''' if cfgname not in self.cfg: return None else: return self.cfg[cfgname] def getcfgitembool(self, cfgname, defaultifnone = None): ''' Return a boolean entry from the configuration dictionary, may return None if undefined. ''' item = self.getcfgitem(cfgname) if item is None: return defaultifnone return bool(item.lower() == "true") def getcfgitemint(self, cfgname, defaultifnone = None): ''' Return an integer entry from the configuration dictionary, may return None if undefined. ''' item = self.getcfgitem(cfgname) if item is None: return defaultifnone return int(item) def instantiate(self, handler=None): ''' We have entered the instantiation state, invoke startup methods of various managers and boot the nodes. Validate nodes and check for transition to the runtime state. ''' self.writeobjs() # controlnet may be needed by some EMANE models self.addremovectrlif(node=None, remove=False) if self.emane.startup() == self.emane.NOT_READY: return # instantiate() will be invoked again upon Emane.configure() self.broker.startup() self.mobility.startup() # boot the services on each node self.bootnodes(handler) # allow time for processes to start time.sleep(0.125) self.validatenodes() # assume either all nodes have booted already, or there are some # nodes on slave servers that will be booted and those servers will # send a node status response message self.checkruntime() def getnodecount(self): ''' Returns the number of CoreNodes and CoreNets, except for those that are not considered in the GUI's node count. ''' with self._objslock: count = len(filter(lambda(x): \ not isinstance(x, (nodes.PtpNet, nodes.CtrlNet)), self.objs())) # on Linux, GreTapBridges are auto-created, not part of # GUI's node count if 'GreTapBridge' in globals(): count -= len(filter(lambda(x): \ isinstance(x, GreTapBridge) and not \ isinstance(x, nodes.TunnelNode), self.objs())) return count def checkruntime(self): ''' Check if we have entered the runtime state, that all nodes have been started and the emulation is running. Start the event loop once we have entered runtime (time=0). ''' # this is called from instantiate() after receiving an event message # for the instantiation state, and from the broker when distributed # nodes have been started if self.node_count is None: return if self.getstate() == coreapi.CORE_EVENT_RUNTIME_STATE: return session_node_count = int(self.node_count) nc = self.getnodecount() # count booted nodes not emulated on this server # TODO: let slave server determine RUNTIME and wait for Event Message # broker.getbootocunt() counts all CoreNodes from status reponse # messages, plus any remote WLANs; remote EMANE, hub, switch, etc. # are already counted in self._objs nc += self.broker.getbootcount() self.info("Checking for runtime with %d of %d session nodes" % \ (nc, session_node_count)) if nc < session_node_count: return # do not have information on all nodes yet # information on all nodes has been received and they have been started # enter the runtime state # TODO: more sophisticated checks to verify that all nodes and networks # are running state = coreapi.CORE_EVENT_RUNTIME_STATE self.evq.run() self.setstate(state, info=True, sendevent=True) def datacollect(self): ''' Tear down a running session. Stop the event loop and any running nodes, and perform clean-up. ''' self.evq.stop() with self._objslock: for obj in self.objs(): if isinstance(obj, nodes.PyCoreNode): self.services.stopnodeservices(obj) self.emane.shutdown() self.updatectrlifhosts(remove=True) # Remove all four possible control networks. Does nothing if ctrlnet is not installed. self.addremovectrlif(node=None, remove=True) self.addremovectrlif(node=None, netidx=1, remove=True) self.addremovectrlif(node=None, netidx=2, remove=True) self.addremovectrlif(node=None, netidx=3, remove=True) # self.checkshutdown() is currently invoked from node delete handler def checkshutdown(self): ''' Check if we have entered the shutdown state, when no running nodes and links remain. ''' nc = self.getnodecount() # TODO: this doesn't consider slave server node counts # wait for slave servers to enter SHUTDOWN state, then master session # can enter SHUTDOWN replies = () if self.getcfgitembool('verbose', False): self.info("Session %d shutdown: %d nodes remaining" % \ (self.sessionid, nc)) if nc == 0: replies = self.setstate(state=coreapi.CORE_EVENT_SHUTDOWN_STATE, info=True, sendevent=True, returnevent=True) self.sdt.shutdown() return replies def setmaster(self, handler): ''' Look for the specified handler and set our master flag appropriately. Returns True if we are connected to the given handler. ''' with self._handlerslock: for h in self._handlers: if h != handler: continue self.master = h.master return True return False def shortsessionid(self): ''' Return a shorter version of the session ID, appropriate for interface names, where length may be limited. ''' ssid = (self.sessionid >> 8) ^ (self.sessionid & ((1 << 8) - 1)) return "%x" % ssid def sendnodeemuid(self, handler, nodenum): ''' Send back node messages to the GUI for node messages that had the status request flag. ''' if handler is None: return if nodenum in handler.nodestatusreq: tlvdata = "" tlvdata += coreapi.CoreNodeTlv.pack(coreapi.CORE_TLV_NODE_NUMBER, nodenum) tlvdata += coreapi.CoreNodeTlv.pack(coreapi.CORE_TLV_NODE_EMUID, nodenum) reply = coreapi.CoreNodeMessage.pack(coreapi.CORE_API_ADD_FLAG \ | coreapi.CORE_API_LOC_FLAG, tlvdata) try: handler.request.sendall(reply) except Exception, e: self.warn("sendall() for node: %d error: %s" % (nodenum, e)) del handler.nodestatusreq[nodenum] def bootnodes(self, handler): ''' Invoke the boot() procedure for all nodes and send back node messages to the GUI for node messages that had the status request flag. ''' with self._objslock: for n in self.objs(): if isinstance(n, nodes.PyCoreNode) and \ not isinstance(n, nodes.RJ45Node): # add a control interface if configured self.addremovectrlif(node=n, remove=False) n.boot() self.sendnodeemuid(handler, n.objid) self.updatectrlifhosts() def validatenodes(self): with self._objslock: for n in self.objs(): # TODO: this can be extended to validate everything # such as vnoded process, bridges, etc. if not isinstance(n, nodes.PyCoreNode): continue if isinstance(n, nodes.RJ45Node): continue n.validate() def getctrlnetprefixes(self): p = getattr(self.options, 'controlnet', self.cfg.get('controlnet')) p0 = getattr(self.options, 'controlnet0', self.cfg.get('controlnet0')) p1 = getattr(self.options, 'controlnet1', self.cfg.get('controlnet1')) p2 = getattr(self.options, 'controlnet2', self.cfg.get('controlnet2')) p3 = getattr(self.options, 'controlnet3', self.cfg.get('controlnet3')) if not p0 and p: p0 = p return [p0,p1,p2,p3] def getctrlnetserverintf(self): d0 = self.cfg.get('controlnetif0') if d0: self.warn("controlnet0 cannot be assigned with a host interface") d1 = self.cfg.get('controlnetif1') d2 = self.cfg.get('controlnetif2') d3 = self.cfg.get('controlnetif3') return [None,d1,d2,d3] def getctrlnetidx(self, dev): if dev[0:4] == 'ctrl' and int(dev[4]) in [0,1,2,3]: idx = int(dev[4]) if idx == 0: return idx if idx < 4 and self.getctrlnetprefixes()[idx] is not None: return idx return -1 def getctrlnetobj(self, netidx): oid = "ctrl%dnet" % netidx return self.obj(oid) def addremovectrlnet(self, netidx, remove=False, conf_reqd=True): ''' Create a control network bridge as necessary. When the remove flag is True, remove the bridge that connects control interfaces. The conf_reqd flag, when False, causes a control network bridge to be added even if one has not been configured. ''' prefixspeclist = self.getctrlnetprefixes() prefixspec = prefixspeclist[netidx] if not prefixspec: if conf_reqd: return None # no controlnet needed else: prefixspec = nodes.CtrlNet.DEFAULT_PREFIX_LIST[netidx] serverintf = self.getctrlnetserverintf()[netidx] # return any existing controlnet bridge try: ctrlnet = self.getctrlnetobj(netidx) if remove: self.delobj(ctrlnet.objid) return None return ctrlnet except KeyError: if remove: return None # build a new controlnet bridge oid = "ctrl%dnet" % netidx # use the updown script for control net 0 only. updown_script = None if netidx == 0: try: if self.cfg['controlnet_updown_script']: updown_script = self.cfg['controlnet_updown_script'] except KeyError: pass # Check if session option set, overwrite if so if hasattr(self.options, 'controlnet_updown_script'): new_uds = self.options.controlnet_updown_script if new_uds: updown_script = new_uds prefixes = prefixspec.split() if len(prefixes) > 1: # A list of per-host prefixes is provided assign_address = True if self.master: try: # split first (master) entry into server and prefix prefix = prefixes[0].split(':', 1)[1] except IndexError: # no server name. possibly only one server prefix = prefixes[0] else: # slave servers have their name and localhost in the serverlist servers = self.broker.getserverlist() servers.remove('localhost') prefix = None for server_prefix in prefixes: try: # split each entry into server and prefix server, p = server_prefix.split(':') except ValueError: server = "" p = None if server == servers[0]: # the server name in the list matches this server prefix = p break if not prefix: msg = "Control network prefix not found for server '%s'" % \ servers[0] self.exception(coreapi.CORE_EXCP_LEVEL_ERROR, "Session.addremovectrlnet()", None, msg) assign_address = False try: prefix = prefixes[0].split(':', 1)[1] except IndexError: prefix = prefixes[0] else: # len(prefixes) == 1 # TODO: can we get the server name from the servers.conf or from the node assignments? # with one prefix, only master gets a ctrlnet address assign_address = self.master prefix = prefixes[0] ctrlnet = self.addobj(cls=nodes.CtrlNet, objid=oid, prefix=prefix, assign_address=assign_address, updown_script=updown_script, serverintf=serverintf) # tunnels between controlnets will be built with Broker.addnettunnels() self.broker.addnet(oid) for server in self.broker.getserverlist(): self.broker.addnodemap(server, oid) return ctrlnet def addremovectrlif(self, node, netidx=0, remove=False, conf_reqd=True): ''' Add a control interface to a node when a 'controlnet' prefix is listed in the config file or session options. Uses addremovectrlnet() to build or remove the control bridge. If conf_reqd is False, the control network may be built even when the user has not configured one (e.g. for EMANE.) ''' ctrlnet = self.addremovectrlnet(netidx, remove, conf_reqd) if ctrlnet is None: return if node is None: return if node.netif(ctrlnet.CTRLIF_IDX_BASE + netidx): return # ctrl# already exists ctrlip = node.objid try: addrlist = ["%s/%s" % (ctrlnet.prefix.addr(ctrlip), ctrlnet.prefix.prefixlen)] except ValueError: msg = "Control interface not added to node %s. " % node.objid msg += "Invalid control network prefix (%s). " % ctrlnet.prefix msg += "A longer prefix length may be required for this many nodes." node.exception(coreapi.CORE_EXCP_LEVEL_ERROR, "Session.addremovectrlif()", msg) return ifi = node.newnetif(net = ctrlnet, ifindex = ctrlnet.CTRLIF_IDX_BASE + netidx, ifname = "ctrl%d" % netidx, hwaddr = MacAddr.random(), addrlist = addrlist) node.netif(ifi).control = True def updatectrlifhosts(self, netidx=0, remove=False): ''' Add the IP addresses of control interfaces to the /etc/hosts file. ''' if not self.getcfgitembool('update_etc_hosts', False): return try: ctrlnet = self.getctrlnetobj(netidx) except KeyError: return header = "CORE session %s host entries" % self.sessionid if remove: if self.getcfgitembool('verbose', False): self.info("Removing /etc/hosts file entries.") filedemunge('/etc/hosts', header) return entries = [] for ifc in ctrlnet.netifs(): name = ifc.node.name for addr in ifc.addrlist: entries.append("%s %s" % (addr.split('/')[0], ifc.node.name)) if self.getcfgitembool('verbose', False): self.info("Adding %d /etc/hosts file entries." % len(entries)) filemunge('/etc/hosts', header, '\n'.join(entries) + '\n') def runtime(self): ''' Return the current time we have been in the runtime state, or zero if not in runtime. ''' if self.getstate() == coreapi.CORE_EVENT_RUNTIME_STATE: return time.time() - self._time else: return 0.0 def addevent(self, etime, node=None, name=None, data=None): ''' Add an event to the event queue, with a start time relative to the start of the runtime state. ''' etime = float(etime) runtime = self.runtime() if runtime > 0.0: if time <= runtime: self.warn("Could not schedule past event for time %s " \ "(run time is now %s)" % (time, runtime)) return etime = etime - runtime func = self.runevent self.evq.add_event(etime, func, node=node, name=name, data=data) if name is None: name = "" self.info("scheduled event %s at time %s data=%s" % \ (name, etime + runtime, data)) def runevent(self, node=None, name=None, data=None): ''' Run a scheduled event, executing commands in the data string. ''' now = self.runtime() if name is None: name = "" self.info("running event %s at time %s cmd=%s" % (name, now, data)) if node is None: mutedetach(shlex.split(data)) else: n = self.obj(node) n.cmd(shlex.split(data), wait=False) def sendobjs(self): ''' Return API messages that describe the current session. ''' replies = [] nn = 0 # send node messages for node and network objects with self._objslock: for obj in self.objs(): msg = obj.tonodemsg(flags = coreapi.CORE_API_ADD_FLAG) if msg is not None: replies.append(msg) nn += 1 nl = 0 # send link messages from net objects with self._objslock: for obj in self.objs(): linkmsgs = obj.tolinkmsgs(flags = coreapi.CORE_API_ADD_FLAG) for msg in linkmsgs: replies.append(msg) nl += 1 # send model info configs = self.mobility.getallconfigs() configs += self.emane.getallconfigs() for (nodenum, cls, values) in configs: #cls = self.mobility._modelclsmap[conftype] msg = cls.toconfmsg(flags=0, nodenum=nodenum, typeflags=coreapi.CONF_TYPE_FLAGS_UPDATE, values=values) replies.append(msg) # service customizations svc_configs = self.services.getallconfigs() for (nodenum, svc) in svc_configs: opaque = "service:%s" % svc._name tlvdata = "" tlvdata += coreapi.CoreConfTlv.pack(coreapi.CORE_TLV_CONF_NODE, nodenum) tlvdata += coreapi.CoreConfTlv.pack(coreapi.CORE_TLV_CONF_OPAQUE, opaque) tmp = coreapi.CoreConfMessage(flags=0, hdr="", data=tlvdata) replies.append(self.services.configure_request(tmp)) for (filename, data) in self.services.getallfiles(svc): flags = coreapi.CORE_API_ADD_FLAG tlvdata = coreapi.CoreFileTlv.pack(coreapi.CORE_TLV_FILE_NODE, nodenum) tlvdata += coreapi.CoreFileTlv.pack(coreapi.CORE_TLV_FILE_NAME, str(filename)) tlvdata += coreapi.CoreFileTlv.pack(coreapi.CORE_TLV_FILE_TYPE, opaque) tlvdata += coreapi.CoreFileTlv.pack(coreapi.CORE_TLV_FILE_DATA, str(data)) replies.append(coreapi.CoreFileMessage.pack(flags, tlvdata)) # TODO: send location info # replies.append(self.location.toconfmsg()) # send hook scripts for state in sorted(self._hooks.keys()): for (filename, data) in self._hooks[state]: flags = coreapi.CORE_API_ADD_FLAG tlvdata = coreapi.CoreFileTlv.pack(coreapi.CORE_TLV_FILE_NAME, str(filename)) tlvdata += coreapi.CoreFileTlv.pack(coreapi.CORE_TLV_FILE_TYPE, "hook:%s" % state) tlvdata += coreapi.CoreFileTlv.pack(coreapi.CORE_TLV_FILE_DATA, str(data)) replies.append(coreapi.CoreFileMessage.pack(flags, tlvdata)) # send meta data tmp = coreapi.CoreConfMessage(flags=0, hdr="", data="") opts = self.options.configure_request(tmp, typeflags = coreapi.CONF_TYPE_FLAGS_UPDATE) if opts: replies.append(opts) meta = self.metadata.configure_request(tmp, typeflags = coreapi.CONF_TYPE_FLAGS_UPDATE) if meta: replies.append(meta) self.info("informing GUI about %d nodes and %d links" % (nn, nl)) return replies class SessionConfig(ConfigurableManager, Configurable): _name = 'session' _type = coreapi.CORE_TLV_REG_UTILITY _confmatrix = [ ("controlnet", coreapi.CONF_DATA_TYPE_STRING, '', '', 'Control network'), ("controlnet_updown_script", coreapi.CONF_DATA_TYPE_STRING, '', '', 'Control network script'), ("enablerj45", coreapi.CONF_DATA_TYPE_BOOL, '1', 'On,Off', 'Enable RJ45s'), ("preservedir", coreapi.CONF_DATA_TYPE_BOOL, '0', 'On,Off', 'Preserve session dir'), ("enablesdt", coreapi.CONF_DATA_TYPE_BOOL, '0', 'On,Off', 'Enable SDT3D output'), ("sdturl", coreapi.CONF_DATA_TYPE_STRING, Sdt.DEFAULT_SDT_URL, '', 'SDT3D URL'), ] _confgroups = "Options:1-%d" % len(_confmatrix) def __init__(self, session): ConfigurableManager.__init__(self, session) session.broker.handlers += (self.handledistributed, ) self.reset() def reset(self): defaults = self.getdefaultvalues() for k in self.getnames(): # value may come from config file v = self.session.getcfgitem(k) if v is None: v = self.valueof(k, defaults) v = self.offontobool(v) setattr(self, k, v) def configure_values(self, msg, values): return self.configure_values_keyvalues(msg, values, self, self.getnames()) def configure_request(self, msg, typeflags = coreapi.CONF_TYPE_FLAGS_NONE): nodenum = msg.gettlv(coreapi.CORE_TLV_CONF_NODE) values = [] for k in self.getnames(): v = getattr(self, k) if v is None: v = "" values.append("%s" % v) return self.toconfmsg(0, nodenum, typeflags, values) def handledistributed(self, msg): ''' Handle the session options config message as it has reached the broker. Options requiring modification for distributed operation should be handled here. ''' if not self.session.master: return if msg.msgtype != coreapi.CORE_API_CONF_MSG or \ msg.gettlv(coreapi.CORE_TLV_CONF_OBJ) != "session": return values_str = msg.gettlv(coreapi.CORE_TLV_CONF_VALUES) if values_str is None: return values = values_str.split('|') if not self.haskeyvalues(values): return for v in values: key, value = v.split('=', 1) if key == "controlnet": self.handledistributedcontrolnet(msg, values, values.index(v)) def handledistributedcontrolnet(self, msg, values, idx): ''' Modify Config Message if multiple control network prefixes are defined. Map server names to prefixes and repack the message before it is forwarded to slave servers. ''' kv = values[idx] key, value = kv.split('=', 1) controlnets = value.split() if len(controlnets) < 2: return # multiple controlnet prefixes do not exist servers = self.session.broker.getserverlist() if len(servers) < 2: return # not distributed servers.remove("localhost") servers.insert(0, "localhost") # master always gets first prefix # create list of "server1:ctrlnet1 server2:ctrlnet2 ..." controlnets = map(lambda(x): "%s:%s" % (x[0],x[1]), zip(servers, controlnets)) values[idx] = "controlnet=%s" % (' '.join(controlnets)) values_str = '|'.join(values) msg.tlvdata[coreapi.CORE_TLV_CONF_VALUES] = values_str msg.repack() class SessionMetaData(ConfigurableManager): ''' Metadata is simply stored in a configs[] dict. Key=value pairs are passed in from configure messages destined to the "metadata" object. The data is not otherwise interpreted or processed. ''' _name = "metadata" _type = coreapi.CORE_TLV_REG_UTILITY def configure_values(self, msg, values): if values is None: return None kvs = values.split('|') for kv in kvs: try: (key, value) = kv.split('=', 1) except ValueError: raise ValueError, "invalid key in metdata: %s" % kv self.additem(key, value) return None def configure_request(self, msg, typeflags = coreapi.CONF_TYPE_FLAGS_NONE): nodenum = msg.gettlv(coreapi.CORE_TLV_CONF_NODE) values_str = "|".join(map(lambda(k,v): "%s=%s" % (k,v), self.items())) return self.toconfmsg(0, nodenum, typeflags, values_str) def toconfmsg(self, flags, nodenum, typeflags, values_str): tlvdata = "" if nodenum is not None: tlvdata += coreapi.CoreConfTlv.pack(coreapi.CORE_TLV_CONF_NODE, nodenum) tlvdata += coreapi.CoreConfTlv.pack(coreapi.CORE_TLV_CONF_OBJ, self._name) tlvdata += coreapi.CoreConfTlv.pack(coreapi.CORE_TLV_CONF_TYPE, typeflags) datatypes = tuple( map(lambda(k,v): coreapi.CONF_DATA_TYPE_STRING, self.items()) ) tlvdata += coreapi.CoreConfTlv.pack(coreapi.CORE_TLV_CONF_DATA_TYPES, datatypes) tlvdata += coreapi.CoreConfTlv.pack(coreapi.CORE_TLV_CONF_VALUES, values_str) msg = coreapi.CoreConfMessage.pack(flags, tlvdata) return msg def additem(self, key, value): self.configs[key] = value def items(self): return self.configs.iteritems() atexit.register(Session.atexit) core-4.8/daemon/core/xen/0000775000175000017500000000000012534327775012324 500000000000000core-4.8/daemon/core/xen/__init__.py0000664000175000017500000000000012534327775014343 00000000000000core-4.8/daemon/core/xen/xen.py0000664000175000017500000007561412534327775013425 00000000000000# # CORE # Copyright (c)2011-2012 the Boeing Company. # See the LICENSE file included in this distribution. # ''' xen.py: implementation of the XenNode and XenVEth classes that support generating Xen domUs based on an ISO image and persistent configuration area ''' from core.netns.vnet import * from core.netns.vnode import LxcNode from core.coreobj import PyCoreObj, PyCoreNode, PyCoreNetIf from core.misc.ipaddr import * from core.misc.utils import * from core.constants import * from core.api import coreapi from core.netns.vif import TunTap from core.emane.nodes import EmaneNode try: import parted except ImportError, e: #print "Failed to load parted Python module required by Xen support." #print "Error was:", e raise ImportError import base64 import crypt import subprocess try: import fsimage except ImportError, e: # fix for fsimage under Ubuntu sys.path.append("/usr/lib/xen-default/lib/python") try: import fsimage except ImportError, e: #print "Failed to load fsimage Python module required by Xen support." #print "Error was:", e raise ImportError import os import time import shutil import string # XXX move these out to config file AWK_PATH = "/bin/awk" KPARTX_PATH = "/sbin/kpartx" LVCREATE_PATH = "/sbin/lvcreate" LVREMOVE_PATH = "/sbin/lvremove" LVCHANGE_PATH = "/sbin/lvchange" MKFSEXT4_PATH = "/sbin/mkfs.ext4" MKSWAP_PATH = "/sbin/mkswap" TAR_PATH = "/bin/tar" SED_PATH = "/bin/sed" XM_PATH = "/usr/sbin/xm" UDEVADM_PATH = "/sbin/udevadm" class XenVEth(PyCoreNetIf): def __init__(self, node, name, localname, mtu = 1500, net = None, start = True, hwaddr = None): # note that net arg is ignored PyCoreNetIf.__init__(self, node = node, name = name, mtu = mtu) self.localname = localname self.up = False self.hwaddr = hwaddr if start: self.startup() def startup(self): cmd = [XM_PATH, 'network-attach', self.node.vmname, 'vifname=%s' % self.localname, 'script=vif-core'] if self.hwaddr is not None: cmd.append('mac=%s' % self.hwaddr) check_call(cmd) check_call([IP_BIN, "link", "set", self.localname, "up"]) self.up = True def shutdown(self): if not self.up: return if self.localname: if self.hwaddr is not None: pass # this should be doable, but some argument isn't a string #check_call([XM_PATH, 'network-detach', self.node.vmname, # self.hwaddr]) self.up = False class XenNode(PyCoreNode): apitype = coreapi.CORE_NODE_XEN FilesToIgnore = frozenset([ #'ipforward.sh', 'quaggaboot.sh', ]) FilesRedirection = { 'ipforward.sh' : '/core-tmp/ipforward.sh', } CmdsToIgnore = frozenset([ #'sh ipforward.sh', #'sh quaggaboot.sh zebra', #'sh quaggaboot.sh ospfd', #'sh quaggaboot.sh ospf6d', 'sh quaggaboot.sh vtysh', 'killall zebra', 'killall ospfd', 'killall ospf6d', 'pidof zebra', 'pidof ospfd', 'pidof ospf6d', ]) def RedirCmd_ipforward(self): sysctlFile = open(os.path.join(self.mountdir, self.etcdir, 'sysctl.conf'), 'a') p1 = subprocess.Popen([AWK_PATH, '/^\/sbin\/sysctl -w/ {print $NF}', os.path.join(self.nodedir, 'core-tmp/ipforward.sh') ], stdout=sysctlFile) p1.wait() sysctlFile.close() def RedirCmd_zebra(self): check_call([SED_PATH, '-i', '-e', 's/^zebra=no/zebra=yes/', os.path.join(self.mountdir, self.etcdir, 'quagga/daemons')]) def RedirCmd_ospfd(self): check_call([SED_PATH, '-i', '-e', 's/^ospfd=no/ospfd=yes/', os.path.join(self.mountdir, self.etcdir, 'quagga/daemons')]) def RedirCmd_ospf6d(self): check_call([SED_PATH, '-i', '-e', 's/^ospf6d=no/ospf6d=yes/', os.path.join(self.mountdir, self.etcdir, 'quagga/daemons')]) CmdsRedirection = { 'sh ipforward.sh' : RedirCmd_ipforward, 'sh quaggaboot.sh zebra' : RedirCmd_zebra, 'sh quaggaboot.sh ospfd' : RedirCmd_ospfd, 'sh quaggaboot.sh ospf6d' : RedirCmd_ospf6d, } # CoreNode: no __init__, take from LxcNode & SimpleLxcNode def __init__(self, session, objid = None, name = None, nodedir = None, bootsh = "boot.sh", verbose = False, start = True, model = None, vgname = None, ramsize = None, disksize = None, isofile = None): # SimpleLxcNode initialization PyCoreNode.__init__(self, session = session, objid = objid, name = name, verbose = verbose) self.nodedir = nodedir self.model = model # indicates startup() has been invoked and disk has been initialized self.up = False # indicates boot() has been invoked and domU is running self.booted = False self.ifindex = 0 self.lock = threading.RLock() self._netif = {} # domU name self.vmname = "c" + str(session.sessionid) + "-" + name # LVM volume group name self.vgname = self.getconfigitem('vg_name', vgname) # LVM logical volume name self.lvname = self.vmname + '-' # LVM logical volume device path name self.lvpath = os.path.join('/dev', self.vgname, self.lvname) self.disksize = self.getconfigitem('disk_size', disksize) self.ramsize = int(self.getconfigitem('ram_size', ramsize)) self.isofile = self.getconfigitem('iso_file', isofile) # temporary mount point for paused VM persistent filesystem self.mountdir = None self.etcdir = self.getconfigitem('etc_path') # TODO: remove this temporary hack self.FilesRedirection['/usr/local/etc/quagga/Quagga.conf'] = \ os.path.join(self.getconfigitem('mount_path'), self.etcdir, 'quagga/Quagga.conf') # LxcNode initialization # self.makenodedir() if self.nodedir is None: self.nodedir = \ os.path.join(session.sessiondir, self.name + ".conf") self.mountdir = self.nodedir + self.getconfigitem('mount_path') if not os.path.isdir(self.mountdir): os.makedirs(self.mountdir) self.tmpnodedir = True else: raise Exception, "Xen PVM node requires a temporary nodedir" self.tmpnodedir = False self.bootsh = bootsh if start: self.startup() def getconfigitem(self, name, default=None): ''' Configuration items come from the xen.conf file and/or input from the GUI, and are stored in the session using the XenConfigManager object. self.model is used to identify particular profiles associated with a node type in the GUI. ''' return self.session.xen.getconfigitem(name=name, model=self.model, node=self, value=default) # from class LxcNode (also SimpleLxcNode) def startup(self): self.warn("XEN PVM startup() called: preparing disk for %s" % self.name) self.lock.acquire() try: if self.up: raise Exception, "already up" self.createlogicalvolume() self.createpartitions() persistdev = self.createfilesystems() check_call([MOUNT_BIN, '-t', 'ext4', persistdev, self.mountdir]) self.untarpersistent(tarname=self.getconfigitem('persist_tar_iso'), iso=True) self.setrootpassword(pw = self.getconfigitem('root_password')) self.sethostname(old='UBASE', new=self.name) self.setupssh(keypath=self.getconfigitem('ssh_key_path')) self.createvm() self.up = True finally: self.lock.release() # from class LxcNode (also SimpleLxcNode) def boot(self): self.warn("XEN PVM boot() called") self.lock.acquire() if not self.up: raise Exception, "Can't boot VM without initialized disk" if self.booted: self.lock.release() return self.session.services.bootnodeservices(self) tarname = self.getconfigitem('persist_tar') if tarname: self.untarpersistent(tarname=tarname, iso=False) try: check_call([UMOUNT_BIN, self.mountdir]) self.unmount_all(self.mountdir) check_call([UDEVADM_PATH, 'settle']) check_call([KPARTX_PATH, '-d', self.lvpath]) #time.sleep(5) #time.sleep(1) # unpause VM if self.verbose: self.warn("XEN PVM boot() unpause domU %s" % self.vmname) mutecheck_call([XM_PATH, 'unpause', self.vmname]) self.booted = True finally: self.lock.release() def validate(self): self.session.services.validatenodeservices(self) # from class LxcNode (also SimpleLxcNode) def shutdown(self): self.warn("XEN PVM shutdown() called") if not self.up: return self.lock.acquire() try: if self.up: # sketch from SimpleLxcNode for netif in self.netifs(): netif.shutdown() try: # RJE XXX what to do here if self.booted: mutecheck_call([XM_PATH, 'destroy', self.vmname]) self.booted = False except OSError: pass except subprocess.CalledProcessError: # ignore this error too, the VM may have exited already pass # discard LVM volume lvmRemoveCount = 0 while os.path.exists(self.lvpath): try: check_call([UDEVADM_PATH, 'settle']) mutecall([LVCHANGE_PATH, '-an', self.lvpath]) lvmRemoveCount += 1 mutecall([LVREMOVE_PATH, '-f', self.lvpath]) except OSError: pass if (lvmRemoveCount > 1): self.warn("XEN PVM shutdown() required %d lvremove " \ "executions." % lvmRemoveCount) self._netif.clear() del self.session self.up = False finally: self.rmnodedir() self.lock.release() def createlogicalvolume(self): ''' Create a logical volume for this Xen domU. Called from startup(). ''' if os.path.exists(self.lvpath): raise Exception, "LVM volume already exists" mutecheck_call([LVCREATE_PATH, '--size', self.disksize, '--name', self.lvname, self.vgname]) def createpartitions(self): ''' Partition the LVM volume into persistent and swap partitions using the parted module. ''' dev = parted.Device(path=self.lvpath) dev.removeFromCache() disk = parted.freshDisk(dev, 'msdos') constraint = parted.Constraint(device=dev) persist_size = int(0.75 * constraint.maxSize); self.createpartition(device=dev, disk=disk, start=1, end=(persist_size - 1) , type="ext4") self.createpartition(device=dev, disk=disk, start=persist_size, end=(constraint.maxSize - 1) , type="linux-swap(v1)") disk.commit() def createpartition(self, device, disk, start, end, type): ''' Create a single partition of the specified type and size and add it to the disk object, using the parted module. ''' geo = parted.Geometry(device=device, start=start, end=end) fs = parted.FileSystem(type=type, geometry=geo) part = parted.Partition(disk=disk, fs=fs, type=parted.PARTITION_NORMAL, geometry=geo) constraint = parted.Constraint(exactGeom=geo) disk.addPartition(partition=part, constraint=constraint) def createfilesystems(self): ''' Make an ext4 filesystem and swap space. Return the device name for the persistent partition so we can mount it. ''' output = subprocess.Popen([KPARTX_PATH, '-l', self.lvpath], stdout=subprocess.PIPE).communicate()[0] lines = output.splitlines() persistdev = '/dev/mapper/' + lines[0].strip().split(' ')[0].strip() swapdev = '/dev/mapper/' + lines[1].strip().split(' ')[0].strip() check_call([KPARTX_PATH, '-a', self.lvpath]) mutecheck_call([MKFSEXT4_PATH, '-L', 'persist', persistdev]) mutecheck_call([MKSWAP_PATH, '-f', '-L', 'swap', swapdev]) return persistdev def untarpersistent(self, tarname, iso): ''' Unpack a persistent template tar file to the mounted mount dir. Uses fsimage library to read from an ISO file. ''' tarname = tarname.replace('%h', self.name) # filename may use hostname if iso: try: fs = fsimage.open(self.isofile, 0) except IOError, e: self.warn("Failed to open ISO file: %s (%s)" % (self.isofile,e)) return try: tardata = fs.open_file(tarname).read(); except IOError, e: self.warn("Failed to open tar file: %s (%s)" % (tarname, e)) return finally: del fs; else: try: f = open(tarname) tardata = f.read() f.close() except IOError, e: self.warn("Failed to open tar file: %s (%s)" % (tarname, e)) return p = subprocess.Popen([TAR_PATH, '-C', self.mountdir, '--numeric-owner', '-xf', '-'], stdin=subprocess.PIPE) p.communicate(input=tardata) p.wait() def setrootpassword(self, pw): ''' Set the root password by updating the shadow password file that is on the filesystem mounted in the temporary area. ''' saltedpw = crypt.crypt(pw, '$6$'+base64.b64encode(os.urandom(12))) check_call([SED_PATH, '-i', '-e', '/^root:/s_^root:\([^:]*\):_root:' + saltedpw + ':_', os.path.join(self.mountdir, self.etcdir, 'shadow')]) def sethostname(self, old, new): ''' Set the hostname by updating the hostname and hosts files that reside on the filesystem mounted in the temporary area. ''' check_call([SED_PATH, '-i', '-e', 's/%s/%s/' % (old, new), os.path.join(self.mountdir, self.etcdir, 'hostname')]) check_call([SED_PATH, '-i', '-e', 's/%s/%s/' % (old, new), os.path.join(self.mountdir, self.etcdir, 'hosts')]) def setupssh(self, keypath): ''' Configure SSH access by installing host keys and a system-wide authorized_keys file. ''' sshdcfg = os.path.join(self.mountdir, self.etcdir, 'ssh/sshd_config') check_call([SED_PATH, '-i', '-e', 's/PermitRootLogin no/PermitRootLogin yes/', sshdcfg]) sshdir = os.path.join(self.getconfigitem('mount_path'), self.etcdir, 'ssh') sshdir = sshdir.replace('/','\\/') # backslash slashes for use in sed check_call([SED_PATH, '-i', '-e', 's/#AuthorizedKeysFile %h\/.ssh\/authorized_keys/' + \ 'AuthorizedKeysFile ' + sshdir + '\/authorized_keys/', sshdcfg]) for f in ('ssh_host_rsa_key','ssh_host_rsa_key.pub','authorized_keys'): src = os.path.join(keypath, f) dst = os.path.join(self.mountdir, self.etcdir, 'ssh', f) shutil.copy(src, dst) if f[-3:] != "pub": os.chmod(dst, 0600) def createvm(self): ''' Instantiate a *paused* domU VM Instantiate it now, so we can add network interfaces, pause it so we can have the filesystem open for configuration. ''' args = [XM_PATH, 'create', os.devnull, '--paused'] args.extend(['name=' + self.vmname, 'memory=' + str(self.ramsize)]) args.append('disk=tap:aio:' + self.isofile + ',hda,r') args.append('disk=phy:' + self.lvpath + ',hdb,w') args.append('bootloader=pygrub') bootargs = '--kernel=/isolinux/vmlinuz --ramdisk=/isolinux/initrd' args.append('bootargs=' + bootargs) for action in ('poweroff', 'reboot', 'suspend', 'crash', 'halt'): args.append('on_%s=destroy' % action) args.append('extra=' + self.getconfigitem('xm_create_extra')) mutecheck_call(args) # from class LxcNode def privatedir(self, path): #self.warn("XEN PVM privatedir() called") # Do nothing, Xen PVM nodes are fully private pass # from class LxcNode def opennodefile(self, filename, mode = "w"): self.warn("XEN PVM opennodefile() called") raise Exception, "Can't open VM file with opennodefile()" # from class LxcNode # open a file on a paused Xen node def openpausednodefile(self, filename, mode = "w"): dirname, basename = os.path.split(filename) if not basename: raise ValueError, "no basename for filename: " + filename if dirname and dirname[0] == "/": dirname = dirname[1:] #dirname = dirname.replace("/", ".") dirname = os.path.join(self.nodedir, dirname) if not os.path.isdir(dirname): os.makedirs(dirname, mode = 0755) hostfilename = os.path.join(dirname, basename) return open(hostfilename, mode) # from class LxcNode def nodefile(self, filename, contents, mode = 0644): if filename in self.FilesToIgnore: #self.warn("XEN PVM nodefile(filename=%s) ignored" % [filename]) return if filename in self.FilesRedirection: redirFilename = self.FilesRedirection[filename] self.warn("XEN PVM nodefile(filename=%s) redirected to %s" % (filename, redirFilename)) filename = redirFilename self.warn("XEN PVM nodefile(filename=%s) called" % [filename]) self.lock.acquire() if not self.up: self.lock.release() raise Exception, "Can't access VM file as VM disk isn't ready" return if self.booted: self.lock.release() raise Exception, "Can't access VM file as VM is already running" return try: f = self.openpausednodefile(filename, "w") f.write(contents) os.chmod(f.name, mode) f.close() self.info("created nodefile: '%s'; mode: 0%o" % (f.name, mode)) finally: self.lock.release() # from class SimpleLxcNode def alive(self): # is VM running? return False # XXX def cmd(self, args, wait = True): cmdAsString = string.join(args, ' ') if cmdAsString in self.CmdsToIgnore: #self.warn("XEN PVM cmd(args=[%s]) called and ignored" % cmdAsString) return 0 if cmdAsString in self.CmdsRedirection: self.CmdsRedirection[cmdAsString](self) return 0 self.warn("XEN PVM cmd(args=[%s]) called, but not yet implemented" % cmdAsString) return 0 def cmdresult(self, args): cmdAsString = string.join(args, ' ') if cmdAsString in self.CmdsToIgnore: #self.warn("XEN PVM cmd(args=[%s]) called and ignored" % cmdAsString) return (0, "") self.warn("XEN PVM cmdresult(args=[%s]) called, but not yet implemented" % cmdAsString) return (0, "") def popen(self, args): cmdAsString = string.join(args, ' ') self.warn("XEN PVM popen(args=[%s]) called, but not yet implemented" % cmdAsString) return def icmd(self, args): cmdAsString = string.join(args, ' ') self.warn("XEN PVM icmd(args=[%s]) called, but not yet implemented" % cmdAsString) return def term(self, sh = "/bin/sh"): self.warn("XEN PVM term() called, but not yet implemented") return def termcmdstring(self, sh = "/bin/sh"): ''' We may add 'sudo' to the command string because the GUI runs as a normal user. Use SSH if control interface is available, otherwise use Xen console with a keymapping for easy login. ''' controlifc = None for ifc in self.netifs(): if hasattr(ifc, 'control') and ifc.control == True: controlifc = ifc break cmd = "xterm " # use SSH if control interface is available if controlifc: controlip = controlifc.addrlist[0].split('/')[0] cmd += "-e ssh root@%s" % controlip return cmd # otherwise use 'xm console' #pw = self.getconfigitem('root_password') #cmd += "-xrm 'XTerm*VT100.translations: #override F1: " #cmd += "string(\"root\\n\") \\n F2: string(\"%s\\n\")' " % pw cmd += "-e sudo %s console %s" % (XM_PATH, self.vmname) return cmd def shcmd(self, cmdstr, sh = "/bin/sh"): self.warn("XEN PVM shcmd(args=[%s]) called, but not yet implemented" % cmdstr) return # from class SimpleLxcNode def info(self, msg): if self.verbose: print "%s: %s" % (self.name, msg) sys.stdout.flush() # from class SimpleLxcNode def warn(self, msg): print >> sys.stderr, "%s: %s" % (self.name, msg) sys.stderr.flush() def mount(self, source, target): self.warn("XEN PVM Nodes can't bind-mount filesystems") def umount(self, target): self.warn("XEN PVM Nodes can't bind-mount filesystems") def newifindex(self): self.lock.acquire() try: while self.ifindex in self._netif: self.ifindex += 1 ifindex = self.ifindex self.ifindex += 1 return ifindex finally: self.lock.release() def getifindex(self, netif): for ifindex in self._netif: if self._netif[ifindex] is netif: return ifindex return -1 def addnetif(self, netif, ifindex): self.warn("XEN PVM addnetif() called") PyCoreNode.addnetif(self, netif, ifindex) def delnetif(self, ifindex): self.warn("XEN PVM delnetif() called") PyCoreNode.delnetif(self, ifindex) def newveth(self, ifindex = None, ifname = None, net = None, hwaddr = None): self.warn("XEN PVM newveth(ifindex=%s, ifname=%s) called" % (ifindex, ifname)) self.lock.acquire() try: if ifindex is None: ifindex = self.newifindex() if ifname is None: ifname = "eth%d" % ifindex sessionid = self.session.shortsessionid() name = "n%s.%s.%s" % (self.objid, ifindex, sessionid) localname = "n%s.%s.%s" % (self.objid, ifname, sessionid) ifclass = XenVEth veth = ifclass(node = self, name = name, localname = localname, mtu = 1500, net = net, hwaddr = hwaddr) veth.name = ifname try: self.addnetif(veth, ifindex) except: veth.shutdown() del veth raise return ifindex finally: self.lock.release() def newtuntap(self, ifindex = None, ifname = None, net = None): self.warn("XEN PVM newtuntap() called but not implemented") def sethwaddr(self, ifindex, addr): self._netif[ifindex].sethwaddr(addr) if self.up: pass #self.cmd([IP_BIN, "link", "set", "dev", self.ifname(ifindex), # "address", str(addr)]) def addaddr(self, ifindex, addr): if self.up: pass # self.cmd([IP_BIN, "addr", "add", str(addr), # "dev", self.ifname(ifindex)]) self._netif[ifindex].addaddr(addr) def deladdr(self, ifindex, addr): try: self._netif[ifindex].deladdr(addr) except ValueError: self.warn("trying to delete unknown address: %s" % addr) if self.up: pass # self.cmd([IP_BIN, "addr", "del", str(addr), # "dev", self.ifname(ifindex)]) valid_deladdrtype = ("inet", "inet6", "inet6link") def delalladdr(self, ifindex, addrtypes = valid_deladdrtype): addr = self.getaddr(self.ifname(ifindex), rescan = True) for t in addrtypes: if t not in self.valid_deladdrtype: raise ValueError, "addr type must be in: " + \ " ".join(self.valid_deladdrtype) for a in addr[t]: self.deladdr(ifindex, a) # update cached information self.getaddr(self.ifname(ifindex), rescan = True) # Xen PVM relies on boot process to bring up links #def ifup(self, ifindex): # if self.up: # self.cmd([IP_BIN, "link", "set", self.ifname(ifindex), "up"]) def newnetif(self, net = None, addrlist = [], hwaddr = None, ifindex = None, ifname = None): self.warn("XEN PVM newnetif(ifindex=%s, ifname=%s) called" % (ifindex, ifname)) self.lock.acquire() if not self.up: self.lock.release() raise Exception, "Can't access add veth as VM disk isn't ready" return if self.booted: self.lock.release() raise Exception, "Can't access add veth as VM is already running" return try: if isinstance(net, EmaneNode): raise Exception, "Xen PVM doesn't yet support Emane nets" # ifindex = self.newtuntap(ifindex = ifindex, ifname = ifname, # net = net) # # TUN/TAP is not ready for addressing yet; the device may # # take some time to appear, and installing it into a # # namespace after it has been bound removes addressing; # # save addresses with the interface now # self.attachnet(ifindex, net) # netif = self.netif(ifindex) # netif.sethwaddr(hwaddr) # for addr in maketuple(addrlist): # netif.addaddr(addr) # return ifindex else: ifindex = self.newveth(ifindex = ifindex, ifname = ifname, net = net, hwaddr = hwaddr) if net is not None: self.attachnet(ifindex, net) rulefile = os.path.join(self.getconfigitem('mount_path'), self.etcdir, 'udev/rules.d/70-persistent-net.rules') f = self.openpausednodefile(rulefile, "a") f.write('\n# Xen PVM virtual interface #%s %s with MAC address %s\n' % (ifindex, self.ifname(ifindex), hwaddr)) # Using MAC address as we're now loading PVM net driver "early" # OLD: Would like to use MAC address, but udev isn't working with paravirtualized NICs. Perhaps the "set hw address" isn't triggering a rescan. f.write('SUBSYSTEM=="net", ACTION=="add", DRIVERS=="?*", ATTR{address}=="%s", KERNEL=="eth*", NAME="%s"\n' % (hwaddr, self.ifname(ifindex))) #f.write('SUBSYSTEM=="net", ACTION=="add", DRIVERS=="?*", DEVPATH=="/devices/vif-%s/?*", KERNEL=="eth*", NAME="%s"\n' % (ifindex, self.ifname(ifindex))) f.close() if hwaddr: self.sethwaddr(ifindex, hwaddr) for addr in maketuple(addrlist): self.addaddr(ifindex, addr) #self.ifup(ifindex) return ifindex finally: self.lock.release() def connectnode(self, ifname, othernode, otherifname): self.warn("XEN PVM connectnode() called") # tmplen = 8 # tmp1 = "tmp." + "".join([random.choice(string.ascii_lowercase) # for x in xrange(tmplen)]) # tmp2 = "tmp." + "".join([random.choice(string.ascii_lowercase) # for x in xrange(tmplen)]) # check_call([IP_BIN, "link", "add", "name", tmp1, # "type", "veth", "peer", "name", tmp2]) # # check_call([IP_BIN, "link", "set", tmp1, "netns", str(self.pid)]) # self.cmd([IP_BIN, "link", "set", tmp1, "name", ifname]) # self.addnetif(PyCoreNetIf(self, ifname), self.newifindex()) # # check_call([IP_BIN, "link", "set", tmp2, "netns", str(othernode.pid)]) # othernode.cmd([IP_BIN, "link", "set", tmp2, "name", otherifname]) # othernode.addnetif(PyCoreNetIf(othernode, otherifname), # othernode.newifindex()) def addfile(self, srcname, filename): self.lock.acquire() if not self.up: self.lock.release() raise Exception, "Can't access VM file as VM disk isn't ready" return if self.booted: self.lock.release() raise Exception, "Can't access VM file as VM is already running" return if filename in self.FilesToIgnore: #self.warn("XEN PVM addfile(filename=%s) ignored" % [filename]) return if filename in self.FilesRedirection: redirFilename = self.FilesRedirection[filename] self.warn("XEN PVM addfile(filename=%s) redirected to %s" % (filename, redirFilename)) filename = redirFilename try: fin = open(srcname, "r") contents = fin.read() fin.close() fout = self.openpausednodefile(filename, "w") fout.write(contents) os.chmod(fout.name, mode) fout.close() self.info("created nodefile: '%s'; mode: 0%o" % (fout.name, mode)) finally: self.lock.release() self.warn("XEN PVM addfile(filename=%s) called" % [filename]) #shcmd = "mkdir -p $(dirname '%s') && mv '%s' '%s' && sync" % \ # (filename, srcname, filename) #self.shcmd(shcmd) def unmount_all(self, path): ''' Namespaces inherit the host mounts, so we need to ensure that all namespaces have unmounted our temporary mount area so that the kpartx command will succeed. ''' # Session.bootnodes() already has self.session._objslock for o in self.session.objs(): if not isinstance(o, LxcNode): continue o.umount(path) core-4.8/daemon/core/xen/xenconfig.py0000664000175000017500000002644012534327775014604 00000000000000# # CORE # Copyright (c)2011-2012 the Boeing Company. # See the LICENSE file included in this distribution. # # author: Jeff Ahrenholz # ''' xenconfig.py: Implementation of the XenConfigManager class for managing configurable items for XenNodes. Configuration for a XenNode is available at these three levels: Global config: XenConfigManager.configs[0] = (type='xen', values) Nodes of this machine type have this config. These are the default values. XenConfigManager.default_config comes from defaults + xen.conf Node type config: XenConfigManager.configs[0] = (type='mytype', values) All nodes of this type have this config. Node-specific config: XenConfigManager.configs[nodenumber] = (type, values) The node having this specific number has this config. ''' import sys, os, threading, subprocess, time, string import ConfigParser from xml.dom.minidom import parseString, Document from core.constants import * from core.api import coreapi from core.conf import ConfigurableManager, Configurable class XenConfigManager(ConfigurableManager): ''' Xen controller object. Lives in a Session instance and is used for building Xen profiles. ''' _name = "xen" _type = coreapi.CORE_TLV_REG_EMULSRV def __init__(self, session): ConfigurableManager.__init__(self, session) self.verbose = self.session.getcfgitembool('verbose', False) self.default_config = XenDefaultConfig(session, objid=None) self.loadconfigfile() def setconfig(self, nodenum, conftype, values): ''' add configuration values for a node to a dictionary; values are usually received from a Configuration Message, and may refer to a node for which no object exists yet ''' if nodenum is None: nodenum = 0 # used for storing the global default config return ConfigurableManager.setconfig(self, nodenum, conftype, values) def getconfig(self, nodenum, conftype, defaultvalues): ''' get configuration values for a node; if the values don't exist in our dictionary then return the default values supplied; if conftype is None then we return a match on any conftype. ''' if nodenum is None: nodenum = 0 # used for storing the global default config return ConfigurableManager.getconfig(self, nodenum, conftype, defaultvalues) def clearconfig(self, nodenum): ''' remove configuration values for a node ''' ConfigurableManager.clearconfig(self, nodenum) if 0 in self.configs: self.configs.pop(0) def configure(self, session, msg): ''' Handle configuration messages for global Xen config. ''' return self.default_config.configure(self, msg) def loadconfigfile(self, filename=None): ''' Load defaults from the /etc/core/xen.conf file into dict object. ''' if filename is None: filename = os.path.join(CORE_CONF_DIR, 'xen.conf') cfg = ConfigParser.SafeConfigParser() if filename not in cfg.read(filename): self.session.warn("unable to read Xen config file: %s" % filename) return section = "xen" if not cfg.has_section(section): self.session.warn("%s is missing a xen section!" % filename) return self.configfile = dict(cfg.items(section)) # populate default config items from config file entries vals = list(self.default_config.getdefaultvalues()) names = self.default_config.getnames() for i in range(len(names)): if names[i] in self.configfile: vals[i] = self.configfile[names[i]] # this sets XenConfigManager.configs[0] = (type='xen', vals) self.setconfig(None, self.default_config._name, vals) def getconfigitem(self, name, model=None, node=None, value=None): ''' Get a config item of the given name, first looking for node-specific configuration, then model specific, and finally global defaults. If a value is supplied, it will override any stored config. ''' if value is not None: return value n = None if node: n = node.objid (t, v) = self.getconfig(nodenum=n, conftype=model, defaultvalues=None) if n is not None and v is None: # get item from default config for the node type (t, v) = self.getconfig(nodenum=None, conftype=model, defaultvalues=None) if v is None: # get item from default config for the machine type (t, v) = self.getconfig(nodenum=None, conftype=self.default_config._name, defaultvalues=None) confignames = self.default_config.getnames() if v and name in confignames: i = confignames.index(name) return v[i] else: # name may only exist in config file if name in self.configfile: return self.configfile[name] else: #self.warn("missing config item '%s'" % name) return None class XenConfig(Configurable): ''' Manage Xen configuration profiles. ''' @classmethod def configure(cls, xen, msg): ''' Handle configuration messages for setting up a model. Similar to Configurable.configure(), but considers opaque data for indicating node types. ''' reply = None nodenum = msg.gettlv(coreapi.CORE_TLV_CONF_NODE) objname = msg.gettlv(coreapi.CORE_TLV_CONF_OBJ) conftype = msg.gettlv(coreapi.CORE_TLV_CONF_TYPE) opaque = msg.gettlv(coreapi.CORE_TLV_CONF_OPAQUE) nodetype = objname if opaque is not None: opaque_items = opaque.split(':') if len(opaque_items) != 2: xen.warn("xen config: invalid opaque data in conf message") return None nodetype = opaque_items[1] if xen.verbose: xen.info("received configure message for %s" % nodetype) if conftype == coreapi.CONF_TYPE_FLAGS_REQUEST: if xen.verbose: xen.info("replying to configure request for %s " % nodetype) # when object name is "all", the reply to this request may be None # if this node has not been configured for this model; otherwise we # reply with the defaults for this model if objname == "all": typeflags = coreapi.CONF_TYPE_FLAGS_UPDATE else: typeflags = coreapi.CONF_TYPE_FLAGS_NONE values = xen.getconfig(nodenum, nodetype, defaultvalues=None)[1] if values is None: # get defaults from default "xen" config which includes # settings from both cls._confdefaultvalues and xen.conf defaults = cls.getdefaultvalues() values = xen.getconfig(nodenum, cls._name, defaults)[1] if values is None: return None # reply with config options if nodenum is None: nodenum = 0 reply = cls.toconfmsg(0, nodenum, typeflags, nodetype, values) elif conftype == coreapi.CONF_TYPE_FLAGS_RESET: if objname == "all": xen.clearconfig(nodenum) #elif conftype == coreapi.CONF_TYPE_FLAGS_UPDATE: else: # store the configuration values for later use, when the XenNode # object has been created if objname is None: xen.info("no configuration object for node %s" % nodenum) return None values_str = msg.gettlv(coreapi.CORE_TLV_CONF_VALUES) if values_str is None: # use default or preconfigured values defaults = cls.getdefaultvalues() values = xen.getconfig(nodenum, cls._name, defaults)[1] else: # use new values supplied from the conf message values = values_str.split('|') xen.setconfig(nodenum, nodetype, values) return reply @classmethod def toconfmsg(cls, flags, nodenum, typeflags, nodetype, values): ''' Convert this class to a Config API message. Some TLVs are defined by the class, but node number, conf type flags, and values must be passed in. ''' values_str = string.join(values, '|') tlvdata = "" tlvdata += coreapi.CoreConfTlv.pack(coreapi.CORE_TLV_CONF_NODE, nodenum) tlvdata += coreapi.CoreConfTlv.pack(coreapi.CORE_TLV_CONF_OBJ, cls._name) tlvdata += coreapi.CoreConfTlv.pack(coreapi.CORE_TLV_CONF_TYPE, typeflags) datatypes = tuple( map(lambda x: x[1], cls._confmatrix) ) tlvdata += coreapi.CoreConfTlv.pack(coreapi.CORE_TLV_CONF_DATA_TYPES, datatypes) tlvdata += coreapi.CoreConfTlv.pack(coreapi.CORE_TLV_CONF_VALUES, values_str) captions = reduce( lambda a,b: a + '|' + b, \ map(lambda x: x[4], cls._confmatrix)) tlvdata += coreapi.CoreConfTlv.pack(coreapi.CORE_TLV_CONF_CAPTIONS, captions) possiblevals = reduce( lambda a,b: a + '|' + b, \ map(lambda x: x[3], cls._confmatrix)) tlvdata += coreapi.CoreConfTlv.pack( coreapi.CORE_TLV_CONF_POSSIBLE_VALUES, possiblevals) if cls._bitmap is not None: tlvdata += coreapi.CoreConfTlv.pack(coreapi.CORE_TLV_CONF_BITMAP, cls._bitmap) if cls._confgroups is not None: tlvdata += coreapi.CoreConfTlv.pack(coreapi.CORE_TLV_CONF_GROUPS, cls._confgroups) opaque = "%s:%s" % (cls._name, nodetype) tlvdata += coreapi.CoreConfTlv.pack(coreapi.CORE_TLV_CONF_OPAQUE, opaque) msg = coreapi.CoreConfMessage.pack(flags, tlvdata) return msg class XenDefaultConfig(XenConfig): ''' Global default Xen configuration options. ''' _name = "xen" # Configuration items: # ('name', 'type', 'default', 'possible-value-list', 'caption') _confmatrix = [ ('ram_size', coreapi.CONF_DATA_TYPE_STRING, '256', '', 'ram size (MB)'), ('disk_size', coreapi.CONF_DATA_TYPE_STRING, '256M', '', 'disk size (use K/M/G suffix)'), ('iso_file', coreapi.CONF_DATA_TYPE_STRING, '', '', 'iso file'), ('mount_path', coreapi.CONF_DATA_TYPE_STRING, '', '', 'mount path'), ('etc_path', coreapi.CONF_DATA_TYPE_STRING, '', '', 'etc path'), ('persist_tar_iso', coreapi.CONF_DATA_TYPE_STRING, '', '', 'iso persist tar file'), ('persist_tar', coreapi.CONF_DATA_TYPE_STRING, '', '', 'persist tar file'), ('root_password', coreapi.CONF_DATA_TYPE_STRING, 'password', '', 'root password'), ] _confgroups = "domU properties:1-%d" % len(_confmatrix) core-4.8/daemon/core/constants.py0000664000175000017500000000127212534330005014016 00000000000000# Constants created by autoconf ./configure script COREDPY_VERSION = "4.8" CORE_STATE_DIR = "/var" CORE_CONF_DIR = "/etc/core" CORE_DATA_DIR = "/usr/share/core" CORE_LIB_DIR = "/usr/lib/core" CORE_SBIN_DIR = "/usr/sbin" BRCTL_BIN = "/usr/sbin/brctl" SYSCTL_BIN = "/usr/sbin/sysctl" IP_BIN = "/usr/sbin/ip" TC_BIN = "/usr/sbin/tc" EBTABLES_BIN = "/usr/sbin/ebtables" IFCONFIG_BIN = "/usr/sbin/ifconfig" NGCTL_BIN = "no/ngctl" VIMAGE_BIN = "no/vimage" QUAGGA_STATE_DIR = "/var/run/quagga" MOUNT_BIN = "/usr/bin/mount" UMOUNT_BIN = "/usr/bin/umount" core-4.8/daemon/ns3/0000775000175000017500000000000012534330007011263 500000000000000core-4.8/daemon/ns3/corens3/0000775000175000017500000000000012534330005012635 500000000000000core-4.8/daemon/ns3/corens3/constants.py.in0000664000175000017500000000134712534327775015601 00000000000000# Constants created by autoconf ./configure script COREDPY_VERSION = "@COREDPY_VERSION@" CORE_STATE_DIR = "@CORE_STATE_DIR@" CORE_CONF_DIR = "@CORE_CONF_DIR@" CORE_DATA_DIR = "@CORE_DATA_DIR@" CORE_LIB_DIR = "@CORE_LIB_DIR@" CORE_SBIN_DIR = "@SBINDIR@" BRCTL_BIN = "@brctl_path@/brctl" IP_BIN = "@ip_path@/ip" TC_BIN = "@tc_path@/tc" EBTABLES_BIN = "@ebtables_path@/ebtables" IFCONFIG_BIN = "@ifconfig_path@/ifconfig" NGCTL_BIN = "@ngctl_path@/ngctl" VIMAGE_BIN = "@vimage_path@/vimage" QUAGGA_STATE_DIR = "@CORE_STATE_DIR@/run/quagga" MOUNT_BIN = "@mount_path@/mount" UMOUNT_BIN = "@umount_path@/umount" core-4.8/daemon/ns3/corens3/.gitignore0000664000175000017500000000001512534327775014565 00000000000000constants.py core-4.8/daemon/ns3/corens3/__init__.py0000664000175000017500000000073312534327775014715 00000000000000# Copyright (c)2011-2012 the Boeing Company. # See the LICENSE file included in this directory. """corens3 Python package containing CORE components for use with the ns-3 simulator. See http://www.nrl.navy.mil/itd/ncs/products/core and http://code.google.com/p/coreemu/ for more information on CORE. Pieces can be imported individually, for example import corens3 or everything listed in __all__ can be imported using from corens3 import * """ __all__ = [] core-4.8/daemon/ns3/corens3/obj.py0000664000175000017500000004772312534327775013742 00000000000000# # CORE # Copyright (c)2011-2013 the Boeing Company. # See the LICENSE file included in this directory. # # author: Jeff Ahrenholz # ''' ns3.py: defines classes for running emulations with ns-3 simulated networks. ''' import sys, os, threading, time from core.netns.nodes import CoreNode from core.coreobj import PyCoreNet from core.session import Session from core.misc import ipaddr from core.constants import * from core.misc.utils import maketuple, check_call from core.api import coreapi from core.mobility import WayPointMobility try: import ns.core except Exception, e: print "Could not locate the ns-3 Python bindings!" print "Try running again from within the ns-3 './waf shell'\n" raise Exception, e import ns.lte import ns.mobility import ns.network import ns.internet import ns.tap_bridge import ns.wifi import ns.wimax ns.core.GlobalValue.Bind("SimulatorImplementationType", ns.core.StringValue("ns3::RealtimeSimulatorImpl")) ns.core.GlobalValue.Bind("ChecksumEnabled", ns.core.BooleanValue("true")) class CoreNs3Node(CoreNode, ns.network.Node): ''' The CoreNs3Node is both a CoreNode backed by a network namespace and an ns-3 Node simulator object. When linked to simulated networks, the TunTap device will be used. ''' def __init__(self, *args, **kwds): ns.network.Node.__init__(self) objid = self.GetId() + 1 # ns-3 ID starts at 0, CORE uses 1 if 'objid' not in kwds: kwds['objid'] = objid CoreNode.__init__(self, *args, **kwds) def newnetif(self, net = None, addrlist = [], hwaddr = None, ifindex = None, ifname = None): ''' Add a network interface. If we are attaching to a CoreNs3Net, this will be a TunTap. Otherwise dispatch to CoreNode.newnetif(). ''' if not isinstance(net, CoreNs3Net): return CoreNode.newnetif(self, net, addrlist, hwaddr, ifindex, ifname) ifindex = self.newtuntap(ifindex = ifindex, ifname = ifname, net = net) self.attachnet(ifindex, net) netif = self.netif(ifindex) netif.sethwaddr(hwaddr) for addr in maketuple(addrlist): netif.addaddr(addr) addrstr = netif.addrlist[0] (addr, mask) = addrstr.split('/') tap = net._tapdevs[netif] tap.SetAttribute("IpAddress", ns.network.Ipv4AddressValue(ns.network.Ipv4Address(addr))) tap.SetAttribute("Netmask", ns.network.Ipv4MaskValue(ns.network.Ipv4Mask("/" + mask))) ns.core.Simulator.Schedule(ns.core.Time('0'), netif.install) return ifindex def getns3position(self): ''' Return the ns-3 (x, y, z) position of a node. ''' try: mm = self.GetObject(ns.mobility.MobilityModel.GetTypeId()) pos = mm.GetPosition() return (pos.x, pos.y, pos.z) except AttributeError: self.warn("ns-3 mobility model not found") return (0,0,0) def setns3position(self, x, y, z): ''' Set the ns-3 (x, y, z) position of a node. ''' try: mm = self.GetObject(ns.mobility.MobilityModel.GetTypeId()) if z is None: z = 0.0 pos = mm.SetPosition(ns.core.Vector(x, y, z)) except AttributeError: self.warn("ns-3 mobility model not found, not setting position") class CoreNs3Net(PyCoreNet): ''' The CoreNs3Net is a helper PyCoreNet object. Networks are represented entirely in simulation with the TunTap device bridging the emulated and simulated worlds. ''' apitype = coreapi.CORE_NODE_WLAN linktype = coreapi.CORE_LINK_WIRELESS type = "wlan" # icon used def __init__(self, session, objid = None, name = None, verbose = False, start = True, policy = None): PyCoreNet.__init__(self, session, objid, name) self.tapbridge = ns.tap_bridge.TapBridgeHelper() self._ns3devs = {} self._tapdevs = {} def attach(self, netif): ''' Invoked from netif.attach(). Create a TAP device using the TapBridge object. Call getns3dev() to get model-specific device. ''' self._netif[netif] = netif self._linked[netif] = {} ns3dev = self.getns3dev(netif.node) tap = self.tapbridge.Install(netif.node, ns3dev) tap.SetMode(ns.tap_bridge.TapBridge.CONFIGURE_LOCAL) tap.SetAttribute("DeviceName", ns.core.StringValue(netif.localname)) self._ns3devs[netif] = ns3dev self._tapdevs[netif] = tap def getns3dev(self, node): ''' Implement depending on network helper. Install this network onto the given node and return the device. Register the ns3 device into self._ns3devs ''' raise NotImplementedError def findns3dev(self, node): ''' Given a node, return the interface and ns3 device associated with this network. ''' for netif in node.netifs(): if netif in self._ns3devs: return netif, self._ns3devs[netif] return None, None def shutdown(self): ''' Session.shutdown() will invoke this. ''' pass def usecorepositions(self): ''' Set position callbacks for interfaces on this net so the CORE GUI can update the ns-3 node position when moved with the mouse. ''' for netif in self.netifs(): netif.poshook = self.setns3position def setns3position(self, netif, x, y, z): #print "setns3position: %s (%s, %s, %s)" % (netif.node.name, x, y, z) netif.node.setns3position(x, y, z) class Ns3LteNet(CoreNs3Net): def __init__(self, *args, **kwds): ''' Uses a LteHelper to create an ns-3 based LTE network. ''' CoreNs3Net.__init__(self, *args, **kwds) self.lte = ns.lte.LteHelper() # enhanced NodeB node list self.enbnodes = [] self.dlsubchannels = None self.ulsubchannels = None def setsubchannels(self, downlink, uplink): ''' Set the downlink/uplink subchannels, which are a list of ints. These should be set prior to using CoreNs3Node.newnetif(). ''' self.dlsubchannels = downlink self.ulsubchannels = uplink def setnodeb(self, node): ''' Mark the given node as a nodeb (base transceiver station) ''' self.enbnodes.append(node) def linknodeb(self, node, nodeb, mob, mobb): ''' Register user equipment with a nodeb. Optionally install mobility model while we have the ns-3 devs handy. ''' (tmp, nodebdev) = self.findns3dev(nodeb) (tmp, dev) = self.findns3dev(node) if nodebdev is None or dev is None: raise KeyError, "ns-3 device for node not found" self.lte.RegisterUeToTheEnb(dev, nodebdev) if mob: self.lte.AddMobility(dev.GetPhy(), mob) if mobb: self.lte.AddDownlinkChannelRealization(mobb, mob, dev.GetPhy()) def getns3dev(self, node): ''' Get the ns3 NetDevice using the LteHelper. ''' if node in self.enbnodes: devtype = ns.lte.LteHelper.DEVICE_TYPE_ENODEB else: devtype = ns.lte.LteHelper.DEVICE_TYPE_USER_EQUIPMENT nodes = ns.network.NodeContainer(node) devs = self.lte.Install(nodes, devtype) devs.Get(0).GetPhy().SetDownlinkSubChannels(self.dlsubchannels) devs.Get(0).GetPhy().SetUplinkSubChannels(self.ulsubchannels) return devs.Get(0) def attach(self, netif): ''' Invoked from netif.attach(). Create a TAP device using the TapBridge object. Call getns3dev() to get model-specific device. ''' self._netif[netif] = netif self._linked[netif] = {} ns3dev = self.getns3dev(netif.node) self.tapbridge.SetAttribute("Mode", ns.core.StringValue("UseLocal")) #self.tapbridge.SetAttribute("Mode", # ns.core.IntegerValue(ns.tap_bridge.TapBridge.USE_LOCAL)) tap = self.tapbridge.Install(netif.node, ns3dev) #tap.SetMode(ns.tap_bridge.TapBridge.USE_LOCAL) print "using TAP device %s for %s/%s" % \ (netif.localname, netif.node.name, netif.name) check_call(['tunctl', '-t', netif.localname, '-n']) #check_call([IP_BIN, 'link', 'set', 'dev', netif.localname, \ # 'address', '%s' % netif.hwaddr]) check_call([IP_BIN, 'link', 'set', netif.localname, 'up']) tap.SetAttribute("DeviceName", ns.core.StringValue(netif.localname)) self._ns3devs[netif] = ns3dev self._tapdevs[netif] = tap class Ns3WifiNet(CoreNs3Net): def __init__(self, *args, **kwds): ''' Uses a WifiHelper to create an ns-3 based Wifi network. ''' rate = kwds.pop('rate', 'OfdmRate54Mbps') CoreNs3Net.__init__(self, *args, **kwds) self.wifi = ns.wifi.WifiHelper().Default() self.wifi.SetStandard(ns.wifi.WIFI_PHY_STANDARD_80211a) self.wifi.SetRemoteStationManager("ns3::ConstantRateWifiManager", "DataMode", ns.core.StringValue(rate), "NonUnicastMode", ns.core.StringValue(rate)) self.mac = ns.wifi.NqosWifiMacHelper.Default() self.mac.SetType("ns3::AdhocWifiMac") channel = ns.wifi.YansWifiChannelHelper.Default() self.phy = ns.wifi.YansWifiPhyHelper.Default() self.phy.SetChannel(channel.Create()) def getns3dev(self, node): ''' Get the ns3 NetDevice using the WifiHelper. ''' devs = self.wifi.Install(self.phy, self.mac, node) return devs.Get(0) class Ns3WimaxNet(CoreNs3Net): def __init__(self, *args, **kwds): CoreNs3Net.__init__(self, *args, **kwds) self.wimax = ns.wimax.WimaxHelper() self.scheduler = ns.wimax.WimaxHelper.SCHED_TYPE_SIMPLE self.phy = ns.wimax.WimaxHelper.SIMPLE_PHY_TYPE_OFDM # base station node list self.bsnodes = [] def setbasestation(self, node): self.bsnodes.append(node) def getns3dev(self, node): if node in self.bsnodes: devtype = ns.wimax.WimaxHelper.DEVICE_TYPE_BASE_STATION else: devtype = ns.wimax.WimaxHelper.DEVICE_TYPE_SUBSCRIBER_STATION nodes = ns.network.NodeContainer(node) devs = self.wimax.Install(nodes, devtype, self.phy, self.scheduler) if node not in self.bsnodes: devs.Get(0).SetModulationType(ns.wimax.WimaxPhy.MODULATION_TYPE_QAM16_12) # debug self.wimax.EnableAscii("wimax-device-%s" % node.name, devs) return devs.Get(0) @staticmethod def ipv4netifaddr(netif): for addr in netif.addrlist: if ':' in addr: continue # skip ipv6 ip = ns.network.Ipv4Address(addr.split('/')[0]) mask = ns.network.Ipv4Mask('/' + addr.split('/')[1]) return (ip, mask) return (None, None) def addflow(self, node1, node2, upclass, downclass): ''' Add a Wimax service flow between two nodes. ''' (netif1, ns3dev1) = self.findns3dev(node1) (netif2, ns3dev2) = self.findns3dev(node2) if not netif1 or not netif2: raise ValueError, "interface not found" (addr1, mask1) = self.ipv4netifaddr(netif1) (addr2, mask2) = self.ipv4netifaddr(netif2) clargs1 = (addr1, mask1, addr2, mask2) + downclass clargs2 = (addr2, mask2, addr1, mask1) + upclass clrec1 = ns.wimax.IpcsClassifierRecord(*clargs1) clrec2 = ns.wimax.IpcsClassifierRecord(*clargs2) ns3dev1.AddServiceFlow( \ self.wimax.CreateServiceFlow(ns.wimax.ServiceFlow.SF_DIRECTION_DOWN, ns.wimax.ServiceFlow.SF_TYPE_RTPS, clrec1)) ns3dev1.AddServiceFlow( \ self.wimax.CreateServiceFlow(ns.wimax.ServiceFlow.SF_DIRECTION_UP, ns.wimax.ServiceFlow.SF_TYPE_RTPS, clrec2)) ns3dev2.AddServiceFlow( \ self.wimax.CreateServiceFlow(ns.wimax.ServiceFlow.SF_DIRECTION_DOWN, ns.wimax.ServiceFlow.SF_TYPE_RTPS, clrec2)) ns3dev2.AddServiceFlow( \ self.wimax.CreateServiceFlow(ns.wimax.ServiceFlow.SF_DIRECTION_UP, ns.wimax.ServiceFlow.SF_TYPE_RTPS, clrec1)) class Ns3Session(Session): ''' A Session that starts an ns-3 simulation thread. ''' def __init__(self, persistent = False, duration=600): self.duration = duration self.nodes = ns.network.NodeContainer() self.mobhelper = ns.mobility.MobilityHelper() Session.__init__(self, persistent = persistent) def run(self, vis=False): ''' Run the ns-3 simulation and return the simulator thread. ''' def runthread(): ns.core.Simulator.Stop(ns.core.Seconds(self.duration)) print "running ns-3 simulation for %d seconds" % self.duration if vis: try: import visualizer except ImportError: print "visualizer is not available" ns.core.Simulator.Run() else: visualizer.start() else: ns.core.Simulator.Run() #self.evq.run() # event queue may have WayPointMobility events self.setstate(coreapi.CORE_EVENT_RUNTIME_STATE, info=True, sendevent=True) t = threading.Thread(target = runthread) t.daemon = True t.start() return t def shutdown(self): # TODO: the following line tends to segfault ns-3 (and therefore # core-daemon) ns.core.Simulator.Destroy() Session.shutdown(self) def addnode(self, name): ''' A convenience helper for Session.addobj(), for adding CoreNs3Nodes to this session. Keeps a NodeContainer for later use. ''' n = self.addobj(cls = CoreNs3Node, name=name) self.nodes.Add(n) return n def setupconstantmobility(self): ''' Install a ConstantPositionMobilityModel. ''' palloc = ns.mobility.ListPositionAllocator() for i in xrange(self.nodes.GetN()): (x, y, z) = ((100.0 * i) + 50, 200.0, 0.0) palloc.Add(ns.core.Vector(x, y, z)) node = self.nodes.Get(i) node.position.set(x, y, z) self.mobhelper.SetPositionAllocator(palloc) self.mobhelper.SetMobilityModel("ns3::ConstantPositionMobilityModel") self.mobhelper.Install(self.nodes) def setuprandomwalkmobility(self, bounds, time=10, speed=25.0): ''' Set up the random walk mobility model within a bounding box. - bounds is the max (x, y, z) boundary - time is the number of seconds to maintain the current speed and direction - speed is the maximum speed, with node speed randomly chosen from [0, speed] ''' (x, y, z) = map(float, bounds) self.mobhelper.SetPositionAllocator("ns3::RandomBoxPositionAllocator", "X", ns.core.StringValue("ns3::UniformRandomVariable[Min=0|Max=%s]" % x), "Y", ns.core.StringValue("ns3::UniformRandomVariable[Min=0|Max=%s]" % y), "Z", ns.core.StringValue("ns3::UniformRandomVariable[Min=0|Max=%s]" % z)) self.mobhelper.SetMobilityModel("ns3::RandomWalk2dMobilityModel", "Mode", ns.core.StringValue("Time"), "Time", ns.core.StringValue("%ss" % time), "Speed", ns.core.StringValue("ns3::UniformRandomVariable[Min=0|Max=%s]" \ % speed), "Bounds", ns.core.StringValue("0|%s|0|%s" % (x, y))) self.mobhelper.Install(self.nodes) def startns3mobility(self, refresh_ms=300): ''' Start a thread that updates CORE nodes based on their ns-3 positions. ''' self.setstate(coreapi.CORE_EVENT_INSTANTIATION_STATE) self.mobilitythread = threading.Thread( target=self.ns3mobilitythread, args=(refresh_ms,)) self.mobilitythread.daemon = True self.mobilitythread.start() def ns3mobilitythread(self, refresh_ms): ''' Thread target that updates CORE nodes every refresh_ms based on their ns-3 positions. ''' valid_states = (coreapi.CORE_EVENT_RUNTIME_STATE, coreapi.CORE_EVENT_INSTANTIATION_STATE) while self.getstate() in valid_states: for i in xrange(self.nodes.GetN()): node = self.nodes.Get(i) (x, y, z) = node.getns3position() if (x, y, z) == node.position.get(): continue # from WayPointMobility.setnodeposition(node, x, y, z) node.position.set(x, y, z) msg = node.tonodemsg(flags=0) self.broadcastraw(None, msg) self.sdt.updatenode(node.objid, flags=0, x=x, y=y, z=z) time.sleep(0.001 * refresh_ms) def setupmobilitytracing(self, net, filename, nodes, verbose=False): ''' Start a tracing thread using the ASCII output from the ns3 mobility helper. ''' net.mobility = WayPointMobility(session=self, objid=net.objid, verbose=verbose, values=None) net.mobility.setendtime() net.mobility.refresh_ms = 300 net.mobility.empty_queue_stop = False of = ns.network.OutputStreamWrapper(filename, filemode=777) self.mobhelper.EnableAsciiAll(of) self.mobilitytracethread = threading.Thread(target=self.mobilitytrace, args=(net, filename, nodes, verbose)) self.mobilitytracethread.daemon = True self.mobilitytracethread.start() def mobilitytrace(self, net, filename, nodes, verbose): nodemap = {} # move nodes to initial positions for node in nodes: (x,y,z) = node.getns3position() net.mobility.setnodeposition(node, x, y, z) nodemap[node.GetId()] = node if verbose: self.info("mobilitytrace opening '%s'" % filename) try: f = open(filename) f.seek(0,2) except Exception, e: self.warn("mobilitytrace error opening '%s': %s" % (filename, e)) sleep = 0.001 kickstart = True while True: if self.getstate() != coreapi.CORE_EVENT_RUNTIME_STATE: break line = f.readline() if not line: time.sleep(sleep) if sleep < 1.0: sleep += 0.001 continue sleep = 0.001 items = dict(map(lambda x: x.split('='), line.split())) if verbose: self.info("trace: %s %s %s" % \ (items['node'], items['pos'], items['vel'])) (x, y, z) = map(float, items['pos'].split(':')) vel = map(float, items['vel'].split(':')) node = nodemap[int(items['node'])] net.mobility.addwaypoint(time=0, nodenum=node.objid, x=x, y=y, z=z, speed=vel) if kickstart: kickstart = False self.evq.add_event(0, net.mobility.start) self.evq.run() else: if net.mobility.state != net.mobility.STATE_RUNNING: net.mobility.state = net.mobility.STATE_RUNNING self.evq.add_event(0, net.mobility.runround) f.close() core-4.8/daemon/ns3/corens3/constants.py0000664000175000017500000000121512534330005015142 00000000000000# Constants created by autoconf ./configure script COREDPY_VERSION = "4.8" CORE_STATE_DIR = "/var" CORE_CONF_DIR = "/etc/core" CORE_DATA_DIR = "/usr/share/core" CORE_LIB_DIR = "/usr/lib/core" CORE_SBIN_DIR = "/usr/sbin" BRCTL_BIN = "/usr/sbin/brctl" IP_BIN = "/usr/sbin/ip" TC_BIN = "/usr/sbin/tc" EBTABLES_BIN = "/usr/sbin/ebtables" IFCONFIG_BIN = "/usr/sbin/ifconfig" NGCTL_BIN = "no/ngctl" VIMAGE_BIN = "no/vimage" QUAGGA_STATE_DIR = "/var/run/quagga" MOUNT_BIN = "/usr/bin/mount" UMOUNT_BIN = "/usr/bin/umount" core-4.8/daemon/ns3/examples/0000775000175000017500000000000012534330007013101 500000000000000core-4.8/daemon/ns3/examples/ns3lte.py0000775000175000017500000000756212534327775014642 00000000000000#!/usr/bin/python # Copyright (c)2011-2012 the Boeing Company. # See the LICENSE file included in this distribution. # # author: Jeff Ahrenholz # ''' ns3lte.py - This script demonstrates using CORE with the ns-3 LTE model. *** Note that this script is not currently functional, see notes below. *** - issues connecting TapBridge with LteNetDevice ''' import os, sys, time, optparse, datetime, math try: from core import pycore except ImportError: # hack for Fedora autoconf that uses the following pythondir: if "/usr/lib/python2.6/site-packages" in sys.path: sys.path.append("/usr/local/lib/python2.6/site-packages") if "/usr/lib64/python2.6/site-packages" in sys.path: sys.path.append("/usr/local/lib64/python2.6/site-packages") if "/usr/lib/python2.7/site-packages" in sys.path: sys.path.append("/usr/local/lib/python2.7/site-packages") if "/usr/lib64/python2.7/site-packages" in sys.path: sys.path.append("/usr/local/lib64/python2.7/site-packages") from core import pycore from core.misc import ipaddr from corens3.obj import Ns3Session, Ns3LteNet import ns.core import ns.mobility def ltesession(opt): ''' Run a test LTE session. ''' session = Ns3Session(persistent=True, duration=opt.duration) lte = session.addobj(cls=Ns3LteNet, name="wlan1") lte.setsubchannels(range(25), range(50, 100)) if opt.verbose: ascii = ns.network.AsciiTraceHelper() stream = ascii.CreateFileStream('/tmp/ns3lte.tr') lte.lte.EnableAsciiAll(stream) #ns.core.LogComponentEnable("EnbNetDevice", ns.core.LOG_LEVEL_INFO) #ns.core.LogComponentEnable("UeNetDevice", ns.core.LOG_LEVEL_INFO) #lte.lte.EnableLogComponents() prefix = ipaddr.IPv4Prefix("10.0.0.0/16") mobb = None nodes = [] for i in xrange(1, opt.numnodes + 1): node = session.addnode(name = "n%d" % i) mob = ns.mobility.ConstantPositionMobilityModel() mob.SetPosition( ns.core.Vector3D(10.0 * i, 0.0, 0.0) ) if i == 1: lte.setnodeb(node) # first node is nodeb mobb = mob node.newnetif(lte, ["%s/%s" % (prefix.addr(i), prefix.prefixlen)]) nodes.append(node) if i == 1: (tmp, ns3dev) = lte.findns3dev(node) lte.lte.AddMobility(ns3dev.GetPhy(), mob) if i > 1: lte.linknodeb(node, nodes[0], mob, mobb) session.thread = session.run(vis=opt.visualize) return session def main(): ''' Main routine when running from command-line. ''' usagestr = "usage: %prog [-h] [options] [args]" parser = optparse.OptionParser(usage = usagestr) parser.set_defaults(numnodes = 4, duration = 600, verbose = False, visualize=False) parser.add_option("-d", "--duration", dest = "duration", type = int, help = "number of seconds to run the simulation") parser.add_option("-n", "--numnodes", dest = "numnodes", type = int, help = "number of nodes") parser.add_option("-z", "--visualize", dest = "visualize", action = "store_true", help = "enable visualizer") parser.add_option("-v", "--verbose", dest = "verbose", action = "store_true", help = "be more verbose") def usage(msg = None, err = 0): sys.stdout.write("\n") if msg: sys.stdout.write(msg + "\n\n") parser.print_help() sys.exit(err) (opt, args) = parser.parse_args() if opt.numnodes < 2: usage("invalid numnodes: %s" % opt.numnodes) for a in args: sys.stderr.write("ignoring command line argument: '%s'\n" % a) return ltesession(opt) def cleanup(): print "shutting down session" session.shutdown() print "joining simulator thread (please kill it)" session.thread.join() if __name__ == "__main__": session = main() core-4.8/daemon/ns3/examples/ns3wifi.py0000775000175000017500000000717212534327775015011 00000000000000#!/usr/bin/python -i # Copyright (c)2011-2013 the Boeing Company. # See the LICENSE file included in this distribution. # # author: Jeff Ahrenholz # ''' ns3wifi.py - This script demonstrates using CORE with the ns-3 Wifi model. How to run this: pushd ~/ns-allinone-3.16/ns-3.16 sudo ./waf shell popd python -i ns3wifi.py To run with the CORE GUI: pushd ~/ns-allinone-3.16/ns-3.16 sudo ./waf shell core-daemon # in another terminal core-daemon -e ./ns3wifi.py # in a third terminal core # now select the running session ''' import os, sys, time, optparse, datetime, math try: from core import pycore except ImportError: # hack for Fedora autoconf that uses the following pythondir: if "/usr/lib/python2.6/site-packages" in sys.path: sys.path.append("/usr/local/lib/python2.6/site-packages") if "/usr/lib64/python2.6/site-packages" in sys.path: sys.path.append("/usr/local/lib64/python2.6/site-packages") if "/usr/lib/python2.7/site-packages" in sys.path: sys.path.append("/usr/local/lib/python2.7/site-packages") if "/usr/lib64/python2.7/site-packages" in sys.path: sys.path.append("/usr/local/lib64/python2.7/site-packages") from core import pycore import ns.core from core.misc import ipaddr from corens3.obj import Ns3Session, Ns3WifiNet def add_to_server(session): ''' Add this session to the server's list if this script is executed from the core-daemon server. ''' global server try: server.addsession(session) return True except NameError: return False def wifisession(opt): ''' Run a test wifi session. ''' session = Ns3Session(persistent=True, duration=opt.duration) session.name = "ns3wifi" session.filename = session.name + ".py" session.node_count = str(opt.numnodes + 1) add_to_server(session) wifi = session.addobj(cls=Ns3WifiNet, name="wlan1") wifi.setposition(30, 30, 0) wifi.phy.Set("RxGain", ns.core.DoubleValue(18.0)) prefix = ipaddr.IPv4Prefix("10.0.0.0/16") nodes = [] for i in xrange(1, opt.numnodes + 1): node = session.addnode(name = "n%d" % i) node.newnetif(wifi, ["%s/%s" % (prefix.addr(i), prefix.prefixlen)]) nodes.append(node) session.setupconstantmobility() wifi.usecorepositions() # PHY tracing #wifi.phy.EnableAsciiAll("ns3wifi") session.thread = session.run(vis=False) return session def main(): ''' Main routine when running from command-line. ''' usagestr = "usage: %prog [-h] [options] [args]" parser = optparse.OptionParser(usage = usagestr) parser.set_defaults(numnodes = 10, duration = 600, verbose = False) parser.add_option("-d", "--duration", dest = "duration", type = int, help = "number of seconds to run the simulation") parser.add_option("-n", "--numnodes", dest = "numnodes", type = int, help = "number of nodes") parser.add_option("-v", "--verbose", dest = "verbose", action = "store_true", help = "be more verbose") def usage(msg = None, err = 0): sys.stdout.write("\n") if msg: sys.stdout.write(msg + "\n\n") parser.print_help() sys.exit(err) (opt, args) = parser.parse_args() if opt.numnodes < 2: usage("invalid numnodes: %s" % opt.numnodes) for a in args: sys.stderr.write("ignoring command line argument: '%s'\n" % a) return wifisession(opt) if __name__ == "__main__" or __name__ == "__builtin__": session = main() print "\nsession =", session core-4.8/daemon/ns3/examples/ns3wifirandomwalk.py0000775000175000017500000001051112534327775017060 00000000000000#!/usr/bin/python -i # Copyright (c)2011-2013 the Boeing Company. # See the LICENSE file included in this distribution. # # author: Jeff Ahrenholz # ''' ns3wifirandomwalk.py - This script demonstrates using CORE with the ns-3 Wifi model and random walk mobility. Patterned after the ns-3 example 'main-random-walk.cc'. How to run this: pushd ~/ns-allinone-3.16/ns-3.16 sudo ./waf shell popd python -i ns3wifirandomwalk.py ''' import os, sys, time, optparse, datetime, math, threading try: from core import pycore except ImportError: # hack for Fedora autoconf that uses the following pythondir: if "/usr/lib/python2.6/site-packages" in sys.path: sys.path.append("/usr/local/lib/python2.6/site-packages") if "/usr/lib64/python2.6/site-packages" in sys.path: sys.path.append("/usr/local/lib64/python2.6/site-packages") if "/usr/lib/python2.7/site-packages" in sys.path: sys.path.append("/usr/local/lib/python2.7/site-packages") if "/usr/lib64/python2.7/site-packages" in sys.path: sys.path.append("/usr/local/lib64/python2.7/site-packages") from core import pycore import ns.core import ns.network from core.api import coreapi from core.misc import ipaddr from corens3.obj import Ns3Session, Ns3WifiNet def add_to_server(session): ''' Add this session to the server's list if this script is executed from the core-daemon server. ''' global server try: server.addsession(session) return True except NameError: return False def wifisession(opt): ''' Run a random walk wifi session. ''' session = Ns3Session(persistent=True, duration=opt.duration) session.name = "ns3wifirandomwalk" session.filename = session.name + ".py" session.node_count = str(opt.numnodes + 1) add_to_server(session) wifi = session.addobj(cls=Ns3WifiNet, name="wlan1", rate="OfdmRate12Mbps") wifi.setposition(30, 30, 0) # for improved connectivity wifi.phy.Set("RxGain", ns.core.DoubleValue(18.0)) prefix = ipaddr.IPv4Prefix("10.0.0.0/16") services_str = "zebra|OSPFv3MDR|vtysh|IPForward" nodes = [] for i in xrange(1, opt.numnodes + 1): node = session.addnode(name = "n%d" % i) node.newnetif(wifi, ["%s/%s" % (prefix.addr(i), prefix.prefixlen)]) nodes.append(node) session.services.addservicestonode(node, "router", services_str, opt.verbose) session.services.bootnodeservices(node) session.setuprandomwalkmobility(bounds=(1000.0, 750.0, 0)) # PHY tracing #wifi.phy.EnableAsciiAll("ns3wifirandomwalk") # mobility tracing #session.setupmobilitytracing(wifi, "ns3wifirandomwalk.mob.tr", # nodes, verbose=True) session.startns3mobility(refresh_ms=150) # start simulation # session.instantiate() ? session.thread = session.run(vis=opt.viz) return session def main(): ''' Main routine when running from command-line. ''' usagestr = "usage: %prog [-h] [options] [args]" parser = optparse.OptionParser(usage = usagestr) parser.set_defaults(numnodes = 5, duration = 600, verbose = False, viz = False) opt = { 'numnodes' : 5, 'duration': 600, 'verbose' :False, 'viz': False } parser.add_option("-d", "--duration", dest = "duration", type = int, help = "number of seconds to run the simulation") parser.add_option("-n", "--numnodes", dest = "numnodes", type = int, help = "number of nodes") parser.add_option("-v", "--verbose", dest = "verbose", action = "store_true", help = "be more verbose") parser.add_option("-V", "--visualize", dest = "viz", action = "store_true", help = "enable PyViz ns-3 visualizer") def usage(msg = None, err = 0): sys.stdout.write("\n") if msg: sys.stdout.write(msg + "\n\n") parser.print_help() sys.exit(err) (opt, args) = parser.parse_args() if opt.numnodes < 2: usage("invalid numnodes: %s" % opt.numnodes) for a in args: sys.stderr.write("ignoring command line argument: '%s'\n" % a) return wifisession(opt) if __name__ == "__main__" or __name__ == "__builtin__": session = main() print "\nsession =", session core-4.8/daemon/ns3/examples/ns3wimax.py0000775000175000017500000000660512534327775015200 00000000000000#!/usr/bin/python -i # Copyright (c)2011-2012 the Boeing Company. # See the LICENSE file included in this distribution. # # author: Jeff Ahrenholz # ''' ns3wimax.py - This script demonstrates using CORE with the ns-3 Wimax model. *** Note that this script is not currently functional, see notes below. *** Current issues: - large amount of base station chatter; huge trace files, 70% CPU usage - PCAP files unreadable - base station causes segfault if it sends packet; due to missing service flows (but AddFlow() is not available for bs devices) - no packets are sent between nodes - no connection? ''' import os, sys, time, optparse, datetime, math try: from core import pycore except ImportError: # hack for Fedora autoconf that uses the following pythondir: if "/usr/lib/python2.6/site-packages" in sys.path: sys.path.append("/usr/local/lib/python2.6/site-packages") if "/usr/lib64/python2.6/site-packages" in sys.path: sys.path.append("/usr/local/lib64/python2.6/site-packages") if "/usr/lib/python2.7/site-packages" in sys.path: sys.path.append("/usr/local/lib/python2.7/site-packages") if "/usr/lib64/python2.7/site-packages" in sys.path: sys.path.append("/usr/local/lib64/python2.7/site-packages") from core import pycore from core.misc import ipaddr from corens3.obj import Ns3Session, Ns3WimaxNet def wimaxsession(opt): ''' Run a test wimax session. ''' session = Ns3Session(persistent=True, duration=opt.duration) wimax = session.addobj(cls=Ns3WimaxNet, name="wlan1") #wimax.wimax.EnableLogComponents() prefix = ipaddr.IPv4Prefix("10.0.0.0/16") # create one classifier for ICMP (protocol 1) traffic # src port low/high, dst port low/high, protocol, priority #classifier = (0, 65000, 0, 65000, 1, 1) classifier = (0, 65000, 0, 65000, 17, 1) nodes = [] for i in xrange(1, opt.numnodes + 1): node = session.addnode(name = "n%d" % i) if i == 1: wimax.setbasestation(node) node.newnetif(wimax, ["%s/%s" % (prefix.addr(i), prefix.prefixlen)]) if i > 2: wimax.addflow(nodes[-1], node, classifier, classifier) nodes.append(node) session.setupconstantmobility() session.thread = session.run(vis=False) return session def main(): ''' Main routine when running from command-line. ''' usagestr = "usage: %prog [-h] [options] [args]" parser = optparse.OptionParser(usage = usagestr) parser.set_defaults(numnodes = 3, duration = 600, verbose = False) parser.add_option("-d", "--duration", dest = "duration", type = int, help = "number of seconds to run the simulation") parser.add_option("-n", "--numnodes", dest = "numnodes", type = int, help = "number of nodes") parser.add_option("-v", "--verbose", dest = "verbose", action = "store_true", help = "be more verbose") def usage(msg = None, err = 0): sys.stdout.write("\n") if msg: sys.stdout.write(msg + "\n\n") parser.print_help() sys.exit(err) (opt, args) = parser.parse_args() if opt.numnodes < 2: usage("invalid numnodes: %s" % opt.numnodes) for a in args: sys.stderr.write("ignoring command line argument: '%s'\n" % a) return wimaxsession(opt) if __name__ == "__main__": session = main() core-4.8/daemon/ns3/Makefile.in0000664000175000017500000004106212534330000013244 00000000000000# Makefile.in generated by automake 1.13.4 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 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@ # CORE # (c)2012 the Boeing Company. # See the LICENSE file included in this directory. # # author: Jeff Ahrenholz # # Makefile for building corens3 components. # VPATH = @srcdir@ am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' 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 = : subdir = daemon/ns3 DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ $(dist_coreexample_SCRIPTS) ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } am__installdirs = "$(DESTDIR)$(coreexampledir)" SCRIPTS = $(dist_coreexample_SCRIPTS) $(noinst_SCRIPTS) 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 = SOURCES = DIST_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) DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ ARCH = @ARCH@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ BINDIR = @BINDIR@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ COREDPY_VERSION = @COREDPY_VERSION@ CORE_CONF_DIR = @CORE_CONF_DIR@ CORE_DATA_DIR = @CORE_DATA_DIR@ CORE_GUI_CONF_DIR = @CORE_GUI_CONF_DIR@ CORE_LIB_DIR = @CORE_LIB_DIR@ CORE_STATE_DIR = @CORE_STATE_DIR@ CORE_VERSION = @CORE_VERSION@ CORE_VERSION_DATE = @CORE_VERSION_DATE@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ GREP = @GREP@ HELP2MAN = @HELP2MAN@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LDFLAGS = @LDFLAGS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIB_DIR = @LIB_DIR@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ OBJEXT = @OBJEXT@ 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@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PYTHON = @PYTHON@ PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ PYTHON_PLATFORM = @PYTHON_PLATFORM@ PYTHON_PREFIX = @PYTHON_PREFIX@ PYTHON_VERSION = @PYTHON_VERSION@ RANLIB = @RANLIB@ SBINDIR = @SBINDIR@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_CC = @ac_ct_CC@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ brctl_path = @brctl_path@ build_alias = @build_alias@ builddir = @builddir@ convert = @convert@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ ebtables_path = @ebtables_path@ enable_daemon = @enable_daemon@ enable_gui = @enable_gui@ exec_prefix = @exec_prefix@ gmake = @gmake@ help2man = @help2man@ host_alias = @host_alias@ htmldir = @htmldir@ ifconfig_path = @ifconfig_path@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ ip_path = @ip_path@ libdir = @libdir@ libev_CFLAGS = @libev_CFLAGS@ libev_LIBS = @libev_LIBS@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ mount_path = @mount_path@ ngctl_path = @ngctl_path@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgpyexecdir = @pkgpyexecdir@ pkgpythondir = @pkgpythondir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ pyexecdir = @pyexecdir@ pyprefix = @pyprefix@ pythondir = @pythondir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ sysctl_path = @sysctl_path@ target_alias = @target_alias@ tc_path = @tc_path@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ umount_path = @umount_path@ vimage_path = @vimage_path@ with_startup = @with_startup@ SETUPPY = setup.py SETUPPYFLAGS = -v EXAMPLE_FILES = \ examples/ns3lte.py \ examples/ns3wifi.py \ examples/ns3wifirandomwalk.py \ examples/ns3wimax.py coreexampledir = $(datadir)/core/examples/corens3 dist_coreexample_SCRIPTS = $(EXAMPLE_FILES) # Python package build noinst_SCRIPTS = build DISTCLEANFILES = Makefile.in *.pyc corens3/*.pyc MANIFEST # files to include with distribution tarball EXTRA_DIST = LICENSE $(SETUPPY) corens3 all: all-am .SUFFIXES: $(srcdir)/Makefile.in: $(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 daemon/ns3/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign daemon/ns3/Makefile .PRECIOUS: 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: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): install-dist_coreexampleSCRIPTS: $(dist_coreexample_SCRIPTS) @$(NORMAL_INSTALL) @list='$(dist_coreexample_SCRIPTS)'; test -n "$(coreexampledir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(coreexampledir)'"; \ $(MKDIR_P) "$(DESTDIR)$(coreexampledir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ if test -f "$$d$$p"; then echo "$$d$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n' \ -e 'h;s|.*|.|' \ -e 'p;x;s,.*/,,;$(transform)' | sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1; } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) { files[d] = files[d] " " $$1; \ if (++n[d] == $(am__install_max)) { \ print "f", d, files[d]; n[d] = 0; files[d] = "" } } \ else { print "f", d "/" $$4, $$1 } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_SCRIPT) $$files '$(DESTDIR)$(coreexampledir)$$dir'"; \ $(INSTALL_SCRIPT) $$files "$(DESTDIR)$(coreexampledir)$$dir" || exit $$?; \ } \ ; done uninstall-dist_coreexampleSCRIPTS: @$(NORMAL_UNINSTALL) @list='$(dist_coreexample_SCRIPTS)'; test -n "$(coreexampledir)" || exit 0; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 's,.*/,,;$(transform)'`; \ dir='$(DESTDIR)$(coreexampledir)'; $(am__uninstall_files_from_dir) tags TAGS: ctags CTAGS: cscope cscopelist: 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 $(MAKE) $(AM_MAKEFLAGS) \ top_distdir="$(top_distdir)" distdir="$(distdir)" \ dist-hook check-am: all-am check: check-am all-am: Makefile $(SCRIPTS) installdirs: for dir in "$(DESTDIR)$(coreexampledir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done 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) -test -z "$(DISTCLEANFILES)" || rm -f $(DISTCLEANFILES) 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-local mostlyclean-am distclean: distclean-am -rm -f Makefile distclean-am: clean-am distclean-generic dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dist_coreexampleSCRIPTS install-dvi: install-dvi-am install-dvi-am: install-exec-am: @$(NORMAL_INSTALL) $(MAKE) $(AM_MAKEFLAGS) install-exec-hook 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 -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-generic pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-dist_coreexampleSCRIPTS @$(NORMAL_INSTALL) $(MAKE) $(AM_MAKEFLAGS) uninstall-hook .MAKE: install-am install-exec-am install-strip uninstall-am .PHONY: all all-am check check-am clean clean-generic clean-local \ cscopelist-am ctags-am dist-hook distclean distclean-generic \ distdir dvi dvi-am html html-am info info-am install \ install-am install-data install-data-am \ install-dist_coreexampleSCRIPTS install-dvi install-dvi-am \ install-exec install-exec-am install-exec-hook 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-generic pdf pdf-am ps ps-am tags-am uninstall \ uninstall-am uninstall-dist_coreexampleSCRIPTS uninstall-hook build: $(PYTHON) $(SETUPPY) $(SETUPPYFLAGS) build # Python package install install-exec-hook: $(PYTHON) $(SETUPPY) $(SETUPPYFLAGS) install --prefix=${DESTDIR}/${pyprefix} --install-purelib=${DESTDIR}/${pythondir} --install-platlib=${DESTDIR}/${pyexecdir} --no-compile # Python package uninstall uninstall-hook: rm -f ${pythondir}/corens3_python-${COREDPY_VERSION}-py${PYTHON_VERSION}.egg-info rm -rf ${pythondir}/corens3 rmdir -p $(coreexampledir) || true # Python package cleanup clean-local: -rm -rf build # Python RPM package rpm: $(PYTHON) $(SETUPPY) $(SETUPPYFLAGS) bdist_rpm # because we include entire directories with EXTRA_DIST, we need to clean up # the source control files dist-hook: rm -rf `find $(distdir)/ -name .svn` `find $(distdir)/ -name '*.pyc'` # 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: core-4.8/daemon/ns3/Makefile.am0000664000175000017500000000262512534327775013266 00000000000000# CORE # (c)2012 the Boeing Company. # See the LICENSE file included in this directory. # # author: Jeff Ahrenholz # # Makefile for building corens3 components. # SETUPPY = setup.py SETUPPYFLAGS = -v EXAMPLE_FILES = \ examples/ns3lte.py \ examples/ns3wifi.py \ examples/ns3wifirandomwalk.py \ examples/ns3wimax.py coreexampledir = $(datadir)/core/examples/corens3 dist_coreexample_SCRIPTS= $(EXAMPLE_FILES) # Python package build noinst_SCRIPTS = build build: $(PYTHON) $(SETUPPY) $(SETUPPYFLAGS) build # Python package install install-exec-hook: $(PYTHON) $(SETUPPY) $(SETUPPYFLAGS) install --prefix=${DESTDIR}/${pyprefix} --install-purelib=${DESTDIR}/${pythondir} --install-platlib=${DESTDIR}/${pyexecdir} --no-compile # Python package uninstall uninstall-hook: rm -f ${pythondir}/corens3_python-${COREDPY_VERSION}-py${PYTHON_VERSION}.egg-info rm -rf ${pythondir}/corens3 rmdir -p $(coreexampledir) || true # Python package cleanup clean-local: -rm -rf build # Python RPM package rpm: $(PYTHON) $(SETUPPY) $(SETUPPYFLAGS) bdist_rpm # because we include entire directories with EXTRA_DIST, we need to clean up # the source control files dist-hook: rm -rf `find $(distdir)/ -name .svn` `find $(distdir)/ -name '*.pyc'` DISTCLEANFILES = Makefile.in *.pyc corens3/*.pyc MANIFEST # files to include with distribution tarball EXTRA_DIST = LICENSE $(SETUPPY) corens3 core-4.8/daemon/ns3/LICENSE0000664000175000017500000004310312534327775012233 00000000000000 GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program 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 General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. core-4.8/daemon/ns3/setup.py0000664000175000017500000000121212534327775012733 00000000000000# Copyright (c)2012 the Boeing Company. # See the LICENSE file included in this directory. import os, glob from distutils.core import setup from corens3.constants import COREDPY_VERSION setup(name = "corens3-python", version = COREDPY_VERSION, packages = [ "corens3", ], description = "Python ns-3 components of CORE", url = "http://www.nrl.navy.mil/itd/ncs/products/core", author = "Boeing Research & Technology", author_email = "core-dev@pf.itd.nrl.navy.mil", license = "GPLv2", long_description="Python scripts and modules for building virtual " \ "simulated networks.") core-4.8/daemon/data/0000775000175000017500000000000012534330007011471 500000000000000core-4.8/daemon/data/core.conf0000664000175000017500000000476412534327775013245 00000000000000# Configuration file for CORE (core-gui, core-daemon) # ### GUI configuration options ### [core-gui] # no options are presently defined; see the ~/.core preferences file ### core-daemon configuration options ### [core-daemon] pidfile = /var/run/core-daemon.pid logfile = /var/log/core-daemon.log xmlfilever = 1.0 # you may want to change the listenaddr below to 0.0.0.0 listenaddr = localhost port = 4038 numthreads = 1 verbose = False quagga_bin_search = "/usr/local/bin /usr/bin /usr/lib/quagga" quagga_sbin_search = "/usr/local/sbin /usr/sbin /usr/lib/quagga" # uncomment the following line to load custom services from the specified dir # this may be a comma-separated list, and directory names should be unique # and not named 'services' #custom_services_dir = /home/username/.core/myservices # # uncomment to establish a standalone control backchannel for accessing nodes # (overriden by the session option of the same name) #controlnet = 172.16.0.0/24 # # # uncomment and edit to establish a distributed control backchannel #controlnet = core1:172.16.1.0/24 core2:172.16.2.0/24 core3:172.16.3.0/24 core4 :172.16.4.0/24 core5:172.16.5.0/24 # uncomment and edit to establish distributed auxiliary control channels. #controlnet1 = core1:172.17.1.0/24 core2:172.17.2.0/24 core3:172.17.3.0/24 core4 :172.17.4.0/24 core5:172.17.5.0/24 #controlnet2 = core1:172.18.1.0/24 core2:172.18.2.0/24 core3:172.18.3.0/24 core4 :172.18.4.0/24 core5:172.18.5.0/24 #controlnet3 = core1:172.19.1.0/24 core2:172.19.2.0/24 core3:172.19.3.0/24 core4 :172.19.4.0/24 core5:172.19.5.0/24 # uncomment and edit to assign host interfaces to auxilary control channels # for use in connecting with other servers in a distributed environments. # Note: This is valid for auxiliary control channels only. The primary control # channel, specified by 'controlnet', is tunneled across servers. #controlnetif1 = eth2 #controlnetif2 = eth3 #controlnetif3 = eth4 # optional controlnet configuration script for controlnet, uncomment to # activate, and likely edit the script. # Note: the controlnet_updown_script is not used by the auxiliary control # channels. # controlnet_updown_script = /usr/local/share/core/examples/controlnet_updown # publish nodes' control IP addresses to /etc/hosts #update_etc_hosts = True # EMANE configuration emane_platform_port = 8101 emane_transform_port = 8201 emane_event_monitor = False emane_models = RfPipe, Ieee80211abg, CommEffect, Bypass # EMANE log level range [0,4] default: 2 #emane_log_level = 2 emane_realtime = True core-4.8/daemon/data/xen.conf0000664000175000017500000000304112534327775013072 00000000000000# Configuration file for CORE Xen support ### Xen configuration options ### [xen] ### The following three configuration options *must* be specified in this ### system-wide configuration file. # LVM volume group name for creating new volumes vg_name = domU # directory containing an RSA SSH host key and authorized_keys file to use # within the VM ssh_key_path = /opt/core-xen/ssh # extra arguments to pass via 'extra=' option to 'xm create' xm_create_extra = console=hvc0 rtr_boot=/dev/xvda rtr_boot_fstype=iso9660 rtr_root=/boot/root.img rtr_persist=LABEL=persist rtr_swap=LABEL=swap rtr_overlay_limit=500 ### The remaining configuration options *may* be specified here. ### If not specified here, they *must* be specified in the user (or scenario's) ### nodes.conf file as profile-specific configuration options. # domU RAM memory size in MB ram_size = 256 # domU disk size in MB disk_size = 256M # ISO filesystem to mount as read-only iso_file = /opt/core-xen/iso-files/rtr.iso # directory used temporarily as moint point for persistent area, under # /tmp/pycore.nnnnn/nX.conf/ mount_path = /rtr/persist # mount_path + this directory where configuration files are located on the VM etc_path = config/etc # name of tar file within the iso_file to unpack to mount_path persist_tar_iso = persist-template.tar # name of tar file in dom0 that will be unpacked to mount_path prior to boot # the string '%h' will be replaced with the hostname (e.g. 'n3' for node 3) persist_tar = /opt/core-xen/rtr-configs/custom-%%h.tar # root password to set root_password = password core-4.8/daemon/examples/0000775000175000017500000000000012534330007012376 500000000000000core-4.8/daemon/examples/myservices/0000775000175000017500000000000012534330007014567 500000000000000core-4.8/daemon/examples/myservices/README.txt0000664000175000017500000000235712534327775016236 00000000000000This directory contains a sample custom service that you can use as a template for creating your own services. Follow these steps to add your own services: 1. Modify the sample service MyService to do what you want. It could generate config/script files, mount per-node directories, start processes/scripts, etc. sample.py is a Python file that defines one or more classes to be imported. You can create multiple Python files that will be imported. Add any new filenames to the __init__.py file. 2. Put these files in a directory such as /home/username/.core/myservices Note that the last component of this directory name 'myservices' should not be named something like 'services' which conflicts with an existing Python name (the syntax 'from myservices import *' is used). 3. Add a 'custom_services_dir = /home/username/.core/myservices' entry to the /etc/core/core.conf file. 4. Restart the CORE daemon (core-daemon). Any import errors (Python syntax) should be displayed in the /var/log/core-daemon.log log file (or on screen). 5. Start using your custom service on your nodes. You can create a new node type that uses your service, or change the default services for an existing node type, or change individual nodes. core-4.8/daemon/examples/myservices/__init__.py0000664000175000017500000000040112534327775016635 00000000000000"""myservices Custom services that you define can be put in this directory. Everything listed in __all__ is automatically loaded when you add this directory to the custom_services_dir = '/full/path/to/here' core.conf file option. """ __all__ = ["sample"] core-4.8/daemon/examples/myservices/sample.py0000664000175000017500000000373212534327775016371 00000000000000# # CORE # Copyright (c)2010-2012 the Boeing Company. # See the LICENSE file included in this distribution. # ''' Sample user-defined service. ''' import os from core.service import CoreService, addservice from core.misc.ipaddr import IPv4Prefix, IPv6Prefix class MyService(CoreService): ''' This is a sample user-defined service. ''' # a unique name is required, without spaces _name = "MyService" # you can create your own group here _group = "Utility" # list of other services this service depends on _depends = () # per-node directories _dirs = () # generated files (without a full path this file goes in the node's dir, # e.g. /tmp/pycore.12345/n1.conf/) _configs = ('myservice.sh', ) # this controls the starting order vs other enabled services _startindex = 50 # list of startup commands, also may be generated during startup _startup = ('sh myservice.sh',) # list of shutdown commands _shutdown = () @classmethod def generateconfig(cls, node, filename, services): ''' Return a string that will be written to filename, or sent to the GUI for user customization. ''' cfg = "#!/bin/sh\n" cfg += "# auto-generated by MyService (sample.py)\n" for ifc in node.netifs(): cfg += 'echo "Node %s has interface %s"\n' % (node.name, ifc.name) # here we do something interesting cfg += "\n".join(map(cls.subnetentry, ifc.addrlist)) break return cfg @staticmethod def subnetentry(x): ''' Generate a subnet declaration block given an IPv4 prefix string for inclusion in the config file. ''' if x.find(":") >= 0: # this is an IPv6 address return "" else: net = IPv4Prefix(x) return 'echo " network %s"' % (net) # this line is required to add the above class to the list of available services addservice(MyService) core-4.8/daemon/examples/netns/0000775000175000017500000000000012534330007013525 500000000000000core-4.8/daemon/examples/netns/basicrange.py0000775000175000017500000000627312534327775016152 00000000000000#!/usr/bin/python # # Copyright (c)2011-2012 the Boeing Company. # See the LICENSE file included in this distribution. # # Test 3D range calculation of the BasicRangeModel by adding n nodes to a WLAN # stacked 100 units above each other (using z-axis). # import optparse, sys, os, datetime, time from core import pycore from core.misc import ipaddr from core.misc.utils import mutecall from core.mobility import BasicRangeModel from core.netns.vnet import EbtablesQueue # node list - global so you can play using 'python -i' # e.g. >>> n[0].session.shutdown() n = [] def test(options): prefix = ipaddr.IPv4Prefix("10.83.0.0/16") session = pycore.Session(persistent = True) if options.enablesdt: session.location.setrefgeo(47.57917,-122.13232,50.0) # GUI default session.location.refscale = 100.0 session.options.enablesdt = True session.options.sdturl = options.sdturl wlanid = options.numnodes + 1 net = session.addobj(cls = pycore.nodes.WlanNode, name = "wlan%d" % wlanid, objid = wlanid, verbose = True) values = list(BasicRangeModel.getdefaultvalues()) #values[0] = 5000000 # 5000km range net.setmodel(BasicRangeModel, values) for i in xrange(1, options.numnodes + 1): tmp = session.addobj(cls = pycore.nodes.LxcNode, name = "n%d" % i, objid = i) tmp.newnetif(net, ["%s/%s" % (prefix.addr(i), prefix.prefixlen)]) # set increasing Z coordinates tmp.setposition(10, 10, 100*i) n.append(tmp) # example setting node n2 to a high altitude #n[1].setposition(10, 10, 2000000) # 2000km #session.sdt.updatenode(n[1].objid, 0, 10, 10, 2000000) n[0].term("bash") # wait for rate seconds to allow ebtables commands to commit time.sleep(EbtablesQueue.rate) #session.shutdown() def main(): usagestr = "usage: %prog [-h] [options] [args]" parser = optparse.OptionParser(usage = usagestr) parser.set_defaults(numnodes = 2, enablesdt = False, sdturl = "tcp://127.0.0.1:50000/") parser.add_option("-n", "--numnodes", dest = "numnodes", type = int, help = "number of nodes to test; default = %s" % parser.defaults["numnodes"]) parser.add_option("-s", "--sdt", dest = "enablesdt", action = "store_true", help = "enable SDT output") parser.add_option("-u", "--sdturl", dest = "sdturl", type = "string", help = "URL for SDT connection, default = %s" % \ parser.defaults["sdturl"]) def usage(msg = None, err = 0): sys.stdout.write("\n") if msg: sys.stdout.write(msg + "\n\n") parser.print_help() sys.exit(err) # parse command line options (options, args) = parser.parse_args() if options.numnodes < 2: usage("invalid number of nodes: %s" % options.numnodes) for a in args: sys.stderr.write("ignoring command line argument: '%s'\n" % a) start = datetime.datetime.now() test(options) print >> sys.stderr, \ "elapsed time: %s" % (datetime.datetime.now() - start) if __name__ == "__main__": main() core-4.8/daemon/examples/netns/distributed.py0000775000175000017500000001241712534327775016373 00000000000000#!/usr/bin/python -i # Copyright (c)2010-2013 the Boeing Company. # See the LICENSE file included in this distribution. # A distributed example where CORE API messaging is used to create a session # distributed across the local server and one slave server. The slave server # must be specified using the '-s ' parameter, and needs to be # running the daemon with listenaddr=0.0.0.0 in the core.conf file. # import sys, datetime, optparse, time from core import pycore from core.misc import ipaddr from core.constants import * from core.api import coreapi # declare classes for use with Broker coreapi.add_node_class("CORE_NODE_DEF", coreapi.CORE_NODE_DEF, pycore.nodes.CoreNode) coreapi.add_node_class("CORE_NODE_SWITCH", coreapi.CORE_NODE_SWITCH, pycore.nodes.SwitchNode) # node list (count from 1) n = [None] def main(): usagestr = "usage: %prog [-h] [options] [args]" parser = optparse.OptionParser(usage = usagestr) parser.set_defaults(numnodes = 5, slave = None) parser.add_option("-n", "--numnodes", dest = "numnodes", type = int, help = "number of nodes") parser.add_option("-s", "--slave-server", dest = "slave", type = str, help = "slave server IP address") def usage(msg = None, err = 0): sys.stdout.write("\n") if msg: sys.stdout.write(msg + "\n\n") parser.print_help() sys.exit(err) # parse command line options (options, args) = parser.parse_args() if options.numnodes < 1: usage("invalid number of nodes: %s" % options.numnodes) if not options.slave: usage("slave server IP address (-s) is a required argument") for a in args: sys.stderr.write("ignoring command line argument: '%s'\n" % a) start = datetime.datetime.now() prefix = ipaddr.IPv4Prefix("10.83.0.0/16") session = pycore.Session(persistent=True) if 'server' in globals(): server.addsession(session) # distributed setup - connect to slave server slaveport = options.slave.split(':') slave = slaveport[0] if len(slaveport) > 1: port = slaveport[1] else: port = coreapi.CORE_API_PORT print "connecting to slave at %s:%d" % (slave, port) session.broker.addserver(slave, slave, port) session.broker.setupserver(slave) session.setstate(coreapi.CORE_EVENT_CONFIGURATION_STATE) tlvdata = coreapi.CoreEventTlv.pack(coreapi.CORE_TLV_EVENT_TYPE, coreapi.CORE_EVENT_CONFIGURATION_STATE) session.broker.handlerawmsg(coreapi.CoreEventMessage.pack(0, tlvdata)) switch = session.addobj(cls = pycore.nodes.SwitchNode, name = "switch") switch.setposition(x=80,y=50) num_local = options.numnodes / 2 num_remote = options.numnodes / 2 + options.numnodes % 2 print "creating %d (%d local / %d remote) nodes with addresses from %s" % \ (options.numnodes, num_local, num_remote, prefix) for i in xrange(1, num_local + 1): tmp = session.addobj(cls = pycore.nodes.CoreNode, name = "n%d" % i, objid=i) tmp.newnetif(switch, ["%s/%s" % (prefix.addr(i), prefix.prefixlen)]) tmp.cmd([SYSCTL_BIN, "net.ipv4.icmp_echo_ignore_broadcasts=0"]) tmp.setposition(x=150*i,y=150) n.append(tmp) flags = coreapi.CORE_API_ADD_FLAG session.broker.handlerawmsg(switch.tonodemsg(flags=flags)) # create remote nodes via API for i in xrange(num_local + 1, options.numnodes + 1): tmp = pycore.nodes.CoreNode(session = session, objid = i, name = "n%d" % i, start=False) tmp.setposition(x=150*i,y=150) tmp.server = slave session.broker.handlerawmsg(tmp.tonodemsg(flags=flags)) # create remote links via API for i in xrange(num_local + 1, options.numnodes + 1): tlvdata = coreapi.CoreLinkTlv.pack(coreapi.CORE_TLV_LINK_N1NUMBER, switch.objid) tlvdata += coreapi.CoreLinkTlv.pack(coreapi.CORE_TLV_LINK_N2NUMBER, i) tlvdata += coreapi.CoreLinkTlv.pack(coreapi.CORE_TLV_LINK_TYPE, coreapi.CORE_LINK_WIRED) tlvdata += coreapi.CoreLinkTlv.pack(coreapi.CORE_TLV_LINK_IF2NUM, 0) tlvdata += coreapi.CoreLinkTlv.pack(coreapi.CORE_TLV_LINK_IF2IP4, prefix.addr(i)) tlvdata += coreapi.CoreLinkTlv.pack(coreapi.CORE_TLV_LINK_IF2IP4MASK, prefix.prefixlen) msg = coreapi.CoreLinkMessage.pack(flags, tlvdata) session.broker.handlerawmsg(msg) session.instantiate() tlvdata = coreapi.CoreEventTlv.pack(coreapi.CORE_TLV_EVENT_TYPE, coreapi.CORE_EVENT_INSTANTIATION_STATE) msg = coreapi.CoreEventMessage.pack(0, tlvdata) session.broker.handlerawmsg(msg) # start a shell on node 1 n[1].term("bash") # TODO: access to remote nodes is currently limited in this script print "elapsed time: %s" % (datetime.datetime.now() - start) print "To stop this session, use the 'core-cleanup' script on this server" print "and on the remote slave server." if __name__ == "__main__" or __name__ == "__builtin__": main() core-4.8/daemon/examples/netns/emane80211.py0000775000175000017500000000612712534327775015533 00000000000000#!/usr/bin/python -i # Copyright (c)2010-2014 the Boeing Company. # See the LICENSE file included in this distribution. # Example CORE Python script that attaches N nodes to an EMANE 802.11abg # network. One of the parameters is changed, the pathloss mode. import sys, datetime, optparse from core import pycore from core.misc import ipaddr from core.constants import * from core.emane.ieee80211abg import EmaneIeee80211abgModel # node list (count from 1) n = [None] def main(): usagestr = "usage: %prog [-h] [options] [args]" parser = optparse.OptionParser(usage = usagestr) parser.set_defaults(numnodes = 5) parser.add_option("-n", "--numnodes", dest = "numnodes", type = int, help = "number of nodes") def usage(msg = None, err = 0): sys.stdout.write("\n") if msg: sys.stdout.write(msg + "\n\n") parser.print_help() sys.exit(err) # parse command line options (options, args) = parser.parse_args() if options.numnodes < 1: usage("invalid number of nodes: %s" % options.numnodes) for a in args: sys.stderr.write("ignoring command line argument: '%s'\n" % a) start = datetime.datetime.now() # IP subnet prefix = ipaddr.IPv4Prefix("10.83.0.0/16") # session with some EMANE initialization cfg = {'verbose': 'false'} session = pycore.Session(cfg = cfg, persistent = True) session.master = True session.location.setrefgeo(47.57917,-122.13232,2.00000) session.location.refscale = 150.0 session.cfg['emane_models'] = "RfPipe, Ieee80211abg, Bypass" session.emane.loadmodels() if 'server' in globals(): server.addsession(session) # EMANE WLAN print "creating EMANE WLAN wlan1" wlan = session.addobj(cls = pycore.nodes.EmaneNode, name = "wlan1") wlan.setposition(x=80,y=50) names = EmaneIeee80211abgModel.getnames() values = list(EmaneIeee80211abgModel.getdefaultvalues()) # TODO: change any of the EMANE 802.11 parameter values here try: values[ names.index('pathlossmode') ] = '2ray' except ValueError: values[ names.index('propagationmodel') ] = '2ray' session.emane.setconfig(wlan.objid, EmaneIeee80211abgModel._name, values) services_str = "zebra|OSPFv3MDR|vtysh|IPForward" print "creating %d nodes with addresses from %s" % \ (options.numnodes, prefix) for i in xrange(1, options.numnodes + 1): tmp = session.addobj(cls = pycore.nodes.CoreNode, name = "n%d" % i, objid=i) tmp.newnetif(wlan, ["%s/%s" % (prefix.addr(i), prefix.prefixlen)]) tmp.cmd([SYSCTL_BIN, "net.ipv4.icmp_echo_ignore_broadcasts=0"]) tmp.setposition(x=150*i,y=150) session.services.addservicestonode(tmp, "", services_str, verbose=False) n.append(tmp) # this starts EMANE, etc. session.node_count = str(options.numnodes + 1) session.instantiate() # start a shell on node 1 n[1].term("bash") print "elapsed time: %s" % (datetime.datetime.now() - start) if __name__ == "__main__" or __name__ == "__builtin__": main() core-4.8/daemon/examples/netns/howmanynodes.py0000775000175000017500000001764312534327775016572 00000000000000#!/usr/bin/python # Copyright (c)2010-2012 the Boeing Company. # See the LICENSE file included in this distribution. # # author: Jeff Ahrenholz # ''' howmanynodes.py - This is a CORE script that creates network namespace nodes having one virtual Ethernet interface connected to a bridge. It continues to add nodes until an exception occurs. The number of nodes per bridge can be specified. ''' import optparse, sys, os, datetime, time, shutil try: from core import pycore except ImportError: # hack for Fedora autoconf that uses the following pythondir: if "/usr/lib/python2.6/site-packages" in sys.path: sys.path.append("/usr/local/lib/python2.6/site-packages") if "/usr/lib64/python2.6/site-packages" in sys.path: sys.path.append("/usr/local/lib64/python2.6/site-packages") if "/usr/lib/python2.7/site-packages" in sys.path: sys.path.append("/usr/local/lib/python2.7/site-packages") if "/usr/lib64/python2.7/site-packages" in sys.path: sys.path.append("/usr/local/lib64/python2.7/site-packages") from core import pycore from core.misc import ipaddr from core.constants import * GBD = 1024.0 * 1024.0 def linuxversion(): ''' Return a string having the Linux kernel version. ''' f = open('/proc/version', 'r') v = f.readline().split() version_str = ' '.join(v[:3]) f.close() return version_str MEMKEYS = ('total', 'free', 'buff', 'cached', 'stotal', 'sfree') def memfree(): ''' Returns kilobytes memory [total, free, buff, cached, stotal, sfree]. useful stats are: free memory = free + buff + cached swap used = stotal - sfree ''' f = open('/proc/meminfo', 'r') lines = f.readlines() f.close() kbs = {} for k in MEMKEYS: kbs[k] = 0 for l in lines: if l[:9] == "MemTotal:": kbs['total'] = int(l.split()[1]) elif l[:8] == "MemFree:": kbs['free'] = int(l.split()[1]) elif l[:8] == "Buffers:": kbs['buff'] = int(l.split()[1]) elif l[:8] == "Cached:": kbs['cache'] = int(l.split()[1]) elif l[:10] == "SwapTotal:": kbs['stotal'] = int(l.split()[1]) elif l[:9] == "SwapFree:": kbs['sfree'] = int(l.split()[1]) break return kbs # node list (count from 1) nodelist = [None] switchlist = [] def main(): usagestr = "usage: %prog [-h] [options] [args]" parser = optparse.OptionParser(usage = usagestr) parser.set_defaults(waittime = 0.2, numnodes = 0, bridges = 0, retries = 0, logfile = None, services = None) parser.add_option("-w", "--waittime", dest = "waittime", type = float, help = "number of seconds to wait between node creation" \ " (default = %s)" % parser.defaults["waittime"]) parser.add_option("-n", "--numnodes", dest = "numnodes", type = int, help = "number of nodes (default = unlimited)") parser.add_option("-b", "--bridges", dest = "bridges", type = int, help = "number of nodes per bridge; 0 = one bridge " \ "(def. = %s)" % parser.defaults["bridges"]) parser.add_option("-r", "--retry", dest = "retries", type = int, help = "number of retries on error (default = %s)" % \ parser.defaults["retries"]) parser.add_option("-l", "--log", dest = "logfile", type = str, help = "log memory usage to this file (default = %s)" % \ parser.defaults["logfile"]) parser.add_option("-s", "--services", dest = "services", type = str, help = "pipe-delimited list of services added to each " \ "node (default = %s)\n(Example: 'zebra|OSPFv2|OSPFv3|" \ "vtysh|IPForward')" % parser.defaults["services"]) def usage(msg = None, err = 0): sys.stdout.write("\n") if msg: sys.stdout.write(msg + "\n\n") parser.print_help() sys.exit(err) (options, args) = parser.parse_args() for a in args: sys.stderr.write("ignoring command line argument: '%s'\n" % a) start = datetime.datetime.now() prefix = ipaddr.IPv4Prefix("10.83.0.0/16") print "Testing how many network namespace nodes this machine can create." print " - %s" % linuxversion() mem = memfree() print " - %.02f GB total memory (%.02f GB swap)" % \ (mem['total']/GBD, mem['stotal']/GBD) print " - using IPv4 network prefix %s" % prefix print " - using wait time of %s" % options.waittime print " - using %d nodes per bridge" % options.bridges print " - will retry %d times on failure" % options.retries print " - adding these services to each node: %s" % options.services print " " lfp = None if options.logfile is not None: # initialize a csv log file header lfp = open(options.logfile, "a") lfp.write("# log from howmanynodes.py %s\n" % time.ctime()) lfp.write("# options = %s\n#\n" % options) lfp.write("# numnodes,%s\n" % ','.join(MEMKEYS)) lfp.flush() session = pycore.Session(persistent=True) switch = session.addobj(cls = pycore.nodes.SwitchNode) switchlist.append(switch) print "Added bridge %s (%d)." % (switch.brname, len(switchlist)) i = 0 retry_count = options.retries while True: i += 1 # optionally add a bridge (options.bridges nodes per bridge) try: if options.bridges > 0 and switch.numnetif() >= options.bridges: switch = session.addobj(cls = pycore.nodes.SwitchNode) switchlist.append(switch) print "\nAdded bridge %s (%d) for node %d." % \ (switch.brname, len(switchlist), i) except Exception, e: print "At %d bridges (%d nodes) caught exception:\n%s\n" % \ (len(switchlist), i-1, e) break # create a node try: n = session.addobj(cls = pycore.nodes.LxcNode, name = "n%d" % i) n.newnetif(switch, ["%s/%s" % (prefix.addr(i), prefix.prefixlen)]) n.cmd([SYSCTL_BIN, "net.ipv4.icmp_echo_ignore_broadcasts=0"]) if options.services is not None: session.services.addservicestonode(n, "", options.services, verbose=False) n.boot() nodelist.append(n) if i % 25 == 0: print "\n%s nodes created " % i, mem = memfree() free = mem['free'] + mem['buff'] + mem['cached'] swap = mem['stotal'] - mem['sfree'] print "(%.02f/%.02f GB free/swap)" % (free/GBD , swap/GBD), if lfp: lfp.write("%d," % i) lfp.write("%s\n" % ','.join(str(mem[x]) for x in MEMKEYS)) lfp.flush() else: sys.stdout.write(".") sys.stdout.flush() time.sleep(options.waittime) except Exception, e: print "At %d nodes caught exception:\n" % i, e if retry_count > 0: print "\nWill retry creating node %d." % i shutil.rmtree(n.nodedir, ignore_errors = True) retry_count -= 1 i -= 1 time.sleep(options.waittime) continue else: print "Stopping at %d nodes!" % i break if i == options.numnodes: print "Stopping at %d nodes due to numnodes option." % i break # node creation was successful at this point retry_count = options.retries if lfp: lfp.flush() lfp.close() print "elapsed time: %s" % (datetime.datetime.now() - start) print "Use the core-cleanup script to remove nodes and bridges." if __name__ == "__main__": main() core-4.8/daemon/examples/netns/iperf-performance-chain.py0000775000175000017500000000617412534327775020540 00000000000000#!/usr/bin/python # Copyright (c)2013 the Boeing Company. # See the LICENSE file included in this distribution. # This script creates a CORE session, that will connect n nodes together # in a chain, with static routes between nodes # number of nodes / number of hops # 2 0 # 3 1 # 4 2 # n n - 2 # # Use core-cleanup to clean up after this script as the session is left running. # import sys, datetime, optparse from core import pycore from core.misc import ipaddr from core.constants import * # node list (count from 1) n = [None] def main(): usagestr = "usage: %prog [-h] [options] [args]" parser = optparse.OptionParser(usage = usagestr) parser.set_defaults(numnodes = 5) parser.add_option("-n", "--numnodes", dest = "numnodes", type = int, help = "number of nodes") def usage(msg = None, err = 0): sys.stdout.write("\n") if msg: sys.stdout.write(msg + "\n\n") parser.print_help() sys.exit(err) # parse command line options (options, args) = parser.parse_args() if options.numnodes < 1: usage("invalid number of nodes: %s" % options.numnodes) if options.numnodes >= 255: usage("invalid number of nodes: %s" % options.numnodes) for a in args: sys.stderr.write("ignoring command line argument: '%s'\n" % a) start = datetime.datetime.now() session = pycore.Session(persistent=True) if 'server' in globals(): server.addsession(session) print "creating %d nodes" % options.numnodes left = None prefix = None for i in xrange(1, options.numnodes + 1): tmp = session.addobj(cls = pycore.nodes.CoreNode, name = "n%d" % i, objid=i) if left: tmp.newnetif(left, ["%s/%s" % (prefix.addr(2), prefix.prefixlen)]) prefix = ipaddr.IPv4Prefix("10.83.%d.0/24" % i) # limit: i < 255 right = session.addobj(cls = pycore.nodes.PtpNet) tmp.newnetif(right, ["%s/%s" % (prefix.addr(1), prefix.prefixlen)]) tmp.cmd([SYSCTL_BIN, "net.ipv4.icmp_echo_ignore_broadcasts=0"]) tmp.cmd([SYSCTL_BIN, "net.ipv4.conf.all.forwarding=1"]) tmp.cmd([SYSCTL_BIN, "net.ipv4.conf.default.rp_filter=0"]) tmp.setposition(x=100*i,y=150) n.append(tmp) left = right prefixes = map(lambda(x): ipaddr.IPv4Prefix("10.83.%d.0/24" % x), xrange(1, options.numnodes + 1)) # set up static routing in the chain for i in xrange(1, options.numnodes + 1): for j in xrange(1, options.numnodes + 1): if j < i - 1: gw = prefixes[i-2].addr(1) elif j > i: if i > len(prefixes) - 1: continue gw = prefixes[i-1].addr(2) else: continue net = prefixes[j-1] n[i].cmd([IP_BIN, "route", "add", str(net), "via", str(gw)]) print "elapsed time: %s" % (datetime.datetime.now() - start) if __name__ == "__main__" or __name__ == "__builtin__": main() core-4.8/daemon/examples/netns/iperf-performance.sh0000775000175000017500000001564612534327775017446 00000000000000#!/bin/sh -e # # iperf-performance.sh # # (c)2013 the Boeing Company # authors: Jeff Ahrenholz # # Utility script to automate several iperf runs. # # number of iperf runs per test NUMRUNS=10 # number of seconds per run (10s is iperf default) RUNTIME=10 # logging LOG=/tmp/${0}.log STAMP=`date +%Y%m%d%H%M%S` # # client---(loopback)---server # loopbacktest () { killall iperf 2> /dev/null || true echo ">> loopback iperf test" echo "loopback" > ${LOG} # start an iperf server in the background # -s = server # -y c = CSV output echo "starting local iperf server" iperf -s -y c >> ${LOG} & # run an iperf client NUMRUNS times i=1 while [ $i -le $NUMRUNS ]; do echo "run $i/$NUMRUNS:" iperf -t ${RUNTIME} -c localhost sleep 0.3 i=$((i+1)) done sleep 1 echo "stopping local iperf server" killall -v iperf } # # lxc1( client )---veth-pair---lxc2( server ) # lxcvethtest () { SERVERIP=10.0.0.1 CLIENTIP=10.0.0.2 SERVER=/tmp/${0}-server CLIENT=/tmp/${0}-client echo ">> lxc veth iperf test" echo "lxcveth" >> ${LOG} echo "starting lxc iperf server" vnoded -l $SERVER.log -p $SERVER.pid -c $SERVER ip link add name veth0.1 type veth peer name veth0 ip link set veth0 netns `cat $SERVER.pid` up vcmd -c $SERVER -- ip link set lo up vcmd -c $SERVER -- ip addr add $SERVERIP/24 dev veth0 vcmd -c $SERVER -- iperf -s -y c >> ${LOG} & echo "starting lxc iperf client" vnoded -l $CLIENT.log -p $CLIENT.pid -c $CLIENT ip link set veth0.1 netns `cat $CLIENT.pid` up vcmd -c $CLIENT -- ip link set lo up vcmd -c $CLIENT -- ip addr add $CLIENTIP/24 dev veth0.1 i=1 while [ $i -le $NUMRUNS ]; do echo "run $i/$NUMRUNS:" vcmd -c $CLIENT -- iperf -t ${RUNTIME} -c ${SERVERIP} sleep 0.3 i=$((i+1)) done sleep 1 echo "stopping lxc iperf server" vcmd -c $SERVER -- killall -v iperf echo "stopping containers" kill -9 `cat $SERVER.pid` kill -9 `cat $CLIENT.pid` echo "cleaning up" rm -f ${SERVER}* rm -f ${CLIENT}* } # # lxc1( client veth:):veth---bridge---veth:(:veth server )lxc2 # lxcbrtest () { SERVERIP=10.0.0.1 CLIENTIP=10.0.0.2 SERVER=/tmp/${0}-server CLIENT=/tmp/${0}-client BRIDGE="lxcbrtest" echo ">> lxc bridge iperf test" echo "lxcbr" >> ${LOG} echo "building bridge" brctl addbr $BRIDGE brctl stp $BRIDGE off # disable spanning tree protocol brctl setfd $BRIDGE 0 # disable forwarding delay ip link set $BRIDGE up echo "starting lxc iperf server" vnoded -l $SERVER.log -p $SERVER.pid -c $SERVER ip link add name veth0.1 type veth peer name veth0 ip link set veth0 netns `cat $SERVER.pid` up vcmd -c $SERVER -- ip link set lo up vcmd -c $SERVER -- ip addr add $SERVERIP/24 dev veth0 brctl addif $BRIDGE veth0.1 ip link set veth0.1 up vcmd -c $SERVER -- iperf -s -y c >> ${LOG} & echo "starting lxc iperf client" vnoded -l $CLIENT.log -p $CLIENT.pid -c $CLIENT ip link add name veth1.1 type veth peer name veth1 ip link set veth1 netns `cat $CLIENT.pid` up vcmd -c $CLIENT -- ip link set lo up vcmd -c $CLIENT -- ip addr add $CLIENTIP/24 dev veth1 brctl addif $BRIDGE veth1.1 ip link set veth1.1 up i=1 while [ $i -le $NUMRUNS ]; do echo "run $i/$NUMRUNS:" vcmd -c $CLIENT -- iperf -t ${RUNTIME} -c ${SERVERIP} sleep 0.3 i=$((i+1)) done sleep 1 echo "stopping lxc iperf server" vcmd -c $SERVER -- killall -v iperf echo "stopping containers" kill -9 `cat $SERVER.pid` kill -9 `cat $CLIENT.pid` echo "cleaning up" ip link set $BRIDGE down brctl delbr $BRIDGE rm -f ${SERVER}* rm -f ${CLIENT}* } # # n1---n2---n3--- ... ---nN # N nodes (N-2 hops) in chain with static routing # chaintest () { NUMNODES=$1 SERVERIP=10.83.$NUMNODES.1 if [ -d /tmp/pycore.* ]; then echo "/tmp/pycore.* already exists, skipping chaintest $NUMNODES" return fi echo ">> n=$NUMNODES node chain iperf test" echo "chain$NUMNODES" >> ${LOG} echo "running external chain CORE script with '-n $NUMNODES'" python iperf-performance-chain.py -n $NUMNODES echo "starting lxc iperf server on node $NUMNODES" vcmd -c /tmp/pycore.*/n$NUMNODES -- iperf -s -y c >> ${LOG} & echo "starting lxc iperf client" i=1 while [ $i -le $NUMRUNS ]; do echo "run $i/$NUMRUNS:" vcmd -c /tmp/pycore.*/n1 -- iperf -t ${RUNTIME} -c ${SERVERIP} sleep 0.3 i=$((i+1)) done sleep 1 echo "stopping lxc iperf server" vcmd -c /tmp/pycore.*/n$NUMNODES -- killall -v iperf echo "cleaning up" core-cleanup } if [ "z$1" != "z" ]; then echo "This script takes no parameters and must be run as root." exit 1 fi if [ `id -u` != 0 ]; then echo "This script must be run as root." exit 1 fi # # N lxc clients >---bridge---veth:(:veth server ) # clientstest () { NUMCLIENTS=$1 SERVERIP=10.0.0.1 SERVER=/tmp/${0}-server BRIDGE="lxcbrtest" echo ">> n=$NUMCLIENTS clients iperf test" echo "clients$NUMCLIENTS" >> ${LOG} echo "building bridge" brctl addbr $BRIDGE brctl stp $BRIDGE off # disable spanning tree protocol brctl setfd $BRIDGE 0 # disable forwarding delay ip link set $BRIDGE up echo "starting lxc iperf server" vnoded -l $SERVER.log -p $SERVER.pid -c $SERVER ip link add name veth0.1 type veth peer name veth0 ip link set veth0 netns `cat $SERVER.pid` up vcmd -c $SERVER -- ip link set lo up vcmd -c $SERVER -- ip addr add $SERVERIP/24 dev veth0 brctl addif $BRIDGE veth0.1 ip link set veth0.1 up vcmd -c $SERVER -- iperf -s -y c >> ${LOG} & i=1 CLIENTS="" while [ $i -le $NUMCLIENTS ]; do echo "starting lxc iperf client $i/$NUMCLIENTS" CLIENT=/tmp/${0}-client$i CLIENTIP=10.0.0.1$i vnoded -l $CLIENT.log -p $CLIENT.pid -c $CLIENT ip link add name veth1.$i type veth peer name veth1 ip link set veth1 netns `cat $CLIENT.pid` up vcmd -c $CLIENT -- ip link set lo up vcmd -c $CLIENT -- ip addr add $CLIENTIP/24 dev veth1 brctl addif $BRIDGE veth1.$i ip link set veth1.$i up i=$((i+1)) CLIENTS="$CLIENTS $CLIENT" done j=1 while [ $j -le $NUMRUNS ]; do echo "run $j/$NUMRUNS iperf:" for CLIENT in $CLIENTS; do vcmd -c $CLIENT -- iperf -t ${RUNTIME} -c ${SERVERIP} & done sleep ${RUNTIME} 1 j=$((j+1)) done sleep 1 echo "stopping lxc iperf server" vcmd -c $SERVER -- killall -v iperf echo "stopping containers" kill -9 `cat $SERVER.pid` for CLIENT in $CLIENTS; do kill -9 `cat $CLIENT.pid` done # time needed for processes/containers to shut down sleep 2 echo "cleaning up" ip link set $BRIDGE down brctl delbr $BRIDGE rm -f ${SERVER}* rm -f /tmp/${0}-client* # time needed for bridge clean-up sleep 1 } # # run all tests # loopbacktest lxcvethtest lxcbrtest chaintest 5 chaintest 10 clientstest 5 clientstest 10 clientstest 15 mv ${LOG} ${PWD}/${0}-${STAMP}.log echo "===> results in ${PWD}/${0}-${STAMP}.log" core-4.8/daemon/examples/netns/ospfmanetmdrtest.py0000775000175000017500000004710612534327775017453 00000000000000#!/usr/bin/python # Copyright (c)2011-2014 the Boeing Company. # See the LICENSE file included in this distribution. # create a random topology running OSPFv3 MDR, wait and then check # that all neighbor states are either full or two-way, and check the routes # in zebra vs those installed in the kernel. import os, sys, random, time, optparse, datetime from string import Template try: from core import pycore except ImportError: # hack for Fedora autoconf that uses the following pythondir: if "/usr/lib/python2.6/site-packages" in sys.path: sys.path.append("/usr/local/lib/python2.6/site-packages") if "/usr/lib64/python2.6/site-packages" in sys.path: sys.path.append("/usr/local/lib64/python2.6/site-packages") if "/usr/lib/python2.7/site-packages" in sys.path: sys.path.append("/usr/local/lib/python2.7/site-packages") if "/usr/lib64/python2.7/site-packages" in sys.path: sys.path.append("/usr/local/lib64/python2.7/site-packages") from core import pycore from core.misc import ipaddr from core.misc.utils import mutecall from core.constants import QUAGGA_STATE_DIR # this is the /etc/core/core.conf default quagga_sbin_search = ("/usr/local/sbin", "/usr/sbin", "/usr/lib/quagga") quagga_path = "zebra" # sanity check that zebra is installed try: for p in quagga_sbin_search: if os.path.exists(os.path.join(p, "zebra")): quagga_path = p break mutecall([os.path.join(quagga_path, "zebra"), "-u", "root", "-g", "root", "-v"]) except OSError: sys.stderr.write("ERROR: running zebra failed\n") sys.exit(1) class ManetNode(pycore.nodes.LxcNode): """ An Lxc namespace node configured for Quagga OSPFv3 MANET MDR """ conftemp = Template("""\ interface eth0 ip address $ipaddr ipv6 ospf6 instance-id 65 ipv6 ospf6 hello-interval 2 ipv6 ospf6 dead-interval 6 ipv6 ospf6 retransmit-interval 5 ipv6 ospf6 network manet-designated-router ipv6 ospf6 diffhellos ipv6 ospf6 adjacencyconnectivity biconnected ipv6 ospf6 lsafullness mincostlsa ! router ospf6 router-id $routerid interface eth0 area 0.0.0.0 ! ip forwarding """) confdir = "/usr/local/etc/quagga" def __init__(self, core, ipaddr, routerid = None, objid = None, name = None, nodedir = None): if routerid is None: routerid = ipaddr.split("/")[0] self.ipaddr = ipaddr self.routerid = routerid pycore.nodes.LxcNode.__init__(self, core, objid, name, nodedir) self.privatedir(self.confdir) self.privatedir(QUAGGA_STATE_DIR) def qconf(self): return self.conftemp.substitute(ipaddr = self.ipaddr, routerid = self.routerid) def config(self): filename = os.path.join(self.confdir, "Quagga.conf") f = self.opennodefile(filename, "w") f.write(self.qconf()) f.close() tmp = self.bootscript() if tmp: self.nodefile(self.bootsh, tmp, mode = 0755) def boot(self): self.config() self.session.services.bootnodeservices(self) def bootscript(self): return """\ #!/bin/sh -e STATEDIR=%s waitfile() { fname=$1 i=0 until [ -e $fname ]; do i=$(($i + 1)) if [ $i -eq 10 ]; then echo "file not found: $fname" >&2 exit 1 fi sleep 0.1 done } mkdir -p $STATEDIR %s/zebra -d -u root -g root waitfile $STATEDIR/zebra.vty %s/ospf6d -d -u root -g root waitfile $STATEDIR/ospf6d.vty vtysh -b """ % (QUAGGA_STATE_DIR, quagga_path, quagga_path) class Route(object): """ Helper class for organzing routing table entries. """ def __init__(self, prefix = None, gw = None, metric = None): try: self.prefix = ipaddr.IPv4Prefix(prefix) except Exception, e: raise ValueError, "Invalid prefix given to Route object: %s\n%s" % \ (prefix, e) self.gw = gw self.metric = metric def __eq__(self, other): try: return self.prefix == other.prefix and self.gw == other.gw and \ self.metric == other.metric except: return False def __str__(self): return "(%s,%s,%s)" % (self.prefix, self.gw, self.metric) @staticmethod def key(r): if not r.prefix: return 0 return r.prefix.prefix class ManetExperiment(object): """ A class for building an MDR network and checking and logging its state. """ def __init__(self, options, start): """ Initialize with options and start time. """ self.session = None # node list self.nodes = [] # WLAN network self.net = None self.verbose = options.verbose # dict from OptionParser self.options = options self.start = start self.logbegin() def info(self, msg): ''' Utility method for writing output to stdout. ''' print msg sys.stdout.flush() self.log(msg) def warn(self, msg): ''' Utility method for writing output to stderr. ''' print >> sys.stderr, msg sys.stderr.flush() self.log(msg) def logbegin(self): """ Start logging. """ self.logfp = None if not self.options.logfile: return self.logfp = open(self.options.logfile, "w") self.log("ospfmanetmdrtest begin: %s\n" % self.start.ctime()) def logend(self): """ End logging. """ if not self.logfp: return end = datetime.datetime.now() self.log("ospfmanetmdrtest end: %s (%s)\n" % \ (end.ctime(), end - self.start)) self.logfp.flush() self.logfp.close() self.logfp = None def log(self, msg): """ Write to the log file, if any. """ if not self.logfp: return print >> self.logfp, msg def logdata(self, nbrs, mdrs, lsdbs, krs, zrs): """ Dump experiment parameters and data to the log file. """ self.log("ospfmantetmdrtest data:") self.log("----- parameters -----") self.log("%s" % self.options) self.log("----- neighbors -----") for rtrid in sorted(nbrs.keys()): self.log("%s: %s" % (rtrid, nbrs[rtrid])) self.log("----- mdr levels -----") self.log(mdrs) self.log("----- link state databases -----") for rtrid in sorted(lsdbs.keys()): self.log("%s lsdb:" % rtrid) for line in lsdbs[rtrid].split("\n"): self.log(line) self.log("----- kernel routes -----") for rtrid in sorted(krs.keys()): msg = rtrid + ": " for rt in krs[rtrid]: msg += "%s" % rt self.log(msg) self.log("----- zebra routes -----") for rtrid in sorted(zrs.keys()): msg = rtrid + ": " for rt in zrs[rtrid]: msg += "%s" % rt self.log(msg) def topology(self, numnodes, linkprob, verbose = False): """ Build a topology consisting of the given number of ManetNodes connected to a WLAN and probabilty of links and set the session, WLAN, and node list objects. """ # IP subnet prefix = ipaddr.IPv4Prefix("10.14.0.0/16") self.session = pycore.Session() # emulated network self.net = self.session.addobj(cls = pycore.nodes.WlanNode) for i in xrange(1, numnodes + 1): addr = "%s/%s" % (prefix.addr(i), 32) tmp = self.session.addobj(cls = ManetNode, ipaddr = addr, objid= "%d" % i, name = "n%d" % i) tmp.newnetif(self.net, [addr]) self.nodes.append(tmp) # connect nodes with probability linkprob for i in xrange(numnodes): for j in xrange(i + 1, numnodes): r = random.random() if r < linkprob: if self.verbose: self.info("linking (%d,%d)" % (i, j)) self.net.link(self.nodes[i].netif(0), self.nodes[j].netif(0)) # force one link to avoid partitions (should check if this is needed) j = i while j == i: j = random.randint(0, numnodes - 1) if self.verbose: self.info("linking (%d,%d)" % (i, j)) self.net.link(self.nodes[i].netif(0), self.nodes[j].netif(0)) self.nodes[i].boot() # run the boot.sh script on all nodes to start Quagga for i in xrange(numnodes): self.nodes[i].cmd(["./%s" % self.nodes[i].bootsh]) def compareroutes(self, node, kr, zr): """ Compare two lists of Route objects. """ kr.sort(key=Route.key) zr.sort(key=Route.key) if kr != zr: self.warn("kernel and zebra routes differ") if self.verbose: msg = "kernel: " for r in kr: msg += "%s " % r msg += "\nzebra: " for r in zr: msg += "%s " % r self.warn(msg) else: self.info(" kernel and zebra routes match") def comparemdrlevels(self, nbrs, mdrs): """ Check that all routers form a connected dominating set, i.e. all routers are either MDR, BMDR, or adjacent to one. """ msg = "All routers form a CDS" for n in self.nodes: if mdrs[n.routerid] != "OTHER": continue connected = False for nbr in nbrs[n.routerid]: if mdrs[nbr] == "MDR" or mdrs[nbr] == "BMDR": connected = True break if not connected: msg = "All routers do not form a CDS" self.warn("XXX %s: not in CDS; neighbors: %s" % \ (n.routerid, nbrs[n.routerid])) if self.verbose: self.info(msg) def comparelsdbs(self, lsdbs): """ Check LSDBs for consistency. """ msg = "LSDBs of all routers are consistent" prev = self.nodes[0] for n in self.nodes: db = lsdbs[n.routerid] if lsdbs[prev.routerid] != db: msg = "LSDBs of all routers are not consistent" self.warn("XXX LSDBs inconsistent for %s and %s" % \ (n.routerid, prev.routerid)) i = 0 for entry in lsdbs[n.routerid].split("\n"): preventries = lsdbs[prev.routerid].split("\n") try: preventry = preventries[i] except IndexError: preventry = None if entry != preventry: self.warn("%s: %s" % (n.routerid, entry)) self.warn("%s: %s" % (prev.routerid, preventry)) i += 1 prev = n if self.verbose: self.info(msg) def checknodes(self): """ Check the neighbor state and routing tables of all nodes. """ nbrs = {} mdrs = {} lsdbs = {} krs = {} zrs = {} v = self.verbose for n in self.nodes: self.info("checking %s" % n.name) nbrs[n.routerid] = Ospf6NeighState(n, verbose=v).run() krs[n.routerid] = KernelRoutes(n, verbose=v).run() zrs[n.routerid] = ZebraRoutes(n, verbose=v).run() self.compareroutes(n, krs[n.routerid], zrs[n.routerid]) mdrs[n.routerid] = Ospf6MdrLevel(n, verbose=v).run() lsdbs[n.routerid] = Ospf6Database(n, verbose=v).run() self.comparemdrlevels(nbrs, mdrs) self.comparelsdbs(lsdbs) self.logdata(nbrs, mdrs, lsdbs, krs, zrs) class Cmd: """ Helper class for running a command on a node and parsing the result. """ args = "" def __init__(self, node, verbose=False): """ Initialize with a CoreNode (LxcNode) """ self.id = None self.stdin = None self.out = None self.node = node self.verbose = verbose def info(self, msg): ''' Utility method for writing output to stdout.''' print msg sys.stdout.flush() def warn(self, msg): ''' Utility method for writing output to stderr. ''' print >> sys.stderr, "XXX %s:" % self.node.routerid, msg sys.stderr.flush() def run(self): """ This is the primary method used for running this command. """ self.open() r = self.parse() self.cleanup() return r def open(self): """ Exceute call to node.popen(). """ self.id, self.stdin, self.out, self.err = \ self.node.popen((self.args)) def parse(self): """ This method is overloaded by child classes and should return some result. """ return None def cleanup(self): """ Close the Popen channels.""" self.stdin.close() self.out.close() self.err.close() tmp = self.id.wait() if tmp: self.warn("nonzero exit status:", tmp) class VtyshCmd(Cmd): """ Runs a vtysh command. """ def open(self): args = ("vtysh", "-c", self.args) self.id, self.stdin, self.out, self.err = self.node.popen((args)) class Ospf6NeighState(VtyshCmd): """ Check a node for OSPFv3 neighbors in the full/two-way states. """ args = "show ipv6 ospf6 neighbor" def parse(self): self.out.readline() # skip first line nbrlist = [] for line in self.out: field = line.split() nbr = field[0] state = field[3].split("/")[0] if not state.lower() in ("full", "twoway"): self.warn("neighbor %s state: %s" % (nbr, state)) nbrlist.append(nbr) if len(nbrlist) == 0: self.warn("no neighbors") if self.verbose: self.info(" %s has %d neighbors" % (self.node.routerid, len(nbrlist))) return nbrlist class Ospf6MdrLevel(VtyshCmd): """ Retrieve the OSPFv3 MDR level for a node. """ args = "show ipv6 ospf6 mdrlevel" def parse(self): line = self.out.readline() # TODO: handle multiple interfaces field = line.split() mdrlevel = field[4] if not mdrlevel in ("MDR", "BMDR", "OTHER"): self.warn("mdrlevel: %s" % mdrlevel) if self.verbose: self.info(" %s is %s" % (self.node.routerid, mdrlevel)) return mdrlevel class Ospf6Database(VtyshCmd): """ Retrieve the OSPFv3 LSDB summary for a node. """ args = "show ipv6 ospf6 database" def parse(self): db = "" for line in self.out: field = line.split() if len(field) < 8: continue # filter out Age and Duration columns filtered = field[:3] + field[4:7] db += " ".join(filtered) + "\n" return db class ZebraRoutes(VtyshCmd): """ Return a list of Route objects for a node based on its zebra routing table. """ args = "show ip route" def parse(self): for i in xrange(0,3): self.out.readline() # skip first three lines r = [] prefix = None for line in self.out: field = line.split() if len(field) < 1: continue # only use OSPFv3 selected FIB routes elif field[0][:2] == "o>": prefix = field[1] metric = field[2].split("/")[1][:-1] if field[0][2:] != "*": continue if field[3] == "via": gw = field[4][:-1] else: gw = field[6][:-1] r.append(Route(prefix, gw, metric)) prefix = None elif prefix and field[0] == "*": # already have prefix and metric from previous line gw = field[2][:-1] r.append(Route(prefix, gw, metric)) prefix = None if len(r) == 0: self.warn("no zebra routes") if self.verbose: self.info(" %s has %d zebra routes" % (self.node.routerid, len(r))) return r class KernelRoutes(Cmd): """ Return a list of Route objects for a node based on its kernel routing table. """ args = ("/sbin/ip", "route", "show") def parse(self): r = [] prefix = None for line in self.out: field = line.split() if field[0] == "nexthop": if not prefix: # this saves only the first nexthop entry if multiple exist continue else: prefix = field[0] metric = field[-1] tmp = prefix.split("/") if len(tmp) < 2: prefix += "/32" if field[1] == "proto": # nexthop entry is on the next line continue gw = field[2] # nexthop IP or interface r.append(Route(prefix, gw, metric)) prefix = None if len(r) == 0: self.warn("no kernel routes") if self.verbose: self.info(" %s has %d kernel routes" % (self.node.routerid, len(r))) return r def main(): usagestr = "usage: %prog [-h] [options] [args]" parser = optparse.OptionParser(usage = usagestr) parser.set_defaults(numnodes = 10, linkprob = 0.35, delay = 20, seed = None) parser.add_option("-n", "--numnodes", dest = "numnodes", type = int, help = "number of nodes") parser.add_option("-p", "--linkprob", dest = "linkprob", type = float, help = "link probabilty") parser.add_option("-d", "--delay", dest = "delay", type = float, help = "wait time before checking") parser.add_option("-s", "--seed", dest = "seed", type = int, help = "specify integer to use for random seed") parser.add_option("-v", "--verbose", dest = "verbose", action = "store_true", help = "be more verbose") parser.add_option("-l", "--logfile", dest = "logfile", type = str, help = "log detailed output to the specified file") def usage(msg = None, err = 0): sys.stdout.write("\n") if msg: sys.stdout.write(msg + "\n\n") parser.print_help() sys.exit(err) # parse command line options (options, args) = parser.parse_args() if options.numnodes < 2: usage("invalid numnodes: %s" % options.numnodes) if options.linkprob <= 0.0 or options.linkprob > 1.0: usage("invalid linkprob: %s" % options.linkprob) if options.delay < 0.0: usage("invalid delay: %s" % options.delay) for a in args: sys.stderr.write("ignoring command line argument: '%s'\n" % a) if options.seed: random.seed(options.seed) me = ManetExperiment(options = options, start=datetime.datetime.now()) me.info("creating topology: numnodes = %s; linkprob = %s" % \ (options.numnodes, options.linkprob)) me.topology(options.numnodes, options.linkprob) me.info("waiting %s sec" % options.delay) time.sleep(options.delay) me.info("checking neighbor state and routes") me.checknodes() me.info("done") me.info("elapsed time: %s" % (datetime.datetime.now() - me.start)) me.logend() return me if __name__ == "__main__": me = main() core-4.8/daemon/examples/netns/switch.py0000775000175000017500000000410412534327775015344 00000000000000#!/usr/bin/python -i # Copyright (c)2010-2013 the Boeing Company. # See the LICENSE file included in this distribution. # connect n nodes to a virtual switch/hub import sys, datetime, optparse from core import pycore from core.misc import ipaddr from core.constants import * # node list (count from 1) n = [None] def main(): usagestr = "usage: %prog [-h] [options] [args]" parser = optparse.OptionParser(usage = usagestr) parser.set_defaults(numnodes = 5) parser.add_option("-n", "--numnodes", dest = "numnodes", type = int, help = "number of nodes") def usage(msg = None, err = 0): sys.stdout.write("\n") if msg: sys.stdout.write(msg + "\n\n") parser.print_help() sys.exit(err) # parse command line options (options, args) = parser.parse_args() if options.numnodes < 1: usage("invalid number of nodes: %s" % options.numnodes) for a in args: sys.stderr.write("ignoring command line argument: '%s'\n" % a) start = datetime.datetime.now() # IP subnet prefix = ipaddr.IPv4Prefix("10.83.0.0/16") session = pycore.Session(persistent=True) if 'server' in globals(): server.addsession(session) # emulated Ethernet switch switch = session.addobj(cls = pycore.nodes.SwitchNode, name = "switch") switch.setposition(x=80,y=50) print "creating %d nodes with addresses from %s" % \ (options.numnodes, prefix) for i in xrange(1, options.numnodes + 1): tmp = session.addobj(cls = pycore.nodes.CoreNode, name = "n%d" % i, objid=i) tmp.newnetif(switch, ["%s/%s" % (prefix.addr(i), prefix.prefixlen)]) tmp.cmd([SYSCTL_BIN, "net.ipv4.icmp_echo_ignore_broadcasts=0"]) tmp.setposition(x=150*i,y=150) n.append(tmp) session.node_count = str(options.numnodes + 1) session.instantiate() # start a shell on node 1 n[1].term("bash") print "elapsed time: %s" % (datetime.datetime.now() - start) if __name__ == "__main__" or __name__ == "__builtin__": main() core-4.8/daemon/examples/netns/switchtest.py0000775000175000017500000000642312534327775016252 00000000000000#!/usr/bin/python # Copyright (c)2010-2012 the Boeing Company. # See the LICENSE file included in this distribution. # run iperf to measure the effective throughput between two nodes when # n nodes are connected to a virtual hub/switch; run test for testsec # and repeat for minnodes <= n <= maxnodes with a step size of # nodestep import optparse, sys, os, datetime from core import pycore from core.misc import ipaddr from core.misc.utils import mutecall try: mutecall(["iperf", "-v"]) except OSError: sys.stderr.write("ERROR: running iperf failed\n") sys.exit(1) def test(numnodes, testsec): # node list n = [] # IP subnet prefix = ipaddr.IPv4Prefix("10.83.0.0/16") session = pycore.Session() # emulated network net = session.addobj(cls = pycore.nodes.SwitchNode) for i in xrange(1, numnodes + 1): tmp = session.addobj(cls = pycore.nodes.LxcNode, name = "n%d" % i) tmp.newnetif(net, ["%s/%s" % (prefix.addr(i), prefix.prefixlen)]) n.append(tmp) n[0].cmd(["iperf", "-s", "-D"]) n[-1].icmd(["iperf", "-t", str(int(testsec)), "-c", str(prefix.addr(1))]) n[0].cmd(["killall", "-9", "iperf"]) session.shutdown() def main(): usagestr = "usage: %prog [-h] [options] [args]" parser = optparse.OptionParser(usage = usagestr) parser.set_defaults(minnodes = 2) parser.add_option("-m", "--minnodes", dest = "minnodes", type = int, help = "min number of nodes to test; default = %s" % parser.defaults["minnodes"]) parser.set_defaults(maxnodes = 2) parser.add_option("-n", "--maxnodes", dest = "maxnodes", type = int, help = "max number of nodes to test; default = %s" % parser.defaults["maxnodes"]) parser.set_defaults(testsec = 10) parser.add_option("-t", "--testsec", dest = "testsec", type = int, help = "test time in seconds; default = %s" % parser.defaults["testsec"]) parser.set_defaults(nodestep = 1) parser.add_option("-s", "--nodestep", dest = "nodestep", type = int, help = "number of nodes step size; default = %s" % parser.defaults["nodestep"]) def usage(msg = None, err = 0): sys.stdout.write("\n") if msg: sys.stdout.write(msg + "\n\n") parser.print_help() sys.exit(err) # parse command line options (options, args) = parser.parse_args() if options.minnodes < 2: usage("invalid min number of nodes: %s" % options.minnodes) if options.maxnodes < options.minnodes: usage("invalid max number of nodes: %s" % options.maxnodes) if options.testsec < 1: usage("invalid test time: %s" % options.testsec) if options.nodestep < 1: usage("invalid node step: %s" % options.nodestep) for a in args: sys.stderr.write("ignoring command line argument: '%s'\n" % a) start = datetime.datetime.now() for i in xrange(options.minnodes, options.maxnodes + 1, options.nodestep): print >> sys.stderr, "%s node test:" % i test(i, options.testsec) print >> sys.stderr, "" print >> sys.stderr, \ "elapsed time: %s" % (datetime.datetime.now() - start) if __name__ == "__main__": main() core-4.8/daemon/examples/netns/twonodes.sh0000775000175000017500000000240112534327775015665 00000000000000#!/bin/sh -e # Below is a transcript of creating two emulated nodes and connecting them # together with a wired link. You can run the core-cleanup script to clean # up after this script. # create node 1 namespace container vnoded -c /tmp/n1.ctl -l /tmp/n1.log -p /tmp/n1.pid # create a virtual Ethernet (veth) pair, installing one end into node 1 ip link add name n1.0.1 type veth peer name n1.0 ip link set n1.0 netns `cat /tmp/n1.pid` vcmd -c /tmp/n1.ctl -- /bin/sh -e -c \ "ip link set lo up && ip link set n1.0 name eth0 up && ip addr add 10.0.0.1/24 dev eth0" # create node 2 namespace container vnoded -c /tmp/n2.ctl -l /tmp/n2.log -p /tmp/n2.pid # create a virtual Ethernet (veth) pair, installing one end into node 2 ip link add name n2.0.1 type veth peer name n2.0 ip link set n2.0 netns `cat /tmp/n2.pid` vcmd -c /tmp/n2.ctl -- /bin/sh -e -c \ "ip link set lo up && ip link set n2.0 name eth0 up && ip addr add 10.0.0.2/24 dev eth0" # bridge together nodes 1 and 2 using the other end of each veth pair brctl addbr b.1.1 brctl setfd b.1.1 0 brctl addif b.1.1 n1.0.1 brctl addif b.1.1 n2.0.1 ip link set n1.0.1 up ip link set n2.0.1 up ip link set b.1.1 up # display connectivity and ping from node 1 to node 2 brctl show vcmd -c /tmp/n1.ctl -- ping 10.0.0.2 core-4.8/daemon/examples/netns/wlanemanetests.py0000775000175000017500000010041112534327775017073 00000000000000#!/usr/bin/python # Copyright (c)2011-2014 the Boeing Company. # See the LICENSE file included in this distribution. # # author: Jeff Ahrenholz # ''' wlanemanetests.py - This script tests the performance of the WLAN device in CORE by measuring various metrics: - delay experienced when pinging end-to-end - maximum TCP throughput achieved using iperf end-to-end - the CPU used and loss experienced when running an MGEN flow of UDP traffic All MANET nodes are arranged in a row, so that any given node can only communicate with the node to its right or to its left. Performance is measured using traffic that travels across each hop in the network. Static /32 routing is used instead of any dynamic routing protocol. Various underlying network types are tested: - bridged (the CORE default, uses ebtables) - bridged with netem (add link effects to the bridge using tc queues) - EMANE bypass - the bypass model just forwards traffic - EMANE RF-PIPE - the bandwidth (bitrate) is set very high / no restrictions - EMANE RF-PIPE - bandwidth is set similar to netem case - EMANE RF-PIPE - default connectivity is off and pathloss events are generated to connect the nodes in a line Results are printed/logged in CSV format. ''' import os, sys, time, optparse, datetime, math from string import Template try: from core import pycore except ImportError: # hack for Fedora autoconf that uses the following pythondir: if "/usr/lib/python2.6/site-packages" in sys.path: sys.path.append("/usr/local/lib/python2.6/site-packages") if "/usr/lib64/python2.6/site-packages" in sys.path: sys.path.append("/usr/local/lib64/python2.6/site-packages") if "/usr/lib/python2.7/site-packages" in sys.path: sys.path.append("/usr/local/lib/python2.7/site-packages") if "/usr/lib64/python2.7/site-packages" in sys.path: sys.path.append("/usr/local/lib64/python2.7/site-packages") from core import pycore from core.misc import ipaddr from core.misc.utils import mutecall from core.constants import QUAGGA_STATE_DIR from core.emane.emane import Emane from core.emane.bypass import EmaneBypassModel from core.emane.rfpipe import EmaneRfPipeModel try: import emaneeventservice import emaneeventpathloss except Exception, e: try: from emanesh.events import EventService from emanesh.events import PathlossEvent except Exception, e2: raise ImportError, "failed to import EMANE Python bindings:\n%s\n%s" % \ (e, e2) # global Experiment object (for interaction with 'python -i') exp = None # move these to core.misc.utils def readstat(): f = open("/proc/stat", "r") lines = f.readlines() f.close() return lines def numcpus(): lines = readstat() n = 0 for l in lines[1:]: if l[:3] != "cpu": break n += 1 return n def getcputimes(line): # return (user, nice, sys, idle) from a /proc/stat cpu line # assume columns are: # cpu# user nice sys idle iowait irq softirq steal guest (man 5 proc) items = line.split() (user, nice, sys, idle) = map(lambda(x): int(x), items[1:5]) return [user, nice, sys, idle] def calculatecpu(timesa, timesb): for i in range(len(timesa)): timesb[i] -= timesa[i] total = sum(timesb) if total == 0: return 0.0 else: # subtract % time spent in idle time return 100 - ((100.0 * timesb[-1]) / total) # end move these to core.misc.utils class Cmd(object): ''' Helper class for running a command on a node and parsing the result. ''' args = "" def __init__(self, node, verbose=False): ''' Initialize with a CoreNode (LxcNode) ''' self.id = None self.stdin = None self.out = None self.node = node self.verbose = verbose def info(self, msg): ''' Utility method for writing output to stdout.''' print msg sys.stdout.flush() def warn(self, msg): ''' Utility method for writing output to stderr. ''' print >> sys.stderr, "XXX %s:" % self.node.name, msg sys.stderr.flush() def run(self): ''' This is the primary method used for running this command. ''' self.open() status = self.id.wait() r = self.parse() self.cleanup() return r def open(self): ''' Exceute call to node.popen(). ''' self.id, self.stdin, self.out, self.err = \ self.node.popen((self.args)) def parse(self): ''' This method is overloaded by child classes and should return some result. ''' return None def cleanup(self): ''' Close the Popen channels.''' self.stdin.close() self.out.close() self.err.close() tmp = self.id.wait() if tmp: self.warn("nonzero exit status:", tmp) class ClientServerCmd(Cmd): ''' Helper class for running a command on a node and parsing the result. ''' args = "" client_args = "" def __init__(self, node, client_node, verbose=False): ''' Initialize with two CoreNodes, node is the server ''' Cmd.__init__(self, node, verbose) self.client_node = client_node def run(self): ''' Run the server command, then the client command, then kill the server ''' self.open() # server self.client_open() # client status = self.client_id.wait() self.node.cmdresult(['killall', self.args[0]]) # stop the server r = self.parse() self.cleanup() return r def client_open(self): ''' Exceute call to client_node.popen(). ''' self.client_id, self.client_stdin, self.client_out, self.client_err = \ self.client_node.popen((self.client_args)) def parse(self): ''' This method is overloaded by child classes and should return some result. ''' return None def cleanup(self): ''' Close the Popen channels.''' self.stdin.close() self.out.close() self.err.close() tmp = self.id.wait() if tmp: self.warn("nonzero exit status: %s" % tmp) self.warn("command was: %s" % ((self.args, ))) class PingCmd(Cmd): ''' Test latency using ping. ''' def __init__(self, node, verbose=False, addr=None, count=50, interval=0.1, ): Cmd.__init__(self, node, verbose) self.addr = addr self.count = count self.interval = interval self.args = ['ping', '-q', '-c', '%s' % count, '-i', '%s' % interval, addr] def run(self): if self.verbose: self.info("%s initial test ping (max 1 second)..." % self.node.name) (status, result) = self.node.cmdresult(["ping", "-q", "-c", "1", "-w", "1", self.addr]) if status != 0: self.warn("initial ping from %s to %s failed! result:\n%s" % \ (self.node.name, self.addr, result)) return (0.0, 0.0) if self.verbose: self.info("%s pinging %s (%d seconds)..." % \ (self.node.name, self.addr, self.count * self.interval)) return Cmd.run(self) def parse(self): lines = self.out.readlines() avg_latency = 0 mdev = 0 try: stats_str = lines[-1].split('=')[1] stats = stats_str.split('/') avg_latency = float(stats[1]) mdev = float(stats[3].split(' ')[0]) except Exception, e: self.warn("ping parsing exception: %s" % e) return (avg_latency, mdev) class IperfCmd(ClientServerCmd): ''' Test throughput using iperf. ''' def __init__(self, node, client_node, verbose=False, addr=None, time=10): # node is the server ClientServerCmd.__init__(self, node, client_node, verbose) self.addr = addr self.time = time # -s server, -y c CSV report output self.args = ["iperf", "-s", "-y", "c"] self.client_args = ["iperf", "-c", self.addr, "-t", "%s" % self.time] def run(self): if self.verbose: self.info("Launching the iperf server on %s..." % self.node.name) self.info("Running the iperf client on %s (%s seconds)..." % \ (self.client_node.name, self.time)) return ClientServerCmd.run(self) def parse(self): lines = self.out.readlines() try: bps = int(lines[-1].split(',')[-1].strip('\n')) except Exception, e: self.warn("iperf parsing exception: %s" % e) bps = 0 return bps class MgenCmd(ClientServerCmd): ''' Run a test traffic flow using an MGEN sender and receiver. ''' def __init__(self, node, client_node, verbose=False, addr=None, time=10, rate=512): ClientServerCmd.__init__(self, node, client_node, verbose) self.addr = addr self.time = time self.args = ['mgen', 'event', 'listen udp 5000', 'output', '/var/log/mgen.log'] self.rate = rate sendevent = "ON 1 UDP DST %s/5000 PERIODIC [%s]" % \ (addr, self.mgenrate(self.rate)) stopevent = "%s OFF 1" % time self.client_args = ['mgen', 'event', sendevent, 'event', stopevent, 'output', '/var/log/mgen.log'] @staticmethod def mgenrate(kbps): ''' Return a MGEN periodic rate string for the given kilobits-per-sec. Assume 1500 byte MTU, 20-byte IP + 8-byte UDP headers, leaving 1472 bytes for data. ''' bps = (kbps / 8) * 1000.0 maxdata = 1472 pps = math.ceil(bps / maxdata) return "%s %s" % (pps, maxdata) def run(self): if self.verbose: self.info("Launching the MGEN receiver on %s..." % self.node.name) self.info("Running the MGEN sender on %s (%s seconds)..." % \ (self.client_node.name, self.time)) return ClientServerCmd.run(self) def cleanup(self): ''' Close the Popen channels.''' self.stdin.close() self.out.close() self.err.close() tmp = self.id.wait() # non-zero mgen exit status OK def parse(self): ''' Check MGEN receiver's log file for packet sequence numbers, and return the percentage of lost packets. ''' logfile = os.path.join(self.node.nodedir, 'var.log/mgen.log') f = open(logfile, 'r') numlost = 0 lastseq = 0 for line in f.readlines(): fields = line.split() if fields[1] != 'RECV': continue try: seq = int(fields[4].split('>')[1]) except: self.info("Unexpected MGEN line:\n%s" % fields) if seq > (lastseq + 1): numlost += seq - (lastseq + 1) lastseq = seq f.close() if lastseq > 0: loss = 100.0 * numlost / lastseq else: loss = 0 if self.verbose: self.info("Receiver log shows %d of %d packets lost" % \ (numlost, lastseq)) return loss class Experiment(object): ''' Experiment object to organize tests. ''' def __init__(self, opt, start): ''' Initialize with opt and start time. ''' self.session = None # node list self.nodes = [] # WLAN network self.net = None self.verbose = opt.verbose # dict from OptionParser self.opt = opt self.start = start self.numping = opt.numping self.numiperf = opt.numiperf self.nummgen = opt.nummgen self.logbegin() def info(self, msg): ''' Utility method for writing output to stdout. ''' print msg sys.stdout.flush() self.log(msg) def warn(self, msg): ''' Utility method for writing output to stderr. ''' print >> sys.stderr, msg sys.stderr.flush() self.log(msg) def logbegin(self): ''' Start logging. ''' self.logfp = None if not self.opt.logfile: return self.logfp = open(self.opt.logfile, "w") self.log("%s begin: %s\n" % (sys.argv[0], self.start.ctime())) self.log("%s args: %s\n" % (sys.argv[0], sys.argv[1:])) (sysname, rel, ver, machine, nodename) = os.uname() self.log("%s %s %s %s on %s" % (sysname, rel, ver, machine, nodename)) def logend(self): ''' End logging. ''' if not self.logfp: return end = datetime.datetime.now() self.log("%s end: %s (%s)\n" % \ (sys.argv[0], end.ctime(), end - self.start)) self.logfp.flush() self.logfp.close() self.logfp = None def log(self, msg): ''' Write to the log file, if any. ''' if not self.logfp: return print >> self.logfp, msg def reset(self): ''' Prepare for another experiment run. ''' if self.session: self.session.shutdown() del self.session self.session = None self.nodes = [] self.net = None def createbridgedsession(self, numnodes, verbose = False): ''' Build a topology consisting of the given number of LxcNodes connected to a WLAN. ''' # IP subnet prefix = ipaddr.IPv4Prefix("10.0.0.0/16") self.session = pycore.Session() # emulated network self.net = self.session.addobj(cls = pycore.nodes.WlanNode, name = "wlan1") prev = None for i in xrange(1, numnodes + 1): addr = "%s/%s" % (prefix.addr(i), 32) tmp = self.session.addobj(cls = pycore.nodes.CoreNode, objid = i, name = "n%d" % i) tmp.newnetif(self.net, [addr]) self.nodes.append(tmp) self.session.services.addservicestonode(tmp, "router", "IPForward", self.verbose) self.session.services.bootnodeservices(tmp) self.staticroutes(i, prefix, numnodes) # link each node in a chain, with the previous node if prev: self.net.link(prev.netif(0), tmp.netif(0)) prev = tmp def createemanesession(self, numnodes, verbose = False, cls = None, values = None): ''' Build a topology consisting of the given number of LxcNodes connected to an EMANE WLAN. ''' prefix = ipaddr.IPv4Prefix("10.0.0.0/16") self.session = pycore.Session() self.session.node_count = str(numnodes + 1) self.session.master = True self.session.location.setrefgeo(47.57917,-122.13232,2.00000) self.session.location.refscale = 150.0 self.session.cfg['emane_models'] = "RfPipe, Ieee80211abg, Bypass" self.session.emane.loadmodels() self.net = self.session.addobj(cls = pycore.nodes.EmaneNode, objid = numnodes + 1, name = "wlan1") self.net.verbose = verbose #self.session.emane.addobj(self.net) for i in xrange(1, numnodes + 1): addr = "%s/%s" % (prefix.addr(i), 32) tmp = self.session.addobj(cls = pycore.nodes.CoreNode, objid = i, name = "n%d" % i) #tmp.setposition(i * 20, 50, None) tmp.setposition(50, 50, None) tmp.newnetif(self.net, [addr]) self.nodes.append(tmp) self.session.services.addservicestonode(tmp, "router", "IPForward", self.verbose) if values is None: values = cls.getdefaultvalues() self.session.emane.setconfig(self.net.objid, cls._name, values) self.session.instantiate() self.info("waiting %s sec (TAP bring-up)" % 2) time.sleep(2) for i in xrange(1, numnodes + 1): tmp = self.nodes[i-1] self.session.services.bootnodeservices(tmp) self.staticroutes(i, prefix, numnodes) def setnodes(self): ''' Set the sender and receiver nodes for use in this experiment, along with the address of the receiver to be used. ''' self.firstnode = self.nodes[0] self.lastnode = self.nodes[-1] self.lastaddr = self.lastnode.netif(0).addrlist[0].split('/')[0] def staticroutes(self, i, prefix, numnodes): ''' Add static routes on node number i to the other nodes in the chain. ''' routecmd = ["/sbin/ip", "route", "add"] node = self.nodes[i-1] neigh_left = "" neigh_right = "" # add direct interface routes first if i > 1: neigh_left = "%s" % prefix.addr(i - 1) cmd = routecmd + [neigh_left, "dev", node.netif(0).name] (status, result) = node.cmdresult(cmd) if status != 0: self.warn("failed to add interface route: %s" % cmd) if i < numnodes: neigh_right = "%s" % prefix.addr(i + 1) cmd = routecmd + [neigh_right, "dev", node.netif(0).name] (status, result) = node.cmdresult(cmd) if status != 0: self.warn("failed to add interface route: %s" % cmd) # add static routes to all other nodes via left/right neighbors for j in xrange(1, numnodes + 1): if abs(j - i) < 2: continue addr = "%s" % prefix.addr(j) if j < i: gw = neigh_left else: gw = neigh_right cmd = routecmd + [addr, "via", gw] (status, result) = node.cmdresult(cmd) if status != 0: self.warn("failed to add route: %s" % cmd) def setpathloss(self, numnodes): ''' Send EMANE pathloss events to connect all NEMs in a chain. ''' if self.session.emane.version < self.session.emane.EMANE091: service = emaneeventservice.EventService() e = emaneeventpathloss.EventPathloss(1) old = True else: if self.session.emane.version == self.session.emane.EMANE091: dev = 'lo' else: dev = self.session.obj('ctrlnet').brname service = EventService(eventchannel=("224.1.2.8", 45703, dev), otachannel=None) old = False for i in xrange(1, numnodes + 1): rxnem = i # inform rxnem that it can hear node to the left with 10dB noise txnem = rxnem - 1 if txnem > 0: if old: e.set(0, txnem, 10.0, 10.0) service.publish(emaneeventpathloss.EVENT_ID, emaneeventservice.PLATFORMID_ANY, rxnem, emaneeventservice.COMPONENTID_ANY, e.export()) else: e = PathlossEvent() e.append(txnem, forward=10.0, reverse=10.0) service.publish(rxnem, e) # inform rxnem that it can hear node to the right with 10dB noise txnem = rxnem + 1 if txnem > numnodes: continue if old: e.set(0, txnem, 10.0, 10.0) service.publish(emaneeventpathloss.EVENT_ID, emaneeventservice.PLATFORMID_ANY, rxnem, emaneeventservice.COMPONENTID_ANY, e.export()) else: e = PathlossEvent() e.append(txnem, forward=10.0, reverse=10.0) service.publish(rxnem, e) def setneteffects(self, bw = None, delay = None): ''' Set link effects for all interfaces attached to the network node. ''' if not self.net: self.warn("failed to set effects: no network node") return for netif in self.net.netifs(): self.net.linkconfig(netif, bw = bw, delay = delay) def runalltests(self, title=""): ''' Convenience helper to run all defined experiment tests. If tests are run multiple times, this returns the average of those runs. ''' duration = self.opt.duration rate = self.opt.rate if len(title) > 0: self.info("----- running %s tests (duration=%s, rate=%s) -----" % \ (title, duration, rate)) (latency, mdev, throughput, cpu, loss) = (0,0,0,0,0) self.info("number of runs: ping=%d, iperf=%d, mgen=%d" % \ (self.numping, self.numiperf, self.nummgen)) if self.numping > 0: (latency, mdev) = self.pingtest(count=self.numping) if self.numiperf > 0: throughputs = [] for i in range(1, self.numiperf + 1): throughput = self.iperftest(time=duration) if self.numiperf > 1: throughputs += throughput time.sleep(1) # iperf is very CPU intensive if self.numiperf > 1: throughput = sum(throughputs) / len(throughputs) self.info("throughputs=%s" % ["%.2f" % v for v in throughputs]) if self.nummgen > 0: cpus = [] losses = [] for i in range(1, self.nummgen + 1): (cpu, loss) = self.cputest(time=duration, rate=rate) if self.nummgen > 1: cpus += cpu, losses += loss, if self.nummgen > 1: cpu = sum(cpus) / len(cpus) loss = sum(losses) / len(losses) self.info("cpus=%s" % ["%.2f" % v for v in cpus]) self.info("losses=%s" % ["%.2f" % v for v in losses]) return (latency, mdev, throughput, cpu, loss) def pingtest(self, count=50): ''' Ping through a chain of nodes and report the average latency. ''' p = PingCmd(node=self.firstnode, verbose=self.verbose, addr = self.lastaddr, count=count, interval=0.1).run() (latency, mdev) = p self.info("latency (ms): %.03f, %.03f" % (latency, mdev)) return p def iperftest(self, time=10): ''' Run iperf through a chain of nodes and report the maximum throughput. ''' bps = IperfCmd(node=self.lastnode, client_node=self.firstnode, verbose=False, addr=self.lastaddr, time=time).run() self.info("throughput (bps): %s" % bps) return bps def cputest(self, time=10, rate=512): ''' Run MGEN through a chain of nodes and report the CPU usage and percent of lost packets. Rate is in kbps. ''' if self.verbose: self.info("%s initial test ping (max 1 second)..." % \ self.firstnode.name) (status, result) = self.firstnode.cmdresult(["ping", "-q", "-c", "1", "-w", "1", self.lastaddr]) if status != 0: self.warn("initial ping from %s to %s failed! result:\n%s" % \ (self.firstnode.name, self.lastaddr, result)) return (0.0, 0.0) lines = readstat() cpustart = getcputimes(lines[0]) loss = MgenCmd(node=self.lastnode, client_node=self.firstnode, verbose=False, addr=self.lastaddr, time=time, rate=rate).run() lines = readstat() cpuend = getcputimes(lines[0]) percent = calculatecpu(cpustart, cpuend) self.info("CPU usage (%%): %.02f, %.02f loss" % (percent, loss)) return percent, loss def main(): ''' Main routine when running from command-line. ''' usagestr = "usage: %prog [-h] [options] [args]" parser = optparse.OptionParser(usage = usagestr) parser.set_defaults(numnodes = 10, delay = 3, duration = 10, rate = 512, verbose = False, numping = 50, numiperf = 1, nummgen = 1) parser.add_option("-d", "--delay", dest = "delay", type = float, help = "wait time before testing") parser.add_option("-l", "--logfile", dest = "logfile", type = str, help = "log detailed output to the specified file") parser.add_option("-n", "--numnodes", dest = "numnodes", type = int, help = "number of nodes") parser.add_option("-r", "--rate", dest = "rate", type = float, help = "kbps rate to use for MGEN CPU tests") parser.add_option("--numping", dest = "numping", type = int, help = "number of ping latency test runs") parser.add_option("--numiperf", dest = "numiperf", type = int, help = "number of iperf throughput test runs") parser.add_option("--nummgen", dest = "nummgen", type = int, help = "number of MGEN CPU tests runs") parser.add_option("-t", "--time", dest = "duration", type = int, help = "duration in seconds of throughput and CPU tests") parser.add_option("-v", "--verbose", dest = "verbose", action = "store_true", help = "be more verbose") def usage(msg = None, err = 0): sys.stdout.write("\n") if msg: sys.stdout.write(msg + "\n\n") parser.print_help() sys.exit(err) # parse command line opt (opt, args) = parser.parse_args() if opt.numnodes < 2: usage("invalid numnodes: %s" % opt.numnodes) if opt.delay < 0.0: usage("invalid delay: %s" % opt.delay) if opt.rate < 0.0: usage("invalid rate: %s" % opt.rate) for a in args: sys.stderr.write("ignoring command line argument: '%s'\n" % a) results = {} starttime = datetime.datetime.now() exp = Experiment(opt = opt, start=starttime) exp.info("Starting wlanemanetests.py tests %s" % starttime.ctime()) # system sanity checks here emanever, emaneverstr = Emane.detectversionfromcmd() if opt.verbose: exp.info("Detected EMANE version %s" % (emaneverstr,)) # bridged exp.info("setting up bridged tests 1/2 no link effects") exp.info("creating topology: numnodes = %s" % \ (opt.numnodes, )) exp.createbridgedsession(numnodes=opt.numnodes, verbose=opt.verbose) exp.setnodes() exp.info("waiting %s sec (node/route bring-up)" % opt.delay) time.sleep(opt.delay) results['0 bridged'] = exp.runalltests("bridged") exp.info("done; elapsed time: %s" % (datetime.datetime.now() - exp.start)) # bridged with netem exp.info("setting up bridged tests 2/2 with netem") exp.setneteffects(bw=54000000, delay=0) exp.info("waiting %s sec (queue bring-up)" % opt.delay) results['1.0 netem'] = exp.runalltests("netem") exp.info("shutting down bridged session") # bridged with netem (1 Mbps,200ms) exp.info("setting up bridged tests 3/2 with netem") exp.setneteffects(bw=1000000, delay=20000) exp.info("waiting %s sec (queue bring-up)" % opt.delay) results['1.2 netem_1M'] = exp.runalltests("netem_1M") exp.info("shutting down bridged session") # bridged with netem (54 kbps,500ms) exp.info("setting up bridged tests 3/2 with netem") exp.setneteffects(bw=54000, delay=100000) exp.info("waiting %s sec (queue bring-up)" % opt.delay) results['1.4 netem_54K'] = exp.runalltests("netem_54K") exp.info("shutting down bridged session") exp.reset() # EMANE bypass model exp.info("setting up EMANE tests 1/2 with bypass model") exp.createemanesession(numnodes=opt.numnodes, verbose=opt.verbose, cls=EmaneBypassModel, values=None) exp.setnodes() exp.info("waiting %s sec (node/route bring-up)" % opt.delay) time.sleep(opt.delay) results['2.0 bypass'] = exp.runalltests("bypass") exp.info("shutting down bypass session") exp.reset() exp.info("waiting %s sec (between EMANE tests)" % opt.delay) time.sleep(opt.delay) # EMANE RF-PIPE model: no restrictions (max datarate) exp.info("setting up EMANE tests 2/4 with RF-PIPE model") rfpipevals = list(EmaneRfPipeModel.getdefaultvalues()) rfpnames = EmaneRfPipeModel.getnames() rfpipevals[ rfpnames.index('datarate') ] = '4294967295' # max value if emanever < Emane.EMANE091: rfpipevals[ rfpnames.index('pathlossmode') ] = '2ray' rfpipevals[ rfpnames.index('defaultconnectivitymode') ] = '1' else: rfpipevals[ rfpnames.index('propagationmodel') ] = '2ray' exp.createemanesession(numnodes=opt.numnodes, verbose=opt.verbose, cls=EmaneRfPipeModel, values=rfpipevals) exp.setnodes() exp.info("waiting %s sec (node/route bring-up)" % opt.delay) time.sleep(opt.delay) results['3.0 rfpipe'] = exp.runalltests("rfpipe") exp.info("shutting down RF-PIPE session") exp.reset() # EMANE RF-PIPE model: 54M datarate exp.info("setting up EMANE tests 3/4 with RF-PIPE model 54M") rfpipevals = list(EmaneRfPipeModel.getdefaultvalues()) rfpnames = EmaneRfPipeModel.getnames() rfpipevals[ rfpnames.index('datarate') ] = '54000000' # TX delay != propagation delay #rfpipevals[ rfpnames.index('delay') ] = '5000' if emanever < Emane.EMANE091: rfpipevals[ rfpnames.index('pathlossmode') ] = '2ray' rfpipevals[ rfpnames.index('defaultconnectivitymode') ] = '1' else: rfpipevals[ rfpnames.index('propagationmodel') ] = '2ray' exp.createemanesession(numnodes=opt.numnodes, verbose=opt.verbose, cls=EmaneRfPipeModel, values=rfpipevals) exp.setnodes() exp.info("waiting %s sec (node/route bring-up)" % opt.delay) time.sleep(opt.delay) results['4.0 rfpipe54m'] = exp.runalltests("rfpipe54m") exp.info("shutting down RF-PIPE session") exp.reset() # EMANE RF-PIPE model: 54K datarate exp.info("setting up EMANE tests 4/4 with RF-PIPE model pathloss") rfpipevals = list(EmaneRfPipeModel.getdefaultvalues()) rfpnames = EmaneRfPipeModel.getnames() rfpipevals[ rfpnames.index('datarate') ] = '54000' if emanever < Emane.EMANE091: rfpipevals[ rfpnames.index('pathlossmode') ] = 'pathloss' rfpipevals[ rfpnames.index('defaultconnectivitymode') ] = '0' else: rfpipevals[ rfpnames.index('propagationmodel') ] = 'precomputed' exp.createemanesession(numnodes=opt.numnodes, verbose=opt.verbose, cls=EmaneRfPipeModel, values=rfpipevals) exp.setnodes() exp.info("waiting %s sec (node/route bring-up)" % opt.delay) time.sleep(opt.delay) exp.info("sending pathloss events to govern connectivity") exp.setpathloss(opt.numnodes) results['5.0 pathloss'] = exp.runalltests("pathloss") exp.info("shutting down RF-PIPE session") exp.reset() # EMANE RF-PIPE model (512K, 200ms) exp.info("setting up EMANE tests 4/4 with RF-PIPE model pathloss") rfpipevals = list(EmaneRfPipeModel.getdefaultvalues()) rfpnames = EmaneRfPipeModel.getnames() rfpipevals[ rfpnames.index('datarate') ] = '512000' rfpipevals[ rfpnames.index('delay') ] = '200' rfpipevals[ rfpnames.index('pathlossmode') ] = 'pathloss' rfpipevals[ rfpnames.index('defaultconnectivitymode') ] = '0' exp.createemanesession(numnodes=opt.numnodes, verbose=opt.verbose, cls=EmaneRfPipeModel, values=rfpipevals) exp.setnodes() exp.info("waiting %s sec (node/route bring-up)" % opt.delay) time.sleep(opt.delay) exp.info("sending pathloss events to govern connectivity") exp.setpathloss(opt.numnodes) results['5.1 pathloss'] = exp.runalltests("pathloss") exp.info("shutting down RF-PIPE session") exp.reset() # summary of results in CSV format exp.info("----- summary of results (%s nodes, rate=%s, duration=%s) -----" \ % (opt.numnodes, opt.rate, opt.duration)) exp.info("netname:latency,mdev,throughput,cpu,loss") for test in sorted(results.keys()): (latency, mdev, throughput, cpu, loss) = results[test] exp.info("%s:%.03f,%.03f,%d,%.02f,%.02f" % \ (test, latency, mdev, throughput, cpu,loss)) exp.logend() return exp if __name__ == "__main__": exp = main() core-4.8/daemon/examples/netns/wlantest.py0000775000175000017500000000651012534327775015707 00000000000000#!/usr/bin/python # Copyright (c)2010-2012 the Boeing Company. # See the LICENSE file included in this distribution. # run iperf to measure the effective throughput between two nodes when # n nodes are connected to a virtual wlan; run test for testsec # and repeat for minnodes <= n <= maxnodes with a step size of # nodestep import optparse, sys, os, datetime from core import pycore from core.misc import ipaddr from core.misc.utils import mutecall try: mutecall(["iperf", "-v"]) except OSError: sys.stderr.write("ERROR: running iperf failed\n") sys.exit(1) def test(numnodes, testsec): # node list n = [] # IP subnet prefix = ipaddr.IPv4Prefix("10.83.0.0/16") session = pycore.Session() # emulated network net = session.addobj(cls = pycore.nodes.WlanNode) for i in xrange(1, numnodes + 1): tmp = session.addobj(cls = pycore.nodes.LxcNode, objid= "%d" % i, name = "n%d" % i) tmp.newnetif(net, ["%s/%s" % (prefix.addr(i), prefix.prefixlen)]) n.append(tmp) net.link(n[0].netif(0), n[-1].netif(0)) n[0].cmd(["iperf", "-s", "-D"]) n[-1].icmd(["iperf", "-t", str(int(testsec)), "-c", str(prefix.addr(1))]) n[0].cmd(["killall", "-9", "iperf"]) session.shutdown() def main(): usagestr = "usage: %prog [-h] [options] [args]" parser = optparse.OptionParser(usage = usagestr) parser.set_defaults(minnodes = 2) parser.add_option("-m", "--minnodes", dest = "minnodes", type = int, help = "min number of nodes to test; default = %s" % parser.defaults["minnodes"]) parser.set_defaults(maxnodes = 2) parser.add_option("-n", "--maxnodes", dest = "maxnodes", type = int, help = "max number of nodes to test; default = %s" % parser.defaults["maxnodes"]) parser.set_defaults(testsec = 10) parser.add_option("-t", "--testsec", dest = "testsec", type = int, help = "test time in seconds; default = %s" % parser.defaults["testsec"]) parser.set_defaults(nodestep = 1) parser.add_option("-s", "--nodestep", dest = "nodestep", type = int, help = "number of nodes step size; default = %s" % parser.defaults["nodestep"]) def usage(msg = None, err = 0): sys.stdout.write("\n") if msg: sys.stdout.write(msg + "\n\n") parser.print_help() sys.exit(err) # parse command line options (options, args) = parser.parse_args() if options.minnodes < 2: usage("invalid min number of nodes: %s" % options.minnodes) if options.maxnodes < options.minnodes: usage("invalid max number of nodes: %s" % options.maxnodes) if options.testsec < 1: usage("invalid test time: %s" % options.testsec) if options.nodestep < 1: usage("invalid node step: %s" % options.nodestep) for a in args: sys.stderr.write("ignoring command line argument: '%s'\n" % a) start = datetime.datetime.now() for i in xrange(options.minnodes, options.maxnodes + 1, options.nodestep): print >> sys.stderr, "%s node test:" % i test(i, options.testsec) print >> sys.stderr, "" print >> sys.stderr, \ "elapsed time: %s" % (datetime.datetime.now() - start) if __name__ == "__main__": main() core-4.8/daemon/examples/services/0000775000175000017500000000000012534330007014221 500000000000000core-4.8/daemon/examples/services/sampleFirewall0000664000175000017500000000200612534327775017053 00000000000000# -------- CUSTOMIZATION REQUIRED -------- # # Below are sample iptables firewall rules that you can uncomment and edit. # You can also use ip6tables rules for IPv6. # # start by flushing all firewall rules (so this script may be re-run) #iptables -F # allow traffic related to established connections #iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT # allow TCP packets from any source destined for 192.168.1.1 #iptables -A INPUT -s 0/0 -i eth0 -d 192.168.1.1 -p TCP -j ACCEPT # allow OpenVPN server traffic from eth0 #iptables -A INPUT -p udp --dport 1194 -j ACCEPT #iptables -A INPUT -i eth0 -j DROP #iptables -A OUTPUT -p udp --sport 1194 -j ACCEPT #iptables -A OUTPUT -o eth0 -j DROP # allow ICMP ping traffic #iptables -A OUTPUT -p icmp --icmp-type echo-request -j ACCEPT #iptables -A INPUT -p icmp --icmp-type echo-reply -j ACCEPT # allow SSH traffic #iptables -A -p tcp -m state --state NEW -m tcp --dport 22 -j ACCEPT # drop all other traffic coming in eth0 #iptables -A INPUT -i eth0 -j DROP core-4.8/daemon/examples/services/sampleIPsec0000664000175000017500000000727412534327775016325 00000000000000# -------- CUSTOMIZATION REQUIRED -------- # # The IPsec service builds ESP tunnels between the specified peers using the # racoon IKEv2 keying daemon. You need to provide keys and the addresses of # peers, along with subnets to tunnel. # directory containing the certificate and key described below keydir=/etc/core/keys # the name used for the "$certname.pem" x509 certificate and # "$certname.key" RSA private key, which can be generated using openssl certname=ipsec1 # list the public-facing IP addresses, starting with the localhost and followed # by each tunnel peer, separated with a single space tunnelhosts="172.16.0.1AND172.16.0.2 172.16.0.1AND172.16.2.1" # Define T where i is the index for each tunnel peer host from # the tunnel_hosts list above (0 is localhost). # T is a list of IPsec tunnels with peer i, with a local subnet address # followed by the remote subnet address: # T="AND AND" # For example, 172.16.0.0/24 is a local network (behind this node) to be # tunneled and 172.16.2.0/24 is a remote network (behind peer 1) T1="172.16.3.0/24AND172.16.5.0/24" T2="172.16.4.0/24AND172.16.5.0/24 172.16.4.0/24AND172.16.6.0/24" # -------- END CUSTOMIZATION -------- echo "building config $PWD/ipsec.conf..." echo "building config $PWD/ipsec.conf..." > $PWD/ipsec.log checkip=0 if [ "$(dpkg -l | grep " sipcalc ")" = "" ]; then echo "WARNING: ip validation disabled because package sipcalc not installed " >> $PWD/ipsec.log checkip=1 fi echo "#!/usr/sbin/setkey -f # Flush the SAD and SPD flush; spdflush; # Security policies \ " > $PWD/ipsec.conf i=0 for hostpair in $tunnelhosts; do i=`expr $i + 1` # parse tunnel host IP thishost=${hostpair%%AND*} peerhost=${hostpair##*AND} if [ $checkip = "0" ] && [ "$(sipcalc "$thishost" "$peerhost" | grep ERR)" != "" ]; then echo "ERROR: invalid host address $thishost or $peerhost \ " >> $PWD/ipsec.log fi # parse each tunnel addresses tunnel_list_var_name=T$i eval tunnels="$"$tunnel_list_var_name"" for ttunnel in $tunnels; do lclnet=${ttunnel%%AND*} rmtnet=${ttunnel##*AND} if [ $checkip = "0" ] && [ "$(sipcalc "$lclnet" "$rmtnet"| grep ERR)" != "" ]; then echo "ERROR: invalid tunnel address $lclnet and $rmtnet \ " >> $PWD/ipsec.log fi # add tunnel policies echo " spdadd $lclnet $rmtnet any -P out ipsec esp/tunnel/$thishost-$peerhost/require; spdadd $rmtnet $lclnet any -P in ipsec esp/tunnel/$peerhost-$thishost/require; \ " >> $PWD/ipsec.conf done done echo "building config $PWD/racoon.conf..." if [ ! -e $keydir\/$certname.key ] || [ ! -e $keydir\/$certname.pem ]; then echo "ERROR: missing certification files under $keydir \ $certname.key or $certname.pem " >> $PWD/ipsec.log fi echo " path certificate \"$keydir\"; listen { adminsock disabled; } remote anonymous { exchange_mode main; certificate_type x509 \"$certname.pem\" \"$certname.key\"; ca_type x509 \"ca-cert.pem\"; my_identifier asn1dn; peers_identifier asn1dn; proposal { encryption_algorithm 3des ; hash_algorithm sha1; authentication_method rsasig ; dh_group modp768; } } sainfo anonymous { pfs_group modp768; lifetime time 1 hour ; encryption_algorithm 3des, blowfish 448, rijndael ; authentication_algorithm hmac_sha1, hmac_md5 ; compression_algorithm deflate ; } " > $PWD/racoon.conf # the setkey program is required from the ipsec-tools package echo "running setkey -f $PWD/ipsec.conf..." setkey -f $PWD/ipsec.conf echo "running racoon -d -f $PWD/racoon.conf..." racoon -d -f $PWD/racoon.conf -l racoon.log core-4.8/daemon/examples/services/sampleVPNClient0000664000175000017500000000336312534327775017117 00000000000000# -------- CUSTOMIZATION REQUIRED -------- # # The VPNClient service builds a VPN tunnel to the specified VPN server using # OpenVPN software and a virtual TUN/TAP device. # directory containing the certificate and key described below keydir=/etc/core/keys # the name used for a "$keyname.crt" certificate and "$keyname.key" private key. keyname=client1 # the public IP address of the VPN server this client should connect with vpnserver="10.0.2.10" # optional next hop for adding a static route to reach the VPN server nexthop="10.0.1.1" # --------- END CUSTOMIZATION -------- # validate addresses if [ "$(dpkg -l | grep " sipcalc ")" = "" ]; then echo "WARNING: ip validation disabled because package sipcalc not installed " > $PWD/vpnclient.log else if [ "$(sipcalc "$vpnserver" "$nexthop" | grep ERR)" != "" ]; then echo "ERROR: invalide address $vpnserver or $nexthop \ " > $PWD/vpnclient.log fi fi # validate key and certification files if [ ! -e $keydir\/$keyname.key ] || [ ! -e $keydir\/$keyname.crt ] \ || [ ! -e $keydir\/ca.crt ] || [ ! -e $keydir\/dh1024.pem ]; then echo "ERROR: missing certification or key files under $keydir \ $keyname.key or $keyname.crt or ca.crt or dh1024.pem" >> $PWD/vpnclient.log fi # if necessary, add a static route for reaching the VPN server IP via the IF vpnservernet=${vpnserver%.*}.0/24 if [ "$nexthop" != "" ]; then /sbin/ip route add $vpnservernet via $nexthop fi # create openvpn client.conf ( cat << EOF client dev tun proto udp remote $vpnserver 1194 nobind ca $keydir/ca.crt cert $keydir/$keyname.crt key $keydir/$keyname.key dh $keydir/dh1024.pem cipher AES-256-CBC log $PWD/openvpn-client.log verb 4 daemon EOF ) > client.conf openvpn --config client.conf core-4.8/daemon/examples/services/sampleVPNServer0000664000175000017500000001116112534327775017142 00000000000000# -------- CUSTOMIZATION REQUIRED -------- # # The VPNServer service sets up the OpenVPN server for building VPN tunnels # that allow access via TUN/TAP device to private networks. # # note that the IPForward and DefaultRoute services should be enabled # directory containing the certificate and key described below, in addition to # a CA certificate and DH key keydir=/etc/core/keys # the name used for a "$keyname.crt" certificate and "$keyname.key" private key. keyname=server2 # the VPN subnet address from which the client VPN IP (for the TUN/TAP) # will be allocated vpnsubnet=10.0.200.0 # public IP address of this vpn server (same as VPNClient vpnserver= setting) vpnserver=10.0.2.10 # optional list of private subnets reachable behind this VPN server # each subnet and next hop is separated by a space # ", , ..." privatenets="10.0.11.0,10.0.10.1 10.0.12.0,10.0.10.1" # optional list of VPN clients, for statically assigning IP addresses to # clients; also, an optional client subnet can be specified for adding static # routes via the client # Note: VPN addresses x.x.x.0-3 are reserved # ",, ,, ..." vpnclients="client1KeyFilename,10.0.200.5,10.0.0.0 client2KeyFilename,," # NOTE: you may need to enable the StaticRoutes service on nodes within the # private subnet, in order to have routes back to the client. # /sbin/ip ro add /24 via # /sbin/ip ro add /24 via # -------- END CUSTOMIZATION -------- echo > $PWD/vpnserver.log rm -f -r $PWD/ccd # validate key and certification files if [ ! -e $keydir\/$keyname.key ] || [ ! -e $keydir\/$keyname.crt ] \ || [ ! -e $keydir\/ca.crt ] || [ ! -e $keydir\/dh1024.pem ]; then echo "ERROR: missing certification or key files under $keydir \ $keyname.key or $keyname.crt or ca.crt or dh1024.pem" >> $PWD/vpnserver.log fi # validate configuration IP addresses checkip=0 if [ "$(dpkg -l | grep " sipcalc ")" = "" ]; then echo "WARNING: ip validation disabled because package sipcalc not installed\ " >> $PWD/vpnserver.log checkip=1 else if [ "$(sipcalc "$vpnsubnet" "$vpnserver" | grep ERR)" != "" ]; then echo "ERROR: invalid vpn subnet or server address \ $vpnsubnet or $vpnserver " >> $PWD/vpnserver.log fi fi # create client vpn ip pool file ( cat << EOF EOF )> $PWD/ippool.txt # create server.conf file ( cat << EOF # openvpn server config local $vpnserver server $vpnsubnet 255.255.255.0 push redirect-gateway def1 EOF )> $PWD/server.conf # add routes to VPN server private subnets, and push these routes to clients for privatenet in $privatenets; do if [ $privatenet != "" ]; then net=${privatenet%%,*} nexthop=${privatenet##*,} if [ $checkip = "0" ] && [ "$(sipcalc "$net" "$nexthop" | grep ERR)" != "" ]; then echo "ERROR: invalid vpn server private net address \ $net or $nexthop " >> $PWD/vpnserver.log fi echo push route $net 255.255.255.0 >> $PWD/server.conf /sbin/ip ro add $net/24 via $nexthop /sbin/ip ro add $vpnsubnet/24 via $nexthop fi done # allow subnet through this VPN, one route for each client subnet for client in $vpnclients; do if [ $client != "" ]; then cSubnetIP=${client##*,} cVpnIP=${client#*,} cVpnIP=${cVpnIP%%,*} cKeyFilename=${client%%,*} if [ "$cSubnetIP" != "" ]; then if [ $checkip = "0" ] && [ "$(sipcalc "$cSubnetIP" "$cVpnIP" | grep ERR)" != "" ]; then echo "ERROR: invalid vpn client and subnet address \ $cSubnetIP or $cVpnIP " >> $PWD/vpnserver.log fi echo route $cSubnetIP 255.255.255.0 >> $PWD/server.conf if ! test -d $PWD/ccd; then mkdir -p $PWD/ccd echo client-config-dir $PWD/ccd >> $PWD/server.conf fi if test -e $PWD/ccd/$cKeyFilename; then echo iroute $cSubnetIP 255.255.255.0 >> $PWD/ccd/$cKeyFilename else echo iroute $cSubnetIP 255.255.255.0 > $PWD/ccd/$cKeyFilename fi fi if [ "$cVpnIP" != "" ]; then echo $cKeyFilename,$cVpnIP >> $PWD/ippool.txt fi fi done ( cat << EOF keepalive 10 120 ca $keydir/ca.crt cert $keydir/$keyname.crt key $keydir/$keyname.key dh $keydir/dh1024.pem cipher AES-256-CBC status /var/log/openvpn-status.log log /var/log/openvpn-server.log ifconfig-pool-linear ifconfig-pool-persist $PWD/ippool.txt port 1194 proto udp dev tun verb 4 daemon EOF )>> $PWD/server.conf # start vpn server openvpn --config server.conf core-4.8/daemon/examples/controlnet_updown0000775000175000017500000000216512534327775016055 00000000000000#!/bin/bash # Sample controlnet up/down script that will be executed when the control # network is brought up or down. This script either adds an interface to the # controlnet bridge or adds a permissive iptables firewall rule. controlnet_intf=$1 action=$2 config_type=iptables # iptables or brctl iptables_address=10.205.15.132 brctl_intf=eth2 BRCTL=/sbin/brctl IPTABLES=/usr/sbin/iptables case "$action" in startup) case "$config_type" in iptables) $IPTABLES -I FORWARD -i $controlnet_intf -d $iptables_address -j ACCEPT $IPTABLES -I FORWARD -o $controlnet_intf -s $iptables_address -j ACCEPT ;; brctl) $BRCTL addif $controlnet_intf $brctl_intf ;; *) echo "Invalid config_type $config_type" ;; esac ;; shutdown) case "$config_type" in iptables) $IPTABLES -D FORWARD -i $controlnet_intf -d $iptables_address -j ACCEPT $IPTABLES -D FORWARD -o $controlnet_intf -s $iptables_address -j ACCEPT ;; brctl) $BRCTL delif $controlnet_intf $brctl_intf ;; *) echo "Invalid config_type $config_type" ;; esac ;; *) echo "Invalid action $action" exit 1 ;; esac exit 0 core-4.8/daemon/examples/emanemodel2core.py0000775000175000017500000001342712534327775015765 00000000000000#!/usr/bin/env python # # CORE # Copyright (c) 2013 the Boeing Company. # See the LICENSE file included in this distribution. # # author: Jeff Ahrenholz # ''' emanemodel2core.py: scans an EMANE model source file (e.g. emane/models/rfpipe/maclayer/rfpipemaclayer.cc) and outputs Python bindings that allow the model to be used in CORE. When using this conversion utility, you should replace XYZ, Xyz, and xyz with the actual model name. Note the capitalization convention. ''' import os, sys, optparse MODEL_TEMPLATE_PART1 = """ # # CORE # Copyright (c)2013 Company. # See the LICENSE file included in this distribution. # # author: Name # ''' xyz.py: EMANE XYZ model bindings for CORE ''' from core.api import coreapi from emane import EmaneModel from universal import EmaneUniversalModel class EmaneXyzModel(EmaneModel): def __init__(self, session, objid = None, verbose = False): EmaneModel.__init__(self, session, objid, verbose) # model name _name = "emane_xyz" # MAC parameters _confmatrix_mac = [ """ MODEL_TEMPLATE_PART2 = """ ] # PHY parameters from Universal PHY _confmatrix_phy = EmaneUniversalModel._confmatrix _confmatrix = _confmatrix_mac + _confmatrix_phy # value groupings _confgroups = "XYZ MAC Parameters:1-%d|Universal PHY Parameters:%d-%d" \ % ( len(_confmatrix_mac), len(_confmatrix_mac) + 1, len(_confmatrix)) def buildnemxmlfiles(self, e, ifc): ''' Build the necessary nem, mac, and phy XMLs in the given path. If an individual NEM has a nonstandard config, we need to build that file also. Otherwise the WLAN-wide nXXemane_xyznem.xml, nXXemane_xyzmac.xml, nXXemane_xyzphy.xml are used. ''' values = e.getifcconfig(self.objid, self._name, self.getdefaultvalues(), ifc) if values is None: return nemdoc = e.xmldoc("nem") nem = nemdoc.getElementsByTagName("nem").pop() nem.setAttribute("name", "XYZ NEM") mactag = nemdoc.createElement("mac") mactag.setAttribute("definition", self.macxmlname(ifc)) nem.appendChild(mactag) phytag = nemdoc.createElement("phy") phytag.setAttribute("definition", self.phyxmlname(ifc)) nem.appendChild(phytag) e.xmlwrite(nemdoc, self.nemxmlname(ifc)) names = list(self.getnames()) macnames = names[:len(self._confmatrix_mac)] phynames = names[len(self._confmatrix_mac):] # make any changes to the mac/phy names here to e.g. exclude them from # the XML output macdoc = e.xmldoc("mac") mac = macdoc.getElementsByTagName("mac").pop() mac.setAttribute("name", "XYZ MAC") mac.setAttribute("library", "xyzmaclayer") # append MAC options to macdoc map( lambda n: mac.appendChild(e.xmlparam(macdoc, n, \ self.valueof(n, values))), macnames) e.xmlwrite(macdoc, self.macxmlname(ifc)) phydoc = EmaneUniversalModel.getphydoc(e, self, values, phynames) e.xmlwrite(phydoc, self.phyxmlname(ifc)) """ def emane_model_source_to_core(infile, outfile): do_parse_line = False output = MODEL_TEMPLATE_PART1 with open(infile, 'r') as f: for line in f: # begin marker if "EMANE::ConfigurationDefinition" in line: do_parse_line = True # end marker -- all done if "{0, 0, 0, 0, 0, 0" in line: break if do_parse_line: outstr = convert_line(line) if outstr is not None: output += outstr continue output += MODEL_TEMPLATE_PART2 if outfile == sys.stdout: sys.stdout.write(output) else: with open(outfile, 'w') as f: f.write(output) def convert_line(line): line = line.strip() # skip comments if line.startswith(('/*', '//')): return None items = line.strip('{},').split(',') if len(items) != 7: #print "continuning on line=", len(items), items return None return convert_items_to_line(items) def convert_items_to_line(items): fields = ('required', 'default', 'count', 'name', 'value', 'type', 'description') getfield = lambda(x): items[fields.index(x)].strip() output = " (" output += "%s, " % getfield('name') value = getfield('value') if value == '"off"': type = "coreapi.CONF_DATA_TYPE_BOOL" value = "0" defaults = '"On,Off"' elif value == '"on"': type = "coreapi.CONF_DATA_TYPE_BOOL" value = '"1"' defaults = '"On,Off"' else: type = "coreapi.CONF_DATA_TYPE_STRING" defaults = '""' output += "%s, %s, %s, " % (type, value, defaults) output += getfield('description') output += "),\n" return output def main(): usagestr = "usage: %prog [-h] [options] -- ..." parser = optparse.OptionParser(usage = usagestr) parser.set_defaults(infile = None, outfile = sys.stdout) parser.add_option("-i", "--infile", dest = "infile", help = "file to read (usually '*mac.cc')") parser.add_option("-o", "--outfile", dest = "outfile", help = "file to write (stdout is default)") def usage(msg = None, err = 0): sys.stdout.write("\n") if msg: sys.stdout.write(msg + "\n\n") parser.print_help() sys.exit(err) # parse command line options (options, args) = parser.parse_args() if options.infile is None: usage("please specify input file with the '-i' option", err=1) emane_model_source_to_core(options.infile, options.outfile) if __name__ == "__main__": main() core-4.8/daemon/examples/findcore.py0000775000175000017500000000424112534327775014507 00000000000000#!/usr/bin/env python # # Search for installed CORE library files and Python bindings. # import os, glob pythondirs = [ "/usr/lib/python2.7/site-packages", "/usr/lib/python2.7/dist-packages", "/usr/lib64/python2.7/site-packages", "/usr/lib64/python2.7/dist-packages", "/usr/local/lib/python2.7/site-packages", "/usr/local/lib/python2.7/dist-packages", "/usr/local/lib64/python2.7/site-packages", "/usr/local/lib64/python2.7/dist-packages", "/usr/lib/python2.6/site-packages", "/usr/lib/python2.6/dist-packages", "/usr/lib64/python2.6/site-packages", "/usr/lib64/python2.6/dist-packages", "/usr/local/lib/python2.6/site-packages", "/usr/local/lib/python2.6/dist-packages", "/usr/local/lib64/python2.6/site-packages", "/usr/local/lib64/python2.6/dist-packages", ] tcldirs = [ "/usr/lib/core", "/usr/local/lib/core", ] def find_in_file(fn, search, column=None): ''' Find a line starting with 'search' in the file given by the filename 'fn'. Return True if found, False if not found, or the column text if column is specified. ''' r = False if not os.path.exists(fn): return r f = open(fn, "r") for line in f: if line[:len(search)] != search: continue r = True if column is not None: r = line.split()[column] break f.close() return r def main(): versions = [] for d in pythondirs: fn = "%s/core/constants.py" % d ver = find_in_file(fn, 'COREDPY_VERSION', 2) if ver: ver = ver.strip('"') versions.append((d, ver)) for e in glob.iglob("%s/core_python*egg-info" % d): ver = find_in_file(e, 'Version:', 1) if ver: versions.append((e, ver)) for e in glob.iglob("%s/netns*egg-info" % d): ver = find_in_file(e, 'Version:', 1) if ver: versions.append((e, ver)) for d in tcldirs: fn = "%s/version.tcl" % d ver = find_in_file(fn, 'set CORE_VERSION', 2) if ver: versions.append((d, ver)) for (d, ver) in versions: print "%8s %s" % (ver, d) if __name__ == "__main__": main() core-4.8/daemon/examples/stopsession.py0000775000175000017500000000262112534327775015307 00000000000000#!/usr/bin/env python # (c)2010-2012 the Boeing Company # author: Jeff Ahrenholz # # List and stop CORE sessions from the command line. # import socket, optparse from core.constants import * from core.api import coreapi def main(): parser = optparse.OptionParser(usage = "usage: %prog [-l] ") parser.add_option("-l", "--list", dest = "list", action = "store_true", help = "list running sessions") (options, args) = parser.parse_args() if options.list is True: num = '0' flags = coreapi.CORE_API_STR_FLAG else: num = args[0] flags = coreapi.CORE_API_DEL_FLAG tlvdata = coreapi.CoreSessionTlv.pack(coreapi.CORE_TLV_SESS_NUMBER, num) msg = coreapi.CoreSessionMessage.pack(flags, tlvdata) sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.connect(('localhost', coreapi.CORE_API_PORT)) sock.send(msg) # receive and print a session list if options.list is True: hdr = sock.recv(coreapi.CoreMessage.hdrsiz) msgtype, msgflags, msglen = coreapi.CoreMessage.unpackhdr(hdr) data = "" if msglen: data = sock.recv(msglen) msg = coreapi.CoreMessage(msgflags, hdr, data) sessions = msg.gettlv(coreapi.CORE_TLV_SESS_NUMBER) print "sessions:", sessions sock.close() if __name__ == "__main__": main() core-4.8/daemon/sbin/0000775000175000017500000000000012534330007011513 500000000000000core-4.8/daemon/sbin/core-cleanup0000775000175000017500000000346712534327775013772 00000000000000#!/bin/sh if [ "z$1" = "z-h" -o "z$1" = "z--help" ]; then echo "usage: $0 [-d [-l]]" echo -n " Clean up all CORE namespaces processes, bridges, interfaces, " echo "and session\n directories. Options:" echo " -h show this help message and exit" echo " -d also kill the Python daemon" echo " -l remove the core-daemon.log file" exit 0 fi if [ `id -u` != 0 ]; then echo "Permission denied. Re-run this script as root." exit 1 fi PATH="/sbin:/bin:/usr/sbin:/usr/bin" export PATH if [ "z$1" = "z-d" ]; then pypids=`pidof python python2` for p in $pypids; do grep -q core-daemon /proc/$p/cmdline if [ $? = 0 ]; then echo "cleaning up core-daemon process: $p" kill -9 $p fi done fi if [ "z$2" = "z-l" ]; then rm -f /var/log/core-daemon.log fi vnodedpids=`pidof vnoded` if [ "z$vnodedpids" != "z" ]; then echo "cleaning up old vnoded processes: $vnodedpids" killall -v -KILL vnoded # pause for 1 second for interfaces to disappear sleep 1 fi killall -q emane killall -q emanetransportd killall -q emaneeventservice if [ -d /sys/class/net ]; then ifcommand="ls -1 /sys/class/net" else ifcommand="ip -o link show | sed -r -e 's/[0-9]+: ([^[:space:]]+): .*/\1/'" fi eval "$ifcommand" | awk ' /^veth[0-9]+\./ {print "removing interface " $1; system("ip link del " $1);} /tmp\./ {print "removing interface " $1; system("ip link del " $1);} /gt\./ {print "removing interface " $1; system("ip link del " $1);} /b\./ {print "removing bridge " $1; system("ip link set " $1 " down; brctl delbr " $1);} ' ebtables -L FORWARD | awk ' /^-.*b\./ {print "removing ebtables " $0; system("ebtables -D FORWARD " $0); print "removing ebtables chain " $4; system("ebtables -X " $4);} ' rm -rf /tmp/pycore* core-4.8/daemon/sbin/core-daemon0000775000175000017500000022602412534327775013602 00000000000000#!/usr/bin/env python # # CORE # Copyright (c)2010-2013 the Boeing Company. # See the LICENSE file included in this distribution. # # authors: Tom Goff # Jeff Ahrenholz # ''' core-daemon: the CORE daemon is a server process that receives CORE API messages and instantiates emulated nodes and networks within the kernel. Various message handlers are defined and some support for sending messages. ''' import SocketServer, fcntl, struct, sys, threading, time, traceback import os, optparse, ConfigParser, gc, shlex, socket, shutil import atexit import signal try: from core import pycore except ImportError: # hack for Fedora autoconf that uses the following pythondir: if "/usr/lib/python2.6/site-packages" in sys.path: sys.path.append("/usr/local/lib/python2.6/site-packages") if "/usr/lib64/python2.6/site-packages" in sys.path: sys.path.append("/usr/local/lib64/python2.6/site-packages") if "/usr/lib/python2.7/site-packages" in sys.path: sys.path.append("/usr/local/lib/python2.7/site-packages") if "/usr/lib64/python2.7/site-packages" in sys.path: sys.path.append("/usr/local/lib64/python2.7/site-packages") from core import pycore from core.constants import * from core.api import coreapi from core.coreobj import PyCoreNet from core.misc.utils import hexdump, daemonize, cmdresult, mutedetach from core.misc.xmlsession import opensessionxml, savesessionxml DEFAULT_MAXFD = 1024 # garbage collection debugging # gc.set_debug(gc.DEBUG_STATS | gc.DEBUG_LEAK) coreapi.add_node_class("CORE_NODE_DEF", coreapi.CORE_NODE_DEF, pycore.nodes.CoreNode) coreapi.add_node_class("CORE_NODE_PHYS", coreapi.CORE_NODE_PHYS, pycore.pnodes.PhysicalNode) try: coreapi.add_node_class("CORE_NODE_XEN", coreapi.CORE_NODE_XEN, pycore.xen.XenNode) except Exception: #print "XenNode class unavailable." pass coreapi.add_node_class("CORE_NODE_TBD", coreapi.CORE_NODE_TBD, None) coreapi.add_node_class("CORE_NODE_SWITCH", coreapi.CORE_NODE_SWITCH, pycore.nodes.SwitchNode) coreapi.add_node_class("CORE_NODE_HUB", coreapi.CORE_NODE_HUB, pycore.nodes.HubNode) coreapi.add_node_class("CORE_NODE_WLAN", coreapi.CORE_NODE_WLAN, pycore.nodes.WlanNode) coreapi.add_node_class("CORE_NODE_RJ45", coreapi.CORE_NODE_RJ45, pycore.nodes.RJ45Node) coreapi.add_node_class("CORE_NODE_TUNNEL", coreapi.CORE_NODE_TUNNEL, pycore.nodes.TunnelNode) coreapi.add_node_class("CORE_NODE_EMANE", coreapi.CORE_NODE_EMANE, pycore.nodes.EmaneNode) def closeonexec(fd): fdflags = fcntl.fcntl(fd, fcntl.F_GETFD) fcntl.fcntl(fd, fcntl.F_SETFD, fdflags | fcntl.FD_CLOEXEC) class CoreRequestHandler(SocketServer.BaseRequestHandler): ''' The SocketServer class uses the RequestHandler class for servicing requests, mainly through the handle() method. The CoreRequestHandler has the following basic flow: 1. Client connects and request comes in via handle(). 2. handle() calls recvmsg() in a loop. 3. recvmsg() does a recv() call on the socket performs basic checks that this we received a CoreMessage, returning it. 4. The message data is queued using queuemsg(). 5. The handlerthread() thread pops messages from the queue and uses handlemsg() to invoke the appropriate handler for that message type. ''' maxmsgqueuedtimes = 8 def __init__(self, request, client_address, server): self.done = False self.msghandler = { coreapi.CORE_API_NODE_MSG: self.handlenodemsg, coreapi.CORE_API_LINK_MSG: self.handlelinkmsg, coreapi.CORE_API_EXEC_MSG: self.handleexecmsg, coreapi.CORE_API_REG_MSG: self.handleregmsg, coreapi.CORE_API_CONF_MSG: self.handleconfmsg, coreapi.CORE_API_FILE_MSG: self.handlefilemsg, coreapi.CORE_API_IFACE_MSG: self.handleifacemsg, coreapi.CORE_API_EVENT_MSG: self.handleeventmsg, coreapi.CORE_API_SESS_MSG: self.handlesessionmsg, } self.msgq = [] self.msgcv = threading.Condition() self.nodestatusreq = {} numthreads = int(server.cfg['numthreads']) if numthreads < 1: raise ValueError, \ "invalid number of threads: %s" % numthreads self.handlerthreads = [] while numthreads: t = threading.Thread(target = self.handlerthread) self.handlerthreads.append(t) t.start() numthreads -= 1 self.master = False self.verbose = bool(server.cfg['verbose'].lower() == "true") self.debug = bool(server.cfg['debug'].lower() == "true") self.session = None #self.numwlan = 0 closeonexec(request.fileno()) SocketServer.BaseRequestHandler.__init__(self, request, client_address, server) def setup(self): ''' Client has connected, set up a new connection. ''' self.info("new TCP connection: %s:%s" % self.client_address) #self.register() def finish(self): ''' Client has disconnected, end this request handler and disconnect from the session. Shutdown sessions that are not running. ''' if self.verbose: self.info("client disconnected: notifying threads") max_attempts = 5 timeout = 0.0625 # wait for 1.9375s max while len(self.msgq) > 0 and max_attempts > 0: if self.verbose: self.info("%d messages remain in queue (%d)" % \ (len(self.msgq), max_attempts)) max_attempts -= 1 self.msgcv.acquire() self.msgcv.notifyAll() # drain msgq before dying self.msgcv.release() time.sleep(timeout) # allow time for msg processing timeout *= 2 # backoff timer self.msgcv.acquire() self.done = True self.msgcv.notifyAll() self.msgcv.release() for t in self.handlerthreads: if self.verbose: self.info("waiting for thread: %s" % t.getName()) timeout = 2.0 # seconds t.join(timeout) if t.isAlive(): self.warn("joining %s failed: still alive after %s sec" % (t.getName(), timeout)) self.info("connection closed: %s:%s" % self.client_address) if self.session: self.session.disconnect(self) return SocketServer.BaseRequestHandler.finish(self) def info(self, msg): ''' Utility method for writing output to stdout. ''' print msg sys.stdout.flush() def warn(self, msg): ''' Utility method for writing output to stderr. ''' print >> sys.stderr, msg sys.stderr.flush() def register(self): ''' Return a Register Message ''' self.info("GUI has connected to session %d at %s" % \ (self.session.sessionid, time.ctime())) tlvdata = "" tlvdata += coreapi.CoreRegTlv.pack(coreapi.CORE_TLV_REG_EXECSRV, "core-daemon") tlvdata += coreapi.CoreRegTlv.pack(coreapi.CORE_TLV_REG_EMULSRV, "core-daemon") tlvdata += self.session.confobjs_to_tlvs() return coreapi.CoreRegMessage.pack(coreapi.CORE_API_ADD_FLAG, tlvdata) def sendall(self, data): ''' Send raw data to the other end of this TCP connection using socket's sendall(). ''' return self.request.sendall(data) def recvmsg(self): ''' Receive data and return a CORE API message object. ''' try: msghdr = self.request.recv(coreapi.CoreMessage.hdrsiz) if self.debug and len(msghdr) > 0: self.info("received message header:\n%s" % hexdump(msghdr)) except Exception, e: raise IOError, "error receiving header (%s)" % e if len(msghdr) != coreapi.CoreMessage.hdrsiz: if len(msghdr) == 0: raise EOFError, "client disconnected" else: raise IOError, "invalid message header size" msgtype, msgflags, msglen = coreapi.CoreMessage.unpackhdr(msghdr) if msglen == 0: self.warn("received message with no data") data = "" while len(data) < msglen: data += self.request.recv(msglen - len(data)) if self.debug: self.info("received message data:\n%s" % hexdump(data)) if len(data) > msglen: self.warn("received message length does not match received data " \ "(%s != %s)" % (len(data), msglen)) raise IOError try: msgcls = coreapi.msg_class(msgtype) msg = msgcls(msgflags, msghdr, data) except KeyError: msg = coreapi.CoreMessage(msgflags, msghdr, data) msg.msgtype = msgtype self.warn("unimplemented core message type: %s" % msg.typestr()) return msg def queuemsg(self, msg): ''' Queue an API message for later processing. ''' if msg.queuedtimes >= self.maxmsgqueuedtimes: self.warn("dropping message queued %d times: %s" % (msg.queuedtimes, msg)) return if self.debug: self.info("queueing msg (queuedtimes = %s): type %s" % (msg.queuedtimes, msg.msgtype)) msg.queuedtimes += 1 self.msgcv.acquire() self.msgq.append(msg) self.msgcv.notify() self.msgcv.release() def handlerthread(self): ''' CORE API message handling loop that is spawned for each server thread; get CORE API messages from the incoming message queue, and call handlemsg() for processing. ''' while not self.done: # get a coreapi.CoreMessage() from the incoming queue self.msgcv.acquire() while not self.msgq: self.msgcv.wait() if self.done: self.msgcv.release() return msg = self.msgq.pop(0) self.msgcv.release() self.handlemsg(msg) def handlemsg(self, msg): ''' Handle an incoming message; dispatch based on message type, optionally sending replies. ''' if self.session and self.session.broker.handlemsg(msg): if self.debug: self.info("%s forwarding message:\n%s" % (threading.currentThread().getName(), msg)) return if self.debug: self.info("%s handling message:\n%s" % (threading.currentThread().getName(), msg)) if msg.msgtype not in self.msghandler: self.warn("no handler for message type: %s" % msg.typestr()) return msghandler = self.msghandler[msg.msgtype] try: replies = msghandler(msg) for reply in replies: if self.debug: msgtype, msgflags, msglen = \ coreapi.CoreMessage.unpackhdr(reply) try: rmsg = coreapi.msg_class(msgtype)(msgflags, reply[:coreapi.CoreMessage.hdrsiz], reply[coreapi.CoreMessage.hdrsiz:]) except KeyError: # multiple TLVs of same type cause KeyError exception rmsg = "CoreMessage (type %d flags %d length %d)" % \ (msgtype, msgflags, msglen) self.info("%s: reply msg:\n%s" % (threading.currentThread().getName(), rmsg)) try: self.sendall(reply) except Exception, e: self.warn("Error sending reply data: %s" % e) except Exception, e: self.warn("%s: exception while handling msg:\n%s\n%s" % (threading.currentThread().getName(), msg, traceback.format_exc())) def handle(self): ''' Handle a new connection request from a client. Dispatch to the recvmsg() method for receiving data into CORE API messages, and add them to an incoming message queue. ''' # use port as session id port = self.request.getpeername()[1] self.session = self.server.getsession(sessionid = port, useexisting = False) self.session.connect(self) while True: try: msg = self.recvmsg() except EOFError: break except IOError, e: self.warn("IOError: %s" % e) break msg.queuedtimes = 0 self.queuemsg(msg) if (msg.msgtype == coreapi.CORE_API_SESS_MSG): # delay is required for brief connections, allow session joining time.sleep(0.125) self.session.broadcast(self, msg) #self.session.shutdown() #del self.session gc.collect() # print "gc count:", gc.get_count() # for o in gc.get_objects(): # if isinstance(o, pycore.PyCoreObj): # print "XXX XXX XXX PyCoreObj:", o # for r in gc.get_referrers(o): # print "XXX XXX XXX referrer:", gc.get_referrers(o) def handlenodemsg(self, msg): ''' Node Message handler ''' replies = [] if msg.flags & coreapi.CORE_API_ADD_FLAG and \ msg.flags & coreapi.CORE_API_DEL_FLAG: self.warn("ignoring invalid message: " "add and delete flag both set") return () nodenum = msg.tlvdata[coreapi.CORE_TLV_NODE_NUMBER] nodexpos = msg.gettlv(coreapi.CORE_TLV_NODE_XPOS) nodeypos = msg.gettlv(coreapi.CORE_TLV_NODE_YPOS) canvas = msg.gettlv(coreapi.CORE_TLV_NODE_CANVAS) icon = msg.gettlv(coreapi.CORE_TLV_NODE_ICON) lat = msg.gettlv(coreapi.CORE_TLV_NODE_LAT) lng = msg.gettlv(coreapi.CORE_TLV_NODE_LONG) alt = msg.gettlv(coreapi.CORE_TLV_NODE_ALT) if nodexpos is None and nodeypos is None and \ lat is not None and lng is not None and alt is not None: (x, y, z) = self.session.location.getxyz(float(lat), float(lng), float(alt)) nodexpos = int(x) nodeypos = int(y) # GUI can't handle lat/long, so generate another X/Y position message tlvdata = "" tlvdata += coreapi.CoreNodeTlv.pack(coreapi.CORE_TLV_NODE_NUMBER, nodenum) tlvdata += coreapi.CoreNodeTlv.pack(coreapi.CORE_TLV_NODE_XPOS, nodexpos) tlvdata += coreapi.CoreNodeTlv.pack(coreapi.CORE_TLV_NODE_YPOS, nodeypos) self.session.broadcastraw(self, coreapi.CoreNodeMessage.pack(0, tlvdata)) if msg.flags & coreapi.CORE_API_ADD_FLAG: nodetype = msg.tlvdata[coreapi.CORE_TLV_NODE_TYPE] try: nodecls = coreapi.node_class(nodetype) except KeyError: try: nodetypestr = " (%s)" % coreapi.node_types[nodetype] except KeyError: nodetypestr = "" self.warn("warning: unimplemented node type: %s%s" % \ (nodetype, nodetypestr)) return () start = False if self.session.getstate() > coreapi.CORE_EVENT_DEFINITION_STATE: start = True nodename = msg.tlvdata[coreapi.CORE_TLV_NODE_NAME] model = msg.gettlv(coreapi.CORE_TLV_NODE_MODEL) clsargs = { 'verbose': self.verbose, 'start': start } if nodetype == coreapi.CORE_NODE_XEN: clsargs['model'] = model if nodetype == coreapi.CORE_NODE_RJ45: if hasattr(self.session.options, 'enablerj45'): if self.session.options.enablerj45 == '0': clsargs['start'] = False # this instantiates an object of class nodecls, # creating the node or network n = self.session.addobj(cls = nodecls, objid = nodenum, name = nodename, **clsargs) if nodexpos is not None and nodeypos is not None: n.setposition(nodexpos, nodeypos, None) if canvas is not None: n.canvas = canvas if icon is not None: n.icon = icon opaque = msg.gettlv(coreapi.CORE_TLV_NODE_OPAQUE) if opaque is not None: n.opaque = opaque # add services to a node, either from its services TLV or # through the configured defaults for this node type if nodetype == coreapi.CORE_NODE_DEF or \ nodetype == coreapi.CORE_NODE_PHYS or \ nodetype == coreapi.CORE_NODE_XEN: if model is None: # TODO: default model from conf file? model = "router" n.type = model services_str = msg.gettlv(coreapi.CORE_TLV_NODE_SERVICES) self.session.services.addservicestonode(n, model, services_str, self.verbose) # boot nodes if they are added after runtime (like # session.bootnodes()) if self.session.getstate() == coreapi.CORE_EVENT_RUNTIME_STATE: if isinstance(n, pycore.nodes.PyCoreNode) and \ not isinstance(n, pycore.nodes.RJ45Node): self.session.writeobjs() self.session.addremovectrlif(node=n, remove=False) n.boot() # self.session.updatectrlifhosts() # n.validate() if msg.flags & coreapi.CORE_API_STR_FLAG: self.nodestatusreq[nodenum] = True self.session.sendnodeemuid(self, nodenum) elif msg.flags & coreapi.CORE_API_STR_FLAG: self.nodestatusreq[nodenum] = True elif msg.flags & coreapi.CORE_API_DEL_FLAG: n = None try: n = self.session.obj(nodenum) except KeyError: pass self.session.delobj(nodenum) if msg.flags & coreapi.CORE_API_STR_FLAG: tlvdata = "" tlvdata += coreapi.CoreNodeTlv.pack(coreapi.CORE_TLV_NODE_NUMBER, nodenum) flags = coreapi.CORE_API_DEL_FLAG | coreapi.CORE_API_LOC_FLAG replies.append(coreapi.CoreNodeMessage.pack(flags, tlvdata)) for reply in self.session.checkshutdown(): replies.append(reply) # Node modify message (no add/del flag) else: n = None try: n = self.session.obj(nodenum) except KeyError: if self.verbose: self.warn("ignoring node message: unknown node number %s" \ % nodenum) #nodeemuid = msg.gettlv(coreapi.CORE_TLV_NODE_EMUID) if nodexpos is None or nodeypos is None: if self.verbose: self.info("ignoring node message: nothing to do") else: if n: n.setposition(nodexpos, nodeypos, None) if n: if canvas is not None: n.canvas = canvas if icon is not None: n.icon = icon return replies def handlelinkmsg(self, msg): ''' Link Message handler ''' nodenum1 = msg.gettlv(coreapi.CORE_TLV_LINK_N1NUMBER) ifindex1 = msg.gettlv(coreapi.CORE_TLV_LINK_IF1NUM) ipv41 = msg.gettlv(coreapi.CORE_TLV_LINK_IF1IP4) ipv4mask1 = msg.gettlv(coreapi.CORE_TLV_LINK_IF1IP4MASK) mac1 = msg.gettlv(coreapi.CORE_TLV_LINK_IF1MAC) ipv61 = msg.gettlv(coreapi.CORE_TLV_LINK_IF1IP6) ipv6mask1 = msg.gettlv(coreapi.CORE_TLV_LINK_IF1IP6MASK) nodenum2 = msg.gettlv(coreapi.CORE_TLV_LINK_N2NUMBER) ifindex2 = msg.gettlv(coreapi.CORE_TLV_LINK_IF2NUM) ipv42 = msg.gettlv(coreapi.CORE_TLV_LINK_IF2IP4) ipv4mask2 = msg.gettlv(coreapi.CORE_TLV_LINK_IF2IP4MASK) mac2 = msg.gettlv(coreapi.CORE_TLV_LINK_IF2MAC) ipv62 = msg.gettlv(coreapi.CORE_TLV_LINK_IF2IP6) ipv6mask2 = msg.gettlv(coreapi.CORE_TLV_LINK_IF2IP6MASK) node1 = None node2 = None net = None net2 = None uni = msg.gettlv(coreapi.CORE_TLV_LINK_UNI) if uni is not None and uni == 1: unidirectional = True else: unidirectional = False # one of the nodes may exist on a remote server if nodenum1 is not None and nodenum2 is not None: t = self.session.broker.gettunnel(nodenum1, nodenum2) if isinstance(t, pycore.nodes.PyCoreNet): net = t if t.remotenum == nodenum1: nodenum1 = None else: nodenum2 = None # PhysicalNode connected via GreTap tunnel; uses adoptnetif() below elif t is not None: if t.remotenum == nodenum1: nodenum1 = None else: nodenum2 = None if nodenum1 is not None: try: n = self.session.obj(nodenum1) except KeyError: # XXX wait and queue this message to try again later # XXX maybe this should be done differently time.sleep(0.125) self.queuemsg(msg) return () if isinstance(n, pycore.nodes.PyCoreNode): node1 = n elif isinstance(n, pycore.nodes.PyCoreNet): if net is None: net = n else: net2 = n else: raise ValueError, "unexpected object class: %s" % n if nodenum2 is not None: try: n = self.session.obj(nodenum2) except KeyError: # XXX wait and queue this message to try again later # XXX maybe this should be done differently time.sleep(0.125) self.queuemsg(msg) return () if isinstance(n, pycore.nodes.PyCoreNode): node2 = n elif isinstance(n, pycore.nodes.PyCoreNet): if net is None: net = n else: net2 = n else: raise ValueError, "unexpected object class: %s" % n link_msg_type = msg.gettlv(coreapi.CORE_TLV_LINK_TYPE) if node1: node1.lock.acquire() if node2: node2.lock.acquire() try: if link_msg_type == coreapi.CORE_LINK_WIRELESS: ''' Wireless link/unlink event ''' numwlan = 0 objs = [node1, node2, net, net2] objs = filter( lambda(x): x is not None, objs ) if len(objs) < 2: raise ValueError, "wireless link/unlink message between unknown objects" nets = objs[0].commonnets(objs[1]) for (netcommon, netif1, netif2) in nets: if not isinstance(netcommon, pycore.nodes.WlanNode) and \ not isinstance(netcommon, pycore.nodes.EmaneNode): continue if msg.flags & coreapi.CORE_API_ADD_FLAG: netcommon.link(netif1, netif2) elif msg.flags & coreapi.CORE_API_DEL_FLAG: netcommon.unlink(netif1, netif2) else: raise ValueError, "invalid flags for wireless link/unlink message" numwlan += 1 if numwlan == 0: raise ValueError, \ "no common network found for wireless link/unlink" elif msg.flags & coreapi.CORE_API_ADD_FLAG: ''' Add a new link. ''' start = False if self.session.getstate() > coreapi.CORE_EVENT_DEFINITION_STATE: start = True if node1 and node2 and not net: # a new wired link net = self.session.addobj(cls = pycore.nodes.PtpNet, verbose = self.verbose, start = start) bw = msg.gettlv(coreapi.CORE_TLV_LINK_BW) delay = msg.gettlv(coreapi.CORE_TLV_LINK_DELAY) loss = msg.gettlv(coreapi.CORE_TLV_LINK_PER) duplicate = msg.gettlv(coreapi.CORE_TLV_LINK_DUP) jitter = msg.gettlv(coreapi.CORE_TLV_LINK_JITTER) key = msg.gettlv(coreapi.CORE_TLV_LINK_KEY) netaddrlist = [] #print " n1=%s n2=%s net=%s net2=%s" % (node1, node2, net, net2) if node1 and net: addrlist = [] if ipv41 is not None and ipv4mask1 is not None: addrlist.append("%s/%s" % (ipv41, ipv4mask1)) if ipv61 is not None and ipv6mask1 is not None: addrlist.append("%s/%s" % (ipv61, ipv6mask1)) if ipv42 is not None and ipv4mask2 is not None: netaddrlist.append("%s/%s" % (ipv42, ipv4mask2)) if ipv62 is not None and ipv6mask2 is not None: netaddrlist.append("%s/%s" % (ipv62, ipv6mask2)) ifindex1 = node1.newnetif(net, addrlist = addrlist, hwaddr = mac1, ifindex = ifindex1) net.linkconfig(node1.netif(ifindex1, net), bw = bw, delay = delay, loss = loss, duplicate = duplicate, jitter = jitter) if node1 is None and net: if ipv41 is not None and ipv4mask1 is not None: netaddrlist.append("%s/%s" % (ipv41, ipv4mask1)) # don't add this address again if node2 and net ipv41 = None if ipv61 is not None and ipv6mask1 is not None: netaddrlist.append("%s/%s" % (ipv61, ipv6mask1)) # don't add this address again if node2 and net ipv61 = None if node2 and net: addrlist = [] if ipv42 is not None and ipv4mask2 is not None: addrlist.append("%s/%s" % (ipv42, ipv4mask2)) if ipv62 is not None and ipv6mask2 is not None: addrlist.append("%s/%s" % (ipv62, ipv6mask2)) if ipv41 is not None and ipv4mask1 is not None: netaddrlist.append("%s/%s" % (ipv41, ipv4mask1)) if ipv61 is not None and ipv6mask1 is not None: netaddrlist.append("%s/%s" % (ipv61, ipv6mask1)) ifindex2 = node2.newnetif(net, addrlist = addrlist, hwaddr = mac2, ifindex = ifindex2) if not unidirectional: net.linkconfig(node2.netif(ifindex2, net), bw = bw, delay = delay, loss = loss, duplicate = duplicate, jitter = jitter) if node2 is None and net2: if ipv42 is not None and ipv4mask2 is not None: netaddrlist.append("%s/%s" % (ipv42, ipv4mask2)) if ipv62 is not None and ipv6mask2 is not None: netaddrlist.append("%s/%s" % (ipv62, ipv6mask2)) # tunnel node finalized with this link message if key and isinstance(net, pycore.nodes.TunnelNode): net.setkey(key) if len(netaddrlist) > 0: net.addrconfig(netaddrlist) if key and isinstance(net2, pycore.nodes.TunnelNode): net2.setkey(key) if len(netaddrlist) > 0: net2.addrconfig(netaddrlist) if net and net2: # two layer-2 networks linked together if isinstance(net2, pycore.nodes.RJ45Node): netif = net2.linknet(net) # RJ45 nodes have different linknet() else: netif = net.linknet(net2) net.linkconfig(netif, bw = bw, delay = delay, loss = loss, duplicate = duplicate, jitter = jitter) if not unidirectional: netif.swapparams('_params_up') net2.linkconfig(netif, bw = bw, delay = delay, loss = loss, duplicate = duplicate, jitter = jitter, devname = netif.name) netif.swapparams('_params_up') elif net is None and net2 is None and \ (node1 is None or node2 is None): # apply address/parameters to PhysicalNodes fx = (bw, delay, loss, duplicate, jitter) addrlist = [] if node1 and isinstance(node1, pycore.pnodes.PhysicalNode): if ipv41 is not None and ipv4mask1 is not None: addrlist.append("%s/%s" % (ipv41, ipv4mask1)) if ipv61 is not None and ipv6mask1 is not None: addrlist.append("%s/%s" % (ipv61, ipv6mask1)) node1.adoptnetif(t, ifindex1, mac1, addrlist) node1.linkconfig(t, bw, delay, loss, duplicate, jitter) elif node2 and isinstance(node2, pycore.pnodes.PhysicalNode): if ipv42 is not None and ipv4mask2 is not None: addrlist.append("%s/%s" % (ipv42, ipv4mask2)) if ipv62 is not None and ipv6mask2 is not None: addrlist.append("%s/%s" % (ipv62, ipv6mask2)) node2.adoptnetif(t, ifindex2, mac2, addrlist) node2.linkconfig(t, bw, delay, loss, duplicate, jitter) # delete a link elif msg.flags & coreapi.CORE_API_DEL_FLAG: ''' Remove a link. ''' if node1 and node2: # TODO: fix this for the case where ifindex[1,2] are # not specified # a wired unlink event, delete the connecting bridge netif1 = node1.netif(ifindex1) netif2 = node2.netif(ifindex2) if netif1 is None and netif2 is None: nets = node1.commonnets(node2) for (netcommon, tmp1, tmp2) in nets: if (net and netcommon == net) or net is None: netif1 = tmp1 netif2 = tmp2 break if netif1 is None or netif2 is None: pass elif netif1.net or netif2.net: if netif1.net != netif2.net: if not netif1.up or not netif2.up: pass else: raise ValueError, "no common network found" net = netif1.net netif1.detachnet() netif2.detachnet() if net.numnetif() == 0: self.session.delobj(net.objid) node1.delnetif(ifindex1) node2.delnetif(ifindex2) else: ''' Modify a link. ''' bw = msg.gettlv(coreapi.CORE_TLV_LINK_BW) delay = msg.gettlv(coreapi.CORE_TLV_LINK_DELAY) loss = msg.gettlv(coreapi.CORE_TLV_LINK_PER) duplicate = msg.gettlv(coreapi.CORE_TLV_LINK_DUP) jitter = msg.gettlv(coreapi.CORE_TLV_LINK_JITTER) numnet = 0 # TODO: clean up all this logic. Having the add flag or not # should use the same code block. if node1 is None and node2 is None: if net and net2: # modify link between nets netif = net.getlinknetif(net2) upstream = False if netif is None: upstream = True netif = net2.getlinknetif(net) if netif is None: raise ValueError, "modify unknown link between nets" if upstream: netif.swapparams('_params_up') net.linkconfig(netif, bw = bw, delay = delay, loss = loss, duplicate = duplicate, jitter = jitter, devname = netif.name) netif.swapparams('_params_up') else: net.linkconfig(netif, bw = bw, delay = delay, loss = loss, duplicate = duplicate, jitter = jitter) if not unidirectional: if upstream: net2.linkconfig(netif, bw = bw, delay = delay, loss = loss, duplicate = duplicate, jitter = jitter) else: netif.swapparams('_params_up') net2.linkconfig(netif, bw = bw, delay = delay, loss = loss, duplicate = duplicate, jitter = jitter, devname = netif.name) netif.swapparams('_params_up') else: raise ValueError, "modify link for unknown nodes" elif node1 is None: # node1 = layer 2node, node2 = layer3 node net.linkconfig(node2.netif(ifindex2, net), bw = bw, delay = delay, loss = loss, duplicate = duplicate, jitter = jitter) elif node2 is None: # node2 = layer 2node, node1 = layer3 node net.linkconfig(node1.netif(ifindex1, net), bw = bw, delay = delay, loss = loss, duplicate = duplicate, jitter = jitter) else: nets = node1.commonnets(node2) for (net, netif1, netif2) in nets: if ifindex1 is not None and \ ifindex1 != node1.getifindex(netif1): continue net.linkconfig(netif1, bw = bw, delay = delay, loss = loss, duplicate = duplicate, jitter = jitter, netif2 = netif2) if not unidirectional: net.linkconfig(netif2, bw = bw, delay = delay, loss = loss, duplicate = duplicate, jitter = jitter, netif2 = netif1) numnet += 1 if numnet == 0: raise ValueError, "no common network found" finally: if node1: node1.lock.release() if node2: node2.lock.release() return () def handleexecmsg(self, msg): ''' Execute Message handler ''' nodenum = msg.gettlv(coreapi.CORE_TLV_EXEC_NODE) execnum = msg.gettlv(coreapi.CORE_TLV_EXEC_NUM) exectime = msg.gettlv(coreapi.CORE_TLV_EXEC_TIME) cmd = msg.gettlv(coreapi.CORE_TLV_EXEC_CMD) # local flag indicates command executed locally, not on a node if nodenum is None and not msg.flags & coreapi.CORE_API_LOC_FLAG: raise ValueError, "Execute Message is missing node number." if execnum is None: raise ValueError, "Execute Message is missing execution number." if exectime is not None: self.session.addevent(exectime, node=nodenum, name=None, data=cmd) return () try: n = self.session.obj(nodenum) except KeyError: # XXX wait and queue this message to try again later # XXX maybe this should be done differently if not msg.flags & coreapi.CORE_API_LOC_FLAG: time.sleep(0.125) self.queuemsg(msg) return () else: pass # build common TLV items for reply tlvdata = "" if nodenum is not None: tlvdata += coreapi.CoreExecTlv.pack(coreapi.CORE_TLV_EXEC_NODE, nodenum) tlvdata += coreapi.CoreExecTlv.pack(coreapi.CORE_TLV_EXEC_NUM, execnum) tlvdata += coreapi.CoreExecTlv.pack(coreapi.CORE_TLV_EXEC_CMD, cmd) if msg.flags & coreapi.CORE_API_TTY_FLAG: if nodenum is None: raise NotImplementedError # echo back exec message with cmd for spawning interactive terminal if cmd == "bash": cmd = "/bin/bash" res = n.termcmdstring(cmd) tlvdata += coreapi.CoreExecTlv.pack(coreapi.CORE_TLV_EXEC_RESULT, res) reply = coreapi.CoreExecMessage.pack(coreapi.CORE_API_TTY_FLAG, tlvdata) return (reply, ) else: if self.verbose: self.info("execute message with cmd = '%s'" % cmd) # execute command and send a response if msg.flags & coreapi.CORE_API_STR_FLAG or \ msg.flags & coreapi.CORE_API_TXT_FLAG: # shlex.split() handles quotes within the string if msg.flags & coreapi.CORE_API_LOC_FLAG: status, res = cmdresult(shlex.split(cmd)) else: status, res = n.cmdresult(shlex.split(cmd)) if self.verbose: self.info("done exec cmd='%s' with status=%d res=(%d bytes)" % (cmd, status, len(res))) if msg.flags & coreapi.CORE_API_TXT_FLAG: tlvdata += coreapi.CoreExecTlv.pack( \ coreapi.CORE_TLV_EXEC_RESULT, res) if msg.flags & coreapi.CORE_API_STR_FLAG: tlvdata += coreapi.CoreExecTlv.pack( \ coreapi.CORE_TLV_EXEC_STATUS, status) reply = coreapi.CoreExecMessage.pack(0, tlvdata) return (reply, ) # execute the command with no response else: if msg.flags & coreapi.CORE_API_LOC_FLAG: mutedetach(shlex.split(cmd)) else: n.cmd(shlex.split(cmd), wait=False) return () def handleregmsg(self, msg): ''' Register Message Handler ''' replies = [] # execute a Python script or XML file ex = msg.gettlv(coreapi.CORE_TLV_REG_EXECSRV) if ex: try: self.info("executing '%s'" % ex) if isinstance(self.server, CoreUdpServer): server = self.server.tcpserver else: server = self.server if msg.flags & coreapi.CORE_API_STR_FLAG: old_session_ids = set(server.getsessionids()) sys.argv = shlex.split(ex) filename = sys.argv[0] if os.path.splitext(filename)[1].lower() == '.xml': session = server.getsession(useexisting=False) try: opensessionxml(session, filename, start=True) except: session.shutdown() server.delsession(session) raise else: t = threading.Thread(target = execfile, args=(filename, {'__file__': filename, 'server': server})) t.daemon = True t.start() time.sleep(0.25) # allow time for session creation if msg.flags & coreapi.CORE_API_STR_FLAG: new_session_ids = set(server.getsessionids()) new_sid = new_session_ids.difference(old_session_ids) try: sid = new_sid.pop() self.info("executed '%s' as session %d" % (ex, sid)) except KeyError: self.info("executed '%s' with unknown session ID" % ex) return replies self.info("checking session %d for RUNTIME state" % sid) session = self.server.getsession(sessionid=sid, useexisting=True) retries = 10 # wait for session to enter RUNTIME state, to prevent GUI from # connecting while nodes are still being instantiated while session.getstate() != coreapi.CORE_EVENT_RUNTIME_STATE: self.info("waiting for session %d to enter RUNTIME state" % sid) time.sleep(1) retries -= 1 if retries <= 0: self.info("session %d did not enter RUNTIME state" % sid) return replies tlvdata = coreapi.CoreRegTlv.pack( \ coreapi.CORE_TLV_REG_EXECSRV, ex) tlvdata += coreapi.CoreRegTlv.pack( \ coreapi.CORE_TLV_REG_SESSION, "%s" % sid) msg = coreapi.CoreRegMessage.pack(0, tlvdata) replies.append(msg) except Exception, e: self.warn("error executing '%s': %s" % \ (ex, traceback.format_exc())) tlvdata = coreapi.CoreExceptionTlv.pack( \ coreapi.CORE_TLV_EXCP_LEVEL, 2) tlvdata += coreapi.CoreExceptionTlv.pack( \ coreapi.CORE_TLV_EXCP_TEXT, str(e)) msg = coreapi.CoreExceptionMessage.pack(0, tlvdata) replies.append(msg) return replies gui = msg.gettlv(coreapi.CORE_TLV_REG_GUI) if gui is None: self.info("ignoring Register message") else: # register capabilities with the GUI self.master = True found = self.server.setsessionmaster(self) replies.append(self.register()) replies.append(self.server.tosessionmsg()) return replies def handleconfmsg(self, msg): ''' Configuration Message handler ''' nodenum = msg.gettlv(coreapi.CORE_TLV_CONF_NODE) objname = msg.gettlv(coreapi.CORE_TLV_CONF_OBJ) if self.verbose: self.info("Configuration message for %s node %s" % \ (objname, nodenum)) # dispatch to any registered callback for this object type replies = self.session.confobj(objname, self.session, msg) # config requests usually have a reply with default data return replies def handlefilemsg(self, msg): ''' File Message handler ''' if msg.flags & coreapi.CORE_API_ADD_FLAG: nodenum = msg.gettlv(coreapi.CORE_TLV_NODE_NUMBER) filename = msg.gettlv(coreapi.CORE_TLV_FILE_NAME) type = msg.gettlv(coreapi.CORE_TLV_FILE_TYPE) srcname = msg.gettlv(coreapi.CORE_TLV_FILE_SRCNAME) data = msg.gettlv(coreapi.CORE_TLV_FILE_DATA) cmpdata = msg.gettlv(coreapi.CORE_TLV_FILE_CMPDATA) if cmpdata is not None: self.warn("Compressed file data not implemented for File " \ "message.") return () if srcname is not None and data is not None: self.warn("ignoring invalid File message: source and data " \ "TLVs are both present") return () # some File Messages store custom files in services, # prior to node creation if type is not None: if type[:8] == "service:": self.session.services.setservicefile(nodenum, type, filename, srcname, data) return () elif type[:5] == "hook:": self.session.sethook(type, filename, srcname, data) return () # writing a file to the host if nodenum is None: if srcname is not None: shutil.copy2(srcname, filename) else: with open(filename, "w") as f: f.write(data) return () try: n = self.session.obj(nodenum) except KeyError: # XXX wait and queue this message to try again later # XXX maybe this should be done differently self.warn("File message for %s for node number %s queued." % \ (filename, nodenum)) time.sleep(0.125) self.queuemsg(msg) return () if srcname is not None: n.addfile(srcname, filename) elif data is not None: n.nodefile(filename, data) else: raise NotImplementedError return () def handleifacemsg(self, msg): ''' Interface Message handler ''' self.info("ignoring Interface message") return () def handleeventmsg(self, msg): ''' Event Message handler ''' eventtype = msg.gettlv(coreapi.CORE_TLV_EVENT_TYPE) if eventtype is None: raise NotImplementedError, "Event message missing event type" node = msg.gettlv(coreapi.CORE_TLV_EVENT_NODE) if self.verbose: self.info("EVENT %d: %s at %s" % \ (eventtype, coreapi.event_types[eventtype], time.ctime())) if eventtype <= coreapi.CORE_EVENT_SHUTDOWN_STATE: if node is not None: try: n = self.session.obj(node) except KeyError: raise KeyError, "Event message for unknown node %d" % node if eventtype == coreapi.CORE_EVENT_INSTANTIATION_STATE: # configure mobility models for WLAN added during runtime if isinstance(n, pycore.nodes.WlanNode): return (self.session.mobility.startup(nodenums=(n.objid,))) self.warn("dropping unhandled Event message with node number") return () self.session.setstate(state=eventtype, info=True, sendevent=False) if eventtype == coreapi.CORE_EVENT_DEFINITION_STATE: # clear all session objects in order to receive new definitions self.session.delobjs() self.session.delhooks() self.session.broker.reset() elif eventtype == coreapi.CORE_EVENT_CONFIGURATION_STATE: pass elif eventtype == coreapi.CORE_EVENT_INSTANTIATION_STATE: if len(self.handlerthreads) > 1: # TODO: sync handler threads here before continuing time.sleep(2.0) # XXX # done receiving node/link configuration, ready to instantiate self.session.instantiate(handler=self) elif eventtype == coreapi.CORE_EVENT_RUNTIME_STATE: if self.session.master: self.warn("Unexpected event message: RUNTIME state received " \ "at session master") else: # master event queue is started in session.checkruntime() self.session.evq.run() elif eventtype == coreapi.CORE_EVENT_DATACOLLECT_STATE: self.session.datacollect() elif eventtype == coreapi.CORE_EVENT_SHUTDOWN_STATE: if self.session.master: self.warn("Unexpected event message: SHUTDOWN state received " \ "at session master") elif eventtype in (coreapi.CORE_EVENT_START, coreapi.CORE_EVENT_STOP, \ coreapi.CORE_EVENT_RESTART, \ coreapi.CORE_EVENT_PAUSE, \ coreapi.CORE_EVENT_RECONFIGURE): handled = False name = msg.gettlv(coreapi.CORE_TLV_EVENT_NAME) if name: # TODO: register system for event message handlers, # like confobjs if name.startswith("service:"): self.session.services.handleevent(msg) handled = True elif name.startswith("mobility:"): self.session.mobility.handleevent(msg) handled = True else: pass if not handled: self.warn("Unhandled event message: event type %s (%s)" % \ (eventtype, coreapi.state_name(eventtype))) elif eventtype == coreapi.CORE_EVENT_FILE_OPEN: self.session.delobjs() self.session.delhooks() self.session.broker.reset() filename = msg.tlvdata[coreapi.CORE_TLV_EVENT_NAME] opensessionxml(self.session, filename) return self.session.sendobjs() elif eventtype == coreapi.CORE_EVENT_FILE_SAVE: filename = msg.tlvdata[coreapi.CORE_TLV_EVENT_NAME] savesessionxml(self.session, filename, self.session.cfg['xmlfilever']) elif eventtype == coreapi.CORE_EVENT_SCHEDULED: etime = msg.gettlv(coreapi.CORE_TLV_EVENT_TIME) node = msg.gettlv(coreapi.CORE_TLV_EVENT_NODE) name = msg.gettlv(coreapi.CORE_TLV_EVENT_NAME) data = msg.gettlv(coreapi.CORE_TLV_EVENT_DATA) if etime is None: self.warn("Event message scheduled event missing start time") return () if msg.flags & coreapi.CORE_API_ADD_FLAG: self.session.addevent(float(etime), node=node, name=name, data=data) else: raise NotImplementedError else: self.warn("Unhandled event message: event type %d" % eventtype) return () def handlesessionmsg(self, msg): ''' Session Message handler ''' replies = [] sid_str = msg.gettlv(coreapi.CORE_TLV_SESS_NUMBER) name_str = msg.gettlv(coreapi.CORE_TLV_SESS_NAME) file_str = msg.gettlv(coreapi.CORE_TLV_SESS_FILE) nc_str = msg.gettlv(coreapi.CORE_TLV_SESS_NODECOUNT) thumb = msg.gettlv(coreapi.CORE_TLV_SESS_THUMB) user = msg.gettlv(coreapi.CORE_TLV_SESS_USER) sids = coreapi.str_to_list(sid_str) names = coreapi.str_to_list(name_str) files = coreapi.str_to_list(file_str) ncs = coreapi.str_to_list(nc_str) self.info("SESSION message flags=0x%x sessions=%s" % (msg.flags, sid_str)) if msg.flags == 0: # modify a session i = 0 for sid in sids: sid = int(sid) if sid == 0: session = self.session else: session = self.server.getsession(sessionid = sid, useexisting = True) if session is None: self.info("session %s not found" % sid) i += 1 continue self.info("request to modify to session %s" % session.sessionid) if names is not None: session.name = names[i] if files is not None: session.filename = files[i] if ncs is not None: session.node_count = ncs[i] if thumb is not None: session.setthumbnail(thumb) if user is not None: session.setuser(user) i += 1 else: if msg.flags & coreapi.CORE_API_STR_FLAG and not \ msg.flags & coreapi.CORE_API_ADD_FLAG: # status request flag: send list of sessions return (self.server.tosessionmsg(), ) # handle ADD or DEL flags for sid in sids: sid = int(sid) session = self.server.getsession(sessionid = sid, useexisting = True) if session is None: self.info("session %s not found (flags=0x%x)" % \ (sid, msg.flags)) continue if session.server is None: # this needs to be set when executing a Python script session.server = self.server if msg.flags & coreapi.CORE_API_ADD_FLAG: # connect to the first session that exists self.info("request to connect to session %s" % sid) # this may shutdown the session if no handlers exist self.session.disconnect(self) self.session = session self.session.connect(self) if user is not None: self.session.setuser(user) if msg.flags & coreapi.CORE_API_STR_FLAG: replies.extend(self.session.sendobjs()) elif msg.flags & coreapi.CORE_API_DEL_FLAG: # shut down the specified session(s) self.info("request to terminate session %s" % sid) session.setstate(state=coreapi.CORE_EVENT_DATACOLLECT_STATE, info=True, sendevent=True) session.setstate(state=coreapi.CORE_EVENT_SHUTDOWN_STATE, info=True, sendevent=True) session.shutdown() else: self.warn("unhandled session flags for session %s" % sid) return replies class CoreDatagramRequestHandler(CoreRequestHandler): ''' A child of the CoreRequestHandler class for handling connectionless UDP messages. No new session is created; messages are handled immediately or sometimes queued on existing session handlers. ''' def __init__(self, request, client_address, server): # TODO: decide which messages cannot be handled with connectionless UDP self.msghandler = { coreapi.CORE_API_NODE_MSG: self.handlenodemsg, coreapi.CORE_API_LINK_MSG: self.handlelinkmsg, coreapi.CORE_API_EXEC_MSG: self.handleexecmsg, coreapi.CORE_API_REG_MSG: self.handleregmsg, coreapi.CORE_API_CONF_MSG: self.handleconfmsg, coreapi.CORE_API_FILE_MSG: self.handlefilemsg, coreapi.CORE_API_IFACE_MSG: self.handleifacemsg, coreapi.CORE_API_EVENT_MSG: self.handleeventmsg, coreapi.CORE_API_SESS_MSG: self.handlesessionmsg, } self.nodestatusreq = {} self.master = False self.session = None self.verbose = bool(server.tcpserver.cfg['verbose'].lower() == "true") self.debug = bool(server.tcpserver.cfg['debug'].lower() == "true") SocketServer.BaseRequestHandler.__init__(self, request, client_address, server) def setup(self): ''' Client has connected, set up a new connection. ''' if self.verbose: self.info("new UDP connection: %s:%s" % self.client_address) def handle(self): msg = self.recvmsg() def finish(self): return SocketServer.BaseRequestHandler.finish(self) def recvmsg(self): ''' Receive data, parse a CoreMessage and queue it onto an existing session handler's queue, if available. ''' data = self.request[0] socket = self.request[1] msghdr = data[:coreapi.CoreMessage.hdrsiz] if len(msghdr) < coreapi.CoreMessage.hdrsiz: raise IOError, "error receiving header (received %d bytes)" % \ len(msghdr) msgtype, msgflags, msglen = coreapi.CoreMessage.unpackhdr(msghdr) if msglen == 0: self.warn("received message with no data") return if len(data) != coreapi.CoreMessage.hdrsiz + msglen: self.warn("received message length does not match received data " \ "(%s != %s)" % \ (len(data), coreapi.CoreMessage.hdrsiz + msglen)) raise IOError elif self.verbose: self.info("UDP socket received message type=%d len=%d" % \ (msgtype, msglen)) try: msgcls = coreapi.msg_class(msgtype) msg = msgcls(msgflags, msghdr, data[coreapi.CoreMessage.hdrsiz:]) except KeyError: msg = coreapi.CoreMessage(msgflags, msghdr, data[coreapi.CoreMessage.hdrsiz:]) msg.msgtype = msgtype self.warn("unimplemented core message type: %s" % msg.typestr()) return sids = msg.sessionnumbers() msg.queuedtimes = 0 #self.info("UDP message has session numbers: %s" % sids) if len(sids) > 0: for sid in sids: sess = self.server.tcpserver.getsession(sessionid=sid, useexisting=True) if sess: self.session = sess sess.broadcast(self, msg) self.handlemsg(msg) else: self.warn("Session %d in %s message not found." % \ (sid, msg.typestr())) else: # no session specified, find an existing one sess = self.server.tcpserver.getsession(sessionid=0, useexisting=True) if sess or msg.msgtype == coreapi.CORE_API_REG_MSG: self.session = sess if sess: sess.broadcast(self, msg) self.handlemsg(msg) else: self.warn("No active session, dropping %s message." % \ msg.typestr()) def queuemsg(self, msg): ''' UDP handlers are short-lived and do not have message queues. ''' raise Exception, "Unable to queue %s message for later processing " \ "using UDP!" % msg.typestr() def sendall(self, data): ''' Use sendto() on the connectionless UDP socket. ''' self.request[1].sendto(data, self.client_address) class CoreServer(SocketServer.ThreadingMixIn, SocketServer.TCPServer): ''' TCP server class, manages sessions and spawns request handlers for incoming connections. ''' daemon_threads = True allow_reuse_address = True servers = set() def __init__(self, server_address, RequestHandlerClass, cfg = None): ''' Server class initialization takes configuration data and calls the SocketServer constructor ''' self.cfg = cfg self._sessions = {} self._sessionslock = threading.Lock() self.newserver(self) SocketServer.TCPServer.__init__(self, server_address, RequestHandlerClass) @classmethod def newserver(cls, server): cls.servers.add(server) @classmethod def delserver(cls, server): try: cls.servers.remove(server) except KeyError: pass def shutdown(self): for session in self._sessions.values(): session.shutdown() if self.cfg['daemonize']: pidfilename = self.cfg['pidfile'] try: os.unlink(pidfilename) except OSError: pass self.delserver(self) def addsession(self, session): ''' Add a session to our dictionary of sessions, ensuring a unique session number ''' self._sessionslock.acquire() try: if session.sessionid in self._sessions: raise KeyError, "non-unique session id %s for %s" % \ (session.sessionid, session) self._sessions[session.sessionid] = session finally: self._sessionslock.release() return session def delsession(self, session): ''' Remove a session from our dictionary of sessions. ''' with self._sessionslock: if session.sessionid not in self._sessions: print "session id %s not found (sessions=%s)" % \ (session.sessionid, self._sessions.keys()) else: del(self._sessions[session.sessionid]) return session def getsessionids(self): ''' Return a list of active session numbers. ''' with self._sessionslock: sids = self._sessions.keys() return sids def getsession(self, sessionid = None, useexisting = True): ''' Create a new session or retrieve an existing one from our dictionary of sessions. When the sessionid=0 and the useexisting flag is set, return on of the existing sessions. ''' if not useexisting: session = pycore.Session(sessionid, cfg = self.cfg, server = self) self.addsession(session) return session with self._sessionslock: # look for the specified session id if sessionid in self._sessions: session = self._sessions[sessionid] else: session = None # pick an existing session if sessionid == 0: for s in self._sessions.itervalues(): if s.getstate() == coreapi.CORE_EVENT_RUNTIME_STATE: if session is None: session = s elif s.node_count > session.node_count: session = s if session is None: for s in self._sessions.itervalues(): session = s break return session def tosessionmsg(self, flags = 0): ''' Build CORE API Sessions message based on current session info. ''' idlist = [] namelist = [] filelist = [] nclist = [] datelist = [] thumblist = [] num_sessions = 0 with self._sessionslock: for sessionid in self._sessions: session = self._sessions[sessionid] # debug: session.dumpsession() num_sessions += 1 idlist.append(str(sessionid)) name = session.name if name is None: name = "" namelist.append(name) file = session.filename if file is None: file = "" filelist.append(file) nc = session.node_count if nc is None: nc = "" nclist.append(str(nc)) datelist.append(time.ctime(session._time)) thumb = session.thumbnail if thumb is None: thumb = "" thumblist.append(thumb) sids = "|".join(idlist) names = "|".join(namelist) files = "|".join(filelist) ncs = "|".join(nclist) dates = "|".join(datelist) thumbs = "|".join(thumblist) if num_sessions > 0: tlvdata = "" if len(sids) > 0: tlvdata += coreapi.CoreSessionTlv.pack( \ coreapi.CORE_TLV_SESS_NUMBER, sids) if len(names) > 0: tlvdata += coreapi.CoreSessionTlv.pack( \ coreapi.CORE_TLV_SESS_NAME, names) if len(files) > 0: tlvdata += coreapi.CoreSessionTlv.pack( \ coreapi.CORE_TLV_SESS_FILE, files) if len(ncs) > 0: tlvdata += coreapi.CoreSessionTlv.pack( \ coreapi.CORE_TLV_SESS_NODECOUNT, ncs) if len(dates) > 0: tlvdata += coreapi.CoreSessionTlv.pack( \ coreapi.CORE_TLV_SESS_DATE, dates) if len(thumbs) > 0: tlvdata += coreapi.CoreSessionTlv.pack( \ coreapi.CORE_TLV_SESS_THUMB, thumbs) msg = coreapi.CoreSessionMessage.pack(flags, tlvdata) else: msg = None return(msg) def dumpsessions(self): ''' Debug print all session info. ''' print "sessions:" self._sessionslock.acquire() try: for sessionid in self._sessions: print sessionid, finally: self._sessionslock.release() print "" sys.stdout.flush() def setsessionmaster(self, handler): ''' Call the setmaster() method for every session. Returns True when a session having the given handler was updated. ''' found = False self._sessionslock.acquire() try: for sessionid in self._sessions: found = self._sessions[sessionid].setmaster(handler) if found is True: break finally: self._sessionslock.release() return found def startudp(self, server_address): ''' Start a thread running a UDP server on the same host,port for connectionless requests. ''' self.udpserver = CoreUdpServer(server_address, CoreDatagramRequestHandler, self) self.udpthread = threading.Thread(target = self.udpserver.start) self.udpthread.daemon = True self.udpthread.start() class CoreUdpServer(SocketServer.ThreadingMixIn, SocketServer.UDPServer): ''' UDP server class, manages sessions and spawns request handlers for incoming connections. ''' daemon_threads = True allow_reuse_address = True def __init__(self, server_address, RequestHandlerClass, tcpserver): ''' Server class initialization takes configuration data and calls the SocketServer constructor ''' self.tcpserver = tcpserver SocketServer.UDPServer.__init__(self, server_address, RequestHandlerClass) def start(self): ''' Thread target to run concurrently with the TCP server. ''' self.serve_forever() def banner(): ''' Output the program banner printed to the terminal or log file. ''' sys.stdout.write("CORE daemon v.%s started %s\n" % \ (COREDPY_VERSION, time.ctime())) sys.stdout.flush() def cored(cfg = None): ''' Start the CoreServer object and enter the server loop. ''' host = cfg['listenaddr'] port = int(cfg['port']) if host == '' or host is None: host = "localhost" try: server = CoreServer((host, port), CoreRequestHandler, cfg) except Exception, e: sys.stderr.write("error starting server on: %s:%s\n\t%s\n" % \ (host, port, e)) sys.stderr.flush() sys.exit(1) closeonexec(server.fileno()) sys.stdout.write("server started, listening on: %s:%s\n" % (host, port)) sys.stdout.flush() server.startudp((host,port)) server.serve_forever() def cleanup(): while CoreServer.servers: server = CoreServer.servers.pop() server.shutdown() atexit.register(cleanup) def sighandler(signum, stackframe): print >> sys.stderr, "terminated by signal:", signum sys.exit(signum) signal.signal(signal.SIGTERM, sighandler) def getMergedConfig(filename): ''' Return a configuration after merging config file and command-line arguments. ''' # these are the defaults used in the config file defaults = { 'port' : '%d' % coreapi.CORE_API_PORT, 'listenaddr' : 'localhost', 'pidfile' : '%s/run/core-daemon.pid' % CORE_STATE_DIR, 'logfile' : '%s/log/core-daemon.log' % CORE_STATE_DIR, 'xmlfilever' : '1.0', 'numthreads' : '1', 'verbose' : 'False', 'daemonize' : 'False', 'debug' : 'False', 'execfile' : None, } usagestr = "usage: %prog [-h] [options] [args]\n\n" + \ "CORE daemon v.%s instantiates Linux network namespace " \ "nodes." % COREDPY_VERSION parser = optparse.OptionParser(usage = usagestr) parser.add_option("-f", "--configfile", dest = "configfile", type = "string", help = "read config from specified file; default = %s" % filename) parser.add_option("-d", "--daemonize", dest = "daemonize", action="store_true", help = "run in background as daemon; default=%s" % \ defaults["daemonize"]) parser.add_option("-e", "--execute", dest = "execfile", type = "string", help = "execute a Python/XML-based session") parser.add_option("-l", "--logfile", dest = "logfile", type = "string", help = "log output to specified file; default = %s" % defaults["logfile"]) parser.add_option("-p", "--port", dest = "port", type = int, help = "port number to listen on; default = %s" % \ defaults["port"]) parser.add_option("-i", "--pidfile", dest = "pidfile", help = "filename to write pid to; default = %s" % \ defaults["pidfile"]) parser.add_option("-t", "--numthreads", dest = "numthreads", type = int, help = "number of server threads; default = %s" % \ defaults["numthreads"]) parser.add_option("-v", "--verbose", dest = "verbose", action="store_true", help = "enable verbose logging; default = %s" % \ defaults["verbose"]) parser.add_option("-g", "--debug", dest = "debug", action="store_true", help = "enable debug logging; default = %s" % \ defaults["debug"]) # parse command line options (options, args) = parser.parse_args() # read the config file if options.configfile is not None: filename = options.configfile del options.configfile cfg = ConfigParser.SafeConfigParser(defaults) cfg.read(filename) section = "core-daemon" if not cfg.has_section(section): cfg.add_section(section) # gracefully support legacy configs (cored.py/cored now core-daemon) if cfg.has_section("cored.py"): for name, val in cfg.items("cored.py"): if name == 'pidfile' or name == 'logfile': bn = os.path.basename(val).replace('coredpy', 'core-daemon') val = os.path.join(os.path.dirname(val), bn) cfg.set(section, name, val) if cfg.has_section("cored"): for name, val in cfg.items("cored"): if name == 'pidfile' or name == 'logfile': bn = os.path.basename(val).replace('cored', 'core-daemon') val = os.path.join(os.path.dirname(val), bn) cfg.set(section, name, val) # merge command line with config file for opt in options.__dict__: val = options.__dict__[opt] if val is not None: cfg.set(section, opt, val.__str__()) return dict(cfg.items(section)), args def exec_file(cfg): ''' Send a Register Message to execute a new session based on XML or Python script file. ''' filename = cfg['execfile'] sys.stdout.write("Telling daemon to execute file: '%s'...\n" % filename) sys.stdout.flush() tlvdata = coreapi.CoreRegTlv.pack(coreapi.CORE_TLV_REG_EXECSRV, filename) msg = coreapi.CoreRegMessage.pack(coreapi.CORE_API_ADD_FLAG, tlvdata) sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) sock.connect(("localhost", int(cfg['port']))) # TODO: connect address option sock.sendall(msg) return 0 def main(): ''' Main program startup. ''' # get a configuration merged from config file and command-line arguments cfg, args = getMergedConfig("%s/core.conf" % CORE_CONF_DIR) for a in args: sys.stderr.write("ignoring command line argument: '%s'\n" % a) if cfg['daemonize'] == 'True': daemonize(rootdir = None, umask = 0, close_fds = False, stdin = os.devnull, stdout = cfg['logfile'], stderr = cfg['logfile'], pidfilename = cfg['pidfile'], defaultmaxfd = DEFAULT_MAXFD) banner() if cfg['execfile']: cfg['execfile'] = os.path.abspath(cfg['execfile']) sys.exit(exec_file(cfg)) try: cored(cfg) except KeyboardInterrupt: pass sys.exit(0) if __name__ == "__main__": main() core-4.8/daemon/sbin/core-manage0000775000175000017500000002121712534327775013564 00000000000000#!/usr/bin/env python # # CORE # Copyright (c)2014 the Boeing Company. # See the LICENSE file included in this distribution. # # author: Jeff Ahrenholz # ''' core-manage: Helper tool to add, remove, or check for services, models, and node types in a CORE installation. ''' import os import sys import ast import optparse import re from core import pycore from core.constants import CORE_CONF_DIR class FileUpdater(object): ''' Helper class for changing configuration files. ''' actions = ("add", "remove", "check") targets = ("service", "model", "nodetype") def __init__(self, action, target, data, options): ''' ''' self.action = action self.target = target self.data = data self.options = options self.verbose = options.verbose self.search, self.filename = self.get_filename(target) def process(self): ''' Invoke update_file() using a helper method depending on target. ''' if self.verbose: txt = "Updating" if self.action == "check": txt = "Checking" sys.stdout.write("%s file: '%s'\n" % (txt, self.filename)) if self.target == "service": r = self.update_file(fn=self.update_services) elif self.target == "model": r = self.update_file(fn=self.update_emane_models) elif self.target == "nodetype": r = self.update_nodes_conf() if self.verbose: txt = "" if not r: txt = "NOT " if self.action == "check": sys.stdout.write("String %sfound.\n" % txt) else: sys.stdout.write("File %supdated.\n" % txt) return r def update_services(self, line): ''' Modify the __init__.py file having this format: __all__ = ["quagga", "nrl", "xorp", "bird", ] Returns True or False when "check" is the action, a modified line otherwise. ''' line = line.strip('\n') key, valstr = line.split('= ') vals = ast.literal_eval(valstr) r = self.update_keyvals(key, vals) if self.action == "check": return r valstr = '%s' % r return '= '.join([key, valstr]) + '\n' def update_emane_models(self, line): ''' Modify the core.conf file having this format: emane_models = RfPipe, Ieee80211abg, CommEffect, Bypass Returns True or False when "check" is the action, a modified line otherwise. ''' line = line.strip('\n') key, valstr = line.split('= ') vals = valstr.split(', ') r = self.update_keyvals(key, vals) if self.action == "check": return r valstr = ', '.join(r) return '= '.join([key, valstr]) + '\n' def update_keyvals(self, key, vals): ''' Perform self.action on (key, vals). Returns True or False when "check" is the action, a modified line otherwise. ''' if self.action == "check": if self.data in vals: return True else: return False elif self.action == "add": if self.data not in vals: vals.append(self.data) elif self.action == "remove": try: vals.remove(self.data) except ValueError: pass return vals def get_filename(self, target): ''' Return search string and filename based on target. ''' if target == "service": pypath = os.path.dirname(pycore.__file__) filename = os.path.join(pypath, "services", "__init__.py") search = "__all__ =" elif target == "model": filename = os.path.join(CORE_CONF_DIR, "core.conf") search = "emane_models =" elif target == "nodetype": if self.options.userpath is None: raise ValueError, "missing user path" filename = os.path.join(self.options.userpath, "nodes.conf") search = self.data else: raise ValueError, "unknown target" if not os.path.exists(filename): raise ValueError, "file '%s' does not exist" % filename return search, filename def update_file(self, fn=None): ''' Open a file and search for self.search, invoking the supplied function on the matching line. Write file changes if necessary. Returns True if the file has changed (or action is "check" and the search string is found), False otherwise. ''' changed = False output = "" # this accumulates output, assumes input is small with open(self.filename, "r") as f: for line in f: if line[:len(self.search)] == self.search: r = fn(line) # line may be modified by fn() here if self.action == "check": return r else: if line != r: changed = True line = r output += line if changed: with open(self.filename, "w") as f: f.write(output) return changed def update_nodes_conf(self): ''' Add/remove/check entries from nodes.conf. This file contains a Tcl-formatted array of node types. The array index must be properly set for new entries. Uses self.{action, filename, search, data} variables as input and returns the same value as update_file(). ''' changed = False output = "" # this accumulates output, assumes input is small with open(self.filename, "r") as f: for line in f: # make sure data is not added twice if line.find(self.search) >= 0: if self.action == "check": return True elif self.action == "add": return False elif self.action == "remove": changed = True continue else: output += line if self.action == "add": index = int(re.match('^\d+', line).group(0)) output += str(index + 1) + ' ' + self.data + '\n' changed = True if changed: with open(self.filename, "w") as f: f.write(output) return changed def main(): usagestr = "usage: %prog [-h] [options] \n" usagestr += "\nHelper tool to add, remove, or check for " usagestr += "services, models, and node types\nin a CORE installation.\n" usagestr += "\nExamples:\n %prog add service newrouting" usagestr += "\n %prog -v check model RfPipe" usagestr += "\n %prog --userpath=\"$HOME/.core\" add nodetype \"{ftp ftp.gif ftp.gif {DefaultRoute FTP} netns {FTP server} }\" \n" usagestr += "\nArguments:\n should be one of: %s" % \ ', '.join(FileUpdater.actions) usagestr += "\n should be one of: %s" % \ ', '.join(FileUpdater.targets) usagestr += "\n is the text to %s" % \ ', '.join(FileUpdater.actions) parser = optparse.OptionParser(usage = usagestr) parser.set_defaults(userpath = None, verbose = False,) parser.add_option("--userpath", dest = "userpath", type = "string", help = "use the specified user path (e.g. \"$HOME/.core" \ "\") to access nodes.conf") parser.add_option("-v", "--verbose", dest = "verbose", action="store_true", help = "be verbose when performing action") def usage(msg = None, err = 0): sys.stdout.write("\n") if msg: sys.stdout.write(msg + "\n\n") parser.print_help() sys.exit(err) (options, args) = parser.parse_args() if len(args) != 3: usage("Missing required arguments!", 1) action = args[0] if action not in FileUpdater.actions: usage("invalid action '%s'" % action, 1) target = args[1] if target not in FileUpdater.targets: usage("invalid target '%s'" % target, 1) if target == "nodetype" and not options.userpath: usage("user path option required for this target (%s)" % target) data = args[2] try: up = FileUpdater(action, target, data, options) r = up.process() except Exception, e: sys.stderr.write("Exception: %s\n" % e) sys.exit(1) if not r: sys.exit(1) sys.exit(0) if __name__ == "__main__": main() core-4.8/daemon/sbin/core-xen-cleanup0000775000175000017500000000324612534327775014555 00000000000000#!/bin/sh if [ "z$1" = "z-h" -o "z$1" = "z--help" ]; then echo "usage: $0 [-d]" echo -n " Clean up all CORE Xen domUs, bridges, interfaces, " echo "and session\n directories. Options:" echo " -h show this help message and exit" echo " -d also kill the Python daemon" exit 0 fi if [ `id -u` != 0 ]; then echo "Permission denied. Re-run this script as root." exit 1 fi PATH="/sbin:/bin:/usr/sbin:/usr/bin" export PATH if [ "z$1" = "z-d" ]; then pypids=`pidof python python2` for p in $pypids; do grep -q core-daemon /proc/$p/cmdline if [ $? = 0 ]; then echo "cleaning up core-daemon process: $p" kill -9 $p fi done fi mount | awk ' /\/tmp\/pycore\./ { print "umount " $3; system("umount " $3); } ' domus=`xm list | awk ' /^c.*-n.*/ { print $1; }'` for domu in $domus do echo "destroy $domu" xm destroy $domu done vgs=`vgs | awk '{ print $1; }'` for vg in $vgs do if [ ! -x /dev/$vg ]; then continue fi echo "searching volume group: $vg" lvs=`ls /dev/$vg/c*-n*- 2> /dev/null` for lv in $lvs do echo "removing volume $lv" kpartx -d $lv lvchange -an $lv lvremove $lv done done /sbin/ip link show | awk ' /b\.ctrlnet\.[0-9]+/ {print "removing interface " $2; system("ip link set " $2 " down; brctl delbr " $2); } ' ls /sys/class/net | awk ' /^b\.[0-9]+\.[0-9]+$/ {print "removing interface " $1; system("ip link set " $1 " down; brctl delbr " $1); } ' ebtables -L FORWARD | awk ' /^-.*b\./ {print "removing ebtables " $0; system("ebtables -D FORWARD " $0); print "removing ebtables chain " $4; system("ebtables -X " $4);} ' rm -rf /tmp/pycore* core-4.8/daemon/sbin/coresendmsg0000775000175000017500000002720212534327775013717 00000000000000#!/usr/bin/env python # # CORE # Copyright (c)2011-2012 the Boeing Company. # See the LICENSE file included in this distribution. # # authors: Jeff Ahrenholz # ''' coresendmsg: utility for generating CORE messages ''' import sys import socket import optparse import os try: from core.constants import * except ImportError: # hack for Fedora autoconf that uses the following pythondir: if "/usr/lib/python2.6/site-packages" in sys.path: sys.path.append("/usr/local/lib/python2.6/site-packages") if "/usr/lib64/python2.6/site-packages" in sys.path: sys.path.append("/usr/local/lib64/python2.6/site-packages") if "/usr/lib/python2.7/site-packages" in sys.path: sys.path.append("/usr/local/lib/python2.7/site-packages") if "/usr/lib64/python2.7/site-packages" in sys.path: sys.path.append("/usr/local/lib64/python2.7/site-packages") from core.constants import * from core.api import coreapi def msgtypenum_to_str(num): ''' Convert the message type number into a string, such as 1 = 'CORE_API_NODE_MSG' = 'node' ''' fulltypestr = coreapi.message_types[num] r = fulltypestr.split('_')[2] return r.lower() def str_to_msgtypenum(s): ''' Convert a shorthand string into a message type number. ''' fulltypestr = str_to_msgtypename(s) for k, v in coreapi.message_types.iteritems(): if v == fulltypestr: return k return None def str_to_msgtypename(s): ''' Convert a shorthand string into a message type name. ''' return "CORE_API_%s_MSG" % s.upper() def msgflagnum_to_str(num): ''' Convert the message flag number into a string, such as 1 = 'CORE_API_ADD_FLAG' = add ''' fullflagstr = coreapi.message_flags[num] r = fullflagstr.split('_')[2] return r.lower() def str_to_msgflagname(s): ''' Convert a shorthand string into a message flag name. ''' return "CORE_API_%s_FLAG" % s.upper() def str_to_msgflagnum(s): flagname = str_to_msgflagname(s) for (k, v) in coreapi.message_flags.iteritems(): if v == flagname: return k return None def tlvname_to_str(name): ''' Convert a TLV name such as CORE_TLV_CONF_NODE to a short sring 'node'. ''' items = name.split('_')[3:] return '_'.join(items).lower() def tlvname_to_num(tlv_cls, name): ''' Convert the given TLV Type class and TLV name to the TLV number. ''' for (k, v) in tlv_cls.tlvtypemap.iteritems(): if v == name: return k return None def str_to_tlvname(t, s): ''' Convert the given TLV type t and string s to a TLV name. ''' return "CORE_TLV_%s_%s" % (t.upper(), s.upper()) def print_available_tlvs(t, tlv_cls): ''' Print a TLV list. ''' print "TLVs available for %s message:" % t for k in sorted(tlv_cls.tlvtypemap.keys()): print "%d:%s" % (k, tlvname_to_str(tlv_cls.tlvtypemap[k])), def print_examples(name): ''' Print example usage of this script. ''' examples = [ ('link n1number=2 n2number=3 delay=15000', 'set a 15ms delay on the link between n2 and n3'), ('link n1number=2 n2number=3 guiattr=\'color=blue\'', 'change the color of the link between n2 and n3'), ('node number=3 xpos=125 ypos=525', 'move node number 3 to x,y=(125,525)'), ('node number=4 icon=/usr/local/share/core/icons/normal/router_red.gif', 'change node number 4\'s icon to red'), ('node flags=add number=5 type=0 name=\'n5\' xpos=500 ypos=500', 'add a new router node n5'), ('link flags=add n1number=4 n2number=5 if1ip4=\'10.0.3.2\' ' \ 'if1ip4mask=24 if2ip4=\'10.0.3.1\' if2ip4mask=24', 'link node n5 with n4 using the given interface addresses'), ('exec flags=str,txt node=1 num=1000 cmd=\'uname -a\' -l', 'run a command on node 1 and wait for the result'), ('exec node=2 num=1001 cmd=\'killall ospfd\'', 'run a command on node 2 and ignore the result'), ('file flags=add node=1 name=\'/var/log/test.log\' data=\'Hello World.\'', 'write a test.log file on node 1 with the given contents'), ('file flags=add node=2 name=\'test.log\' ' \ 'srcname=\'./test.log\'', 'move a test.log file from host to node 2'), ] print "Example %s invocations:" % name for cmd, descr in examples: print " %s %s\n\t\t%s" % (name, cmd, descr) def receive_message(sock): ''' Retrieve a message from a socket and return the CoreMessage object or None upon disconnect. Socket data beyond the first message is dropped. ''' try: # large receive buffer used for UDP sockets, instead of just receiving # the 4-byte header data = sock.recv(4096) msghdr = data[:coreapi.CoreMessage.hdrsiz] except KeyboardInterrupt: print "CTRL+C pressed" sys.exit(1) if len(msghdr) == 0: return None msgdata = None msgtype, msgflags, msglen = coreapi.CoreMessage.unpackhdr(msghdr) if msglen: msgdata = data[coreapi.CoreMessage.hdrsiz:] try: msgcls = coreapi.msg_class(msgtype) except KeyError: msg = coreapi.CoreMessage(msgflags, msghdr, msgdata) msg.msgtype = msgtype print "unimplemented CORE message type: %s" % msg.typestr() return msg if len(data) > msglen + coreapi.CoreMessage.hdrsiz: print "received a message of type %d, dropping %d bytes of extra data" \ % (msgtype, len(data) - (msglen + coreapi.CoreMessage.hdrsiz)) return msgcls(msgflags, msghdr, msgdata) def connect_to_session(sock, requested): ''' Use Session Messages to retrieve the current list of sessions and connect to the first one. ''' # request the session list tlvdata = coreapi.CoreSessionTlv.pack(coreapi.CORE_TLV_SESS_NUMBER, "0") flags = coreapi.CORE_API_STR_FLAG smsg = coreapi.CoreSessionMessage.pack(flags, tlvdata) sock.sendall(smsg) print "waiting for session list..." smsgreply = receive_message(sock) if smsgreply is None: print "disconnected" return False sessstr = smsgreply.gettlv(coreapi.CORE_TLV_SESS_NUMBER) if sessstr is None: print "missing session numbers" return False # join the first session (that is not our own connection) (tmp, localport) = sock.getsockname() sessions = sessstr.split('|') sessions.remove(str(localport)) if len(sessions) == 0: print "no sessions to join" return False if not requested: session = sessions[0] elif requested in sessions: session = requested else: print "requested session not found!" return False print "joining session %s..." % session tlvdata = coreapi.CoreSessionTlv.pack(coreapi.CORE_TLV_SESS_NUMBER, session) flags = coreapi.CORE_API_ADD_FLAG smsg = coreapi.CoreSessionMessage.pack(flags, tlvdata) sock.sendall(smsg) return True def receive_response(sock, opt): ''' Receive and print a CORE message from the given socket. ''' print "waiting for response..." msg = receive_message(sock) if msg is None: print "disconnected from %s:%s" % (opt.address, opt.port) sys.exit(0) print "received message:", msg def main(): ''' Parse command-line arguments to build and send a CORE message. ''' types = map(msgtypenum_to_str, coreapi.message_types.keys()[:-1]) flags = map(msgflagnum_to_str, sorted(coreapi.message_flags.keys())) usagestr = "usage: %prog [-h|-H] [options] [message-type] [flags=flags] " usagestr += "[message-TLVs]\n\n" usagestr += "Supported message types:\n %s\n" % types usagestr += "Supported message flags (flags=f1,f2,...):\n %s" % flags parser = optparse.OptionParser(usage = usagestr) parser.set_defaults(port = coreapi.CORE_API_PORT, address = "localhost", session = None, listen = False, examples = False, tlvs = False, tcp = False) parser.add_option("-H", dest = "examples", action = "store_true", help = "show example usage help message and exit") parser.add_option("-p", "--port", dest = "port", type = int, help = "TCP port to connect to, default: %d" % \ parser.defaults['port']) parser.add_option("-a", "--address", dest = "address", type = str, help = "Address to connect to, default: %s" % \ parser.defaults['address']) parser.add_option("-s", "--session", dest = "session", type = str, help = "Session to join, default: %s" % \ parser.defaults['session']) parser.add_option("-l", "--listen", dest = "listen", action = "store_true", help = "Listen for a response message and print it.") parser.add_option("-t", "--list-tlvs", dest = "tlvs", action = "store_true", help = "List TLVs for the specified message type.") parser.add_option("-T", "--tcp", dest = "tcp", action = "store_true", help = "Use TCP instead of UDP and connect to a session" \ ", default: %s" % parser.defaults['tcp']) def usage(msg = None, err = 0): sys.stdout.write("\n") if msg: sys.stdout.write(msg + "\n\n") parser.print_help() sys.exit(err) # parse command line opt (opt, args) = parser.parse_args() if (opt.examples): print_examples(os.path.basename(sys.argv[0])) sys.exit(0) if len(args) == 0: usage("Please specify a message type to send.") # given a message type t, determine the message and TLV classes t = args.pop(0) if t not in types: usage("Unknown message type requested: %s" % t) msg_cls = coreapi.msgclsmap[str_to_msgtypenum(t)] tlv_cls = msg_cls.tlvcls # list TLV types for this message type if opt.tlvs: print_available_tlvs(t, tlv_cls) sys.exit(0) # build a message consisting of TLVs from 'type=value' arguments flagstr = "" tlvdata = "" for a in args: typevalue = a.split('=') if len(typevalue) < 2: usage("Use 'type=value' syntax instead of '%s'." % a) tlv_typestr = typevalue[0] tlv_valstr = '='.join(typevalue[1:]) if tlv_typestr == "flags": flagstr = tlv_valstr continue tlv_name = str_to_tlvname(t, tlv_typestr) tlv_type = tlvname_to_num(tlv_cls, tlv_name) if tlv_name not in tlv_cls.tlvtypemap.values(): usage("Unknown TLV: '%s' / %s" % (tlv_typestr, tlv_name)) tlvdata += tlv_cls.packstring(tlv_type, tlv_valstr) flags = 0 for f in flagstr.split(","): if f == '': continue n = str_to_msgflagnum(f) if n is None: usage("Invalid flag '%s'." % f) flags |= n msg = msg_cls.pack(flags, tlvdata) # send the message if opt.tcp: protocol = socket.SOCK_STREAM else: protocol = socket.SOCK_DGRAM sock = socket.socket(socket.AF_INET, protocol) sock.setblocking(True) try: sock.connect((opt.address, opt.port)) except Exception, e: print "Error connecting to %s:%s:\n\t%s" % (opt.address, opt.port, e) sys.exit(1) if opt.tcp and not connect_to_session(sock, opt.session): print "warning: continuing without joining a session!" sock.sendall(msg) if opt.listen: receive_response(sock, opt) if opt.tcp: sock.shutdown(socket.SHUT_RDWR) sock.close() sys.exit(0) if __name__ == "__main__": main() core-4.8/daemon/Makefile.in0000664000175000017500000007600512534327777012601 00000000000000# Makefile.in generated by automake 1.13.4 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 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@ # CORE # (c)2010-2012 the Boeing Company. # See the LICENSE file included in this distribution. # # author: Jeff Ahrenholz # # Makefile for building netns components. # VPATH = @srcdir@ am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' 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 = : subdir = daemon DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ $(dist_coreex_SCRIPTS) $(dist_coreexnetns_SCRIPTS) \ $(dist_sbin_SCRIPTS) $(dist_coreconf_DATA) \ $(dist_coreexmyservices_DATA) $(dist_coreexservices_DATA) ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } am__installdirs = "$(DESTDIR)$(coreexdir)" \ "$(DESTDIR)$(coreexnetnsdir)" "$(DESTDIR)$(sbindir)" \ "$(DESTDIR)$(coreconfdir)" "$(DESTDIR)$(coreexmyservicesdir)" \ "$(DESTDIR)$(coreexservicesdir)" SCRIPTS = $(dist_coreex_SCRIPTS) $(dist_coreexnetns_SCRIPTS) \ $(dist_sbin_SCRIPTS) $(noinst_SCRIPTS) 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 = SOURCES = DIST_SOURCES = RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \ ctags-recursive dvi-recursive html-recursive info-recursive \ install-data-recursive install-dvi-recursive \ install-exec-recursive install-html-recursive \ install-info-recursive install-pdf-recursive \ install-ps-recursive install-recursive installcheck-recursive \ installdirs-recursive pdf-recursive ps-recursive \ tags-recursive uninstall-recursive am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac DATA = $(dist_coreconf_DATA) $(dist_coreexmyservices_DATA) \ $(dist_coreexservices_DATA) RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ distclean-recursive maintainer-clean-recursive am__recursive_targets = \ $(RECURSIVE_TARGETS) \ $(RECURSIVE_CLEAN_TARGETS) \ $(am__extra_recursive_targets) AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \ distdir 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 DIST_SUBDIRS = src ns3 DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) am__relativize = \ dir0=`pwd`; \ sed_first='s,^\([^/]*\)/.*$$,\1,'; \ sed_rest='s,^[^/]*/*,,'; \ sed_last='s,^.*/\([^/]*\)$$,\1,'; \ sed_butlast='s,/*[^/]*$$,,'; \ while test -n "$$dir1"; do \ first=`echo "$$dir1" | sed -e "$$sed_first"`; \ if test "$$first" != "."; then \ if test "$$first" = ".."; then \ dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ else \ first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ if test "$$first2" = "$$first"; then \ dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ else \ dir2="../$$dir2"; \ fi; \ dir0="$$dir0"/"$$first"; \ fi; \ fi; \ dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ done; \ reldir="$$dir2" ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ ARCH = @ARCH@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ BINDIR = @BINDIR@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ COREDPY_VERSION = @COREDPY_VERSION@ CORE_CONF_DIR = @CORE_CONF_DIR@ CORE_DATA_DIR = @CORE_DATA_DIR@ CORE_GUI_CONF_DIR = @CORE_GUI_CONF_DIR@ CORE_LIB_DIR = @CORE_LIB_DIR@ CORE_STATE_DIR = @CORE_STATE_DIR@ CORE_VERSION = @CORE_VERSION@ CORE_VERSION_DATE = @CORE_VERSION_DATE@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ GREP = @GREP@ HELP2MAN = @HELP2MAN@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LDFLAGS = @LDFLAGS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIB_DIR = @LIB_DIR@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ OBJEXT = @OBJEXT@ 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@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PYTHON = @PYTHON@ PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ PYTHON_PLATFORM = @PYTHON_PLATFORM@ PYTHON_PREFIX = @PYTHON_PREFIX@ PYTHON_VERSION = @PYTHON_VERSION@ RANLIB = @RANLIB@ SBINDIR = @SBINDIR@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_CC = @ac_ct_CC@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ brctl_path = @brctl_path@ build_alias = @build_alias@ builddir = @builddir@ convert = @convert@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ ebtables_path = @ebtables_path@ enable_daemon = @enable_daemon@ enable_gui = @enable_gui@ exec_prefix = @exec_prefix@ gmake = @gmake@ help2man = @help2man@ host_alias = @host_alias@ htmldir = @htmldir@ ifconfig_path = @ifconfig_path@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ ip_path = @ip_path@ libdir = @libdir@ libev_CFLAGS = @libev_CFLAGS@ libev_LIBS = @libev_LIBS@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ mount_path = @mount_path@ ngctl_path = @ngctl_path@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgpyexecdir = @pkgpyexecdir@ pkgpythondir = @pkgpythondir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ pyexecdir = @pyexecdir@ pyprefix = @pyprefix@ pythondir = @pythondir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ sysctl_path = @sysctl_path@ target_alias = @target_alias@ tc_path = @tc_path@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ umount_path = @umount_path@ vimage_path = @vimage_path@ with_startup = @with_startup@ SETUPPY = setup.py SETUPPYFLAGS = -v @WANT_NETNS_TRUE@SUBDIRS = src ns3 SBIN_FILES = \ sbin/core-cleanup \ sbin/core-daemon \ sbin/core-manage \ sbin/core-xen-cleanup \ sbin/coresendmsg dist_sbin_SCRIPTS = $(SBIN_FILES) CONF_FILES = \ data/core.conf \ data/xen.conf coreconfdir = $(CORE_CONF_DIR) dist_coreconf_DATA = $(CONF_FILES) EXAMPLE_FILES = \ examples/controlnet_updown \ examples/emanemodel2core.py \ examples/findcore.py \ examples/stopsession.py coreexdir = $(datadir)/core/examples dist_coreex_SCRIPTS = $(EXAMPLE_FILES) EXAMPLE_MYSERVICES_FILES = \ examples/myservices/README.txt \ examples/myservices/__init__.py \ examples/myservices/sample.py coreexmyservicesdir = $(coreexdir)/myservices dist_coreexmyservices_DATA = $(EXAMPLE_MYSERVICES_FILES) EXAMPLE_NETNS_FILES = \ examples/netns/basicrange.py \ examples/netns/distributed.py \ examples/netns/emane80211.py \ examples/netns/howmanynodes.py \ examples/netns/iperf-performance-chain.py \ examples/netns/iperf-performance.sh \ examples/netns/ospfmanetmdrtest.py \ examples/netns/switch.py \ examples/netns/switchtest.py \ examples/netns/twonodes.sh \ examples/netns/wlanemanetests.py \ examples/netns/wlantest.py coreexnetnsdir = $(coreexdir)/netns dist_coreexnetns_SCRIPTS = $(EXAMPLE_NETNS_FILES) EXAMPLE_SERVICES_FILES = \ examples/services/sampleFirewall \ examples/services/sampleIPsec \ examples/services/sampleVPNClient \ examples/services/sampleVPNServer coreexservicesdir = $(coreexdir)/services dist_coreexservices_DATA = $(EXAMPLE_SERVICES_FILES) # Python package build noinst_SCRIPTS = build DISTCLEANFILES = Makefile.in core/*.pyc MANIFEST doc/Makefile.in doc/Makefile \ doc/conf.py core/addons/*.pyc # files to include with distribution tarball EXTRA_DIST = $(SETUPPY) MANIFEST.in CORE.e4p core doc all: all-recursive .SUFFIXES: $(srcdir)/Makefile.in: $(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 daemon/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign daemon/Makefile .PRECIOUS: 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: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): install-dist_coreexSCRIPTS: $(dist_coreex_SCRIPTS) @$(NORMAL_INSTALL) @list='$(dist_coreex_SCRIPTS)'; test -n "$(coreexdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(coreexdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(coreexdir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ if test -f "$$d$$p"; then echo "$$d$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n' \ -e 'h;s|.*|.|' \ -e 'p;x;s,.*/,,;$(transform)' | sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1; } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) { files[d] = files[d] " " $$1; \ if (++n[d] == $(am__install_max)) { \ print "f", d, files[d]; n[d] = 0; files[d] = "" } } \ else { print "f", d "/" $$4, $$1 } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_SCRIPT) $$files '$(DESTDIR)$(coreexdir)$$dir'"; \ $(INSTALL_SCRIPT) $$files "$(DESTDIR)$(coreexdir)$$dir" || exit $$?; \ } \ ; done uninstall-dist_coreexSCRIPTS: @$(NORMAL_UNINSTALL) @list='$(dist_coreex_SCRIPTS)'; test -n "$(coreexdir)" || exit 0; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 's,.*/,,;$(transform)'`; \ dir='$(DESTDIR)$(coreexdir)'; $(am__uninstall_files_from_dir) install-dist_coreexnetnsSCRIPTS: $(dist_coreexnetns_SCRIPTS) @$(NORMAL_INSTALL) @list='$(dist_coreexnetns_SCRIPTS)'; test -n "$(coreexnetnsdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(coreexnetnsdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(coreexnetnsdir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ if test -f "$$d$$p"; then echo "$$d$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n' \ -e 'h;s|.*|.|' \ -e 'p;x;s,.*/,,;$(transform)' | sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1; } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) { files[d] = files[d] " " $$1; \ if (++n[d] == $(am__install_max)) { \ print "f", d, files[d]; n[d] = 0; files[d] = "" } } \ else { print "f", d "/" $$4, $$1 } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_SCRIPT) $$files '$(DESTDIR)$(coreexnetnsdir)$$dir'"; \ $(INSTALL_SCRIPT) $$files "$(DESTDIR)$(coreexnetnsdir)$$dir" || exit $$?; \ } \ ; done uninstall-dist_coreexnetnsSCRIPTS: @$(NORMAL_UNINSTALL) @list='$(dist_coreexnetns_SCRIPTS)'; test -n "$(coreexnetnsdir)" || exit 0; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 's,.*/,,;$(transform)'`; \ dir='$(DESTDIR)$(coreexnetnsdir)'; $(am__uninstall_files_from_dir) install-dist_sbinSCRIPTS: $(dist_sbin_SCRIPTS) @$(NORMAL_INSTALL) @list='$(dist_sbin_SCRIPTS)'; test -n "$(sbindir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(sbindir)'"; \ $(MKDIR_P) "$(DESTDIR)$(sbindir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ if test -f "$$d$$p"; then echo "$$d$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n' \ -e 'h;s|.*|.|' \ -e 'p;x;s,.*/,,;$(transform)' | sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1; } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) { files[d] = files[d] " " $$1; \ if (++n[d] == $(am__install_max)) { \ print "f", d, files[d]; n[d] = 0; files[d] = "" } } \ else { print "f", d "/" $$4, $$1 } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_SCRIPT) $$files '$(DESTDIR)$(sbindir)$$dir'"; \ $(INSTALL_SCRIPT) $$files "$(DESTDIR)$(sbindir)$$dir" || exit $$?; \ } \ ; done uninstall-dist_sbinSCRIPTS: @$(NORMAL_UNINSTALL) @list='$(dist_sbin_SCRIPTS)'; test -n "$(sbindir)" || exit 0; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 's,.*/,,;$(transform)'`; \ dir='$(DESTDIR)$(sbindir)'; $(am__uninstall_files_from_dir) install-dist_coreconfDATA: $(dist_coreconf_DATA) @$(NORMAL_INSTALL) @list='$(dist_coreconf_DATA)'; test -n "$(coreconfdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(coreconfdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(coreconfdir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(coreconfdir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(coreconfdir)" || exit $$?; \ done uninstall-dist_coreconfDATA: @$(NORMAL_UNINSTALL) @list='$(dist_coreconf_DATA)'; test -n "$(coreconfdir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(coreconfdir)'; $(am__uninstall_files_from_dir) install-dist_coreexmyservicesDATA: $(dist_coreexmyservices_DATA) @$(NORMAL_INSTALL) @list='$(dist_coreexmyservices_DATA)'; test -n "$(coreexmyservicesdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(coreexmyservicesdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(coreexmyservicesdir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(coreexmyservicesdir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(coreexmyservicesdir)" || exit $$?; \ done uninstall-dist_coreexmyservicesDATA: @$(NORMAL_UNINSTALL) @list='$(dist_coreexmyservices_DATA)'; test -n "$(coreexmyservicesdir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(coreexmyservicesdir)'; $(am__uninstall_files_from_dir) install-dist_coreexservicesDATA: $(dist_coreexservices_DATA) @$(NORMAL_INSTALL) @list='$(dist_coreexservices_DATA)'; test -n "$(coreexservicesdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(coreexservicesdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(coreexservicesdir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(coreexservicesdir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(coreexservicesdir)" || exit $$?; \ done uninstall-dist_coreexservicesDATA: @$(NORMAL_UNINSTALL) @list='$(dist_coreexservices_DATA)'; test -n "$(coreexservicesdir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(coreexservicesdir)'; $(am__uninstall_files_from_dir) # This directory's subdirectories are mostly independent; you can cd # into them and run 'make' without going through this Makefile. # To change the values of 'make' variables: instead of editing Makefiles, # (1) if the variable is set in 'config.status', edit 'config.status' # (which will cause the Makefiles to be regenerated when you run 'make'); # (2) otherwise, pass the desired values on the 'make' command line. $(am__recursive_targets): @fail=; \ if $(am__make_keepgoing); then \ failcom='fail=yes'; \ else \ failcom='exit 1'; \ fi; \ dot_seen=no; \ target=`echo $@ | sed s/-recursive//`; \ case "$@" in \ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ *) list='$(SUBDIRS)' ;; \ esac; \ for subdir in $$list; do \ echo "Making $$target in $$subdir"; \ if test "$$subdir" = "."; then \ dot_seen=yes; \ local_target="$$target-am"; \ else \ local_target="$$target"; \ fi; \ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ || eval $$failcom; \ done; \ if test "$$dot_seen" = "no"; then \ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ fi; test -z "$$fail" ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-recursive TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ include_option=--etags-include; \ empty_fix=.; \ else \ include_option=--include; \ empty_fix=; \ fi; \ list='$(SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ test ! -f $$subdir/TAGS || \ set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ fi; \ done; \ $(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-recursive 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-recursive 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 @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ $(am__make_dryrun) \ || test -d "$(distdir)/$$subdir" \ || $(MKDIR_P) "$(distdir)/$$subdir" \ || exit 1; \ dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ $(am__relativize); \ new_distdir=$$reldir; \ dir1=$$subdir; dir2="$(top_distdir)"; \ $(am__relativize); \ new_top_distdir=$$reldir; \ echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ ($(am__cd) $$subdir && \ $(MAKE) $(AM_MAKEFLAGS) \ top_distdir="$$new_top_distdir" \ distdir="$$new_distdir" \ am__remove_distdir=: \ am__skip_length_check=: \ am__skip_mode_fix=: \ distdir) \ || exit 1; \ fi; \ done $(MAKE) $(AM_MAKEFLAGS) \ top_distdir="$(top_distdir)" distdir="$(distdir)" \ dist-hook check-am: all-am check: check-recursive all-am: Makefile $(SCRIPTS) $(DATA) installdirs: installdirs-recursive installdirs-am: for dir in "$(DESTDIR)$(coreexdir)" "$(DESTDIR)$(coreexnetnsdir)" "$(DESTDIR)$(sbindir)" "$(DESTDIR)$(coreconfdir)" "$(DESTDIR)$(coreexmyservicesdir)" "$(DESTDIR)$(coreexservicesdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-recursive install-exec: install-exec-recursive install-data: install-data-recursive uninstall: uninstall-recursive install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-recursive 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) -test -z "$(DISTCLEANFILES)" || rm -f $(DISTCLEANFILES) 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-recursive clean-am: clean-generic clean-local mostlyclean-am distclean: distclean-recursive -rm -f Makefile distclean-am: clean-am distclean-generic distclean-tags dvi: dvi-recursive dvi-am: html: html-recursive html-am: info: info-recursive info-am: install-data-am: install-dist_coreconfDATA install-dist_coreexSCRIPTS \ install-dist_coreexmyservicesDATA \ install-dist_coreexnetnsSCRIPTS \ install-dist_coreexservicesDATA install-dvi: install-dvi-recursive install-dvi-am: install-exec-am: install-dist_sbinSCRIPTS @$(NORMAL_INSTALL) $(MAKE) $(AM_MAKEFLAGS) install-exec-hook install-html: install-html-recursive install-html-am: install-info: install-info-recursive install-info-am: install-man: install-pdf: install-pdf-recursive install-pdf-am: install-ps: install-ps-recursive install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-recursive -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-recursive mostlyclean-am: mostlyclean-generic pdf: pdf-recursive pdf-am: ps: ps-recursive ps-am: uninstall-am: uninstall-dist_coreconfDATA uninstall-dist_coreexSCRIPTS \ uninstall-dist_coreexmyservicesDATA \ uninstall-dist_coreexnetnsSCRIPTS \ uninstall-dist_coreexservicesDATA uninstall-dist_sbinSCRIPTS @$(NORMAL_INSTALL) $(MAKE) $(AM_MAKEFLAGS) uninstall-hook .MAKE: $(am__recursive_targets) install-am install-exec-am \ install-strip uninstall-am .PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am check \ check-am clean clean-generic clean-local cscopelist-am ctags \ ctags-am dist-hook distclean distclean-generic distclean-tags \ distdir dvi dvi-am html html-am info info-am install \ install-am install-data install-data-am \ install-dist_coreconfDATA install-dist_coreexSCRIPTS \ install-dist_coreexmyservicesDATA \ install-dist_coreexnetnsSCRIPTS \ install-dist_coreexservicesDATA install-dist_sbinSCRIPTS \ install-dvi install-dvi-am install-exec install-exec-am \ install-exec-hook 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 installdirs-am maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-generic pdf \ pdf-am ps ps-am tags tags-am uninstall uninstall-am \ uninstall-dist_coreconfDATA uninstall-dist_coreexSCRIPTS \ uninstall-dist_coreexmyservicesDATA \ uninstall-dist_coreexnetnsSCRIPTS \ uninstall-dist_coreexservicesDATA uninstall-dist_sbinSCRIPTS \ uninstall-hook build: $(PYTHON) $(SETUPPY) $(SETUPPYFLAGS) build # Python package install install-exec-hook: $(PYTHON) $(SETUPPY) $(SETUPPYFLAGS) install --prefix=${DESTDIR}/${pyprefix} --install-purelib=${DESTDIR}/${pythondir} --install-platlib=${DESTDIR}/${pyexecdir} --no-compile # Python package uninstall uninstall-hook: rm -f ${pythondir}/core_python-${COREDPY_VERSION}-py${PYTHON_VERSION}.egg-info rm -f ${pythondir}/core_python_netns-1.0-py${PYTHON_VERSION}.egg-info rm -rf ${pythondir}/core rmdir -p $(coreexservicesdir) || true rmdir -p $(coreexnetnsdir) || true rmdir -p $(coreexmyservicesdir) || true rmdir -p $(coreexdir) || true rmdir -p $(coreconfdir) || true # Python package cleanup clean-local: -rm -rf build # Python RPM package rpm: $(PYTHON) $(SETUPPY) $(SETUPPYFLAGS) bdist_rpm # because we include entire directories with EXTRA_DIST, we need to clean up # the source control files dist-hook: rm -rf `find $(distdir)/ -name .svn` `find $(distdir)/ -name '*.pyc'` # 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: core-4.8/daemon/Makefile.am0000664000175000017500000000601112534327775012554 00000000000000# CORE # (c)2010-2012 the Boeing Company. # See the LICENSE file included in this distribution. # # author: Jeff Ahrenholz # # Makefile for building netns components. # SETUPPY = setup.py SETUPPYFLAGS = -v if WANT_NETNS SUBDIRS = src ns3 endif SBIN_FILES = \ sbin/core-cleanup \ sbin/core-daemon \ sbin/core-manage \ sbin/core-xen-cleanup \ sbin/coresendmsg dist_sbin_SCRIPTS = $(SBIN_FILES) CONF_FILES = \ data/core.conf \ data/xen.conf coreconfdir = $(CORE_CONF_DIR) dist_coreconf_DATA = $(CONF_FILES) EXAMPLE_FILES = \ examples/controlnet_updown \ examples/emanemodel2core.py \ examples/findcore.py \ examples/stopsession.py coreexdir = $(datadir)/core/examples dist_coreex_SCRIPTS = $(EXAMPLE_FILES) EXAMPLE_MYSERVICES_FILES = \ examples/myservices/README.txt \ examples/myservices/__init__.py \ examples/myservices/sample.py coreexmyservicesdir = $(coreexdir)/myservices dist_coreexmyservices_DATA = $(EXAMPLE_MYSERVICES_FILES) EXAMPLE_NETNS_FILES = \ examples/netns/basicrange.py \ examples/netns/distributed.py \ examples/netns/emane80211.py \ examples/netns/howmanynodes.py \ examples/netns/iperf-performance-chain.py \ examples/netns/iperf-performance.sh \ examples/netns/ospfmanetmdrtest.py \ examples/netns/switch.py \ examples/netns/switchtest.py \ examples/netns/twonodes.sh \ examples/netns/wlanemanetests.py \ examples/netns/wlantest.py coreexnetnsdir = $(coreexdir)/netns dist_coreexnetns_SCRIPTS= $(EXAMPLE_NETNS_FILES) EXAMPLE_SERVICES_FILES = \ examples/services/sampleFirewall \ examples/services/sampleIPsec \ examples/services/sampleVPNClient \ examples/services/sampleVPNServer coreexservicesdir = $(coreexdir)/services dist_coreexservices_DATA= $(EXAMPLE_SERVICES_FILES) # Python package build noinst_SCRIPTS = build build: $(PYTHON) $(SETUPPY) $(SETUPPYFLAGS) build # Python package install install-exec-hook: $(PYTHON) $(SETUPPY) $(SETUPPYFLAGS) install --prefix=${DESTDIR}/${pyprefix} --install-purelib=${DESTDIR}/${pythondir} --install-platlib=${DESTDIR}/${pyexecdir} --no-compile # Python package uninstall uninstall-hook: rm -f ${pythondir}/core_python-${COREDPY_VERSION}-py${PYTHON_VERSION}.egg-info rm -f ${pythondir}/core_python_netns-1.0-py${PYTHON_VERSION}.egg-info rm -rf ${pythondir}/core rmdir -p $(coreexservicesdir) || true rmdir -p $(coreexnetnsdir) || true rmdir -p $(coreexmyservicesdir) || true rmdir -p $(coreexdir) || true rmdir -p $(coreconfdir) || true # Python package cleanup clean-local: -rm -rf build # Python RPM package rpm: $(PYTHON) $(SETUPPY) $(SETUPPYFLAGS) bdist_rpm # because we include entire directories with EXTRA_DIST, we need to clean up # the source control files dist-hook: rm -rf `find $(distdir)/ -name .svn` `find $(distdir)/ -name '*.pyc'` DISTCLEANFILES = Makefile.in core/*.pyc MANIFEST doc/Makefile.in doc/Makefile \ doc/conf.py core/addons/*.pyc # files to include with distribution tarball EXTRA_DIST = $(SETUPPY) MANIFEST.in CORE.e4p core doc core-4.8/daemon/setup.py0000664000175000017500000000150312534327775012233 00000000000000# Copyright (c)2010-2012 the Boeing Company. # See the LICENSE file included in this distribution. import os, glob from distutils.core import setup from core.constants import COREDPY_VERSION setup(name = "core-python", version = COREDPY_VERSION, packages = [ "core", "core.addons", "core.api", "core.emane", "core.misc", "core.bsd", "core.netns", "core.phys", "core.xen", "core.services", ], description = "Python components of CORE", url = "http://www.nrl.navy.mil/itd/ncs/products/core", author = "Boeing Research & Technology", author_email = "core-dev@pf.itd.nrl.navy.mil", license = "BSD", long_description="Python scripts and modules for building virtual " \ "emulated networks.") core-4.8/daemon/MANIFEST.in0000664000175000017500000000022012534327775012252 00000000000000recursive-include sbin *.sh *.py include data/core.conf recursive-include examples/netns *.py *.sh recursive-exclude examples/netns *.pyc *.pyo core-4.8/daemon/CORE.e4p0000664000175000017500000001445012534327775011670 00000000000000 en Python Console 4.0 setup.py examples/netns/switchtest.py examples/netns/ospfmanetmdrtest.py examples/netns/switch.py examples/netns/wlantest.py examples/stopsession.py src/setup.py core/emane/__init__.py core/emane/emane.py core/emane/ieee80211abg.py core/emane/rfpipe.py core/emane/nodes.py core/netns/vif.py core/netns/vnet.py core/netns/__init__.py core/netns/vnode.py core/netns/vnodeclient.py core/netns/nodes.py core/service.py core/__init__.py core/addons/__init__.py core/broker.py core/services/__init__.py core/services/quagga.py core/misc/LatLongUTMconversion.py core/misc/__init__.py core/misc/ipaddr.py core/misc/quagga.py core/misc/utils.py core/pycore.py core/coreobj.py core/location.py core/session.py core/api/__init__.py core/api/data.py core/api/coreapi.py core/services/nrl.py core/services/utility.py core/bsd/netgraph.py core/bsd/__init__.py core/bsd/nodes.py core/bsd/vnet.py core/bsd/vnode.py core/xen/xen.py core/xen/xenconfig.py core/xen/__init__.py examples/myservices/sample.py examples/myservices/__init__.py core/services/security.py core/emane/universal.py examples/netns/wlanemanetests.py core/services/xorp.py core/misc/xmlutils.py core/mobility.py core/phys/pnodes.py core/phys/__init__.py ns3/setup.py ns3/corens3/__init__.py ns3/corens3/constants.py ns3/corens3/obj.py ns3/examples/ns3wifi.py ns3/examples/ns3lte.py ns3/examples/ns3wimax.py core/emane/commeffect.py core/services/ucarp.py core/emane/bypass.py core/conf.py core/misc/event.py core/sdt.py core/services/bird.py examples/netns/basicrange.py examples/netns/howmanynodes.py sbin/core-daemon sbin/coresendmsg sbin/core-cleanup sbin/core-xen-cleanup ns3/examples/ns3wifirandomwalk.py core/misc/utm.py Subversion add checkout commit diff export global history log remove status tag update standardLayout True core-4.8/daemon/doc/0000775000175000017500000000000012534330005011323 500000000000000core-4.8/daemon/doc/.gitignore0000664000175000017500000000002512534327775013254 00000000000000*.rst _build conf.py core-4.8/daemon/doc/Makefile.am0000664000175000017500000001216112534327775013324 00000000000000# CORE # (c)2012 the Boeing Company. # See the LICENSE file included in this distribution. # # author: Jeff Ahrenholz # # Builds html and pdf documentation using Sphinx. # # extra cruft to remove DISTCLEANFILES = conf.py Makefile.in stamp-vti *.rst all: index.rst # auto-generated Python documentation using Sphinx index.rst: sphinx-apidoc -o . ../core mv modules.rst index.rst ###### below this line was generated using sphinx-quickstart ###### # Makefile for Sphinx documentation # # You can set these variables from the command line. SPHINXOPTS = SPHINXBUILD = sphinx-build PAPER = BUILDDIR = _build # Internal variables. PAPEROPT_a4 = -D latex_paper_size=a4 PAPEROPT_letter = -D latex_paper_size=letter ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . .PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest help: @echo "Please use \`make ' where is one of" @echo " html to make standalone HTML files" @echo " dirhtml to make HTML files named index.html in directories" @echo " singlehtml to make a single large HTML file" @echo " pickle to make pickle files" @echo " json to make JSON files" @echo " htmlhelp to make HTML files and a HTML help project" @echo " qthelp to make HTML files and a qthelp project" @echo " devhelp to make HTML files and a Devhelp project" @echo " epub to make an epub" @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" @echo " latexpdf to make LaTeX files and run them through pdflatex" @echo " text to make text files" @echo " man to make manual pages" @echo " changes to make an overview of all changed/added/deprecated items" @echo " linkcheck to check all external links for integrity" @echo " doctest to run all doctests embedded in the documentation (if enabled)" clean-local: -rm -rf $(BUILDDIR) html: index.rst $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." dirhtml: index.rst $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." singlehtml: index.rst $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml @echo @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." pickle: index.rst $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle @echo @echo "Build finished; now you can process the pickle files." json: index.rst $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json @echo @echo "Build finished; now you can process the JSON files." htmlhelp: index.rst $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp @echo @echo "Build finished; now you can run HTML Help Workshop with the" \ ".hhp project file in $(BUILDDIR)/htmlhelp." qthelp: index.rst $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp @echo @echo "Build finished; now you can run "qcollectiongenerator" with the" \ ".qhcp project file in $(BUILDDIR)/qthelp, like this:" @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/CORE.qhcp" @echo "To view the help file:" @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/CORE.qhc" devhelp: index.rst $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp @echo @echo "Build finished." @echo "To view the help file:" @echo "# mkdir -p $$HOME/.local/share/devhelp/CORE" @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/CORE" @echo "# devhelp" epub: index.rst $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub @echo @echo "Build finished. The epub file is in $(BUILDDIR)/epub." latex: index.rst $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." @echo "Run \`make' in that directory to run these through (pdf)latex" \ "(use \`make latexpdf' here to do that automatically)." latexpdf: index.rst $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo "Running LaTeX files through pdflatex..." make -C $(BUILDDIR)/latex all-pdf @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." text: index.rst $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text @echo @echo "Build finished. The text files are in $(BUILDDIR)/text." man: index.rst $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man @echo @echo "Build finished. The manual pages are in $(BUILDDIR)/man." changes: index.rst $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes @echo @echo "The overview file is in $(BUILDDIR)/changes." linkcheck: index.rst $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck @echo @echo "Link check complete; look for any errors in the above output " \ "or in $(BUILDDIR)/linkcheck/output.txt." doctest: index.rst $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest @echo "Testing of doctests in the sources finished, look at the " \ "results in $(BUILDDIR)/doctest/output.txt." core-4.8/daemon/doc/conf.py.in0000664000175000017500000002005212534327775013172 00000000000000# -*- coding: utf-8 -*- # # CORE Python documentation build configuration file, created by # sphinx-quickstart on Wed Jun 13 10:44:22 2012. # # This file is execfile()d with the current directory set to its containing dir. # # Note that not all possible configuration values are present in this # autogenerated file. # # All configuration values have a default; values that are commented out # serve to show the default. import sys, os # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. #sys.path.insert(0, os.path.abspath('.')) # -- General configuration ----------------------------------------------------- # If your documentation needs a minimal Sphinx version, state it here. #needs_sphinx = '1.0' # Add any Sphinx extension module names here, as strings. They can be extensions # coming with Sphinx (named 'sphinx.ext.*') or your custom ones. extensions = ['sphinx.ext.autodoc', 'sphinx.ext.todo', 'sphinx.ext.pngmath', 'sphinx.ext.ifconfig'] # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] # The suffix of source filenames. source_suffix = '.rst' # The encoding of source files. #source_encoding = 'utf-8-sig' # The master toctree document. master_doc = 'index' # General information about the project. project = u'CORE Python modules' copyright = u'2012, core-dev' # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the # built documents. # # The short X.Y version. version = '@CORE_VERSION@' # The full version, including alpha/beta/rc tags. release = '@CORE_VERSION@' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. #language = None # There are two options for replacing |today|: either, you set today to some # non-false value, then it is used: #today = '' # Else, today_fmt is used as the format for a strftime call. #today_fmt = '%B %d, %Y' # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. exclude_patterns = ['_build'] # The reST default role (used for this markup: `text`) to use for all documents. #default_role = None # If true, '()' will be appended to :func: etc. cross-reference text. #add_function_parentheses = True # If true, the current module name will be prepended to all description # unit titles (such as .. function::). #add_module_names = True # If true, sectionauthor and moduleauthor directives will be shown in the # output. They are ignored by default. #show_authors = False # The name of the Pygments (syntax highlighting) style to use. pygments_style = 'sphinx' # A list of ignored prefixes for module index sorting. #modindex_common_prefix = [] # -- Options for HTML output --------------------------------------------------- # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. html_theme = 'default' # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the # documentation. #html_theme_options = {} # Add any paths that contain custom themes here, relative to this directory. #html_theme_path = [] # The name for this set of Sphinx documents. If None, it defaults to # " v documentation". #html_title = None # A shorter title for the navigation bar. Default is the same as html_title. #html_short_title = None # The name of an image file (relative to this directory) to place at the top # of the sidebar. #html_logo = None # The name of an image file (within the static path) to use as favicon of the # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 # pixels large. #html_favicon = None # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". html_static_path = ['_static'] # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, # using the given strftime format. #html_last_updated_fmt = '%b %d, %Y' # If true, SmartyPants will be used to convert quotes and dashes to # typographically correct entities. #html_use_smartypants = True # Custom sidebar templates, maps document names to template names. #html_sidebars = {} # Additional templates that should be rendered to pages, maps page names to # template names. #html_additional_pages = {} # If false, no module index is generated. #html_domain_indices = True # If false, no index is generated. #html_use_index = True # If true, the index is split into individual pages for each letter. #html_split_index = False # If true, links to the reST sources are added to the pages. #html_show_sourcelink = True # If true, "Created using Sphinx" is shown in the HTML footer. Default is True. #html_show_sphinx = True # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. #html_show_copyright = True # If true, an OpenSearch description file will be output, and all pages will # contain a tag referring to it. The value of this option must be the # base URL from which the finished HTML is served. #html_use_opensearch = '' # This is the file name suffix for HTML files (e.g. ".xhtml"). #html_file_suffix = None # Output file base name for HTML help builder. htmlhelp_basename = 'COREpythondoc' # -- Options for LaTeX output -------------------------------------------------- # The paper size ('letter' or 'a4'). #latex_paper_size = 'letter' # The font size ('10pt', '11pt' or '12pt'). #latex_font_size = '10pt' # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, author, documentclass [howto/manual]). latex_documents = [ ('index', 'index.tex', u'CORE Python Documentation', u'core-dev', 'manual'), ] # The name of an image file (relative to this directory) to place at the top of # the title page. #latex_logo = None # For "manual" documents, if this is true, then toplevel headings are parts, # not chapters. #latex_use_parts = False # If true, show page references after internal links. #latex_show_pagerefs = False # If true, show URL addresses after external links. #latex_show_urls = False # Additional stuff for the LaTeX preamble. #latex_preamble = '' # Documents to append as an appendix to all manuals. #latex_appendices = [] # If false, no module index is generated. #latex_domain_indices = True # -- Options for manual page output -------------------------------------------- # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). man_pages = [ ('index', 'core-python', u'CORE Python Documentation', [u'core-dev'], 1) ] # -- Options for Epub output --------------------------------------------------- # Bibliographic Dublin Core info. epub_title = u'CORE Python' epub_author = u'core-dev' epub_publisher = u'core-dev' epub_copyright = u'2012, core-dev' # The language of the text. It defaults to the language option # or en if the language is not set. #epub_language = '' # The scheme of the identifier. Typical schemes are ISBN or URL. #epub_scheme = '' # The unique identifier of the text. This can be a ISBN number # or the project homepage. #epub_identifier = '' # A unique identification for the text. #epub_uid = '' # HTML files that should be inserted before the pages created by sphinx. # The format is a list of tuples containing the path and title. #epub_pre_files = [] # HTML files shat should be inserted after the pages created by sphinx. # The format is a list of tuples containing the path and title. #epub_post_files = [] # A list of files that should not be packed into the epub file. #epub_exclude_files = [] # The depth of the table of contents in toc.ncx. #epub_tocdepth = 3 # Allow duplicate toc entries. #epub_tocdup = True core-4.8/daemon/doc/Makefile.in0000664000175000017500000004206212534330000013307 00000000000000# Makefile.in generated by automake 1.13.4 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 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@ # CORE # (c)2012 the Boeing Company. # See the LICENSE file included in this distribution. # # author: Jeff Ahrenholz # # Builds html and pdf documentation using Sphinx. # VPATH = @srcdir@ am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' 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 = : subdir = daemon/doc DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ $(srcdir)/conf.py.in ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = conf.py CONFIG_CLEAN_VPATH_FILES = 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 = SOURCES = DIST_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) DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ ARCH = @ARCH@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ BINDIR = @BINDIR@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ COREDPY_VERSION = @COREDPY_VERSION@ CORE_CONF_DIR = @CORE_CONF_DIR@ CORE_DATA_DIR = @CORE_DATA_DIR@ CORE_GUI_CONF_DIR = @CORE_GUI_CONF_DIR@ CORE_LIB_DIR = @CORE_LIB_DIR@ CORE_STATE_DIR = @CORE_STATE_DIR@ CORE_VERSION = @CORE_VERSION@ CORE_VERSION_DATE = @CORE_VERSION_DATE@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ GREP = @GREP@ HELP2MAN = @HELP2MAN@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LDFLAGS = @LDFLAGS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIB_DIR = @LIB_DIR@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ OBJEXT = @OBJEXT@ 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@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PYTHON = @PYTHON@ PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ PYTHON_PLATFORM = @PYTHON_PLATFORM@ PYTHON_PREFIX = @PYTHON_PREFIX@ PYTHON_VERSION = @PYTHON_VERSION@ RANLIB = @RANLIB@ SBINDIR = @SBINDIR@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_CC = @ac_ct_CC@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ brctl_path = @brctl_path@ build_alias = @build_alias@ builddir = @builddir@ convert = @convert@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ ebtables_path = @ebtables_path@ enable_daemon = @enable_daemon@ enable_gui = @enable_gui@ exec_prefix = @exec_prefix@ gmake = @gmake@ help2man = @help2man@ host_alias = @host_alias@ htmldir = @htmldir@ ifconfig_path = @ifconfig_path@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ ip_path = @ip_path@ libdir = @libdir@ libev_CFLAGS = @libev_CFLAGS@ libev_LIBS = @libev_LIBS@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ mount_path = @mount_path@ ngctl_path = @ngctl_path@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgpyexecdir = @pkgpyexecdir@ pkgpythondir = @pkgpythondir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ pyexecdir = @pyexecdir@ pyprefix = @pyprefix@ pythondir = @pythondir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ sysctl_path = @sysctl_path@ target_alias = @target_alias@ tc_path = @tc_path@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ umount_path = @umount_path@ vimage_path = @vimage_path@ with_startup = @with_startup@ # extra cruft to remove DISTCLEANFILES = conf.py Makefile.in stamp-vti *.rst ###### below this line was generated using sphinx-quickstart ###### # Makefile for Sphinx documentation # # You can set these variables from the command line. SPHINXOPTS = SPHINXBUILD = sphinx-build PAPER = BUILDDIR = _build # Internal variables. PAPEROPT_a4 = -D latex_paper_size=a4 PAPEROPT_letter = -D latex_paper_size=letter ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . all: all-am .SUFFIXES: $(srcdir)/Makefile.in: $(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 daemon/doc/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign daemon/doc/Makefile .PRECIOUS: 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: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): conf.py: $(top_builddir)/config.status $(srcdir)/conf.py.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ tags TAGS: ctags CTAGS: cscope cscopelist: 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 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) -test -z "$(DISTCLEANFILES)" || rm -f $(DISTCLEANFILES) 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-local mostlyclean-am distclean: distclean-am -rm -f Makefile distclean-am: clean-am distclean-generic dvi: dvi-am dvi-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 -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-generic pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: .MAKE: install-am install-strip .PHONY: all all-am check check-am clean clean-generic clean-local \ cscopelist-am ctags-am distclean distclean-generic 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-generic pdf \ pdf-am ps ps-am tags-am uninstall uninstall-am all: index.rst # auto-generated Python documentation using Sphinx index.rst: sphinx-apidoc -o . ../core mv modules.rst index.rst .PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest help: @echo "Please use \`make ' where is one of" @echo " html to make standalone HTML files" @echo " dirhtml to make HTML files named index.html in directories" @echo " singlehtml to make a single large HTML file" @echo " pickle to make pickle files" @echo " json to make JSON files" @echo " htmlhelp to make HTML files and a HTML help project" @echo " qthelp to make HTML files and a qthelp project" @echo " devhelp to make HTML files and a Devhelp project" @echo " epub to make an epub" @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" @echo " latexpdf to make LaTeX files and run them through pdflatex" @echo " text to make text files" @echo " man to make manual pages" @echo " changes to make an overview of all changed/added/deprecated items" @echo " linkcheck to check all external links for integrity" @echo " doctest to run all doctests embedded in the documentation (if enabled)" clean-local: -rm -rf $(BUILDDIR) html: index.rst $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." dirhtml: index.rst $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." singlehtml: index.rst $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml @echo @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." pickle: index.rst $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle @echo @echo "Build finished; now you can process the pickle files." json: index.rst $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json @echo @echo "Build finished; now you can process the JSON files." htmlhelp: index.rst $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp @echo @echo "Build finished; now you can run HTML Help Workshop with the" \ ".hhp project file in $(BUILDDIR)/htmlhelp." qthelp: index.rst $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp @echo @echo "Build finished; now you can run "qcollectiongenerator" with the" \ ".qhcp project file in $(BUILDDIR)/qthelp, like this:" @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/CORE.qhcp" @echo "To view the help file:" @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/CORE.qhc" devhelp: index.rst $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp @echo @echo "Build finished." @echo "To view the help file:" @echo "# mkdir -p $$HOME/.local/share/devhelp/CORE" @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/CORE" @echo "# devhelp" epub: index.rst $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub @echo @echo "Build finished. The epub file is in $(BUILDDIR)/epub." latex: index.rst $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." @echo "Run \`make' in that directory to run these through (pdf)latex" \ "(use \`make latexpdf' here to do that automatically)." latexpdf: index.rst $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo "Running LaTeX files through pdflatex..." make -C $(BUILDDIR)/latex all-pdf @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." text: index.rst $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text @echo @echo "Build finished. The text files are in $(BUILDDIR)/text." man: index.rst $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man @echo @echo "Build finished. The manual pages are in $(BUILDDIR)/man." changes: index.rst $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes @echo @echo "The overview file is in $(BUILDDIR)/changes." linkcheck: index.rst $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck @echo @echo "Link check complete; look for any errors in the above output " \ "or in $(BUILDDIR)/linkcheck/output.txt." doctest: index.rst $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest @echo "Testing of doctests in the sources finished, look at the " \ "results in $(BUILDDIR)/doctest/output.txt." # 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: core-4.8/daemon/doc/Makefile0000664000175000017500000004274012534330005012712 00000000000000# Makefile.in generated by automake 1.13.4 from Makefile.am. # daemon/doc/Makefile. Generated from Makefile.in by configure. # Copyright (C) 1994-2013 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. # CORE # (c)2012 the Boeing Company. # See the LICENSE file included in this distribution. # # author: Jeff Ahrenholz # # Builds html and pdf documentation using Sphinx. # am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' 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)/core pkgincludedir = $(includedir)/core pkglibdir = $(libdir)/core pkglibexecdir = $(libexecdir)/core 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 = : subdir = daemon/doc DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ $(srcdir)/conf.py.in ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = conf.py CONFIG_CLEAN_VPATH_FILES = AM_V_P = $(am__v_P_$(V)) am__v_P_ = $(am__v_P_$(AM_DEFAULT_VERBOSITY)) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_$(V)) am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY)) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_$(V)) am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY)) am__v_at_0 = @ am__v_at_1 = SOURCES = DIST_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) DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = ${SHELL} /home/tgoff/work/core/repos/pf.itd.nrl.navy.mil/tmp/core/trunk/config/missing aclocal-1.13 AMTAR = $${TAR-tar} AM_DEFAULT_VERBOSITY = 1 ARCH = amd64 AUTOCONF = ${SHELL} /home/tgoff/work/core/repos/pf.itd.nrl.navy.mil/tmp/core/trunk/config/missing autoconf AUTOHEADER = ${SHELL} /home/tgoff/work/core/repos/pf.itd.nrl.navy.mil/tmp/core/trunk/config/missing autoheader AUTOMAKE = ${SHELL} /home/tgoff/work/core/repos/pf.itd.nrl.navy.mil/tmp/core/trunk/config/missing automake-1.13 AWK = gawk BINDIR = /usr/bin CC = gcc CCDEPMODE = depmode=gcc3 CFLAGS = -O3 -Werror -Wall -D_GNU_SOURCE COREDPY_VERSION = 4.8 CORE_CONF_DIR = /etc/core CORE_DATA_DIR = /usr/share/core CORE_GUI_CONF_DIR = ${HOME}/.core CORE_LIB_DIR = /usr/lib/core CORE_STATE_DIR = /var CORE_VERSION = 4.8 CORE_VERSION_DATE = 20150605 CPP = gcc -E CPPFLAGS = CYGPATH_W = echo DEFS = -DHAVE_CONFIG_H DEPDIR = .deps ECHO_C = ECHO_N = -n ECHO_T = EGREP = /usr/bin/grep -E EXEEXT = GREP = /usr/bin/grep HELP2MAN = ${SHELL} /home/tgoff/work/core/repos/pf.itd.nrl.navy.mil/tmp/core/trunk/config/missing help2man INSTALL = /usr/bin/install -c INSTALL_DATA = ${INSTALL} -m 644 INSTALL_PROGRAM = ${INSTALL} INSTALL_SCRIPT = ${INSTALL} INSTALL_STRIP_PROGRAM = $(install_sh) -c -s LDFLAGS = LIBOBJS = LIBS = LIB_DIR = /usr/lib LTLIBOBJS = MAKEINFO = ${SHELL} /home/tgoff/work/core/repos/pf.itd.nrl.navy.mil/tmp/core/trunk/config/missing makeinfo MKDIR_P = /usr/bin/mkdir -p OBJEXT = o PACKAGE = core PACKAGE_BUGREPORT = core-dev@pf.itd.nrl.navy.mil PACKAGE_NAME = core PACKAGE_STRING = core 4.8 PACKAGE_TARNAME = core PACKAGE_URL = PACKAGE_VERSION = 4.8 PATH_SEPARATOR = : PKG_CONFIG = /usr/bin/pkg-config PKG_CONFIG_LIBDIR = PKG_CONFIG_PATH = PYTHON = /usr/bin/python PYTHON_EXEC_PREFIX = ${exec_prefix} PYTHON_PLATFORM = linux2 PYTHON_PREFIX = ${prefix} PYTHON_VERSION = 2.7 RANLIB = ranlib SBINDIR = /usr/sbin SET_MAKE = SHELL = /bin/sh STRIP = VERSION = 4.8 abs_builddir = /home/tgoff/work/core/repos/pf.itd.nrl.navy.mil/tmp/core/trunk/daemon/doc abs_srcdir = /home/tgoff/work/core/repos/pf.itd.nrl.navy.mil/tmp/core/trunk/daemon/doc abs_top_builddir = /home/tgoff/work/core/repos/pf.itd.nrl.navy.mil/tmp/core/trunk abs_top_srcdir = /home/tgoff/work/core/repos/pf.itd.nrl.navy.mil/tmp/core/trunk ac_ct_CC = gcc am__include = include am__leading_dot = . am__quote = am__tar = $${TAR-tar} chof - "$$tardir" am__untar = $${TAR-tar} xf - bindir = /usr/bin brctl_path = /usr/sbin build_alias = builddir = . convert = yes datadir = ${datarootdir} datarootdir = /usr/share docdir = ${datarootdir}/doc/${PACKAGE_TARNAME} dvidir = ${docdir} ebtables_path = /usr/sbin enable_daemon = yes enable_gui = yes exec_prefix = /usr gmake = help2man = no host_alias = htmldir = ${docdir} ifconfig_path = /usr/sbin includedir = ${prefix}/include infodir = ${datarootdir}/info install_sh = ${SHELL} /home/tgoff/work/core/repos/pf.itd.nrl.navy.mil/tmp/core/trunk/config/install-sh ip_path = /usr/sbin libdir = /usr/lib libev_CFLAGS = libev_LIBS = -lev libexecdir = ${exec_prefix}/libexec localedir = ${datarootdir}/locale localstatedir = ${prefix}/var mandir = ${datarootdir}/man mkdir_p = $(MKDIR_P) mount_path = /usr/bin ngctl_path = no oldincludedir = /usr/include pdfdir = ${docdir} pkgpyexecdir = ${pyexecdir}/core pkgpythondir = ${pythondir}/core prefix = /usr program_transform_name = s,x,x, psdir = ${docdir} pyexecdir = ${pyprefix}/lib64/python2.7/site-packages pyprefix = /usr pythondir = ${pyprefix}/lib/python2.7/site-packages sbindir = /usr/sbin sharedstatedir = ${prefix}/com srcdir = . sysconfdir = /etc sysctl_path = /usr/sbin target_alias = tc_path = /usr/sbin top_build_prefix = ../../ top_builddir = ../.. top_srcdir = ../.. umount_path = /usr/bin vimage_path = no with_startup = systemd # extra cruft to remove DISTCLEANFILES = conf.py Makefile.in stamp-vti *.rst ###### below this line was generated using sphinx-quickstart ###### # Makefile for Sphinx documentation # # You can set these variables from the command line. SPHINXOPTS = SPHINXBUILD = sphinx-build PAPER = BUILDDIR = _build # Internal variables. PAPEROPT_a4 = -D latex_paper_size=a4 PAPEROPT_letter = -D latex_paper_size=letter ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . all: all-am .SUFFIXES: $(srcdir)/Makefile.in: $(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 daemon/doc/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign daemon/doc/Makefile .PRECIOUS: 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: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): conf.py: $(top_builddir)/config.status $(srcdir)/conf.py.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ tags TAGS: ctags CTAGS: cscope cscopelist: 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 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) -test -z "$(DISTCLEANFILES)" || rm -f $(DISTCLEANFILES) 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-local mostlyclean-am distclean: distclean-am -rm -f Makefile distclean-am: clean-am distclean-generic dvi: dvi-am dvi-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 -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-generic pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: .MAKE: install-am install-strip .PHONY: all all-am check check-am clean clean-generic clean-local \ cscopelist-am ctags-am distclean distclean-generic 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-generic pdf \ pdf-am ps ps-am tags-am uninstall uninstall-am all: index.rst # auto-generated Python documentation using Sphinx index.rst: sphinx-apidoc -o . ../core mv modules.rst index.rst .PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest help: @echo "Please use \`make ' where is one of" @echo " html to make standalone HTML files" @echo " dirhtml to make HTML files named index.html in directories" @echo " singlehtml to make a single large HTML file" @echo " pickle to make pickle files" @echo " json to make JSON files" @echo " htmlhelp to make HTML files and a HTML help project" @echo " qthelp to make HTML files and a qthelp project" @echo " devhelp to make HTML files and a Devhelp project" @echo " epub to make an epub" @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" @echo " latexpdf to make LaTeX files and run them through pdflatex" @echo " text to make text files" @echo " man to make manual pages" @echo " changes to make an overview of all changed/added/deprecated items" @echo " linkcheck to check all external links for integrity" @echo " doctest to run all doctests embedded in the documentation (if enabled)" clean-local: -rm -rf $(BUILDDIR) html: index.rst $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." dirhtml: index.rst $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." singlehtml: index.rst $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml @echo @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." pickle: index.rst $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle @echo @echo "Build finished; now you can process the pickle files." json: index.rst $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json @echo @echo "Build finished; now you can process the JSON files." htmlhelp: index.rst $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp @echo @echo "Build finished; now you can run HTML Help Workshop with the" \ ".hhp project file in $(BUILDDIR)/htmlhelp." qthelp: index.rst $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp @echo @echo "Build finished; now you can run "qcollectiongenerator" with the" \ ".qhcp project file in $(BUILDDIR)/qthelp, like this:" @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/CORE.qhcp" @echo "To view the help file:" @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/CORE.qhc" devhelp: index.rst $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp @echo @echo "Build finished." @echo "To view the help file:" @echo "# mkdir -p $$HOME/.local/share/devhelp/CORE" @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/CORE" @echo "# devhelp" epub: index.rst $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub @echo @echo "Build finished. The epub file is in $(BUILDDIR)/epub." latex: index.rst $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." @echo "Run \`make' in that directory to run these through (pdf)latex" \ "(use \`make latexpdf' here to do that automatically)." latexpdf: index.rst $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo "Running LaTeX files through pdflatex..." make -C $(BUILDDIR)/latex all-pdf @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." text: index.rst $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text @echo @echo "Build finished. The text files are in $(BUILDDIR)/text." man: index.rst $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man @echo @echo "Build finished. The manual pages are in $(BUILDDIR)/man." changes: index.rst $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes @echo @echo "The overview file is in $(BUILDDIR)/changes." linkcheck: index.rst $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck @echo @echo "Link check complete; look for any errors in the above output " \ "or in $(BUILDDIR)/linkcheck/output.txt." doctest: index.rst $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest @echo "Testing of doctests in the sources finished, look at the " \ "results in $(BUILDDIR)/doctest/output.txt." # 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: core-4.8/daemon/doc/conf.py0000664000175000017500000002002412534330005012540 00000000000000# -*- coding: utf-8 -*- # # CORE Python documentation build configuration file, created by # sphinx-quickstart on Wed Jun 13 10:44:22 2012. # # This file is execfile()d with the current directory set to its containing dir. # # Note that not all possible configuration values are present in this # autogenerated file. # # All configuration values have a default; values that are commented out # serve to show the default. import sys, os # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. #sys.path.insert(0, os.path.abspath('.')) # -- General configuration ----------------------------------------------------- # If your documentation needs a minimal Sphinx version, state it here. #needs_sphinx = '1.0' # Add any Sphinx extension module names here, as strings. They can be extensions # coming with Sphinx (named 'sphinx.ext.*') or your custom ones. extensions = ['sphinx.ext.autodoc', 'sphinx.ext.todo', 'sphinx.ext.pngmath', 'sphinx.ext.ifconfig'] # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] # The suffix of source filenames. source_suffix = '.rst' # The encoding of source files. #source_encoding = 'utf-8-sig' # The master toctree document. master_doc = 'index' # General information about the project. project = u'CORE Python modules' copyright = u'2012, core-dev' # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the # built documents. # # The short X.Y version. version = '4.8' # The full version, including alpha/beta/rc tags. release = '4.8' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. #language = None # There are two options for replacing |today|: either, you set today to some # non-false value, then it is used: #today = '' # Else, today_fmt is used as the format for a strftime call. #today_fmt = '%B %d, %Y' # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. exclude_patterns = ['_build'] # The reST default role (used for this markup: `text`) to use for all documents. #default_role = None # If true, '()' will be appended to :func: etc. cross-reference text. #add_function_parentheses = True # If true, the current module name will be prepended to all description # unit titles (such as .. function::). #add_module_names = True # If true, sectionauthor and moduleauthor directives will be shown in the # output. They are ignored by default. #show_authors = False # The name of the Pygments (syntax highlighting) style to use. pygments_style = 'sphinx' # A list of ignored prefixes for module index sorting. #modindex_common_prefix = [] # -- Options for HTML output --------------------------------------------------- # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. html_theme = 'default' # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the # documentation. #html_theme_options = {} # Add any paths that contain custom themes here, relative to this directory. #html_theme_path = [] # The name for this set of Sphinx documents. If None, it defaults to # " v documentation". #html_title = None # A shorter title for the navigation bar. Default is the same as html_title. #html_short_title = None # The name of an image file (relative to this directory) to place at the top # of the sidebar. #html_logo = None # The name of an image file (within the static path) to use as favicon of the # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 # pixels large. #html_favicon = None # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". html_static_path = ['_static'] # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, # using the given strftime format. #html_last_updated_fmt = '%b %d, %Y' # If true, SmartyPants will be used to convert quotes and dashes to # typographically correct entities. #html_use_smartypants = True # Custom sidebar templates, maps document names to template names. #html_sidebars = {} # Additional templates that should be rendered to pages, maps page names to # template names. #html_additional_pages = {} # If false, no module index is generated. #html_domain_indices = True # If false, no index is generated. #html_use_index = True # If true, the index is split into individual pages for each letter. #html_split_index = False # If true, links to the reST sources are added to the pages. #html_show_sourcelink = True # If true, "Created using Sphinx" is shown in the HTML footer. Default is True. #html_show_sphinx = True # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. #html_show_copyright = True # If true, an OpenSearch description file will be output, and all pages will # contain a tag referring to it. The value of this option must be the # base URL from which the finished HTML is served. #html_use_opensearch = '' # This is the file name suffix for HTML files (e.g. ".xhtml"). #html_file_suffix = None # Output file base name for HTML help builder. htmlhelp_basename = 'COREpythondoc' # -- Options for LaTeX output -------------------------------------------------- # The paper size ('letter' or 'a4'). #latex_paper_size = 'letter' # The font size ('10pt', '11pt' or '12pt'). #latex_font_size = '10pt' # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, author, documentclass [howto/manual]). latex_documents = [ ('index', 'index.tex', u'CORE Python Documentation', u'core-dev', 'manual'), ] # The name of an image file (relative to this directory) to place at the top of # the title page. #latex_logo = None # For "manual" documents, if this is true, then toplevel headings are parts, # not chapters. #latex_use_parts = False # If true, show page references after internal links. #latex_show_pagerefs = False # If true, show URL addresses after external links. #latex_show_urls = False # Additional stuff for the LaTeX preamble. #latex_preamble = '' # Documents to append as an appendix to all manuals. #latex_appendices = [] # If false, no module index is generated. #latex_domain_indices = True # -- Options for manual page output -------------------------------------------- # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). man_pages = [ ('index', 'core-python', u'CORE Python Documentation', [u'core-dev'], 1) ] # -- Options for Epub output --------------------------------------------------- # Bibliographic Dublin Core info. epub_title = u'CORE Python' epub_author = u'core-dev' epub_publisher = u'core-dev' epub_copyright = u'2012, core-dev' # The language of the text. It defaults to the language option # or en if the language is not set. #epub_language = '' # The scheme of the identifier. Typical schemes are ISBN or URL. #epub_scheme = '' # The unique identifier of the text. This can be a ISBN number # or the project homepage. #epub_identifier = '' # A unique identification for the text. #epub_uid = '' # HTML files that should be inserted before the pages created by sphinx. # The format is a list of tuples containing the path and title. #epub_pre_files = [] # HTML files shat should be inserted after the pages created by sphinx. # The format is a list of tuples containing the path and title. #epub_post_files = [] # A list of files that should not be packed into the epub file. #epub_exclude_files = [] # The depth of the table of contents in toc.ncx. #epub_tocdepth = 3 # Allow duplicate toc entries. #epub_tocdup = True core-4.8/daemon/src/0000775000175000017500000000000012534330007011347 500000000000000core-4.8/daemon/src/Makefile.in0000664000175000017500000005472412534330000013341 00000000000000# Makefile.in generated by automake 1.13.4 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 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@ # CORE # (c)2010-2013 the Boeing Company. # See the LICENSE file included in this distribution. # # author: Jeff Ahrenholz # # Makefile for building netns. # VPATH = @srcdir@ am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' 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 = : sbin_PROGRAMS = vnoded$(EXEEXT) vcmd$(EXEEXT) netns$(EXEEXT) subdir = daemon/src DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ $(srcdir)/version.h.in $(top_srcdir)/config/depcomp ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = version.h CONFIG_CLEAN_VPATH_FILES = LIBRARIES = $(noinst_LIBRARIES) AR = ar ARFLAGS = cru AM_V_AR = $(am__v_AR_@AM_V@) am__v_AR_ = $(am__v_AR_@AM_DEFAULT_V@) am__v_AR_0 = @echo " AR " $@; am__v_AR_1 = libnetns_a_AR = $(AR) $(ARFLAGS) libnetns_a_LIBADD = am_libnetns_a_OBJECTS = netnsmodule.$(OBJEXT) vcmdmodule.$(OBJEXT) libnetns_a_OBJECTS = $(am_libnetns_a_OBJECTS) am__installdirs = "$(DESTDIR)$(sbindir)" PROGRAMS = $(sbin_PROGRAMS) am__objects_1 = netns_main.$(OBJEXT) netns.$(OBJEXT) am_netns_OBJECTS = $(am__objects_1) netns_OBJECTS = $(am_netns_OBJECTS) netns_LDADD = $(LDADD) am__objects_2 = vnode_msg.$(OBJEXT) vnode_cmd.$(OBJEXT) \ vnode_chnl.$(OBJEXT) vnode_io.$(OBJEXT) am__objects_3 = vcmd_main.$(OBJEXT) vnode_client.$(OBJEXT) am_vcmd_OBJECTS = $(am__objects_2) $(am__objects_3) vcmd_OBJECTS = $(am_vcmd_OBJECTS) vcmd_DEPENDENCIES = am__objects_4 = vnoded_main.$(OBJEXT) vnode_server.$(OBJEXT) \ netns.$(OBJEXT) am_vnoded_OBJECTS = $(am__objects_2) $(am__objects_4) vnoded_OBJECTS = $(am_vnoded_OBJECTS) vnoded_DEPENDENCIES = 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)/config/depcomp am__depfiles_maybe = depfiles am__mv = mv -f 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 = $(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 = $(libnetns_a_SOURCES) $(netns_SOURCES) $(vcmd_SOURCES) \ $(vnoded_SOURCES) DIST_SOURCES = $(libnetns_a_SOURCES) $(netns_SOURCES) $(vcmd_SOURCES) \ $(vnoded_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 DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ ARCH = @ARCH@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ BINDIR = @BINDIR@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ COREDPY_VERSION = @COREDPY_VERSION@ CORE_CONF_DIR = @CORE_CONF_DIR@ CORE_DATA_DIR = @CORE_DATA_DIR@ CORE_GUI_CONF_DIR = @CORE_GUI_CONF_DIR@ CORE_LIB_DIR = @CORE_LIB_DIR@ CORE_STATE_DIR = @CORE_STATE_DIR@ CORE_VERSION = @CORE_VERSION@ CORE_VERSION_DATE = @CORE_VERSION_DATE@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ GREP = @GREP@ HELP2MAN = @HELP2MAN@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LDFLAGS = @LDFLAGS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIB_DIR = @LIB_DIR@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ OBJEXT = @OBJEXT@ 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@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PYTHON = @PYTHON@ PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ PYTHON_PLATFORM = @PYTHON_PLATFORM@ PYTHON_PREFIX = @PYTHON_PREFIX@ PYTHON_VERSION = @PYTHON_VERSION@ RANLIB = @RANLIB@ SBINDIR = @SBINDIR@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_CC = @ac_ct_CC@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ brctl_path = @brctl_path@ build_alias = @build_alias@ builddir = @builddir@ convert = @convert@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ ebtables_path = @ebtables_path@ enable_daemon = @enable_daemon@ enable_gui = @enable_gui@ exec_prefix = @exec_prefix@ gmake = @gmake@ help2man = @help2man@ host_alias = @host_alias@ htmldir = @htmldir@ ifconfig_path = @ifconfig_path@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ ip_path = @ip_path@ libdir = @libdir@ libev_CFLAGS = @libev_CFLAGS@ libev_LIBS = @libev_LIBS@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ mount_path = @mount_path@ ngctl_path = @ngctl_path@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgpyexecdir = @pkgpyexecdir@ pkgpythondir = @pkgpythondir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ pyexecdir = @pyexecdir@ pyprefix = @pyprefix@ pythondir = @pythondir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ sysctl_path = @sysctl_path@ target_alias = @target_alias@ tc_path = @tc_path@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ umount_path = @umount_path@ vimage_path = @vimage_path@ with_startup = @with_startup@ AM_CFLAGS = -Wall -fno-strict-aliasing -O3 -g @libev_CFLAGS@ # -DDEBUG SRC_COMMON = vnode_msg.c vnode_cmd.c vnode_chnl.c vnode_io.c \ vnode_msg.h vnode_cmd.h vnode_chnl.h vnode_io.h \ vnode_tlv.h myerr.h netns.h SRC_VNODED = vnoded_main.c vnode_server.c netns.c \ vnode_server.h SRC_VCMD = vcmd_main.c vnode_client.c \ vnode_client.h SRC_NETNS = netns_main.c netns.c netns.h vnoded_LDADD = @libev_LIBS@ vnoded_SOURCES = ${SRC_COMMON} ${SRC_VNODED} vcmd_LDADD = @libev_LIBS@ vcmd_SOURCES = ${SRC_COMMON} ${SRC_VCMD} netns_SOURCES = ${SRC_NETNS} # this triggers automake to run setup.py for building the Python libraries # actual library names are netns.so and vcmd.so # SOURCES line prevents 'make dist' from looking for a 'libnetns.c' file noinst_LIBRARIES = libnetns.a libnetns_a_SOURCES = netnsmodule.c vcmdmodule.c # extra cruft to remove DISTCLEANFILES = Makefile.in rpmbuild.sh MANIFEST # include source files for Python libraries with distribution tarball EXTRA_DIST = setup.py MANIFEST.in all: all-am .SUFFIXES: .SUFFIXES: .c .o .obj $(srcdir)/Makefile.in: $(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 daemon/src/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign daemon/src/Makefile .PRECIOUS: 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: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): version.h: $(top_builddir)/config.status $(srcdir)/version.h.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ clean-noinstLIBRARIES: -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) install-sbinPROGRAMS: $(sbin_PROGRAMS) @$(NORMAL_INSTALL) @list='$(sbin_PROGRAMS)'; test -n "$(sbindir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(sbindir)'"; \ $(MKDIR_P) "$(DESTDIR)$(sbindir)" || exit 1; \ fi; \ for p in $$list; do echo "$$p $$p"; done | \ sed 's/$(EXEEXT)$$//' | \ while read p p1; do if test -f $$p \ ; then echo "$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n;h' \ -e 's|.*|.|' \ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) files[d] = files[d] " " $$1; \ else { print "f", $$3 "/" $$4, $$1; } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(sbindir)$$dir'"; \ $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(sbindir)$$dir" || exit $$?; \ } \ ; done uninstall-sbinPROGRAMS: @$(NORMAL_UNINSTALL) @list='$(sbin_PROGRAMS)'; test -n "$(sbindir)" || list=; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ -e 's/$$/$(EXEEXT)/' \ `; \ test -n "$$list" || exit 0; \ echo " ( cd '$(DESTDIR)$(sbindir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(sbindir)" && rm -f $$files clean-sbinPROGRAMS: -test -z "$(sbin_PROGRAMS)" || rm -f $(sbin_PROGRAMS) netns$(EXEEXT): $(netns_OBJECTS) $(netns_DEPENDENCIES) $(EXTRA_netns_DEPENDENCIES) @rm -f netns$(EXEEXT) $(AM_V_CCLD)$(LINK) $(netns_OBJECTS) $(netns_LDADD) $(LIBS) vcmd$(EXEEXT): $(vcmd_OBJECTS) $(vcmd_DEPENDENCIES) $(EXTRA_vcmd_DEPENDENCIES) @rm -f vcmd$(EXEEXT) $(AM_V_CCLD)$(LINK) $(vcmd_OBJECTS) $(vcmd_LDADD) $(LIBS) vnoded$(EXEEXT): $(vnoded_OBJECTS) $(vnoded_DEPENDENCIES) $(EXTRA_vnoded_DEPENDENCIES) @rm -f vnoded$(EXEEXT) $(AM_V_CCLD)$(LINK) $(vnoded_OBJECTS) $(vnoded_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/netns.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/netns_main.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/netnsmodule.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/vcmd_main.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/vcmdmodule.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/vnode_chnl.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/vnode_client.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/vnode_cmd.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/vnode_io.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/vnode_msg.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/vnode_server.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/vnoded_main.Po@am__quote@ .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.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 $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.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 `$(CYGPATH_W) '$<'` 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 $(LIBRARIES) $(PROGRAMS) installdirs: for dir in "$(DESTDIR)$(sbindir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done 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) -test -z "$(DISTCLEANFILES)" || rm -f $(DISTCLEANFILES) 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-local clean-noinstLIBRARIES \ clean-sbinPROGRAMS mostlyclean-am distclean: distclean-am -rm -rf ./$(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-exec-local install-sbinPROGRAMS 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) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-sbinPROGRAMS @$(NORMAL_INSTALL) $(MAKE) $(AM_MAKEFLAGS) uninstall-hook .MAKE: install-am install-strip uninstall-am .PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \ clean-local clean-noinstLIBRARIES clean-sbinPROGRAMS \ cscopelist-am ctags ctags-am distclean distclean-compile \ distclean-generic 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-exec-local install-html \ install-html-am install-info install-info-am install-man \ install-pdf install-pdf-am install-ps install-ps-am \ install-sbinPROGRAMS install-strip installcheck \ installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic pdf pdf-am ps ps-am tags tags-am uninstall \ uninstall-am uninstall-hook uninstall-sbinPROGRAMS libnetns.a: SBINDIR=@SBINDIR@ LDFLAGS="$(LDFLAGS) @libev_LIBS@" CFLAGS="$(CFLAGS) @libev_CFLAGS@" $(PYTHON) setup.py build # Python libraries install install-exec-local: SBINDIR=${DESTDIR}/@SBINDIR@ $(PYTHON) setup.py install --prefix=${DESTDIR}/${pyprefix} --install-purelib=${DESTDIR}/${pythondir} --install-platlib=${DESTDIR}/${pyexecdir} --no-compile #python setup.py install --prefix=${DESTDIR}${PYTHON_PREFIX} # Python libraries uninstall uninstall-hook: rm -f ${pyexecdir}/core_python_netns-1.0-py${PYTHON_VERSION}.egg-info rm -f ${pyexecdir}/netns.so rm -f ${pyexecdir}/vcmd.so # Python libraries cleanup clean-local: clean-local-check .PHONY: clean-local-check clean-local-check: -rm -rf build rpmbuild.sh: echo SBINDIR=@SBINDIR@ LDFLAGS="$(LDFLAGS)" CFLAGS="$(CFLAGS) @libev_CFLAGS@" $(PYTHON) setup.py build > rpmbuild.sh chmod a+x rpmbuild.sh rpm: rpmbuild.sh $(PYTHON) setup.py bdist_rpm --build-script=rpmbuild.sh --requires="libev" --build-requires="libev-devel" # 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: core-4.8/daemon/src/Makefile.am0000664000175000017500000000430612534327775013350 00000000000000# CORE # (c)2010-2013 the Boeing Company. # See the LICENSE file included in this distribution. # # author: Jeff Ahrenholz # # Makefile for building netns. # AM_CFLAGS = -Wall -fno-strict-aliasing -O3 -g @libev_CFLAGS@ # -DDEBUG SRC_COMMON = vnode_msg.c vnode_cmd.c vnode_chnl.c vnode_io.c \ vnode_msg.h vnode_cmd.h vnode_chnl.h vnode_io.h \ vnode_tlv.h myerr.h netns.h SRC_VNODED = vnoded_main.c vnode_server.c netns.c \ vnode_server.h SRC_VCMD = vcmd_main.c vnode_client.c \ vnode_client.h SRC_NETNS = netns_main.c netns.c netns.h sbin_PROGRAMS = vnoded vcmd netns vnoded_LDADD = @libev_LIBS@ vnoded_SOURCES = ${SRC_COMMON} ${SRC_VNODED} vcmd_LDADD = @libev_LIBS@ vcmd_SOURCES = ${SRC_COMMON} ${SRC_VCMD} netns_SOURCES = ${SRC_NETNS} # this triggers automake to run setup.py for building the Python libraries # actual library names are netns.so and vcmd.so # SOURCES line prevents 'make dist' from looking for a 'libnetns.c' file noinst_LIBRARIES = libnetns.a libnetns_a_SOURCES = netnsmodule.c vcmdmodule.c libnetns.a: SBINDIR=@SBINDIR@ LDFLAGS="$(LDFLAGS) @libev_LIBS@" CFLAGS="$(CFLAGS) @libev_CFLAGS@" $(PYTHON) setup.py build # Python libraries install install-exec-local: SBINDIR=${DESTDIR}/@SBINDIR@ $(PYTHON) setup.py install --prefix=${DESTDIR}/${pyprefix} --install-purelib=${DESTDIR}/${pythondir} --install-platlib=${DESTDIR}/${pyexecdir} --no-compile #python setup.py install --prefix=${DESTDIR}${PYTHON_PREFIX} # Python libraries uninstall uninstall-hook: rm -f ${pyexecdir}/core_python_netns-1.0-py${PYTHON_VERSION}.egg-info rm -f ${pyexecdir}/netns.so rm -f ${pyexecdir}/vcmd.so # Python libraries cleanup clean-local: clean-local-check .PHONY: clean-local-check clean-local-check: -rm -rf build rpmbuild.sh: echo SBINDIR=@SBINDIR@ LDFLAGS="$(LDFLAGS)" CFLAGS="$(CFLAGS) @libev_CFLAGS@" $(PYTHON) setup.py build > rpmbuild.sh chmod a+x rpmbuild.sh rpm: rpmbuild.sh $(PYTHON) setup.py bdist_rpm --build-script=rpmbuild.sh --requires="libev" --build-requires="libev-devel" # extra cruft to remove DISTCLEANFILES = Makefile.in rpmbuild.sh MANIFEST # include source files for Python libraries with distribution tarball EXTRA_DIST = setup.py MANIFEST.in core-4.8/daemon/src/version.h.in0000664000175000017500000000045112534327775013554 00000000000000/* * CORE * Copyright (c)2012 the Boeing Company. * See the LICENSE file included in this distribution. * * author: Jeff Ahrenholz * * version.h * */ #ifndef _VERSION_H_ #define _VERSION_H_ #define CORE_VERSION "@CORE_VERSION@" #endif /* _VERSION_H_ */ core-4.8/daemon/src/netnsmodule.c0000664000175000017500000000606112534327775014015 00000000000000/* * CORE * Copyright (c)2010-2012 the Boeing Company. * See the LICENSE file included in this distribution. * * author: Tom Goff * * netnsmodule.c * * Python module C bindings providing nsfork and nsexecvp methods for * forking a child process into a new namespace, with nsexecvp executing a * new program using the default search path. * */ #include #include #include #include "netns.h" /* parts taken from python/trunk/Modules/posixmodule.c */ static void free_string_array(char **array, Py_ssize_t count) { Py_ssize_t i; for (i = 0; i < count; i++) PyMem_Free(array[i]); PyMem_DEL(array); } static PyObject *netns_nsexecvp(PyObject *self, PyObject *args) { pid_t pid; char **argv; Py_ssize_t i, argc; PyObject *(*getitem)(PyObject *, Py_ssize_t); /* args should be a list or tuple of strings */ if (PyList_Check(args)) { argc = PyList_Size(args); getitem = PyList_GetItem; } else if (PyTuple_Check(args)) { argc = PyTuple_Size(args); getitem = PyTuple_GetItem; } else { PyErr_SetString(PyExc_TypeError, "netns_nsexecvp() args must be a tuple or list"); return NULL; } argv = PyMem_NEW(char *, argc + 1); if (argv == NULL) return PyErr_NoMemory(); for (i = 0; i < argc; i++) { if (!PyArg_Parse((*getitem)(args, i), "et", Py_FileSystemDefaultEncoding, &argv[i])) { free_string_array(argv, i); PyErr_SetString(PyExc_TypeError, "netns_nsexecvp() args must contain only strings"); return NULL; } } argv[argc] = NULL; pid = nsexecvp(argv); free_string_array(argv, argc); if (pid < 0) return PyErr_SetFromErrno(PyExc_OSError); else return PyInt_FromLong(pid); } static PyObject *netns_nsfork(PyObject *self, PyObject *args) { int flags; pid_t pid; if (!PyArg_ParseTuple(args, "i", &flags)) return NULL; pid = nsfork(flags); if (pid < 0) return PyErr_SetFromErrno(PyExc_OSError); if (pid == 0) /* child */ PyOS_AfterFork(); return PyInt_FromLong(pid); } static PyMethodDef netns_methods[] = { {"nsfork", netns_nsfork, METH_VARARGS, "nsfork(cloneflags) -> int\n\n" "Fork a child process into a new namespace using the Linux clone()\n" "system call.\n\n" "cloneflags: additional flags passed to clone()"}, {"nsexecvp", netns_nsexecvp, METH_VARARGS, "nsexecvp(args...) -> int\n\n" "Fork a child process into a new namespace using the Linux clone()\n" "system call and have the child execute a new program using the\n" "default search path.\n\n" "args: the executable file name followed by command arguments"}, {NULL, NULL, 0, NULL}, }; PyMODINIT_FUNC initnetns(void) { PyObject *m; m = Py_InitModule("netns", netns_methods); if (m == NULL) return; #define MODADDINT(x) \ do { \ PyObject *tmp = Py_BuildValue("i", x); \ if (tmp) \ { \ Py_INCREF(tmp); \ PyModule_AddObject(m, #x, tmp); \ } \ } while (0) MODADDINT(CLONE_VFORK); #undef MODADDINT return; } core-4.8/daemon/src/vcmdmodule.c0000664000175000017500000004520212534327775013617 00000000000000/* * CORE * Copyright (c)2010-2012 the Boeing Company. * See the LICENSE file included in this distribution. * * author: Tom Goff * * vcmdmodule.c * * C bindings for the vcmd Python module that allows a Python script to * execute a program within a running namespace given by the specified channel. * */ #include #include #include #include #undef NDEBUG /* XXX force enabling asserts for now */ #include #include "vnode_client.h" /* #define DEBUG */ int verbose; /* ev_default_loop(0) is not used because it interferes with SIGCHLD */ static struct ev_loop *loop; static pthread_t evloopthread; static TAILQ_HEAD(asyncreqhead, asyncreq) asyncreqlisthead; static pthread_mutex_t asyncreqlist_mutex = PTHREAD_MUTEX_INITIALIZER; static int asyncpipe[2]; static pthread_mutex_t asyncpipe_writemutex = PTHREAD_MUTEX_INITIALIZER; static ev_io asyncwatcher; typedef void (*asyncfunc_t)(struct ev_loop *loop, void *data); typedef struct asyncreq { TAILQ_ENTRY(asyncreq) entries; pthread_mutex_t mutex; pthread_cond_t cv; int done; asyncfunc_t asyncfunc; void *data; } vcmd_asyncreq_t; static void vcmd_asyncreq_cb(struct ev_loop *loop, ev_io *w, int revents) { vcmd_asyncreq_t *asyncreq; /* drain the event pipe */ for (;;) { ssize_t len; char buf[BUFSIZ]; len = read(asyncpipe[0], buf, sizeof(buf)); if (len <= 0) { if (len == 0) ERR(1, "asynchronous event pipe closed"); break; } } for (;;) { pthread_mutex_lock(&asyncreqlist_mutex); asyncreq = TAILQ_FIRST(&asyncreqlisthead); if (asyncreq) TAILQ_REMOVE(&asyncreqlisthead, asyncreq, entries); pthread_mutex_unlock(&asyncreqlist_mutex); if (!asyncreq) break; assert(asyncreq->asyncfunc); asyncreq->asyncfunc(loop, asyncreq->data); pthread_mutex_lock(&asyncreq->mutex); asyncreq->done = 1; pthread_cond_broadcast(&asyncreq->cv); pthread_mutex_unlock(&asyncreq->mutex); } return; } static void call_asyncfunc(asyncfunc_t asyncfunc, void *data) { vcmd_asyncreq_t asyncreq = { .asyncfunc = asyncfunc, .data = data, }; char zero = 0; ssize_t len; pthread_mutex_init(&asyncreq.mutex, NULL); pthread_cond_init(&asyncreq.cv, NULL); pthread_mutex_lock(&asyncreqlist_mutex); TAILQ_INSERT_TAIL(&asyncreqlisthead, &asyncreq, entries); pthread_mutex_unlock(&asyncreqlist_mutex); pthread_mutex_lock(&asyncpipe_writemutex); len = write(asyncpipe[1], &zero, sizeof(zero)); pthread_mutex_unlock(&asyncpipe_writemutex); if (len == -1) ERR(1, "write() failed"); if (len != sizeof(zero)) WARN("incomplete write: %d of %d", len, sizeof(zero)); pthread_mutex_lock(&asyncreq.mutex); Py_BEGIN_ALLOW_THREADS while (!asyncreq.done) pthread_cond_wait(&asyncreq.cv, &asyncreq.mutex); Py_END_ALLOW_THREADS pthread_mutex_unlock(&asyncreq.mutex); pthread_mutex_destroy(&asyncreq.mutex); pthread_cond_destroy(&asyncreq.cv); return; } static void *start_evloop(void *data) { struct ev_loop *loop = data; #ifdef DEBUG WARNX("starting event loop: %p", loop); #endif ev_loop(loop, 0); #ifdef DEBUG WARNX("event loop done: %p", loop); #endif return NULL; } static int init_evloop(void) { int err; loop = ev_loop_new(0); if (!loop) { WARN("ev_loop_new() failed"); return -1; } TAILQ_INIT(&asyncreqlisthead); err = pipe(asyncpipe); if (err) { WARN("pipe() failed"); return -1; } set_nonblock(asyncpipe[0]); ev_io_init(&asyncwatcher, vcmd_asyncreq_cb, asyncpipe[0], EV_READ); ev_io_start(loop, &asyncwatcher); err = pthread_create(&evloopthread, NULL, start_evloop, loop); if (err) { errno = err; WARN("pthread_create() failed"); return -1; } return 0; } typedef struct { PyObject_HEAD int32_t _cmdid; int _complete; int _status; pthread_mutex_t _mutex; pthread_cond_t _cv; } VCmdWait; static PyObject *VCmdWait_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { VCmdWait *self; #ifdef DEBUG WARNX("enter"); #endif self = (VCmdWait *)type->tp_alloc(type, 0); if (!self) return NULL; self->_cmdid = -1; self->_complete = 0; self->_status = -1; pthread_mutex_init(&self->_mutex, NULL); pthread_cond_init(&self->_cv, NULL); #ifdef DEBUG WARNX("%p: exit", self); #endif return (PyObject *)self; } static void VCmdWait_dealloc(VCmdWait *self) { #ifdef DEBUG WARNX("%p: enter", self); #endif pthread_mutex_destroy(&self->_mutex); pthread_cond_destroy(&self->_cv); self->ob_type->tp_free((PyObject *)self); return; } static PyObject *VCmdWait_wait(VCmdWait *self) { int status; pthread_mutex_lock(&self->_mutex); #ifdef DEBUG WARNX("%p: waiting for cmd %d: complete: %d; status: %d", self, self->_cmdid, self->_complete, self->_status); #endif Py_BEGIN_ALLOW_THREADS while (!self->_complete) pthread_cond_wait(&self->_cv, &self->_mutex); Py_END_ALLOW_THREADS status = self->_status; pthread_mutex_unlock(&self->_mutex); #ifdef DEBUG WARNX("%p: done waiting for cmd %d: status: %d", self, self->_cmdid, self->_status); #endif return Py_BuildValue("i", status); } static PyObject *VCmdWait_complete(VCmdWait *self, PyObject *args, PyObject *kwds) { if (self->_complete) Py_RETURN_TRUE; else Py_RETURN_FALSE; } static PyObject *VCmdWait_status(VCmdWait *self, PyObject *args, PyObject *kwds) { if (self->_complete) return Py_BuildValue("i", self->_status); else Py_RETURN_NONE; } static PyMemberDef VCmdWait_members[] = { {NULL, 0, 0, 0, NULL}, }; static PyMethodDef VCmdWait_methods[] = { {"wait", (PyCFunction)VCmdWait_wait, METH_NOARGS, "wait() -> int\n\n" "Wait for command to complete and return exit status"}, {"complete", (PyCFunction)VCmdWait_complete, METH_NOARGS, "complete() -> boolean\n\n" "Return True if command has completed; return False otherwise."}, {"status", (PyCFunction)VCmdWait_status, METH_NOARGS, "status() -> int\n\n" "Return exit status if command has completed; return None otherwise."}, {NULL, NULL, 0, NULL}, }; static PyTypeObject vcmd_VCmdWaitType = { PyObject_HEAD_INIT(NULL) .tp_name = "vcmd.VCmdWait", .tp_basicsize = sizeof(VCmdWait), .tp_dealloc = (destructor)VCmdWait_dealloc, .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, .tp_doc = "VCmdWait objects", .tp_methods = VCmdWait_methods, .tp_members = VCmdWait_members, .tp_new = VCmdWait_new, }; typedef struct vcmdentry { PyObject_HEAD vnode_client_t *_client; int _client_connected; } VCmd; static PyObject *VCmd_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { VCmd *self; self = (VCmd *)type->tp_alloc(type, 0); if (!self) return NULL; self->_client = NULL; self->_client_connected = 0; return (PyObject *)self; } static void vcmd_ioerrorcb(vnode_client_t *client) { VCmd *self; PyGILState_STATE gstate = 0; int pythreads; pythreads = PyEval_ThreadsInitialized(); if (pythreads) gstate = PyGILState_Ensure(); if (verbose) WARNX("i/o error for client %p", client); self = client->data; assert(self); assert(self->_client == client); self->_client_connected = 0; if (pythreads) PyGILState_Release(gstate); return; } typedef struct { vnode_client_t *client; const char *ctrlchnlname; void *data; } vcmd_newclientreq_t; static void async_newclientreq(struct ev_loop *loop, void *data) { vcmd_newclientreq_t *newclreq = data; newclreq->client = vnode_client(loop, newclreq->ctrlchnlname, vcmd_ioerrorcb, newclreq->data); return; } typedef struct { vnode_client_t *client; } vcmd_delclientreq_t; static void async_delclientreq(struct ev_loop *loop, void *data) { vcmd_delclientreq_t *delclreq = data; vnode_delclient(delclreq->client); return; } static int VCmd_init(VCmd *self, PyObject *args, PyObject *kwds) { vcmd_newclientreq_t newclreq = {.data = self}; #ifdef DEBUG WARNX("%p: enter", self); #endif if (!loop) if (init_evloop()) return -1; if (!PyArg_ParseTuple(args, "s", &newclreq.ctrlchnlname)) return -1; call_asyncfunc(async_newclientreq, &newclreq); self->_client = newclreq.client; if (!self->_client) { WARN("vnode_client() failed"); PyErr_SetFromErrno(PyExc_OSError); return -1; } self->_client_connected = 1; return 0; } static void VCmd_dealloc(VCmd *self) { #ifdef DEBUG WARNX("%p: enter", self); #endif self->_client_connected = 0; if (self->_client) { vcmd_delclientreq_t delclreq = {.client = self->_client}; call_asyncfunc(async_delclientreq, &delclreq); self->_client = NULL; } self->ob_type->tp_free((PyObject *)self); return; } static PyObject *VCmd_connected(VCmd *self, PyObject *args, PyObject *kwds) { if (self->_client_connected) Py_RETURN_TRUE; else Py_RETURN_FALSE; } static void vcmd_cmddonecb(int32_t cmdid, pid_t pid, int status, void *data) { VCmdWait *cmdwait = data; PyGILState_STATE gstate = 0; int pythreads; #ifdef DEBUG WARNX("cmdid %d; pid %d; status: 0x%x", cmdid, pid, status); if (WIFEXITED(status)) WARNX("command %d terminated normally with status: %d", cmdid, WEXITSTATUS(status)); else if (WIFSIGNALED(status)) WARNX("command %d terminated by signal: %d", cmdid, WTERMSIG(status)); else WARNX("unexpected termination status for command %d: 0x%x", cmdid, status); #endif #ifdef DEBUG WARNX("%p: waiting for lock", cmdwait); #endif pthread_mutex_lock(&cmdwait->_mutex); cmdwait->_status = status; cmdwait->_complete = 1; #ifdef DEBUG WARNX("%p: command callback done", cmdwait); #endif pthread_cond_broadcast(&cmdwait->_cv); pthread_mutex_unlock(&cmdwait->_mutex); pythreads = PyEval_ThreadsInitialized(); if (pythreads) gstate = PyGILState_Ensure(); Py_DECREF(cmdwait); if (pythreads) PyGILState_Release(gstate); return; } typedef struct { int cmdid; vnode_client_t *client; vnode_client_cmdio_t *clientcmdio; void *data; int argc; char **argv; } vcmd_cmdreq_t; static void async_cmdreq(struct ev_loop *loop, void *data) { vcmd_cmdreq_t *cmdreq = data; cmdreq->cmdid = vnode_client_cmdreq(cmdreq->client, cmdreq->clientcmdio, vcmd_cmddonecb, cmdreq->data, cmdreq->argc, cmdreq->argv); return; } static void free_string_array(char **array, Py_ssize_t count) { Py_ssize_t i; for (i = 0; i < count; i++) PyMem_Free(array[i]); PyMem_Del(array); } static PyObject *_VCmd_cmd(VCmd *self, PyObject *args, PyObject *kwds, vnode_client_cmdiotype_t iotype) { int status, infd, outfd, errfd; PyObject *cmdargs; char **argv = NULL; Py_ssize_t i, argc; PyObject *(*getitem)(PyObject *, Py_ssize_t); VCmdWait *cmdwait; vnode_client_cmdio_t *cmdio; PyObject *pyinfile = NULL, *pyoutfile = NULL, *pyerrfile = NULL; PyObject *pyptyfile = NULL; PyObject *ret; if (!self->_client_connected) { PyErr_SetString(PyExc_ValueError, "not connected"); return NULL; } if (iotype == VCMD_IO_FD) { char *kwlist[] = {"infd", "outfd", "errfd", "args", NULL}; status = PyArg_ParseTupleAndKeywords(args, kwds, "iiiO", kwlist, &infd, &outfd, &errfd, &cmdargs); } else { char *kwlist[] = {"args", NULL}; status = PyArg_ParseTupleAndKeywords(args, kwds, "O", kwlist, &cmdargs); } if (!status) return NULL; /* cmdargs must be a list or tuple of strings */ if (PyList_Check(cmdargs)) { argc = PyList_Size(cmdargs); getitem = PyList_GetItem; } else if (PyTuple_Check(cmdargs)) { argc = PyTuple_Size(cmdargs); getitem = PyTuple_GetItem; } else { argc = -1; } if (argc <= 0) { PyErr_SetString(PyExc_TypeError, "cmd arg must be a nonempty tuple or list"); return NULL; } argv = PyMem_New(char *, argc + 1); if (argv == NULL) return PyErr_NoMemory(); for (i = 0; i < argc; i++) { if (!PyArg_Parse((*getitem)(cmdargs, i), "et", Py_FileSystemDefaultEncoding, &argv[i])) { free_string_array(argv, i); PyErr_SetString(PyExc_TypeError, "cmd arg must contain only strings"); return NULL; } } argv[argc] = NULL; cmdwait = (VCmdWait *)VCmdWait_new(&vcmd_VCmdWaitType, NULL, NULL); if (cmdwait == NULL) { free_string_array(argv, i); return PyErr_NoMemory(); } pthread_mutex_lock(&cmdwait->_mutex); cmdwait->_cmdid = -1; cmdio = vnode_open_clientcmdio(iotype); if (cmdio) { int err = 0; vcmd_cmdreq_t cmdreq = { .client = self->_client, .clientcmdio = cmdio, .data = cmdwait, .argc = argc, .argv = argv, }; #define PYFILE(obj, fd, name, mode) \ do { \ FILE *tmp; \ obj = NULL; \ tmp = fdopen(fd, mode); \ if (!tmp) \ { \ WARN("fdopen() failed for fd %d", fd); \ break; \ } \ obj = PyFile_FromFile(tmp, name, mode, fclose); \ if (!obj) \ fclose(tmp); \ } while(0) switch (iotype) { case VCMD_IO_NONE: break; case VCMD_IO_FD: SET_STDIOFD(cmdio, infd, outfd, errfd); break; case VCMD_IO_PIPE: PYFILE(pyinfile, cmdio->stdiopipe.infd[1], "", "wb"); if (!pyinfile) { err = 1; break; } PYFILE(pyoutfile, cmdio->stdiopipe.outfd[0], "", "rb"); if (!pyoutfile) { PyObject_Del(pyinfile); err = 1; break; } PYFILE(pyerrfile, cmdio->stdiopipe.errfd[0], "", "rb"); if (!pyerrfile) { PyObject_Del(pyoutfile); PyObject_Del(pyinfile); err = 1; break; } break; case VCMD_IO_PTY: PYFILE(pyptyfile, cmdio->stdiopty.masterfd, "/dev/ptmx", "r+b"); if (!pyptyfile) err = 1; break; default: if (verbose) WARNX("invalid iotype: 0x%x", iotype); errno = EINVAL; err = 1; break; } #undef PYFILE if (!err) { call_asyncfunc(async_cmdreq, &cmdreq); cmdwait->_cmdid = cmdreq.cmdid; } } free_string_array(argv, argc); free(cmdio); if (cmdwait->_cmdid < 0) { if (pyinfile) PyObject_Del(pyinfile); if (pyoutfile) PyObject_Del(pyoutfile); if (pyerrfile) PyObject_Del(pyerrfile); if (pyptyfile) PyObject_Del(pyptyfile); PyErr_SetFromErrno(PyExc_OSError); pthread_mutex_unlock(&cmdwait->_mutex); Py_DECREF(cmdwait); return NULL; } /* don't do Py_DECREF(cmdwait) or VCmdWait_dealloc(cmdwait) if * there's an error below since cmddonecb should still get called */ switch (iotype) { case VCMD_IO_NONE: case VCMD_IO_FD: ret = Py_BuildValue("O", (PyObject *)cmdwait); break; case VCMD_IO_PIPE: ret = Py_BuildValue("(OOOO)", (PyObject *)cmdwait, pyinfile, pyoutfile, pyerrfile); break; case VCMD_IO_PTY: ret = Py_BuildValue("(OO)", (PyObject *)cmdwait, pyptyfile); break; default: ret = NULL; break; } pthread_mutex_unlock(&cmdwait->_mutex); return ret; } static PyObject *VCmd_qcmd(VCmd *self, PyObject *args, PyObject *kwds) { return _VCmd_cmd(self, args, kwds, VCMD_IO_NONE); } static PyObject *VCmd_redircmd(VCmd *self, PyObject *args, PyObject *kwds) { return _VCmd_cmd(self, args, kwds, VCMD_IO_FD); } static PyObject *VCmd_popen(VCmd *self, PyObject *args, PyObject *kwds) { return _VCmd_cmd(self, args, kwds, VCMD_IO_PIPE); } static PyObject *VCmd_ptyopen(VCmd *self, PyObject *args, PyObject *kwds) { return _VCmd_cmd(self, args, kwds, VCMD_IO_PTY); } static PyObject *VCmd_kill(VCmd *self, PyObject *args, PyObject *kwds) { VCmdWait *cmdwait; int sig; if (!PyArg_ParseTuple(args, "O!i", &vcmd_VCmdWaitType, &cmdwait, &sig)) return NULL; if (cmdwait->_complete) { PyErr_SetString(PyExc_ValueError, "command already complete"); return NULL; } if (vnode_send_cmdsignal(self->_client->serverfd, cmdwait->_cmdid, sig)) { PyErr_SetFromErrno(PyExc_OSError); return NULL; } Py_RETURN_NONE; } static PyMemberDef VCmd_members[] = { {NULL, 0, 0, 0, NULL}, }; static PyMethodDef VCmd_methods[] = { {"connected", (PyCFunction)VCmd_connected, METH_NOARGS, "connected() -> boolean\n\n" "returns True if connected; False otherwise"}, {"popen", (PyCFunction)VCmd_popen, METH_VARARGS | METH_KEYWORDS, "popen(args...) -> (VCmdWait, cmdin, cmdout, cmderr)\n\n" "Send command request and use pipe I/O.\n\n" "args: executable file name followed by command arguments"}, {"ptyopen", (PyCFunction)VCmd_ptyopen, METH_VARARGS| METH_KEYWORDS, "ptyopen(args...) -> (VCmdWait, cmdpty)\n\n" "Send command request and use pty I/O.\n\n" "args: executable file name followed by command arguments"}, {"qcmd", (PyCFunction)VCmd_qcmd, METH_VARARGS | METH_KEYWORDS, "qcmd(args...) -> VCmdWait\n\n" "Send command request without I/O.\n\n" "args: executable file name followed by command arguments"}, {"redircmd", (PyCFunction)VCmd_redircmd, METH_VARARGS | METH_KEYWORDS, "redircmd(infd, outfd, errfd, args...) -> VCmdWait\n\n" "Send command request with I/O redirected from/to the given fds.\n\n" "infd: file descriptor for command standard input\n" "outfd: file descriptor for command standard output\n" "errfd: file descriptor for command standard error\n" "args: executable file name followed by command arguments"}, {"kill", (PyCFunction)VCmd_kill, METH_VARARGS, "kill(cmdwait, signum) -> None\n\n" "Send signal to a command.\n\n" "cmdwait: the VCmdWait object from an earlier command request\n" "signum: the signal to send"}, {NULL, NULL, 0, NULL}, }; static PyTypeObject vcmd_VCmdType = { PyObject_HEAD_INIT(NULL) .tp_name = "vcmd.VCmd", .tp_basicsize = sizeof(VCmd), .tp_dealloc = (destructor)VCmd_dealloc, .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, .tp_doc = "VCmd objects", .tp_methods = VCmd_methods, .tp_members = VCmd_members, .tp_init = (initproc)VCmd_init, .tp_new = VCmd_new, }; static PyObject *vcmd_verbose(PyObject *self, PyObject *args) { int oldval = verbose; if (!PyArg_ParseTuple(args, "|i", &verbose)) return NULL; return Py_BuildValue("i", oldval); } static PyMethodDef vcmd_methods[] = { {"verbose", (PyCFunction)vcmd_verbose, METH_VARARGS, "verbose([newval]) -> int\n\n" "Get the current verbose level and optionally set it to newval."}, {NULL, NULL, 0, NULL}, }; PyMODINIT_FUNC initvcmd(void) { PyObject *m; if (PyType_Ready(&vcmd_VCmdType) < 0) return; if (PyType_Ready(&vcmd_VCmdWaitType) < 0) return; m = Py_InitModule3("vcmd", vcmd_methods, "vcmd module that does stuff..."); if (!m) return; Py_INCREF(&vcmd_VCmdType); PyModule_AddObject(m, "VCmd", (PyObject *)&vcmd_VCmdType); Py_INCREF(&vcmd_VCmdWaitType); PyModule_AddObject(m, "VCmdWait", (PyObject *)&vcmd_VCmdWaitType); return; } core-4.8/daemon/src/netns_main.c0000664000175000017500000000445512534327775013620 00000000000000/* * CORE * Copyright (c)2010-2012 the Boeing Company. * See the LICENSE file included in this distribution. * * author: Tom Goff * * netns_main.c * * netns utility program runs the specified program with arguments in a new * namespace. * */ #include #include #include #include #include #include #include #include "version.h" #include "netns.h" #include "myerr.h" struct option longopts[] = { {"version", no_argument, NULL, 'V'}, {"help", no_argument, NULL, 'h'}, { 0 } }; static void usage(int status, char *fmt, ...) { extern const char *__progname; va_list ap; FILE *output; va_start(ap, fmt); output = status ? stderr : stdout; fprintf(output, "\n"); if (fmt != NULL) { vfprintf(output, fmt, ap); fprintf(output, "\n\n"); } fprintf(output, "Usage: %s [-h|-V] [-w] -- command [args...]\n\n" "Run the specified command in a new network namespace.\n\n" "Options:\n" " -h, --help show this help message and exit\n" " -V, --version show version number and exit\n" " -w wait for command to complete " "(useful for interactive commands)\n", __progname); va_end(ap); exit(status); } int main(int argc, char *argv[]) { pid_t pid; int waitcmd = 0; int status = 0; extern const char *__progname; for (;;) { int opt; if ((opt = getopt_long(argc, argv, "hwV", longopts, NULL)) == -1) break; switch (opt) { case 'w': waitcmd++; break; case 'V': printf("%s version %s\n", __progname, CORE_VERSION); exit(0); case 'h': default: usage(0, NULL); } } argc -= optind; argv += optind; if (!argc) usage(1, "no command given"); if (geteuid() != 0) usage(1, "must be suid or run as root"); if (setuid(0)) ERR(1, "setuid() failed"); pid = nsexecvp(argv); if (pid < 0) ERR(1, "nsexecvp() failed"); printf("%d\n", pid); if (waitcmd) { if (waitpid(pid, &status, 0) == -1) ERR(1, "waitpid() failed"); if (WIFEXITED(status)) status = WEXITSTATUS(status); else if (WIFSIGNALED(status)) { fprintf(stderr, "process terminated by signal %d\n", WTERMSIG(status)); status = -1; } } exit(status); } core-4.8/daemon/src/netns.c0000664000175000017500000000363412534327775012612 00000000000000/* * CORE * Copyright (c)2010-2012 the Boeing Company. * See the LICENSE file included in this distribution. * * author: Tom Goff * * netns.c * * Implements nsfork() and nsexecvp() for forking and executing processes * within a network namespace. * */ #include #include #include #include #include #include "myerr.h" #include "netns.h" #define NSCLONEFLGS \ ( \ SIGCHLD | \ CLONE_NEWNS | \ CLONE_NEWUTS | \ CLONE_NEWIPC | \ CLONE_NEWPID | \ CLONE_NEWNET \ ) #define MOUNT_SYS_MIN_VERSION "2.6.35" static void nssetup(void) { int r; struct utsname uts; /* Taken from systemd-nspawn. Not sure why needed, but without this, * the host system goes a bit crazy under systemd. */ r = mount(NULL, "/", NULL, MS_SLAVE|MS_REC, NULL); if (r) WARN("mounting / failed"); /* mount per-namespace /proc */ r = mount(NULL, "/proc", "proc", 0, NULL); if (r) WARN("mounting /proc failed"); r = uname(&uts); if (r) { WARN("uname() failed"); return; } r = strncmp(uts.release, MOUNT_SYS_MIN_VERSION, sizeof(MOUNT_SYS_MIN_VERSION) - 1); if (r >= 0) { /* mount per-namespace /sys */ r = mount(NULL, "/sys", "sysfs", 0, NULL); if (r) WARN("mounting /sys failed"); } } pid_t nsfork(int flags) { int pid; pid = syscall(SYS_clone, flags | NSCLONEFLGS, NULL, NULL, NULL, NULL); if (pid == 0) /* child */ { nssetup(); } return pid; } pid_t nsexecvp(char *argv[]) { pid_t pid; pid = nsfork(CLONE_VFORK); switch (pid) { case -1: WARN("nsfork() failed"); break; case 0: /* child */ execvp(argv[0], argv); WARN("execvp() failed for '%s'", argv[0]); _exit(1); break; default: /* parent */ if (kill(pid, 0)) pid = -1; break; } return pid; } core-4.8/daemon/src/netns.h0000664000175000017500000000050712534327775012613 00000000000000/* * CORE * Copyright (c)2010-2012 the Boeing Company. * See the LICENSE file included in this distribution. * * author: Tom Goff * * netns.h * */ #ifndef _FORKNS_H_ #define _FORKNS_H_ #include pid_t nsfork(int flags); pid_t nsexecvp(char *argv[]); #endif /* _FORKNS_H_ */ core-4.8/daemon/src/vnode_msg.c0000664000175000017500000001301712534327775013440 00000000000000/* * CORE * Copyright (c)2010-2012 the Boeing Company. * See the LICENSE file included in this distribution. * * author: Tom Goff * * vnode_msg.c * */ #include #include #include #include #include #include "myerr.h" #include "vnode_msg.h" static void vnode_msg_cb(struct ev_loop *loop, ev_io *w, int revents) { vnode_msgio_t *msgio = w->data; ssize_t tmp; vnode_msghandler_t msghandlefn; #ifdef DEBUG WARNX("new message on fd %d", msgio->fd); #endif assert(msgio); tmp = vnode_recvmsg(msgio); if (tmp == 0) return; else if (tmp < 0) { ev_io_stop(loop, w); if (msgio->ioerror) msgio->ioerror(msgio); return; } msghandlefn = msgio->msghandler[msgio->msgbuf.msg->hdr.type]; if (!msghandlefn) { WARNX("no handler found for msg type %u from fd %d", msgio->msgbuf.msg->hdr.type, msgio->fd); return; } msghandlefn(msgio); return; } ssize_t vnode_sendmsg(int fd, vnode_msgbuf_t *msgbuf) { struct msghdr msg = {}; struct iovec iov[1]; char buf[CMSG_SPACE(3 * sizeof(int))]; iov[0].iov_base = msgbuf->msg; iov[0].iov_len = vnode_msglen(msgbuf); msg.msg_iov = iov; msg.msg_iovlen = 1; if (msgbuf->infd >= 0) { struct cmsghdr *cmsg; int *fdptr; assert(msgbuf->outfd >= 0); assert(msgbuf->errfd >= 0); msg.msg_control = buf; msg.msg_controllen = sizeof(buf); cmsg = CMSG_FIRSTHDR(&msg); cmsg->cmsg_level = SOL_SOCKET; cmsg->cmsg_type = SCM_RIGHTS; cmsg->cmsg_len = CMSG_LEN(3 * sizeof(int)); fdptr = (int *)CMSG_DATA(cmsg); fdptr[0] = msgbuf->infd; fdptr[1] = msgbuf->outfd; fdptr[2] = msgbuf->errfd; msg.msg_controllen = cmsg->cmsg_len; } return sendmsg(fd, &msg, 0); } /* * return the number of bytes received * return 0 if the message should be ignored * return a negative value if i/o should stop */ ssize_t vnode_recvmsg(vnode_msgio_t *msgio) { ssize_t recvlen; struct msghdr msg = {}; struct iovec iov[1]; char buf[CMSG_SPACE(3 * sizeof(int))]; struct cmsghdr *cmsg; if (msgio->msgbuf.msgbufsize < VNODE_MSGSIZMAX) { if (vnode_resizemsgbuf(&msgio->msgbuf, VNODE_MSGSIZMAX)) return -1; } msgio->msgbuf.infd = msgio->msgbuf.outfd = msgio->msgbuf.errfd = -1; iov[0].iov_base = msgio->msgbuf.msg; iov[0].iov_len = msgio->msgbuf.msgbufsize; msg.msg_iov = iov; msg.msg_iovlen = 1; msg.msg_control = buf; msg.msg_controllen = sizeof(buf); recvlen = recvmsg(msgio->fd, &msg, 0); if (recvlen == 0) return -1; else if (recvlen < 0) { if (errno == EAGAIN) return 0; WARN("recvmsg() failed"); return -1; } cmsg = CMSG_FIRSTHDR(&msg); if (cmsg != NULL && cmsg->cmsg_type == SCM_RIGHTS) { int *fdptr; fdptr = (int *)CMSG_DATA(cmsg); msgio->msgbuf.infd = fdptr[0]; msgio->msgbuf.outfd = fdptr[1]; msgio->msgbuf.errfd = fdptr[2]; } if (recvlen < sizeof(msgio->msgbuf.msg->hdr)) { WARNX("message header truncated: received %d of %d bytes", recvlen, sizeof(msgio->msgbuf.msg->hdr)); return 0; } if (msgio->msgbuf.msg->hdr.type == VNODE_MSG_NONE || msgio->msgbuf.msg->hdr.type >= VNODE_MSG_MAX) { WARNX("invalid message type: %u", msgio->msgbuf.msg->hdr.type); return 0; } if (recvlen - sizeof(msgio->msgbuf.msg->hdr) != msgio->msgbuf.msg->hdr.datalen) { WARNX("message length mismatch: received %d bytes; expected %d bytes", recvlen - sizeof(msgio->msgbuf.msg->hdr), msgio->msgbuf.msg->hdr.datalen); return 0; } return recvlen; } int vnode_msgiostart(vnode_msgio_t *msgio, struct ev_loop *loop, int fd, void *data, vnode_msghandler_t ioerror, const vnode_msghandler_t msghandler[VNODE_MSG_MAX]) { #ifdef DEBUG WARNX("starting message i/o for fd %d", fd); #endif if (vnode_initmsgbuf(&msgio->msgbuf)) return -1; msgio->loop = loop; msgio->fd = fd; msgio->fdwatcher.data = msgio; ev_io_init(&msgio->fdwatcher, vnode_msg_cb, fd, EV_READ); msgio->data = data; msgio->ioerror = ioerror; memcpy(msgio->msghandler, msghandler, sizeof(msgio->msghandler)); ev_io_start(msgio->loop, &msgio->fdwatcher); return 0; } void vnode_msgiostop(vnode_msgio_t *msgio) { ev_io_stop(msgio->loop, &msgio->fdwatcher); FREE_MSGBUF(&msgio->msgbuf); return; } int vnode_parsemsg(vnode_msg_t *msg, void *data, const vnode_tlvhandler_t tlvhandler[VNODE_TLV_MAX]) { size_t offset = 0; vnode_tlv_t *tlv; vnode_tlvhandler_t tlvhandlefn; int tmp = -1; while (offset < msg->hdr.datalen) { tlv = (void *)msg->data + offset; offset += sizeof(*tlv) + tlv->vallen; if (tlv->vallen == 0 || offset > msg->hdr.datalen) { WARNX("invalid value length: %u", tlv->vallen); continue; } if ((tlvhandlefn = tlvhandler[tlv->type]) == NULL) { WARNX("unknown tlv type: %u", tlv->type); continue; } if ((tmp = tlvhandlefn(tlv, data))) break; } return tmp; } ssize_t vnode_addtlv(vnode_msgbuf_t *msgbuf, size_t offset, uint32_t type, uint32_t vallen, const void *valp) { vnode_tlv_t *tlv; size_t msglen, tlvlen; tlv = (void *)msgbuf->msg->data + offset; msglen = (void *)tlv - (void *)msgbuf->msg; tlvlen = sizeof(*tlv) + vallen; if (msglen + tlvlen > msgbuf->msgbufsize) { if (vnode_resizemsgbuf(msgbuf, msgbuf->msgbufsize + tlvlen)) return -1; else tlv = (void *)msgbuf->msg->data + offset; } tlv->type = type; tlv->vallen = vallen; memcpy(tlv->val, valp, vallen); return tlvlen; } core-4.8/daemon/src/vnode_cmd.c0000664000175000017500000002404612534327775013421 00000000000000/* * CORE * Copyright (c)2010-2012 the Boeing Company. * See the LICENSE file included in this distribution. * * author: Tom Goff * * vnode_cmd.c * */ #include #include #include #include #include #include "myerr.h" #include "vnode_msg.h" #include "vnode_server.h" #include "vnode_tlv.h" #include "vnode_io.h" #include "vnode_cmd.h" extern int verbose; static void vnode_process_cmdreq(vnode_cliententry_t *client, vnode_cmdreq_t *cmdreq); static int tlv_cmdreq_cmdid(vnode_tlv_t *tlv, void *data) { vnode_cmdreq_t *cmdreq = data; int tmp; assert(tlv->type == VNODE_TLV_CMDID); tmp = tlv_int32(&cmdreq->cmdid, tlv); if (tmp == 0 && verbose) INFO("VNODE_TLV_CMDID: %u", cmdreq->cmdid); return tmp; } static int tlv_cmdreq_cmdarg(vnode_tlv_t *tlv, void *data) { vnode_cmdreq_t *cmdreq = data; int i, tmp; assert(tlv->type == VNODE_TLV_CMDARG); #define CMDARGMAX (sizeof(cmdreq->cmdarg) / sizeof(cmdreq->cmdarg[0])) for (i = 0; i < CMDARGMAX; i++) if (cmdreq->cmdarg[i] == NULL) break; if (i == CMDARGMAX) { WARNX("too many command arguments"); return -1; } #undef CMDARGMAX tmp = tlv_string(&cmdreq->cmdarg[i], tlv); if (tmp == 0 && verbose) INFO("VNODE_TLV_CMDARG: '%s'", cmdreq->cmdarg[i]); return tmp; } void vnode_recv_cmdreq(vnode_msgio_t *msgio) { vnode_cliententry_t *client = msgio->data; vnode_cmdreq_t cmdreq = CMDREQ_INIT; static vnode_tlvhandler_t cmdreq_tlvhandler[VNODE_TLV_MAX] = { [VNODE_TLV_CMDID] = tlv_cmdreq_cmdid, [VNODE_TLV_CMDARG] = tlv_cmdreq_cmdarg, }; #ifdef DEBUG WARNX("command request"); #endif assert(msgio->msgbuf.msg->hdr.type == VNODE_MSG_CMDREQ); if (vnode_parsemsg(msgio->msgbuf.msg, &cmdreq, cmdreq_tlvhandler)) return; cmdreq.cmdio.infd = msgio->msgbuf.infd; cmdreq.cmdio.outfd = msgio->msgbuf.outfd; cmdreq.cmdio.errfd = msgio->msgbuf.errfd; vnode_process_cmdreq(client, &cmdreq); return; } int vnode_send_cmdreq(int fd, int32_t cmdid, char *argv[], int infd, int outfd, int errfd) { size_t offset = 0; vnode_msgbuf_t msgbuf; char **cmdarg; int tmp; if (vnode_initmsgbuf(&msgbuf)) return -1; #define ADDTLV(t, l, vp) \ do { \ ssize_t tlvlen; \ tlvlen = vnode_addtlv(&msgbuf, offset, t, l, vp); \ if (tlvlen < 0) \ { \ WARNX("vnode_addtlv() failed"); \ FREE_MSGBUF(&msgbuf); \ return -1; \ } \ offset += tlvlen; \ } while (0) ADDTLV(VNODE_TLV_CMDID, sizeof(cmdid), &cmdid); for (cmdarg = argv; *cmdarg; cmdarg++) ADDTLV(VNODE_TLV_CMDARG, strlen(*cmdarg) + 1, *cmdarg); #undef ADDTLV msgbuf.infd = infd; msgbuf.outfd = outfd; msgbuf.errfd = errfd; #ifdef DEBUG WARNX("sending cmd req on fd %d: cmd '%s'", fd, argv[0]); #endif msgbuf.msg->hdr.type = VNODE_MSG_CMDREQ; msgbuf.msg->hdr.datalen = offset; if (vnode_sendmsg(fd, &msgbuf) == vnode_msglen(&msgbuf)) tmp = 0; else tmp = -1; FREE_MSGBUF(&msgbuf); return tmp; } int vnode_send_cmdreqack(int fd, int32_t cmdid, int32_t pid) { ssize_t tmp = -1; size_t offset = 0; vnode_msgbuf_t msgbuf; if (vnode_initmsgbuf(&msgbuf)) return -1; #define ADDTLV(t, l, vp) \ do { \ ssize_t tlvlen; \ tlvlen = vnode_addtlv(&msgbuf, offset, t, l, vp); \ if (tlvlen < 0) \ { \ WARNX("vnode_addtlv() failed"); \ FREE_MSGBUF(&msgbuf); \ return -1; \ } \ offset += tlvlen; \ } while (0) ADDTLV(VNODE_TLV_CMDID, sizeof(cmdid), &cmdid); ADDTLV(VNODE_TLV_CMDPID, sizeof(pid), &pid); #undef ADDTLV #ifdef DEBUG WARNX("sending cmd req ack on fd %d: cmdid %d; pid %d", fd, cmdid, pid); #endif msgbuf.msg->hdr.type = VNODE_MSG_CMDREQACK; msgbuf.msg->hdr.datalen = offset; if (vnode_sendmsg(fd, &msgbuf) == vnode_msglen(&msgbuf)) tmp = 0; FREE_MSGBUF(&msgbuf); return tmp; } int vnode_send_cmdstatus(int fd, int32_t cmdid, int32_t status) { int tmp; size_t offset = 0; vnode_msgbuf_t msgbuf; if (vnode_initmsgbuf(&msgbuf)) return -1; #define ADDTLV(t, l, vp) \ do { \ ssize_t tlvlen; \ tlvlen = vnode_addtlv(&msgbuf, offset, t, l, vp); \ if (tlvlen < 0) \ { \ WARNX("vnode_addtlv() failed"); \ FREE_MSGBUF(&msgbuf); \ return -1; \ } \ offset += tlvlen; \ } while (0) ADDTLV(VNODE_TLV_CMDID, sizeof(cmdid), &cmdid); ADDTLV(VNODE_TLV_CMDSTATUS, sizeof(status), &status); #undef ADDTLV #ifdef DEBUG WARNX("sending cmd status on fd %d: cmdid %d; status %d", fd, cmdid, status); #endif msgbuf.msg->hdr.type = VNODE_MSG_CMDSTATUS; msgbuf.msg->hdr.datalen = offset; if (vnode_sendmsg(fd, &msgbuf) == vnode_msglen(&msgbuf)) tmp = 0; else tmp = -1; FREE_MSGBUF(&msgbuf); return tmp; } int vnode_send_cmdsignal(int fd, int32_t cmdid, int32_t signum) { ssize_t tmp; size_t offset = 0; vnode_msgbuf_t msgbuf; if (vnode_initmsgbuf(&msgbuf)) return -1; #define ADDTLV(t, l, vp) \ do { \ ssize_t tlvlen; \ tlvlen = vnode_addtlv(&msgbuf, offset, t, l, vp); \ if (tlvlen < 0) \ { \ WARNX("vnode_addtlv() failed"); \ FREE_MSGBUF(&msgbuf); \ return -1; \ } \ offset += tlvlen; \ } while (0) ADDTLV(VNODE_TLV_CMDID, sizeof(cmdid), &cmdid); ADDTLV(VNODE_TLV_SIGNUM, sizeof(signum), &signum); #undef ADDTLV #ifdef DEBUG WARNX("sending cmd signal on fd %d: cmdid %d; signum %d", fd, cmdid, signum); #endif msgbuf.msg->hdr.type = VNODE_MSG_CMDSIGNAL; msgbuf.msg->hdr.datalen = offset; if (vnode_sendmsg(fd, &msgbuf) == vnode_msglen(&msgbuf)) tmp = 0; else tmp = -1; FREE_MSGBUF(&msgbuf); return tmp; } static int tlv_cmdsignal_cmdid(vnode_tlv_t *tlv, void *data) { vnode_cmdsignal_t *cmdsignal = data; int tmp; assert(tlv->type == VNODE_TLV_CMDID); tmp = tlv_int32(&cmdsignal->cmdid, tlv); if (tmp == 0 && verbose) INFO("VNODE_TLV_CMDID: %d", cmdsignal->cmdid); return tmp; } static int tlv_cmdsignal_signum(vnode_tlv_t *tlv, void *data) { vnode_cmdsignal_t *cmdsignal = data; int tmp; assert(tlv->type == VNODE_TLV_SIGNUM); tmp = tlv_int32(&cmdsignal->signum, tlv); if (tmp == 0 && verbose) INFO("VNODE_TLV_SIGNUM: %d", cmdsignal->signum); return tmp; } void vnode_recv_cmdsignal(vnode_msgio_t *msgio) { vnode_cliententry_t *client = msgio->data; vnode_cmdsignal_t cmdsignal = CMDSIGNAL_INIT; static vnode_tlvhandler_t cmdsignal_tlvhandler[VNODE_TLV_MAX] = { [VNODE_TLV_CMDID] = tlv_cmdsignal_cmdid, [VNODE_TLV_SIGNUM] = tlv_cmdsignal_signum, }; vnode_cmdentry_t *cmd; #ifdef DEBUG WARNX("command signal"); #endif assert(msgio->msgbuf.msg->hdr.type == VNODE_MSG_CMDSIGNAL); if (vnode_parsemsg(msgio->msgbuf.msg, &cmdsignal, cmdsignal_tlvhandler)) return; TAILQ_FOREACH(cmd, &client->server->cmdlisthead, entries) { if (cmd->cmdid == cmdsignal.cmdid && cmd->data == client) { if (verbose) INFO("sending pid %u signal %u", cmd->pid, cmdsignal.signum); if (kill(cmd->pid, cmdsignal.signum)) WARN("kill() failed"); break; } } if (cmd == NULL) WARNX("cmdid %d not found for client %p", cmdsignal.cmdid, client); return; } static pid_t forkexec(vnode_cmdreq_t *cmdreq) { pid_t pid; if (verbose) INFO("spawning '%s'", cmdreq->cmdarg[0]); pid = fork(); switch (pid) { case -1: WARN("fork() failed"); break; case 0: /* child */ if (setsid() == -1) WARN("setsid() failed"); #define DUP2(oldfd, newfd) \ do { \ if (oldfd >= 0) \ if (dup2(oldfd, newfd) < 0) \ { \ WARN("dup2() failed for " #newfd \ ": oldfd: %d; newfd: %d", \ oldfd, newfd); \ _exit(1); \ } \ } while (0) DUP2(cmdreq->cmdio.infd, STDIN_FILENO); DUP2(cmdreq->cmdio.outfd, STDOUT_FILENO); DUP2(cmdreq->cmdio.errfd, STDERR_FILENO); #undef DUP2 #define CLOSE_IF_NOT(fd, notfd) \ do { \ if (fd >= 0 && fd != notfd) \ close(fd); \ } while (0) CLOSE_IF_NOT(cmdreq->cmdio.infd, STDIN_FILENO); CLOSE_IF_NOT(cmdreq->cmdio.outfd, STDOUT_FILENO); CLOSE_IF_NOT(cmdreq->cmdio.errfd, STDERR_FILENO); #undef CLOSE_IF_NOT if (clear_nonblock(STDIN_FILENO)) WARN("clear_nonblock() failed"); if (clear_nonblock(STDOUT_FILENO)) WARN("clear_nonblock() failed"); if (clear_nonblock(STDERR_FILENO)) WARN("clear_nonblock() failed"); /* try to get a controlling terminal (don't steal a terminal and ignore errors) */ if (isatty(STDIN_FILENO)) ioctl(STDIN_FILENO, TIOCSCTTY, 0); else if (isatty(STDOUT_FILENO)) ioctl(STDOUT_FILENO, TIOCSCTTY, 0); execvp(cmdreq->cmdarg[0], cmdreq->cmdarg); WARN("execvp() failed for '%s'", cmdreq->cmdarg[0]); _exit(1); break; default: /* parent */ break; } #define CLOSE(fd) \ do { \ if (fd >= 0) \ close(fd); \ } while (0) CLOSE(cmdreq->cmdio.infd); CLOSE(cmdreq->cmdio.outfd); CLOSE(cmdreq->cmdio.errfd); #undef CLOSE return pid; } static void vnode_process_cmdreq(vnode_cliententry_t *client, vnode_cmdreq_t *cmdreq) { vnode_cmdentry_t *cmd = NULL; if ((cmd = malloc(sizeof(*cmd))) == NULL) { WARN("malloc() failed"); return; } cmd->cmdid = cmdreq->cmdid; cmd->pid = -1; cmd->status = -1; cmd->data = client; cmd->pid = forkexec(cmdreq); if (verbose) INFO("cmd: '%s'; pid: %d; cmdid: %d; " "infd: %d; outfd: %d; errfd: %d", cmdreq->cmdarg[0], cmd->pid, cmd->cmdid, cmdreq->cmdio.infd, cmdreq->cmdio.outfd, cmdreq->cmdio.errfd); if (vnode_send_cmdreqack(client->clientfd, cmd->cmdid, cmd->pid)) { WARNX("vnode_send_cmdreqack() failed"); // XXX if (cmd->pid != -1) kill(cmd->pid, SIGKILL); ? free(cmd); return; } if (cmd->pid == -1) free(cmd); else { #ifdef DEBUG WARNX("adding pid %d to cmd list", cmd->pid); #endif TAILQ_INSERT_TAIL(&client->server->cmdlisthead, cmd, entries); } return; } core-4.8/daemon/src/vnode_chnl.c0000664000175000017500000000404712534327775013601 00000000000000/* * CORE * Copyright (c)2010-2012 the Boeing Company. * See the LICENSE file included in this distribution. * * author: Tom Goff * * vnode_chnl.c * * Functions for setting up a local UNIX socket to use as a control channel * for interacting with a network namespace. * */ #include #include #include #include #include #include #include "vnode_msg.h" #include "vnode_tlv.h" #include "vnode_chnl.h" #include "vnode_io.h" extern int verbose; int vnode_connect(const char *name) { int fd; struct sockaddr_un addr; #ifdef DEBUG WARNX("opening '%s'", name); #endif if (strlen(name) > sizeof(addr.sun_path) - 1) { WARNX("name too long: '%s'", name); return -1; } if ((fd = socket(AF_UNIX, SOCK_SEQPACKET, 0)) < 0) { WARN("socket() failed"); return -1; } addr.sun_family = AF_UNIX; strcpy(addr.sun_path, name); if (connect(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) { WARN("connect() failed for '%s'", name); close(fd); return -1; } if (set_nonblock(fd)) WARN("set_nonblock() failed for fd %d", fd); return fd; } int vnode_listen(const char *name) { int fd; struct sockaddr_un addr; #ifdef DEBUG WARNX("opening '%s'", name); #endif if (strlen(name) > sizeof(addr.sun_path) - 1) { WARNX("name too long: '%s'", name); return -1; } if ((fd = socket(AF_UNIX, SOCK_SEQPACKET, 0)) < 0) { WARN("socket() failed"); return -1; } unlink(name); addr.sun_family = AF_UNIX; strcpy(addr.sun_path, name); if (bind(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) { WARN("bind() failed for '%s'", name); close(fd); return -1; } /* to override umask */ if (chmod(name, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH)) WARN("fchmod() failed for '%s'", name); if (listen(fd, 5) < 0) { WARN("listen() failed"); close(fd); return -1; } if (set_nonblock(fd)) WARN("set_nonblock() failed for fd %d", fd); return fd; } core-4.8/daemon/src/vnode_io.c0000664000175000017500000000543312534327775013264 00000000000000/* * CORE * Copyright (c)2010-2012 the Boeing Company. * See the LICENSE file included in this distribution. * * author: Tom Goff * * vnode_io.c * */ #include #include #include /* #define _XOPEN_SOURCE */ #ifndef __USE_XOPEN #define __USE_XOPEN #endif #include #include #include #include #include "myerr.h" #include "vnode_chnl.h" #include "vnode_io.h" int set_nonblock(int fd) { int fl, r = 0; if ((fl = fcntl(fd, F_GETFL)) == -1) { fl = 0; r = -1; } if (fcntl(fd, F_SETFL, fl | O_NONBLOCK)) r = -1; return r; } int clear_nonblock(int fd) { int fl, r = 0; if ((fl = fcntl(fd, F_GETFL)) == -1) { fl = 0; r = -1; } if (fcntl(fd, F_SETFL, fl & ~O_NONBLOCK)) r = -1; return r; } int open_stdio_pty(stdio_pty_t *stdiopty) { int masterfd, slavefd; INIT_STDIO_PTY(stdiopty); if ((masterfd = posix_openpt(O_RDWR | O_NOCTTY)) < 0) { WARN("posix_openpt() failed"); return -1; } if (grantpt(masterfd)) { WARN("grantpt() failed"); close(masterfd); return -1; } if (unlockpt(masterfd)) { WARN("unlockpt() failed"); close(masterfd); return -1; } if ((slavefd = open(ptsname(masterfd), O_RDWR | O_NOCTTY)) < 0) { WARN("open() failed"); close(masterfd); return -1; } stdiopty->masterfd = masterfd; stdiopty->slavefd = slavefd; return 0; } void close_stdio_pty(stdio_pty_t *stdiopty) { if (stdiopty->masterfd >= 0) close(stdiopty->masterfd); if (stdiopty->slavefd >= 0) close(stdiopty->slavefd); INIT_STDIO_PTY(stdiopty); return; } int open_stdio_pipe(stdio_pipe_t *stdiopipe) { int infd[2], outfd[2], errfd[2]; INIT_STDIO_PIPE(stdiopipe); if (pipe(infd) < 0) { WARN("pipe() failed"); return -1; } if (pipe(outfd) < 0) { WARN("pipe() failed"); close(infd[0]); close(infd[1]); return -1; } if (pipe(errfd) < 0) { WARN("pipe() failed"); close(infd[0]); close(infd[1]); close(outfd[0]); close(outfd[1]); return -1; } stdiopipe->infd[0] = infd[0]; stdiopipe->infd[1] = infd[1]; stdiopipe->outfd[0] = outfd[0]; stdiopipe->outfd[1] = outfd[1]; stdiopipe->errfd[0] = errfd[0]; stdiopipe->errfd[1] = errfd[1]; return 0; } void close_stdio_pipe(stdio_pipe_t *stdiopipe) { if (stdiopipe->infd[0] >= 0) close(stdiopipe->infd[0]); if (stdiopipe->infd[1] >= 0) close(stdiopipe->infd[1]); if (stdiopipe->outfd[0] >= 0) close(stdiopipe->outfd[0]); if (stdiopipe->outfd[1] >= 0) close(stdiopipe->outfd[1]); if (stdiopipe->errfd[0] >= 0) close(stdiopipe->errfd[0]); if (stdiopipe->errfd[1] >= 0) close(stdiopipe->errfd[1]); INIT_STDIO_PIPE(stdiopipe); return; } core-4.8/daemon/src/vnode_msg.h0000664000175000017500000000625512534327775013453 00000000000000/* * CORE * Copyright (c)2010-2012 the Boeing Company. * See the LICENSE file included in this distribution. * * author: Tom Goff * * vnode_msg.h * */ #ifndef _VNODE_MSG_H_ #define _VNODE_MSG_H_ #include #include #include #include #include "myerr.h" typedef struct __attribute__ ((__packed__)) { uint32_t type; uint32_t vallen; uint8_t val[]; } vnode_tlv_t; typedef struct __attribute__ ((__packed__)) { uint32_t type; uint32_t datalen; } vnode_msghdr_t; typedef struct __attribute__ ((__packed__)) { vnode_msghdr_t hdr; uint8_t data[]; } vnode_msg_t; typedef enum { VNODE_MSG_NONE = 0, VNODE_MSG_CMDREQ, VNODE_MSG_CMDREQACK, VNODE_MSG_CMDSTATUS, VNODE_MSG_CMDSIGNAL, VNODE_MSG_MAX, } vnode_msgtype_t; typedef enum { VNODE_TLV_NONE = 0, VNODE_TLV_CMDID, VNODE_TLV_STDIN, VNODE_TLV_STDOUT, VNODE_TLV_STDERR, VNODE_TLV_CMDARG, VNODE_TLV_CMDPID, VNODE_TLV_CMDSTATUS, VNODE_TLV_SIGNUM, VNODE_TLV_MAX, } vnode_tlvtype_t; enum { VNODE_ARGMAX = 1024, VNODE_MSGSIZMAX = 65535, }; typedef struct { vnode_msg_t *msg; size_t msgbufsize; int infd; int outfd; int errfd; } vnode_msgbuf_t; #define INIT_MSGBUF(msgbuf) \ do { \ (msgbuf)->msg = NULL; \ (msgbuf)->msgbufsize = 0; \ (msgbuf)->infd = -1; \ (msgbuf)->outfd = -1; \ (msgbuf)->errfd = -1; \ } while (0) #define FREE_MSGBUF(msgbuf) \ do { \ if ((msgbuf)->msg) \ free((msgbuf)->msg); \ INIT_MSGBUF(msgbuf); \ } while (0) struct vnode_msgio; typedef void (*vnode_msghandler_t)(struct vnode_msgio *msgio); typedef struct vnode_msgio { struct ev_loop *loop; int fd; ev_io fdwatcher; vnode_msgbuf_t msgbuf; void *data; vnode_msghandler_t ioerror; vnode_msghandler_t msghandler[VNODE_MSG_MAX]; } vnode_msgio_t; typedef int (*vnode_tlvhandler_t)(vnode_tlv_t *tlv, void *data); static inline void vnode_msgiohandler(vnode_msgio_t *msgio, vnode_msgtype_t msgtype, vnode_msghandler_t msghandlefn) { msgio->msghandler[msgtype] = msghandlefn; return; } static inline int vnode_resizemsgbuf(vnode_msgbuf_t *msgbuf, size_t size) { void *newbuf; if ((newbuf = realloc(msgbuf->msg, size)) == NULL) { WARN("realloc() failed for size %u", size); return -1; } msgbuf->msg = newbuf; msgbuf->msgbufsize = size; return 0; } static inline int vnode_initmsgbuf(vnode_msgbuf_t *msgbuf) { INIT_MSGBUF(msgbuf); return vnode_resizemsgbuf(msgbuf, VNODE_MSGSIZMAX); } #define vnode_msglen(msgbuf) \ (sizeof(*(msgbuf)->msg) + (msgbuf)->msg->hdr.datalen) ssize_t vnode_sendmsg(int fd, vnode_msgbuf_t *msgbuf); ssize_t vnode_recvmsg(vnode_msgio_t *msgio); int vnode_msgiostart(vnode_msgio_t *msgio, struct ev_loop *loop, int fd, void *data, vnode_msghandler_t ioerror, const vnode_msghandler_t msghandler[VNODE_MSG_MAX]); void vnode_msgiostop(vnode_msgio_t *msgio); int vnode_parsemsg(vnode_msg_t *msg, void *data, const vnode_tlvhandler_t tlvhandler[VNODE_TLV_MAX]); ssize_t vnode_addtlv(vnode_msgbuf_t *msgbuf, size_t offset, uint32_t type, uint32_t vallen, const void *valp); #endif /* _VNODE_MSG_H_ */ core-4.8/daemon/src/vnode_cmd.h0000664000175000017500000000252512534327775013424 00000000000000/* * CORE * Copyright (c)2010-2012 the Boeing Company. * See the LICENSE file included in this distribution. * * author: Tom Goff * * vnode_cmd.h * */ #ifndef _VNODE_CMD_H_ #define _VNODE_CMD_H_ #include #include #include "vnode_msg.h" typedef struct { int infd; int outfd; int errfd; } vnode_cmdio_t; typedef struct { int32_t cmdid; vnode_cmdio_t cmdio; char *cmdarg[VNODE_ARGMAX]; } vnode_cmdreq_t; #define CMDREQ_INIT {} typedef struct { int32_t cmdid; int32_t pid; } vnode_cmdreqack_t; #define CMDREQACK_INIT {.cmdid = 0, .pid = -1} typedef struct { int32_t cmdid; int32_t status; } vnode_cmdstatus_t; #define CMDSTATUS_INIT {.cmdid = 0, .status = -1} typedef struct { int32_t cmdid; int32_t signum; } vnode_cmdsignal_t; #define CMDSIGNAL_INIT {.cmdid = 0, .signum = 0} typedef struct cmdentry { TAILQ_ENTRY(cmdentry) entries; int32_t cmdid; pid_t pid; int status; void *data; } vnode_cmdentry_t; void vnode_recv_cmdreq(vnode_msgio_t *msgio); int vnode_send_cmdreq(int fd, int32_t cmdid, char *argv[], int infd, int outfd, int errfd); int vnode_send_cmdstatus(int fd, int32_t cmdid, int32_t status); int vnode_send_cmdsignal(int fd, int32_t cmdid, int32_t signum); void vnode_recv_cmdsignal(vnode_msgio_t *msgio); #endif /* _VNODE_CMD_H_ */ core-4.8/daemon/src/vnode_chnl.h0000664000175000017500000000052012534327775013576 00000000000000/* * CORE * Copyright (c)2010-2012 the Boeing Company. * See the LICENSE file included in this distribution. * * author: Tom Goff * * vnode_chnl.h * */ #ifndef _VNODE_CHNL_H_ #define _VNODE_CHNL_H_ int vnode_connect(const char *name); int vnode_listen(const char *name); #endif /* _VNODE_CHNL_H_ */ core-4.8/daemon/src/vnode_io.h0000664000175000017500000000217212534327775013266 00000000000000/* * CORE * Copyright (c)2010-2012 the Boeing Company. * See the LICENSE file included in this distribution. * * author: Tom Goff * * vnode_io.h * */ #ifndef _VNODE_IO_H_ #define _VNODE_IO_H_ typedef struct { int infd; int outfd; int errfd; } stdio_fd_t; #define INIT_STDIO_FD(s) \ do { \ (s)->infd = -1; \ (s)->outfd = -1; \ (s)->errfd = -1; \ } while (0) typedef struct { int masterfd; int slavefd; } stdio_pty_t; #define INIT_STDIO_PTY(s) \ do { \ (s)->masterfd = -1; \ (s)->slavefd = -1; \ } while (0) typedef struct { int infd[2]; int outfd[2]; int errfd[2]; } stdio_pipe_t; #define INIT_STDIO_PIPE(s) \ do { \ (s)->infd[0] = (s)->infd[1] = -1; \ (s)->outfd[0] = (s)->outfd[1] = -1; \ (s)->errfd[0] = (s)->errfd[1] = -1; \ } while (0) int set_nonblock(int fd); int clear_nonblock(int fd); int open_stdio_pty(stdio_pty_t *stdiopty); void close_stdio_pty(stdio_pty_t *stdiopty); int open_stdio_pipe(stdio_pipe_t *stdiopipe); void close_stdio_pipe(stdio_pipe_t *stdiopipe); #endif /* _VNODE_IO_H_ */ core-4.8/daemon/src/vnode_tlv.h0000664000175000017500000000127512534327775013467 00000000000000/* * CORE * Copyright (c)2010-2012 the Boeing Company. * See the LICENSE file included in this distribution. * * author: Tom Goff * * vnode_tlv.h * */ #ifndef _VNODE_TLV_H_ #define _VNODE_TLV_H_ static inline int tlv_string(char **var, vnode_tlv_t *tlv) { if (tlv->val[tlv->vallen - 1] != '\0') { WARNX("string not null-terminated"); return -1; } *var = (char *)tlv->val; return 0; } static inline int tlv_int32(int32_t *var, vnode_tlv_t *tlv) { if (tlv->vallen != sizeof(int32_t)) { WARNX("invalid value length for int32: %u", tlv->vallen); return -1; } *var = *(int32_t *)tlv->val; return 0; } #endif /* _VNODE_TLV_H_ */ core-4.8/daemon/src/myerr.h0000664000175000017500000000316212534327775012622 00000000000000/* * CORE * Copyright (c)2010-2012 the Boeing Company. * See the LICENSE file included in this distribution. * * author: Tom Goff * * myerr.h * * Custom error printing macros. */ #ifndef _MYERR_H_ #define _MYERR_H_ #include #include #include #include #include #include #include static void __myerrprintf(const char *func, const char *file, const int line, FILE *stream, const char *fmt, ...) { extern const char *__progname; va_list ap; pid_t pid; struct timeval tv; va_start(ap, fmt); pid = getpid(); if (gettimeofday(&tv, NULL)) { fprintf(stream, "%s[%u]: %s[%s:%d]: ", __progname, pid, func, file, line); } else { char timestr[9]; strftime(timestr, sizeof(timestr), "%H:%M:%S", localtime(&tv.tv_sec)); fprintf(stream, "%s[%u]: %s.%06ld %s[%s:%d]: ", __progname, pid, timestr, tv.tv_usec, func, file, line); } vfprintf(stream, fmt, ap); fputs("\n", stream); va_end(ap); return; } #define INFO(fmt, args...) \ __myerrprintf(__func__, __FILE__, __LINE__, \ stdout, fmt, ##args) #define WARNX(fmt, args...) \ __myerrprintf(__func__, __FILE__, __LINE__, \ stderr, fmt, ##args) #define WARN(fmt, args...) \ __myerrprintf(__func__, __FILE__, __LINE__, \ stderr, fmt ": %s", ##args, strerror(errno)) #define ERRX(eval, fmt, args...) \ do { \ WARNX(fmt, ##args); \ exit(eval); \ } while (0) #define ERR(eval, fmt, args...) \ do { \ WARN(fmt, ##args); \ exit(eval); \ } while (0) #endif /* _MYERR_H_ */ core-4.8/daemon/src/vcmd_main.c0000664000175000017500000002161612534327775013420 00000000000000/* * CORE * Copyright (c)2010-2012 the Boeing Company. * See the LICENSE file included in this distribution. * * author: Tom Goff * * vcmd_main.c * * vcmd utility program for executing programs in an existing namespace * specified by the given channel. * */ #include #include #include #include #include #include #include #include #include #include #include "version.h" #include "vnode_chnl.h" #include "vnode_cmd.h" #include "vnode_client.h" #include "myerr.h" #define FORWARD_SIGNALS #define VCMD_DEFAULT_CMD "/bin/bash" int verbose; typedef struct { vnode_client_t *client; vnode_client_cmdio_t *cmdio; int argc; char **argv; int cmdid; int cmdstatus; ev_io stdin_watcher; int stdin_fwdfd; ev_io ptymaster_watcher; int ptymaster_fwdfd; } vcmd_t; static vcmd_t vcmd; static struct termios saveattr; static int saveattr_set; struct option longopts[] = { {"version", no_argument, NULL, 'V'}, {"help", no_argument, NULL, 'h'}, { 0 } }; void usage(int status, char *fmt, ...) { extern const char *__progname; va_list ap; FILE *output; va_start(ap, fmt); output = status ? stderr : stdout; fprintf(output, "\n"); if (fmt != NULL) { vfprintf(output, fmt, ap); fprintf(output, "\n\n"); } fprintf(output, "Usage: %s [-h|-V] [-v] [-q|-i|-I] -c -- command args" "...\n\n" "Run the specified command in the Linux namespace container " "specified by the \ncontrol , with the specified " "arguments.\n\nOptions:\n" " -h, --help show this help message and exit\n" " -V, --version show version number and exit\n" " -v enable verbose logging\n" " -q run the command quietly, without local input or output\n" " -i run the command interactively (use PTY)\n" " -I run the command non-interactively (without PTY)\n" " -c control channel name (e.g. '/tmp/pycore.45647/n3')\n", __progname); va_end(ap); exit(status); } static void vcmd_rwcb(struct ev_loop *loop, ev_io *w, int revents) { int outfd = *(int *)w->data; char buf[BUFSIZ]; ssize_t rcount, wcount; rcount = read(w->fd, buf, sizeof(buf)); if (rcount <= 0) { ev_io_stop(loop, w); } else { wcount = write(outfd, buf, rcount); if (wcount != rcount) WARN("write() error: wrote %d of %d bytes", wcount, rcount); } return; } static void vcmd_cmddonecb(int32_t cmdid, pid_t pid, int status, void *data) { vcmd_t *vcmd = data; if (vcmd->cmdio->iotype == VCMD_IO_PTY) { ev_io_stop(vcmd->client->loop, &vcmd->stdin_watcher); ev_io_stop(vcmd->client->loop, &vcmd->ptymaster_watcher); /* drain command output */ for (;;) { char buf[BUFSIZ]; ssize_t rcount, wcount; rcount = read(vcmd->ptymaster_watcher.fd, buf, sizeof(buf)); if (rcount <= 0) break; wcount = write(STDOUT_FILENO, buf, rcount); if (wcount != rcount) WARN("write() error: %d of %d bytes", wcount, rcount); } } vnode_close_clientcmdio(vcmd->cmdio); #ifdef DEBUG WARNX("cmdid %u; pid %d; status: 0x%x", cmdid, pid, status); #endif if (WIFEXITED(status)) /* normal terminataion */ vcmd->cmdstatus = WEXITSTATUS(status); else if (WIFSIGNALED(status)) { if (verbose) INFO("command %u terminated by signal: %d", cmdid, WTERMSIG(status)); vcmd->cmdstatus = 255; } else { INFO("unexpected termination status for command %u: 0x%x", cmdid, status); vcmd->cmdstatus = 255; } vcmd->cmdid = -1; ev_unloop(vcmd->client->loop, EVUNLOOP_ALL); return; } static void vcmd_cmdreqcb(struct ev_loop *loop, ev_timer *w, int revents) { vcmd_t *vcmd = w->data; #ifdef DEBUG WARNX("sending command request: serverfd %d; vcmd %p", vcmd->client->serverfd, vcmd); #endif if (vcmd->cmdio->iotype == VCMD_IO_PTY) { /* setup forwarding i/o */ vcmd->stdin_fwdfd = vcmd->cmdio->stdiopty.masterfd; vcmd->stdin_watcher.data = &vcmd->stdin_fwdfd; ev_io_init(&vcmd->stdin_watcher, vcmd_rwcb, STDIN_FILENO, EV_READ); ev_io_start(loop, &vcmd->stdin_watcher); vcmd->ptymaster_fwdfd = STDOUT_FILENO; vcmd->ptymaster_watcher.data = &vcmd->ptymaster_fwdfd; ev_io_init(&vcmd->ptymaster_watcher, vcmd_rwcb, vcmd->cmdio->stdiopty.masterfd, EV_READ); ev_io_start(loop, &vcmd->ptymaster_watcher); } vcmd->cmdid = vnode_client_cmdreq(vcmd->client, vcmd->cmdio, vcmd_cmddonecb, vcmd, vcmd->argc, vcmd->argv); if (vcmd->cmdid < 0) { WARNX("vnode_client_cmdreq() failed"); vnode_delclient(vcmd->client); vcmd->client = NULL; exit(255); } return; } static void vcmd_ioerrorcb(vnode_client_t *client) { vcmd_t *vcmd = client->data; WARNX("i/o error"); vnode_delclient(client); vcmd->client = NULL; exit(1); return; } #ifdef FORWARD_SIGNALS static void sighandler(int signum) { if (!vcmd.client || vcmd.cmdid < 0) return; #ifdef DEBUG WARNX("sending command signal: serverfd %d; cmdid %u; signum: %d", vcmd.client->serverfd, vcmd.cmdid, signum); #endif if (vnode_send_cmdsignal(vcmd.client->serverfd, vcmd.cmdid, signum)) WARN("vnode_send_cmdsignal() failed"); return; } #endif /* FORWARD_SIGNALS */ static void sigwinch_handler(int signum) { struct winsize wsiz; if (signum != SIGWINCH) { WARNX("unexpected signal number: %d", signum); return; } if (!vcmd.cmdio || vcmd.cmdio->iotype != VCMD_IO_PTY) return; if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &wsiz)) { WARN("ioctl() failed"); return; } if (ioctl(vcmd.cmdio->stdiopty.masterfd, TIOCSWINSZ, &wsiz)) WARN("ioctl() failed"); return; } static int termioraw(int fd, struct termios *saveattr) { int err; struct termios raw = {}; err = tcgetattr(fd, saveattr); if (err) { WARN("tcgetattr() failed"); return err; } cfmakeraw(&raw); err = tcsetattr(fd, TCSADRAIN, &raw); if (err) { WARN("tcsetattr() failed"); return err; } return 0; } static void cleanup(void) { if (saveattr_set) if (tcsetattr(STDOUT_FILENO, TCSADRAIN, &saveattr)) WARN("tcsetattr() failed"); return; } int main(int argc, char *argv[]) { char *ctrlchnlname = NULL; vnode_client_cmdiotype_t iotype = VCMD_IO_FD; ev_timer cmdreq; extern const char *__progname; #ifdef FORWARD_SIGNALS int i; struct sigaction sig_action = { .sa_handler = sighandler, }; #endif /* FORWARD_SIGNALS */ char *def_argv[2] = { VCMD_DEFAULT_CMD, 0 }; if (isatty(STDIN_FILENO) && isatty(STDOUT_FILENO) && isatty(STDERR_FILENO) && getpgrp() == tcgetpgrp(STDOUT_FILENO)) iotype = VCMD_IO_PTY; /* Parse command line argument list */ for (;;) { int opt; if ((opt = getopt_long(argc, argv, "c:hiIqvV", longopts, NULL)) == -1) break; switch (opt) { case 'c': ctrlchnlname = optarg; break; case 'i': iotype = VCMD_IO_PTY; break; case 'I': iotype = VCMD_IO_FD; break; case 'q': iotype = VCMD_IO_NONE; break; case 'v': verbose++; break; case 'V': printf("%s version %s\n", __progname, CORE_VERSION); exit(0); case 'h': /* pass through */ default: usage(0, NULL); } } argc -= optind; argv += optind; if (ctrlchnlname == NULL) usage(1, "no control channel name given"); if (!argc) { argc = 1; argv = def_argv; } if (argc >= VNODE_ARGMAX) usage(1, "too many command arguments"); if (atexit(cleanup)) ERR(1, "atexit() failed"); #ifdef FORWARD_SIGNALS for (i = 1; i < _NSIG; i++) if (sigaction(i, &sig_action, NULL)) if (verbose && i != SIGKILL && i != SIGSTOP) WARN("sigaction() failed for %d", i); #endif /* FORWARD_SIGNALS */ vcmd.cmdio = vnode_open_clientcmdio(iotype); if (!vcmd.cmdio) ERR(1, "vnode_open_clientcmdio() failed"); vcmd.argc = argc; vcmd.argv = argv; vcmd.cmdstatus = 255; switch (vcmd.cmdio->iotype) { case VCMD_IO_NONE: break; case VCMD_IO_FD: SET_STDIOFD(vcmd.cmdio, STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO); break; case VCMD_IO_PTY: { struct sigaction sigwinch_action = { .sa_handler = sigwinch_handler, }; if (sigaction(SIGWINCH, &sigwinch_action, NULL)) WARN("sigaction() failed for SIGWINCH"); sigwinch_handler(SIGWINCH); if (termioraw(STDOUT_FILENO, &saveattr)) WARNX("termioraw() failed"); else saveattr_set = 1; } break; default: ERR(1, "unsupported i/o type: %u", vcmd.cmdio->iotype); break; } vcmd.client = vnode_client(ev_default_loop(0), ctrlchnlname, vcmd_ioerrorcb, &vcmd); if (!vcmd.client) ERR(1, "vnode_client() failed"); cmdreq.data = &vcmd; ev_timer_init(&cmdreq, vcmd_cmdreqcb, 0, 0); ev_timer_start(vcmd.client->loop, &cmdreq); ev_loop(vcmd.client->loop, 0); vnode_delclient(vcmd.client); exit(vcmd.cmdstatus); } core-4.8/daemon/src/vnode_client.c0000664000175000017500000002357512534327775014142 00000000000000/* * CORE * Copyright (c)2010-2012 the Boeing Company. * See the LICENSE file included in this distribution. * * author: Tom Goff * * vnode_client.c * * * */ #include #include #include #include #include #include "vnode_chnl.h" #include "vnode_client.h" #include "vnode_tlv.h" #include "vnode_io.h" extern int verbose; typedef struct { vnode_client_cmddonecb_t cmddonecb; void *data; } vnode_clientcmd_t; vnode_client_cmdio_t *vnode_open_clientcmdio(vnode_client_cmdiotype_t iotype) { int err; vnode_client_cmdio_t *clientcmdio; clientcmdio = malloc(sizeof(*clientcmdio)); if (!clientcmdio) { WARN("malloc() failed"); return NULL; } clientcmdio->iotype = iotype; switch (clientcmdio->iotype) { case VCMD_IO_NONE: case VCMD_IO_FD: err = 0; break; case VCMD_IO_PIPE: err = open_stdio_pipe(&clientcmdio->stdiopipe); break; case VCMD_IO_PTY: err = open_stdio_pty(&clientcmdio->stdiopty); break; default: WARNX("unknown i/o type: %u", clientcmdio->iotype); err = -1; break; } if (err) { free(clientcmdio); clientcmdio = NULL; } return clientcmdio; } void vnode_close_clientcmdio(vnode_client_cmdio_t *clientcmdio) { switch (clientcmdio->iotype) { case VCMD_IO_NONE: case VCMD_IO_FD: break; case VCMD_IO_PIPE: close_stdio_pipe(&clientcmdio->stdiopipe); break; case VCMD_IO_PTY: close_stdio_pty(&clientcmdio->stdiopty); break; default: WARNX("unknown i/o type: %u", clientcmdio->iotype); break; } memset(clientcmdio, 0, sizeof(*clientcmdio)); free(clientcmdio); return; } static void vnode_client_cmddone(vnode_cmdentry_t *cmd) { vnode_clientcmd_t *clientcmd = cmd->data;; if (clientcmd->cmddonecb) clientcmd->cmddonecb(cmd->cmdid, cmd->pid, cmd->status, clientcmd->data); memset(clientcmd, 0, sizeof(*clientcmd)); free(clientcmd); memset(cmd, 0, sizeof(*cmd)); free(cmd); return; } static int tlv_cmdreqack_cmdid(vnode_tlv_t *tlv, void *data) { vnode_cmdreqack_t *cmdreqack = data; int tmp; assert(tlv->type == VNODE_TLV_CMDID); tmp = tlv_int32(&cmdreqack->cmdid, tlv); if (tmp == 0 && verbose) INFO("VNODE_TLV_CMDID: %d", cmdreqack->cmdid); return tmp; } static int tlv_cmdreqack_cmdpid(vnode_tlv_t *tlv, void *data) { vnode_cmdreqack_t *cmdreqack = data; int tmp; assert(tlv->type == VNODE_TLV_CMDPID); tmp = tlv_int32(&cmdreqack->pid, tlv); if (tmp == 0 && verbose) INFO("VNODE_TLV_CMDPID: %d", cmdreqack->pid); return tmp; } static void vnode_clientrecv_cmdreqack(vnode_msgio_t *msgio) { vnode_cmdentry_t *cmd; vnode_client_t *client = msgio->data; vnode_cmdreqack_t cmdreqack = CMDREQACK_INIT; static const vnode_tlvhandler_t tlvhandler[VNODE_TLV_MAX] = { [VNODE_TLV_CMDID] = tlv_cmdreqack_cmdid, [VNODE_TLV_CMDPID] = tlv_cmdreqack_cmdpid, }; #ifdef DEBUG WARNX("command request ack"); #endif assert(msgio->msgbuf.msg->hdr.type == VNODE_MSG_CMDREQACK); if (vnode_parsemsg(msgio->msgbuf.msg, &cmdreqack, tlvhandler)) return; TAILQ_FOREACH(cmd, &client->cmdlisthead, entries) if (cmd->cmdid == cmdreqack.cmdid) break; if (cmd == NULL) { WARNX("cmdid %d not found in command list", cmdreqack.cmdid); return; } #ifdef DEBUG WARNX("cmdid %d found in cmd list", cmdreqack.cmdid); #endif cmd->pid = cmdreqack.pid; if (cmdreqack.pid == -1) { #ifdef DEBUG WARNX("XXX pid == -1 removing cmd from list"); #endif TAILQ_REMOVE(&client->cmdlisthead, cmd, entries); cmd->status = -1; vnode_client_cmddone(cmd); return; } return; } static int tlv_cmdstatus_cmdid(vnode_tlv_t *tlv, void *data) { vnode_cmdstatus_t *cmdstatus = data; int tmp; assert(tlv->type == VNODE_TLV_CMDID); tmp = tlv_int32(&cmdstatus->cmdid, tlv); if (tmp == 0 && verbose) INFO("VNODE_TLV_CMDID: %d", cmdstatus->cmdid); return tmp; } static int tlv_cmdstatus_status(vnode_tlv_t *tlv, void *data) { vnode_cmdstatus_t *cmdstatus = data; int tmp; assert(tlv->type == VNODE_TLV_CMDSTATUS); tmp = tlv_int32(&cmdstatus->status, tlv); if (tmp == 0 && verbose) INFO("VNODE_TLV_CMDSTATUS: %d", cmdstatus->status); return tmp; } static void vnode_clientrecv_cmdstatus(vnode_msgio_t *msgio) { vnode_cmdentry_t *cmd; vnode_client_t *client = msgio->data; vnode_cmdstatus_t cmdstatus = CMDSTATUS_INIT; static const vnode_tlvhandler_t tlvhandler[VNODE_TLV_MAX] = { [VNODE_TLV_CMDID] = tlv_cmdstatus_cmdid, [VNODE_TLV_CMDSTATUS] = tlv_cmdstatus_status, }; #ifdef DEBUG WARNX("command status"); #endif assert(msgio->msgbuf.msg->hdr.type == VNODE_MSG_CMDSTATUS); if (vnode_parsemsg(msgio->msgbuf.msg, &cmdstatus, tlvhandler)) return; TAILQ_FOREACH(cmd, &client->cmdlisthead, entries) if (cmd->cmdid == cmdstatus.cmdid) break; if (cmd == NULL) { WARNX("cmdid %d not found in command list", cmdstatus.cmdid); return; } #ifdef DEBUG WARNX("cmdid %d found in cmd list; removing", cmdstatus.cmdid); #endif TAILQ_REMOVE(&client->cmdlisthead, cmd, entries); cmd->status = cmdstatus.status; vnode_client_cmddone(cmd); return; } static void server_ioerror(vnode_msgio_t *msgio) { vnode_client_t *client = msgio->data; #ifdef DEBUG WARNX("i/o error on fd %d; client: %p", msgio->fd, client); #endif if (client) { assert(msgio == &client->msgio); if (client->ioerrorcb) client->ioerrorcb(client); } return; } vnode_client_t *vnode_client(struct ev_loop *loop, const char *ctrlchnlname, vnode_clientcb_t ioerrorcb, void *data) { int fd = -1; vnode_client_t *client; static const vnode_msghandler_t msghandler[VNODE_MSG_MAX] = { [VNODE_MSG_CMDREQACK] = vnode_clientrecv_cmdreqack, [VNODE_MSG_CMDSTATUS] = vnode_clientrecv_cmdstatus, }; if (!ioerrorcb) { WARNX("no i/o error callback given"); return NULL; } fd = vnode_connect(ctrlchnlname); if (fd < 0) { WARN("vnode_connect() failed for '%s'", ctrlchnlname); return NULL; } if ((client = calloc(1, sizeof(*client))) == NULL) { WARN("calloc() failed"); close(fd); return NULL; } TAILQ_INIT(&client->cmdlisthead); client->loop = loop; client->serverfd = fd; client->ioerrorcb = ioerrorcb; client->data = data; if (vnode_msgiostart(&client->msgio, client->loop, client->serverfd, client, server_ioerror, msghandler)) { WARNX("vnode_msgiostart() failed"); close(fd); return NULL; } #ifdef DEBUG WARNX("new client connected to %s: %p", ctrlchnlname, client); #endif return client; } void vnode_delclient(vnode_client_t *client) { #ifdef DEBUG WARNX("deleting client: %p", client); #endif vnode_msgiostop(&client->msgio); if (client->serverfd >= 0) { close(client->serverfd); client->serverfd = -1; } while (!TAILQ_EMPTY(&client->cmdlisthead)) { vnode_cmdentry_t *cmd; cmd = TAILQ_FIRST(&client->cmdlisthead); TAILQ_REMOVE(&client->cmdlisthead, cmd, entries); cmd->status = -1; vnode_client_cmddone(cmd); } /* XXX more stuff ?? */ memset(client, 0, sizeof(*client)); free(client); return; } static int vnode_setcmdio(int *cmdin, int *cmdout, int *cmderr, vnode_client_cmdio_t *clientcmdio) { switch (clientcmdio->iotype) { case VCMD_IO_NONE: *cmdin = -1; *cmdout = -1; *cmderr = -1; break; case VCMD_IO_FD: *cmdin = clientcmdio->stdiofd.infd; *cmdout = clientcmdio->stdiofd.outfd; *cmderr = clientcmdio->stdiofd.errfd; break; case VCMD_IO_PIPE: *cmdin = clientcmdio->stdiopipe.infd[0]; *cmdout = clientcmdio->stdiopipe.outfd[1]; *cmderr = clientcmdio->stdiopipe.errfd[1]; break; case VCMD_IO_PTY: *cmdin = clientcmdio->stdiopty.slavefd; *cmdout = clientcmdio->stdiopty.slavefd; *cmderr = clientcmdio->stdiopty.slavefd; break; default: WARNX("unknown i/o type: %u", clientcmdio->iotype); return -1; } return 0; } static void vnode_cleanupcmdio(vnode_client_cmdio_t *clientcmdio) { #define CLOSE(var) \ do { \ if (var >= 0) \ close(var); \ var = -1; \ } while (0) switch (clientcmdio->iotype) { case VCMD_IO_NONE: case VCMD_IO_FD: break; case VCMD_IO_PIPE: CLOSE(clientcmdio->stdiopipe.infd[0]); CLOSE(clientcmdio->stdiopipe.outfd[1]); CLOSE(clientcmdio->stdiopipe.errfd[1]); break; case VCMD_IO_PTY: CLOSE(clientcmdio->stdiopty.slavefd); break; default: WARNX("unknown i/o type: %u", clientcmdio->iotype); break; } #undef CLOSE return; } int vnode_client_cmdreq(vnode_client_t *client, vnode_client_cmdio_t *clientcmdio, vnode_client_cmddonecb_t cmddonecb, void *data, int argc, char *argv[]) { int cmdin, cmdout, cmderr; vnode_clientcmd_t *clientcmd; vnode_cmdentry_t *cmd; if (argc >= VNODE_ARGMAX) { WARNX("too many command arguments"); return -1; } if (argv[argc] != NULL) { WARNX("command arguments not null-terminated"); return -1; } if (vnode_setcmdio(&cmdin, &cmdout, &cmderr, clientcmdio)) { WARNX("vnode_setcmdio() failed"); return -1; } if ((clientcmd = malloc(sizeof(*clientcmd))) == NULL) { WARN("malloc() failed"); return -1; } clientcmd->cmddonecb = cmddonecb; clientcmd->data = data; if ((cmd = malloc(sizeof(*cmd))) == NULL) { WARN("malloc() failed"); free(clientcmd); return -1; } if (client->cmdid < 0) client->cmdid = 0; cmd->cmdid = client->cmdid++; cmd->pid = -1; cmd->status = -1; cmd->data = clientcmd; TAILQ_INSERT_TAIL(&client->cmdlisthead, cmd, entries); if (vnode_send_cmdreq(client->serverfd, cmd->cmdid, argv, cmdin, cmdout, cmderr)) { WARN("vnode_send_cmdreq() failed"); TAILQ_REMOVE(&client->cmdlisthead, cmd, entries); free(clientcmd); free(cmd); return -1; } vnode_cleanupcmdio(clientcmdio); return cmd->cmdid; } core-4.8/daemon/src/vnode_client.h0000664000175000017500000000340312534327775014133 00000000000000/* * CORE * Copyright (c)2010-2012 the Boeing Company. * See the LICENSE file included in this distribution. * * author: Tom Goff * * vnode_client.h * */ #ifndef _VNODE_CLIENT_H_ #define _VNODE_CLIENT_H_ #include #include #include "vnode_msg.h" #include "vnode_cmd.h" #include "vnode_io.h" struct vnode_client; typedef void (*vnode_clientcb_t)(struct vnode_client *client); typedef struct vnode_client { TAILQ_HEAD(cmdlist, cmdentry) cmdlisthead; struct ev_loop *loop; int serverfd; struct vnode_msgio msgio; void *data; vnode_clientcb_t ioerrorcb; int32_t cmdid; } vnode_client_t; typedef void (*vnode_client_cmddonecb_t)(int32_t cmdid, pid_t pid, int status, void *data); typedef enum { VCMD_IO_NONE = 0, VCMD_IO_FD, VCMD_IO_PIPE, VCMD_IO_PTY, } vnode_client_cmdiotype_t; typedef struct { vnode_client_cmdiotype_t iotype; union { stdio_fd_t stdiofd; stdio_pipe_t stdiopipe; stdio_pty_t stdiopty; }; } vnode_client_cmdio_t; #define SET_STDIOFD(clcmdio, ifd, ofd, efd) \ do { \ (clcmdio)->iotype = VCMD_IO_FD; \ (clcmdio)->stdiofd.infd = (ifd); \ (clcmdio)->stdiofd.outfd = (ofd); \ (clcmdio)->stdiofd.errfd = (efd); \ } while (0) vnode_client_t *vnode_client(struct ev_loop *loop, const char *ctrlchnlname, vnode_clientcb_t ioerrorcb, void *data); void vnode_delclient(vnode_client_t *client); vnode_client_cmdio_t *vnode_open_clientcmdio(vnode_client_cmdiotype_t iotype); void vnode_close_clientcmdio(vnode_client_cmdio_t *clientcmdio); int vnode_client_cmdreq(vnode_client_t *client, vnode_client_cmdio_t *clientcmdio, vnode_client_cmddonecb_t cmddonecb, void *data, int argc, char *argv[]); #endif /* _VNODE_CLIENT_H_ */ core-4.8/daemon/src/vnoded_main.c0000664000175000017500000001077312534327775013750 00000000000000/* * CORE * Copyright (c)2010-2012 the Boeing Company. * See the LICENSE file included in this distribution. * * author: Tom Goff * * vnoded_main.c * * vnoded daemon runs as PID 1 in the Linux namespace container and receives * and executes commands via a control channel. * */ #include #include #include #include #include #include #include "version.h" #include "vnode_server.h" #include "myerr.h" int verbose; static vnode_server_t *vnodeserver; struct option longopts[] = { {"version", no_argument, NULL, 'V'}, {"help", no_argument, NULL, 'h'}, { 0 } }; static void usage(int status, char *fmt, ...) { extern const char *__progname; va_list ap; FILE *output; va_start(ap, fmt); output = status ? stderr : stdout; fprintf(output, "\n"); if (fmt != NULL) { vfprintf(output, fmt, ap); fprintf(output, "\n\n"); } fprintf(output, "Usage: %s [-h|-V] [-v] [-n] [-C ] [-l ] " "[-p ] -c \n\n" "Linux namespace container server daemon runs as PID 1 in the " "container. \nNormally this process is launched automatically by the " "CORE daemon.\n\nOptions:\n" " -h, --help show this help message and exit\n" " -V, --version show version number and exit\n" " -v enable verbose logging\n" " -n do not create and run daemon within a new network namespace " "(for debug)\n" " -C change to the specified directory\n" " -l log output to the specified file\n" " -p write process id to the specified file\n" " -c establish the specified for receiving " "control commands\n", __progname); va_end(ap); exit(0); } static void sigexit(int signum) { WARNX("exiting due to signal: %d", signum); exit(0); return; } static void cleanup_sigchld(int signum) { /* nothing */ } static void cleanup() { static int incleanup = 0; if (incleanup) return; incleanup = 1; if (vnodeserver) { struct ev_loop *loop = vnodeserver->loop; vnode_delserver(vnodeserver); if (loop) ev_unloop(loop, EVUNLOOP_ALL); } /* don't use SIG_IGN here because receiving SIGCHLD is needed to * interrupt the sleep below in order to avoid long delays */ if (signal(SIGCHLD, cleanup_sigchld) == SIG_ERR) WARN("signal() failed"); if (getpid() == 1) { struct timespec delay = { .tv_sec = 2, .tv_nsec = 0, }; /* try to gracefully terminate all processes in this namespace * first */ kill(-1, SIGTERM); /* wait for child processes to terminate */ for (;;) { pid_t pid; int err; struct timespec rem; pid = waitpid(-1, NULL, WNOHANG); if (pid == -1) break; /* an error occurred */ if (pid != 0) continue; /* a child was reaped */ err = nanosleep(&delay, &rem); if (err == -1 && errno == EINTR) { delay = rem; continue; } /* force termination after delay */ kill(-1, SIGKILL); break; } } return; } int main(int argc, char *argv[]) { int newnetns = 1; char *ctrlchnlname = NULL, *logfilename = NULL, *chdirname = NULL; char *pidfilename = NULL; extern const char *__progname; for (;;) { int opt; if ((opt = getopt_long(argc, argv, "c:C:l:nvVhp:", longopts, NULL)) == -1) break; switch (opt) { case 'c': ctrlchnlname = optarg; break; case 'C': chdirname = optarg; break; case 'l': logfilename = optarg; break; case 'n': newnetns = 0; break; case 'p': pidfilename = optarg; break; case 'v': verbose++; break; case 'V': printf("%s version %s\n", __progname, CORE_VERSION); exit(0); case 'h': /* pass through */ default: usage(0, NULL); } } argc -= optind; argv += optind; if (ctrlchnlname == NULL) usage(1, "no control channel given"); for (; argc; argc--, argv++) WARNX("ignoring command line argument: '%s'", *argv); if (atexit(cleanup)) ERR(1, "atexit() failed"); if (signal(SIGTERM, sigexit) == SIG_ERR) ERR(1, "signal() failed"); if (signal(SIGINT, sigexit) == SIG_ERR) ERR(1, "signal() failed"); /* XXX others? */ vnodeserver = vnoded(newnetns, ctrlchnlname, logfilename, pidfilename, chdirname); if (vnodeserver == NULL) ERRX(1, "vnoded() failed"); ev_loop(vnodeserver->loop, 0); exit(0); } core-4.8/daemon/src/vnode_server.c0000664000175000017500000002027512534327775014164 00000000000000/* * CORE * Copyright (c)2010-2012 the Boeing Company. * See the LICENSE file included in this distribution. * * author: Tom Goff * * vnode_server.c * */ #include #include #include #include #include #include #include #include #include #include "netns.h" #include "myerr.h" #include "vnode_msg.h" #include "vnode_chnl.h" #include "vnode_cmd.h" #include "vnode_server.h" extern int verbose; static vnode_cliententry_t *vnode_server_newclient(vnode_server_t *server, int fd); static void vnode_server_delclient(vnode_cliententry_t *client); static int cloexec(int fd) { int fdflags; if ((fdflags = fcntl(fd, F_GETFD)) == -1) fdflags = 0; if (fcntl(fd, F_SETFD, fdflags | FD_CLOEXEC) == -1) return -1; return 0; } static void client_ioerror(vnode_msgio_t *msgio) { vnode_cliententry_t *client = msgio->data; if (verbose) INFO("i/o error for client fd %d; deleting client", client->msgio.fd); vnode_server_delclient(client); return; } static vnode_cliententry_t *vnode_server_newclient(vnode_server_t *server, int fd) { vnode_cliententry_t *client; vnode_msghandler_t msghandler[VNODE_MSG_MAX] = { [VNODE_MSG_CMDREQ] = vnode_recv_cmdreq, [VNODE_MSG_CMDSIGNAL] = vnode_recv_cmdsignal, }; #ifdef DEBUG WARNX("new client on fd %d", fd); #endif cloexec(fd); if ((client = malloc(sizeof(*client))) == NULL) { WARN("malloc() failed"); return NULL; } client->server = server; client->clientfd = fd; TAILQ_INSERT_TAIL(&server->clientlisthead, client, entries); if (vnode_msgiostart(&client->msgio, server->loop, client->clientfd, client, client_ioerror, msghandler)) { WARNX("vnode_msgiostart() failed"); free(client); return NULL; } return client; } static void vnode_server_delclient(vnode_cliententry_t *client) { #ifdef DEBUG WARNX("deleting client for fds %d %d", client->clientfd, client->msgio.fd); #endif TAILQ_REMOVE(&client->server->clientlisthead, client, entries); vnode_msgiostop(&client->msgio); close(client->clientfd); memset(client, 0, sizeof(*client)); free(client); return; } /* XXX put this in vnode_cmd.c ?? */ static void vnode_child_cb(struct ev_loop *loop, ev_child *w, int revents) { vnode_server_t *server = w->data; vnode_cmdentry_t *cmd; char *how; int status; #ifdef DEBUG WARNX("child process %d exited with status 0x%x", w->rpid, w->rstatus); if (WIFEXITED(w->rstatus)) WARNX("normal terminataion status: %d", WEXITSTATUS(w->rstatus)); else if (WIFSIGNALED(w->rstatus)) WARNX("terminated by signal: %d", WTERMSIG(w->rstatus)); else WARNX("unexpected status: %d", w->rstatus); #endif if (WIFEXITED(w->rstatus)) { how = "normally"; status = WEXITSTATUS(w->rstatus); } else if (WIFSIGNALED(w->rstatus)) { how = "due to signal"; status = WTERMSIG(w->rstatus); } else { how = "for unknown reason"; status = w->rstatus; } TAILQ_FOREACH(cmd, &server->cmdlisthead, entries) { if (cmd->pid == w->rpid) { vnode_cliententry_t *client = cmd->data; #ifdef DEBUG WARNX("pid %d found in cmd list; removing", w->rpid); #endif TAILQ_REMOVE(&server->cmdlisthead, cmd, entries); if (verbose) INFO("cmd completed %s: pid: %d; cmdid: %d; status %d", how, w->rpid, cmd->cmdid, status); if (vnode_send_cmdstatus(client->clientfd, cmd->cmdid, w->rstatus)) WARNX("vnode_send_cmdstatus() failed"); free(cmd); return; } } WARNX("pid %d not found in client command list: " "completed %s with status %d", w->rpid, how, status); return; } static void vnode_server_cb(struct ev_loop *loop, ev_io *w, int revents) { vnode_server_t *server = w->data; int fd; for (;;) { fd = accept(server->serverfd, NULL, NULL); if (fd < 0) { if (errno != EAGAIN) WARN("accept() failed"); break; } if (vnode_server_newclient(server, fd) == NULL) { WARN("vnode_server_newclient() failed"); close(fd); } } return; } static vnode_server_t *vnode_newserver(struct ev_loop *loop, int ctrlfd, const char *ctrlchnlname) { vnode_server_t *server; if ((server = malloc(sizeof(*server))) == NULL) { WARN("malloc() failed"); return NULL; } TAILQ_INIT(&server->clientlisthead); TAILQ_INIT(&server->cmdlisthead); server->loop = loop; strncpy(server->ctrlchnlname, ctrlchnlname, sizeof(server->ctrlchnlname)); server->ctrlchnlname[sizeof(server->ctrlchnlname) -1] = '\0'; memset(server->pidfilename, 0, sizeof(server->pidfilename)); server->serverfd = ctrlfd; #ifdef DEBUG WARNX("adding vnode_child_cb for pid 0"); #endif server->childwatcher.data = server; ev_child_init(&server->childwatcher, vnode_child_cb, 0, 0); ev_child_start(server->loop, &server->childwatcher); #ifdef DEBUG WARNX("adding vnode_server_cb for fd %d", server->serverfd); #endif server->fdwatcher.data = server; ev_io_init(&server->fdwatcher, vnode_server_cb, server->serverfd, EV_READ); ev_io_start(server->loop, &server->fdwatcher); return server; } void vnode_delserver(vnode_server_t *server) { unlink(server->ctrlchnlname); if (server->pidfilename[0] != '\0') { unlink(server->pidfilename); } ev_io_stop(server->loop, &server->fdwatcher); close(server->serverfd); ev_child_stop(server->loop, &server->childwatcher); while (!TAILQ_EMPTY(&server->clientlisthead)) { vnode_cliententry_t *client; client = TAILQ_FIRST(&server->clientlisthead); TAILQ_REMOVE(&server->clientlisthead, client, entries); vnode_server_delclient(client); } while (!TAILQ_EMPTY(&server->cmdlisthead)) { vnode_cmdentry_t *cmd; cmd = TAILQ_FIRST(&server->cmdlisthead); TAILQ_REMOVE(&server->cmdlisthead, cmd, entries); free(cmd); } memset(server, 0, sizeof(*server)); free(server); return; } vnode_server_t *vnoded(int newnetns, const char *ctrlchnlname, const char *logfilename, const char *pidfilename, const char *chdirname) { int ctrlfd; unsigned int i; long openmax; vnode_server_t *server; pid_t pid; setsid(); if ((ctrlfd = vnode_listen(ctrlchnlname)) < 0) { WARNX("vnode_listen() failed for '%s'", ctrlchnlname); return NULL; } cloexec(ctrlfd); if (newnetns) { pid = nsfork(0); if (pid == -1) { WARN("nsfork() failed"); close(ctrlfd); unlink(ctrlchnlname); return NULL; } } else { pid = getpid(); } if (pid) { printf("%u\n", pid); fflush(stdout); if (pidfilename) { FILE *pidfile; pidfile = fopen(pidfilename, "w"); if (pidfile != NULL) { fprintf(pidfile, "%u\n", pid); fclose(pidfile); } else { WARN("fopen() failed for '%s'", pidfilename); } } if (newnetns) _exit(0); /* nothing else for the parent to do */ } /* try to close any open files */ if ((openmax = sysconf(_SC_OPEN_MAX)) < 0) openmax = 1024; assert(openmax >= _POSIX_OPEN_MAX); for (i = 3; i < openmax; i++) if (i != ctrlfd) close(i); if (!logfilename) logfilename = "/dev/null"; #define DUPFILE(filename, mode, fileno) \ do { \ int fd; \ if ((fd = open(filename, mode, 0644)) == -1) \ WARN("open() failed for '%s'", filename); \ else \ { \ if (dup2(fd, fileno) == -1) \ WARN("dup2() failed for " #fileno); \ close(fd); \ } \ } while (0); DUPFILE("/dev/null", O_RDONLY, STDIN_FILENO); DUPFILE(logfilename, O_WRONLY | O_CREAT | O_TRUNC | O_APPEND, STDOUT_FILENO); DUPFILE(logfilename, O_WRONLY | O_CREAT | O_TRUNC | O_APPEND, STDERR_FILENO); #undef DUPFILE setvbuf(stdout, NULL, _IOLBF, 0); setvbuf(stderr, NULL, _IOLBF, 0); if (chdirname && chdir(chdirname)) WARN("chdir() failed"); server = vnode_newserver(ev_default_loop(0), ctrlfd, ctrlchnlname); if (!server) { close(ctrlfd); unlink(ctrlchnlname); } if (pidfilename) { strncpy(server->pidfilename, pidfilename, sizeof(server->pidfilename)); server->pidfilename[sizeof(server->pidfilename) -1] = '\0'; } return server; } core-4.8/daemon/src/vnode_server.h0000664000175000017500000000173712534327775014173 00000000000000/* * CORE * Copyright (c)2010-2012 the Boeing Company. * See the LICENSE file included in this distribution. * * author: Tom Goff * * vnode_server.h * */ #ifndef _VNODE_SERVER_H_ #define _VNODE_SERVER_H_ #include #include #include #include "vnode_msg.h" typedef struct { TAILQ_HEAD(clientlist, cliententry) clientlisthead; TAILQ_HEAD(cmdlist, cmdentry) cmdlisthead; struct ev_loop *loop; char ctrlchnlname[PATH_MAX]; char pidfilename[PATH_MAX]; int serverfd; ev_io fdwatcher; ev_child childwatcher; } vnode_server_t; typedef struct cliententry { TAILQ_ENTRY(cliententry) entries; vnode_server_t *server; int clientfd; vnode_msgio_t msgio; } vnode_cliententry_t; vnode_server_t *vnoded(int newnetns, const char *ctrlchnlname, const char *logfilename, const char *pidfilename, const char *chdirname); void vnode_delserver(vnode_server_t *server); #endif /* _VNODE_SERVER_H_ */ core-4.8/daemon/src/setup.py0000664000175000017500000000217412534327775013027 00000000000000# Copyright (c)2010-2012 the Boeing Company. # See the LICENSE file included in this distribution. import os, glob from distutils.core import setup, Extension netns = Extension("netns", sources = ["netnsmodule.c", "netns.c"]) vcmd = Extension("vcmd", sources = ["vcmdmodule.c", "vnode_client.c", "vnode_chnl.c", "vnode_io.c", "vnode_msg.c", "vnode_cmd.c", ], library_dirs = ["build/lib"], libraries = ["ev"]) setup(name = "core-python-netns", version = "1.0", description = "Extension modules to support virtual nodes using " \ "Linux network namespaces", ext_modules = [netns, vcmd], url = "http://www.nrl.navy.mil/itd/ncs/products/core", author = "Boeing Research & Technology", author_email = "core-dev@pf.itd.nrl.navy.mil", license = "BSD", long_description="Extension modules and utilities to support virtual " \ "nodes using Linux network namespaces") core-4.8/daemon/src/MANIFEST.in0000664000175000017500000000003312534327775013043 00000000000000include *.h include sbin/* core-4.8/packaging/0000775000175000017500000000000012534330006011240 500000000000000core-4.8/packaging/deb/0000775000175000017500000000000012534330006011772 500000000000000core-4.8/packaging/deb/core-daemon.install.in0000664000175000017500000000137712534327775016133 00000000000000#! /usr/bin/dh-exec @SBINDIR@ @CORE_CONF_DIR@ # configure prints a warning if CORE_DATA_DIR is used here # ATdatarootdirAT is expanding to ${datarootdir}/man/man1/ /usr/share/core/examples/corens3 /usr/share/core/examples/*.py /usr/share/core/examples/hooks /usr/share/core/examples/myservices /usr/share/core/examples/netns /usr/share/core/examples/services # ATmandirAT is expanding to ${datarootdir}/man/man1/core-daemon.1 /usr/share/man/man1/vnoded.1 /usr/share/man/man1/vcmd.1 /usr/share/man/man1/netns.1 /usr/share/man/man1/core-daemon.1 /usr/share/man/man1/coresendmsg.1 /usr/share/man/man1/core-cleanup.1 /usr/share/man/man1/core-xen-cleanup.1 # ATpythondirAT is expanding to ${prefix}/lib/python2.7/dist-packages /usr/lib/python2.7/dist-packages /etc/init.d core-4.8/packaging/deb/core-gui.install.in0000664000175000017500000000055412534327775015450 00000000000000#! /usr/bin/dh-exec @BINDIR@/core-gui @CORE_LIB_DIR@ # configure prints a warning if CORE_DATA_DIR is used here # ATdatarootdirAT is expanding to ${datarootdir}/man/man1/ /usr/share/core/icons /usr/share/core/examples/configs /usr/share/pixmaps /usr/share/applications # ATmandirAT is expanding to ${datarootdir}/man/man1/core-gui.1 /usr/share/man/man1/core-gui.1 core-4.8/packaging/deb/compat0000664000175000017500000000000212534327775013133 000000000000009 core-4.8/packaging/deb/copyright0000664000175000017500000000311312534327775013666 00000000000000This package was debianized by Jeff Ahrenholz 4/3/13 It was downloaded from: http://www.nrl.navy.mil/itd/ncs/products/core Upstream Author(s): Jeff Ahrenholz Copyright: Copyright (C) 2010-2013, the Boeing Company. License: Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE 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 OWNER 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. Packaging: Copyright (C) 2010-2013, the Boeing Company. core-4.8/packaging/deb/changelog0000664000175000017500000000371612534327775013616 00000000000000core (4.8-0ubuntu1) precise; urgency=low * Support for NRL Network Modeling Framework (NMF) XML representation, bugfixes -- CORE Developers Fri, 05 Jun 2015 00:00:00 -0700 core (4.7-0ubuntu1) precise; urgency=low * EMANE 0.9.1, asymmetric links, bugfixes -- Jeff Ahrenholz Wed, 08 Aug 2014 08:27:18 -0700 core (4.6-0ubuntu1) precise; urgency=low * Edit Copy and Paste, Edit Find, bugfixes, Debian compliance -- Jeff Ahrenholz Wed, 25 Sep 2013 12:36:54 -0700 core (4.5-0ubuntu1) precise; urgency=low * XML support, SDT3D support, EMANE 0.8.1, ns-3 locations, code cleanup, bugfixes, and more. -- Jeff Ahrenholz Thu, 11 Apr 2013 14:19:05 -0700 core (4.4-0ubuntu1) precise; urgency=low * Bandwidth plots, event scheduling, EMANE 0.7.4, improved services support, code cleanup, bugfixes, and more. -- Jeff Ahrenholz Tue, 04 Sep 2012 11:53:23 -0700 core (4.3-0ubuntu1) oneiric; urgency=low * Hook scripts, CEL, EMANE 0.7.3, physical nodes, improved WLAN and service dialogs, code cleanup, bugfixes, and more. -- Jeff Ahrenholz Thu, 09 Feb 2012 08:00:52 -0800 core (4.2-0ubuntu1) maverick; urgency=low * bugfixes, EMANE 0.7.1 support. -- Jeff Ahrenholz Mon, 15 Aug 2011 13:19:16 -0800 core (4.1-0ubuntu1) lucid; urgency=low * Node services, customizable nodes, traffic flows, IP address allocator, distributed emulation using GRE tunnels, EMANE 0.6.4 support, and more. -- Jeff Ahrenholz Thu, 09 Dec 2010 07:02:16 -0800 core (4.0-0ubuntu1) lucid; urgency=low * New CORE deb packaging. Extra magic added to omit the horrible /usr/share/info/dir.gz file from being generated. -- Jeff Ahrenholz Wed, 29 Jul 2010 16:07:26 -0700 core-4.8/packaging/deb/core.postrm0000664000175000017500000000036112534327775014133 00000000000000#!/bin/sh if [ "$1" = "remove" ]; then PYTHONS="python2.6 python2.7" for P in $PYTHONS do DIR="usr/lib/$P/dist-packages/core" if [ -d $DIR ]; then find $DIR -name '*.pyc' -exec rm -f '{}' ';' 2> /dev/null fi done fi core-4.8/packaging/deb/rules0000775000175000017500000000117112534327775013015 00000000000000#!/usr/bin/make -f # See debhelper(7) (uncomment to enable) # output every command that modifies files on the build system. # DH_VERBOSE = 1 include /usr/share/cdbs/1/rules/debhelper.mk include /usr/share/cdbs/1/class/autotools.mk include /usr/share/cdbs/1/rules/autoreconf.mk DEB_DH_AUTORECONF_ARGS += ./bootstrap.sh # this prevents 'make install' from invoking install-info that generates a # $(DEB_DESTDIR)usr/share/info/dir.gz file that causes a lintian error # the following rule was not enough # binary-post-install/core:: # rm -f $(DEB_DESTDIR)usr/share/info/dir.gz #DEB_CONFIGURE_EXTRA_FLAGS := --disable-install-info core-4.8/packaging/deb/control0000664000175000017500000000240612534327775013342 00000000000000Source: core Section: net Priority: optional Maintainer: CORE Developers Standards-Version: 3.8.4 Build-Depends: debhelper (>= 9), cdbs, dh-autoreconf, autoconf, automake, gcc, libev-dev, make, python-dev, libreadline-dev, bridge-utils, ebtables, iproute2 | iproute, imagemagick, pkg-config, help2man # python-sphinx Homepage: http://www.nrl.navy.mil/itd/ncs/products/core Package: core-daemon Architecture: any Depends: bash (>=3.0), bridge-utils, ebtables, iproute2 | iproute, libev4, python (>=2.6), dpkg (>=1.15.4), procps, ${shlibs:Depends} Recommends: quagga Description: Emulate virtual networks in a box. The Common Open Research Emulator provides Python modules for building virtual networks using Linux network namespace containers and bridging. This is the daemon package containing the backend Python modules and core-daemon. Package: core-gui Architecture: all Depends: bash (>=3.0), tcl (>= 8.5), tk (>= 8.5) Recommends: libtk-img Description: Emulate virtual networks in a box. The Common Open Research Emulator provides Python modules for building virtual networks using Linux network namespace containers and bridging. This is the GUI package containing a canvas-based Tcl/Tk GUI for easily drawing virtual network topologies. core-4.8/packaging/rpm/0000775000175000017500000000000012534330006012036 500000000000000core-4.8/packaging/rpm/core.spec.in0000664000175000017500000003674212534327775014226 00000000000000%define version @PACKAGE_VERSION@ %define lib_version @GENERIC_RELEASE@ %define python_version %(%{__python} -c "import sys; print '%s.%s' % (sys.version_info[0], sys.version_info[1])")%{nil} %if 0%{?fedora} >= 17 %define with_kernel_modules_extra 1 %else %define with_kernel_modules_extra 0 %endif Name: core Summary: Common Open Research Emulator for use with network namespaces License: BSD Prefix: /usr Release: 1%{?dist} Source: core-%{version}.tar.gz URL: http://www.nrl.navy.mil/itd/ncs/products/core Version: %{version} %description The Common Open Research Emulator provides Python modules and a GUI for building virtual networks using Linux network namespace containers and bridging. %package daemon Summary: Common Open Research Emulator daemon back-end Group: System Tools Requires: bash bridge-utils ebtables iproute libev python net-tools %if 0%{?el6} Requires: procps %else Requires: procps-ng %endif %if %{with_kernel_modules_extra} Requires: kernel-modules-extra %endif BuildRequires: make automake autoconf libev-devel python-devel bridge-utils ebtables iproute net-tools ImageMagick help2man %if 0%{?el6} BuildRequires: procps %else BuildRequires: procps-ng %endif Provides: core-daemon # python-sphinx %description daemon The Common Open Research Emulator provides Python modules for building virtual networks using Linux network namespace containers and bridging. %package gui Summary: Common Open Research Emulator GUI front-end Group: System Tools Requires: tcl tk BuildArch: noarch BuildRequires: make automake autoconf Provides: core-gui %description gui The Common Open Research Emulator canvas-based Tcl/Tk GUI for easily drawing virtual network topologies. %prep %setup -q %build ./bootstrap.sh # not using --disable-gui/--disable-daemon, because RPM expects both to be # installed by this build process # assume Fedora, using systemd startup script CFLAGS="-fno-strict-aliasing $CFLAGS" %configure --with-startup=systemd make -j4 %install rm -rf $RPM_BUILD_ROOT make DESTDIR=$RPM_BUILD_ROOT install %clean rm -rf $RPM_BUILD_ROOT %post %post daemon # don't run EMANE with realtime option under Fedora sed -i 's/emane_realtime = True/emane_realtime = False/' /etc/core/core.conf %preun #if [ "$1" = 0 ]; then #find %{_libdir}/python%{python_version}/site-packages/core -name '*.pyc' -exec rm -f '{}' ';' 2> /dev/null #fi %postun %files gui %{_bindir}/core-gui %dir @CORE_LIB_DIR@ %dir @CORE_LIB_DIR@/addons @CORE_LIB_DIR@/addons/ipsecservice.tcl @CORE_LIB_DIR@/annotations.tcl @CORE_LIB_DIR@/api.tcl @CORE_LIB_DIR@/canvas.tcl @CORE_LIB_DIR@/cfgparse.tcl @CORE_LIB_DIR@/core-bsd-cleanup.sh @CORE_LIB_DIR@/core.tcl @CORE_LIB_DIR@/debug.tcl @CORE_LIB_DIR@/editor.tcl @CORE_LIB_DIR@/exceptions.tcl @CORE_LIB_DIR@/exec.tcl @CORE_LIB_DIR@/filemgmt.tcl @CORE_LIB_DIR@/gpgui.tcl @CORE_LIB_DIR@/graph_partitioning.tcl @CORE_LIB_DIR@/help.tcl %{_datadir}/applications/core-gui.desktop %{_datadir}/pixmaps/core-gui.xpm %dir %{_datadir}/%{name} %dir %{_datadir}/%{name}/icons %dir %{_datadir}/%{name}/icons/normal %{_datadir}/%{name}/icons/normal/antenna.gif %{_datadir}/%{name}/icons/normal/ap.gif %{_datadir}/%{name}/icons/normal/core-icon.png %{_datadir}/%{name}/icons/normal/core-icon.xbm %{_datadir}/%{name}/icons/normal/core-logo-275x75.gif %{_datadir}/%{name}/icons/normal/document-properties.gif %{_datadir}/%{name}/icons/normal/gps-diagram.xbm %{_datadir}/%{name}/icons/normal/host.gif %{_datadir}/%{name}/icons/normal/hub.gif %{_datadir}/%{name}/icons/normal/lanswitch.gif %{_datadir}/%{name}/icons/normal/mdr.gif %{_datadir}/%{name}/icons/normal/oval.gif %{_datadir}/%{name}/icons/normal/pc.gif %{_datadir}/%{name}/icons/normal/rj45.gif %{_datadir}/%{name}/icons/normal/router_black.gif %{_datadir}/%{name}/icons/normal/router.gif %{_datadir}/%{name}/icons/normal/router_green.gif %{_datadir}/%{name}/icons/normal/router_purple.gif %{_datadir}/%{name}/icons/normal/router_red.gif %{_datadir}/%{name}/icons/normal/router_yellow.gif %{_datadir}/%{name}/icons/normal/simple.xbm %{_datadir}/%{name}/icons/normal/text.gif %{_datadir}/%{name}/icons/normal/thumb-unknown.gif %{_datadir}/%{name}/icons/normal/tunnel.gif %{_datadir}/%{name}/icons/normal/wlan.gif %{_datadir}/%{name}/icons/normal/xen.gif %dir %{_datadir}/%{name}/icons/svg %{_datadir}/%{name}/icons/svg/ap.svg %{_datadir}/%{name}/icons/svg/cel.svg %{_datadir}/%{name}/icons/svg/hub.svg %{_datadir}/%{name}/icons/svg/lanswitch.svg %{_datadir}/%{name}/icons/svg/mdr.svg %{_datadir}/%{name}/icons/svg/otr.svg %{_datadir}/%{name}/icons/svg/rj45.svg %{_datadir}/%{name}/icons/svg/router_black.svg %{_datadir}/%{name}/icons/svg/router_green.svg %{_datadir}/%{name}/icons/svg/router_purple.svg %{_datadir}/%{name}/icons/svg/router_red.svg %{_datadir}/%{name}/icons/svg/router.svg %{_datadir}/%{name}/icons/svg/router_yellow.svg %{_datadir}/%{name}/icons/svg/start.svg %{_datadir}/%{name}/icons/svg/tunnel.svg %{_datadir}/%{name}/icons/svg/vlan.svg %{_datadir}/%{name}/icons/svg/xen.svg %dir %{_datadir}/%{name}/icons/tiny %{_datadir}/%{name}/icons/tiny/ap.gif %{_datadir}/%{name}/icons/tiny/arrow.down.gif %{_datadir}/%{name}/icons/tiny/arrow.gif %{_datadir}/%{name}/icons/tiny/arrow.up.gif %{_datadir}/%{name}/icons/tiny/blank.gif %{_datadir}/%{name}/icons/tiny/button.play.gif %{_datadir}/%{name}/icons/tiny/button.stop.gif %{_datadir}/%{name}/icons/tiny/cel.gif %{_datadir}/%{name}/icons/tiny/delete.gif %{_datadir}/%{name}/icons/tiny/document-new.gif %{_datadir}/%{name}/icons/tiny/document-properties.gif %{_datadir}/%{name}/icons/tiny/document-save.gif %{_datadir}/%{name}/icons/tiny/edit-delete.gif %{_datadir}/%{name}/icons/tiny/eraser.gif %{_datadir}/%{name}/icons/tiny/fileopen.gif %{_datadir}/%{name}/icons/tiny/folder.gif %{_datadir}/%{name}/icons/tiny/host.gif %{_datadir}/%{name}/icons/tiny/hub.gif %{_datadir}/%{name}/icons/tiny/lanswitch.gif %{_datadir}/%{name}/icons/tiny/link.gif %{_datadir}/%{name}/icons/tiny/marker.gif %{_datadir}/%{name}/icons/tiny/mdr.gif %{_datadir}/%{name}/icons/tiny/mobility.gif %{_datadir}/%{name}/icons/tiny/moboff.gif %{_datadir}/%{name}/icons/tiny/observe.gif %{_datadir}/%{name}/icons/tiny/oval.gif %{_datadir}/%{name}/icons/tiny/pc.gif %{_datadir}/%{name}/icons/tiny/ping.gif %{_datadir}/%{name}/icons/tiny/plot.gif %{_datadir}/%{name}/icons/tiny/rectangle.gif %{_datadir}/%{name}/icons/tiny/rj45.gif %{_datadir}/%{name}/icons/tiny/router_black.gif %{_datadir}/%{name}/icons/tiny/router.gif %{_datadir}/%{name}/icons/tiny/router_green.gif %{_datadir}/%{name}/icons/tiny/router_purple.gif %{_datadir}/%{name}/icons/tiny/router_red.gif %{_datadir}/%{name}/icons/tiny/router_yellow.gif %{_datadir}/%{name}/icons/tiny/run.gif %{_datadir}/%{name}/icons/tiny/script_pause.gif %{_datadir}/%{name}/icons/tiny/script_play.gif %{_datadir}/%{name}/icons/tiny/script_stop.gif %{_datadir}/%{name}/icons/tiny/select.gif %{_datadir}/%{name}/icons/tiny/start.gif %{_datadir}/%{name}/icons/tiny/stock_connect.gif %{_datadir}/%{name}/icons/tiny/stock_disconnect.gif %{_datadir}/%{name}/icons/tiny/stop.gif %{_datadir}/%{name}/icons/tiny/text.gif %{_datadir}/%{name}/icons/tiny/trace.gif %{_datadir}/%{name}/icons/tiny/tunnel.gif %{_datadir}/%{name}/icons/tiny/twonode.gif %{_datadir}/%{name}/icons/tiny/view-refresh.gif %{_datadir}/%{name}/icons/tiny/wlan.gif %{_datadir}/%{name}/icons/tiny/xen.gif @CORE_LIB_DIR@/initgui.tcl @CORE_LIB_DIR@/ipv4.tcl @CORE_LIB_DIR@/ipv6.tcl @CORE_LIB_DIR@/linkcfg.tcl @CORE_LIB_DIR@/mobility.tcl @CORE_LIB_DIR@/nodecfg.tcl @CORE_LIB_DIR@/nodes.tcl @CORE_LIB_DIR@/ns2imunes.tcl @CORE_LIB_DIR@/plugins.tcl @CORE_LIB_DIR@/services.tcl @CORE_LIB_DIR@/tooltips.tcl @CORE_LIB_DIR@/topogen.tcl @CORE_LIB_DIR@/traffic.tcl @CORE_LIB_DIR@/util.tcl @CORE_LIB_DIR@/version.tcl @CORE_LIB_DIR@/widget.tcl @CORE_LIB_DIR@/wlanscript.tcl @CORE_LIB_DIR@/wlan.tcl %dir %{_datadir}/%{name}/examples %dir %{_datadir}/%{name}/examples/configs %{_datadir}/%{name}/examples/configs/sample10-kitchen-sink.imn %{_datadir}/%{name}/examples/configs/sample1-bg.gif %{_datadir}/%{name}/examples/configs/sample1.imn %{_datadir}/%{name}/examples/configs/sample1.scen %{_datadir}/%{name}/examples/configs/sample2-ssh.imn %{_datadir}/%{name}/examples/configs/sample3-bgp.imn %{_datadir}/%{name}/examples/configs/sample4-bg.jpg %{_datadir}/%{name}/examples/configs/sample4-nrlsmf.imn %{_datadir}/%{name}/examples/configs/sample4.scen %{_datadir}/%{name}/examples/configs/sample5-mgen.imn %{_datadir}/%{name}/examples/configs/sample6-emane-rfpipe.imn %{_datadir}/%{name}/examples/configs/sample7-emane-ieee80211abg.imn %{_datadir}/%{name}/examples/configs/sample8-ipsec-service.imn %{_datadir}/%{name}/examples/configs/sample9-vpn.imn %doc %{_mandir}/man1/core-gui.1.gz %files daemon %config @CORE_CONF_DIR@/core.conf %config @CORE_CONF_DIR@/perflogserver.conf %config @CORE_CONF_DIR@/xen.conf %dir %{_datadir}/%{name} %dir %{_datadir}/%{name}/examples %{_datadir}/%{name}/examples/controlnet_updown %dir %{_datadir}/%{name}/examples/corens3 %{_datadir}/%{name}/examples/corens3/ns3lte.py* %{_datadir}/%{name}/examples/corens3/ns3wifi.py* %{_datadir}/%{name}/examples/corens3/ns3wifirandomwalk.py* %{_datadir}/%{name}/examples/corens3/ns3wimax.py* %{_datadir}/%{name}/examples/emanemodel2core.py* %{_datadir}/%{name}/examples/findcore.py* %dir %{_datadir}/%{name}/examples/hooks %{_datadir}/%{name}/examples/hooks/configuration_hook.sh %{_datadir}/%{name}/examples/hooks/datacollect_hook.sh %{_datadir}/%{name}/examples/hooks/perflogserver.py* %{_datadir}/%{name}/examples/hooks/perflogstart.sh %{_datadir}/%{name}/examples/hooks/perflogstop.sh %{_datadir}/%{name}/examples/hooks/sessiondatacollect.sh %{_datadir}/%{name}/examples/hooks/timesyncstart.sh %{_datadir}/%{name}/examples/hooks/timesyncstop.sh %dir %{_datadir}/%{name}/examples/myservices %{_datadir}/%{name}/examples/myservices/__init__.py* %{_datadir}/%{name}/examples/myservices/README.txt %{_datadir}/%{name}/examples/myservices/sample.py* %dir %{_datadir}/%{name}/examples/netns %{_datadir}/%{name}/examples/netns/basicrange.py* %{_datadir}/%{name}/examples/netns/distributed.py* %{_datadir}/%{name}/examples/netns/emane80211.py* %{_datadir}/%{name}/examples/netns/howmanynodes.py* %{_datadir}/%{name}/examples/netns/iperf-performance-chain.py* %{_datadir}/%{name}/examples/netns/iperf-performance.sh %{_datadir}/%{name}/examples/netns/ospfmanetmdrtest.py* %{_datadir}/%{name}/examples/netns/switch.py* %{_datadir}/%{name}/examples/netns/switchtest.py* %{_datadir}/%{name}/examples/netns/twonodes.sh %{_datadir}/%{name}/examples/netns/wlanemanetests.py* %{_datadir}/%{name}/examples/netns/wlantest.py* %dir %{_datadir}/%{name}/examples/services %{_datadir}/%{name}/examples/services/sampleFirewall %{_datadir}/%{name}/examples/services/sampleIPsec %{_datadir}/%{name}/examples/services/sampleVPNClient %{_datadir}/%{name}/examples/services/sampleVPNServer %{_datadir}/%{name}/examples/stopsession.py* %doc %{_mandir}/man1/core-cleanup.1.gz %doc %{_mandir}/man1/core-daemon.1.gz %doc %{_mandir}/man1/core-manage.1.gz %doc %{_mandir}/man1/coresendmsg.1.gz %doc %{_mandir}/man1/core-xen-cleanup.1.gz %doc %{_mandir}/man1/netns.1.gz %doc %{_mandir}/man1/vcmd.1.gz %doc %{_mandir}/man1/vnoded.1.gz /etc/systemd/system/core-daemon.service %{python_sitearch}/core_python_netns-1.0-py%{python_version}.egg-info %{python_sitearch}/netns.so %{python_sitearch}/vcmd.so %{python_sitelib}/core/addons/__init__.py* %{python_sitelib}/core/api/coreapi.py* %{python_sitelib}/core/api/data.py* %{python_sitelib}/core/api/__init__.py* %{python_sitelib}/core/broker.py* %{python_sitelib}/core/bsd/__init__.py* %{python_sitelib}/core/bsd/netgraph.py* %{python_sitelib}/core/bsd/nodes.py* %{python_sitelib}/core/bsd/vnet.py* %{python_sitelib}/core/bsd/vnode.py* %{python_sitelib}/core/conf.py* %{python_sitelib}/core/constants.py* %{python_sitelib}/core/coreobj.py* %{python_sitelib}/core/emane/bypass.py* %{python_sitelib}/core/emane/commeffect.py* %{python_sitelib}/core/emane/emane.py* %{python_sitelib}/core/emane/ieee80211abg.py* %{python_sitelib}/core/emane/__init__.py* %{python_sitelib}/core/emane/nodes.py* %{python_sitelib}/core/emane/rfpipe.py* %{python_sitelib}/core/emane/universal.py* %{python_sitelib}/core/__init__.py* %{python_sitelib}/core/location.py* %{python_sitelib}/core/misc/event.py* %{python_sitelib}/core/misc/__init__.py* %{python_sitelib}/core/misc/ipaddr.py* %{python_sitelib}/core/misc/LatLongUTMconversion.py* %{python_sitelib}/core/misc/quagga.py* %{python_sitelib}/core/misc/utils.py* %{python_sitelib}/core/misc/utm.py* %{python_sitelib}/core/misc/xmldeployment.py* %{python_sitelib}/core/misc/xmlparser.py* %{python_sitelib}/core/misc/xmlparser0.py* %{python_sitelib}/core/misc/xmlparser1.py* %{python_sitelib}/core/misc/xmlsession.py* %{python_sitelib}/core/misc/xmlutils.py* %{python_sitelib}/core/misc/xmlwriter.py* %{python_sitelib}/core/misc/xmlwriter0.py* %{python_sitelib}/core/misc/xmlwriter1.py* %{python_sitelib}/core/mobility.py* %{python_sitelib}/core/netns/__init__.py* %{python_sitelib}/core/netns/nodes.py* %{python_sitelib}/core/netns/vif.py* %{python_sitelib}/core/netns/vnet.py* %{python_sitelib}/core/netns/vnodeclient.py* %{python_sitelib}/core/netns/vnode.py* %{python_sitelib}/corens3/constants.py* %{python_sitelib}/corens3/__init__.py* %{python_sitelib}/corens3/obj.py* %{python_sitelib}/corens3_python-@COREDPY_VERSION@-py%{python_version}.egg-info %{python_sitelib}/core/phys/__init__.py* %{python_sitelib}/core/phys/pnodes.py* %{python_sitelib}/core/pycore.py* %{python_sitelib}/core_python-@COREDPY_VERSION@-py%{python_version}.egg-info %{python_sitelib}/core/sdt.py* %{python_sitelib}/core/service.py* %{python_sitelib}/core/services/bird.py* %{python_sitelib}/core/services/__init__.py* %{python_sitelib}/core/services/dockersvc.py* %{python_sitelib}/core/services/nrl.py* %{python_sitelib}/core/services/quagga.py* %{python_sitelib}/core/services/security.py* %{python_sitelib}/core/services/ucarp.py* %{python_sitelib}/core/services/utility.py* %{python_sitelib}/core/services/xorp.py* %{python_sitelib}/core/session.py* %{python_sitelib}/core/xen/__init__.py* %{python_sitelib}/core/xen/xenconfig.py* %{python_sitelib}/core/xen/xen.py* %{_sbindir}/core-cleanup %{_sbindir}/core-daemon %{_sbindir}/core-manage %{_sbindir}/coresendmsg %{_sbindir}/core-xen-cleanup %{_sbindir}/netns %{_sbindir}/vcmd %{_sbindir}/vnoded %changelog * Thu Jun 5 2015 CORE Developers - 4.8 - Support for NRL Network Modeling Framework (NMF) XML representation, bugfixes * Wed Aug 6 2014 Jeff Ahrenholz - 4.7 - EMANE 0.9.1, asymmetric links, bugfixes * Thu Aug 22 2013 Jeff Ahrenholz - 4.6 - cored now core-daemon, core now core-gui for CORE 4.6 release * Wed Apr 3 2013 Jeff Ahrenholz - 4.5 - split into gui and daemon RPMs for CORE 4.5 release * Tue Sep 4 2012 Jeff Ahrenholz - 4.4 - update files list for CORE 4.4 release, removed info file * Tue Feb 7 2012 Jeff Ahrenholz - 4.3 - update files list for CORE 4.3 release, freshen dependencies * Tue Aug 16 2011 Jeff Ahrenholz - 4.2 - update for CORE 4.2 release; use dir variables, more arch independent * Mon Dec 13 2010 Jeff Ahrenholz - 4.1 - update for CORE 4.1 release; added calls to ldconfig and removal of pyc files * Wed Aug 4 2010 Jeff Ahrenholz - 4.0 - update for CORE 4.0 release for Python and network namespaces * Thu Sep 10 2009 Jeff Ahrenholz - 3.5 - update for CORE 3.5 release to include init script * Fri May 29 2009 Jeff Ahrenholz - 3.4 - initial spec file for CORE 3.4 release core-4.8/packaging/rpm/specfiles.sh0000775000175000017500000000300412534327775014312 00000000000000#!/bin/sh OLDDIR=$PWD cd ../../ if [ ! -e Makefile ]; then echo "Missing file: Makefile" fi VER=`grep PACKAGE_VERSION Makefile | awk '{ print $3 }'` echo "Detected CORE version $VER." DESTDIR=/tmp/corerpmspec make install if [ $? != 0 ]; then exit 1 fi cd /tmp/corerpmspec find . -type f | sort > newspecfiles.log # append all .py files with .py* so .pyc files are uninstalled sed -i 's/\.py$/.py*/g' newspecfiles.log # directory replacements sed -i 's/^\.\//\//g' newspecfiles.log sed -i 's/\/usr\/bin/%{_bindir}/g' newspecfiles.log sed -i 's/\/usr\/sbin/%{_sbindir}/g' newspecfiles.log sed -i 's/\/usr\/lib64\/python2.7\/site-packages/%{python_sitearch}/g' newspecfiles.log sed -i 's/\/usr\/lib\/python2.7\/site-packages/%{python_sitelib}/g' newspecfiles.log sed -i 's/\/usr\/lib\/python2.7\/dist-packages/%{python_sitelib}/g' newspecfiles.log sed -i 's/\/usr\/lib\/core/@CORE_LIB_DIR@/g' newspecfiles.log sed -i 's/\/usr\/share\/applications/%{_datadir}\/applications/g' newspecfiles.log sed -i 's/\/usr\/share\/pixmaps/%{_datadir}\/pixmaps/g' newspecfiles.log sed -i 's/\/usr\/share\/core/%{_datadir}\/%{name}/g' newspecfiles.log sed -i 's/\/etc\/core/%config @CORE_CONF_DIR@/g' newspecfiles.log sed -i 's/py2.7.egg/py@PYTHON_VERSION@.egg/g' newspecfiles.log sed -i "s/$VER/@COREDPY_VERSION@/g" newspecfiles.log sed -i 's/\/usr\/share\/man/%doc %{_mandir}/g' newspecfiles.log sed -i 's/\.1$/.1.gz/g' newspecfiles.log echo . echo A new filelist is available here: ls -al /tmp/corerpmspec/newspecfiles.log echo . cd $OLDDIR core-4.8/packaging/bsd/0000775000175000017500000000000012534327775012033 500000000000000core-4.8/packaging/bsd/core-kernel-deinstall-4.11.sh0000775000175000017500000000021712534327775017056 00000000000000#!/bin/sh echo Restoring /kernel.old ... install -m 555 -o root -g wheel -fschg /kernel.old /kernel rm -rf /modules mv /modules.old /modules core-4.8/packaging/bsd/core-kernel-deinstall-8.x.sh0000775000175000017500000000064212534327775017112 00000000000000#!/bin/sh PREV="" if [ ! -e "/boot/kernel.old" ] ; then if [ ! -e "/boot/GENERIC" ] ; then echo Previous kernel does not exist in /boot/kernel.old or /boot/GENERIC ! exit 1; else PREV="/boot/GENERIC" fi; else PREV="/boot/kernel.old" fi; echo Removing current kernel... chflags -R noschg /boot/kernel rm -rf /boot/kernel echo Restoring previous kernel from $PREV... mv $PREV /boot/kernel exit 0; core-4.8/packaging/bsd/core-kernel-pkgcreate.sh0000775000175000017500000000374712534327775016476 00000000000000#!/bin/sh VER=0.0 # determine FreeBSD 4.11 or 8.x REL=`uname -r` case "$REL" in 9.*) echo "Using FreeBSD 9.x..." KERN=9.x SCRIPTVER=8.x ;; 8.*) echo "Using FreeBSD 8.x..." KERN=8.x SCRIPTVER=8.x ;; 4.11-RELEASE) echo "Using FreeBSD 4.11..." KERN=4.11 SCRIPTVER=4.11 ;; *) echo "What version of FreeBSD are you running (4.11/8.x) ?" exit 1 esac if [ "a$1" = "a" ] then echo "usage: ./core-kernel-release.sh 20080228 [clean]" echo a version number is required exit 1; else VER=$1 fi; if [ "a$2" = "aclean" ] then echo Cleaning up... rm -f core-kernel.pkglist.tmp rm -f core-kernel.pkglist rm -f core-kernel-${KERN}-${VER}.tbz exit fi; # check for /kernel.new on 4.11 if [ ${KERN} = "4.11" ] then if [ -e "/kernel.new" ] then echo Note: proceeding using this kernel... ls -al /kernel.new else echo "error: first copy the desired kernel to /kernel.new" exit fi; fi; # # build the packing list # echo @comment ORIGIN:net/core-kernel > core-kernel.pkglist if [ ${KERN} = "4.11" ] # FreeBSD 4.11 then echo @cwd / >> core-kernel.pkglist echo kernel.new >> core-kernel.pkglist find /modules \! -type d > core-kernel.pkglist.tmp find /sbin/vimage >> core-kernel.pkglist.tmp find /usr/share/man/man8/vimage.8.gz >> core-kernel.pkglist.tmp find /sbin/ngctl >> core-kernel.pkglist.tmp find /usr/share/man/man8/ngctl.8.gz >> core-kernel.pkglist.tmp # FreeBSD 8.x else echo @cwd /boot >> core-kernel.pkglist PWDOLD=${PWD} cd /boot find kernel \! -type d > ${PWDOLD}/core-kernel.pkglist.tmp cd ${PWDOLD} echo @cwd / >> core-kernel.pkglist.tmp find /usr/sbin/vimage >> core-kernel.pkglist.tmp find /usr/share/man/man8/vimage.8.gz >> core-kernel.pkglist.tmp fi; # remove leading '/' from lines sed -e "s,^/,," core-kernel.pkglist.tmp >> core-kernel.pkglist # # build the package # pkg_create -c core-kernel.pkgdesc -d core-kernel.pkgdesclong -f core-kernel.pkglist -i core-kernel-preinstall-${SCRIPTVER}.sh -K core-kernel-deinstall-${SCRIPTVER}.sh -v core-kernel-${KERN}-${VER}.tbz core-4.8/packaging/bsd/core-kernel-preinstall-4.11.sh0000775000175000017500000000054312534327775017256 00000000000000#!/bin/sh if [ "x$2" = "xPOST-INSTALL" ] then install -m 555 -o root -g wheel -fschg /kernel.new /kernel rm -f /kernel.new echo Please reboot this machine to enable the new CORE kernel. exit 0; fi; install -m 555 -o root -g wheel -fschg /kernel /kernel.old if [ -e /modules.old ] then rm -rf /modules.old fi; mv /modules /modules.old exit 0; core-4.8/packaging/bsd/core-kernel-preinstall-8.x.sh0000775000175000017500000000106012534327775017303 00000000000000#!/bin/sh if [ "x$2" = "xPOST-INSTALL" ] then echo Please reboot this machine to enable the new CORE kernel. exit 0; fi; # PRE-INSTALL # save the GENERIC kernel OLDNAME=`strings /boot/kernel/kernel | tail -n 1` if [ "x$OLDNAME" = "xGENERIC" ] then chflags -R noschg /boot/kernel mv /boot/kernel /boot/GENERIC exit 0; fi; # get rid of /boot/kernel.old if it is in the way if [ -e "/boot/kernel.old" ] ; then chflags -R noschg /boot/kernel.old rm -rf /boot/kernel.old fi; chflags -R noschg /boot/kernel mv /boot/kernel /boot/kernel.old exit 0; core-4.8/packaging/bsd/core-kernel.pkgdesc0000664000175000017500000000007112534327775015521 00000000000000CORE FreeBSD kernel enables lightweight virtual machines core-4.8/packaging/bsd/core-kernel.pkgdesclong0000664000175000017500000000064112534327775016404 00000000000000This package contains the CORE FreeBSD kernel with kernel modules. Custom modules include ng_pipe and ng_wlan. Also contains the userspace utility program vimage. This package can be used along with the CORE GUI to build emulated networks. This kernel is based on the GENERIC kernel with the VIMAGE option turned on (per-jail network stack virtualization), and with a small patch to allow per-node filesystem access. core-4.8/packaging/bsd/core-pkgcreate.sh0000775000175000017500000000311112534327775015201 00000000000000#!/bin/sh VER=`grep -m 1 "set CORE_VERSION" ../../gui/version.tcl | awk '{ print $3 }'` ARCH=`uname -m` # determine FreeBSD 4.11 or 7.x REL=`uname -r` case "$REL" in 9.*) echo "Using FreeBSD 9.x..." KERN=9.x ;; 8.*) echo "Using FreeBSD 8.x..." KERN=8.x ;; 4.11-RELEASE) echo "Using FreeBSD 4.11..." KERN=4.11 ;; *) echo "What version of FreeBSD are you running (4.11/8.x) ?" exit 1 esac if [ "a$1" = "aclean" ] then echo Cleaning up... rm -f core.pkglist.tmp rm -f core.pkglist rm -f core-${KERN}-${VER}.tbz rm -rf /tmp/staging exit fi; # # build the packing list # echo @comment ORIGIN:net/core > core.pkglist echo @cwd /usr/local >> core.pkglist PKG_BASH=`pkg_info -E -x ^bash` # for 4.11 change this back to 8.4 PKG_TCL=`pkg_info -E -x ^tcl-8.5` PKG_TK=`pkg_info -E -x ^tk-8.5` echo @pkgdep ${PKG_BASH} >> core.pkglist echo @comment DEPORIGIN:shells/bash >> core.pkglist echo @pkgdep ${PKG_TCL} >> core.pkglist echo @comment DEPORIGIN:lang/tcl85 >> core.pkglist echo @pkgdep ${PKG_TK} >> core.pkglist echo @comment DEPORIGIN:x11-toolkits/tk85 >> core.pkglist SAVEDIR=`pwd` cd ../.. rm -rf /tmp/staging gmake DESTDIR=/tmp/staging install cd $SAVEDIR find /tmp/staging/usr/local \! -type d >> core.pkglist echo @cwd /etc >> core.pkglist find /tmp/staging/etc \! -type d >> core.pkglist sed -e "s,^/tmp/staging/usr/local/,," core.pkglist > core.pkglist.new1 sed -e "s,^/tmp/staging/etc/,," core.pkglist.new1 > core.pkglist rm -f core.pkglist.new1 # # build the package # pkg_create -c core.pkgdesc -d core.pkgdesclong -f core.pkglist -v core-${KERN}-${ARCH}-${VER}.tbz core-4.8/packaging/bsd/core.pkgdesc0000664000175000017500000000006312534327775014244 00000000000000Common Open Research Emulator userspace components core-4.8/packaging/bsd/core.pkgdesclong0000664000175000017500000000067012534327775015130 00000000000000The Common Open Research Emulator (CORE) is a tool that allows you to emulate entire networks on a FreeBSD or Linux machine. You can connect these emulated networks to live networks (or to additional emulated networks) via the machine's physical interfaces. This package contains CORE userspace components for easily drawing topologies that drive lightweight virutalized network stacks. WWW: http://www.nrl.navy.mil/itd/ncs/products/core core-4.8/Makefile.in0000664000175000017500000006676512534327777011352 00000000000000# Makefile.in generated by automake 1.13.4 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 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@ # CORE # (c)2010-2012 the Boeing Company. # See the LICENSE file included in this distribution. # # author: Jeff Ahrenholz # # Top-level Makefile for CORE project. # VPATH = @srcdir@ am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' 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 = : subdir = . DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ $(top_srcdir)/configure $(am__configure_deps) \ $(srcdir)/config.h.in \ $(top_srcdir)/daemon/core/constants.py.in \ $(top_srcdir)/daemon/ns3/corens3/constants.py.in \ $(top_srcdir)/packaging/deb/core-daemon.install.in \ $(top_srcdir)/packaging/deb/core-gui.install.in \ $(top_srcdir)/packaging/rpm/core.spec.in README \ config/install-sh config/missing \ $(top_srcdir)/config/install-sh $(top_srcdir)/config/missing ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \ configure.lineno config.status.lineno mkinstalldirs = $(install_sh) -d CONFIG_HEADER = config.h CONFIG_CLEAN_FILES = daemon/core/constants.py \ daemon/ns3/corens3/constants.py \ packaging/deb/core-daemon.install \ packaging/deb/core-gui.install packaging/rpm/core.spec CONFIG_CLEAN_VPATH_FILES = 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 = SOURCES = DIST_SOURCES = RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \ ctags-recursive dvi-recursive html-recursive info-recursive \ install-data-recursive install-dvi-recursive \ install-exec-recursive install-html-recursive \ install-info-recursive install-pdf-recursive \ install-ps-recursive install-recursive installcheck-recursive \ installdirs-recursive pdf-recursive ps-recursive \ tags-recursive uninstall-recursive am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ distclean-recursive maintainer-clean-recursive am__recursive_targets = \ $(RECURSIVE_TARGETS) \ $(RECURSIVE_CLEAN_TARGETS) \ $(am__extra_recursive_targets) AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \ cscope distdir dist dist-all distcheck am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) \ $(LISP)config.h.in # 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 CSCOPE = cscope DIST_SUBDIRS = gui scripts daemon doc DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) distdir = $(PACKAGE)-$(VERSION) top_distdir = $(distdir) am__remove_distdir = \ if test -d "$(distdir)"; then \ find "$(distdir)" -type d ! -perm -200 -exec chmod u+w {} ';' \ && rm -rf "$(distdir)" \ || { sleep 5 && rm -rf "$(distdir)"; }; \ else :; fi am__post_remove_distdir = $(am__remove_distdir) am__relativize = \ dir0=`pwd`; \ sed_first='s,^\([^/]*\)/.*$$,\1,'; \ sed_rest='s,^[^/]*/*,,'; \ sed_last='s,^.*/\([^/]*\)$$,\1,'; \ sed_butlast='s,/*[^/]*$$,,'; \ while test -n "$$dir1"; do \ first=`echo "$$dir1" | sed -e "$$sed_first"`; \ if test "$$first" != "."; then \ if test "$$first" = ".."; then \ dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ else \ first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ if test "$$first2" = "$$first"; then \ dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ else \ dir2="../$$dir2"; \ fi; \ dir0="$$dir0"/"$$first"; \ fi; \ fi; \ dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ done; \ reldir="$$dir2" DIST_ARCHIVES = $(distdir).tar.gz GZIP_ENV = --best DIST_TARGETS = dist-gzip distuninstallcheck_listfiles = find . -type f -print am__distuninstallcheck_listfiles = $(distuninstallcheck_listfiles) \ | sed 's|^\./|$(prefix)/|' | grep -v '$(infodir)/dir$$' distcleancheck_listfiles = find . -type f -print ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ ARCH = @ARCH@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ BINDIR = @BINDIR@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ COREDPY_VERSION = @COREDPY_VERSION@ CORE_CONF_DIR = @CORE_CONF_DIR@ CORE_DATA_DIR = @CORE_DATA_DIR@ CORE_GUI_CONF_DIR = @CORE_GUI_CONF_DIR@ CORE_LIB_DIR = @CORE_LIB_DIR@ CORE_STATE_DIR = @CORE_STATE_DIR@ CORE_VERSION = @CORE_VERSION@ CORE_VERSION_DATE = @CORE_VERSION_DATE@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ GREP = @GREP@ HELP2MAN = @HELP2MAN@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LDFLAGS = @LDFLAGS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIB_DIR = @LIB_DIR@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ OBJEXT = @OBJEXT@ 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@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PYTHON = @PYTHON@ PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ PYTHON_PLATFORM = @PYTHON_PLATFORM@ PYTHON_PREFIX = @PYTHON_PREFIX@ PYTHON_VERSION = @PYTHON_VERSION@ RANLIB = @RANLIB@ SBINDIR = @SBINDIR@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_CC = @ac_ct_CC@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ brctl_path = @brctl_path@ build_alias = @build_alias@ builddir = @builddir@ convert = @convert@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ ebtables_path = @ebtables_path@ enable_daemon = @enable_daemon@ enable_gui = @enable_gui@ exec_prefix = @exec_prefix@ gmake = @gmake@ help2man = @help2man@ host_alias = @host_alias@ htmldir = @htmldir@ ifconfig_path = @ifconfig_path@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ ip_path = @ip_path@ libdir = @libdir@ libev_CFLAGS = @libev_CFLAGS@ libev_LIBS = @libev_LIBS@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ mount_path = @mount_path@ ngctl_path = @ngctl_path@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgpyexecdir = @pkgpyexecdir@ pkgpythondir = @pkgpythondir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ pyexecdir = @pyexecdir@ pyprefix = @pyprefix@ pythondir = @pythondir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ sysctl_path = @sysctl_path@ target_alias = @target_alias@ tc_path = @tc_path@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ umount_path = @umount_path@ vimage_path = @vimage_path@ with_startup = @with_startup@ @WANT_DOCS_TRUE@DOCS = doc @WANT_GUI_TRUE@GUI = gui @WANT_DAEMON_TRUE@DAEMON = scripts daemon # keep docs last due to dependencies on binaries SUBDIRS = ${GUI} ${DAEMON} ${DOCS} ACLOCAL_AMFLAGS = -I config # extra files to include with distribution tarball EXTRA_DIST = bootstrap.sh LICENSE README-Xen Changelog kernel \ python-prefix.py \ packaging/bsd \ packaging/deb/compat \ packaging/deb/copyright \ packaging/deb/changelog \ packaging/deb/core.postrm \ packaging/deb/rules \ packaging/deb/control \ packaging/deb/core-daemon.install.in \ packaging/deb/core-gui.install.in \ packaging/rpm/core.spec.in \ packaging/rpm/specfiles.sh DISTCLEAN_TARGETS = aclocal.m4 config.h.in # extra cruft to remove DISTCLEANFILES = aclocal.m4 config.h.in configure Makefile.in config/compile all: config.h $(MAKE) $(AM_MAKEFLAGS) all-recursive .SUFFIXES: am--refresh: Makefile @: $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ echo ' cd $(srcdir) && $(AUTOMAKE) --foreign'; \ $(am__cd) $(srcdir) && $(AUTOMAKE) --foreign \ && exit 0; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ echo ' $(SHELL) ./config.status'; \ $(SHELL) ./config.status;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) $(SHELL) ./config.status --recheck $(top_srcdir)/configure: $(am__configure_deps) $(am__cd) $(srcdir) && $(AUTOCONF) $(ACLOCAL_M4): $(am__aclocal_m4_deps) $(am__cd) $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS) $(am__aclocal_m4_deps): config.h: stamp-h1 @if test ! -f $@; then rm -f stamp-h1; else :; fi @if test ! -f $@; then $(MAKE) $(AM_MAKEFLAGS) stamp-h1; else :; fi stamp-h1: $(srcdir)/config.h.in $(top_builddir)/config.status @rm -f stamp-h1 cd $(top_builddir) && $(SHELL) ./config.status config.h $(srcdir)/config.h.in: $(am__configure_deps) ($(am__cd) $(top_srcdir) && $(AUTOHEADER)) rm -f stamp-h1 touch $@ distclean-hdr: -rm -f config.h stamp-h1 daemon/core/constants.py: $(top_builddir)/config.status $(top_srcdir)/daemon/core/constants.py.in cd $(top_builddir) && $(SHELL) ./config.status $@ daemon/ns3/corens3/constants.py: $(top_builddir)/config.status $(top_srcdir)/daemon/ns3/corens3/constants.py.in cd $(top_builddir) && $(SHELL) ./config.status $@ packaging/deb/core-daemon.install: $(top_builddir)/config.status $(top_srcdir)/packaging/deb/core-daemon.install.in cd $(top_builddir) && $(SHELL) ./config.status $@ packaging/deb/core-gui.install: $(top_builddir)/config.status $(top_srcdir)/packaging/deb/core-gui.install.in cd $(top_builddir) && $(SHELL) ./config.status $@ packaging/rpm/core.spec: $(top_builddir)/config.status $(top_srcdir)/packaging/rpm/core.spec.in cd $(top_builddir) && $(SHELL) ./config.status $@ # This directory's subdirectories are mostly independent; you can cd # into them and run 'make' without going through this Makefile. # To change the values of 'make' variables: instead of editing Makefiles, # (1) if the variable is set in 'config.status', edit 'config.status' # (which will cause the Makefiles to be regenerated when you run 'make'); # (2) otherwise, pass the desired values on the 'make' command line. $(am__recursive_targets): @fail=; \ if $(am__make_keepgoing); then \ failcom='fail=yes'; \ else \ failcom='exit 1'; \ fi; \ dot_seen=no; \ target=`echo $@ | sed s/-recursive//`; \ case "$@" in \ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ *) list='$(SUBDIRS)' ;; \ esac; \ for subdir in $$list; do \ echo "Making $$target in $$subdir"; \ if test "$$subdir" = "."; then \ dot_seen=yes; \ local_target="$$target-am"; \ else \ local_target="$$target"; \ fi; \ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ || eval $$failcom; \ done; \ if test "$$dot_seen" = "no"; then \ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ fi; test -z "$$fail" ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-recursive TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ include_option=--etags-include; \ empty_fix=.; \ else \ include_option=--include; \ empty_fix=; \ fi; \ list='$(SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ test ! -f $$subdir/TAGS || \ set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ fi; \ done; \ $(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-recursive 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" cscope: cscope.files test ! -s cscope.files \ || $(CSCOPE) -b -q $(AM_CSCOPEFLAGS) $(CSCOPEFLAGS) -i cscope.files $(CSCOPE_ARGS) clean-cscope: -rm -f cscope.files cscope.files: clean-cscope cscopelist cscopelist: cscopelist-recursive 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 -rm -f cscope.out cscope.in.out cscope.po.out cscope.files distdir: $(DISTFILES) $(am__remove_distdir) test -d "$(distdir)" || mkdir "$(distdir)" @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 @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ $(am__make_dryrun) \ || test -d "$(distdir)/$$subdir" \ || $(MKDIR_P) "$(distdir)/$$subdir" \ || exit 1; \ dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ $(am__relativize); \ new_distdir=$$reldir; \ dir1=$$subdir; dir2="$(top_distdir)"; \ $(am__relativize); \ new_top_distdir=$$reldir; \ echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ ($(am__cd) $$subdir && \ $(MAKE) $(AM_MAKEFLAGS) \ top_distdir="$$new_top_distdir" \ distdir="$$new_distdir" \ am__remove_distdir=: \ am__skip_length_check=: \ am__skip_mode_fix=: \ distdir) \ || exit 1; \ fi; \ done $(MAKE) $(AM_MAKEFLAGS) \ top_distdir="$(top_distdir)" distdir="$(distdir)" \ dist-hook -test -n "$(am__skip_mode_fix)" \ || find "$(distdir)" -type d ! -perm -755 \ -exec chmod u+rwx,go+rx {} \; -o \ ! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \ ! -type d ! -perm -400 -exec chmod a+r {} \; -o \ ! -type d ! -perm -444 -exec $(install_sh) -c -m a+r {} {} \; \ || chmod -R a+r "$(distdir)" dist-gzip: distdir tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz $(am__post_remove_distdir) dist-bzip2: distdir tardir=$(distdir) && $(am__tar) | BZIP2=$${BZIP2--9} bzip2 -c >$(distdir).tar.bz2 $(am__post_remove_distdir) dist-lzip: distdir tardir=$(distdir) && $(am__tar) | lzip -c $${LZIP_OPT--9} >$(distdir).tar.lz $(am__post_remove_distdir) dist-xz: distdir tardir=$(distdir) && $(am__tar) | XZ_OPT=$${XZ_OPT--e} xz -c >$(distdir).tar.xz $(am__post_remove_distdir) dist-tarZ: distdir tardir=$(distdir) && $(am__tar) | compress -c >$(distdir).tar.Z $(am__post_remove_distdir) dist-shar: distdir shar $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).shar.gz $(am__post_remove_distdir) dist-zip: distdir -rm -f $(distdir).zip zip -rq $(distdir).zip $(distdir) $(am__post_remove_distdir) dist dist-all: $(MAKE) $(AM_MAKEFLAGS) $(DIST_TARGETS) am__post_remove_distdir='@:' $(am__post_remove_distdir) # This target untars the dist file and tries a VPATH configuration. Then # it guarantees that the distribution is self-contained by making another # tarfile. distcheck: dist case '$(DIST_ARCHIVES)' in \ *.tar.gz*) \ GZIP=$(GZIP_ENV) gzip -dc $(distdir).tar.gz | $(am__untar) ;;\ *.tar.bz2*) \ bzip2 -dc $(distdir).tar.bz2 | $(am__untar) ;;\ *.tar.lz*) \ lzip -dc $(distdir).tar.lz | $(am__untar) ;;\ *.tar.xz*) \ xz -dc $(distdir).tar.xz | $(am__untar) ;;\ *.tar.Z*) \ uncompress -c $(distdir).tar.Z | $(am__untar) ;;\ *.shar.gz*) \ GZIP=$(GZIP_ENV) gzip -dc $(distdir).shar.gz | unshar ;;\ *.zip*) \ unzip $(distdir).zip ;;\ esac chmod -R a-w $(distdir) chmod u+w $(distdir) mkdir $(distdir)/_build $(distdir)/_inst chmod a-w $(distdir) test -d $(distdir)/_build || exit 0; \ dc_install_base=`$(am__cd) $(distdir)/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \ && dc_destdir="$${TMPDIR-/tmp}/am-dc-$$$$/" \ && am__cwd=`pwd` \ && $(am__cd) $(distdir)/_build \ && ../configure --srcdir=.. --prefix="$$dc_install_base" \ $(AM_DISTCHECK_CONFIGURE_FLAGS) \ $(DISTCHECK_CONFIGURE_FLAGS) \ && $(MAKE) $(AM_MAKEFLAGS) \ && $(MAKE) $(AM_MAKEFLAGS) dvi \ && $(MAKE) $(AM_MAKEFLAGS) check \ && $(MAKE) $(AM_MAKEFLAGS) install \ && $(MAKE) $(AM_MAKEFLAGS) installcheck \ && $(MAKE) $(AM_MAKEFLAGS) uninstall \ && $(MAKE) $(AM_MAKEFLAGS) distuninstallcheck_dir="$$dc_install_base" \ distuninstallcheck \ && chmod -R a-w "$$dc_install_base" \ && ({ \ (cd ../.. && umask 077 && mkdir "$$dc_destdir") \ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" install \ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" uninstall \ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" \ distuninstallcheck_dir="$$dc_destdir" distuninstallcheck; \ } || { rm -rf "$$dc_destdir"; exit 1; }) \ && rm -rf "$$dc_destdir" \ && $(MAKE) $(AM_MAKEFLAGS) dist \ && rm -rf $(DIST_ARCHIVES) \ && $(MAKE) $(AM_MAKEFLAGS) distcleancheck \ && cd "$$am__cwd" \ || exit 1 $(am__post_remove_distdir) @(echo "$(distdir) archives ready for distribution: "; \ list='$(DIST_ARCHIVES)'; for i in $$list; do echo $$i; done) | \ sed -e 1h -e 1s/./=/g -e 1p -e 1x -e '$$p' -e '$$x' distuninstallcheck: @test -n '$(distuninstallcheck_dir)' || { \ echo 'ERROR: trying to run $@ with an empty' \ '$$(distuninstallcheck_dir)' >&2; \ exit 1; \ }; \ $(am__cd) '$(distuninstallcheck_dir)' || { \ echo 'ERROR: cannot chdir into $(distuninstallcheck_dir)' >&2; \ exit 1; \ }; \ test `$(am__distuninstallcheck_listfiles) | wc -l` -eq 0 \ || { echo "ERROR: files left after uninstall:" ; \ if test -n "$(DESTDIR)"; then \ echo " (check DESTDIR support)"; \ fi ; \ $(distuninstallcheck_listfiles) ; \ exit 1; } >&2 distcleancheck: distclean @if test '$(srcdir)' = . ; then \ echo "ERROR: distcleancheck can only run from a VPATH build" ; \ exit 1 ; \ fi @test `$(distcleancheck_listfiles) | wc -l` -eq 0 \ || { echo "ERROR: files left in build directory after distclean:" ; \ $(distcleancheck_listfiles) ; \ exit 1; } >&2 check-am: all-am check: check-recursive all-am: Makefile config.h installdirs: installdirs-recursive installdirs-am: install: install-recursive install-exec: install-exec-recursive install-data: install-data-recursive uninstall: uninstall-recursive install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-recursive 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) -test -z "$(DISTCLEANFILES)" || rm -f $(DISTCLEANFILES) 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-recursive clean-am: clean-generic mostlyclean-am distclean: distclean-recursive -rm -f $(am__CONFIG_DISTCLEAN_FILES) -rm -f Makefile distclean-am: clean-am distclean-generic distclean-hdr distclean-tags dvi: dvi-recursive dvi-am: html: html-recursive html-am: info: info-recursive info-am: install-data-am: install-dvi: install-dvi-recursive install-dvi-am: install-exec-am: install-html: install-html-recursive install-html-am: install-info: install-info-recursive install-info-am: install-man: install-pdf: install-pdf-recursive install-pdf-am: install-ps: install-ps-recursive install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-recursive -rm -f $(am__CONFIG_DISTCLEAN_FILES) -rm -rf $(top_srcdir)/autom4te.cache -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-recursive mostlyclean-am: mostlyclean-generic pdf: pdf-recursive pdf-am: ps: ps-recursive ps-am: uninstall-am: .MAKE: $(am__recursive_targets) all install-am install-strip .PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am \ am--refresh check check-am clean clean-cscope clean-generic \ cscope cscopelist-am ctags ctags-am dist dist-all dist-bzip2 \ dist-gzip dist-hook dist-lzip dist-shar dist-tarZ dist-xz \ dist-zip distcheck distclean distclean-generic distclean-hdr \ distclean-tags distcleancheck distdir distuninstallcheck 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 installdirs-am \ maintainer-clean maintainer-clean-generic mostlyclean \ mostlyclean-generic pdf pdf-am ps ps-am tags tags-am uninstall \ uninstall-am # don't include svn dirs in source tarball dist-hook: rm -rf `find $(distdir)/kernel -name .svn` rm -rf $(distdir)/packaging/bsd/.svn # build a source RPM using Fedora ~/rpmbuild dirs .PHONY: rpm rpm: dist rpmdev-setuptree cp -afv core-@CORE_VERSION@.tar.gz ~/rpmbuild/SOURCES cp -afv packaging/rpm/core.spec ~/rpmbuild/SPECS rpmbuild -bs ~/rpmbuild/SPECS/core.spec # build a Ubuntu deb package using CDBS .PHONY: deb deb: rm -rf debian mkdir -p debian cp -vf packaging/deb/* debian/ @echo "First create source archive with: dpkg-source -b core-@CORE_VERSION@" @echo "Then build with: pbuilder-dist precise i386 build core*.dsc" .PHONY: core-restart core-restart: /etc/init.d/core-daemon stop daemon/sbin/core-cleanup rm -f /var/log/core-daemon.log /etc/init.d/core-daemon start # 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: core-4.8/Makefile.am0000664000175000017500000000351612534327775011320 00000000000000# CORE # (c)2010-2012 the Boeing Company. # See the LICENSE file included in this distribution. # # author: Jeff Ahrenholz # # Top-level Makefile for CORE project. # if WANT_DOCS DOCS = doc endif if WANT_GUI GUI = gui endif if WANT_DAEMON DAEMON = scripts daemon endif # keep docs last due to dependencies on binaries SUBDIRS = ${GUI} ${DAEMON} ${DOCS} ACLOCAL_AMFLAGS = -I config # extra files to include with distribution tarball EXTRA_DIST = bootstrap.sh LICENSE README-Xen Changelog kernel \ python-prefix.py \ packaging/bsd \ packaging/deb/compat \ packaging/deb/copyright \ packaging/deb/changelog \ packaging/deb/core.postrm \ packaging/deb/rules \ packaging/deb/control \ packaging/deb/core-daemon.install.in \ packaging/deb/core-gui.install.in \ packaging/rpm/core.spec.in \ packaging/rpm/specfiles.sh DISTCLEAN_TARGETS = aclocal.m4 config.h.in # extra cruft to remove DISTCLEANFILES = aclocal.m4 config.h.in configure Makefile.in config/compile # don't include svn dirs in source tarball dist-hook: rm -rf `find $(distdir)/kernel -name .svn` rm -rf $(distdir)/packaging/bsd/.svn # build a source RPM using Fedora ~/rpmbuild dirs .PHONY: rpm rpm: dist rpmdev-setuptree cp -afv core-@CORE_VERSION@.tar.gz ~/rpmbuild/SOURCES cp -afv packaging/rpm/core.spec ~/rpmbuild/SPECS rpmbuild -bs ~/rpmbuild/SPECS/core.spec # build a Ubuntu deb package using CDBS .PHONY: deb deb: rm -rf debian mkdir -p debian cp -vf packaging/deb/* debian/ @echo "First create source archive with: dpkg-source -b core-@CORE_VERSION@" @echo "Then build with: pbuilder-dist precise i386 build core*.dsc" .PHONY: core-restart core-restart: /etc/init.d/core-daemon stop daemon/sbin/core-cleanup rm -f /var/log/core-daemon.log /etc/init.d/core-daemon start core-4.8/configure0000775000175000017500000071153012534330000011144 00000000000000#! /bin/sh # Guess values for system-dependent variables and create Makefiles. # Generated by GNU Autoconf 2.69 for core 4.8. # # Report bugs to . # # # Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc. # # # This configure script is free software; the Free Software Foundation # gives unlimited permission to copy, distribute and modify it. ## -------------------- ## ## M4sh Initialization. ## ## -------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi as_nl=' ' export as_nl # Printing a long string crashes Solaris 7 /usr/bin/printf. as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo # Prefer a ksh shell builtin over an external printf program on Solaris, # but without wasting forks for bash or zsh. if test -z "$BASH_VERSION$ZSH_VERSION" \ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='print -r --' as_echo_n='print -rn --' elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='printf %s\n' as_echo_n='printf %s' else if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' as_echo_n='/usr/ucb/echo -n' else as_echo_body='eval expr "X$1" : "X\\(.*\\)"' as_echo_n_body='eval arg=$1; case $arg in #( *"$as_nl"*) expr "X$arg" : "X\\(.*\\)$as_nl"; arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; esac; expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" ' export as_echo_n_body as_echo_n='sh -c $as_echo_n_body as_echo' fi export as_echo_body as_echo='sh -c $as_echo_body as_echo' fi # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || PATH_SEPARATOR=';' } fi # IFS # We need space, tab and new line, in precisely that order. Quoting is # there to prevent editors from complaining about space-tab. # (If _AS_PATH_WALK were called with IFS unset, it would disable word # splitting by setting IFS to empty value.) IFS=" "" $as_nl" # Find who we are. Look in the path if we contain no directory separator. as_myself= case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break done IFS=$as_save_IFS ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi # Unset variables that we do not need and which cause bugs (e.g. in # pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" # suppresses any "Segmentation fault" message there. '((' could # trigger a bug in pdksh 5.2.14. for as_var in BASH_ENV ENV MAIL MAILPATH do eval test x\${$as_var+set} = xset \ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done PS1='$ ' PS2='> ' PS4='+ ' # NLS nuisances. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # CDPATH. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH # Use a proper internal environment variable to ensure we don't fall # into an infinite loop, continuously re-executing ourselves. if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then _as_can_reexec=no; export _as_can_reexec; # We cannot yet assume a decent shell, so we have to provide a # neutralization value for shells without unset; and this also # works around shells that cannot unset nonexistent variables. # Preserve -v and -x to the replacement shell. BASH_ENV=/dev/null ENV=/dev/null (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV case $- in # (((( *v*x* | *x*v* ) as_opts=-vx ;; *v* ) as_opts=-v ;; *x* ) as_opts=-x ;; * ) as_opts= ;; esac exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} # Admittedly, this is quite paranoid, since all the known shells bail # out after a failed `exec'. $as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 as_fn_exit 255 fi # We don't want this to propagate to other subprocesses. { _as_can_reexec=; unset _as_can_reexec;} if test "x$CONFIG_SHELL" = x; then as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which # is contrary to our usage. Disable this feature. alias -g '\${1+\"\$@\"}'='\"\$@\"' setopt NO_GLOB_SUBST else case \`(set -o) 2>/dev/null\` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi " as_required="as_fn_return () { (exit \$1); } as_fn_success () { as_fn_return 0; } as_fn_failure () { as_fn_return 1; } as_fn_ret_success () { return 0; } as_fn_ret_failure () { return 1; } exitcode=0 as_fn_success || { exitcode=1; echo as_fn_success failed.; } as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; } as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; } as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; } if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then : else exitcode=1; echo positional parameters were not saved. fi test x\$exitcode = x0 || exit 1 test -x / || exit 1" as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1 test \$(( 1 + 1 )) = 2 || exit 1" if (eval "$as_required") 2>/dev/null; then : as_have_required=yes else as_have_required=no fi if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then : else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR as_found=false for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. as_found=: case $as_dir in #( /*) for as_base in sh bash ksh sh5; do # Try only shells that exist, to save several forks. as_shell=$as_dir/$as_base if { test -f "$as_shell" || test -f "$as_shell.exe"; } && { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then : CONFIG_SHELL=$as_shell as_have_required=yes if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then : break 2 fi fi done;; esac as_found=false done $as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } && { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then : CONFIG_SHELL=$SHELL as_have_required=yes fi; } IFS=$as_save_IFS if test "x$CONFIG_SHELL" != x; then : export CONFIG_SHELL # We cannot yet assume a decent shell, so we have to provide a # neutralization value for shells without unset; and this also # works around shells that cannot unset nonexistent variables. # Preserve -v and -x to the replacement shell. BASH_ENV=/dev/null ENV=/dev/null (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV case $- in # (((( *v*x* | *x*v* ) as_opts=-vx ;; *v* ) as_opts=-v ;; *x* ) as_opts=-x ;; * ) as_opts= ;; esac exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} # Admittedly, this is quite paranoid, since all the known shells bail # out after a failed `exec'. $as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 exit 255 fi if test x$as_have_required = xno; then : $as_echo "$0: This script requires a shell more modern than all" $as_echo "$0: the shells that I found on your system." if test x${ZSH_VERSION+set} = xset ; then $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should" $as_echo "$0: be upgraded to zsh 4.3.4 or later." else $as_echo "$0: Please tell bug-autoconf@gnu.org and $0: core-dev@pf.itd.nrl.navy.mil about your system, $0: including any error possibly output before this $0: message. Then install a modern shell, or manually run $0: the script under such a shell if you do have one." fi exit 1 fi fi fi SHELL=${CONFIG_SHELL-/bin/sh} export SHELL # Unset more variables known to interfere with behavior of common tools. CLICOLOR_FORCE= GREP_OPTIONS= unset CLICOLOR_FORCE GREP_OPTIONS ## --------------------- ## ## M4sh Shell Functions. ## ## --------------------- ## # as_fn_unset VAR # --------------- # Portably unset VAR. as_fn_unset () { { eval $1=; unset $1;} } as_unset=as_fn_unset # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. as_fn_set_status () { return $1 } # as_fn_set_status # as_fn_exit STATUS # ----------------- # Exit the shell with STATUS, even in a "trap 0" or "set -e" context. as_fn_exit () { set +e as_fn_set_status $1 exit $1 } # as_fn_exit # as_fn_mkdir_p # ------------- # Create "$as_dir" as a directory, including parents if necessary. as_fn_mkdir_p () { case $as_dir in #( -*) as_dir=./$as_dir;; esac test -d "$as_dir" || eval $as_mkdir_p || { as_dirs= while :; do case $as_dir in #( *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" as_dir=`$as_dirname -- "$as_dir" || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" } # as_fn_mkdir_p # as_fn_executable_p FILE # ----------------------- # Test if FILE is an executable regular file. as_fn_executable_p () { test -f "$1" && test -x "$1" } # as_fn_executable_p # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : eval 'as_fn_append () { eval $1+=\$2 }' else as_fn_append () { eval $1=\$$1\$2 } fi # as_fn_append # as_fn_arith ARG... # ------------------ # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : eval 'as_fn_arith () { as_val=$(( $* )) }' else as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } fi # as_fn_arith # as_fn_error STATUS ERROR [LINENO LOG_FD] # ---------------------------------------- # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are # provided, also output the error to LOG_FD, referencing LINENO. Then exit the # script with STATUS, using 1 if that was 0. as_fn_error () { as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi $as_echo "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then as_dirname=dirname else as_dirname=false fi as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || $as_echo X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits as_lineno_1=$LINENO as_lineno_1a=$LINENO as_lineno_2=$LINENO as_lineno_2a=$LINENO eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" && test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || { # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-) sed -n ' p /[$]LINENO/= ' <$as_myself | sed ' s/[$]LINENO.*/&-/ t lineno b :lineno N :loop s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ t loop s/-\n.*// ' >$as_me.lineno && chmod +x "$as_me.lineno" || { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } # If we had to re-execute with $CONFIG_SHELL, we're ensured to have # already done that, so ensure we don't try to do so again and fall # in an infinite loop. This has already happened in practice. _as_can_reexec=no; export _as_can_reexec # Don't try to exec as it changes $[0], causing all sort of problems # (the dirname of $[0] is not the place where we might find the # original and so on. Autoconf is especially sensitive to this). . "./$as_me.lineno" # Exit status is that of the last command. exit } ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) case `echo 'xy\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. xy) ECHO_C='\c';; *) echo `echo ksh88 bug on AIX 6.1` > /dev/null ECHO_T=' ';; esac;; *) ECHO_N='-n';; esac rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir mkdir conf$$.dir 2>/dev/null fi if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. # In both cases, we have to default to `cp -pR'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -pR' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -pR' fi else as_ln_s='cp -pR' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null if mkdir -p . 2>/dev/null; then as_mkdir_p='mkdir -p "$as_dir"' else test -d ./-p && rmdir ./-p as_mkdir_p=false fi as_test_x='test -x' as_executable_p=as_fn_executable_p # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" test -n "$DJDIR" || exec 7<&0
    &1 # Name of the host. # hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status, # so uname gets run too. ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` # # Initializations. # ac_default_prefix=/usr/local ac_clean_files= ac_config_libobj_dir=. LIBOBJS= cross_compiling=no subdirs= MFLAGS= MAKEFLAGS= # Identity of this package. PACKAGE_NAME='core' PACKAGE_TARNAME='core' PACKAGE_VERSION='4.8' PACKAGE_STRING='core 4.8' PACKAGE_BUGREPORT='core-dev@pf.itd.nrl.navy.mil' PACKAGE_URL='' ac_unique_file="daemon/src/version.h.in" # Factoring default headers for most tests. ac_includes_default="\ #include #ifdef HAVE_SYS_TYPES_H # include #endif #ifdef HAVE_SYS_STAT_H # include #endif #ifdef STDC_HEADERS # include # include #else # ifdef HAVE_STDLIB_H # include # endif #endif #ifdef HAVE_STRING_H # if !defined STDC_HEADERS && defined HAVE_MEMORY_H # include # endif # include #endif #ifdef HAVE_STRINGS_H # include #endif #ifdef HAVE_INTTYPES_H # include #endif #ifdef HAVE_STDINT_H # include #endif #ifdef HAVE_UNISTD_H # include #endif" ac_subst_vars='am__EXEEXT_FALSE am__EXEEXT_TRUE LTLIBOBJS HELP2MAN WANT_SUSE_FALSE WANT_SUSE_TRUE WANT_SYSTEMD_FALSE WANT_SYSTEMD_TRUE WANT_INITD_FALSE WANT_INITD_TRUE WANT_NETNS_FALSE WANT_NETNS_TRUE WANT_PYTHON_FALSE WANT_PYTHON_TRUE WANT_DOCS_FALSE WANT_DOCS_TRUE WANT_BSD_FALSE WANT_BSD_TRUE WANT_DAEMON_FALSE WANT_DAEMON_TRUE WANT_GUI_FALSE WANT_GUI_TRUE with_startup pyprefix PKG_CONFIG_LIBDIR PKG_CONFIG_PATH PKG_CONFIG libev_LIBS libev_CFLAGS gmake ARCH LIBOBJS EGREP GREP CPP help2man convert umount_path mount_path vimage_path ngctl_path ifconfig_path tc_path ip_path ebtables_path sysctl_path brctl_path pkgpyexecdir pyexecdir pkgpythondir pythondir PYTHON_PLATFORM PYTHON_EXEC_PREFIX PYTHON_PREFIX PYTHON_VERSION PYTHON RANLIB am__fastdepCC_FALSE am__fastdepCC_TRUE CCDEPMODE am__nodep AMDEPBACKSLASH AMDEP_FALSE AMDEP_TRUE am__quote am__include DEPDIR OBJEXT EXEEXT ac_ct_CC CPPFLAGS LDFLAGS CFLAGS CC CORE_STATE_DIR enable_daemon enable_gui CORE_GUI_CONF_DIR CORE_DATA_DIR CORE_CONF_DIR BINDIR SBINDIR CORE_LIB_DIR LIB_DIR COREDPY_VERSION CORE_VERSION_DATE CORE_VERSION AM_BACKSLASH AM_DEFAULT_VERBOSITY AM_DEFAULT_V AM_V am__untar am__tar AMTAR am__leading_dot SET_MAKE AWK mkdir_p MKDIR_P INSTALL_STRIP_PROGRAM STRIP install_sh MAKEINFO AUTOHEADER AUTOMAKE AUTOCONF ACLOCAL VERSION PACKAGE CYGPATH_W am__isrc INSTALL_DATA INSTALL_SCRIPT INSTALL_PROGRAM target_alias host_alias build_alias LIBS ECHO_T ECHO_N ECHO_C DEFS mandir localedir libdir psdir pdfdir dvidir htmldir infodir docdir oldincludedir includedir localstatedir sharedstatedir sysconfdir datadir datarootdir libexecdir sbindir bindir program_transform_name prefix exec_prefix PACKAGE_URL PACKAGE_BUGREPORT PACKAGE_STRING PACKAGE_VERSION PACKAGE_TARNAME PACKAGE_NAME PATH_SEPARATOR SHELL' ac_subst_files='' ac_user_opts=' enable_option_checking enable_silent_rules with_guiconfdir enable_gui enable_daemon enable_dependency_tracking with_startup ' ac_precious_vars='build_alias host_alias target_alias CC CFLAGS LDFLAGS LIBS CPPFLAGS PYTHON CPP PKG_CONFIG PKG_CONFIG_PATH PKG_CONFIG_LIBDIR libev_CFLAGS libev_LIBS' # Initialize some variables set by options. ac_init_help= ac_init_version=false ac_unrecognized_opts= ac_unrecognized_sep= # The variables have the same names as the options, with # dashes changed to underlines. cache_file=/dev/null exec_prefix=NONE no_create= no_recursion= prefix=NONE program_prefix=NONE program_suffix=NONE program_transform_name=s,x,x, silent= site= srcdir= verbose= x_includes=NONE x_libraries=NONE # Installation directory options. # These are left unexpanded so users can "make install exec_prefix=/foo" # and all the variables that are supposed to be based on exec_prefix # by default will actually change. # Use braces instead of parens because sh, perl, etc. also accept them. # (The list follows the same order as the GNU Coding Standards.) bindir='${exec_prefix}/bin' sbindir='${exec_prefix}/sbin' libexecdir='${exec_prefix}/libexec' datarootdir='${prefix}/share' datadir='${datarootdir}' sysconfdir='${prefix}/etc' sharedstatedir='${prefix}/com' localstatedir='${prefix}/var' includedir='${prefix}/include' oldincludedir='/usr/include' docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' infodir='${datarootdir}/info' htmldir='${docdir}' dvidir='${docdir}' pdfdir='${docdir}' psdir='${docdir}' libdir='${exec_prefix}/lib' localedir='${datarootdir}/locale' mandir='${datarootdir}/man' ac_prev= ac_dashdash= for ac_option do # If the previous option needs an argument, assign it. if test -n "$ac_prev"; then eval $ac_prev=\$ac_option ac_prev= continue fi case $ac_option in *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; *=) ac_optarg= ;; *) ac_optarg=yes ;; esac # Accept the important Cygnus configure options, so we can diagnose typos. case $ac_dashdash$ac_option in --) ac_dashdash=yes ;; -bindir | --bindir | --bindi | --bind | --bin | --bi) ac_prev=bindir ;; -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) bindir=$ac_optarg ;; -build | --build | --buil | --bui | --bu) ac_prev=build_alias ;; -build=* | --build=* | --buil=* | --bui=* | --bu=*) build_alias=$ac_optarg ;; -cache-file | --cache-file | --cache-fil | --cache-fi \ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) ac_prev=cache_file ;; -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) cache_file=$ac_optarg ;; --config-cache | -C) cache_file=config.cache ;; -datadir | --datadir | --datadi | --datad) ac_prev=datadir ;; -datadir=* | --datadir=* | --datadi=* | --datad=*) datadir=$ac_optarg ;; -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ | --dataroo | --dataro | --datar) ac_prev=datarootdir ;; -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) datarootdir=$ac_optarg ;; -disable-* | --disable-*) ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid feature name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval enable_$ac_useropt=no ;; -docdir | --docdir | --docdi | --doc | --do) ac_prev=docdir ;; -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) docdir=$ac_optarg ;; -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) ac_prev=dvidir ;; -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) dvidir=$ac_optarg ;; -enable-* | --enable-*) ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid feature name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval enable_$ac_useropt=\$ac_optarg ;; -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ | --exec | --exe | --ex) ac_prev=exec_prefix ;; -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ | --exec=* | --exe=* | --ex=*) exec_prefix=$ac_optarg ;; -gas | --gas | --ga | --g) # Obsolete; use --with-gas. with_gas=yes ;; -help | --help | --hel | --he | -h) ac_init_help=long ;; -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) ac_init_help=recursive ;; -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) ac_init_help=short ;; -host | --host | --hos | --ho) ac_prev=host_alias ;; -host=* | --host=* | --hos=* | --ho=*) host_alias=$ac_optarg ;; -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) ac_prev=htmldir ;; -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ | --ht=*) htmldir=$ac_optarg ;; -includedir | --includedir | --includedi | --included | --include \ | --includ | --inclu | --incl | --inc) ac_prev=includedir ;; -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ | --includ=* | --inclu=* | --incl=* | --inc=*) includedir=$ac_optarg ;; -infodir | --infodir | --infodi | --infod | --info | --inf) ac_prev=infodir ;; -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) infodir=$ac_optarg ;; -libdir | --libdir | --libdi | --libd) ac_prev=libdir ;; -libdir=* | --libdir=* | --libdi=* | --libd=*) libdir=$ac_optarg ;; -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ | --libexe | --libex | --libe) ac_prev=libexecdir ;; -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ | --libexe=* | --libex=* | --libe=*) libexecdir=$ac_optarg ;; -localedir | --localedir | --localedi | --localed | --locale) ac_prev=localedir ;; -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) localedir=$ac_optarg ;; -localstatedir | --localstatedir | --localstatedi | --localstated \ | --localstate | --localstat | --localsta | --localst | --locals) ac_prev=localstatedir ;; -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) localstatedir=$ac_optarg ;; -mandir | --mandir | --mandi | --mand | --man | --ma | --m) ac_prev=mandir ;; -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) mandir=$ac_optarg ;; -nfp | --nfp | --nf) # Obsolete; use --without-fp. with_fp=no ;; -no-create | --no-create | --no-creat | --no-crea | --no-cre \ | --no-cr | --no-c | -n) no_create=yes ;; -no-recursion | --no-recursion | --no-recursio | --no-recursi \ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) no_recursion=yes ;; -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ | --oldin | --oldi | --old | --ol | --o) ac_prev=oldincludedir ;; -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) oldincludedir=$ac_optarg ;; -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) ac_prev=prefix ;; -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) prefix=$ac_optarg ;; -program-prefix | --program-prefix | --program-prefi | --program-pref \ | --program-pre | --program-pr | --program-p) ac_prev=program_prefix ;; -program-prefix=* | --program-prefix=* | --program-prefi=* \ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) program_prefix=$ac_optarg ;; -program-suffix | --program-suffix | --program-suffi | --program-suff \ | --program-suf | --program-su | --program-s) ac_prev=program_suffix ;; -program-suffix=* | --program-suffix=* | --program-suffi=* \ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) program_suffix=$ac_optarg ;; -program-transform-name | --program-transform-name \ | --program-transform-nam | --program-transform-na \ | --program-transform-n | --program-transform- \ | --program-transform | --program-transfor \ | --program-transfo | --program-transf \ | --program-trans | --program-tran \ | --progr-tra | --program-tr | --program-t) ac_prev=program_transform_name ;; -program-transform-name=* | --program-transform-name=* \ | --program-transform-nam=* | --program-transform-na=* \ | --program-transform-n=* | --program-transform-=* \ | --program-transform=* | --program-transfor=* \ | --program-transfo=* | --program-transf=* \ | --program-trans=* | --program-tran=* \ | --progr-tra=* | --program-tr=* | --program-t=*) program_transform_name=$ac_optarg ;; -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) ac_prev=pdfdir ;; -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) pdfdir=$ac_optarg ;; -psdir | --psdir | --psdi | --psd | --ps) ac_prev=psdir ;; -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) psdir=$ac_optarg ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) silent=yes ;; -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) ac_prev=sbindir ;; -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ | --sbi=* | --sb=*) sbindir=$ac_optarg ;; -sharedstatedir | --sharedstatedir | --sharedstatedi \ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ | --sharedst | --shareds | --shared | --share | --shar \ | --sha | --sh) ac_prev=sharedstatedir ;; -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ | --sha=* | --sh=*) sharedstatedir=$ac_optarg ;; -site | --site | --sit) ac_prev=site ;; -site=* | --site=* | --sit=*) site=$ac_optarg ;; -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) ac_prev=srcdir ;; -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) srcdir=$ac_optarg ;; -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ | --syscon | --sysco | --sysc | --sys | --sy) ac_prev=sysconfdir ;; -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) sysconfdir=$ac_optarg ;; -target | --target | --targe | --targ | --tar | --ta | --t) ac_prev=target_alias ;; -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) target_alias=$ac_optarg ;; -v | -verbose | --verbose | --verbos | --verbo | --verb) verbose=yes ;; -version | --version | --versio | --versi | --vers | -V) ac_init_version=: ;; -with-* | --with-*) ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid package name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval with_$ac_useropt=\$ac_optarg ;; -without-* | --without-*) ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid package name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval with_$ac_useropt=no ;; --x) # Obsolete; use --with-x. with_x=yes ;; -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ | --x-incl | --x-inc | --x-in | --x-i) ac_prev=x_includes ;; -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) x_includes=$ac_optarg ;; -x-libraries | --x-libraries | --x-librarie | --x-librari \ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) ac_prev=x_libraries ;; -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) x_libraries=$ac_optarg ;; -*) as_fn_error $? "unrecognized option: \`$ac_option' Try \`$0 --help' for more information" ;; *=*) ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` # Reject names that are not valid shell variable names. case $ac_envvar in #( '' | [0-9]* | *[!_$as_cr_alnum]* ) as_fn_error $? "invalid variable name: \`$ac_envvar'" ;; esac eval $ac_envvar=\$ac_optarg export $ac_envvar ;; *) # FIXME: should be removed in autoconf 3.0. $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2 expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2 : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}" ;; esac done if test -n "$ac_prev"; then ac_option=--`echo $ac_prev | sed 's/_/-/g'` as_fn_error $? "missing argument to $ac_option" fi if test -n "$ac_unrecognized_opts"; then case $enable_option_checking in no) ;; fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;; *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; esac fi # Check all directory arguments for consistency. for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ datadir sysconfdir sharedstatedir localstatedir includedir \ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ libdir localedir mandir do eval ac_val=\$$ac_var # Remove trailing slashes. case $ac_val in */ ) ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'` eval $ac_var=\$ac_val;; esac # Be sure to have absolute directory names. case $ac_val in [\\/$]* | ?:[\\/]* ) continue;; NONE | '' ) case $ac_var in *prefix ) continue;; esac;; esac as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val" done # There might be people who depend on the old broken behavior: `$host' # used to hold the argument of --host etc. # FIXME: To remove some day. build=$build_alias host=$host_alias target=$target_alias # FIXME: To remove some day. if test "x$host_alias" != x; then if test "x$build_alias" = x; then cross_compiling=maybe elif test "x$build_alias" != "x$host_alias"; then cross_compiling=yes fi fi ac_tool_prefix= test -n "$host_alias" && ac_tool_prefix=$host_alias- test "$silent" = yes && exec 6>/dev/null ac_pwd=`pwd` && test -n "$ac_pwd" && ac_ls_di=`ls -di .` && ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || as_fn_error $? "working directory cannot be determined" test "X$ac_ls_di" = "X$ac_pwd_ls_di" || as_fn_error $? "pwd does not report name of working directory" # Find the source files, if location was not specified. if test -z "$srcdir"; then ac_srcdir_defaulted=yes # Try the directory containing this script, then the parent directory. ac_confdir=`$as_dirname -- "$as_myself" || $as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_myself" : 'X\(//\)[^/]' \| \ X"$as_myself" : 'X\(//\)$' \| \ X"$as_myself" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_myself" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` srcdir=$ac_confdir if test ! -r "$srcdir/$ac_unique_file"; then srcdir=.. fi else ac_srcdir_defaulted=no fi if test ! -r "$srcdir/$ac_unique_file"; then test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir" fi ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" ac_abs_confdir=`( cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg" pwd)` # When building in place, set srcdir=. if test "$ac_abs_confdir" = "$ac_pwd"; then srcdir=. fi # Remove unnecessary trailing slashes from srcdir. # Double slashes in file names in object file debugging info # mess up M-x gdb in Emacs. case $srcdir in */) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; esac for ac_var in $ac_precious_vars; do eval ac_env_${ac_var}_set=\${${ac_var}+set} eval ac_env_${ac_var}_value=\$${ac_var} eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} eval ac_cv_env_${ac_var}_value=\$${ac_var} done # # Report the --help message. # if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF \`configure' configures core 4.8 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... To assign environment variables (e.g., CC, CFLAGS...), specify them as VAR=VALUE. See below for descriptions of some of the useful variables. Defaults for the options are specified in brackets. Configuration: -h, --help display this help and exit --help=short display options specific to this package --help=recursive display the short help of all the included packages -V, --version display version information and exit -q, --quiet, --silent do not print \`checking ...' messages --cache-file=FILE cache test results in FILE [disabled] -C, --config-cache alias for \`--cache-file=config.cache' -n, --no-create do not create output files --srcdir=DIR find the sources in DIR [configure dir or \`..'] Installation directories: --prefix=PREFIX install architecture-independent files in PREFIX [$ac_default_prefix] --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX [PREFIX] By default, \`make install' will install all the files in \`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify an installation prefix other than \`$ac_default_prefix' using \`--prefix', for instance \`--prefix=\$HOME'. For better control, use the options below. Fine tuning of the installation directories: --bindir=DIR user executables [EPREFIX/bin] --sbindir=DIR system admin executables [EPREFIX/sbin] --libexecdir=DIR program executables [EPREFIX/libexec] --sysconfdir=DIR read-only single-machine data [PREFIX/etc] --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] --localstatedir=DIR modifiable single-machine data [PREFIX/var] --libdir=DIR object code libraries [EPREFIX/lib] --includedir=DIR C header files [PREFIX/include] --oldincludedir=DIR C header files for non-gcc [/usr/include] --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] --datadir=DIR read-only architecture-independent data [DATAROOTDIR] --infodir=DIR info documentation [DATAROOTDIR/info] --localedir=DIR locale-dependent data [DATAROOTDIR/locale] --mandir=DIR man documentation [DATAROOTDIR/man] --docdir=DIR documentation root [DATAROOTDIR/doc/core] --htmldir=DIR html documentation [DOCDIR] --dvidir=DIR dvi documentation [DOCDIR] --pdfdir=DIR pdf documentation [DOCDIR] --psdir=DIR ps documentation [DOCDIR] _ACEOF cat <<\_ACEOF Program names: --program-prefix=PREFIX prepend PREFIX to installed program names --program-suffix=SUFFIX append SUFFIX to installed program names --program-transform-name=PROGRAM run sed PROGRAM on installed program names _ACEOF fi if test -n "$ac_init_help"; then case $ac_init_help in short | recursive ) echo "Configuration of core 4.8:";; esac cat <<\_ACEOF Optional Features: --disable-option-checking ignore unrecognized --enable/--with options --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) --enable-FEATURE[=ARG] include FEATURE [ARG=yes] --enable-silent-rules less verbose build output (undo: "make V=1") --disable-silent-rules verbose build output (undo: "make V=0") --enable-gui=ARG build and install the GUI (default is yes) --enable-daemon=ARG build and install the daemon with Python modules (default is yes) --enable-dependency-tracking do not reject slow dependency extractors --disable-dependency-tracking speeds up one-time build Optional Packages: --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) --with-guiconfdir=dir specify GUI configuration directory --with-startup=option option=systemd,suse,none to install systemd/SUSE init scripts Some influential environment variables: CC C compiler command CFLAGS C compiler flags LDFLAGS linker flags, e.g. -L if you have libraries in a nonstandard directory LIBS libraries to pass to the linker, e.g. -l CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I if you have headers in a nonstandard directory PYTHON the Python interpreter CPP C preprocessor PKG_CONFIG path to pkg-config utility PKG_CONFIG_PATH directories to add to pkg-config's search path PKG_CONFIG_LIBDIR path overriding pkg-config's built-in search path libev_CFLAGS C compiler flags for libev, overriding pkg-config libev_LIBS linker flags for libev, overriding pkg-config Use these variables to override the choices made by `configure' or to help it to find libraries and programs with nonstandard names/locations. Report bugs to . _ACEOF ac_status=$? fi if test "$ac_init_help" = "recursive"; then # If there are subdirs, report their specific --help. for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue test -d "$ac_dir" || { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } || continue ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix cd "$ac_dir" || { ac_status=$?; continue; } # Check for guested configure. if test -f "$ac_srcdir/configure.gnu"; then echo && $SHELL "$ac_srcdir/configure.gnu" --help=recursive elif test -f "$ac_srcdir/configure"; then echo && $SHELL "$ac_srcdir/configure" --help=recursive else $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 fi || ac_status=$? cd "$ac_pwd" || { ac_status=$?; break; } done fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF core configure 4.8 generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. This configure script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it. _ACEOF exit fi ## ------------------------ ## ## Autoconf initialization. ## ## ------------------------ ## # ac_fn_c_try_compile LINENO # -------------------------- # Try to compile conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_compile # ac_fn_c_try_link LINENO # ----------------------- # Try to link conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_link () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext conftest$ac_exeext if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest$ac_exeext && { test "$cross_compiling" = yes || test -x conftest$ac_exeext }; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would # interfere with the next link command; also delete a directory that is # left behind by Apple's compiler. We do this before executing the actions. rm -rf conftest.dSYM conftest_ipa8_conftest.oo eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_link # ac_fn_c_try_cpp LINENO # ---------------------- # Try to preprocess conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_cpp () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if { { ac_try="$ac_cpp conftest.$ac_ext" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } > conftest.i && { test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || test ! -s conftest.err }; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_cpp # ac_fn_c_check_header_mongrel LINENO HEADER VAR INCLUDES # ------------------------------------------------------- # Tests whether HEADER exists, giving a warning if it cannot be compiled using # the include files in INCLUDES and setting the cache variable VAR # accordingly. ac_fn_c_check_header_mongrel () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if eval \${$3+:} false; then : { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } else # Is the header compilable? { $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 usability" >&5 $as_echo_n "checking $2 usability... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 #include <$2> _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_header_compiler=yes else ac_header_compiler=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_compiler" >&5 $as_echo "$ac_header_compiler" >&6; } # Is the header present? { $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 presence" >&5 $as_echo_n "checking $2 presence... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include <$2> _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : ac_header_preproc=yes else ac_header_preproc=no fi rm -f conftest.err conftest.i conftest.$ac_ext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5 $as_echo "$ac_header_preproc" >&6; } # So? What about this header? case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in #(( yes:no: ) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&5 $as_echo "$as_me: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 $as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} ;; no:yes:* ) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: present but cannot be compiled" >&5 $as_echo "$as_me: WARNING: $2: present but cannot be compiled" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: check for missing prerequisite headers?" >&5 $as_echo "$as_me: WARNING: $2: check for missing prerequisite headers?" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: see the Autoconf documentation" >&5 $as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&5 $as_echo "$as_me: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 $as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} ( $as_echo "## ------------------------------------------- ## ## Report this to core-dev@pf.itd.nrl.navy.mil ## ## ------------------------------------------- ##" ) | sed "s/^/$as_me: WARNING: /" >&2 ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else eval "$3=\$ac_header_compiler" fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_header_mongrel # ac_fn_c_try_run LINENO # ---------------------- # Try to link conftest.$ac_ext, and return whether this succeeded. Assumes # that executables *can* be run. ac_fn_c_try_run () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { ac_try='./conftest$ac_exeext' { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; }; then : ac_retval=0 else $as_echo "$as_me: program exited with status $ac_status" >&5 $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=$ac_status fi rm -rf conftest.dSYM conftest_ipa8_conftest.oo eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_run # ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES # ------------------------------------------------------- # Tests whether HEADER exists and can be compiled using the include files in # INCLUDES, setting the cache variable VAR accordingly. ac_fn_c_check_header_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 #include <$2> _ACEOF if ac_fn_c_try_compile "$LINENO"; then : eval "$3=yes" else eval "$3=no" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_header_compile # ac_fn_c_find_intX_t LINENO BITS VAR # ----------------------------------- # Finds a signed integer type with width BITS, setting cache variable VAR # accordingly. ac_fn_c_find_intX_t () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for int$2_t" >&5 $as_echo_n "checking for int$2_t... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else eval "$3=no" # Order is important - never check a type that is potentially smaller # than half of the expected target width. for ac_type in int$2_t 'int' 'long int' \ 'long long int' 'short int' 'signed char'; do cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_includes_default enum { N = $2 / 2 - 1 }; int main () { static int test_array [1 - 2 * !(0 < ($ac_type) ((((($ac_type) 1 << N) << N) - 1) * 2 + 1))]; test_array [0] = 0; return test_array [0]; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_includes_default enum { N = $2 / 2 - 1 }; int main () { static int test_array [1 - 2 * !(($ac_type) ((((($ac_type) 1 << N) << N) - 1) * 2 + 1) < ($ac_type) ((((($ac_type) 1 << N) << N) - 1) * 2 + 2))]; test_array [0] = 0; return test_array [0]; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : else case $ac_type in #( int$2_t) : eval "$3=yes" ;; #( *) : eval "$3=\$ac_type" ;; esac fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext if eval test \"x\$"$3"\" = x"no"; then : else break fi done fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_find_intX_t # ac_fn_c_check_type LINENO TYPE VAR INCLUDES # ------------------------------------------- # Tests whether TYPE exists after having included INCLUDES, setting cache # variable VAR accordingly. ac_fn_c_check_type () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else eval "$3=no" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main () { if (sizeof ($2)) return 0; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 int main () { if (sizeof (($2))) return 0; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : else eval "$3=yes" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_type # ac_fn_c_find_uintX_t LINENO BITS VAR # ------------------------------------ # Finds an unsigned integer type with width BITS, setting cache variable VAR # accordingly. ac_fn_c_find_uintX_t () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for uint$2_t" >&5 $as_echo_n "checking for uint$2_t... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else eval "$3=no" # Order is important - never check a type that is potentially smaller # than half of the expected target width. for ac_type in uint$2_t 'unsigned int' 'unsigned long int' \ 'unsigned long long int' 'unsigned short int' 'unsigned char'; do cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_includes_default int main () { static int test_array [1 - 2 * !((($ac_type) -1 >> ($2 / 2 - 1)) >> ($2 / 2 - 1) == 3)]; test_array [0] = 0; return test_array [0]; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : case $ac_type in #( uint$2_t) : eval "$3=yes" ;; #( *) : eval "$3=\$ac_type" ;; esac fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext if eval test \"x\$"$3"\" = x"no"; then : else break fi done fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_find_uintX_t # ac_fn_c_check_func LINENO FUNC VAR # ---------------------------------- # Tests whether FUNC exists, setting the cache variable VAR accordingly ac_fn_c_check_func () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Define $2 to an innocuous variant, in case declares $2. For example, HP-UX 11i declares gettimeofday. */ #define $2 innocuous_$2 /* System header to define __stub macros and hopefully few prototypes, which can conflict with char $2 (); below. Prefer to if __STDC__ is defined, since exists even on freestanding compilers. */ #ifdef __STDC__ # include #else # include #endif #undef $2 /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char $2 (); /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined __stub_$2 || defined __stub___$2 choke me #endif int main () { return $2 (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : eval "$3=yes" else eval "$3=no" fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_func cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. It was created by core $as_me 4.8, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ _ACEOF exec 5>>config.log { cat <<_ASUNAME ## --------- ## ## Platform. ## ## --------- ## hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` uname -m = `(uname -m) 2>/dev/null || echo unknown` uname -r = `(uname -r) 2>/dev/null || echo unknown` uname -s = `(uname -s) 2>/dev/null || echo unknown` uname -v = `(uname -v) 2>/dev/null || echo unknown` /usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` /bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` /bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` /usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` /bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` /bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` _ASUNAME as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. $as_echo "PATH: $as_dir" done IFS=$as_save_IFS } >&5 cat >&5 <<_ACEOF ## ----------- ## ## Core tests. ## ## ----------- ## _ACEOF # Keep a trace of the command line. # Strip out --no-create and --no-recursion so they do not pile up. # Strip out --silent because we don't want to record it for future runs. # Also quote any args containing shell meta-characters. # Make two passes to allow for proper duplicate-argument suppression. ac_configure_args= ac_configure_args0= ac_configure_args1= ac_must_keep_next=false for ac_pass in 1 2 do for ac_arg do case $ac_arg in -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) continue ;; *\'*) ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; esac case $ac_pass in 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;; 2) as_fn_append ac_configure_args1 " '$ac_arg'" if test $ac_must_keep_next = true; then ac_must_keep_next=false # Got value, back to normal. else case $ac_arg in *=* | --config-cache | -C | -disable-* | --disable-* \ | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ | -with-* | --with-* | -without-* | --without-* | --x) case "$ac_configure_args0 " in "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; esac ;; -* ) ac_must_keep_next=true ;; esac fi as_fn_append ac_configure_args " '$ac_arg'" ;; esac done done { ac_configure_args0=; unset ac_configure_args0;} { ac_configure_args1=; unset ac_configure_args1;} # When interrupted or exit'd, cleanup temporary files, and complete # config.log. We remove comments because anyway the quotes in there # would cause problems or look ugly. # WARNING: Use '\'' to represent an apostrophe within the trap. # WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. trap 'exit_status=$? # Save into config.log some information that might help in debugging. { echo $as_echo "## ---------------- ## ## Cache variables. ## ## ---------------- ##" echo # The following way of writing the cache mishandles newlines in values, ( for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #( *${as_nl}ac_space=\ *) sed -n \ "s/'\''/'\''\\\\'\'''\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p" ;; #( *) sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) echo $as_echo "## ----------------- ## ## Output variables. ## ## ----------------- ##" echo for ac_var in $ac_subst_vars do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac $as_echo "$ac_var='\''$ac_val'\''" done | sort echo if test -n "$ac_subst_files"; then $as_echo "## ------------------- ## ## File substitutions. ## ## ------------------- ##" echo for ac_var in $ac_subst_files do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac $as_echo "$ac_var='\''$ac_val'\''" done | sort echo fi if test -s confdefs.h; then $as_echo "## ----------- ## ## confdefs.h. ## ## ----------- ##" echo cat confdefs.h echo fi test "$ac_signal" != 0 && $as_echo "$as_me: caught signal $ac_signal" $as_echo "$as_me: exit $exit_status" } >&5 rm -f core *.core core.conftest.* && rm -f -r conftest* confdefs* conf$$* $ac_clean_files && exit $exit_status ' 0 for ac_signal in 1 2 13 15; do trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal done ac_signal=0 # confdefs.h avoids OS command line length limits that DEFS can exceed. rm -f -r conftest* confdefs.h $as_echo "/* confdefs.h */" > confdefs.h # Predefined preprocessor variables. cat >>confdefs.h <<_ACEOF #define PACKAGE_NAME "$PACKAGE_NAME" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_TARNAME "$PACKAGE_TARNAME" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_VERSION "$PACKAGE_VERSION" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_STRING "$PACKAGE_STRING" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_URL "$PACKAGE_URL" _ACEOF # Let the site file select an alternate cache file if it wants to. # Prefer an explicitly selected file to automatically selected ones. ac_site_file1=NONE ac_site_file2=NONE if test -n "$CONFIG_SITE"; then # We do not want a PATH search for config.site. case $CONFIG_SITE in #(( -*) ac_site_file1=./$CONFIG_SITE;; */*) ac_site_file1=$CONFIG_SITE;; *) ac_site_file1=./$CONFIG_SITE;; esac elif test "x$prefix" != xNONE; then ac_site_file1=$prefix/share/config.site ac_site_file2=$prefix/etc/config.site else ac_site_file1=$ac_default_prefix/share/config.site ac_site_file2=$ac_default_prefix/etc/config.site fi for ac_site_file in "$ac_site_file1" "$ac_site_file2" do test "x$ac_site_file" = xNONE && continue if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 $as_echo "$as_me: loading site script $ac_site_file" >&6;} sed 's/^/| /' "$ac_site_file" >&5 . "$ac_site_file" \ || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "failed to load site script $ac_site_file See \`config.log' for more details" "$LINENO" 5; } fi done if test -r "$cache_file"; then # Some versions of bash will fail to source /dev/null (special files # actually), so we avoid doing that. DJGPP emulates it as a regular file. if test /dev/null != "$cache_file" && test -f "$cache_file"; then { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 $as_echo "$as_me: loading cache $cache_file" >&6;} case $cache_file in [\\/]* | ?:[\\/]* ) . "$cache_file";; *) . "./$cache_file";; esac fi else { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 $as_echo "$as_me: creating cache $cache_file" >&6;} >$cache_file fi # Check that the precious variables saved in the cache have kept the same # value. ac_cache_corrupted=false for ac_var in $ac_precious_vars; do eval ac_old_set=\$ac_cv_env_${ac_var}_set eval ac_new_set=\$ac_env_${ac_var}_set eval ac_old_val=\$ac_cv_env_${ac_var}_value eval ac_new_val=\$ac_env_${ac_var}_value case $ac_old_set,$ac_new_set in set,) { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 $as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} ac_cache_corrupted=: ;; ,set) { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 $as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} ac_cache_corrupted=: ;; ,);; *) if test "x$ac_old_val" != "x$ac_new_val"; then # differences in whitespace do not lead to failure. ac_old_val_w=`echo x $ac_old_val` ac_new_val_w=`echo x $ac_new_val` if test "$ac_old_val_w" != "$ac_new_val_w"; then { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 $as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} ac_cache_corrupted=: else { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 $as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} eval $ac_var=\$ac_old_val fi { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 $as_echo "$as_me: former value: \`$ac_old_val'" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 $as_echo "$as_me: current value: \`$ac_new_val'" >&2;} fi;; esac # Pass precious variables to config.status. if test "$ac_new_set" = set; then case $ac_new_val in *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; *) ac_arg=$ac_var=$ac_new_val ;; esac case " $ac_configure_args " in *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. *) as_fn_append ac_configure_args " '$ac_arg'" ;; esac fi done if $ac_cache_corrupted; then { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 $as_echo "$as_me: error: changes in the environment can compromise the build" >&2;} as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5 fi ## -------------------- ## ## Main body of script. ## ## -------------------- ## ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu VERSION=$PACKAGE_VERSION CORE_VERSION=$PACKAGE_VERSION CORE_VERSION_DATE=20150605 COREDPY_VERSION=$PACKAGE_VERSION # # autoconf and automake initialization # ac_aux_dir= for ac_dir in config "$srcdir"/config; do if test -f "$ac_dir/install-sh"; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/install-sh -c" break elif test -f "$ac_dir/install.sh"; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/install.sh -c" break elif test -f "$ac_dir/shtool"; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/shtool install -c" break fi done if test -z "$ac_aux_dir"; then as_fn_error $? "cannot find install-sh, install.sh, or shtool in config \"$srcdir\"/config" "$LINENO" 5 fi # These three variables are undocumented and unsupported, # and are intended to be withdrawn in a future Autoconf release. # They can cause serious problems if a builder's source tree is in a directory # whose full name contains unusual characters. ac_config_guess="$SHELL $ac_aux_dir/config.guess" # Please don't use this var. ac_config_sub="$SHELL $ac_aux_dir/config.sub" # Please don't use this var. ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var. ac_config_headers="$ac_config_headers config.h" am__api_version='1.13' # Find a good install program. We prefer a C program (faster), # so one script is as good as another. But avoid the broken or # incompatible versions: # SysV /etc/install, /usr/sbin/install # SunOS /usr/etc/install # IRIX /sbin/install # AIX /bin/install # AmigaOS /C/install, which installs bootblocks on floppy discs # AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag # AFS /usr/afsws/bin/install, which mishandles nonexistent args # SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" # OS/2's system install, which has a completely different semantic # ./install, which can be erroneously created by make from ./install.sh. # Reject install programs that cannot install multiple files. { $as_echo "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5 $as_echo_n "checking for a BSD-compatible install... " >&6; } if test -z "$INSTALL"; then if ${ac_cv_path_install+:} false; then : $as_echo_n "(cached) " >&6 else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. # Account for people who put trailing slashes in PATH elements. case $as_dir/ in #(( ./ | .// | /[cC]/* | \ /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ ?:[\\/]os2[\\/]install[\\/]* | ?:[\\/]OS2[\\/]INSTALL[\\/]* | \ /usr/ucb/* ) ;; *) # OSF1 and SCO ODT 3.0 have their own names for install. # Don't use installbsd from OSF since it installs stuff as root # by default. for ac_prog in ginstall scoinst install; do for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext"; then if test $ac_prog = install && grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then # AIX install. It has an incompatible calling convention. : elif test $ac_prog = install && grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then # program-specific install script used by HP pwplus--don't use. : else rm -rf conftest.one conftest.two conftest.dir echo one > conftest.one echo two > conftest.two mkdir conftest.dir if "$as_dir/$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir" && test -s conftest.one && test -s conftest.two && test -s conftest.dir/conftest.one && test -s conftest.dir/conftest.two then ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c" break 3 fi fi fi done done ;; esac done IFS=$as_save_IFS rm -rf conftest.one conftest.two conftest.dir fi if test "${ac_cv_path_install+set}" = set; then INSTALL=$ac_cv_path_install else # As a last resort, use the slow shell script. Don't cache a # value for INSTALL within a source directory, because that will # break other packages using the cache if that directory is # removed, or if the value is a relative name. INSTALL=$ac_install_sh fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5 $as_echo "$INSTALL" >&6; } # Use test -z because SunOS4 sh mishandles braces in ${var-val}. # It thinks the first close brace ends the variable substitution. test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether build environment is sane" >&5 $as_echo_n "checking whether build environment is sane... " >&6; } # Reject unsafe characters in $srcdir or the absolute working directory # name. Accept space and tab only in the latter. am_lf=' ' case `pwd` in *[\\\"\#\$\&\'\`$am_lf]*) as_fn_error $? "unsafe absolute working directory name" "$LINENO" 5;; esac case $srcdir in *[\\\"\#\$\&\'\`$am_lf\ \ ]*) as_fn_error $? "unsafe srcdir value: '$srcdir'" "$LINENO" 5;; esac # Do 'set' in a subshell so we don't clobber the current shell's # arguments. Must try -L first in case configure is actually a # symlink; some systems play weird games with the mod time of symlinks # (eg FreeBSD returns the mod time of the symlink's containing # directory). if ( am_has_slept=no for am_try in 1 2; do echo "timestamp, slept: $am_has_slept" > conftest.file set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null` if test "$*" = "X"; then # -L didn't work. set X `ls -t "$srcdir/configure" conftest.file` fi if test "$*" != "X $srcdir/configure conftest.file" \ && test "$*" != "X conftest.file $srcdir/configure"; then # If neither matched, then we have a broken ls. This can happen # if, for instance, CONFIG_SHELL is bash and it inherits a # broken ls alias from the environment. This has actually # happened. Such a system could not be considered "sane". as_fn_error $? "ls -t appears to fail. Make sure there is not a broken alias in your environment" "$LINENO" 5 fi if test "$2" = conftest.file || test $am_try -eq 2; then break fi # Just in case. sleep 1 am_has_slept=yes done test "$2" = conftest.file ) then # Ok. : else as_fn_error $? "newly created file is older than distributed files! Check your system clock" "$LINENO" 5 fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } # If we didn't sleep, we still need to ensure time stamps of config.status and # generated files are strictly newer. am_sleep_pid= if grep 'slept: no' conftest.file >/dev/null 2>&1; then ( sleep 1 ) & am_sleep_pid=$! fi rm -f conftest.file test "$program_prefix" != NONE && program_transform_name="s&^&$program_prefix&;$program_transform_name" # Use a double $ so make ignores it. test "$program_suffix" != NONE && program_transform_name="s&\$&$program_suffix&;$program_transform_name" # Double any \ or $. # By default was `s,x,x', remove it if useless. ac_script='s/[\\$]/&&/g;s/;s,x,x,$//' program_transform_name=`$as_echo "$program_transform_name" | sed "$ac_script"` # expand $ac_aux_dir to an absolute path am_aux_dir=`cd $ac_aux_dir && pwd` if test x"${MISSING+set}" != xset; then case $am_aux_dir in *\ * | *\ *) MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;; *) MISSING="\${SHELL} $am_aux_dir/missing" ;; esac fi # Use eval to expand $SHELL if eval "$MISSING --is-lightweight"; then am_missing_run="$MISSING " else am_missing_run= { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: 'missing' script is too old or missing" >&5 $as_echo "$as_me: WARNING: 'missing' script is too old or missing" >&2;} fi if test x"${install_sh}" != xset; then case $am_aux_dir in *\ * | *\ *) install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;; *) install_sh="\${SHELL} $am_aux_dir/install-sh" esac fi # Installed binaries are usually stripped using 'strip' when the user # run "make install-strip". However 'strip' might not be the right # tool to use in cross-compilation environments, therefore Automake # will honor the 'STRIP' environment variable to overrule this program. if test "$cross_compiling" != no; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args. set dummy ${ac_tool_prefix}strip; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_STRIP+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$STRIP"; then ac_cv_prog_STRIP="$STRIP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_STRIP="${ac_tool_prefix}strip" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi STRIP=$ac_cv_prog_STRIP if test -n "$STRIP"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5 $as_echo "$STRIP" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_STRIP"; then ac_ct_STRIP=$STRIP # Extract the first word of "strip", so it can be a program name with args. set dummy strip; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_STRIP+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_STRIP"; then ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_STRIP="strip" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP if test -n "$ac_ct_STRIP"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5 $as_echo "$ac_ct_STRIP" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_STRIP" = x; then STRIP=":" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac STRIP=$ac_ct_STRIP fi else STRIP="$ac_cv_prog_STRIP" fi fi INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for a thread-safe mkdir -p" >&5 $as_echo_n "checking for a thread-safe mkdir -p... " >&6; } if test -z "$MKDIR_P"; then if ${ac_cv_path_mkdir+:} false; then : $as_echo_n "(cached) " >&6 else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/opt/sfw/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in mkdir gmkdir; do for ac_exec_ext in '' $ac_executable_extensions; do as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext" || continue case `"$as_dir/$ac_prog$ac_exec_ext" --version 2>&1` in #( 'mkdir (GNU coreutils) '* | \ 'mkdir (coreutils) '* | \ 'mkdir (fileutils) '4.1*) ac_cv_path_mkdir=$as_dir/$ac_prog$ac_exec_ext break 3;; esac done done done IFS=$as_save_IFS fi test -d ./--version && rmdir ./--version if test "${ac_cv_path_mkdir+set}" = set; then MKDIR_P="$ac_cv_path_mkdir -p" else # As a last resort, use the slow shell script. Don't cache a # value for MKDIR_P within a source directory, because that will # break other packages using the cache if that directory is # removed, or if the value is a relative name. MKDIR_P="$ac_install_sh -d" fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MKDIR_P" >&5 $as_echo "$MKDIR_P" >&6; } for ac_prog in gawk mawk nawk awk do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_AWK+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$AWK"; then ac_cv_prog_AWK="$AWK" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_AWK="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi AWK=$ac_cv_prog_AWK if test -n "$AWK"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AWK" >&5 $as_echo "$AWK" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$AWK" && break done { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} sets \$(MAKE)" >&5 $as_echo_n "checking whether ${MAKE-make} sets \$(MAKE)... " >&6; } set x ${MAKE-make} ac_make=`$as_echo "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'` if eval \${ac_cv_prog_make_${ac_make}_set+:} false; then : $as_echo_n "(cached) " >&6 else cat >conftest.make <<\_ACEOF SHELL = /bin/sh all: @echo '@@@%%%=$(MAKE)=@@@%%%' _ACEOF # GNU make sometimes prints "make[1]: Entering ...", which would confuse us. case `${MAKE-make} -f conftest.make 2>/dev/null` in *@@@%%%=?*=@@@%%%*) eval ac_cv_prog_make_${ac_make}_set=yes;; *) eval ac_cv_prog_make_${ac_make}_set=no;; esac rm -f conftest.make fi if eval test \$ac_cv_prog_make_${ac_make}_set = yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } SET_MAKE= else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } SET_MAKE="MAKE=${MAKE-make}" fi rm -rf .tst 2>/dev/null mkdir .tst 2>/dev/null if test -d .tst; then am__leading_dot=. else am__leading_dot=_ fi rmdir .tst 2>/dev/null # Check whether --enable-silent-rules was given. if test "${enable_silent_rules+set}" = set; then : enableval=$enable_silent_rules; fi case $enable_silent_rules in # ((( yes) AM_DEFAULT_VERBOSITY=0;; no) AM_DEFAULT_VERBOSITY=1;; *) AM_DEFAULT_VERBOSITY=1;; esac am_make=${MAKE-make} { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $am_make supports nested variables" >&5 $as_echo_n "checking whether $am_make supports nested variables... " >&6; } if ${am_cv_make_support_nested_variables+:} false; then : $as_echo_n "(cached) " >&6 else if $as_echo 'TRUE=$(BAR$(V)) BAR0=false BAR1=true V=1 am__doit: @$(TRUE) .PHONY: am__doit' | $am_make -f - >/dev/null 2>&1; then am_cv_make_support_nested_variables=yes else am_cv_make_support_nested_variables=no fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_make_support_nested_variables" >&5 $as_echo "$am_cv_make_support_nested_variables" >&6; } if test $am_cv_make_support_nested_variables = yes; then AM_V='$(V)' AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)' else AM_V=$AM_DEFAULT_VERBOSITY AM_DEFAULT_V=$AM_DEFAULT_VERBOSITY fi AM_BACKSLASH='\' if test "`cd $srcdir && pwd`" != "`pwd`"; then # Use -I$(srcdir) only when $(srcdir) != ., so that make's output # is not polluted with repeated "-I." am__isrc=' -I$(srcdir)' # test to see if srcdir already configured if test -f $srcdir/config.status; then as_fn_error $? "source directory already configured; run \"make distclean\" there first" "$LINENO" 5 fi fi # test whether we have cygpath if test -z "$CYGPATH_W"; then if (cygpath --version) >/dev/null 2>/dev/null; then CYGPATH_W='cygpath -w' else CYGPATH_W=echo fi fi # Define the identity of the package. PACKAGE='core' VERSION='4.8' cat >>confdefs.h <<_ACEOF #define PACKAGE "$PACKAGE" _ACEOF cat >>confdefs.h <<_ACEOF #define VERSION "$VERSION" _ACEOF # Some tools Automake needs. ACLOCAL=${ACLOCAL-"${am_missing_run}aclocal-${am__api_version}"} AUTOCONF=${AUTOCONF-"${am_missing_run}autoconf"} AUTOMAKE=${AUTOMAKE-"${am_missing_run}automake-${am__api_version}"} AUTOHEADER=${AUTOHEADER-"${am_missing_run}autoheader"} MAKEINFO=${MAKEINFO-"${am_missing_run}makeinfo"} # For better backward compatibility. To be removed once Automake 1.9.x # dies out for good. For more background, see: # # mkdir_p='$(MKDIR_P)' # We need awk for the "check" target. The system "awk" is bad on # some platforms. # Always define AMTAR for backward compatibility. Yes, it's still used # in the wild :-( We should find a proper way to deprecate it ... AMTAR='$${TAR-tar}' # We'll loop over all known methods to create a tar archive until one works. _am_tools='gnutar pax cpio none' am__tar='$${TAR-tar} chof - "$$tardir"' am__untar='$${TAR-tar} xf -' # # some of the following directory variables are not expanded at configure-time, # so we have special checks to expand them # # CORE GUI files in LIBDIR # AC_PREFIX_DEFAULT is /usr/local, but not expanded yet if test "x$prefix" = "xNONE" ; then prefix="/usr/local" fi if test "x$exec_prefix" = "xNONE" ; then exec_prefix="$prefix" fi if test "$libdir" = "\${exec_prefix}/lib" ; then libdir="${exec_prefix}/lib" fi if test "$sbindir" = "\${exec_prefix}/sbin" ; then sbindir="${exec_prefix}/sbin" fi if test "$bindir" = "\${exec_prefix}/bin" ; then bindir="${exec_prefix}/bin" fi # this can be /usr/lib or /usr/lib64 LIB_DIR="${libdir}" # don't let the Tcl files install to /usr/lib64/core CORE_LIB_DIR="${prefix}/lib/core" SBINDIR="${sbindir}" BINDIR="${bindir}" # CORE daemon configuration file (core.conf) in CORE_CONF_DIR if test "$sysconfdir" = "\${prefix}/etc" ; then sysconfdir="/etc" CORE_CONF_DIR="/etc/core" else CORE_CONF_DIR="$sysconfdir/core" fi if test "$datarootdir" = "\${prefix}/share" ; then datarootdir="${prefix}/share" fi CORE_DATA_DIR="$datarootdir/core" # CORE GUI configuration files and preferences in CORE_GUI_CONF_DIR # scenario files in ~/.core/configs/ #AC_ARG_VAR(CORE_GUI_CONF_DIR, [GUI configuration directory.]) # Check whether --with-guiconfdir was given. if test "${with_guiconfdir+set}" = set; then : withval=$with_guiconfdir; CORE_GUI_CONF_DIR="$with_guiconfdir" else CORE_GUI_CONF_DIR="\${HOME}/.core" fi # Check whether --enable-gui was given. if test "${enable_gui+set}" = set; then : enableval=$enable_gui; else enable_gui=yes fi # Check whether --enable-daemon was given. if test "${enable_daemon+set}" = set; then : enableval=$enable_daemon; else enable_daemon=yes fi if test "x$enable_daemon" = "xno"; then want_python=no want_bsd=no want_linux_netns=no fi # CORE state files if test "$localstatedir" = "\${prefix}/var" ; then # use /var instead of /usr/local/var (/usr/local/var/log isn't standard) CORE_STATE_DIR="/var" else CORE_STATE_DIR="$localstatedir" fi # default compiler flags # _GNU_SOURCE is defined to get c99 defines for lrint() CFLAGS="$CFLAGS -O3 -Werror -Wall -D_GNU_SOURCE" # debug flags #CFLAGS="$CFLAGS -g -Werror -Wall -D_GNU_SOURCE" # Checks for programs. for ac_prog in gawk mawk nawk awk do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_AWK+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$AWK"; then ac_cv_prog_AWK="$AWK" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_AWK="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi AWK=$ac_cv_prog_AWK if test -n "$AWK"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AWK" >&5 $as_echo "$AWK" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$AWK" && break done ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. set dummy ${ac_tool_prefix}gcc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}gcc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_CC"; then ac_ct_CC=$CC # Extract the first word of "gcc", so it can be a program name with args. set dummy gcc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="gcc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 $as_echo "$ac_ct_CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi else CC="$ac_cv_prog_CC" fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. set dummy ${ac_tool_prefix}cc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}cc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi fi if test -z "$CC"; then # Extract the first word of "cc", so it can be a program name with args. set dummy cc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else ac_prog_rejected=no as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then ac_prog_rejected=yes continue fi ac_cv_prog_CC="cc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS if test $ac_prog_rejected = yes; then # We found a bogon in the path, so make sure we never use it. set dummy $ac_cv_prog_CC shift if test $# != 0; then # We chose a different compiler from the bogus one. # However, it has the same basename, so the bogon will be chosen # first if we set CC to just the basename; use the full file name. shift ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" fi fi fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then for ac_prog in cl.exe do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="$ac_tool_prefix$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$CC" && break done fi if test -z "$CC"; then ac_ct_CC=$CC for ac_prog in cl.exe do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 $as_echo "$ac_ct_CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$ac_ct_CC" && break done if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi fi fi test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "no acceptable C compiler found in \$PATH See \`config.log' for more details" "$LINENO" 5; } # Provide some information about the compiler. $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 set X $ac_compile ac_compiler=$2 for ac_option in --version -v -V -qversion; do { { ac_try="$ac_compiler $ac_option >&5" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compiler $ac_option >&5") 2>conftest.err ac_status=$? if test -s conftest.err; then sed '10a\ ... rest of stderr output deleted ... 10q' conftest.err >conftest.er1 cat conftest.er1 >&5 fi rm -f conftest.er1 conftest.err $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } done cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out" # Try to create an executable without -o first, disregard a.out. # It will help us diagnose broken compilers, and finding out an intuition # of exeext. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5 $as_echo_n "checking whether the C compiler works... " >&6; } ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` # The possible output files: ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*" ac_rmfiles= for ac_file in $ac_files do case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; * ) ac_rmfiles="$ac_rmfiles $ac_file";; esac done rm -f $ac_rmfiles if { { ac_try="$ac_link_default" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link_default") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. # So ignore a value of `no', otherwise this would lead to `EXEEXT = no' # in a Makefile. We should not override ac_cv_exeext if it was cached, # so that the user can short-circuit this test for compilers unknown to # Autoconf. for ac_file in $ac_files '' do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; [ab].out ) # We found the default executable, but exeext='' is most # certainly right. break;; *.* ) if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no; then :; else ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` fi # We set ac_cv_exeext here because the later test for it is not # safe: cross compilers may not add the suffix if given an `-o' # argument, so we may need to know it at that point already. # Even if this section looks crufty: it has the advantage of # actually working. break;; * ) break;; esac done test "$ac_cv_exeext" = no && ac_cv_exeext= else ac_file='' fi if test -z "$ac_file"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "C compiler cannot create executables See \`config.log' for more details" "$LINENO" 5; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 $as_echo_n "checking for C compiler default output file name... " >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 $as_echo "$ac_file" >&6; } ac_exeext=$ac_cv_exeext rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out ac_clean_files=$ac_clean_files_save { $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 $as_echo_n "checking for suffix of executables... " >&6; } if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : # If both `conftest.exe' and `conftest' are `present' (well, observable) # catch `conftest.exe'. For instance with Cygwin, `ls conftest' will # work properly (i.e., refer to `conftest.exe'), while it won't with # `rm'. for ac_file in conftest.exe conftest conftest.*; do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` break;; * ) break;; esac done else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of executables: cannot compile and link See \`config.log' for more details" "$LINENO" 5; } fi rm -f conftest conftest$ac_cv_exeext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 $as_echo "$ac_cv_exeext" >&6; } rm -f conftest.$ac_ext EXEEXT=$ac_cv_exeext ac_exeext=$EXEEXT cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { FILE *f = fopen ("conftest.out", "w"); return ferror (f) || fclose (f) != 0; ; return 0; } _ACEOF ac_clean_files="$ac_clean_files conftest.out" # Check that the compiler produces executables we can run. If not, either # the compiler is broken, or we cross compile. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 $as_echo_n "checking whether we are cross compiling... " >&6; } if test "$cross_compiling" != yes; then { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } if { ac_try='./conftest$ac_cv_exeext' { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; }; then cross_compiling=no else if test "$cross_compiling" = maybe; then cross_compiling=yes else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot run C compiled programs. If you meant to cross compile, use \`--host'. See \`config.log' for more details" "$LINENO" 5; } fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 $as_echo "$cross_compiling" >&6; } rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out ac_clean_files=$ac_clean_files_save { $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 $as_echo_n "checking for suffix of object files... " >&6; } if ${ac_cv_objext+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF rm -f conftest.o conftest.obj if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : for ac_file in conftest.o conftest.obj conftest.*; do test -f "$ac_file" || continue; case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;; *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` break;; esac done else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of object files: cannot compile See \`config.log' for more details" "$LINENO" 5; } fi rm -f conftest.$ac_cv_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 $as_echo "$ac_cv_objext" >&6; } OBJEXT=$ac_cv_objext ac_objext=$OBJEXT { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5 $as_echo_n "checking whether we are using the GNU C compiler... " >&6; } if ${ac_cv_c_compiler_gnu+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { #ifndef __GNUC__ choke me #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_compiler_gnu=yes else ac_compiler_gnu=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_cv_c_compiler_gnu=$ac_compiler_gnu fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 $as_echo "$ac_cv_c_compiler_gnu" >&6; } if test $ac_compiler_gnu = yes; then GCC=yes else GCC= fi ac_test_CFLAGS=${CFLAGS+set} ac_save_CFLAGS=$CFLAGS { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 $as_echo_n "checking whether $CC accepts -g... " >&6; } if ${ac_cv_prog_cc_g+:} false; then : $as_echo_n "(cached) " >&6 else ac_save_c_werror_flag=$ac_c_werror_flag ac_c_werror_flag=yes ac_cv_prog_cc_g=no CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_g=yes else CFLAGS="" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : else ac_c_werror_flag=$ac_save_c_werror_flag CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_g=yes fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_c_werror_flag=$ac_save_c_werror_flag fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 $as_echo "$ac_cv_prog_cc_g" >&6; } if test "$ac_test_CFLAGS" = set; then CFLAGS=$ac_save_CFLAGS elif test $ac_cv_prog_cc_g = yes; then if test "$GCC" = yes; then CFLAGS="-g -O2" else CFLAGS="-g" fi else if test "$GCC" = yes; then CFLAGS="-O2" else CFLAGS= fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5 $as_echo_n "checking for $CC option to accept ISO C89... " >&6; } if ${ac_cv_prog_cc_c89+:} false; then : $as_echo_n "(cached) " >&6 else ac_cv_prog_cc_c89=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include struct stat; /* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ struct buf { int x; }; FILE * (*rcsopen) (struct buf *, struct stat *, int); static char *e (p, i) char **p; int i; { return p[i]; } static char *f (char * (*g) (char **, int), char **p, ...) { char *s; va_list v; va_start (v,p); s = g (p, va_arg (v,int)); va_end (v); return s; } /* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has function prototypes and stuff, but not '\xHH' hex character constants. These don't provoke an error unfortunately, instead are silently treated as 'x'. The following induces an error, until -std is added to get proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an array size at least. It's necessary to write '\x00'==0 to get something that's true only with -std. */ int osf4_cc_array ['\x00' == 0 ? 1 : -1]; /* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters inside strings and character constants. */ #define FOO(x) 'x' int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1]; int test (int i, double x); struct s1 {int (*f) (int a);}; struct s2 {int (*f) (double a);}; int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); int argc; char **argv; int main () { return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; ; return 0; } _ACEOF for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \ -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" do CC="$ac_save_CC $ac_arg" if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_c89=$ac_arg fi rm -f core conftest.err conftest.$ac_objext test "x$ac_cv_prog_cc_c89" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC fi # AC_CACHE_VAL case "x$ac_cv_prog_cc_c89" in x) { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 $as_echo "none needed" >&6; } ;; xno) { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 $as_echo "unsupported" >&6; } ;; *) CC="$CC $ac_cv_prog_cc_c89" { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 $as_echo "$ac_cv_prog_cc_c89" >&6; } ;; esac if test "x$ac_cv_prog_cc_c89" != xno; then : fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu DEPDIR="${am__leading_dot}deps" ac_config_commands="$ac_config_commands depfiles" am_make=${MAKE-make} cat > confinc << 'END' am__doit: @echo this is the am__doit target .PHONY: am__doit END # If we don't find an include directive, just comment out the code. { $as_echo "$as_me:${as_lineno-$LINENO}: checking for style of include used by $am_make" >&5 $as_echo_n "checking for style of include used by $am_make... " >&6; } am__include="#" am__quote= _am_result=none # First try GNU make style include. echo "include confinc" > confmf # Ignore all kinds of additional output from 'make'. case `$am_make -s -f confmf 2> /dev/null` in #( *the\ am__doit\ target*) am__include=include am__quote= _am_result=GNU ;; esac # Now try BSD make style include. if test "$am__include" = "#"; then echo '.include "confinc"' > confmf case `$am_make -s -f confmf 2> /dev/null` in #( *the\ am__doit\ target*) am__include=.include am__quote="\"" _am_result=BSD ;; esac fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $_am_result" >&5 $as_echo "$_am_result" >&6; } rm -f confinc confmf # Check whether --enable-dependency-tracking was given. if test "${enable_dependency_tracking+set}" = set; then : enableval=$enable_dependency_tracking; fi if test "x$enable_dependency_tracking" != xno; then am_depcomp="$ac_aux_dir/depcomp" AMDEPBACKSLASH='\' am__nodep='_no' fi if test "x$enable_dependency_tracking" != xno; then AMDEP_TRUE= AMDEP_FALSE='#' else AMDEP_TRUE='#' AMDEP_FALSE= fi depcc="$CC" am_compiler_list= { $as_echo "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5 $as_echo_n "checking dependency style of $depcc... " >&6; } if ${am_cv_CC_dependencies_compiler_type+:} false; then : $as_echo_n "(cached) " >&6 else if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then # We make a subdir and do the tests there. Otherwise we can end up # making bogus files that we don't know about and never remove. For # instance it was reported that on HP-UX the gcc test will end up # making a dummy file named 'D' -- because '-MD' means "put the output # in D". rm -rf conftest.dir mkdir conftest.dir # Copy depcomp to subdir because otherwise we won't find it if we're # using a relative directory. cp "$am_depcomp" conftest.dir cd conftest.dir # We will build objects and dependencies in a subdirectory because # it helps to detect inapplicable dependency modes. For instance # both Tru64's cc and ICC support -MD to output dependencies as a # side effect of compilation, but ICC will put the dependencies in # the current directory while Tru64 will put them in the object # directory. mkdir sub am_cv_CC_dependencies_compiler_type=none if test "$am_compiler_list" = ""; then am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp` fi am__universal=false case " $depcc " in #( *\ -arch\ *\ -arch\ *) am__universal=true ;; esac for depmode in $am_compiler_list; do # Setup a source with many dependencies, because some compilers # like to wrap large dependency lists on column 80 (with \), and # we should not choose a depcomp mode which is confused by this. # # We need to recreate these files for each test, as the compiler may # overwrite some of them when testing with obscure command lines. # This happens at least with the AIX C compiler. : > sub/conftest.c for i in 1 2 3 4 5 6; do echo '#include "conftst'$i'.h"' >> sub/conftest.c # Using ": > sub/conftst$i.h" creates only sub/conftst1.h with # Solaris 10 /bin/sh. echo '/* dummy */' > sub/conftst$i.h done echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf # We check with '-c' and '-o' for the sake of the "dashmstdout" # mode. It turns out that the SunPro C++ compiler does not properly # handle '-M -o', and we need to detect this. Also, some Intel # versions had trouble with output in subdirs. am__obj=sub/conftest.${OBJEXT-o} am__minus_obj="-o $am__obj" case $depmode in gcc) # This depmode causes a compiler race in universal mode. test "$am__universal" = false || continue ;; nosideeffect) # After this tag, mechanisms are not by side-effect, so they'll # only be used when explicitly requested. if test "x$enable_dependency_tracking" = xyes; then continue else break fi ;; msvc7 | msvc7msys | msvisualcpp | msvcmsys) # This compiler won't grok '-c -o', but also, the minuso test has # not run yet. These depmodes are late enough in the game, and # so weak that their functioning should not be impacted. am__obj=conftest.${OBJEXT-o} am__minus_obj= ;; none) break ;; esac if depmode=$depmode \ source=sub/conftest.c object=$am__obj \ depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ >/dev/null 2>conftest.err && grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && grep $am__obj sub/conftest.Po > /dev/null 2>&1 && ${MAKE-make} -s -f confmf > /dev/null 2>&1; then # icc doesn't choke on unknown options, it will just issue warnings # or remarks (even with -Werror). So we grep stderr for any message # that says an option was ignored or not supported. # When given -MP, icc 7.0 and 7.1 complain thusly: # icc: Command line warning: ignoring option '-M'; no argument required # The diagnosis changed in icc 8.0: # icc: Command line remark: option '-MP' not supported if (grep 'ignoring option' conftest.err || grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else am_cv_CC_dependencies_compiler_type=$depmode break fi fi done cd .. rm -rf conftest.dir else am_cv_CC_dependencies_compiler_type=none fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_CC_dependencies_compiler_type" >&5 $as_echo "$am_cv_CC_dependencies_compiler_type" >&6; } CCDEPMODE=depmode=$am_cv_CC_dependencies_compiler_type if test "x$enable_dependency_tracking" != xno \ && test "$am_cv_CC_dependencies_compiler_type" = gcc3; then am__fastdepCC_TRUE= am__fastdepCC_FALSE='#' else am__fastdepCC_TRUE='#' am__fastdepCC_FALSE= fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} sets \$(MAKE)" >&5 $as_echo_n "checking whether ${MAKE-make} sets \$(MAKE)... " >&6; } set x ${MAKE-make} ac_make=`$as_echo "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'` if eval \${ac_cv_prog_make_${ac_make}_set+:} false; then : $as_echo_n "(cached) " >&6 else cat >conftest.make <<\_ACEOF SHELL = /bin/sh all: @echo '@@@%%%=$(MAKE)=@@@%%%' _ACEOF # GNU make sometimes prints "make[1]: Entering ...", which would confuse us. case `${MAKE-make} -f conftest.make 2>/dev/null` in *@@@%%%=?*=@@@%%%*) eval ac_cv_prog_make_${ac_make}_set=yes;; *) eval ac_cv_prog_make_${ac_make}_set=no;; esac rm -f conftest.make fi if eval test \$ac_cv_prog_make_${ac_make}_set = yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } SET_MAKE= else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } SET_MAKE="MAKE=${MAKE-make}" fi if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args. set dummy ${ac_tool_prefix}ranlib; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_RANLIB+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$RANLIB"; then ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi RANLIB=$ac_cv_prog_RANLIB if test -n "$RANLIB"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RANLIB" >&5 $as_echo "$RANLIB" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_RANLIB"; then ac_ct_RANLIB=$RANLIB # Extract the first word of "ranlib", so it can be a program name with args. set dummy ranlib; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_RANLIB+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_RANLIB"; then ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_RANLIB="ranlib" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB if test -n "$ac_ct_RANLIB"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RANLIB" >&5 $as_echo "$ac_ct_RANLIB" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_RANLIB" = x; then RANLIB=":" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac RANLIB=$ac_ct_RANLIB fi else RANLIB="$ac_cv_prog_RANLIB" fi if test -n "$PYTHON"; then # If the user set $PYTHON, use it and don't search something else. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $PYTHON version is >= 2.6" >&5 $as_echo_n "checking whether $PYTHON version is >= 2.6... " >&6; } prog="import sys # split strings by '.' and convert to numeric. Append some zeros # because we need at least 4 digits for the hex conversion. # map returns an iterator in Python 3.0 and a list in 2.x minver = list(map(int, '2.6'.split('.'))) + [0, 0, 0] minverhex = 0 # xrange is not present in Python 3.0 and range returns an iterator for i in list(range(0, 4)): minverhex = (minverhex << 8) + minver[i] sys.exit(sys.hexversion < minverhex)" if { echo "$as_me:$LINENO: $PYTHON -c "$prog"" >&5 ($PYTHON -c "$prog") >&5 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } as_fn_error $? "Python interpreter is too old" "$LINENO" 5 fi am_display_PYTHON=$PYTHON else # Otherwise, try each interpreter until we find one that satisfies # VERSION. { $as_echo "$as_me:${as_lineno-$LINENO}: checking for a Python interpreter with version >= 2.6" >&5 $as_echo_n "checking for a Python interpreter with version >= 2.6... " >&6; } if ${am_cv_pathless_PYTHON+:} false; then : $as_echo_n "(cached) " >&6 else for am_cv_pathless_PYTHON in python python2 python3 python3.3 python3.2 python3.1 python3.0 python2.7 python2.6 python2.5 python2.4 python2.3 python2.2 python2.1 python2.0 none; do test "$am_cv_pathless_PYTHON" = none && break prog="import sys # split strings by '.' and convert to numeric. Append some zeros # because we need at least 4 digits for the hex conversion. # map returns an iterator in Python 3.0 and a list in 2.x minver = list(map(int, '2.6'.split('.'))) + [0, 0, 0] minverhex = 0 # xrange is not present in Python 3.0 and range returns an iterator for i in list(range(0, 4)): minverhex = (minverhex << 8) + minver[i] sys.exit(sys.hexversion < minverhex)" if { echo "$as_me:$LINENO: $am_cv_pathless_PYTHON -c "$prog"" >&5 ($am_cv_pathless_PYTHON -c "$prog") >&5 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; then : break fi done fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_pathless_PYTHON" >&5 $as_echo "$am_cv_pathless_PYTHON" >&6; } # Set $PYTHON to the absolute path of $am_cv_pathless_PYTHON. if test "$am_cv_pathless_PYTHON" = none; then PYTHON=: else # Extract the first word of "$am_cv_pathless_PYTHON", so it can be a program name with args. set dummy $am_cv_pathless_PYTHON; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_path_PYTHON+:} false; then : $as_echo_n "(cached) " >&6 else case $PYTHON in [\\/]* | ?:[\\/]*) ac_cv_path_PYTHON="$PYTHON" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_path_PYTHON="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi PYTHON=$ac_cv_path_PYTHON if test -n "$PYTHON"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PYTHON" >&5 $as_echo "$PYTHON" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi am_display_PYTHON=$am_cv_pathless_PYTHON fi if test "$PYTHON" = :; then want_python=no else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $am_display_PYTHON version" >&5 $as_echo_n "checking for $am_display_PYTHON version... " >&6; } if ${am_cv_python_version+:} false; then : $as_echo_n "(cached) " >&6 else am_cv_python_version=`$PYTHON -c "import sys; sys.stdout.write(sys.version[:3])"` fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_python_version" >&5 $as_echo "$am_cv_python_version" >&6; } PYTHON_VERSION=$am_cv_python_version PYTHON_PREFIX='${prefix}' PYTHON_EXEC_PREFIX='${exec_prefix}' { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $am_display_PYTHON platform" >&5 $as_echo_n "checking for $am_display_PYTHON platform... " >&6; } if ${am_cv_python_platform+:} false; then : $as_echo_n "(cached) " >&6 else am_cv_python_platform=`$PYTHON -c "import sys; sys.stdout.write(sys.platform)"` fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_python_platform" >&5 $as_echo "$am_cv_python_platform" >&6; } PYTHON_PLATFORM=$am_cv_python_platform # Just factor out some code duplication. am_python_setup_sysconfig="\ import sys # Prefer sysconfig over distutils.sysconfig, for better compatibility # with python 3.x. See automake bug#10227. try: import sysconfig except ImportError: can_use_sysconfig = 0 else: can_use_sysconfig = 1 # Can't use sysconfig in CPython 2.7, since it's broken in virtualenvs: # try: from platform import python_implementation if python_implementation() == 'CPython' and sys.version[:3] == '2.7': can_use_sysconfig = 0 except ImportError: pass" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $am_display_PYTHON script directory" >&5 $as_echo_n "checking for $am_display_PYTHON script directory... " >&6; } if ${am_cv_python_pythondir+:} false; then : $as_echo_n "(cached) " >&6 else if test "x$prefix" = xNONE then am_py_prefix=$ac_default_prefix else am_py_prefix=$prefix fi am_cv_python_pythondir=`$PYTHON -c " $am_python_setup_sysconfig if can_use_sysconfig: sitedir = sysconfig.get_path('purelib', vars={'base':'$am_py_prefix'}) else: from distutils import sysconfig sitedir = sysconfig.get_python_lib(0, 0, prefix='$am_py_prefix') sys.stdout.write(sitedir)"` case $am_cv_python_pythondir in $am_py_prefix*) am__strip_prefix=`echo "$am_py_prefix" | sed 's|.|.|g'` am_cv_python_pythondir=`echo "$am_cv_python_pythondir" | sed "s,^$am__strip_prefix,$PYTHON_PREFIX,"` ;; *) case $am_py_prefix in /usr|/System*) ;; *) am_cv_python_pythondir=$PYTHON_PREFIX/lib/python$PYTHON_VERSION/site-packages ;; esac ;; esac fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_python_pythondir" >&5 $as_echo "$am_cv_python_pythondir" >&6; } pythondir=$am_cv_python_pythondir pkgpythondir=\${pythondir}/$PACKAGE { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $am_display_PYTHON extension module directory" >&5 $as_echo_n "checking for $am_display_PYTHON extension module directory... " >&6; } if ${am_cv_python_pyexecdir+:} false; then : $as_echo_n "(cached) " >&6 else if test "x$exec_prefix" = xNONE then am_py_exec_prefix=$am_py_prefix else am_py_exec_prefix=$exec_prefix fi am_cv_python_pyexecdir=`$PYTHON -c " $am_python_setup_sysconfig if can_use_sysconfig: sitedir = sysconfig.get_path('platlib', vars={'platbase':'$am_py_prefix'}) else: from distutils import sysconfig sitedir = sysconfig.get_python_lib(1, 0, prefix='$am_py_prefix') sys.stdout.write(sitedir)"` case $am_cv_python_pyexecdir in $am_py_exec_prefix*) am__strip_prefix=`echo "$am_py_exec_prefix" | sed 's|.|.|g'` am_cv_python_pyexecdir=`echo "$am_cv_python_pyexecdir" | sed "s,^$am__strip_prefix,$PYTHON_EXEC_PREFIX,"` ;; *) case $am_py_exec_prefix in /usr|/System*) ;; *) am_cv_python_pyexecdir=$PYTHON_EXEC_PREFIX/lib/python$PYTHON_VERSION/site-packages ;; esac ;; esac fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_python_pyexecdir" >&5 $as_echo "$am_cv_python_pyexecdir" >&6; } pyexecdir=$am_cv_python_pyexecdir pkgpyexecdir=\${pyexecdir}/$PACKAGE want_python=yes fi SEARCHPATH="/usr/sbin:/usr/bin:/sbin:/bin:/usr/local/sbin:/usr/local/bin" # # daemon dependencies # if test "x$enable_daemon" = "xyes" ; then # Extract the first word of "brctl", so it can be a program name with args. set dummy brctl; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_brctl_path+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$brctl_path"; then ac_cv_prog_brctl_path="$brctl_path" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $SEARCHPATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_brctl_path="$as_dir" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS test -z "$ac_cv_prog_brctl_path" && ac_cv_prog_brctl_path="no" fi fi brctl_path=$ac_cv_prog_brctl_path if test -n "$brctl_path"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $brctl_path" >&5 $as_echo "$brctl_path" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi # Extract the first word of "sysctl", so it can be a program name with args. set dummy sysctl; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_sysctl_path+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$sysctl_path"; then ac_cv_prog_sysctl_path="$sysctl_path" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $SEARCHPATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_sysctl_path="$as_dir" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS test -z "$ac_cv_prog_sysctl_path" && ac_cv_prog_sysctl_path="no" fi fi sysctl_path=$ac_cv_prog_sysctl_path if test -n "$sysctl_path"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $sysctl_path" >&5 $as_echo "$sysctl_path" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi # Extract the first word of "ebtables", so it can be a program name with args. set dummy ebtables; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ebtables_path+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ebtables_path"; then ac_cv_prog_ebtables_path="$ebtables_path" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $SEARCHPATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ebtables_path="$as_dir" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS test -z "$ac_cv_prog_ebtables_path" && ac_cv_prog_ebtables_path="no" fi fi ebtables_path=$ac_cv_prog_ebtables_path if test -n "$ebtables_path"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ebtables_path" >&5 $as_echo "$ebtables_path" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi # Extract the first word of "ip", so it can be a program name with args. set dummy ip; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ip_path+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ip_path"; then ac_cv_prog_ip_path="$ip_path" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $SEARCHPATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ip_path="$as_dir" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS test -z "$ac_cv_prog_ip_path" && ac_cv_prog_ip_path="no" fi fi ip_path=$ac_cv_prog_ip_path if test -n "$ip_path"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ip_path" >&5 $as_echo "$ip_path" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi # Extract the first word of "tc", so it can be a program name with args. set dummy tc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_tc_path+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$tc_path"; then ac_cv_prog_tc_path="$tc_path" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $SEARCHPATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_tc_path="$as_dir" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS test -z "$ac_cv_prog_tc_path" && ac_cv_prog_tc_path="no" fi fi tc_path=$ac_cv_prog_tc_path if test -n "$tc_path"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $tc_path" >&5 $as_echo "$tc_path" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi # Extract the first word of "ifconfig", so it can be a program name with args. set dummy ifconfig; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ifconfig_path+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ifconfig_path"; then ac_cv_prog_ifconfig_path="$ifconfig_path" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $SEARCHPATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ifconfig_path="$as_dir" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS test -z "$ac_cv_prog_ifconfig_path" && ac_cv_prog_ifconfig_path="no" fi fi ifconfig_path=$ac_cv_prog_ifconfig_path if test -n "$ifconfig_path"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ifconfig_path" >&5 $as_echo "$ifconfig_path" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi # Extract the first word of "ngctl", so it can be a program name with args. set dummy ngctl; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ngctl_path+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ngctl_path"; then ac_cv_prog_ngctl_path="$ngctl_path" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $SEARCHPATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ngctl_path="$as_dir" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS test -z "$ac_cv_prog_ngctl_path" && ac_cv_prog_ngctl_path="no" fi fi ngctl_path=$ac_cv_prog_ngctl_path if test -n "$ngctl_path"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ngctl_path" >&5 $as_echo "$ngctl_path" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi # Extract the first word of "vimage", so it can be a program name with args. set dummy vimage; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_vimage_path+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$vimage_path"; then ac_cv_prog_vimage_path="$vimage_path" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $SEARCHPATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_vimage_path="$as_dir" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS test -z "$ac_cv_prog_vimage_path" && ac_cv_prog_vimage_path="no" fi fi vimage_path=$ac_cv_prog_vimage_path if test -n "$vimage_path"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $vimage_path" >&5 $as_echo "$vimage_path" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi # Extract the first word of "mount", so it can be a program name with args. set dummy mount; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_mount_path+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$mount_path"; then ac_cv_prog_mount_path="$mount_path" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $SEARCHPATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_mount_path="$as_dir" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS test -z "$ac_cv_prog_mount_path" && ac_cv_prog_mount_path="no" fi fi mount_path=$ac_cv_prog_mount_path if test -n "$mount_path"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $mount_path" >&5 $as_echo "$mount_path" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi # Extract the first word of "umount", so it can be a program name with args. set dummy umount; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_umount_path+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$umount_path"; then ac_cv_prog_umount_path="$umount_path" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $SEARCHPATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_umount_path="$as_dir" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS test -z "$ac_cv_prog_umount_path" && ac_cv_prog_umount_path="no" fi fi umount_path=$ac_cv_prog_umount_path if test -n "$umount_path"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $umount_path" >&5 $as_echo "$umount_path" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi # Extract the first word of "convert", so it can be a program name with args. set dummy convert; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_convert+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$convert"; then ac_cv_prog_convert="$convert" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $SEARCHPATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_convert="yes" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS test -z "$ac_cv_prog_convert" && ac_cv_prog_convert="no" fi fi convert=$ac_cv_prog_convert if test -n "$convert"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $convert" >&5 $as_echo "$convert" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi #AC_CHECK_PROG(dia, dia, yes, no) # Extract the first word of "help2man", so it can be a program name with args. set dummy help2man; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_help2man+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$help2man"; then ac_cv_prog_help2man="$help2man" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $SEARCHPATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_help2man="yes" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS test -z "$ac_cv_prog_help2man" && ac_cv_prog_help2man="no" fi fi help2man=$ac_cv_prog_help2man if test -n "$help2man"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $help2man" >&5 $as_echo "$help2man" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$convert" = "xno" ; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Could not locate ImageMagick convert." >&5 $as_echo "$as_me: WARNING: Could not locate ImageMagick convert." >&2;} #want_docs_missing="convert" fi #if test "x$dia" = "xno" ; then # AC_MSG_WARN([Could not locate dia.]) # want_docs_missing="dia" #fi if test "x$help2man" = "xno" ; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Could not locate help2man." >&5 $as_echo "$as_me: WARNING: Could not locate help2man." >&2;} want_docs_missing="$want_docs_missing help2man" fi if test "x$want_docs_missing" = "x" ; then want_docs=yes else { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Could not find required helper utilities (${want_docs_missing}) so the CORE documentation will not be built." >&5 $as_echo "$as_me: WARNING: Could not find required helper utilities (${want_docs_missing}) so the CORE documentation will not be built." >&2;} want_docs=no fi #AC_PATH_PROGS(tcl_path, [tclsh tclsh8.5 tclsh8.4], no) #if test "x$tcl_path" = "xno" ; then # AC_MSG_ERROR([Could not locate tclsh. Please install Tcl/Tk.]) #fi #AC_PATH_PROGS(wish_path, [wish wish8.5 wish8.4], no) #if test "x$wish_path" = "xno" ; then # AC_MSG_ERROR([Could not locate wish. Please install Tcl/Tk.]) #fi if test "x$enable_daemon" = "xyes" ; then # Checks for libraries. { $as_echo "$as_me:${as_lineno-$LINENO}: checking for NgMkSockNode in -lnetgraph" >&5 $as_echo_n "checking for NgMkSockNode in -lnetgraph... " >&6; } if ${ac_cv_lib_netgraph_NgMkSockNode+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lnetgraph $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char NgMkSockNode (); int main () { return NgMkSockNode (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_netgraph_NgMkSockNode=yes else ac_cv_lib_netgraph_NgMkSockNode=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_netgraph_NgMkSockNode" >&5 $as_echo "$ac_cv_lib_netgraph_NgMkSockNode" >&6; } if test "x$ac_cv_lib_netgraph_NgMkSockNode" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBNETGRAPH 1 _ACEOF LIBS="-lnetgraph $LIBS" fi # Checks for header files. ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5 $as_echo_n "checking how to run the C preprocessor... " >&6; } # On Suns, sometimes $CPP names a directory. if test -n "$CPP" && test -d "$CPP"; then CPP= fi if test -z "$CPP"; then if ${ac_cv_prog_CPP+:} false; then : $as_echo_n "(cached) " >&6 else # Double quotes because CPP needs to be expanded for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp" do ac_preproc_ok=false for ac_c_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. # Prefer to if __STDC__ is defined, since # exists even on freestanding compilers. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef __STDC__ # include #else # include #endif Syntax error _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : else # Broken: fails on valid input. continue fi rm -f conftest.err conftest.i conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : # Broken: success on invalid input. continue else # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.i conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.i conftest.err conftest.$ac_ext if $ac_preproc_ok; then : break fi done ac_cv_prog_CPP=$CPP fi CPP=$ac_cv_prog_CPP else ac_cv_prog_CPP=$CPP fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5 $as_echo "$CPP" >&6; } ac_preproc_ok=false for ac_c_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. # Prefer to if __STDC__ is defined, since # exists even on freestanding compilers. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef __STDC__ # include #else # include #endif Syntax error _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : else # Broken: fails on valid input. continue fi rm -f conftest.err conftest.i conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : # Broken: success on invalid input. continue else # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.i conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.i conftest.err conftest.$ac_ext if $ac_preproc_ok; then : else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "C preprocessor \"$CPP\" fails sanity check See \`config.log' for more details" "$LINENO" 5; } fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu { $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5 $as_echo_n "checking for grep that handles long lines and -e... " >&6; } if ${ac_cv_path_GREP+:} false; then : $as_echo_n "(cached) " >&6 else if test -z "$GREP"; then ac_path_GREP_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in grep ggrep; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext" as_fn_executable_p "$ac_path_GREP" || continue # Check for GNU ac_path_GREP and select it if it is found. # Check for GNU $ac_path_GREP case `"$ac_path_GREP" --version 2>&1` in *GNU*) ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;; *) ac_count=0 $as_echo_n 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" $as_echo 'GREP' >> "conftest.nl" "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_GREP_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_GREP_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_GREP"; then as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 fi else ac_cv_path_GREP=$GREP fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5 $as_echo "$ac_cv_path_GREP" >&6; } GREP="$ac_cv_path_GREP" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5 $as_echo_n "checking for egrep... " >&6; } if ${ac_cv_path_EGREP+:} false; then : $as_echo_n "(cached) " >&6 else if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 then ac_cv_path_EGREP="$GREP -E" else if test -z "$EGREP"; then ac_path_EGREP_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in egrep; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext" as_fn_executable_p "$ac_path_EGREP" || continue # Check for GNU ac_path_EGREP and select it if it is found. # Check for GNU $ac_path_EGREP case `"$ac_path_EGREP" --version 2>&1` in *GNU*) ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;; *) ac_count=0 $as_echo_n 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" $as_echo 'EGREP' >> "conftest.nl" "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_EGREP_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_EGREP_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_EGREP"; then as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 fi else ac_cv_path_EGREP=$EGREP fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5 $as_echo "$ac_cv_path_EGREP" >&6; } EGREP="$ac_cv_path_EGREP" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5 $as_echo_n "checking for ANSI C header files... " >&6; } if ${ac_cv_header_stdc+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include #include int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_header_stdc=yes else ac_cv_header_stdc=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext if test $ac_cv_header_stdc = yes; then # SunOS 4.x string.h does not declare mem*, contrary to ANSI. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "memchr" >/dev/null 2>&1; then : else ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "free" >/dev/null 2>&1; then : else ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. if test "$cross_compiling" = yes; then : : else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #if ((' ' & 0x0FF) == 0x020) # define ISLOWER(c) ('a' <= (c) && (c) <= 'z') # define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) #else # define ISLOWER(c) \ (('a' <= (c) && (c) <= 'i') \ || ('j' <= (c) && (c) <= 'r') \ || ('s' <= (c) && (c) <= 'z')) # define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) #endif #define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) int main () { int i; for (i = 0; i < 256; i++) if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) return 2; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : else ac_cv_header_stdc=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5 $as_echo "$ac_cv_header_stdc" >&6; } if test $ac_cv_header_stdc = yes; then $as_echo "#define STDC_HEADERS 1" >>confdefs.h fi # On IRIX 5.3, sys/types and inttypes.h are conflicting. for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \ inttypes.h stdint.h unistd.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default " if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF fi done for ac_header in arpa/inet.h fcntl.h limits.h stdint.h stdlib.h string.h sys/ioctl.h sys/mount.h sys/socket.h sys/time.h termios.h unistd.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF fi done # Checks for typedefs, structures, and compiler characteristics. { $as_echo "$as_me:${as_lineno-$LINENO}: checking for inline" >&5 $as_echo_n "checking for inline... " >&6; } if ${ac_cv_c_inline+:} false; then : $as_echo_n "(cached) " >&6 else ac_cv_c_inline=no for ac_kw in inline __inline__ __inline; do cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifndef __cplusplus typedef int foo_t; static $ac_kw foo_t static_foo () {return 0; } $ac_kw foo_t foo () {return 0; } #endif _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_c_inline=$ac_kw fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext test "$ac_cv_c_inline" != no && break done fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_inline" >&5 $as_echo "$ac_cv_c_inline" >&6; } case $ac_cv_c_inline in inline | yes) ;; *) case $ac_cv_c_inline in no) ac_val=;; *) ac_val=$ac_cv_c_inline;; esac cat >>confdefs.h <<_ACEOF #ifndef __cplusplus #define inline $ac_val #endif _ACEOF ;; esac ac_fn_c_find_intX_t "$LINENO" "32" "ac_cv_c_int32_t" case $ac_cv_c_int32_t in #( no|yes) ;; #( *) cat >>confdefs.h <<_ACEOF #define int32_t $ac_cv_c_int32_t _ACEOF ;; esac ac_fn_c_check_type "$LINENO" "pid_t" "ac_cv_type_pid_t" "$ac_includes_default" if test "x$ac_cv_type_pid_t" = xyes; then : else cat >>confdefs.h <<_ACEOF #define pid_t int _ACEOF fi ac_fn_c_check_type "$LINENO" "size_t" "ac_cv_type_size_t" "$ac_includes_default" if test "x$ac_cv_type_size_t" = xyes; then : else cat >>confdefs.h <<_ACEOF #define size_t unsigned int _ACEOF fi ac_fn_c_check_type "$LINENO" "ssize_t" "ac_cv_type_ssize_t" "$ac_includes_default" if test "x$ac_cv_type_ssize_t" = xyes; then : else cat >>confdefs.h <<_ACEOF #define ssize_t int _ACEOF fi ac_fn_c_find_uintX_t "$LINENO" "32" "ac_cv_c_uint32_t" case $ac_cv_c_uint32_t in #( no|yes) ;; #( *) $as_echo "#define _UINT32_T 1" >>confdefs.h cat >>confdefs.h <<_ACEOF #define uint32_t $ac_cv_c_uint32_t _ACEOF ;; esac ac_fn_c_find_uintX_t "$LINENO" "8" "ac_cv_c_uint8_t" case $ac_cv_c_uint8_t in #( no|yes) ;; #( *) $as_echo "#define _UINT8_T 1" >>confdefs.h cat >>confdefs.h <<_ACEOF #define uint8_t $ac_cv_c_uint8_t _ACEOF ;; esac # Checks for library functions. for ac_header in vfork.h do : ac_fn_c_check_header_mongrel "$LINENO" "vfork.h" "ac_cv_header_vfork_h" "$ac_includes_default" if test "x$ac_cv_header_vfork_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_VFORK_H 1 _ACEOF fi done for ac_func in fork vfork do : as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" if eval test \"x\$"$as_ac_var"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 _ACEOF fi done if test "x$ac_cv_func_fork" = xyes; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for working fork" >&5 $as_echo_n "checking for working fork... " >&6; } if ${ac_cv_func_fork_works+:} false; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : ac_cv_func_fork_works=cross else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_includes_default int main () { /* By Ruediger Kuhlmann. */ return fork () < 0; ; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : ac_cv_func_fork_works=yes else ac_cv_func_fork_works=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_fork_works" >&5 $as_echo "$ac_cv_func_fork_works" >&6; } else ac_cv_func_fork_works=$ac_cv_func_fork fi if test "x$ac_cv_func_fork_works" = xcross; then case $host in *-*-amigaos* | *-*-msdosdjgpp*) # Override, as these systems have only a dummy fork() stub ac_cv_func_fork_works=no ;; *) ac_cv_func_fork_works=yes ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: result $ac_cv_func_fork_works guessed because of cross compilation" >&5 $as_echo "$as_me: WARNING: result $ac_cv_func_fork_works guessed because of cross compilation" >&2;} fi ac_cv_func_vfork_works=$ac_cv_func_vfork if test "x$ac_cv_func_vfork" = xyes; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for working vfork" >&5 $as_echo_n "checking for working vfork... " >&6; } if ${ac_cv_func_vfork_works+:} false; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : ac_cv_func_vfork_works=cross else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Thanks to Paul Eggert for this test. */ $ac_includes_default #include #ifdef HAVE_VFORK_H # include #endif /* On some sparc systems, changes by the child to local and incoming argument registers are propagated back to the parent. The compiler is told about this with #include , but some compilers (e.g. gcc -O) don't grok . Test for this by using a static variable whose address is put into a register that is clobbered by the vfork. */ static void #ifdef __cplusplus sparc_address_test (int arg) # else sparc_address_test (arg) int arg; #endif { static pid_t child; if (!child) { child = vfork (); if (child < 0) { perror ("vfork"); _exit(2); } if (!child) { arg = getpid(); write(-1, "", 0); _exit (arg); } } } int main () { pid_t parent = getpid (); pid_t child; sparc_address_test (0); child = vfork (); if (child == 0) { /* Here is another test for sparc vfork register problems. This test uses lots of local variables, at least as many local variables as main has allocated so far including compiler temporaries. 4 locals are enough for gcc 1.40.3 on a Solaris 4.1.3 sparc, but we use 8 to be safe. A buggy compiler should reuse the register of parent for one of the local variables, since it will think that parent can't possibly be used any more in this routine. Assigning to the local variable will thus munge parent in the parent process. */ pid_t p = getpid(), p1 = getpid(), p2 = getpid(), p3 = getpid(), p4 = getpid(), p5 = getpid(), p6 = getpid(), p7 = getpid(); /* Convince the compiler that p..p7 are live; otherwise, it might use the same hardware register for all 8 local variables. */ if (p != p1 || p != p2 || p != p3 || p != p4 || p != p5 || p != p6 || p != p7) _exit(1); /* On some systems (e.g. IRIX 3.3), vfork doesn't separate parent from child file descriptors. If the child closes a descriptor before it execs or exits, this munges the parent's descriptor as well. Test for this by closing stdout in the child. */ _exit(close(fileno(stdout)) != 0); } else { int status; struct stat st; while (wait(&status) != child) ; return ( /* Was there some problem with vforking? */ child < 0 /* Did the child fail? (This shouldn't happen.) */ || status /* Did the vfork/compiler bug occur? */ || parent != getpid() /* Did the file descriptor bug occur? */ || fstat(fileno(stdout), &st) != 0 ); } } _ACEOF if ac_fn_c_try_run "$LINENO"; then : ac_cv_func_vfork_works=yes else ac_cv_func_vfork_works=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_vfork_works" >&5 $as_echo "$ac_cv_func_vfork_works" >&6; } fi; if test "x$ac_cv_func_fork_works" = xcross; then ac_cv_func_vfork_works=$ac_cv_func_vfork { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: result $ac_cv_func_vfork_works guessed because of cross compilation" >&5 $as_echo "$as_me: WARNING: result $ac_cv_func_vfork_works guessed because of cross compilation" >&2;} fi if test "x$ac_cv_func_vfork_works" = xyes; then $as_echo "#define HAVE_WORKING_VFORK 1" >>confdefs.h else $as_echo "#define vfork fork" >>confdefs.h fi if test "x$ac_cv_func_fork_works" = xyes; then $as_echo "#define HAVE_WORKING_FORK 1" >>confdefs.h fi for ac_header in stdlib.h do : ac_fn_c_check_header_mongrel "$LINENO" "stdlib.h" "ac_cv_header_stdlib_h" "$ac_includes_default" if test "x$ac_cv_header_stdlib_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_STDLIB_H 1 _ACEOF fi done { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU libc compatible malloc" >&5 $as_echo_n "checking for GNU libc compatible malloc... " >&6; } if ${ac_cv_func_malloc_0_nonnull+:} false; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : ac_cv_func_malloc_0_nonnull=no else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #if defined STDC_HEADERS || defined HAVE_STDLIB_H # include #else char *malloc (); #endif int main () { return ! malloc (0); ; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : ac_cv_func_malloc_0_nonnull=yes else ac_cv_func_malloc_0_nonnull=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_malloc_0_nonnull" >&5 $as_echo "$ac_cv_func_malloc_0_nonnull" >&6; } if test $ac_cv_func_malloc_0_nonnull = yes; then : $as_echo "#define HAVE_MALLOC 1" >>confdefs.h else $as_echo "#define HAVE_MALLOC 0" >>confdefs.h case " $LIBOBJS " in *" malloc.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS malloc.$ac_objext" ;; esac $as_echo "#define malloc rpl_malloc" >>confdefs.h fi for ac_header in stdlib.h do : ac_fn_c_check_header_mongrel "$LINENO" "stdlib.h" "ac_cv_header_stdlib_h" "$ac_includes_default" if test "x$ac_cv_header_stdlib_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_STDLIB_H 1 _ACEOF fi done { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU libc compatible realloc" >&5 $as_echo_n "checking for GNU libc compatible realloc... " >&6; } if ${ac_cv_func_realloc_0_nonnull+:} false; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : ac_cv_func_realloc_0_nonnull=no else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #if defined STDC_HEADERS || defined HAVE_STDLIB_H # include #else char *realloc (); #endif int main () { return ! realloc (0, 0); ; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : ac_cv_func_realloc_0_nonnull=yes else ac_cv_func_realloc_0_nonnull=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_realloc_0_nonnull" >&5 $as_echo "$ac_cv_func_realloc_0_nonnull" >&6; } if test $ac_cv_func_realloc_0_nonnull = yes; then : $as_echo "#define HAVE_REALLOC 1" >>confdefs.h else $as_echo "#define HAVE_REALLOC 0" >>confdefs.h case " $LIBOBJS " in *" realloc.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS realloc.$ac_objext" ;; esac $as_echo "#define realloc rpl_realloc" >>confdefs.h fi for ac_func in atexit dup2 gettimeofday memset socket strerror uname do : as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" if eval test \"x\$"$as_ac_var"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 _ACEOF fi done fi # simple architecture detection if test `uname -m` = "x86_64"; then ARCH=amd64 else ARCH=i386 fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: using architecture $ARCH" >&5 $as_echo "using architecture $ARCH" >&6; } # Host-specific detection want_linux_netns=no want_bsd=no if test `uname -s` = "FreeBSD"; then want_bsd=yes for ac_prog in do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_gmake+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$gmake"; then ac_cv_prog_gmake="$gmake" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_gmake="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi gmake=$ac_cv_prog_gmake if test -n "$gmake"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $gmake" >&5 $as_echo "$gmake" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$gmake" && break done # FreeBSD fix for linking libev port below CFLAGS="$CFLAGS -L/usr/local/lib" else want_linux_netns=yes fi if test "x$want_python" = "xno"; then want_bsd=no want_linux_netns=no fi if test "x$want_python" = "xyes"; then if test "x$want_linux_netns" = "xyes"; then CFLAGS_save=$CFLAGS CPPFLAGS_save=$CPPFLAGS if test "x$PYTHON_INCLUDE_DIR" = "x"; then PYTHON_INCLUDE_DIR=`$PYTHON -c "import distutils.sysconfig; print distutils.sysconfig.get_python_inc()"` fi CFLAGS="-I$PYTHON_INCLUDE_DIR" CPPFLAGS="-I$PYTHON_INCLUDE_DIR" for ac_header in Python.h do : ac_fn_c_check_header_mongrel "$LINENO" "Python.h" "ac_cv_header_Python_h" "$ac_includes_default" if test "x$ac_cv_header_Python_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_PYTHON_H 1 _ACEOF else as_fn_error $? "Python bindings require Python development headers (try installing your 'python-devel' or 'python-dev' package)" "$LINENO" 5 fi done CFLAGS=$CFLAGS_save CPPFLAGS=$CPPFLAGS_save if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}pkg-config", so it can be a program name with args. set dummy ${ac_tool_prefix}pkg-config; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_path_PKG_CONFIG+:} false; then : $as_echo_n "(cached) " >&6 else case $PKG_CONFIG in [\\/]* | ?:[\\/]*) ac_cv_path_PKG_CONFIG="$PKG_CONFIG" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_path_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi PKG_CONFIG=$ac_cv_path_PKG_CONFIG if test -n "$PKG_CONFIG"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PKG_CONFIG" >&5 $as_echo "$PKG_CONFIG" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_path_PKG_CONFIG"; then ac_pt_PKG_CONFIG=$PKG_CONFIG # Extract the first word of "pkg-config", so it can be a program name with args. set dummy pkg-config; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_path_ac_pt_PKG_CONFIG+:} false; then : $as_echo_n "(cached) " >&6 else case $ac_pt_PKG_CONFIG in [\\/]* | ?:[\\/]*) ac_cv_path_ac_pt_PKG_CONFIG="$ac_pt_PKG_CONFIG" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_path_ac_pt_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi ac_pt_PKG_CONFIG=$ac_cv_path_ac_pt_PKG_CONFIG if test -n "$ac_pt_PKG_CONFIG"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_pt_PKG_CONFIG" >&5 $as_echo "$ac_pt_PKG_CONFIG" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_pt_PKG_CONFIG" = x; then PKG_CONFIG="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac PKG_CONFIG=$ac_pt_PKG_CONFIG fi else PKG_CONFIG="$ac_cv_path_PKG_CONFIG" fi fi if test -n "$PKG_CONFIG"; then _pkg_min_version=0.9.0 { $as_echo "$as_me:${as_lineno-$LINENO}: checking pkg-config is at least version $_pkg_min_version" >&5 $as_echo_n "checking pkg-config is at least version $_pkg_min_version... " >&6; } if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } PKG_CONFIG="" fi fi pkg_failed=no { $as_echo "$as_me:${as_lineno-$LINENO}: checking for libev" >&5 $as_echo_n "checking for libev... " >&6; } if test -n "$libev_CFLAGS"; then pkg_cv_libev_CFLAGS="$libev_CFLAGS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libev\""; } >&5 ($PKG_CONFIG --exists --print-errors "libev") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_libev_CFLAGS=`$PKG_CONFIG --cflags "libev" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test -n "$libev_LIBS"; then pkg_cv_libev_LIBS="$libev_LIBS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libev\""; } >&5 ($PKG_CONFIG --exists --print-errors "libev") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_libev_LIBS=`$PKG_CONFIG --libs "libev" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test $pkg_failed = yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes else _pkg_short_errors_supported=no fi if test $_pkg_short_errors_supported = yes; then libev_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "libev" 2>&1` else libev_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "libev" 2>&1` fi # Put the nasty error message in config.log where it belongs echo "$libev_PKG_ERRORS" >&5 { $as_echo "$as_me:${as_lineno-$LINENO}: result: did not find libev using pkconfig..." >&5 $as_echo "did not find libev using pkconfig..." >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ev_set_allocator in -lev" >&5 $as_echo_n "checking for ev_set_allocator in -lev... " >&6; } if ${ac_cv_lib_ev_ev_set_allocator+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lev $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char ev_set_allocator (); int main () { return ev_set_allocator (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_ev_ev_set_allocator=yes else ac_cv_lib_ev_ev_set_allocator=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ev_ev_set_allocator" >&5 $as_echo "$ac_cv_lib_ev_ev_set_allocator" >&6; } if test "x$ac_cv_lib_ev_ev_set_allocator" = xyes; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: found libev OK" >&5 $as_echo "found libev OK" >&6; } libev_LIBS=-lev else as_fn_error $? "Python bindings require libev (try installing your 'libev-devel' or 'libev-dev' package)" "$LINENO" 5 fi elif test $pkg_failed = untried; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: result: did not find libev using pkconfig..." >&5 $as_echo "did not find libev using pkconfig..." >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ev_set_allocator in -lev" >&5 $as_echo_n "checking for ev_set_allocator in -lev... " >&6; } if ${ac_cv_lib_ev_ev_set_allocator+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lev $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char ev_set_allocator (); int main () { return ev_set_allocator (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_ev_ev_set_allocator=yes else ac_cv_lib_ev_ev_set_allocator=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ev_ev_set_allocator" >&5 $as_echo "$ac_cv_lib_ev_ev_set_allocator" >&6; } if test "x$ac_cv_lib_ev_ev_set_allocator" = xyes; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: found libev OK" >&5 $as_echo "found libev OK" >&6; } libev_LIBS=-lev else as_fn_error $? "Python bindings require libev (try installing your 'libev-devel' or 'libev-dev' package)" "$LINENO" 5 fi else libev_CFLAGS=$pkg_cv_libev_CFLAGS libev_LIBS=$pkg_cv_libev_LIBS { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: result: found libev using pkgconfig OK" >&5 $as_echo "found libev using pkgconfig OK" >&6; } fi fi pyprefix=`eval ${PYTHON} ./python-prefix.py ${PYTHON_PREFIX} ${PYTHON_VERSION}` if test "${pyprefix}" != "${PYTHON_PREFIX}"; then pythondir=`echo ${pythondir} | sed -e 's,${prefix},${pyprefix},g'` pyexecdir=`echo ${pyexecdir} | sed -e 's,${exec_prefix},${pyprefix},g'` fi else # Namespace support requires Python support want_linux_netns=no fi progs_missing="" if test "x$want_linux_netns" = "xyes"; then if test "x$brctl_path" = "xno" ; then progs_missing="${progs_missing}brctl " brctl_path="/usr/sbin" as_fn_error $? "Could not locate brctl (from bridge-utils package)." "$LINENO" 5 fi if test "x$ebtables_path" = "xno" ; then progs_missing="${progs_missing}ebtables " ebtables_path="/sbin" as_fn_error $? "Could not locate ebtables (from ebtables package)." "$LINENO" 5 fi if test "x$ip_path" = "xno" ; then progs_missing="${progs_missing}ip " ip_path="/sbin" as_fn_error $? "Could not locate ip (from iproute package)." "$LINENO" 5 fi if test "x$tc_path" = "xno" ; then progs_missing="${progs_missing}tc " tc_path="/sbin" as_fn_error $? "Could not locate tc (from iproute package)." "$LINENO" 5 fi fi if test "x$want_bsd" = "xyes"; then if test "x$ifconfig_path" = "xno" ; then as_fn_error $? "Could not locate the 'ifconfig' utility." "$LINENO" 5 fi if test "x$ngctl_path" = "xno" ; then as_fn_error $? "Could not locate the 'ngctl' utility." "$LINENO" 5 fi if test "x$vimage_path" = "xno" ; then as_fn_error $? "Could not locate the 'vimage' utility." "$LINENO" 5 fi fi # Check whether --with-startup was given. if test "${with_startup+set}" = set; then : withval=$with_startup; with_startup=$with_startup else with_startup=initd fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: using startup option $with_startup" >&5 $as_echo "using startup option $with_startup" >&6; } # Variable substitutions if test x$enable_gui = xyes; then WANT_GUI_TRUE= WANT_GUI_FALSE='#' else WANT_GUI_TRUE='#' WANT_GUI_FALSE= fi if test x$enable_daemon = xyes; then WANT_DAEMON_TRUE= WANT_DAEMON_FALSE='#' else WANT_DAEMON_TRUE='#' WANT_DAEMON_FALSE= fi if test x$want_bsd = xyes; then WANT_BSD_TRUE= WANT_BSD_FALSE='#' else WANT_BSD_TRUE='#' WANT_BSD_FALSE= fi if test x$want_docs = xyes; then WANT_DOCS_TRUE= WANT_DOCS_FALSE='#' else WANT_DOCS_TRUE='#' WANT_DOCS_FALSE= fi if test x$want_python = xyes; then WANT_PYTHON_TRUE= WANT_PYTHON_FALSE='#' else WANT_PYTHON_TRUE='#' WANT_PYTHON_FALSE= fi if test x$want_linux_netns = xyes; then WANT_NETNS_TRUE= WANT_NETNS_FALSE='#' else WANT_NETNS_TRUE='#' WANT_NETNS_FALSE= fi if test x$with_startup = xinitd; then WANT_INITD_TRUE= WANT_INITD_FALSE='#' else WANT_INITD_TRUE='#' WANT_INITD_FALSE= fi if test x$with_startup = xsystemd; then WANT_SYSTEMD_TRUE= WANT_SYSTEMD_FALSE='#' else WANT_SYSTEMD_TRUE='#' WANT_SYSTEMD_FALSE= fi if test x$with_startup = xsuse; then WANT_SUSE_TRUE= WANT_SUSE_FALSE='#' else WANT_SUSE_TRUE='#' WANT_SUSE_FALSE= fi if test $cross_compiling = no; then HELP2MAN=${HELP2MAN-"${am_missing_run}help2man"} else HELP2MAN=: fi # Output files ac_config_files="$ac_config_files Makefile gui/core-gui gui/version.tcl gui/Makefile gui/icons/Makefile scripts/Makefile scripts/perf/Makefile scripts/xen/Makefile doc/Makefile doc/conf.py doc/man/Makefile doc/figures/Makefile daemon/Makefile daemon/src/Makefile daemon/src/version.h daemon/core/constants.py daemon/ns3/Makefile daemon/ns3/corens3/constants.py daemon/doc/Makefile daemon/doc/conf.py packaging/deb/core-daemon.install packaging/deb/core-gui.install packaging/rpm/core.spec" cat >confcache <<\_ACEOF # This file is a shell script that caches the results of configure # tests run on this system so they can be shared between configure # scripts and configure runs, see configure's option --config-cache. # It is not useful on other systems. If it contains results you don't # want to keep, you may remove or edit it. # # config.status only pays attention to the cache file if you give it # the --recheck option to rerun configure. # # `ac_cv_env_foo' variables (set or unset) will be overridden when # loading this file, other *unset* `ac_cv_foo' will be assigned the # following values. _ACEOF # The following way of writing the cache mishandles newlines in values, # but we know of no workaround that is simple, portable, and efficient. # So, we kill variables containing newlines. # Ultrix sh set writes to stderr and can't be redirected directly, # and sets the high bit in the cache file unless we assign to the vars. ( for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space=' '; set) 2>&1` in #( *${as_nl}ac_space=\ *) # `set' does not quote correctly, so add quotes: double-quote # substitution turns \\\\ into \\, and sed turns \\ into \. sed -n \ "s/'/'\\\\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" ;; #( *) # `set' quotes correctly as required by POSIX, so do not add quotes. sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) | sed ' /^ac_cv_env_/b end t clear :clear s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ t end s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ :end' >>confcache if diff "$cache_file" confcache >/dev/null 2>&1; then :; else if test -w "$cache_file"; then if test "x$cache_file" != "x/dev/null"; then { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 $as_echo "$as_me: updating cache $cache_file" >&6;} if test ! -f "$cache_file" || test -h "$cache_file"; then cat confcache >"$cache_file" else case $cache_file in #( */* | ?:*) mv -f confcache "$cache_file"$$ && mv -f "$cache_file"$$ "$cache_file" ;; #( *) mv -f confcache "$cache_file" ;; esac fi fi else { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 $as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} fi fi rm -f confcache test "x$prefix" = xNONE && prefix=$ac_default_prefix # Let make expand exec_prefix. test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' DEFS=-DHAVE_CONFIG_H ac_libobjs= ac_ltlibobjs= U= for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue # 1. Remove the extension, and $U if already installed. ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' ac_i=`$as_echo "$ac_i" | sed "$ac_script"` # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR # will be set to the directory where LIBOBJS objects are built. as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext" as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo' done LIBOBJS=$ac_libobjs LTLIBOBJS=$ac_ltlibobjs { $as_echo "$as_me:${as_lineno-$LINENO}: checking that generated files are newer than configure" >&5 $as_echo_n "checking that generated files are newer than configure... " >&6; } if test -n "$am_sleep_pid"; then # Hide warnings about reused PIDs. wait $am_sleep_pid 2>/dev/null fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: done" >&5 $as_echo "done" >&6; } if test -n "$EXEEXT"; then am__EXEEXT_TRUE= am__EXEEXT_FALSE='#' else am__EXEEXT_TRUE='#' am__EXEEXT_FALSE= fi if test -z "${AMDEP_TRUE}" && test -z "${AMDEP_FALSE}"; then as_fn_error $? "conditional \"AMDEP\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${am__fastdepCC_TRUE}" && test -z "${am__fastdepCC_FALSE}"; then as_fn_error $? "conditional \"am__fastdepCC\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${WANT_GUI_TRUE}" && test -z "${WANT_GUI_FALSE}"; then as_fn_error $? "conditional \"WANT_GUI\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${WANT_DAEMON_TRUE}" && test -z "${WANT_DAEMON_FALSE}"; then as_fn_error $? "conditional \"WANT_DAEMON\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${WANT_BSD_TRUE}" && test -z "${WANT_BSD_FALSE}"; then as_fn_error $? "conditional \"WANT_BSD\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${WANT_DOCS_TRUE}" && test -z "${WANT_DOCS_FALSE}"; then as_fn_error $? "conditional \"WANT_DOCS\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${WANT_PYTHON_TRUE}" && test -z "${WANT_PYTHON_FALSE}"; then as_fn_error $? "conditional \"WANT_PYTHON\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${WANT_NETNS_TRUE}" && test -z "${WANT_NETNS_FALSE}"; then as_fn_error $? "conditional \"WANT_NETNS\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${WANT_INITD_TRUE}" && test -z "${WANT_INITD_FALSE}"; then as_fn_error $? "conditional \"WANT_INITD\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${WANT_SYSTEMD_TRUE}" && test -z "${WANT_SYSTEMD_FALSE}"; then as_fn_error $? "conditional \"WANT_SYSTEMD\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${WANT_SUSE_TRUE}" && test -z "${WANT_SUSE_FALSE}"; then as_fn_error $? "conditional \"WANT_SUSE\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi : "${CONFIG_STATUS=./config.status}" ac_write_fail=0 ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files $CONFIG_STATUS" { $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 $as_echo "$as_me: creating $CONFIG_STATUS" >&6;} as_write_fail=0 cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1 #! $SHELL # Generated by $as_me. # Run this file to recreate the current configuration. # Compiler output produced by configure, useful for debugging # configure, is in config.log if it exists. debug=false ac_cs_recheck=false ac_cs_silent=false SHELL=\${CONFIG_SHELL-$SHELL} export SHELL _ASEOF cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1 ## -------------------- ## ## M4sh Initialization. ## ## -------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi as_nl=' ' export as_nl # Printing a long string crashes Solaris 7 /usr/bin/printf. as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo # Prefer a ksh shell builtin over an external printf program on Solaris, # but without wasting forks for bash or zsh. if test -z "$BASH_VERSION$ZSH_VERSION" \ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='print -r --' as_echo_n='print -rn --' elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='printf %s\n' as_echo_n='printf %s' else if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' as_echo_n='/usr/ucb/echo -n' else as_echo_body='eval expr "X$1" : "X\\(.*\\)"' as_echo_n_body='eval arg=$1; case $arg in #( *"$as_nl"*) expr "X$arg" : "X\\(.*\\)$as_nl"; arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; esac; expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" ' export as_echo_n_body as_echo_n='sh -c $as_echo_n_body as_echo' fi export as_echo_body as_echo='sh -c $as_echo_body as_echo' fi # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || PATH_SEPARATOR=';' } fi # IFS # We need space, tab and new line, in precisely that order. Quoting is # there to prevent editors from complaining about space-tab. # (If _AS_PATH_WALK were called with IFS unset, it would disable word # splitting by setting IFS to empty value.) IFS=" "" $as_nl" # Find who we are. Look in the path if we contain no directory separator. as_myself= case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break done IFS=$as_save_IFS ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi # Unset variables that we do not need and which cause bugs (e.g. in # pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" # suppresses any "Segmentation fault" message there. '((' could # trigger a bug in pdksh 5.2.14. for as_var in BASH_ENV ENV MAIL MAILPATH do eval test x\${$as_var+set} = xset \ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done PS1='$ ' PS2='> ' PS4='+ ' # NLS nuisances. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # CDPATH. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH # as_fn_error STATUS ERROR [LINENO LOG_FD] # ---------------------------------------- # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are # provided, also output the error to LOG_FD, referencing LINENO. Then exit the # script with STATUS, using 1 if that was 0. as_fn_error () { as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi $as_echo "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. as_fn_set_status () { return $1 } # as_fn_set_status # as_fn_exit STATUS # ----------------- # Exit the shell with STATUS, even in a "trap 0" or "set -e" context. as_fn_exit () { set +e as_fn_set_status $1 exit $1 } # as_fn_exit # as_fn_unset VAR # --------------- # Portably unset VAR. as_fn_unset () { { eval $1=; unset $1;} } as_unset=as_fn_unset # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : eval 'as_fn_append () { eval $1+=\$2 }' else as_fn_append () { eval $1=\$$1\$2 } fi # as_fn_append # as_fn_arith ARG... # ------------------ # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : eval 'as_fn_arith () { as_val=$(( $* )) }' else as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } fi # as_fn_arith if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then as_dirname=dirname else as_dirname=false fi as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || $as_echo X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) case `echo 'xy\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. xy) ECHO_C='\c';; *) echo `echo ksh88 bug on AIX 6.1` > /dev/null ECHO_T=' ';; esac;; *) ECHO_N='-n';; esac rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir mkdir conf$$.dir 2>/dev/null fi if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. # In both cases, we have to default to `cp -pR'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -pR' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -pR' fi else as_ln_s='cp -pR' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null # as_fn_mkdir_p # ------------- # Create "$as_dir" as a directory, including parents if necessary. as_fn_mkdir_p () { case $as_dir in #( -*) as_dir=./$as_dir;; esac test -d "$as_dir" || eval $as_mkdir_p || { as_dirs= while :; do case $as_dir in #( *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" as_dir=`$as_dirname -- "$as_dir" || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" } # as_fn_mkdir_p if mkdir -p . 2>/dev/null; then as_mkdir_p='mkdir -p "$as_dir"' else test -d ./-p && rmdir ./-p as_mkdir_p=false fi # as_fn_executable_p FILE # ----------------------- # Test if FILE is an executable regular file. as_fn_executable_p () { test -f "$1" && test -x "$1" } # as_fn_executable_p as_test_x='test -x' as_executable_p=as_fn_executable_p # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" exec 6>&1 ## ----------------------------------- ## ## Main body of $CONFIG_STATUS script. ## ## ----------------------------------- ## _ASEOF test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1 cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Save the log message, to keep $0 and so on meaningful, and to # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" This file was extended by core $as_me 4.8, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES CONFIG_HEADERS = $CONFIG_HEADERS CONFIG_LINKS = $CONFIG_LINKS CONFIG_COMMANDS = $CONFIG_COMMANDS $ $0 $@ on `(hostname || uname -n) 2>/dev/null | sed 1q` " _ACEOF case $ac_config_files in *" "*) set x $ac_config_files; shift; ac_config_files=$*;; esac case $ac_config_headers in *" "*) set x $ac_config_headers; shift; ac_config_headers=$*;; esac cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 # Files that config.status was made for. config_files="$ac_config_files" config_headers="$ac_config_headers" config_commands="$ac_config_commands" _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 ac_cs_usage="\ \`$as_me' instantiates files and other configuration actions from templates according to the current configuration. Unless the files and actions are specified as TAGs, all are instantiated by default. Usage: $0 [OPTION]... [TAG]... -h, --help print this help, then exit -V, --version print version number and configuration settings, then exit --config print configuration, then exit -q, --quiet, --silent do not print progress messages -d, --debug don't remove temporary files --recheck update $as_me by reconfiguring in the same conditions --file=FILE[:TEMPLATE] instantiate the configuration file FILE --header=FILE[:TEMPLATE] instantiate the configuration header FILE Configuration files: $config_files Configuration headers: $config_headers Configuration commands: $config_commands Report bugs to ." _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ core config.status 4.8 configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" Copyright (C) 2012 Free Software Foundation, Inc. This config.status script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it." ac_pwd='$ac_pwd' srcdir='$srcdir' INSTALL='$INSTALL' MKDIR_P='$MKDIR_P' AWK='$AWK' test -n "\$AWK" || AWK=awk _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # The default lists apply if the user does not specify any file. ac_need_defaults=: while test $# != 0 do case $1 in --*=?*) ac_option=`expr "X$1" : 'X\([^=]*\)='` ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` ac_shift=: ;; --*=) ac_option=`expr "X$1" : 'X\([^=]*\)='` ac_optarg= ac_shift=: ;; *) ac_option=$1 ac_optarg=$2 ac_shift=shift ;; esac case $ac_option in # Handling of the options. -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) ac_cs_recheck=: ;; --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) $as_echo "$ac_cs_version"; exit ;; --config | --confi | --conf | --con | --co | --c ) $as_echo "$ac_cs_config"; exit ;; --debug | --debu | --deb | --de | --d | -d ) debug=: ;; --file | --fil | --fi | --f ) $ac_shift case $ac_optarg in *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; '') as_fn_error $? "missing file argument" ;; esac as_fn_append CONFIG_FILES " '$ac_optarg'" ac_need_defaults=false;; --header | --heade | --head | --hea ) $ac_shift case $ac_optarg in *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; esac as_fn_append CONFIG_HEADERS " '$ac_optarg'" ac_need_defaults=false;; --he | --h) # Conflict between --help and --header as_fn_error $? "ambiguous option: \`$1' Try \`$0 --help' for more information.";; --help | --hel | -h ) $as_echo "$ac_cs_usage"; exit ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil | --si | --s) ac_cs_silent=: ;; # This is an error. -*) as_fn_error $? "unrecognized option: \`$1' Try \`$0 --help' for more information." ;; *) as_fn_append ac_config_targets " $1" ac_need_defaults=false ;; esac shift done ac_configure_extra_args= if $ac_cs_silent; then exec 6>/dev/null ac_configure_extra_args="$ac_configure_extra_args --silent" fi _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 if \$ac_cs_recheck; then set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion shift \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6 CONFIG_SHELL='$SHELL' export CONFIG_SHELL exec "\$@" fi _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 exec 5>>config.log { echo sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX ## Running $as_me. ## _ASBOX $as_echo "$ac_log" } >&5 _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 # # INIT-COMMANDS # AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir" _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Handling of arguments. for ac_config_target in $ac_config_targets do case $ac_config_target in "config.h") CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;; "depfiles") CONFIG_COMMANDS="$CONFIG_COMMANDS depfiles" ;; "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; "gui/core-gui") CONFIG_FILES="$CONFIG_FILES gui/core-gui" ;; "gui/version.tcl") CONFIG_FILES="$CONFIG_FILES gui/version.tcl" ;; "gui/Makefile") CONFIG_FILES="$CONFIG_FILES gui/Makefile" ;; "gui/icons/Makefile") CONFIG_FILES="$CONFIG_FILES gui/icons/Makefile" ;; "scripts/Makefile") CONFIG_FILES="$CONFIG_FILES scripts/Makefile" ;; "scripts/perf/Makefile") CONFIG_FILES="$CONFIG_FILES scripts/perf/Makefile" ;; "scripts/xen/Makefile") CONFIG_FILES="$CONFIG_FILES scripts/xen/Makefile" ;; "doc/Makefile") CONFIG_FILES="$CONFIG_FILES doc/Makefile" ;; "doc/conf.py") CONFIG_FILES="$CONFIG_FILES doc/conf.py" ;; "doc/man/Makefile") CONFIG_FILES="$CONFIG_FILES doc/man/Makefile" ;; "doc/figures/Makefile") CONFIG_FILES="$CONFIG_FILES doc/figures/Makefile" ;; "daemon/Makefile") CONFIG_FILES="$CONFIG_FILES daemon/Makefile" ;; "daemon/src/Makefile") CONFIG_FILES="$CONFIG_FILES daemon/src/Makefile" ;; "daemon/src/version.h") CONFIG_FILES="$CONFIG_FILES daemon/src/version.h" ;; "daemon/core/constants.py") CONFIG_FILES="$CONFIG_FILES daemon/core/constants.py" ;; "daemon/ns3/Makefile") CONFIG_FILES="$CONFIG_FILES daemon/ns3/Makefile" ;; "daemon/ns3/corens3/constants.py") CONFIG_FILES="$CONFIG_FILES daemon/ns3/corens3/constants.py" ;; "daemon/doc/Makefile") CONFIG_FILES="$CONFIG_FILES daemon/doc/Makefile" ;; "daemon/doc/conf.py") CONFIG_FILES="$CONFIG_FILES daemon/doc/conf.py" ;; "packaging/deb/core-daemon.install") CONFIG_FILES="$CONFIG_FILES packaging/deb/core-daemon.install" ;; "packaging/deb/core-gui.install") CONFIG_FILES="$CONFIG_FILES packaging/deb/core-gui.install" ;; "packaging/rpm/core.spec") CONFIG_FILES="$CONFIG_FILES packaging/rpm/core.spec" ;; *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;; esac done # If the user did not use the arguments to specify the items to instantiate, # then the envvar interface is used. Set only those that are not. # We use the long form for the default assignment because of an extremely # bizarre bug on SunOS 4.1.3. if $ac_need_defaults; then test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers test "${CONFIG_COMMANDS+set}" = set || CONFIG_COMMANDS=$config_commands fi # Have a temporary directory for convenience. Make it in the build tree # simply because there is no reason against having it here, and in addition, # creating and moving files from /tmp can sometimes cause problems. # Hook for its removal unless debugging. # Note that there is a small window in which the directory will not be cleaned: # after its creation but before its name has been assigned to `$tmp'. $debug || { tmp= ac_tmp= trap 'exit_status=$? : "${ac_tmp:=$tmp}" { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status ' 0 trap 'as_fn_exit 1' 1 2 13 15 } # Create a (secure) tmp directory for tmp files. { tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && test -d "$tmp" } || { tmp=./conf$$-$RANDOM (umask 077 && mkdir "$tmp") } || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5 ac_tmp=$tmp # Set up the scripts for CONFIG_FILES section. # No need to generate them if there are no CONFIG_FILES. # This happens for instance with `./config.status config.h'. if test -n "$CONFIG_FILES"; then ac_cr=`echo X | tr X '\015'` # On cygwin, bash can eat \r inside `` if the user requested igncr. # But we know of no other shell where ac_cr would be empty at this # point, so we can use a bashism as a fallback. if test "x$ac_cr" = x; then eval ac_cr=\$\'\\r\' fi ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }'
    /dev/null` if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then ac_cs_awk_cr='\\r' else ac_cs_awk_cr=$ac_cr fi echo 'BEGIN {' >"$ac_tmp/subs1.awk" && _ACEOF { echo "cat >conf$$subs.awk <<_ACEOF" && echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' && echo "_ACEOF" } >conf$$subs.sh || as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'` ac_delim='%!_!# ' for ac_last_try in false false false false false :; do . ./conf$$subs.sh || as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X` if test $ac_delim_n = $ac_delim_num; then break elif $ac_last_try; then as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 else ac_delim="$ac_delim!$ac_delim _$ac_delim!! " fi done rm -f conf$$subs.sh cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK && _ACEOF sed -n ' h s/^/S["/; s/!.*/"]=/ p g s/^[^!]*!// :repl t repl s/'"$ac_delim"'$// t delim :nl h s/\(.\{148\}\)..*/\1/ t more1 s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/ p n b repl :more1 s/["\\]/\\&/g; s/^/"/; s/$/"\\/ p g s/.\{148\}// t nl :delim h s/\(.\{148\}\)..*/\1/ t more2 s/["\\]/\\&/g; s/^/"/; s/$/"/ p b :more2 s/["\\]/\\&/g; s/^/"/; s/$/"\\/ p g s/.\{148\}// t delim ' >$CONFIG_STATUS || ac_write_fail=1 rm -f conf$$subs.awk cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 _ACAWK cat >>"\$ac_tmp/subs1.awk" <<_ACAWK && for (key in S) S_is_set[key] = 1 FS = "" } { line = $ 0 nfields = split(line, field, "@") substed = 0 len = length(field[1]) for (i = 2; i < nfields; i++) { key = field[i] keylen = length(key) if (S_is_set[key]) { value = S[key] line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3) len += length(value) + length(field[++i]) substed = 1 } else len += 1 + keylen } print line } _ACAWK _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" else cat fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \ || as_fn_error $? "could not setup config files machinery" "$LINENO" 5 _ACEOF # VPATH may cause trouble with some makes, so we remove sole $(srcdir), # ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and # trailing colons and then remove the whole line if VPATH becomes empty # (actually we leave an empty line to preserve line numbers). if test "x$srcdir" = x.; then ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{ h s/// s/^/:/ s/[ ]*$/:/ s/:\$(srcdir):/:/g s/:\${srcdir}:/:/g s/:@srcdir@:/:/g s/^:*// s/:*$// x s/\(=[ ]*\).*/\1/ G s/\n// s/^[^=]*=[ ]*$// }' fi cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 fi # test -n "$CONFIG_FILES" # Set up the scripts for CONFIG_HEADERS section. # No need to generate them if there are no CONFIG_HEADERS. # This happens for instance with `./config.status Makefile'. if test -n "$CONFIG_HEADERS"; then cat >"$ac_tmp/defines.awk" <<\_ACAWK || BEGIN { _ACEOF # Transform confdefs.h into an awk script `defines.awk', embedded as # here-document in config.status, that substitutes the proper values into # config.h.in to produce config.h. # Create a delimiter string that does not exist in confdefs.h, to ease # handling of long lines. ac_delim='%!_!# ' for ac_last_try in false false :; do ac_tt=`sed -n "/$ac_delim/p" confdefs.h` if test -z "$ac_tt"; then break elif $ac_last_try; then as_fn_error $? "could not make $CONFIG_HEADERS" "$LINENO" 5 else ac_delim="$ac_delim!$ac_delim _$ac_delim!! " fi done # For the awk script, D is an array of macro values keyed by name, # likewise P contains macro parameters if any. Preserve backslash # newline sequences. ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]* sed -n ' s/.\{148\}/&'"$ac_delim"'/g t rset :rset s/^[ ]*#[ ]*define[ ][ ]*/ / t def d :def s/\\$// t bsnl s/["\\]/\\&/g s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ D["\1"]=" \3"/p s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2"/p d :bsnl s/["\\]/\\&/g s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ D["\1"]=" \3\\\\\\n"\\/p t cont s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2\\\\\\n"\\/p t cont d :cont n s/.\{148\}/&'"$ac_delim"'/g t clear :clear s/\\$// t bsnlc s/["\\]/\\&/g; s/^/"/; s/$/"/p d :bsnlc s/["\\]/\\&/g; s/^/"/; s/$/\\\\\\n"\\/p b cont ' >$CONFIG_STATUS || ac_write_fail=1 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 for (key in D) D_is_set[key] = 1 FS = "" } /^[\t ]*#[\t ]*(define|undef)[\t ]+$ac_word_re([\t (]|\$)/ { line = \$ 0 split(line, arg, " ") if (arg[1] == "#") { defundef = arg[2] mac1 = arg[3] } else { defundef = substr(arg[1], 2) mac1 = arg[2] } split(mac1, mac2, "(") #) macro = mac2[1] prefix = substr(line, 1, index(line, defundef) - 1) if (D_is_set[macro]) { # Preserve the white space surrounding the "#". print prefix "define", macro P[macro] D[macro] next } else { # Replace #undef with comments. This is necessary, for example, # in the case of _POSIX_SOURCE, which is predefined and required # on some systems where configure will not decide to define it. if (defundef == "undef") { print "/*", prefix defundef, macro, "*/" next } } } { print } _ACAWK _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 as_fn_error $? "could not setup config headers machinery" "$LINENO" 5 fi # test -n "$CONFIG_HEADERS" eval set X " :F $CONFIG_FILES :H $CONFIG_HEADERS :C $CONFIG_COMMANDS" shift for ac_tag do case $ac_tag in :[FHLC]) ac_mode=$ac_tag; continue;; esac case $ac_mode$ac_tag in :[FHL]*:*);; :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;; :[FH]-) ac_tag=-:-;; :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; esac ac_save_IFS=$IFS IFS=: set x $ac_tag IFS=$ac_save_IFS shift ac_file=$1 shift case $ac_mode in :L) ac_source=$1;; :[FH]) ac_file_inputs= for ac_f do case $ac_f in -) ac_f="$ac_tmp/stdin";; *) # Look for the file first in the build tree, then in the source tree # (if the path is not absolute). The absolute path cannot be DOS-style, # because $ac_f cannot contain `:'. test -f "$ac_f" || case $ac_f in [\\/$]*) false;; *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; esac || as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;; esac case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac as_fn_append ac_file_inputs " '$ac_f'" done # Let's still pretend it is `configure' which instantiates (i.e., don't # use $as_me), people would be surprised to read: # /* config.h. Generated by config.status. */ configure_input='Generated from '` $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' `' by configure.' if test x"$ac_file" != x-; then configure_input="$ac_file. $configure_input" { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 $as_echo "$as_me: creating $ac_file" >&6;} fi # Neutralize special characters interpreted by sed in replacement strings. case $configure_input in #( *\&* | *\|* | *\\* ) ac_sed_conf_input=`$as_echo "$configure_input" | sed 's/[\\\\&|]/\\\\&/g'`;; #( *) ac_sed_conf_input=$configure_input;; esac case $ac_tag in *:-:* | *:-) cat >"$ac_tmp/stdin" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; esac ;; esac ac_dir=`$as_dirname -- "$ac_file" || $as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$ac_file" : 'X\(//\)[^/]' \| \ X"$ac_file" : 'X\(//\)$' \| \ X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$ac_file" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` as_dir="$ac_dir"; as_fn_mkdir_p ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix case $ac_mode in :F) # # CONFIG_FILE # case $INSTALL in [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;; esac ac_MKDIR_P=$MKDIR_P case $MKDIR_P in [\\/$]* | ?:[\\/]* ) ;; */*) ac_MKDIR_P=$ac_top_build_prefix$MKDIR_P ;; esac _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # If the template does not know about datarootdir, expand it. # FIXME: This hack should be removed a few years after 2.60. ac_datarootdir_hack=; ac_datarootdir_seen= ac_sed_dataroot=' /datarootdir/ { p q } /@datadir@/p /@docdir@/p /@infodir@/p /@localedir@/p /@mandir@/p' case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in *datarootdir*) ac_datarootdir_seen=yes;; *@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 $as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_datarootdir_hack=' s&@datadir@&$datadir&g s&@docdir@&$docdir&g s&@infodir@&$infodir&g s&@localedir@&$localedir&g s&@mandir@&$mandir&g s&\\\${datarootdir}&$datarootdir&g' ;; esac _ACEOF # Neutralize VPATH when `$srcdir' = `.'. # Shell code in configure.ac might set extrasub. # FIXME: do we really want to maintain this feature? cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_sed_extra="$ac_vpsub $extrasub _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 :t /@[a-zA-Z_][a-zA-Z_0-9]*@/!b s|@configure_input@|$ac_sed_conf_input|;t t s&@top_builddir@&$ac_top_builddir_sub&;t t s&@top_build_prefix@&$ac_top_build_prefix&;t t s&@srcdir@&$ac_srcdir&;t t s&@abs_srcdir@&$ac_abs_srcdir&;t t s&@top_srcdir@&$ac_top_srcdir&;t t s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t s&@builddir@&$ac_builddir&;t t s&@abs_builddir@&$ac_abs_builddir&;t t s&@abs_top_builddir@&$ac_abs_top_builddir&;t t s&@INSTALL@&$ac_INSTALL&;t t s&@MKDIR_P@&$ac_MKDIR_P&;t t $ac_datarootdir_hack " eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \ >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5 test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } && { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \ "$ac_tmp/out"`; test -z "$ac_out"; } && { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined" >&5 $as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined" >&2;} rm -f "$ac_tmp/stdin" case $ac_file in -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";; *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";; esac \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; :H) # # CONFIG_HEADER # if test x"$ac_file" != x-; then { $as_echo "/* $configure_input */" \ && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" } >"$ac_tmp/config.h" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 if diff "$ac_file" "$ac_tmp/config.h" >/dev/null 2>&1; then { $as_echo "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5 $as_echo "$as_me: $ac_file is unchanged" >&6;} else rm -f "$ac_file" mv "$ac_tmp/config.h" "$ac_file" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 fi else $as_echo "/* $configure_input */" \ && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" \ || as_fn_error $? "could not create -" "$LINENO" 5 fi # Compute "$ac_file"'s index in $config_headers. _am_arg="$ac_file" _am_stamp_count=1 for _am_header in $config_headers :; do case $_am_header in $_am_arg | $_am_arg:* ) break ;; * ) _am_stamp_count=`expr $_am_stamp_count + 1` ;; esac done echo "timestamp for $_am_arg" >`$as_dirname -- "$_am_arg" || $as_expr X"$_am_arg" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$_am_arg" : 'X\(//\)[^/]' \| \ X"$_am_arg" : 'X\(//\)$' \| \ X"$_am_arg" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$_am_arg" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'`/stamp-h$_am_stamp_count ;; :C) { $as_echo "$as_me:${as_lineno-$LINENO}: executing $ac_file commands" >&5 $as_echo "$as_me: executing $ac_file commands" >&6;} ;; esac case $ac_file$ac_mode in "depfiles":C) test x"$AMDEP_TRUE" != x"" || { # Older Autoconf quotes --file arguments for eval, but not when files # are listed without --file. Let's play safe and only enable the eval # if we detect the quoting. case $CONFIG_FILES in *\'*) eval set x "$CONFIG_FILES" ;; *) set x $CONFIG_FILES ;; esac shift for mf do # Strip MF so we end up with the name of the file. mf=`echo "$mf" | sed -e 's/:.*$//'` # Check whether this is an Automake generated Makefile or not. # We used to match only the files named 'Makefile.in', but # some people rename them; so instead we look at the file content. # Grep'ing the first line is not enough: some people post-process # each Makefile.in and add a new line on top of each file to say so. # Grep'ing the whole file is not good either: AIX grep has a line # limit of 2048, but all sed's we know have understand at least 4000. if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then dirpart=`$as_dirname -- "$mf" || $as_expr X"$mf" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$mf" : 'X\(//\)[^/]' \| \ X"$mf" : 'X\(//\)$' \| \ X"$mf" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$mf" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` else continue fi # Extract the definition of DEPDIR, am__include, and am__quote # from the Makefile without running 'make'. DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"` test -z "$DEPDIR" && continue am__include=`sed -n 's/^am__include = //p' < "$mf"` test -z "$am__include" && continue am__quote=`sed -n 's/^am__quote = //p' < "$mf"` # Find all dependency output files, they are included files with # $(DEPDIR) in their names. We invoke sed twice because it is the # simplest approach to changing $(DEPDIR) to its actual value in the # expansion. for file in `sed -n " s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \ sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g'`; do # Make sure the directory exists. test -f "$dirpart/$file" && continue fdir=`$as_dirname -- "$file" || $as_expr X"$file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$file" : 'X\(//\)[^/]' \| \ X"$file" : 'X\(//\)$' \| \ X"$file" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$file" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` as_dir=$dirpart/$fdir; as_fn_mkdir_p # echo "creating $dirpart/$file" echo '# dummy' > "$dirpart/$file" done done } ;; esac done # for ac_tag as_fn_exit 0 _ACEOF ac_clean_files=$ac_clean_files_save test $ac_write_fail = 0 || as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5 # configure is writing to config.log, and then calls config.status. # config.status does its own redirection, appending to config.log. # Unfortunately, on DOS this fails, as config.log is still kept open # by configure, so config.status won't be able to write to it; its # output is simply discarded. So we exec the FD to /dev/null, # effectively closing config.log, so it can be properly (re)opened and # appended to by config.status. When coming back to configure, we # need to make the FD available again. if test "$no_create" != yes; then ac_cs_success=: ac_config_status_args= test "$silent" = yes && ac_config_status_args="$ac_config_status_args --quiet" exec 5>/dev/null $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false exec 5>>config.log # Use ||, not &&, to avoid exiting from the if with $? = 1, which # would make configure fail if this is the last instruction. $ac_cs_success || as_fn_exit 1 fi if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} fi # Summary text echo \ "------------------------------------------------------------------------ ${PACKAGE_STRING} Configuration: Host System Type: ${host} C Compiler and flags: ${CC} ${CFLAGS} Install prefix: ${prefix} Build GUI: ${enable_gui} GUI path: ${CORE_LIB_DIR} GUI config: ${CORE_GUI_CONF_DIR} Daemon path: ${SBINDIR} Daemon config: ${CORE_CONF_DIR} Python install prefix: ${pyprefix} Python modules: ${pythondir} Logs: ${CORE_STATE_DIR}/log Features to build: Python bindings: ${want_python} Linux Namespaces emulation: ${want_linux_netns} FreeBSD Jails emulation: ${want_bsd} Documentation: ${want_docs} ------------------------------------------------------------------------" if test "x${want_bsd}" = "xyes" ; then # TODO: more sophisticated checks of gmake vs make echo ">>> NOTE: on FreeBSD you should use 'gmake' instead of 'make' ------------------------------------------------------------------------" fi if test "x${want_linux_netns}" = "xyes" ; then echo "On this platform you should run core-gui as a normal user. ------------------------------------------------------------------------" fi if test "x${progs_missing}" != "x" ; then echo ">>> NOTE: the following programs could not be found:" echo " $progs_missing ------------------------------------------------------------------------" fi core-4.8/configure.ac0000664000175000017500000002726512534327775011561 00000000000000# # Copyright (c) 2010-2013 the Boeing Company # See the LICENSE file included in this distribution. # # CORE configure script # # author: Jeff Ahrenholz # # -*- Autoconf -*- # Process this file with autoconf to produce a configure script. # # this defines the CORE version number, must be static for AC_INIT # AC_INIT(core, 4.8, core-dev@pf.itd.nrl.navy.mil) VERSION=$PACKAGE_VERSION CORE_VERSION=$PACKAGE_VERSION CORE_VERSION_DATE=20150605 COREDPY_VERSION=$PACKAGE_VERSION # # autoconf and automake initialization # AC_CONFIG_SRCDIR([daemon/src/version.h.in]) AC_CONFIG_AUX_DIR(config) AC_CONFIG_MACRO_DIR(config) AC_CONFIG_HEADERS([config.h]) AM_INIT_AUTOMAKE AC_SUBST(CORE_VERSION) AC_SUBST(CORE_VERSION_DATE) AC_SUBST(COREDPY_VERSION) # # some of the following directory variables are not expanded at configure-time, # so we have special checks to expand them # # CORE GUI files in LIBDIR # AC_PREFIX_DEFAULT is /usr/local, but not expanded yet if test "x$prefix" = "xNONE" ; then prefix="/usr/local" fi if test "x$exec_prefix" = "xNONE" ; then exec_prefix="$prefix" fi if test "$libdir" = "\${exec_prefix}/lib" ; then libdir="${exec_prefix}/lib" fi if test "$sbindir" = "\${exec_prefix}/sbin" ; then sbindir="${exec_prefix}/sbin" fi if test "$bindir" = "\${exec_prefix}/bin" ; then bindir="${exec_prefix}/bin" fi # this can be /usr/lib or /usr/lib64 LIB_DIR="${libdir}" # don't let the Tcl files install to /usr/lib64/core CORE_LIB_DIR="${prefix}/lib/core" AC_SUBST(LIB_DIR) AC_SUBST(CORE_LIB_DIR) SBINDIR="${sbindir}" AC_SUBST(SBINDIR) BINDIR="${bindir}" AC_SUBST(BINDIR) # CORE daemon configuration file (core.conf) in CORE_CONF_DIR if test "$sysconfdir" = "\${prefix}/etc" ; then sysconfdir="/etc" CORE_CONF_DIR="/etc/core" else CORE_CONF_DIR="$sysconfdir/core" fi AC_SUBST(CORE_CONF_DIR) if test "$datarootdir" = "\${prefix}/share" ; then datarootdir="${prefix}/share" fi CORE_DATA_DIR="$datarootdir/core" AC_SUBST(CORE_DATA_DIR) # CORE GUI configuration files and preferences in CORE_GUI_CONF_DIR # scenario files in ~/.core/configs/ #AC_ARG_VAR(CORE_GUI_CONF_DIR, [GUI configuration directory.]) AC_ARG_WITH([guiconfdir], [AS_HELP_STRING([--with-guiconfdir=dir], [specify GUI configuration directory])], [CORE_GUI_CONF_DIR="$with_guiconfdir"], [CORE_GUI_CONF_DIR="\${HOME}/.core"]) AC_SUBST(CORE_GUI_CONF_DIR) AC_ARG_ENABLE([gui], [AS_HELP_STRING([--enable-gui[=ARG]], [build and install the GUI (default is yes)])], [], [enable_gui=yes]) AC_SUBST(enable_gui) AC_ARG_ENABLE([daemon], [AS_HELP_STRING([--enable-daemon[=ARG]], [build and install the daemon with Python modules (default is yes)])], [], [enable_daemon=yes]) AC_SUBST(enable_daemon) if test "x$enable_daemon" = "xno"; then want_python=no want_bsd=no want_linux_netns=no fi # CORE state files if test "$localstatedir" = "\${prefix}/var" ; then # use /var instead of /usr/local/var (/usr/local/var/log isn't standard) CORE_STATE_DIR="/var" else CORE_STATE_DIR="$localstatedir" fi AC_SUBST(CORE_STATE_DIR) # default compiler flags # _GNU_SOURCE is defined to get c99 defines for lrint() CFLAGS="$CFLAGS -O3 -Werror -Wall -D_GNU_SOURCE" # debug flags #CFLAGS="$CFLAGS -g -Werror -Wall -D_GNU_SOURCE" # Checks for programs. AC_PROG_AWK AC_PROG_CC AC_PROG_INSTALL AC_PROG_MAKE_SET AC_PROG_RANLIB AM_PATH_PYTHON(2.6, want_python=yes, want_python=no) SEARCHPATH="/usr/sbin:/usr/bin:/sbin:/bin:/usr/local/sbin:/usr/local/bin" # # daemon dependencies # if test "x$enable_daemon" = "xyes" ; then AC_CHECK_PROG(brctl_path, brctl, $as_dir, no, $SEARCHPATH) AC_CHECK_PROG(sysctl_path, sysctl, $as_dir, no, $SEARCHPATH) AC_CHECK_PROG(ebtables_path, ebtables, $as_dir, no, $SEARCHPATH) AC_CHECK_PROG(ip_path, ip, $as_dir, no, $SEARCHPATH) AC_CHECK_PROG(tc_path, tc, $as_dir, no, $SEARCHPATH) AC_CHECK_PROG(ifconfig_path, ifconfig, $as_dir, no, $SEARCHPATH) AC_CHECK_PROG(ngctl_path, ngctl, $as_dir, no, $SEARCHPATH) AC_CHECK_PROG(vimage_path, vimage, $as_dir, no, $SEARCHPATH) AC_CHECK_PROG(mount_path, mount, $as_dir, no, $SEARCHPATH) AC_CHECK_PROG(umount_path, umount, $as_dir, no, $SEARCHPATH) AC_CHECK_PROG(convert, convert, yes, no, $SEARCHPATH) fi #AC_CHECK_PROG(dia, dia, yes, no) AC_CHECK_PROG(help2man, help2man, yes, no, $SEARCHPATH) if test "x$convert" = "xno" ; then AC_MSG_WARN([Could not locate ImageMagick convert.]) #want_docs_missing="convert" fi #if test "x$dia" = "xno" ; then # AC_MSG_WARN([Could not locate dia.]) # want_docs_missing="dia" #fi if test "x$help2man" = "xno" ; then AC_MSG_WARN([Could not locate help2man.]) want_docs_missing="$want_docs_missing help2man" fi if test "x$want_docs_missing" = "x" ; then want_docs=yes else AC_MSG_WARN([Could not find required helper utilities (${want_docs_missing}) so the CORE documentation will not be built.]) want_docs=no fi #AC_PATH_PROGS(tcl_path, [tclsh tclsh8.5 tclsh8.4], no) #if test "x$tcl_path" = "xno" ; then # AC_MSG_ERROR([Could not locate tclsh. Please install Tcl/Tk.]) #fi #AC_PATH_PROGS(wish_path, [wish wish8.5 wish8.4], no) #if test "x$wish_path" = "xno" ; then # AC_MSG_ERROR([Could not locate wish. Please install Tcl/Tk.]) #fi if test "x$enable_daemon" = "xyes" ; then # Checks for libraries. AC_CHECK_LIB([netgraph], [NgMkSockNode]) # Checks for header files. AC_CHECK_HEADERS([arpa/inet.h fcntl.h limits.h stdint.h stdlib.h string.h sys/ioctl.h sys/mount.h sys/socket.h sys/time.h termios.h unistd.h]) # Checks for typedefs, structures, and compiler characteristics. AC_C_INLINE AC_TYPE_INT32_T AC_TYPE_PID_T AC_TYPE_SIZE_T AC_TYPE_SSIZE_T AC_TYPE_UINT32_T AC_TYPE_UINT8_T # Checks for library functions. AC_FUNC_FORK AC_FUNC_MALLOC AC_FUNC_REALLOC AC_CHECK_FUNCS([atexit dup2 gettimeofday memset socket strerror uname]) fi # simple architecture detection if test `uname -m` = "x86_64"; then ARCH=amd64 else ARCH=i386 fi AC_MSG_RESULT([using architecture $ARCH]) AC_SUBST(ARCH) # Host-specific detection want_linux_netns=no want_bsd=no if test `uname -s` = "FreeBSD"; then want_bsd=yes AC_CHECK_PROGS(gmake) # FreeBSD fix for linking libev port below CFLAGS="$CFLAGS -L/usr/local/lib" else want_linux_netns=yes fi if test "x$want_python" = "xno"; then want_bsd=no want_linux_netns=no fi if test "x$want_python" = "xyes"; then if test "x$want_linux_netns" = "xyes"; then CFLAGS_save=$CFLAGS CPPFLAGS_save=$CPPFLAGS if test "x$PYTHON_INCLUDE_DIR" = "x"; then PYTHON_INCLUDE_DIR=`$PYTHON -c "import distutils.sysconfig; print distutils.sysconfig.get_python_inc()"` fi CFLAGS="-I$PYTHON_INCLUDE_DIR" CPPFLAGS="-I$PYTHON_INCLUDE_DIR" AC_CHECK_HEADERS([Python.h], [], AC_MSG_ERROR([Python bindings require Python development headers (try installing your 'python-devel' or 'python-dev' package)])) CFLAGS=$CFLAGS_save CPPFLAGS=$CPPFLAGS_save PKG_CHECK_MODULES(libev, libev, AC_MSG_RESULT([found libev using pkgconfig OK]) AC_SUBST(libev_CFLAGS) AC_SUBST(libev_LIBS), AC_MSG_RESULT([did not find libev using pkconfig...]) AC_CHECK_LIB([ev], ev_set_allocator, AC_MSG_RESULT([found libev OK]) AC_SUBST(libev_CFLAGS) AC_SUBST(libev_LIBS, [-lev]), AC_MSG_ERROR([Python bindings require libev (try installing your 'libev-devel' or 'libev-dev' package)]))) fi AC_SUBST(pyprefix, `eval ${PYTHON} ./python-prefix.py ${PYTHON_PREFIX} ${PYTHON_VERSION}`) if test "${pyprefix}" != "${PYTHON_PREFIX}"; then pythondir=`echo ${pythondir} | sed -e 's,[$][{]prefix[}],${pyprefix},g'` pyexecdir=`echo ${pyexecdir} | sed -e 's,[$][{]exec_prefix[}],${pyprefix},g'` fi else # Namespace support requires Python support want_linux_netns=no fi progs_missing="" if test "x$want_linux_netns" = "xyes"; then if test "x$brctl_path" = "xno" ; then progs_missing="${progs_missing}brctl " brctl_path="/usr/sbin" AC_MSG_ERROR([Could not locate brctl (from bridge-utils package).]) fi if test "x$ebtables_path" = "xno" ; then progs_missing="${progs_missing}ebtables " ebtables_path="/sbin" AC_MSG_ERROR([Could not locate ebtables (from ebtables package).]) fi if test "x$ip_path" = "xno" ; then progs_missing="${progs_missing}ip " ip_path="/sbin" AC_MSG_ERROR([Could not locate ip (from iproute package).]) fi if test "x$tc_path" = "xno" ; then progs_missing="${progs_missing}tc " tc_path="/sbin" AC_MSG_ERROR([Could not locate tc (from iproute package).]) fi fi if test "x$want_bsd" = "xyes"; then if test "x$ifconfig_path" = "xno" ; then AC_MSG_ERROR([Could not locate the 'ifconfig' utility.]) fi if test "x$ngctl_path" = "xno" ; then AC_MSG_ERROR([Could not locate the 'ngctl' utility.]) fi if test "x$vimage_path" = "xno" ; then AC_MSG_ERROR([Could not locate the 'vimage' utility.]) fi fi AC_ARG_WITH([startup], [AS_HELP_STRING([--with-startup=option], [option=systemd,suse,none to install systemd/SUSE init scripts])], [with_startup=$with_startup], [with_startup=initd]) AC_SUBST(with_startup) AC_MSG_RESULT([using startup option $with_startup]) # Variable substitutions AM_CONDITIONAL(WANT_GUI, test x$enable_gui = xyes) AM_CONDITIONAL(WANT_DAEMON, test x$enable_daemon = xyes) AM_CONDITIONAL(WANT_BSD, test x$want_bsd = xyes) AM_CONDITIONAL(WANT_DOCS, test x$want_docs = xyes) AM_CONDITIONAL(WANT_PYTHON, test x$want_python = xyes) AM_CONDITIONAL(WANT_NETNS, test x$want_linux_netns = xyes) AM_CONDITIONAL(WANT_INITD, test x$with_startup = xinitd) AM_CONDITIONAL(WANT_SYSTEMD, test x$with_startup = xsystemd) AM_CONDITIONAL(WANT_SUSE, test x$with_startup = xsuse) if test $cross_compiling = no; then AM_MISSING_PROG(HELP2MAN, help2man) else HELP2MAN=: fi # Output files AC_CONFIG_FILES([Makefile gui/core-gui gui/version.tcl gui/Makefile gui/icons/Makefile scripts/Makefile scripts/perf/Makefile scripts/xen/Makefile doc/Makefile doc/conf.py doc/man/Makefile doc/figures/Makefile daemon/Makefile daemon/src/Makefile daemon/src/version.h daemon/core/constants.py daemon/ns3/Makefile daemon/ns3/corens3/constants.py daemon/doc/Makefile daemon/doc/conf.py packaging/deb/core-daemon.install packaging/deb/core-gui.install packaging/rpm/core.spec],) AC_OUTPUT # Summary text echo \ "------------------------------------------------------------------------ ${PACKAGE_STRING} Configuration: Host System Type: ${host} C Compiler and flags: ${CC} ${CFLAGS} Install prefix: ${prefix} Build GUI: ${enable_gui} GUI path: ${CORE_LIB_DIR} GUI config: ${CORE_GUI_CONF_DIR} Daemon path: ${SBINDIR} Daemon config: ${CORE_CONF_DIR} Python install prefix: ${pyprefix} Python modules: ${pythondir} Logs: ${CORE_STATE_DIR}/log Features to build: Python bindings: ${want_python} Linux Namespaces emulation: ${want_linux_netns} FreeBSD Jails emulation: ${want_bsd} Documentation: ${want_docs} ------------------------------------------------------------------------" if test "x${want_bsd}" = "xyes" ; then # TODO: more sophisticated checks of gmake vs make echo ">>> NOTE: on FreeBSD you should use 'gmake' instead of 'make' ------------------------------------------------------------------------" fi if test "x${want_linux_netns}" = "xyes" ; then echo "On this platform you should run core-gui as a normal user. ------------------------------------------------------------------------" fi if test "x${progs_missing}" != "x" ; then echo ">>> NOTE: the following programs could not be found:" echo " $progs_missing ------------------------------------------------------------------------" fi core-4.8/aclocal.m40000664000175000017500000015260412534327776011130 00000000000000# generated automatically by aclocal 1.13.4 -*- Autoconf -*- # Copyright (C) 1996-2013 Free Software Foundation, Inc. # This file 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. m4_ifndef([AC_CONFIG_MACRO_DIRS], [m4_defun([_AM_CONFIG_MACRO_DIRS], [])m4_defun([AC_CONFIG_MACRO_DIRS], [_AM_CONFIG_MACRO_DIRS($@)])]) m4_ifndef([AC_AUTOCONF_VERSION], [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl m4_if(m4_defn([AC_AUTOCONF_VERSION]), [2.69],, [m4_warning([this file was generated for autoconf 2.69. You have another version of autoconf. It may work, but is not guaranteed to. If you have problems, you may need to regenerate the build system entirely. To do so, use the procedure documented by the package, typically 'autoreconf'.])]) # pkg.m4 - Macros to locate and utilise pkg-config. -*- Autoconf -*- # serial 1 (pkg-config-0.24) # # Copyright © 2004 Scott James Remnant . # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program 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 # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # PKG_PROG_PKG_CONFIG([MIN-VERSION]) # ---------------------------------- AC_DEFUN([PKG_PROG_PKG_CONFIG], [m4_pattern_forbid([^_?PKG_[A-Z_]+$]) m4_pattern_allow([^PKG_CONFIG(_(PATH|LIBDIR|SYSROOT_DIR|ALLOW_SYSTEM_(CFLAGS|LIBS)))?$]) m4_pattern_allow([^PKG_CONFIG_(DISABLE_UNINSTALLED|TOP_BUILD_DIR|DEBUG_SPEW)$]) AC_ARG_VAR([PKG_CONFIG], [path to pkg-config utility]) AC_ARG_VAR([PKG_CONFIG_PATH], [directories to add to pkg-config's search path]) AC_ARG_VAR([PKG_CONFIG_LIBDIR], [path overriding pkg-config's built-in search path]) if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then AC_PATH_TOOL([PKG_CONFIG], [pkg-config]) fi if test -n "$PKG_CONFIG"; then _pkg_min_version=m4_default([$1], [0.9.0]) AC_MSG_CHECKING([pkg-config is at least version $_pkg_min_version]) if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) PKG_CONFIG="" fi fi[]dnl ])# PKG_PROG_PKG_CONFIG # PKG_CHECK_EXISTS(MODULES, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) # # Check to see whether a particular set of modules exists. Similar # to PKG_CHECK_MODULES(), but does not set variables or print errors. # # Please remember that m4 expands AC_REQUIRE([PKG_PROG_PKG_CONFIG]) # only at the first occurence in configure.ac, so if the first place # it's called might be skipped (such as if it is within an "if", you # have to call PKG_CHECK_EXISTS manually # -------------------------------------------------------------- AC_DEFUN([PKG_CHECK_EXISTS], [AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl if test -n "$PKG_CONFIG" && \ AC_RUN_LOG([$PKG_CONFIG --exists --print-errors "$1"]); then m4_default([$2], [:]) m4_ifvaln([$3], [else $3])dnl fi]) # _PKG_CONFIG([VARIABLE], [COMMAND], [MODULES]) # --------------------------------------------- m4_define([_PKG_CONFIG], [if test -n "$$1"; then pkg_cv_[]$1="$$1" elif test -n "$PKG_CONFIG"; then PKG_CHECK_EXISTS([$3], [pkg_cv_[]$1=`$PKG_CONFIG --[]$2 "$3" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes ], [pkg_failed=yes]) else pkg_failed=untried fi[]dnl ])# _PKG_CONFIG # _PKG_SHORT_ERRORS_SUPPORTED # ----------------------------- AC_DEFUN([_PKG_SHORT_ERRORS_SUPPORTED], [AC_REQUIRE([PKG_PROG_PKG_CONFIG]) if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes else _pkg_short_errors_supported=no fi[]dnl ])# _PKG_SHORT_ERRORS_SUPPORTED # PKG_CHECK_MODULES(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND], # [ACTION-IF-NOT-FOUND]) # # # Note that if there is a possibility the first call to # PKG_CHECK_MODULES might not happen, you should be sure to include an # explicit call to PKG_PROG_PKG_CONFIG in your configure.ac # # # -------------------------------------------------------------- AC_DEFUN([PKG_CHECK_MODULES], [AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl AC_ARG_VAR([$1][_CFLAGS], [C compiler flags for $1, overriding pkg-config])dnl AC_ARG_VAR([$1][_LIBS], [linker flags for $1, overriding pkg-config])dnl pkg_failed=no AC_MSG_CHECKING([for $1]) _PKG_CONFIG([$1][_CFLAGS], [cflags], [$2]) _PKG_CONFIG([$1][_LIBS], [libs], [$2]) m4_define([_PKG_TEXT], [Alternatively, you may set the environment variables $1[]_CFLAGS and $1[]_LIBS to avoid the need to call pkg-config. See the pkg-config man page for more details.]) if test $pkg_failed = yes; then AC_MSG_RESULT([no]) _PKG_SHORT_ERRORS_SUPPORTED if test $_pkg_short_errors_supported = yes; then $1[]_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "$2" 2>&1` else $1[]_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "$2" 2>&1` fi # Put the nasty error message in config.log where it belongs echo "$$1[]_PKG_ERRORS" >&AS_MESSAGE_LOG_FD m4_default([$4], [AC_MSG_ERROR( [Package requirements ($2) were not met: $$1_PKG_ERRORS Consider adjusting the PKG_CONFIG_PATH environment variable if you installed software in a non-standard prefix. _PKG_TEXT])[]dnl ]) elif test $pkg_failed = untried; then AC_MSG_RESULT([no]) m4_default([$4], [AC_MSG_FAILURE( [The pkg-config script could not be found or is too old. Make sure it is in your PATH or set the PKG_CONFIG environment variable to the full path to pkg-config. _PKG_TEXT To get pkg-config, see .])[]dnl ]) else $1[]_CFLAGS=$pkg_cv_[]$1[]_CFLAGS $1[]_LIBS=$pkg_cv_[]$1[]_LIBS AC_MSG_RESULT([yes]) $3 fi[]dnl ])# PKG_CHECK_MODULES # PKG_INSTALLDIR(DIRECTORY) # ------------------------- # Substitutes the variable pkgconfigdir as the location where a module # should install pkg-config .pc files. By default the directory is # $libdir/pkgconfig, but the default can be changed by passing # DIRECTORY. The user can override through the --with-pkgconfigdir # parameter. AC_DEFUN([PKG_INSTALLDIR], [m4_pushdef([pkg_default], [m4_default([$1], ['${libdir}/pkgconfig'])]) m4_pushdef([pkg_description], [pkg-config installation directory @<:@]pkg_default[@:>@]) AC_ARG_WITH([pkgconfigdir], [AS_HELP_STRING([--with-pkgconfigdir], pkg_description)],, [with_pkgconfigdir=]pkg_default) AC_SUBST([pkgconfigdir], [$with_pkgconfigdir]) m4_popdef([pkg_default]) m4_popdef([pkg_description]) ]) dnl PKG_INSTALLDIR # PKG_NOARCH_INSTALLDIR(DIRECTORY) # ------------------------- # Substitutes the variable noarch_pkgconfigdir as the location where a # module should install arch-independent pkg-config .pc files. By # default the directory is $datadir/pkgconfig, but the default can be # changed by passing DIRECTORY. The user can override through the # --with-noarch-pkgconfigdir parameter. AC_DEFUN([PKG_NOARCH_INSTALLDIR], [m4_pushdef([pkg_default], [m4_default([$1], ['${datadir}/pkgconfig'])]) m4_pushdef([pkg_description], [pkg-config arch-independent installation directory @<:@]pkg_default[@:>@]) AC_ARG_WITH([noarch-pkgconfigdir], [AS_HELP_STRING([--with-noarch-pkgconfigdir], pkg_description)],, [with_noarch_pkgconfigdir=]pkg_default) AC_SUBST([noarch_pkgconfigdir], [$with_noarch_pkgconfigdir]) m4_popdef([pkg_default]) m4_popdef([pkg_description]) ]) dnl PKG_NOARCH_INSTALLDIR # Copyright (C) 2002-2013 Free Software Foundation, Inc. # # This file 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. # AM_AUTOMAKE_VERSION(VERSION) # ---------------------------- # Automake X.Y traces this macro to ensure aclocal.m4 has been # generated from the m4 files accompanying Automake X.Y. # (This private macro should not be called outside this file.) AC_DEFUN([AM_AUTOMAKE_VERSION], [am__api_version='1.13' dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to dnl require some minimum version. Point them to the right macro. m4_if([$1], [1.13.4], [], [AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl ]) # _AM_AUTOCONF_VERSION(VERSION) # ----------------------------- # aclocal traces this macro to find the Autoconf version. # This is a private macro too. Using m4_define simplifies # the logic in aclocal, which can simply ignore this definition. m4_define([_AM_AUTOCONF_VERSION], []) # AM_SET_CURRENT_AUTOMAKE_VERSION # ------------------------------- # Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced. # This function is AC_REQUIREd by AM_INIT_AUTOMAKE. AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION], [AM_AUTOMAKE_VERSION([1.13.4])dnl m4_ifndef([AC_AUTOCONF_VERSION], [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl _AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))]) # AM_AUX_DIR_EXPAND -*- Autoconf -*- # Copyright (C) 2001-2013 Free Software Foundation, Inc. # # This file 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. # For projects using AC_CONFIG_AUX_DIR([foo]), Autoconf sets # $ac_aux_dir to '$srcdir/foo'. In other projects, it is set to # '$srcdir', '$srcdir/..', or '$srcdir/../..'. # # Of course, Automake must honor this variable whenever it calls a # tool from the auxiliary directory. The problem is that $srcdir (and # therefore $ac_aux_dir as well) can be either absolute or relative, # depending on how configure is run. This is pretty annoying, since # it makes $ac_aux_dir quite unusable in subdirectories: in the top # source directory, any form will work fine, but in subdirectories a # relative path needs to be adjusted first. # # $ac_aux_dir/missing # fails when called from a subdirectory if $ac_aux_dir is relative # $top_srcdir/$ac_aux_dir/missing # fails if $ac_aux_dir is absolute, # fails when called from a subdirectory in a VPATH build with # a relative $ac_aux_dir # # The reason of the latter failure is that $top_srcdir and $ac_aux_dir # are both prefixed by $srcdir. In an in-source build this is usually # harmless because $srcdir is '.', but things will broke when you # start a VPATH build or use an absolute $srcdir. # # So we could use something similar to $top_srcdir/$ac_aux_dir/missing, # iff we strip the leading $srcdir from $ac_aux_dir. That would be: # am_aux_dir='\$(top_srcdir)/'`expr "$ac_aux_dir" : "$srcdir//*\(.*\)"` # and then we would define $MISSING as # MISSING="\${SHELL} $am_aux_dir/missing" # This will work as long as MISSING is not called from configure, because # unfortunately $(top_srcdir) has no meaning in configure. # However there are other variables, like CC, which are often used in # configure, and could therefore not use this "fixed" $ac_aux_dir. # # Another solution, used here, is to always expand $ac_aux_dir to an # absolute PATH. The drawback is that using absolute paths prevent a # configured tree to be moved without reconfiguration. AC_DEFUN([AM_AUX_DIR_EXPAND], [dnl Rely on autoconf to set up CDPATH properly. AC_PREREQ([2.50])dnl # expand $ac_aux_dir to an absolute path am_aux_dir=`cd $ac_aux_dir && pwd` ]) # AM_CONDITIONAL -*- Autoconf -*- # Copyright (C) 1997-2013 Free Software Foundation, Inc. # # This file 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. # AM_CONDITIONAL(NAME, SHELL-CONDITION) # ------------------------------------- # Define a conditional. AC_DEFUN([AM_CONDITIONAL], [AC_PREREQ([2.52])dnl m4_if([$1], [TRUE], [AC_FATAL([$0: invalid condition: $1])], [$1], [FALSE], [AC_FATAL([$0: invalid condition: $1])])dnl AC_SUBST([$1_TRUE])dnl AC_SUBST([$1_FALSE])dnl _AM_SUBST_NOTMAKE([$1_TRUE])dnl _AM_SUBST_NOTMAKE([$1_FALSE])dnl m4_define([_AM_COND_VALUE_$1], [$2])dnl if $2; then $1_TRUE= $1_FALSE='#' else $1_TRUE='#' $1_FALSE= fi AC_CONFIG_COMMANDS_PRE( [if test -z "${$1_TRUE}" && test -z "${$1_FALSE}"; then AC_MSG_ERROR([[conditional "$1" was never defined. Usually this means the macro was only invoked conditionally.]]) fi])]) # Copyright (C) 1999-2013 Free Software Foundation, Inc. # # This file 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. # There are a few dirty hacks below to avoid letting 'AC_PROG_CC' be # written in clear, in which case automake, when reading aclocal.m4, # will think it sees a *use*, and therefore will trigger all it's # C support machinery. Also note that it means that autoscan, seeing # CC etc. in the Makefile, will ask for an AC_PROG_CC use... # _AM_DEPENDENCIES(NAME) # ---------------------- # See how the compiler implements dependency checking. # NAME is "CC", "CXX", "OBJC", "OBJCXX", "UPC", or "GJC". # We try a few techniques and use that to set a single cache variable. # # We don't AC_REQUIRE the corresponding AC_PROG_CC since the latter was # modified to invoke _AM_DEPENDENCIES(CC); we would have a circular # dependency, and given that the user is not expected to run this macro, # just rely on AC_PROG_CC. AC_DEFUN([_AM_DEPENDENCIES], [AC_REQUIRE([AM_SET_DEPDIR])dnl AC_REQUIRE([AM_OUTPUT_DEPENDENCY_COMMANDS])dnl AC_REQUIRE([AM_MAKE_INCLUDE])dnl AC_REQUIRE([AM_DEP_TRACK])dnl m4_if([$1], [CC], [depcc="$CC" am_compiler_list=], [$1], [CXX], [depcc="$CXX" am_compiler_list=], [$1], [OBJC], [depcc="$OBJC" am_compiler_list='gcc3 gcc'], [$1], [OBJCXX], [depcc="$OBJCXX" am_compiler_list='gcc3 gcc'], [$1], [UPC], [depcc="$UPC" am_compiler_list=], [$1], [GCJ], [depcc="$GCJ" am_compiler_list='gcc3 gcc'], [depcc="$$1" am_compiler_list=]) AC_CACHE_CHECK([dependency style of $depcc], [am_cv_$1_dependencies_compiler_type], [if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then # We make a subdir and do the tests there. Otherwise we can end up # making bogus files that we don't know about and never remove. For # instance it was reported that on HP-UX the gcc test will end up # making a dummy file named 'D' -- because '-MD' means "put the output # in D". rm -rf conftest.dir mkdir conftest.dir # Copy depcomp to subdir because otherwise we won't find it if we're # using a relative directory. cp "$am_depcomp" conftest.dir cd conftest.dir # We will build objects and dependencies in a subdirectory because # it helps to detect inapplicable dependency modes. For instance # both Tru64's cc and ICC support -MD to output dependencies as a # side effect of compilation, but ICC will put the dependencies in # the current directory while Tru64 will put them in the object # directory. mkdir sub am_cv_$1_dependencies_compiler_type=none if test "$am_compiler_list" = ""; then am_compiler_list=`sed -n ['s/^#*\([a-zA-Z0-9]*\))$/\1/p'] < ./depcomp` fi am__universal=false m4_case([$1], [CC], [case " $depcc " in #( *\ -arch\ *\ -arch\ *) am__universal=true ;; esac], [CXX], [case " $depcc " in #( *\ -arch\ *\ -arch\ *) am__universal=true ;; esac]) for depmode in $am_compiler_list; do # Setup a source with many dependencies, because some compilers # like to wrap large dependency lists on column 80 (with \), and # we should not choose a depcomp mode which is confused by this. # # We need to recreate these files for each test, as the compiler may # overwrite some of them when testing with obscure command lines. # This happens at least with the AIX C compiler. : > sub/conftest.c for i in 1 2 3 4 5 6; do echo '#include "conftst'$i'.h"' >> sub/conftest.c # Using ": > sub/conftst$i.h" creates only sub/conftst1.h with # Solaris 10 /bin/sh. echo '/* dummy */' > sub/conftst$i.h done echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf # We check with '-c' and '-o' for the sake of the "dashmstdout" # mode. It turns out that the SunPro C++ compiler does not properly # handle '-M -o', and we need to detect this. Also, some Intel # versions had trouble with output in subdirs. am__obj=sub/conftest.${OBJEXT-o} am__minus_obj="-o $am__obj" case $depmode in gcc) # This depmode causes a compiler race in universal mode. test "$am__universal" = false || continue ;; nosideeffect) # After this tag, mechanisms are not by side-effect, so they'll # only be used when explicitly requested. if test "x$enable_dependency_tracking" = xyes; then continue else break fi ;; msvc7 | msvc7msys | msvisualcpp | msvcmsys) # This compiler won't grok '-c -o', but also, the minuso test has # not run yet. These depmodes are late enough in the game, and # so weak that their functioning should not be impacted. am__obj=conftest.${OBJEXT-o} am__minus_obj= ;; none) break ;; esac if depmode=$depmode \ source=sub/conftest.c object=$am__obj \ depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ >/dev/null 2>conftest.err && grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && grep $am__obj sub/conftest.Po > /dev/null 2>&1 && ${MAKE-make} -s -f confmf > /dev/null 2>&1; then # icc doesn't choke on unknown options, it will just issue warnings # or remarks (even with -Werror). So we grep stderr for any message # that says an option was ignored or not supported. # When given -MP, icc 7.0 and 7.1 complain thusly: # icc: Command line warning: ignoring option '-M'; no argument required # The diagnosis changed in icc 8.0: # icc: Command line remark: option '-MP' not supported if (grep 'ignoring option' conftest.err || grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else am_cv_$1_dependencies_compiler_type=$depmode break fi fi done cd .. rm -rf conftest.dir else am_cv_$1_dependencies_compiler_type=none fi ]) AC_SUBST([$1DEPMODE], [depmode=$am_cv_$1_dependencies_compiler_type]) AM_CONDITIONAL([am__fastdep$1], [ test "x$enable_dependency_tracking" != xno \ && test "$am_cv_$1_dependencies_compiler_type" = gcc3]) ]) # AM_SET_DEPDIR # ------------- # Choose a directory name for dependency files. # This macro is AC_REQUIREd in _AM_DEPENDENCIES. AC_DEFUN([AM_SET_DEPDIR], [AC_REQUIRE([AM_SET_LEADING_DOT])dnl AC_SUBST([DEPDIR], ["${am__leading_dot}deps"])dnl ]) # AM_DEP_TRACK # ------------ AC_DEFUN([AM_DEP_TRACK], [AC_ARG_ENABLE([dependency-tracking], [dnl AS_HELP_STRING( [--enable-dependency-tracking], [do not reject slow dependency extractors]) AS_HELP_STRING( [--disable-dependency-tracking], [speeds up one-time build])]) if test "x$enable_dependency_tracking" != xno; then am_depcomp="$ac_aux_dir/depcomp" AMDEPBACKSLASH='\' am__nodep='_no' fi AM_CONDITIONAL([AMDEP], [test "x$enable_dependency_tracking" != xno]) AC_SUBST([AMDEPBACKSLASH])dnl _AM_SUBST_NOTMAKE([AMDEPBACKSLASH])dnl AC_SUBST([am__nodep])dnl _AM_SUBST_NOTMAKE([am__nodep])dnl ]) # Generate code to set up dependency tracking. -*- Autoconf -*- # Copyright (C) 1999-2013 Free Software Foundation, Inc. # # This file 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. # _AM_OUTPUT_DEPENDENCY_COMMANDS # ------------------------------ AC_DEFUN([_AM_OUTPUT_DEPENDENCY_COMMANDS], [{ # Older Autoconf quotes --file arguments for eval, but not when files # are listed without --file. Let's play safe and only enable the eval # if we detect the quoting. case $CONFIG_FILES in *\'*) eval set x "$CONFIG_FILES" ;; *) set x $CONFIG_FILES ;; esac shift for mf do # Strip MF so we end up with the name of the file. mf=`echo "$mf" | sed -e 's/:.*$//'` # Check whether this is an Automake generated Makefile or not. # We used to match only the files named 'Makefile.in', but # some people rename them; so instead we look at the file content. # Grep'ing the first line is not enough: some people post-process # each Makefile.in and add a new line on top of each file to say so. # Grep'ing the whole file is not good either: AIX grep has a line # limit of 2048, but all sed's we know have understand at least 4000. if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then dirpart=`AS_DIRNAME("$mf")` else continue fi # Extract the definition of DEPDIR, am__include, and am__quote # from the Makefile without running 'make'. DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"` test -z "$DEPDIR" && continue am__include=`sed -n 's/^am__include = //p' < "$mf"` test -z "$am__include" && continue am__quote=`sed -n 's/^am__quote = //p' < "$mf"` # Find all dependency output files, they are included files with # $(DEPDIR) in their names. We invoke sed twice because it is the # simplest approach to changing $(DEPDIR) to its actual value in the # expansion. for file in `sed -n " s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \ sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g'`; do # Make sure the directory exists. test -f "$dirpart/$file" && continue fdir=`AS_DIRNAME(["$file"])` AS_MKDIR_P([$dirpart/$fdir]) # echo "creating $dirpart/$file" echo '# dummy' > "$dirpart/$file" done done } ])# _AM_OUTPUT_DEPENDENCY_COMMANDS # AM_OUTPUT_DEPENDENCY_COMMANDS # ----------------------------- # This macro should only be invoked once -- use via AC_REQUIRE. # # This code is only required when automatic dependency tracking # is enabled. FIXME. This creates each '.P' file that we will # need in order to bootstrap the dependency handling code. AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS], [AC_CONFIG_COMMANDS([depfiles], [test x"$AMDEP_TRUE" != x"" || _AM_OUTPUT_DEPENDENCY_COMMANDS], [AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir"]) ]) # Do all the work for Automake. -*- Autoconf -*- # Copyright (C) 1996-2013 Free Software Foundation, Inc. # # This file 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 macro actually does too much. Some checks are only needed if # your package does certain things. But this isn't really a big deal. # AM_INIT_AUTOMAKE(PACKAGE, VERSION, [NO-DEFINE]) # AM_INIT_AUTOMAKE([OPTIONS]) # ----------------------------------------------- # The call with PACKAGE and VERSION arguments is the old style # call (pre autoconf-2.50), which is being phased out. PACKAGE # and VERSION should now be passed to AC_INIT and removed from # the call to AM_INIT_AUTOMAKE. # We support both call styles for the transition. After # the next Automake release, Autoconf can make the AC_INIT # arguments mandatory, and then we can depend on a new Autoconf # release and drop the old call support. AC_DEFUN([AM_INIT_AUTOMAKE], [AC_PREREQ([2.65])dnl dnl Autoconf wants to disallow AM_ names. We explicitly allow dnl the ones we care about. m4_pattern_allow([^AM_[A-Z]+FLAGS$])dnl AC_REQUIRE([AM_SET_CURRENT_AUTOMAKE_VERSION])dnl AC_REQUIRE([AC_PROG_INSTALL])dnl if test "`cd $srcdir && pwd`" != "`pwd`"; then # Use -I$(srcdir) only when $(srcdir) != ., so that make's output # is not polluted with repeated "-I." AC_SUBST([am__isrc], [' -I$(srcdir)'])_AM_SUBST_NOTMAKE([am__isrc])dnl # test to see if srcdir already configured if test -f $srcdir/config.status; then AC_MSG_ERROR([source directory already configured; run "make distclean" there first]) fi fi # test whether we have cygpath if test -z "$CYGPATH_W"; then if (cygpath --version) >/dev/null 2>/dev/null; then CYGPATH_W='cygpath -w' else CYGPATH_W=echo fi fi AC_SUBST([CYGPATH_W]) # Define the identity of the package. dnl Distinguish between old-style and new-style calls. m4_ifval([$2], [AC_DIAGNOSE([obsolete], [$0: two- and three-arguments forms are deprecated.]) m4_ifval([$3], [_AM_SET_OPTION([no-define])])dnl AC_SUBST([PACKAGE], [$1])dnl AC_SUBST([VERSION], [$2])], [_AM_SET_OPTIONS([$1])dnl dnl Diagnose old-style AC_INIT with new-style AM_AUTOMAKE_INIT. m4_if( m4_ifdef([AC_PACKAGE_NAME], [ok]):m4_ifdef([AC_PACKAGE_VERSION], [ok]), [ok:ok],, [m4_fatal([AC_INIT should be called with package and version arguments])])dnl AC_SUBST([PACKAGE], ['AC_PACKAGE_TARNAME'])dnl AC_SUBST([VERSION], ['AC_PACKAGE_VERSION'])])dnl _AM_IF_OPTION([no-define],, [AC_DEFINE_UNQUOTED([PACKAGE], ["$PACKAGE"], [Name of package]) AC_DEFINE_UNQUOTED([VERSION], ["$VERSION"], [Version number of package])])dnl # Some tools Automake needs. AC_REQUIRE([AM_SANITY_CHECK])dnl AC_REQUIRE([AC_ARG_PROGRAM])dnl AM_MISSING_PROG([ACLOCAL], [aclocal-${am__api_version}]) AM_MISSING_PROG([AUTOCONF], [autoconf]) AM_MISSING_PROG([AUTOMAKE], [automake-${am__api_version}]) AM_MISSING_PROG([AUTOHEADER], [autoheader]) AM_MISSING_PROG([MAKEINFO], [makeinfo]) AC_REQUIRE([AM_PROG_INSTALL_SH])dnl AC_REQUIRE([AM_PROG_INSTALL_STRIP])dnl AC_REQUIRE([AC_PROG_MKDIR_P])dnl # For better backward compatibility. To be removed once Automake 1.9.x # dies out for good. For more background, see: # # AC_SUBST([mkdir_p], ['$(MKDIR_P)']) # We need awk for the "check" target. The system "awk" is bad on # some platforms. AC_REQUIRE([AC_PROG_AWK])dnl AC_REQUIRE([AC_PROG_MAKE_SET])dnl AC_REQUIRE([AM_SET_LEADING_DOT])dnl _AM_IF_OPTION([tar-ustar], [_AM_PROG_TAR([ustar])], [_AM_IF_OPTION([tar-pax], [_AM_PROG_TAR([pax])], [_AM_PROG_TAR([v7])])]) _AM_IF_OPTION([no-dependencies],, [AC_PROVIDE_IFELSE([AC_PROG_CC], [_AM_DEPENDENCIES([CC])], [m4_define([AC_PROG_CC], m4_defn([AC_PROG_CC])[_AM_DEPENDENCIES([CC])])])dnl AC_PROVIDE_IFELSE([AC_PROG_CXX], [_AM_DEPENDENCIES([CXX])], [m4_define([AC_PROG_CXX], m4_defn([AC_PROG_CXX])[_AM_DEPENDENCIES([CXX])])])dnl AC_PROVIDE_IFELSE([AC_PROG_OBJC], [_AM_DEPENDENCIES([OBJC])], [m4_define([AC_PROG_OBJC], m4_defn([AC_PROG_OBJC])[_AM_DEPENDENCIES([OBJC])])])dnl AC_PROVIDE_IFELSE([AC_PROG_OBJCXX], [_AM_DEPENDENCIES([OBJCXX])], [m4_define([AC_PROG_OBJCXX], m4_defn([AC_PROG_OBJCXX])[_AM_DEPENDENCIES([OBJCXX])])])dnl ]) AC_REQUIRE([AM_SILENT_RULES])dnl dnl The testsuite driver may need to know about EXEEXT, so add the dnl 'am__EXEEXT' conditional if _AM_COMPILER_EXEEXT was seen. This dnl macro is hooked onto _AC_COMPILER_EXEEXT early, see below. AC_CONFIG_COMMANDS_PRE(dnl [m4_provide_if([_AM_COMPILER_EXEEXT], [AM_CONDITIONAL([am__EXEEXT], [test -n "$EXEEXT"])])])dnl ]) dnl Hook into '_AC_COMPILER_EXEEXT' early to learn its expansion. Do not dnl add the conditional right here, as _AC_COMPILER_EXEEXT may be further dnl mangled by Autoconf and run in a shell conditional statement. m4_define([_AC_COMPILER_EXEEXT], m4_defn([_AC_COMPILER_EXEEXT])[m4_provide([_AM_COMPILER_EXEEXT])]) # When config.status generates a header, we must update the stamp-h file. # This file resides in the same directory as the config header # that is generated. The stamp files are numbered to have different names. # Autoconf calls _AC_AM_CONFIG_HEADER_HOOK (when defined) in the # loop where config.status creates the headers, so we can generate # our stamp files there. AC_DEFUN([_AC_AM_CONFIG_HEADER_HOOK], [# Compute $1's index in $config_headers. _am_arg=$1 _am_stamp_count=1 for _am_header in $config_headers :; do case $_am_header in $_am_arg | $_am_arg:* ) break ;; * ) _am_stamp_count=`expr $_am_stamp_count + 1` ;; esac done echo "timestamp for $_am_arg" >`AS_DIRNAME(["$_am_arg"])`/stamp-h[]$_am_stamp_count]) # Copyright (C) 2001-2013 Free Software Foundation, Inc. # # This file 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. # AM_PROG_INSTALL_SH # ------------------ # Define $install_sh. AC_DEFUN([AM_PROG_INSTALL_SH], [AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl if test x"${install_sh}" != xset; then case $am_aux_dir in *\ * | *\ *) install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;; *) install_sh="\${SHELL} $am_aux_dir/install-sh" esac fi AC_SUBST([install_sh])]) # Copyright (C) 2003-2013 Free Software Foundation, Inc. # # This file 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. # Check whether the underlying file-system supports filenames # with a leading dot. For instance MS-DOS doesn't. AC_DEFUN([AM_SET_LEADING_DOT], [rm -rf .tst 2>/dev/null mkdir .tst 2>/dev/null if test -d .tst; then am__leading_dot=. else am__leading_dot=_ fi rmdir .tst 2>/dev/null AC_SUBST([am__leading_dot])]) # Check to see how 'make' treats includes. -*- Autoconf -*- # Copyright (C) 2001-2013 Free Software Foundation, Inc. # # This file 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. # AM_MAKE_INCLUDE() # ----------------- # Check to see how make treats includes. AC_DEFUN([AM_MAKE_INCLUDE], [am_make=${MAKE-make} cat > confinc << 'END' am__doit: @echo this is the am__doit target .PHONY: am__doit END # If we don't find an include directive, just comment out the code. AC_MSG_CHECKING([for style of include used by $am_make]) am__include="#" am__quote= _am_result=none # First try GNU make style include. echo "include confinc" > confmf # Ignore all kinds of additional output from 'make'. case `$am_make -s -f confmf 2> /dev/null` in #( *the\ am__doit\ target*) am__include=include am__quote= _am_result=GNU ;; esac # Now try BSD make style include. if test "$am__include" = "#"; then echo '.include "confinc"' > confmf case `$am_make -s -f confmf 2> /dev/null` in #( *the\ am__doit\ target*) am__include=.include am__quote="\"" _am_result=BSD ;; esac fi AC_SUBST([am__include]) AC_SUBST([am__quote]) AC_MSG_RESULT([$_am_result]) rm -f confinc confmf ]) # Fake the existence of programs that GNU maintainers use. -*- Autoconf -*- # Copyright (C) 1997-2013 Free Software Foundation, Inc. # # This file 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. # AM_MISSING_PROG(NAME, PROGRAM) # ------------------------------ AC_DEFUN([AM_MISSING_PROG], [AC_REQUIRE([AM_MISSING_HAS_RUN]) $1=${$1-"${am_missing_run}$2"} AC_SUBST($1)]) # AM_MISSING_HAS_RUN # ------------------ # Define MISSING if not defined so far and test if it is modern enough. # If it is, set am_missing_run to use it, otherwise, to nothing. AC_DEFUN([AM_MISSING_HAS_RUN], [AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl AC_REQUIRE_AUX_FILE([missing])dnl if test x"${MISSING+set}" != xset; then case $am_aux_dir in *\ * | *\ *) MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;; *) MISSING="\${SHELL} $am_aux_dir/missing" ;; esac fi # Use eval to expand $SHELL if eval "$MISSING --is-lightweight"; then am_missing_run="$MISSING " else am_missing_run= AC_MSG_WARN(['missing' script is too old or missing]) fi ]) # Helper functions for option handling. -*- Autoconf -*- # Copyright (C) 2001-2013 Free Software Foundation, Inc. # # This file 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. # _AM_MANGLE_OPTION(NAME) # ----------------------- AC_DEFUN([_AM_MANGLE_OPTION], [[_AM_OPTION_]m4_bpatsubst($1, [[^a-zA-Z0-9_]], [_])]) # _AM_SET_OPTION(NAME) # -------------------- # Set option NAME. Presently that only means defining a flag for this option. AC_DEFUN([_AM_SET_OPTION], [m4_define(_AM_MANGLE_OPTION([$1]), [1])]) # _AM_SET_OPTIONS(OPTIONS) # ------------------------ # OPTIONS is a space-separated list of Automake options. AC_DEFUN([_AM_SET_OPTIONS], [m4_foreach_w([_AM_Option], [$1], [_AM_SET_OPTION(_AM_Option)])]) # _AM_IF_OPTION(OPTION, IF-SET, [IF-NOT-SET]) # ------------------------------------------- # Execute IF-SET if OPTION is set, IF-NOT-SET otherwise. AC_DEFUN([_AM_IF_OPTION], [m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])]) # Copyright (C) 1999-2013 Free Software Foundation, Inc. # # This file 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. # AM_PATH_PYTHON([MINIMUM-VERSION], [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) # --------------------------------------------------------------------------- # Adds support for distributing Python modules and packages. To # install modules, copy them to $(pythondir), using the python_PYTHON # automake variable. To install a package with the same name as the # automake package, install to $(pkgpythondir), or use the # pkgpython_PYTHON automake variable. # # The variables $(pyexecdir) and $(pkgpyexecdir) are provided as # locations to install python extension modules (shared libraries). # Another macro is required to find the appropriate flags to compile # extension modules. # # If your package is configured with a different prefix to python, # users will have to add the install directory to the PYTHONPATH # environment variable, or create a .pth file (see the python # documentation for details). # # If the MINIMUM-VERSION argument is passed, AM_PATH_PYTHON will # cause an error if the version of python installed on the system # doesn't meet the requirement. MINIMUM-VERSION should consist of # numbers and dots only. AC_DEFUN([AM_PATH_PYTHON], [ dnl Find a Python interpreter. Python versions prior to 2.0 are not dnl supported. (2.0 was released on October 16, 2000). m4_define_default([_AM_PYTHON_INTERPRETER_LIST], [python python2 python3 python3.3 python3.2 python3.1 python3.0 python2.7 dnl python2.6 python2.5 python2.4 python2.3 python2.2 python2.1 python2.0]) AC_ARG_VAR([PYTHON], [the Python interpreter]) m4_if([$1],[],[ dnl No version check is needed. # Find any Python interpreter. if test -z "$PYTHON"; then AC_PATH_PROGS([PYTHON], _AM_PYTHON_INTERPRETER_LIST, :) fi am_display_PYTHON=python ], [ dnl A version check is needed. if test -n "$PYTHON"; then # If the user set $PYTHON, use it and don't search something else. AC_MSG_CHECKING([whether $PYTHON version is >= $1]) AM_PYTHON_CHECK_VERSION([$PYTHON], [$1], [AC_MSG_RESULT([yes])], [AC_MSG_RESULT([no]) AC_MSG_ERROR([Python interpreter is too old])]) am_display_PYTHON=$PYTHON else # Otherwise, try each interpreter until we find one that satisfies # VERSION. AC_CACHE_CHECK([for a Python interpreter with version >= $1], [am_cv_pathless_PYTHON],[ for am_cv_pathless_PYTHON in _AM_PYTHON_INTERPRETER_LIST none; do test "$am_cv_pathless_PYTHON" = none && break AM_PYTHON_CHECK_VERSION([$am_cv_pathless_PYTHON], [$1], [break]) done]) # Set $PYTHON to the absolute path of $am_cv_pathless_PYTHON. if test "$am_cv_pathless_PYTHON" = none; then PYTHON=: else AC_PATH_PROG([PYTHON], [$am_cv_pathless_PYTHON]) fi am_display_PYTHON=$am_cv_pathless_PYTHON fi ]) if test "$PYTHON" = :; then dnl Run any user-specified action, or abort. m4_default([$3], [AC_MSG_ERROR([no suitable Python interpreter found])]) else dnl Query Python for its version number. Getting [:3] seems to be dnl the best way to do this; it's what "site.py" does in the standard dnl library. AC_CACHE_CHECK([for $am_display_PYTHON version], [am_cv_python_version], [am_cv_python_version=`$PYTHON -c "import sys; sys.stdout.write(sys.version[[:3]])"`]) AC_SUBST([PYTHON_VERSION], [$am_cv_python_version]) dnl Use the values of $prefix and $exec_prefix for the corresponding dnl values of PYTHON_PREFIX and PYTHON_EXEC_PREFIX. These are made dnl distinct variables so they can be overridden if need be. However, dnl general consensus is that you shouldn't need this ability. AC_SUBST([PYTHON_PREFIX], ['${prefix}']) AC_SUBST([PYTHON_EXEC_PREFIX], ['${exec_prefix}']) dnl At times (like when building shared libraries) you may want dnl to know which OS platform Python thinks this is. AC_CACHE_CHECK([for $am_display_PYTHON platform], [am_cv_python_platform], [am_cv_python_platform=`$PYTHON -c "import sys; sys.stdout.write(sys.platform)"`]) AC_SUBST([PYTHON_PLATFORM], [$am_cv_python_platform]) # Just factor out some code duplication. am_python_setup_sysconfig="\ import sys # Prefer sysconfig over distutils.sysconfig, for better compatibility # with python 3.x. See automake bug#10227. try: import sysconfig except ImportError: can_use_sysconfig = 0 else: can_use_sysconfig = 1 # Can't use sysconfig in CPython 2.7, since it's broken in virtualenvs: # try: from platform import python_implementation if python_implementation() == 'CPython' and sys.version[[:3]] == '2.7': can_use_sysconfig = 0 except ImportError: pass" dnl Set up 4 directories: dnl pythondir -- where to install python scripts. This is the dnl site-packages directory, not the python standard library dnl directory like in previous automake betas. This behavior dnl is more consistent with lispdir.m4 for example. dnl Query distutils for this directory. AC_CACHE_CHECK([for $am_display_PYTHON script directory], [am_cv_python_pythondir], [if test "x$prefix" = xNONE then am_py_prefix=$ac_default_prefix else am_py_prefix=$prefix fi am_cv_python_pythondir=`$PYTHON -c " $am_python_setup_sysconfig if can_use_sysconfig: sitedir = sysconfig.get_path('purelib', vars={'base':'$am_py_prefix'}) else: from distutils import sysconfig sitedir = sysconfig.get_python_lib(0, 0, prefix='$am_py_prefix') sys.stdout.write(sitedir)"` case $am_cv_python_pythondir in $am_py_prefix*) am__strip_prefix=`echo "$am_py_prefix" | sed 's|.|.|g'` am_cv_python_pythondir=`echo "$am_cv_python_pythondir" | sed "s,^$am__strip_prefix,$PYTHON_PREFIX,"` ;; *) case $am_py_prefix in /usr|/System*) ;; *) am_cv_python_pythondir=$PYTHON_PREFIX/lib/python$PYTHON_VERSION/site-packages ;; esac ;; esac ]) AC_SUBST([pythondir], [$am_cv_python_pythondir]) dnl pkgpythondir -- $PACKAGE directory under pythondir. Was dnl PYTHON_SITE_PACKAGE in previous betas, but this naming is dnl more consistent with the rest of automake. AC_SUBST([pkgpythondir], [\${pythondir}/$PACKAGE]) dnl pyexecdir -- directory for installing python extension modules dnl (shared libraries) dnl Query distutils for this directory. AC_CACHE_CHECK([for $am_display_PYTHON extension module directory], [am_cv_python_pyexecdir], [if test "x$exec_prefix" = xNONE then am_py_exec_prefix=$am_py_prefix else am_py_exec_prefix=$exec_prefix fi am_cv_python_pyexecdir=`$PYTHON -c " $am_python_setup_sysconfig if can_use_sysconfig: sitedir = sysconfig.get_path('platlib', vars={'platbase':'$am_py_prefix'}) else: from distutils import sysconfig sitedir = sysconfig.get_python_lib(1, 0, prefix='$am_py_prefix') sys.stdout.write(sitedir)"` case $am_cv_python_pyexecdir in $am_py_exec_prefix*) am__strip_prefix=`echo "$am_py_exec_prefix" | sed 's|.|.|g'` am_cv_python_pyexecdir=`echo "$am_cv_python_pyexecdir" | sed "s,^$am__strip_prefix,$PYTHON_EXEC_PREFIX,"` ;; *) case $am_py_exec_prefix in /usr|/System*) ;; *) am_cv_python_pyexecdir=$PYTHON_EXEC_PREFIX/lib/python$PYTHON_VERSION/site-packages ;; esac ;; esac ]) AC_SUBST([pyexecdir], [$am_cv_python_pyexecdir]) dnl pkgpyexecdir -- $(pyexecdir)/$(PACKAGE) AC_SUBST([pkgpyexecdir], [\${pyexecdir}/$PACKAGE]) dnl Run any user-specified action. $2 fi ]) # AM_PYTHON_CHECK_VERSION(PROG, VERSION, [ACTION-IF-TRUE], [ACTION-IF-FALSE]) # --------------------------------------------------------------------------- # Run ACTION-IF-TRUE if the Python interpreter PROG has version >= VERSION. # Run ACTION-IF-FALSE otherwise. # This test uses sys.hexversion instead of the string equivalent (first # word of sys.version), in order to cope with versions such as 2.2c1. # This supports Python 2.0 or higher. (2.0 was released on October 16, 2000). AC_DEFUN([AM_PYTHON_CHECK_VERSION], [prog="import sys # split strings by '.' and convert to numeric. Append some zeros # because we need at least 4 digits for the hex conversion. # map returns an iterator in Python 3.0 and a list in 2.x minver = list(map(int, '$2'.split('.'))) + [[0, 0, 0]] minverhex = 0 # xrange is not present in Python 3.0 and range returns an iterator for i in list(range(0, 4)): minverhex = (minverhex << 8) + minver[[i]] sys.exit(sys.hexversion < minverhex)" AS_IF([AM_RUN_LOG([$1 -c "$prog"])], [$3], [$4])]) # Copyright (C) 2001-2013 Free Software Foundation, Inc. # # This file 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. # AM_RUN_LOG(COMMAND) # ------------------- # Run COMMAND, save the exit status in ac_status, and log it. # (This has been adapted from Autoconf's _AC_RUN_LOG macro.) AC_DEFUN([AM_RUN_LOG], [{ echo "$as_me:$LINENO: $1" >&AS_MESSAGE_LOG_FD ($1) >&AS_MESSAGE_LOG_FD 2>&AS_MESSAGE_LOG_FD ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD (exit $ac_status); }]) # Check to make sure that the build environment is sane. -*- Autoconf -*- # Copyright (C) 1996-2013 Free Software Foundation, Inc. # # This file 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. # AM_SANITY_CHECK # --------------- AC_DEFUN([AM_SANITY_CHECK], [AC_MSG_CHECKING([whether build environment is sane]) # Reject unsafe characters in $srcdir or the absolute working directory # name. Accept space and tab only in the latter. am_lf=' ' case `pwd` in *[[\\\"\#\$\&\'\`$am_lf]]*) AC_MSG_ERROR([unsafe absolute working directory name]);; esac case $srcdir in *[[\\\"\#\$\&\'\`$am_lf\ \ ]]*) AC_MSG_ERROR([unsafe srcdir value: '$srcdir']);; esac # Do 'set' in a subshell so we don't clobber the current shell's # arguments. Must try -L first in case configure is actually a # symlink; some systems play weird games with the mod time of symlinks # (eg FreeBSD returns the mod time of the symlink's containing # directory). if ( am_has_slept=no for am_try in 1 2; do echo "timestamp, slept: $am_has_slept" > conftest.file set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null` if test "$[*]" = "X"; then # -L didn't work. set X `ls -t "$srcdir/configure" conftest.file` fi if test "$[*]" != "X $srcdir/configure conftest.file" \ && test "$[*]" != "X conftest.file $srcdir/configure"; then # If neither matched, then we have a broken ls. This can happen # if, for instance, CONFIG_SHELL is bash and it inherits a # broken ls alias from the environment. This has actually # happened. Such a system could not be considered "sane". AC_MSG_ERROR([ls -t appears to fail. Make sure there is not a broken alias in your environment]) fi if test "$[2]" = conftest.file || test $am_try -eq 2; then break fi # Just in case. sleep 1 am_has_slept=yes done test "$[2]" = conftest.file ) then # Ok. : else AC_MSG_ERROR([newly created file is older than distributed files! Check your system clock]) fi AC_MSG_RESULT([yes]) # If we didn't sleep, we still need to ensure time stamps of config.status and # generated files are strictly newer. am_sleep_pid= if grep 'slept: no' conftest.file >/dev/null 2>&1; then ( sleep 1 ) & am_sleep_pid=$! fi AC_CONFIG_COMMANDS_PRE( [AC_MSG_CHECKING([that generated files are newer than configure]) if test -n "$am_sleep_pid"; then # Hide warnings about reused PIDs. wait $am_sleep_pid 2>/dev/null fi AC_MSG_RESULT([done])]) rm -f conftest.file ]) # Copyright (C) 2009-2013 Free Software Foundation, Inc. # # This file 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. # AM_SILENT_RULES([DEFAULT]) # -------------------------- # Enable less verbose build rules; with the default set to DEFAULT # ("yes" being less verbose, "no" or empty being verbose). AC_DEFUN([AM_SILENT_RULES], [AC_ARG_ENABLE([silent-rules], [dnl AS_HELP_STRING( [--enable-silent-rules], [less verbose build output (undo: "make V=1")]) AS_HELP_STRING( [--disable-silent-rules], [verbose build output (undo: "make V=0")])dnl ]) case $enable_silent_rules in @%:@ ((( yes) AM_DEFAULT_VERBOSITY=0;; no) AM_DEFAULT_VERBOSITY=1;; *) AM_DEFAULT_VERBOSITY=m4_if([$1], [yes], [0], [1]);; esac dnl dnl A few 'make' implementations (e.g., NonStop OS and NextStep) dnl do not support nested variable expansions. dnl See automake bug#9928 and bug#10237. am_make=${MAKE-make} AC_CACHE_CHECK([whether $am_make supports nested variables], [am_cv_make_support_nested_variables], [if AS_ECHO([['TRUE=$(BAR$(V)) BAR0=false BAR1=true V=1 am__doit: @$(TRUE) .PHONY: am__doit']]) | $am_make -f - >/dev/null 2>&1; then am_cv_make_support_nested_variables=yes else am_cv_make_support_nested_variables=no fi]) if test $am_cv_make_support_nested_variables = yes; then dnl Using '$V' instead of '$(V)' breaks IRIX make. AM_V='$(V)' AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)' else AM_V=$AM_DEFAULT_VERBOSITY AM_DEFAULT_V=$AM_DEFAULT_VERBOSITY fi AC_SUBST([AM_V])dnl AM_SUBST_NOTMAKE([AM_V])dnl AC_SUBST([AM_DEFAULT_V])dnl AM_SUBST_NOTMAKE([AM_DEFAULT_V])dnl AC_SUBST([AM_DEFAULT_VERBOSITY])dnl AM_BACKSLASH='\' AC_SUBST([AM_BACKSLASH])dnl _AM_SUBST_NOTMAKE([AM_BACKSLASH])dnl ]) # Copyright (C) 2001-2013 Free Software Foundation, Inc. # # This file 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. # AM_PROG_INSTALL_STRIP # --------------------- # One issue with vendor 'install' (even GNU) is that you can't # specify the program used to strip binaries. This is especially # annoying in cross-compiling environments, where the build's strip # is unlikely to handle the host's binaries. # Fortunately install-sh will honor a STRIPPROG variable, so we # always use install-sh in "make install-strip", and initialize # STRIPPROG with the value of the STRIP variable (set by the user). AC_DEFUN([AM_PROG_INSTALL_STRIP], [AC_REQUIRE([AM_PROG_INSTALL_SH])dnl # Installed binaries are usually stripped using 'strip' when the user # run "make install-strip". However 'strip' might not be the right # tool to use in cross-compilation environments, therefore Automake # will honor the 'STRIP' environment variable to overrule this program. dnl Don't test for $cross_compiling = yes, because it might be 'maybe'. if test "$cross_compiling" != no; then AC_CHECK_TOOL([STRIP], [strip], :) fi INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" AC_SUBST([INSTALL_STRIP_PROGRAM])]) # Copyright (C) 2006-2013 Free Software Foundation, Inc. # # This file 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. # _AM_SUBST_NOTMAKE(VARIABLE) # --------------------------- # Prevent Automake from outputting VARIABLE = @VARIABLE@ in Makefile.in. # This macro is traced by Automake. AC_DEFUN([_AM_SUBST_NOTMAKE]) # AM_SUBST_NOTMAKE(VARIABLE) # -------------------------- # Public sister of _AM_SUBST_NOTMAKE. AC_DEFUN([AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE($@)]) # Check how to create a tarball. -*- Autoconf -*- # Copyright (C) 2004-2013 Free Software Foundation, Inc. # # This file 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. # _AM_PROG_TAR(FORMAT) # -------------------- # Check how to create a tarball in format FORMAT. # FORMAT should be one of 'v7', 'ustar', or 'pax'. # # Substitute a variable $(am__tar) that is a command # writing to stdout a FORMAT-tarball containing the directory # $tardir. # tardir=directory && $(am__tar) > result.tar # # Substitute a variable $(am__untar) that extract such # a tarball read from stdin. # $(am__untar) < result.tar # AC_DEFUN([_AM_PROG_TAR], [# Always define AMTAR for backward compatibility. Yes, it's still used # in the wild :-( We should find a proper way to deprecate it ... AC_SUBST([AMTAR], ['$${TAR-tar}']) # We'll loop over all known methods to create a tar archive until one works. _am_tools='gnutar m4_if([$1], [ustar], [plaintar]) pax cpio none' m4_if([$1], [v7], [am__tar='$${TAR-tar} chof - "$$tardir"' am__untar='$${TAR-tar} xf -'], [m4_case([$1], [ustar], [# The POSIX 1988 'ustar' format is defined with fixed-size fields. # There is notably a 21 bits limit for the UID and the GID. In fact, # the 'pax' utility can hang on bigger UID/GID (see automake bug#8343 # and bug#13588). am_max_uid=2097151 # 2^21 - 1 am_max_gid=$am_max_uid # The $UID and $GID variables are not portable, so we need to resort # to the POSIX-mandated id(1) utility. Errors in the 'id' calls # below are definitely unexpected, so allow the users to see them # (that is, avoid stderr redirection). am_uid=`id -u || echo unknown` am_gid=`id -g || echo unknown` AC_MSG_CHECKING([whether UID '$am_uid' is supported by ustar format]) if test $am_uid -le $am_max_uid; then AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) _am_tools=none fi AC_MSG_CHECKING([whether GID '$am_gid' is supported by ustar format]) if test $am_gid -le $am_max_gid; then AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) _am_tools=none fi], [pax], [], [m4_fatal([Unknown tar format])]) AC_MSG_CHECKING([how to create a $1 tar archive]) # Go ahead even if we have the value already cached. We do so because we # need to set the values for the 'am__tar' and 'am__untar' variables. _am_tools=${am_cv_prog_tar_$1-$_am_tools} for _am_tool in $_am_tools; do case $_am_tool in gnutar) for _am_tar in tar gnutar gtar; do AM_RUN_LOG([$_am_tar --version]) && break done am__tar="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$$tardir"' am__tar_="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$tardir"' am__untar="$_am_tar -xf -" ;; plaintar) # Must skip GNU tar: if it does not support --format= it doesn't create # ustar tarball either. (tar --version) >/dev/null 2>&1 && continue am__tar='tar chf - "$$tardir"' am__tar_='tar chf - "$tardir"' am__untar='tar xf -' ;; pax) am__tar='pax -L -x $1 -w "$$tardir"' am__tar_='pax -L -x $1 -w "$tardir"' am__untar='pax -r' ;; cpio) am__tar='find "$$tardir" -print | cpio -o -H $1 -L' am__tar_='find "$tardir" -print | cpio -o -H $1 -L' am__untar='cpio -i -H $1 -d' ;; none) am__tar=false am__tar_=false am__untar=false ;; esac # If the value was cached, stop now. We just wanted to have am__tar # and am__untar set. test -n "${am_cv_prog_tar_$1}" && break # tar/untar a dummy directory, and stop if the command works. rm -rf conftest.dir mkdir conftest.dir echo GrepMe > conftest.dir/file AM_RUN_LOG([tardir=conftest.dir && eval $am__tar_ >conftest.tar]) rm -rf conftest.dir if test -s conftest.tar; then AM_RUN_LOG([$am__untar /dev/null 2>&1 && break fi done rm -rf conftest.dir AC_CACHE_VAL([am_cv_prog_tar_$1], [am_cv_prog_tar_$1=$_am_tool]) AC_MSG_RESULT([$am_cv_prog_tar_$1])]) AC_SUBST([am__tar]) AC_SUBST([am__untar]) ]) # _AM_PROG_TAR core-4.8/config.h.in0000664000175000017500000001152712534327777011312 00000000000000/* config.h.in. Generated from configure.ac by autoheader. */ /* Define to 1 if you have the header file. */ #undef HAVE_ARPA_INET_H /* Define to 1 if you have the `atexit' function. */ #undef HAVE_ATEXIT /* Define to 1 if you have the `dup2' function. */ #undef HAVE_DUP2 /* Define to 1 if you have the header file. */ #undef HAVE_FCNTL_H /* Define to 1 if you have the `fork' function. */ #undef HAVE_FORK /* Define to 1 if you have the `gettimeofday' function. */ #undef HAVE_GETTIMEOFDAY /* Define to 1 if you have the header file. */ #undef HAVE_INTTYPES_H /* Define to 1 if you have the `netgraph' library (-lnetgraph). */ #undef HAVE_LIBNETGRAPH /* Define to 1 if you have the header file. */ #undef HAVE_LIMITS_H /* Define to 1 if your system has a GNU libc compatible `malloc' function, and to 0 otherwise. */ #undef HAVE_MALLOC /* Define to 1 if you have the header file. */ #undef HAVE_MEMORY_H /* Define to 1 if you have the `memset' function. */ #undef HAVE_MEMSET /* Define to 1 if you have the header file. */ #undef HAVE_PYTHON_H /* Define to 1 if your system has a GNU libc compatible `realloc' function, and to 0 otherwise. */ #undef HAVE_REALLOC /* Define to 1 if you have the `socket' function. */ #undef HAVE_SOCKET /* Define to 1 if you have the header file. */ #undef HAVE_STDINT_H /* Define to 1 if you have the header file. */ #undef HAVE_STDLIB_H /* Define to 1 if you have the `strerror' function. */ #undef HAVE_STRERROR /* Define to 1 if you have the header file. */ #undef HAVE_STRINGS_H /* Define to 1 if you have the header file. */ #undef HAVE_STRING_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_IOCTL_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_MOUNT_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_SOCKET_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_STAT_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_TIME_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_TYPES_H /* Define to 1 if you have the header file. */ #undef HAVE_TERMIOS_H /* Define to 1 if you have the `uname' function. */ #undef HAVE_UNAME /* Define to 1 if you have the header file. */ #undef HAVE_UNISTD_H /* Define to 1 if you have the `vfork' function. */ #undef HAVE_VFORK /* Define to 1 if you have the header file. */ #undef HAVE_VFORK_H /* Define to 1 if `fork' works. */ #undef HAVE_WORKING_FORK /* Define to 1 if `vfork' works. */ #undef HAVE_WORKING_VFORK /* Name of package */ #undef PACKAGE /* Define to the address where bug reports for this package should be sent. */ #undef PACKAGE_BUGREPORT /* Define to the full name of this package. */ #undef PACKAGE_NAME /* Define to the full name and version of this package. */ #undef PACKAGE_STRING /* Define to the one symbol short name of this package. */ #undef PACKAGE_TARNAME /* Define to the home page for this package. */ #undef PACKAGE_URL /* Define to the version of this package. */ #undef PACKAGE_VERSION /* Define to 1 if you have the ANSI C header files. */ #undef STDC_HEADERS /* Version number of package */ #undef VERSION /* Define for Solaris 2.5.1 so the uint32_t typedef from , , or is not used. If the typedef were allowed, the #define below would cause a syntax error. */ #undef _UINT32_T /* Define for Solaris 2.5.1 so the uint8_t typedef from , , or is not used. If the typedef were allowed, the #define below would cause a syntax error. */ #undef _UINT8_T /* Define to `__inline__' or `__inline' if that's what the C compiler calls it, or to nothing if 'inline' is not supported under any name. */ #ifndef __cplusplus #undef inline #endif /* Define to the type of a signed integer type of width exactly 32 bits if such a type exists and the standard includes do not define it. */ #undef int32_t /* Define to rpl_malloc if the replacement function should be used. */ #undef malloc /* Define to `int' if does not define. */ #undef pid_t /* Define to rpl_realloc if the replacement function should be used. */ #undef realloc /* Define to `unsigned int' if does not define. */ #undef size_t /* Define to `int' if does not define. */ #undef ssize_t /* Define to the type of an unsigned integer type of width exactly 32 bits if such a type exists and the standard includes do not define it. */ #undef uint32_t /* Define to the type of an unsigned integer type of width exactly 8 bits if such a type exists and the standard includes do not define it. */ #undef uint8_t /* Define as `fork' if `vfork' does not work. */ #undef vfork core-4.8/README0000664000175000017500000000364412534327775010146 00000000000000 CORE: Common Open Research Emulator Copyright (c)2005-2013 the Boeing Company. See the LICENSE file included in this distribution. == ABOUT ======================================================================= CORE is a tool for emulating networks using a GUI or Python scripts. The CORE project site (1) is a good source of introductory information, with a manual, screenshots, and demos about this software. Also a supplemental Google Code page (2) hosts a wiki, blog, bug tracker, and quickstart guide. 1. http://www.nrl.navy.mil/itd/ncs/products/core 2. http://code.google.com/p/coreemu/ == BUILDING CORE =============================================================== To build this software you should use: ./bootstrap.sh ./configure make sudo make install Here is what is installed with 'make install': /usr/local/bin/core-gui /usr/local/sbin/core-daemon /usr/local/sbin/[vcmd, vnoded, coresendmsg, core-cleanup.sh] /usr/local/lib/core/* /usr/local/share/core/* /usr/local/lib/python2.6/dist-packages/core/* /usr/local/lib/python2.6/dist-packages/[netns,vcmd].so /etc/core/* /etc/init.d/core See the manual for the software required for building CORE. == RUNNING CORE ================================================================ First start the CORE services: sudo /etc/init.d/core-daemon start This automatically runs the core-daemon program. Assuming the GUI is in your PATH, run the CORE GUI by typing the following: core-gui This launches the CORE GUI. You do not need to run the GUI as root. == SUPPORT ===================================================================== If you have questions, comments, or trouble, please use the CORE mailing lists: - core-users for general comments and questions http://pf.itd.nrl.navy.mil/mailman/listinfo/core-users - core-dev for bugs, compile errors, and other development issues http://pf.itd.nrl.navy.mil/mailman/listinfo/core-dev core-4.8/bootstrap.sh0000775000175000017500000000270412534327775011636 00000000000000#!/bin/sh # # (c)2010-2012 the Boeing Company # # author: Jeff Ahrenholz # # Bootstrap the autoconf system. # if [ x$1 = x ]; then # PASS echo "Bootstrapping the autoconf system..." # echo " These autotools programs should be installed for this script to work:" # echo " aclocal, libtoolize, autoheader, automake, autoconf" echo "(Messages below about copying and installing files are normal.)" elif [ x$1 = xclean ]; then # clean - take out the trash echo "Cleaning up the autoconf mess..." rm -rf autom4te.cache config BSDmakefile exit 0; else # help text echo "usage: $0 [clean]" echo -n " Use this script to bootstrap the autoconf build system prior to " echo "running the " echo " ./configure script." exit 1; fi # try to keep everything nice and tidy in ./config if ! [ -d "config" ]; then mkdir config fi # on FreeBSD, discourage use of make UNAME=`uname` if [ x${UNAME} = xFreeBSD ]; then echo "all:" > BSDmakefile echo ' @echo "Please use GNU make instead by typing:"' >> BSDmakefile echo ' @echo " gmake"' >> BSDmakefile echo ' @echo ""' >> BSDmakefile fi # bootstrapping echo "(1/4) Running aclocal..." && aclocal -I config \ && echo "(2/4) Running autoheader..." && autoheader \ && echo "(3/4) Running automake..." \ && automake --add-missing --copy --foreign \ && echo "(4/4) Running autoconf..." && autoconf \ && echo "" \ && echo "You are now ready to run \"./configure\"." core-4.8/LICENSE0000664000175000017500000000241212534327775010263 00000000000000Copyright (c) 2005-2013, the Boeing Company. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE 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 OWNER 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. core-4.8/README-Xen0000664000175000017500000000657212534327775010701 00000000000000CORE Xen README This file describes the xen branch of the CORE development tree which enables machines based on Xen domUs. When you edit node types, you are given the option of changing the machine type (netns, physical, or xen) and the profile for each node type. CORE will create each domU machine on the fly, having a bootable ISO image that contains the root filesystem, and a special persitent area (/rtr/persistent) using a LVM volume where configuration is stored. See the /etc/core/xen.conf file for related settings here. INSTALLATION 1. Tested under OpenSUSE 11.3 which allows installing a Xen dom0 during the install process. 2. Create an LVM volume group having enough free space available for CORE to build logical volumes for domU nodes. The name of this group is set with the 'vg_name=' option in /etc/core/xen.conf. (With 256M per persistent area, 10GB would allow for 40 nodes.) 3. To get libev-devel in OpenSUSE, use: zypper ar http://download.opensuse.org/repositories/X11:/windowmanagers/openSUSE_11.3 WindowManagers zypper install libev-devel 4. In addition to the normal CORE dependencies (see http://code.google.com/p/coreemu/wiki/Quickstart), pyparted-3.2 is used when creating LVM partitions and decorator-3.3.0 is a dependency for pyparted. The 'python setup.py install' and 'make install' need to be performed on these source tarballs as no packages are available. tar xzf decorator-3.3.0.tar.gz cd decorator-3.3.0 python setup.py build python setup.py install tar xzf pyparted-3.2.tar.gz cd pyparted-3.2 ./configure make make install 5. These Xen parameters were used for dom0, by editing /boot/grub/menu.lst: a) Add options to "kernel /xen.gz" line: gnttab_max_nr_frames=128 dom0_mem=1G dom0_max_vcpus=2 dom0_vcpus_pin b) Make Xen default boot by editing the "default" line with the index for the Xen boot option. e.g. change "default 0" to "default 2" Reboot to enable the Xen kernel. 5. Run CORE's ./configure script as root to properly discover sbin binaries. tar xzf core-xen.tgz cd core-xen ./bootstrap.sh ./configure make make install 6. Put your ISO images in /opt/core-xen/iso-files and set the "iso_file=" xen.conf option appropriately. 7. Uncomment the controlnet entry in /etc/core/core.conf: # establish a control backchannel for accessing nodes controlnet = 172.16.0.0/24 This setting governs what IP addresses will be used for a control channel. Given this default setting the host dom0 will have the address 172.16.0.254 assigned to a bridge device; domU VMs will get interfaces joined to this bridge, having addresses such as 172.16.0.1 for node n1, 172.16.0.2 for n2, etc. When 'controlnet =' is unspecified in the core.conf file, double-clicking on a node results in the 'xm console' method. A key mapping is set up so you can press 'F1' then 'F2' to login as root. The key ctrl+']' detaches from the console. Only one console is available per domU VM. 8. When 'controlnet =' is specified, double-clicking on a node results in an attempt to ssh to that node's control IP address. Put a host RSA key for use on the domUs in /opt/core-xen/ssh: mkdir -p /opt/core-xen/ssh ssh-keygen -t rsa -f /opt/core-xen/ssh/ssh_host_rsa_key cp ~/.ssh/id_rsa.pub /opt/core-xen/ssh/authorized_keys chmod 600 /opt/core-xen/ssh/authorized_keys core-4.8/Changelog0000664000175000017500000003300212534327775011067 000000000000002015-06-05 CORE 4.8 * EMANE: - support for EMANE 0.9.2 - run emane in each container when using EMANE 0.9.2 - support using separate control networks for EMANE OTA and event traffic * GUI: - fixed an issue where the adjacency widget lines pointed to old node positions - fixed an issue where not all EMANE 0.9.x IEEE 802.11 MAC parameter were configurable - fixed an issue related to running python scripts from the GUI when using tcl/tk version 8.6 - improved batch mode execution to display the check emulation light status - improved managing multiple sessions - improved support for using multiple canvases - added a reload option to the file menu to revert back to a saved scenario * DAEMON: - support exporting scenarios in NRL Network Modeling Framework 1.0 XML format - support importing scenarios in NRL Network Modeling Framework 1.0 XML format - support exporting the deployed scenario state in NRL NMF XML 1.0 format - improved EMANE post-startup processing to better synchronize distributed emulations - improved how addresses are assigned to tun/tap devices - added support for python state-change callbacks * SERVICES: - added mgen sink and mgen actor services - added oslrv2 and olsr.org services - added a docker service * BUILD: - improved the install/uninstall process - improved debian and rpm packaging * BUGFIXES: - updated the http service for ubuntu 14.04 - improved included examples - shortened the length of network interface names - improved how the core system service manages running the core daemon - fixed an issues related to applying session configuration setting - improved detecting when a distributed emulation is already running - improved documentation 2014-08-06 CORE 4.7 * EMANE: - support for EMANE 0.9.1 - fix error when using Comm Effect model with loss/duplicate string values - enable flow control in virtual transport if enabled in the MAC model - fix bug #150 where EMANE event service/address port were not used * GUI: - support Tcl/Tk 8.6 when available - added --(a)ddress and --(p)ort arguments to core-gui command-line - added File > Execute XML or Python script... option - added File > Execute Python script with options... menu item - when executing Python script from GUI, run in background thread, wait for RUNTIME state - enter RUNTIME state when start button pressed with empty canvas - added support for asymmetric link effects - support link delays up to 274 seconds (netem maximum) - allow runtime changes of WLAN link effects * DAEMON: - set NODE_NAME, NODE_NUMBER, SESSION_SHORT in default vnoded environment - changed host device naming to use veth, tap prefixes; b.n.SS for bridges - allow parsing XML files into live running session - enable link effects between hub/switch and hub/switch connections - update MDR service to use broadcast interfaces for non-WLAN links - allow node class to be specified when initializing XML parser - save and parse canvas origin (reference point) and scale in MP XML - up/down control script session option - fix hash calculation used to determine GRE tunnel keys - use shell script to detach SMF on startup - added NRL services for mgen sink and nrlolsrv2 - use SDT URL session option - added core-manage tool for addons to add/remove/check services, models, and custom node types * API: - implement local flag in Execute Message for running host commands - jitter changed to 64-bit value to align with delay in Link Message - added unidirectional link flag TLV to Link Message - added reconfigure event type for re-generating service config files - return errors in API with failed services * BUGFIXES: - fix HTTP service running under Ubuntu - fixed the following bugs: #150, 169, 188, 220, 225, 230, 231, 242, 244, 247, 248, 250, 251 2013-09-25 CORE 4.6 * NOTE: cored is now core-daemon, and core is now core-gui (for Debian acceptance) * NOTE: /etc/init.d/core is now /etc/init.d/core-daemon (for insserv compatibility) * EMANE: - don't start EMANE locally if no local NEMs - EMANE poststartup() to re-transmit location events during initialization - added debug port to EMANE options - added a basic EMANE 802.11 CORE Python script example - expose transport XML block generation to EmaneModels - expose NEM entry to the EmaneModel so it can be overridden by a model - add the control interface bridge prior to starting EMANE, as some models may - depend on the controlnet functionality - added EMANE model to CORE converter - parse lat/long/alt from node messages, for moving nodes using command-line - fix bug #196 incorrect distance when traversing UTM zones * GUI: - added Cut, Copy, and Paste options to the Edit menu - paste will copy selected services and take care of node and interface - renumbering - implement Edit > Find dialog for searching nodes and links - when copying existing file for a service, perform string replacement of: - "~", "%SESSION%", "%SESSION_DIR%", "%SESSION_USER%", "%NODE%", "%NODENAME%" - use CORE_DATA_DIR insteadof LIBDIR - fix Adjacency Widget to work with OSPFv2 only networks * BUILD: - build/packaging improvements for inclusion on Debian - fix error when running scenario with a mobility script in batch mode - include Linux kernel patches for 3.8 - renamed core-cleanup.sh to core-cleanup for Debian conformance - don't always generate man pages from Makefile; new manpages for coresendmsg and core-daemon * BUGFIXES: - don't auto-assign IPv4/IPv6 addresses when none received in Link Messages (session reconnect) - fixed lock view - fix GUI spinbox errors for Tk 8.5.8 (RHEL/CentOS 6.2) - fix broker node count for distributed session entering the RUNTIME state when - (non-EMANE) WLANs or GreTapBridges are involved; - fix "file exists" error message when distributed session number is re-used - and servers file is written - fix bug #194 configuration dialog too long, make dialog scrollable/resizable - allow float values for loss and duplicates percent - fix the following bugs: 166, 172, 177, 178, 192, 194, 196, 201, 202, 205, 206, 210, 212, 213, 214, 221 2013-04-13 CORE 4.5 * GUI: - improved behavior when starting GUI without daemon, or using File New after connection with daemon is lost - fix various GUI issues when reconnecting to a session - support 3D GUI via output to SDT3D - added "Execute Python script..." entry to the File Menu - support user-defined terminal program instead of hard-coded xterm - added session options for "enable RJ45s", "preserve session dir" - added buttons to the IP Addresses dialog for removing all/selected IPv4/IPv6 - allow sessions with multiple canvases to enter RUNTIME state - added "--addons" startup mode to pass control to code included from addons dir - added "Locked" entry to View menu to prevent moving items - use currently selected node type when invoking a topology generator - updated throughput plots with resizing, color picker, plot labels, locked scales, and save/load plot configuration with imn file - improved session dialog * EMANE: - EMANE 0.8.1 support with backwards-compatibility for 0.7.4 - extend CommEffect model to generate CommEffect events upon receipt of Link Messages having link effects * Services: - updated FTP service with root directory for anonymous users - added HTTP, PCAP, BIRD, RADVD, and Babel services - support copying existing files instead of always generating them - added "Services..." entry to node right-click menu - added "View" button for side-by-side comparison when copying customized config files - updated Quagga daemons to wait for zebra.vty VTY file before starting * General: - XML import and export - renamed "cored.py" to "cored", "coresendmsg.py" to "coresendmsg" - code reorganization and clean-up - updated XML export to write NetworkPlan, MotionPlan, and ServicePlan within a Scenario tag, added new "Save As XML..." File menu entry - added script_start/pause/stop options to Ns2ScriptedMobility - "python" source sub-directory renamed to "daemon" - added "cored -e" option to execute a Python script, adding its session to the active sessions list, allowing for GUI connection - support comma-separated list for custom_services_dir in core.conf file - updated kernel patches for Linux kernel 3.5 - support RFC 6164-style IPv6 /127 addressing * ns-3: - integrate ns-3 node location between CORE and ns-3 simulation - added ns-3 random walk mobility example - updated ns-3 Wifi example to allow GUI connection and moving of nodes * fixed the following bugs: 54, 103, 111, 136, 145, 153, 157, 160, 161, 162, 164, 165, 168, 170, 171, 173, 174, 176, 184, 190, 193 2012-09-25 CORE 4.4 * GUI: - real-time bandwidth plotting tool - added Wireshark and tshark right-click menu items - X,Y coordinates shown in the status bar - updated GUI attribute option to link messages for changing color/width/dash - added sample IPsec and VPN scenarios, how many nodes script - added jitter parameter to WLANs - renamed Experiment menu to Session menu, added session options - use 'key=value' configuration for services, EMANE models, WLAN models, etc. - save only service values that have been customized - copy service parameters from one customized service to another - right-click menu to start/stop/restart each service * EMANE: - EMANE 0.7.4 support - added support for EMANE CommEffect model and Comm Effect controller GUI - added support for EMANE Raw Transport when using RJ45 devices * Services: - improved service customization; allow a service to define custom Tcl tab - added vtysh.conf for Quagga service to support 'write mem' - support scheduled events and services that start N seconds after runtime - added UCARP service * Documentation: - converted the CORE manual to reStructuredText using Sphinx; added Python docs * General: - Python code reorganization - improved cored.py thread locking - merged xen branch into trunk - added an event queue to a session with notion of time zero - added UDP support to cored.py - use UDP by default in coresendmsg.py; added '-H' option to print examples - enter a bash shell by default when running vcmd with no arguments - fixes to distributed emulation entering runtime state - write 'nodes' file upon session startup - make session number and other attributes available in environment - support /etc/core/environment and ~/.core/environment files - added Ns2ScriptedMobility model to Python, removed from the GUI - namespace nodes mount a private /sys - fixed the following bugs: 80, 81, 84, 99, 104, 109, 110, 122, 124, 131, 133, 134, 135, 137, 140, 143, 144, 146, 147, 151, 154, 155 2012-03-07 CORE 4.3 * EMANE 0.7.2 and 0.7.3 support * hook scripts: customize actions at any of six different session states * Check Emulation Light (CEL) exception feedback system * added FTP and XORP services, and service validate commands * services can flag when customization is required * Python classes to support ns-3 simulation experiments * write state, node X,Y position, and servers to pycore session dir * removed over 9,000 lines of unused GUI code * performance monitoring script * batch mode improvements and --closebatch option * export session to EmulationScript XML files * basic range model moved from GUI to Python, supports 3D coordinates * improved WLAN dialog with tabs * added PhysicalNode class for joining real nodes with emulated networks * fixed the following bugs: 50, 75, 76, 79, 82, 83, 85, 86, 89, 90, 92, 94, 96, 98, 100, 112, 113, 116, 119, 120 2011-08-19 CORE 4.2 * EMANE 0.7.1 support - support for Bypass model, Universal PHY, logging, realtime * configurable MAC addresses * control interfaces (backchannel between node and host) * service customization dialog improved (tabbed) * new testing scripts for MDR and EMANE performance testing * improved upgrading of old imn files * new coresendmsg.py utility (deprecates libcoreapi and coreapisend) * new security services, custom service becomes UserDefined * new services and Python scripting chapters in manual * fixes to distributed emulation, linking tunnels/RJ45s with WLANs/hubs/switches * fixed the following bugs: 18, 32, 34, 38, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 52, 53, 55, 57, 58, 60, 62, 64, 65, 66, 68, 71, 72, 74 2011-01-05 CORE 4.1 * new icons for toolbars and nodes * node services introduced, node models deprecated * customizable node types * traffic flow editor with MGEN support * user configs moved from /etc/core/`*` to ~/.core/ * allocate addresses from custom IPv4/IPv6 prefixes * distributed emulation using GRE tunnels * FreeBSD 8.1 now uses cored.py * EMANE 0.6.4 support * numerous bugfixes 2010-08-17 CORE 4.0 * Python framework with Linux network namespace (netns) support (Linux netns is now the primary supported platform) * ability to close the GUI and later reconnect to a running session (netns only) * EMANE integration (netns only) * new topology generators, host file generator * user-editable Observer Widgets * use of /etc/core instead of /usr/local/etc/core * various bugfixes 2009-09-15 CORE 3.5 2009-06-23 CORE 3.4 2009-03-11 CORE 3.3 core-4.8/kernel/0000775000175000017500000000000012534327775010617 500000000000000core-4.8/kernel/core-kernel-2.6.38/0000775000175000017500000000000012534327775013561 500000000000000core-4.8/kernel/core-kernel-2.6.38/Makefile0000664000175000017500000000313412534327775015142 00000000000000VERSION := 2.6.38 TARBALL := /usr/src/linux-source-$(VERSION).tar.bz2 SUBVERSION := -core REVISION := 1.0 PATCHDIR := patches PATCHES := $(sort $(wildcard $(PATCHDIR)/*.patch)) CONFIG := config.core DEPDEBS := linux-source kernel-package po-debconf gettext CONCURRENCY_LEVEL := 2 MAINTAINER ?= Tom Goff EMAIL ?= thomas.goff@boeing.com MAKEKPKGFLAGS := --initrd --rootcmd fakeroot --us --uc \ --append-to-version $(SUBVERSION) --revision $(REVISION) .PHONY: build build: debcheck defaultconfig patch export CONCURRENCY_LEVEL="$(CONCURRENCY_LEVEL)" \ KPKG_MAINTAINER="$(MAINTAINER)" KPKG_EMAIL="$(EMAIL)"; \ cd linux-source-$(VERSION) && \ if [ -f ../$(CONFIG) ]; then \ cat ../$(CONFIG) >> .config; \ fi && \ fakeroot make-kpkg $(MAKEKPKGFLAGS) binary-arch .PHONY: debcheck debcheck: for d in $(DEPDEBS); do \ if ! dpkg-query -s $$d > /dev/null 2>&1; then \ echo ERROR: build dependency not installed: $$d >&2; \ exit 1; \ fi; \ done .PHONY: defaultconfig defaultconfig: linux-source-$(VERSION) export KPKG_MAINTAINER="$(MAINTAINER)" KPKG_EMAIL="$(EMAIL)"; \ cd linux-source-$(VERSION) && make-kpkg $(MAKEKPKGFLAGS) configure .PHONY: patch patch: linux-source-$(VERSION) patch-stamp patch-stamp: $(PATCHES) for p in $^; do \ if ! patch -d linux-source-$(VERSION) -p1 < $$p; then \ echo ERROR: applying patch failed: $$p >&2; \ exit 1; \ fi; \ done touch patch-stamp linux-source-$(VERSION): $(TARBALL) tar -xjf $^ .PHONY: clean clean: rm -rf linux-source-$(VERSION) patch-stamp core-4.8/kernel/core-kernel-2.6.38/README.txt0000664000175000017500000000077112534327775015204 00000000000000Author: Tom Goff The Makefile is basically a wrapper around the make-kpkg command that simplifies building kernel packages. Running make will do some basic dependency checks then build architecture appropriate kernel packages that include changes from the patches directory. The nfnetlink patch is what virtualizes the netfilter queue mechanism; the flow-cache patch allows using IPsec between network namespaces; the ifindex patch virtualizes network interface index numbers. core-4.8/kernel/core-kernel-2.6.38/config.core0000664000175000017500000000003112534327775015612 00000000000000CONFIG_XFRM_STATISTICS=y core-4.8/kernel/core-kernel-2.6.38/patches/0000775000175000017500000000000012534327775015210 500000000000000core-4.8/kernel/core-kernel-2.6.38/patches/00-linux-2.6.38.flow-cache.patch0000664000175000017500000000152412534327775022272 00000000000000Only use the flow cache for the initial network namespace. The flow cache is not per netns and its entries do not include what namespace they are valid for. This causes problems when transformed traffic is sent between namespaces. --- net/core/flow.c | 4 ++++ 1 files changed, 4 insertions(+), 0 deletions(-) diff --git a/net/core/flow.c b/net/core/flow.c index 127c8a7..890510f 100644 --- a/net/core/flow.c +++ b/net/core/flow.c @@ -24,6 +24,7 @@ #include #include #include +#include struct flow_cache_entry { union { @@ -227,6 +228,9 @@ flow_cache_lookup(struct net *net, struct flowi *key, u16 family, u8 dir, if (!fcp->hash_table) goto nocache; + if (!net_eq(net, &init_net)) + goto nocache; + if (fcp->hash_rnd_recalc) flow_new_hash_rnd(fc, fcp); core-4.8/kernel/core-kernel-2.6.38/patches/00-linux-2.6.38.ifindex.patch0000664000175000017500000000301612534327775021706 00000000000000Make network device ifindex sequential per network namespace. --- include/net/net_namespace.h | 2 ++ net/core/dev.c | 13 ++++++------- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/include/net/net_namespace.h b/include/net/net_namespace.h index 1bf812b..6ee0db4 100644 --- a/include/net/net_namespace.h +++ b/include/net/net_namespace.h @@ -57,6 +57,8 @@ struct net { struct sock *rtnl; /* rtnetlink socket */ struct sock *genl_sock; + int ifindex; + struct list_head dev_base_head; struct hlist_head *dev_name_head; struct hlist_head *dev_index_head; diff --git a/net/core/dev.c b/net/core/dev.c index 6561021..764a190 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -4975,12 +4975,11 @@ int dev_ioctl(struct net *net, unsigned int cmd, void __user *arg) */ static int dev_new_index(struct net *net) { - static int ifindex; for (;;) { - if (++ifindex <= 0) - ifindex = 1; - if (!__dev_get_by_index(net, ifindex)) - return ifindex; + if (++net->ifindex <= 0) + net->ifindex = 1; + if (!__dev_get_by_index(net, net->ifindex)) + return net->ifindex; } } @@ -5918,8 +5917,8 @@ int dev_change_net_namespace(struct net_device *dev, struct net *net, const char /* Actually switch the network namespace */ dev_net_set(dev, net); - /* If there is an ifindex conflict assign a new one */ - if (__dev_get_by_index(net, dev->ifindex)) { + /* Assign a new ifindex */ + { int iflink = (dev->iflink == dev->ifindex); dev->ifindex = dev_new_index(net); if (iflink) core-4.8/kernel/core-kernel-2.6.38/patches/00-linux-2.6.38.nfnetlink.patch0000664000175000017500000013541512534327775022261 00000000000000netfilter: make nfnetlink network namespace aware Move static variables to structures allocated per netns and accessed with generic net pointers. Make nfnetlink subsystem registration per netns. Make proc filesystem entries per netns. --- include/linux/netfilter.h | 2 +- include/linux/netfilter/nfnetlink.h | 10 +- include/net/netfilter/nf_queue.h | 3 +- net/ipv4/netfilter/ip_queue.c | 6 +- net/ipv6/netfilter/ip6_queue.c | 6 +- net/netfilter/core.c | 55 +++++++-- net/netfilter/nf_conntrack_netlink.c | 55 ++++++--- net/netfilter/nf_log.c | 34 ++++-- net/netfilter/nf_queue.c | 47 ++++++- net/netfilter/nfnetlink.c | 89 ++++++++++---- net/netfilter/nfnetlink_log.c | 218 ++++++++++++++++++++++------------ net/netfilter/nfnetlink_queue.c | 191 ++++++++++++++++++++---------- net/netfilter/xt_osf.c | 42 +++++-- 13 files changed, 537 insertions(+), 221 deletions(-) diff --git a/include/linux/netfilter.h b/include/linux/netfilter.h index 1893837..f52e719 100644 --- a/include/linux/netfilter.h +++ b/include/linux/netfilter.h @@ -329,7 +329,7 @@ nf_nat_decode_session(struct sk_buff *skb, struct flowi *fl, u_int8_t family) #ifdef CONFIG_PROC_FS #include -extern struct proc_dir_entry *proc_net_netfilter; +extern struct proc_dir_entry *proc_net_netfilter(struct net *net); #endif #else /* !CONFIG_NETFILTER */ diff --git a/include/linux/netfilter/nfnetlink.h b/include/linux/netfilter/nfnetlink.h index 361d6b5..8acaa17 100644 --- a/include/linux/netfilter/nfnetlink.h +++ b/include/linux/netfilter/nfnetlink.h @@ -70,8 +70,10 @@ struct nfnetlink_subsystem { const struct nfnl_callback *cb; /* callback for individual types */ }; -extern int nfnetlink_subsys_register(const struct nfnetlink_subsystem *n); -extern int nfnetlink_subsys_unregister(const struct nfnetlink_subsystem *n); +extern int nfnetlink_subsys_register(struct net *net, + const struct nfnetlink_subsystem *n); +extern int nfnetlink_subsys_unregister(struct net *net, + const struct nfnetlink_subsystem *n); extern int nfnetlink_has_listeners(struct net *net, unsigned int group); extern int nfnetlink_send(struct sk_buff *skb, struct net *net, u32 pid, unsigned group, @@ -79,8 +81,8 @@ extern int nfnetlink_send(struct sk_buff *skb, struct net *net, u32 pid, unsigne extern int nfnetlink_set_err(struct net *net, u32 pid, u32 group, int error); extern int nfnetlink_unicast(struct sk_buff *skb, struct net *net, u_int32_t pid, int flags); -extern void nfnl_lock(void); -extern void nfnl_unlock(void); +extern void nfnl_lock(struct net *net); +extern void nfnl_unlock(struct net *net); #define MODULE_ALIAS_NFNL_SUBSYS(subsys) \ MODULE_ALIAS("nfnetlink-subsys-" __stringify(subsys)) diff --git a/include/net/netfilter/nf_queue.h b/include/net/netfilter/nf_queue.h index 252fd10..3e5bde8 100644 --- a/include/net/netfilter/nf_queue.h +++ b/include/net/netfilter/nf_queue.h @@ -19,7 +19,8 @@ struct nf_queue_entry { /* Packet queuing */ struct nf_queue_handler { - int (*outfn)(struct nf_queue_entry *entry, + int (*outfn)(struct net *net, + struct nf_queue_entry *entry, unsigned int queuenum); char *name; }; diff --git a/net/ipv4/netfilter/ip_queue.c b/net/ipv4/netfilter/ip_queue.c index d2c1311..bccef48 100644 --- a/net/ipv4/netfilter/ip_queue.c +++ b/net/ipv4/netfilter/ip_queue.c @@ -223,7 +223,8 @@ nlmsg_failure: } static int -ipq_enqueue_packet(struct nf_queue_entry *entry, unsigned int queuenum) +ipq_enqueue_packet(struct net *net, struct nf_queue_entry *entry, + unsigned int queuenum) { int status = -EINVAL; struct sk_buff *nskb; @@ -237,6 +238,9 @@ ipq_enqueue_packet(struct nf_queue_entry *entry, unsigned int queuenum) spin_lock_bh(&queue_lock); + if (!net_eq(net, &init_net)) + goto err_out_free_nskb; + if (!peer_pid) goto err_out_free_nskb; diff --git a/net/ipv6/netfilter/ip6_queue.c b/net/ipv6/netfilter/ip6_queue.c index 413ab07..b227789 100644 --- a/net/ipv6/netfilter/ip6_queue.c +++ b/net/ipv6/netfilter/ip6_queue.c @@ -223,7 +223,8 @@ nlmsg_failure: } static int -ipq_enqueue_packet(struct nf_queue_entry *entry, unsigned int queuenum) +ipq_enqueue_packet(struct net *net, struct nf_queue_entry *entry, + unsigned int queuenum) { int status = -EINVAL; struct sk_buff *nskb; @@ -237,6 +238,9 @@ ipq_enqueue_packet(struct nf_queue_entry *entry, unsigned int queuenum) spin_lock_bh(&queue_lock); + if (!net_eq(net, &init_net)) + goto err_out_free_nskb; + if (!peer_pid) goto err_out_free_nskb; diff --git a/net/netfilter/core.c b/net/netfilter/core.c index 4aa614b..157785f 100644 --- a/net/netfilter/core.c +++ b/net/netfilter/core.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include "nf_internals.h" @@ -249,24 +250,62 @@ EXPORT_SYMBOL(nf_conntrack_destroy); #endif /* CONFIG_NF_CONNTRACK */ #ifdef CONFIG_PROC_FS -struct proc_dir_entry *proc_net_netfilter; +static int netfilter_net_id __read_mostly; +struct netns_netfilter { + struct proc_dir_entry *proc_net_netfilter; +}; + +struct proc_dir_entry *proc_net_netfilter(struct net *net) +{ + struct netns_netfilter *net_netfilter; + + net_netfilter = net_generic(net, netfilter_net_id); + return net_netfilter->proc_net_netfilter; +} EXPORT_SYMBOL(proc_net_netfilter); -#endif + +static int __net_init netfilter_net_init(struct net *net) +{ + struct netns_netfilter *net_netfilter = + net_generic(net, netfilter_net_id); + + net_netfilter->proc_net_netfilter = + proc_net_mkdir(net, "netfilter", net->proc_net); + if (!net_netfilter->proc_net_netfilter) { + pr_err("cannot create netfilter proc entry\n"); + return -ENOMEM; + } + + return 0; +} + +static void __net_exit netfilter_net_exit(struct net *net) +{ + proc_net_remove(net, "netfilter"); +} + +static struct pernet_operations netfilter_net_ops = { + .init = netfilter_net_init, + .exit = netfilter_net_exit, + .id = &netfilter_net_id, + .size = sizeof(struct netns_netfilter), +}; +#endif /* CONFIG_PROC_FS */ void __init netfilter_init(void) { int i, h; + +#ifdef CONFIG_PROC_FS + if (register_pernet_subsys(&netfilter_net_ops)) + panic("netfilter_init: cannot initialize per netns operations"); +#endif + for (i = 0; i < ARRAY_SIZE(nf_hooks); i++) { for (h = 0; h < NF_MAX_HOOKS; h++) INIT_LIST_HEAD(&nf_hooks[i][h]); } -#ifdef CONFIG_PROC_FS - proc_net_netfilter = proc_mkdir("netfilter", init_net.proc_net); - if (!proc_net_netfilter) - panic("cannot create netfilter proc entry"); -#endif - if (netfilter_queue_init() < 0) panic("cannot initialize nf_queue"); if (netfilter_log_init() < 0) diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c index eead9db..6c22c74 100644 --- a/net/netfilter/nf_conntrack_netlink.c +++ b/net/netfilter/nf_conntrack_netlink.c @@ -984,20 +984,21 @@ ctnetlink_parse_nat_setup(struct nf_conn *ct, const struct nlattr *attr) { typeof(nfnetlink_parse_nat_setup_hook) parse_nat_setup; + struct net *net = nf_ct_net(ct); parse_nat_setup = rcu_dereference(nfnetlink_parse_nat_setup_hook); if (!parse_nat_setup) { #ifdef CONFIG_MODULES rcu_read_unlock(); spin_unlock_bh(&nf_conntrack_lock); - nfnl_unlock(); + nfnl_unlock(net); if (request_module("nf-nat-ipv4") < 0) { - nfnl_lock(); + nfnl_lock(net); spin_lock_bh(&nf_conntrack_lock); rcu_read_lock(); return -EOPNOTSUPP; } - nfnl_lock(); + nfnl_lock(net); spin_lock_bh(&nf_conntrack_lock); rcu_read_lock(); if (nfnetlink_parse_nat_setup_hook) @@ -2114,28 +2115,59 @@ MODULE_ALIAS("ip_conntrack_netlink"); MODULE_ALIAS_NFNL_SUBSYS(NFNL_SUBSYS_CTNETLINK); MODULE_ALIAS_NFNL_SUBSYS(NFNL_SUBSYS_CTNETLINK_EXP); -static int __init ctnetlink_init(void) +static int __net_init ctnetlink_net_init(struct net *net) { int ret; pr_info("ctnetlink v%s: registering with nfnetlink.\n", version); - ret = nfnetlink_subsys_register(&ctnl_subsys); + ret = nfnetlink_subsys_register(net, &ctnl_subsys); if (ret < 0) { pr_err("ctnetlink_init: cannot register with nfnetlink.\n"); goto err_out; } - ret = nfnetlink_subsys_register(&ctnl_exp_subsys); + ret = nfnetlink_subsys_register(net, &ctnl_exp_subsys); if (ret < 0) { pr_err("ctnetlink_init: cannot register exp with nfnetlink.\n"); goto err_unreg_subsys; } + return 0; + +err_unreg_subsys: + nfnetlink_subsys_unregister(net, &ctnl_subsys); +err_out: + return ret; +} + +static void __net_exit ctnetlink_net_exit(struct net *net) +{ + pr_info("ctnetlink: unregistering from nfnetlink.\n"); + + nfnetlink_subsys_unregister(net, &ctnl_exp_subsys); + nfnetlink_subsys_unregister(net, &ctnl_subsys); +} + +static struct pernet_operations ctnetlink_net_ops = { + .init = ctnetlink_net_init, + .exit = ctnetlink_net_exit, +}; + +static int __init ctnetlink_init(void) +{ + int ret; + + ret = register_pernet_subsys(&ctnetlink_net_ops); + if (ret) { + pr_err("ctnetlink_init: cannot initialize ctnetlink.\n"); + goto err_out; + } + #ifdef CONFIG_NF_CONNTRACK_EVENTS ret = nf_conntrack_register_notifier(&ctnl_notifier); if (ret < 0) { pr_err("ctnetlink_init: cannot register notifier.\n"); - goto err_unreg_exp_subsys; + goto err_out; } ret = nf_ct_expect_register_notifier(&ctnl_notifier_exp); @@ -2150,27 +2182,20 @@ static int __init ctnetlink_init(void) #ifdef CONFIG_NF_CONNTRACK_EVENTS err_unreg_notifier: nf_conntrack_unregister_notifier(&ctnl_notifier); -err_unreg_exp_subsys: - nfnetlink_subsys_unregister(&ctnl_exp_subsys); #endif -err_unreg_subsys: - nfnetlink_subsys_unregister(&ctnl_subsys); err_out: return ret; } static void __exit ctnetlink_exit(void) { - pr_info("ctnetlink: unregistering from nfnetlink.\n"); - nf_ct_remove_userspace_expectations(); #ifdef CONFIG_NF_CONNTRACK_EVENTS nf_ct_expect_unregister_notifier(&ctnl_notifier_exp); nf_conntrack_unregister_notifier(&ctnl_notifier); #endif - nfnetlink_subsys_unregister(&ctnl_exp_subsys); - nfnetlink_subsys_unregister(&ctnl_subsys); + unregister_pernet_subsys(&ctnetlink_net_ops); } module_init(ctnetlink_init); diff --git a/net/netfilter/nf_log.c b/net/netfilter/nf_log.c index 9181699..6c193b1 100644 --- a/net/netfilter/nf_log.c +++ b/net/netfilter/nf_log.c @@ -209,7 +209,24 @@ static const struct file_operations nflog_file_ops = { .release = seq_release, }; +static int __net_init netfilter_log_net_init(struct net *net) +{ + if (!proc_create("nf_log", S_IRUGO, + proc_net_netfilter(net), &nflog_file_ops)) + return -ENOMEM; + + return 0; +} +static void __net_exit netfilter_log_net_exit(struct net *net) +{ + remove_proc_entry("nf_log", proc_net_netfilter(net)); +} + +static struct pernet_operations netfilter_log_net_ops = { + .init = netfilter_log_net_init, + .exit = netfilter_log_net_exit, +}; #endif /* PROC_FS */ #ifdef CONFIG_SYSCTL @@ -288,26 +305,27 @@ static __init int netfilter_log_sysctl_init(void) return 0; } -#else -static __init int netfilter_log_sysctl_init(void) -{ - return 0; -} #endif /* CONFIG_SYSCTL */ int __init netfilter_log_init(void) { int i, r; + #ifdef CONFIG_PROC_FS - if (!proc_create("nf_log", S_IRUGO, - proc_net_netfilter, &nflog_file_ops)) - return -1; + r = register_pernet_subsys(&netfilter_log_net_ops); + if (r) { + pr_err("netfilter_log_init: " + "cannot initialize per netns operations\n"); + return r; + } #endif +#ifdef CONFIG_SYSCTL /* Errors will trigger panic, unroll on error is unnecessary. */ r = netfilter_log_sysctl_init(); if (r < 0) return r; +#endif for (i = NFPROTO_UNSPEC; i < NFPROTO_NUMPROTO; i++) INIT_LIST_HEAD(&(nf_loggers_l[i])); diff --git a/net/netfilter/nf_queue.c b/net/netfilter/nf_queue.c index 74aebed..c9fc05f 100644 --- a/net/netfilter/nf_queue.c +++ b/net/netfilter/nf_queue.c @@ -123,6 +123,7 @@ static int __nf_queue(struct sk_buff *skb, #endif const struct nf_afinfo *afinfo; const struct nf_queue_handler *qh; + struct net *net = NULL; /* QUEUE == DROP if noone is waiting, to be safe. */ rcu_read_lock(); @@ -156,6 +157,17 @@ static int __nf_queue(struct sk_buff *skb, return 0; } + if (indev) + net = dev_net(indev); + else if (outdev) + net = dev_net(outdev); + else if (skb->sk) + net = sock_net(skb->sk); + else { + pr_warn("%s: no net for skb: %p\n", __func__, skb); + goto err_unlock; + } + /* Bump dev refs so they don't vanish while packet is out */ if (indev) dev_hold(indev); @@ -173,7 +185,7 @@ static int __nf_queue(struct sk_buff *skb, #endif skb_dst_force(skb); afinfo->saveroute(skb, entry); - status = qh->outfn(entry, queuenum); + status = qh->outfn(net, entry, queuenum); rcu_read_unlock(); @@ -344,16 +356,37 @@ static const struct file_operations nfqueue_file_ops = { .llseek = seq_lseek, .release = seq_release, }; -#endif /* PROC_FS */ - -int __init netfilter_queue_init(void) +static int __net_init netfilter_queue_net_init(struct net *net) { -#ifdef CONFIG_PROC_FS if (!proc_create("nf_queue", S_IRUGO, - proc_net_netfilter, &nfqueue_file_ops)) + proc_net_netfilter(net), &nfqueue_file_ops)) return -1; -#endif + return 0; } +static void __net_exit netfilter_queue_net_exit(struct net *net) +{ + remove_proc_entry("nf_queue", proc_net_netfilter(net)); +} + +static struct pernet_operations netfilter_queue_net_ops = { + .init = netfilter_queue_net_init, + .exit = netfilter_queue_net_exit, +}; +#endif /* PROC_FS */ + +int __init netfilter_queue_init(void) +{ + int err = 0; + +#ifdef CONFIG_PROC_FS + err = register_pernet_subsys(&netfilter_queue_net_ops); + if (err) + pr_err("netfilter_queue_init: " + "cannot initialize per netns operations\n"); +#endif + + return err; +} diff --git a/net/netfilter/nfnetlink.c b/net/netfilter/nfnetlink.c index b4a4532..235da38 100644 --- a/net/netfilter/nfnetlink.c +++ b/net/netfilter/nfnetlink.c @@ -24,6 +24,8 @@ #include #include #include +#include +#include #include #include #include @@ -35,55 +37,79 @@ MODULE_LICENSE("GPL"); MODULE_AUTHOR("Harald Welte "); MODULE_ALIAS_NET_PF_PROTO(PF_NETLINK, NETLINK_NETFILTER); +static int nfnl_net_id __read_mostly; +struct netns_nfnl { + const struct nfnetlink_subsystem *subsys_table[NFNL_SUBSYS_COUNT]; + struct mutex nfnl_mutex; +}; + static char __initdata nfversion[] = "0.30"; -static const struct nfnetlink_subsystem *subsys_table[NFNL_SUBSYS_COUNT]; -static DEFINE_MUTEX(nfnl_mutex); +static void __nfnl_lock(struct netns_nfnl *net_nfnl) +{ + mutex_lock(&net_nfnl->nfnl_mutex); +} -void nfnl_lock(void) +void nfnl_lock(struct net *net) { - mutex_lock(&nfnl_mutex); + struct netns_nfnl *net_nfnl = net_generic(net, nfnl_net_id); + + __nfnl_lock(net_nfnl); } EXPORT_SYMBOL_GPL(nfnl_lock); -void nfnl_unlock(void) +static void __nfnl_unlock(struct netns_nfnl *net_nfnl) +{ + mutex_unlock(&net_nfnl->nfnl_mutex); +} + +void nfnl_unlock(struct net *net) { - mutex_unlock(&nfnl_mutex); + struct netns_nfnl *net_nfnl = net_generic(net, nfnl_net_id); + + __nfnl_unlock(net_nfnl); } EXPORT_SYMBOL_GPL(nfnl_unlock); -int nfnetlink_subsys_register(const struct nfnetlink_subsystem *n) +int nfnetlink_subsys_register(struct net *net, + const struct nfnetlink_subsystem *n) { - nfnl_lock(); - if (subsys_table[n->subsys_id]) { - nfnl_unlock(); + struct netns_nfnl *net_nfnl = net_generic(net, nfnl_net_id); + + __nfnl_lock(net_nfnl); + if (net_nfnl->subsys_table[n->subsys_id]) { + __nfnl_unlock(net_nfnl); return -EBUSY; } - subsys_table[n->subsys_id] = n; - nfnl_unlock(); + net_nfnl->subsys_table[n->subsys_id] = n; + __nfnl_unlock(net_nfnl); return 0; } EXPORT_SYMBOL_GPL(nfnetlink_subsys_register); -int nfnetlink_subsys_unregister(const struct nfnetlink_subsystem *n) +int nfnetlink_subsys_unregister(struct net *net, + const struct nfnetlink_subsystem *n) { - nfnl_lock(); - subsys_table[n->subsys_id] = NULL; - nfnl_unlock(); + struct netns_nfnl *net_nfnl = net_generic(net, nfnl_net_id); + + __nfnl_lock(net_nfnl); + net_nfnl->subsys_table[n->subsys_id] = NULL; + __nfnl_unlock(net_nfnl); return 0; } EXPORT_SYMBOL_GPL(nfnetlink_subsys_unregister); -static inline const struct nfnetlink_subsystem *nfnetlink_get_subsys(u_int16_t type) +static inline const struct nfnetlink_subsystem *nfnetlink_get_subsys(struct netns_nfnl *net_nfnl, + u_int16_t type) { u_int8_t subsys_id = NFNL_SUBSYS_ID(type); if (subsys_id >= NFNL_SUBSYS_COUNT) return NULL; - return subsys_table[subsys_id]; + return net_nfnl->subsys_table[subsys_id]; } static inline const struct nfnl_callback * @@ -129,6 +155,7 @@ static int nfnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) const struct nfnl_callback *nc; const struct nfnetlink_subsystem *ss; int type, err; + struct netns_nfnl *net_nfnl; if (security_netlink_recv(skb, CAP_NET_ADMIN)) return -EPERM; @@ -137,15 +164,17 @@ static int nfnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) if (nlh->nlmsg_len < NLMSG_LENGTH(sizeof(struct nfgenmsg))) return 0; + net_nfnl = net_generic(net, nfnl_net_id); + type = nlh->nlmsg_type; replay: - ss = nfnetlink_get_subsys(type); + ss = nfnetlink_get_subsys(net_nfnl, type); if (!ss) { #ifdef CONFIG_MODULES - nfnl_unlock(); + nfnl_unlock(net); request_module("nfnetlink-subsys-%d", NFNL_SUBSYS_ID(type)); - nfnl_lock(); - ss = nfnetlink_get_subsys(type); + nfnl_lock(net); + ss = nfnetlink_get_subsys(net_nfnl, type); if (!ss) #endif return -EINVAL; @@ -176,14 +205,18 @@ replay: static void nfnetlink_rcv(struct sk_buff *skb) { - nfnl_lock(); + struct net *net = sock_net(skb->sk); + + nfnl_lock(net); netlink_rcv_skb(skb, &nfnetlink_rcv_msg); - nfnl_unlock(); + nfnl_unlock(net); } static int __net_init nfnetlink_net_init(struct net *net) { struct sock *nfnl; + int i; + struct netns_nfnl *net_nfnl; nfnl = netlink_kernel_create(net, NETLINK_NETFILTER, NFNLGRP_MAX, nfnetlink_rcv, NULL, THIS_MODULE); @@ -191,6 +224,12 @@ static int __net_init nfnetlink_net_init(struct net *net) return -ENOMEM; net->nfnl_stash = nfnl; rcu_assign_pointer(net->nfnl, nfnl); + + net_nfnl = net_generic(net, nfnl_net_id); + for (i = 0; i < NFNL_SUBSYS_COUNT; i++) + net_nfnl->subsys_table[i] = NULL; + mutex_init(&net_nfnl->nfnl_mutex); + return 0; } @@ -208,6 +247,8 @@ static void __net_exit nfnetlink_net_exit_batch(struct list_head *net_exit_list) static struct pernet_operations nfnetlink_net_ops = { .init = nfnetlink_net_init, .exit_batch = nfnetlink_net_exit_batch, + .id = &nfnl_net_id, + .size = sizeof(struct netns_nfnl), }; static int __init nfnetlink_init(void) diff --git a/net/netfilter/nfnetlink_log.c b/net/netfilter/nfnetlink_log.c index 6a1572b..44508bb 100644 --- a/net/netfilter/nfnetlink_log.c +++ b/net/netfilter/nfnetlink_log.c @@ -32,6 +32,8 @@ #include #include #include +#include +#include #include @@ -67,14 +69,17 @@ struct nfulnl_instance { u_int16_t flags; u_int8_t copy_mode; struct rcu_head rcu; -}; -static DEFINE_SPINLOCK(instances_lock); -static atomic_t global_seq; + struct net *net; +}; #define INSTANCE_BUCKETS 16 -static struct hlist_head instance_table[INSTANCE_BUCKETS]; -static unsigned int hash_init; +static int nfulnl_net_id __read_mostly; +struct netns_nfulnl { + spinlock_t instances_lock; + atomic_t global_seq; + struct hlist_head instance_table[INSTANCE_BUCKETS]; +}; static inline u_int8_t instance_hashfn(u_int16_t group_num) { @@ -82,13 +87,13 @@ static inline u_int8_t instance_hashfn(u_int16_t group_num) } static struct nfulnl_instance * -__instance_lookup(u_int16_t group_num) +__instance_lookup(struct netns_nfulnl *net_nfulnl, u_int16_t group_num) { struct hlist_head *head; struct hlist_node *pos; struct nfulnl_instance *inst; - head = &instance_table[instance_hashfn(group_num)]; + head = &net_nfulnl->instance_table[instance_hashfn(group_num)]; hlist_for_each_entry_rcu(inst, pos, head, hlist) { if (inst->group_num == group_num) return inst; @@ -103,12 +108,12 @@ instance_get(struct nfulnl_instance *inst) } static struct nfulnl_instance * -instance_lookup_get(u_int16_t group_num) +instance_lookup_get(struct netns_nfulnl *net_nfulnl, u_int16_t group_num) { struct nfulnl_instance *inst; rcu_read_lock_bh(); - inst = __instance_lookup(group_num); + inst = __instance_lookup(net_nfulnl, group_num); if (inst && !atomic_inc_not_zero(&inst->use)) inst = NULL; rcu_read_unlock_bh(); @@ -118,7 +123,10 @@ instance_lookup_get(u_int16_t group_num) static void nfulnl_instance_free_rcu(struct rcu_head *head) { - kfree(container_of(head, struct nfulnl_instance, rcu)); + struct nfulnl_instance *inst = + container_of(head, struct nfulnl_instance, rcu); + put_net(inst->net); + kfree(inst); module_put(THIS_MODULE); } @@ -132,13 +140,14 @@ instance_put(struct nfulnl_instance *inst) static void nfulnl_timer(unsigned long data); static struct nfulnl_instance * -instance_create(u_int16_t group_num, int pid) +instance_create(struct net *net, struct netns_nfulnl *net_nfulnl, + u_int16_t group_num, int pid) { struct nfulnl_instance *inst; int err; - spin_lock_bh(&instances_lock); - if (__instance_lookup(group_num)) { + spin_lock_bh(&net_nfulnl->instances_lock); + if (__instance_lookup(net_nfulnl, group_num)) { err = -EEXIST; goto out_unlock; } @@ -171,15 +180,17 @@ instance_create(u_int16_t group_num, int pid) inst->copy_mode = NFULNL_COPY_PACKET; inst->copy_range = NFULNL_COPY_RANGE_MAX; + inst->net = get_net(net); + hlist_add_head_rcu(&inst->hlist, - &instance_table[instance_hashfn(group_num)]); + &net_nfulnl->instance_table[instance_hashfn(group_num)]); - spin_unlock_bh(&instances_lock); + spin_unlock_bh(&net_nfulnl->instances_lock); return inst; out_unlock: - spin_unlock_bh(&instances_lock); + spin_unlock_bh(&net_nfulnl->instances_lock); return ERR_PTR(err); } @@ -208,11 +219,11 @@ __instance_destroy(struct nfulnl_instance *inst) } static inline void -instance_destroy(struct nfulnl_instance *inst) +instance_destroy(struct netns_nfulnl *net_nfulnl, struct nfulnl_instance *inst) { - spin_lock_bh(&instances_lock); + spin_lock_bh(&net_nfulnl->instances_lock); __instance_destroy(inst); - spin_unlock_bh(&instances_lock); + spin_unlock_bh(&net_nfulnl->instances_lock); } static int @@ -334,7 +345,7 @@ __nfulnl_send(struct nfulnl_instance *inst) NLMSG_DONE, sizeof(struct nfgenmsg)); - status = nfnetlink_unicast(inst->skb, &init_net, inst->peer_pid, + status = nfnetlink_unicast(inst->skb, inst->net, inst->peer_pid, MSG_DONTWAIT); inst->qlen = 0; @@ -369,7 +380,8 @@ nfulnl_timer(unsigned long data) /* This is an inline function, we don't really care about a long * list of arguments */ static inline int -__build_packet_message(struct nfulnl_instance *inst, +__build_packet_message(struct netns_nfulnl *net_nfulnl, + struct nfulnl_instance *inst, const struct sk_buff *skb, unsigned int data_len, u_int8_t pf, @@ -507,7 +519,7 @@ __build_packet_message(struct nfulnl_instance *inst, /* global sequence number */ if (inst->flags & NFULNL_CFG_F_SEQ_GLOBAL) NLA_PUT_BE32(inst->skb, NFULA_SEQ_GLOBAL, - htonl(atomic_inc_return(&global_seq))); + htonl(atomic_inc_return(&net_nfulnl->global_seq))); if (data_len) { struct nlattr *nla; @@ -563,13 +575,16 @@ nfulnl_log_packet(u_int8_t pf, const struct nf_loginfo *li; unsigned int qthreshold; unsigned int plen; + struct netns_nfulnl *net_nfulnl; + + net_nfulnl = net_generic(dev_net(in), nfulnl_net_id); if (li_user && li_user->type == NF_LOG_TYPE_ULOG) li = li_user; else li = &default_loginfo; - inst = instance_lookup_get(li->u.ulog.group); + inst = instance_lookup_get(net_nfulnl, li->u.ulog.group); if (!inst) return; @@ -651,7 +666,7 @@ nfulnl_log_packet(u_int8_t pf, inst->qlen++; - __build_packet_message(inst, skb, data_len, pf, + __build_packet_message(net_nfulnl, inst, skb, data_len, pf, hooknum, in, out, li, prefix, plen); if (inst->qlen >= qthreshold) @@ -680,24 +695,26 @@ nfulnl_rcv_nl_event(struct notifier_block *this, unsigned long event, void *ptr) { struct netlink_notify *n = ptr; + struct netns_nfulnl *net_nfulnl; + net_nfulnl = net_generic(n->net, nfulnl_net_id); if (event == NETLINK_URELEASE && n->protocol == NETLINK_NETFILTER) { int i; /* destroy all instances for this pid */ - spin_lock_bh(&instances_lock); + spin_lock_bh(&net_nfulnl->instances_lock); for (i = 0; i < INSTANCE_BUCKETS; i++) { struct hlist_node *tmp, *t2; struct nfulnl_instance *inst; - struct hlist_head *head = &instance_table[i]; + struct hlist_head *head = + &net_nfulnl->instance_table[i]; hlist_for_each_entry_safe(inst, tmp, t2, head, hlist) { - if ((net_eq(n->net, &init_net)) && - (n->pid == inst->peer_pid)) + if (n->pid == inst->peer_pid) __instance_destroy(inst); } } - spin_unlock_bh(&instances_lock); + spin_unlock_bh(&net_nfulnl->instances_lock); } return NOTIFY_DONE; } @@ -739,6 +756,10 @@ nfulnl_recv_config(struct sock *ctnl, struct sk_buff *skb, struct nfulnl_instance *inst; struct nfulnl_msg_config_cmd *cmd = NULL; int ret = 0; + struct net *net = sock_net(ctnl); + struct netns_nfulnl *net_nfulnl; + + net_nfulnl = net_generic(net, nfulnl_net_id); if (nfula[NFULA_CFG_CMD]) { u_int8_t pf = nfmsg->nfgen_family; @@ -754,7 +775,7 @@ nfulnl_recv_config(struct sock *ctnl, struct sk_buff *skb, } } - inst = instance_lookup_get(group_num); + inst = instance_lookup_get(net_nfulnl, group_num); if (inst && inst->peer_pid != NETLINK_CB(skb).pid) { ret = -EPERM; goto out_put; @@ -768,7 +789,7 @@ nfulnl_recv_config(struct sock *ctnl, struct sk_buff *skb, goto out_put; } - inst = instance_create(group_num, + inst = instance_create(net, net_nfulnl, group_num, NETLINK_CB(skb).pid); if (IS_ERR(inst)) { ret = PTR_ERR(inst); @@ -781,7 +802,7 @@ nfulnl_recv_config(struct sock *ctnl, struct sk_buff *skb, goto out; } - instance_destroy(inst); + instance_destroy(net_nfulnl, inst); goto out_put; default: ret = -ENOTSUPP; @@ -867,37 +888,45 @@ struct iter_state { unsigned int bucket; }; -static struct hlist_node *get_first(struct iter_state *st) +static struct hlist_node *get_first(struct seq_file *seq) { + struct iter_state *st = seq->private; + struct netns_nfulnl *net_nfulnl; + if (!st) return NULL; + net_nfulnl = net_generic(seq_file_net(seq), nfulnl_net_id); for (st->bucket = 0; st->bucket < INSTANCE_BUCKETS; st->bucket++) { - if (!hlist_empty(&instance_table[st->bucket])) - return rcu_dereference_bh(instance_table[st->bucket].first); + if (!hlist_empty(&net_nfulnl->instance_table[st->bucket])) + return rcu_dereference_bh(net_nfulnl->instance_table[st->bucket].first); } return NULL; } -static struct hlist_node *get_next(struct iter_state *st, struct hlist_node *h) +static struct hlist_node *get_next(struct seq_file *seq, struct hlist_node *h) { + struct iter_state *st = seq->private; + struct netns_nfulnl *net_nfulnl; + + net_nfulnl = net_generic(seq_file_net(seq), nfulnl_net_id); h = rcu_dereference_bh(h->next); while (!h) { if (++st->bucket >= INSTANCE_BUCKETS) return NULL; - h = rcu_dereference_bh(instance_table[st->bucket].first); + h = rcu_dereference_bh(net_nfulnl->instance_table[st->bucket].first); } return h; } -static struct hlist_node *get_idx(struct iter_state *st, loff_t pos) +static struct hlist_node *get_idx(struct seq_file *seq, loff_t pos) { struct hlist_node *head; - head = get_first(st); + head = get_first(seq); if (head) - while (pos && (head = get_next(st, head))) + while (pos && (head = get_next(seq, head))) pos--; return pos ? NULL : head; } @@ -906,13 +935,13 @@ static void *seq_start(struct seq_file *seq, loff_t *pos) __acquires(rcu_bh) { rcu_read_lock_bh(); - return get_idx(seq->private, *pos); + return get_idx(seq, *pos); } static void *seq_next(struct seq_file *s, void *v, loff_t *pos) { (*pos)++; - return get_next(s->private, v); + return get_next(s, v); } static void seq_stop(struct seq_file *s, void *v) @@ -941,8 +970,8 @@ static const struct seq_operations nful_seq_ops = { static int nful_open(struct inode *inode, struct file *file) { - return seq_open_private(file, &nful_seq_ops, - sizeof(struct iter_state)); + return seq_open_net(inode, file, &nful_seq_ops, + sizeof(struct iter_state)); } static const struct file_operations nful_file_ops = { @@ -950,62 +979,103 @@ static const struct file_operations nful_file_ops = { .open = nful_open, .read = seq_read, .llseek = seq_lseek, - .release = seq_release_private, + .release = seq_release_net, }; #endif /* PROC_FS */ -static int __init nfnetlink_log_init(void) +static int __net_init nfnetlink_log_net_init(struct net *net) { - int i, status = -ENOMEM; + int err, i; + struct netns_nfulnl *net_nfulnl = net_generic(net, nfulnl_net_id); + spin_lock_init(&net_nfulnl->instances_lock); + atomic_set(&net_nfulnl->global_seq, 0); for (i = 0; i < INSTANCE_BUCKETS; i++) - INIT_HLIST_HEAD(&instance_table[i]); + INIT_HLIST_HEAD(&net_nfulnl->instance_table[i]); - /* it's not really all that important to have a random value, so - * we can do this from the init function, even if there hasn't - * been that much entropy yet */ - get_random_bytes(&hash_init, sizeof(hash_init)); +#ifdef CONFIG_PROC_FS + if (proc_net_fops_create(net, "nfnetlink_log", 0440, + &nful_file_ops)) + return -ENOMEM; +#endif - netlink_register_notifier(&nfulnl_rtnl_notifier); - status = nfnetlink_subsys_register(&nfulnl_subsys); - if (status < 0) { + err = nfnetlink_subsys_register(net, &nfulnl_subsys); + if (err < 0) { printk(KERN_ERR "log: failed to create netlink socket\n"); - goto cleanup_netlink_notifier; + goto cleanup_proc; } - status = nf_log_register(NFPROTO_UNSPEC, &nfulnl_logger); - if (status < 0) { - printk(KERN_ERR "log: failed to register logger\n"); - goto cleanup_subsys; - } + return 0; +cleanup_proc: #ifdef CONFIG_PROC_FS - if (!proc_create("nfnetlink_log", 0440, - proc_net_netfilter, &nful_file_ops)) - goto cleanup_logger; + proc_net_remove(net, "nfnetlink_log"); #endif - return status; + return err; +} + +static void __net_exit nfnetlink_log_net_exit(struct net *net) +{ + int i; + struct netns_nfulnl *net_nfulnl; + nfnetlink_subsys_unregister(net, &nfulnl_subsys); #ifdef CONFIG_PROC_FS -cleanup_logger: - nf_log_unregister(&nfulnl_logger); + proc_net_remove(net, "nfnetlink_log"); #endif -cleanup_subsys: - nfnetlink_subsys_unregister(&nfulnl_subsys); + + net_nfulnl = net_generic(net, nfulnl_net_id); + spin_lock_bh(&net_nfulnl->instances_lock); + for (i = 0; i < INSTANCE_BUCKETS; i++) { + struct hlist_node *tmp, *t2; + struct nfulnl_instance *inst; + struct hlist_head *head = &net_nfulnl->instance_table[i]; + + hlist_for_each_entry_safe(inst, tmp, t2, head, hlist) + __instance_destroy(inst); + } + spin_unlock_bh(&net_nfulnl->instances_lock); +} + +static struct pernet_operations nfnetlink_log_net_ops = { + .init = nfnetlink_log_net_init, + .exit = nfnetlink_log_net_exit, + .id = &nfulnl_net_id, + .size = sizeof(struct netns_nfulnl), +}; + +static int __init nfnetlink_log_init(void) +{ + int err; + + err = register_pernet_subsys(&nfnetlink_log_net_ops); + if (err) { + pr_err("nfnetlink_log_init: " + "cannot initialize per netns operations\n"); + return err; + } + + netlink_register_notifier(&nfulnl_rtnl_notifier); + + err = nf_log_register(NFPROTO_UNSPEC, &nfulnl_logger); + if (err < 0) { + pr_err("log: failed to register logger\n"); + goto cleanup_netlink_notifier; + } + + return err; + cleanup_netlink_notifier: netlink_unregister_notifier(&nfulnl_rtnl_notifier); - return status; + return err; } static void __exit nfnetlink_log_fini(void) { nf_log_unregister(&nfulnl_logger); -#ifdef CONFIG_PROC_FS - remove_proc_entry("nfnetlink_log", proc_net_netfilter); -#endif - nfnetlink_subsys_unregister(&nfulnl_subsys); netlink_unregister_notifier(&nfulnl_rtnl_notifier); + unregister_pernet_subsys(&nfnetlink_log_net_ops); } MODULE_DESCRIPTION("netfilter userspace logging"); diff --git a/net/netfilter/nfnetlink_queue.c b/net/netfilter/nfnetlink_queue.c index 68e67d1..3fa78a7 100644 --- a/net/netfilter/nfnetlink_queue.c +++ b/net/netfilter/nfnetlink_queue.c @@ -30,6 +30,8 @@ #include #include #include +#include +#include #include @@ -62,12 +64,14 @@ struct nfqnl_instance { struct list_head queue_list; /* packets in queue */ }; -typedef int (*nfqnl_cmpfn)(struct nf_queue_entry *, unsigned long); - -static DEFINE_SPINLOCK(instances_lock); - #define INSTANCE_BUCKETS 16 -static struct hlist_head instance_table[INSTANCE_BUCKETS] __read_mostly; +static int nfqnl_net_id __read_mostly; +struct netns_nfqnl { + spinlock_t instances_lock; + struct hlist_head instance_table[INSTANCE_BUCKETS]; +}; + +typedef int (*nfqnl_cmpfn)(struct nf_queue_entry *, unsigned long); static inline u_int8_t instance_hashfn(u_int16_t queue_num) { @@ -75,13 +79,14 @@ static inline u_int8_t instance_hashfn(u_int16_t queue_num) } static struct nfqnl_instance * -instance_lookup(u_int16_t queue_num) +instance_lookup(struct net *net, u_int16_t queue_num) { struct hlist_head *head; struct hlist_node *pos; struct nfqnl_instance *inst; + struct netns_nfqnl *net_nfqnl = net_generic(net, nfqnl_net_id); - head = &instance_table[instance_hashfn(queue_num)]; + head = &net_nfqnl->instance_table[instance_hashfn(queue_num)]; hlist_for_each_entry_rcu(inst, pos, head, hlist) { if (inst->queue_num == queue_num) return inst; @@ -90,14 +95,15 @@ instance_lookup(u_int16_t queue_num) } static struct nfqnl_instance * -instance_create(u_int16_t queue_num, int pid) +instance_create(struct net *net, u_int16_t queue_num, int pid) { + struct netns_nfqnl *net_nfqnl = net_generic(net, nfqnl_net_id); struct nfqnl_instance *inst; unsigned int h; int err; - spin_lock(&instances_lock); - if (instance_lookup(queue_num)) { + spin_lock(&net_nfqnl->instances_lock); + if (instance_lookup(net, queue_num)) { err = -EEXIST; goto out_unlock; } @@ -122,16 +128,16 @@ instance_create(u_int16_t queue_num, int pid) } h = instance_hashfn(queue_num); - hlist_add_head_rcu(&inst->hlist, &instance_table[h]); + hlist_add_head_rcu(&inst->hlist, &net_nfqnl->instance_table[h]); - spin_unlock(&instances_lock); + spin_unlock(&net_nfqnl->instances_lock); return inst; out_free: kfree(inst); out_unlock: - spin_unlock(&instances_lock); + spin_unlock(&net_nfqnl->instances_lock); return ERR_PTR(err); } @@ -157,11 +163,13 @@ __instance_destroy(struct nfqnl_instance *inst) } static void -instance_destroy(struct nfqnl_instance *inst) +instance_destroy(struct net *net, struct nfqnl_instance *inst) { - spin_lock(&instances_lock); + struct netns_nfqnl *net_nfqnl = net_generic(net, nfqnl_net_id); + + spin_lock(&net_nfqnl->instances_lock); __instance_destroy(inst); - spin_unlock(&instances_lock); + spin_unlock(&net_nfqnl->instances_lock); } static inline void @@ -383,14 +391,15 @@ nla_put_failure: } static int -nfqnl_enqueue_packet(struct nf_queue_entry *entry, unsigned int queuenum) +nfqnl_enqueue_packet(struct net *net, struct nf_queue_entry *entry, + unsigned int queuenum) { struct sk_buff *nskb; struct nfqnl_instance *queue; int err; /* rcu_read_lock()ed by nf_hook_slow() */ - queue = instance_lookup(queuenum); + queue = instance_lookup(net, queuenum); if (!queue) goto err_out; @@ -416,7 +425,7 @@ nfqnl_enqueue_packet(struct nf_queue_entry *entry, unsigned int queuenum) } /* nfnetlink_unicast will either free the nskb or add it to a socket */ - err = nfnetlink_unicast(nskb, &init_net, queue->peer_pid, MSG_DONTWAIT); + err = nfnetlink_unicast(nskb, net, queue->peer_pid, MSG_DONTWAIT); if (err < 0) { queue->queue_user_dropped++; goto err_out_unlock; @@ -525,16 +534,17 @@ dev_cmp(struct nf_queue_entry *entry, unsigned long ifindex) /* drop all packets with either indev or outdev == ifindex from all queue * instances */ static void -nfqnl_dev_drop(int ifindex) +nfqnl_dev_drop(struct net *net, int ifindex) { int i; + struct netns_nfqnl *net_nfqnl = net_generic(net, nfqnl_net_id); rcu_read_lock(); for (i = 0; i < INSTANCE_BUCKETS; i++) { struct hlist_node *tmp; struct nfqnl_instance *inst; - struct hlist_head *head = &instance_table[i]; + struct hlist_head *head = &net_nfqnl->instance_table[i]; hlist_for_each_entry_rcu(inst, tmp, head, hlist) nfqnl_flush(inst, dev_cmp, ifindex); @@ -551,12 +561,9 @@ nfqnl_rcv_dev_event(struct notifier_block *this, { struct net_device *dev = ptr; - if (!net_eq(dev_net(dev), &init_net)) - return NOTIFY_DONE; - /* Drop any packets associated with the downed device */ if (event == NETDEV_DOWN) - nfqnl_dev_drop(dev->ifindex); + nfqnl_dev_drop(dev_net(dev), dev->ifindex); return NOTIFY_DONE; } @@ -569,24 +576,25 @@ nfqnl_rcv_nl_event(struct notifier_block *this, unsigned long event, void *ptr) { struct netlink_notify *n = ptr; + struct netns_nfqnl *net_nfqnl = net_generic(n->net, nfqnl_net_id); if (event == NETLINK_URELEASE && n->protocol == NETLINK_NETFILTER) { int i; /* destroy all instances for this pid */ - spin_lock(&instances_lock); + spin_lock(&net_nfqnl->instances_lock); for (i = 0; i < INSTANCE_BUCKETS; i++) { struct hlist_node *tmp, *t2; struct nfqnl_instance *inst; - struct hlist_head *head = &instance_table[i]; + struct hlist_head *head = + &net_nfqnl->instance_table[i]; hlist_for_each_entry_safe(inst, tmp, t2, head, hlist) { - if ((n->net == &init_net) && - (n->pid == inst->peer_pid)) + if (n->pid == inst->peer_pid) __instance_destroy(inst); } } - spin_unlock(&instances_lock); + spin_unlock(&net_nfqnl->instances_lock); } return NOTIFY_DONE; } @@ -614,9 +622,10 @@ nfqnl_recv_verdict(struct sock *ctnl, struct sk_buff *skb, unsigned int verdict; struct nf_queue_entry *entry; int err; + struct net *net = sock_net(ctnl); rcu_read_lock(); - queue = instance_lookup(queue_num); + queue = instance_lookup(net, queue_num); if (!queue) { err = -ENODEV; goto err_out_unlock; @@ -692,6 +701,7 @@ nfqnl_recv_config(struct sock *ctnl, struct sk_buff *skb, struct nfqnl_instance *queue; struct nfqnl_msg_config_cmd *cmd = NULL; int ret = 0; + struct net *net = sock_net(ctnl); if (nfqa[NFQA_CFG_CMD]) { cmd = nla_data(nfqa[NFQA_CFG_CMD]); @@ -708,7 +718,7 @@ nfqnl_recv_config(struct sock *ctnl, struct sk_buff *skb, } rcu_read_lock(); - queue = instance_lookup(queue_num); + queue = instance_lookup(net, queue_num); if (queue && queue->peer_pid != NETLINK_CB(skb).pid) { ret = -EPERM; goto err_out_unlock; @@ -721,7 +731,8 @@ nfqnl_recv_config(struct sock *ctnl, struct sk_buff *skb, ret = -EBUSY; goto err_out_unlock; } - queue = instance_create(queue_num, NETLINK_CB(skb).pid); + queue = instance_create(net, queue_num, + NETLINK_CB(skb).pid); if (IS_ERR(queue)) { ret = PTR_ERR(queue); goto err_out_unlock; @@ -732,7 +743,7 @@ nfqnl_recv_config(struct sock *ctnl, struct sk_buff *skb, ret = -ENODEV; goto err_out_unlock; } - instance_destroy(queue); + instance_destroy(net, queue); break; case NFQNL_CFG_CMD_PF_BIND: case NFQNL_CFG_CMD_PF_UNBIND: @@ -799,13 +810,15 @@ struct iter_state { static struct hlist_node *get_first(struct seq_file *seq) { struct iter_state *st = seq->private; + struct net *net = seq_file_net(seq); + struct netns_nfqnl *net_nfqnl = net_generic(net, nfqnl_net_id); if (!st) return NULL; for (st->bucket = 0; st->bucket < INSTANCE_BUCKETS; st->bucket++) { - if (!hlist_empty(&instance_table[st->bucket])) - return instance_table[st->bucket].first; + if (!hlist_empty(&net_nfqnl->instance_table[st->bucket])) + return net_nfqnl->instance_table[st->bucket].first; } return NULL; } @@ -813,13 +826,15 @@ static struct hlist_node *get_first(struct seq_file *seq) static struct hlist_node *get_next(struct seq_file *seq, struct hlist_node *h) { struct iter_state *st = seq->private; + struct net *net = seq_file_net(seq); + struct netns_nfqnl *net_nfqnl = net_generic(net, nfqnl_net_id); h = h->next; while (!h) { if (++st->bucket >= INSTANCE_BUCKETS) return NULL; - h = instance_table[st->bucket].first; + h = net_nfqnl->instance_table[st->bucket].first; } return h; } @@ -836,9 +851,11 @@ static struct hlist_node *get_idx(struct seq_file *seq, loff_t pos) } static void *seq_start(struct seq_file *seq, loff_t *pos) - __acquires(instances_lock) { - spin_lock(&instances_lock); + struct netns_nfqnl *net_nfqnl = + net_generic(seq_file_net(seq), nfqnl_net_id); + + spin_lock(&net_nfqnl->instances_lock); return get_idx(seq, *pos); } @@ -849,9 +866,11 @@ static void *seq_next(struct seq_file *s, void *v, loff_t *pos) } static void seq_stop(struct seq_file *s, void *v) - __releases(instances_lock) { - spin_unlock(&instances_lock); + struct netns_nfqnl *net_nfqnl = + net_generic(seq_file_net(s), nfqnl_net_id); + + spin_unlock(&net_nfqnl->instances_lock); } static int seq_show(struct seq_file *s, void *v) @@ -875,8 +894,8 @@ static const struct seq_operations nfqnl_seq_ops = { static int nfqnl_open(struct inode *inode, struct file *file) { - return seq_open_private(file, &nfqnl_seq_ops, - sizeof(struct iter_state)); + return seq_open_net(inode, file, &nfqnl_seq_ops, + sizeof(struct iter_state)); } static const struct file_operations nfqnl_file_ops = { @@ -884,54 +903,96 @@ static const struct file_operations nfqnl_file_ops = { .open = nfqnl_open, .read = seq_read, .llseek = seq_lseek, - .release = seq_release_private, + .release = seq_release_net, }; #endif /* PROC_FS */ -static int __init nfnetlink_queue_init(void) +static int __net_init nfnetlink_queue_net_init(struct net *net) { - int i, status = -ENOMEM; + int err, i; + struct netns_nfqnl *net_nfqnl = net_generic(net, nfqnl_net_id); + spin_lock_init(&net_nfqnl->instances_lock); for (i = 0; i < INSTANCE_BUCKETS; i++) - INIT_HLIST_HEAD(&instance_table[i]); + INIT_HLIST_HEAD(&net_nfqnl->instance_table[i]); - netlink_register_notifier(&nfqnl_rtnl_notifier); - status = nfnetlink_subsys_register(&nfqnl_subsys); - if (status < 0) { +#ifdef CONFIG_PROC_FS + if (proc_net_fops_create(net, "nfnetlink_queue", 0440, + &nfqnl_file_ops) == NULL) + return -ENOMEM; +#endif + + err = nfnetlink_subsys_register(net, &nfqnl_subsys); + if (err < 0) { printk(KERN_ERR "nf_queue: failed to create netlink socket\n"); - goto cleanup_netlink_notifier; + goto cleanup_proc; } + return 0; + +cleanup_proc: #ifdef CONFIG_PROC_FS - if (!proc_create("nfnetlink_queue", 0440, - proc_net_netfilter, &nfqnl_file_ops)) - goto cleanup_subsys; + proc_net_remove(net, "nfnetlink_queue"); #endif + return err; +} - register_netdevice_notifier(&nfqnl_dev_notifier); - return status; +static void __net_exit nfnetlink_queue_net_exit(struct net *net) +{ + int i; + struct netns_nfqnl *net_nfqnl = net_generic(net, nfqnl_net_id); + nfnetlink_subsys_unregister(net, &nfqnl_subsys); #ifdef CONFIG_PROC_FS -cleanup_subsys: - nfnetlink_subsys_unregister(&nfqnl_subsys); + proc_net_remove(net, "nfnetlink_queue"); #endif -cleanup_netlink_notifier: - netlink_unregister_notifier(&nfqnl_rtnl_notifier); - return status; + + spin_lock(&net_nfqnl->instances_lock); + for (i = 0; i < INSTANCE_BUCKETS; i++) { + struct hlist_node *tmp, *t2; + struct nfqnl_instance *inst; + struct hlist_head *head = &net_nfqnl->instance_table[i]; + + hlist_for_each_entry_safe(inst, tmp, t2, head, hlist) + __instance_destroy(inst); + } + spin_unlock(&net_nfqnl->instances_lock); +} + +static struct pernet_operations nfnetlink_queue_net_ops = { + .init = nfnetlink_queue_net_init, + .exit = nfnetlink_queue_net_exit, + .id = &nfqnl_net_id, + .size = sizeof(struct netns_nfqnl), +}; + +static int __init nfnetlink_queue_init(void) +{ + int err; + + err = register_pernet_subsys(&nfnetlink_queue_net_ops); + if (err) { + pr_err("nfnetlink_queue_init: " + "cannot initialize per netns operations\n"); + return err; + } + + netlink_register_notifier(&nfqnl_rtnl_notifier); + register_netdevice_notifier(&nfqnl_dev_notifier); + + return err; } static void __exit nfnetlink_queue_fini(void) { nf_unregister_queue_handlers(&nfqh); unregister_netdevice_notifier(&nfqnl_dev_notifier); -#ifdef CONFIG_PROC_FS - remove_proc_entry("nfnetlink_queue", proc_net_netfilter); -#endif - nfnetlink_subsys_unregister(&nfqnl_subsys); netlink_unregister_notifier(&nfqnl_rtnl_notifier); rcu_barrier(); /* Wait for completion of call_rcu()'s */ + + unregister_pernet_subsys(&nfnetlink_queue_net_ops); } MODULE_DESCRIPTION("netfilter packet queue handler"); diff --git a/net/netfilter/xt_osf.c b/net/netfilter/xt_osf.c index 4327e10..62fdeb1 100644 --- a/net/netfilter/xt_osf.c +++ b/net/netfilter/xt_osf.c @@ -31,6 +31,7 @@ #include #include +#include #include #include @@ -359,6 +360,27 @@ xt_osf_match_packet(const struct sk_buff *skb, struct xt_action_param *p) return fmatch == FMATCH_OK; } +static int __net_init xt_osf_net_init(struct net *net) +{ + int err; + + err = nfnetlink_subsys_register(net, &xt_osf_nfnetlink); + if (err < 0) + pr_err("Failed to register OSF nsfnetlink helper (%d)\n", err); + + return err; +} + +static void __net_exit xt_osf_net_exit(struct net *net) +{ + nfnetlink_subsys_unregister(net, &xt_osf_nfnetlink); +} + +static struct pernet_operations xt_osf_net_ops = { + .init = xt_osf_net_init, + .exit = xt_osf_net_exit, +}; + static struct xt_match xt_osf_match = { .name = "osf", .revision = 0, @@ -374,29 +396,26 @@ static struct xt_match xt_osf_match = { static int __init xt_osf_init(void) { - int err = -EINVAL; + int err; int i; for (i=0; i> .config; \ fi && \ fakeroot make-kpkg $(MAKEKPKGFLAGS) binary-arch .PHONY: debcheck debcheck: for d in $(DEPDEBS); do \ if ! dpkg-query -s $$d > /dev/null 2>&1; then \ echo ERROR: build dependency not installed: $$d >&2; \ exit 1; \ fi; \ done .PHONY: defaultconfig defaultconfig: linux-source-$(VERSION) export KPKG_MAINTAINER="$(MAINTAINER)" KPKG_EMAIL="$(EMAIL)"; \ cd linux-source-$(VERSION) && make-kpkg $(MAKEKPKGFLAGS) configure .PHONY: patch patch: linux-source-$(VERSION) patch-stamp patch-stamp: $(PATCHES) for p in $^; do \ if ! patch -d linux-source-$(VERSION) -p1 < $$p; then \ echo ERROR: applying patch failed: $$p >&2; \ exit 1; \ fi; \ done touch patch-stamp linux-source-$(VERSION): $(TARBALL) tar -xjf $^ .PHONY: clean clean: rm -rf linux-source-$(VERSION) patch-stamp core-4.8/kernel/core-kernel-3.0/README.txt0000664000175000017500000000077112534327775014746 00000000000000Author: Tom Goff The Makefile is basically a wrapper around the make-kpkg command that simplifies building kernel packages. Running make will do some basic dependency checks then build architecture appropriate kernel packages that include changes from the patches directory. The nfnetlink patch is what virtualizes the netfilter queue mechanism; the flow-cache patch allows using IPsec between network namespaces; the ifindex patch virtualizes network interface index numbers. core-4.8/kernel/core-kernel-3.0/config.core0000664000175000017500000000003112534327775015354 00000000000000CONFIG_XFRM_STATISTICS=y core-4.8/kernel/core-kernel-3.0/patches/0000775000175000017500000000000012534327775014752 500000000000000core-4.8/kernel/core-kernel-3.0/patches/00-linux-3.0.flow-cache.patch0000664000175000017500000000335412534327775021601 00000000000000commit 0542b69e2c57fc9668ce6a03155bea6e1f557901 Author: dpward Date: Wed Aug 31 06:05:27 2011 +0000 net: Make flow cache namespace-aware flow_cache_lookup will return a cached object (or null pointer) that the resolver (i.e. xfrm_policy_lookup) previously found for another namespace using the same key/family/dir. Instead, make the namespace part of what identifies entries in the cache. As before, flow_entry_valid will return 0 for entries where the namespace has been deleted, and they will be removed from the cache the next time flow_cache_gc_task is run. Reported-by: Andrew Dickinson Signed-off-by: David Ward Signed-off-by: David S. Miller diff --git a/net/core/flow.c b/net/core/flow.c index bf32c33..47b6d26 100644 --- a/net/core/flow.c +++ b/net/core/flow.c @@ -30,6 +30,7 @@ struct flow_cache_entry { struct hlist_node hlist; struct list_head gc_list; } u; + struct net *net; u16 family; u8 dir; u32 genid; @@ -232,7 +233,8 @@ flow_cache_lookup(struct net *net, const struct flowi *key, u16 family, u8 dir, hash = flow_hash_code(fc, fcp, key); hlist_for_each_entry(tfle, entry, &fcp->hash_table[hash], u.hlist) { - if (tfle->family == family && + if (tfle->net == net && + tfle->family == family && tfle->dir == dir && flow_key_compare(key, &tfle->key) == 0) { fle = tfle; @@ -246,6 +248,7 @@ flow_cache_lookup(struct net *net, const struct flowi *key, u16 family, u8 dir, fle = kmem_cache_alloc(flow_cachep, GFP_ATOMIC); if (fle) { + fle->net = net; fle->family = family; fle->dir = dir; memcpy(&fle->key, key, sizeof(*key)); core-4.8/kernel/core-kernel-3.0/patches/00-linux-3.0.ifindex.patch0000664000175000017500000000300412534327775021207 00000000000000commit 7da7dfcb787d77929c15d5b7127c816ee16f1ede Author: Tom Goff Date: Fri Dec 16 17:39:00 2011 -0800 Make network device ifindex sequential per network namespace. diff --git a/include/net/net_namespace.h b/include/net/net_namespace.h index 3bb6fa0..2fd53da 100644 --- a/include/net/net_namespace.h +++ b/include/net/net_namespace.h @@ -62,6 +62,8 @@ struct net { struct sock *rtnl; /* rtnetlink socket */ struct sock *genl_sock; + int ifindex; + struct list_head dev_base_head; struct hlist_head *dev_name_head; struct hlist_head *dev_index_head; diff --git a/net/core/dev.c b/net/core/dev.c index 6ba50a1..ba95aa5 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -5260,12 +5260,11 @@ int dev_ioctl(struct net *net, unsigned int cmd, void __user *arg) */ static int dev_new_index(struct net *net) { - static int ifindex; for (;;) { - if (++ifindex <= 0) - ifindex = 1; - if (!__dev_get_by_index(net, ifindex)) - return ifindex; + if (++net->ifindex <= 0) + net->ifindex = 1; + if (!__dev_get_by_index(net, net->ifindex)) + return net->ifindex; } } @@ -6277,8 +6276,8 @@ int dev_change_net_namespace(struct net_device *dev, struct net *net, const char /* Actually switch the network namespace */ dev_net_set(dev, net); - /* If there is an ifindex conflict assign a new one */ - if (__dev_get_by_index(net, dev->ifindex)) { + /* Assign a new ifindex */ + { int iflink = (dev->iflink == dev->ifindex); dev->ifindex = dev_new_index(net); if (iflink) core-4.8/kernel/core-kernel-3.0/patches/00-linux-3.0.nfnetlink_queue.patch0000664000175000017500000002267412534327775022773 00000000000000From 4b819adab7892f61a96bab1e36e5d9a74018432b Mon Sep 17 00:00:00 2001 From: Tom Goff Date: Tue, 3 Jan 2012 14:39:04 -0800 Subject: [PATCH 1/2] netfilter: Make the /proc/net/netfilter directory per netns. This allows subsystems to create per-netns entries. Signed-off-by: Tom Goff --- include/linux/netfilter.h | 5 ---- include/net/net_namespace.h | 3 ++ net/netfilter/core.c | 35 +++++++++++++++++++++++------- net/netfilter/nf_log.c | 33 +++++++++++++++++++++++++--- net/netfilter/nf_queue.c | 31 +++++++++++++++++++++++--- net/netfilter/nfnetlink_log.c | 44 ++++++++++++++++++++++++++----------- net/netfilter/nfnetlink_queue.c | 45 ++++++++++++++++++++++++++------------ 7 files changed, 148 insertions(+), 48 deletions(-) diff --git a/include/linux/netfilter.h b/include/linux/netfilter.h index 857f502..b4e02fb 100644 --- a/include/linux/netfilter.h +++ b/include/linux/netfilter.h @@ -340,11 +340,6 @@ nf_nat_decode_session(struct sk_buff *skb, struct flowi *fl, u_int8_t family) #endif } -#ifdef CONFIG_PROC_FS -#include -extern struct proc_dir_entry *proc_net_netfilter; -#endif - #else /* !CONFIG_NETFILTER */ #define NF_HOOK(pf, hook, skb, indev, outdev, okfn) (okfn)(skb) #define NF_HOOK_COND(pf, hook, skb, indev, outdev, okfn, cond) (okfn)(skb) diff --git a/include/net/net_namespace.h b/include/net/net_namespace.h index 3bb6fa0..cf126ef 100644 --- a/include/net/net_namespace.h +++ b/include/net/net_namespace.h @@ -84,6 +84,9 @@ struct net { struct netns_dccp dccp; #endif #ifdef CONFIG_NETFILTER +#ifdef CONFIG_PROC_FS + struct proc_dir_entry *proc_net_netfilter; +#endif struct netns_xt xt; #if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE) struct netns_ct ct; diff --git a/net/netfilter/core.c b/net/netfilter/core.c index afca6c7..9d9b103 100644 --- a/net/netfilter/core.c +++ b/net/netfilter/core.c @@ -255,25 +255,44 @@ void nf_conntrack_destroy(struct nf_conntrack *nfct) EXPORT_SYMBOL(nf_conntrack_destroy); #endif /* CONFIG_NF_CONNTRACK */ +static int __net_init netfilter_net_init(struct net *net) +{ #ifdef CONFIG_PROC_FS -struct proc_dir_entry *proc_net_netfilter; -EXPORT_SYMBOL(proc_net_netfilter); + net->proc_net_netfilter = proc_net_mkdir(net, "netfilter", + net->proc_net); + if (!net->proc_net_netfilter) { + pr_err("%s: cannot create netfilter proc entry\n", __func__); + return -ENOMEM; + } #endif + return 0; +} + +static void __net_exit netfilter_net_exit(struct net *net) +{ +#ifdef CONFIG_PROC_FS + proc_net_remove(net, "netfilter"); +#endif +} + +static struct pernet_operations netfilter_net_ops = { + .init = netfilter_net_init, + .exit = netfilter_net_exit, +}; + void __init netfilter_init(void) { int i, h; + + if (register_pernet_subsys(&netfilter_net_ops)) + panic("%s: failed to register per netns operations", __func__); + for (i = 0; i < ARRAY_SIZE(nf_hooks); i++) { for (h = 0; h < NF_MAX_HOOKS; h++) INIT_LIST_HEAD(&nf_hooks[i][h]); } -#ifdef CONFIG_PROC_FS - proc_net_netfilter = proc_mkdir("netfilter", init_net.proc_net); - if (!proc_net_netfilter) - panic("cannot create netfilter proc entry"); -#endif - if (netfilter_queue_init() < 0) panic("cannot initialize nf_queue"); if (netfilter_log_init() < 0) diff --git a/net/netfilter/nf_log.c b/net/netfilter/nf_log.c index ce0c406..ccc15d6 100644 --- a/net/netfilter/nf_log.c +++ b/net/netfilter/nf_log.c @@ -297,14 +297,39 @@ static __init int netfilter_log_sysctl_init(void) } #endif /* CONFIG_SYSCTL */ -int __init netfilter_log_init(void) +static int __net_init netfilter_log_net_init(struct net *net) { - int i, r; #ifdef CONFIG_PROC_FS if (!proc_create("nf_log", S_IRUGO, - proc_net_netfilter, &nflog_file_ops)) - return -1; + net->proc_net_netfilter, &nflog_file_ops)) + return -ENOMEM; +#endif + + return 0; +} + +static void __net_exit netfilter_log_net_exit(struct net *net) +{ +#ifdef CONFIG_PROC_FS + remove_proc_entry("nf_log", net->proc_net_netfilter); #endif +} + +static struct pernet_operations netfilter_log_net_ops = { + .init = netfilter_log_net_init, + .exit = netfilter_log_net_exit, +}; + +int __init netfilter_log_init(void) +{ + int i, r; + + r = register_pernet_subsys(&netfilter_log_net_ops); + if (r) { + pr_err("%s: failed to register per netns operations\n", + __func__); + return r; + } /* Errors will trigger panic, unroll on error is unnecessary. */ r = netfilter_log_sysctl_init(); diff --git a/net/netfilter/nf_queue.c b/net/netfilter/nf_queue.c index 99ffd28..ecb84a3 100644 --- a/net/netfilter/nf_queue.c +++ b/net/netfilter/nf_queue.c @@ -383,14 +383,37 @@ static const struct file_operations nfqueue_file_ops = { }; #endif /* PROC_FS */ - -int __init netfilter_queue_init(void) +static int __net_init netfilter_queue_net_init(struct net *net) { #ifdef CONFIG_PROC_FS if (!proc_create("nf_queue", S_IRUGO, - proc_net_netfilter, &nfqueue_file_ops)) - return -1; + net->proc_net_netfilter, &nfqueue_file_ops)) + return -ENOMEM; #endif + return 0; } +static void __net_exit netfilter_queue_net_exit(struct net *net) +{ +#ifdef CONFIG_PROC_FS + remove_proc_entry("nf_queue", net->proc_net_netfilter); +#endif +} + +static struct pernet_operations netfilter_queue_net_ops = { + .init = netfilter_queue_net_init, + .exit = netfilter_queue_net_exit, +}; + +int __init netfilter_queue_init(void) +{ + int err; + + err = register_pernet_subsys(&netfilter_queue_net_ops); + if (err) + pr_err("%s: cannot initialize per netns operations\n", + __func__); + + return err; +} diff --git a/net/netfilter/nfnetlink_log.c b/net/netfilter/nfnetlink_log.c index 66b2c54..e4c3c1e 100644 --- a/net/netfilter/nfnetlink_log.c +++ b/net/netfilter/nfnetlink_log.c @@ -950,9 +950,39 @@ static const struct file_operations nful_file_ops = { #endif /* PROC_FS */ +static int __net_init nfnetlink_log_net_init(struct net *net) +{ +#ifdef CONFIG_PROC_FS + if (!proc_create("nfnetlink_log", 0440, + net->proc_net_netfilter, &nful_file_ops)) + return -ENOMEM; +#endif + + return 0; +} + +static void __net_exit nfnetlink_log_net_exit(struct net *net) +{ +#ifdef CONFIG_PROC_FS + remove_proc_entry("nfnetlink_log", net->proc_net_netfilter); +#endif +} + +static struct pernet_operations nfnetlink_log_net_ops = { + .init = nfnetlink_log_net_init, + .exit = nfnetlink_log_net_exit, +}; + static int __init nfnetlink_log_init(void) { - int i, status = -ENOMEM; + int i, status; + + status = register_pernet_subsys(&nfnetlink_log_net_ops); + if (status) { + pr_err("%s: failed to register per netns operations\n", + __func__); + return status; + } for (i = 0; i < INSTANCE_BUCKETS; i++) INIT_HLIST_HEAD(&instance_table[i]); @@ -975,17 +1005,8 @@ static int __init nfnetlink_log_init(void) goto cleanup_subsys; } -#ifdef CONFIG_PROC_FS - if (!proc_create("nfnetlink_log", 0440, - proc_net_netfilter, &nful_file_ops)) - goto cleanup_logger; -#endif return status; -#ifdef CONFIG_PROC_FS -cleanup_logger: - nf_log_unregister(&nfulnl_logger); -#endif cleanup_subsys: nfnetlink_subsys_unregister(&nfulnl_subsys); cleanup_netlink_notifier: @@ -996,9 +1017,6 @@ cleanup_netlink_notifier: static void __exit nfnetlink_log_fini(void) { nf_log_unregister(&nfulnl_logger); -#ifdef CONFIG_PROC_FS - remove_proc_entry("nfnetlink_log", proc_net_netfilter); -#endif nfnetlink_subsys_unregister(&nfulnl_subsys); netlink_unregister_notifier(&nfulnl_rtnl_notifier); } diff --git a/net/netfilter/nfnetlink_queue.c b/net/netfilter/nfnetlink_queue.c index a80b0cb..b615da5 100644 --- a/net/netfilter/nfnetlink_queue.c +++ b/net/netfilter/nfnetlink_queue.c @@ -974,9 +974,39 @@ static const struct file_operations nfqnl_file_ops = { #endif /* PROC_FS */ +static int __net_init nfnetlink_queue_net_init(struct net *net) +{ +#ifdef CONFIG_PROC_FS + if (!proc_create("nfnetlink_queue", 0440, + net->proc_net_netfilter, &nfqnl_file_ops)) + return -ENOMEM; +#endif + + return 0; +} + +static void __net_exit nfnetlink_queue_net_exit(struct net *net) +{ +#ifdef CONFIG_PROC_FS + remove_proc_entry("nfnetlink_queue", net->proc_net_netfilter); +#endif +} + +static struct pernet_operations nfnetlink_queue_net_ops = { + .init = nfnetlink_queue_net_init, + .exit = nfnetlink_queue_net_exit, +}; + static int __init nfnetlink_queue_init(void) { - int i, status = -ENOMEM; + int i, status; + + status = register_pernet_subsys(&nfnetlink_queue_net_ops); + if (status) { + pr_err("%s: failed to register per netns operations\n", + __func__); + return status; + } for (i = 0; i < INSTANCE_BUCKETS; i++) INIT_HLIST_HEAD(&instance_table[i]); @@ -988,19 +1018,9 @@ static int __init nfnetlink_queue_init(void) goto cleanup_netlink_notifier; } -#ifdef CONFIG_PROC_FS - if (!proc_create("nfnetlink_queue", 0440, - proc_net_netfilter, &nfqnl_file_ops)) - goto cleanup_subsys; -#endif - register_netdevice_notifier(&nfqnl_dev_notifier); return status; -#ifdef CONFIG_PROC_FS -cleanup_subsys: - nfnetlink_subsys_unregister(&nfqnl_subsys); -#endif cleanup_netlink_notifier: netlink_unregister_notifier(&nfqnl_rtnl_notifier); return status; @@ -1010,9 +1030,6 @@ static void __exit nfnetlink_queue_fini(void) { nf_unregister_queue_handlers(&nfqh); unregister_netdevice_notifier(&nfqnl_dev_notifier); -#ifdef CONFIG_PROC_FS - remove_proc_entry("nfnetlink_queue", proc_net_netfilter); -#endif nfnetlink_subsys_unregister(&nfqnl_subsys); netlink_unregister_notifier(&nfqnl_rtnl_notifier); -- 1.7.5.4 core-4.8/kernel/core-kernel-3.0/patches/01-linux-3.0.nfnetlink_queue.patch0000664000175000017500000003557012534327775022773 00000000000000From dd504f32d24e9f239d429204c43a5c500c9853c6 Mon Sep 17 00:00:00 2001 From: Tom Goff Date: Tue, 3 Jan 2012 15:52:32 -0800 Subject: [PATCH 2/2] netfilter: nfnetlink_queue: Add netns support. Make nfnetlink_queue network namespace aware including a per-netns /proc/net/netfilter/nfnetlink_queue file. Signed-off-by: Tom Goff --- include/net/net_namespace.h | 6 ++ include/net/netfilter/nf_queue.h | 3 +- include/net/netns/nfqnl.h | 14 ++++ net/ipv4/netfilter/ip_queue.c | 6 ++- net/ipv6/netfilter/ip6_queue.c | 6 ++- net/netfilter/nf_queue.c | 12 +++- net/netfilter/nfnetlink_queue.c | 138 +++++++++++++++++++------------------- 7 files changed, 112 insertions(+), 73 deletions(-) create mode 100644 include/net/netns/nfqnl.h diff --git a/include/net/net_namespace.h b/include/net/net_namespace.h index cf126ef..4b6f04a 100644 --- a/include/net/net_namespace.h +++ b/include/net/net_namespace.h @@ -21,6 +21,9 @@ #include #endif #include +#if defined(CONFIG_NETFILTER_NETLINK_QUEUE) || defined(CONFIG_NETFILTER_NETLINK_QUEUE_MODULE) +#include +#endif struct proc_dir_entry; struct net_device; @@ -93,6 +96,9 @@ struct net { #endif struct sock *nfnl; struct sock *nfnl_stash; +#if defined(CONFIG_NETFILTER_NETLINK_QUEUE) || defined(CONFIG_NETFILTER_NETLINK_QUEUE_MODULE) + struct netns_nfqnl nfqnl; +#endif #endif #ifdef CONFIG_WEXT_CORE struct sk_buff_head wext_nlevents; diff --git a/include/net/netfilter/nf_queue.h b/include/net/netfilter/nf_queue.h index 252fd10..3e5bde8 100644 --- a/include/net/netfilter/nf_queue.h +++ b/include/net/netfilter/nf_queue.h @@ -19,7 +19,8 @@ struct nf_queue_entry { /* Packet queuing */ struct nf_queue_handler { - int (*outfn)(struct nf_queue_entry *entry, + int (*outfn)(struct net *net, + struct nf_queue_entry *entry, unsigned int queuenum); char *name; }; diff --git a/include/net/netns/nfqnl.h b/include/net/netns/nfqnl.h new file mode 100644 index 0000000..0fe7fbe --- /dev/null +++ b/include/net/netns/nfqnl.h @@ -0,0 +1,14 @@ +#ifndef __NETNS_NFQNL_H +#define __NETNS_NFQNL_H + +#include +#include + +#define NFQNL_INSTANCE_BUCKETS 16 + +struct netns_nfqnl { + spinlock_t instances_lock; + struct hlist_head instance_table[NFQNL_INSTANCE_BUCKETS]; +}; + +#endif /* __NETNS_NFQNL_H */ diff --git a/net/ipv4/netfilter/ip_queue.c b/net/ipv4/netfilter/ip_queue.c index e59aabd..f3c43e5 100644 --- a/net/ipv4/netfilter/ip_queue.c +++ b/net/ipv4/netfilter/ip_queue.c @@ -225,7 +225,8 @@ nlmsg_failure: } static int -ipq_enqueue_packet(struct nf_queue_entry *entry, unsigned int queuenum) +ipq_enqueue_packet(struct net *net, struct nf_queue_entry *entry, + unsigned int queuenum) { int status = -EINVAL; struct sk_buff *nskb; @@ -239,6 +240,9 @@ ipq_enqueue_packet(struct nf_queue_entry *entry, unsigned int queuenum) spin_lock_bh(&queue_lock); + if (!net_eq(net, &init_net)) + goto err_out_free_nskb; + if (!peer_pid) goto err_out_free_nskb; diff --git a/net/ipv6/netfilter/ip6_queue.c b/net/ipv6/netfilter/ip6_queue.c index e63c397..322c511 100644 --- a/net/ipv6/netfilter/ip6_queue.c +++ b/net/ipv6/netfilter/ip6_queue.c @@ -225,7 +225,8 @@ nlmsg_failure: } static int -ipq_enqueue_packet(struct nf_queue_entry *entry, unsigned int queuenum) +ipq_enqueue_packet(struct net *net, struct nf_queue_entry *entry, + unsigned int queuenum) { int status = -EINVAL; struct sk_buff *nskb; @@ -239,6 +240,9 @@ ipq_enqueue_packet(struct nf_queue_entry *entry, unsigned int queuenum) spin_lock_bh(&queue_lock); + if (!net_eq(net, &init_net)) + goto err_out_free_nskb; + if (!peer_pid) goto err_out_free_nskb; diff --git a/net/netfilter/nf_queue.c b/net/netfilter/nf_queue.c index ecb84a3..9490bd5 100644 --- a/net/netfilter/nf_queue.c +++ b/net/netfilter/nf_queue.c @@ -133,6 +133,16 @@ static int __nf_queue(struct sk_buff *skb, #endif const struct nf_afinfo *afinfo; const struct nf_queue_handler *qh; + struct net *net; + + if (indev) + net = dev_net(indev); + else if (skb->sk) + net = sock_net(skb->sk); + else if (outdev) + net = dev_net(outdev); + else + return status; /* QUEUE == DROP if no one is waiting, to be safe. */ rcu_read_lock(); @@ -185,7 +195,7 @@ static int __nf_queue(struct sk_buff *skb, #endif skb_dst_force(skb); afinfo->saveroute(skb, entry); - status = qh->outfn(entry, queuenum); + status = qh->outfn(net, entry, queuenum); rcu_read_unlock(); diff --git a/net/netfilter/nfnetlink_queue.c b/net/netfilter/nfnetlink_queue.c index b615da5..48ea6f4 100644 --- a/net/netfilter/nfnetlink_queue.c +++ b/net/netfilter/nfnetlink_queue.c @@ -64,24 +64,19 @@ struct nfqnl_instance { typedef int (*nfqnl_cmpfn)(struct nf_queue_entry *, unsigned long); -static DEFINE_SPINLOCK(instances_lock); - -#define INSTANCE_BUCKETS 16 -static struct hlist_head instance_table[INSTANCE_BUCKETS] __read_mostly; - static inline u_int8_t instance_hashfn(u_int16_t queue_num) { - return ((queue_num >> 8) | queue_num) % INSTANCE_BUCKETS; + return ((queue_num >> 8) | queue_num) % NFQNL_INSTANCE_BUCKETS; } static struct nfqnl_instance * -instance_lookup(u_int16_t queue_num) +instance_lookup(struct net *net, u_int16_t queue_num) { struct hlist_head *head; struct hlist_node *pos; struct nfqnl_instance *inst; - head = &instance_table[instance_hashfn(queue_num)]; + head = &net->nfqnl.instance_table[instance_hashfn(queue_num)]; hlist_for_each_entry_rcu(inst, pos, head, hlist) { if (inst->queue_num == queue_num) return inst; @@ -90,14 +85,14 @@ instance_lookup(u_int16_t queue_num) } static struct nfqnl_instance * -instance_create(u_int16_t queue_num, int pid) +instance_create(struct net *net, u_int16_t queue_num, int pid) { struct nfqnl_instance *inst; unsigned int h; int err; - spin_lock(&instances_lock); - if (instance_lookup(queue_num)) { + spin_lock(&net->nfqnl.instances_lock); + if (instance_lookup(net, queue_num)) { err = -EEXIST; goto out_unlock; } @@ -122,16 +117,16 @@ instance_create(u_int16_t queue_num, int pid) } h = instance_hashfn(queue_num); - hlist_add_head_rcu(&inst->hlist, &instance_table[h]); + hlist_add_head_rcu(&inst->hlist, &net->nfqnl.instance_table[h]); - spin_unlock(&instances_lock); + spin_unlock(&net->nfqnl.instances_lock); return inst; out_free: kfree(inst); out_unlock: - spin_unlock(&instances_lock); + spin_unlock(&net->nfqnl.instances_lock); return ERR_PTR(err); } @@ -157,11 +152,11 @@ __instance_destroy(struct nfqnl_instance *inst) } static void -instance_destroy(struct nfqnl_instance *inst) +instance_destroy(struct net *net, struct nfqnl_instance *inst) { - spin_lock(&instances_lock); + spin_lock(&net->nfqnl.instances_lock); __instance_destroy(inst); - spin_unlock(&instances_lock); + spin_unlock(&net->nfqnl.instances_lock); } static inline void @@ -390,7 +385,8 @@ nla_put_failure: } static int -nfqnl_enqueue_packet(struct nf_queue_entry *entry, unsigned int queuenum) +nfqnl_enqueue_packet(struct net *net, struct nf_queue_entry *entry, + unsigned int queuenum) { struct sk_buff *nskb; struct nfqnl_instance *queue; @@ -398,7 +394,7 @@ nfqnl_enqueue_packet(struct nf_queue_entry *entry, unsigned int queuenum) __be32 *packet_id_ptr; /* rcu_read_lock()ed by nf_hook_slow() */ - queue = instance_lookup(queuenum); + queue = instance_lookup(net, queuenum); if (!queue) { err = -ESRCH; goto err_out; @@ -432,7 +428,7 @@ nfqnl_enqueue_packet(struct nf_queue_entry *entry, unsigned int queuenum) *packet_id_ptr = htonl(entry->id); /* nfnetlink_unicast will either free the nskb or add it to a socket */ - err = nfnetlink_unicast(nskb, &init_net, queue->peer_pid, MSG_DONTWAIT); + err = nfnetlink_unicast(nskb, net, queue->peer_pid, MSG_DONTWAIT); if (err < 0) { queue->queue_user_dropped++; goto err_out_unlock; @@ -541,16 +537,16 @@ dev_cmp(struct nf_queue_entry *entry, unsigned long ifindex) /* drop all packets with either indev or outdev == ifindex from all queue * instances */ static void -nfqnl_dev_drop(int ifindex) +nfqnl_dev_drop(struct net *net, int ifindex) { int i; rcu_read_lock(); - for (i = 0; i < INSTANCE_BUCKETS; i++) { + for (i = 0; i < NFQNL_INSTANCE_BUCKETS; i++) { struct hlist_node *tmp; struct nfqnl_instance *inst; - struct hlist_head *head = &instance_table[i]; + struct hlist_head *head = &net->nfqnl.instance_table[i]; hlist_for_each_entry_rcu(inst, tmp, head, hlist) nfqnl_flush(inst, dev_cmp, ifindex); @@ -567,12 +563,9 @@ nfqnl_rcv_dev_event(struct notifier_block *this, { struct net_device *dev = ptr; - if (!net_eq(dev_net(dev), &init_net)) - return NOTIFY_DONE; - /* Drop any packets associated with the downed device */ if (event == NETDEV_DOWN) - nfqnl_dev_drop(dev->ifindex); + nfqnl_dev_drop(dev_net(dev), dev->ifindex); return NOTIFY_DONE; } @@ -590,19 +583,19 @@ nfqnl_rcv_nl_event(struct notifier_block *this, int i; /* destroy all instances for this pid */ - spin_lock(&instances_lock); - for (i = 0; i < INSTANCE_BUCKETS; i++) { + spin_lock(&n->net->nfqnl.instances_lock); + for (i = 0; i < NFQNL_INSTANCE_BUCKETS; i++) { struct hlist_node *tmp, *t2; struct nfqnl_instance *inst; - struct hlist_head *head = &instance_table[i]; + struct hlist_head *head = + &n->net->nfqnl.instance_table[i]; hlist_for_each_entry_safe(inst, tmp, t2, head, hlist) { - if ((n->net == &init_net) && - (n->pid == inst->peer_pid)) + if (n->pid == inst->peer_pid) __instance_destroy(inst); } } - spin_unlock(&instances_lock); + spin_unlock(&n->net->nfqnl.instances_lock); } return NOTIFY_DONE; } @@ -715,9 +710,10 @@ nfqnl_recv_verdict(struct sock *ctnl, struct sk_buff *skb, unsigned int verdict; struct nf_queue_entry *entry; int err; + struct net *net = sock_net(ctnl); rcu_read_lock(); - queue = instance_lookup(queue_num); + queue = instance_lookup(net, queue_num); if (!queue) { err = -ENODEV; goto err_out_unlock; @@ -774,6 +770,7 @@ nfqnl_recv_config(struct sock *ctnl, struct sk_buff *skb, struct nfqnl_instance *queue; struct nfqnl_msg_config_cmd *cmd = NULL; int ret = 0; + struct net *net = sock_net(ctnl); if (nfqa[NFQA_CFG_CMD]) { cmd = nla_data(nfqa[NFQA_CFG_CMD]); @@ -790,7 +787,7 @@ nfqnl_recv_config(struct sock *ctnl, struct sk_buff *skb, } rcu_read_lock(); - queue = instance_lookup(queue_num); + queue = instance_lookup(net, queue_num); if (queue && queue->peer_pid != NETLINK_CB(skb).pid) { ret = -EPERM; goto err_out_unlock; @@ -803,7 +800,8 @@ nfqnl_recv_config(struct sock *ctnl, struct sk_buff *skb, ret = -EBUSY; goto err_out_unlock; } - queue = instance_create(queue_num, NETLINK_CB(skb).pid); + queue = instance_create(net, queue_num, + NETLINK_CB(skb).pid); if (IS_ERR(queue)) { ret = PTR_ERR(queue); goto err_out_unlock; @@ -814,7 +812,7 @@ nfqnl_recv_config(struct sock *ctnl, struct sk_buff *skb, ret = -ENODEV; goto err_out_unlock; } - instance_destroy(queue); + instance_destroy(net, queue); break; case NFQNL_CFG_CMD_PF_BIND: case NFQNL_CFG_CMD_PF_UNBIND: @@ -878,65 +876,64 @@ static const struct nfnetlink_subsystem nfqnl_subsys = { #ifdef CONFIG_PROC_FS struct iter_state { + struct seq_net_private p; unsigned int bucket; }; -static struct hlist_node *get_first(struct seq_file *seq) +static struct hlist_node *get_first(struct net *net, struct iter_state *st) { - struct iter_state *st = seq->private; - if (!st) return NULL; - for (st->bucket = 0; st->bucket < INSTANCE_BUCKETS; st->bucket++) { - if (!hlist_empty(&instance_table[st->bucket])) - return instance_table[st->bucket].first; + for (st->bucket = 0; st->bucket < NFQNL_INSTANCE_BUCKETS; st->bucket++) { + if (!hlist_empty(&net->nfqnl.instance_table[st->bucket])) + return net->nfqnl.instance_table[st->bucket].first; } return NULL; } -static struct hlist_node *get_next(struct seq_file *seq, struct hlist_node *h) +static struct hlist_node *get_next(struct net *net, struct iter_state *st, + struct hlist_node *h) { - struct iter_state *st = seq->private; - h = h->next; while (!h) { - if (++st->bucket >= INSTANCE_BUCKETS) + if (++st->bucket >= NFQNL_INSTANCE_BUCKETS) return NULL; - h = instance_table[st->bucket].first; + h = net->nfqnl.instance_table[st->bucket].first; } return h; } -static struct hlist_node *get_idx(struct seq_file *seq, loff_t pos) +static struct hlist_node *get_idx(struct net *net, struct iter_state *st, + loff_t pos) { struct hlist_node *head; - head = get_first(seq); + head = get_first(net, st); if (head) - while (pos && (head = get_next(seq, head))) + while (pos && (head = get_next(net, st, head))) pos--; return pos ? NULL : head; } static void *seq_start(struct seq_file *seq, loff_t *pos) - __acquires(instances_lock) { - spin_lock(&instances_lock); - return get_idx(seq, *pos); + struct net *net = seq_file_net(seq); + spin_lock(&net->nfqnl.instances_lock); + return get_idx(net, seq->private, *pos); } static void *seq_next(struct seq_file *s, void *v, loff_t *pos) { (*pos)++; - return get_next(s, v); + return get_next(seq_file_net(s), s->private, v); } static void seq_stop(struct seq_file *s, void *v) - __releases(instances_lock) { - spin_unlock(&instances_lock); + struct net *net = seq_file_net(s); + spin_unlock(&net->nfqnl.instances_lock); } static int seq_show(struct seq_file *s, void *v) @@ -960,8 +957,8 @@ static const struct seq_operations nfqnl_seq_ops = { static int nfqnl_open(struct inode *inode, struct file *file) { - return seq_open_private(file, &nfqnl_seq_ops, - sizeof(struct iter_state)); + return seq_open_net(inode, file, &nfqnl_seq_ops, + sizeof(struct iter_state)); } static const struct file_operations nfqnl_file_ops = { @@ -969,13 +966,19 @@ static const struct file_operations nfqnl_file_ops = { .open = nfqnl_open, .read = seq_read, .llseek = seq_lseek, - .release = seq_release_private, + .release = seq_release_net, }; #endif /* PROC_FS */ static int __net_init nfnetlink_queue_net_init(struct net *net) { + int i; + + spin_lock_init(&net->nfqnl.instances_lock); + for (i = 0; i < NFQNL_INSTANCE_BUCKETS; i++) + INIT_HLIST_HEAD(&net->nfqnl.instance_table[i]); + #ifdef CONFIG_PROC_FS if (!proc_create("nfnetlink_queue", 0440, net->proc_net_netfilter, &nfqnl_file_ops)) @@ -999,7 +1002,7 @@ static struct pernet_operations nfnetlink_queue_net_ops = { static int __init nfnetlink_queue_init(void) { - int i, status; + int status; status = register_pernet_subsys(&nfnetlink_queue_net_ops); if (status) { @@ -1008,9 +1011,6 @@ static int __init nfnetlink_queue_init(void) return status; } - for (i = 0; i < INSTANCE_BUCKETS; i++) - INIT_HLIST_HEAD(&instance_table[i]); - netlink_register_notifier(&nfqnl_rtnl_notifier); status = nfnetlink_subsys_register(&nfqnl_subsys); if (status < 0) { -- 1.7.5.4 core-4.8/kernel/core-kernel-3.2/0000775000175000017500000000000012534327775013325 500000000000000core-4.8/kernel/core-kernel-3.2/Makefile0000664000175000017500000000313312534327775014705 00000000000000VERSION := 3.2.0 TARBALL := /usr/src/linux-source-$(VERSION).tar.bz2 SUBVERSION := -core REVISION := 1.0 PATCHDIR := patches PATCHES := $(sort $(wildcard $(PATCHDIR)/*.patch)) CONFIG := config.core DEPDEBS := linux-source kernel-package po-debconf gettext CONCURRENCY_LEVEL := 8 MAINTAINER ?= Tom Goff EMAIL ?= thomas.goff@boeing.com MAKEKPKGFLAGS := --initrd --rootcmd fakeroot --us --uc \ --append-to-version $(SUBVERSION) --revision $(REVISION) .PHONY: build build: debcheck defaultconfig patch export CONCURRENCY_LEVEL="$(CONCURRENCY_LEVEL)" \ KPKG_MAINTAINER="$(MAINTAINER)" KPKG_EMAIL="$(EMAIL)"; \ cd linux-source-$(VERSION) && \ if [ -f ../$(CONFIG) ]; then \ cat ../$(CONFIG) >> .config; \ fi && \ fakeroot make-kpkg $(MAKEKPKGFLAGS) binary-arch .PHONY: debcheck debcheck: for d in $(DEPDEBS); do \ if ! dpkg-query -s $$d > /dev/null 2>&1; then \ echo ERROR: build dependency not installed: $$d >&2; \ exit 1; \ fi; \ done .PHONY: defaultconfig defaultconfig: linux-source-$(VERSION) export KPKG_MAINTAINER="$(MAINTAINER)" KPKG_EMAIL="$(EMAIL)"; \ cd linux-source-$(VERSION) && make-kpkg $(MAKEKPKGFLAGS) configure .PHONY: patch patch: linux-source-$(VERSION) patch-stamp patch-stamp: $(PATCHES) for p in $^; do \ if ! patch -d linux-source-$(VERSION) -p1 < $$p; then \ echo ERROR: applying patch failed: $$p >&2; \ exit 1; \ fi; \ done touch patch-stamp linux-source-$(VERSION): $(TARBALL) tar -xjf $^ .PHONY: clean clean: rm -rf linux-source-$(VERSION) patch-stamp core-4.8/kernel/core-kernel-3.2/README.txt0000664000175000017500000000066612534327775014753 00000000000000Author: Tom Goff The Makefile is basically a wrapper around the make-kpkg command that simplifies building kernel packages. Running make will do some basic dependency checks then build architecture appropriate kernel packages that include changes from the patches directory. The nfnetlink patch is what virtualizes the netfilter queue mechanism; the ifindex patch virtualizes network interface index numbers. core-4.8/kernel/core-kernel-3.2/config.core0000664000175000017500000000003112534327775015356 00000000000000CONFIG_XFRM_STATISTICS=y core-4.8/kernel/core-kernel-3.2/patches/0000775000175000017500000000000012534327775014754 500000000000000core-4.8/kernel/core-kernel-3.2/patches/00-linux-3.2.ifindex.patch0000664000175000017500000000336312534327775021223 00000000000000From 918e253ebaa3d28c54ff64b596a0afc8779d106a Mon Sep 17 00:00:00 2001 From: Tom Goff Date: Fri, 27 Jul 2012 00:02:50 -0700 Subject: [PATCH] Make network device ifindex sequential per network namespace. Signed-off-by: Tom Goff --- include/net/net_namespace.h | 2 ++ net/core/dev.c | 13 ++++++------- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/include/net/net_namespace.h b/include/net/net_namespace.h index 4b6f04a..266e747 100644 --- a/include/net/net_namespace.h +++ b/include/net/net_namespace.h @@ -65,6 +65,8 @@ struct net { struct sock *rtnl; /* rtnetlink socket */ struct sock *genl_sock; + int ifindex; + struct list_head dev_base_head; struct hlist_head *dev_name_head; struct hlist_head *dev_index_head; diff --git a/net/core/dev.c b/net/core/dev.c index 1cbddc9..d7f5711 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -5236,12 +5236,11 @@ int dev_ioctl(struct net *net, unsigned int cmd, void __user *arg) */ static int dev_new_index(struct net *net) { - static int ifindex; for (;;) { - if (++ifindex <= 0) - ifindex = 1; - if (!__dev_get_by_index(net, ifindex)) - return ifindex; + if (++net->ifindex <= 0) + net->ifindex = 1; + if (!__dev_get_by_index(net, net->ifindex)) + return net->ifindex; } } @@ -6253,8 +6252,8 @@ int dev_change_net_namespace(struct net_device *dev, struct net *net, const char /* Actually switch the network namespace */ dev_net_set(dev, net); - /* If there is an ifindex conflict assign a new one */ - if (__dev_get_by_index(net, dev->ifindex)) { + /* Assign a new ifindex */ + { int iflink = (dev->iflink == dev->ifindex); dev->ifindex = dev_new_index(net); if (iflink) -- 1.7.9.5 core-4.8/kernel/core-kernel-3.2/patches/00-linux-3.2.nfnetlink_queue.patch0000664000175000017500000002270212534327775022767 00000000000000From 67765faf27ec646bcc008bd34d12e48a7466dcdd Mon Sep 17 00:00:00 2001 From: Tom Goff Date: Thu, 26 Jul 2012 23:57:06 -0700 Subject: [PATCH 1/2] netfilter: Make the /proc/net/netfilter directory per netns. This allows subsystems to create per-netns entries. Signed-off-by: Tom Goff --- include/linux/netfilter.h | 5 ----- include/net/net_namespace.h | 3 +++ net/netfilter/core.c | 35 +++++++++++++++++++++++------- net/netfilter/nf_log.c | 33 ++++++++++++++++++++++++---- net/netfilter/nf_queue.c | 31 +++++++++++++++++++++++---- net/netfilter/nfnetlink_log.c | 44 +++++++++++++++++++++++++++----------- net/netfilter/nfnetlink_queue.c | 45 +++++++++++++++++++++++++++------------ 7 files changed, 148 insertions(+), 48 deletions(-) diff --git a/include/linux/netfilter.h b/include/linux/netfilter.h index 857f502..b4e02fb 100644 --- a/include/linux/netfilter.h +++ b/include/linux/netfilter.h @@ -340,11 +340,6 @@ nf_nat_decode_session(struct sk_buff *skb, struct flowi *fl, u_int8_t family) #endif } -#ifdef CONFIG_PROC_FS -#include -extern struct proc_dir_entry *proc_net_netfilter; -#endif - #else /* !CONFIG_NETFILTER */ #define NF_HOOK(pf, hook, skb, indev, outdev, okfn) (okfn)(skb) #define NF_HOOK_COND(pf, hook, skb, indev, outdev, okfn, cond) (okfn)(skb) diff --git a/include/net/net_namespace.h b/include/net/net_namespace.h index 3bb6fa0..cf126ef 100644 --- a/include/net/net_namespace.h +++ b/include/net/net_namespace.h @@ -84,6 +84,9 @@ struct net { struct netns_dccp dccp; #endif #ifdef CONFIG_NETFILTER +#ifdef CONFIG_PROC_FS + struct proc_dir_entry *proc_net_netfilter; +#endif struct netns_xt xt; #if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE) struct netns_ct ct; diff --git a/net/netfilter/core.c b/net/netfilter/core.c index afca6c7..9d9b103 100644 --- a/net/netfilter/core.c +++ b/net/netfilter/core.c @@ -255,25 +255,44 @@ void nf_conntrack_destroy(struct nf_conntrack *nfct) EXPORT_SYMBOL(nf_conntrack_destroy); #endif /* CONFIG_NF_CONNTRACK */ +static int __net_init netfilter_net_init(struct net *net) +{ #ifdef CONFIG_PROC_FS -struct proc_dir_entry *proc_net_netfilter; -EXPORT_SYMBOL(proc_net_netfilter); + net->proc_net_netfilter = proc_net_mkdir(net, "netfilter", + net->proc_net); + if (!net->proc_net_netfilter) { + pr_err("%s: cannot create netfilter proc entry\n", __func__); + return -ENOMEM; + } #endif + return 0; +} + +static void __net_exit netfilter_net_exit(struct net *net) +{ +#ifdef CONFIG_PROC_FS + proc_net_remove(net, "netfilter"); +#endif +} + +static struct pernet_operations netfilter_net_ops = { + .init = netfilter_net_init, + .exit = netfilter_net_exit, +}; + void __init netfilter_init(void) { int i, h; + + if (register_pernet_subsys(&netfilter_net_ops)) + panic("%s: failed to register per netns operations", __func__); + for (i = 0; i < ARRAY_SIZE(nf_hooks); i++) { for (h = 0; h < NF_MAX_HOOKS; h++) INIT_LIST_HEAD(&nf_hooks[i][h]); } -#ifdef CONFIG_PROC_FS - proc_net_netfilter = proc_mkdir("netfilter", init_net.proc_net); - if (!proc_net_netfilter) - panic("cannot create netfilter proc entry"); -#endif - if (netfilter_queue_init() < 0) panic("cannot initialize nf_queue"); if (netfilter_log_init() < 0) diff --git a/net/netfilter/nf_log.c b/net/netfilter/nf_log.c index 957374a..c546ad7 100644 --- a/net/netfilter/nf_log.c +++ b/net/netfilter/nf_log.c @@ -297,14 +297,39 @@ static __init int netfilter_log_sysctl_init(void) } #endif /* CONFIG_SYSCTL */ -int __init netfilter_log_init(void) +static int __net_init netfilter_log_net_init(struct net *net) { - int i, r; #ifdef CONFIG_PROC_FS if (!proc_create("nf_log", S_IRUGO, - proc_net_netfilter, &nflog_file_ops)) - return -1; + net->proc_net_netfilter, &nflog_file_ops)) + return -ENOMEM; +#endif + + return 0; +} + +static void __net_exit netfilter_log_net_exit(struct net *net) +{ +#ifdef CONFIG_PROC_FS + remove_proc_entry("nf_log", net->proc_net_netfilter); #endif +} + +static struct pernet_operations netfilter_log_net_ops = { + .init = netfilter_log_net_init, + .exit = netfilter_log_net_exit, +}; + +int __init netfilter_log_init(void) +{ + int i, r; + + r = register_pernet_subsys(&netfilter_log_net_ops); + if (r) { + pr_err("%s: failed to register per netns operations\n", + __func__); + return r; + } /* Errors will trigger panic, unroll on error is unnecessary. */ r = netfilter_log_sysctl_init(); diff --git a/net/netfilter/nf_queue.c b/net/netfilter/nf_queue.c index b3a7db6..470ec3a 100644 --- a/net/netfilter/nf_queue.c +++ b/net/netfilter/nf_queue.c @@ -383,14 +383,37 @@ static const struct file_operations nfqueue_file_ops = { }; #endif /* PROC_FS */ - -int __init netfilter_queue_init(void) +static int __net_init netfilter_queue_net_init(struct net *net) { #ifdef CONFIG_PROC_FS if (!proc_create("nf_queue", S_IRUGO, - proc_net_netfilter, &nfqueue_file_ops)) - return -1; + net->proc_net_netfilter, &nfqueue_file_ops)) + return -ENOMEM; #endif + return 0; } +static void __net_exit netfilter_queue_net_exit(struct net *net) +{ +#ifdef CONFIG_PROC_FS + remove_proc_entry("nf_queue", net->proc_net_netfilter); +#endif +} + +static struct pernet_operations netfilter_queue_net_ops = { + .init = netfilter_queue_net_init, + .exit = netfilter_queue_net_exit, +}; + +int __init netfilter_queue_init(void) +{ + int err; + + err = register_pernet_subsys(&netfilter_queue_net_ops); + if (err) + pr_err("%s: cannot initialize per netns operations\n", + __func__); + + return err; +} diff --git a/net/netfilter/nfnetlink_log.c b/net/netfilter/nfnetlink_log.c index 66b2c54..e4c3c1e 100644 --- a/net/netfilter/nfnetlink_log.c +++ b/net/netfilter/nfnetlink_log.c @@ -950,9 +950,39 @@ static const struct file_operations nful_file_ops = { #endif /* PROC_FS */ +static int __net_init nfnetlink_log_net_init(struct net *net) +{ +#ifdef CONFIG_PROC_FS + if (!proc_create("nfnetlink_log", 0440, + net->proc_net_netfilter, &nful_file_ops)) + return -ENOMEM; +#endif + + return 0; +} + +static void __net_exit nfnetlink_log_net_exit(struct net *net) +{ +#ifdef CONFIG_PROC_FS + remove_proc_entry("nfnetlink_log", net->proc_net_netfilter); +#endif +} + +static struct pernet_operations nfnetlink_log_net_ops = { + .init = nfnetlink_log_net_init, + .exit = nfnetlink_log_net_exit, +}; + static int __init nfnetlink_log_init(void) { - int i, status = -ENOMEM; + int i, status; + + status = register_pernet_subsys(&nfnetlink_log_net_ops); + if (status) { + pr_err("%s: failed to register per netns operations\n", + __func__); + return status; + } for (i = 0; i < INSTANCE_BUCKETS; i++) INIT_HLIST_HEAD(&instance_table[i]); @@ -975,17 +1005,8 @@ static int __init nfnetlink_log_init(void) goto cleanup_subsys; } -#ifdef CONFIG_PROC_FS - if (!proc_create("nfnetlink_log", 0440, - proc_net_netfilter, &nful_file_ops)) - goto cleanup_logger; -#endif return status; -#ifdef CONFIG_PROC_FS -cleanup_logger: - nf_log_unregister(&nfulnl_logger); -#endif cleanup_subsys: nfnetlink_subsys_unregister(&nfulnl_subsys); cleanup_netlink_notifier: @@ -996,9 +1017,6 @@ cleanup_netlink_notifier: static void __exit nfnetlink_log_fini(void) { nf_log_unregister(&nfulnl_logger); -#ifdef CONFIG_PROC_FS - remove_proc_entry("nfnetlink_log", proc_net_netfilter); -#endif nfnetlink_subsys_unregister(&nfulnl_subsys); netlink_unregister_notifier(&nfulnl_rtnl_notifier); } diff --git a/net/netfilter/nfnetlink_queue.c b/net/netfilter/nfnetlink_queue.c index a80b0cb..b615da5 100644 --- a/net/netfilter/nfnetlink_queue.c +++ b/net/netfilter/nfnetlink_queue.c @@ -974,9 +974,39 @@ static const struct file_operations nfqnl_file_ops = { #endif /* PROC_FS */ +static int __net_init nfnetlink_queue_net_init(struct net *net) +{ +#ifdef CONFIG_PROC_FS + if (!proc_create("nfnetlink_queue", 0440, + net->proc_net_netfilter, &nfqnl_file_ops)) + return -ENOMEM; +#endif + + return 0; +} + +static void __net_exit nfnetlink_queue_net_exit(struct net *net) +{ +#ifdef CONFIG_PROC_FS + remove_proc_entry("nfnetlink_queue", net->proc_net_netfilter); +#endif +} + +static struct pernet_operations nfnetlink_queue_net_ops = { + .init = nfnetlink_queue_net_init, + .exit = nfnetlink_queue_net_exit, +}; + static int __init nfnetlink_queue_init(void) { - int i, status = -ENOMEM; + int i, status; + + status = register_pernet_subsys(&nfnetlink_queue_net_ops); + if (status) { + pr_err("%s: failed to register per netns operations\n", + __func__); + return status; + } for (i = 0; i < INSTANCE_BUCKETS; i++) INIT_HLIST_HEAD(&instance_table[i]); @@ -988,19 +1018,9 @@ static int __init nfnetlink_queue_init(void) goto cleanup_netlink_notifier; } -#ifdef CONFIG_PROC_FS - if (!proc_create("nfnetlink_queue", 0440, - proc_net_netfilter, &nfqnl_file_ops)) - goto cleanup_subsys; -#endif - register_netdevice_notifier(&nfqnl_dev_notifier); return status; -#ifdef CONFIG_PROC_FS -cleanup_subsys: - nfnetlink_subsys_unregister(&nfqnl_subsys); -#endif cleanup_netlink_notifier: netlink_unregister_notifier(&nfqnl_rtnl_notifier); return status; @@ -1010,9 +1030,6 @@ static void __exit nfnetlink_queue_fini(void) { nf_unregister_queue_handlers(&nfqh); unregister_netdevice_notifier(&nfqnl_dev_notifier); -#ifdef CONFIG_PROC_FS - remove_proc_entry("nfnetlink_queue", proc_net_netfilter); -#endif nfnetlink_subsys_unregister(&nfqnl_subsys); netlink_unregister_notifier(&nfqnl_rtnl_notifier); -- 1.7.9.5 core-4.8/kernel/core-kernel-3.2/patches/01-linux-3.2.nfnetlink_queue.patch0000664000175000017500000003753612534327775023003 00000000000000From f8179877a37f37631d831de6381f22fd643b4ea0 Mon Sep 17 00:00:00 2001 From: Tom Goff Date: Thu, 26 Jul 2012 23:58:38 -0700 Subject: [PATCH 2/2] netfilter: nfnetlink_queue: Add netns support. Make nfnetlink_queue network namespace aware including a per-netns /proc/net/netfilter/nfnetlink_queue file. Signed-off-by: Tom Goff --- include/net/net_namespace.h | 6 ++ include/net/netfilter/nf_queue.h | 3 +- include/net/netns/nfqnl.h | 14 ++++ net/ipv4/netfilter/ip_queue.c | 6 +- net/ipv6/netfilter/ip6_queue.c | 6 +- net/netfilter/nf_queue.c | 12 +++- net/netfilter/nfnetlink_queue.c | 136 +++++++++++++++++++------------------- 7 files changed, 111 insertions(+), 72 deletions(-) create mode 100644 include/net/netns/nfqnl.h diff --git a/include/net/net_namespace.h b/include/net/net_namespace.h index cf126ef..4b6f04a 100644 --- a/include/net/net_namespace.h +++ b/include/net/net_namespace.h @@ -21,6 +21,9 @@ #include #endif #include +#if defined(CONFIG_NETFILTER_NETLINK_QUEUE) || defined(CONFIG_NETFILTER_NETLINK_QUEUE_MODULE) +#include +#endif struct proc_dir_entry; struct net_device; @@ -93,6 +96,9 @@ struct net { #endif struct sock *nfnl; struct sock *nfnl_stash; +#if defined(CONFIG_NETFILTER_NETLINK_QUEUE) || defined(CONFIG_NETFILTER_NETLINK_QUEUE_MODULE) + struct netns_nfqnl nfqnl; +#endif #endif #ifdef CONFIG_WEXT_CORE struct sk_buff_head wext_nlevents; diff --git a/include/net/netfilter/nf_queue.h b/include/net/netfilter/nf_queue.h index 252fd10..3e5bde8 100644 --- a/include/net/netfilter/nf_queue.h +++ b/include/net/netfilter/nf_queue.h @@ -19,7 +19,8 @@ struct nf_queue_entry { /* Packet queuing */ struct nf_queue_handler { - int (*outfn)(struct nf_queue_entry *entry, + int (*outfn)(struct net *net, + struct nf_queue_entry *entry, unsigned int queuenum); char *name; }; diff --git a/include/net/netns/nfqnl.h b/include/net/netns/nfqnl.h new file mode 100644 index 0000000..0fe7fbe --- /dev/null +++ b/include/net/netns/nfqnl.h @@ -0,0 +1,14 @@ +#ifndef __NETNS_NFQNL_H +#define __NETNS_NFQNL_H + +#include +#include + +#define NFQNL_INSTANCE_BUCKETS 16 + +struct netns_nfqnl { + spinlock_t instances_lock; + struct hlist_head instance_table[NFQNL_INSTANCE_BUCKETS]; +}; + +#endif /* __NETNS_NFQNL_H */ diff --git a/net/ipv4/netfilter/ip_queue.c b/net/ipv4/netfilter/ip_queue.c index e59aabd..f3c43e5 100644 --- a/net/ipv4/netfilter/ip_queue.c +++ b/net/ipv4/netfilter/ip_queue.c @@ -225,7 +225,8 @@ nlmsg_failure: } static int -ipq_enqueue_packet(struct nf_queue_entry *entry, unsigned int queuenum) +ipq_enqueue_packet(struct net *net, struct nf_queue_entry *entry, + unsigned int queuenum) { int status = -EINVAL; struct sk_buff *nskb; @@ -239,6 +240,9 @@ ipq_enqueue_packet(struct nf_queue_entry *entry, unsigned int queuenum) spin_lock_bh(&queue_lock); + if (!net_eq(net, &init_net)) + goto err_out_free_nskb; + if (!peer_pid) goto err_out_free_nskb; diff --git a/net/ipv6/netfilter/ip6_queue.c b/net/ipv6/netfilter/ip6_queue.c index e63c397..322c511 100644 --- a/net/ipv6/netfilter/ip6_queue.c +++ b/net/ipv6/netfilter/ip6_queue.c @@ -225,7 +225,8 @@ nlmsg_failure: } static int -ipq_enqueue_packet(struct nf_queue_entry *entry, unsigned int queuenum) +ipq_enqueue_packet(struct net *net, struct nf_queue_entry *entry, + unsigned int queuenum) { int status = -EINVAL; struct sk_buff *nskb; @@ -239,6 +240,9 @@ ipq_enqueue_packet(struct nf_queue_entry *entry, unsigned int queuenum) spin_lock_bh(&queue_lock); + if (!net_eq(net, &init_net)) + goto err_out_free_nskb; + if (!peer_pid) goto err_out_free_nskb; diff --git a/net/netfilter/nf_queue.c b/net/netfilter/nf_queue.c index 470ec3a..6894ecc 100644 --- a/net/netfilter/nf_queue.c +++ b/net/netfilter/nf_queue.c @@ -133,6 +133,16 @@ static int __nf_queue(struct sk_buff *skb, #endif const struct nf_afinfo *afinfo; const struct nf_queue_handler *qh; + struct net *net; + + if (indev) + net = dev_net(indev); + else if (skb->sk) + net = sock_net(skb->sk); + else if (outdev) + net = dev_net(outdev); + else + return status; /* QUEUE == DROP if no one is waiting, to be safe. */ rcu_read_lock(); @@ -185,7 +195,7 @@ static int __nf_queue(struct sk_buff *skb, #endif skb_dst_force(skb); afinfo->saveroute(skb, entry); - status = qh->outfn(entry, queuenum); + status = qh->outfn(net, entry, queuenum); rcu_read_unlock(); diff --git a/net/netfilter/nfnetlink_queue.c b/net/netfilter/nfnetlink_queue.c index b615da5..11725a0 100644 --- a/net/netfilter/nfnetlink_queue.c +++ b/net/netfilter/nfnetlink_queue.c @@ -64,24 +64,19 @@ struct nfqnl_instance { typedef int (*nfqnl_cmpfn)(struct nf_queue_entry *, unsigned long); -static DEFINE_SPINLOCK(instances_lock); - -#define INSTANCE_BUCKETS 16 -static struct hlist_head instance_table[INSTANCE_BUCKETS] __read_mostly; - static inline u_int8_t instance_hashfn(u_int16_t queue_num) { - return ((queue_num >> 8) | queue_num) % INSTANCE_BUCKETS; + return ((queue_num >> 8) | queue_num) % NFQNL_INSTANCE_BUCKETS; } static struct nfqnl_instance * -instance_lookup(u_int16_t queue_num) +instance_lookup(struct net *net, u_int16_t queue_num) { struct hlist_head *head; struct hlist_node *pos; struct nfqnl_instance *inst; - head = &instance_table[instance_hashfn(queue_num)]; + head = &net->nfqnl.instance_table[instance_hashfn(queue_num)]; hlist_for_each_entry_rcu(inst, pos, head, hlist) { if (inst->queue_num == queue_num) return inst; @@ -90,14 +85,14 @@ instance_lookup(u_int16_t queue_num) } static struct nfqnl_instance * -instance_create(u_int16_t queue_num, int pid) +instance_create(struct net *net, u_int16_t queue_num, int pid) { struct nfqnl_instance *inst; unsigned int h; int err; - spin_lock(&instances_lock); - if (instance_lookup(queue_num)) { + spin_lock(&net->nfqnl.instances_lock); + if (instance_lookup(net, queue_num)) { err = -EEXIST; goto out_unlock; } @@ -122,16 +117,16 @@ instance_create(u_int16_t queue_num, int pid) } h = instance_hashfn(queue_num); - hlist_add_head_rcu(&inst->hlist, &instance_table[h]); + hlist_add_head_rcu(&inst->hlist, &net->nfqnl.instance_table[h]); - spin_unlock(&instances_lock); + spin_unlock(&net->nfqnl.instances_lock); return inst; out_free: kfree(inst); out_unlock: - spin_unlock(&instances_lock); + spin_unlock(&net->nfqnl.instances_lock); return ERR_PTR(err); } @@ -157,11 +152,11 @@ __instance_destroy(struct nfqnl_instance *inst) } static void -instance_destroy(struct nfqnl_instance *inst) +instance_destroy(struct net *net, struct nfqnl_instance *inst) { - spin_lock(&instances_lock); + spin_lock(&net->nfqnl.instances_lock); __instance_destroy(inst); - spin_unlock(&instances_lock); + spin_unlock(&net->nfqnl.instances_lock); } static inline void @@ -390,7 +385,8 @@ nla_put_failure: } static int -nfqnl_enqueue_packet(struct nf_queue_entry *entry, unsigned int queuenum) +nfqnl_enqueue_packet(struct net *net, struct nf_queue_entry *entry, + unsigned int queuenum) { struct sk_buff *nskb; struct nfqnl_instance *queue; @@ -398,7 +394,7 @@ nfqnl_enqueue_packet(struct nf_queue_entry *entry, unsigned int queuenum) __be32 *packet_id_ptr; /* rcu_read_lock()ed by nf_hook_slow() */ - queue = instance_lookup(queuenum); + queue = instance_lookup(net, queuenum); if (!queue) { err = -ESRCH; goto err_out; @@ -432,7 +428,7 @@ nfqnl_enqueue_packet(struct nf_queue_entry *entry, unsigned int queuenum) *packet_id_ptr = htonl(entry->id); /* nfnetlink_unicast will either free the nskb or add it to a socket */ - err = nfnetlink_unicast(nskb, &init_net, queue->peer_pid, MSG_DONTWAIT); + err = nfnetlink_unicast(nskb, net, queue->peer_pid, MSG_DONTWAIT); if (err < 0) { queue->queue_user_dropped++; goto err_out_unlock; @@ -541,16 +537,16 @@ dev_cmp(struct nf_queue_entry *entry, unsigned long ifindex) /* drop all packets with either indev or outdev == ifindex from all queue * instances */ static void -nfqnl_dev_drop(int ifindex) +nfqnl_dev_drop(struct net *net, int ifindex) { int i; rcu_read_lock(); - for (i = 0; i < INSTANCE_BUCKETS; i++) { + for (i = 0; i < NFQNL_INSTANCE_BUCKETS; i++) { struct hlist_node *tmp; struct nfqnl_instance *inst; - struct hlist_head *head = &instance_table[i]; + struct hlist_head *head = &net->nfqnl.instance_table[i]; hlist_for_each_entry_rcu(inst, tmp, head, hlist) nfqnl_flush(inst, dev_cmp, ifindex); @@ -567,12 +563,9 @@ nfqnl_rcv_dev_event(struct notifier_block *this, { struct net_device *dev = ptr; - if (!net_eq(dev_net(dev), &init_net)) - return NOTIFY_DONE; - /* Drop any packets associated with the downed device */ if (event == NETDEV_DOWN) - nfqnl_dev_drop(dev->ifindex); + nfqnl_dev_drop(dev_net(dev), dev->ifindex); return NOTIFY_DONE; } @@ -590,19 +583,19 @@ nfqnl_rcv_nl_event(struct notifier_block *this, int i; /* destroy all instances for this pid */ - spin_lock(&instances_lock); - for (i = 0; i < INSTANCE_BUCKETS; i++) { + spin_lock(&n->net->nfqnl.instances_lock); + for (i = 0; i < NFQNL_INSTANCE_BUCKETS; i++) { struct hlist_node *tmp, *t2; struct nfqnl_instance *inst; - struct hlist_head *head = &instance_table[i]; + struct hlist_head *head = + &n->net->nfqnl.instance_table[i]; hlist_for_each_entry_safe(inst, tmp, t2, head, hlist) { - if ((n->net == &init_net) && - (n->pid == inst->peer_pid)) + if (n->pid == inst->peer_pid) __instance_destroy(inst); } } - spin_unlock(&instances_lock); + spin_unlock(&n->net->nfqnl.instances_lock); } return NOTIFY_DONE; } @@ -622,11 +615,12 @@ static const struct nla_policy nfqa_verdict_batch_policy[NFQA_MAX+1] = { [NFQA_MARK] = { .type = NLA_U32 }, }; -static struct nfqnl_instance *verdict_instance_lookup(u16 queue_num, int nlpid) +static struct nfqnl_instance *verdict_instance_lookup(struct net *net, + u16 queue_num, int nlpid) { struct nfqnl_instance *queue; - queue = instance_lookup(queue_num); + queue = instance_lookup(net, queue_num); if (!queue) return ERR_PTR(-ENODEV); @@ -670,7 +664,8 @@ nfqnl_recv_verdict_batch(struct sock *ctnl, struct sk_buff *skb, LIST_HEAD(batch_list); u16 queue_num = ntohs(nfmsg->res_id); - queue = verdict_instance_lookup(queue_num, NETLINK_CB(skb).pid); + queue = verdict_instance_lookup(sock_net(ctnl), queue_num, + NETLINK_CB(skb).pid); if (IS_ERR(queue)) return PTR_ERR(queue); @@ -715,11 +710,12 @@ nfqnl_recv_verdict(struct sock *ctnl, struct sk_buff *skb, struct nfqnl_instance *queue; unsigned int verdict; struct nf_queue_entry *entry; + struct net *net = sock_net(ctnl); - queue = instance_lookup(queue_num); + queue = instance_lookup(net, queue_num); if (!queue) - queue = verdict_instance_lookup(queue_num, NETLINK_CB(skb).pid); + queue = verdict_instance_lookup(net, queue_num, NETLINK_CB(skb).pid); if (IS_ERR(queue)) return PTR_ERR(queue); @@ -774,6 +770,7 @@ nfqnl_recv_config(struct sock *ctnl, struct sk_buff *skb, struct nfqnl_instance *queue; struct nfqnl_msg_config_cmd *cmd = NULL; int ret = 0; + struct net *net = sock_net(ctnl); if (nfqa[NFQA_CFG_CMD]) { cmd = nla_data(nfqa[NFQA_CFG_CMD]); @@ -790,7 +787,7 @@ nfqnl_recv_config(struct sock *ctnl, struct sk_buff *skb, } rcu_read_lock(); - queue = instance_lookup(queue_num); + queue = instance_lookup(net, queue_num); if (queue && queue->peer_pid != NETLINK_CB(skb).pid) { ret = -EPERM; goto err_out_unlock; @@ -803,7 +800,8 @@ nfqnl_recv_config(struct sock *ctnl, struct sk_buff *skb, ret = -EBUSY; goto err_out_unlock; } - queue = instance_create(queue_num, NETLINK_CB(skb).pid); + queue = instance_create(net, queue_num, + NETLINK_CB(skb).pid); if (IS_ERR(queue)) { ret = PTR_ERR(queue); goto err_out_unlock; @@ -814,7 +812,7 @@ nfqnl_recv_config(struct sock *ctnl, struct sk_buff *skb, ret = -ENODEV; goto err_out_unlock; } - instance_destroy(queue); + instance_destroy(net, queue); break; case NFQNL_CFG_CMD_PF_BIND: case NFQNL_CFG_CMD_PF_UNBIND: @@ -878,65 +876,64 @@ static const struct nfnetlink_subsystem nfqnl_subsys = { #ifdef CONFIG_PROC_FS struct iter_state { + struct seq_net_private p; unsigned int bucket; }; -static struct hlist_node *get_first(struct seq_file *seq) +static struct hlist_node *get_first(struct net *net, struct iter_state *st) { - struct iter_state *st = seq->private; - if (!st) return NULL; - for (st->bucket = 0; st->bucket < INSTANCE_BUCKETS; st->bucket++) { - if (!hlist_empty(&instance_table[st->bucket])) - return instance_table[st->bucket].first; + for (st->bucket = 0; st->bucket < NFQNL_INSTANCE_BUCKETS; st->bucket++) { + if (!hlist_empty(&net->nfqnl.instance_table[st->bucket])) + return net->nfqnl.instance_table[st->bucket].first; } return NULL; } -static struct hlist_node *get_next(struct seq_file *seq, struct hlist_node *h) +static struct hlist_node *get_next(struct net *net, struct iter_state *st, + struct hlist_node *h) { - struct iter_state *st = seq->private; - h = h->next; while (!h) { - if (++st->bucket >= INSTANCE_BUCKETS) + if (++st->bucket >= NFQNL_INSTANCE_BUCKETS) return NULL; - h = instance_table[st->bucket].first; + h = net->nfqnl.instance_table[st->bucket].first; } return h; } -static struct hlist_node *get_idx(struct seq_file *seq, loff_t pos) +static struct hlist_node *get_idx(struct net *net, struct iter_state *st, + loff_t pos) { struct hlist_node *head; - head = get_first(seq); + head = get_first(net, st); if (head) - while (pos && (head = get_next(seq, head))) + while (pos && (head = get_next(net, st, head))) pos--; return pos ? NULL : head; } static void *seq_start(struct seq_file *seq, loff_t *pos) - __acquires(instances_lock) { - spin_lock(&instances_lock); - return get_idx(seq, *pos); + struct net *net = seq_file_net(seq); + spin_lock(&net->nfqnl.instances_lock); + return get_idx(net, seq->private, *pos); } static void *seq_next(struct seq_file *s, void *v, loff_t *pos) { (*pos)++; - return get_next(s, v); + return get_next(seq_file_net(s), s->private, v); } static void seq_stop(struct seq_file *s, void *v) - __releases(instances_lock) { - spin_unlock(&instances_lock); + struct net *net = seq_file_net(s); + spin_unlock(&net->nfqnl.instances_lock); } static int seq_show(struct seq_file *s, void *v) @@ -960,8 +957,8 @@ static const struct seq_operations nfqnl_seq_ops = { static int nfqnl_open(struct inode *inode, struct file *file) { - return seq_open_private(file, &nfqnl_seq_ops, - sizeof(struct iter_state)); + return seq_open_net(inode, file, &nfqnl_seq_ops, + sizeof(struct iter_state)); } static const struct file_operations nfqnl_file_ops = { @@ -969,13 +966,19 @@ static const struct file_operations nfqnl_file_ops = { .open = nfqnl_open, .read = seq_read, .llseek = seq_lseek, - .release = seq_release_private, + .release = seq_release_net, }; #endif /* PROC_FS */ static int __net_init nfnetlink_queue_net_init(struct net *net) { + int i; + + spin_lock_init(&net->nfqnl.instances_lock); + for (i = 0; i < NFQNL_INSTANCE_BUCKETS; i++) + INIT_HLIST_HEAD(&net->nfqnl.instance_table[i]); + #ifdef CONFIG_PROC_FS if (!proc_create("nfnetlink_queue", 0440, net->proc_net_netfilter, &nfqnl_file_ops)) @@ -999,7 +1002,7 @@ static struct pernet_operations nfnetlink_queue_net_ops = { static int __init nfnetlink_queue_init(void) { - int i, status; + int status; status = register_pernet_subsys(&nfnetlink_queue_net_ops); if (status) { @@ -1008,9 +1011,6 @@ static int __init nfnetlink_queue_init(void) return status; } - for (i = 0; i < INSTANCE_BUCKETS; i++) - INIT_HLIST_HEAD(&instance_table[i]); - netlink_register_notifier(&nfqnl_rtnl_notifier); status = nfnetlink_subsys_register(&nfqnl_subsys); if (status < 0) { -- 1.7.9.5 core-4.8/kernel/core-kernel-3.5/0000775000175000017500000000000012534327775013330 500000000000000core-4.8/kernel/core-kernel-3.5/Makefile0000664000175000017500000000365412534327775014720 00000000000000VERSION := $(shell dpkg -l linux-source 2> /dev/null | \ awk '/^i/ {match($$3, "[0-9]+[.][0-9]+[.][0-9]+"); if (RSTART) print substr($$3, RSTART, RLENGTH)}') TARBALL := /usr/src/linux-source-$(VERSION).tar.bz2 SUBVERSION := -core REVISION := 1.0 PATCHDIR := patches PATCHES := $(sort $(wildcard $(PATCHDIR)/*.patch)) CONFIG := config.core DEPDEBS := linux-source kernel-package po-debconf gettext CONCURRENCY_LEVEL := $(shell lscpu 2> /dev/null | \ awk '/^CPU\(s\)/ {print $$2}') ifeq ($(strip $(CONCURRENCY_LEVEL)),) CONCURRENCY_LEVEL := 1 endif MAINTAINER ?= $(shell id -nu) EMAIL ?= $(MAINTAINER)@$(shell hostname -f) MAKEKPKGFLAGS := --initrd --rootcmd fakeroot --us --uc \ --append-to-version $(SUBVERSION) --revision $(REVISION) .PHONY: build build: debcheck defaultconfig patch export CONCURRENCY_LEVEL="$(CONCURRENCY_LEVEL)" \ KPKG_MAINTAINER="$(MAINTAINER)" KPKG_EMAIL="$(EMAIL)"; \ cd linux-source-$(VERSION) && \ if [ -f ../$(CONFIG) ]; then \ cat ../$(CONFIG) >> .config; \ fi && \ fakeroot make-kpkg $(MAKEKPKGFLAGS) binary-arch .PHONY: debcheck debcheck: for d in $(DEPDEBS); do \ if ! dpkg-query -s $$d > /dev/null 2>&1; then \ echo ERROR: build dependency not installed: $$d >&2; \ exit 1; \ fi; \ done .PHONY: defaultconfig defaultconfig: linux-source-$(VERSION) export KPKG_MAINTAINER="$(MAINTAINER)" KPKG_EMAIL="$(EMAIL)"; \ cd linux-source-$(VERSION) && make-kpkg $(MAKEKPKGFLAGS) configure .PHONY: patch patch: linux-source-$(VERSION) patch-stamp patch-stamp: $(PATCHES) for p in $^; do \ if ! patch -d linux-source-$(VERSION) -p1 < $$p; then \ echo ERROR: applying patch failed: $$p >&2; \ exit 1; \ fi; \ done touch patch-stamp .PHONY: source source: linux-source-$(VERSION) linux-source-$(VERSION): $(TARBALL) tar -xjf $^ .PHONY: clean clean: rm -rf linux-source-$(VERSION) patch-stamp core-4.8/kernel/core-kernel-3.5/config.core0000664000175000017500000000003112534327775015361 00000000000000CONFIG_XFRM_STATISTICS=y core-4.8/kernel/core-kernel-3.5/patches/0000775000175000017500000000000012534327775014757 500000000000000core-4.8/kernel/core-kernel-3.5/patches/00-ifindex.patch0000664000175000017500000000336412534327775017571 00000000000000From e98f08306dd0dc854d93339730a8603638173e23 Mon Sep 17 00:00:00 2001 From: Tom Goff Date: Fri, 27 Jul 2012 00:02:50 -0700 Subject: [PATCH] Make network device ifindex sequential per network namespace. Signed-off-by: Tom Goff --- include/net/net_namespace.h | 2 ++ net/core/dev.c | 13 ++++++------- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/include/net/net_namespace.h b/include/net/net_namespace.h index ac9195e..1b9c99a 100644 --- a/include/net/net_namespace.h +++ b/include/net/net_namespace.h @@ -62,6 +62,8 @@ struct net { struct sock *rtnl; /* rtnetlink socket */ struct sock *genl_sock; + int ifindex; + struct list_head dev_base_head; struct hlist_head *dev_name_head; struct hlist_head *dev_index_head; diff --git a/net/core/dev.c b/net/core/dev.c index 3ad746b..7bec156 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -5168,12 +5168,11 @@ int dev_ioctl(struct net *net, unsigned int cmd, void __user *arg) */ static int dev_new_index(struct net *net) { - static int ifindex; for (;;) { - if (++ifindex <= 0) - ifindex = 1; - if (!__dev_get_by_index(net, ifindex)) - return ifindex; + if (++net->ifindex <= 0) + net->ifindex = 1; + if (!__dev_get_by_index(net, net->ifindex)) + return net->ifindex; } } @@ -6182,8 +6181,8 @@ int dev_change_net_namespace(struct net_device *dev, struct net *net, const char /* Actually switch the network namespace */ dev_net_set(dev, net); - /* If there is an ifindex conflict assign a new one */ - if (__dev_get_by_index(net, dev->ifindex)) { + /* Assign a new ifindex */ + { int iflink = (dev->iflink == dev->ifindex); dev->ifindex = dev_new_index(net); if (iflink) -- 1.7.10.4 core-4.8/kernel/core-kernel-3.5/patches/00-nfnetlink_queue.patch0000664000175000017500000002270412534327775021336 00000000000000From 5af499895ded68e1d42510df30be2004b4b778bf Mon Sep 17 00:00:00 2001 From: Tom Goff Date: Thu, 26 Jul 2012 23:57:06 -0700 Subject: [PATCH 1/2] netfilter: Make the /proc/net/netfilter directory per netns. This allows subsystems to create per-netns entries. Signed-off-by: Tom Goff --- include/linux/netfilter.h | 5 ----- include/net/net_namespace.h | 3 +++ net/netfilter/core.c | 35 +++++++++++++++++++++++------- net/netfilter/nf_log.c | 33 ++++++++++++++++++++++++---- net/netfilter/nf_queue.c | 31 +++++++++++++++++++++++---- net/netfilter/nfnetlink_log.c | 44 +++++++++++++++++++++++++++----------- net/netfilter/nfnetlink_queue.c | 45 +++++++++++++++++++++++++++------------ 7 files changed, 148 insertions(+), 48 deletions(-) diff --git a/include/linux/netfilter.h b/include/linux/netfilter.h index ff9c84c..e28a566 100644 --- a/include/linux/netfilter.h +++ b/include/linux/netfilter.h @@ -350,11 +350,6 @@ nf_nat_decode_session(struct sk_buff *skb, struct flowi *fl, u_int8_t family) #endif } -#ifdef CONFIG_PROC_FS -#include -extern struct proc_dir_entry *proc_net_netfilter; -#endif - #else /* !CONFIG_NETFILTER */ #define NF_HOOK(pf, hook, skb, indev, outdev, okfn) (okfn)(skb) #define NF_HOOK_COND(pf, hook, skb, indev, outdev, okfn, cond) (okfn)(skb) diff --git a/include/net/net_namespace.h b/include/net/net_namespace.h index 1b9c99a..449fc8e 100644 --- a/include/net/net_namespace.h +++ b/include/net/net_namespace.h @@ -86,6 +86,9 @@ struct net { struct netns_dccp dccp; #endif #ifdef CONFIG_NETFILTER +#ifdef CONFIG_PROC_FS + struct proc_dir_entry *proc_net_netfilter; +#endif struct netns_xt xt; #if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE) struct netns_ct ct; diff --git a/net/netfilter/core.c b/net/netfilter/core.c index e19f365..c7c9f39 100644 --- a/net/netfilter/core.c +++ b/net/netfilter/core.c @@ -266,25 +266,44 @@ void nf_conntrack_destroy(struct nf_conntrack *nfct) EXPORT_SYMBOL(nf_conntrack_destroy); #endif /* CONFIG_NF_CONNTRACK */ +static int __net_init netfilter_net_init(struct net *net) +{ +#ifdef CONFIG_PROC_FS + net->proc_net_netfilter = proc_net_mkdir(net, "netfilter", + net->proc_net); + if (!net->proc_net_netfilter) { + pr_err("%s: cannot create netfilter proc entry\n", __func__); + return -ENOMEM; + } +#endif + + return 0; +} + +static void __net_exit netfilter_net_exit(struct net *net) +{ #ifdef CONFIG_PROC_FS -struct proc_dir_entry *proc_net_netfilter; -EXPORT_SYMBOL(proc_net_netfilter); + proc_net_remove(net, "netfilter"); #endif +} + +static struct pernet_operations netfilter_net_ops = { + .init = netfilter_net_init, + .exit = netfilter_net_exit, +}; void __init netfilter_init(void) { int i, h; + + if (register_pernet_subsys(&netfilter_net_ops)) + panic("%s: failed to register per netns operations", __func__); + for (i = 0; i < ARRAY_SIZE(nf_hooks); i++) { for (h = 0; h < NF_MAX_HOOKS; h++) INIT_LIST_HEAD(&nf_hooks[i][h]); } -#ifdef CONFIG_PROC_FS - proc_net_netfilter = proc_mkdir("netfilter", init_net.proc_net); - if (!proc_net_netfilter) - panic("cannot create netfilter proc entry"); -#endif - if (netfilter_queue_init() < 0) panic("cannot initialize nf_queue"); if (netfilter_log_init() < 0) diff --git a/net/netfilter/nf_log.c b/net/netfilter/nf_log.c index 703fb26..4507932 100644 --- a/net/netfilter/nf_log.c +++ b/net/netfilter/nf_log.c @@ -290,14 +290,39 @@ static __init int netfilter_log_sysctl_init(void) } #endif /* CONFIG_SYSCTL */ -int __init netfilter_log_init(void) +static int __net_init netfilter_log_net_init(struct net *net) { - int i, r; #ifdef CONFIG_PROC_FS if (!proc_create("nf_log", S_IRUGO, - proc_net_netfilter, &nflog_file_ops)) - return -1; + net->proc_net_netfilter, &nflog_file_ops)) + return -ENOMEM; +#endif + + return 0; +} + +static void __net_exit netfilter_log_net_exit(struct net *net) +{ +#ifdef CONFIG_PROC_FS + remove_proc_entry("nf_log", net->proc_net_netfilter); #endif +} + +static struct pernet_operations netfilter_log_net_ops = { + .init = netfilter_log_net_init, + .exit = netfilter_log_net_exit, +}; + +int __init netfilter_log_init(void) +{ + int i, r; + + r = register_pernet_subsys(&netfilter_log_net_ops); + if (r) { + pr_err("%s: failed to register per netns operations\n", + __func__); + return r; + } /* Errors will trigger panic, unroll on error is unnecessary. */ r = netfilter_log_sysctl_init(); diff --git a/net/netfilter/nf_queue.c b/net/netfilter/nf_queue.c index ce60cf0..288c6f5 100644 --- a/net/netfilter/nf_queue.c +++ b/net/netfilter/nf_queue.c @@ -407,14 +407,37 @@ static const struct file_operations nfqueue_file_ops = { }; #endif /* PROC_FS */ - -int __init netfilter_queue_init(void) +static int __net_init netfilter_queue_net_init(struct net *net) { #ifdef CONFIG_PROC_FS if (!proc_create("nf_queue", S_IRUGO, - proc_net_netfilter, &nfqueue_file_ops)) - return -1; + net->proc_net_netfilter, &nfqueue_file_ops)) + return -ENOMEM; #endif + return 0; } +static void __net_exit netfilter_queue_net_exit(struct net *net) +{ +#ifdef CONFIG_PROC_FS + remove_proc_entry("nf_queue", net->proc_net_netfilter); +#endif +} + +static struct pernet_operations netfilter_queue_net_ops = { + .init = netfilter_queue_net_init, + .exit = netfilter_queue_net_exit, +}; + +int __init netfilter_queue_init(void) +{ + int err; + + err = register_pernet_subsys(&netfilter_queue_net_ops); + if (err) + pr_err("%s: cannot initialize per netns operations\n", + __func__); + + return err; +} diff --git a/net/netfilter/nfnetlink_log.c b/net/netfilter/nfnetlink_log.c index bbc1d91..e5c1731 100644 --- a/net/netfilter/nfnetlink_log.c +++ b/net/netfilter/nfnetlink_log.c @@ -966,9 +966,39 @@ static const struct file_operations nful_file_ops = { #endif /* PROC_FS */ +static int __net_init nfnetlink_log_net_init(struct net *net) +{ +#ifdef CONFIG_PROC_FS + if (!proc_create("nfnetlink_log", 0440, + net->proc_net_netfilter, &nful_file_ops)) + return -ENOMEM; +#endif + + return 0; +} + +static void __net_exit nfnetlink_log_net_exit(struct net *net) +{ +#ifdef CONFIG_PROC_FS + remove_proc_entry("nfnetlink_log", net->proc_net_netfilter); +#endif +} + +static struct pernet_operations nfnetlink_log_net_ops = { + .init = nfnetlink_log_net_init, + .exit = nfnetlink_log_net_exit, +}; + static int __init nfnetlink_log_init(void) { - int i, status = -ENOMEM; + int i, status; + + status = register_pernet_subsys(&nfnetlink_log_net_ops); + if (status) { + pr_err("%s: failed to register per netns operations\n", + __func__); + return status; + } for (i = 0; i < INSTANCE_BUCKETS; i++) INIT_HLIST_HEAD(&instance_table[i]); @@ -991,17 +1021,8 @@ static int __init nfnetlink_log_init(void) goto cleanup_subsys; } -#ifdef CONFIG_PROC_FS - if (!proc_create("nfnetlink_log", 0440, - proc_net_netfilter, &nful_file_ops)) - goto cleanup_logger; -#endif return status; -#ifdef CONFIG_PROC_FS -cleanup_logger: - nf_log_unregister(&nfulnl_logger); -#endif cleanup_subsys: nfnetlink_subsys_unregister(&nfulnl_subsys); cleanup_netlink_notifier: @@ -1012,9 +1033,6 @@ cleanup_netlink_notifier: static void __exit nfnetlink_log_fini(void) { nf_log_unregister(&nfulnl_logger); -#ifdef CONFIG_PROC_FS - remove_proc_entry("nfnetlink_log", proc_net_netfilter); -#endif nfnetlink_subsys_unregister(&nfulnl_subsys); netlink_unregister_notifier(&nfulnl_rtnl_notifier); } diff --git a/net/netfilter/nfnetlink_queue.c b/net/netfilter/nfnetlink_queue.c index 4162437..add33dc 100644 --- a/net/netfilter/nfnetlink_queue.c +++ b/net/netfilter/nfnetlink_queue.c @@ -982,9 +982,39 @@ static const struct file_operations nfqnl_file_ops = { #endif /* PROC_FS */ +static int __net_init nfnetlink_queue_net_init(struct net *net) +{ +#ifdef CONFIG_PROC_FS + if (!proc_create("nfnetlink_queue", 0440, + net->proc_net_netfilter, &nfqnl_file_ops)) + return -ENOMEM; +#endif + + return 0; +} + +static void __net_exit nfnetlink_queue_net_exit(struct net *net) +{ +#ifdef CONFIG_PROC_FS + remove_proc_entry("nfnetlink_queue", net->proc_net_netfilter); +#endif +} + +static struct pernet_operations nfnetlink_queue_net_ops = { + .init = nfnetlink_queue_net_init, + .exit = nfnetlink_queue_net_exit, +}; + static int __init nfnetlink_queue_init(void) { - int i, status = -ENOMEM; + int i, status; + + status = register_pernet_subsys(&nfnetlink_queue_net_ops); + if (status) { + pr_err("%s: failed to register per netns operations\n", + __func__); + return status; + } for (i = 0; i < INSTANCE_BUCKETS; i++) INIT_HLIST_HEAD(&instance_table[i]); @@ -996,19 +1026,9 @@ static int __init nfnetlink_queue_init(void) goto cleanup_netlink_notifier; } -#ifdef CONFIG_PROC_FS - if (!proc_create("nfnetlink_queue", 0440, - proc_net_netfilter, &nfqnl_file_ops)) - goto cleanup_subsys; -#endif - register_netdevice_notifier(&nfqnl_dev_notifier); return status; -#ifdef CONFIG_PROC_FS -cleanup_subsys: - nfnetlink_subsys_unregister(&nfqnl_subsys); -#endif cleanup_netlink_notifier: netlink_unregister_notifier(&nfqnl_rtnl_notifier); return status; @@ -1018,9 +1038,6 @@ static void __exit nfnetlink_queue_fini(void) { nf_unregister_queue_handlers(&nfqh); unregister_netdevice_notifier(&nfqnl_dev_notifier); -#ifdef CONFIG_PROC_FS - remove_proc_entry("nfnetlink_queue", proc_net_netfilter); -#endif nfnetlink_subsys_unregister(&nfqnl_subsys); netlink_unregister_notifier(&nfqnl_rtnl_notifier); -- 1.7.10.4 core-4.8/kernel/core-kernel-3.5/patches/01-nfnetlink_queue.patch0000664000175000017500000003466412534327775021347 00000000000000From 1ede1963c84e15359d4b5bf7fb01587d90bcf1d4 Mon Sep 17 00:00:00 2001 From: Tom Goff Date: Thu, 26 Jul 2012 23:58:38 -0700 Subject: [PATCH 2/2] netfilter: nfnetlink_queue: Add netns support. Make nfnetlink_queue network namespace aware including a per-netns /proc/net/netfilter/nfnetlink_queue file. Signed-off-by: Tom Goff --- include/net/net_namespace.h | 6 ++ include/net/netfilter/nf_queue.h | 3 +- include/net/netns/nfqnl.h | 14 ++++ net/netfilter/nf_queue.c | 12 +++- net/netfilter/nfnetlink_queue.c | 136 +++++++++++++++++++------------------- 5 files changed, 101 insertions(+), 70 deletions(-) create mode 100644 include/net/netns/nfqnl.h diff --git a/include/net/net_namespace.h b/include/net/net_namespace.h index 449fc8e..c4229f1 100644 --- a/include/net/net_namespace.h +++ b/include/net/net_namespace.h @@ -21,6 +21,9 @@ #include #endif #include +#if defined(CONFIG_NETFILTER_NETLINK_QUEUE) || defined(CONFIG_NETFILTER_NETLINK_QUEUE_MODULE) +#include +#endif struct proc_dir_entry; struct net_device; @@ -95,6 +98,9 @@ struct net { #endif struct sock *nfnl; struct sock *nfnl_stash; +#if defined(CONFIG_NETFILTER_NETLINK_QUEUE) || defined(CONFIG_NETFILTER_NETLINK_QUEUE_MODULE) + struct netns_nfqnl nfqnl; +#endif #endif #ifdef CONFIG_WEXT_CORE struct sk_buff_head wext_nlevents; diff --git a/include/net/netfilter/nf_queue.h b/include/net/netfilter/nf_queue.h index 252fd10..3e5bde8 100644 --- a/include/net/netfilter/nf_queue.h +++ b/include/net/netfilter/nf_queue.h @@ -19,7 +19,8 @@ struct nf_queue_entry { /* Packet queuing */ struct nf_queue_handler { - int (*outfn)(struct nf_queue_entry *entry, + int (*outfn)(struct net *net, + struct nf_queue_entry *entry, unsigned int queuenum); char *name; }; diff --git a/include/net/netns/nfqnl.h b/include/net/netns/nfqnl.h new file mode 100644 index 0000000..0fe7fbe --- /dev/null +++ b/include/net/netns/nfqnl.h @@ -0,0 +1,14 @@ +#ifndef __NETNS_NFQNL_H +#define __NETNS_NFQNL_H + +#include +#include + +#define NFQNL_INSTANCE_BUCKETS 16 + +struct netns_nfqnl { + spinlock_t instances_lock; + struct hlist_head instance_table[NFQNL_INSTANCE_BUCKETS]; +}; + +#endif /* __NETNS_NFQNL_H */ diff --git a/net/netfilter/nf_queue.c b/net/netfilter/nf_queue.c index 288c6f5..3cb8733 100644 --- a/net/netfilter/nf_queue.c +++ b/net/netfilter/nf_queue.c @@ -133,6 +133,16 @@ static int __nf_queue(struct sk_buff *skb, #endif const struct nf_afinfo *afinfo; const struct nf_queue_handler *qh; + struct net *net; + + if (indev) + net = dev_net(indev); + else if (skb->sk) + net = sock_net(skb->sk); + else if (outdev) + net = dev_net(outdev); + else + return status; /* QUEUE == DROP if no one is waiting, to be safe. */ rcu_read_lock(); @@ -185,7 +195,7 @@ static int __nf_queue(struct sk_buff *skb, #endif skb_dst_force(skb); afinfo->saveroute(skb, entry); - status = qh->outfn(entry, queuenum); + status = qh->outfn(net, entry, queuenum); rcu_read_unlock(); diff --git a/net/netfilter/nfnetlink_queue.c b/net/netfilter/nfnetlink_queue.c index add33dc..43c50bb 100644 --- a/net/netfilter/nfnetlink_queue.c +++ b/net/netfilter/nfnetlink_queue.c @@ -64,24 +64,19 @@ struct nfqnl_instance { typedef int (*nfqnl_cmpfn)(struct nf_queue_entry *, unsigned long); -static DEFINE_SPINLOCK(instances_lock); - -#define INSTANCE_BUCKETS 16 -static struct hlist_head instance_table[INSTANCE_BUCKETS] __read_mostly; - static inline u_int8_t instance_hashfn(u_int16_t queue_num) { - return ((queue_num >> 8) | queue_num) % INSTANCE_BUCKETS; + return ((queue_num >> 8) | queue_num) % NFQNL_INSTANCE_BUCKETS; } static struct nfqnl_instance * -instance_lookup(u_int16_t queue_num) +instance_lookup(struct net *net, u_int16_t queue_num) { struct hlist_head *head; struct hlist_node *pos; struct nfqnl_instance *inst; - head = &instance_table[instance_hashfn(queue_num)]; + head = &net->nfqnl.instance_table[instance_hashfn(queue_num)]; hlist_for_each_entry_rcu(inst, pos, head, hlist) { if (inst->queue_num == queue_num) return inst; @@ -90,14 +85,14 @@ instance_lookup(u_int16_t queue_num) } static struct nfqnl_instance * -instance_create(u_int16_t queue_num, int pid) +instance_create(struct net *net, u_int16_t queue_num, int pid) { struct nfqnl_instance *inst; unsigned int h; int err; - spin_lock(&instances_lock); - if (instance_lookup(queue_num)) { + spin_lock(&net->nfqnl.instances_lock); + if (instance_lookup(net, queue_num)) { err = -EEXIST; goto out_unlock; } @@ -122,16 +117,16 @@ instance_create(u_int16_t queue_num, int pid) } h = instance_hashfn(queue_num); - hlist_add_head_rcu(&inst->hlist, &instance_table[h]); + hlist_add_head_rcu(&inst->hlist, &net->nfqnl.instance_table[h]); - spin_unlock(&instances_lock); + spin_unlock(&net->nfqnl.instances_lock); return inst; out_free: kfree(inst); out_unlock: - spin_unlock(&instances_lock); + spin_unlock(&net->nfqnl.instances_lock); return ERR_PTR(err); } @@ -157,11 +152,11 @@ __instance_destroy(struct nfqnl_instance *inst) } static void -instance_destroy(struct nfqnl_instance *inst) +instance_destroy(struct net *net, struct nfqnl_instance *inst) { - spin_lock(&instances_lock); + spin_lock(&net->nfqnl.instances_lock); __instance_destroy(inst); - spin_unlock(&instances_lock); + spin_unlock(&net->nfqnl.instances_lock); } static inline void @@ -400,7 +395,8 @@ nla_put_failure: } static int -nfqnl_enqueue_packet(struct nf_queue_entry *entry, unsigned int queuenum) +nfqnl_enqueue_packet(struct net *net, struct nf_queue_entry *entry, + unsigned int queuenum) { struct sk_buff *nskb; struct nfqnl_instance *queue; @@ -408,7 +404,7 @@ nfqnl_enqueue_packet(struct nf_queue_entry *entry, unsigned int queuenum) __be32 *packet_id_ptr; /* rcu_read_lock()ed by nf_hook_slow() */ - queue = instance_lookup(queuenum); + queue = instance_lookup(net, queuenum); if (!queue) { err = -ESRCH; goto err_out; @@ -440,7 +436,7 @@ nfqnl_enqueue_packet(struct nf_queue_entry *entry, unsigned int queuenum) *packet_id_ptr = htonl(entry->id); /* nfnetlink_unicast will either free the nskb or add it to a socket */ - err = nfnetlink_unicast(nskb, &init_net, queue->peer_pid, MSG_DONTWAIT); + err = nfnetlink_unicast(nskb, net, queue->peer_pid, MSG_DONTWAIT); if (err < 0) { queue->queue_user_dropped++; goto err_out_unlock; @@ -549,16 +545,16 @@ dev_cmp(struct nf_queue_entry *entry, unsigned long ifindex) /* drop all packets with either indev or outdev == ifindex from all queue * instances */ static void -nfqnl_dev_drop(int ifindex) +nfqnl_dev_drop(struct net *net, int ifindex) { int i; rcu_read_lock(); - for (i = 0; i < INSTANCE_BUCKETS; i++) { + for (i = 0; i < NFQNL_INSTANCE_BUCKETS; i++) { struct hlist_node *tmp; struct nfqnl_instance *inst; - struct hlist_head *head = &instance_table[i]; + struct hlist_head *head = &net->nfqnl.instance_table[i]; hlist_for_each_entry_rcu(inst, tmp, head, hlist) nfqnl_flush(inst, dev_cmp, ifindex); @@ -575,12 +571,9 @@ nfqnl_rcv_dev_event(struct notifier_block *this, { struct net_device *dev = ptr; - if (!net_eq(dev_net(dev), &init_net)) - return NOTIFY_DONE; - /* Drop any packets associated with the downed device */ if (event == NETDEV_DOWN) - nfqnl_dev_drop(dev->ifindex); + nfqnl_dev_drop(dev_net(dev), dev->ifindex); return NOTIFY_DONE; } @@ -598,19 +591,19 @@ nfqnl_rcv_nl_event(struct notifier_block *this, int i; /* destroy all instances for this pid */ - spin_lock(&instances_lock); - for (i = 0; i < INSTANCE_BUCKETS; i++) { + spin_lock(&n->net->nfqnl.instances_lock); + for (i = 0; i < NFQNL_INSTANCE_BUCKETS; i++) { struct hlist_node *tmp, *t2; struct nfqnl_instance *inst; - struct hlist_head *head = &instance_table[i]; + struct hlist_head *head = + &n->net->nfqnl.instance_table[i]; hlist_for_each_entry_safe(inst, tmp, t2, head, hlist) { - if ((n->net == &init_net) && - (n->pid == inst->peer_pid)) + if (n->pid == inst->peer_pid) __instance_destroy(inst); } } - spin_unlock(&instances_lock); + spin_unlock(&n->net->nfqnl.instances_lock); } return NOTIFY_DONE; } @@ -630,11 +623,12 @@ static const struct nla_policy nfqa_verdict_batch_policy[NFQA_MAX+1] = { [NFQA_MARK] = { .type = NLA_U32 }, }; -static struct nfqnl_instance *verdict_instance_lookup(u16 queue_num, int nlpid) +static struct nfqnl_instance *verdict_instance_lookup(struct net *net, + u16 queue_num, int nlpid) { struct nfqnl_instance *queue; - queue = instance_lookup(queue_num); + queue = instance_lookup(net, queue_num); if (!queue) return ERR_PTR(-ENODEV); @@ -678,7 +672,8 @@ nfqnl_recv_verdict_batch(struct sock *ctnl, struct sk_buff *skb, LIST_HEAD(batch_list); u16 queue_num = ntohs(nfmsg->res_id); - queue = verdict_instance_lookup(queue_num, NETLINK_CB(skb).pid); + queue = verdict_instance_lookup(sock_net(ctnl), queue_num, + NETLINK_CB(skb).pid); if (IS_ERR(queue)) return PTR_ERR(queue); @@ -723,11 +718,12 @@ nfqnl_recv_verdict(struct sock *ctnl, struct sk_buff *skb, struct nfqnl_instance *queue; unsigned int verdict; struct nf_queue_entry *entry; + struct net *net = sock_net(ctnl); - queue = instance_lookup(queue_num); + queue = instance_lookup(net, queue_num); if (!queue) - queue = verdict_instance_lookup(queue_num, NETLINK_CB(skb).pid); + queue = verdict_instance_lookup(net, queue_num, NETLINK_CB(skb).pid); if (IS_ERR(queue)) return PTR_ERR(queue); @@ -782,6 +778,7 @@ nfqnl_recv_config(struct sock *ctnl, struct sk_buff *skb, struct nfqnl_instance *queue; struct nfqnl_msg_config_cmd *cmd = NULL; int ret = 0; + struct net *net = sock_net(ctnl); if (nfqa[NFQA_CFG_CMD]) { cmd = nla_data(nfqa[NFQA_CFG_CMD]); @@ -798,7 +795,7 @@ nfqnl_recv_config(struct sock *ctnl, struct sk_buff *skb, } rcu_read_lock(); - queue = instance_lookup(queue_num); + queue = instance_lookup(net, queue_num); if (queue && queue->peer_pid != NETLINK_CB(skb).pid) { ret = -EPERM; goto err_out_unlock; @@ -811,7 +808,8 @@ nfqnl_recv_config(struct sock *ctnl, struct sk_buff *skb, ret = -EBUSY; goto err_out_unlock; } - queue = instance_create(queue_num, NETLINK_CB(skb).pid); + queue = instance_create(net, queue_num, + NETLINK_CB(skb).pid); if (IS_ERR(queue)) { ret = PTR_ERR(queue); goto err_out_unlock; @@ -822,7 +820,7 @@ nfqnl_recv_config(struct sock *ctnl, struct sk_buff *skb, ret = -ENODEV; goto err_out_unlock; } - instance_destroy(queue); + instance_destroy(net, queue); break; case NFQNL_CFG_CMD_PF_BIND: case NFQNL_CFG_CMD_PF_UNBIND: @@ -886,65 +884,64 @@ static const struct nfnetlink_subsystem nfqnl_subsys = { #ifdef CONFIG_PROC_FS struct iter_state { + struct seq_net_private p; unsigned int bucket; }; -static struct hlist_node *get_first(struct seq_file *seq) +static struct hlist_node *get_first(struct net *net, struct iter_state *st) { - struct iter_state *st = seq->private; - if (!st) return NULL; - for (st->bucket = 0; st->bucket < INSTANCE_BUCKETS; st->bucket++) { - if (!hlist_empty(&instance_table[st->bucket])) - return instance_table[st->bucket].first; + for (st->bucket = 0; st->bucket < NFQNL_INSTANCE_BUCKETS; st->bucket++) { + if (!hlist_empty(&net->nfqnl.instance_table[st->bucket])) + return net->nfqnl.instance_table[st->bucket].first; } return NULL; } -static struct hlist_node *get_next(struct seq_file *seq, struct hlist_node *h) +static struct hlist_node *get_next(struct net *net, struct iter_state *st, + struct hlist_node *h) { - struct iter_state *st = seq->private; - h = h->next; while (!h) { - if (++st->bucket >= INSTANCE_BUCKETS) + if (++st->bucket >= NFQNL_INSTANCE_BUCKETS) return NULL; - h = instance_table[st->bucket].first; + h = net->nfqnl.instance_table[st->bucket].first; } return h; } -static struct hlist_node *get_idx(struct seq_file *seq, loff_t pos) +static struct hlist_node *get_idx(struct net *net, struct iter_state *st, + loff_t pos) { struct hlist_node *head; - head = get_first(seq); + head = get_first(net, st); if (head) - while (pos && (head = get_next(seq, head))) + while (pos && (head = get_next(net, st, head))) pos--; return pos ? NULL : head; } static void *seq_start(struct seq_file *seq, loff_t *pos) - __acquires(instances_lock) { - spin_lock(&instances_lock); - return get_idx(seq, *pos); + struct net *net = seq_file_net(seq); + spin_lock(&net->nfqnl.instances_lock); + return get_idx(net, seq->private, *pos); } static void *seq_next(struct seq_file *s, void *v, loff_t *pos) { (*pos)++; - return get_next(s, v); + return get_next(seq_file_net(s), s->private, v); } static void seq_stop(struct seq_file *s, void *v) - __releases(instances_lock) { - spin_unlock(&instances_lock); + struct net *net = seq_file_net(s); + spin_unlock(&net->nfqnl.instances_lock); } static int seq_show(struct seq_file *s, void *v) @@ -968,8 +965,8 @@ static const struct seq_operations nfqnl_seq_ops = { static int nfqnl_open(struct inode *inode, struct file *file) { - return seq_open_private(file, &nfqnl_seq_ops, - sizeof(struct iter_state)); + return seq_open_net(inode, file, &nfqnl_seq_ops, + sizeof(struct iter_state)); } static const struct file_operations nfqnl_file_ops = { @@ -977,13 +974,19 @@ static const struct file_operations nfqnl_file_ops = { .open = nfqnl_open, .read = seq_read, .llseek = seq_lseek, - .release = seq_release_private, + .release = seq_release_net, }; #endif /* PROC_FS */ static int __net_init nfnetlink_queue_net_init(struct net *net) { + int i; + + spin_lock_init(&net->nfqnl.instances_lock); + for (i = 0; i < NFQNL_INSTANCE_BUCKETS; i++) + INIT_HLIST_HEAD(&net->nfqnl.instance_table[i]); + #ifdef CONFIG_PROC_FS if (!proc_create("nfnetlink_queue", 0440, net->proc_net_netfilter, &nfqnl_file_ops)) @@ -1007,7 +1010,7 @@ static struct pernet_operations nfnetlink_queue_net_ops = { static int __init nfnetlink_queue_init(void) { - int i, status; + int status; status = register_pernet_subsys(&nfnetlink_queue_net_ops); if (status) { @@ -1016,9 +1019,6 @@ static int __init nfnetlink_queue_init(void) return status; } - for (i = 0; i < INSTANCE_BUCKETS; i++) - INIT_HLIST_HEAD(&instance_table[i]); - netlink_register_notifier(&nfqnl_rtnl_notifier); status = nfnetlink_subsys_register(&nfqnl_subsys); if (status < 0) { -- 1.7.10.4 core-4.8/kernel/core-kernel-3.8/0000775000175000017500000000000012534327775013333 500000000000000core-4.8/kernel/core-kernel-3.8/Makefile0000664000175000017500000000365412534327775014723 00000000000000VERSION := $(shell dpkg -l linux-source 2> /dev/null | \ awk '/^i/ {match($$3, "[0-9]+[.][0-9]+[.][0-9]+"); if (RSTART) print substr($$3, RSTART, RLENGTH)}') TARBALL := /usr/src/linux-source-$(VERSION).tar.bz2 SUBVERSION := -core REVISION := 1.0 PATCHDIR := patches PATCHES := $(sort $(wildcard $(PATCHDIR)/*.patch)) CONFIG := config.core DEPDEBS := linux-source kernel-package po-debconf gettext CONCURRENCY_LEVEL := $(shell lscpu 2> /dev/null | \ awk '/^CPU\(s\)/ {print $$2}') ifeq ($(strip $(CONCURRENCY_LEVEL)),) CONCURRENCY_LEVEL := 1 endif MAINTAINER ?= $(shell id -nu) EMAIL ?= $(MAINTAINER)@$(shell hostname -f) MAKEKPKGFLAGS := --initrd --rootcmd fakeroot --us --uc \ --append-to-version $(SUBVERSION) --revision $(REVISION) .PHONY: build build: debcheck defaultconfig patch export CONCURRENCY_LEVEL="$(CONCURRENCY_LEVEL)" \ KPKG_MAINTAINER="$(MAINTAINER)" KPKG_EMAIL="$(EMAIL)"; \ cd linux-source-$(VERSION) && \ if [ -f ../$(CONFIG) ]; then \ cat ../$(CONFIG) >> .config; \ fi && \ fakeroot make-kpkg $(MAKEKPKGFLAGS) binary-arch .PHONY: debcheck debcheck: for d in $(DEPDEBS); do \ if ! dpkg-query -s $$d > /dev/null 2>&1; then \ echo ERROR: build dependency not installed: $$d >&2; \ exit 1; \ fi; \ done .PHONY: defaultconfig defaultconfig: linux-source-$(VERSION) export KPKG_MAINTAINER="$(MAINTAINER)" KPKG_EMAIL="$(EMAIL)"; \ cd linux-source-$(VERSION) && make-kpkg $(MAKEKPKGFLAGS) configure .PHONY: patch patch: linux-source-$(VERSION) patch-stamp patch-stamp: $(PATCHES) for p in $^; do \ if ! patch -d linux-source-$(VERSION) -p1 < $$p; then \ echo ERROR: applying patch failed: $$p >&2; \ exit 1; \ fi; \ done touch patch-stamp .PHONY: source source: linux-source-$(VERSION) linux-source-$(VERSION): $(TARBALL) tar -xjf $^ .PHONY: clean clean: rm -rf linux-source-$(VERSION) patch-stamp core-4.8/kernel/core-kernel-3.8/config.core0000664000175000017500000000003112534327775015364 00000000000000CONFIG_XFRM_STATISTICS=y core-4.8/kernel/core-kernel-3.8/patches/0000775000175000017500000000000012534327775014762 500000000000000core-4.8/kernel/core-kernel-3.8/patches/00-ifindex.patch0000664000175000017500000000161012534327775017564 00000000000000From 1d992600b0f1962d0478df2083b76b1ceba50517 Mon Sep 17 00:00:00 2001 From: Tom Goff Date: Mon, 3 Jun 2013 18:29:42 -0700 Subject: [PATCH 1/3] Make network device ifindex sequential per network namespace. Signed-off-by: Tom Goff --- net/core/dev.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/core/dev.c b/net/core/dev.c index d592214..4b8da6e 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -6455,8 +6455,8 @@ int dev_change_net_namespace(struct net_device *dev, struct net *net, const char /* Actually switch the network namespace */ dev_net_set(dev, net); - /* If there is an ifindex conflict assign a new one */ - if (__dev_get_by_index(net, dev->ifindex)) { + /* Assign a new ifindex */ + { int iflink = (dev->iflink == dev->ifindex); dev->ifindex = dev_new_index(net); if (iflink) -- 1.8.1.2 core-4.8/kernel/core-kernel-3.8/patches/00-nfnetlink_queue.patch0000664000175000017500000002052712534327775021342 00000000000000From 433bc9e01b6a50db276c0b0d9dcd8bfcc2bc42f8 Mon Sep 17 00:00:00 2001 From: Tom Goff Date: Mon, 3 Jun 2013 18:30:31 -0700 Subject: [PATCH 2/3] netfilter: Make the /proc/net/netfilter directory per netns. This allows subsystems to create per-netns entries. Signed-off-by: Tom Goff --- include/linux/netfilter.h | 5 ---- include/net/net_namespace.h | 3 +++ net/netfilter/core.c | 35 ++++++++++++++++++++------- net/netfilter/nf_log.c | 33 ++++++++++++++++++++++---- net/netfilter/nfnetlink_log.c | 46 ++++++++++++++++++++++++------------ net/netfilter/nfnetlink_queue_core.c | 45 ++++++++++++++++++++++++----------- 6 files changed, 121 insertions(+), 46 deletions(-) diff --git a/include/linux/netfilter.h b/include/linux/netfilter.h index ee14284..0060fde 100644 --- a/include/linux/netfilter.h +++ b/include/linux/netfilter.h @@ -289,11 +289,6 @@ nf_nat_decode_session(struct sk_buff *skb, struct flowi *fl, u_int8_t family) #endif } -#ifdef CONFIG_PROC_FS -#include -extern struct proc_dir_entry *proc_net_netfilter; -#endif - #else /* !CONFIG_NETFILTER */ #define NF_HOOK(pf, hook, skb, indev, outdev, okfn) (okfn)(skb) #define NF_HOOK_COND(pf, hook, skb, indev, outdev, okfn, cond) (okfn)(skb) diff --git a/include/net/net_namespace.h b/include/net/net_namespace.h index de644bc..96b2242 100644 --- a/include/net/net_namespace.h +++ b/include/net/net_namespace.h @@ -94,6 +94,9 @@ struct net { struct netns_dccp dccp; #endif #ifdef CONFIG_NETFILTER +#ifdef CONFIG_PROC_FS + struct proc_dir_entry *proc_net_netfilter; +#endif struct netns_xt xt; #if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE) struct netns_ct ct; diff --git a/net/netfilter/core.c b/net/netfilter/core.c index a9c488b..00e356d 100644 --- a/net/netfilter/core.c +++ b/net/netfilter/core.c @@ -276,25 +276,44 @@ void (*nf_nat_decode_session_hook)(struct sk_buff *, struct flowi *); EXPORT_SYMBOL(nf_nat_decode_session_hook); #endif +static int __net_init netfilter_net_init(struct net *net) +{ +#ifdef CONFIG_PROC_FS + net->proc_net_netfilter = proc_net_mkdir(net, "netfilter", + net->proc_net); + if (!net->proc_net_netfilter) { + pr_err("%s: cannot create netfilter proc entry\n", __func__); + return -ENOMEM; + } +#endif + + return 0; +} + +static void __net_exit netfilter_net_exit(struct net *net) +{ #ifdef CONFIG_PROC_FS -struct proc_dir_entry *proc_net_netfilter; -EXPORT_SYMBOL(proc_net_netfilter); + proc_net_remove(net, "netfilter"); #endif +} + +static struct pernet_operations netfilter_net_ops = { + .init = netfilter_net_init, + .exit = netfilter_net_exit, +}; void __init netfilter_init(void) { int i, h; + + if (register_pernet_subsys(&netfilter_net_ops)) + panic("%s: failed to register per netns operations", __func__); + for (i = 0; i < ARRAY_SIZE(nf_hooks); i++) { for (h = 0; h < NF_MAX_HOOKS; h++) INIT_LIST_HEAD(&nf_hooks[i][h]); } -#ifdef CONFIG_PROC_FS - proc_net_netfilter = proc_mkdir("netfilter", init_net.proc_net); - if (!proc_net_netfilter) - panic("cannot create netfilter proc entry"); -#endif - if (netfilter_log_init() < 0) panic("cannot initialize nf_log"); } diff --git a/net/netfilter/nf_log.c b/net/netfilter/nf_log.c index 9e31269..5f33072 100644 --- a/net/netfilter/nf_log.c +++ b/net/netfilter/nf_log.c @@ -290,14 +290,39 @@ static __init int netfilter_log_sysctl_init(void) } #endif /* CONFIG_SYSCTL */ -int __init netfilter_log_init(void) +static int __net_init netfilter_log_net_init(struct net *net) { - int i, r; #ifdef CONFIG_PROC_FS if (!proc_create("nf_log", S_IRUGO, - proc_net_netfilter, &nflog_file_ops)) - return -1; + net->proc_net_netfilter, &nflog_file_ops)) + return -ENOMEM; +#endif + + return 0; +} + +static void __net_exit netfilter_log_net_exit(struct net *net) +{ +#ifdef CONFIG_PROC_FS + remove_proc_entry("nf_log", net->proc_net_netfilter); #endif +} + +static struct pernet_operations netfilter_log_net_ops = { + .init = netfilter_log_net_init, + .exit = netfilter_log_net_exit, +}; + +int __init netfilter_log_init(void) +{ + int i, r; + + r = register_pernet_subsys(&netfilter_log_net_ops); + if (r) { + pr_err("%s: failed to register per netns operations\n", + __func__); + return r; + } /* Errors will trigger panic, unroll on error is unnecessary. */ r = netfilter_log_sysctl_init(); diff --git a/net/netfilter/nfnetlink_log.c b/net/netfilter/nfnetlink_log.c index 92fd8ec..9571c43 100644 --- a/net/netfilter/nfnetlink_log.c +++ b/net/netfilter/nfnetlink_log.c @@ -986,9 +986,39 @@ static const struct file_operations nful_file_ops = { #endif /* PROC_FS */ +static int __net_init nfnetlink_log_net_init(struct net *net) +{ +#ifdef CONFIG_PROC_FS + if (!proc_create("nfnetlink_log", 0440, + net->proc_net_netfilter, &nful_file_ops)) + return -ENOMEM; +#endif + + return 0; +} + +static void __net_exit nfnetlink_log_net_exit(struct net *net) +{ +#ifdef CONFIG_PROC_FS + remove_proc_entry("nfnetlink_log", net->proc_net_netfilter); +#endif +} + +static struct pernet_operations nfnetlink_log_net_ops = { + .init = nfnetlink_log_net_init, + .exit = nfnetlink_log_net_exit, +}; + static int __init nfnetlink_log_init(void) { - int i, status = -ENOMEM; + int i, status; + + status = register_pernet_subsys(&nfnetlink_log_net_ops); + if (status) { + pr_err("%s: failed to register per netns operations\n", + __func__); + return status; + } for (i = 0; i < INSTANCE_BUCKETS; i++) INIT_HLIST_HEAD(&instance_table[i]); @@ -1011,19 +1041,8 @@ static int __init nfnetlink_log_init(void) goto cleanup_subsys; } -#ifdef CONFIG_PROC_FS - if (!proc_create("nfnetlink_log", 0440, - proc_net_netfilter, &nful_file_ops)) { - status = -ENOMEM; - goto cleanup_logger; - } -#endif return status; -#ifdef CONFIG_PROC_FS -cleanup_logger: - nf_log_unregister(&nfulnl_logger); -#endif cleanup_subsys: nfnetlink_subsys_unregister(&nfulnl_subsys); cleanup_netlink_notifier: @@ -1034,9 +1053,6 @@ cleanup_netlink_notifier: static void __exit nfnetlink_log_fini(void) { nf_log_unregister(&nfulnl_logger); -#ifdef CONFIG_PROC_FS - remove_proc_entry("nfnetlink_log", proc_net_netfilter); -#endif nfnetlink_subsys_unregister(&nfulnl_subsys); netlink_unregister_notifier(&nfulnl_rtnl_notifier); } diff --git a/net/netfilter/nfnetlink_queue_core.c b/net/netfilter/nfnetlink_queue_core.c index 3158d87..8f2d9bb 100644 --- a/net/netfilter/nfnetlink_queue_core.c +++ b/net/netfilter/nfnetlink_queue_core.c @@ -1048,9 +1048,39 @@ static const struct file_operations nfqnl_file_ops = { #endif /* PROC_FS */ +static int __net_init nfnetlink_queue_net_init(struct net *net) +{ +#ifdef CONFIG_PROC_FS + if (!proc_create("nfnetlink_queue", 0440, + net->proc_net_netfilter, &nfqnl_file_ops)) + return -ENOMEM; +#endif + + return 0; +} + +static void __net_exit nfnetlink_queue_net_exit(struct net *net) +{ +#ifdef CONFIG_PROC_FS + remove_proc_entry("nfnetlink_queue", net->proc_net_netfilter); +#endif +} + +static struct pernet_operations nfnetlink_queue_net_ops = { + .init = nfnetlink_queue_net_init, + .exit = nfnetlink_queue_net_exit, +}; + static int __init nfnetlink_queue_init(void) { - int i, status = -ENOMEM; + int i, status; + + status = register_pernet_subsys(&nfnetlink_queue_net_ops); + if (status) { + pr_err("%s: failed to register per netns operations\n", + __func__); + return status; + } for (i = 0; i < INSTANCE_BUCKETS; i++) INIT_HLIST_HEAD(&instance_table[i]); @@ -1062,20 +1092,10 @@ static int __init nfnetlink_queue_init(void) goto cleanup_netlink_notifier; } -#ifdef CONFIG_PROC_FS - if (!proc_create("nfnetlink_queue", 0440, - proc_net_netfilter, &nfqnl_file_ops)) - goto cleanup_subsys; -#endif - register_netdevice_notifier(&nfqnl_dev_notifier); nf_register_queue_handler(&nfqh); return status; -#ifdef CONFIG_PROC_FS -cleanup_subsys: - nfnetlink_subsys_unregister(&nfqnl_subsys); -#endif cleanup_netlink_notifier: netlink_unregister_notifier(&nfqnl_rtnl_notifier); return status; @@ -1085,9 +1105,6 @@ static void __exit nfnetlink_queue_fini(void) { nf_unregister_queue_handler(); unregister_netdevice_notifier(&nfqnl_dev_notifier); -#ifdef CONFIG_PROC_FS - remove_proc_entry("nfnetlink_queue", proc_net_netfilter); -#endif nfnetlink_subsys_unregister(&nfqnl_subsys); netlink_unregister_notifier(&nfqnl_rtnl_notifier); -- 1.8.1.2 core-4.8/kernel/core-kernel-3.8/patches/01-nfnetlink_queue.patch0000664000175000017500000003405512534327775021344 00000000000000From 3d1c0bfef9d6ca43050e7a9077b46e0139ee1e1f Mon Sep 17 00:00:00 2001 From: Tom Goff Date: Mon, 3 Jun 2013 18:31:29 -0700 Subject: [PATCH 3/3] netfilter: nfnetlink_queue: Add netns support. Make nfnetlink_queue network namespace aware including a per-netns /proc/net/netfilter/nfnetlink_queue file. Signed-off-by: Tom Goff --- include/net/net_namespace.h | 6 ++ include/net/netfilter/nf_queue.h | 3 +- net/netfilter/nf_queue.c | 12 ++- net/netfilter/nfnetlink_queue_core.c | 137 ++++++++++++++++++----------------- 4 files changed, 88 insertions(+), 70 deletions(-) diff --git a/include/net/net_namespace.h b/include/net/net_namespace.h index 96b2242..1af155b 100644 --- a/include/net/net_namespace.h +++ b/include/net/net_namespace.h @@ -22,6 +22,9 @@ #include #endif #include +#if defined(CONFIG_NETFILTER_NETLINK_QUEUE) || defined(CONFIG_NETFILTER_NETLINK_QUEUE_MODULE) +#include +#endif struct user_namespace; struct proc_dir_entry; @@ -106,6 +109,9 @@ struct net { #endif struct sock *nfnl; struct sock *nfnl_stash; +#if defined(CONFIG_NETFILTER_NETLINK_QUEUE) || defined(CONFIG_NETFILTER_NETLINK_QUEUE_MODULE) + struct netns_nfqnl nfqnl; +#endif #endif #ifdef CONFIG_WEXT_CORE struct sk_buff_head wext_nlevents; diff --git a/include/net/netfilter/nf_queue.h b/include/net/netfilter/nf_queue.h index fb1c0be..484453d 100644 --- a/include/net/netfilter/nf_queue.h +++ b/include/net/netfilter/nf_queue.h @@ -19,7 +19,8 @@ struct nf_queue_entry { /* Packet queuing */ struct nf_queue_handler { - int (*outfn)(struct nf_queue_entry *entry, + int (*outfn)(struct net *net, + struct nf_queue_entry *entry, unsigned int queuenum); }; diff --git a/net/netfilter/nf_queue.c b/net/netfilter/nf_queue.c index d812c12..0d69be9 100644 --- a/net/netfilter/nf_queue.c +++ b/net/netfilter/nf_queue.c @@ -81,6 +81,16 @@ static int __nf_queue(struct sk_buff *skb, #endif const struct nf_afinfo *afinfo; const struct nf_queue_handler *qh; + struct net *net; + + if (indev) + net = dev_net(indev); + else if (skb->sk) + net = sock_net(skb->sk); + else if (outdev) + net = dev_net(outdev); + else + return status; /* QUEUE == DROP if no one is waiting, to be safe. */ rcu_read_lock(); @@ -133,7 +143,7 @@ static int __nf_queue(struct sk_buff *skb, #endif skb_dst_force(skb); afinfo->saveroute(skb, entry); - status = qh->outfn(entry, queuenum); + status = qh->outfn(net, entry, queuenum); rcu_read_unlock(); diff --git a/net/netfilter/nfnetlink_queue_core.c b/net/netfilter/nfnetlink_queue_core.c index 8f2d9bb..1e0a830 100644 --- a/net/netfilter/nfnetlink_queue_core.c +++ b/net/netfilter/nfnetlink_queue_core.c @@ -66,24 +66,19 @@ struct nfqnl_instance { typedef int (*nfqnl_cmpfn)(struct nf_queue_entry *, unsigned long); -static DEFINE_SPINLOCK(instances_lock); - -#define INSTANCE_BUCKETS 16 -static struct hlist_head instance_table[INSTANCE_BUCKETS] __read_mostly; - static inline u_int8_t instance_hashfn(u_int16_t queue_num) { - return ((queue_num >> 8) | queue_num) % INSTANCE_BUCKETS; + return ((queue_num >> 8) | queue_num) % NFQNL_INSTANCE_BUCKETS; } static struct nfqnl_instance * -instance_lookup(u_int16_t queue_num) +instance_lookup(struct net *net, u_int16_t queue_num) { struct hlist_head *head; struct hlist_node *pos; struct nfqnl_instance *inst; - head = &instance_table[instance_hashfn(queue_num)]; + head = &net->nfqnl.instance_table[instance_hashfn(queue_num)]; hlist_for_each_entry_rcu(inst, pos, head, hlist) { if (inst->queue_num == queue_num) return inst; @@ -92,14 +87,14 @@ instance_lookup(u_int16_t queue_num) } static struct nfqnl_instance * -instance_create(u_int16_t queue_num, int portid) +instance_create(struct net *net, u_int16_t queue_num, int portid) { struct nfqnl_instance *inst; unsigned int h; int err; - spin_lock(&instances_lock); - if (instance_lookup(queue_num)) { + spin_lock(&net->nfqnl.instances_lock); + if (instance_lookup(net, queue_num)) { err = -EEXIST; goto out_unlock; } @@ -124,16 +119,16 @@ instance_create(u_int16_t queue_num, int portid) } h = instance_hashfn(queue_num); - hlist_add_head_rcu(&inst->hlist, &instance_table[h]); + hlist_add_head_rcu(&inst->hlist, &net->nfqnl.instance_table[h]); - spin_unlock(&instances_lock); + spin_unlock(&net->nfqnl.instances_lock); return inst; out_free: kfree(inst); out_unlock: - spin_unlock(&instances_lock); + spin_unlock(&net->nfqnl.instances_lock); return ERR_PTR(err); } @@ -159,11 +154,11 @@ __instance_destroy(struct nfqnl_instance *inst) } static void -instance_destroy(struct nfqnl_instance *inst) +instance_destroy(struct net *net, struct nfqnl_instance *inst) { - spin_lock(&instances_lock); + spin_lock(&net->nfqnl.instances_lock); __instance_destroy(inst); - spin_unlock(&instances_lock); + spin_unlock(&net->nfqnl.instances_lock); } static inline void @@ -417,7 +412,8 @@ nla_put_failure: } static int -nfqnl_enqueue_packet(struct nf_queue_entry *entry, unsigned int queuenum) +nfqnl_enqueue_packet(struct net *net, struct nf_queue_entry *entry, + unsigned int queuenum) { struct sk_buff *nskb; struct nfqnl_instance *queue; @@ -426,7 +422,7 @@ nfqnl_enqueue_packet(struct nf_queue_entry *entry, unsigned int queuenum) int failopen = 0; /* rcu_read_lock()ed by nf_hook_slow() */ - queue = instance_lookup(queuenum); + queue = instance_lookup(net, queuenum); if (!queue) { err = -ESRCH; goto err_out; @@ -463,7 +459,7 @@ nfqnl_enqueue_packet(struct nf_queue_entry *entry, unsigned int queuenum) *packet_id_ptr = htonl(entry->id); /* nfnetlink_unicast will either free the nskb or add it to a socket */ - err = nfnetlink_unicast(nskb, &init_net, queue->peer_portid, MSG_DONTWAIT); + err = nfnetlink_unicast(nskb, net, queue->peer_portid, MSG_DONTWAIT); if (err < 0) { queue->queue_user_dropped++; goto err_out_unlock; @@ -576,16 +572,16 @@ dev_cmp(struct nf_queue_entry *entry, unsigned long ifindex) /* drop all packets with either indev or outdev == ifindex from all queue * instances */ static void -nfqnl_dev_drop(int ifindex) +nfqnl_dev_drop(struct net *net, int ifindex) { int i; rcu_read_lock(); - for (i = 0; i < INSTANCE_BUCKETS; i++) { + for (i = 0; i < NFQNL_INSTANCE_BUCKETS; i++) { struct hlist_node *tmp; struct nfqnl_instance *inst; - struct hlist_head *head = &instance_table[i]; + struct hlist_head *head = &net->nfqnl.instance_table[i]; hlist_for_each_entry_rcu(inst, tmp, head, hlist) nfqnl_flush(inst, dev_cmp, ifindex); @@ -602,12 +598,9 @@ nfqnl_rcv_dev_event(struct notifier_block *this, { struct net_device *dev = ptr; - if (!net_eq(dev_net(dev), &init_net)) - return NOTIFY_DONE; - /* Drop any packets associated with the downed device */ if (event == NETDEV_DOWN) - nfqnl_dev_drop(dev->ifindex); + nfqnl_dev_drop(dev_net(dev), dev->ifindex); return NOTIFY_DONE; } @@ -625,19 +618,19 @@ nfqnl_rcv_nl_event(struct notifier_block *this, int i; /* destroy all instances for this portid */ - spin_lock(&instances_lock); - for (i = 0; i < INSTANCE_BUCKETS; i++) { + spin_lock(&n->net->nfqnl.instances_lock); + for (i = 0; i < NFQNL_INSTANCE_BUCKETS; i++) { struct hlist_node *tmp, *t2; struct nfqnl_instance *inst; - struct hlist_head *head = &instance_table[i]; + struct hlist_head *head = + &n->net->nfqnl.instance_table[i]; hlist_for_each_entry_safe(inst, tmp, t2, head, hlist) { - if ((n->net == &init_net) && - (n->portid == inst->peer_portid)) + if (n->portid == inst->peer_portid) __instance_destroy(inst); } } - spin_unlock(&instances_lock); + spin_unlock(&n->net->nfqnl.instances_lock); } return NOTIFY_DONE; } @@ -658,11 +651,13 @@ static const struct nla_policy nfqa_verdict_batch_policy[NFQA_MAX+1] = { [NFQA_MARK] = { .type = NLA_U32 }, }; -static struct nfqnl_instance *verdict_instance_lookup(u16 queue_num, int nlportid) +static struct nfqnl_instance *verdict_instance_lookup(struct net *net, + u16 queue_num, + int nlportid) { struct nfqnl_instance *queue; - queue = instance_lookup(queue_num); + queue = instance_lookup(net, queue_num); if (!queue) return ERR_PTR(-ENODEV); @@ -706,7 +701,8 @@ nfqnl_recv_verdict_batch(struct sock *ctnl, struct sk_buff *skb, LIST_HEAD(batch_list); u16 queue_num = ntohs(nfmsg->res_id); - queue = verdict_instance_lookup(queue_num, NETLINK_CB(skb).portid); + queue = verdict_instance_lookup(sock_net(ctnl), queue_num, + NETLINK_CB(skb).portid); if (IS_ERR(queue)) return PTR_ERR(queue); @@ -751,13 +747,14 @@ nfqnl_recv_verdict(struct sock *ctnl, struct sk_buff *skb, struct nfqnl_instance *queue; unsigned int verdict; struct nf_queue_entry *entry; + struct net *net = sock_net(ctnl); enum ip_conntrack_info uninitialized_var(ctinfo); struct nf_conn *ct = NULL; - queue = instance_lookup(queue_num); + queue = instance_lookup(net, queue_num); if (!queue) - queue = verdict_instance_lookup(queue_num, NETLINK_CB(skb).portid); + queue = verdict_instance_lookup(net, queue_num, NETLINK_CB(skb).portid); if (IS_ERR(queue)) return PTR_ERR(queue); @@ -822,6 +819,7 @@ nfqnl_recv_config(struct sock *ctnl, struct sk_buff *skb, struct nfqnl_instance *queue; struct nfqnl_msg_config_cmd *cmd = NULL; int ret = 0; + struct net *net = sock_net(ctnl); if (nfqa[NFQA_CFG_CMD]) { cmd = nla_data(nfqa[NFQA_CFG_CMD]); @@ -834,7 +832,7 @@ nfqnl_recv_config(struct sock *ctnl, struct sk_buff *skb, } rcu_read_lock(); - queue = instance_lookup(queue_num); + queue = instance_lookup(net, queue_num); if (queue && queue->peer_portid != NETLINK_CB(skb).portid) { ret = -EPERM; goto err_out_unlock; @@ -847,7 +845,8 @@ nfqnl_recv_config(struct sock *ctnl, struct sk_buff *skb, ret = -EBUSY; goto err_out_unlock; } - queue = instance_create(queue_num, NETLINK_CB(skb).portid); + queue = instance_create(net, queue_num, + NETLINK_CB(skb).portid); if (IS_ERR(queue)) { ret = PTR_ERR(queue); goto err_out_unlock; @@ -858,7 +857,7 @@ nfqnl_recv_config(struct sock *ctnl, struct sk_buff *skb, ret = -ENODEV; goto err_out_unlock; } - instance_destroy(queue); + instance_destroy(net, queue); break; case NFQNL_CFG_CMD_PF_BIND: case NFQNL_CFG_CMD_PF_UNBIND: @@ -952,65 +951,64 @@ static const struct nfnetlink_subsystem nfqnl_subsys = { #ifdef CONFIG_PROC_FS struct iter_state { + struct seq_net_private p; unsigned int bucket; }; -static struct hlist_node *get_first(struct seq_file *seq) +static struct hlist_node *get_first(struct net *net, struct iter_state *st) { - struct iter_state *st = seq->private; - if (!st) return NULL; - for (st->bucket = 0; st->bucket < INSTANCE_BUCKETS; st->bucket++) { - if (!hlist_empty(&instance_table[st->bucket])) - return instance_table[st->bucket].first; + for (st->bucket = 0; st->bucket < NFQNL_INSTANCE_BUCKETS; st->bucket++) { + if (!hlist_empty(&net->nfqnl.instance_table[st->bucket])) + return net->nfqnl.instance_table[st->bucket].first; } return NULL; } -static struct hlist_node *get_next(struct seq_file *seq, struct hlist_node *h) +static struct hlist_node *get_next(struct net *net, struct iter_state *st, + struct hlist_node *h) { - struct iter_state *st = seq->private; - h = h->next; while (!h) { - if (++st->bucket >= INSTANCE_BUCKETS) + if (++st->bucket >= NFQNL_INSTANCE_BUCKETS) return NULL; - h = instance_table[st->bucket].first; + h = net->nfqnl.instance_table[st->bucket].first; } return h; } -static struct hlist_node *get_idx(struct seq_file *seq, loff_t pos) +static struct hlist_node *get_idx(struct net *net, struct iter_state *st, + loff_t pos) { struct hlist_node *head; - head = get_first(seq); + head = get_first(net, st); if (head) - while (pos && (head = get_next(seq, head))) + while (pos && (head = get_next(net, st, head))) pos--; return pos ? NULL : head; } static void *seq_start(struct seq_file *seq, loff_t *pos) - __acquires(instances_lock) { - spin_lock(&instances_lock); - return get_idx(seq, *pos); + struct net *net = seq_file_net(seq); + spin_lock(&net->nfqnl.instances_lock); + return get_idx(net, seq->private, *pos); } static void *seq_next(struct seq_file *s, void *v, loff_t *pos) { (*pos)++; - return get_next(s, v); + return get_next(seq_file_net(s), s->private, v); } static void seq_stop(struct seq_file *s, void *v) - __releases(instances_lock) { - spin_unlock(&instances_lock); + struct net *net = seq_file_net(s); + spin_unlock(&net->nfqnl.instances_lock); } static int seq_show(struct seq_file *s, void *v) @@ -1034,8 +1032,8 @@ static const struct seq_operations nfqnl_seq_ops = { static int nfqnl_open(struct inode *inode, struct file *file) { - return seq_open_private(file, &nfqnl_seq_ops, - sizeof(struct iter_state)); + return seq_open_net(inode, file, &nfqnl_seq_ops, + sizeof(struct iter_state)); } static const struct file_operations nfqnl_file_ops = { @@ -1043,13 +1041,19 @@ static const struct file_operations nfqnl_file_ops = { .open = nfqnl_open, .read = seq_read, .llseek = seq_lseek, - .release = seq_release_private, + .release = seq_release_net, }; #endif /* PROC_FS */ static int __net_init nfnetlink_queue_net_init(struct net *net) { + int i; + + spin_lock_init(&net->nfqnl.instances_lock); + for (i = 0; i < NFQNL_INSTANCE_BUCKETS; i++) + INIT_HLIST_HEAD(&net->nfqnl.instance_table[i]); + #ifdef CONFIG_PROC_FS if (!proc_create("nfnetlink_queue", 0440, net->proc_net_netfilter, &nfqnl_file_ops)) @@ -1073,7 +1077,7 @@ static struct pernet_operations nfnetlink_queue_net_ops = { static int __init nfnetlink_queue_init(void) { - int i, status; + int status; status = register_pernet_subsys(&nfnetlink_queue_net_ops); if (status) { @@ -1082,9 +1086,6 @@ static int __init nfnetlink_queue_init(void) return status; } - for (i = 0; i < INSTANCE_BUCKETS; i++) - INIT_HLIST_HEAD(&instance_table[i]); - netlink_register_notifier(&nfqnl_rtnl_notifier); status = nfnetlink_subsys_register(&nfqnl_subsys); if (status < 0) { -- 1.8.1.2 core-4.8/kernel/freebsd/0000775000175000017500000000000012534327775012231 500000000000000core-4.8/kernel/freebsd/4.11-R-CORE.diff0000664000175000017500000062770612534327775014335 00000000000000diff -urN sys/i386/conf/CORE sys.CORE/i386/conf/CORE --- sys/i386/conf/CORE Wed Dec 31 16:00:00 1969 +++ sys.CORE/i386/conf/CORE Wed Jan 31 16:02:43 2007 @@ -0,0 +1,182 @@ +machine i386 +cpu I586_CPU +cpu I686_CPU +ident CORE +maxusers 0 + +makeoptions DEBUG=-g #Build kernel with gdb(1) debug symbols +options DDB + +options INET #InterNETworking +options INET6 #IPv6 communications protocols +options IPSEC +options IPSEC_ESP +#options IPSEC_DEBUG +options FFS #Berkeley Fast Filesystem +options FFS_ROOT #FFS usable as root device [keep this!] +options SOFTUPDATES #Enable FFS soft updates support +options UFS_DIRHASH #Improve performance on big directories +options MFS #Memory Filesystem +options MD_ROOT #MD is a potential root device +options MSDOSFS #MSDOS Filesystem +options CD9660 #ISO 9660 Filesystem +options CD9660_ROOT #CD-ROM usable as root, CD9660 required +options PROCFS #Process filesystem +options COMPAT_43 #Compatible with BSD 4.3 [KEEP THIS!] +options UCONSOLE #Allow users to grab the console +options USERCONFIG #boot -c editor +options VISUAL_USERCONFIG #visual boot -c editor +options KTRACE #ktrace(1) support +options SYSVSHM #SYSV-style shared memory +options SYSVMSG #SYSV-style message queues +options SYSVSEM #SYSV-style semaphores +options P1003_1B #Posix P1003_1B real-time extensions +options _KPOSIX_PRIORITY_SCHEDULING +options ICMP_BANDLIM #Rate limit bad replies +options KBD_INSTALL_CDEV # install a CDEV entry in /dev + +device isa +device pci + +# Floppy drives +device fdc0 at isa? port IO_FD1 irq 6 drq 2 +device fd0 at fdc0 drive 0 + +# ATA and ATAPI devices +device ata0 at isa? port IO_WD1 irq 14 +device ata1 at isa? port IO_WD2 irq 15 +device ata +device atadisk # ATA disk drives +device atapicd # ATAPI CDROM drives +device atapifd # ATAPI floppy drives +device atapist # ATAPI tape drives +options ATA_STATIC_ID #Static device numbering + +# SCSI peripherals +device scbus # SCSI bus (required) +device da # Direct Access (disks) +device sa # Sequential Access (tape etc) +device cd # CD +device pass # Passthrough device (direct SCSI access) + +# atkbdc0 controls both the keyboard and the PS/2 mouse +device atkbdc0 at isa? port IO_KBD +device atkbd0 at atkbdc? irq 1 flags 0x1 +device psm0 at atkbdc? irq 12 + +device vga0 at isa? + +# syscons is the default console driver, resembling an SCO console +device sc0 at isa? flags 0x100 + +device agp # support several AGP chipsets + +# Floating point support - do not disable. +device npx0 at nexus? port IO_NPX irq 13 + +# Power management support (see LINT for more options) +#device apm0 at nexus? #flags 0x20 # Advanced Power Management + +# PCCARD (PCMCIA) support +device card +device pcic0 at isa? irq 0 port 0x3e0 iomem 0xd0000 +device pcic1 at isa? irq 0 port 0x3e2 iomem 0xd4000 disable + +# Serial (COM) ports +# jeffa: added debug flag +device sio0 at isa? port IO_COM1 flags 0x80 irq 4 +#device sio0 at isa? port IO_COM1 flags 0x10 irq 4 +device sio1 at isa? port IO_COM2 irq 3 + +# PCI Ethernet NICs. +device de # DEC/Intel DC21x4x (``Tulip'') +device em # Intel PRO/1000 adapter Gigabit Ethernet Card (``Wiseman'') +device txp # 3Com 3cR990 (``Typhoon'') +device vx # 3Com 3c590, 3c595 (``Vortex'') + +# PCI Ethernet NICs that use the common MII bus controller code. +# NOTE: Be sure to keep the 'device miibus' line in order to use these NICs! +device miibus # MII bus support +device dc # DEC/Intel 21143 and various workalikes +device fxp # Intel EtherExpress PRO/100B (82557, 82558) +device pcn # AMD Am79C97x PCI 10/100 NICs +device rl # RealTek 8129/8139 +device sf # Adaptec AIC-6915 (``Starfire'') +device sis # Silicon Integrated Systems SiS 900/SiS 7016 +device ste # Sundance ST201 (D-Link DFE-550TX) +device tl # Texas Instruments ThunderLAN +device tx # SMC EtherPower II (83c170 ``EPIC'') +device vr # VIA Rhine, Rhine II +device wb # Winbond W89C840F +device xl # 3Com 3c90x (``Boomerang'', ``Cyclone'') +device bge # Broadcom BCM570x (``Tigon III'') + +# ISA Ethernet NICs. +# 'device ed' requires 'device miibus' +device ed0 at isa? disable port 0x280 irq 10 iomem 0xd8000 +device ex +device ep +device fe0 at isa? disable port 0x300 +# Xircom Ethernet +device xe + +# Wireless +#device awi +device wi +device an + +# The probe order of these is presently determined by i386/isa/isa_compat.c. +device ie0 at isa? disable port 0x300 irq 10 iomem 0xd0000 +#device le0 at isa? disable port 0x300 irq 5 iomem 0xd0000 +device lnc0 at isa? disable port 0x280 irq 10 drq 0 +device cs0 at isa? disable port 0x300 +device sn0 at isa? disable port 0x300 irq 10 + +# Pseudo devices - the number indicates how many units to allocate. +pseudo-device loop # Network loopback +pseudo-device ether # Ethernet support +pseudo-device tun # Packet tunnel. +pseudo-device pty # Pseudo-ttys (telnet etc) +pseudo-device md # Memory "disks" +pseudo-device gif +pseudo-device gre + +# The `bpf' pseudo-device enables the Berkeley Packet Filter. +# Be aware of the administrative consequences of enabling this! +pseudo-device bpf #Berkeley packet filter + +# USB support +device uhci # UHCI PCI->USB interface +device ohci # OHCI PCI->USB interface +device usb # USB Bus (required) +device ugen # Generic +device uhid # "Human Interface Devices" +device ukbd # Keyboard +device ulpt # Printer +device umass # Disks/Mass storage - Requires scbus and da +device ums # Mouse +# USB Ethernet, requires mii +device aue # ADMtek USB ethernet +device cue # CATC USB ethernet +device kue # Kawasaki LSI USB ethernet +# USB com devices +device ucom +device uftdi + +# LIMUNES specific options +options ROOTDEVNAME=\"cd9660:acd0\" +options UNION # Is this really needed? +options EXT2FS # And this? +pseudo-device vn 15 # Vnode driver (turns a file into a device) + +options MROUTING # Multicast routing +options PIM # Protocol Independent Multicast +#options IPFIREWALL # firewall +#options IPFIREWALL_DEFAULT_TO_ACCEPT # allow everything by default +#options IPDIVERT # divert sockets + +options HZ=1000 +#options AUTO_EOI_1 +options CPU_ENABLE_SSE +options CPU_FASTER_5X86_FPU +makeoptions CONF_CFLAGS=-mpentiumpro diff -urN sys/kern/kern_vimage.c sys.CORE/kern/kern_vimage.c --- sys/kern/kern_vimage.c Wed Jan 31 15:57:04 2007 +++ sys.CORE/kern/kern_vimage.c Wed Jan 31 16:02:43 2007 @@ -52,9 +52,13 @@ #include #include #include +#include #include #include +#ifdef IPSEC +#include +#endif /* Arbitrary values */ #define TCP_SYNCACHE_HASHSIZE 512 @@ -107,6 +111,12 @@ { "mrt6stat", V_NET, v_mrt6stat, sizeof (x_vnet->mrt6stat) }, { "mf6ctable", V_NET, v_mf6ctable, sizeof (x_vnet->mf6ctable) }, { "mif6table", V_NET, v_mif6table, sizeof (x_vnet->mif6table) }, +#ifdef IPSEC + { "ipsecstat", V_NET, v_ipsecstat, sizeof (x_vnet->ipsecstat) }, +#ifdef INET6 + { "ipsec6stat", V_NET, v_ipsec6stat, sizeof (x_vnet->ipsec6stat) }, +#endif /* INET6 */ +#endif /* IPSEC */ { NULL, 0, 0 , 0 } }; @@ -742,7 +752,17 @@ } rtable_init((void **)vnet->rt_tables, vnet); +#ifdef IPSEC + if (vnet != vnet0) + key_init(vnet); +#endif vi_loopattach(vnet); + if (vnet != vnet0) + gif_init(vnet); + + /*Boeing IDC*/ + if (vnet != vnet0) + gre_init(vnet); if (IPFW_LOADED) ip_fw_init_ptr(vnet); @@ -796,6 +816,15 @@ free((caddr_t)vnet->ifnet_addrs, M_IFADDR); free((caddr_t)vnet->ifindex2ifnet, M_IFADDR); + + while (!LIST_EMPTY(&vnet->gif_softc_list)) + gif_clone_destroy(&LIST_FIRST(&vnet->gif_softc_list)->gif_if); + rman_fini(vnet->gifunits); + + /*Boeing IDC*/ + while (!LIST_EMPTY(&vnet->gre_softc_list)) + gre_clone_destroy(&LIST_FIRST(&vnet->gre_softc_list)->sc_if); + rman_fini(vnet->greunits); /* hopefully, we are finally clear to free the vnet container itself! */ LIST_REMOVE(vnet, vnet_le); diff -urN sys/net/if.c sys.CORE/net/if.c --- sys/net/if.c Wed Jan 31 15:57:05 2007 +++ sys.CORE/net/if.c Wed Jan 31 16:19:58 2007 @@ -276,6 +276,11 @@ sdl->sdl_data[--namelen] = 0xff; TAILQ_INSERT_HEAD(&ifp->if_addrhead, ifa, ifa_link); } +#ifdef MROUTING +#ifdef PIM + vnet->reg_vif_num = -1; /* XXX means VIFI_INVALID */ +#endif +#endif /* Announce the interface. */ rt_ifannouncemsg(ifp, IFAN_ARRIVAL); diff -urN sys/net/if_gif.c sys.CORE/net/if_gif.c --- sys/net/if_gif.c Wed Jan 31 15:57:05 2007 +++ sys.CORE/net/if_gif.c Wed Jan 31 16:02:43 2007 @@ -90,7 +90,9 @@ #define GIF_MAXUNIT 0x7fff /* ifp->if_unit is only 15 bits */ static MALLOC_DEFINE(M_GIF, "gif", "Generic Tunnel Interface"); +#ifdef MOVED_TO_VNET static struct rman gifunits[1]; +#endif /* MOVED_TO_VNET */ int gif_clone_create __P((struct if_clone *, int *, struct vnet *)); void gif_clone_destroy __P((struct ifnet *)); @@ -114,22 +116,26 @@ */ #define MAX_GIF_NEST 1 #endif +#ifdef MOVED_TO_VNET static int max_gif_nesting = MAX_GIF_NEST; -SYSCTL_INT(_net_link_gif, OID_AUTO, max_nesting, CTLFLAG_RW, - &max_gif_nesting, 0, "Max nested tunnels"); +#endif /* MOVED_TO_VNET */ +SYSCTL_V_INT(V_NET, _net_link_gif, OID_AUTO, max_nesting, CTLFLAG_RW, + v_max_gif_nesting, 0, "Max nested tunnels"); /* * By default, we disallow creation of multiple tunnels between the same * pair of addresses. Some applications require this functionality so * we allow control over this check here. */ +#ifdef MOVED_TO_VNET #ifdef XBONEHACK static int parallel_tunnels = 1; #else static int parallel_tunnels = 0; #endif -SYSCTL_INT(_net_link_gif, OID_AUTO, parallel_tunnels, CTLFLAG_RW, - ¶llel_tunnels, 0, "Allow parallel tunnels?"); +#endif /* MOVED_TO_VNET */ +SYSCTL_V_INT(V_NET, _net_link_gif, OID_AUTO, parallel_tunnels, CTLFLAG_RW, + v_parallel_tunnels, 0, "Allow parallel tunnels?"); int gif_clone_create(ifc, unit, vnet) @@ -140,17 +146,19 @@ struct resource *r; struct gif_softc *sc; + if (vnet == NULL) + panic("gif_clone_create: NULL vnet was passed."); if (*unit > GIF_MAXUNIT) return (ENXIO); if (*unit < 0) { - r = rman_reserve_resource(gifunits, 0, GIF_MAXUNIT, 1, + r = rman_reserve_resource(vnet->gifunits, 0, GIF_MAXUNIT, 1, RF_ALLOCATED | RF_ACTIVE, NULL); if (r == NULL) return (ENOSPC); *unit = rman_get_start(r); } else { - r = rman_reserve_resource(gifunits, *unit, *unit, 1, + r = rman_reserve_resource(vnet->gifunits, *unit, *unit, 1, RF_ALLOCATED | RF_ACTIVE, NULL); if (r == NULL) return (EEXIST); @@ -202,6 +210,8 @@ struct gif_softc *sc = ifp->if_softc; struct vnet *vnet = ifp->if_vnet; + if (vnet == NULL) + panic("gif_clone_destroy: NULL vnet from ifp."); gif_delete_tunnel(&sc->gif_if); LIST_REMOVE(sc, gif_list); #ifdef INET6 @@ -226,31 +236,61 @@ free(sc, M_GIF); } +/* Initialize gif vars for a single vnet */ +int +gif_init(vnet) + struct vnet *vnet; +{ + int err=0; + + vnet->max_gif_nesting = MAX_GIF_NEST; + vnet->parallel_tunnels = 0; + vnet->gifunits->rm_type = RMAN_ARRAY; + vnet->gifunits->rm_descr = "configurable if_gif units"; + err = rman_init(vnet->gifunits); + if (err != 0) + return (err); + err = rman_manage_region(vnet->gifunits, 0, GIF_MAXUNIT); + if (err != 0) { + printf("%s: gifunits: rman_manage_region: Failed %d\n", + GIFNAME, err); + rman_fini(vnet->gifunits); + return (err); + } + LIST_INIT(&vnet->gif_softc_list); + + return 0; +} + static int gifmodevent(mod, type, data) module_t mod; int type; void *data; { - int err; + int err=0; struct vnet *vnet; switch (type) { case MOD_LOAD: - gifunits->rm_type = RMAN_ARRAY; - gifunits->rm_descr = "configurable if_gif units"; - err = rman_init(gifunits); + LIST_FOREACH(vnet, &vnet_head, vnet_le) + { + vnet->max_gif_nesting = MAX_GIF_NEST; + vnet->parallel_tunnels = 0; + vnet->gifunits->rm_type = RMAN_ARRAY; + vnet->gifunits->rm_descr = "configurable if_gif units"; + err = rman_init(vnet->gifunits); if (err != 0) return (err); - err = rman_manage_region(gifunits, 0, GIF_MAXUNIT); + err = rman_manage_region(vnet->gifunits, 0, GIF_MAXUNIT); if (err != 0) { printf("%s: gifunits: rman_manage_region: Failed %d\n", GIFNAME, err); - rman_fini(gifunits); + rman_fini(vnet->gifunits); return (err); } - LIST_FOREACH(vnet, &vnet_head, vnet_le) - LIST_INIT(&vnet->gif_softc_list); + LIST_INIT(&vnet->gif_softc_list); + } if_clone_attach(&gif_cloner); #ifdef INET6 @@ -261,11 +301,12 @@ case MOD_UNLOAD: if_clone_detach(&gif_cloner); - LIST_FOREACH(vnet, &vnet_head, vnet_le) + LIST_FOREACH(vnet, &vnet_head, vnet_le) { while (!LIST_EMPTY(&vnet->gif_softc_list)) gif_clone_destroy(&LIST_FIRST(&vnet->gif_softc_list)->gif_if); + err = rman_fini(vnet->gifunits); + } - err = rman_fini(gifunits); if (err != 0) return (err); #ifdef INET6 @@ -295,6 +336,8 @@ struct ip ip; struct gif_softc *sc; + if (vnet == NULL) + panic("gif_encapcheck: NULL vnet was passed."); sc = (struct gif_softc *)arg; if (sc == NULL) return 0; @@ -358,6 +401,11 @@ struct gif_softc *sc = (struct gif_softc*)ifp; int error = 0; static int called = 0; /* XXX: MUTEX */ + struct vnet *vnet; + + vnet = ifp->if_vnet; + /*if (vnet == NULL) + panic("gif_output: cannot find vnet.");*/ /* * gif may cause infinite recursion calls when misconfigured. @@ -366,7 +414,7 @@ * mutual exclusion of the variable CALLED, especially if we * use kernel thread. */ - if (++called > max_gif_nesting) { + if (++called > vnet->max_gif_nesting) { log(LOG_NOTICE, "gif_output: recursively called too many times(%d)\n", called); @@ -441,13 +489,16 @@ int s, isr; struct p_ifqueue *p_ifq = NULL; struct ifqueue *ifq; - struct vnet *vnet = m->m_pkthdr.rcvif->if_vnet; + struct vnet *vnet; if (ifp == NULL) { /* just in case */ m_freem(m); return; } + vnet = ifp->if_vnet; + if (vnet == NULL) + panic("gif_input: NULL vnet was passed."); m->m_pkthdr.rcvif = ifp; @@ -779,6 +830,8 @@ int error = 0; struct vnet *vnet = sc->gif_vnet; + if (vnet == NULL) + panic("gif_set_tunnel: NULL vnet from sc->gif_vnet"); s = splnet(); LIST_FOREACH(sc2, &vnet->gif_softc_list, gif_list) { @@ -796,7 +849,7 @@ * Disallow parallel tunnels unless instructed * otherwise. */ - if (!parallel_tunnels && + if (!vnet->parallel_tunnels && bcmp(sc2->gif_pdst, dst, dst->sa_len) == 0 && bcmp(sc2->gif_psrc, src, src->sa_len) == 0) { error = EADDRNOTAVAIL; diff -urN sys/net/if_gif.h sys.CORE/net/if_gif.h --- sys/net/if_gif.h Wed Jan 31 15:57:05 2007 +++ sys.CORE/net/if_gif.h Wed Jan 31 16:02:43 2007 @@ -75,6 +75,7 @@ #define GIF_MTU_MAX (8192) /* Maximum MTU */ /* Prototypes */ +int gif_init(struct vnet *); void gifattach0 __P((struct gif_softc *)); void gif_input __P((struct mbuf *, int, struct ifnet *)); int gif_output __P((struct ifnet *, struct mbuf *, diff -urN sys/net/if_gre.c sys.CORE/net/if_gre.c --- sys/net/if_gre.c Wed Jan 31 15:57:05 2007 +++ sys.CORE/net/if_gre.c Wed Jan 31 16:02:43 2007 @@ -97,10 +97,14 @@ #define GRE_MAXUNIT 0x7fff static MALLOC_DEFINE(M_GRE, GRENAME, "Generic Routing Encapsulation"); +#ifdef MOVED_TO_VNET static struct rman greunits[1]; +#endif /* MOVED_TO_VNET */ -static int gre_clone_create(struct if_clone *, int *, struct vnet *); -static void gre_clone_destroy(struct ifnet *); +/*Boeing IDC static int gre_clone_create(struct if_clone *, int *, struct vnet *);*/ +/*Boeing IDC static void gre_clone_destroy(struct ifnet *);*/ +int gre_clone_create __P((struct if_clone *, int *, struct vnet *)); +void gre_clone_destroy __P((struct ifnet *)); static int gre_ioctl(struct ifnet *, u_long, caddr_t); static int gre_output(struct ifnet *, struct mbuf *, struct sockaddr *, struct rtentry *rt); @@ -144,9 +148,11 @@ */ #define MAX_GRE_NEST 1 #endif +#ifdef MOVED_TO_VNET static int max_gre_nesting = MAX_GRE_NEST; -SYSCTL_INT(_net_link_gre, OID_AUTO, max_nesting, CTLFLAG_RW, - &max_gre_nesting, 0, "Max nested tunnels"); +#endif /* MOVED_TO_VNET */ +SYSCTL_V_INT(V_NET, _net_link_gre, OID_AUTO, max_nesting, CTLFLAG_RW, + v_max_gre_nesting, 0, "Max nested tunnels"); /* ARGSUSED */ static void @@ -167,17 +173,20 @@ struct resource *r; struct gre_softc *sc; + if (vnet == NULL) + panic("gre_clone_create: NULL vnet was passed."); + if (*unit > GRE_MAXUNIT) return (ENXIO); if (*unit < 0) { - r = rman_reserve_resource(greunits, 0, GRE_MAXUNIT, 1, + r = rman_reserve_resource(vnet->greunits, 0, GRE_MAXUNIT, 1, RF_ALLOCATED | RF_ACTIVE, NULL); if (r == NULL) return (ENOSPC); *unit = rman_get_start(r); } else { - r = rman_reserve_resource(greunits, *unit, *unit, 1, + r = rman_reserve_resource(vnet->greunits, *unit, *unit, 1, RF_ALLOCATED | RF_ACTIVE, NULL); if (r == NULL) return (EEXIST); @@ -211,12 +220,16 @@ return (0); } -static void +/*static*/ +void gre_clone_destroy(ifp) struct ifnet *ifp; { int err; struct gre_softc *sc = ifp->if_softc; + /*Boeing IDC copied from if_gif.c*/ + if (sc->g_vnet == NULL) + panic("gre_clone_destroy: NULL vnet from ifp."); #ifdef INET if (sc->encap != NULL) @@ -232,6 +245,37 @@ free(sc, M_GRE); } + +/*Boeing IDC*/ + +/* Initialize gif vars for a single vnet */ +int +gre_init(vnet) + struct vnet *vnet; +{ + int err=0; + + vnet->max_gre_nesting = MAX_GRE_NEST; + vnet->parallel_tunnels = 0; + vnet->greunits->rm_type = RMAN_ARRAY; + vnet->gifunits->rm_descr = "configurable if_gre units"; + err = rman_init(vnet->greunits); + if (err != 0) + return (err); + err = rman_manage_region(vnet->greunits, 0, GRE_MAXUNIT); + if (err != 0) { + printf("%s: greunits: rman_manage_region: Failed %d\n", + GRENAME, err); + rman_fini(vnet->greunits); + return (err); + } + LIST_INIT(&vnet->gre_softc_list); + return 0; +} + + + + /* * The output routine. Takes a packet and encapsulates it in the protocol * given by sc->g_proto. See also RFC 1701 and RFC 2004 @@ -247,12 +291,14 @@ u_char osrc; u_short etype = 0; struct mobile_h mob_h; + struct vnet *vnet; + vnet = ifp->if_vnet; /* * gre may cause infinite recursion calls when misconfigured. * We'll prevent this by introducing upper limit. */ - if (++(sc->called) > max_gre_nesting) { + if (++(sc->called) > vnet->max_gre_nesting) { printf("%s: gre_output: recursively called too many " "times(%d)\n", if_name(&sc->sc_if), sc->called); m_freem(m); @@ -780,31 +826,33 @@ switch (type) { case MOD_LOAD: - greunits->rm_type = RMAN_ARRAY; - greunits->rm_descr = "configurable if_gre units"; - err = rman_init(greunits); + LIST_FOREACH(vnet, &vnet_head, vnet_le) + { + vnet->max_gre_nesting = MAX_GRE_NEST; + vnet->greunits->rm_type = RMAN_ARRAY; + vnet->greunits->rm_descr = "configurable if_gre units"; + err = rman_init(vnet->greunits); if (err != 0) return (err); - err = rman_manage_region(greunits, 0, GRE_MAXUNIT); + err = rman_manage_region(vnet->greunits, 0, GRE_MAXUNIT); if (err != 0) { - printf("%s: greunits: rman_manage_region: Failed %d\n", - GRENAME, err); - rman_fini(greunits); - return (err); + printf("%s: greunits: rman_manage_region: Failed %d\n", + GRENAME, err); + rman_fini(vnet->greunits); + return (err); + } + greattach(vnet); } - - LIST_FOREACH(vnet, &vnet_head, vnet_le) - greattach(vnet); - break; case MOD_UNLOAD: if_clone_detach(&gre_cloner); - LIST_FOREACH(vnet, &vnet_head, vnet_le) + err = 0; + LIST_FOREACH(vnet, &vnet_head, vnet_le) { while (!LIST_EMPTY(&vnet->gre_softc_list)) gre_clone_destroy(&LIST_FIRST(&vnet->gre_softc_list)->sc_if); - - err = rman_fini(greunits); + err += rman_fini(vnet->greunits); + } if (err != 0) return (err); diff -urN sys/net/if_gre.h sys.CORE/net/if_gre.h --- sys/net/if_gre.h Wed Jan 31 15:57:05 2007 +++ sys.CORE/net/if_gre.h Wed Jan 31 16:02:43 2007 @@ -172,4 +172,7 @@ u_short gre_in_cksum(u_short *p, u_int len); #endif /* _KERNEL */ +/* Prototypes */ +int gre_init(struct vnet *); + #endif diff -urN sys/net/vnet.h sys.CORE/net/vnet.h --- sys/net/vnet.h Wed Jan 31 15:57:05 2007 +++ sys.CORE/net/vnet.h Wed Jan 31 16:02:43 2007 @@ -83,6 +83,15 @@ #include #include +/* IPsec support */ +#include +#include +#include +#include +/* gif support */ +#include +#include + #ifdef _KERNEL int vi_if_move(struct vi_req *, struct ifnet *, struct vimage *); @@ -131,6 +140,7 @@ TAILQ_HEAD(dadq_head, dadq); +/**/ struct vnet { LIST_ENTRY(vnet) vnet_le; /* linked list of all vnets */ @@ -172,7 +182,8 @@ struct ifnet loif; /* from net/if_loop.c */ struct ifnet vipa; /* from net/if_loop.c */ - struct gre_softc_head gre_softc_list; + /*Boeing IDC struct gre_softc_head gre_softc_list;*/ + LIST_HEAD(, gre_softc) gre_softc_list; LIST_HEAD(, gif_softc) gif_softc_list; /* NETINET */ @@ -370,6 +381,8 @@ struct udpstat udpstat; /* from udp_usrreq.c */ struct icmpstat icmpstat; /* from ip_icmp.c */ struct igmpstat igmpstat; /* from igmp.c */ + struct pfkeystat pfkeystat; /* from keysock.c */ + struct _keystat { u_long getspi_count; } keystat; u_int rsvpdebug; /* from ip_mroute.c */ u_int mrtdebug; @@ -571,6 +584,67 @@ struct ip_fib_heap_entry ip_fib_heap[33]; int ip_fib_heap_index; + +/* gif tunneling interface stuff */ + /* + * from net/if_gif.c + */ + struct rman gifunits[1]; + int max_gif_nesting; + int parallel_tunnels; + /* + * from net/if_gre.c + */ + struct rman greunits[1]; + int max_gre_nesting; +/* IPsec stuff */ +/* Do not use #ifdef IPSEC here, or problems will occur! */ + /* + * from netkey/key.c + */ + u_int key_spi_trycnt; + u_int32_t key_spi_minval; + u_int32_t key_spi_maxval; + u_int32_t policy_id; + u_int key_int_random; /*interval to initialize randseed,1(m)*/ + u_int key_larval_lifetime; /* interval to expire acquiring, 30(s)*/ + int key_blockacq_count; /* counter for blocking SADB_ACQUIRE.*/ + int key_blockacq_lifetime; /* lifetime for blocking SADB_ACQUIRE.*/ + int key_preferred_oldsa; /* preferred old sa rather than new sa.*/ + u_int32_t acq_seq; + int key_tick_init_random; + LIST_HEAD(_sptree, secpolicy) sptree[IPSEC_DIR_MAX]; /* SPD */ + LIST_HEAD(_sahtree, secashead) sahtree; /* SAD */ + LIST_HEAD(_regtree, secreg) regtree[SADB_SATYPE_MAX + 1]; /* regd list*/ + LIST_HEAD(_acqtree, secacq) acqtree; /* acquiring list */ + LIST_HEAD(_spacqtree, secspacq) spacqtree; /* SP acquiring list */ + struct key_cb key_cb; + + /* + * from netinet6/ipsec.c + */ + /* int ipsec_debug; stays in ipsec.c to avoid unnecessary passing + of vnet in simple functions that are printing */ + struct ipsecstat ipsecstat; + int ip4_ah_cleartos; + int ip4_ah_offsetmask; /* maybe IP_DF? */ + int ip4_ipsec_dfbit; /* DF bit on encap. 0: clear 1: set 2: copy */ + int ip4_esp_trans_deflev; + int ip4_esp_net_deflev; + int ip4_ah_trans_deflev; + int ip4_ah_net_deflev; + struct secpolicy ip4_def_policy; + int ip4_ipsec_ecn; /* ECN ignore(-1)/forbidden(0)/allowed(1) */ + int ip4_esp_randpad; + struct ipsecstat ipsec6stat; + int ip6_esp_trans_deflev; + int ip6_esp_net_deflev; + int ip6_ah_trans_deflev; + int ip6_ah_net_deflev; + struct secpolicy ip6_def_policy; + int ip6_ipsec_ecn; /* ECN ignore(-1)/forbidden(0)/allowed(1) */ + int ip6_esp_randpad; + }; /* @@ -827,7 +901,41 @@ #define v_rtq_reallyold6 offsetof(struct vnet, rtq_reallyold6) #define v_rtq_minreallyold6 offsetof(struct vnet, rtq_minreallyold6) #define v_rtq_toomany6 offsetof(struct vnet, rtq_toomany6) - +#define v_max_gif_nesting offsetof(struct vnet, max_gif_nesting) +#define v_parallel_tunnels offsetof(struct vnet, parallel_tunnels) +#define v_max_gre_nesting offsetof(struct vnet, max_gre_nesting) +#define v_key_debug_level offsetof(struct vnet, key_debug_level) +#define v_key_spi_trycnt offsetof(struct vnet, key_spi_trycnt) +#define v_key_spi_minval offsetof(struct vnet, key_spi_minval) +#define v_key_spi_maxval offsetof(struct vnet, key_spi_maxval) +#define v_policy_id offsetof(struct vnet, policy_id) +#define v_key_int_random offsetof(struct vnet, key_int_random) +#define v_key_larval_lifetime offsetof(struct vnet, key_larval_lifetime) +#define v_key_blockacq_count offsetof(struct vnet, key_blockacq_count) +#define v_key_blockacq_lifetime offsetof(struct vnet, key_blockacq_lifetime) +#define v_key_preferred_oldsa offsetof(struct vnet, key_preferred_oldsa) +#define v_acq_seq offsetof(struct vnet, acq_seq) +#define v_key_tick_init_random offsetof(struct vnet, key_tick_init_random) +#define v_key_cb offsetof(struct vnet, key_cb) +#define v_ipsecstat offsetof(struct vnet, ipsecstat) +#define v_ip4_ah_cleartos offsetof(struct vnet, ip4_ah_cleartos) +#define v_ip4_ah_offsetmask offsetof(struct vnet, ip4_ah_offsetmask) +#define v_ip4_ipsec_dfbit offsetof(struct vnet, ip4_ipsec_dfbit) +#define v_ip4_esp_trans_deflev offsetof(struct vnet, ip4_esp_trans_deflev) +#define v_ip4_esp_net_deflev offsetof(struct vnet, ip4_esp_net_deflev) +#define v_ip4_ah_trans_deflev offsetof(struct vnet, ip4_ah_trans_deflev) +#define v_ip4_ah_net_deflev offsetof(struct vnet, ip4_ah_net_deflev) +#define v_ip4_def_policy offsetof(struct vnet, ip4_def_policy) +#define v_ip4_ipsec_ecn offsetof(struct vnet, ip4_ipsec_ecn) +#define v_ip4_esp_randpad offsetof(struct vnet, ip4_esp_randpad) +#define v_ipsec6stat offsetof(struct vnet, ipsec6stat) +#define v_ip6_esp_trans_deflev offsetof(struct vnet, ip6_esp_trans_deflev) +#define v_ip6_esp_net_deflev offsetof(struct vnet, ip6_esp_net_deflev) +#define v_ip6_ah_trans_deflev offsetof(struct vnet, ip6_ah_trans_deflev) +#define v_ip6_ah_net_deflev offsetof(struct vnet, ip6_ah_net_deflev) +#define v_ip6_def_policy offsetof(struct vnet, ip6_def_policy) +#define v_ip6_ipsec_ecn offsetof(struct vnet, ip6_ipsec_ecn) +#define v_ip6_esp_randpad offsetof(struct vnet, ip6_esp_randpad) #endif _KERNEL diff -urN sys/netinet/ip_encap.c sys.CORE/netinet/ip_encap.c --- sys/netinet/ip_encap.c Wed Jan 31 15:57:05 2007 +++ sys.CORE/netinet/ip_encap.c Wed Jan 31 16:02:43 2007 @@ -151,6 +151,7 @@ match = NULL; matchprio = 0; + for (ep = LIST_FIRST(&vnet->encaptab); ep; ep = LIST_NEXT(ep, chain)) { if (ep->af != AF_INET) continue; @@ -228,7 +229,7 @@ const struct ip6protosw *psw; struct encaptab *ep, *match; int prio, matchprio; - struct vnet *vnet = m->m_pkthdr.rcvif->if_vnet; + struct vnet *vnet = m->m_pkthdr.rcvif->if_vnet; ip6 = mtod(m, struct ip6_hdr *); @@ -378,7 +379,7 @@ encap_attach_func(af, proto, func, psw, arg, vnet) int af; int proto; - int (*func) __P((const struct mbuf *, int, int, void *)); + int (*func) __P((const struct mbuf *, int, int, void *, struct vnet *)); const struct protosw *psw; void *arg; struct vnet *vnet; @@ -450,6 +451,8 @@ u_int8_t *r; int matchlen; + char *inetadd; + if (sp->sa_len > sizeof(s) || dp->sa_len > sizeof(d)) return 0; if (sp->sa_family != ep->af || dp->sa_family != ep->af) @@ -483,11 +486,24 @@ d.ss_len = dp->sa_len; d.ss_family = dp->sa_family; - if (bcmp(&s, &ep->src, ep->src.ss_len) == 0 && + if (bcmp(&s, &ep->src, ep->src.ss_len) == 0 && bcmp(&d, &ep->dst, ep->dst.ss_len) == 0) { return matchlen; - } else - return 0; + /*Boeing IDC MTUN IPv4 case*/ + } else if ((ep->src.ss_family == AF_INET) && + (IN_MULTICAST(ntohl(((struct sockaddr_in*)&ep->dst)->sin_addr.s_addr ))) && + (IN_MULTICAST(ntohl(((struct sockaddr_in*)sp)->sin_addr.s_addr ))) && + (bcmp(&s, &ep->dst, ep->src.ss_len) == 0)) { + return matchlen+1; + /*Boeing IDC MTUN IPv6 case*/ + } else if ((ep->src.ss_family == AF_INET6) && + (IN6_IS_ADDR_MULTICAST(&(((struct sockaddr_in6*)&ep->dst)->sin6_addr))) && + (IN6_IS_ADDR_MULTICAST(&(((struct sockaddr_in6*)sp)->sin6_addr))) && + (bcmp(&s, &ep->dst, ep->src.ss_len) == 0)) { + return matchlen+1; + } else { + return 0; + } } static void diff -urN sys/netinet/ip_encap.h sys.CORE/netinet/ip_encap.h --- sys/netinet/ip_encap.h Wed Jan 31 15:57:05 2007 +++ sys.CORE/netinet/ip_encap.h Wed Jan 31 16:02:43 2007 @@ -57,7 +57,7 @@ const struct sockaddr *, const struct protosw *, void *, struct vnet *); const struct encaptab *encap_attach_func(int, int, - int (*)(const struct mbuf *, int, int, void *), + int (*)(const struct mbuf *, int, int, void *, struct vnet *), const struct protosw *, void *, struct vnet *); int encap_detach(const struct encaptab *, struct vnet *); void *encap_getarg(struct mbuf *); diff -urN sys/netinet/ip_icmp.c sys.CORE/netinet/ip_icmp.c --- sys/netinet/ip_icmp.c Wed Jan 31 15:57:05 2007 +++ sys.CORE/netinet/ip_icmp.c Wed Jan 31 16:02:43 2007 @@ -600,7 +600,7 @@ (struct sockaddr *)&icmpgw, (struct rtentry **)0, vnet); pfctlinput(PRC_REDIRECT_HOST, (struct sockaddr *)&icmpsrc, vnet); #ifdef IPSEC - key_sa_routechange((struct sockaddr *)&icmpsrc); + key_sa_routechange((struct sockaddr *)&icmpsrc, vnet); #endif break; diff -urN sys/netinet/ip_input.c sys.CORE/netinet/ip_input.c --- sys/netinet/ip_input.c Wed Jan 31 15:57:05 2007 +++ sys.CORE/netinet/ip_input.c Wed Jan 31 16:02:43 2007 @@ -694,8 +694,8 @@ /* * Enforce inbound IPsec SPD. */ - if (ipsec4_in_reject(m, NULL)) { - ipsecstat.in_polvio++; + if (ipsec4_in_reject(m, NULL, vnet)) { + vnet->ipsecstat.in_polvio++; goto bad; } #endif /* IPSEC */ @@ -903,8 +903,8 @@ * code - like udp/tcp/raw ip. */ if ((inetsw[ip_protox[ip->ip_p]].pr_flags & PR_LASTHDR) != 0 && - ipsec4_in_reject(m, NULL)) { - ipsecstat.in_polvio++; + ipsec4_in_reject(m, NULL, vnet)) { + vnet->ipsecstat.in_polvio++; goto bad; } #endif @@ -1970,7 +1970,7 @@ sp = ipsec4_getpolicybyaddr(mcopy, IPSEC_DIR_OUTBOUND, IP_FORWARDING, - &ipsecerror); + &ipsecerror, vnet); if (sp == NULL) destifp = vnet->ipforward_rt.ro_rt->rt_ifp; @@ -1978,7 +1978,7 @@ /* count IPsec header size */ ipsechdr = ipsec4_hdrsiz(mcopy, IPSEC_DIR_OUTBOUND, - NULL); + NULL, vnet); /* * find the correct route for outer IPv4 @@ -2029,7 +2029,7 @@ /* count IPsec header size */ ipsechdr = ipsec4_hdrsiz(mcopy, IPSEC_DIR_OUTBOUND, - NULL); + NULL, vnet); /* * find the correct route for outer IPv4 diff -urN sys/netinet/ip_output.c sys.CORE/netinet/ip_output.c --- sys/netinet/ip_output.c Wed Jan 31 15:57:05 2007 +++ sys.CORE/netinet/ip_output.c Wed Jan 31 16:02:43 2007 @@ -320,14 +320,22 @@ * See if the caller provided any multicast options */ if (imo != NULL) { - ip->ip_ttl = imo->imo_multicast_ttl; + /* Boeing IDC to handle divert re-injection + * If you don't want the TTL to be modified then + * set the multicast_ttl socket option to zero. + */ + if (imo->imo_multicast_ttl != 0){ + ip->ip_ttl = imo->imo_multicast_ttl; + } if (imo->imo_multicast_vif != -1) ip->ip_src.s_addr = ip_mcast_src ? ip_mcast_src(imo->imo_multicast_vif, vnet) : INADDR_ANY; - } else - ip->ip_ttl = IP_DEFAULT_MULTICAST_TTL; + } else { + ip->ip_ttl = IP_DEFAULT_MULTICAST_TTL; + } + /* * Confirm that the outgoing interface supports multicast. */ @@ -459,12 +467,12 @@ #ifdef IPSEC /* get SP for this packet */ if (so == NULL) - sp = ipsec4_getpolicybyaddr(m, IPSEC_DIR_OUTBOUND, flags, &error); + sp = ipsec4_getpolicybyaddr(m, IPSEC_DIR_OUTBOUND, flags, &error, vnet); else sp = ipsec4_getpolicybysock(m, IPSEC_DIR_OUTBOUND, so, &error); if (sp == NULL) { - ipsecstat.out_inval++; + vnet->ipsecstat.out_inval++; goto bad; } @@ -476,7 +484,7 @@ /* * This packet is just discarded. */ - ipsecstat.out_polvio++; + vnet->ipsecstat.out_polvio++; goto bad; case IPSEC_POLICY_BYPASS: diff -urN sys/netinet/raw_ip.c sys.CORE/netinet/raw_ip.c --- sys/netinet/raw_ip.c Wed Jan 31 15:57:05 2007 +++ sys.CORE/netinet/raw_ip.c Wed Jan 31 16:02:43 2007 @@ -184,9 +184,9 @@ #ifdef IPSEC /* check AH/ESP integrity. */ - if (n && ipsec4_in_reject_so(n, last->inp_socket)) { + if (n && ipsec4_in_reject_so(n, last->inp_socket, vnet)) { m_freem(n); - ipsecstat.in_polvio++; + vnet->ipsecstat.in_polvio++; /* do not inject data to pcb */ } else #endif /*IPSEC*/ @@ -217,9 +217,9 @@ } #ifdef IPSEC /* check AH/ESP integrity. */ - if (last && ipsec4_in_reject_so(m, last->inp_socket)) { + if (last && ipsec4_in_reject_so(m, last->inp_socket, vnet)) { m_freem(m); - ipsecstat.in_polvio++; + vnet->ipsecstat.in_polvio++; vnet->ipstat.ips_delivered--; /* do not inject data to pcb */ } else diff -urN sys/netinet/tcp_input.c sys.CORE/netinet/tcp_input.c --- sys/netinet/tcp_input.c Wed Jan 31 15:57:05 2007 +++ sys.CORE/netinet/tcp_input.c Wed Jan 31 16:02:43 2007 @@ -580,13 +580,15 @@ #ifdef IPSEC if (isipv6) { - if (inp != NULL && ipsec6_in_reject_so(m, inp->inp_socket)) { - ipsec6stat.in_polvio++; +#ifdef INET6 + if (inp != NULL && ipsec6_in_reject_so(m, inp->inp_socket, vnet)) { + vnet->ipsec6stat.in_polvio++; goto drop; } +#endif } else { - if (inp != NULL && ipsec4_in_reject_so(m, inp->inp_socket)) { - ipsecstat.in_polvio++; + if (inp != NULL && ipsec4_in_reject_so(m, inp->inp_socket, vnet)) { + vnet->ipsecstat.in_polvio++; goto drop; } } diff -urN sys/netinet/tcp_subr.c sys.CORE/netinet/tcp_subr.c --- sys/netinet/tcp_subr.c Wed Jan 31 15:57:05 2007 +++ sys.CORE/netinet/tcp_subr.c Wed Jan 31 16:02:43 2007 @@ -1468,9 +1468,13 @@ struct ip6_hdr *ip6; #endif /* INET6 */ struct tcphdr *th; + struct vnet *vnet; if ((tp == NULL) || ((inp = tp->t_inpcb) == NULL)) return 0; + vnet = tp->t_vnet; + if (vnet == NULL) + panic("ipsec_hdrsiz_tcp: NULL vnet was passed."); MGETHDR(m, M_DONTWAIT, MT_DATA); if (!m) return 0; @@ -1482,7 +1486,7 @@ m->m_pkthdr.len = m->m_len = sizeof(struct ip6_hdr) + sizeof(struct tcphdr); tcp_fillheaders(tp, ip6, th); - hdrsiz = ipsec6_hdrsiz(m, IPSEC_DIR_OUTBOUND, inp); + hdrsiz = ipsec6_hdrsiz(m, IPSEC_DIR_OUTBOUND, inp, vnet); } else #endif /* INET6 */ { @@ -1490,7 +1494,7 @@ th = (struct tcphdr *)(ip + 1); m->m_pkthdr.len = m->m_len = sizeof(struct tcpiphdr); tcp_fillheaders(tp, ip, th); - hdrsiz = ipsec4_hdrsiz(m, IPSEC_DIR_OUTBOUND, inp); + hdrsiz = ipsec4_hdrsiz(m, IPSEC_DIR_OUTBOUND, inp, vnet); } m_free(m); diff -urN sys/netinet/udp_usrreq.c sys.CORE/netinet/udp_usrreq.c --- sys/netinet/udp_usrreq.c Wed Jan 31 15:57:05 2007 +++ sys.CORE/netinet/udp_usrreq.c Wed Jan 31 16:02:43 2007 @@ -325,8 +325,8 @@ #ifdef IPSEC /* check AH/ESP integrity. */ - if (ipsec4_in_reject_so(m, last->inp_socket)) - ipsecstat.in_polvio++; + if (ipsec4_in_reject_so(m, last->inp_socket, vnet)) + vnet->ipsecstat.in_polvio++; /* do not inject data to pcb */ else #endif /*IPSEC*/ @@ -365,8 +365,8 @@ } #ifdef IPSEC /* check AH/ESP integrity. */ - if (ipsec4_in_reject_so(m, last->inp_socket)) { - ipsecstat.in_polvio++; + if (ipsec4_in_reject_so(m, last->inp_socket, vnet)) { + vnet->ipsecstat.in_polvio++; goto bad; } #endif /*IPSEC*/ @@ -410,8 +410,8 @@ return; } #ifdef IPSEC - if (ipsec4_in_reject_so(m, inp->inp_socket)) { - ipsecstat.in_polvio++; + if (ipsec4_in_reject_so(m, inp->inp_socket, vnet)) { + vnet->ipsecstat.in_polvio++; goto bad; } #endif /*IPSEC*/ diff -urN sys/netinet6/ah.h sys.CORE/netinet6/ah.h --- sys/netinet6/ah.h Sat Apr 27 22:40:26 2002 +++ sys.CORE/netinet6/ah.h Wed Jan 31 16:02:43 2007 @@ -86,9 +86,9 @@ extern size_t ah_hdrsiz __P((struct ipsecrequest *)); extern void ah4_input __P((struct mbuf *, ...)); -extern int ah4_output __P((struct mbuf *, struct ipsecrequest *)); +extern int ah4_output __P((struct mbuf *, struct ipsecrequest *, struct vnet*)); extern int ah4_calccksum __P((struct mbuf *, caddr_t, size_t, - const struct ah_algorithm *, struct secasvar *)); + const struct ah_algorithm *, struct secasvar *, struct vnet *)); #endif /* _KERNEL */ #endif /* _NETINET6_AH_H_ */ diff -urN sys/netinet6/ah_core.c sys.CORE/netinet6/ah_core.c --- sys/netinet6/ah_core.c Sat Apr 27 22:40:26 2002 +++ sys.CORE/netinet6/ah_core.c Wed Jan 31 16:02:43 2007 @@ -52,6 +52,7 @@ #include #include +#include #include #include @@ -1181,12 +1182,13 @@ * Don't use m_copy(), it will try to share cluster mbuf by using refcnt. */ int -ah4_calccksum(m, ahdat, len, algo, sav) +ah4_calccksum(m, ahdat, len, algo, sav, vnet) struct mbuf *m; caddr_t ahdat; size_t len; const struct ah_algorithm *algo; struct secasvar *sav; + struct vnet *vnet; { int off; int hdrtype; @@ -1200,6 +1202,9 @@ if ((m->m_flags & M_PKTHDR) == 0) return EINVAL; + if (vnet == NULL) + panic("ah4_calccksum: NULL vnet was passed."); + ahseen = 0; hdrtype = -1; /* dummy, it is called IPPROTO_IP */ @@ -1231,9 +1236,9 @@ #endif iphdr.ip_ttl = 0; iphdr.ip_sum = htons(0); - if (ip4_ah_cleartos) + if (vnet->ip4_ah_cleartos) iphdr.ip_tos = 0; - iphdr.ip_off = htons(ntohs(iphdr.ip_off) & ip4_ah_offsetmask); + iphdr.ip_off = htons(ntohs(iphdr.ip_off) & vnet->ip4_ah_offsetmask); (algo->update)(&algos, (caddr_t)&iphdr, sizeof(struct ip)); if (hlen != sizeof(struct ip)) { diff -urN sys/netinet6/ah_input.c sys.CORE/netinet6/ah_input.c --- sys/netinet6/ah_input.c Wed Jan 31 15:57:05 2007 +++ sys.CORE/netinet6/ah_input.c Wed Jan 31 16:02:43 2007 @@ -87,6 +87,8 @@ #define KEYDEBUG(lev,arg) #endif +#include + #include #include @@ -120,19 +122,25 @@ int off, proto; va_list ap; size_t stripsiz = 0; + struct vnet *vnet; va_start(ap, m); off = va_arg(ap, int); proto = va_arg(ap, int); va_end(ap); + if (m == NULL || m->m_pkthdr.rcvif == NULL) + panic("ah4_input: cannot find vnet."); + vnet = m->m_pkthdr.rcvif->if_vnet; + if (vnet == NULL) + panic("ah4_input: NULL vnet passed."); #ifndef PULLDOWN_TEST if (m->m_len < off + sizeof(struct newah)) { m = m_pullup(m, off + sizeof(struct newah)); if (!m) { ipseclog((LOG_DEBUG, "IPv4 AH input: can't pullup;" "dropping the packet for simplicity\n")); - ipsecstat.in_inval++; + vnet->ipsecstat.in_inval++; goto fail; } } @@ -145,7 +153,7 @@ if (ah == NULL) { ipseclog((LOG_DEBUG, "IPv4 AH input: can't pullup;" "dropping the packet for simplicity\n")); - ipsecstat.in_inval++; + vnet->ipsecstat.in_inval++; goto fail; } #endif @@ -161,11 +169,11 @@ if ((sav = key_allocsa(AF_INET, (caddr_t)&ip->ip_src, (caddr_t)&ip->ip_dst, - IPPROTO_AH, spi)) == 0) { + IPPROTO_AH, spi, vnet)) == 0) { ipseclog((LOG_WARNING, "IPv4 AH input: no key association found for spi %u\n", (u_int32_t)ntohl(spi))); - ipsecstat.in_nosa++; + vnet->ipsecstat.in_nosa++; goto fail; } KEYDEBUG(KEYDEBUG_IPSEC_STAMP, @@ -175,7 +183,7 @@ ipseclog((LOG_DEBUG, "IPv4 AH input: non-mature/dying SA found for spi %u\n", (u_int32_t)ntohl(spi))); - ipsecstat.in_badspi++; + vnet->ipsecstat.in_badspi++; goto fail; } @@ -184,7 +192,7 @@ ipseclog((LOG_DEBUG, "IPv4 AH input: " "unsupported authentication algorithm for spi %u\n", (u_int32_t)ntohl(spi))); - ipsecstat.in_badspi++; + vnet->ipsecstat.in_badspi++; goto fail; } @@ -225,7 +233,7 @@ "(%lu, should be at least %lu): %s\n", (u_long)siz1, (u_long)siz, ipsec4_logpacketstr(ip, spi))); - ipsecstat.in_inval++; + vnet->ipsecstat.in_inval++; goto fail; } if ((ah->ah_len << 2) - sizoff != siz1) { @@ -233,7 +241,7 @@ "(%d should be %lu): %s\n", (ah->ah_len << 2) - sizoff, (u_long)siz1, ipsec4_logpacketstr(ip, spi))); - ipsecstat.in_inval++; + vnet->ipsecstat.in_inval++; goto fail; } @@ -242,7 +250,7 @@ m = m_pullup(m, off + sizeof(struct ah) + sizoff + siz1); if (!m) { ipseclog((LOG_DEBUG, "IPv4 AH input: can't pullup\n")); - ipsecstat.in_inval++; + vnet->ipsecstat.in_inval++; goto fail; } @@ -254,7 +262,7 @@ sizeof(struct ah) + sizoff + siz1); if (ah == NULL) { ipseclog((LOG_DEBUG, "IPv4 AH input: can't pullup\n")); - ipsecstat.in_inval++; + vnet->ipsecstat.in_inval++; goto fail; } #endif @@ -267,7 +275,7 @@ if (ipsec_chkreplay(ntohl(((struct newah *)ah)->ah_seq), sav)) ; /* okey */ else { - ipsecstat.in_ahreplay++; + vnet->ipsecstat.in_ahreplay++; ipseclog((LOG_WARNING, "replay packet in IPv4 AH input: %s %s\n", ipsec4_logpacketstr(ip, spi), ipsec_logsastr(sav))); @@ -283,7 +291,7 @@ if (!cksum) { ipseclog((LOG_DEBUG, "IPv4 AH input: " "couldn't alloc temporary region for cksum\n")); - ipsecstat.in_inval++; + vnet->ipsecstat.in_inval++; goto fail; } @@ -293,12 +301,12 @@ */ ip->ip_len = htons(ip->ip_len + hlen); ip->ip_off = htons(ip->ip_off); - if (ah4_calccksum(m, (caddr_t)cksum, siz1, algo, sav)) { + if (ah4_calccksum(m, (caddr_t)cksum, siz1, algo, sav, vnet)) { free(cksum, M_TEMP); - ipsecstat.in_inval++; + vnet->ipsecstat.in_inval++; goto fail; } - ipsecstat.in_ahhist[sav->alg_auth]++; + vnet->ipsecstat.in_ahhist[sav->alg_auth]++; /* * flip them back. */ @@ -321,7 +329,7 @@ "checksum mismatch in IPv4 AH input: %s %s\n", ipsec4_logpacketstr(ip, spi), ipsec_logsastr(sav))); free(cksum, M_TEMP); - ipsecstat.in_ahauthfail++; + vnet->ipsecstat.in_ahauthfail++; goto fail; } } @@ -374,12 +382,12 @@ ipseclog((LOG_DEBUG, "IPv4 AH input: authentication succeess\n")); #endif - ipsecstat.in_ahauthsucc++; + vnet->ipsecstat.in_ahauthsucc++; } else { ipseclog((LOG_WARNING, "authentication failed in IPv4 AH input: %s %s\n", ipsec4_logpacketstr(ip, spi), ipsec_logsastr(sav))); - ipsecstat.in_ahauthfail++; + vnet->ipsecstat.in_ahauthfail++; goto fail; } @@ -388,7 +396,7 @@ */ if ((sav->flags & SADB_X_EXT_OLD) == 0 && sav->replay) { if (ipsec_updatereplay(ntohl(((struct newah *)ah)->ah_seq), sav)) { - ipsecstat.in_ahreplay++; + vnet->ipsecstat.in_ahreplay++; goto fail; } } @@ -416,19 +424,19 @@ if (m->m_len < sizeof(*ip)) { m = m_pullup(m, sizeof(*ip)); if (!m) { - ipsecstat.in_inval++; + vnet->ipsecstat.in_inval++; goto fail; } } ip = mtod(m, struct ip *); /* ECN consideration. */ - ip_ecn_egress(ip4_ipsec_ecn, &tos, &ip->ip_tos); + ip_ecn_egress(vnet->ip4_ipsec_ecn, &tos, &ip->ip_tos); if (!key_checktunnelsanity(sav, AF_INET, (caddr_t)&ip->ip_src, (caddr_t)&ip->ip_dst)) { ipseclog((LOG_NOTICE, "ipsec tunnel address mismatch " "in IPv4 AH input: %s %s\n", ipsec4_logpacketstr(ip, spi), ipsec_logsastr(sav))); - ipsecstat.in_inval++; + vnet->ipsecstat.in_inval++; goto fail; } @@ -459,13 +467,13 @@ key_sa_recordxfer(sav, m); if (ipsec_addhist(m, IPPROTO_AH, spi) != 0 || ipsec_addhist(m, IPPROTO_IPV4, 0) != 0) { - ipsecstat.in_nomem++; + vnet->ipsecstat.in_nomem++; goto fail; } s = splimp(); if (IF_QFULL(&g_ipintrq)) { - ipsecstat.in_inval++; + vnet->ipsecstat.in_inval++; splx(s); goto fail; } @@ -521,7 +529,7 @@ if (m->m_len < sizeof(*ip)) { m = m_pullup(m, sizeof(*ip)); if (m == NULL) { - ipsecstat.in_inval++; + vnet->ipsecstat.in_inval++; goto fail; } } @@ -536,14 +544,14 @@ key_sa_recordxfer(sav, m); if (ipsec_addhist(m, IPPROTO_AH, spi) != 0) { - ipsecstat.in_nomem++; + vnet->ipsecstat.in_nomem++; goto fail; } if (nxt != IPPROTO_DONE) { if ((inetsw[ip_protox[nxt]].pr_flags & PR_LASTHDR) != 0 && - ipsec4_in_reject(m, NULL)) { - ipsecstat.in_polvio++; + ipsec4_in_reject(m, NULL, vnet)) { + vnet->ipsecstat.in_polvio++; goto fail; } (*inetsw[ip_protox[nxt]].pr_input)(m, off, nxt); @@ -557,7 +565,7 @@ printf("DP ah4_input call free SA:%p\n", sav)); key_freesav(sav); } - ipsecstat.in_success++; + vnet->ipsecstat.in_success++; return; fail: @@ -591,7 +599,12 @@ u_int16_t nxt; int s; size_t stripsiz = 0; + struct vnet *vnet; + if (m == NULL || m->m_pkthdr.rcvif == NULL) + panic("ah6_input: cannot find vnet."); + vnet = m->m_pkthdr.rcvif->if_vnet; + if (vnet == NULL) #ifndef PULLDOWN_TEST IP6_EXTHDR_CHECK(m, off, sizeof(struct ah), IPPROTO_DONE); ah = (struct ah *)(mtod(m, caddr_t) + off); @@ -599,7 +612,7 @@ IP6_EXTHDR_GET(ah, struct ah *, m, off, sizeof(struct newah)); if (ah == NULL) { ipseclog((LOG_DEBUG, "IPv6 AH input: can't pullup\n")); - ipsec6stat.in_inval++; + vnet->ipsec6stat.in_inval++; return IPPROTO_DONE; } #endif @@ -612,17 +625,17 @@ if (ntohs(ip6->ip6_plen) == 0) { ipseclog((LOG_ERR, "IPv6 AH input: " "AH with IPv6 jumbogram is not supported.\n")); - ipsec6stat.in_inval++; + vnet->ipsec6stat.in_inval++; goto fail; } if ((sav = key_allocsa(AF_INET6, (caddr_t)&ip6->ip6_src, (caddr_t)&ip6->ip6_dst, - IPPROTO_AH, spi)) == 0) { + IPPROTO_AH, spi, vnet)) == 0) { ipseclog((LOG_WARNING, "IPv6 AH input: no key association found for spi %u\n", (u_int32_t)ntohl(spi))); - ipsec6stat.in_nosa++; + vnet->ipsec6stat.in_nosa++; goto fail; } KEYDEBUG(KEYDEBUG_IPSEC_STAMP, @@ -632,7 +645,7 @@ ipseclog((LOG_DEBUG, "IPv6 AH input: non-mature/dying SA found for spi %u; ", (u_int32_t)ntohl(spi))); - ipsec6stat.in_badspi++; + vnet->ipsec6stat.in_badspi++; goto fail; } @@ -641,7 +654,7 @@ ipseclog((LOG_DEBUG, "IPv6 AH input: " "unsupported authentication algorithm for spi %u\n", (u_int32_t)ntohl(spi))); - ipsec6stat.in_badspi++; + vnet->ipsec6stat.in_badspi++; goto fail; } @@ -665,7 +678,7 @@ "(%lu, should be at least %lu): %s\n", (u_long)siz1, (u_long)siz, ipsec6_logpacketstr(ip6, spi))); - ipsec6stat.in_inval++; + vnet->ipsec6stat.in_inval++; goto fail; } if ((ah->ah_len << 2) - sizoff != siz1) { @@ -673,7 +686,7 @@ "(%d should be %lu): %s\n", (ah->ah_len << 2) - sizoff, (u_long)siz1, ipsec6_logpacketstr(ip6, spi))); - ipsec6stat.in_inval++; + vnet->ipsec6stat.in_inval++; goto fail; } #ifndef PULLDOWN_TEST @@ -683,7 +696,7 @@ sizeof(struct ah) + sizoff + siz1); if (ah == NULL) { ipseclog((LOG_NOTICE, "couldn't pullup gather IPv6 AH checksum part")); - ipsec6stat.in_inval++; + vnet->ipsec6stat.in_inval++; m = NULL; goto fail; } @@ -697,7 +710,7 @@ if (ipsec_chkreplay(ntohl(((struct newah *)ah)->ah_seq), sav)) ; /* okey */ else { - ipsec6stat.in_ahreplay++; + vnet->ipsec6stat.in_ahreplay++; ipseclog((LOG_WARNING, "replay packet in IPv6 AH input: %s %s\n", ipsec6_logpacketstr(ip6, spi), @@ -714,16 +727,16 @@ if (!cksum) { ipseclog((LOG_DEBUG, "IPv6 AH input: " "couldn't alloc temporary region for cksum\n")); - ipsec6stat.in_inval++; + vnet->ipsec6stat.in_inval++; goto fail; } if (ah6_calccksum(m, (caddr_t)cksum, siz1, algo, sav)) { free(cksum, M_TEMP); - ipsec6stat.in_inval++; + vnet->ipsec6stat.in_inval++; goto fail; } - ipsec6stat.in_ahhist[sav->alg_auth]++; + vnet->ipsec6stat.in_ahhist[sav->alg_auth]++; { caddr_t sumpos = NULL; @@ -741,7 +754,7 @@ "checksum mismatch in IPv6 AH input: %s %s\n", ipsec6_logpacketstr(ip6, spi), ipsec_logsastr(sav))); free(cksum, M_TEMP); - ipsec6stat.in_ahauthfail++; + vnet->ipsec6stat.in_ahauthfail++; goto fail; } } @@ -786,12 +799,12 @@ ipseclog((LOG_DEBUG, "IPv6 AH input: authentication succeess\n")); #endif - ipsec6stat.in_ahauthsucc++; + vnet->ipsec6stat.in_ahauthsucc++; } else { ipseclog((LOG_WARNING, "authentication failed in IPv6 AH input: %s %s\n", ipsec6_logpacketstr(ip6, spi), ipsec_logsastr(sav))); - ipsec6stat.in_ahauthfail++; + vnet->ipsec6stat.in_ahauthfail++; goto fail; } @@ -800,7 +813,7 @@ */ if ((sav->flags & SADB_X_EXT_OLD) == 0 && sav->replay) { if (ipsec_updatereplay(ntohl(((struct newah *)ah)->ah_seq), sav)) { - ipsec6stat.in_ahreplay++; + vnet->ipsec6stat.in_ahreplay++; goto fail; } } @@ -832,20 +845,20 @@ */ m = m_pullup(m, sizeof(*ip6)); if (!m) { - ipsec6stat.in_inval++; + vnet->ipsec6stat.in_inval++; goto fail; } } ip6 = mtod(m, struct ip6_hdr *); /* ECN consideration. */ - ip6_ecn_egress(ip6_ipsec_ecn, &flowinfo, &ip6->ip6_flow); + ip6_ecn_egress(vnet->ip6_ipsec_ecn, &flowinfo, &ip6->ip6_flow); if (!key_checktunnelsanity(sav, AF_INET6, (caddr_t)&ip6->ip6_src, (caddr_t)&ip6->ip6_dst)) { ipseclog((LOG_NOTICE, "ipsec tunnel address mismatch " "in IPv6 AH input: %s %s\n", ipsec6_logpacketstr(ip6, spi), ipsec_logsastr(sav))); - ipsec6stat.in_inval++; + vnet->ipsec6stat.in_inval++; goto fail; } @@ -861,17 +874,17 @@ key_sa_recordxfer(sav, m); if (ipsec_addhist(m, IPPROTO_AH, spi) != 0 || ipsec_addhist(m, IPPROTO_IPV6, 0) != 0) { - ipsec6stat.in_nomem++; + vnet->ipsec6stat.in_nomem++; goto fail; } s = splimp(); - if (IF_QFULL(&ip6intrq)) { - ipsec6stat.in_inval++; + if (IF_QFULL(&g_ip6intrq)) { + vnet->ipsec6stat.in_inval++; splx(s); goto fail; } - IF_ENQUEUE(&ip6intrq, m); + IF_ENQUEUE(&g_ip6intrq, m); m = NULL; schednetisr(NETISR_IPV6); /* can be skipped but to make sure */ splx(s); @@ -934,7 +947,7 @@ key_sa_recordxfer(sav, m); if (ipsec_addhist(m, IPPROTO_AH, spi) != 0) { - ipsec6stat.in_nomem++; + vnet->ipsec6stat.in_nomem++; goto fail; } } @@ -947,7 +960,7 @@ printf("DP ah6_input call free SA:%p\n", sav)); key_freesav(sav); } - ipsec6stat.in_success++; + vnet->ipsec6stat.in_success++; return nxt; fail: @@ -972,6 +985,7 @@ struct secasvar *sav; struct ip6_hdr *ip6; struct mbuf *m; + struct vnet *vnet = NULL; struct ip6ctlparam *ip6cp = NULL; int off; struct sockaddr_in6 *sa6_src, *sa6_dst; @@ -986,11 +1000,15 @@ if (d != NULL) { ip6cp = (struct ip6ctlparam *)d; m = ip6cp->ip6c_m; + if (m == NULL || m->m_pkthdr.rcvif == NULL) + panic("ah6_ctlinput: cannot find vnet."); + vnet = m->m_pkthdr.rcvif->if_vnet; ip6 = ip6cp->ip6c_ip6; off = ip6cp->ip6c_off; } else { m = NULL; ip6 = NULL; + off = 0; } if (ip6) { @@ -1025,7 +1043,7 @@ sav = key_allocsa(AF_INET6, (caddr_t)&sa6_src->sin6_addr, (caddr_t)&sa6_dst->sin6_addr, - IPPROTO_AH, ahp->ah_spi); + IPPROTO_AH, ahp->ah_spi, vnet); if (sav) { if (sav->state == SADB_SASTATE_MATURE || sav->state == SADB_SASTATE_DYING) @@ -1042,7 +1060,7 @@ * corresponding routing entry, or * - ignore the MTU change notification. */ - icmp6_mtudisc_update((struct ip6ctlparam *)d, valid); + icmp6_mtudisc_update((struct ip6ctlparam *)d, valid, vnet); } /* we normally notify single pcb here */ diff -urN sys/netinet6/ah_output.c sys.CORE/netinet6/ah_output.c --- sys/netinet6/ah_output.c Mon May 5 23:46:58 2003 +++ sys.CORE/netinet6/ah_output.c Wed Jan 31 16:02:43 2007 @@ -75,6 +75,7 @@ #include #include +#include #ifdef INET static struct in_addr *ah4_finaldst __P((struct mbuf *)); @@ -142,9 +143,10 @@ * the function does not modify m. */ int -ah4_output(m, isr) +ah4_output(m, isr, vnet) struct mbuf *m; struct ipsecrequest *isr; + struct vnet *vnet; { struct secasvar *sav = isr->sav; const struct ah_algorithm *algo; @@ -159,6 +161,8 @@ struct in_addr *finaldst; int error; + if (vnet == NULL) + panic("ah4_output: NULL vnet was passed."); /* sanity checks */ if ((sav->flags & SADB_X_EXT_OLD) == 0 && !sav->replay) { struct ip *ip; @@ -169,7 +173,7 @@ (u_int32_t)ntohl(ip->ip_src.s_addr), (u_int32_t)ntohl(ip->ip_dst.s_addr), (u_int32_t)ntohl(sav->spi))); - ipsecstat.out_inval++; + vnet->ipsecstat.out_inval++; m_freem(m); return EINVAL; } @@ -178,7 +182,7 @@ if (!algo) { ipseclog((LOG_ERR, "ah4_output: unsupported algorithm: " "SPI=%u\n", (u_int32_t)ntohl(sav->spi))); - ipsecstat.out_inval++; + vnet->ipsecstat.out_inval++; m_freem(m); return EINVAL; } @@ -260,7 +264,7 @@ ipseclog((LOG_WARNING, "replay counter overflowed. %s\n", ipsec_logsastr(sav))); - ipsecstat.out_inval++; + vnet->ipsecstat.out_inval++; m_freem(m); return EINVAL; } @@ -282,7 +286,7 @@ ip->ip_len = htons(ntohs(ip->ip_len) + ahlen); else { ipseclog((LOG_ERR, "IPv4 AH output: size exceeds limit\n")); - ipsecstat.out_inval++; + vnet->ipsecstat.out_inval++; m_freem(m); return EMSGSIZE; } @@ -304,13 +308,13 @@ * calcurate the checksum, based on security association * and the algorithm specified. */ - error = ah4_calccksum(m, (caddr_t)ahsumpos, plen, algo, sav); + error = ah4_calccksum(m, (caddr_t)ahsumpos, plen, algo, sav, vnet); if (error) { ipseclog((LOG_ERR, "error after ah4_calccksum, called from ah4_output")); m_freem(m); m = NULL; - ipsecstat.out_inval++; + vnet->ipsecstat.out_inval++; return error; } @@ -318,8 +322,8 @@ ip = mtod(m, struct ip *); /* just to make sure */ ip->ip_dst.s_addr = dst.s_addr; } - ipsecstat.out_success++; - ipsecstat.out_ahhist[sav->alg_auth]++; + vnet->ipsecstat.out_success++; + vnet->ipsecstat.out_ahhist[sav->alg_auth]++; key_sa_recordxfer(sav, m); return 0; @@ -371,6 +375,11 @@ int error = 0; int ahlen; struct ip6_hdr *ip6; + struct vnet *vnet; + + if (m == NULL || m->m_pkthdr.rcvif == NULL) + panic("ah6_output: unable to find vnet."); + vnet = m->m_pkthdr.rcvif->if_vnet; if (m->m_len < sizeof(struct ip6_hdr)) { ipseclog((LOG_DEBUG, "ah6_output: first mbuf too short\n")); @@ -422,7 +431,7 @@ ipseclog((LOG_DEBUG, "ah6_output: internal error: " "sav->replay is null: SPI=%u\n", (u_int32_t)ntohl(sav->spi))); - ipsec6stat.out_inval++; + vnet->ipsec6stat.out_inval++; m_freem(m); return EINVAL; } @@ -431,7 +440,7 @@ if (!algo) { ipseclog((LOG_ERR, "ah6_output: unsupported algorithm: " "SPI=%u\n", (u_int32_t)ntohl(sav->spi))); - ipsec6stat.out_inval++; + vnet->ipsec6stat.out_inval++; m_freem(m); return EINVAL; } @@ -467,7 +476,7 @@ ipseclog((LOG_WARNING, "replay counter overflowed. %s\n", ipsec_logsastr(sav))); - ipsec6stat.out_inval++; + vnet->ipsec6stat.out_inval++; m_freem(m); return EINVAL; } @@ -487,13 +496,13 @@ */ error = ah6_calccksum(m, (caddr_t)ahsumpos, plen, algo, sav); if (error) { - ipsec6stat.out_inval++; + vnet->ipsec6stat.out_inval++; m_freem(m); } else { - ipsec6stat.out_success++; + vnet->ipsec6stat.out_success++; key_sa_recordxfer(sav, m); } - ipsec6stat.out_ahhist[sav->alg_auth]++; + vnet->ipsec6stat.out_ahhist[sav->alg_auth]++; return(error); } diff -urN sys/netinet6/esp.h sys.CORE/netinet6/esp.h --- sys/netinet6/esp.h Sat Apr 27 22:40:26 2002 +++ sys.CORE/netinet6/esp.h Wed Jan 31 16:02:43 2007 @@ -97,7 +97,8 @@ extern int esp_max_ivlen __P((void)); /* crypt routines */ -extern int esp4_output __P((struct mbuf *, struct ipsecrequest *)); +extern int esp4_output __P((struct mbuf *, struct ipsecrequest *, + struct vnet *vnet)); extern void esp4_input __P((struct mbuf *, ...)); extern size_t esp_hdrsiz __P((struct ipsecrequest *)); diff -urN sys/netinet6/esp6.h sys.CORE/netinet6/esp6.h --- sys/netinet6/esp6.h Tue Jul 3 04:01:49 2001 +++ sys.CORE/netinet6/esp6.h Wed Jan 31 16:02:43 2007 @@ -39,10 +39,10 @@ #ifdef _KERNEL extern int esp6_output __P((struct mbuf *, u_char *, struct mbuf *, - struct ipsecrequest *)); + struct ipsecrequest *, struct vnet *)); extern int esp6_input __P((struct mbuf **, int *, int)); -extern void esp6_ctlinput __P((int, struct sockaddr *, void *)); +extern void esp6_ctlinput __P((int, struct sockaddr *, void *, struct vnet *)); #endif /*_KERNEL*/ #endif /*_NETINET6_ESP6_H_*/ diff -urN sys/netinet6/esp_input.c sys.CORE/netinet6/esp_input.c --- sys/netinet6/esp_input.c Fri Nov 28 06:52:52 2003 +++ sys.CORE/netinet6/esp_input.c Wed Jan 31 16:02:43 2007 @@ -89,6 +89,7 @@ #include #include +#include #define IPLEN_FLIPPED @@ -123,17 +124,21 @@ int s; va_list ap; int off, proto; + struct vnet *vnet; va_start(ap, m); off = va_arg(ap, int); proto = va_arg(ap, int); va_end(ap); + if (m == NULL || m->m_pkthdr.rcvif == NULL) + panic("esp4_input: cannot find vnet."); + vnet = m->m_pkthdr.rcvif->if_vnet; /* sanity check for alignment. */ if (off % 4 != 0 || m->m_pkthdr.len % 4 != 0) { ipseclog((LOG_ERR, "IPv4 ESP input: packet alignment problem " "(off=%d, pktlen=%d)\n", off, m->m_pkthdr.len)); - ipsecstat.in_inval++; + vnet->ipsecstat.in_inval++; goto bad; } @@ -142,7 +147,7 @@ if (!m) { ipseclog((LOG_DEBUG, "IPv4 ESP input: can't pullup in esp4_input\n")); - ipsecstat.in_inval++; + vnet->ipsecstat.in_inval++; goto bad; } } @@ -160,11 +165,11 @@ if ((sav = key_allocsa(AF_INET, (caddr_t)&ip->ip_src, (caddr_t)&ip->ip_dst, - IPPROTO_ESP, spi)) == 0) { + IPPROTO_ESP, spi, vnet)) == 0) { ipseclog((LOG_WARNING, "IPv4 ESP input: no key association found for spi %u\n", (u_int32_t)ntohl(spi))); - ipsecstat.in_nosa++; + vnet->ipsecstat.in_nosa++; goto bad; } KEYDEBUG(KEYDEBUG_IPSEC_STAMP, @@ -174,7 +179,7 @@ ipseclog((LOG_DEBUG, "IPv4 ESP input: non-mature/dying SA found for spi %u\n", (u_int32_t)ntohl(spi))); - ipsecstat.in_badspi++; + vnet->ipsecstat.in_badspi++; goto bad; } algo = esp_algorithm_lookup(sav->alg_enc); @@ -182,7 +187,7 @@ ipseclog((LOG_DEBUG, "IPv4 ESP input: " "unsupported encryption algorithm for spi %u\n", (u_int32_t)ntohl(spi))); - ipsecstat.in_badspi++; + vnet->ipsecstat.in_badspi++; goto bad; } @@ -191,7 +196,7 @@ if (ivlen < 0) { ipseclog((LOG_ERR, "inproper ivlen in IPv4 ESP input: %s %s\n", ipsec4_logpacketstr(ip, spi), ipsec_logsastr(sav))); - ipsecstat.in_inval++; + vnet->ipsecstat.in_inval++; goto bad; } @@ -209,7 +214,7 @@ if (ipsec_chkreplay(ntohl(((struct newesp *)esp)->esp_seq), sav)) ; /* okey */ else { - ipsecstat.in_espreplay++; + vnet->ipsecstat.in_espreplay++; ipseclog((LOG_WARNING, "replay packet in IPv4 ESP input: %s %s\n", ipsec4_logpacketstr(ip, spi), ipsec_logsastr(sav))); @@ -228,14 +233,14 @@ goto noreplaycheck; siz = (((*sumalgo->sumsiz)(sav) + 3) & ~(4 - 1)); if (m->m_pkthdr.len < off + ESPMAXLEN + siz) { - ipsecstat.in_inval++; + vnet->ipsecstat.in_inval++; goto bad; } if (AH_MAXSUMSIZE < siz) { ipseclog((LOG_DEBUG, "internal error: AH_MAXSUMSIZE must be larger than %lu\n", (u_long)siz)); - ipsecstat.in_inval++; + vnet->ipsecstat.in_inval++; goto bad; } @@ -244,14 +249,14 @@ if (esp_auth(m, off, m->m_pkthdr.len - off - siz, sav, sum)) { ipseclog((LOG_WARNING, "auth fail in IPv4 ESP input: %s %s\n", ipsec4_logpacketstr(ip, spi), ipsec_logsastr(sav))); - ipsecstat.in_espauthfail++; + vnet->ipsecstat.in_espauthfail++; goto bad; } if (bcmp(sum0, sum, siz) != 0) { ipseclog((LOG_WARNING, "auth fail in IPv4 ESP input: %s %s\n", ipsec4_logpacketstr(ip, spi), ipsec_logsastr(sav))); - ipsecstat.in_espauthfail++; + vnet->ipsecstat.in_espauthfail++; goto bad; } @@ -264,7 +269,7 @@ ip->ip_len = htons(ntohs(ip->ip_len) - siz); #endif m->m_flags |= M_AUTHIPDGM; - ipsecstat.in_espauthsucc++; + vnet->ipsecstat.in_espauthsucc++; } /* @@ -272,7 +277,7 @@ */ if ((sav->flags & SADB_X_EXT_OLD) == 0 && sav->replay) { if (ipsec_updatereplay(ntohl(((struct newesp *)esp)->esp_seq), sav)) { - ipsecstat.in_espreplay++; + vnet->ipsecstat.in_espreplay++; goto bad; } } @@ -294,7 +299,7 @@ if (m->m_pkthdr.len < off + esplen + ivlen + sizeof(esptail)) { ipseclog((LOG_WARNING, "IPv4 ESP input: packet too short\n")); - ipsecstat.in_inval++; + vnet->ipsecstat.in_inval++; goto bad; } @@ -303,7 +308,7 @@ if (!m) { ipseclog((LOG_DEBUG, "IPv4 ESP input: can't pullup in esp4_input\n")); - ipsecstat.in_inval++; + vnet->ipsecstat.in_inval++; goto bad; } } @@ -312,7 +317,7 @@ * pre-compute and cache intermediate key */ if (esp_schedule(algo, sav) != 0) { - ipsecstat.in_inval++; + vnet->ipsecstat.in_inval++; goto bad; } @@ -326,10 +331,10 @@ m = NULL; ipseclog((LOG_ERR, "decrypt fail in IPv4 ESP input: %s\n", ipsec_logsastr(sav))); - ipsecstat.in_inval++; + vnet->ipsecstat.in_inval++; goto bad; } - ipsecstat.in_esphist[sav->alg_enc]++; + vnet->ipsecstat.in_esphist[sav->alg_enc]++; m->m_flags |= M_DECRYPTED; @@ -346,7 +351,7 @@ ipseclog((LOG_WARNING, "bad pad length in IPv4 ESP input: %s %s\n", ipsec4_logpacketstr(ip, spi), ipsec_logsastr(sav))); - ipsecstat.in_inval++; + vnet->ipsecstat.in_inval++; goto bad; } @@ -375,36 +380,36 @@ if (m->m_len < sizeof(*ip)) { m = m_pullup(m, sizeof(*ip)); if (!m) { - ipsecstat.in_inval++; + vnet->ipsecstat.in_inval++; goto bad; } } ip = mtod(m, struct ip *); /* ECN consideration. */ - ip_ecn_egress(ip4_ipsec_ecn, &tos, &ip->ip_tos); + ip_ecn_egress(vnet->ip4_ipsec_ecn, &tos, &ip->ip_tos); if (!key_checktunnelsanity(sav, AF_INET, (caddr_t)&ip->ip_src, (caddr_t)&ip->ip_dst)) { ipseclog((LOG_ERR, "ipsec tunnel address mismatch " "in IPv4 ESP input: %s %s\n", ipsec4_logpacketstr(ip, spi), ipsec_logsastr(sav))); - ipsecstat.in_inval++; + vnet->ipsecstat.in_inval++; goto bad; } key_sa_recordxfer(sav, m); if (ipsec_addhist(m, IPPROTO_ESP, spi) != 0 || ipsec_addhist(m, IPPROTO_IPV4, 0) != 0) { - ipsecstat.in_nomem++; + vnet->ipsecstat.in_nomem++; goto bad; } s = splimp(); - if (IF_QFULL(&ipintrq)) { - ipsecstat.in_inval++; + if (IF_QFULL(&g_ipintrq)) { + vnet->ipsecstat.in_inval++; splx(s); goto bad; } - IF_ENQUEUE(&ipintrq, m); + IF_ENQUEUE(&g_ipintrq, m); m = NULL; schednetisr(NETISR_IP); /* can be skipped but to make sure */ splx(s); @@ -435,14 +440,14 @@ key_sa_recordxfer(sav, m); if (ipsec_addhist(m, IPPROTO_ESP, spi) != 0) { - ipsecstat.in_nomem++; + vnet->ipsecstat.in_nomem++; goto bad; } if (nxt != IPPROTO_DONE) { if ((inetsw[ip_protox[nxt]].pr_flags & PR_LASTHDR) != 0 && - ipsec4_in_reject(m, NULL)) { - ipsecstat.in_polvio++; + ipsec4_in_reject(m, NULL, vnet)) { + vnet->ipsecstat.in_polvio++; goto bad; } (*inetsw[ip_protox[nxt]].pr_input)(m, off, nxt); @@ -456,7 +461,7 @@ printf("DP esp4_input call free SA:%p\n", sav)); key_freesav(sav); } - ipsecstat.in_success++; + vnet->ipsecstat.in_success++; return; bad: @@ -478,6 +483,7 @@ int *offp, proto; { struct mbuf *m = *mp; + struct vnet *vnet; int off = *offp; struct ip6_hdr *ip6; struct esp *esp; @@ -491,11 +497,14 @@ size_t esplen; int s; + if (m == NULL || m->m_pkthdr.rcvif == NULL) + panic("esp6_input: cannot find vnet."); + vnet = m->m_pkthdr.rcvif->if_vnet; /* sanity check for alignment. */ if (off % 4 != 0 || m->m_pkthdr.len % 4 != 0) { ipseclog((LOG_ERR, "IPv6 ESP input: packet alignment problem " "(off=%d, pktlen=%d)\n", off, m->m_pkthdr.len)); - ipsec6stat.in_inval++; + vnet->ipsec6stat.in_inval++; goto bad; } @@ -505,7 +514,7 @@ #else IP6_EXTHDR_GET(esp, struct esp *, m, off, ESPMAXLEN); if (esp == NULL) { - ipsec6stat.in_inval++; + vnet->ipsec6stat.in_inval++; return IPPROTO_DONE; } #endif @@ -514,7 +523,7 @@ if (ntohs(ip6->ip6_plen) == 0) { ipseclog((LOG_ERR, "IPv6 ESP input: " "ESP with IPv6 jumbogram is not supported.\n")); - ipsec6stat.in_inval++; + vnet->ipsec6stat.in_inval++; goto bad; } @@ -523,11 +532,11 @@ if ((sav = key_allocsa(AF_INET6, (caddr_t)&ip6->ip6_src, (caddr_t)&ip6->ip6_dst, - IPPROTO_ESP, spi)) == 0) { + IPPROTO_ESP, spi, vnet)) == 0) { ipseclog((LOG_WARNING, "IPv6 ESP input: no key association found for spi %u\n", (u_int32_t)ntohl(spi))); - ipsec6stat.in_nosa++; + vnet->ipsec6stat.in_nosa++; goto bad; } KEYDEBUG(KEYDEBUG_IPSEC_STAMP, @@ -537,7 +546,7 @@ ipseclog((LOG_DEBUG, "IPv6 ESP input: non-mature/dying SA found for spi %u\n", (u_int32_t)ntohl(spi))); - ipsec6stat.in_badspi++; + vnet->ipsec6stat.in_badspi++; goto bad; } algo = esp_algorithm_lookup(sav->alg_enc); @@ -545,7 +554,7 @@ ipseclog((LOG_DEBUG, "IPv6 ESP input: " "unsupported encryption algorithm for spi %u\n", (u_int32_t)ntohl(spi))); - ipsec6stat.in_badspi++; + vnet->ipsec6stat.in_badspi++; goto bad; } @@ -554,7 +563,7 @@ if (ivlen < 0) { ipseclog((LOG_ERR, "inproper ivlen in IPv6 ESP input: %s %s\n", ipsec6_logpacketstr(ip6, spi), ipsec_logsastr(sav))); - ipsec6stat.in_badspi++; + vnet->ipsec6stat.in_badspi++; goto bad; } @@ -572,7 +581,7 @@ if (ipsec_chkreplay(ntohl(((struct newesp *)esp)->esp_seq), sav)) ; /* okey */ else { - ipsec6stat.in_espreplay++; + vnet->ipsec6stat.in_espreplay++; ipseclog((LOG_WARNING, "replay packet in IPv6 ESP input: %s %s\n", ipsec6_logpacketstr(ip6, spi), ipsec_logsastr(sav))); @@ -591,14 +600,14 @@ goto noreplaycheck; siz = (((*sumalgo->sumsiz)(sav) + 3) & ~(4 - 1)); if (m->m_pkthdr.len < off + ESPMAXLEN + siz) { - ipsec6stat.in_inval++; + vnet->ipsec6stat.in_inval++; goto bad; } if (AH_MAXSUMSIZE < siz) { ipseclog((LOG_DEBUG, "internal error: AH_MAXSUMSIZE must be larger than %lu\n", (u_long)siz)); - ipsec6stat.in_inval++; + vnet->ipsec6stat.in_inval++; goto bad; } @@ -607,14 +616,14 @@ if (esp_auth(m, off, m->m_pkthdr.len - off - siz, sav, sum)) { ipseclog((LOG_WARNING, "auth fail in IPv6 ESP input: %s %s\n", ipsec6_logpacketstr(ip6, spi), ipsec_logsastr(sav))); - ipsec6stat.in_espauthfail++; + vnet->ipsec6stat.in_espauthfail++; goto bad; } if (bcmp(sum0, sum, siz) != 0) { ipseclog((LOG_WARNING, "auth fail in IPv6 ESP input: %s %s\n", ipsec6_logpacketstr(ip6, spi), ipsec_logsastr(sav))); - ipsec6stat.in_espauthfail++; + vnet->ipsec6stat.in_espauthfail++; goto bad; } @@ -624,7 +633,7 @@ ip6->ip6_plen = htons(ntohs(ip6->ip6_plen) - siz); m->m_flags |= M_AUTHIPDGM; - ipsec6stat.in_espauthsucc++; + vnet->ipsec6stat.in_espauthsucc++; } /* @@ -632,7 +641,7 @@ */ if ((sav->flags & SADB_X_EXT_OLD) == 0 && sav->replay) { if (ipsec_updatereplay(ntohl(((struct newesp *)esp)->esp_seq), sav)) { - ipsec6stat.in_espreplay++; + vnet->ipsec6stat.in_espreplay++; goto bad; } } @@ -654,7 +663,7 @@ if (m->m_pkthdr.len < off + esplen + ivlen + sizeof(esptail)) { ipseclog((LOG_WARNING, "IPv6 ESP input: packet too short\n")); - ipsec6stat.in_inval++; + vnet->ipsec6stat.in_inval++; goto bad; } @@ -663,7 +672,7 @@ #else IP6_EXTHDR_GET(esp, struct esp *, m, off, esplen + ivlen); if (esp == NULL) { - ipsec6stat.in_inval++; + vnet->ipsec6stat.in_inval++; m = NULL; goto bad; } @@ -674,7 +683,7 @@ * pre-compute and cache intermediate key */ if (esp_schedule(algo, sav) != 0) { - ipsec6stat.in_inval++; + vnet->ipsec6stat.in_inval++; goto bad; } @@ -688,10 +697,10 @@ m = NULL; ipseclog((LOG_ERR, "decrypt fail in IPv6 ESP input: %s\n", ipsec_logsastr(sav))); - ipsec6stat.in_inval++; + vnet->ipsec6stat.in_inval++; goto bad; } - ipsec6stat.in_esphist[sav->alg_enc]++; + vnet->ipsec6stat.in_esphist[sav->alg_enc]++; m->m_flags |= M_DECRYPTED; @@ -708,7 +717,7 @@ ipseclog((LOG_WARNING, "bad pad length in IPv6 ESP input: %s %s\n", ipsec6_logpacketstr(ip6, spi), ipsec_logsastr(sav))); - ipsec6stat.in_inval++; + vnet->ipsec6stat.in_inval++; goto bad; } @@ -740,37 +749,37 @@ #endif m = m_pullup(m, sizeof(*ip6)); if (!m) { - ipsec6stat.in_inval++; + vnet->ipsec6stat.in_inval++; goto bad; } } ip6 = mtod(m, struct ip6_hdr *); /* ECN consideration. */ - ip6_ecn_egress(ip6_ipsec_ecn, &flowinfo, &ip6->ip6_flow); + ip6_ecn_egress(vnet->ip6_ipsec_ecn, &flowinfo, &ip6->ip6_flow); if (!key_checktunnelsanity(sav, AF_INET6, (caddr_t)&ip6->ip6_src, (caddr_t)&ip6->ip6_dst)) { ipseclog((LOG_ERR, "ipsec tunnel address mismatch " "in IPv6 ESP input: %s %s\n", ipsec6_logpacketstr(ip6, spi), ipsec_logsastr(sav))); - ipsec6stat.in_inval++; + vnet->ipsec6stat.in_inval++; goto bad; } key_sa_recordxfer(sav, m); if (ipsec_addhist(m, IPPROTO_ESP, spi) != 0 || ipsec_addhist(m, IPPROTO_IPV6, 0) != 0) { - ipsec6stat.in_nomem++; + vnet->ipsec6stat.in_nomem++; goto bad; } s = splimp(); - if (IF_QFULL(&ip6intrq)) { - ipsec6stat.in_inval++; + if (IF_QFULL(&g_ip6intrq)) { + vnet->ipsec6stat.in_inval++; splx(s); goto bad; } - IF_ENQUEUE(&ip6intrq, m); + IF_ENQUEUE(&g_ip6intrq, m); m = NULL; schednetisr(NETISR_IPV6); /* can be skipped but to make sure */ splx(s); @@ -864,7 +873,7 @@ key_sa_recordxfer(sav, m); if (ipsec_addhist(m, IPPROTO_ESP, spi) != 0) { - ipsec6stat.in_nomem++; + vnet->ipsec6stat.in_nomem++; goto bad; } } @@ -877,7 +886,7 @@ printf("DP esp6_input call free SA:%p\n", sav)); key_freesav(sav); } - ipsec6stat.in_success++; + vnet->ipsec6stat.in_success++; return nxt; bad: @@ -892,10 +901,11 @@ } void -esp6_ctlinput(cmd, sa, d) +esp6_ctlinput(cmd, sa, d, vnet) int cmd; struct sockaddr *sa; void *d; + struct vnet *vnet; { const struct newesp *espp; struct newesp esp; @@ -906,6 +916,8 @@ int off; struct sockaddr_in6 *sa6_src, *sa6_dst; + if (vnet == NULL) + panic("esp6_ctlinput: NULL vnet was passed."); if (sa->sa_family != AF_INET6 || sa->sa_len != sizeof(struct sockaddr_in6)) return; @@ -921,6 +933,7 @@ } else { m = NULL; ip6 = NULL; + off = 0; } if (ip6) { @@ -939,7 +952,7 @@ */ bzero(&ip6cp1, sizeof(ip6cp1)); ip6cp1.ip6c_src = ip6cp->ip6c_src; - pfctlinput2(cmd, sa, (void *)&ip6cp1); + pfctlinput2(cmd, sa, (void *)&ip6cp1, vnet); /* * Then go to special cases that need ESP header information. @@ -973,7 +986,7 @@ sav = key_allocsa(AF_INET6, (caddr_t)&sa6_src->sin6_addr, (caddr_t)&sa6_dst->sin6_addr, - IPPROTO_ESP, espp->esp_spi); + IPPROTO_ESP, espp->esp_spi, vnet); if (sav) { if (sav->state == SADB_SASTATE_MATURE || sav->state == SADB_SASTATE_DYING) @@ -990,7 +1003,7 @@ * corresponding routing entry, or * - ignore the MTU change notification. */ - icmp6_mtudisc_update((struct ip6ctlparam *)d, valid); + icmp6_mtudisc_update((struct ip6ctlparam *)d, valid, vnet); } } else { /* we normally notify any pcb here */ diff -urN sys/netinet6/esp_output.c sys.CORE/netinet6/esp_output.c --- sys/netinet6/esp_output.c Fri Nov 28 06:54:26 2003 +++ sys.CORE/netinet6/esp_output.c Wed Jan 31 16:02:43 2007 @@ -78,9 +78,10 @@ #include #include +#include static int esp_output __P((struct mbuf *, u_char *, struct mbuf *, - struct ipsecrequest *, int)); + struct ipsecrequest *, int, struct vnet *)); /* * compute ESP header size. @@ -174,12 +175,13 @@ * <-----------------> espoff */ static int -esp_output(m, nexthdrp, md, isr, af) +esp_output(m, nexthdrp, md, isr, af, vnet) struct mbuf *m; u_char *nexthdrp; struct mbuf *md; struct ipsecrequest *isr; int af; + struct vnet *vnet; { struct mbuf *n; struct mbuf *mprev; @@ -197,17 +199,19 @@ int error = 0; struct ipsecstat *stat; + if (vnet == NULL) + panic("esp6_output: NULL vnet was passed."); switch (af) { #ifdef INET case AF_INET: afnumber = 4; - stat = &ipsecstat; + stat = &vnet->ipsecstat; break; #endif #ifdef INET6 case AF_INET6: afnumber = 6; - stat = &ipsec6stat; + stat = &vnet->ipsec6stat; break; #endif default: @@ -229,7 +233,7 @@ (u_int32_t)ntohl(ip->ip_src.s_addr), (u_int32_t)ntohl(ip->ip_dst.s_addr), (u_int32_t)ntohl(sav->spi))); - ipsecstat.out_inval++; + vnet->ipsecstat.out_inval++; break; } #endif /* INET */ @@ -238,7 +242,7 @@ ipseclog((LOG_DEBUG, "esp6_output: internal error: " "sav->replay is null: SPI=%u\n", (u_int32_t)ntohl(sav->spi))); - ipsec6stat.out_inval++; + vnet->ipsec6stat.out_inval++; break; #endif /* INET6 */ default: @@ -368,7 +372,7 @@ else { ipseclog((LOG_ERR, "IPv4 ESP output: size exceeds limit\n")); - ipsecstat.out_inval++; + vnet->ipsecstat.out_inval++; m_freem(m); error = EMSGSIZE; goto fail; @@ -435,12 +439,12 @@ switch (af) { #ifdef INET case AF_INET: - randpadmax = ip4_esp_randpad; + randpadmax = vnet->ip4_esp_randpad; break; #endif #ifdef INET6 case AF_INET6: - randpadmax = ip6_esp_randpad; + randpadmax = vnet->ip6_esp_randpad; break; #endif default: @@ -539,7 +543,7 @@ else { ipseclog((LOG_ERR, "IPv4 ESP output: size exceeds limit\n")); - ipsecstat.out_inval++; + vnet->ipsecstat.out_inval++; m_freem(m); error = EMSGSIZE; goto fail; @@ -651,7 +655,7 @@ else { ipseclog((LOG_ERR, "IPv4 ESP output: size exceeds limit\n")); - ipsecstat.out_inval++; + vnet->ipsecstat.out_inval++; m_freem(m); error = EMSGSIZE; goto fail; @@ -686,9 +690,10 @@ #ifdef INET int -esp4_output(m, isr) +esp4_output(m, isr, vnet) struct mbuf *m; struct ipsecrequest *isr; + struct vnet *vnet; { struct ip *ip; if (m->m_len < sizeof(struct ip)) { @@ -698,23 +703,24 @@ } ip = mtod(m, struct ip *); /* XXX assumes that m->m_next points to payload */ - return esp_output(m, &ip->ip_p, m->m_next, isr, AF_INET); + return esp_output(m, &ip->ip_p, m->m_next, isr, AF_INET, vnet); } #endif /* INET */ #ifdef INET6 int -esp6_output(m, nexthdrp, md, isr) +esp6_output(m, nexthdrp, md, isr, vnet) struct mbuf *m; u_char *nexthdrp; struct mbuf *md; struct ipsecrequest *isr; + struct vnet *vnet; { if (m->m_len < sizeof(struct ip6_hdr)) { ipseclog((LOG_DEBUG, "esp6_output: first mbuf too short\n")); m_freem(m); return 0; } - return esp_output(m, nexthdrp, md, isr, AF_INET6); + return esp_output(m, nexthdrp, md, isr, AF_INET6, vnet); } #endif /* INET6 */ diff -urN sys/netinet6/icmp6.c sys.CORE/netinet6/icmp6.c --- sys/netinet6/icmp6.c Wed Jan 31 15:57:05 2007 +++ sys.CORE/netinet6/icmp6.c Wed Jan 31 16:02:43 2007 @@ -2416,7 +2416,7 @@ bcopy(&reddst6, &sdst.sin6_addr, sizeof(struct in6_addr)); pfctlinput(PRC_REDIRECT_HOST, (struct sockaddr *)&sdst, vnet); #ifdef IPSEC - key_sa_routechange((struct sockaddr *)&sdst); + key_sa_routechange((struct sockaddr *)&sdst, vnet); #endif } diff -urN sys/netinet6/in6_ifattach.c sys.CORE/netinet6/in6_ifattach.c --- sys/netinet6/in6_ifattach.c Wed Jan 31 15:57:05 2007 +++ sys.CORE/netinet6/in6_ifattach.c Wed Jan 31 16:02:43 2007 @@ -1032,6 +1032,8 @@ bzero(nullbuf, sizeof(nullbuf)); for (i = 1; i < vnet->if_index + 1; i++) { + if (vnet->nd_ifinfo == NULL) /* nd6 not initialized yet! */ + continue; ndi = &vnet->nd_ifinfo[i]; if (bcmp(ndi->randomid, nullbuf, sizeof(nullbuf)) != 0) { /* diff -urN sys/netinet6/in6_proto.c sys.CORE/netinet6/in6_proto.c --- sys/netinet6/in6_proto.c Wed Jan 31 15:57:05 2007 +++ sys.CORE/netinet6/in6_proto.c Wed Jan 31 16:02:43 2007 @@ -209,7 +209,7 @@ #ifdef IPSEC { SOCK_RAW, &inet6domain, IPPROTO_AH, PR_ATOMIC|PR_ADDR, ah6_input, 0, 0, 0, - 0, + 0, 0, 0, 0, 0, 0, &nousrreqs, }, @@ -218,14 +218,14 @@ esp6_input, 0, esp6_ctlinput, 0, - 0, + 0, 0, 0, 0, 0, 0, &nousrreqs, }, #endif { SOCK_RAW, &inet6domain, IPPROTO_IPCOMP, PR_ATOMIC|PR_ADDR, ipcomp6_input, 0, 0, 0, - 0, + 0, 0, 0, 0, 0, 0, &nousrreqs, }, diff -urN sys/netinet6/ip6_forward.c sys.CORE/netinet6/ip6_forward.c --- sys/netinet6/ip6_forward.c Wed Jan 31 15:57:05 2007 +++ sys.CORE/netinet6/ip6_forward.c Wed Jan 31 16:02:43 2007 @@ -122,9 +122,9 @@ * Don't increment ip6s_cantforward because this is the check * before forwarding packet actually. */ - if (ipsec6_in_reject(m, NULL)) { + if (ipsec6_in_reject(m, NULL, vnet)) { #if !defined(FAST_IPSEC) - ipsec6stat.in_polvio++; + vnet->ipsec6stat.in_polvio++; #endif m_freem(m); return; @@ -178,9 +178,9 @@ #ifdef IPSEC /* get a security policy for this packet */ sp = ipsec6_getpolicybyaddr(m, IPSEC_DIR_OUTBOUND, IP_FORWARDING, - &error); + &error, vnet); if (sp == NULL) { - ipsec6stat.out_inval++; + vnet->ipsec6stat.out_inval++; vnet->ip6stat.ip6s_cantforward++; if (mcopy) { #if 0 @@ -201,7 +201,7 @@ /* * This packet is just discarded. */ - ipsec6stat.out_polvio++; + vnet->ipsec6stat.out_polvio++; vnet->ip6stat.ip6s_cantforward++; key_freesp(sp); if (mcopy) { @@ -263,7 +263,7 @@ state.ro = NULL; /* update at ipsec6_output_tunnel() */ state.dst = NULL; /* update at ipsec6_output_tunnel() */ - error = ipsec6_output_tunnel(&state, sp, 0); + error = ipsec6_output_tunnel(&state, sp, 0, vnet); m = state.m; key_freesp(sp); @@ -401,10 +401,10 @@ * encapsulated packet as "rt->rt_ifp". */ sp = ipsec6_getpolicybyaddr(mcopy, IPSEC_DIR_OUTBOUND, - IP_FORWARDING, &ipsecerror); + IP_FORWARDING, &ipsecerror, vnet); if (sp) { ipsechdrsiz = ipsec6_hdrsiz(mcopy, - IPSEC_DIR_OUTBOUND, NULL); + IPSEC_DIR_OUTBOUND, NULL, vnet); if (ipsechdrsiz < mtu) mtu -= ipsechdrsiz; } diff -urN sys/netinet6/ip6_input.c sys.CORE/netinet6/ip6_input.c --- sys/netinet6/ip6_input.c Wed Jan 31 15:57:05 2007 +++ sys.CORE/netinet6/ip6_input.c Wed Jan 31 16:02:43 2007 @@ -928,8 +928,8 @@ * code - like udp/tcp/raw ip. */ if ((inet6sw[ip6_protox[nxt]].pr_flags & PR_LASTHDR) != 0 && - ipsec6_in_reject(m, NULL)) { - ipsec6stat.in_polvio++; + ipsec6_in_reject(m, NULL, vnet)) { + vnet->ipsec6stat.in_polvio++; goto bad; } #endif diff -urN sys/netinet6/ip6_output.c sys.CORE/netinet6/ip6_output.c --- sys/netinet6/ip6_output.c Wed Jan 31 15:57:05 2007 +++ sys.CORE/netinet6/ip6_output.c Wed Jan 31 16:02:43 2007 @@ -193,6 +193,8 @@ ip6 = mtod(m, struct ip6_hdr *); #endif /* FAST_IPSEC */ + if (vnet == NULL) + panic("ip6_output: NULL vnet was passed."); #define MAKE_EXTHDR(hp, mp) \ do { \ if (hp) { \ @@ -221,12 +223,12 @@ #ifdef IPSEC /* get a security policy for this packet */ if (so == NULL) - sp = ipsec6_getpolicybyaddr(m, IPSEC_DIR_OUTBOUND, 0, &error); + sp = ipsec6_getpolicybyaddr(m, IPSEC_DIR_OUTBOUND, 0, &error, vnet); else sp = ipsec6_getpolicybysock(m, IPSEC_DIR_OUTBOUND, so, &error); if (sp == NULL) { - ipsec6stat.out_inval++; + vnet->ipsec6stat.out_inval++; goto freehdrs; } @@ -238,7 +240,7 @@ /* * This packet is just discarded. */ - ipsec6stat.out_polvio++; + vnet->ipsec6stat.out_polvio++; goto freehdrs; case IPSEC_POLICY_BYPASS: @@ -250,7 +252,7 @@ case IPSEC_POLICY_IPSEC: if (sp->req == NULL) { /* acquire a policy */ - error = key_spdacquire(sp); + error = key_spdacquire(sp, vnet); goto freehdrs; } needipsec = 1; @@ -436,7 +438,7 @@ bzero(&state, sizeof(state)); state.m = m; error = ipsec6_output_trans(&state, nexthdrp, mprev, sp, flags, - &needipsectun); + &needipsectun, vnet); m = state.m; if (error) { /* mbuf is already reclaimed in ipsec6_output_trans. */ @@ -562,7 +564,7 @@ state.ro = (struct route *)ro; state.dst = (struct sockaddr *)dst; - error = ipsec6_output_tunnel(&state, sp, flags); + error = ipsec6_output_tunnel(&state, sp, flags, vnet); m = state.m; ro = (struct route_in6 *)state.ro; @@ -1337,6 +1339,8 @@ int alwaysfrag = 0; int error = 0; + if (vnet == NULL) + panic("ip6_getpmtu: NULL vnet was passed."); if (ro_pmtu != ro) { /* The first hop and the final destination may differ. */ struct sockaddr_in6 *sa6_dst = @@ -1416,6 +1420,8 @@ int optlen; struct proc *p; + if (vnet == NULL) + panic("ip6_ctloutput: NULL vnet from socket."); if (sopt) { level = sopt->sopt_level; op = sopt->sopt_dir; @@ -1853,6 +1859,8 @@ struct proc *p = sopt->sopt_p; int priv = 0; + if (vnet == NULL) + panic("ip6_pcbopts: NULL vnet from socket."); /* turn off any old options. */ if (opt) { #ifdef DIAGNOSTIC @@ -2042,6 +2050,8 @@ struct in6_multi_mship *imm; struct proc *p = curproc; /* XXX */ + if (vnet == NULL) + panic("ip6_setmoptions: NULL vnet passed."); if (im6o == NULL) { /* * No multicast option buffer attached to the pcb; @@ -2326,6 +2336,8 @@ *mp = m_get(M_WAIT, MT_HEADER); /* XXX */ + if (vnet == NULL) + panic("ip6_getmoptions: NULL vnet was passed."); switch (optname) { case IPV6_MULTICAST_IF: diff -urN sys/netinet6/ipcomp_input.c sys.CORE/netinet6/ipcomp_input.c --- sys/netinet6/ipcomp_input.c Sat Apr 27 22:40:27 2002 +++ sys.CORE/netinet6/ipcomp_input.c Wed Jan 31 16:02:43 2007 @@ -47,6 +47,7 @@ #include #include +/*#include */ #include #include #include @@ -79,6 +80,7 @@ #include #include +#include #define IPLEN_FLIPPED @@ -106,6 +108,7 @@ size_t newlen, olen; struct secasvar *sav = NULL; int off, proto; + struct vnet *vnet; va_list ap; va_start(ap, m); @@ -113,10 +116,14 @@ proto = va_arg(ap, int); va_end(ap); + if (m == NULL || m->m_pkthdr.rcvif == NULL) + panic("ipcomp_input: cannot find vnet."); + vnet = m->m_pkthdr.rcvif->if_vnet; + if (m->m_pkthdr.len < off + sizeof(struct ipcomp)) { ipseclog((LOG_DEBUG, "IPv4 IPComp input: assumption failed " "(packet too short)\n")); - ipsecstat.in_inval++; + vnet->ipsecstat.in_inval++; goto fail; } @@ -125,7 +132,7 @@ m = NULL; /* already freed */ ipseclog((LOG_DEBUG, "IPv4 IPComp input: assumption failed " "(pulldown failure)\n")); - ipsecstat.in_inval++; + vnet->ipsecstat.in_inval++; goto fail; } ipcomp = mtod(md, struct ipcomp *); @@ -141,7 +148,7 @@ if (cpi >= IPCOMP_CPI_NEGOTIATE_MIN) { sav = key_allocsa(AF_INET, (caddr_t)&ip->ip_src, - (caddr_t)&ip->ip_dst, IPPROTO_IPCOMP, htonl(cpi)); + (caddr_t)&ip->ip_dst, IPPROTO_IPCOMP, htonl(cpi), vnet); if (sav != NULL && (sav->state == SADB_SASTATE_MATURE || sav->state == SADB_SASTATE_DYING)) { @@ -153,7 +160,7 @@ if (!algo) { ipseclog((LOG_WARNING, "IPv4 IPComp input: unknown cpi %u\n", cpi)); - ipsecstat.in_nosa++; + vnet->ipsecstat.in_nosa++; goto fail; } @@ -173,13 +180,13 @@ error = (*algo->decompress)(m, m->m_next, &newlen); if (error != 0) { if (error == EINVAL) - ipsecstat.in_inval++; + vnet->ipsecstat.in_inval++; else if (error == ENOBUFS) - ipsecstat.in_nomem++; + vnet->ipsecstat.in_nomem++; m = NULL; goto fail; } - ipsecstat.in_comphist[cpi]++; + vnet->ipsecstat.in_comphist[cpi]++; /* * returning decompressed packet onto icmp is meaningless. @@ -204,7 +211,7 @@ len -= olen; if (len & ~0xffff) { /* packet too big after decompress */ - ipsecstat.in_inval++; + vnet->ipsecstat.in_inval++; goto fail; } #ifdef IPLEN_FLIPPED @@ -218,7 +225,7 @@ if (sav) { key_sa_recordxfer(sav, m); if (ipsec_addhist(m, IPPROTO_IPCOMP, (u_int32_t)cpi) != 0) { - ipsecstat.in_nomem++; + vnet->ipsecstat.in_nomem++; goto fail; } key_freesav(sav); @@ -227,8 +234,8 @@ if (nxt != IPPROTO_DONE) { if ((inetsw[ip_protox[nxt]].pr_flags & PR_LASTHDR) != 0 && - ipsec4_in_reject(m, NULL)) { - ipsecstat.in_polvio++; + ipsec4_in_reject(m, NULL, vnet)) { + vnet->ipsecstat.in_polvio++; goto fail; } (*inetsw[ip_protox[nxt]].pr_input)(m, off, nxt); @@ -236,7 +243,7 @@ m_freem(m); m = NULL; - ipsecstat.in_success++; + vnet->ipsecstat.in_success++; return; fail: @@ -265,16 +272,20 @@ size_t newlen; struct secasvar *sav = NULL; char *prvnxtp; + struct vnet *vnet = NULL; m = *mp; off = *offp; + if (m == NULL || m->m_pkthdr.rcvif == NULL) + panic("ipcomp6_input: unable to find vnet."); + vnet = m->m_pkthdr.rcvif->if_vnet; md = m_pulldown(m, off, sizeof(*ipcomp), NULL); if (!m) { m = NULL; /* already freed */ ipseclog((LOG_DEBUG, "IPv6 IPComp input: assumption failed " "(pulldown failure)\n")); - ipsec6stat.in_inval++; + vnet->ipsec6stat.in_inval++; goto fail; } ipcomp = mtod(md, struct ipcomp *); @@ -285,7 +296,8 @@ if (cpi >= IPCOMP_CPI_NEGOTIATE_MIN) { sav = key_allocsa(AF_INET6, (caddr_t)&ip6->ip6_src, - (caddr_t)&ip6->ip6_dst, IPPROTO_IPCOMP, htonl(cpi)); + (caddr_t)&ip6->ip6_dst, IPPROTO_IPCOMP, htonl(cpi), + vnet); if (sav != NULL && (sav->state == SADB_SASTATE_MATURE || sav->state == SADB_SASTATE_DYING)) { @@ -297,7 +309,7 @@ if (!algo) { ipseclog((LOG_WARNING, "IPv6 IPComp input: unknown cpi %u; " "dropping the packet for simplicity\n", cpi)); - ipsec6stat.in_nosa++; + vnet->ipsec6stat.in_nosa++; goto fail; } @@ -311,13 +323,13 @@ error = (*algo->decompress)(m, md, &newlen); if (error != 0) { if (error == EINVAL) - ipsec6stat.in_inval++; + vnet->ipsec6stat.in_inval++; else if (error == ENOBUFS) - ipsec6stat.in_nomem++; + vnet->ipsec6stat.in_nomem++; m = NULL; goto fail; } - ipsec6stat.in_comphist[cpi]++; + vnet->ipsec6stat.in_comphist[cpi]++; m->m_pkthdr.len = off + newlen; /* @@ -338,7 +350,7 @@ if (sav) { key_sa_recordxfer(sav, m); if (ipsec_addhist(m, IPPROTO_IPCOMP, (u_int32_t)cpi) != 0) { - ipsec6stat.in_nomem++; + vnet->ipsec6stat.in_nomem++; goto fail; } key_freesav(sav); @@ -346,7 +358,7 @@ } *offp = off; *mp = m; - ipsec6stat.in_success++; + vnet->ipsec6stat.in_success++; return nxt; fail: diff -urN sys/netinet6/ipcomp_output.c sys.CORE/netinet6/ipcomp_output.c --- sys/netinet6/ipcomp_output.c Tue Apr 29 01:33:50 2003 +++ sys.CORE/netinet6/ipcomp_output.c Wed Jan 31 16:02:43 2007 @@ -80,6 +80,7 @@ #include #include +#include static int ipcomp_output __P((struct mbuf *, u_char *, struct mbuf *, struct ipsecrequest *, int)); @@ -123,18 +124,23 @@ int afnumber; int error = 0; struct ipsecstat *stat; + struct vnet *vnet; + + if (m == NULL || m->m_pkthdr.rcvif == NULL) + panic("ipcomp_output: unable to get vnet."); + vnet = m->m_pkthdr.rcvif->if_vnet; switch (af) { #ifdef INET case AF_INET: afnumber = 4; - stat = &ipsecstat; + stat = &vnet->ipsecstat; break; #endif #ifdef INET6 case AF_INET6: afnumber = 6; - stat = &ipsec6stat; + stat = &vnet->ipsec6stat; break; #endif default: @@ -309,7 +315,7 @@ else { ipseclog((LOG_ERR, "IPv4 ESP output: size exceeds limit\n")); - ipsecstat.out_inval++; + vnet->ipsecstat.out_inval++; m_freem(m); error = EMSGSIZE; goto fail; @@ -353,9 +359,14 @@ struct ipsecrequest *isr; { struct ip *ip; + struct vnet *vnet; + + if (m == NULL || m->m_pkthdr.rcvif == NULL) + panic("ipcomp4_output: unable to get vnet."); + vnet = m->m_pkthdr.rcvif->if_vnet; if (m->m_len < sizeof(struct ip)) { ipseclog((LOG_DEBUG, "ipcomp4_output: first mbuf too short\n")); - ipsecstat.out_inval++; + vnet->ipsecstat.out_inval++; m_freem(m); return 0; } @@ -373,9 +384,13 @@ struct mbuf *md; struct ipsecrequest *isr; { + struct vnet *vnet; + if (m == NULL || m->m_pkthdr.rcvif == NULL) + panic("ipcomp6_output: cannot find vnet."); + vnet = m->m_pkthdr.rcvif->if_vnet; if (m->m_len < sizeof(struct ip6_hdr)) { ipseclog((LOG_DEBUG, "ipcomp6_output: first mbuf too short\n")); - ipsec6stat.out_inval++; + vnet->ipsec6stat.out_inval++; m_freem(m); return 0; } diff -urN sys/netinet6/ipsec.c sys.CORE/netinet6/ipsec.c --- sys/netinet6/ipsec.c Wed Jan 31 15:57:05 2007 +++ sys.CORE/netinet6/ipsec.c Wed Jan 31 16:02:43 2007 @@ -112,6 +112,7 @@ int ipsec_debug = 0; #endif +#ifdef MOVED_TO_VNET struct ipsecstat ipsecstat; int ip4_ah_cleartos = 1; int ip4_ah_offsetmask = 0; /* maybe IP_DF? */ @@ -123,6 +124,7 @@ struct secpolicy ip4_def_policy; int ip4_ipsec_ecn = 0; /* ECN ignore(-1)/forbidden(0)/allowed(1) */ int ip4_esp_randpad = -1; +#endif #ifdef SYSCTL_DECL SYSCTL_DECL(_net_inet_ipsec); @@ -132,32 +134,33 @@ #endif /* net.inet.ipsec */ -SYSCTL_STRUCT(_net_inet_ipsec, IPSECCTL_STATS, - stats, CTLFLAG_RD, &ipsecstat, ipsecstat, ""); -SYSCTL_INT(_net_inet_ipsec, IPSECCTL_DEF_POLICY, - def_policy, CTLFLAG_RW, &ip4_def_policy.policy, 0, ""); -SYSCTL_INT(_net_inet_ipsec, IPSECCTL_DEF_ESP_TRANSLEV, esp_trans_deflev, - CTLFLAG_RW, &ip4_esp_trans_deflev, 0, ""); -SYSCTL_INT(_net_inet_ipsec, IPSECCTL_DEF_ESP_NETLEV, esp_net_deflev, - CTLFLAG_RW, &ip4_esp_net_deflev, 0, ""); -SYSCTL_INT(_net_inet_ipsec, IPSECCTL_DEF_AH_TRANSLEV, ah_trans_deflev, - CTLFLAG_RW, &ip4_ah_trans_deflev, 0, ""); -SYSCTL_INT(_net_inet_ipsec, IPSECCTL_DEF_AH_NETLEV, ah_net_deflev, - CTLFLAG_RW, &ip4_ah_net_deflev, 0, ""); -SYSCTL_INT(_net_inet_ipsec, IPSECCTL_AH_CLEARTOS, - ah_cleartos, CTLFLAG_RW, &ip4_ah_cleartos, 0, ""); -SYSCTL_INT(_net_inet_ipsec, IPSECCTL_AH_OFFSETMASK, - ah_offsetmask, CTLFLAG_RW, &ip4_ah_offsetmask, 0, ""); -SYSCTL_INT(_net_inet_ipsec, IPSECCTL_DFBIT, - dfbit, CTLFLAG_RW, &ip4_ipsec_dfbit, 0, ""); -SYSCTL_INT(_net_inet_ipsec, IPSECCTL_ECN, - ecn, CTLFLAG_RW, &ip4_ipsec_ecn, 0, ""); +SYSCTL_V_STRUCT(V_NET, _net_inet_ipsec, IPSECCTL_STATS, + stats, CTLFLAG_RD, v_ipsecstat, ipsecstat, ""); +SYSCTL_V_INT(V_NET, _net_inet_ipsec, IPSECCTL_DEF_POLICY, + def_policy, CTLFLAG_RW, &((struct secpolicy*)v_ip4_def_policy)->policy, 0, ""); +SYSCTL_V_INT(V_NET, _net_inet_ipsec, IPSECCTL_DEF_ESP_TRANSLEV, + esp_trans_deflev, CTLFLAG_RW, v_ip4_esp_trans_deflev, 0, ""); +SYSCTL_V_INT(V_NET, _net_inet_ipsec, IPSECCTL_DEF_ESP_NETLEV, esp_net_deflev, + CTLFLAG_RW, v_ip4_esp_net_deflev, 0, ""); +SYSCTL_V_INT(V_NET, _net_inet_ipsec, IPSECCTL_DEF_AH_TRANSLEV, ah_trans_deflev, + CTLFLAG_RW, v_ip4_ah_trans_deflev, 0, ""); +SYSCTL_V_INT(V_NET, _net_inet_ipsec, IPSECCTL_DEF_AH_NETLEV, ah_net_deflev, + CTLFLAG_RW, v_ip4_ah_net_deflev, 0, ""); +SYSCTL_V_INT(V_NET, _net_inet_ipsec, IPSECCTL_AH_CLEARTOS, + ah_cleartos, CTLFLAG_RW, v_ip4_ah_cleartos, 0, ""); +SYSCTL_V_INT(V_NET, _net_inet_ipsec, IPSECCTL_AH_OFFSETMASK, + ah_offsetmask, CTLFLAG_RW, v_ip4_ah_offsetmask, 0, ""); +SYSCTL_V_INT(V_NET, _net_inet_ipsec, IPSECCTL_DFBIT, + dfbit, CTLFLAG_RW, v_ip4_ipsec_dfbit, 0, ""); +SYSCTL_V_INT(V_NET, _net_inet_ipsec, IPSECCTL_ECN, + ecn, CTLFLAG_RW, v_ip4_ipsec_ecn, 0, ""); SYSCTL_INT(_net_inet_ipsec, IPSECCTL_DEBUG, debug, CTLFLAG_RW, &ipsec_debug, 0, ""); -SYSCTL_INT(_net_inet_ipsec, IPSECCTL_ESP_RANDPAD, - esp_randpad, CTLFLAG_RW, &ip4_esp_randpad, 0, ""); +SYSCTL_V_INT(V_NET, _net_inet_ipsec, IPSECCTL_ESP_RANDPAD, + esp_randpad, CTLFLAG_RW, v_ip4_esp_randpad, 0, ""); #ifdef INET6 +#ifdef MOVED_TO_VNET struct ipsecstat ipsec6stat; int ip6_esp_trans_deflev = IPSEC_LEVEL_USE; int ip6_esp_net_deflev = IPSEC_LEVEL_USE; @@ -166,26 +169,27 @@ struct secpolicy ip6_def_policy; int ip6_ipsec_ecn = 0; /* ECN ignore(-1)/forbidden(0)/allowed(1) */ int ip6_esp_randpad = -1; +#endif /* MOVED_TO_VNET */ /* net.inet6.ipsec6 */ -SYSCTL_STRUCT(_net_inet6_ipsec6, IPSECCTL_STATS, - stats, CTLFLAG_RD, &ipsec6stat, ipsecstat, ""); -SYSCTL_INT(_net_inet6_ipsec6, IPSECCTL_DEF_POLICY, - def_policy, CTLFLAG_RW, &ip6_def_policy.policy, 0, ""); -SYSCTL_INT(_net_inet6_ipsec6, IPSECCTL_DEF_ESP_TRANSLEV, esp_trans_deflev, - CTLFLAG_RW, &ip6_esp_trans_deflev, 0, ""); -SYSCTL_INT(_net_inet6_ipsec6, IPSECCTL_DEF_ESP_NETLEV, esp_net_deflev, - CTLFLAG_RW, &ip6_esp_net_deflev, 0, ""); -SYSCTL_INT(_net_inet6_ipsec6, IPSECCTL_DEF_AH_TRANSLEV, ah_trans_deflev, - CTLFLAG_RW, &ip6_ah_trans_deflev, 0, ""); -SYSCTL_INT(_net_inet6_ipsec6, IPSECCTL_DEF_AH_NETLEV, ah_net_deflev, - CTLFLAG_RW, &ip6_ah_net_deflev, 0, ""); -SYSCTL_INT(_net_inet6_ipsec6, IPSECCTL_ECN, - ecn, CTLFLAG_RW, &ip6_ipsec_ecn, 0, ""); +SYSCTL_V_STRUCT(V_NET, _net_inet6_ipsec6, IPSECCTL_STATS, + stats, CTLFLAG_RD, v_ipsec6stat, ipsecstat, ""); +SYSCTL_V_INT(V_NET, _net_inet6_ipsec6, IPSECCTL_DEF_POLICY, + def_policy, CTLFLAG_RW, &((struct secpolicy *)v_ip6_def_policy)->policy, 0, ""); +SYSCTL_V_INT(V_NET, _net_inet6_ipsec6, IPSECCTL_DEF_ESP_TRANSLEV, + esp_trans_deflev, CTLFLAG_RW, v_ip6_esp_trans_deflev, 0, ""); +SYSCTL_V_INT(V_NET, _net_inet6_ipsec6, IPSECCTL_DEF_ESP_NETLEV, esp_net_deflev, + CTLFLAG_RW, v_ip6_esp_net_deflev, 0, ""); +SYSCTL_V_INT(V_NET, _net_inet6_ipsec6, IPSECCTL_DEF_AH_TRANSLEV, + ah_trans_deflev, CTLFLAG_RW, v_ip6_ah_trans_deflev, 0, ""); +SYSCTL_V_INT(V_NET, _net_inet6_ipsec6, IPSECCTL_DEF_AH_NETLEV, ah_net_deflev, + CTLFLAG_RW, v_ip6_ah_net_deflev, 0, ""); +SYSCTL_V_INT(V_NET, _net_inet6_ipsec6, IPSECCTL_ECN, + ecn, CTLFLAG_RW, v_ip6_ipsec_ecn, 0, ""); SYSCTL_INT(_net_inet6_ipsec6, IPSECCTL_DEBUG, debug, CTLFLAG_RW, &ipsec_debug, 0, ""); -SYSCTL_INT(_net_inet6_ipsec6, IPSECCTL_ESP_RANDPAD, - esp_randpad, CTLFLAG_RW, &ip6_esp_randpad, 0, ""); +SYSCTL_V_INT(V_NET, _net_inet6_ipsec6, IPSECCTL_ESP_RANDPAD, + esp_randpad, CTLFLAG_RW, v_ip6_esp_randpad, 0, ""); #endif /* INET6 */ static int ipsec_setspidx_mbuf @@ -217,10 +221,10 @@ static struct mbuf *ipsec6_splithdr __P((struct mbuf *)); #endif #ifdef INET -static int ipsec4_encapsulate __P((struct mbuf *, struct secasvar *)); +static int ipsec4_encapsulate __P((struct mbuf *, struct secasvar *, struct vnet *)); #endif #ifdef INET6 -static int ipsec6_encapsulate __P((struct mbuf *, struct secasvar *)); +static int ipsec6_encapsulate __P((struct mbuf *, struct secasvar *, struct vnet *)); #endif /* @@ -245,11 +249,15 @@ struct inpcbpolicy *pcbsp = NULL; struct secpolicy *currsp = NULL; /* policy on socket */ struct secpolicy *kernsp = NULL; /* policy on kernel */ + struct vnet *vnet; /* sanity check */ if (m == NULL || so == NULL || error == NULL) panic("ipsec4_getpolicybysock: NULL pointer was passed."); - + vnet = so->so_vnet; + if (vnet == NULL) + panic("ipsec4_getpolicybysock: NULL vnet pointer."); + switch (so->so_proto->pr_domain->dom_family) { case AF_INET: /* set spidx in pcb */ @@ -306,7 +314,7 @@ case IPSEC_POLICY_ENTRUST: /* look for a policy in SPD */ - kernsp = key_allocsp(&currsp->spidx, dir); + kernsp = key_allocsp(&currsp->spidx, dir, vnet); /* SP found */ if (kernsp != NULL) { @@ -318,16 +326,16 @@ } /* no SP found */ - if (ip4_def_policy.policy != IPSEC_POLICY_DISCARD - && ip4_def_policy.policy != IPSEC_POLICY_NONE) { + if (vnet->ip4_def_policy.policy != IPSEC_POLICY_DISCARD + && vnet->ip4_def_policy.policy != IPSEC_POLICY_NONE) { ipseclog((LOG_INFO, "fixed system default policy: %d->%d\n", - ip4_def_policy.policy, IPSEC_POLICY_NONE)); - ip4_def_policy.policy = IPSEC_POLICY_NONE; + vnet->ip4_def_policy.policy, IPSEC_POLICY_NONE)); + vnet->ip4_def_policy.policy = IPSEC_POLICY_NONE; } - ip4_def_policy.refcnt++; + vnet->ip4_def_policy.refcnt++; *error = 0; - return &ip4_def_policy; + return &vnet->ip4_def_policy; case IPSEC_POLICY_IPSEC: currsp->refcnt++; @@ -345,7 +353,7 @@ /* when non-privilieged socket */ /* look for a policy in SPD */ - kernsp = key_allocsp(&currsp->spidx, dir); + kernsp = key_allocsp(&currsp->spidx, dir, vnet); /* SP found */ if (kernsp != NULL) { @@ -366,16 +374,16 @@ return NULL; case IPSEC_POLICY_ENTRUST: - if (ip4_def_policy.policy != IPSEC_POLICY_DISCARD - && ip4_def_policy.policy != IPSEC_POLICY_NONE) { + if (vnet->ip4_def_policy.policy != IPSEC_POLICY_DISCARD + && vnet->ip4_def_policy.policy != IPSEC_POLICY_NONE) { ipseclog((LOG_INFO, "fixed system default policy: %d->%d\n", - ip4_def_policy.policy, IPSEC_POLICY_NONE)); - ip4_def_policy.policy = IPSEC_POLICY_NONE; + vnet->ip4_def_policy.policy, IPSEC_POLICY_NONE)); + vnet->ip4_def_policy.policy = IPSEC_POLICY_NONE; } - ip4_def_policy.refcnt++; + vnet->ip4_def_policy.refcnt++; *error = 0; - return &ip4_def_policy; + return &vnet->ip4_def_policy; case IPSEC_POLICY_IPSEC: currsp->refcnt++; @@ -402,17 +410,20 @@ * others : error occured. */ struct secpolicy * -ipsec4_getpolicybyaddr(m, dir, flag, error) +ipsec4_getpolicybyaddr(m, dir, flag, error, vnet) struct mbuf *m; u_int dir; int flag; int *error; + struct vnet *vnet; { struct secpolicy *sp = NULL; /* sanity check */ if (m == NULL || error == NULL) panic("ipsec4_getpolicybyaddr: NULL pointer was passed."); + if (vnet == NULL) + panic("ipsec4_getpolicybyaddr: NULL vnet pointer was passed."); { struct secpolicyindex spidx; @@ -426,7 +437,7 @@ if (*error != 0) return NULL; - sp = key_allocsp(&spidx, dir); + sp = key_allocsp(&spidx, dir, vnet); } /* SP found */ @@ -439,16 +450,16 @@ } /* no SP found */ - if (ip4_def_policy.policy != IPSEC_POLICY_DISCARD - && ip4_def_policy.policy != IPSEC_POLICY_NONE) { + if (vnet->ip4_def_policy.policy != IPSEC_POLICY_DISCARD + && vnet->ip4_def_policy.policy != IPSEC_POLICY_NONE) { ipseclog((LOG_INFO, "fixed system default policy:%d->%d\n", - ip4_def_policy.policy, + vnet->ip4_def_policy.policy, IPSEC_POLICY_NONE)); - ip4_def_policy.policy = IPSEC_POLICY_NONE; + vnet->ip4_def_policy.policy = IPSEC_POLICY_NONE; } - ip4_def_policy.refcnt++; + vnet->ip4_def_policy.refcnt++; *error = 0; - return &ip4_def_policy; + return &vnet->ip4_def_policy; } #ifdef INET6 @@ -472,10 +483,15 @@ struct inpcbpolicy *pcbsp = NULL; struct secpolicy *currsp = NULL; /* policy on socket */ struct secpolicy *kernsp = NULL; /* policy on kernel */ + struct vnet *vnet; /* sanity check */ if (m == NULL || so == NULL || error == NULL) panic("ipsec6_getpolicybysock: NULL pointer was passed."); + vnet = so->so_vnet; + if (vnet == NULL) + panic("ipsec6_getpolicybysock: NULL vnet pointer was passed."); + #ifdef DIAGNOSTIC if (so->so_proto->pr_domain->dom_family != AF_INET6) @@ -516,7 +532,7 @@ case IPSEC_POLICY_ENTRUST: /* look for a policy in SPD */ - kernsp = key_allocsp(&currsp->spidx, dir); + kernsp = key_allocsp(&currsp->spidx, dir, vnet); /* SP found */ if (kernsp != NULL) { @@ -528,16 +544,16 @@ } /* no SP found */ - if (ip6_def_policy.policy != IPSEC_POLICY_DISCARD - && ip6_def_policy.policy != IPSEC_POLICY_NONE) { + if (vnet->ip6_def_policy.policy != IPSEC_POLICY_DISCARD + && vnet->ip6_def_policy.policy != IPSEC_POLICY_NONE) { ipseclog((LOG_INFO, "fixed system default policy: %d->%d\n", - ip6_def_policy.policy, IPSEC_POLICY_NONE)); - ip6_def_policy.policy = IPSEC_POLICY_NONE; + vnet->ip6_def_policy.policy, IPSEC_POLICY_NONE)); + vnet->ip6_def_policy.policy = IPSEC_POLICY_NONE; } - ip6_def_policy.refcnt++; + vnet->ip6_def_policy.refcnt++; *error = 0; - return &ip6_def_policy; + return &vnet->ip6_def_policy; case IPSEC_POLICY_IPSEC: currsp->refcnt++; @@ -555,7 +571,7 @@ /* when non-privilieged socket */ /* look for a policy in SPD */ - kernsp = key_allocsp(&currsp->spidx, dir); + kernsp = key_allocsp(&currsp->spidx, dir, vnet); /* SP found */ if (kernsp != NULL) { @@ -576,16 +592,16 @@ return NULL; case IPSEC_POLICY_ENTRUST: - if (ip6_def_policy.policy != IPSEC_POLICY_DISCARD - && ip6_def_policy.policy != IPSEC_POLICY_NONE) { + if (vnet->ip6_def_policy.policy != IPSEC_POLICY_DISCARD + && vnet->ip6_def_policy.policy != IPSEC_POLICY_NONE) { ipseclog((LOG_INFO, "fixed system default policy: %d->%d\n", - ip6_def_policy.policy, IPSEC_POLICY_NONE)); - ip6_def_policy.policy = IPSEC_POLICY_NONE; + vnet->ip6_def_policy.policy, IPSEC_POLICY_NONE)); + vnet->ip6_def_policy.policy = IPSEC_POLICY_NONE; } - ip6_def_policy.refcnt++; + vnet->ip6_def_policy.refcnt++; *error = 0; - return &ip6_def_policy; + return &vnet->ip6_def_policy; case IPSEC_POLICY_IPSEC: currsp->refcnt++; @@ -619,17 +635,20 @@ #endif struct secpolicy * -ipsec6_getpolicybyaddr(m, dir, flag, error) +ipsec6_getpolicybyaddr(m, dir, flag, error, vnet) struct mbuf *m; u_int dir; int flag; int *error; + struct vnet *vnet; { struct secpolicy *sp = NULL; /* sanity check */ if (m == NULL || error == NULL) panic("ipsec6_getpolicybyaddr: NULL pointer was passed."); + if (vnet == NULL) + panic("ipsec6_getpolicybyaddr: NULL vnet pointer was passed."); { struct secpolicyindex spidx; @@ -643,7 +662,7 @@ if (*error != 0) return NULL; - sp = key_allocsp(&spidx, dir); + sp = key_allocsp(&spidx, dir, vnet); } /* SP found */ @@ -656,15 +675,15 @@ } /* no SP found */ - if (ip6_def_policy.policy != IPSEC_POLICY_DISCARD - && ip6_def_policy.policy != IPSEC_POLICY_NONE) { + if (vnet->ip6_def_policy.policy != IPSEC_POLICY_DISCARD + && vnet->ip6_def_policy.policy != IPSEC_POLICY_NONE) { ipseclog((LOG_INFO, "fixed system default policy: %d->%d\n", - ip6_def_policy.policy, IPSEC_POLICY_NONE)); - ip6_def_policy.policy = IPSEC_POLICY_NONE; + vnet->ip6_def_policy.policy, IPSEC_POLICY_NONE)); + vnet->ip6_def_policy.policy = IPSEC_POLICY_NONE; } - ip6_def_policy.refcnt++; + vnet->ip6_def_policy.refcnt++; *error = 0; - return &ip6_def_policy; + return &vnet->ip6_def_policy; } #endif /* INET6 */ @@ -1505,8 +1524,9 @@ * Either IPSEC_LEVEL_USE or IPSEC_LEVEL_REQUIRE are always returned. */ u_int -ipsec_get_reqlevel(isr) +ipsec_get_reqlevel(isr, vnet) struct ipsecrequest *isr; + struct vnet *vnet; { u_int level = 0; u_int esp_trans_deflev, esp_net_deflev, ah_trans_deflev, ah_net_deflev; @@ -1514,6 +1534,8 @@ /* sanity check */ if (isr == NULL || isr->sp == NULL) panic("ipsec_get_reqlevel: NULL pointer is passed."); + if (vnet == NULL) + panic("ipsec_get_reqlevel: NULL vnet is passed."); if (((struct sockaddr *)&isr->sp->spidx.src)->sa_family != ((struct sockaddr *)&isr->sp->spidx.dst)->sa_family) panic("ipsec_get_reqlevel: family mismatched."); @@ -1534,18 +1556,18 @@ switch (((struct sockaddr *)&isr->sp->spidx.src)->sa_family) { #ifdef INET case AF_INET: - esp_trans_deflev = IPSEC_CHECK_DEFAULT(ip4_esp_trans_deflev); - esp_net_deflev = IPSEC_CHECK_DEFAULT(ip4_esp_net_deflev); - ah_trans_deflev = IPSEC_CHECK_DEFAULT(ip4_ah_trans_deflev); - ah_net_deflev = IPSEC_CHECK_DEFAULT(ip4_ah_net_deflev); + esp_trans_deflev = IPSEC_CHECK_DEFAULT(vnet->ip4_esp_trans_deflev); + esp_net_deflev = IPSEC_CHECK_DEFAULT(vnet->ip4_esp_net_deflev); + ah_trans_deflev = IPSEC_CHECK_DEFAULT(vnet->ip4_ah_trans_deflev); + ah_net_deflev = IPSEC_CHECK_DEFAULT(vnet->ip4_ah_net_deflev); break; #endif #ifdef INET6 case AF_INET6: - esp_trans_deflev = IPSEC_CHECK_DEFAULT(ip6_esp_trans_deflev); - esp_net_deflev = IPSEC_CHECK_DEFAULT(ip6_esp_net_deflev); - ah_trans_deflev = IPSEC_CHECK_DEFAULT(ip6_ah_trans_deflev); - ah_net_deflev = IPSEC_CHECK_DEFAULT(ip6_ah_net_deflev); + esp_trans_deflev = IPSEC_CHECK_DEFAULT(vnet->ip6_esp_trans_deflev); + esp_net_deflev = IPSEC_CHECK_DEFAULT(vnet->ip6_esp_net_deflev); + ah_trans_deflev = IPSEC_CHECK_DEFAULT(vnet->ip6_ah_trans_deflev); + ah_net_deflev = IPSEC_CHECK_DEFAULT(vnet->ip6_ah_net_deflev); break; #endif /* INET6 */ default: @@ -1614,10 +1636,16 @@ struct ipsecrequest *isr; u_int level; int need_auth, need_conf, need_icv; + struct vnet *vnet; KEYDEBUG(KEYDEBUG_IPSEC_DATA, printf("ipsec_in_reject: using SP\n"); kdebug_secpolicy(sp)); + if (m == NULL || m->m_pkthdr.rcvif == NULL) + panic("ipsec_in_reject(): unable to get vnet."); + vnet = m->m_pkthdr.rcvif->if_vnet; + if (vnet == NULL) + panic("ipsec_in_reject(): NULL vnet was passed."); /* check policy */ switch (sp->policy) { @@ -1644,7 +1672,7 @@ for (isr = sp->req; isr != NULL; isr = isr->next) { /* get current level */ - level = ipsec_get_reqlevel(isr); + level = ipsec_get_reqlevel(isr, vnet); switch (isr->saidx.proto) { case IPPROTO_ESP: @@ -1691,9 +1719,10 @@ * and {ah,esp}4_input for tunnel mode */ int -ipsec4_in_reject_so(m, so) +ipsec4_in_reject_so(m, so, vnet) struct mbuf *m; struct socket *so; + struct vnet *vnet; { struct secpolicy *sp = NULL; int error; @@ -1708,7 +1737,7 @@ * ipsec4_getpolicybyaddr() with IP_FORWARDING flag. */ if (so == NULL) - sp = ipsec4_getpolicybyaddr(m, IPSEC_DIR_INBOUND, IP_FORWARDING, &error); + sp = ipsec4_getpolicybyaddr(m, IPSEC_DIR_INBOUND, IP_FORWARDING, &error, vnet); else sp = ipsec4_getpolicybysock(m, IPSEC_DIR_INBOUND, so, &error); @@ -1725,14 +1754,15 @@ } int -ipsec4_in_reject(m, inp) +ipsec4_in_reject(m, inp, vnet) struct mbuf *m; struct inpcb *inp; + struct vnet *vnet; { if (inp == NULL) - return ipsec4_in_reject_so(m, NULL); + return ipsec4_in_reject_so(m, NULL, vnet); if (inp->inp_socket) - return ipsec4_in_reject_so(m, inp->inp_socket); + return ipsec4_in_reject_so(m, inp->inp_socket, vnet); else panic("ipsec4_in_reject: invalid inpcb/socket"); } @@ -1744,9 +1774,10 @@ * and {ah,esp}6_input for tunnel mode */ int -ipsec6_in_reject_so(m, so) +ipsec6_in_reject_so(m, so, vnet) struct mbuf *m; struct socket *so; + struct vnet *vnet; { struct secpolicy *sp = NULL; int error; @@ -1761,7 +1792,7 @@ * ipsec6_getpolicybyaddr() with IP_FORWARDING flag. */ if (so == NULL) - sp = ipsec6_getpolicybyaddr(m, IPSEC_DIR_INBOUND, IP_FORWARDING, &error); + sp = ipsec6_getpolicybyaddr(m, IPSEC_DIR_INBOUND, IP_FORWARDING, &error, vnet); else sp = ipsec6_getpolicybysock(m, IPSEC_DIR_INBOUND, so, &error); @@ -1777,14 +1808,15 @@ } int -ipsec6_in_reject(m, in6p) +ipsec6_in_reject(m, in6p, vnet) struct mbuf *m; struct in6pcb *in6p; + struct vnet *vnet; { if (in6p == NULL) - return ipsec6_in_reject_so(m, NULL); + return ipsec6_in_reject_so(m, NULL, vnet); if (in6p->in6p_socket) - return ipsec6_in_reject_so(m, in6p->in6p_socket); + return ipsec6_in_reject_so(m, in6p->in6p_socket, vnet); else panic("ipsec6_in_reject: invalid in6p/socket"); } @@ -1868,10 +1900,11 @@ /* This function is called from ip_forward() and ipsec4_hdrsize_tcp(). */ size_t -ipsec4_hdrsiz(m, dir, inp) +ipsec4_hdrsiz(m, dir, inp, vnet) struct mbuf *m; u_int dir; struct inpcb *inp; + struct vnet *vnet; { struct secpolicy *sp = NULL; int error; @@ -1888,7 +1921,7 @@ * ipsec4_getpolicybyaddr() with IP_FORWARDING flag. */ if (inp == NULL) - sp = ipsec4_getpolicybyaddr(m, dir, IP_FORWARDING, &error); + sp = ipsec4_getpolicybyaddr(m, dir, IP_FORWARDING, &error,vnet); else sp = ipsec4_getpolicybysock(m, dir, inp->inp_socket, &error); @@ -1910,10 +1943,11 @@ * and maybe from ip6_forward.() */ size_t -ipsec6_hdrsiz(m, dir, in6p) +ipsec6_hdrsiz(m, dir, in6p, vnet) struct mbuf *m; u_int dir; struct in6pcb *in6p; + struct vnet *vnet; { struct secpolicy *sp = NULL; int error; @@ -1928,7 +1962,7 @@ /* get SP for this packet */ /* XXX Is it right to call with IP_FORWARDING. */ if (in6p == NULL) - sp = ipsec6_getpolicybyaddr(m, dir, IP_FORWARDING, &error); + sp = ipsec6_getpolicybyaddr(m, dir, IP_FORWARDING, &error, vnet); else sp = ipsec6_getpolicybysock(m, dir, in6p->in6p_socket, &error); @@ -1951,9 +1985,10 @@ * ip->ip_src must be fixed later on. */ static int -ipsec4_encapsulate(m, sav) +ipsec4_encapsulate(m, sav, vnet) struct mbuf *m; struct secasvar *sav; + struct vnet *vnet; { struct ip *oip; struct ip *ip; @@ -1967,6 +2002,8 @@ m_freem(m); return EINVAL; } + if (vnet == NULL) + panic("ipsec4_encapsulate(): vnet is NULL."); #if 0 /* XXX if the dst is myself, perform nothing. */ if (key_ismyaddr((struct sockaddr *)&sav->sah->saidx.dst)) { @@ -2030,7 +2067,7 @@ /* construct new IPv4 header. see RFC 2401 5.1.2.1 */ /* ECN consideration. */ - ip_ecn_ingress(ip4_ipsec_ecn, &ip->ip_tos, &oip->ip_tos); + ip_ecn_ingress(vnet->ip4_ipsec_ecn, &ip->ip_tos, &oip->ip_tos); #ifdef _IP_VHL ip->ip_vhl = IP_MAKE_VHL(IPVERSION, sizeof(struct ip) >> 2); #else @@ -2038,7 +2075,7 @@ #endif ip->ip_off &= htons(~IP_OFFMASK); ip->ip_off &= htons(~IP_MF); - switch (ip4_ipsec_dfbit) { + switch (vnet->ip4_ipsec_dfbit) { case 0: /* clear DF bit */ ip->ip_off &= htons(~IP_DF); break; @@ -2058,7 +2095,7 @@ #ifdef RANDOM_IP_ID ip->ip_id = ip_randomid(); #else - ip->ip_id = htons(ip_id++); + ip->ip_id = htons(vnet->ip_id++); #endif bcopy(&((struct sockaddr_in *)&sav->sah->saidx.src)->sin_addr, &ip->ip_src, sizeof(ip->ip_src)); @@ -2074,14 +2111,18 @@ #ifdef INET6 static int -ipsec6_encapsulate(m, sav) +ipsec6_encapsulate(m, sav, vnet) struct mbuf *m; struct secasvar *sav; + struct vnet *vnet; { struct ip6_hdr *oip6; struct ip6_hdr *ip6; size_t plen; + if (vnet == NULL) + panic("ipsec6_encapsulate(): vnet is NULL."); + /* can't tunnel between different AFs */ if (((struct sockaddr *)&sav->sah->saidx.src)->sa_family != ((struct sockaddr *)&sav->sah->saidx.dst)->sa_family @@ -2133,7 +2174,7 @@ /* construct new IPv6 header. see RFC 2401 5.1.2.2 */ /* ECN consideration. */ - ip6_ecn_ingress(ip6_ipsec_ecn, &ip6->ip6_flow, &oip6->ip6_flow); + ip6_ecn_ingress(vnet->ip6_ipsec_ecn, &ip6->ip6_flow, &oip6->ip6_flow); if (plen < IPV6_MAXPACKET - sizeof(struct ip6_hdr)) ip6->ip6_plen = htons(plen); else { @@ -2493,6 +2534,8 @@ panic("state->ro == NULL in ipsec4_output"); if (!state->dst) panic("state->dst == NULL in ipsec4_output"); + if (vnet == NULL) + panic("ipsec4_output: vnet is NULL."); KEYDEBUG(KEYDEBUG_IPSEC_DATA, printf("ipsec4_output: applyed SP\n"); @@ -2541,13 +2584,13 @@ * this packet because it is responsibility for * upper layer to retransmit the packet. */ - ipsecstat.out_nosa++; + vnet->ipsecstat.out_nosa++; goto bad; } /* validity check */ if (isr->sav == NULL) { - switch (ipsec_get_reqlevel(isr)) { + switch (ipsec_get_reqlevel(isr, vnet)) { case IPSEC_LEVEL_USE: continue; case IPSEC_LEVEL_REQUIRE: @@ -2565,7 +2608,7 @@ */ if (isr->sav->state != SADB_SASTATE_MATURE && isr->sav->state != SADB_SASTATE_DYING) { - ipsecstat.out_nosa++; + vnet->ipsecstat.out_nosa++; error = EINVAL; goto bad; } @@ -2596,7 +2639,7 @@ error = ENOMEM; goto bad; } - error = ipsec4_encapsulate(state->m, isr->sav); + error = ipsec4_encapsulate(state->m, isr->sav, vnet); splx(s); if (error) { state->m = NULL; @@ -2641,7 +2684,7 @@ switch (isr->saidx.proto) { case IPPROTO_ESP: #ifdef IPSEC_ESP - if ((error = esp4_output(state->m, isr)) != 0) { + if ((error = esp4_output(state->m, isr, vnet)) != 0) { state->m = NULL; goto bad; } @@ -2653,7 +2696,7 @@ goto bad; #endif case IPPROTO_AH: - if ((error = ah4_output(state->m, isr)) != 0) { + if ((error = ah4_output(state->m, isr, vnet)) != 0) { state->m = NULL; goto bad; } @@ -2695,13 +2738,14 @@ * IPsec output logic for IPv6, transport mode. */ int -ipsec6_output_trans(state, nexthdrp, mprev, sp, flags, tun) +ipsec6_output_trans(state, nexthdrp, mprev, sp, flags, tun, vnet) struct ipsec_output_state *state; u_char *nexthdrp; struct mbuf *mprev; struct secpolicy *sp; int flags; int *tun; + struct vnet *vnet; { struct ip6_hdr *ip6; struct ipsecrequest *isr = NULL; @@ -2722,6 +2766,8 @@ panic("sp == NULL in ipsec6_output_trans"); if (!tun) panic("tun == NULL in ipsec6_output_trans"); + if (!vnet) + panic("vnet == NULL in ipsec6_output_trans"); KEYDEBUG(KEYDEBUG_IPSEC_DATA, printf("ipsec6_output_trans: applyed SP\n"); @@ -2766,7 +2812,7 @@ } } - if (key_checkrequest(isr, &saidx) == ENOENT) { + if (key_checkrequest(isr, &saidx, vnet) == ENOENT) { /* * IPsec processing is required, but no SA found. * I assume that key_acquire() had been called @@ -2774,7 +2820,7 @@ * this packet because it is responsibility for * upper layer to retransmit the packet. */ - ipsec6stat.out_nosa++; + vnet->ipsec6stat.out_nosa++; error = ENOENT; /* @@ -2793,7 +2839,7 @@ /* validity check */ if (isr->sav == NULL) { - switch (ipsec_get_reqlevel(isr)) { + switch (ipsec_get_reqlevel(isr, vnet)) { case IPSEC_LEVEL_USE: continue; case IPSEC_LEVEL_REQUIRE: @@ -2808,7 +2854,7 @@ */ if (isr->sav->state != SADB_SASTATE_MATURE && isr->sav->state != SADB_SASTATE_DYING) { - ipsec6stat.out_nosa++; + vnet->ipsec6stat.out_nosa++; error = EINVAL; goto bad; } @@ -2816,7 +2862,7 @@ switch (isr->saidx.proto) { case IPPROTO_ESP: #ifdef IPSEC_ESP - error = esp6_output(state->m, nexthdrp, mprev->m_next, isr); + error = esp6_output(state->m, nexthdrp, mprev->m_next, isr, vnet); #else m_freem(state->m); error = EINVAL; @@ -2832,7 +2878,7 @@ ipseclog((LOG_ERR, "ipsec6_output_trans: " "unknown ipsec protocol %d\n", isr->saidx.proto)); m_freem(state->m); - ipsec6stat.out_inval++; + vnet->ipsec6stat.out_inval++; error = EINVAL; break; } @@ -2844,7 +2890,7 @@ if (plen > IPV6_MAXPACKET) { ipseclog((LOG_ERR, "ipsec6_output_trans: " "IPsec with IPv6 jumbogram is not supported\n")); - ipsec6stat.out_inval++; + vnet->ipsec6stat.out_inval++; error = EINVAL; /* XXX */ goto bad; } @@ -2868,10 +2914,11 @@ * IPsec output logic for IPv6, tunnel mode. */ int -ipsec6_output_tunnel(state, sp, flags) +ipsec6_output_tunnel(state, sp, flags, vnet) struct ipsec_output_state *state; struct secpolicy *sp; int flags; + struct vnet *vnet; { struct ip6_hdr *ip6; struct ipsecrequest *isr = NULL; @@ -2887,6 +2934,8 @@ panic("state->m == NULL in ipsec6_output_tunnel"); if (!sp) panic("sp == NULL in ipsec6_output_tunnel"); + if (!vnet) + panic("vnet == NULL in ipsec6_output_tunnel"); KEYDEBUG(KEYDEBUG_IPSEC_DATA, printf("ipsec6_output_tunnel: applyed SP\n"); @@ -2943,7 +2992,7 @@ } } - if (key_checkrequest(isr, &saidx) == ENOENT) { + if (key_checkrequest(isr, &saidx, vnet) == ENOENT) { /* * IPsec processing is required, but no SA found. * I assume that key_acquire() had been called @@ -2951,14 +3000,14 @@ * this packet because it is responsibility for * upper layer to retransmit the packet. */ - ipsec6stat.out_nosa++; + vnet->ipsec6stat.out_nosa++; error = ENOENT; goto bad; } /* validity check */ if (isr->sav == NULL) { - switch (ipsec_get_reqlevel(isr)) { + switch (ipsec_get_reqlevel(isr, vnet)) { case IPSEC_LEVEL_USE: continue; case IPSEC_LEVEL_REQUIRE: @@ -2973,7 +3022,7 @@ */ if (isr->sav->state != SADB_SASTATE_MATURE && isr->sav->state != SADB_SASTATE_DYING) { - ipsec6stat.out_nosa++; + vnet->ipsec6stat.out_nosa++; error = EINVAL; goto bad; } @@ -2994,7 +3043,7 @@ "family mismatched between inner and outer, spi=%u\n", (u_int32_t)ntohl(isr->sav->spi))); splx(s); - ipsec6stat.out_inval++; + vnet->ipsec6stat.out_inval++; error = EAFNOSUPPORT; goto bad; } @@ -3002,11 +3051,11 @@ state->m = ipsec6_splithdr(state->m); if (!state->m) { splx(s); - ipsec6stat.out_nomem++; + vnet->ipsec6stat.out_nomem++; error = ENOMEM; goto bad; } - error = ipsec6_encapsulate(state->m, isr->sav); + error = ipsec6_encapsulate(state->m, isr->sav, vnet); splx(s); if (error) { state->m = 0; @@ -3028,11 +3077,11 @@ dst6->sin6_family = AF_INET6; dst6->sin6_len = sizeof(*dst6); dst6->sin6_addr = ip6->ip6_dst; - rtalloc(state->ro); + rtalloc(state->ro, vnet); } if (state->ro->ro_rt == 0) { - ip6stat.ip6s_noroute++; - ipsec6stat.out_noroute++; + vnet->ip6stat.ip6s_noroute++; + vnet->ipsec6stat.out_noroute++; error = EHOSTUNREACH; goto bad; } @@ -3047,7 +3096,7 @@ state->m = ipsec6_splithdr(state->m); if (!state->m) { - ipsec6stat.out_nomem++; + vnet->ipsec6stat.out_nomem++; error = ENOMEM; goto bad; } @@ -3055,7 +3104,7 @@ switch (isr->saidx.proto) { case IPPROTO_ESP: #ifdef IPSEC_ESP - error = esp6_output(state->m, &ip6->ip6_nxt, state->m->m_next, isr); + error = esp6_output(state->m, &ip6->ip6_nxt, state->m->m_next, isr, vnet); #else m_freem(state->m); error = EINVAL; @@ -3071,7 +3120,7 @@ ipseclog((LOG_ERR, "ipsec6_output_tunnel: " "unknown ipsec protocol %d\n", isr->saidx.proto)); m_freem(state->m); - ipsec6stat.out_inval++; + vnet->ipsec6stat.out_inval++; error = EINVAL; break; } @@ -3083,7 +3132,7 @@ if (plen > IPV6_MAXPACKET) { ipseclog((LOG_ERR, "ipsec6_output_tunnel: " "IPsec with IPv6 jumbogram is not supported\n")); - ipsec6stat.out_inval++; + vnet->ipsec6stat.out_inval++; error = EINVAL; /* XXX */ goto bad; } @@ -3193,7 +3242,11 @@ int hlen; struct secpolicy *sp; struct ip *oip; + struct vnet *vnet; + if (m == NULL || m->m_pkthdr.rcvif == NULL) + panic("ipsec4_tunnel_validate: cannot find vnet."); + vnet = m->m_pkthdr.rcvif->if_vnet; #ifdef DIAGNOSTIC if (m->m_len < sizeof(struct ip)) panic("too short mbuf on ipsec4_tunnel_validate"); @@ -3260,7 +3313,7 @@ */ sp = key_gettunnel((struct sockaddr *)&osrc, (struct sockaddr *)&odst, - (struct sockaddr *)&isrc, (struct sockaddr *)&idst); + (struct sockaddr *)&isrc, (struct sockaddr *)&idst, vnet); if (!sp) return 0; key_freesp(sp); @@ -3282,7 +3335,12 @@ struct sockaddr_in6 osrc, odst, isrc, idst; struct secpolicy *sp; struct ip6_hdr *oip6; + struct vnet *vnet; + if (m == NULL || m->m_pkthdr.rcvif == NULL) + panic("ipsec6_tunnel_validate: cannot find vnet."); + vnet = m->m_pkthdr.rcvif->if_vnet; + #ifdef DIAGNOSTIC if (m->m_len < sizeof(struct ip6_hdr)) panic("too short mbuf on ipsec6_tunnel_validate"); @@ -3325,7 +3383,7 @@ */ sp = key_gettunnel((struct sockaddr *)&osrc, (struct sockaddr *)&odst, - (struct sockaddr *)&isrc, (struct sockaddr *)&idst); + (struct sockaddr *)&isrc, (struct sockaddr *)&idst, vnet); /* * when there is no suitable inbound policy for the packet of the ipsec * tunnel mode, the kernel never decapsulate the tunneled packet diff -urN sys/netinet6/ipsec.h sys.CORE/netinet6/ipsec.h --- sys/netinet6/ipsec.h Wed Jan 31 15:57:05 2007 +++ sys.CORE/netinet6/ipsec.h Wed Jan 31 16:02:43 2007 @@ -285,6 +285,7 @@ extern int ipsec_debug; +#ifdef MOVED_TO_VNET extern struct ipsecstat ipsecstat; extern struct secpolicy ip4_def_policy; extern int ip4_esp_trans_deflev; @@ -296,34 +297,36 @@ extern int ip4_ipsec_dfbit; extern int ip4_ipsec_ecn; extern int ip4_esp_randpad; +#endif #define ipseclog(x) do { if (ipsec_debug) log x; } while (0) extern struct secpolicy *ipsec4_getpolicybysock __P((struct mbuf *, u_int, struct socket *, int *)); extern struct secpolicy *ipsec4_getpolicybyaddr - __P((struct mbuf *, u_int, int, int *)); + __P((struct mbuf *, u_int, int, int *, struct vnet *)); struct inpcb; extern int ipsec_init_policy __P((struct socket *so, struct inpcbpolicy **)); extern int ipsec_copy_policy __P((struct inpcbpolicy *, struct inpcbpolicy *)); -extern u_int ipsec_get_reqlevel __P((struct ipsecrequest *)); +extern u_int ipsec_get_reqlevel __P((struct ipsecrequest *, struct vnet *)); extern int ipsec4_set_policy __P((struct inpcb *inp, int optname, caddr_t request, size_t len, int priv)); extern int ipsec4_get_policy __P((struct inpcb *inpcb, caddr_t request, size_t len, struct mbuf **mp)); extern int ipsec4_delete_pcbpolicy __P((struct inpcb *)); -extern int ipsec4_in_reject_so __P((struct mbuf *, struct socket *)); -extern int ipsec4_in_reject __P((struct mbuf *, struct inpcb *)); +extern int ipsec4_in_reject_so __P((struct mbuf *, struct socket *, struct vnet *)); +extern int ipsec4_in_reject __P((struct mbuf *, struct inpcb *, struct vnet *)); struct secas; struct tcpcb; extern int ipsec_chkreplay __P((u_int32_t, struct secasvar *)); extern int ipsec_updatereplay __P((u_int32_t, struct secasvar *)); -extern size_t ipsec4_hdrsiz __P((struct mbuf *, u_int, struct inpcb *)); +extern size_t ipsec4_hdrsiz __P((struct mbuf *, u_int, struct inpcb *, + struct vnet *)); extern size_t ipsec_hdrsiz_tcp __P((struct tcpcb *)); struct ip; diff -urN sys/netinet6/ipsec6.h sys.CORE/netinet6/ipsec6.h --- sys/netinet6/ipsec6.h Tue Jul 3 04:01:54 2001 +++ sys.CORE/netinet6/ipsec6.h Wed Jan 31 16:02:43 2007 @@ -53,29 +53,29 @@ extern struct secpolicy *ipsec6_getpolicybysock __P((struct mbuf *, u_int, struct socket *, int *)); extern struct secpolicy *ipsec6_getpolicybyaddr - __P((struct mbuf *, u_int, int, int *)); + __P((struct mbuf *, u_int, int, int *, struct vnet *)); struct inpcb; -extern int ipsec6_in_reject_so __P((struct mbuf *, struct socket *)); +extern int ipsec6_in_reject_so __P((struct mbuf *, struct socket *, struct vnet *)); extern int ipsec6_delete_pcbpolicy __P((struct inpcb *)); extern int ipsec6_set_policy __P((struct inpcb *inp, int optname, caddr_t request, size_t len, int priv)); extern int ipsec6_get_policy __P((struct inpcb *inp, caddr_t request, size_t len, struct mbuf **mp)); -extern int ipsec6_in_reject __P((struct mbuf *, struct inpcb *)); +extern int ipsec6_in_reject __P((struct mbuf *, struct inpcb *, struct vnet *)); struct tcp6cb; -extern size_t ipsec6_hdrsiz __P((struct mbuf *, u_int, struct inpcb *)); +extern size_t ipsec6_hdrsiz __P((struct mbuf *, u_int, struct inpcb *, struct vnet *vnet)); struct ip6_hdr; extern const char *ipsec6_logpacketstr __P((struct ip6_hdr *, u_int32_t)); extern int ipsec6_output_trans __P((struct ipsec_output_state *, u_char *, - struct mbuf *, struct secpolicy *, int, int *)); + struct mbuf *, struct secpolicy *, int, int *, struct vnet *)); extern int ipsec6_output_tunnel __P((struct ipsec_output_state *, - struct secpolicy *, int)); + struct secpolicy *, int, struct vnet *)); extern int ipsec6_tunnel_validate __P((struct mbuf *, int, u_int, struct secasvar *)); #endif /*_KERNEL*/ diff -urN sys/netinet6/raw_ip6.c sys.CORE/netinet6/raw_ip6.c --- sys/netinet6/raw_ip6.c Wed Jan 31 15:57:05 2007 +++ sys.CORE/netinet6/raw_ip6.c Wed Jan 31 16:02:43 2007 @@ -168,9 +168,9 @@ /* * Check AH/ESP integrity. */ - if (n && ipsec6_in_reject_so(n, last->inp_socket)) { + if (n && ipsec6_in_reject_so(n, last->inp_socket, vnet)) { m_freem(n); - ipsec6stat.in_polvio++; + vnet->ipsec6stat.in_polvio++; /* do not inject data into pcb */ } else #endif /*IPSEC*/ @@ -207,10 +207,10 @@ /* * Check AH/ESP integrity. */ - if (last && ipsec6_in_reject_so(m, last->inp_socket)) { + if (last && ipsec6_in_reject_so(m, last->inp_socket, vnet)) { m_freem(m); - ipsec6stat.in_polvio++; - ip6stat.ip6s_delivered--; + vnet->ipsec6stat.in_polvio++; + vnet->ip6stat.ip6s_delivered--; /* do not inject data into pcb */ } else #endif /*IPSEC*/ @@ -220,7 +220,7 @@ */ if (last && ipsec6_in_reject(m, last)) { m_freem(m); - ip6stat.ip6s_delivered--; + vnet->ip6stat.ip6s_delivered--; /* do not inject data into pcb */ } else #endif /*FAST_IPSEC*/ diff -urN sys/netinet6/udp6_usrreq.c sys.CORE/netinet6/udp6_usrreq.c --- sys/netinet6/udp6_usrreq.c Wed Jan 31 15:57:05 2007 +++ sys.CORE/netinet6/udp6_usrreq.c Wed Jan 31 16:02:43 2007 @@ -260,8 +260,8 @@ /* * Check AH/ESP integrity. */ - if (ipsec6_in_reject_so(m, last->inp_socket)) - ipsec6stat.in_polvio++; + if (ipsec6_in_reject_so(m, last->inp_socket, vnet)) + vnet->ipsec6stat.in_polvio++; /* do not inject data into pcb */ else #endif /* IPSEC */ @@ -327,8 +327,8 @@ /* * Check AH/ESP integrity. */ - if (ipsec6_in_reject_so(m, last->inp_socket)) { - ipsec6stat.in_polvio++; + if (ipsec6_in_reject_so(m, last->inp_socket, vnet)) { + vnet->ipsec6stat.in_polvio++; goto bad; } #endif /* IPSEC */ @@ -383,8 +383,8 @@ /* * Check AH/ESP integrity. */ - if (ipsec6_in_reject_so(m, in6p->in6p_socket)) { - ipsec6stat.in_polvio++; + if (ipsec6_in_reject_so(m, in6p->in6p_socket, vnet)) { + vnet->ipsec6stat.in_polvio++; goto bad; } #endif /* IPSEC */ diff -urN sys/netipsec/ipsec.c sys.CORE/netipsec/ipsec.c --- sys/netipsec/ipsec.c Mon Jun 30 18:38:13 2003 +++ sys.CORE/netipsec/ipsec.c Wed Jan 31 16:02:43 2007 @@ -53,6 +53,7 @@ #include #include +#include #include #include @@ -123,31 +124,31 @@ SYSCTL_DECL(_net_inet_ipsec); /* net.inet.ipsec */ -SYSCTL_INT(_net_inet_ipsec, IPSECCTL_DEF_POLICY, +SYSCTL_V_INT(V_NET, _net_inet_ipsec, IPSECCTL_DEF_POLICY, def_policy, CTLFLAG_RW, &ip4_def_policy.policy, 0, ""); -SYSCTL_INT(_net_inet_ipsec, IPSECCTL_DEF_ESP_TRANSLEV, esp_trans_deflev, +SYSCTL_V_INT(V_NET, _net_inet_ipsec, IPSECCTL_DEF_ESP_TRANSLEV,esp_trans_deflev, CTLFLAG_RW, &ip4_esp_trans_deflev, 0, ""); -SYSCTL_INT(_net_inet_ipsec, IPSECCTL_DEF_ESP_NETLEV, esp_net_deflev, +SYSCTL_V_INT(V_NET, _net_inet_ipsec, IPSECCTL_DEF_ESP_NETLEV, esp_net_deflev, CTLFLAG_RW, &ip4_esp_net_deflev, 0, ""); -SYSCTL_INT(_net_inet_ipsec, IPSECCTL_DEF_AH_TRANSLEV, ah_trans_deflev, +SYSCTL_V_INT(V_NET, _net_inet_ipsec, IPSECCTL_DEF_AH_TRANSLEV, ah_trans_deflev, CTLFLAG_RW, &ip4_ah_trans_deflev, 0, ""); -SYSCTL_INT(_net_inet_ipsec, IPSECCTL_DEF_AH_NETLEV, ah_net_deflev, +SYSCTL_V_INT(V_NET, _net_inet_ipsec, IPSECCTL_DEF_AH_NETLEV, ah_net_deflev, CTLFLAG_RW, &ip4_ah_net_deflev, 0, ""); -SYSCTL_INT(_net_inet_ipsec, IPSECCTL_AH_CLEARTOS, +SYSCTL_V_INT(V_NET, _net_inet_ipsec, IPSECCTL_AH_CLEARTOS, ah_cleartos, CTLFLAG_RW, &ah_cleartos, 0, ""); -SYSCTL_INT(_net_inet_ipsec, IPSECCTL_AH_OFFSETMASK, +SYSCTL_V_INT(V_NET, _net_inet_ipsec, IPSECCTL_AH_OFFSETMASK, ah_offsetmask, CTLFLAG_RW, &ip4_ah_offsetmask, 0, ""); -SYSCTL_INT(_net_inet_ipsec, IPSECCTL_DFBIT, +SYSCTL_V_INT(V_NET, _net_inet_ipsec, IPSECCTL_DFBIT, dfbit, CTLFLAG_RW, &ip4_ipsec_dfbit, 0, ""); -SYSCTL_INT(_net_inet_ipsec, IPSECCTL_ECN, +SYSCTL_V_INT(V_NET, _net_inet_ipsec, IPSECCTL_ECN, ecn, CTLFLAG_RW, &ip4_ipsec_ecn, 0, ""); -SYSCTL_INT(_net_inet_ipsec, IPSECCTL_DEBUG, +SYSCTL_V_INT(V_NET, _net_inet_ipsec, IPSECCTL_DEBUG, debug, CTLFLAG_RW, &ipsec_debug, 0, ""); -SYSCTL_INT(_net_inet_ipsec, IPSECCTL_ESP_RANDPAD, +SYSCTL_V_INT(V_NET, _net_inet_ipsec, IPSECCTL_ESP_RANDPAD, esp_randpad, CTLFLAG_RW, &ip4_esp_randpad, 0, ""); -SYSCTL_INT(_net_inet_ipsec, OID_AUTO, +SYSCTL_V_INT(V_NET, _net_inet_ipsec, OID_AUTO, crypto_support, CTLFLAG_RW, &crypto_support,0, ""); -SYSCTL_STRUCT(_net_inet_ipsec, OID_AUTO, +SYSCTL_V_STRUCT(V_NET, _net_inet_ipsec, OID_AUTO, ipsecstats, CTLFLAG_RD, &newipsecstat, newipsecstat, ""); #ifdef INET6 @@ -165,21 +166,21 @@ SYSCTL_OID(_net_inet6_ipsec6, IPSECCTL_STATS, stats, CTLFLAG_RD, 0,0, compat_ipsecstats_sysctl, "S", ""); #endif /* COMPAT_KAME */ -SYSCTL_INT(_net_inet6_ipsec6, IPSECCTL_DEF_POLICY, +SYSCTL_V_INT(V_NET, _net_inet6_ipsec6, IPSECCTL_DEF_POLICY, def_policy, CTLFLAG_RW, &ip4_def_policy.policy, 0, ""); -SYSCTL_INT(_net_inet6_ipsec6, IPSECCTL_DEF_ESP_TRANSLEV, esp_trans_deflev, - CTLFLAG_RW, &ip6_esp_trans_deflev, 0, ""); -SYSCTL_INT(_net_inet6_ipsec6, IPSECCTL_DEF_ESP_NETLEV, esp_net_deflev, +SYSCTL_V_INT(V_NET, _net_inet6_ipsec6, IPSECCTL_DEF_ESP_TRANSLEV, + esp_trans_deflev, CTLFLAG_RW, &ip6_esp_trans_deflev, 0, ""); +SYSCTL_V_INT(V_NET, _net_inet6_ipsec6, IPSECCTL_DEF_ESP_NETLEV, esp_net_deflev, CTLFLAG_RW, &ip6_esp_net_deflev, 0, ""); -SYSCTL_INT(_net_inet6_ipsec6, IPSECCTL_DEF_AH_TRANSLEV, ah_trans_deflev, - CTLFLAG_RW, &ip6_ah_trans_deflev, 0, ""); -SYSCTL_INT(_net_inet6_ipsec6, IPSECCTL_DEF_AH_NETLEV, ah_net_deflev, +SYSCTL_V_INT(V_NET, _net_inet6_ipsec6, IPSECCTL_DEF_AH_TRANSLEV, + ah_trans_deflev, CTLFLAG_RW, &ip6_ah_trans_deflev, 0, ""); +SYSCTL_V_INT(V_NET, _net_inet6_ipsec6, IPSECCTL_DEF_AH_NETLEV, ah_net_deflev, CTLFLAG_RW, &ip6_ah_net_deflev, 0, ""); -SYSCTL_INT(_net_inet6_ipsec6, IPSECCTL_ECN, +SYSCTL_V_INT(V_NET, _net_inet6_ipsec6, IPSECCTL_ECN, ecn, CTLFLAG_RW, &ip6_ipsec_ecn, 0, ""); -SYSCTL_INT(_net_inet6_ipsec6, IPSECCTL_DEBUG, +SYSCTL_V_INT(V_NET, _net_inet6_ipsec6, IPSECCTL_DEBUG, debug, CTLFLAG_RW, &ipsec_debug, 0, ""); -SYSCTL_INT(_net_inet6_ipsec6, IPSECCTL_ESP_RANDPAD, +SYSCTL_V_INT(V_NET, _net_inet6_ipsec6, IPSECCTL_ESP_RANDPAD, esp_randpad, CTLFLAG_RW, &ip6_esp_randpad, 0, ""); #endif /* INET6 */ diff -urN sys/netipsec/key.c sys.CORE/netipsec/key.c --- sys/netipsec/key.c Sat Feb 14 14:23:23 2004 +++ sys.CORE/netipsec/key.c Wed Jan 31 16:02:43 2007 @@ -54,6 +54,7 @@ #include #include +#include #include #include #include @@ -203,51 +204,51 @@ SYSCTL_DECL(_net_key); #endif -SYSCTL_INT(_net_key, KEYCTL_DEBUG_LEVEL, debug, CTLFLAG_RW, \ +SYSCTL_V_INT(V_NET, _net_key, KEYCTL_DEBUG_LEVEL, debug, CTLFLAG_RW, \ &key_debug_level, 0, ""); /* max count of trial for the decision of spi value */ -SYSCTL_INT(_net_key, KEYCTL_SPI_TRY, spi_trycnt, CTLFLAG_RW, \ +SYSCTL_V_INT(V_NET, _net_key, KEYCTL_SPI_TRY, spi_trycnt, CTLFLAG_RW, \ &key_spi_trycnt, 0, ""); /* minimum spi value to allocate automatically. */ -SYSCTL_INT(_net_key, KEYCTL_SPI_MIN_VALUE, spi_minval, CTLFLAG_RW, \ +SYSCTL_V_INT(V_NET, _net_key, KEYCTL_SPI_MIN_VALUE, spi_minval, CTLFLAG_RW, \ &key_spi_minval, 0, ""); /* maximun spi value to allocate automatically. */ -SYSCTL_INT(_net_key, KEYCTL_SPI_MAX_VALUE, spi_maxval, CTLFLAG_RW, \ +SYSCTL_V_INT(V_NET, _net_key, KEYCTL_SPI_MAX_VALUE, spi_maxval, CTLFLAG_RW, \ &key_spi_maxval, 0, ""); /* interval to initialize randseed */ -SYSCTL_INT(_net_key, KEYCTL_RANDOM_INT, int_random, CTLFLAG_RW, \ +SYSCTL_V_INT(V_NET, _net_key, KEYCTL_RANDOM_INT, int_random, CTLFLAG_RW, \ &key_int_random, 0, ""); /* lifetime for larval SA */ -SYSCTL_INT(_net_key, KEYCTL_LARVAL_LIFETIME, larval_lifetime, CTLFLAG_RW, \ +SYSCTL_V_INT(V_NET, _net_key, KEYCTL_LARVAL_LIFETIME, larval_lifetime, CTLFLAG_RW, \ &key_larval_lifetime, 0, ""); /* counter for blocking to send SADB_ACQUIRE to IKEd */ -SYSCTL_INT(_net_key, KEYCTL_BLOCKACQ_COUNT, blockacq_count, CTLFLAG_RW, \ +SYSCTL_V_INT(V_NET, _net_key, KEYCTL_BLOCKACQ_COUNT,blockacq_count,CTLFLAG_RW, \ &key_blockacq_count, 0, ""); /* lifetime for blocking to send SADB_ACQUIRE to IKEd */ -SYSCTL_INT(_net_key, KEYCTL_BLOCKACQ_LIFETIME, blockacq_lifetime, CTLFLAG_RW, \ +SYSCTL_V_INT(V_NET, _net_key, KEYCTL_BLOCKACQ_LIFETIME, blockacq_lifetime, CTLFLAG_RW, \ &key_blockacq_lifetime, 0, ""); /* ESP auth */ -SYSCTL_INT(_net_key, KEYCTL_ESP_AUTH, esp_auth, CTLFLAG_RW, \ +SYSCTL_V_INT(V_NET, _net_key, KEYCTL_ESP_AUTH, esp_auth, CTLFLAG_RW, \ &ipsec_esp_auth, 0, ""); /* minimum ESP key length */ -SYSCTL_INT(_net_key, KEYCTL_ESP_KEYMIN, esp_keymin, CTLFLAG_RW, \ +SYSCTL_V_INT(V_NET, _net_key, KEYCTL_ESP_KEYMIN, esp_keymin, CTLFLAG_RW, \ &ipsec_esp_keymin, 0, ""); /* minimum AH key length */ -SYSCTL_INT(_net_key, KEYCTL_AH_KEYMIN, ah_keymin, CTLFLAG_RW, \ +SYSCTL_V_INT(V_NET, _net_key, KEYCTL_AH_KEYMIN, ah_keymin, CTLFLAG_RW, \ &ipsec_ah_keymin, 0, ""); /* perfered old SA rather than new SA */ -SYSCTL_INT(_net_key, KEYCTL_PREFERED_OLDSA, prefered_oldsa, CTLFLAG_RW,\ +SYSCTL_V_INT(V_NET, _net_key, KEYCTL_PREFERED_OLDSA,prefered_oldsa, CTLFLAG_RW,\ &key_prefered_oldsa, 0, ""); #ifndef LIST_FOREACH @@ -349,12 +350,13 @@ int extlen[SADB_EXT_MAX + 1]; }; -static struct secasvar *key_allocsa_policy __P((const struct secasindex *)); +static struct secasvar *key_allocsa_policy __P((const struct secasindex *, + struct vnet *)); static void key_freesp_so __P((struct secpolicy **)); static struct secasvar *key_do_allocsa_policy __P((struct secashead *, u_int)); static void key_delsp __P((struct secpolicy *)); -static struct secpolicy *key_getsp __P((struct secpolicyindex *)); -static struct secpolicy *key_getspbyid __P((u_int32_t)); +static struct secpolicy *key_getsp __P((struct secpolicyindex *, struct vnet*)); +static struct secpolicy *key_getspbyid __P((u_int32_t, struct vnet *)); static u_int32_t key_newreqid __P((void)); static struct mbuf *key_gather_mbuf __P((struct mbuf *, const struct sadb_msghdr *, int, int, ...)); @@ -523,7 +525,7 @@ * others: found and return the pointer. */ struct secpolicy * -key_allocsp(struct secpolicyindex *spidx, u_int dir, const char* where, int tag) +key_allocsp(struct secpolicyindex *spidx, u_int dir, const char* where, int tag, struct vnet *vnet) { struct secpolicy *sp; int s; @@ -541,7 +543,7 @@ printf("*** objects\n"); kdebug_secpolicyindex(spidx)); - LIST_FOREACH(sp, &sptree[dir], chain) { + LIST_FOREACH(sp, &vnet->sptree[dir], chain) { KEYDEBUG(KEYDEBUG_IPSEC_DATA, printf("*** in SPD\n"); kdebug_secpolicyindex(&sp->spidx)); @@ -580,7 +582,7 @@ union sockaddr_union *dst, u_int8_t proto, u_int dir, - const char* where, int tag) + const char* where, int tag, struct vnet *vnet) { struct secpolicy *sp; int s; @@ -599,7 +601,7 @@ printf("spi %u proto %u dir %u\n", spi, proto, dir); kdebug_sockaddr(&dst->sa)); - LIST_FOREACH(sp, &sptree[dir], chain) { + LIST_FOREACH(sp, &vnet->sptree[dir], chain) { KEYDEBUG(KEYDEBUG_IPSEC_DATA, printf("*** in SPD\n"); kdebug_secpolicyindex(&sp->spidx)); @@ -642,7 +644,7 @@ const struct sockaddr *odst, const struct sockaddr *isrc, const struct sockaddr *idst, - const char* where, int tag) + const char* where, int tag, struct vnet *vnet) { struct secpolicy *sp; const int dir = IPSEC_DIR_INBOUND; @@ -661,7 +663,7 @@ } s = splnet(); /*called from softclock()*/ - LIST_FOREACH(sp, &sptree[dir], chain) { + LIST_FOREACH(sp, &vnet->sptree[dir], chain) { if (sp->state == IPSEC_SPSTATE_DEAD) continue; @@ -817,7 +819,7 @@ struct secasvar *sav; u_int stateidx, state; - LIST_FOREACH(sah, &sahtree, chain) { + LIST_FOREACH(sah, &vnet->sahtree, chain) { if (sah->state == SADB_SASTATE_DEAD) continue; if (key_cmpsaidx(&sah->saidx, saidx, CMP_MODE_REQID)) @@ -991,7 +993,7 @@ union sockaddr_union *dst, u_int proto, u_int32_t spi, - const char* where, int tag) + const char* where, int tag, struct vnet *vnet) { struct secashead *sah; struct secasvar *sav; @@ -1010,7 +1012,7 @@ * encrypted so we can't check internal IP header. */ s = splnet(); /*called from softclock()*/ - LIST_FOREACH(sah, &sahtree, chain) { + LIST_FOREACH(sah, &vnet->sahtree, chain) { /* search valid state */ for (stateidx = 0; stateidx < _ARRAYLEN(saorder_state_valid); @@ -1213,13 +1215,13 @@ * others : found, pointer to a SP. */ static struct secpolicy * -key_getsp(struct secpolicyindex *spidx) +key_getsp(struct secpolicyindex *spidx, struct vnet *vnet) { struct secpolicy *sp; KASSERT(spidx != NULL, ("key_getsp: null spidx")); - LIST_FOREACH(sp, &sptree[spidx->dir], chain) { + LIST_FOREACH(sp, &vnet->sptree[spidx->dir], chain) { if (sp->state == IPSEC_SPSTATE_DEAD) continue; if (key_cmpspidx_exactly(spidx, &sp->spidx)) { @@ -1237,11 +1239,11 @@ * others : found, pointer to a SP. */ static struct secpolicy * -key_getspbyid(u_int32_t id) +key_getspbyid(u_int32_t id, struct vnet *vnet) { struct secpolicy *sp; - LIST_FOREACH(sp, &sptree[IPSEC_DIR_INBOUND], chain) { + LIST_FOREACH(sp, &vnet->sptree[IPSEC_DIR_INBOUND], chain) { if (sp->state == IPSEC_SPSTATE_DEAD) continue; if (sp->id == id) { @@ -1250,7 +1252,7 @@ } } - LIST_FOREACH(sp, &sptree[IPSEC_DIR_OUTBOUND], chain) { + LIST_FOREACH(sp, &vnet->sptree[IPSEC_DIR_OUTBOUND], chain) { if (sp->state == IPSEC_SPSTATE_DEAD) continue; if (sp->id == id) { @@ -7060,37 +7062,59 @@ } void -key_init() +key_init(vnet) + struct vnet *vnet; { int i; for (i = 0; i < IPSEC_DIR_MAX; i++) { - LIST_INIT(&sptree[i]); + LIST_INIT(&vnet->sptree[i]); } - LIST_INIT(&sahtree); + LIST_INIT(&vnet->sahtree); for (i = 0; i <= SADB_SATYPE_MAX; i++) { - LIST_INIT(®tree[i]); + LIST_INIT(&vnet->regtree[i]); } #ifndef IPSEC_NONBLOCK_ACQUIRE - LIST_INIT(&acqtree); + LIST_INIT(&vnet->acqtree); #endif - LIST_INIT(&spacqtree); + LIST_INIT(&vnet->spacqtree); /* system default */ - ip4_def_policy.policy = IPSEC_POLICY_NONE; - ip4_def_policy.refcnt++; /*never reclaim this*/ + vnet->ip4_def_policy.policy = IPSEC_POLICY_NONE; + vnet->ip4_def_policy.refcnt++; /*never reclaim this*/ #ifndef IPSEC_DEBUG2 timeout((void *)key_timehandler, (void *)0, hz); #endif /*IPSEC_DEBUG2*/ /* initialize key statistics */ - keystat.getspi_count = 1; + vnet->keystat.getspi_count = 1; + + /* initialize vars in struct vnet */ + vnet->acq_seq = 0; + vnet->ip4_ah_offsetmask = 0; + vnet->ip4_ipsec_dfbit = 0; + vnet->ip4_esp_trans_deflev = IPSEC_LEVEL_USE; + vnet->ip4_esp_net_deflev = IPSEC_LEVEL_USE; + vnet->ip4_ah_trans_deflev = IPSEC_LEVEL_USE; + vnet->ip4_ah_net_deflev = IPSEC_LEVEL_USE; + vnet->ip4_ipsec_ecn = 0; + vnet->ip4_esp_randpad = -1; + vnet->crypto_support = 0; +#ifdef INET6 + vnet->ip6_esp_trans_deflev = IPSEC_LEVEL_USE; + vnet->ip6_esp_net_deflev = IPSEC_LEVEL_USE; + vnet->ip6_ah_trans_deflev = IPSEC_LEVEL_USE; + vnet->ip6_ah_net_deflev = IPSEC_LEVEL_USE; + vnet->ip6_ipsec_ecn = 0; + vnet->ip6_esp_randpad = -1; +#endif - printf("IPsec: Initialized Security Association Processing.\n"); + if (vnet == vnet0) + printf("IPsec: Initialized Security Association Processing.\n"); return; } diff -urN sys/netipsec/keysock.c sys.CORE/netipsec/keysock.c --- sys/netipsec/keysock.c Thu Jan 23 21:11:36 2003 +++ sys.CORE/netipsec/keysock.c Wed Jan 31 16:02:43 2007 @@ -592,10 +592,11 @@ }; static void -key_init0(void) +key_init0(vnet) + struct vnet *vnet; { - bzero((caddr_t)&key_cb, sizeof(key_cb)); - key_init(); + bzero((caddr_t)&vnet->key_cb, sizeof(key_cb)); + key_init(vnet); } struct domain keydomain = diff -urN sys/netkey/key.c sys.CORE/netkey/key.c --- sys/netkey/key.c Thu Jan 13 14:47:18 2005 +++ sys.CORE/netkey/key.c Wed Jan 31 16:02:43 2007 @@ -107,6 +107,8 @@ #include #include +#include +#include #ifndef satosin #define satosin(s) ((struct sockaddr_in *)s) @@ -126,6 +128,7 @@ */ u_int32_t key_debug_level = 0; +#ifdef MOVED_TO_VNET static u_int key_spi_trycnt = 1000; static u_int32_t key_spi_minval = 0x100; static u_int32_t key_spi_maxval = 0x0fffffff; /* XXX */ @@ -149,6 +152,7 @@ static LIST_HEAD(_spacqtree, secspacq) spacqtree; /* SP acquiring list */ struct key_cb key_cb; +#endif /* MOVED_TO_VNET */ /* search order for SAs */ static const u_int saorder_state_valid_prefer_old[] = { @@ -223,32 +227,32 @@ &key_debug_level, 0, ""); /* max count of trial for the decision of spi value */ -SYSCTL_INT(_net_key, KEYCTL_SPI_TRY, spi_trycnt, CTLFLAG_RW, \ - &key_spi_trycnt, 0, ""); +SYSCTL_V_INT(V_NET, _net_key, KEYCTL_SPI_TRY, spi_trycnt, CTLFLAG_RW, \ + v_key_spi_trycnt, 0, ""); /* minimum spi value to allocate automatically. */ -SYSCTL_INT(_net_key, KEYCTL_SPI_MIN_VALUE, spi_minval, CTLFLAG_RW, \ - &key_spi_minval, 0, ""); +SYSCTL_V_INT(V_NET, _net_key, KEYCTL_SPI_MIN_VALUE, spi_minval, CTLFLAG_RW, \ + v_key_spi_minval, 0, ""); /* maximun spi value to allocate automatically. */ -SYSCTL_INT(_net_key, KEYCTL_SPI_MAX_VALUE, spi_maxval, CTLFLAG_RW, \ - &key_spi_maxval, 0, ""); +SYSCTL_V_INT(V_NET, _net_key, KEYCTL_SPI_MAX_VALUE, spi_maxval, CTLFLAG_RW, \ + v_key_spi_maxval, 0, ""); /* interval to initialize randseed */ -SYSCTL_INT(_net_key, KEYCTL_RANDOM_INT, int_random, CTLFLAG_RW, \ - &key_int_random, 0, ""); +SYSCTL_V_INT(V_NET, _net_key, KEYCTL_RANDOM_INT, int_random, CTLFLAG_RW, \ + v_key_int_random, 0, ""); /* lifetime for larval SA */ -SYSCTL_INT(_net_key, KEYCTL_LARVAL_LIFETIME, larval_lifetime, CTLFLAG_RW, \ - &key_larval_lifetime, 0, ""); +SYSCTL_V_INT(V_NET, _net_key, KEYCTL_LARVAL_LIFETIME, larval_lifetime, CTLFLAG_RW, \ + v_key_larval_lifetime, 0, ""); /* counter for blocking to send SADB_ACQUIRE to IKEd */ -SYSCTL_INT(_net_key, KEYCTL_BLOCKACQ_COUNT, blockacq_count, CTLFLAG_RW, \ - &key_blockacq_count, 0, ""); +SYSCTL_V_INT(V_NET, _net_key, KEYCTL_BLOCKACQ_COUNT, blockacq_count, CTLFLAG_RW, \ + v_key_blockacq_count, 0, ""); /* lifetime for blocking to send SADB_ACQUIRE to IKEd */ -SYSCTL_INT(_net_key, KEYCTL_BLOCKACQ_LIFETIME, blockacq_lifetime, CTLFLAG_RW, \ - &key_blockacq_lifetime, 0, ""); +SYSCTL_V_INT(V_NET, _net_key, KEYCTL_BLOCKACQ_LIFETIME, blockacq_lifetime, CTLFLAG_RW, \ + v_key_blockacq_lifetime, 0, ""); /* ESP auth */ SYSCTL_INT(_net_key, KEYCTL_ESP_AUTH, esp_auth, CTLFLAG_RW, \ @@ -263,8 +267,8 @@ &ipsec_ah_keymin, 0, ""); /* perfered old SA rather than new SA */ -SYSCTL_INT(_net_key, KEYCTL_PREFERED_OLDSA, prefered_oldsa, CTLFLAG_RW,\ - &key_preferred_oldsa, 0, ""); +SYSCTL_V_INT(V_NET, _net_key, KEYCTL_PREFERED_OLDSA, prefered_oldsa, CTLFLAG_RW,\ + v_key_preferred_oldsa, 0, ""); #ifndef LIST_FOREACH #define LIST_FOREACH(elm, head, field) \ @@ -352,9 +356,11 @@ } while (0) /* key statistics */ +#ifdef MOVED_TO_VNET struct _keystat { u_long getspi_count; /* the avarage of count to try to get new SPI */ } keystat; +#endif struct sadb_msghdr { struct sadb_msg *msg; @@ -363,18 +369,20 @@ int extlen[SADB_EXT_MAX + 1]; }; -static struct secasvar *key_allocsa_policy __P((struct secasindex *)); +static struct secasvar *key_allocsa_policy __P((struct secasindex *, + struct vnet *)); static void key_freesp_so __P((struct secpolicy **)); -static struct secasvar *key_do_allocsa_policy __P((struct secashead *, u_int)); +static struct secasvar *key_do_allocsa_policy __P((struct secashead *, u_int, + struct vnet *)); static void key_delsp __P((struct secpolicy *)); -static struct secpolicy *key_getsp __P((struct secpolicyindex *)); -static struct secpolicy *key_getspbyid __P((u_int32_t)); +static struct secpolicy *key_getsp __P((struct secpolicyindex *, struct vnet*)); +static struct secpolicy *key_getspbyid __P((u_int32_t, struct vnet*)); static u_int32_t key_newreqid __P((void)); static struct mbuf *key_gather_mbuf __P((struct mbuf *, const struct sadb_msghdr *, int, int, ...)); static int key_spdadd __P((struct socket *, struct mbuf *, const struct sadb_msghdr *)); -static u_int32_t key_getnewspid __P((void)); +static u_int32_t key_getnewspid __P((struct vnet *)); static int key_spddelete __P((struct socket *, struct mbuf *, const struct sadb_msghdr *)); static int key_spddelete2 __P((struct socket *, struct mbuf *, @@ -388,14 +396,15 @@ static struct mbuf *key_setdumpsp __P((struct secpolicy *, u_int8_t, u_int32_t, u_int32_t)); static u_int key_getspreqmsglen __P((struct secpolicy *)); -static int key_spdexpire __P((struct secpolicy *)); -static struct secashead *key_newsah __P((struct secasindex *)); +static int key_spdexpire __P((struct secpolicy *, struct vnet *)); +static struct secashead *key_newsah __P((struct secasindex *, struct vnet *)); static void key_delsah __P((struct secashead *)); static struct secasvar *key_newsav __P((struct mbuf *, const struct sadb_msghdr *, struct secashead *, int *)); static void key_delsav __P((struct secasvar *)); -static struct secashead *key_getsah __P((struct secasindex *)); -static struct secasvar *key_checkspidup __P((struct secasindex *, u_int32_t)); +static struct secashead *key_getsah __P((struct secasindex *, struct vnet *)); +static struct secasvar *key_checkspidup __P((struct secasindex *, u_int32_t, + struct vnet *)); static struct secasvar *key_getsavbyspi __P((struct secashead *, u_int32_t)); static int key_setsaval __P((struct secasvar *, struct mbuf *, const struct sadb_msghdr *)); @@ -416,7 +425,7 @@ u_int32_t)); static void *key_newbuf __P((const void *, u_int)); #ifdef INET6 -static int key_ismyaddr6 __P((struct sockaddr_in6 *)); +static int key_ismyaddr6 __P((struct sockaddr_in6 *, struct vnet *)); #endif /* flags for key_cmpsaidx() */ @@ -440,7 +449,8 @@ static int key_getspi __P((struct socket *, struct mbuf *, const struct sadb_msghdr *)); static u_int32_t key_do_getnewspi __P((struct sadb_spirange *, - struct secasindex *)); + struct secasindex *, + struct vnet *)); static int key_update __P((struct socket *, struct mbuf *, const struct sadb_msghdr *)); #ifdef IPSEC_DOSEQCHECK @@ -465,19 +475,20 @@ static struct mbuf *key_getcomb_ipcomp __P((void)); static struct mbuf *key_getprop __P((const struct secasindex *)); -static int key_acquire __P((struct secasindex *, struct secpolicy *)); +static int key_acquire __P((struct secasindex *, struct secpolicy *, + struct vnet *)); #ifndef IPSEC_NONBLOCK_ACQUIRE -static struct secacq *key_newacq __P((struct secasindex *)); -static struct secacq *key_getacq __P((struct secasindex *)); -static struct secacq *key_getacqbyseq __P((u_int32_t)); +static struct secacq *key_newacq __P((struct secasindex *, struct vnet *)); +static struct secacq *key_getacq __P((struct secasindex *, struct vnet *)); +static struct secacq *key_getacqbyseq __P((u_int32_t, struct vnet *)); #endif static struct secspacq *key_newspacq __P((struct secpolicyindex *)); -static struct secspacq *key_getspacq __P((struct secpolicyindex *)); +static struct secspacq *key_getspacq __P((struct secpolicyindex *, struct vnet *)); static int key_acquire2 __P((struct socket *, struct mbuf *, const struct sadb_msghdr *)); static int key_register __P((struct socket *, struct mbuf *, const struct sadb_msghdr *)); -static int key_expire __P((struct secasvar *)); +static int key_expire __P((struct secasvar *, struct vnet *vnet)); static int key_flush __P((struct socket *, struct mbuf *, const struct sadb_msghdr *)); static int key_dump __P((struct socket *, struct mbuf *, @@ -486,7 +497,7 @@ const struct sadb_msghdr *)); static int key_senderror __P((struct socket *, struct mbuf *, int)); static int key_validate_ext __P((const struct sadb_ext *, int)); -static int key_align __P((struct mbuf *, struct sadb_msghdr *)); +static int key_align __P((struct mbuf *, struct sadb_msghdr *, struct vnet *)); #if 0 static const char *key_getfqdn __P((void)); static const char *key_getuserfqdn __P((void)); @@ -502,9 +513,10 @@ * others: found and return the pointer. */ struct secpolicy * -key_allocsp(spidx, dir) +key_allocsp(spidx, dir, vnet) struct secpolicyindex *spidx; u_int dir; + struct vnet *vnet; { struct secpolicy *sp; struct timeval tv; @@ -513,6 +525,8 @@ /* sanity check */ if (spidx == NULL) panic("key_allocsp: NULL pointer is passed.\n"); + if (vnet == NULL) + panic("key_allocsp: NULL vnet is passed.\n"); /* check direction */ switch (dir) { @@ -529,7 +543,7 @@ printf("*** objects\n"); kdebug_secpolicyindex(spidx)); - LIST_FOREACH(sp, &sptree[dir], chain) { + LIST_FOREACH(sp, &vnet->sptree[dir], chain) { KEYDEBUG(KEYDEBUG_IPSEC_DATA, printf("*** in SPD\n"); kdebug_secpolicyindex(&sp->spidx)); @@ -564,8 +578,9 @@ * XXX slow */ struct secpolicy * -key_gettunnel(osrc, odst, isrc, idst) +key_gettunnel(osrc, odst, isrc, idst, vnet) struct sockaddr *osrc, *odst, *isrc, *idst; + struct vnet *vnet; { struct secpolicy *sp; const int dir = IPSEC_DIR_INBOUND; @@ -580,9 +595,11 @@ isrc->sa_family, idst->sa_family)); return NULL; } + if (vnet == NULL) + panic("key_gettunnel: NULL vnet is passed.\n"); s = splnet(); /*called from softclock()*/ - LIST_FOREACH(sp, &sptree[dir], chain) { + LIST_FOREACH(sp, &vnet->sptree[dir], chain) { if (sp->state == IPSEC_SPSTATE_DEAD) continue; @@ -639,9 +656,10 @@ * ENOENT: policy may be valid, but SA with REQUIRE is on acquiring. */ int -key_checkrequest(isr, saidx) +key_checkrequest(isr, saidx, vnet) struct ipsecrequest *isr; struct secasindex *saidx; + struct vnet *vnet; { u_int level; int error; @@ -649,6 +667,8 @@ /* sanity check */ if (isr == NULL || saidx == NULL) panic("key_checkrequest: NULL pointer is passed.\n"); + if (vnet == NULL) + panic("key_checkrequest: NULL vnet is passed.\n"); /* check mode */ switch (saidx->mode) { @@ -661,7 +681,7 @@ } /* get current level */ - level = ipsec_get_reqlevel(isr); + level = ipsec_get_reqlevel(isr, vnet); #if 0 /* @@ -704,14 +724,14 @@ * See key_do_allocsa_policy(), and draft-jenkins-ipsec-rekeying-03.txt. */ if (isr->sav == NULL) - isr->sav = key_allocsa_policy(saidx); + isr->sav = key_allocsa_policy(saidx, vnet); /* When there is SA. */ if (isr->sav != NULL) return 0; /* there is no SA */ - if ((error = key_acquire(saidx, isr->sp)) != 0) { + if ((error = key_acquire(saidx, isr->sp, vnet)) != 0) { /* XXX What should I do ? */ ipseclog((LOG_DEBUG, "key_checkrequest: error %d returned " "from key_acquire.\n", error)); @@ -728,8 +748,9 @@ * others: found and return the pointer. */ static struct secasvar * -key_allocsa_policy(saidx) +key_allocsa_policy(saidx, vnet) struct secasindex *saidx; + struct vnet *vnet; { struct secashead *sah; struct secasvar *sav; @@ -737,7 +758,9 @@ const u_int *saorder_state_valid; int arraysize; - LIST_FOREACH(sah, &sahtree, chain) { + if (vnet == NULL) + panic("key_allocsa_policy: NULL vnet is passed.\n"); + LIST_FOREACH(sah, &vnet->sahtree, chain) { if (sah->state == SADB_SASTATE_DEAD) continue; if (key_cmpsaidx(&sah->saidx, saidx, CMP_MODE_REQID)) @@ -752,7 +775,7 @@ * search a valid state list for outbound packet. * This search order is important. */ - if (key_preferred_oldsa) { + if (vnet->key_preferred_oldsa) { saorder_state_valid = saorder_state_valid_prefer_old; arraysize = _ARRAYLEN(saorder_state_valid_prefer_old); } else { @@ -764,7 +787,7 @@ state = saorder_state_valid[stateidx]; - sav = key_do_allocsa_policy(sah, state); + sav = key_do_allocsa_policy(sah, state, vnet); if (sav != NULL) return sav; } @@ -780,12 +803,15 @@ * others : found, pointer to a SA. */ static struct secasvar * -key_do_allocsa_policy(sah, state) +key_do_allocsa_policy(sah, state, vnet) struct secashead *sah; u_int state; + struct vnet *vnet; { struct secasvar *sav, *nextsav, *candidate, *d; + if (vnet == NULL) + panic("key_do_allocsa_policy: NULL vnet is passed.\n"); /* initilize */ candidate = NULL; @@ -812,7 +838,7 @@ "lifetime_current is NULL.\n"); /* What the best method is to compare ? */ - if (key_preferred_oldsa) { + if (vnet->key_preferred_oldsa) { if (candidate->lft_c->sadb_lifetime_addtime > sav->lft_c->sadb_lifetime_addtime) { candidate = sav; @@ -883,7 +909,7 @@ PFKEY_UNIT64(result->m_pkthdr.len); if (key_sendup_mbuf(NULL, result, - KEY_SENDUP_REGISTERED)) + KEY_SENDUP_REGISTERED, vnet)) goto msgfail; msgfail: key_freesav(d); @@ -916,10 +942,11 @@ * keep source address in IPsec SA. We see a tricky situation here. */ struct secasvar * -key_allocsa(family, src, dst, proto, spi) +key_allocsa(family, src, dst, proto, spi, vnet) u_int family, proto; caddr_t src, dst; u_int32_t spi; + struct vnet *vnet; { struct secashead *sah; struct secasvar *sav; @@ -933,12 +960,14 @@ /* sanity check */ if (src == NULL || dst == NULL) panic("key_allocsa: NULL pointer is passed.\n"); + if (vnet == NULL) + panic("key_allocsa: NULL vnet is passed.\n"); /* * when both systems employ similar strategy to use a SA. * the search order is important even in the inbound case. */ - if (key_preferred_oldsa) { + if (vnet->key_preferred_oldsa) { saorder_state_valid = saorder_state_valid_prefer_old; arraysize = _ARRAYLEN(saorder_state_valid_prefer_old); } else { @@ -953,7 +982,7 @@ * encrypted so we can't check internal IP header. */ s = splnet(); /*called from softclock()*/ - LIST_FOREACH(sah, &sahtree, chain) { + LIST_FOREACH(sah, &vnet->sahtree, chain) { /* * search a valid state list for inbound packet. * the search order is not important. @@ -1248,16 +1277,19 @@ * others : found, pointer to a SP. */ static struct secpolicy * -key_getsp(spidx) +key_getsp(spidx, vnet) struct secpolicyindex *spidx; + struct vnet *vnet; { struct secpolicy *sp; /* sanity check */ if (spidx == NULL) panic("key_getsp: NULL pointer is passed.\n"); + if (vnet == NULL) + panic("key_getsp: NULL vnet is passed.\n"); - LIST_FOREACH(sp, &sptree[spidx->dir], chain) { + LIST_FOREACH(sp, &vnet->sptree[spidx->dir], chain) { if (sp->state == IPSEC_SPSTATE_DEAD) continue; if (key_cmpspidx_exactly(spidx, &sp->spidx)) { @@ -1275,12 +1307,15 @@ * others : found, pointer to a SP. */ static struct secpolicy * -key_getspbyid(id) +key_getspbyid(id, vnet) u_int32_t id; + struct vnet *vnet; { struct secpolicy *sp; - LIST_FOREACH(sp, &sptree[IPSEC_DIR_INBOUND], chain) { + if (vnet == NULL) + panic("key_getspbyid: NULL vnet is passed.\n"); + LIST_FOREACH(sp, &vnet->sptree[IPSEC_DIR_INBOUND], chain) { if (sp->state == IPSEC_SPSTATE_DEAD) continue; if (sp->id == id) { @@ -1289,7 +1324,7 @@ } } - LIST_FOREACH(sp, &sptree[IPSEC_DIR_OUTBOUND], chain) { + LIST_FOREACH(sp, &vnet->sptree[IPSEC_DIR_OUTBOUND], chain) { if (sp->state == IPSEC_SPSTATE_DEAD) continue; if (sp->id == id) { @@ -1735,10 +1770,14 @@ struct secpolicy *newsp; struct timeval tv; int error; + struct vnet *vnet; /* sanity check */ if (so == NULL || m == NULL || mhp == NULL || mhp->msg == NULL) panic("key_spdadd: NULL pointer is passed.\n"); + vnet = so->so_vnet; + if (vnet == NULL) + panic("key_spdadd: NULL vnet pointer.\n"); if (mhp->ext[SADB_EXT_ADDRESS_SRC] == NULL || mhp->ext[SADB_EXT_ADDRESS_DST] == NULL || @@ -1808,7 +1847,7 @@ * If the type is either SPDADD or SPDSETIDX AND a SP is found, * then error. */ - newsp = key_getsp(&spidx); + newsp = key_getsp(&spidx, vnet); if (mhp->msg->sadb_msg_type == SADB_X_SPDUPDATE) { if (newsp) { newsp->state = IPSEC_SPSTATE_DEAD; @@ -1827,7 +1866,7 @@ return key_senderror(so, m, error); } - if ((newsp->id = key_getnewspid()) == 0) { + if ((newsp->id = key_getnewspid(vnet)) == 0) { keydb_delsecpolicy(newsp); return key_senderror(so, m, ENOBUFS); } @@ -1879,12 +1918,13 @@ newsp->refcnt = 1; /* do not reclaim until I say I do */ newsp->state = IPSEC_SPSTATE_ALIVE; - LIST_INSERT_TAIL(&sptree[newsp->spidx.dir], newsp, secpolicy, chain); + LIST_INSERT_TAIL(&vnet->sptree[newsp->spidx.dir], newsp, + secpolicy, chain); /* delete the entry in spacqtree */ if (mhp->msg->sadb_msg_type == SADB_X_SPDUPDATE) { struct secspacq *spacq; - if ((spacq = key_getspacq(&spidx)) != NULL) { + if ((spacq = key_getspacq(&spidx, vnet)) != NULL) { /* reset counter in order to deletion by timehandler. */ microtime(&tv); spacq->created = tv.tv_sec; @@ -1934,7 +1974,7 @@ xpl->sadb_x_policy_id = newsp->id; m_freem(m); - return key_sendup_mbuf(so, n, KEY_SENDUP_ALL); + return key_sendup_mbuf(so, n, KEY_SENDUP_ALL, vnet); } } @@ -1945,17 +1985,22 @@ * others: success. */ static u_int32_t -key_getnewspid() +key_getnewspid(vnet) + struct vnet *vnet; { u_int32_t newid = 0; - int count = key_spi_trycnt; /* XXX */ + int count; struct secpolicy *sp; + if (vnet == NULL) + panic("key_getnewspid: NULL vnet was passed."); + count = vnet->key_spi_trycnt; /* XXX */ /* when requesting to allocate spi ranged */ while (count--) { - newid = (policy_id = (policy_id == ~0 ? 1 : policy_id + 1)); + newid = (vnet->policy_id = (vnet->policy_id == ~0 ? + 1 : vnet->policy_id+1)); - if ((sp = key_getspbyid(newid)) == NULL) + if ((sp = key_getspbyid(newid, vnet)) == NULL) break; key_freesp(sp); @@ -1991,10 +2036,14 @@ struct sadb_x_policy *xpl0; struct secpolicyindex spidx; struct secpolicy *sp; + struct vnet *vnet; /* sanity check */ if (so == NULL || m == NULL || mhp == NULL || mhp->msg == NULL) panic("key_spddelete: NULL pointer is passed.\n"); + vnet = so->so_vnet; + if (vnet == NULL) + panic("key_spddelete: NULL vnet pointer.\n"); if (mhp->ext[SADB_EXT_ADDRESS_SRC] == NULL || mhp->ext[SADB_EXT_ADDRESS_DST] == NULL || @@ -2034,7 +2083,7 @@ } /* Is there SP in SPD ? */ - if ((sp = key_getsp(&spidx)) == NULL) { + if ((sp = key_getsp(&spidx, vnet)) == NULL) { ipseclog((LOG_DEBUG, "key_spddelete: no SP found.\n")); return key_senderror(so, m, EINVAL); } @@ -2060,7 +2109,7 @@ newmsg->sadb_msg_len = PFKEY_UNIT64(n->m_pkthdr.len); m_freem(m); - return key_sendup_mbuf(so, n, KEY_SENDUP_ALL); + return key_sendup_mbuf(so, n, KEY_SENDUP_ALL, vnet); } } @@ -2084,10 +2133,14 @@ { u_int32_t id; struct secpolicy *sp; + struct vnet *vnet; /* sanity check */ if (so == NULL || m == NULL || mhp == NULL || mhp->msg == NULL) panic("key_spddelete2: NULL pointer is passed.\n"); + vnet = so->so_vnet; + if (vnet == NULL) + panic("key_spddelete2: NULL vnet pointer.\n"); if (mhp->ext[SADB_X_EXT_POLICY] == NULL || mhp->extlen[SADB_X_EXT_POLICY] < sizeof(struct sadb_x_policy)) { @@ -2099,7 +2152,7 @@ id = ((struct sadb_x_policy *)mhp->ext[SADB_X_EXT_POLICY])->sadb_x_policy_id; /* Is there SP in SPD ? */ - if ((sp = key_getspbyid(id)) == NULL) { + if ((sp = key_getspbyid(id, vnet)) == NULL) { ipseclog((LOG_DEBUG, "key_spddelete2: no SP found id:%u.\n", id)); key_senderror(so, m, EINVAL); } @@ -2156,7 +2209,7 @@ newmsg->sadb_msg_len = PFKEY_UNIT64(n->m_pkthdr.len); m_freem(m); - return key_sendup_mbuf(so, n, KEY_SENDUP_ALL); + return key_sendup_mbuf(so, n, KEY_SENDUP_ALL, vnet); } } @@ -2181,10 +2234,14 @@ u_int32_t id; struct secpolicy *sp; struct mbuf *n; + struct vnet *vnet; /* sanity check */ if (so == NULL || m == NULL || mhp == NULL || mhp->msg == NULL) panic("key_spdget: NULL pointer is passed.\n"); + vnet = so->so_vnet; + if (vnet == NULL) + panic("key_spdget: NULL vnet pointer.\n"); if (mhp->ext[SADB_X_EXT_POLICY] == NULL || mhp->extlen[SADB_X_EXT_POLICY] < sizeof(struct sadb_x_policy)) { @@ -2195,7 +2252,7 @@ id = ((struct sadb_x_policy *)mhp->ext[SADB_X_EXT_POLICY])->sadb_x_policy_id; /* Is there SP in SPD ? */ - if ((sp = key_getspbyid(id)) == NULL) { + if ((sp = key_getspbyid(id, vnet)) == NULL) { ipseclog((LOG_DEBUG, "key_spdget: no SP found id:%u.\n", id)); return key_senderror(so, m, ENOENT); } @@ -2203,7 +2260,7 @@ n = key_setdumpsp(sp, SADB_X_SPDGET, 0, mhp->msg->sadb_msg_pid); if (n != NULL) { m_freem(m); - return key_sendup_mbuf(so, n, KEY_SENDUP_ONE); + return key_sendup_mbuf(so, n, KEY_SENDUP_ONE, vnet); } else return key_senderror(so, m, ENOBUFS); } @@ -2224,8 +2281,9 @@ * others: error number */ int -key_spdacquire(sp) +key_spdacquire(sp, vnet) struct secpolicy *sp; + struct vnet *vnet; { struct mbuf *result = NULL, *m; struct secspacq *newspacq; @@ -2238,10 +2296,12 @@ panic("key_spdacquire: called but there is request.\n"); if (sp->policy != IPSEC_POLICY_IPSEC) panic("key_spdacquire: policy mismathed. IPsec is expected.\n"); + if (vnet == NULL) + panic("key_spdacquire: NULL vnet is passed.\n"); /* get a entry to check whether sent message or not. */ - if ((newspacq = key_getspacq(&sp->spidx)) != NULL) { - if (key_blockacq_count < newspacq->count) { + if ((newspacq = key_getspacq(&sp->spidx, vnet)) != NULL) { + if (vnet->key_blockacq_count < newspacq->count) { /* reset counter and do send message. */ newspacq->count = 0; } else { @@ -2255,7 +2315,7 @@ return ENOBUFS; /* add to acqtree */ - LIST_INSERT_HEAD(&spacqtree, newspacq, chain); + LIST_INSERT_HEAD(&vnet->spacqtree, newspacq, chain); } /* create new sadb_msg to reply. */ @@ -2273,7 +2333,7 @@ mtod(result, struct sadb_msg *)->sadb_msg_len = PFKEY_UNIT64(result->m_pkthdr.len); - return key_sendup_mbuf(NULL, m, KEY_SENDUP_REGISTERED); + return key_sendup_mbuf(NULL, m, KEY_SENDUP_REGISTERED, vnet); fail: if (result) @@ -2302,16 +2362,20 @@ struct sadb_msg *newmsg; struct secpolicy *sp; u_int dir; + struct vnet *vnet; /* sanity check */ if (so == NULL || m == NULL || mhp == NULL || mhp->msg == NULL) panic("key_spdflush: NULL pointer is passed.\n"); + vnet = so->so_vnet; + if (vnet == NULL) + panic("key_spdflush: NULL vnet pointer.\n"); if (m->m_len != PFKEY_ALIGN8(sizeof(struct sadb_msg))) return key_senderror(so, m, EINVAL); for (dir = 0; dir < IPSEC_DIR_MAX; dir++) { - LIST_FOREACH(sp, &sptree[dir], chain) { + LIST_FOREACH(sp, &vnet->sptree[dir], chain) { sp->state = IPSEC_SPSTATE_DEAD; } } @@ -2329,7 +2393,7 @@ newmsg->sadb_msg_errno = 0; newmsg->sadb_msg_len = PFKEY_UNIT64(m->m_pkthdr.len); - return key_sendup_mbuf(so, m, KEY_SENDUP_ALL); + return key_sendup_mbuf(so, m, KEY_SENDUP_ALL, vnet); } /* @@ -2353,15 +2417,19 @@ int cnt; u_int dir; struct mbuf *n; + struct vnet *vnet; /* sanity check */ if (so == NULL || m == NULL || mhp == NULL || mhp->msg == NULL) panic("key_spddump: NULL pointer is passed.\n"); + vnet = so->so_vnet; + if (vnet == NULL) + panic("key_spddump: NULL vnet pointer.\n"); /* search SPD entry and get buffer size. */ cnt = 0; for (dir = 0; dir < IPSEC_DIR_MAX; dir++) { - LIST_FOREACH(sp, &sptree[dir], chain) { + LIST_FOREACH(sp, &vnet->sptree[dir], chain) { cnt++; } } @@ -2370,13 +2438,13 @@ return key_senderror(so, m, ENOENT); for (dir = 0; dir < IPSEC_DIR_MAX; dir++) { - LIST_FOREACH(sp, &sptree[dir], chain) { + LIST_FOREACH(sp, &vnet->sptree[dir], chain) { --cnt; n = key_setdumpsp(sp, SADB_X_SPDDUMP, cnt, mhp->msg->sadb_msg_pid); if (n) - key_sendup_mbuf(so, n, KEY_SENDUP_ONE); + key_sendup_mbuf(so, n, KEY_SENDUP_ONE, vnet); } } @@ -2481,8 +2549,9 @@ * others : error number */ static int -key_spdexpire(sp) +key_spdexpire(sp, vnet) struct secpolicy *sp; + struct vnet *vnet; { int s; struct mbuf *result = NULL, *m; @@ -2496,6 +2565,8 @@ /* sanity check */ if (sp == NULL) panic("key_spdexpire: NULL pointer is passed.\n"); + if (vnet == NULL) + panic("key_spdexpire: NULL vnet is passed.\n"); /* set msg header */ m = key_setsadbmsg(SADB_X_SPDEXPIRE, 0, 0, 0, 0, 0); @@ -2580,7 +2651,7 @@ PFKEY_UNIT64(result->m_pkthdr.len); splx(s); - return key_sendup_mbuf(NULL, result, KEY_SENDUP_REGISTERED); + return key_sendup_mbuf(NULL, result, KEY_SENDUP_REGISTERED, vnet); fail: if (result) @@ -2596,14 +2667,17 @@ * others : pointer to new SA head. */ static struct secashead * -key_newsah(saidx) +key_newsah(saidx, vnet) struct secasindex *saidx; + struct vnet *vnet; { struct secashead *newsah; /* sanity check */ if (saidx == NULL) panic("key_newsaidx: NULL pointer is passed.\n"); + if (vnet == NULL) + panic("key_newsaidx: NULL vnet is passed.\n"); newsah = keydb_newsecashead(); if (newsah == NULL) @@ -2613,7 +2687,7 @@ /* add to saidxtree */ newsah->state = SADB_SASTATE_MATURE; - LIST_INSERT_HEAD(&sahtree, newsah, chain); + LIST_INSERT_HEAD(&vnet->sahtree, newsah, chain); return(newsah); } @@ -2846,12 +2920,15 @@ * others : found, pointer to a SA. */ static struct secashead * -key_getsah(saidx) +key_getsah(saidx, vnet) struct secasindex *saidx; + struct vnet *vnet; { struct secashead *sah; - LIST_FOREACH(sah, &sahtree, chain) { + if (vnet == NULL) + panic("key_getsah: NULL vnet was passed."); + LIST_FOREACH(sah, &vnet->sahtree, chain) { if (sah->state == SADB_SASTATE_DEAD) continue; if (key_cmpsaidx(&sah->saidx, saidx, CMP_REQID)) @@ -2869,13 +2946,16 @@ * others : found, pointer to a SA. */ static struct secasvar * -key_checkspidup(saidx, spi) +key_checkspidup(saidx, spi, vnet) struct secasindex *saidx; u_int32_t spi; + struct vnet *vnet; { struct secashead *sah; struct secasvar *sav; + if (vnet == NULL) + panic("key_checkspidup: NULL vnet was passed."); /* check address family */ if (saidx->src.ss_family != saidx->dst.ss_family) { ipseclog((LOG_DEBUG, "key_checkspidup: address family mismatched.\n")); @@ -2883,8 +2963,8 @@ } /* check all SAD */ - LIST_FOREACH(sah, &sahtree, chain) { - if (!key_ismyaddr((struct sockaddr *)&sah->saidx.dst)) + LIST_FOREACH(sah, &vnet->sahtree, chain) { + if (!key_ismyaddr((struct sockaddr *)&sah->saidx.dst, vnet)) continue; sav = key_getsavbyspi(sah, spi); if (sav != NULL) @@ -3794,8 +3874,9 @@ * 0: false */ int -key_ismyaddr(sa) +key_ismyaddr(sa, vnet) struct sockaddr *sa; + struct vnet *vnet; { #ifdef INET struct sockaddr_in *sin; @@ -3805,12 +3886,14 @@ /* sanity check */ if (sa == NULL) panic("key_ismyaddr: NULL pointer is passed.\n"); + if (vnet == NULL) + panic("key_ismyaddr: NULL vnet was passed."); switch (sa->sa_family) { #ifdef INET case AF_INET: sin = (struct sockaddr_in *)sa; - for (ia = in_ifaddrhead.tqh_first; ia; + for (ia = vnet->in_ifaddrhead.tqh_first; ia; ia = ia->ia_link.tqe_next) { if (sin->sin_family == ia->ia_addr.sin_family && @@ -3824,7 +3907,7 @@ #endif #ifdef INET6 case AF_INET6: - return key_ismyaddr6((struct sockaddr_in6 *)sa); + return key_ismyaddr6((struct sockaddr_in6 *)sa, vnet); #endif } @@ -3841,13 +3924,16 @@ #include static int -key_ismyaddr6(sin6) +key_ismyaddr6(sin6, vnet) struct sockaddr_in6 *sin6; + struct vnet *vnet; { struct in6_ifaddr *ia; struct in6_multi *in6m; - for (ia = in6_ifaddr; ia; ia = ia->ia_next) { + if (vnet == NULL) + panic("key_ismyaddr6: NULL vnet was passed."); + for (ia = vnet->in6_ifaddr; ia; ia = ia->ia_next) { if (key_sockaddrcmp((struct sockaddr *)&sin6, (struct sockaddr *)&ia->ia_addr, 0) == 0) return 1; @@ -4178,17 +4264,22 @@ u_int dir; int s; struct timeval tv; + struct vnet *vnet; microtime(&tv); s = splnet(); /*called from softclock()*/ + /* This timer function is called once to step through every vnet. */ + LIST_FOREACH(vnet, &vnet_head, vnet_le) + { + /* SPD */ { struct secpolicy *sp, *nextsp; for (dir = 0; dir < IPSEC_DIR_MAX; dir++) { - for (sp = LIST_FIRST(&sptree[dir]); + for (sp = LIST_FIRST(&vnet->sptree[dir]); sp != NULL; sp = nextsp) { @@ -4208,7 +4299,7 @@ || (sp->validtime && tv.tv_sec - sp->lastused > sp->validtime)) { sp->state = IPSEC_SPSTATE_DEAD; - key_spdexpire(sp); + key_spdexpire(sp, vnet); continue; } } @@ -4220,7 +4311,7 @@ struct secashead *sah, *nextsah; struct secasvar *sav, *nextsav; - for (sah = LIST_FIRST(&sahtree); + for (sah = LIST_FIRST(&vnet->sahtree); sah != NULL; sah = nextsah) { @@ -4239,7 +4330,7 @@ nextsav = LIST_NEXT(sav, chain); - if (tv.tv_sec - sav->created > key_larval_lifetime) { + if (tv.tv_sec - sav->created > vnet->key_larval_lifetime) { key_freesav(sav); } } @@ -4284,7 +4375,7 @@ * message in the status of * DYING. Do remove below code. */ - key_expire(sav); + key_expire(sav, vnet); } } @@ -4303,7 +4394,7 @@ * message in the status of * DYING. Do remove below code. */ - key_expire(sav); + key_expire(sav, vnet); } } @@ -4387,13 +4478,13 @@ { struct secacq *acq, *nextacq; - for (acq = LIST_FIRST(&acqtree); + for (acq = LIST_FIRST(&vnet->acqtree); acq != NULL; acq = nextacq) { nextacq = LIST_NEXT(acq, chain); - if (tv.tv_sec - acq->created > key_blockacq_lifetime + if (tv.tv_sec - acq->created > vnet->key_blockacq_lifetime && __LIST_CHAINED(acq)) { LIST_REMOVE(acq, chain); KFREE(acq); @@ -4406,13 +4497,13 @@ { struct secspacq *acq, *nextacq; - for (acq = LIST_FIRST(&spacqtree); + for (acq = LIST_FIRST(&vnet->spacqtree); acq != NULL; acq = nextacq) { nextacq = LIST_NEXT(acq, chain); - if (tv.tv_sec - acq->created > key_blockacq_lifetime + if (tv.tv_sec - acq->created > vnet->key_blockacq_lifetime && __LIST_CHAINED(acq)) { LIST_REMOVE(acq, chain); KFREE(acq); @@ -4421,11 +4512,13 @@ } /* initialize random seed */ - if (key_tick_init_random++ > key_int_random) { - key_tick_init_random = 0; + if (vnet->key_tick_init_random++ > vnet->key_int_random) { + vnet->key_tick_init_random = 0; key_srandom(); } + /* end LIST_FOREACH(vnet, ...) */ + } #ifndef IPSEC_DEBUG2 /* do exchange to tick time !! */ (void)timeout((void *)key_timehandler, (void *)0, hz); @@ -4562,10 +4655,14 @@ u_int8_t mode; u_int32_t reqid; int error; + struct vnet *vnet; /* sanity check */ if (so == NULL || m == NULL || mhp == NULL || mhp->msg == NULL) panic("key_getspi: NULL pointer is passed.\n"); + vnet = so->so_vnet; + if (vnet == NULL) + panic("key_getspi: cannot find vnet.\n"); if (mhp->ext[SADB_EXT_ADDRESS_SRC] == NULL || mhp->ext[SADB_EXT_ADDRESS_DST] == NULL) { @@ -4633,14 +4730,14 @@ /* SPI allocation */ spi = key_do_getnewspi((struct sadb_spirange *)mhp->ext[SADB_EXT_SPIRANGE], - &saidx); + &saidx, vnet); if (spi == 0) return key_senderror(so, m, EINVAL); /* get a SA index */ - if ((newsah = key_getsah(&saidx)) == NULL) { + if ((newsah = key_getsah(&saidx, vnet)) == NULL) { /* create a new SA index */ - if ((newsah = key_newsah(&saidx)) == NULL) { + if ((newsah = key_newsah(&saidx, vnet)) == NULL) { ipseclog((LOG_DEBUG, "key_getspi: No more memory.\n")); return key_senderror(so, m, ENOBUFS); } @@ -4661,7 +4758,7 @@ /* delete the entry in acqtree */ if (mhp->msg->sadb_msg_seq != 0) { struct secacq *acq; - if ((acq = key_getacqbyseq(mhp->msg->sadb_msg_seq)) != NULL) { + if ((acq = key_getacqbyseq(mhp->msg->sadb_msg_seq, vnet)) != NULL) { /* reset counter in order to deletion by timehandler. */ struct timeval tv; microtime(&tv); @@ -4722,7 +4819,7 @@ if (n->m_len < sizeof(struct sadb_msg)) { n = m_pullup(n, sizeof(struct sadb_msg)); if (n == NULL) - return key_sendup_mbuf(so, m, KEY_SENDUP_ONE); + return key_sendup_mbuf(so, m, KEY_SENDUP_ONE, vnet); } n->m_pkthdr.len = 0; @@ -4735,7 +4832,7 @@ newmsg->sadb_msg_len = PFKEY_UNIT64(n->m_pkthdr.len); m_freem(m); - return key_sendup_mbuf(so, n, KEY_SENDUP_ONE); + return key_sendup_mbuf(so, n, KEY_SENDUP_ONE, vnet); } } @@ -4747,21 +4844,26 @@ * others: success. */ static u_int32_t -key_do_getnewspi(spirange, saidx) +key_do_getnewspi(spirange, saidx, vnet) struct sadb_spirange *spirange; struct secasindex *saidx; + struct vnet *vnet; { u_int32_t newspi; u_int32_t min, max; - int count = key_spi_trycnt; + int count; + + if (vnet == NULL) + panic("key_do_getnewspi: NULL vnet was passed."); + count = vnet->key_spi_trycnt; /* set spi range to allocate */ if (spirange != NULL) { min = spirange->sadb_spirange_min; max = spirange->sadb_spirange_max; } else { - min = key_spi_minval; - max = key_spi_maxval; + min = vnet->key_spi_minval; + max = vnet->key_spi_maxval; } /* IPCOMP needs 2-byte SPI */ if (saidx->proto == IPPROTO_IPCOMP) { @@ -4776,7 +4878,7 @@ } if (min == max) { - if (key_checkspidup(saidx, min) != NULL) { + if (key_checkspidup(saidx, min, vnet) != NULL) { ipseclog((LOG_DEBUG, "key_do_getnewspi: SPI %u exists already.\n", min)); return 0; } @@ -4794,7 +4896,7 @@ /* generate pseudo-random SPI value ranged. */ newspi = min + (key_random() % (max - min + 1)); - if (key_checkspidup(saidx, newspi) == NULL) + if (key_checkspidup(saidx, newspi, vnet) == NULL) break; } @@ -4805,8 +4907,8 @@ } /* statistics */ - keystat.getspi_count = - (keystat.getspi_count + key_spi_trycnt - count) / 2; + vnet->keystat.getspi_count = + (vnet->keystat.getspi_count + vnet->key_spi_trycnt - count)/2; return newspi; } @@ -4839,10 +4941,14 @@ u_int8_t mode; u_int32_t reqid; int error; + struct vnet *vnet; /* sanity check */ if (so == NULL || m == NULL || mhp == NULL || mhp->msg == NULL) panic("key_update: NULL pointer is passed.\n"); + vnet = so->so_vnet; + if (vnet == NULL) + panic("key_update: cannot find vnet.\n"); /* map satype to proto */ if ((proto = key_satype2proto(mhp->msg->sadb_msg_satype)) == 0) { @@ -4887,7 +4993,7 @@ KEY_SETSECASIDX(proto, mode, reqid, src0 + 1, dst0 + 1, &saidx); /* get a SA header */ - if ((sah = key_getsah(&saidx)) == NULL) { + if ((sah = key_getsah(&saidx, vnet)) == NULL) { ipseclog((LOG_DEBUG, "key_update: no SA index found.\n")); return key_senderror(so, m, ENOENT); } @@ -4963,7 +5069,7 @@ } m_freem(m); - return key_sendup_mbuf(so, n, KEY_SENDUP_ALL); + return key_sendup_mbuf(so, n, KEY_SENDUP_ALL, vnet); } } @@ -5034,10 +5140,14 @@ u_int8_t mode; u_int32_t reqid; int error; + struct vnet *vnet; /* sanity check */ if (so == NULL || m == NULL || mhp == NULL || mhp->msg == NULL) panic("key_add: NULL pointer is passed.\n"); + vnet = so->so_vnet; + if (vnet == NULL) + panic("key_add: NULL vnet pointer is passed.\n"); /* map satype to proto */ if ((proto = key_satype2proto(mhp->msg->sadb_msg_satype)) == 0) { @@ -5082,9 +5192,9 @@ KEY_SETSECASIDX(proto, mode, reqid, src0 + 1, dst0 + 1, &saidx); /* get a SA header */ - if ((newsah = key_getsah(&saidx)) == NULL) { + if ((newsah = key_getsah(&saidx, vnet)) == NULL) { /* create a new SA header */ - if ((newsah = key_newsah(&saidx)) == NULL) { + if ((newsah = key_newsah(&saidx, vnet)) == NULL) { ipseclog((LOG_DEBUG, "key_add: No more memory.\n")); return key_senderror(so, m, ENOBUFS); } @@ -5130,7 +5240,7 @@ } m_freem(m); - return key_sendup_mbuf(so, n, KEY_SENDUP_ALL); + return key_sendup_mbuf(so, n, KEY_SENDUP_ALL, vnet); } } @@ -5265,10 +5375,14 @@ struct secashead *sah; struct secasvar *sav = NULL; u_int16_t proto; + struct vnet *vnet; /* sanity check */ if (so == NULL || m == NULL || mhp == NULL || mhp->msg == NULL) panic("key_delete: NULL pointer is passed.\n"); + vnet = so->so_vnet; + if (vnet == NULL) + panic("key_delete: NULL vnet pointer is passed.\n"); /* map satype to proto */ if ((proto = key_satype2proto(mhp->msg->sadb_msg_satype)) == 0) { @@ -5309,7 +5423,7 @@ KEY_SETSECASIDX(proto, IPSEC_MODE_ANY, 0, src0 + 1, dst0 + 1, &saidx); /* get a SA header */ - LIST_FOREACH(sah, &sahtree, chain) { + LIST_FOREACH(sah, &vnet->sahtree, chain) { if (sah->state == SADB_SASTATE_DEAD) continue; if (key_cmpsaidx(&sah->saidx, &saidx, CMP_HEAD) == 0) @@ -5349,7 +5463,7 @@ newmsg->sadb_msg_len = PFKEY_UNIT64(n->m_pkthdr.len); m_freem(m); - return key_sendup_mbuf(so, n, KEY_SENDUP_ALL); + return key_sendup_mbuf(so, n, KEY_SENDUP_ALL, vnet); } } @@ -5368,6 +5482,11 @@ struct secashead *sah; struct secasvar *sav, *nextsav; u_int stateidx, state; + struct vnet *vnet; + + if (so == NULL || so->so_vnet == NULL) + panic("key_delete_all: cannot find vnet.\n"); + vnet = so->so_vnet; src0 = (struct sadb_address *)(mhp->ext[SADB_EXT_ADDRESS_SRC]); dst0 = (struct sadb_address *)(mhp->ext[SADB_EXT_ADDRESS_DST]); @@ -5375,7 +5494,7 @@ /* XXX boundary check against sa_len */ KEY_SETSECASIDX(proto, IPSEC_MODE_ANY, 0, src0 + 1, dst0 + 1, &saidx); - LIST_FOREACH(sah, &sahtree, chain) { + LIST_FOREACH(sah, &vnet->sahtree, chain) { if (sah->state == SADB_SASTATE_DEAD) continue; if (key_cmpsaidx(&sah->saidx, &saidx, CMP_HEAD) == 0) @@ -5425,7 +5544,7 @@ newmsg->sadb_msg_len = PFKEY_UNIT64(n->m_pkthdr.len); m_freem(m); - return key_sendup_mbuf(so, n, KEY_SENDUP_ALL); + return key_sendup_mbuf(so, n, KEY_SENDUP_ALL, vnet); } } @@ -5453,10 +5572,14 @@ struct secashead *sah; struct secasvar *sav = NULL; u_int16_t proto; + struct vnet *vnet; /* sanity check */ if (so == NULL || m == NULL || mhp == NULL || mhp->msg == NULL) panic("key_get: NULL pointer is passed.\n"); + vnet = so->so_vnet; + if (vnet == NULL) + panic("key_get: NULL vnet pointer is passed.\n"); /* map satype to proto */ if ((proto = key_satype2proto(mhp->msg->sadb_msg_satype)) == 0) { @@ -5485,7 +5608,7 @@ KEY_SETSECASIDX(proto, IPSEC_MODE_ANY, 0, src0 + 1, dst0 + 1, &saidx); /* get a SA header */ - LIST_FOREACH(sah, &sahtree, chain) { + LIST_FOREACH(sah, &vnet->sahtree, chain) { if (sah->state == SADB_SASTATE_DEAD) continue; if (key_cmpsaidx(&sah->saidx, &saidx, CMP_HEAD) == 0) @@ -5518,7 +5641,7 @@ return key_senderror(so, m, ENOBUFS); m_freem(m); - return key_sendup_mbuf(so, n, KEY_SENDUP_ONE); + return key_sendup_mbuf(so, n, KEY_SENDUP_ONE, vnet); } } @@ -5795,9 +5918,10 @@ * others: error number */ static int -key_acquire(saidx, sp) +key_acquire(saidx, sp, vnet) struct secasindex *saidx; struct secpolicy *sp; + struct vnet *vnet; { struct mbuf *result = NULL, *m; #ifndef IPSEC_NONBLOCK_ACQUIRE @@ -5812,6 +5936,8 @@ panic("key_acquire: NULL pointer is passed.\n"); if ((satype = key_proto2satype(saidx->proto)) == 0) panic("key_acquire: invalid proto is passed.\n"); + if (vnet == NULL) + panic("key_acquire: NULL vnet is passed.\n"); #ifndef IPSEC_NONBLOCK_ACQUIRE /* @@ -5821,8 +5947,8 @@ * managed with ACQUIRING list. */ /* get a entry to check whether sending message or not. */ - if ((newacq = key_getacq(saidx)) != NULL) { - if (key_blockacq_count < newacq->count) { + if ((newacq = key_getacq(saidx, vnet)) != NULL) { + if (vnet->key_blockacq_count < newacq->count) { /* reset counter and do send message. */ newacq->count = 0; } else { @@ -5832,11 +5958,11 @@ } } else { /* make new entry for blocking to send SADB_ACQUIRE. */ - if ((newacq = key_newacq(saidx)) == NULL) + if ((newacq = key_newacq(saidx, vnet)) == NULL) return ENOBUFS; /* add to acqtree */ - LIST_INSERT_HEAD(&acqtree, newacq, chain); + LIST_INSERT_HEAD(&vnet->acqtree, newacq, chain); } #endif @@ -5966,7 +6092,7 @@ mtod(result, struct sadb_msg *)->sadb_msg_len = PFKEY_UNIT64(result->m_pkthdr.len); - return key_sendup_mbuf(NULL, result, KEY_SENDUP_REGISTERED); + return key_sendup_mbuf(NULL, result, KEY_SENDUP_REGISTERED, vnet); fail: if (result) @@ -5976,12 +6102,15 @@ #ifndef IPSEC_NONBLOCK_ACQUIRE static struct secacq * -key_newacq(saidx) +key_newacq(saidx, vnet) struct secasindex *saidx; + struct vnet *vnet; { struct secacq *newacq; struct timeval tv; + if (vnet == NULL) + panic("key_newacq: NULL vnet was passed."); /* get new entry */ KMALLOC(newacq, struct secacq *, sizeof(struct secacq)); if (newacq == NULL) { @@ -5992,7 +6121,7 @@ /* copy secindex */ bcopy(saidx, &newacq->saidx, sizeof(newacq->saidx)); - newacq->seq = (acq_seq == ~0 ? 1 : ++acq_seq); + newacq->seq = (vnet->acq_seq == ~0 ? 1 : ++vnet->acq_seq); microtime(&tv); newacq->created = tv.tv_sec; newacq->count = 0; @@ -6001,12 +6130,15 @@ } static struct secacq * -key_getacq(saidx) +key_getacq(saidx, vnet) struct secasindex *saidx; + struct vnet *vnet; { struct secacq *acq; - LIST_FOREACH(acq, &acqtree, chain) { + if (vnet == NULL) + panic("key_getacq: NULL vnet was passed."); + LIST_FOREACH(acq, &vnet->acqtree, chain) { if (key_cmpsaidx(saidx, &acq->saidx, CMP_EXACTLY)) return acq; } @@ -6015,12 +6147,15 @@ } static struct secacq * -key_getacqbyseq(seq) +key_getacqbyseq(seq, vnet) u_int32_t seq; + struct vnet *vnet; { struct secacq *acq; - LIST_FOREACH(acq, &acqtree, chain) { + if (vnet == NULL) + panic("key_getacqbyseq: NULL vnet was passed."); + LIST_FOREACH(acq, &vnet->acqtree, chain) { if (acq->seq == seq) return acq; } @@ -6054,12 +6189,15 @@ } static struct secspacq * -key_getspacq(spidx) +key_getspacq(spidx, vnet) struct secpolicyindex *spidx; + struct vnet *vnet; { struct secspacq *acq; - LIST_FOREACH(acq, &spacqtree, chain) { + if (vnet == NULL) + panic("key_getspacq: NULL vnet was passed."); + LIST_FOREACH(acq, &vnet->spacqtree, chain) { if (key_cmpspidx_exactly(spidx, &acq->spidx)) return acq; } @@ -6092,10 +6230,14 @@ struct secashead *sah; u_int16_t proto; int error; + struct vnet *vnet; /* sanity check */ if (so == NULL || m == NULL || mhp == NULL || mhp->msg == NULL) panic("key_acquire2: NULL pointer is passed.\n"); + vnet = so->so_vnet; + if (vnet == NULL) + panic("key_acquire2: NULL vnet pointer is passed.\n"); /* * Error message from KMd. @@ -6115,7 +6257,7 @@ return 0; } - if ((acq = key_getacqbyseq(mhp->msg->sadb_msg_seq)) == NULL) { + if ((acq = key_getacqbyseq(mhp->msg->sadb_msg_seq, vnet)) == NULL) { /* * the specified larval SA is already gone, or we got * a bogus sequence number. we can silently ignore it. @@ -6165,7 +6307,7 @@ KEY_SETSECASIDX(proto, IPSEC_MODE_ANY, 0, src0 + 1, dst0 + 1, &saidx); /* get a SA index */ - LIST_FOREACH(sah, &sahtree, chain) { + LIST_FOREACH(sah, &vnet->sahtree, chain) { if (sah->state == SADB_SASTATE_DEAD) continue; if (key_cmpsaidx(&sah->saidx, &saidx, CMP_MODE_REQID)) @@ -6176,14 +6318,14 @@ return key_senderror(so, m, EEXIST); } - error = key_acquire(&saidx, NULL); + error = key_acquire(&saidx, NULL, vnet); if (error != 0) { ipseclog((LOG_DEBUG, "key_acquire2: error %d returned " "from key_acquire.\n", mhp->msg->sadb_msg_errno)); return key_senderror(so, m, error); } - return key_sendup_mbuf(so, m, KEY_SENDUP_REGISTERED); + return key_sendup_mbuf(so, m, KEY_SENDUP_REGISTERED, vnet); } /* @@ -6206,13 +6348,17 @@ const struct sadb_msghdr *mhp; { struct secreg *reg, *newreg = 0; + struct vnet *vnet; /* sanity check */ if (so == NULL || m == NULL || mhp == NULL || mhp->msg == NULL) panic("key_register: NULL pointer is passed.\n"); + vnet = so->so_vnet; + if (vnet == NULL) + panic("key_register: NULL vnet is passed.\n"); /* check for invalid register message */ - if (mhp->msg->sadb_msg_satype >= sizeof(regtree)/sizeof(regtree[0])) + if (mhp->msg->sadb_msg_satype >= sizeof(vnet->regtree)/sizeof(vnet->regtree[0])) return key_senderror(so, m, EINVAL); /* When SATYPE_UNSPEC is specified, only return sabd_supported. */ @@ -6220,7 +6366,7 @@ goto setmsg; /* check whether existing or not */ - LIST_FOREACH(reg, ®tree[mhp->msg->sadb_msg_satype], chain) { + LIST_FOREACH(reg, &vnet->regtree[mhp->msg->sadb_msg_satype], chain) { if (reg->so == so) { ipseclog((LOG_DEBUG, "key_register: socket exists already.\n")); return key_senderror(so, m, EEXIST); @@ -6239,7 +6385,8 @@ ((struct keycb *)sotorawcb(so))->kp_registered++; /* add regnode to regtree. */ - LIST_INSERT_HEAD(®tree[mhp->msg->sadb_msg_satype], newreg, chain); + LIST_INSERT_HEAD(&vnet->regtree[mhp->msg->sadb_msg_satype], + newreg, chain); setmsg: { @@ -6355,7 +6502,7 @@ #endif m_freem(m); - return key_sendup_mbuf(so, n, KEY_SENDUP_REGISTERED); + return key_sendup_mbuf(so, n, KEY_SENDUP_REGISTERED, vnet); } } @@ -6369,10 +6516,14 @@ { struct secreg *reg; int i; + struct vnet *vnet; /* sanity check */ if (so == NULL) panic("key_freereg: NULL pointer is passed.\n"); + vnet = so->so_vnet; + if (vnet == NULL) + panic("key_freereg: NULL vnet pointer is passed.\n"); /* * check whether existing or not. @@ -6380,7 +6531,7 @@ * one socket is registered to multiple type of SA. */ for (i = 0; i <= SADB_SATYPE_MAX; i++) { - LIST_FOREACH(reg, ®tree[i], chain) { + LIST_FOREACH(reg, &vnet->regtree[i], chain) { if (reg->so == so && __LIST_CHAINED(reg)) { LIST_REMOVE(reg, chain); @@ -6404,8 +6555,9 @@ * others : error number */ static int -key_expire(sav) +key_expire(sav, vnet) struct secasvar *sav; + struct vnet *vnet; { int s; int satype; @@ -6414,6 +6566,8 @@ int error = -1; struct sadb_lifetime *lt; + if (vnet == NULL) + panic("key_expire: NULL vnet was passed."); /* XXX: Why do we lock ? */ s = splnet(); /*called from softclock()*/ @@ -6513,7 +6667,7 @@ PFKEY_UNIT64(result->m_pkthdr.len); splx(s); - return key_sendup_mbuf(NULL, result, KEY_SENDUP_REGISTERED); + return key_sendup_mbuf(NULL, result, KEY_SENDUP_REGISTERED, vnet); fail: if (result) @@ -6546,10 +6700,14 @@ u_int16_t proto; u_int8_t state; u_int stateidx; + struct vnet *vnet; /* sanity check */ if (so == NULL || mhp == NULL || mhp->msg == NULL) panic("key_flush: NULL pointer is passed.\n"); + vnet = so->so_vnet; + if (vnet == NULL) + panic("key_flush: NULL vnet pointer is passed.\n"); /* map satype to proto */ if ((proto = key_satype2proto(mhp->msg->sadb_msg_satype)) == 0) { @@ -6558,7 +6716,7 @@ } /* no SATYPE specified, i.e. flushing all SA. */ - for (sah = LIST_FIRST(&sahtree); + for (sah = LIST_FIRST(&vnet->sahtree); sah != NULL; sah = nextsah) { nextsah = LIST_NEXT(sah, chain); @@ -6599,7 +6757,7 @@ newmsg->sadb_msg_errno = 0; newmsg->sadb_msg_len = PFKEY_UNIT64(m->m_pkthdr.len); - return key_sendup_mbuf(so, m, KEY_SENDUP_ALL); + return key_sendup_mbuf(so, m, KEY_SENDUP_ALL, vnet); } /* @@ -6629,10 +6787,12 @@ int cnt; struct sadb_msg *newmsg; struct mbuf *n; + struct vnet *vnet; /* sanity check */ if (so == NULL || m == NULL || mhp == NULL || mhp->msg == NULL) panic("key_dump: NULL pointer is passed.\n"); + vnet = so->so_vnet; /* map satype to proto */ if ((proto = key_satype2proto(mhp->msg->sadb_msg_satype)) == 0) { @@ -6642,7 +6802,7 @@ /* count sav entries to be sent to the userland. */ cnt = 0; - LIST_FOREACH(sah, &sahtree, chain) { + LIST_FOREACH(sah, &vnet->sahtree, chain) { if (mhp->msg->sadb_msg_satype != SADB_SATYPE_UNSPEC && proto != sah->saidx.proto) continue; @@ -6662,7 +6822,7 @@ /* send this to the userland, one at a time. */ newmsg = NULL; - LIST_FOREACH(sah, &sahtree, chain) { + LIST_FOREACH(sah, &vnet->sahtree, chain) { if (mhp->msg->sadb_msg_satype != SADB_SATYPE_UNSPEC && proto != sah->saidx.proto) continue; @@ -6683,7 +6843,7 @@ if (!n) return key_senderror(so, m, ENOBUFS); - key_sendup_mbuf(so, n, KEY_SENDUP_ONE); + key_sendup_mbuf(so, n, KEY_SENDUP_ONE, vnet); } } } @@ -6704,10 +6864,14 @@ const struct sadb_msghdr *mhp; { int olen; + struct vnet *vnet; /* sanity check */ if (so == NULL || m == NULL || mhp == NULL || mhp->msg == NULL) panic("key_promisc: NULL pointer is passed.\n"); + vnet = so->so_vnet; + if (vnet == NULL); + panic("key_promisc: NULL vnet pointer is passed.\n"); olen = PFKEY_UNUNIT64(mhp->msg->sadb_msg_len); @@ -6736,14 +6900,14 @@ /* send the original message back to everyone */ mhp->msg->sadb_msg_errno = 0; - return key_sendup_mbuf(so, m, KEY_SENDUP_ALL); + return key_sendup_mbuf(so, m, KEY_SENDUP_ALL, vnet); } else { /* send packet as is */ m_adj(m, PFKEY_ALIGN8(sizeof(struct sadb_msg))); /* TODO: if sadb_msg_seq is specified, send to specific pid */ - return key_sendup_mbuf(so, m, KEY_SENDUP_ALL); + return key_sendup_mbuf(so, m, KEY_SENDUP_ALL, vnet); } } @@ -6790,6 +6954,7 @@ struct mbuf *m; struct socket *so; { + struct vnet *vnet; struct sadb_msg *msg; struct sadb_msghdr mh; u_int orglen; @@ -6799,6 +6964,9 @@ /* sanity check */ if (m == NULL || so == NULL) panic("key_parse: NULL pointer is passed.\n"); + vnet = so->so_vnet; + if (vnet == NULL) + panic("key_parse: NULL vnet is passed.\n"); #if 0 /*kdebug_sadb assumes msg in linear buffer*/ KEYDEBUG(KEYDEBUG_KEY_DUMP, @@ -6818,7 +6986,7 @@ if ((m->m_flags & M_PKTHDR) == 0 || m->m_pkthdr.len != m->m_pkthdr.len) { ipseclog((LOG_DEBUG, "key_parse: invalid message length.\n")); - pfkeystat.out_invlen++; + vnet->pfkeystat.out_invlen++; error = EINVAL; goto senderror; } @@ -6827,7 +6995,7 @@ ipseclog((LOG_DEBUG, "key_parse: PF_KEY version %u is mismatched.\n", msg->sadb_msg_version)); - pfkeystat.out_invver++; + vnet->pfkeystat.out_invver++; error = EINVAL; goto senderror; } @@ -6835,7 +7003,7 @@ if (msg->sadb_msg_type > SADB_MAX) { ipseclog((LOG_DEBUG, "key_parse: invalid type %u is passed.\n", msg->sadb_msg_type)); - pfkeystat.out_invmsgtype++; + vnet->pfkeystat.out_invmsgtype++; error = EINVAL; goto senderror; } @@ -6868,7 +7036,7 @@ } /* align the mbuf chain so that extensions are in contiguous region. */ - error = key_align(m, &mh); + error = key_align(m, &mh, vnet); if (error) return error; @@ -6892,7 +7060,7 @@ case SADB_EXPIRE: ipseclog((LOG_DEBUG, "key_parse: must specify satype " "when msg type=%u.\n", msg->sadb_msg_type)); - pfkeystat.out_invsatype++; + vnet->pfkeystat.out_invsatype++; error = EINVAL; goto senderror; } @@ -6911,7 +7079,7 @@ case SADB_X_SPDDELETE2: ipseclog((LOG_DEBUG, "key_parse: illegal satype=%u\n", msg->sadb_msg_type)); - pfkeystat.out_invsatype++; + vnet->pfkeystat.out_invsatype++; error = EINVAL; goto senderror; } @@ -6922,7 +7090,7 @@ case SADB_SATYPE_MIP: ipseclog((LOG_DEBUG, "key_parse: type %u isn't supported.\n", msg->sadb_msg_satype)); - pfkeystat.out_invsatype++; + vnet->pfkeystat.out_invsatype++; error = EOPNOTSUPP; goto senderror; case 1: /* XXX: What does it do? */ @@ -6932,7 +7100,7 @@ default: ipseclog((LOG_DEBUG, "key_parse: invalid type %u is passed.\n", msg->sadb_msg_satype)); - pfkeystat.out_invsatype++; + vnet->pfkeystat.out_invsatype++; error = EINVAL; goto senderror; } @@ -6949,7 +7117,7 @@ /* check upper layer protocol */ if (src0->sadb_address_proto != dst0->sadb_address_proto) { ipseclog((LOG_DEBUG, "key_parse: upper layer protocol mismatched.\n")); - pfkeystat.out_invaddr++; + vnet->pfkeystat.out_invaddr++; error = EINVAL; goto senderror; } @@ -6958,7 +7126,7 @@ if (PFKEY_ADDR_SADDR(src0)->sa_family != PFKEY_ADDR_SADDR(dst0)->sa_family) { ipseclog((LOG_DEBUG, "key_parse: address family mismatched.\n")); - pfkeystat.out_invaddr++; + vnet->pfkeystat.out_invaddr++; error = EINVAL; goto senderror; } @@ -6966,7 +7134,7 @@ PFKEY_ADDR_SADDR(dst0)->sa_len) { ipseclog((LOG_DEBUG, "key_parse: address struct size mismatched.\n")); - pfkeystat.out_invaddr++; + vnet->pfkeystat.out_invaddr++; error = EINVAL; goto senderror; } @@ -6975,7 +7143,7 @@ case AF_INET: if (PFKEY_ADDR_SADDR(src0)->sa_len != sizeof(struct sockaddr_in)) { - pfkeystat.out_invaddr++; + vnet->pfkeystat.out_invaddr++; error = EINVAL; goto senderror; } @@ -6983,7 +7151,7 @@ case AF_INET6: if (PFKEY_ADDR_SADDR(src0)->sa_len != sizeof(struct sockaddr_in6)) { - pfkeystat.out_invaddr++; + vnet->pfkeystat.out_invaddr++; error = EINVAL; goto senderror; } @@ -6991,7 +7159,7 @@ default: ipseclog((LOG_DEBUG, "key_parse: unsupported address family.\n")); - pfkeystat.out_invaddr++; + vnet->pfkeystat.out_invaddr++; error = EAFNOSUPPORT; goto senderror; } @@ -7013,7 +7181,7 @@ dst0->sadb_address_prefixlen > plen) { ipseclog((LOG_DEBUG, "key_parse: illegal prefixlen.\n")); - pfkeystat.out_invaddr++; + vnet->pfkeystat.out_invaddr++; error = EINVAL; goto senderror; } @@ -7026,7 +7194,7 @@ if (msg->sadb_msg_type >= sizeof(key_typesw)/sizeof(key_typesw[0]) || key_typesw[msg->sadb_msg_type] == NULL) { - pfkeystat.out_invmsgtype++; + vnet->pfkeystat.out_invmsgtype++; error = EINVAL; goto senderror; } @@ -7035,7 +7203,7 @@ senderror: msg->sadb_msg_errno = error; - return key_sendup_mbuf(so, m, target); + return key_sendup_mbuf(so, m, target, vnet); } static int @@ -7044,14 +7212,18 @@ struct mbuf *m; int code; { + struct vnet *vnet; struct sadb_msg *msg; + if (so == NULL || so->so_vnet == NULL) + panic("key_senderror: cannot find vnet"); + vnet = so->so_vnet; if (m->m_len < sizeof(struct sadb_msg)) panic("invalid mbuf passed to key_senderror"); msg = mtod(m, struct sadb_msg *); msg->sadb_msg_errno = code; - return key_sendup_mbuf(so, m, KEY_SENDUP_ONE); + return key_sendup_mbuf(so, m, KEY_SENDUP_ONE, vnet); } /* @@ -7060,9 +7232,10 @@ * XXX larger-than-MCLBYTES extension? */ static int -key_align(m, mhp) +key_align(m, mhp, vnet) struct mbuf *m; struct sadb_msghdr *mhp; + struct vnet *vnet; { struct mbuf *n; struct sadb_ext *ext; @@ -7075,6 +7248,8 @@ panic("key_align: NULL pointer is passed.\n"); if (m->m_len < sizeof(struct sadb_msg)) panic("invalid mbuf passed to key_align"); + if (vnet == NULL) + panic("key_align: NULL vnet is passed.\n"); /* initialize */ bzero(mhp, sizeof(*mhp)); @@ -7122,7 +7297,7 @@ "key_align: duplicate ext_type %u " "is passed.\n", ext->sadb_ext_type)); m_freem(m); - pfkeystat.out_dupext++; + vnet->pfkeystat.out_dupext++; return EINVAL; } break; @@ -7131,7 +7306,7 @@ "key_align: invalid ext_type %u is passed.\n", ext->sadb_ext_type)); m_freem(m); - pfkeystat.out_invexttype++; + vnet->pfkeystat.out_invexttype++; return EINVAL; } @@ -7139,7 +7314,7 @@ if (key_validate_ext(ext, extlen)) { m_freem(m); - pfkeystat.out_invlen++; + vnet->pfkeystat.out_invlen++; return EINVAL; } @@ -7157,7 +7332,7 @@ if (off != end) { m_freem(m); - pfkeystat.out_invlen++; + vnet->pfkeystat.out_invlen++; return EINVAL; } @@ -7224,49 +7399,97 @@ } void -key_init() +key_init(vnet) + struct vnet *vnet; { int i; - bzero((caddr_t)&key_cb, sizeof(key_cb)); + if (vnet == NULL) + panic("key_init: NULL vnet was passed."); + bzero((caddr_t)&vnet->key_cb, sizeof(vnet->key_cb)); for (i = 0; i < IPSEC_DIR_MAX; i++) { - LIST_INIT(&sptree[i]); + LIST_INIT(&vnet->sptree[i]); } - LIST_INIT(&sahtree); + LIST_INIT(&vnet->sahtree); for (i = 0; i <= SADB_SATYPE_MAX; i++) { - LIST_INIT(®tree[i]); + LIST_INIT(&vnet->regtree[i]); } #ifndef IPSEC_NONBLOCK_ACQUIRE - LIST_INIT(&acqtree); + LIST_INIT(&vnet->acqtree); #endif - LIST_INIT(&spacqtree); + LIST_INIT(&vnet->spacqtree); /* system default */ #ifdef INET - ip4_def_policy.policy = IPSEC_POLICY_NONE; - ip4_def_policy.refcnt++; /*never reclaim this*/ + vnet->ip4_def_policy.policy = IPSEC_POLICY_NONE; + vnet->ip4_def_policy.refcnt++; /*never reclaim this*/ #endif #ifdef INET6 - ip6_def_policy.policy = IPSEC_POLICY_NONE; - ip6_def_policy.refcnt++; /*never reclaim this*/ + vnet->ip6_def_policy.policy = IPSEC_POLICY_NONE; + vnet->ip6_def_policy.refcnt++; /*never reclaim this*/ #endif -#ifndef IPSEC_DEBUG2 - timeout((void *)key_timehandler, (void *)0, hz); -#endif /*IPSEC_DEBUG2*/ - /* initialize key statistics */ - keystat.getspi_count = 1; + vnet->keystat.getspi_count = 1; - printf("IPsec: Initialized Security Association Processing.\n"); + /* initalize vnet variables (normally static) */ + /* from netkey/key.c */ + vnet->key_spi_trycnt = 1000; + vnet->key_spi_minval = 0x100; + vnet->key_spi_maxval = 0x0fffffff; /* XXX */ + vnet->policy_id = 0; + vnet->key_int_random = 60; /*interval to initialize randseed,1(m)*/ + vnet->key_larval_lifetime = 30; /* interval to expire acquiring, 30(s)*/ + vnet->key_blockacq_count = 10; /* counter for blocking SADB_ACQUIRE.*/ + vnet->key_blockacq_lifetime = 20;/* lifetime f/ blocking SADB_ACQUIRE.*/ + vnet->key_preferred_oldsa = 1; /* preferred old sa rather than new sa.*/ + vnet->acq_seq = 0; + vnet->key_tick_init_random = 0; + + /* from netinet6/ipsec.c */ + vnet->ip4_ah_cleartos = 1; + vnet->ip4_ah_offsetmask = 0; /* maybe IP_DF? */ + vnet->ip4_ipsec_dfbit = 0;/* DF bit on encap. 0: clear 1: set 2: copy */ + vnet->ip4_esp_trans_deflev = IPSEC_LEVEL_USE; + vnet->ip4_esp_net_deflev = IPSEC_LEVEL_USE; + vnet->ip4_ah_trans_deflev = IPSEC_LEVEL_USE; + vnet->ip4_ah_net_deflev = IPSEC_LEVEL_USE; + vnet->ip4_ipsec_ecn = 0; /* ECN ignore(-1)/forbidden(0)/allowed(1) */ + vnet->ip4_esp_randpad = -1; +#ifdef INET6 + /* what about ipsec6stat? */ + vnet->ip6_esp_trans_deflev = IPSEC_LEVEL_USE; + vnet->ip6_esp_net_deflev = IPSEC_LEVEL_USE; + vnet->ip6_ah_trans_deflev = IPSEC_LEVEL_USE; + vnet->ip6_ah_net_deflev = IPSEC_LEVEL_USE; + vnet->ip6_ipsec_ecn = 0; /* ECN ignore(-1)/forbidden(0)/allowed(1) */ + vnet->ip6_esp_randpad = -1; +#endif + +/* net.inet6.ipsec6 */ + +#ifndef IPSEC_DEBUG2 + if (vnet == vnet0) /* one timehandler iterates for all vnets */ + timeout((void *)key_timehandler, (void *)0, hz); +#endif /*IPSEC_DEBUG2*/ + + if (vnet == vnet0) + printf("IPsec: Initialized Security Association Processing.\n"); return; } +void +key_destroy(vnet) +struct vnet *vnet; +{ + /* XXX do nothing */ +} + /* * XXX: maybe This function is called after INBOUND IPsec processing. * @@ -7406,13 +7629,16 @@ /* dumb version */ void -key_sa_routechange(dst) +key_sa_routechange(dst, vnet) struct sockaddr *dst; + struct vnet *vnet; { struct secashead *sah; struct route *ro; - LIST_FOREACH(sah, &sahtree, chain) { + if (vnet == NULL) + panic("key_sa_routechange: NULL vnet was passed."); + LIST_FOREACH(sah, &vnet->sahtree, chain) { ro = &sah->sa_route; if (ro->ro_rt && dst->sa_len == ro->ro_dst.sa_len && bcmp(dst, &ro->ro_dst, dst->sa_len) == 0) { diff -urN sys/netkey/key.h sys.CORE/netkey/key.h --- sys/netkey/key.h Wed Jan 31 15:57:05 2007 +++ sys.CORE/netkey/key.h Wed Jan 31 16:02:43 2007 @@ -35,7 +35,7 @@ #ifdef _KERNEL -extern struct key_cb key_cb; +/*extern struct key_cb key_cb;*/ struct secpolicy; struct secpolicyindex; @@ -46,14 +46,15 @@ struct sadb_msg; struct sadb_x_policy; -extern struct secpolicy *key_allocsp __P((struct secpolicyindex *, u_int)); +extern struct secpolicy *key_allocsp __P((struct secpolicyindex *, u_int, + struct vnet*)); extern struct secpolicy *key_gettunnel __P((struct sockaddr *, - struct sockaddr *, struct sockaddr *, struct sockaddr *)); + struct sockaddr *, struct sockaddr *, struct sockaddr *, struct vnet*)); extern int key_checkrequest __P((struct ipsecrequest *isr, struct secasindex *, struct vnet *)); extern struct secasvar *key_allocsa __P((u_int, caddr_t, caddr_t, - u_int, u_int32_t)); + u_int, u_int32_t, struct vnet *)); extern void key_freesp __P((struct secpolicy *)); extern void key_freeso __P((struct socket *)); extern void key_freesav __P((struct secasvar *)); @@ -68,11 +69,12 @@ extern void key_randomfill __P((void *, size_t)); extern void key_freereg __P((struct socket *)); extern int key_parse __P((struct mbuf *, struct socket *)); -extern void key_init __P((void)); +extern void key_init __P((struct vnet *)); +extern void key_destroy __P((struct vnet *)); extern int key_checktunnelsanity __P((struct secasvar *, u_int, caddr_t, caddr_t)); extern void key_sa_recordxfer __P((struct secasvar *, struct mbuf *)); -extern void key_sa_routechange __P((struct sockaddr *)); +extern void key_sa_routechange __P((struct sockaddr *, struct vnet *)); extern void key_sa_stir_iv __P((struct secasvar *)); #ifdef MALLOC_DECLARE diff -urN sys/netkey/keysock.c sys.CORE/netkey/keysock.c --- sys/netkey/keysock.c Wed Jan 31 15:57:05 2007 +++ sys.CORE/netkey/keysock.c Wed Jan 31 16:02:43 2007 @@ -65,9 +65,7 @@ struct sockaddr key_dst = { 2, PF_KEY, }; struct sockaddr key_src = { 2, PF_KEY, }; -static int key_sendup0 __P((struct rawcb *, struct mbuf *, int)); - -struct pfkeystat pfkeystat; +static int key_sendup0 __P((struct rawcb *, struct mbuf *, int, struct vnet*)); /* * key_output() @@ -86,27 +84,31 @@ int s; struct socket *so; va_list ap; + struct vnet *vnet; va_start(ap, m); so = va_arg(ap, struct socket *); + vnet = va_arg(ap, struct vnet *); va_end(ap); if (m == 0) panic("key_output: NULL pointer was passed.\n"); + if (vnet == NULL) + panic("key_output: NULL vnet was passed.\n"); - pfkeystat.out_total++; - pfkeystat.out_bytes += m->m_pkthdr.len; + vnet->pfkeystat.out_total++; + vnet->pfkeystat.out_bytes += m->m_pkthdr.len; len = m->m_pkthdr.len; if (len < sizeof(struct sadb_msg)) { - pfkeystat.out_tooshort++; + vnet->pfkeystat.out_tooshort++; error = EINVAL; goto end; } if (m->m_len < sizeof(struct sadb_msg)) { if ((m = m_pullup(m, sizeof(struct sadb_msg))) == 0) { - pfkeystat.out_nomem++; + vnet->pfkeystat.out_nomem++; error = ENOBUFS; goto end; } @@ -118,9 +120,9 @@ KEYDEBUG(KEYDEBUG_KEY_DUMP, kdebug_mbuf(m)); msg = mtod(m, struct sadb_msg *); - pfkeystat.out_msgtype[msg->sadb_msg_type]++; + vnet->pfkeystat.out_msgtype[msg->sadb_msg_type]++; if (len != PFKEY_UNUNIT64(msg->sadb_msg_len)) { - pfkeystat.out_invlen++; + vnet->pfkeystat.out_invlen++; error = EINVAL; goto end; } @@ -140,13 +142,17 @@ * send message to the socket. */ static int -key_sendup0(rp, m, promisc) +key_sendup0(rp, m, promisc, vnet) struct rawcb *rp; struct mbuf *m; int promisc; + struct vnet *vnet; { int error; + if (vnet == NULL) + panic("key_sendup0: NULL vnet was passed.\n"); + if (promisc) { struct sadb_msg *pmsg; @@ -154,7 +160,7 @@ if (m && m->m_len < sizeof(struct sadb_msg)) m = m_pullup(m, sizeof(struct sadb_msg)); if (!m) { - pfkeystat.in_nomem++; + vnet->pfkeystat.in_nomem++; m_freem(m); return ENOBUFS; } @@ -167,12 +173,12 @@ pmsg->sadb_msg_len = PFKEY_UNIT64(m->m_pkthdr.len); /* pid and seq? */ - pfkeystat.in_msgtype[pmsg->sadb_msg_type]++; + vnet->pfkeystat.in_msgtype[pmsg->sadb_msg_type]++; } if (!sbappendaddr(&rp->rcb_socket->so_rcv, (struct sockaddr *)&key_src, m, NULL)) { - pfkeystat.in_nomem++; + vnet->pfkeystat.in_nomem++; m_freem(m); error = ENOBUFS; } else @@ -196,6 +202,8 @@ /* sanity check */ if (so == 0 || msg == 0) panic("key_sendup: NULL pointer was passed.\n"); + if (vnet == NULL) + panic("key_sendup: NULL vnet was passed.\n"); KEYDEBUG(KEYDEBUG_KEY_DUMP, printf("key_sendup: \n"); @@ -205,9 +213,9 @@ * we increment statistics here, just in case we have ENOBUFS * in this function. */ - pfkeystat.in_total++; - pfkeystat.in_bytes += len; - pfkeystat.in_msgtype[msg->sadb_msg_type]++; + vnet->pfkeystat.in_total++; + vnet->pfkeystat.in_bytes += len; + vnet->pfkeystat.in_msgtype[msg->sadb_msg_type]++; /* * Get mbuf chain whenever possible (not clusters), @@ -229,7 +237,7 @@ n->m_len = MLEN; } if (!n) { - pfkeystat.in_nomem++; + vnet->pfkeystat.in_nomem++; return ENOBUFS; } if (tlen >= MCLBYTES) { /*XXX better threshold? */ @@ -237,7 +245,7 @@ if ((n->m_flags & M_EXT) == 0) { m_free(n); m_freem(m); - pfkeystat.in_nomem++; + vnet->pfkeystat.in_nomem++; return ENOBUFS; } n->m_len = MCLBYTES; @@ -260,9 +268,9 @@ m_copyback(m, 0, len, (caddr_t)msg); /* avoid duplicated statistics */ - pfkeystat.in_total--; - pfkeystat.in_bytes -= len; - pfkeystat.in_msgtype[msg->sadb_msg_type]--; + vnet->pfkeystat.in_total--; + vnet->pfkeystat.in_bytes -= len; + vnet->pfkeystat.in_msgtype[msg->sadb_msg_type]--; return key_sendup_mbuf(so, m, target, vnet); } @@ -285,14 +293,16 @@ panic("key_sendup_mbuf: NULL pointer was passed.\n"); if (so == NULL && target == KEY_SENDUP_ONE) panic("key_sendup_mbuf: NULL pointer was passed.\n"); + if (vnet == NULL) + panic("key_sendup_mbuf: NULL vnet pointer was passed.\n"); - pfkeystat.in_total++; - pfkeystat.in_bytes += m->m_pkthdr.len; + vnet->pfkeystat.in_total++; + vnet->pfkeystat.in_bytes += m->m_pkthdr.len; if (m->m_len < sizeof(struct sadb_msg)) { #if 1 m = m_pullup(m, sizeof(struct sadb_msg)); if (m == NULL) { - pfkeystat.in_nomem++; + vnet->pfkeystat.in_nomem++; return ENOBUFS; } #else @@ -302,7 +312,7 @@ if (m->m_len >= sizeof(struct sadb_msg)) { struct sadb_msg *msg; msg = mtod(m, struct sadb_msg *); - pfkeystat.in_msgtype[msg->sadb_msg_type]++; + vnet->pfkeystat.in_msgtype[msg->sadb_msg_type]++; } LIST_FOREACH(rp, &vnet->rawcb_list, list) @@ -323,7 +333,7 @@ */ if (((struct keycb *)rp)->kp_promisc) { if ((n = m_copy(m, 0, (int)M_COPYALL)) != NULL) { - (void)key_sendup0(rp, n, 1); + (void)key_sendup0(rp, n, 1, vnet); n = NULL; } } @@ -347,18 +357,18 @@ sendup++; break; } - pfkeystat.in_msgtarget[target]++; + vnet->pfkeystat.in_msgtarget[target]++; if (!sendup) continue; if ((n = m_copy(m, 0, (int)M_COPYALL)) == NULL) { m_freem(m); - pfkeystat.in_nomem++; + vnet->pfkeystat.in_nomem++; return ENOBUFS; } - if ((error = key_sendup0(rp, n, 0)) != 0) { + if ((error = key_sendup0(rp, n, 0, vnet)) != 0) { m_freem(m); return error; } @@ -367,7 +377,7 @@ } if (so) { - error = key_sendup0(sotorawcb(so), m, 0); + error = key_sendup0(sotorawcb(so), m, 0, vnet); m = NULL; } else { error = 0; @@ -397,9 +407,12 @@ static int key_attach(struct socket *so, int proto, struct proc *p) { + struct vnet *vnet = so->so_vnet; struct keycb *kp; int s, error; + if (vnet == NULL) + panic("key_attach: NULL vnet was passed.\n"); if (sotorawcb(so) != 0) return EISCONN; /* XXX panic? */ kp = (struct keycb *)malloc(sizeof *kp, M_PCB, M_WAITOK); /* XXX */ @@ -428,8 +441,8 @@ kp->kp_promisc = kp->kp_registered = 0; if (kp->kp_raw.rcb_proto.sp_protocol == PF_KEY) /* XXX: AF_KEY */ - key_cb.key_count++; - key_cb.any_count++; + vnet->key_cb.key_count++; + vnet->key_cb.any_count++; kp->kp_raw.rcb_laddr = &key_src; kp->kp_raw.rcb_faddr = &key_dst; soisconnected(so); @@ -474,15 +487,18 @@ static int key_detach(struct socket *so) { + struct vnet *vnet = so->so_vnet; struct keycb *kp = (struct keycb *)sotorawcb(so); int s, error; + if (vnet == NULL) + panic("key_detach: NULL vnet from sock."); s = splnet(); if (kp != 0) { if (kp->kp_raw.rcb_proto.sp_protocol == PF_KEY) /* XXX: AF_KEY */ - key_cb.key_count--; - key_cb.any_count--; + vnet->key_cb.key_count--; + vnet->key_cb.any_count--; key_freereg(so); } @@ -585,13 +601,13 @@ { SOCK_RAW, &keydomain, PF_KEY_V2, PR_ATOMIC|PR_ADDR, 0, key_output, raw_ctlinput, 0, 0, - raw_init, 0, 0, 0, + raw_init, raw_destroy, 0, 0, 0, &key_usrreqs } }; struct domain keydomain = - { PF_KEY, "key", key_init, 0, 0, + { PF_KEY, "key", key_init, key_destroy, 0, 0, keysw, &keysw[sizeof(keysw)/sizeof(keysw[0])] }; DOMAIN_SET(key); diff -urN sys/netkey/keysock.h sys.CORE/netkey/keysock.h --- sys/netkey/keysock.h Wed Jan 31 15:57:05 2007 +++ sys.CORE/netkey/keysock.h Wed Jan 31 16:02:43 2007 @@ -69,8 +69,6 @@ int kp_registered; /* registered socket */ }; -extern struct pfkeystat pfkeystat; - extern int key_output __P((struct mbuf *, ...)); extern int key_usrreq __P((struct socket *, int, struct mbuf *, struct mbuf *, struct mbuf *)); core-4.8/kernel/freebsd/README.txt0000664000175000017500000000235412534327775013653 00000000000000CORE kernel patches For information on the kernel modules ng_pipe and ng_wlan, see the README files in their respective directories. You should run the make && make install from the module directories for CORE to work properly. FreeBSD 8.x requires the small patches to allow per-node directories. The FreeBSD 7.x version of CORE does not require the patch included here. Instead you should download the latest vimage_7 kernel from: http://imunes.net/virtnet/ The FreeBSD 4.11 version of CORE requires the included patch to work. See the CORE manual for patching details. ng_pipe module you should install with FreeBSD 4.11 or 7.x ng_wlan module you should install with FreeBSD 4.11 or 7.x 4.11-R-CORE.diff patch you should use with FreeBSD 4.11 freebsd7-config-CORE config that you may use with vimage_7 kernels freebsd7-config-COREDEBUG debugging config for use with vimage_7 kernels vimage_7-CORE.diff patch to add multicast routing to vimage_7_20081015 imunes-8.0-RELEASE.diff per-node directories, persistent hub/switch, and traffic snopping for wireshark for FreeBSD 8.0 symlinks-8.1-RELEASE.diff per-node directories for FreeBSD 8.1 core-4.8/kernel/freebsd/freebsd7-config-CORE0000664000175000017500000000062312534327775015567 00000000000000# # VIMAGE - sample kernel configuration file with a virtualized network stack # configure. # # $FreeBSD$ # include GENERIC ident CORE options IPSEC device crypto options VIMAGE options IPFIREWALL options IPFIREWALL_DEFAULT_TO_ACCEPT #allow everything by default # # Some kernel subsystems and functions don't yet compile with VIMAGE. Remove # from the configuration for now. # nooptions SCTP core-4.8/kernel/freebsd/freebsd7-config-COREDEBUG0000664000175000017500000000057312534327775016342 00000000000000# # VIMAGE - sample kernel configuration file with a virtualized network stack # configure. # # $FreeBSD$ # include GENERIC ident COREDEBUG device crypto options IPSEC options VIMAGE options DDB options GDB options KDB options KDB_TRACE # # Some kernel subsystems and functions don't yet compile with VIMAGE. Remove # from the configuration for now. # nooptions SCTP core-4.8/kernel/freebsd/freebsd8-config-CORE0000664000175000017500000000032312534327775015565 00000000000000# this is the FreeBSD 8.x kernel configuration file for CORE include GENERIC ident CORE options VIMAGE nooptions SCTP options IPSEC device crypto options IPFIREWALL options IPFIREWALL_DEFAULT_TO_ACCEPT core-4.8/kernel/freebsd/imunes-8.0-RELEASE.diff0000664000175000017500000002576412534327775015702 00000000000000# This patch is from http://imunes.net/imunes-8.0-RC3.diff # # This patch enables per-node directories, persistent hub/switch nodes, traffic # snooping for wireshark, and disallows vlan interfaces within a jail. diff -drup src-org/sys/kern/vfs_lookup.c src/sys/kern/vfs_lookup.c --- src-org/sys/kern/vfs_lookup.c 2009-10-25 01:10:29.000000000 +0000 +++ src/sys/kern/vfs_lookup.c 2009-11-11 12:46:02.000000000 +0000 @@ -59,6 +59,8 @@ __FBSDID("$FreeBSD: src/sys/kern/vfs_loo #include #endif +#include + #include #include @@ -72,6 +74,19 @@ SDT_PROBE_DEFINE3(vfs, namei, lookup, en "unsigned long"); SDT_PROBE_DEFINE2(vfs, namei, lookup, return, "int", "struct vnode *"); +#ifdef VIMAGE +#define IMUNES_SYMLINK_HACK +#endif + +#ifdef IMUNES_SYMLINK_HACK +static VNET_DEFINE(int, morphing_symlinks); +#define V_morphing_symlinks VNET(morphing_symlinks) + +SYSCTL_VNET_INT(_vfs, OID_AUTO, morphing_symlinks, CTLFLAG_RW, + &VNET_NAME(morphing_symlinks), 0, + "Resolve @ to vimage name in symlinks"); +#endif + /* * Allocation zone for namei */ @@ -333,6 +348,44 @@ namei(struct nameidata *ndp) error = ENOENT; break; } +#ifdef IMUNES_SYMLINK_HACK + /* + * If the symbolic link includes a special character '@', + * and V_morphing_symlinks is set, substitute the first + * occurence of '@' with full path to jail / vimage name. + * If the full path includes subhierarchies, s/./\// when + * expanding '@' to jail / vimage name. + * + * XXX revisit buffer length checking. + */ + CURVNET_SET_QUIET(TD_TO_VNET(curthread)); + if (V_morphing_symlinks) { + char *sp = strchr(cp, '@'); + + if (sp) { + char *vname = td->td_ucred->cr_prison->pr_name; + int vnamelen = strlen(vname); + int i; + + if (vnamelen >= auio.uio_resid) { + if (ndp->ni_pathlen > 1) + uma_zfree(namei_zone, cp); + error = ENAMETOOLONG; + CURVNET_RESTORE(); + break; + } + bcopy(sp + 1, sp + vnamelen, + linklen - (sp - cp)); + bcopy(td->td_ucred->cr_prison->pr_name, + sp, vnamelen); + linklen += (vnamelen - 1); + for (i = 0; i < vnamelen; i++) + if (sp[i] == '.') + sp[i] = '/'; + } + } + CURVNET_RESTORE(); +#endif if (linklen + ndp->ni_pathlen >= MAXPATHLEN) { if (ndp->ni_pathlen > 1) uma_zfree(namei_zone, cp); diff -drup src-org/sys/net/bpf.c src/sys/net/bpf.c --- src-org/sys/net/bpf.c 2009-10-25 01:10:29.000000000 +0000 +++ src/sys/net/bpf.c 2009-11-11 12:46:02.000000000 +0000 @@ -44,6 +44,7 @@ __FBSDID("$FreeBSD: src/sys/net/bpf.c,v #include #include #include +#include #include #include #include @@ -1435,9 +1436,34 @@ bpf_setif(struct bpf_d *d, struct ifreq struct bpf_if *bp; struct ifnet *theywant; +#define XVNET_BPF_SNOOPING +#if defined(VIMAGE) && defined(XVNET_BPF_SNOOPING) + struct vnet *target_vnet = curvnet; + char *c; + + /* Attempt to attach to an ifnet in a foreign vnet, specified as @ */ + c = rindex(ifr->ifr_name, '@'); + if ( c != NULL ) { + struct prison *target_pr; + + *c++ = 0; + if (!isascii(*c) && !isdigit(*c)) + return ENXIO; + target_pr = prison_find_name(curthread->td_ucred->cr_prison, c); + if (target_pr == NULL) + return ENXIO; + target_vnet = target_pr->pr_vnet; + } + CURVNET_SET_QUIET(target_vnet); +#endif + theywant = ifunit(ifr->ifr_name); - if (theywant == NULL || theywant->if_bpf == NULL) + if (theywant == NULL || theywant->if_bpf == NULL) { +#if defined(VIMAGE) && defined(XVNET_BPF_SNOOPING) + CURVNET_RESTORE(); +#endif return (ENXIO); + } bp = theywant->if_bpf; @@ -1477,6 +1503,9 @@ bpf_setif(struct bpf_d *d, struct ifreq BPFD_LOCK(d); reset_d(d); BPFD_UNLOCK(d); +#if defined(VIMAGE) && defined(XVNET_BPF_SNOOPING) + CURVNET_RESTORE(); +#endif return (0); } diff -drup src-org/sys/net/if.c src/sys/net/if.c --- src-org/sys/net/if.c 2009-10-25 01:10:29.000000000 +0000 +++ src/sys/net/if.c 2009-11-11 12:46:02.000000000 +0000 @@ -813,6 +813,14 @@ if_detach_internal(struct ifnet *ifp, in struct ifnet *iter; int found = 0; + /* + * Detach from any vlan, bridge or lagg ifnets linked to us. + * A small though unlikely window for a race from here to ifp + * unlinking from ifnet list is possible, hence we repeat the + * procedure once again further bellow. XXX. + */ + EVENTHANDLER_INVOKE(ifnet_departure_event, ifp); + IFNET_WLOCK(); TAILQ_FOREACH(iter, &V_ifnet, if_link) if (iter == ifp) { diff -drup src-org/sys/net/if_llatbl.c src/sys/net/if_llatbl.c --- src-org/sys/net/if_llatbl.c 2009-10-25 01:10:29.000000000 +0000 +++ src/sys/net/if_llatbl.c 2009-11-11 12:53:49.000000000 +0000 @@ -57,11 +57,14 @@ __FBSDID("$FreeBSD: src/sys/net/if_llatb MALLOC_DEFINE(M_LLTABLE, "lltable", "link level address tables"); -static SLIST_HEAD(, lltable) lltables = SLIST_HEAD_INITIALIZER(lltables); +static VNET_DEFINE(SLIST_HEAD(, lltable), lltables); +#define V_lltables VNET(lltables) extern void arprequest(struct ifnet *, struct in_addr *, struct in_addr *, u_char *); +static void vnet_lltable_init(void); + struct rwlock lltable_rwlock; RW_SYSINIT(lltable_rwlock, &lltable_rwlock, "lltable_rwlock"); @@ -75,7 +78,7 @@ lltable_sysctl_dumparp(int af, struct sy int error = 0; LLTABLE_RLOCK(); - SLIST_FOREACH(llt, &lltables, llt_link) { + SLIST_FOREACH(llt, &V_lltables, llt_link) { if (llt->llt_af == af) { error = llt->llt_dump(llt, wr); if (error != 0) @@ -157,7 +160,7 @@ lltable_free(struct lltable *llt) KASSERT(llt != NULL, ("%s: llt is NULL", __func__)); LLTABLE_WLOCK(); - SLIST_REMOVE(&lltables, llt, lltable, llt_link); + SLIST_REMOVE(&V_lltables, llt, lltable, llt_link); LLTABLE_WUNLOCK(); for (i=0; i < LLTBL_HASHTBL_SIZE; i++) { @@ -180,7 +183,7 @@ lltable_drain(int af) register int i; LLTABLE_RLOCK(); - SLIST_FOREACH(llt, &lltables, llt_link) { + SLIST_FOREACH(llt, &V_lltables, llt_link) { if (llt->llt_af != af) continue; @@ -202,7 +205,7 @@ lltable_prefix_free(int af, struct socka struct lltable *llt; LLTABLE_RLOCK(); - SLIST_FOREACH(llt, &lltables, llt_link) { + SLIST_FOREACH(llt, &V_lltables, llt_link) { if (llt->llt_af != af) continue; @@ -232,7 +235,7 @@ lltable_init(struct ifnet *ifp, int af) LIST_INIT(&llt->lle_head[i]); LLTABLE_WLOCK(); - SLIST_INSERT_HEAD(&lltables, llt, llt_link); + SLIST_INSERT_HEAD(&V_lltables, llt, llt_link); LLTABLE_WUNLOCK(); return (llt); @@ -302,7 +305,7 @@ lla_rt_output(struct rt_msghdr *rtm, str /* XXX linked list may be too expensive */ LLTABLE_RLOCK(); - SLIST_FOREACH(llt, &lltables, llt_link) { + SLIST_FOREACH(llt, &V_lltables, llt_link) { if (llt->llt_af == dst->sa_family && llt->llt_ifp == ifp) break; @@ -367,3 +370,12 @@ lla_rt_output(struct rt_msghdr *rtm, str return (error); } + +static void +vnet_lltable_init() +{ + + SLIST_INIT(&V_lltables); +} +VNET_SYSINIT(vnet_lltable_init, SI_SUB_PSEUDO, SI_ORDER_FIRST, vnet_lltable_init, NULL); + diff -drup src-org/sys/net/if_vlan.c src/sys/net/if_vlan.c --- src-org/sys/net/if_vlan.c 2009-10-25 01:10:29.000000000 +0000 +++ src/sys/net/if_vlan.c 2009-11-11 12:46:02.000000000 +0000 @@ -1359,6 +1359,12 @@ vlan_ioctl(struct ifnet *ifp, u_long cmd error = copyin(ifr->ifr_data, &vlr, sizeof(vlr)); if (error) break; +#ifdef VIMAGE + if (ifp->if_home_vnet != ifp->if_vnet) { + error = EPERM; + break; + } +#endif if (vlr.vlr_parent[0] == '\0') { vlan_unconfig(ifp); break; @@ -1386,6 +1392,12 @@ vlan_ioctl(struct ifnet *ifp, u_long cmd case SIOCGETVLAN: bzero(&vlr, sizeof(vlr)); +#ifdef VIMAGE + if (ifp->if_home_vnet != ifp->if_vnet) { + error = EPERM; + break; + } +#endif VLAN_LOCK(); if (TRUNK(ifv) != NULL) { strlcpy(vlr.vlr_parent, PARENT(ifv)->if_xname, diff -drup src-org/sys/netgraph/ng_bridge.c src/sys/netgraph/ng_bridge.c --- src-org/sys/netgraph/ng_bridge.c 2009-10-25 01:10:29.000000000 +0000 +++ src/sys/netgraph/ng_bridge.c 2009-11-11 12:46:02.000000000 +0000 @@ -105,6 +105,7 @@ struct ng_bridge_private { u_int numBuckets; /* num buckets in table */ u_int hashMask; /* numBuckets - 1 */ int numLinks; /* num connected links */ + int persistent; /* can exist w/o any hooks */ struct callout timer; /* one second periodic timer */ }; typedef struct ng_bridge_private *priv_p; @@ -345,13 +346,13 @@ static int ng_bridge_newhook(node_p node, hook_p hook, const char *name) { const priv_p priv = NG_NODE_PRIVATE(node); + int linkNum = -1; /* Check for a link hook */ if (strncmp(name, NG_BRIDGE_HOOK_LINK_PREFIX, strlen(NG_BRIDGE_HOOK_LINK_PREFIX)) == 0) { const char *cp; char *eptr; - u_long linkNum; cp = name + strlen(NG_BRIDGE_HOOK_LINK_PREFIX); if (!isdigit(*cp) || (cp[0] == '0' && cp[1] != '\0')) @@ -359,6 +360,12 @@ ng_bridge_newhook(node_p node, hook_p ho linkNum = strtoul(cp, &eptr, 10); if (*eptr != '\0' || linkNum >= NG_BRIDGE_MAX_LINKS) return (EINVAL); + } else if (strcmp(name, "anchor") == 0) { + linkNum = 0; + priv->persistent = 1; + } + + if (linkNum >= 0 ) { if (priv->links[linkNum] != NULL) return (EISCONN); priv->links[linkNum] = malloc(sizeof(*priv->links[linkNum]), @@ -366,7 +373,7 @@ ng_bridge_newhook(node_p node, hook_p ho if (priv->links[linkNum] == NULL) return (ENOMEM); priv->links[linkNum]->hook = hook; - NG_HOOK_SET_PRIVATE(hook, (void *)linkNum); + NG_HOOK_SET_PRIVATE(hook, (void *)(intptr_t)linkNum); priv->numLinks++; return (0); } @@ -799,7 +806,8 @@ ng_bridge_disconnect(hook_p hook) /* If no more hooks, go away */ if ((NG_NODE_NUMHOOKS(NG_HOOK_NODE(hook)) == 0) - && (NG_NODE_IS_VALID(NG_HOOK_NODE(hook)))) { + && (NG_NODE_IS_VALID(NG_HOOK_NODE(hook))) + && !priv->persistent) { ng_rmnode_self(NG_HOOK_NODE(hook)); } return (0); diff -drup src-org/sys/netgraph/ng_hub.c src/sys/netgraph/ng_hub.c --- src-org/sys/netgraph/ng_hub.c 2009-10-25 01:10:29.000000000 +0000 +++ src/sys/netgraph/ng_hub.c 2009-11-11 12:46:02.000000000 +0000 @@ -37,6 +37,7 @@ #include static ng_constructor_t ng_hub_constructor; +static ng_newhook_t ng_hub_newhook; static ng_rcvdata_t ng_hub_rcvdata; static ng_disconnect_t ng_hub_disconnect; @@ -44,6 +45,7 @@ static struct ng_type ng_hub_typestruct .version = NG_ABI_VERSION, .name = NG_HUB_NODE_TYPE, .constructor = ng_hub_constructor, + .newhook = ng_hub_newhook, .rcvdata = ng_hub_rcvdata, .disconnect = ng_hub_disconnect, }; @@ -57,6 +59,14 @@ ng_hub_constructor(node_p node) return (0); } +static int +ng_hub_newhook(node_p node, hook_p hook, const char *name) +{ + if (strcmp(name, "anchor") == 0) + node->nd_private = (void *) 1; + return (0); +} + static int ng_hub_rcvdata(hook_p hook, item_p item) { @@ -94,7 +104,7 @@ ng_hub_disconnect(hook_p hook) { if (NG_NODE_NUMHOOKS(NG_HOOK_NODE(hook)) == 0 && - NG_NODE_IS_VALID(NG_HOOK_NODE(hook))) + NG_NODE_IS_VALID(NG_HOOK_NODE(hook)) && !hook->hk_node->nd_private) ng_rmnode_self(NG_HOOK_NODE(hook)); return (0); } core-4.8/kernel/freebsd/ng_pipe/0000775000175000017500000000000012534327775013652 500000000000000core-4.8/kernel/freebsd/ng_pipe/Makefile0000664000175000017500000000065312534327775015236 00000000000000# # (c)2008 the Boeing Company # # modified ng_pipe node # .if !defined(PLATFORM) #PLATFORM=i386 PLATFORM=amd64 .endif CFLAGS=-DBOEING_WLAN -I/usr/src/sys/${PLATFORM}/compile/CORE KMOD= ng_pipe SRCS= ng_pipe.c #MAN= ng_pipe.4 # FreeBSD 4.11 is "FreeBSD" and 7.0 is "freebsd7.0" #.if defined(OSTYPE) #.if (${OSTYPE} == "FreeBSD") #CFLAGS+=-DFREEBSD411 #SRCS= ng_pipe_freebsd4.c #.endif #.endif .include core-4.8/kernel/freebsd/ng_pipe/README0000664000175000017500000000163512534327775014457 00000000000000 ng_pipe FreeBSD kernel module See the copyright statement at the top of the source file. Copyright (c) 2004, 2005, 2007 University of Zagreb Copyright (c) 2007 FreeBSD Foundation (c) 2008 the Boeing Company modifications: Jeff Ahrenholz More complete documentation is available in the ng_pipe(4) man page. This version of ng_pipe has been modified as follows: - added burst rate (or burstiness) which is the probability that the next packet will be dropped given an error with the current packet, 0 to 100 - added jitter effect, which randomizes the delay an additional amount from 0 to jitter microseconds - ng_wlan support added, to remove and read mbuf tags containing wlan link effect information - bugfix: random number generation improved from defective modulo algorithm - bugfix: fixed mbuf dangling pointer reference when ng_pipe has both duplicates and errors configured core-4.8/kernel/freebsd/ng_pipe/ng_pipe.c0000664000175000017500000010047212534327775015363 00000000000000/* * Copyright (c) 2004-2008 University of Zagreb * Copyright (c) 2007-2008 FreeBSD Foundation * * This software was developed by the University of Zagreb and the * FreeBSD Foundation under sponsorship by the Stichting NLnet and the * FreeBSD Foundation. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * This node permits simple traffic shaping by emulating bandwidth * and delay, as well as random packet losses. * The node has two hooks, upper and lower. Traffic flowing from upper to * lower hook is referenced as downstream, and vice versa. Parameters for * both directions can be set separately, except for delay. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef BOEING_WLAN #include "ng_pipe.h" #include "../ng_wlan/ng_wlan.h" #include "../ng_wlan/ng_wlan_tag.h" #else #include #endif /* BOEING_WLAN */ static MALLOC_DEFINE(M_NG_PIPE, "ng_pipe", "ng_pipe"); struct mtx ng_pipe_giant; /* Packet header struct */ struct ngp_hdr { TAILQ_ENTRY(ngp_hdr) ngp_link; /* next pkt in queue */ struct timeval when; /* this packet's due time */ struct mbuf *m; /* ptr to the packet data */ }; TAILQ_HEAD(p_head, ngp_hdr); /* FIFO queue struct */ struct ngp_fifo { TAILQ_ENTRY(ngp_fifo) fifo_le; /* list of active queues only */ struct p_head packet_head; /* FIFO queue head */ u_int32_t hash; /* flow signature */ struct timeval vtime; /* virtual time, for WFQ */ u_int32_t rr_deficit; /* for DRR */ u_int32_t packets; /* # of packets in this queue */ }; /* Per hook info */ struct hookinfo { hook_p hook; int noqueue; /* bypass any processing */ TAILQ_HEAD(, ngp_fifo) fifo_head; /* FIFO queues */ TAILQ_HEAD(, ngp_hdr) qout_head; /* delay queue head */ LIST_ENTRY(hookinfo) active_le; /* active hooks */ struct timeval qin_utime; struct ng_pipe_hookcfg cfg; struct ng_pipe_hookrun run; struct ng_pipe_hookstat stats; uint64_t *ber_p; /* loss_p(BER,psize) map */ }; /* Per node info */ struct node_priv { u_int64_t delay; u_int32_t overhead; u_int32_t header_offset; struct hookinfo lower; struct hookinfo upper; }; typedef struct node_priv *priv_p; /* Macro for calculating the virtual time for packet dequeueing in WFQ */ #define FIFO_VTIME_SORT(plen) \ if (hinfo->cfg.wfq && hinfo->cfg.bandwidth) { \ ngp_f->vtime.tv_usec = now->tv_usec + ((uint64_t) (plen) \ + priv->overhead ) * hinfo->run.fifo_queues * \ 8000000 / hinfo->cfg.bandwidth; \ ngp_f->vtime.tv_sec = now->tv_sec + \ ngp_f->vtime.tv_usec / 1000000; \ ngp_f->vtime.tv_usec = ngp_f->vtime.tv_usec % 1000000; \ TAILQ_FOREACH(ngp_f1, &hinfo->fifo_head, fifo_le) \ if (ngp_f1->vtime.tv_sec > ngp_f->vtime.tv_sec || \ (ngp_f1->vtime.tv_sec == ngp_f->vtime.tv_sec && \ ngp_f1->vtime.tv_usec > ngp_f->vtime.tv_usec)) \ break; \ if (ngp_f1 == NULL) \ TAILQ_INSERT_TAIL(&hinfo->fifo_head, ngp_f, fifo_le); \ else \ TAILQ_INSERT_BEFORE(ngp_f1, ngp_f, fifo_le); \ } else \ TAILQ_INSERT_TAIL(&hinfo->fifo_head, ngp_f, fifo_le); \ static void parse_cfg(struct ng_pipe_hookcfg *, struct ng_pipe_hookcfg *, struct hookinfo *, priv_p); static void pipe_dequeue(struct hookinfo *, struct timeval *); static void pipe_scheduler(void *); static void pipe_poll(void); static int ngp_modevent(module_t, int, void *); /* linked list of active "pipe" hooks */ static LIST_HEAD(, hookinfo) active_head; static int active_gen_id = 0; /* timeout handle for pipe_scheduler */ static struct callout polling_timer; /* zone for storing ngp_hdr-s */ static uma_zone_t ngp_zone; /* Netgraph methods */ static ng_constructor_t ngp_constructor; static ng_rcvmsg_t ngp_rcvmsg; static ng_shutdown_t ngp_shutdown; static ng_newhook_t ngp_newhook; static ng_rcvdata_t ngp_rcvdata; static ng_disconnect_t ngp_disconnect; /* Parse type for struct ng_pipe_hookstat */ static const struct ng_parse_struct_field ng_pipe_hookstat_type_fields[] = NG_PIPE_HOOKSTAT_INFO; static const struct ng_parse_type ng_pipe_hookstat_type = { &ng_parse_struct_type, &ng_pipe_hookstat_type_fields }; /* Parse type for struct ng_pipe_stats */ static const struct ng_parse_struct_field ng_pipe_stats_type_fields[] = NG_PIPE_STATS_INFO(&ng_pipe_hookstat_type); static const struct ng_parse_type ng_pipe_stats_type = { &ng_parse_struct_type, &ng_pipe_stats_type_fields }; /* Parse type for struct ng_pipe_hookrun */ static const struct ng_parse_struct_field ng_pipe_hookrun_type_fields[] = NG_PIPE_HOOKRUN_INFO; static const struct ng_parse_type ng_pipe_hookrun_type = { &ng_parse_struct_type, &ng_pipe_hookrun_type_fields }; /* Parse type for struct ng_pipe_run */ static const struct ng_parse_struct_field ng_pipe_run_type_fields[] = NG_PIPE_RUN_INFO(&ng_pipe_hookrun_type); static const struct ng_parse_type ng_pipe_run_type = { &ng_parse_struct_type, &ng_pipe_run_type_fields }; /* Parse type for struct ng_pipe_hookcfg */ static const struct ng_parse_struct_field ng_pipe_hookcfg_type_fields[] = NG_PIPE_HOOKCFG_INFO; static const struct ng_parse_type ng_pipe_hookcfg_type = { &ng_parse_struct_type, &ng_pipe_hookcfg_type_fields }; /* Parse type for struct ng_pipe_cfg */ static const struct ng_parse_struct_field ng_pipe_cfg_type_fields[] = NG_PIPE_CFG_INFO(&ng_pipe_hookcfg_type); static const struct ng_parse_type ng_pipe_cfg_type = { &ng_parse_struct_type, &ng_pipe_cfg_type_fields }; /* List of commands and how to convert arguments to/from ASCII */ static const struct ng_cmdlist ngp_cmds[] = { { .cookie = NGM_PIPE_COOKIE, .cmd = NGM_PIPE_GET_STATS, .name = "getstats", .respType = &ng_pipe_stats_type }, { .cookie = NGM_PIPE_COOKIE, .cmd = NGM_PIPE_CLR_STATS, .name = "clrstats" }, { .cookie = NGM_PIPE_COOKIE, .cmd = NGM_PIPE_GETCLR_STATS, .name = "getclrstats", .respType = &ng_pipe_stats_type }, { .cookie = NGM_PIPE_COOKIE, .cmd = NGM_PIPE_GET_RUN, .name = "getrun", .respType = &ng_pipe_run_type }, { .cookie = NGM_PIPE_COOKIE, .cmd = NGM_PIPE_GET_CFG, .name = "getcfg", .respType = &ng_pipe_cfg_type }, { .cookie = NGM_PIPE_COOKIE, .cmd = NGM_PIPE_SET_CFG, .name = "setcfg", .mesgType = &ng_pipe_cfg_type, }, { 0 } }; /* Netgraph type descriptor */ static struct ng_type ng_pipe_typestruct = { .version = NG_ABI_VERSION, .name = NG_PIPE_NODE_TYPE, .mod_event = ngp_modevent, .constructor = ngp_constructor, .shutdown = ngp_shutdown, .rcvmsg = ngp_rcvmsg, .newhook = ngp_newhook, .rcvdata = ngp_rcvdata, .disconnect = ngp_disconnect, .cmdlist = ngp_cmds }; NETGRAPH_INIT(pipe, &ng_pipe_typestruct); /* Node constructor */ static int ngp_constructor(node_p node) { priv_p priv; MALLOC(priv, priv_p, sizeof(*priv), M_NG_PIPE, M_ZERO | M_NOWAIT); if (priv == NULL) return (ENOMEM); NG_NODE_SET_PRIVATE(node, priv); return (0); } /* Add a hook */ static int ngp_newhook(node_p node, hook_p hook, const char *name) { const priv_p priv = NG_NODE_PRIVATE(node); struct hookinfo *hinfo; if (strcmp(name, NG_PIPE_HOOK_UPPER) == 0) { bzero(&priv->upper, sizeof(priv->upper)); priv->upper.hook = hook; NG_HOOK_SET_PRIVATE(hook, &priv->upper); } else if (strcmp(name, NG_PIPE_HOOK_LOWER) == 0) { bzero(&priv->lower, sizeof(priv->lower)); priv->lower.hook = hook; NG_HOOK_SET_PRIVATE(hook, &priv->lower); } else return (EINVAL); /* Load non-zero initial cfg values */ hinfo = NG_HOOK_PRIVATE(hook); hinfo->cfg.qin_size_limit = 50; hinfo->cfg.fifo = 1; hinfo->cfg.droptail = 1; TAILQ_INIT(&hinfo->fifo_head); TAILQ_INIT(&hinfo->qout_head); return (0); } /* Receive a control message */ static int ngp_rcvmsg(node_p node, item_p item, hook_p lasthook) { const priv_p priv = NG_NODE_PRIVATE(node); struct ng_mesg *resp = NULL; struct ng_mesg *msg; struct ng_pipe_stats *stats; struct ng_pipe_run *run; struct ng_pipe_cfg *cfg; int error = 0; mtx_lock(&ng_pipe_giant); NGI_GET_MSG(item, msg); switch (msg->header.typecookie) { case NGM_PIPE_COOKIE: switch (msg->header.cmd) { case NGM_PIPE_GET_STATS: case NGM_PIPE_CLR_STATS: case NGM_PIPE_GETCLR_STATS: if (msg->header.cmd != NGM_PIPE_CLR_STATS) { NG_MKRESPONSE(resp, msg, sizeof(*stats), M_NOWAIT); if (resp == NULL) { error = ENOMEM; break; } stats = (struct ng_pipe_stats *)resp->data; bcopy(&priv->upper.stats, &stats->downstream, sizeof(stats->downstream)); bcopy(&priv->lower.stats, &stats->upstream, sizeof(stats->upstream)); } if (msg->header.cmd != NGM_PIPE_GET_STATS) { bzero(&priv->upper.stats, sizeof(priv->upper.stats)); bzero(&priv->lower.stats, sizeof(priv->lower.stats)); } break; case NGM_PIPE_GET_RUN: NG_MKRESPONSE(resp, msg, sizeof(*run), M_NOWAIT); if (resp == NULL) { error = ENOMEM; break; } run = (struct ng_pipe_run *)resp->data; bcopy(&priv->upper.run, &run->downstream, sizeof(run->downstream)); bcopy(&priv->lower.run, &run->upstream, sizeof(run->upstream)); break; case NGM_PIPE_GET_CFG: NG_MKRESPONSE(resp, msg, sizeof(*cfg), M_NOWAIT); if (resp == NULL) { error = ENOMEM; break; } cfg = (struct ng_pipe_cfg *)resp->data; bcopy(&priv->upper.cfg, &cfg->downstream, sizeof(cfg->downstream)); bcopy(&priv->lower.cfg, &cfg->upstream, sizeof(cfg->upstream)); cfg->delay = priv->delay; cfg->overhead = priv->overhead; cfg->header_offset = priv->header_offset; if (cfg->upstream.bandwidth == cfg->downstream.bandwidth) { cfg->bandwidth = cfg->upstream.bandwidth; cfg->upstream.bandwidth = 0; cfg->downstream.bandwidth = 0; } else cfg->bandwidth = 0; break; case NGM_PIPE_SET_CFG: cfg = (struct ng_pipe_cfg *)msg->data; if (msg->header.arglen != sizeof(*cfg)) { error = EINVAL; break; } if (cfg->delay == -1) priv->delay = 0; else if (cfg->delay > 0 && cfg->delay < 10000000) priv->delay = cfg->delay; if (cfg->bandwidth == -1) { priv->upper.cfg.bandwidth = 0; priv->lower.cfg.bandwidth = 0; priv->overhead = 0; } else if (cfg->bandwidth >= 100 && cfg->bandwidth <= 1000000000) { priv->upper.cfg.bandwidth = cfg->bandwidth; priv->lower.cfg.bandwidth = cfg->bandwidth; if (cfg->bandwidth >= 10000000) priv->overhead = 8+4+12; /* Ethernet */ else priv->overhead = 10; /* HDLC */ } if (cfg->overhead == -1) priv->overhead = 0; else if (cfg->overhead > 0 && cfg->overhead < 256) priv->overhead = cfg->overhead; if (cfg->header_offset == -1) priv->header_offset = 0; else if (cfg->header_offset > 0 && cfg->header_offset < 64) priv->header_offset = cfg->header_offset; parse_cfg(&priv->upper.cfg, &cfg->downstream, &priv->upper, priv); parse_cfg(&priv->lower.cfg, &cfg->upstream, &priv->lower, priv); break; default: error = EINVAL; break; } break; default: error = EINVAL; break; } NG_RESPOND_MSG(error, node, item, resp); NG_FREE_MSG(msg); mtx_unlock(&ng_pipe_giant); return (error); } static void parse_cfg(struct ng_pipe_hookcfg *current, struct ng_pipe_hookcfg *new, struct hookinfo *hinfo, priv_p priv) { if (new->ber == -1) { current->ber = 0; if (hinfo->ber_p) { FREE(hinfo->ber_p, M_NG_PIPE); hinfo->ber_p = NULL; } } else if (new->ber >= 1 && new->ber <= 1000000000000) { static const uint64_t one = 0x1000000000000; /* = 2^48 */ uint64_t p0, p; uint32_t fsize, i; if (hinfo->ber_p == NULL) MALLOC(hinfo->ber_p, uint64_t *, \ (MAX_FSIZE + MAX_OHSIZE)*sizeof(uint64_t), \ M_NG_PIPE, M_NOWAIT); current->ber = new->ber; /* * For given BER and each frame size N (in bytes) calculate * the probability P_OK that the frame is clean: * * P_OK(BER,N) = (1 - 1/BER)^(N*8) * * We use a 64-bit fixed-point format with decimal point * positioned between bits 47 and 48. */ p0 = one - one / new->ber; p = one; for (fsize = 0; fsize < MAX_FSIZE + MAX_OHSIZE; fsize++) { hinfo->ber_p[fsize] = p; for (i=0; i<8; i++) p = (p*(p0&0xffff)>>48) + \ (p*((p0>>16)&0xffff)>>32) + \ (p*(p0>>32)>>16); } } if (new->qin_size_limit == -1) current->qin_size_limit = 0; else if (new->qin_size_limit >= 5) current->qin_size_limit = new->qin_size_limit; if (new->qout_size_limit == -1) current->qout_size_limit = 0; else if (new->qout_size_limit >= 5) current->qout_size_limit = new->qout_size_limit; if (new->duplicate == -1) current->duplicate = 0; else if (new->duplicate > 0 && new->duplicate <= 50) current->duplicate = new->duplicate; if (new->fifo) { current->fifo = 1; current->wfq = 0; current->drr = 0; } if (new->wfq) { current->fifo = 0; current->wfq = 1; current->drr = 0; } if (new->drr) { current->fifo = 0; current->wfq = 0; /* DRR quantum */ if (new->drr >= 32) current->drr = new->drr; else current->drr = 2048; /* default quantum */ } if (new->droptail) { current->droptail = 1; current->drophead = 0; } if (new->drophead) { current->droptail = 0; current->drophead = 1; } if (new->bandwidth == -1) { current->bandwidth = 0; current->fifo = 1; current->wfq = 0; current->drr = 0; } else if (new->bandwidth >= 100 && new->bandwidth <= 1000000000) current->bandwidth = new->bandwidth; if (current->bandwidth | priv->delay | current->duplicate | current->ber) hinfo->noqueue = 0; else hinfo->noqueue = 1; } /* * Compute a hash signature for a packet. This function suffers from the * NIH sindrome, so probably it would be wise to look around what other * folks have found out to be a good and efficient IP hash function... */ static int ip_hash(struct mbuf *m, int offset) { u_int64_t i; struct ip *ip = (struct ip *)(mtod(m, u_char *) + offset); if (m->m_len < sizeof(struct ip) + offset || ip->ip_v != 4 || ip->ip_hl << 2 != sizeof(struct ip)) return 0; i = ((u_int64_t) ip->ip_src.s_addr ^ ((u_int64_t) ip->ip_src.s_addr << 13) ^ ((u_int64_t) ip->ip_dst.s_addr << 7) ^ ((u_int64_t) ip->ip_dst.s_addr << 19)); return (i ^ (i >> 32)); } /* * Receive data on a hook - both in upstream and downstream direction. * We put the frame on the inbound queue, and try to initiate dequeuing * sequence immediately. If inbound queue is full, discard one frame * depending on dropping policy (from the head or from the tail of the * queue). */ static int ngp_rcvdata(hook_p hook, item_p item) { struct hookinfo *const hinfo = NG_HOOK_PRIVATE(hook); const priv_p priv = NG_NODE_PRIVATE(NG_HOOK_NODE(hook)); struct timeval uuptime; struct timeval *now = &uuptime; struct ngp_fifo *ngp_f = NULL, *ngp_f1; struct ngp_hdr *ngp_h = NULL; struct mbuf *m; int hash; int error = 0; if (hinfo->noqueue) { struct hookinfo *dest; if (hinfo == &priv->lower) dest = &priv->upper; else dest = &priv->lower; NG_FWD_ITEM_HOOK(error, item, dest->hook); return error; } mtx_lock(&ng_pipe_giant); microuptime(now); /* * Attach us to the list of active ng_pipes if this was an empty * one before, and also update the queue service deadline time. */ if (hinfo->run.qin_frames == 0) { struct timeval *when = &hinfo->qin_utime; if (when->tv_sec < now->tv_sec || (when->tv_sec == now->tv_sec && when->tv_usec < now->tv_usec)) { when->tv_sec = now->tv_sec; when->tv_usec = now->tv_usec; } if (hinfo->run.qout_frames == 0) LIST_INSERT_HEAD(&active_head, hinfo, active_le); } /* Populate the packet header */ ngp_h = uma_zalloc(ngp_zone, M_NOWAIT); KASSERT((ngp_h != NULL), ("ngp_h zalloc failed (1)")); NGI_GET_M(item, m); KASSERT(m != NULL, ("NGI_GET_M failed")); ngp_h->m = m; NG_FREE_ITEM(item); if (hinfo->cfg.fifo) hash = 0; /* all packets go into a single FIFO queue */ else hash = ip_hash(m, priv->header_offset); /* Find the appropriate FIFO queue for the packet and enqueue it*/ TAILQ_FOREACH(ngp_f, &hinfo->fifo_head, fifo_le) if (hash == ngp_f->hash) break; if (ngp_f == NULL) { ngp_f = uma_zalloc(ngp_zone, M_NOWAIT); KASSERT(ngp_h != NULL, ("ngp_h zalloc failed (2)")); TAILQ_INIT(&ngp_f->packet_head); ngp_f->hash = hash; ngp_f->packets = 1; ngp_f->rr_deficit = hinfo->cfg.drr; /* DRR quantum */ hinfo->run.fifo_queues++; TAILQ_INSERT_TAIL(&ngp_f->packet_head, ngp_h, ngp_link); FIFO_VTIME_SORT(m->m_pkthdr.len); } else { TAILQ_INSERT_TAIL(&ngp_f->packet_head, ngp_h, ngp_link); ngp_f->packets++; } hinfo->run.qin_frames++; hinfo->run.qin_octets += m->m_pkthdr.len; /* Discard a frame if inbound queue limit has been reached */ if (hinfo->run.qin_frames > hinfo->cfg.qin_size_limit) { struct mbuf *m1; int longest = 0; /* Find the longest queue */ TAILQ_FOREACH(ngp_f1, &hinfo->fifo_head, fifo_le) if (ngp_f1->packets > longest) { longest = ngp_f1->packets; ngp_f = ngp_f1; } /* Drop a frame from the queue head/tail, depending on cfg */ if (hinfo->cfg.drophead) ngp_h = TAILQ_FIRST(&ngp_f->packet_head); else ngp_h = TAILQ_LAST(&ngp_f->packet_head, p_head); TAILQ_REMOVE(&ngp_f->packet_head, ngp_h, ngp_link); m1 = ngp_h->m; uma_zfree(ngp_zone, ngp_h); hinfo->run.qin_octets -= m1->m_pkthdr.len; hinfo->stats.in_disc_octets += m1->m_pkthdr.len; m_freem(m1); if (--(ngp_f->packets) == 0) { TAILQ_REMOVE(&hinfo->fifo_head, ngp_f, fifo_le); uma_zfree(ngp_zone, ngp_f); hinfo->run.fifo_queues--; } hinfo->run.qin_frames--; hinfo->stats.in_disc_frames++; } else if (hinfo->run.qin_frames > hinfo->cfg.qin_size_limit) { struct mbuf *m1; int longest = 0; /* Find the longest queue */ TAILQ_FOREACH(ngp_f1, &hinfo->fifo_head, fifo_le) if (ngp_f1->packets > longest) { longest = ngp_f1->packets; ngp_f = ngp_f1; } /* Drop a frame from the queue head/tail, depending on cfg */ if (hinfo->cfg.drophead) ngp_h = TAILQ_FIRST(&ngp_f->packet_head); else ngp_h = TAILQ_LAST(&ngp_f->packet_head, p_head); TAILQ_REMOVE(&ngp_f->packet_head, ngp_h, ngp_link); m1 = ngp_h->m; uma_zfree(ngp_zone, ngp_h); hinfo->run.qin_octets -= m1->m_pkthdr.len; hinfo->stats.in_disc_octets += m1->m_pkthdr.len; m_freem(m1); if (--(ngp_f->packets) == 0) { TAILQ_REMOVE(&hinfo->fifo_head, ngp_f, fifo_le); uma_zfree(ngp_zone, ngp_f); hinfo->run.fifo_queues--; } hinfo->run.qin_frames--; hinfo->stats.in_disc_frames++; } /* * Try to start the dequeuing process immediately. We must * hold the ng_pipe_giant lock here and pipe_dequeue() will * release it */ pipe_dequeue(hinfo, now); return (0); } #ifdef BOEING_WLAN /* generate a random integer between 1 and max */ #define pipe_good_random(max) (1 + (random() % max)) #if 0 /* generate a good random integer between 1 and max */ #define pipe_good_random(max) \ (1 + (int) (max * (random() / (__ULONG_MAX + 1.0)))) #endif #endif /* * Dequeueing sequence - we basically do the following: * 1) Try to extract the frame from the inbound (bandwidth) queue; * 2) In accordance to BER specified, discard the frame randomly; * 3) If the frame survives BER, prepend it with delay info and move it * to outbound (delay) queue; * 4) Loop to 2) until bandwidth quota for this timeslice is reached, or * inbound queue is flushed completely; * 5) Extract the first frame from the outbound queue, if it's time has * come. Queue the frame for transmission on the outbound hook; * 6) Loop to 5) until outbound queue is flushed completely, or the next * frame in the queue is not scheduled to be dequeued yet; * 7) Transimit all frames queued in 5) * * Note: the caller must hold the ng_pipe_giant lock; this function * returns with the lock released. */ static void pipe_dequeue(struct hookinfo *hinfo, struct timeval *now) { static uint64_t rand, oldrand; const priv_p priv = NG_NODE_PRIVATE(NG_HOOK_NODE(hinfo->hook)); struct hookinfo *dest; struct ngp_fifo *ngp_f, *ngp_f1; struct ngp_hdr *ngp_h; struct timeval *when; struct mbuf *q_head = NULL; struct mbuf *q_tail = NULL; struct mbuf *m; int error = 0; #ifdef BOEING_WLAN struct ngp_hdr *ngp_h1 = NULL; struct m_tag *tag = NULL; struct ng_wlan_tag wtag; static int was_lost = 0; #endif /* BOEING_WLAN */ /* Which one is the destination hook? */ if (hinfo == &priv->lower) dest = &priv->upper; else dest = &priv->lower; /* Bandwidth queue processing */ while ((ngp_f = TAILQ_FIRST(&hinfo->fifo_head))) { when = &hinfo->qin_utime; if (when->tv_sec > now->tv_sec || (when->tv_sec == now->tv_sec && when->tv_usec > now->tv_usec)) break; ngp_h = TAILQ_FIRST(&ngp_f->packet_head); m = ngp_h->m; #ifdef BOEING_WLAN /* Check the first mbuf tag for WLAN data, and remove it */ tag = m_tag_first(m); if (tag && (tag->m_tag_cookie == NGM_WLAN_COOKIE) && (tag->m_tag_id == NG_TAG_WLAN)) { WLAN_TAG_COPY( (&wtag), tag) /* enforce maximum parameters */ if (wtag.delay > NG_WLAN_MAX_DELAY) wtag.delay = NG_WLAN_MAX_DELAY; if (wtag.duplicate > NG_WLAN_MAX_DUP) wtag.duplicate = NG_WLAN_MAX_DUP; if (wtag.jitter > NG_WLAN_MAX_JITTER) wtag.jitter = NG_WLAN_MAX_JITTER; m_tag_delete(m, tag); } else { WLAN_TAG_ZERO( (&wtag) ); } #endif /* BOEING_WLAN */ /* Deficit Round Robin (DRR) processing */ if (hinfo->cfg.drr) { if (ngp_f->rr_deficit >= m->m_pkthdr.len) { ngp_f->rr_deficit -= m->m_pkthdr.len; } else { ngp_f->rr_deficit += hinfo->cfg.drr; TAILQ_REMOVE(&hinfo->fifo_head, ngp_f, fifo_le); TAILQ_INSERT_TAIL(&hinfo->fifo_head, ngp_f, fifo_le); continue; } } /* * Either create a duplicate and pass it on, or dequeue * the original packet... */ #ifdef BOEING_WLAN if (wtag.duplicate && pipe_good_random(100) <= wtag.duplicate) { ngp_h = uma_zalloc(ngp_zone, M_NOWAIT); KASSERT(ngp_h != NULL, ("ngp_h zalloc failed (3)")); ngp_h->m = m_dup(m, M_NOWAIT); KASSERT(ngp_h->m != NULL, ("m_dup failed")); m = ngp_h->m; /* Boeing: we are now working with copied mbuf, leaving original in the queue */ } else #endif /* BOEING_WLAN */ if (hinfo->cfg.duplicate && pipe_good_random(100) <= hinfo->cfg.duplicate) {/*Boeing*/ /* random() % 100 <= hinfo->cfg.duplicate) { */ ngp_h = uma_zalloc(ngp_zone, M_NOWAIT); KASSERT(ngp_h != NULL, ("ngp_h zalloc failed (3)")); ngp_h->m = m_dup(m, M_NOWAIT); KASSERT(ngp_h->m != NULL, ("m_dup failed")); m = ngp_h->m; /* Boeing: we are now working with copied mbuf, leaving original in the queue */ } else { TAILQ_REMOVE(&ngp_f->packet_head, ngp_h, ngp_link); hinfo->run.qin_frames--; hinfo->run.qin_octets -= m->m_pkthdr.len; ngp_f->packets--; } /* Boeing: now we have valid ngp_h and m pointers */ /* Calculate the serialization delay */ #ifdef BOEING_WLAN if (wtag.bandwidth) { hinfo->qin_utime.tv_usec += ((uint64_t) m->m_pkthdr.len + priv->overhead ) * 8000000 / wtag.bandwidth; hinfo->qin_utime.tv_sec += hinfo->qin_utime.tv_usec / 1000000; hinfo->qin_utime.tv_usec = hinfo->qin_utime.tv_usec % 1000000; } else #endif /* BOEING_WLAN */ if (hinfo->cfg.bandwidth) { hinfo->qin_utime.tv_usec += ((uint64_t) m->m_pkthdr.len + priv->overhead ) * 8000000 / hinfo->cfg.bandwidth; hinfo->qin_utime.tv_sec += hinfo->qin_utime.tv_usec / 1000000; hinfo->qin_utime.tv_usec = hinfo->qin_utime.tv_usec % 1000000; } when = &ngp_h->when; when->tv_sec = hinfo->qin_utime.tv_sec; when->tv_usec = hinfo->qin_utime.tv_usec; /* Sort / rearrange inbound queues */ if (ngp_f->packets) { if (hinfo->cfg.wfq) { TAILQ_REMOVE(&hinfo->fifo_head, ngp_f, fifo_le); FIFO_VTIME_SORT(TAILQ_FIRST( &ngp_f->packet_head)->m->m_pkthdr.len) } } else { TAILQ_REMOVE(&hinfo->fifo_head, ngp_f, fifo_le); uma_zfree(ngp_zone, ngp_f); hinfo->run.fifo_queues--; } /* Randomly discard the frame, according to BER setting */ #ifdef BOEING_WLAN /* use specified Packet Error Rate setting for random discard */ if (wtag.per) { u_int16_t burst, test; burst = wtag.burst; if (burst < wtag.per) burst = wtag.per; if (was_lost) { test = burst; } else if ((wtag.per >= 100) || (burst >= 100)) { test = 100; } else { test = wtag.per*(100-burst)/(100-wtag.per); } if (pipe_good_random(100) <= test) { was_lost = 1; hinfo->stats.out_disc_frames++; hinfo->stats.out_disc_octets += m->m_pkthdr.len; uma_zfree(ngp_zone, ngp_h); m_freem(m); continue; } was_lost = 0; } else #endif /* BOEING_WLAN */ if (hinfo->cfg.ber && ((oldrand = rand) ^ (rand = random())<<17) >= hinfo->ber_p[priv->overhead + m->m_pkthdr.len] ) { hinfo->stats.out_disc_frames++; hinfo->stats.out_disc_octets += m->m_pkthdr.len; uma_zfree(ngp_zone, ngp_h); m_freem(m); continue; } /* Discard frame if outbound queue size limit exceeded */ if (hinfo->cfg.qout_size_limit && hinfo->run.qout_frames>=hinfo->cfg.qout_size_limit) { hinfo->stats.out_disc_frames++; hinfo->stats.out_disc_octets += m->m_pkthdr.len; uma_zfree(ngp_zone, ngp_h); m_freem(m); continue; } #ifdef BOEING_WLAN /* Calculate the propagation delay including jitter */ if (wtag.jitter) { when->tv_usec += pipe_good_random(wtag.jitter); /* overflow handled below... */ } when->tv_usec += wtag.delay ? wtag.delay : priv->delay; #else /* Calculate the propagation delay */ when->tv_usec += priv->delay; #endif /* BOEING_WLAN */ when->tv_sec += when->tv_usec / 1000000; when->tv_usec = when->tv_usec % 1000000; /* Put the frame into the delay queue */ #ifdef BOEING_WLAN /* Because WLAN packets may have varying dequeue times, we need to * perform sorted queueing; the dequeuing process expects packets in * the queue that are sorted by time. */ TAILQ_FOREACH(ngp_h1, &hinfo->qout_head, ngp_link) { if (ngp_h1->when.tv_sec > ngp_h->when.tv_sec || (ngp_h1->when.tv_sec == ngp_h->when.tv_sec && ngp_h1->when.tv_usec > ngp_h->when.tv_usec)) break; } if (ngp_h1 == NULL) TAILQ_INSERT_TAIL(&hinfo->qout_head, ngp_h, ngp_link); else TAILQ_INSERT_BEFORE(ngp_h1, ngp_h, ngp_link); /* The original code below just inserts the packet at the * tail of the queue because the delay time is constant. */ #else /* BOEING_WLAN */ TAILQ_INSERT_TAIL(&hinfo->qout_head, ngp_h, ngp_link); #endif /* BOEING_WLAN */ hinfo->run.qout_frames++; hinfo->run.qout_octets += m->m_pkthdr.len; } /* Delay queue processing */ while ((ngp_h = TAILQ_FIRST(&hinfo->qout_head))) { struct mbuf *m = ngp_h->m; /* BOEING_WLAN: this is why we have sorted the queue input */ when = &ngp_h->when; if (when->tv_sec > now->tv_sec || (when->tv_sec == now->tv_sec && when->tv_usec > now->tv_usec)) break; /* Update outbound queue stats */ hinfo->stats.fwd_frames++; hinfo->stats.fwd_octets += m->m_pkthdr.len; hinfo->run.qout_frames--; hinfo->run.qout_octets -= m->m_pkthdr.len; /* Dequeue the packet from qout */ TAILQ_REMOVE(&hinfo->qout_head, ngp_h, ngp_link); uma_zfree(ngp_zone, ngp_h); /* Enqueue locally for sending downstream */ if (q_head == NULL) q_head = m; if (q_tail) q_tail->m_nextpkt = m; q_tail = m; m->m_nextpkt = NULL; } /* If both queues are empty detach us from the list of active queues */ if (hinfo->run.qin_frames + hinfo->run.qout_frames == 0) { LIST_REMOVE(hinfo, active_le); active_gen_id++; } mtx_unlock(&ng_pipe_giant); while ((m = q_head) != NULL) { q_head = m->m_nextpkt; m->m_nextpkt = NULL; NG_SEND_DATA(error, dest->hook, m, meta); } } /* * This routine is called on every clock tick. We poll all nodes/hooks * for queued frames by calling pipe_dequeue(). */ static void pipe_scheduler(void *arg) { pipe_poll(); /* Reschedule */ callout_reset(&polling_timer, 1, &pipe_scheduler, NULL); } /* * Traverse the list of all active hooks and attempt to dequeue * some packets. Hooks with empty queues are not traversed since * they are not linked into this list. */ static void pipe_poll(void) { struct hookinfo *hinfo; struct timeval now; int old_gen_id = active_gen_id; mtx_lock(&ng_pipe_giant); microuptime(&now); LIST_FOREACH(hinfo, &active_head, active_le) { CURVNET_SET(NG_HOOK_NODE(hinfo->hook)->nd_vnet); pipe_dequeue(hinfo, &now); CURVNET_RESTORE(); mtx_lock(&ng_pipe_giant); if (old_gen_id != active_gen_id) { /* the list was updated; restart traversing */ hinfo = LIST_FIRST(&active_head); if (hinfo == NULL) break; old_gen_id = active_gen_id; continue; } } mtx_unlock(&ng_pipe_giant); } /* * Shutdown processing * * This is tricky. If we have both a lower and upper hook, then we * probably want to extricate ourselves and leave the two peers * still linked to each other. Otherwise we should just shut down as * a normal node would. */ static int ngp_shutdown(node_p node) { const priv_p priv = NG_NODE_PRIVATE(node); if (priv->lower.hook && priv->upper.hook) ng_bypass(priv->lower.hook, priv->upper.hook); else { if (priv->upper.hook != NULL) ng_rmhook_self(priv->upper.hook); if (priv->lower.hook != NULL) ng_rmhook_self(priv->lower.hook); } NG_NODE_UNREF(node); FREE(priv, M_NG_PIPE); return (0); } /* * Hook disconnection */ static int ngp_disconnect(hook_p hook) { struct hookinfo *const hinfo = NG_HOOK_PRIVATE(hook); struct ngp_fifo *ngp_f; struct ngp_hdr *ngp_h; int removed = 0; mtx_lock(&ng_pipe_giant); KASSERT(hinfo != NULL, ("%s: null info", __FUNCTION__)); hinfo->hook = NULL; /* Flush all fifo queues associated with the hook */ while ((ngp_f = TAILQ_FIRST(&hinfo->fifo_head))) { while ((ngp_h = TAILQ_FIRST(&ngp_f->packet_head))) { TAILQ_REMOVE(&ngp_f->packet_head, ngp_h, ngp_link); m_freem(ngp_h->m); uma_zfree(ngp_zone, ngp_h); removed++; } TAILQ_REMOVE(&hinfo->fifo_head, ngp_f, fifo_le); uma_zfree(ngp_zone, ngp_f); } /* Flush the delay queue */ while ((ngp_h = TAILQ_FIRST(&hinfo->qout_head))) { TAILQ_REMOVE(&hinfo->qout_head, ngp_h, ngp_link); m_freem(ngp_h->m); uma_zfree(ngp_zone, ngp_h); removed++; } /* * Both queues should be empty by now, so detach us from * the list of active queues */ if (removed) { LIST_REMOVE(hinfo, active_le); active_gen_id++; } if (hinfo->run.qin_frames + hinfo->run.qout_frames != removed) printf("Mismatch: queued=%d but removed=%d !?!", hinfo->run.qin_frames + hinfo->run.qout_frames, removed); /* Release the packet loss probability table (BER) */ if (hinfo->ber_p) FREE(hinfo->ber_p, M_NG_PIPE); mtx_unlock(&ng_pipe_giant); return (0); } static int ngp_modevent(module_t mod, int type, void *unused) { int error = 0; switch (type) { case MOD_LOAD: ngp_zone = uma_zcreate("ng_pipe", max(sizeof(struct ngp_hdr), sizeof (struct ngp_fifo)), NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, 0); if (ngp_zone == NULL) panic("ng_pipe: couldn't allocate descriptor zone"); mtx_init(&ng_pipe_giant, "ng_pipe_giant", NULL, MTX_DEF); LIST_INIT(&active_head); callout_init(&polling_timer, CALLOUT_MPSAFE); callout_reset(&polling_timer, 1, &pipe_scheduler, NULL); break; case MOD_UNLOAD: callout_drain(&polling_timer); uma_zdestroy(ngp_zone); mtx_destroy(&ng_pipe_giant); break; default: error = EOPNOTSUPP; break; } return (error); } core-4.8/kernel/freebsd/ng_pipe/ng_pipe.h0000664000175000017500000001276112534327775015373 00000000000000/* * Copyright (c) 2004, 2007 University of Zagreb * Copyright (c) 2007 FreeBSD Foundation * * This software was developed by the University of Zagreb and the * FreeBSD Foundation under sponsorship by the Stichting NLnet and the * FreeBSD Foundation. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef _NETGRAPH_PIPE_H_ #define _NETGRAPH_PIPE_H_ /* Node type name and magic cookie */ #define NG_PIPE_NODE_TYPE "pipe" #define NGM_PIPE_COOKIE 200708191 /* Hook names */ #define NG_PIPE_HOOK_UPPER "upper" #define NG_PIPE_HOOK_LOWER "lower" #define MAX_FSIZE 16384 /* Largest supported frame size, in bytes, for BER */ #define MAX_OHSIZE 256 /* Largest supported dummy-framing size, in bytes */ /* Statistics structure for one hook */ struct ng_pipe_hookstat { u_int64_t fwd_octets; u_int64_t fwd_frames; u_int64_t in_disc_octets; u_int64_t in_disc_frames; u_int64_t out_disc_octets; u_int64_t out_disc_frames; }; /* Keep this in sync with the above structure definition */ #define NG_PIPE_HOOKSTAT_INFO { \ { "FwdOctets", &ng_parse_uint64_type }, \ { "FwdFrames", &ng_parse_uint64_type }, \ { "queueDropOctets", &ng_parse_uint64_type }, \ { "queueDropFrames", &ng_parse_uint64_type }, \ { "delayDropOctets", &ng_parse_uint64_type }, \ { "delayDropFrames", &ng_parse_uint64_type }, \ { NULL }, \ } /* Statistics structure returned by NGM_PIPE_GET_STATS */ struct ng_pipe_stats { struct ng_pipe_hookstat downstream; struct ng_pipe_hookstat upstream; }; /* Keep this in sync with the above structure definition */ #define NG_PIPE_STATS_INFO(hstype) { \ { "downstream", (hstype) }, \ { "upstream", (hstype) }, \ { NULL }, \ } /* Runtime structure for one hook */ struct ng_pipe_hookrun { u_int32_t fifo_queues; u_int32_t qin_octets; u_int32_t qin_frames; u_int32_t qout_octets; u_int32_t qout_frames; }; /* Keep this in sync with the above structure definition */ #define NG_PIPE_HOOKRUN_INFO { \ { "queues", &ng_parse_uint32_type }, \ { "queuedOctets", &ng_parse_uint32_type }, \ { "queuedFrames", &ng_parse_uint32_type }, \ { "delayedOctets", &ng_parse_uint32_type }, \ { "delayedFrames", &ng_parse_uint32_type }, \ { NULL }, \ } /* Runtime structure returned by NGM_PIPE_GET_RUN */ struct ng_pipe_run { struct ng_pipe_hookrun downstream; struct ng_pipe_hookrun upstream; }; /* Keep this in sync with the above structure definition */ #define NG_PIPE_RUN_INFO(hstype) { \ { "downstream", (hstype) }, \ { "upstream", (hstype) }, \ { NULL }, \ } /* Config structure for one hook */ struct ng_pipe_hookcfg { u_int64_t bandwidth; u_int64_t ber; u_int32_t qin_size_limit; u_int32_t qout_size_limit; u_int32_t duplicate; u_int32_t fifo; u_int32_t drr; u_int32_t wfq; u_int32_t droptail; u_int32_t drophead; }; /* Keep this in sync with the above structure definition */ #define NG_PIPE_HOOKCFG_INFO { \ { "bandwidth", &ng_parse_uint64_type }, \ { "BER", &ng_parse_uint64_type }, \ { "queuelen", &ng_parse_uint32_type }, \ { "delaylen", &ng_parse_uint32_type }, \ { "duplicate", &ng_parse_uint32_type }, \ { "fifo", &ng_parse_uint32_type }, \ { "drr", &ng_parse_uint32_type }, \ { "wfq", &ng_parse_uint32_type }, \ { "droptail", &ng_parse_uint32_type }, \ { "drophead", &ng_parse_uint32_type }, \ { NULL }, \ } /* Config structure returned by NGM_PIPE_GET_CFG */ struct ng_pipe_cfg { u_int64_t bandwidth; u_int64_t delay; u_int32_t header_offset; u_int32_t overhead; struct ng_pipe_hookcfg downstream; struct ng_pipe_hookcfg upstream; }; /* Keep this in sync with the above structure definition */ #define NG_PIPE_CFG_INFO(hstype) { \ { "bandwidth", &ng_parse_uint64_type }, \ { "delay", &ng_parse_uint64_type }, \ { "header_offset", &ng_parse_uint32_type }, \ { "overhead", &ng_parse_uint32_type }, \ { "downstream", (hstype) }, \ { "upstream", (hstype) }, \ { NULL }, \ } /* Netgraph commands */ enum { NGM_PIPE_GET_STATS=1, /* get stats */ NGM_PIPE_CLR_STATS, /* clear stats */ NGM_PIPE_GETCLR_STATS, /* atomically get and clear stats */ NGM_PIPE_GET_RUN, /* get current runtime status */ NGM_PIPE_GET_CFG, /* get configurable parameters */ NGM_PIPE_SET_CFG, /* set configurable parameters */ }; #endif /* _NETGRAPH_PIPE_H_ */ core-4.8/kernel/freebsd/ng_pipe/ng_pipe_freebsd4.c0000664000175000017500000010336112534327775017141 00000000000000/* * ng_pipe.c * * Copyright (c) 2004 University of Zagreb, Croatia * Copyright (c) 1996-1999 Whistle Communications, Inc. * All rights reserved. * * Subject to the following obligations and disclaimer of warranty, use and * redistribution of this software, in source or object code forms, with or * without modifications are expressly permitted by Whistle Communications * and author; provided, however, that: * 1. Any and all reproductions of the source or object code must include the * copyright notice above and the following disclaimer of warranties; and * 2. No rights are granted, in any manner or form, to use Whistle * Communications, Inc. trademarks, including the mark "WHISTLE * COMMUNICATIONS" on advertising, endorsements, or otherwise except as * such appears in the above copyright notice or in the software. * * THIS SOFTWARE IS BEING PROVIDED BY BOTH AUTHOR AND WHISTLE COMMUNICATIONS * "AS IS", AND TO THE MAXIMUM EXTENT PERMITTED BY LAW, THEY MAKE NO * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE, * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. * AUTHOR AND WHISTLE COMMUNICATIONS DO NOT WARRANT, GUARANTEE, OR MAKE * ANY REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE. * IN NO EVENT WILL AUTHOR OR WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER 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 AUTHOR OR WHISTLE COMMUNICATIONS IS ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ /* v 1.15 2004/10/25 */ /* * This node permits simple traffic shaping by emulating bandwidth * and delay, as well as random packet losses. * The node has two hooks, upper and lower. Traffic flowing from upper to * lower hook is referenced as downstream, and vice versa. Parameters for * both directions can be set separately, except for delay. */ /* * TODO: * * - some splimp()s and extra checks are possibly pure paranoia, * if they prove to be redundant they should be removed. * * - update the manpage. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "ng_pipe.h" #ifdef XCP #include "xcp_var.h" #endif #ifdef BOEING_WLAN #include "../ng_wlan/ng_wlan.h" #include "../ng_wlan/ng_wlan_tag.h" #endif /* BOEING_WLAN */ typedef void idle_polling_t (void); extern idle_polling_t *idle_polling_h; extern int cpu_idle_hlt; /* Packet header struct */ struct ngp_hdr { TAILQ_ENTRY(ngp_hdr) ngp_link; /* next pkt in queue */ struct timeval when; /* when to dequeue this packet? */ struct mbuf *m; /* ptr to the actual packet data */ #ifdef BOEING_WLAN meta_p meta; /* optional metadata containing link effects from ng_wlan*/ #endif }; TAILQ_HEAD(p_head ,ngp_hdr); /* FIFO queue struct */ struct ngp_fifo { TAILQ_ENTRY(ngp_fifo) fifo_le; /* list of active queues only */ struct p_head packet_head; /* FIFO queue head */ u_int32_t hash; /* flow signature */ struct timeval vtime; /* virtual time, for WFQ */ u_int32_t rr_deficit; /* for DRR */ u_int32_t packets; /* # of packets in this queue */ }; /* Per hook info */ struct hookinfo { hook_p hook; LIST_ENTRY(hookinfo) hook_le; /* all active ng_pipe instances */ TAILQ_HEAD(, ngp_fifo) fifo_head; /* this hooks's FIFO queues */ TAILQ_HEAD(, ngp_hdr) qout_head; /* delay queue head */ struct timeval qin_utime; struct ng_pipe_hookcfg cfg; struct ng_pipe_hookrun run; struct ng_pipe_hookstat stats; #ifdef XCP struct xcp_router_state xcps; #endif uint64_t *ber_p; }; /* Per node info */ struct privdata { node_p node; LIST_ENTRY(privdata) node_le; u_int64_t delay; u_int32_t overhead; u_int32_t header_offset; struct hookinfo lower; struct hookinfo upper; }; typedef struct privdata *sc_p; /* Macro for calculating the virtual time for packet dequeueing in WFQ */ #define FIFO_VTIME_SORT(plen) \ if (hinfo->cfg.wfq && hinfo->cfg.bandwidth) { \ ngp_f->vtime.tv_usec = now->tv_usec + ((uint64_t) (plen) \ + sc->overhead ) * hinfo->run.fifo_queues * \ 8000000 / hinfo->cfg.bandwidth; \ ngp_f->vtime.tv_sec = now->tv_sec + \ ngp_f->vtime.tv_usec / 1000000; \ ngp_f->vtime.tv_usec = ngp_f->vtime.tv_usec % 1000000; \ TAILQ_FOREACH(ngp_f1, &hinfo->fifo_head, fifo_le) \ if (ngp_f1->vtime.tv_sec > ngp_f->vtime.tv_sec || \ (ngp_f1->vtime.tv_sec == ngp_f->vtime.tv_sec && \ ngp_f1->vtime.tv_usec > ngp_f->vtime.tv_usec)) \ break; \ if (ngp_f1 == NULL) \ TAILQ_INSERT_TAIL(&hinfo->fifo_head, ngp_f, fifo_le); \ else \ TAILQ_INSERT_BEFORE(ngp_f1, ngp_f, fifo_le); \ } else \ TAILQ_INSERT_TAIL(&hinfo->fifo_head, ngp_f, fifo_le); \ static void parse_cfg(struct ng_pipe_hookcfg *, struct ng_pipe_hookcfg *, struct hookinfo *); static void pipe_dequeue(struct hookinfo *, struct timeval *); static void pipe_scheduler(void); static void pipe_poll(void); static int ngp_modevent(module_t, int, void *); /* linked list of all "pipe" nodes */ LIST_HEAD(pipe_node_head, privdata) node_head; /* linked list of active "pipe" hooks */ LIST_HEAD(pipe_hook_head, hookinfo) hook_head; /* timeout handle for pipe_scheduler */ struct callout_handle ds_handle = { 0 }; /* saved value of cpu_idle_hlt */ static int old_cpu_idle_hlt = 0; /* VM zone for storing ngp_hdr-s */ struct vm_zone *ngp_zone; /* Netgraph methods */ static ng_constructor_t ngp_constructor; static ng_rcvmsg_t ngp_rcvmsg; static ng_shutdown_t ngp_rmnode; static ng_newhook_t ngp_newhook; static ng_rcvdata_t ngp_rcvdata; static ng_disconnect_t ngp_disconnect; /* Parse type for struct ng_pipe_hookstat */ static const struct ng_parse_struct_field ng_pipe_hookstat_type_fields[] = NG_PIPE_HOOKSTAT_INFO; static const struct ng_parse_type ng_pipe_hookstat_type = { &ng_parse_struct_type, &ng_pipe_hookstat_type_fields }; /* Parse type for struct ng_pipe_stats */ static const struct ng_parse_struct_field ng_pipe_stats_type_fields[] = NG_PIPE_STATS_INFO(&ng_pipe_hookstat_type); static const struct ng_parse_type ng_pipe_stats_type = { &ng_parse_struct_type, &ng_pipe_stats_type_fields }; /* Parse type for struct ng_pipe_hookrun */ static const struct ng_parse_struct_field ng_pipe_hookrun_type_fields[] = NG_PIPE_HOOKRUN_INFO; static const struct ng_parse_type ng_pipe_hookrun_type = { &ng_parse_struct_type, &ng_pipe_hookrun_type_fields }; /* Parse type for struct ng_pipe_run */ static const struct ng_parse_struct_field ng_pipe_run_type_fields[] = NG_PIPE_RUN_INFO(&ng_pipe_hookrun_type); static const struct ng_parse_type ng_pipe_run_type = { &ng_parse_struct_type, &ng_pipe_run_type_fields }; /* Parse type for struct ng_pipe_hookcfg */ static const struct ng_parse_struct_field ng_pipe_hookcfg_type_fields[] = NG_PIPE_HOOKCFG_INFO; static const struct ng_parse_type ng_pipe_hookcfg_type = { &ng_parse_struct_type, &ng_pipe_hookcfg_type_fields }; /* Parse type for struct ng_pipe_cfg */ static const struct ng_parse_struct_field ng_pipe_cfg_type_fields[] = NG_PIPE_CFG_INFO(&ng_pipe_hookcfg_type); static const struct ng_parse_type ng_pipe_cfg_type = { &ng_parse_struct_type, &ng_pipe_cfg_type_fields }; /* List of commands and how to convert arguments to/from ASCII */ static const struct ng_cmdlist ng_pipe_cmds[] = { { NGM_PIPE_COOKIE, NGM_PIPE_GET_STATS, "getstats", NULL, &ng_pipe_stats_type }, { NGM_PIPE_COOKIE, NGM_PIPE_CLR_STATS, "clrstats", NULL, NULL }, { NGM_PIPE_COOKIE, NGM_PIPE_GETCLR_STATS, "getclrstats", NULL, &ng_pipe_stats_type }, { NGM_PIPE_COOKIE, NGM_PIPE_GET_RUN, "getrun", NULL, &ng_pipe_run_type }, { NGM_PIPE_COOKIE, NGM_PIPE_GET_CFG, "getcfg", NULL, &ng_pipe_cfg_type }, { NGM_PIPE_COOKIE, NGM_PIPE_SET_CFG, "setcfg", &ng_pipe_cfg_type, NULL }, { 0 } }; /* Netgraph type descriptor */ static struct ng_type ng_pipe_typestruct = { NG_VERSION, NG_PIPE_NODE_TYPE, ngp_modevent, ngp_constructor, ngp_rcvmsg, ngp_rmnode, ngp_newhook, NULL, NULL, ngp_rcvdata, ngp_rcvdata, ngp_disconnect, ng_pipe_cmds }; NETGRAPH_INIT(pipe, &ng_pipe_typestruct); #ifdef BOEING_WLAN /* generate a random integer between 1 and max */ #define pipe_good_random(max) (1 + (random() % max)) #endif /* * Node constructor */ static int ngp_constructor(node_p *nodep) { sc_p privdata; node_p node; int error = 0; int s; MALLOC(privdata, sc_p, sizeof(*privdata), M_NETGRAPH, M_NOWAIT); if (privdata == NULL) return (ENOMEM); bzero(privdata, sizeof(*privdata)); if ((error = ng_make_node_common(&ng_pipe_typestruct, nodep))) { FREE(privdata, M_NETGRAPH); return (error); } node=*nodep; node->private = privdata; privdata->node = node; /* Add new node to the "all nodes" list */ s=splimp(); LIST_INSERT_HEAD(&node_head, privdata, node_le); splx(s); return (0); } /* * Add a hook */ static int ngp_newhook(node_p node, hook_p hook, const char *name) { const sc_p sc = node->private; struct hookinfo *hinfo; if (strcmp(name, NG_PIPE_HOOK_UPPER) == 0) { bzero(&sc->upper, sizeof(sc->upper)); sc->upper.hook = hook; hook->private = &sc->upper; } else if (strcmp(name, NG_PIPE_HOOK_LOWER) == 0) { bzero(&sc->lower, sizeof(sc->lower)); sc->lower.hook = hook; hook->private = &sc->lower; } else return (EINVAL); /* Load non-zero initial cfg values */ hinfo = (struct hookinfo *) hook->private; hinfo->cfg.qin_size_limit = 50; hinfo->cfg.fifo = 1; hinfo->cfg.droptail = 1; TAILQ_INIT(&hinfo->fifo_head); TAILQ_INIT(&hinfo->qout_head); return (0); } /* * Receive a control message */ static int ngp_rcvmsg(node_p node, struct ng_mesg *msg, const char *retaddr, struct ng_mesg **rptr) { const sc_p sc = node->private; struct ng_mesg *resp = NULL; int error = 0; switch (msg->header.typecookie) { case NGM_PIPE_COOKIE: switch (msg->header.cmd) { case NGM_PIPE_GET_STATS: case NGM_PIPE_CLR_STATS: case NGM_PIPE_GETCLR_STATS: { struct ng_pipe_stats *stats; if (msg->header.cmd != NGM_PIPE_CLR_STATS) { NG_MKRESPONSE(resp, msg, sizeof(*stats), M_NOWAIT); if (resp == NULL) { error = ENOMEM; goto done; } stats=(struct ng_pipe_stats *)resp->data; bcopy(&sc->upper.stats, &stats->downstream, sizeof(stats->downstream)); bcopy(&sc->lower.stats, &stats->upstream, sizeof(stats->upstream)); } if (msg->header.cmd != NGM_PIPE_GET_STATS) { bzero(&sc->upper.stats, sizeof(sc->upper.stats)); bzero(&sc->lower.stats, sizeof(sc->lower.stats)); } break; } case NGM_PIPE_GET_RUN: { struct ng_pipe_run *run; NG_MKRESPONSE(resp, msg, sizeof(*run), M_NOWAIT); if (resp == NULL) { error = ENOMEM; goto done; } run = (struct ng_pipe_run *)resp->data; bcopy(&sc->upper.run, &run->downstream, sizeof(run->downstream)); bcopy(&sc->lower.run, &run->upstream, sizeof(run->upstream)); break; } case NGM_PIPE_GET_CFG: { struct ng_pipe_cfg *cfg; NG_MKRESPONSE(resp, msg, sizeof(*cfg), M_NOWAIT); if (resp == NULL) { error = ENOMEM; goto done; } cfg = (struct ng_pipe_cfg *)resp->data; bcopy(&sc->upper.cfg, &cfg->downstream, sizeof(cfg->downstream)); bcopy(&sc->lower.cfg, &cfg->upstream, sizeof(cfg->upstream)); cfg->delay = sc->delay; cfg->overhead = sc->overhead; cfg->header_offset = sc->header_offset; if (cfg->upstream.bandwidth == cfg->downstream.bandwidth) { cfg->bandwidth = cfg->upstream.bandwidth; cfg->upstream.bandwidth = 0; cfg->downstream.bandwidth = 0; } else cfg->bandwidth = 0; break; } case NGM_PIPE_SET_CFG: { struct ng_pipe_cfg *cfg; cfg = (struct ng_pipe_cfg *)msg->data; if (msg->header.arglen != sizeof(*cfg)) { error = EINVAL; break; } if (cfg->delay == -1) sc->delay = 0; else if (cfg->delay > 0 && cfg->delay < 10000000) sc->delay = cfg->delay; if (cfg->bandwidth == -1) { sc->upper.cfg.bandwidth = 0; sc->lower.cfg.bandwidth = 0; sc->overhead = 0; } else if (cfg->bandwidth >= 100 && cfg->bandwidth <= 1000000000) { sc->upper.cfg.bandwidth = cfg->bandwidth; sc->lower.cfg.bandwidth = cfg->bandwidth; if (cfg->bandwidth >= 10000000) sc->overhead = 8+4+12; /* Ethernet */ else sc->overhead = 10; /* HDLC */ } if (cfg->overhead == -1) sc->overhead = 0; else if (cfg->overhead > 0 && cfg->overhead < 256) sc->overhead = cfg->overhead; if (cfg->header_offset == -1) sc->header_offset = 0; else if (cfg->header_offset > 0 && cfg->header_offset < 64) sc->header_offset = cfg->header_offset; parse_cfg(&sc->upper.cfg, &cfg->downstream, &sc->upper); parse_cfg(&sc->lower.cfg, &cfg->upstream, &sc->lower); break; } default: error = EINVAL; break; } break; default: error = EINVAL; break; } if (rptr) *rptr = resp; else if (resp) FREE(resp, M_NETGRAPH); done: FREE(msg, M_NETGRAPH); return (error); } static void parse_cfg(struct ng_pipe_hookcfg *current, struct ng_pipe_hookcfg *new, struct hookinfo *hinfo) { if (new->ber == -1) { current->ber = 0; if (hinfo->ber_p) { FREE(hinfo->ber_p, M_NETGRAPH); hinfo->ber_p = NULL; } } else if (new->ber >= 1 && new->ber <= 1000000000000) { static const uint64_t one = 0x1000000000000; /* = 2^48 */ uint64_t p0, p; uint32_t fsize, i; if (hinfo->ber_p == NULL) MALLOC(hinfo->ber_p, uint64_t *, \ (MAX_FSIZE + MAX_OHSIZE)*sizeof(uint64_t), \ M_NETGRAPH, M_NOWAIT); current->ber = new->ber; /* * For given BER and each frame size N (in bytes) calculate * the probability P_OK that the frame is clean: * * P_OK(BER,N) = (1 - 1/BER)^(N*8) * * We use a 64-bit fixed-point format with decimal point * positioned between bits 47 and 48. */ p0 = one - one / new->ber; p = one; for (fsize = 0; fsize < MAX_FSIZE + MAX_OHSIZE; fsize++) { hinfo->ber_p[fsize] = p; for (i=0; i<8; i++) p = (p*(p0&0xffff)>>48) + \ (p*((p0>>16)&0xffff)>>32) + \ (p*(p0>>32)>>16); } } if (new->qin_size_limit == 0xffff) current->qin_size_limit = 0; else if (new->qin_size_limit >= 5) current->qin_size_limit = new->qin_size_limit; if (new->qout_size_limit == 0xffff) current->qout_size_limit = 0; else if (new->qout_size_limit >= 5) current->qout_size_limit = new->qout_size_limit; if (new->duplicate == -1) current->duplicate = 0; else if (new->duplicate > 0 && new->duplicate <= 50) current->duplicate = new->duplicate; if (new->fifo) { current->fifo = 1; current->wfq = 0; current->drr = 0; } if (new->wfq) { current->fifo = 0; current->wfq = 1; current->drr = 0; } if (new->drr) { current->fifo = 0; current->wfq = 0; /* DRR quantum */ if (new->drr >= 32) current->drr = new->drr; else current->drr = 2048; /* default quantum */ } if (new->droptail) { current->droptail = 1; current->drophead = 0; } if (new->drophead) { current->droptail = 0; current->drophead = 1; } if (new->bandwidth == -1) { current->bandwidth = 0; current->fifo = 1; current->wfq = 0; current->drr = 0; } else if (new->bandwidth >= 100 && new->bandwidth <= 1000000000) current->bandwidth = new->bandwidth; #ifdef XCP init_xcp_state(&hinfo->xcps, 0, current->bandwidth / 1024); #endif } /* * Compute a hash signature for a packet. This function suffers from the * NIH sindrome, so probably it would be wise to look around what other * folks have found out to be a good and efficient IP hash function... */ __inline static int ip_hash(struct mbuf *m, int offset) { u_int64_t i; struct ip *ip = (struct ip *)(mtod(m, u_char *) + offset); struct udphdr *udp = 0; if (m->m_len < sizeof(struct ip) + offset || ip->ip_v != 4 || ip->ip_hl << 2 != sizeof(struct ip)) return 0; if ((m->m_len >= sizeof(struct ip) + sizeof(struct udphdr) + offset) && (ip->ip_p == IPPROTO_TCP || ip->ip_p == IPPROTO_UDP) && !(ntohs(ip->ip_off) & IP_OFFMASK)) udp = (struct udphdr *)((u_char *) ip + sizeof(struct ip)); #if 0 /* an overkill IP hash, but could be too slow */ i = 0; for ( j = (ip->ip_p & 0x1f) + 1; j ; j = j >> 2) { i ^= ((u_int64_t) ip->ip_src.s_addr + ((u_int64_t) ip->ip_dst.s_addr << 7) - ((u_int64_t) ip->ip_src.s_addr << 13) - ((u_int64_t) ip->ip_dst.s_addr << 19) + ((u_int64_t) ip->ip_p << 9)) << j; if (udp) i ^= (((u_int64_t) udp->uh_sport << (ip->ip_p + 5)) - ((u_int64_t) udp->uh_dport << ip->ip_p)) << j; } #else /* a slightly faster yet less reliable version */ i = ((u_int64_t) ip->ip_src.s_addr ^ ((u_int64_t) ip->ip_dst.s_addr << 7) ^ ((u_int64_t) ip->ip_src.s_addr << 13) ^ ((u_int64_t) ip->ip_dst.s_addr << 19) ^ ((u_int64_t) ip->ip_p << 9)); if (udp) i ^= (((u_int64_t) udp->uh_sport << (ip->ip_p + 5)) ^ ((u_int64_t) udp->uh_dport << ip->ip_p)); #endif return (i ^ (i >> 32)); } /* * Receive data on a hook - both in upstream and downstream direction. * We put the frame on the inbound queue, and try to initiate dequeuing * sequence immediately. If inbound queue is full, discard one frame * depending on dropping policy (from the head or from the tail of the * queue). */ static int ngp_rcvdata(hook_p hook, struct mbuf *m, meta_p meta) { struct hookinfo *const hinfo = (struct hookinfo *) hook->private; const sc_p sc = hook->node->private; struct timeval uuptime; struct timeval *now = &uuptime; struct ngp_fifo *ngp_f = NULL, *ngp_f1; struct ngp_hdr *ngp_h = NULL; int hash; int s; microuptime(now); s = splimp(); #ifdef BOEING_WLAN if (meta != NULL) { if ((meta->used_len != WLAN_META_SIZE) || (meta->options[0].cookie != NGM_WLAN_COOKIE)) { /* metadata from elsewhere, not queued */ NG_FREE_META(meta); /* sets meta = NULL */ }/* else metadata from ng_wlan, contains tag */ } #else NG_FREE_META(meta); #endif /* * Attach us to the list of active ng_pipes if this one was an empty * one before, and also update the queue service deadline time. */ if (hinfo->run.qin_frames == 0) { struct timeval *when = &hinfo->qin_utime; if (when->tv_sec < now->tv_sec || (when->tv_sec == now->tv_sec && when->tv_usec < now->tv_usec)) { when->tv_sec = now->tv_sec; when->tv_usec = now->tv_usec; } if (hinfo->run.qout_frames == 0) { LIST_INSERT_HEAD(&hook_head, hinfo, hook_le); if (cpu_idle_hlt) { old_cpu_idle_hlt = cpu_idle_hlt; cpu_idle_hlt = 0; } } } /* Populate the packet header */ ngp_h = zalloc(ngp_zone); ngp_h->m = m; #ifdef BOEING_WLAN ngp_h->meta = meta; meta = NULL; /* don't free elsewhere */ #endif if (hinfo->cfg.fifo) hash = 0; /* all packets go into a single FIFO queue */ else hash = ip_hash(m, sc->header_offset); #ifdef XCP if (do_xcp) xcp_forward(m, sc->header_offset, &hinfo->xcps); #endif /* Find the appropriate FIFO queue for the packet and enqueue it*/ TAILQ_FOREACH(ngp_f, &hinfo->fifo_head, fifo_le) if (hash == ngp_f->hash) break; if (ngp_f == NULL) { ngp_f = zalloc(ngp_zone); TAILQ_INIT(&ngp_f->packet_head); ngp_f->hash = hash; ngp_f->packets = 1; ngp_f->rr_deficit = hinfo->cfg.drr; /* DRR quantum */ hinfo->run.fifo_queues++; TAILQ_INSERT_TAIL(&ngp_f->packet_head, ngp_h, ngp_link); FIFO_VTIME_SORT(m->m_pkthdr.len); } else { TAILQ_INSERT_TAIL(&ngp_f->packet_head, ngp_h, ngp_link); ngp_f->packets++; } hinfo->run.qin_frames++; hinfo->run.qin_octets += m->m_pkthdr.len; /* Discard a frame if inbound queue limit has been reached */ if (hinfo->run.qin_frames > hinfo->cfg.qin_size_limit) { struct mbuf *m1; int longest = 0; /* Find the longest queue */ TAILQ_FOREACH(ngp_f1, &hinfo->fifo_head, fifo_le) if (ngp_f1->packets > longest) { longest = ngp_f1->packets; ngp_f = ngp_f1; } /* Drop a frame from the queue head/tail, depending on cfg */ if (hinfo->cfg.drophead) ngp_h = TAILQ_FIRST(&ngp_f->packet_head); else ngp_h = TAILQ_LAST(&ngp_f->packet_head, p_head); TAILQ_REMOVE(&ngp_f->packet_head, ngp_h, ngp_link); m1 = ngp_h->m; #ifdef BOEING_WLAN NG_FREE_META(ngp_h->meta); #endif /* BOEING_WLAN */ zfree(ngp_zone, ngp_h); hinfo->run.qin_octets -= m1->m_pkthdr.len; hinfo->stats.in_disc_octets += m1->m_pkthdr.len; m_freem(m1); if (--(ngp_f->packets) == 0) { TAILQ_REMOVE(&hinfo->fifo_head, ngp_f, fifo_le); zfree(ngp_zone, ngp_f); hinfo->run.fifo_queues--; } hinfo->run.qin_frames--; hinfo->stats.in_disc_frames++; } /* Try to start the dequeuing process immediately */ pipe_dequeue(hinfo, now); splx(s); return (0); } /* * Dequeueing sequence - we basically do the following: * 1) Try to extract the frame from the inbound (bandwidth) queue; * 2) In accordance to BER specified, discard the frame randomly; * 3) If the frame survives BER, prepend it with delay info and move it * to outbound (delay) queue, or send directly to the outbound hook; * 4) Loop to 2) until bandwidth limit is reached, or inbound queue is * flushed completely; * 5) Extract the first frame from the outbound queue, if it's time has come. * Send this frame to the outbound hook; * 6) Loop to 6) until outbound queue is flushed completely, or the next * frame in the queue is not scheduled to be dequeued yet * * This routine must be called at splimp()! */ static void pipe_dequeue(struct hookinfo *hinfo, struct timeval *now) { static uint64_t rand, oldrand; const sc_p sc = hinfo->hook->node->private; struct hookinfo *dest; struct ngp_fifo *ngp_f, *ngp_f1; struct ngp_hdr *ngp_h; struct timeval *when; meta_p meta = NULL; int error = 0; struct mbuf *m; #ifdef BOEING_WLAN struct ngp_hdr *ngp_h1 = NULL; struct ng_wlan_tag *tag, wtag; int need_free_meta; #endif /* BOEING_WLAN */ /* Which one is the destination hook? */ if (hinfo == &sc->lower) dest = &sc->upper; else dest = &sc->lower; /* Bandwidth queue processing */ while ((ngp_f = TAILQ_FIRST(&hinfo->fifo_head))) { when = &hinfo->qin_utime; if (when->tv_sec > now->tv_sec || (when->tv_sec == now->tv_sec && when->tv_usec > now->tv_usec)) break; ngp_h = TAILQ_FIRST(&ngp_f->packet_head); m = ngp_h->m; #ifdef BOEING_WLAN meta = ngp_h->meta; ngp_h->meta = NULL; /* keep ptr in meta*/ need_free_meta = 0; if (meta != NULL) { need_free_meta = 1; tag = (struct ng_wlan_tag*)meta->options; WLAN_TAG_COPY( (&wtag), tag) /* enforce maximum parameters */ if (wtag.delay > NG_WLAN_MAX_DELAY) wtag.delay = NG_WLAN_MAX_DELAY; if (wtag.duplicate > NG_WLAN_MAX_DUP) wtag.duplicate = NG_WLAN_MAX_DUP; if (wtag.jitter > NG_WLAN_MAX_JITTER) wtag.jitter = NG_WLAN_MAX_JITTER; } else { WLAN_TAG_ZERO( (&wtag) ); } #endif /* BOEING_WLAN */ /* Deficit Round Robin (DRR) processing */ if (hinfo->cfg.drr) { if (ngp_f->rr_deficit >= m->m_pkthdr.len) { ngp_f->rr_deficit -= m->m_pkthdr.len; } else { ngp_f->rr_deficit += hinfo->cfg.drr; TAILQ_REMOVE(&hinfo->fifo_head, ngp_f, fifo_le); TAILQ_INSERT_TAIL(&hinfo->fifo_head, \ ngp_f, fifo_le); /* BOEING_WLAN: need to free meta here? */ continue; } } /* * Either create a duplicate and pass it on, or dequeue * the original packet... */ #ifdef BOEING_WLAN if (wtag.duplicate && pipe_good_random(100) <= wtag.duplicate) { ngp_h = zalloc(ngp_zone); KASSERT(ngp_h != NULL, ("ngp_h zalloc failed (3)")); ngp_h->m = m_dup(m, M_NOWAIT); ngp_h->meta = meta; /* reuse the old metadata instead of * allocating another */ need_free_meta = 0; meta = NULL; KASSERT(ngp_h->m != NULL, ("m_dup failed")); m = ngp_h->m; /* Boeing: we are now working with copied mbuf, leaving original in the queue */ } else #endif /* BOEING_WLAN */ if (hinfo->cfg.duplicate && random() % 100 <= hinfo->cfg.duplicate) { if ((m = m_dup(m, M_NOWAIT))) if ((ngp_h = zalloc(ngp_zone))) ngp_h->m = m; if ( m == NULL || ngp_h == NULL ) panic("ng_pipe: m_dup or zalloc failed!"); } else { TAILQ_REMOVE(&ngp_f->packet_head, ngp_h, ngp_link); hinfo->run.qin_frames--; hinfo->run.qin_octets -= m->m_pkthdr.len; ngp_f->packets--; } #ifdef BOEING_WLAN /* free the metadata if it was not re-used for the duplicate */ if (need_free_meta) NG_FREE_META(meta); #endif /* BOEING_WLAN */ /* Calculate the serialization delay */ #ifdef BOEING_WLAN if (wtag.bandwidth) { hinfo->qin_utime.tv_usec += ((uint64_t) m->m_pkthdr.len + sc->overhead ) * 8000000 / wtag.bandwidth; hinfo->qin_utime.tv_sec += hinfo->qin_utime.tv_usec / 1000000; hinfo->qin_utime.tv_usec = hinfo->qin_utime.tv_usec % 1000000; } else #endif /* BOEING_WLAN */ if (hinfo->cfg.bandwidth) { hinfo->qin_utime.tv_usec += ((uint64_t) m->m_pkthdr.len + sc->overhead ) * 8000000 / hinfo->cfg.bandwidth; hinfo->qin_utime.tv_sec += hinfo->qin_utime.tv_usec / 1000000; hinfo->qin_utime.tv_usec = hinfo->qin_utime.tv_usec % 1000000; } when = &ngp_h->when; when->tv_sec = hinfo->qin_utime.tv_sec; when->tv_usec = hinfo->qin_utime.tv_usec; /* Sort / rearrange inbound queues */ if (ngp_f->packets) { if (hinfo->cfg.wfq) { TAILQ_REMOVE(&hinfo->fifo_head, ngp_f, fifo_le); FIFO_VTIME_SORT(TAILQ_FIRST(&ngp_f->packet_head)->m->m_pkthdr.len) } } else { TAILQ_REMOVE(&hinfo->fifo_head, ngp_f, fifo_le); zfree(ngp_zone, ngp_f); hinfo->run.fifo_queues--; } /* Randomly discard the frame, according to BER setting */ #ifdef BOEING_WLAN /* use specified Packet Error Rate setting for random discard */ if (wtag.per && pipe_good_random(100) <= wtag.per) { hinfo->stats.out_disc_frames++; hinfo->stats.out_disc_octets += m->m_pkthdr.len; zfree(ngp_zone, ngp_h); m_freem(m); continue; } else #endif /* BOEING_WLAN */ if (hinfo->cfg.ber && ( (oldrand = rand) ^ (rand = random())<<17) >= hinfo->ber_p[sc->overhead + m->m_pkthdr.len] ) { hinfo->stats.out_disc_frames++; hinfo->stats.out_disc_octets += m->m_pkthdr.len; zfree(ngp_zone, ngp_h); m_freem(m); continue; } /* Discard frame if outbound queue size limit exceeded */ if (hinfo->cfg.qout_size_limit && hinfo->run.qout_frames>=hinfo->cfg.qout_size_limit) { hinfo->stats.out_disc_frames++; hinfo->stats.out_disc_octets += m->m_pkthdr.len; zfree(ngp_zone, ngp_h); m_freem(m); continue; } #ifdef BOEING_WLAN /* Calculate the propagation delay including jitter */ if (wtag.jitter) { when->tv_usec += pipe_good_random(wtag.jitter); /* overflow handled below... */ } when->tv_usec += wtag.delay ? wtag.delay : sc->delay; #else /* Calculate the propagation delay */ when->tv_usec += sc->delay; #endif /* BOEING_WLAN */ when->tv_sec += when->tv_usec / 1000000; when->tv_usec = when->tv_usec % 1000000; /* Put the frame into the delay queue */ #ifdef BOEING_WLAN /* Because WLAN packets may have varying dequeue times, we need to * perform sorted queueing; the dequeuing process expects packets in * the queue that are sorted by time. */ TAILQ_FOREACH(ngp_h1, &hinfo->qout_head, ngp_link) { if (ngp_h1->when.tv_sec > ngp_h->when.tv_sec || (ngp_h1->when.tv_sec == ngp_h->when.tv_sec && ngp_h1->when.tv_usec > ngp_h->when.tv_usec)) break; } if (ngp_h1 == NULL) TAILQ_INSERT_TAIL(&hinfo->qout_head, ngp_h, ngp_link); else TAILQ_INSERT_BEFORE(ngp_h1, ngp_h, ngp_link); /* The original code below just inserts the packet at the * tail of the queue because the delay time is constant. */ #else /* BOEING_WLAN */ TAILQ_INSERT_TAIL(&hinfo->qout_head, ngp_h, ngp_link); #endif /* BOEING_WLAN */ hinfo->run.qout_frames++; hinfo->run.qout_octets += m->m_pkthdr.len; } /* Delay queue processing */ while ((ngp_h = TAILQ_FIRST(&hinfo->qout_head))) { struct mbuf *m = ngp_h->m; /* BOEING_WLAN: this is why we have sorted the queue input */ when = &ngp_h->when; if (when->tv_sec > now->tv_sec || (when->tv_sec == now->tv_sec && when->tv_usec > now->tv_usec)) break; /* Update outbound queue stats */ hinfo->stats.fwd_frames++; hinfo->stats.fwd_octets += m->m_pkthdr.len; hinfo->run.qout_frames--; hinfo->run.qout_octets -= m->m_pkthdr.len; /* Dequeue/send the packet */ TAILQ_REMOVE(&hinfo->qout_head, ngp_h, ngp_link); zfree(ngp_zone, ngp_h); #ifdef BOEING_WLAN NG_SEND_DATA_ONLY(error, dest->hook, m); #else NG_SEND_DATA(error, dest->hook, m, meta); #endif /* BOEING_WLAN */ } /* If both queues are empty detach us from the list of active queues */ if (hinfo->run.qin_frames + hinfo->run.qout_frames == 0) LIST_REMOVE(hinfo, hook_le); } /* * This routine is called on every clock tick. We poll all nodes/hooks * for queued frames by calling pipe_dequeue(). */ static void pipe_scheduler(void) { static struct timeval old; struct timeval new; microuptime(&new); if (old.tv_sec > new.tv_sec) printf ("ng_pipe: dsec=%ld\n", old.tv_sec - new.tv_sec); else if (old.tv_sec == new.tv_sec && old.tv_usec > new.tv_usec) printf ("ng_pipe: dusec=%ld\n", old.tv_usec - new.tv_usec); old.tv_sec = new.tv_sec; old.tv_usec = new.tv_usec; pipe_poll(); #ifdef XCP if ( do_xcp ) { sc_p priv; /* Set off any XCP timers hooked to ng_pipe queues */ LIST_FOREACH(priv, &node_head, node_le) { if ( --priv->upper.xcps.ticks_until_Te == 0 ) xcp_Te_timeout(&priv->upper.xcps); if ( --priv->upper.xcps.ticks_until_Tq == 0 ) xcp_Tq_timeout(&priv->upper.xcps); if ( --priv->lower.xcps.ticks_until_Te == 0 ) xcp_Te_timeout(&priv->lower.xcps); if ( --priv->lower.xcps.ticks_until_Tq == 0 ) xcp_Tq_timeout(&priv->lower.xcps); } } #endif /* Reschedule */ ds_handle = timeout((timeout_t *) &pipe_scheduler, NULL, 1); } static void pipe_poll(void) { struct hookinfo *hinfo; int s; struct timeval now; s=splimp(); microuptime(&now); LIST_FOREACH(hinfo, &hook_head, hook_le) pipe_dequeue(hinfo, &now); if (LIST_EMPTY(&hook_head) && cpu_idle_hlt == 0) cpu_idle_hlt = old_cpu_idle_hlt; splx(s); } /* * Shutdown processing * * This is tricky. If we have both a lower and upper hook, then we * probably want to extricate ourselves and leave the two peers * still linked to each other. Otherwise we should just shut down as * a normal node would. We run at splimp() in order to avoid race * condition with pipe_scheduler(). */ static int ngp_rmnode(node_p node) { const sc_p privdata = node->private; int s; s=splimp(); node->flags |= NG_INVALID; if (privdata->lower.hook && privdata->upper.hook) ng_bypass(privdata->lower.hook, privdata->upper.hook); ng_cutlinks(node); ng_unname(node); /* unlink the node from the list */ LIST_REMOVE(privdata, node_le); node->private = NULL; ng_unref(privdata->node); FREE(privdata, M_NETGRAPH); splx(s); return (0); } /* * Hook disconnection */ static int ngp_disconnect(hook_p hook) { struct hookinfo *const hinfo = (struct hookinfo *) hook->private; struct ngp_fifo *ngp_f; struct ngp_hdr *ngp_h; int s, removed = 0; s=splimp(); KASSERT(hinfo != NULL, ("%s: null info", __FUNCTION__)); hinfo->hook = NULL; /* Flush all fifo queues associated with the hook */ while ((ngp_f = TAILQ_FIRST(&hinfo->fifo_head))) { while ((ngp_h = TAILQ_FIRST(&ngp_f->packet_head))) { TAILQ_REMOVE(&ngp_f->packet_head, ngp_h, ngp_link); m_freem(ngp_h->m); #ifdef BOEING_WLAN NG_FREE_META(ngp_h->meta); #endif /* BOEING_WLAN */ zfree(ngp_zone, ngp_h); removed++; } TAILQ_REMOVE(&hinfo->fifo_head, ngp_f, fifo_le); zfree(ngp_zone, ngp_f); } /* Flush the delay queue */ while ((ngp_h = TAILQ_FIRST(&hinfo->qout_head))) { TAILQ_REMOVE(&hinfo->qout_head, ngp_h, ngp_link); m_freem(ngp_h->m); #ifdef BOEING_WLAN NG_FREE_META(ngp_h->meta); #endif /* BOEING_WLAN */ zfree(ngp_zone, ngp_h); removed++; } /* * Both queues should be empty by now, so detach us from * the list of active queues */ if (removed) LIST_REMOVE(hinfo, hook_le); if (hinfo->run.qin_frames + hinfo->run.qout_frames != removed) printf("Mismatch: queued=%d but removed=%d !?!", hinfo->run.qin_frames + hinfo->run.qout_frames, removed); /* Release the packet loss probability table (BER) */ if (hinfo->ber_p) FREE(hinfo->ber_p, M_NETGRAPH); if (hook->node->numhooks == 0) ng_rmnode(hook->node); splx(s); return (0); } static int ngp_modevent(module_t mod, int type, void *unused) { sc_p priv; int error = 0; int s; switch (type) { case MOD_LOAD: if (ngp_zone) error = EEXIST; else { ngp_zone = zinit("ng_pipe", max(sizeof(struct ngp_hdr), sizeof (struct ngp_fifo)), nmbufs, ZONE_INTERRUPT, 0); if (ngp_zone == NULL) { error = ENOMEM; break; } LIST_INIT(&node_head); LIST_INIT(&hook_head); ds_handle = timeout((timeout_t *) &pipe_scheduler, NULL, 1); idle_polling_h = pipe_poll; } break; case MOD_UNLOAD: LIST_FOREACH(priv, &node_head, node_le) error = EBUSY; if (error == 0) { s = splimp(); idle_polling_h = NULL; untimeout((timeout_t *) &pipe_scheduler, NULL, ds_handle); ds_handle.callout = NULL; zdestroy(ngp_zone); splx (s); } break; default: break; } return (error); } core-4.8/kernel/freebsd/ng_wlan/0000775000175000017500000000000012534327775013656 500000000000000core-4.8/kernel/freebsd/ng_wlan/Makefile0000664000175000017500000000061712534327775015242 00000000000000# # (c)2006-2011 the Boeing Company # # ng_wlan # .if !defined(PLATFORM) #PLATFORM=i386 PLATFORM=amd64 .endif CFLAGS+=-I/usr/src/sys/${PLATFORM}/compile/CORE -DMULTICAST_LOOKUPS # FreeBSD 4.11 is "FreeBSD" and 7.0 is "freebsd7.0" #.if defined(OSTYPE) #.if (${OSTYPE} == "FreeBSD") #CFLAGS+=-DFREEBSD411 #.endif #.endif KMOD= ng_wlan SRCS= ng_wlan.c #MAN= ng_wlan.4 .include core-4.8/kernel/freebsd/ng_wlan/README0000664000175000017500000000507412534327775014464 00000000000000 ng_wlan FreeBSD kernel module (c) 2006-2011 the Boeing Company author: Jeff Ahrenholz The ng_wlan modules implements a netgraph node that models wireless LAN connectivity. ng_wlan extends the ng_hub node, only instead of sending packets to each connected peer, maintains a hash table of node connectivity, and sends packets between two nodes only when they are linked. By default all nodes are unlinked. Nodes can be linked and unlinked using "link" and "unlink" messages: ngctl msg e0_n2: link { node1=0x23 node2=0x0c } The node IDs of the two nodes are the parameters, as depicted above. Link effects between can also be specified for each node pair. If two nodes are linked and parameters are specified, an mbuf tag will be added to each data packet mbuf that specifies the effects. For FreeBSD 4.11, the metadata parameter is used instead of mbuf tags. Delay (microseconds), bandwidth (bits per second), PER (% packet errors), duplicates (%), jitter (microseconds), and burst (% burst errors) are supported. This tag is then removed by the ng_pipe node and the appropriate effects are applied. Link effects are specified with "set" and "unset" messages: ngctl msg e0_n2: set { node1=0x23 node2=0x0c delay=50000 bandwidth=54000000 per=0 duplicate=0 jitter=5000 burst=30 } ngctl msg e0_n2: unset { node1=0x23 node2=0x0c } Note that a special ng_pipe module is needed (the default one does not support the mbuf tags and some effects.) A separate error rate and burst rate affecting all multicast packets may be defined. Use the "mer" message: ngctl msg e0_n2: mer { mer=20 mburst=35 } The above example sets the multicast error rate to drop 20% of all multicast packets, with 35% burst errors. When MULTICAST_LOOKUPS is defined, a second lookup table is defined for each WLAN where multicast group, source, and node pair tuples can be linked or unlinked. This causes different forwarding behavior for multicast packets, where non-local groups are only forwarded if the node pair has been linked together for that group (and the normal node pair has been linked). Usage: ngctl msg e0_n2: mcastset { node1=0x23 node2=0x0c group=0xEF020364 source=0x0a000002 } ngctl msg e0_n2: mcastset { node1=0x23 node2=0x0c group=0xEF020364 source=0} ngctl msg e0_n2: mcastunset { node1=0x23 node2=0x0c group=0xEF020364 source=0 } Once the first mcastset/mcastunset message is received, that ng_wlan will drop all non-local multicast packets that do not have a matching source, group, node pair entry. The source address of zero matches any IP source. core-4.8/kernel/freebsd/ng_wlan/ng_wlan.c0000664000175000017500000010400712534327775015371 00000000000000/* * Copyright (c) 2006-2011 the Boeing Company * ng_wlan is based on ng_hub, which is: * Copyright (c) 2004 Ruslan Ermilov * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * */ #include #include #include #include #include #include #ifdef MULTICAST_LOOKUPS #include /* in.h */ #include /* IN_MULTICAST(), etc */ #include /* struct ip */ #include /* struct ether_header */ #endif /* MULTICAST_LOOKUPS */ #include #include #include /* #include */ #include "ng_wlan.h" #include "ng_wlan_tag.h" #ifdef NG_SEPARATE_MALLOC MALLOC_DEFINE(M_NETGRAPH_WLAN, "netgraph_wlan", "netgraph WLAN node "); #else #define M_NETGRAPH_WLAN M_NETGRAPH #endif #ifdef WLAN_GIANT_LOCK struct mtx ng_wlan_giant; #endif #ifdef MULTICAST_LOOKUPS #define mtod_off(m,off,t) ((t)(mtod((m),caddr_t)+(off))) #define IP_MCAST_HDR_OFFSET ETHER_HDR_LEN #define IP_MCAST_MIN_LEN (IP_MCAST_HDR_OFFSET + sizeof(struct ip)) #endif /* MULTICAST_LOOKUPS */ /* * WLAN node data types */ /* Hash table entry for wlan connectivity */ struct ng_wlan_hent { ng_ID_t l_id; ng_ID_t g_id; int linked; u_int64_t delay; u_int64_t bandwidth; u_int16_t per; u_int16_t duplicate; u_int32_t jitter; u_int16_t burst; SLIST_ENTRY(ng_wlan_hent) next; }; /* Hash table bucket declaration */ /* struct ng_wlan_bucket { struct ng_wlan_hent *slh_first; };*/ SLIST_HEAD(ng_wlan_bucket, ng_wlan_hent); #define MIN_BUCKETS 256 #define HASH(a, b) ( ((a << 16) + b) % MIN_BUCKETS ) #define IS_PEER_KSOCKET(h) \ (NG_PEER_NODE(h) != NULL && \ NG_PEER_NODE(h)->nd_type->name[0] == 'k' && \ NG_PEER_NODE(h)->nd_type->name[1] == 's') /* WLAN node private data */ struct ng_wlan_private { struct ng_wlan_bucket *tab; #ifndef FREEBSD411 struct mtx ng_wlan_tab_lock; #ifdef MULTICAST_LOOKUPS struct ng_wlan_mcast_bucket *mcast_tab; struct mtx ng_wlan_mcast_tab_lock; int multicast_enabled; #endif #endif /* !FREEBSD411 */ int persistent; u_int16_t mer; /* multicast error rate */ u_int16_t mburst; /* multicast burst rate */ }; typedef struct ng_wlan_private *priv_p; /* * Local function declarations */ static int ng_wlan_lookup(node_p node, hook_p hook1, hook_p hook2, struct ng_wlan_tag *tag); static int ng_wlan_unlink(node_p node, ng_ID_t node1, ng_ID_t node2); static int ng_wlan_link(node_p node, ng_ID_t node1, ng_ID_t node2, struct ng_wlan_set_data *data); #ifdef MULTICAST_LOOKUPS static int ng_wlan_mcast_lookup(node_p node, hook_p hook1, hook_p hook2, u_int32_t group, u_int32_t source); static int ng_wlan_mcast_link(node_p node, ng_ID_t node1, ng_ID_t node2, u_int32_t group, u_int32_t source, int unlink); /* Hash table entry for multicast connectivity */ struct ng_wlan_mcast_hent { ng_ID_t l_id; ng_ID_t g_id; u_int32_t group; u_int32_t source; int linked; SLIST_ENTRY(ng_wlan_mcast_hent) next; }; SLIST_HEAD(ng_wlan_mcast_bucket, ng_wlan_mcast_hent); #define MCAST_HASH(a, b, g) ( (((a << 16) + b) & g) % MIN_BUCKETS ) #endif /* MULTICAST_LOOKUPS */ /* * Netgraph node methods */ #ifndef FREEBSD411 static int ng_wlan_modevent(module_t mod, int type, void *unused); #endif static ng_constructor_t ng_wlan_constructor; static ng_rcvmsg_t ng_wlan_rcvmsg; static ng_shutdown_t ng_wlan_rmnode; static ng_newhook_t ng_wlan_newhook; static ng_rcvdata_t ng_wlan_rcvdata; #ifndef FREEBSD411 static ng_rcvdata_t ng_wlan_rcvdata_ks; #endif static ng_disconnect_t ng_wlan_disconnect; /* Parse types */ static const struct ng_parse_struct_field ng_wlan_link_type_fields[] = NG_WLAN_CONFIG_TYPE_INFO; static const struct ng_parse_type ng_wlan_link_type = { &ng_parse_struct_type, &ng_wlan_link_type_fields }; static const struct ng_parse_struct_field ng_wlan_set_type_fields[] = NG_WLAN_SET_DATA_TYPE_INFO; static const struct ng_parse_type ng_wlan_set_type = { &ng_parse_struct_type, &ng_wlan_set_type_fields }; static const struct ng_parse_struct_field ng_wlan_mer_type_fields[] = NG_WLAN_MER_TYPE_INFO; static const struct ng_parse_type ng_wlan_mer_type = { &ng_parse_struct_type, &ng_wlan_mer_type_fields }; #ifdef MULTICAST_LOOKUPS static const struct ng_parse_struct_field ng_wlan_multicast_set_type_fields[] = NG_WLAN_MULTICAST_SET_DATA_TYPE_INFO; static const struct ng_parse_type ng_wlan_multicast_set_type = { &ng_parse_struct_type, &ng_wlan_multicast_set_type_fields }; #endif /* MULTICAST_LOOKUPS */ /* List of commands and how to convert arguments to/from ASCII */ static const struct ng_cmdlist ng_wlan_cmdlist[] = { { NGM_WLAN_COOKIE, NGM_WLAN_LINK_NODES, "link", &ng_wlan_link_type, NULL }, { NGM_WLAN_COOKIE, NGM_WLAN_UNLINK_NODES, "unlink", &ng_wlan_link_type, NULL }, { NGM_WLAN_COOKIE, NGM_WLAN_NODES_SET, "set", &ng_wlan_set_type, NULL }, { NGM_WLAN_COOKIE, NGM_WLAN_NODES_UNSET, "unset", &ng_wlan_link_type, NULL }, { NGM_WLAN_COOKIE, NGM_WLAN_NODES_GET, "get", &ng_wlan_link_type, &ng_wlan_set_type }, { NGM_WLAN_COOKIE, NGM_WLAN_MER, "mer", &ng_wlan_mer_type, NULL }, #ifdef MULTICAST_LOOKUPS { NGM_WLAN_COOKIE, NGM_WLAN_MULTICAST_SET, "mcastset", &ng_wlan_multicast_set_type, NULL }, { NGM_WLAN_COOKIE, NGM_WLAN_MULTICAST_UNSET, "mcastunset", &ng_wlan_multicast_set_type, NULL }, { NGM_WLAN_COOKIE, NGM_WLAN_MULTICAST_GET, "mcastget", &ng_wlan_multicast_set_type, &ng_wlan_multicast_set_type }, #endif /* MULTICAST_LOOKUPS */ { 0 } }; /* * Netgraph node type descriptor */ static struct ng_type ng_wlan_typestruct = { .version = NG_ABI_VERSION, .name = NG_WLAN_NODE_TYPE, #ifndef FREEBSD411 .mod_event = ng_wlan_modevent, #endif .constructor = ng_wlan_constructor, .rcvmsg = ng_wlan_rcvmsg, .shutdown = ng_wlan_rmnode, .newhook = ng_wlan_newhook, .rcvdata = ng_wlan_rcvdata, .disconnect = ng_wlan_disconnect, .cmdlist = ng_wlan_cmdlist, }; NETGRAPH_INIT(wlan, &ng_wlan_typestruct); #ifndef FREEBSD411 /* * Function implementations */ static int ng_wlan_modevent(module_t mod, int type, void *unused) { int error = 0; switch (type) { case MOD_LOAD: #ifdef WLAN_GIANT_LOCK mtx_init(&ng_wlan_giant, "ng_wlan_giant", NULL, MTX_DEF); #endif break; case MOD_UNLOAD: #ifdef WLAN_GIANT_LOCK mtx_destroy(&ng_wlan_giant); #endif break; default: error = EOPNOTSUPP; break; } return (error); } #endif /* !FREEBSD411 */ #ifdef FREEBSD411 static int ng_wlan_constructor(node_p *nodep) #else static int ng_wlan_constructor(node_p node) #endif { priv_p priv; #ifdef FREEBSD411 int error=0; #endif /* initialize the hash table */ MALLOC( priv, priv_p, sizeof(struct ng_wlan_private), M_NETGRAPH_WLAN, M_NOWAIT | M_ZERO); if (priv == NULL) return (ENOMEM); MALLOC( priv->tab, struct ng_wlan_bucket *, MIN_BUCKETS * sizeof(struct ng_wlan_bucket), M_NETGRAPH_WLAN, M_NOWAIT | M_ZERO); if (priv->tab == NULL) { FREE(priv, M_NETGRAPH_WLAN); return (ENOMEM); } #ifdef FREEBSD411 /* Call the generic node constructor. */ if ((error=ng_make_node_common(&ng_wlan_typestruct, nodep))) { FREE(priv->tab, M_NETGRAPH_WLAN); FREE(priv, M_NETGRAPH_WLAN); return(error); } NG_NODE_SET_PRIVATE(*nodep, priv); #else /* FREEBSD411 */ #ifdef MULTICAST_LOOKUPS priv->multicast_enabled = 0; /* turned off, until ng_wlan_mcast_link()*/ /* initialize multicast hash table */ MALLOC( priv->mcast_tab, struct ng_wlan_mcast_bucket *, MIN_BUCKETS * sizeof(struct ng_wlan_mcast_bucket), M_NETGRAPH_WLAN, M_NOWAIT | M_ZERO); if (priv->mcast_tab == NULL) { FREE(priv->tab, M_NETGRAPH_WLAN); FREE(priv, M_NETGRAPH_WLAN); return (ENOMEM); } mtx_init(&priv->ng_wlan_mcast_tab_lock, "ng_wlan_mcast_tab_lock", NULL, MTX_DEF); #endif /* MULTICAST_LOOKUPS */ mtx_init(&priv->ng_wlan_tab_lock, "ng_wlan_tab_lock", NULL, MTX_DEF); NG_NODE_SET_PRIVATE(node, priv); #endif /* FREEBSD411 */ return (0); } static int ng_wlan_newhook(node_p node, hook_p hook, const char *name) { const priv_p priv = NG_NODE_PRIVATE(node); /* ksocket hooks "ks0", "ks1", etc. get special receive function */ if (name[0] == 'k' && name[1] == 's') { #ifndef FREEBSD411 NG_HOOK_SET_RCVDATA(hook, ng_wlan_rcvdata_ks); #endif return 0; } if (strcmp(name, "anchor") == 0) { if (priv->persistent) return(EISCONN); priv->persistent = 1; } return 0; } /* * Receive a control message. */ #ifdef FREEBSD411 static int ng_wlan_rcvmsg(node_p node, struct ng_mesg *msg, const char *retaddr, struct ng_mesg **rptr) #else static int ng_wlan_rcvmsg(node_p node, item_p item, hook_p lasthook) #endif { const priv_p priv = NG_NODE_PRIVATE(node); struct ng_mesg *resp = NULL; int error = 0; struct ng_wlan_config *nodes; struct ng_wlan_set_data *set_data; struct ng_wlan_tag tag; u_int32_t node1, node2; struct ng_hook h1, h2; struct ng_node n1, n2; #ifndef FREEBSD411 struct ng_mesg *msg; #ifdef MULTICAST_LOOKUPS struct ng_wlan_multicast_set_data *mcsd; u_int32_t group, src; int unlink; #endif /* MULTICAST_LOOKUPS */ #endif #ifndef FREEBSD411 #ifdef WLAN_GIANT_LOCK mtx_lock(&ng_wlan_giant); #else mtx_lock(&priv->ng_wlan_tab_lock); #ifdef MULTICAST_LOOKUPS mtx_lock(&priv->ng_wlan_mcast_tab_lock); #endif /* MULTICAST_LOOKUPS */ #endif NGI_GET_MSG(item, msg); #endif /* !FREEBSD411 */ switch (msg->header.typecookie) { case NGM_WLAN_COOKIE: switch (msg->header.cmd) { /* all of these messages take (node1=a,node2=b) param */ case NGM_WLAN_LINK_NODES: case NGM_WLAN_UNLINK_NODES: case NGM_WLAN_NODES_UNSET: case NGM_WLAN_NODES_GET: if (msg->header.arglen != sizeof(struct ng_wlan_config)) { error = EINVAL; break; } nodes = (struct ng_wlan_config *)msg->data; node1 = nodes->node1; node2 = nodes->node2; if (msg->header.cmd == NGM_WLAN_NODES_GET) { NG_MKRESPONSE(resp, msg, sizeof(*set_data), M_NOWAIT); if (resp == NULL) { error = ENOMEM; break; } set_data = (struct ng_wlan_set_data*)resp->data; bzero(set_data, sizeof(*set_data)); /* make fake peer/node structures for lookup */ #ifdef FREEBSD411 h1.peer = &h2; h2.peer = &h1; h1.node = &n1; h2.node = &n2; n1.ID = node1; n2.ID = node2; #else h1.hk_peer = &h2; h2.hk_peer = &h1; h1.hk_node = &n1; h2.hk_node = &n2; n1.nd_ID = node1; n2.nd_ID = node2; #endif if (ng_wlan_lookup(node, &h1, &h2, &tag)) { set_data->node1 = node1; set_data->node2 = node2; WLAN_TAG_COPY(set_data, (&tag)); } /* if not found, node1/node2 will be zero */ break; } if (msg->header.cmd == NGM_WLAN_LINK_NODES) error = ng_wlan_link(node, node1, node2, NULL); else error = ng_wlan_unlink(node, node1, node2); break; case NGM_WLAN_NODES_SET: if (msg->header.arglen != sizeof(struct ng_wlan_set_data)) { error = EINVAL; break; } set_data = (struct ng_wlan_set_data *)msg->data; node1 = set_data->node1; node2 = set_data->node2; if (set_data->delay > NG_WLAN_MAX_DELAY || set_data->bandwidth > NG_WLAN_MAX_BW || set_data->per > NG_WLAN_MAX_PER || set_data->duplicate > NG_WLAN_MAX_DUP || set_data->jitter > NG_WLAN_MAX_JITTER || set_data->burst > NG_WLAN_MAX_BURST) { error = EINVAL; break; } error = ng_wlan_link(node, node1, node2, set_data); break; case NGM_WLAN_MER: if (msg->header.arglen != sizeof(struct ng_wlan_mer)) { error = EINVAL; break; } priv->mer = *((u_int16_t *)msg->data); priv->mburst = *((u_int16_t *)&msg->data[2]); break; case NGM_WLAN_MULTICAST_SET: case NGM_WLAN_MULTICAST_UNSET: case NGM_WLAN_MULTICAST_GET: #ifndef MULTICAST_LOOKUPS error = ENOTSUP; break; #else if (msg->header.arglen != sizeof(struct ng_wlan_multicast_set_data)) { error = EINVAL; break; } unlink = (msg->header.cmd == NGM_WLAN_MULTICAST_UNSET); mcsd = (struct ng_wlan_multicast_set_data *)msg->data; node1 = mcsd->node1; node2 = mcsd->node2; group = mcsd->group; src = mcsd->source; if (msg->header.cmd == NGM_WLAN_MULTICAST_GET) { NG_MKRESPONSE(resp, msg, sizeof(*mcsd), M_NOWAIT); if (resp == NULL) { error = ENOMEM; break; } mcsd = (struct ng_wlan_multicast_set_data*) resp->data; bzero(mcsd, sizeof(*mcsd)); /* make fake peer/node structures for lookup */ #ifdef FREEBSD411 h1.peer = &h2; h2.peer = &h1; h1.node = &n1; h2.node = &n2; n1.ID = node1; n2.ID = node2; #else h1.hk_peer = &h2; h2.hk_peer = &h1; h1.hk_node = &n1; h2.hk_node = &n2; n1.nd_ID = node1; n2.nd_ID = node2; #endif if (ng_wlan_mcast_lookup(node, &h1, &h2, group, src)){ mcsd->node1 = node1; mcsd->node2 = node2; mcsd->group = group; } /* if not found, node1/node2 will be zero */ break; } error = ng_wlan_mcast_link(node, node1, node2, group, src, unlink); break; #endif /* MULTICAST_LOOKUPS */ default: error = EINVAL; break; } break; default: error = EINVAL; break; } #ifndef FREEBSD411 NG_RESPOND_MSG(error, node, item, resp); #endif NG_FREE_MSG(msg); #ifndef FREEBSD411 #ifdef WLAN_GIANT_LOCK mtx_unlock(&ng_wlan_giant); #else mtx_unlock(&priv->ng_wlan_tab_lock); #ifdef MULTICAST_LOOKUPS mtx_unlock(&priv->ng_wlan_mcast_tab_lock); #endif /* MULTICAST_LOOKUPS */ #endif #endif return(error); } #ifdef FREEBSD411 /* * Handle incoming data from connected netgraph hooks. * FreeBSD 4.11 version uses netgraph metadata. * Does not support ksocket backchannel, multicast lookups. */ static int ng_wlan_rcvdata(hook_p hook, struct mbuf *m, meta_p meta) { const node_p node = NG_HOOK_NODE(hook); const priv_p priv = NG_NODE_PRIVATE(node); int error = 0; hook_p hook2; struct mbuf *m2; int nhooks; struct ng_wlan_tag *tag = NULL; /* Checking for NG_INVALID flag fixes race upon shutdown */ if ((NG_NODE_NOT_VALID(node)) || ((nhooks = NG_NODE_NUMHOOKS(node)) == 1)) { NG_FREE_DATA(m, meta); return (0); } /* Meta information is not preserved by this node but replaced with * its own data. This sets meta = NULL */ NG_FREE_META(meta); /* Count number of linked nodes, not just number of hooks */ nhooks = 0; LIST_FOREACH(hook2, &node->hooks, hooks) { /* TODO: maintain a count of the number of linked nodes */ if (hook2 == hook) continue; if (!ng_wlan_lookup(node, hook, hook2, NULL)) continue; nhooks++; } if (nhooks==0) /* Nobody to receive the data */ goto rcvdata_free_item_error; LIST_FOREACH(hook2, &node->hooks, hooks) { if (hook2 == hook) continue; /* Allocate a meta+tag for sending with the data, which may or may not be used. If used, the ptr is set to NULL for the next loop iteration; unused (non-NULL ptr) will be freed after loop. */ if (!meta) { MALLOC(meta, meta_p, WLAN_META_SIZE, M_NETGRAPH, M_NOWAIT | M_ZERO); if (!meta) goto rcvdata_free_item_error_nobufs; meta->used_len = (u_short) WLAN_META_SIZE; meta->allocated_len = (u_short) WLAN_META_SIZE; meta->flags = 0; meta->priority = WLAN_META_PRIORITY; meta->discardability = -1; tag = (struct ng_wlan_tag*)meta->options; tag->meta_hdr.cookie = NGM_WLAN_COOKIE; tag->meta_hdr.type = NG_TAG_WLAN; tag->meta_hdr.len = sizeof(struct ng_wlan_tag); } WLAN_TAG_ZERO(tag); if ( !ng_wlan_lookup(node, hook, hook2, tag)) { /* determine if peers are connected, fill in tag data */ continue; } if ((m->m_flags & M_MCAST) && (priv->mer > 0) && tag) { tag->per = priv->mer; /* use configured mcast error */ tag->burst = priv->mburst; /* use conf mcast burst */ } if (--nhooks == 0) { /* nhooks is really number of links */ if (tag && TAG_HAS_DATA(tag)) { /* send metadata and set meta = NULL */ NG_SEND_DATA(error, hook2, m, meta); tag = NULL; /* tag used */ } else { /* Don't send any metadata */ NG_SEND_DATA_ONLY(error, hook2, m); } break; /* no need to loop and malloc */ } else { if ((m2 = m_dup(m, M_DONTWAIT)) == NULL) goto rcvdata_free_item_error_nobufs; if (tag && TAG_HAS_DATA(tag)) { /* send metadata and set meta = NULL */ NG_SEND_DATA(error, hook2, m2, meta); tag = NULL; /* tag used */ } else { /* Don't send any metadata */ NG_SEND_DATA_ONLY(error, hook2, m2); if (error) /* XXX free mbuf? */ continue; /* don't give up */ } } /* end if nhooks==0 */ } /* end FOREACH hook */ if (meta) /* cleanup unused meta+tag */ NG_FREE_META(meta); goto rcvdata_out; rcvdata_free_item_error_nobufs: error = ENOBUFS; rcvdata_free_item_error: NG_FREE_DATA(m, meta); rcvdata_out: return (error); } #else /* FREEBSD411 */ /* * Handle incoming data from connected netgraph hooks. * FreeBSD 7.0 version uses mbuf tags; has additional features: * - ksocket backchannel for connecting two ng_wlans together * - multicast lookups for different forwarding behavior for multicast packets */ static int ng_wlan_rcvdata(hook_p hook, item_p item) { const node_p node = NG_HOOK_NODE(hook); int error = 0; hook_p hook2; struct mbuf *m2; int nhooks; struct ng_wlan_tag *tag = NULL; struct mbuf *m; const priv_p priv = NG_NODE_PRIVATE(node); ng_ID_t srcid; node_p peer; #ifdef MULTICAST_LOOKUPS u_int32_t group, src; struct ip *ip; struct ether_header *eh; #endif /* MULTICAST_LOOKUPS */ /* Checking for NG_INVALID flag fixes race upon shutdown */ if ((NG_NODE_NOT_VALID(node)) || ((nhooks = NG_NODE_NUMHOOKS(node)) == 1)) { NG_FREE_ITEM(item); return (0); } #ifdef WLAN_GIANT_LOCK mtx_lock(&ng_wlan_giant); #else mtx_lock(&priv->ng_wlan_tab_lock); #endif m = NGI_M(item); /* 'item' still owns it... we are peeking */ #ifdef MULTICAST_LOOKUPS mtx_lock(&priv->ng_wlan_mcast_tab_lock); src = group = 0; if (priv->multicast_enabled && (m->m_flags & M_MCAST) && (m->m_flags & M_PKTHDR)) { /* disassociate mbuf from item (now we must free it) */ NGI_GET_M(item, m); /* Get group of packets sent to non-local multicast addresses */ if ((m->m_pkthdr.len >= IP_MCAST_MIN_LEN) && (m = m_pullup(m, IP_MCAST_MIN_LEN)) != NULL) { eh = mtod_off(m, 0, struct ether_header *); if (ETHER_IS_MULTICAST(eh->ether_dhost) && ntohs(eh->ether_type) == ETHERTYPE_IP) { ip = mtod_off(m, IP_MCAST_HDR_OFFSET, struct ip *); if ((ip->ip_v == IPVERSION) && IN_MULTICAST(ntohl(ip->ip_dst.s_addr)) && !(IN_LOCAL_GROUP(ntohl(ip->ip_dst.s_addr)))) { group = ntohl(ip->ip_dst.s_addr); src = NG_NODE_ID(NG_PEER_NODE(hook)); } } } else if (!m) { /* m_pullup failed, free item and leave */ error = EINVAL; goto rcvdata_free_item_error; } NGI_M(item) = m; /* give mbuf back to item */ } #endif /* MULTICAST_LOOKUPS */ /* Count number of linked nodes, not just number of hooks */ nhooks = 0; LIST_FOREACH(hook2, &node->nd_hooks, hk_hooks) { /* TODO: maintain a count of the number of linked nodes */ if (hook2 == hook) continue; if (IS_PEER_KSOCKET(hook2)) { /* count all ksockets */ nhooks++; continue; } #ifdef MULTICAST_LOOKUPS /* count hook using multicast lookup if packet is multicast */ if ( group > 0 ) { if (!ng_wlan_mcast_lookup(node, hook, hook2, group, src) || !ng_wlan_lookup(node, hook, hook2, NULL)) continue; /* use normal unicast lookup */ } else #endif /* MULTICAST_LOOKUPS */ if (!ng_wlan_lookup(node, hook, hook2, NULL)) continue; nhooks++; } if (nhooks==0) /* Nobody to receive the data */ goto rcvdata_free_item_error; LIST_FOREACH(hook2, &node->nd_hooks, hk_hooks) { if (hook2 == hook) continue; /* Allocate a tag for prepending to the mbuf, which may or may not be used. If used, the ptr is set to NULL for the next loop iteration; unused (non-NULL ptr) will be freed after loop. */ if (!tag) tag = (struct ng_wlan_tag *)m_tag_alloc(NGM_WLAN_COOKIE, NG_TAG_WLAN, TAGSIZE, M_NOWAIT | M_ZERO); if (!tag) goto rcvdata_free_item_error_nobufs; WLAN_TAG_ZERO(tag); /* check for ksocket backchannel to another ng_wlan */ srcid = 0; if (IS_PEER_KSOCKET(hook2)) { /* this hook is connected to a ksocket * set srcid for prepending the mbuf */ peer = NG_PEER_NODE(hook2); srcid = (NG_NODE_ID(peer) << 8) + NG_NODE_ID(NG_PEER_NODE(hook)); } else #ifdef MULTICAST_LOOKUPS if ( group > 0 ) { if (!ng_wlan_mcast_lookup(node, hook, hook2, group, src) || !ng_wlan_lookup(node, hook, hook2, tag)) continue; /* multicast lookup failed */ /* multicast lookup success - tag data filled in */ } else #endif /* MULTICAST_LOOKUPS */ if ( !ng_wlan_lookup(node, hook, hook2, tag)) { /* determine if peers are connected, fill in tag data */ continue; } if ((m->m_flags & M_MCAST) && (priv->mer > 0) && tag) { tag->per = priv->mer; /* use configured mcast error */ tag->burst = priv->mburst; /* use conf mcast burst */ } if (--nhooks == 0) { /* nhooks is really number of links */ if (srcid > 0) { /* add srcid for ksockets */ NGI_GET_M(item, m); M_PREPEND(m, sizeof(ng_ID_t), M_DONTWAIT); if (!m) goto rcvdata_free_item_error_nobufs; mtod(m, ng_ID_t*)[0] = htonl(srcid); NGI_M(item) = m; } else if (tag && TAG_HAS_DATA(tag)) { m_tag_prepend(m, &tag->tag); tag = NULL; /* tag used */ } NG_FWD_ITEM_HOOK(error, item, hook2); break; /* no need to loop and malloc */ } else { if ((m2 = m_dup(m, M_DONTWAIT)) == NULL) goto rcvdata_free_item_error_nobufs; if (srcid > 0) { /* add srcid for ksockets */ M_PREPEND(m2, sizeof(ng_ID_t), M_DONTWAIT); if (!m2) goto rcvdata_free_item_error_nobufs; mtod(m2, ng_ID_t*)[0] = htonl(srcid); } else if (tag && TAG_HAS_DATA(tag)) { m_tag_prepend(m2, &tag->tag); tag = NULL; /* tag used */ } NG_SEND_DATA_ONLY(error, hook2, m2); if (error) /* XXX free mbuf? */ continue; /* don't give up */ } /* end if nhooks==0 */ } /* end FOREACH hook */ if (tag) /* cleanup unused tag */ m_tag_free(&tag->tag); /* assume item has been freed by fwd above (nhooks==0) */ goto rcvdata_out; rcvdata_free_item_error_nobufs: error = ENOBUFS; rcvdata_free_item_error: NG_FREE_ITEM(item); rcvdata_out: #ifdef WLAN_GIANT_LOCK mtx_unlock(&ng_wlan_giant); #else mtx_unlock(&priv->ng_wlan_tab_lock); #ifdef MULTICAST_LOOKUPS mtx_unlock(&priv->ng_wlan_mcast_tab_lock); #endif /* MULTICAST_LOOKUPS */ #endif return (error); } #endif /* FREEBSD411 */ #ifndef FREEBSD411 /* * Handle incoming data from hooks connected to kernel sockets */ static int ng_wlan_rcvdata_ks(hook_p hook, item_p item) { const node_p node = NG_HOOK_NODE(hook); const priv_p priv = NG_NODE_PRIVATE(node); int error = 0; hook_p hook2; struct mbuf *m, *m2; int nhooks; struct ng_wlan_tag *tag = NULL; ng_ID_t srcid; struct ng_hook hooklookup, hooklookup2; struct ng_node nodelookup; /* Checking for NG_INVALID flag fixes race upon shutdown */ if ((NG_NODE_NOT_VALID(node)) || ((nhooks = NG_NODE_NUMHOOKS(node)) == 1)) { NG_FREE_ITEM(item); return (0); } #ifndef FREEBSD411 #ifdef WLAN_GIANT_LOCK mtx_lock(&ng_wlan_giant); #else mtx_lock(&priv->ng_wlan_tab_lock); #endif #endif /* this packet came from another system, so we read the * netgraph ID from the mbuf for use in lookups */ NGI_GET_M(item, m); if (m->m_pkthdr.len < sizeof(ng_ID_t)) { /* too short */ error = EINVAL; goto rcvdata_ks_free_item_error; } if (m->m_len < sizeof(ng_ID_t) && (m = m_pullup(m, sizeof(ng_ID_t))) == NULL) { goto rcvdata_ks_free_item_error_nobufs; } srcid = ntohl(*mtod(m, ng_ID_t*)); m_adj(m, sizeof(ng_ID_t)); NGI_M(item) = (m); /* build fake hooks/node for performing lookup */ hooklookup2.hk_node = &nodelookup; hooklookup.hk_peer = &hooklookup2; nodelookup.nd_ID = srcid; /* Count number of linked nodes, not just number of hooks */ nhooks = 0; LIST_FOREACH(hook2, &node->nd_hooks, hk_hooks) { /* TODO: maintain a count of the number of linked nodes */ if (hook2 == hook) continue; /* ksockets not counted here -- they'll be skipped */ if (!ng_wlan_lookup(node, &hooklookup, hook2, NULL)) continue; nhooks++; } if (nhooks==0) /* Nobody to receive the data */ goto rcvdata_ks_free_item_error; LIST_FOREACH(hook2, &node->nd_hooks, hk_hooks) { if (hook2 == hook) continue; /* Allocate a tag for prepending to the mbuf, which may or may not be used. If used, the ptr is set to NULL for the next loop iteration; unused (non-NULL ptr) will be freed after loop. */ if (!tag) tag = (struct ng_wlan_tag *)m_tag_alloc(NGM_WLAN_COOKIE, NG_TAG_WLAN, TAGSIZE, M_NOWAIT | M_ZERO); if (!tag) goto rcvdata_ks_free_item_error_nobufs; WLAN_TAG_ZERO(tag); /* don't send data to other ksockets */ if (IS_PEER_KSOCKET(hook2)) { continue; /* determine if peers are connected */ } else if ( !ng_wlan_lookup(node, &hooklookup, hook2, tag)) { continue; } if (--nhooks == 0) { /* nhooks is really number of links */ if (tag && TAG_HAS_DATA(tag)) { m_tag_prepend(m, &tag->tag); tag = NULL; /* tag used */ } NG_FWD_ITEM_HOOK(error, item, hook2); } else { if ((m2 = m_dup(m, M_DONTWAIT)) == NULL) goto rcvdata_ks_free_item_error_nobufs; if (tag && TAG_HAS_DATA(tag)) { m_tag_prepend(m2, &tag->tag); tag = NULL; /* tag used */ } NG_SEND_DATA_ONLY(error, hook2, m2); if (error) /* XXX free mbuf? */ continue; /* don't give up */ } } if (tag) /* cleanup unused tag */ m_tag_free(&tag->tag); goto rcvdata_ks_out; rcvdata_ks_free_item_error_nobufs: error = ENOBUFS; rcvdata_ks_free_item_error: NG_FREE_ITEM(item); rcvdata_ks_out: #ifndef FREEBSD411 #ifdef WLAN_GIANT_LOCK mtx_unlock(&ng_wlan_giant); #else mtx_unlock(&priv->ng_wlan_tab_lock); #endif #endif return (error); } #endif /* !FREEBSD411 */ static int ng_wlan_disconnect(hook_p hook) { #ifdef FREEBSD411 const priv_p priv = hook->node->private; #else const priv_p priv = hook->hk_node->nd_private; #endif if (NG_NODE_NUMHOOKS(NG_HOOK_NODE(hook)) == 0 && NG_NODE_IS_VALID(NG_HOOK_NODE(hook)) && !priv->persistent) #ifdef FREEBSD411 ng_rmnode(NG_HOOK_NODE(hook)); #else ng_rmnode_self(NG_HOOK_NODE(hook)); #endif return (0); } static int ng_wlan_rmnode(node_p node) { const priv_p priv = NG_NODE_PRIVATE(node); int b, s; struct ng_wlan_hent *tmp; #ifdef MULTICAST_LOOKUPS struct ng_wlan_mcast_hent *mtmp; #endif /* MULTICAST_LOOKUPS */ s=splimp(); #ifdef FREEBSD411 node->flags |= NG_INVALID; ng_cutlinks(node); ng_unname(node); #else node->nd_flags |= NGF_INVALID; #endif NG_NODE_SET_PRIVATE(node, NULL); NG_NODE_UNREF(node); /* empty any link lists */ for (b = 0; b < MIN_BUCKETS; b++) { tmp = SLIST_FIRST(&priv->tab[b]); while (tmp) { SLIST_REMOVE_HEAD(&priv->tab[b], next); FREE(tmp, M_NETGRAPH_WLAN); tmp = SLIST_FIRST(&priv->tab[b]); } } FREE(priv->tab, M_NETGRAPH_WLAN); #ifndef FREEBSD411 mtx_destroy(&priv->ng_wlan_tab_lock); #endif priv->tab = NULL; #ifdef MULTICAST_LOOKUPS /* empty any multicast entry link lists */ for (b = 0; b < MIN_BUCKETS; b++) { mtmp = SLIST_FIRST(&priv->mcast_tab[b]); while (mtmp) { SLIST_REMOVE_HEAD(&priv->mcast_tab[b], next); FREE(mtmp, M_NETGRAPH_WLAN); mtmp = SLIST_FIRST(&priv->mcast_tab[b]); } } FREE(priv->mcast_tab, M_NETGRAPH_WLAN); mtx_destroy(&priv->ng_wlan_mcast_tab_lock); #endif /* MULTICAST_LOOKUPS */ FREE(priv, M_NETGRAPH_WLAN); splx(s); return 0; } /********************************************************************* * WLAN FUNCTIONS * **********************************************************************/ #define NODE_SORT(a, b, l, g) do { \ if (a > b) { \ g = a; \ l = b; \ } else { \ g = b; \ l = a; \ } \ } while (0); /* * Returns 1 if peers are linked, 0 if unlinked (default). */ static int ng_wlan_lookup(node_p node, hook_p hook1, hook_p hook2, struct ng_wlan_tag *tag) { const priv_p priv = NG_NODE_PRIVATE(node); struct ng_wlan_hent *hent; node_p node1, node2; ng_ID_t l_id, g_id; int bucket; if (!hook1 || !hook2) return 0; node1 = NG_PEER_NODE(hook1); node2 = NG_PEER_NODE(hook2); if (!node1 || !node2) return 0; NODE_SORT(NG_NODE_ID(node1), NG_NODE_ID(node2), l_id, g_id); bucket = HASH(l_id, g_id); /* mtx_lock(&priv->ng_wlan_tab_lock); */ SLIST_FOREACH(hent, &priv->tab[bucket], next) { if ((hent->l_id == l_id) && (hent->g_id == g_id)) { /* optionally fill in tag with link data*/ if (tag && hent->linked) { tag->delay = hent->delay; tag->bandwidth = hent->bandwidth; tag->per = hent->per; tag->duplicate = hent->duplicate; tag->jitter = hent->jitter; tag->burst = hent->burst; } /* mtx_unlock(&priv->ng_wlan_tab_lock); */ return (hent->linked); /* linked or not linked flag */ } } /* mtx_unlock(&priv->ng_wlan_tab_lock); */ return 0; /* not linked (not found) */ } #ifdef MULTICAST_LOOKUPS /* * Returns 1 if peers are linked for this multicast group, * 0 if unlinked (default). */ static int ng_wlan_mcast_lookup(node_p node, hook_p hook1, hook_p hook2, u_int32_t group, u_int32_t source) { const priv_p priv = NG_NODE_PRIVATE(node); struct ng_wlan_mcast_hent *hent; node_p node1, node2; ng_ID_t l_id, g_id; int bucket; if (!hook1 || !hook2) return 0; node1 = NG_PEER_NODE(hook1); node2 = NG_PEER_NODE(hook2); if (!node1 || !node2) return 0; NODE_SORT(NG_NODE_ID(node1), NG_NODE_ID(node2), l_id, g_id); bucket = MCAST_HASH(l_id, g_id, group); SLIST_FOREACH(hent, &priv->mcast_tab[bucket], next) { if ((hent->l_id == l_id) && (hent->g_id == g_id) && (hent->group == group) && (hent->source == source)) { return (hent->linked); } } return 0; /* not linked (not found) */ } /* * Link/unlink to peers for a given multicast group. */ static int ng_wlan_mcast_link(node_p node, ng_ID_t node1, ng_ID_t node2, u_int32_t group, u_int32_t source, int unlink) { const priv_p priv = NG_NODE_PRIVATE(node); ng_ID_t l_id, g_id; int bucket; struct ng_wlan_mcast_hent *hent; NODE_SORT(node1, node2, l_id, g_id); bucket = MCAST_HASH(l_id, g_id, group); priv->multicast_enabled = 1; /* turn on multicast lookups, this is never turned off */ /* Look for existing entry */ SLIST_FOREACH(hent, &priv->mcast_tab[bucket], next) { if ((hent->l_id == l_id) && (hent->g_id == g_id) && (hent->group == group) && (hent->source == source)) break; } /* Unlink called but no entry exists */ if (!hent && unlink) { return 0; } /* Allocate and initialize a new hash table entry */ if (!hent) { MALLOC( hent, struct ng_wlan_mcast_hent *, sizeof(*hent), M_NETGRAPH_WLAN, M_NOWAIT); if (hent == NULL) { return(ENOBUFS); } hent->l_id = l_id; hent->g_id = g_id; hent->group = group; hent->source = source; /* Add the new element to the hash bucket */ SLIST_INSERT_HEAD(&priv->mcast_tab[bucket], hent, next); } if (unlink) hent->linked = 0; else hent->linked = 1; return 0; } #endif /* MULTICAST_LOOKUPS */ /* * Link two peers together. * Once two peers have been linked together, the link can be flagged as * linked/unlinked in their hash table entry. Set link data if supplied. */ static int ng_wlan_link(node_p node, ng_ID_t node1, ng_ID_t node2, struct ng_wlan_set_data *data) { const priv_p priv = NG_NODE_PRIVATE(node); ng_ID_t l_id, g_id; int bucket; struct ng_wlan_hent *hent; NODE_SORT(node1, node2, l_id, g_id); bucket = HASH(l_id, g_id); /* mtx_lock(&priv->ng_wlan_tab_lock); */ /* Look for existing entry */ SLIST_FOREACH(hent, &priv->tab[bucket], next) { if ((hent->l_id == l_id) && (hent->g_id == g_id)) break; } /* Allocate and initialize a new hash table entry */ if (!hent) { MALLOC( hent, struct ng_wlan_hent *, sizeof(*hent), M_NETGRAPH_WLAN, M_NOWAIT | M_ZERO); if (hent == NULL) { /* mtx_unlock(&priv->ng_wlan_tab_lock); */ return(ENOBUFS); } hent->l_id = l_id; hent->g_id = g_id; /* Add the new element to the hash bucket */ SLIST_INSERT_HEAD(&priv->tab[bucket], hent, next); } hent->linked = 1; if (data) { hent->delay = data->delay; hent->bandwidth = data->bandwidth; hent->per = data->per; hent->duplicate = data->duplicate; hent->jitter = data->jitter; hent->burst = data->burst; } else { WLAN_TAG_ZERO(hent); } /* mtx_unlock(&priv->ng_wlan_tab_lock); */ return 0; } /* * Unlink two previously-linked peers. * because singly-linked list is not optimized for removals, we just * unset the "linked" flag. Link data is zeroed. */ static int ng_wlan_unlink(node_p node, ng_ID_t node1, ng_ID_t node2) { const priv_p priv = NG_NODE_PRIVATE(node); ng_ID_t l_id, g_id; int bucket; struct ng_wlan_hent *hent; NODE_SORT(node1, node2, l_id, g_id); bucket = HASH(l_id, g_id); /* Look for existing entry */ /* mtx_lock(&priv->ng_wlan_tab_lock); */ SLIST_FOREACH(hent, &priv->tab[bucket], next) { /* entry exists in hash table, unset linked flag */ if ((hent->l_id == l_id) && (hent->g_id == g_id)) { hent->linked = 0; WLAN_TAG_ZERO(hent); /* mtx_unlock(&priv->ng_wlan_tab_lock); */ return(0); } } /* Entry does not exist in the hash table, do nothing. */ /* mtx_unlock(&priv->ng_wlan_tab_lock); */ return 0; } core-4.8/kernel/freebsd/ng_wlan/ng_wlan.h0000664000175000017500000000655112534327775015403 00000000000000/* * Copyright (c) 2006-2011 the Boeing Company * ng_wlan is based on ng_hub, which is: * Copyright (c) 2004 Ruslan Ermilov * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * */ #ifndef _NETGRAPH_NG_WLAN_H_ #define _NETGRAPH_NG_WLAN_H_ /* Node type name and magic cookie. */ #define NG_WLAN_NODE_TYPE "wlan" #define NGM_WLAN_COOKIE 1146673193 /* Control message parse info */ struct ng_wlan_config { u_int32_t node1; u_int32_t node2; }; #define NG_WLAN_CONFIG_TYPE_INFO { \ { "node1", &ng_parse_uint32_type }, \ { "node2", &ng_parse_uint32_type }, \ { NULL } \ } struct ng_wlan_set_data { u_int32_t node1; u_int32_t node2; u_int64_t delay; /* keep these aligned with struct ng_wlan_tag */ u_int64_t bandwidth; u_int16_t per; u_int16_t duplicate; u_int32_t jitter; u_int16_t burst; }; #define NG_WLAN_SET_DATA_TYPE_INFO { \ { "node1", &ng_parse_uint32_type }, \ { "node2", &ng_parse_uint32_type }, \ { "delay", &ng_parse_uint64_type }, \ { "bandwidth", &ng_parse_uint64_type }, \ { "per", &ng_parse_uint16_type }, \ { "duplicate", &ng_parse_uint16_type }, \ { "jitter", &ng_parse_uint32_type }, \ { "burst", &ng_parse_uint16_type }, \ { NULL } \ } struct ng_wlan_mer { uint16_t mer; uint16_t mburst; }; #define NG_WLAN_MER_TYPE_INFO { \ { "mer", &ng_parse_uint16_type }, \ { "mburst", &ng_parse_uint16_type }, \ { NULL } \ } #ifdef MULTICAST_LOOKUPS struct ng_wlan_multicast_set_data { u_int32_t node1; u_int32_t node2; u_int32_t group; u_int32_t source; }; #define NG_WLAN_MULTICAST_SET_DATA_TYPE_INFO { \ { "node1", &ng_parse_uint32_type }, \ { "node2", &ng_parse_uint32_type }, \ { "group", &ng_parse_uint32_type }, \ { "source", &ng_parse_uint32_type }, \ { NULL } \ } #endif /* MULTICAST_LOOKUPS */ /* List of supported Netgraph control messages */ enum { NGM_WLAN_LINK_NODES = 1, NGM_WLAN_UNLINK_NODES, NGM_WLAN_NODES_SET, NGM_WLAN_NODES_UNSET, NGM_WLAN_NODES_GET, NGM_WLAN_MER, /* MULTICAST_ERR */ NGM_WLAN_MULTICAST_SET, /* MULTICAST_LOOKUPS */ NGM_WLAN_MULTICAST_UNSET, /* MULTICAST_LOOKUPS */ NGM_WLAN_MULTICAST_GET, /* MULTICAST_LOOKUPS */ }; #endif /* _NETGRAPH_NG_WLAN_H_ */ core-4.8/kernel/freebsd/ng_wlan/ng_wlan_tag.h0000664000175000017500000000321112534327775016224 00000000000000/* * Copyright (c) 2006-2011 the Boeing Company * All rights reserved. * * author: Jeff Ahrenholz */ #define NG_TAG_WLAN 0x01 #ifdef FREEBSD411 #define WLAN_META_SIZE (sizeof(struct ng_meta))+(sizeof(struct ng_wlan_tag)) #define WLAN_META_PRIORITY 0x01 #define TAGSIZE (sizeof(struct ng_wlan_tag) - sizeof(struct meta_field_header)) #else #define TAGSIZE (sizeof(struct ng_wlan_tag) - sizeof(struct m_tag)) #endif #define NG_WLAN_MAX_DELAY 2000000 /* 2,000,000us = 2s */ #define NG_WLAN_MAX_BW 1000000000 /* 1,000,000,000bps = 1000M */ #define NG_WLAN_MAX_PER 100 /* 100% */ #define NG_WLAN_MAX_DUP 50 /* 50% */ #define NG_WLAN_MAX_JITTER NG_WLAN_MAX_DELAY #define NG_WLAN_MAX_BURST NG_WLAN_MAX_PER /* Tag data that is prepended to packets passing through the WLAN node. */ struct ng_wlan_tag { #ifdef FREEBSD411 struct meta_field_header meta_hdr; #else struct m_tag tag; #endif u_int64_t delay; u_int64_t bandwidth; u_int16_t per; u_int16_t duplicate; u_int32_t jitter; u_int16_t burst; }; #define TAG_HAS_DATA(t) (t->delay || t->bandwidth || t->per || t->duplicate \ || t->jitter || t->burst ) #define WLAN_TAG_ZERO(t) do { \ t->delay = 0; \ t->bandwidth = 0; \ t->per = 0; \ t->duplicate = 0; \ t->jitter = 0; \ t->burst = 0; \ } while(0); #define WLAN_TAG_COPY(a, b) do { \ a->delay = ((struct ng_wlan_tag*)b)->delay; \ a->bandwidth = ((struct ng_wlan_tag*)b)->bandwidth; \ a->per = ((struct ng_wlan_tag*)b)->per; \ a->duplicate = ((struct ng_wlan_tag*)b)->duplicate; \ a->jitter = ((struct ng_wlan_tag*)b)->jitter; \ a->burst = ((struct ng_wlan_tag*)b)->burst; \ } while(0); core-4.8/kernel/freebsd/symlinks-8.1-RELEASE.diff0000664000175000017500000000404412534327775016240 00000000000000Index: sys/kern/vfs_lookup.c =========================================================================== --- sys/kern/vfs_lookup.c 2010/06/17 19:18:00 #3 +++ sys/kern/vfs_lookup.c 2010/06/17 19:18:00 @@ -59,6 +59,8 @@ #include #endif +#include + #include #include @@ -72,6 +74,19 @@ "unsigned long"); SDT_PROBE_DEFINE2(vfs, namei, lookup, return, "int", "struct vnode *"); +#ifdef VIMAGE +#define IMUNES_SYMLINK_HACK +#endif + +#ifdef IMUNES_SYMLINK_HACK +static VNET_DEFINE(int, morphing_symlinks); +#define V_morphing_symlinks VNET(morphing_symlinks) + +SYSCTL_VNET_INT(_vfs, OID_AUTO, morphing_symlinks, CTLFLAG_RW, + &VNET_NAME(morphing_symlinks), 0, + "Resolve @ to vimage name in symlinks"); +#endif + /* * Allocation zone for namei */ @@ -333,6 +348,44 @@ error = ENOENT; break; } +#ifdef IMUNES_SYMLINK_HACK + /* + * If the symbolic link includes a special character '@', + * and V_morphing_symlinks is set, substitute the first + * occurence of '@' with full path to jail / vimage name. + * If the full path includes subhierarchies, s/./\// when + * expanding '@' to jail / vimage name. + * + * XXX revisit buffer length checking. + */ + CURVNET_SET_QUIET(TD_TO_VNET(curthread)); + if (V_morphing_symlinks) { + char *sp = strchr(cp, '@'); + + if (sp) { + char *vname = td->td_ucred->cr_prison->pr_name; + int vnamelen = strlen(vname); + int i; + + if (vnamelen >= auio.uio_resid) { + if (ndp->ni_pathlen > 1) + uma_zfree(namei_zone, cp); + error = ENAMETOOLONG; + CURVNET_RESTORE(); + break; + } + bcopy(sp + 1, sp + vnamelen, + linklen - (sp - cp)); + bcopy(td->td_ucred->cr_prison->pr_name, + sp, vnamelen); + linklen += (vnamelen - 1); + for (i = 0; i < vnamelen; i++) + if (sp[i] == '.') + sp[i] = '/'; + } + } + CURVNET_RESTORE(); +#endif if (linklen + ndp->ni_pathlen >= MAXPATHLEN) { if (ndp->ni_pathlen > 1) uma_zfree(namei_zone, cp); core-4.8/kernel/freebsd/vimage/0000775000175000017500000000000012534327775013501 500000000000000core-4.8/kernel/freebsd/vimage/Makefile0000664000175000017500000000023012534327775015054 00000000000000# $FreeBSD$ PROG= vimage LDADD= -ljail DPADD= ${LIBJAIL} WARNS?= 2 CFLAGS+= -I../../../sys MAN= vimage.8 BINDIR?= /usr/sbin .include core-4.8/kernel/freebsd/vimage/vimage.80000664000175000017500000001274612534327775014774 00000000000000.\" Copyright (c) 2002, 2003 Marko Zec .\" Copyright (c) 2009 University of Zagreb .\" Copyright (c) 2009 FreeBSD Foundation .\" .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" $FreeBSD$ .\" .Dd August 25, 2009 .Dt VIMAGE 8 .Os .Sh NAME .Nm vimage .Nd manage virtual network stacks .Sh SYNOPSIS .Nm .Op Fl c | m .Ar vname .Op Ar param=value ... .Nm .Fl d .Ar vname .Nm .Fl l .Op Fl rvj .Op Ar vname .Nm .Fl i .Ar vname ifname .Op Ar newifname .Nm .Ar vi_name .Op command ... .Sh DESCRIPTION The .Nm utility is an alternative user interface for controlling virtual network stacks in FreeBSD, aimed primarily at supporting legacy applications which are not yet converted to using .Xr jail 8 , .Xr jexec 8 , and .Xr jls 8 . . .Ss Overview A virtual image or vimage is a jail with its own independent network stack instance. Every process, socket and network interface present in the system is always attached to one, and only one, virtual network stack instance (vnet). During system bootup sequence a default vnet is created to which all the configured interfaces and user processes are initially attached. Assuming that enough system resources are are available, a user with sufficient privileges can create and manage a hierarchy of subordinated virtual images. The .Nm command allows for creation, deletion and monitoring of virtual images, as well as for execution of arbitrary processes in a targeted virtual image. .Ss Invocation If invoked with no modifiers, the .Nm command spawns a new interactive shell in virtual image .Ar vname . If optional additional arguments following .Ar vname are provided, the first of those will be executed in place of the interactive shell, and the rest of the arguments will be passed as arguments to the executed command. .Pp The following modifiers are available: .Bl -tag -width indent .It Fl c Create a new virtual image named .Ar vname . Additional arguments, if provided, may be used to specify operating parameters different from defaults, in format .Ar param=value . See .Xr jail 8 for an extensive list of available parameters. .It Fl m Modify the parameters of a virtual image named .Ar vname , using the same syntax as with the -c form of the command. .It Fl d Delete the virtual image .Ar vname . No processes and/or sockets should exist in the target virtual image in order for the delete request to succeed. Non-loopback interfaces residing in the target virtual image will be reassigned to the virtual image's parent. .It Fl l List the properties and statistics for virtual images one level below the current one in the hierarchy. If an optional argument .Ar vname is provided, only the information regarding the target virtual image .Ar vname is displayed. With the optional .Op Ar -r switch enabled the list will include all virtual images below the current level in the vimage hierarchy. Enabling the optional .Op Ar -v or .Op Ar -j switches results in a more detailed output. .It Fl i Move interface .Ar ifname to the target virtual image .Ar vname . Interfaces will be automatically renamed to .So ethXX .Sc , unless an optional argument specifying the desired interface name .Op Ar newifname is provided. .El .Sh EXAMPLES Create a new virtual image named .So v1 .Sc , which is allowed to create and manage an own subhierarchy of vimages: .Pp .Dl vimage -c v1 children.max=100 .Pp Execute the .So ifconfig .Sc command in the virtual image .So v1 .Sc : .Pp .Dl vimage v1 ifconfig .Pp Move the interface .So vlan0 .Sc to the virtual image .So v1 .Sc while renaming the interface as .So ve0 .Sc : .Pp .Dl vimage -i v1 vlan0 ve0 .Pp Show the status information for virtual image .So v1 .Sc : .Pp .Dl vimage -lv v1 .Sh DIAGNOSTICS The .Nm command exits 0 on success, and >0 if an error occurs. .Sh SEE ALSO .Xr jail 8 .Xr jexec 8 .Xr jls 8 .Sh HISTORY Network stack virtualization framework first appeared as a patchset against the FreeBSD 4.7 kernel in 2002, and was maintained outside of the main FreeBSD tree. As a result of a project sponsored by the FreeBSD Foundation and Stiching NLNet, integrated virtualized network stack first appeared in FreeBSD 8.0. .Sh BUGS Deletion of vimages / vnets is known to leak kernel memory and fail at stopping various timers, hence may lead to system crashes. .Sh AUTHOR .An "Marko Zec" Aq zec@fer.hr core-4.8/kernel/freebsd/vimage/vimage.c0000664000175000017500000002366212534327775015046 00000000000000/* * Copyright (c) 2002-2004 Marko Zec * Copyright (c) 2009 University of Zagreb * Copyright (c) 2009 FreeBSD Foundation * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ #include #include #include #include #include #include #include #include #include #include #include typedef enum { VI_SWITCHTO, VI_CREATE, VI_MODIFY, VI_DESTROY, VI_IFMOVE, VI_GET } vi_cmd_t; typedef struct vimage_status { char name[MAXPATHLEN]; /* Must be first field for strcmp(). */ char path[MAXPATHLEN]; char hostname[MAXPATHLEN]; char domainname[MAXPATHLEN]; int jid; int parentjid; int vnet; int childcnt; int childmax; int cpuset; int rawsock; int socket_af; int mount; } vstat_t; #define VST_SIZE_STEP 1024 #define MAXPARAMS 32 static int getjail(vstat_t *, int, int); static char *invocname; static void usage(void) { fprintf(stderr, "usage: %s [-c | -m] vname [param=value ...]\n" " %s -d vname\n" " %s -l[rvj] [vname]\n" " %s -i vname ifname [newifname]\n" " %s vname [command ...]\n", invocname, invocname, invocname, invocname, invocname); exit(1); } int main(int argc, char **argv) { struct jailparam params[MAXPARAMS]; char ifname[IFNAMSIZ]; struct ifreq ifreq; vi_cmd_t newcmd, cmd; int recurse = 0; int verbose = 0; int jid, i, s, namelen; int vst_size, vst_last; vstat_t *vst; char *str; char ch; invocname = argv[0]; newcmd = cmd = VI_SWITCHTO; /* Default if no modifiers specified. */ while ((ch = getopt(argc, argv, "cdijlmrv")) != -1) { switch (ch) { case 'c': newcmd = VI_CREATE; break; case 'm': newcmd = VI_MODIFY; break; case 'd': newcmd = VI_DESTROY; break; case 'l': newcmd = VI_GET; break; case 'i': newcmd = VI_IFMOVE; break; case 'r': recurse = 1; break; case 'v': verbose++; break; case 'j': verbose = 2; break; default: usage(); } if (cmd == VI_SWITCHTO || cmd == newcmd) cmd = newcmd; else usage(); } argc -= optind; argv += optind; if ((cmd != VI_GET && (argc == 0 || recurse != 0 || verbose != 0)) || (cmd == VI_IFMOVE && (argc < 2 || argc > 3)) || (cmd == VI_MODIFY && argc < 2) || argc >= MAXPARAMS) usage(); switch (cmd) { case VI_GET: vst_last = 0; vst_size = VST_SIZE_STEP; if ((vst = malloc(vst_size * sizeof(*vst))) == NULL) break; if (argc == 1) namelen = strlen(argv[0]); else namelen = 0; jid = 0; while ((jid = getjail(&vst[vst_last], jid, verbose)) > 0) { /* Skip jails which do not own vnets. */ if (vst[vst_last].vnet != 1) continue; /* Skip non-matching vnames / hierarchies. */ if (namelen && ((strlen(vst[vst_last].name) < namelen || strncmp(vst[vst_last].name, argv[0], namelen) != 0) || (strlen(vst[vst_last].name) > namelen && vst[vst_last].name[namelen] != '.'))) continue; /* Skip any sub-trees if -r not requested. */ if (!recurse && (strlen(vst[vst_last].name) < namelen || strchr(&vst[vst_last].name[namelen], '.') != NULL)) continue; /* Grow vst table if necessary. */ if (++vst_last == vst_size) { vst_size += VST_SIZE_STEP; vst = realloc(vst, vst_size * sizeof(*vst)); if (vst == NULL) break; } } if (vst == NULL) break; /* Sort: the key is the 1st field in *vst, i.e. vimage name. */ qsort(vst, vst_last, sizeof(*vst), (void *) strcmp); for (i = 0; i < vst_last; i++) { if (!verbose) { printf("%s\n", vst[i].name); continue; } printf("%s:\n", vst[i].name); printf(" Path: %s\n", vst[i].path); printf(" Hostname: %s\n", vst[i].hostname); printf(" Domainname: %s\n", vst[i].domainname); printf(" Children: %d\n", vst[i].childcnt); if (verbose < 2) continue; printf(" Children limit: %d\n", vst[i].childmax); printf(" CPUsetID: %d\n", vst[i].cpuset); printf(" JID: %d\n", vst[i].jid); printf(" PJID: %d\n", vst[i].parentjid); printf(" Raw sockets allowed: %d\n", vst[i].rawsock); printf(" All AF allowed: %d\n", vst[i].socket_af); printf(" Mount allowed: %d\n", vst[i].mount); } free(vst); exit(0); case VI_IFMOVE: if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) break; if ((jid = jail_getid(argv[0])) < 0) break; ifreq.ifr_jid = jid; strncpy(ifreq.ifr_name, argv[1], sizeof(ifreq.ifr_name)); if (ioctl(s, SIOCSIFVNET, (caddr_t)&ifreq) < 0) break; close(s); if (argc == 3) snprintf(ifname, sizeof(ifname), "%s", argv[2]); else snprintf(ifname, sizeof(ifname), "eth0"); ifreq.ifr_data = ifname; /* Do we need to rename the ifnet? */ if (strcmp(ifreq.ifr_name, ifname) != 0) { /* Switch to the context of the target vimage. */ if (jail_attach(jid) < 0) break; if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) break; for (namelen = 0; isalpha(ifname[namelen]); namelen++); i = 0; /* Search for a free ifunit in target vnet. Unsafe. */ while (ioctl(s, SIOCSIFNAME, (caddr_t)&ifreq) < 0) { snprintf(&ifname[namelen], sizeof(ifname) - namelen, "%d", i); /* Emergency brake. */ if (i++ == IF_MAXUNIT) break; } } if (i < IF_MAXUNIT) printf("%s@%s\n", ifname, argv[0]); else printf("%s@%s\n", ifreq.ifr_name, argv[0]); exit(0); case VI_CREATE: if (jail_setv(JAIL_CREATE, "name", argv[0], "vnet", NULL, "host", NULL, "persist", NULL, "allow.raw_sockets", "true", "allow.socket_af", "true", "allow.mount", "true", NULL) < 0) break; if (argc == 1) exit(0); /* Not done yet, proceed to apply non-default parameters. */ case VI_MODIFY: jailparam_init(¶ms[0], "name"); jailparam_import(¶ms[0], argv[0]); for (i = 1; i < argc; i++) { for (str = argv[i]; *str != '=' && *str != 0; str++) { /* Do nothing - search for '=' delimeter. */ } if (*str == 0) break; *str++ = 0; if (*str == 0) break; jailparam_init(¶ms[i], argv[i]); jailparam_import(¶ms[i], str); } if (i != argc) break; if (jailparam_set(params, i, JAIL_UPDATE) < 0) break; exit(0); case VI_DESTROY: if ((jid = jail_getid(argv[0])) < 0) break; if (jail_remove(jid) < 0) break; exit(0); case VI_SWITCHTO: if ((jid = jail_getid(argv[0])) < 0) break; if (jail_attach(jid) < 0) break; if (argc == 1) { printf("Switched to vimage %s\n", argv[0]); if ((str = getenv("SHELL")) == NULL) execlp("/bin/sh", invocname, NULL); else execlp(str, invocname, NULL); } else execvp(argv[1], &argv[1]); break; default: /* Should be unreachable. */ break; } if (jail_errmsg[0]) fprintf(stderr, "Error: %s\n", jail_errmsg); else perror("Error"); exit(1); } static int getjail(vstat_t *vs, int lastjid, int verbose) { struct jailparam params[32]; /* Must be > max(psize). */ int psize = 0; bzero(params, sizeof(params)); bzero(vs, sizeof(*vs)); jailparam_init(¶ms[psize], "lastjid"); jailparam_import_raw(¶ms[psize++], &lastjid, sizeof lastjid); jailparam_init(¶ms[psize], "vnet"); jailparam_import_raw(¶ms[psize++], &vs->vnet, sizeof(vs->vnet)); jailparam_init(¶ms[psize], "name"); jailparam_import_raw(¶ms[psize++], &vs->name, sizeof(vs->name)); if (verbose == 0) goto done; jailparam_init(¶ms[psize], "path"); jailparam_import_raw(¶ms[psize++], &vs->path, sizeof(vs->path)); jailparam_init(¶ms[psize], "host.hostname"); jailparam_import_raw(¶ms[psize++], &vs->hostname, sizeof(vs->hostname)); jailparam_init(¶ms[psize], "host.domainname"); jailparam_import_raw(¶ms[psize++], &vs->domainname, sizeof(vs->domainname)); jailparam_init(¶ms[psize], "children.cur"); jailparam_import_raw(¶ms[psize++], &vs->childcnt, sizeof(vs->childcnt)); if (verbose == 1) goto done; jailparam_init(¶ms[psize], "children.max"); jailparam_import_raw(¶ms[psize++], &vs->childmax, sizeof(vs->childmax)); jailparam_init(¶ms[psize], "cpuset.id"); jailparam_import_raw(¶ms[psize++], &vs->cpuset, sizeof(vs->cpuset)); jailparam_init(¶ms[psize], "parent"); jailparam_import_raw(¶ms[psize++], &vs->parentjid, sizeof(vs->parentjid)); jailparam_init(¶ms[psize], "allow.raw_sockets"); jailparam_import_raw(¶ms[psize++], &vs->rawsock, sizeof(vs->rawsock)); jailparam_init(¶ms[psize], "allow.socket_af"); jailparam_import_raw(¶ms[psize++], &vs->socket_af, sizeof(vs->socket_af)); jailparam_init(¶ms[psize], "allow.mount"); jailparam_import_raw(¶ms[psize++], &vs->mount, sizeof(vs->mount)); done: vs->jid = jailparam_get(params, psize, 0); jailparam_free(params, psize); return (vs->jid); } core-4.8/kernel/freebsd/vimage_7-CORE.diff0000664000175000017500000026216512534327775015243 00000000000000diff -ur sys.20081015/netinet/ip_mroute.c sys/netinet/ip_mroute.c --- sys.20081015/netinet/ip_mroute.c 2008-08-16 16:29:19.000000000 -0700 +++ sys/netinet/ip_mroute.c 2008-11-05 16:30:04.000000000 -0800 @@ -99,6 +99,7 @@ #include #include #ifdef INET6 +#include #include #include #include @@ -112,21 +113,30 @@ * Control debugging code for rsvp and multicast routing code. * Can only set them with the debugger. */ +#ifndef VIMAGE static u_int rsvpdebug; /* non-zero enables debugging */ static u_int mrtdebug; /* any set of the flags below */ +#endif /* !VIMAGE */ #define DEBUG_MFC 0x02 #define DEBUG_FORWARD 0x04 #define DEBUG_EXPIRE 0x08 #define DEBUG_XMIT 0x10 #define DEBUG_PIM 0x20 +#ifndef VIMAGE #define VIFI_INVALID ((vifi_t) -1) +#endif /* !VIMAGE */ #define M_HASCL(m) ((m)->m_flags & M_EXT) static MALLOC_DEFINE(M_MRTABLE, "mroutetbl", "multicast routing tables"); +static int vnet_mroute_iattach(const void *); +static int vnet_mroute_idetach(const void *); + +VNET_MOD_DECLARE(MROUTE, mroute, vnet_mroute_iattach, vnet_mroute_idetach, INET, NULL) + /* * Locking. We use two locks: one for the virtual interface table and * one for the forwarding table. These locks may be nested in which case @@ -140,48 +150,59 @@ * */ +#ifndef VIMAGE static struct mrtstat mrtstat; -SYSCTL_STRUCT(_net_inet_ip, OID_AUTO, mrtstat, CTLFLAG_RW, - &mrtstat, mrtstat, +#endif /* !VIMAGE */ +SYSCTL_V_STRUCT(V_NET, vnet_mroute, _net_inet_ip, OID_AUTO, mrtstat, + CTLFLAG_RW, mrtstat, mrtstat, "Multicast Routing Statistics (struct mrtstat, netinet/ip_mroute.h)"); - +#ifndef VIMAGE static struct mfc *mfctable[MFCTBLSIZ]; -SYSCTL_OPAQUE(_net_inet_ip, OID_AUTO, mfctable, CTLFLAG_RD, - &mfctable, sizeof(mfctable), "S,*mfc[MFCTBLSIZ]", +SYSCTL_V_OID(V_NET, vnet_mroute, _net_inet_ip, CTLTYPE_OPAQUE|OID_AUTO, + mfctable, CTLFLAG_RD, mfctable, sizeof(mfctable), sysctl_handle_opaque, + "S,*mfc[MFCTBLSIZ]", "Multicast Forwarding Table (struct *mfc[MFCTBLSIZ], netinet/ip_mroute.h)"); static struct mtx mrouter_mtx; -#define MROUTER_LOCK() mtx_lock(&mrouter_mtx) -#define MROUTER_UNLOCK() mtx_unlock(&mrouter_mtx) -#define MROUTER_LOCK_ASSERT() mtx_assert(&mrouter_mtx, MA_OWNED) +#endif /* !VIMAGE */ +#define MROUTER_LOCK() mtx_lock(&V_mrouter_mtx) +#define MROUTER_UNLOCK() mtx_unlock(&V_mrouter_mtx) +#define MROUTER_LOCK_ASSERT() mtx_assert(&V_mrouter_mtx, MA_OWNED) #define MROUTER_LOCK_INIT() \ - mtx_init(&mrouter_mtx, "IPv4 multicast forwarding", NULL, MTX_DEF) -#define MROUTER_LOCK_DESTROY() mtx_destroy(&mrouter_mtx) + mtx_init(&V_mrouter_mtx, "IPv4 multicast forwarding", NULL, MTX_DEF) +#define MROUTER_LOCK_DESTROY() mtx_destroy(&V_mrouter_mtx) +#ifndef VIMAGE static struct mtx mfc_mtx; -#define MFC_LOCK() mtx_lock(&mfc_mtx) -#define MFC_UNLOCK() mtx_unlock(&mfc_mtx) -#define MFC_LOCK_ASSERT() mtx_assert(&mfc_mtx, MA_OWNED) -#define MFC_LOCK_INIT() mtx_init(&mfc_mtx, "mroute mfc table", NULL, MTX_DEF) -#define MFC_LOCK_DESTROY() mtx_destroy(&mfc_mtx) +#endif /* !VIMAGE */ +#define MFC_LOCK() mtx_lock(&V_mfc_mtx) +#define MFC_UNLOCK() mtx_unlock(&V_mfc_mtx) +#define MFC_LOCK_ASSERT() mtx_assert(&V_mfc_mtx, MA_OWNED) +#define MFC_LOCK_INIT() mtx_init(&V_mfc_mtx, "mroute mfc table", NULL, MTX_DEF) +#define MFC_LOCK_DESTROY() mtx_destroy(&V_mfc_mtx) +#ifndef VIMAGE static struct vif viftable[MAXVIFS]; -SYSCTL_OPAQUE(_net_inet_ip, OID_AUTO, viftable, CTLFLAG_RD, - &viftable, sizeof(viftable), "S,vif[MAXVIFS]", +SYSCTL_V_OID(V_NET, vnet_mroute, _net_inet_ip, CTLTYPE_OPAQUE|OID_AUTO, viftable, + CTLFLAG_RD, viftable, sizeof(viftable), sysctl_handle_opaque, + "S,vif[MAXVIFS]", "Multicast Virtual Interfaces (struct vif[MAXVIFS], netinet/ip_mroute.h)"); static struct mtx vif_mtx; -#define VIF_LOCK() mtx_lock(&vif_mtx) -#define VIF_UNLOCK() mtx_unlock(&vif_mtx) -#define VIF_LOCK_ASSERT() mtx_assert(&vif_mtx, MA_OWNED) -#define VIF_LOCK_INIT() mtx_init(&vif_mtx, "mroute vif table", NULL, MTX_DEF) -#define VIF_LOCK_DESTROY() mtx_destroy(&vif_mtx) +#endif /* !VIMAGE */ +#define VIF_LOCK() mtx_lock(&V_vif_mtx) +#define VIF_UNLOCK() mtx_unlock(&V_vif_mtx) +#define VIF_LOCK_ASSERT() mtx_assert(&V_vif_mtx, MA_OWNED) +#define VIF_LOCK_INIT() mtx_init(&V_vif_mtx, "mroute vif table", NULL, MTX_DEF) +#define VIF_LOCK_DESTROY() mtx_destroy(&V_vif_mtx) +#ifndef VIMAGE static u_char nexpire[MFCTBLSIZ]; static eventhandler_tag if_detach_event_tag = NULL; static struct callout expire_upcalls_ch; +#endif /* !VIMAGE */ #define EXPIRE_TIMEOUT (hz / 4) /* 4x / second */ #define UPCALL_EXPIRE 6 /* number of timeouts */ @@ -196,25 +217,31 @@ * Pending timeouts are stored in a hash table, the key being the * expiration time. Periodically, the entries are analysed and processed. */ +#ifndef VIMAGE #define BW_METER_BUCKETS 1024 static struct bw_meter *bw_meter_timers[BW_METER_BUCKETS]; -static struct callout bw_meter_ch; +static struct callout V_bw_meter_ch; +#endif /* !VIMAGE */ #define BW_METER_PERIOD (hz) /* periodical handling of bw meters */ /* * Pending upcalls are stored in a vector which is flushed when * full, or periodically */ +#ifndef VIMAGE static struct bw_upcall bw_upcalls[BW_UPCALLS_MAX]; static u_int bw_upcalls_n; /* # of pending upcalls */ static struct callout bw_upcalls_ch; +#endif /* !VIMAGE */ #define BW_UPCALLS_PERIOD (hz) /* periodical flush of bw upcalls */ +#ifndef VIMAGE static struct pimstat pimstat; +#endif /* !VIMAGE */ SYSCTL_NODE(_net_inet, IPPROTO_PIM, pim, CTLFLAG_RW, 0, "PIM"); -SYSCTL_STRUCT(_net_inet_pim, PIMCTL_STATS, stats, CTLFLAG_RD, - &pimstat, pimstat, +SYSCTL_V_STRUCT(V_NET, vnet_mroute, _net_inet_pim, PIMCTL_STATS, stats, + CTLFLAG_RD, pimstat, pimstat, "PIM Statistics (struct pimstat, netinet/pim_var.h)"); static u_long pim_squelch_wholepkt = 0; @@ -222,6 +249,7 @@ &pim_squelch_wholepkt, 0, "Disable IGMP_WHOLEPKT notifications if rendezvous point is unspecified"); + extern struct domain inetdomain; struct protosw in_pim_protosw = { .pr_type = SOCK_RAW, @@ -291,13 +319,17 @@ 0 /* flags */ }; +#ifndef VIMAGE static struct ifnet multicast_register_if; static vifi_t reg_vif_num = VIFI_INVALID; +#endif /* !VIMAGE */ /* * Private variables. */ +#ifndef VIMAGE static vifi_t numvifs; +#endif /* !VIMAGE */ static u_long X_ip_mcast_src(int vifi); static int X_ip_mforward(struct ip *ip, struct ifnet *ifp, @@ -337,7 +369,7 @@ static void bw_upcalls_send(void); static void schedule_bw_meter(struct bw_meter *x, struct timeval *nowp); static void unschedule_bw_meter(struct bw_meter *x); -static void bw_meter_process(void); +static void bw_meter_process(struct vnet *vnet); static void expire_bw_upcalls_send(void *); static void expire_bw_meter_process(void *); @@ -352,7 +384,9 @@ /* * whether or not special PIM assert processing is enabled. */ +#ifndef VIMAGE static int pim_assert; +#endif /* !VIMAGE */ /* * Rate limit for assert notification messages, in usec */ @@ -367,7 +401,9 @@ MRT_MFC_FLAGS_BORDER_VIF | MRT_MFC_RP | MRT_MFC_BW_UPCALL); +#ifndef VIMAGE static uint32_t mrt_api_config = 0; +#endif /* !VIMAGE */ /* * Hash function for a source, group entry @@ -383,11 +419,12 @@ static struct mfc * mfc_find(in_addr_t o, in_addr_t g) { + INIT_VNET_MROUTE(curvnet); struct mfc *rt; MFC_LOCK_ASSERT(); - for (rt = mfctable[MFCHASH(o,g)]; rt; rt = rt->mfc_next) + for (rt = V_mfctable[MFCHASH(o,g)]; rt; rt = rt->mfc_next) if ((rt->mfc_origin.s_addr == o) && (rt->mfc_mcastgrp.s_addr == g) && (rt->mfc_stall == NULL)) break; @@ -424,7 +461,8 @@ static int X_ip_mrouter_set(struct socket *so, struct sockopt *sopt) { - INIT_VNET_INET(curvnet); + INIT_VNET_INET(so->so_vnet); + INIT_VNET_MROUTE(so->so_vnet); int error, optval; vifi_t vifi; struct vifctl vifc; @@ -468,7 +506,7 @@ * select data size depending on API version. */ if (sopt->sopt_name == MRT_ADD_MFC && - mrt_api_config & MRT_API_FLAGS_ALL) { + V_mrt_api_config & MRT_API_FLAGS_ALL) { error = sooptcopyin(sopt, &mfc, sizeof(struct mfcctl2), sizeof(struct mfcctl2)); } else { @@ -525,6 +563,7 @@ static int X_ip_mrouter_get(struct socket *so, struct sockopt *sopt) { + INIT_VNET_MROUTE(so->so_vnet); int error; static int version = 0x0305; /* !!! why is this here? XXX */ @@ -534,7 +573,7 @@ break; case MRT_ASSERT: - error = sooptcopyout(sopt, &pim_assert, sizeof pim_assert); + error = sooptcopyout(sopt, &V_pim_assert, sizeof V_pim_assert); break; case MRT_API_SUPPORT: @@ -542,7 +581,7 @@ break; case MRT_API_CONFIG: - error = sooptcopyout(sopt, &mrt_api_config, sizeof mrt_api_config); + error = sooptcopyout(sopt, &V_mrt_api_config, sizeof V_mrt_api_config); break; default: @@ -590,6 +629,7 @@ static int get_sg_cnt(struct sioc_sg_req *req) { + INIT_VNET_MROUTE(curvnet); struct mfc *rt; MFC_LOCK(); @@ -612,18 +652,19 @@ static int get_vif_cnt(struct sioc_vif_req *req) { + INIT_VNET_MROUTE(curvnet); vifi_t vifi = req->vifi; VIF_LOCK(); - if (vifi >= numvifs) { + if (vifi >= V_numvifs) { VIF_UNLOCK(); return EINVAL; } - req->icount = viftable[vifi].v_pkt_in; - req->ocount = viftable[vifi].v_pkt_out; - req->ibytes = viftable[vifi].v_bytes_in; - req->obytes = viftable[vifi].v_bytes_out; + req->icount = V_viftable[vifi].v_pkt_in; + req->ocount = V_viftable[vifi].v_pkt_out; + req->ibytes = V_viftable[vifi].v_bytes_in; + req->obytes = V_viftable[vifi].v_bytes_out; VIF_UNLOCK(); return 0; @@ -632,24 +673,30 @@ static void ip_mrouter_reset(void) { - bzero((caddr_t)mfctable, sizeof(mfctable)); - bzero((caddr_t)nexpire, sizeof(nexpire)); - - pim_assert = 0; - mrt_api_config = 0; - - callout_init(&expire_upcalls_ch, CALLOUT_MPSAFE); - - bw_upcalls_n = 0; - bzero((caddr_t)bw_meter_timers, sizeof(bw_meter_timers)); - callout_init(&bw_upcalls_ch, CALLOUT_MPSAFE); - callout_init(&bw_meter_ch, CALLOUT_MPSAFE); + INIT_VNET_MROUTE(curvnet); + bzero((caddr_t)V_mfctable, sizeof(V_mfctable)); + bzero((caddr_t)V_nexpire, sizeof(V_nexpire)); + if (V_reg_vif_num != VIFI_INVALID) + IF_ADDR_LOCK_DESTROY(&V_multicast_register_if); + bzero(&V_multicast_register_if, sizeof(V_multicast_register_if)); + + V_reg_vif_num = VIFI_INVALID; + V_pim_assert = 0; + V_mrt_api_config = 0; + + callout_init(&V_expire_upcalls_ch, CALLOUT_MPSAFE); + + V_bw_upcalls_n = 0; + bzero((caddr_t)V_bw_meter_timers, sizeof(V_bw_meter_timers)); + callout_init(&V_bw_upcalls_ch, CALLOUT_MPSAFE); + callout_init(&V_bw_meter_ch, CALLOUT_MPSAFE); } static void if_detached_event(void *arg __unused, struct ifnet *ifp) { INIT_VNET_INET(curvnet); + INIT_VNET_MROUTE(curvnet); vifi_t vifi; int i; struct mfc *mfc; @@ -676,12 +723,12 @@ */ VIF_LOCK(); MFC_LOCK(); - for (vifi = 0; vifi < numvifs; vifi++) { - if (viftable[vifi].v_ifp != ifp) + for (vifi = 0; vifi < V_numvifs; vifi++) { + if (V_viftable[vifi].v_ifp != ifp) continue; for (i = 0; i < MFCTBLSIZ; i++) { - ppmfc = &mfctable[i]; - for (mfc = mfctable[i]; mfc != NULL; ) { + ppmfc = &V_mfctable[i]; + for (mfc = V_mfctable[i]; mfc != NULL; ) { nmfc = mfc->mfc_next; if (mfc->mfc_parent == vifi) { for (pq = mfc->mfc_stall; pq != NULL; ) { @@ -713,9 +760,10 @@ static int ip_mrouter_init(struct socket *so, int version) { - INIT_VNET_INET(curvnet); + INIT_VNET_INET(so->so_vnet); + INIT_VNET_MROUTE(so->so_vnet); - if (mrtdebug) + if (V_mrtdebug) log(LOG_DEBUG, "ip_mrouter_init: so_type = %d, pr_protocol = %d\n", so->so_type, so->so_proto->pr_protocol); @@ -732,24 +780,25 @@ return EADDRINUSE; } - if_detach_event_tag = EVENTHANDLER_REGISTER(ifnet_departure_event, + V_if_detach_event_tag = EVENTHANDLER_REGISTER(ifnet_departure_event, if_detached_event, NULL, EVENTHANDLER_PRI_ANY); - if (if_detach_event_tag == NULL) { + if (V_if_detach_event_tag == NULL) { MROUTER_UNLOCK(); return (ENOMEM); } - callout_reset(&expire_upcalls_ch, EXPIRE_TIMEOUT, expire_upcalls, NULL); - - callout_reset(&bw_upcalls_ch, BW_UPCALLS_PERIOD, - expire_bw_upcalls_send, NULL); - callout_reset(&bw_meter_ch, BW_METER_PERIOD, expire_bw_meter_process, NULL); + callout_reset(&V_expire_upcalls_ch, EXPIRE_TIMEOUT, + expire_upcalls, (void *)so->so_vnet); + callout_reset(&V_bw_upcalls_ch, BW_UPCALLS_PERIOD, + expire_bw_upcalls_send, (void *)so->so_vnet); + callout_reset(&V_bw_meter_ch, BW_METER_PERIOD, + expire_bw_meter_process, (void *)so->so_vnet); V_ip_mrouter = so; MROUTER_UNLOCK(); - if (mrtdebug) + if (V_mrtdebug) log(LOG_DEBUG, "ip_mrouter_init\n"); return 0; @@ -762,6 +811,7 @@ X_ip_mrouter_done(void) { INIT_VNET_INET(curvnet); + INIT_VNET_MROUTE(curvnet); vifi_t vifi; int i; struct ifnet *ifp; @@ -780,41 +830,41 @@ * Detach/disable hooks to the reset of the system. */ V_ip_mrouter = NULL; - mrt_api_config = 0; + V_mrt_api_config = 0; VIF_LOCK(); /* * For each phyint in use, disable promiscuous reception of all IP * multicasts. */ - for (vifi = 0; vifi < numvifs; vifi++) { - if (viftable[vifi].v_lcl_addr.s_addr != 0 && - !(viftable[vifi].v_flags & (VIFF_TUNNEL | VIFF_REGISTER))) { + for (vifi = 0; vifi < V_numvifs; vifi++) { + if (V_viftable[vifi].v_lcl_addr.s_addr != 0 && + !(V_viftable[vifi].v_flags & (VIFF_TUNNEL | VIFF_REGISTER))) { struct sockaddr_in *so = (struct sockaddr_in *)&(ifr.ifr_addr); so->sin_len = sizeof(struct sockaddr_in); so->sin_family = AF_INET; so->sin_addr.s_addr = INADDR_ANY; - ifp = viftable[vifi].v_ifp; + ifp = V_viftable[vifi].v_ifp; if_allmulti(ifp, 0); } } - bzero((caddr_t)viftable, sizeof(viftable)); - numvifs = 0; - pim_assert = 0; + bzero((caddr_t)V_viftable, sizeof(V_viftable)); + V_numvifs = 0; + V_pim_assert = 0; VIF_UNLOCK(); - EVENTHANDLER_DEREGISTER(ifnet_departure_event, if_detach_event_tag); + EVENTHANDLER_DEREGISTER(ifnet_departure_event, V_if_detach_event_tag); /* * Free all multicast forwarding cache entries. */ - callout_stop(&expire_upcalls_ch); - callout_stop(&bw_upcalls_ch); - callout_stop(&bw_meter_ch); + callout_stop(&V_expire_upcalls_ch); + callout_stop(&V_bw_upcalls_ch); + callout_stop(&V_bw_meter_ch); MFC_LOCK(); for (i = 0; i < MFCTBLSIZ; i++) { - for (rt = mfctable[i]; rt != NULL; ) { + for (rt = V_mfctable[i]; rt != NULL; ) { struct mfc *nr = rt->mfc_next; for (rte = rt->mfc_stall; rte != NULL; ) { @@ -829,17 +879,19 @@ rt = nr; } } - bzero((caddr_t)mfctable, sizeof(mfctable)); - bzero((caddr_t)nexpire, sizeof(nexpire)); - bw_upcalls_n = 0; - bzero(bw_meter_timers, sizeof(bw_meter_timers)); + bzero((caddr_t)V_mfctable, sizeof(V_mfctable)); + bzero((caddr_t)V_nexpire, sizeof(V_nexpire)); + V_bw_upcalls_n = 0; + bzero(V_bw_meter_timers, sizeof(V_bw_meter_timers)); MFC_UNLOCK(); - reg_vif_num = VIFI_INVALID; + if (V_reg_vif_num != VIFI_INVALID) + IF_ADDR_LOCK_DESTROY(&V_multicast_register_if); + V_reg_vif_num = VIFI_INVALID; MROUTER_UNLOCK(); - if (mrtdebug) + if (V_mrtdebug) log(LOG_DEBUG, "ip_mrouter_done\n"); return 0; @@ -851,10 +903,11 @@ static int set_assert(int i) { + INIT_VNET_MROUTE(curvnet); if ((i != 1) && (i != 0)) return EINVAL; - pim_assert = i; + V_pim_assert = i; return 0; } @@ -865,6 +918,7 @@ int set_api_config(uint32_t *apival) { + INIT_VNET_MROUTE(curvnet); int i; /* @@ -874,23 +928,23 @@ * - pim_assert is not enabled * - the MFC table is empty */ - if (numvifs > 0) { + if (V_numvifs > 0) { *apival = 0; return EPERM; } - if (pim_assert) { + if (V_pim_assert) { *apival = 0; return EPERM; } for (i = 0; i < MFCTBLSIZ; i++) { - if (mfctable[i] != NULL) { + if (V_mfctable[i] != NULL) { *apival = 0; return EPERM; } } - mrt_api_config = *apival & mrt_api_support; - *apival = mrt_api_config; + V_mrt_api_config = *apival & mrt_api_support; + *apival = V_mrt_api_config; return 0; } @@ -901,7 +955,8 @@ static int add_vif(struct vifctl *vifcp) { - struct vif *vifp = viftable + vifcp->vifc_vifi; + INIT_VNET_MROUTE(curvnet); + struct vif *vifp = V_viftable + vifcp->vifc_vifi; struct sockaddr_in sin = {sizeof sin, AF_INET}; struct ifaddr *ifa; struct ifnet *ifp; @@ -950,14 +1005,19 @@ VIF_UNLOCK(); return EOPNOTSUPP; } else if (vifcp->vifc_flags & VIFF_REGISTER) { - ifp = &multicast_register_if; - if (mrtdebug) + ifp = &V_multicast_register_if; + if (V_mrtdebug) log(LOG_DEBUG, "Adding a register vif, ifp: %p\n", - (void *)&multicast_register_if); - if (reg_vif_num == VIFI_INVALID) { - if_initname(&multicast_register_if, "register_vif", 0); - multicast_register_if.if_flags = IFF_LOOPBACK; - reg_vif_num = vifcp->vifc_vifi; + (void *)&V_multicast_register_if); + if (V_reg_vif_num == VIFI_INVALID) { + if_initname(&V_multicast_register_if, "register_vif", 0); + V_multicast_register_if.if_flags = IFF_LOOPBACK; + V_reg_vif_num = vifcp->vifc_vifi; + IF_ADDR_LOCK_INIT(&V_multicast_register_if); +#ifdef VIMAGE + V_multicast_register_if.if_vnet = curvnet; + V_multicast_register_if.if_home_vnet = curvnet; +#endif /* VIMAGE */ } } else { /* Make sure the interface supports multicast */ if ((ifp->if_flags & IFF_MULTICAST) == 0) { @@ -988,11 +1048,11 @@ bzero(&vifp->v_route, sizeof(vifp->v_route)); /* Adjust numvifs up if the vifi is higher than numvifs */ - if (numvifs <= vifcp->vifc_vifi) numvifs = vifcp->vifc_vifi + 1; + if (V_numvifs <= vifcp->vifc_vifi) V_numvifs = vifcp->vifc_vifi + 1; VIF_UNLOCK(); - if (mrtdebug) + if (V_mrtdebug) log(LOG_DEBUG, "add_vif #%d, lcladdr %lx, %s %lx, thresh %x\n", vifcp->vifc_vifi, (u_long)ntohl(vifcp->vifc_lcl_addr.s_addr), @@ -1009,14 +1069,15 @@ static int del_vif_locked(vifi_t vifi) { + INIT_VNET_MROUTE(curvnet); struct vif *vifp; VIF_LOCK_ASSERT(); - if (vifi >= numvifs) { + if (vifi >= V_numvifs) { return EINVAL; } - vifp = &viftable[vifi]; + vifp = &V_viftable[vifi]; if (vifp->v_lcl_addr.s_addr == INADDR_ANY) { return EADDRNOTAVAIL; } @@ -1024,19 +1085,22 @@ if (!(vifp->v_flags & (VIFF_TUNNEL | VIFF_REGISTER))) if_allmulti(vifp->v_ifp, 0); - if (vifp->v_flags & VIFF_REGISTER) - reg_vif_num = VIFI_INVALID; + if (vifp->v_flags & VIFF_REGISTER) { + if (V_reg_vif_num != VIFI_INVALID) + IF_ADDR_LOCK_DESTROY(&V_multicast_register_if); + V_reg_vif_num = VIFI_INVALID; + } bzero((caddr_t)vifp, sizeof (*vifp)); - if (mrtdebug) - log(LOG_DEBUG, "del_vif %d, numvifs %d\n", vifi, numvifs); + if (V_mrtdebug) + log(LOG_DEBUG, "del_vif %d, numvifs %d\n", vifi, V_numvifs); /* Adjust numvifs down */ - for (vifi = numvifs; vifi > 0; vifi--) - if (viftable[vifi-1].v_lcl_addr.s_addr != INADDR_ANY) + for (vifi = V_numvifs; vifi > 0; vifi--) + if (V_viftable[vifi-1].v_lcl_addr.s_addr != INADDR_ANY) break; - numvifs = vifi; + V_numvifs = vifi; return 0; } @@ -1044,6 +1108,7 @@ static int del_vif(vifi_t vifi) { + INIT_VNET_MROUTE(curvnet); int cc; VIF_LOCK(); @@ -1059,16 +1124,17 @@ static void update_mfc_params(struct mfc *rt, struct mfcctl2 *mfccp) { + INIT_VNET_MROUTE(curvnet); int i; rt->mfc_parent = mfccp->mfcc_parent; - for (i = 0; i < numvifs; i++) { + for (i = 0; i < V_numvifs; i++) { rt->mfc_ttls[i] = mfccp->mfcc_ttls[i]; - rt->mfc_flags[i] = mfccp->mfcc_flags[i] & mrt_api_config & + rt->mfc_flags[i] = mfccp->mfcc_flags[i] & V_mrt_api_config & MRT_MFC_FLAGS_ALL; } /* set the RP address */ - if (mrt_api_config & MRT_MFC_RP) + if (V_mrt_api_config & MRT_MFC_RP) rt->mfc_rp = mfccp->mfcc_rp; else rt->mfc_rp.s_addr = INADDR_ANY; @@ -1099,6 +1165,7 @@ static int add_mfc(struct mfcctl2 *mfccp) { + INIT_VNET_MROUTE(curvnet); struct mfc *rt; u_long hash; struct rtdetq *rte; @@ -1111,7 +1178,7 @@ /* If an entry already exists, just update the fields */ if (rt) { - if (mrtdebug & DEBUG_MFC) + if (V_mrtdebug & DEBUG_MFC) log(LOG_DEBUG,"add_mfc update o %lx g %lx p %x\n", (u_long)ntohl(mfccp->mfcc_origin.s_addr), (u_long)ntohl(mfccp->mfcc_mcastgrp.s_addr), @@ -1127,7 +1194,7 @@ * Find the entry for which the upcall was made and update */ hash = MFCHASH(mfccp->mfcc_origin.s_addr, mfccp->mfcc_mcastgrp.s_addr); - for (rt = mfctable[hash], nstl = 0; rt; rt = rt->mfc_next) { + for (rt = V_mfctable[hash], nstl = 0; rt; rt = rt->mfc_next) { if ((rt->mfc_origin.s_addr == mfccp->mfcc_origin.s_addr) && (rt->mfc_mcastgrp.s_addr == mfccp->mfcc_mcastgrp.s_addr) && @@ -1140,7 +1207,7 @@ (u_long)ntohl(mfccp->mfcc_mcastgrp.s_addr), mfccp->mfcc_parent, (void *)rt->mfc_stall); - if (mrtdebug & DEBUG_MFC) + if (V_mrtdebug & DEBUG_MFC) log(LOG_DEBUG,"add_mfc o %lx g %lx p %x dbg %p\n", (u_long)ntohl(mfccp->mfcc_origin.s_addr), (u_long)ntohl(mfccp->mfcc_mcastgrp.s_addr), @@ -1149,7 +1216,7 @@ init_mfc_params(rt, mfccp); rt->mfc_expire = 0; /* Don't clean this guy up */ - nexpire[hash]--; + V_nexpire[hash]--; /* free packets Qed at the end of this entry */ for (rte = rt->mfc_stall; rte != NULL; ) { @@ -1168,18 +1235,18 @@ * It is possible that an entry is being inserted without an upcall */ if (nstl == 0) { - if (mrtdebug & DEBUG_MFC) + if (V_mrtdebug & DEBUG_MFC) log(LOG_DEBUG,"add_mfc no upcall h %lu o %lx g %lx p %x\n", hash, (u_long)ntohl(mfccp->mfcc_origin.s_addr), (u_long)ntohl(mfccp->mfcc_mcastgrp.s_addr), mfccp->mfcc_parent); - for (rt = mfctable[hash]; rt != NULL; rt = rt->mfc_next) { + for (rt = V_mfctable[hash]; rt != NULL; rt = rt->mfc_next) { if ((rt->mfc_origin.s_addr == mfccp->mfcc_origin.s_addr) && (rt->mfc_mcastgrp.s_addr == mfccp->mfcc_mcastgrp.s_addr)) { init_mfc_params(rt, mfccp); if (rt->mfc_expire) - nexpire[hash]--; + V_nexpire[hash]--; rt->mfc_expire = 0; break; /* XXX */ } @@ -1198,8 +1265,8 @@ rt->mfc_bw_meter = NULL; /* insert new entry at head of hash chain */ - rt->mfc_next = mfctable[hash]; - mfctable[hash] = rt; + rt->mfc_next = V_mfctable[hash]; + V_mfctable[hash] = rt; } } MFC_UNLOCK(); @@ -1213,6 +1280,7 @@ static int del_mfc(struct mfcctl2 *mfccp) { + INIT_VNET_MROUTE(curvnet); struct in_addr origin; struct in_addr mcastgrp; struct mfc *rt; @@ -1223,14 +1291,14 @@ origin = mfccp->mfcc_origin; mcastgrp = mfccp->mfcc_mcastgrp; - if (mrtdebug & DEBUG_MFC) + if (V_mrtdebug & DEBUG_MFC) log(LOG_DEBUG,"del_mfc orig %lx mcastgrp %lx\n", (u_long)ntohl(origin.s_addr), (u_long)ntohl(mcastgrp.s_addr)); MFC_LOCK(); hash = MFCHASH(origin.s_addr, mcastgrp.s_addr); - for (nptr = &mfctable[hash]; (rt = *nptr) != NULL; nptr = &rt->mfc_next) + for (nptr = &V_mfctable[hash]; (rt = *nptr) != NULL; nptr = &rt->mfc_next) if (origin.s_addr == rt->mfc_origin.s_addr && mcastgrp.s_addr == rt->mfc_mcastgrp.s_addr && rt->mfc_stall == NULL) @@ -1294,11 +1362,12 @@ struct ip_moptions *imo) { INIT_VNET_INET(curvnet); + INIT_VNET_MROUTE(curvnet); struct mfc *rt; int error; vifi_t vifi; - if (mrtdebug & DEBUG_FORWARD) + if (V_mrtdebug & DEBUG_FORWARD) log(LOG_DEBUG, "ip_mforward: src %lx, dst %lx, ifp %p\n", (u_long)ntohl(ip->ip_src.s_addr), (u_long)ntohl(ip->ip_dst.s_addr), (void *)ifp); @@ -1326,11 +1395,11 @@ VIF_LOCK(); MFC_LOCK(); - if (imo && ((vifi = imo->imo_multicast_vif) < numvifs)) { + if (imo && ((vifi = imo->imo_multicast_vif) < V_numvifs)) { if (ip->ip_ttl < MAXTTL) ip->ip_ttl++; /* compensate for -1 in *_send routines */ - if (rsvpdebug && ip->ip_p == IPPROTO_RSVP) { - struct vif *vifp = viftable + vifi; + if (V_rsvpdebug && ip->ip_p == IPPROTO_RSVP) { + struct vif *vifp = V_viftable + vifi; printf("Sending IPPROTO_RSVP from %lx to %lx on vif %d (%s%s)\n", (long)ntohl(ip->ip_src.s_addr), (long)ntohl(ip->ip_dst.s_addr), @@ -1343,7 +1412,7 @@ VIF_UNLOCK(); return error; } - if (rsvpdebug && ip->ip_p == IPPROTO_RSVP) { + if (V_rsvpdebug && ip->ip_p == IPPROTO_RSVP) { printf("Warning: IPPROTO_RSVP from %lx to %lx without vif option\n", (long)ntohl(ip->ip_src.s_addr), (long)ntohl(ip->ip_dst.s_addr)); if (!imo) @@ -1363,7 +1432,7 @@ /* * Determine forwarding vifs from the forwarding cache table */ - ++mrtstat.mrts_mfc_lookups; + ++V_mrtstat.mrts_mfc_lookups; rt = mfc_find(ip->ip_src.s_addr, ip->ip_dst.s_addr); /* Entry exists, so forward if necessary */ @@ -1383,10 +1452,10 @@ u_long hash; int hlen = ip->ip_hl << 2; - ++mrtstat.mrts_mfc_misses; + ++V_mrtstat.mrts_mfc_misses; - mrtstat.mrts_no_route++; - if (mrtdebug & (DEBUG_FORWARD | DEBUG_MFC)) + V_mrtstat.mrts_no_route++; + if (V_mrtdebug & (DEBUG_FORWARD | DEBUG_MFC)) log(LOG_DEBUG, "ip_mforward: no rte s %lx g %lx\n", (u_long)ntohl(ip->ip_src.s_addr), (u_long)ntohl(ip->ip_dst.s_addr)); @@ -1414,7 +1483,7 @@ /* is there an upcall waiting for this flow ? */ hash = MFCHASH(ip->ip_src.s_addr, ip->ip_dst.s_addr); - for (rt = mfctable[hash]; rt; rt = rt->mfc_next) { + for (rt = V_mfctable[hash]; rt; rt = rt->mfc_next) { if ((ip->ip_src.s_addr == rt->mfc_origin.s_addr) && (ip->ip_dst.s_addr == rt->mfc_mcastgrp.s_addr) && (rt->mfc_stall != NULL)) @@ -1431,9 +1500,9 @@ * Locate the vifi for the incoming interface for this packet. * If none found, drop packet. */ - for (vifi=0; vifi < numvifs && viftable[vifi].v_ifp != ifp; vifi++) + for (vifi=0; vifi < V_numvifs && V_viftable[vifi].v_ifp != ifp; vifi++) ; - if (vifi >= numvifs) /* vif not found, drop packet */ + if (vifi >= V_numvifs) /* vif not found, drop packet */ goto non_fatal; /* no upcall, so make a new entry */ @@ -1455,12 +1524,12 @@ im->im_mbz = 0; im->im_vif = vifi; - mrtstat.mrts_upcalls++; + V_mrtstat.mrts_upcalls++; k_igmpsrc.sin_addr = ip->ip_src; if (socket_send(V_ip_mrouter, mm, &k_igmpsrc) < 0) { log(LOG_WARNING, "ip_mforward: ip_mrouter socket queue full\n"); - ++mrtstat.mrts_upq_sockfull; + ++V_mrtstat.mrts_upq_sockfull; fail1: free(rt, M_MRTABLE); fail: @@ -1475,8 +1544,8 @@ rt->mfc_origin.s_addr = ip->ip_src.s_addr; rt->mfc_mcastgrp.s_addr = ip->ip_dst.s_addr; rt->mfc_expire = UPCALL_EXPIRE; - nexpire[hash]++; - for (i = 0; i < numvifs; i++) { + V_nexpire[hash]++; + for (i = 0; i < V_numvifs; i++) { rt->mfc_ttls[i] = 0; rt->mfc_flags[i] = 0; } @@ -1487,8 +1556,8 @@ rt->mfc_bw_meter = NULL; /* link into table */ - rt->mfc_next = mfctable[hash]; - mfctable[hash] = rt; + rt->mfc_next = V_mfctable[hash]; + V_mfctable[hash] = rt; rt->mfc_stall = rte; } else { @@ -1505,7 +1574,7 @@ npkts++; if (npkts > MAX_UPQ) { - mrtstat.mrts_upq_ovflw++; + V_mrtstat.mrts_upq_ovflw++; non_fatal: free(rte, M_MRTABLE); m_freem(mb0); @@ -1535,15 +1604,16 @@ static void expire_upcalls(void *unused) { + INIT_VNET_MROUTE( ((struct vnet *)unused) ); struct rtdetq *rte; struct mfc *mfc, **nptr; int i; MFC_LOCK(); for (i = 0; i < MFCTBLSIZ; i++) { - if (nexpire[i] == 0) + if (V_nexpire[i] == 0) continue; - nptr = &mfctable[i]; + nptr = &V_mfctable[i]; for (mfc = *nptr; mfc != NULL; mfc = *nptr) { /* * Skip real cache entries @@ -1552,7 +1622,7 @@ */ if (mfc->mfc_stall != NULL && mfc->mfc_expire != 0 && --mfc->mfc_expire == 0) { - if (mrtdebug & DEBUG_EXPIRE) + if (V_mrtdebug & DEBUG_EXPIRE) log(LOG_DEBUG, "expire_upcalls: expiring (%lx %lx)\n", (u_long)ntohl(mfc->mfc_origin.s_addr), (u_long)ntohl(mfc->mfc_mcastgrp.s_addr)); @@ -1567,8 +1637,8 @@ free(rte, M_MRTABLE); rte = n; } - ++mrtstat.mrts_cache_cleanups; - nexpire[i]--; + ++V_mrtstat.mrts_cache_cleanups; + V_nexpire[i]--; /* * free the bw_meter entries @@ -1587,9 +1657,8 @@ } } } + callout_reset(&V_expire_upcalls_ch, EXPIRE_TIMEOUT, expire_upcalls, unused); MFC_UNLOCK(); - - callout_reset(&expire_upcalls_ch, EXPIRE_TIMEOUT, expire_upcalls, NULL); } /* @@ -1599,6 +1668,7 @@ ip_mdq(struct mbuf *m, struct ifnet *ifp, struct mfc *rt, vifi_t xmt_vif) { INIT_VNET_INET(curvnet); + INIT_VNET_MROUTE(curvnet); struct ip *ip = mtod(m, struct ip *); vifi_t vifi; int plen = ip->ip_len; @@ -1610,11 +1680,11 @@ * * (since vifi_t is u_short, -1 becomes MAXUSHORT, which > numvifs.) */ - if (xmt_vif < numvifs) { - if (viftable[xmt_vif].v_flags & VIFF_REGISTER) - pim_register_send(ip, viftable + xmt_vif, m, rt); + if (xmt_vif < V_numvifs) { + if (V_viftable[xmt_vif].v_flags & VIFF_REGISTER) + pim_register_send(ip, V_viftable + xmt_vif, m, rt); else - phyint_send(ip, viftable + xmt_vif, m); + phyint_send(ip, V_viftable + xmt_vif, m); return 1; } @@ -1622,12 +1692,12 @@ * Don't forward if it didn't arrive from the parent vif for its origin. */ vifi = rt->mfc_parent; - if ((vifi >= numvifs) || (viftable[vifi].v_ifp != ifp)) { + if ((vifi >= V_numvifs) || (V_viftable[vifi].v_ifp != ifp)) { /* came in the wrong interface */ - if (mrtdebug & DEBUG_FORWARD) + if (V_mrtdebug & DEBUG_FORWARD) log(LOG_DEBUG, "wrong if: ifp %p vifi %d vififp %p\n", - (void *)ifp, vifi, (void *)viftable[vifi].v_ifp); - ++mrtstat.mrts_wrong_if; + (void *)ifp, vifi, (void *)V_viftable[vifi].v_ifp); + ++V_mrtstat.mrts_wrong_if; ++rt->mfc_wrong_if; /* * If we are doing PIM assert processing, send a message @@ -1637,17 +1707,18 @@ * can complete the SPT switch, regardless of the type * of the iif (broadcast media, GRE tunnel, etc). */ - if (pim_assert && (vifi < numvifs) && viftable[vifi].v_ifp) { + if (V_pim_assert && (vifi < V_numvifs) && V_viftable[vifi].v_ifp) { struct timeval now; u_long delta; - if (ifp == &multicast_register_if) - pimstat.pims_rcv_registers_wrongiif++; + if (ifp == &V_multicast_register_if) + V_pimstat.pims_rcv_registers_wrongiif++; /* Get vifi for the incoming packet */ - for (vifi=0; vifi < numvifs && viftable[vifi].v_ifp != ifp; vifi++) + for (vifi=0; vifi < V_numvifs && V_viftable[vifi].v_ifp != ifp; + vifi++) ; - if (vifi >= numvifs) + if (vifi >= V_numvifs) return 0; /* The iif is not found: ignore the packet. */ if (rt->mfc_flags[vifi] & MRT_MFC_FLAGS_DISABLE_WRONGVIF) @@ -1675,13 +1746,13 @@ im->im_mbz = 0; im->im_vif = vifi; - mrtstat.mrts_upcalls++; + V_mrtstat.mrts_upcalls++; k_igmpsrc.sin_addr = im->im_src; if (socket_send(V_ip_mrouter, mm, &k_igmpsrc) < 0) { log(LOG_WARNING, "ip_mforward: ip_mrouter socket queue full\n"); - ++mrtstat.mrts_upq_sockfull; + ++V_mrtstat.mrts_upq_sockfull; return ENOBUFS; } } @@ -1690,12 +1761,12 @@ } /* If I sourced this packet, it counts as output, else it was input. */ - if (ip->ip_src.s_addr == viftable[vifi].v_lcl_addr.s_addr) { - viftable[vifi].v_pkt_out++; - viftable[vifi].v_bytes_out += plen; + if (ip->ip_src.s_addr == V_viftable[vifi].v_lcl_addr.s_addr) { + V_viftable[vifi].v_pkt_out++; + V_viftable[vifi].v_bytes_out += plen; } else { - viftable[vifi].v_pkt_in++; - viftable[vifi].v_bytes_in += plen; + V_viftable[vifi].v_pkt_in++; + V_viftable[vifi].v_bytes_in += plen; } rt->mfc_pkt_cnt++; rt->mfc_byte_cnt += plen; @@ -1706,14 +1777,14 @@ * - the ttl exceeds the vif's threshold * - there are group members downstream on interface */ - for (vifi = 0; vifi < numvifs; vifi++) + for (vifi = 0; vifi < V_numvifs; vifi++) if ((rt->mfc_ttls[vifi] > 0) && (ip->ip_ttl > rt->mfc_ttls[vifi])) { - viftable[vifi].v_pkt_out++; - viftable[vifi].v_bytes_out += plen; - if (viftable[vifi].v_flags & VIFF_REGISTER) - pim_register_send(ip, viftable + vifi, m, rt); + V_viftable[vifi].v_pkt_out++; + V_viftable[vifi].v_bytes_out += plen; + if (V_viftable[vifi].v_flags & VIFF_REGISTER) + pim_register_send(ip, V_viftable + vifi, m, rt); else - phyint_send(ip, viftable + vifi, m); + phyint_send(ip, V_viftable + vifi, m); } /* @@ -1738,8 +1809,9 @@ static int X_legal_vif_num(int vif) { + INIT_VNET_MROUTE(curvnet); /* XXX unlocked, matter? */ - return (vif >= 0 && vif < numvifs); + return (vif >= 0 && vif < V_numvifs); } /* @@ -1748,9 +1820,10 @@ static u_long X_ip_mcast_src(int vifi) { + INIT_VNET_MROUTE(curvnet); /* XXX unlocked, matter? */ - if (vifi >= 0 && vifi < numvifs) - return viftable[vifi].v_lcl_addr.s_addr; + if (vifi >= 0 && vifi < V_numvifs) + return V_viftable[vifi].v_lcl_addr.s_addr; else return INADDR_ANY; } @@ -1780,6 +1853,7 @@ static void send_packet(struct vif *vifp, struct mbuf *m) { + INIT_VNET_MROUTE(curvnet); struct ip_moptions imo; struct in_multi *imm[2]; int error; @@ -1801,16 +1875,17 @@ * the loopback interface, thus preventing looping. */ error = ip_output(m, NULL, &vifp->v_route, IP_FORWARDING, &imo, NULL); - if (mrtdebug & DEBUG_XMIT) { + if (V_mrtdebug & DEBUG_XMIT) { log(LOG_DEBUG, "phyint_send on vif %td err %d\n", - vifp - viftable, error); + vifp - V_viftable, error); } } static int X_ip_rsvp_vif(struct socket *so, struct sockopt *sopt) { - INIT_VNET_INET(curvnet); + INIT_VNET_INET(so->so_vnet); + INIT_VNET_MROUTE(so->so_vnet); int error, vifi; if (so->so_type != SOCK_RAW || so->so_proto->pr_protocol != IPPROTO_RSVP) @@ -1822,39 +1897,39 @@ VIF_LOCK(); - if (vifi < 0 || vifi >= numvifs) { /* Error if vif is invalid */ + if (vifi < 0 || vifi >= V_numvifs) { /* Error if vif is invalid */ VIF_UNLOCK(); return EADDRNOTAVAIL; } if (sopt->sopt_name == IP_RSVP_VIF_ON) { /* Check if socket is available. */ - if (viftable[vifi].v_rsvpd != NULL) { + if (V_viftable[vifi].v_rsvpd != NULL) { VIF_UNLOCK(); return EADDRINUSE; } - viftable[vifi].v_rsvpd = so; + V_viftable[vifi].v_rsvpd = so; /* This may seem silly, but we need to be sure we don't over-increment * the RSVP counter, in case something slips up. */ - if (!viftable[vifi].v_rsvp_on) { - viftable[vifi].v_rsvp_on = 1; + if (!V_viftable[vifi].v_rsvp_on) { + V_viftable[vifi].v_rsvp_on = 1; V_rsvp_on++; } } else { /* must be VIF_OFF */ /* * XXX as an additional consistency check, one could make sure - * that viftable[vifi].v_rsvpd == so, otherwise passing so as + * that V_viftable[vifi].v_rsvpd == so, otherwise passing so as * first parameter is pretty useless. */ - viftable[vifi].v_rsvpd = NULL; + V_viftable[vifi].v_rsvpd = NULL; /* * This may seem silly, but we need to be sure we don't over-decrement * the RSVP counter, in case something slips up. */ - if (viftable[vifi].v_rsvp_on) { - viftable[vifi].v_rsvp_on = 0; + if (V_viftable[vifi].v_rsvp_on) { + V_viftable[vifi].v_rsvp_on = 0; V_rsvp_on--; } } @@ -1865,7 +1940,8 @@ static void X_ip_rsvp_force_done(struct socket *so) { - INIT_VNET_INET(curvnet); + INIT_VNET_INET(so->so_vnet); + INIT_VNET_MROUTE(so->so_vnet); int vifi; /* Don't bother if it is not the right type of socket. */ @@ -1877,14 +1953,14 @@ /* The socket may be attached to more than one vif...this * is perfectly legal. */ - for (vifi = 0; vifi < numvifs; vifi++) { - if (viftable[vifi].v_rsvpd == so) { - viftable[vifi].v_rsvpd = NULL; + for (vifi = 0; vifi < V_numvifs; vifi++) { + if (V_viftable[vifi].v_rsvpd == so) { + V_viftable[vifi].v_rsvpd = NULL; /* This may seem silly, but we need to be sure we don't * over-decrement the RSVP counter, in case something slips up. */ - if (viftable[vifi].v_rsvp_on) { - viftable[vifi].v_rsvp_on = 0; + if (V_viftable[vifi].v_rsvp_on) { + V_viftable[vifi].v_rsvp_on = 0; V_rsvp_on--; } } @@ -1897,12 +1973,13 @@ X_rsvp_input(struct mbuf *m, int off) { INIT_VNET_INET(curvnet); + INIT_VNET_MROUTE(curvnet); int vifi; struct ip *ip = mtod(m, struct ip *); struct sockaddr_in rsvp_src = { sizeof rsvp_src, AF_INET }; struct ifnet *ifp; - if (rsvpdebug) + if (V_rsvpdebug) printf("rsvp_input: rsvp_on %d\n", V_rsvp_on); /* Can still get packets with rsvp_on = 0 if there is a local member @@ -1914,7 +1991,7 @@ return; } - if (rsvpdebug) + if (V_rsvpdebug) printf("rsvp_input: check vifs\n"); #ifdef DIAGNOSTIC @@ -1925,14 +2002,14 @@ VIF_LOCK(); /* Find which vif the packet arrived on. */ - for (vifi = 0; vifi < numvifs; vifi++) - if (viftable[vifi].v_ifp == ifp) + for (vifi = 0; vifi < V_numvifs; vifi++) + if (V_viftable[vifi].v_ifp == ifp) break; - if (vifi == numvifs || viftable[vifi].v_rsvpd == NULL) { + if (vifi == V_numvifs || V_viftable[vifi].v_rsvpd == NULL) { /* * Drop the lock here to avoid holding it across rip_input. - * This could make rsvpdebug printfs wrong. If you care, + * This could make V_rsvpdebug printfs wrong. If you care, * record the state of stuff before dropping the lock. */ VIF_UNLOCK(); @@ -1942,13 +2019,13 @@ * is no specific socket for this vif. */ if (V_ip_rsvpd != NULL) { - if (rsvpdebug) + if (V_rsvpdebug) printf("rsvp_input: Sending packet up old-style socket\n"); rip_input(m, off); /* xxx */ } else { - if (rsvpdebug && vifi == numvifs) + if (V_rsvpdebug && vifi == V_numvifs) printf("rsvp_input: Can't find vif for packet.\n"); - else if (rsvpdebug && viftable[vifi].v_rsvpd == NULL) + else if (V_rsvpdebug && V_viftable[vifi].v_rsvpd == NULL) printf("rsvp_input: No socket defined for vif %d\n",vifi); m_freem(m); } @@ -1956,15 +2033,15 @@ } rsvp_src.sin_addr = ip->ip_src; - if (rsvpdebug && m) + if (V_rsvpdebug && m) printf("rsvp_input: m->m_len = %d, sbspace() = %ld\n", - m->m_len,sbspace(&(viftable[vifi].v_rsvpd->so_rcv))); + m->m_len,sbspace(&(V_viftable[vifi].v_rsvpd->so_rcv))); - if (socket_send(viftable[vifi].v_rsvpd, m, &rsvp_src) < 0) { - if (rsvpdebug) + if (socket_send(V_viftable[vifi].v_rsvpd, m, &rsvp_src) < 0) { + if (V_rsvpdebug) printf("rsvp_input: Failed to append to socket\n"); } else { - if (rsvpdebug) + if (V_rsvpdebug) printf("rsvp_input: send packet up\n"); } VIF_UNLOCK(); @@ -2004,6 +2081,7 @@ static int add_bw_upcall(struct bw_upcall *req) { + INIT_VNET_MROUTE(curvnet); struct mfc *mfc; struct timeval delta = { BW_UPCALL_THRESHOLD_INTERVAL_MIN_SEC, BW_UPCALL_THRESHOLD_INTERVAL_MIN_USEC }; @@ -2011,7 +2089,7 @@ struct bw_meter *x; uint32_t flags; - if (!(mrt_api_config & MRT_MFC_BW_UPCALL)) + if (!(V_mrt_api_config & MRT_MFC_BW_UPCALL)) return EOPNOTSUPP; /* Test if the flags are valid */ @@ -2096,10 +2174,11 @@ static int del_bw_upcall(struct bw_upcall *req) { + INIT_VNET_MROUTE(curvnet); struct mfc *mfc; struct bw_meter *x; - if (!(mrt_api_config & MRT_MFC_BW_UPCALL)) + if (!(V_mrt_api_config & MRT_MFC_BW_UPCALL)) return EOPNOTSUPP; MFC_LOCK(); @@ -2252,6 +2331,7 @@ static void bw_meter_prepare_upcall(struct bw_meter *x, struct timeval *nowp) { + INIT_VNET_MROUTE(curvnet); struct timeval delta; struct bw_upcall *u; @@ -2266,13 +2346,13 @@ /* * If there are too many pending upcalls, deliver them now */ - if (bw_upcalls_n >= BW_UPCALLS_MAX) + if (V_bw_upcalls_n >= BW_UPCALLS_MAX) bw_upcalls_send(); /* * Set the bw_upcall entry */ - u = &bw_upcalls[bw_upcalls_n++]; + u = &V_bw_upcalls[V_bw_upcalls_n++]; u->bu_src = x->bm_mfc->mfc_origin; u->bu_dst = x->bm_mfc->mfc_mcastgrp; u->bu_threshold.b_time = x->bm_threshold.b_time; @@ -2299,8 +2379,9 @@ bw_upcalls_send(void) { INIT_VNET_INET(curvnet); + INIT_VNET_MROUTE(curvnet); struct mbuf *m; - int len = bw_upcalls_n * sizeof(bw_upcalls[0]); + int len = V_bw_upcalls_n * sizeof(V_bw_upcalls[0]); struct sockaddr_in k_igmpsrc = { sizeof k_igmpsrc, AF_INET }; static struct igmpmsg igmpmsg = { 0, /* unused1 */ 0, /* unused2 */ @@ -2313,10 +2394,10 @@ MFC_LOCK_ASSERT(); - if (bw_upcalls_n == 0) + if (V_bw_upcalls_n == 0) return; /* No pending upcalls */ - bw_upcalls_n = 0; + V_bw_upcalls_n = 0; /* * Allocate a new mbuf, initialize it with the header and @@ -2330,16 +2411,16 @@ m->m_len = m->m_pkthdr.len = 0; m_copyback(m, 0, sizeof(struct igmpmsg), (caddr_t)&igmpmsg); - m_copyback(m, sizeof(struct igmpmsg), len, (caddr_t)&bw_upcalls[0]); + m_copyback(m, sizeof(struct igmpmsg), len, (caddr_t)&V_bw_upcalls[0]); /* * Send the upcalls * XXX do we need to set the address in k_igmpsrc ? */ - mrtstat.mrts_upcalls++; + V_mrtstat.mrts_upcalls++; if (socket_send(V_ip_mrouter, m, &k_igmpsrc) < 0) { log(LOG_WARNING, "bw_upcalls_send: ip_mrouter socket queue full\n"); - ++mrtstat.mrts_upq_sockfull; + ++V_mrtstat.mrts_upq_sockfull; } } @@ -2364,6 +2445,7 @@ static void schedule_bw_meter(struct bw_meter *x, struct timeval *nowp) { + INIT_VNET_MROUTE(curvnet); int time_hash; MFC_LOCK_ASSERT(); @@ -2383,8 +2465,8 @@ * Compute the timeout hash value and insert the entry */ BW_METER_TIMEHASH(x, time_hash); - x->bm_time_next = bw_meter_timers[time_hash]; - bw_meter_timers[time_hash] = x; + x->bm_time_next = V_bw_meter_timers[time_hash]; + V_bw_meter_timers[time_hash] = x; x->bm_time_hash = time_hash; } @@ -2395,6 +2477,7 @@ static void unschedule_bw_meter(struct bw_meter *x) { + INIT_VNET_MROUTE(curvnet); int time_hash; struct bw_meter *prev, *tmp; @@ -2410,7 +2493,7 @@ if (time_hash >= BW_METER_BUCKETS) return; /* Entry was not scheduled */ - for (prev = NULL, tmp = bw_meter_timers[time_hash]; + for (prev = NULL, tmp = V_bw_meter_timers[time_hash]; tmp != NULL; prev = tmp, tmp = tmp->bm_time_next) if (tmp == x) break; @@ -2421,7 +2504,7 @@ if (prev != NULL) prev->bm_time_next = x->bm_time_next; else - bw_meter_timers[time_hash] = x->bm_time_next; + V_bw_meter_timers[time_hash] = x->bm_time_next; x->bm_time_next = NULL; x->bm_time_hash = BW_METER_BUCKETS; @@ -2438,8 +2521,9 @@ * looking at. */ static void -bw_meter_process() +bw_meter_process(struct vnet *vnet) { + INIT_VNET_MROUTE(vnet); static uint32_t last_tv_sec; /* last time we processed this */ uint32_t loops; @@ -2456,6 +2540,7 @@ loops = BW_METER_BUCKETS; MFC_LOCK(); + CURVNET_SET(vnet); /* * Process all bins of bw_meter entries from the one after the last * processed to the current one. On entry, i points to the last bucket @@ -2468,8 +2553,8 @@ i = 0; /* Disconnect the list of bw_meter entries from the bin */ - tmp_list = bw_meter_timers[i]; - bw_meter_timers[i] = NULL; + tmp_list = V_bw_meter_timers[i]; + V_bw_meter_timers[i] = NULL; /* Process the list of bw_meter entries */ while (tmp_list != NULL) { @@ -2492,8 +2577,8 @@ if (++time_hash >= BW_METER_BUCKETS) time_hash = 0; } - x->bm_time_next = bw_meter_timers[time_hash]; - bw_meter_timers[time_hash] = x; + x->bm_time_next = V_bw_meter_timers[time_hash]; + V_bw_meter_timers[time_hash] = x; x->bm_time_hash = time_hash; continue; @@ -2520,6 +2605,7 @@ /* Send all upcalls that are pending delivery */ bw_upcalls_send(); + CURVNET_RESTORE(); MFC_UNLOCK(); } @@ -2529,12 +2615,14 @@ static void expire_bw_upcalls_send(void *unused) { + INIT_VNET_MROUTE( (struct vnet *)unused ); MFC_LOCK(); + CURVNET_SET( (struct vnet*)unused ); bw_upcalls_send(); + callout_reset(&V_bw_upcalls_ch, BW_UPCALLS_PERIOD, + expire_bw_upcalls_send, unused); + CURVNET_RESTORE(); MFC_UNLOCK(); - - callout_reset(&bw_upcalls_ch, BW_UPCALLS_PERIOD, - expire_bw_upcalls_send, NULL); } /* @@ -2544,10 +2632,12 @@ static void expire_bw_meter_process(void *unused) { - if (mrt_api_config & MRT_MFC_BW_UPCALL) - bw_meter_process(); + INIT_VNET_MROUTE( (struct vnet *)unused ); + if (V_mrt_api_config & MRT_MFC_BW_UPCALL) + bw_meter_process( (struct vnet *)unused ); - callout_reset(&bw_meter_ch, BW_METER_PERIOD, expire_bw_meter_process, NULL); + callout_reset(&V_bw_meter_ch, BW_METER_PERIOD, + expire_bw_meter_process, unused); } /* @@ -2562,16 +2652,17 @@ pim_register_send(struct ip *ip, struct vif *vifp, struct mbuf *m, struct mfc *rt) { + INIT_VNET_MROUTE(curvnet); struct mbuf *mb_copy, *mm; - if (mrtdebug & DEBUG_PIM) + if (V_mrtdebug & DEBUG_PIM) log(LOG_DEBUG, "pim_register_send: "); /* * Do not send IGMP_WHOLEPKT notifications to userland, if the * rendezvous point was unspecified, and we were told not to. */ - if (pim_squelch_wholepkt != 0 && (mrt_api_config & MRT_MFC_RP) && + if (pim_squelch_wholepkt != 0 && (V_mrt_api_config & MRT_MFC_RP) && (rt->mfc_rp.s_addr == INADDR_ANY)) return 0; @@ -2589,7 +2680,7 @@ mm = m_pullup(mm, sizeof(struct ip)); if (mm != NULL) { ip = mtod(mm, struct ip *); - if ((mrt_api_config & MRT_MFC_RP) && + if ((V_mrt_api_config & MRT_MFC_RP) && (rt->mfc_rp.s_addr != INADDR_ANY)) { pim_register_send_rp(ip, vifp, mm, rt); } else { @@ -2660,6 +2751,7 @@ struct mbuf *mb_copy, struct mfc *rt) { INIT_VNET_INET(curvnet); + INIT_VNET_MROUTE(curvnet); struct mbuf *mb_first; int len = ntohs(ip->ip_len); struct igmpmsg *im; @@ -2684,25 +2776,25 @@ im = mtod(mb_first, struct igmpmsg *); im->im_msgtype = IGMPMSG_WHOLEPKT; im->im_mbz = 0; - im->im_vif = vifp - viftable; + im->im_vif = vifp - V_viftable; im->im_src = ip->ip_src; im->im_dst = ip->ip_dst; k_igmpsrc.sin_addr = ip->ip_src; - mrtstat.mrts_upcalls++; + V_mrtstat.mrts_upcalls++; if (socket_send(V_ip_mrouter, mb_first, &k_igmpsrc) < 0) { - if (mrtdebug & DEBUG_PIM) + if (V_mrtdebug & DEBUG_PIM) log(LOG_WARNING, "mcast: pim_register_send_upcall: ip_mrouter socket queue full"); - ++mrtstat.mrts_upq_sockfull; + ++V_mrtstat.mrts_upq_sockfull; return ENOBUFS; } /* Keep statistics */ - pimstat.pims_snd_registers_msgs++; - pimstat.pims_snd_registers_bytes += len; + V_pimstat.pims_snd_registers_msgs++; + V_pimstat.pims_snd_registers_bytes += len; return 0; } @@ -2715,6 +2807,7 @@ struct mfc *rt) { INIT_VNET_INET(curvnet); + INIT_VNET_MROUTE(curvnet); struct mbuf *mb_first; struct ip *ip_outer; struct pim_encap_pimhdr *pimhdr; @@ -2723,7 +2816,7 @@ VIF_LOCK_ASSERT(); - if ((vifi >= numvifs) || (viftable[vifi].v_lcl_addr.s_addr == 0)) { + if ((vifi >= V_numvifs) || (V_viftable[vifi].v_lcl_addr.s_addr == 0)) { m_freem(mb_copy); return EADDRNOTAVAIL; /* The iif vif is invalid */ } @@ -2749,7 +2842,7 @@ *ip_outer = pim_encap_iphdr; ip_outer->ip_id = ip_newid(); ip_outer->ip_len = len + sizeof(pim_encap_iphdr) + sizeof(pim_encap_pimhdr); - ip_outer->ip_src = viftable[vifi].v_lcl_addr; + ip_outer->ip_src = V_viftable[vifi].v_lcl_addr; ip_outer->ip_dst = rt->mfc_rp; /* * Copy the inner header TOS to the outer header, and take care of the @@ -2762,7 +2855,7 @@ + sizeof(pim_encap_iphdr)); *pimhdr = pim_encap_pimhdr; /* If the iif crosses a border, set the Border-bit */ - if (rt->mfc_flags[vifi] & MRT_MFC_FLAGS_BORDER_VIF & mrt_api_config) + if (rt->mfc_flags[vifi] & MRT_MFC_FLAGS_BORDER_VIF & V_mrt_api_config) pimhdr->flags |= htonl(PIM_BORDER_REGISTER); mb_first->m_data += sizeof(pim_encap_iphdr); @@ -2772,8 +2865,8 @@ send_packet(vifp, mb_first); /* Keep statistics */ - pimstat.pims_snd_registers_msgs++; - pimstat.pims_snd_registers_bytes += len; + V_pimstat.pims_snd_registers_msgs++; + V_pimstat.pims_snd_registers_bytes += len; return 0; } @@ -2807,6 +2900,7 @@ void pim_input(struct mbuf *m, int off) { + INIT_VNET_MROUTE(curvnet); struct ip *ip = mtod(m, struct ip *); struct pim *pim; int minlen; @@ -2815,14 +2909,14 @@ int iphlen = off; /* Keep statistics */ - pimstat.pims_rcv_total_msgs++; - pimstat.pims_rcv_total_bytes += datalen; + V_pimstat.pims_rcv_total_msgs++; + V_pimstat.pims_rcv_total_bytes += datalen; /* * Validate lengths */ if (datalen < PIM_MINLEN) { - pimstat.pims_rcv_tooshort++; + V_pimstat.pims_rcv_tooshort++; log(LOG_ERR, "pim_input: packet size too small %d from %lx\n", datalen, (u_long)ip->ip_src.s_addr); m_freem(m); @@ -2866,8 +2960,8 @@ if (PIM_VT_T(pim->pim_vt) == PIM_REGISTER && in_cksum(m, PIM_MINLEN) == 0) { /* do nothing, checksum okay */ } else if (in_cksum(m, datalen)) { - pimstat.pims_rcv_badsum++; - if (mrtdebug & DEBUG_PIM) + V_pimstat.pims_rcv_badsum++; + if (V_mrtdebug & DEBUG_PIM) log(LOG_DEBUG, "pim_input: invalid checksum"); m_freem(m); return; @@ -2875,7 +2969,7 @@ /* PIM version check */ if (PIM_VT_V(pim->pim_vt) < PIM_VERSION) { - pimstat.pims_rcv_badversion++; + V_pimstat.pims_rcv_badversion++; log(LOG_ERR, "pim_input: incorrect version %d, expecting %d\n", PIM_VT_V(pim->pim_vt), PIM_VERSION); m_freem(m); @@ -2899,24 +2993,24 @@ struct ifnet *vifp; VIF_LOCK(); - if ((reg_vif_num >= numvifs) || (reg_vif_num == VIFI_INVALID)) { + if ((V_reg_vif_num >= V_numvifs) || (V_reg_vif_num == VIFI_INVALID)) { VIF_UNLOCK(); - if (mrtdebug & DEBUG_PIM) + if (V_mrtdebug & DEBUG_PIM) log(LOG_DEBUG, - "pim_input: register vif not set: %d\n", reg_vif_num); + "pim_input: register vif not set: %d\n", V_reg_vif_num); m_freem(m); return; } /* XXX need refcnt? */ - vifp = viftable[reg_vif_num].v_ifp; + vifp = V_viftable[V_reg_vif_num].v_ifp; VIF_UNLOCK(); /* * Validate length */ if (datalen < PIM_REG_MINLEN) { - pimstat.pims_rcv_tooshort++; - pimstat.pims_rcv_badregisters++; + V_pimstat.pims_rcv_tooshort++; + V_pimstat.pims_rcv_badregisters++; log(LOG_ERR, "pim_input: register packet size too small %d from %lx\n", datalen, (u_long)ip->ip_src.s_addr); @@ -2927,7 +3021,7 @@ reghdr = (u_int32_t *)(pim + 1); encap_ip = (struct ip *)(reghdr + 1); - if (mrtdebug & DEBUG_PIM) { + if (V_mrtdebug & DEBUG_PIM) { log(LOG_DEBUG, "pim_input[register], encap_ip: %lx -> %lx, encap_ip len %d\n", (u_long)ntohl(encap_ip->ip_src.s_addr), @@ -2937,8 +3031,8 @@ /* verify the version number of the inner packet */ if (encap_ip->ip_v != IPVERSION) { - pimstat.pims_rcv_badregisters++; - if (mrtdebug & DEBUG_PIM) { + V_pimstat.pims_rcv_badregisters++; + if (V_mrtdebug & DEBUG_PIM) { log(LOG_DEBUG, "pim_input: invalid IP version (%d) " "of the inner packet\n", encap_ip->ip_v); } @@ -2948,8 +3042,8 @@ /* verify the inner packet is destined to a mcast group */ if (!IN_MULTICAST(ntohl(encap_ip->ip_dst.s_addr))) { - pimstat.pims_rcv_badregisters++; - if (mrtdebug & DEBUG_PIM) + V_pimstat.pims_rcv_badregisters++; + if (V_mrtdebug & DEBUG_PIM) log(LOG_DEBUG, "pim_input: inner packet of register is not " "multicast %lx\n", @@ -3000,21 +3094,21 @@ /* Keep statistics */ /* XXX: registers_bytes include only the encap. mcast pkt */ - pimstat.pims_rcv_registers_msgs++; - pimstat.pims_rcv_registers_bytes += ntohs(encap_ip->ip_len); + V_pimstat.pims_rcv_registers_msgs++; + V_pimstat.pims_rcv_registers_bytes += ntohs(encap_ip->ip_len); /* * forward the inner ip packet; point m_data at the inner ip. */ m_adj(m, iphlen + PIM_MINLEN); - if (mrtdebug & DEBUG_PIM) { + if (V_mrtdebug & DEBUG_PIM) { log(LOG_DEBUG, "pim_input: forwarding decapsulated register: " "src %lx, dst %lx, vif %d\n", (u_long)ntohl(encap_ip->ip_src.s_addr), (u_long)ntohl(encap_ip->ip_dst.s_addr), - reg_vif_num); + V_reg_vif_num); } /* NB: vifp was collected above; can it change on us? */ if_simloop(vifp, m, dst.sin_family, 0); @@ -3037,6 +3131,41 @@ return; } +#ifdef VIMAGE +/* initialization for multicast routing state */ +static int +vnet_mroute_iattach(unused) + const void *unused; +{ + INIT_VNET_MROUTE(curvnet); + + V_reg_vif_num = VIFI_INVALID; + MROUTER_LOCK_INIT(); + MFC_LOCK_INIT(); + VIF_LOCK_INIT(); + ip_mrouter_reset(); + return 0; +} + +/* de-initialization for multicast routing state */ +static int +vnet_mroute_idetach(unused) + const void *unused; +{ + INIT_VNET_MROUTE(curvnet); + + X_ip_mrouter_done(); +#ifdef INET6 + X_ip6_mrouter_done(); +#endif + + VIF_LOCK_DESTROY(); + MFC_LOCK_DESTROY(); + MROUTER_LOCK_DESTROY(); + return 0; +} +#endif /* VIMAGE */ + /* * XXX: This is common code for dealing with initialization for both * the IPv4 and IPv6 multicast forwarding paths. It could do with cleanup. @@ -3045,12 +3174,15 @@ ip_mroute_modevent(module_t mod, int type, void *unused) { INIT_VNET_INET(curvnet); + INIT_VNET_INET6(curvnet); + INIT_VNET_MROUTE(curvnet); switch (type) { case MOD_LOAD: - MROUTER_LOCK_INIT(); - MFC_LOCK_INIT(); - VIF_LOCK_INIT(); - ip_mrouter_reset(); +#ifdef VIMAGE + vnet_mod_register(&vnet_mroute_modinfo); +#else + vnet_mroute_iattach(NULL); +#endif TUNABLE_ULONG_FETCH("net.inet.pim.squelch_wholepkt", &pim_squelch_wholepkt); @@ -3113,17 +3245,21 @@ */ if (V_ip_mrouter #ifdef INET6 - || ip6_mrouter + || V_ip6_mrouter #endif ) return EINVAL; +#ifdef VIMAGE + vnet_mod_deregister(&vnet_mroute_modinfo); +#else + vnet_mroute_idetach(NULL) +#endif #ifdef INET6 if (pim6_encap_cookie) { encap_detach(pim6_encap_cookie); pim6_encap_cookie = NULL; } - X_ip6_mrouter_done(); ip6_mforward = NULL; ip6_mrouter_done = NULL; ip6_mrouter_get = NULL; @@ -3135,7 +3271,6 @@ encap_detach(pim_encap_cookie); pim_encap_cookie = NULL; } - X_ip_mrouter_done(); ip_mcast_src = NULL; ip_mforward = NULL; ip_mrouter_done = NULL; @@ -3148,10 +3283,6 @@ legal_vif_num = NULL; mrt_ioctl = NULL; rsvp_input_p = NULL; - - VIF_LOCK_DESTROY(); - MFC_LOCK_DESTROY(); - MROUTER_LOCK_DESTROY(); break; default: diff -ur sys.20081015/netinet/ip_mroute.h sys/netinet/ip_mroute.h --- sys.20081015/netinet/ip_mroute.h 2008-08-16 16:29:19.000000000 -0700 +++ sys/netinet/ip_mroute.h 2008-11-05 13:21:08.000000000 -0800 @@ -52,6 +52,10 @@ * bandwidth metering and signaling. */ +#ifdef VIMAGE +#include /* struct pimstat */ +#endif + /* * Multicast Routing set/getsockopt commands. @@ -80,6 +84,9 @@ typedef u_long vifbitmap_t; typedef u_short vifi_t; /* type of a vif index */ #define ALL_VIFS (vifi_t)-1 +#ifdef VIMAGE +#define VIFI_INVALID ((vifi_t) -1) +#endif /* VIMAGE */ #define VIFM_SET(n, m) ((m) |= (1 << (n))) #define VIFM_CLR(n, m) ((m) &= ~(1 << (n))) @@ -205,6 +212,10 @@ #define BW_UPCALL_THRESHOLD_INTERVAL_MIN_SEC 3 #define BW_UPCALL_THRESHOLD_INTERVAL_MIN_USEC 0 +#ifdef VIMAGE +#define BW_METER_BUCKETS 1024 +#endif /* VIMAGE */ + /* * The kernel's multicast routing statistics. */ @@ -361,6 +372,62 @@ extern int (*ip_mrouter_done)(void); extern int (*mrt_ioctl)(int, caddr_t, int); +#ifdef VIMAGE +struct vnet_mroute { + /* from ip_mroute.c */ + u_int _rsvpdebug; + u_int _mrtdebug; + struct mrtstat _mrtstat; + struct mfc *_mfctable[MFCTBLSIZ]; + struct mtx _mrouter_mtx; + struct mtx _mfc_mtx; + struct vif _viftable[MAXVIFS]; + struct mtx _vif_mtx; + u_char _nexpire[MFCTBLSIZ]; + eventhandler_tag _if_detach_event_tag; + struct callout _expire_upcalls_ch; + struct bw_meter *_bw_meter_timers[BW_METER_BUCKETS]; + struct callout _bw_meter_ch; + struct bw_upcall _bw_upcalls[BW_UPCALLS_MAX]; + u_int _bw_upcalls_n; + struct callout _bw_upcalls_ch; + struct pimstat _pimstat; + struct ifnet _multicast_register_if; + vifi_t _reg_vif_num; + vifi_t _numvifs; + int _pim_assert; + uint32_t _mrt_api_config; +}; +#endif /* VIMAGE */ + +#define INIT_VNET_MROUTE(vnet) \ + INIT_FROM_VNET(vnet, VNET_MOD_MROUTE, struct vnet_mroute, vnet_mroute) + +#define VNET_MROUTE(sym) VSYM(vnet_mroute, sym) + +#define V_rsvpdebug VNET_MROUTE(rsvpdebug) +#define V_mrtdebug VNET_MROUTE(mrtdebug) +#define V_mrtstat VNET_MROUTE(mrtstat) +#define V_mfctable VNET_MROUTE(mfctable) +#define V_mrouter_mtx VNET_MROUTE(mrouter_mtx) +#define V_mfc_mtx VNET_MROUTE(mfc_mtx) +#define V_viftable VNET_MROUTE(viftable) +#define V_vif_mtx VNET_MROUTE(vif_mtx) +#define V_nexpire VNET_MROUTE(nexpire) +#define V_if_detach_event_tag VNET_MROUTE(if_detach_event_tag) +#define V_expire_upcalls_ch VNET_MROUTE(expire_upcalls_ch) +#define V_bw_meter_timers VNET_MROUTE(bw_meter_timers) +#define V_bw_meter_ch VNET_MROUTE(bw_meter_ch) +#define V_bw_upcalls VNET_MROUTE(bw_upcalls) +#define V_bw_upcalls_n VNET_MROUTE(bw_upcalls_n) +#define V_bw_upcalls_ch VNET_MROUTE(bw_upcalls_ch) +#define V_pimstat VNET_MROUTE(pimstat) +#define V_multicast_register_if VNET_MROUTE(multicast_register_if) +#define V_reg_vif_num VNET_MROUTE(reg_vif_num) +#define V_numvifs VNET_MROUTE(numvifs) +#define V_pim_assert VNET_MROUTE(pim_assert) +#define V_mrt_api_config VNET_MROUTE(mrt_api_config) + #endif /* _KERNEL */ #endif /* _NETINET_IP_MROUTE_H_ */ diff -ur sys.20081015/netinet/pim_var.h sys/netinet/pim_var.h --- sys.20081015/netinet/pim_var.h 2007-11-19 06:49:11.000000000 -0800 +++ sys/netinet/pim_var.h 2008-10-28 20:01:22.000000000 -0700 @@ -73,7 +73,9 @@ #ifdef _KERNEL void pim_input(struct mbuf *, int); +#ifdef SYSCTL_DECL SYSCTL_DECL(_net_inet_pim); #endif +#endif #endif /* _NETINET_PIM_VAR_H_ */ diff -ur sys.20081015/netinet/vinet.h sys/netinet/vinet.h --- sys.20081015/netinet/vinet.h 2007-11-19 09:09:38.000000000 -0800 +++ sys/netinet/vinet.h 2008-11-03 16:04:36.000000000 -0800 @@ -53,6 +53,9 @@ #include #include #include +#include +#include +#include struct vnet_inet { struct in_ifaddrhashhead *_in_ifaddrhashtbl; diff -ur sys.20081015/netinet6/ip6_input.c sys/netinet6/ip6_input.c --- sys.20081015/netinet6/ip6_input.c 2008-10-15 08:25:28.000000000 -0700 +++ sys/netinet6/ip6_input.c 2008-10-28 20:01:22.000000000 -0700 @@ -192,6 +192,20 @@ nd6_init(); frag6_init(); + V_ip6_mrouter_ver = 0; + V_ip6_mrouter = NULL; + bzero(&V_mrt6stat, sizeof(V_mrt6stat)); + bzero((caddr_t)V_mf6ctable, sizeof(V_mf6ctable)); + bzero((caddr_t)V_n6expire, sizeof(V_n6expire)); + bzero((caddr_t)V_mif6table, sizeof(V_mif6table)); + V_mrt6debug = 0; + V_multicast_register_if6 = NULL; + V_nummifs = 0; + V_reg_mif_num = (mifi_t)-1; + bzero(&V_pim6stat, sizeof(V_pim6stat)); + V_pim6 = 0; + bzero((caddr_t)V_upcall_data, sizeof(V_upcall_data)); + #ifdef VIMAGE /* Skip global initialization stuff for non-default instances. */ if (!IS_DEFAULT_VNET(curvnet)) @@ -507,7 +521,7 @@ IN6_LOOKUP_MULTI(ip6->ip6_dst, m->m_pkthdr.rcvif, in6m); if (in6m) ours = 1; - else if (!ip6_mrouter) { + else if (!V_ip6_mrouter) { V_ip6stat.ip6s_notmember++; V_ip6stat.ip6s_cantforward++; in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_discard); @@ -768,7 +782,7 @@ * ip6_mforward() returns a non-zero value, the packet * must be discarded, else it may be accepted below. */ - if (ip6_mrouter && ip6_mforward && + if (V_ip6_mrouter && ip6_mforward && ip6_mforward(ip6, m->m_pkthdr.rcvif, m)) { V_ip6stat.ip6s_cantforward++; m_freem(m); diff -ur sys.20081015/netinet6/ip6_mroute.c sys/netinet6/ip6_mroute.c --- sys.20081015/netinet6/ip6_mroute.c 2008-10-15 08:25:28.000000000 -0700 +++ sys/netinet6/ip6_mroute.c 2008-11-05 14:34:10.000000000 -0800 @@ -160,14 +160,17 @@ SYSCTL_DECL(_net_inet6_ip6); SYSCTL_NODE(_net_inet6, IPPROTO_PIM, pim, CTLFLAG_RW, 0, "PIM"); +#ifndef VIMAGE static struct mrt6stat mrt6stat; -SYSCTL_STRUCT(_net_inet6_ip6, OID_AUTO, mrt6stat, CTLFLAG_RW, - &mrt6stat, mrt6stat, +#endif /* !VIMAGE */ +SYSCTL_V_STRUCT(V_NET, vnet_inet6, _net_inet6_ip6, OID_AUTO, mrt6stat, + CTLFLAG_RW, mrt6stat, mrt6stat, "Multicast Routing Statistics (struct mrt6stat, netinet6/ip6_mroute.h)"); #define NO_RTE_FOUND 0x1 #define RTE_FOUND 0x2 +#ifndef VIMAGE static struct mf6c *mf6ctable[MF6CTBLSIZ]; SYSCTL_OPAQUE(_net_inet6_ip6, OID_AUTO, mf6ctable, CTLFLAG_RD, &mf6ctable, sizeof(mf6ctable), "S,*mf6ctable[MF6CTBLSIZ]", @@ -180,6 +183,7 @@ SYSCTL_OPAQUE(_net_inet6_ip6, OID_AUTO, mif6table, CTLFLAG_RD, &mif6table, sizeof(mif6table), "S,vif[MAXMIFS]", "Multicast Interfaces (struct mif[MAXMIFS], netinet6/ip6_mroute.h)"); +#endif /* !VIMAGE */ #ifdef MRT6DEBUG #ifndef VIMAGE @@ -199,7 +203,9 @@ #ifdef INET #ifdef MROUTING +#ifndef VIMAGE extern struct socket *ip_mrouter; +#endif /* !VIMAGE */ #endif #endif @@ -214,19 +220,23 @@ * only exist as a placeholder for multicast source * verification. */ +#ifndef VIMAGE static struct ifnet *multicast_register_if6; +#endif /* !VIMAGE */ #define ENCAP_HOPS 64 /* * Private variables. */ +#ifndef VIMAGE static mifi_t nummifs = 0; static mifi_t reg_mif_num = (mifi_t)-1; static struct pim6stat pim6stat; -SYSCTL_STRUCT(_net_inet6_pim, PIM6CTL_STATS, stats, CTLFLAG_RD, - &pim6stat, pim6stat, +#endif /* !VIMAGE */ +SYSCTL_V_STRUCT(V_NET, vnet_inet6, _net_inet6_pim, PIM6CTL_STATS, stats, + CTLFLAG_RD, pim6stat, pim6stat, "PIM Statistics (struct pim6stat, netinet6/pim_var.h)"); #ifndef VIMAGE @@ -245,9 +255,9 @@ * Find a route for a given origin IPv6 address and Multicast group address. */ #define MF6CFIND(o, g, rt) do { \ - struct mf6c *_rt = mf6ctable[MF6CHASH(o,g)]; \ + struct mf6c *_rt = V_mf6ctable[MF6CHASH(o,g)]; \ rt = NULL; \ - mrt6stat.mrt6s_mfc_lookups++; \ + V_mrt6stat.mrt6s_mfc_lookups++; \ while (_rt) { \ if (IN6_ARE_ADDR_EQUAL(&_rt->mf6c_origin.sin6_addr, &(o)) && \ IN6_ARE_ADDR_EQUAL(&_rt->mf6c_mcastgrp.sin6_addr, &(g)) && \ @@ -258,7 +268,7 @@ _rt = _rt->mf6c_next; \ } \ if (rt == NULL) { \ - mrt6stat.mrt6s_mfc_misses++; \ + V_mrt6stat.mrt6s_mfc_misses++; \ } \ } while (/*CONSTCOND*/ 0) @@ -291,7 +301,9 @@ #ifdef UPCALL_TIMING #define UPCALL_MAX 50 +#ifndef VIMAGE static u_long upcall_data[UPCALL_MAX + 1]; +#endif /* !VIMAGE */ static void collate(); #endif /* UPCALL_TIMING */ @@ -303,7 +315,9 @@ static int add_m6fc(struct mf6cctl *); static int del_m6fc(struct mf6cctl *); -static struct callout expire_upcalls_ch; +#ifndef VIMAGE +static struct callout expire_upcalls_ch6; +#endif /* !VIMAGE */ int X_ip6_mforward(struct ip6_hdr *ip6, struct ifnet *ifp, struct mbuf *m); int X_ip6_mrouter_done(void); @@ -311,19 +325,21 @@ int X_ip6_mrouter_get(struct socket *so, struct sockopt *sopt); int X_mrt6_ioctl(int cmd, caddr_t data); + /* * Handle MRT setsockopt commands to modify the multicast routing tables. */ int X_ip6_mrouter_set(struct socket *so, struct sockopt *sopt) { + INIT_VNET_INET6(so->so_vnet); int error = 0; int optval; struct mif6ctl mifc; struct mf6cctl mfcc; mifi_t mifi; - if (so != ip6_mrouter && sopt->sopt_name != MRT6_INIT) + if (so != V_ip6_mrouter && sopt->sopt_name != MRT6_INIT) return (EACCES); switch (sopt->sopt_name) { @@ -385,10 +401,10 @@ int X_ip6_mrouter_get(struct socket *so, struct sockopt *sopt) { - INIT_VNET_INET6(curvnet); + INIT_VNET_INET6(so->so_vnet); int error = 0; - if (so != ip6_mrouter) + if (so != V_ip6_mrouter) return (EACCES); switch (sopt->sopt_name) { @@ -421,6 +437,7 @@ static int get_sg_cnt(struct sioc_sg_req6 *req) { + INIT_VNET_INET6(curvnet); struct mf6c *rt; int s; @@ -446,15 +463,16 @@ static int get_mif6_cnt(struct sioc_mif_req6 *req) { + INIT_VNET_INET6(curvnet); mifi_t mifi = req->mifi; - if (mifi >= nummifs) + if (mifi >= V_nummifs) return (EINVAL); - req->icount = mif6table[mifi].m6_pkt_in; - req->ocount = mif6table[mifi].m6_pkt_out; - req->ibytes = mif6table[mifi].m6_bytes_in; - req->obytes = mif6table[mifi].m6_bytes_out; + req->icount = V_mif6table[mifi].m6_pkt_in; + req->ocount = V_mif6table[mifi].m6_pkt_out; + req->ibytes = V_mif6table[mifi].m6_bytes_in; + req->obytes = V_mif6table[mifi].m6_bytes_out; return (0); } @@ -477,9 +495,11 @@ static int ip6_mrouter_init(struct socket *so, int v, int cmd) { - INIT_VNET_INET6(curvnet); + INIT_VNET_INET6(so->so_vnet); V_ip6_mrouter_ver = 0; + V_nummifs = 0; + V_reg_mif_num = (mifi_t)-1; #ifdef MRT6DEBUG V_mrt6debug = 0; @@ -497,20 +517,20 @@ if (v != 1) return (ENOPROTOOPT); - if (ip6_mrouter != NULL) + if (V_ip6_mrouter != NULL) return (EADDRINUSE); - ip6_mrouter = so; + V_ip6_mrouter = so; V_ip6_mrouter_ver = cmd; - bzero((caddr_t)mf6ctable, sizeof(mf6ctable)); - bzero((caddr_t)n6expire, sizeof(n6expire)); + bzero((caddr_t)V_mf6ctable, sizeof(V_mf6ctable)); + bzero((caddr_t)V_n6expire, sizeof(V_n6expire)); V_pim6 = 0;/* used for stubbing out/in pim stuff */ - callout_init(&expire_upcalls_ch, 0); - callout_reset(&expire_upcalls_ch, EXPIRE_TIMEOUT, - expire_upcalls, NULL); + callout_init(&V_expire_upcalls_ch6, 0); + callout_reset(&V_expire_upcalls_ch6, EXPIRE_TIMEOUT, + expire_upcalls, (void *)so->so_vnet); #ifdef MRT6DEBUG if (V_mrt6debug) @@ -547,29 +567,29 @@ * XXX: there may be an interface in which the IPv4 multicast * daemon is not interested... */ - if (!ip_mrouter) + if (!V_ip_mrouter) #endif #endif { - for (mifi = 0; mifi < nummifs; mifi++) { - if (mif6table[mifi].m6_ifp && - !(mif6table[mifi].m6_flags & MIFF_REGISTER)) { - if_allmulti(mif6table[mifi].m6_ifp, 0); + for (mifi = 0; mifi < V_nummifs; mifi++) { + if (V_mif6table[mifi].m6_ifp && + !(V_mif6table[mifi].m6_flags & MIFF_REGISTER)) { + if_allmulti(V_mif6table[mifi].m6_ifp, 0); } } } - bzero((caddr_t)mif6table, sizeof(mif6table)); - nummifs = 0; + bzero((caddr_t)V_mif6table, sizeof(V_mif6table)); + V_nummifs = 0; V_pim6 = 0; /* used to stub out/in pim specific code */ - callout_stop(&expire_upcalls_ch); + callout_stop(&V_expire_upcalls_ch6); /* * Free all multicast forwarding cache entries. */ for (i = 0; i < MF6CTBLSIZ; i++) { - rt = mf6ctable[i]; + rt = V_mf6ctable[i]; while (rt) { struct mf6c *frt; @@ -586,19 +606,19 @@ } } - bzero((caddr_t)mf6ctable, sizeof(mf6ctable)); + bzero((caddr_t)V_mf6ctable, sizeof(V_mf6ctable)); /* * Reset register interface */ - if (reg_mif_num != (mifi_t)-1 && multicast_register_if6 != NULL) { - if_detach(multicast_register_if6); - if_free(multicast_register_if6); - reg_mif_num = (mifi_t)-1; - multicast_register_if6 = NULL; + if (V_reg_mif_num != (mifi_t)-1 && V_multicast_register_if6 != NULL) { + if_detach(V_multicast_register_if6); + if_free(V_multicast_register_if6); + V_reg_mif_num = (mifi_t)-1; + V_multicast_register_if6 = NULL; } - ip6_mrouter = NULL; + V_ip6_mrouter = NULL; V_ip6_mrouter_ver = 0; splx(s); @@ -620,13 +640,14 @@ add_m6if(struct mif6ctl *mifcp) { INIT_VNET_NET(curvnet); + INIT_VNET_INET6(curvnet); struct mif6 *mifp; struct ifnet *ifp; int error, s; if (mifcp->mif6c_mifi >= MAXMIFS) return (EINVAL); - mifp = mif6table + mifcp->mif6c_mifi; + mifp = V_mif6table + mifcp->mif6c_mifi; if (mifp->m6_ifp) return (EADDRINUSE); /* XXX: is it appropriate? */ if (mifcp->mif6c_pifi == 0 || mifcp->mif6c_pifi > V_if_index) @@ -634,14 +655,14 @@ ifp = ifnet_byindex(mifcp->mif6c_pifi); if (mifcp->mif6c_flags & MIFF_REGISTER) { - if (reg_mif_num == (mifi_t)-1) { + if (V_reg_mif_num == (mifi_t)-1) { ifp = if_alloc(IFT_OTHER); if_initname(ifp, "register_mif", 0); ifp->if_flags |= IFF_LOOPBACK; if_attach(ifp); - multicast_register_if6 = ifp; - reg_mif_num = mifcp->mif6c_mifi; + V_multicast_register_if6 = ifp; + V_reg_mif_num = mifcp->mif6c_mifi; /* * it is impossible to guess the ifindex of the * register interface. So mif6c_pifi is automatically @@ -649,7 +670,7 @@ */ mifcp->mif6c_pifi = ifp->if_index; } else { - ifp = multicast_register_if6; + ifp = V_multicast_register_if6; } } /* if REGISTER */ @@ -676,9 +697,9 @@ mifp->m6_bytes_out = 0; splx(s); - /* Adjust nummifs up if the mifi is higher than nummifs */ - if (nummifs <= mifcp->mif6c_mifi) - nummifs = mifcp->mif6c_mifi + 1; + /* Adjust V_nummifs up if the mifi is higher than V_nummifs */ + if (V_nummifs <= mifcp->mif6c_mifi) + V_nummifs = mifcp->mif6c_mifi + 1; #ifdef MRT6DEBUG if (V_mrt6debug) @@ -697,12 +718,13 @@ static int del_m6if(mifi_t *mifip) { - struct mif6 *mifp = mif6table + *mifip; + INIT_VNET_INET6(curvnet); + struct mif6 *mifp = V_mif6table + *mifip; mifi_t mifi; struct ifnet *ifp; int s; - if (*mifip >= nummifs) + if (*mifip >= V_nummifs) return (EINVAL); if (mifp->m6_ifp == NULL) return (EINVAL); @@ -718,28 +740,28 @@ if_allmulti(ifp, 0); } else { - if (reg_mif_num != (mifi_t)-1 && - multicast_register_if6 != NULL) { - if_detach(multicast_register_if6); - if_free(multicast_register_if6); - reg_mif_num = (mifi_t)-1; - multicast_register_if6 = NULL; + if (V_reg_mif_num != (mifi_t)-1 && + V_multicast_register_if6 != NULL) { + if_detach(V_multicast_register_if6); + if_free(V_multicast_register_if6); + V_reg_mif_num = (mifi_t)-1; + V_multicast_register_if6 = NULL; } } bzero((caddr_t)mifp, sizeof(*mifp)); - /* Adjust nummifs down */ - for (mifi = nummifs; mifi > 0; mifi--) - if (mif6table[mifi - 1].m6_ifp) + /* Adjust V_nummifs down */ + for (mifi = V_nummifs; mifi > 0; mifi--) + if (V_mif6table[mifi - 1].m6_ifp) break; - nummifs = mifi; + V_nummifs = mifi; splx(s); #ifdef MRT6DEBUG if (V_mrt6debug) - log(LOG_DEBUG, "del_m6if %d, nummifs %d\n", *mifip, nummifs); + log(LOG_DEBUG, "del_m6if %d, nummifs %d\n", *mifip, V_nummifs); #endif return (0); @@ -787,7 +809,7 @@ s = splnet(); hash = MF6CHASH(mfccp->mf6cc_origin.sin6_addr, mfccp->mf6cc_mcastgrp.sin6_addr); - for (rt = mf6ctable[hash], nstl = 0; rt; rt = rt->mf6c_next) { + for (rt = V_mf6ctable[hash], nstl = 0; rt; rt = rt->mf6c_next) { if (IN6_ARE_ADDR_EQUAL(&rt->mf6c_origin.sin6_addr, &mfccp->mf6cc_origin.sin6_addr) && IN6_ARE_ADDR_EQUAL(&rt->mf6c_mcastgrp.sin6_addr, @@ -825,7 +847,7 @@ rt->mf6c_wrong_if = 0; rt->mf6c_expire = 0; /* Don't clean this guy up */ - n6expire[hash]--; + V_n6expire[hash]--; /* free packets Qed at the end of this entry */ for (rte = rt->mf6c_stall; rte != NULL; ) { @@ -856,7 +878,7 @@ mfccp->mf6cc_parent); #endif - for (rt = mf6ctable[hash]; rt; rt = rt->mf6c_next) { + for (rt = V_mf6ctable[hash]; rt; rt = rt->mf6c_next) { if (IN6_ARE_ADDR_EQUAL(&rt->mf6c_origin.sin6_addr, &mfccp->mf6cc_origin.sin6_addr)&& @@ -873,7 +895,7 @@ rt->mf6c_wrong_if = 0; if (rt->mf6c_expire) - n6expire[hash]--; + V_n6expire[hash]--; rt->mf6c_expire = 0; } } @@ -899,8 +921,8 @@ rt->mf6c_stall = NULL; /* link into table */ - rt->mf6c_next = mf6ctable[hash]; - mf6ctable[hash] = rt; + rt->mf6c_next = V_mf6ctable[hash]; + V_mf6ctable[hash] = rt; } } splx(s); @@ -914,6 +936,7 @@ static void collate(struct timeval *t) { + INIT_VNET_INET6(curvnet); u_long d; struct timeval tp; u_long delta; @@ -928,7 +951,7 @@ if (d > UPCALL_MAX) d = UPCALL_MAX; - ++upcall_data[d]; + ++V_upcall_data[d]; } } #endif /* UPCALL_TIMING */ @@ -962,7 +985,7 @@ s = splnet(); - nptr = &mf6ctable[hash]; + nptr = &V_mf6ctable[hash]; while ((rt = *nptr) != NULL) { if (IN6_ARE_ADDR_EQUAL(&origin.sin6_addr, &rt->mf6c_origin.sin6_addr) && @@ -1097,7 +1120,7 @@ GET_TIME(tp); #endif /* UPCALL_TIMING */ - mrt6stat.mrt6s_no_route++; + V_mrt6stat.mrt6s_no_route++; #ifdef MRT6DEBUG if (V_mrt6debug & (DEBUG_FORWARD | DEBUG_MFC)) log(LOG_DEBUG, "ip6_mforward: no rte s %s g %s\n", @@ -1131,7 +1154,7 @@ /* is there an upcall waiting for this packet? */ hash = MF6CHASH(ip6->ip6_src, ip6->ip6_dst); - for (rt = mf6ctable[hash]; rt; rt = rt->mf6c_next) { + for (rt = V_mf6ctable[hash]; rt; rt = rt->mf6c_next) { if (IN6_ARE_ADDR_EQUAL(&ip6->ip6_src, &rt->mf6c_origin.sin6_addr) && IN6_ARE_ADDR_EQUAL(&ip6->ip6_dst, @@ -1205,8 +1228,8 @@ "getting the iif info in the kernel\n"); #endif - for (mifp = mif6table, mifi = 0; - mifi < nummifs && mifp->m6_ifp != ifp; + for (mifp = V_mif6table, mifi = 0; + mifi < V_nummifs && mifp->m6_ifp != ifp; mifp++, mifi++) ; @@ -1221,10 +1244,10 @@ break; } - if (socket_send(ip6_mrouter, mm, &sin6) < 0) { + if (socket_send(V_ip6_mrouter, mm, &sin6) < 0) { log(LOG_WARNING, "ip6_mforward: ip6_mrouter " "socket queue full\n"); - mrt6stat.mrt6s_upq_sockfull++; + V_mrt6stat.mrt6s_upq_sockfull++; free(rte, M_MRTABLE6); m_freem(mb0); free(rt, M_MRTABLE6); @@ -1232,7 +1255,7 @@ return (ENOBUFS); } - mrt6stat.mrt6s_upcalls++; + V_mrt6stat.mrt6s_upcalls++; /* insert new entry at head of hash chain */ bzero(rt, sizeof(*rt)); @@ -1243,12 +1266,12 @@ rt->mf6c_mcastgrp.sin6_len = sizeof(struct sockaddr_in6); rt->mf6c_mcastgrp.sin6_addr = ip6->ip6_dst; rt->mf6c_expire = UPCALL_EXPIRE; - n6expire[hash]++; + V_n6expire[hash]++; rt->mf6c_parent = MF6C_INCOMPLETE_PARENT; /* link into table */ - rt->mf6c_next = mf6ctable[hash]; - mf6ctable[hash] = rt; + rt->mf6c_next = V_mf6ctable[hash]; + V_mf6ctable[hash] = rt; /* Add this entry to the end of the queue */ rt->mf6c_stall = rte; } else { @@ -1258,7 +1281,7 @@ for (p = &rt->mf6c_stall; *p != NULL; p = &(*p)->next) if (++npkts > MAX_UPQ6) { - mrt6stat.mrt6s_upq_ovflw++; + V_mrt6stat.mrt6s_upq_ovflw++; free(rte, M_MRTABLE6); m_freem(mb0); splx(s); @@ -1289,7 +1312,7 @@ static void expire_upcalls(void *unused) { - INIT_VNET_INET6(curvnet); + INIT_VNET_INET6( (struct vnet*)unused ); struct rtdetq *rte; struct mf6c *mfc, **nptr; int i; @@ -1297,9 +1320,9 @@ s = splnet(); for (i = 0; i < MF6CTBLSIZ; i++) { - if (n6expire[i] == 0) + if (V_n6expire[i] == 0) continue; - nptr = &mf6ctable[i]; + nptr = &V_mf6ctable[i]; while ((mfc = *nptr) != NULL) { rte = mfc->mf6c_stall; /* @@ -1329,8 +1352,8 @@ free(rte, M_MRTABLE6); rte = n; } while (rte != NULL); - mrt6stat.mrt6s_cache_cleanups++; - n6expire[i]--; + V_mrt6stat.mrt6s_cache_cleanups++; + V_n6expire[i]--; *nptr = mfc->mf6c_next; free(mfc, M_MRTABLE6); @@ -1339,9 +1362,9 @@ } } } + callout_reset(&V_expire_upcalls_ch6, EXPIRE_TIMEOUT, + expire_upcalls, unused); splx(s); - callout_reset(&expire_upcalls_ch, EXPIRE_TIMEOUT, - expire_upcalls, NULL); } /* @@ -1377,16 +1400,16 @@ * for its origin. */ mifi = rt->mf6c_parent; - if ((mifi >= nummifs) || (mif6table[mifi].m6_ifp != ifp)) { + if ((mifi >= V_nummifs) || (V_mif6table[mifi].m6_ifp != ifp)) { /* came in the wrong interface */ #ifdef MRT6DEBUG if (V_mrt6debug & DEBUG_FORWARD) log(LOG_DEBUG, "wrong if: ifid %d mifi %d mififid %x\n", ifp->if_index, mifi, - mif6table[mifi].m6_ifp->if_index); + V_mif6table[mifi].m6_ifp->if_index); #endif - mrt6stat.mrt6s_wrong_if++; + V_mrt6stat.mrt6s_wrong_if++; rt->mf6c_wrong_if++; /* * If we are doing PIM processing, and we are forwarding @@ -1394,7 +1417,7 @@ * routing daemon. */ /* have to make sure this is a valid mif */ - if (mifi < nummifs && mif6table[mifi].m6_ifp) + if (mifi < V_nummifs && V_mif6table[mifi].m6_ifp) if (V_pim6 && (m->m_flags & M_LOOP) == 0) { /* * Check the M_LOOP flag to avoid an @@ -1440,8 +1463,8 @@ return (EINVAL); } - for (mifp = mif6table, iif = 0; - iif < nummifs && mifp && + for (mifp = V_mif6table, iif = 0; + iif < V_nummifs && mifp && mifp->m6_ifp != ifp; mifp++, iif++) ; @@ -1459,14 +1482,14 @@ break; } - mrt6stat.mrt6s_upcalls++; + V_mrt6stat.mrt6s_upcalls++; - if (socket_send(ip6_mrouter, mm, &sin6) < 0) { + if (socket_send(V_ip6_mrouter, mm, &sin6) < 0) { #ifdef MRT6DEBUG if (V_mrt6debug) log(LOG_WARNING, "mdq, ip6_mrouter socket queue full\n"); #endif - ++mrt6stat.mrt6s_upq_sockfull; + ++V_mrt6stat.mrt6s_upq_sockfull; return (ENOBUFS); } /* if socket Q full */ } /* if PIM */ @@ -1476,11 +1499,11 @@ /* If I sourced this packet, it counts as output, else it was input. */ if (m->m_pkthdr.rcvif == NULL) { /* XXX: is rcvif really NULL when output?? */ - mif6table[mifi].m6_pkt_out++; - mif6table[mifi].m6_bytes_out += plen; + V_mif6table[mifi].m6_pkt_out++; + V_mif6table[mifi].m6_bytes_out += plen; } else { - mif6table[mifi].m6_pkt_in++; - mif6table[mifi].m6_bytes_in += plen; + V_mif6table[mifi].m6_pkt_in++; + V_mif6table[mifi].m6_bytes_in += plen; } rt->mf6c_pkt_cnt++; rt->mf6c_byte_cnt += plen; @@ -1496,7 +1519,7 @@ V_ip6stat.ip6s_badscope++; return (error); } - for (mifp = mif6table, mifi = 0; mifi < nummifs; mifp++, mifi++) { + for (mifp = V_mif6table, mifi = 0; mifi < V_nummifs; mifp++, mifi++) { if (IF_ISSET(mifi, &rt->mf6c_ifset)) { /* * check if the outgoing packet is going to break @@ -1504,12 +1527,12 @@ * XXX For packets through PIM register tunnel * interface, we believe a routing daemon. */ - if (!(mif6table[rt->mf6c_parent].m6_flags & + if (!(V_mif6table[rt->mf6c_parent].m6_flags & MIFF_REGISTER) && - !(mif6table[mifi].m6_flags & MIFF_REGISTER)) { - if (in6_setscope(&src0, mif6table[mifi].m6_ifp, + !(V_mif6table[mifi].m6_flags & MIFF_REGISTER)) { + if (in6_setscope(&src0, V_mif6table[mifi].m6_ifp, &oszone) || - in6_setscope(&dst0, mif6table[mifi].m6_ifp, + in6_setscope(&dst0, V_mif6table[mifi].m6_ifp, &odzone) || iszone != oszone || idzone != odzone) { @@ -1575,7 +1598,7 @@ #ifdef MRT6DEBUG if (V_mrt6debug & DEBUG_XMIT) log(LOG_DEBUG, "phyint_send on mif %d err %d\n", - mifp - mif6table, error); + mifp - V_mif6table, error); #endif splx(s); return; @@ -1611,7 +1634,7 @@ #ifdef MRT6DEBUG if (V_mrt6debug & DEBUG_XMIT) log(LOG_DEBUG, "phyint_send on mif %d err %d\n", - mifp - mif6table, error); + mifp - V_mif6table, error); #endif } else { /* @@ -1659,7 +1682,7 @@ ip6_sprintf(ip6bufd, &ip6->ip6_dst)); } #endif - ++pim6stat.pim6s_snd_registers; + ++V_pim6stat.pim6s_snd_registers; /* Make a copy of the packet to send to the user level process */ MGETHDR(mm, M_DONTWAIT, MT_HEADER); @@ -1691,18 +1714,18 @@ im6->im6_msgtype = MRT6MSG_WHOLEPKT; im6->im6_mbz = 0; - im6->im6_mif = mif - mif6table; + im6->im6_mif = mif - V_mif6table; /* iif info is not given for reg. encap.n */ - mrt6stat.mrt6s_upcalls++; + V_mrt6stat.mrt6s_upcalls++; - if (socket_send(ip6_mrouter, mm, &sin6) < 0) { + if (socket_send(V_ip6_mrouter, mm, &sin6) < 0) { #ifdef MRT6DEBUG if (V_mrt6debug) log(LOG_WARNING, "register_send: ip6_mrouter socket queue full\n"); #endif - ++mrt6stat.mrt6s_upq_sockfull; + ++V_mrt6stat.mrt6s_upq_sockfull; return (ENOBUFS); } return (0); @@ -1726,7 +1749,7 @@ int minlen; int off = *offp; - ++pim6stat.pim6s_rcv_total; + ++V_pim6stat.pim6s_rcv_total; ip6 = mtod(m, struct ip6_hdr *); pimlen = m->m_pkthdr.len - *offp; @@ -1735,7 +1758,7 @@ * Validate lengths */ if (pimlen < PIM_MINLEN) { - ++pim6stat.pim6s_rcv_tooshort; + ++V_pim6stat.pim6s_rcv_tooshort; #ifdef MRT6DEBUG if (V_mrt6debug & DEBUG_PIM) log(LOG_DEBUG,"pim6_input: PIM packet too short\n"); @@ -1768,7 +1791,7 @@ #else IP6_EXTHDR_GET(pim, struct pim *, m, off, minlen); if (pim == NULL) { - pim6stat.pim6s_rcv_tooshort++; + V_pim6stat.pim6s_rcv_tooshort++; return (IPPROTO_DONE); } #endif @@ -1788,7 +1811,7 @@ cksumlen = pimlen; if (in6_cksum(m, IPPROTO_PIM, off, cksumlen)) { - ++pim6stat.pim6s_rcv_badsum; + ++V_pim6stat.pim6s_rcv_badsum; #ifdef MRT6DEBUG if (V_mrt6debug & DEBUG_PIM) log(LOG_DEBUG, @@ -1802,7 +1825,7 @@ /* PIM version check */ if (pim->pim_ver != PIM_VERSION) { - ++pim6stat.pim6s_rcv_badversion; + ++V_pim6stat.pim6s_rcv_badversion; #ifdef MRT6DEBUG log(LOG_ERR, "pim6_input: incorrect version %d, expecting %d\n", @@ -1828,14 +1851,14 @@ char ip6bufs[INET6_ADDRSTRLEN], ip6bufd[INET6_ADDRSTRLEN]; #endif - ++pim6stat.pim6s_rcv_registers; + ++V_pim6stat.pim6s_rcv_registers; - if ((reg_mif_num >= nummifs) || (reg_mif_num == (mifi_t) -1)) { + if ((V_reg_mif_num >= V_nummifs) || (V_reg_mif_num == (mifi_t) -1)) { #ifdef MRT6DEBUG if (V_mrt6debug & DEBUG_PIM) log(LOG_DEBUG, "pim6_input: register mif not set: %d\n", - reg_mif_num); + V_reg_mif_num); #endif m_freem(m); return (IPPROTO_DONE); @@ -1850,8 +1873,8 @@ * Validate length */ if (pimlen < PIM6_REG_MINLEN) { - ++pim6stat.pim6s_rcv_tooshort; - ++pim6stat.pim6s_rcv_badregisters; + ++V_pim6stat.pim6s_rcv_tooshort; + ++V_pim6stat.pim6s_rcv_badregisters; #ifdef MRT6DEBUG log(LOG_ERR, "pim6_input: register packet size too " @@ -1875,7 +1898,7 @@ /* verify the version number of the inner packet */ if ((eip6->ip6_vfc & IPV6_VERSION_MASK) != IPV6_VERSION) { - ++pim6stat.pim6s_rcv_badregisters; + ++V_pim6stat.pim6s_rcv_badregisters; #ifdef MRT6DEBUG log(LOG_DEBUG, "pim6_input: invalid IP version (%d) " "of the inner packet\n", @@ -1887,7 +1910,7 @@ /* verify the inner packet is destined to a mcast group */ if (!IN6_IS_ADDR_MULTICAST(&eip6->ip6_dst)) { - ++pim6stat.pim6s_rcv_badregisters; + ++V_pim6stat.pim6s_rcv_badregisters; #ifdef MRT6DEBUG if (V_mrt6debug & DEBUG_PIM) log(LOG_DEBUG, @@ -1924,11 +1947,11 @@ "src %s, dst %s, mif %d\n", ip6_sprintf(ip6bufs, &eip6->ip6_src), ip6_sprintf(ip6bufd, &eip6->ip6_dst), - reg_mif_num); + V_reg_mif_num); } #endif - rc = if_simloop(mif6table[reg_mif_num].m6_ifp, m, + rc = if_simloop(V_mif6table[V_reg_mif_num].m6_ifp, m, dst.sin6_family, 0); /* prepare the register head to send to the mrouting daemon */ diff -ur sys.20081015/netinet6/ip6_mroute.h sys/netinet6/ip6_mroute.h --- sys.20081015/netinet6/ip6_mroute.h 2008-10-15 08:25:28.000000000 -0700 +++ sys/netinet6/ip6_mroute.h 2008-11-05 13:21:56.000000000 -0800 @@ -266,6 +266,7 @@ extern int (*ip6_mrouter_get)(struct socket *so, struct sockopt *sopt); extern int (*ip6_mrouter_done)(void); extern int (*mrt6_ioctl)(int, caddr_t); + #endif /* _KERNEL */ #endif /* !_NETINET6_IP6_MROUTE_H_ */ diff -ur sys.20081015/netinet6/ip6_output.c sys/netinet6/ip6_output.c --- sys.20081015/netinet6/ip6_output.c 2008-10-15 08:25:28.000000000 -0700 +++ sys/netinet6/ip6_output.c 2008-10-28 20:01:22.000000000 -0700 @@ -744,7 +744,7 @@ * above, will be forwarded by the ip6_input() routine, * if necessary. */ - if (ip6_mrouter && (flags & IPV6_FORWARDING) == 0) { + if (V_ip6_mrouter && (flags & IPV6_FORWARDING) == 0) { /* * XXX: ip6_mforward expects that rcvif is NULL * when it is called from the originating path. diff -ur sys.20081015/netinet6/ip6_var.h sys/netinet6/ip6_var.h --- sys.20081015/netinet6/ip6_var.h 2008-10-15 08:25:28.000000000 -0700 +++ sys/netinet6/ip6_var.h 2008-10-28 20:01:22.000000000 -0700 @@ -292,8 +292,8 @@ extern int ip6_v6only; #endif -extern struct socket *ip6_mrouter; /* multicast routing daemon */ #ifndef VIMAGE +extern struct socket *ip6_mrouter; /* multicast routing daemon */ extern int ip6_sendredirects; /* send IP redirects when forwarding? */ extern int ip6_maxfragpackets; /* Maximum packets in reassembly queue */ extern int ip6_maxfrags; /* Maximum fragments in reassembly queue */ diff -ur sys.20081015/netinet6/mld6.c sys/netinet6/mld6.c --- sys.20081015/netinet6/mld6.c 2008-10-15 08:25:28.000000000 -0700 +++ sys/netinet6/mld6.c 2008-10-28 20:01:22.000000000 -0700 @@ -518,7 +518,7 @@ * Request loopback of the report if we are acting as a multicast * router, so that the process-level routing daemon can hear it. */ - im6o.im6o_multicast_loop = (ip6_mrouter != NULL); + im6o.im6o_multicast_loop = (V_ip6_mrouter != NULL); /* increment output statictics */ V_icmp6stat.icp6s_outhist[type]++; diff -ur sys.20081015/netinet6/raw_ip6.c sys/netinet6/raw_ip6.c --- sys.20081015/netinet6/raw_ip6.c 2008-10-15 08:25:28.000000000 -0700 +++ sys/netinet6/raw_ip6.c 2008-10-28 20:01:22.000000000 -0700 @@ -129,7 +129,9 @@ /* * Hooks for multicast forwarding. */ +#ifndef VIMAGE struct socket *ip6_mrouter = NULL; +#endif int (*ip6_mrouter_set)(struct socket *, struct sockopt *); int (*ip6_mrouter_get)(struct socket *, struct sockopt *); int (*ip6_mrouter_done)(void); @@ -599,12 +601,13 @@ rip6_detach(struct socket *so) { INIT_VNET_INET(so->so_vnet); + INIT_VNET_INET6(so->so_vnet); struct inpcb *inp; inp = sotoinpcb(so); KASSERT(inp != NULL, ("rip6_detach: inp == NULL")); - if (so == ip6_mrouter && ip6_mrouter_done) + if (so == V_ip6_mrouter && ip6_mrouter_done) ip6_mrouter_done(); /* xxx: RSVP */ INP_INFO_WLOCK(&V_ripcbinfo); diff -ur sys.20081015/netinet6/vinet6.h sys/netinet6/vinet6.h --- sys.20081015/netinet6/vinet6.h 2008-10-15 08:25:28.000000000 -0700 +++ sys/netinet6/vinet6.h 2008-10-29 12:58:52.000000000 -0700 @@ -43,6 +43,8 @@ #include #include #include +#include +#include /* struct pim6stat */ #define INIT_VNET_INET6(vnet) \ INIT_FROM_VNET(vnet, VNET_MOD_INET6, \ @@ -95,6 +97,7 @@ //int _icmp6_nodeinfo; int _ip6_forwarding; + struct socket * _ip6_mrouter; int _ip6_sendredirects; int _ip6_defhlim; int _ip6_defmcasthlim; @@ -149,14 +152,25 @@ u_int32_t _ip6_temp_preferred_lifetime; u_int32_t _ip6_temp_valid_lifetime; - int _ip6_mrouter_ver; - int _pim6; - u_int _mrt6debug; - int _ip6_temp_regen_advance; int _ip6_use_defzone; struct ip6_pktopts _ip6_opts; + + /* from ip6_mroute.c */ + int _ip6_mrouter_ver; /* = 0; */ + struct mrt6stat _mrt6stat; + struct mf6c * _mf6ctable[MF6CTBLSIZ]; + u_char _n6expire[MF6CTBLSIZ]; + struct mif6 _mif6table[MAXMIFS]; + u_int _mrt6debug; + struct ifnet * _multicast_register_if6; + mifi_t _nummifs; /* = 0; */ + mifi_t _reg_mif_num; /* = (mifi_t)-1; */ + struct pim6stat _pim6stat; + int _pim6; + u_long _upcall_data[51]; + struct callout _expire_upcalls_ch6; }; #endif @@ -206,6 +220,7 @@ //#define V_icmp6_nodeinfo VNET_INET6(icmp6_nodeinfo) #define V_ip6_forwarding VNET_INET6(ip6_forwarding) +#define V_ip6_mrouter VNET_INET6(ip6_mrouter) #define V_ip6_sendredirects VNET_INET6(ip6_sendredirects) #define V_ip6_defhlim VNET_INET6(ip6_defhlim) #define V_ip6_defmcasthlim VNET_INET6(ip6_defmcasthlim) @@ -260,13 +275,24 @@ #define V_ip6_temp_preferred_lifetime VNET_INET6(ip6_temp_preferred_lifetime) #define V_ip6_temp_valid_lifetime VNET_INET6(ip6_temp_valid_lifetime) -#define V_ip6_mrouter_ver VNET_INET6(ip6_mrouter_ver) -#define V_pim6 VNET_INET6(pim6) -#define V_mrt6debug VNET_INET6(mrt6debug) #define V_ip6_temp_regen_advance VNET_INET6(ip6_temp_regen_advance) #define V_ip6_use_defzone VNET_INET6(ip6_use_defzone) #define V_ip6_opts VNET_INET6(ip6_opts) +#define V_ip6_mrouter_ver VNET_INET6(ip6_mrouter_ver) +#define V_mrt6stat VNET_INET6(mrt6stat) +#define V_mf6ctable VNET_INET6(mf6ctable) +#define V_n6expire VNET_INET6(n6expire) +#define V_mif6table VNET_INET6(mif6table) +#define V_mrt6debug VNET_INET6(mrt6debug) +#define V_multicast_register_if6 VNET_INET6(multicast_register_if6) +#define V_nummifs VNET_INET6(nummifs) +#define V_reg_mif_num VNET_INET6(reg_mif_num) +#define V_pim6stat VNET_INET6(pim6stat) +#define V_pim6 VNET_INET6(pim6) +#define V_upcall_data VNET_INET6(upcall_data) +#define V_expire_upcalls_ch6 VNET_INET6(expire_upcalls_ch6) + #endif /* !_NETINET6_VINET6_H_ */ diff -ur sys.20081015/netipsec/keysock.c sys/netipsec/keysock.c --- sys.20081015/netipsec/keysock.c 2008-10-15 08:25:29.000000000 -0700 +++ sys/netipsec/keysock.c 2008-10-29 07:57:18.000000000 -0700 @@ -429,8 +429,8 @@ kp->kp_promisc = kp->kp_registered = 0; if (kp->kp_raw.rcb_proto.sp_protocol == PF_KEY) /* XXX: AF_KEY */ - key_cb.key_count++; - key_cb.any_count++; + V_key_cb.key_count++; + V_key_cb.any_count++; soisconnected(so); so->so_options |= SO_USELOOPBACK; diff -ur sys.20081015/sys/vimage.h sys/sys/vimage.h --- sys.20081015/sys/vimage.h 2008-10-15 08:25:30.000000000 -0700 +++ sys/sys/vimage.h 2008-11-04 13:56:18.000000000 -0800 @@ -77,6 +77,7 @@ #define VNET_MOD_IPX 9 #define VNET_MOD_ATALK 10 #define VNET_MOD_DIVERT 11 +#define VNET_MOD_MROUTE 12 /* stateless modules */ #define VNET_MOD_NG_WORMHOLE 19 #define VNET_MOD_NG_ETHER 20 @@ -103,6 +104,7 @@ #define V_MOD_vnet_pf VNET_MOD_PF #define V_MOD_vnet_gif VNET_MOD_GIF #define V_MOD_vnet_ipsec VNET_MOD_IPSEC +#define V_MOD_vnet_mroute VNET_MOD_MROUTE #define V_MOD_vprocg 0 #define V_MOD_vcpu 0 core-4.8/python-prefix.py0000775000175000017500000000163412534327775012454 00000000000000#!/usr/bin/env python import sys import os.path import site def main(): '''\ Check if the given prefix is included in sys.path for the given python version; if not find an alternate valid prefix. Print the result to standard out. ''' if len(sys.argv) != 3: msg = 'usage: %s \n' % \ os.path.basename(sys.argv[0]) sys.stderr.write(msg) return 1 python_prefix = sys.argv[1] python_version = sys.argv[2] path = '%s/lib/python%s' % (python_prefix, python_version) path = os.path.normpath(path) if path[-1] != '/': path = path + '/' prefix = None for p in sys.path: if p.startswith(path): prefix = python_prefix break if not prefix: prefix = site.PREFIXES[-1] sys.stdout.write('%s\n' % prefix) return 0 if __name__ == '__main__': sys.exit(main()) core-4.8/gui/0000775000175000017500000000000012534330006010100 500000000000000core-4.8/gui/addons/0000775000175000017500000000000012534327775011373 500000000000000core-4.8/gui/addons/ipsecservice.tcl0000664000175000017500000002601212534327775014504 00000000000000# # Copyright 2012 the Boeing Company. # See the LICENSE file included in this distribution. # # author: Jeff Ahrenholz # # This is a separate "addons" file because it is closely tied to Python # service definition for the IPsec service. # # # Helper dialog for configuring the IPsec service # proc popupServiceConfig_IPsec { parent w node service btn } { global plugin_img_add plugin_img_del plugin_img_edit set f $w.note.ipsec ttk::frame $f set h "This IPsec service helper will assist with building an ipsec.sh file" set h "$h (located on the Files tab).\nThe IPsec service builds ESP" set h "$h tunnels between the specified peers using the racoon IKEv2" set h "$h\nkeying daemon. You need to provide keys and the addresses of" set h "$h peers, along with the\nsubnets to tunnel." ttk::label $f.help -text $h pack $f.help -side top -anchor w -padx 4 -pady 4 $w.note add $f -text "IPsec" -underline 0 global g_ipsec_key_dir g_ipsec_key_name set g_ipsec_key_dir "/etc/core/keys" set g_ipsec_key_name "ipsec1" ttk::labelframe $f.keys -text "Keys" ttk::frame $f.keys.dir ttk::label $f.keys.dir.lab -text "Key directory:" ttk::entry $f.keys.dir.ent -width 40 -textvariable g_ipsec_key_dir ttk::button $f.keys.dir.btn -width 5 -text "..." -command { set f .popupServicesCustomize.note.ipsec set d [$f.keys.dir.ent get] set d [tk_chooseDirectory -initialdir $d -title "Key directory"] if { $d != "" } { $f.keys.dir.ent delete 0 end $f.keys.dir.ent insert 0 $d } } pack $f.keys.dir.lab $f.keys.dir.ent $f.keys.dir.btn \ -side left -padx 4 -pady 4 pack $f.keys.dir -side top -anchor w ttk::frame $f.keys.name ttk::label $f.keys.name.lab -text "Key base name:" ttk::entry $f.keys.name.ent -width 10 -textvariable g_ipsec_key_name pack $f.keys.name.lab $f.keys.name.ent -side left -padx 4 -pady 4 pack $f.keys.name -side top -anchor w set h "The (name).pem x509 certificate and (name).key RSA private key need" set h "$h to exist in the\nspecified directory. These can be generated" set h "$h using the openssl tool. Also, a ca-cert.pem\nfile should exist" set h "$h in the key directory for the CA that issued the certs." ttk::label $f.keys.help -text $h pack $f.keys.help -side top -anchor w -padx 4 -pady 4 pack $f.keys -side top -pady 4 -pady 4 -expand true -fill x ttk::labelframe $f.t -text "IPsec Tunnel Endpoints" set h "(1) Define tunnel endpoints (select peer node using the button" set h "$h, then select address from the list)" ttk::label $f.t.lab1 -text $h pack $f.t.lab1 -side top -anchor w -padx 4 -pady 4 ttk::frame $f.t.ep ttk::label $f.t.ep.lab1 -text "Local:" ttk::combobox $f.t.ep.combo1 -width 12 pack $f.t.ep.lab1 $f.t.ep.combo1 -side left -padx 4 -pady 4 populateComboWithIPs $f.t.ep.combo1 $node global g_twoNodeSelect g_twoNodeSelectCallback set g_twoNodeSelect "" set g_twoNodeSelectCallback selectTwoNodeIPsecCallback set h "Choose a node by clicking it on the canvas" set h "$h or\nby selecting it from the list below." ttk::label $f.t.ep.lab2 -text "Peer node:" ttk::checkbutton $f.t.ep.node -text " (none) " -variable g_twoNodeSelect \ -onvalue "$f.t.ep.node" -style Toolbutton \ -command "popupSelectNodes {$h} {} selectNodesIPsecCallback" ttk::label $f.t.ep.lab3 -text "Peer:" ttk::combobox $f.t.ep.combo2 -width 12 ttk::button $f.t.ep.add -text "Add Endpoint" -image $plugin_img_add \ -compound left -command "ipsecTreeHelper $f ep" pack $f.t.ep.lab2 $f.t.ep.node $f.t.ep.lab3 $f.t.ep.combo2 \ $f.t.ep.add -side left -padx 4 -pady 4 pack $f.t.ep -side top -anchor w set h "(2) Select endpoints below and add the subnets to be encrypted" ttk::label $f.t.lab2 -text $h pack $f.t.lab2 -side top -anchor w -padx 4 -pady 4 ttk::frame $f.t.sub ttk::label $f.t.sub.lab1 -text "Local subnet:" ttk::combobox $f.t.sub.combo1 -width 12 ttk::label $f.t.sub.lab2 -text "Remote subnet:" ttk::combobox $f.t.sub.combo2 -width 12 ttk::button $f.t.sub.add -text "Add Subnet" -image $plugin_img_add \ -compound left -command "ipsecTreeHelper $f sub" pack $f.t.sub.lab1 $f.t.sub.combo1 $f.t.sub.lab2 $f.t.sub.combo2 \ $f.t.sub.add -side left -padx 5 -pady 4 pack $f.t.sub -side top -anchor w global node_list set net_list [ipv4SubnetList $node_list] $f.t.sub.combo1 configure -values $net_list $f.t.sub.combo2 configure -values $net_list ttk::treeview $f.t.tree -height 5 -selectmode browse -show tree pack $f.t.tree -side top -padx 4 -pady 4 -fill both pack $f.t -side top -expand true -fill both ttk::frame $f.bottom ttk::button $f.bottom.del -image $plugin_img_del \ -command "ipsecTreeHelper $f del" ttk::button $f.bottom.gen -text "Generate ipsec.sh" \ -image $plugin_img_edit -compound left -command "generateIPsecScript $w" pack $f.bottom.del $f.bottom.gen -side left -padx 4 -pady 4 pack $f.bottom -side top } # # Callback invoked when receiving configuration values # from a Configuration Message; this service helper depends on the ipsec.sh # file, not the other configuration values. # #proc popupServiceConfig_IPsec_vals { node values services w } { #} # # Callback invoked when receiving service file data from a File Message proc popupServiceConfig_IPsec_file { node name data w } { if { $name == "ipsec.sh" } { readIPsecScript $w } } # helper to insert all of a node's IP addresses into a combo proc populateComboWithIPs { combo node } { set ip_list [ipv4List $node 0] $combo configure -values $ip_list $combo delete 0 end $combo insert 0 [lindex $ip_list 0] } # called from editor.tcl:button1 when user clicks on a node # search for IP address and populate proc selectTwoNodeIPsecCallback {} { set w .popupServicesCustomize set f $w.note.ipsec if { ![winfo exists $w] } { return }; # user has closed window catch {destroy .nodeselect} set node [string trim [$f.t.ep.node cget -text]] if { [set node] == "(none)" } { set node "" } # populate peer interface combo with list of IPs populateComboWithIPs $f.t.ep.combo2 $node } # called from popupSelectNodes dialog when a node selection has been made proc selectNodesIPsecCallback { nodes } { global g_twoNodeSelect set w .popupServicesCustomize set f $w.note.ipsec set g_twoNodeSelect "" set node [lindex $nodes 0] if { $node == "" } { $f.t.ep.node configure -text "(none)" return } $f.t.ep.node configure -text " $node " # populate peer interface combo with list of IPs populateComboWithIPs $f.t.ep.combo2 $node } # helper to manipulate tree; cmd is "del", "ep" or "sub" proc ipsecTreeHelper { f cmd } { if { $cmd == "del" } { set sel [$f.t.tree selection] $f.t.tree delete $sel return } # add endpoint (ep) or subnet (sub) set l [string trim [$f.t.$cmd.combo1 get]] set p [string trim [$f.t.$cmd.combo2 get]] if { $l == "" || $p == "" } { if { $cmd == "ep" } { set h "tunnel interface addresses" } else { set h "subnet addresses" } tk_messageBox -type ok -icon warning -message \ "You need to select local and peer $h." return } if { $cmd == "ep" } { set item [$f.t.tree insert {} end -text "$l <--> $p" -open true] $f.t.tree selection set $item } elseif { $cmd == "sub" } { set parent [$f.t.tree selection] if { $parent == "" } { tk_messageBox -type ok -icon warning -message \ "You need to first select endpoints, then configure their subnets." return } if { [$f.t.tree parent $parent] != {} } { set parent [$f.t.tree parent $parent] } $f.t.tree insert $parent end -text "$l <===> $p" } } # update an ipsec.sh file that was generated by the IPsec service proc generateIPsecScript { w } { #puts "generateIPsecScript $w..." set cfg [$w.note.files.txt get 0.0 end-1c] set newcfg "" # # Gather data for a new config # set f $w.note.ipsec set keydir [$f.keys.dir.ent get] set keyname [$f.keys.name.ent get] set tunnelhosts "" set subnet_list "" set ti 0 set th_items [$f.t.tree children {}] foreach th $th_items { set ep [$f.t.tree item $th -text] set i [string first " " $ep] # replace " <--> " with "AND" set ep [string replace $ep $i $i+5 "AND"] # build a list e.g.: # tunnelhosts="172.16.0.1AND172.16.0.2 172.16.0.1AND172.16.2.1" lappend tunnelhosts $ep set subnets "" foreach subnet_item [$f.t.tree children $th] { set sn [$f.t.tree item $subnet_item -text] set i [string first " " $sn] # replace " <===> " with "AND" set sn [string replace $sn $i $i+6 "AND"] lappend subnets $sn } incr ti set subnetstxt [join $subnets " "] # build a list e.g.: # T2="172.16.4.0/24AND172.16.5.0/24 172.16.4.0/24AND172.16.6.0/24" set subnets "T$ti=\"$subnetstxt\"" lappend subnet_list $subnets } # # Perform replacements in existing ipsec.sh file. # set have_subnets 0 foreach line [split $cfg "\n"] { if { [string range $line 0 6] == "keydir=" } { set line "keydir=$keydir" } elseif { [string range $line 0 8] == "certname=" } { set line "certname=$keyname" } elseif { [string range $line 0 11] == "tunnelhosts=" } { set tunnelhosts [join $tunnelhosts " "] set line "tunnelhosts=\"$tunnelhosts\"" } elseif { [string range $line 0 0] == "T" && \ [string is digit [string range $line 1 1]] } { if { $have_subnets } { continue ;# skip this line } else { set line [join $subnet_list "\n"] set have_subnets 1 } } lappend newcfg $line } $w.note.files.txt delete 0.0 end $w.note.files.txt insert 0.0 [join $newcfg "\n"] $w.note select $w.note.files $w.btn.apply configure -state normal } proc readIPsecScript { w } { set cfg [$w.note.files.txt get 0.0 end-1c] set f $w.note.ipsec $f.keys.dir.ent delete 0 end $f.keys.name.ent delete 0 end $f.t.tree delete [$f.t.tree children {}] set ti 1 foreach line [split $cfg "\n"] { if { [string range $line 0 6] == "keydir=" } { $f.keys.dir.ent insert 0 [string range $line 7 end] } elseif { [string range $line 0 8] == "certname=" } { $f.keys.name.ent insert 0 [string range $line 9 end] } elseif { [string range $line 0 11] == "tunnelhosts=" } { set tunnelhosts [string range $line 13 end-1] set ti 0 foreach ep [split $tunnelhosts " "] { incr ti set i [string first "AND" $ep] set ep [string replace $ep $i $i+2 " <--> "] $f.t.tree insert {} end -id "T$ti" -text "$ep" -open true } } elseif { [string range $line 0 0] == "T" && \ [string is digit [string range $line 1 1]] } { set i [string first "=" $line] set ti [string range $line 0 $i-1] set subnets [split [string range $line $i+2 end-1] " "] foreach sn $subnets { set i [string first "AND" $sn] set sn [string replace $sn $i $i+2 " <===> "] if { [catch {$f.t.tree insert $ti end -text "$sn"} e] } { puts "IPsec service ignoring line '$ti='" } } } } } core-4.8/gui/configs/0000775000175000017500000000000012534330006011530 500000000000000core-4.8/gui/configs/sample1.imn0000664000175000017500000002001412534327775013537 00000000000000node n1 { type router model router network-config { hostname n1 ! interface eth1 ip address 10.0.5.1/24 ipv6 address a:5::1/64 ! interface eth0 ip address 10.0.3.2/24 ipv6 address a:3::2/64 ! } canvas c1 iconcoords {384.0 456.0} labelcoords {384.0 484.0} interface-peer {eth0 n2} interface-peer {eth1 n15} } node n2 { type router model router network-config { hostname n2 ! interface eth2 ip address 10.0.4.1/24 ipv6 address a:4::1/64 ! interface eth1 ip address 10.0.3.1/24 ipv6 address a:3::1/64 ! interface eth0 ip address 10.0.2.2/24 ipv6 address a:2::2/64 ! } canvas c1 iconcoords {264.0 432.0} labelcoords {264.0 460.0} interface-peer {eth0 n3} interface-peer {eth1 n1} interface-peer {eth2 n15} } node n3 { type router model router network-config { hostname n3 ! interface eth1 ip address 10.0.2.1/24 ipv6 address a:2::1/64 ! interface eth0 ip address 10.0.1.1/24 ipv6 address a:1::1/64 ! } canvas c1 iconcoords {120.0 360.0} labelcoords {120.0 388.0} interface-peer {eth0 n4} interface-peer {eth1 n2} } node n4 { type lanswitch network-config { hostname n4 ! } canvas c1 iconcoords {192.0 252.0} labelcoords {192.0 280.0} interface-peer {e0 n3} interface-peer {e1 n11} interface-peer {e2 n12} interface-peer {e3 n13} interface-peer {e4 n14} } node n5 { type router model mdr network-config { hostname n5 ! interface eth0 ipv6 address a:0::3/128 ip address 10.0.0.5/32 ! interface eth1 ip address 10.0.6.2/24 ipv6 address a:6::2/64 ! } canvas c1 iconcoords {540.0 348.0} labelcoords {540.0 376.0} interface-peer {eth0 n10} interface-peer {eth1 n15} services {zebra OSPFv2 OSPFv3MDR vtysh IPForward} custom-config { custom-config-id service:zebra custom-command zebra config { files=('/usr/local/etc/quagga/Quagga.conf', 'quaggaboot.sh', ) } } custom-config { custom-config-id service:zebra:/usr/local/etc/quagga/Quagga.conf custom-command /usr/local/etc/quagga/Quagga.conf config { interface eth0 ip address 10.0.0.5/32 ipv6 address a::3/128 ipv6 ospf6 instance-id 65 ipv6 ospf6 hello-interval 2 ipv6 ospf6 dead-interval 6 ipv6 ospf6 retransmit-interval 5 ipv6 ospf6 network manet-designated-router ipv6 ospf6 diffhellos ipv6 ospf6 adjacencyconnectivity uniconnected ipv6 ospf6 lsafullness mincostlsa ! interface eth1 ip address 10.0.6.2/24 !ip ospf hello-interval 2 !ip ospf dead-interval 6 !ip ospf retransmit-interval 5 !ip ospf network point-to-point ipv6 address a:6::2/64 ! router ospf router-id 10.0.0.5 network 10.0.0.5/32 area 0 network 10.0.6.0/24 area 0 redistribute connected metric-type 1 redistribute ospf6 metric-type 1 ! router ospf6 router-id 10.0.0.5 interface eth0 area 0.0.0.0 redistribute connected redistribute ospf ! } } } node n6 { type router model mdr network-config { hostname n6 ! interface eth0 ip address 10.0.0.6/32 ipv6 address a:0::6/128 ! } canvas c1 iconcoords {780.0 228.0} labelcoords {780.0 252.0} interface-peer {eth0 n10} } node n7 { type router model mdr network-config { hostname n7 ! interface eth0 ip address 10.0.0.7/32 ipv6 address a:0::7/128 ! } canvas c1 iconcoords {816.0 348.0} labelcoords {816.0 372.0} interface-peer {eth0 n10} } node n8 { type router model mdr network-config { hostname n8 ! interface eth0 ip address 10.0.0.8/32 ipv6 address a:0::8/128 ! } canvas c1 iconcoords {672.0 420.0} labelcoords {672.0 444.0} interface-peer {eth0 n10} } node n9 { type router model mdr network-config { hostname n9 ! interface eth0 ip address 10.0.0.9/32 ipv6 address a:0::9/128 ! } canvas c1 iconcoords {672.0 96.0} labelcoords {672.0 120.0} interface-peer {eth0 n10} } node n10 { type wlan network-config { hostname wlan10 ! interface wireless ip address 10.0.0.0/32 ipv6 address a:0::0/128 ! mobmodel coreapi basic_range ns2script ! } canvas c1 iconcoords {852.0 564.0} labelcoords {852.0 596.0} interface-peer {e0 n8} interface-peer {e1 n7} interface-peer {e2 n5} interface-peer {e3 n6} interface-peer {e4 n9} custom-config { custom-config-id basic_range custom-command {3 3 9 9 9} config { range=240 bandwidth=54000000 jitter=0 delay=50000 error=0 } } custom-config { custom-config-id ns2script custom-command {10 3 11 10 10} config { file=sample1.scen refresh_ms=50 loop=1 autostart=5 map= } } } node n11 { type router model PC network-config { hostname n11 ! interface eth0 ip address 10.0.1.20/24 ipv6 address a:1::20/64 ! } canvas c1 iconcoords {192.0 156.0} labelcoords {192.0 188.0} interface-peer {eth0 n4} } node n12 { type router model PC network-config { hostname n12 ! interface eth0 ip address 10.0.1.21/24 ipv6 address a:1::21/64 ! } canvas c1 iconcoords {264.0 156.0} labelcoords {264.0 188.0} interface-peer {eth0 n4} } node n13 { type router model PC network-config { hostname n13 ! interface eth0 ip address 10.0.1.22/24 ipv6 address a:1::22/64 ! } canvas c1 iconcoords {336.0 156.0} labelcoords {336.0 188.0} interface-peer {eth0 n4} } node n14 { type router model host network-config { hostname n14 ! interface eth0 ip address 10.0.1.10/24 ipv6 address a:1::10/64 ! } canvas c1 iconcoords {348.0 228.0} labelcoords {348.0 260.0} interface-peer {eth0 n4} } node n15 { type router model router network-config { hostname n15 ! interface eth2 ip address 10.0.6.1/24 ipv6 address a:6::1/64 ! interface eth1 ip address 10.0.5.2/24 ipv6 address a:5::2/64 ! interface eth0 ip address 10.0.4.2/24 ipv6 address a:4::2/64 ! } canvas c1 iconcoords {384.0 312.0} labelcoords {384.0 340.0} interface-peer {eth0 n2} interface-peer {eth1 n1} interface-peer {eth2 n5} } link l1 { nodes {n10 n8} bandwidth 11000000 delay 25000 } link l0 { nodes {n10 n7} bandwidth 11000000 delay 25000 } link l2 { nodes {n10 n5} bandwidth 11000000 delay 25000 } link l3 { nodes {n10 n6} bandwidth 11000000 delay 25000 } link l4 { nodes {n10 n9} bandwidth 11000000 delay 25000 } link l5 { nodes {n3 n4} bandwidth 100000000 } link l6 { delay 25000 nodes {n3 n2} bandwidth 100000000 } link l7 { nodes {n2 n1} bandwidth 100000000 } link l8 { delay 50000 nodes {n2 n15} bandwidth 100000000 } link l9 { nodes {n1 n15} bandwidth 100000000 } link l10 { nodes {n15 n5} bandwidth 100000000 } link l11 { nodes {n4 n11} bandwidth 100000000 } link l12 { nodes {n4 n12} bandwidth 100000000 } link l13 { nodes {n4 n13} bandwidth 100000000 } link l14 { nodes {n4 n14} bandwidth 100000000 } annotation a0 { iconcoords {612.0 492.0} type text label {wireless network} labelcolor black fontfamily {Arial} fontsize {12} effects {bold} canvas c1 } annotation a1 { iconcoords {142.0 112.0 393.0 291.0} type rectangle label {} labelcolor black fontfamily {Arial} fontsize {12} color #ebebde width 1 border #ffffff rad 25 canvas c1 } annotation a2 { iconcoords {492.0 384.0} type text label {gateway} labelcolor black fontfamily {Arial} fontsize {12} effects {bold} canvas c1 } canvas c1 { name {Canvas1} wallpaper-style {upperleft} wallpaper {sample1-bg.gif} } option global { interface_names no ip_addresses yes ipv6_addresses no node_labels yes link_labels yes ipsec_configs yes exec_errors no show_api no background_images no annotations yes grid no traffic_start 0 } option session { } core-4.8/gui/configs/sample1.scen0000664000175000017500000000172612534327775013715 00000000000000# # nodes: 4, max time: 27.000000, max x: 600.00, max y: 600.00 # nominal range: 300.00 link bw: 54000000.00 # pause: 30.00, min speed 1.50 max speed: 4.50 $node_(6) set X_ 780.0 $node_(6) set Y_ 228.0 $node_(6) set Z_ 0.00 $node_(7) set X_ 816.0 $node_(7) set Y_ 348.0 $node_(7) set Z_ 0.00 $node_(8) set X_ 672.0 $node_(8) set Y_ 420.0 $node_(8) set Z_ 0.00 $node_(9) set X_ 672.0 $node_(9) set Y_ 96.0 $node_(9) set Z_ 0.00 $ns_ at 1.00 "$node_(6) setdest 500.0 178.0 25.0" $ns_ at 2.00 "$node_(7) setdest 400.0 288.0 15.0" $ns_ at 1.00 "$node_(8) setdest 590.0 520.0 17.0" $ns_ at 3.00 "$node_(9) setdest 720.0 300.0 20.0" $ns_ at 8.00 "$node_(7) setdest 600.0 350.0 10.0" $ns_ at 9.00 "$node_(8) setdest 730.0 300.0 15.0" $ns_ at 10.00 "$node_(6) setdest 600.0 108.0 10.0" $ns_ at 16.00 "$node_(9) setdest 672.0 96.0 20.0" $ns_ at 17.00 "$node_(7) setdest 816.0 348.0 20.0" $ns_ at 18.00 "$node_(6) setdest 780.0 228.0 25.0" $ns_ at 22.00 "$node_(8) setdest 672.0 420.0 20.0" core-4.8/gui/configs/sample1-bg.gif0000664000175000017500000115722612534327775014130 00000000000000GIF89al:$*&*! *E29&48.?D7@LhOQPPUH^dVZjM[kH_kiljfuXnsfp{pu~yvg|vxnx}{ĞϪȤŘ¥ЧĥЭ˴˥ǞôÛ¡›âŤÞüŭðijªǠǦƧƭںŴѵɨ˷˪˲ˬ˹έʺ̿ʳ̴ϨμΩѰжҶаӲҳӹպխմ֨ԮӺ׶ֶ֪Խָؾظڸس׿٭޶޼ݽ۽ݷܸܲۿݿ߲߹޻!(c) 2008 the Boeing Company! ,lӤQIAYбcÇH\ЍfTfM =覤6(SLD:&GJ3fJnYN͜/M9LCY 8UrPGNxNCC1fȑRi!+ &xhV--"%؅ \Uܠۅ EK8ic&$טlTIȕtR^ͺjo&%luyZ[X WukyȓMslI96ӲW^-o.y|ޝ~sZO(nnQG'ݔRVNar 0UX^0\ b8K5" 4h(7;DC/'<£'&Rij]sq7T9K4XF5䐃n$R5DND;0 *lb&Iʞ{޲&y Z8FtR`$T+T UBGKFRF8Tatq` pvF fఄFPњj.8!\+Z jhQ &D '"B$ʞ@j1 !4DD$fcőgtĒK ,FQ5(dDGHL5řTjuQ4H7#G]Tk&iAM# t`K4p5t@aO5 a[puAHJrȁf5URԶ!#`$|&5D M =3O[q qU\jUwt^'/a(zG+ht?!Rb0)b|wП -H3y)=㏡c"M8…6JrT2K.2Kr>(+5'?f"TVu ]Z6A@I"(|$V8Ao└ D#T_ &.I.A‘WAlc9mefc8jo䁎U.5D4>E6xu)=ڝy&%*Ȋn/7. iCyF .s ꡓ#N`ժ@eٺu9ujuZǭ&x;@C8a|=BЊ{C- Npաxt |k# kxV#p \a :EWvmO} v8'et.o1W!\ʌAZ`( M#V턒W2 薕SIOݲA*ID1 [y0<$OIb eT 50ĢVf|##ynDBpgzQ[8D* &a*#B5P36!*GV X24\ lrh#xVĢp@ASCr̞5t1:kN5^ta?ȇ:ɈNL")`:TU#ЁF= у ib~tiph? 0k2 @ %NR%08pWV30 5` @Umf'*p 0U>PU"Z2t'[3Pm 0I(% *H ,dZ3U(+P\>c G,`'\(+T!_/ o weG?s/(=(pn@tWpHGHT13 `R;qhW7I#bQ `a7 4fG :v+%wHHw?`)6( q\a`K rQKMMM`1cmQDn+pIo!ODzqz8ACA˱%N$9? yر0 N<ԗW!'7Ñ1}1|} )7CbD'~c"$$Α &!y& 9>i #0 Q7R 0GAAxh  Vx @ x Cp-&G0NXQ2 6'6U ( @;Q p r H,W~Da0o;.hbZy)Ek[[K GZu\9q1R0GoKp]-Y r@CGvr`GG.`  Q6S1`q@]`)t<4 #0&IWG1Yw:cJ/umo;D/B |3@1JSd #ItGw7v`+!fw„+PKJeIiy?qi5`{,P} fmsS i;MəSj)P !ڀ Ih# :A< I Tu> 9^Iet : C  1ɧ3 ?~ P  ^¨:  @&t { V9 guhx`p`W36fK 'xҗ; 5^vpL> 6^/\r*o+\w0aY2 eWX$D+BC0 +)T[,@. ݢM5+ p^P Ew1t6Ui ô h u51)1*001)`H 2Rlؔ%F_u1AC-1)7I_"74++4DEUyd_[)Rt3k qkP]1$>ƣ$ƃ ے| |bxymSK6tAfgƧ+q ۸;|,>hR(({n@4vQpb} }?`: "c`&v $4 $*k4Wx-p Wr% #WE&(xC {LBpYYeDBi#( F@pb*)n9!9A5qNք3wKuo ԎGV'<(P s-Jl҆bz @sFnҜm%A3ms?  /J4}F2"u@u#{|.gNtW':B0v&k3awJ>_FbRKfoWU- qJ[-Deo Jɕ Ae7 "ꓶf 9z{fC0y0p %^ H X ֫RHLU; .RDZmpbŒp[P/™v."pc0.`[3 +dbE+9@l*xr N @" 2q X*q YJv٭qb`ْ1. )_D)i)I3/"N}b ђ۠Y}ΘY[J &nNop3 ܥ'OP;8`k ˸nr-'QbҒl!S}Ǥ WÌ\&/'Iu>I 9~ycp~" xF 5 XS0gpuF@` `.V0X/X۾?WlVAVJ  m-x-IM̴9p8R+D΅[pvpb)~ 8PZ䇇8qmX\~Qp)px+7qq'Ps<;wo`3 6 fK3`"H%; dQ)a}mu}-Ǘprk̈́_NGwO`-KTHa3U <:f(l6qQb +VR!BmܴI&"7-ᘁ#/t5męSk.tڪM˓) N g E7pNasX9lMVZ0ZKV\u M]DҎN&`j F|+P>=YdɛH}tI7#~X0&Lj֭]& ڼaaBl{\kmuFƚ5սF}M\ T=S|3E)T"J2^٫G)3G,Y+IznDy 'Z8b$!HHz&r.,'t~)P8CR{MiAl:GdC"*"*8#jc%>zE錎#J;"a5h@>th5x VhÎ%\…%ܰC7T8hӆ4d" FTɑ3NU1m[R`p F\)WzӻnahpλjRŹ\%s?0"'F^u'~ydÊӣ#AᓘAH{FtrW:#HB$3HQRő4Rnv6 r<&ܨ 7 :% f;@E ~T05 U`:EbZVK"f l䠆K sPPw$"VbwիeJb g kb6,q(($6 u+ٌe(r+)@"R| zSAJ._'JEp!E`6Q%bc`RDCt鱝\HdmOtD $ ĒꄕLU9†b-GQ[5D͜=Bh F0N95e1([>'c_kKVLsw(.qEol\HFE5u 7h0[5^uBAP"RauB%P~<Ax;!{xC<ѓrhL=:*L!D%JG rEhEDTRu@O.hC4$@Gm B0KV <5y 6tBہh)G@PG4C % r !)WnGpPA,V Ap6DTA@\"lC`\KXJg\eXkN:|[,r[1"+꿪ٵLp (>+ǭ,~ $.I AᨴQtW/4!)>H4)LÌyj2f[Pcm=qmpXFI MJ,!E'J" JUOr m~f-\MM`7Dh.|3Rg;G lb\PS(LcEde팻-7h1AwEF4Ѹ rZ`}{(D=X! L`BdTAx5!RCj @F@NH|w[AEj(Bv8:裓 UN'Rt ] @3:vhCCdŒPH+fd4px乔@N9zH'@B,7 $YqS9 `.N4*2 CPBp)CE\O9:[l(p9V^ܥԫ/@i5H5]IUSsh !*:[qPMIH\ٺ&yE`$!?ɪ̟qu&hJ#Δ ˊ!6$^KI91u@9(נ)!5AIKVJ$\AOH?\#6 6썒z#yş.Dh >fB|Z+Y0w@ЄO[d5e1H(l5†?XŹ5`d5a<)0!7p#h2Q7jˇT(0p6at$`vZh{I{ytBItmKS'B&V؄Q؜.R%_9܄@>ؚQ&~H9Xc* xÁ *E<r^Kz-K (7x:C"s*e7O3:KS1KKj;/1c=aC0Sz0 (>{qS+Qic# -oҐ- %똷s.kPXY& Hh`#SE>9˅qB ?9hPuAȆl@\$B E4؄h4@T4!GtKapX@xKנ4kkH[j=7e#*6vj#!7BȪ$$Aqv"!@Iqo`jk(y=≂qȄM6ܜ7%OXa:*HZ#i`3Ya!58+-\X7؄)-GުY8|p%FB#HX5?GYUeP[O 8h ^K:قK[)#{/W (8Q\ ^CjGwԼ> #l£5tt;I- 4'@_Jh?;@3?34ʹP4s4J  \]8CC&WP `ȅt{#x doZ8(l5* e+C0qdu0cC A*tcXŸ:B,#*.q ePU@\SX\eL`A"dP6+%/aC!8Xѓ7qN7(qiOLE\D,Yi= e X)CP-͊ 2e,VTC::<#!HM=LhPXHiZxPR[UP(I>"fԯ#Ѽ;\Qΐ#иQ-I::JG!]=R$5"0sȕQ%+ 38_9~$]1*VTDl+*@i; ,ȚІ_AۍM-S,+ĚIqB =4`0;.@hJm0iXTUVeKի}*\8n`M`n`\f}@cSSgxx b\0Bxp(q:lp}c۷TLvpq(6hxB6z={U7'7YC( idHV0OJO)}3{uSpLjH0 M8_$raEV<6 T X2¸ ғ+YJ3Z9qҟ;q/ @A!Ȃ9e15 TXJBȅs[ =RRH#lTi2 dƢgdUi*Mf-Q͓Q1eGwQ fh9x#Rv#i*=1R*] iRuYZ߆Ѥy!'9b2:XM0[ _xP^uzX\L45M-c,:(_8>ͅY_A@dkTm5[՚F?ZbFj^XU( j25 zi@\P() (0c0fcwm'dCy"6=xGHca F(n;+sOW >!2`p(hp(t?PBHHH`V;L(1 j*!a%uKI=@=0,_+0*ޏdP.(+qPf@Z((N흪'f=h`mɌY,:~ے'4}&Vg!aq&(9XPdx ו9~?[XLo!⚃,Ho w1.4(Hu]9 7; q)=H V"Lâɲ.ZF8z()\ 1\G;pW0O c1սЗEg#+ LsA%CU=M^")q$J;  Y:Kȅ+טP>su?Y'4W"1裭w6;W6?7Gos,AkKX֬_OUt'F G?WXuG.pPOu\`hsZh((j˃ (*vA1lXV=aΜq S7q̉Wo<ƍDe멓FˑO*GdӦM:HO#1|pհP@Ty/HmC0_"EZ6KbIEU\1:fVv!8k (6nx0kfɒwյL$8fpAf1Ď4iɑ)!(ak%W1 2e CIU\rԧJ87mib 5rҸ8m}{7}x'WNW]/;6א~|e1^tЈfjM4[f(_wgƆՆaYq\Yna]umWPqH VKÇ"g\W!PH\bv!tBt4Y㉂8"H.N:ؠs5i&נ&33D/xrw`qt"X9Z8#TLM0HM.\BK0f:M0x)NS :j0 3! p0#$] :tZ:)(h8*jB'LEe-# {.2骻.Ȝ.;# H# 4B4{3C*.B*#L -n -( N!C@E3;0BCO=cjo&XC:3O"ș7r32@JbSt% Ii7~ F,ElDC(dvP'}J.QiuS2(i!-R%K<er˼/#LTL\(W3rU XE"fMax^(DAXE(x1sg48>QW7,L2C75Pëa(B/M7P܂L ̗2\;=%|PlB}Rl -HRl,ŠxESALT`AyMH`!x|E[xD x]A * BAt؀ 䈅p[@\ BJ,^DLX~Acq d'DHOj\,z\xֈ(V˹ܟO~mOx|P#A8fb\!gmGlAezTԅAF MF\Iw% ΓPq6[qWPȈ\]ThiC9 : :3È\Y_ WL<~8( /X B )~ 3 %DC#,$7d"È%ү#1CD5 6HC5CDM"ETJ%B.0ٵ8^ԔW~e/i/ A"e,64ӗKCQD:H#P$T B$<rȓ-HC7$R~10C7t+< &d>IyB9'ԍ'7=f(C7pJ)E!n"hl[pɏ|^؅&h$ab ,ApLgxXTS%bA$WYALG0$ԁ ,M r LSUA]AMA#pF$xLpMEq7rs A#DG-bO{(]L0L()hH.-hy4ʿ!AhPȉ$֏Ёx WӅYH\W]4qEV8qQXyqΉVq4TP]"UIIx xBA5ȃ*Hkn,(/=C=2QRx/lܨ^'qIIWŎ,ABSbQg 8]a!8 Zx%`7t7Cr"82HC:h 8 ń *%l8) LT $pl:\JĠE؟4_.p+LT$E Ĕm$"I2մQ]ցEw6t'] Q-WY)V |f8'%#tUet '@% A,/zh!rpBHnBL.q}xI,fJ^>At%pO AhLAWE΢0e)kѭՈ'Fhe" tM}7|$GM!JP؛ (."垮vUAcO!p#Wdx@{Ɂ# %ap Me%1yðj e  2+$=2<0#Bw-WiJw`~ہUIgCP:t`8Г , 4ГyZ0zzu=eweK0a?|yѧw\鲣K}c\BMaٞyiaf:~ofCx,2 脧FeR A ڀ8 XqˤB9 bT)J01aj^ūUM YЂC32 ȂC", ` Ԡ>?Dvšjbû&D^gAD&/|,vkMj\n+HL '4J # ȪΕPKd ,;R4/[2(zlX6sв#!k ӤZs D.R@\0w E?r_ 将ًpw re_7X򆕆\I8t `/!,r i#2e y4v;:Fу;9Bp@B 8_!(9߉~H -wYN}ӆ夁YJ|0*J_@fu Ydftjg܏Ӕ%B,h4eg"&XM&!"diڏe)0f\#EXe&Jg(aּ!F1BȈL#"زBE !.Zi%*Є\~~rMsjdgF`)RKJ, ͪ#A 6,@܁p5`, n*5v 5"9&n 㸣<1@1C4ף=t@ Pm.A愁AvKr*(tBlv'ΤPDF\Vꢠx5>DR$F$8!K؎L+eKn|ae!nY nf DQB/odo4+Ăa42 `/@ axT T |ao&fb+l`0"YI&oώ^))Z a'F4▸܀[ A^IRfe.T^ioj>p&g` L*+F*l@d09cEf,$!R- c,'*sAD b+hNh"(O&bXe G?-A C G`|7/¡̭ AAAd|KN(Ap=aS<1|l|kK4@) /J BH`Av hv$!`ΡE$0rdbd:AAQBJJH+<4kAv/!bdd=J<@MvAҁtӨ!AuAM>-q<Vkey'lC2vtha\Vh؁ n@A᷂  jaB!2A RAAr\JW T$;8!+rYE16AKO$L0)o$ؔ!=lp< ~ t+VO |"P Uv!d\6B|D ^!\Ҁ fR2 Ld@:≅BMW;F8!XPUTI"_XY P**%7"B̏ꠦJ-+_oɇ΢1gxX#P f-Tu_I\!&+ȅ]ҐE X3>Mn@'P{//O 7*dS,B_5kG'p*a>83B 3dnrV4 AAڬ 2$0(g$Y 2^h9;=`b#  a=dD!nBdg!8r-L! a8d(!G0DO\H2d A^r7KoQ/N anP[ȥKBwb"B"o `deP cH$h\ Z, -/QӀ!#b Ω+R䀑Wѷz _`˲zd:̌U_/Mm' B&ԠTWI`df.XXa&Yz,Z!$$u\b@\EIj CFLa%.{R}7 `&L'9M@dNQ^be'",sK%⍫UQa~İ91Wt#.@-j +:%!Z ,*rCp0aH r }yE^̓u`#pn`>` Bt\D"\w60*$!aK|\O>|8VL!Qħ%> PP2D[(_HjBQDnp;fQ^B~'\K!O^o%g 0A 7`axh~K$ZL;=/#WE&A l/ջrwih$!l=/=d״g`F+pe-# [fDe&-δ, "6T &jVM-i)(-3u1'*JT9iNM-:Κ*tcf;bls7"s)$_l֬hT5-Ŋ\rXEՂa웥 A$k8qҨM& ,Űb( [.if_9~ 9ɔ+[9Za6IDhZ]vJ*=Q;rDƺwԡ]Nۼo+;p¥ˋNZL<2u潛''ON'+7y _B8EjyOۿE>y8F$t`N=Kp)`!tp`$8BV K&@.дN4!AnaFNm,Ffx Q| UXE9p,1bJ|1$JXHpG^~p;FAn"[GqF)ʑFC!j!GahrfIbmIik))FbxbF~Ɩ^rbi9)f\jjV(榖^Z*(%ze C[#JКy戒Ȯe;ImځߚA"'tdN% 5T]V3*|ȡEIWK!,KG4$gOt1O7H ф Mq 3#LT]sUWX[1XX]!LYh) A aE\\nj4aW0[/MGoFuV_5gIfcL 2\+Pr!sOGWN9[9pPmE '" Q2cO8J(܁WKGJ-{p )lBJx-|B+l2ԅ3.AU8b4^I$.P 8ႉUT m\ÂKIIK4ǐPbr@2qJ;d41%?M*h[ p2< FeBPԦFQpӝT;aPP$4IYz2S(Gn2֮E*IpMjBFkA^ !4V" gʈԩ%,Z%(Ȕ&ςֹj$E_[V$,#}kH’DIl8ҋ+(bXE | C_FՑ_BZ@bK2%t]i(ŚPD5\+ԎLfȠ/A J@aCC+wFv̼%H4b1J ^ɚ5l>fk F5h1IDC 2lQ l0uoh987rPRx Њq̃rF-2 n<->~u'0n&'1kF18 'kA6W;C-pd& ߆.U2HB8x;9!7+3!r:((p Up@fb>giG7LTQZCFʉDl0C氇1xpsS*8=JBb=BWҤ 6qWLƢ K2ri(*a%ԉKvXD$,-,WbmRxҰtEj&6ePaУd޸_T$2Y`l4k-qD ZeU&U$W#D$B<ЦP" dt24+c-B(#(? ~9`l9AS|"Ѓ$$I49T>O(2A J&FHt%Q$нx Aw6-G"&y@K DNx" L&AHUJ B`#a.!qH @JI _ڰ_^ ;B6+FdL`517oSP2(:AgyH9Lx(#G b*2RJv, vԡ5D%HD+C$K^!#j~Ki*>r=<ԥ~9q>C!#m&x=6 0p(XG !  WpVv&F#nA_ k²)s%9&(**g|9dD9[] G=&&Ac`o s rrP$S..Bb\9Ń0 Ae;F8d&5*:)2F ,,ru*c|L+L׀Hq_-!!'s[leB& | {aW!xeQ3 ސbL0cKJzLc!46x{y 0ccvKXj ``p b0IőqgSqP 0  }0 d$ @MN p$*|З  @ Lʰ s} u,g:7U0 =Up_!у#scJ"'0;RKT& &u ^##&dlhBsspmq6&D)q$J0>:$+,Phq.* A.:r0AŜ1DZ^4pwU؜޽Ǣ˹=%u Ml @R?sBr]+4#gZXKr҃hq^ a{ɝs#Z$-H]z2r¢ʩe^Fp :jxǔ %g"t W0]t%Ql}bj`Ma KͤLudpz-/0x:аd3 0 #cvI޻}d)P 0p$`7 .p |{< vMK-QN-PpPվ|Ї]_œ@AR N7Γޠ ) ؂MJUnA:U#0>Xi;B;5l"rEL.8!"1EL,>yU40pOU0Pu u'+;"`t(Pisps0Ba1xip6-k1a+8%Xej#* ,X 2&Ȩ*4KIIE)l! uPL]sBe*lRpYU$D%-K'G'GF,ZƛP_ tɀ 1 r?8's$j 3fqJλ_1 I3 7p 'y[3Y ذ}hdW~`p A_ް@ pP@]` pp@}@0@̀ Ӱv x8bg՗:f J_),Ν;z띳7޽q6xrqTOF}bO(ct@"-9͡*]Bnj;"tSNCmڬąC֬iStŒ6.Tiu@"kf3Uykf9i*K4K,iaSŌ:0fc  r3js`kyZԍ94"mHrd8% N8dbМ4vع:٭Oڝ[y.R{m(QHsE Ac@5 pL(pA9B70.n <݂ /C|n;1.tSo 0*Zb*+.J %poq ЁlFirJ(&oԡiPqD6PE.6>KӍ5|8H¿,hD -Ҹ`r` f)j(DiQPlaE"{Qi,ETTS` +c'HfW^{W`vXbwE&_ l~emƈLСo`@oG/Ao=z$?v@>1u8blyCGzT;VGˈByK渜rœQF$N8!F/ZfΡZq6p]dePPR &ޤ̡.3Vp%ɌH:ʅ%p<5i{ D6B*07p(7o $&1TC -Gn8,?XW\cH-X]&ܐ@C-hSvݼC1"3D, C+ʼS/;o׍5ӯԂӨ Œ4P9x@<(B5D ugzz>.2rQon7lN/e*;2jB'ǰ(08Q԰<Š%EIVБ /&91 vc8pC> %4A: :0 0+B U"Tl\!PP3)tS`: UJZլkbF mb%R$V6p\D ~(4h!-Wh&q0ƀ IJG=ZiK;9ayG i d4|bPB50D>|ЂTd긆!yc7K2mt*'B!M̬PJg>;ЈfȰipINQfZ9!OPCgP o -cڠ`zkiw6 7mD` zg=:ڻ`Jd%pB3A [R%h! ͹ I4B)RP` CBQpK@hBl&\k (x!XE@A:AiIZTFb"B+1nQ{/|4aybP3}U(G2x,82V.o@=l9z0 _:I, Ùą0yK02&Ԁ8KpSsNGȁNj-{Y(:t @?`t2 ^$*P L Cz6x `:pD*1H,]:(nUV VMB7/Jk6;HPU"r/TC=40h0jK2nr\ζ2VbC]Z8fsnGpMNByRt >&4!hK Z|Y3j[H-'q =DEt'T(A uH1ѸF9 9i.jNmyq"D`4bPAp G`#z U Xy @Tt҆=P A$`X#[%k`. ] &@ R#@H` tl/`dCHq)[~WȄ|x=69c3:qrІ<۳Ox?44J}q?dDe0 M+N@pr)W쀊CM,:ӈAA 8X!$H97U+j68!W>0UAȅUPU`PCP8 Ȃˎ38(:H8JA8⠞*:J:ߘҎ@8h +R p9s94*A+Tq:3Q ށ2ƺ 6 َːzz6)1Tm G9{;B39ڍ8ꐍ4ȂC4%#3C^ [YS(Qs(C0wympZ< J+Qk80R_I\U1@ 0n>JXX8>?X qXXU@0DA8x6`D䄄шI -˞߁Px4 ;i ҪBDZ j9`/8Y:8* J! H"B` >Q,KrxSqop,aKhL 32S0Ӭ->;1E19@.3H=%D_(0[qG<0u?{kJ1HG!iSY!C=|&`pIOW`!?ajk8YJJI./8I[i`@*ZHhP?kCJh<0j(U&Y.u{xK;,WsKM(iTzxe Lm H(X1;H p06pYR5# b!·`X+P:AFL̂\PP1\exPWQ"WxP:W@PB4I̎8Y퉓:h9gKĸ#8D8PE-R9 6Ij100ٓPɂ` Z " (yH 9x:ؠ/-h*pųA.}v9/$ r#ESGȝ]QCA1?KQo0(Ȧ{WFņjRp԰)hu`0J`aO-`^Ɇ`t\W9C\$[pGTTІhSfIZr_S;UB= ȇ|x+xp}t@4W%KtHW v4hO(PP0w´W [ p8YX5Yc0@  Hacي-)-G*Ki \tٟjX!hA@1U.=eZxuW8>T1UCBσͱA9(*,gj!,_cZƩgi.xF+9q۾]X8oGPKa+f Jp] JH(FXٚ6P^ideCW{PM=hHE#Tϛ<ڡhtHI K%zS.3anVK\\(bI Xx`\b&8]C`V"K?9גb(P(m>=Sv(ڴ.@L8ph耳P  8 މQ* 8=ib^XG?B0Ԃ;.RR:].HbC59ee0`8T@?ZP^F ߍ7(f+{J g&1q/DJ͐0yeJX$q-8ArCJ I5` J]r|&  s|/@P8);H(O8hh`=YA8T0!,:4z @ha Iu.0a8_/yx9nhSnHT I*c%&-AdȄ!Lp!ÆB|Hp6ZFL6+0 Jm!4a@U!AiaDŽK/_NU.>ѤM#`G~#D)` qr]Qٛ7Ϟ;tʡ +v,ٲґ F)T(P0&wD*ҭOH}JxqzC[EPe5Y$%M0ą͇,Y@Lg+TW ^e .NhcmܔN#S: ~Q 8WQ t3fڌg3j MQ9ijRJY.Tr~2"H`0K,@`.sbYnl "FIRD ڪ 1|@ T(AZT6a'=!Utx_#~pR

    aӉ3[b79.Xç RpUpj#@Di `ATAcCKECg8pyc#na'LE3f\ fBe) +>DBv8"05Bc(Lt?6G$ ]T1J~,6)(7ZHdP4"w{Fh MjX0X-JPbTjǮgih(1C\p2[ %GD"sUϐMD뮠 u$21 e]r`ArР&aYH8-4I!)ls,gЙ [+"M0R9{K tT.21e.eGk!6+ВFea#vU E# X^a Ը0!G<0|BY,P b9t' +CWvU9 /bA &GhHmN$ {^4akO5-G52èP6|BPW!HBQD΁Vc;(G q{b3%$rEA4hALu oݦ8Zu(("UQEe?QU`!M{72QO=Or>U6 L \Є9jAA2\u\iPBue4p/ Mx0B ( YI߅J(Z>9 \0E&@ sc@m8T lhY}Rz8K.A4T,(N32^Ih&Ah@ 2.U IP'02+k9'l _HfpIac*3!trF*Rq`9ըK&^հ4K8 ܨf F$Mk-N( &9B2%:$bBvo)F9Y4h'X_fODʎԕ'0ЛU](^Qแɖ\¸xݐ]Aǹɴt  Q ϏxU])|heyT ȏ% s\x <U`q +|\@RB:H׈D Iyז`I4E5%!]5,]91+pB&L10B(8FXى)UMȄ *ͨϤM\4+>/1μD8L| hC0K- .S)74K AuJ U wLA"iBB"U]%bbcpׁ݂tXuKM-zgGW8B˄ G wFH ٭8EY0B9T0.l6\^"< ?6ڃlYxc8R(…s)mH"?nsJh xo ZTA0$ԁ0Avy8IȈ@Xڤs߫mJXH_qyU QZ p ̈bY]V(fLjH\LA-ѹH&XI`%@bŕ e=J-gٖtn`HǟU.d peQ#`yg hfܖ AAH&ˀ" "~#ML$A (tܴ9 'NX:L5ʮHŨu\uAL0.DHzRB\XHhB:1H 5B52d)lC72P(; =46k8D7^8VhB$ l)IL@E  @8iYɕb xDUB%g,Jj ԁ X!`c*iH *hiiЏGQ#pxi^JPȠT \B#t},Iۚz[YjxuۨVEw V ۟O^J 6"$T e D8\+s!iS.8L+ hhɡH  `BH|ݹ>k#*k&+a %sؾb!*K%p^p>S.5D#v,CE\|%Sɔ 7D6% %HAװC,(:(9kFلm' ߘ9/ߌFlM oȆ<~F| kr@HTfi@b=uY'BmƤ(bJ=+ MIy8 k5yt ch"즖)3ߨz ڐښjcG  ¸hй,Q^% Te 2. ͈wȔ|.]fc=-v!8$mx"$S$_Ԇ}|UpupB 5ѳ& T@pBKG JՌ'rp9C/)tB' \+ +D' W6HcO)4KǮHDӢpL6$V'CTC:=h^.H,:Wt#:6PѺ1@dMސ+ 'l HHņ@\HΣq h4U݉}H i9k4BA#+xrHRZy ǧ  VUs NJ \¹@L{JS YV5С0.<>2P5' % MiΙ+:z]ʸiAq)4Zh% ~!۟?9mrAAtW>QF -W\{E|ꢋni1t.YQmq`ń\ҡ%&V$m&\dbQF_F!k?` iJxa$f0.˜yALt '> 阣PBKԆn|d }H7i4J?@V }!eH ⬱%pX…%3Cu R] 7p֋P=u Zj̰58hB5 7HHb(ۻbc AP/F @hR݆ƽHƌ:*-pk(6 XXrju9 Qᒝ̠/$>;J@kৎ#-)+5P"+9|ZKBK8Ђ !e5P# !*C`,l\vw[AYۥ_8;.b Δy5rf:B8 D=E+ۮ;i\1&AA,;4E7S?$<WFBO,PCS=;WETz1sDRoQmH酁RjhF.F-2+؟|8bCXnF. `0}aq rQa<N8B v Ep (:( /jንBP+@A PAl1Ũ~®%T\0Ik*8t Әk"pXaV2z#M%E -Z,_^iFsXx -!:H&Q2ZA_JF=ƪ$I⦒@ h GPaZ#ņ+$dH1oq8 AŜZjހĕl|54+iBx2NP*;I@ifIɵy%$#LbQ=K Sqv[9E)*4! hYSMc AUIݎ7Q \8bs !!B@:0\ 캏Tv "-&DPwT5EW$KyKjR > ӠFSU}`0EQQ6P({Q$ZL_}|#Ȃ-Zu$xsQWt+^#A^}*Gx¯Ĥzu+S !" 0Dv!A9B#ͲSyDV :\BrLghBQ&mw9YX! sD!D@ju[cF9Xvxpg#+_amHߑo|Gݹ RPv M;tXhް4˂YM0VҀ  P{#o*ԫc+1mڦycX IL ШФ#.`56$& v() <*-ZE ,f ul% W YH'"t${O< RP(8hh Lc"E/FӸ .!Q:4b%hU #*S%Kɟ50pQ7#CGVA|Z f  !dOJ@A EC-+ܮ NaN>aEHp HUNe5tݐ MU . !/+A Hi &e*@1tr$@ҢV@ `TBas2e , @ _$Bbegv#%vl( L%,)2$pN p' j7aJG @ KsLg#f(-2B B*Lu@VƠDi' D 48♶b:iT #02)Ë-l3* e@t\VsP|yE];!VA7NL@ 6j:$$JAB@!6Ш#G?~ ֯F^M?p!qMվHn?HT$VƇ{\':.a/cҶ'9Lj4JX!* d)jD*OlrGeO,Ų3*$T Tde Be߂eb` ^0N= !nsAxn ~Nf >.C.Ҩ22Bq / Ĩ Mi @:KA-!LkUPB(h(TQ`TB(@'P8, 1ߢ_t $;i&0!@~, Fq-z.3*If @?@ ` a a; 23B3"Q"1p-H30f"@n "XL` $3QyA&!PaqF`r4Gp2!j!cGD ,-"3JgH~AbaP!~>$o$H HO?nGbh&/'|!A JGԄ}Fa @M f`r A*ѡ@j@DO4BBOwBuSDz+TeRBeFtU"f%Ғ2CrC=BNqA0 4!`$ȩ&5*&T"JSUd^8ZiL vQ3)P,BgAUAU[l:_+o(5nB@) \J9d/Za&ԁlA.m^H*S3uڞ4J6D#=#6Ip!$¡LɇJ ͤԄ9PN- ^2(sD(ͤ5 dQQ#A&OXj,)R`,T-0^ !:@< p` 8 lh2id e(zmO !rpleJkP+"30Ɠ#,GD`U)@ 3 V $"TE_4C5:Nl%#i /^nBc ŖjlT h'c'14D:ݢ(TB(4 \f=b.A`E"b^4iHv)fn` 3j#$%$S#tYFX/H)kʰ#v fJPa?8pݖ!4hǮRSw6Do9:GrGsxHfD|zqhqa !FYOqr?:!X2j{c~ Ҫ)O7u !vu3Q0d7wQBNșn71p@VɒB_ f^"+iΔbr{_6"aX. W!\fL-[qnʃ~d# j @3뀥˞U5Ɓu+oN'dIISZeItxj@.+*h'fF;cm0O(ʚOjl$%xɂtPs^؊EC[0I;5)db`**c㖐 /:r!abaF`!:X=)H6I!qm9M3r?GtJ^Yz?&pw+?y+9KW?BYrA 'jg? Z !}mؐ+OKRQS1ȹ{wRRU54U@P‰;c\d8aPΠPf'@^:U|_/)yd"ĕ.A2(1Π2ٕyM%U^F0H3֧7z #`'4_ #iflp^i^1m/͐'* `"f:> A\>Pcf e Fk(C ?Fdqd"ѪIm:#"7ܩ`S l FAF@Z[PhNTHٰ,[;J? a(;z*}O?I!t@ "YpNaC&( a,j)v g7?jnz{O$+u۹ ۗnC%".e V\@5𥋡 %#.!j8Y a`22Q] #UTV!P[&Fxho= ],+T.#nӊ1#@Ү6glg;.e?!(x@^`UlȻ3fFA`bb.sCf*c2 [Xpsd'm뎒|bN@ B2l ˼llzbar%kG**ёjO¡A}C[e?F!FݔiPaմK,C4W JDB_BjCjAhH 9p9 RAUR=vpR{۷ {RH )%U,5fִic&"*KI#OԠ4hМAjJi4(Mc%W ƌK^h@K-*U8tfb8mҋKjhY6K\i5P*kVِjՉ۬܆jqB-Z"d4gaՉ+vsABqC *TSgI@3R4UaϚ[Uq 7n دh{נَ36JHJ30h 8%V10D=7taPOU7tAuYBI0q `s:3ω#3xK;@:D#͍C)؂K6)DiH9M5ڔΓ#%6ɕXfXn+,9͘dih9f@ 7^/dcxL.Ҥ# |L0 +ɢ6&Y(Rh(Ԓ :`%4 y$4#20P3D i3n8Q lF@ `"EPtK!& Մ"A%E J NpB `~" >q#P">i~jD.9K5= GpbQr((Pp+~W E :\D$R@$+jp%AjC(D2d \l]x$p BA4&V*kP$  X0,A 8~@=>ρF3qbf(H$7pqLyȦ=!av T%Yh<7 otg ?fXb '0LPgBȽD2s v~RsNFIȈnc./sdzЙⰡ \mX= 8:TzXѰэ2H6ġV& KJ(+D-8n LCSUӊo`~[  l!X'#قsA HtB\QPX#$~ mlu|xR0 \PzBjCXA DxV#JQR9lCYXߕ+H<^jDŘb`_ <Eaˬ -6 R\"Υǚ9ODXDeuP4Ma!a 2"QH sqCȖ8XVJ"t^V:[!t4T j`d -TĶ6Pni(B#P3|KI(t+=827  ƒ,f K. 79g/+1 җ6_&HXpsN1i AlD"Bׄ',LO@KLEt6,B (0HE#Om7թzod2v}ObJh%,Ȥ?6f:ҍVT൪AMCT*`@pL6aqX.=AY` C,!\\gC+`h+!aPDl[P !6Aa-\mbnDa-bCG1[ }εl( ,-!kޢ2n$9PA(nCQPN@B6u0X:8` QM *!K>sEƋ'A"(N"SC!@u @ Dhfz[(j4 N>>~6@IŒ\тK0p" ZHL7S%vg@9 cwdUat&,51ѣ< #-  Hk=7R&&EkC%`,VRl%a#ж$϶؁'E( | V-2 ;$`WAnAB)?rDY ) ` ?'pP ʀQpQ py@qw qPq %`En-|l /s9.gsel[spY,%G7Be`Ogdi{S6ǣ0@S@vL uc#9ǔ!`3P@a,.w1+5'c@mc`#e Y"Lf0 ` 7w`8ye6M1A6{k\bl:TC_%& /%3Q;g'M4 v~g:R:cMQ}fLy mc!d| &[bf4a^B;/~S:';RQ rv Z B ;`=;Y'0 `k7"*s&X(A]@!l %eeV…V.ȂskXu#:ÅI2  )0 }#"pn@pEAFlص L\T p  pXD*YuE 0D Rch) y`NDGypސq WE#-raY' sbs.(Q psGtt]%u KNP!wUzW u8,U`1'1+ja&3# f& %`rגk:b j `d BxR8c1cA 7h2ꨒQmA6@spUri bKy:#wRaP1O;u|!cG1Y# 1;By r0| y^JGt~2Kta4$cRb N! T3 EU@ UALR&?ci$6'iIE *-t(X6I*c`n3 SӃ ̰Bnr ʰ * DoҘE *>$@ ĠO/`ɐ" /0+J0ƒOr $!gE>ɹ,bP`dYF %I-pt vwDGWB^dAbim8Ma'J1ZvB.=o#gQA`h ).Pa.pG[rx9" :; !  , @3:Q&x 2JfqX!* {pf7Fo*_| wи;foPac^륨s4'77sz :{fnP`F!eLcD~5;~Q i`0" Q6 @#F*C(L?F&^| :Ҫ]%%%&sy.pBr*o # d*X[ :&zWDA`y?rrB?]Pt P) p$ |YZV5p D0ORP_r)  ( 2(:8\fU.۹ vx5\Gg:zxf+/UvWj$c6eb!3`p`1MAYI bM!wbмew,Cv]}qq/!t1Qw^apPUn.6*sFMD!f`9(ujH  6?s q{rKnQme!\9gԱ'K蕻c:| ёuf38Շ8,7щtlLLW%:J 1 &"  ,Z#C&V7B|Dk '(4]6Fntrm;$Ӑ & fb>+Z&BR3]lomd Ժ ! #< (Y|y*xu Z/`p7<N0>Q @$[`WFK`'P®^)ō0J<)?B)o )-m0K* Ő ``CPR"' Qp1A Y MR0 (NF1wP 咇\^rmY\(E2o2c qins"B Sg!o۽/i #b=` Sȓ0Lq5Q80`P9E3oan7cr1dcK5W q^q1 ֳ┼P`kl{n ^Pݎ?5h0)1[ResARQSQ^*M:'n(o^Q_9:vQw/&|v ({J uxPhpF<1A~S\f;DOw`&8BVu0?@x _ `KNu 3"O"$@ O  opN ۏ,@ }Y,kV`=a&6^z"Ki C0ش_HD -"D0jk(R6mʓ+ ʼnS(H#P<}TH\~&Ra/>(-gȤ X-lV=ȐS9~^i1$8q•#:U+'-ץ1Cu׍SPźBRP,=9[< SZd T蔠TY'`K P[=ۘ19HSTW6 ;o 9R: i$ ?FXZg\欴)}ΚdsQGТGt 2@ pp'*ᄦ8∫lj)f 7&c?9dGᇃ&KLc`l>&j6Ydv%\Z^'PC>UBrI&}󉨦B`~_  :N "xA{E-I<身kɫtA皽U7exLSd"0NfMN=t<}6֒ &jqėHP [L vn%O@"q@CK,tc P dBY,{:`нEoH0P<3CMR ; a [_펯…0H@ѥe"D US/G=$"8p4B&A lXC怂A)=[%X-5aWBaC8W$d,Zq*Qt"QH&&PbStrj: šMa#V!Q ELU)B_|'MqDp@ [R'1guHЅUBQ`yЃ @p`(G fr]0%WJ@豁 ؀(`J<+@V1fF6ñ́M![9N@PaK\ea.ub(J.:E1lút !*ZB*@`lkFͣDS!х0v6ap~7'8! ԁ.7<h#/0_0#G5M? S@b' (ƛ١5 g:SЌf&B,y+"q@Ў#Vm[0 xfȷ홇r@A ԣ C @bk<Ё=[S }ū*3HWy UlC04V"ow%H "!}  gh;VC (* _C4N\(o{!a1HU!ψ](jHO+=}TJp,ja$30+, T!Cn`rEXTx 5MUPBS$)~ BB-B!j\#_㔦4:0fX$ xcP2@ :$rK `$/@XGI͊YbKᑎut!M &ED0Z"=Bz `CPzb8ID1kQd"{C&22 2`#9 0F6ACSE57Z#5p1IG>$q-{I4:fzxyc؇i1?qŽ U3\(V535ɷI}VW` JHfDg8C`fSۆ%'=7җX"  wi k0Ǟ?Oj18gFR-W}룰.k 8TW9Vc5e+o4/~sI@ aK>lR#LP1:1сP44ApۋEQ.SY&RVTVz#{Pr* Ax*NjTڷ!iNgL0D7/gڕ< +d S8qATLi53v0kHP=D@ <@LyCr=1gqD={`83 )3 8U{8 ) hB#'i؋xI7yHln_14x@1p@6Q [(THPenOb#N5<=)hKN b#cgxb6I{spw eT~~07u~}2ቘК˰*R(P*ab؇n艕 ac ؄[SA XRx5(-I!A1!`!H8Г9A⠃2"*P,"Xi: 7ab? +#(< ӓ!=jp(R;22-YH1>FC0<єy\!!Fq \A A#-</X<"߲#ǔL$,xA$b+pB#D$S;K$ ڲ+A`1(ْ,G\оXЙz~c}2u؇qq-ST. 88C `І !@oH oLtC< "3,aȘ_`شihjH6셦`[(6Qp3f18;x33À2|WW?І|̇ @mLfVp"M4 d\\0>k1iNdLZjULx=`8=CȃJj ؆y(@jȅBo`C+cqPw8{poXd'^LzLt vj ͌Lߐۑ`м*n0FG XERXθ ˪@; il$*9>ͱ0;/7Ν !6^:7P,fI-`Y;mL-y, H$Y6x,T/:c+2Y$ j;OXB& 6 HI(!F!=@B%CI*`m.Iz#b ˳=QJ9fG)2ВNEQbI:pYͫ >$8Yc$!P c\[aj u*@S?S$W%^Z%\z?*f.`&3(c̬؀5"#*hA:AH̉=Aʼ iX4l(Ad8M fh : 12He#+_!qwD";#bTf܋#<~05I-5&8@@BA.&K= >*Z0櫂Q1x,&;p-$bjX%kiCo:un;yۦtdƗ||Q6u!1HE.C̙Rkc:N4A= j4T͵9Y>41Ʌ $M$.HKdc ZQV.) ԅuo`Z Ti(P{(kCwq<0fB@fXfHlfATpը[ E~]E PWr^ [Ψ#: :gF4 b!0483ɓ+0<i09`*+)3YRR<(ޕBf)_QM%!550""]=4ȣ?21-[ܕ4a=I"asHb ;` ^/U#<;O@I"T) 7R"-A蹎E9rc„ti 6k2lXN@vژHp5n Y#r$6רl嚎,_tX;RdU4S4M-iqB!Aibf]R8:sV42eḥ0ȱЏuQ&MN&m`&u-X5mӂ]=fޘbfYhIp[v5ZՂM;r9x-<|,9ҧGl:vRGvmlsӦE#Q3ф#hr4 dEKd T ̠ 3׬mimҠ/hہ< 5Sns C >^z]cv&:D<_{V G .g6R%PpQPӟe 19uG)LdG: >1 +2QqO:Bz01o0$fQ8!pax9:*z߈ H U.KBO4"Ob> [BRT6LaJ2 ̲EK_A^Uh,(p+8a| &TpWjCԀ-! M8#`,-D#iIV;UR%l kV\-&WPBLZ&W;D"x\ZfD(o6P#.!zv2d\f6,Q p23DjM 2gшW".K1ߌt%l  naQB6ejD!PЈ,ma HPf o K~ʢmJR5L4SC" Px\I2]0*:3PRzTt-3;mf8]tp ='6ayƫ uڜ6Al*W5:80vt\|0-61`c7Nj5a T/C0 yȃ"qV@(Pt'G!pPZ`/VH"uF1QWa c8-F nt$ơj;E>ۏROt}c!xMؓ#>1 LPZ' Q,lqH”Tr9nXHi*,ހ6abV9\5GFX e̗QEDBUXB:ժu h:A.(l»9k$CP`[kVK.7t@fdA49dReЈ9lWoGɐ")WPr(fHB#ZI|v hBr\uFzBsQO20B$~!99H*2/SmY!.qUvGT& RcIr0(\A Z\C47Qaln3U[pUalU>WDɛ-t抝jT2 ~gjt6r1pIlV7$w4&G"􀘐h@bH"A+!["wZ۷T8,p/ v؇#^y$5ސqaK@tE\}hY#L}'KnpT-kHxeo %gvv,L$̆5r*+jUrV!&B+ave%Wص l4)<䨰H:iKv-A, >h E2ÂJ(NKIYȅ.8Y@QJ.C3| ^>D؁SYΘQ 񕋹HȰ< ͅDTCJL8“ !8K =qADGY "FUZxBDd AUQHE8bB0P2m /`7*B.DP e<\Cŵ4Ύ ۺAV[tp±图mF2Y~\-b z5k@ j@8L23-7C+A2</*ʽ$)pB'(!PM\/8@D 1lqC0hC!PB7H1,CH80mW97C>:=RCե9:$:Pi7+IMţᝈ4nPD^R |`Y%DpEB,LxT}Ø bMD L;E2̕8eȈ&G̋¼ ʜA,T$ML+ x"$Gmm~Q!:':*=}h\mO g]-"bz"f"ftXs4B0!nbU3sH:|C=ԃ87h@|᜸\.H'4ۅŒB/+ DAB]e7ƆfC-A+HPC2̃2H6=x$0:#qlģXc-))C7>ƃx!]B1pW}ɉ-D' EB8 &,uDI MGDf BXGm!C!CfW|,T %۝ȋ")\(Ɍ-lH AHC]A5V'B(%0pC2@2L77b>#/pI١bqC:'C<(B7PwqW?`%\/̝>؂+ -H J,B\ 'KpҼ d'F@Rڠ$t@t0@Ba + +! PN_Йʶ B}=MQT aU^eD/uj2f(0D&؟M6!JA4YΰcL/ШݸͣEdEN4$ `-PNKU F2T89/ N`DL}XMs&L Z!1RԂDya4wF5$"6pm҆cF֧; ~u.sZ3?udYq2W:ICtA9 ݂se(oxC@|aS((HРs('tB&t\  +.ZmUѱ[/x.6$9B5pc8|Q|vtGG{Ji4)B1-Jפ4B-)܂n Z޼ IE< QDp 0 Ё,Ω | eLց  (GQKGFS˽DY& p)|  ZfZ*Z,tLq(l J]0fLߙ8$(IхI(,O@!c2q:,&YԱ^R;ElPLZ5Ҥټ:wmNTdTׁGM"gfEl_6 Ed A 4ʲ}#bF. twr"g"v 1"3W3370@3P\eUP3-I@.d6@20Im G53t2H.0H/fni%=B(/:n D9trV(L%$01H/Ȗ6C+ X=ԃ:8 RGK{4(To'PQ -มH$jzˍʏGaqa$pE(etT78 &TA$fA* " !K" Jbr!aE$XPb/4kzoKB B$ +XFD-2ºhwyeC ę `rϊm̐˜6_u"_ PjA vф"Pw` ;/V*Kk*:.Y:Ҝv@˛3ᤥp+Sŋpc4+s'WlFcJdTi`mބFL5 `OT ;n:2H5f0^Aj"d-Zy-Xw? *W\Ү]%Z4iӤŗ?ySGO? *a,LP!P &@ !< ;yFja>tTaACad _QǏȏo~FZ\D%=i%tғQTRL|("jl8D[іZLi&d iA&J!$Y{!n"VGoCrA'KÑODIR@RD%UNM%RIWlœH6VZW<$H4;K7:!ր#@1Å%T#&&k98h+\8`hE48 ; PwN,d d5dV!Ha9B*s2z@'; ^C%p0yת":77t͍dIH:&j6v))6֪4/1!, L):ryˡ NZfz,(ۉ48 鷰j4B *LP'ߘ kl;+ZvL8%[ ̘CI:9<>8<+kY r?ygL^1ly /.ZCLlf>HHGTbq$0Oh>iOE<FMLURJA )5JUD&pKIAjhyFj:|B 7Za+Hb%! aJEf0#8! Qau#a9,ut`蔧@տRVOQ݂#_m"pŬH,SP\TasXa3` m`2lk?C!%\e8`@j]Up p/LjTpkS Bpht0:! Y!0,;""cY`4!*x m d˩ !v|tg6!e.iJfc8'iCծ6-\Sb2Ö5 -kIB " en"3lz@gdr4*{i 4,4Y0x5-rbMNH-ŝĚ=!*%a DJ1x+ B 8Uh]}jW$iDC=_@{xv>,LEHQrֲAb0u/؁2I@C'j,_ҟEOxDYPtBxxX!(<[p@ȅ% a`UĐ ^sH#uG>^0Ecȃ@ 7t0ƫP-)UPB Oo-hEYdEB Uvv51nP tL1?" iȢDB&{eHAAtP "´`E-VLVNsBC2ɬ!)!Ka*҆`\s(4-i a>Chrn_+9u0>l63x&)Kp$2'9k^R'YnȒ"fASo~6'B8rasF56)-fg B-~khcHϔͯR5KЂaT(5>:Y@PW+DTтU4=F]䭕4p oLb\,Їj#27.g\o"2Li 9%')), NOptD`w' Vdˌe#V ZA qX"x5

    B<~MMJܜC- J(M&DJ{a=&6}AڰaԁH!ރ( .*H6L!'k- `q v ;@u~;xtP>ԭv&3>C?Qp= UA5*~ 1$-}!-Aa؇n20v`*!=A+NVB@KKA& p!!@o`!d ,Aa? Cn@q1AVzt.j!B#@ }@OIVhX S˜~C"@!NW"&2 Q5v 2I)!;~R!R*@@A!kV^eWb8W>l` ASv%012 a%okr%"5[~0Z[+"k,/Q_B}ei-0l>"Vvcɐ" bw& nޙ B(՝R VyF @lp C](lؤ!@< &Aj?@vgF^yx5}5-)˄Fj${!`0O^7bbF`=85OJ>DL Kf Fzp!A`nj  ajч]'%Ɂj tRj ֈ>T8VaŔd"|!DwB۶P_VHrfgW zW`Z!G"ek &|R42((`Xq@ m\c^@Bba"FB @qGaM`ȚqlQ;i%c%/C&+Ѐ"zR)%æ!h37EERZ3.M)7T5q7,qZ*&XɃ5f/§x.FL 2 xYOȔo)ί45> \) <NDBƃGA-Z4!=#b82#ʍ{i;\h5F9rt*K.rlZ :OPre˳ӎyrDꖛ@"E2s-OH rhHۡ:p,܎:ٱȃ1JKVP&,%P8nҘD4Zn 68R q"utaFm|]tKZDqU\Fs"U, +PmaȉF nT!pQ5tבu^E6 B*S m-E?Ltm;+ױ亪ܭ@ 6Z֌HvbA#X(碡 gb]4髛oBX[#b%ș}D(p&`Ei` 7 ;"îs ,@"XR\_ v)i\-72,ř^p '0/N 2Lh"*$0|/K`Pio\mp& ʷhh?q䁿ћE 7A zJBB*ېCE"M``ȊcX+r92plA3)1uBtl'p@s)AeqY$*Yt[{()IDɈEYγCCVd*2'^Ե;j#螫芭-*^j0gZs v_1ƨȨ)qvˆ5׀7_`ڨh!511`=0~@7._'CJBL7GIgE& ۠ ad T  A0 pO* whC q p ryynCJ|h7s}a+8YJ 9S+)֧q:BGTSYSpR\H,=4F!*R@"cP<;"W rnĭ?C@T K!"$(;Y&ɁZY қAY&b'0p1yqZ䜚$(4qIAԯ[5'"'[AYri`H]l`#u a"^/C0%60.$>*PB UZHv`;0 JX3(~G%z1!zvƴF|B !2;,2>1VJ};3 +P @M pAu7 SQ6`` O4f0 꺓i`)H&nҕs}E89mP~K~k9cP9wP!qq%Pnvp%h!:\r.-p>uXPdc6\"; i}I\ ss rUV (9}` "BlV4"+M$p`-m@ XubkɀuZixn]q(W #sE( 9ioEd(L%y[ GT[vCl:2B%[3`8q`b c)MSV*Bu(`.@V8E J41KSVk/"@0 _x1a1d[ta-aB 0 u; 1bAqz䷵e˻L P Sc;z )  pP pQpe`KffMR}M)ѯbm(rpw 0ӣP9wy6QxP7ԣ%Y1G'uf`<HEJS0=\3 +X$iz!* ?:JXBYrsj( "0 wj-EGrGUui慰+:=jwTT&`"<*v-qp"j)(t?us%b[C57Y寝R){q*p<;+Y UiUi3*kpc#C˖ˮ$]uBB˪kutJ__ HU xa Hנ jJLl' 5g - !  0v8!+0 2t*6c8`AŀJڸ>et  ٠ S0 5 y0Np4 pP SZNLI]I7B']BťyQmXA%UƼ #8A^WYR8#[Am4xFpqkQkn<;:c2 Q^j=vRG"Dh'p?g -*WqDCq>DqDMZ؞sRY2tk[>2+Gd00ᑖuz*?>&C"*"$¾ ?*@*Ǎ$[H&9cgJQ /ITK0R1n/- Z؝ިvH` `xv2f4 } G, 0 0$|kj(9 z;VP, MАz @p C`4\M)9wb)h!Qauf`ggL tp WW8{φ<9ⱽaQ%_$.0=!*-a?)Ly nmZb\89s"j3SSB!G]txZWecGm @Wp IH\MF b?RBrD2CgB`k 3tu8p Zf`]*hZ8ڸ9XV)%8&3u)QxeI"yc V ?eBh$h!H_'OzyW%#",rXe1rjd~CAZnye52)Hc eꎲA ѠcZ쯺>g~3,1u.~f!, rfO!2R(F=^2QA@)2֖T- k%Wؒ@$$IzK@Bld")C*ŃXd%$eA %`\[ɂЭK' PCV3c\ɂji30Aq(A5 1tqcC5l;3>5-n h횏έ 4_[=xVx :f H8apf`:lC,8kBjФa' PG5`G< zn`aa4hA p#4awڝT(#q@2$B:aKW}@8 )6*h$uV=ҟ%@9$It:!LAI}IT"̰6z y80A 6a@#U%Vpو)v ȥjtӽRND}_bd3C 0`MRR"zOMA&X;,E _LZF8X9,6$+ +E+%+xAm17,( 5(=eiH;@z/L0%h8-105Bz F! vaZH898h=!kCR"J0Iz6 ЁXT@KGpS(HMp\?KWxHP<MO(H32IX2>>&㚷4õ`o?`<o(8yP{({[?tk XkxZ鈂(#h|ȇ(Fxs khH*QBTCЂ(REzà8%P0z68SA.9.("[)EZH$RTPEFi`A84Dђ 4:YÆ:\,#":ؒ%jAl1+ P$3P*#]Z>>`%9˪-QN.ؐPџ=!Dyti_18EFy84j4*e -/P8GAP4`NR:sA;A$0K($V:󗙸 s6/`LaUX:m`S >}Y2YIB2-z1inȆ^ThXr"*fh`en +P%%跖ij^10~[ U6}p\ha"eܐ4pU1Eшw ]=]iF{$kv9G"5k$$ۭ%ПP+Xˉ`QZв1 UBEJZx uh`'Sn o/V.J+)=􅇷xHmhjy*իɭuJX_P r?lh8' \^Idv_jI`$Xl?ɖr^$|Txyr4b|H[H+7Ί];)Yլ:T}%$—:9NRBY+uÅ=ʒْ-{T=!P3`+PM 64dn[(6 H,Еj:8۱!XJP?X4E@40{H췄h qqHdo(Zpv(wTnn_v")nuT%X`uas&͛$†MZ`sIK+/y҅J4i56W4ir0`^C&Z1VO$Ϸi_B{)OF Ņ؞Ifȗ/ʋqy3LQ`Ծ$v,YR@JӦ[ta&%D m2c#9Kp5c7p츠hIDZTe 7tW1cN*PLʚCv>i;h5vŁㄋ6ӆM3 3hw3UܰQ)Em6TfƒK̘vS>7lqݍg;wGq&; rì '!.$@cD!#(LWZN&+1 D &@ KW%HNjcp81]ⓟtԙ-QfҜDC&$:TRT ?9>acH&,T!} !< N GC BVC1caU}!Yrֳ&-ENkYBJ$X6y\C`F")H82fB%/{ 3#0E"żtT!XV,mB%ղAh-hQ-d 5jI`1~ h>#2$A0psDWbk\#Z"HU-4i[G8+p (b!@3 eLPQ≛<g4+(vYk13( n@LdJ e M_vӞ&4?k 4hacXED` KjÖ;A $f,@Ȭ`X@ `28, hK\" jhJAJғA>A"'bB(Mb?l@C;^?Ĩ(FZ"ڔE*63 hQ6biM$|;S*kp#  ph+@dle#3FPkR99\fQks%oy/{=x7|IChIPA", oI|',%Ü2U-2g#$}TIC*MG3 U2)S(4f/| x/`D铗g0/!\j`DB[aܲ ߠͦ0 V5 ICaŝI9.p@5ϦKFY3ftt>Qk$3-tK0NVș mPt`'< 8&07U юi\pHz pCC.>nl:՘5;iPK@}R8\Og8 H0C,& 8x2Z )7P '\zK  :LpEq >:$!60|5E)!WڴF6Ib$(Qr{SU}{B'5Z$0}GPfr;4.0At$g! d7ܐOPcb cAJ#LHC<LYWd(e B9эx2 T0h {PDwxCZM2LfF2?0JPGKr%Z?%#0k/E/Dx TW.! ]lL.@A@ ?0:HCtWDPXBה-#؂x 8f,DwD)x&܆-F${|_Fg[~nM8JtFmc)N1γOlOX唶[k\^ b{Ǻ `ܬ&PNE |8= \ AdA%)]BAL\dqȉ  ,@,",\axH.-b,F"de tũ<,F lxc iQݡxDUzc5-=ri)[{ڕ4 l hA C4D: 5P6S5B940$8$BAúp7B4B+12t9;B7D1U_QmR HPʒI=%_e1SB1X75@38>A @<9ZWDq't/؂' 7xl ba l&-p)Z|^ jϕj|r܆ U u}Znbi({|J~Qt!\85! "L )ԔlF$OaA$ |an#` 2b"RB#|8B$B|pLB'0,+pXˡ8%Nlha//p$(7(ʬ BROrhcPw)hDxIJ::f}Q I`YlF<J#( ̊ 6B$BB S.4d4C.%Bj.l$)GZKH2KG`C8%܀!pAq8,-<8A+É\Ë==#PRR*S*8jLe%Y%V_M W*+WNK3t8E$܀04@.<W.HB]! ;H0dQaa7`-+( .+x(&A "'dݻͬajxFF`hbP ^DLD1jjDJ."%L (X]DB{[T^a~-A|(&܁ 4 Ɂ~ZЄBPP-/4\B.4t"3 *@B(-L@t 4¬fx.V m4pщp6'L.N.`B pB##8  peR^HƝɞ:b8."h3VA,P#p=cD^  A  I@-PFpQ2Q9.] |9=_%h08+ 6u]: C :%1/oJ,7(.VxC,,3CJ7B`&==8آCe0"zp[ 3cKU^eV*p.[5I 5(C+'@a%;DA9@_+ENY[t 0؀ؐ 0x' 50 /T1yh'~ߨU]o{4lwJ0ʘ! Fǘ| jqqۆ $ A#8 ' _Аkpi,bkoĕiA(71i/FȁѱH*\#%WBA-.*xU<Qm\:PxXontAl)IЉ@-hUcTCssݥTUED#G $H r]4@.A%0Fj)ݴO/*&%11I5\Ct7/PCH=mB,X=67`%x,0;@*APLJ ZQnQ5\0\ #V 5\Qĥ-H1A8 DB7P-М"H@>(qe_F(t;bB+`k J@R mh&ذ+ &pߴw$xjTI"tFz(j'|=7 vVXKG]sux)gPkDOzlMB8Ь\aA;,w An ȁ؀ȁ PPhd|Ƅ.'Ị}? @xA"+$PXB} g}̝n9laߍׇWc mQ<a1/ji߉>Ɓ4A ‹Ʈ᎖\)SBjOh:5 !>mp$$0BЂ0EފCF<5+$+8ļ]2x&Mڴ`MPBj VxcF+"Cְ!B#I4yeJtҥCa,!ƒ^Kn칒d!a&Tٳj k >jc 9f< &v yalhžA Q>խKݻn}(jrē-`M\seÑȒ?Eķ/[Zlغ)3K̔vc'Ph:k9PEqfMi:DN:tTYtk;k褶NڬF73.,)^s7T&8fڜ#ѡ{7b%.-d' ; 3֨ *\9:D\$~<'ņ+\ qؐEJu ]㗲8Sjզp3:֨RZcXHҴIUсLW\& z8T/CIPҒhDc] /Q_lk!:Kq3J ^)Gs FM`L E.Aza//1/$8̡k&4}J]3^ʻi͓TƅpӠF5I LyDŽ&ʠP$$L#Q KkA8%nxzxE܃[NP`&I&o#XP"F 7t_HAREO#qj 04΀u)5 rLSs8Lk|T->JP`p0IsX 94(NVa 8CRG3( + 8U+-M!;HZ Bbxh<9^D,P19X/D0 @4mU0U6 А%6!(S(.t7G702TCT5Aa ˜uj ^`p@(Ab9U)1zQK]_JWi,UݭR6pJ4+>q%ia6K^ :/rr-%_2i#h2D m0dM t@9wB(<[7/z!34l7is,D䔢>H…xp)=éV*$tj#~@E~DVxe $ dp@MM@GpDbn8 hUYSSKXh78eꮠIn~؀@YEHh~,!CըUNV^R^2厾8h@lm .YA6k@(CjKM@QWT!܉F)\.v`Vni`zB[Ee&aA!hc&X|)^fxAί$.2d"rܥz&o~,$&IX$VO]Ϻb!j!^b+} MjXjA1p"P0 *0#R/J*!/ #Dp~ /|!n?flb#6/!Vl\@2n a s9Fr1ޚ9DC39Î(WUhSA0p`*QԃH2e ntBzS:V` \?|8BC jxhPF҄C@x֤`vh3 |d {rHzG|$@.9NJ`: ź%n1U`R W I@!T6d~  4@G҄ /5΄r~Aё=d(9SlH`Ą3KfK% ! N&2,^jf%DB~!. $v!raf!gˤ,afrr$uR'''4R(Y#'A2Qef@)bbM!2|J,^ ^ @jQa~V  ar.APo&C.D@H0}?&5Aq4s+4sV;c WI =c4c pw+TDrUB߰z@8J;ayZtP@;K:4;6a 57uUbmR3 l.rA rI#4J=!A嚠xLkr۪"+jP(UKcAs4A HqYHpM@嚪YˆLh5dNp$@ e%@z  ĀBql Πs KDn@lS^65D|C >QKDC_QC_#mN/I)mT%\aZae&_OMEaAXQsQym&^ S5jSAf#""rdB  OU mj`@+2RAZx)V^Ѣ .pPmF=roX` #>63/5@ u@[#abA^CdjQ;j: +'5 T&.gue8Sv# L^ycABp >l#]q8 Me:ǰD(R @`kD` ®9 :dP2/F0<@rc_>!@@J$;J#äe-T9Ħֺd ֶ jLРRF *qH,aDMS=ml+A t*%VjQaRVeSo7^o9T+5EEWC@8B>$:ź(Kp# DK͌_@taf t!F0 $fOwAN&^Tdy ΞqfLE@>'(LWex!j~AdϺ"{l) j  JI:JX! j@uTz!61m>BjD/]#>m@1 0 5/8DpG 'tbvL8oGW:$_g٨d DC6q@TX<6 Ug #A\k cJcJ,A Ҡ)]Qk @Qld9⠾ Q(%EkkH4sC9:Pn[osCDaBѠ NBXtK` ~`H4P:YUoqjјC댎V,L*sG޳GK: eLv1m&OSoa OYoOAt Zh|  BV UA!!!աtk^&rA$LB'Z)f0D8$=ZfTeR"+&{W" #!aZ f VѺN"tA@G-€ Co"1X`C|.}j0]  #@ J:` T4>@85%qFE04[B; PBԪ`!|XtҠF=@ OH6|cL63Qt @JJ'̀<3 *{Jk͠Y4~1EƠd@p_:YAn]DzU'2L  ah PVyNt{PxZ;Ps8@no|SA+l:x^&h 8 IXƙW%^#G_^|t!x,52VA"fb !nƟ<ʍdRWh#$$Io(*ڢ+^ax`e}&-"7 E)ҧO}0Ck7.#Κ5vbK֘qC:رCgCm,3)TYLWаaŒAA%5*asJ@W`1M%GO5UTP3iǚ8]!bJ!5M&\1zM#!BBaNȑ`\))ѡUr ArҤ3*4f 7k=̞3iҁeKG7;y9Ye;n̺y:tiQQ#G9b`A:QH!cU#(\eDŽlGfd[][kx[p_-mavxQ+f؆B#jaRK}TR!C4H&L"̓P>4x :訣N[^͗]̂Η"M536M4*ʘCTP!z暴27̢&lNS4i)IVi駠*ꨤz驨***M4t!: o>)L6rK1ðPPb/Qp<УP"# 0BL/Y∿iÞDbVJ'd&!E2"OtOd+ErV\h[sLSs-hV2rGu\Feh(Qq B\2[6j.UZDUPr ! gqfS^"FihMUYFvYFJph!pk&1j*pQNnؑL-WdA'tfap4 (tz,^SHdnuG&![j$:\21FcnaZ iYat+(?b%~x4!4a>cvt# \ u'P JT&(AJS_5V f!l`CnF5UYM`d)hEPHsJވF fʆM8*zqI+IMVRͨ8SӠ5čadBV=tYF3:EaDi9y^0/}`)>ϸ 'RO`'nK^d! &xM!) CCx,? >3,k4QZJX3Hh@irbGpG_q S9ؠ qh"7!Ym'rC9q^.Fm&a{+nDA8 MGóv ]!5p38H0P.t`U bÇ:Bx\l 4@*TPU@*Q 8шGkWUCۋT25G}QaYQ58C*-ȤbJiZeX)g/A_@ŠdT8$<xA"EB]CK稗A p ]-Tv2jjVް=dZ. VL7Qn{nR(` ܍%w8CQY&9yAX׾ a#l"B +00ň L.l)86[ .;7faYID26;cvazV5 YJN%lp1E" 6|AtNw`2>A5+M$s\15Cm{)Pb BhR` ut/9J2,dV{4'pmAKp@vM7N+ l8Į9b{;0u ۛ L#]s<lÇpОYw54FwգWuXE,XLbPb" @P`KXk)jז EEΎ! XaZkgL;E.r8VI"ڻ+XEkIk|k]$MQ"A=xu :r-oT5+"PQYP #f>L6miB0!$;-?!"sP ``  =1!ap~hX, !Ep %jT*q7?pqY<"F 0sZRC4)0A(ӐZ  _0}0B_Z'$j) "` \ @ 0ˠ 9T uf/UW(ؠ&/$q*[vKu`unbvRv*v]jTn$ x'y b zdP @x(J2ؠ %[2C" Ԓxu P.aRg`#fJad` /i { / Ǒ´A|cS e+e%2M0+AJDB"s4*8?|@ 0 尉 %܌z)k&ߥ]M+CC`%ǹPE[0ty`@ ĀkB@s3DeYt[$rU^J*md^Ұx0pkЀ I2X_ĠO`x o; / E2J )- RpC P0G/$0KJ B/+K0d11Lp@ C v@M)+ ~qLGfqcCUa6f0tQI vp 0OU Ĩ.LtJzi88pN9g!4pcYP` ABqEMq?a96ף=zHo4"q3:U4%i6QvU׵v ?A=j |S#>#*`Y|p9#xaS>B0 ɝ`" ^pS5!ܘ/";F聀ʑʱ;! :ғu[94| :vN+KA'f$ J&0 }pZZ` " P (T@ M'ԍ"DB0bШMu|nr[ p<0pA)0%r% @ *}OЋ`2m Cp0 =zQ`rԙp R.GP0ܐs{jev 3 l1 J0:$4<^F!6^Ak f"$80NEah91ƅ1pδ 26sJ0QS2ehq6q氓"`q,`2A_ =v\,%g;?;F<١\%u`ߗW :a"&` #1` ?`0* ʠ ` p^eR1~,q.2l ;2bS@!U&q+G~IJrJ>A|+) ;P_<pL.'lr`g "DakEvcZ$oGc%̰ "ZH& t`VRWP" fʰ]RKN ^3매{qӦM"" A<ʑ `<"q`HBj&i\>lQFUobδ $/+ڈ(ԃcj9+0Ax$0A1 1Ҹ 9n 'pD'L1,L3&j\S7\s9礳i3N;&`Ѧ`~tCakPD!bW!dIV$) E:fkAi=gN<뼕NavW_6`f%Xc5W\db|WMjhuUjE:nb!HFoA'iU_HL( F`8`}smE8 +xq{W@)#n@ $ O4\W\%8 [0zye:D%:#)p" ɥ@2EhtZ%̸븣hcUƨC-[^Z-WHȤLı2z i@ *@Ì4cT(Kc1䢺o"qp:s"K~,+7ll#$K*@P:tDXPbA==-&`@6dc7O>Ȣ ӐCGdNB *Ā98 @Q7)F9Bju*D zOrP+l@2jRәA6Dcy/Zd,"^ ),/Zp-s0O ̌$nI$sQ9'K8h 8$(t:)oA_`u"23D[[{ʓYd\Ahpٰrb(x+(x8!Aޡq AA+ `CIAx9ϼ jB9EYCDRIJkEZ$=fdrq;yp NgQ<#oYg$5oQ+3aoXVVxu8|aF?PS`Jx&Ѓk3QdETJq4#{HG{vT?(_O8a 02=C}ը YܛX6;((h\88؉*tZCPԳ+iRhhG@aqC$Pk/ 4ϚN3 =bP7e0Smq:E+`n(waPTi@iܤ$ VF+PU:+5=U(rTQ%G@4!ђXp "гP ( "؄ )(4|>  [ 2뛱6;ԋ-J@>N+!C3* @]!(SY3 @@,>T9 HPUu-& !<@SՑ+Tx$IN#Y= 398M匶w^VI IJ9Jq1 5!9`l x̚0LHT*858 mC4ԙ! XcӆpXX/_XhXh,]q0YEkٙY90N#lУ>uX`X$.dxhtpċV*g̤F0jׁy/4-*L,b,> j0KPз9ԭ/؝k!#;\$VbAbbB^(jzbH.f/%cEe;7i:H>@tc"iabVȃ JJ<jȆ^pj$a(V`+hdj HdUTHuQ`2ҽ>@ DX`ME[e]F2O8 ՚6TkKC]~v-&Rp2"a4h'%ɉA 2hY)P PZhgkV_ɉ N@S]`~ T1h[] K56ب!`Ƹ M蜞(L9lC<*Q*:&Q9NvZ46(*0@9*gKyyX(9!6d99H{12:3'}#;y 6( `F 77¥<*Gʮ.t7,k6lW^U Ԛ4Lw/ .!t;Z/Q0R'YPch0bD[ZǕ1OJo?N*ZYo`Ve׃qHg?f`Wv\^Z#Ŕ+[ 2lB\$Jl+OX"NRͳ7oZ>u RDtӧCKYC8nED'R5ImTgM~rIꢦ-J@v2ΚEm̀%kǍ:UYR%k|YaF(8sWYcflp…ݹt R6Phѭ[Ԍ:tܬiZ%YxmsI9sQ#HP W|uq[umC6КMyj"' 'by;8 :4 ,rb"U!TrmEj !G!}(S1i1y Zl!q"aFa5%&XFhF"H" "GġY\R rxwV` efek r9VhJY4! uf# : :ᄃ 餃4NS4ZZi5^)f)J:\xL4j4x#D駡+ + ;, *抬:k鲕Jj5T$"5hSm5"M6(ӊ$\qɌs;F4L0҉(r)2( -pEH<1şb1Ʈ1<Šl s*R$7qO.I'<@ ;L*KhC6Cf6Piɞ-LcsځoW3!f.pלmy:Dc"Hp.byUA.M֠UUA̘6aT8&.tX"Qt0? H 1j!uqWĂM[XA>TT#A Bֲu M2;P`Ahp1@*P-! DCV:Î'# DղلWSD @[r"LE FX4 "(N@]SMiSyhZVO΅rB#x!1A9IAa!@*@B@gTv LHyWIkHF&[ J8D' U#D A U'I pH+V* (e "Pϊ:IHk8.Hp` O'l< O )PAPϽ+8ƞeM:f.mI5 O+b}g~.י.\ec|M5p \I{-] ބC˅jhn3l/2$CtD97CLэ'(^.Tm@!A !(!Ad('h##׀рdJ倓YlPMT01EE7EB\(V ȩwI(ʚ뉠 My\镢q-` A& C(TfpŽ# | v*uOOr6+$*Lªz$AWe#p@%2BYtH55g+E\LZBW&N[ P6` x a 5,w`K,xA"* lЩp S"ZTaa]Q6Zr#+N7B(ҤXŠD$$9p9D0d0]X/'r 0NQpi$n G\kvƖ % f#h!AZiVDUd sԁ*oā8wFk05ҹѵbUufHo'6HUvx1P (j&\Oku\VaYoJYHp  |kWh$Kˀrq,B4J}ޱX#iwmB 6":ܱ*2 'X72@N+www6J21!(;4i㞃2Ԃgȁ.@Y̙1G[q$j dnu;Մ٘ؔXM:ՓSj)D@4@Lj(X! 'H ³PQi1x`'wd''\7g/%E-'B.*P %*\% !ISI \AK3$Z[f&Hp X%aExA)8tVG`AW+]fc¥d|  ǯ:\49^ߎa无E< $ (rmv^YE@{37| 3u~M8I( |5$9j!,T0EXM[-ȁȁ+p'T -x0tZ㚡x/|Œׂd J:#pK9*wց@"XBO9Ab\Ԙ*p  dTEvb(jf 'S6jZfP >BX.n>A Y֏4,>WtؑPPNc1S%Zf: IKuJa.z0Pi)a;:7I+@Q3I3ͬYÆ5\i+"kUԸ#ŌQL.4ժMSrZJ-Q|9SL7gTY-X5iѼ$m_GsE&/d4i1kTj s'K82,̱Y~-lWjfS7/]E{M%pZEJ+q;ʓ'P5 U+TnqSOQ&E*&ׯS>IvmۧIyᤆ,-y7Ϟ=fByb! "ucgŊC\N@6ى 5f2*Uִ1f.~7: Xc:8̠@_p<` " .6@P(q0: 1ƀ.OOF.Ae#y%DhRƨ# C 9B A# 6` 0Eʌ#+Í*NA8x3A:Ď:;995ރ<3Kу8D5hDTPCl24HÎ4dAȢS@o*4 :Í]=\wKG[&[hqYZ HGRkp#L6@Í6PHC!3ĜO3w.>]uU{_bNTF} :Ba M4> s4Arbr"4裎P($ti$n"kҒytRbA*),ɪ *oF榝,mq旴~/+te!hoԱoFd[ F83BGxo?$ş#X6s ą"c Hc/ELWC7{o a 7x%^#aXר[ :0Z4T["ؠ o`nj "eppQؠ1 QHOn!PjTBXE!& x+Hy) X%0 o(2mM T;7̧A0|<]BTÆ$ D |A&#Ĩ4A`3aNwЄ4!WZF I2T1KVup0A %6V.)L]wܵ2:d ع{I^ :\^zU0Dv|ICaLfB0,Ԫ XT#)%ZVU&Z՞,**̠傚8Sr`hXAJb3c&Sg[y 9ɖ3jfIl2t|lza4V V`-p$Azv- bb1\1:SGWtFi mMfTIx/UpBp꣼ \wUOEۙds QKPU\B Dэ d|  m5|((F#2p 4 ҂ \?*$ bq* XS* x&V_ )Nt`Р&5 {O~Ԡ@iP+\q'w=IO^Hb@~sH%0m U &AW ZX:CY\Z92 jPrA4a;Y%L/W`A+xʨ ZN] ^kLڔ|ԫG_>þU_6RuXԐ%#ۥG.Ke)0rbkD`EE5K@eTZX܈sxf73'8 T&p:@f C$! (;r - +@=+U 3=hSء RefBv='Y^nTXA! t?R EX >-Vi  u6u{",2䷨lZPt`#z?0i}hW)A{19daJcGpt }$y;X/beь*DB3dJ:hR߷ӷip+rč~p >x; ᗛ/Cp: 4wcP'p|? 8%xbs+ I^6tYQrΐLf =V4 `e7dVEPZp{\|'hruCM qCi2AbD2`w(*ND(Q 1BԤ6 hf(4!\UXBXm =<Cyf N] РNzH;cNVQZmOUO]6XK@ x,!~Kέxk *e e ~ ۮW` jѴ? cv`oĺLdoTDbfljT"xR'B!fFkvƻȉ>qr1fhr- +XeA %`0na11N4*40 DO%P6-njA&CAO/]aollS/3fAN @ M .36 1aLcO.wPf;Wwp?dvp-[($ V#V7kUeS^A, @4/a R6E 8a[i=h'QC!DWN%b1b")*l R`$hSƖxr7pclDa WWʹV ! Ac t 2uIɱ#Zl# /gdƘr'b/x|(~A("iATO"*2?)&r!![O.~"/R&!Œn@0ZA>a:!p!&sl6a>JGacvV>N'xc a O`E=i>?&.0v=(!`&T!^2媮*H$ A $ ba&@Š 8&a(sxXr56:6A!tj N؅ %Ԥ^ jIW!FP m9]-QdAM8dU0 &~-E6_`;;~@>>婴M 4%%j,jlȢB ߠ S\ҀMLxHA?dEWe]J]J@ @ڀ @ AL \Sb gʹ =*H P`;R¤*lSnt#Jh3_!AQ&!vp "›BxB")L>Kejh"LB"]hOgT&fHឲA^``RRA!~)Fa&-3r\0a*oXO6hCZjR@6 Т 0^!tT;9p`=6N<X dSU &jvDOꭅ@z+ ng=:pH:E28Klm X`@\iu@8E Sv@^uU0!\\c `Q` n!,VKC<D.%Fm7D sP,]Ӏ;Z7e80^0L8 6 Z\XԂ'=47ũ&FIJ$ 2;X.A `S E`lAvOR.!!KLBN# `S,ct@ @ R "la`Ty6&e!Z!V#," W$,wȢ"4f2W"ƴsa~b/*BlJiKbJGQ+>yjji `ƢKLg!HO_FF@x Z! !Alt0IH>㢮/96KaQ p!'470g0 @ A@O`e=`@b&'iXO-urB!{"*Qz) @8naZ@$?(/7pL HP(]!'1*-OcZZW5gq3*#S|@bU \``:!2=G.! / Ba@ `9Y<C5Kl׃P?!N6h4h3c. IP I@@Mb>.#AuvAQO_su_Ë(My=xjy `U6K d B .(T@^p?KpWՂo"欃 TtV97^K_?еvwlh 5fe*\DldaARU0F F+EK(T{!6dY9$9w¡s"re)/&(b!Oކh$i F߹+vvq£K?gʽy ~AnAσ!܌\!n:~~70>a5>a&***'6gY^>$G`Ǒ(ɘf*KP3v, 3qs)2HcTsI3R3hPjJ#'MmL4#E3װrD3pl Ȗ ɉР7jl$Ǔ&&5SVAb@4+c "Vi&V8b5nSccf-N;8nڄl@t.Vg 6fd7e g⢑ᘹ†6EKĉC[Ti!m֙ɑ:c4bCCj\V48 X4Ƞ<8M0؂l1Nb0t]qERnL1Fw'FZK]qEs u1Bh \w<1G?5S̑CF1&eFxBK5ڤN\&j gr6h`z| (MzJK4FShD(3IJ Bx 3(:,`5:`6jj{)k| /, =C]!O DS0HaE2`N52H 0|I C+| -~'pJ(Ԣ>po p+/)+p(RlI&{$q P QlaƭQE.0l#W2 1 S#1Ts@AHFGM4cl(FpEErH a:"Dxd'[ ,tA4 Y3"HZbi]:D< +UCXZRUh+FFmFGfQYNjIdx!&ondlmds FSCvmS>CdX 3qPB+i멨J 58rfN(,Ŏ Ԥ*N]".v)m"ǥ8kڔP >(Ns ~deAjt ,/K{8(G9Ф6]cN<|S8‘ `׾[jPRԡ)uDcv0,b1X$edRXt])@Zb!$qs?ꉳbЇ KYrV41 JH (7!XU-\1?`PĹHOLW-.q T_' RaH\a4'ENX1qD66Ƽƀ+&GBK v Hb u*r,-, NBQU4B RP05$ 3M,"qC6 CkQ l` H-7Nd4,@PɗU` l+(1L2땦4ćȬKeQuLdfKMGqwyh.d;]g6(! uSQG񴾿U ,ٯ 値.u~ h|0M9 &li4F4B&8ǐiM M1vAYL,Ĥ6 iL諡 ה6p@ b:VVsH@E#SI^|Q(@!x9`Ӑ:?կ qOخх@SP7sp3I *PzJ^f0oML1(_"'Սo_/uiz5a6!=PA!I8H>ZcY#!Ld8h RÂ^5)tJ4LPrr-c9na!0@ "pG F-2f@,E  + rP+(fMLLs8;D*f;!MH"@0qZc5EI Q=lTd"D"hP_" ZC\!EEnQbЂ!c "tX6m`55=-'H8F g!N)q c%|mZNS,)[H\iP & 7P6sh * PYpСYL!;Q#tW;1rvAY#8QZUUAԦQ;U!qvmlQl\85t%!AQM@O(!N#pg`orp'XGt_*6 ! W4B ( 2N5W"](3:)>qa#\sl"p$ sƁ=*|Pu&%E eb\6Di&t<$DE(>Bh*   {tz+ =x@(*VWuan4GtGxIFR*r!D2}p 0 r kgxr0 @ @ ߰]rzu2 ʠP $/ @(R/ g1{g0r03 b0sd+Y17 |N GpA  S6b4Z!@ ?l58N>b$nZER4NRb%b!lSf`  `7Ű` uei,#T` <0j&Laۡ"[%"c<+WTQ+SlRT#Y6""%DECq"3bqPCec8\8k5 #Uej!N1xE>"wX~2p> Nŀܐ%(Ya= G#h!RiM.NY>%q*6T0':ԋ\f*~_RG+鎖gXr Pr( @a !` vmwHq7 *xf_Fw @ PMjxGOj⸎"GSgDwF ʈ$ѐ {d( pylpɐ ` ˀ)򦾒 "` ߰yJ @ y F qac6?F1L0/.8{` pQcC0y0H9 0 Vc5kV ,cY`kphhqpVa6po5B26fr4Ypp$?  4 Y 6vJ 0RV6 p9>nvkQ81N")*;:%*# A6"8c92ATQ;QhDoB&Uୢ!f#Y bIO!+#k"{5.xgG W@=4 5*T{%B"rY TL!qpg֪WYbrE8 P4gPlB/%<"CX'ʋ)'BĢk a pv'FDS]0 m ,ux !zZF(X `'ڂq-PP Ҡ P (eRpY (H_p ;(B`@C^ct) F P  P+ 0c ׻DP (  @/"/K19=1 { {Q?yLQ0Fi@ P+&,%nXc[#"J>!?}r f0r[N@Jt s I4%`NX0W 6N#KwfmqxaS֙K0L  BPr (#[2J w2Ilt l@#@TYu!r &% U?Ζ6s ]0 <}Mc!ܡ1CH†} ICpRuu (`_Pby  p Hx)د  퀼퀇Ew( pP+q4YzEvB(2xX4 XD+c&роc` &mPm `"؍Ѝm ب hH0O/ j DJm c0{d %1NPA`phZ."}@#(VaȔL|F9MW2Xc`(!HBi@+sA#?Eb%|@N/qpl 2$c8npgPn,>KD PKPw!A-˓Z3HCGhElRb8k:yd)ء "d[&ha%S>(!i!"ȋ1K,Ò(}ԡgiz@Z9z0ju g'i"v6bsF\y:&m*+YHi! /ZI8BDx9@0GŖB@DYoBᬸZ-Z 'ԢgH ׀64L.4OBD Cؙ! 8Bq~AQ@C;3R @DHhB 8 %8D s,M%Dp* C  ʐ!%S>T7a>9ЈxDp.z#<*8BnXw0?@S:ЇӟCbKi  +A &(a pp KD  "7j\>(%jQ[ Ԛشh$/zpE(^`9p@.`mrC7/f a>Zf7<1Q&ytq|@o3Z TxC#%G ZpDpil(X^a r:1D@p2_(4_ QԆ@t`#C\-DKu8!c61dA 6DU]!Kpm@yVL$':O+`]o]'jNtD >E}Q</KKЄgOZA8ip .~0 P_`4`:t-4PRIW?Q'2 Z:J5IOJ(+Z|%j&2Pz_u@f +9|z5e @Ptz;':AΒ)2;}ymI. yNC#qЀm<{@@PK0ח[9s" 9"PK@ mLP4ݲ}'6t;)?1bXA4"em´2 Ez0T/GaQVFp  0`d80tmnq 7 'vz$` kэ/ \ N3F?$yGB2 [ `P( VHFjBŕD1 8AՆ+p=-"H6 0E7v{ V27҇>ta :/9%@ a-rǖXZ" IU8!ir?EbD KA nB[?Qwl(^{M׊ .(A81ZHDBd4e4CӱQ9 @jmFߧ&өlÆ| (6⤦Z506@4x W"岾FѾ*6h/b@4POyUP#[9#r/;AA,@NP,9pژtxt`yB)dBB*4 }2H(2m(y"_PPzBaW(*q86bDZyXypD@ {bÛJN+ñA q 7{idQMBZl28(. o7rCr zxet.08/e(@z@0zX0f< ؀tوިPЀu+}ox P@Q PRɅn}x(+$xI0H(5p;Xb =S)BK/EÒYEE "CX41E :`29)?D6C貃nBD:#3L1yn%7`,;q?0(pS(C65(Ep&Yr⣃;=%(>Ta0 4: r%%b9QA 'XCEP<A;!XXY 6LHc6oäq@ T@HP @X?9@ jLa6hX<ɐ::x6O68x8@3 %AT4,*)B‘1|P|E+$L_6uw2 ;(X~ Ȱ8z8@t6?8^$تyI QbځX 8΄:4DX); U'UK_ěS}†3Y`bJho˷X@ l6x}XW({otDe sRopuo(bOG{\UP0ZةJGq}~T p+Opl+x0L'("$V=09QP7-8N4o mQ=/769<EA025)h?-WNyAȐ9Xf|Iȼ 8XXa?-;A*K>i/j-1343?X2?S1Y&⏜mE%Z2#F[Ll. J\DE3#A|Kp-11>QC(1S 9BiS:$@'9| _ٝ@-`7x@n2]tj+EԺ?<ԣ/6)[q-9d:HI;&K/R1G-@v8)y",!HHI!&ZC`Mji/:=9ﰰ. {/rHIE WZ<*1*Yc:h*\3M!Z!С"B.ӟƃ5 !& 4ݽeK"\ K*\N5HM\l\| u/+Y[yȅ A4}/&*Yu 2>BH*\bj.jZΙ/^99T )ßpђD8.@k_zAz oQe8e8l(jm ӣ@ʮl6`d8^Vn7iӞ8Cl(LOb6) hYӃ`Øh(``y]Fz.6)\eZ%^9BlS(9Pe+x@ TKOCN(c+xfoPaAà)@Ac-Vi/* ~1+ (<3 .s,(dhDHA1 EXbгbP= "',0KGل / :*9f{e*\f2F"%X&Օ<1rMA' 41,48;`(]&x Jm!K02&xcځ}Fٝv@7~RY@]DŁ Ki6bnƏpaih1jUC t`Ȉ d!C-ё_e^fȶKxF@9Vn{,vXUH 0o\ՇbhPpr`\r *pR (|C9&G y(|ɒvR4ؤ2XI9ʬҥ)'p(BI$QD SL (QKm1k(E!"\RUpKK J8T!FS+5uKM-)k؁Sjdф 1  <͡FT1GVcCOs42 %pHKP '@ےvġ`F,r!vKR.itd.!*¼0Z!aݖRQGԒ6|H$th!Ȧ#B#Ydңm,® F. om.aErBqH؂X"f@P0= b-BpEfFHRM1JUJ2vNj$ BdP%4Ml0HGN8!6$|AmcنYaa󋘟dIB _XW;M)8e]sב@%VV,IJqL&y^JN.dRY4.5N.}֕dכoe]w~6PcY8pŲCM+ * a@/@)PvHtc2`B5! 3v0 tgjհF51 mS;a.3 o!%!K)эnBG#nA!qs(ґ!BXDa"Mr'B Llx q|j(pq7! Hp5(PJTVP&vPXnm *!Iإȵd FL !*~0B@TT:Lt q7$thv٩T#U M~]&J \Hq* 3!FxjaC['aWQM +pTؖ0In)SId nVՆm,H.;e^ Ah'Xb* H˕ KUadCPtB\$r-Q"1M0y,X.j EA"@B Zhl"NeK%}Ė25M&/ad:YNd$i#Rt"AhBY |,F1.O%G R^M{!_Ltu{ ln3 `gB%$#]v0c~vE+51Uj3K@lk%khw%-A >ÞЪ4lb5SI*zd[A0w1 B "XRTmDMj;!6r>YHmV T*T-isUQ>J2C2 G+b$I9БZˆ %CUJd 'PJ4͠H-Є , HD]ˠģS$,0ƸA )ABAف#xB<\ש!C5pCx&a6ӣԦ؁QQQxN řNT!0EűA$J"5IN8|b:7'%ӶDBɁNW-m W$1E~0J> &!>eUJdT|ļ 򋦬EML:J@ 'H 5  l ,BHeA IJ!9ؔ+> 7u hYJLXfTK"QODEXQI' zUMI:C*X] 9D:':_5UdmFɄ*'ԅj(v]inNPW;r[(:=(z$$l.%,3:.9ficH춎cPޮA 7p"ޚVÄ0C"@*hjQZ*^&&*4*؛|Z`&™-|B x*\ xĖeKT 4AKr`Ā FJB Y> a%@BHk8J$0ۤ !Aȁ6@|RU lB$ܷ  )p 'K!؁[ &1 bR Nd Ad9fnZ_+eLKJFeJKL8-%nC1l xK"с͌Eq²$T 0dD`ʢ7KIDq=LNm8=J_s D0p0$2#AId XUAi$% D*/'6.jx['.V.,ID4)܂@K?nXsLF,,nVyPm)Dp|aP}8:gj]V;~ᖖ9ha -E 3FjdݲTC߮0HM{XM0l-+(p3>CJC1íG؅qՅ'\/)2#"udB#p-(]hQDG D!Am\,JX! B fiL@ $HP3t&, f 7mIeI+VD,Bٓi5SŒfT1R;pqNHRȍ%W&u*FY6G:.E+"h7-YH3?'BT3h̏ABԴa%EƅH׬;MԦ~f Tm%n:!)U0mI-ׯiզw0ᾇ.yՂњrqSM6t\=(ט9*ZdiBǜ9iy|ũۢ~Sg 6HCذ I'yQPtFo9Iy0t&W<O6)UD]$`F`lGF9|쭚jn&?a &&&Hr۬Ҷ\rul2KQH,\L-\7ۂ ҸItF.k~KoFٖN mQ/QAW\ك#qDDG4ф;BDO";(7va3``Ȩ@CLU9$~Diқ.,׎ %r@*lPc HTC>S†,Ԑ %X3+{3?PʀrC:z0c!8:$aPYZ(F,~bY$'HdOьrBNTMt oĢ # rqkJbĥ_Dcb LZZ(^PT3d2pdi`6N4i7O$ld W"Y&[PFUfDma eyPA^~68,W(x#W"PBD*G,Rʈ%}؄#nKD|':(4qM,bpE$䰉‘r20Z *BikKK 6Q-mЂA4aqMyڰ*,"  'Ja8D$qFbiKfL%]C]`74]ΠIM / 00(U8r7}#Q3aG *s ie07LF<јxXk \ ءc S (Nӈg,tXDGuBd7@;0 '  YNiI9SnTR`{]m?0] MIafh>)XÀ(G o@6 q}"`G zw"x[^Ѩ0~FvI$(ecx*aCʌBrk3шG 6n*k"$F4#8=-lA >Ɵ#A6O\c#e7J6MBw(^Ŏ2P,y"Ї-ae(&Ht\Җh%1s9I$H,ZS1St~CP ڔ2V$CaBG8p`#A>t  p,`0P + .fyƮF0.0C~r#W>DWi,Oz0 JujHx3쓨$(g o dbʁGGTzjAҿ"o~(,x'JHȼ..x;-kYpE#n@ŴkU@B1q$ F4#,L!S\"a@[jaAЦ pw0Ft- a.ct cܠ a".,n$΢ .*vG0 f0vj>a(2FtB".:C/~M @D lcbJ< b2#oph`bdª&pp"|.i((m $C," F. TC <-/B'ߦ2<c$V(&񎃿ljzcr!L |F `!Jn$ }&g1nP`sƩ g\b!z@xaaI䡂!+VX^쑰ƐcZhP!džphx@CFLV UG8&,O0O& #r9EJ΋Do8F`FlP RKȖSr&Y~ϐ$҉~wV TDBVƀ*iOP^RoZY\2!8BAZ\A+EZ.A+C8VZBA  n"F$xB 0fpG ,*BN)BboҢ,Z2c"܆F=XM @"+v(&ր[\)+J(R/p2F \^̀>`̉)0a"f$ f<.tBB9+.x#6V<ƚ-aF<14'%8PʌŻ+:EDe1AKkba,<%+L,2O( AnydܔUT~av` u.Ld.%&M{OpFfd|VYXHB!Fr!!)?S´YTYLF$8V!R,Z%2B؅* f-Q!YFa0SnSP)/:^[ڒJ*2P׊;(44xEf)!";BVVA c&0;%%tk'<(Vtbfgzl g2? bFDKAa !A6)6yaF`V)Y5*74%dNm,7!vOO0TQUPGHIˉlRr~?LDH$*l7#{bibY ,@B#cr7J18&xN$9fN@6gtzFN{nG @w^0a1",ؠ1~lAȹ܁! n r%la I̲@!LO :H\!|$v`qo#lwڄg!N6 Mw2" Xh:I=8pfa 'NYB8ƌENm ƠVsFF۴O۴o/E8A~a F^!){x{%χC/ EAӡZH^?ZN oĸ@ZIN|#uAE3*.tjPvb P:f i!0!`t (a @Hs +cJ<~ Ģ Xc"t92PG$7U$Z#K~!9㢯G~ r` dt^v"3@g~Bhn:A ,iYhzr~Rp!FPmY%;{|%6 f7wArNRL "#OE%S@}dSKGaAOIL5(QVґ0ۑ2;UP!.O|X괾a! %{3eZbYaIpֳyAq{,B @tS[ D:^tG*H5c>`(N GYA\}>,Bd a$n(tiN㧒pN<@ـ`n Ń&p`(,3p:`2h^*R⫝̸0a.`jBY-f>%% g>B#XW i`cBݰL81e2q(@"(D% !|ABΈ&q 6AH8%B GqCAB+aSBK'>#;@%aHn ih T2xX׹_E(6H9&:a'&d%BQNDHGh2D N )4wb ; &,F+> l@ L@U``LR'QaCШCeà yaٗ$:` Y`]YD8,K}jeh!f5@KyfofM)&0MLJgUphr,iP%R*I/MH\QI%% [NKj'cvjj,C Y bHPc@l*N(Fbk Z &lD0@q Su PVj V \A` PS0t ZapW8A:@Fe:p #WՀ ϐ Y pqFE:qqt! `:!Yɣ:Ѡ ް x;N/` @ V1 ;[o=tXu5O0uu pA[u3 H00 bS:b]Xv "w w  a I0 > tv0DE: =y#$z`epe8%-s-J(?s3%F? iJ/-RK'BMB-E$V*JcH8I.n 61`P limnF{h,r}-m)1QFSraϒQH&,Dc.Fn'U@*-f.+iPD/,Y?PUqWKDMbM]V2,FSxPoQMMkNo8^p B'N E U ehqRDod P < "6`S$S @\ PAC|xS I~=8&3lU9Ypo_%P8ZXSt&:_Q\%=ҐWX(EYKAV)QC0\`ɰ R_QW;}CzAGэ` Pj#Ath[]W=Yڰrd p5]c: 3BwY y"  x>pQ`R 9y rs׈#9_0$ =]w_y,`TF%f3e3jP ?0'i rHt*?$1PK,:%0QH & ~v0`M0,(.)+}Ydwb_J=`WDY/$p$@%,XKZ"1,K,AJSdKR2,8əRDQN8 -%Mb*BCi]yQ%NTOjEj1%c{O> e3қ@S<3;3r0qT%1kwN ݀6P `!߰ 0y. " Ր 0 #@ WV*6 @vd1]0 Pd @ n zZ#~A)=ѢL XYA Xq;;Ҡ /0G-0@ { !;0QJ>3Nt\O]sc 0Y#ѱ#5 XC2ڰYe;] H*P pm "P/O uC  5Ѩ ICI`0 թ .NZy_y4 <4:b_MDʬ@`w T"ip00ht|%"1Cu ? =J ];̀t6J/՟ԅ!6ZwN2!Œ!I>uҐ yS0 W&v:Y82sQT*JwN ӎuu#qqd P0 bc`b<`N ь |* pġ l_@[|0_ Bd Ib ED Ib@  }C "p3#s 0 0BQX/9k (=*Sh,3is_E(Z`+Y/t֗'@Mb}/Q(-ⳳ%$Be}X"J=/p4vzǡenlf6iPHb0 sPZ |@)s-Fb'3L'`'0EJE!Ŭ8KL}W,v, "䫃LtS~-6Fʿ0(ѷ%r 1m ^6 OV6p"Ar^@Ԡ P`p5PeĈ]&1Y4i &L0h&^ĘQF9N9ZÆ!M4-ZBoꢅ$)L¨I PŊQӨQBEz+H݂ 5~RF\GZM!6i!gJ[٧74 q0WI풲W^}zBU(K-NL#flI'\b AX"T"!fi/j,CI%؂뭓2Y1Ȝrta&+qYFVVf8bYH;vX t0$@Tׄ0bf!FKX; M/PqgQq T?+fI4K rM&iZS<$/UnPHxQT z4Jvb\%OKY"*ذKi!؆:YBT D7\m߻2LU#0ַA<[" @ԀV` *D H@ZT @(`&m ,q9AJS U.P Asq,caЫ& ufҚNt%D(\8r1[\HU ;$㺊d\;`_9jdF6_S%ŝ(\Q/700@`<KpxE ~p\F4⳵W eb ?A\އIu@H'8@%:#daiB&ڠD#%Z1XqD_y2\q#L]AԆ,[Ȣ`&ںAvPD J݇䓙Lf7r@0e] :VPp9\䥟 cHK v0\jS&z6Aeoђ׶t Oaʿ&K-rMfu\TÙCG: H7g: HE*` Б\H u:B;Djxj7y+ PfЛW 2Hk `0 YXKO8ri9цV/63±H$TBr1*̩Wr)z< ~ z˪wp5 n@h(JTBI88G( TM(@AX9PA`1XH}*H5h0Pp{0iR"RA؏86qPG`I&P,#*Z[+%Y:i9 :@ /!% kd\4H+,Z+6ػ;i җq%#SbQK0-9w>ȂJCB0!JA9q %&y-@T0 >ᓯJ1&%`> \R*it>1`>_g7H&6ZrxI loH<&'Pp$`K't(3iPPSKZJf%kjP \@@,f(|wAI'KA"YP O"#%MZ*hhB - PWp9J.9I$3)$B%Fh`Ta&z71+QWxr"J<$pm$c3zʋK\ au؁PXOM*$ׅhT3 dcc*)BJWB|(`J@|DX)| j )s6팙_Ps{0ίjN*sxTl ~j09#Ѓ {0epȞDKHXKpL Aab\Pt98-T8Ѥ =!;%X /Q28!Z+" BG؄>c 2\0Fi5:d\Q#+E !.z/!Xka".Z4`BPT8QI%h,xF:Fs#Va8r1s,P@`@82]K.A W"+ &{ny4UͲia{7[keDT!`lKc- a-m(yg VV‘P f4Qrq*d w aЉ$E_\P/ B+,̈́\miX{>sW4=ƚ`nG8|x DbXhOOUo] rjL9@qU]9>q-ZA!YB1"b.qQx+%5!:xZ8=9Q$7(] R/X1F(.{,.S R+2"+s-0rR[& *"31%ZGA@$h4@8r*3h  @10=JB(:HPH:zAp73}]],CT]27`]%vYc[uʧ-+6T "]‘Y$"7G'*#>3X" c\l. R9Z>8ZNpB4h6(+`6kiU>У& e i#++-l)jA3mp(a2WB\Zx!\U6`9p_qI(`da3$ٙM (oefÆlNxh@$p}at l`QLɁF5^cL7X (%#Mˠ6xg+-5 ͆?4wBoʃ:郿Ioo z`/ * q.3&qKUoP*BHhb%KXtZZG[2pCBQqZ Y0:7p:h@0#DYGQ+"k [ ;qQ- 8ؑYC #Q;hZIc:cɱ0I21X"!JtEȒPB`@h>A%8&}Q8-~y$t闃S;-L(~k 5>N[. A'`P6RTjh6hZsP`I2`I8Ir@-gϛ4`q#>R㨭گ_t4fҜ9mZ`w'Рo-j(h1UMگ9G) XI\<}Wbǎ VOݬI44t3Q\-l0ĊEUGMP@>ղMlQ{k xfh}!7f WjޖAP"y 920I(obXA+KVTKڷxW)SVG|)[P!T.rɕ#Jq` mH!$qat K,FtAG vZ1ȅBd h p q\!UQp`#HCQK!d AG+@8f,vQEmpH""q ]z%T9VDt0*@ raC|X* J +(q 8hQ`rEnM4 1s̨ƌ\ fr p8FЮF6چp -0Ui)طtUIB3#AKɡԶaZ{Ԣ8D % IH,CG@Gb=dF$RH=%,$rM.Ք\R$93h=:M4_T4Bea1֕YNZFC%DUM014v`BiӞadaSoYϟFմ UJJ!5%DN. s pDq0B/\2a <+7^`+A{K?tч%+@ Bmɂ#aB X8Grr`" vl)Hr: &\2F:W4Z!V$ 8p:mp0d-!DN@-`{nxV*HRD8)L $a8\0i l<ITĠ:*8h`&(!P84 @-A mHC4%;q *`  P%ni/H WJ&6C2qbW0 GAVr$}qR_5-6 @9Ƒ'@bkC*18EƆw؃͠,e;/O LpiRhR upәJOPnY&&23Fm>#&ƶ}smn[ }Sj g<͞&4YJr8%nqG,7+pC#hD v`@=ı o|Cސa,񇢊+*OZ\h`!4n5!p a?/ z4C:0Kxk>@uXSA j l%U\@![AD<Dt,V ;0|iNTH H ".8uH P-ScԡH(@nh8(!Ah큑@0D HkO -:C-C8H߆Gqȓ&0R wp/̡Y Cva $_j#xFGEʸ#8Y0qYw"?c!( 5JRMzx3.ଊU:,Xi(o~]&̧ ؿ} > 52PTƠyC(ߎg\36r T*\.z X *!h@T#!B8@p9~t8x5x`v@0@7g+& h-6` B p ʡ~Zj(zs(7Vч.@0@B 0r"4&UkNeR*6u  k"JhOɮҐx"E۱ӛ(g!Y*D*(JÅtp\Gq`4"XЀ:( Mh9,[8q .Qf8Y.!`3$#}PtHݼ$%|A_Gc # }oVA ), p>|ss 0CF6^d'k}Gy\#]h&3\`RENZgFGE sDW.6tf-Gi(Rrl=eq>3>,C-Ba+[45чc/y^g.@݃" ;o&-u?A<8 (M:ILCC 3B6:h\dIFِK_Kz͸dydMSNNbSOƄD\(6qS2=%UX`eV~BdQBY ;EYjLtA8mB:Lj|PACd>."br>p9@@`pN@B0!c 2,,2Hܛ%,+(8$U#Bj!Q8,}Xlܠ|Af!4 #tPJ^%D ~u\L0ɒB ,b:F?F!K[ j" +è 7%2,xAx3B:'4[MYPR,b6zg ]1 q1YYl}B! 4%6U\A}!|rBT y"T ȁ -A H(H,B}NI@cM\amzaqUdA#-'h($7T3n1>ʴ4xA elI]}fvi8ˑnށFꚥic~9VL@ )on^DAF=]6C6o7=Q a1j:I*$6(G 9ozLN5xLH `t9y<USXX^':q˸%9N{0=$%A A(Bu< Xx%<XA35$«|ă27 *H  ,[\v@, O8D_]B.؇^\A8]hʕ̦!$4nG#4!hyB$Lh P\*4p⅘@$R-BB^-2VM X_5BrqB# d6 L8(An ԶV]ˉ8lMܑTKmzv9JnPPж Dww.~6YR9xY(φXKPU))](Ǘ()HA+i c=A<8)4X4J0Xk4[;8*̹<(0yo۬԰K 3o4Md/ u>oa-AC(4-pLtFI[Chn ;$8Hp@^C>A pZa[3kC:= Y%ݴxes' >bxBk ),ΚJ^;"Cـ48:0.Ap% DÑ469Ɍ+9Ot6e- Vd)@4HrsC~ "WX &5A:PK\ x  Rp{fL5 B+Y @315 1* i@M*qp #e?U  g.69Os;`TCw{<Ed;u7uzأ KMA7pB!^C3H†w @׿U&6h }1HG:qh}* _X&Px=-xT#U~*;U|RQ/|qMBu- GI 4jd EnzbiD`{h,WZ5w0t9Z!l7 G> Ic`%_Ă]9r!)va7X0;@x .>Ns28Tl "uF_^'TA8m<ґc$b XsK9 `a2 zid,,*ZD/x?<w٠6H!D UVl`!т#,08 &c/@ ;bDUP>AT֥-p!)1oӆɒJ-TaUڸc*;+vj;Gy5HZͪw}+.w?R%V@)H /.PЊ<|uC+Y/dVuOh+6WS # \ jQ4M]OÄla +D+k#HYbvE|G #}SP{N2ZжpHVqS)}Јvrckvi'ɢaaX`W|¨"d a.hAUP!.!hꘁIPY^A"8!@ p7.kb"B'&;rG'BG`6;'b \@C |6 uab@f):bj (Lˠ ؀(B/ 01/FA*@brvel`r i B**.+l +p69Q-ƢDd6  .%`"HI(1&bWd)8&(diÐ#R?.6y6D" zjlèTɛ{s1Wbt z J# ,8a],]jP@+Ҡr6(P0o ` 8 zl V0adWr8?>X¥70o@rX#FNwrM6xҠ ^wZEpyzMgp| V3C5Cjhį rhQ x M\y@ی5dah=PO8n#jbFʐEH[ExfAaYEP\SG}6F!GJd=h#F+B!@^@[A ;d^ *;~faa *lQxΡ[z 뼁F@@ h@ 7x )l?9d &7QV-y/ihFKp㥘V;WAiҢyCDo\K}ljՖ֊$PtS,qD 4?D/X!=xM4au~m -" 6x7]EL8` ="X2pYhM41%cP$s qmB VB$#fTq,b"@G p,Giځ&8KHtkDkб T.&UTGKlF vH!mnlFZAKTFwv:@d" , t ZDE,"%~`n,Z,68 b\ IcQEfaUÝrH8Kx1J U)꣤ J"i zbZ 8థWaVTaG"&[!er!'Py7Y8qˆ GlODq2= LTC: 1Ê)r]^HFMQ TT -aaYiݍZmEuuIFw_!s3E}Tc7+c@ڴwKsYt}'> va!TGi%\;(-4)xՔv{X#4=w2|*I(x:07TX8\MHß+$VÌYHA#i"ptz5 p >, X$1+9BrhŖ`CP C2bQiU"fQՖdEy drE 2WB` :T&.A @ިd RBVp,Tlnj`V+8,!@ ֐ i@ @U &ˡ"SRMaLâT" k04`.ZT@+ D$aR- Xڠ-J#}HFI mHDL֦* S1s-A31&g3+x'3"Dюv0PUk L|@EV=(Fq8ځ . bC)E00cmh[7"8Q'”-2z 0)ըL:꓋w<͝JC }J25vS Gx` 5z0C Rv"\:RԈP.>&|X2-n6$GfY8|^i.Gk;)O) GLgğ>(_0#@ {i\1;E(6,\ Vb7j u HEZ8`"l(]]`(~0_R6m#&mSJ85Be' >+F!vF.5n6OQo*V+թq+0\蟹mPD@*+ 3IW?Y A'MAP<37=lx貇[.cه"E4bQ?@ 3sc;ȅr"'R5>`6PC, sQ Jx'ġ/1pPMN'5 QqYTZ9|!0P0YBR8 #D1;D6u.bKrW0Mks[Y RHlP3 M[ZT(A2 "V ͹dEe Qve8pd*ٕن5d\HD&\4+&v~y~5z bm@АZҰ $vPAman"5lPR16O! hT8#9# pm$h:ɡ5(?kl]ņa @ 6SqN2ؙ`q`GP L; n!eqp p q؀ >v  6NP??2  @Y QP 2;  `%] )`)'VucIY *tR]TƋv@Dt.f +iG x*y(DnK+&&b^)&m`(BY`bb MBKD2.fR(4^R.a2^(r0'W A6+J0PrwFOUds )1DLH"/۸Kn K *(Mz1'p0jM1e⒱wMmt>vCNlpmOR'ANPt T9oMR 5` 2 lٖQSqp:|Ija 7t `#JEaMFeBZ\6,HTJK4*%tB\*'(T}+0'B $-B_bdzIR(@F£Bf{"2K].\COJ($,w^Le2:FMeĄ #nIi 9q3= +fѪǔ4藫xg5qN`:-0h _Q p`9fViqQR Z6Ucsb pp3lj ] 93XR` \09hI =a!@A1YQq fY$rPfe=) "1(>\Q6WY_=r"FZ%(\]w&}2/Uj&R)X'Cx*)ev)b*81lrz*m@zU`8Aj%>(`H_r0$ c.ڬ+`R_ĥյ)zEm0%L8  *GzqAG!ZA`kI`f%xdd'ȡ4ʋh^CA+t̡]B\m:/싨B+2Yy 3sRhp4MNO$oZOPo2Q -OG`x !<ְQ ;$s=W\e!NilQp7 Å

    22,pDy.{Er.1b''SK' H,*͕‡1Hv)W_l&B(R[ua)ZCG,&{1BM]LrcP#IRu0mXuAGoV:Ps T(2X1u2)̾H1p1.vI)%!'Sũ*}12j $3R4F'{2n4TP~Do0Qo:1G5`| 1fаS,LA&@ ә\Jg/B'vwGk@0{N(BMe[Ʃ̧t)%N@2Y"<3Lj"5.gm03O41͉RݫPgG q "8SH}b.aԨ 6biJZ0ϞQ$I)U4iK0ƤҖ4m֬qO@l CVJ)mS'H<\A&5\ٞIʣ€UtZt0f-t}LZݕr%^FH(W5hGpk6lr )_<2Cӎ8$H5`4c0)͠M6D9BQCB"T*0AX74Ì(Mq`qQ¸!cnBs$QFi-懎肨+N,%yq)&[@I8}IS(lfJ酒 h Hɦ_]+jlfˆi$Fyr"FkB8VI0P*\pWklP(̾Йŏ/FXb!!G-nY(^a$P7!˜{i9Ct"ZPpE`s=qBXr%h 3]%c! PhB1 4N`S*@AmIUX"IHtՔrī"JN8bߌEDP;D:!TkD# \YPCE#Z܀#!GkB 6jF+ՆHDq 4:)!KZ҇X`0U\* -r*5ApSŁSA%(&FZ(+%!G@r'XZ۲#pD[҈-a]rp#\yiN2C5p g!b!&†0ElE`fw<Got (0OBr- T#&0krQN%1vvO hpC@4n4< CB!5آF1,Z тD.!a@fqK=聎٭$Ӑ5q "nJ׌6M1SQHTC3MΧw LuĢiLiTxdG;+X^͙= $͐Kh;_Ṅwl9^1|$I-} Z\@h5*NCPP4D&'0 ^XT';0m4F~tp CA9 BiZ6X.X鴄 8&"p!%,rHBE@SfQ0BC 94a~AC\9!k#B44A&:1)BJ pp"F:wtK" 9.OM[)%J\#Z+畾 hta R` YL(atntf:3@$A sF7| W1',C$6ڃ=.5m'>}̲>P"ЙcTxA@ jB͓smA +A 3P2\6EСGJYc2iMSl HIOqs9xELKrA:uaoj!adOx0˪懑5Nrs0m62"xkK֝,vS`#2ҙ5h +Ub:j8?H?Kp E W&Z$)a[AҨh4HN""!JޗNАC,`]p(ww{cR0`#&MPfX1B!ܢWt;rB3B\LdO A f <\& #>IJ+x=`"p7(h~Ddl@On4ĩ|ӝ(G8#bCĉ}/I$8Ap"VKsi:')Nfc gb& AU`psrY*G;Gӧ8Si8)=>'Vx_XK)ȄJ)=IhIWcV:X_j0d0Ppt8 ˡRia`X*iecᶟ2W^*,±Ba(h ˱joۈX`X؇}h\=`#(w;2싂{{Awhhi™ksҋ\ʫ3$k`sh4('W;P9Z@8QC .풃n 9ʓRmJ^5";"'14@KP!Xs $!GϓHH.Ŷ>Yjx-b %!;Ϻ@<<H>P1"k(5а@G5S@`/Q/#zG7`` ;9#( $;@0I4$QbS28.`QQ)e(a0=YCȾ!YhKb 70qOSGQ`QP{Zih_x ÒB)̧ت,>(@bx'x=HamxhUx5J:pd|<)NHn_owxoةy*o4#yB& B a\^mg /l\@Co)C&4c8Ђ9ȃ{{zPB)i~(F B+8=w2kZ`% -8P.9ÄɮS9> ;5qSp=XIゖ!q(@pq=-惁CK!FY6Fz ;&ɯ-JZ r+حCC@c"ڒk9h0H KI;AH(/@G9pԒyG-j2%* q9!;?q=Fns$C%45@4<S.a pUVGT0KH>Y( 3y%XWYxu4k$@EX+ojLKP+>@Ppg)PC@)'ZXI`$^bȃ= ꅑ@*M!*Z(DlNO l锆A 4Bو(DBN,[`4‘0S98bAժ;H2 1+$E}Kr<VA R6QG1K#!`gt1=JCTr@*7)ZPfIC>;n)(q)٣ڬv9PЁUP5@9ɢExY>r(S??"T/h9z2pIV2p!>V6@4R\+h!X ؅ HV( FxF`Y`x06KYKBcY9.2}%b3CP縆=Ko [г KK,[.\ؚ8,Q5h3ٰ`hVPYo ٰpM)ЃGY\t5-Dahڒ$ +HuhPqN 'p\BXo@LEBIī{Xv * dp”}(Jb8lL`aGJ0aB4ke{X/oxdF t $$̊_@f!nj0OQ `X[PFyeTn(J%ّȃd{8gn܋+G#юzsu H$YIWx xp-6X E06 ٢C`i %:F@aT3GFUgAj1\C!DGj)(j92ǎl r (*("/1])YIRi;pq=~SXQ'y6 K?9Lt9>9E,9;HMe!30G-{2ady&*n)$7x0*mKٗ,V(nW` F`FnFv hyY5Xc)n{o<[ZB^X!1(dud_p ppD[V ]H^/n ]8zDNp / .a`!,Sx/,g]iЁ>`z_`(d9' lj:zo8M \IΙzJ8 ~_DC&?I.w̹XMX`/{50 t+* 9QXbК6v,YbpQ5KYQMK LXN 8s)!,X4B'P ;m*h614s`5.h:l#J Yaǡ%kP\gD:vT1զfp|Zь3ҏ}ARg:WǧML$Pi@iUmҩM'K:ҴYV3i:pd5֮C -57h)s a~ ER="#4*`y T`:# b; 4$xP ,\wϞ8or uk&WBq'/_~C 5 bj4~(#X'h+X͇ոaR(!LCa/+ 4K>6\PJ L4=D8z:SM04&"L3XҢe82HC 7$_DfN 䛋2ڨ2j0''`'b:4p>( CEPkG1{Ƽs=SO=5萣 6餃:̆ 'ւc,/,bYrM4f:Dm-Tq6EE] ,bt삾RY*`Z!Gihas _Eqh\X a8贓CU@ -;W dBp\H& R1.UEDbKD+4nx!+$4?QT.;mkUUCE8P4USRe/qJY(]q -tDmL>/oKB؁EpnPB/U47ݟVi6e6[keW]1T0O%S@ Qwig1w} =ߗA!{79xśtB'| 'BL`!P~[VXm0-2N 6a*dFFbTA@ML&fG &p"XЄ+PZ`ڮRE )JdrQ+& 9Ď3cXwykLgDaB^PW 1RaYȢ;8;q3'eArWl1 TT&Bpc`hE;qSz[c:q/T,rQAD! tCdX7r D1uDxT M^w nBO`|;#8 RB+BPJF:X%\bk03eOq%&la?ZA\7 $U$Yz\ƞ|V::NX@G8[*c% UD J#*/1NRaA%HQ:2KD A#a;"@O`M@ !ï(/%4NJ-aҨz4HH.T BjF-\l 0ܛjZ9"8B$8& [́B@2}E!c[k tYNݸ̮ ATAnfޥA H` fl_jS9 1A!APJF2 }<  \ WƾLC|ېfDBA\eeGYCDBN\ *M˴N`# k\L$*T[%4B0egC0FhQKQDLA(la[kdLA(R^)R 0*~!hmFi :D 0&t(th,|J-ÀbX n&B/pה(6ň-KxK+!ِH0PJ7 ҵ $Z50V݁)0Ā$A (F „dàW2^fPj)x/$dА3;*%܀(֗@ H¥2Pl)2xC8Hq-םR80@FBimmRo!$7CnBѥpB1S-pb,N璂-Pn1x-K뮮3nnȇPC73d4҅: o ʼn7l6Hc)@ D#9ԃ8J*@ /b2)h&/B$0(J/+ P=6$#t'p)ICDkWR(3),Bi}-|aR ,BE EP@S9E\ne1Uք Ig~(oD; AYT@DlY<ɒ TDް El<tքh0]UA p*DMH" a5Ul*AOh2H68UYIBpFL0F2=.G`bJ Ȇh[.3/F>k-N1Wh Ph@!ԗad%@&#$J2ꥐ'ѥ\B\ ;w3= *FKғ1X A+(yiW慣x%E0-LÙQ2C<$QC<$#I \B9 MMoH)DLZo ( ىXR4^& ,Ou8PB=OpY}H+(iJ+i!zDUTt 'lej4}Xa4L)F(^h~5.XYGЙ"jŖiҡ̋:JG}a '8qQǝtѦo$yahAaz~Mvd{%PWlRLiUJ4fba evuޱYhH!e[At&*H!e? MDPW@ XhB0GĨ GC"9K9XP9ԐC+t"z73ڮ L `"+0 ZAA C !AAKʖCE<Բn ۴R[,I%Pb*VXήpp- .EݫXČCa\:l7+:;$;:ܭ5z ΢=5⛃4p8$5`BX/D_HV9 (5RLA{hJR@ܴ!pDE4bf4"̈E6‘؀p ?rj IIIBR@ + E6zҠ-ԉb S@ByZ'ja$D41z-l 7ڌ"j尉DGQGdUHC6,#XU5!V`ƪ&FaӰd0`D!ƤlAj[d:)_ JBo044a C/}Ɍ+D`ll&'P1!3)oa%!_a )B2t$)~3R<|F@|P(~fiH S7(EF8AX QC V,9N6E= ֐56\.Q\9T IE iAj!0i `)J`ZV`}&Eq O@ jNRh uee N>b 3 yJA+`4B ntx%xdQr/mR8Er! (%t#H5JPBn7\B"D$̀6@ {,uxJw̃d  BpĜ.a aEJO k#0(I [3b{d:TeGMq*'X7+Ncئ4٪1Ҩ6NM J9GZ#8W:4Q`49$$8͐giVsE\MЄ' fkbEc8:POќP\LB`%-h.K8p5; Om~4GhTa. 5D匷d4Nn8u O -aø`u3 UMkbsi~BGLU!PCP +XsM`1 2HX ]) ͈8#BF%Hp iIHԡmn @b:6!,sP 1@ڪa)6DY/GKm3H ћZb*0w½ `~:n*TP.)? 9yk=<lv }>ַޜF..)+k9V~U)ad[7\E%*d V !S7MN~dr <C\F"UY/1LR$6(.#\/=QlT!h@b*o$^bne4L f;3j$BJ D  c{F" L-'.Cl":')5G4.z⧲f6@Fc& T j"kªJ+-"@VF N@ pm"p x386 4/$j jwơ2kI<"uM27C;V@FPpJc+Ɗ9-ؠ ZC @bڠ4  `b@Vv`F`b!nVApv @ $d딑7Ƨ3{CEM@a.A @;+-Ce&0Dx>:.348c3 '5JJԠ&CP0 &7>$GAT3 Lkߔs D m=C`k%Hv:4vC,Cn8-G[EHE~-)<#ft56dD?YC`rA~D`bKA!`,8f+bgli@=cDDv3zF,\4j̢yB)Nj>#<kV,T$ DcR$:D$H@ 5.l;BF"!@dkl DCD`^Z-AM q۬b5F6JLCǀ:Ix]^`";gmP:"ͯ`D*3> ڬ1SJ*+ df;v ,`U*q#Ќ5t옱ΚK\\N-sԨ4Aќt#L->9i,libEʓ ٺ0P%fVXP8,!:ppNEG;m"}跍:T4/Km82(AsҤSQ%QN\ Ċ%A,fD,[`^}@,ygu 2%J`$e5׸ئYΆ͛oʏ<2˴CI$ϟƬ3=У7&⠃|2 &xJ((3Ԃ+(b (* 5X:4hX4<#/\s4=)L6d5;>%Q/D:\hd`Fs y,l .S 6҈=e Դ矀4@H7h̚,K/݌cH 1%Ũiev駠iL0N?Z 4Xz#+(GQ:x (`I(`7p&˟mⵤD([mGf{UatOEr$" RvVSpLQ^9attm!v]$- qH kha p B42?ć B#rhK-|ii(VDX-!tpI++BбKPQy0nvRE)lJU!rQOs8RaRWá$n,3P%x7 J?21Ztխq]vuw^{塁y$ylgQ}5ĮTo2 I8'!s~b/0x8jHYgb^+K@Ǘ1јd DӘtTVpC0zQ sHbD X'alJ8̡GeR~dvT$YVC`uW(6bH#b'6AgiZj㚪>e&bpZ0vY 6A !@t3nhUNȅm Hbt-$$I.S2hFs 21$&CL^""UpXpp&4Aiؔ6"Y cΠd iلC p"r 6V6D,\fpaP4Pf_$P А au$$8@phB:56T:ح iЂtcw]v;mHu;6AyR`B `#W<+hꠂ:(ZE$ڢ핑E#r!p~pQb$&-GJ 45a t00m걐9X tcOadؤ\, Sip0h@.5ܡlgK[O@Z4!Hy M`D1rqFA($0JZ#:aY Grvu0~3U1XGe)f8glQL3Bŀ4oˣ !3|b',oy72[%0At t)@ 4 @aaXfS{(f A6!͂g!W 1IFnl(+!{(g76cʌ#jQpt-*V e$ʀ7:ԍb#YĎ5@8UCLքqhdi wC32a8G)7ZmtB r  IEM#3ey$dzAuVW1vP ]u=v&LHi1}.P`qe!wtS9Ebrv07Ɣ8 UW7ld"80P*0y](Mpb0GNq4D.X10 wB7$p `t W.T^^bV`Aw~zA1: Y~sJ#dWOW0d$M27:6a,P8WeU_w : Ó2ES6e;D<VGDC%kXk^yD>v!2: \t!2tU!"EVm3V6m$v9x@FX&8@@e U )p t >T` 3QQ0p C c" {* ` /Xmb܅Fګ~ @XW9nEX%L" @ R$4BG(ppzpq&)BO$@C6 u 0-" P ):Ӏ 9 `Qr@p " R4E(b&ӖF{h3#c1oN~Ï(pJrp uPkVM:A"0r4d 8OX!fKÏUl07Fbt^FyI /sp |b`6'Pl' 8[STd(A}"d za] " l40qemaHwHOeM#8gga73suoPxgf|&ALzQtqPW;,i2m@7 b  Ԑ}J<7jjaaL0W00_@MQu.dPvUPea4pF$H=2Qa|QMn?!zQ0QLYF`%uvy]GiF (SֱJg}V2Am#CMՅL$L%[JI%٭u2&Y):8ՠ& `jMA@ rpBƪ }P%pJ!#!݁:gn[7LNF}.HVac 6t3qpP0]M;"Nz$]f0jQ0GirGbU@bp byw8c+3H.>ck6KbսZHLJ iv4ǤppS89~x7:7Y26R;eT.$6pD&Gq$xd0ԑ1,SSv]&>@' Vj 0EЂ"  m:4Rv@F@$`Rp D"@%c@ѠXU:Xw &p`y< A rs*z(sb J upK} %֖"pU-*bgW.Y I7er P# Y`fQeU 1cJ*K9aU hNC dLE"8ܸZ8J#v촑ɑALQ 5( E 83v1%fؔF,*t6}]D:tDV9(*nBa[+Pp4\E3 7$ئ1uT4JCq[p,nCE 7݁kq3H:9 $YUrJse5I 8nԨL5gܼAfaP" IQ$I>ǟ_#?"uޱǛhBO1՝*UQ^ XVE׼`@tD,Yhi2HY0Kbu܀6>p($"`:7P;yP =3R_y,rdj=oi/I0>ݔI`Q&Ili&/I"zsHLJ=:5a Y#|TBNPTq©HBDrUh8+`PVX`1!C`ZtHnxf Kk 5\*`6E8Ez#w"C9Cr/C[aøa% lF jP =`b8b(J 1!, <NpD ې0ŤBx}.fEJ4(sBd̠q/+277wnQ\E.(/)f3e %/G+ld[BɗDXⰴVlA3A=Oxd7'=E3s!cF(P .KbA(B-$r)L[D#F({7jy꽝rϧoRDu0p4'aOߗZ#ZRS8A lJ-4BRSZADϬ^ӛwk2~aBJ?dN9qHa o( MB7.\ .6X?EdWP.n"T."@ nBpK` g`ڢA h ˜j~5@e I {( ~NB(DVq1~ʡ ,@ N}8 85F/ 1€@"$FT uTY8w~= faX qHE\B2gLb`cYDEX sT4ˊiKm mr$seLsI@$+8҆6QmhhG::E!A('Am`PK& ^Pf.Ͱc!|p FAg(ʞ @3 =}TzhtkN{ѥ$fxJ@R_(I2a`H7VVZHW-iZ4l5da;D96LY2!?H?%)N(8`!'PyTXO,ZAr?a@7`ȡBbs%0ȒڗCʂA1-pSui"Ș‹HH0d9M8efiɂFB0F۾ 4뾶>Q 4!Q 71 ' s` G?+9Æ%/ @ ܑ̟`*>+PIDncb7!E3i2t7$ CT #SHOH<8\P5rf|2j8):a܄E$ƛ*̢ѷM(s9TȂAS;☎)`-X.p`DP8qg1 Y栥C:pk02șD31B-+gwizF 7;(sO4 -*ȑγBy4tȒtP>܃Mjz685Bx^wX]0!h$j+qPPhOhߩQ !qȎ"`nE m3IICɔeᴮ\OD† M/!6Le3HO˅9J$D ʞ\u.A.b(k#,K'KW$qc?ҕ@|ۄb): 4 %X&HP>4*89& -%V0g)ࢃ` P;1xK N@Ԣ`LbiqɁ* -pmXТ }3ə@:@'!ͪe8HAЗ$BP͉ H91ৄ8/k1pP #P ǰ8$Wb" ze)*l,ypUsTqJZ@+ 5`VY=\yx]u`!-QR{0\3 z*!YA)*WuW(ž.|T31\IClPsSm6axΣId07DɘdSĒ/pHJRc5^ SX uhM+vUQXM7(M5ÒZȅ!8X0)Ebکi%,U(IH2jL"ͱ iX*PȢh D9H I&0NY5عYBHc4rA%8T`3XГ#a߳`,VtQ-@+&hXVlPаٿ7Eї)Jя[AV:Zt(d/nSx@[%Ww[~|m('xdo\P4R A1@Zhҕ\\+,/?=Sf6S ]](Aiԅ/0UJ/ TY 395wv(E(`o@KHQ2nXyy]XTQ3[UN!uS,tZ68e[Dp探Z\̕Up<0Wc+h2f0i{P7ݛl(n^]qds.tVpe uI^GA5a OVp8YXX 5vȇ%hQ^v^a!]SL&Mp􀌮#E%ЗG3|16hJ-13g qiƚN ظ*GX`њ:QZc9h蚃[W i@F9lF#@$ y) N%=&8;0МYpHR 2@B ik Ѱ稍xx:ՔXq#OZquy{ym 5oH?> L*L0es0yE0{XTQ!3Xr`UX6)%>~Mbw?g Ǖ ϡ!@=*!IH_PBX|pP ptCu;\_Mp_#_Eh,: @H95`dA1/`Li1#:_ j/ ąN5n@\U/%p85$X%@h,0,s@Zl9$08zCĿ xcj" ;(2_PX$" 1ci\.!ЁЂ6`:;nicƠA3kT1cg@: Ԧ78̘d 380\(:,"5fAPI ':uܹgԞ;{vɸ\t(N+nPj'Q~x޽!G)-ܸrq{IqtʓPC5 ㇲUrrDQ&Sl2(ʚ7sM\*ԨMEu`մf[[ܶU滷‡ M8r+:{]&\{c ۴`ƓvR}}qرǮo~ϙ17y x " 22  r- "h6E7}2`c,`A o)27L& `H'hF y$Ff=dgpF 08‚r8i iB'P!Z;@EU(DraC qQqIUDR" A)mBmBlf`Fr4 ́ B` Uqp1-&ry 'dU 3ѱ Z4$;H!@RH? ΑtA8h dtRK|In, k@Dm ,bCcPaW j  kGWQA2GUQ/iVtQDRkU* i-Ҥ<ERG%N*f3N2 yJdLNʄh> 3LBr'rLC4#Y# IPlGL[&#$E+.%a.~PeC[,H# Px[M `qQ 3z)0P 1B! 2~H*^"Hl!.!MKP/ !ff&0, jX@]`q7 +6IҰ:jaBPC0iYaVԠ) uLBb uUDMfpF,a LX05APC@\ qCH&*4G*7DYం̲ g"a!JD2 E;!PT:XGCG-j VBVxT](t.lA]8&C< `B&U` @EtQ*(.(VET1 9\EWgE#wU;l7:P3 j>4zC~ `=,bh!%* hLV@:1H+4m3g?mx 7 TB:x3k C ? Q'p`/B!%L*Jғ27Ծu-( 6-\썎A)˓L fTp -"MdR&KkDf4I$eCJdeF7 W.m kDj "&!h$KIK!f,t#.%IhAƒp B\MDAXp+(AQٿpp';d0k١թ!D(ac @`l[ i׃EIce\*y( iba[E/l(+A1wD Ep$Qqԣ0%`m#! !"-Z-*AFwyCX-T [x8Ш~P7!ϛ-tYʓ@Vى;8ajGz;cWCkHP} nCiK+ssWO/A1x.k/AE߂ƣ![P#E|< B4q/x:A!J4Knqqi(' Of~ ( [L=ƨ8'j 3C)ai8?v0@5ͺBtva%@J̰49H0)l O8,4)&rv!_KYԵu#:ǣsXřUPeaB2.\ :2vd캈LH"2U kA,* bFia!Aڰb,zdŴdjdPfC\pJj*l˝AP4)@Dn$ @8$$HXA ZT E]%\L ]X` ®!5pB)xT @B.\B_Hѵ IIN/DH/YU[1YQHû* 0fΰHlŰTD4D!X-M¡_R.8P Aؼ@,`B9PTRZ < M =4T4'|/D'N(X:Y&U! Da[q;PG.a4yƈCuxd\5d_!eez$cޖ:,l@.Da ClHaə恐BY@,8LEUCvD+C*B FފEDLFGdTDL5e'B2DdqƠ]E0R@ٙΤ=K$ғ D@MKTdL2M1p ۼ ER[ B=Z P 4*:C=m '#/H% Փ8jFY rN `[B[¥ WyU47c[ɥvbdV~ 5`CuDkubLmq@,T4lay.\Wg4fj3HYuԛY!aNC4oHN*;C:+B .S,i K8rC (K|b}PU,Inġt|BDJ DHLȸ HTxię_::B* _n8EZ@ѮTT8qك7|4P ^2 6'bpXv/UY1O`5*jުvLtE`Cvx0P5pJ450@0^jejXup/TC4Ѓ846H:=Ѓ4d(4APBv+Av-/)l'ҙtD} 4- _olˡhEt"ʭBT^$DIx,%% AĄ ?ާ҃y<^9m'ʣؓ56-f#hpB4 ADQ0l ;ʔaE^<]C\BCP雦  IPl l)d;mJip H@`SĿI"1M> N\UpZ$j :C>l!Pu\slL:U%Bb(`,hNw5"tZrVUͩ=t/EE[twܖ;xlnƇ~4&I{GT2d4(@p@UP-0OIO4@-T b]nqC5`2@:%8&!J|qrcܽ{ݫwo\+IR0a8rG^XIV^\6"%cA$S}) PdLP \YM )0԰Fi8A Q;Mh\ƛhD7pF;԰‘&j R!,#2`yayzGxiYRZ~` rCV8h[$@I!`lq%XW\q(G8_6#H *V!ȢT$& 4C+:(@(ȅCBW ɌH sGK ȂKPhD-6h"\!2%x5DÌZҊ8`$l@A !0aKh9h%f:!%*/:%;b;PcA׌CNV+jH+5"s"8(ꗣ6$9j.PuS$$l R< G nHz@o1'V[0V!&T#Qj)\B齓@U70lAl*/ 'qzoqiXted,A@"޶$ț$ _JΦ$rd†Hk@N#C`@,{Q+ʁ dadXHjh#j1( 5!+ 3=BnpSR ! G=\OJd4'!O‹ W-xd5jj!n빱WFkhdn͕DX`߇BFJK` $pu`:vp 3c@>`/lAA  lEXk05A l/(X*8\M:ȁ2&WmgX( 7h&n*SY Uh vIK<"袓YK8Qq1_~F$b|L` r v"k6(Eܑ %='3x#pa̜gd6c~"' X9C 9 qXWTǘWI&/#(YByA pK<$/-]2Đ71aX"1$,12j 6Udmje#h^" 2m'EΡ8R9 00G7 h9ArlGW6jHtJGz'DaHlT bB0a0ڬ-m d۸Ar!&dmz- GDCڭ5GMPDm Ht  Da,a $ADDġ `'`KHZl?Jh.pHa 85VN!nd8. dʼnXVüĮWe>aYޮWp=>!9ΌD "VF~&#&nܠdžj&+*o3,rb*P JHlL@ k)(lc2* 2: ]F%"|!$J"dbN `oVBL@!8! \ *\)N$b3$ĉ.xɪ\h@ ) 2)$%m *d**B`/2 *p"%*$@#Ҍ-,A8ʡT6m9! ^ ;R09L-|@3CգW>XrTB>AHA8fVa# 3@ +" NJ Cڍ5P|jڐCC0IJp%1AWHA? `@^A/&Ar ""`Y\V%Q+Z*p3&E/@ @fl3v@\2 O #)nTB"J!c(X.BV@ Z F‚i\2Q, ͚ ,t`L7\B%H. d/Ze /|ȶ""<ǾnXhacl5ހjX8 LaL!8 ?>ˋ\rPtG.O 7v08"0Cܐ3z:QVCZEsG|aާp!$aH+!?!8@6@aHٔ;4Q&a$A^2yr:dIʾYjNAHXVLTM$z S&$A Tjp( Ui &Wl 0YNˑ6aʱ:_@ TWn, p:Y61o/4AB~0?Dw?ÃVASUr8B8_dA'k 9eE`DePS됥HA-9[YktaA ِ aAKD`&!UEZ.PIٶ}֍bbf lje2o+rOz `k(0O Lbd`/֔AL"0@z'$A4RT/% #̝4H==hѵA?zja6bp{ Dи[;5D-Ĺ; 諸QU{;gI.E2d}ĥaz-縤r)  !`HtMDE~жy@pķ$vN |yӄ '5zHT7Y:A! Uܠ\AQ= ?\Dl Ƽt}wϓe2<\Pl]>*¼,CnLlԀg"Z),b~F&0F4*d)m"/V%@ H#l~``gH%,)1l#h$XIn8? } حVCF ,C3 "CRŌ%kq6Tq&R$;p.`5kh Jn:L&-fICGNN9qzƑ#'MDs)R>9}TOBq U?Vy +O@I=6ڵlۺEKӦH$Ȯ޻–.0 &4i;~ 9ɔWVW4oEƸhȿJM/]`Z~ [ٴk۾}ndfS4Zk#>jăM+-W0Z뗼>GC.1&L$-]8P]?T(MomJ.k+0Fb:Ktڔӎ67lUaQC5PD-18ԣ 'r4FoF9HSo+8reDB&LE'&r&suIS"$"0Bna .D4CU,KP]+XDfBIKUBfdkDnЄ0Hju! }a%@''dQAt,q" 8@]vjCs "]rIrh rؠkDaסpGqW 24m>tQF);wDbrz%R Y %&-{iGDB HJ&F*rl$&-ҹl(kBURL-c$Ҟ|xJYSEucRO\u5^~a`}]zMhfXj41gaٓEiI\~+L.nBf#O8#.p#5F9”x9AXf]vu-b |@7xU[G Lrab WN9lSXC "} Cq9bL.@7HZܢccN9$)7‰#MnQDiD!D` 5$TEN  d Lm\!UClDfBT!,Tj=p,AT FL5D]BtOU  B.Ni @H#pT(R  t9djQlp…X:a (b]Z-RaPA!lp;^ytNX}Da0t- }Zĭv= cHBV`PTҢLe3-e҆>%.-%g>*~@4ح=򡊎5%}ԬfԪ Z:Nt1e9%öt֭1o:& \/mB+gX:Ӽ~x(!#*L,kpjm|0z Z#$A cNր}ք-lV`iː!HsD}4C-~ XdO WGZ'NوVM`!YLCsD ,CA ZЂ0@I@[*LpBںI 8Do?(\rT$ j3B5 $P?7}$W&D:oQl-ͫ^w8?riOqS&*W Y Oxjڄ.(hиQHFXr֥\ (0b A! -ṪicaΤ2ͮxNZ6pS= 8F ;F/wfmB~㪡EB'fH 6/M T#rŀafڤͲa3̻T[ڰ TA( hqb=(F .'9^<0p&K$^ǒBOCn \{0D3Ow,qGE'#n C*)04G_T2tK/=g2x2lh vW@`#MU 0w 0 3y|O3gR["!9fxpO]xqQx'yWOp q K6y H{op aP'} y -3q :P4 -J /Q z a}!~ `9mF~x /~>0=` x5jWR#kbb ?%Jq xqa ?p 0W$MP>Y&mZ"p@3Zo2XEUkD[?`$2Ap)jQ0Q[.{2Xmo+E1 @va`vX%BI&m0X]DrpPZRT4+IH8'd'uI^"q l`sS0<a/G'/ a(}& q`#Co]\aItl.0 vKxK$K0B> W eR^;*F6 ҈t zMtq5|c x㔎A66! ǡq*:yzA׀ w P c|P c4;5 0S !b !4 Б :Б :Q `Q~C`p""4daog}bi JWLV`JA N5h c C Bas!A!T1Fw&Ip+-w,|i-HG"jFdCAt'g"p*u,u GDEYdOV/Yb(ursW0`C0M0k+}B_"&s22%al^)qp)_Cm'"t%*Ytrtb& UbY(u8382$k^oZ4q]1;P;+ ʠ9tM4Tzb'jG{9HQ6TF6 TYKzq7AsS;Pb4rF0#<ӣ; Qp &A 0bL4p / H ` @ Rs4 SVkE wgk|>KMLNAkb84V i4*"FHC >fZ(&p5ZNgXoD@J`1p-B)Y"1[/i/DNǞuA"R*p0.C7CrR2Y!JU(/_% @"G=qsPs 2EDABA^(.6nwGѾÒT_dsKKT3>2%,cԲ(P4s+V8gsѳ9B6D;XH:!!8zRdM8ʏ8 !P )8a8' : 4 `e [& Pڐ;`-(x| w{0OPGPQ`TC ò}bm!k6Vr 耘$MbJ F  FÌPZr.~`&(@ovG oIX.t(8i#&0p.aB@)j-ub*R,X ZR1H/8UZt'')90pWBFCzJ`m[I91O`^!#Wr8iH d*(&w"^%&I}0_IveI)u$E*A+r(2,/M<`l-a*AiBH?p ŃRQ#GƏ$%xZ @p<a ud dvxw,y\#Q;OBV6g}aq! G°7\f@ 8@|P Aӑ-šܮ`%irY fB`sTPN`r30p ;p-U8Tmy#Ek *kbT1l `i1&,Y-2>4YD1X~Yp(l#Q~t="CBPZOE~j(ma& !.*D=&ؖlI'E.Yn`6fbKm 8@(owLŞGj"xf2WTq@*%ϊE1B& =, ALޗ` 90X$&%K)N)lQ,2c2Z`)sC*v;cQj~g1ِj }٘dSt1P:!cڠPv [jO;E^@uS7=l{7% \@R- ܔ0]bka` Hv UiTW=U0gQH#CܬBpV?k4  ^8Qg$Ğ;+kC{]D3~+ڊDn1.2)M`1r(GYƾ9T%'X3)kb&TU H0pػܬ( eEۉCXtt &-! 267WZa+f1 Xp,Fab_YLB.&Y sx(O/o@K3H& BCu `bd ceoc8@ ބهMzx<RځNh5 Q@^!ңjӂ-\ 0%N8E*nQ%B Y_I#6j1q)`ӤjU-O4y[I3Ū~I͛8nҤS ;gHa2Gp6Ɍ'W(ֻi`Rrؓ'GىrM>YlxO0y lʔUZʑ:nY38Ś6K̘R@r(f,Ԧ*k /:ċY"G,F %k_R8\>wXÎ@pÌHX"HpHt[C8;s4I ;` d <b1"鈳#pXa63#%qG7܈H5 Q4Ҍ5|lB8; , 8 H3[s Ϭ H pC[! \M?x7 5 4: 6<Ѭ܀*FPB|Ps-NBDzW uVZkV\ c09A$mIbXdU6p GmvZj&jv[nbo'ZtQ[ivleHښhrh!A'%V Qiޝ֡x (# FiY.f%j1xN f%P@qAGW

    sH96ft%&M88 o8.1l9RF,0CL<ʥ 887T7lԳp3IܰC*O% 94Í(]hbAln;8$]:6+309CBoi:nft8@&6'9.N5ѡN!0@l*Қ@' iJT#(A5[@5KB%B XVZxD$Jm-Qd kXb,b][ ,(G5rRl [Yd18ZKhrG~9KMG@R"6.># ad# I$@}#)AE-P! T""G> :0`IHB `BN$ ixez&L$~-|AHܢNv p 4pD'zã6xHlқ3'8BB@0q9jq\8)@Q@xs D8̳mL:nXA M(rD 1: 1!h[9Xn d>` :}Ύ?R4:q3zӅp& 'sy?9  ql,BNjM.lgY2% r.1`]*`FYK4m{["Qm-bIQXU$.u16JV<9Dna$aǂ+{^c;A*V\Q$y!`%搋}cP2,l=Ұ:(сQBC+5%B-49P-tM\sP'4sM&9 (HFt/P';,b3L{Sh' 8!j N.dG8Σ0@B D!΁7QaJB7&Kf@ `Dyq'4B0 UeKYЄ\ $)*hL DRm*T!v<bQ$Ps2!'r'(PR:+) ujΣP`SS 1`Jmk\orj979!5~/B<[c4q,c] xMNI#-x݂3 {Kc 7|.p_`+&!Eif,5ܒ Lp/Ђ#Hqԃ$SժB3 OܶlH@}M$qg<H œh/r!A n pVyi80xP(I:IC!=SV7lVGmu(Y` )oF]ADIpqP#4!dGFR\Nsj?@ PPp'qy;pktCRRF玙SN'P☒BQp?IIa7u 7vc 5СK8=1B1hFh8L۲ _C)R8*"Ӹ'BkP.z8p! Fb$x!\RFJi_H`i@80A%T_}e4LT x(sAؑ>6 3'x8H3!!qEJNhNSHh"Ġ:[': J̦1h ѻs"2KH=p*= -.<)òi8ؑ IiS1bE 64''Xѽڄ*3Xstpڠe_'X(E:XAH:((!>7ۊ-;I!))@+HH?!X?:)YJ Ιi`( +Z6ZE ɳ ,v)bIv{J,!ҊJ;!RAJ[ Gpmh2Ae.Ң|88)ABb‚ B!dK8i 'Z$>H@0µ|ap4F\F Pbg 19`=+# :;${o[pP@Z$D[7P2hdzqYЍ~s`p̀2x;)*Nj`K(-G!ЁA 7/<;CF; x KЂ?Y~B )31/Q6^k+!1*W{Ep,RIV:REYN5-S J8Sh W0D8AJ Kˏ)tKpK $DmԒ3-BQJ!ANUH9ipPǨL}h<aZuF<8MC"8DtZPkj L 3͈2 N0'x53q0)a\:)} Z,' /q@,O!؊,QFk5+(m( ҳK3XF#5p6EE|X6>I084(X9!&2V̑ˑyQZ18q#i8,יH 9\", 6ٽ Y+aɓ}RȎ R, @h P9(Sy0(!Ax SƅWq`08pXűMN8YRD͠;~[ݦCЎః+0jȂK79)Yɿe#R( '@E(fWA( ;+Y@Cְ ,R KZ75k9 _ɒ>6 6Y^X(FcԬ+ JJM3-a43*yƭd-9ɭ"cl\+݈X%$]W~eҝ$ FCҁ׍\PQ\P0CAL醖QNeP~OXiSS\+%|0 wuQ-=30βь9 ͠Ĺ OȌ _O/e:q9=8{=p+i4X0: ܁5P@c+K!l_s?1X}> 6 M ƶpG 2jՀ564QA*ȳ+53 0c +xW˲ڎW Qq IWN3.[t>ѡTJI-486Ld8LV Nd=6"-TFLbVe~%SF+t@\Eʅ Pe!3䆿be" r"U~[؊ kDc gS Q9.8gwH&UPwjJYDpJ i 9xD"hvYR堫 Ǜl+I@1:+:7=33hGHi>Hh Η)㍓yM`;&s4wmS@Ft-#!ѱ",Z4HPK8P5i5ŁwՙfH(X6Wk5d2ݏ⹩pRIϪ@ԬPJIKHX fBa(AlglOkv`p4m.`$ty@]خu[?/ٞ@el@)ԁBie}V&[T Q^Txn}G :MkKN)8q>ipV;|v1P21vDNB_PG@ à;3y<.prSPj gK0юaP=]:e3l62 1 HŠۧ`:kհ|ȂaЂq. !a>KpБm:,b?)01*06@  6gDIP`E|sCI4Fo5:h935q#97L_Mt՟Wj`2u8luQU_ؗk߾@ru$nj")oXHWP`vj^ J㼄U09X6݃ㄕЋp@D"HxTp0ww0bMhh;v"}ڴMexzIt"#OpI!>\$(!)M 1"?B A4&4Eʈ*td[rw$KoTGR6',tCJJQ>k:-QNmఄLCb@N-̔NckMA$tpAmxn Ddvqd+0 R\J<hVij!ZNnKmUElcogAw [3R)1k"yҡIbK;` wx t qCZ#I1*hטN5>/( c4OYBf)%2~%5M5s;x%/(7v 7h'\Oy'8y*C3P%QI B`ILg4>;HtC$ంE/n vAb/ J\6&yZ\Ȝ`9䡃7Ҙ51lP6K01D>,hU`d%!60%KBخ֒=M`۸Q1/C|oyږ?'pjL:bjY~-Ѐ(.Ҝ&rբ`IthvJ lb).J[;i*AH 1eHCV NԢwQ`"Ћ>k{zu"SH{ǤSb¥jj6&DLf-7ᨢ&*kɑi:ݫ&n4@/Tչ>*46C\܅(Љe,F'B&dTϦآB'+Zȁ4|J(P0 ΄`|"jAxAj<_ȲͅRh<`4[=ux\,eD  D%P9Z\fS@Y8K,^qs]P8EILSE(Ee^,~ 4S^G* o\!@` Fܶ+l<S'K. w D ^G  B@#<ȣ f.栈&$蜮t挰^Ω84 :f3*|7C8H2/s*C<\B40%- 8?uo',s:'8OEwEY^M8k4hLxQJH h'b, B-(1wP-5֨t`RapIg܉#tǴA  M +QQMȐ \j`ڎ6'H@mM{\~q u`(^P%dt,]Ss$Ĥ10y؞qMվTB@v7ze?>[2fs_CYC5I&7 \fjz;4B4H:/zr8 -W"')$ s G(h&< L;!LO @9FE) לMB}zO"{{,}b` ;JAaG`i)DaBZyOD$R}riѦ[icL*mI¦ :*F#GРU q⚇kXtbL30!\㢊7fp,bE3@Y#JJQ±ą@m.Yפ蘡#)JW:M̙3h!B\*TRԤqEvƢY7m,C֎%tHt GNgNj&3khsdJ 6lTQcD9j nmZqs6h IpGoSxɗ7}z7y_'ѓreVb-p DTprԦi$ )PBa4ܐ=0`)KThT ]|emp(D_&_Gu&P@P/H%<WH o'?SdHʫ%&r -H+.D/%4E# -" J$T`-aH h;"d[:$8p[$u5:(+";hO׀㡓bjc2r5H d#3))b-5[ pa@Z2ۨ24b6#3T *2+m &.MuV5Pc: nT͈i $(G+Ȗ`i$Z#̘u73Y+$#"2Q6vFPc0x9ڹ骻dG;\n{>#IW춻pp/GC1AuL<f F\pI5ߜ) Q`.GiT|}PVf\>WnQ NDl|B; %ocmqOO"9ec#Iq{@UCsE7QP( ]OsWFڄZtG4a/{aP* :ԡcl#j;Wn &hC "\gh2d oNED%̹ ^燐J"(R'KPRp@ǺAf8xNHc/UDf WZƨZĮ q(_0l8%إ:K"2 MY;lb#ZjVBF5 RLX %9jPiUDYh^Y ך+p;ѕQ6^-|A ͼ B.H5/6j)}Æ4fx69_ސ6hc#I8ncI%Mf:ŌS 5E(vlR:n`T w|4zOW Yκ`X";p Bd>C#Piapf7!GdRF蟅`1RU>!2E0AH X98r8~fte\^ ]5c P։<lAnApA CFBd PJ.aCIi6_0s:.T (D{£Ψ(jȘ*PSؠV`@ CVa/7b8hP,/@a !P=v WgC*ΧX5C  Al(O&&pCP5-a%R~)0["+6hJ "x: ,r\N Ro\[~ ֶi.,% d2ffڀ3f(2He*HiF3`ERP{QRʎ`bURf9 o7㒾Ʀ0H04*!8Rr $@K,pB F4C:PuAD@>1$D"(_C~~5ha!6mHpIdjKnV! f| M@bA.#l -=ԅ#e:C'hjE_a @ZD a 8jE'.PVhB&x&/VNz,Q1&: 4bZÊcRP(bZ^cxg6 ERì/,%؅+F&7FR KZ#hp؂7d `ı.AB#®f0]`J-b'zТ+ƬY"!AT@8A .E !j!1I1(ғFd2$-,dFD.2 @-} b aBN|!/=x% b³2⯊"#"#^# ca 8*k ȇ-hV aL ).Œ[&.hVp U`V,s a'Rt&0M-\f,%7 zb슃sGYFXc^ ,[5O2a-! 2P3>@ ª "<NVU.ER:|pBY<2NҒ2n9r=g#T` XEY / ̈́Itmj枾$x2DWzԔ$ApAmvAN!P8PJ ;gq:gDK!'s4J[LWI@ RCIX˕D> Q,cau!Ikw<@w:VLNj.Ĝ@>Vɢ8H7lK^eH & x @L@>VDMZjZa+H2,*SiŀV5G7&QD\Q'%0 #*O#ͳ 6|ˆ8") t(A2³("E-Zv]Hͮ橪 jԀ#(cZ 2 H^% *@8aX8`/8d֮Ҍt, -OZ6 efha"c>Í Í7jcumO ;B!LlOi VvmET?~?7ACa6o?ofppAJW9D${CnAF#v7{lQe fa&V'h9 c;^!A.WP@hl 4- {>'!~dbac*ZeehKh$1H%@xm_`4v" ز*o'ƅ*ƅM ,̢3ʘ8 fbU:iXĀlV`$:Ւ&8")8o , @%Ѐ:Ztx2>C֚"iI;m6P<Dd$q"'b!R$nA)%A.[򖕃DnKpʡ bK2vR]Մ  4|-AN RU#P®3,pOМ3\1C}/Z?`{V~VD P3YE ccB9/|&bW,6 %WE5(-+V_82e:C0*iJ怓 G @BP삑g8V&? e"4t PsU6Z{q< +jZb͈ < b@!( "q#+賚/l, /]IFםXa zcIڗ?taaZ$AA!j ,X0aLa‡#"F"5j3JLhB=Nm(S\ɲ˗0~TN*i  ÅZ\ ʕ'W8#5R n K_KI.*NҪŪ6OH}*&.Q_vAFNY]SOPCv1dI6nTbkY-GMB"QEΜ9pcN5UBYf8m4޹#IwtQ8Ղj T11?Tf %4ݸpmСsP + 8,anfauFZf@UD8D"&~HpnVgvهyƋÙ!j "8bpuW$I5FKT(!e(Fjqf UGsUС#7~6ad++ȁit5p褠I~p!nıi Flee*[ib(m*뮡xb'd2a&쮞VI/`N9崃:ވsO2yX! QD1A$ʼ$TVR)ׅ>p7Y5[%(@v&\Š$}1:@QrԞX$"Hw/ h2niܦčK^ST(25_J|$͡ƚ_Ǥ#1~Ë z0a .ZgұD$K?xgMZ/aiWhUqt?`}uY@7x?>W)YL5/(,( Dӆ b Zf"3{hfCuڣ*uSU!L7H:jل XVg+Rt" {)!R(:Ĥ I9 u# P8I0/2]x/t!Q4°PG8> 4L _T'-q eLZ@эxB) 6'D8pA "3Ɓ ̀";4 Ntn8"d!􄃪  5xsN~P)#SS)bh%4AZ@A#AKK q6Eop a9g6oHCI}0{klEOJT*XaO.DbZYvWU'0xⴰ-Vx RF(l Ip jDI0u#ATxԆ!蠆Uop,D&CrAoFo,` SP 7bpm p4VEQ5`qǕ3 ` 034Gz@ 0ץ'W]wЇ~x/!1!rtd]ߥr9׈;Հ @'t2At 3rI`J3S u1oSO7-]ހ VqAs,fLtp jg IN. Usd5QRȁyr@AfAqjsqMyLW!#f=>5`$}7e} QamqA:B6:Y!4|Ք("gЦ7et`;!mzRk{##v ;"AV ;B b(l0 X!U0oSpP8(#80!&dVi SI&Y0n# 6PWbv B"})ű!(( ަm-Bܖ:0(38*5*$W`2i Ia @x,FQ La+S _G+VX+X( {I]5.КA0p`-n؆p ۀ%- "1 & r \G؝މp @, ` D H`JgeP hIv@utHސ qb,@ P㰆I`v-z s7yM` p *I 56X2"f'COYB00')w5Q83!7Abv!'v@΢keOkJe=?z2d?u7 d š!8!t} `r@$ܺ,+0@+z;+҄qE :D\" PE z {NT @ 腜(ч1 ڰ{ xf l|r$ 谲-771+D3EC-t [m1.o1a*JV+3J3uߒ VENO'0u&Sßۇ()=udtpy[{ io]#C״ͦ'wnȱ!N2>G00@ [i6'?S"4iNL|R2R+pxd"q! mp{=~Ƣt"$dr & 1%FMۤqh\%'SW?;c!2Y OXt B \`jY̬@ ،# [YCM $p-,[CS`8`` SmX Dl`j P cL鰔0 ,ч]ےPEٞmpr ssL);swǮs3 b"V -$6KjʳpwFa,F @2+Svp@GE3p10R a+8}t}"RE'wZ!u Y#4+O8d!c[ # E"1۱r h)e(&Q.XYq'̒b#6!+@A+ENc! ba~#dADZI86q\y:p0WF8pB۹*m 7"Í%H.87~8$@8d <Ac l\"%M3✛:s#19P1`%Å8`C5$רB9A 8=6:`N 98\X ;@QA0q6p 98l49`4?/RI#}4`KLF$`NR*^EիB1Ŕ="S:!eL*;M0!N\ēNL SzRUX[o_[RkQ ūK<٤L`hb~汇:l&rΙc" =pQ{R"dd^iV%_AHx:F_~Ih!Bgt7rI9pJ &F:itT$\%8)&lr)`D}b˭` 6YBg}.KVUePҽogyvBi!$s69h‘&\F[yl -nc 5X -VQe (iU-Gqrpˌ8EE#AȄN@ VIgd Df~ Ol4aSp9ޣMT7KV33+ "a&.i8<>A0,( '$7ayDF|Bߤ,>'PЈNŁ r*~azR9XъB!L![&+uwfх6uܹ6 h&dPŷ4Xi[$(P.PtBxxŅwЗ̺P91TV`E1 dT/AX!EvѰbdȗq#8 (LDrRܠ7 = q@C,j*\"x$eMwR='a f>ϡ - =iVÛw㝸LIFwErQ#/~z _XlQ}% B 9f8A1;b&i3 g@𦄇, z8fPGT@t0 5da ?A0]e Jؒ0lxаW+gRX4'5|1 r Vk 9"h܊`ճH\GR2r Em5i݂:HMA_w)i1[u *xp!_P=Z$; &@.:VkH Ph'%4Ёu\)AN.wJj 2ۘgFs=e$%?7P #_H"lZb8~8(2,=ua!Z=!-`-i !2 i<WhOKb6Tݸ.-j4]SYrC1QϛE)}P=#/%$HO?s)v|5ߥ(ތ·fmvQ#wrAvi/8߹Z3̓QUbP$ˤ*`~kVE@s<H6 BPC# ԡ͵ p]c(. U/=)!}I.ASA/Fksǿu>LT`E&tePx0BsRI[tkVuw[p-jxBރ!0ޗ47 2U4qqXVH2>Oj|:)NF 0tC_x-{YeL-|j~?6( HONѡxd 8?=D#V+<*Q\8&'D!x'xVRQX q*Rج 94he eXaQ[3*5y7hH6+;jض)Ar7Kq I,,e;D)sG9 X!vۏA 6@xH #5*FɌ ϰXC(ŒР&q53A11P15x9p3C+73Bk:8CHPHX6Mp#J*xJPF<@F, ij3*+AI_$kd5@8y +7 T >`A2:{3yM7MӑAˏ+JM3ُϴ P ؄CP ݀XaX7"-E8.l"jC7 Y8D A)a!W! I93>)KP-K28ʊY6BIW|8-61 ;&T)aᖰFB؃:(Jx=؃LQP;+sQ ᖏƾbPXQ i@ҝa(xhu%FM {ٲi.<:II2eyBl'}`xTit+(xTT9[G*z[ԈUhPq0T'c[%@b(b\Z8Sha;58] *D@%hAheP `B.ĸz7 Wᵂ n{»2BB,:<XbELT(u4;Fi.]zq @ĐX  h# Q$.Y|-`9S@@8Cx/hODN.-`sŁrcUܫd]378#5[,6PWP=fZ+V#Gf Ř0idzUv \C!qr({~ g؆^pi {ȃod`dxR'lhԕa'RPjނ6y: ܁_@%}(1Nꉸbh]Qq%I`L##h#aHG9`\8Rp܄D8pTCԂ@G FhU1ۄ-;P)8:ؒ5Hກ3!`&,ڬ|[&.<lxIJHCF8a$(. aP#ֲ764I"lCQيCC3,A!P E銹O-HGn|ͥZB7 X2[Z*Q&D9IBZb+0=h;;\yV{xXZ`^safN [ "frl'G {@qލf@Ih>ayNx<IP|.>ImXGQG!/ h BXh#^lM= Њ$oQ([ťqHt$`$p6us+he&mh_%Mc:.֫&UC?d[63.ElӲ=` 85!*  -E:eE)+T6Z ϊUkBK3l"R-R2J@\3p! q%`!-rš8L-`БA袋AOʩO|d5xp^Py!CX `jZ( zmʔnA;ga(=CGؕWٛ;[KokqQH bs`@ k@{ RCtHȗH#/q7I Hu<}aVȃaqT޻1 g{%i%?W@_鉐h(Vբom l̏Ji(6g)J&V o(󗹉mq.֐D݄cCA rH\P>tv!_b} ̪-qOAYZOx׵0Q/j`u舌N6X"6I΃x֬v\C1v׊d; , B=L pHD`簃O:m,qQŅ3n,qΕ8X8NhIFM:c~"$N Gkflc󦛜nngN8pм#( Xp)\~ 6M[5ZՂeVm`ly*ʑֲ QrbiӰGVkeӧNn֍;l(N:q25qS-MUk3Тn[pҡCG59tč%ɑ桛L‡?{ `іfJ<.s G5̸a pYŖ^8iOk=V~? 8 p`*G0}' <`F')JZmJiyYe&4)3$NrD 1P4L4EVC ) kE .8!UTEkD p"DI#ب2'֝jFrfT @mFn!ZyYuߣ5FtԆ4mqp!ԩAONnPں*pDh)a ~ ш dƬf`a!KC`Vц`ұDp@`[*Wbg+q 0dg+fRH!ua bq%4j6%TQWh1HR" 3`3i{\iS6 N." ]suK-_"[#ʅX(UT8yS=pRZ ,ioR0ը֚k]2IԐ=3/cO27X!8K6mIxG 2y07:5^}N 뭻:B, .Ea-4p '_٤u\8¢2(2DnN;C G0V=JqKdYoI !!'CAbmV m~u_´D !T4pPUI>X{Bx$Mq2ӧQ6T%R'}2ԡvTRUaNE$8hLfp5!ZӺ+6qRD|d ~ډ ׀/ R,'؉ p%( r `|dĠ!bPr5W} V҉P@! X\Hް/$iHe. WA$fpr-8IiwL I$їdܣLG I4͜\A m5lđ )zK84̡4+$#7~D0Nx09bs(G;!)4>E*RPjŮ.})Ld v9rGG(F5m?s>3-a:Ah0'toCh aJq}Kgf>9N]ttPqE\0KBuXiJ Mc9xPuf?P") ZA;h,^d&"t(O Q'BԪ AOR!D&wP+d K8054Xp}av@Ր+}!._( 5.B !dWk 6hB>"I!4\d#,1Pr'- {@T i  (#5~_H/Q\"h'<e6u49Zq@aK mfDr) +B7ND|;ijh#'9qyz(*P* 7hs(.F/njD<҄AA~ <ݢ b#(v1D;Lֽ8Ɲ4F$?V9t# <B-N4MC6@5Lr,AA/܂`!&Ԑ,vqɯ؂B`1ۭ’B-[EZ@ICX{ 5T VT | m P`P VkJV k}I1@$ X eA <ɦBF0 H\Ė̄#EOġ L$Ѓ tHX呣:hZ&1 B>#Ѐ+B.1[5dC,3Dâ/Ġ/ &&ܚ88" &'X+$0hr7PCjrrxWͨ`iqJ>o \[ A nK@ :VQ\('袧hrġdЯ0$iBiF(\x!v%9\W$Cɼ yD KBѹTA LP-DD1ץ p޸,D"h @ N$RȠ\AhXP!=xp@p@=ԨChA,tx87(7FBZZx*B1=8<(t'&E(d+–(Ywn7I :9(%A!@*pB'(`%b' 6P$:8 HKm<1܂/HLHVNZOGUD_|SQΤjW:jV$:HH_H*+I%HpeH-tMxYS]Xa)*0$!A?CHaB(6RԣU}.D̩IE5*|t90AUI.Tz44$opCZxəao Ix m l | ݐ@8@j]t'ͽJA]#K$X,A  =Oxѩhml#Ҫ \P(9`LK .Rn,%:A2 B=)p@7BM٣FA2N.@  0ADdPR):$hko\$1DA+̌^8 $@ 1r/TTh)l:Z GǩrHl5Ll kQND0=k00C'@B!Ht*„^S+ q@X ս EɿN%B,,:DC0ZfG }E;@/^%I8h7z#LVpe ^Em欭 Lvq^gxJ࿂Z{sIhf \pێm ĭΑKai AT! ' ̶}gKʫ`\..3~J3"4r+=3x6# l :,@:uvi*$:x!$1Bbh*t+LA&&p'd'"^+! =)G;dgB暴IFiYkEAn4U5 |B |C/ ^3PzQpL96<5Q{HN5U\~4+BCp8<a+dVNDn'8W9*f('C{@@,EC>$2Ęj&t'˸D9ޙǍ~$1u(D5t 5n} z0QS:j5YJ r?UF?&Wa  4Z 'ѐF&XHC-ǟGӇi@8 [})@WHmKVlYY! `E&mZK-MVm`h FmjԴq J[\.\~:zɖ+AhI*mҡbŚ@K̘i#muƎ3p1M@vw@tЉ vM\7pങ۷MHYfACp\,s @iB%!i1CJ3U.Ypk~7oUBrN 3'R{ nZM6ȑmcƍ+X0ׯ?N6pPÒц.PgI ه"F0DW0iBIq4O ,l<#| hd7RA Ac Qcӭ h+XÌʌ%ޫOXŽ*Vp!:p=zcts[m{>6x40`f IT0 ~hP8tEj脜>QQ8)P!(6=< '³bEr8"*D2o\f/i/~ W`Er BqM&DM WI$S:X +V~:pa O/]"7:G-phbX&lezԻ\?{ c /7Y7=q\C=]O>S[|O0WꍿUވaxul7 GMLQ8щnf` =qq")A)!'L0x0 Ejq( SzF"l d&4yI,dR1Rq< բ%EI@ ( `hI؈GV/FqmT88-N1%* KRU$Mn]*SұXi( r4]p.`'Y 4rACh pN#p&!S"g C$MF!f$D IC%L誓$[IC9`fs ,`t`Z"vڀIM.U8(r7uqèx\Ӗ l 8ĥ%F[ڤ-Mڠ6 W`0@b'xӆ M]` %ھY\:7pcLsu/M+Q.zC\!lXC.pF:h\'8n#pN&EP Q,B=AuѸcw0z!tJ;ɡ:Gq.g$c-pN Np$b>#``޸g@8! a4p<~;2V/&oc-4-0ր-">bn zC>ڀ maValH,f \$D3L3R !LAaA(JdH́́ `<1f,`Ǝ a\dzEX.年xYH@ AN%.%f4,fWnQVn0H^Ȏbi"RHthM8hBLe!n\A3NoEZ$M@! !H JZ AvOO~Uϛ b®dct&o!"!(h2&C^Aa"n%ǫo" ͈I<Ϫ/fu Mx r2 m؊10(jxc1Vs.@z*>^[ C6,P%~!U&*tp.h^Df2!@ @R @`4N^K@JRd d 8⇆pzH3pbpȮ Y Za 格(Cce(bb"LkC;D4lZHTFDQT\Vtm^t!&A `⑊(ĀT(.A4F"m6 MDR KT~#14M5tmnbz5\gݪ^^uI5`gf)b&&&\W!6k4<`heA"BAAH KZ=E a̡ZJ@]!A|}?VVKFqA aZR lA)74t)>CǶ-9FD3qQE7g%F&~!z"l@I AwQ/EqI2A nāds4VO9%BW%uA4,N!aR`CLr $fb 57kk {7AvB"-f'2NG/:ۆU"cr"#77 - cv`mvc[JXEoa3wy-U%CZ@ d7ͭ*اn&XV1 zu[]x dgdxN!qfoW)^JJ(9d$ vArUX4N=CKN"I2 nk BgH9bEE) %@E jaa+fptVAh[l%hC9oW4g2<&$%X(VXq3b\jaȄLp]xEغE BO9p &w[`LQO 4 uMk!.An)NbaFVb&lzk*:5< {]`\L'h'Jz*vO::z.#C20c& F:ܢ.1*mT8{Q*/2A>@,j@ Ԝ0zx5:t(#âZES/oo>xa j ˁFU"aP`Ϻ&l(Ho fr@_fI|@r vk a8bKqkn\\".$3(&T8Lb(!qWZ\cV.pA˷6%JNZiE{mQh#%Xb"L;eR*"D< 4$8= Pz/"ϙ[t4lAgC3!azIrdvXBwk@"~xU 2p,"-p  Ҭ "';@ /X~1,c5DuYtT@Yg>#Y@ A`x -Z 33# ?4C>u!h[ `:{&4\Ҥ5j (l`A;vDlڴĈ+tئD1̙4kڼ3gN(]mɓP=ХL~"'PPp},NtNFM.W94TKr7e8tޣ<Ɋ$3Gkrڪt˜5,bƋFz6*P?#=%H_m,W VMگk&aI]_t @q N*pZb"СcyVpQ %6XB#\̒6q,I_mk. `vٹa~Lgv`_U,!t,bF^&/.B/θ!9F!k,ftq%cpI#rHWfHGaw ^`ҭwX uwtY$ce_J(^i .hqI.D4HfjvYA!j+Eu)h ( 8Q$CND=|#5 L.<Z I,[QpAAL12-HQC=*vb.bKE ch:uWR3=$OLp0&' ? ãPq/\4/\b4xu-PM7qͅ%2_mB-tC>,;8HJэ$MgӀ jg]S/a )ziot`n5,;7r U +`F$ml Uq< Cz #"auv|R~kp) `~KؗnT a['xvHvui.8u:>w"# vfɧi qdllVzj)5oI@GN w5dߡVBIBB' Q3AKBӢ)O9-TXPTNxbE(= - c (G5kH`Bu85p yh0^ C8ByKP*B lt@F`j9": rHJ0x-błO`"cbF0 \!:#-N0U@"J'5Cx+@Z:acj EBixZHlD[iB7PG~c {CnuC΀o fX GM iup6@DB=X*HNqtH69D#Іgt8D$NBݐPS:᧎PÅ O OX uDKZ7юpmW0$8HS|AT]=y 0DCPW_(-X cB_q ""LQeb(( jxL+Lո8>!(啟lQp(t$rl0c:-8qfRkA@ih8rohBI:QF)p5ʑVgl8Qk^y8`K "I/F!E(4p\wSژe. ӥ #:fA;,g8iFt젗vv B g~ Gu'BqXUj# !j<8x! + w#m+^V w"e1a($"2i QP?SxK @BU]h#dR8Qhyd{dR@?&$(ah1%s ?Pcf$l \h(:&q"P/T|^{@ b!&Ρ@(?{\}ȏWO 4 4P7pņl2 04`,R3~[2.ހ ` 1)pG1Y P0 YC PLr}Vʥ(0<8HU 0B`] m" 5c*W epP ,@4v r,I)~DZ /b *0RUp.V 0 0}%˱B`( s|" K :w Z 7v;s'xš*bw? v`5ax@#Q"ѹUmp2fc!c#!C"!"i1r 0m%).`ր+1l<&Q׽2 {E]D}l؍ / 2~ 1pp 3:}5ptm ely`*U\_812GIhZf Q3p܎< |v#9)v+ QP5#4 pM% ɳmš P#߁v&'1 KpQ"t+0PP#Va@,R8A U(@aS]u0? iA=D2{Y'/ (eT:Vfvw UӲ1R;f*Nz7LFzhj$ 48tjIl()Pp:9 `BT;/rpQt- VS\L` P ~t.n /2 ]씎Ƞ06I HLٰBQ E'  +L=坁KH22;GҠkf(`Zr1 %>PkW*PP"ӫ*Τ0yt`;ۚ:d0`37gp@ 4W<#+B 30PjDT~ ApA Sp=Exg}x HdAr g,9lbmIкO^\M$tpB !dE 7YD/s C A8Sđ>`C ;p0c:J)Z$EZa5qEp0ɃMX*ֈdK(7r#50c,8TB8%Xh)`hVh rhOYJ+*b(#3Di6*b-Nu XLꯣHcATc5`1*H`)|3Bg֎IʫL"*0,b<1o&!!6lIԬj1R\@D_I(ZieCrTǝߚ[9DG(ƺ{lj*Eeb=v@ ?7C&{oap,+PE WQKeo\NAJ/$*][lpa'kZ$-k帡spRj&p༴b DXF -x 6p::8dd ;Z8rSYD,0DZHd~i" X2CWIU,:TamxX:9D f`BlE;0h1C$b&$'\_Kp@$T&Rpb%VC␆A@Alxᠾ>e+X6H)#NՕlxRT&Oǖ11N i$ؙ4D3F9񴚝ҰElt#H"a:(ӢV$M6iLQ55Y=ˆ0pq7dds Xm]vA qnxe17A3+LpXƐK{4-tQvIB=NGʩ5u{]8b'% &)i+uBL THS*,`2 x" p9S&_y@*]Jc@xX pEQTb0848 & [2AƄxp )`*4 w 쐩*% FY-u, ^26>)pOV14BqJ_Up${ ^ Z@ |Jm3CR"ē,l9Hg őc{`G1$Qj-4\wޘ-l MP#p4Jss !#MK%9aJTn-37sW7(1V/Kl!&}_آ\q!gz $T TxIzSfC DHAaiUfRy`81X *|LV]Y/n+8@j. IVǕZ"ym.LI0zI#d4rA b4&zoNrn4)ԁp#^"nq-?Sf@za IWЎ7 WPA!B Whx}pLAAF9x$,7hG±#І6<̮[D-C8*%DB(CTP!*l&aI&6Z*DkpFK*|ڈ 6ăb|!yA@ՋWm-M-KBżDY4,TCևIj&8iEZO} NFDq0FXaIЀ8x(H{rH;RX"@5#  OX,_) xQ9 6B-B8Pؘh۪ z@Ҩ}7tH\2Zc0.a8y8S`_xbJjH9'ُc.@(9iB'BI 9᧙K:P@ר1Z:{ { #qoh'h۸:+кt:+$- DHDD )ɝR`!X p9 868ASZP-p6940 Pq@ؓ8=zaۓX+EiIA4p.+" b=78+i<)uh+I; C OI%(֋@lANB@3=J{4E 񕊨!LRx ͖A,뫩5( M/2 8t 9`P򣣙58=دB XMH؄PI 𼇔qӘ<0m}-TЁ\ hSIܴ٪pBޱA%KCKY`x֕uT~eO}]]á]EK$P@e9\eL[(`|0蕄{AՆe%qܤX*:%@148Mp@P@HT2N>M@N[ X-g)hS!92Ko|jlت x!PZl 0E )bkiV pBq! ㄁k\SS4hNCD鬎 h=ڈ^I7;<,=8f8 R@ӹI7(XSU$lH\-%!N6QSPihh%W/L#)ll)fZKib9hU#Oi :m8(DHfN mN6M0QM0f_Iɽz%-PH@13PLh46 K(X +e^hoϩn "Eewt(Ț`:N 5#/ыkVphy2JCNAЂAx.+?Aq{U| @=I[\chHXn)#|0k뼞#^xl1lAAI.\5q..v86mG8.G8DM1mm ZhȅPhWMm1cEpDx-n'V6$d5jmR"&-xd2,ՂK`UPh&h+`-pCXO(FB!ksTQl+M:["bP8,4r  X9HP X"r 蓃ix=R ֣̓* 98A1P%`(3X&dž xa+#h@b9Zgp dx7 wFft%$Et#r\QJ7X J?iu*İ1 ]F-9TL:1[(Jf 3$xVANr-!^! 4AvAByWG`&wPt!N4)*6|7=A/IQ* IpftЩ$aB;UXNv P5.Ih̒O+ܴ EkD M T!fjIŒNH;@ ZCE.!jٸrS:BV4YA23<5ZiP7txhYb%ze&CK vXSM7taf2Jƌ™ly7*شj>˄hҦ-{6jժr 7p!fx9mA.}:aGV};޿/^شkѡv}<Oϯ?{)'E2+|&_u (a}SN:ơ3 ! Ɉ:פ9ƥ6Ը !C١GQѱDP@ HpS8rT U K#rB8PQPN.xTka]U tme& UOAVEAE _We]x-&tBDtIk"A l&pd]{Hng lf8tHr4RTb ,Q& AM&@y0R$D A8u v4fFޤ)ra+Bd!=Q0L5YI,hUCjn[m[ȶ\9G$4B^0\;w3M:x/K+"@J( "D( r¡}VҸh85m 5Cb8'(?CE2g#:~l8$DN~ctR0RbԡBYM!J\FM4F5AI8০IZWִUtG k _TɾqE-Ѹ_FFX I*0f5dmꁚƴM8BD5YPDrRȫ!\|x6a:D h9eÁ2AL$rJiZ|.BJ̰>o 69D$0aLyf$U,4)R# c#YFF+b7a|/ 'flQ4l4lCD/ԣ341ɐ! hpE(8Z('DET5?1"F!qz B?C"b-40;p69$e MR YV%ܥMjDľEB{|i!8H6*⅝I5!$yC&bb0ŊZ(Ni#mpˆ[#σ\JIi:)"\*ZH A})~^\?!(_BR?`.  cp%O EL"aLe*6(21Ԩ MKjH__]F0"e#cVF6gAC=* M;pqK\?8,! [gɶmD{m2p"Ap A4o+ N4A ZhX0,f8hW3Ÿb  eq6@ I3vGU2)9,oQɇ*OѡR&>9PlQ^x(uW.8\RfM-#IpB'6%"89E& Q,Uig@P!d[,B\6ɗy8YK,:GbD2HBۇߙ4)b޾ɔ1ee= eDZC BG;Yb+cjV Zd[š_hF ec.}XL fti&YL=FE.PAbSAF0~JuéAo.5Yȭe" %jPlvdwfldKm䳙+ i 0Ff`lone"GGm )UKJD xDHҁJ]T@J`L @ꘅR\.Dh;Y K4K<:IYCYS!g gAx0dGD/xCԁ#*\%^j&e0p1 .@C6H.DǨQ%x@ 'pA %2B1[/B/<3t"C^/Ì03|&(B3H0PCzRu2efzch(8!q)*' N [9|+Ԃ4q39@8!% ~ P!  xNFP.De%XVO G1T YOB* S(GWEi[@FRY 2!KDr ƝqD"DIa,8 t@EZ%4B:TS€ʩ8}eɻڝ\WJ,h$%:K&Za/)[E502=Jbosf@olDǩF6К-/(+Potm`04lm'7f<Ѓ8"8pgV.]t5ujTSBM 0ailXcɆElfjF+֭pqj%/^^yS[jRLnԄ &-zͻ+O(xVkg3m'6oյnMϵ:tע.{wngrf (W7~yr˕ z(8%qRġg'i([ɃE浫^IO<劆c%2$cbnT.%Hp%rpA%\8a 5ؠ1~A9d b*8Ä$rc:VX"H5<Ȏ 9b* d3\hc(Y*0#a0cq 0@耣@ČH9 0@%;1ȅ56*)"*dSntʄpc :E C#9!"/=E 4 3B1.1>d>@aA@A9XBahK:̨"p-F3X5e":oW Hr㤂J|=fat f-R'A*p 5vj)lK;K(mLvkby*n\Ĕ)HD6t2< 3 L'IzG(b huڛkY7|nQ*\m䜋n:eTN@qeOoު>rƚo ɇ(GP. ALk)Elc HN6h a:PC+]C71Q]FFu] X7SmqC( T(Գ H]bM$č@蔓wߤ";gPrT%%,"8hKg2B:-o  4e v* lxӯb8pe j~3NQ^]p:Z"tpI|bT$BQ _!E/{-%+HHZ-&F8l>'p"iC)JlL4$X1#PYSp`ס$ qxjXH ?F6#yX1n4FՠEYr4@ծq Ȧ3-A,-\ (ɉ)?E-o~sxIyC O0F9! ʽ  ZaaPI[4:n>Ğ4u#óV*x@ |Va9AL'd(iCEДjD|C",rR![MLo!:ӢX';)$P!$%IH0ED0GH$;("P 2wm0QnXM(nC;E3hQjm2CPkD9 V bP  v.XְL'Hrt"8ddR.(IOrzy$q@#.h! bOBalqŘ{>>wX e9; y\S[ա4rQ^fb! dzCJ2`z8%u\0<PpX "BmņqX,SVlmC4xrG0?dq! øC2m-T Wb%Du$ư,zyx4RDb 9<)Jp*ŏU R:&hMpڰ! ]|:j:TR5NS$@H*%QPx:\sY+aFڑ(7/ |E,eF"ܐ9PKlBШ~5D7BJf4сir]D6pd-r #t/rt;1O(%9o(c1y~F%.P 2Q)bF13N\B+$d(;4 GY =#po`nqNGh;LuZf̎CnPl @B.ڀ<%y t=@̪Wrε2CJ{?kv!wudґiSEP2)9Ui:DRz"T8ptW:oMyVq A8$~4͞D! ] ! BH#! `m&[M"PN ܼH e^%hd#ak-"ߒb*+PߞACo\Cj~F4<>)A!x :;~, npFhh~` A@ JBHfɾg[4BCLSzvD><`H"A "fGD!#P.E?"PDxDPKJup$6 !6!S!2b 6#xC`M rUXM@ @pO 8!a#\`QF%6Q>a "ȆUMD50 raJиA~ެ&(-L s#5ka6aXn!>؃=l!jx'x"xƓBFb0LA8@B``++plilOQB<E:F/o6 }zA8!̡ |CA8C J5)d;TV4%R$TZGGBh0a :Va l P` L6kTFe! @@ "KNޅDlU<@y%!ltFgQ(K'G\iOZORN"J"]<$"6 {8"ZF(! "rM zmYXo </ 8R @D.K#+#@C2F6{HHvA++'f-2(,k,Ae3ł&N-ˡSA "BbUflv#-L#ὼi<)-LCaB!32T37CӓJ35;s5='j!=aQ3V.L nJ&MQҕ A3,z b ^ Av`=a;tnt4$#6Fu<@ @xP@ N *Gp ԐVG" e\Fd JN4TnU$H&*[; 82 -bZ ` ֬ 3f1c'P%\ThExX͒YB;tTfa :U&iG%+D89DKfܘ)JM68 dgODW1(L1.ƌC8,iTPɑ# !* QИArEj̡59Dr ;n,ТD9h`KSǏ:&y$3ЗDrT @.]RuI6n xq7Ƌa͕8qX4\Ұ6iF^yaҫ'6mGG_N[(`0|]6,E"ɘ'Ɇv'x!)R 0ܤhy]:$7 .-Lx-.VS<5 aK8/HK9ո͊橇yc .x&|p)'""&~Bg#\:pRL-dZh&&x- 0T 6pg3z^/jj/أ0 'dG5p-O>Q0 3L'F+b+|8QVfA? ,4] @" M(Df ja4"lH[bUZ56&k06HqkՐAv 60 cK=AN1!PY*Kn(KlrKffo-WqAmA" Dq5Z׃ ҈w Ȇ14Q){ i! aaD@.|*+3I,8 ,*RK7(2JvA7p\sEs@ZJɝx]y牙^w=Nө'ģM5`&<·]SN:x#˘c!'yNblRb-pC 0`:4(8` 49Jf-T,r->A-d Npxnt :4KYV(hB% M`)tpS*!U F \X L&,S9P[%!+P67t! ε@"D̰@-9 LB91re\"L@+Jx65D(VE YZagKXƲt ,HA*G4  0 >`@B1Cs0MBJ tKNذSauP2 N!z'(TժV5>A> a=Dxa0$hpCQ(rh&2@S 5aQU؉s\׍Z(H&s輻4aAX-h ~u=ҁJI`7@?0<$0jC" #^Q2QX1:X O "0wXz ^.(^Xx{^' E0c 3`$A StD˲Sl-ZkSrtE  3rHCUF:PCІ9 KLJ6a0t$6b]p33:1=Bp2ei#iB2D7nBl8 ZLnIv/jjL楂 0[3Y`q I3eT0Upp.'ZQz: 0 " R1Hp`/MP?AcfS&lĦ̡r0b @%3;S4ms\F<&Thnbx n P=0`9Fp&C >+C =PPX p"@*@ ` |< p@XY 8#7*-l[obG-< u AS W$v\EVY\W\C 0^PvcwڅvѰpS"ޡ^bbp z%,\L  iB'FͲ0 |12 aZy!t~Vd?A7I0pp3FCc10g/. 1G 2p!C13.I4Wm.c2P2Sqgl7]3'Y`v fSB/5i xR{UQa+@I1, s8? } @#ˠ( ip~QAA1l̑<Zl PRb 2=QӅ1ncXnV`=0P [Fho˲|p @рs U 0P  |P$}z;;@@]4Fwe=&8[9-,8Š?@9u_5\̸+GE0uev]ڵUD 5 &Sq BC\>p3wxg_Q`,@ "v*G1"BY .1Kp6cR?p Y0.1A4 JTa;QG{ Sg},00dF ?3P+aL! 8{c 7Na~S9{?IoCSJї8`} K7BNS6Ũ|N_IdpJ.31I?!Clp8p{Pd)(Qc P `` } l=-lSll) UAp V_ 0]P"tuH'9i"z*( (pe$ (R İ @^P B ire@@Ƞe:R&w % ^*'` B`@ yȌT-+TEGK_(pи` +@ C ƥa\IPI NзSw5`Pxs!ݣ`m) }'!N KGa''IjPP PW'0Le1!(c2{2#a6aK.`F1csf e|I5}tPq:"vRM$|#?5vSb#i@q+HG;4 cd,ÐvD6B0OR s ! C鰇8k r!#1ޒKSao1*V%C"Pű[![Yg F-&u¶o&C)) h#p^ೃF<<Pހ "TP@ @ @s*P"m& P*Ћ&;u.++мEI\\g0۸pYO0 n Q  P3X\)ͻB@GdD `Woˎ)͢y-L su0SfCe {u}b* Q2aJ i+124y?0J)QԬTp.\ 04s~m3&cJ k 0d)Pbs0s{sz>gs J%HYI4sW@{i5" i=t fSPC<0 0!<yaq3,`pb% e,fUkmg-5+xh'Rqe {d" @ =P[w \`  QUߴP|hҏN^ S@ b/WAnZ3`u3uICAup(vr/ =7x_G `+_,`z@ GK兩 ka{).4Cdqtv'NtJ'UfiyEq{TQM|UJ.Q~;髨J0 1 i0ppt%qXNӹd AFt2s bi5qqSg0WPaUP(ˠ4vYJHfTㆎ%JlbcE8\СH͜@Щ#9i HT#* f kVYLM> 5kȹԩ`14e͚ vVm0amݾjʥKN^}-jEX5t,h%[:lҼ OMFm4jOu jM] \jSq{ Jq␯ Dѽx؞=sMloj wak O-?-䒶OH1"$7j :0#!p59">8<0C)ڰ9VU"%@C6R*49Zc A(Tr5p&֨%2%ӃHLZ)V\X5$GpÎYA!8\aC M3@4*QO jc5$8AF$9PCGX80_H=+`֌HXI5qgCNR1G^.rn9%μbwݭKrR6iTȢLXhaD-{ b%|d!dE" +7ɇ[ߎp(h12 O!)H,J 4O,"\gl\ЭAUDA!5! Є9ԡ?pCB\%rFM@PBBUYJ%aGbx,;,f9EB!HX̀0)Vq \!0N?Z1pB\$.BX L D呍,@"(ICI@6n% RH8M2\JCC:Dg=G45! f0#̐F5 3Im-eyK\YZ@2lE[M/8xH#Ґ<ԡU~R>PԢ^j( P8mѧ-ADx7q$@-'PZV<zd' c$H0dQ#(Aؑ E \p] G cE'6q G8h-*B R'Fr5`9]Fj!UJ~3iP) ܐ)001X#&Z+0@ =)F -4q/3V+ m7U&Ӫ[2M$m #T\b1)?i62F P9`m ,8( 0P4H؄ I 8 W&u Zh /^1 yu1hpp @Z,%qȬȴ4 ]zCªt .LR5%`ЅĦK4f fDNs( H x  p@hv8 @IKrhwpr@qD Ju _ʍݰxdppzh(=HbH'|`^Pq,+t_P؃'Ȑ|8.ȃux{e@N8ÙLJ+!a"1D9 ! )=h$CSNHq3B- Q4ṅ@x6p$ja BEz˔)r!8`%ЂPP):M@`4hCH3h@mqW!^YA6J/H!XE6 [T л % 99KKu$H×G:6X+p8(");mm:ÕRY:k"[#Uq\) 0/Tqi xGb RB@iCT.-X 1[q6AJ660p` 6ah@̳dppp:˹L94n uHHutjȅKX$E? \'ls*8ddT_Y +lԜAbPK0=`CB25{PhP5RZ jG|Ȫ?Cɲ7T**TM E"H  [@rU@0%8fҖ4%2+:WA8(Ph`-h0*r2h6؄["R,)Xr3%X{c{Rr E&T8= mKS1+88XL886@8\YPI=1`S|dUA#m;$?Q[믶c !8;>0XYZh906q^M5p9 D8ʯ\4ԳL˯կ[\Ul y@ІI@mAoh`&>u3;.PJB$k5ٕbʇhTl;fZA>-@>5h10(>%5[ ETQUeYH$௒G@i\@h"q<; [%89 1.X!1ѶiA,.8H?4}6^4P4pTljhAz2LKy_yx* `aՋ qWhVVCe+A pos`Vް^ vEr`-l ZH:&]0]uX~x<f(̃}5L85ӠÇe&v⁣C6u[L\al5s㮐[%Tj0[:a7Z;EP 7P:H9P@(SJ{"7G5]R#]IQY[n╙E:+2%OvD:c`qRvBJ.0ܴ0_ICJՂ/x;&ޒdi #%r@؄S`y;c%` >(X9H".8 P>8w4`-8 G5J> hǘ\_8, y:h_߳_bEo8I)Xt \p(PbVb _eLV(a`th6^׃]la hJ&Rj{pWL2*؄Jkr򏲖PÃ/ :ӀYERfsd}PbiK6ijA 72B)/$+:2[ERQG(J H 5GO[5Ti#6#ٕG J/b36![8G[WJB QH%]ܗ4nx>AⓃ-h \H@!cz7\WAeY"bT!b"HZ|f!HNj#\n9Ȅ4xpxTnAhx @Vqa334Kߋ>K`K]ZovKȅNDz%r Y `sP(00+a̤ª+kAHd)!؅ޤXe6FhF&Nh[B[[hjnH&w܄xr7>u.6:pѮ9H`,p5qI9Ё1y1@\!@JfFh&f_ߨ3=czO(Ar yq0!xGnhtҸQ5)LD_yHBsApƱ@BلP@d)p !va{A4ŇMLظF +ADGbK? @Wb|jQ$T5!%ۢ74@Huh8>6bpa#LI/䖶k[n L"aA 6Cb.cҕ3':8f̬Ҧ+qٱG 9 6k!B4(+O\q͖#WZF-jl *'(A(P5mVpc":KraɚC K3m,AUTI̡80ؘ3!jh;w\7K0fq*~)x̘UL3%>_Ftn_].iӪ6M_v{Z0a‡/^7Ւ3nҧSn]:5nʡ#p yBL]v#=ytI7xP>?{ q n#9PBR5+!8"#&C2xHQCI/s# -!I (7$'‰B䑎x!&Ub" (nb0P]0$i)mnB}! 1Zm TeaG.pUE-AGhQsQErd!p lġ q؁CguL%Gm"c-j+0[* mlK1UYnE]m,rZf G * FZtAtS (B dB8 'D\47(DdPo)髯 a-BU wVa(U !!E_Y " sh[١TAզqI[Q?#`3}4I45TmV[s]'}7ͽ7|g]w]N: 1xN:܌+\ 6K(&!N"HnM<񘓌A84rK~~tbb/&1|؈=Ѓ*4;}xglj'a՟q9Ob"{ܷ}I>~r/BJr\PnNU(HȖpcii`5 m`:`uhB*;aTJPZ4fñe:@ZYbEaU[Z5| cܰ'3 tlD8Ċn8\qP 4hW 0" l\G`8:"c(q2" F$1J+fZu.XB:H ,jY $,8\TгP&p@ \C)5!4:02PL>ɚ4 fb;ȍ4 f-Ymr6ɭo:YNs˜6‘r|H @8tp>Lo#AB1Abs (^hń0<' ԁH6t-[ސ?Eԛh($S@*vZ$Hqءs5E%-UpDT+h`Rΰ ! j*Є&0X D"U@ GDUdjCB \\:-D[Z8,E0ű4LW(.5 Ap7.@/ -j ʽ!b R(kĪBUKE%.b@KPǪ0-'ۤA|Rj7!q`r==P."5ѐf5ǐh"b!pmؙ#A3D |j%R:$B/miNtSO?K&5L4$S]!GC AC(SrP d.t[A7ȡM+%ADMHC9l.C$u K"{qdkV*6.F"\ıP~V%h! MP*.!/!d!^@W7jMx p@< FG8B=AK p Y P <=;trC 1bEj,wO iR.r(*V%-&8A WHCS=GsD.ahjH }&fmlK9Y,5fP : (ܠ@5##=^/l5CL/!PGɳ>M0WbLpB ^9s}Pg)(CR4-&B7#Gݟ@?SR]iOOQ'&B08Ը֢DW> ЙϤAX\) HY1WǴMEDZtK{qҝY@YE ʜeVȁ '4/AnIDD@ '7D pr+tl-al'\@ŐȸWDB5)1-BC4DyD@y@\ $aUB\q \A-"U[M]J,mDS4х]4Mj/"-;͝XA2S:0wC3\/FH{\/ÞiNQ((#p(-• y+PB(`B#7Ȕx)^)d8::9HLaC(7Pc~U=s<lj=NYip_7mȮI8—VЗhaP QQA\@`9Q,5`%\]QJС,p]ԐtN= 0)@*Xvc{x`N& ;CC@(PQ&_>zBɗ+6ڔȎը'|JQ&hWadj ]QZ*HA$\h Hş`YRT MD*RhE܆Vؐ|)KY`AR@\@ 'tB#TPB18p** ’pLdK:q jKxv}*jU Q5h'Bh #E$@_.fqZ  )XtlVCm$LnnL6+SrLk]F: U2X9x`6Ц%A*GwC7Czd~ONu)P܃ S&$@N݇!ҏ' \B(d#_-c3IIP'&ZXHY תEe hB#m14X aH~"VBV[ቱ-nC<е(c. CPUV#L.d  M 8TFLL-' Ԅd͹e6 fꃹ IAX YV&p/Qres8 ` VHEğvp@(KJF@F%tn2:T C.@" +m0t QCm2+e5٘|0w:Î@A+=lg81@)2A_!PF4 /_#[}s([h]L`YBk]@ (P` "*b#9-_ b0|3G (usQ aO@IXTTܯb\JH8_@؅ۀ#9U \Bj"x@YQ,A B ZE,KXY~;Zt8 Pr6,3xh6B!@11%H DA>"<\W%?uBIp gB47H@ $AD<1;mt0@x/G>OpOЎ/$ۛ||~yϜ~R~U85QRՁ Ye DrhZTiuеUtjRY @ jr[ejaU13FI ӄ+DÌ BhA4NIKGF˳w$fjtdjڀA $AEN ! 80A@B O 4m NBxP _k/\TR"cC3C]*Ftz:I<w@37e 1qБCwWK<"5 &OjIK/\PE"%)'PwJ$I4'NrHÇ ;xxqn2hU! TtKBsi5|/?I?C 7ظ 80493"&p9l! 9DA0c :D 5Blc83P"DGɂBa(. Q Pi9hH`曙 5PeJ{! c"]y瞃q"R"-@*>iꓘHɊ!Z{(BDa%WYw? aVv͗MnD5;"9DG MpK99+s383ҘC 1 DL0e~P: I]9c>C Pc)5+dQt6b !dA 3<5 RNӈQ >tP#,0C %dP\! Aa !Eh@4 F'~*KfG)MUOR>@lb_:`M,78DUn(h6 ҠJա f0թO8cq"L} zh lA4шF5 baKֱ%.juZؒ-=\J6.oY (GlF:Ut `s D!ްWB W\8+~ t#b*]A URo,/I NlE'@F(Ah+XPe/3ʀ͖ PUPBVxQ!x8LZЂv̔\*MQL!aBC+1 Q,t0G+)HF1%GZ1/iolD[, Y 6q6ǹD:U4tÆ8T *P!N$ Q$W4j5"`(i 0aZ`t>hZ['0O+ %lbRڸa .8A #QS*FP-dM ׵ }t誺*YpbJ`㼦ac5R-@Z ~9HqR3! d!peIy ްp8{qrA+ sRG \Ŵ,d|5.EJRm2e+S)) V Sl"&E8^[2}(8@GHCjp p!$ qQOWD.HBAA  I SBMJ-Ad B7jA ͘7FZU9&DXC*C)MEB8sN0~N: T:L Z%.;K$ cC. >C!]:!vӁtiP!QHUthca,@U"jko cCg̯x aX8 o"CMHCe %%ZhX[8B ,oC(H1[yr'u8Xa3̀Ɇ *.G4St8@Jsn!Ҡs;A Uӣ9h8YRE]Fv޳wx-b&Yۢ_n 2 a.'P>'sr\ tڠЀ C@! zٖ wM cx'{`BChL`*nڪMy'ޮڲG + dG"@ \$d6BaNhO+K$JAjG9@SV@NMrn p J(\@UBĆ#OzHD8h頋F~&HڠTݐS:,gN V!(kv@nbEh!I^nܨ)nZi"ђ ^AoވVx AAҁE!WԋATV>`f@YB5Dc:?&Xaa!B!(%Sȯ$8 #OcV\.(@^`!mv3B4OL I#52%@!EDҜ "0F&ir^JqKXbpeF Sr՘DD>%2D2@0UzԠ(AD`?aCJ4Kg~' {M{ԠC Z!8Eה X7aLd r LCUРd OA 8aP@{S~ak $9pJV .xzmyZ$`@.ALC`6`0 uNୄcq3,C.DST I$H >6$8IqOkA.|d " 2|.p`JKp@N&Evı38EqQtPDUE ΈNUHtԿ1ŰH4W(a2A~IIAVM$MrHƙ H&c]%XW3\3XT$0\IN!)"^;ZAdDVAʘ kS/"UT[pB+TR nhj`iDip).W=2jL:S9,W!h h@AҐAE[8 S"\3o_ qxrD"DkG(5,^IOjq8n1R_}5q'Pg`JT'U@P9U= ටc;{GOS z>$܌G B6U3hBzl P`~xȸ ڠmSDPKB9 k6v@lJ9PzyñDS-Dh.PEkn@֠CX%pg0Tz8:NETrCns`b[ s%{hHW, `2!v!eEKwwǥZα2mh@)A^anaNz 2weԁOה튱&r.䷁/ 8=CB& a$la*B::c>A@A(!d^AJkZ*c@&R!kpT""F~qhޡc AҠAň1$"~lerc}wD4 ' ǵ][(|7q,=gMH֠L&OzK1 H`% `!@6@i`b Ұ & K>rg0 Z #>L>5V! a5c;0G[A||αx Hb6 yx ȸz7Q܍I6BO28lNT9P­Cv`EDUC=ptD(h1ڼaF`֢Fm!y7C!A{ջ,6 @n~)ڢ,2 AdAi!H'2lV`{W呾s!}o[{)NPfO&X J@A$ Yt(bF (.!ra%!ÃĆj̚DϵRPF=&Ɓb u%,SiO(p漄qcZcj#e4E^9>قրDU>AjNA̭`rG &禘 λέ?c{jarGw{ U@jujǿMڀU\G/ݨwȍizq̻%]2(aє tn)Zk߀h,fTbHT"#ZV!˖_|C%X0e#ҸF5y^+Q+NnkrL^qKAH<l@WXQ*A/$bG=聱f4Fc~.oR@5Z*FDIj2-n1w.334H'0 Wx8ZYA++a+GaxHDDsӧzWDb$Tq3+pޖIH)b01& GT' H!<{< l)66 a2t5(@эB$!bb4CM2!Q~7CTMɏkĜEg88tc6"Wp`+!R3$v0KAm8>kv4[6(aӂ uPpB.` 44A KnF d&E!ɇC:EpKsంC%' b&JGґE/Z7+XOJa }4)VKj0k7( 4F+JyL3*A?#@iF*ǎQ 1(Qd8+^G;zPot*sE*X[|~ ^ P/ d cT1@jE+$!y ^PF4pr2Ǫ7>F3 >&551fj:h55psO4j@Zb $,6E@{c1S=Hk NMfNCk Ca )tƉU M#@QO,ݔ :e'0۹Y'2 땨 Oַ#@zf 1PA8B Ja% WЂߵ`& b$"%zY‹#!a:1MgMУ%7;cr4PGU8uF< Hr ##󪯆 ]p=+]H08\7b:QV#OBɢtHD~3ȫbFƂA`ظBƂ*b긘:ڑ ,w;dy` wd! dcfXM ـM0 p $ dP z 7vC‚R/X0ޠG" H*z6* c F.2(P` PR  $ P M8b \ ` :hO P8p}h}TO@O4Xhm!P P \eop3OS`xq37ᠱ o!  ʀy 7NGx4MBVo2]A56Q;{.scP3 =<$%'cEq=74#CDEEnM "p Zl(.'s)k0f@bPc0 nhY#7C8z8KJ)$Bm :EPt$:&ΡC"`ZԳ:RC9r=vmaB)ǡtb:D#hb]3TD#1$%=qP>?g5|P*jat8r>x9)-feX~}#0!}gi0 #0 1AN7 t " _.0ț<8fӀ ° P  % ϒa& ișMɴM˴1$ 62р+6ԙ- ` SS9p$M  ߀U p 8Ϙ5Ő)0k􂋋v`  7I3:ᇠvO>ᡵsQ "nBq /3Pl &kgdpVUPqOɆU  U6e Lj*V2SػX^W:+s qP%*$ӡB1>sUE'Ht J@ e8ҁ3''%H:2$#"n"_5u$4tK'1CC_X#%^yP:TtvB#n %2ZnDV'p\J~di#~dGT zcҀG5 40ʐ$ӵffkv@ A.P[A8 Yc:H˵G C8 cڀ \{fD+ؠ 00<ɫp0` c!tK M0` ͛,İ  0+8/p A +xQsPP :0_P( 5Cpn3xfszC B @06Q,}zdɰTs| c2α;6skWj>A%>+@\u.VpP'9)by|R"p Fw Q=,P 1k `ތbSkӢI-0Cy LN8-<-id5;ԘV6:QV!<|rRtW`$B8"`!<ʬaXҡ0?@ t i"Qwm$t~f| *PA)b5Nl$:@Eg(A$Q8pr::(K6&F۸MbwzAC!rGRE>YQ*0b%UT-F؝Zi dfH*rd#0 R{c'\ /eS 1w6 ` 4 -jF @OESh2|t9,-5 ^9 ƨj"ӹ,c jbh`pPP 4 g/M_S~ vPa7 0 1 sy bp|zx {pqom!( P7# }>E6& qphOQM P( ypx-pIm(/ @H>m iA *ܴ !2D )!.+PбcfE@v(*8 tfq'7#Y҆*q`ThKRe 4mDih 834(4.(4gN6n4cԍV3:sM3KӹKv. JϠ8)%K,x5Uiͦ@U,9 :VhkI 8f8fC]LUmJ]Fĩ-$*Qf{f|}ۦϸݤ"0jO0O&i~&?Ai o_i% 'fœnAfh~fBiFD&g%.dPDo~d+1'O{1Ze<8b D&*FBIjFDEZieb҄2KaEa&tgwR"BHRd&rOB eQ{ܡǛ\B1#N;%HBe6Q> OF=ᄓQ@db+Z1bjAM9*PBQ rQFtZHi4AyYOQL#|$ '!BVLW6Ԃue߂BŸ́b$8H2L"(an2S*Zh$vZc,tmP/`DzPi3==j﮺;CK Glƿp}#@fAf%DdAbZy! qHOH$jC1v$@`0l&c>An 1A ŋyC"ƕ *JR ᴥl` Ԃ(< { 1AiB6$jC= +"IU2p` E# JC(H1 LdJH>oH%+N`Y0G2<*ވ*c쑟x52q!pHjbA X(8dB -00C$X!K>!r~!$WrV'Lda5A(LNC jIF3$IMdX6sveg:)Oc0*0`8sQ&:CJ̰ s9JR␆4aA f!L]Cn'ka2pB YexR$6*@C|lq(9JrրϹৠW(WP7$M|ԟt_LW9U^:.?L$35?]Br8HI̲\ n%P0-4G z x.tl#WB4P iD"F%vHO6XZiy0!h?ϔ hd"QEqJTӇq tE!:A[0SbmC4 `&:X iPV@BMpH25FsxBXpsVᩄ)M,ӆHp3ۄlSӚTf]\M$/¡s3y rY,g68L@8!5ي.8JG6!۹i\A тAhA MP 4/X7<.u+SY&oRJLxEnh$|.IpOh^ix"zziZWdqPIW髣)ɈN(+r+ Nx$aD` 칕|#.C6A )Vj=)#zG1SZ(,Wt!KE)LW!Jfl2p,ُ 4<'$_5YXѴLb̞R;t@A x!щR-u4PÿPp{XĪP *m д M{bC: y`ϼ'qQAو_8 !D>f,bp+Q h}³)Af&H,&N) I,ʒ/_LZiu/#J'V0Rݍ_b W{5͒x3nh^KHU(T ̒(,Q1L 2=_M)Dtpw8=uXhxNlm%33PP`GFI;+_ ?PU] ؅w+ʃf-SjHrYQTXojSi-2VaS؄Qjk(W2jί͘_&d'b&ib 4ay1!X#tUm<) Z 2L U8 3X&:P4$ (۟̀ P @ث-PHIר* D Ɍui8 1Ou-f֬ z7't0ތ sDjh+7Hݠ:X,x pS jC9@ ;9gp 9y٪X On {^"ɹ50eeHh'?# ڦ5/d4E!^*a_m!e0bxʺCit|<}!{.#ʬfh3/tFCh6vlw Oob C~jLjSR(Z9]5YwP UqpaI>b7d==0VmpG0%ePXiQa*<h'K&Sl(t^wk`J^n>m*hGb[QmPOͬqjX\5&b 38g|j(LCXV PdS3jWHXDp X8H6`j,5CeA5XzPdxVMq xX 4FdX2 LA nO (Lx_ ]2AG1ɧT1UpA|-D N30EGl"ӂ{`0*r #b+^b xp`-GAlBbnϑtlGMwu?b̾hFn`9mЅV O?mS b̨qQ=>(r$EO>L)TIKT&*R^ $I +VlVzxޫ3fʔ3G(y$Q2ũbC^~UbT T(HIdQ&,[k#NrKV+za*ȑ#N+ҦQJ,Ɖ`_c$';U9u[,nH*ҡ])5mȍ&iYv%YbCU"9tL :kʷY%˙%W! @FtAgUa vз kD" BqjXWkp& ±Kɍ..T!`yPEyEx㙑KQ1G&>!*, f@c `w"`U(f@$zn!ri<*YQPd !xl'HCM5ڜ6M5FFZZ/*Hy$38`Sk5>ҔkiZ20˜s=#2$#WK24#T@;x3Lc4Zj 3ܰöShqd؄c DP9ajD ZW k 5LlѴR}C: 1ĘL7Hr9H *0)<2 7J&,y'|UeyYQۜp&d5 I$q;l݊2ᤃ+vXc%-PYy%E2ԊVpj'kZ+ (.+ #2"Iw6)9wKqNnvKr9cW҈}EX cNg >ǃJ^ rJǠ)w BK"D@ B a6@=n&5 tќ"]CaP@mP<~:<>DmpAl 2 J< S' IC:D\AU8`ߔD  (4E4~0A@}B?&:ڠCֳY f ZCHOLVFҌFc~ oq=qW#GJ ɈEdэn$X=X7~1Vk$31w )tY&ܦnCibŐF8q ɡ!0E.2leqd$(BazB+"]K8эZp2\+ F3E(h PD&ҏPdg)FeB7ӑB⃼$nq#TxJ.j4Vq'nK&b [\$2CHXi] A8:"w F@y"49.=K8!n0<0jA78"6' )Hį@rv;G̹N p0AD`4A Ҡ";FpE*2ӂT ALD2<x\pCyA8|x%,ȇ7Qc!GR$,O]D}g!qt8k$ֈ}0x;>\bP=KX D x$ꐅ]TYCq6\AUHF.\2昈"#LYްJ ^#,/ V,$ɱUy EXx /i\Tİ{#2Ǭ2 a9ge握)M:$u"hHqX4NF3sg}ϰn"E-rg:Bt~)vЃvɐniI+$ݶB5AD.?I RV cG0ּƥf[(V8D)pG>e|C<ISZ4d =VVjX3i䳬sY!&pDng;G&zlyr㋈H'+r<1gPݻagt A}PH浟e&΁* ̤ -b Tjm"@4 0P p[6 9߹KZ avSX)ծ`|Ud~ VP"^( xs4%E.rEY!C*7 mT E8I la( Z4>`IZb,6BM]ZS7@D XDؚ)t*OGBDB(ETՈEDZ- 9<$1LF(l['W(L5[aIJB=A$ M|!1@A",7S5S5ƹ);IN[eqխ[85IZ5- ܾj&6-@O^9^U8OD (VF,b-Š,H}(Hv,IHhIzzAdqe-HH׋\ z4B (A 9wVHHd4~ЎP πiQ\ Y!xtt@,lpTH]ͽ܍ @Vs0-p1mJz9B.PX;؃7B,?$B!ԁ J8%%<&$ CO"8h%R"hB4\5DTU2@P!q5Й4(C,X%A"$øCK=+ԁ2tCԌ+85P _` `Ykݛ'45@`c:a: ~`>-t^ :QJL JX ų0?t%RLa 4l0 e:P.n\YM:aE$RB/={/Z\jepm{EGF-$@HѼ5J\w!p h ZC$ 7ph iŸ/HQUh z7$TULU8+4IVh%Lf`B3!X:A&HaR!+kp!6,AP0P;ASpt]*S*e&P 6AkJ V&ciPR,:] XѼ찄6pK]΢Ôp,:3##fLFnccJurG n#^%xN zxp܁ $S4M S݂# OpEABf X.8/ު¯ g̀J+KuQ! 0m$t'nXNjIVff 0HJ4$!S"%(Eit8A#2rSB$E"):`:ɿ+³RK%8Y \B e`EK"V` 0d ܰdM O QE!"ص +-qI0B@1=ԑstaCRلF(0_ELbmMm^\3*D;2k`c(*^A7LND)>c f҈I?`d8tP 2"\ը.IOQ?JH2R,'M)KyWt,tp]쒒4$&LNrV\!JӉlBa q0 W㨪X},WP {@['\Q ba3^ <ڸkޜ"/`k0&p\bseGz'(%HHR q*MkkhØEMLN#D}ڄ/[dȁvԭ*.Q)Z_kpԪƒWKn LWHV:! Ⱥa$RZKBCT t'1Lh$ӋTXm@R': 7 UYE#86caDMM--|J0Z!x ؁`ҡN/F n&Z$/*!#p0n~hjAEYj\:XCĿKTP鉶.r ؠp .L\dI` LRT A G N]V`#SdLTҥDKB2`hVIKU\ToԎĎ`J KeKQZEK^PZLx1rH񌥉XLDxh v&a `G @r80A$ (c@t/}b+]&ϔ $a,]ʦ'0jv .-"ArF  0l\ "bfo jk2 32imjbz-^, aBd/j4IaMS842` 2AHg>!XA N6:@023p8s2Js98Rw$|A=Ɓ  a=./A >sf42Dl@Q! @Y`KSS*1SnN6OK)PTH.dD6 L\\ITck ⥓XdFHsHjA~`1 F@JRTbWKIl`JU %QKJdHdVPMM䀌ra偐kX**J\Kde腎săD\YH$$EVK @ QjG D @ `f̤"S`)b.$iHX,aAj"^jfA@ rEb*6h*A&xXh]G„&$P'!"2٦?lG8H*2lgS,*cB`ڂk6@  @:`*DA98!f snad'np3Pdq,!`  !fy.ʁyyzBA  3F@_?IJ,KK>> DTTHԋE6&L,IZHA[$D^إtzT NSH΄Yr.:I@M& bn-0 @8A T  an% dh|CZQ\f/ԑ@U%O\{bh hE]RŐη 9 HɄK:J`{DV&ePILC1[ޥE]yǼ @ `J Kt@ Jd8rAsh!er'IxX !%0jL&~ jba09s۠Pb?cצÂ̭2;Y_0~wx`ٓX/ጩ0mޘo*2!kxj0\Aj9D* yv2B#ZA,uL,|j5h"<3F΁oekuz٘`s03:M*nƧ},Kq~ Vr,RDXDVFZY$lQBd?7`DCL$YTIʋ#OInɑUSSnt @^T4 rHDL m@ .`@ ՅZW$U"K|fH(EX*D.D4oD%U q $T\NueϛDe v @Ơ섀 @RD piA@\${5ej~"dP8c!%,9P(",-~#0!PFBMm]_{$?A"-(-p6w?Q!c!𺳛nNS^-(6lP[2,)>;EA$8@Zs$!6-Gv58vrg1HaA6{3 `j5,<=༡>YXFA4,|h *(H&%WelLIVtC6tJ~|H~Z\sD\BI$J(dxYˈ\KV{n .xQ,a pQ9iI@ (Q.L@[PE̿R!cI҅AYd:)F2ȀUAOV+qfOE$+%V0} :KС5f2c3WhDæ5~i&K-f4S&iIC3 frqMGUVM`Ӓ &MТIkKZ4exi%N:u̢B:iSOUkOk҂+*ڤBhgKIժE\X6#KLY-5`@yΞ>D:&Υ5媖Z~U.۸s뾝qhϤ+_μ=s2%INjDTn4+L2E9J&Q]q ʼnRƙ3T裕6(B_(K(\i5xs;$ O8cC=ۉ&bo| Iq &hBZ'g/ DH .+,qB+H 8G|Hk,DdiU,Ĕf$'pC2&U!kdK .*eUaGNFCVAC! MȗtTцc6JPhtgaF $sG 4ERJ\$HY䒅 Y 21ٰ,Iǖرfk ǩpqnkY繛*k.Hy!k`o+ꂜnZfQK +nf@:,!ꆭvm!FA&i 0 "HM4:cubv%5Y@2,=Df9c` cM5Kf3rX{?nSc9+"-rVUdNuo鄣Wh/\7DɌ3L(4I(ʨSybJ9)u6_&`~ O ( 8' 'yvZg kZ8OC :N80~,o  I0=;j4! @!oAARnp*)QtXA"  V%jK9Sy ^_ط.f+1-]= &)INjWRPa2PuȂ:';m81; 4`9[jI)TL{V*'K T6(!d .RD \u5k ۊ6HB 2e D$-TBpcpSqqI o`0AdPP&`(k١ҥnيde.t!aUb ]2([ZJ|!,ҠSC/!o$bzͨF1A9AR`P1KJW~.tبGM 8NX!YƸ\3Z|)D(8T0E'>AQGB8(: S 49:#b\CX|`Fn?C- |CНzpBrD;Vtb" WSG[X@| ; +xALn%:4BYP Y&okJv(l"˴k2%$(nRR ġZR'S :0+;,bZUHd l(E:2$C30AA $QCe` AlLŭE\@ __ YҺEd TpH*0m#t:*R!?K r考(m &S׹;/z W09Aш3[n$nƂb!iE]8:Bj5U`7 ucCgY%$7ɹja7F04Γyh8򳰶M9Rݜ蜙)Z#|j.5V0FICհ(L*H!<\ԂAGQRr%TJ ҅w).$ct`J KA$Y%6V-f.qL'ip:7EcEe0#m=!6.jQ4rahxcXLhHE UFb(*iP95mnR49 k! 6T  ݐ TRl C P` 0 ceVb5h'p VpqYn&W>Lp@AP?9'o I03L0pS gYW*cBvZUARe'/I4P\!4I-Yu sCh*R.Yq&pP|'^p"H8v*z^E.~l0d+$"0 | 4* $Ni0G6c(`-ol8\yc_KR*pBR0!EgC,EZYr)A1h{(y'$[r'C]+C,2}7)R*UJ^rG?PH/K0 d2&rr`.!LQtK\;!Q,)5rHP  f"@瓹0~&}hh{ ]as 7v6Th\.%@ j薂ZijRRgp {   P  &x Ʊ `YL @"0K@qK +I"CGC91%6&ZhbHY(^H 'XOY'ѕ%#y,D%Cs(DE,2*(KRt)Af`KG ?p i 1t(70F3icP~E_f,ɲ%\+C/ S(r(;2^n(+u/s%$( BcTD ᗡ@ ; Иlx$?Юq*9 `4|BN@;@"@A%b dX #@ _.xy'| T0Ysb& 0t. :``(EGYeA4wDVt&pb9c`,AN61Eq,)kɵjC,bG2G~4`3E-sԅ*Avqz2Ɲs(s| 1/%r)U/-BJ<.-:k*\ tQY^ %JÈv`rdz*S'%!~nALJb+'R\υ0tZQ[QFN!J @lsfabh7f`~}1uX 6j{Ip2;#R  b 8k1 p  Y p Ϧ A >{Z F`lr'Rp a0TV@ =̿R)u"ѯ 71UBd,&4y(Dz8@yՙIgxBvp7K81a8ZypAD_F+YB)/"r151Qڂ z0: #.%'n Z4)(PdBr ' x[1/A.b|pҏ.I*!T[ _b,wUWDd'2!C*/I1-!1Ǣ)x(EIحXd2"ac1&&G.tO0)J PS ]f{ qm =JQZ P; 駾g#/%6fhX w$8"e99 @$ s JLS@Aà bnS>]pBua9=ن ҠiN z0?@L^6PH ` XA @M EQgJ2&.+ 7T%/%MI|M2Ǐm"K E-Qc"s'*|/ +-r'~7 *2[/{S'^|"jme1G|p :|G-]E{r  ]2%nbICJ.J۞u&+DsHB1 )u%rybDY z(t.um.5{)1GcΔAZ'&1>;\|t0p:Na5CGX0]}SoNAP1k`p&q9~cװpS#TC @ !Aٿm:kw^©F b 0 &JNmO} ߐ M >6H’ .!Pf*e @ Q01"0Q % ks zuQ P=ӨO uԡCkTʉ5fYU ,xðŠ۫r 0-/k A\{&ZxEl("멇:ԁrFD|#-HpR$(H:v+=i^2>A-UcLe"TB3a#rŝ?jPn! Z"Y bшGD< WxW`X ҉Xma2E(E{=솮na0O[U*iuBS6pxnc 40Dab +)LRP&8&Q]ElRPȥ|MHatpYpi0I@"v Y wyQOf ߙeo!ff$u lX6t.uYs\b cF7XĞ1CCG,c ^F:!)̘5A *HE~t5|@ CAB>$_іŊҰ *Z ʯ~JB` I&N8L UX1JF8j' Jk"S9^U&Ѻ2$k]a ixX:0H#AH7 n(FMtZ8%eJbubrBjp5pnk^-B\e ԣ5;$'YXלV&U^&>U&V!)Es#71QBzd.3]B˧9iɒ &-In֩e%`| tcj$@>atA!G TiM3\AKR,"KPˢbuvЪE* )dNV4~rWA)o1 CK6xOYvº4pER Jh1 leq,ω* 2SZ2bn'K0,b;BI`F5& VCpG4zD0}G7hpD#$@5.]~/1x# n0a?mHz61+$4KDW0ط}k&2inԥ>uʎ)0XA=axhE+{c%L I$?T[Bo@*RaQo5w/H?d.$#Ȇ0vǧ""Ge%Og8u !کZtLbfm Q E@xx'==J'Y*L-I`$MqƓѓD2WC aDs)1SV64 16F`h7-H13(Zbp8iR 92؈ \ɳy3å@+xH(A;H'\kph*'P=`-H+X:Pc5)XS 1+q :p-( \H(hrf" Қs-ABhPXu\j謜S:vI7!9K.NꢺVt$ҮKAOVHT (+!0B \UR@R#UR{KT1iI!>R³0qvt`[0bI#;%ұ GT2(xq("O;RH4h&s4 4&C*)aQH6o2%Ȣ69/' IcrpcP a5z5S 76AȂ9h>ЁAXX!-Ȏ}҈h2ډ z28ЈLx'pK@X<͑٦¦ۉ(88+dh(x xqCH,jqU(qPh_=DhDu*-QD+Nfu`tl=INM 7)O!@ daGP0:SDTz"ד+OTF.ThT0(`_Ihcdd뢓PЛ\0gDiA#Wk#oYCE'`óV0i\k[,N;[SʄG)H!U;H!_O Rr5ۀ/ˊ`\2 _p+ & )(Ӌ Ô`ȵEx0+ 0 h4ӘɂAPPX(4 H` 4@9 228K`X897ȈD%` #|#6 8| ;*3(1 /HB+T8bu9%WhL٧}Ӌ՜8Ԙ_x.q$N$Μ,PD=YJh@D>.*k KNl8ENTAr9)vD4!ZyVtK!L[$#bxa ˃4ށ.>@.K9BY]Y>O5OY3Yj0sRD8-ZIYEOWpMVZXVyd/SXSWinȅKhTFnH$I'8\'hLM$*)-#+:9z۹}#1|܂[35 X^=ȝ@?-&t2W*i%, /C Qib pݍR!*܋]3d MVW  AeI |Z A!QM&:@_\Վ@M ]cq "l˿(Xރu*SZ u {Y#H0L tr?Јb' zS%Pf75xW HZXӬ М> 7F4P(899do@b%aplcCѢDFz@XEDJ Ё/KE1؞؁Y@"/ёLcOY SYBߎt0ZUdP7z#xnx{#"*pKptBeՃ#};IҤ_1G3aLЃ#p'mEїHx%)@X‹h PE8渊@&#֟IY2hcCrk* &0d ~ \pĸ` 5h,(:AB0c yÎh`K{򟄊 I&-X qժI/]T>૫X*rXkR ,Ɖ9b4 @UakMgO{5 U !A`^T_hظԊb֊bͦA8qXm㐍\@؍mf "rm3Y n?5M6Ouanyn.:[y G9" V(o /f)؃N EZV "6 h$;qm!]pCY8xVMG 2a[/N #8HaW@G ܛ2rX *5e7* )Y/d_ hkҴBuhB)̉*x%Rh.'>3)*8'Te]鑘AH@}5:BLP3@7KtDf z~ m2XJ13 h Z*HC(]x 1*5tɎ5f1cL6f؁ʒq4hJ5q1%v.J#5nN[4˓#ZӪUJtZ`C*&- ICmhюNuiDa&Z4fygR>4kVX11bGfҰ5WfB7r TRDfg¥CgtQnZu9m@yi'PFZӅrʗ3omɗoB 0j¶s. n5gmb 7b0؊Gy )`Rʁ%8EJ-s~#^*܂:猨HOQXtlj (A )(+I8^p9G8d"xRn@!%)jWņ+Mc̰4~s a6Db:SG3h #(Z\"]T(Hlu ESY,R@ OuL ,)H je0;&R@XMZ%Er+|d jCpMIOOaC4Ej Z14Ɣ )6V (( 礱9`Y:&:kmhuĂ40SЄ0.i.*MfPtt} o|ut4jAQ5:i΀ jxOWձ:ƫ'xI~&8/hEE H( &FaVPL}(hD1BшF\U=Fd( G*^"It=V(N1 oCjЂ8!5xmeoRUk3BnCfo)Vjr əQ+;_bUa躁!VtA !aA[]X S*qØ*Bb2HmYVQ A8!WB9a[ 1[ ɂ&&6j:)l j#dC %:L18qS%q'f)0V3z8XtiG$7>je~.ħ6>W5DeδFLqP '!1.LlI1DMV)1xQqx㠉QfEjB޾ E.-괐/ceQ^/0/zF4*STiE=mѵ!i!ܑuAz;<k}吂o8 )XNx蚄$8 zD'O֯T'\QA+ZHC;w'Hn GSx03! D}=S\B !1.M}q5 Cu*d"6If) u7MaChTa5ìEYQW%Y, o without output it will stream to stdout. } node n1 { type router model mdr network-config { hostname n1 ! interface eth0 ip address 10.0.0.1/32 ipv6 address a:0::1/128 ! } iconcoords {186.2364578872143 137.89039496012572} labelcoords {186.2364578872143 161.89039496012572} canvas c1 interface-peer {eth0 n11} custom-image $CORE_DATA_DIR/icons/normal/router_green.gif services {zebra OSPFv3MDR vtysh SMF IPForward UserDefined} custom-config { custom-config-id service:UserDefined:custom-post-config-commands.sh custom-command custom-post-config-commands.sh config { route add default dev eth0 route add -net 224.0.0.0 netmask 224.0.0.0 dev eth0 } } custom-config { custom-config-id service:UserDefined custom-command UserDefined config { files=('custom-post-config-commands.sh', ) startidx=35 cmdup=('sh custom-post-config-commands.sh', ) } } } node n2 { type router model mdr network-config { hostname n2 ! interface eth0 ip address 10.0.0.2/32 ipv6 address a:0::2/128 ! } iconcoords {49.97421009111123 297.31725181124926} labelcoords {49.97421009111123 321.31725181124926} canvas c1 interface-peer {eth0 n11} custom-image $CORE_DATA_DIR/icons/normal/router_green.gif services {zebra OSPFv3MDR vtysh SMF IPForward UserDefined} custom-config { custom-config-id service:UserDefined:custom-post-config-commands.sh custom-command custom-post-config-commands.sh config { route add default dev eth0 route add -net 224.0.0.0 netmask 224.0.0.0 dev eth0 } } custom-config { custom-config-id service:UserDefined custom-command UserDefined config { files=('custom-post-config-commands.sh', ) startidx=35 cmdup=('sh custom-post-config-commands.sh', ) } } } node n3 { type router model mdr network-config { hostname n3 ! interface eth0 ip address 10.0.0.3/32 ipv6 address a:0::3/128 ! } iconcoords {176.46110847174833 328.14864514530865} labelcoords {176.46110847174833 352.14864514530865} canvas c1 interface-peer {eth0 n11} custom-image $CORE_DATA_DIR/icons/normal/router_green.gif services {zebra OSPFv3MDR vtysh SMF IPForward UserDefined} custom-config { custom-config-id service:UserDefined:custom-post-config-commands.sh custom-command custom-post-config-commands.sh config { route add default dev eth0 route add -net 224.0.0.0 netmask 224.0.0.0 dev eth0 } } custom-config { custom-config-id service:UserDefined custom-command UserDefined config { files=('custom-post-config-commands.sh', ) startidx=35 cmdup=('sh custom-post-config-commands.sh', ) } } } node n4 { type router model mdr network-config { hostname n4 ! interface eth0 ip address 10.0.0.4/32 ipv6 address a:0::4/128 ! } iconcoords {145.04062040794378 195.27962082775758} labelcoords {145.04062040794378 219.27962082775758} canvas c1 interface-peer {eth0 n11} custom-image $CORE_DATA_DIR/icons/normal/router_green.gif services {zebra OSPFv3MDR vtysh SMF IPForward UserDefined} custom-config { custom-config-id service:UserDefined:custom-post-config-commands.sh custom-command custom-post-config-commands.sh config { route add default dev eth0 route add -net 224.0.0.0 netmask 224.0.0.0 dev eth0 } } custom-config { custom-config-id service:UserDefined custom-command UserDefined config { files=('custom-post-config-commands.sh', ) startidx=35 cmdup=('sh custom-post-config-commands.sh', ) } } } node n5 { type router model mdr network-config { hostname n5 ! interface eth0 ip address 10.0.0.5/32 ipv6 address a:0::5/128 ! } iconcoords {137.9101266949479 257.51849231830334} labelcoords {137.9101266949479 281.51849231830334} canvas c1 interface-peer {eth0 n11} custom-image $CORE_DATA_DIR/icons/normal/router_green.gif services {zebra OSPFv3MDR vtysh SMF IPForward UserDefined} custom-config { custom-config-id service:UserDefined:custom-post-config-commands.sh custom-command custom-post-config-commands.sh config { route add default dev eth0 route add -net 224.0.0.0 netmask 224.0.0.0 dev eth0 } } custom-config { custom-config-id service:UserDefined custom-command UserDefined config { files=('custom-post-config-commands.sh', ) startidx=35 cmdup=('sh custom-post-config-commands.sh', ) } } } node n6 { type router model mdr network-config { hostname n6 ! interface eth0 ip address 10.0.0.6/32 ipv6 address a:0::6/128 ! } iconcoords {119.15850324229558 93.2505296351548} labelcoords {119.15850324229558 117.2505296351548} canvas c1 interface-peer {eth0 n11} custom-image $CORE_DATA_DIR/icons/normal/router_red.gif services {zebra OSPFv3MDR vtysh SMF IPForward UserDefined} custom-config { custom-config-id service:UserDefined:custom-post-config-commands.sh custom-command custom-post-config-commands.sh config { route add default dev eth0 route add -net 224.0.0.0 netmask 224.0.0.0 dev eth0 } } custom-config { custom-config-id service:UserDefined custom-command UserDefined config { files=('custom-post-config-commands.sh', ) startidx=35 cmdup=('sh custom-post-config-commands.sh', ) } } } node n7 { type router model mdr network-config { hostname n7 ! interface eth0 ip address 10.0.0.7/32 ipv6 address a:0::7/128 ! } iconcoords {79.1102256826161 50.123535235375556} labelcoords {79.1102256826161 74.12353523537556} canvas c1 interface-peer {eth0 n11} custom-image $CORE_DATA_DIR/icons/normal/router_red.gif services {zebra OSPFv3MDR vtysh SMF IPForward UserDefined} custom-config { custom-config-id service:UserDefined:custom-post-config-commands.sh custom-command custom-post-config-commands.sh config { route add default dev eth0 route add -net 224.0.0.0 netmask 224.0.0.0 dev eth0 } } custom-config { custom-config-id service:UserDefined custom-command UserDefined config { files=('custom-post-config-commands.sh', ) startidx=35 cmdup=('sh custom-post-config-commands.sh', ) } } } node n8 { type router model mdr network-config { hostname n8 ! interface eth0 ip address 10.0.0.8/32 ipv6 address a:0::8/128 ! } iconcoords {159.90259315202974 8.220638318379141} labelcoords {159.90259315202974 32.220638318379144} canvas c1 interface-peer {eth0 n11} custom-image $CORE_DATA_DIR/icons/normal/router_red.gif services {zebra OSPFv3MDR vtysh SMF IPForward UserDefined} custom-config { custom-config-id service:UserDefined:custom-post-config-commands.sh custom-command custom-post-config-commands.sh config { route add default dev eth0 route add -net 224.0.0.0 netmask 224.0.0.0 dev eth0 } } custom-config { custom-config-id service:UserDefined custom-command UserDefined config { files=('custom-post-config-commands.sh', ) startidx=35 cmdup=('sh custom-post-config-commands.sh', ) } } } node n9 { type router model mdr network-config { hostname n9 ! interface eth0 ip address 10.0.0.9/32 ipv6 address a:0::9/128 ! } iconcoords {150.43010603614704 165.70781621981482} labelcoords {150.43010603614704 189.70781621981482} canvas c1 interface-peer {eth0 n11} custom-image $CORE_DATA_DIR/icons/normal/router_red.gif services {zebra OSPFv3MDR vtysh SMF IPForward UserDefined} custom-config { custom-config-id service:UserDefined:custom-post-config-commands.sh custom-command custom-post-config-commands.sh config { route add default dev eth0 route add -net 224.0.0.0 netmask 224.0.0.0 dev eth0 } } custom-config { custom-config-id service:UserDefined custom-command UserDefined config { files=('custom-post-config-commands.sh', ) startidx=35 cmdup=('sh custom-post-config-commands.sh', ) } } } node n10 { type router model mdr network-config { hostname n10 ! interface eth0 ip address 10.0.0.10/32 ipv6 address a:0::10/128 ! } iconcoords {64.19289632467826 42.49909518554088} labelcoords {64.19289632467826 66.49909518554088} canvas c1 interface-peer {eth0 n11} custom-image $CORE_DATA_DIR/icons/normal/router_red.gif services {zebra OSPFv3MDR vtysh SMF IPForward UserDefined} custom-config { custom-config-id service:UserDefined:custom-post-config-commands.sh custom-command custom-post-config-commands.sh config { route add default dev eth0 route add -net 224.0.0.0 netmask 224.0.0.0 dev eth0 } } custom-config { custom-config-id service:UserDefined custom-command UserDefined config { files=('custom-post-config-commands.sh', ) startidx=35 cmdup=('sh custom-post-config-commands.sh', ) } } } node n11 { type wlan network-config { hostname wlan11 ! interface wireless ip address 10.0.0.0/32 ipv6 address a:0::0/128 ! mobmodel coreapi basic_range ns2script ! } iconcoords {0 0} labelcoords {0 0} canvas c1 interface-peer {e0 n1} interface-peer {e1 n2} interface-peer {e2 n3} interface-peer {e3 n4} interface-peer {e4 n5} interface-peer {e5 n6} interface-peer {e6 n7} interface-peer {e7 n8} interface-peer {e8 n9} interface-peer {e9 n10} custom-config { custom-config-id ns2script custom-command {10 3 11 10 10} config { file=sample4.scen refresh_ms=50 loop=1 autostart=5 map= } } custom-config { custom-config-id basic_range custom-command {3 3 9 9 9} config { range=200 bandwidth=54000000 jitter=0 delay=50000 error=0 } } } link l1 { nodes {n11 n1} bandwidth 54000000 delay 50000 } link l2 { nodes {n11 n2} bandwidth 54000000 delay 50000 } link l3 { nodes {n11 n3} bandwidth 54000000 delay 50000 } link l4 { nodes {n11 n4} bandwidth 54000000 delay 50000 } link l5 { nodes {n11 n5} bandwidth 54000000 delay 50000 } link l6 { nodes {n11 n6} bandwidth 54000000 delay 50000 } link l7 { nodes {n11 n7} bandwidth 54000000 delay 50000 } link l8 { nodes {n11 n8} bandwidth 54000000 delay 50000 } link l9 { nodes {n11 n9} bandwidth 54000000 delay 50000 } link l10 { nodes {n11 n10} bandwidth 54000000 delay 50000 } canvas c1 { name {Canvas1} wallpaper-style {upperleft} wallpaper {sample4-bg.jpg} size {1000 750} } option global { interface_names no ip_addresses yes ipv6_addresses yes node_labels yes link_labels yes show_api no background_images no annotations yes grid no traffic_start 0 } option session { } core-4.8/gui/configs/sample4.scen0000664000175000017500000053176012534327775013726 00000000000000$node_(1) set X_ 196.387421 $node_(1) set Y_ 462.134022 $ns_ at 0.000000 "$node_(1) setdest 196.387421 462.134022 1.000000" $ns_ at 0.000000 "$node_(1) setdest 195.956911 462.201568 0.435777" $node_(2) set X_ 108.414716 $node_(2) set Y_ 393.160360 $ns_ at 0.000000 "$node_(2) setdest 108.414716 393.160360 1.000000" $ns_ at 0.000000 "$node_(2) setdest 108.686466 392.778045 0.469055" $node_(3) set X_ 14.254378 $node_(3) set Y_ 541.257030 $ns_ at 0.000000 "$node_(3) setdest 14.254378 541.257030 1.000000" $ns_ at 0.000000 "$node_(3) setdest 14.839150 541.372844 0.596131" $node_(4) set X_ 41.851670 $node_(4) set Y_ 545.867138 $ns_ at 0.000000 "$node_(4) setdest 41.851670 545.867138 1.000000" $ns_ at 0.000000 "$node_(4) setdest 42.442273 545.926217 0.593550" $node_(5) set X_ 182.809226 $node_(5) set Y_ 513.055969 $ns_ at 0.000000 "$node_(5) setdest 182.809226 513.055969 1.000000" $ns_ at 0.000000 "$node_(5) setdest 183.335280 513.337339 0.596575" $node_(6) set X_ 122.027997 $node_(6) set Y_ 524.087717 $ns_ at 0.000000 "$node_(6) setdest 122.027997 524.087717 1.000000" $ns_ at 0.000000 "$node_(6) setdest 122.475860 524.470641 0.589248" $node_(7) set X_ 186.692167 $node_(7) set Y_ 453.103964 $ns_ at 0.000000 "$node_(7) setdest 186.692167 453.103964 1.000000" $ns_ at 0.000000 "$node_(7) setdest 186.362331 453.043815 0.335275" $node_(8) set X_ 6.841010 $node_(8) set Y_ 411.004614 $ns_ at 0.000000 "$node_(8) setdest 6.841010 411.004614 1.000000" $ns_ at 0.000000 "$node_(8) setdest 6.715910 410.970880 0.129569" $node_(9) set X_ 180.514289 $node_(9) set Y_ 395.901964 $ns_ at 0.000000 "$node_(9) setdest 180.514289 395.901964 1.000000" $ns_ at 0.000000 "$node_(9) setdest 180.863640 396.303766 0.532438" $node_(10) set X_ 148.853602 $node_(10) set Y_ 357.991260 $ns_ at 0.000000 "$node_(10) setdest 148.853602 357.991260 1.000000" $ns_ at 0.000000 "$node_(10) setdest 148.959253 358.166829 0.204906" $ns_ at 1.000000 "$node_(1) setdest 194.187758 463.051431 1.962694" $ns_ at 1.000000 "$node_(2) setdest 109.321754 390.842582 2.037058" $ns_ at 1.000000 "$node_(3) setdest 16.393600 542.808055 2.115690" $ns_ at 1.000000 "$node_(4) setdest 44.634359 546.049079 2.195526" $ns_ at 1.000000 "$node_(5) setdest 184.328928 515.246522 2.152281" $ns_ at 1.000000 "$node_(6) setdest 123.835691 526.192539 2.194099" $ns_ at 1.000000 "$node_(7) setdest 184.877733 452.038170 1.793140" $ns_ at 1.000000 "$node_(8) setdest 6.671562 410.117567 0.854465" $ns_ at 1.000000 "$node_(9) setdest 181.894113 398.159435 2.122590" $ns_ at 1.000000 "$node_(10) setdest 148.870931 359.695988 1.531708" $ns_ at 2.000000 "$node_(1) setdest 190.851655 464.311512 3.566145" $ns_ at 2.000000 "$node_(2) setdest 110.783099 387.546466 3.605539" $ns_ at 2.000000 "$node_(3) setdest 14.881262 545.183484 2.815996" $ns_ at 2.000000 "$node_(4) setdest 48.394729 546.584695 3.798324" $ns_ at 2.000000 "$node_(5) setdest 184.473917 519.006641 3.762914" $ns_ at 2.000000 "$node_(6) setdest 126.386821 528.676353 3.560561" $ns_ at 2.000000 "$node_(7) setdest 182.160868 450.006458 3.392523" $ns_ at 2.000000 "$node_(8) setdest 8.577394 409.839307 1.926038" $ns_ at 2.000000 "$node_(9) setdest 182.309184 401.800750 3.664895" $ns_ at 2.000000 "$node_(10) setdest 149.229189 362.797090 3.121727" $ns_ at 3.000000 "$node_(1) setdest 185.998912 466.082945 5.165955" $ns_ at 3.000000 "$node_(2) setdest 114.977824 384.500577 5.183932" $ns_ at 3.000000 "$node_(3) setdest 12.849462 546.572220 2.461056" $ns_ at 3.000000 "$node_(4) setdest 52.522431 543.493688 5.156767" $ns_ at 3.000000 "$node_(5) setdest 181.227267 523.091806 5.218171" $ns_ at 3.000000 "$node_(6) setdest 122.849749 526.513462 4.145958" $ns_ at 3.000000 "$node_(7) setdest 178.377101 446.748671 4.993003" $ns_ at 3.000000 "$node_(8) setdest 11.957948 411.081133 3.601427" $ns_ at 3.000000 "$node_(9) setdest 179.694536 406.348826 5.246083" $ns_ at 3.000000 "$node_(10) setdest 150.721736 367.286506 4.731021" $ns_ at 4.000000 "$node_(1) setdest 179.555767 468.148449 6.766123" $ns_ at 4.000000 "$node_(2) setdest 121.705230 383.835205 6.760230" $ns_ at 4.000000 "$node_(3) setdest 12.743213 545.655478 0.922878" $ns_ at 4.000000 "$node_(4) setdest 54.718112 536.856974 6.990493" $ns_ at 4.000000 "$node_(5) setdest 174.581069 521.988831 6.737099" $ns_ at 4.000000 "$node_(6) setdest 117.358177 524.776868 5.759612" $ns_ at 4.000000 "$node_(7) setdest 173.583229 442.224357 6.591709" $ns_ at 4.000000 "$node_(8) setdest 16.085272 414.253650 5.205734" $ns_ at 4.000000 "$node_(9) setdest 174.174132 410.497488 6.905523" $ns_ at 4.000000 "$node_(10) setdest 152.442894 373.377115 6.329131" $ns_ at 5.000000 "$node_(1) setdest 184.255964 467.324102 4.771939" $ns_ at 5.000000 "$node_(2) setdest 130.096253 384.724742 8.438041" $ns_ at 5.000000 "$node_(3) setdest 13.104636 545.386686 0.450418" $ns_ at 5.000000 "$node_(4) setdest 60.821055 533.607888 6.913933" $ns_ at 5.000000 "$node_(5) setdest 176.727658 522.545813 2.217673" $ns_ at 5.000000 "$node_(6) setdest 109.928718 524.861347 7.429940" $ns_ at 5.000000 "$node_(7) setdest 168.331832 435.943930 8.186631" $ns_ at 5.000000 "$node_(8) setdest 20.338476 419.569962 6.808298" $ns_ at 5.000000 "$node_(9) setdest 166.303912 413.725191 8.506376" $ns_ at 5.000000 "$node_(10) setdest 153.598648 381.217946 7.925553" $ns_ at 6.000000 "$node_(1) setdest 190.713020 468.199291 6.516097" $ns_ at 6.000000 "$node_(2) setdest 140.041968 386.083359 10.038083" $ns_ at 6.000000 "$node_(3) setdest 15.010480 545.397474 1.905875" $ns_ at 6.000000 "$node_(4) setdest 69.199175 531.278561 8.695899" $ns_ at 6.000000 "$node_(5) setdest 180.271997 521.405130 3.723372" $ns_ at 6.000000 "$node_(6) setdest 100.969155 523.987540 9.002072" $ns_ at 6.000000 "$node_(7) setdest 162.840946 427.835646 9.792553" $ns_ at 6.000000 "$node_(8) setdest 24.574187 426.845069 8.418339" $ns_ at 6.000000 "$node_(9) setdest 156.473605 416.105660 10.114424" $ns_ at 6.000000 "$node_(10) setdest 153.809976 390.743972 9.528370" $ns_ at 7.000000 "$node_(1) setdest 198.802940 468.836289 8.114961" $ns_ at 7.000000 "$node_(2) setdest 151.520674 388.001681 11.637897" $ns_ at 7.000000 "$node_(3) setdest 18.516288 545.400428 3.505809" $ns_ at 7.000000 "$node_(4) setdest 79.188417 528.784398 10.295912" $ns_ at 7.000000 "$node_(5) setdest 185.412195 520.020244 5.323489" $ns_ at 7.000000 "$node_(6) setdest 91.080154 520.135759 10.612660" $ns_ at 7.000000 "$node_(7) setdest 157.194066 417.952547 11.382569" $ns_ at 7.000000 "$node_(8) setdest 29.470473 435.584536 10.017580" $ns_ at 7.000000 "$node_(9) setdest 144.909476 418.020989 11.721670" $ns_ at 7.000000 "$node_(10) setdest 154.204220 401.865406 11.128419" $ns_ at 8.000000 "$node_(1) setdest 208.501664 469.415232 9.715988" $ns_ at 8.000000 "$node_(2) setdest 164.443430 390.863715 13.235894" $ns_ at 8.000000 "$node_(3) setdest 23.619197 545.235409 5.105577" $ns_ at 8.000000 "$node_(4) setdest 90.784905 526.131143 11.896146" $ns_ at 8.000000 "$node_(5) setdest 192.096154 518.214428 6.923603" $ns_ at 8.000000 "$node_(6) setdest 80.107574 514.731340 12.231323" $ns_ at 8.000000 "$node_(7) setdest 153.494434 405.549908 12.942672" $ns_ at 8.000000 "$node_(8) setdest 34.279206 446.159167 11.616658" $ns_ at 8.000000 "$node_(9) setdest 131.868827 420.741097 13.321318" $ns_ at 8.000000 "$node_(10) setdest 155.452554 414.535462 12.731405" $ns_ at 9.000000 "$node_(1) setdest 219.760670 470.533402 11.314394" $ns_ at 9.000000 "$node_(2) setdest 178.682089 395.031168 14.836006" $ns_ at 9.000000 "$node_(3) setdest 30.308442 544.767661 6.705579" $ns_ at 9.000000 "$node_(4) setdest 103.964771 523.226201 13.496205" $ns_ at 9.000000 "$node_(5) setdest 200.282657 515.840475 8.523761" $ns_ at 9.000000 "$node_(6) setdest 69.403546 506.039069 13.788828" $ns_ at 9.000000 "$node_(7) setdest 157.365544 391.985292 14.106179" $ns_ at 9.000000 "$node_(8) setdest 38.646714 458.620995 13.205010" $ns_ at 9.000000 "$node_(9) setdest 117.255049 423.747093 14.919736" $ns_ at 9.000000 "$node_(10) setdest 155.850673 428.857711 14.327781" $ns_ at 10.000000 "$node_(1) setdest 232.472738 472.803312 12.913139" $ns_ at 10.000000 "$node_(2) setdest 194.127048 400.653131 16.436339" $ns_ at 10.000000 "$node_(3) setdest 38.581962 544.035935 8.305815" $ns_ at 10.000000 "$node_(4) setdest 118.685377 519.880090 15.096115" $ns_ at 10.000000 "$node_(5) setdest 210.050487 513.181447 10.123286" $ns_ at 10.000000 "$node_(6) setdest 59.302514 494.374293 15.430420" $ns_ at 10.000000 "$node_(7) setdest 169.643190 381.472758 16.163353" $ns_ at 10.000000 "$node_(8) setdest 40.877385 473.255023 14.803063" $ns_ at 10.000000 "$node_(9) setdest 100.860701 425.784585 16.520473" $ns_ at 10.000000 "$node_(10) setdest 154.521863 444.723981 15.921817" $ns_ at 11.000000 "$node_(1) setdest 246.478612 476.598268 14.510900" $ns_ at 11.000000 "$node_(2) setdest 210.951195 407.159256 18.038337" $ns_ at 11.000000 "$node_(3) setdest 48.438708 543.050999 9.905834" $ns_ at 11.000000 "$node_(4) setdest 134.861031 515.746212 16.695530" $ns_ at 11.000000 "$node_(5) setdest 221.527307 510.799257 11.721444" $ns_ at 11.000000 "$node_(6) setdest 49.457411 480.494289 17.017067" $ns_ at 11.000000 "$node_(7) setdest 180.598709 367.456279 17.790028" $ns_ at 11.000000 "$node_(8) setdest 39.538357 489.562934 16.362792" $ns_ at 11.000000 "$node_(9) setdest 83.020566 428.952409 18.119203" $ns_ at 11.000000 "$node_(10) setdest 151.821820 462.044995 17.530195" $ns_ at 12.000000 "$node_(1) setdest 261.629729 482.087033 16.114679" $ns_ at 12.000000 "$node_(2) setdest 229.245871 414.133015 19.578776" $ns_ at 12.000000 "$node_(3) setdest 59.881260 541.845844 11.505842" $ns_ at 12.000000 "$node_(4) setdest 152.423948 510.621388 18.295352" $ns_ at 12.000000 "$node_(5) setdest 234.527040 507.889458 13.321411" $ns_ at 12.000000 "$node_(6) setdest 40.966307 463.915095 18.627091" $ns_ at 12.000000 "$node_(7) setdest 185.609934 356.000078 12.504276" $ns_ at 12.000000 "$node_(8) setdest 30.885561 505.096833 17.781252" $ns_ at 12.000000 "$node_(9) setdest 63.625003 431.905828 19.619138" $ns_ at 12.000000 "$node_(10) setdest 146.050593 480.248923 19.096860" $ns_ at 13.000000 "$node_(1) setdest 278.393127 487.812114 17.714064" $ns_ at 13.000000 "$node_(2) setdest 248.189196 420.533024 19.995242" $ns_ at 13.000000 "$node_(3) setdest 72.938784 540.726815 13.105387" $ns_ at 13.000000 "$node_(4) setdest 171.235204 504.613101 19.747478" $ns_ at 13.000000 "$node_(5) setdest 249.025623 504.352557 14.923758" $ns_ at 13.000000 "$node_(6) setdest 30.880946 446.819434 19.848832" $ns_ at 13.000000 "$node_(7) setdest 184.657559 357.512927 1.787661" $ns_ at 13.000000 "$node_(8) setdest 14.206642 507.144149 16.804101" $ns_ at 13.000000 "$node_(9) setdest 44.005432 428.793757 19.864857" $ns_ at 13.000000 "$node_(10) setdest 132.025204 492.782747 18.809792" $ns_ at 14.000000 "$node_(1) setdest 297.118073 492.525399 19.309031" $ns_ at 14.000000 "$node_(2) setdest 267.609451 425.285611 19.993334" $ns_ at 14.000000 "$node_(3) setdest 87.624368 539.967665 14.705193" $ns_ at 14.000000 "$node_(4) setdest 190.013797 497.736791 19.997979" $ns_ at 14.000000 "$node_(5) setdest 265.067340 500.390654 16.523722" $ns_ at 14.000000 "$node_(6) setdest 22.990420 428.699834 19.763105" $ns_ at 14.000000 "$node_(7) setdest 182.833109 360.375049 3.394165" $ns_ at 14.000000 "$node_(8) setdest 11.626599 492.727976 14.645227" $ns_ at 14.000000 "$node_(9) setdest 26.668091 418.946242 19.938830" $ns_ at 14.000000 "$node_(10) setdest 123.299921 486.526765 10.736287" $ns_ at 15.000000 "$node_(1) setdest 316.902786 495.404161 19.993052" $ns_ at 15.000000 "$node_(2) setdest 287.409944 428.039581 19.991095" $ns_ at 15.000000 "$node_(3) setdest 103.927453 539.724173 16.304903" $ns_ at 15.000000 "$node_(4) setdest 208.447762 489.981073 19.999056" $ns_ at 15.000000 "$node_(5) setdest 282.569771 495.688589 18.123038" $ns_ at 15.000000 "$node_(6) setdest 32.358017 413.328574 18.000764" $ns_ at 15.000000 "$node_(7) setdest 180.522818 364.802409 4.993892" $ns_ at 15.000000 "$node_(8) setdest 17.250049 478.879349 14.946828" $ns_ at 15.000000 "$node_(9) setdest 19.305071 401.972918 18.501562" $ns_ at 15.000000 "$node_(10) setdest 122.308127 476.484801 10.090823" $ns_ at 16.000000 "$node_(1) setdest 336.810376 497.321840 19.999742" $ns_ at 16.000000 "$node_(2) setdest 307.390871 428.541832 19.987239" $ns_ at 16.000000 "$node_(3) setdest 121.831706 539.952811 17.905713" $ns_ at 16.000000 "$node_(4) setdest 227.120033 482.822730 19.997389" $ns_ at 16.000000 "$node_(5) setdest 301.236586 489.579183 19.641151" $ns_ at 16.000000 "$node_(6) setdest 46.948370 420.814042 16.398495" $ns_ at 16.000000 "$node_(7) setdest 177.898557 370.854610 6.596658" $ns_ at 16.000000 "$node_(8) setdest 30.672025 469.903968 16.146420" $ns_ at 16.000000 "$node_(9) setdest 28.762169 396.296220 11.030031" $ns_ at 16.000000 "$node_(10) setdest 119.039643 465.199922 11.748680" $ns_ at 17.000000 "$node_(1) setdest 356.723919 496.365486 19.936494" $ns_ at 17.000000 "$node_(2) setdest 327.327857 427.009656 19.995774" $ns_ at 17.000000 "$node_(3) setdest 141.310307 540.046329 19.478826" $ns_ at 17.000000 "$node_(4) setdest 246.180029 476.772114 19.997335" $ns_ at 17.000000 "$node_(5) setdest 320.056175 482.812486 19.999128" $ns_ at 17.000000 "$node_(6) setdest 50.106366 436.546462 16.046245" $ns_ at 17.000000 "$node_(7) setdest 175.044087 378.536882 8.195444" $ns_ at 17.000000 "$node_(8) setdest 48.497193 467.760705 17.953557" $ns_ at 17.000000 "$node_(9) setdest 38.413556 402.420929 11.430719" $ns_ at 17.000000 "$node_(10) setdest 114.693546 452.584125 13.343422" $ns_ at 18.000000 "$node_(1) setdest 376.664288 496.703412 19.943231" $ns_ at 18.000000 "$node_(2) setdest 346.945189 423.241158 19.976018" $ns_ at 18.000000 "$node_(3) setdest 161.304062 539.571077 19.999402" $ns_ at 18.000000 "$node_(4) setdest 265.558802 471.836704 19.997378" $ns_ at 18.000000 "$node_(5) setdest 338.448532 474.970956 19.994209" $ns_ at 18.000000 "$node_(6) setdest 54.288270 451.088370 15.131272" $ns_ at 18.000000 "$node_(7) setdest 172.073073 387.868710 9.793362" $ns_ at 18.000000 "$node_(8) setdest 67.655050 465.445201 19.297281" $ns_ at 18.000000 "$node_(9) setdest 49.709921 408.850378 12.997910" $ns_ at 18.000000 "$node_(10) setdest 114.878490 437.804560 14.780722" $ns_ at 19.000000 "$node_(1) setdest 396.221169 500.830441 19.987596" $ns_ at 19.000000 "$node_(2) setdest 364.910034 414.653995 19.911680" $ns_ at 19.000000 "$node_(3) setdest 181.265387 538.352550 19.998483" $ns_ at 19.000000 "$node_(4) setdest 285.155517 467.848358 19.998454" $ns_ at 19.000000 "$node_(5) setdest 356.023480 465.435990 19.994859" $ns_ at 19.000000 "$node_(6) setdest 59.822992 466.650093 16.516669" $ns_ at 19.000000 "$node_(7) setdest 170.484709 399.136223 11.378916" $ns_ at 19.000000 "$node_(8) setdest 84.504418 457.452149 18.649130" $ns_ at 19.000000 "$node_(9) setdest 63.410973 414.003103 14.637944" $ns_ at 19.000000 "$node_(10) setdest 124.979075 425.189235 16.160700" $ns_ at 20.000000 "$node_(1) setdest 414.959731 507.703787 19.959373" $ns_ at 20.000000 "$node_(2) setdest 380.876777 402.624609 19.991073" $ns_ at 20.000000 "$node_(3) setdest 201.169537 536.405487 19.999156" $ns_ at 20.000000 "$node_(4) setdest 304.943032 464.963448 19.996711" $ns_ at 20.000000 "$node_(5) setdest 372.787924 454.543588 19.992274" $ns_ at 20.000000 "$node_(6) setdest 70.020001 481.532051 18.040280" $ns_ at 20.000000 "$node_(7) setdest 170.249709 412.128831 12.994733" $ns_ at 20.000000 "$node_(8) setdest 93.638312 442.200433 17.777595" $ns_ at 20.000000 "$node_(9) setdest 78.562641 419.829513 16.233302" $ns_ at 20.000000 "$node_(10) setdest 142.579167 424.108364 17.633250" $ns_ at 21.000000 "$node_(1) setdest 429.209520 521.348596 19.729097" $ns_ at 21.000000 "$node_(2) setdest 397.102346 390.982114 19.970398" $ns_ at 21.000000 "$node_(3) setdest 220.965783 533.570502 19.998213" $ns_ at 21.000000 "$node_(4) setdest 324.852277 463.066604 19.999402" $ns_ at 21.000000 "$node_(5) setdest 388.665021 442.382765 19.999195" $ns_ at 21.000000 "$node_(6) setdest 86.716919 491.602850 19.498924" $ns_ at 21.000000 "$node_(7) setdest 169.847567 426.715435 14.592147" $ns_ at 21.000000 "$node_(8) setdest 97.710618 423.903178 18.744951" $ns_ at 21.000000 "$node_(9) setdest 95.770736 424.404680 17.805917" $ns_ at 21.000000 "$node_(10) setdest 161.156216 426.885868 18.783538" $ns_ at 22.000000 "$node_(1) setdest 430.473009 540.114895 18.808785" $ns_ at 22.000000 "$node_(2) setdest 416.281990 386.251137 19.754515" $ns_ at 22.000000 "$node_(3) setdest 240.636740 529.963240 19.998972" $ns_ at 22.000000 "$node_(4) setdest 344.804967 461.695943 19.999714" $ns_ at 22.000000 "$node_(5) setdest 405.064820 430.950640 19.991171" $ns_ at 22.000000 "$node_(6) setdest 105.990772 495.255793 19.616967" $ns_ at 22.000000 "$node_(7) setdest 167.385262 442.713557 16.186502" $ns_ at 22.000000 "$node_(8) setdest 103.162186 405.249727 19.433755" $ns_ at 22.000000 "$node_(9) setdest 115.163365 425.341594 19.415248" $ns_ at 22.000000 "$node_(10) setdest 179.829755 431.479678 19.230293" $ns_ at 23.000000 "$node_(1) setdest 415.678953 543.404262 15.155331" $ns_ at 23.000000 "$node_(2) setdest 435.187649 392.319327 19.855651" $ns_ at 23.000000 "$node_(3) setdest 260.149758 525.579574 19.999361" $ns_ at 23.000000 "$node_(4) setdest 364.757106 460.319210 19.999581" $ns_ at 23.000000 "$node_(5) setdest 423.001973 422.178788 19.967143" $ns_ at 23.000000 "$node_(6) setdest 123.055577 489.304227 18.072872" $ns_ at 23.000000 "$node_(7) setdest 163.127378 459.989903 17.793305" $ns_ at 23.000000 "$node_(8) setdest 100.668183 387.349777 18.072860" $ns_ at 23.000000 "$node_(9) setdest 134.745751 421.781273 19.903410" $ns_ at 23.000000 "$node_(10) setdest 192.254617 443.561434 17.330494" $ns_ at 24.000000 "$node_(1) setdest 406.160525 540.747525 9.882242" $ns_ at 24.000000 "$node_(2) setdest 449.530999 405.814727 19.694098" $ns_ at 24.000000 "$node_(3) setdest 279.642597 521.105699 19.999658" $ns_ at 24.000000 "$node_(4) setdest 384.596757 457.826144 19.995677" $ns_ at 24.000000 "$node_(5) setdest 442.473674 417.861163 19.944649" $ns_ at 24.000000 "$node_(6) setdest 134.199736 475.485411 17.752521" $ns_ at 24.000000 "$node_(7) setdest 160.485918 479.161017 19.352233" $ns_ at 24.000000 "$node_(8) setdest 89.621312 373.738896 17.529673" $ns_ at 24.000000 "$node_(9) setdest 151.033770 410.479558 19.824942" $ns_ at 24.000000 "$node_(10) setdest 187.121532 459.497919 16.742763" $ns_ at 25.000000 "$node_(1) setdest 409.358404 540.925330 3.202818" $ns_ at 25.000000 "$node_(2) setdest 458.447905 423.373342 19.693049" $ns_ at 25.000000 "$node_(3) setdest 299.300679 517.470033 19.991455" $ns_ at 25.000000 "$node_(4) setdest 404.207394 453.940099 19.991959" $ns_ at 25.000000 "$node_(5) setdest 462.251199 419.968804 19.889511" $ns_ at 25.000000 "$node_(6) setdest 137.331615 457.789340 17.971076" $ns_ at 25.000000 "$node_(7) setdest 163.430534 498.853924 19.911840" $ns_ at 25.000000 "$node_(8) setdest 77.657124 359.369184 18.698407" $ns_ at 25.000000 "$node_(9) setdest 164.260780 395.480602 19.998061" $ns_ at 25.000000 "$node_(10) setdest 184.039441 474.459839 15.276071" $ns_ at 26.000000 "$node_(1) setdest 413.898194 539.190016 4.860144" $ns_ at 26.000000 "$node_(2) setdest 472.249585 436.422368 18.993774" $ns_ at 26.000000 "$node_(3) setdest 319.267001 516.756455 19.979069" $ns_ at 26.000000 "$node_(4) setdest 422.915330 447.007413 19.951166" $ns_ at 26.000000 "$node_(5) setdest 477.938097 430.823097 19.076018" $ns_ at 26.000000 "$node_(6) setdest 140.850027 439.467490 18.656618" $ns_ at 26.000000 "$node_(7) setdest 173.893091 515.708878 19.838210" $ns_ at 26.000000 "$node_(8) setdest 62.077819 360.254769 15.604455" $ns_ at 26.000000 "$node_(9) setdest 179.407140 382.455787 19.976437" $ns_ at 26.000000 "$node_(10) setdest 185.534654 490.826466 16.434784" $ns_ at 27.000000 "$node_(1) setdest 419.345130 535.713495 6.461836" $ns_ at 27.000000 "$node_(2) setdest 485.947996 449.586921 18.998734" $ns_ at 27.000000 "$node_(3) setdest 339.044367 519.533812 19.971427" $ns_ at 27.000000 "$node_(4) setdest 438.826119 435.000710 19.932740" $ns_ at 27.000000 "$node_(5) setdest 473.471267 424.832381 7.472701" $ns_ at 27.000000 "$node_(6) setdest 135.925019 421.904243 18.240706" $ns_ at 27.000000 "$node_(7) setdest 186.435379 531.166580 19.906018" $ns_ at 27.000000 "$node_(8) setdest 57.119411 374.294350 14.889447" $ns_ at 27.000000 "$node_(9) setdest 192.143744 373.866180 15.362370" $ns_ at 27.000000 "$node_(10) setdest 185.569664 508.866862 18.040430" $ns_ at 28.000000 "$node_(1) setdest 425.125458 530.097247 8.059430" $ns_ at 28.000000 "$node_(2) setdest 493.049174 466.718934 18.545421" $ns_ at 28.000000 "$node_(3) setdest 358.303469 524.898542 19.992332" $ns_ at 28.000000 "$node_(4) setdest 450.847143 419.080495 19.948891" $ns_ at 28.000000 "$node_(5) setdest 466.757695 428.118270 7.474565" $ns_ at 28.000000 "$node_(6) setdest 128.600444 404.149699 19.206072" $ns_ at 28.000000 "$node_(7) setdest 190.977325 534.505975 5.637449" $ns_ at 28.000000 "$node_(8) setdest 50.549060 388.112799 15.300949" $ns_ at 28.000000 "$node_(9) setdest 191.629729 374.111864 0.569712" $ns_ at 28.000000 "$node_(10) setdest 181.834449 527.981880 19.476543" $ns_ at 29.000000 "$node_(1) setdest 431.663417 522.972367 9.669997" $ns_ at 29.000000 "$node_(2) setdest 500.999975 483.730217 18.777619" $ns_ at 29.000000 "$node_(3) setdest 378.191935 526.327594 19.939741" $ns_ at 29.000000 "$node_(4) setdest 458.446194 400.622892 19.960678" $ns_ at 29.000000 "$node_(5) setdest 461.699992 435.699961 9.113857" $ns_ at 29.000000 "$node_(6) setdest 122.697249 385.435598 19.623081" $ns_ at 29.000000 "$node_(7) setdest 183.725190 529.813555 8.637839" $ns_ at 29.000000 "$node_(8) setdest 38.920729 400.522858 17.006694" $ns_ at 29.000000 "$node_(9) setdest 190.433575 375.757305 2.034271" $ns_ at 29.000000 "$node_(10) setdest 169.338208 541.367431 18.311990" $ns_ at 30.000000 "$node_(1) setdest 440.262619 515.700706 11.261586" $ns_ at 30.000000 "$node_(2) setdest 500.811238 501.442061 17.712850" $ns_ at 30.000000 "$node_(3) setdest 397.439899 521.321197 19.888392" $ns_ at 30.000000 "$node_(4) setdest 464.984365 381.792314 19.933348" $ns_ at 30.000000 "$node_(5) setdest 458.178246 445.894374 10.785581" $ns_ at 30.000000 "$node_(6) setdest 117.489012 366.365374 19.768641" $ns_ at 30.000000 "$node_(7) setdest 174.343370 525.704745 10.242113" $ns_ at 30.000000 "$node_(8) setdest 24.090640 411.759729 18.606419" $ns_ at 30.000000 "$node_(9) setdest 187.828459 378.293814 3.636002" $ns_ at 30.000000 "$node_(10) setdest 152.821188 535.712898 17.458113" $ns_ at 31.000000 "$node_(1) setdest 451.405438 509.290896 12.854885" $ns_ at 31.000000 "$node_(2) setdest 491.700571 517.036414 18.060678" $ns_ at 31.000000 "$node_(3) setdest 413.171544 509.240492 19.835022" $ns_ at 31.000000 "$node_(4) setdest 480.918024 372.117997 18.640651" $ns_ at 31.000000 "$node_(5) setdest 456.464076 458.133299 12.358384" $ns_ at 31.000000 "$node_(6) setdest 116.659357 360.796271 5.630563" $ns_ at 31.000000 "$node_(7) setdest 164.951174 518.581014 11.788168" $ns_ at 31.000000 "$node_(8) setdest 8.936318 423.738537 19.316970" $ns_ at 31.000000 "$node_(9) setdest 184.393707 382.243473 5.234245" $ns_ at 31.000000 "$node_(10) setdest 139.669561 526.256345 16.198509" $ns_ at 32.000000 "$node_(1) setdest 464.725397 503.658293 14.461934" $ns_ at 32.000000 "$node_(2) setdest 479.083065 531.312050 19.052435" $ns_ at 32.000000 "$node_(3) setdest 421.035268 491.095019 19.776156" $ns_ at 32.000000 "$node_(4) setdest 490.592449 383.745440 15.125870" $ns_ at 32.000000 "$node_(5) setdest 456.762816 472.118321 13.988212" $ns_ at 32.000000 "$node_(6) setdest 116.717596 368.408818 7.612770" $ns_ at 32.000000 "$node_(7) setdest 156.422329 508.202089 13.433662" $ns_ at 32.000000 "$node_(8) setdest 11.745791 420.358995 4.394820" $ns_ at 32.000000 "$node_(9) setdest 180.640795 387.951388 6.831153" $ns_ at 32.000000 "$node_(10) setdest 126.512644 516.165541 16.580976" $ns_ at 33.000000 "$node_(1) setdest 480.312677 499.837211 16.048799" $ns_ at 33.000000 "$node_(2) setdest 464.103605 542.498822 18.695670" $ns_ at 33.000000 "$node_(3) setdest 415.566812 472.559995 19.324884" $ns_ at 33.000000 "$node_(4) setdest 492.444864 398.380771 14.752097" $ns_ at 33.000000 "$node_(5) setdest 454.811405 487.581008 15.585336" $ns_ at 33.000000 "$node_(6) setdest 117.946938 377.618577 9.291444" $ns_ at 33.000000 "$node_(7) setdest 147.983933 495.750139 15.041861" $ns_ at 33.000000 "$node_(8) setdest 16.630884 421.422038 4.999419" $ns_ at 33.000000 "$node_(9) setdest 176.046756 395.024567 8.434160" $ns_ at 33.000000 "$node_(10) setdest 114.664512 502.380973 18.176703" $ns_ at 34.000000 "$node_(1) setdest 497.919072 498.422291 17.663158" $ns_ at 34.000000 "$node_(2) setdest 467.653826 541.046000 3.835981" $ns_ at 34.000000 "$node_(3) setdest 405.186017 464.081358 13.403290" $ns_ at 34.000000 "$node_(4) setdest 490.175129 414.347121 16.126873" $ns_ at 34.000000 "$node_(5) setdest 451.792079 504.480069 17.166671" $ns_ at 34.000000 "$node_(6) setdest 121.883147 387.777476 10.894815" $ns_ at 34.000000 "$node_(7) setdest 138.114893 482.374086 16.622777" $ns_ at 34.000000 "$node_(8) setdest 22.994022 423.191629 6.604618" $ns_ at 34.000000 "$node_(9) setdest 170.044883 403.068060 10.035948" $ns_ at 34.000000 "$node_(10) setdest 107.004140 484.410586 19.534997" $ns_ at 35.000000 "$node_(1) setdest 517.152845 499.275087 19.252670" $ns_ at 35.000000 "$node_(2) setdest 469.760083 536.639542 4.883974" $ns_ at 35.000000 "$node_(3) setdest 406.522026 464.499466 1.399905" $ns_ at 35.000000 "$node_(4) setdest 486.192447 431.664927 17.769867" $ns_ at 35.000000 "$node_(5) setdest 441.963945 520.294525 18.619593" $ns_ at 35.000000 "$node_(6) setdest 124.346991 399.961894 12.431032" $ns_ at 35.000000 "$node_(7) setdest 124.150809 470.712739 18.192929" $ns_ at 35.000000 "$node_(8) setdest 30.684577 426.047417 8.203668" $ns_ at 35.000000 "$node_(9) setdest 162.654904 412.053873 11.634287" $ns_ at 35.000000 "$node_(10) setdest 107.841118 465.759378 18.669978" $ns_ at 36.000000 "$node_(1) setdest 536.528998 504.082029 19.963517" $ns_ at 36.000000 "$node_(2) setdest 474.403635 532.108135 6.488160" $ns_ at 36.000000 "$node_(3) setdest 409.528015 464.468428 3.006149" $ns_ at 36.000000 "$node_(4) setdest 484.427652 450.881008 19.296950" $ns_ at 36.000000 "$node_(5) setdest 426.470273 532.788799 19.903788" $ns_ at 36.000000 "$node_(6) setdest 120.932715 413.505237 13.967084" $ns_ at 36.000000 "$node_(7) setdest 105.532349 464.813463 19.530707" $ns_ at 36.000000 "$node_(8) setdest 39.253080 430.783080 9.790084" $ns_ at 36.000000 "$node_(9) setdest 153.536221 421.645072 13.234104" $ns_ at 36.000000 "$node_(10) setdest 117.666134 450.695452 17.984794" $ns_ at 37.000000 "$node_(1) setdest 554.428542 512.921944 19.963411" $ns_ at 37.000000 "$node_(2) setdest 481.127335 527.610678 8.089206" $ns_ at 37.000000 "$node_(3) setdest 414.102043 465.013680 4.606412" $ns_ at 37.000000 "$node_(4) setdest 489.773407 469.940100 19.794597" $ns_ at 37.000000 "$node_(5) setdest 408.058188 532.100718 18.424937" $ns_ at 37.000000 "$node_(6) setdest 109.012095 423.192684 15.360592" $ns_ at 37.000000 "$node_(7) setdest 85.728992 467.102452 19.935205" $ns_ at 37.000000 "$node_(8) setdest 48.361002 437.630220 11.394629" $ns_ at 37.000000 "$node_(9) setdest 142.102893 431.075459 14.820701" $ns_ at 37.000000 "$node_(10) setdest 131.161133 437.935237 18.572509" $ns_ at 38.000000 "$node_(1) setdest 566.932229 527.655226 19.323866" $ns_ at 38.000000 "$node_(2) setdest 490.148231 524.075412 9.688895" $ns_ at 38.000000 "$node_(3) setdest 420.185075 466.255244 6.208443" $ns_ at 38.000000 "$node_(4) setdest 501.252538 485.927117 19.681340" $ns_ at 38.000000 "$node_(5) setdest 405.981429 521.845202 10.463677" $ns_ at 38.000000 "$node_(6) setdest 91.954174 422.557957 17.069726" $ns_ at 38.000000 "$node_(7) setdest 66.578736 472.830545 19.988581" $ns_ at 38.000000 "$node_(8) setdest 58.379443 445.916629 13.001297" $ns_ at 38.000000 "$node_(9) setdest 128.348746 440.069498 16.433785" $ns_ at 38.000000 "$node_(10) setdest 139.114132 421.205939 18.523488" $ns_ at 39.000000 "$node_(1) setdest 567.143596 529.512240 1.869004" $ns_ at 39.000000 "$node_(2) setdest 501.202329 521.792270 11.287418" $ns_ at 39.000000 "$node_(3) setdest 427.677364 468.446739 7.806218" $ns_ at 39.000000 "$node_(4) setdest 511.141012 502.780491 19.540167" $ns_ at 39.000000 "$node_(5) setdest 413.374406 514.767835 10.234513" $ns_ at 39.000000 "$node_(6) setdest 75.493177 413.507199 18.785117" $ns_ at 39.000000 "$node_(7) setdest 46.764183 471.773954 19.842703" $ns_ at 39.000000 "$node_(8) setdest 69.942011 454.838968 14.604833" $ns_ at 39.000000 "$node_(9) setdest 112.291115 448.251876 18.022176" $ns_ at 39.000000 "$node_(10) setdest 141.846200 402.561193 18.843852" $ns_ at 40.000000 "$node_(1) setdest 564.578377 527.996748 2.979440" $ns_ at 40.000000 "$node_(2) setdest 514.059687 520.805131 12.895197" $ns_ at 40.000000 "$node_(3) setdest 436.538030 471.609166 9.408100" $ns_ at 40.000000 "$node_(4) setdest 519.473141 520.208352 19.317213" $ns_ at 40.000000 "$node_(5) setdest 419.858457 504.879506 11.824634" $ns_ at 40.000000 "$node_(6) setdest 87.235668 420.830481 13.838951" $ns_ at 40.000000 "$node_(7) setdest 64.203274 476.552061 18.081820" $ns_ at 40.000000 "$node_(8) setdest 84.829204 454.481993 14.891472" $ns_ at 40.000000 "$node_(9) setdest 125.059425 443.474044 13.632954" $ns_ at 40.000000 "$node_(10) setdest 148.729503 397.886383 8.320679" $ns_ at 41.000000 "$node_(1) setdest 560.539286 525.794333 4.600531" $ns_ at 41.000000 "$node_(2) setdest 528.559240 520.724740 14.499776" $ns_ at 41.000000 "$node_(3) setdest 446.636223 475.986259 11.006019" $ns_ at 41.000000 "$node_(4) setdest 526.125692 538.415388 19.384339" $ns_ at 41.000000 "$node_(5) setdest 424.189640 492.212788 13.386743" $ns_ at 41.000000 "$node_(6) setdest 102.775617 424.456016 15.957271" $ns_ at 41.000000 "$node_(7) setdest 83.933552 478.414079 19.817945" $ns_ at 41.000000 "$node_(8) setdest 101.442514 452.999884 16.679290" $ns_ at 41.000000 "$node_(9) setdest 140.551926 441.300742 15.644194" $ns_ at 41.000000 "$node_(10) setdest 158.699125 396.791989 10.029510" $ns_ at 42.000000 "$node_(1) setdest 554.946328 523.113767 6.202145" $ns_ at 42.000000 "$node_(2) setdest 544.648492 520.084739 16.101976" $ns_ at 42.000000 "$node_(3) setdest 457.867768 481.716252 12.608743" $ns_ at 42.000000 "$node_(4) setdest 542.996006 542.160589 17.281030" $ns_ at 42.000000 "$node_(5) setdest 427.836410 477.619041 15.042485" $ns_ at 42.000000 "$node_(6) setdest 120.073180 427.461833 17.556783" $ns_ at 42.000000 "$node_(7) setdest 103.908927 479.371110 19.998288" $ns_ at 42.000000 "$node_(8) setdest 119.693903 451.998492 18.278840" $ns_ at 42.000000 "$node_(9) setdest 157.508841 438.167173 17.244020" $ns_ at 42.000000 "$node_(10) setdest 170.268449 395.614996 11.629039" $ns_ at 43.000000 "$node_(1) setdest 548.011229 519.540767 7.801405" $ns_ at 43.000000 "$node_(2) setdest 559.640611 513.386833 16.420280" $ns_ at 43.000000 "$node_(3) setdest 470.540438 488.142494 14.208911" $ns_ at 43.000000 "$node_(4) setdest 557.442321 534.605141 16.302785" $ns_ at 43.000000 "$node_(5) setdest 432.038134 461.515754 16.642426" $ns_ at 43.000000 "$node_(6) setdest 139.110535 429.593024 19.156274" $ns_ at 43.000000 "$node_(7) setdest 123.907121 479.374828 19.998194" $ns_ at 43.000000 "$node_(8) setdest 139.427933 451.544210 19.739258" $ns_ at 43.000000 "$node_(9) setdest 176.047394 434.787992 18.844013" $ns_ at 43.000000 "$node_(10) setdest 183.465605 394.695269 13.229166" $ns_ at 44.000000 "$node_(1) setdest 540.245181 514.250782 9.396566" $ns_ at 44.000000 "$node_(2) setdest 557.197334 501.679640 11.959430" $ns_ at 44.000000 "$node_(3) setdest 484.194340 496.104414 15.805733" $ns_ at 44.000000 "$node_(4) setdest 569.805764 524.976564 15.670489" $ns_ at 44.000000 "$node_(5) setdest 437.187949 444.017164 18.240648" $ns_ at 44.000000 "$node_(6) setdest 159.082551 430.599768 19.997374" $ns_ at 44.000000 "$node_(7) setdest 143.880972 478.393510 19.997942" $ns_ at 44.000000 "$node_(8) setdest 159.427822 451.554805 19.999892" $ns_ at 44.000000 "$node_(9) setdest 195.825003 432.098619 19.959623" $ns_ at 44.000000 "$node_(10) setdest 198.232049 393.331915 14.829248" $ns_ at 45.000000 "$node_(1) setdest 531.522089 507.546145 11.002022" $ns_ at 45.000000 "$node_(2) setdest 547.805553 492.435892 13.177725" $ns_ at 45.000000 "$node_(3) setdest 499.562490 504.256506 17.396455" $ns_ at 45.000000 "$node_(4) setdest 586.131716 520.450839 16.941632" $ns_ at 45.000000 "$node_(5) setdest 444.245357 425.600998 19.722124" $ns_ at 45.000000 "$node_(6) setdest 179.081213 430.697528 19.998900" $ns_ at 45.000000 "$node_(7) setdest 163.775015 476.359693 19.997735" $ns_ at 45.000000 "$node_(8) setdest 179.427632 451.479451 19.999952" $ns_ at 45.000000 "$node_(9) setdest 215.744509 430.326634 19.998166" $ns_ at 45.000000 "$node_(10) setdest 214.511122 391.127338 16.427671" $ns_ at 46.000000 "$node_(1) setdest 521.224593 500.285353 12.599902" $ns_ at 46.000000 "$node_(2) setdest 537.140911 482.188971 14.789658" $ns_ at 46.000000 "$node_(3) setdest 517.239989 511.230267 19.003350" $ns_ at 46.000000 "$node_(4) setdest 596.737679 531.230366 15.122323" $ns_ at 46.000000 "$node_(5) setdest 450.567683 406.626744 19.999853" $ns_ at 46.000000 "$node_(6) setdest 199.077088 430.293213 19.999963" $ns_ at 46.000000 "$node_(7) setdest 183.547456 473.359299 19.998794" $ns_ at 46.000000 "$node_(8) setdest 199.426772 451.293967 19.999999" $ns_ at 46.000000 "$node_(9) setdest 235.727172 429.545275 19.997933" $ns_ at 46.000000 "$node_(10) setdest 232.313482 388.287908 18.027380" $ns_ at 47.000000 "$node_(1) setdest 509.132728 492.839445 14.200519" $ns_ at 47.000000 "$node_(2) setdest 529.956513 467.566241 16.292323" $ns_ at 47.000000 "$node_(3) setdest 530.443547 512.706866 13.285868" $ns_ at 47.000000 "$node_(4) setdest 593.888061 544.610217 13.679939" $ns_ at 47.000000 "$node_(5) setdest 455.365546 387.217155 19.993791" $ns_ at 47.000000 "$node_(6) setdest 219.066969 429.662345 19.999833" $ns_ at 47.000000 "$node_(7) setdest 203.164862 469.479130 19.997458" $ns_ at 47.000000 "$node_(8) setdest 219.417361 451.789967 19.996742" $ns_ at 47.000000 "$node_(9) setdest 255.709496 428.728816 19.998997" $ns_ at 47.000000 "$node_(10) setdest 251.796297 386.439234 19.570326" $ns_ at 48.000000 "$node_(1) setdest 494.811654 486.211110 15.780621" $ns_ at 48.000000 "$node_(2) setdest 523.405915 450.824130 17.978004" $ns_ at 48.000000 "$node_(3) setdest 527.369831 511.982215 3.157982" $ns_ at 48.000000 "$node_(4) setdest 596.143329 540.896760 4.344652" $ns_ at 48.000000 "$node_(5) setdest 452.127739 368.087344 19.401882" $ns_ at 48.000000 "$node_(6) setdest 239.040183 428.633694 19.999686" $ns_ at 48.000000 "$node_(7) setdest 222.507492 464.407083 19.996575" $ns_ at 48.000000 "$node_(8) setdest 239.319828 453.699710 19.993882" $ns_ at 48.000000 "$node_(9) setdest 275.658454 427.303064 19.999843" $ns_ at 48.000000 "$node_(10) setdest 271.767272 385.393628 19.998328" $ns_ at 49.000000 "$node_(1) setdest 477.936814 482.029186 17.385301" $ns_ at 49.000000 "$node_(2) setdest 511.589591 435.283606 19.522638" $ns_ at 49.000000 "$node_(3) setdest 522.811495 510.411820 4.821262" $ns_ at 49.000000 "$node_(4) setdest 596.364469 534.992612 5.908287" $ns_ at 49.000000 "$node_(5) setdest 441.999585 365.539662 10.443668" $ns_ at 49.000000 "$node_(6) setdest 259.000403 427.373742 19.999946" $ns_ at 49.000000 "$node_(7) setdest 241.427668 457.938519 19.995384" $ns_ at 49.000000 "$node_(8) setdest 258.949550 457.488811 19.992080" $ns_ at 49.000000 "$node_(9) setdest 295.601472 425.794473 19.999995" $ns_ at 49.000000 "$node_(10) setdest 291.764641 385.099501 19.999532" $ns_ at 50.000000 "$node_(1) setdest 460.251786 475.213570 18.952911" $ns_ at 50.000000 "$node_(2) setdest 494.572859 425.450831 19.653312" $ns_ at 50.000000 "$node_(3) setdest 516.437962 509.551212 6.431374" $ns_ at 50.000000 "$node_(4) setdest 595.905073 527.487889 7.518771" $ns_ at 50.000000 "$node_(5) setdest 435.704871 370.756310 8.175380" $ns_ at 50.000000 "$node_(6) setdest 278.984020 426.603522 19.998455" $ns_ at 50.000000 "$node_(7) setdest 259.940900 450.373613 19.999189" $ns_ at 50.000000 "$node_(8) setdest 278.151718 463.062180 19.994642" $ns_ at 50.000000 "$node_(9) setdest 315.561187 424.532692 19.999558" $ns_ at 50.000000 "$node_(10) setdest 311.760339 384.687257 19.999947" $ns_ at 51.000000 "$node_(1) setdest 445.750485 461.773203 19.771980" $ns_ at 51.000000 "$node_(2) setdest 477.062237 431.160008 18.417833" $ns_ at 51.000000 "$node_(3) setdest 508.417207 509.293695 8.024888" $ns_ at 51.000000 "$node_(4) setdest 596.138322 518.372789 9.118084" $ns_ at 51.000000 "$node_(5) setdest 427.847555 376.601237 9.792885" $ns_ at 51.000000 "$node_(6) setdest 298.977580 426.115506 19.999515" $ns_ at 51.000000 "$node_(7) setdest 278.425975 442.746479 19.996779" $ns_ at 51.000000 "$node_(8) setdest 297.021088 469.690556 19.999713" $ns_ at 51.000000 "$node_(9) setdest 335.550946 423.983930 19.997290" $ns_ at 51.000000 "$node_(10) setdest 331.755079 384.949165 19.996455" $ns_ at 52.000000 "$node_(1) setdest 440.756113 442.613683 19.799772" $ns_ at 52.000000 "$node_(2) setdest 463.491729 442.499863 17.684767" $ns_ at 52.000000 "$node_(3) setdest 498.797256 509.801163 9.633327" $ns_ at 52.000000 "$node_(4) setdest 595.872849 507.661271 10.714807" $ns_ at 52.000000 "$node_(5) setdest 421.543150 385.787102 11.141168" $ns_ at 52.000000 "$node_(6) setdest 318.966418 425.467482 19.999339" $ns_ at 52.000000 "$node_(7) setdest 297.432455 436.535728 19.995493" $ns_ at 52.000000 "$node_(8) setdest 316.154504 475.504807 19.997327" $ns_ at 52.000000 "$node_(9) setdest 355.519975 424.976200 19.993668" $ns_ at 52.000000 "$node_(10) setdest 351.681172 386.619992 19.996020" $ns_ at 53.000000 "$node_(1) setdest 439.775796 422.648723 19.989013" $ns_ at 53.000000 "$node_(2) setdest 454.163430 457.931863 18.032299" $ns_ at 53.000000 "$node_(3) setdest 487.566288 509.968935 11.232221" $ns_ at 53.000000 "$node_(4) setdest 593.366650 495.626354 12.293098" $ns_ at 53.000000 "$node_(5) setdest 426.618346 394.729658 10.282360" $ns_ at 53.000000 "$node_(6) setdest 338.963772 425.552181 19.997533" $ns_ at 53.000000 "$node_(7) setdest 316.854629 431.777866 19.996452" $ns_ at 53.000000 "$node_(8) setdest 335.626595 480.039122 19.993058" $ns_ at 53.000000 "$node_(9) setdest 375.323130 427.689354 19.988150" $ns_ at 53.000000 "$node_(10) setdest 371.379909 390.033338 19.992278" $ns_ at 54.000000 "$node_(1) setdest 445.215882 403.632184 19.779365" $ns_ at 54.000000 "$node_(2) setdest 454.059564 475.725275 17.793715" $ns_ at 54.000000 "$node_(3) setdest 474.763417 509.199397 12.825977" $ns_ at 54.000000 "$node_(4) setdest 586.634251 483.521630 13.850977" $ns_ at 54.000000 "$node_(5) setdest 434.740699 390.416312 9.196607" $ns_ at 54.000000 "$node_(6) setdest 358.922646 426.804947 19.998152" $ns_ at 54.000000 "$node_(7) setdest 336.584130 428.536703 19.993958" $ns_ at 54.000000 "$node_(8) setdest 355.462297 482.552656 19.994323" $ns_ at 54.000000 "$node_(9) setdest 394.479217 433.330580 19.969455" $ns_ at 54.000000 "$node_(10) setdest 390.644077 395.375055 19.991051" $ns_ at 55.000000 "$node_(1) setdest 453.489395 385.467485 19.960143" $ns_ at 55.000000 "$node_(2) setdest 462.180023 491.875553 18.076873" $ns_ at 55.000000 "$node_(3) setdest 460.781091 505.762029 14.398644" $ns_ at 55.000000 "$node_(4) setdest 575.183381 473.135665 15.459324" $ns_ at 55.000000 "$node_(5) setdest 443.385083 383.339482 11.171700" $ns_ at 55.000000 "$node_(6) setdest 378.818295 428.840950 19.999553" $ns_ at 55.000000 "$node_(7) setdest 356.438978 426.133796 19.999724" $ns_ at 55.000000 "$node_(8) setdest 375.442154 483.043104 19.985875" $ns_ at 55.000000 "$node_(9) setdest 411.603795 443.510768 19.922032" $ns_ at 55.000000 "$node_(10) setdest 409.167270 402.886591 19.988293" $ns_ at 56.000000 "$node_(1) setdest 459.358776 366.350314 19.997896" $ns_ at 56.000000 "$node_(2) setdest 474.439207 506.513884 19.093672" $ns_ at 56.000000 "$node_(3) setdest 448.331346 496.551801 15.486266" $ns_ at 56.000000 "$node_(4) setdest 559.796949 465.725065 17.078034" $ns_ at 56.000000 "$node_(5) setdest 453.233562 375.205933 12.772907" $ns_ at 56.000000 "$node_(6) setdest 398.640054 431.491358 19.998170" $ns_ at 56.000000 "$node_(7) setdest 376.341269 424.293425 19.987200" $ns_ at 56.000000 "$node_(8) setdest 395.289271 480.727854 19.981702" $ns_ at 56.000000 "$node_(9) setdest 424.686463 458.541108 19.926549" $ns_ at 56.000000 "$node_(10) setdest 426.588462 412.682524 19.986450" $ns_ at 57.000000 "$node_(1) setdest 474.147494 357.589355 17.188968" $ns_ at 57.000000 "$node_(2) setdest 487.397435 521.211648 19.594386" $ns_ at 57.000000 "$node_(3) setdest 449.175044 489.763733 6.840299" $ns_ at 57.000000 "$node_(4) setdest 541.945847 460.100331 18.716289" $ns_ at 57.000000 "$node_(5) setdest 461.910819 364.190126 14.022938" $ns_ at 57.000000 "$node_(6) setdest 418.176323 435.711193 19.986816" $ns_ at 57.000000 "$node_(7) setdest 395.624998 428.517124 19.740868" $ns_ at 57.000000 "$node_(8) setdest 414.491546 475.216368 19.977584" $ns_ at 57.000000 "$node_(9) setdest 432.332273 476.914703 19.900939" $ns_ at 57.000000 "$node_(10) setdest 442.302058 425.016869 19.976315" $ns_ at 58.000000 "$node_(1) setdest 481.754901 367.368742 12.389877" $ns_ at 58.000000 "$node_(2) setdest 501.253150 535.247087 19.722434" $ns_ at 58.000000 "$node_(3) setdest 452.555239 490.811571 3.538882" $ns_ at 58.000000 "$node_(4) setdest 523.200618 453.356899 19.921282" $ns_ at 58.000000 "$node_(5) setdest 462.037992 362.225513 1.968725" $ns_ at 58.000000 "$node_(6) setdest 436.692511 443.161055 19.958699" $ns_ at 58.000000 "$node_(7) setdest 407.232993 444.170234 19.487570" $ns_ at 58.000000 "$node_(8) setdest 432.402128 466.376774 19.973166" $ns_ at 58.000000 "$node_(9) setdest 433.371712 496.829333 19.941738" $ns_ at 58.000000 "$node_(10) setdest 455.460442 440.041839 19.972301" $ns_ at 59.000000 "$node_(1) setdest 490.840101 378.013714 13.994866" $ns_ at 59.000000 "$node_(2) setdest 517.254096 544.656606 18.562578" $ns_ at 59.000000 "$node_(3) setdest 456.805761 493.906270 5.257765" $ns_ at 59.000000 "$node_(4) setdest 505.296597 444.480311 19.983688" $ns_ at 59.000000 "$node_(5) setdest 459.985759 364.047842 2.744548" $ns_ at 59.000000 "$node_(6) setdest 452.558464 455.227354 19.932988" $ns_ at 59.000000 "$node_(7) setdest 405.781902 462.093611 17.982022" $ns_ at 59.000000 "$node_(8) setdest 448.131072 454.084488 19.962465" $ns_ at 59.000000 "$node_(9) setdest 431.643951 516.751552 19.996999" $ns_ at 59.000000 "$node_(10) setdest 465.450760 457.326282 19.963928" $ns_ at 60.000000 "$node_(1) setdest 498.659527 391.489267 15.579922" $ns_ at 60.000000 "$node_(2) setdest 534.755136 543.334674 17.550895" $ns_ at 60.000000 "$node_(3) setdest 462.401977 497.870630 6.858118" $ns_ at 60.000000 "$node_(4) setdest 488.791604 433.220713 19.979823" $ns_ at 60.000000 "$node_(5) setdest 456.842494 367.045729 4.343667" $ns_ at 60.000000 "$node_(6) setdest 465.331500 470.591333 19.980047" $ns_ at 60.000000 "$node_(7) setdest 408.815556 476.318798 14.545068" $ns_ at 60.000000 "$node_(8) setdest 460.493008 438.434407 19.943483" $ns_ at 60.000000 "$node_(9) setdest 438.396275 534.407383 18.902969" $ns_ at 60.000000 "$node_(10) setdest 472.292912 476.109195 19.990319" $ns_ at 61.000000 "$node_(1) setdest 506.422494 406.848972 17.210003" $ns_ at 61.000000 "$node_(2) setdest 550.122906 534.408750 17.771901" $ns_ at 61.000000 "$node_(3) setdest 469.441169 502.553605 8.454613" $ns_ at 61.000000 "$node_(4) setdest 473.810761 419.970774 19.999664" $ns_ at 61.000000 "$node_(5) setdest 452.869841 371.468100 5.944690" $ns_ at 61.000000 "$node_(6) setdest 475.369253 487.873233 19.985509" $ns_ at 61.000000 "$node_(7) setdest 420.177106 474.634595 11.485703" $ns_ at 61.000000 "$node_(8) setdest 468.519800 420.146652 19.971764" $ns_ at 61.000000 "$node_(9) setdest 456.064353 537.336055 17.909162" $ns_ at 61.000000 "$node_(10) setdest 480.398446 494.324173 19.937028" $ns_ at 62.000000 "$node_(1) setdest 514.243671 423.949759 18.804460" $ns_ at 62.000000 "$node_(2) setdest 558.597008 518.822165 17.741252" $ns_ at 62.000000 "$node_(3) setdest 478.289486 507.332608 10.056420" $ns_ at 62.000000 "$node_(4) setdest 459.228341 406.299144 19.989007" $ns_ at 62.000000 "$node_(5) setdest 448.065246 377.284900 7.544488" $ns_ at 62.000000 "$node_(6) setdest 483.292150 506.217705 19.982291" $ns_ at 62.000000 "$node_(7) setdest 431.806592 467.919195 13.429130" $ns_ at 62.000000 "$node_(8) setdest 473.157337 400.709492 19.982741" $ns_ at 62.000000 "$node_(9) setdest 471.569985 531.759731 16.477864" $ns_ at 62.000000 "$node_(10) setdest 493.533931 509.329068 19.942113" $ns_ at 63.000000 "$node_(1) setdest 526.606177 439.546625 19.902105" $ns_ at 63.000000 "$node_(2) setdest 563.865355 500.625921 18.943568" $ns_ at 63.000000 "$node_(3) setdest 488.865584 512.231308 11.655519" $ns_ at 63.000000 "$node_(4) setdest 443.896167 393.463964 19.995435" $ns_ at 63.000000 "$node_(5) setdest 443.134296 384.956898 9.119968" $ns_ at 63.000000 "$node_(6) setdest 483.704532 525.909424 19.696036" $ns_ at 63.000000 "$node_(7) setdest 441.488756 456.383377 15.060524" $ns_ at 63.000000 "$node_(8) setdest 471.609423 381.023538 19.746717" $ns_ at 63.000000 "$node_(9) setdest 484.411309 520.929706 16.798483" $ns_ at 63.000000 "$node_(10) setdest 509.195143 521.746549 19.986681" $ns_ at 64.000000 "$node_(1) setdest 540.433816 453.956062 19.970865" $ns_ at 64.000000 "$node_(2) setdest 568.124533 481.658093 19.440142" $ns_ at 64.000000 "$node_(3) setdest 501.350038 516.664198 13.248098" $ns_ at 64.000000 "$node_(4) setdest 433.455434 376.647829 19.793718" $ns_ at 64.000000 "$node_(5) setdest 440.254466 395.258128 10.696204" $ns_ at 64.000000 "$node_(6) setdest 469.652755 537.742107 18.370216" $ns_ at 64.000000 "$node_(7) setdest 449.511886 441.764181 16.676076" $ns_ at 64.000000 "$node_(8) setdest 457.550576 367.766860 19.323320" $ns_ at 64.000000 "$node_(9) setdest 498.202162 508.754862 18.396045" $ns_ at 64.000000 "$node_(10) setdest 527.839755 528.576108 19.856093" $ns_ at 65.000000 "$node_(1) setdest 536.004799 446.599409 8.586997" $ns_ at 65.000000 "$node_(2) setdest 564.983309 461.913673 19.992735" $ns_ at 65.000000 "$node_(3) setdest 500.747238 516.306833 0.700769" $ns_ at 65.000000 "$node_(4) setdest 438.545894 357.691580 19.627842" $ns_ at 65.000000 "$node_(5) setdest 441.586829 385.431591 9.916452" $ns_ at 65.000000 "$node_(6) setdest 457.118274 526.488725 16.844935" $ns_ at 65.000000 "$node_(7) setdest 457.806607 425.470338 18.283646" $ns_ at 65.000000 "$node_(8) setdest 439.123220 364.402269 18.732003" $ns_ at 65.000000 "$node_(9) setdest 510.416367 493.167415 19.802912" $ns_ at 65.000000 "$node_(10) setdest 547.813104 529.300629 19.986485" $ns_ at 66.000000 "$node_(1) setdest 535.511187 436.310624 10.300619" $ns_ at 66.000000 "$node_(2) setdest 562.492130 442.069901 19.999531" $ns_ at 66.000000 "$node_(3) setdest 500.517193 514.277017 2.042810" $ns_ at 66.000000 "$node_(4) setdest 445.642038 338.993091 19.999719" $ns_ at 66.000000 "$node_(5) setdest 444.691682 374.116179 11.733655" $ns_ at 66.000000 "$node_(6) setdest 455.508240 510.110942 16.456730" $ns_ at 66.000000 "$node_(7) setdest 468.428808 408.858654 19.717485" $ns_ at 66.000000 "$node_(8) setdest 419.931073 364.342807 19.192239" $ns_ at 66.000000 "$node_(9) setdest 524.816169 479.714481 19.706235" $ns_ at 66.000000 "$node_(10) setdest 567.683020 530.920241 19.935814" $ns_ at 67.000000 "$node_(1) setdest 534.977282 424.421906 11.900701" $ns_ at 67.000000 "$node_(2) setdest 560.569724 422.162987 19.999522" $ns_ at 67.000000 "$node_(3) setdest 500.250852 510.644079 3.642688" $ns_ at 67.000000 "$node_(4) setdest 452.955902 320.378413 19.999972" $ns_ at 67.000000 "$node_(5) setdest 448.073535 361.217857 13.334303" $ns_ at 67.000000 "$node_(6) setdest 451.399100 495.313815 15.357083" $ns_ at 67.000000 "$node_(7) setdest 481.733772 393.932468 19.995327" $ns_ at 67.000000 "$node_(8) setdest 408.322022 365.329378 11.650896" $ns_ at 67.000000 "$node_(9) setdest 539.158447 466.290889 19.644179" $ns_ at 67.000000 "$node_(10) setdest 586.678542 530.162271 19.010638" $ns_ at 68.000000 "$node_(1) setdest 534.442950 410.931909 13.500575" $ns_ at 68.000000 "$node_(2) setdest 558.901130 402.232965 19.999749" $ns_ at 68.000000 "$node_(3) setdest 500.103546 505.403612 5.242537" $ns_ at 68.000000 "$node_(4) setdest 460.080618 301.691006 19.999519" $ns_ at 68.000000 "$node_(5) setdest 452.196525 346.864412 14.933869" $ns_ at 68.000000 "$node_(6) setdest 438.416880 485.903560 16.034056" $ns_ at 68.000000 "$node_(7) setdest 492.545093 377.214664 19.909034" $ns_ at 68.000000 "$node_(8) setdest 416.839668 364.609333 8.548026" $ns_ at 68.000000 "$node_(9) setdest 555.040544 454.694707 19.665006" $ns_ at 68.000000 "$node_(10) setdest 586.825175 529.031950 1.139792" $ns_ at 69.000000 "$node_(1) setdest 534.282344 395.832941 15.099822" $ns_ at 69.000000 "$node_(2) setdest 557.329589 382.294855 19.999950" $ns_ at 69.000000 "$node_(3) setdest 500.199783 498.561725 6.842563" $ns_ at 69.000000 "$node_(4) setdest 466.364502 282.705492 19.998423" $ns_ at 69.000000 "$node_(5) setdest 457.330300 331.148052 16.533591" $ns_ at 69.000000 "$node_(6) setdest 422.274174 478.513804 17.753744" $ns_ at 69.000000 "$node_(7) setdest 503.862909 361.836359 19.094115" $ns_ at 69.000000 "$node_(8) setdest 427.020554 367.160258 10.495602" $ns_ at 69.000000 "$node_(9) setdest 571.735283 444.352269 19.638745" $ns_ at 69.000000 "$node_(10) setdest 585.455531 526.966140 2.478608" $ns_ at 70.000000 "$node_(1) setdest 534.838474 379.142686 16.699517" $ns_ at 70.000000 "$node_(2) setdest 555.525020 362.376742 19.999692" $ns_ at 70.000000 "$node_(3) setdest 500.519465 490.124854 8.442926" $ns_ at 70.000000 "$node_(4) setdest 471.472022 263.373599 19.995221" $ns_ at 70.000000 "$node_(5) setdest 463.120393 313.962864 18.134383" $ns_ at 70.000000 "$node_(6) setdest 408.213514 466.311334 18.617262" $ns_ at 70.000000 "$node_(7) setdest 507.696506 363.297112 4.102471" $ns_ at 70.000000 "$node_(8) setdest 439.013807 368.678079 12.088916" $ns_ at 70.000000 "$node_(9) setdest 589.464572 437.178961 19.125482" $ns_ at 70.000000 "$node_(10) setdest 583.204839 523.564669 4.078679" $ns_ at 71.000000 "$node_(1) setdest 536.112282 360.887514 18.299561" $ns_ at 71.000000 "$node_(2) setdest 553.523133 342.477773 19.999413" $ns_ at 71.000000 "$node_(3) setdest 501.048110 480.096108 10.042669" $ns_ at 71.000000 "$node_(4) setdest 475.511485 243.786853 19.998948" $ns_ at 71.000000 "$node_(5) setdest 469.394485 295.340571 19.650802" $ns_ at 71.000000 "$node_(6) setdest 409.735707 449.316228 17.063139" $ns_ at 71.000000 "$node_(7) setdest 509.753088 368.161673 5.281428" $ns_ at 71.000000 "$node_(8) setdest 452.539013 366.922685 13.638644" $ns_ at 71.000000 "$node_(9) setdest 593.411094 420.224329 17.407888" $ns_ at 71.000000 "$node_(10) setdest 580.200954 518.748793 5.675913" $ns_ at 72.000000 "$node_(1) setdest 538.243058 341.252788 19.750004" $ns_ at 72.000000 "$node_(2) setdest 552.067476 322.531052 19.999766" $ns_ at 72.000000 "$node_(3) setdest 502.043198 468.496468 11.642244" $ns_ at 72.000000 "$node_(4) setdest 478.483272 224.011916 19.996990" $ns_ at 72.000000 "$node_(5) setdest 475.540955 276.308901 19.999589" $ns_ at 72.000000 "$node_(6) setdest 417.775607 434.844392 16.555181" $ns_ at 72.000000 "$node_(7) setdest 510.902737 374.952179 6.887138" $ns_ at 72.000000 "$node_(8) setdest 467.088300 362.216077 15.291629" $ns_ at 72.000000 "$node_(9) setdest 588.386379 404.792399 16.229363" $ns_ at 72.000000 "$node_(10) setdest 576.937804 512.244383 7.277053" $ns_ at 73.000000 "$node_(1) setdest 540.337760 321.362851 19.999934" $ns_ at 73.000000 "$node_(2) setdest 550.508182 302.593413 19.998521" $ns_ at 73.000000 "$node_(3) setdest 503.738640 455.363500 13.241955" $ns_ at 73.000000 "$node_(4) setdest 480.607929 204.125582 19.999511" $ns_ at 73.000000 "$node_(5) setdest 482.491192 257.559586 19.996064" $ns_ at 73.000000 "$node_(6) setdest 424.060892 418.184577 17.806018" $ns_ at 73.000000 "$node_(7) setdest 511.222289 383.432144 8.485983" $ns_ at 73.000000 "$node_(8) setdest 483.575039 358.506602 16.898898" $ns_ at 73.000000 "$node_(9) setdest 581.016072 390.553508 16.033323" $ns_ at 73.000000 "$node_(10) setdest 573.633501 504.005362 8.876930" $ns_ at 74.000000 "$node_(1) setdest 542.640833 301.496124 19.999775" $ns_ at 74.000000 "$node_(2) setdest 547.211487 282.875900 19.991211" $ns_ at 74.000000 "$node_(3) setdest 506.228546 440.731667 14.842176" $ns_ at 74.000000 "$node_(4) setdest 483.949062 184.414401 19.992345" $ns_ at 74.000000 "$node_(5) setdest 490.772371 239.358717 19.996239" $ns_ at 74.000000 "$node_(6) setdest 428.971719 399.458697 19.359101" $ns_ at 74.000000 "$node_(7) setdest 510.977845 393.521870 10.092687" $ns_ at 74.000000 "$node_(8) setdest 501.649850 360.807649 18.220692" $ns_ at 74.000000 "$node_(9) setdest 574.169947 374.218269 17.711845" $ns_ at 74.000000 "$node_(10) setdest 569.666315 494.308359 10.477138" $ns_ at 75.000000 "$node_(1) setdest 545.286982 281.676690 19.995301" $ns_ at 75.000000 "$node_(2) setdest 541.579801 263.698851 19.986873" $ns_ at 75.000000 "$node_(3) setdest 509.521933 424.622555 16.442319" $ns_ at 75.000000 "$node_(4) setdest 489.316472 165.158057 19.990394" $ns_ at 75.000000 "$node_(5) setdest 499.170013 221.211394 19.996143" $ns_ at 75.000000 "$node_(6) setdest 433.995690 380.248856 19.855938" $ns_ at 75.000000 "$node_(7) setdest 509.830491 405.143663 11.678292" $ns_ at 75.000000 "$node_(8) setdest 514.956828 375.067165 19.504088" $ns_ at 75.000000 "$node_(9) setdest 563.225009 358.537277 19.122897" $ns_ at 75.000000 "$node_(10) setdest 564.059199 483.616863 12.072607" $ns_ at 76.000000 "$node_(1) setdest 550.377288 262.356101 19.979900" $ns_ at 76.000000 "$node_(2) setdest 533.540653 245.403103 19.984051" $ns_ at 76.000000 "$node_(3) setdest 513.154562 406.949557 18.042473" $ns_ at 76.000000 "$node_(4) setdest 496.890661 146.658823 19.989748" $ns_ at 76.000000 "$node_(5) setdest 507.041942 202.829163 19.996842" $ns_ at 76.000000 "$node_(6) setdest 441.406995 362.103882 19.600192" $ns_ at 76.000000 "$node_(7) setdest 506.263148 417.944045 13.288180" $ns_ at 76.000000 "$node_(8) setdest 523.622151 393.089514 19.997322" $ns_ at 76.000000 "$node_(9) setdest 562.694870 356.369564 2.231598" $ns_ at 76.000000 "$node_(10) setdest 556.855146 471.989381 13.678331" $ns_ at 77.000000 "$node_(1) setdest 559.088417 244.398391 19.959036" $ns_ at 77.000000 "$node_(2) setdest 521.840951 229.244414 19.949593" $ns_ at 77.000000 "$node_(3) setdest 516.301733 387.623702 19.580433" $ns_ at 77.000000 "$node_(4) setdest 505.320440 128.522356 19.999815" $ns_ at 77.000000 "$node_(5) setdest 515.254078 184.596382 19.996837" $ns_ at 77.000000 "$node_(6) setdest 437.257639 351.072545 11.785905" $ns_ at 77.000000 "$node_(7) setdest 500.846086 431.809163 14.885767" $ns_ at 77.000000 "$node_(8) setdest 529.413794 412.094108 19.867504" $ns_ at 77.000000 "$node_(9) setdest 565.572234 358.356299 3.496619" $ns_ at 77.000000 "$node_(10) setdest 548.808724 459.002515 15.277551" $ns_ at 78.000000 "$node_(1) setdest 568.615890 226.866730 19.953243" $ns_ at 78.000000 "$node_(2) setdest 506.765408 216.107743 19.996103" $ns_ at 78.000000 "$node_(3) setdest 518.586099 367.756661 19.997941" $ns_ at 78.000000 "$node_(4) setdest 511.394728 109.548785 19.922183" $ns_ at 78.000000 "$node_(5) setdest 521.978222 165.767794 19.993245" $ns_ at 78.000000 "$node_(6) setdest 429.959797 352.164602 7.379098" $ns_ at 78.000000 "$node_(7) setdest 494.140339 446.876872 16.492510" $ns_ at 78.000000 "$node_(8) setdest 525.963760 430.106023 18.339351" $ns_ at 78.000000 "$node_(9) setdest 569.000240 362.124933 5.094490" $ns_ at 78.000000 "$node_(10) setdest 540.470647 444.327845 16.878077" $ns_ at 79.000000 "$node_(1) setdest 574.185687 207.679959 19.978859" $ns_ at 79.000000 "$node_(2) setdest 491.733402 202.925804 19.993117" $ns_ at 79.000000 "$node_(3) setdest 519.783067 347.795031 19.997485" $ns_ at 79.000000 "$node_(4) setdest 508.990521 89.908093 19.787293" $ns_ at 79.000000 "$node_(5) setdest 526.722730 146.349523 19.989487" $ns_ at 79.000000 "$node_(6) setdest 421.402925 354.646309 8.909485" $ns_ at 79.000000 "$node_(7) setdest 484.722595 462.296802 18.068430" $ns_ at 79.000000 "$node_(8) setdest 513.980626 443.368125 17.873971" $ns_ at 79.000000 "$node_(9) setdest 572.479374 367.825573 6.678447" $ns_ at 79.000000 "$node_(10) setdest 529.744275 429.315243 18.450834" $ns_ at 80.000000 "$node_(1) setdest 576.539904 187.859407 19.959875" $ns_ at 80.000000 "$node_(2) setdest 480.207033 186.703672 19.900119" $ns_ at 80.000000 "$node_(3) setdest 519.812887 327.797852 19.997201" $ns_ at 80.000000 "$node_(4) setdest 497.292409 73.848971 19.868096" $ns_ at 80.000000 "$node_(5) setdest 528.886672 126.481962 19.985060" $ns_ at 80.000000 "$node_(6) setdest 415.020974 363.015006 10.524466" $ns_ at 80.000000 "$node_(7) setdest 471.817545 477.042190 19.595070" $ns_ at 80.000000 "$node_(8) setdest 503.184441 458.887502 18.905255" $ns_ at 80.000000 "$node_(9) setdest 575.661628 375.491501 8.300193" $ns_ at 80.000000 "$node_(10) setdest 514.499292 416.740217 19.762106" $ns_ at 81.000000 "$node_(1) setdest 574.626392 167.968199 19.983034" $ns_ at 81.000000 "$node_(2) setdest 475.821624 167.311287 19.882063" $ns_ at 81.000000 "$node_(3) setdest 518.646194 307.835016 19.996899" $ns_ at 81.000000 "$node_(4) setdest 483.578324 59.304461 19.990471" $ns_ at 81.000000 "$node_(5) setdest 527.651007 106.553198 19.967035" $ns_ at 81.000000 "$node_(6) setdest 410.440591 374.312692 12.190882" $ns_ at 81.000000 "$node_(7) setdest 456.292988 489.616829 19.978324" $ns_ at 81.000000 "$node_(8) setdest 498.005915 477.169448 19.001228" $ns_ at 81.000000 "$node_(9) setdest 579.725346 384.508368 9.890283" $ns_ at 81.000000 "$node_(10) setdest 495.634540 410.515884 19.865074" $ns_ at 82.000000 "$node_(1) setdest 573.744222 148.036265 19.951446" $ns_ at 82.000000 "$node_(2) setdest 474.558082 147.369780 19.981497" $ns_ at 82.000000 "$node_(3) setdest 516.187480 287.990063 19.996686" $ns_ at 82.000000 "$node_(4) setdest 474.515345 41.610136 19.880309" $ns_ at 82.000000 "$node_(5) setdest 522.091375 87.379602 19.963374" $ns_ at 82.000000 "$node_(6) setdest 414.780703 386.764139 13.186170" $ns_ at 82.000000 "$node_(7) setdest 438.763875 499.134151 19.946158" $ns_ at 82.000000 "$node_(8) setdest 500.792450 494.938482 17.986199" $ns_ at 82.000000 "$node_(9) setdest 588.726105 391.049918 11.126794" $ns_ at 82.000000 "$node_(10) setdest 475.806091 412.296842 19.908270" $ns_ at 83.000000 "$node_(1) setdest 577.404142 128.397041 19.977341" $ns_ at 83.000000 "$node_(2) setdest 471.772322 127.583434 19.981491" $ns_ at 83.000000 "$node_(3) setdest 512.431069 268.349770 19.996293" $ns_ at 83.000000 "$node_(4) setdest 467.791067 22.805362 19.970865" $ns_ at 83.000000 "$node_(5) setdest 513.352198 69.412545 19.979699" $ns_ at 83.000000 "$node_(6) setdest 426.772346 396.441652 15.409535" $ns_ at 83.000000 "$node_(7) setdest 419.593750 498.212291 19.192278" $ns_ at 83.000000 "$node_(8) setdest 513.064464 506.922013 17.152474" $ns_ at 83.000000 "$node_(9) setdest 594.729903 387.107313 7.182599" $ns_ at 83.000000 "$node_(10) setdest 456.101092 415.641689 19.986870" $ns_ at 84.000000 "$node_(1) setdest 583.213841 109.262849 19.996747" $ns_ at 84.000000 "$node_(2) setdest 476.419501 108.372979 19.764560" $ns_ at 84.000000 "$node_(3) setdest 507.266385 249.033080 19.995211" $ns_ at 84.000000 "$node_(4) setdest 462.492387 11.625346 12.372096" $ns_ at 84.000000 "$node_(5) setdest 502.089366 52.902858 19.985523" $ns_ at 84.000000 "$node_(6) setdest 437.511332 409.573265 16.963640" $ns_ at 84.000000 "$node_(7) setdest 412.014189 481.555847 18.299914" $ns_ at 84.000000 "$node_(8) setdest 526.654692 519.163066 18.290371" $ns_ at 84.000000 "$node_(9) setdest 592.714197 381.218901 6.223863" $ns_ at 84.000000 "$node_(10) setdest 436.259652 418.153011 19.999737" $ns_ at 85.000000 "$node_(1) setdest 587.867212 89.874667 19.938793" $ns_ at 85.000000 "$node_(2) setdest 489.338727 93.291200 19.858662" $ns_ at 85.000000 "$node_(3) setdest 500.466087 230.231287 19.993786" $ns_ at 85.000000 "$node_(4) setdest 463.199929 17.989912 6.403773" $ns_ at 85.000000 "$node_(5) setdest 487.155522 39.734993 19.910107" $ns_ at 85.000000 "$node_(6) setdest 443.956620 426.937800 18.522117" $ns_ at 85.000000 "$node_(7) setdest 404.982373 466.107830 16.973145" $ns_ at 85.000000 "$node_(8) setdest 537.501281 535.276226 19.423759" $ns_ at 85.000000 "$node_(9) setdest 588.601285 374.648766 7.751304" $ns_ at 85.000000 "$node_(10) setdest 417.844644 423.934655 19.301293" $ns_ at 86.000000 "$node_(1) setdest 583.707241 70.590453 19.727804" $ns_ at 86.000000 "$node_(2) setdest 507.837671 86.031211 19.872553" $ns_ at 86.000000 "$node_(3) setdest 492.487335 211.892008 19.999741" $ns_ at 86.000000 "$node_(4) setdest 460.684485 25.836346 8.239780" $ns_ at 86.000000 "$node_(5) setdest 468.395888 33.126211 19.889693" $ns_ at 86.000000 "$node_(6) setdest 439.617458 445.683926 19.241766" $ns_ at 86.000000 "$node_(7) setdest 405.686381 458.064025 8.074554" $ns_ at 86.000000 "$node_(8) setdest 552.956635 544.737738 18.121484" $ns_ at 86.000000 "$node_(9) setdest 579.604555 372.897661 9.165562" $ns_ at 86.000000 "$node_(10) setdest 417.084191 434.018891 10.112869" $ns_ at 87.000000 "$node_(1) setdest 568.163720 58.723273 19.555844" $ns_ at 87.000000 "$node_(2) setdest 527.597802 85.380885 19.770830" $ns_ at 87.000000 "$node_(3) setdest 484.486710 193.561998 19.999982" $ns_ at 87.000000 "$node_(4) setdest 458.575323 35.422524 9.815466" $ns_ at 87.000000 "$node_(5) setdest 448.529777 33.971581 19.884089" $ns_ at 87.000000 "$node_(6) setdest 425.906823 457.123064 17.855963" $ns_ at 87.000000 "$node_(7) setdest 408.452236 458.872840 2.881690" $ns_ at 87.000000 "$node_(8) setdest 568.879506 540.146677 16.571531" $ns_ at 87.000000 "$node_(9) setdest 569.851338 377.857203 10.941769" $ns_ at 87.000000 "$node_(10) setdest 421.850394 441.875446 9.189240" $ns_ at 88.000000 "$node_(1) setdest 548.683399 54.449519 19.943618" $ns_ at 88.000000 "$node_(2) setdest 546.933768 82.546059 19.542668" $ns_ at 88.000000 "$node_(3) setdest 476.681038 175.148773 19.999384" $ns_ at 88.000000 "$node_(4) setdest 461.366028 46.344763 11.273125" $ns_ at 88.000000 "$node_(5) setdest 430.847089 43.014463 19.860795" $ns_ at 88.000000 "$node_(6) setdest 410.587500 453.395095 15.766401" $ns_ at 88.000000 "$node_(7) setdest 412.362473 461.216708 4.558911" $ns_ at 88.000000 "$node_(8) setdest 582.276440 530.346179 16.599024" $ns_ at 88.000000 "$node_(9) setdest 560.884729 386.754776 12.631979" $ns_ at 88.000000 "$node_(10) setdest 424.841637 452.326111 10.870324" $ns_ at 89.000000 "$node_(1) setdest 529.270019 51.276340 19.671004" $ns_ at 89.000000 "$node_(2) setdest 565.972708 77.913315 19.594477" $ns_ at 89.000000 "$node_(3) setdest 469.023624 156.673222 19.999549" $ns_ at 89.000000 "$node_(4) setdest 471.973165 53.282586 12.674571" $ns_ at 89.000000 "$node_(5) setdest 419.286989 58.968693 19.702116" $ns_ at 89.000000 "$node_(6) setdest 404.803098 439.911564 14.671910" $ns_ at 89.000000 "$node_(7) setdest 416.934945 465.341967 6.158349" $ns_ at 89.000000 "$node_(8) setdest 595.673075 523.961962 14.840082" $ns_ at 89.000000 "$node_(9) setdest 554.608120 399.466950 14.177277" $ns_ at 89.000000 "$node_(10) setdest 428.943927 464.092911 12.461395" $ns_ at 90.000000 "$node_(1) setdest 510.446672 45.560687 19.671987" $ns_ at 90.000000 "$node_(2) setdest 581.900465 67.427062 19.069739" $ns_ at 90.000000 "$node_(3) setdest 460.852421 138.421298 19.997532" $ns_ at 90.000000 "$node_(4) setdest 486.548028 54.559831 14.630720" $ns_ at 90.000000 "$node_(5) setdest 417.520328 78.793399 19.903267" $ns_ at 90.000000 "$node_(6) setdest 412.989536 428.553731 14.000647" $ns_ at 90.000000 "$node_(7) setdest 421.706379 471.443160 7.745395" $ns_ at 90.000000 "$node_(8) setdest 596.698144 525.418757 1.781297" $ns_ at 90.000000 "$node_(9) setdest 552.296746 415.092034 15.795117" $ns_ at 90.000000 "$node_(10) setdest 437.002050 475.535203 13.994977" $ns_ at 91.000000 "$node_(1) setdest 491.216630 41.851459 19.584506" $ns_ at 91.000000 "$node_(2) setdest 597.391272 59.977823 17.188841" $ns_ at 91.000000 "$node_(3) setdest 451.041441 121.016462 19.979581" $ns_ at 91.000000 "$node_(4) setdest 502.763761 55.445814 16.239919" $ns_ at 91.000000 "$node_(5) setdest 420.064577 98.608541 19.977814" $ns_ at 91.000000 "$node_(6) setdest 427.036725 421.558974 15.692359" $ns_ at 91.000000 "$node_(7) setdest 425.224219 480.087841 9.333043" $ns_ at 91.000000 "$node_(8) setdest 595.078325 527.548271 2.675565" $ns_ at 91.000000 "$node_(9) setdest 555.215513 432.214111 17.369074" $ns_ at 91.000000 "$node_(10) setdest 450.540971 483.206577 15.561245" $ns_ at 92.000000 "$node_(1) setdest 471.659908 39.220660 19.732878" $ns_ at 92.000000 "$node_(2) setdest 599.260739 62.844430 3.422330" $ns_ at 92.000000 "$node_(3) setdest 437.200521 106.710742 19.905394" $ns_ at 92.000000 "$node_(4) setdest 520.463512 57.440346 17.811775" $ns_ at 92.000000 "$node_(5) setdest 425.407301 117.784600 19.906430" $ns_ at 92.000000 "$node_(6) setdest 441.106703 411.581456 17.248628" $ns_ at 92.000000 "$node_(7) setdest 426.330437 490.960272 10.928563" $ns_ at 92.000000 "$node_(8) setdest 592.410482 530.533599 4.003694" $ns_ at 92.000000 "$node_(9) setdest 564.412524 448.873432 19.029397" $ns_ at 92.000000 "$node_(10) setdest 467.267881 487.413523 17.247838" $ns_ at 93.000000 "$node_(1) setdest 453.466313 33.175001 19.171774" $ns_ at 93.000000 "$node_(2) setdest 598.291343 67.449039 4.705545" $ns_ at 93.000000 "$node_(3) setdest 420.425409 96.070528 19.865007" $ns_ at 93.000000 "$node_(4) setdest 539.462165 61.491498 19.425773" $ns_ at 93.000000 "$node_(5) setdest 434.020030 135.209813 19.437519" $ns_ at 93.000000 "$node_(6) setdest 455.272226 399.073428 18.897428" $ns_ at 93.000000 "$node_(7) setdest 427.424847 503.463387 12.550921" $ns_ at 93.000000 "$node_(8) setdest 593.809342 529.223559 1.916510" $ns_ at 93.000000 "$node_(9) setdest 576.244847 464.961799 19.970965" $ns_ at 93.000000 "$node_(10) setdest 485.902916 490.396138 18.872215" $ns_ at 94.000000 "$node_(1) setdest 440.069927 20.181823 18.662418" $ns_ at 94.000000 "$node_(2) setdest 596.289520 73.428855 6.305989" $ns_ at 94.000000 "$node_(3) setdest 418.138459 85.885901 10.438235" $ns_ at 94.000000 "$node_(4) setdest 559.121472 65.074947 19.983229" $ns_ at 94.000000 "$node_(5) setdest 433.752323 153.363814 18.155975" $ns_ at 94.000000 "$node_(6) setdest 468.907539 384.565199 19.910059" $ns_ at 94.000000 "$node_(7) setdest 423.892158 517.002474 13.992382" $ns_ at 94.000000 "$node_(8) setdest 594.496732 525.690274 3.599529" $ns_ at 94.000000 "$node_(9) setdest 587.176402 481.519615 19.840871" $ns_ at 94.000000 "$node_(10) setdest 505.557558 493.894481 19.963551" $ns_ at 95.000000 "$node_(1) setdest 427.052116 6.847278 18.635275" $ns_ at 95.000000 "$node_(2) setdest 594.485579 81.120759 7.900607" $ns_ at 95.000000 "$node_(3) setdest 420.911514 86.122459 2.783127" $ns_ at 95.000000 "$node_(4) setdest 579.042638 65.882017 19.937508" $ns_ at 95.000000 "$node_(5) setdest 419.915636 161.815294 16.213618" $ns_ at 95.000000 "$node_(6) setdest 479.384927 367.530238 19.999139" $ns_ at 95.000000 "$node_(7) setdest 413.636242 520.451794 10.820426" $ns_ at 95.000000 "$node_(8) setdest 595.480416 520.598937 5.185494" $ns_ at 95.000000 "$node_(9) setdest 588.142218 501.154215 19.658340" $ns_ at 95.000000 "$node_(10) setdest 525.501306 495.121901 19.981483" $ns_ at 96.000000 "$node_(1) setdest 410.783725 0.750524 17.373284" $ns_ at 96.000000 "$node_(2) setdest 593.127576 90.529264 9.506006" $ns_ at 96.000000 "$node_(3) setdest 424.469755 88.906562 4.517998" $ns_ at 96.000000 "$node_(4) setdest 589.252016 52.033514 17.205011" $ns_ at 96.000000 "$node_(5) setdest 406.673798 155.191050 14.806312" $ns_ at 96.000000 "$node_(6) setdest 483.266169 352.608643 15.418108" $ns_ at 96.000000 "$node_(7) setdest 410.018337 513.556034 7.787216" $ns_ at 96.000000 "$node_(8) setdest 595.625065 513.990687 6.609832" $ns_ at 96.000000 "$node_(9) setdest 576.073216 515.525770 18.767056" $ns_ at 96.000000 "$node_(10) setdest 544.912679 490.672198 19.914850" $ns_ at 97.000000 "$node_(1) setdest 419.156506 3.762852 8.898179" $ns_ at 97.000000 "$node_(2) setdest 591.679304 101.541365 11.106928" $ns_ at 97.000000 "$node_(3) setdest 429.445594 92.463295 6.116317" $ns_ at 97.000000 "$node_(4) setdest 580.554829 37.419012 17.006609" $ns_ at 97.000000 "$node_(5) setdest 406.950962 153.565137 1.649367" $ns_ at 97.000000 "$node_(6) setdest 479.856644 351.887222 3.485012" $ns_ at 97.000000 "$node_(7) setdest 408.684567 504.276932 9.374469" $ns_ at 97.000000 "$node_(8) setdest 590.406909 507.617288 8.237073" $ns_ at 97.000000 "$node_(9) setdest 559.752265 523.162622 18.019294" $ns_ at 97.000000 "$node_(10) setdest 561.124452 479.086372 19.926187" $ns_ at 98.000000 "$node_(1) setdest 429.488659 2.608879 10.396395" $ns_ at 98.000000 "$node_(2) setdest 589.054917 113.968791 12.701509" $ns_ at 98.000000 "$node_(3) setdest 436.124983 96.326552 7.716151" $ns_ at 98.000000 "$node_(4) setdest 574.740693 23.094755 15.459253" $ns_ at 98.000000 "$node_(5) setdest 409.384783 153.230897 2.456664" $ns_ at 98.000000 "$node_(6) setdest 474.746734 352.016833 5.111553" $ns_ at 98.000000 "$node_(7) setdest 413.021931 494.129886 11.035183" $ns_ at 98.000000 "$node_(8) setdest 580.882175 505.117671 9.847266" $ns_ at 98.000000 "$node_(9) setdest 542.784470 531.635980 18.965860" $ns_ at 98.000000 "$node_(10) setdest 575.265149 465.030323 19.938201" $ns_ at 99.000000 "$node_(1) setdest 441.489099 2.335719 12.003549" $ns_ at 99.000000 "$node_(2) setdest 586.056851 127.939810 14.289078" $ns_ at 99.000000 "$node_(3) setdest 444.433154 100.546506 9.318461" $ns_ at 99.000000 "$node_(4) setdest 563.604426 11.802092 15.860034" $ns_ at 99.000000 "$node_(5) setdest 413.431025 153.540340 4.058058" $ns_ at 99.000000 "$node_(6) setdest 468.323715 353.930297 6.701979" $ns_ at 99.000000 "$node_(7) setdest 422.987216 486.505659 12.547341" $ns_ at 99.000000 "$node_(8) setdest 569.510780 507.343850 11.587256" $ns_ at 99.000000 "$node_(9) setdest 530.489038 544.913627 18.096231" $ns_ at 99.000000 "$node_(10) setdest 581.656414 446.357042 19.736760" $ns_ at 100.000000 "$node_(1) setdest 454.447553 5.677176 13.382334" $ns_ at 100.000000 "$node_(2) setdest 586.790587 143.764948 15.842139" $ns_ at 100.000000 "$node_(3) setdest 454.264488 105.292106 10.916769" $ns_ at 100.000000 "$node_(4) setdest 547.205392 5.747685 17.480967" $ns_ at 100.000000 "$node_(5) setdest 419.055426 154.172769 5.659845" $ns_ at 100.000000 "$node_(6) setdest 468.513902 353.682612 0.312280" $ns_ at 100.000000 "$node_(7) setdest 425.531876 476.300999 10.517147" $ns_ at 100.000000 "$node_(8) setdest 568.125928 506.009333 1.923214" $ns_ at 100.000000 "$node_(9) setdest 534.125064 533.948308 11.552442" $ns_ at 100.000000 "$node_(10) setdest 574.270722 427.825799 19.948820" $ns_ at 101.000000 "$node_(1) setdest 463.974595 17.337902 15.057791" $ns_ at 101.000000 "$node_(2) setdest 588.818288 160.985039 17.339062" $ns_ at 101.000000 "$node_(3) setdest 465.953584 109.763324 12.515061" $ns_ at 101.000000 "$node_(4) setdest 528.686907 4.225543 18.580936" $ns_ at 101.000000 "$node_(5) setdest 426.301451 153.959775 7.249155" $ns_ at 101.000000 "$node_(6) setdest 468.409172 351.964764 1.721038" $ns_ at 101.000000 "$node_(7) setdest 425.627464 463.860769 12.440598" $ns_ at 101.000000 "$node_(8) setdest 568.230938 502.795685 3.215363" $ns_ at 101.000000 "$node_(9) setdest 534.843844 520.422103 13.545289" $ns_ at 101.000000 "$node_(10) setdest 565.376509 409.915463 19.997179" $ns_ at 102.000000 "$node_(1) setdest 469.266398 33.192266 16.714186" $ns_ at 102.000000 "$node_(2) setdest 583.250087 179.129202 18.979345" $ns_ at 102.000000 "$node_(3) setdest 479.708421 112.845067 14.095839" $ns_ at 102.000000 "$node_(4) setdest 513.846746 13.845484 17.685407" $ns_ at 102.000000 "$node_(5) setdest 434.772540 151.433158 8.839861" $ns_ at 102.000000 "$node_(6) setdest 467.957451 348.674042 3.321581" $ns_ at 102.000000 "$node_(7) setdest 425.462374 449.821538 14.040202" $ns_ at 102.000000 "$node_(8) setdest 568.504849 497.988118 4.815363" $ns_ at 102.000000 "$node_(9) setdest 536.479818 505.366286 15.144440" $ns_ at 102.000000 "$node_(10) setdest 555.303153 392.642708 19.995513" $ns_ at 103.000000 "$node_(1) setdest 465.730169 51.026601 18.181541" $ns_ at 103.000000 "$node_(2) setdest 566.879047 186.735999 18.051989" $ns_ at 103.000000 "$node_(3) setdest 495.386590 112.701027 15.678831" $ns_ at 103.000000 "$node_(4) setdest 498.374210 23.147625 18.053509" $ns_ at 103.000000 "$node_(5) setdest 443.971210 146.477076 10.448841" $ns_ at 103.000000 "$node_(6) setdest 467.040158 343.838883 4.921401" $ns_ at 103.000000 "$node_(7) setdest 424.846982 434.193648 15.640001" $ns_ at 103.000000 "$node_(8) setdest 568.959563 491.588797 6.415456" $ns_ at 103.000000 "$node_(9) setdest 539.291404 488.859842 16.744184" $ns_ at 103.000000 "$node_(10) setdest 543.978114 376.161913 19.996828" $ns_ at 104.000000 "$node_(1) setdest 453.885584 66.862210 19.775255" $ns_ at 104.000000 "$node_(2) setdest 550.420005 182.065219 17.108953" $ns_ at 104.000000 "$node_(3) setdest 512.035228 108.074256 17.279588" $ns_ at 104.000000 "$node_(4) setdest 480.422154 28.888008 18.847502" $ns_ at 104.000000 "$node_(5) setdest 453.481156 139.084396 12.045363" $ns_ at 104.000000 "$node_(6) setdest 465.522276 337.496223 6.521756" $ns_ at 104.000000 "$node_(7) setdest 423.890552 416.980065 17.240133" $ns_ at 104.000000 "$node_(8) setdest 569.408345 483.586152 8.015219" $ns_ at 104.000000 "$node_(9) setdest 542.421361 470.785101 18.343743" $ns_ at 104.000000 "$node_(10) setdest 532.315171 359.914903 19.999739" $ns_ at 105.000000 "$node_(1) setdest 441.554672 82.598803 19.992292" $ns_ at 105.000000 "$node_(2) setdest 539.013776 170.214626 16.448058" $ns_ at 105.000000 "$node_(3) setdest 529.234106 100.206225 18.913152" $ns_ at 105.000000 "$node_(4) setdest 461.595790 33.254097 19.326011" $ns_ at 105.000000 "$node_(5) setdest 463.150011 129.433979 13.660795" $ns_ at 105.000000 "$node_(6) setdest 464.066377 329.507246 8.120554" $ns_ at 105.000000 "$node_(7) setdest 423.478241 398.145310 18.839268" $ns_ at 105.000000 "$node_(8) setdest 569.653858 473.974181 9.615106" $ns_ at 105.000000 "$node_(9) setdest 544.689190 451.144354 19.771242" $ns_ at 105.000000 "$node_(10) setdest 521.557519 343.060211 19.995192" $ns_ at 106.000000 "$node_(1) setdest 426.035377 95.120154 19.940731" $ns_ at 106.000000 "$node_(2) setdest 527.796998 156.046188 18.070991" $ns_ at 106.000000 "$node_(3) setdest 546.577423 90.292431 19.976836" $ns_ at 106.000000 "$node_(4) setdest 442.458573 31.949902 19.181606" $ns_ at 106.000000 "$node_(5) setdest 473.667535 118.375737 15.261160" $ns_ at 106.000000 "$node_(6) setdest 463.038352 319.841988 9.719776" $ns_ at 106.000000 "$node_(7) setdest 424.022196 378.194573 19.958150" $ns_ at 106.000000 "$node_(8) setdest 569.813158 462.759869 11.215443" $ns_ at 106.000000 "$node_(9) setdest 547.190950 431.303404 19.998052" $ns_ at 106.000000 "$node_(10) setdest 512.059389 325.464003 19.996025" $ns_ at 107.000000 "$node_(1) setdest 413.339629 110.424764 19.884997" $ns_ at 107.000000 "$node_(2) setdest 522.889895 138.019659 18.682489" $ns_ at 107.000000 "$node_(3) setdest 562.785458 78.657080 19.951987" $ns_ at 107.000000 "$node_(4) setdest 424.326276 36.316554 18.650680" $ns_ at 107.000000 "$node_(5) setdest 485.278736 106.151196 16.859994" $ns_ at 107.000000 "$node_(6) setdest 462.686740 308.528017 11.319434" $ns_ at 107.000000 "$node_(7) setdest 425.056084 358.221365 19.999950" $ns_ at 107.000000 "$node_(8) setdest 570.011307 449.945947 12.815454" $ns_ at 107.000000 "$node_(9) setdest 550.802202 411.635114 19.997070" $ns_ at 107.000000 "$node_(10) setdest 504.100758 307.123887 19.992490" $ns_ at 108.000000 "$node_(1) setdest 403.484524 120.881194 14.368718" $ns_ at 108.000000 "$node_(2) setdest 522.671723 118.777356 19.243540" $ns_ at 108.000000 "$node_(3) setdest 566.030236 61.969468 17.000146" $ns_ at 108.000000 "$node_(4) setdest 406.729266 43.449566 18.987750" $ns_ at 108.000000 "$node_(5) setdest 498.299352 93.063657 18.461314" $ns_ at 108.000000 "$node_(6) setdest 463.350139 295.626592 12.918469" $ns_ at 108.000000 "$node_(7) setdest 425.713473 338.232633 19.999539" $ns_ at 108.000000 "$node_(8) setdest 570.151839 435.531284 14.415348" $ns_ at 108.000000 "$node_(9) setdest 553.849836 391.873169 19.995562" $ns_ at 108.000000 "$node_(10) setdest 497.862638 288.126445 19.995423" $ns_ at 109.000000 "$node_(1) setdest 403.989736 119.896423 1.106803" $ns_ at 109.000000 "$node_(2) setdest 528.443915 101.055487 18.638209" $ns_ at 109.000000 "$node_(3) setdest 555.086711 59.581719 11.200986" $ns_ at 109.000000 "$node_(4) setdest 419.658364 34.543594 15.699616" $ns_ at 109.000000 "$node_(5) setdest 512.018250 78.744240 19.830629" $ns_ at 109.000000 "$node_(6) setdest 465.226532 281.230082 14.518276" $ns_ at 109.000000 "$node_(7) setdest 425.892742 318.233998 19.999438" $ns_ at 109.000000 "$node_(8) setdest 569.845697 419.519895 16.014315" $ns_ at 109.000000 "$node_(9) setdest 555.287187 371.932228 19.992677" $ns_ at 109.000000 "$node_(10) setdest 493.133245 268.700773 19.993096" $ns_ at 110.000000 "$node_(1) setdest 405.689023 117.799747 2.698820" $ns_ at 110.000000 "$node_(2) setdest 542.452784 89.981334 17.857360" $ns_ at 110.000000 "$node_(3) setdest 541.878384 60.468639 13.238071" $ns_ at 110.000000 "$node_(4) setdest 431.508634 26.710829 14.204967" $ns_ at 110.000000 "$node_(5) setdest 525.437273 63.918876 19.996540" $ns_ at 110.000000 "$node_(6) setdest 468.870766 265.532533 16.115008" $ns_ at 110.000000 "$node_(7) setdest 425.465752 298.239034 19.999523" $ns_ at 110.000000 "$node_(8) setdest 568.423672 401.966936 17.610467" $ns_ at 110.000000 "$node_(9) setdest 554.604727 351.953670 19.990211" $ns_ at 110.000000 "$node_(10) setdest 490.462288 248.888314 19.991687" $ns_ at 111.000000 "$node_(1) setdest 409.267839 115.417933 4.298949" $ns_ at 111.000000 "$node_(2) setdest 559.897956 86.045463 17.883655" $ns_ at 111.000000 "$node_(3) setdest 527.059137 59.782209 14.835137" $ns_ at 111.000000 "$node_(4) setdest 443.573833 19.915640 13.847152" $ns_ at 111.000000 "$node_(5) setdest 538.192908 48.515225 19.999468" $ns_ at 111.000000 "$node_(6) setdest 473.714036 248.485385 17.721809" $ns_ at 111.000000 "$node_(7) setdest 424.698720 278.254092 19.999656" $ns_ at 111.000000 "$node_(8) setdest 566.060462 382.899839 19.212989" $ns_ at 111.000000 "$node_(9) setdest 551.708859 332.174554 19.989984" $ns_ at 111.000000 "$node_(10) setdest 489.396329 228.922479 19.994270" $ns_ at 112.000000 "$node_(1) setdest 414.950785 113.903111 5.881374" $ns_ at 112.000000 "$node_(2) setdest 578.124561 87.480642 18.283021" $ns_ at 112.000000 "$node_(3) setdest 510.636699 60.626058 16.444104" $ns_ at 112.000000 "$node_(4) setdest 457.652786 13.663710 15.404660" $ns_ at 112.000000 "$node_(5) setdest 551.827674 34.309326 19.690465" $ns_ at 112.000000 "$node_(6) setdest 478.228138 229.700152 19.319992" $ns_ at 112.000000 "$node_(7) setdest 422.398639 258.396580 19.990277" $ns_ at 112.000000 "$node_(8) setdest 565.174425 362.924990 19.994490" $ns_ at 112.000000 "$node_(9) setdest 546.871512 312.774624 19.993929" $ns_ at 112.000000 "$node_(10) setdest 491.447099 209.200491 19.828325" $ns_ at 113.000000 "$node_(1) setdest 422.446166 114.130760 7.498837" $ns_ at 113.000000 "$node_(2) setdest 591.915195 78.408014 16.507397" $ns_ at 113.000000 "$node_(3) setdest 492.624699 59.666840 18.037523" $ns_ at 113.000000 "$node_(4) setdest 472.214347 5.489961 16.698779" $ns_ at 113.000000 "$node_(5) setdest 551.486872 35.177611 0.932773" $ns_ at 113.000000 "$node_(6) setdest 482.217820 210.104151 19.998020" $ns_ at 113.000000 "$node_(7) setdest 417.831564 238.927314 19.997762" $ns_ at 113.000000 "$node_(8) setdest 564.744712 342.930184 19.999424" $ns_ at 113.000000 "$node_(9) setdest 540.209785 293.926814 19.990462" $ns_ at 113.000000 "$node_(10) setdest 504.489346 196.354667 18.306158" $ns_ at 114.000000 "$node_(1) setdest 431.271998 116.305610 9.089845" $ns_ at 114.000000 "$node_(2) setdest 588.736507 63.560605 15.183860" $ns_ at 114.000000 "$node_(3) setdest 473.963039 54.031040 19.494096" $ns_ at 114.000000 "$node_(4) setdest 473.434460 2.312632 3.403542" $ns_ at 114.000000 "$node_(5) setdest 548.218838 37.090081 3.786501" $ns_ at 114.000000 "$node_(6) setdest 484.657569 190.258834 19.994725" $ns_ at 114.000000 "$node_(7) setdest 414.150519 219.279742 19.989426" $ns_ at 114.000000 "$node_(8) setdest 563.955033 322.946138 19.999642" $ns_ at 114.000000 "$node_(9) setdest 531.976806 275.701992 19.998151" $ns_ at 114.000000 "$node_(10) setdest 520.244752 190.438199 16.829659" $ns_ at 115.000000 "$node_(1) setdest 440.908069 120.949190 10.696574" $ns_ at 115.000000 "$node_(2) setdest 580.431419 50.836504 15.194645" $ns_ at 115.000000 "$node_(3) setdest 456.876131 43.692246 19.971307" $ns_ at 115.000000 "$node_(4) setdest 472.869595 2.467477 0.585704" $ns_ at 115.000000 "$node_(5) setdest 543.700691 40.023340 5.386804" $ns_ at 115.000000 "$node_(6) setdest 485.938648 170.301151 19.998756" $ns_ at 115.000000 "$node_(7) setdest 414.076804 199.317789 19.962089" $ns_ at 115.000000 "$node_(8) setdest 563.190475 302.961948 19.998810" $ns_ at 115.000000 "$node_(9) setdest 522.369871 258.168219 19.993159" $ns_ at 115.000000 "$node_(10) setdest 534.924858 194.630099 15.266877" $ns_ at 116.000000 "$node_(1) setdest 451.284786 127.573697 12.310985" $ns_ at 116.000000 "$node_(2) setdest 569.402032 38.175636 16.791217" $ns_ at 116.000000 "$node_(3) setdest 440.770647 31.838598 19.997390" $ns_ at 116.000000 "$node_(4) setdest 472.841751 4.274661 1.807398" $ns_ at 116.000000 "$node_(5) setdest 537.436100 43.104717 6.981403" $ns_ at 116.000000 "$node_(6) setdest 486.954575 150.332081 19.994896" $ns_ at 116.000000 "$node_(7) setdest 417.830901 179.685288 19.988205" $ns_ at 116.000000 "$node_(8) setdest 563.641683 282.971460 19.995579" $ns_ at 116.000000 "$node_(9) setdest 511.298664 241.517648 19.995328" $ns_ at 116.000000 "$node_(10) setdest 550.011999 194.908027 15.089700" $ns_ at 117.000000 "$node_(1) setdest 462.138089 136.267655 13.906081" $ns_ at 117.000000 "$node_(2) setdest 556.634968 24.940619 18.389225" $ns_ at 117.000000 "$node_(3) setdest 425.324448 19.136132 19.998443" $ns_ at 117.000000 "$node_(4) setdest 473.314494 7.680851 3.438840" $ns_ at 117.000000 "$node_(5) setdest 529.438223 46.226951 8.585708" $ns_ at 117.000000 "$node_(6) setdest 490.129007 130.598208 19.987566" $ns_ at 117.000000 "$node_(7) setdest 423.966373 160.668563 19.981989" $ns_ at 117.000000 "$node_(8) setdest 565.740884 263.087161 19.994799" $ns_ at 117.000000 "$node_(9) setdest 499.055031 225.704650 19.998936" $ns_ at 117.000000 "$node_(10) setdest 563.557238 186.500635 15.942326" $ns_ at 118.000000 "$node_(1) setdest 473.241458 147.092544 15.506870" $ns_ at 118.000000 "$node_(2) setdest 539.814754 14.774438 19.653774" $ns_ at 118.000000 "$node_(3) setdest 409.111886 8.883379 19.182442" $ns_ at 118.000000 "$node_(4) setdest 473.692202 12.706450 5.039772" $ns_ at 118.000000 "$node_(5) setdest 519.739209 49.337753 10.185674" $ns_ at 118.000000 "$node_(6) setdest 496.431453 111.642085 19.976371" $ns_ at 118.000000 "$node_(7) setdest 432.569997 142.630498 19.984847" $ns_ at 118.000000 "$node_(8) setdest 568.702436 243.307677 19.999970" $ns_ at 118.000000 "$node_(9) setdest 485.443278 211.070870 19.985678" $ns_ at 118.000000 "$node_(10) setdest 570.192106 171.160831 16.713200" $ns_ at 119.000000 "$node_(1) setdest 487.251601 156.862702 17.080401" $ns_ at 119.000000 "$node_(2) setdest 520.683497 9.021841 19.977421" $ns_ at 119.000000 "$node_(3) setdest 417.073766 12.056418 8.570864" $ns_ at 119.000000 "$node_(4) setdest 474.036968 19.336302 6.638810" $ns_ at 119.000000 "$node_(5) setdest 508.315867 52.234824 11.784981" $ns_ at 119.000000 "$node_(6) setdest 506.265369 94.271345 19.961175" $ns_ at 119.000000 "$node_(7) setdest 443.201855 125.694874 19.996294" $ns_ at 119.000000 "$node_(8) setdest 571.628211 223.523019 19.999821" $ns_ at 119.000000 "$node_(9) setdest 470.395480 197.901690 19.996588" $ns_ at 119.000000 "$node_(10) setdest 581.059668 156.562270 18.199503" $ns_ at 120.000000 "$node_(1) setdest 504.954771 159.215359 17.858813" $ns_ at 120.000000 "$node_(2) setdest 501.192874 10.606251 19.554916" $ns_ at 120.000000 "$node_(3) setdest 423.571462 19.617907 9.969763" $ns_ at 120.000000 "$node_(4) setdest 474.472309 27.560057 8.235270" $ns_ at 120.000000 "$node_(5) setdest 495.207683 54.945946 13.385614" $ns_ at 120.000000 "$node_(6) setdest 520.516470 80.409235 19.880946" $ns_ at 120.000000 "$node_(7) setdest 453.570709 108.596480 19.996705" $ns_ at 120.000000 "$node_(8) setdest 573.762328 203.638794 19.998422" $ns_ at 120.000000 "$node_(9) setdest 453.975818 186.542303 19.965996" $ns_ at 120.000000 "$node_(10) setdest 592.135494 143.826225 16.878411" $ns_ at 121.000000 "$node_(1) setdest 509.718099 146.506082 13.572583" $ns_ at 121.000000 "$node_(2) setdest 484.117793 19.082124 19.063023" $ns_ at 121.000000 "$node_(3) setdest 433.058684 26.201559 11.547808" $ns_ at 121.000000 "$node_(4) setdest 476.147484 37.254243 9.837858" $ns_ at 121.000000 "$node_(5) setdest 480.493467 57.703401 14.970361" $ns_ at 121.000000 "$node_(6) setdest 537.165573 83.737558 16.978527" $ns_ at 121.000000 "$node_(7) setdest 464.612917 91.921714 19.999454" $ns_ at 121.000000 "$node_(8) setdest 575.622097 183.725674 19.999777" $ns_ at 121.000000 "$node_(9) setdest 435.402591 179.523497 19.855186" $ns_ at 121.000000 "$node_(10) setdest 589.495037 140.928854 3.920047" $ns_ at 122.000000 "$node_(1) setdest 501.618767 135.407562 13.739589" $ns_ at 122.000000 "$node_(2) setdest 468.354636 30.000884 19.175412" $ns_ at 122.000000 "$node_(3) setdest 444.780251 32.212762 13.173066" $ns_ at 122.000000 "$node_(4) setdest 478.682436 48.409195 11.439359" $ns_ at 122.000000 "$node_(5) setdest 465.298067 64.267961 16.552753" $ns_ at 122.000000 "$node_(6) setdest 544.950948 98.256877 16.474910" $ns_ at 122.000000 "$node_(7) setdest 475.946542 75.443825 19.999297" $ns_ at 122.000000 "$node_(8) setdest 576.534377 163.749996 19.996499" $ns_ at 122.000000 "$node_(9) setdest 434.434766 179.467028 0.969471" $ns_ at 122.000000 "$node_(10) setdest 584.521690 139.425209 5.195683" $ns_ at 123.000000 "$node_(1) setdest 492.075637 123.450755 15.298253" $ns_ at 123.000000 "$node_(2) setdest 455.863068 44.093278 18.831751" $ns_ at 123.000000 "$node_(3) setdest 458.619999 37.371581 14.769972" $ns_ at 123.000000 "$node_(4) setdest 482.138433 60.980026 13.037244" $ns_ at 123.000000 "$node_(5) setdest 449.568122 73.372764 18.174944" $ns_ at 123.000000 "$node_(6) setdest 555.460624 109.423500 15.334495" $ns_ at 123.000000 "$node_(7) setdest 488.072608 59.566099 19.978580" $ns_ at 123.000000 "$node_(8) setdest 575.616599 143.782691 19.988386" $ns_ at 123.000000 "$node_(9) setdest 437.345563 182.540188 4.232854" $ns_ at 123.000000 "$node_(10) setdest 578.082071 137.243055 6.799300" $ns_ at 124.000000 "$node_(1) setdest 481.629922 110.164467 16.900841" $ns_ at 124.000000 "$node_(2) setdest 442.838643 58.392410 19.341686" $ns_ at 124.000000 "$node_(3) setdest 474.615429 40.719637 16.342070" $ns_ at 124.000000 "$node_(4) setdest 486.172579 75.052483 14.639275" $ns_ at 124.000000 "$node_(5) setdest 430.524277 77.428350 19.470897" $ns_ at 124.000000 "$node_(6) setdest 570.380491 116.561320 16.539374" $ns_ at 124.000000 "$node_(7) setdest 503.421106 46.832482 19.942953" $ns_ at 124.000000 "$node_(8) setdest 571.969243 124.135771 19.982610" $ns_ at 124.000000 "$node_(9) setdest 437.850553 188.097996 5.580703" $ns_ at 124.000000 "$node_(10) setdest 570.292753 134.115544 8.393736" $ns_ at 125.000000 "$node_(1) setdest 468.764309 108.362457 12.991198" $ns_ at 125.000000 "$node_(2) setdest 424.365917 65.103086 19.653874" $ns_ at 125.000000 "$node_(3) setdest 458.785742 38.071495 16.049662" $ns_ at 125.000000 "$node_(4) setdest 485.862028 75.256264 0.371442" $ns_ at 125.000000 "$node_(5) setdest 410.538520 78.179722 19.999876" $ns_ at 125.000000 "$node_(6) setdest 586.519711 124.964926 18.196017" $ns_ at 125.000000 "$node_(7) setdest 522.204110 40.543630 19.807850" $ns_ at 125.000000 "$node_(8) setdest 565.283378 105.313652 19.974308" $ns_ at 125.000000 "$node_(9) setdest 438.236927 188.566948 0.607619" $ns_ at 125.000000 "$node_(10) setdest 561.454881 129.437687 9.999516" $ns_ at 126.000000 "$node_(1) setdest 453.894330 110.665395 15.047252" $ns_ at 126.000000 "$node_(2) setdest 404.988454 70.046829 19.998166" $ns_ at 126.000000 "$node_(3) setdest 440.858781 37.340840 17.941845" $ns_ at 126.000000 "$node_(4) setdest 484.107042 74.965456 1.778916" $ns_ at 126.000000 "$node_(5) setdest 390.542704 78.440085 19.997511" $ns_ at 126.000000 "$node_(6) setdest 592.964875 127.196911 6.820696" $ns_ at 126.000000 "$node_(7) setdest 542.036992 42.707094 19.950533" $ns_ at 126.000000 "$node_(8) setdest 554.346165 88.643407 19.937896" $ns_ at 126.000000 "$node_(9) setdest 438.863799 187.609138 1.144713" $ns_ at 126.000000 "$node_(10) setdest 550.853562 124.755186 11.589383" $ns_ at 127.000000 "$node_(1) setdest 437.536983 113.753231 16.646247" $ns_ at 127.000000 "$node_(2) setdest 385.400042 74.078678 19.999042" $ns_ at 127.000000 "$node_(3) setdest 421.408233 35.863244 19.506591" $ns_ at 127.000000 "$node_(4) setdest 480.756885 74.527052 3.378720" $ns_ at 127.000000 "$node_(5) setdest 370.587368 77.185177 19.994756" $ns_ at 127.000000 "$node_(6) setdest 591.806569 125.973434 1.684805" $ns_ at 127.000000 "$node_(7) setdest 561.938216 44.598425 19.990894" $ns_ at 127.000000 "$node_(8) setdest 538.791423 76.225827 19.903424" $ns_ at 127.000000 "$node_(9) setdest 439.851088 185.026858 2.764582" $ns_ at 127.000000 "$node_(10) setdest 538.598737 119.856049 13.197813" $ns_ at 128.000000 "$node_(1) setdest 419.670201 117.456660 18.246569" $ns_ at 128.000000 "$node_(2) setdest 365.724919 77.666346 19.999545" $ns_ at 128.000000 "$node_(3) setdest 401.445644 34.670369 19.998197" $ns_ at 128.000000 "$node_(4) setdest 475.797670 74.087926 4.978620" $ns_ at 128.000000 "$node_(5) setdest 350.726157 74.834010 19.999892" $ns_ at 128.000000 "$node_(6) setdest 589.270539 123.860295 3.301031" $ns_ at 128.000000 "$node_(7) setdest 581.791247 44.803262 19.854088" $ns_ at 128.000000 "$node_(8) setdest 520.702123 67.707079 19.994795" $ns_ at 128.000000 "$node_(9) setdest 441.303563 180.909826 4.365734" $ns_ at 128.000000 "$node_(10) setdest 525.473635 113.036002 14.791260" $ns_ at 129.000000 "$node_(1) setdest 400.190414 120.538102 19.722002" $ns_ at 129.000000 "$node_(2) setdest 345.957172 80.701765 19.999440" $ns_ at 129.000000 "$node_(3) setdest 381.449576 34.354000 19.998570" $ns_ at 129.000000 "$node_(4) setdest 469.225898 73.791977 6.578432" $ns_ at 129.000000 "$node_(5) setdest 330.797553 73.177839 19.997304" $ns_ at 129.000000 "$node_(6) setdest 585.243076 121.062983 4.903612" $ns_ at 129.000000 "$node_(7) setdest 588.511397 48.281694 7.567028" $ns_ at 129.000000 "$node_(8) setdest 502.905331 58.615452 19.984581" $ns_ at 129.000000 "$node_(9) setdest 443.695561 175.443621 5.966662" $ns_ at 129.000000 "$node_(10) setdest 511.499269 104.458277 16.396959" $ns_ at 130.000000 "$node_(1) setdest 380.319010 122.788460 19.998421" $ns_ at 130.000000 "$node_(2) setdest 326.114659 83.198800 19.999013" $ns_ at 130.000000 "$node_(3) setdest 361.450892 34.562067 19.999767" $ns_ at 130.000000 "$node_(4) setdest 461.047591 73.796428 8.178308" $ns_ at 130.000000 "$node_(5) setdest 310.805689 73.087262 19.992069" $ns_ at 130.000000 "$node_(6) setdest 580.472921 116.653619 6.495912" $ns_ at 130.000000 "$node_(7) setdest 586.575808 48.184730 1.938017" $ns_ at 130.000000 "$node_(8) setdest 485.758668 48.322000 19.999080" $ns_ at 130.000000 "$node_(9) setdest 446.859035 168.570017 7.566637" $ns_ at 130.000000 "$node_(10) setdest 497.658476 92.981586 17.980044" $ns_ at 131.000000 "$node_(1) setdest 360.365366 124.127494 19.998522" $ns_ at 131.000000 "$node_(2) setdest 306.164975 84.538799 19.994637" $ns_ at 131.000000 "$node_(3) setdest 341.453459 34.881321 19.999981" $ns_ at 131.000000 "$node_(4) setdest 451.277647 74.201781 9.778349" $ns_ at 131.000000 "$node_(5) setdest 290.929481 75.205162 19.988725" $ns_ at 131.000000 "$node_(6) setdest 575.708834 110.114534 8.090498" $ns_ at 131.000000 "$node_(7) setdest 583.023276 48.266735 3.553478" $ns_ at 131.000000 "$node_(8) setdest 468.711352 37.876329 19.993075" $ns_ at 131.000000 "$node_(9) setdest 451.428019 160.631101 9.159804" $ns_ at 131.000000 "$node_(10) setdest 485.035837 78.081245 19.528215" $ns_ at 132.000000 "$node_(1) setdest 340.372607 124.577953 19.997833" $ns_ at 132.000000 "$node_(2) setdest 286.178506 84.073191 19.991892" $ns_ at 132.000000 "$node_(3) setdest 321.454012 34.894377 19.999451" $ns_ at 132.000000 "$node_(4) setdest 439.923459 74.951472 11.378912" $ns_ at 132.000000 "$node_(5) setdest 271.481106 79.805860 19.985138" $ns_ at 132.000000 "$node_(6) setdest 571.726779 101.275821 9.694308" $ns_ at 132.000000 "$node_(7) setdest 577.934453 49.068828 5.151648" $ns_ at 132.000000 "$node_(8) setdest 450.507813 29.624318 19.986609" $ns_ at 132.000000 "$node_(9) setdest 457.527500 151.759105 10.766428" $ns_ at 132.000000 "$node_(10) setdest 474.583709 61.040590 19.990771" $ns_ at 133.000000 "$node_(1) setdest 320.380450 124.065568 19.998722" $ns_ at 133.000000 "$node_(2) setdest 266.383509 81.306673 19.987384" $ns_ at 133.000000 "$node_(3) setdest 301.478147 33.972686 19.997117" $ns_ at 133.000000 "$node_(4) setdest 426.974114 75.826178 12.978853" $ns_ at 133.000000 "$node_(5) setdest 252.963837 87.304381 19.977914" $ns_ at 133.000000 "$node_(6) setdest 568.310797 90.505002 11.299534" $ns_ at 133.000000 "$node_(7) setdest 571.352734 50.591970 6.755663" $ns_ at 133.000000 "$node_(8) setdest 430.748481 26.892605 19.947266" $ns_ at 133.000000 "$node_(9) setdest 464.585787 141.605483 12.365900" $ns_ at 133.000000 "$node_(10) setdest 461.707413 45.848981 19.914416" $ns_ at 134.000000 "$node_(1) setdest 300.449527 122.443033 19.996858" $ns_ at 134.000000 "$node_(2) setdest 247.068943 76.153410 19.990212" $ns_ at 134.000000 "$node_(3) setdest 281.620279 31.641423 19.994242" $ns_ at 134.000000 "$node_(4) setdest 412.407798 76.413196 14.578139" $ns_ at 134.000000 "$node_(5) setdest 236.182515 98.124469 19.967150" $ns_ at 134.000000 "$node_(6) setdest 565.493969 77.924687 12.891814" $ns_ at 134.000000 "$node_(7) setdest 563.139327 52.127120 8.355642" $ns_ at 134.000000 "$node_(8) setdest 416.947036 15.226109 18.071719" $ns_ at 134.000000 "$node_(9) setdest 472.330576 129.982714 13.966765" $ns_ at 134.000000 "$node_(10) setdest 445.040272 34.848403 19.970135" $ns_ at 135.000000 "$node_(1) setdest 280.660058 119.566270 19.997470" $ns_ at 135.000000 "$node_(2) setdest 228.579859 68.567935 19.984636" $ns_ at 135.000000 "$node_(3) setdest 261.870140 28.489966 19.999992" $ns_ at 135.000000 "$node_(4) setdest 396.230443 76.619532 16.178671" $ns_ at 135.000000 "$node_(5) setdest 221.570082 111.764000 19.988997" $ns_ at 135.000000 "$node_(6) setdest 565.462360 63.456976 14.467745" $ns_ at 135.000000 "$node_(7) setdest 553.580974 54.883009 9.947715" $ns_ at 135.000000 "$node_(8) setdest 426.301069 2.292969 15.961330" $ns_ at 135.000000 "$node_(9) setdest 481.564388 117.456807 15.561543" $ns_ at 135.000000 "$node_(10) setdest 426.598641 27.230647 19.953044" $ns_ at 136.000000 "$node_(1) setdest 260.964022 116.093665 19.999821" $ns_ at 136.000000 "$node_(2) setdest 211.157455 58.763950 19.991455" $ns_ at 136.000000 "$node_(3) setdest 242.069536 25.684400 19.998378" $ns_ at 136.000000 "$node_(4) setdest 378.451498 76.635633 17.778952" $ns_ at 136.000000 "$node_(5) setdest 207.405609 125.883222 19.999618" $ns_ at 136.000000 "$node_(6) setdest 570.550150 48.286694 16.000721" $ns_ at 136.000000 "$node_(7) setdest 543.178360 59.884928 11.542685" $ns_ at 136.000000 "$node_(8) setdest 439.426261 7.213786 14.017314" $ns_ at 136.000000 "$node_(9) setdest 492.799836 104.479486 17.165259" $ns_ at 136.000000 "$node_(10) setdest 416.515775 29.332216 10.299553" $ns_ at 137.000000 "$node_(1) setdest 241.166659 113.273096 19.997279" $ns_ at 137.000000 "$node_(2) setdest 193.607811 49.185768 19.993288" $ns_ at 137.000000 "$node_(3) setdest 222.148163 23.923978 19.999004" $ns_ at 137.000000 "$node_(4) setdest 359.072806 76.657629 19.378705" $ns_ at 137.000000 "$node_(5) setdest 192.886203 139.634471 19.997750" $ns_ at 137.000000 "$node_(6) setdest 583.970533 42.100482 14.777547" $ns_ at 137.000000 "$node_(7) setdest 532.296270 67.248819 13.139511" $ns_ at 137.000000 "$node_(8) setdest 453.839916 9.148842 14.542968" $ns_ at 137.000000 "$node_(9) setdest 505.861846 91.012627 18.760928" $ns_ at 137.000000 "$node_(10) setdest 417.284418 30.284041 1.223431" $ns_ at 138.000000 "$node_(1) setdest 221.227107 111.767797 19.996292" $ns_ at 138.000000 "$node_(2) setdest 175.271841 41.218919 19.991961" $ns_ at 138.000000 "$node_(3) setdest 202.333247 21.224188 19.997993" $ns_ at 138.000000 "$node_(4) setdest 339.081034 77.216611 19.999585" $ns_ at 138.000000 "$node_(5) setdest 177.604021 152.479213 19.963278" $ns_ at 138.000000 "$node_(6) setdest 588.327423 50.944124 9.858625" $ns_ at 138.000000 "$node_(7) setdest 521.858823 77.648040 14.733774" $ns_ at 138.000000 "$node_(8) setdest 470.072953 9.536007 16.237653" $ns_ at 138.000000 "$node_(9) setdest 520.526387 77.499927 19.940959" $ns_ at 138.000000 "$node_(10) setdest 420.076823 30.790374 2.837939" $ns_ at 139.000000 "$node_(1) setdest 201.240697 111.066682 19.998704" $ns_ at 139.000000 "$node_(2) setdest 164.466411 38.985513 11.033831" $ns_ at 139.000000 "$node_(3) setdest 184.238943 13.733066 19.583686" $ns_ at 139.000000 "$node_(4) setdest 319.132136 78.610994 19.997570" $ns_ at 139.000000 "$node_(5) setdest 159.330537 160.396138 19.914767" $ns_ at 139.000000 "$node_(6) setdest 588.282286 62.792033 11.847995" $ns_ at 139.000000 "$node_(7) setdest 512.243129 90.872745 16.350976" $ns_ at 139.000000 "$node_(8) setdest 487.878750 9.368775 17.806582" $ns_ at 139.000000 "$node_(9) setdest 536.534192 65.547922 19.977493" $ns_ at 139.000000 "$node_(10) setdest 424.324084 29.536639 4.428439" $ns_ at 140.000000 "$node_(1) setdest 181.242347 111.274656 19.999432" $ns_ at 140.000000 "$node_(2) setdest 175.502159 37.272010 11.167982" $ns_ at 140.000000 "$node_(3) setdest 182.074451 1.712658 12.213731" $ns_ at 140.000000 "$node_(4) setdest 299.283899 81.049008 19.997411" $ns_ at 140.000000 "$node_(5) setdest 139.532044 162.682204 19.930038" $ns_ at 140.000000 "$node_(6) setdest 589.138402 76.155223 13.390586" $ns_ at 140.000000 "$node_(7) setdest 501.789191 105.467392 17.952396" $ns_ at 140.000000 "$node_(8) setdest 505.637603 16.818056 19.257951" $ns_ at 140.000000 "$node_(9) setdest 554.813129 57.628754 19.920661" $ns_ at 140.000000 "$node_(10) setdest 429.800533 26.943825 6.059223" $ns_ at 141.000000 "$node_(1) setdest 161.247046 111.473323 19.996287" $ns_ at 141.000000 "$node_(2) setdest 185.373829 29.829709 12.362755" $ns_ at 141.000000 "$node_(3) setdest 183.778520 1.889613 1.713232" $ns_ at 141.000000 "$node_(4) setdest 279.550001 84.297092 19.999419" $ns_ at 141.000000 "$node_(5) setdest 119.793534 159.666849 19.967502" $ns_ at 141.000000 "$node_(6) setdest 592.156148 90.830024 14.981874" $ns_ at 141.000000 "$node_(7) setdest 488.189099 119.413179 19.479412" $ns_ at 141.000000 "$node_(8) setdest 523.321051 26.105433 19.973976" $ns_ at 141.000000 "$node_(9) setdest 571.486632 63.791740 17.776055" $ns_ at 141.000000 "$node_(10) setdest 436.921300 24.140901 7.652561" $ns_ at 142.000000 "$node_(1) setdest 141.772095 115.540184 19.895051" $ns_ at 142.000000 "$node_(2) setdest 196.339570 29.318053 10.977671" $ns_ at 142.000000 "$node_(3) setdest 184.812005 4.915605 3.197612" $ns_ at 142.000000 "$node_(4) setdest 259.803815 87.459443 19.997808" $ns_ at 142.000000 "$node_(5) setdest 100.096591 156.319135 19.979409" $ns_ at 142.000000 "$node_(6) setdest 590.692452 107.433540 16.667908" $ns_ at 142.000000 "$node_(7) setdest 471.797782 130.833795 19.977632" $ns_ at 142.000000 "$node_(8) setdest 541.126366 35.173355 19.981403" $ns_ at 142.000000 "$node_(9) setdest 567.782585 75.167477 11.963585" $ns_ at 142.000000 "$node_(10) setdest 446.013398 22.445407 9.248835" $ns_ at 143.000000 "$node_(1) setdest 127.450194 128.944032 19.615810" $ns_ at 143.000000 "$node_(2) setdest 197.147859 36.740438 7.466266" $ns_ at 143.000000 "$node_(3) setdest 185.893987 9.604906 4.812507" $ns_ at 143.000000 "$node_(4) setdest 239.858385 88.607005 19.978416" $ns_ at 143.000000 "$node_(5) setdest 80.175258 157.537770 19.958571" $ns_ at 143.000000 "$node_(6) setdest 585.791697 124.971994 18.210293" $ns_ at 143.000000 "$node_(7) setdest 454.924266 141.549003 19.988276" $ns_ at 143.000000 "$node_(8) setdest 556.871642 47.471369 19.978860" $ns_ at 143.000000 "$node_(9) setdest 558.206517 84.854499 13.621287" $ns_ at 143.000000 "$node_(10) setdest 456.841721 21.664948 10.856413" $ns_ at 144.000000 "$node_(1) setdest 118.524599 146.840858 19.999066" $ns_ at 144.000000 "$node_(2) setdest 196.591811 45.826445 9.103005" $ns_ at 144.000000 "$node_(3) setdest 187.092769 15.899568 6.407796" $ns_ at 144.000000 "$node_(4) setdest 220.066145 86.102236 19.950103" $ns_ at 144.000000 "$node_(5) setdest 60.964143 162.769298 19.910697" $ns_ at 144.000000 "$node_(6) setdest 574.313128 140.914141 19.644582" $ns_ at 144.000000 "$node_(7) setdest 441.557267 156.254138 19.872536" $ns_ at 144.000000 "$node_(8) setdest 571.374396 61.086555 19.892289" $ns_ at 144.000000 "$node_(9) setdest 552.626228 98.963335 15.172307" $ns_ at 144.000000 "$node_(10) setdest 469.299904 21.561095 12.458615" $ns_ at 145.000000 "$node_(1) setdest 112.115498 165.696718 19.915321" $ns_ at 145.000000 "$node_(2) setdest 190.250128 47.613148 6.588570" $ns_ at 145.000000 "$node_(3) setdest 187.313861 23.900730 8.004216" $ns_ at 145.000000 "$node_(4) setdest 203.065906 94.794565 19.093577" $ns_ at 145.000000 "$node_(5) setdest 45.972008 175.619703 19.745810" $ns_ at 145.000000 "$node_(6) setdest 560.255115 155.135300 19.996727" $ns_ at 145.000000 "$node_(7) setdest 438.601722 175.534770 19.505846" $ns_ at 145.000000 "$node_(8) setdest 588.750250 69.671374 19.380903" $ns_ at 145.000000 "$node_(9) setdest 551.878665 115.778256 16.831530" $ns_ at 145.000000 "$node_(10) setdest 483.345939 22.123346 14.057284" $ns_ at 146.000000 "$node_(1) setdest 111.731159 185.496144 19.803156" $ns_ at 146.000000 "$node_(2) setdest 183.547590 43.776632 7.722881" $ns_ at 146.000000 "$node_(3) setdest 185.862180 33.389020 9.598699" $ns_ at 146.000000 "$node_(4) setdest 190.626206 108.639388 18.612503" $ns_ at 146.000000 "$node_(5) setdest 47.072918 193.458445 17.872681" $ns_ at 146.000000 "$node_(6) setdest 545.916182 169.049201 19.980032" $ns_ at 146.000000 "$node_(7) setdest 444.782179 193.174570 18.691190" $ns_ at 146.000000 "$node_(8) setdest 586.255822 69.734557 2.495228" $ns_ at 146.000000 "$node_(9) setdest 554.631147 134.007561 18.435936" $ns_ at 146.000000 "$node_(10) setdest 498.884774 24.015570 15.653623" $ns_ at 147.000000 "$node_(1) setdest 111.899554 186.471049 0.989342" $ns_ at 147.000000 "$node_(2) setdest 175.795557 38.607572 9.317360" $ns_ at 147.000000 "$node_(3) setdest 182.523745 44.090935 11.210537" $ns_ at 147.000000 "$node_(4) setdest 179.070997 123.870067 19.117961" $ns_ at 147.000000 "$node_(5) setdest 62.376736 192.812895 15.317427" $ns_ at 147.000000 "$node_(6) setdest 531.919229 183.302102 19.976483" $ns_ at 147.000000 "$node_(7) setdest 436.724006 199.709287 10.374810" $ns_ at 147.000000 "$node_(8) setdest 576.168467 67.370369 10.360701" $ns_ at 147.000000 "$node_(9) setdest 562.586604 152.129905 19.791631" $ns_ at 147.000000 "$node_(10) setdest 515.441797 28.772088 17.226708" $ns_ at 148.000000 "$node_(1) setdest 108.990066 180.641200 6.515540" $ns_ at 148.000000 "$node_(2) setdest 167.327952 31.720295 10.914894" $ns_ at 148.000000 "$node_(3) setdest 179.086940 56.426752 12.805624" $ns_ at 148.000000 "$node_(4) setdest 163.850105 134.459779 18.542318" $ns_ at 148.000000 "$node_(5) setdest 69.482057 179.583763 15.016508" $ns_ at 148.000000 "$node_(6) setdest 513.623888 191.062746 19.873276" $ns_ at 148.000000 "$node_(7) setdest 426.833193 195.609739 10.706749" $ns_ at 148.000000 "$node_(8) setdest 564.268369 67.203121 11.901272" $ns_ at 148.000000 "$node_(9) setdest 570.951086 170.282477 19.987006" $ns_ at 148.000000 "$node_(10) setdest 531.755709 38.134043 18.809304" $ns_ at 149.000000 "$node_(1) setdest 104.753756 173.710069 8.123232" $ns_ at 149.000000 "$node_(2) setdest 156.878825 24.944390 12.453801" $ns_ at 149.000000 "$node_(3) setdest 176.599709 70.622921 14.412410" $ns_ at 149.000000 "$node_(4) setdest 146.434634 142.639565 19.240778" $ns_ at 149.000000 "$node_(5) setdest 75.707512 165.318603 15.564417" $ns_ at 149.000000 "$node_(6) setdest 493.935495 190.646337 19.692796" $ns_ at 149.000000 "$node_(7) setdest 417.399684 187.603159 12.373213" $ns_ at 149.000000 "$node_(8) setdest 551.157370 70.606676 13.545571" $ns_ at 149.000000 "$node_(9) setdest 576.243443 189.189175 19.633448" $ns_ at 149.000000 "$node_(10) setdest 546.734747 51.323269 19.958137" $ns_ at 150.000000 "$node_(1) setdest 99.278520 165.679385 9.719573" $ns_ at 150.000000 "$node_(2) setdest 143.075068 24.363392 13.815978" $ns_ at 150.000000 "$node_(3) setdest 173.400696 86.306718 16.006723" $ns_ at 150.000000 "$node_(4) setdest 130.649757 153.943580 19.415023" $ns_ at 150.000000 "$node_(5) setdest 88.488112 154.041636 17.044464" $ns_ at 150.000000 "$node_(6) setdest 475.349957 183.326049 19.975206" $ns_ at 150.000000 "$node_(7) setdest 414.624429 174.179041 13.707991" $ns_ at 150.000000 "$node_(8) setdest 537.189239 76.498837 15.160021" $ns_ at 150.000000 "$node_(9) setdest 575.465562 180.778988 8.446085" $ns_ at 150.000000 "$node_(10) setdest 560.401937 65.884227 19.970318" $ns_ at 151.000000 "$node_(1) setdest 91.813160 157.170777 11.319364" $ns_ at 151.000000 "$node_(2) setdest 138.004596 35.391633 12.138031" $ns_ at 151.000000 "$node_(3) setdest 168.114267 103.099736 17.605447" $ns_ at 151.000000 "$node_(4) setdest 119.996573 169.374810 18.751351" $ns_ at 151.000000 "$node_(5) setdest 105.657672 146.388340 18.798051" $ns_ at 151.000000 "$node_(6) setdest 459.956503 171.347805 19.504788" $ns_ at 151.000000 "$node_(7) setdest 416.813764 158.732695 15.600731" $ns_ at 151.000000 "$node_(8) setdest 521.788366 83.114604 16.761720" $ns_ at 151.000000 "$node_(9) setdest 577.687876 171.392622 9.645857" $ns_ at 151.000000 "$node_(10) setdest 569.087851 83.782994 19.894998" $ns_ at 152.000000 "$node_(1) setdest 82.097039 148.659628 12.916759" $ns_ at 152.000000 "$node_(2) setdest 146.119591 45.797946 13.196382" $ns_ at 152.000000 "$node_(3) setdest 160.937701 120.920891 19.211888" $ns_ at 152.000000 "$node_(4) setdest 105.936747 181.378621 18.487028" $ns_ at 152.000000 "$node_(5) setdest 124.801631 141.076851 19.867135" $ns_ at 152.000000 "$node_(6) setdest 448.544469 155.827294 19.264495" $ns_ at 152.000000 "$node_(7) setdest 417.880719 141.561761 17.204051" $ns_ at 152.000000 "$node_(8) setdest 503.612706 85.135031 18.287612" $ns_ at 152.000000 "$node_(9) setdest 582.520079 161.274967 11.212365" $ns_ at 152.000000 "$node_(10) setdest 569.702380 103.596801 19.823334" $ns_ at 153.000000 "$node_(1) setdest 70.379904 140.091185 14.515835" $ns_ at 153.000000 "$node_(2) setdest 158.134566 54.430381 14.794545" $ns_ at 153.000000 "$node_(3) setdest 156.219850 140.328761 19.973071" $ns_ at 153.000000 "$node_(4) setdest 88.725972 189.580626 19.065247" $ns_ at 153.000000 "$node_(5) setdest 144.327183 138.526583 19.691395" $ns_ at 153.000000 "$node_(6) setdest 442.382049 137.609253 19.232068" $ns_ at 153.000000 "$node_(7) setdest 416.376540 122.816638 18.805376" $ns_ at 153.000000 "$node_(8) setdest 483.914674 83.287628 19.784472" $ns_ at 153.000000 "$node_(9) setdest 586.204849 149.285184 12.543222" $ns_ at 153.000000 "$node_(10) setdest 559.010783 119.996465 19.577008" $ns_ at 154.000000 "$node_(1) setdest 55.997138 132.866034 16.095551" $ns_ at 154.000000 "$node_(2) setdest 172.406373 62.536019 16.412977" $ns_ at 154.000000 "$node_(3) setdest 151.635699 159.667002 19.874155" $ns_ at 154.000000 "$node_(4) setdest 78.054821 195.479620 12.193096" $ns_ at 154.000000 "$node_(5) setdest 163.592391 140.383876 19.354528" $ns_ at 154.000000 "$node_(6) setdest 441.383428 118.459568 19.175706" $ns_ at 154.000000 "$node_(7) setdest 412.338720 103.315957 19.914330" $ns_ at 154.000000 "$node_(8) setdest 464.344857 79.349340 19.962160" $ns_ at 154.000000 "$node_(9) setdest 576.816577 139.350201 13.669073" $ns_ at 154.000000 "$node_(10) setdest 540.866973 128.225326 19.922651" $ns_ at 155.000000 "$node_(1) setdest 41.252307 123.224103 17.617516" $ns_ at 155.000000 "$node_(2) setdest 186.611964 72.729002 17.484157" $ns_ at 155.000000 "$node_(3) setdest 144.090830 165.764530 9.700768" $ns_ at 155.000000 "$node_(4) setdest 84.150229 193.306525 6.471193" $ns_ at 155.000000 "$node_(5) setdest 178.718241 150.366969 18.123286" $ns_ at 155.000000 "$node_(6) setdest 439.600336 99.066105 19.475263" $ns_ at 155.000000 "$node_(7) setdest 407.087226 84.024775 19.993196" $ns_ at 155.000000 "$node_(8) setdest 447.207539 69.162889 19.936185" $ns_ at 155.000000 "$node_(9) setdest 561.438062 134.917972 16.004480" $ns_ at 155.000000 "$node_(10) setdest 526.487380 140.831521 19.122992" $ns_ at 156.000000 "$node_(1) setdest 34.078752 105.954513 18.700231" $ns_ at 156.000000 "$node_(2) setdest 187.094893 73.875178 1.243760" $ns_ at 156.000000 "$node_(3) setdest 141.135685 162.335572 4.526658" $ns_ at 156.000000 "$node_(4) setdest 92.326017 193.380787 8.176125" $ns_ at 156.000000 "$node_(5) setdest 191.326981 163.978216 18.553877" $ns_ at 156.000000 "$node_(6) setdest 441.938872 80.015861 19.193242" $ns_ at 156.000000 "$node_(7) setdest 410.869511 64.803585 19.589788" $ns_ at 156.000000 "$node_(8) setdest 431.974289 56.242401 19.974757" $ns_ at 156.000000 "$node_(9) setdest 545.448883 127.932357 17.448572" $ns_ at 156.000000 "$node_(10) setdest 515.851572 156.904956 19.273705" $ns_ at 157.000000 "$node_(1) setdest 43.916030 90.582641 18.250109" $ns_ at 157.000000 "$node_(2) setdest 185.047818 73.249294 2.140618" $ns_ at 157.000000 "$node_(3) setdest 137.743986 157.188007 6.164499" $ns_ at 157.000000 "$node_(4) setdest 102.029528 194.793971 9.805877" $ns_ at 157.000000 "$node_(5) setdest 189.463671 163.013794 2.098103" $ns_ at 157.000000 "$node_(6) setdest 447.800127 61.558044 19.366087" $ns_ at 157.000000 "$node_(7) setdest 421.274390 47.730933 19.993423" $ns_ at 157.000000 "$node_(8) setdest 417.596276 42.348809 19.993978" $ns_ at 157.000000 "$node_(9) setdest 533.516072 113.369140 18.827619" $ns_ at 157.000000 "$node_(10) setdest 508.458281 174.872098 19.428817" $ns_ at 158.000000 "$node_(1) setdest 55.511989 78.080336 17.052094" $ns_ at 158.000000 "$node_(2) setdest 181.442077 72.235518 3.745545" $ns_ at 158.000000 "$node_(3) setdest 134.731133 150.035278 7.761367" $ns_ at 158.000000 "$node_(4) setdest 113.388357 195.826949 11.405702" $ns_ at 158.000000 "$node_(5) setdest 189.430347 155.904971 7.108901" $ns_ at 158.000000 "$node_(6) setdest 451.172245 42.328961 19.522521" $ns_ at 158.000000 "$node_(7) setdest 430.947390 30.485112 19.773347" $ns_ at 158.000000 "$node_(8) setdest 416.344354 24.696906 17.696242" $ns_ at 158.000000 "$node_(9) setdest 532.772610 95.462924 17.921644" $ns_ at 158.000000 "$node_(10) setdest 499.709975 191.961210 19.198193" $ns_ at 159.000000 "$node_(1) setdest 62.113656 61.761513 17.603579" $ns_ at 159.000000 "$node_(2) setdest 176.123023 71.889821 5.330276" $ns_ at 159.000000 "$node_(3) setdest 131.954733 141.086339 9.369734" $ns_ at 159.000000 "$node_(4) setdest 126.380996 196.373692 13.004139" $ns_ at 159.000000 "$node_(5) setdest 187.683229 147.360821 8.720947" $ns_ at 159.000000 "$node_(6) setdest 451.279335 22.737061 19.592193" $ns_ at 159.000000 "$node_(7) setdest 436.024525 11.839659 19.324342" $ns_ at 159.000000 "$node_(8) setdest 426.226077 23.617931 9.940454" $ns_ at 159.000000 "$node_(9) setdest 526.035117 80.351338 16.545509" $ns_ at 159.000000 "$node_(10) setdest 503.894359 181.756466 11.029318" $ns_ at 160.000000 "$node_(1) setdest 65.960718 43.172044 18.983367" $ns_ at 160.000000 "$node_(2) setdest 169.348075 73.331064 6.926551" $ns_ at 160.000000 "$node_(3) setdest 128.796997 130.584343 10.966459" $ns_ at 160.000000 "$node_(4) setdest 140.930810 195.800748 14.561090" $ns_ at 160.000000 "$node_(5) setdest 187.045369 137.058154 10.322393" $ns_ at 160.000000 "$node_(6) setdest 444.402909 18.604950 8.022441" $ns_ at 160.000000 "$node_(7) setdest 434.909325 14.365720 2.761278" $ns_ at 160.000000 "$node_(8) setdest 424.301771 22.863179 2.067028" $ns_ at 160.000000 "$node_(9) setdest 512.812174 79.050168 13.286808" $ns_ at 160.000000 "$node_(10) setdest 495.740867 177.608074 9.148147" $ns_ at 161.000000 "$node_(1) setdest 72.042419 24.842076 19.312556" $ns_ at 161.000000 "$node_(2) setdest 161.871350 77.405615 8.514892" $ns_ at 161.000000 "$node_(3) setdest 126.355196 118.254232 12.569568" $ns_ at 161.000000 "$node_(4) setdest 150.057613 187.830197 12.117269" $ns_ at 161.000000 "$node_(5) setdest 187.048576 125.133800 11.924355" $ns_ at 161.000000 "$node_(6) setdest 434.736032 18.300064 9.671684" $ns_ at 161.000000 "$node_(7) setdest 431.202382 15.736051 3.952118" $ns_ at 161.000000 "$node_(8) setdest 421.173291 24.251968 3.422882" $ns_ at 161.000000 "$node_(9) setdest 497.627026 80.566955 15.260713" $ns_ at 161.000000 "$node_(10) setdest 485.182776 174.616363 10.973770" $ns_ at 162.000000 "$node_(1) setdest 76.823348 6.990102 18.481078" $ns_ at 162.000000 "$node_(2) setdest 155.188412 84.965774 10.090474" $ns_ at 162.000000 "$node_(3) setdest 123.148854 104.452853 14.168934" $ns_ at 162.000000 "$node_(4) setdest 146.530739 184.039119 5.177945" $ns_ at 162.000000 "$node_(5) setdest 185.580284 111.692807 13.520953" $ns_ at 162.000000 "$node_(6) setdest 423.465948 18.099012 11.271878" $ns_ at 162.000000 "$node_(7) setdest 426.070562 17.854362 5.551829" $ns_ at 162.000000 "$node_(8) setdest 416.609786 26.350567 5.022917" $ns_ at 162.000000 "$node_(9) setdest 480.789422 81.428650 16.859639" $ns_ at 162.000000 "$node_(10) setdest 473.049914 171.315733 12.573802" $ns_ at 163.000000 "$node_(1) setdest 74.663686 11.270534 4.794396" $ns_ at 163.000000 "$node_(2) setdest 150.947840 95.880837 11.709870" $ns_ at 163.000000 "$node_(3) setdest 117.765575 89.646315 15.754785" $ns_ at 163.000000 "$node_(4) setdest 140.287067 180.992837 6.947177" $ns_ at 163.000000 "$node_(5) setdest 184.617717 96.618690 15.104819" $ns_ at 163.000000 "$node_(6) setdest 410.594549 18.024662 12.871613" $ns_ at 163.000000 "$node_(7) setdest 419.556244 20.806580 7.152058" $ns_ at 163.000000 "$node_(8) setdest 410.491787 28.885939 6.622539" $ns_ at 163.000000 "$node_(9) setdest 462.331560 81.229685 18.458934" $ns_ at 163.000000 "$node_(10) setdest 459.326921 167.770043 14.173654" $ns_ at 164.000000 "$node_(1) setdest 77.700460 16.056801 5.668364" $ns_ at 164.000000 "$node_(2) setdest 148.502806 108.986321 13.331613" $ns_ at 164.000000 "$node_(3) setdest 109.149818 74.597894 17.340307" $ns_ at 164.000000 "$node_(4) setdest 131.820856 181.190189 8.468511" $ns_ at 164.000000 "$node_(5) setdest 185.147114 79.901197 16.725873" $ns_ at 164.000000 "$node_(6) setdest 396.123158 17.912799 14.471824" $ns_ at 164.000000 "$node_(7) setdest 411.667762 24.597608 8.752145" $ns_ at 164.000000 "$node_(8) setdest 402.783503 31.748758 8.222735" $ns_ at 164.000000 "$node_(9) setdest 442.549827 79.886156 19.827305" $ns_ at 164.000000 "$node_(10) setdest 443.980346 164.127469 15.772942" $ns_ at 165.000000 "$node_(1) setdest 80.751011 22.632665 7.248989" $ns_ at 165.000000 "$node_(2) setdest 147.928686 123.907075 14.931795" $ns_ at 165.000000 "$node_(3) setdest 96.035595 60.970960 18.912329" $ns_ at 165.000000 "$node_(4) setdest 122.502042 185.210639 10.149105" $ns_ at 165.000000 "$node_(5) setdest 185.141179 61.579353 18.321845" $ns_ at 165.000000 "$node_(6) setdest 380.051979 17.762097 16.071885" $ns_ at 165.000000 "$node_(7) setdest 402.404607 29.219681 10.352276" $ns_ at 165.000000 "$node_(8) setdest 393.507649 34.981420 9.823012" $ns_ at 165.000000 "$node_(9) setdest 422.735375 77.199676 19.995742" $ns_ at 165.000000 "$node_(10) setdest 426.942629 160.730540 17.373052" $ns_ at 166.000000 "$node_(1) setdest 82.726194 31.276530 8.866665" $ns_ at 166.000000 "$node_(2) setdest 148.987588 140.420750 16.547590" $ns_ at 166.000000 "$node_(3) setdest 78.637722 51.317801 19.896468" $ns_ at 166.000000 "$node_(4) setdest 111.343377 182.740860 11.428718" $ns_ at 166.000000 "$node_(5) setdest 183.940304 41.880407 19.735515" $ns_ at 166.000000 "$node_(6) setdest 362.380169 17.752944 17.671813" $ns_ at 166.000000 "$node_(7) setdest 391.653384 34.440900 11.951984" $ns_ at 166.000000 "$node_(8) setdest 382.669885 38.590161 11.422790" $ns_ at 166.000000 "$node_(9) setdest 403.199353 72.940877 19.994837" $ns_ at 166.000000 "$node_(10) setdest 408.274085 157.340788 18.973796" $ns_ at 167.000000 "$node_(1) setdest 83.836001 41.676120 10.458640" $ns_ at 167.000000 "$node_(2) setdest 153.399183 157.898562 18.025984" $ns_ at 167.000000 "$node_(3) setdest 58.975217 50.354423 19.686091" $ns_ at 167.000000 "$node_(4) setdest 103.966143 171.791634 13.202619" $ns_ at 167.000000 "$node_(5) setdest 192.412042 25.101152 18.796642" $ns_ at 167.000000 "$node_(6) setdest 343.128857 18.513654 19.266336" $ns_ at 167.000000 "$node_(7) setdest 379.364734 40.154703 13.552065" $ns_ at 167.000000 "$node_(8) setdest 370.163237 42.213745 13.021007" $ns_ at 167.000000 "$node_(9) setdest 384.109842 66.996327 19.993677" $ns_ at 167.000000 "$node_(10) setdest 388.699756 153.273291 19.992471" $ns_ at 168.000000 "$node_(1) setdest 84.894126 53.682119 12.052537" $ns_ at 168.000000 "$node_(2) setdest 167.272527 171.355308 19.327536" $ns_ at 168.000000 "$node_(3) setdest 50.795974 63.637111 15.599033" $ns_ at 168.000000 "$node_(4) setdest 99.748116 157.437131 14.961400" $ns_ at 168.000000 "$node_(5) setdest 198.947067 22.026635 7.222133" $ns_ at 168.000000 "$node_(6) setdest 323.346757 21.396871 19.991109" $ns_ at 168.000000 "$node_(7) setdest 365.975599 47.239433 15.148014" $ns_ at 168.000000 "$node_(8) setdest 355.878352 45.327028 14.620207" $ns_ at 168.000000 "$node_(9) setdest 365.020316 61.038320 19.997696" $ns_ at 168.000000 "$node_(10) setdest 369.105098 149.269829 19.999458" $ns_ at 169.000000 "$node_(1) setdest 89.451531 66.521653 13.624375" $ns_ at 169.000000 "$node_(2) setdest 185.788334 169.598855 18.598931" $ns_ at 169.000000 "$node_(3) setdest 57.023606 66.857513 7.011019" $ns_ at 169.000000 "$node_(4) setdest 94.375213 141.785412 16.548244" $ns_ at 169.000000 "$node_(5) setdest 197.685641 21.098308 1.566202" $ns_ at 169.000000 "$node_(6) setdest 303.800583 25.627234 19.998722" $ns_ at 169.000000 "$node_(7) setdest 351.976358 56.428967 16.745934" $ns_ at 169.000000 "$node_(8) setdest 339.845401 47.794114 16.221653" $ns_ at 169.000000 "$node_(9) setdest 345.625203 56.166910 19.997526" $ns_ at 169.000000 "$node_(10) setdest 349.412594 145.778646 19.999576" $ns_ at 170.000000 "$node_(1) setdest 98.595971 78.660537 15.197805" $ns_ at 170.000000 "$node_(2) setdest 191.824229 152.854155 17.799355" $ns_ at 170.000000 "$node_(3) setdest 65.505872 65.288800 8.626105" $ns_ at 170.000000 "$node_(4) setdest 84.771789 126.399680 18.136882" $ns_ at 170.000000 "$node_(5) setdest 194.447590 20.748193 3.256924" $ns_ at 170.000000 "$node_(6) setdest 284.422089 30.561769 19.996891" $ns_ at 170.000000 "$node_(7) setdest 336.488392 66.266943 18.348375" $ns_ at 170.000000 "$node_(8) setdest 322.137911 49.798598 17.820583" $ns_ at 170.000000 "$node_(9) setdest 325.954317 52.576373 19.995892" $ns_ at 170.000000 "$node_(10) setdest 329.735957 142.201287 19.999189" $ns_ at 171.000000 "$node_(1) setdest 112.977297 87.271027 16.761953" $ns_ at 171.000000 "$node_(2) setdest 191.611035 136.352639 16.502893" $ns_ at 171.000000 "$node_(3) setdest 75.600405 63.592078 10.236135" $ns_ at 171.000000 "$node_(4) setdest 69.325659 114.455881 19.525298" $ns_ at 171.000000 "$node_(5) setdest 189.626370 20.167736 4.856036" $ns_ at 171.000000 "$node_(6) setdest 265.427300 36.816797 19.998184" $ns_ at 171.000000 "$node_(7) setdest 319.125355 75.725898 19.772377" $ns_ at 171.000000 "$node_(8) setdest 302.740361 50.564467 19.412663" $ns_ at 171.000000 "$node_(9) setdest 306.097225 50.200000 19.998782" $ns_ at 171.000000 "$node_(10) setdest 310.324303 137.409564 19.994322" $ns_ at 172.000000 "$node_(1) setdest 130.889740 91.652087 18.440426" $ns_ at 172.000000 "$node_(2) setdest 188.195099 119.984720 16.720568" $ns_ at 172.000000 "$node_(3) setdest 87.261624 61.566337 11.835863" $ns_ at 172.000000 "$node_(4) setdest 50.408455 108.069384 19.966171" $ns_ at 172.000000 "$node_(5) setdest 183.210315 19.462493 6.454698" $ns_ at 172.000000 "$node_(6) setdest 246.804372 44.105199 19.998357" $ns_ at 172.000000 "$node_(7) setdest 300.903681 83.960245 19.995847" $ns_ at 172.000000 "$node_(8) setdest 282.761368 49.802834 19.993506" $ns_ at 172.000000 "$node_(9) setdest 286.178420 48.427559 19.997508" $ns_ at 172.000000 "$node_(10) setdest 291.419852 130.900985 19.993495" $ns_ at 173.000000 "$node_(1) setdest 150.117221 96.445478 19.815968" $ns_ at 173.000000 "$node_(2) setdest 186.605797 101.739334 18.314476" $ns_ at 173.000000 "$node_(3) setdest 100.596739 59.980711 13.429055" $ns_ at 173.000000 "$node_(4) setdest 30.490170 107.030632 19.945353" $ns_ at 173.000000 "$node_(5) setdest 175.384564 17.552862 8.055375" $ns_ at 173.000000 "$node_(6) setdest 228.279753 51.641445 19.998913" $ns_ at 173.000000 "$node_(7) setdest 282.201859 91.043224 19.998168" $ns_ at 173.000000 "$node_(8) setdest 263.086759 46.344289 19.976279" $ns_ at 173.000000 "$node_(9) setdest 266.189461 47.940458 19.994893" $ns_ at 173.000000 "$node_(10) setdest 273.195059 122.679443 19.993419" $ns_ at 174.000000 "$node_(1) setdest 168.902350 103.226473 19.971554" $ns_ at 174.000000 "$node_(2) setdest 184.513754 82.093305 19.757102" $ns_ at 174.000000 "$node_(3) setdest 115.623096 60.000922 15.026371" $ns_ at 174.000000 "$node_(4) setdest 11.378375 105.199769 19.199290" $ns_ at 174.000000 "$node_(5) setdest 165.905684 15.739495 9.650776" $ns_ at 174.000000 "$node_(6) setdest 210.524312 60.821660 19.988297" $ns_ at 174.000000 "$node_(7) setdest 263.237099 97.391304 19.999006" $ns_ at 174.000000 "$node_(8) setdest 244.452806 39.179900 19.963784" $ns_ at 174.000000 "$node_(9) setdest 246.259591 49.492870 19.990241" $ns_ at 174.000000 "$node_(10) setdest 255.875893 112.695630 19.990749" $ns_ at 175.000000 "$node_(1) setdest 179.680069 118.492693 18.687341" $ns_ at 175.000000 "$node_(2) setdest 180.258778 62.740869 19.814682" $ns_ at 175.000000 "$node_(3) setdest 132.021670 62.570627 16.598693" $ns_ at 175.000000 "$node_(4) setdest 5.755446 88.484328 17.635853" $ns_ at 175.000000 "$node_(5) setdest 155.223912 16.670444 10.722262" $ns_ at 175.000000 "$node_(6) setdest 194.092342 72.196532 19.984929" $ns_ at 175.000000 "$node_(7) setdest 244.024859 102.944527 19.998711" $ns_ at 175.000000 "$node_(8) setdest 226.039257 31.479843 19.958700" $ns_ at 175.000000 "$node_(9) setdest 226.666973 53.441639 19.986582" $ns_ at 175.000000 "$node_(10) setdest 239.867016 100.730485 19.986216" $ns_ at 176.000000 "$node_(1) setdest 178.455056 113.826735 4.824088" $ns_ at 176.000000 "$node_(2) setdest 170.317497 46.270492 19.238045" $ns_ at 176.000000 "$node_(3) setdest 148.852278 69.512159 18.205884" $ns_ at 176.000000 "$node_(4) setdest 7.747696 72.189753 16.415914" $ns_ at 176.000000 "$node_(5) setdest 155.067960 17.267330 0.616923" $ns_ at 176.000000 "$node_(6) setdest 179.520253 85.870172 19.982848" $ns_ at 176.000000 "$node_(7) setdest 224.758061 108.308526 19.999549" $ns_ at 176.000000 "$node_(8) setdest 206.348654 28.206572 19.960815" $ns_ at 176.000000 "$node_(9) setdest 207.773501 59.963121 19.987322" $ns_ at 176.000000 "$node_(10) setdest 225.733708 86.607919 19.979922" $ns_ at 177.000000 "$node_(1) setdest 175.246544 108.496016 6.221826" $ns_ at 177.000000 "$node_(2) setdest 157.726290 31.362125 19.514044" $ns_ at 177.000000 "$node_(3) setdest 164.683417 81.103727 19.621148" $ns_ at 177.000000 "$node_(4) setdest 17.513917 60.031501 15.594941" $ns_ at 177.000000 "$node_(5) setdest 156.535342 17.780235 1.554439" $ns_ at 177.000000 "$node_(6) setdest 167.122891 101.545865 19.985543" $ns_ at 177.000000 "$node_(7) setdest 205.299075 112.923724 19.998805" $ns_ at 177.000000 "$node_(8) setdest 186.493072 30.105946 19.946222" $ns_ at 177.000000 "$node_(9) setdest 189.928589 68.956396 19.982989" $ns_ at 177.000000 "$node_(10) setdest 213.261658 71.046403 19.942738" $ns_ at 178.000000 "$node_(1) setdest 172.424003 101.197065 7.825690" $ns_ at 178.000000 "$node_(2) setdest 142.888376 19.133692 19.227539" $ns_ at 178.000000 "$node_(3) setdest 174.810337 98.211073 19.880034" $ns_ at 178.000000 "$node_(4) setdest 31.152481 49.569283 17.189195" $ns_ at 178.000000 "$node_(5) setdest 159.699097 18.019297 3.172774" $ns_ at 178.000000 "$node_(6) setdest 157.052647 118.802745 19.980234" $ns_ at 178.000000 "$node_(7) setdest 185.768249 117.229326 19.999784" $ns_ at 178.000000 "$node_(8) setdest 167.818405 37.111714 19.945525" $ns_ at 178.000000 "$node_(9) setdest 173.871013 80.833808 19.972948" $ns_ at 178.000000 "$node_(10) setdest 196.419365 70.738967 16.845098" $ns_ at 179.000000 "$node_(1) setdest 170.753363 91.918408 9.427858" $ns_ at 179.000000 "$node_(2) setdest 125.010723 12.749372 18.983414" $ns_ at 179.000000 "$node_(3) setdest 181.874760 116.920836 19.999033" $ns_ at 179.000000 "$node_(4) setdest 46.551054 38.789818 18.796620" $ns_ at 179.000000 "$node_(5) setdest 163.906434 16.048997 4.645834" $ns_ at 179.000000 "$node_(6) setdest 150.159618 137.551322 19.975559" $ns_ at 179.000000 "$node_(7) setdest 166.344084 121.993628 19.999919" $ns_ at 179.000000 "$node_(8) setdest 150.738069 47.480338 19.981147" $ns_ at 179.000000 "$node_(9) setdest 160.581359 95.722920 19.957469" $ns_ at 179.000000 "$node_(10) setdest 195.672687 84.091040 13.372934" $ns_ at 180.000000 "$node_(1) setdest 170.379290 80.898702 11.026053" $ns_ at 180.000000 "$node_(2) setdest 106.108663 11.307135 18.957001" $ns_ at 180.000000 "$node_(3) setdest 186.831517 136.224536 19.929934" $ns_ at 180.000000 "$node_(4) setdest 63.824239 28.948857 19.879825" $ns_ at 180.000000 "$node_(5) setdest 169.419179 13.556525 6.050023" $ns_ at 180.000000 "$node_(6) setdest 147.828308 157.269197 19.855216" $ns_ at 180.000000 "$node_(7) setdest 147.059157 127.267473 19.993046" $ns_ at 180.000000 "$node_(8) setdest 134.966214 59.765581 19.991963" $ns_ at 180.000000 "$node_(9) setdest 151.747848 113.601200 19.941509" $ns_ at 180.000000 "$node_(10) setdest 189.493134 92.502152 10.437130" $ns_ at 181.000000 "$node_(1) setdest 171.163052 68.288192 12.634842" $ns_ at 181.000000 "$node_(2) setdest 91.123305 20.053465 17.351060" $ns_ at 181.000000 "$node_(3) setdest 188.637831 156.141046 19.998253" $ns_ at 181.000000 "$node_(4) setdest 82.685943 28.747684 18.862777" $ns_ at 181.000000 "$node_(5) setdest 172.747269 19.290485 6.629817" $ns_ at 181.000000 "$node_(6) setdest 160.476531 170.330272 18.181563" $ns_ at 181.000000 "$node_(7) setdest 128.509912 134.706388 19.985292" $ns_ at 181.000000 "$node_(8) setdest 117.253969 68.951910 19.952752" $ns_ at 181.000000 "$node_(9) setdest 145.153561 132.482364 19.999575" $ns_ at 181.000000 "$node_(10) setdest 178.683836 98.024600 12.138302" $ns_ at 182.000000 "$node_(1) setdest 172.888706 54.198358 14.195116" $ns_ at 182.000000 "$node_(2) setdest 83.890009 35.949121 17.464032" $ns_ at 182.000000 "$node_(3) setdest 190.094980 176.021799 19.934083" $ns_ at 182.000000 "$node_(4) setdest 96.855632 39.340425 17.691417" $ns_ at 182.000000 "$node_(5) setdest 173.027925 27.952089 8.666149" $ns_ at 182.000000 "$node_(6) setdest 177.244737 175.603016 17.577672" $ns_ at 182.000000 "$node_(7) setdest 111.416146 145.032855 19.970798" $ns_ at 182.000000 "$node_(8) setdest 97.650034 72.426294 19.909435" $ns_ at 182.000000 "$node_(9) setdest 139.260466 151.590578 19.996310" $ns_ at 182.000000 "$node_(10) setdest 167.962697 106.536181 13.689040" $ns_ at 183.000000 "$node_(1) setdest 180.428826 40.405392 15.719393" $ns_ at 183.000000 "$node_(2) setdest 80.665629 54.207418 18.540821" $ns_ at 183.000000 "$node_(3) setdest 196.076606 187.662698 13.087794" $ns_ at 183.000000 "$node_(4) setdest 113.096835 43.407822 16.742771" $ns_ at 183.000000 "$node_(5) setdest 175.004921 38.052270 10.291850" $ns_ at 183.000000 "$node_(6) setdest 192.567746 173.044954 15.535067" $ns_ at 183.000000 "$node_(7) setdest 94.933105 156.301721 19.966922" $ns_ at 183.000000 "$node_(8) setdest 78.202415 68.303846 19.879749" $ns_ at 183.000000 "$node_(9) setdest 128.466810 168.153105 19.769176" $ns_ at 183.000000 "$node_(10) setdest 155.692441 115.659456 15.290302" $ns_ at 184.000000 "$node_(1) setdest 194.682139 32.290056 16.401695" $ns_ at 184.000000 "$node_(2) setdest 71.721236 70.341996 18.447948" $ns_ at 184.000000 "$node_(3) setdest 195.005636 184.210017 3.614967" $ns_ at 184.000000 "$node_(4) setdest 131.373418 43.329977 18.276749" $ns_ at 184.000000 "$node_(5) setdest 177.681189 49.641032 11.893773" $ns_ at 184.000000 "$node_(6) setdest 192.538130 172.725928 0.320398" $ns_ at 184.000000 "$node_(7) setdest 76.208559 163.180223 19.947993" $ns_ at 184.000000 "$node_(8) setdest 59.386392 61.528995 19.998534" $ns_ at 184.000000 "$node_(9) setdest 119.659162 170.816167 9.201443" $ns_ at 184.000000 "$node_(10) setdest 139.468774 119.990598 16.791848" $ns_ at 185.000000 "$node_(1) setdest 195.613467 33.069178 1.214250" $ns_ at 185.000000 "$node_(2) setdest 72.027737 89.787372 19.447792" $ns_ at 185.000000 "$node_(3) setdest 194.672645 188.582756 4.385400" $ns_ at 185.000000 "$node_(4) setdest 134.492679 47.692958 5.363338" $ns_ at 185.000000 "$node_(5) setdest 173.964993 62.431439 13.319333" $ns_ at 185.000000 "$node_(6) setdest 191.099665 172.527656 1.452065" $ns_ at 185.000000 "$node_(7) setdest 56.380453 165.404161 19.952436" $ns_ at 185.000000 "$node_(8) setdest 40.804330 54.137082 19.998335" $ns_ at 185.000000 "$node_(9) setdest 119.805941 169.859912 0.967454" $ns_ at 185.000000 "$node_(10) setdest 121.371407 116.477413 18.435216" $ns_ at 186.000000 "$node_(1) setdest 195.523460 35.547228 2.479684" $ns_ at 186.000000 "$node_(2) setdest 72.860222 109.769952 19.999913" $ns_ at 186.000000 "$node_(3) setdest 193.465576 194.532746 6.071194" $ns_ at 186.000000 "$node_(4) setdest 134.472696 54.482129 6.789201" $ns_ at 186.000000 "$node_(5) setdest 169.445995 76.675295 14.943519" $ns_ at 186.000000 "$node_(6) setdest 188.017704 172.548818 3.082034" $ns_ at 186.000000 "$node_(7) setdest 36.936529 161.362410 19.859555" $ns_ at 186.000000 "$node_(8) setdest 21.592497 48.640305 19.982719" $ns_ at 186.000000 "$node_(9) setdest 120.575903 167.393762 2.583551" $ns_ at 186.000000 "$node_(10) setdest 104.372214 106.231584 19.848162" $ns_ at 187.000000 "$node_(1) setdest 195.465659 39.626432 4.079614" $ns_ at 187.000000 "$node_(2) setdest 73.033876 129.767033 19.997835" $ns_ at 187.000000 "$node_(3) setdest 192.328990 202.117959 7.669894" $ns_ at 187.000000 "$node_(4) setdest 134.718626 62.867220 8.388696" $ns_ at 187.000000 "$node_(5) setdest 165.002660 92.609977 16.542591" $ns_ at 187.000000 "$node_(6) setdest 183.363363 172.076516 4.678243" $ns_ at 187.000000 "$node_(7) setdest 27.040671 147.302132 17.193587" $ns_ at 187.000000 "$node_(8) setdest 15.086590 34.481154 15.582310" $ns_ at 187.000000 "$node_(9) setdest 122.262624 163.566603 4.182365" $ns_ at 187.000000 "$node_(10) setdest 87.019330 96.377428 19.955625" $ns_ at 188.000000 "$node_(1) setdest 195.493442 45.306014 5.679650" $ns_ at 188.000000 "$node_(2) setdest 72.088632 149.742168 19.997487" $ns_ at 188.000000 "$node_(3) setdest 191.694603 211.364885 9.268662" $ns_ at 188.000000 "$node_(4) setdest 135.397225 72.832879 9.988737" $ns_ at 188.000000 "$node_(5) setdest 160.860419 110.273346 18.142567" $ns_ at 188.000000 "$node_(6) setdest 177.331385 170.366266 6.269746" $ns_ at 188.000000 "$node_(7) setdest 33.339932 142.144690 8.141247" $ns_ at 188.000000 "$node_(8) setdest 25.950932 28.357513 12.471284" $ns_ at 188.000000 "$node_(9) setdest 125.574753 158.840877 5.770848" $ns_ at 188.000000 "$node_(10) setdest 73.723879 81.531864 19.928868" $ns_ at 189.000000 "$node_(1) setdest 195.501926 52.585695 7.279686" $ns_ at 189.000000 "$node_(2) setdest 70.118723 169.643281 19.998371" $ns_ at 189.000000 "$node_(3) setdest 191.784503 222.234607 10.870094" $ns_ at 189.000000 "$node_(4) setdest 136.587465 84.360558 11.588963" $ns_ at 189.000000 "$node_(5) setdest 157.134792 129.574013 19.656960" $ns_ at 189.000000 "$node_(6) setdest 170.511875 166.445811 7.866110" $ns_ at 189.000000 "$node_(7) setdest 42.075135 137.545000 9.872230" $ns_ at 189.000000 "$node_(8) setdest 39.756298 24.207709 14.415582" $ns_ at 189.000000 "$node_(9) setdest 131.266657 154.174797 7.360033" $ns_ at 189.000000 "$node_(10) setdest 62.437001 65.038639 19.985497" $ns_ at 190.000000 "$node_(1) setdest 195.416493 61.464644 8.879359" $ns_ at 190.000000 "$node_(2) setdest 67.278825 189.439428 19.998811" $ns_ at 190.000000 "$node_(3) setdest 192.074302 234.702462 12.471222" $ns_ at 190.000000 "$node_(4) setdest 138.172614 97.454006 13.189051" $ns_ at 190.000000 "$node_(5) setdest 154.020435 149.328771 19.998742" $ns_ at 190.000000 "$node_(6) setdest 163.520779 160.060724 9.468092" $ns_ at 190.000000 "$node_(7) setdest 51.690561 131.290754 11.470484" $ns_ at 190.000000 "$node_(8) setdest 55.087819 19.437284 16.056541" $ns_ at 190.000000 "$node_(9) setdest 139.311546 150.191848 8.976865" $ns_ at 190.000000 "$node_(10) setdest 59.419189 45.948052 19.327640" $ns_ at 191.000000 "$node_(1) setdest 195.032236 71.937101 10.479504" $ns_ at 191.000000 "$node_(2) setdest 63.774126 209.129366 19.999414" $ns_ at 191.000000 "$node_(3) setdest 192.134525 248.773197 14.070864" $ns_ at 191.000000 "$node_(4) setdest 140.151210 112.110209 14.789156" $ns_ at 191.000000 "$node_(5) setdest 151.528492 169.172266 19.999351" $ns_ at 191.000000 "$node_(6) setdest 156.653106 151.371539 11.075507" $ns_ at 191.000000 "$node_(7) setdest 61.020362 122.160481 13.054006" $ns_ at 191.000000 "$node_(8) setdest 72.246356 15.431568 17.619908" $ns_ at 191.000000 "$node_(9) setdest 149.037901 146.020315 10.583179" $ns_ at 191.000000 "$node_(10) setdest 62.233515 26.981985 19.173735" $ns_ at 192.000000 "$node_(1) setdest 194.328858 83.995651 12.079047" $ns_ at 192.000000 "$node_(2) setdest 60.068139 228.782066 19.999074" $ns_ at 192.000000 "$node_(3) setdest 191.210367 264.413225 15.667308" $ns_ at 192.000000 "$node_(4) setdest 142.034412 128.390629 16.388976" $ns_ at 192.000000 "$node_(5) setdest 149.209226 189.037194 19.999859" $ns_ at 192.000000 "$node_(6) setdest 149.885588 140.648727 12.679826" $ns_ at 192.000000 "$node_(7) setdest 70.178665 110.699923 14.670341" $ns_ at 192.000000 "$node_(8) setdest 91.480263 14.579377 19.252776" $ns_ at 192.000000 "$node_(9) setdest 160.621424 145.650484 11.589425" $ns_ at 192.000000 "$node_(10) setdest 71.531198 10.851366 18.618372" $ns_ at 193.000000 "$node_(1) setdest 193.150556 97.624358 13.679549" $ns_ at 193.000000 "$node_(2) setdest 56.962041 248.539067 19.999673" $ns_ at 193.000000 "$node_(3) setdest 188.728422 281.499973 17.266065" $ns_ at 193.000000 "$node_(4) setdest 143.661611 146.305417 17.988535" $ns_ at 193.000000 "$node_(5) setdest 146.639128 208.871240 19.999870" $ns_ at 193.000000 "$node_(6) setdest 141.678111 128.965386 14.278065" $ns_ at 193.000000 "$node_(7) setdest 77.526460 96.240451 16.219323" $ns_ at 193.000000 "$node_(8) setdest 111.285642 11.901841 19.985551" $ns_ at 193.000000 "$node_(9) setdest 162.320582 151.191100 5.795306" $ns_ at 193.000000 "$node_(10) setdest 69.434904 14.512209 4.218556" $ns_ at 194.000000 "$node_(1) setdest 191.331293 112.793988 15.278331" $ns_ at 194.000000 "$node_(2) setdest 54.045499 268.325206 19.999938" $ns_ at 194.000000 "$node_(3) setdest 184.809887 299.958796 18.870163" $ns_ at 194.000000 "$node_(4) setdest 144.576980 165.824228 19.540263" $ns_ at 194.000000 "$node_(5) setdest 143.541952 228.628802 19.998844" $ns_ at 194.000000 "$node_(6) setdest 132.011405 116.363647 15.882350" $ns_ at 194.000000 "$node_(7) setdest 81.390315 78.832201 17.831897" $ns_ at 194.000000 "$node_(8) setdest 130.995388 8.526521 19.996672" $ns_ at 194.000000 "$node_(9) setdest 158.304055 156.109234 6.349844" $ns_ at 194.000000 "$node_(10) setdest 64.357297 23.822765 10.605120" $ns_ at 195.000000 "$node_(1) setdest 188.282059 129.392447 16.876216" $ns_ at 195.000000 "$node_(2) setdest 51.150472 288.114471 19.999904" $ns_ at 195.000000 "$node_(3) setdest 179.637007 319.243200 19.966145" $ns_ at 195.000000 "$node_(4) setdest 144.982177 185.819869 19.999746" $ns_ at 195.000000 "$node_(5) setdest 139.870629 248.288518 19.999576" $ns_ at 195.000000 "$node_(6) setdest 122.921583 101.453520 17.462438" $ns_ at 195.000000 "$node_(7) setdest 80.824768 59.414565 19.425870" $ns_ at 195.000000 "$node_(8) setdest 150.685052 6.112369 19.837111" $ns_ at 195.000000 "$node_(9) setdest 153.669623 162.564787 7.946831" $ns_ at 195.000000 "$node_(10) setdest 62.963882 36.031903 12.288395" $ns_ at 196.000000 "$node_(1) setdest 183.957321 147.358510 18.479253" $ns_ at 196.000000 "$node_(2) setdest 48.611087 307.952411 19.999809" $ns_ at 196.000000 "$node_(3) setdest 172.922634 338.070779 19.989011" $ns_ at 196.000000 "$node_(4) setdest 145.105736 205.819344 19.999857" $ns_ at 196.000000 "$node_(5) setdest 135.716006 267.851495 19.999273" $ns_ at 196.000000 "$node_(6) setdest 114.965812 84.111046 19.080244" $ns_ at 196.000000 "$node_(7) setdest 77.199943 39.771797 19.974427" $ns_ at 196.000000 "$node_(8) setdest 170.172454 10.569598 19.990641" $ns_ at 196.000000 "$node_(9) setdest 146.820750 169.209669 9.542616" $ns_ at 196.000000 "$node_(10) setdest 65.562221 49.704614 13.917413" $ns_ at 197.000000 "$node_(1) setdest 179.424231 166.672897 19.839215" $ns_ at 197.000000 "$node_(2) setdest 46.811525 327.868842 19.997566" $ns_ at 197.000000 "$node_(3) setdest 163.939414 355.929108 19.990452" $ns_ at 197.000000 "$node_(4) setdest 145.006109 225.818471 19.999375" $ns_ at 197.000000 "$node_(5) setdest 130.662166 287.197475 19.995206" $ns_ at 197.000000 "$node_(6) setdest 106.357417 66.062345 19.996501" $ns_ at 197.000000 "$node_(7) setdest 75.946021 20.181201 19.630684" $ns_ at 197.000000 "$node_(8) setdest 188.099728 18.417830 19.569923" $ns_ at 197.000000 "$node_(9) setdest 138.645810 176.738594 11.113701" $ns_ at 197.000000 "$node_(10) setdest 71.277978 64.136289 15.522342" $ns_ at 198.000000 "$node_(1) setdest 175.356307 186.254820 19.999992" $ns_ at 198.000000 "$node_(2) setdest 45.427324 347.820835 19.999951" $ns_ at 198.000000 "$node_(3) setdest 152.416252 372.246071 19.975649" $ns_ at 198.000000 "$node_(4) setdest 143.832197 245.780166 19.996183" $ns_ at 198.000000 "$node_(5) setdest 123.549176 305.874927 19.986041" $ns_ at 198.000000 "$node_(6) setdest 95.007893 49.716550 19.899666" $ns_ at 198.000000 "$node_(7) setdest 89.910882 8.256505 18.363434" $ns_ at 198.000000 "$node_(8) setdest 186.767229 35.321285 16.955895" $ns_ at 198.000000 "$node_(9) setdest 140.360459 185.666801 9.091364" $ns_ at 198.000000 "$node_(10) setdest 79.585340 79.054188 17.075010" $ns_ at 199.000000 "$node_(1) setdest 171.310371 205.841290 19.999985" $ns_ at 199.000000 "$node_(2) setdest 45.246485 367.808943 19.988926" $ns_ at 199.000000 "$node_(3) setdest 141.026187 379.353825 13.425861" $ns_ at 199.000000 "$node_(4) setdest 141.471649 265.638334 19.997976" $ns_ at 199.000000 "$node_(5) setdest 113.615585 323.205618 19.975712" $ns_ at 199.000000 "$node_(6) setdest 77.769915 49.534854 17.238935" $ns_ at 199.000000 "$node_(7) setdest 106.824065 10.366785 17.044326" $ns_ at 199.000000 "$node_(8) setdest 175.640526 47.155431 16.243476" $ns_ at 199.000000 "$node_(9) setdest 145.881782 184.022631 5.760929" $ns_ at 199.000000 "$node_(10) setdest 88.755604 95.337817 18.688240" $ns_ at 200.000000 "$node_(1) setdest 167.224719 225.419522 19.999993" $ns_ at 200.000000 "$node_(2) setdest 49.050666 387.354600 19.912420" $ns_ at 200.000000 "$node_(3) setdest 144.119591 377.312601 3.706177" $ns_ at 200.000000 "$node_(4) setdest 138.256986 285.377161 19.998884" $ns_ at 200.000000 "$node_(5) setdest 100.527566 338.285629 19.967548" $ns_ at 200.000000 "$node_(6) setdest 72.091162 65.514596 16.958785" $ns_ at 200.000000 "$node_(7) setdest 122.081158 16.304017 16.371610" $ns_ at 200.000000 "$node_(8) setdest 160.926667 51.839992 15.441592" $ns_ at 200.000000 "$node_(9) setdest 149.142428 177.126205 7.628401" $ns_ at 200.000000 "$node_(10) setdest 99.613365 111.937528 19.835356" $ns_ at 201.000000 "$node_(1) setdest 163.241486 245.018750 19.999897" $ns_ at 201.000000 "$node_(2) setdest 61.654558 402.610167 19.788644" $ns_ at 201.000000 "$node_(3) setdest 149.076068 375.294812 5.351461" $ns_ at 201.000000 "$node_(4) setdest 134.200711 304.958942 19.997488" $ns_ at 201.000000 "$node_(5) setdest 84.538504 350.240382 19.964123" $ns_ at 201.000000 "$node_(6) setdest 67.136324 80.376662 15.666251" $ns_ at 201.000000 "$node_(7) setdest 139.717702 18.648063 17.791633" $ns_ at 201.000000 "$node_(8) setdest 145.832431 59.287246 16.831446" $ns_ at 201.000000 "$node_(9) setdest 152.552155 168.551362 9.227902" $ns_ at 201.000000 "$node_(10) setdest 117.014782 121.404332 19.809839" $ns_ at 202.000000 "$node_(1) setdest 159.391115 264.644218 19.999609" $ns_ at 202.000000 "$node_(2) setdest 78.236392 413.777419 19.991617" $ns_ at 202.000000 "$node_(3) setdest 155.820516 373.560161 6.963950" $ns_ at 202.000000 "$node_(4) setdest 129.372934 324.366691 19.999203" $ns_ at 202.000000 "$node_(5) setdest 66.671342 359.206049 19.990464" $ns_ at 202.000000 "$node_(6) setdest 59.005599 94.783951 16.543236" $ns_ at 202.000000 "$node_(7) setdest 158.694781 17.342255 19.021952" $ns_ at 202.000000 "$node_(8) setdest 128.180124 62.164422 17.885247" $ns_ at 202.000000 "$node_(9) setdest 155.239978 158.052038 10.837906" $ns_ at 202.000000 "$node_(10) setdest 136.907991 122.875448 19.947530" $ns_ at 203.000000 "$node_(1) setdest 156.090421 284.369430 19.999465" $ns_ at 203.000000 "$node_(2) setdest 95.064626 424.526948 19.968521" $ns_ at 203.000000 "$node_(3) setdest 163.970693 371.055823 8.526259" $ns_ at 203.000000 "$node_(4) setdest 123.550868 343.497632 19.997233" $ns_ at 203.000000 "$node_(5) setdest 47.626658 365.068247 19.926499" $ns_ at 203.000000 "$node_(6) setdest 44.129184 104.390756 17.708711" $ns_ at 203.000000 "$node_(7) setdest 173.699979 7.360376 18.022038" $ns_ at 203.000000 "$node_(8) setdest 113.299302 53.211896 17.366248" $ns_ at 203.000000 "$node_(9) setdest 158.404079 146.023580 12.437658" $ns_ at 203.000000 "$node_(10) setdest 156.369232 118.860713 19.871034" $ns_ at 204.000000 "$node_(1) setdest 153.023861 304.132837 19.999901" $ns_ at 204.000000 "$node_(2) setdest 111.823384 435.393263 19.973301" $ns_ at 204.000000 "$node_(3) setdest 169.826488 362.901841 10.038813" $ns_ at 204.000000 "$node_(4) setdest 116.289633 362.124419 19.992067" $ns_ at 204.000000 "$node_(5) setdest 28.522161 370.489417 19.858773" $ns_ at 204.000000 "$node_(6) setdest 27.051512 112.644070 18.967447" $ns_ at 204.000000 "$node_(7) setdest 180.486356 8.534284 6.887160" $ns_ at 204.000000 "$node_(8) setdest 98.103987 42.322359 18.694375" $ns_ at 204.000000 "$node_(9) setdest 161.029362 132.243002 14.028416" $ns_ at 204.000000 "$node_(10) setdest 172.443816 107.486758 19.691600" $ns_ at 205.000000 "$node_(1) setdest 149.277393 323.777154 19.998380" $ns_ at 205.000000 "$node_(2) setdest 129.394110 444.945228 19.999261" $ns_ at 205.000000 "$node_(3) setdest 168.110917 364.353857 2.247562" $ns_ at 205.000000 "$node_(4) setdest 106.734376 379.674290 19.982515" $ns_ at 205.000000 "$node_(5) setdest 24.594624 377.857992 8.349937" $ns_ at 205.000000 "$node_(6) setdest 9.174780 116.138563 18.215078" $ns_ at 205.000000 "$node_(7) setdest 181.039157 13.299606 4.797278" $ns_ at 205.000000 "$node_(8) setdest 82.787587 30.297708 19.472656" $ns_ at 205.000000 "$node_(9) setdest 162.200630 116.656242 15.630705" $ns_ at 205.000000 "$node_(10) setdest 181.116590 90.598550 18.984958" $ns_ at 206.000000 "$node_(1) setdest 144.598638 343.219337 19.997231" $ns_ at 206.000000 "$node_(2) setdest 147.113812 454.211788 19.996424" $ns_ at 206.000000 "$node_(3) setdest 161.975039 369.257123 7.854363" $ns_ at 206.000000 "$node_(4) setdest 94.731875 395.657510 19.988080" $ns_ at 206.000000 "$node_(5) setdest 28.110519 380.700946 4.521493" $ns_ at 206.000000 "$node_(6) setdest 5.389523 111.880557 5.697261" $ns_ at 206.000000 "$node_(7) setdest 182.643028 19.505356 6.409660" $ns_ at 206.000000 "$node_(8) setdest 66.703839 19.152674 19.567798" $ns_ at 206.000000 "$node_(9) setdest 163.096529 99.441502 17.238037" $ns_ at 206.000000 "$node_(10) setdest 185.879217 71.902868 19.292773" $ns_ at 207.000000 "$node_(1) setdest 138.750622 362.341225 19.996146" $ns_ at 207.000000 "$node_(2) setdest 163.876030 465.070012 19.971805" $ns_ at 207.000000 "$node_(3) setdest 153.481555 373.421602 9.459501" $ns_ at 207.000000 "$node_(4) setdest 81.367103 410.535184 19.999058" $ns_ at 207.000000 "$node_(5) setdest 33.182405 384.121656 6.117622" $ns_ at 207.000000 "$node_(6) setdest 7.670427 109.002037 3.672656" $ns_ at 207.000000 "$node_(7) setdest 183.240979 27.459965 7.977052" $ns_ at 207.000000 "$node_(8) setdest 48.471800 15.353912 18.623584" $ns_ at 207.000000 "$node_(9) setdest 164.150679 80.632580 18.838438" $ns_ at 207.000000 "$node_(10) setdest 185.014933 52.993766 18.928844" $ns_ at 208.000000 "$node_(1) setdest 131.154711 380.829290 19.987657" $ns_ at 208.000000 "$node_(2) setdest 180.272876 476.520635 19.999333" $ns_ at 208.000000 "$node_(3) setdest 143.368479 377.932962 11.073692" $ns_ at 208.000000 "$node_(4) setdest 69.391507 426.525693 19.977769" $ns_ at 208.000000 "$node_(5) setdest 39.946435 387.849275 7.723163" $ns_ at 208.000000 "$node_(6) setdest 10.931499 104.858445 5.272945" $ns_ at 208.000000 "$node_(7) setdest 180.816137 36.719425 9.571701" $ns_ at 208.000000 "$node_(8) setdest 30.381523 9.369616 19.054393" $ns_ at 208.000000 "$node_(9) setdest 164.385587 60.684667 19.949297" $ns_ at 208.000000 "$node_(10) setdest 174.507313 38.662418 17.770695" $ns_ at 209.000000 "$node_(1) setdest 121.092963 398.095887 19.984348" $ns_ at 209.000000 "$node_(2) setdest 189.211708 490.664051 16.731375" $ns_ at 209.000000 "$node_(3) setdest 131.945788 383.417256 12.671044" $ns_ at 209.000000 "$node_(4) setdest 59.975120 444.153298 19.985015" $ns_ at 209.000000 "$node_(5) setdest 48.328073 391.937141 9.325369" $ns_ at 209.000000 "$node_(6) setdest 14.411675 98.942625 6.863568" $ns_ at 209.000000 "$node_(7) setdest 175.728098 46.705469 11.207551" $ns_ at 209.000000 "$node_(8) setdest 12.204122 7.859309 18.240037" $ns_ at 209.000000 "$node_(9) setdest 159.026552 41.578356 19.843648" $ns_ at 209.000000 "$node_(10) setdest 163.369819 23.521448 18.796083" $ns_ at 210.000000 "$node_(1) setdest 108.982057 413.993854 19.985480" $ns_ at 210.000000 "$node_(2) setdest 180.764820 496.526252 10.281795" $ns_ at 210.000000 "$node_(3) setdest 119.741871 390.808564 14.267692" $ns_ at 210.000000 "$node_(4) setdest 53.047125 462.900705 19.986555" $ns_ at 210.000000 "$node_(5) setdest 57.929229 397.148381 10.924249" $ns_ at 210.000000 "$node_(6) setdest 16.629371 90.783736 8.454918" $ns_ at 210.000000 "$node_(7) setdest 170.109979 58.216735 12.809079" $ns_ at 210.000000 "$node_(8) setdest 7.612919 9.823576 4.993745" $ns_ at 210.000000 "$node_(9) setdest 144.943214 27.647777 19.809125" $ns_ at 210.000000 "$node_(10) setdest 151.654646 8.351943 19.166615" $ns_ at 211.000000 "$node_(1) setdest 94.765433 428.045068 19.988722" $ns_ at 211.000000 "$node_(2) setdest 169.488840 501.292361 12.241876" $ns_ at 211.000000 "$node_(3) setdest 106.907423 400.126968 15.860507" $ns_ at 211.000000 "$node_(4) setdest 49.262673 482.502882 19.964153" $ns_ at 211.000000 "$node_(5) setdest 68.775716 403.409497 12.523891" $ns_ at 211.000000 "$node_(6) setdest 18.101119 80.820271 10.071578" $ns_ at 211.000000 "$node_(7) setdest 164.220636 71.367090 14.408894" $ns_ at 211.000000 "$node_(8) setdest 8.398181 10.582628 1.092152" $ns_ at 211.000000 "$node_(9) setdest 126.252440 20.979851 19.844553" $ns_ at 211.000000 "$node_(10) setdest 150.671362 7.925031 1.071962" $ns_ at 212.000000 "$node_(1) setdest 79.694798 440.482197 19.539862" $ns_ at 212.000000 "$node_(2) setdest 158.086396 509.199851 13.876027" $ns_ at 212.000000 "$node_(3) setdest 93.891593 411.784206 17.472923" $ns_ at 212.000000 "$node_(4) setdest 51.602803 502.238394 19.873768" $ns_ at 212.000000 "$node_(5) setdest 79.786377 412.225707 14.105326" $ns_ at 212.000000 "$node_(6) setdest 18.082994 69.169270 11.651015" $ns_ at 212.000000 "$node_(7) setdest 156.452151 85.357032 16.002119" $ns_ at 212.000000 "$node_(8) setdest 10.252534 12.543807 2.699046" $ns_ at 212.000000 "$node_(9) setdest 106.444082 18.349570 19.982227" $ns_ at 212.000000 "$node_(10) setdest 150.561643 9.241322 1.320856" $ns_ at 213.000000 "$node_(1) setdest 74.331248 439.156532 5.524948" $ns_ at 213.000000 "$node_(2) setdest 147.109484 520.059714 15.441154" $ns_ at 213.000000 "$node_(3) setdest 78.802986 423.444845 19.069257" $ns_ at 213.000000 "$node_(4) setdest 64.714464 515.886813 18.926040" $ns_ at 213.000000 "$node_(5) setdest 90.367257 423.848581 15.717704" $ns_ at 213.000000 "$node_(6) setdest 15.231940 56.211466 13.267750" $ns_ at 213.000000 "$node_(7) setdest 146.294162 99.736602 17.605590" $ns_ at 213.000000 "$node_(8) setdest 12.764348 16.030199 4.296992" $ns_ at 213.000000 "$node_(9) setdest 87.094251 13.355646 19.983875" $ns_ at 213.000000 "$node_(10) setdest 150.265932 12.167440 2.941022" $ns_ at 214.000000 "$node_(1) setdest 75.387413 435.963971 3.362726" $ns_ at 214.000000 "$node_(2) setdest 134.637490 531.303365 16.791972" $ns_ at 214.000000 "$node_(3) setdest 63.111503 435.821747 19.985253" $ns_ at 214.000000 "$node_(4) setdest 82.741655 517.689625 18.117113" $ns_ at 214.000000 "$node_(5) setdest 100.190863 438.094362 17.304495" $ns_ at 214.000000 "$node_(6) setdest 11.435316 41.831751 14.872477" $ns_ at 214.000000 "$node_(7) setdest 134.405054 114.825240 19.209838" $ns_ at 214.000000 "$node_(8) setdest 15.786921 21.097420 5.900227" $ns_ at 214.000000 "$node_(9) setdest 67.206233 11.386313 19.985283" $ns_ at 214.000000 "$node_(10) setdest 150.233247 16.709509 4.542186" $ns_ at 215.000000 "$node_(1) setdest 78.105600 431.749429 5.015068" $ns_ at 215.000000 "$node_(2) setdest 119.211728 527.255675 15.947976" $ns_ at 215.000000 "$node_(3) setdest 48.423135 449.394750 19.999364" $ns_ at 215.000000 "$node_(4) setdest 100.521552 517.808971 17.780297" $ns_ at 215.000000 "$node_(5) setdest 109.423660 454.614792 18.925357" $ns_ at 215.000000 "$node_(6) setdest 16.762073 29.826767 13.133696" $ns_ at 215.000000 "$node_(7) setdest 121.638439 130.219167 19.998986" $ns_ at 215.000000 "$node_(8) setdest 20.223833 27.143327 7.499279" $ns_ at 215.000000 "$node_(9) setdest 47.635785 14.277190 19.782811" $ns_ at 215.000000 "$node_(10) setdest 149.981298 22.846536 6.142197" $ns_ at 216.000000 "$node_(1) setdest 82.316111 426.647880 6.614696" $ns_ at 216.000000 "$node_(2) setdest 110.714063 514.069971 15.686717" $ns_ at 216.000000 "$node_(3) setdest 34.234170 463.437881 19.963373" $ns_ at 216.000000 "$node_(4) setdest 119.756878 518.623367 19.252559" $ns_ at 216.000000 "$node_(5) setdest 118.021417 472.643823 19.974168" $ns_ at 216.000000 "$node_(6) setdest 24.439905 33.577223 8.544883" $ns_ at 216.000000 "$node_(7) setdest 109.264356 145.928934 19.997868" $ns_ at 216.000000 "$node_(8) setdest 26.436807 33.784570 9.094347" $ns_ at 216.000000 "$node_(9) setdest 34.763093 28.005283 18.819318" $ns_ at 216.000000 "$node_(10) setdest 149.466985 30.571752 7.742318" $ns_ at 217.000000 "$node_(1) setdest 87.966643 420.681429 8.217484" $ns_ at 217.000000 "$node_(2) setdest 106.139891 497.477479 17.211446" $ns_ at 217.000000 "$node_(3) setdest 24.871837 481.006527 19.907551" $ns_ at 217.000000 "$node_(4) setdest 139.198045 521.043816 19.591262" $ns_ at 217.000000 "$node_(5) setdest 125.144910 491.320562 19.989115" $ns_ at 217.000000 "$node_(6) setdest 29.906717 42.714611 10.647906" $ns_ at 217.000000 "$node_(7) setdest 95.624683 160.464758 19.933160" $ns_ at 217.000000 "$node_(8) setdest 35.012079 40.154365 10.682209" $ns_ at 217.000000 "$node_(9) setdest 26.794592 44.498695 18.317469" $ns_ at 217.000000 "$node_(10) setdest 148.822317 39.891733 9.342250" $ns_ at 218.000000 "$node_(1) setdest 95.567803 414.482141 9.808608" $ns_ at 218.000000 "$node_(2) setdest 101.751650 479.151427 18.844119" $ns_ at 218.000000 "$node_(3) setdest 21.772410 500.718610 19.954264" $ns_ at 218.000000 "$node_(4) setdest 156.440799 529.170085 19.061711" $ns_ at 218.000000 "$node_(5) setdest 136.804828 507.434328 19.889875" $ns_ at 218.000000 "$node_(6) setdest 34.936287 53.901566 12.265583" $ns_ at 218.000000 "$node_(7) setdest 77.559907 162.800620 18.215168" $ns_ at 218.000000 "$node_(8) setdest 46.265277 45.048070 12.271219" $ns_ at 218.000000 "$node_(9) setdest 18.369496 61.553834 19.022618" $ns_ at 218.000000 "$node_(10) setdest 148.315037 50.819341 10.939376" $ns_ at 219.000000 "$node_(1) setdest 105.384019 408.666566 11.409602" $ns_ at 219.000000 "$node_(2) setdest 105.257830 460.439311 19.037767" $ns_ at 219.000000 "$node_(3) setdest 20.836622 520.669754 19.973078" $ns_ at 219.000000 "$node_(4) setdest 169.726291 541.962081 18.442870" $ns_ at 219.000000 "$node_(5) setdest 151.392428 509.951508 14.803185" $ns_ at 219.000000 "$node_(6) setdest 39.985524 66.816926 13.867275" $ns_ at 219.000000 "$node_(7) setdest 65.983518 149.611440 17.548997" $ns_ at 219.000000 "$node_(8) setdest 60.002002 46.833409 13.852258" $ns_ at 219.000000 "$node_(9) setdest 12.671632 79.346833 18.683052" $ns_ at 219.000000 "$node_(10) setdest 149.329428 63.307247 12.529038" $ns_ at 220.000000 "$node_(1) setdest 117.372851 403.595980 13.017025" $ns_ at 220.000000 "$node_(2) setdest 114.312002 443.838623 18.909280" $ns_ at 220.000000 "$node_(3) setdest 32.633983 533.959274 17.770455" $ns_ at 220.000000 "$node_(4) setdest 186.809428 545.300049 17.406194" $ns_ at 220.000000 "$node_(5) setdest 154.136381 499.903314 10.416116" $ns_ at 220.000000 "$node_(6) setdest 38.966285 82.245893 15.462596" $ns_ at 220.000000 "$node_(7) setdest 74.429529 163.526860 16.278023" $ns_ at 220.000000 "$node_(8) setdest 62.748658 50.955781 4.953592" $ns_ at 220.000000 "$node_(9) setdest 16.722542 97.580963 18.678688" $ns_ at 220.000000 "$node_(10) setdest 147.564335 77.337282 14.140630" $ns_ at 221.000000 "$node_(1) setdest 130.510749 397.211113 14.607220" $ns_ at 221.000000 "$node_(2) setdest 126.001789 428.533431 19.258765" $ns_ at 221.000000 "$node_(3) setdest 47.085796 524.976442 17.016055" $ns_ at 221.000000 "$node_(4) setdest 195.470877 545.496075 8.663667" $ns_ at 221.000000 "$node_(5) setdest 153.537843 487.668110 12.249835" $ns_ at 221.000000 "$node_(6) setdest 37.659369 99.258980 17.063211" $ns_ at 221.000000 "$node_(7) setdest 81.550077 180.240654 18.167363" $ns_ at 221.000000 "$node_(8) setdest 62.598894 57.433367 6.479317" $ns_ at 221.000000 "$node_(9) setdest 23.470822 116.374653 19.968527" $ns_ at 221.000000 "$node_(10) setdest 144.701469 92.814988 15.740247" $ns_ at 222.000000 "$node_(1) setdest 145.829089 392.029894 16.170856" $ns_ at 222.000000 "$node_(2) setdest 140.217574 415.094347 19.562657" $ns_ at 222.000000 "$node_(3) setdest 60.241100 516.107987 15.865420" $ns_ at 222.000000 "$node_(4) setdest 195.175480 544.049314 1.476611" $ns_ at 222.000000 "$node_(5) setdest 153.773151 473.824698 13.845411" $ns_ at 222.000000 "$node_(6) setdest 36.836689 117.903151 18.662312" $ns_ at 222.000000 "$node_(7) setdest 88.469997 198.652396 19.669203" $ns_ at 222.000000 "$node_(8) setdest 62.213896 65.503403 8.079215" $ns_ at 222.000000 "$node_(9) setdest 31.284840 134.781911 19.997150" $ns_ at 222.000000 "$node_(10) setdest 140.588071 109.660694 17.340642" $ns_ at 223.000000 "$node_(1) setdest 163.506752 392.575980 17.686096" $ns_ at 223.000000 "$node_(2) setdest 154.063643 401.028161 19.737558" $ns_ at 223.000000 "$node_(3) setdest 74.782464 518.041618 14.669363" $ns_ at 223.000000 "$node_(4) setdest 194.480877 541.034819 3.093486" $ns_ at 223.000000 "$node_(5) setdest 154.461775 458.388033 15.452018" $ns_ at 223.000000 "$node_(6) setdest 36.889515 137.817056 19.913975" $ns_ at 223.000000 "$node_(7) setdest 93.285752 218.049531 19.986004" $ns_ at 223.000000 "$node_(8) setdest 61.558857 75.160595 9.679381" $ns_ at 223.000000 "$node_(9) setdest 40.120888 152.722334 19.998363" $ns_ at 223.000000 "$node_(10) setdest 135.370957 127.870138 18.942073" $ns_ at 224.000000 "$node_(1) setdest 181.923802 396.004220 18.733408" $ns_ at 224.000000 "$node_(2) setdest 167.390779 386.339495 19.833544" $ns_ at 224.000000 "$node_(3) setdest 88.812375 526.590208 16.429145" $ns_ at 224.000000 "$node_(4) setdest 193.757794 536.395966 4.694870" $ns_ at 224.000000 "$node_(5) setdest 155.534575 441.369278 17.052534" $ns_ at 224.000000 "$node_(6) setdest 37.937125 157.787942 19.998344" $ns_ at 224.000000 "$node_(7) setdest 95.263234 237.932451 19.981015" $ns_ at 224.000000 "$node_(8) setdest 60.618285 86.400311 11.279002" $ns_ at 224.000000 "$node_(9) setdest 49.705686 170.274483 19.998657" $ns_ at 224.000000 "$node_(10) setdest 129.766491 147.053821 19.985588" $ns_ at 225.000000 "$node_(1) setdest 169.232343 395.048481 12.727394" $ns_ at 225.000000 "$node_(2) setdest 178.021040 369.992559 19.499353" $ns_ at 225.000000 "$node_(3) setdest 105.697669 532.818640 17.997403" $ns_ at 225.000000 "$node_(4) setdest 193.626695 530.109972 6.287361" $ns_ at 225.000000 "$node_(5) setdest 157.030780 422.777712 18.651674" $ns_ at 225.000000 "$node_(6) setdest 39.945670 177.684547 19.997729" $ns_ at 225.000000 "$node_(7) setdest 93.862395 257.856020 19.972755" $ns_ at 225.000000 "$node_(8) setdest 59.031456 99.180711 12.878534" $ns_ at 225.000000 "$node_(9) setdest 59.205275 187.873059 19.998802" $ns_ at 225.000000 "$node_(10) setdest 124.063931 166.223553 19.999945" $ns_ at 226.000000 "$node_(1) setdest 156.800156 391.440287 12.945205" $ns_ at 226.000000 "$node_(2) setdest 181.618992 357.273651 13.218014" $ns_ at 226.000000 "$node_(3) setdest 124.505138 538.184199 19.557865" $ns_ at 226.000000 "$node_(4) setdest 193.643917 522.227082 7.882909" $ns_ at 226.000000 "$node_(5) setdest 158.657327 402.933793 19.910469" $ns_ at 226.000000 "$node_(6) setdest 43.108409 197.429911 19.997057" $ns_ at 226.000000 "$node_(7) setdest 88.502871 277.089742 19.966486" $ns_ at 226.000000 "$node_(8) setdest 56.808037 113.487980 14.479003" $ns_ at 226.000000 "$node_(9) setdest 67.791820 205.933327 19.997551" $ns_ at 226.000000 "$node_(10) setdest 117.964834 185.269423 19.998604" $ns_ at 227.000000 "$node_(1) setdest 142.278798 390.812500 14.534922" $ns_ at 227.000000 "$node_(2) setdest 180.809611 361.122439 3.932972" $ns_ at 227.000000 "$node_(3) setdest 139.353761 542.830733 15.558660" $ns_ at 227.000000 "$node_(4) setdest 190.918757 513.212438 9.417553" $ns_ at 227.000000 "$node_(5) setdest 158.201943 382.958722 19.980261" $ns_ at 227.000000 "$node_(6) setdest 47.461748 216.947467 19.997164" $ns_ at 227.000000 "$node_(7) setdest 79.883191 295.123722 19.988080" $ns_ at 227.000000 "$node_(8) setdest 54.120836 129.341065 16.079222" $ns_ at 227.000000 "$node_(9) setdest 75.603470 224.344458 19.999791" $ns_ at 227.000000 "$node_(10) setdest 111.317961 204.132478 19.999894" $ns_ at 228.000000 "$node_(1) setdest 126.803939 394.954915 16.019702" $ns_ at 228.000000 "$node_(2) setdest 181.453885 366.636563 5.551636" $ns_ at 228.000000 "$node_(3) setdest 139.679950 541.809477 1.072084" $ns_ at 228.000000 "$node_(4) setdest 182.221684 506.884617 10.755483" $ns_ at 228.000000 "$node_(5) setdest 147.532398 367.471383 18.806830" $ns_ at 228.000000 "$node_(6) setdest 53.185240 236.106169 19.995355" $ns_ at 228.000000 "$node_(7) setdest 69.135376 311.964610 19.978263" $ns_ at 228.000000 "$node_(8) setdest 50.220110 146.582020 17.676713" $ns_ at 228.000000 "$node_(9) setdest 83.229589 242.832888 19.999493" $ns_ at 228.000000 "$node_(10) setdest 104.487873 222.930048 19.999968" $ns_ at 229.000000 "$node_(1) setdest 112.719153 405.732941 17.735474" $ns_ at 229.000000 "$node_(2) setdest 184.190891 373.250673 7.158048" $ns_ at 229.000000 "$node_(3) setdest 138.130687 540.190583 2.240767" $ns_ at 229.000000 "$node_(4) setdest 170.893314 511.903508 12.390368" $ns_ at 229.000000 "$node_(5) setdest 131.769906 373.894402 17.020909" $ns_ at 229.000000 "$node_(6) setdest 60.421096 254.745402 19.994464" $ns_ at 229.000000 "$node_(7) setdest 55.227342 326.293985 19.969086" $ns_ at 229.000000 "$node_(8) setdest 46.727716 165.535396 19.272448" $ns_ at 229.000000 "$node_(9) setdest 90.276455 261.550003 19.999718" $ns_ at 229.000000 "$node_(10) setdest 98.003508 241.846149 19.996647" $ns_ at 230.000000 "$node_(1) setdest 96.091336 415.488575 19.278400" $ns_ at 230.000000 "$node_(2) setdest 183.469209 381.617058 8.397453" $ns_ at 230.000000 "$node_(3) setdest 135.135321 537.790149 3.838527" $ns_ at 230.000000 "$node_(4) setdest 159.237705 520.178185 14.294178" $ns_ at 230.000000 "$node_(5) setdest 126.003487 389.332246 16.479642" $ns_ at 230.000000 "$node_(6) setdest 69.231636 272.693606 19.994091" $ns_ at 230.000000 "$node_(7) setdest 39.927801 339.173368 19.998862" $ns_ at 230.000000 "$node_(8) setdest 44.917086 185.446450 19.993211" $ns_ at 230.000000 "$node_(9) setdest 96.877144 280.425405 19.996247" $ns_ at 230.000000 "$node_(10) setdest 92.829898 261.161671 19.996390" $ns_ at 231.000000 "$node_(1) setdest 76.542960 419.096553 19.878544" $ns_ at 231.000000 "$node_(2) setdest 176.455767 382.214395 7.038833" $ns_ at 231.000000 "$node_(3) setdest 130.270647 535.384863 5.426828" $ns_ at 231.000000 "$node_(4) setdest 147.767236 531.122795 15.854216" $ns_ at 231.000000 "$node_(5) setdest 120.093704 403.690952 15.527329" $ns_ at 231.000000 "$node_(6) setdest 79.612346 289.781035 19.993483" $ns_ at 231.000000 "$node_(7) setdest 24.003817 350.585990 19.591355" $ns_ at 231.000000 "$node_(8) setdest 44.961975 205.440954 19.994554" $ns_ at 231.000000 "$node_(9) setdest 99.747344 300.145262 19.927640" $ns_ at 231.000000 "$node_(10) setdest 89.013268 280.789285 19.995247" $ns_ at 232.000000 "$node_(1) setdest 57.010907 414.931045 19.971292" $ns_ at 232.000000 "$node_(2) setdest 170.625082 375.887436 8.603912" $ns_ at 232.000000 "$node_(3) setdest 123.401898 533.915668 7.024119" $ns_ at 232.000000 "$node_(4) setdest 133.831007 536.334199 14.878750" $ns_ at 232.000000 "$node_(5) setdest 112.784511 418.983603 16.949616" $ns_ at 232.000000 "$node_(6) setdest 91.565883 305.808159 19.993893" $ns_ at 232.000000 "$node_(7) setdest 24.991666 366.397074 15.841913" $ns_ at 232.000000 "$node_(8) setdest 46.668910 225.364489 19.996521" $ns_ at 232.000000 "$node_(9) setdest 95.297668 319.497789 19.857489" $ns_ at 232.000000 "$node_(10) setdest 86.767611 300.658389 19.995606" $ns_ at 233.000000 "$node_(1) setdest 39.647141 405.570459 19.726149" $ns_ at 233.000000 "$node_(2) setdest 163.274148 368.970881 10.093313" $ns_ at 233.000000 "$node_(3) setdest 114.780291 533.380993 8.638170" $ns_ at 233.000000 "$node_(4) setdest 131.539148 532.333883 4.610330" $ns_ at 233.000000 "$node_(5) setdest 104.102864 435.367253 18.541710" $ns_ at 233.000000 "$node_(6) setdest 103.303347 321.997575 19.996631" $ns_ at 233.000000 "$node_(7) setdest 30.412033 380.296306 14.918748" $ns_ at 233.000000 "$node_(8) setdest 49.123918 245.211852 19.998622" $ns_ at 233.000000 "$node_(9) setdest 83.212825 335.267364 19.867635" $ns_ at 233.000000 "$node_(10) setdest 86.025912 320.638077 19.993450" $ns_ at 234.000000 "$node_(1) setdest 27.316123 390.616503 19.382332" $ns_ at 234.000000 "$node_(2) setdest 152.190026 371.188100 11.303708" $ns_ at 234.000000 "$node_(3) setdest 104.559734 533.881666 10.232813" $ns_ at 234.000000 "$node_(4) setdest 134.437047 528.843275 4.536757" $ns_ at 234.000000 "$node_(5) setdest 99.490371 454.660971 19.837405" $ns_ at 234.000000 "$node_(6) setdest 113.260598 339.320990 19.981180" $ns_ at 234.000000 "$node_(7) setdest 34.878867 395.284625 15.639767" $ns_ at 234.000000 "$node_(8) setdest 52.561370 264.911186 19.996995" $ns_ at 234.000000 "$node_(9) setdest 66.066130 345.377223 19.905235" $ns_ at 234.000000 "$node_(10) setdest 87.285070 340.587013 19.988635" $ns_ at 235.000000 "$node_(1) setdest 20.218846 372.865040 19.117682" $ns_ at 235.000000 "$node_(2) setdest 142.051256 379.923957 13.383193" $ns_ at 235.000000 "$node_(3) setdest 92.840981 535.571717 11.839993" $ns_ at 235.000000 "$node_(4) setdest 138.217326 524.011125 6.135160" $ns_ at 235.000000 "$node_(5) setdest 91.141238 472.512581 19.707562" $ns_ at 235.000000 "$node_(6) setdest 120.629818 357.902574 19.989513" $ns_ at 235.000000 "$node_(7) setdest 37.667906 412.302677 17.245082" $ns_ at 235.000000 "$node_(8) setdest 57.399640 284.312240 19.995243" $ns_ at 235.000000 "$node_(9) setdest 47.135371 351.684805 19.953928" $ns_ at 235.000000 "$node_(10) setdest 91.171326 360.189136 19.983649" $ns_ at 236.000000 "$node_(1) setdest 24.598928 356.149629 17.279760" $ns_ at 236.000000 "$node_(2) setdest 133.409494 392.148552 14.970664" $ns_ at 236.000000 "$node_(3) setdest 79.429653 536.017371 13.418731" $ns_ at 236.000000 "$node_(4) setdest 141.644180 517.087121 7.725617" $ns_ at 236.000000 "$node_(5) setdest 82.659254 489.792059 19.249010" $ns_ at 236.000000 "$node_(6) setdest 124.911845 377.382671 19.945173" $ns_ at 236.000000 "$node_(7) setdest 36.308163 431.068874 18.815394" $ns_ at 236.000000 "$node_(8) setdest 63.770885 303.263885 19.993940" $ns_ at 236.000000 "$node_(9) setdest 27.530214 350.712658 19.629245" $ns_ at 236.000000 "$node_(10) setdest 98.063978 378.939773 19.977363" $ns_ at 237.000000 "$node_(1) setdest 40.321183 353.037350 16.027339" $ns_ at 237.000000 "$node_(2) setdest 125.329380 406.653920 16.604033" $ns_ at 237.000000 "$node_(3) setdest 64.843715 532.584356 14.984497" $ns_ at 237.000000 "$node_(4) setdest 144.634350 508.245730 9.333344" $ns_ at 237.000000 "$node_(5) setdest 82.909106 508.254419 18.464050" $ns_ at 237.000000 "$node_(6) setdest 118.133725 394.817452 18.706002" $ns_ at 237.000000 "$node_(7) setdest 29.233267 449.643599 19.876483" $ns_ at 237.000000 "$node_(8) setdest 71.818285 321.564343 19.991683" $ns_ at 237.000000 "$node_(9) setdest 29.921966 351.885394 2.663792" $ns_ at 237.000000 "$node_(10) setdest 108.291461 396.089794 19.968090" $ns_ at 238.000000 "$node_(1) setdest 45.596210 362.703271 11.011628" $ns_ at 238.000000 "$node_(2) setdest 116.291703 422.438321 18.188648" $ns_ at 238.000000 "$node_(3) setdest 50.905662 523.641287 16.560429" $ns_ at 238.000000 "$node_(4) setdest 147.083186 497.586315 10.937090" $ns_ at 238.000000 "$node_(5) setdest 86.823206 527.075434 19.223704" $ns_ at 238.000000 "$node_(6) setdest 100.295091 394.820595 17.838634" $ns_ at 238.000000 "$node_(7) setdest 14.754694 462.701263 19.496965" $ns_ at 238.000000 "$node_(8) setdest 82.106778 338.696777 19.984329" $ns_ at 238.000000 "$node_(9) setdest 29.384525 352.572171 0.872069" $ns_ at 238.000000 "$node_(10) setdest 121.581838 411.004409 19.976983" $ns_ at 239.000000 "$node_(1) setdest 43.050325 374.782260 12.344371" $ns_ at 239.000000 "$node_(2) setdest 109.603123 440.967025 19.698985" $ns_ at 239.000000 "$node_(3) setdest 40.281591 508.934509 18.142774" $ns_ at 239.000000 "$node_(4) setdest 150.186991 485.439022 12.537557" $ns_ at 239.000000 "$node_(5) setdest 88.363743 540.891623 13.901811" $ns_ at 239.000000 "$node_(6) setdest 83.872867 392.609649 16.570387" $ns_ at 239.000000 "$node_(7) setdest 2.120167 462.131925 12.647348" $ns_ at 239.000000 "$node_(8) setdest 94.881055 354.058754 19.979301" $ns_ at 239.000000 "$node_(9) setdest 28.147365 354.727230 2.484924" $ns_ at 239.000000 "$node_(10) setdest 137.437686 423.128242 19.959841" $ns_ at 240.000000 "$node_(1) setdest 38.556092 388.011135 13.971445" $ns_ at 240.000000 "$node_(2) setdest 102.994537 459.843356 19.999731" $ns_ at 240.000000 "$node_(3) setdest 34.511155 490.212704 19.590914" $ns_ at 240.000000 "$node_(4) setdest 153.699183 471.745840 14.136432" $ns_ at 240.000000 "$node_(5) setdest 87.677276 538.921027 2.086741" $ns_ at 240.000000 "$node_(6) setdest 67.844685 393.430187 16.049172" $ns_ at 240.000000 "$node_(7) setdest 2.807388 458.762773 3.438526" $ns_ at 240.000000 "$node_(8) setdest 109.948493 367.184167 19.982596" $ns_ at 240.000000 "$node_(9) setdest 26.581030 358.478450 4.065102" $ns_ at 240.000000 "$node_(10) setdest 155.787822 430.945677 19.945921" $ns_ at 241.000000 "$node_(1) setdest 36.249641 403.358559 15.519767" $ns_ at 241.000000 "$node_(2) setdest 95.054734 478.197050 19.997464" $ns_ at 241.000000 "$node_(3) setdest 38.588756 470.902314 19.736210" $ns_ at 241.000000 "$node_(4) setdest 158.039693 456.618076 15.738147" $ns_ at 241.000000 "$node_(5) setdest 85.810743 535.721185 3.704447" $ns_ at 241.000000 "$node_(6) setdest 50.254348 394.635888 17.631610" $ns_ at 241.000000 "$node_(7) setdest 5.492504 454.380668 5.139327" $ns_ at 241.000000 "$node_(8) setdest 125.740547 379.432191 19.985071" $ns_ at 241.000000 "$node_(9) setdest 26.686133 364.112657 5.635187" $ns_ at 241.000000 "$node_(10) setdest 175.328309 429.760207 19.576413" $ns_ at 242.000000 "$node_(1) setdest 37.522192 420.480349 17.169015" $ns_ at 242.000000 "$node_(2) setdest 90.631305 497.645680 19.945323" $ns_ at 242.000000 "$node_(3) setdest 50.739464 455.055826 19.968748" $ns_ at 242.000000 "$node_(4) setdest 162.672725 439.910564 17.337991" $ns_ at 242.000000 "$node_(5) setdest 82.862827 531.310088 5.305468" $ns_ at 242.000000 "$node_(6) setdest 31.030156 394.391413 19.225746" $ns_ at 242.000000 "$node_(7) setdest 9.560885 449.014231 6.734268" $ns_ at 242.000000 "$node_(8) setdest 138.863619 394.470220 19.958891" $ns_ at 242.000000 "$node_(9) setdest 30.044622 370.532583 7.245336" $ns_ at 242.000000 "$node_(10) setdest 184.068040 414.234527 17.816555" $ns_ at 243.000000 "$node_(1) setdest 37.985476 439.243636 18.769005" $ns_ at 243.000000 "$node_(2) setdest 87.433717 517.377092 19.988827" $ns_ at 243.000000 "$node_(3) setdest 62.449094 438.866145 19.980520" $ns_ at 243.000000 "$node_(4) setdest 167.366807 421.571460 18.930323" $ns_ at 243.000000 "$node_(5) setdest 79.256025 525.421283 6.905580" $ns_ at 243.000000 "$node_(6) setdest 11.506341 396.543000 19.642013" $ns_ at 243.000000 "$node_(7) setdest 15.539098 443.203051 8.337197" $ns_ at 243.000000 "$node_(8) setdest 147.973211 412.218070 19.949207" $ns_ at 243.000000 "$node_(9) setdest 36.059140 377.050285 8.868758" $ns_ at 243.000000 "$node_(10) setdest 177.685561 398.128349 17.324694" $ns_ at 244.000000 "$node_(1) setdest 39.206090 459.137583 19.931358" $ns_ at 244.000000 "$node_(2) setdest 83.154377 536.500088 19.595961" $ns_ at 244.000000 "$node_(3) setdest 78.636311 427.281132 19.905741" $ns_ at 244.000000 "$node_(4) setdest 170.390886 401.818715 19.982892" $ns_ at 244.000000 "$node_(5) setdest 74.252665 518.545692 8.503374" $ns_ at 244.000000 "$node_(6) setdest 7.973051 410.375276 14.276414" $ns_ at 244.000000 "$node_(7) setdest 23.323807 437.026222 9.937551" $ns_ at 244.000000 "$node_(8) setdest 153.374916 431.467556 19.993027" $ns_ at 244.000000 "$node_(9) setdest 44.032723 383.856539 10.483469" $ns_ at 244.000000 "$node_(10) setdest 172.718843 382.551826 16.349201" $ns_ at 245.000000 "$node_(1) setdest 34.618867 478.486864 19.885606" $ns_ at 245.000000 "$node_(2) setdest 84.300844 531.592510 5.039713" $ns_ at 245.000000 "$node_(3) setdest 94.940590 415.825326 19.926490" $ns_ at 245.000000 "$node_(4) setdest 172.304961 394.881002 7.196912" $ns_ at 245.000000 "$node_(5) setdest 68.133382 510.504064 10.105117" $ns_ at 245.000000 "$node_(6) setdest 17.059711 420.972002 13.959154" $ns_ at 245.000000 "$node_(7) setdest 32.971174 430.706107 11.533236" $ns_ at 245.000000 "$node_(8) setdest 157.601063 450.999458 19.983881" $ns_ at 245.000000 "$node_(9) setdest 53.145590 391.780127 12.075909" $ns_ at 245.000000 "$node_(10) setdest 169.004729 365.196387 17.748406" $ns_ at 246.000000 "$node_(1) setdest 23.314948 494.915448 19.941839" $ns_ at 246.000000 "$node_(2) setdest 80.388414 526.333405 6.554791" $ns_ at 246.000000 "$node_(3) setdest 105.925896 399.190915 19.934407" $ns_ at 246.000000 "$node_(4) setdest 172.261920 400.073454 5.192630" $ns_ at 246.000000 "$node_(5) setdest 60.662128 501.492990 11.705516" $ns_ at 246.000000 "$node_(6) setdest 25.067644 434.285222 15.536049" $ns_ at 246.000000 "$node_(7) setdest 44.416211 424.250797 13.140012" $ns_ at 246.000000 "$node_(8) setdest 157.547382 470.971881 19.972495" $ns_ at 246.000000 "$node_(9) setdest 61.816142 402.356439 13.676142" $ns_ at 246.000000 "$node_(10) setdest 159.697284 354.841814 13.922848" $ns_ at 247.000000 "$node_(1) setdest 11.471594 510.982443 19.960295" $ns_ at 247.000000 "$node_(2) setdest 73.667647 521.515333 8.269373" $ns_ at 247.000000 "$node_(3) setdest 115.687404 381.745967 19.990329" $ns_ at 247.000000 "$node_(4) setdest 172.542353 406.883343 6.815660" $ns_ at 247.000000 "$node_(5) setdest 53.043729 490.595790 13.296201" $ns_ at 247.000000 "$node_(6) setdest 35.532652 447.799237 17.092249" $ns_ at 247.000000 "$node_(7) setdest 57.583686 417.635230 14.735946" $ns_ at 247.000000 "$node_(8) setdest 155.807521 490.895157 19.999102" $ns_ at 247.000000 "$node_(9) setdest 70.586313 414.874960 15.284936" $ns_ at 247.000000 "$node_(10) setdest 150.705382 353.022498 9.174106" $ns_ at 248.000000 "$node_(1) setdest 6.250205 530.216206 19.929890" $ns_ at 248.000000 "$node_(2) setdest 64.550481 517.738746 9.868400" $ns_ at 248.000000 "$node_(3) setdest 129.575043 368.902786 18.915967" $ns_ at 248.000000 "$node_(4) setdest 172.766820 415.295599 8.415251" $ns_ at 248.000000 "$node_(5) setdest 45.664917 477.649441 14.901504" $ns_ at 248.000000 "$node_(6) setdest 49.236481 460.622756 18.767994" $ns_ at 248.000000 "$node_(7) setdest 72.542200 411.059556 16.340032" $ns_ at 248.000000 "$node_(8) setdest 154.151119 510.826019 19.999573" $ns_ at 248.000000 "$node_(9) setdest 80.048453 428.859710 16.885062" $ns_ at 248.000000 "$node_(10) setdest 150.693495 353.348529 0.326248" $ns_ at 249.000000 "$node_(1) setdest 15.633937 545.116140 17.608591" $ns_ at 249.000000 "$node_(2) setdest 53.897778 513.466205 11.477573" $ns_ at 249.000000 "$node_(3) setdest 147.143605 364.268821 18.169425" $ns_ at 249.000000 "$node_(4) setdest 172.715108 425.310616 10.015150" $ns_ at 249.000000 "$node_(5) setdest 40.276620 462.090927 16.465147" $ns_ at 249.000000 "$node_(6) setdest 66.591813 470.358500 19.899554" $ns_ at 249.000000 "$node_(7) setdest 89.011277 403.945945 17.939731" $ns_ at 249.000000 "$node_(8) setdest 153.637467 522.766334 11.951358" $ns_ at 249.000000 "$node_(9) setdest 90.366944 444.196722 18.484999" $ns_ at 249.000000 "$node_(10) setdest 152.055411 354.274810 1.647062" $ns_ at 250.000000 "$node_(1) setdest 32.767440 547.185729 17.258045" $ns_ at 250.000000 "$node_(2) setdest 42.327370 507.405581 13.061605" $ns_ at 250.000000 "$node_(3) setdest 166.110136 361.566966 19.158010" $ns_ at 250.000000 "$node_(4) setdest 171.517760 436.860424 11.611706" $ns_ at 250.000000 "$node_(5) setdest 39.663162 444.108944 17.992445" $ns_ at 250.000000 "$node_(6) setdest 82.640473 482.268268 19.985046" $ns_ at 250.000000 "$node_(7) setdest 106.691634 395.709099 19.504889" $ns_ at 250.000000 "$node_(8) setdest 156.539558 511.951326 11.197613" $ns_ at 250.000000 "$node_(9) setdest 102.661633 459.753615 19.828673" $ns_ at 250.000000 "$node_(10) setdest 155.016298 355.644768 3.262459" core-4.8/gui/configs/sample4-bg.jpg0000664000175000017500000061050612534327775014140 00000000000000JFIFHHICC_PROFILEapplmntrRGB XYZ !acspAPPL-appldescPbdscmBcprtwtptrXYZgXYZbXYZrTRC aarg $ vcgt DndinX>chad,mmod(bTRC gTRC aabg $ aagg $ descDisplaymluc nlNLdaDKplPLenUS,nbNO>frFRPptBRfptPT~zhCN esESjaJPruRU$svSEzhTWdeDEfiFIitIT"koKR 6Kleuren-LCDLCD-farveskrmKolor LCDColor LCDFarge-LCDLCD couleurLCD ColoridoLCD a Cores_ir LCDLCD color000 LCD&25B=>9 -48A?;59Frg-LCD_irmfvoy:VhFarb-LCDVri-LCDLCD colori LCDtextCopyright Apple, Inc., 2010XYZ RXYZ o19cXYZ `jXYZ &2ɗcurv #(-26;@EJOTY^chmrw| %+28>ELRY`gnu| &/8AKT]gqz !-8COZfr~ -;HUcq~ +:IXgw'7HYj{+=Oat 2FZn  % : O d y  ' = T j " 9 Q i  * C \ u & @ Z t .Id %A^z &Ca~1Om&Ed#Cc'Ij4Vx&IlAe@e Ek*Qw;c*R{Gp@j>i  A l !!H!u!!!"'"U"""# #8#f###$$M$|$$% %8%h%%%&'&W&&&''I'z''( (?(q(())8)k))**5*h**++6+i++,,9,n,,- -A-v--..L.../$/Z///050l0011J1112*2c223 3F3334+4e4455M555676r667$7`7788P8899B999:6:t::;-;k;;<' >`>>?!?a??@#@d@@A)AjAAB0BrBBC:C}CDDGDDEEUEEF"FgFFG5G{GHHKHHIIcIIJ7J}JK KSKKL*LrLMMJMMN%NnNOOIOOP'PqPQQPQQR1R|RSS_SSTBTTU(UuUVV\VVWDWWX/X}XYYiYZZVZZ[E[[\5\\]']x]^^l^__a_``W``aOaabIbbcCccd@dde=eef=ffg=ggh?hhiCiijHjjkOkklWlmm`mnnknooxop+ppq:qqrKrss]sttptu(uuv>vvwVwxxnxy*yyzFz{{c{|!||}A}~~b~#G k͂0WGrׇ;iΉ3dʋ0cʍ1fΏ6n֑?zM _ɖ4 uL$h՛BdҞ@iءG&vVǥ8nRĩ7u\ЭD-u`ֲK³8%yhYѹJº;.! zpg_XQKFAǿ=ȼ:ɹ8ʷ6˶5̵5͵6ζ7ϸ9к<Ѿ?DINU\dlvۀ܊ݖޢ)߯6DScs 2F[p(@Xr4Pm8Ww)Kmparaff Y vcgtJ*ntIGm|>  K\a !d"$N%'/()+I,-/C013 4B5s6789;<+=9>E?R@cAsBCDEFGHJK,LCM[NiOvPQRSTUVWXYZ[\]^_`abcdzeffQg;h$iijklmnpoSp7qqrstuvfwIx+y yz{|}~wqrz߇ >?@ABCDEFGHwIhJYKHL8M'NOOPQRSTUVsW^XIY3Z[[\]^_`oaTb4c cdeffgj?2?@AB]C*CDEF[G'GHIJVK!KLMNLOOPQsR;SSTUZV VWXuY;ZZ[\S]]^_]``ab]ccdeVffghEiijvk1klmbnnopNqqrzs3stu^vvwx?xyzi{ {|}T~~yf\Y[euƍՎ"0:CJQYboˠ%yЦ'~֪-ۮ1޲6߶3ܺ3 ?@@ABCDEoFXGBH/IJKKLMNOPQRSTV WX'Y9ZM[c\{]^_`bc3dYefghikl!m*n.o-p)q"rs stvwMxyz|E}~M4I㉇!@X=IwŞ/DYiv~Ā}vl`΋и!]ٟ1+G{fp.Qu 2[:`-Y <k1dL M%r  l # J +  "@mA-0HF !"s#F$$%&'()*+,-./01245:6c789;%<_=>@AdBCEEFGIJ7KbLMNOPRST*U@VYWsXYZ[]^=_f`abd#eXfghj4kilmop2q`rstvw7x`yz{}~I}#]؈Y-xƑo̕0 'ǡi Z_ðx/赧i-򼺾LŰ|JUz֋S&rS'>_Ap2f"R!X>z5vO;D  p L 7 B Y ~O>S LrA k!T"A#2$'%&'( )+*9+K,a-|./023<4r56859:<(=>@LAC+DF!GI)JLDMOpQ RT[V WYv[4\^`b^d6f gikIlnyoqtrtPuwxry{:|~ xX̅B4=ɎY~/><Lߤ*wŨfdp˴(QW+Õj@ʫshҬ#Wׂب+5:>@@>:71*"w5Y f\BU'^/dsf32 B&lmmodExifMM*JR(iZHHGC      C  G" }!1AQa"q2#BR$3br %&'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz w!1AQaq"2B #3Rbr $4%&'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz ?s]]jc ^w}L %cb:d:Σ>c.g^88|Gͱs<{a'\լH^sjY¹R VRfQcV 4m,-A;p=jJ{7q(0fw %</RWGA,Ѻ =U/ְ<;Gk$Ew+OU>@jW]#᷅w=*֣r#r6g@q)oӮ_.W4d)ddmҜTR^GsqMi%xjIt , ޖb;AD3YW=jyas㊂3T`tz&Ztn"H$fͧL+* ɍq8KHȆR8ML7J˹}ꌒ;1V IArFyWӴ֙z&7@sZp'ؒ1 5q&ܰkkwjǸV6,Z=VR";vԲ,E5fn7ֳVŗ',wzK3SDVà7:jjW^)a4̩WgU&pzR)gis6|\r!Lk2{ӬaLdq4CaV he_̄yJ6j]Oᥧ͖w3ʤ[ȋtAu"t_WI mDp~2n7CǗn&4XQʆր2Uu 2;eٶ1TI*2UDf^gmm G^K&] @5hQyZYEm)s&UȲ:N(uB F56rʡ; ok ".9+j uKvg&9bwxN${u#^![zy='Ie#͌eNRோWU)A c5鰋x𿆞0R;|.B^-ɖ);n 6[V0;w"E:,g k ',鑺ZG5zf#qR˶̘bk2-Cxӏ ǣ}#ZiQ0~3NY؆Б915}&8oJؙ86L]8O9H$F۸X4)xx옫xirQ!`?CX΢$Þ+.Sܶq\]b 2g2} a؊.I?Me`~1%5 *U ;v9.M%x(㊀ٜ犅Df$k[;>'ҳK̑yuNXÒjbl4.Q$zv.mlqgʊx2yRLqPݟ~cʊ$Jn c/Jb:K!;B=pwfN)oC>WJ&2HyOj 96)D\LSCϓZ {bN sHF~r)ǯ}/#KYcP}X7PV<ʵ5(ն|r fS}͉1+TjsMp*v~PO~(-ldGN]oP6WT#mn7ihGC׊g~\|99IڧqQ.q>ºqZ`HsHlX\+VtKv8U>_i^]VZюG|eںZf6dZa5ǞGELfư&pYʲ[,eT.G.khg(ݙͽAƊԴkHbzQO̞VcGҌ֧ij^s}rg, 5kP4zw Zdxif8+h)ҺQ l=*ݴeGJ֢ }PN-UdNE0@VS,kC-h|Gл|ڲ1s5`m-SX cqmɵmq]dygj|s-+x?_OA5"VpzUY<]mtI͊Q\CqJAp<=z1•<X_VEqʠW!Iy1l7fGc(G^}AUVTKh[ ay\皕v8xq5Ic{hw10xwK=N_jWCMIGc=zus.1X-I.2FFK]VsRt~Vl1qX3@tKHg$4 N7ՃrnhH\UɼG]b1i& COZћz=;dZ-P'5x^UӤ%+٪sQ=L)v&s{ eu.9=y*s\\ڥ<֟j]%PJ6D y$SU\P!,uF|;sImXEss$_2̻n|G,gֲ,Tܷ"֬ȳ,aҔ}VW ,%&gݸZ>>WL_<Wt[Yukc2N3;+SHƟޮ}* zԦfzeIC&®BῄvIiOIn7׮x>7XjdȲ/S :O|=3yS>x^WZ[CSҺ&sFtJ[O)p2XʆJ {Ѯ!POҭXZ,PbsJzRЊPU'^,I ~ Gl.7_Fi+dhCyGjkȤTt6./6 \n6q` ֮E797 #2Tu<)9W4Xҫy$6)LD֪WU͸vDvj1.Oi̤WyEO>\$WbpjݶI09ikT ץA%aGjdcWomC $|?5>EAl AIpz:⬏Y`rZB7}*X4)SZAc=NN[y,漻ˑZs֧aX,0ɭU֦Fsc7jj5zU{Tӽu355j[ Qҟ&`{}*K,lPG I"iF?#Nk'Adi߂1`Q}wV&MC˗k\D>v5 ԲGՔI\Ɋ'F8 T005cJ.y+aXY:z[-=^1vQdU[|vx[lj5J +YaǟJ$h#G59 ]=-rVf쵋Њ M.6|V/ q^zj}YkT*a[;͌uxLjS|`^U yR<MG G+ѯmh<%$}:VcZR;B.=MkF#ӷ[=qY/RE kL~ى k.kg2ڶ-]~F@Jg !"0+Y\,e5}:[faP=fqpEQ֮Nג[NI2LW![.Yͼ- ⋅Go9򤌶2{y7 *\ծcl>R( J"X :olgB#gk=߉bzG63ǥ7Onwv(\J$Z6$q#|E!5A#kzqd 3So}K֙8"dSBrsysvH_'1TԂzA(&gfGS~Ե,[?mhto6c.s5=[xȼ^֦]Myz]i VrrHտz>| @Ȭ__Cc}qY=n*P%^E]W%eH??@zϷ̽cuM6b+qc0^.bb4X.Z`$-w 185KmX R,u®E_J~qڳTn#YRA'۶g:_!Md?gAGc4ᰑqZ"\4PU ST [ Qi@m mQRϴ5\ǒU{ֲ/bYT)V\j@B>NjjE)G0rjw? B9^3T<[q"C #/LmEN7֨kzw(>ӹ-Xfo遣wj.b.EK&r+:`tj1ɶT(8OueyJ!'!I''5zShZu4j||՜r.5=W#VcorVswGp[$oh/xk[(!gIw#etrgXM|˷uiQ#G\+=B2mjh%mk-gϩG3ۨ뻻O\/%&^p+3Dk^|Z?f}ѯ4]Gsxm셝!y%$!|JNVy/84;10L7/xKQ\e`sjvx[ ~ښF({T@H93xX(,F9' x5+7h[Db4P\(Fb8^浹-1rk6bVVw{`վ)|1Imlzځ&kc5[ }]~ k'?7QM'?UDž/ԙ`3W|@i2n`tjaNu.An!xroֹG%ЀĻۉ?Mä=n+/8 ׵rJFuStjSLIri/#8[Ӿ+kZ$: ߧ^躶aigDgFq~&.A[ݙ!d,\zf)_CMZI ɏ`rm0,qȯ:/+}$:">in=ԟ2ˎ+#_\}K xm-`붋gwl)/4jvshIp|{TI ÊKpaIS!$vC":WGYye6)&8 ̀Jfr| OZ2[Y+YnE犤YQ?1渺ԛWf@BZOMm,XUYzc AOj\&b̄1+^U?*<V.]Z\-|2`HOU[XK|r=Mmܥ 5zsTO^pE)QFt;rsQo8k]iKqwӿ' SޠTexa=ƊVpӀG\ >P ZM!!5NM?Z2-FO8{V}{"#'~Bvr@y 92 %^dD-ui[hDT/G+S-qd1n(YvTV4Yn®s +A'JҒ>8@3U$\Zdj&N+ԱKlpZ牾̃M&fi3g,X*W%⩳Vl$)m|*+y=RS<20zq[,odI 41i_=JJNw w W^] eGE$(Ճn5mbn&Iqsi'?KihTLP(WhZI*EoJaxcPM崪TH0 }ow[yldl-#:;|oLem&ΖUqܑ-ҵSNGIs3kӱs7MX/?t:}䓝T|/Fɮqr1^_?̗w@[b/zwHDp\^+Pе&Ym\Si:? 4M[Wx/OMFtWZ&{I-#9ϛ}cԼ7^bz{TT#{Jc-@|pӸӡI l }K4#;X*k+ON$gUZEg6npD`U8ے+|I%Ԛ2~j_\h֖qr ͕Bru5ǝ Yn: <"5*M{c_,`Hi  5+'-=-F'iCA_qNi1whl.w-l!a ޼3L%F5MJB`B [b7ZRU 먱iP z~lU>S5(Ӆkmq dW&7NlF1YI8?uRWWOydFO3n_k:E{SBּǿ _h[oBO5ڧMsL>\V$uy ;;KYÐDlN2W0='KeyQ3L [6ڵoKIHyEH8qPݟMlTnϙ銡_n0z/S}tdk$@yOZn\ZXMҙ tS4BDj-X\ z^[?wb="bD0 pո]l|t5m?{yՙfV49%xMHX F,P&KP㊞M;Ρsڮwqzro<Ffhb[SBKr*ѴӅ#J1bν,6[q{U{FP#RHK~M[*αyt7֢S9eyX +p>eDp$Xd`fsj9[ӭ>Њg0]bMaXJ} =ƬJ}VtT9)j-9GԘbp);QІm3j,rxK}9&U *kK*IV?[FLj MYmWlC9]ikiYҬ+ e#IchK1K% $vԭ 0o\ qT9Ik[ ldgj| YvMh2ƉmobXRLuoJn*kOu7}lBJЌVGo2D/ԔwdyłG6{0c(qX:uk'neH-sQ>>RI~EIac$I>2=m&-|ڰRE,vcjG-RgkҢQc@j2rhޒX5~(zT$//xT:P*/O uZcM]$_2z`]U9#Wĵ6.#րx)/Nj{~sRC c4 aZ=sUn;JRR4o93ֆ$ohs?#b&L a!D $ҸEQp2o7FX߭d\H<~i\͆9MCŏZkQXUH1E41{N+7Xt+o_j>hvsKl[f rN~:W5_wY..Hضӷ :ѽ'+Lhr3ö.Ks>'Ӡ_5h^%IʹJ_~hfo% _xlj$bRY[exQFwn2])|&1xP֯?_on;Ѭlt_?gÞ$^IhP)-pz:noTi~ kƺ6nRmu4DdZj6Q6zݽ̈́@ mwj`wՍJnOm6+ qt. 4l⯌o_ G_1^ycwdrGV}H("8SBu Biі2j1oFby5Й^F1Î:oσ5{k3rI@|n!\z撹Ou^%Nyx7֡i"{3"FU׿"̖^YA*H\χ5{dFcWOC[)ao3LB&yɯY_l?;Igy0Da>S.F*yW//V̿/=MyuC`}m<]~lv7:i ͏Q]5ndpT67;!#4r(3T=l:V&^sXAs#w~ԹF_dv_Jd-ȧ- 2үi^E^F",uϵDdޏrkYߛK}ЌUYu6w2Jm"/>, Ռݥ~h8X:nU=FWIN.3Ҵ<' ;ǖ;Ej9`gJI hP tZv)\?jĐ==} K/mmD@~ԛž"[kig^|Eɯ.YnTojWKz~o>[VHUge &5SOf!px%ޔM>bϵkK#YzqTʖ>[X%m{R[Ȳy&OMfLr+h2ZvĀhS\|=ᘵ=C};WabmlG>ԥ#Hbn.ؒ߈b=+Ħ"2]м;<*x (2S)!v1X6>8K1܏R e1]iZ` N:ŲH6zUc f9aIy<=b'UmímcR hFdc]\C ͆UsgڡŽRhggI+GysZ[IkFGsdeBh`d\Ÿƫ0sWM im&E}7~se9&Kw'Ė-UO~xe.۸_Myr4..ǯoVuh㶱ȑWBcFJG=뺵ՠӬu.IYÌm֬+2{KV׵8H"F55߈ۤU{,@~+s_ ,5WXtDD$0 |[>6᷌v/¿ j7{Z'մ~y$]} Oɨih-V4[A1Y''59~xbOx~fIAPGQ=]k^Nac޴P=3G1gqc$:}p? tVxOFIOܓ#+6MI|GY< [#5J BMKm9 ) r> P.@{]E5ZۂcI-|;KDӉ6Cm=9 Yh59 =|+0[Y nt[MܟVmt; 2XV2(b~;$gX$>LkY𱸾9f|"HK`8@ډn$@ҧr⡶2\jW1Ґ@iJrl_U{LZe@Iޖb#CsVcp@jNFWϺ2PYOEXIvQU`zMh;gP#VJXqjZ,`OҘy6(]3~=+ZM,{Zk-"f)%iskY%X$7!azWWi~"妬~(nyKe 8@s?gQz~xoP,Z܈  y&?>4O(4 !JcmxK SuOǿ_߇~l<of4(I+In kcNxWk?ijvˊ+U"f#pv<:Ws|@QYʦ2޽^Ǣxkx?SoN3m*D>P:UE9Zܥ_ ~%ԧ"r8 <OlC+O|]Ծ_Vm3O l{Xw=_oе^1 |)+49 *k$ Gʞ>z^:{Of ԣGEW!P8^Wþ#t z7uΓJ`bcnЊKYFEƃxoR[,$PN#$OS:qjMRw K]+i_-2j/iF۹gP7ٲyodc}k%V1v=:m"٭st1Nom.J:-7M2Z+k{?Tvq^J\Be>]GcJ k i_TVzPhVlYȮY]n%q(c$IF9tm-(rN- [ma*Ww5J$p!AiQP\"29Q <ȧE$L U^!xga񟋦ymZqT5[csp26O?SW74r߻H4[qI[դvW;*A#?U\ܼ<\MɊ;^ڏu{(/cQwO^? '!1k1qՇ*.-&ӌֺ.)^{~sny»_ k 3Fx'?Z^9ޮ׾_$+.1mgs"S/˶ e dy{M&sa 8|E*;WS@n,'sG4WcuO5;QZ湥a5ާӚųI34}QdV2~NĄay߁n OMY ^FGc8zomgE9osR5v߭'XZm?1!DJ223Y^_9@gAnd/$/]Oc '^X#%n+%0В%8DT_Ɩ2ŁǵIi>DBNSJHЋy~mXkvkh $+xg[V5T`8Ի7AojVEܑ*n6a^)XĠ]27*=3Y -f|Ca(ApG>gO.$^[,У~XcW= xW\kR'2L|#N z&l$r`C wͨ׽[Wvt8Qۊg>52v^{eԥp $YEf+T_\9iHAEq޽*2]zWa!|n1koo\x‘?6:QHen;vޣO^:+Tw3oJ&!甐ʥex]Ok]OwiݟJot4W7ij t'sW 6v%mcВYeR$/6ns^Kes]6k*mQXZa>wWfЇv^+92hxzI6\GMf/DX$Leh&: k>ϑ$E[XL(0N3T=ړ*}@}Ey܄T(wvZ*au'%c'56(h$NcFIT-OWQ8[нE->n}k Ƕ2y]ȿמr;afXկ#<@x`W6li."_;8Ϗ,-76 ۑWo←J{;R-\cW|gMs:"Aqc&W!?Ύd#6^GaY7-t.8Σo0;?kSi`€pZ)׷;㹑cwx.WbǖTTt8⤹G,=mFբ1Zb Ф, ; SiXS PNO ,M{x5'hix LPtolqZ!Tʥ8>״IѪʰl]`r{ $sկí$-tO `;AX0pzU#2VJ@[vh/I$c?f~#[F(/6?3gOzƺ֚9co!TBhdr}kGmfy'C_ N"YBt%Ѵ[ɼ5bOZܚ=.gt/pr d|hՎ)&"՜qӃThq |6 uZsY;b+K{FNͅȞ2B2zU&W\#Tr|inknZ0FqY΢3~kK0ߝery8IURc<rȘ:pG2 i.q>v53F TN.x ٓӐ8tSlnZ駻c[@R =sW|kb `.2w ]nKKhH%@;\U8]lt~#~=3žvfk7o|-5XaM:F74JG\:nGe:(:*jzq2Mns\_o+W]Fx/4;U j&mX[Q,lEYs;^,֌$p=8bB-]2:Cū\֪+oXx?h?yX>)Is᫏c1?kCqw l>3JH|Iik.g2& z48 φaMb1vrO՟tk| q6pxLXw2%GeP 5Pyg+Xq^K_ .>9\ieiu}.yIنG;fƍd*}FȽu<]5F*n^fMTJnAmczw`ű?\Z_Wá&q45 (4/6CpstW4fw̿dM\NzA]Ė:#r'gx@<mkqnTf_t{ƕ$i .Y $d~C5XM-d<%:Re$Sm'p > 7S׽ll1+ 6ʻ$AǗvPyeb4H$k!$V χOVvtL q]v_76/CVt/*;F>53+CE[eܠ>=N4v&6auW X+!(f&&iW^KUH{x\zɧ̷w2ta zUشEԐXMi8+Kך]_)RXAkh-4'0N\tҫѕIs 5l&bmB^8 |7oN[ ֶGû^&qw,NL185~xlBw؟jM94~3D1^YF"V9+ӵxfM=[Ku v3һ~іz=X%̫5L~ٙYXaDYޕ06 t5<*޽xPjΣjlE<g82T oU=5.ne*pAA⵬[L|yڱ121?RE.fsVKfbac㷽Ggq,msXFMH:?ȚE);f׿KGf$Dhk`5Kke+IXIX|\@2|ӟ/کj֚S+ց]gunr6X[ݧn>oU֯vr[s`{ҙhehZ(š'#dg%ִͩ2*gG]xⶴ BǙ9b S& -ۭijKd}|H o.y U/ o"e\d}^kCnQ.4 2+3j:+IE mtY+G l }h֟\8ef6}⟱YxovDt)>,WrN؏J sk:r$V@OZ,;]V^,O%r1+W:^%ވ jV1g>ҙQqdzV$ʛ2P Mg[ ?֬qM-1KZo"|'Gs)բjЋVܨ۸#H/|;^ |1rM.DZt&0@6>*ZCk VP.@0q^o5֍uml3J~v\P~鵒<ݫ*A|i頬v:e͟٧Xs.NyW:|)Q 1#Z.&8 ۙdH[K Vx6@ŬV;Loߊ|YZD@[<=+__on|<KV0_E-8sӼCmR4o&`;?hKоȻ= 0Oi:$ɻHhV~/hrH|&l"Υ.Qel@-٢,ǟ~5=J ðO[2phgkOppji*!2?QVp;mOB^858nWt.o/\dZ^&DVy3\ⱹnI.8ǽ{6xsGR};IrI9r$=G-Z MvV Kao];{rz{QM2zDŽfЧ-LWxsIޕmEٓۊ*q_#5.v4䌯vMn, tE}7ͮwMcͦ$ڴ̜^Wg}ek}6S0XмG k =+&fyτu(oN{]H?,j:mnAa,C=Q&%1qM5$o~GH`%_\Zsu*sjgG1E'<kЭQ+OlOGSra^n/Hz*U*wc*_ ΤϭƼn7G#TwXq{ozGXO >} 2dCkbF$ݳUSptĴl|Mh\YiocTk6KCȬNj0Fϊ'qAhРtU*GQ{[9\OmJpʿJSz ٞ?֖n-o<iuV,}sBQBle"V zTe:vf殥ݙFjΝ1a5s^W͡u@R5@=}3Lkm;* czca-Έ\WI1N}=a&'ޱ ?vpGpź=|NԮo:UoA<~yt7Rs,.bf6`Lެq\v`^GXk[bkXγ=;Rw"`=x#y5N-̈́+[p26(8ⷾ?Juwm\9Xa}kxÛsYXDwʝ̣}C5Υe CB2>>ٞ' :}Hj =@Ql+-5$cXWZ4~1hg`rx\MQC7u x4͋Grzs-&{=Q$rq[xڛrpH;OkMc{'~˃7?f/ikiMTlff[rķַr@n3V#~!؊8n-$rj}B+ľ0Q$.Y`UrXT6ӎ1^UAZfcѴU=s^ŷsMkmZF)CJțqFzSf0^tBY̒wi&+9WDNF4w9sRE`+SvW֓Kھ̌dWIY[`6ۏA6l`'nQw, ++n?>k`ۋsfxr17NFx"%m), 2cq]$kbBK.{b&j6kK3.x,I9ijbfPSC.9bp2exU#4*[wBkV֝`A\zg9hOxZnme_wLtc,  "7q[i!=Տjq]][[Hsi#>SkF[F+@[P.?ÚWT}6c:dg~hSM|_\#2z ŹԢ0Q'z_="D4pz;]zȸU jUdڎbc6" ?q>^y+4m2C FPwxcw sa厡3X}/FQخcvPOXn?.Τɕ֡l#3x#`?Z ]DL  v #^x`ʒ>⤞mxzkpl%?e2g 5(䶻,Q<~X+q[3&}g" $⹯xk觟[ؐq9tzqMu&# -dw3{+1E {qH־Ţ'\aZ7IMT1Ȏ [5bnf,8ϭUL6j\ni.FwogxE𥴖BN@O}}7mnOt]k]wEd`œ]CKoG,E{ YoO_ #)5'zo.%u+ڷ't A(}+ @׾n"]zi8K^[ѐy8'nWO Hl&W#GZm4a$ab|Lr1joڵmE^oZӧo3ҡ 6Z$ևl!}?]jDwJNFj FS-ޱOAzna5oÚ%k'#M82cO` 9{ۣ*簫Wu مGzUS⦲j@f?J]徫efJO[SG)m喑5*[ /!h3q [q=k)Vί-8PIXW13#HNMviSih}%D=,>f12Id1vQ#URN bz1ȧrZY.Ts(9U ZKϧZ#?X?:岏F0F.q[g8W~8#[2g8NH^I>0[fHj?xǶV2,<'֦ZV%pFMp,L)y SЬ9]o>g$7 xj?م,!T90iqߊO`=#ƨw<i ҽ a ~Swʚ/hҽ7ľ6Vnڸ+5̱1]9uuikYgF?slf2]4;s_DžfMڵ[; `{W4p9FŲYi6;<3km ee$Z놹[NXtc ߇z~O$6ک ǵkh.bo; \Zb'>3 Xs޷|Cxϸґ`a*ܟ\͕Ox_ \[{-_#.EdQ3ຆ [nq`bt@1-LM֒q}:7IaђAW9=6ѴB`~lRe쮚;t5 0AecO/.@=E_5eTr3k%RWMK#UhI[퇆=6[rƵ,5x/e)\ɝ 5mr[_*8i>Y?|m $8 tzm4l@ixT'U}U-4Dq-w@ힿc {FڇәԂx[bH-q΢L8Z߉ Cy\&Kjs"U= vc|kouHZ=Fx-p=զDkvY!RWwf8uB)`ֱm.,$vDmiM_&A,g\F⾠>%k763*Le]1ʰ|MId)o ,ӿ3~m"e1.DUwƯ|s@B$vۜO_"j|~t]ޙ欲y,>oa_E힝h3Kq4DF7 g᳨x~"Kh sYOyҕIYjsZGj>;z妑7$maL5}7~Aʉe't$q5}J8,2o$k+NJ^k}o!R"܄v´=Ƨ}hvV[ǧOH仹O. +CMO)(xnvKm+ʓ⼳4I8ܿY+sSA=uiu@XCke$.P~B.t7Y}3],6QYJmxǵfj@Լ>cJ(Vɥ!0ayuMY.n:O#^N0luuZ}AGc&lo4q~d\♤Η)V>Z] JNZ:N5k}Bh,Ty$`w-smIJ=7Km7A&G!k:Ss]C␉Q/[XƯxw@kUk?5KNo~kNsj[crր4o|yv0GjRr*-2i'W]Tæ㚛H)<\2Cߟҫ˳%^umc*|! L\)\Â3M&]F-.F8i .N{Y54#V&$vT;{z[Dlv+\ >|H]byF#9 kşRҡF*$ }EP̌C%iu L O-Sj8DE7ޥJSApVb7IXFg6JIak7?ih[5'lhgbڔ3$lXD'W&F\h(<,jY|hhyap5gW-"} U4ctĖE<>{F|Q0$g(hscRnw/E>-$;i|im.ՅљzWn|,3ܴ@Iz bZlgУ`V-| w7V  lצ_JL@"q*M^b(xT{=jܣdNLge. W+-BeF<$oS{iHgYDM{ye|hronmy.sGHxaTw q5^Ǡ,0B27%ϝ6'l.㌷Ҏb9Lp-RJp͞35T78Vw)v :JUYElyu5K]Oa%r+JyohkZJ(nҦѼAxR{vi3 eNo/#H"pǵr~#e4IM@׼ xdc"[+ŷwI%9=T,"M|g?="QE2M0i`&At]ė6t$wevdV߅ƃ7a8 gG|?+Csύ~Mk3j+j%I9alRAjcלVH +i /%> [ u+ owsڛmORk}E_:MiSy7qg-hK euZ\G-8V*c{GbرSOx V5U%]^jW7>֖KB7v~]ǾB&|CfڭɎ4 8G*_VcNqҶVN>76V=0Pp*եI#$`zqRM^jg Eddg5V7zcu_wHolv̪ yuW+=N/nfaI;΅ 9 r1]#s9|W: pjH'>"jɬ[GskN݌ux?OO~B l`jgv_YLKJ4K&&Xf(.vzsȳDH5ƹ`m:cX:l1i+ X~5C}9W_ɔHnᾂmnV"B8whB {B\ [ȝYy'"cI+Ȯmۻ&<ٓRi鰳Y_f2eA#jTxrP0o!h΄8-nRsʳMCd%! a< |ب?h}ڭ~$W3"˩dp\mjԣt8d1ϟ 8nkSJ2eRӎmf`&nTfIU=:V][#kbԥ%fjribpw qnߚhUa%1Zkk1i70e<ʯO1y%L*&o8}NF2yQnI oIsɕ#%m8 ڣOe&FkPcjUXKe%{K[hظ3}r$ta%uIH"ㆃS`좼eA v۵uÝבhZ~xyu_0M&c^}*%#־OܸKFG'+"8mNU?h1x'~^K;'yk>3Njtء`` c)߳MZ-uBvv I)9j=?]]#P"XDe9ێ3]"ۮXG>uZ:={Kݧs3I9yov .JKDV鍣5c,Q%ǘwvrsZUȟWHe#xNX!QQZty&pY&_e՚ ;g5U<$$*b[ؠc!ݘ]V:{FG(%-("aAy.CuM]J+; c8 jOH7WٍO c*8'>"}'5,l:i.uրb5<<mɫ_/Q1IkkPZ|%bf_ Ҝƀ5,?M6|c8kI{2PNp1EMǦ+LiEj"L)eur ?ԷU?]PJ-• t?: +YF^rsW<]ӤG Q402CXRN5gZDQh.by>APLvz_QLл,y4|JMe @b; v1+=[hczƳ5׾KB+W IulxX n5ƀ/BXZ?6EC/Oj4_) )~m=*S?- Sǵnٳ+Bx|Ɵ37 z}Ԕ=aNG~3VyǓ*=B 9?s|AGcm#d|09^#]oft h"dnzgiϨ\_ᗃwW?[{WVHɅԞk5O-.O)W999混5]]t?>֮S%rz{WCk\e2 o'|9[[}615l#u 6 =v$ytD,qm|wg7<;jM*]MnP)GqSp5yz޼*H$Lz+s\-ʞML??%t e  ہW*I*CYVflaNr>$Ӿ7)KY7||Htz奜m{rȻPju~#+.xK7rdo {}kk5߅[ZeˀֹُԶVח^%]I"gһ˳= ?7u;H4KM~{C |rqy5_i^ lA{ٔc8)kw݉6[<2+#&So 3q4S3Gm5Q2=߁⅂OKitCkAOmf|a^-㯈<|n4$Z1ZynK V%E+orύh-#LD:jw%mRx9QZ |ykɪڌ^X0k_'Jb?- Hs^xFG+HCҕGf&^-4]g"Cu\4K }?L1ܰc'cU/WMsY \u|VaHuۦ- ǐAڳ*)| g%ܸu ܫ<( K}Etoae}~Hg$wj]R}5(dPF6Ӛ dž/YawFw;*9? |oydvUw[fiI: xI`ܫc@ s_/Yd4FCy9BNsuI~Վou1,,kĚGM sEIj^mޑjDB$U7ρ4Ylax>aB1Ҏarڭ qt}R[_ j^"?>ԈcXƽ [Rc|R asE [ g%Nkqχu[ {8"Ms\W^$[R>Qv~/m߷5{4>24 e}q@m#rZefy8J#i?x/U`H馓`HѤ>jFs@kZ;蚒M~m|O=V?c,O pEf؞=ȭ sQDP4zT:^$7\!#v[^]B~dh.a#{Ծ5櫫V*E&?6"puZwme#FcVǂ-< +M=2 Utm^[,qQy3"-we,jVV9<]i6Ƃ d)xOqV LV$С~q onn&.(jF+ץQDO䚻iؑ4gymG^_;@̨>j͊[hm+c#fU+ڣw m5ooygJwƭ?YX$F#13X9G>I#e64`ӊE .&ji9:WA]v+$M˜V}.T/mܕa+ b#8Mk[O>Y$i$ǚGty.劁5rKӃ=!8s+qfGS^ycftvc ;\π+q_3yrgnOYr-uGVyU6/ca=| dft79WLO(17Sc5z q^mோr@Pvt@צX刚ljqgL_1PӟZTF!v’[K$Bc@F _Lttl p:qZF" |AoN|ַ}f[b^@܌sXG݉/Ouz– :}j[6妤l9YI,l^& u˼8$l=*MdzNӤf!d=M\a P=6Ϧ\ft"-4-Gv[o"2eV:;_A)[8'xfQ'.-]5T2J ZYqv*ϟ;zo3I KP\.UtOͭ`g^WWƟj-?Xwko>"GZ UXӥS׼fc<񔹅GNs8>mYQwqe#I7E1$.1!X47ГԆ##5Gm7`պ\\nfAjZ/Z& q\䶩Wɕvama\]v11ԺЕXȫM8WsXYEo?܉bNoMB2O(;=VD n nfSڴNΡԛ>Y(O2+;TZM6XsVi\5v4%ԢPLlJK>F)zne _6/6.@3ˏJ¤5)cKgB% I1WMEl/$3n+՗\5"yV wkޱ4~0&Fx:GV)YJr9Va^8s՛7uaEgQTZሴƲ>l5N$u0Z7(!AKK{$×v|&jy3 N.RW]M#Kw›w?t:ԭd~yVV}J|y=뢖X sp֩f܅Z\gLFHǷAn->RvW'U]NaDȏv{+fQK{d,.=jֱ4P7&-\®OJ9sƼMfAiH=Wdcּ;m sf pxhM3$WZ}?Cc:6PS!^V#_f漳-iߍzφl&S j-#ûg ׅV-zU(4Zib;Xfvp3Vu/E ]LYOthDua+WyA:{?B&{4 ;~{xkkUyh_YRL \Ӭ4|W#,+kQc֤ԤMoUh ӵH@zB3uP٤bsZyn.-dve>`i5-u@jmԪՖU\\nO8͔lrw`dqޝ YY a*S–_>QLu{/c+[kJ=2"OE;p-&ˁUެO;e1[=U&*ġUۘ;/ʴ k:Uܾ\I0r+;H `:m>J`4᫗⿋m+iirO%0:Srz)oQűO[e/Tlt:Ρoxb9μ>O5lf`oI6jȮ~lcj\3@Z?'r>Hi 2F| -?ɡ|2ZW=J;^ \Zf+4݈Ws6Ⱦ2BaQ|zgk |tswL_ Cs$:ki |?z0օxE'su-4j:LB!w8xwb2gUkEȕIYpݶ\2*G`? xi0^3] ʁ4ț׊ V~"kﴫZlSkFhz9r+D~6+lf;]lO<ʫ=[ì?a2+A*!U*4I[{U];L<\/VE7d9t9"ğu Ɨ Z+kZ$Dqu5S.N@i#r|{muO\B_Az'M-[إr9Һ&3lu|si=֣!\'>>|+N6Epe ۱} Ǣʚ`y o v# oA5-lKNzsgᕕh4.Kȭck+PHINH[<ׯAƳ䯇#cLvμ|sklдQ"q.0I9%IԼ9;L eݰ:&sIt[IT|~jg~loڤ)<8Z˩_Q)\SQ+o9w;b i|akg<@`MzS4;>|G(.n[m7AޒԹY>*Luq z"'Ӛw1 21y>xM مvt;"==+֍˿xHIVR}p3~*lu|I~ 7%Cvsc'PcK]CVHŒ7sF8+9 :_Dyu-ؼvsԆ& ־[6f&#ʋîXx#AK[k(nws^g M|,IN쑏í7zOh꭮2*]徭Esqi 2u[ sNjӰJ>3`<9-̒DG\dsU{ 9}k]%np:RxK}\oo{=as]K^m~vUu0jdSH֣}v ? $ ` ЯZ{ l{Wezx}*Q^D'5x 51D:&{~PXmgQ{!- E*;ӻ&$urZ2cOݙ^;C4?h\npsғa4>5LX=ȴAol2F ϥ|}9iE12x:3xOX/rt9?x4QDҧ%}F.DjKTEά/b u..t|I}[ ha_ُZƩKc29#%__ U_7 ><3H;DzG6Ar$foƹm zLRrѐ|BUՒapBSA7 .!\T;WTկQ@2kҏ5}&Y$l>_[EtKmll\Xb$Ixo`c^Q9!nKӦ~SAaRˏߴfXI.B8&ƌk?}k(׻aߘd"!X~m<1Gmt伱`Lz33,vFҷ-%Rt9"ͅ]RH`l_٧#|Yh pNkok5Ӑ?*{ᗅt |b}RI0H_RXm#O9YG>f8h[7˛p/{pyؿOSO|/ .`W̸8hϨG!OٛhX)AkSfIu|ͽ ĞR95SEH#K%[Th$ʶ֡Ml`ʜVVw\}CI^k; >ѦOB,oT'=Q̣yMnos~#n- D*\+ g^{C~k5 4"ԘBH57LXtm6z,h'@ n$p kwhP{v145;3ռUnN\DQx栂¢ch,y w/␱v$IBA\'B+o E%ܒ,qbx+yRlSn .0Ts\tkVt?B\!۔ufP10+GCVp7vj<R_\1~Rz&2?p2woGag'ޅ]\m*໴_kV}ᎰmQlbn 43ZX.AqE̹W^#\j0m!c98Uc$P4؂K(gS®;zxፊ1˜Z&VX߾5kW^yy}kxNvٸ>ZGcKΊdj]F$H؄z5fH͡!wrIr@%܋F*6TmXN'MAtFW-Z^3K 'q=ǵz~8Nk|Qck%ڮF35 7/DOƻsG?wէSkYѓZ:ŭZMQ'H;q^ue"?+_ˏVe4=E$if"@8cJW>]FOi!0Gq§ˑ85ei.6kK[Fu@̓6~+KEokda ΰ华9#l euU 3Sa>Ys_VmD;gxswx}mtsֹCCPmA粒+}FS0}~*$/Yͦ)opWC]kNYՅ8JR<\[uZmQ߯aOҥ. %^cP]LC9C.:ʰ|Y5-*]d0t=⦱=g7I}s_VxcEm/LȎ#p#=3+zfhNƺjlǀꢥ \d}s?!:ƚ FN"i>%tAξnV~:mĎ2FstM0EXXˀ+ȩB[Gh3"#*.v (-TMq!ƒ$ |>|IxLR'<yW|}M[ Z] 5A1M`V``5_'7`EmĦ[SAo#'vZ+y\IGG|=4t_O_ r6O 9Z_x^}]˳`N1V>-"qjT&S!Aj-^{U!b7g&R l|PϜgYHeM+Oӭ4u󡕙G}T~ԷZKX@<$usq+w/pq+8|@sze?>#Pk25|\| C φm~'M j33X:.:EK,Һn|eT4q)V/%E֣C(#v-7.ubq ?SHO.lNbvaIR? =S){+\cg<3oYM궺=ق˞A~ğ- +Hsߊ˖nG;_W:WM𡑥 qJlj/|bY崵%0{wRLvUı/`'W\T|9 LWeLJ X+v:nw07<+]i]k"ܤn.7m?n];C6Zcy#ҦwOCJNR-~(5K,ʰ;~I5'W%)_ _;$J\ûY4AQ1V7Rkuj6<\ k=VO\m^1+_ ~mƛU{>]\Τțvc~ujvj-,ssY-xְ-Mvfi Z40r6>YG+ oZ}0$o+қUpL   +HP<co# WC]i ^{o&wsz[7&wF|s}5[(h`qⳒL6K㱪>%ǧߦ$d;xA;x|H8lWx7FO\k-2EOphhwfq|_}᯳ޭF Fl|}"w\iG^1yţ۩t6|1ƺy#;T!ԯe0)+rR`}- RNNkw.|m\Mitsٜ 3p;rYiTqdQF@5hU5B$w=p hVaf\mާe3s|-<eG[cω!E_q߭pvzQu{+Aav?]cPRCmi} pe){Lt%ɞxk/S^f k ƀ)<"! |=]gnWti) Ήu\I; E*1WG{~ 'G.YEX9i^9ѵmyv:SÒfn9<;gu{vNX{hwg `wOjм-@&6gXS{W6Gxx~sYoSCkEO,reXo$t Yu-#BX)vU>"ul*$Eq8 hrȵ;WčrBbѠ]l7Bz5Mi/彭 \UZ.y u2qVɡJ"+69kjڸKD's`Zŋчb8=*f:vnm3շj(^˃#+PfJϓKOef#t<[ZV~Ѫ5~ݚ1؊}-t+ha̬wgTO|u4z$yXvsEZ!~!3Xk=_Q.[Y-NFfMsA$,'wS΢Oby򪇽~΂7Ss﯅z..C]$NQ-`A_<~_`-OO0׵/%Y-X"%FqM&cPiӃMuUBjwus^.>3b==M?h#S.Dܞ+{ItAΙt-$; ~j^,^,ǁ Ӛd=8-Ӣo9jf_IQd2@4{7GyJH6玵W@SywEi7F7 ,}9{N̾'Y gweoo]5&FqNiA@9Qf&8ޓuR\aeQ5My1g'oj0ƒA"ێkHY 6Vhv~j)_=!P|ޟW.Mjan&/cnOOJfԫv#Ҵ '33v gެ\]T)]ҹF5a*01]ViUsFYMhcjr[rDoz5D3mִφSOwdfyx[I5~-oxY_5Cv-e]74{wrBFjYS#ϿfM+VPx&X`dbҳ1:'KX)|R% E!IvW;rrk?ۛWE@GQ]i8KR֪$cg*rzd`|0񅶁q,5<25xZKm/&f85{6Mዔ նA\2:6#t!|JMCL 3KO$]Pcɫ^ =:D4BB[j0I|s:b|4X[\j6roO9棻x,<< rB1b9KmL#PI4f+e`׈~Կ5;崗I牰~R{ŮZj ! jMf19"4h~YlY'J啂&5IxI]3JHi7_N;RZM~<2,+exUWdDxXT絾P8xާc㦳qinkK1w3^viCq %#t=M_|VEʪF^VjM;X^/㟴Om|JWcoϲdQavC%cBGZE=/-| ;:~ Z^x{My_W(m*vDy3ֺ c6-Q3ۥhĚ/)NXɶt?J$/xӬtXأ]deҴvMfx$ F`չPջ|I&Ed_Z-3PuΪј# TQ)-e|#2 gIYW߳EV$#q\z]KA bQk| 6)Hͭ heZ蚌dr^MwRi$ڟDb݂^p/ǧvy ǗVhndB6_r־ GѮ&մ]OJ&bUV=PqҰTmXf MG~2Sqr,|J]Ta ^ ˧Yc3RFۿA_7_Ḭu MĻFIW5h;Ygjj}A[i3I5ߗ(fkXnzg<5⿈;E915zD><.[[z}֝4y| 8wٲVy[S_-y#F;О[ GGvmt??ho ~d}"AWG|oxki"V%%ߏΎFͫk3wLqmq|5~X*NQsTikZFvY|fмkZiՍюU r zRq`ꭊ>2 `s~+CohAdKq'ȸ߀yJ,R֢@s"XV gW^Iӊr);Pe~^yk{xm4iRyoⷆQ,4{H7Ȝ3׭xį٪,:n%T}[m42%Čw}]ʑOpY™py9 tnoLIlb g?JЭ͞Rԭ!s#俈! rx{B;[猫c}cMI p x-tm~V8>F}*qNc|Qyyo')IYp;= Q1U-bFwG㧌to ;mtɭg77%Tjm+㏄ @҆ǩY-؁m\y"pR37 t6~RrJWП>xZu˧b>Yw^>f?¢mRɭeIe'*ץ=ǔe3Ӧ*6lm"r$aT;Z!hXI|ŭI%ow_vS|nG%xAX~ x6[hRn{m^ 47ID>.MU\"±˽KHhvZFopaFL$rh҇@>lG$r;IZ\,So#9?Z#WZ!ЈP>V 5gɿh˯Џx,-$ʮwqҽ7KlykWf\1=k_jW yۚ Tg9ɮ$c(6ϫ_64ʳn>/\n k u+ϖ_8zw\lt ^UNy=k:ǕFia609U(l`FL }ƍ  >[x,52K" >gsi%Wl3&+?X_@L W>TD6 X9>'?+*Ҹ*X'/ծN03SGo/$8;y95M'l͑ڭhR಺3 r2lm).'v@vqEjGj$Qk*g+[^գQ?Q/*>u{ޑByxhQYkjDAʠB&" *l>c6֭VF+$xQ"!'Ұ,5댚ͼ#{:סX1Oa*2ʶz)5dLsЖ V}k6 ֟t3M;ωs3^@4#Q.xXWiLv5 <5Zs $4XG=UȚjKYABkѼa;e LW vgU?tO5;*Uճõz-9:,eoqw_NvU=1߱^XcIc`Xt ם]Η- }6u+'\~V=$՟[ 5s-Hm4]?OBs$ABk"ޕ{t \c5w^T֭fk{W?潞yE1P@hL*&H7lnp^kmHNӌ~u)6at``g`FNW'kxWŅؑLs/ '58ٛh5{UNkL.`A,0c#/KMx^c-0Y%23x_ŰN\`$+jTԌjU?D4M!n@<Ľ)'͂| 2zv^*▟ԣO5b^~Xx^?|kizDA}R0Z4Ź\ȯ|/_˻ eypHo^a; X9:,5wc/?l +B'Rj>M_)Oc?͖awP,;zW }93Q@ʓǿj_>J顅^+l"KKk%%R3Dn135C.-Ri2JTd`I "=ٷZPx)r !Jdg?ky"6*$>K^EtD|=zW=YmM#;9*9tـ\\,o4 N*2j?xI=^9 m;XtϽu3|6ӭ>a/Ǧ+|G4巼ѯm<3 MFP ՞!Nsr+#(ե? >U[{,^_7u.&g@HkWwWOWTm/p8nku9SQ?{A ( Q_<+y*hPcDQ U>%(籂m’6s3L>i/4gI+:#//;Mи2$vwCW4NǗjڟ۫;]00b"ryl~_[|C]_Sh;{s mll*{iWo.ِpz}'-;d w1- ^#ֵJJ8֯ 'lf]2sߥt~,jioiW8mYv CVŵЛhԾCUtK>xX=up+t(>չXO2b7=-'I۝kS\ѼcK <̥ W9%;͞_*_jKFUE>jrI?5bަ۟Dxc6 Gt0I1^MTނlڰ|KhWzK< 6^sP>)AvЧ9*8e֯Y'O]k$D`sڱHmmm{1ZQ4U暓@!-Ks 6QX5IXnr?j3ikZUF$Lq+-M[ʆ+4:K{vE zUbq.Q4p=떞$-?H=k]o"׊4߉Kd=KKu5֚k:16餈t}Yͽá-aZ]\jܭQFvϹRFUSXx4np&$7ZVZ̥Mx #Nߚ奖Ov~^j$J2F+!m[Zcm\px{/[cxđ0{WL}kSo%1ےb$_.8W(rg-5Y&e;Tiro$4ge>jwgnmN9tGA&.~b~ai5|ɒ7{ZEҙ0bzEgWTI=xK}:ؕMGv k꺟V?DJ!ǰV_oԼY[i#xw#T^"e &MIݽ~T#H!ҳ<4-u?¶o 6ߚoOҤXn _m8K[D GOmwY:}MR$A]@!żQ$!&K0*7VPY[F 㸢l#3?.Mxύlf\WN<י!([Zh<;;ګT2Z~v\̧g/u=F=t&{~<<-|Y,q7jtmv*7s_&ze>ՒJzP?p߈UDvoQ]KZ[łJf/ڑQcF%v>" n!p5Z8UIhTֳ6د>15n17ٯ7rI-G~,!OہFe5K/#l o0KGZ\}2KM2ܘJ\W]^Xdy!Hm>լ4ycy6* EbxFtstq#sk'׷kp?63[\CXφ޲,`gb٭WK}!,qz+1\ԍg8$:= qB8u~ Em V_c Ѷ4N޴ז2-sJ 9JCym3g0(ȶWS ˅[@˽BsɮOqs{ZHe&>T]kD,/l}њF".SC7U*)!Nm01^cϳTnkat{9P_"2>Ʒ%Ljފ?*aJ!ߌj ~_ǤN}+NcA3\5?^jMV8+ jz7XhYmp:IW/RSYI( EMH. vSlk a$OzzhSv ,qCk %fd-帎oWu7MrWz1p=\ Wl:3Wua<usҼc\/lc?J :" ^֍ ї69u^&E.%6 y %\2Ǔ^3Bp)I93"u::vp0JzW;%hF\<%_ [100޹xZM9#p|Bk} vlp1Z C=~'"UCm&'+Tk CX+>T^*ߧ&O7T5gx-[U!  [4{ugZCQu> m@3U]3kz[C ,F}+{Z.(>0˶WܜbëcvԼ"aqӚV%U =k6O5;cJ}(Fz+𕴛o:g&*$p{ֱM8p͞_ ˧jy"$w-٥cqG^*U1J펹rEٞWF{,wsIv 1[ޗC sb.К& YsZT3P3CgZttC[8ds޺}.;@vʪq\ڶ=>Yϥ²{S֥KH֒JvBB$e:?:g q6" F~ CXN;rSEgl؉u Vw5$-3יO͠OƏ+m[<敏*g5!q%SM]ę9.cZڶL̸G76Y= af .^Cc¹]t'k'זGSB5$jm׭t?5S⥦<9ot{׾~~ ΛCrU xJ5i^uH9of[wTtSpbm? KiP?e1q@_K9wuE- ~i*id/珽YP\,Kyt۞QX7Bz7AH;koE}kmqm ]rlvtyͿ4X&x&y cqkK8M\s˲M֝>mnȓh-&Lh~G5Nt2SWq"i+,s(_\ZO|=.}I?ӐS%.QuFʅM:tZkɧ*i>^ݴ,e݀{Cb󋶆E_H0 ׵bPKY$IB$g;63IoemRҺzW|D0S^FjGnmuY;eŇdkU;TmBQ-2Qsmw]嵝hćjKP.5v;^]_z]cM9#D$\"W @$oiƟ/C*3n)x{Ht-EԘ[?αlM6r㸁欭oOm~2ZrQf<)xb(4M?R6od "dk K6&yrn+>"-/|Zo8%ʱcڣ)a{<>Ƥns85sn\&:ƑuTf"R}kmkVڗ]3*G_Opzx!C?5h^54ӝiU*gSGE&khNc$YZ|z5p'Mb:fk64!GMj=vYoDA Di4-'↯uc(T/$~-9-UܖA[S~/s.1!4mZ 4\LS @R(]^O1)oǭ]N|$ηg%@:սvޟ#X3L"yif&q/q]D\+asRѳ:o&$yf:C>(çv 8ZM 8ݍA.1֪jwmp]Z}@;xKgnр~׌t{i׉ p(!Ҽ$sҤڳfVUᾂ6kӾ0xܶƫݰ1{ [dW!9\"A4 UHuj}W<=*H"!jÿoBXE 5ڎj ;K/[b?c7+EqiV澧Zt-m-U >c]:i ylW~5xNTJkoƍ5?Q/5Ow=DI %u^@T_/1(fQZs4GJ^ 0CwhYn03֧_q3]9s,h˝n9^ <5.(w v(T%Xil4+!2]Lj5 S*F S'|J{˻"`zu,v(py>5%{bG]3lk.6hq rE$@aM ]2}V/>d RE;MDLOJUIWOǪ|@9mF0[_56(!9|+㿥q-+08khZ_j;O+rv^gvJs\hYBJBņӒxȴOqc~'>C+âkB@uF3Eh|DMg[-[qUυ<-y0;/E0gҼ_q2 }#O -y7K).Jq&tF:Ld /#T2=zzΉ-֋OIUO_!ʜ+ϊZl36>xlXjeϦ{זM{!Gb<4G Is𴽢9%sᅥR{k[{oiQ,#`{ ?V< #9~R躴g飕dm95R flFeSBp8+{{#3<oh1+UK:`C ۟1ҵmdŚ=|;0$K:\iRy+|VܡP㑎et\Mb'Qؿ?SGSmgߎ1Km*kL,V_aҬ5\X+TZnZ'i7o'i풼$: GRΑ-n_UuQ<ڮPs\7!} bd x;st/ ti5 ~|5/K>i`v.-Hd8?0'n* ?gj`dJ7qꦏa:۲د0}DZeѹ2{׳Ttm;V;4D_k)㚱⻉siR5LcIAׄk<~i>"Zu)nT~åCwgD?G9 ݭoetF]-_jM=ifbK~ ޥԢ=,|ÃIh]Lc]oo,Xްk)X)r`Y5cu =F ]1Ic9{i7qEWQJ3Ԩ5!dg}SN<"yԊي>J<Ɩ1EJ$M-YVw7;KJ/PcU/.{zb܍Q;λ QٶvUMhz]Jtzv.Yh,{OP`5QŽ%~5k,>kZ|7AEeUg&o+3ۥq {C$>RI[x_MgU7:2KL>O,j<1 &O2yx@̻>f_$⴬B6kk/vċ ll)m$6o=zהZ4]:O%|Hzݶ|ZrnY?r4SjS6I2IycCOŨ\_-?UIyg$:j?']i55}?PZw(16B7'{T73xcynwFOROiX  qΚyQqx~Ԣ ~T᳓R^b n&;Nv?J䵉yDI.#'gLիjm6'9N{i#/{⡴J^ ټҮ#3uݴWV7HZ΂$🉑׫>3Yf @q֥?u䗠V1^\X)ǭVѴٵmTDhxb,D/_ktY4%挢;+h ,z:U_ /:\0h#ϗo|:NhYᑜ֤~xgL}rܾ|'] hAu_M 2zZE'҅H~װ*nԭ|UXqҽƶ[% 4{`9׾ԾtkW}ݦ Y{њ6h_kA6fOt"{[{[vFp;"[]ɧVxyAA^ $ih>֟hxH'+ Z9L߄-l>$WȦޱ0|H4+:=#X*xK[UGֽo^|I^ 3Q=u>v+[m@;znielmZy@ _!_?2#ӚG=A/ҥ"th-|3lG-"xZz #,rs&#Peӿ)(duPI1+EgZek׳6&Bzcf]LCǞ1]~82;0^]W]{=B>ykv8ҩzq&k+h{q/ ,/<ךtvf$dhEs3Œzg}wG;;m= =kcB;k6AJXm3S]֥[Y,fIkoGFg]Ҽ?o^8$dIck٠#[gw}+ҖL/+5x1Wum$ =Л _9-Ή'J7]+:A+"ⲱA"$Zt fc^ X{gpגGXZպY}њf<3fIDNEU9'??iei ~{\ (ᶶcdߏ^k,ؗ%JfUWjd[r9T'] ۾7}d֢Y|jH!5M-8|}:I)  h,W8?U|m_4̻U<4xgOY\Oc`Vԕ޼I׼ ܟx燯9aYʛEFC۱}gk {Rn"YڮxWWOôVKlx!8Snuc}kybSJ~k [,rk9T{k($IPkɾ.|S vV;¬6imy4h0$0x_(ֵljUPA #] I u*qsMoaI-zTU3FzuKOP6Fݳt &,E&Hi$BϽC3T`~uc(J;W7dPlWmQ6 yQ#]?Y uaT=X7KXVmؕPZ[aWkl5(4R2j4<7{їGGxYoul8yx<5-۴{F7-[H`Dm[SaTT9SU/F9ڕ,.0;k6nŸXvs֎qw,&zCZW:F9 9PWLW]֎t^Y!P㼚,Ո,哜(CR].[o!3Z&XWܱ۞V^x!:זErF}&N85=5y1dxq#wb6!c9Psh4!A_Ӵ%oGaj a^9]©xu8XZ#J_-<_$ߣ8zC!.ۅ&52]A Hϊ6'=jEr^:JԵ=GڟpM)3PU3C\ iڏlA9}Z—9i."|/Ӽ$T#e[R6`Ѡ!:"{ٔ[x7zAW;J'Oq"`&RI&z[ڷguMmKU[ngֵY;3wjVPd5xr*活C+/NHS=LI-G$d#PkNi $2s?ۿoq Pi_4G_C' 1|ZZpѸc˼~6aYfު2w*[4dqr\/<=xKs\8Q5A;jSShM;Vi-O*pMtƽBR,hV:IK8c]3F[ |Yf FOCjY6mˡzƭ}gK6`q1贝:eJGFzTwv3eϸIn[7:ƛ[Y_rtQ;5.]k_fRc C:؍J+'j7VHU=S{{F3LןV{*FG,e3:||+?SY?#cRWÌ MK}v5;|5|>߯[E}A$m;8*?]k^~:ͭ*Q#S\t^Ej/nьӚu /H,GO"Դi ̹K0^!*s)YֺC|<'3]ѕ +׼pe<+WR$K,$ vLƕ<{%֟ـ'= ߇MsAcCbFLb=z* pţO1rzWfMh5f"3im\!%]͞3ZZHW@WY5ɽѲfWJu  ީc-]e7BAws֊>|9[i[{>nIE!#Wh/yG>ar#vW^5#I4Gʛʟ*Mj`֪,$^EaR stc19>BoF\ϊ(CG^v' uѪϗ_ָMZg咞yAҼŚ9Mxo'HUydϩ0_7>Ě\P?NM}-.K-Zh&b1gg>,'m2S+Mx˳-[Dʹ{ o} yyR3$|EMH$jҸ!Uas*eeˉmTf~hٯ&w& Yi[pzƍsFJ3B? u8[ v$|hԋ148<xPԼMѲ$Sg88~ oe'>3Kicux-a~3i<%F۲(ac"{Q \|g?tĚ6\(Y]Ps2MN{20+rr馭RKhbM/^TJӥu;~^(%-?)af:ts$?.ANn,kSӫCGit?4>em ٝ9 tC_ oZ'L ߒ<{-35ԲmN\, :w9ՌJA;p~~j;o.af$7` ;UmHfB[*ީwsɦیKϜz0H| *[3tQ$n͐8k[O oo̒~b4__- \mr VImh73xۚV延Pa-+;m-SU,<)ոa{hY'Pc'VOsUB+-xmXaK\h55EfKiA95\^Nnz=e^.rAQwú~ͶkE1t#]~z^g_;T+'x$כV)Y[x#zUr`DjqI#y5BL&]-n? ݇Hͽݢ'NۮkO;,Kq- تMel1O۲qWWҹ{O'ִp<ۻ);%\Kdznc<桷*͵Tb.C.Ua} c_iɖ+g]$Bp=y${֜)%G+.Ye[b$qN)%rƐ#'ֱw{S}~-ʧ<.R9c pdC=*긆2Ƴ&--Wx曨 \zSV#h[hOjl x*Ν)G>V>ѐٖ}oy=I氒1ӚyE\Izj,caս#P]>2Nsgz|(US K~:\>ᙷWgVՏ->6\`7 7y2`iqJ-9+&c&)g?4knH I3cVNfyQUYUwEtZ}kq]06֥Ķb|G$z~5混w> aⓒNΕxbo藻aq${Y:oX>'帾P888Ńw_h"=Aӗ=G Y'J`pZT3 p֎Tm\a'%'Qc^D_藉 Ìv'߭q_4LĪ|z' }>Io~VRr"$6~3h`ϷtU۟<9bh,uuQ|M(Z}Rm>p^ܸ1ڦ؁jyoh|kvAӁE<W4&A$[>ԶJrw4FLZL7_ەe=g#'k=JD2F|byVk4vtrh*~\6}2j۹oY-L'yүU}kDŽc'ԮGw1V|L6_-/i}OBт,Bb89dU6bbIsǥynoF"*2:Cgyr0\ f=oxđF!'Y6IU2G|%J=TBvFZ/m 2+t y2vj,MC]ނj:|>)ԭۦ u|D.At$ czF6<:~NR%rmҭ~ɧKT|ڤdDx⊭;ȏ0zZz<_v?&)MHU?"cȦqBI[U SLIFTKϖF>6Iy|*ҝ;k|O 5/Ѽdc_=PN:4j|]ʔS;P?x|liev+c(59K=V*bkJնǓTaՎ:=1/ό%ހ=*$irT;+}1_JO>IWT5G7Wy-%O׫kU_-Ē=lMOG֊+ ~8iV{AHX}j7;ATut{q_Yh}e8-Nf3BfVx 7H I Jc[+,& k0\< \?o xÞ#[YeWW{k#ftpZvڎw[xh߶R[-ȌyN3eof,M h%[yHb^:Ԛ:n]FPUUpW enJ#ޓeYA'<mSšmpͳz]#7^c\}Mt~9[Q\E (JtozMNwu|ִۑbk fi<t (PP+neWBHW>m2xR=K9IhTƠ[c+GTS2q/n >:(= FdFۑڸO(yA (F=4XX\H֮`gsjv`,\wY&#"FG5C'+E'6|M8-")Ѱ:{>_U0Z1wl(kRҬJڷ;AV5cJϵft΁+ RY\WhអB;naU.,"]]fxTDL?uqxqn,ZXY?$מ|czr2^Y@Y|T`26JV~^ǍmR+<jrAVnȮa(ü (}5VF;]hbd"5R;LgQua=ӀYqW]HֻhkX1㚩;?Š"+lߵfxRsj@Stm,%S5gCr /zd$ʂGO<CJ&]W v-%'sC})$3V>f0q>勋:yEosCoq|isǵp>Zx7mc䑿BrcVN@J𯊓]ۡ2ўk-cLYne>xJ(G&wP::mttfN^!v3V!1wS?utfPnuFtE*q8h]\4v?/^:U;VOwS;q婒gLi!8#=:V|~x.Kjˌ^yR{-f{YVFߌ$JEV97zf.^@w >TWQLķWڤ6֨KRڌx${ qz8׊wbGG4-{5^KR9|ո_9C b|wW, ,?晩Y;Y%H@Ti$gl~5jXbnz3Tıސg)$^Ԓ+eD 2\#jc9 >M.iX}^Ӗux #mAcXR,c#Wb qtBȡZ}paRkuDFXqW`ؒ4DZľI5kfCϙia4=<W|34VkE7-]E+}!i?P$c^GCy|i"WUWj6HJ; w:X9y> :Bz u4.,{xSQ'v}n`\ȿvP:5[DMhK3']Dl#'<9GO[PV)X~Z[+ %ܲ*w߳Zg("lV|%oq `B22 w53XGP6H>*կ"we`[^JۏX^.(*Ydxr9'?ʐP\Mmyn̙uHO -u%Tz~om㟆^Bk{׌xi 8 u~[m8dBvX%ɐ pD!S gCD\nxQsmNM7F4F,{5}A-1=-6Vp⻻=>[?oWҼl6Vl };S/r,/>>ٔzQ]_O ^snss̰=JN@'ޮ?'A'10}mݮ(~;w>NxBMWsOeq+V6DA k/#՗;]5${h.[}{c"4%7-ϠiYho5=FI!2- mE UkG&D =|iQo#QqTz]\~㨩I $8#Ҵ-:TqJ'Tr|Wz[[|F-t+bv2TW}xrzʜZi=MYmlj4ڒ'jcYY5鮧#sҽ;K|UE9TOdf`оZ[0g&xN=WX\ +WOѬ%UEpJWwkoiMuOA[іLǺ-WG)?GW!xGT"9g\JշZO wV[Pl5xZ+ Tx$Ҳ.Hqz6(M?zddp=:5xx4G%"ÂU1^}xG%嬊\cJ_=>x5顶b`c¦}38CC5={R'͸,rak<= [iO(|]7UB!K2{? <A𲶥fy` 3#H# r+")}L /w)%gZ? jeG H4gOgOn=k>iH]z VY]2CV*;#O7. j߶hfcՈ֏#Q.X[NG iz}D&o¬F)m-'Y4+tcʃ~tZ^hnX|"E=j{W׈(7~@AD162= -[Gt²G;MҟTtLT7bT΃ᆽgI![q\c5ri2{r=c][gcp.x<ѩ2;/ c Mj-6**LЄ@GF[h wb\uZ bn6+ؾcpUAQ^o ڝW ~*34#WЕE,XT,O+t\Qi uƽt;]IjHj]_DuôrcP2P5 u@,_*Iu)7eN8j"8kU AYnZYX-I"L8b',EYʧ.J}'ӃLG Y5i?J#aPcDUm 2ռ!O t'ݫ,ekW,aԊ>,xU5}sMդƗhQRlþ0k).jG|zlWl73PKC W~))AG1B>_&S)J84ZF%jAk@C<ATlnb*fW2,1=M4gQ6HWLdxM( T'ex:dzTZ3J> U$V ӤXn3,ҭAvndQsT4IisV)5YM;:cܔbB](A޴DG<+HϜ Z1_\UqҤ/${u5<1u<.f;@Xм0MG5~ >0@&iP?ZjUVV*h/ ow`ndqڧc%ry"w`IFw~Q'{y5ڵ?i )ZW͝O" 17!._{ O^>͚u)⣵ОĞl`s[׶uq=J<>AOXIe !#gjfo;`}+G#_Bmdž~t;k B?w''5-O׊}T [h- a&LUrN;Jgm$ K2O/H \h'Mo<21f^:7E!ԅV:i59#2-`iwXukj:Vtλxo,T-9^aܡfk<t FcrPbyOhqIyyk/c?axP\;+|Im|/e!m+wTtAK-2NB*| +kؤY|:zį#,sf-xcWzWxATb Mgf2Lv{ףVPD,Tm ET]hub?434e}9緽dMK?^'Eᘺ\w6| 45˱_4XqZ|=}z)zTsY6%cSVr;cPQ##|'+<6E.Jz?KQ'k:1KWGÅusHE%?*/Uҵm5I!^t2Hzq[[H4x'eGQnE5jD.Oy +:Q^HTJu\.ӃF3w5?n/ X.{hdިxl`w3x.41F=J^EyNrJaP{T(#88Ne[$LR)8V2<#uvVczkQ>s5z5Kh;址__.V ޥj_oMr.o~Qn(3&f j:T^_=[h#!,5;M 9}jx~BFiI|vÚ˸bZ`rh'Rvsҹ~7ҺF-kZ2ݲ+H;3|KmlzWM3FĚy yG, =fB[y7/ԚĄ+3BVW'wFUec_o` fu ث’\A孻m/+7zKKkŷ9тJ$f{-{΋Ih[vff֚r@AUiA7̛s<];[5tHsM^HQؼgl/º{Ww*_j4M*|U|L_;͑\OVvnPs3 mM*; ZM.?7XqYU7oZلWif'x];@v1VfA_|ԶڸI4Ҹ5ro Fq+3pΩNMlj y&|Y~%gh8\t+J'D>wF%o|q'1qqZk}Kh$R[5, yq>9]qcqrA yi Qw_'Qg$tľ< mXk9+,Q|׋|YuaczǏ|g@usrs1ּS⎤=M07sJƷxћ[XJmuox#n⳼ 4K8e?s#Uh3^+FZGS=^6Y<JXpMASGϓd&;q"±4||fcEyT-Pf,b>-?XV`t8Clt]VI=.@+ JkቤOB6 ˥b8.w?vj{n|D ث:ݯm9 en'~gE-W/sa3F3.-F'$VU-E͢a1Z^MXW{U+7 }kxJ$zNl0[iiy 6!%3ZR.,2g%%)nx5wMV#Iէ ;6֟uclَg5m fO<*旤 .<XZw&x*zctZV&` QkisZ Y'ulsڌQ2,ҽHk0X`2*Zu8Mr';Q c]߀vo-PuTZվf޹O x:_zmӊ׭aZjzKrTGKǷИˡױ(A56yC~fIiWT>kLvձ=8,:{6&"15,Vsc&Imtr}ևsosw#ٖS5-F S[K9,2 vZVQ 2i7'PerѨZm̯q0mQ67R89e?ȵvSS{e9%Y6V&G\ц/Mocne`<Ω\r~>v=)mެ1\֪qmk6IxYhX)XeoYڮ#oZ!`z˚ɞw||S1䔓<$sVyvT偯g'Ă$cҸߌJneE;}koWĝB?lnFu '=lhfF U|?pY]Vx{T׭{7WOnzVƇ$"5摌$o RҴ-G27,C؜s~$يj)"Y<_k;bbM_}.K1(g),4BEwp+8|Aޝ?75G}]]g;Y~gZg Ii!I6\EԵO\Zx[{vds5,,5;B|wrxO5|el9mP?zmSkϽuWl} ] o3k{Q|mVӧAA ּWKAh_AiWjL/i! dN+ZoVď V?|O!&|-Q]gKQhNN020q^_RfA0'֞w>,ruk[sRT9V֛ۃg:Bw[o\_,jZ|lqӠM`i_4㿄Gß׌46'U@Nݾi 1}uլxV{o kڭizŌ?hiǿJDIvvɨ"kZ毗<O|E~~*hZon\ 8ݴ~ p0>,4/KMA kj7dO#9=k㉁E$ύ?Gok(m ' tX{g-t/zDn=C{<8噊1`yπ>Ɵ ) D Բ~L |Z۫xaɵ-Xg'\x+H F|c㯄0_~̿-|YWX%ydB_(dX _|H:o"|EM~K"8o,3CppIY+hb=Z>|Uu$h+n+[ǯ N {%t]U -l$ȹ.CqO-gOt]Oiemo#ȦAG7kJf'ͤ zH!xgĄ+)_ǯ~ sxisg+h&X\dUwe+c$0 sp}kJy]XuAHcƶ.xCw=^..2yz7|!}egq]IF a6/ %*aׯ?rYs#_7Zn=̓I<TIQcZVVN85KBRO1k><|)hL&S,X'!èM H!GNiN&!Yu%זp)^!ΎrEM5(WvHW _UrG-O̻BzVk]_n$>Z`v^9K7C\ 2|Rѭ&*gaUޛ {Lp}IFIݳT]/9TotX4ej;R-1@X3H˫$ck4gq"]z̀8?>Ϗkake)=7J%fYM5_-МdP23ԊKA5a0#%j"0ci0_jeDdQ%`wLΜwqW:%)9GZԯeT"5ЊŋMDc;Zdr!ZO}6+g+38ݎVHń(z^*rcRrO\V2,֋K#)|+}jiXưλ:,o-ts%@kÿ u.07Zͺ6t`@q]hQ;Q4=J9^k^Ioɇ8?hhLYkw/RFe!m268 b^x)6s_d7-?ƩA;cS]]!B>lf[w@K˱sojѷRU/h`ϯAp[l|Xx^i⿄ڂ$ Lyu Ge\Oqwr>a={l$y |Oۿ B `XP3⽇^ci-΅r$9 vDg^1һiM4gV.qƗY$w]'X&C" { _xt_js܊I{|+xHO͸NY6˧Y#uyNaב|w;=[̞U.{bqס hHB% ȋO^xg6ڗą'ك){ְUZkayHb^g7@.|r?tm:ema3g↩i~ZGp#'*.㱏ڎy1G(t'a b?7|}*M١R&x†Wj⾗ OɗwoJ+@{ψIi#ǕNy>|FMxiLxbIVNɸW_ QR>|VwKCM6VR&o^eK5o>jS =x| a_Ǧx}>XXoҿ/<)Gv|Hs=e7闚K0>aʒJf4{ў0נh =  hV7z$TE}ߊ-;ڗ 4d/+{+p.FHx yt?گ~]lz8yV0h[x3YZ]لcL~u8{4Fy h~6xQм%R`//XYı񞥈=1ڥi_2Y[>c~ֲ`Tg s#4o ̳gR[+;MO%Y.'u{pb918ҹgS4?0x,<;'؛Ki5H2ZT'iRFzʿG+~~{M1uxPЂeHSnYXݧ$A3܌~{Xp\Bh=.~R*?CS%1 Xob;g~,3x Y躤^\|㸯8_&mf)%v6cNIjڵWe~!Z,΋c*GE_~%hϋ~?W ԧԬ#Ic*3 SNQg?Ó;V }-O*_#Ck.oN<~/$= NKx2\j^gE;t#>%g+xkȲ q$=v_J`'QjGM[5YJc\ cH,? FfA'2{ּKb`ѵm;TxzLӥlVE,#wr~N{V3U* A\-W otRndPۣUZ>&ӵ RMJ/Cx?=GVztDhЁ޺k').䈬.7pf:)ԟc-rx[|#m.DMr;(={W?Zόjs k4) r5c <~>Ԗqm#:"iO\X֧h8NGᎥ<:/q3<~54/D9;Ik񗌮;(ČGʺmzIGBYj4fDaULK'UPߏ]L,mBijZK`#SN8aOc (@M%A+W` j*HϩTچecaӉElu1`y_xrmeG &vaKy4ٚ݊9}۱_-N1L茍 dX `Rdͷm2֣V@cR嵭܎]Hеt2@c-jyTzke.e[Ķ)Vkk~ L6Li ^_8n<;nѮ]g^/j!6:s=t@x^ o_=jy#Ř9+|/H/H޼E3 o~A'AizIq>f?HjNgM'dzݦy˂z2ʶ~wKG>b 2YwNys?8Y1EIj3^Y. ɜvq@~UP:0Zn6]Tv|>ZH.j$S/#Oמ/]$)} AD~T|Z-#%rxU]4<b$ yRs[I0W͡˓Pnzn+ɭ#E?B|0F7 }zK*yl7]zö:ƛaR!m`4jYۮ ~6{U-OT6}T3k#rj/^.؍NWkszk+w c+@;w)ޢ1R5案bCU~+^kϵOM 3xpÚ"|Hd6Lxֺc HjPMHLm5BPqV9>"8+pr@J0[3Ik[hdvi[0@G@xN^=7œ.0|ֽC$:Aehnc^V TkIU}p@tDsbkw#Z\aF[RBDH<1 omd:Y^rd݋ot 䚯oҦ&Lk,m>Wk e?™tܾ&4!HzWE%I71`d9JY5( %šSUXR$Ӕ{4/ֹIhU;Gm%2-RW'Srq][[q޼KΡ{p!#V>'"darIi F v>rLuZo-@A2Xm/| {WYk Vfzj2k_BimFfd?0u}-䟻U4ikec'rW&92\njUIgg"A&aD(TkV4ޜ7jλ|l_jЍbX4Θm6ɸVZ8޷<>ٴrs[LI${֥9@:TL߸.pұ1i^Z76[ӹ/叭AuHTfͧgcR_Hhy#e=M ep2ftU/\߇^9/X'=+8t=n-(~SZɫJ}=òoi:zaeU+=rՖ~|Ꮄ!v[FHmrw}{ϭyƍkۏ]V+{7IkKSe-FY| yotxMe iކ}Jx^+a 0qh9WvS.km%dduږ.a Ⱜt@6Os6`>k"Po 5Mjiv mm;PNfᰙ$uǤcA‘"q^Q@msè%DF'x .]["qXG5-rP5H̶?gv$WB=;>($W=vZQ^Z̀ؤgL'5tJ~ZEů5sP+ƴG_ }6$ Sjta.7[jPGm7c]Rat+l:< .VMՓN>P1[-Gbʫxv$W$= J!#n[E1}z+|I6u$6Y6HҊ+P0=*DN&9cӥ\@/E`J: L/^;]Nե+K{nGsעg^)>|{k={8~$Qݟ|cɒy{f9an{_4x,{ׁtw—J F d w[KnQr)IẺ[$BIP`{զ*ygG /}iU2I,,c}(STN5mM[ ȏ8>KV𕇉εcovyX§8OND2Ggoc"ÿb"EKx5TzV g[Qš+`/9\JzJ/-LKzz? i(@&PzWx_ĆM*'{1W=E6~W#S.jm-zᘜ¸Tv4ἆIxo7P@圜10cYZx;qW-$b\Is{vB:ߗ3.`Ej?^}L*ַ⽗A8p.3UN&mkiIO~n =Ķ^<և;llc?3Z1#Cy8kw<-wiKqumN~M՗|VйQuO-P[n9Ǫ[ `bV?^J]F^/ojfQ"aXm=K{7 K$y A+VGo"&H&壺}%ėV?#]MeEMdUaԃT+س{lǕɭ6ps`J[WbX~q沑dnY[n۽zX!eF8)]/F 8dӣqŒsX|ѻU%hXfdy6-c^˾vqa9zֱ9npU^ >"u̶1U꺈6^vc@goh]X^姈td-6fQ=jSk|r9?nƞ_:].☼Gc& (v3*'쮁{|t߈봱՘ofu;(4I%L{5鰾W];U~;;=Tj4ʷ&Zj˜S\wŸ`$>\5,{Ս<ds߲!p޴-m$d7h fj}w7`xKWͼ_d9;*ՠBD wij#̠.~M|A#7\I=4r+Q׵Y>oڝRK6T1mfH>l3g;ҳƯ "c 0mŧ<+)ͪ_9'daVC0yq\ǎQ;dRU8Ķ,֣f3u])~pN+H攎 D-=@İϯ"~0u)t-* Bȹ_92+mK@V 58Hi.lU:963|.-lctӣoRI9zKRgE㚥_wKq#6$02i Pp<yt1R~,JKGw~^i#c]iri<h d`t1񆪚{Jw@5tFG {L q/ZNj.% c]!Ōv! Zw㏇9,:l7ʡD;nD1esۜWxŒh#0&7p3 ;rnFwrtM6+y}k9Evuלl,Zui¦>1\6-'SIFDg!3kԯ/m'g`Zq7-:y#Ղ`3P1Ayo7Ht+u+'"UX]匧DC$9&RRi jBM#1\mB7U:h~õ [ 9yDZ6r .#B9q[Y(5AbӦq,pzU$;h!7 X\HwQj )R\p1PA.>Vhc3:PIڿJ殝V5[ ԃ\ 8 i5cjnR4g H$ۺolu'5muzfY2}WYZmP2851!BF>ѬP;G5gOn+{8*=ZRtEkd=GSt^P RMFcZvqi6DQKUj >n{8c_RifpzХtz-axI} 8[( Ic'59_tG9]!v gffp~}L.5Y>W#xm.R {+Vf6>~j-.<=ȷsLA4đũl%Du@DI5i $yrb%JMĚ>0a椊X6WJ_NNJqM`|fֈ3qziKċ#ְ/twYF^Mčo6y_ҾqӭA7mO޻/R@lusP# <`t=ۭQާ\ 9iB ${Vܗ,O+n5˫T(=MGoiAo8`%5 L#Ó_T9i74yC4APrp+O%;~ux+M߂5IeGܬA0#5?~yujZCXV15 s7ұuBXñӎ/s,~b|/yf^7@Npkl:UzeO^г7֝_4»tGE5FÆs͹895+B*5&tjG*ݎ98bKrAR\ӃUu5m k_CҜ tB[r]n4.V Gu#8B:EW?s] n0SeK۩/Y;wC.zSp~RT56BIDz#v}hHw+O~Cim=_РcixIejlt?j-So[WW/IU̧տ&=(tunW5Dr/bHq}7]r5Kޟ.眶8G{yyuK`՘ΓS]'=V-rےϠK (Jǧ +24aUQ!ĕ㺈>Pjvi]?4AF7(r1ЯncL|#q44uE>nd=Z#;m/[@tYcj%Fc԰nk5^H@8I]SsP˙jmXSulңѯ.d6$T|ϥPMiȾR4QHM]ET[{ApH$S\:s#g Nm"ՕƢl=h4MaRJ+GnW^^>~s58 W*\]Šu;ze~U_#u+SZURI<$d^+]xRd٢1bH9:YJaI=II@=Zai|Ynon:٤z.>AT]:֘,'d#8"Z@C] k#2<*ߞA95?Տu\T-/iWO"֟L$:~"yl׵'xh4ZB6vEdIP%)nRm'h)ls8a ,cI&`ǿ.|Lbfp5ȹsY*)ahA Y;8Mqi#;X!ڻIc,cmX͸ggD$ֆSԋ~$5HWv25rHPמx*csZ\֖WW;s-Hqz"7l$jwozTH=MX {k BUXF\uFOj$]9S䓝ݰk6(g$zfkzRC׊\ٲԾ +U9h F+6XKZBfqHnx%-~Q,<j04 OJ%s $$F2)pyGwWw2[s֧{|8Gj숥s-%6 zXt@5Jk`cVtpp?0KJڕdUHڅgPA#wRhQ|# s2>wvY=A^$ұֹɻey)G#5<+t縺0+sS2YZ|(.̻'tHybۈ`8z|L9R}iEHyGz!6fϛ9l_Zn Dс\W<\^mNRFsj-w;W( TcqZbi\%T')Xzذ:1U &\m^8fARia(7GT[hW:);!+,Z.Kt 9};dAp}0)h) YsZRJ~H*;9.P)X9Tb%IQX9ͺ0ck+*|m㷊[\"#z/^=01ֹ{~cۀpkREc_xJ;dRGѴAt@rm7IU%ܧa^.# "x<= V&߾׮|HH5TmA*s׽|vyRZowNӱFD<ƹk*֛wvOU{F䴑o&|abEfᥑE~MC4YON<_|U?$ZObmdbz'B~mw_u ҃!a݁|e';CcuM,t?g@`=充ìejs_ y+ݛ\݂ky%MrGUuqW3whH Хp3%!d{蓏䛒Hchy3SEe jn}"]"q]1Fhd JXѯ ,k^FfBSh&FL8JΕj4[T9MZD[lV/ñ;IFKwd8bH+`F)"b\XhqE4swZ֚MŞRdc x-_4@8}/- ǜ/3늡4(g\IkA%vk;R6w-qv 3Iw~z8 lhK ZtWKJ^k`*j/$lsڨjz.[I,v<5š!S/%k&J}2-tCP?xz}@[kâ#N%b;i]Kqly<ux#a# [i,Qsዻ/8z;;[:bgKȂݑ'5MGҼWq[/פCxOS|{5Nk AsqڟktY'ՙyQ\elDd KWE:(<,~;Jd"HrS]]4v%S4ܗ<0旴~dS7xR`Oح=BYz8-˰4Q. Zw k 睊scel!ls]19淄T%Ӌ.?z L,@ x~o9[ /vAεW4*[2F$vڬj)4Nlӯcu;⩤ n=3P,n3Aq-4`q\gC+E3˵aG EؠO A$p?$t_Ǟ,3?Z9Ա鑁hC+vWx;4~"qr{]Ƌ㘠_.y桫 ˝\[hm86f Q6OjλXy񍾒!{?8-jhDV8Fީ вF '[+Ӎk R%]I%M./9keԿn+#xпLEET5cfKah5bXv|ګZv7Ͻk7i%Vz xbfhF+gyLZυ!]WL<">HYq[B\v.jΉ:_3Ůh*,G'.:b? ;T\?'ں949g3CB/ m:]7W\ʡsJ+;2ͻ7q4n> %hi?lhqҟ0~*QpqUӔZSqp$o E'+YT|1$h~aV`1Y9S t4]/j۸ԓH~o .l&Q!jhWbAګ W-yiKU?!+'k{mFpc;8<'JdY\,:݌Ba^3Q?:! Wf}㾔y,݁aV."18Y-ϥscZžOOyt"T拹i:s+?-SS8Ʊ]TZkh `o:d]tQ)jXĖ` krk"/:9)ս5}r^3+t*f4֐.fGf^\!SK`Q?A7}=pTc89u[=O1,?"k)`Ɯ'-N]' Lr01ҵ#7Y3IJےu UYK .; ⲛ64nsSiޮsU3Y~QtDTxooҘMx!)8v>*^=OFT<33eW{fx:3(۪+º,zW{m(6V5OÖF.طd f&6Z2mE ךd^'o*\9붽4Su \bP*4mT]{ }ҭ? qN:UË/}(*iVݢ?XVCkc9M@5j$N(.&%΋k=`A8FkImaYiTUu(ى`7gz$eq񠢭E;Ȫte(Jh~QJSNq֦j/mJwzSTtO!/ H6);Vl$dc6or>{T!{G<Z˨[\F-USmZ6ZEzTF%,̪s)s#?Vn#\}= :o՟mhn:g^[X* jlX_sZw<[~ |9t"-AskuywJ2wa nGդCҺ _Tcٟʳ򢶓[Va!snEѵ<ۀsֹ_Y]- [?ʤ_f@ ҭ.]L3TN It3ZtrrzvpMr^:(o#GBP$eޣ۫ӑs"-.×㧽vZG$ebP9{׎RK+`1@+<9ťhPx&RGic2'9IsUϭp "LPK*$l}2!"jCm6U~^3=+]o[ns/KsxQpDq' @wm@\sSOAi4MAu6Oa\6֮}qyjg,1cK|洰ַac@%*;}ݥFlUZռ8Vrc:)B֪jBw k*'Zښ=; V 9+-LX ȫV1*=J6 a%zy{kѴ:ʓ#]0co_j`Ov]γpjV5u!&jI0"RsұHv*zՀ7з07~) [/oDvT|> mXQt|ӚȮ>IԞ=?:vVEgP?z4Rrs6?)QX"҅בJ6_ֺy|_oYp?.voidk{Pm?M)|BZQ]Ү-o(d$bkĞ\abjrCtgXYq.}n^TҸxTז/HFړR[jsI_]\xzkeT~o<.:h%en$/hO~'h1sP@c?AYk:c,!w&6WWPj,L T_7,cingd´d/l`⸋K#6 u_WR*Xכx[dӌ܈>+bǫiNsA9/l> \Mz3\圽 -E2zg .,f2J<~F_(mN13@ NDO&@ {Ѱ{)ҍޘlbD&Q?J&SÃKC_DzEe1QO==:BMC:qVB5R]-R ~ͨwcmEcwۃXַ&=c v+lPFpJUx _C^y\U#ϼZ3rq2cT9t%JO<'pKj/`N^?*r֧(/11~.5 [ch`"nWgѤk#Ikk5r`isVL6v$@6=OF#cZOCk_4 \qO9$zIa!U\2ls]$dLb KToI-@ ܟj+=k Jٌ(NEz\:},c)Ñkx4d嚘i'T*85 Y`tDži D֓Vƽ>"GeZ+m+pT29b9,Mp -3Sjn_W/ )}Ԓ~nȊ.EsڥL(*֔7Kwdi FS!-'Ӷs &5}j]@N9 e;D+Jri q=zl~PXvё} q0Zgh]r)\r()Uxv)G "[:x2(:VX$qfG1'ZZj,H;-dj/ mJ{Ҹt/CoclZ 1r ~jFgKXI,~OIy4;[x]oȔWD&e(D&k6s\~"v7?\λ7MY/krՒIOVZJ'Zeֈ#ԭܱ p^SNԬ|;|7'޽ƞ4]E8E cZt O6o4r 2["O0Ko=QϖV 6N+4T%KLI_~pH=w")t[bPriYiRA*I-d#³4olfԨOt:}3a@'9*F츻?z6BEॸȪ\yV-q“\EG9GY͘[UƯoۣrFAq;-$X@;[|;sc9a9a: ;<MKlj.XΤk;3߻9".s[tZF ·*s+zV_`XlV-@U6 jkmEϥeksJ]-M:LMJOFA^ l 2nΣ}ky= X艦1w&V;?[_Um'qڍڄH <ZёL.k2dKAwozneU9^Kn'7NkNvߦ]0Q`Vd2}ycO-|cW"Lݢ<{֩Io=żsvx\L6Jn8 A$:<ԯk MnwcnxJF`JYr+923|l6~~\`5M" gd* cjogksso"! dM66+18\RK:ԗWW.6ݸR;)/~^ۿ>^~_lS˭'[?gj̓=s4=;^aQW /ޓa g>M{)h11Z |@Ht-zXW6W=ݝ(+K'!ҡn9vҏ))xm_ZkZFMI#7Xxeyp1֙ZE#As9Ďnm0ɨZW,VlrK4<֡is!o=~]CzmzYܞi$U ˟:k`x= g y@]c=k$k֯$J Qޮ|]ߕsf]] [+I .}=*}΢3T%'5DDXppx=[jւk@eŢDžu8q(S޻/ ^pkj$87Z985ˉ:g"{}bLzðwrd^s\^R1ں_ t-}ّnkл?}IҹQ̑dyWAj͜5\N#'zQΝ4zg&a/ b 2'>-oe\i4 /^V8ȹV ^PVԮytxHQjEojj7=6enU.RyIyh@]Lo͵)撛w9S, W<[߅R5|t%fk;]?1>sSnk_X5 8y)`>cדIK G$V@69^Կo=K"&<}Or)4^m^.с㞤TM"WMXܿ->P#^ `0D ܁~&ѵ{Iy-EVsMqt|ՎW.z1_,7ޜ]6 ?_bfb85ƚR=ӎEżce%EpX#I>q̗.;|}%kIlc\<xkVKRȀL:0 [EN4<5;X)t~U$mrҸ /tROf|QЧszzU]Į̥@73c#k55I`HfwTvuG.ydJ.T~3.ĠW65,?tOZں7c!{qYGNE;Y:L05NP$ie1UvXAn#ַ} >.+b_ҭͤPcN+-O'1y{' rzVs&^)6qs>$סlDxV^f|$rH7◜9hנh*}*1";vb햙wuŦ%֏u4уAIj.cY5kW4_ uG*6 lkw hh;i$W/ٵ<Z- {#δ 3bH[˒=k+j淇p uzQć$)a! K:H%S32ZPw7Ad~6WȮc[{ZdS-gpk.[s#_N3N*kќd*osjXwr)Y"8nK@օSNo#U\١|s=[&XcHםTe7wM+j촺&NZе_T[mFd9"]FtZz@.[_>]+YLNL\Eŝ ߉!%I$VÌc"Dx伶#`$zV|M[;{.I=꾛-CW%ޏvtyF9o7}I(h5Լ #Hc=F9<0K\k> YHM,nځ~aǽiBOT)JkQb=| /4z41oӟּԵȷ3n*㰯Gp+#'k95JVw9Ӽ/dQ6Psz#gHuHI;sWoISmcjΚ?uS99Y |M.p'zb5$Ռ+w `tFM^g;dڶܻg<ZRr͵OiRbKp|$9Msa|Ucm`~K+Oj~mǨUOr<7T߁{gy#G{>9[|,̮[n3J|rѦfޱ\W-kNҭ5ip-xzd\ճi`&\3uٜgt-۴e>q[Mw7*Z;t__"016ެq: Q@X~@/ueܜ-rK$!c`:6_ď?2 VK7'ҠFM+v9cv~mu{;8,&@:{UȖ=ѵ]&4E$UI섌͆c?HYsj,oMiappLX0t-Y ]fZ4B7fD<TȟC4N+Q mR#"LrS"8+bY,<;gMFF{ qVɲ)tA_ >Wo)*юT }+5oN+ qvIY xO} 鲓rfNLF{]!Z2*r g|Aq{.nnmGKmc۷\]xzH3:'MTpváͽZd}mե=섌̨`U9$(VV\V_bF:lF1K2Z#gƅ^Irr.xQ.bG^\oO٣R_AU5Z@!7IuD3Zm sMe:uYM_Q1WNo}kV+{+ m4!'5\4 DJ}07[Zw*ç,޶:-YIj=:`5W46fzMťj,27rke=*ں籶E_SX~=ߌt 1Fњ9Qw߉[c$IlwxDE7 m#z?_4TV7mu%;24s"BM@Ny_m}3G"9u{1<]*7=q֊Xj$Ն$1';`.3NKS=* :o]@%M3b?\N77&KP_xFTeq3^;ƁhHyMn :FyC+'$oc4=oU }$P<vIS Yv2E.4X/ьr? uvG{xiZZ7 [.1_1$C YeU'־Xl0'W7K{&8梿K<1"Q }kCOԃq5*>(Xuvk)²WABFѸg"Rm>oHt4 ZDwAq(A,WGQ[Ec'|A]'T Nk{L6,wqA\JEU#6U d7=sYUjKvһ7DNFerrwϿ)._5*ANi3&5Gpq*$[}CR#c\W T!>跀@J̠,Uȕ UV9?W\B2I/޹Eo8[/3uvJ+Tika  Woq3Yڎ> }?OoQu|HCc3ͭhYbѯhvW'.rnk"xAМInB&ִ9&%%p> ;X7S#ˌ%r~]hR/7[$gG^ݍEx1Kូ[dt/`ی!ⴘ種yGϟ&\-jm>SMCs]s/6{Tu#pڒg?+o_|/ź1_][)e`;r}sNIZA;c^s|(GϢhڭۈ/O+ּSkkV0Zj($} B, 0O3eZ|" ƶW#Xm剡\*.m4s,գ` ̷w5a(8J@tv _Kbslw"R?w+Jr"dOG]= һTy `?uFǹxs;PU5Ű>Q}:Y&ȪF8jL }j̷j(#T15m\9L}J 1JdC 4{>6ʳxq}k]ͷ|/=~-9c?O埆-X9K0#cӚj |]RNhA:/ Ƅd~ __5ߍo-dDR&qoz_-4QR8_hS'i4Q٘s7gDdAZ:t! dzUV⦸0tGſr+9ѤmIjlk涴{FuO^&iȒ81/RS!!ZĮfwgPW2~Rr9Tm稫EEQf6 AzPsRR[xuz yf_XYbMh\2\LW{xŶ[2@y6YrZw~/n":,V9.K3ŖZJCXlR&5q][\h21;;;x97_Z}CSVH(ǽy|G'Ey%wS.e'b;o l3y9Zwyu>~v?_oxaq>F G?]2-)uh/b8.?bYx6v-^]jAd[u'^"zFJƢQ4 ^8 nnλ M)цRU8%x翶feX#V:սJM6I)=m>NA(U]7oU8h3[2@ K*ߓ>.==h;0isRu4 #sW}; {Hzp= Aݪso(c&s5ZFjj~K@[]p5B;KU˟⡞uOsvbj'!k*JutShM8nrA,ko$ɮijlV8k3ZEiSO#A|§渫זAGz.Ybˑ5v+1yG5G7noyscNŊ)N2zu&f#F2H0~g<6/+K41SKB3gZai֩,#=k̼|jhV`ND}?QKQ]I0+-m5-뚂sL[8!YIj:B]0f.K7MԾ^ؚH"X뻞d^F(#p"O ((FL:4p zI#Ac=l^jQ!-s#HRaMT_-  G+ј>egʙUDioFطFzgY΢Rc&"6.oj+O,٪W|USY9 ӥX[2TMXkVuZp7Ku+I^DA0PWR)G&Rߑ9]=MUt]>0FY[j7Z_?[5bBkLJ6jAc;kTmwb̚ƾךȱ G4Νyx\zEuڴ$eeYhđ8}M"dw,eGԮ>qzýSZx~Ud^:ע[ZjMmsW1gi縛d*L_S\7/|88lV:.ul s X5 u#?&gɬKh!G/#hWw/|v60]Dxгg o7Hb =3LAwx/7 .1'.|8.Xk\MZDZ -UؚL_M1Hi-\e?;qKxu&U<\F?^ůƓkrF1g,+1^Wm+rlA戧c@Iu')|$p=kdё|Ato, 6Q] )(]6 +jю\rx?RS:K.HY(*I% x)ܟҭA'5z͎VϚ g灚|fR0sWmm#5#:SCұn#?Tfڤ`.zUDMkcN0=(rؐp \љI{V^i:W>+Cb}t<`W>n$n;ץ_oʷ7"Ċ.]cL6kGþmNbgvi~5뉡gEؚV:+h"/ |NivYLjr2y^uidfjn^ e +u=ciWa _z@s#tVP̀cTTк~(FN %kۥZx`zmg`jy[١68%>4n<;ӬMcvi||gaj˦OAWi@9l^iAktK~˽"[w-L{?^ j%T{1OroPG^+>P w3R궢tqdVI֐rH.})zU[ϔSirB1*g4=*Qr/BU`x[uxV9w3JU% zby*`%֟9t`䃟j~ fSGQ)VWĚDtUSG34tcOz0V)2ޅ3NJ Kn!)d85M\t|jydxg][M֓&7 o=(Y-B8.|w*j)&&!zʵ]*v >Y|BA2}@H)k) +]`>cח; [?u8U-r9ʅ&6tФTvќ{~</e.YL&ŰZg_Yߏ4m/&odmBg+{L pNa> 61B?x1Z/fҾBG sA>_|Hgnھ,vvcuq}j6.ԋMO2kyslg_+48;q$M\ަRC ޵vF̰pEkƖ;GךlʫޝHd:׈mӃk36d}:4p/kpÊm#_k n7IjA#|U/ [>f+kjWQI"`OiArI=jCȨJdZM)PxwA#|[:K=kϥEs,[C?eoM) U o <9X# qp:O!?ox6nmGǾ{k^ԡ-ܝA1_/cs,ڻFw+$mNX R);@}u7+,Q\kYJtլ[.{Yr錑Wk70Ro<'2py?hvhw%I~j4=?R/x4~iG+#˷fdƳ#u%X `y,#gWx>w*ż)2sA}6P Ҥ>Ro,v+̲ +7z_ EWv%IK~!k3i*ZC"m'߭yǛHS;&ϘuN=3SW>\v'IO4r\9?JGDvzefiՉk۱NWD@N.f-lb0;I؜H{U jWMrG>mLQcjր J k?hfơrӛ})p6OOZͻclq|H╶d+浌a(i㏅:hRj\b|̷oך- IIy}W<^Dׯk= KMXV፤2d0$OTR[I8X`zK}x B"m9j Ɨ?MLҭ \FekᏳADw[ߞN jscӼO{Wtz _EkHkmsV)~\񓶻Qo%TByJVٌ] J#yK#0Nԏ[@L"z3k,dd+[Y#hT AaЖ~ a'[V5pZlaQi`kJzSٵ2#֨Os␋?e`~LsV%h{G8&aICgn*Q5hI+Y̨3F5O?rHi^ʇ[TZ;hVw Yr crH5 Y䶐=piL'!yQ |#4/'n2jƲq4aV0F_qN[b8f=!{J",軭BxO=jdԤђDM.56GpqPwMa. r%q>a|0M5HOWp*V6Ç]P8^$Y4Yw_U/S]H'] u=۞Apq\ۘ|jYx5n#!T_Z[KJj3!I;5u!bviUJKVr#%a<᫘"5Ϧk:k).lgȼ;(4Ǩ꺥[RIWyB29T~5S֯ 2*d\Iudi2֢Z VhSeM@ΊֳI";W³cDf#ȃvXHKiN*߈c}6tfR=IKYKP+kZmΡ4>Y"TZd {jVoUR%ҳ.%".3nU;Un<u)!yO11 W4eIIw*t]k|e8'һ xz+XBAVDJvgGY`SڷMyⲴ;Sic7c2!8ZQ`[#9 j'_R1MgL[u-$`YjRJh\ sj6*}3 MV^A9%M 4WҴNe.dgq=+_ Fҋk_]LVޠ ;+-IrCӋM wP>S^O:2,O=z4Ktp}x_8Vls15HmZ92 ð5ᗇ'b;0z{kL9 \LjZn#]NFMj{ FuGNvsҹOԾ' +au0SGy N>>.',fMo|DIiwGg$ WD rT0ːNkF ?4X<%wW`QƩ|lna3"y`,1; -tu$cwYZ:Zklmi7F0NkI)+JBV:O #G]-imC—9b3PsDs(F`Hm6| oHOgs^% -Rp\u(]&mMn٭Uv 'XK%@늳6gOTI5EnZG3iFCqՃR{&4MfUA@m6YZƷM:yn$ IkE69sp-؝GAH|O\ۚǻ쭶Xw46t8 q֫$ےifbGģG+aBr;umFxc_x}xmYyɯwEXwtaI{?*nS>cu4a[cY\\\0TnYxn{{$zs^QW_ 'V ŐNECc[l9=+RPtY#pZ-s^'ͺBJs^λcs\iZtĖepKr{CӠ^g=9=*][ ;kQlsZV_0X͇b^q&B7ލ#ub#;4#e.v61{<&eW lTFPFz>QaiD"j'RH䝾n62nbhOb'y&=+: ,(,Զ{PZʬ-T;Oգ2U2d[yjy!)噢#yrl"-z⯼0v0LUI.cĺNmYN15ӷEJsӨx"R̊? Vz531PMAf'Qeʑ}E^۱ [Ioă) ;+mVK/q\(xWEX.2@]5Q5-Oj-K珜7IkYma- $5/'"Y_ $xi"X DUmObdxNc>MzݫJXKֻE߉oVpuE} xc6֚&2^Lw~ cvd_*j(5cЛ2J{-d Nj?,TxZ L^=HU%GF5rSE}53Yv6.QUG^_[, s\0:|sO,lT8n*j K˺3>_iZͼT7`0) EmxF7 C0j6k=~ iW p&'CA3㎕KZӣHrAtvңugOmiu$3n'4qr]e8?_ 0}VOK]!h%]*9X>H^]"/6Q2Tk -Im9DA'ڹ;r[#2\ s-_ЙݥnKj}f)f˃1G1FN-io'n*p MIXmKD3O|;╭fI@F}kNa}npG<6M=Hqb&½g.> ۠ Ěkڿe6ペ࿆<:K!Z5lqǢS9.&O5]*3Z [զC&=3Q)]AreF\ם7kмQ, Bg=kFLYz}Ma.5|e)j)//үjvH1KZQs3opF9^jޠՌ1.s֢յwFW|mtoby2z^¬[w_դNdnɢ5m~o41|0=譕ucd2.\ĶIN3k15Ihv3/XvXϓS [Pć98Ukc֔ae.m>$Mt<˝N[Cؖ95aƷV7l{*L~ɺ/צvODTϷ&rIS;Y]+ܩu&myoxOFĻ=ݵMKm>(R  cZ١O2gU*e۩ K 7kSŚ׈%Hcbqn XJw.Hdm֥ec%HhkW$t2ÕMSDK/NxqrZu;4yR:GC=5?سGcGS >\ О #爃p 6{}-$*?S̏p]Դ8ỗsVr9#X;RoCE>usg-,_ntElCN=B,i''~hG1 cRGhEx+μ;r\Mt@A$J;a>T|5Di8QgRڄqHVR)^Zy]-7ZO U9m >ڄl| kBHry4>3bO֟.jX̠ȘجM\Zz&U?ߚ/E7QlZ}}}Qg 1MyFji$5xRCp6湛? mݬ,['%ŤfH攣d8iYlp0˴fKPI=T(˓{W^ۑֲ63}{[{8[7?Bj6>w0H9[ @Gg]PMq3p;M +ѓиm!cܱM=UTr-+,]FZi$c!c}RĬh6#O%vwzwe$?@-\AOee-lG5Œk2;ȉ8촐#w%d;XVM^J-%ٸ %qz!mJMnŒ#okWLrDž.ipZR T1eܠnEqlzư[2$O-/qQ Ec Ɵ2N<>mGM|3;tPZF;:tjS⼷w&]r}tӌј&T`j_DDr L;fB,_[ "YB60Mc?QJʸY2@]ҠҙG-%n#\nǞl Ā9Y.$X椋Ng˧rAc \py̹JCM`kc`.Hp*w s T/˅8WV-CfEg(\^_5.NV9ˈ8֝,F[q]xvDcNCrxu;[ЮM֍eAֽ#KH" i$YEmOb[>.1&D,k\n#ľ0F+y;{ÏJ5Xبxb 0m$kACg :H!k7_Gx~6izeJ)m:ztl=i=iH)T/4)H wn:Vz]S[)ɀ E2O\('M>+[{S~"IcS4[r/nb/m-կpxXE1*&zdpe 374ѝ]bԭYWsHTs5u13 &:͂zfاgfj[X$ qW (VM`+5ԌA qּ<:)NҌ=JMvU fgu_1xm=N0}+WXk7G_ )F1Z|Ykud-fwTVvZ"|sr6YGwTǍd{ŏQa ^C.'vzڳE-Q:t?klwyOVXݟ$km&/5 {zOC//K$\J|O;z6WWZG>1]"$ v*me =vqQIiєkKG1w;=ZoV+1W/Y*"+˹tJHj)8xQT^^XbnSV3[%犫*m5;o*b͎ s\^@U!~|,lA9b 5qh(9ǥsڼq6ȿZI+*sChkTksM87 r:Ӆ6E!8!XqgsnB0}ffEM8Š,z@Ԛ:MN欯千%I'ں7#%84Ygɽ<j<7%G ~`vѴ&l4%TmO Ks~YtUϻ`WWVm!cboHXBwkh렢<{OsFo!;p>'ƭjxs_hP~komHr>KM9e9~}+;tfƬsK+պm K|1%FWx[TԌ^Elz[ǽվS4wZRpsvH,_)fGtiќuGn+\ Mu;jvc>,@f4k"퐍ϽSɧ܁'F*j&f\ScG|>𝽿[q#@ǵG`!Sb#{Fv^&P i dm$<&x}k'Mf,ksMSޕnΣǥ=$^*,~`a|VΉuLb$?i;*Nr+=?Dj<k`p ֳӃX7:wgXqS܃LҸ̃֙c,[es5Sӭ=[>1^+DW::{f3cWJX* Aʞխ1n;!&j̫J1 HI۱Y``ҷm>ݢ M sgmO .IۏǭxP-;p=񎛪xbS*é"5'Ez_9j}k<-ST{UrN[D6N=k6@^yZH2@#wֽa"&@n»'ҬQ3OYPm'RHQ(mizlpܱݒ5Ɨ2G dV {V4,Ċ@޸̌=nk =+.^_%ƠJ5m5"WhjΏ%2yw r0t*-\/vi%ָ$Bc;jՑ,eWh@s\ŗ6H)dݞ86F;&[I_jKy,V]+*;GOabع4i%S^D?͉8V2ՉN[ֆjTamqڢQ];` ӊRO"0?zTA-xzm&XǵuSxOּ,z֡ ^yD oowE#vk4SHvCc}̊ΓN{[?~[: Vυt.+K1IvH~Eg>u:~kwey,<{oSH莎rv .?w;sY3i WƐz?Deqifg;MFIt?:[l uoƼŎ;itًenNk_]?~"i<+ses^o|:4*4ɪH psc9T f#[qxG죹K5ȅAEoΑxQ_ēC)~: (RGZhDiݩiǠ*t7l-zW[N?:F$^SMx$?!s^㋍)%fO xRsf=bRXA7ڏ33a(4FINj;{D֢N|rCrSuq#k֘h|Y:No,TZ~i?E6dSÖݜWʿG2T)GUֆEڎv3׀+菉ּgyozȑ4"TofFxe4c8?J X׾4+xrqL)4*Y*ȟ|5z6orz_0Hk9岌MaXU^c0srwlj)~^ً=d݌jy49Umhf{kh);WStNlA*G0L0P26pH^xL+d^H5Bq-@29ۻ";1y ??"b]A@m56.NVq{VWnl)id_]4[`#*Q;Wd"\^+XVJ;j3#!Vl$N3Y^$jAM.qlJqetMQgMl`ݨme~5ee0~Q GQvG:Ve ^2uFsrEu2 Ww9._?w a-7~L=k u#Z0Rtwl 泅/ չ nݗ~=k/ga'Jnʩ- 楧X4Qk5WOi ysE4Io^J_Wg$|hz|<Ե^kE6 d];uէS̩3s}l&x/6D:PҼ.Cr3NzWx.|1m o"uzg4dB C>R<{O kR,m^V\ [~>񅶃d2[*LW78Π8nҮQeS%۩"c*cx"3*3ʧO=[ĺM-<>Zfn7|jK^K4ĩ.E:5zNծ6ާҴmdhڹ313 *kb%'Yʹ=L 5F[OX+M( ZEy rj%i_ƨwc^G kY~Ϡ.[$q?_Qd^ʁT Z1x78汢3d%aܜ%`C^}Evt&ԾM­Yk_c Uiϲ{ȃԌTr/r)RGI$s?iozӃ]hI2Eir j\.S*,#GL+n&Nb՗?{Fdq՛k`5lƸ+Qaۇ\ AkrT\)YJ|'34O[2.rꕥW$JdO036BFaD||5~?c:SWtaI(d:ȷbIA\5~3Z!0G?̺qߖxqQI#G)s0xeSS;N=q-w,qjum_FVýo R;/tp-du&╜eFő 羇>|[ۆK_H.v_J vx9n&د<]F85OkRSJ IZ8#޲=XzH|u)\sk ;Vk}\]Xj0ĸ[r$,95v¥^C^Huf$9cRM$2jEQHfn R2no#&2OeW #FtcsԮ"UeۣD ձg뱱]Lct^"v5S5ZbՇ ӔSwW/yz9e|xV }sQfeHIw:9_GO]yBI XIzn-,l!QZo)RHY=GwӴ0*%g=hkO 6au7>[3Hdxr: ي0 T48]UI`I HٵM2U[[8ݻP,^9s0sxgGoT.yU_Cye rwweVoʹɴRM-nIZN.6ҙ$+$v+oJl?g-Hp48?^Qw>{./ [9{p~8;d'Һ#/Oi_Eh6ok&L}vIx߆PxmI7@n93,>Wt *Ǿ)A=kuNst#ъKntZNO]-B[O|&Pԓ:K:,Bre'kfor\cށ$/u cy?6RCofֽj5Db*Ek!Sx z3*>'2_x*qXdc z#K\9,=Mx֡Kx{xT )nkK-Gw&a, +¯7S4JJ:/ aȂÒ+d/E :{טxwТ>n%,æO4DeR1^|XҾ%CiuX LrZ=3 +Ε7}QhzDir +HI/}; <+y[[ D] k+g=Ir*iw57+ʾ29v6$H .Qf2-OBݎP~3d" mW?3z_:ZAIo4S3/rzץ._ W~oun#} TX#5ψa6R]0|?o*ȇgۋc77aӭn‘kV.c]nj;ԇž S8z|C u N;UYNWwlW|5h!KO_?68V*۽[5BY]4Qk ߚYCgӳJ/*{'5DlsjYVfǽR2s U0- ˿ԂNBzVYVz){ͩRd 8[#Ekkķ[ C đ9tk#\{k "uK,0-uvUIh|φ.?ֺ*Svq`zZ3M}ĭ}yr`FjhfSq+֜yR8V qun@ Ҧ|EjIvCj޵u gkV9}SLSgKӜV~mav-EwZe}FiL|㓌ׇ\zmO7QKmPhbf$ v9o: 4/E S^i:eơO~XW߂x2+';ԣOuodAݹB#NwI_ؔAt>.:֕<`niC[ҠvtF&;Cqn gp~=,#{:NGUa+>-uO䵣D<ۮQWM܊ô=UMͤ`FX~5=ڎ`$DxErou? ir_޾t^3'O|CF䵎<:4%v MCOAjl.mOK4Y`<{޺O x,wO=ɼ3ͦc..8>[XP),Zi !8%ּ֣xx,^=?~# ޫ\xHj(G{i5-wvSZF6Dٌ|I-N>>'pKo}jbEѤI Zooqys+2[g( djAA es2\GZҭ|Pgn1\҈sͧ֒RwsҴ8ACb `wĖQ^O] C{? ףEj) A>V'Ԣ ZIL6;/ 湦A@zצi+vo^k#ݸɷ^I |D{"N^yΚ.lebT|[(m9-Tk2W/Pd#5FRie^EPD+_m$ QOQX[griqVvA6xuL@׭EzE$LEPx߂G:C[D6m$_T{1hWZoou+گI KD{0i|\|oq$^ $'#+rg} `I嗚vop=c=#C#P[W ,p^wwonb=B r# Zt|CB5$s[P\̂9/7Mۇ&:QҘ€傶>+ӬB[k\'?Zd1Z7R{2{%֢H°H-[Ku,nfQ;jb[[HmbNnH9GnDk('5j$O{ipq^o|5qc^UhrUF}++_o\[/kyf}YrxI@𪦍{3NOY><5|_:hy6q\Nu9u׍1yk!\$1*?

    o>.F_#ZR'ZWHjrjQ!xJyY5 H?hyHC%9jړ:9Xxo ǧ˨nmdֵn( 3\=.4}&鎝47|>'u;RlXvܟǜO#Zo~^84Xêܾ5;wi$P1?S ^O_xS^% "Uo3T.F[&={=c?ڷDjѵ]'Y֧4 o(4&fP%mھ>qqz2{C|m"J- /--mwh2{įj/uR[!%̓rN+i_~M?c/Px~yO|ƿ_3yBrW㟧M压lC Z65YhgwtsDһBSv+]Ǩ gGԴZK,a;vW~'-?@Gu++k 4cc;#AT>J5W/#ԞugPTƽYG9+$kuco}>> >O(/jm ?"i"qd6 g=טxi\29=+S[T=ݿQj;)θtTln[ ~kЁLjD&=T/ViL^(URl$s-e 'mBSjz>{syc%G\{ƾ7guٲ<jNğn&y>f{+aRWeOItxf;HH~hk,Z\Dd>\zהx|ѭKo%@]|:-G9cZbhtOCG2]実@[ ~$\iV{$cf5Ȅhm׃_GM,czv7A{沦llt,@ko6w+` 5fާDe͝p8ɭki4+^'~"Ly>^{>mtOkxEu*&I2m)'+@Z2gM A1]FՍt)}GW·≵;}ZQWSUB'Wsmuy\;7ʹ{_1B1p+OŞ n@qHG=cϭ*əG57@Ks+/W/<+i0|N6֚}3:>ie'5b6s4G;q]˩Dcfy\.j(rFf[v^sWal t^%% 3rE-rܪZosnt(6Co#PV[HD7 *Cq[z~YiZ[赧5t(B1T4jHn1ț?c|S26s(FH\C^kvodt~--Oޫ_jF? i!]秭g˪ɧD dZF3tYmSs]Na rzO0穮VbROzWq㹐A${ՐǶҒ{_,"jV6N黣kVG3V&x ~uH.25hen=*ކ<3ܚ#5$Y8sN76L0E>x [:t[kYEv q0%;rMZF6(J:/ \iI1('P~-_>#kR~|:_ā;9lrڂZ7-%ev .I1-^ͯ1:Sn/mcmo1vrOY5+LOS%eL& HR=y!-u.u כXLr H{ RH2Z?9bKi Ԕ|?=Td+>aEz&mǢJsfw87 #;q ӵxϞc&s [蚍Hg>SX:ɨ-2caw|"hrQU?i͵dmHW2P!̇=EG,Ooj㨋vwM0#}CVSu[0k/L Ua[k-8\!1Ir9]?rznukBQd;EҺ Hp lYXFfz0 3}oiM河Yd[?]W[9Z^M&伒 v-^xK'ڻK|GV'd/ͰO\ocsz.u7|+2_H|x͐>W|?|6wWsͺ15Xzvfu C nt`U4^dd,\W> >`DO85q]!˂wA&K鍾#9ﱎZuԿ{(m0MK^<g\Yk?+ 沦֣_O[$[+*W+qfCÚCM ]yZRJy\?5!DM-"s f<;ְn}}}@~yQջ O{P)xdԝʾG < cҊ3zE`|My`҅)pijC(b ~EL\fIְY'˶PS7Cr0=kȼonI&PH+׼S-k|v3;+-o1V;?mZSYZ^]f[&>0vEv Y+f&_ =i(=pju"QfOp>䌗Rwm~=ai|;442l2&yc+BmMsI~>εe2 F1J1՞E,>%xƺ߇ıEu &?5A8@[ڵݽZJ5=׏,(tqX]GY"Y/H \眰#?Wea <#oiuqnPsʫU/ 3E!?2(ST-?(G?lڸ/? 51aj G޵b,'%*.mD3'_YG3MRs>=nCoF 1\׍_G|Y\4l?5}{ڀOl罵cra|9JOe/=fL[0T.?J8N9?|v77)Y;^-/gRW4|7.?ٹPr5͌Ifmn!A W#VY0 Fz׽xznQ!<@k˭cѦh>^ܣnB~GC \ǭ\}2`wڰb[VF8V51x֙PD׵i^Z/ Isy{mq1sԊ`} HfWEh|?#uCHĞv+Mfj^1d zS.Ѻc |„|޵GPcK'o'~ EdFxzM|EҤ7n8ҔK>hfĴ1DesGJFքpzkKqMsF8zJIRKEp a( m˹6D)H߻6d}_kOH@MiYoq]p$RP6[YOQ2˚N&XU-t $f,<2 z-Lj1[fyJ&;MuդSڽZ8 ҹmf{D~Ů\p3\OvNj/}a'/ѡ<}+>ȟ_qnIL s=#t[kr%'ojob:2RSi9 ӴŽ 6Оk=sS5iF(,J+J搏)n hAnV(e$U;-KKy!zQo @61CejڬN;TjL#ҶڅNgYY’@LElas]>p`;8aB?x iJ$\XR7tFgx?EҮm-`H3~`YU  y#=6JuSOy:sAdgjYuk6Y T6)Z"U}{MԵbmN$9 Z% ]gi~f+ 9HﻜH۟\ mZl\ V 66q8.|?}$A?޺^[xŎ"I^j~ %Ot?xI w^3ZNRŪAxAqvg28+C\u~#YxO]ܠ#ӓo+9ERNs]4$39x+Y3ΓO#a4XN[/DsYw~8Fɬ PÜ~UJėk` qZU:JrOob\#lǧJuyU#I$Q(\Es"IV!Qy#lI*n2栳֧jPdAiU`fI,%0\Q7cפFuqh<HVoenfAbɨ*rv<2eG^'g4GbV7dq%m/u @ ? /Gx#u8 *knw?0B*cyQxO 9ԜE J+NK3B@V|!b+3sk{b|3ZSt}PQ眃ڷՋ{}ukklZ.>PAgR{Vc+?/5xQcZ X.`3]p YX^VhƊ|/3I1C5Ą?\5wh鄏+񭪙9s^i.?[ˍҸ!k11NGksqmm.YDWGO_a+%im߉S⎋vQLkM;H8~ Kz.|uco$q[&$'sT|W8_tn3EjBSs |=5焯[P2 6ݺsKZxL6" rӕR^E|RwӴs1_bѮk&Y̌8Z<_yi \Oep-s6uY#É&t1&kv< :,B.ZtkK+}s^:4fu؆=jl1Lt U_u4b sܨ+iwxҾ}z$T?.Jrk2债ǖz׌S'Zhjvc99F.~>DJXq\1ңׯ )sΧ;i;hA诱fEpm;&KWgpڨ1s CBd շ*=;=[Mμ+4) 4D{fphe{$]$wS4.&#Y$=p}kh1Ao$ 9&]J~"Yϕfnfi;`e5^Od[9d4*~$G`Wٷ⻘gH5/9ayt#m'˗?#YpxJuKy ğ#o"%(ڰbK5 ntr8-O:t!!H#/di%~+6BR:c yOl$ w+[x\/Ų,6PkeLk*9*O5sXϸ@>Ic,7iddqe-3SǬKb3 c^U9qT@z E;qTT[lN^-a͵ŝp3] NzHi*rsfml⳴]'Qlc sirΗ+߇~4?RM^ng#Wx2 wȆz`< o]GNȻO{ CGỹ;kŚ:[>Ƹ q 6k"B/Y>[jLLv'ҷ&X[ʁG3Y[Tq0n4Nntwn=JQH5Cʓ '5oR kֲB^C1ؒf%6Jm-n졃ȋ;sڲuy'd+D!fepw֗uB{ Z[q@{B+bi4-%YȞ18"uF3'1E;{o(ts@{C4[aβHz^1t]2xcuYy@zVZeQ]>.LXVFӣ$%ݚ:Nwj-.4wxeȌş5!.P(`Z3u,zk܅ÎAUkӼ_w4ݞ[vv>ךh[ytHF>J| ŗSF,d|'Skiq_J081 +N5WWKUll?S.&T-"ct [Rm+zG0r+]Ljm8oiu]I> /˂zM; Fwܬ/==JՏ>C}Z3Vǥ\ZݛK)䀙Z֑bs|j{9\D}l~kc:~6mƾG~> $r7W^4_ipjsEW~xEk Hלף$'BVGQ _q>#RL zHiZX' ;W®;V:zBݿyo87NDZ |r)?t2J4u(u{eE8+?/'VְCӵ f7 \KQ6[XӼ7֏HM+ ?!? ojߴm;wcX4m#@cP0k濈|hF'=x/78fԤXҢ}y:,I+1+KSr]¿0/Kq5$tc@ F(=I95hbGˍG>Zq+_ A2ܒīiŦ?ʪq1 %Q]u"#HC~VM;\®q+`7sP_,$ t֢%?WO%E_; /Ri&3SQX{ǜ=<]mI!{b7.rk|O1gʜcu{0$.0l#[E N1KύM",Ienn_$j;_'wBݛ `qZ=/7C- ݘGc|V>QW.t/Yi߳wb f-YwuoH>e[ZMeże-bPI8^}gqO᙭/?<\SƒiAd*N9Y<7O7mCmLØՐ9P#zq]'į^5$,-3A?x7<-suai\Y #+_ )|Zߎ;kq^?ڕ t'tkcc׿_:̿ =&+-/Q{xB!l׊5_-xn I%{e-T! 8m_l|;q{OM[ÒAg'bC2m2tt!'v>:SjߴxΑ=EDW:};ԎջCG'5iu:,Z|:ŭ̸ʩ+Ӿ|RC\čuθ3ҵ ?to4Y|_Msou勨W9DfRiN*-PY 'ux s$]IF偹A$_[O^]i9O5w?;n/VZ;5']Rh=%~h$״!fub% )~9 uRmMj}40F<遚:T RXh WrN+N[KB gs4Suij w#[xI"p h׊wM%7I4e?Q_~?M[ `Ur:6uo<3|3SI~s|,]$O$۵ǹnYR#ɭ$gRV1.eax5cƯK;y)RY;1SH VԎiHB*hpcբӴ 﫻Ro;q]x^6->Rqygmo/$aB 9{tY7uc[ߴFܶqrZ  W{V:g4:ݦcvH/rqo -h K(PF+7m,4[GS \K9 ߊ?|m.ˉU5$ 1!ɫ~>$x^nb)^]Onё}fr}͞bɴdH]Md ]u*їL"P#ҟ(V\+/L 枧D=,ĕmjEUcE;XR!G#U[<-zbpջQa}ϢIi.svz>< 0\73I}\bIz<)jfr gi,Rn<n:ּ@lT X±Y!IClY[+[é4sV{֮4 ~U-͢uZ|235>KCֱ7ek|nǫ}jSTl4# >Īq=꥖.(8O;T+78 }*'(\UZaޣZ18WgeSYO2nxQׁ eR?FUO't|'2j*%YvN+ؼykl|)&TRܐ##&@ Tc=sfٍ[Y!FH$`mSc;d 9P`YLͼwv F/&O;>llctx3|MgWoL0(ng""u[mƤgȭMwzek]jvzU[mHe[91\|6꺣M{0q#V-׈/VǖFN;ytA|,Ih{xLfkh[ M{sqqtX+dX6;` \1cZI-f|B @3Y5[uƤT"Vl1aqn&l,iZhG4?qjؤQ|sZ3+QX5gMk8?oeQ,Ē>b9+;AnTeӷqAԶ=kQ4}\D{%̙p-_7>[ۜ/1tX\+8<ϪPfǢ{uc@5Q#B93ݎ6vU-YPyY|;tmdK{ePǞqX Wo)+;z '8hdY1 -_S31\?&jjD> s[/uՎۚݛLuN 69-.֎IB97?|QG[(5@ 9oO?21N0ж1 zܶ 0 UZkS8d mX-/*_<׫E|%iZ~9$Ʋf/K±_rm\cYn59]89.J~ujZΞ%|p ~}hCVeVd3i58o8$u0xإD`hUM*;w9CqT%'M!vq6NP`$,T{f|E ߔ]<45 Ɨ\GgCw9PMojWy ۞ lc [Y۞Xe.4Lk7g 4lV:Ž–~ͧ8BÎQkLn5?pc1*xb `dG H\V2y';*i4!\OƏp:;V\wFvvgcjhGyPY5To,=7+qHSg|⿇735U#JV։]%Β⟩W+725S\-{òiڜ&7Qրf ӑBΆG}Rs{P}d7':v\.WqC]"_B-Ή;ް_y j+-fP @N~4r 渭OM%ƪ&g?uR25[WO4ao7J+-ٌ%m$"v󢛬P<#!X#"\X㣝L'JcLI&ARȰ7Ni|М(K2`P 4nj(r[@ĒrL K * Eم\YwpB犷!j kjTt9^s\otmGz=_{kִ֚L WRN2о΃n9^O+ PwyF gڼ[s.Gޯh(^G*i\Y9r0=jνY ̆Yb0޼8 _~ x*k2Rp/2~o٣ ;^iOOn0NG5wkէ ڦ&)db qM^KS(6G{e&yCopyOR;S~*ľ2YcysW}GLaUhk1|V#֡iA9U~ID[2_83#p97_w6I.  ugZZ[YFDlr?x/Ư|I77DᙠP@,Hk:T>h?|-=Ow1F `n1ׅ|u°񦿨XiLrHX=+m$c} rcc䲝 y?|^SUỽ2I3J%cp]^Z CҿaMGU[>-2ɹ2 fE~ϿM{/LP#˔ KucR]/_7mx> L^k W>/j\{Y,o)e󵳓JǗWf'~Ne^j7h] 3WWi jLH0 j'jI5^ CL/[tZTM_U 4 ̶+J7 }^Taܐ W߷Uut? +lbA9˶1|#,+\ |0_AvycW–"Ҡv8\c#ҿt}sy HOSa:r: &_.6wm8!N¦ӴĻ8s>nMB AHVYRCY.ln$zU xk-@1"O7uѴmR?S^W /x=\[þ=L])lϸ|uE#,Eei>ZĄ.B9/TA nkSkH- ?0WN:XFAKMnϫ4=2HybGSG3TXc`ByR2>WmtQmIJ0Pz'c5#-Q'J}j8a{ѐ5n;p !i+1J^ { }R㹭T\0CeՋOozR(Ӕ`xIJ&>jJHXM=y$O}3gSݸ1.ONuEAM)VK#ӱ*QuY{&E?gfI-tUsm?zNJ]OST`T?tqY^|aB/T8ͻy"|+O7TyFN||>|,o'U~hw_N[Oi| wm˜1}f+{` <ς\]x,"$s.=֖#ޣFqxm-wv[Tc"|m=}i6,[T-+nSaN͉FYBvY|ު:6se8y-}j[h< UZդu?,F{~Euȡ7dPyrzƻzך$j2CIҪMUhQ.{ Ϋsڷg˽33J[׍VpM,цṯV vV3Bn8C;nj|1tUTKr@wx|ٹ¶))XM{Y0:ԣV>Y`n:Z2`d#'YVzZg_kZUm<9O"cO2Y\EM'ëYFW:bw)1K1>Q/s1Iq;F&uga$%~򞆵u8B 1ϭSWK֞r9Ǜzf|Jm/K&L&WVc Gu^jԜ4z O\@ח LvnH"8!EmZYVIgnqu,ZH {Кױ9r쮃0~^:S:_/#A :͂7% *ڍA;e@i֦+Hr9'5`$Cc5S#Xt&}o(A$qM`&l {ceT hV$!1֓Y-gq,yk'{pv-3?fd;$>_e};n`m3N}x'sУ5\^up'M6ᶯG,-0аC~\إ73b?OEMGO;c:zx9^cz*3?mM_ Lѯ.}{Hq_nkKOiO#+R.c-k;/2t 9Ye$_,.G+0Z1{ݡj^9|Nmixc7i|[9Wa2Cێk>i-Ϻ?qk,%w#QcB#,sZ /k ӼG٦_0ۻO;⿅i85HH[f$v!Th^٪~ş>xֽ>  ,O,Q׫/L5 3kmrۅ^6ET.I:gq }ms6}oYPa㏦r=7N=jqM\Vg3. YF4>D7-|H蟴_úV,mj{mv(js:{uxr^wIG Ph 5xx "ږxvjҧ{p+CUMjXZ'$np:)9{SXWѫU,aDWb~ƾ:IHb='5=.PZ2Tc UW>DL@5֫Mv59 j$+>=Z`ý88HКG?|^)T˥!A>=5Kkta"0nֻ5φrIkwcglIR!=xnSkmJ IO>{9ӳ?J?e*ϳelV狿^bGḾև as_.|Ufi$[^,xTe{;uxQ&~PJҗAS(Rիo#p17o/U[֊_Wgx2?UkO]5Q98W:SV8{Wַ>M27Zc־}OZԸ&$ijzN$2*9cU\Skm1mִmt׶/mcZ:l/1G?X>}gT9Uf ]e]ԐȂL xgio"0y_Γu6#$cA&kkf^5Jt>keNDm vfOx*mkZi%38y&c)5MϓC r1%׌*{?2Lyޝ£L1GT.Ǻ.Fzk2\! z{ Db/q[+2>40IGuCއ[ s^+=:|+֯c2L *A@F凘'zu]fLB)T}rWHƆ< x?hO i=K }?Wogr5Q2Fa>3~ ?7L.O]h;xzrh! Bnx+(kOfxڃ?_h.Nz^OWsᗅx>I4TDvft,O@uБ[0+{XX kʢ3[~ ;)\1>.HufLHH΋#5_]F0/JM^xYojۯzV_ND3J1d;F>"3߭j5QYCc|mV%_!OW VeqzTKNy$|VG@j4 3~tKkٍ⥷)Ǫ z֗r&E,.;3x2[mI'ja޲7D- AJy. ПZ{WI{sUu'fCz⁘63Cvvr>i ˟Ʈk+{ nx -\O3]Y'$dU yo(ގh /F%  RgN-ړ)SY]U3blI J5O隝ZQs2BW~5|5MS'\3ҹxkn9QsG+n Pl@ cif!)5k+K2I`x2j}qW,U5%fnE:1 Sy>//'KemZR=HR>S&MNt`LHĠ֬q$Y^r#4)-3F[y![`*ޥCҲ9BJFǞ)E>~0tTWc|"ҭ?p79~MdDBq@r I+vkqo eZ:<ڌ#p'$7J|+oX0 tk Q9-n#-![CbC.n:M:\̍%X&ipNGSGv;Fj]>?7pE8c҅RS;xU5t:SGKZ4xek# 0N*5"/p6# kxh,C3Fqٖs.e5W;Tkڛkȗ'ַ̿R2J:|I]OJdeH$~ ѵ9"(OG5]O W% [FƥjӜb"ʺ{bƮO 34vr=-F|J^"1.$|6GX [i{FûudKqo 7]b;M>VOlrʬx~KRj6n\}p?m5}Llhnl.G|q^W?4+\1_[ntFuG1[ƹ:Ύ~[)!I&`?卋֬xMږr,lާ|OPMA%i\SU~m1g-6\Kik("ϡ!EaM }㷧ZO7IA1\X5!3=;kw0hy*d)Z4lǤ7F%8ׅB!sN؋qr҆dY0e<8+ncvUaPȒʂ'&<:I$YXGa#ϭ͞࿴6g4jq{2R1W|x:ͷ<>lTcO¾ /yR@'kXggxeyTڬFsȯNK=Xr3%6M&뿸b4K~?d~/Co1*^k ͽm8;D+#Y]J͈UW'lUMfxU=nŪo3A-7i hNw4O8?7e8>v v)qA}4w jxE,&; W~cGui?6zǯ;OW~z$~xZ:~t $,sgx1׍VFa+BSK^ݟKUc^XN3]kᎹ{c4f,ZjAZJzUpfs&"B_+Ƚj0jj7PW< '4{xEm쮘lGD+}S++%3&x\ J|r=w~9'TsJcO_Pđ^៍Wt"#w9̭/V{gܿN+'[LW2xk̫}cD*T][i 7,b?V:=Wr_hOOss,Vǘ^h Z+?y3+S(мai 淦5J$'GzFu='#ܑ`p3_/ME&iiQ{gmƙ%.Fw>yR=HfW n\Ӯucl0Zɳvs5>n|=^oik cωux.s6er9c-yy~o'4kW5kf 77?adBkkA<Ca\Og?Z[>xjGџ̺E38*rsGMf'ވ9`Xtl氕^s~CxVHXs\ŋu!vaZ{?o/x?noUGv>8|X6ZNgpr!}'kIH#7Lw×Z|^'mM +[Ou{mgQRX6DxGM {p{A ~ V92gi-oA4 U +ODn݈=+٥'*qў5k|d'4XNe |.pM dҺQAbomKogg_]lŬ95JUy /؛~)ˈ|Wc?!gω{ D'ZG!-V$ pzuӀ Moar"55ҫ"O I,%̑kP}2A5"мKS[_ܾDij0NuNm|ۏmaMhdu?7Z[Nv+ 9YgQ,춐89>+kO,n@5iNpB'es??n$cӡaq$¢񶥦]&&mp_zN>;iw^bNc {֑)jk3ja {#㟍`!&X6YOb9Srp 9Z&MDCHw ms~/_1] ız+υZ_- :]̗ hmWF+Eek\--/qN3u?ԚkYgr1ᳺ-m}*:q䤯'9),amsJ9 aXODoV[n]w|x⡶Ϩ$MY12fOمE %kwL fu|m2wMGVD\ij꭭q/r ӭH~j7(/JfcwXzj͒&Dȳ$,GZ| ScvѮv@lr=hQWeP8_%1&Nx͛/uGlt-PgZuuwnYaӦ=^7OǖW#UEUcdzo0ۏݪ*dۭͷ28ɮG?]~s^"Ҵ8}Si>`))*XZO) G)n cA'xiIl Gp#2PeBmY0cɾv\KpT]O5qn~T)-ğ,aִ#b$l]TV؛g/>H|LKp˨A[`]ҴQq;4h;I^kZ`"QhSl5RkBh7Wj&}E:H;;J(WGў=[ʖChlyUWi¡Ѯ2$NZEg&ijM9-KL$>ԜLk|}[,+p1m lX6k꺇LH+CZ3\h,xbLhΪ'܉^ѶF}9⥖8uÍ.vCIjy#fuZ7xK .{⒒nF^[#|!x ̲Ɂjoǚw"ºM ;Hl/:{QfmJESo%#|:SM_ɖ>P^iqi _Z\altP|ucGK$zl !rk+}L[B'] F#+w/i8YxM_k[-v;WC8֟K+:8@_0.{I,*#7'}Oᾑm-[FPxx^Fa{*w7U=|?]:{%onbi qwi$o ihIǝk#xexR]5+N9է$&A5⿴O VOX+(#nμ ɞ#Gt/x;Blpۃ]7g_j,ѝtԜJNʿk)/(/ּ7j~aOlv_Y1Gb2 |4;j}WKQRApX>Wkѭ~4ZJ0"S# ז-$bWqH$\<שN)jNRgu_\k9[yNqzg]Mj浿$GXw0k"{ѥ'5|G.f5CC v4o`:H 6r}&R6)FTWCP F'p}k`iwn)`qƜ{Iq&D>MºH&DӐ|?x:m?eE8?s5⿴7;#L CpbHEz'~!_i2~ $r7Lk~w.uuDc5Hgk^Nn5Jq?u_[ZSk _,(zֽ2cK䰊{sG5_ea3KxdyjGª[su+M ;m=x+yϋ"RvS @޷--,->fAc6#~Gޭ&Td>o9(tĎYI+W$s-X auáw5 &pnn|xq3Q޳Q}3S}}xW\]F .g qkoǬ^I!mkFo=BdžP84f3OЬ[+N88$n𖈩 bXjҤ2HukYFH@VOQ9 B<`T+Kh*ҡF#vk6 j's9JHӭZ[vǐ瞵j27ƤM9I's\Z\2}DE2ENGnjdTerS"3LXuF<QDdYHjW%,A8^©=-69;uw8k:[E9cZ92wc}f¶7yj@ܮk^Cp\W{ H%n#mz]E>_S ҇G1m{K}KN DaZz\:\:츊ض5x>KYqʆ~㻋Ҧ)"kD3jcqno\XqW!bu,I%S)Sjmoxcb3ޠ/1skG l .Ƕ k7کHe|jܺlvq7ًk.IrREWᖉn]IVK?w.0[c le)޺ Xy.xvf.L>$^-ā )^4:qo.yX]񦤚5 PJh}MmbYJ'_J)&N_|ҡ]_Ķ06U׌~kO|M{ ֢" tuξ5m)jV<(3 *6LqoLxpkSIn!C)=+|/e5H.<9 fxbO" }{'yM;Ofg4wgD 28^=pƪhh > zWC,2fȇ rڮ`W' >2L֑: }7UU [GU1FCCA .qwܚ;芧iI$Q}Jxb$%w,O$|ielʌCq 7׌.vV-o4t'#+#JdF]n0P0ڴ3dc3=7XsҦ0K,WcgV͵2pI\*+"v]6[!tvkh/8B'ptQA=9#zȼX&o- X_cP]vl}Vb'b~!5XR,h>kXrpr/xikQ!C=]Ɵyb4*Ԉ1Ovq"Z\D˨:H#±u/D`~*N͏@ktǡ:duhQE"g9_Fse̲yl3nj)4Q,q23g"FF.*KT~wx;oW&zr?5!Xũ&Ͳ+ړ‘_YW +~,qxz[I{ recv.mgn mgen input recv.mgn output $LOGDIR/mgen.log > /dev/null 2> /dev/null < /dev/null & } } custom-config { custom-config-id service:UserDefined custom-command UserDefined config { files=('mgen.sh', ) startidx=35 cmdup=('sh mgen.sh', ) } } services {zebra OSPFv2 OSPFv3 vtysh IPForward UserDefined} } node n2 { type router model router network-config { hostname n2 ! interface eth0 ip address 10.0.0.1/24 ipv6 address a:0::1/64 ! } canvas c1 iconcoords {72.0 48.0} labelcoords {72.0 76.0} interface-peer {eth0 n1} custom-config { custom-config-id service:UserDefined custom-command UserDefined config { files=('mgen.sh', ) startidx=35 cmdup=('sh mgen.sh', ) } } custom-config { custom-config-id service:UserDefined:mgen.sh custom-command mgen.sh config { #!/bin/sh HN=`hostname` SCRIPTDIR=$SESSION_DIR LOGDIR=/var/log if [ `uname` = "FreeBSD" ]; then SCRIPTDIR=/tmp/e0_$HN LOGDIR=$SCRIPTDIR fi cd $SCRIPTDIR ( cat << 'EOF' # mgen sender script: send UDP traffic to UDP port 5001 after 15 seconds 15.0 ON 1 UDP SRC 5000 DST 10.0.0.2/5001 PERIODIC [1 4096] EOF ) > send_$HN.mgn mgen input send_$HN.mgn output $LOGDIR/mgen_$HN.log > /dev/null 2> /dev/null < /dev/null & } } services {zebra OSPFv2 OSPFv3 vtysh IPForward UserDefined} } link l1 { nodes {n2 n1} bandwidth 0 } canvas c1 { name {Canvas1} } option global { interface_names no ip_addresses yes ipv6_addresses yes node_labels yes link_labels yes show_api no background_images no annotations yes grid yes traffic_start 0 } option session { } core-4.8/gui/configs/sample6-emane-rfpipe.imn0000664000175000017500000001042112534327775016113 00000000000000node n1 { type router model mdr network-config { hostname n1 ! interface eth0 ip address 10.0.0.1/32 ipv6 address a:0::1/128 ! } iconcoords {263.148836492 76.94184084899999} labelcoords {263.148836492 100.94184084899999} canvas c1 interface-peer {eth0 n11} } node n2 { type router model mdr network-config { hostname n2 ! interface eth0 ip address 10.0.0.2/32 ipv6 address a:0::2/128 ! } iconcoords {184.35166313500002 532.524009667} labelcoords {184.35166313500002 556.524009667} canvas c1 interface-peer {eth0 n11} } node n3 { type router model mdr network-config { hostname n3 ! interface eth0 ip address 10.0.0.3/32 ipv6 address a:0::3/128 ! } iconcoords {121.17243156500001 313.104176223} labelcoords {121.17243156500001 337.104176223} canvas c1 interface-peer {eth0 n11} } node n4 { type router model mdr network-config { hostname n4 ! interface eth0 ip address 10.0.0.4/32 ipv6 address a:0::4/128 ! } iconcoords {443.031505695 586.805480735} labelcoords {443.031505695 610.805480735} canvas c1 interface-peer {eth0 n11} } node n5 { type router model mdr network-config { hostname n5 ! interface eth0 ip address 10.0.0.5/32 ipv6 address a:0::5/128 ! } iconcoords {548.817758443 209.207353139} labelcoords {548.817758443 233.207353139} canvas c1 interface-peer {eth0 n11} } node n6 { type router model mdr network-config { hostname n6 ! interface eth0 ip address 10.0.0.6/32 ipv6 address a:0::6/128 ! } iconcoords {757.062318769 61.533941783} labelcoords {757.062318769 85.533941783} canvas c1 interface-peer {eth0 n11} } node n7 { type router model mdr network-config { hostname n7 ! interface eth0 ip address 10.0.0.7/32 ipv6 address a:0::7/128 ! } iconcoords {778.142667152 489.227596061} labelcoords {778.142667152 513.227596061} canvas c1 interface-peer {eth0 n11} } node n8 { type router model mdr network-config { hostname n8 ! interface eth0 ip address 10.0.0.8/32 ipv6 address a:0::8/128 ! } iconcoords {93.895107521 135.228007484} labelcoords {93.895107521 159.228007484} canvas c1 interface-peer {eth0 n11} } node n9 { type router model mdr network-config { hostname n9 ! interface eth0 ip address 10.0.0.9/32 ipv6 address a:0::9/128 ! } iconcoords {528.693178831 84.9814304098} labelcoords {528.693178831 108.9814304098} canvas c1 interface-peer {eth0 n11} } node n10 { type router model mdr network-config { hostname n10 ! interface eth0 ip address 10.0.0.10/32 ipv6 address a:0::10/128 ! } iconcoords {569.534639911 475.46828902} labelcoords {569.534639911 499.46828902} canvas c1 interface-peer {eth0 n11} } node n11 { bandwidth 54000000 type wlan range 275 network-config { hostname wlan11 ! interface wireless ip address 10.0.0.0/32 ipv6 address a:0::0/128 ! mobmodel coreapi emane_rfpipe ! } canvas c1 iconcoords {65.0 558.0} labelcoords {65.0 582.0} interface-peer {e0 n1} interface-peer {e1 n2} interface-peer {e2 n3} interface-peer {e3 n4} interface-peer {e4 n5} interface-peer {e5 n6} interface-peer {e6 n7} interface-peer {e7 n8} interface-peer {e8 n9} interface-peer {e9 n10} } link l1 { nodes {n11 n1} bandwidth 54000000 } link l2 { nodes {n11 n2} bandwidth 54000000 } link l3 { nodes {n11 n3} bandwidth 54000000 } link l4 { nodes {n11 n4} bandwidth 54000000 } link l5 { nodes {n11 n5} bandwidth 54000000 } link l6 { nodes {n11 n6} bandwidth 54000000 } link l7 { nodes {n11 n7} bandwidth 54000000 } link l8 { nodes {n11 n8} bandwidth 54000000 } link l9 { nodes {n11 n9} bandwidth 54000000 } link l10 { nodes {n11 n10} bandwidth 54000000 } canvas c1 { name {Canvas1} } option global { interface_names no ip_addresses yes ipv6_addresses yes node_labels yes link_labels yes ipsec_configs yes remote_exec no exec_errors yes show_api no background_images no annotations yes grid yes traffic_start 0 } core-4.8/gui/configs/sample7-emane-ieee80211abg.imn0000664000175000017500000001055712534327775016616 00000000000000node n1 { type router model mdr network-config { hostname n1 ! interface eth0 ip address 10.0.0.1/32 ipv6 address a:0::1/128 ! } iconcoords {115.14883649199999 139.941840849} labelcoords {115.14883649199999 167.941840849} canvas c1 interface-peer {eth0 n11} } node n2 { type router model mdr network-config { hostname n2 ! interface eth0 ip address 10.0.0.2/32 ipv6 address a:0::2/128 ! } iconcoords {190.35166313500002 519.524009667} labelcoords {190.35166313500002 547.524009667} canvas c1 interface-peer {eth0 n11} } node n3 { type router model mdr network-config { hostname n3 ! interface eth0 ip address 10.0.0.3/32 ipv6 address a:0::3/128 ! } iconcoords {142.172431565 307.104176223} labelcoords {142.172431565 335.104176223} canvas c1 interface-peer {eth0 n11} } node n4 { type router model mdr network-config { hostname n4 ! interface eth0 ip address 10.0.0.4/32 ipv6 address a:0::4/128 ! } iconcoords {395.031505695 589.805480735} labelcoords {395.031505695 617.805480735} canvas c1 interface-peer {eth0 n11} } node n5 { type router model mdr network-config { hostname n5 ! interface eth0 ip address 10.0.0.5/32 ipv6 address a:0::5/128 ! } iconcoords {250.817758443 27.20735313899999} labelcoords {250.817758443 55.20735313899999} canvas c1 interface-peer {eth0 n11} } node n6 { type router model mdr network-config { hostname n6 ! interface eth0 ip address 10.0.0.6/32 ipv6 address a:0::6/128 ! } iconcoords {757.062318769 61.533941783} labelcoords {757.062318769 89.533941783} canvas c1 interface-peer {eth0 n11} } node n7 { type router model mdr network-config { hostname n7 ! interface eth0 ip address 10.0.0.7/32 ipv6 address a:0::7/128 ! } iconcoords {909.142667152 593.227596061} labelcoords {909.142667152 621.227596061} canvas c1 interface-peer {eth0 n11} } node n8 { type router model mdr network-config { hostname n8 ! interface eth0 ip address 10.0.0.8/32 ipv6 address a:0::8/128 ! } iconcoords {351.895107521 337.228007484} labelcoords {351.895107521 365.228007484} canvas c1 interface-peer {eth0 n11} } node n9 { type router model mdr network-config { hostname n9 ! interface eth0 ip address 10.0.0.9/32 ipv6 address a:0::9/128 ! } iconcoords {528.693178831 84.9814304098} labelcoords {528.693178831 112.98143041} canvas c1 interface-peer {eth0 n11} } node n10 { type router model mdr network-config { hostname n10 ! interface eth0 ip address 10.0.0.10/32 ipv6 address a:0::10/128 ! } iconcoords {568.534639911 526.4682890199999} labelcoords {568.534639911 554.4682890199999} canvas c1 interface-peer {eth0 n11} } node n11 { bandwidth 54000000 type wlan range 275 network-config { hostname wlan11 ! interface wireless ip address 10.0.0.0/32 ipv6 address a:0::0/128 ! mobmodel coreapi emane_ieee80211abg ! } canvas c1 iconcoords {65.0 558.0} labelcoords {65.0 590.0} interface-peer {e0 n1} interface-peer {e1 n2} interface-peer {e2 n3} interface-peer {e3 n4} interface-peer {e4 n5} interface-peer {e5 n6} interface-peer {e6 n7} interface-peer {e7 n8} interface-peer {e8 n9} interface-peer {e9 n10} } link l1 { nodes {n11 n1} bandwidth 54000000 } link l2 { nodes {n11 n2} bandwidth 54000000 } link l3 { nodes {n11 n3} bandwidth 54000000 } link l4 { nodes {n11 n4} bandwidth 54000000 } link l5 { nodes {n11 n5} bandwidth 54000000 } link l6 { nodes {n11 n6} bandwidth 54000000 } link l7 { nodes {n11 n7} bandwidth 54000000 } link l8 { nodes {n11 n8} bandwidth 54000000 } link l9 { nodes {n11 n9} bandwidth 54000000 } link l10 { nodes {n11 n10} bandwidth 54000000 } canvas c1 { name {Canvas1} refpt {0 0 47.5791667 -122.132322 2.0} scale 350.0 size {1000 750} } option global { interface_names no ip_addresses yes ipv6_addresses yes node_labels yes link_labels yes ipsec_configs yes remote_exec no exec_errors yes show_api no background_images no annotations yes grid yes traffic_start 0 } core-4.8/gui/configs/sample8-ipsec-service.imn0000664000175000017500000006362212534327775016321 00000000000000comments { Sample scenario showing IPsec service configuration. There are three red routers having the IPsec service enabled. The IPsec service must be customized with the tunnel hosts (peers) and their keys, and the subnet addresses that should be tunneled. For simplicity, the same keys and certificates are used in each of the three IPsec gateways. These are written to node n1's configuration directory. Keys can be generated using the openssl utility. Note that this scenario may require at patched kernel in order to work; see the kernels subdirectory of the CORE source for kernel patches. The racoon keying daemon and setkey from the ipsec-tools package should also be installed. } node n1 { type router model router network-config { hostname n1 ! interface eth3 ip address 192.168.6.1/24 ipv6 address 2001:6::1/64 ! interface eth2 ip address 192.168.5.1/24 ipv6 address 2001:5::1/64 ! interface eth1 ip address 192.168.1.1/24 ipv6 address 2001:1::1/64 ! interface eth0 ip address 192.168.0.1/24 ipv6 address 2001:0::1/64 ! } canvas c1 iconcoords {210.0 172.0} labelcoords {210.0 200.0} interface-peer {eth0 n2} interface-peer {eth1 n3} interface-peer {eth2 n7} interface-peer {eth3 n8} custom-config { custom-config-id service:IPsec:copycerts.sh custom-command copycerts.sh config { #!/bin/sh FILES="test1.pem test1.key ca-cert.pem" mkdir -p /tmp/certs for f in $FILES; do cp $f /tmp/certs done } } custom-config { custom-config-id service:IPsec:ca-cert.pem custom-command ca-cert.pem config { Certificate: Data: Version: 3 (0x2) Serial Number: 16615976057451940887 (0xe697ce3064d18c17) Signature Algorithm: sha1WithRSAEncryption Issuer: C=US, ST=WA, O=CORE CA/emailAddress=root@localhost Validity Not Before: Sep 9 17:18:04 2013 GMT Not After : Sep 7 17:18:04 2023 GMT Subject: C=US, ST=WA, O=CORE CA/emailAddress=root@localhost Subject Public Key Info: Public Key Algorithm: rsaEncryption Public-Key: (1024 bit) Modulus: 00:d3:0d:ab:91:72:50:ca:10:43:8d:18:d8:92:05: 9d:d9:aa:16:2b:d1:25:f8:be:52:48:e4:e7:7a:83: 9b:b4:3b:26:12:fa:46:23:df:09:cb:34:ba:6f:f6: 5e:38:9c:d4:90:ea:44:ad:65:f6:bd:85:6f:ac:9f: 4c:83:d4:10:ab:0a:0e:cd:ba:99:1a:ae:f7:b7:e2: c3:00:0b:c1:02:69:16:c7:55:e3:cf:4c:c3:72:77: 10:be:da:66:ce:91:b2:cc:92:e1:a8:f0:74:fe:b9: 03:38:fc:49:97:73:bb:40:55:1b:7d:3e:41:63:02: b5:ad:f4:33:95:76:fd:7b:61 Exponent: 65537 (0x10001) X509v3 extensions: X509v3 Subject Key Identifier: 9A:EF:A7:36:28:06:4A:0A:2F:F9:2E:99:BE:6F:06:E1:83:9C:A2:0E X509v3 Authority Key Identifier: keyid:9A:EF:A7:36:28:06:4A:0A:2F:F9:2E:99:BE:6F:06:E1:83:9C:A2:0E X509v3 Basic Constraints: CA:TRUE Signature Algorithm: sha1WithRSAEncryption 2d:88:84:20:19:9b:97:90:2d:18:86:7d:db:6c:d0:5e:ae:c2: 55:61:af:ca:86:5b:3b:e8:15:c5:31:de:ea:d3:7e:9e:39:61: 2e:b4:a0:93:43:bf:a2:95:f8:b6:13:b3:2f:cb:f8:fb:72:8c: 40:95:50:db:03:cc:f7:b8:a5:d8:fb:77:88:c4:f5:f9:65:85: 29:c8:0c:e9:ce:c9:fa:1d:4e:b2:3f:92:dc:b5:2e:73:50:c3: c8:3e:90:9e:9a:34:ef:fd:ed:de:74:0b:19:73:6a:95:de:90: 3b:ee:db:b0:be:14:fd:bf:3e:c6:7b:cd:7d:3c:ba:45:3c:f1: 46:d7 -----BEGIN CERTIFICATE----- MIICZDCCAc2gAwIBAgIJAOaXzjBk0YwXMA0GCSqGSIb3DQEBBQUAMEsxCzAJBgNV BAYTAlVTMQswCQYDVQQIDAJXQTEQMA4GA1UECgwHQ09SRSBDQTEdMBsGCSqGSIb3 DQEJARYOcm9vdEBsb2NhbGhvc3QwHhcNMTMwOTA5MTcxODA0WhcNMjMwOTA3MTcx ODA0WjBLMQswCQYDVQQGEwJVUzELMAkGA1UECAwCV0ExEDAOBgNVBAoMB0NPUkUg Q0ExHTAbBgkqhkiG9w0BCQEWDnJvb3RAbG9jYWxob3N0MIGfMA0GCSqGSIb3DQEB AQUAA4GNADCBiQKBgQDTDauRclDKEEONGNiSBZ3ZqhYr0SX4vlJI5Od6g5u0OyYS +kYj3wnLNLpv9l44nNSQ6kStZfa9hW+sn0yD1BCrCg7Nupkarve34sMAC8ECaRbH VePPTMNydxC+2mbOkbLMkuGo8HT+uQM4/EmXc7tAVRt9PkFjArWt9DOVdv17YQID AQABo1AwTjAdBgNVHQ4EFgQUmu+nNigGSgov+S6Zvm8G4YOcog4wHwYDVR0jBBgw FoAUmu+nNigGSgov+S6Zvm8G4YOcog4wDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0B AQUFAAOBgQAtiIQgGZuXkC0Yhn3bbNBersJVYa/Khls76BXFMd7q036eOWEutKCT Q7+ilfi2E7Mvy/j7coxAlVDbA8z3uKXY+3eIxPX5ZYUpyAzpzsn6HU6yP5LctS5z UMPIPpCemjTv/e3edAsZc2qV3pA77tuwvhT9vz7Ge819PLpFPPFG1w== -----END CERTIFICATE----- } } custom-config { custom-config-id service:IPsec:test1.pem custom-command test1.pem config { Certificate: Data: Version: 3 (0x2) Serial Number: 16098433458223693585 (0xdf691fefe5afbf11) Signature Algorithm: sha1WithRSAEncryption Issuer: C=US, ST=WA, O=CORE CA/emailAddress=root@localhost Validity Not Before: Sep 9 17:44:47 2013 GMT Not After : Sep 7 17:44:47 2023 GMT Subject: C=US, ST=WA, O=core-dev, CN=test1 Subject Public Key Info: Public Key Algorithm: rsaEncryption Public-Key: (1024 bit) Modulus: 00:b3:26:ed:b6:eb:26:ea:c0:5a:d1:09:6f:d4:5f: 8d:11:cc:3c:ff:d7:5e:37:e6:55:71:5c:eb:c9:e8: f8:8e:a3:85:99:2c:3e:a2:8e:b2:1c:2f:fe:99:c6: 0d:d3:ce:c0:ed:c1:e2:4d:bc:10:35:f6:61:02:b9: 8f:cc:c5:80:d1:7f:c8:2e:2d:9a:32:9f:8a:bb:32: ea:14:82:e0:6f:cb:3d:9d:d5:1c:f1:43:52:9f:49: 79:f1:94:03:48:2c:91:51:c7:8f:32:90:a7:c2:c0: 25:64:34:f1:c7:f2:ac:d5:96:87:a2:0a:fb:e5:b3: 0b:90:bf:6f:08:75:5d:54:cb Exponent: 65537 (0x10001) X509v3 extensions: X509v3 Basic Constraints: CA:FALSE Netscape Comment: OpenSSL Generated Certificate X509v3 Subject Key Identifier: B3:EC:1A:56:77:F9:DC:0E:60:0F:B7:69:C9:DC:43:2D:09:39:A6:1C X509v3 Authority Key Identifier: keyid:9A:EF:A7:36:28:06:4A:0A:2F:F9:2E:99:BE:6F:06:E1:83:9C:A2:0E Signature Algorithm: sha1WithRSAEncryption c5:3f:65:1f:b6:a4:33:fd:c8:04:a1:da:07:f6:e0:3b:55:b9: 76:b7:aa:78:55:4a:59:ad:36:7f:cb:00:1c:32:cb:fe:40:72: eb:49:27:b4:9d:5d:05:6f:30:37:1d:49:35:5e:0b:6b:5d:c5: 07:3d:c8:63:1f:b6:46:6d:f9:c9:52:ce:1d:1f:d9:e8:02:46: 95:18:26:39:ec:17:fe:ae:07:cf:55:25:45:1f:8a:e4:bb:f2: 73:d2:e1:01:c3:8e:5f:eb:e4:7e:80:44:40:e6:a1:cd:85:9b: e8:fb:16:d0:7b:4f:ad:3b:4c:eb:bd:67:02:2c:08:2b:62:f1: c5:0a -----BEGIN CERTIFICATE----- MIICgTCCAeqgAwIBAgIJAN9pH+/lr78RMA0GCSqGSIb3DQEBBQUAMEsxCzAJBgNV BAYTAlVTMQswCQYDVQQIDAJXQTEQMA4GA1UECgwHQ09SRSBDQTEdMBsGCSqGSIb3 DQEJARYOcm9vdEBsb2NhbGhvc3QwHhcNMTMwOTA5MTc0NDQ3WhcNMjMwOTA3MTc0 NDQ3WjA9MQswCQYDVQQGEwJVUzELMAkGA1UECAwCV0ExETAPBgNVBAoMCGNvcmUt ZGV2MQ4wDAYDVQQDDAV0ZXN0MTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA sybttusm6sBa0Qlv1F+NEcw8/9deN+ZVcVzryej4jqOFmSw+oo6yHC/+mcYN087A 7cHiTbwQNfZhArmPzMWA0X/ILi2aMp+KuzLqFILgb8s9ndUc8UNSn0l58ZQDSCyR UcePMpCnwsAlZDTxx/Ks1ZaHogr75bMLkL9vCHVdVMsCAwEAAaN7MHkwCQYDVR0T BAIwADAsBglghkgBhvhCAQ0EHxYdT3BlblNTTCBHZW5lcmF0ZWQgQ2VydGlmaWNh dGUwHQYDVR0OBBYEFLPsGlZ3+dwOYA+3acncQy0JOaYcMB8GA1UdIwQYMBaAFJrv pzYoBkoKL/kumb5vBuGDnKIOMA0GCSqGSIb3DQEBBQUAA4GBAMU/ZR+2pDP9yASh 2gf24DtVuXa3qnhVSlmtNn/LABwyy/5AcutJJ7SdXQVvMDcdSTVeC2tdxQc9yGMf tkZt+clSzh0f2egCRpUYJjnsF/6uB89VJUUfiuS78nPS4QHDjl/r5H6AREDmoc2F m+j7FtB7T607TOu9ZwIsCCti8cUK -----END CERTIFICATE----- } } custom-config { custom-config-id service:IPsec:test1.key custom-command test1.key config { -----BEGIN PRIVATE KEY----- MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBALMm7bbrJurAWtEJ b9RfjRHMPP/XXjfmVXFc68no+I6jhZksPqKOshwv/pnGDdPOwO3B4k28EDX2YQK5 j8zFgNF/yC4tmjKfirsy6hSC4G/LPZ3VHPFDUp9JefGUA0gskVHHjzKQp8LAJWQ0 8cfyrNWWh6IK++WzC5C/bwh1XVTLAgMBAAECgYB1zJIgZe04DPVqYC8lURL8cfRm MeIlFZJ3MSdlo4fUmtddCYfB8dxRxok96cnrzRZ0/7jjblamdPQDC6rvdaqmfLFx nJ/RVhCj6HqDMrQnv/9tnl6UQmkaYSnYvTn2GgmpqvBf9RUQk4+kjwgRgdqKxaIz oH8j0ZxMh2DOZuzJMQJBAOJwEnbG085q2k1Qg8PQz0cpVG9QCE3sJUNs0hMPC7dk IzknFtidlpCf6NMboJ2Nt9dzmJmKLqWb3oauyQRQA6MCQQDKin0wElLV1268IbcF RXhkVlxcg5fDEazeNL9p1z5vmwaq0IcLtSPrIaect2hacCkfJoREhcA+f9YIpcod lby5AkEApyXla0ofpXqYxIOPkGc96qCmlDh2uNZ9N0VH2Qu9MVW47oJdSe8h6oYv /k2hhUvMjjzlQ0mOX28slyzEc+uAkwJAWlAsiE3zX+UjPIJwIMqcZ2lW3+3Rsyrj gWXV4HUZIxzmeS5ouWC5NnSYT7o8ru8KdxhurDtTwMqx/sMmf9CwCQJAIDbMwwIs XStw0y/M9+hdPUkccVoHyXKPTensyX/miAUwHZN/oadGUUOZO7XBKb1uNFv1uowU 29bGgXa+mvb6aA== -----END PRIVATE KEY----- } } custom-config { custom-config-id service:IPsec:ipsec.sh custom-command ipsec.sh config { #!/bin/sh # set up static tunnel mode security assocation for service (security.py) # -------- CUSTOMIZATION REQUIRED -------- # # The IPsec service builds ESP tunnels between the specified peers using the # racoon IKEv2 keying daemon. You need to provide keys and the addresses of # peers, along with subnets to tunnel. # directory containing the certificate and key described below keydir=/tmp/certs # the name used for the "$certname.pem" x509 certificate and # "$certname.key" RSA private key, which can be generated using openssl certname=test1 # list the public-facing IP addresses, starting with the localhost and followed # by each tunnel peer, separated with a single space tunnelhosts="192.168.0.1AND192.168.0.2 192.168.1.1AND192.168.1.2" # Define T where i is the index for each tunnel peer host from # the tunnel_hosts list above (0 is localhost). # T is a list of IPsec tunnels with peer i, with a local subnet address # followed by the remote subnet address: # T="AND AND" # For example, 192.168.0.0/24 is a local network (behind this node) to be # tunneled and 192.168.2.0/24 is a remote network (behind peer 1) T1="192.168.5.0/24AND192.168.8.0/24" T2="192.168.5.0/24AND192.168.4.0/24 192.168.6.0/24AND192.168.4.0/24" # -------- END CUSTOMIZATION -------- echo "building config $PWD/ipsec.conf..." echo "building config $PWD/ipsec.conf..." > $PWD/ipsec.log checkip=0 if [ "$(dpkg -l | grep " sipcalc ")" = "" ]; then echo "WARNING: ip validation disabled because package sipcalc not installed " >> $PWD/ipsec.log checkip=1 fi echo "#!/usr/sbin/setkey -f # Flush the SAD and SPD flush; spdflush; # Security policies \ " > $PWD/ipsec.conf i=0 for hostpair in $tunnelhosts; do i=`expr $i + 1` # parse tunnel host IP thishost=${hostpair%%AND*} peerhost=${hostpair##*AND} if [ $checkip = "0" ] && [ "$(sipcalc "$thishost" "$peerhost" | grep ERR)" != "" ]; then echo "ERROR: invalid host address $thishost or $peerhost \ " >> $PWD/ipsec.log fi # parse each tunnel addresses tunnel_list_var_name=T$i eval tunnels="$"$tunnel_list_var_name"" for ttunnel in $tunnels; do lclnet=${ttunnel%%AND*} rmtnet=${ttunnel##*AND} if [ $checkip = "0" ] && [ "$(sipcalc "$lclnet" "$rmtnet"| grep ERR)" != "" ]; then echo "ERROR: invalid tunnel address $lclnet and $rmtnet \ " >> $PWD/ipsec.log fi # add tunnel policies echo " spdadd $lclnet $rmtnet any -P out ipsec esp/tunnel/$thishost-$peerhost/require; spdadd $rmtnet $lclnet any -P in ipsec esp/tunnel/$peerhost-$thishost/require; \ " >> $PWD/ipsec.conf done done echo "building config $PWD/racoon.conf..." if [ ! -e $keydir\/$certname.key ] || [ ! -e $keydir\/$certname.pem ]; then echo "ERROR: missing certification files under $keydir \ $certname.key or $certname.pem " >> $PWD/ipsec.log fi echo " path certificate \"$keydir\"; listen { adminsock disabled; } remote anonymous { exchange_mode main; certificate_type x509 \"$certname.pem\" \"$certname.key\"; ca_type x509 \"ca-cert.pem\"; my_identifier asn1dn; peers_identifier asn1dn; proposal { encryption_algorithm 3des ; hash_algorithm sha1; authentication_method rsasig ; dh_group modp768; } } sainfo anonymous { pfs_group modp768; lifetime time 1 hour ; encryption_algorithm 3des, blowfish 448, rijndael ; authentication_algorithm hmac_sha1, hmac_md5 ; compression_algorithm deflate ; } " > $PWD/racoon.conf # the setkey program is required from the ipsec-tools package echo "running setkey -f $PWD/ipsec.conf..." setkey -f $PWD/ipsec.conf echo "running racoon -d -f $PWD/racoon.conf..." racoon -d -f $PWD/racoon.conf -l racoon.log } } custom-config { custom-config-id service:IPsec custom-command IPsec config { ('ipsec.sh', 'test1.key', 'test1.pem', 'ca-cert.pem', 'copycerts.sh', ) 60 ('sh copycerts.sh', 'sh ipsec.sh', ) ('killall racoon', ) } } services {zebra OSPFv2 OSPFv3 vtysh IPForward IPsec} custom-image $CORE_DATA_DIR/icons/normal/router_red.gif } node n2 { type router model router network-config { hostname n2 ! interface eth3 ip address 192.168.8.1/24 ipv6 address 2001:8::1/64 ! interface eth2 ip address 192.168.7.1/24 ipv6 address 2001:7::1/64 ! interface eth1 ip address 192.168.2.1/24 ipv6 address 2001:2::1/64 ! interface eth0 ip address 192.168.0.2/24 ipv6 address 2001:0::2/64 ! } canvas c1 iconcoords {455.0 173.0} labelcoords {455.0 201.0} interface-peer {eth0 n1} interface-peer {eth1 n4} interface-peer {eth2 n9} interface-peer {eth3 n10} custom-config { custom-config-id service:IPsec:ipsec.sh custom-command ipsec.sh config { #!/bin/sh # set up static tunnel mode security assocation for service (security.py) # -------- CUSTOMIZATION REQUIRED -------- # # The IPsec service builds ESP tunnels between the specified peers using the # racoon IKEv2 keying daemon. You need to provide keys and the addresses of # peers, along with subnets to tunnel. # directory containing the certificate and key described below keydir=/tmp/certs # the name used for the "$certname.pem" x509 certificate and # "$certname.key" RSA private key, which can be generated using openssl certname=test1 # list the public-facing IP addresses, starting with the localhost and followed # by each tunnel peer, separated with a single space tunnelhosts="192.168.0.2AND192.168.0.1" # Define T where i is the index for each tunnel peer host from # the tunnel_hosts list above (0 is localhost). # T is a list of IPsec tunnels with peer i, with a local subnet address # followed by the remote subnet address: # T="AND AND" # For example, 192.168.0.0/24 is a local network (behind this node) to be # tunneled and 192.168.2.0/24 is a remote network (behind peer 1) T1="192.168.8.0/24AND192.168.5.0/24" # -------- END CUSTOMIZATION -------- echo "building config $PWD/ipsec.conf..." echo "building config $PWD/ipsec.conf..." > $PWD/ipsec.log checkip=0 if [ "$(dpkg -l | grep " sipcalc ")" = "" ]; then echo "WARNING: ip validation disabled because package sipcalc not installed " >> $PWD/ipsec.log checkip=1 fi echo "#!/usr/sbin/setkey -f # Flush the SAD and SPD flush; spdflush; # Security policies \ " > $PWD/ipsec.conf i=0 for hostpair in $tunnelhosts; do i=`expr $i + 1` # parse tunnel host IP thishost=${hostpair%%AND*} peerhost=${hostpair##*AND} if [ $checkip = "0" ] && [ "$(sipcalc "$thishost" "$peerhost" | grep ERR)" != "" ]; then echo "ERROR: invalid host address $thishost or $peerhost \ " >> $PWD/ipsec.log fi # parse each tunnel addresses tunnel_list_var_name=T$i eval tunnels="$"$tunnel_list_var_name"" for ttunnel in $tunnels; do lclnet=${ttunnel%%AND*} rmtnet=${ttunnel##*AND} if [ $checkip = "0" ] && [ "$(sipcalc "$lclnet" "$rmtnet"| grep ERR)" != "" ]; then echo "ERROR: invalid tunnel address $lclnet and $rmtnet \ " >> $PWD/ipsec.log fi # add tunnel policies echo " spdadd $lclnet $rmtnet any -P out ipsec esp/tunnel/$thishost-$peerhost/require; spdadd $rmtnet $lclnet any -P in ipsec esp/tunnel/$peerhost-$thishost/require; \ " >> $PWD/ipsec.conf done done echo "building config $PWD/racoon.conf..." if [ ! -e $keydir\/$certname.key ] || [ ! -e $keydir\/$certname.pem ]; then echo "ERROR: missing certification files under $keydir \ $certname.key or $certname.pem " >> $PWD/ipsec.log fi echo " path certificate \"$keydir\"; listen { adminsock disabled; } remote anonymous { exchange_mode main; certificate_type x509 \"$certname.pem\" \"$certname.key\"; ca_type x509 \"ca-cert.pem\"; my_identifier asn1dn; peers_identifier asn1dn; proposal { encryption_algorithm 3des ; hash_algorithm sha1; authentication_method rsasig ; dh_group modp768; } } sainfo anonymous { pfs_group modp768; lifetime time 1 hour ; encryption_algorithm 3des, blowfish 448, rijndael ; authentication_algorithm hmac_sha1, hmac_md5 ; compression_algorithm deflate ; } " > $PWD/racoon.conf # the setkey program is required from the ipsec-tools package echo "running setkey -f $PWD/ipsec.conf..." setkey -f $PWD/ipsec.conf echo "running racoon -d -f $PWD/racoon.conf..." racoon -d -f $PWD/racoon.conf -l racoon.log } } custom-config { custom-config-id service:IPsec custom-command IPsec config { ('ipsec.sh', ) 60 ('sh ipsec.sh', ) ('killall racoon', ) } } services {zebra OSPFv2 OSPFv3 vtysh IPForward IPsec} custom-image $CORE_DATA_DIR/icons/normal/router_red.gif } node n3 { type router model router network-config { hostname n3 ! interface eth2 ip address 192.168.4.1/24 ipv6 address 2001:4::1/64 ! interface eth1 ip address 192.168.3.1/24 ipv6 address 2001:3::1/64 ! interface eth0 ip address 192.168.1.2/24 ipv6 address 2001:1::2/64 ! } canvas c1 iconcoords {211.0 375.0} labelcoords {211.0 403.0} interface-peer {eth0 n1} interface-peer {eth1 n5} interface-peer {eth2 n6} custom-config { custom-config-id service:IPsec:ipsec.sh custom-command ipsec.sh config { #!/bin/sh # set up static tunnel mode security assocation for service (security.py) # -------- CUSTOMIZATION REQUIRED -------- # # The IPsec service builds ESP tunnels between the specified peers using the # racoon IKEv2 keying daemon. You need to provide keys and the addresses of # peers, along with subnets to tunnel. # directory containing the certificate and key described below keydir=/tmp/certs # the name used for the "$certname.pem" x509 certificate and # "$certname.key" RSA private key, which can be generated using openssl certname=test1 # list the public-facing IP addresses, starting with the localhost and followed # by each tunnel peer, separated with a single space tunnelhosts="192.168.1.2AND192.168.1.1" # Define T where i is the index for each tunnel peer host from # the tunnel_hosts list above (0 is localhost). # T is a list of IPsec tunnels with peer i, with a local subnet address # followed by the remote subnet address: # T="AND AND" # For example, 192.168.0.0/24 is a local network (behind this node) to be # tunneled and 192.168.2.0/24 is a remote network (behind peer 1) T1="192.168.4.0/24AND192.168.5.0/24 192.168.4.0/24AND192.168.6.0/24" # -------- END CUSTOMIZATION -------- echo "building config $PWD/ipsec.conf..." echo "building config $PWD/ipsec.conf..." > $PWD/ipsec.log checkip=0 if [ "$(dpkg -l | grep " sipcalc ")" = "" ]; then echo "WARNING: ip validation disabled because package sipcalc not installed " >> $PWD/ipsec.log checkip=1 fi echo "#!/usr/sbin/setkey -f # Flush the SAD and SPD flush; spdflush; # Security policies \ " > $PWD/ipsec.conf i=0 for hostpair in $tunnelhosts; do i=`expr $i + 1` # parse tunnel host IP thishost=${hostpair%%AND*} peerhost=${hostpair##*AND} if [ $checkip = "0" ] && [ "$(sipcalc "$thishost" "$peerhost" | grep ERR)" != "" ]; then echo "ERROR: invalid host address $thishost or $peerhost \ " >> $PWD/ipsec.log fi # parse each tunnel addresses tunnel_list_var_name=T$i eval tunnels="$"$tunnel_list_var_name"" for ttunnel in $tunnels; do lclnet=${ttunnel%%AND*} rmtnet=${ttunnel##*AND} if [ $checkip = "0" ] && [ "$(sipcalc "$lclnet" "$rmtnet"| grep ERR)" != "" ]; then echo "ERROR: invalid tunnel address $lclnet and $rmtnet \ " >> $PWD/ipsec.log fi # add tunnel policies echo " spdadd $lclnet $rmtnet any -P out ipsec esp/tunnel/$thishost-$peerhost/require; spdadd $rmtnet $lclnet any -P in ipsec esp/tunnel/$peerhost-$thishost/require; \ " >> $PWD/ipsec.conf done done echo "building config $PWD/racoon.conf..." if [ ! -e $keydir\/$certname.key ] || [ ! -e $keydir\/$certname.pem ]; then echo "ERROR: missing certification files under $keydir \ $certname.key or $certname.pem " >> $PWD/ipsec.log fi echo " path certificate \"$keydir\"; listen { adminsock disabled; } remote anonymous { exchange_mode main; certificate_type x509 \"$certname.pem\" \"$certname.key\"; ca_type x509 \"ca-cert.pem\"; my_identifier asn1dn; peers_identifier asn1dn; proposal { encryption_algorithm 3des ; hash_algorithm sha1; authentication_method rsasig ; dh_group modp768; } } sainfo anonymous { pfs_group modp768; lifetime time 1 hour ; encryption_algorithm 3des, blowfish 448, rijndael ; authentication_algorithm hmac_sha1, hmac_md5 ; compression_algorithm deflate ; } " > $PWD/racoon.conf # the setkey program is required from the ipsec-tools package echo "running setkey -f $PWD/ipsec.conf..." setkey -f $PWD/ipsec.conf echo "running racoon -d -f $PWD/racoon.conf..." racoon -d -f $PWD/racoon.conf -l racoon.log } } custom-config { custom-config-id service:IPsec custom-command IPsec config { ('ipsec.sh', ) 60 ('sh ipsec.sh', ) ('killall racoon', ) } } services {zebra OSPFv2 OSPFv3 vtysh IPForward IPsec} custom-image $CORE_DATA_DIR/icons/normal/router_red.gif } node n4 { type router model router network-config { hostname n4 ! interface eth1 ip address 192.168.9.1/24 ipv6 address 2001:9::1/64 ! interface eth0 ip address 192.168.2.2/24 ipv6 address 2001:2::2/64 ! } canvas c1 iconcoords {456.0 376.0} labelcoords {456.0 404.0} interface-peer {eth0 n2} interface-peer {eth1 n11} } node n5 { type router model host network-config { hostname n5 ! interface eth0 ip address 192.168.3.10/24 ipv6 address 2001:3::10/64 ! } canvas c1 iconcoords {50.0 472.0} labelcoords {50.0 504.0} interface-peer {eth0 n3} } node n6 { type router model host network-config { hostname n6 ! interface eth0 ip address 192.168.4.10/24 ipv6 address 2001:4::10/64 ! } canvas c1 iconcoords {44.0 292.0} labelcoords {44.0 324.0} interface-peer {eth0 n3} } node n7 { type router model host network-config { hostname n7 ! interface eth0 ip address 192.168.5.10/24 ipv6 address 2001:5::10/64 ! } canvas c1 iconcoords {41.0 62.0} labelcoords {41.0 94.0} interface-peer {eth0 n1} } node n8 { type router model host network-config { hostname n8 ! interface eth0 ip address 192.168.6.10/24 ipv6 address 2001:6::10/64 ! } canvas c1 iconcoords {39.0 121.0} labelcoords {39.0 153.0} interface-peer {eth0 n1} } node n9 { type router model host network-config { hostname n9 ! interface eth0 ip address 192.168.7.10/24 ipv6 address 2001:7::10/64 ! } canvas c1 iconcoords {653.0 69.0} labelcoords {653.0 101.0} interface-peer {eth0 n2} } node n10 { type router model host network-config { hostname n10 ! interface eth0 ip address 192.168.8.10/24 ipv6 address 2001:8::10/64 ! } canvas c1 iconcoords {454.0 48.0} labelcoords {484.0 59.0} interface-peer {eth0 n2} } node n11 { type router model host network-config { hostname n11 ! interface eth0 ip address 192.168.9.10/24 ipv6 address 2001:9::10/64 ! } canvas c1 iconcoords {654.0 460.0} labelcoords {654.0 492.0} interface-peer {eth0 n4} } link l1 { nodes {n1 n2} bandwidth 0 } link l2 { nodes {n1 n3} bandwidth 0 } link l3 { nodes {n2 n4} bandwidth 0 } link l4 { nodes {n3 n5} bandwidth 0 } link l5 { nodes {n3 n6} bandwidth 0 } link l6 { nodes {n1 n7} bandwidth 0 } link l7 { nodes {n1 n8} bandwidth 0 } link l8 { nodes {n2 n9} bandwidth 0 } link l9 { nodes {n2 n10} bandwidth 0 } link l10 { nodes {n4 n11} bandwidth 0 } annotation a1 { iconcoords {8.0 6.0 514.0 99.0} type rectangle label {Tunnel 1} labelcolor black fontfamily {Arial} fontsize {12} color #ffd0d0 width 0 border #00ff00 rad 22 canvas c1 } annotation a2 { iconcoords {8.0 6.0 137.0 334.0} type rectangle label {Tunnel 2} labelcolor black fontfamily {Arial} fontsize {12} color #ffe1e1 width 0 border black rad 23 canvas c1 } annotation a5 { iconcoords {263.0 127.0} type text label {} labelcolor black fontfamily {Arial} fontsize {12} effects {underline} canvas c1 } canvas c1 { name {Canvas1} } option global { interface_names yes ip_addresses yes ipv6_addresses no node_labels yes link_labels yes ipsec_configs yes exec_errors yes show_api no background_images no annotations yes grid yes traffic_start 0 } core-4.8/gui/configs/sample9-vpn.imn0000664000175000017500000011025412534327775014356 00000000000000comments { Sample scenario showing VPNClient and VPNServer service configuration. This topology features an OpenVPN client and server for virtual private networking. The client can access the private 10.0.6.0/24 network via the VPN server. First wait until routing converges in the center routers (try using the Adjacency Widget and wait for blue lines, meaning full adjacencies), then open a shell on the vpnclient and try pinging the private address of the vpnserver: vpnclient> ping 10.0.6.1 You can also access the other 10.0.6.* hosts behind the server. Try running tcpudmp on one of the center routers, e.g. the n2 eth1/10.0.5.2 interface, and you'll see UDP packets with TLS encrypted data instead of ICMP packets. Keys are included as extra files in the VPNClient and VPNServer service configuration. } node n1 { type router model router network-config { hostname n1 ! interface eth2 ip address 10.0.4.2/24 ipv6 address 2001:4::2/64 ! interface eth1 ip address 10.0.2.1/24 ipv6 address 2001:2::1/64 ! interface eth0 ip address 10.0.0.1/24 ipv6 address 2001:0::1/64 ! } canvas c1 iconcoords {297.0 236.0} labelcoords {297.0 264.0} interface-peer {eth0 n6} interface-peer {eth1 n2} interface-peer {eth2 n3} } node n2 { type router model router network-config { hostname n2 ! interface eth1 ip address 10.0.5.2/24 ipv6 address 2001:5::2/64 ! interface eth0 ip address 10.0.2.2/24 ipv6 address 2001:2::2/64 ! } canvas c1 iconcoords {298.0 432.0} labelcoords {298.0 460.0} interface-peer {eth0 n1} interface-peer {eth1 n4} } node n3 { type router model router network-config { hostname n3 ! interface eth1 ip address 10.0.4.1/24 ipv6 address 2001:4::1/64 ! interface eth0 ip address 10.0.3.1/24 ipv6 address 2001:3::1/64 ! } canvas c1 iconcoords {573.0 233.0} labelcoords {573.0 261.0} interface-peer {eth0 n4} interface-peer {eth1 n1} } node n4 { type router model router network-config { hostname n4 ! interface eth2 ip address 10.0.5.1/24 ipv6 address 2001:5::1/64 ! interface eth1 ip address 10.0.3.2/24 ipv6 address 2001:3::2/64 ! interface eth0 ip address 10.0.1.1/24 ipv6 address 2001:1::1/64 ! } canvas c1 iconcoords {574.0 429.0} labelcoords {574.0 457.0} interface-peer {eth0 n5} interface-peer {eth1 n3} interface-peer {eth2 n2} } node n5 { type router model host network-config { hostname vpnserver ! interface eth1 ipv6 address 2001:6::10/64 ip address 10.0.6.1/24 ! interface eth0 ip address 10.0.1.10/24 ipv6 address 2001:1::10/64 ! } canvas c1 iconcoords {726.0 511.0} labelcoords {726.0 543.0} interface-peer {eth0 n4} interface-peer {eth1 n7} custom-config { custom-config-id service:VPNServer:vpnserver.pem custom-command vpnserver.pem config { Certificate: Data: Version: 3 (0x2) Serial Number: 1 (0x1) Signature Algorithm: sha256WithRSAEncryption Issuer: C=US, ST=WA, O=core-dev/emailAddress=root@localhost Validity Not Before: May 19 02:09:57 2015 GMT Not After : Apr 25 02:09:57 2115 GMT Subject: C=US, ST=WA, O=core-dev, CN=vpnserver/emailAddress=root@localhost Subject Public Key Info: Public Key Algorithm: rsaEncryption Public-Key: (2048 bit) Modulus: 00:d2:88:b2:9b:32:ac:38:ca:45:e0:6b:db:1c:92: 5d:9a:42:23:df:64:a0:3b:c2:c4:f2:3a:75:bb:d6: 54:12:61:6e:aa:ac:0f:a6:2e:d9:3b:63:dc:3d:48: 02:f1:36:c8:97:d3:ef:24:6f:7f:dd:b7:9a:9d:6d: c1:c9:e2:11:49:1c:e0:67:d6:b0:b7:62:84:9a:f8: c3:af:4f:f7:77:29:74:01:81:47:49:84:d6:1c:0c: 36:41:42:a2:3e:92:28:83:50:7a:9c:fd:f3:66:7c: f8:d9:c7:f6:63:d2:59:d2:fd:9a:a4:9b:75:a6:16: ec:37:de:05:dd:05:a2:31:65:79:66:eb:b3:82:41: af:b9:e8:4a:bc:02:d6:a1:68:49:6c:09:e1:c5:9f: 3e:cf:52:76:d9:63:65:7a:a5:34:75:ee:ce:a3:c6: 92:f3:0d:2f:7f:b0:b4:12:fe:44:5f:77:10:25:98: b2:45:af:69:c8:9b:13:fc:f9:de:c6:be:b5:cf:62: 06:01:32:71:d5:84:1d:14:b9:28:46:80:f6:98:35: 12:e4:c8:e4:7a:94:e5:99:a3:6b:34:de:be:33:fe: 63:21:a3:cc:c4:64:15:49:e0:9d:57:84:b9:11:e5: 05:79:ba:22:6e:e4:24:b0:64:f0:54:13:1a:f4:73: 8a:ff Exponent: 65537 (0x10001) X509v3 extensions: X509v3 Basic Constraints: CA:FALSE Netscape Cert Type: SSL Server Netscape Comment: OpenSSL Generated Server Certificate X509v3 Subject Key Identifier: A5:A6:80:4D:3C:CD:E2:FE:AD:32:FD:9D:B2:7C:B6:00:76:16:C0:41 X509v3 Authority Key Identifier: keyid:DB:D2:9C:8D:22:D9:D7:E2:38:A0:8D:6C:3B:BE:33:CE:8D:2A:BE:C8 DirName:/C=US/ST=WA/O=core-dev/emailAddress=root@localhost serial:CE:78:96:91:DB:9B:84:FD X509v3 Extended Key Usage: TLS Web Server Authentication X509v3 Key Usage: Digital Signature, Key Encipherment Signature Algorithm: sha256WithRSAEncryption 3b:40:af:3a:c0:95:10:bc:d4:63:4a:1b:0f:9d:af:9c:27:29: 34:c9:80:dc:c2:2d:72:40:0e:50:15:fe:b4:87:bc:59:56:de: 81:96:1f:4f:ec:1a:44:ce:23:ba:69:b1:f5:ed:4b:1a:22:cf: 16:17:29:f9:bb:69:12:3c:42:87:09:48:26:a2:b3:88:40:3e: 3c:06:92:e1:65:6e:c0:62:50:55:08:5d:a0:4b:3a:0f:ff:9d: 65:91:b9:bf:d3:69:b9:ac:27:83:2c:fd:5a:bd:58:d3:75:a0: 70:e6:21:e9:f0:0d:19:a6:5f:2b:2d:1f:c9:fb:72:73:06:40: 32:5a:f8:81:30:59:b7:cb:3a:a7:3e:6f:af:4c:4b:57:eb:4a: d8:24:65:13:c3:86:fd:35:d3:6d:a0:3a:4b:63:40:9e:b4:98: e0:a2:c7:f2:71:42:d5:08:72:95:fd:df:8f:05:e9:68:a8:f8: 13:db:e6:0a:ec:c2:df:29:65:33:52:57:52:e5:7e:1d:09:2c: 56:0b:cc:d3:2d:dd:46:72:f0:cb:8b:2d:53:c4:d3:9d:63:a6: 6e:9f:dd:1a:7c:b2:87:d1:9e:4e:a0:b2:36:85:4a:5e:89:f9: 01:82:94:3d:3a:86:17:84:48:d4:0c:c4:25:25:54:3f:d7:65: 6b:85:c2:44:b3:6a:f5:74:69:f4:be:b2:13:68:a0:99:82:88: 07:23:8e:a3:67:e0:88:07:fe:fd:ba:85:f8:8a:1f:ac:1e:7d: ac:1e:f9:d1:3d:a8:fd:d9:91:9e:b2:3d:4f:f1:b4:80:9e:0b: aa:bb:44:6a:20:08:68:a4:45:0e:21:21:4d:d1:5f:ab:a8:96: 5a:29:e1:0f:9a:ff:a4:58:c6:80:15:51:98:ac:3c:23:4e:9e: 8f:a2:34:c1:f6:4c:26:f0:33:8d:db:15:b9:30:03:a7:b3:17: 31:9f:9a:5a:e7:a1:10:5e:61:57:04:bf:9a:6f:ec:87:15:4e: 33:2a:0c:e4:4a:b0:66:ab:04:7a:32:4d:66:44:af:d9:ad:41: a9:b1:05:c4:7d:2a:ba:2b:bb:c9:1e:5a:ff:cd:e0:e3:54:39: b6:be:e2:70:6c:db:e6:71:dc:27:7e:ef:e9:11:1f:cb:fa:cd: e1:57:a9:b9:ba:d6:69:fc:c0:d7:57:b0:51:4d:c4:2a:2f:1b: 99:fc:b7:65:11:99:fe:0b:58:4e:11:aa:06:c6:e1:53:20:c7: 56:0a:de:a6:65:c1:a6:41:e1:7b:1d:d7:17:45:b0:e4:66:50: 26:d8:85:c3:c3:93:2d:df:b0:35:6d:29:9a:6b:cc:cc:75:de: cf:72:37:8b:2d:24:b2:45 -----BEGIN CERTIFICATE----- MIIFQTCCAymgAwIBAgIBATANBgkqhkiG9w0BAQsFADBMMQswCQYDVQQGEwJVUzEL MAkGA1UECBMCV0ExETAPBgNVBAoTCGNvcmUtZGV2MR0wGwYJKoZIhvcNAQkBFg5y b290QGxvY2FsaG9zdDAgFw0xNTA1MTkwMjA5NTdaGA8yMTE1MDQyNTAyMDk1N1ow YDELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAldBMREwDwYDVQQKEwhjb3JlLWRldjES MBAGA1UEAxMJdnBuc2VydmVyMR0wGwYJKoZIhvcNAQkBFg5yb290QGxvY2FsaG9z dDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANKIspsyrDjKReBr2xyS XZpCI99koDvCxPI6dbvWVBJhbqqsD6Yu2Ttj3D1IAvE2yJfT7yRvf923mp1twcni EUkc4GfWsLdihJr4w69P93cpdAGBR0mE1hwMNkFCoj6SKINQepz982Z8+NnH9mPS WdL9mqSbdaYW7DfeBd0FojFleWbrs4JBr7noSrwC1qFoSWwJ4cWfPs9SdtljZXql NHXuzqPGkvMNL3+wtBL+RF93ECWYskWvacibE/z53sa+tc9iBgEycdWEHRS5KEaA 9pg1EuTI5HqU5ZmjazTevjP+YyGjzMRkFUngnVeEuRHlBXm6Im7kJLBk8FQTGvRz iv8CAwEAAaOCARYwggESMAkGA1UdEwQCMAAwEQYJYIZIAYb4QgEBBAQDAgZAMDMG CWCGSAGG+EIBDQQmFiRPcGVuU1NMIEdlbmVyYXRlZCBTZXJ2ZXIgQ2VydGlmaWNh dGUwHQYDVR0OBBYEFKWmgE08zeL+rTL9nbJ8tgB2FsBBMHwGA1UdIwR1MHOAFNvS nI0i2dfiOKCNbDu+M86NKr7IoVCkTjBMMQswCQYDVQQGEwJVUzELMAkGA1UECBMC V0ExETAPBgNVBAoTCGNvcmUtZGV2MR0wGwYJKoZIhvcNAQkBFg5yb290QGxvY2Fs aG9zdIIJAM54lpHbm4T9MBMGA1UdJQQMMAoGCCsGAQUFBwMBMAsGA1UdDwQEAwIF oDANBgkqhkiG9w0BAQsFAAOCAgEAO0CvOsCVELzUY0obD52vnCcpNMmA3MItckAO UBX+tIe8WVbegZYfT+waRM4jummx9e1LGiLPFhcp+btpEjxChwlIJqKziEA+PAaS 4WVuwGJQVQhdoEs6D/+dZZG5v9Npuawngyz9Wr1Y03WgcOYh6fANGaZfKy0fyfty cwZAMlr4gTBZt8s6pz5vr0xLV+tK2CRlE8OG/TXTbaA6S2NAnrSY4KLH8nFC1Qhy lf3fjwXpaKj4E9vmCuzC3yllM1JXUuV+HQksVgvM0y3dRnLwy4stU8TTnWOmbp/d Gnyyh9GeTqCyNoVKXon5AYKUPTqGF4RI1AzEJSVUP9dla4XCRLNq9XRp9L6yE2ig mYKIByOOo2fgiAf+/bqF+IofrB59rB750T2o/dmRnrI9T/G0gJ4LqrtEaiAIaKRF DiEhTdFfq6iWWinhD5r/pFjGgBVRmKw8I06ej6I0wfZMJvAzjdsVuTADp7MXMZ+a WuehEF5hVwS/mm/shxVOMyoM5EqwZqsEejJNZkSv2a1BqbEFxH0quiu7yR5a/83g 41Q5tr7icGzb5nHcJ37v6REfy/rN4VepubrWafzA11ewUU3EKi8bmfy3ZRGZ/gtY ThGqBsbhUyDHVgrepmXBpkHhex3XF0Ww5GZQJtiFw8OTLd+wNW0pmmvMzHXez3I3 iy0kskU= -----END CERTIFICATE----- } } custom-config { custom-config-id service:VPNServer:vpnserver.key custom-command vpnserver.key config { -----BEGIN PRIVATE KEY----- MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDSiLKbMqw4ykXg a9sckl2aQiPfZKA7wsTyOnW71lQSYW6qrA+mLtk7Y9w9SALxNsiX0+8kb3/dt5qd bcHJ4hFJHOBn1rC3YoSa+MOvT/d3KXQBgUdJhNYcDDZBQqI+kiiDUHqc/fNmfPjZ x/Zj0lnS/Zqkm3WmFuw33gXdBaIxZXlm67OCQa+56Eq8AtahaElsCeHFnz7PUnbZ Y2V6pTR17s6jxpLzDS9/sLQS/kRfdxAlmLJFr2nImxP8+d7GvrXPYgYBMnHVhB0U uShGgPaYNRLkyOR6lOWZo2s03r4z/mMho8zEZBVJ4J1XhLkR5QV5uiJu5CSwZPBU Exr0c4r/AgMBAAECggEATaktMUC09NHwisNedSCstI13TB2DWegT3EKiUWLTamBU gVKtByE68sR4ZoacxzvtLMx555fVtATZXP8yv/TLaYvkX4l7cHo/7iabkJzP7T32 U+PLVxxQGtKKZPJehPRHS4ExaZ3n3kN1TGiNw+7BQapZFCVgdZ75DfaxdQFx/gQD 4htDr7SZL/jG1Sn08Cf7DRQ9U0rISecmm9nG9LV1LXMfnbdWTwvmm/z0a6wjDZ4n Byfd5jOOI4cpgetHhAQCH+ksComY0GBf21MOsfQT/NzfuW/KFGag992Yub8tBUFa AG+SlaNZBiLAPYfMegjCxR1jZeUCthlB2kdzYKcmyQKBgQD4lgbktGO/VKjnKnGD SR8oJT82HvkfB16M/pSlTNOTmAAbbY9yMNj/zKPJDOhxHLhFxmXqVnvs70Ye+pfT 3o3v0NkAfdIhzNzqbFlUA15QqELhrXHaTtpU3/nyw+/lQhoiEof9yj9vuGBy4iDf GdP1R8G7OWqJIDXwZd3s99XujQKBgQDY0CPvCe1j43wfG8MjI/bLeDWmxjGaLWJu IKbMepEbqcaz9x+25Ey3E35DYtfLjeAQ+qRc5T4Cj6L9iG/mS89/ShPGj91xyFzQ qoZf4lGB0/A80aTgmDiF4FxHFzWpXKaJPS1gTfWZ9Qs7r0LP8Uwni9dhO8LGPNAr 9Ky3jaHyuwKBgQDxml74yZpoyw+eHVJWFyuBCTJ2l4Po9HCg+I3gWtsICCOShNl2 UqOVen91WGZSCWfP6RQEvimUDrpIQaZu9U9eVc2S/LbOwx2zebsYPG3eVqsqTDjr xNfOxiFYIbd3Ste7ZedmcrtVCg4zmjP4olGvgx53qUYyIGxMSbV4KyhxwQKBgQCQ ba7SSLGrrdl8O5k1Knr3tb8/tp1KUFtWc0fJxQgu/lzQe5nT0qdL+Z9NsmWAQqV1 ihG9lDRHrnlsHNw19GBoMeeUiTeB2XACzOWwr+mN66oISbtkpeJZREkUTmC/zmld 2LQGiEhIY9U00B5YuSv62AwEyLOKLO6bqWT47U9piwKBgQDm2+ufGU+ZBr0qpyCf TiZFngJ1fGK0tyVrERm1y83vWzbqaW9nX5hJilqYDB3jpHARvbY56+jWVSm4ADwG dlqEpmPHBgDRYBkdLUl50TN5vINcXQCGlA0zOHAueAUESyL5nLnO7NsK/McSRDd5 XonR43XumudHzs3R6BwBTKv1gw== -----END PRIVATE KEY----- } } custom-config { custom-config-id service:VPNServer:vpnserver.sh custom-command vpnserver.sh config { #!/bin/sh # custom VPN Server Configuration for service (security.py) # -------- CUSTOMIZATION REQUIRED -------- # # The VPNServer service sets up the OpenVPN server for building VPN tunnels # that allow access via TUN/TAP device to private networks. # # note that the IPForward and DefaultRoute services should be enabled # directory containing the certificate and key described below, in addition to # a CA certificate and DH key certdir=$SESSION_DIR/certs keydir=$PWD # the name used for a "$keyname.pem" certificate and "$keyname.key" private key. keyname=vpnserver # the VPN subnet address from which the client VPN IP (for the TUN/TAP) # will be allocated vpnsubnet=10.0.200.0 # public IP address of this vpn server (same as VPNClient vpnserver= setting) vpnserver=10.0.1.10 # optional list of private subnets reachable behind this VPN server # each subnet and next hop is separated by a space # ", , ..." privatenets="10.0.6.0,10.0.1.10" # optional list of VPN clients, for statically assigning IP addresses to # clients; also, an optional client subnet can be specified for adding static # routes via the client # Note: VPN addresses x.x.x.0-3 are reserved # ",, ,, ..." #vpnclients="client1KeyFilename,10.0.200.5,10.0.0.0 client2KeyFilename,," vpnclients="" # NOTE: you may need to enable the StaticRoutes service on nodes within the # private subnet, in order to have routes back to the client. # /sbin/ip ro add /24 via # /sbin/ip ro add /24 via # -------- END CUSTOMIZATION -------- echo > $PWD/vpnserver.log rm -f -r $PWD/ccd # validate key and certification files check-key-file() { if [ ! -e $1 ]; then echo "ERROR: missing certification or key file: $1" >> $PWD/vpnserver.log fi } check-key-file $keydir/$keyname.key check-key-file $keydir/$keyname.pem check-key-file $certdir/ca-cert.pem check-key-file $certdir/dh2048.pem # validate configuration IP addresses checkip=0 if [ "$(dpkg -l | grep sipcalc)" = "" ]; then echo "WARNING: ip validation disabled because package sipcalc not installed\ " >> $PWD/vpnserver.log checkip=1 else if [ "$(sipcalc "$vpnsubnet" "$vpnserver" | grep ERR)" != "" ]; then echo "ERROR: invalid vpn subnet or server address \ $vpnsubnet or $vpnserver " >> $PWD/vpnserver.log fi fi # create client vpn ip pool file ( cat << EOF EOF )> $PWD/ippool.txt # create server.conf file ( cat << EOF # openvpn server config local $vpnserver server $vpnsubnet 255.255.255.0 push redirect-gateway def1 EOF )> $PWD/server.conf # add routes to VPN server private subnets, and push these routes to clients for privatenet in $privatenets; do if [ $privatenet != "" ]; then net=${privatenet%%,*} nexthop=${privatenet##*,} if [ $checkip = "0" ] && [ "$(sipcalc "$net" "$nexthop" | grep ERR)" != "" ]; then echo "ERROR: invalid vpn server private net address \ $net or $nexthop " >> $PWD/vpnserver.log fi echo push route $net 255.255.255.0 >> $PWD/server.conf fi done # allow subnet through this VPN, one route for each client subnet for client in $vpnclients; do if [ $client != "" ]; then cSubnetIP=${client##*,} cVpnIP=${client#*,} cVpnIP=${cVpnIP%%,*} cKeyFilename=${client%%,*} if [ "$cSubnetIP" != "" ]; then if [ $checkip = "0" ] && [ "$(sipcalc "$cSubnetIP" "$cVpnIP" | grep ERR)" != "" ]; then echo "ERROR: invalid vpn client and subnet address \ $cSubnetIP or $cVpnIP " >> $PWD/vpnserver.log fi echo route $cSubnetIP 255.255.255.0 >> $PWD/server.conf if ! test -d $PWD/ccd; then mkdir -p $PWD/ccd echo client-config-dir $PWD/ccd >> $PWD/server.conf fi if test -e $PWD/ccd/$cKeyFilename; then echo iroute $cSubnetIP 255.255.255.0 >> $PWD/ccd/$cKeyFilename else echo iroute $cSubnetIP 255.255.255.0 > $PWD/ccd/$cKeyFilename fi fi if [ "$cVpnIP" != "" ]; then echo $cKeyFilename,$cVpnIP >> $PWD/ippool.txt fi fi done ( cat << EOF keepalive 10 120 ca $certdir/ca-cert.pem cert $keydir/$keyname.pem key $keydir/$keyname.key dh $certdir/dh2048.pem cipher AES-256-CBC status /var/log/openvpn-status.log log /var/log/openvpn-server.log ifconfig-pool-linear ifconfig-pool-persist $PWD/ippool.txt port 1194 proto udp dev tun verb 4 daemon EOF )>> $PWD/server.conf # start vpn server openvpn --config server.conf } } custom-config { custom-config-id service:VPNServer custom-command VPNServer config { ('vpnserver.sh', 'vpnserver.key', 'vpnserver.pem', ) 50 ('bash vpnserver.sh', ) ('killall openvpn', ) ('pidof openvpn', ) } } services {IPForward DefaultRoute SSH VPNServer} } node n6 { type router model PC network-config { hostname vpnclient ! interface eth0 ip address 10.0.0.20/24 ipv6 address 2001:0::20/64 ! } canvas c1 iconcoords {120.0 133.0} labelcoords {120.0 165.0} interface-peer {eth0 n1} custom-config { custom-config-id service:VPNClient:vpnclient.key custom-command vpnclient.key config { -----BEGIN PRIVATE KEY----- MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC6T+1XG/EQX8pj vGSq5QMS6G8sqozjDPInZz8hSukeJCueE9Ib/nbg9wXLST6fAVA/VsY4eGXZzQNB vl6BxVXjjj/UkY4R+RXchKjg85fq+I37uZnzUL3S2jIalswB4LsLSGusBbTTfe8v 0rMCPVUzojMSXhkOVJs1gzusmdNnqEg7TZ+W4Ov12jzACbRdGMA572sXvnXRPhdR BI4CSfrsPRueWPO317oLDCECMrxzza9y65UFS3oPFvf2s6oR7FlAIEq0Z1YUQayx LDH0kE1ZjhLxBmaqNO7hD0gCjYYX8XSHOpiq045N+OGmKcI3Th8ZsGkXKMMyQ1yN a1c2PuehAgMBAAECggEAVVqYmPesEJxR1C9SzxfruJXTmNrpgHtF1NdwDIiNE8nu UZUzBLAnNhj1BpSfo6iuYtYWKXi+8HEDtPLJyRnmp0Fb7L5iH8nFQilkVOpEBtmn 8lKtPNMYo6him9vJynJyPlEHQt+6X8mp8nbMm5INnoIIc7m4MOCB2poslH5EY4/j /WTohzXVdx3nhYAJ5v5uVi/i6jeNHfY+6sj6pBKDq82OrfxgjrtABRj3/K5UcVd0 UBsaqXXObHxSvJkHFOSxK+qhVivuT3svZZlaYaleRB1oDmMx3uRNvtxdkhVz5zZY zeEddu5/BQzHPpIwKR/HScpFes92fiQ639bJxIzGAQKBgQDtNoE7V2CVpvMVgTsX 3WsqjTZZOnH8jWfWrOMPgRWmDWSA7P7SNSL7dCIftqdMv3pPxCoYVzH7Skp18HGD 8EVRqrBUupfj7NXOWlG624qtlilWQsNwPkpjXWciQQapdAhEX+T+1/d5UrVR/mY9 gP4M6rnT87ShcPPi/Otvr/B6SQKBgQDJEWj0wR5GyCfDA0L8ez3OzAwkiWB3K+8b usc0Cs/+ZFOjQd4Qxahoo6lL8G17TaIcSvdrULaWsQ/oeJ40M2xzsdlwrrtr6ueL 7q/mqsJeGLIN0h0I0i6DTUYWwzTR5CXCox967FZV46FQ8Jof3c7fsXCNUajHzcUh zxqp+AdCmQKBgHeV5bqTxzZKrvtlZfQXBOKzw/VhuHs4kmOwTtvPGKnY0JUKZUB1 10fq+RUB0P+o/DFgVFRnCOSFRFqGt8NrCpcsNK7STqZyDCt2bwODkDsIm5hIGhzo 2jmTqd2j6Ibe3xgRO/GZ0MHSB2TpmoNhFzJN1xbaInLM7ba+CLcKfHI5AoGBAIaS b3O4uSHYnrwnt7KybXi2Gr5tb7HzJrKhfOf5AKKb1VqkIBOLpx55wzp/LVdka0aS aixaNgp/cU0/RWtcq453jzeayvf8nYKLexFgYnyF/M3BPguEWPsqQenENtrv3tH5 SX2FJnePxY0dq5n+Y5JV+SWsbNFliDYLniX6SimpAoGAR9ABECd9DMnhgi+WkhZs 55YBE8P8jFuSUASBIKVmke60nDn4oot0YD74kykb6TxasGXX5lC1vCje/olNBIGM y687YmrudDfXWxEUwlHMoec5wrHDGIGCnBRAlt4whDoCREH1H+fp/9BgAThcjv58 NyNDfW+vGpDlkbwFvyhc4pY= -----END PRIVATE KEY----- } } custom-config { custom-config-id service:VPNClient:vpnclient.pem custom-command vpnclient.pem config { Certificate: Data: Version: 3 (0x2) Serial Number: 2 (0x2) Signature Algorithm: sha256WithRSAEncryption Issuer: C=US, ST=WA, O=core-dev/emailAddress=root@localhost Validity Not Before: May 19 02:09:57 2015 GMT Not After : Apr 25 02:09:57 2115 GMT Subject: C=US, ST=WA, O=core-dev, CN=vpnclient/emailAddress=root@localhost Subject Public Key Info: Public Key Algorithm: rsaEncryption Public-Key: (2048 bit) Modulus: 00:ba:4f:ed:57:1b:f1:10:5f:ca:63:bc:64:aa:e5: 03:12:e8:6f:2c:aa:8c:e3:0c:f2:27:67:3f:21:4a: e9:1e:24:2b:9e:13:d2:1b:fe:76:e0:f7:05:cb:49: 3e:9f:01:50:3f:56:c6:38:78:65:d9:cd:03:41:be: 5e:81:c5:55:e3:8e:3f:d4:91:8e:11:f9:15:dc:84: a8:e0:f3:97:ea:f8:8d:fb:b9:99:f3:50:bd:d2:da: 32:1a:96:cc:01:e0:bb:0b:48:6b:ac:05:b4:d3:7d: ef:2f:d2:b3:02:3d:55:33:a2:33:12:5e:19:0e:54: 9b:35:83:3b:ac:99:d3:67:a8:48:3b:4d:9f:96:e0: eb:f5:da:3c:c0:09:b4:5d:18:c0:39:ef:6b:17:be: 75:d1:3e:17:51:04:8e:02:49:fa:ec:3d:1b:9e:58: f3:b7:d7:ba:0b:0c:21:02:32:bc:73:cd:af:72:eb: 95:05:4b:7a:0f:16:f7:f6:b3:aa:11:ec:59:40:20: 4a:b4:67:56:14:41:ac:b1:2c:31:f4:90:4d:59:8e: 12:f1:06:66:aa:34:ee:e1:0f:48:02:8d:86:17:f1: 74:87:3a:98:aa:d3:8e:4d:f8:e1:a6:29:c2:37:4e: 1f:19:b0:69:17:28:c3:32:43:5c:8d:6b:57:36:3e: e7:a1 Exponent: 65537 (0x10001) X509v3 extensions: X509v3 Basic Constraints: CA:FALSE X509v3 Subject Key Identifier: 55:33:21:40:42:B6:63:7F:EA:A5:20:FA:18:21:C7:27:5B:6F:65:68 X509v3 Authority Key Identifier: keyid:DB:D2:9C:8D:22:D9:D7:E2:38:A0:8D:6C:3B:BE:33:CE:8D:2A:BE:C8 DirName:/C=US/ST=WA/O=core-dev/emailAddress=root@localhost serial:CE:78:96:91:DB:9B:84:FD Signature Algorithm: sha256WithRSAEncryption 33:e5:aa:b3:19:63:ce:24:c7:ee:2f:11:18:5b:7b:1d:6b:4c: 71:2d:0b:ea:6f:9b:5e:43:11:45:50:a6:00:fc:19:11:50:46: 6a:d8:1d:38:eb:9f:3a:81:09:6e:dc:ae:b3:df:71:85:e2:16: 7e:b8:bf:4c:ec:36:97:ae:58:a6:d9:d1:64:47:cf:8b:e8:0e: 8c:41:2e:c3:a7:32:ef:a0:90:c2:5c:e5:6f:aa:03:ca:15:7f: fb:ef:42:b1:22:28:47:fe:0a:df:58:b5:88:5b:a6:15:f8:13: 3f:7e:19:da:ec:3f:63:72:0b:e5:c6:94:9f:53:1c:99:60:48: 25:b5:b4:60:9a:4a:94:ab:68:be:5a:08:67:4c:c8:b5:7e:12: 32:2c:e9:e7:fb:d1:a2:40:a8:e6:68:0e:37:a1:48:99:17:b6: 40:f6:50:0a:f7:16:d1:90:e6:8a:3e:b0:c7:21:aa:9a:b9:79: 6a:69:5c:25:9b:4b:29:b7:0e:13:80:ea:e8:5c:6d:95:cd:5c: 69:de:20:69:d7:df:20:ec:6f:7b:9f:1d:61:c2:d1:59:6f:1e: 0a:45:01:f6:25:02:e5:be:fb:91:a9:82:08:c8:42:2a:3e:2c: 75:bb:4e:9c:0a:b6:07:24:52:e5:4f:f5:81:45:7b:77:ca:19: 38:56:7f:17:63:5e:1f:a4:be:03:7d:d3:48:fc:e9:43:5c:2b: b1:d5:da:44:c0:0c:56:23:4a:7d:bf:c0:ac:c6:9c:93:6d:69: 9a:b9:02:3e:aa:1b:27:3e:b1:c8:6a:39:96:09:1d:c0:08:c8: 1c:a4:82:ea:d2:72:e7:e1:47:66:7f:76:ac:d5:8c:99:59:02: 25:ee:ec:ad:76:65:0f:8a:ba:5f:a7:33:ef:8e:34:71:d2:f5: 3c:63:b0:c4:b2:65:c2:55:2d:35:d7:13:04:9c:87:d2:76:6b: af:37:ba:58:d2:63:e0:fb:9c:a4:3a:97:e4:e6:79:0f:ca:d4: 07:8c:39:80:4d:5e:d4:09:3a:09:1f:16:1a:58:c0:96:58:19: e8:f7:56:bc:bd:fd:23:f4:4b:93:eb:a4:f2:22:7d:7c:d2:f3: 6b:5a:13:24:a6:b8:1a:33:0c:fa:cd:77:36:12:c8:c6:ac:e9: 0f:29:1a:4f:c3:3c:92:53:8c:af:80:04:ac:9b:2a:73:af:a8: 0f:ef:7d:9f:5e:7c:52:d3:03:2e:19:6f:25:b0:f7:17:ef:c9: 37:b9:50:ad:60:b0:c7:d9:ba:8f:9e:93:27:ba:52:27:70:b8: ae:2b:9a:f7:33:2a:fd:a6:51:f5:e2:42:1a:e9:e6:08:5e:62: 75:e9:b2:1b:ca:ce:cd:d1 -----BEGIN CERTIFICATE----- MIIE1TCCAr2gAwIBAgIBAjANBgkqhkiG9w0BAQsFADBMMQswCQYDVQQGEwJVUzEL MAkGA1UECBMCV0ExETAPBgNVBAoTCGNvcmUtZGV2MR0wGwYJKoZIhvcNAQkBFg5y b290QGxvY2FsaG9zdDAgFw0xNTA1MTkwMjA5NTdaGA8yMTE1MDQyNTAyMDk1N1ow YDELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAldBMREwDwYDVQQKEwhjb3JlLWRldjES MBAGA1UEAxMJdnBuY2xpZW50MR0wGwYJKoZIhvcNAQkBFg5yb290QGxvY2FsaG9z dDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALpP7Vcb8RBfymO8ZKrl AxLobyyqjOMM8idnPyFK6R4kK54T0hv+duD3BctJPp8BUD9Wxjh4ZdnNA0G+XoHF VeOOP9SRjhH5FdyEqODzl+r4jfu5mfNQvdLaMhqWzAHguwtIa6wFtNN97y/SswI9 VTOiMxJeGQ5UmzWDO6yZ02eoSDtNn5bg6/XaPMAJtF0YwDnvaxe+ddE+F1EEjgJJ +uw9G55Y87fXugsMIQIyvHPNr3LrlQVLeg8W9/azqhHsWUAgSrRnVhRBrLEsMfSQ TVmOEvEGZqo07uEPSAKNhhfxdIc6mKrTjk344aYpwjdOHxmwaRcowzJDXI1rVzY+ 56ECAwEAAaOBqzCBqDAJBgNVHRMEAjAAMB0GA1UdDgQWBBRVMyFAQrZjf+qlIPoY IccnW29laDB8BgNVHSMEdTBzgBTb0pyNItnX4jigjWw7vjPOjSq+yKFQpE4wTDEL MAkGA1UEBhMCVVMxCzAJBgNVBAgTAldBMREwDwYDVQQKEwhjb3JlLWRldjEdMBsG CSqGSIb3DQEJARYOcm9vdEBsb2NhbGhvc3SCCQDOeJaR25uE/TANBgkqhkiG9w0B AQsFAAOCAgEAM+WqsxljziTH7i8RGFt7HWtMcS0L6m+bXkMRRVCmAPwZEVBGatgd OOufOoEJbtyus99xheIWfri/TOw2l65YptnRZEfPi+gOjEEuw6cy76CQwlzlb6oD yhV/++9CsSIoR/4K31i1iFumFfgTP34Z2uw/Y3IL5caUn1McmWBIJbW0YJpKlKto vloIZ0zItX4SMizp5/vRokCo5mgON6FImRe2QPZQCvcW0ZDmij6wxyGqmrl5amlc JZtLKbcOE4Dq6Fxtlc1cad4gadffIOxve58dYcLRWW8eCkUB9iUC5b77kamCCMhC Kj4sdbtOnAq2ByRS5U/1gUV7d8oZOFZ/F2NeH6S+A33TSPzpQ1wrsdXaRMAMViNK fb/ArMack21pmrkCPqobJz6xyGo5lgkdwAjIHKSC6tJy5+FHZn92rNWMmVkCJe7s rXZlD4q6X6cz7440cdL1PGOwxLJlwlUtNdcTBJyH0nZrrze6WNJj4PucpDqX5OZ5 D8rUB4w5gE1e1Ak6CR8WGljAllgZ6PdWvL39I/RLk+uk8iJ9fNLza1oTJKa4GjMM +s13NhLIxqzpDykaT8M8klOMr4AErJsqc6+oD+99n158UtMDLhlvJbD3F+/JN7lQ rWCwx9m6j56TJ7pSJ3C4riua9zMq/aZR9eJCGunmCF5idemyG8rOzdE= -----END CERTIFICATE----- } } custom-config { custom-config-id service:VPNClient:vpnclient.sh custom-command vpnclient.sh config { #!/bin/sh # custom VPN Client configuration for service (security.py) # -------- CUSTOMIZATION REQUIRED -------- # # The VPNClient service builds a VPN tunnel to the specified VPN server using # OpenVPN software and a virtual TUN/TAP device. # directory containing the certificate and key described below certdir=$SESSION_DIR/certs keydir=$PWD # the name used for a "$keyname.pem" certificate and "$keyname.key" private key. keyname=vpnclient # the public IP address of the VPN server this client should connect with vpnserver="10.0.1.10" # optional next hop for adding a static route to reach the VPN server nexthop="" # --------- END CUSTOMIZATION -------- # validate addresses if [ "$(dpkg -l | grep sipcalc)" = "" ]; then echo "WARNING: ip validation disabled because package sipcalc not installed " > $PWD/vpnclient.log else if [ "$(sipcalc "$vpnserver" "$nexthop" | grep ERR)" != "" ]; then echo "ERROR: invalide address $vpnserver or $nexthop \ " > $PWD/vpnclient.log fi fi # validate key and certification files check-key-file() { if [ ! -e $1 ]; then echo "ERROR: missing certification or key file: $1" >> $PWD/vpnserver.log fi } check-key-file $keydir/$keyname.key check-key-file $keydir/$keyname.pem check-key-file $certdir/ca-cert.pem check-key-file $certdir/dh2048.pem # if necessary, add a static route for reaching the VPN server IP via the IF vpnservernet=${vpnserver%.*}.0/24 if [ "$nexthop" != "" ]; then /sbin/ip route add $vpnservernet via $nexthop fi # create openvpn client.conf ( cat << EOF client dev tun proto udp remote $vpnserver 1194 nobind ca $certdir/ca-cert.pem cert $keydir/$keyname.pem key $keydir/$keyname.key dh $certdir/dh2048.pem cipher AES-256-CBC log /var/log/openvpn-client.log verb 4 daemon EOF ) > client.conf openvpn --config client.conf } } custom-config { custom-config-id service:VPNClient custom-command VPNClient config { ('vpnclient.sh', 'vpnclient.pem', 'vpnclient.key', ) 60 ('bash vpnclient.sh', ) ('killall openvpn', ) ('pidof openvpn', ) } } services {DefaultRoute VPNClient} } node n7 { type lanswitch network-config { hostname n7 ! } canvas c1 iconcoords {824.0 458.0} labelcoords {824.0 482.0} interface-peer {e0 n5} interface-peer {e1 n8} interface-peer {e2 n9} interface-peer {e3 n10} } node n8 { type router model PC network-config { hostname n8 ! interface eth0 ip address 10.0.6.20/24 ipv6 address 2001:6::20/64 ! } canvas c1 iconcoords {801.0 264.0} labelcoords {801.0 296.0} interface-peer {eth0 n7} } node n9 { type router model PC network-config { hostname n9 ! interface eth0 ip address 10.0.6.21/24 ipv6 address 2001:6::21/64 ! } canvas c1 iconcoords {885.0 305.0} labelcoords {885.0 337.0} interface-peer {eth0 n7} } node n10 { type router model PC network-config { hostname n10 ! interface eth0 ip address 10.0.6.22/24 ipv6 address 2001:6::22/64 ! } canvas c1 iconcoords {954.0 353.0} labelcoords {954.0 385.0} interface-peer {eth0 n7} } link l1 { nodes {n6 n1} bandwidth 0 } link l2 { nodes {n4 n5} bandwidth 0 } link l3 { nodes {n1 n2} bandwidth 0 } link l4 { nodes {n3 n4} bandwidth 0 } link l5 { nodes {n3 n1} bandwidth 0 } link l6 { nodes {n4 n2} bandwidth 0 } link l7 { nodes {n5 n7} bandwidth 0 } link l8 { nodes {n8 n7} bandwidth 0 } link l9 { nodes {n9 n7} bandwidth 0 } link l10 { nodes {n10 n7} bandwidth 0 } annotation a1 { iconcoords {661.0 187.0 997.0 579.0} type rectangle label {private network} labelcolor black fontfamily {Arial} fontsize 12 color #e9e9fe width 0 border black rad 25 effects {bold} canvas c1 } canvas c1 { name {Canvas1} } hook 3:instantiation_hook.sh { #!/bin/sh # session hook script; write commands here to execute on the host at the # specified state CERT_DIR=$SESSION_DIR/certs mkdir $CERT_DIR cat > $CERT_DIR/dh2048.pem < $CERT_DIR/ca-cert.pem < # # Makefile for installing the CORE GUI. Since it is a Tcl/Tk script, we do not # build anything here. # VPATH = @srcdir@ am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' 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 = : subdir = gui DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ $(srcdir)/core-gui.in $(srcdir)/version.tcl.in \ $(dist_bin_SCRIPTS) $(dist_core_SCRIPTS) $(dist_core_DATA) \ $(dist_coreaddons_DATA) $(dist_coreconfigs_DATA) ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = core-gui version.tcl CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } am__installdirs = "$(DESTDIR)$(bindir)" "$(DESTDIR)$(coredir)" \ "$(DESTDIR)$(coredir)" "$(DESTDIR)$(coreaddonsdir)" \ "$(DESTDIR)$(coreconfigsdir)" SCRIPTS = $(dist_bin_SCRIPTS) $(dist_core_SCRIPTS) 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 = SOURCES = DIST_SOURCES = RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \ ctags-recursive dvi-recursive html-recursive info-recursive \ install-data-recursive install-dvi-recursive \ install-exec-recursive install-html-recursive \ install-info-recursive install-pdf-recursive \ install-ps-recursive install-recursive installcheck-recursive \ installdirs-recursive pdf-recursive ps-recursive \ tags-recursive uninstall-recursive am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac DATA = $(dist_core_DATA) $(dist_coreaddons_DATA) \ $(dist_coreconfigs_DATA) RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ distclean-recursive maintainer-clean-recursive am__recursive_targets = \ $(RECURSIVE_TARGETS) \ $(RECURSIVE_CLEAN_TARGETS) \ $(am__extra_recursive_targets) AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \ distdir 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 DIST_SUBDIRS = $(SUBDIRS) DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) am__relativize = \ dir0=`pwd`; \ sed_first='s,^\([^/]*\)/.*$$,\1,'; \ sed_rest='s,^[^/]*/*,,'; \ sed_last='s,^.*/\([^/]*\)$$,\1,'; \ sed_butlast='s,/*[^/]*$$,,'; \ while test -n "$$dir1"; do \ first=`echo "$$dir1" | sed -e "$$sed_first"`; \ if test "$$first" != "."; then \ if test "$$first" = ".."; then \ dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ else \ first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ if test "$$first2" = "$$first"; then \ dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ else \ dir2="../$$dir2"; \ fi; \ dir0="$$dir0"/"$$first"; \ fi; \ fi; \ dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ done; \ reldir="$$dir2" ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ ARCH = @ARCH@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ BINDIR = @BINDIR@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ COREDPY_VERSION = @COREDPY_VERSION@ CORE_CONF_DIR = @CORE_CONF_DIR@ CORE_DATA_DIR = @CORE_DATA_DIR@ CORE_GUI_CONF_DIR = @CORE_GUI_CONF_DIR@ CORE_LIB_DIR = @CORE_LIB_DIR@ CORE_STATE_DIR = @CORE_STATE_DIR@ CORE_VERSION = @CORE_VERSION@ CORE_VERSION_DATE = @CORE_VERSION_DATE@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ GREP = @GREP@ HELP2MAN = @HELP2MAN@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LDFLAGS = @LDFLAGS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIB_DIR = @LIB_DIR@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ OBJEXT = @OBJEXT@ 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@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PYTHON = @PYTHON@ PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ PYTHON_PLATFORM = @PYTHON_PLATFORM@ PYTHON_PREFIX = @PYTHON_PREFIX@ PYTHON_VERSION = @PYTHON_VERSION@ RANLIB = @RANLIB@ SBINDIR = @SBINDIR@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_CC = @ac_ct_CC@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ brctl_path = @brctl_path@ build_alias = @build_alias@ builddir = @builddir@ convert = @convert@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ ebtables_path = @ebtables_path@ enable_daemon = @enable_daemon@ enable_gui = @enable_gui@ exec_prefix = @exec_prefix@ gmake = @gmake@ help2man = @help2man@ host_alias = @host_alias@ htmldir = @htmldir@ ifconfig_path = @ifconfig_path@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ ip_path = @ip_path@ libdir = @libdir@ libev_CFLAGS = @libev_CFLAGS@ libev_LIBS = @libev_LIBS@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ mount_path = @mount_path@ ngctl_path = @ngctl_path@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ pkgpyexecdir = @pkgpyexecdir@ pkgpythondir = @pkgpythondir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ pyexecdir = @pyexecdir@ pyprefix = @pyprefix@ pythondir = @pythondir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ sysctl_path = @sysctl_path@ target_alias = @target_alias@ tc_path = @tc_path@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ umount_path = @umount_path@ vimage_path = @vimage_path@ with_startup = @with_startup@ SUBDIRS = icons TCL_FILES = annotations.tcl api.tcl canvas.tcl cfgparse.tcl \ core.tcl debug.tcl editor.tcl exec.tcl \ filemgmt.tcl gpgui.tcl \ graph_partitioning.tcl help.tcl \ initgui.tcl ipv4.tcl ipv6.tcl \ linkcfg.tcl mobility.tcl nodecfg.tcl \ nodes.tcl services.tcl ns2imunes.tcl plugins.tcl \ tooltips.tcl topogen.tcl traffic.tcl util.tcl \ version.tcl widget.tcl wlan.tcl wlanscript.tcl \ exceptions.tcl ADDONS_FILES = addons/ipsecservice.tcl CONFIG_FILES = configs/sample1.imn configs/sample1.scen \ configs/sample1-bg.gif configs/sample2-ssh.imn \ configs/sample3-bgp.imn configs/sample4-nrlsmf.imn \ configs/sample4.scen configs/sample4-bg.jpg \ configs/sample5-mgen.imn configs/sample6-emane-rfpipe.imn \ configs/sample7-emane-ieee80211abg.imn \ configs/sample8-ipsec-service.imn \ configs/sample9-vpn.imn \ configs/sample10-kitchen-sink.imn OTHER_FILES = core-bsd-cleanup.sh # # CORE GUI script (/usr/local/bin/core-gui) # dist_bin_SCRIPTS = core-gui # # Tcl/Tk scripts (/usr/local/lib/core) # coredir = $(CORE_LIB_DIR) dist_core_DATA = $(TCL_FILES) dist_core_SCRIPTS = $(OTHER_FILES) # # Addon files # coreaddonsdir = $(coredir)/addons dist_coreaddons_DATA = $(ADDONS_FILES) # # Sample configs (/usr/local/share/core/examples/configs) # coreconfigsdir = $(datadir)/core/examples/configs dist_coreconfigs_DATA = $(CONFIG_FILES) # extra cruft to remove DISTCLEANFILES = Makefile.in # files to include in source tarball not included elsewhere EXTRA_DIST = addons all: all-recursive .SUFFIXES: $(srcdir)/Makefile.in: $(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 gui/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign gui/Makefile .PRECIOUS: 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: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): core-gui: $(top_builddir)/config.status $(srcdir)/core-gui.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ version.tcl: $(top_builddir)/config.status $(srcdir)/version.tcl.in cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ install-dist_binSCRIPTS: $(dist_bin_SCRIPTS) @$(NORMAL_INSTALL) @list='$(dist_bin_SCRIPTS)'; test -n "$(bindir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(bindir)'"; \ $(MKDIR_P) "$(DESTDIR)$(bindir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ if test -f "$$d$$p"; then echo "$$d$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n' \ -e 'h;s|.*|.|' \ -e 'p;x;s,.*/,,;$(transform)' | sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1; } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) { files[d] = files[d] " " $$1; \ if (++n[d] == $(am__install_max)) { \ print "f", d, files[d]; n[d] = 0; files[d] = "" } } \ else { print "f", d "/" $$4, $$1 } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_SCRIPT) $$files '$(DESTDIR)$(bindir)$$dir'"; \ $(INSTALL_SCRIPT) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \ } \ ; done uninstall-dist_binSCRIPTS: @$(NORMAL_UNINSTALL) @list='$(dist_bin_SCRIPTS)'; test -n "$(bindir)" || exit 0; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 's,.*/,,;$(transform)'`; \ dir='$(DESTDIR)$(bindir)'; $(am__uninstall_files_from_dir) install-dist_coreSCRIPTS: $(dist_core_SCRIPTS) @$(NORMAL_INSTALL) @list='$(dist_core_SCRIPTS)'; test -n "$(coredir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(coredir)'"; \ $(MKDIR_P) "$(DESTDIR)$(coredir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ if test -f "$$d$$p"; then echo "$$d$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n' \ -e 'h;s|.*|.|' \ -e 'p;x;s,.*/,,;$(transform)' | sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1; } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) { files[d] = files[d] " " $$1; \ if (++n[d] == $(am__install_max)) { \ print "f", d, files[d]; n[d] = 0; files[d] = "" } } \ else { print "f", d "/" $$4, $$1 } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_SCRIPT) $$files '$(DESTDIR)$(coredir)$$dir'"; \ $(INSTALL_SCRIPT) $$files "$(DESTDIR)$(coredir)$$dir" || exit $$?; \ } \ ; done uninstall-dist_coreSCRIPTS: @$(NORMAL_UNINSTALL) @list='$(dist_core_SCRIPTS)'; test -n "$(coredir)" || exit 0; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 's,.*/,,;$(transform)'`; \ dir='$(DESTDIR)$(coredir)'; $(am__uninstall_files_from_dir) install-dist_coreDATA: $(dist_core_DATA) @$(NORMAL_INSTALL) @list='$(dist_core_DATA)'; test -n "$(coredir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(coredir)'"; \ $(MKDIR_P) "$(DESTDIR)$(coredir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(coredir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(coredir)" || exit $$?; \ done uninstall-dist_coreDATA: @$(NORMAL_UNINSTALL) @list='$(dist_core_DATA)'; test -n "$(coredir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(coredir)'; $(am__uninstall_files_from_dir) install-dist_coreaddonsDATA: $(dist_coreaddons_DATA) @$(NORMAL_INSTALL) @list='$(dist_coreaddons_DATA)'; test -n "$(coreaddonsdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(coreaddonsdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(coreaddonsdir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(coreaddonsdir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(coreaddonsdir)" || exit $$?; \ done uninstall-dist_coreaddonsDATA: @$(NORMAL_UNINSTALL) @list='$(dist_coreaddons_DATA)'; test -n "$(coreaddonsdir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(coreaddonsdir)'; $(am__uninstall_files_from_dir) install-dist_coreconfigsDATA: $(dist_coreconfigs_DATA) @$(NORMAL_INSTALL) @list='$(dist_coreconfigs_DATA)'; test -n "$(coreconfigsdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(coreconfigsdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(coreconfigsdir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(coreconfigsdir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(coreconfigsdir)" || exit $$?; \ done uninstall-dist_coreconfigsDATA: @$(NORMAL_UNINSTALL) @list='$(dist_coreconfigs_DATA)'; test -n "$(coreconfigsdir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(coreconfigsdir)'; $(am__uninstall_files_from_dir) # This directory's subdirectories are mostly independent; you can cd # into them and run 'make' without going through this Makefile. # To change the values of 'make' variables: instead of editing Makefiles, # (1) if the variable is set in 'config.status', edit 'config.status' # (which will cause the Makefiles to be regenerated when you run 'make'); # (2) otherwise, pass the desired values on the 'make' command line. $(am__recursive_targets): @fail=; \ if $(am__make_keepgoing); then \ failcom='fail=yes'; \ else \ failcom='exit 1'; \ fi; \ dot_seen=no; \ target=`echo $@ | sed s/-recursive//`; \ case "$@" in \ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ *) list='$(SUBDIRS)' ;; \ esac; \ for subdir in $$list; do \ echo "Making $$target in $$subdir"; \ if test "$$subdir" = "."; then \ dot_seen=yes; \ local_target="$$target-am"; \ else \ local_target="$$target"; \ fi; \ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ || eval $$failcom; \ done; \ if test "$$dot_seen" = "no"; then \ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ fi; test -z "$$fail" ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-recursive TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ include_option=--etags-include; \ empty_fix=.; \ else \ include_option=--include; \ empty_fix=; \ fi; \ list='$(SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ test ! -f $$subdir/TAGS || \ set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ fi; \ done; \ $(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-recursive 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-recursive 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 @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ $(am__make_dryrun) \ || test -d "$(distdir)/$$subdir" \ || $(MKDIR_P) "$(distdir)/$$subdir" \ || exit 1; \ dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ $(am__relativize); \ new_distdir=$$reldir; \ dir1=$$subdir; dir2="$(top_distdir)"; \ $(am__relativize); \ new_top_distdir=$$reldir; \ echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ ($(am__cd) $$subdir && \ $(MAKE) $(AM_MAKEFLAGS) \ top_distdir="$$new_top_distdir" \ distdir="$$new_distdir" \ am__remove_distdir=: \ am__skip_length_check=: \ am__skip_mode_fix=: \ distdir) \ || exit 1; \ fi; \ done $(MAKE) $(AM_MAKEFLAGS) \ top_distdir="$(top_distdir)" distdir="$(distdir)" \ dist-hook check-am: all-am check: check-recursive all-am: Makefile $(SCRIPTS) $(DATA) installdirs: installdirs-recursive installdirs-am: for dir in "$(DESTDIR)$(bindir)" "$(DESTDIR)$(coredir)" "$(DESTDIR)$(coredir)" "$(DESTDIR)$(coreaddonsdir)" "$(DESTDIR)$(coreconfigsdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-recursive install-exec: install-exec-recursive install-data: install-data-recursive uninstall: uninstall-recursive install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-recursive 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) -test -z "$(DISTCLEANFILES)" || rm -f $(DISTCLEANFILES) 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-recursive clean-am: clean-generic mostlyclean-am distclean: distclean-recursive -rm -f Makefile distclean-am: clean-am distclean-generic distclean-tags dvi: dvi-recursive dvi-am: html: html-recursive html-am: info: info-recursive info-am: install-data-am: install-dist_coreDATA install-dist_coreSCRIPTS \ install-dist_coreaddonsDATA install-dist_coreconfigsDATA install-dvi: install-dvi-recursive install-dvi-am: install-exec-am: install-dist_binSCRIPTS install-html: install-html-recursive install-html-am: install-info: install-info-recursive install-info-am: install-man: install-pdf: install-pdf-recursive install-pdf-am: install-ps: install-ps-recursive install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-recursive -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-recursive mostlyclean-am: mostlyclean-generic pdf: pdf-recursive pdf-am: ps: ps-recursive ps-am: uninstall-am: uninstall-dist_binSCRIPTS uninstall-dist_coreDATA \ uninstall-dist_coreSCRIPTS uninstall-dist_coreaddonsDATA \ uninstall-dist_coreconfigsDATA @$(NORMAL_INSTALL) $(MAKE) $(AM_MAKEFLAGS) uninstall-hook .MAKE: $(am__recursive_targets) install-am install-strip uninstall-am .PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am check \ check-am clean clean-generic cscopelist-am ctags ctags-am \ dist-hook distclean distclean-generic distclean-tags distdir \ dvi dvi-am html html-am info info-am install install-am \ install-data install-data-am install-dist_binSCRIPTS \ install-dist_coreDATA install-dist_coreSCRIPTS \ install-dist_coreaddonsDATA install-dist_coreconfigsDATA \ 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 installdirs-am maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-generic pdf \ pdf-am ps ps-am tags tags-am uninstall uninstall-am \ uninstall-dist_binSCRIPTS uninstall-dist_coreDATA \ uninstall-dist_coreSCRIPTS uninstall-dist_coreaddonsDATA \ uninstall-dist_coreconfigsDATA uninstall-hook dist-hook: rm -rf $(distdir)/addons/.svn uninstall-hook: rmdir -p $(coreconfigsdir) || true rmdir -p $(coreaddonsdir) || true rmdir -p $(coredir) || true # 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: core-4.8/gui/Makefile.am0000664000175000017500000000364212534327775012104 00000000000000# CORE # (c)2010-2013 the Boeing Company. # See the LICENSE file included in this distribution. # # author: Jeff Ahrenholz # # Makefile for installing the CORE GUI. Since it is a Tcl/Tk script, we do not # build anything here. # SUBDIRS = icons TCL_FILES = annotations.tcl api.tcl canvas.tcl cfgparse.tcl \ core.tcl debug.tcl editor.tcl exec.tcl \ filemgmt.tcl gpgui.tcl \ graph_partitioning.tcl help.tcl \ initgui.tcl ipv4.tcl ipv6.tcl \ linkcfg.tcl mobility.tcl nodecfg.tcl \ nodes.tcl services.tcl ns2imunes.tcl plugins.tcl \ tooltips.tcl topogen.tcl traffic.tcl util.tcl \ version.tcl widget.tcl wlan.tcl wlanscript.tcl \ exceptions.tcl ADDONS_FILES = addons/ipsecservice.tcl CONFIG_FILES = configs/sample1.imn configs/sample1.scen \ configs/sample1-bg.gif configs/sample2-ssh.imn \ configs/sample3-bgp.imn configs/sample4-nrlsmf.imn \ configs/sample4.scen configs/sample4-bg.jpg \ configs/sample5-mgen.imn configs/sample6-emane-rfpipe.imn \ configs/sample7-emane-ieee80211abg.imn \ configs/sample8-ipsec-service.imn \ configs/sample9-vpn.imn \ configs/sample10-kitchen-sink.imn OTHER_FILES = core-bsd-cleanup.sh # # CORE GUI script (/usr/local/bin/core-gui) # dist_bin_SCRIPTS = core-gui # # Tcl/Tk scripts (/usr/local/lib/core) # coredir = $(CORE_LIB_DIR) dist_core_DATA = $(TCL_FILES) dist_core_SCRIPTS = $(OTHER_FILES) # # Addon files # coreaddonsdir = $(coredir)/addons dist_coreaddons_DATA = $(ADDONS_FILES) # # Sample configs (/usr/local/share/core/examples/configs) # coreconfigsdir = $(datadir)/core/examples/configs dist_coreconfigs_DATA = $(CONFIG_FILES) dist-hook: rm -rf $(distdir)/addons/.svn uninstall-hook: rmdir -p $(coreconfigsdir) || true rmdir -p $(coreaddonsdir) || true rmdir -p $(coredir) || true # extra cruft to remove DISTCLEANFILES = Makefile.in # files to include in source tarball not included elsewhere EXTRA_DIST = addons core-4.8/gui/core-gui.in0000775000175000017500000001260212534327775012111 00000000000000#!/bin/sh # # Copyright 2005-2013 the Boeing Company. # See the LICENSE file included in this distribution. # # # Copyright 2004-2008 University of Zagreb, Croatia. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF # SUCH DAMAGE. # # This work was supported in part by Croatian Ministry of Science # and Technology through the research contract #IP-2003-143. # case $1 in -h | --help) echo "" echo "Usage: `basename $0` [-h|-v] [-b|-c ] [-s] [-a address] [-p port]" echo " []" echo "" echo "Launches the CORE Tcl/Tk X11 GUI or starts an imn-based emulation." echo "" echo " -(-h)elp show help message and exit" echo " -(-v)ersion show version number and exit" echo " -(-b)atch batch mode (no X11 GUI)" echo -n " -(-c)losebatch stop and clean up a batch mode " echo "session " echo " -(-s)tart start in execute mode, not edit mode" echo " -(-a)ddress connect to the specified IP address (default 127.0.0.1)" echo " -(-p)port connect to the specified TCP port (default 4038)" echo " (optional) load the specified imn scenario file" echo "" echo "With no parameters, starts the GUI in edit mode with a blank canvas." echo "" exit 0 ;; -v | --version) exec echo "`basename $0` version @CORE_VERSION@ (@CORE_VERSION_DATE@)" exit 0 ;; esac SHELL=/bin/sh export SHELL export LIBDIR="@CORE_LIB_DIR@" export SBINDIR="@SBINDIR@" # eval is used here to expand "~" to user's home dir if [ x$CONFDIR = x ]; then export CONFDIR=`eval "echo @CORE_GUI_CONF_DIR@"` ; fi export CORE_STATE_DIR="@CORE_STATE_DIR@" export CORE_DATA_DIR="@CORE_DATA_DIR@" export CORE_USER=`id -u -n` export CORE_START_DIR=$PWD init_conf_dir() { echo "Setting up user config area $CONFDIR, $CONFDIR/configs, and " echo " $CONFDIR/myservices" mkdir -p $CONFDIR if [ $? != 0 ]; then echo "error making directory $CONFDIR!"; fi mkdir -p $CONFDIR/configs if [ $? != 0 ]; then echo "error making directory $CONFDIR/configs!"; else cp -a $CORE_DATA_DIR/examples/configs/* $CONFDIR/configs/ fi mkdir -p $CONFDIR/myservices if [ $? != 0 ]; then echo "error making directory $CONFDIR/myservices!"; else cp -a $CORE_DATA_DIR/examples/myservices/* $CONFDIR/myservices/ fi } cd $LIBDIR core=$LIBDIR/core.tcl # locate wish8.5 binaries WISHLIST="/usr/bin/wish8.6 /usr/local/bin/wish8.5 /usr/bin/wish8.5" for wishbin in $WISHLIST do if [ -x $wishbin ] then WISH=$wishbin; break; fi; done; if [ a$WISH = a ] then echo "CORE could not locate the Tcl/Tk binary (wish8.5)." exit 1; fi; # create /home/user/.core directory if necessary if [ ! -e $CONFDIR ] then init_conf_dir fi; # check for and fix write permissions on /home/user/.core directory while [ ! -w $CONFDIR ]; do echo " CORE requires write permissions to the '$CONFDIR'" echo " configuration directory for the user '$CORE_USER'," echo " would you like to fix this now [Y/n]?" read yn if [ "z$yn" = "zn" ]; then break fi echo -n " (sudo may prompt you for a password; if you do not have sudo set" echo " up for the" echo " user '$CORE_USER', su to root and run this command:" echo " chown -R $CORE_USER $CONFDIR )" sudo chown -R $U $CONFDIR sudo chmod -R u+w $CONFDIR done # GUI config directory should not be a file (old prefs) if [ ! -d $CONFDIR ] then mv $CONFDIR $CONFDIR.tmp if [ $? != 0 ]; then echo "error moving $CONFDIR!"; exit 1; fi init_conf_dir echo "Old preferences file $CONFDIR has been moved to $CONFDIR/prefs.conf" mv $CONFDIR.tmp $CONFDIR/prefs.conf if [ $? != 0 ]; then echo "error moving $CONFDIR.tmp to $CONFDIR/prefs.conf!"; exit 1; fi fi; case $1 in -b | --batch) TCLBIN=`echo ${WISH} | sed s/wish/tclsh/g` exec ${TCLBIN} $core "$@" ;; -c | --closebatch) TCLBIN=`echo ${WISH} | sed s/wish/tclsh/g` exec ${TCLBIN} $core "$@" ;; -s) shift exec ${WISH} $core -- "--start" "$@" ;; -a) shift exec ${WISH} $core -- "--address" "$@" ;; -p) shift exec ${WISH} $core -- "--port" "$@" ;; *) exec ${WISH} $core -- $@ ;; esac cd $CORE_START_DIR core-4.8/gui/version.tcl.in0000664000175000017500000000034512534327775012643 00000000000000# # Copyright 2005-2013 the Boeing Company. # See the LICENSE file included in this distribution. # # # define the version number and release date here # set CORE_VERSION @CORE_VERSION@ set CORE_VERSION_DATE @CORE_VERSION_DATE@ core-4.8/gui/core-gui0000664000175000017500000001253112534330005011456 00000000000000#!/bin/sh # # Copyright 2005-2013 the Boeing Company. # See the LICENSE file included in this distribution. # # # Copyright 2004-2008 University of Zagreb, Croatia. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF # SUCH DAMAGE. # # This work was supported in part by Croatian Ministry of Science # and Technology through the research contract #IP-2003-143. # case $1 in -h | --help) echo "" echo "Usage: `basename $0` [-h|-v] [-b|-c ] [-s] [-a address] [-p port]" echo " []" echo "" echo "Launches the CORE Tcl/Tk X11 GUI or starts an imn-based emulation." echo "" echo " -(-h)elp show help message and exit" echo " -(-v)ersion show version number and exit" echo " -(-b)atch batch mode (no X11 GUI)" echo -n " -(-c)losebatch stop and clean up a batch mode " echo "session " echo " -(-s)tart start in execute mode, not edit mode" echo " -(-a)ddress connect to the specified IP address (default 127.0.0.1)" echo " -(-p)port connect to the specified TCP port (default 4038)" echo " (optional) load the specified imn scenario file" echo "" echo "With no parameters, starts the GUI in edit mode with a blank canvas." echo "" exit 0 ;; -v | --version) exec echo "`basename $0` version 4.8 (20150605)" exit 0 ;; esac SHELL=/bin/sh export SHELL export LIBDIR="/usr/lib/core" export SBINDIR="/usr/sbin" # eval is used here to expand "~" to user's home dir if [ x$CONFDIR = x ]; then export CONFDIR=`eval "echo ${HOME}/.core"` ; fi export CORE_STATE_DIR="/var" export CORE_DATA_DIR="/usr/share/core" export CORE_USER=`id -u -n` export CORE_START_DIR=$PWD init_conf_dir() { echo "Setting up user config area $CONFDIR, $CONFDIR/configs, and " echo " $CONFDIR/myservices" mkdir -p $CONFDIR if [ $? != 0 ]; then echo "error making directory $CONFDIR!"; fi mkdir -p $CONFDIR/configs if [ $? != 0 ]; then echo "error making directory $CONFDIR/configs!"; else cp -a $CORE_DATA_DIR/examples/configs/* $CONFDIR/configs/ fi mkdir -p $CONFDIR/myservices if [ $? != 0 ]; then echo "error making directory $CONFDIR/myservices!"; else cp -a $CORE_DATA_DIR/examples/myservices/* $CONFDIR/myservices/ fi } cd $LIBDIR core=$LIBDIR/core.tcl # locate wish8.5 binaries WISHLIST="/usr/bin/wish8.6 /usr/local/bin/wish8.5 /usr/bin/wish8.5" for wishbin in $WISHLIST do if [ -x $wishbin ] then WISH=$wishbin; break; fi; done; if [ a$WISH = a ] then echo "CORE could not locate the Tcl/Tk binary (wish8.5)." exit 1; fi; # create /home/user/.core directory if necessary if [ ! -e $CONFDIR ] then init_conf_dir fi; # check for and fix write permissions on /home/user/.core directory while [ ! -w $CONFDIR ]; do echo " CORE requires write permissions to the '$CONFDIR'" echo " configuration directory for the user '$CORE_USER'," echo " would you like to fix this now [Y/n]?" read yn if [ "z$yn" = "zn" ]; then break fi echo -n " (sudo may prompt you for a password; if you do not have sudo set" echo " up for the" echo " user '$CORE_USER', su to root and run this command:" echo " chown -R $CORE_USER $CONFDIR )" sudo chown -R $U $CONFDIR sudo chmod -R u+w $CONFDIR done # GUI config directory should not be a file (old prefs) if [ ! -d $CONFDIR ] then mv $CONFDIR $CONFDIR.tmp if [ $? != 0 ]; then echo "error moving $CONFDIR!"; exit 1; fi init_conf_dir echo "Old preferences file $CONFDIR has been moved to $CONFDIR/prefs.conf" mv $CONFDIR.tmp $CONFDIR/prefs.conf if [ $? != 0 ]; then echo "error moving $CONFDIR.tmp to $CONFDIR/prefs.conf!"; exit 1; fi fi; case $1 in -b | --batch) TCLBIN=`echo ${WISH} | sed s/wish/tclsh/g` exec ${TCLBIN} $core "$@" ;; -c | --closebatch) TCLBIN=`echo ${WISH} | sed s/wish/tclsh/g` exec ${TCLBIN} $core "$@" ;; -s) shift exec ${WISH} $core -- "--start" "$@" ;; -a) shift exec ${WISH} $core -- "--address" "$@" ;; -p) shift exec ${WISH} $core -- "--port" "$@" ;; *) exec ${WISH} $core -- $@ ;; esac cd $CORE_START_DIR core-4.8/gui/core-bsd-cleanup.sh0000775000175000017500000000260012534327775013523 00000000000000#!/bin/sh # # cleanup.sh # # Copyright 2005-2013 the Boeing Company. # See the LICENSE file included in this distribution. # # Removes leftover netgraph nodes and vimages from an emulation that # did not exit properly. # ngnodes="pipe eiface hub switch wlan" vimages=`vimage -l | fgrep -v " " | cut -d: -f 1 | sed s/\"//g` # shutdown netgraph nodes for ngn in $ngnodes do nodes=`ngctl list | grep $ngn | awk '{print $2}'` for n in $nodes do echo ngctl shutdown $n: ngctl shutdown $n: done done # kills processes and remove vimages for vimage in $vimages do procs=`vimage $vimage ps x | awk '{print $1}'` for proc in $procs do if [ $proc != "PID" ] then echo vimage $vimage kill $proc vimage $vimage kill $proc fi done loopback=`vimage $vimage ifconfig -a | head -n 1 | awk '{split($1,a,":"); print a[1]}'` if [ "$loopback" != "" ] then addrs=`ifconfig $loopback | grep inet | awk '{print $2}'` for addr in $addrs do echo vimage $vimage ifconfig $loopback $addr -alias vimage $vimage ifconfig $loopback $addr -alias if [ $? != 0 ] then vimage $vimage ifconfig $loopback inet6 $addr -alias fi done echo vimage $vimage ifconfig $loopback down vimage $vimage ifconfig $loopback down fi vimage $vimage kill -9 -1 2> /dev/null echo vimage -d $vimage vimage -d $vimage done # clean up temporary area rm -rf /tmp/pycore.* core-4.8/gui/annotations.tcl0000664000175000017500000006125412534327775013114 00000000000000# # Copyright 2007-2013 the Boeing Company. # See the LICENSE file included in this distribution. # # # Copyright 2007-2008 University of Zagreb, Croatia. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF # SUCH DAMAGE. # #****h* imunes/annotations.tcl # NAME # annotations.tcl -- oval, rectangle, text, background, ... # FUNCTION # This module is used for configuration/image annotations, such as oval, # rectangle, text, background or some other. #**** #****f* annotations.tcl/annotationConfig # NAME # annotationConfig -- # SYNOPSIS # annotationConfig $canvas $target # FUNCTION # . . . # INPUTS # * canvas -- # * target -- oval or rectangle object #**** proc annotationConfig { c target } { switch -exact -- [nodeType $target] { oval { popupAnnotationDialog $c $target "true" } rectangle { popupAnnotationDialog $c $target "true" } text { popupAnnotationDialog $c $target "true" } default { puts "Unknown type [nodeType $target] for target $target" } } redrawAll } #****f* annotations.tcl/popupOvalDialog # NAME # popupOvalDialog -- creates a new oval or modifies existing oval # SYNOPSIS # popupOvalDialog $canvas $modify $color $label $lcolor # FUNCTION # Called from: # - editor.tcl/button1-release when new oval is drawn # - annotationConfig which is called from popupConfigDialog bound to # Double-1 on various objects # - configureOval called from button3annotation procedure which creates # a menu for configuration and deletion (bound to 3 on oval, # rectangle and text) # INPUTS # * canvas -- # * modify -- create new oval "newoval" if modify=false or # modify an existing oval "newoval" if modify=true # * color -- oval color # * label -- label text # * lcolor -- label (text) color #**** #****f* annotations.tcl/destroyNewoval # NAME # destroyNewoval -- helper for popupOvalDialog and popupOvalApply # SYNOPSIS # destroyNewoval $canvas # FUNCTION # . . . # INPUTS # * canvas -- #**** proc destroyNewoval { c } { global newoval $c delete -withtags newoval set newoval "" } # oval/rectangle/text right-click menu proc button3annotation { type c x y } { if { $type == "oval" } { set procname "Oval" set item [lindex [$c gettags {oval && current}] 1] } elseif { $type == "rectangle" } { set procname "Rectangle" set item [lindex [$c gettags {rectangle && current}] 1] } elseif { $type == "label" } { set procname "Label" set item [lindex [$c gettags {label && current}] 1] } elseif { $type == "text" } { set procname "Text" set item [lindex [$c gettags {text && current}] 1] } elseif { $type == "marker" } { # erase markings $c delete -withtags {marker && current} return } else { # ??? return } if { $item == "" } { return } set menutext "$type $item" .button3menu delete 0 end .button3menu add command -label "Configure $menutext" \ -command "annotationConfig $c $item" .button3menu add command -label "Delete $menutext" \ -command "deleteAnnotation $c $type $item" set x [winfo pointerx .] set y [winfo pointery .] tk_popup .button3menu $x $y } proc deleteAnnotation { c type target } { global changed annotation_list $c delete -withtags "$type && $target" $c delete -withtags "new$type" set i [lsearch -exact $annotation_list $target] set annotation_list [lreplace $annotation_list $i $i] set changed 1 updateUndoLog } proc drawOval {oval} { global $oval defOvalColor zoom curcanvas global defTextFontFamily defTextFontSize set coords [getNodeCoords $oval] if { [llength $coords] < 4 } { puts "Bad coordinates for oval $oval" return } set x1 [expr {[lindex $coords 0] * $zoom}] set y1 [expr {[lindex $coords 1] * $zoom}] set x2 [expr {[lindex $coords 2] * $zoom}] set y2 [expr {[lindex $coords 3] * $zoom}] set color [lindex [lsearch -inline [set $oval] "color *"] 1] set label [lindex [lsearch -inline [set $oval] "label *"] 1] set lcolor [lindex [lsearch -inline [set $oval] "labelcolor *"] 1] set bordercolor [lindex [lsearch -inline [set $oval] "border *"] 1] set width [lindex [lsearch -inline [set $oval] "width *"] 1] set lx [expr $x1 + (($x2 - $x1) / 2)] set ly [expr ($y1 + 20)] if { $color == "" } { set color $defOvalColor } if { $lcolor == "" } { set lcolor black } if { $width == "" } { set width 0 } if { $bordercolor == "" } { set bordercolor black } # -outline red -stipple gray50 set newoval [.c create oval $x1 $y1 $x2 $y2 \ -fill $color -width $width -outline $bordercolor \ -tags "oval $oval annotation"] .c raise $newoval background set fontfamily [lindex [lsearch -inline [set $oval] "fontfamily *"] 1] set fontsize [lindex [lsearch -inline [set $oval] "fontsize *"] 1] if { $fontfamily == "" } { set fontfamily $defTextFontFamily } if { $fontsize == "" } { set fontsize $defTextFontSize } set newfontsize $fontsize set font [list "$fontfamily" $fontsize] set effects [lindex [lsearch -inline [set $oval] "effects *"] 1] .c create text $lx $ly -tags "oval $oval annotation" -text $label \ -justify center -font "$font $effects" -fill $lcolor setNodeCanvas $oval $curcanvas setType $oval "oval" } # Color helper for popupOvalDialog and popupLabelDialog proc popupColor { type l settext } { # popup color selection dialog with current color if { $type == "fg" } { set initcolor [$l cget -fg] } else { set initcolor [$l cget -bg] } set newcolor [tk_chooseColor -initialcolor $initcolor] # set fg or bg of the "l" label control if { $newcolor == "" } { return } if { $settext == "true" } { $l configure -text $newcolor -$type $newcolor } else { $l configure -$type $newcolor } } #****f* annotations.tcl/roundRect # NAME # roundRect -- Draw a rounded rectangle in the canvas. # Called from drawRect procedure # SYNOPSIS # roundRect $w $x0 $y0 $x3 $y3 $radius $args # FUNCTION # Creates a rounded rectangle as a smooth polygon in the canvas # and returns the canvas item number of the rounded rectangle. # INPUTS # * w -- Path name of the canvas # * x0, y0 -- Coordinates of the upper left corner, in pixels # * x3, y3 -- Coordinates of the lower right corner, in pixels # * radius -- Radius of the bend at the corners, in any form # acceptable to Tk_GetPixels # * args -- Other args suitable to a 'polygon' item on the canvas # Example: # roundRect .c 100 50 500 250 $rad -fill white -outline black -tags rectangle #**** proc roundRect { w x0 y0 x3 y3 radius args } { set r [winfo pixels $w $radius] set d [expr { 2 * $r }] # Make sure that the radius of the curve is less than 3/8 size of the box set maxr 0.75 if { $d > $maxr * ( $x3 - $x0 ) } { set d [expr { $maxr * ( $x3 - $x0 ) }] } if { $d > $maxr * ( $y3 - $y0 ) } { set d [expr { $maxr * ( $y3 - $y0 ) }] } set x1 [expr { $x0 + $d }] set x2 [expr { $x3 - $d }] set y1 [expr { $y0 + $d }] set y2 [expr { $y3 - $d }] set cmd [list $w create polygon] lappend cmd $x0 $y0 $x1 $y0 $x2 $y0 $x3 $y0 $x3 $y1 $x3 $y2 lappend cmd $x3 $y3 $x2 $y3 $x1 $y3 $x0 $y3 $x0 $y2 $x0 $y1 lappend cmd -smooth 1 return [eval $cmd $args] } proc drawRect {rectangle} { global $rectangle defRectColor zoom curcanvas global defTextFontFamily defTextFontSize set coords [getNodeCoords $rectangle] if {$coords == "" || [llength $coords] != 4 } { puts "Bad coordinates for rectangle $rectangle" return } set x1 [expr {[lindex $coords 0] * $zoom}] set y1 [expr {[lindex $coords 1] * $zoom}] set x2 [expr {[lindex $coords 2] * $zoom}] set y2 [expr {[lindex $coords 3] * $zoom}] set color [lindex [lsearch -inline [set $rectangle] "color *"] 1] set label [lindex [lsearch -inline [set $rectangle] "label *"] 1] set lcolor [lindex [lsearch -inline [set $rectangle] "labelcolor *"] 1] set bordercolor [lindex [lsearch -inline [set $rectangle] "border *"] 1] set width [lindex [lsearch -inline [set $rectangle] "width *"] 1] set rad [lindex [lsearch -inline [set $rectangle] "rad *"] 1] set lx [expr $x1 + (($x2 - $x1) / 2)] set ly [expr ($y1 + 20)] if { $color == "" } { set color $defRectColor } if { $lcolor == "" } { set lcolor black } if { $bordercolor == "" } { set bordercolor black } if { $width == "" } { set width 0 } # rounded-rectangle radius if { $rad == "" } { set rad 25 } # Boeing: allow borderless rectangles if { $width == 0 } { set newrect [roundRect .c $x1 $y1 $x2 $y2 $rad \ -fill $color -tags "rectangle $rectangle annotation"] } else { # end Boeing set newrect [roundRect .c $x1 $y1 $x2 $y2 $rad \ -fill $color -outline $bordercolor -width $width \ -tags "rectangle $rectangle annotation"] .c raise $newrect background # Boeing } # end Boeing set fontfamily [lindex [lsearch -inline [set $rectangle] "fontfamily *"] 1] set fontsize [lindex [lsearch -inline [set $rectangle] "fontsize *"] 1] if { $fontfamily == "" } { set fontfamily $defTextFontFamily } if { $fontsize == "" } { set fontsize $defTextFontSize } set newfontsize $fontsize set font [list "$fontfamily" $fontsize] set effects [lindex [lsearch -inline [set $rectangle] "effects *"] 1] .c create text $lx $ly -tags "rectangle $rectangle annotation" \ -text $label -justify center -font "$font $effects" -fill $lcolor setNodeCanvas $rectangle $curcanvas setType $rectangle "rectangle" } proc popupAnnotationDialog { c target modify } { global $target newrect newoval global width rad fontfamily fontsize global defFillColor defTextColor defTextFontFamily defTextFontSize # do nothing, return, if coords are empty if { $target == 0 \ && [$c coords "$newrect"] == "" \ && [$c coords "$newoval"] == "" } { return } if { $target == 0 } { set width 0 set rad 25 set coords [$c bbox "$newrect"] if { [$c coords "$newrect"] == "" } { set coords [$c bbox "$newoval"] set annotationType "oval" } else { set annotationType "rectangle" } set fontfamily "" set fontsize "" set effects "" set color "" set label "" set lcolor "" set bordercolor "" } else { set width [lindex [lsearch -inline [set $target] "width *"] 1] set rad [lindex [lsearch -inline [set $target] "rad *"] 1] set coords [$c bbox "$target"] set color [lindex [lsearch -inline [set $target] "color *"] 1] set fontfamily [lindex [lsearch -inline [set $target] "fontfamily *"] 1] set fontsize [lindex [lsearch -inline [set $target] "fontsize *"] 1] set effects [lindex [lsearch -inline [set $target] "effects *"] 1] set label [lindex [lsearch -inline [set $target] "label *"] 1] set lcolor [lindex [lsearch -inline [set $target] "labelcolor *"] 1] set bordercolor [lindex [lsearch -inline [set $target] "border *"] 1] set annotationType [nodeType $target] } if { $color == "" } { # Boeing: use default shape colors if { $annotationType == "oval" } { global defOvalColor set color $defOvalColor } elseif { $annotationType == "rectangle" } { global defRectColor set color $defRectColor } else { set color $defFillColor } } if { $lcolor == "" } { set lcolor black } if { $bordercolor == "" } { set bordercolor black } if { $width == "" } { set width 0 } if { $rad == "" } { set rad 25 } if { $fontfamily == "" } { set fontfamily $defTextFontFamily } if { $fontsize == "" } { set fontsize $defTextFontSize } set textBold 0 set textItalic 0 set textUnderline 0 if { [lsearch $effects bold ] != -1} {set textBold 1} if { [lsearch $effects italic ] != -1} {set textItalic 1} if { [lsearch $effects underline ] != -1} {set textUnderline 1} set x1 [lindex $coords 0] set y1 [lindex $coords 1] set x2 [lindex $coords 2] set y2 [lindex $coords 3] set xx [expr {abs($x2 - $x1)}] set yy [expr {abs($y2 - $y1)}] if { $xx > $yy } { set maxrad [expr $yy * 3.0 / 8.0] } else { set maxrad [expr $xx * 3.0 / 8.0] } set wi .popup catch {destroy $wi} toplevel $wi wm transient $wi . wm resizable $wi 0 0 if { $modify == "true" } { set windowtitle "Configure $annotationType $target" } else { set windowtitle "Add a new $annotationType" } wm title $wi $windowtitle frame $wi.text -relief groove -bd 2 frame $wi.text.lab label $wi.text.lab.name_label -text "Text for top of $annotationType:" entry $wi.text.lab.name -bg white -fg $lcolor -width 32 \ -validate focus -invcmd "focusAndFlash %W" $wi.text.lab.name insert 0 $label pack $wi.text.lab.name_label $wi.text.lab.name -side left -anchor w \ -padx 2 -pady 2 -fill x pack $wi.text.lab -side top -fill x frame $wi.text.format set fontmenu [tk_optionMenu $wi.text.format.fontmenu fontfamily "$fontfamily"] set sizemenu [tk_optionMenu $wi.text.format.fontsize fontsize "$fontsize"] # color selection if { $color == "" } { set color $defTextColor } button $wi.text.format.fg -text "Text color" -command \ "popupColor fg $wi.text.lab.name false" checkbutton $wi.text.format.bold -text "Bold" -variable textBold \ -command [list fontupdate $wi.text.lab.name bold] checkbutton $wi.text.format.italic -text "Italic" -variable textItalic \ -command [list fontupdate $wi.text.lab.name italic] checkbutton $wi.text.format.underline -text "Underline" \ -variable textUnderline \ -command [list fontupdate $wi.text.lab.name underline] if {$textBold == 1} { $wi.text.format.bold select } else { $wi.text.format.bold deselect } if {$textItalic == 1} { $wi.text.format.italic select } else { $wi.text.format.italic deselect } if {$textUnderline == 1} { $wi.text.format.underline select } else { $wi.text.format.underline deselect } pack $wi.text.format.fontmenu \ $wi.text.format.fontsize \ $wi.text.format.fg \ $wi.text.format.bold \ $wi.text.format.italic \ $wi.text.format.underline \ -side left -pady 2 pack $wi.text.format -side top -fill x pack $wi.text -side top -fill x fontupdate $wi.text.lab.name fontfamily $fontfamily fontupdate $wi.text.lab.name fontsize $fontsize $fontmenu delete 0 foreach f [lsort -dictionary [font families]] { $fontmenu add radiobutton -value "$f" -label $f \ -variable fontfamily \ -command [list fontupdate $wi.text.lab.name fontfamily $f] } $sizemenu delete 0 foreach f {8 9 10 11 12 14 16 18 20 22 24 26 28 36 48 72} { $sizemenu add radiobutton -value "$f" -label $f \ -variable fontsize \ -command [list fontupdate $wi.text.lab.name fontsize $f] } if { "$annotationType" == "rectangle" || "$annotationType" == "oval" } { # fill color, border color frame $wi.colors -relief groove -bd 2 # color selection controls label $wi.colors.label -text "Fill color:" label $wi.colors.color -text $color -width 8 \ -bg $color -fg $lcolor button $wi.colors.bg -text "Color" -command \ "popupColor bg $wi.colors.color true" pack $wi.colors.label $wi.colors.color $wi.colors.bg \ -side left -padx 2 -pady 2 -anchor w -fill x pack $wi.colors -side top -fill x # border selection controls frame $wi.border -relief groove -bd 2 label $wi.border.label -text "Border color:" label $wi.border.color -text $bordercolor -width 8 \ -bg $color -fg $bordercolor label $wi.border.width_label -text "Border width:" set widthMenu [tk_optionMenu $wi.border.width width "$width"] $widthMenu delete 0 foreach f {0 1 2 3 4 5 6 7 8 9 10} { $widthMenu add radiobutton -value $f -label $f \ -variable width } button $wi.border.fg -text "Color" -command \ "popupColor fg $wi.border.color true" pack $wi.border.label $wi.border.color $wi.border.fg \ $wi.border.width_label $wi.border.width \ $wi.border.fg $wi.border.color $wi.border.label \ -side left -padx 2 -pady 2 -anchor w -fill x pack $wi.border -side top -fill x } if { $annotationType == "rectangle" } { frame $wi.radius -relief groove -bd 2 scale $wi.radius.rad -from 0 -to [expr int($maxrad)] \ -length 400 -variable rad \ -orient horizontal -label "Radius of the bend at the corners: " \ -tickinterval [expr int($maxrad / 15) + 1] -showvalue true pack $wi.radius.rad -side left -padx 2 -pady 2 -anchor w -fill x pack $wi.radius -side top -fill x } # Add new oval or modify old one? if { $modify == "true" } { set cancelcmd "destroy $wi" set applytext "Modify $annotationType" } else { set cancelcmd "destroy $wi; destroyNewRect $c" set applytext "Add $annotationType" } frame $wi.butt -borderwidth 6 button $wi.butt.apply -text $applytext -command "popupAnnotationApply $c $wi $target $annotationType" button $wi.butt.cancel -text "Cancel" -command $cancelcmd bind $wi "$cancelcmd" bind $wi "popupAnnotationApply $c $wi $target $annotationType" pack $wi.butt.cancel $wi.butt.apply -side right pack $wi.butt -side bottom after 100 { grab .popup } return } # helper for popupOvalDialog and popupOvalApply proc destroyNewRect { c } { global newrect $c delete -withtags newrect set newrect "" } proc popupAnnotationApply { c wi target type } { global newrect newoval annotation_list global $target global changed global width rad global fontfamily fontsize textBold textItalic textUnderline # attributes set caption [string trim [$wi.text.lab.name get]] set labelcolor [$wi.text.lab.name cget -fg] set coords [$c coords "$target"] set iconcoords "iconcoords" if {"$type" == "rectangle" || "$type" == "oval" } { set color [$wi.colors.color cget -text] set bordercolor [$wi.border.color cget -text] } if { $target == 0 } { # Create a new annotation object set target [newObjectId annotation] global $target lappend annotation_list $target if {"$type" == "rectangle" } { set coords [$c coords $newrect] } elseif { "$type" == "oval" } { set coords [$c coords $newoval] } } else { set coords [getNodeCoords $target] } set $target {} lappend $iconcoords $coords lappend $target $iconcoords "label {$caption}" "labelcolor $labelcolor" \ "fontfamily {$fontfamily}" "fontsize $fontsize" if {"$type" == "rectangle" || "$type" == "oval" } { lappend $target "color $color" "width $width" "border $bordercolor" } if {"$type" == "rectangle" } { lappend $target "rad $rad" } set ef {} if {"$textBold" == 1} { lappend ef bold} if {"$textItalic" == 1} { lappend ef italic} if {"$textUnderline" == 1} { lappend ef underline} if {"$ef" != ""} { lappend $target "effects {$ef}"} # draw it if { $type == "rectangle" } { drawRect $target destroyNewRect $c } elseif { $type == "oval" } { drawOval $target destroyNewoval $c } elseif { $type == "text" } { drawText $target } set changed 1 updateUndoLog redrawAll destroy $wi } proc selectmarkEnter {c x y} { set isThruplot false if {$c == ".c"} { set obj [lindex [$c gettags current] 1] set type [nodeType $obj] if {$type != "oval" && $type != "rectangle"} { return } } else { set obj $c set c .c set isThruplot true } set bbox [$c bbox $obj] set x1 [lindex $bbox 0] set y1 [lindex $bbox 1] set x2 [lindex $bbox 2] set y2 [lindex $bbox 3] if {$isThruplot == true} { set x [expr $x+$x1] set y [expr $y+$y1] } set l 0 ;# left set r 0 ;# right set u 0 ;# up set d 0 ;# down set x [$c canvasx $x] set y [$c canvasy $y] if { $x < [expr $x1+($x2-$x1)/8.0]} { set l 1 } if { $x > [expr $x2-($x2-$x1)/8.0]} { set r 1 } if { $y < [expr $y1+($y2-$y1)/8.0]} { set u 1 } if { $y > [expr $y2-($y2-$y1)/8.0]} { set d 1 } if {$l==1} { if {$u==1} { $c config -cursor top_left_corner } elseif {$d==1} { $c config -cursor bottom_left_corner } else { $c config -cursor left_side } } elseif {$r==1} { if {$u==1} { $c config -cursor top_right_corner } elseif {$d==1} { $c config -cursor bottom_right_corner } else { $c config -cursor right_side } } elseif {$u==1} { $c config -cursor top_side } elseif {$d==1} { $c config -cursor bottom_side } else { $c config -cursor left_ptr } } proc selectmarkLeave {c x y} { global thruplotResize .bottom.textbox config -text {} # cursor options for thruplot resize if {$thruplotResize == true} { } else { # no resize update cursor $c config -cursor left_ptr } } proc textEnter { c x y } { global annotation_list global curcanvas set object [newObjectId annotation] set newtext [$c create text $x $y -text "" \ -anchor w -justify left -tags "text $object annotation"] set coords [$c coords "text && $object"] set iconcoords "iconcoords" global $object set $object {} setType $object "text" lappend $iconcoords $coords lappend $object $iconcoords lappend $object "label {}" setNodeCanvas $object $curcanvas lappend annotation_list $object popupAnnotationDialog $c $object "false" } proc drawText {text} { global $text defTextColor defTextFont defTextFontFamily defTextFontSize global zoom curcanvas newfontsize set coords [getNodeCoords $text] if { [llength $coords] < 2 } { puts "Bad coordinates for text $text" return } set x [expr {[lindex $coords 0] * $zoom}] set y [expr {[lindex $coords 1] * $zoom}] set color [lindex [lsearch -inline [set $text] "labelcolor *"] 1] if { $color == "" } { set color $defTextColor } set label [lindex [lsearch -inline [set $text] "label *"] 1] set fontfamily [lindex [lsearch -inline [set $text] "fontfamily *"] 1] set fontsize [lindex [lsearch -inline [set $text] "fontsize *"] 1] if { $fontfamily == "" } { set fontfamily $defTextFontFamily } if { $fontsize == "" } { set fontsize $defTextFontSize } set newfontsize $fontsize set font [list "$fontfamily" $fontsize] set effects [lindex [lsearch -inline [set $text] "effects *"] 1] set newtext [.c create text $x $y -text $label -anchor w \ -font "$font $effects" -justify left -fill $color \ -tags "text $text annotation"] .c addtag text withtag $newtext .c raise $text background setNodeCanvas $text $curcanvas setType $text "text" } proc fontupdate { label type args} { global fontfamily fontsize global textBold textItalic textUnderline if {"$textBold" == 1} {set bold "bold"} else {set bold {} } if {"$textItalic"} {set italic "italic"} else {set italic {} } if {"$textUnderline"} {set underline "underline"} else {set underline {} } switch $type { fontsize { set fontsize $args } fontfamily { set fontfamily "$args" } } set f [list "$fontfamily" $fontsize] lappend f "$bold $italic $underline" $label configure -font "$f" } proc drawAnnotation { obj } { switch -exact -- [nodeType $obj] { oval { drawOval $obj } rectangle { drawRect $obj } text { drawText $obj } } } # shift annotation coordinates by dx, dy; does not redraw the annotation proc moveAnnotation { obj dx dy } { set coords [getNodeCoords $obj] lassign $coords x1 y1 x2 y2 set pt1 "[expr {$x1 + $dx}] [expr {$y1 + $dy}]" if { [nodeType $obj] == "text" } { # shift one point setNodeCoords $obj $pt1 } else { ;# oval/rectangle # shift two points set pt2 "[expr {$x2 + $dx}] [expr {$y2 + $dy}]" setNodeCoords $obj "$pt1 $pt2" } } core-4.8/gui/api.tcl0000664000175000017500000031141512534327775011325 00000000000000# # CORE API # Copyright 2005-2013 the Boeing Company. # See the LICENSE file included in this distribution. # # author: Jeff Ahrenholz # # version of the API document that is used set CORE_API_VERSION 1.23 set DEFAULT_API_PORT 4038 set g_api_exec_num 100; # starting execution number # set scale for X/Y coordinate translation set XSCALE 1.0 set YSCALE 1.0 set XOFFSET 0 set YOFFSET 0 # current session; 0 is a new session set g_current_session 0 set g_session_dialog_hint 1 # this is an array of lists, with one array entry for each widget or callback, # and the entry is a list of execution numbers (for matching replies with # requests) array set g_execRequests { shell "" observer "" } # for a simulator, uncomment this line or cut/paste into debugger: # set XSCALE 4.0; set YSCALE 4.0; set XOFFSET 1800; set YOFFSET 300 array set nodetypes { 0 def 1 phys 2 xen 3 tbd 4 lanswitch 5 hub \ 6 wlan 7 rj45 8 tunnel 9 ktunnel 10 emane } array set regtypes { wl 1 mob 2 util 3 exec 4 gui 5 emul 6 } array set regntypes { 1 wl 2 mob 3 util 4 exec 5 gui 6 emul 7 relay 10 session } array set regtxttypes { wl "Wireless Module" mob "Mobility Module" \ util "Utility Module" exec "Execution Server" \ gui "Graphical User Interface" emul "Emulation Server" \ relay "Relay" } set DEFAULT_GUI_REG "gui core_2d_gui" array set eventtypes { definition_state 1 configuration_state 2 \ instantiation_state 3 runtime_state 4 \ datacollect_state 5 shutdown_state 6 \ event_start 7 event_stop 8 event_pause 9 \ event_restart 10 file_open 11 file_save 12 \ event_scheduled 31 } set CORE_STATES \ "NONE DEFINITION CONFIGURATION INSTANTIATION RUNTIME DATACOLLECT SHUTDOWN" set EXCEPTION_LEVELS \ "NONE FATAL ERROR WARNING NOTICE" # Event handler invoked for each message received by peer proc receiveMessage { channel } { global curcanvas showAPI set prmsg $showAPI set type 0 set flags 0 set len 0 set seq 0 #puts "API receive data." # disable the fileevent here, then reinstall the handler at the end fileevent $channel readable "" # channel closed if { [eof $channel] } { resetChannel channel 1 return } # # read first four bytes of message header set more_data 1 while { $more_data == 1 } { if { [catch { set bytes [read $channel 4] } e] } { # in tcl8.6 this occurs during shutdown #puts "channel closed: $e" break; } if { [fblocked $channel] == 1} { # 4 bytes not available yet break; } elseif { [eof $channel] } { resetChannel channel 1 break; } elseif { [string bytelength $bytes] == 0 } { # zero bytes read - parseMessageHeader would fail break; } # parse type/flags/length if { [parseMessageHeader $bytes type flags len] < 0 } { # Message header error break; } # read message data of specified length set bytes [read $channel $len] #if { $prmsg== 1} { # puts "read $len bytes (type=$type, flags=$flags, len=$len)..." #} # handle each message type switch -exact -- "$type" { 1 { parseNodeMessage $bytes $len $flags } 2 { parseLinkMessage $bytes $len $flags } 3 { parseExecMessage $bytes $len $flags $channel } 4 { parseRegMessage $bytes $len $flags $channel } 5 { parseConfMessage $bytes $len $flags $channel } 6 { parseFileMessage $bytes $len $flags $channel } 8 { parseEventMessage $bytes $len $flags $channel } 9 { parseSessionMessage $bytes $len $flags $channel } 10 { parseExceptionMessage $bytes $len $flags $channel; #7 { parseIfaceMessage $bytes $len $flags $channel } # } default { puts "Unknown Message = $type" } } # end switch } # end while # update the canvas catch { # this messes up widgets #raiseAll .c .c config -cursor left_ptr ;# otherwise we have hourglass/pirate update } if {$channel != -1 } { resetChannel channel 0 } } # # Open an API socket to the specified server:port, prompt user for retry # if specified; set the readable file event and parameters; # returns the channel name or -1 on error. # proc openAPIChannel { server port retry } { # use default values (localhost:4038) when none specified if { $server == "" || $server == 0 } { set server "localhost" } if { $port == 0 } { global DEFAULT_API_PORT set port $DEFAULT_API_PORT } # loop when retry is true set s -1 while { $s < 0 } { # TODO: fix this to remove lengthy timeout periods... # (need to convert all channel I/O to use async channel) # vwait doesn't work here, blocks on socket call #puts "Connecting to $server:$port..."; # verbose set svcstart [getServiceStartString] set e "This feature requires a connection to the CORE daemon.\n" set e "$e\nFailed to connect to $server:$port!\n" set e "$e\nHave you started the CORE daemon with" set e "$e '$svcstart'?" if { [catch {set s [socket $server $port]} ex] } { puts "\n$e\n (Error: $ex)" set s -1 if { ! $retry } { return $s; }; # error, don't retry } if { $s > 0 } { puts "connected." }; # verbose if { $retry } {; # prompt user with retry dialog if { $s < 0 } { set choice [tk_dialog .connect "Error" $e \ error 0 Retry "Start daemon..." Cancel] if { $choice == 2 } { return $s } ;# cancel if { $choice == 1 } { set sudocmd "gksudo" set cmd "core-daemon -d" if { [catch {exec $sudocmd $cmd & } e] } { puts "Error running '$sudocmd $cmd'!" } after 300 ;# allow time for daemon to start } # fall through for retry... } } }; # end while # now we have a valid socket, set up encoding and receive event fconfigure $s -blocking 0 -encoding binary -translation { binary binary } \ -buffering full -buffersize 4096 fileevent $s readable [list receiveMessage $s] return $s } # # Reinstall the receiveMessage event handler # proc resetChannel { channel_ptr close } { upvar 1 $channel_ptr channel if {$close == 1} { close $channel pluginChannelClosed $channel set $channel -1 } if { [catch { fileevent $channel readable \ [list receiveMessage $channel] } ] } { # may print error here } } # # Catch errors when flushing sockets # proc flushChannel { channel_ptr msg } { upvar 1 $channel_ptr channel if { [catch { flush $channel } err] } { puts "*** $msg: $err" set channel -1 return -1 } return 0 } # # CORE message header # proc parseMessageHeader { bytes type flags len } { # variables are passed by reference upvar 1 $type mytype upvar 1 $flags myflags upvar 1 $len mylen # # read the four-byte message header # if { [binary scan $bytes ccS mytype myflags mylen] != 3 } { puts "*** warning: message header error" return -1 } else { set mytype [expr {$mytype & 0xFF}]; # convert signed to unsigned set myflags [expr {$myflags & 0xFF}] if { $mylen == 0 } { puts "*** warning: zero length message header!" # empty the channel #set bytes [read $channel] return -1 } } return 0 } # # CORE API Node message TLVs # proc parseNodeMessage { data len flags } { global node_list curcanvas c router eid showAPI nodetypes CORE_DATA_DIR global XSCALE YSCALE XOFFSET YOFFSET deployCfgAPI_lock #puts "Parsing node message of length=$len, flags=$flags" set prmsg $showAPI set current 0 array set typenames { 1 num 2 type 3 name 4 ipv4_addr 5 mac_addr \ 6 ipv6_addr 7 model 8 emulsrv 10 session \ 32 xpos 33 ypos 34 canv \ 35 emuid 36 netid 37 services \ 48 lat 49 long 50 alt \ 66 icon 80 opaque } array set typesizes { num 4 type 4 name -1 ipv4_addr 4 ipv6_addr 16 \ mac_addr 8 model -1 emulsrv -1 session -1 \ xpos 2 ypos 2 canv 2 emuid 4 \ netid 4 services -1 lat 4 long 4 alt 4 \ icon -1 opaque -1 } array set vals { num 0 type 0 name "" ipv4_addr -1 ipv6_addr -1 \ mac_addr -1 model "" emulsrv "" session "" \ xpos 0 ypos 0 canv "" \ emuid -1 netid -1 services "" \ lat 0 long 0 alt 0 \ icon "" opaque "" } if { $prmsg==1 } { puts -nonewline "NODE(flags=$flags," } # # TLV parsing # while { $current < $len } { # TLV header if { [binary scan $data @${current}cc type length] != 2 } { puts "TLV header error" break } set length [expr {$length & 0xFF}]; # convert signed to unsigned if { $length == 0 } {; # prevent endless looping if { $type == 0 } { puts -nonewline "(extra padding)"; break } else { puts "Found zero-length TLV for type=$type, dropping."; break } } set pad [pad_32bit $length] # verbose debugging #puts "tlv type=$type length=$length pad=$pad current=$current" incr current 2 if {![info exists typenames($type)] } { ;# unknown TLV type if { $prmsg } { puts -nonewline "unknown=$type," } incr current $length continue } set typename $typenames($type) set size $typesizes($typename) # 32-bit and 64-bit vals pre-padded if { $size == 4 || $size == 8 } { incr current $pad } # read TLV data depending on size switch -exact -- "$size" { 2 { binary scan $data @${current}S vals($typename) } 4 { binary scan $data @${current}I vals($typename) } 8 { binary scan $data @${current}W vals($typename) } 16 { binary scan $data @${current}c16 vals($typename) } -1 { binary scan $data @${current}a${length} vals($typename) } } if { $size == -1 } { incr current $pad } ;# string vals post-padded if { $type == 6 } { incr current $pad } ;# 128-bit vals post-padded incr current $length # special handling of data here switch -exact -- "$typename" { ipv4_addr { array set vals [list $typename \ [ipv4ToString $vals($typename)] ] } mac_addr { array set vals [list $typename \ [macToString $vals($typename)] ] } ipv6_addr { array set vals [list $typename \ [ipv6ToString $vals($typename)] ] } xpos { array set vals [list $typename \ [expr { ($vals($typename) * $XSCALE) - $XOFFSET }] ] } ypos { array set vals [list $typename \ [expr { ($vals($typename) * $YSCALE) - $YOFFSET }] ] } } if { $prmsg } { puts -nonewline "$typename=$vals($typename)," } } if { $prmsg } { puts ") "} # # Execution # # TODO: enforce message parameters here if { ![info exists nodetypes($vals(type))] } { puts "NODE: invalid node type ($vals(type)), dropping"; return } set node "n$vals(num)" set node_id "$eid\_$node" if { [lsearch $node_list $node] == -1 } {; # check for node existance set exists false } else { set exists true } if { $vals(name) == "" } {; # make sure there is a node name set name $node if { $exists } { set name [getNodeName $node] } array set vals [list name $name] } if { $exists } { if { $flags == 1 } { puts "Node add msg but node ($node) already exists, dropping." return } } elseif { $flags != 1 } { puts -nonewline "Node modify/delete message but node ($node) does " puts "not exist dropping." return } if { $vals(icon) != "" } { set icon $vals(icon) if { [file pathtype $icon] == "relative" } { set icon "$CORE_DATA_DIR/icons/normal/$icon" } if { ![file exists $icon ] } { puts "Node icon '$vals(icon)' does not exist." array set vals [list icon ""] } else { array set vals [list icon $icon] } } global $node set wlans_needing_update { } if { $vals(emuid) != -1 } { # For Linux (FreeBSD populates ngnodeidmap in l3node.instantiate/ # buildInterface when the netgraph ID is known) # populate ngnodeidmap for later use with wireless; it is treated as # a hex value string (without the leading "0x") global ngnodeidmap foreach wlan [findWlanNodes $node] { if { ![info exists ngnodeidmap($eid\_$wlan)] } { set netid [string range $wlan 1 end] set emulation_type [lindex [getEmulPlugin $node] 1] # TODO: verify that this incr 1000 is for OpenVZ if { $emulation_type == "openvz" } { incr netid 1000 } set ngnodeidmap($eid\_$wlan) [format "%x" $netid] } if { ![info exists ngnodeidmap($eid\_$wlan-$node)] } { set ngnodeidmap($eid\_$wlan-$node) [format "%x" $vals(emuid)] lappend wlans_needing_update $wlan } } ;# end foreach wlan } # local flags: informational message that node was added or deleted if {[expr {$flags & 0x8}]} { if { ![info exists c] } { return } if {[expr {$flags & 0x1}] } { ;# add flag nodeHighlights $c $node on green after 3000 "nodeHighlights .c $node off green" } elseif {[expr {$flags & 0x2}] } { ;# delete flag nodeHighlights $c $node on black after 3000 "nodeHighlights .c $node off black" } # note: we may want to save other data passed in this message here # rather than just returning... return } # now we have all the information about this node switch -exact -- "$flags" { 0 { apiNodeModify $node vals } 1 { apiNodeCreate $node vals } 2 { apiNodeDelete $node } default { puts "NODE: unsupported flags ($flags)"; return } } } # # modify a node # proc apiNodeModify { node vals_ref } { global c eid zoom curcanvas upvar $vals_ref vals if { ![info exists c] } { return } ;# batch mode set draw 0 if { $vals(icon) != "" } { setCustomImage $node $vals(icon) set draw 1 } # move the node and its links if {$vals(xpos) != 0 && $vals(ypos) != 0} { moveNodeAbs $c $node [expr {$zoom * $vals(xpos)}] \ [expr {$zoom * $vals(ypos)}] } if { $vals(name) != "" } { setNodeName $node $vals(name) set draw 1 } if { $vals(services) != "" } { set services [split $vals(services) |] setNodeServices $node $services } # TODO: handle other optional on-screen data # lat, long, alt, heading, platform type, platform id if { $draw && [getNodeCanvas $node] == $curcanvas } { .c delete withtag "node && $node" .c delete withtag "nodelabel && $node" drawNode .c $node } } # # add a node # proc apiNodeCreate { node vals_ref } { global $node nodetypes node_list canvas_list curcanvas eid upvar $vals_ref vals # create GUI object set nodetype $nodetypes($vals(type)) set nodename $vals(name) if { $nodetype == "emane" } { set nodetype "wlan" } ;# special case - EMANE if { $nodetype == "def" || $nodetype == "xen" } { set nodetype "router" } newNode [list $nodetype $node] ;# use node number supplied from API message setNodeName $node $nodename if { $vals(canv) == "" } { setNodeCanvas $node $curcanvas } else { set canv $vals(canv) if { ![string is integer $canv] || $canv < 0 || $canv > 100} { puts "warning: invalid canvas '$canv' in Node message!" return } set canv "c$canv" if { [lsearch $canvas_list $canv] < 0 && $canv == "c0" } { # special case -- support old imn files with Canvas0 global $canv lappend canvas_list $canv set $canv {} setCanvasName $canv "Canvas0" set curcanvas $canv switchCanvas none } else { while { [lsearch $canvas_list $canv] < 0 } { set canvnew [newCanvas ""] switchCanvas none ;# redraw canvas tabs } } setNodeCanvas $node $canv } setNodeCoords $node "$vals(xpos) $vals(ypos)" lassign [getDefaultLabelOffsets [nodeType $node]] dx dy setNodeLabelCoords $node "[expr $vals(xpos) + $dx] [expr $vals(ypos) + $dy]" setNodeLocation $node $vals(emulsrv) if { $vals(icon) != "" } { setCustomImage $node $vals(icon) } drawNode .c $node set model $vals(model) if { $model != "" && $vals(type) < 4} { # set model only for (0 def 1 phys 2 xen 3 tbd) 4 lanswitch setNodeModel $node $model if { [lsearch -exact [getNodeTypeNames] $model] == -1 } { puts "warning: unknown node type '$model' in Node message!" } } if { $vals(services) != "" } { set services [split $vals(services) |] setNodeServices $node $services } if { $vals(type) == 7 } { ;# RJ45 node - used later to control linking netconfInsertSection $node [list model $vals(model)] } elseif { $vals(type) == 10 } { ;# EMANE node set section [list mobmodel coreapi ""] netconfInsertSection $node $section #set sock [lindex [getEmulPlugin $node] 2] #sendConfRequestMessage $sock $node "all" 0x1 -1 "" } elseif { $vals(type) == 6 } { ;# WLAN node if { $vals(opaque) != "" } { # treat opaque as a list to accomodate other data set i [lsearch $vals(opaque) "range=*"] if { $i != -1 } { set range [lindex $vals(opaque) $i] setNodeRange $node [lindex [split $range =] 1] } } } } # # delete a node # proc apiNodeDelete { node } { removeGUINode $node } # # CORE API Link message TLVs # proc parseLinkMessage { data len flags } { global router def_router_model eid global link_list node_list ngnodeidmap ngnodeidrmap showAPI execMode set prmsg $showAPI set current 0 set c .c #puts "Parsing link message of length=$len, flags=$flags" array set typenames { 1 node1num 2 node2num 3 delay 4 bw 5 per \ 6 dup 7 jitter 8 mer 9 burst 10 session \ 16 mburst 32 ltype 33 guiattr 34 uni \ 35 emuid1 36 netid 37 key \ 48 if1num 49 if1ipv4 50 if1ipv4mask 51 if1mac \ 52 if1ipv6 53 if1ipv6mask \ 54 if2num 55 if2ipv4 56 if2ipv4mask 57 if2mac \ 64 if2ipv6 65 if2ipv6mask } array set typesizes { node1num 4 node2num 4 delay 8 bw 8 per -1 \ dup -1 jitter 8 mer 2 burst 2 session -1 \ mburst 2 ltype 4 guiattr -1 uni 2 \ emuid1 4 netid 4 key 4 \ if1num 2 if1ipv4 4 if1ipv4mask 2 if1mac 8 \ if1ipv6 16 if1ipv6mask 2 \ if2num 2 if2ipv4 4 if2ipv4mask 2 if2mac 8 \ if2ipv6 16 if2ipv6mask 2 } array set vals { node1num -1 node2num -1 delay 0 bw 0 per "" \ dup "" jitter 0 mer 0 burst 0 session "" \ mburst 0 ltype 0 guiattr "" uni 0 \ emuid1 -1 netid -1 key -1 \ if1num -1 if1ipv4 -1 if1ipv4mask 24 if1mac -1 \ if1ipv6 -1 if1ipv6mask 64 \ if2num -1 if2ipv4 -1 if2ipv4mask 24 if2mac -1 \ if2ipv6 -1 if2ipv6mask 64 } set emuid1 -1 if { $prmsg==1 } { puts -nonewline "LINK(flags=$flags," } # # TLV parsing # while { $current < $len } { # TLV header if { [binary scan $data @${current}cc type length] != 2 } { puts "TLV header error" break } set length [expr {$length & 0xFF}]; # convert signed to unsigned if { $length == 0 } {; # prevent endless looping if { $type == 0 } { puts -nonewline "(extra padding)"; break } else { puts "Found zero-length TLV for type=$type, dropping."; break } } set pad [pad_32bit $length] # verbose debugging #puts "tlv type=$type length=$length pad=$pad current=$current" incr current 2 if {![info exists typenames($type)] } { ;# unknown TLV type if { $prmsg } { puts -nonewline "unknown=$type," } incr current $length continue } set typename $typenames($type) set size $typesizes($typename) # 32-bit and 64-bit vals pre-padded if { $size == 4 || $size == 8} { incr current $pad } # read TLV data depending on size switch -exact -- "$size" { 2 { binary scan $data @${current}S vals($typename) } 4 { binary scan $data @${current}I vals($typename) } 8 { binary scan $data @${current}W vals($typename) } 16 { binary scan $data @${current}c16 vals($typename) } -1 { binary scan $data @${current}a${length} vals($typename) } } incr current $length # special handling of data here switch -exact -- "$typename" { delay - jitter { if { $vals($typename) > 2000000 } { array set vals [list $typename 2000000] } } bw { if { $vals($typename) > 1000000000 } { array set vals [list $typename 0] } } per { if { $vals($typename) > 100 } { array set vals [list $typename 100] } } dup { if { $vals($typename) > 50 } { array set vals [list $typename 50] } } emuid1 { if { $emuid1 == -1 } { set emuid $vals($typename) } else { ;# this sets emuid2 if we already have emuid1 array set vals [list emuid2 $vals($typename) ] array set vals [list emuid1 $emuid1 ] } } if1ipv4 - if2ipv4 { array set vals [list $typename \ [ipv4ToString $vals($typename)] ] } if1mac - if2mac { array set vals [list $typename \ [macToString $vals($typename)] ] } if1ipv6 - if2ipv6 { array set vals [list $typename \ [ipv6ToString $vals($typename)] ] } } if { $prmsg } { puts -nonewline "$typename=$vals($typename)," } if { $size == 16 } { incr current $pad } ;# 128-bit vals post-padded if { $size == -1 } { incr current $pad } ;# string vals post-padded } if { $prmsg == 1 } { puts ") " } # perform some sanity checking of the link message if { $vals(node1num) == $vals(node2num) || \ $vals(node1num) < 0 || $vals(node2num) < 0 } { puts -nonewline "link message error - node1=$vals(node1num), " puts "node2=$vals(node2num)" return } # convert node number to node and check for node existance set node1 "n$vals(node1num)" set node2 "n$vals(node2num)" if { [lsearch $node_list $node1] == -1 || \ [lsearch $node_list $node2] == -1 } { puts "Node ($node1/$node2) in link message not found, dropping" return } # set IPv4 and IPv6 address if specified, otherwise may be automatic set prefix1 [chooseIfName $node1 $node2] set prefix2 [chooseIfName $node2 $node1] foreach i "1 2" { # set interface name/number if { $vals(if${i}num) == -1 } { set ifname [newIfc [set prefix${i}] [set node${i}]] set prefixlen [string length [set prefix${i}]] set if${i}num [string range $ifname $prefixlen end] array set vals [list if${i}num [set if${i}num]] } set ifname [set prefix${i}]$vals(if${i}num) array set vals [list if${i}name $ifname] # record IPv4/IPv6 addresses for newGUILink foreach j "4 6" { if { $vals(if${i}ipv${j}) != -1 } { setIfcIPv${j}addr [set node${i}] $ifname \ $vals(if${i}ipv${j})/$vals(if${i}ipv${j}mask) } } if { $vals(if${i}mac) != -1 } { setIfcMacaddr [set node${i}] $ifname $vals(if${i}mac) } } # adopt network address for WLAN (WLAN must be node 1) if { [nodeType $node1] == "wlan" } { set v4addr $vals(if2ipv4) if { $v4addr != -1 } { set v4net [ipv4ToNet $v4addr $vals(if2ipv4mask)] setIfcIPv4addr $node1 wireless "$v4net/$vals(if2ipv4mask)" } set v6addr $vals(if2ipv6) if { $v6addr != -1 } { set v6net [ipv6ToNet $v6addr $vals(if2ipv6mask)] setIfcIPv6addr $node1 wireless "${v6net}::0/$vals(if2ipv6mask)" } } if { $execMode == "batch" } { return ;# no GUI to update in batch mode } # treat 100% loss as link delete if { $flags == 0 && $vals(per) == 100 } { apiLinkDelete $node1 $node2 vals return } # now we have all the information about this node switch -exact -- "$flags" { 0 { apiLinkAddModify $node1 $node2 vals 0 } 1 { apiLinkAddModify $node1 $node2 vals 1 } 2 { apiLinkDelete $node1 $node2 vals } default { puts "LINK: unsupported flags ($flags)"; return } } } # # add or modify a link # if add flag is set, check if two nodes are part of same wlan, and do wlan # linkage, or add a wired link; otherwise modify wired/wireless link with # supplied parameters proc apiLinkAddModify { node1 node2 vals_ref add } { global eid defLinkWidth set c .c upvar $vals_ref vals if {$vals(key) > -1} { if { [nodeType $node1] == "tunnel" } { netconfInsertSection $node1 [list "tunnel-key" $vals(key)] } if { [nodeType $node2] == "tunnel" } { netconfInsertSection $node2 [list "tunnel-key" $vals(key)] } } # look for a wired link in the link list set wired_link [linkByPeers $node1 $node2] if { $wired_link != "" && $add == 0 } { ;# wired link exists, modify it #puts "modify wired link" if { $vals(uni) == 1 } { ;# unidirectional link effects message set peers [linkPeers $wired_link] if { $node1 == [lindex $peers 0] } { ;# downstream n1 <-- n2 set bw [list $vals(bw) [getLinkBandwidth $wired_link up]] set delay [list $vals(delay) [getLinkDelay $wired_link up]] set per [list $vals(per) [getLinkBER $wired_link up]] set dup [list $vals(dup) [getLinkBER $wired_link up]] set jitter [list $vals(jitter) [getLinkJitter $wired_link up]] } else { ;# upstream n1 --> n2 set bw [list [getLinkBandwidth $wired_link] $vals(bw)] set delay [list [getLinkDelay $wired_link] $vals(delay)] set per [list [getLinkBER $wired_link] $vals(per)] set dup [list [getLinkBER $wired_link] $vals(dup)] set jitter [list $vals(jitter) [getLinkJitter $wired_link]] } setLinkBandwidth $wired_link $bw setLinkDelay $wired_link $delay setLinkBER $wired_link $per setLinkDup $wired_link $dup setLinkJitter $wired_link $jitter } else { setLinkBandwidth $wired_link $vals(bw) setLinkDelay $wired_link $vals(delay) setLinkBER $wired_link $vals(per) setLinkDup $wired_link $vals(dup) setLinkJitter $wired_link $vals(jitter) } updateLinkLabel $wired_link updateLinkGuiAttr $wired_link $vals(guiattr) return # if add flag is set and a wired link already exists, assume wlan linkage # special case: rj45 model=1 means link via wireless } elseif {[nodeType $node1] == "rj45" || [nodeType $node2] == "rj45"} { if { [nodeType $node1] == "rj45" } { set rj45node $node1; set othernode $node2; } else { set rj45node $node2; set othernode $node1; } if { [netconfFetchSection $rj45node model] == 1 } { set wlan [findWlanNodes $othernode] if {$wlan != ""} {newGUILink $wlan $rj45node};# link rj4node to wlan } } # no wired link; determine if both nodes belong to the same wlan, and # link them; otherwise add a wired link if add flag is set set wlan $vals(netid) if { $wlan < 0 } { # WLAN not specified with netid, search for common WLAN set wlans1 [findWlanNodes $node1] set wlans2 [findWlanNodes $node2] foreach w $wlans1 { if { [lsearch -exact $wlans2 $w] < 0 } { continue } set wlan $w break } } if { $wlan < 0 } { ;# no common wlan if {$add == 1} { ;# add flag was set - add a wired link global g_newLink_ifhints set g_newLink_ifhints [list $vals(if1name) $vals(if2name)] newGUILink $node1 $node2 if { [getNodeCanvas $node1] != [getNodeCanvas $node2] } { set wired_link [linkByPeersMirror $node1 $node2] } else { set wired_link [linkByPeers $node1 $node2] } setLinkBandwidth $wired_link $vals(bw) setLinkDelay $wired_link $vals(delay) setLinkBER $wired_link $vals(per) setLinkDup $wired_link $vals(dup) setLinkJitter $wired_link $vals(jitter) updateLinkLabel $wired_link updateLinkGuiAttr $wired_link $vals(guiattr) # adopt link effects for WLAN (WLAN must be node 1) if { [nodeType $node1] == "wlan" } { setLinkBandwidth $node1 $vals(bw) setLinkDelay $node1 $vals(delay) setLinkBER $node1 $vals(per) } return } else { ;# modify link, but no wired link or common wlan! puts -nonewline "link modify message received, but no wired link" puts " or wlan for nodes $node1-$node2, dropping" return } } set wlan "n$wlan" drawWlanLink $node1 $node2 $wlan } # # delete a link # proc apiLinkDelete { node1 node2 vals_ref } { global eid upvar $vals_ref vals set c .c # look for a wired link in the link list set wired_link [linkByPeers $node1 $node2] if { $wired_link != "" } { removeGUILink $wired_link non-atomic return } set wlan $vals(netid) if { $wlan < 0 } { # WLAN not specified with netid, search for common WLAN set wlans1 [findWlanNodes $node1] set wlans2 [findWlanNodes $node2] foreach w $wlans1 { if { [lsearch -exact $wlans2 $w] < 0 } { continue } set wlan $w break } } if { $wlan < 0 } { puts "apiLinkDelete: no common WLAN!" return } set wlan "n$wlan" # look for wireless link on the canvas, remove GUI object $c delete -withtags "wlanlink && $node2 && $node1 && $wlan" $c delete -withtags "linklabel && $node2 && $node1 && $wlan" } # # CORE API Execute message TLVs # proc parseExecMessage { data len flags channel } { global node_list curcanvas c router eid showAPI global XSCALE YSCALE XOFFSET YOFFSET set prmsg $showAPI set current 0 # set default values set nodenum 0 set execnum 0 set exectime 0 set execcmd "" set execres "" set execstatus 0 set session "" if { $prmsg==1 } { puts -nonewline "EXEC(flags=$flags," } # parse each TLV while { $current < $len } { # TLV header set typelength [parseTLVHeader $data current] set type [lindex $typelength 0] set length [lindex $typelength 1] if { $length == 0 || $length == "" } { break } set pad [pad_32bit $length] # verbose debugging #puts "exec tlv type=$type length=$length pad=$pad current=$current" if { [expr {$current + $length + $pad}] > $len } { puts "error with EXEC message length (len=$len, TLV length=$length)" break } # TLV data switch -exact -- "$type" { 1 { incr current $pad binary scan $data @${current}I nodenum if { $prmsg==1 } { puts -nonewline "node=$nodenum/" } } 2 { incr current $pad binary scan $data @${current}I execnum if { $prmsg == 1} { puts -nonewline "exec=$execnum," } } 3 { incr current $pad binary scan $data @${current}I exectime if { $prmsg == 1} { puts -nonewline "time=$exectime," } } 4 { binary scan $data @${current}a${length} execcmd if { $prmsg == 1} { puts -nonewline "cmd=$execcmd," } incr current $pad } 5 { binary scan $data @${current}a${length} execres if { $prmsg == 1} { puts -nonewline "res=($length bytes)," } incr current $pad } 6 { incr current $pad binary scan $data @${current}I execstatus if { $prmsg == 1} { puts -nonewline "status=$execstatus," } } 10 { binary scan $data @${current}a${length} session if { $prmsg == 1} { puts -nonewline "session=$session," } incr current $pad } default { if { $prmsg == 1} { puts -nonewline "unknown=" } if { $prmsg == 1} { puts -nonewline "$type," } } } # end switch # advance current pointer incr current $length } if { $prmsg == 1 } { puts ") "} set node "n$nodenum" set node_id "$eid\_$node" # check for node existance if { [lsearch $node_list $node] == -1 } { puts "Execute message but node ($node) does not exist, dropping." return } global $node # Callback support - match execnum from response with original request, and # invoke type-specific callback global g_execRequests foreach type [array names g_execRequests] { set idx [lsearch $g_execRequests($type) $execnum] if { $idx > -1 } { set g_execRequests($type) \ [lreplace $g_execRequests($type) $idx $idx] exec_${type}_callback $node $execnum $execcmd $execres $execstatus return } } } # spawn interactive terminal proc exec_shell_callback { node execnum execcmd execres execstatus } { #puts "opening terminal for $node by running '$execres'" set title "CORE: [getNodeName $node] (console)" set term [get_term_prog false] set xi [string first "xterm -e" $execres] # shell callback already has xterm command, launch it using user-defined # term program (e.g. remote nodes 'ssh -X -f a.b.c.d xterm -e ...' if { $xi > -1 } { set execres [string replace $execres $xi [expr $xi+7] $term] if { [catch {exec sh -c "$execres" & } ] } { puts "Warning: failed to open terminal for $node" } return # no xterm command; execute shell callback in a terminal (e.g. local nodes) } elseif { \ [catch {eval exec $term "$execres" & } ] } { puts "Warning: failed to open terminal for $node: ($term $execres)" } } # # CORE API Register message TLVs # parse register message into plugin capabilities # proc parseRegMessage { data len flags channel } { global regntypes showAPI set prmsg $showAPI set current 0 set str 0 set session "" set fnhint "" set plugin_cap_list {} ;# plugin capabilities list if { $prmsg==1 } { puts -nonewline "REG(flags=$flags," } # parse each TLV while { $current < $len } { # TLV header if { [binary scan $data @${current}cc type length] != 2 } { puts "TLV header error" break } set length [expr {$length & 0xFF}]; # convert signed to unsigned if { $length == 0 } { # prevent endless looping if { $type == 0 } { puts -nonewline "(extra padding)" break } else { puts "Found zero-length TLV for type=$type, dropping." break } } set pad [pad_32bit $length] # verbose debugging #puts "tlv type=$type length=$length pad=$pad current=$current" incr current 2 # TLV data if { [info exists regntypes($type)] } { set plugin_type $regntypes($type) binary scan $data @${current}a${length} str if { $prmsg == 1} { puts -nonewline "$plugin_type=$str," } if { $type == 10 } { ;# session number set session $str } else { lappend plugin_cap_list "$plugin_type=$str" if { $plugin_type == "exec" } { set fnhint $str } } } else { if { $prmsg == 1} { puts -nonewline "unknown($type)," } } incr current $pad # end switch # advance current pointer incr current $length } if { $prmsg == 1 } { puts ") "} # reg message with session number indicates the sid of a session that # was just started from XML or Python script (via reg exec=scriptfile.py) if { $session != "" } { # The channel passed to here is soon after discarded for # sessions that are started from XML or Python scripts. This causes # an exception in the GUI when responding back to daemon if the # response is sent after the channel has been destroyed. Setting # the channel to -1 basically disables the GUI response to the daemon, # but it turns out the daemon does not need the response anyway. set channel -1 # assume session string only contains one session number connectShutdownSession connect $channel $session $fnhint return } set plugin [pluginByChannel $channel] if { [setPluginCapList $plugin $plugin_cap_list] < 0 } { return } # callback to refresh any open dialogs this message may refresh pluginsConfigRefreshCallback } proc parseConfMessage { data len flags channel } { global showAPI node_list MACHINE_TYPES set prmsg $showAPI set current 0 set str 0 set nodenum -1 set obj "" set tflags 0 set types {} set values {} set captions {} set bitmap {} set possible_values {} set groups {} set opaque {} set session "" set netid -1 if { $prmsg==1 } { puts -nonewline "CONF(flags=$flags," } # parse each TLV while { $current < $len } { set typelength [parseTLVHeader $data current] set type [lindex $typelength 0] set length [lindex $typelength 1] set pad [pad_32bit $length] if { $length == 0 || $length == "" } { # allow some zero-length string TLVs if { $type < 5 || $type > 9 } { break } } # verbose debugging #puts "tlv type=$type length=$length pad=$pad current=$current" # TLV data switch -exact -- "$type" { 1 { incr current $pad binary scan $data @${current}I nodenum if { $prmsg == 1} { puts -nonewline "node=$nodenum/" } } 2 { binary scan $data @${current}a${length} obj if { $prmsg == 1} { puts -nonewline "obj=$obj," } incr current $pad } 3 { binary scan $data @${current}S tflags if { $prmsg == 1} { puts -nonewline "cflags=$tflags," } } 4 { set type 0 set types {} if { $prmsg == 1} { puts -nonewline "types=" } # number of 16-bit values set types_len $length # get each 16-bit type value, add to list while {$types_len > 0} { binary scan $data @${current}S type if {$type > 0 && $type < 12} { lappend types $type if { $prmsg == 1} { puts -nonewline "$type/" } } incr current 2 incr types_len -2 } if { $prmsg == 1} { puts -nonewline "," } incr current -$length; # length incremented below incr current $pad } 5 { set values {} binary scan $data @${current}a${length} vals if { $prmsg == 1} { puts -nonewline "vals=$vals," } set values [split $vals |] incr current $pad } 6 { set captions {} binary scan $data @${current}a${length} capt if { $prmsg == 1} { puts -nonewline "capt=$capt," } set captions [split $capt |] incr current $pad } 7 { set bitmap {} binary scan $data @${current}a${length} bitmap if { $prmsg == 1} { puts -nonewline "bitmap," } incr current $pad } 8 { set possible_values {} binary scan $data @${current}a${length} pvals if { $prmsg == 1} { puts -nonewline "pvals=$pvals," } set possible_values [split $pvals |] incr current $pad } 9 { set groups {} binary scan $data @${current}a${length} groupsstr if { $prmsg == 1} { puts -nonewline "groups=$groupsstr," } set groups [split $groupsstr |] incr current $pad } 10 { binary scan $data @${current}a${length} session if { $prmsg == 1} { puts -nonewline "session=$session," } incr current $pad } 35 { incr current $pad binary scan $data @${current}I netid if { $prmsg == 1} { puts -nonewline "netid=$netid/" } } 80 { set opaque {} binary scan $data @${current}a${length} opaquestr if { $prmsg == 1} { puts -nonewline "opaque=$opaquestr," } set opaque [split $opaquestr |] incr current $pad } default { if { $prmsg == 1} { puts -nonewline "unknown=" } if { $prmsg == 1} { puts -nonewline "$type," } } } # end switch # advance current pointer incr current $length } if { $prmsg == 1 } { puts ") "} set objs_ok [concat "services session metadata emane" $MACHINE_TYPES] if { $nodenum > -1 } { set node "n$nodenum" } else { set node "" } # check for node existance if { [lsearch $node_list $node] == -1 } { if { [lsearch $objs_ok $obj] < 0 } { set msg "Configure message for $obj but node ($node) does" set msg "$msg not exist, dropping." puts $msg return } } else { global $node } # for handling node services # this could be improved, instead of checking for the hard-coded object # "services" and opaque data for service customization if { $obj == "services" } { if { $tflags & 0x2 } { ;# update flag if { $opaque != "" } { set services [lindex [split $opaque ":"] 1] set services [split $services ","] customizeServiceValues n$nodenum $values $services } # TODO: save services config with the node } elseif { $tflags & 0x1 } { ;# request flag # TODO: something else } else { popupServicesConfig $channel n$nodenum $types $values $captions \ $possible_values $groups $session } return # metadata received upon XML file load } elseif { $obj == "metadata" } { parseMetaData $values return # session options received upon XML file load } elseif { $obj == "session" && $tflags & 0x2 } { setSessionOptions $types $values return } # handle node machine-type profile if { [lsearch $MACHINE_TYPES $obj] != -1 } { if { $tflags == 0 } { popupNodeProfileConfig $channel n$nodenum $obj $types $values \ $captions $bitmap $possible_values $groups $session \ $opaque } else { puts -nonewline "warning: received Configure message for profile " puts "with unexpected flags!" } return } # update the configuration for a node without displaying dialog box if { $tflags & 0x2 } { if { $obj == "emane" && $node == "" } { set node [lindex [findWlanNodes ""] 0] } if { $node == "" } { puts "ignoring Configure message for $obj with no node" return } # this is similar to popupCapabilityConfigApply setCustomConfig $node $obj $types $values 0 if { $obj != "emane" && [nodeType $node] == "wlan"} { set section [list mobmodel coreapi $obj] netconfInsertSection $node $section } # configuration request - unhandled } elseif { $tflags & 0x1 } { # configuration response data from our request (from GUI plugin configure) } else { popupCapabilityConfig $channel n$nodenum $obj $types $values \ $captions $bitmap $possible_values $groups } } # process metadata received from Conf Message when loading XML proc parseMetaData { values } { global canvas_list annotation_list execMode g_comments foreach value $values { # data looks like this: "annotation a1={iconcoords {514.0 132.0...}}" lassign [splitKeyValue $value] key object_config lassign $key class object # metadata with no object name e.g. comments="Comment text" if { "$class" == "comments" } { set g_comments $object_config continue } elseif { "$class" == "global_options" } { foreach opt $object_config { lassign [split $opt =] key value setGlobalOption $key $value } continue } # metadata having class and object name if {"$class" == "" || $object == ""} { puts "warning: invalid metadata value '$value'" } if { "$class" == "canvas" } { if { [lsearch $canvas_list $object] < 0 } { lappend canvas_list $object } } elseif { "$class" == "annotation" } { if { [lsearch $annotation_list $object] < 0 } { lappend annotation_list $object } } else { puts "metadata parsing error: unknown object class $class" } global $object set $object $object_config } if { $execMode == "batch" } { return } switchCanvas none redrawAll } proc parseFileMessage { data len flags channel } { global showAPI node_list set prmsg $showAPI array set tlvnames { 1 num 2 name 3 mode 4 fno 5 type 6 sname \ 10 session 16 data 17 cdata } array set tlvsizes { num 4 name -1 mode -3 fno 2 type -1 sname -1 \ session -1 data -1 cdata -1 } array set defvals { num -1 name "" mode -1 fno -1 type "" sname "" \ session "" data "" cdata "" } if { $prmsg==1 } { puts -nonewline "FILE(flags=$flags," } array set vals [parseMessage $data $len $flags [array get tlvnames] \ [array get tlvsizes] [array get defvals]] if { $prmsg } { puts ") "} # hook scripts received in File Message if { [string range $vals(type) 0 4] == "hook:" } { global g_hook_scripts set state [string range $vals(type) 5 end] lappend g_hook_scripts [list $vals(name) $state $vals(data)] return } # required fields foreach t "num name data" { if { $vals($t) == $defvals($t) } { puts "Received File Message without $t, dropping."; return; } } # check for node existance set node "n$vals(num)" if { [lsearch $node_list $node] == -1 } { puts "File message but node ($node) does not exist, dropping." return } else { global $node } # service customization received in File Message if { [string range $vals(type) 0 7] == "service:" } { customizeServiceFile $node $vals(name) $vals(type) $vals(data) true } } proc parseEventMessage { data len flags channel } { global showAPI eventtypes g_traffic_start_opt execMode node_list set prmsg $showAPI set current 0 set nodenum -1 set eventtype -1 set eventname "" set eventdata "" set eventtime "" set session "" if { $prmsg==1 } { puts -nonewline "EVENT(flags=$flags," } # parse each TLV while { $current < $len } { set typelength [parseTLVHeader $data current] set type [lindex $typelength 0] set length [lindex $typelength 1] if { $length == 0 || $length == "" } { break } set pad [pad_32bit $length] # verbose debugging #puts "tlv type=$type length=$length pad=$pad current=$current" # TLV data switch -exact -- "$type" { 1 { incr current $pad binary scan $data @${current}I nodenum if { $prmsg == 1} { puts -nonewline "node=$nodenum," } } 2 { incr current $pad binary scan $data @${current}I eventtype if { $prmsg == 1} { set typestr "" foreach t [array names eventtypes] { if { $eventtypes($t) == $eventtype } { set typestr "-$t" break } } puts -nonewline "type=$eventtype$typestr," } } 3 { binary scan $data @${current}a${length} eventname if { $prmsg == 1} { puts -nonewline "name=$eventname," } incr current $pad } 4 { binary scan $data @${current}a${length} eventdata if { $prmsg == 1} { puts -nonewline "data=$eventdata," } incr current $pad } 5 { binary scan $data @${current}a${length} eventtime if { $prmsg == 1} { puts -nonewline "time=$eventtime," } incr current $pad } 10 { binary scan $data @${current}a${length} session if { $prmsg == 1} { puts -nonewline "session=$session," } incr current $pad } default { if { $prmsg == 1} { puts -nonewline "unknown=" } if { $prmsg == 1} { puts -nonewline "$type," } } } # end switch # advance current pointer incr current $length } if { $prmsg == 1 } { puts ") "} # TODO: take other actions here based on Event Message if { $eventtype == 4 } { ;# entered the runtime state if { $g_traffic_start_opt == 1 } { startTrafficScripts } if { $execMode == "batch" } { global g_current_session g_abort_session if {$g_abort_session} { puts "Current session ($g_current_session) aborted. Disconnecting." shutdownSession } else { puts "Session running. Session id is $g_current_session. Disconnecting." } exit.real } } elseif { $eventtype == 6 } { ;# shutdown state set name [lindex [getEmulPlugin "*"] 0] if { [getAssignedRemoteServers] == "" } { # start a new session if not distributed # otherwise we need to allow time for node delete messages # from other servers pluginConnect $name disconnect 1 pluginConnect $name connect 1 } } elseif { $eventtype >= 7 || $eventtype <= 10 } { if { [string range $eventname 0 8] == "mobility:" } { set node "n$nodenum" if {[lsearch $node_list $node] == -1} { puts "Event message with unknown node %nodenum." return } handleMobilityScriptEvent $node $eventtype $eventdata $eventtime } } } proc parseSessionMessage { data len flags channel } { global showAPI g_current_session g_session_dialog_hint execMode set prmsg $showAPI set current 0 set sessionids {} set sessionnames {} set sessionfiles {} set nodecounts {} set sessiondates {} set thumbs {} set sessionopaque {} if { $prmsg==1 } { puts -nonewline "SESSION(flags=$flags," } # parse each TLV while { $current < $len } { set typelength [parseTLVHeader $data current] set type [lindex $typelength 0] set length [lindex $typelength 1] if { $length == 0 || $length == "" } { puts "warning: zero-length TLV, discarding remainder of message!" break } set pad [pad_32bit $length] # verbose debugging #puts "tlv type=$type length=$length pad=$pad current=$current" # TLV data switch -exact -- "$type" { 1 { set sessionids {} binary scan $data @${current}a${length} sids if { $prmsg == 1} { puts -nonewline "sids=$sids," } set sessionids [split $sids |] incr current $pad } 2 { set sessionnames {} binary scan $data @${current}a${length} snames if { $prmsg == 1} { puts -nonewline "names=$snames," } set sessionnames [split $snames |] incr current $pad } 3 { set sessionfiles {} binary scan $data @${current}a${length} sfiles if { $prmsg == 1} { puts -nonewline "files=$sfiles," } set sessionfiles [split $sfiles |] incr current $pad } 4 { set nodecounts {} binary scan $data @${current}a${length} ncs if { $prmsg == 1} { puts -nonewline "ncs=$ncs," } set nodecounts [split $ncs |] incr current $pad } 5 { set sessiondates {} binary scan $data @${current}a${length} sdates if { $prmsg == 1} { puts -nonewline "dates=$sdates," } set sessiondates [split $sdates |] incr current $pad } 6 { set thumbs {} binary scan $data @${current}a${length} th if { $prmsg == 1} { puts -nonewline "thumbs=$th," } set thumbs [split $th |] incr current $pad } 10 { set sessionopaque {} binary scan $data @${current}a${length} sessionopaque if { $prmsg == 1} { puts -nonewline "$sessionopaque," } incr current $pad } default { if { $prmsg == 1} { puts -nonewline "unknown=" } if { $prmsg == 1} { puts -nonewline "$type," } } } # end switch # advance current pointer incr current $length } if { $prmsg == 1 } { puts ") "} if {$g_current_session == 0} { # set the current session to the channel port number set current_session [lindex [fconfigure $channel -sockname] 2] } else { set current_session $g_current_session } if {[lsearch $sessionids $current_session] == -1} { puts -nonewline "*** warning: current session ($g_current_session) " puts "not found in session list: $sessionids" } set orig_session_choice $g_current_session set g_current_session $current_session setGuiTitle "" if {$execMode == "closebatch"} { # we're going to close some session, so this is expected global g_session_choice if {[lsearch $sessionids $g_session_choice] == -1} { puts -nonewline "*** warning: current session ($g_session_choice) " puts "not found in session list: $sessionids" } else { set flags 0x2 ;# delete flag set sid $g_session_choice set name "" set f "" set nodecount "" set thumb "" set user "" sendSessionMessage $channel $flags $sid $name $f $nodecount $thumb $user puts "Session shutdown message sent." } exit.real } if {$orig_session_choice == 0 && [llength $sessionids] == 1} { # we just started up and only the current session exists set g_session_dialog_hint 0 return } if {$execMode == "batch"} { puts "Another session is active." exit.real } if { $g_session_dialog_hint } { popupSessionConfig $channel $sessionids $sessionnames $sessionfiles \ $nodecounts $sessiondates $thumbs $sessionopaque } set g_session_dialog_hint 0 } # parse message TLVs given the possible TLV names and sizes # default values are supplied in defaultvals, parsed values are returned proc parseMessage { data len flags tlvnamesl tlvsizesl defaultvalsl } { global showAPI set prmsg $showAPI array set tlvnames $tlvnamesl array set tlvsizes $tlvsizesl array set vals $defaultvalsl ;# this array is returned set current 0 while { $current < $len } { set typelength [parseTLVHeader $data current] set type [lindex $typelength 0] set length [lindex $typelength 1] if { $length == 0 || $length == "" } { break } set pad [pad_32bit $length] if {![info exists tlvnames($type)] } { ;# unknown TLV type if { $prmsg } { puts -nonewline "unknown=$type," } incr current $length continue } set tlvname $tlvnames($type) set size $tlvsizes($tlvname) # 32-bit and 64-bit vals pre-padded if { $size == 4 || $size == 8 } { incr current $pad } # read TLV data depending on size switch -exact -- "$size" { 2 { binary scan $data @${current}S vals($tlvname) } 4 { binary scan $data @${current}I vals($tlvname) } 8 { binary scan $data @${current}W vals($tlvname) } 16 { binary scan $data @${current}c16 vals($tlvname) } -1 { binary scan $data @${current}a${length} vals($tlvname) } } if { $size == -1 } { incr current $pad } ;# string vals post-padded if { $type == 6 } { incr current $pad } ;# 128-bit vals post-padded incr current $length if { $prmsg } { puts -nonewline "$tlvname=$vals($tlvname)," } } return [array get vals] } proc parseExceptionMessage { data len flags channel } { global showAPI set prmsg $showAPI array set typenames { 1 num 2 sess 3 level 4 src 5 date 6 txt 10 opaque } array set typesizes { num 4 sess -1 level 2 src -1 date -1 txt -1 \ opaque -1 } array set defvals { num -1 sess "" level -1 src "" date "" txt "" opaque ""} if { $prmsg==1 } { puts -nonewline "EXCEPTION(flags=$flags," } array set vals [parseMessage $data $len $flags [array get typenames] \ [array get typesizes] [array get defvals]] if { $prmsg == 1 } { puts ") "} if { $vals(level) == $defvals(level) } { puts "Exception Message received without an exception level."; return; } receiveException [array get vals] } proc sendNodePosMessage { channel node nodeid x y wlanid force } { global showAPI set prmsg $showAPI if { $channel == -1 } { set channel [lindex [getEmulPlugin $node] 2] if { $channel == -1 } { return } } set node_num [string range $node 1 end] set x [format "%u" [expr int($x)]] set y [format "%u" [expr int($y)]] set len [expr 8+4+4] ;# node number, x, y if {$nodeid > -1} { incr len 8 } if {$wlanid > -1} { incr len 8 } if {$force == 1 } { set crit 0x4 } else { set crit 0x0 } #puts "sending [expr $len+4] bytes: $nodeid $x $y $wlanid" if { $prmsg == 1 } { puts -nonewline ">NODE(flags=$crit,$node,x=$x,y=$y" } set msg [binary format ccSc2sIc2Sc2S \ 1 $crit $len \ {1 4} 0 $node_num \ {0x20 2} $x \ {0x21 2} $y ] set msg2 "" set msg3 "" if { $nodeid > -1 } { if { $prmsg == 1 } { puts -nonewline ",emuid=$nodeid" } set msg2 [binary format c2sI {0x23 4} 0 $nodeid] } if { $wlanid > -1 } { if { $prmsg == 1 } { puts -nonewline ",netid=$wlanid" } set msg3 [binary format c2sI {0x24 4} 0 $wlanid] } if { $prmsg == 1 } { puts ")" } puts -nonewline $channel $msg$msg2$msg3 flushChannel channel "Error sending node position" } # build a new node proc sendNodeAddMessage { channel node } { global showAPI CORE_DATA_DIR set prmsg $showAPI set len [expr {8+8+4+4}]; # node number, type, x, y set ipv4 0 set ipv6 0 set macstr "" set wireless 0 # type, name set type [getNodeTypeAPI $node] set model [getNodeModel $node] set model_len [string length $model] set model_pad_len [pad_32bit $model_len] set model_pad [binary format x$model_pad_len] set name [getNodeName $node] set name_len [string length $name] set name_pad_len [pad_32bit $name_len] set name_pad [binary format x$name_pad_len] incr len [expr { 2+$name_len+$name_pad_len}] if {$model_len > 0} { incr len [expr {2+$model_len+$model_pad_len }] } set node_num [string range $node 1 end] # fixup node type for EMANE-enabled WLAN nodes set opaque "" if { [isEmane $node] } { set type 0xA } # emulation server (node location) set emusrv [getNodeLocation $node] set emusrv_len [string length $emusrv] set emusrv_pad_len [pad_32bit $emusrv_len] set emusrv_pad [binary format x$emusrv_pad_len] if { $emusrv_len > 0 } { incr len [expr {2+$emusrv_len+$emusrv_pad_len } ] } # canvas set canv [getNodeCanvas $node] if { $canv != "c1" } { set canv [string range $canv 1 end] ;# convert "c2" to "2" incr len 4 } else { set canv "" } # services set svc [getNodeServices $node false] set svc [join $svc "|"] set svc_len [string length $svc] set svc_pad_len [pad_32bit $svc_len] set svc_pad [binary format x$svc_pad_len] if { $svc_len > 0 } { incr len [expr {2+$svc_len+$svc_pad_len } ] } # icon set icon [getCustomImage $node] if { [file dirname $icon] == "$CORE_DATA_DIR/icons/normal" } { set icon [file tail $icon] ;# don't include standard icon path } set icon_len [string length $icon] set icon_pad_len [pad_32bit $icon_len] set icon_pad [binary format x$icon_pad_len] if { $icon_len > 0 } { incr len [expr {2+$icon_len+$icon_pad_len} ] } # opaque data set opaque_len [string length $opaque] set opaque_pad_len [pad_32bit $opaque_len] set opaque_pad [binary format x$opaque_pad_len] if { $opaque_len > 0 } { incr len [expr {2+$opaque_len+$opaque_pad_len} ] } # length must be calculated before this if { $prmsg == 1 } { puts -nonewline ">NODE(flags=add/str,$node,type=$type,$name," } set msg [binary format c2Sc2sIc2sIcc \ {0x1 0x11} $len \ {0x1 4} 0 $node_num \ {0x2 4} 0 $type \ 0x3 $name_len ] puts -nonewline $channel $msg$name$name_pad # IPv4 address if { $ipv4 > 0 } { if { $prmsg == 1 } { puts -nonewline "$ipv4str," } set msg [binary format c2sI {0x4 4} 0 $ipv4] puts -nonewline $channel $msg } # MAC address if { $macstr != "" } { if { $prmsg == 1 } { puts -nonewline "$macstr," } set mac [join [split $macstr ":"] ""] puts -nonewline $channel [binary format c2x2W {0x5 8} 0x$mac] } # IPv6 address if { $ipv6 != 0 } { if { $prmsg == 1 } { puts -nonewline "$ipv6str," } set msg [binary format c2 {0x6 16} ] puts -nonewline $channel $msg foreach ipv6w [split $ipv6 ":"] { set msg [binary format S 0x$ipv6w] puts -nonewline $channel $msg } puts -nonewline $channel [binary format x2]; # 2 bytes padding } # model type if { $model_len > 0 } { set mh [binary format cc 0x7 $model_len] puts -nonewline $channel $mh$model$model_pad if { $prmsg == 1 } { puts -nonewline "m=$model," } } # emulation server if { $emusrv_len > 0 } { puts -nonewline $channel [binary format cc 0x8 $emusrv_len] puts -nonewline $channel $emusrv$emusrv_pad if { $prmsg == 1 } { puts -nonewline "srv=$emusrv," } } # X,Y coordinates set coords [getNodeCoords $node] set x [format "%u" [expr int([lindex $coords 0])]] set y [format "%u" [expr int([lindex $coords 1])]] set msg [binary format c2Sc2S {0x20 2} $x {0x21 2} $y] puts -nonewline $channel $msg # canvas if { $canv != "" } { if { $prmsg == 1 } { puts -nonewline "canvas=$canv," } set msg [binary format c2S {0x22 2} $canv] puts -nonewline $channel $msg } if { $prmsg == 1 } { puts -nonewline "x=$x,y=$y" } # services if { $svc_len > 0 } { puts -nonewline $channel [binary format cc 0x25 $svc_len] puts -nonewline $channel $svc$svc_pad if { $prmsg == 1 } { puts -nonewline ",svc=$svc" } } # icon if { $icon_len > 0 } { puts -nonewline $channel [binary format cc 0x42 $icon_len] puts -nonewline $channel $icon$icon_pad if { $prmsg == 1 } { puts -nonewline ",icon=$icon" } } # opaque data if { $opaque_len > 0 } { puts -nonewline $channel [binary format cc 0x50 $opaque_len] puts -nonewline $channel $opaque$opaque_pad if { $prmsg == 1 } { puts -nonewline ",opaque=$opaque" } } if { $prmsg == 1 } { puts ")" } flushChannel channel "Error sending node add" } # delete a node proc sendNodeDelMessage { channel node } { global showAPI set prmsg $showAPI set len 8; # node number set node_num [string range $node 1 end] if { $prmsg == 1 } { puts ">NODE(flags=del/str,$node_num)" } set msg [binary format c2Sc2sI \ {0x1 0x12} $len \ {0x1 4} 0 $node_num ] puts -nonewline $channel $msg flushChannel channel "Error sending node delete" } # send a message to build, modify, or delete a link # type should indicate add/delete/link/unlink proc sendLinkMessage { channel link type {sendboth true} } { global showAPI set prmsg $showAPI set node1 [lindex [linkPeers $link] 0] set node2 [lindex [linkPeers $link] 1] set if1 [ifcByPeer $node1 $node2]; set if2 [ifcByPeer $node2 $node1] if { [nodeType $node1] == "pseudo" } { return } ;# never seems to occur if { [nodeType $node2] == "pseudo" } { set mirror2 [getLinkMirror $node2] set node2 [getNodeName $node2] if { [string range $node1 1 end] > [string range $node2 1 end] } { return ;# only send one link message (for two pseudo-links) } set if2 [ifcByPeer $node2 $mirror2] } set node1_num [string range $node1 1 end] set node2_num [string range $node2 1 end] # flag for sending unidirectional link messages set uni 0 if { $sendboth && [isLinkUni $link] } { set uni 1 } # set flags and link message type from supplied type parameter set flags 0 set ltype 1 ;# add/delete a link (not wireless link/unlink) set netid -1 if { $type == "add" || $type == "link" } { set flags 1 } elseif { $type == "delete" || $type == "unlink" } { set flags 2 } if { $type == "link" || $type == "unlink" } { set ltype 0 ;# a wireless link/unlink event set tmp [getLinkOpaque $link net] if { $tmp != "" } { set netid [string range $tmp 1 end] } } set key "" if { [nodeType $node1] == "tunnel" } { set key [netconfFetchSection $node1 "tunnel-key"] if { $key == "" } { set key 1 } } if {[nodeType $node2] == "tunnel" } { set key [netconfFetchSection $node2 "tunnel-key"] if { $key == "" } { set key 1 } } if { $prmsg == 1 } { puts -nonewline ">LINK(flags=$flags,$node1_num-$node2_num," } # len = node1num, node2num, type set len [expr {8+8+8}] set delay [getLinkDelay $link] if { $delay == "" } { set delay 0 } set jitter [getLinkJitter $link] if { $jitter == "" } { set jitter 0 } set bw [getLinkBandwidth $link] if { $bw == "" } { set bw 0 } set per [getLinkBER $link]; # PER and BER if { $per == "" } { set per 0 } set per_len 0 set per_msg [buildStringTLV 0x5 $per per_len] set dup [getLinkDup $link] if { $dup == "" } { set dup 0 } set dup_len 0 set dup_msg [buildStringTLV 0x6 $dup dup_len] if { $type != "delete" } { incr len [expr {12+12+$per_len+$dup_len+12}] ;# delay,bw,per,dup,jitter if {$prmsg==1 } { puts -nonewline "$delay,$bw,$per,$dup,$jitter," } } # TODO: mer, burst, mburst if { $prmsg == 1 } { puts -nonewline "type=$ltype," } if { $uni } { incr len 4 if { $prmsg == 1 } { puts -nonewline "uni=$uni," } } if { $netid > -1 } { incr len 8 if { $prmsg == 1 } { puts -nonewline "netid=$netid," } } if { $key != "" } { incr len 8 if { $prmsg == 1 } { puts -nonewline "key=$key," } } set if1num [ifcNameToNum $if1]; set if2num [ifcNameToNum $if2] set if1ipv4 0; set if2ipv4 0; set if1ipv6 ""; set if2ipv6 ""; set if1ipv4mask 0; set if2ipv4mask 0; set if1ipv6mask ""; set if2ipv6mask ""; set if1mac ""; set if2mac ""; if { $if1num >= 0 && ([[typemodel $node1].layer] == "NETWORK" || \ [nodeType $node1] == "tunnel") } { incr len 4 if { $prmsg == 1 } { puts -nonewline "if1n=$if1num," } if { $type != "delete" } { getIfcAddrs $node1 $if1 if1ipv4 if1ipv6 if1mac if1ipv4mask \ if1ipv6mask len } } if { $if2num >= 0 && ([[typemodel $node2].layer] == "NETWORK" || \ [nodeType $node2] == "tunnel") } { incr len 4 if { $prmsg == 1 } { puts -nonewline "if2n=$if2num," } if { $type != "delete" } { getIfcAddrs $node2 $if2 if2ipv4 if2ipv6 if2mac if2ipv4mask \ if2ipv6mask len } } # start building the binary message on channel # length must be calculated before this set msg [binary format ccSc2sIc2sI \ {0x2} $flags $len \ {0x1 4} 0 $node1_num \ {0x2 4} 0 $node2_num ] puts -nonewline $channel $msg if { $type != "delete" } { puts -nonewline $channel [binary format c2sW {0x3 8} 0 $delay] puts -nonewline $channel [binary format c2sW {0x4 8} 0 $bw] puts -nonewline $channel $per_msg puts -nonewline $channel $dup_msg puts -nonewline $channel [binary format c2sW {0x7 8} 0 $jitter] } # TODO: mer, burst, mburst # link type puts -nonewline $channel [binary format c2sI {0x20 4} 0 $ltype] # unidirectional flag if { $uni } { puts -nonewline $channel [binary format c2S {0x22 2} $uni] } # network ID if { $netid > -1 } { puts -nonewline $channel [binary format c2sI {0x24 4} 0 $netid] } if { $key != "" } { puts -nonewline $channel [binary format c2sI {0x25 4} 0 $key] } # interface 1 info if { $if1num >= 0 && ([[typemodel $node1].layer] == "NETWORK" || \ [nodeType $node1] == "tunnel") } { puts -nonewline $channel [ binary format c2S {0x30 2} $if1num ] } if { $if1ipv4 > 0 } { puts -nonewline $channel [binary format c2sIc2S \ {0x31 4} 0 $if1ipv4 {0x32 2} $if1ipv4mask ] } if { $if1mac != "" } { set if1mac [join [split $if1mac ":"] ""] puts -nonewline $channel [binary format c2x2W {0x33 8} 0x$if1mac] } if {$if1ipv6 != ""} { puts -nonewline $channel [binary format c2 {0x34 16}] foreach ipv6w [split $if1ipv6 ":"] { puts -nonewline $channel \ [binary format S 0x$ipv6w] } puts -nonewline $channel [binary format x2c2S {0x35 2} $if1ipv6mask] } # interface 2 info if { $if2num >= 0 && ([[typemodel $node2].layer] == "NETWORK" || \ [nodeType $node2] == "tunnel") } { puts -nonewline $channel [ binary format c2S {0x36 2} $if2num ] } if { $if2ipv4 > 0 } { puts -nonewline $channel [binary format c2sIc2S \ {0x37 4} 0 $if2ipv4 {0x38 2} $if2ipv4mask ] } if { $if2mac != "" } { set if2mac [join [split $if2mac ":"] ""] puts -nonewline $channel [binary format c2x2W {0x39 8} 0x$if2mac] } if {$if2ipv6 != ""} { puts -nonewline $channel [binary format c2 {0x40 16}] foreach ipv6w [split $if2ipv6 ":"] { puts -nonewline $channel \ [binary format S 0x$ipv6w] } puts -nonewline $channel [binary format x2c2S {0x41 2} $if2ipv6mask] } if { $prmsg==1 } { puts ")" } flushChannel channel "Error sending link message" ########################################################## # send a second Link Message for unidirectional link effects if { $uni < 1 } { return } # first calculate length and possibly print the message set flags 0 if { $prmsg == 1 } { puts -nonewline ">LINK(flags=$flags,$node2_num-$node1_num," } set len [expr {8+8+8}] ;# len = node2num, node1num (swapped), type set delay [getLinkDelay $link up] if { $delay == "" } { set delay 0 } set jitter [getLinkJitter $link up] if { $jitter == "" } { set jitter 0 } set bw [getLinkBandwidth $link up] if { $bw == "" } { set bw 0 } set per [getLinkBER $link up]; # PER and BER if { $per == "" } { set per 0 } set per_len 0 set per_msg [buildStringTLV 0x5 $per per_len] set dup [getLinkDup $link up] if { $dup == "" } { set dup 0 } set dup_len 0 set dup_msg [buildStringTLV 0x6 $dup dup_len] incr len [expr {12+12+$per_len+$dup_len+12}] ;# delay,bw,per,dup,jitter if {$prmsg==1 } { puts -nonewline "$delay,$bw,$per,$dup,$jitter," } if { $prmsg == 1 } { puts -nonewline "type=$ltype," } incr len 4 ;# unidirectional flag if { $prmsg == 1 } { puts -nonewline "uni=$uni," } # note that if1num / if2num are reversed here due to reversed node nums if { $if2num >= 0 && ([[typemodel $node2].layer] == "NETWORK" || \ [nodeType $node2] == "tunnel") } { incr len 4 if { $prmsg == 1 } { puts -nonewline "if1n=$if2num," } } if { $if1num >= 0 && ([[typemodel $node1].layer] == "NETWORK" || \ [nodeType $node1] == "tunnel") } { incr len 4 if { $prmsg == 1 } { puts -nonewline "if2n=$if1num," } } # build and send the link message set msg [binary format ccSc2sIc2sI \ {0x2} $flags $len \ {0x1 4} 0 $node2_num \ {0x2 4} 0 $node1_num ] puts -nonewline $channel $msg puts -nonewline $channel [binary format c2sW {0x3 8} 0 $delay] puts -nonewline $channel [binary format c2sW {0x4 8} 0 $bw] puts -nonewline $channel $per_msg puts -nonewline $channel $dup_msg puts -nonewline $channel [binary format c2sW {0x7 8} 0 $jitter] puts -nonewline $channel [binary format c2sI {0x20 4} 0 $ltype] puts -nonewline $channel [binary format c2S {0x22 2} $uni] if { $if2num >= 0 && ([[typemodel $node2].layer] == "NETWORK" || \ [nodeType $node2] == "tunnel") } { puts -nonewline $channel [ binary format c2S {0x30 2} $if2num ] } if { $if1num >= 0 && ([[typemodel $node1].layer] == "NETWORK" || \ [nodeType $node1] == "tunnel") } { puts -nonewline $channel [ binary format c2S {0x36 2} $if1num ] } if { $prmsg==1 } { puts ")" } flushChannel channel "Error sending link message" } # helper to get IPv4, IPv6, MAC address and increment length # also prints TLV-style addresses if showAPI is true proc getIfcAddrs { node ifc ipv4p ipv6p macp ipv4maskp ipv6maskp lenp } { global showAPI upvar $ipv4p ipv4 upvar $ipv6p ipv6 upvar $macp mac upvar $ipv4maskp ipv4mask upvar $ipv6maskp ipv6mask upvar $lenp len if { $ifc == "" || $node == "" } { return } # IPv4 address set ipv4str [getIfcIPv4addr $node $ifc] if {$ipv4str != ""} { set ipv4 [lindex [split $ipv4str /] 0] if { [info exists ipv4mask ] } { set ipv4mask [lindex [split $ipv4str / ] 1] incr len 12; # 8 addr + 4 mask if { $showAPI == 1 } { puts -nonewline "$ipv4str," } } else { incr len 8; # 8 addr if { $showAPI == 1 } { puts -nonewline "$ipv4," } } set ipv4 [stringToIPv4 $ipv4]; # convert to integer } # IPv6 address set ipv6str [getIfcIPv6addr $node $ifc] if {$ipv6str != ""} { set ipv6 [lindex [split $ipv6str /] 0] if { [info exists ipv6mask ] } { set ipv6mask [lindex [split $ipv6str / ] 1] incr len 24; # 20 addr + 4 mask if { $showAPI == 1 } { puts -nonewline "$ipv6str," } } else { incr len 20; # 20 addr if { $showAPI == 1 } { puts -nonewline "$ipv6," } } set ipv6 [expandIPv6 $ipv6]; # convert to long string } # MAC address (from conf if there, otherwise generated) if { [info exists mac] } { set mac [lindex [getIfcMacaddr $node $ifc] 0] if {$mac == ""} { set mac [getNextMac] } if { $showAPI == 1 } { puts -nonewline "$mac," } incr len 12; } } # # Register Message: (registration types) # This is a simple Register Message, types is an array of # tuples. proc sendRegMessage { channel flags types_list } { global showAPI regtypes set prmsg $showAPI if { $channel == -1 || $channel == "" } { set plugin [lindex [getEmulPlugin "*"] 0] set channel [pluginConnect $plugin connect true] if { $channel == -1 } { return } } set len 0 array set types $types_list # array names output is unreliable, sort it set type_list [lsort -dict [array names types]] foreach type $type_list { if { ![info exists regtypes($type)] } { puts "sendRegMessage: unknown registration type '$type'" return -1 } set str_$type $types($type) set str_${type}_len [string length [set str_$type]] set str_${type}_pad_len [pad_32bit [set str_${type}_len]] set str_${type}_pad [binary format x[set str_${type}_pad_len]] incr len [expr { 2 + [set str_${type}_len] + [set str_${type}_pad_len]}] } if { $prmsg == 1 } { puts ">REG($type_list)" } # message header set msg1 [binary format ccS 4 $flags $len] puts -nonewline $channel $msg1 foreach type $type_list { set type_num $regtypes($type) set tlvh [binary format cc $type_num [set str_${type}_len]] puts -nonewline $channel $tlvh[set str_${type}][set str_${type}_pad] } flushChannel channel "Error: API channel was closed" } # # Configuration Message: (object, type flags, node) # This is a simple Configuration Message containing flags proc sendConfRequestMessage { channel node model flags netid opaque } { global showAPI set prmsg $showAPI if { $channel == -1 || $channel == "" } { set pname [lindex [getEmulPlugin $node] 0] set channel [pluginConnect $pname connect true] if { $channel == -1 } { return } } set model_len [string length $model] set model_pad_len [pad_32bit $model_len] set model_pad [binary format x$model_pad_len ] set len [expr {4+2+$model_len+$model_pad_len}] # optional network ID to provide Netgraph mapping if { $netid != -1 } { incr len 8 } # convert from node name to number if { [string is alpha [string range $node 0 0]] } { set node [string range $node 1 end] } if { $node > 0 } { incr len 8 } # add a session number when configuring services set session "" set session_len 0 set session_pad_len 0 set session_pad "" if { $node <= 0 && $model == "services" } { global g_current_session set session [format "0x%x" $g_current_session] set session_len [string length $session] set session_pad_len [pad_32bit $session_len] set session_pad [binary format x$session_pad_len] incr len [expr {2 + $session_len + $session_pad_len}] } # opaque data - used when custom configuring services set opaque_len 0 set msgop [buildStringTLV 0x50 $opaque opaque_len] if { $opaque_len > 0 } { incr len $opaque_len } if { $prmsg == 1 } { puts -nonewline ">CONF(flags=0," if { $node > 0 } { puts -nonewline "node=$node," } puts -nonewline "obj=$model,cflags=$flags" if { $session != "" } { puts -nonewline ",session=$session" } if { $netid > -1 } { puts -nonewline ",netid=$netid" } if { $opaque_len > 0 } { puts -nonewline ",opaque=$opaque" } puts ") request" } # header, node node number, node model header set msg1 [binary format c2S {5 0} $len ] set msg1b "" if { $node > 0 } { set msg1b [binary format c2sI {1 4} 0 $node] } set msg1c [binary format cc 2 $model_len] # request flag set msg2 [binary format c2S {3 2} $flags ] # session number set msg3 "" if { $session != "" } { set msg3 [binary format cc 0x0A $session_len] set msg3 $msg3$session$session_pad } # network ID set msg4 "" if { $netid != -1 } { set msg4 [binary format c2sI {0x23 4} 0 0x$netid ] } #catch {puts -nonewline $channel $msg1$model$model_pad$msg2$msg3$msg4$msg5} puts -nonewline $channel $msg1$msg1b$msg1c$model$model_pad$msg2$msg3$msg4 if { $opaque_len > 0 } { puts -nonewline $channel $msgop } flushChannel channel "Error: API channel was closed" } # # Configuration Message: (object, type flags, node, types, values) # This message is more complicated to build because of the list of # data types and values. proc sendConfReplyMessage { channel node model types values opaque } { global showAPI set prmsg $showAPI # convert from node name to number if { [string is alpha [string range $node 0 0]] } { set node [string range $node 1 end] } # add a session number when configuring services set session "" set session_len 0 set session_pad_len 0 set session_pad "" if { $node <= 0 && $model == "services" && $opaque == "" } { global g_current_session set session [format "0x%x" $g_current_session] set session_len [string length $session] set session_pad_len [pad_32bit $session_len] set session_pad [binary format x$session_pad_len] incr len [expr {$session_len + $session_pad_len}] } if { $prmsg == 1 } { puts -nonewline ">CONF(flags=0," if {$node > -1 } { puts -nonewline "node=$node," } puts -nonewline "obj=$model,cflags=0" if {$session != "" } { puts -nonewline "session=$session," } if {$opaque != "" } { puts -nonewline "opaque=$opaque," } puts "types=<$types>,values=<$values>) reply" } # types (16-bit values) and values set n 0 set type_len [expr {[llength $types] * 2} ] set type_data [binary format cc 4 $type_len] set value_data "" foreach type $types { set t [binary format S $type] set type_data $type_data$t set val [lindex $values $n] if { $val == "" } { #puts "warning: empty value $n (type=$type)" if { $type != 10 } { set val 0 } } incr n lappend value_data $val }; # end foreach set value_len 0 set value_data [join $value_data |] set msgval [buildStringTLV 0x5 $value_data value_len] set type_pad_len [pad_32bit $type_len] set type_pad [binary format x$type_pad_len ] set model_len [string length $model] set model_pad_len [pad_32bit $model_len] set model_pad [binary format x$model_pad_len ] # opaque data - used when custom configuring services set opaque_len 0 set msgop [buildStringTLV 0x50 $opaque opaque_len] # 4 bytes header, model TLV set len [expr 4+2+$model_len+$model_pad_len] if { $node > -1 } { incr len 8 } # session number set msg3 "" if { $session != "" } { incr len [expr {2 + $session_len + $session_pad_len }] set msg3 [binary format cc 0x0A $session_len] set msg3 $msg3$session$session_pad } if { $opaque_len > 0 } { incr len $opaque_len } # types TLV, values TLV incr len [expr {2 + $type_len + $type_pad_len + $value_len}] # header, node node number, node model header set msgh [binary format c2S {5 0} $len ] set msgwl "" if { $node > -1 } { set msgwl [binary format c2sI {1 4} 0 $node] } set model_hdr [binary format cc 2 $model_len] # no flags set type_hdr [binary format c2S {3 2} 0 ] set msg $msgh$msgwl$model_hdr$model$model_pad$type_hdr$type_data$type_pad set msg $msg$msgval$msg3 puts -nonewline $channel $msg if { $opaque_len > 0 } { puts -nonewline $channel $msgop } flushChannel channel "Error sending conf reply" } # Event Message proc sendEventMessage { channel type nodenum name data flags } { global showAPI eventtypes set prmsg $showAPI set len [expr 8] ;# event type if {$nodenum > -1} { incr len 8 } set name_len [string length $name] set name_pad_len [pad_32bit $name_len] if { $name_len > 0 } { incr len [expr {2 + $name_len + $name_pad_len}] } set data_len [string length $data] set data_pad_len [pad_32bit $data_len] if { $data_len > 0 } { incr len [expr {2 + $data_len + $data_pad_len}] } if { $prmsg == 1 } { puts -nonewline ">EVENT(flags=$flags," } set msg [binary format ccS 8 $flags $len ] ;# message header set msg2 "" if { $nodenum > -1 } { if { $prmsg == 1 } { puts -nonewline "node=$nodenum," } set msg2 [binary format c2sI {0x01 4} 0 $nodenum] } if { $prmsg == 1} { set typestr "" foreach t [array names eventtypes] { if { $eventtypes($t) == $type } { set typestr "-$t"; break } } puts -nonewline "type=$type$typestr," } set msg3 [binary format c2sI {0x02 4} 0 $type] set msg4 "" set msg5 "" if { $name_len > 0 } { if { $prmsg == 1 } { puts -nonewline "name=$name," } set msg4 [binary format cc 0x03 $name_len ] set name_pad [binary format x$name_pad_len ] set msg5 $name$name_pad } set msg6 "" set msg7 "" if { $data_len > 0 } { if { $prmsg == 1 } { puts -nonewline "data=$data" } set msg6 [binary format cc 0x04 $data_len ] set data_pad [binary format x$data_pad_len ] set msg7 $data$data_pad } if { $prmsg == 1 } { puts ")" } puts -nonewline $channel $msg$msg2$msg3$msg4$msg5$msg6$msg7 flushChannel channel "Error sending Event type=$type" } # deploy working configuration using CORE API # Deploys a current working configuration. It creates all the # nodes and link as defined in configuration file. proc deployCfgAPI { sock } { global eid global node_list link_list annotation_list canvas_list global mac_byte4 mac_byte5 global execMode global ngnodemap global mac_addr_start global deployCfgAPI_lock global eventtypes global g_comments if { ![info exists deployCfgAPI_lock] } { set deployCfgAPI_lock 0 } if { $deployCfgAPI_lock } { puts "***error: deployCfgAPI called while deploying config" return } set deployCfgAPI_lock 1 ;# lock set mac_byte4 0 set mac_byte5 0 if { [info exists mac_addr_start] } { set mac_byte5 $mac_addr_start } set t_start [clock seconds] global systype set systype [lindex [checkOS] 0] statgraph on [expr (2*[llength $node_list]) + [llength $link_list]] sendSessionProperties $sock # this tells the CORE services that we are starting to send # configuration data # clear any existing config sendEventMessage $sock $eventtypes(definition_state) -1 "" "" 0 # inform CORE services about emulation servers, hook scripts, canvas info, # and services sendEventMessage $sock $eventtypes(configuration_state) -1 "" "" 0 sendEmulationServerInfo $sock 0 sendSessionOptions $sock sendHooks $sock sendCanvasInfo $sock sendNodeTypeInfo $sock 0 # send any custom service info before the node messages sendNodeCustomServices $sock # send Node add messages for all emulation nodes foreach node $node_list { set node_id "$eid\_$node" set type [nodeType $node] set name [getNodeName $node] if { $type == "pseudo" } { continue } statgraph inc 1 statline "Creating node $name" if { [[typemodel $node].layer] == "NETWORK" } { nodeHighlights .c $node on red } # inform the CORE daemon of the node sendNodeAddMessage $sock $node pluginCapsInitialize $node "mobmodel" writeNodeCoords $node [getNodeCoords $node] } # send Link add messages for all network links for { set pending_links $link_list } { $pending_links != "" } {} { set link [lindex $pending_links 0] set i [lsearch -exact $pending_links $link] set pending_links [lreplace $pending_links $i $i] statgraph inc 1 set lnode1 [lindex [linkPeers $link] 0] set lnode2 [lindex [linkPeers $link] 1] if { [nodeType $lnode2] == "router" && \ [getNodeModel $lnode2] == "remote" } { continue; # remote routers are ctrl. by GUI; TODO: move to daemon } sendLinkMessage $sock $link add } # GUI-specific meta-data send via Configure Messages if { [llength $annotation_list] > 0 } { sendMetaData $sock $annotation_list "annotation" } sendMetaData $sock $canvas_list "canvas" ;# assume >= 1 canvas # global GUI options - send as meta-data set obj "metadata" set values [getGlobalOptionList] sendConfReplyMessage $sock -1 $obj "10" "{global_options=$values}" "" if { [info exists g_comments] && $g_comments != "" } { sendConfReplyMessage $sock -1 $obj "10" "{comments=$g_comments}" "" } # status bar graph statgraph off 0 statline "Network topology instantiated in [expr [clock seconds] - $t_start] seconds ([llength $node_list] nodes and [llength $link_list] links)." # TODO: turn on tcpdump if enabled; customPostConfigCommands; # addons 4 deployCfgHook # draw lines between wlan nodes # initialization does not work earlier than this foreach node $node_list { # WLAN handling: draw lines between wireless nodes if { [nodeType $node] == "wlan" && $execMode == "interactive" } { wlanRunMobilityScript $node } } sendTrafficScripts $sock # tell the CORE services that we are ready to instantiate sendEventMessage $sock $eventtypes(instantiation_state) -1 "" "" 0 set deployCfgAPI_lock 0 ;# unlock statline "Network topology instantiated in [expr [clock seconds] - $t_start] seconds ([llength $node_list] nodes and [llength $link_list] links)." } # # emulation shutdown procedure when using the CORE API proc shutdownSession {} { global link_list node_list eid eventtypes execMode set nodecount [getNodeCount] if { $nodecount == 0 } { # This allows switching to edit mode without extra API messages, # such as when file new is selected while running an existing session. return } # prepare the channel set plugin [lindex [getEmulPlugin "*"] 0] set sock [pluginConnect $plugin connect true] sendEventMessage $sock $eventtypes(datacollect_state) -1 "" "" 0 # shut down all links foreach link $link_list { set lnode2 [lindex [linkPeers $link] 1] if { [nodeType $lnode2] == "router" && \ [getNodeModel $lnode2] == "remote" } { continue; # remote routers are ctrl. by GUI; TODO: move to daemon } sendLinkMessage $sock $link delete false } # shut down all nodes foreach node $node_list { set type [nodeType $node] if { [[typemodel $node].layer] == "NETWORK" && $execMode != "batch" } { nodeHighlights .c $node on red } sendNodeDelMessage $sock $node pluginCapsDeinitialize $node "mobmodel" deleteNodeCoords $node } sendNodeTypeInfo $sock 1 sendEmulationServerInfo $sock 1 } # inform the CORE services about the canvas information to support # conversion between X,Y and lat/long coordinates proc sendCanvasInfo { sock } { global curcanvas if { ![info exists curcanvas] } { return } ;# batch mode set obj "location" set scale [getCanvasScale $curcanvas] set refpt [getCanvasRefPoint $curcanvas] set refx [lindex $refpt 0] set refy [lindex $refpt 1] set latitude [lindex $refpt 2] set longitude [lindex $refpt 3] set altitude [lindex $refpt 4] set types [list 2 2 10 10 10 10] set values [list $refx $refy $latitude $longitude $altitude $scale] sendConfReplyMessage $sock -1 $obj $types $values "" } # inform the CORE services about the default services for a node type, which # are used when node-specific services have not been configured for a node proc sendNodeTypeInfo { sock reset } { global node_list set obj "services" if { $reset == 1} { sendConfRequestMessage $sock -1 "all" 0x3 -1 "" return } # build a list of node types in use set typesinuse "" foreach node $node_list { set type [nodeType $node] if { $type != "router" } { continue } set model [getNodeModel $node] if { [lsearch $typesinuse $model] < 0 } { lappend typesinuse $model } } foreach type $typesinuse { # build a list of type + enabled services, all strings set values [getNodeTypeServices $type] set values [linsert $values 0 $type] set types [string repeat "10 " [llength $values]] sendConfReplyMessage $sock -1 $obj $types $values "" # send any custom profiles for a node type; node type passed in opaque set machine_type [getNodeTypeMachineType $type] set values [getNodeTypeProfile $type] if { $values != "" } { set types [string repeat "10 " [llength $values]] sendConfReplyMessage $sock -1 $machine_type $types $values \ "$machine_type:$type" } } } # inform the CORE services about any services that have been customized for # a particular node proc sendNodeCustomServices { sock } { global node_list foreach node $node_list { set cfgs [getCustomConfig $node] set cfgfiles "" foreach cfg $cfgs { set ids [split [getConfig $cfg "custom-config-id"] :] if { [lindex $ids 0] != "service" } { continue } if { [llength $ids] == 3 } { # customized service config file -- build a list lappend cfgfiles $cfg continue } set s [lindex $ids 1] set values [getConfig $cfg "config"] set t [string repeat "10 " [llength $values]] sendConfReplyMessage $sock $node services $t $values "service:$s" } # send customized service config files after the service info foreach cfg $cfgfiles { set idstr [getConfig $cfg "custom-config-id"] set ids [split $idstr :] if { [lindex $ids 0] != "service" } { continue } set s [lindex $ids 1] set filename [lindex $ids 2] set data [join [getConfig $cfg "config"] "\n"] sendFileMessage $sock $node "service:$s" $filename "" $data \ [string length $data] } } } # publish hooks to the CORE services proc sendHooks { sock } { global g_hook_scripts if { ![info exists g_hook_scripts] } { return } foreach hook $g_hook_scripts { set name [lindex $hook 0] set state [lindex $hook 1] set data [lindex $hook 2] # TODO: modify sendFileMessage to make node number optional sendFileMessage $sock n0 "hook:$state" $name "" $data \ [string length $data] } } # inform the CORE services about the emulation servers that will be used proc sendEmulationServerInfo { sock reset } { global exec_servers set node -1 ;# not used set obj "broker" set servernames [getAssignedRemoteServers] if { $servernames == "" } { return } ;# not using emulation servers if { $reset == 1} { sendConfRequestMessage $sock $node $obj 0x3 -1 "" return } set servers "" foreach servername $servernames { set host [lindex $exec_servers($servername) 0] set port [lindex $exec_servers($servername) 1] lappend servers "$servername:$host:$port" } set serversstring [join $servers ,] set types [list 10] set values [list $serversstring] sendConfReplyMessage $sock $node $obj $types $values "" } # returns the length of node_list minus any pseudo-nodes (inter-canvas nodes) proc getNodeCount {} { global node_list set nodecount 0 foreach node $node_list { if { [nodeType $node] != "pseudo" } { incr nodecount } } return $nodecount } # send basic properties of a session proc sendSessionProperties { sock } { global currentFile CORE_DATA_DIR CORE_USER set sessionname [file tail $currentFile] set nodecount [getNodeCount] if { $sessionname == "" } { set sessionname "untitled" } set tf "/tmp/thumb.jpg" if { ![writeCanvasThumbnail .c $tf] } { set src "$CORE_DATA_DIR/icons/normal/thumb-unknown.gif" set tf "/tmp/thumb.gif" if [catch { file copy $src $tf } e] { puts -nonewline "warning: failed to copy $src to $tf\n($e)" set tf "" } } set user $CORE_USER sendSessionMessage $sock 0 0 $sessionname $currentFile $nodecount $tf $user } # send session options from global array in Config Message proc sendSessionOptions { sock } { if { $sock == -1 } { set sock [lindex [getEmulPlugin "*"] 2] } set values [getSessionOptionsList] set types [string repeat "10 " [llength $values]] sendConfReplyMessage $sock -1 "session" $types $values "" } # send annotations as key=value metadata in Config Message proc sendAnnotations { sock } { global annotation_list if { $sock == -1 } { set sock [lindex [getEmulPlugin "*"] 2] } set values "" foreach a $annotation_list { global $a set val [set $a] lappend values "annotation $a=$val" } set types [string repeat "10 " [llength $values]] sendConfReplyMessage $sock -1 "metadata" $types $values "" } # send items as key=value metadata in Config Message proc sendMetaData { sock items itemtype } { if { $sock == -1 } { set sock [lindex [getEmulPlugin "*"] 2] } set values "" foreach i $items { global $i set val [set $i] lappend values "$itemtype $i=$val" } set types [string repeat "10 " [llength $values]] sendConfReplyMessage $sock -1 "metadata" $types $values "" } # send an Event message for the definition state (this clears any existing # state), then send all node and link definitions to the CORE services proc sendNodeLinkDefinitions { sock } { global node_list link_list annotation_list canvas_list eventtypes global g_comments #sendEventMessage $sock $eventtypes(definition_state) -1 "" "" 0 foreach node $node_list { sendNodeAddMessage $sock $node pluginCapsInitialize $node "mobmodel" } foreach link $link_list { sendLinkMessage $sock $link add } # GUI-specific meta-data send via Configure Messages sendMetaData $sock $annotation_list "annotation" sendMetaData $sock $canvas_list "canvas" set obj "metadata" set values [getGlobalOptionList] sendConfReplyMessage $sock -1 $obj "10" "{global_options=$values}" "" if { [info exists g_comments] && $g_comments != "" } { sendConfReplyMessage $sock -1 $obj "10" "{comments=$g_comments}" "" } } proc getNodeTypeAPI { node } { set type [nodeType $node] if { $type == "router" } { set model [getNodeModel $node] set type [getNodeTypeMachineType $model] } switch -exact -- "$type" { router { return 0x0 } netns { return 0x0 } jail { return 0x0 } physical { return 0x1 } xen { return 0x2 } tbd { return 0x3 } lanswitch { return 0x4 } hub { return 0x5 } wlan { return 0x6 } rj45 { return 0x7 } tunnel { return 0x8 } ktunnel { return 0x9 } emane { return 0xA } default { return 0x0 } } } # send an Execute message proc sendExecMessage { channel node cmd exec_num flags } { global showAPI g_api_exec_num set prmsg $showAPI set node_num [string range $node 1 end] set cmd_len [string length $cmd] if { $cmd_len > 255 } { puts "sendExecMessage error: cmd too long!"; return} set cmd_pad_len [pad_32bit $cmd_len] set cmd_pad [binary format x$cmd_pad_len] if { $exec_num == 0 } { incr g_api_exec_num set exec_num $g_api_exec_num } # node num + exec num + command string set len [expr {8 + 8 + 2 + $cmd_len + $cmd_pad_len}] if { $prmsg == 1 } {puts ">EXEC(flags=$flags,$node,n=$exec_num,cmd='$cmd')" } set msg [binary format ccSc2sIc2sIcc \ 3 $flags $len \ {1 4} 0 $node_num \ {2 4} 0 $exec_num \ 4 $cmd_len \ ] puts -nonewline $channel $msg$cmd$cmd_pad flushChannel channel "Error sending file message" } # if source file (sf) is specified, then send a message that the file source # file should be copied to the given file name (f); otherwise, include the file # data in this message proc sendFileMessage { channel node type f sf data data_len } { global showAPI set prmsg $showAPI set node_num [string range $node 1 end] set f_len [string length $f] set f_pad_len [pad_32bit $f_len] set f_pad [binary format x$f_pad_len] set type_len [string length $type] set type_pad_len [pad_32bit $type_len] set type_pad [binary format x$type_pad_len] if { $sf != "" } { set sf_len [string length $sf] set sf_pad_len [pad_32bit $sf_len] set sf_pad [binary format x$sf_pad_len] set data_len 0 set data_pad_len 0 } else { set sf_len 0 set sf_pad_len 0 set data_pad_len [pad_32bit $data_len] set data_pad [binary format x$data_pad_len] } # TODO: gzip compression w/tlv type 0x11 # node number TLV + file name TLV + ( file src name / data TLV) set len [expr {8 + 2 + 2 + $f_len + $f_pad_len + $sf_len + $sf_pad_len \ + $data_len + $data_pad_len}] # 16-bit data length if { $data_len > 255 } { incr len 2 if { $data_len > 65536 } { puts -nonewline "*** error: File Message data length too large " puts "($data_len > 65536)" return } } if { $type_len > 0 } { incr len [expr {2 + $type_len + $type_pad_len}] } set flags 1; # add flag if { $prmsg == 1 } { puts -nonewline ">FILE(flags=$flags,$node,f=$f," if { $type != "" } { puts -nonewline "type=$type," } if { $sf != "" } { puts "src=$sf)" } else { puts "data=($data_len))" } } set msg [binary format ccSc2sIcc \ 6 $flags $len \ {1 4} 0 $node_num \ 2 $f_len \ ] set msg2 "" if { $type_len > 0 } { set msg2 [binary format cc 0x5 $type_len] set msg2 $msg2$type$type_pad } if { $sf != "" } { ;# source file name TLV set msg3 [binary format cc 0x6 $sf_len] puts -nonewline $channel $msg$f$f_pad$msg2$msg3$sf$sf_pad } else { ;# file data TLV if { $data_len > 255 } { set msg3 [binary format ccS 0x10 0 $data_len] } else { set msg3 [binary format cc 0x10 $data_len] } puts -nonewline $channel $msg$f$f_pad$msg2$msg3$data$data_pad } flushChannel channel "Error sending file message" } # Session Message proc sendSessionMessage { channel flags num name sfile nodecount tf user } { global showAPI set prmsg $showAPI if { $channel == -1 } { set pname [lindex [getEmulPlugin "*"] 0] set channel [pluginConnect $pname connect true] if { $channel == -1 } { return } } set num_len [string length $num] set num_pad_len [pad_32bit $num_len] set len [expr {2 + $num_len + $num_pad_len}] if { $num_len <= 0 } { puts "error: sendSessionMessage requires at least one session number" return } set name_len [string length $name] set name_pad_len [pad_32bit $name_len] if { $name_len > 0 } { incr len [expr { 2 + $name_len + $name_pad_len }] } set sfile_len [string length $sfile] set sfile_pad_len [pad_32bit $sfile_len] if { $sfile_len > 0 } { incr len [expr { 2 + $sfile_len + $sfile_pad_len }] } set nc_len [string length $nodecount] set nc_pad_len [pad_32bit $nc_len] if { $nc_len > 0 } { incr len [expr { 2 + $nc_len + $nc_pad_len }] } set tf_len [string length $tf] set tf_pad_len [pad_32bit $tf_len] if { $tf_len > 0 } { incr len [expr { 2 + $tf_len + $tf_pad_len }] } set user_len [string length $user] set user_pad_len [pad_32bit $user_len] if { $user_len > 0 } { incr len [expr { 2 + $user_len + $user_pad_len }] } if { $prmsg == 1 } { puts -nonewline ">SESSION(flags=$flags" } set msgh [binary format ccS 0x09 $flags $len ] ;# message header if { $prmsg == 1 } { puts -nonewline ",sids=$num" } set num_hdr [binary format cc 0x01 $num_len] set num_pad [binary format x$num_pad_len ] set msg1 "$num_hdr$num$num_pad" set msg2 "" if { $name_len > 0 } { if { $prmsg == 1 } { puts -nonewline ",name=$name" } # TODO: name_len > 255 set name_hdr [binary format cc 0x02 $name_len] set name_pad [binary format x$name_pad_len] set msg2 "$name_hdr$name$name_pad" } set msg3 "" if { $sfile_len > 0 } { if { $prmsg == 1 } { puts -nonewline ",file=$sfile" } # TODO: sfile_len > 255 set sfile_hdr [binary format cc 0x03 $sfile_len] set sfile_pad [binary format x$sfile_pad_len] set msg3 "$sfile_hdr$sfile$sfile_pad" } set msg4 "" if { $nc_len > 0 } { if { $prmsg == 1 } { puts -nonewline ",nc=$nodecount" } set nc_hdr [binary format cc 0x04 $nc_len] set nc_pad [binary format x$nc_pad_len] set msg4 "$nc_hdr$nodecount$nc_pad" } set msg5 "" if { $tf_len > 0 } { if { $prmsg == 1 } { puts -nonewline ",thumb=$tf" } set tf_hdr [binary format cc 0x06 $tf_len] set tf_pad [binary format x$tf_pad_len] set msg5 "$tf_hdr$tf$tf_pad" } set msg6 "" if { $user_len > 0 } { if { $prmsg == 1 } { puts -nonewline ",user=$user" } set user_hdr [binary format cc 0x07 $user_len] set user_pad [binary format x$user_pad_len] set msg6 "$user_hdr$user$user_pad" } if { $prmsg == 1 } { puts ")" } puts -nonewline $channel $msgh$msg1$msg2$msg3$msg4$msg5$msg6 flushChannel channel "Error sending Session num=$num" } # return a new execution number and record it in the execution request list # for the given callback (e.g. widget) type proc newExecCallbackRequest { type } { global g_api_exec_num g_execRequests incr g_api_exec_num set exec_num $g_api_exec_num lappend g_execRequests($type) $exec_num return $exec_num } # ask daemon to load or save an XML file based on the current session proc xmlFileLoadSave { cmd name } { global oper_mode eventtypes set plugin [lindex [getEmulPlugin "*"] 0] set sock [pluginConnect $plugin connect true] if { $sock == -1 || $sock == "" } { return } # inform daemon about nodes and links when saving in edit mode if { $cmd == "save" && $oper_mode != "exec" } { sendSessionProperties $sock # this tells the CORE services that we are starting to send # configuration data # clear any existing config sendEventMessage $sock $eventtypes(definition_state) -1 "" "" 0 sendEventMessage $sock $eventtypes(configuration_state) -1 "" "" 0 sendEmulationServerInfo $sock 0 sendSessionOptions $sock sendHooks $sock sendCanvasInfo $sock sendNodeTypeInfo $sock 0 # send any custom service info before the node messages sendNodeCustomServices $sock sendNodeLinkDefinitions $sock } elseif { $cmd == "open" } { # reset config objects sendNodeTypeInfo $sock 1 } sendEventMessage $sock $eventtypes(file_$cmd) -1 $name "" 0 } ############################################################################ # # Helper functions below here # # helper function to get interface number from name proc ifcNameToNum { ifc } { # eth0, eth1, etc. if {[string range $ifc 0 2] == "eth"} { set ifnum [string range $ifc 3 end] # l0, l1, etc. } else { set ifnum [string range $ifc 1 end] } if { $ifnum == "" } { return -1 } if {![string is integer $ifnum]} { return -1 } return $ifnum } # # parse the type and length from a TLV header proc parseTLVHeader { data current_ref } { global showAPI set prmsg $showAPI upvar $current_ref current if { [binary scan $data @${current}cc type length] != 2 } { if { $prmsg == 1 } { puts "TLV header error" } return "" } set length [expr {$length & 0xFF}]; # convert signed to unsigned if { $length == 0 } { if { $type == 0 } { # prevent endless looping if { $prmsg == 1 } { puts -nonewline "(extra padding)" } return "" } else { # support for length > 255 incr current 2 if { [binary scan $data @${current}S length] != 1 } { puts "error reading TLV length (type=$type)" return "" } set length [expr {$length & 0xFFFF}] if { $length == 0 } { # zero-length string, not length > 255 incr current -2 } } } incr current 2 return [list $type $length] } # return the binary string, and length by reference proc buildStringTLV { type data len_ref } { upvar $len_ref len set data_len [string length $data] if { $data_len > 65536 } { puts "warning: buildStringTLV data truncated" set data_len 65536 set data [string range 0 65535] } set data_pad_len [pad_32bit $data_len] set data_pad [binary format x$data_pad_len] if { $data_len == 0 } { set len 0 return "" } if { $data_len > 255 } { set hdr [binary format ccS $type 0 $data_len] set hdr_len 4 } else { set hdr [binary format cc $type $data_len] set hdr_len 2 } set len [expr {$hdr_len + $data_len + $data_pad_len}] return $hdr$data$data_pad } # calculate padding to 32-bit word boundary # 32-bit and 64-bit values are pre-padded, strings and 128-bit values are # post-padded to word boundary, depending on type proc pad_32bit { len } { # total length = 2 + len + pad if { $len < 256 } { set hdrsiz 2 } else { set hdrsiz 4 } # calculate padding to fill 32-bit boundary return [expr { -($hdrsiz + $len) % 4 }] } proc macToString { mac_num } { set mac_bytes "" # convert 64-bit integer into 12-digit hex string set mac_num 0x[format "%.12lx" $mac_num] while { $mac_num > 0 } { # append 8-bit hex number to list set uchar [format "%02x" [expr $mac_num & 0xFF]] lappend mac_bytes $uchar # shift off 8-bits set mac_num [expr $mac_num >> 8] } # make sure we have six hex digits set num_zeroes [expr 6 - [llength $mac_bytes]] while { $num_zeroes > 0 } { lappend mac_bytes 00 incr num_zeroes -1 } # this is lreverse in tcl8.5 and later set r {} set i [llength $mac_bytes] while { $i > 0 } { lappend r [lindex $mac_bytes [incr i -1]] } return [join $r :] } proc hexdump { data } { # read data as hex binary scan $data H* hex # split into pairs of hex digits regsub -all -- {..} $hex {& } hex return $hex } core-4.8/gui/canvas.tcl0000664000175000017500000002722412534327775012031 00000000000000# # Copyright 2005-2013 the Boeing Company. # See the LICENSE file included in this distribution. # # # Copyright 2005-2008 University of Zagreb, Croatia. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF # SUCH DAMAGE. # # #****h* imunes/canvas.tcl # NAME # canvas.tcl -- file used for manipultaion with canvases in IMUNES # FUNCTION # This module is used to define all the actions used for configuring # canvases in IMUNES. On each canvas a part of the simulation is presented # If there is no additional canvas defined, simulation is presented on the # defalut canvas. # #**** #****f* canvas.tcl/removeCanvas # NAME # removeCanvas -- remove canvas # SYNOPSIS # removeCanvas $canvas_id # FUNCTION # Removes the canvas from simulation. This function does not change the # configuration of the nodes, i.e. nodes attached to the removed canvas # remain attached to the same non existing canvas. # INPUTS # * canvas_id -- canvas id #**** proc removeCanvas { canvas } { global canvas_list $canvas set i [lsearch $canvas_list $canvas] set canvas_list [lreplace $canvas_list $i $i] set $canvas {} } #****f* canvas.tcl/newCanvas # NAME # newCanvas -- craete new canvas # SYNOPSIS # set canvas_id [newCanvas $canvas_name] # FUNCTION # Creates new canvas. Returns the canvas_id of the new canvas. # If the canvas_name parameter is empty, the name of the new canvas # is set to CanvasN, where N represents the canvas_id of the new canvas. # INPUTS # * canvas_name -- canvas name # RESULT # * canvas_id -- canvas id #**** proc newCanvas { name } { global canvas_list set canvas [newObjectId canvas] global $canvas lappend canvas_list $canvas set $canvas {} if { $name != "" } { setCanvasName $canvas $name } else { setCanvasName $canvas Canvas[string range $canvas 1 end] } return $canvas } proc setCanvasSize { canvas x y } { global $canvas set i [lsearch [set $canvas] "size *"] if { $i >= 0 } { set $canvas [lreplace [set $canvas] $i $i "size {$x $y}"] } else { set $canvas [linsert [set $canvas] 1 "size {$x $y}"] } } proc getCanvasSize { canvas } { global $canvas g_prefs set entry [lrange [lsearch -inline [set $canvas] "size *"] 1 end] set size [string trim $entry \{\}] if { $size == "" } { return "$g_prefs(gui_canvas_x) $g_prefs(gui_canvas_y)" } else { return $size } } #****f* canvas.tcl/getCanvasName # NAME # getCanvasName -- get canvas name # SYNOPSIS # set canvas_name [getCanvasName $canvas_id] # FUNCTION # Returns the name of the canvas. # INPUTS # * canvas_id -- canvas id # RESULT # * canvas_name -- canvas name #**** proc getCanvasName { canvas } { global $canvas set entry [lrange [lsearch -inline [set $canvas] "name *"] 1 end] return [string trim $entry \{\}] } #****f* canvas.tcl/setCanvasName # NAME # setCanvasName -- set canvas name # SYNOPSIS # setCanvasName $canvas_id $canvas_name # FUNCTION # Sets the name of the canvas. # INPUTS # * canvas_id -- canvas id # * canvas_name -- canvas name #**** proc setCanvasName { canvas name } { global $canvas set i [lsearch [set $canvas] "name *"] if { $i >= 0 } { set $canvas [lreplace [set $canvas] $i $i "name {$name}"] } else { set $canvas [linsert [set $canvas] 1 "name {$name}"] } } # Boeing: canvas wallpaper support proc getCanvasWallpaper { canvas } { global $canvas set entry [lrange [lsearch -inline [set $canvas] "wallpaper *"] 1 end] set entry2 [lrange [lsearch -inline \ [set $canvas] "wallpaper-style *"] 1 end] return [list [string trim $entry \{\}] [string trim $entry2 \{\}]] } proc setCanvasWallpaper { canvas file style} { global $canvas set i [lsearch [set $canvas] "wallpaper *"] if { $i >= 0 } { set $canvas [lreplace [set $canvas] $i $i "wallpaper {$file}"] } else { set $canvas [linsert [set $canvas] 1 "wallpaper {$file}"] } set i [lsearch [set $canvas] "wallpaper-style *"] if { $i >= 0 } { set $canvas [lreplace [set $canvas] $i $i "wallpaper-style {$style}"] } else { set $canvas [linsert [set $canvas] 1 "wallpaper-style {$style}"] } } # Boeing: manage canvases proc manageCanvasPopup { x y } { global curcanvas CORE_DATA_DIR set w .entry1 catch {destroy $w} toplevel $w -takefocus 1 if { $x == 0 && $y == 0 } { set screen [wm maxsize .] set x [expr {[lindex $screen 0] / 4}] set y [expr {[lindex $screen 1] / 4}] } else { set x [expr {$x + 10}] set y [expr {$y - 250}] } wm geometry $w +$x+$y wm title $w "Manage Canvases" wm iconname $w "Manage Canvases" ttk::frame $w.name ttk::label $w.name.lab -text "Canvas name:" ttk::entry $w.name.ent $w.name.ent insert 0 [getCanvasName $curcanvas] pack $w.name.lab $w.name.ent -side left -fill x pack $w.name -side top -padx 4 -pady 4 global canvas_list ttk::frame $w.canv listbox $w.canv.cl -bg white -yscrollcommand "$w.canv.scroll set" ttk::scrollbar $w.canv.scroll -orient vertical -command "$w.canv.cl yview" foreach canvas $canvas_list { $w.canv.cl insert end [getCanvasName $canvas] if { $canvas == $curcanvas } { set curindex [expr {[$w.canv.cl size] - 1}] } } pack $w.canv.cl -side left -pady 4 -fill both -expand true pack $w.canv.scroll -side left -fill y pack $w.canv -side top -fill both -expand true -padx 4 -pady 4 $w.canv.cl selection set $curindex $w.canv.cl see $curindex bind $w.canv.cl "manageCanvasSwitch $w" ttk::frame $w.buttons2 foreach b {up down} { set fn "$CORE_DATA_DIR/icons/tiny/arrow.${b}.gif" set img$b [image create photo -file $fn] ttk::button $w.buttons2.$b -image [set img${b}] \ -command "manageCanvasUpDown $w $b" } pack $w.buttons2.up $w.buttons2.down -side left -expand 1 pack $w.buttons2 -side top -fill x -pady 2 # hidden list of canvas numbers ttk::label $w.list -text $canvas_list ttk::frame $w.buttons ttk::button $w.buttons.apply -text "Apply" -command "manageCanvasApply $w" ttk::button $w.buttons.cancel -text "Cancel" -command "destroy $w" pack $w.buttons.apply $w.buttons.cancel -side left -expand 1 pack $w.buttons -side bottom -fill x -pady 2m bind $w "destroy $w" bind $w "manageCanvasApply $w" } # Boeing: manage canvases helper # called when a canvas in the list is double-clicked proc manageCanvasSwitch { w } { global canvas_list curcanvas set i [$w.canv.cl curselection] if {$i == ""} { return} set i [lindex $i 0] set item [$w.canv.cl get $i] foreach canvas $canvas_list { if {[getCanvasName $canvas] == $item} { $w.name.ent delete 0 end $w.name.ent insert 0 $item set curcanvas $canvas switchCanvas none return } } } # manage canvases helper # handle the move up/down buttons for the canvas selection window proc manageCanvasUpDown { w dir } { global canvas_list # get the currently selected item set i [$w.canv.cl curselection] if {$i == ""} { return} set i [lindex $i 0] set item [$w.canv.cl get $i] if {$dir == "down" } { set max [expr {[llength $canvas_list] - 1}] if {$i >= $max } { return } set newi [expr {$i + 1}] } else { if {$i <= 0} { return } set newi [expr {$i - 1}] } # change the position $w.canv.cl delete $i $w.canv.cl insert $newi $item $w.canv.cl selection set $newi $w.canv.cl see $newi # update hidden list of canvas numbers set new_canvas_list [$w.list cget -text] set item [lindex $new_canvas_list $i] set new_canvas_list [lreplace $new_canvas_list $i $i] set new_canvas_list [linsert $new_canvas_list $newi $item] $w.list configure -text $new_canvas_list } # manage canvases helper # called when apply button is pressed - changes the order of the canvases proc manageCanvasApply { w } { global canvas_list curcanvas changed # we calculated this list earlier, making life easier here set new_canvas_list [$w.list cget -text] if {$canvas_list != $new_canvas_list} { set canvas_list $new_canvas_list } set newname [$w.name.ent get] destroy $w if { $newname != [getCanvasName $curcanvas] } { set changed 1 } setCanvasName $curcanvas $newname switchCanvas none updateUndoLog } proc setCanvasScale { canvas scale } { global $canvas set i [lsearch [set $canvas] "scale *"] if { $i >= 0 } { set $canvas [lreplace [set $canvas] $i $i "scale $scale"] } else { set $canvas [linsert [set $canvas] 1 "scale $scale"] } } proc getCanvasScale { canvas } { global $canvas g_prefs set entry [lrange [lsearch -inline [set $canvas] "scale *"] 1 end] set scale [string trim $entry \{\}] if { $scale == "" } { if { ![info exists g_prefs(gui_canvas_scale)] } { return 150.0 } return "$g_prefs(gui_canvas_scale)" } else { return $scale } } proc setCanvasRefPoint { canvas refpt } { global $canvas set i [lsearch [set $canvas] "refpt *"] if { $i >= 0 } { set $canvas [lreplace [set $canvas] $i $i "refpt {$refpt}"] } else { set $canvas [linsert [set $canvas] 1 "refpt {$refpt}"] } } proc getCanvasRefPoint { canvas } { global $canvas g_prefs DEFAULT_REFPT set entry [lrange [lsearch -inline [set $canvas] "refpt *"] 1 end] set altitude [string trim $entry \{\}] if { $altitude == "" } { if { ![info exists g_prefs(gui_canvas_refpt)] } { return $DEFAULT_REFPT } return "$g_prefs(gui_canvas_refpt)" } else { return $altitude } } # from http://wiki.tcl.tk/1415 (MAK) proc canvasSee { hWnd items } { set box [eval $hWnd bbox $items] if {$box == ""} { return } if {[string match {} [$hWnd cget -scrollregion]] } { # People really should set -scrollregion you know... foreach {x y x1 y1} $box break set x [expr round(2.5 * ($x1+$x) / [winfo width $hWnd])] set y [expr round(2.5 * ($y1+$y) / [winfo height $hWnd])] $hWnd xview moveto 0 $hWnd yview moveto 0 $hWnd xview scroll $x units $hWnd yview scroll $y units } else { # If -scrollregion is set properly, use this foreach { x y x1 y1 } $box break foreach { top btm } [$hWnd yview] break foreach { left right } [$hWnd xview] break foreach { p q xmax ymax } [$hWnd cget -scrollregion] break set xpos [expr (($x1+$x) / 2.0) / $xmax - ($right-$left) / 2.0] set ypos [expr (($y1+$y) / 2.0) / $ymax - ($btm-$top) / 2.0] $hWnd xview moveto $xpos $hWnd yview moveto $ypos } } core-4.8/gui/cfgparse.tcl0000664000175000017500000007742012534327775012353 00000000000000# # Copyright 2005-2013 the Boeing Company. # See the LICENSE file included in this distribution. # # # Copyright 2005-2008 University of Zagreb, Croatia. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF # SUCH DAMAGE. # # This work was supported in part by the Croatian Ministry of Science # and Technology through the research contract #IP-2003-143. # #****h* imunes/cfgparse.tcl # NAME # cfgparse.tcl -- file used for parsing the configuration # FUNCTION # This module is used for parsing the configuration, i.e. reading the # configuration from a file or a string and writing the configuration # to a file or a string. This module also contains a function for returning # a new ID for nodes, links and canvases. #**** #****f* nodecfg.tcl/dumpputs # NAME # dumpputs -- puts a string to a file or a string configuration # SYNOPSIS # dumpputs $method $destination $string # FUNCTION # Puts a sting to the file or appends the string configuration (used for # undo functions), the choice depends on the value of method parameter. # INPUTS # * method -- method used. Possiable values are file (if saving the string # to the file) and string (if appending the string configuration) # * dest -- destination used. File_id for files, and string name for string # configuration # * string -- the string that is inserted to a file or appended to the string # configuartion #**** proc dumpputs {method dest string} { switch -exact -- $method { file { puts $dest $string } string { global $dest append $dest "$string " } } } #****f* nodecfg.tcl/dumpCfg # NAME # dumpCfg -- puts the current configuraton to a file or a string # SYNOPSIS # dumpCfg $method $destination # FUNCTION # Writes the working (current) configuration to a file or a string. # INPUTS # * method -- used method. Possiable values are file (saving current congif # to the file) and string (saving current config in a string) # * dest -- destination used. File_id for files, and string name for string # configurations #**** proc dumpCfg {method dest} { global node_list plot_list link_list canvas_list annotation_list global g_comments if { [info exists g_comments] && $g_comments != "" } { dumpputs $method $dest "comments \{" foreach line [split $g_comments "\n"] { dumpputs $method $dest "$line" } dumpputs $method $dest "\}" dumpputs $method $dest "" } foreach node $node_list { global $node upvar 0 $node lnode dumpputs $method $dest "node $node \{" foreach element $lnode { if { "[lindex $element 0]" == "network-config" } { dumpputs $method $dest " network-config \{" foreach line [lindex $element 1] { dumpputs $method $dest " $line" } dumpputs $method $dest " \}" } elseif { "[lindex $element 0]" == "custom-config" } { dumpputs $method $dest " custom-config \{" foreach line [lindex $element 1] { if { $line != {} } { if { [catch {set str [lindex $line 0]} err] } { puts "error loading config: $err" puts "problem section: [lindex $element 0]" puts "problem line: $line" set str "" } if { $str == "config" } { dumpputs $method $dest " config \{" foreach element [lindex $line 1] { dumpputs $method $dest " $element" } dumpputs $method $dest " \}" } else { dumpputs $method $dest " $line" } } } dumpputs $method $dest " \}" } elseif { "[lindex $element 0]" == "ipsec-config" } { dumpputs $method $dest " ipsec-config \{" foreach line [lindex $element 1] { if { $line != {} } { dumpputs $method $dest " $line" } } dumpputs $method $dest " \}" } elseif { "[lindex $element 0]" == "custom-pre-config-commands" } { #Boeing custom pre config commands dumpputs $method $dest " custom-pre-config-commands \{" foreach line [lindex $element 1] { dumpputs $method $dest " $line" } dumpputs $method $dest " \}" } elseif { "[lindex $element 0]" == "custom-post-config-commands" } { #Boeing custom post config commands dumpputs $method $dest " custom-post-config-commands \{" foreach line [lindex $element 1] { dumpputs $method $dest " $line" } dumpputs $method $dest " \}" } elseif { "[lindex $element 0]" == "ine-config" } { # Boeing: INE config support dumpputs $method $dest " ine-config \{" foreach line [lindex $element 1] { dumpputs $method $dest " $line" } dumpputs $method $dest " \}" # end Boeing } else { dumpputs $method $dest " $element" } } dumpputs $method $dest "\}" dumpputs $method $dest "" } foreach obj "link annotation canvas plot" { upvar 0 ${obj}_list obj_list foreach elem $obj_list { global $elem upvar 0 $elem lelem dumpputs $method $dest "$obj $elem \{" foreach element $lelem { dumpputs $method $dest " $element" } dumpputs $method $dest "\}" dumpputs $method $dest "" } } global g_traffic_flows if { [info exists g_traffic_flows] && [llength $g_traffic_flows] > 0 } { dumpputs $method $dest "traffic \{" foreach flow $g_traffic_flows { dumpputs $method $dest " $flow" } dumpputs $method $dest "\}" dumpputs $method $dest "" } global g_hook_scripts if { [info exists g_hook_scripts] && [llength $g_hook_scripts] > 0 } { foreach hook $g_hook_scripts { set name [lindex $hook 0] set state [lindex $hook 1] set script [lindex $hook 2] dumpputs $method $dest "hook $state:$name \{" foreach line [split $script "\n"] { dumpputs $method $dest "$line" } dumpputs $method $dest "\}" dumpputs $method $dest "" } } dumpGlobalOptions $method $dest # session options dumpputs $method $dest "option session \{" foreach kv [getSessionOptionsList] { dumpputs $method $dest " $kv" } dumpputs $method $dest "\}" dumpputs $method $dest "" } proc dumpGlobalOptions { method dest } { global showIfNames showNodeLabels showLinkLabels global showIfIPaddrs showIfIPv6addrs global showBkgImage showGrid showAnnotations global showAPI global g_view_locked global g_traffic_start_opt global mac_addr_start dumpputs $method $dest "option global \{" if {$showIfNames == 0} { dumpputs $method $dest " interface_names no" } else { dumpputs $method $dest " interface_names yes" } if {$showIfIPaddrs == 0} { dumpputs $method $dest " ip_addresses no" } else { dumpputs $method $dest " ip_addresses yes" } if {$showIfIPv6addrs == 0} { dumpputs $method $dest " ipv6_addresses no" } else { dumpputs $method $dest " ipv6_addresses yes" } if {$showNodeLabels == 0} { dumpputs $method $dest " node_labels no" } else { dumpputs $method $dest " node_labels yes" } if {$showLinkLabels == 0} { dumpputs $method $dest " link_labels no" } else { dumpputs $method $dest " link_labels yes" } if {$showAPI == 0} { dumpputs $method $dest " show_api no" } else { dumpputs $method $dest " show_api yes" } if {$showBkgImage == 0} { dumpputs $method $dest " background_images no" } else { dumpputs $method $dest " background_images yes" } if {$showAnnotations == 0} { dumpputs $method $dest " annotations no" } else { dumpputs $method $dest " annotations yes" } if {$showGrid == 0} { dumpputs $method $dest " grid no" } else { dumpputs $method $dest " grid yes" } if {$g_view_locked == 1} { dumpputs $method $dest " locked yes" } if { [info exists g_traffic_start_opt] } { dumpputs $method $dest " traffic_start $g_traffic_start_opt" } if { [info exists mac_addr_start] && $mac_addr_start > 0 } { dumpputs $method $dest " mac_address_start $mac_addr_start" } dumpputs $method $dest "\}" dumpputs $method $dest "" } # get the global options into a list of key=value pairs proc getGlobalOptionList {} { global tmp set tmp "" dumpGlobalOptions string tmp ;# put "options global {items}" into tmp set items [lindex $tmp 2] return [listToKeyValues $items] } proc setGlobalOption { field value } { global showIfNames showNodeLabels showLinkLabels global showIfIPaddrs showIfIPv6addrs global showBkgImage showGrid showAnnotations global showAPI global mac_addr_start global g_traffic_start_opt global g_view_locked switch -exact -- $field { interface_names { if { $value == "no" } { set showIfNames 0 } elseif { $value == "yes" } { set showIfNames 1 } } ip_addresses { if { $value == "no" } { set showIfIPaddrs 0 } elseif { $value == "yes" } { set showIfIPaddrs 1 } } ipv6_addresses { if { $value == "no" } { set showIfIPv6addrs 0 } elseif { $value == "yes" } { set showIfIPv6addrs 1 } } node_labels { if { $value == "no" } { set showNodeLabels 0 } elseif { $value == "yes" } { set showNodeLabels 1 } } link_labels { if { $value == "no" } { set showLinkLabels 0 } elseif { $value == "yes" } { set showLinkLabels 1 } } show_api { if { $value == "no" } { set showAPI 0 } elseif { $value == "yes" } { set showAPI 1 } } background_images { if { $value == "no" } { set showBkgImage 0 } elseif { $value == "yes" } { set showBkgImage 1 } } annotations { if { $value == "no" } { set showAnnotations 0 } elseif { $value == "yes" } { set showAnnotations 1 } } grid { if { $value == "no" } { set showGrid 0 } elseif { $value == "yes" } { set showGrid 1 } } locked { if { $value == "yes" } { set g_view_locked 1 } else { set g_view_locked 0 } } mac_address_start { set mac_addr_start $value } traffic_start { set g_traffic_start_opt $value } } } # reset global vars when opening a new file proc cleanupGUIState {} { global node_list link_list plot_list canvas_list annotation_list global mac_addr_start g_comments global g_traffic_flows g_traffic_start_opt g_hook_scripts global g_view_locked set node_list {} set link_list {} set annotation_list {} set plot_list {} set canvas_list {} set g_traffic_flows "" set g_traffic_start_opt 0 set g_hook_scripts "" set g_comments "" set g_view_locked 0 resetSessionOptions } #****f* nodecfg.tcl/loadCfg # NAME # loadCfg -- loads the current configuration. # SYNOPSIS # loadCfg $cfg # FUNCTION # Loads the configuration written in the cfg string to a current # configuration. # INPUTS # * cfg -- string containing the new working configuration. #**** proc loadCfg { cfg } { global node_list plot_list link_list canvas_list annotation_list global g_traffic_flows g_traffic_start_opt g_hook_scripts global g_view_locked global g_comments # maximum coordinates set maxX 0 set maxY 0 set do_upgrade [upgradeOldConfig cfg] if { $do_upgrade == "no"} { return } # Cleanup first cleanupGUIState set class "" set object "" foreach entry $cfg { if {"$class" == ""} { set class $entry continue } elseif {"$object" == ""} { set object $entry if {"$class" == "node"} { lappend node_list $object } elseif {"$class" == "link"} { lappend link_list $object } elseif {"$class" == "canvas"} { lappend canvas_list $object } elseif {"$class" == "plot"} { lappend plot_list $object } elseif {"$class" == "option"} { # do nothing } elseif {"$class" == "traffic"} { ;# save traffic flows set g_traffic_flows [split [string trim $object] "\n"] set class ""; set object ""; continue } elseif {"$class" == "script"} { # global_script (old config) becomes a runtime hook set name "runtime_hook.sh" set script [string trim $object] lappend g_hook_scripts [list $name 4 $script] ;# 4=RUNTIME_STATE set class ""; set object ""; continue } elseif {"$class" == "hook"} { continue } elseif {"$class" == "comments"} { set g_comments [string trim $object] set class ""; set object ""; continue } elseif {"$class" == "annotation"} { lappend annotation_list $object } else { puts "configuration parsing error: unknown object class $class" #exit 1 } # create an empty global variable named object for most objects global $object set $object {} continue } else { set line [concat $entry] # uses 'key=value' instead of 'key value' if { $object == "session" } { # 'key=value', values with space needs quoting 'key={space val}' setSessionOptions "" [split $line "\n"] set class "" set object "" continue } # extracts "field { value }" elements from line if { [catch { set tmp [llength $line] } e] } { puts "*** Error with line ('$e'):\n$line" puts "*** Line will be skipped. This is a Tcl limitation, " puts "*** consider using XML or fixing with whitespace." continue } while {[llength $line] >= 2} { set field [lindex $line 0] if {"$field" == ""} { set line [lreplace $line 0 0] continue } # consume first two list elements from line set value [lindex $line 1] set line [lreplace $line 0 1] if {"$class" == "node"} { switch -exact -- $field { type { lappend $object "type $value" } mirror { lappend $object "mirror $value" } model { lappend $object "model $value" } cpu { lappend $object "cpu {$value}" } interface-peer { lappend $object "interface-peer {$value}" } network-config { set cfg "" foreach zline [split $value { }] { if { [string index "$zline" 0] == " " } { set zline [string replace "$zline" 0 0] } lappend cfg $zline } set cfg [lrange $cfg 1 [expr {[llength $cfg] - 2}]] lappend $object "network-config {$cfg}" } custom-enabled { lappend $object "custom-enabled $value" } custom-command { lappend $object "custom-command {$value}" } custom-config { set cfg "" set have_config 0 set ccfg {} foreach zline [split $value "\n"] { if { [string index "$zline" 0] == \ " " } { # remove leading tab character set zline [string replace "$zline" 0 0] } # flag for config lines if { $zline == "config \{" } { set have_config 1 # collect custom config lines into list } elseif { $have_config == 1 } { lappend ccfg $zline # add non-config lines } else { lappend cfg $zline } } # chop off last brace in config { } block and add it if { $have_config } { set ccfg [lrange $ccfg 0 \ [expr {[llength $ccfg] - 3}]] lappend cfg [list config $ccfg] } #set cfg [lrange $cfg 1 [expr {[llength $cfg] - 2}]] lappend $object "custom-config {$cfg}" } ipsec-enabled { lappend $object "ipsec-enabled $value" } ipsec-config { set cfg "" foreach zline [split $value { }] { if { [string index "$zline" 0] == " " } { set zline [string replace "$zline" 0 0] } lappend cfg $zline } set cfg [lrange $cfg 1 [expr {[llength $cfg] - 2}]] lappend $object "ipsec-config {$cfg}" } iconcoords { checkMaxCoords $value maxX maxY lappend $object "iconcoords {$value}" } labelcoords { checkMaxCoords $value maxX maxY lappend $object "labelcoords {$value}" } canvas { lappend $object "canvas $value" } hidden { lappend $object "hidden $value" } /* { set comment "$field $value" foreach c $line { lappend comment $c # consume one element from line set line [lreplace $line 0 0] if { $c == "*/" } { break } } lappend $object "$comment" } custom-pre-config-commands { # Boeing - custom pre config commands set cfg "" foreach zline [split $value { }] { if { [string index "$zline" 0] == " " } { set zline [string replace "$zline" 0 0] } lappend cfg $zline } set cfg [lrange $cfg 1 [expr [llength $cfg] - 2]] lappend $object "custom-pre-config-commands {$cfg}" } custom-post-config-commands { # Boeing - custom post config commands set cfg "" foreach zline [split $value { }] { if { [string index "$zline" 0] == " " } { set zline [string replace "$zline" 0 0] } lappend cfg $zline } set cfg [lrange $cfg 1 [expr [llength $cfg] - 2]] lappend $object "custom-post-config-commands {$cfg}" } custom-image { # Boeing - custom-image lappend $object "custom-image $value" } ine-config { # Boeing - INE set cfg "" foreach zline [split $value { }] { if { [string index "$zline" 0] == " " } { set zline [string replace "$zline" 0 0] } lappend cfg $zline } set cfg [lrange $cfg 1 [expr [llength $cfg] - 2]] lappend $object "ine-config {$cfg}" } tunnel-peer { # Boeing - Span tunnels lappend $object "tunnel-peer {$value}" } range { # Boeing - WLAN range lappend $object "range $value" } bandwidth { # Boeing - WLAN bandwidth lappend $object "bandwidth $value" } cli-enabled { puts "Warning: cli-enabled setting is deprecated" } delay { # Boeing - WLAN delay lappend $object "delay $value" } ber { # Boeing - WLAN BER lappend $object "ber $value" } location { # Boeing - node location lappend $object "location $value" } os { # Boeing - node OS # just ignore it, set at runtime } services { lappend $object "services {$value}" } default { # Boeing - added warning puts -nonewline "config file warning: unknown confi" puts "guration item '$field' ignored for $object" } } } elseif {"$class" == "plot"} { switch -exact -- $field { name { lappend $object "name $value" } height { lappend $object "height $value" } width { lappend $object "width $value" } x { lappend $object "x $value" } y { lappend $object "y $value" } color { lappend $object "color $value" } } } elseif {"$class" == "link"} { switch -exact -- $field { nodes { lappend $object "nodes {$value}" } mirror { lappend $object "mirror $value" } bandwidth - delay - ber - duplicate - jitter { if { [llength $value] > 1 } { ;# down/up-stream lappend $object "$field {$value}" } else { lappend $object "$field $value" } } color { lappend $object "color $value" } width { lappend $object "width $value" } default { # this enables opaque data to be stored along with # each link (any key is stored) lappend $object "$field $value" # Boeing - added warning #puts -nonewline "config file warning: unknown conf" #puts "iguration item '$field' ignored for $object" } } } elseif {"$class" == "canvas"} { switch -exact -- $field { name { lappend $object "name {$value}" } size { lappend $object "size {$value}" } bkgImage { lappend $object "wallpaper {$value}" } wallpaper { lappend $object "wallpaper {$value}" } wallpaper-style { lappend $object "wallpaper-style {$value}" } scale { lappend $object "scale {$value}" } refpt { lappend $object "refpt {$value}" } } } elseif {"$class" == "option"} { setGlobalOption $field $value } elseif {"$class" == "annotation"} { switch -exact -- $field { type { lappend $object "type $value" } iconcoords { lappend $object "iconcoords {$value}" } color { lappend $object "color $value" } border { lappend $object "border $value" } label { lappend $object "label {$value}" } labelcolor { lappend $object "labelcolor $value" } size { lappend $object "size $value" } canvas { lappend $object "canvas $value" } font { lappend $object "font {$value}" } fontfamily { lappend $object "fontfamily {$value}" } fontsize { lappend $object "fontsize {$value}" } effects { lappend $object "effects {$value}" } width { lappend $object "width $value" } rad { lappend $object "rad $value" } } ;# end switch } elseif {"$class" == "hook"} { set state_name [split $object :] if { [llength $state_name] != 2 } { puts "invalid hook in config file" continue } set state [lindex $state_name 0] set name [lindex $state_name 1] set lines [split $entry "\n"] set lines [lreplace $lines 0 0] ;# chop extra newline set lines [join $lines "\n"] set hook [list $name $state $lines] lappend g_hook_scripts $hook set line "" ;# exit this while loop } ;#endif class } } set class "" set object "" } # # Hack for comaptibility with old format files (no canvases) # if { $canvas_list == "" } { set curcanvas [newCanvas ""] foreach node $node_list { setNodeCanvas $node $curcanvas } } # auto resize canvas set curcanvas [lindex $canvas_list 0] set newX 0 set newY 0 if { $maxX > [lindex [getCanvasSize $curcanvas] 0] } { set newX [expr {$maxX + 50}] } if { $maxY > [lindex [getCanvasSize $curcanvas] 1] } { set newY [expr {$maxY + 50}] } if { $newX > 0 || $newY > 0 } { if { $newX == 0 } { set newX [lindex [getCanvasSize $curcanvas] 0] } if { $newY == 0 } { set newY [lindex [getCanvasSize $curcanvas] 1] } setCanvasSize $curcanvas $newX $newY } # extra upgrade steps if { $do_upgrade == "yes" } { upgradeNetworkConfigToServices } upgradeConfigRemoveNode0 upgradeConfigServices upgradeWlanConfigs } #****f* nodecfg.tcl/newObjectId # NAME # newObjectId -- new object Id # SYNOPSIS # set obj_id [newObjectId $type] # FUNCTION # Returns the Id for a new object of the defined type. Supported types # are node, link and canvas. The Id is in the form $mark$number. $mark is the # first letter of the given type and $number is the first available number to # that can be used for id. # INPUTS # * type -- the type of the new object. Can be node, link or canvas. # RESULT # * obj_id -- object Id in the form $mark$number. $mark is the # first letter of the given type and $number is the first available number to # that can be used for id. #**** proc newObjectId { type } { global node_list link_list annotation_list canvas_list set mark [string range [set type] 0 0] set id 1 ;# start numbering at 1, not 0 while {[lsearch [set [set type]_list] "$mark$id"] != -1} { incr id } return $mark$id } # Boeing: pick a new link id for temporary newlinks proc newlinkId { } { global link_list set id [newObjectId link] set mark "l" set id 0 # alllinks contains a list of all existing and new links set alllinks $link_list foreach newlink [.c find withtag "newlink"] { set newlinkname [lindex [.c gettags $newlink] 1] lappend alllinks $newlinkname } while {[lsearch $alllinks "$mark$id"] != -1 } { incr id } return $mark$id } # Boeing: helper fn to determine canvas size during load proc checkMaxCoords { str maxXp maxYp } { upvar 1 $maxXp maxX upvar 1 $maxYp maxY set x [lindex $str 0] set y [lindex $str 1] if { $x > $maxX } { set maxX $x } if { $y > $maxY } { set maxY $y } if { [llength $str] == 4 } { set x [lindex $str 2] set y [lindex $str 3] if { $x > $maxX } { set maxX $x } if { $y > $maxY } { set maxY $y } } } # Boeing: pick a router for OSPF proc newRouterId { type node } { set mark [string range [set type] 0 0] for { set id 0 } { $node != "$mark$id" } { incr id } { } return "0.0.0.${id}" } # end Boeing # Boeing: load servers.conf file into exec_servers array proc loadServersConf { } { global CONFDIR exec_servers DEFAULT_API_PORT set confname "$CONFDIR/servers.conf" if { [catch { set f [open "$confname" r] } ] } { puts "Creating a default $confname" if { [catch { set f [open "$confname" w+] } ] } { puts "***Warning: could not create a default $confname file." return } puts $f "core1 192.168.0.2 $DEFAULT_API_PORT" puts $f "core2 192.168.0.3 $DEFAULT_API_PORT" close $f if { [catch { set f [open "$confname" r] } ] } { return } } array unset exec_servers while { [ gets $f line ] >= 0 } { if { [string range $line 0 0] == "#" } { continue } ;# skip comments set l [split $line] ;# parse fields separated by whitespace set name [lindex $l 0] set ip [lindex $l 1] set port [lindex $l 2] set sock -1 if { $name == "" } { continue } ;# blank name # load array of servers array set exec_servers [list $name [list $ip $port $sock]] } close $f } # end Boeing # Boeing: write servers.conf file from exec_servers array proc writeServersConf { } { global CONFDIR exec_servers set confname "$CONFDIR/servers.conf" if { [catch { set f [open "$confname" w] } ] } { puts "***Warning: could not write servers file: $confname" return } set header "# servers.conf: list of CORE emulation servers for running" set header "$header remotely." puts $f $header foreach server [lsort -dictionary [array names exec_servers]] { set ip [lindex $exec_servers($server) 0] set port [lindex $exec_servers($server) 1] puts $f "$server $ip $port" } close $f } # end Boeing # display the preferences dialog proc popupPrefs {} { global EDITORS TERMS set wi .core_prefs catch { destroy $wi } toplevel $wi wm transient $wi . wm resizable $wi 0 0 wm title $wi "Preferences" global g_prefs g_prefs_old array set g_prefs_old [array get g_prefs] # # Paths # labelframe $wi.dirs -borderwidth 4 -text "Paths" -relief raised frame $wi.dirs.conf label $wi.dirs.conf.label -text "Default configuration file path:" entry $wi.dirs.conf.entry -bg white -width 40 \ -textvariable g_prefs(default_conf_path) pack $wi.dirs.conf.label $wi.dirs.conf.entry -side left pack $wi.dirs.conf -side top -anchor w -padx 4 -pady 4 frame $wi.dirs.mru label $wi.dirs.mru.label -text "Number of recent files to remember:" entry $wi.dirs.mru.num -bg white -width 3 \ -textvariable g_prefs(num_recent) button $wi.dirs.mru.clear -text "Clear recent files" \ -command "addFileToMrulist \"\"" pack $wi.dirs.mru.label $wi.dirs.mru.num $wi.dirs.mru.clear -side left pack $wi.dirs.mru -side top -anchor w -padx 4 -pady 4 pack $wi.dirs -side top -fill x # # Window # labelframe $wi.win -borderwidth 4 -text "GUI Window" -relief raised frame $wi.win.win checkbutton $wi.win.win.savepos -text "remember window position" \ -variable g_prefs(gui_save_pos) checkbutton $wi.win.win.savesiz -text "remember window size" \ -variable g_prefs(gui_save_size) pack $wi.win.win.savepos $wi.win.win.savesiz -side left -anchor w -padx 4 pack $wi.win.win -side top -anchor w -padx 4 -pady 4 frame $wi.win.a checkbutton $wi.win.a.snaptogrid -text "snap to grid" \ -variable g_prefs(gui_snap_grid) checkbutton $wi.win.a.showtooltips -text "show tooltips" \ -variable g_prefs(gui_show_tooltips) pack $wi.win.a.snaptogrid $wi.win.a.showtooltips \ -side left -anchor w -padx 4 pack $wi.win.a -side top -anchor w -padx 4 -pady 4 frame $wi.win.canv label $wi.win.canv.label -text "Default canvas size:" entry $wi.win.canv.x -bg white -width 5 -textvariable g_prefs(gui_canvas_x) entry $wi.win.canv.y -bg white -width 5 -textvariable g_prefs(gui_canvas_y) label $wi.win.canv.label2 -text "Default # of canvases:" entry $wi.win.canv.num -bg white -width 5 \ -textvariable g_prefs(gui_num_canvases) pack $wi.win.canv.label $wi.win.canv.x $wi.win.canv.y \ $wi.win.canv.label2 $wi.win.canv.num \ -side left -anchor w -padx 4 pack $wi.win.canv -side top -anchor w -padx 4 -pady 4 pack $wi.win -side top -fill x # # Programs # labelframe $wi.pr -borderwidth 4 -text "Programs" -relief raised frame $wi.pr.editor label $wi.pr.editor.label -text "Text editor:" set editors [linsert $EDITORS 0 "EDITOR"] ttk::combobox $wi.pr.editor.combo -width 10 -exportselection 0 \ -values $editors -textvariable g_prefs(gui_text_editor) label $wi.pr.editor.label2 -text "Terminal program:" set terms [linsert $TERMS 0 "TERM"] ttk::combobox $wi.pr.editor.combo2 -width 20 -exportselection 0 \ -values $terms -textvariable g_prefs(gui_term_prog) pack $wi.pr.editor.label $wi.pr.editor.combo -padx 4 -pady 4 -side left pack $wi.pr.editor.label2 $wi.pr.editor.combo2 -padx 4 -pady 4 -side left pack $wi.pr.editor -side top -anchor w -padx 4 -pady 4 frame $wi.pr.3d label $wi.pr.3d.label -text "3D GUI command:" entry $wi.pr.3d.entry -bg white -width 40 -textvariable g_prefs(gui_3d_path) pack $wi.pr.3d.label $wi.pr.3d.entry -side left -padx 4 -pady 4 pack $wi.pr.3d -side top -anchor w -padx 4 -pady 4 pack $wi.pr -side top -fill x # # Buttons at the bottom # frame $wi.bot -borderwidth 0 button $wi.bot.apply -text "Save" -command "savePrefsFile; destroy $wi" button $wi.bot.defaults -text "Load defaults" -command initDefaultPrefs button $wi.bot.cancel -text "Cancel" -command { global g_prefs g_prefs_old array set g_prefs [array get g_prefs_old] destroy .core_prefs } pack $wi.bot.cancel $wi.bot.defaults $wi.bot.apply -side right pack $wi.bot -side bottom -fill x after 100 { catch { grab .core_prefs } } } # initialize preferences array with default values proc initDefaultPrefs {} { global g_prefs CONFDIR SBINDIR DEFAULT_REFPT tcl_platform # variable expansions must be done here array set g_prefs [list default_conf_path "$CONFDIR/configs"] array set g_prefs [list gui_canvas_refpt "$DEFAULT_REFPT"] if { $tcl_platform(os) == "FreeBSD" } { set shell "/usr/local/bin/bash" } else { set shell "bash" } array set g_prefs [list shell $shell] array set g_prefs [list gui_text_editor [get_text_editor true]] array set g_prefs [list gui_term_prog [get_term_prog true]] setDefaultAddrs ipv4 setDefaultAddrs ipv6 # preferences will be reordered alphabetically array set g_prefs { num_recent 4 log_path "/tmp/core_logs" gui_save_pos 0 gui_save_size 0 gui_snap_grid 0 gui_show_tooltips 1 gui_canvas_x 1000 gui_canvas_y 750 gui_canvas_scale 150.0 gui_num_canvases 1 gui_3d_path "/usr/local/bin/sdt3d.sh" } # add new preferences above; keep this at the end of the file } core-4.8/gui/core.tcl0000664000175000017500000001321112534327775011475 00000000000000# # Copyright 2005-2013 the Boeing Company. # See the LICENSE file included in this distribution. # # # Copyright 2004-2008 University of Zagreb, Croatia. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF # SUCH DAMAGE. # # This work was supported in part by Croatian Ministry of Science # and Technology through the research contract #IP-2003-143. # if {[lindex $argv 0] == "-b" || [lindex $argv 0] == "--batch"} { set argv [lrange $argv 1 end] set execMode batch } elseif {[lindex $argv 0] == "-c" || [lindex $argv 0] == "--closebatch"} { set argv [lrange $argv 1 end] set execMode closebatch } elseif {[lindex $argv 0] == "--addons"} { set argv [lrange $argv 1 end] set execMode addons } else { set execMode interactive } set LIBDIR "" set SBINDIR "/usr/local/sbin" set CONFDIR "." set CORE_DATA_DIR "." set CORE_STATE_DIR "." set CORE_START_DIR "" set CORE_USER "" if { [info exists env(LIBDIR)] } { set LIBDIR $env(LIBDIR) } if { [info exists env(SBINDIR)] } { set SBINDIR $env(SBINDIR) } if { [info exists env(CONFDIR)] } { set CONFDIR $env(CONFDIR) } if { [info exists env(CORE_DATA_DIR)] } { set CORE_DATA_DIR $env(CORE_DATA_DIR) } if { [info exists env(CORE_STATE_DIR)] } { set CORE_STATE_DIR $env(CORE_STATE_DIR) } if { [info exists env(CORE_START_DIR)] } { set CORE_START_DIR $env(CORE_START_DIR) } if { [info exists env(CORE_USER)] } { set CORE_USER $env(CORE_USER) } source "$LIBDIR/version.tcl" source "$LIBDIR/linkcfg.tcl" source "$LIBDIR/nodecfg.tcl" source "$LIBDIR/ipv4.tcl" source "$LIBDIR/ipv6.tcl" source "$LIBDIR/cfgparse.tcl" source "$LIBDIR/exec.tcl" source "$LIBDIR/canvas.tcl" source "$LIBDIR/editor.tcl" source "$LIBDIR/annotations.tcl" source "$LIBDIR/help.tcl" source "$LIBDIR/filemgmt.tcl" source "$LIBDIR/ns2imunes.tcl" source "$LIBDIR/mobility.tcl" source "$LIBDIR/api.tcl" source "$LIBDIR/wlan.tcl" source "$LIBDIR/wlanscript.tcl" source "$LIBDIR/util.tcl" source "$LIBDIR/plugins.tcl" source "$LIBDIR/nodes.tcl" source "$LIBDIR/services.tcl" source "$LIBDIR/traffic.tcl" source "$LIBDIR/exceptions.tcl" # # Global variables are initialized here # set node_list {} set link_list {} set annotation_list {} set canvas_list {} set eid e0 set plot_list {} array set exec_servers {} loadServersConf ;# populate exec_servers # global vars set showAPI 0 set mac_byte4 0 set mac_byte5 0 set g_mrulist {} initDefaultPrefs loadDotFile loadPluginsConf checkCommandLineAddressPort autoConnectPlugins set g_abort_session 0 # # Initialization should be complete now, so let's start doing something... # if {$execMode == "interactive"} { # GUI-related files source "$LIBDIR/widget.tcl" source "$LIBDIR/tooltips.tcl" source "$LIBDIR/initgui.tcl" source "$LIBDIR/topogen.tcl" source "$LIBDIR/graph_partitioning.tcl" source "$LIBDIR/gpgui.tcl" source "$LIBDIR/debug.tcl" # Load all Tcl files from the addons directory foreach file [glob -nocomplain -directory "$LIBDIR/addons" *.tcl] { if { [catch { if { [file isfile $file ] } { source "$file"; } } e] } { puts "*** Error loading addon file: $file" puts " $e" } } setOperMode edit fileOpenStartUp foreach arg $argv { if { $arg == "--start" } { global currentFile if { [file extension $currentFile] == ".xml" } { after 100; update; # yield to other events so XML file after 100; update; # can be loaded and received } startStopButton "exec"; break; } } # Boeing changed elseif to catch batch and else to output error } elseif {$execMode == "batch"} { puts "batch execute $argv" set sock [lindex [getEmulPlugin "*"] 2] if { $sock == "" || $sock == "-1" || $sock == -1 } { exit.real; } if {$argv != ""} { global currentFile set currentFile [argAbsPathname $argv] set fileId [open $currentFile r] set cfg "" foreach entry [read $fileId] { lappend cfg $entry } close $fileId after 100 { loadCfg $cfg deployCfgAPI $sock puts "Waiting to enter RUNTIME state..." } global vwaitdummy vwait vwaitdummy } } elseif {$execMode == "closebatch"} { global g_session_choice set g_session_choice $argv puts "Attempting to close session $argv ..." global vwaitdummy vwait vwaitdummy } elseif {$execMode == "addons"} { # pass control to included addons code foreach file [glob -nocomplain -directory "$LIBDIR/addons" *.tcl] { if { [file isfile $file ] } { source "$file"; } } global vwaitdummy vwait vwaitdummy } else { puts "ERROR: execMode is not set in core.tcl" } core-4.8/gui/debug.tcl0000664000175000017500000000261112534327775011635 00000000000000# # CORE Debugger # Copyright 2005-2013 the Boeing Company. # See the LICENSE file included in this distribution. # # author: Jeff Ahrenholz # .menubar.tools add command -label "Debugger..." -command popupDebugger set g_last_debug_cmd "puts \"Hello world\"" proc popupDebugger {} { global g_last_debug_cmd set wi .debugger catch { destroy $wi } toplevel $wi wm transient $wi . wm resizable $wi 300 200 wm title $wi "CORE Debugger" frame $wi.dbg -borderwidth 4 label $wi.dbg.label1 \ -text "Enter TCL/Tk commands below, press Run to evaluate:" text $wi.dbg.cmd -bg white -width 100 -height 3 pack $wi.dbg.label1 $wi.dbg.cmd -side top -anchor w -padx 4 -pady 4 pack $wi.dbg -side top $wi.dbg.cmd insert end "$g_last_debug_cmd" frame $wi.btn # evaluate debugging commands entered into the text box below button $wi.btn.exec -text "Run" -command { global g_last_debug_cmd set wi .debugger set i 1 set g_last_debug_cmd "" while { 1 } { set cmd [$wi.dbg.cmd get $i.0 $i.end] set g_last_debug_cmd "$g_last_debug_cmd$cmd\n" if { $cmd == "" } { break } catch { eval $cmd } output puts $output incr i } } button $wi.btn.close -text "Close" -command "destroy .debugger" pack $wi.btn.exec $wi.btn.close -side left -padx 4 -pady 4 pack $wi.btn -side bottom } core-4.8/gui/editor.tcl0000664000175000017500000046775112534327775012061 00000000000000# # Copyright 2005-2013 the Boeing Company. # See the LICENSE file included in this distribution. # # # Copyright 2004-2008 University of Zagreb, Croatia. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF # SUCH DAMAGE. # # This work was supported in part by the Croatian Ministry of Science # and Technology through the research contract #IP-2003-143. # #****h* imunes/editor.tcl # NAME # editor.tcl -- file used for defining functions that can be used in # edit mode as well as all the functions which change the appearance # of the imunes GUI. # FUNCTION # This module is used for defining all possible actions in imunes # edit mode. It is also used for all the GUI related actions. #**** proc animateCursor {} { global cursorState global clock_seconds if { [clock seconds] == $clock_seconds } { update return } set clock_seconds [clock seconds] if { $cursorState } { .c config -cursor watch set cursorState 0 } else { .c config -cursor pirate set cursorState 1 } update } #****f* editor.tcl/removeGUILink # NAME # removeGUILink -- remove link from GUI # SYNOPSIS # renoveGUILink $link_id $atomic # FUNCTION # Removes link from GUI. It removes standard links as well as # split links and links connecting nodes on different canvases. # INPUTS # * link_id -- the link id # * atomic -- defines if the remove was atomic action or a part # of a composed, non-atomic action (relevant for updating log # for undo). #**** proc removeGUILink { link atomic } { global changed set nodes [linkPeers $link] set node1 [lindex $nodes 0] set node2 [lindex $nodes 1] if { [nodeType $node1] == "pseudo" } { removeLink [getLinkMirror $link] removeLink $link removeNode [getNodeMirror $node1] removeNode $node1 .c delete $node1 } elseif { [nodeType $node2] == "pseudo" } { removeLink [getLinkMirror $link] removeLink $link removeNode [getNodeMirror $node2] removeNode $node2 .c delete $node2 } else { removeLink $link } .c delete $link if { $atomic == "atomic" } { set changed 1 updateUndoLog } } #****f* editor.tcl/removeGUINode # NAME # removeGUINode -- remove node from GUI # SYNOPSIS # renoveGUINode $node_id # FUNCTION # Removes node from GUI. When removing a node from GUI the links # connected to that node are also removed. # INPUTS # * node_id -- node id #**** proc removeGUINode { node } { set type [nodeType $node] foreach ifc [ifcList $node] { set peer [peerByIfc $node $ifc] set link [lindex [.c gettags "link && $node && $peer"] 1] removeGUILink $link non-atomic } if { [lsearch -exact "oval rectangle label text marker" $type] != -1 } { deleteAnnotation .c $type $node } elseif { $type != "pseudo" } { removeNode $node .c delete $node } } #****f* editor.tcl/updateUndoLog # NAME # updateUndoLog -- update the undo log # SYNOPSIS # updateUndoLog # FUNCTION # Updates the undo log. Writes the current configuration to the # undolog array and updates the undolevel variable. #**** proc updateUndoLog {} { global changed undolog undolevel redolevel if { $changed } { global t_undolog undolog set t_undolog "" dumpCfg string t_undolog incr undolevel set undolog($undolevel) $t_undolog set redolevel $undolevel updateUndoRedoMenu "" # Boeing: XXX why is this set here? set changed 0 } } #****f* editor.tcl/undo # NAME # undo -- undo function # SYNOPSIS # undo # FUNCTION # Undo the change. Reads the undolog and updates the current # configuration. Reduces the value of undolevel. #**** proc undo {} { global undolevel undolog oper_mode if {$oper_mode == "edit" && $undolevel > 0} { incr undolevel -1 updateUndoRedoMenu "" .c config -cursor watch loadCfg $undolog($undolevel) switchCanvas none } } #****f* editor.tcl/redo # NAME # redo # SYNOPSIS # redo # FUNCTION # Redo the change if possible (redolevel is greater than # undolevel). Reads the configuration from undolog and # updates the current configuration. Increases the value # of undolevel. #**** proc redo {} { global undolevel redolevel undolog oper_mode if {$oper_mode == "edit" && $redolevel > $undolevel} { incr undolevel updateUndoRedoMenu "" .c config -cursor watch loadCfg $undolog($undolevel) switchCanvas none } } proc updateUndoRedoMenu { forced } { global undolevel redolevel if { $forced == "" } { if { $undolevel > 0 } { set undo "normal" } else { set undo "disabled" } if { $redolevel > $undolevel } { set redo "normal" } else { set redo "disabled" } } else { set undo $forced set redo $forced } .menubar.edit entryconfigure "Undo" -state $undo .menubar.edit entryconfigure "Redo" -state $redo } #****f* editor.tcl/redrawAll # NAME # redrawAll # SYNOPSIS # redrawAll # FUNCTION # Redraws all the objects on the current canvas. #**** proc redrawAll {} { global node_list plot_list link_list annotation_list plot_list background sizex sizey grid global curcanvas zoom global showAnnotations showGrid #Call_Trace ;# debugging when things disappear .bottom.zoom config -text "zoom [expr {int($zoom * 100)}]%" set e_sizex [expr {int($sizex * $zoom)}] set e_sizey [expr {int($sizey * $zoom)}] set border 28 .c configure -scrollregion \ "-$border -$border [expr {$e_sizex + $border}] \ [expr {$e_sizey + $border}]" saveRestoreWlanLinks .c save .c delete all set background [.c create rectangle 0 0 $e_sizex $e_sizey \ -fill white -tags "background"] # Boeing: wallpaper set wallpaper [lindex [getCanvasWallpaper $curcanvas] 0] set wallpaperStyle [lindex [getCanvasWallpaper $curcanvas] 1] if { $wallpaper != "" } { drawWallpaper .c $wallpaper $wallpaperStyle } # end Boeing if { $showAnnotations == 1 } { foreach obj $annotation_list { # fix annotations having no canvas (from old config) if { [getNodeCanvas $obj] == "" } { setNodeCanvas $obj $curcanvas} if { [getNodeCanvas $obj] == $curcanvas } { drawAnnotation $obj } } } # Grid set e_grid [expr {int($grid * $zoom)}] set e_grid2 [expr {$e_grid * 2}] if { $showGrid } { for { set x $e_grid } { $x < $e_sizex } { incr x $e_grid } { if { [expr {$x % $e_grid2}] != 0 } { if { $zoom > 0.5 } { .c create line $x 1 $x $e_sizey \ -fill gray -dash {1 7} -tags "grid" } } else { .c create line $x 1 $x $e_sizey -fill gray -dash {1 3} \ -tags "grid" } } for { set y $e_grid } { $y < $e_sizey } { incr y $e_grid } { if { [expr {$y % $e_grid2}] != 0 } { if { $zoom > 0.5 } { .c create line 1 $y $e_sizex $y \ -fill gray -dash {1 7} -tags "grid" } } else { .c create line 1 $y $e_sizex $y -fill gray -dash {1 3} \ -tags "grid" } } } .c lower -withtags background foreach node $node_list { if { [getNodeCanvas $node] == $curcanvas } { drawNode .c $node } } redrawAllThruplots foreach link $link_list { set nodes [linkPeers $link] if { [getNodeCanvas [lindex $nodes 0]] != $curcanvas || [getNodeCanvas [lindex $nodes 1]] != $curcanvas } { continue } drawLink $link redrawLink $link updateLinkLabel $link } saveRestoreWlanLinks .c restore .c config -cursor left_ptr raiseAll .c } #****f* editor.tcl/drawNode # NAME # drawNode # SYNOPSIS # drawNode node_id # FUNCTION # Draws the specified node. Draws node's image (router pc # host lanswitch rj45 hub pseudo) and label. # The visibility of the label depends on the showNodeLabels # variable for all types of nodes and on invisible variable # for pseudo nodes. # INPUTS # * node_id -- node id #**** proc drawNode { c node } { global showNodeLabels global router pc host lanswitch rj45 hub pseudo global curcanvas zoom global wlan if { $c == "" } { set c .c } ;# default canvas set type [nodeType $node] set coords [getNodeCoords $node] set x [expr {[lindex $coords 0] * $zoom}] set y [expr {[lindex $coords 1] * $zoom}] # special handling for custom images, dummy nodes # could move this to separate getImage function set model "" set cimg "" set imgzoom $zoom if { $zoom == 0.75 || $zoom == 1.5 } { set imgzoom 1.0 } if { $type == "router" } { set model [getNodeModel $node] set cimg [getNodeTypeImage $model normal] } set tmp [absPathname [getCustomImage $node]] if { $tmp != "" } { set cimg $tmp } if { $cimg != "" } { # name of global variable storing the image is the filename without path set img [file tail $cimg] # create the variable if the image hasn't been loaded before global [set img] if { ![info exists $img] } { if { [catch { set [set img] [image create photo -file $cimg] createScaledImages $img } e ] } { ;# problem loading image file puts "icon error: $e" set cimg "" ;# fall back to default model icon setCustomImage $node "" ;# prevent errors elsewhere } } if { $cimg != "" } { ;# only if image file loaded global $img$imgzoom $c create image $x $y -image [set $img$imgzoom] -tags "node $node" } } if { $cimg == "" } { if { $type == "pseudo" } { $c create image $x $y -image [set $type] -tags "node $node" } else { # create scaled images based on zoom level global $type$imgzoom $c create image $x $y -image [set $type$imgzoom] \ -tags "node $node" } } set coords [getNodeLabelCoords $node] set x [expr {[lindex $coords 0] * $zoom}] set y [expr {[lindex $coords 1] * $zoom}] if { [nodeType $node] != "pseudo" } { ;# Boeing: show remote server set loc [getNodeLocation $node] set labelstr0 "" if { $loc != "" } { set labelstr0 "([getNodeLocation $node]):" } set labelstr1 [getNodeName $node]; set labelstr2 "" if [info exists getNodePartition] { [getNodePartition $node]; } set l [format "%s%s\n%s" $labelstr0 $labelstr1 $labelstr2]; set label [$c create text $x $y -fill blue \ -text "$l" \ -tags "nodelabel $node"] } else { set pnode [getNodeName $node] set pcanvas [getNodeCanvas $pnode] set ifc [ifcByPeer $pnode [getNodeMirror $node]] if { $pcanvas != $curcanvas } { set label [$c create text $x $y -fill blue \ -text "[getNodeName $pnode]:$ifc @[getCanvasName $pcanvas]" \ -tags "nodelabel $node" -justify center] } else { set label [$c create text $x $y -fill blue \ -text "[getNodeName $pnode]:$ifc" \ -tags "nodelabel $node" -justify center] } } if { $showNodeLabels == 0} { $c itemconfigure $label -state hidden } global invisible if { $invisible == 1 && [nodeType $node] == "pseudo" } { $c itemconfigure $label -state hidden } } #****f* editor.tcl/drawLink # NAME # drawLink # SYNOPSIS # drawLink link_id # FUNCTION # Draws the specified link. An arrow is displayed for links # connected to pseudo nodes. If the variable invisible # is specified link connecting a pseudo node stays hidden. # INPUTS # * link_id -- link id #**** proc drawLink { link } { set nodes [linkPeers $link] set lnode1 [lindex $nodes 0] set lnode2 [lindex $nodes 1] set lwidth [getLinkWidth $link] if { [getLinkMirror $link] != "" } { set newlink [.c create line 0 0 0 0 \ -fill [getLinkColor $link] -width $lwidth \ -tags "link $link $lnode1 $lnode2" -arrow both] } else { set newlink [.c create line 0 0 0 0 \ -fill [getLinkColor $link] -width $lwidth \ -tags "link $link $lnode1 $lnode2"] } # Boeing: links between two nodes on different servers if { [getNodeLocation $lnode1] != [getNodeLocation $lnode2]} { .c itemconfigure $newlink -dash ","; } # end Boeing # XXX Invisible pseudo-liks global invisible if { $invisible == 1 && [getLinkMirror $link] != "" } { .c itemconfigure $link -state hidden } # Boeing: wlan links are hidden if { [nodeType $lnode1] == "wlan" || [nodeType $lnode2] == "wlan" } { global zoom set imgzoom $zoom if { $zoom == 0.75 || $zoom == 1.5 } { set imgzoom 1.0 } global antenna$imgzoom .c itemconfigure $link -state hidden .c create image 0 0 -image [set antenna$imgzoom] \ -tags "antenna $lnode2 $link" .c create text 0 0 -tags "interface $lnode1 $link" -justify center .c create text 0 0 -tags "interface $lnode2 $link" -justify center .c raise interface "link || linklabel || background" } else { .c raise $newlink background .c create text 0 0 -tags "linklabel $link" -justify center .c create text 0 0 -tags "interface $lnode1 $link" -justify center .c create text 0 0 -tags "interface $lnode2 $link" -justify center .c raise linklabel "link || background" .c raise interface "link || linklabel || background" } foreach n [list $lnode1 $lnode2] { if { [getNodeHidden $n] } { hideNode $n statline "Hidden node(s) exist." } } } # draw a green link between wireless nodes (or other color if multiple WLANs) # WLAN links appear on the canvas but not in the global link_list proc drawWlanLink { node1 node2 wlan } { global zoom defLinkWidth curcanvas set c .c set wlanlink [$c find withtag "wlanlink && $node1 && $node2 && $wlan"] if { $wlanlink != "" } { return $wlanlink ;# already exists } set color [getWlanColor $wlan] set xy [getNodeCoords $node1] set x [lindex $xy 0]; set y [lindex $xy 1] set pxy [getNodeCoords $node2] set px [lindex $pxy 0]; set py [lindex $pxy 1] set wlanlink [$c create line [expr {$x*$zoom}] [expr {$y*$zoom}] \ [expr {$px*$zoom}] [expr {$py*$zoom}] \ -fill $color -width $defLinkWidth \ -tags "wlanlink $node1 $node2 $wlan"] if { [getNodeCanvas $node1] == $curcanvas && [getNodeCanvas $node2] == $curcanvas} { $c itemconfigure $wlanlink -state normal $c raise $wlanlink "background || grid || oval || rectangle" } else { $c itemconfigure $wlanlink -state hidden } return $wlanlink } #****f* editor.tcl/chooseIfName # NAME # chooseIfName -- choose interface name # SYNOPSIS # set ifcName [chooseIfName $lnode1 $lnode2] # FUNCTION # Choose intreface name. The name can be: # * eth -- for interface connecting pc, host and router # * e -- for interface connecting hub and lanswitch # INPUTS # * link_id -- link id # RESULT # * ifcName -- the name of the interface #**** proc chooseIfName { lnode1 lnode2 } { global $lnode1 $lnode2 # TODO: just check if layer == NETWORK and return eth, LINK return e switch -exact -- [nodeType $lnode1] { pc { return eth } host { return eth } hub { return e } lanswitch { return e } router { return eth } rj45 { return } tunnel { return e } ktunnel { return } wlan { return e } default { return eth # end Boeing: below } } } #****f* editor.tcl/listLANNodes # NAME # listLANNodes -- list LAN nodes # SYNOPSIS # set l2peers [listLANNodes $l2node $l2peers] # FUNCTION # Recursive function for finding all link layer nodes that are # connected to node l2node. Returns the list of all link layer # nodes that are on the same LAN as l2node. # INPUTS # * l2node -- node id of a link layer node # * l2peers -- old link layer nodes on the same LAN # RESULT # * l2peers -- new link layer nodes on the same LAN #**** proc listLANnodes { l2node l2peers } { lappend l2peers $l2node foreach ifc [ifcList $l2node] { set peer [logicalPeerByIfc $l2node $ifc] set type [nodeType $peer] # Boeing if { [ lsearch {lanswitch hub wlan} $type] != -1 } { if { [lsearch $l2peers $peer] == -1 } { set l2peers [listLANnodes $peer $l2peers] } } } return $l2peers } #****f* editor.tcl/calcDxDy # NAME # calcDxDy lnode -- list LAN nodes # SYNOPSIS # calcDxDy $lnode # FUNCTION # Calculates dx and dy variables of the calling function. # INPUTS # * lnode -- node id of a node whose dx and dy coordinates are # calculated #**** proc calcDxDy { lnode } { global showIfIPaddrs showIfIPv6addrs zoom upvar dx x upvar dy y if { $zoom > 1.0 } { set x 1 set y 1 return } switch -exact -- [nodeType $lnode] { hub { set x [expr {1.5 / $zoom}] set y [expr {2.6 / $zoom}] } lanswitch { set x [expr {1.5 / $zoom}] set y [expr {2.6 / $zoom}] } router { set x [expr {1 / $zoom}] set y [expr {2 / $zoom}] } rj45 { set x [expr {1 / $zoom}] set y [expr {1 / $zoom}] } tunnel { set x [expr {1 / $zoom}] set y [expr {1 / $zoom}] } wlan { set x [expr {1.5 / $zoom}] set y [expr {2.6 / $zoom}] } default { set x [expr {1 / $zoom}] set y [expr {2 / $zoom}] } } return } #****f* editor.tcl/updateIfcLabel # NAME # updateIfcLabel -- update interface label # SYNOPSIS # updateIfcLabel $lnode1 $lnode2 # FUNCTION # Updates the interface label, including interface name, # interface state (* for interfaces that are down), IPv4 # address and IPv6 address. # INPUTS # * lnode1 -- node id of a node where the interface resides # * lnode2 -- node id of the node that is connected by this # interface. #**** proc updateIfcLabel { lnode1 lnode2 } { global showIfNames showIfIPaddrs showIfIPv6addrs set link [lindex [.c gettags "link && $lnode1 && $lnode2"] 1] set ifc [ifcByPeer $lnode1 $lnode2] set ifipv4addr [getIfcIPv4addr $lnode1 $ifc] set ifipv6addr [getIfcIPv6addr $lnode1 $ifc] if { $ifc == 0 } { set ifc "" } if { [getIfcOperState $lnode1 $ifc] == "down" } { set labelstr "*" } else { set labelstr "" } if { $showIfNames } { set labelstr "$labelstr$ifc " } if { $showIfIPaddrs && $ifipv4addr != "" } { set labelstr "$labelstr$ifipv4addr " } if { $showIfIPv6addrs && $ifipv6addr != "" } { set labelstr "$labelstr$ifipv6addr " } set labelstr \ [string range $labelstr 0 [expr {[string length $labelstr] - 2}]] .c itemconfigure "interface && $lnode1 && $link" \ -text "$labelstr" # Boeing: hide ifc label on wlans if { [nodeType $lnode1] == "wlan" } { .c itemconfigure "interface && $lnode1 && $link" -state hidden } } #****f* editor.tcl/updateLinkLabel # NAME # updateLinkLabel -- update link label # SYNOPSIS # updateLinkLabel $link # FUNCTION # Updates the link label, including link bandwidth, link delay, # BER and duplicate values. # INPUTS # * link -- link id of the link whose labels are updated. #**** proc updateLinkLabel { link } { global showLinkLabels set bwstr [getLinkBandwidthString $link] set delstr [getLinkDelayString $link] set berstr [getLinkBERString $link] set dupstr [getLinkDupString $link] set labelstr " " if { "$bwstr" != "" } { set labelstr "$labelstr$bwstr " } if { "$delstr" != "" } { set labelstr "$labelstr$delstr " } if { "$berstr" != "" } { set labelstr "$labelstr$berstr " } if { "$dupstr" != "" } { set labelstr "$labelstr$dupstr " } set labelstr \ [string range $labelstr 0 [expr {[string length $labelstr] - 2}]] .c itemconfigure "linklabel && $link" -text "$labelstr" if { $showLinkLabels == 0} { .c itemconfigure "linklabel && $link" -state hidden } } #****f* editor.tcl/redrawAllLinks # NAME # redrawAllLinks -- redraw all links # SYNOPSIS # redrawAllLinks # FUNCTION # Redraws all links on the current canvas. #**** proc redrawAllLinks {} { global link_list curcanvas foreach link $link_list { set nodes [linkPeers $link] if { [getNodeCanvas [lindex $nodes 0]] != $curcanvas || [getNodeCanvas [lindex $nodes 1]] != $curcanvas } { continue } redrawLink $link } } #****f* editor.tcl/redrawLink # NAME # redrawLink -- redraw a links # SYNOPSIS # redrawLink $link # FUNCTION # Redraws the specified link. # INPUTS # * link -- link id #**** proc redrawLink { link } { global $link set limages [.c find withtag "link && $link"] set limage1 [lindex $limages 0] set limage2 [lindex $limages 1] set tags [.c gettags $limage1] set link [lindex $tags 1] set lnode1 [lindex $tags 2] set lnode2 [lindex $tags 3] set coords1 [.c coords "node && $lnode1"] set coords2 [.c coords "node && $lnode2"] set x1 [lindex $coords1 0] set y1 [lindex $coords1 1] set x2 [lindex $coords2 0] set y2 [lindex $coords2 1] .c coords $limage1 $x1 $y1 $x2 $y2 .c coords $limage2 $x1 $y1 $x2 $y2 set lx [expr {0.5 * ($x1 + $x2)}] set ly [expr {0.5 * ($y1 + $y2)}] .c coords "linklabel && $link" $lx $ly set n [expr {sqrt (($x1 - $x2) * ($x1 - $x2) + \ ($y1 - $y2) * ($y1 - $y2)) * 0.015}] if { $n < 1 } { set n 1 } calcDxDy $lnode1 set lx [expr {($x1 * ($n * $dx - 1) + $x2) / $n / $dx}] set ly [expr {($y1 * ($n * $dy - 1) + $y2) / $n / $dy}] .c coords "interface && $lnode1 && $link" $lx $ly updateIfcLabel $lnode1 $lnode2 calcDxDy $lnode2 set lx [expr {($x1 + $x2 * ($n * $dx - 1)) / $n / $dx}] set ly [expr {($y1 + $y2 * ($n * $dy - 1)) / $n / $dy}] .c coords "interface && $lnode2 && $link" $lx $ly updateIfcLabel $lnode2 $lnode1 # Boeing - wlan antennas if { [nodeType $lnode1] == "wlan" } { global zoom set an [lsearch -exact [findWlanNodes $lnode2] $lnode1] if { $an < 0 || $an >= 5 } { set an 0 } set dx [expr {20 - (10*$an)}] .c coords "antenna && $lnode2 && $link" [expr {$x2-($dx*$zoom)}] \ [expr {$y2-(20*$zoom)}] } } # Boeing proc redrawWlanLink { link } { global $link set tags [.c gettags $link] set lnode1 [lindex $tags 1] set lnode2 [lindex $tags 2] set coords1 [.c coords "node && $lnode1"] set coords2 [.c coords "node && $lnode2"] set x1 [lindex $coords1 0] set y1 [lindex $coords1 1] set x2 [lindex $coords2 0] set y2 [lindex $coords2 1] set lx [expr {0.5 * ($x1 + $x2)}] set ly [expr {0.5 * ($y1 + $y2)}] .c coords $link $x1 $y1 $x2 $y2 .c coords "linklabel && $lnode2 && $lnode1" $lx $ly return } # end Boeing #****f* editor.tcl/splitGUILink # NAME # splitGUILink -- splits a links # SYNOPSIS # splitGUILink $link # FUNCTION # Splits the link and draws new links and new pseudo nodes # on the canvas. # INPUTS # * link -- link id #**** proc splitGUILink { link } { global changed zoom set peer_nodes [linkPeers $link] set new_nodes [splitLink $link pseudo] set orig_node1 [lindex $peer_nodes 0] set orig_node2 [lindex $peer_nodes 1] set new_node1 [lindex $new_nodes 0] set new_node2 [lindex $new_nodes 1] set new_link1 [linkByPeers $orig_node1 $new_node1] set new_link2 [linkByPeers $orig_node2 $new_node2] setLinkMirror $new_link1 $new_link2 setLinkMirror $new_link2 $new_link1 setNodeMirror $new_node1 $new_node2 setNodeMirror $new_node2 $new_node1 setNodeName $new_node1 $orig_node2 setNodeName $new_node2 $orig_node1 set x1 [lindex [getNodeCoords $orig_node1] 0] set y1 [lindex [getNodeCoords $orig_node1] 1] set x2 [lindex [getNodeCoords $orig_node2] 0] set y2 [lindex [getNodeCoords $orig_node2] 1] setNodeCoords $new_node1 \ "[expr {($x1 + 0.4 * ($x2 - $x1)) / $zoom}] \ [expr {($y1 + 0.4 * ($y2 - $y1)) / $zoom}]" setNodeCoords $new_node2 \ "[expr {($x1 + 0.6 * ($x2 - $x1)) / $zoom}] \ [expr {($y1 + 0.6 * ($y2 - $y1)) / $zoom}]" setNodeLabelCoords $new_node1 [getNodeCoords $new_node1] setNodeLabelCoords $new_node2 [getNodeCoords $new_node2] set changed 1 updateUndoLog redrawAll } #****f* editor.tcl/selectNode # NAME # selectNode -- select node # SYNOPSIS # selectNode $c $obj # FUNCTION # Crates the selecting box around the specified canvas # object. # INPUTS # * c -- tk canvas # * obj -- tk canvas object tag id #**** proc selectNode { c obj } { set node [lindex [$c gettags $obj] 1] if { $node == "" } { return } ;# Boeing: fix occassional error $c addtag selected withtag "node && $node" if { [nodeType $node] == "pseudo" } { set bbox [$c bbox "nodelabel && $node"] } elseif { [nodeType $node] == "rectangle" } { $c addtag selected withtag "rectangle && $node" set bbox [$c bbox "rectangle && $node"] } elseif { [nodeType $node] == "text" } { $c addtag selected withtag "text && $node" set bbox [$c bbox "text && $node"] } elseif { [nodeType $node] == "oval" } { $c addtag selected withtag "oval && $node" set bbox [$c bbox "oval && $node"] } else { set bbox [$c bbox "node && $node"] } set bx1 [expr {[lindex $bbox 0] - 2}] set by1 [expr {[lindex $bbox 1] - 2}] set bx2 [expr {[lindex $bbox 2] + 1}] set by2 [expr {[lindex $bbox 3] + 1}] $c delete -withtags "selectmark && $node" $c create line $bx1 $by1 $bx2 $by1 $bx2 $by2 $bx1 $by2 $bx1 $by1 \ -dash {6 4} -fill black -width 1 -tags "selectmark $node" } proc selectNodes { nodelist } { foreach node $nodelist { selectNode .c [.c find withtag "node && $node"] } } proc selectedNodes {} { set selected {} foreach obj [.c find withtag "node && selected"] { lappend selected [lindex [.c gettags $obj] 1] } foreach obj [.c find withtag "oval && selected"] { lappend selected [lindex [.c gettags $obj] 1] } foreach obj [.c find withtag "rectangle && selected"] { lappend selected [lindex [.c gettags $obj] 1] } foreach obj [.c find withtag "text && selected"] { lappend selected [lindex [.c gettags $obj] 1] } return $selected } proc selectedRealNodes {} { set selected {} foreach obj [.c find withtag "node && selected"] { set node [lindex [.c gettags $obj] 1] if { [getNodeMirror $node] != "" || [nodeType $node] == "rj45" } { continue } lappend selected $node } return $selected } proc selectAdjacent {} { global curcanvas set selected [selectedNodes] set adjacent {} foreach node $selected { foreach ifc [ifcList $node] { set peer [peerByIfc $node $ifc] if { [getNodeMirror $peer] != "" } { return } if { [lsearch $adjacent $peer] < 0 } { lappend adjacent $peer } } } selectNodes $adjacent } #****f* editor.tcl/button3link # NAME # button3link # SYNOPSIS # button3link $c $x $y # FUNCTION # This procedure is called when a right mouse button is # clicked on the canvas. If there is a link on the place of # mouse click this procedure creates and configures a popup # menu. The options in the menu are: # * Configure -- configure the link # * Delete -- delete the link # * Split -- split the link # * Merge -- this option is active only if the link is previously # been split, by this action the link is merged. # INPUTS # * c -- tk canvas # * x -- x coordinate for popup menu # * y -- y coordinate for popup menu #**** proc button3link { c x y } { global oper_mode env eid canvas_list node_list global curcanvas set link [lindex [$c gettags {link && current}] 1] if { $link == "" } { set link [lindex [$c gettags {linklabel && current}] 1] if { $link == "" } { return } } .button3menu delete 0 end # # Configure link # .button3menu add command -label "Configure" \ -command "popupConfigDialog $c" # # Delete link # if { $oper_mode != "exec" } { .button3menu add command -label "Delete" \ -command "removeGUILink $link atomic" } else { .button3menu add command -label "Delete" \ -state disabled } # # Split link # if { $oper_mode != "exec" && [getLinkMirror $link] == "" } { .button3menu add command -label "Split" \ -command "splitGUILink $link" } else { .button3menu add command -label "Split" \ -state disabled } # # Merge two pseudo nodes / links # if { $oper_mode != "exec" && [getLinkMirror $link] != "" && [getNodeCanvas [getNodeMirror [lindex [linkPeers $link] 1]]] == $curcanvas } { .button3menu add command -label "Merge" \ -command "mergeGUINode [lindex [linkPeers $link] 1]" } else { .button3menu add command -label "Merge" -state disabled } set x [winfo pointerx .] set y [winfo pointery .] tk_popup .button3menu $x $y } #****f* editor.tcl/movetoCanvas # NAME # movetoCanvas -- move to canvas # SYNOPSIS # movetoCanvas $canvas # FUNCTION # This procedure moves all the nodes selected in the GUI to # the specified canvas. # INPUTS # * canvas -- canvas id. #**** proc movetoCanvas { canvas } { global changed set selected_nodes [selectedNodes] foreach node $selected_nodes { setNodeCanvas $node $canvas set changed 1 } foreach obj [.c find withtag "linklabel"] { set link [lindex [.c gettags $obj] 1] set link_peers [linkPeers $link] set peer1 [lindex $link_peers 0] set peer2 [lindex $link_peers 1] set peer1_in_selected [lsearch $selected_nodes $peer1] set peer2_in_selected [lsearch $selected_nodes $peer2] if { ($peer1_in_selected == -1 && $peer2_in_selected != -1) || ($peer1_in_selected != -1 && $peer2_in_selected == -1) } { if { [nodeType $peer2] == "pseudo" } { setNodeCanvas $peer2 $canvas if { [getNodeCanvas [getNodeMirror $peer2]] == $canvas } { mergeLink $link } continue } set new_nodes [splitLink $link pseudo] set new_node1 [lindex $new_nodes 0] set new_node2 [lindex $new_nodes 1] setNodeMirror $new_node1 $new_node2 setNodeMirror $new_node2 $new_node1 setNodeName $new_node1 $peer2 setNodeName $new_node2 $peer1 set link1 [linkByPeers $peer1 $new_node1] set link2 [linkByPeers $peer2 $new_node2] setLinkMirror $link1 $link2 setLinkMirror $link2 $link1 } } updateUndoLog redrawAll } #****f* editor.tcl/mergeGUINode # NAME # mergeGUINode -- merge GUI node # SYNOPSIS # mergeGUINode $node # FUNCTION # This procedure removes the specified pseudo node as well # as it's mirror copy. Also this procedure removes the # pseudo links and reestablish the original link between # the non-pseudo nodes. # INPUTS # * node -- node id of a pseudo node. #**** proc mergeGUINode { node } { set link [lindex [linkByIfc $node [ifcList $node]] 0] mergeLink $link redrawAll } #****f* editor.tcl/button3node # NAME # button3node # SYNOPSIS # button3node $c $x $y # FUNCTION # This procedure is called when a right mouse button is # clicked on the canvas. Also called when double-clicking # on a node during runtime. # If there is a node on the place of # mouse click this procedure creates and configures a popup # menu. The options in the menu are: # * Configure -- configure the node # * Create link to -- create a link to any available node, # it can be on the same canvas or on a different canvas. # * Move to -- move to some other canvas # * Merge -- this option is available only for pseudo nodes # that have mirror nodes on the same canvas (Pseudo nodes # created by splitting a link). # * Delete -- delete the node # * Shell window -- specifies the shell window to open in # exec mode. This option is available only to nodes on a # network layer # * Ethereal -- opens a Ethereal program for the specified # node and the specified interface. This option is available # only for network layer nodes in exec mode. # INPUTS # * c -- tk canvas # * x -- x coordinate for popup menu # * y -- y coordinate for popup menu #**** #old proc button3node { c x y } #Boeing proc button3node { c x y button } { global oper_mode env eid canvas_list node_list curcanvas systype g_prefs set node [lindex [$c gettags {node && current}] 1] if { $node == "" } { set node [lindex [$c gettags {nodelabel && current}] 1] if { $node == "" } { return } } set mirror_node [getNodeMirror $node] if { [$c gettags "node && $node && selected"] == "" } { $c dtag node selected $c delete -withtags selectmark selectNode $c [$c find withtag "current"] } # open up shells upon double-click or shift/ctrl-click set shell $g_prefs(shell) if { $button == "shift" || $button == "ctrl" } { if { [nodeType $node] == "pseudo" } { # # Hyperlink to another canvas # set curcanvas [getNodeCanvas [getNodeMirror $node]] switchCanvas none return } # only open bash shells for NETWORK nodes and remote routers if { [[typemodel $node].layer] != "NETWORK" } { if { [typemodel $node] == "wlan" } { wlanDoubleClick $node $button } return } if { $button == "shift" } { ;# normal bash shell spawnShell $node $shell } else { ;# right-click vtysh shell set cmd [[typemodel $node].shellcmd $node] if { $cmd != "/bin/sh" && $cmd != "" } { spawnShell $node $cmd } } return ;# open shell, don't post a menu } # # below here we build and post a menu # .button3menu delete 0 end # # Configure node # if { [nodeType $node] != "pseudo" } { .button3menu add command -label "Configure" \ -command "popupConfigDialog $c" } else { .button3menu add command -label "Configure" \ -command "popupConfigDialog $c" -state disabled } # # Select adjacent # if { [nodeType $node] != "pseudo" } { .button3menu add command -label "Select adjacent" \ -command "selectAdjacent" } else { .button3menu add command -label "Select adjacent" \ -command "selectAdjacent" -state disabled } # # Create a new link - can be between different canvases # .button3menu.connect delete 0 end if { $oper_mode == "exec" || [nodeType $node] == "pseudo" } { #.button3menu add cascade -label "Create link to" \ -menu .button3menu.connect -state disabled } else { .button3menu add cascade -label "Create link to" \ -menu .button3menu.connect } destroy .button3menu.connect.selected menu .button3menu.connect.selected -tearoff 0 .button3menu.connect add cascade -label "Selected" \ -menu .button3menu.connect.selected .button3menu.connect.selected add command \ -label "Chain" -command "P \[selectedRealNodes\]" .button3menu.connect.selected add command \ -label "Star" \ -command "Kb \[lindex \[selectedRealNodes\] 0\] \ \[lrange \[selectedNodes\] 1 end\]" .button3menu.connect.selected add command \ -label "Cycle" -command "C \[selectedRealNodes\]" .button3menu.connect.selected add command \ -label "Clique" -command "K \[selectedRealNodes\]" .button3menu.connect add separator foreach canvas $canvas_list { destroy .button3menu.connect.$canvas menu .button3menu.connect.$canvas -tearoff 0 .button3menu.connect add cascade -label [getCanvasName $canvas] \ -menu .button3menu.connect.$canvas } foreach peer_node $node_list { set canvas [getNodeCanvas $peer_node] if { $node != $peer_node && [nodeType $node] != "rj45" && [lsearch {pseudo rj45} [nodeType $peer_node]] < 0 && [ifcByLogicalPeer $node $peer_node] == "" } { .button3menu.connect.$canvas add command \ -label [getNodeName $peer_node] \ -command "newGUILink $node $peer_node" } elseif { [nodeType $peer_node] != "pseudo" } { .button3menu.connect.$canvas add command \ -label [getNodeName $peer_node] \ -state disabled } } # # assign to emulation server # if { $oper_mode != "exec" } { global exec_servers node_location .button3menu.assign delete 0 end .button3menu add cascade -label "Assign to" -menu .button3menu.assign .button3menu.assign add command -label "(none)" \ -command "assignSelection \"\"" foreach server [lsort -dictionary [array names exec_servers]] { .button3menu.assign add command -label "$server" \ -command "assignSelection $server" } } # # wlan link to all nodes # if { [nodeType $node] == "wlan" } { .button3menu add command -label "Link to all routers" \ -command "linkAllNodes $node" set msg "Select new WLAN $node members:" set cmd "linkSelectedNodes $node" .button3menu add command -label "Select WLAN members..." \ -command "popupSelectNodes \"$msg\" \"\" {$cmd}" set state normal if { $oper_mode != "exec" } { set state disabled } .button3menu add command -label "Mobility script..." \ -command "showMobilityScriptPopup $node" -state $state } # # Move to another canvas # .button3menu.moveto delete 0 end if { $oper_mode != "exec" && [nodeType $node] != "pseudo" } { .button3menu add cascade -label "Move to" \ -menu .button3menu.moveto .button3menu.moveto add command -label "Canvas:" -state disabled foreach canvas $canvas_list { if { $canvas != $curcanvas } { .button3menu.moveto add command \ -label [getCanvasName $canvas] \ -command "movetoCanvas $canvas" } else { .button3menu.moveto add command \ -label [getCanvasName $canvas] -state disabled } } } # # Merge two pseudo nodes / links # if { $oper_mode != "exec" && [nodeType $node] == "pseudo" && \ [getNodeCanvas $mirror_node] == $curcanvas } { .button3menu add command -label "Merge" \ -command "mergeGUINode $node" } # # Delete selection # if { $oper_mode != "exec" } { .button3menu add command -label "Cut" -command cutSelection .button3menu add command -label "Copy" -command copySelection .button3menu add command -label "Paste" -command pasteSelection .button3menu add command -label "Delete" -command deleteSelection } .button3menu add command -label "Hide" -command "hideSelected" # Boeing: flag used below set execstate disabled if { $oper_mode == "exec" } { set execstate normal } # # Shell selection # .button3menu.shell delete 0 end if { $oper_mode == "exec" && [[typemodel $node].layer] == "NETWORK" } { .button3menu add cascade -label "Shell window" \ -menu .button3menu.shell set cmd [[typemodel $node].shellcmd $node] if { $cmd != "/bin/sh" && $cmd != "" } { ;# typically adds vtysh .button3menu.shell add command -label "$cmd" \ -command "spawnShell $node $cmd" } .button3menu.shell add command -label "/bin/sh" \ -command "spawnShell $node sh" .button3menu.shell add command -label "$shell" \ -command "spawnShell $node $shell" } # # services # .button3menu.services delete 0 end if { $oper_mode == "exec" && [[typemodel $node].layer] == "NETWORK" } { addServicesRightClickMenu .button3menu $node } else { .button3menu add command -label "Services..." -command \ "sendConfRequestMessage -1 $node services 0x1 -1 \"\"" } # # Tcpdump, gpsd # if { $oper_mode == "exec" && [[typemodel $node].layer] == "NETWORK" } { addInterfaceCommand $node .button3menu "Tcpdump" "tcpdump -n -l -i" \ $execstate 1 addInterfaceCommand $node .button3menu "TShark" "tshark -n -l -i" \ $execstate 1 addInterfaceCommand $node .button3menu "Wireshark" "wireshark -k -i" \ $execstate 0 # wireshark on host veth pair -- need veth pair name #wireshark -k -i if { [lindex $systype 0] == "Linux" } { set name [getNodeName $node] .button3menu add command -label "View log..." -state $execstate \ -command "spawnShell $node \"less ../$name.log\"" } } # # Finally post the popup menu on current pointer position # set x [winfo pointerx .] set y [winfo pointery .] tk_popup .button3menu $x $y } #****f* editor.tcl/spawnShell # NAME # spawnShell -- spawn shell # SYNOPSIS # spawnShell $node $cmd # FUNCTION # This procedure spawns a new shell for a specified node. # The shell is specified in cmd parameter. # INPUTS # * node -- node id of the node for which the shell # is spawned. # * cmd -- the path to the shell. #**** proc spawnShell { node cmd } { # request an interactive terminal set sock [lindex [getEmulPlugin $node] 2] set flags 0x44 ;# set TTY, critical flags set exec_num [newExecCallbackRequest shell] sendExecMessage $sock $node $cmd $exec_num $flags } # add a sub-menu to the parentmenu with the given command for each interface proc addInterfaceCommand { node parentmenu txt cmd state isnodecmd } { global g_current_session set childmenu "$parentmenu.[lindex $cmd 0]" $childmenu delete 0 end $parentmenu add cascade -label $txt -menu $childmenu -state $state if { ! $isnodecmd } { if { $g_current_session == 0 } { set state disabled } set ssid [shortSessionID $g_current_session] } foreach ifc [ifcList $node] { set addr [lindex [getIfcIPv4addr $node $ifc] 0] if { $addr != "" } { set addr " ($addr)" } if { $isnodecmd } { ;# run command in a node set icmd "spawnShell $node \"$cmd $ifc\"" } else { ;# exec a command directly set nodenum [string range $node 1 end] set ifnum [string range $ifc 3 end] set localifc veth$nodenum.$ifnum.$ssid set icmd "exec $cmd $localifc &" } $childmenu add command -label "$ifc$addr" -state $state -command $icmd } } # Boeing: consolodate various raise statements here proc raiseAll {c} { $c raise rectangle background $c raise oval "rectangle || background" $c raise grid "oval || rectangle || background" $c raise link "grid || oval || rectangle || background" $c raise linklabel "link || grid || oval || rectangle || background" $c raise newlink "linklabel || link || grid || oval || rectangle || background" $c raise wlanlink "newlink || linklabel || link || grid || oval || rectangle || background" $c raise antenna "wlanlink || newlink || linklabel || link || grid || oval || rectangle || background" $c raise interface "antenna || wlanlink || newlink || linklabel || link || grid || oval || rectangle || background" $c raise node "interface || antenna || wlanlink || newlink || linklabel || link || grid || oval || rectangle || background" $c raise nodelabel "node || interface || antenna || wlanlink || newlink || linklabel || link || grid || oval || rectangle || background" $c raise text "nodelabel || node || interface || antenna || wlanlink || newlink || linklabel || link || grid || oval || rectangle || background" $c raise -cursor } # end Boeing #****f* editor.tcl/button1 # NAME # button1 # SYNOPSIS # button1 $c $x $y $button # FUNCTION # This procedure is called when a left mouse button is # clicked on the canvas. This procedure selects a new # node or creates a new node, depending on the selected # tool. # INPUTS # * c -- tk canvas # * x -- x coordinate # * y -- y coordinate # * button -- the keyboard button that is pressed. #**** proc button1 { c x y button } { global node_list plot_list curcanvas zoom global activetool activetoolp newlink curobj changed def_router_model global router pc host lanswitch rj45 hub global oval rectangle text global lastX lastY global background selectbox global defLinkColor defLinkWidth global resizemode resizeobj global wlan g_twoNodeSelect global g_view_locked set x [$c canvasx $x] set y [$c canvasy $y] set lastX $x set lastY $y # TODO: clean this up # - too many global variables # - too many hardcoded cases (lanswitch, router, etc) # - should be functionalized since lengthy if-else difficult to read set curobj [$c find withtag current] set curtype [lindex [$c gettags current] 0] if { $curtype == "node" || \ $curtype == "oval" || $curtype == "rectangle" || $curtype == "text" \ || ( $curtype == "nodelabel" && \ [nodeType [lindex [$c gettags $curobj] 1]] == "pseudo") } { set node [lindex [$c gettags current] 1] set wasselected \ [expr {[lsearch [$c find withtag "selected"] \ [$c find withtag "node && $node"]] > -1}] if { $button == "ctrl" } { if { $wasselected } { $c dtag $node selected $c delete -withtags "selectmark && $node" } } elseif { !$wasselected } { $c dtag node selected $c delete -withtags selectmark } if { $activetool == "select" && !$wasselected} { selectNode $c $curobj } } elseif { $curtype == "selectmark" } { setResizeMode $c $x $y } elseif { $activetool == "plot" } { # plot tool: create new plot windows when clicking on a link set link "" set tags [$c gettags $curobj] if { $curtype == "link" || $curtype == "linklabel" } { set link [lindex $tags 1] } elseif { $curtype == "interface" } { set link [lindex $tags 2] } if { $link != "" } { thruPlot $c $link $x $y 150 220 false } return } elseif { $button != "ctrl" || $activetool != "select" } { $c dtag node selected $c delete -withtags selectmark } # user has clicked on a blank area or background item if { [lsearch [.c gettags $curobj] background] != -1 || [lsearch [.c gettags $curobj] grid] != -1 || [lsearch [.c gettags $curobj] annotation] != -1 } { # left mouse button pressed to create a new node if { [lsearch {select marker link mobility twonode run stop oval \ rectangle text} $activetool] < 0 } { if { $g_view_locked == 1 } { return } if { $activetoolp == "routers" } { set node [newNode router] setNodeModel $node $activetool } else { set node [newNode $activetool] } setNodeCanvas $node $curcanvas setNodeCoords $node "[expr {$x / $zoom}] [expr {$y / $zoom}]" lassign [getDefaultLabelOffsets $activetool] dx dy setNodeLabelCoords $node "[expr {$x / $zoom + $dx}] \ [expr {$y / $zoom + $dy}]" drawNode $c $node selectNode $c [$c find withtag "node && $node"] set changed 1 # remove any existing select box } elseif { $activetool == "select" \ && $curtype != "node" && $curtype != "nodelabel"} { $c config -cursor cross set lastX $x set lastY $y if {$selectbox != ""} { # We actually shouldn't get here! $c delete $selectbox set selectbox "" } # begin drawing an annotation } elseif { $activetoolp == "bgobjs" } { set newcursor cross if { $activetool == "text" } { set newcursor xterm } $c config -cursor $newcursor set lastX $x set lastY $y # draw with the marker } elseif { $activetool == "marker" } { global markersize markercolor set newline [$c create oval $lastX $lastY $x $y \ -width $markersize -outline $markercolor -tags "marker"] $c raise $newline "background || link || linklabel || interface" set lastX $x set lastY $y } } else { if {$curtype == "node" || $curtype == "nodelabel"} { $c config -cursor fleur } if {$activetool == "link" && $curtype == "node"} { $c config -cursor cross set lastX [lindex [$c coords $curobj] 0] set lastY [lindex [$c coords $curobj] 1] set newlink [$c create line $lastX $lastY $x $y \ -fill $defLinkColor -width $defLinkWidth \ -tags "link"] # twonode tool support } elseif {$g_twoNodeSelect != "" && $curtype == "node"} { set curnode [lindex [$c gettags $curobj] 1] selectTwoNode $curnode } elseif { $curtype == "node" } { selectNode $c $curobj } # end Boeing } raiseAll $c } proc setResizeMode { c x y } { set isThruplot false set type1 notset if {$c == ".c"} { set t1 [$c gettags current] set o1 [lindex $t1 1] set type1 [nodeType $o1] } else { set o1 $c set c .c set isThruplot true } #DYL #puts "RESIZE NODETYPE = $type1" global resizemode resizeobj if {$type1== "oval" || $type1== "rectangle" || $isThruplot == true} { set resizeobj $o1 set bbox1 [$c bbox $o1] set x1 [lindex $bbox1 0] set y1 [lindex $bbox1 1] set x2 [lindex $bbox1 2] set y2 [lindex $bbox1 3] set l 0 ;# left set r 0 ;# right set u 0 ;# up set d 0 ;# down if { $x < [expr $x1+($x2-$x1)/8.0]} { set l 1 } if { $x > [expr $x2-($x2-$x1)/8.0]} { set r 1 } if { $y < [expr $y1+($y2-$y1)/8.0]} { set u 1 } if { $y > [expr $y2-($y2-$y1)/8.0]} { set d 1 } if {$l==1} { if {$u==1} { set resizemode lu } elseif {$d==1} { set resizemode ld } else { set resizemode l } } elseif {$r==1} { if {$u==1} { set resizemode ru } elseif {$d==1} { set resizemode rd } else { set resizemode r } } elseif {$u==1} { set resizemode u } elseif {$d==1} { set resizemode d } else { set resizemode false } } } #****f* editor.tcl/button1-motion # NAME # button1-motion # SYNOPSIS # button1-motion $c $x $y # FUNCTION # This procedure is called when a left mouse button is # pressed and the mouse is moved around the canvas. # This procedure creates new select box, moves the # selected nodes or draws a new link. # INPUTS # * c -- tk canvas # * x -- x coordinate # * y -- y coordinate #**** proc button1-motion { c x y } { global activetool newlink changed global lastX lastY sizex sizey selectbox background global oper_mode newoval newrect resizemode global zoom global g_view_locked global thruPlotCur thruPlotDragStart set x [$c canvasx $x] set y [$c canvasy $y] if {$thruPlotDragStart == "dragging"} { #puts "active tool is $activetool" thruPlotDrag $c $thruPlotCur $x $y null true return } # fix occasional error if { $x == "" || $y == "" || $lastX == "" || $lastY == "" } { return } set curobj [$c find withtag current] set curtype [lindex [$c gettags current] 0] # display coordinates in the status bar set zoomx [expr {$x / $zoom}] set zoomy [expr {$y / $zoom}] .bottom.textbox config -text "<$zoomx, $zoomy>" # prevent dragging outside of the canvas area if { $x < 0 } { set x 0 } elseif { $x > $sizex } { set x $sizex } if { $y < 0 } { set y 0 } elseif { $y > $sizey } { set y $sizey } # marker tool drawing on the canvas if { $activetool == "marker" } { global markersize markercolor set dx [expr {$x-$lastX} ] set dy [expr {$y-$lastY} ] # this provides smoother drawing if { $dx > $markersize || $dy > $markersize } { set mark [$c create line $lastX $lastY $x $y \ -width $markersize -fill $markercolor -tags "marker"] $c raise $mark \ "marker || background || link || linklabel || interface" } set mark [$c create oval $x $y $x $y \ -width $markersize -fill $markercolor \ -outline $markercolor -tags "marker"] $c raise $mark "marker || background || link || linklabel || interface" set lastX $x set lastY $y return } # disable all other mouse drags in locked mode if { $g_view_locked == 1 } { return } # don't move nodelabels in exec mode, use calcx,y instead of x,y if {$oper_mode == "exec" && $curtype == "nodelabel" } { set node [lindex [$c gettags $curobj] 1] set curobj [$c find withtag "node && $node"] set curtype "node" set coords [$c coords $curobj] set calcx [expr {[lindex $coords 0] / $zoom}] set calcy [expr {[lindex $coords 1] / $zoom}] selectNode $c $curobj } else { set calcx $x set calcy $y } # drawing a new link if {$activetool == "link" && $newlink != ""} { $c coords $newlink $lastX $lastY $x $y # draw a selection box } elseif { $activetool == "select" && \ ( $curobj == $selectbox || $curtype == "background" || $curtype == "grid")} { if {$selectbox == ""} { set selectbox [$c create line \ $lastX $lastY $x $lastY $x $y $lastX $y $lastX $lastY \ -dash {10 4} -fill black -width 1 -tags "selectbox"] $c raise $selectbox "background || link || linklabel || interface" } else { $c coords $selectbox \ $lastX $lastY $x $lastY $x $y $lastX $y $lastX $lastY } # move a text annotation } elseif { $activetool == "select" && $curtype == "text" } { $c move $curobj [expr {$x - $lastX}] [expr {$y - $lastY}] set changed 1 set lastX $x set lastY $y $c delete [$c find withtag "selectmark"] # move a nodelabel apart from a node (edit mode only) } elseif { $activetool == "select" && $curtype == "nodelabel" \ && [nodeType [lindex [$c gettags $curobj] 1]] != "pseudo" } { $c move $curobj [expr {$x - $lastX}] [expr {$y - $lastY}] set changed 1 set lastX $x set lastY $y # actually we should check if curobj==bkgImage # annotations } elseif { $activetool == "oval" && \ ( $curobj == $newoval || $curobj == $background || $curtype == "background" || $curtype == "grid")} { # Draw a new oval if {$newoval == ""} { set newoval [$c create oval $lastX $lastY $x $y \ -dash {10 4} -width 1 -tags "newoval"] $c raise $newoval "background || link || linklabel || interface" } else { $c coords $newoval \ $lastX $lastY $x $y } # actually we should check if curobj==bkgImage } elseif { $activetool == "rectangle" && \ ( $curobj == $newrect || $curobj == $background || $curtype == "background" || $curtype == "grid")} { # Draw a new rectangle if {$newrect == ""} { set newrect [$c create rectangle $lastX $lastY $x $y \ -outline blue \ -dash {10 4} -width 1 -tags "newrect"] $c raise $newrect "oval || background || link || linklabel || interface" } else { $c coords $newrect $lastX $lastY $x $y } # resizing an annotation } elseif { $curtype == "selectmark" } { foreach o [$c find withtag "selected"] { set node [lindex [$c gettags $o] 1] set tagovi [$c gettags $o] set koord [getNodeCoords $node] set oldX1 [lindex $koord 0] set oldY1 [lindex $koord 1] set oldX2 [lindex $koord 2] set oldY2 [lindex $koord 3] switch -exact -- $resizemode { lu { set oldX1 $x set oldY1 $y } ld { set oldX1 $x set oldY2 $y } l { set oldX1 $x } ru { set oldX2 $x set oldY1 $y } rd { set oldX2 $x set oldY2 $y } r { set oldX2 $x } u { set oldY1 $y } d { set oldY2 $y } } if {$selectbox == ""} { # Boeing: fix "bad screen distance" error if { $oldX1 == "" || $oldX2 == "" || $oldY1 == "" || \ $oldY2 == "" } { return } # end Boeing set selectbox [$c create line \ $oldX1 $oldY1 $oldX2 $oldY1 $oldX2 $oldY2 $oldX1 \ $oldY2 $oldX1 $oldY1 \ -dash {10 4} -fill black -width 1 -tags "selectbox"] $c raise $selectbox \ "background || link || linklabel || interface" } else { $c coords $selectbox \ $oldX1 $oldY1 $oldX2 $oldY1 $oldX2 $oldY2 $oldX1 \ $oldY2 $oldX1 $oldY1 } } # selected node(s) are being moved } else { foreach img [$c find withtag "selected"] { set node [lindex [$c gettags $img] 1] set newcoords [$c coords $img] ;# different than getNodeCoords set img [$c find withtag "selectmark && $node"] if {$curtype == "oval" || $curtype == "rectangle"} { $c move $img [expr {($x - $lastX) / 2}] \ [expr {($y - $lastY) / 2}] } else { $c move $img [expr {$x - $lastX}] [expr {$y - $lastY}] set img [$c find withtag "node && $node"] $c move $img [expr {$x - $lastX}] [expr {$y - $lastY}] set img [$c find withtag "nodelabel && $node"] $c move $img [expr {$x - $lastX}] [expr {$y - $lastY}] set img [$c find withtag "twonode && $node"] if {$img != "" } {; # move Two Node Tool circles around node $c move $img [expr {$x - $lastX}] [expr {$y - $lastY}] }; set img [$c find withtag "rangecircles && $node"] if {$img != "" } {; # move throughput circles around node $c move $img [expr {$x - $lastX}] [expr {$y - $lastY}] }; $c addtag need_redraw withtag "link && $node" } if { $oper_mode == "exec" } { set newx [expr {[lindex $newcoords 0] / $zoom}] set newy [expr {[lindex $newcoords 1] / $zoom}] sendNodePosMessage -1 $node -1 $newx $newy -1 0 } $c addtag need_redraw withtag "wlanlink && $node" widgets_move_node $c $node 0 } foreach link [$c find withtag "link && need_redraw"] { redrawLink [lindex [$c gettags $link] 1] } foreach wlanlink [$c find withtag "wlanlink && need_redraw"] { redrawWlanLink $wlanlink } $c dtag wlanlink need_redraw $c dtag link need_redraw set changed 1 set lastX $x set lastY $y } } #****f* editor.tcl/pseudo.layer # NAME # pseudo.layer # SYNOPSIS # set layer [pseudo.layer] # FUNCTION # Returns the layer on which the pseudo node operates # i.e. returns no layer. # RESULT # * layer -- returns an empty string #**** proc pseudo.layer {} { } #****f* editor.tcl/newGUILink # NAME # newGUILink -- new GUI link # SYNOPSIS # newGUILink $lnode1 $lnode2 # FUNCTION # This procedure is called to create a new link between # nodes lnode1 and lnode2. Nodes can be on the same canvas # or on different canvases. The result of this function # is directly visible in GUI. # INPUTS # * lnode1 -- node id of the first node # * lnode2 -- node id of the second node #**** proc newGUILink { lnode1 lnode2 } { global changed set link [newLink $lnode1 $lnode2] if { $link == "" } { return } if { [getNodeCanvas $lnode1] != [getNodeCanvas $lnode2] } { set new_nodes [splitLink $link pseudo] set orig_nodes [linkPeers $link] set new_node1 [lindex $new_nodes 0] set new_node2 [lindex $new_nodes 1] set orig_node1 [lindex $orig_nodes 0] set orig_node2 [lindex $orig_nodes 1] set new_link1 [linkByPeers $orig_node1 $new_node1] set new_link2 [linkByPeers $orig_node2 $new_node2] setNodeMirror $new_node1 $new_node2 setNodeMirror $new_node2 $new_node1 setNodeName $new_node1 $orig_node2 setNodeName $new_node2 $orig_node1 setLinkMirror $new_link1 $new_link2 setLinkMirror $new_link2 $new_link1 } redrawAll set changed 1 updateUndoLog } #****f* editor.tcl/button1-release # NAME # button1-release # SYNOPSIS # button1-release $c $x $y # FUNCTION # This procedure is called when a left mouse button is # released. # The result of this function depends on the actions # during the button1-motion procedure. # INPUTS # * c -- tk canvas # * x -- x coordinate # * y -- y coordinate #**** proc button1-release { c x y } { global node_list plot_list activetool newlink curobj grid global changed undolog undolevel redolevel selectbox global lastX lastY sizex sizey zoom global autorearrange_enabled global resizemode resizeobj set redrawNeeded 0 global oper_mode global g_prefs global g_view_locked set x [$c canvasx $x] set y [$c canvasy $y] $c config -cursor left_ptr # place a new link between items if {$activetool == "link" && $newlink != ""} { if { $g_view_locked == 1 } { return } $c delete $newlink set newlink "" set destobj "" foreach obj [$c find overlapping $x $y $x $y] { if {[lindex [$c gettags $obj] 0] == "node"} { set destobj $obj break } } if {$destobj != "" && $curobj != "" && $destobj != $curobj} { set lnode1 [lindex [$c gettags $curobj] 1] set lnode2 [lindex [$c gettags $destobj] 1] if { [ifcByLogicalPeer $lnode1 $lnode2] == "" } { set link [newLink $lnode1 $lnode2] if { $link != "" } { drawLink $link redrawLink $link updateLinkLabel $link set changed 1 } } } # annotations } elseif {$activetool == "rectangle" || $activetool == "oval" } { if { $g_view_locked == 1 } { return } popupAnnotationDialog $c 0 "false" # edit text annotation } elseif {$activetool == "text" } { if { $g_view_locked == 1 } { return } textEnter $c $x $y } if { $changed == 1 } { set regular true if { [lindex [$c gettags $curobj] 0] == "nodelabel" } { set node [lindex [$c gettags $curobj] 1] selectNode $c [$c find withtag "node && $node"] } set selected {} foreach img [$c find withtag "selected"] { set node [lindex [$c gettags $img] 1] lappend selected $node set coords [$c coords $img] set x [expr {[lindex $coords 0] / $zoom}] set y [expr {[lindex $coords 1] / $zoom}] if { $autorearrange_enabled == 0 && $g_prefs(gui_snap_grid)} { set dx [expr {(int($x / $grid + 0.5) * $grid - $x) * $zoom}] set dy [expr {(int($y / $grid + 0.5) * $grid - $y) * $zoom}] $c move $img $dx $dy set coords [$c coords $img] set x [expr {[lindex $coords 0] / $zoom}] set y [expr {[lindex $coords 1] / $zoom}] } else { set dx 0 set dy 0 } if {$x < 0 || $y < 0 || $x > $sizex || $y > $sizey} { set regular false } # nodes with four coordinates if { [lindex [$c gettags $node] 0] == "oval" || [lindex [$c gettags $node] 0] == "rectangle" } { set bbox [$c bbox "selectmark && $node"] # Boeing: bbox causes annotations to grow, subtract 5 if { [llength $bbox] > 3 } { set x1 [lindex $bbox 0] set y1 [lindex $bbox 1] set x2 [expr {[lindex $bbox 2] - 5}] set y2 [expr {[lindex $bbox 3] - 5}] setNodeCoords $node "$x1 $y1 $x2 $y2" set redrawNeeded 1 if {$x1 < 0 || $y1 < 0 || $x1 > $sizex || $y1 > $sizey || \ $x2 < 0 || $y2 < 0 || $x2 > $sizex || $y2 > $sizey} { set regular false } } # nodes with two coordinates } else { setNodeCoords $node "$x $y" } if {[$c find withtag "nodelabel && $node"] != "" } { $c move "nodelabel && $node" $dx $dy set coords [$c coords "nodelabel && $node"] set x [expr {[lindex $coords 0] / $zoom}] set y [expr {[lindex $coords 1] / $zoom}] setNodeLabelCoords $node "$x $y" if {$x < 0 || $y < 0 || $x > $sizex || $y > $sizey} { set regular false } } $c move "selectmark && $node" $dx $dy $c addtag need_redraw withtag "link && $node" set changed 1 if { $oper_mode == "exec" } { # send node position update using x,y stored in node set xy [getNodeCoords $node] ;# read new coordinates sendNodePosMessage -1 $node -1 [lindex $xy 0] [lindex $xy 1] \ -1 0 widgets_move_node $c $node 1 } $c addtag need_redraw withtag "wlanlink && $node" } ;# end of: foreach img selected if {$regular == "true"} { # user has dragged something within the canvas boundaries foreach link [$c find withtag "link && need_redraw"] { redrawLink [lindex [$c gettags $link] 1] } } else { # user has dragged something beyond the canvas boundaries .c config -cursor watch loadCfg $undolog($undolevel) redrawAll if {$activetool == "select" } { selectNodes $selected } set changed 0 } $c dtag link need_redraw nodeEnter $c # $changed!=1 } elseif {$activetool == "select" } { if {$selectbox == ""} { set x1 $x set y1 $y rearrange_off } else { set coords [$c coords $selectbox] set x [lindex $coords 0] set y [lindex $coords 1] set x1 [lindex $coords 4] set y1 [lindex $coords 5] $c delete $selectbox set selectbox "" } if { $resizemode == "false" } { # select tool mouse button release while drawing select box set enclosed {} # fix occasional error if { $x == "" || $y == "" || $x1 == "" || $y1 == "" } { return } foreach obj [$c find enclosed $x $y $x1 $y1] { set tags [$c gettags $obj] if {[lindex $tags 0] == "node" && [lsearch $tags selected] == -1} { lappend enclosed $obj } if {[lindex $tags 0] == "oval" && [lsearch $tags selected] == -1} { lappend enclosed $obj } if {[lindex $tags 0] == "rectangle" && [lsearch $tags selected] == -1} { lappend enclosed $obj } if {[lindex $tags 0] == "text" && [lsearch $tags selected] == -1} { lappend enclosed $obj } } foreach obj $enclosed { selectNode $c $obj } } else { # select tool resizing an object by dragging its handles # DYL bugfix. if x,y does not change, do not resize! # fixes a bug where the object dissappears if { $x != $x1 || $y != $y1 } { setNodeCoords $resizeobj "$x $y $x1 $y1" } set redrawNeeded 1 set resizemode false } } if { $redrawNeeded } { set redrawNeeded 0 redrawAll } else { raiseAll $c } update updateUndoLog } #****f* editor.tcl/nodeEnter # NAME # nodeEnter # SYNOPSIS # nodeEnter $c # FUNCTION # This procedure prints the node id, node name and # node model (if exists), as well as all the interfaces # of the node in the status line. # Information is presented for the node above which is # the mouse pointer. # INPUTS # * c -- tk canvas #**** proc nodeEnter { c } { global activetool set curtags [$c gettags current] if { [lsearch -exact "node nodelabel" [lindex $curtags 0]] < 0 } { return ;# allow this proc to be called from button1-release } set node [lindex $curtags 1] set type [nodeType $node] set name [getNodeName $node] set model [getNodeModel $node] if { $model != "" } { set line "{$node} $name ($model):" } else { set line "{$node} $name:" } if { $type != "rj45" && $type != "tunnel" } { foreach ifc [ifcList $node] { set line "$line $ifc:[getIfcIPv4addr $node $ifc]" } } set xy [getNodeCoords $node] set line "$line <[lindex $xy 0], [lindex $xy 1]>" .bottom.textbox config -text "$line" widgetObserveNode $c $node } #****f* editor.tcl/linkEnter # NAME # linkEnter # SYNOPSIS # linkEnter $c # FUNCTION # This procedure prints the link id, link bandwidth # and link delay in the status line. # Information is presented for the link above which is # the mouse pointer. # INPUTS # * c -- tk canvas #**** proc linkEnter {c} { global activetool link_list set link [lindex [$c gettags current] 1] if { [lsearch $link_list $link] == -1 } { return } set line "$link: [getLinkBandwidthString $link] [getLinkDelayString $link]" .bottom.textbox config -text "$line" } #****f* editor.tcl/anyLeave # NAME # anyLeave # SYNOPSIS # anyLeave $c # FUNCTION # This procedure clears the status line. # INPUTS # * c -- tk canvas #**** proc anyLeave {c} { global activetool .bottom.textbox config -text "" # Boeing widgetObserveNode $c "" # nodeHighlights $c "" off "" # end Boeing } #****f* editor.tcl/checkIntRange # NAME # checkIntRange -- check integer range # SYNOPSIS # set check [checkIntRange $str $low $high] # FUNCTION # This procedure checks the input string to see if it is # an integer between the low and high value. # INPUTS # str -- string to check # low -- the bottom value # high -- the top value # RESULT # * check -- set to 1 if the str is string between low and high # value, 0 otherwise. #**** proc checkIntRange { str low high } { if { $str == "" } { return 1 } set str [string trimleft $str 0] if { $str == "" } { set str 0 } if { ![string is integer $str] } { return 0 } if { $str < $low || $str > $high } { return 0 } return 1 } proc checkFloatRange { str low high } { if { $str == "" } { return 1 } set str [string trimleft $str 0] if { $str == "" } { set str 0 } if { ![string is double $str] } { return 0 } if { $str < $low || $str > $high } { return 0 } return 1 } proc checkHostname { str } { # per RFC 952 and RFC 1123, any letter, number, or hyphen return [regexp {^[A-Za-z0-9-]+$} $str] } #****f* editor.tcl/focusAndFlash # NAME # focusAndFlash -- focus and flash # SYNOPSIS # focusAndFlash $W $count # FUNCTION # This procedure sets the focus on the bad entry field # and on this filed it provides an effect of flashing # for approximately 1 second. # INPUTS # * W -- textbox field that caused the bed entry # * count -- the parameter that causes flashes. # It can be left blank. #**** proc focusAndFlash {W {count 9}} { global badentry set fg black set bg white if { $badentry == -1 } { return } else { set badentry 1 } focus -force $W if {$count<1} { $W configure -foreground $fg -background $bg set badentry 0 } else { if {$count%2} { $W configure -foreground $bg -background $fg } else { $W configure -foreground $fg -background $bg } after 200 [list focusAndFlash $W [expr {$count - 1}]] } } #****f* editor.tcl/popupConfigDialog # NAME # popupConfigDialog -- popup Configuration Dialog Box # SYNOPSIS # popupConfigDialog $c # FUNCTION # Dynamically creates a popup dialog box for configuring # links or nodes in IMUNES. # INPUTS # * c -- canvas id #**** proc popupConfigDialog { c } { global activetool router_model link_color oper_mode global badentry curcanvas global node_location systype global plugin_img_del set type "" set wi .popup if { [winfo exists $wi ] } { return } catch {destroy $wi} toplevel $wi wm transient $wi . wm resizable $wi 1 1 set object_type "" set tk_type [lindex [$c gettags current] 0] set target [lindex [$c gettags current] 1] if { [lsearch {node nodelabel interface} $tk_type] > -1 } { set object_type node } if { [lsearch {link linklabel} $tk_type] > -1 } { set object_type link } if { [lsearch {oval} $tk_type] > -1 } { set object_type oval } if { [lsearch {rectangle} $tk_type] > -1 } { set object_type rectangle } if { [lsearch {text} $tk_type] > -1 } { set object_type text } if { "$object_type" == ""} { destroy $wi return } if { $object_type == "link" } { set n0 [lindex [linkPeers $target] 0] set n1 [lindex [linkPeers $target] 1] # Boeing: added tunnel check #if { [nodeType $n0] == "rj45" || [nodeType $n1] == "rj45" || \ # [nodeType $n0] == "tunnel" || [nodeType $n1] == "tunnel" } { # destroy $wi # return #} } $c dtag node selected $c delete -withtags selectmark switch -exact -- $object_type { node { set type [nodeType $target] if { $type == "pseudo" } { # # Hyperlink to another canvas # destroy $wi set curcanvas [getNodeCanvas [getNodeMirror $target]] switchCanvas none return } set model [getNodeModel $target] set router_model $model wm title $wi "$type configuration" ttk::frame $wi.ftop -borderwidth 4 ttk::entry $wi.ftop.name -width 16 \ -validate focus -invalidcommand "focusAndFlash %W" if { $type == "rj45" } { ttk::label $wi.ftop.name_label -text "Physical interface:" } elseif { $type == "tunnel" } { ttk::label $wi.ftop.name_label -text "IP address of tunnel peer:" } else { ttk::label $wi.ftop.name_label -text "Node name:" $wi.ftop.name configure -validatecommand {checkHostname %P} } $wi.ftop.name insert 0 [getNodeName $target] set img [getNodeImage $target] ttk::button $wi.ftop.img -image $img -command "popupCustomImage $target" if { $type == "rj45" } { rj45ifclist $wi $target 0 } # execution server global exec_servers node_location set node_location [getNodeLocation $target] set servers [lsort -dictionary [array names exec_servers]] set servers "(none) $servers" if { $node_location == "" } { set node_location "(none)" } eval tk_optionMenu $wi.ftop.menu node_location $servers pack $wi.ftop.img $wi.ftop.menu $wi.ftop.name $wi.ftop.name_label \ -side right -padx 4 -pady 4 # end Boeing pack $wi.ftop -side top if { $type == "router" } { ttk::frame $wi.model -borderwidth 4 ttk::label $wi.model.label -text "Type:" set runstate "disabled" if { $oper_mode == "edit" } { eval tk_optionMenu $wi.model.menu router_model \ [getNodeTypeNames] set runstate "normal" } else { tk_optionMenu $wi.model.menu router_model $model } # would be nice to update the image upon selection; binding to # will not work #tkwait variable router_model "customImageApply $wi $target" set sock [lindex [getEmulPlugin $target] 2] ttk::button $wi.model.services -text "Services..." -state $runstate \ -command \ "sendConfRequestMessage $sock $target services 0x1 -1 \"\"" pack $wi.model.services $wi.model.menu $wi.model.label \ -side right -padx 0 -pady 0 pack $wi.model -side top } if { $type == "wlan" } { wlanConfigDialogHelper $wi $target 0 } elseif { $type == "tunnel" } { # # tunnel controls # ttk::frame $wi.con2 global conntap set conntap [netconfFetchSection $target "tunnel-tap"] if { $conntap == "" } { set conntap off } # TODO: clean this up ttk::radiobutton $wi.con2.dotap0 \ -variable conntap -value off \ -text "tunnel to another CORE emulation" ttk::frame $wi.con2.key ttk::label $wi.con2.key.lab -text "GRE key:" ttk::entry $wi.con2.key.key -width 6 ttk::radiobutton $wi.con2.dotap1 -state disabled \ -variable conntap -value on \ -text "tunnel to the virtual TAP interface of another system" pack $wi.con2.key.lab $wi.con2.key.key -side left pack $wi.con2.dotap0 -side top -anchor w pack $wi.con2.key -side top pack $wi.con2.dotap1 -side top -anchor w pack $wi.con2 -side top set key [netconfFetchSection $target "tunnel-key"] if { $key == "" } { set key 1 } $wi.con2.key.key insert 0 $key # TODO: clean this up ttk::frame $wi.conn ttk::label $wi.conn.label -text "Transport type:" tk_optionMenu $wi.conn.conntype conntype "UDP" "TCP" $wi.conn.conntype configure -state disabled pack $wi.conn.label $wi.conn.conntype -side left -anchor w pack $wi.conn -side top global conntype set conntype [netconfFetchSection $target "tunnel-type"] if { $conntype == "" } { set conntype "UDP" } # TODO: clean this up ttk::frame $wi.linfo ttk::label $wi.linfo.label -text "Local hook:" ttk::entry $wi.linfo.local -state disabled set localhook [netconfFetchSection $target "local-hook"] if { $localhook == "" || $localhook == "(none)" } { # automatically generate local hook name set ifc [lindex [ifcList $target] 0] if { $ifc != "" } { set hname [info hostname] set peer [peerByIfc $target $ifc] set localhook "$hname$peer" } else { set localhook "(none)" } } $wi.linfo.local insert 0 $localhook pack $wi.linfo.label $wi.linfo.local -side left -anchor w pack $wi.linfo -side top ttk::frame $wi.pinfo ttk::label $wi.pinfo.label -text "Peer hook:" ttk::entry $wi.pinfo.peer -state disabled $wi.pinfo.peer insert 0 \ [netconfFetchSection $target "peer-hook"] pack $wi.pinfo.label $wi.pinfo.peer -side left -anchor w pack $wi.pinfo -side top } # interface list if { [[typemodel $target].layer] == "NETWORK" } { # canvas used for scrolling frames for each interface ttk::frame $wi.ifaces set height [expr {100 * [llength [ifcList $target]]}] if { $height > 300 } { set height 300 } canvas $wi.ifaces.c -height $height -highlightthickness 0 \ -yscrollcommand "$wi.ifaces.scroll set" scrollbar $wi.ifaces.scroll -command "$wi.ifaces.c yview" pack $wi.ifaces.c -side left -fill both -expand 1 pack $wi.ifaces.scroll -side right -fill y pack $wi.ifaces -side top -fill both -expand 1 set y 0 foreach ifc [lsort -ascii [ifcList $target]] { set fr $wi.ifaces.c.if$ifc ttk::labelframe $fr -text "Interface $ifc" $wi.ifaces.c create window 4 $y -window $fr -anchor nw incr y 100 set peer [peerByIfc $target $ifc] if { [isEmane $peer] } { ttk::frame $fr.opts set caps [getCapabilities $peer "mobmodel"] set cap [lindex $caps 0] set cmd "sendConfRequestMessage -1 $target $cap 0x1 -1 \"\"" ttk::button $fr.opts.cfg -command $cmd \ -text "$cap options..." pack $fr.opts.cfg -side left -padx 4 pack $fr.opts -side top -anchor w incr y 28 } ttk::frame $fr.cfg # # MAC address # ttk::frame $fr.cfg.mac ttk::label $fr.cfg.mac.addrl -text "MAC address" \ -anchor w set macaddr [getIfcMacaddr $target $ifc] global if${ifc}_auto_mac if { $macaddr == "" } { set if${ifc}_auto_mac 1 set state disabled } else { set if${ifc}_auto_mac 0 set state normal } ttk::checkbutton $fr.cfg.mac.auto -text "auto-assign" \ -variable if${ifc}_auto_mac \ -command "macEntryHelper $wi $ifc" ttk::entry $fr.cfg.mac.addrv -width 15 \ -state $state $fr.cfg.mac.addrv insert 0 $macaddr pack $fr.cfg.mac.addrl $fr.cfg.mac.auto \ $fr.cfg.mac.addrv -side left -padx 4 pack $fr.cfg.mac -side top -anchor w # # IPv4 address # ttk::frame $fr.cfg.ipv4 ttk::label $fr.cfg.ipv4.addrl -text "IPv4 address" \ -anchor w ttk::entry $fr.cfg.ipv4.addrv -width 30 \ -validate focus -invalidcommand "focusAndFlash %W" $fr.cfg.ipv4.addrv insert 0 \ [getIfcIPv4addr $target $ifc] $fr.cfg.ipv4.addrv configure \ -validatecommand {checkIPv4Net %P} ttk::button $fr.cfg.ipv4.clear -image $plugin_img_del \ -command "$fr.cfg.ipv4.addrv delete 0 end" pack $fr.cfg.ipv4.addrl $fr.cfg.ipv4.addrv \ $fr.cfg.ipv4.clear -side left pack $fr.cfg.ipv4 -side top -anchor w -padx 4 # # IPv6 address # ttk::frame $fr.cfg.ipv6 ttk::label $fr.cfg.ipv6.addrl -text "IPv6 address" \ -anchor w ttk::entry $fr.cfg.ipv6.addrv -width 30 \ -validate focus -invalidcommand "focusAndFlash %W" $fr.cfg.ipv6.addrv insert 0 \ [getIfcIPv6addr $target $ifc] $fr.cfg.ipv6.addrv configure -validatecommand {checkIPv6Net %P} ttk::button $fr.cfg.ipv6.clear -image $plugin_img_del \ -command "$fr.cfg.ipv6.addrv delete 0 end" pack $fr.cfg.ipv6.addrl $fr.cfg.ipv6.addrv \ $fr.cfg.ipv6.clear -side left pack $fr.cfg.ipv6 -side top -anchor w -padx 4 pack $fr.cfg -side left bind $fr.cfg <4> "$wi.ifaces.c yview scroll -1 units" bind $fr.cfg <5> "$wi.ifaces.c yview scroll 1 units" } ;# end foreach ifc $wi.ifaces.c configure -scrollregion "0 0 250 $y" # mouse wheel bindings for scrolling foreach ctl [list $wi.ifaces.c $wi.ifaces.scroll] { bind $ctl <4> "$wi.ifaces.c yview scroll -1 units" bind $ctl <5> "$wi.ifaces.c yview scroll 1 units" bind $ctl "$wi.ifaces.c yview scroll -1 units" bind $ctl "$wi.ifaces.c yview scroll 1 units" } } } oval { destroy $wi annotationConfig $c $target return } rectangle { destroy $wi annotationConfig $c $target return } text { destroy $wi annotationConfig $c $target return } link { wm title $wi "link configuration" ttk::frame $wi.ftop -borderwidth 6 set nam0 [getNodeName $n0] set nam1 [getNodeName $n1] ttk::label $wi.ftop.name_label -justify left -text \ "Link from $nam0 to $nam1" pack $wi.ftop.name_label -side right pack $wi.ftop -side top set spinbox [getspinbox] global g_link_config_uni_state set g_link_config_uni_state "bid" ttk::frame $wi.preset -borderwidth 4 global link_preset_val set link_preset_val unlimited set linkpreMenu [tk_optionMenu $wi.preset.linkpre link_preset_val a] # unidirectional links not always supported if { [isUniSupported $n0 $n1] } { set unistate normal } else { set unistate disabled } ttk::button $wi.preset.uni -text " >> " -state $unistate \ -command "linkConfigUni $wi" pack $wi.preset.uni $wi.preset.linkpre -side right linkPresets $wi $linkpreMenu init pack $wi.preset -side top -anchor e ttk::frame $wi.unilabel -borderwidth 4 ttk::label $wi.unilabel.updown -text "Symmetric link effects:" pack $wi.unilabel.updown -side left -anchor w pack $wi.unilabel -side top -anchor w ttk::frame $wi.bandwidth -borderwidth 4 ttk::label $wi.bandwidth.label -anchor e -text "Bandwidth (bps):" $spinbox $wi.bandwidth.value -justify right -width 10 \ -validate focus -invalidcommand "focusAndFlash %W" $wi.bandwidth.value insert 0 [getLinkBandwidth $target] $wi.bandwidth.value configure \ -validatecommand {checkIntRange %P 0 1000000000} \ -from 0 -to 1000000000 -increment 1000000 pack $wi.bandwidth.value $wi.bandwidth.label -side right pack $wi.bandwidth -side top -anchor e ttk::frame $wi.delay -borderwidth 4 ttk::label $wi.delay.label -anchor e -text "Delay (us):" $spinbox $wi.delay.value -justify right -width 10 \ -validate focus -invalidcommand "focusAndFlash %W" $wi.delay.value insert 0 [getLinkDelay $target] # 274 seconds is maximum netem delay for Linux 3.2.0-60-generic kernel $wi.delay.value configure \ -validatecommand {checkIntRange %P 0 274000000} \ -from 0 -to 10000000 -increment 5 pack $wi.delay.value $wi.delay.label -side right pack $wi.delay -side top -anchor e ttk::frame $wi.jitter -borderwidth 4 ttk::label $wi.jitter.label -anchor e -text "Jitter (us):" $spinbox $wi.jitter.value -justify right -width 10 \ -validate focus -invalidcommand "focusAndFlash %W" $wi.jitter.value insert 0 [getLinkJitter $target] $wi.jitter.value configure \ -validatecommand {checkIntRange %P 0 10000000} \ -from 0 -to 10000000 -increment 5 pack $wi.jitter.value $wi.jitter.label -side right pack $wi.jitter -side top -anchor e ttk::frame $wi.ber -borderwidth 4 if { [lindex $systype 0] == "Linux" } { set bertext "Loss (%):" set berinc 0.1 set bermax 100.0 } else { ;# netgraph uses BER set bertext "BER (1/N):" set berinc 1000 set bermax 10000000000000 } ttk::label $wi.ber.label -anchor e -text $bertext $spinbox $wi.ber.value -justify right -width 10 \ -validate focus -invalidcommand "focusAndFlash %W" $wi.ber.value insert 0 [getLinkBER $target] $wi.ber.value configure \ -validatecommand "checkFloatRange %P 0.0 $bermax" \ -from 0.0 -to $bermax -increment $berinc pack $wi.ber.value $wi.ber.label -side right pack $wi.ber -side top -anchor e ttk::frame $wi.dup -borderwidth 4 ttk::label $wi.dup.label -anchor e -text "Duplicate (%):" $spinbox $wi.dup.value -justify right -width 10 \ -validate focus -invalidcommand "focusAndFlash %W" $wi.dup.value insert 0 [getLinkDup $target] $wi.dup.value configure \ -validatecommand {checkFloatRange %P 0 50} \ -from 0 -to 50 -increment 1 pack $wi.dup.value $wi.dup.label -side right pack $wi.dup -side top -anchor e # Boeing: jitter # frame $wi.jitter -borderwidth 4 # label $wi.jitter.label -anchor e -text "Jitter (us):" # spinbox $wi.jitter.value -bg white -justify right -width 10 \ # -validate focus -invalidcommand "focusAndFlash %W" # $wi.jitter.value insert 0 [getLinkJitter $target] # $wi.jitter.value configure \ # -validatecommand {checkIntRange %P 0 10000000} \ # -from 0 -to 10000000 -increment 5 # pack $wi.jitter.value $wi.jitter.label -side right # pack $wi.jitter -side top -anchor e # end Boeing ttk::frame $wi.color -borderwidth 4 ttk::label $wi.color.label -anchor e -text "Color:" set link_color [getLinkColor $target] tk_optionMenu $wi.color.value link_color \ Red Green Blue Yellow Magenta Cyan Black $wi.color.value configure -width 8 pack $wi.color.value $wi.color.label -side right pack $wi.color -side top -anchor e ttk::frame $wi.width -borderwidth 4 ttk::label $wi.width.label -anchor e -text "Width:" $spinbox $wi.width.value -justify right -width 10 \ -validate focus -invalidcommand "focusAndFlash %W" $wi.width.value insert 0 [getLinkWidth $target] $wi.width.value configure \ -validatecommand {checkIntRange %P 1 8} \ -from 1 -to 8 -increment 1 pack $wi.width.value $wi.width.label -side right pack $wi.width -side top -anchor e # auto-expand upstream if values exist set bw [getLinkBandwidth $target up] set dl [getLinkDelay $target up] set jt [getLinkJitter $target up] set ber [getLinkBER $target up] set dup [getLinkDup $target up] if { $bw > 0 || $dl > 0 || $jt > 0 || $ber > 0 || $dup > 0 } { linkConfigUni $wi $wi.bandwidth.value2 delete 0 end $wi.bandwidth.value2 insert 0 $bw $wi.delay.value2 delete 0 end $wi.delay.value2 insert 0 $dl $wi.jitter.value2 delete 0 end $wi.jitter.value2 insert 0 $jt $wi.ber.value2 delete 0 end $wi.ber.value2 insert 0 $ber $wi.dup.value2 delete 0 end $wi.dup.value2 insert 0 $dup } } } ;# end switch ttk::frame $wi.butt -borderwidth 6 # NOTE: plugins.tcl:popupCapabilityConfig may read this command option ttk::button $wi.butt.apply -text "Apply" -command \ "popupConfigApply $wi $object_type $target 0" focus $wi.butt.apply # Boeing: remove range circles upon cancel if {$type == "wlan"} { set cancelcmd "set badentry -1 ; destroy $wi;" set cancelcmd "$cancelcmd updateRangeCircles $target 0" } else { set cancelcmd "set badentry -1 ; destroy $wi" } ttk::button $wi.butt.cancel -text "Cancel" -command $cancelcmd #end Boeing pack $wi.butt.cancel $wi.butt.apply -side right pack $wi.butt -side bottom bind $wi $cancelcmd # bind $wi "popupConfigApply $wi $object_type $target 0" } proc linkConfigUni { wi } { global g_link_config_uni_state set capt [lindex [$wi.preset.uni configure -text] 4] if { $capt == " >> " } { set g_link_config_uni_state "uni" $wi.preset.uni configure -text " << " set txt "Asymmetric effects: downstream / upstream" $wi.unilabel.updown configure -text $txt set spinbox [getspinbox] if { ![winfo exists $wi.bandwidth.value2] } { $spinbox $wi.bandwidth.value2 -justify right \ -width 10 -validate focus -invalidcommand "focusAndFlash %W" $wi.bandwidth.value2 configure \ -validatecommand {checkIntRange %P 0 1000000000} \ -from 0 -to 1000000000 -increment 1000000 } $wi.bandwidth.value2 delete 0 end $wi.bandwidth.value2 insert 0 [$wi.bandwidth.value get] pack $wi.bandwidth.value2 -side right pack $wi.bandwidth.value2 -before $wi.bandwidth.value if { ![winfo exists $wi.delay.value2] } { $spinbox $wi.delay.value2 -justify right -width 10 \ -validate focus -invalidcommand "focusAndFlash %W" $wi.delay.value2 configure \ -validatecommand {checkIntRange %P 0 10000000} \ -from 0 -to 10000000 -increment 5 } $wi.delay.value2 delete 0 end $wi.delay.value2 insert 0 [$wi.delay.value get] pack $wi.delay.value2 -side right pack $wi.delay.value2 -before $wi.delay.value if { ![winfo exists $wi.jitter.value2] } { $spinbox $wi.jitter.value2 -justify right -width 10 \ -validate focus -invalidcommand "focusAndFlash %W" $wi.jitter.value2 configure \ -validatecommand {checkIntRange %P 0 10000000} \ -from 0 -to 10000000 -increment 5 } $wi.jitter.value2 delete 0 end $wi.jitter.value2 insert 0 [$wi.jitter.value get] pack $wi.jitter.value2 -side right pack $wi.jitter.value2 -before $wi.jitter.value if { ![winfo exists $wi.ber.value2] } { $spinbox $wi.ber.value2 -justify right -width 10 \ -validate focus -invalidcommand "focusAndFlash %W" $wi.ber.value2 configure \ -validatecommand "checkFloatRange %P 0.0 100.0" \ -from 0.0 -to 100.0 -increment 0.1 } $wi.ber.value2 delete 0 end $wi.ber.value2 insert 0 [$wi.ber.value get] pack $wi.ber.value2 -side right pack $wi.ber.value2 -before $wi.ber.value if { ![winfo exists $wi.dup.value2] } { $spinbox $wi.dup.value2 -justify right -width 10 \ -validate focus -invalidcommand "focusAndFlash %W" $wi.dup.value2 configure \ -validatecommand {checkFloatRange %P 0 50} \ -from 0 -to 50 -increment 1 } $wi.dup.value2 delete 0 end $wi.dup.value2 insert 0 [$wi.dup.value get] pack $wi.dup.value2 -side right pack $wi.dup.value2 -before $wi.dup.value } else { set g_link_config_uni_state "bid" $wi.preset.uni configure -text " >> " $wi.unilabel.updown configure -text "Symmetric link effects:" pack forget $wi.bandwidth.value2 pack forget $wi.delay.value2 pack forget $wi.jitter.value2 pack forget $wi.ber.value2 pack forget $wi.dup.value2 } } # unidirectional links are not always supported proc isUniSupported { n1 n2 } { set blacklist [list "hub" "lanswitch"] set type1 [nodeType $n1] set type2 [nodeType $n2] # not yet supported for GRE tap device if { $type1 == "tunnel" || $type2 == "tunnel" } { return false } # unidirectional links are supported between two switches/hubs if { [lsearch $blacklist $type1] != -1 && \ [lsearch $blacklist $type2] != -1 } { return true } # unidirectional links not supported between hub/switch and something else if { [lsearch $blacklist $type1] != -1 || \ [lsearch $blacklist $type2] != -1 } { return false } # unidirectional links are supported between routers, rj45s, etc. # WLANs not included here because they have no link dialog return true } # toggle the state of the mac address entry, and insert MAC address template proc macEntryHelper { wi ifc } { set fr $wi.ifaces.c.if$ifc set ctl $fr.cfg.mac.addrv set s normal if { [$ctl cget -state] == $s } { set s disabled } $ctl configure -state $s if { [$ctl get] == "" } { $ctl insert 0 "00:00:00:00:00:00" } } #****f* editor.tcl/popupConfigApply # NAME # popupConfigApply -- popup configuration apply # SYNOPSIS # popupConfigApply $w $object_type $target $phase # FUNCTION # This procedure is called when the button apply is pressed in # popup configuration dialog box. It reads different # configuration parameters depending on the object_type. # INPUTS # * w -- widget # * object_type -- describes the object type that is currently # configured. It can be either link or node. # * target -- node id of the configured node or link id of the # configured link # * phase -- This procedure is invoked in two diffenet phases # to enable validation of the entry that was the last made. # When calling this function always use the phase parameter # set to 0. #**** proc popupConfigApply { wi object_type target phase } { global changed oper_mode router_model link_color badentry global customEnabled ipsecEnabled global eid $wi config -cursor watch update if { $phase == 0 } { set badentry 0 focus . after 100 "popupConfigApply $wi $object_type $target 1" return } elseif { $badentry } { $wi config -cursor left_ptr return } switch -exact -- $object_type { # # Node # node { set type [nodeType $target] set model [getNodeModel $target] set name [string trim [$wi.ftop.name get]] set changed_to_remote 0 global node_location if { $node_location != [getNodeLocation $target] } { if { $node_location == "(none)" } { set node_location "" } setNodeLocation $target $node_location set changed 1 } set node_location "" if { $name != [getNodeName $target] } { setNodeName $target $name set changed 1 } if { $oper_mode == "edit" && $type == "router" && \ $router_model != $model } { setNodeModel $target $router_model set changed 1 if { $router_model == "remote" } { set changed_to_remote 1 };#Boeing } # Boeing - added wlan, remote, tunnel, ktunnel items if { $type == "wlan" } { wlanConfigDialogHelper $wi $target 1 } elseif { $type == "tunnel" } { # # apply tunnel items # set ipaddr "$name/24" ;# tunnel name == IP address of peer set oldipaddr [getIfcIPv4addr $target e0] if { $ipaddr != $oldipaddr } { setIfcIPv4addr $target e0 $ipaddr } global conntype conntap set oldconntype [netconfFetchSection $target "tunnel-type"] if { $oldconntype != $conntype } { netconfInsertSection $target [list "tunnel-type" $conntype] } set oldconntap [netconfFetchSection $target "tunnel-tap"] if { $oldconntap != $conntap } { netconfInsertSection $target [list "tunnel-tap" $conntap] } set oldkey [netconfFetchSection $target "tunnel-key"] set key [$wi.con2.key.key get] if { $oldkey != $key } { netconfInsertSection $target [list "tunnel-key" $key] } set oldlocal [netconfFetchSection $target "local-hook"] set local [$wi.linfo.local get] if { $oldlocal != $local } { netconfInsertSection $target [list "local-hook" $local] } set oldpeer [netconfFetchSection $target "peer-hook"] set peer [$wi.pinfo.peer get] if { $oldpeer != $peer } { netconfInsertSection $target [list "peer-hook" $peer] } } elseif { $type == "ktunnel" } { # # apply ktunnel items # set oldlocal [netconfFetchSection $target "local-hook"] set local [$wi.linfo.local get] if { $oldlocal != $local } { netconfInsertSection $target [list "local-hook" $local] } # Boeing changing to interface name for RJ45 # } elseif { $type == "rj45" } { # # # # apply rj45 items # # # set ifcName [string trim [$wi.interface.name get]] # puts "$ifcName\n" # } elseif { $type == "router" && [getNodeModel $target] == "remote" } { if { $changed_to_remote == 0 } { set i 1 set remoteIP [string trim [$wi.remoteinfo.ip.text get $i.0 $i.end]] if { $remoteIP != [router.remote.getRemoteIP $target] } { router.remote.setRemoteIP $target $remoteIP set changed 1 } set ifc [string trim [$wi.remoteinfo.ifc.text get $i.0 $i.end]] if { $ifc != [router.remote.getCInterface $target] } { router.remote.setCInterface $target $ifc set changed 1 } set startcmd [string trim [$wi.remotecommands.start.text get $i.0 $i.end]] if { $startcmd != [router.remote.getStartCmd $target] } { router.remote.setStartCmd $target $startcmd set changed 1 } set stopcmd [string trim [$wi.remotecommands.stop.text get $i.0 $i.end]] if { $stopcmd != [router.remote.getStopCmd $target] } { router.remote.setStopCmd $target $stopcmd set changed 1 } } } if {[[typemodel $target].layer] == "NETWORK"} { foreach ifc [ifcList $target] { set fr $wi.ifaces.c.if$ifc set macaddr [$fr.cfg.mac.addrv get] global if${ifc}_auto_mac if { [set if${ifc}_auto_mac] == 1 } { set macaddr "" } set oldmacaddr [getIfcMacaddr $target $ifc] if { $macaddr != $oldmacaddr } { setIfcMacaddr $target $ifc $macaddr set changed 1 } set ipaddr [$fr.cfg.ipv4.addrv get] set oldipaddr [getIfcIPv4addr $target $ifc] if { $ipaddr != $oldipaddr } { setIfcIPv4addr $target $ifc $ipaddr set changed 1 } set ipaddr [$fr.cfg.ipv6.addrv get] set oldipaddr [getIfcIPv6addr $target $ifc] if { $ipaddr != $oldipaddr } { setIfcIPv6addr $target $ifc $ipaddr set changed 1 } } } } link { global g_link_config_uni_state set mirror [getLinkMirror $target] if { [setIfChanged $target $mirror $wi "bandwidth" "LinkBandwidth"] } { set changed 1 } if { [setIfChanged $target $mirror $wi "delay" "LinkDelay"] } { set changed 1 } if { [setIfChanged $target $mirror $wi "ber" "LinkBER"] } { set changed 1 } if { [setIfChanged $target $mirror $wi "dup" "LinkDup"] } { set changed 1 } if { [setIfChanged $target $mirror $wi "jitter" "LinkJitter"] } { set changed 1 } if { $link_color != [getLinkColor $target] } { setLinkColor $target $link_color if { $mirror != "" } { setLinkColor $mirror $link_color } set changed 1 } set width [$wi.width.value get] if { $width != [getLinkWidth $target] } { setLinkWidth $target $width if { $mirror != "" } { setLinkWidth $mirror $width } set changed 1 } if { $changed == 1 && $oper_mode == "exec" } { execSetLinkParams $eid $target } } } popdownConfig $wi } # helper for Link Config dialog # ctl must exist as $wi.$ctl.value{2}, and {get,set}$procname must be valid # returns true when value has changed, false otherwise proc setIfChanged { target mirror wi ctl procname } { global g_link_config_uni_state set val [$wi.$ctl.value get] if { $g_link_config_uni_state == "uni" } { set val [list $val [$wi.$ctl.value2 get]] } set oldval [get$procname $target] set oldval2 [get$procname $target "up"] if { $oldval2 != "" } { set oldval [list $oldval $oldval2] } if { $val != $oldval } { set$procname $target $val if { $mirror != "" } { set$procname $mirror $val } return true } return false } #****f* editor.tcl/printCanvas # NAME # printCanvas -- print canvas # SYNOPSIS # printCanvas $w # FUNCTION # This procedure is called when the print button in # print dialog box is pressed. # INPUTS # * w -- print dialog widget #**** proc printCanvas { w } { global sizex sizey set prncmd [$w.e1 get] destroy $w set p [open "|$prncmd" WRONLY] puts $p [.c postscript -height $sizey -width $sizex -x 0 -y 0 -rotate yes -pageheight 297m -pagewidth 210m] close $p } #****f* editor.tcl/deleteSelection # NAME # deleteSelection -- delete selection # SYNOPSIS # deleteSelection # FUNCTION # By calling this procedure all the selected nodes in imunes will # be deleted. #**** proc deleteSelection { } { global changed global background global viewid catch {unset viewid} .c config -cursor watch; update foreach lnode [selectedNodes] { if { $lnode != "" } { removeGUINode $lnode } set changed 1 } raiseAll .c updateUndoLog .c config -cursor left_ptr .bottom.textbox config -text "" } proc assignSelection { server } { global changed .c config -cursor watch; update foreach node [selectedNodes] { if { $node != "" } { setNodeLocation $node $server } set changed 1 } redrawAll updateUndoLog .c config -cursor left_ptr .bottom.textbox config -text "" } proc align2grid {} { global sizex sizey grid zoom changed set node_objects [.c find withtag node] if { [llength $node_objects] == 0 } { return } set step [expr {$grid * 4}] for { set x $step } { $x <= [expr {$sizex - $step}] } { incr x $step } { for { set y $step } { $y <= [expr {$sizey - $step}] } { incr y $step } { if { [llength $node_objects] == 0 } { set changed 1 updateUndoLog redrawAll return } set node [lindex [.c gettags [lindex $node_objects 0]] 1] set node_objects [lreplace $node_objects 0 0] setNodeCoords $node "$x $y" lassign [getDefaultLabelOffsets [nodeType $node]] dx dy setNodeLabelCoords $node "[expr {$x + $dx}] [expr {$y + $dy}]" } } } #****f* editor.tcl/rearrange # NAME # rearrange # SYNOPSIS # rearrange $mode # FUNCTION # This procedure rearranges the position of nodes in imunes. # It can be used to rearrange all the nodes or only the selected # nodes. # INPUTS # * mode -- when set to "selected" only the selected nodes will be # rearranged. #**** proc rearrange { mode } { global link_list autorearrange_enabled sizex sizey curcanvas zoom activetool set activetool select if { $autorearrange_enabled } { rearrange_off return } set autorearrange_enabled 1 .bottom.mbuf config -text "autorearrange" if { $mode == "selected" } { .menubar.tools entryconfigure "Auto rearrange all" -state disabled .menubar.tools entryconfigure "Auto rearrange all" -indicatoron off .menubar.tools entryconfigure "Auto rearrange selected" -indicatoron on set tagmatch "node && selected" } else { .menubar.tools entryconfigure "Auto rearrange all" -indicatoron on .menubar.tools entryconfigure "Auto rearrange selected" -state disabled .menubar.tools entryconfigure "Auto rearrange selected" -indicatoron off set tagmatch "node" } set otime [clock clicks -milliseconds] while { $autorearrange_enabled } { set ntime [clock clicks -milliseconds] if { $otime == $ntime } { set dt 0.001 } else { set dt [expr {($ntime - $otime) * 0.001}] if { $dt > 0.2 } { set dt 0.2 } set otime $ntime } set objects [.c find withtag $tagmatch] set peer_objects [.c find withtag node] foreach obj $peer_objects { set node [lindex [.c gettags $obj] 1] set coords [.c coords $obj] set x [expr {[lindex $coords 0] / $zoom}] set y [expr {[lindex $coords 1] / $zoom}] set x_t($node) $x set y_t($node) $y if { $x > 0 } { set fx [expr {1000 / ($x * $x + 100)}] } else { set fx 10 } set dx [expr {$sizex - $x}] if { $dx > 0 } { set fx [expr {$fx - 1000 / ($dx * $dx + 100)}] } else { set fx [expr {$fx - 10}] } if { $y > 0 } { set fy [expr {1000 / ($y * $y + 100)}] } else { set fy 10 } set dy [expr {$sizey - $y}] if { $dy > 0 } { set fy [expr {$fy - 1000 / ($dy * $dy + 100)}] } else { set fy [expr {$fy - 10}] } set fx_t($node) $fx set fy_t($node) $fy } foreach obj $objects { set node [lindex [.c gettags $obj] 1] set i [lsearch -exact $peer_objects $obj] set peer_objects [lreplace $peer_objects $i $i] set x $x_t($node) set y $y_t($node) foreach other_obj $peer_objects { set other [lindex [.c gettags $other_obj] 1] set o_x $x_t($other) set o_y $y_t($other) set dx [expr {$x - $o_x}] set dy [expr {$y - $o_y}] set d [expr {hypot($dx, $dy)}] set d2 [expr {$d * $d}] set p_fx [expr {1000.0 * $dx / ($d2 * $d + 100)}] set p_fy [expr {1000.0 * $dy / ($d2 * $d + 100)}] if {[linkByPeers $node $other] != ""} { set p_fx [expr {$p_fx - $dx * $d2 * .0000000005}] set p_fy [expr {$p_fy - $dy * $d2 * .0000000005}] } set fx_t($node) [expr {$fx_t($node) + $p_fx}] set fy_t($node) [expr {$fy_t($node) + $p_fy}] set fx_t($other) [expr {$fx_t($other) - $p_fx}] set fy_t($other) [expr {$fy_t($other) - $p_fy}] } foreach link $link_list { set nodes [linkPeers $link] if { [getNodeCanvas [lindex $nodes 0]] != $curcanvas || [getNodeCanvas [lindex $nodes 1]] != $curcanvas || [getLinkMirror $link] != "" } { continue } set peers [linkPeers $link] set coords0 [getNodeCoords [lindex $peers 0]] set coords1 [getNodeCoords [lindex $peers 1]] set o_x \ [expr {([lindex $coords0 0] + [lindex $coords1 0]) * .5}] set o_y \ [expr {([lindex $coords0 1] + [lindex $coords1 1]) * .5}] set dx [expr {$x - $o_x}] set dy [expr {$y - $o_y}] set d [expr {hypot($dx, $dy)}] set d2 [expr {$d * $d}] set fx_t($node) \ [expr {$fx_t($node) + 500.0 * $dx / ($d2 * $d + 100)}] set fy_t($node) \ [expr {$fy_t($node) + 500.0 * $dy / ($d2 * $d + 100)}] } } foreach obj $objects { set node [lindex [.c gettags $obj] 1] if { [catch "set v_t($node)" v] } { set vx 0.0 set vy 0.0 } else { set vx [lindex $v_t($node) 0] set vy [lindex $v_t($node) 1] } set vx [expr {$vx + 1000.0 * $fx_t($node) * $dt}] set vy [expr {$vy + 1000.0 * $fy_t($node) * $dt}] set dampk [expr {0.5 + ($vx * $vx + $vy * $vy) * 0.00001}] set vx [expr {$vx * exp( - $dampk * $dt)}] set vy [expr {$vy * exp( - $dampk * $dt)}] set dx [expr {$vx * $dt}] set dy [expr {$vy * $dt}] set x [expr {$x_t($node) + $dx}] set y [expr {$y_t($node) + $dy}] set v_t($node) "$vx $vy" setNodeCoords $node "$x $y" set e_dx [expr {$dx * $zoom}] set e_dy [expr {$dy * $zoom}] .c move $obj $e_dx $e_dy set img [.c find withtag "selectmark && $node"] .c move $img $e_dx $e_dy set img [.c find withtag "nodelabel && $node"] .c move $img $e_dx $e_dy set x [expr {[lindex [.c coords $img] 0] / $zoom}] set y [expr {[lindex [.c coords $img] 1] / $zoom}] setNodeLabelCoords $node "$x $y" .c addtag need_redraw withtag "link && $node" } foreach link [.c find withtag "link && need_redraw"] { redrawLink [lindex [.c gettags $link] 1] } .c dtag link need_redraw update } rearrange_off .bottom.mbuf config -text "" } proc rearrange_off { } { global autorearrange_enabled set autorearrange_enabled 0 .menubar.tools entryconfigure "Auto rearrange all" -state normal .menubar.tools entryconfigure "Auto rearrange all" -indicatoron off .menubar.tools entryconfigure "Auto rearrange selected" -state normal .menubar.tools entryconfigure "Auto rearrange selected" -indicatoron off } #****f* editor.tcl/switchCanvas # NAME # switchCanvas -- switch canvas # SYNOPSIS # switchCanvas $direction # FUNCTION # This procedure switches the canvas in one of the defined # directions (previous, next, first and last). # INPUTS # * direction -- the direction of switching canvas. Can be: prev -- # previus, next -- next, first -- first, last -- last. #**** proc switchCanvas { direction } { global canvas_list curcanvas global sizex sizey set i [lsearch $canvas_list $curcanvas] switch -exact -- $direction { prev { incr i -1 if { $i < 0 } { set curcanvas [lindex $canvas_list end] } else { set curcanvas [lindex $canvas_list $i] } } next { incr i if { $i >= [llength $canvas_list] } { set curcanvas [lindex $canvas_list 0] } else { set curcanvas [lindex $canvas_list $i] } } first { set curcanvas [lindex $canvas_list 0] } last { set curcanvas [lindex $canvas_list end] } } .hframe.t delete all set x 0 foreach canvas $canvas_list { set text [.hframe.t create text 0 0 \ -text "[getCanvasName $canvas]" -tags "text $canvas"] set ox [lindex [.hframe.t bbox $text] 2] set oy [lindex [.hframe.t bbox $text] 3] set tab [.hframe.t create polygon $x 0 [expr {$x + 7}] 18 \ [expr {$x + 2 * $ox + 17}] 18 [expr {$x + 2 * $ox + 24}] 0 $x 0 \ -fill gray -tags "tab $canvas"] set line [.hframe.t create line 0 0 $x 0 [expr {$x + 7}] 18 \ [expr {$x + 2 * $ox + 17}] 18 [expr {$x + 2 * $ox + 24}] 0 999 0 \ -fill #808080 -width 2 -tags "line $canvas"] .hframe.t coords $text [expr {$x + $ox + 12}] [expr {$oy + 2}] .hframe.t raise $text incr x [expr {2 * $ox + 17}] } incr x 7 .hframe.t raise "$curcanvas" .hframe.t itemconfigure "tab && $curcanvas" -fill #e0e0e0 .hframe.t configure -scrollregion "0 0 $x 18" update set width [lindex [.hframe.t configure -width] 4] set lborder [lindex [.hframe.t bbox "tab && $curcanvas"] 0] set rborder [lindex [.hframe.t bbox "tab && $curcanvas"] 2] set lmargin [expr {[lindex [.hframe.t xview] 0] * $x - 1}] set rmargin [expr {[lindex [.hframe.t xview] 1] * $x + 1}] if { $lborder < $lmargin } { .hframe.t xview moveto [expr {1.0 * ($lborder - 10) / $x}] } if { $rborder > $rmargin } { .hframe.t xview moveto [expr {1.0 * ($rborder - $width + 10) / $x}] } set sizex [lindex [getCanvasSize $curcanvas] 0] set sizey [lindex [getCanvasSize $curcanvas] 1] redrawAll } proc resizeCanvasPopup {} { global curcanvas set w .canvasSizeScaleDialog catch {destroy $w} toplevel $w wm transient $w . wm title $w "Canvas Size and Scale" frame $w.buttons pack $w.buttons -side bottom -fill x -pady 2m button $w.buttons.print -text "Apply" -command "resizeCanvasApply $w" button $w.buttons.cancel -text "Cancel" -command "destroy $w" pack $w.buttons.print $w.buttons.cancel -side left -expand 1 set cursize [getCanvasSize $curcanvas] set x [lindex $cursize 0] set y [lindex $cursize 1] set scale [getCanvasScale $curcanvas] set refpt [getCanvasRefPoint $curcanvas] set refx [lindex $refpt 0] set refy [lindex $refpt 1] set latitude [lindex $refpt 2] set longitude [lindex $refpt 3] set altitude [lindex $refpt 4] labelframe $w.size -text "Size" frame $w.size.pixels pack $w.size $w.size.pixels -side top -padx 4 -pady 4 -fill x spinbox $w.size.pixels.x -bg white -width 5 $w.size.pixels.x insert 0 $x $w.size.pixels.x configure -from 300 -to 5000 -increment 2 label $w.size.pixels.label -text "W x" spinbox $w.size.pixels.y -bg white -width 5 $w.size.pixels.y insert 0 $y $w.size.pixels.y configure -from 300 -to 5000 -increment 2 label $w.size.pixels.label2 -text "H pixels" pack $w.size.pixels.x $w.size.pixels.label $w.size.pixels.y \ $w.size.pixels.label2 -side left -pady 2 -padx 2 -fill x frame $w.size.meters pack $w.size.meters -side top -padx 4 -pady 4 -fill x spinbox $w.size.meters.x -bg white -width 7 $w.size.meters.x configure -from 300 -to 10000 -increment 100 label $w.size.meters.label -text "x" spinbox $w.size.meters.y -bg white -width 7 $w.size.meters.y configure -from 300 -to 10000 -increment 100 label $w.size.meters.label2 -text "meters" pack $w.size.meters.x $w.size.meters.label $w.size.meters.y \ $w.size.meters.label2 -side left -pady 2 -padx 2 -fill x labelframe $w.scale -text "Scale" frame $w.scale.ppm pack $w.scale $w.scale.ppm -side top -padx 4 -pady 4 -fill x label $w.scale.ppm.label -text "100 pixels =" entry $w.scale.ppm.metersper100 -bg white -width 10 $w.scale.ppm.metersper100 insert 0 $scale label $w.scale.ppm.label2 -text "meters" pack $w.scale.ppm.label $w.scale.ppm.metersper100 \ $w.scale.ppm.label2 -side left -pady 2 -padx 2 -fill x bind $w.size.pixels.x