17879db76SDevin Teske#!/bin/sh 27879db76SDevin Teske#- 37879db76SDevin Teske# Copyright (c) 2016 Devin Teske 47879db76SDevin Teske# All rights reserved. 57879db76SDevin Teske# 67879db76SDevin Teske# Redistribution and use in source and binary forms, with or without 77879db76SDevin Teske# modification, are permitted provided that the following conditions 87879db76SDevin Teske# are met: 97879db76SDevin Teske# 1. Redistributions of source code must retain the above copyright 107879db76SDevin Teske# notice, this list of conditions and the following disclaimer. 117879db76SDevin Teske# 2. Redistributions in binary form must reproduce the above copyright 127879db76SDevin Teske# notice, this list of conditions and the following disclaimer in the 137879db76SDevin Teske# documentation and/or other materials provided with the distribution. 147879db76SDevin Teske# 157879db76SDevin Teske# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 167879db76SDevin Teske# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 177879db76SDevin Teske# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 187879db76SDevin Teske# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 197879db76SDevin Teske# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 207879db76SDevin Teske# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 217879db76SDevin Teske# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 227879db76SDevin Teske# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 237879db76SDevin Teske# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 247879db76SDevin Teske# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 257879db76SDevin Teske# SUCH DAMAGE. 267879db76SDevin Teske# 277879db76SDevin Teske# $FreeBSD$ 287879db76SDevin Teske# 297879db76SDevin Teske############################################################ IDENT(1) 307879db76SDevin Teske# 317879db76SDevin Teske# $Title: netgraph(4) management script for vnet jails $ 327879db76SDevin Teske# 337879db76SDevin Teske############################################################ INFORMATION 347879db76SDevin Teske# 357879db76SDevin Teske# Use this tool with jail.conf(5) (or rc.conf(5) ``legacy'' configuration) to 36626ddc51SDevin Teske# manage `vnet' interfaces for jails. Designed to automate the creation of vnet 37626ddc51SDevin Teske# interface(s) during jail `prestart' and destroy said interface(s) during jail 38626ddc51SDevin Teske# `poststop'. 39626ddc51SDevin Teske# 40626ddc51SDevin Teske# In jail.conf(5) format: 417879db76SDevin Teske# 427879db76SDevin Teske# ### BEGIN EXCERPT ### 437879db76SDevin Teske# 447879db76SDevin Teske# xxx { 457879db76SDevin Teske# host.hostname = "xxx.yyy"; 467879db76SDevin Teske# path = "/vm/xxx"; 477879db76SDevin Teske# 487879db76SDevin Teske# # 497879db76SDevin Teske# # NB: Below 2-lines required 507879db76SDevin Teske# # NB: The number of ngN_xxx interfaces should match the number of 517879db76SDevin Teske# # arguments given to `jng bridge xxx' in exec.prestart value. 527879db76SDevin Teske# # 537879db76SDevin Teske# vnet; 547879db76SDevin Teske# vnet.interface = "ng0_xxx ng1_xxx ..."; 557879db76SDevin Teske# 567879db76SDevin Teske# exec.clean; 577879db76SDevin Teske# exec.system_user = "root"; 587879db76SDevin Teske# exec.jail_user = "root"; 597879db76SDevin Teske# 607879db76SDevin Teske# # 617879db76SDevin Teske# # NB: Below 2-lines required 627879db76SDevin Teske# # NB: The number of arguments after `jng bridge xxx' should match 637879db76SDevin Teske# # the number of ngN_xxx arguments in vnet.interface value. 647879db76SDevin Teske# # 657879db76SDevin Teske# exec.prestart += "jng bridge xxx em0 em1 ..."; 667879db76SDevin Teske# exec.poststop += "jng shutdown xxx"; 677879db76SDevin Teske# 687879db76SDevin Teske# # Standard recipe 697879db76SDevin Teske# exec.start += "/bin/sh /etc/rc"; 707879db76SDevin Teske# exec.stop = "/bin/sh /etc/rc.shutdown"; 717879db76SDevin Teske# exec.consolelog = "/var/log/jail_xxx_console.log"; 727879db76SDevin Teske# mount.devfs; 737879db76SDevin Teske# 747879db76SDevin Teske# # Optional (default off) 757879db76SDevin Teske# #allow.mount; 767879db76SDevin Teske# #allow.set_hostname = 1; 777879db76SDevin Teske# #allow.sysvipc = 1; 787879db76SDevin Teske# #devfs_ruleset = "11"; # rule to unhide bpf for DHCP 797879db76SDevin Teske# } 807879db76SDevin Teske# 817879db76SDevin Teske# ### END EXCERPT ### 827879db76SDevin Teske# 837879db76SDevin Teske# In rc.conf(5) ``legacy'' format (used when /etc/jail.conf does not exist): 847879db76SDevin Teske# 857879db76SDevin Teske# ### BEGIN EXCERPT ### 867879db76SDevin Teske# 877879db76SDevin Teske# jail_enable="YES" 887879db76SDevin Teske# jail_list="xxx" 897879db76SDevin Teske# 907879db76SDevin Teske# # 917879db76SDevin Teske# # Global presets for all jails 927879db76SDevin Teske# # 937879db76SDevin Teske# jail_devfs_enable="YES" # mount devfs 947879db76SDevin Teske# 957879db76SDevin Teske# # 967879db76SDevin Teske# # Global options (default off) 977879db76SDevin Teske# # 987879db76SDevin Teske# #jail_mount_enable="YES" # mount /etc/fstab.{name} 997879db76SDevin Teske# #jail_set_hostname_allow="YES" # Allow hostname to change 1007879db76SDevin Teske# #jail_sysvipc_allow="YES" # Allow SysV Interprocess Comm. 1017879db76SDevin Teske# 1027879db76SDevin Teske# # xxx 1037879db76SDevin Teske# jail_xxx_hostname="xxx.shxd.cx" # hostname 1047879db76SDevin Teske# jail_xxx_rootdir="/vm/xxx" # root directory 1057879db76SDevin Teske# jail_xxx_vnet_interfaces="ng0_xxx ng1xxx ..." # vnet interface(s) 1067879db76SDevin Teske# jail_xxx_exec_prestart0="jng bridge xxx em0 em1 ..." # bridge interface(s) 1077879db76SDevin Teske# jail_xxx_exec_poststop0="jng shutdown xxx" # destroy interface(s) 1087879db76SDevin Teske# #jail_xxx_mount_enable="YES" # mount /etc/fstab.xxx 1097879db76SDevin Teske# #jail_xxx_devfs_ruleset="11" # rule to unhide bpf for DHCP 1107879db76SDevin Teske# 1117879db76SDevin Teske# ### END EXCERPT ### 1127879db76SDevin Teske# 1137879db76SDevin Teske# Note that the legacy rc.conf(5) format is converted to 1147879db76SDevin Teske# /var/run/jail.{name}.conf by /etc/rc.d/jail if jail.conf(5) is missing. 1157879db76SDevin Teske# 1167879db76SDevin Teske# ASIDE: dhclient(8) inside a vnet jail... 1177879db76SDevin Teske# 1187879db76SDevin Teske# To allow dhclient(8) to work inside a vnet jail, make sure the following 1197879db76SDevin Teske# appears in /etc/devfs.rules (which should be created if it doesn't exist): 1207879db76SDevin Teske# 1217879db76SDevin Teske# [devfsrules_jail=11] 1227879db76SDevin Teske# add include $devfsrules_hide_all 1237879db76SDevin Teske# add include $devfsrules_unhide_basic 1247879db76SDevin Teske# add include $devfsrules_unhide_login 125517ca8c0SDevin Teske# add path 'bpf*' unhide 1267879db76SDevin Teske# 1277879db76SDevin Teske# And set ether devfs.ruleset="11" (jail.conf(5)) or 1287879db76SDevin Teske# jail_{name}_devfs_ruleset="11" (rc.conf(5)). 1297879db76SDevin Teske# 1307879db76SDevin Teske# NB: While this tool can't create every type of desirable topology, it should 1317879db76SDevin Teske# handle most setups, minus some which considered exotic or purpose-built. 1327879db76SDevin Teske# 1337879db76SDevin Teske############################################################ GLOBALS 1347879db76SDevin Teske 1357879db76SDevin Teskepgm="${0##*/}" # Program basename 1367879db76SDevin Teske 1377879db76SDevin Teske# 1387879db76SDevin Teske# Global exit status 1397879db76SDevin Teske# 1407879db76SDevin TeskeSUCCESS=0 1417879db76SDevin TeskeFAILURE=1 1427879db76SDevin Teske 1437879db76SDevin Teske############################################################ FUNCTIONS 1447879db76SDevin Teske 1457879db76SDevin Teskeusage() 1467879db76SDevin Teske{ 1477879db76SDevin Teske local action usage descr 1487879db76SDevin Teske exec >&2 1497879db76SDevin Teske echo "Usage: $pgm action [arguments]" 1507879db76SDevin Teske echo "Actions:" 1517879db76SDevin Teske for action in \ 1527879db76SDevin Teske bridge \ 1537879db76SDevin Teske graph \ 1547879db76SDevin Teske show \ 1557879db76SDevin Teske show1 \ 1567879db76SDevin Teske shutdown \ 157*39d9a52dSDevin Teske stats \ 1587879db76SDevin Teske ; do 1597879db76SDevin Teske eval usage=\"\$jng_${action}_usage\" 1607879db76SDevin Teske [ "$usage" ] || continue 1617879db76SDevin Teske eval descr=\"\$jng_${action}_descr\" 1627879db76SDevin Teske printf "\t%s\n\t\t%s\n" "$usage" "$descr" 1637879db76SDevin Teske done 1647879db76SDevin Teske exit $FAILURE 1657879db76SDevin Teske} 1667879db76SDevin Teske 1677879db76SDevin Teskeaction_usage() 1687879db76SDevin Teske{ 1697879db76SDevin Teske local usage action="$1" 1707879db76SDevin Teske eval usage=\"\$jng_${action}_usage\" 1717879db76SDevin Teske echo "Usage: $pgm $usage" >&2 1727879db76SDevin Teske exit $FAILURE 1737879db76SDevin Teske} 1747879db76SDevin Teske 1757879db76SDevin Teskemustberoot_to_continue() 1767879db76SDevin Teske{ 1777879db76SDevin Teske if [ "$( id -u )" -ne 0 ]; then 1787879db76SDevin Teske echo "Must run as root!" >&2 1797879db76SDevin Teske exit $FAILURE 1807879db76SDevin Teske fi 1817879db76SDevin Teske} 1827879db76SDevin Teske 1837879db76SDevin Teskejng_bridge_usage="bridge [-b BRIDGE_NAME] NAME interface0 [interface1 ...]" 1847879db76SDevin Teskejng_bridge_descr="Create ng0_NAME [ng1_NAME ...]" 1857879db76SDevin Teskejng_bridge() 1867879db76SDevin Teske{ 1877879db76SDevin Teske local OPTIND=1 OPTARG flag bridge=bridge 1887879db76SDevin Teske while getopts b: flag; do 1897879db76SDevin Teske case "$flag" in 1907879db76SDevin Teske b) bridge="$OPTARG" 1917879db76SDevin Teske [ "$bridge" ] || action_usage bridge ;; # NOTREACHED 1927879db76SDevin Teske *) action_usage bridge # NOTREACHED 1937879db76SDevin Teske esac 1947879db76SDevin Teske done 1957879db76SDevin Teske shift $(( $OPTIND - 1 )) 1967879db76SDevin Teske 1977879db76SDevin Teske local name="$1" 1987879db76SDevin Teske [ "${name:-x}" = "${name#*[!0-9a-zA-Z_]}" -a $# -gt 1 ] || 1997879db76SDevin Teske action_usage bridge # NOTREACHED 2007879db76SDevin Teske shift 1 # name 2017879db76SDevin Teske 2027879db76SDevin Teske mustberoot_to_continue 2037879db76SDevin Teske 2047879db76SDevin Teske local iface iface_devid eiface eiface_devid 2057879db76SDevin Teske local new num quad i=0 2067879db76SDevin Teske for iface in $*; do 2077879db76SDevin Teske 2087879db76SDevin Teske # 0. Make sure the interface doesn't exist already 2097879db76SDevin Teske eiface=ng${i}_$name 2107879db76SDevin Teske ngctl msg "$eiface:" getifname > /dev/null 2>&1 && continue 2117879db76SDevin Teske 2127879db76SDevin Teske # 1. Bring the interface up 2137879db76SDevin Teske ifconfig $iface up || return 2147879db76SDevin Teske 2157879db76SDevin Teske # 2. Set promiscuous mode and don't overwrite src addr 2167879db76SDevin Teske ngctl msg $iface: setpromisc 1 || return 2177879db76SDevin Teske ngctl msg $iface: setautosrc 0 || return 2187879db76SDevin Teske 2197879db76SDevin Teske # 3. Make sure the interface has been bridged 2207879db76SDevin Teske if ! ngctl info ${iface}bridge: > /dev/null 2>&1; then 2217879db76SDevin Teske ngctl mkpeer $iface: bridge lower link0 || return 2227879db76SDevin Teske ngctl connect $iface: $iface:lower upper link1 || 2237879db76SDevin Teske return 2247879db76SDevin Teske ngctl name $iface:lower ${iface}bridge || return 2257879db76SDevin Teske fi 2267879db76SDevin Teske 2277879db76SDevin Teske # 3.5. Optionally create a secondary bridge 2287879db76SDevin Teske if [ "$bridge" != "bridge" ] && 2297879db76SDevin Teske ! ngctl info "$iface$bridge:" > /dev/null 2>&1 2307879db76SDevin Teske then 2317879db76SDevin Teske num=2 2327879db76SDevin Teske while ngctl msg ${iface}bridge: getstats $num \ 2337879db76SDevin Teske > /dev/null 2>&1 2347879db76SDevin Teske do 2357879db76SDevin Teske num=$(( $num + 1 )) 2367879db76SDevin Teske done 2377879db76SDevin Teske ngctl mkpeer $iface:lower bridge link$num link1 || 2387879db76SDevin Teske return 2397879db76SDevin Teske ngctl name ${iface}bridge:link$num "$iface$bridge" || 2407879db76SDevin Teske return 2417879db76SDevin Teske fi 2427879db76SDevin Teske 2437879db76SDevin Teske # 4. Create a new interface to the bridge 2447879db76SDevin Teske num=2 2457879db76SDevin Teske while ngctl msg "$iface$bridge:" getstats $num > /dev/null 2>&1 2467879db76SDevin Teske do 2477879db76SDevin Teske num=$(( $num + 1 )) 2487879db76SDevin Teske done 2497879db76SDevin Teske ngctl mkpeer "$iface$bridge:" eiface link$num ether || return 2507879db76SDevin Teske 2517879db76SDevin Teske # 5. Rename the new interface 2527879db76SDevin Teske while [ ${#eiface} -gt 15 ]; do # OS limitation 2537879db76SDevin Teske eiface=${eiface%?} 2547879db76SDevin Teske done 2557879db76SDevin Teske new=$( set -- `ngctl show -n "$iface$bridge:link$num"` && 2567879db76SDevin Teske echo $2 ) || return 2577879db76SDevin Teske ngctl name "$iface$bridge:link$num" $eiface || return 2587879db76SDevin Teske ifconfig $new name $eiface || return 259f2c27deaSDevin Teske ifconfig $eiface up || return 2607879db76SDevin Teske 2617879db76SDevin Teske # 2627879db76SDevin Teske # 6. Set the MAC address of the new interface using a sensible 2637879db76SDevin Teske # algorithm to prevent conflicts on the network. 2647879db76SDevin Teske # 26578a38b8fSDevin Teske # The formula I'm using is ``NP:SS:SS:II:II:II'' where: 26678a38b8fSDevin Teske # + N denotes 4 bits used as a counter to support branching 26778a38b8fSDevin Teske # each parent interface up to 15 times under the same jail 26878a38b8fSDevin Teske # name (see S below). 2697879db76SDevin Teske # + P denotes the special nibble whose value, if one of 2707879db76SDevin Teske # 2, 6, A, or E (but usually 2) denotes a privately 2717879db76SDevin Teske # administered MAC address (while remaining routable). 27278a38b8fSDevin Teske # + S denotes 16 bits, the sum(1) value of the jail name. 2737879db76SDevin Teske # + I denotes bits that are inherited from parent interface. 2747879db76SDevin Teske # 2757879db76SDevin Teske # The S bits are a CRC-16 checksum of NAME, allowing the jail 2767879db76SDevin Teske # to change link numbers in ng_bridge(4) without affecting the 27778a38b8fSDevin Teske # MAC address. Meanwhile, if... 27878a38b8fSDevin Teske # + the jail NAME changes (e.g., it was duplicated and given 27978a38b8fSDevin Teske # a new name with no other changes) 28078a38b8fSDevin Teske # + the underlying network interface changes 28178a38b8fSDevin Teske # + the jail is moved to another host 28278a38b8fSDevin Teske # the MAC address will be recalculated to a new, similarly 28378a38b8fSDevin Teske # unique value preventing conflict. 2847879db76SDevin Teske # 2857879db76SDevin Teske iface_devid=$( ifconfig $iface ether | awk '/ether/,$0=$2' ) 28678a38b8fSDevin Teske eiface_devid=${iface_devid#??:??:??} 2877879db76SDevin Teske num=$( set -- `echo -n $name | sum` && echo $1 ) 2887879db76SDevin Teske quad=$(( $num & 15 )) 2897879db76SDevin Teske case "$quad" in 2907879db76SDevin Teske 10) quad=a ;; 11) quad=b ;; 12) quad=c ;; 2917879db76SDevin Teske 13) quad=d ;; 14) quad=e ;; 15) quad=f ;; 2927879db76SDevin Teske esac 29378a38b8fSDevin Teske eiface_devid=$quad$eiface_devid 2947879db76SDevin Teske num=$(( $num >> 4 )) 2957879db76SDevin Teske quad=$(( $num & 15 )) 2967879db76SDevin Teske case "$quad" in 2977879db76SDevin Teske 10) quad=a ;; 11) quad=b ;; 12) quad=c ;; 2987879db76SDevin Teske 13) quad=d ;; 14) quad=e ;; 15) quad=f ;; 2997879db76SDevin Teske esac 3007879db76SDevin Teske eiface_devid=$quad$eiface_devid 3017879db76SDevin Teske num=$(( $num >> 4 )) 3027879db76SDevin Teske quad=$(( $num & 15 )) 3037879db76SDevin Teske case "$quad" in 3047879db76SDevin Teske 10) quad=a ;; 11) quad=b ;; 12) quad=c ;; 3057879db76SDevin Teske 13) quad=d ;; 14) quad=e ;; 15) quad=f ;; 3067879db76SDevin Teske esac 30778a38b8fSDevin Teske eiface_devid=$quad:$eiface_devid 30878a38b8fSDevin Teske num=$(( $num >> 4 )) 30978a38b8fSDevin Teske quad=$(( $num & 15 )) 31078a38b8fSDevin Teske case "$quad" in 31178a38b8fSDevin Teske 10) quad=a ;; 11) quad=b ;; 12) quad=c ;; 31278a38b8fSDevin Teske 13) quad=d ;; 14) quad=e ;; 15) quad=f ;; 31378a38b8fSDevin Teske esac 31443a45064SDevin Teske case "$iface_devid" in 31543a45064SDevin Teske ?2:*) eiface_devid=a:$quad$eiface_devid ;; 31643a45064SDevin Teske *) eiface_devid=2:$quad$eiface_devid 31743a45064SDevin Teske esac 31878a38b8fSDevin Teske eval num=\$_${iface}_num 31978a38b8fSDevin Teske if [ "$num" ]; then 32078a38b8fSDevin Teske num=$(( $num + 1 )) 32178a38b8fSDevin Teske eval _${iface}_num=$num 32278a38b8fSDevin Teske else 32378a38b8fSDevin Teske num=0 32478a38b8fSDevin Teske local _${iface}_num=$num 32578a38b8fSDevin Teske fi 3267879db76SDevin Teske quad=$(( $num & 15 )) 3277879db76SDevin Teske case "$quad" in 3287879db76SDevin Teske 10) quad=a ;; 11) quad=b ;; 12) quad=c ;; 3297879db76SDevin Teske 13) quad=d ;; 14) quad=e ;; 15) quad=f ;; 3307879db76SDevin Teske esac 3317879db76SDevin Teske eiface_devid=$quad$eiface_devid 3327879db76SDevin Teske ifconfig $eiface ether $eiface_devid > /dev/null 2>&1 3337879db76SDevin Teske 3347879db76SDevin Teske i=$(( $i + 1 )) # on to next ng{i}_name 3357879db76SDevin Teske done # for iface 3367879db76SDevin Teske} 3377879db76SDevin Teske 3387879db76SDevin Teskejng_graph_usage="graph [-f] [-T type] [-o output]" 3397879db76SDevin Teskejng_graph_descr="Generate network graph (default output is \`jng.svg')" 3407879db76SDevin Teskejng_graph() 3417879db76SDevin Teske{ 3427879db76SDevin Teske local OPTIND=1 OPTARG flag 3437879db76SDevin Teske local output=jng.svg output_type= force= 3447879db76SDevin Teske while getopts fo:T: flag; do 3457879db76SDevin Teske case "$flag" in 3467879db76SDevin Teske f) force=1 ;; 3477879db76SDevin Teske o) output="$OPTARG" ;; 3487879db76SDevin Teske T) output_type="$OPTARG" ;; 3497879db76SDevin Teske *) action_usage graph # NOTREACHED 3507879db76SDevin Teske esac 3517879db76SDevin Teske done 3527879db76SDevin Teske shift $(( $OPTIND - 1 )) 3537879db76SDevin Teske [ $# -eq 0 -a "$output" ] || action_usage graph # NOTREACHED 3547879db76SDevin Teske mustberoot_to_continue 3557879db76SDevin Teske if [ -e "$output" -a ! "$force" ]; then 3567879db76SDevin Teske echo "$output: Already exists (use \`-f' to overwrite)" >&2 3577879db76SDevin Teske return $FAILURE 3587879db76SDevin Teske fi 3597879db76SDevin Teske if [ ! "$output_type" ]; then 3607879db76SDevin Teske local valid suffix 3617879db76SDevin Teske valid=$( dot -Txxx 2>&1 ) 3627879db76SDevin Teske for suffix in ${valid##*:}; do 3637879db76SDevin Teske [ "$output" != "${output%.$suffix}" ] || continue 3647879db76SDevin Teske output_type=$suffix 3657879db76SDevin Teske break 3667879db76SDevin Teske done 3677879db76SDevin Teske fi 3687879db76SDevin Teske ngctl dot | dot ${output_type:+-T "$output_type"} -o "$output" 3697879db76SDevin Teske} 3707879db76SDevin Teske 3717879db76SDevin Teskejng_show_usage="show" 3727879db76SDevin Teskejng_show_descr="List possible NAME values for \`show NAME'" 3737879db76SDevin Teskejng_show1_usage="show NAME" 3747879db76SDevin Teskejng_show1_descr="Lists ng0_NAME [ng1_NAME ...]" 3757879db76SDevin Teskejng_show2_usage="show [NAME]" 3767879db76SDevin Teskejng_show() 3777879db76SDevin Teske{ 3787879db76SDevin Teske local OPTIND=1 OPTARG flag 3797879db76SDevin Teske while getopts "" flag; do 3807879db76SDevin Teske case "$flag" in 3817879db76SDevin Teske *) action_usage show2 # NOTREACHED 3827879db76SDevin Teske esac 3837879db76SDevin Teske done 3847879db76SDevin Teske shift $(( $OPTIND - 1 )) 3857879db76SDevin Teske mustberoot_to_continue 3867879db76SDevin Teske if [ $# -eq 0 ]; then 3877879db76SDevin Teske ngctl ls | awk '$4=="bridge",$0=$2' | 3887879db76SDevin Teske xargs -rn1 -Ibridge ngctl show bridge: | 3897879db76SDevin Teske awk 'sub(/^ng[[:digit:]]+_/, "", $2), $0 = $2' | 3907879db76SDevin Teske sort -u 3917879db76SDevin Teske return 3927879db76SDevin Teske fi 3937879db76SDevin Teske ngctl ls | awk -v name="$1" ' 3947879db76SDevin Teske match($2, /^ng[[:digit:]]+_/) && 3957879db76SDevin Teske substr($2, RSTART + RLENGTH) == name && 3967879db76SDevin Teske $4 == "eiface", $0 = $2 3977879db76SDevin Teske ' | sort 3987879db76SDevin Teske} 3997879db76SDevin Teske 4007879db76SDevin Teskejng_shutdown_usage="shutdown NAME" 4017879db76SDevin Teskejng_shutdown_descr="Shutdown ng0_NAME [ng1_NAME ...]" 4027879db76SDevin Teskejng_shutdown() 4037879db76SDevin Teske{ 4047879db76SDevin Teske local OPTIND=1 OPTARG flag 4057879db76SDevin Teske while getopts "" flag; do 4067879db76SDevin Teske case "$flag" in 4077879db76SDevin Teske *) action_usage shutdown # NOTREACHED 4087879db76SDevin Teske esac 4097879db76SDevin Teske done 4107879db76SDevin Teske shift $(( $OPTIND -1 )) 4117879db76SDevin Teske local name="$1" 4127879db76SDevin Teske [ "${name:-x}" = "${name#*[!0-9a-zA-Z_]}" -a $# -eq 1 ] || 4137879db76SDevin Teske action_usage shutdown # NOTREACHED 4147879db76SDevin Teske mustberoot_to_continue 4157879db76SDevin Teske jng_show "$name" | xargs -rn1 -I eiface ngctl shutdown eiface: 4167879db76SDevin Teske} 4177879db76SDevin Teske 418*39d9a52dSDevin Teskejng_stats_usage="stats NAME" 419*39d9a52dSDevin Teskejng_stats_descr="Show ng_bridge link statistics for NAME interfaces" 420*39d9a52dSDevin Teskejng_stats() 421*39d9a52dSDevin Teske{ 422*39d9a52dSDevin Teske local OPTIND=1 OPTARG flag 423*39d9a52dSDevin Teske while getopts "" flag; do 424*39d9a52dSDevin Teske case "$flag" in 425*39d9a52dSDevin Teske *) action_usage stats # NOTREACHED 426*39d9a52dSDevin Teske esac 427*39d9a52dSDevin Teske done 428*39d9a52dSDevin Teske shift $(( $OPTIND -1 )) 429*39d9a52dSDevin Teske local name="$1" 430*39d9a52dSDevin Teske [ "${name:-x}" = "${name#*[!0-9a-zA-Z_]}" -a $# -eq 1 ] || 431*39d9a52dSDevin Teske action_usage stats # NOTREACHED 432*39d9a52dSDevin Teske mustberoot_to_continue 433*39d9a52dSDevin Teske for eiface in $( jng_show "$name" ); do 434*39d9a52dSDevin Teske echo "$eiface:" 435*39d9a52dSDevin Teske ngctl show $eiface: | awk ' 436*39d9a52dSDevin Teske $3 == "bridge" && $5 ~ /^link/ { 437*39d9a52dSDevin Teske bridge = $2 438*39d9a52dSDevin Teske link = substr($5, 5) 439*39d9a52dSDevin Teske system(sprintf("ngctl msg %s: getstats %u", 440*39d9a52dSDevin Teske bridge, link)) 441*39d9a52dSDevin Teske }' | fmt 2 | awk ' 442*39d9a52dSDevin Teske /=/ && fl = index($0, "=") { 443*39d9a52dSDevin Teske printf "%20s = %s\n", 444*39d9a52dSDevin Teske substr($0, 0, fl-1), 445*39d9a52dSDevin Teske substr($0, 0, fl+1) 446*39d9a52dSDevin Teske } 447*39d9a52dSDevin Teske ' # END-QUOTE 448*39d9a52dSDevin Teske done 449*39d9a52dSDevin Teske} 450*39d9a52dSDevin Teske 4517879db76SDevin Teske############################################################ MAIN 4527879db76SDevin Teske 4537879db76SDevin Teske# 4547879db76SDevin Teske# Command-line arguments 4557879db76SDevin Teske# 4567879db76SDevin Teskeaction="$1" 4577879db76SDevin Teske[ "$action" ] || usage # NOTREACHED 4587879db76SDevin Teske 4597879db76SDevin Teske# 4607879db76SDevin Teske# Validate action argument 4617879db76SDevin Teske# 4627879db76SDevin Teskeif [ "$BASH_VERSION" ]; then 4637879db76SDevin Teske type="$( type -t "jng_$action" )" || usage # NOTREACHED 4647879db76SDevin Teskeelse 4657879db76SDevin Teske type="$( type "jng_$action" 2> /dev/null )" || usage # NOTREACHED 4667879db76SDevin Teskefi 4677879db76SDevin Teskecase "$type" in 4687879db76SDevin Teske*function) 4697879db76SDevin Teske shift 1 # action 4707879db76SDevin Teske eval "jng_$action" \"\$@\" 4717879db76SDevin Teske ;; 4727879db76SDevin Teske*) usage # NOTREACHED 4737879db76SDevin Teskeesac 4747879db76SDevin Teske 4757879db76SDevin Teske################################################################################ 4767879db76SDevin Teske# END 4777879db76SDevin Teske################################################################################ 478