From 54db4b39c468c9581ff05d476c4e743828d98c26 Mon Sep 17 00:00:00 2001 From: Phil Whineray Date: Fri, 10 Apr 2015 12:14:55 +0100 Subject: [PATCH] Add vnetbuild --- .gitignore | 16 +- configure.ac | 3 + doc/Makefile.am | 7 +- doc/links-internal-vnetbuild | 11 + doc/links-keywords-vnetbuild | 0 doc/links-website-vnetbuild | 0 doc/vnetbuild/Makefile.am | 129 ++++++ doc/vnetbuild/contents.md | 24 ++ doc/vnetbuild/introduction.md | 80 ++++ doc/vnetbuild/vnetbuild-conf.5.md | 270 +++++++++++++ doc/vnetbuild/vnetbuild.1.md | 102 +++++ examples/Makefile.am | 2 + examples/vnetbuild-simple.conf | 48 +++ examples/vnetbuild.conf | 165 ++++++++ sbin/Makefile.am | 2 +- sbin/vnetbuild.in | 650 ++++++++++++++++++++++++++++++ 16 files changed, 1496 insertions(+), 13 deletions(-) create mode 100644 doc/links-internal-vnetbuild create mode 100644 doc/links-keywords-vnetbuild create mode 100644 doc/links-website-vnetbuild create mode 100644 doc/vnetbuild/Makefile.am create mode 100644 doc/vnetbuild/contents.md create mode 100644 doc/vnetbuild/introduction.md create mode 100644 doc/vnetbuild/vnetbuild-conf.5.md create mode 100644 doc/vnetbuild/vnetbuild.1.md create mode 100644 examples/vnetbuild-simple.conf create mode 100644 examples/vnetbuild.conf create mode 100755 sbin/vnetbuild.in diff --git a/.gitignore b/.gitignore index f9796a0..8d89cc5 100644 --- a/.gitignore +++ b/.gitignore @@ -11,19 +11,14 @@ config.log config.status doc/db-valid doc/services-generated +doc/*/tmp* +doc/*/man/man1/ +doc/*/man/man5/ +doc/*/*-manual.html +doc/*/*-manual.pdf doc/firehol.ent -doc/firehol/tmp* -doc/firehol/man/man1/ -doc/firehol/man/man5/ -doc/firehol/firehol-manual.html -doc/firehol/firehol-manual.pdf doc/firehol/firehol-services.html doc/firehol/firehol-services.5.md -doc/fireqos/tmp* -doc/fireqos/man/man1/ -doc/fireqos/man/man5/ -doc/fireqos/fireqos-manual.html -doc/fireqos/fireqos-manual.pdf doc/index-services.html doc/index.html doc/ch*.html @@ -36,6 +31,7 @@ doc/tools/pandoc-post sbin/firehol sbin/fireqos sbin/link-balancer +sbin/vnetbuild *.xz *.gz *.bz2 diff --git a/configure.ac b/configure.ac index 27e1d9b..c8823db 100644 --- a/configure.ac +++ b/configure.ac @@ -7,6 +7,7 @@ AC_CONFIG_AUX_DIR([autotool]) AC_CONFIG_SRCDIR([sbin/firehol.in]) AC_CONFIG_SRCDIR([sbin/fireqos.in]) AC_CONFIG_SRCDIR([sbin/link-balancer.in]) +AC_CONFIG_SRCDIR([sbin/vnetbuild.in]) AM_INIT_AUTOMAKE([gnu]) AM_MAINTAINER_MODE([disable]) @@ -103,6 +104,7 @@ AC_CONFIG_FILES([ doc/Makefile doc/firehol/Makefile doc/fireqos/Makefile + doc/vnetbuild/Makefile examples/Makefile etc/Makefile packaging/Makefile @@ -111,5 +113,6 @@ AC_CONFIG_FILES([ AC_CONFIG_FILES([sbin/firehol], [chmod +x sbin/firehol]) AC_CONFIG_FILES([sbin/fireqos], [chmod +x sbin/fireqos]) AC_CONFIG_FILES([sbin/link-balancer], [chmod +x sbin/link-balancer]) +AC_CONFIG_FILES([sbin/vnetbuild], [chmod +x sbin/vnetbuild]) AC_OUTPUT diff --git a/doc/Makefile.am b/doc/Makefile.am index 0aa2781..9ace6a2 100644 --- a/doc/Makefile.am +++ b/doc/Makefile.am @@ -1,6 +1,6 @@ # Process this file with automake to produce Makefile.in -SUBDIRS = . firehol fireqos +SUBDIRS = . firehol fireqos vnetbuild all-local: service-links @@ -9,10 +9,13 @@ dochtmldir = $(htmldir)/html MANUAL_LINKS = \ links-internal-firehol \ links-internal-fireqos \ + links-internal-vnetbuild \ links-keywords-firehol \ links-keywords-fireqos \ + links-keywords-vnetbuild \ links-website-firehol \ - links-website-fireqos + links-website-fireqos \ + links-website-vnetbuild if ENABLE_DOC diff --git a/doc/links-internal-vnetbuild b/doc/links-internal-vnetbuild new file mode 100644 index 0000000..f8fcbef --- /dev/null +++ b/doc/links-internal-vnetbuild @@ -0,0 +1,11 @@ + + + +[vnetbuild(1)]: vnetbuild.1.md#vnetbuild1 +[vnetbuild.conf(5)]: vnetbuild-conf.5.md#vnetbuild.conf5 diff --git a/doc/links-keywords-vnetbuild b/doc/links-keywords-vnetbuild new file mode 100644 index 0000000..e69de29 diff --git a/doc/links-website-vnetbuild b/doc/links-website-vnetbuild new file mode 100644 index 0000000..e69de29 diff --git a/doc/vnetbuild/Makefile.am b/doc/vnetbuild/Makefile.am new file mode 100644 index 0000000..09d61a5 --- /dev/null +++ b/doc/vnetbuild/Makefile.am @@ -0,0 +1,129 @@ +# Process this file with automake to produce Makefile.in + +MANUAL_LINKS = \ + ${top_srcdir}/doc/links-internal-vnetbuild \ + ${top_srcdir}/doc/links-keywords-vnetbuild \ + ${top_srcdir}/doc/links-website-vnetbuild + +dochtmldir = $(htmldir)/html + +MANUALHTML_GENERATED = \ + vnetbuild-manual.html + +MANUALPDF_GENERATED = \ + vnetbuild-manual.pdf + +# Generate using: +# (ls vn*.md) | sed -ne 's;\(.*\).\([0-9]\).md;\tman/man\2/\1.\2 \\;p' |sort -u +MANUALMAN_GENERATED = \ + man/man1/vnetbuild.1 \ + man/man5/vnetbuild-conf.5 + +# Generate using: +# sed -ne 's;extra-manpage: \(.*\)\([0-9]\);\tman/man\2/\1\2 \\;p' *.md|sort -u +MANUALMAN_GENERATED_INDIRECT = \ + man/man5/vnetbuild-bridgedev.5 \ + man/man5/vnetbuild.conf.5 \ + man/man5/vnetbuild-dev.5 \ + man/man5/vnetbuild-exec.5 \ + man/man5/vnetbuild-host.5 \ + man/man5/vnetbuild-route.5 \ + man/man5/vnetbuild-switch.5 + +if ENABLE_DOC + +dochtml_DATA = \ + $(MANUALHTML_GENERATED) + +pdf_DATA = \ + $(MANUALPDF_GENERATED) + +endif + +man_MANS = \ + $(MANUALMAN_GENERATED) \ + $(MANUALMAN_GENERATED_INDIRECT) + +if MAINTAINER_MODE + +MKSERVICELINKS = ${top_srcdir}/doc/tools/mkservicelinks +MKSERVICEMAN = ${top_srcdir}/doc/tools/mkserviceman +MANSYNOS = ${top_srcdir}/doc/tools/man-synos +COMBINEPANDOC = ${top_srcdir}/doc/tools/combine-pandoc +PANDOCPOST = ${top_srcdir}/doc/tools/pandoc-post +CHECKLINKS = ${top_srcdir}/doc/tools/check-links + +FIREHOLIN = $(top_srcdir)/sbin/firehol.in + +man/man1/%.1: %.1.md + $(MKDIR_P) man/man1 + $(SED) -e '/^%/s/DATE/@PACKAGE_BUILT_DATE@/' -e '/^%/s/VERSION/@PACKAGE_VERSION@/' $< > tmp-manproc + $(SED) -e 's/: .*#/: #/' $(MANUAL_LINKS) > tmp-anchor-links + $(PANDOC) $(PANDOC_MAN_FLAGS) -o $@ tmp-manproc tmp-anchor-links + $(PANDOCPOST) $(PANDOC_VERSION) man $@ + $(MANSYNOS) $< $@ man/ + +man/man5/%.5: %.5.md + $(MKDIR_P) man/man5 + $(SED) -e '/^%/s/DATE/@PACKAGE_BUILT_DATE@/' -e '/^%/s/VERSION/@PACKAGE_VERSION@/' $< > tmp-manproc + $(SED) -e 's/: .*#/: #/' $(MANUAL_LINKS) > tmp-anchor-links + $(PANDOC) $(PANDOC_MAN_FLAGS) -o $@ tmp-manproc tmp-anchor-links + $(PANDOCPOST) $(PANDOC_VERSION) man $@ + $(MANSYNOS) $< $@ man/ + +$(MANUALMAN_GENERATED): $(MANUAL_LINKS) + +vnetbuild-manual.pdf: *.md $(MANUAL_LINKS) + $(SED) -e 's/: .*#/: #/' $(MANUAL_LINKS) > tmp-anchor-links + $(COMBINEPANDOC) pdf tmp-pdf-combined.md contents.md tmp-anchor-links + $(SED) -i -e '/^%/s/DATE/@PACKAGE_BUILT_DATE@/' -e '/^%/s/VERSION/@PACKAGE_VERSION@/' tmp-pdf-combined.md + $(PANDOC) $(PANDOC_PDF_FLAGS) -o $@ tmp-pdf-combined.md + rm tmp-pdf-combined.md + $(PANDOCPOST) $(PANDOC_VERSION) pdf $@ + +vnetbuild-manual.html: *.md $(MANUAL_LINKS) + $(SED) -e 's/: .*#/: #/' $(MANUAL_LINKS) > tmp-anchor-links + $(COMBINEPANDOC) html tmp-html-combined.md contents.md tmp-anchor-links + $(SED) -i -e '/^%/s/DATE/@PACKAGE_BUILT_DATE@/' -e '/^%/s/VERSION/@PACKAGE_VERSION@/' tmp-html-combined.md + $(PANDOC) $(PANDOC_HTML_FLAGS) -o tmp-manual.html tmp-html-combined.md + rm tmp-html-combined.md + $(CHECKLINKS) tmp-manual.html $(MANUAL_LINKS) + $(PANDOCPOST) $(PANDOC_VERSION) html tmp-manual.html + mv tmp-manual.html $@ + +endif + +EXTRA_DIST = \ + *.md \ + $(MANUALHTML_GENERATED) \ + $(MANUALPDF_GENERATED) \ + $(MANUALMAN_GENERATED) \ + $(MANUALMAN_GENERATED_INDIRECT) + +CLEANFILES = \ + tmp-anchor-links \ + tmp-html-combined.md \ + tmp-manproc \ + tmp-manual.html \ + tmp-pdf-combined.md + +DISTCLEANFILES = + +MAINTAINERCLEANFILES = \ + service-links \ + $(MANUALHTML_GENERATED) \ + $(MANUALPDF_GENERATED) \ + $(MANUALMAN_GENERATED) \ + $(MANUALMAN_GENERATED_INDIRECT) + + +if MAINTAINER_MODE + +DISTCLEANFILES += $(MAINTAINERCLEANFILES) + +endif + + +uninstall-local: + @-rmdir --ignore-fail-on-non-empty $(DESTDIR)$(dochtmldir) + @-rmdir --ignore-fail-on-non-empty $(DESTDIR)$(pdfdir) diff --git a/doc/vnetbuild/contents.md b/doc/vnetbuild/contents.md new file mode 100644 index 0000000..d26fba9 --- /dev/null +++ b/doc/vnetbuild/contents.md @@ -0,0 +1,24 @@ +% VNetBuild Reference +% Copyright (c) Copyright (c) 2012-2015 Phil Whineray ; 2015 Costa Tsaousis +% Version VERSION (Built DATE) + +\newpage + + + +The latest version of this manual is available online as a +[PDF](http://firehol.org/vnetbuild-manual.pdf), as +[single page HTML](http://firehol.org/vnetbuild-manual.html) +and also as +[multiple pages within the website](http://firehol.org/vnetbuild-manual/). + +# VNetBuild Reference + +## Running and Configuring VNetBuild + +* [vnetbuild(1)](vnetbuild.1.md) +* [vnetbuild.conf(5)](vnetbuild-conf.5.md) diff --git a/doc/vnetbuild/introduction.md b/doc/vnetbuild/introduction.md new file mode 100644 index 0000000..dcb0b37 --- /dev/null +++ b/doc/vnetbuild/introduction.md @@ -0,0 +1,80 @@ +Introduction +============ + +Who should read this manual +--------------------------- + +This is a reference guide with specific detailed information on +commands and configuration syntax for the VNetBuild tool. +The reference is unlikely to be suitable for newcomers to the tools, +except as a means to look up more information on a particular command. + +For tutorials and guides to using FireHOL and VNetBuild, please visit the +[website](http://firehol.org/). + +Where to get help +----------------- + +The [FireHOL website](http://firehol.org/). + +The [mailing lists and +archives](http://lists.firehol.org/mailman/listinfo). + +The package comes with a complete set of manpages, a README and a brief +INSTALL guide. + +Installation +------------ + +You can download tar-file releases by visiting the [FireHOL website +download area](http://firehol.org/download/). + +Unpack and change directory with: + + tar xfz firehol-version.tar.gz + cd firehol-version + + +Options for the configure program can be seen in the INSTALL file and by +running: + + ./configure --help + + +To build and install taking the default options: + + ./configure && make && sudo make install + + +Alternatively, just copy the `sbin/vnetbuild.in` file to where you want it. +All of the common SysVInit command line arguments are recognised which +makes it easy to deploy the script as a startup service. + +Packages are available for most distributions and you can use your +distribution's standard commands (e.g. aptitude, yum, etc.) to install +these. + +> **Note** +> +> Distributions do not always offer the latest version. You can see what +> the latest release is on the [FireHOL website](http://firehol.org/). + +Licence +------- + +This manual is licensed under the same terms as the FireHOL package, the +GNU GPL v2 or later. + +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 diff --git a/doc/vnetbuild/vnetbuild-conf.5.md b/doc/vnetbuild/vnetbuild-conf.5.md new file mode 100644 index 0000000..0dd3acd --- /dev/null +++ b/doc/vnetbuild/vnetbuild-conf.5.md @@ -0,0 +1,270 @@ +% vnetbuild.conf(5) VNetBuild Reference | VERSION +% FireHOL Team +% Built DATE + +# NAME + +vnetbuild.conf - VNetBuild configuration file + + + +# SYNOPSIS + +```` +host *ID* + dev *DEVICE* [ *ID*/*PAIRDEV* ] [ *IP*/*MASK*... ] + ... + bridgedev *BRIDGE* [ *DEVICE*... ] [ *IP*/*MASK*... ] + ... + route *ROUTECMD* + ... + exec *CUSTOMCMD* + ... + +... + +switch *ID* + dev *DEVICE* [ *ID*/*PAIRDEV* ] + ... + exec *CUSTOMCMD* + ... + +... +```` + +# DESCRIPTION + +There is no default configuration file for [vnetbuild(1)][]; one must +always be specified on the command line. + +The configuration file defines a set of namespaces that will be operated +on. + +VNetBuild defines two types of namespace, a `host` and a `switch`. Any +number of each may be specified, with any number of configuration +statements in each. + +Note +: The Linux kernel does not see any difference between a `host` and + a `switch` namespace. VNetBuild provides the distinction to make it + easy build full virtual networks. + + +# NAMESPACE DEFINITIONS + +Namespace definitions come in two types, `host` and `switch`. Simply +provide a simple unique alphanumeric *ID*. Any subsequent statements +apply to this namespace until the next `host` or `switch` statement. + +A `host` definition is designed to work like a physical machine. +It allows you to specify any number of `dev` entries for network +interfaces, with their IP addresses. You can also define any +number of Linux bridges with `bridgedev` to add your defined +interfaces to. + +A `host` also allows any number of custom `exec` commands for +extensibility and provides a `route` statement to deal with the +common case of wanting to add network routes to the host. + +A `switch` definition is designed to work like a physical network +switch. It allows you to add any number of `dev` entries (and also +custom `exec` commands for extensibility) but nothing else. + +In addition, `dev` entries in a `switch` may only specify device names, +they cannot have an IP address associated. A `switch` has a bridge +automatically created in it and all `dev` entries are automatically +added to it. + +# CONFIGURATION STATEMENTS + +dev *DEVICE* ... +: Define a virtual ethernet device, *DEVICE* in a `host` or `switch`. + + Devices must exist in pairs. A `dev` must first be defined unpaired + in a namespace, then some subsequent `dev` must define the pair: + + ```` + host a + dev veth0 + host b + dev vppp0 a/veth0 + ```` + + Any *DEVICE* name which is acceptable to the Linux kernel + may be used. We recommend sticking to e.g. `veth0`, `vppp0` etc. + to make it clear that they are virtual and also how you are + thinking of the device in terms of your setup. Devices will + be created as type `veth`, irrespective of what you call them. + + Hosts may optionally specify one or more *IP*/*MASK* values which + will be applied (along with the calculated broadcast address) + automatically, e.g.: + + ```` + host a + dev veth0 10.0.0.1/8 192.168.1.2/24 + host b + dev vppp0 a/veth0 10.0.0.2/8 192.168.1.3/24 + ```` + + A `dev` may not specify an IP address if it is in a `switch`. Switches + exist just to tie together multiple devices in hosts, just like a + physical network switch. + +bridgedev *BRIDGE* ... +: Define an ethernet bridge, *BRIDGE* in a `host`. These are setup + automatically using brctl(8). + + A bridge can specify network devices from its own namespace to + be automatically added, as well as its own IP address(es). + + ```` + host a + dev veth0 + dev veth1 otherns/vdev0 + bridgedev vbr0 veth0 veth1 10.0.0.3/8 + ```` + + Devices included in a bridge generally do not need their own IP + address (although that is permitted). + + Bridges cannot have a pair themselves, but any devices added to + a bridge need a pair as usual. + +route *ROUTECMD* +: Specify an additional network route for a `host`. + + Most commonly to add a default route from hosts on a "LAN" to + the machine that acts as a gateway, e.g.: + + ```` + route default via 10.0.0.254 + ```` + + The syntax of *ROUTECMD* is anything that can fit this pattern: + + ```` + ip route add ROUTECMD + ```` + + See ip(8) and ip-route(8) for help adding routes. If you want to do + anything more complex than simply adding routes, use the `exec` + configuration statement. + +exec *CUSTOMCMD* +: Execute a custom command in a `host` or `switch` once the rest + of the namespace setup is complete. + + Once all the namespaces are created, the final step in setting + each one up is to have its `exec` statements combined and executed. + + It is roughly the equivalent to writing your own script and executing + it after `vnetbuild start` has finished: + + ```` + sudo iptables netns exec myns ./myscript.sh + ```` + + See below for some common uses for custom `exec` commands. + +# COMMON CUSTOM COMMANDS + +Forwarding is not enabled by the Linux kernel when a namespace is first +created. This can be easily done for any hosts that need to forward +traffic: + +~~~~ +host mygateway + ... + exec echo 1 > /proc/sys/net/ipv4/ip_forward +~~~~ + +The `exec` operates in the `mygateway` namespace so your host is not +affected. + +Logs from network namespaces are not included in the normal system +logs. To enable iptables logging you must start an instance of +ulogd(8) in the namespace and use *ULOG* or *NFLOG* logging. For +FireHOL, that means set `FIREHOL_LOG_MODE=ULOG` or +`FIREHOL_LOG_MODE=NFLOG`. Note that *NFLOG* only works with ulogd +version 2. + +The default configuration for ulogd(8) is `/etc/ulogd.conf`. Assuming +the default place it will write iptables logs to is +`/var/log/ulog/syslogemu.log` (otherwise change the `sed` command +as required), it is simple to set up per-namespace logging: + +~~~~ +host mygateway + ... + exec sed 's:/var/log/ulog/syslogemu.log:/var/log/ulog/mygateway.log:' /etc/ulogd.conf > $NSTMP/ulogd.conf + exec /usr/sbin/ulogd -d -c $NSTMP/ulogd.conf +~~~~ + +The `-d` flag to ulogd(8) makes it become a daemon; when `vnetbuild stop` +executes it will automatically kill any programs running in the namespaces +is is stopping, which includes the logging daemon. + +The configuration file will get cleaned as soon as `vnetbuild start` +is finished. To be able to access such files you need to write them to +a location not under `$NSTMP` or create them up outside the `vnetbuild` +configuration altogether. + +# EXAMPLE + +A simple LAN arrangement with two hosts, one of which is a gateway +to third host: + +```` +host host01 + dev veth0 10.0.0.1/8 + dev vppp0 192.168.0.1/24 + exec echo 1 > /proc/sys/net/ipv4/ip_forward + route default via 192.168.0.1 + +host host02 + dev veth0 10.0.0.2/8 + route default via 10.0.0.1 + +switch lan + dev d01 host01/veth0 + dev d02 host02/veth0 + +host extern01 + dev veth0 host01/vppp0 192.168.0.254/24 + route default via 192.168.0.1 + exec echo 1 > /proc/sys/net/ipv4/ip_forward +```` + +# LIMITATIONS + +When created, the namespaces setup by `vnetbuild` are completely +disconnected from any real network. There is no way of defining +such a connection in the `vnetbuild` configuration as allowing it +would lead to conflicts with the normal network setup tools and +configuration files in most distributions. + +It is possible to arrange your network so you can connect real +devices into one or more network namespaces. For the general +approach see this [mailing list post][ml]. + +[ml]: http://lists.firehol.org/pipermail/firehol-support/2015-April/003043.html + +# SEE ALSO + +* [vnetbuild(1)][] - VNetBuild program +* [FireHOL Website](http://firehol.org/) +* [VNetBuild Online PDF Manual](http://firehol.org/vnetbuild-manual.pdf) +* [VNetBuild Online Documentation](http://firehol.org/documentation/) +* [ip(8)](http://manpages.ubuntu.com/manpages/trusty/man8/ip.8.html) - show/manipulate network devices +* [ip-route(8)](http://manpages.ubuntu.com/manpages/trusty/man8/ip-route.8.html) - routing table management +* [brctl(8)](http://manpages.ubuntu.com/manpages/trusty/man8/brctl.8.html) - routing table management +* [ulogd(8)](http://manpages.ubuntu.com/manpages/trusty/man8/ulogd.8.html) - netfilter/iptables logging daemon diff --git a/doc/vnetbuild/vnetbuild.1.md b/doc/vnetbuild/vnetbuild.1.md new file mode 100644 index 0000000..a1b58ef --- /dev/null +++ b/doc/vnetbuild/vnetbuild.1.md @@ -0,0 +1,102 @@ +% vnetbuild(1) VNetBuild Reference | VERSION +% FireHOL Team +% Built DATE + +# NAME + +vnetbuild - an easy to use but powerful namespace setup tool + +# SYNOPSIS + +sudo vnetbuild *CONFIGFILE* { start | stop | status } + +vnetbuild *CONFIGFILE* graphviz *OUTFILE*.{gv|png|pdf|ps} + +# DESCRIPTION + +VNetBuild is a program that helps you set up groups of interconnected +network namespaces, to simulate networks of any complexity without +resorting to using real or virtual machines. + +This is ideal for testing complex multi-host configurations with a minimal +amount of resources on a single machine: + +* Each namespace can have its own network setup, including firewall + and QOS configuration. +* Commands can be run in the namespace and will have that specific + view of the network, including running standard network tools and + daemons. + +Run without any arguments, `vnetbuild` will present some help on usage. + +# COMMANDS + +start +: Sets up a series of network namespaces as defined in *CONFIGFILE*. + `vnetbuild` creates interconnected network devices as specified + in the configuration, sets up routing and runs any custom + commands that are given within the namespace. + +stop +: Removes any devices from the namespaces defined in *CONFIGFILE* + and kills any processes running with the namespaces, then + removes the namespaces themselves. + +status +: For each namespace defined in *CONFIGFILE*, shows if it is active + and if so its network devices and their configuration. + +graphviz *OUTFILE* +: Generates a graph of the network defined in *CONFIGFILE*. This + does not need root access, nor does it require the namespaces + to have been started. + + *OUTFILE* can be `png` `pdf` or `ps`. If the extension `gv` is + given the output is a graphviz(7) file which you can process + separately. + +# RUNNING COMMANDS IN A NAMESPACE + +Once you have created a set of network namespaces, you can easily +run any commands you want within them. If for instance you defined +three hosts (`host_a` with IP `10.0.0.1`, `host_b` +with IP `10.0.0.2` and `host_c` with IP `10.0.0.3`) +connected via a common switch `sw0`: + +~~~~ + # ping host_b and host_c from host_a + sudo ip netns exec host_a ping 10.0.0.2 + sudo ip netns exec host_a ping 10.0.0.3 + + # use netcat to listen on host_a and send data from host_b + # (use two terminals to run the commands simultaneously) + sudo ip netns exec host_a nc -l -p 23 + sudo ip netns exec host_b nc -q 0 10.0.0.1 23 < /etc/hosts + + # capture traffic passing through the switch, then view it + sudo ip netns exec sw0 tcpdump -i switch -w capfile + wireshark capfile + + # Use 'firehol panic' in host_b to block all traffic + # (you could equally load a full config etc.) + sudo ip netns exec host_b firehol panic + + # this is now blocked + sudo ip netns exec host_a ping 10.0.0.2 + + # not blocked (host_b not involved) + sudo ip netns exec host_a ping 10.0.0.3 + + # obtain a shell for your regular user, only "in" host_c + sudo ip netns exec host_c sudo -i -u $USER + ip a | grep 10.0.0.3 +~~~~ + +# SEE ALSO + +* [vnetbuild.conf(5)][] - VNetBuild configuration file +* firehol(1) - FireHOL program +* fireqos(1) - FireQOS program +* [FireHOL Website](http://firehol.org/) +* [VNetBuild Online PDF Manual](http://firehol.org/vnetbuild-manual.pdf) +* [VNetBuild Online Documentation](http://firehol.org/documentation/) diff --git a/examples/Makefile.am b/examples/Makefile.am index 4f54c22..8715e3a 100644 --- a/examples/Makefile.am +++ b/examples/Makefile.am @@ -11,6 +11,8 @@ examples_DATA = \ lan-gateway.conf \ office.conf \ icmpv6.conf \ + vnetbuild.conf \ + vnetbuild-simple.conf \ fireqos.conf EXTRA_DIST = \ diff --git a/examples/vnetbuild-simple.conf b/examples/vnetbuild-simple.conf new file mode 100644 index 0000000..d0f9312 --- /dev/null +++ b/examples/vnetbuild-simple.conf @@ -0,0 +1,48 @@ +# +# Simple vnetbuild config with one namespace representing the firewall, +# one representing the ISP and the whole internet behind it and a few +# more representing hosts on a LAN. +# +# Start namespace: +# sudo vnetbuild vnetbuild-simple.conf start +# +# Ping from a host on the LAN to an internet address (served by ISP) +# sudo ip netns exec host01 ping 192.0.2.1 +# Ping from an internet address (served by ISP) to a host on the LAN: +# sudo ip netns exec isp ping -I 192.0.2.1 10.0.0.2 +# Block all traffic through firewall by invoking firehol in the namespace: +# sudo ip netns exec firewall firehol panic +# Clear the firewall with firehol to re-enable the traffic: +# sudo ip netns exec firewall firehol stop +# + +host firewall + dev ppp0 192.168.1.1/30 + dev veth0 10.0.0.254/8 + route default via 192.168.1.2 + exec echo 1 > /proc/sys/net/ipv4/ip_forward + exec sed 's:/var/log/ulog/syslogemu.log:/var/log/ulog/firewall.log:' /etc/ulogd.conf > $NSTMP/ulogd.conf + exec /usr/sbin/ulogd -d -c $NSTMP/ulogd.conf + +host isp + dev ppp0-wan firewall/ppp0 192.168.1.2/30 192.0.2.1/24 198.51.100.1/24 203.0.113.1/24 + route default via 192.168.1.1 + exec echo 1 > /proc/sys/net/ipv4/ip_forward + +host host01 + dev veth0 10.0.0.1/8 + route default via 10.0.0.254 + +host host02 + dev veth0 10.0.0.2/8 + route default via 10.0.0.254 + +host host03 + dev veth0 10.0.0.2/8 + route default via 10.0.0.254 + +switch lan + dev d01 firewall/veth0 + dev d02 host01/veth0 + dev d03 host02/veth0 + dev d04 host03/veth0 diff --git a/examples/vnetbuild.conf b/examples/vnetbuild.conf new file mode 100644 index 0000000..273fe2e --- /dev/null +++ b/examples/vnetbuild.conf @@ -0,0 +1,165 @@ +# This definition sets up a network according to the diagram below which +# covers a multitude of possible scenarios. +# +# Install graphviz to produce a nice graph: +# vnetbuild vnetbuild-complex.conf graphviz vnetbuild-complex.png +# +# To get iptables logs for "fw", ulogd must be installed. A sed command +# is configured which will create a custom logfile from the system standard +# /etc/ulogd.conf - this may need editing to match your system. +# +# Run: +# sudo vnetbuild vnetbuild.conf start +# +# A network namespace is created for each host and switch to keep everything +# isolated. You can apply different networking setups including routing, +# firewalling and QOS in every namespace. Add more "exec" commands to +# automate this at start time. +# +# Note that there are no virtual machines in use, all processing is done +# on the host but with separate views of what the network looks like. +# +# The name of a host or switch in the configuration is the name used for +# the namespace making it easy to use "ip netns exec" to specify where +# commands should run. Examples: +# +# Tcpdump traffic passing through a switch +# sudo ip netns exec sw0 tcpdump -i switch -w capfile +# +# Tcpdump traffic seen by a device on a host +# sudo ip netns exec host12 tcpdump -i veth0 -w capfile +# +# Ping "from" host01 (10.0.0.1) to host12 via switch sw0 and hosts fw and gw: +# sudo ip netns exec host01 ping 192.168.2.12 +# +# Start netcat on port 23 of host52 to receive telnet: +# sudo ip netns exec host52 nc -l -p 23 +# +# In a different terminal, telnet "from" host21 (10.0.0.1) to host52 +# via fw, switches and bridges: +# sudo ip netns exec host21 telnet 10.45.45.52 +# +# Start firehol in fw host namespace: +# sudo ip netns exec fw firehol some-firehol.conf start +# +# Panic firehol in fw host namespace (now previous commands are blocked): +# sudo ip netns exec fw firehol panic +# +# Key: +# hostname +# [device] (hosts have just a [veth0] unless otherwise noted) +# (switch) +# +# host21 +- host01 host41 +# | | | +# | host22 +- host02 | host42 +# | | | (sw0) | | +# | | . . . . . . . . | . . . . . . . . . | | +# | | . [veth0] . | | +# +-----+----[vbr0eth2] | [vbr1eth4]----+-----+ +# (sw2) . | | fw | . (sw4) +# . + [vbr0]--+---[vbr1] + . +# (sw3) . | | | . (sw5) +# +-----+----[vbr0eth3] | [vbr1eth5]----+-----+ +# | | . [veth1] . | | +# | | . . . . . . . . | . . . . . . . . . | | +# | | | () | | +# | host31 [veth0] | host52 +# | gw | +# host32 [veth1] [veth2] host51 +# () / \ () +# host11 host12 + +host fw + dev veth0 10.0.0.254/24 + dev veth1 10.1.1.254/24 + dev vbr0eth2 + dev vbr0eth3 + dev vbr1eth4 + dev vbr1eth5 + bridgedev vbr0 vbr0eth2 vbr0eth3 10.23.23.254/24 + bridgedev vbr1 vbr1eth4 vbr1eth5 10.45.45.254/24 + route default via 10.1.1.253 + exec echo 1 > /proc/sys/net/ipv4/ip_forward + exec sed 's:/var/log/ulog/syslogemu.log:/var/log/ulog/fw.log:' /etc/ulogd.conf > $NSTMP/ulogd.conf + exec /usr/sbin/ulogd -d -c $NSTMP/ulogd.conf + +host gw + dev veth0 fw/veth1 10.1.1.253/24 + dev veth1 192.168.1.254/24 + dev veth2 192.168.2.254/24 + route default via 10.1.1.254 + exec echo 1 > /proc/sys/net/ipv4/ip_forward + +host host01 + dev veth0 10.0.0.1/24 + route default via 10.0.0.254 + +host host02 + dev veth0 10.0.0.2/24 + route default via 10.0.0.254 + +host host11 + dev veth0 gw/veth1 192.168.1.11/24 + route default via 192.168.1.254 + +host host12 + dev veth0 gw/veth2 192.168.2.12/24 + route default via 192.168.2.254 + +host host21 + dev veth0 10.23.23.21/24 + route default via 10.23.23.254 + +host host22 + dev veth0 10.23.23.22/24 + route default via 10.23.23.254 + +host host31 + dev veth0 10.23.23.31/24 + route default via 10.23.23.254 + +host host32 + dev veth0 10.23.23.32/24 + route default via 10.23.23.254 + +host host41 + dev veth0 10.45.45.41/24 + route default via 10.45.45.254 + +host host42 + dev veth0 10.45.45.42/24 + route default via 10.45.45.254 + +host host51 + dev veth0 10.45.45.51/24 + route default via 10.45.45.254 + +host host52 + dev veth0 10.45.45.52/24 + route default via 10.45.45.254 + +switch sw0 + dev d01 fw/veth0 + dev d02 host01/veth0 + dev d03 host02/veth0 + +switch sw2 + dev d01 fw/vbr0eth2 + dev d02 host21/veth0 + dev d03 host22/veth0 + +switch sw3 + dev d01 fw/vbr0eth3 + dev d02 host31/veth0 + dev d03 host32/veth0 + +switch sw4 + dev d01 fw/vbr1eth4 + dev d02 host41/veth0 + dev d03 host42/veth0 + +switch sw5 + dev d01 fw/vbr1eth5 + dev d02 host51/veth0 + dev d03 host52/veth0 diff --git a/sbin/Makefile.am b/sbin/Makefile.am index 4cfadb8..e60526c 100644 --- a/sbin/Makefile.am +++ b/sbin/Makefile.am @@ -1,3 +1,3 @@ # Process this file with automake to produce Makefile.in -sbin_SCRIPTS = firehol fireqos link-balancer +sbin_SCRIPTS = firehol fireqos link-balancer vnetbuild diff --git a/sbin/vnetbuild.in b/sbin/vnetbuild.in new file mode 100755 index 0000000..06e93b3 --- /dev/null +++ b/sbin/vnetbuild.in @@ -0,0 +1,650 @@ +#!/bin/bash +# +# vnetbuild - linked network namespace setup for humans... +# +# Copyright +# +# Copyright (C) 2015 Phil Whineray +# Copyright (C) 2015 Costa Tsaousis +# +# License +# +# 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, see . +# +# See the file COPYING for details. +# + +# make sure sbin is included in the path +# it seems that pppd ip-up.d script need this +export PATH="$PATH:/sbin:/usr/sbin:/usr/local/sbin" + +get_version() { + GIT_REF='$Format:%d,commit-%h$' + local IFS=":(), " + set -- "$GIT_REF" + ver='$Id$' + for i in $@ + do + case "$i" in + *[0-9].[0.9]*) + echo "$i" | sed -e 's/^v//' + return 0 + ;; + commit-[0-9a-zA-Z]*) + ver="$i" + ;; + esac + done + echo "$ver" + return 0 +} +VERSION=$(get_version) + +emit_version() { + cat < +(C) Copyright 2015 Costa Tsaousis +FireHOL is distributed under the GPL v2+. +Home Page: http://firehol.org + +------------------------------------------------------------------------- +Get notified of new FireHOL releases by subscribing to the mailing list: + http://lists.firehol.org/mailman/listinfo/firehol-support/ +------------------------------------------------------------------------- +EOF +} + +needroot=Y +haderror="" +#gvprog=dot +#gvprog=sfdp +gvprog=neato + +setup="$1" +mode="$2" +outfile="$3" + +case "$mode" in + ""|-h|help|-v|version) + mode= + needroot= + haderror="Y" + ;; + start|stop|status) + : + ;; + graphviz) + needroot= + case "$outfile" in + *.gv|"") + graphviz=cat + ;; + *.ps) + format=ps + graphviz="$gvprog -T$format" + ;; + *.pdf) + format=pdf + graphviz="$gvprog -T$format" + ;; + *.png) + format=png + graphviz="$gvprog -T$format" + ;; + *) + 1>&2 echo "Unrecognised file extension: $mode" + haderror="Y" + ;; + esac + ;; + *) + 1>&2 echo "Unrecognised mode: $mode" + haderror="Y" + needroot= + ;; +esac + +if [ "$mode" = "" ] +then + emit_version +fi + +if [ "$needroot" -a "`id -r -u`" != "0" ] +then + echo "Error: must be root to use '$mode'" + haderror="Y" +fi + +if [ "$haderror" -o $# -lt 2 ] +then + echo "" + echo "Usage: sudo vnetbuild CONFIGFILE stop|start|status" + echo " or: vnetbuild CONFIGFILE graphviz OUTFILE.{gv,png,pdf,ps}" + exit 1 +else + shift + shift +fi + +setupbase="$(basename $setup)" +errline="" +error="" + +if ! MYTMP="`mktemp -d -t vnetbuild-XXXXXX`" +then + echo >&2 + echo >&2 + echo >&2 "Cannot create temporary directory." + echo >&2 + exit 1 +fi + +myexit() { + status=$? + if [ "$error" != "" ] + then + echo "$setupbase: line $errline: $error" + fi + rm -rf $MYTMP + exit $status +} + +trap myexit INT +trap myexit HUP +trap myexit 0 + +CURDIR=`pwd`/ +export CURDIR + +set -e + +mkdir $MYTMP/setup +sed = "$setup" > $MYTMP/withnum +(echo "cd $CURDIR"; sed -e 'N;s/\n/\t/' -e 's/^/lineno=/' -e '/exec/s/[<>|&]/\\&/g' $MYTMP/withnum) > $MYTMP/setup/$setupbase + +mkdir $MYTMP/ns +mkdir $MYTMP/runtime-lines + +current_name= + +create_namespace() { + errline=$lineno + local type="$1" + current_name="$2" + NSTMP=$MYTMP/ns/$current_name + if [ -d $NSTMP ] + then + error="$current_name: $(cat $NSTMP/type) already defined" + return 1 + fi + mkdir $NSTMP + mkdir $NSTMP/devices + mkdir $NSTMP/devicepairs + echo $type > $NSTMP/type + echo 0 > $NSTMP/forward + > $NSTMP/routes + > $NSTMP/devlist + > $NSTMP/pairlist + > $NSTMP/bridgelist + echo $current_name >> $MYTMP/nslist + echo $errline > $MYTMP/runtime-lines/$current_name +} + +host() { + errline=$lineno + create_namespace host "$1" +} + +switch() { + errline=$lineno + create_namespace switch "$1" +} + +dev() { + errline=$lineno + device="$1" + shift + + if [ ! "$current_name" ] + then + error="cannot define dev outside of a host or switch" + return 1 + fi + + if [ -f $NSTMP/devices/$device ] + then + error="$current_name/$device: already defined" + return 1 + fi + + local otherns= + local otherdev= + case $1 in + */[a-zA-Z]*) + otherns=$(echo $1 | cut -f1 -d/) + otherdev=$(echo $1 | cut -f2 -d/) + shift + if [ -f $MYTMP/ns/$otherns/devicepairs/$otherdev ] + then + error="$otherns/$otherdev: already has paired device" + return 1 + fi + ;; + esac + + local type="$(cat $NSTMP/type)" + if [ "$*" != "" -a "$type" = "switch" ] + then + error="device in switch may not specify an IP address" + return 1 + fi + + + f=$NSTMP/devices/$device + > $f + for ip in "$@" + do + case $ip in + */*) + echo "$ip" >> $f + ;; + *) + error="IP address should be expressed as ip/mask" + return 1 + ;; + esac + done + + if [ "$otherdev" ] + then + if [ ! -d $MYTMP/ns/$otherns ] + then + error="$otherns undefined" + return 1 + fi + echo "$current_name $device" > $MYTMP/ns/$otherns/devicepairs/$otherdev + echo "n/a n/a" > $NSTMP/devicepairs/$device + echo "$otherns $otherdev" >> $NSTMP/pairlist + echo $errline > $MYTMP/runtime-lines/$otherns-pair-$otherdev + fi + + echo $device >> $NSTMP/devlist + echo $errline > $MYTMP/runtime-lines/$current_name-dev-$device + return 0 +} + +route() { + errline=$lineno + if [ ! "$current_name" ] + then + error="can only specify route in a host" + return 1 + fi + + local type="$(cat $NSTMP/type)" + if [ "$type" = "switch" ] + then + error="can only specify route in a host" + return 1 + fi + + echo "$*" >> $NSTMP/routes + echo $errline >> $MYTMP/runtime-lines/$current_name-routes + return 0 +} + +bridgedev() { + errline=$lineno + device="$1" + shift + + if [ ! "$current_name" ] + then + error="can only specify bridgedev in a host" + return 1 + fi + + local type="$(cat $NSTMP/type)" + if [ "$type" = "switch" ] + then + error="can only specify bridgedev in a host" + return 1 + fi + + if [ -f $NSTMP/devices/$device ] + then + error="$current_name/$device: already defined" + return 1 + fi + + ipf=$NSTMP/devices/$device + devf=$ipf-bridged + > $ipf + > $devf + for ipordev in "$@" + do + case $ipordev in + */*) + echo "$ipordev" >> $ipf + ;; + *) + echo "$ipordev" >> $devf + ;; + esac + done + + echo $device >> $NSTMP/bridgelist + echo $errline > $MYTMP/runtime-lines/$current_name-dev-$device + return 0 +} + +exec() { + errline=$lineno + if [ ! "$current_name" ] + then + error="can only specify exec in a host or switch" + return 1 + fi + + echo "$*" >> $NSTMP/exec + echo $errline >> $MYTMP/runtime-lines/$current_name-exec + return 0 +} + +cd $MYTMP/setup +. $setupbase +errline="" +cd $CURDIR + +exists_ns() { + if [ "$(ip netns list | grep "^$1\$")" ] + then + return 0 + else + return 1 + fi +} + +dev_in_ns() { + ip netns exec $1 ip link list | grep "^[0-9]" | cut -d: -f2 | tr -d ' ' +} + +get_pids() { + # Not in all versions: + # ip netns pids $1 + find -L /proc/[0-9]*/ns -maxdepth 1 -samefile /var/run/netns/$1 2>/dev/null | cut -f3 -d/ +} + +shutdown_ns() { + for i in $(dev_in_ns $1) + do + ip netns exec $1 ip link set $i down + done + pids=$(get_pids $1) + if [ "$pids" ]; then kill $pids; sleep 1; fi + pids=$(get_pids $1) + if [ "$pids" ]; then kill -9 $pids; fi +} + +startup_ns() { + for i in $(dev_in_ns $1) + do + ip netns exec $1 ip link set $i up + done +} + +while read ns +do + while read dev + do + read errline < $MYTMP/runtime-lines/$ns-dev-$dev + if [ ! -f $MYTMP/ns/$ns/devicepairs/$dev ] + then + error="$ns/$dev has no paired device" + exit 1 + fi + done < $MYTMP/ns/$ns/devlist + + while read otherns otherdev + do + read errline < $MYTMP/runtime-lines/$otherns-pair-$otherdev + if [ ! -f $MYTMP/ns/$otherns/devices/$otherdev ] + then + error="$otherns/$otherdev not defined to be paired with" + exit 1 + fi + done < $MYTMP/ns/$ns/pairlist +done < $MYTMP/nslist + +if [ "$mode" = "stop" -o "$mode" = "start" ] +then + while read ns + do + read errline < $MYTMP/runtime-lines/$ns + error="shutting down namespace" + exists_ns $ns && shutdown_ns $ns + done < $MYTMP/nslist + + while read ns + do + read errline < $MYTMP/runtime-lines/$ns + error="deleting namespace" + exists_ns $ns && ip netns del $ns + done < $MYTMP/nslist + + error="" +fi + +if [ "$mode" = "stop" ] +then + exit 0 +fi + +if [ "$mode" = "start" ] +then + while read ns + do + read errline < $MYTMP/runtime-lines/$ns + error="adding namespace" + type="$(cat $MYTMP/ns/$ns/type)" + ip netns add $ns + if [ "$type" = "switch" ] + then + error="adding bridge to switch namespace" + ip netns exec $ns brctl addbr switch + fi + done < $MYTMP/nslist + + while read ns + do + type="$(cat $MYTMP/ns/$ns/type)" + while read dev + do + read errline < $MYTMP/runtime-lines/$ns-dev-$dev + read ons odev < $MYTMP/ns/$ns/devicepairs/$dev + if [ "$ons" != "n/a" ] + then + error="adding virtual ethernet to $type namespace" + ip link add $dev netns $ns type veth peer netns $ons name $odev + else + : # gets set up from the other end + fi + if [ "$type" = "switch" ] + then + error="adding virtual ethernet to bridge" + ip netns exec $ns brctl addif switch $dev + fi + while read ip + do + error="adding ip address to virtual ethernet" + ip netns exec $ns ip addr add $ip broadcast + dev $dev + done < $MYTMP/ns/$ns/devices/$dev + done < $MYTMP/ns/$ns/devlist + + while read bridge + do + read errline < $MYTMP/runtime-lines/$ns-dev-$bridge + error="adding bridge to host namespace" + ip netns exec $ns brctl addbr $bridge + while read dev + do + error="adding virtual interface to bridge" + ip netns exec $ns brctl addif $bridge $dev + done < $MYTMP/ns/$ns/devices/$bridge-bridged + while read ip + do + error="adding ip to virtual interface" + ip netns exec $ns ip addr add $ip broadcast + dev $bridge + done < $MYTMP/ns/$ns/devices/$bridge + done < $MYTMP/ns/$ns/bridgelist + done < $MYTMP/nslist + + while read ns + do + echo "Starting namespace $ns" + + read errline < $MYTMP/runtime-lines/$ns + error="starting namespace" + startup_ns $ns + + while read route + do + errline=$(tr "\n" "/" < $MYTMP/runtime-lines/$ns-routes | sed -e s:/$::) + error="adding route to $ns" + ip netns exec $ns ip route add $route + done < $MYTMP/ns/$ns/routes + + if [ -f $MYTMP/ns/$ns/exec ] + then + errline=$(tr "\n" "/" < $MYTMP/runtime-lines/$ns-exec | sed -e s:/$::) + error="running exec for $ns" + ip netns exec $ns sh -e $MYTMP/ns/$ns/exec + fi + done < $MYTMP/nslist + error="" +fi + +if [ "$mode" = "status" ] +then + while read ns + do + echo "---------------------- $ns --------------------" + if exists_ns $ns + then + ip netns exec $ns ip addr show + ip netns exec $ns ip route show + ip netns exec $ns brctl show + else + echo "Namespace not running" + fi + echo "" + done < $MYTMP/nslist +fi + +if [ "$mode" = "graphviz" ] +then + gv=$MYTMP/gv + echo "/* process e.g.: $gvprog -Tps filename.gv -o filename.ps */" >$gv + echo "graph NET {" >>$gv + if [ "$format" != "png" ] + then + echo "size=7; /* Max size 7 inches */" >>$gv + fi + echo "overlap=prism;" >>$gv + echo "edge [color=blue,style=dashed];" >>$gv + while read ns + do + type="$(cat $MYTMP/ns/$ns/type)" + if [ "$type" = "switch" ] + then + echo "switch_$ns [shape=polygon,sides=4,skew=.4,label=\"$ns\"];" >>$gv + else + echo -n "host_$ns [shape=record,label=\"$ns" >>$gv + while read route + do + echo -n "\\n$route" >>$gv + done < $MYTMP/ns/$ns/routes + while read bridge + do + echo -n "|{<$bridge> $bridge" >>$gv + while read ip + do + echo -n "\\n$ip" >>$gv + done < $MYTMP/ns/$ns/devices/$bridge + while read dev + do + echo -n "|{" >>$gv + echo -n "<$dev> $dev" >>$gv + while read ip + do + echo -n "\n$ip" >>$gv + done < $MYTMP/ns/$ns/devices/$dev + echo -n "}" >>$gv + echo "$bridge" > $MYTMP/ns/$ns/suppress-$dev + done < $MYTMP/ns/$ns/devices/$bridge-bridged + echo -n "}" >>$gv + done < $MYTMP/ns/$ns/bridgelist + while read dev + do + if [ ! -f $MYTMP/ns/$ns/suppress-$dev ] + then + echo -n "|<$dev> $dev" >>$gv + while read ip + do + echo -n "\\n$ip" >>$gv + done < $MYTMP/ns/$ns/devices/$dev + fi + done < $MYTMP/ns/$ns/devlist + echo "\"];" >>$gv + fi + done < $MYTMP/nslist + while read ns + do + type="$(cat $MYTMP/ns/$ns/type)" + while read dev + do + read ons odev < $MYTMP/ns/$ns/devicepairs/$dev + if [ "$ons" != "n/a" ] + then + otype="$(cat $MYTMP/ns/$ons/type)" + if [ "$type" = "switch" ] + then + from="switch_$ns" + else + from="host_$ns:$dev" + fi + if [ "$otype" = "switch" ] + then + to="switch_$ons" + else + to="host_$ons:$odev" + fi + echo "$from -- $to;" >>$gv + else + : # gets set up from the other end + fi + done < $MYTMP/ns/$ns/devlist + done < $MYTMP/nslist + echo "}" >>$gv + + if [ "$outfile" = "" ] + then + $graphviz $gv + else + $graphviz $gv > "$outfile" + fi +fi + +exit 0