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# 287879db76SDevin Teske############################################################ IDENT(1) 297879db76SDevin Teske# 307879db76SDevin Teske# $Title: netgraph(4) management script for vnet jails $ 317879db76SDevin Teske# 327879db76SDevin Teske############################################################ INFORMATION 337879db76SDevin Teske# 347879db76SDevin Teske# Use this tool with jail.conf(5) (or rc.conf(5) ``legacy'' configuration) to 35626ddc51SDevin Teske# manage `vnet' interfaces for jails. Designed to automate the creation of vnet 36626ddc51SDevin Teske# interface(s) during jail `prestart' and destroy said interface(s) during jail 37626ddc51SDevin Teske# `poststop'. 38626ddc51SDevin Teske# 39626ddc51SDevin Teske# In jail.conf(5) format: 407879db76SDevin Teske# 417879db76SDevin Teske# ### BEGIN EXCERPT ### 427879db76SDevin Teske# 437879db76SDevin Teske# xxx { 447879db76SDevin Teske# host.hostname = "xxx.yyy"; 457879db76SDevin Teske# path = "/vm/xxx"; 467879db76SDevin Teske# 477879db76SDevin Teske# # 487879db76SDevin Teske# # NB: Below 2-lines required 497879db76SDevin Teske# # NB: The number of ngN_xxx interfaces should match the number of 507879db76SDevin Teske# # arguments given to `jng bridge xxx' in exec.prestart value. 517879db76SDevin Teske# # 527879db76SDevin Teske# vnet; 5330482552SDevin Teske# vnet.interface = ng0_xxx, ng1_xxx, ...; 547879db76SDevin Teske# 557879db76SDevin Teske# exec.clean; 567879db76SDevin Teske# exec.system_user = "root"; 577879db76SDevin Teske# exec.jail_user = "root"; 587879db76SDevin Teske# 597879db76SDevin Teske# # 607879db76SDevin Teske# # NB: Below 2-lines required 617879db76SDevin Teske# # NB: The number of arguments after `jng bridge xxx' should match 627879db76SDevin Teske# # the number of ngN_xxx arguments in vnet.interface value. 637879db76SDevin Teske# # 647879db76SDevin Teske# exec.prestart += "jng bridge xxx em0 em1 ..."; 657879db76SDevin Teske# exec.poststop += "jng shutdown xxx"; 667879db76SDevin Teske# 677879db76SDevin Teske# # Standard recipe 687879db76SDevin Teske# exec.start += "/bin/sh /etc/rc"; 695fda0d60SAndriy Gapon# exec.stop = "/bin/sh /etc/rc.shutdown jail"; 707879db76SDevin Teske# exec.consolelog = "/var/log/jail_xxx_console.log"; 717879db76SDevin Teske# mount.devfs; 727879db76SDevin Teske# 737879db76SDevin Teske# # Optional (default off) 747879db76SDevin Teske# #allow.mount; 757879db76SDevin Teske# #allow.set_hostname = 1; 767879db76SDevin Teske# #allow.sysvipc = 1; 777879db76SDevin Teske# #devfs_ruleset = "11"; # rule to unhide bpf for DHCP 787879db76SDevin Teske# } 797879db76SDevin Teske# 807879db76SDevin Teske# ### END EXCERPT ### 817879db76SDevin Teske# 827879db76SDevin Teske# In rc.conf(5) ``legacy'' format (used when /etc/jail.conf does not exist): 837879db76SDevin Teske# 847879db76SDevin Teske# ### BEGIN EXCERPT ### 857879db76SDevin Teske# 867879db76SDevin Teske# jail_enable="YES" 877879db76SDevin Teske# jail_list="xxx" 887879db76SDevin Teske# 897879db76SDevin Teske# # 907879db76SDevin Teske# # Global presets for all jails 917879db76SDevin Teske# # 927879db76SDevin Teske# jail_devfs_enable="YES" # mount devfs 937879db76SDevin Teske# 947879db76SDevin Teske# # 957879db76SDevin Teske# # Global options (default off) 967879db76SDevin Teske# # 977879db76SDevin Teske# #jail_mount_enable="YES" # mount /etc/fstab.{name} 987879db76SDevin Teske# #jail_set_hostname_allow="YES" # Allow hostname to change 997879db76SDevin Teske# #jail_sysvipc_allow="YES" # Allow SysV Interprocess Comm. 1007879db76SDevin Teske# 1017879db76SDevin Teske# # xxx 1027879db76SDevin Teske# jail_xxx_hostname="xxx.shxd.cx" # hostname 1037879db76SDevin Teske# jail_xxx_rootdir="/vm/xxx" # root directory 1047879db76SDevin Teske# jail_xxx_vnet_interfaces="ng0_xxx ng1xxx ..." # vnet interface(s) 1057879db76SDevin Teske# jail_xxx_exec_prestart0="jng bridge xxx em0 em1 ..." # bridge interface(s) 1067879db76SDevin Teske# jail_xxx_exec_poststop0="jng shutdown xxx" # destroy interface(s) 1077879db76SDevin Teske# #jail_xxx_mount_enable="YES" # mount /etc/fstab.xxx 1087879db76SDevin Teske# #jail_xxx_devfs_ruleset="11" # rule to unhide bpf for DHCP 1097879db76SDevin Teske# 1107879db76SDevin Teske# ### END EXCERPT ### 1117879db76SDevin Teske# 1127879db76SDevin Teske# Note that the legacy rc.conf(5) format is converted to 1137879db76SDevin Teske# /var/run/jail.{name}.conf by /etc/rc.d/jail if jail.conf(5) is missing. 1147879db76SDevin Teske# 1157879db76SDevin Teske# ASIDE: dhclient(8) inside a vnet jail... 1167879db76SDevin Teske# 1177879db76SDevin Teske# To allow dhclient(8) to work inside a vnet jail, make sure the following 1187879db76SDevin Teske# appears in /etc/devfs.rules (which should be created if it doesn't exist): 1197879db76SDevin Teske# 1207879db76SDevin Teske# [devfsrules_jail=11] 1217879db76SDevin Teske# add include $devfsrules_hide_all 1227879db76SDevin Teske# add include $devfsrules_unhide_basic 1237879db76SDevin Teske# add include $devfsrules_unhide_login 124517ca8c0SDevin Teske# add path 'bpf*' unhide 1257879db76SDevin Teske# 1267879db76SDevin Teske# And set ether devfs.ruleset="11" (jail.conf(5)) or 1277879db76SDevin Teske# jail_{name}_devfs_ruleset="11" (rc.conf(5)). 1287879db76SDevin Teske# 1297879db76SDevin Teske# NB: While this tool can't create every type of desirable topology, it should 1307879db76SDevin Teske# handle most setups, minus some which considered exotic or purpose-built. 1317879db76SDevin Teske# 1327879db76SDevin Teske############################################################ GLOBALS 1337879db76SDevin Teske 1347879db76SDevin Teskepgm="${0##*/}" # Program basename 1357879db76SDevin Teske 1367879db76SDevin Teske# 1377879db76SDevin Teske# Global exit status 1387879db76SDevin Teske# 1397879db76SDevin TeskeSUCCESS=0 1407879db76SDevin TeskeFAILURE=1 1417879db76SDevin Teske 1427879db76SDevin Teske############################################################ FUNCTIONS 1437879db76SDevin Teske 1447879db76SDevin Teskeusage() 1457879db76SDevin Teske{ 1467879db76SDevin Teske local action usage descr 1477879db76SDevin Teske exec >&2 1487879db76SDevin Teske echo "Usage: $pgm action [arguments]" 1497879db76SDevin Teske echo "Actions:" 1507879db76SDevin Teske for action in \ 1517879db76SDevin Teske bridge \ 1527879db76SDevin Teske graph \ 1537879db76SDevin Teske show \ 1547879db76SDevin Teske show1 \ 1557879db76SDevin Teske shutdown \ 15639d9a52dSDevin Teske stats \ 1577879db76SDevin Teske ; do 1587879db76SDevin Teske eval usage=\"\$jng_${action}_usage\" 1597879db76SDevin Teske [ "$usage" ] || continue 1607879db76SDevin Teske eval descr=\"\$jng_${action}_descr\" 1617879db76SDevin Teske printf "\t%s\n\t\t%s\n" "$usage" "$descr" 1627879db76SDevin Teske done 1637879db76SDevin Teske exit $FAILURE 1647879db76SDevin Teske} 1657879db76SDevin Teske 1667879db76SDevin Teskeaction_usage() 1677879db76SDevin Teske{ 1683ce83dbfSDevin Teske local usage descr action="$1" 1697879db76SDevin Teske eval usage=\"\$jng_${action}_usage\" 1707879db76SDevin Teske echo "Usage: $pgm $usage" >&2 1713ce83dbfSDevin Teske eval descr=\"\$jng_${action}_descr\" 1723ce83dbfSDevin Teske printf "\t%s\n" "$descr" 1737879db76SDevin Teske exit $FAILURE 1747879db76SDevin Teske} 1757879db76SDevin Teske 1767e4b7c79SDevin Teskederive_mac() 1777e4b7c79SDevin Teske{ 1787e4b7c79SDevin Teske local OPTIND=1 OPTARG __flag 1797e4b7c79SDevin Teske local __mac_num= __make_pair= 1807e4b7c79SDevin Teske while getopts 2n: __flag; do 1817e4b7c79SDevin Teske case "$__flag" in 1827e4b7c79SDevin Teske 2) __make_pair=1 ;; 1837e4b7c79SDevin Teske n) __mac_num=${OPTARG%%[^0-9]*} ;; 1847e4b7c79SDevin Teske esac 1857e4b7c79SDevin Teske done 1867e4b7c79SDevin Teske shift $(( $OPTIND - 1 )) 1877e4b7c79SDevin Teske 1887e4b7c79SDevin Teske if [ ! "$__mac_num" ]; then 1897e4b7c79SDevin Teske eval __mac_num=\${_${iface}_num:--1} 1907e4b7c79SDevin Teske __mac_num=$(( $__mac_num + 1 )) 1917e4b7c79SDevin Teske eval _${iface}_num=\$__mac_num 1927e4b7c79SDevin Teske fi 1937e4b7c79SDevin Teske 1947e4b7c79SDevin Teske local __iface="$1" __name="$2" __var_to_set="$3" __var_to_set_b="$4" 1957e4b7c79SDevin Teske local __iface_devid __new_devid __num __new_devid_b 1967e4b7c79SDevin Teske # 1977e4b7c79SDevin Teske # Calculate MAC address derived from given iface. 1987e4b7c79SDevin Teske # 1997e4b7c79SDevin Teske # The formula I'm using is ``NP:SS:SS:II:II:II'' where: 2007e4b7c79SDevin Teske # + N denotes 4 bits used as a counter to support branching 2017e4b7c79SDevin Teske # each parent interface up to 15 times under the same jail 2027e4b7c79SDevin Teske # name (see S below). 2037e4b7c79SDevin Teske # + P denotes the special nibble whose value, if one of 2047e4b7c79SDevin Teske # 2, 6, A, or E (but usually 2) denotes a privately 2057e4b7c79SDevin Teske # administered MAC address (while remaining routable). 2067e4b7c79SDevin Teske # + S denotes 16 bits, the sum(1) value of the jail name. 2077e4b7c79SDevin Teske # + I denotes bits that are inherited from parent interface. 2087e4b7c79SDevin Teske # 2097e4b7c79SDevin Teske # The S bits are a CRC-16 checksum of NAME, allowing the jail 2107e4b7c79SDevin Teske # to change link numbers in ng_bridge(4) without affecting the 2117e4b7c79SDevin Teske # MAC address. Meanwhile, if... 2127e4b7c79SDevin Teske # + the jail NAME changes (e.g., it was duplicated and given 2137e4b7c79SDevin Teske # a new name with no other changes) 2147e4b7c79SDevin Teske # + the underlying network interface changes 2157e4b7c79SDevin Teske # + the jail is moved to another host 2167e4b7c79SDevin Teske # the MAC address will be recalculated to a new, similarly 2177e4b7c79SDevin Teske # unique value preventing conflict. 2187e4b7c79SDevin Teske # 2197e4b7c79SDevin Teske __iface_devid=$( ifconfig $__iface ether | awk '/ether/,$0=$2' ) 22078954c3bSDevin Teske # ??:??:??:II:II:II 22178954c3bSDevin Teske __new_devid=${__iface_devid#??:??:??} # => :II:II:II 22278954c3bSDevin Teske # => :SS:SS:II:II:II 2237e4b7c79SDevin Teske __num=$( set -- `echo -n "$__name" | sum` && echo $1 ) 22478954c3bSDevin Teske __new_devid=$( printf :%02x:%02x \ 22578954c3bSDevin Teske $(( $__num >> 8 & 255 )) $(( $__num & 255 )) )$__new_devid 22678954c3bSDevin Teske # => P:SS:SS:II:II:II 2277e4b7c79SDevin Teske case "$__iface_devid" in 2287e4b7c79SDevin Teske ?2:*) __new_devid=a$__new_devid __new_devid_b=e$__new_devid ;; 2297e4b7c79SDevin Teske ?[Ee]:*) __new_devid=2$__new_devid __new_devid_b=6$__new_devid ;; 2307e4b7c79SDevin Teske *) __new_devid=2$__new_devid __new_devid_b=e$__new_devid 2317e4b7c79SDevin Teske esac 23278954c3bSDevin Teske # => NP:SS:SS:II:II:II 2337e4b7c79SDevin Teske __new_devid=$( printf %x $(( $__mac_num & 15 )) )$__new_devid 2347e4b7c79SDevin Teske __new_devid_b=$( printf %x $(( $__mac_num & 15 )) )$__new_devid_b 2357e4b7c79SDevin Teske 2367e4b7c79SDevin Teske # 2377e4b7c79SDevin Teske # Return derivative MAC address(es) 2387e4b7c79SDevin Teske # 2397e4b7c79SDevin Teske if [ "$__make_pair" ]; then 2407e4b7c79SDevin Teske if [ "$__var_to_set" -a "$__var_to_set_b" ]; then 2417e4b7c79SDevin Teske eval $__var_to_set=\$__new_devid 2427e4b7c79SDevin Teske eval $__var_to_set_b=\$__new_devid_b 2437e4b7c79SDevin Teske else 2447e4b7c79SDevin Teske echo $__new_devid $__new_devid_b 2457e4b7c79SDevin Teske fi 2467e4b7c79SDevin Teske else 2477e4b7c79SDevin Teske if [ "$__var_to_set" ]; then 2487e4b7c79SDevin Teske eval $__var_to_set=\$__new_devid 2497e4b7c79SDevin Teske else 2507e4b7c79SDevin Teske echo $__new_devid 2517e4b7c79SDevin Teske fi 2527e4b7c79SDevin Teske fi 2537e4b7c79SDevin Teske} 2547e4b7c79SDevin Teske 2557879db76SDevin Teskemustberoot_to_continue() 2567879db76SDevin Teske{ 2577879db76SDevin Teske if [ "$( id -u )" -ne 0 ]; then 2587879db76SDevin Teske echo "Must run as root!" >&2 2597879db76SDevin Teske exit $FAILURE 2607879db76SDevin Teske fi 2617879db76SDevin Teske} 2627879db76SDevin Teske 2631ccea30fSDevin Teskejng_bridge_usage="bridge [-b BRIDGE_NAME] NAME [!|=]iface0 [[!|=]iface1 ...]" 2647879db76SDevin Teskejng_bridge_descr="Create ng0_NAME [ng1_NAME ...]" 2657879db76SDevin Teskejng_bridge() 2667879db76SDevin Teske{ 2677879db76SDevin Teske local OPTIND=1 OPTARG flag bridge=bridge 2687879db76SDevin Teske while getopts b: flag; do 2697879db76SDevin Teske case "$flag" in 2707879db76SDevin Teske b) bridge="$OPTARG" 2717879db76SDevin Teske [ "$bridge" ] || action_usage bridge ;; # NOTREACHED 2727879db76SDevin Teske *) action_usage bridge # NOTREACHED 2737879db76SDevin Teske esac 2747879db76SDevin Teske done 2757879db76SDevin Teske shift $(( $OPTIND - 1 )) 2767879db76SDevin Teske 2777879db76SDevin Teske local name="$1" 2787879db76SDevin Teske [ "${name:-x}" = "${name#*[!0-9a-zA-Z_]}" -a $# -gt 1 ] || 2797879db76SDevin Teske action_usage bridge # NOTREACHED 2807879db76SDevin Teske shift 1 # name 2817879db76SDevin Teske 2827879db76SDevin Teske mustberoot_to_continue 2837879db76SDevin Teske 284b35d45aaSDevin Teske local iface parent eiface eiface_devid 2851ccea30fSDevin Teske local new clone_mac no_derive num quad i=0 2867879db76SDevin Teske for iface in $*; do 2877879db76SDevin Teske 288b35d45aaSDevin Teske clone_mac= 2891ccea30fSDevin Teske no_derive= 290b35d45aaSDevin Teske case "$iface" in 291b35d45aaSDevin Teske =*) iface=${iface#=} clone_mac=1 ;; 2921ccea30fSDevin Teske !*) iface=${iface#!} no_derive=1 ;; 293b35d45aaSDevin Teske esac 294b35d45aaSDevin Teske 2954b9a5d61SDevin Teske # Make sure the interface doesn't exist already 2967879db76SDevin Teske eiface=ng${i}_$name 2974b9a5d61SDevin Teske if ngctl msg "$eiface:" getifname > /dev/null 2>&1; then 2984b9a5d61SDevin Teske i=$(( $i + 1 )) 2994b9a5d61SDevin Teske continue 3004b9a5d61SDevin Teske fi 3017879db76SDevin Teske 3024b9a5d61SDevin Teske # Bring the interface up 3037879db76SDevin Teske ifconfig $iface up || return 3047879db76SDevin Teske 3054b9a5d61SDevin Teske # Set promiscuous mode and don't overwrite src addr 3067879db76SDevin Teske ngctl msg $iface: setpromisc 1 || return 3077879db76SDevin Teske ngctl msg $iface: setautosrc 0 || return 3087879db76SDevin Teske 3094b9a5d61SDevin Teske # Make sure the interface has been bridged 3107879db76SDevin Teske if ! ngctl info ${iface}bridge: > /dev/null 2>&1; then 3117879db76SDevin Teske ngctl mkpeer $iface: bridge lower link0 || return 3127879db76SDevin Teske ngctl connect $iface: $iface:lower upper link1 || 3137879db76SDevin Teske return 3147879db76SDevin Teske ngctl name $iface:lower ${iface}bridge || return 3157879db76SDevin Teske fi 3167879db76SDevin Teske 317*de121c54SMariusz Zaborski mtu=$(ifconfig ${iface} | sed -n '1s/^.*mtu //p;') || return 318*de121c54SMariusz Zaborski 3194b9a5d61SDevin Teske # Optionally create a secondary bridge 3207879db76SDevin Teske if [ "$bridge" != "bridge" ] && 3217879db76SDevin Teske ! ngctl info "$iface$bridge:" > /dev/null 2>&1 3227879db76SDevin Teske then 3237879db76SDevin Teske num=2 3247879db76SDevin Teske while ngctl msg ${iface}bridge: getstats $num \ 3257879db76SDevin Teske > /dev/null 2>&1 3267879db76SDevin Teske do 3277879db76SDevin Teske num=$(( $num + 1 )) 3287879db76SDevin Teske done 3297879db76SDevin Teske ngctl mkpeer $iface:lower bridge link$num link1 || 3307879db76SDevin Teske return 3317879db76SDevin Teske ngctl name ${iface}bridge:link$num "$iface$bridge" || 3327879db76SDevin Teske return 3337879db76SDevin Teske fi 3347879db76SDevin Teske 3354b9a5d61SDevin Teske # Create a new interface to the bridge 3367879db76SDevin Teske num=2 3377879db76SDevin Teske while ngctl msg "$iface$bridge:" getstats $num > /dev/null 2>&1 3387879db76SDevin Teske do 3397879db76SDevin Teske num=$(( $num + 1 )) 3407879db76SDevin Teske done 3417879db76SDevin Teske ngctl mkpeer "$iface$bridge:" eiface link$num ether || return 3427879db76SDevin Teske 3434b9a5d61SDevin Teske # Rename the new interface 3447879db76SDevin Teske while [ ${#eiface} -gt 15 ]; do # OS limitation 3457879db76SDevin Teske eiface=${eiface%?} 3467879db76SDevin Teske done 3477879db76SDevin Teske new=$( set -- `ngctl show -n "$iface$bridge:link$num"` && 3487879db76SDevin Teske echo $2 ) || return 3497879db76SDevin Teske ngctl name "$iface$bridge:link$num" $eiface || return 3507879db76SDevin Teske ifconfig $new name $eiface || return 351*de121c54SMariusz Zaborski ifconfig $eiface mtu $mtu || return 352f2c27deaSDevin Teske ifconfig $eiface up || return 3537879db76SDevin Teske 3547879db76SDevin Teske # 3554b9a5d61SDevin Teske # Set the MAC address of the new interface using a sensible 3567879db76SDevin Teske # algorithm to prevent conflicts on the network. 3577879db76SDevin Teske # 3581ccea30fSDevin Teske eiface_devid= 359b35d45aaSDevin Teske if [ "$clone_mac" ]; then 3601ccea30fSDevin Teske eiface_devid=$( ifconfig $iface ether | 3611ccea30fSDevin Teske awk '/ether/,$0=$2' ) 3621ccea30fSDevin Teske elif [ ! "$no_derive" ]; then 3637e4b7c79SDevin Teske derive_mac $iface "$name" eiface_devid 364b35d45aaSDevin Teske fi 3651ccea30fSDevin Teske [ "$eiface_devid" ] && 3661ccea30fSDevin Teske ifconfig $eiface ether $eiface_devid > /dev/null 2>&1 3677879db76SDevin Teske 3684b9a5d61SDevin Teske i=$(( $i + 1 )) 3697879db76SDevin Teske done # for iface 3707879db76SDevin Teske} 3717879db76SDevin Teske 3727879db76SDevin Teskejng_graph_usage="graph [-f] [-T type] [-o output]" 3737879db76SDevin Teskejng_graph_descr="Generate network graph (default output is \`jng.svg')" 3747879db76SDevin Teskejng_graph() 3757879db76SDevin Teske{ 3767879db76SDevin Teske local OPTIND=1 OPTARG flag 3777879db76SDevin Teske local output=jng.svg output_type= force= 3787879db76SDevin Teske while getopts fo:T: flag; do 3797879db76SDevin Teske case "$flag" in 3807879db76SDevin Teske f) force=1 ;; 3817879db76SDevin Teske o) output="$OPTARG" ;; 3827879db76SDevin Teske T) output_type="$OPTARG" ;; 3837879db76SDevin Teske *) action_usage graph # NOTREACHED 3847879db76SDevin Teske esac 3857879db76SDevin Teske done 3867879db76SDevin Teske shift $(( $OPTIND - 1 )) 3877879db76SDevin Teske [ $# -eq 0 -a "$output" ] || action_usage graph # NOTREACHED 3887879db76SDevin Teske mustberoot_to_continue 3897879db76SDevin Teske if [ -e "$output" -a ! "$force" ]; then 3907879db76SDevin Teske echo "$output: Already exists (use \`-f' to overwrite)" >&2 3917879db76SDevin Teske return $FAILURE 3927879db76SDevin Teske fi 3937879db76SDevin Teske if [ ! "$output_type" ]; then 3947879db76SDevin Teske local valid suffix 3957879db76SDevin Teske valid=$( dot -Txxx 2>&1 ) 3967879db76SDevin Teske for suffix in ${valid##*:}; do 3977879db76SDevin Teske [ "$output" != "${output%.$suffix}" ] || continue 3987879db76SDevin Teske output_type=$suffix 3997879db76SDevin Teske break 4007879db76SDevin Teske done 4017879db76SDevin Teske fi 4027879db76SDevin Teske ngctl dot | dot ${output_type:+-T "$output_type"} -o "$output" 4037879db76SDevin Teske} 4047879db76SDevin Teske 4057879db76SDevin Teskejng_show_usage="show" 4067879db76SDevin Teskejng_show_descr="List possible NAME values for \`show NAME'" 4077879db76SDevin Teskejng_show1_usage="show NAME" 4087879db76SDevin Teskejng_show1_descr="Lists ng0_NAME [ng1_NAME ...]" 4097879db76SDevin Teskejng_show2_usage="show [NAME]" 4107879db76SDevin Teskejng_show() 4117879db76SDevin Teske{ 4127879db76SDevin Teske local OPTIND=1 OPTARG flag 4137879db76SDevin Teske while getopts "" flag; do 4147879db76SDevin Teske case "$flag" in 4157879db76SDevin Teske *) action_usage show2 # NOTREACHED 4167879db76SDevin Teske esac 4177879db76SDevin Teske done 4187879db76SDevin Teske shift $(( $OPTIND - 1 )) 4197879db76SDevin Teske mustberoot_to_continue 4207879db76SDevin Teske if [ $# -eq 0 ]; then 4217879db76SDevin Teske ngctl ls | awk '$4=="bridge",$0=$2' | 4227879db76SDevin Teske xargs -rn1 -Ibridge ngctl show bridge: | 4237879db76SDevin Teske awk 'sub(/^ng[[:digit:]]+_/, "", $2), $0 = $2' | 4247879db76SDevin Teske sort -u 4257879db76SDevin Teske return 4267879db76SDevin Teske fi 4277879db76SDevin Teske ngctl ls | awk -v name="$1" ' 4287879db76SDevin Teske match($2, /^ng[[:digit:]]+_/) && 4297879db76SDevin Teske substr($2, RSTART + RLENGTH) == name && 4307879db76SDevin Teske $4 == "eiface", $0 = $2 4317879db76SDevin Teske ' | sort 4327879db76SDevin Teske} 4337879db76SDevin Teske 4347879db76SDevin Teskejng_shutdown_usage="shutdown NAME" 4357879db76SDevin Teskejng_shutdown_descr="Shutdown ng0_NAME [ng1_NAME ...]" 4367879db76SDevin Teskejng_shutdown() 4377879db76SDevin Teske{ 4387879db76SDevin Teske local OPTIND=1 OPTARG flag 4397879db76SDevin Teske while getopts "" flag; do 4407879db76SDevin Teske case "$flag" in 4417879db76SDevin Teske *) action_usage shutdown # NOTREACHED 4427879db76SDevin Teske esac 4437879db76SDevin Teske done 4447879db76SDevin Teske shift $(( $OPTIND -1 )) 4457879db76SDevin Teske local name="$1" 4467879db76SDevin Teske [ "${name:-x}" = "${name#*[!0-9a-zA-Z_]}" -a $# -eq 1 ] || 4477879db76SDevin Teske action_usage shutdown # NOTREACHED 4487879db76SDevin Teske mustberoot_to_continue 4497879db76SDevin Teske jng_show "$name" | xargs -rn1 -I eiface ngctl shutdown eiface: 4507879db76SDevin Teske} 4517879db76SDevin Teske 45239d9a52dSDevin Teskejng_stats_usage="stats NAME" 45339d9a52dSDevin Teskejng_stats_descr="Show ng_bridge link statistics for NAME interfaces" 45439d9a52dSDevin Teskejng_stats() 45539d9a52dSDevin Teske{ 45639d9a52dSDevin Teske local OPTIND=1 OPTARG flag 45739d9a52dSDevin Teske while getopts "" flag; do 45839d9a52dSDevin Teske case "$flag" in 45939d9a52dSDevin Teske *) action_usage stats # NOTREACHED 46039d9a52dSDevin Teske esac 46139d9a52dSDevin Teske done 46239d9a52dSDevin Teske shift $(( $OPTIND -1 )) 46339d9a52dSDevin Teske local name="$1" 46439d9a52dSDevin Teske [ "${name:-x}" = "${name#*[!0-9a-zA-Z_]}" -a $# -eq 1 ] || 46539d9a52dSDevin Teske action_usage stats # NOTREACHED 46639d9a52dSDevin Teske mustberoot_to_continue 46739d9a52dSDevin Teske for eiface in $( jng_show "$name" ); do 46839d9a52dSDevin Teske echo "$eiface:" 46939d9a52dSDevin Teske ngctl show $eiface: | awk ' 47039d9a52dSDevin Teske $3 == "bridge" && $5 ~ /^link/ { 47139d9a52dSDevin Teske bridge = $2 47239d9a52dSDevin Teske link = substr($5, 5) 47339d9a52dSDevin Teske system(sprintf("ngctl msg %s: getstats %u", 47439d9a52dSDevin Teske bridge, link)) 47539d9a52dSDevin Teske }' | fmt 2 | awk ' 47639d9a52dSDevin Teske /=/ && fl = index($0, "=") { 47739d9a52dSDevin Teske printf "%20s = %s\n", 47839d9a52dSDevin Teske substr($0, 0, fl-1), 47939d9a52dSDevin Teske substr($0, 0, fl+1) 48039d9a52dSDevin Teske } 48139d9a52dSDevin Teske ' # END-QUOTE 48239d9a52dSDevin Teske done 48339d9a52dSDevin Teske} 48439d9a52dSDevin Teske 4857879db76SDevin Teske############################################################ MAIN 4867879db76SDevin Teske 4877879db76SDevin Teske# 4887879db76SDevin Teske# Command-line arguments 4897879db76SDevin Teske# 4907879db76SDevin Teskeaction="$1" 4917879db76SDevin Teske[ "$action" ] || usage # NOTREACHED 4927879db76SDevin Teske 4937879db76SDevin Teske# 4947879db76SDevin Teske# Validate action argument 4957879db76SDevin Teske# 4967879db76SDevin Teskeif [ "$BASH_VERSION" ]; then 4977879db76SDevin Teske type="$( type -t "jng_$action" )" || usage # NOTREACHED 4987879db76SDevin Teskeelse 4997879db76SDevin Teske type="$( type "jng_$action" 2> /dev/null )" || usage # NOTREACHED 5007879db76SDevin Teskefi 5017879db76SDevin Teskecase "$type" in 5027879db76SDevin Teske*function) 5037879db76SDevin Teske shift 1 # action 5047879db76SDevin Teske eval "jng_$action" \"\$@\" 5057879db76SDevin Teske ;; 5067879db76SDevin Teske*) usage # NOTREACHED 5077879db76SDevin Teskeesac 5087879db76SDevin Teske 5097879db76SDevin Teske################################################################################ 5107879db76SDevin Teske# END 5117879db76SDevin Teske################################################################################ 512