aboutsummaryrefslogtreecommitdiff
path: root/share/examples/netgraph
diff options
context:
space:
mode:
Diffstat (limited to 'share/examples/netgraph')
-rw-r--r--share/examples/netgraph/ether.bridge169
-rw-r--r--share/examples/netgraph/frame_relay45
-rw-r--r--share/examples/netgraph/ngctl172
-rw-r--r--share/examples/netgraph/raw15
-rw-r--r--share/examples/netgraph/udp.tunnel52
-rw-r--r--share/examples/netgraph/virtual.chain369
-rw-r--r--share/examples/netgraph/virtual.lan358
7 files changed, 1180 insertions, 0 deletions
diff --git a/share/examples/netgraph/ether.bridge b/share/examples/netgraph/ether.bridge
new file mode 100644
index 000000000000..6a9dd5c36c6e
--- /dev/null
+++ b/share/examples/netgraph/ether.bridge
@@ -0,0 +1,169 @@
+#!/bin/sh
+# This script sets up an Ethernet bridging network across multiple
+# Ethernet interfaces using the ng_bridge(4) and ng_ether(4) netgraph
+# node types.
+#
+# To use this script:
+#
+# 0. Make your own copy of this example script.
+#
+# 1. Give your bridging network a name by editing the definition of
+# ${BRIDGE_NAME} below. It must be a valid netgraph node name.
+#
+# 2. Edit the definitions of ${BRIDGE_IFACES} and ${LOCAL_IFACES}
+# as described below to define your bridging interfaces.
+#
+# 3. Run this script with "start" as the command line argument.
+#
+# 4. Examine bridging statistics by running this script with "stats"
+# as the command line argument.
+#
+# 5. Stop bridging by running this script with "stop" as the
+# command line argument.
+#
+# To run multiple independent bridging networks, create multiple
+# copies of this script with different variable definitions.
+#
+# To make a "brouted" network, with IP being routed and other protocols being
+# bridged, add all the interface in the BRIDGE_IFACES to the LOCAL_IFACES.
+# If you just want a normal bridge, just one will be enough.
+# In some cases you may want some combination.
+#
+
+# Give each bridging network a unique name here.
+
+BRIDGE_NAME="bnet0"
+
+# List the names of the interfaces that you want to bridge across
+# here in ${BRIDGE_IFACES}. If you want to include the local host
+# machine as well then set ${LOCAL_IFACES} as well (they may also be
+# listed in ${BRIDGE_IFACES}). Of course, any ${LOCAL_IFACE} must
+# be ifconfig(8)ured separately. If you don't want a ${LOCAL_IFACE}
+# then assign it the empty string.
+
+BRIDGE_IFACES="de0 fxp0 fxp1"
+LOCAL_IFACES="fxp0 fxp1"
+
+#####################################################################
+#### Everything below this point should not need to be modified. ####
+#####################################################################
+
+# Routine to verify node's existence.
+bridge_verify() {
+ ngctl info ${BRIDGE_NAME}: >/dev/null 2>&1
+ if [ $? -ne 0 ]; then
+ echo "${BRIDGE_NAME}: bridge network not found"
+ exit 1
+ fi
+}
+
+# Routine to get and display link stats.
+bridge_linkstats() {
+ STATS=`ngctl msg ${BRIDGE_NAME}: getstats $1`
+ if [ $? -ne 0 ]; then
+ exit 1
+ fi
+ echo "${STATS}" | fmt 2 | awk '/=/ { fl=index($0, "="); \
+ printf "%20s = %s\n", substr($0, 0, fl - 1), substr($0, fl + 1); }'
+}
+
+# Start/restart routine.
+bridge_start() {
+
+ # Load netgraph KLD's as necessary.
+ for KLD in ng_ether ng_bridge; do
+ if ! kldstat -v | grep -qw ${KLD}; then
+ echo -n "Loading ${KLD}.ko... "
+ kldload ${KLD} || exit 1
+ echo "done"
+ fi
+ done
+
+ # Reset all interfaces.
+ bridge_stop
+
+ # Verify all interfaces exist.
+ for ETHER in ${BRIDGE_IFACES} ${LOCAL_IFACES}; do
+ if ! ngctl info ${ETHER}: >/dev/null 2>&1; then
+ echo "Error: interface ${ETHER} does not exist"
+ exit 1
+ fi
+ ifconfig ${ETHER} up || exit 1
+ done
+
+ # Create new ng_bridge(4) node, attached to the first interface.
+ FIRSTIF=`echo ${BRIDGE_IFACES} | awk '{ print $1 }'`
+ ngctl mkpeer ${FIRSTIF}: bridge lower link0 || exit 1
+ ngctl name ${FIRSTIF}:lower ${BRIDGE_NAME} || exit 1
+
+ # Attach other interfaces as well.
+ LINKNUM=0
+ for ETHER in ${BRIDGE_IFACES}; do
+ if [ ${LINKNUM} != 0 ]; then
+ ngctl connect ${ETHER}: ${BRIDGE_NAME}: \
+ lower link${LINKNUM} || exit 1
+ fi
+ LINKNUM=`expr ${LINKNUM} + 1`
+ done
+
+ # Hook up local interface, if any.
+ for LOCAL_IFACE in ${LOCAL_IFACES}; do
+ ngctl connect ${LOCAL_IFACE}: ${BRIDGE_NAME}: \
+ upper link${LINKNUM} || exit 1
+ LINKNUM=`expr ${LINKNUM} + 1`
+ done
+
+ # Set all interfaces in promiscuous mode and don't overwrite src addr.
+ for ETHER in ${BRIDGE_IFACES}; do
+ ngctl msg ${ETHER}: setpromisc 1 || exit 1
+ ngctl msg ${ETHER}: setautosrc 0 || exit 1
+ done
+}
+
+# Stop routine.
+bridge_stop() {
+ ngctl kill ${BRIDGE_NAME}: >/dev/null 2>&1
+ for ETHER in ${BRIDGE_IFACES} ${LOCAL_IFACES}; do
+ ngctl kill ${ETHER}: >/dev/null 2>&1
+ done
+}
+
+# Stats routine.
+bridge_stats() {
+
+ # Make sure node exists.
+ bridge_verify
+
+ echo ""
+ echo "Statistics for bridging network ${BRIDGE_NAME}:"
+ echo ""
+ LINKNUM=0
+ for ETHER in ${BRIDGE_IFACES}; do
+ echo "Network interface ${ETHER}:"
+ bridge_linkstats ${LINKNUM}
+ LINKNUM=`expr ${LINKNUM} + 1`
+ done
+ for LOCAL_IFACE in ${LOCAL_IFACES}; do
+ echo "Local host interface ${LOCAL_IFACE}:"
+ bridge_linkstats ${LINKNUM}
+ LINKNUM=`expr ${LINKNUM} + 1`
+ done
+}
+
+# Main entry point.
+case $1 in
+ start)
+ bridge_start
+ ;;
+ stats)
+ bridge_verify
+ bridge_stats
+ ;;
+ stop)
+ bridge_verify
+ bridge_stop
+ ;;
+ *)
+ echo "usage: $0 [ start | stop | stats ]"
+ exit 1
+esac
diff --git a/share/examples/netgraph/frame_relay b/share/examples/netgraph/frame_relay
new file mode 100644
index 000000000000..0113f76076da
--- /dev/null
+++ b/share/examples/netgraph/frame_relay
@@ -0,0 +1,45 @@
+#!/bin/sh
+# script to set up a frame relay link on the sr card.
+# The dlci used is selected below. The default is 16
+
+CARD=sr0
+DLCI=16
+
+# create a frame_relay type node and attach it to the sync port.
+ngctl mkpeer ${CARD}: frame_relay rawdata downstream
+
+# Attach the dlci output of the (de)multiplexor to a new
+# Link management protocol node.
+ngctl mkpeer ${CARD}:rawdata lmi dlci0 auto0
+
+# Also attach dlci 1023, as it needs both to try auto-configuring.
+# The Link management protocol is now alive and probing..
+ngctl connect ${CARD}:rawdata ${CARD}:rawdata.dlci0 dlci1023 auto1023
+
+# Attach the DLCI(channel) the Telco has assigned you to
+# a node to handle whatever protocol encapsulation your peer
+# is using. In this case RFC1490 encapsulation.
+ngctl mkpeer ${CARD}:rawdata rfc1490 dlci${DLCI} downstream
+
+
+# Attach the ip (inet) protocol output of the protocol mux to the ip (inet)
+# input of a netgraph "interface" node (ifconfig should show it as "ng0").
+#if interface ng0 needs to be created use a mkpeer command.. e.g.
+ngctl mkpeer ${CARD}:rawdata.dlci${DLCI} iface inet inet
+
+# if ng0 already exists, use a CONNECT command instead of a mkpeer. e.g.
+# ngctl connect ${CARD}:rawdata.dlci${DLCI} ng0: inet inet
+
+# Then use ifconfig on interface ng0 as usual
+
+# A variant on this whole set might use the 'name' command to make it more
+# readable. But it doesn't work if you have multiple lines or dlcis
+# e.g.
+# ngctl mkpeer ${CARD}: frame_relay rawdata downstream
+# ngctl name ${CARD}:rawdata mux
+# ngctl mkpeer mux: lmi dlci0 auto0
+# ngctl name mux:dlci0 lmi
+# ngctl connect mux: lmi: dlci1023 auto1023
+# ngctl mkpeer mux: rfc1490 dlci${DLCI} downstream
+# ngctl mux:dlci${DLCI} protomux
+# ngctl mkpeer protomux: iface inet inet
diff --git a/share/examples/netgraph/ngctl b/share/examples/netgraph/ngctl
new file mode 100644
index 000000000000..c879cbea7b0f
--- /dev/null
+++ b/share/examples/netgraph/ngctl
@@ -0,0 +1,172 @@
+
+#
+# This is an example that shows how to send ASCII formatted control
+# messages to a node using ngctl(8).
+#
+# What we will do here create a divert(4) tap. This simply dumps
+# out all packets diverted by some ipfw(8) divert rule to the console.
+#
+# Lines that begin with ``$'' (shell prompt) or ``+'' (ngctl prompt)
+# indicate user input
+#
+
+# First, start up ngctl in interactive mode:
+
+ $ ngctl
+ Available commands:
+ connect Connects hook <peerhook> of the node at <relpath> to <hook>
+ debug Get/set debugging verbosity level
+ help Show command summary or get more help on a specific command
+ list Show information about all nodes
+ mkpeer Create and connect a new node to the node at "path"
+ msg Send a netgraph control message to the node at "path"
+ name Assign name <name> to the node at <path>
+ read Read and execute commands from a file
+ rmhook Disconnect hook "hook" of the node at "path"
+ show Show information about the node at <path>
+ shutdown Shutdown the node at <path>
+ status Get human readable status information from the node at <path>
+ types Show information about all installed node types
+ quit Exit program
+ +
+
+# Now let's create a ng_ksocket(4) node, in the family PF_DIVERT,
+# of type SOCK_RAW:
+
+ + mkpeer ksocket foo divert/raw/0
+
+# Note that ``foo'' is the hook name on the socket node, which can be
+# anything. The ``inet/raw/divert'' is the hook name on the ksocket
+# node, which tells it what kind of socket to create.
+
+# Lets give our ksocket node a global name. How about ``fred'':
+
+ + name foo fred
+
+# Note that we used ngctl's ``name'' command to do this. However,
+# the following manually constructed netgraph message would have
+# accomplished the exact same thing:
+
+ + msg foo name { name="fred" }
+
+# Here we are using the ASCII <-> binary control message conversion
+# routines. ngctl does this for us automatically when we use the
+# ``msg'' command.
+
+# Now lets bind the socket associated with the ksocket node to a port
+# supplied by the system. We do this by sending the ksocket node a
+# ``bind'' control message. Again, ngctl does the conversion of the
+# control message from ASCII to binary behind the scenes.
+
+ + msg fred: bind inet/192.168.1.1
+
+# The ksocket accepts arbitrary sockaddr structures, but also has
+# special support for the PF_LOCAL and PF_INET protocol families.
+# That is why we can specify the struct sockaddr argument to the
+# ``bind'' command as ``inet/192.168.1.1'' (since we didn't specify
+# a port number, it's assumed to be zero). We could have also
+# relied on the generic sockaddr syntax and instead said this:
+
+ + msg fred: bind { family=2 len=16 data=[ 2=192 168 1 1 ] }
+
+# This is what you would have to do for protocol families other
+# that PF_INET and PF_LOCAL, at least until special handling for
+# new ones is added.
+
+# The reason for the ``2=192'' is to skip the two byte IP port number,
+# which causes it to be set to zero, the default value for integral
+# types when parsing. Now since we didn't ask for a specific port
+# number, we need to do a ``getname'' to see what port number we got:
+
+ + msg fred: getname
+ Rec'd response "getname" (5) from "fred:":
+ Args: inet/192.168.1.1:1029
+
+# As soon as we sent the message, we got back a response. Here
+# ngctl is telling us that it received a control message with the
+# NGF_RESP (response) flag set, the response was to a prior ``getname''
+# control message, that the originator was the node addressable
+# as ``fred:''. The message arguments field is then displayed to
+# us in its ASCII form. In this case, what we get back is a struct
+# sockaddr, and there we see that our port number is 1029.
+
+# So now let's add the ipfw divert rule for whatever packets we
+# want to see. How about anything from 192.168.1.129.
+
+ + ^Z
+ Suspended
+ $ ipfw add 100 divert 1029 ip from 192.168.1.129 to any
+ 00100 divert 1029 ip from 192.168.1.129 to any
+ $ fg
+
+# Now watch what happens when we try to ping from that machine:
+
+ +
+ Rec'd data packet on hook "foo":
+ 0000: 45 00 00 3c 57 00 00 00 20 01 bf ee c0 a8 01 81 E..<W... .......
+ 0010: c0 a8 01 01 08 00 49 5c 03 00 01 00 61 62 63 64 ......I\....abcd
+ 0020: 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 efghijklmnopqrst
+ 0030: 75 76 77 61 62 63 64 65 66 67 68 69 uvwabcdefghi
+ +
+ Rec'd data packet on hook "foo":
+ 0000: 45 00 00 3c 58 00 00 00 20 01 be ee c0 a8 01 81 E..<X... .......
+ 0010: c0 a8 01 01 08 00 48 5c 03 00 02 00 61 62 63 64 ......H\....abcd
+ 0020: 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 efghijklmnopqrst
+ 0030: 75 76 77 61 62 63 64 65 66 67 68 69 uvwabcdefghi
+ +
+ Rec'd data packet on hook "foo":
+ 0000: 45 00 00 3c 59 00 00 00 20 01 bd ee c0 a8 01 81 E..<Y... .......
+ 0010: c0 a8 01 01 08 00 47 5c 03 00 03 00 61 62 63 64 ......G\....abcd
+ 0020: 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 efghijklmnopqrst
+ 0030: 75 76 77 61 62 63 64 65 66 67 68 69 uvwabcdefghi
+ +
+
+# So we're seeing the output from the ksocket socket appear on the ``foo''
+# hook of ngctl's socket node. Since the packets are getting diverted,
+# the 192.168.1.129 machine doesn't see any response from us.
+
+# Of course, any type of socket can be used, even TCP:
+
+ + mkpeer ksocket bar inet/stream/tcp
+ + msg bar connect inet/192.168.1.33:13
+ ngctl: send msg: Operation now in progress
+ +
+ Rec'd data packet on hook "foo":
+ 0000: 4d 6f 6e 20 4e 6f 76 20 32 39 20 31 37 3a 34 38 Mon Nov 29 17:48
+ 0010: 3a 33 37 20 31 39 39 39 0d 0a :37 1999..
+ +
+
+# Or, UNIX domain:
+
+ + mkpeer ksocket bar local/stream/0
+ + msg bar bind local/"/tmp/bar.socket"
+ +
+
+# Here's an example of a more complicated ASCII control message argument.
+# If you look in /sys/netgraph/ng_message.h, you will see that a node
+# responds to a NGM_LISTHOOKS with a struct hooklist, which contains
+# an array of struct linkinfo:
+#
+# /* Structure used for NGM_LISTHOOKS */
+# struct linkinfo {
+# char ourhook[NG_HOOKSIZ]; /* hook name */
+# char peerhook[NG_HOOKSIZ]; /* peer hook */
+# struct nodeinfo nodeinfo;
+# };
+#
+# struct hooklist {
+# struct nodeinfo nodeinfo; /* node information */
+# struct linkinfo link[0]; /* info about each hook */
+# };
+#
+# By sending a node the ``listhooks'' command using ngctl, we can see
+# this structure in ASCII form (lines wrapped for readability):
+
+ + msg bar bind local/"/tmp/bar.socket"
+ + msg bar listhooks
+ Rec'd response "listhooks" (7) from "bar":
+ Args: { nodeinfo={ type="ksocket" id=9 hooks=1 }
+ linkinfo=[ { ourhook="local/stream/0" peerhook="bar"
+ nodeinfo={ name="ngctl1327" type="socket" id=8 hooks=1 } } ] }
+
+
diff --git a/share/examples/netgraph/raw b/share/examples/netgraph/raw
new file mode 100644
index 000000000000..44196780fd0c
--- /dev/null
+++ b/share/examples/netgraph/raw
@@ -0,0 +1,15 @@
+#!/bin/sh
+# script to connect a raw synchronous card to a system interface.
+# Assumes the file if_sr was compiled with options NETGRAPH.
+
+CARD=sr0
+
+# create an interface "ng0" and attach it to the sync port.
+# The packets had jolly well better be IP because we are not discriminating.
+ngctl mkpeer ${CARD}: iface rawdata inet
+
+# if ng0 already exists, use a CONNECT command instead of a mkpeer. e.g.
+# ngctl connect ${CARD}: ng0: rawdata inet
+
+# Then use ifconfig on interface ng0 as usual
+
diff --git a/share/examples/netgraph/udp.tunnel b/share/examples/netgraph/udp.tunnel
new file mode 100644
index 000000000000..fb589ed7e15f
--- /dev/null
+++ b/share/examples/netgraph/udp.tunnel
@@ -0,0 +1,52 @@
+#!/bin/sh
+
+# This script sets up a virtual point-to-point WAN link between
+# two subnets, using UDP packets as the ``WAN connection.''
+# The two subnets might be non-routable addresses behind a
+# firewall.
+#
+
+# Here define the local and remote inside networks as well
+# as the local and remote outside IP addresses and UDP port
+# number that will be used for the tunnel.
+#
+LOC_INTERIOR_IP=192.168.1.1
+LOC_EXTERIOR_IP=1.1.1.1
+REM_INTERIOR_IP=192.168.2.1
+REM_EXTERIOR_IP=2.2.2.2
+REM_INSIDE_NET=192.168.2.0
+UDP_TUNNEL_PORT=4028
+
+# Create the interface node ``ng0'' if it doesn't exist already,
+# otherwise just make sure it's not connected to anything.
+# In FreeBSD, interfaces cannot be removed so it might already
+# be there from before.
+#
+if ifconfig ng0 >/dev/null 2>&1; then
+ ifconfig ng0 inet down delete >/dev/null 2>&1
+ ngctl shutdown ng0:
+else
+ ngctl mkpeer iface dummy inet
+fi
+
+# Attach a UDP socket to the ``inet'' hook of the interface node
+# using the ng_ksocket(4) node type.
+#
+ngctl mkpeer ng0: ksocket inet inet/dgram/udp
+
+# Bind the UDP socket to the local external IP address and port
+#
+ngctl msg ng0:inet bind inet/${LOC_EXTERIOR_IP}:${UDP_TUNNEL_PORT}
+
+# Connect the UDP socket to the peer's external IP address and port
+#
+ngctl msg ng0:inet connect inet/${REM_EXTERIOR_IP}:${UDP_TUNNEL_PORT}
+
+# Configure the point-to-point interface
+#
+ifconfig ng0 ${LOC_INTERIOR_IP} ${REM_INTERIOR_IP}
+
+# Add a route to the peer's interior network via the tunnel
+#
+route add ${REM_INSIDE_NET} ${REM_INTERIOR_IP}
+
diff --git a/share/examples/netgraph/virtual.chain b/share/examples/netgraph/virtual.chain
new file mode 100644
index 000000000000..615f7da20a52
--- /dev/null
+++ b/share/examples/netgraph/virtual.chain
@@ -0,0 +1,369 @@
+#!/bin/sh
+#
+# Copyright (c) 2010, Yavuz Gokirmak
+#
+# All rights reserved.
+#
+# This source code may be used, modified, copied, distributed, and
+# sold, in both source and binary form provided that the above
+# copyright and these terms are retained, verbatim, as the first
+# lines of this file. Under no circumstances is the author
+# responsible for the proper functioning of the software nor does
+# the author assume any responsibility for damages incurred with
+# its use.
+#
+#
+# This script creates and connects n router like nodes. Complex wide
+# area topologies can be created with the help of script.
+#
+# Virtual nodes are generated via jails and network connections are
+# established using ng_eiface(4) node types.
+#
+# To use this script:
+#
+# 0. Make your own copy of this example script.
+#
+# 1. Edit the definition of ${TARGET_TOPOLOGY} to define your virtual
+# nodes. Virtual topology definition includes node names and their
+# IP address. Target top. syntax: ( name|ip<->name|ip ... )
+# Example 1: ( n1|10.0.2.1/30<->n2|10.0.2.2/30 ...)
+# Example 2: ( n1|2001:b90::14a/125<->n1|2001:b90::14b/125 ...)
+#
+# 2. Run this script with "start" as the command line argument.
+#
+# 3. Add necessary static route commands for each virtual node. For
+# example assume you have three virtual nodes connected each other
+# like a chain (n1 is connected to n2, n2 is connected to n3).
+# In order to establish connectivity among these virtual nodes,
+# you have to add default routes to node n1 and node n3. Example
+# static route command is:
+# STATIC_ROUTE0="jexec n1 route add -inet default 10.0.2.2"
+# STATIC_ROUTE1="jexec n3 route add -inet default 10.0.2.5"
+# After defining default routes with above format you have to set
+# the total number of static route commands as:
+# STATIC_ROUTE_CNT=2
+#
+# 4. Stop bridging by running this script with "stop" as the
+# command line argument.
+#
+# 5. This script uses a template file in order to carry information
+# between start and stop calls.
+# In the start call, the netgraph interfaces and jails are created.
+# At the stop phase, all created objects should be removed.
+# DO NOT delete the temporary file between the start and stop phases.
+#
+# Target Topology:
+#
+# +---------------+ +---------------------------------------------+
+# | n1 (vimage) | | n2 (vimage) |
+# | | | |
+# | +-----------+ | | +-----------+ +-----------+ +-----------+ |
+# | | ngeth0 | | | | ngeth1 | | ngeth2 | | ngeth4 | |
+# | |(ng_eiface)| | | |(ng_eiface)| |(ng_eiface)| |(ng_eiface)| |
+# | +--+-----+--+ | | +--+-----+--+ +--+-----+--+ +--+-----+--+ |
+# | |ether| | | |ether| |ether| |ether| |
+# | +-X---+ | | +--X--+ +--X--+ +--X--+ |
+# +-------X-------+ +------X--------------X---------------X-------+
+# X X X X
+# X X X X
+# XXXXXXXXXXXXXXX X X
+# X X
+# +--------X------+ +--------X------+
+# | -+--X--+- | | -+--X--+- |
+# | |ether| | | |ether| |
+# | +--+-----+--+ | | +--+-----+--+ |
+# | | ngeth3 | | | | ngeth5 | |
+# | |(ng_eiface)| | | |(ng_eiface)| |
+# | +-----------+ | | +-----------+ |
+# | | | |
+# | n3 (vimage) | | n4 (vimage) |
+# +---------------+ +---------------+
+#
+#
+#
+
+# List the names of virtual nodes and their IP addresses. Use ':'
+# character to separate node name from node IP address and netmask.
+
+TARGET_TOPOLOGY="n1|10.0.2.1/30<->n2|10.0.2.2/30 n2|10.0.2.5/30<->n3|10.0.2.6/30 n2|10.0.2.9/30<->n4|10.0.2.10/30"
+STATIC_ROUTE0="jexec n1 route add -inet default 10.0.2.2"
+STATIC_ROUTE1="jexec n3 route add -inet default 10.0.2.5"
+STATIC_ROUTE2="jexec n4 route add -inet default 10.0.2.9"
+STATIC_ROUTE_CNT=3
+
+# MAC manufacturer prefix. This can be modified according to needs.
+MAC_PREFIX="00:1d:92"
+
+# Temporary file is important for proper execution of script.
+TEMP_FILE="/var/tmp/.virtual.chain.tmp"
+
+# Set root directory for jails to be created.
+JAIL_PATH="/usr/jails/router"
+
+
+####################################################################
+#### Nothing below this point should need to be modified. ####
+####################################################################
+
+
+# Start/restart routine.
+virtual_chain_start() {
+
+ # Load netgraph KLD's as necessary.
+
+ for KLD in ng_ether ng_bridge ng_eiface; do
+ if ! kldstat -v | grep -qw ${KLD}; then
+ echo -n "Loading ${KLD}.ko... "
+ kldload ${KLD} || exit 1
+ echo "done"
+ fi
+ done
+
+ # Reset all interfaces and jails. If temporary file can not be found
+ # script assumes that there is no previous configuration.
+
+ if [ ! -e ${TEMP_FILE} ]; then
+ echo "No previous configuration(${TEMP_FILE}) found to clean-up."
+ else
+ echo -n "Cleaning previous configuration..."
+ virtual_chain_stop
+ echo "done"
+ fi
+
+ # Create temporary file for usage. This file includes generated
+ # interface names and jail names. All bridges, interfaces and jails
+ # are written to file while created. In clean-up process written
+ # objects are cleaned (i.e. removed) from system.
+
+ if [ -e ${TEMP_FILE} ]; then
+ touch ${TEMP_FILE}
+ fi
+
+
+ # Attach other interfaces as well.
+ for CONNECTION in ${TARGET_TOPOLOGY}; do
+
+ # Virtual connections are defined in TARGET_TOPOLOGY variable.
+ # They have the form of 'nodeName|IPaddr'. Below two lines split
+
+ PEER1=`echo ${CONNECTION} | awk -F"<->" '{print $1}'`
+ PEER1_NAME=`echo ${PEER1} | awk -F"|" '{print $1}'`
+ PEER1_IP=`echo ${PEER1} | awk -F"|" '{print $2}'`
+
+ PEER2=`echo ${CONNECTION} | awk -F"<->" '{print $2}'`
+ PEER2_NAME=`echo ${PEER2} | awk -F"|" '{print $1}'`
+ PEER2_IP=`echo ${PEER2} | awk -F"|" '{print $2}'`
+
+ # !!! if not created already..
+ # Create virtual node (jail) with given name and using
+ # JAIL_PATH as root directory for jail.
+
+ virtual_chain_create_peer_if_necessary ${PEER1_NAME}
+ virtual_chain_create_peer_if_necessary ${PEER2_NAME}
+
+ # create an interface for peer with the given peer IP. Get interface
+ # for future use; you will connect this interface to the other
+ # peers' (PEER2) interface.
+ virtual_chain_create_interface_with_ip ${PEER1_NAME} ${PEER1_IP}
+ PEER1_INTERFACE=${RET_INTERFACE}
+
+ # create an interface for peer with the given peer IP. Get interface
+ # for future use; you will connect this interface to the other
+ # peers' (PEER2) interface.
+ virtual_chain_create_interface_with_ip ${PEER2_NAME} ${PEER2_IP}
+ PEER2_INTERFACE=${RET_INTERFACE}
+
+ # Connect virtual interface to other interface. Syntax is :
+ # ngctl connect INTERFACE1: INTERFACE2: ether ether.
+
+ echo -n "Connecting ${PEER1_INTERFACE}:ether to ${PEER2_INTERFACE}:ether..."
+ ngctl connect ${PEER1_INTERFACE}: ${PEER2_INTERFACE}: ether ether \
+ || exit 1
+ echo "done"
+
+ done
+
+ # Executes static route add commands.
+ i=0
+ while [ $i != $STATIC_ROUTE_CNT ]; do
+ eval ROUTE=\${STATIC_ROUTE${i}}
+ ret=`${ROUTE}`
+ i=`expr $i + 1`
+ done
+
+ echo "Virtual WAN established successfully!"
+}
+
+virtual_chain_create_interface_with_ip() {
+
+ NODE_NAME=$1
+ NODE_IP=$2
+
+ # Create a ng_eiface object for virtual node. ng_eiface
+ # object has a hook that can be connected to one of bridge
+ # links. After creating interface get its automatically
+ # generated name for further usage.
+
+ echo "Creating eiface interface for virtual node ${NODE_NAME}."
+ ngctl mkpeer eiface ether ether
+ EIFACE=`ngctl l | grep ngeth | tail -n 1| awk '{print $2}'`
+ echo "Interface ${EIFACE} is created."
+
+ # Write name of the interface to temp file. Clean-up procedure
+ # will use this name to shutdown interface.
+
+ echo "interface ${EIFACE}" >> ${TEMP_FILE}
+
+ # Move virtual interface to virtual node. Note that Interface
+ # name will not be changed at the end of this movement. Moved
+ # interface can be seen at the output of ifconfig command in
+ # jail: 'jexec jailname ifconfig'
+
+ echo "Moving ${EIFACE} to ${NODE_NAME}"
+ ifconfig ${EIFACE} vnet ${NODE_NAME}
+
+ # Make lo0 interface localhost.
+ jexec ${NODE_NAME} ifconfig lo0 localhost
+
+ # Generate a random mac address for virtual interface. First
+ # three octets can be changed by user. Last three octets are
+ # generated randomly.
+ M4=`od -An -N2 -i /dev/random | sed -e 's/ //g' | \
+ awk '{ print $1 % 256 }'`
+ M5=`od -An -N2 -i /dev/random | sed -e 's/ //g' | \
+ awk '{ print $1 % 256 }'`
+ M6=`od -An -N2 -i /dev/random | sed -e 's/ //g' | \
+ awk '{ print $1 % 256 }'`
+
+ MAC=`printf ${MAC_PREFIX}:%02x:%02x:%02x ${M4} ${M5} ${M6}`
+
+ # Set the link address (mac address) of virtual interface in
+ # virtual node to randomly generated MAC.
+ echo "Setting MAC address of ${EIFACE} to '${MAC}'"
+ jexec ${NODE_NAME} ifconfig ${EIFACE} link $MAC
+
+ # Either IPv4 or IPv6 can be used in this script. Ifconfig
+ # IP setting syntax differs slightly for two IP versions.
+ # For version 4 'inet' keyword is used whereas for version 6
+ # 'inet6' is used. Below line tries to decide which IP version
+ # is given and sets IPVER to 'inet' or 'inet6'.
+
+ IPVER=`echo ${NODE_IP} | awk -F"." '{ split($4,last,"/"); \
+ if( NF==4 && $1>0 && $1<256 && $2<256 && $3<256 && \
+ last[1]<256) print "inet"; else print "inet6"}'`
+
+ # Set IP address of virtual interface in virtual node.
+ echo "Setting IP address of ${EIFACE} to '${NODE_IP}'"
+ jexec ${NODE_NAME} ifconfig ${EIFACE} ${IPVER} ${NODE_IP}
+
+ RET_INTERFACE=${EIFACE}
+}
+
+virtual_chain_create_peer_if_necessary() {
+
+ if ! grep -q $1 ${TEMP_FILE} ; then
+
+ echo -n "Creating virtual node (jail) ${1}..."
+ jail -c vnet name=${1} host.hostname=${1} \
+ path=${JAIL_PATH} persist
+ jexec ${1} sysctl -w net.inet.ip.forwarding=1
+ jexec ${1} sysctl -w net.inet6.ip6.forwarding=1
+ echo "done"
+
+ # Write name of the jail to temp file. Clean-up
+ # procedure will use this name to remove jail.
+
+ echo "node ${1}" >> ${TEMP_FILE}
+ fi
+
+}
+
+# Stop routine.
+virtual_chain_stop() {
+
+ if [ ! -e ${TEMP_FILE} ]; then
+ echo "Nothing to stop! ${TEMP_FILE}: temp file not found"
+ else
+
+ echo -n "Shutdown bridge interface.."
+ OBJECTS=`cat ${TEMP_FILE} | grep bridge | awk '{print $2}'`
+ for BRIDGE in ${OBJECTS}; do
+ ngctl shutdown ${BRIDGE}: >/dev/null 2>&1
+ done
+ echo "done"
+
+ echo -n "Shutdown all eiface interfaces..."
+ OBJECTS=`cat ${TEMP_FILE} | grep interface | awk '{print $2}'`
+ for INTERFACE in ${OBJECTS}; do
+ ngctl shutdown ${INTERFACE}: >/dev/null 2>&1
+ done
+ echo "done"
+
+ echo -n "Removing all jails..."
+ OBJECTS=`cat ${TEMP_FILE} | grep node | awk '{print $2}'`
+ for NODE in ${OBJECTS}; do
+ jail -r ${NODE}
+ done
+ echo "done"
+
+ echo "Removing tempfile ${TEMP_FILE}"
+ rm ${TEMP_FILE}
+ fi
+ echo "Virtual LAN objects removed successfully!"
+
+}
+
+virtual_chain_usage() {
+ echo "usage: $0 start [target_topology]"
+ echo " : $0 [ stop | help ]"
+}
+
+
+# Main entry point.
+
+case $# in
+ 1)
+ case $1 in
+ start)
+ echo -n "Creating default target topology:"
+ echo " ${TARGET_TOPOLOGY}"
+ virtual_chain_start
+ ;;
+ stop)
+
+ if [ ! -e ${TEMP_FILE} ]; then
+ echo -n "Noting to stop! ${TEMP_FILE}:"
+ echo " temp file not found"
+ else
+ virtual_chain_stop
+ fi
+ ;;
+ help)
+ virtual_chain_usage
+ exit 1
+ ;;
+ *)
+ virtual_chain_usage
+ exit 1
+
+ esac
+ ;;
+ 2)
+ case $1 in
+ start)
+ TARGET_TOPOLOGY=$2
+ echo -n "Creating target topology:"
+ echo "${TARGET_TOPOLOGY}"
+ virtual_chain_start
+ ;;
+ *)
+ virtual_chain_usage
+ exit 1
+ esac
+ ;;
+
+ *)
+ virtual_chain_usage
+ exit 1
+esac
+
diff --git a/share/examples/netgraph/virtual.lan b/share/examples/netgraph/virtual.lan
new file mode 100644
index 000000000000..2ec47aa08b51
--- /dev/null
+++ b/share/examples/netgraph/virtual.lan
@@ -0,0 +1,358 @@
+#!/bin/sh
+#
+# Copyright (c) 2010, Yavuz Gokirmak
+#
+# All rights reserved.
+#
+# This source code may be used, modified, copied, distributed, and
+# sold, in both source and binary form provided that the above
+# copyright and these terms are retained, verbatim, as the first
+# lines of this file. Under no circumstances is the author
+# responsible for the proper functioning of the software nor does
+# the author assume any responsibility for damages incurred with
+# its use.
+#
+#
+# This script adds virtual nodes to one of the physical interfaces
+# visible on your local area network (LAN). Virtual nodes seems real
+# to external observers.
+# If traceroute is executed to one of virtual nodes, the IP
+# address of the physical interface will not be seen in the output.
+# Virtual nodes are generated via jails and network connections are
+# established using ng_bridge(4) and ng_eiface(4) node types.
+#
+# To use this script:
+#
+# 0. Make your own copy of this example script.
+#
+# 1. Edit the definition of ${ETHER_INTF} as described below
+# to define your real interface connected to the LAN. Virtual nodes
+# will placed on the same physical network as this interface.
+#
+# 2. Edit the definition of ${TARGET_TOPOLOGY} to define your virtual
+# nodes. Virtual topology definition includes node names and their
+# IP address. Target top. syntax: ( node1|ip1/24 node2|ip2/24 ... )
+# Example 1: ( n1|122.122.122.12/24, n2|122.122.122.13/24 ...)
+# Example 2: ( n1|2001:b90::14a/125, n1|2001:b90::14b/125 ...)
+#
+# 3. Run this script with "start" as the command line argument.
+#
+# 4. Stop bridging by running this script with "stop" as the
+# command line argument.
+#
+# 5. This script uses a template file in order to carry information
+# between start and stop calls.
+# In the start call, the netgraph interfaces and jails are created.
+# At the stop phase, all created objects should be removed.
+# DO NOT delete the temporary file between the start and stop phases.
+#
+# To add virtual nodes for multiple independent LANs, create multiple
+# copies of this script with different variable definitions.
+#
+# Target Topology:
+#
+#
+# +---------------+ +---------------+ +---------------+
+# | n0 (vimage) | | n1 (vimage) | | nk (vimage) |
+# | | | | | |
+# | +-----------+ | | +-----------+ | | +-----------+ |
+# | | ngeth0 | | | | ngeth1 | | | | ngethk | |
+# | |(ng_eiface)| | | |(ng_eiface)| | | |(ng_eiface)| |
+# | +--+-----+--+ | | +--+-----+--+ | | +--+-----+--+ |
+# | |ether| | | |ether| | | |ether| |
+# | +--X--+ | | +--X--+ | | +---X-+ |
+# +-----+ +--------\------+ +--------\------+ +-------/-------+
+# |upper|----\ \ip_addr \ip_addr /ip_addr
+# +-+-----+--+ \ \ \ \
+# | em0 | \ +--------+ +-+ \
+# |(ng_ether)| +-----------+ \ \ \
+# +-+-----+--+ \ \ / \
+# |lower| +---------\ \ \ / /
+# +--X--+ / O--X--O O-X---O O---X-O O--X--O O---X---O
+# \ | |link0| |link1| |link2| |link3| |linkk+2|
+# \ / +-O-----O-O-----O-O-----O-O-----O-----O-------O-+
+# +---+ | |
+# | bridge (ng_bridge) |
+# +-----------------------------------------------+
+#
+#
+
+# Give the name of ethernet interface. Virtual nodes will be seen as
+# local neighbours of this interface.
+
+ETHER_INTF="em0"
+
+# List the names of virtual nodes and their IP addresses. Use ':'
+# character to separate node name from node IP address and netmask.
+
+TARGET_TOPOLOGY="c1|10.0.2.20/24 c2|10.0.2.21/24 c3|10.0.2.22/24"
+
+# MAC manufacturer prefix. This can be modified according to needs.
+MAC_PREFIX="00:1d:92"
+
+# Temporary file is important for proper execution of script.
+TEMP_FILE="/var/tmp/.virtual.lan.tmp"
+
+# Set root directory for jails to be created.
+JAIL_PATH="/usr/jails/node"
+
+
+####################################################################
+#### Nothing below this point should need to be modified. ####
+####################################################################
+
+
+# Start/restart routine.
+virtual_lan_start() {
+
+ # Load netgraph KLD's as necessary.
+
+ for KLD in ng_ether ng_bridge ng_eiface; do
+ if ! kldstat -v | grep -qw ${KLD}; then
+ echo -n "Loading ${KLD}.ko... "
+ kldload ${KLD} || exit 1
+ echo "done"
+ fi
+ done
+
+ # Reset all interfaces and jails. If temporary file can not be found
+ # script assumes that there is no previous configuration.
+
+ if [ ! -e ${TEMP_FILE} ]; then
+ echo "No previous configuration(${TEMP_FILE}) found to clean-up."
+ else
+ echo -n "Cleaning previous configuration..."
+ virtual_lan_stop
+ echo "done"
+ fi
+
+ # Create temporary file for usage. This file includes generated
+ # interface names and jail names. All bridges, interfaces and jails
+ # are written to file while created. In clean-up process written
+ # objects are cleaned (i.e. removed) from system.
+
+ if [ -e ${TEMP_FILE} ]; then
+ touch ${TEMP_FILE}
+ fi
+
+ echo -n "Verifying ethernet interface existence..."
+ # Verify ethernet interface exist.
+ if ! ngctl info ${ETHER_INTF}: >/dev/null 2>&1; then
+ echo "Error: interface ${ETHER_INTF} does not exist"
+ exit 1
+ fi
+ ifconfig ${ETHER_INTF} up || exit 1
+ echo "done"
+
+ # Get current number of bridge interfaces in the system. This number
+ # is used to create a name for new bridge.
+ BRIDGE_COUNT=`ngctl l | grep bridge | wc -l | sed -e "s/ //g"`
+ BRIDGE_NAME="bridge${BRIDGE_COUNT}"
+
+ # Create new ng_bridge(4) node and attach it to the ethernet interface.
+ # Connect ng_ether:lower hook to bridge:link0 when creating bridge and
+ # connect ng_ether:upper hook to bridge:link1 after bridge name is set.
+
+ echo "Creating bridge interface: ${BRIDGE_NAME}..."
+ ngctl mkpeer ${ETHER_INTF}: bridge lower link0 || exit 1
+ ngctl name ${ETHER_INTF}:lower ${BRIDGE_NAME} || exit 1
+ ngctl connect ${ETHER_INTF}: ${BRIDGE_NAME}: upper link1 || exit 1
+ echo "Bridge ${BRIDGE_NAME} is created and ${ETHER_INTF} is connected."
+
+ # In the above code block two hooks are connected to bridge interface,
+ # therefore LINKNUM is set to 2 indicating total number of connected
+ # hooks on the bridge interface.
+ LINKNUM=2
+
+ # Write name of the bridge to temp file. Clean-up procedure will use
+ # this name to shutdown bridge interface.
+ echo "bridge ${BRIDGE_NAME}" > ${TEMP_FILE}
+
+
+ # Attach other interfaces as well.
+ for NODE in ${TARGET_TOPOLOGY}; do
+
+ # Virtual nodes are defined in TARGET_TOPOLOGY variable. They
+ # have the form of 'nodeName|IPaddr'. Below two lines split
+ # node definition to get node name and node IP.
+
+ NODE_NAME=`echo ${NODE} | awk -F"|" '{print $1}'`
+ NODE_IP=`echo ${NODE} | awk -F"|" '{print $2}'`
+
+ # Create virtual node (jail) with given name and using
+ # JAIL_PATH as root directory for jail.
+
+ echo -n "Creating virtual node (jail) ${NODE_NAME}..."
+ jail -c vnet name=${NODE_NAME} host.hostname=${NODE_NAME} \
+ path=${JAIL_PATH} persist
+ echo "done"
+
+ # Write name of the jail to temp file. Clean-up procedure will
+ # use this name to remove jail.
+
+ echo "node ${NODE_NAME}" >> ${TEMP_FILE}
+
+ # Create a ng_eiface object for virtual node. ng_eiface
+ # object has a hook that can be connected to one of bridge
+ # links. After creating interface get its automatically
+ # generated name for further usage.
+
+ echo "Creating eiface interface for virtual node ${NODE_NAME}."
+ ngctl mkpeer eiface ether ether
+ EIFACE=`ngctl l | grep ngeth | tail -n 1| awk '{print $2}'`
+ echo "Interface ${EIFACE} is created."
+
+ # Write name of the interface to temp file. Clean-up procedure
+ # will use this name to shutdown interface.
+
+ echo "interface ${EIFACE}" >> ${TEMP_FILE}
+
+ # Move virtual interface to virtual node. Note that Interface
+ # name will not be changed at the end of this movement. Moved
+ # interface can be seen at the output of ifconfig command in
+ # jail: 'jexec jailname ifconfig'
+
+ echo "Moving ${EIFACE} to ${NODE_NAME}"
+ ifconfig ${EIFACE} vnet ${NODE_NAME}
+
+ # Make lo0 interface localhost.
+ jexec ${NODE_NAME} ifconfig lo0 localhost
+
+ # Generate a random mac address for virtual interface. First
+ # three octets can be changed by user. Last three octets are
+ # generated randomly.
+ M4=`od -An -N2 -i /dev/random | sed -e 's/ //g' | \
+ awk '{ print $1 % 256 }'`
+ M5=`od -An -N2 -i /dev/random | sed -e 's/ //g' | \
+ awk '{ print $1 % 256 }'`
+ M6=`od -An -N2 -i /dev/random | sed -e 's/ //g' | \
+ awk '{ print $1 % 256 }'`
+
+ MAC=`printf ${MAC_PREFIX}:%02x:%02x:%02x ${M4} ${M5} ${M6}`
+
+ # Set the link address (mac address) of virtual interface in
+ # virtual node to randomly generated MAC.
+ echo "Setting MAC address of ${EIFACE} to '${MAC}'"
+ jexec ${NODE_NAME} ifconfig ${EIFACE} link $MAC
+
+ # Either IPv4 or IPv6 can be used in this script. Ifconfig
+ # IP setting syntax differs slightly for two IP versions.
+ # For version 4 'inet' keyword is used whereas for version 6
+ # 'inet6' is used. Below line tries to decide which IP version
+ # is given and sets IPVER to 'inet' or 'inet6'.
+
+ IPVER=`echo ${NODE_IP} | awk -F"." '{ split($4,last,"/"); \
+ if( NF==4 && $1>0 && $1<256 && $2<256 && $3<256 && \
+ last[1]<256) print "inet"; else print "inet6"}'`
+
+ # Set IP address of virtual interface in virtual node.
+ echo "Setting IP address of ${EIFACE} to '${NODE_IP}'"
+ jexec ${NODE_NAME} ifconfig ${EIFACE} ${IPVER} ${NODE_IP}
+
+ # Connect virtual interface to bridge interface. Syntax is :
+ # ngctl connect INTERFACE: BRIDGE: INTERFACE_HOOK EMPTY_LINK.
+ # Interface has one hook named 'ether' and below line connects
+ # ether hook to bridge's first unconnected link.
+
+ echo -n "Connecting ${EIFACE}:ether to ${BRIDGE_NAME}:link${LINKNUM}..."
+ ngctl connect ${EIFACE}: ${BRIDGE_NAME}: ether link${LINKNUM} \
+ || exit 1
+ echo "done"
+
+ # Now, bridge has one more connected link thus link count is
+ # incremented.
+ LINKNUM=`expr ${LINKNUM} + 1`
+ done
+ echo "Virtual LAN established successfully!"
+
+}
+
+# Stop routine.
+virtual_lan_stop() {
+
+ if [ ! -e ${TEMP_FILE} ]; then
+ echo "Nothing to stop! ${TEMP_FILE}: temp file not found"
+ else
+
+ echo -n "Shutdown bridge interface.."
+ OBJECTS=`cat ${TEMP_FILE} | grep bridge | awk '{print $2}'`
+ for BRIDGE in ${OBJECTS}; do
+ ngctl shutdown ${BRIDGE}: >/dev/null 2>&1
+ done
+ echo "done"
+
+ echo -n "Shutdown all eiface interfaces..."
+ OBJECTS=`cat ${TEMP_FILE} | grep interface | awk '{print $2}'`
+ for INTERFACE in ${OBJECTS}; do
+ ngctl shutdown ${INTERFACE}: >/dev/null 2>&1
+ done
+ echo "done"
+
+ echo -n "Removing all jails..."
+ OBJECTS=`cat ${TEMP_FILE} | grep node | awk '{print $2}'`
+ for NODE in ${OBJECTS}; do
+ jail -r ${NODE}
+ done
+ echo "done"
+
+ echo "Removing tempfile ${TEMP_FILE}"
+ rm ${TEMP_FILE}
+ fi
+ echo "Virtual LAN objects removed successfully!"
+
+}
+
+virtual_lan_usage() {
+ echo "usage: $0 start [target_topology]"
+ echo " : $0 [ stop | help ]"
+}
+
+
+# Main entry point.
+
+case $# in
+ 1)
+ case $1 in
+ start)
+ echo -n "Creating default target topology:"
+ echo " ${TARGET_TOPOLOGY}"
+ virtual_lan_start
+ ;;
+ stop)
+
+ if [ ! -e ${TEMP_FILE} ]; then
+ echo -n "Noting to stop! ${TEMP_FILE}:"
+ echo " temp file not found"
+ else
+ virtual_lan_stop
+ fi
+ ;;
+ help)
+ virtual_lan_usage
+ exit 1
+ ;;
+ *)
+ virtual_lan_usage
+ exit 1
+
+ esac
+ ;;
+ 2)
+ case $1 in
+ start)
+ TARGET_TOPOLOGY=$2
+ echo -n "Creating target topology:"
+ echo "${TARGET_TOPOLOGY}"
+ virtual_lan_start
+ ;;
+ *)
+ virtual_lan_usage
+ exit 1
+ esac
+ ;;
+
+ *)
+ virtual_lan_usage
+ exit 1
+esac
+