From nobody Tue Aug 18 18:56:38 2026 X-Original-To: dev-commits-src-main@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id 4hPf7W1XhBz6nghJ for ; Tue, 18 Aug 2026 18:56:39 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "YR2" (not verified)) by mx1.freebsd.org (Postfix) with ESMTPS id 4hPf7W19dSz3NJH for ; Tue, 18 Aug 2026 18:56:39 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1787079399; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=kyepnhoyqPhiPwTPbSck9alFAxHx4IRUokE/KPnTM9Q=; b=vjAjFLibGKpDmYtHOgux7nS03xCQnLn3o7TpH9kaIis8csrt8KzRpxsU1h1lP6rP/prWiT 9xCA/DjhNWNP+ViS5dhzu6fUXTuF+Y6tVLpJBlgtchuBUvkyFdlO1VoObzoTINH6t6qxMF D2GeW9PdpiCuVOKfVjtXPxgmXkPP3ZrCn0S1FmucNhU4ZlfWyUuO7b9TX083m05JQXmMIF Fy1WTMbhI+t8KCu1kiNsrIWRoCvVy2b88McC5GR86ylfyM9qwqzAQmkj05/aLaSFJFSlub w1rACJSnAxyums8qDOZjPCdxMPQ4DhJ3ibn1LmdIvRK25ee4l7iWBLtKUNLGNw== ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1787079399; a=rsa-sha256; cv=none; b=HCQKbhv6DvrsC+H3JfKtHtzqL5oa0bFPsOTaWSUGVJffXCsWuESFHKpa0k0tlThD5IB0bf w8a2WlVhfhAS4KYJT2sjiJnqkZ9WHs2VGtbQ581di9weAHxVS0FxT9P9UBQFuohW3tQ/3G 2dN7w3YR+pTi0ur5tERL9k9W2aXJsd1gXVurCxdL+lk4wwpEnsfrPAhtHdoZ9GnUutCGpR 3j0IQ95MeVF6411XGBR/HPMCXWAH9/WBDyjy/oCwSPQRTclA8XzhhMGZUjMASpjcaFXzD9 YSuJT/Li8qkQLro6QepeDyeCWZEpfqiGH+i2TtA4++PMR1EsMDBeAnqYKMdaMA== ARC-Authentication-Results: i=1; mx1.freebsd.org; none ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1787079399; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=kyepnhoyqPhiPwTPbSck9alFAxHx4IRUokE/KPnTM9Q=; b=QJjcN7rYhX6idVGnLtHng3HUrTGkNjt2t54U07XJ2r+FMyHXKZZzgVGhcLzGh1V8pChl6y Xt6SUF9g27EVtbYL+Bbh/WWjyAgMMtmIOTiYQ7fATOiz7fYJlpSnqEFqyeQdpHt6FP0MEz RDUSKzSbGEzz0SO3luLU8qHeleaKfc8m06GR3YBeJWC+glhm5JYkbXb0j6PGNNELka7uSv cRdyBbrTeTNZgFHlFB+KWUA7b9Y2G9c8mT0SAS20qU+LmWwaX9co94Qc5M4GdOYVFCkogm Ulm7EMunD8M9YNUGcot8DiAV08q08GzKu0LC/hZFY0x4FPrBRulPI59dgxlEag== Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) by mxrelay.nyi.freebsd.org (Postfix) with ESMTP id 4hPf7W03ndzxDh for ; Tue, 18 Aug 2026 18:56:39 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from git (uid 1279) (envelope-from git@FreeBSD.org) id 3f7ed by gitrepo.freebsd.org (DragonFly Mail Agent v0.13+ on gitrepo.freebsd.org); Tue, 18 Aug 2026 18:56:38 +0000 To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org From: Devin Teske Subject: git: 644990f193cc - main - New version of jng (9.0) List-Id: Commit messages for the main branch of the src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-main List-Help: List-Post: List-Subscribe: List-Unsubscribe: X-BeenThere: dev-commits-src-main@freebsd.org Sender: owner-dev-commits-src-main@FreeBSD.org List-Id: List-Post: List-Help: List-Subscribe: List-Unsubscribe: List-Owner: Precedence: list MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: dteske X-Git-Repository: src X-Git-Refname: refs/heads/main X-Git-Reftype: branch X-Git-Commit: 644990f193cc284db241125e567519cafa1c7ccd Auto-Submitted: auto-generated Date: Tue, 18 Aug 2026 18:56:38 +0000 Message-Id: <6a84aae6.3f7ed.446c48ae@gitrepo.freebsd.org> The branch main has been updated by dteske: URL: https://cgit.FreeBSD.org/src/commit/?id=644990f193cc284db241125e567519cafa1c7ccd commit 644990f193cc284db241125e567519cafa1c7ccd Author: Devin Teske AuthorDate: 2026-08-18 18:54:36 +0000 Commit: Devin Teske CommitDate: 2026-08-18 18:54:36 +0000 New version of jng (9.0) Changes for jng 2.0 -> 9.0 include: + Use ng_bridge(4) uplink hooks on ng_ether(4) lower so the host mapping table stays small (first hook is uplink; unknown unicast goes only to uplink) + Add `jng pin [-h] {-a | NAME ...}' to plant eiface MACs with NGM_BRIDGE_MOVE_HOST and raise maxStaleness so they do not expire + Remove experimental NG_TYPE=iface / ng_tcpmss(4); ng_iface(4) cannot work with ng_bridge(4) + Add -v + SPDX-License-Identifier: BSD-2-Clause; bump copyright to 2026 See D58902 for the ng_bridge(4) data-path MOVE_HOST fix. MFC after: 1 week Reviewed by: kfv, jlduran Differential Revision: https://reviews.freebsd.org/D58903 --- share/examples/jails/jng | 347 +++++++++++++++++++++++++++++++---------------- 1 file changed, 232 insertions(+), 115 deletions(-) diff --git a/share/examples/jails/jng b/share/examples/jails/jng index 03f5c318199c..82f1dd7b5e94 100755 --- a/share/examples/jails/jng +++ b/share/examples/jails/jng @@ -1,33 +1,13 @@ #!/bin/sh -#- -# Copyright (c) 2016-2024 Devin Teske -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND -# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE -# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS -# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -# SUCH DAMAGE. +# +# SPDX-License-Identifier: BSD-2-Clause +# +# Copyright (c) 2016-2026 Devin Teske # ############################################################ IDENT(1) # # $Title: netgraph(4) management script for vnet jails $ -# $Version: 2.0 $ +# $Version: 9.0 $ # ############################################################ INFORMATION # @@ -84,6 +64,7 @@ # ### BEGIN EXCERPT ### # # jail_enable="YES" +# #jail_confwarn="NO" # Optional: disable warning to migrate to jail.conf(5) # jail_list="xxx" # # # @@ -127,30 +108,32 @@ # jail_{name}_devfs_ruleset="11" (rc.conf(5)). # # NB: While this tool can't create every type of desirable topology, it should -# handle most setups, minus some which considered exotic or purpose-built. +# handle most setups, minus some considered exotic or purpose-built. +# +# Uplink on ng_ether(4) `lower' (jng 7+) keeps the WAN MAC table small: +# ng_bridge(4) does not learn on uplink hooks. The first connected hook being +# uplink also selects restrictive unknown-unicast: frames for an unknown dest +# go only to uplink, not to jail links. Inbound unicast to a jail therefore +# requires that jail's MAC to live in the forwarding database (FDB) on the +# jail's link. jng 8 pins each eiface MAC with ngctl movehost and sets +# maxStaleness so host->staleness cannot catch it. `jng pin NAME' replants +# after an accidental move. ng_bridge must not MOVE_HOST from learnMac=0 hooks +# or promiscuous TX echo can steal a pinned MAC onto uplink; without that +# kernel fix, re-run `jng pin'. # ############################################################ CONFIGURATION # -# Netgraph node type. Can be `iface' or `eiface' and refers to whether -# ng_iface(4) or ng_eiface(4) is used with ng_bridge(4). The advantages of -# choosing iface over eiface is that with iface you can utilize ng_tcpmss(4) -# to limit the TCP MSS for operating in environments that clamp down on ICMP. -# -# NB: iface/tcpmss support is EXPERIMENTAL -# -NG_TYPE=eiface # Can be iface or eiface - -# -# Clamp TCP Maximum Segment Size to reasonably below standard MTU -# NB: Fixes TCP hangup issue in environments where ICMP is restricted -# NB: Be liberal about MSS (RFC 879, section 7) -# NB: Unused unless NG_TYPE=iface +# host->staleness is uint16_t; conf.maxStaleness is uint32_t. +# ng_bridge_timeout expires when ++staleness >= maxStaleness. +# A threshold above 65535 is unreachable (the counter wraps). # -NG_TCPMSS_CONFIG='{ inHook="bridge" outHook="'$NG_TYPE'" maxMSS=1280 }' +NG_BRIDGE_MAX_STALENESS=4294967295 ############################################################ GLOBALS +VERSION='$Version: 9.0 $' + pgm="${0##*/}" # Program basename # @@ -168,22 +151,35 @@ STATS_FMT=text # -j for JSON quietly(){ "$@" > /dev/null 2>&1; } +die() +{ + local fmt="$1" + if [ "$fmt" ]; then + shift 1 # fmt + printf "%s: $fmt\n" "$pgm" "$@" >&2 + fi + exit $FAILURE +} + usage() { local fmt="$1" + local optfmt="\t%-5s %s\n" local action usage descr exec >&2 if [ "$fmt" ]; then shift 1 # fmt printf "%s: $fmt\n" "$pgm" "$@" fi - echo "Usage: $pgm [-h] action [arguments]" - echo "Options:" - printf "\t-h Print usage statement and exit.\n" - echo "Actions:" + printf "Usage: %s [-hv] action [arguments]\n" "$pgm" + printf "Options:\n" + printf "$optfmt" "-h" "Print this usage statement and exit." + printf "$optfmt" "-v" "Print version information and exit." + printf "Actions:\n" for action in \ bridge \ graph \ + pin \ show \ show1 \ shutdown \ @@ -194,7 +190,7 @@ usage() eval descr=\"\$jng_${action}_descr\" printf "\t%s\n\t\t%s\n" "$usage" "$descr" done - exit $FAILURE + die } action_usage() @@ -206,10 +202,10 @@ action_usage() printf "%s: %s: $fmt\n" "$pgm" "$action" "$@" >&2 fi eval usage=\"\$jng_${action}_usage\" - echo "Usage: $pgm $usage" >&2 + printf "Usage: %s %s\n" "$pgm" "$usage" >&2 eval descr=\"\$jng_${action}_descr\" - printf "\t%s\n" "$descr" - exit $FAILURE + printf "\t%s\n" "$descr" >&2 + die } derive_mac() @@ -235,7 +231,7 @@ derive_mac() # # Calculate MAC address derived from given iface. # - # The formula I'm using is ``NP:SS:SS:II:II:II'' where: + # The formula used is ``NP:SS:SS:II:II:II'' where: # + N denotes 4 bits used as a counter to support branching # each parent interface up to 15 times under the same jail # name (see S below). @@ -246,7 +242,7 @@ derive_mac() # + I denotes bits that are inherited from parent interface. # # The S bits are a CRC-16 checksum of NAME, allowing the jail - # to change link numbers in ng_bridge(4) without affecting the + # to change link numbers in ng_bridge(4) without effecting the # MAC address. Meanwhile, if... # + the jail NAME changes (e.g., it was duplicated and given # a new name with no other changes) @@ -259,7 +255,7 @@ derive_mac() # ??:??:??:II:II:II __new_devid=${__iface_devid#??:??:??} # => :II:II:II # => :SS:SS:II:II:II - __num=$( set -- `echo -n "$__name" | sum` && echo $1 ) + __num=$( set -- $( echo -n "$__name" | sum ) && echo $1 ) __new_devid=$( printf :%02x:%02x \ $(( $__num >> 8 & 255 )) $(( $__num & 255 )) )$__new_devid # => P:SS:SS:II:II:II @@ -293,10 +289,100 @@ derive_mac() mustberoot_to_continue() { - if [ "$( id -u )" -ne 0 ]; then - echo "Must run as root!" >&2 - exit $FAILURE + [ "$( id -u )" -eq 0 ] || die "Must run as root!" +} + +jng_bridge_has_uplink() +{ + ngctl show "$1:" 2> /dev/null | awk ' + $1 ~ /^uplink/ { found = 1; exit } + END { exit !found } + ' # END-QUOTE +} + +jng_bridge_persist_hosts() +{ + local node="$1" + local debug=0 loop=60 stable=1 config + + eval $( ngctl msg "$node:" getconfig 2> /dev/null | awk ' + { + if (match($0, /debugLevel=[0-9]+/)) + printf "debug=%s ", + substr($0, RSTART + 11, RLENGTH - 11) + if (match($0, /loopTimeout=[0-9]+/)) + printf "loop=%s ", + substr($0, RSTART + 12, RLENGTH - 12) + if (match($0, /minStableAge=[0-9]+/)) + printf "stable=%s ", + substr($0, RSTART + 13, RLENGTH - 13) + } + ' ) + config="debugLevel=$debug" + config="$config loopTimeout=$loop" + config="$config maxStaleness=$NG_BRIDGE_MAX_STALENESS" + config="$config minStableAge=$stable" + quietly ngctl msg "$node:" setconfig "{ $config }" +} + +jng_pin_mac() +{ + local node="$1" mac="$2" hook="$3" + + [ "$node" -a "$mac" -a "$hook" ] || return $FAILURE + quietly ngctl msg "$node:" movehost "{ addr=$mac hook=\"$hook\" }" +} + +jng_jiface_mac() +{ + local __jiface="$1" __jail="$2" __var_to_set="$3" + local __mac + + __mac=$( ifconfig "$__jiface" ether 2> /dev/null | + awk '/ether/ { print $2; exit }' ) + if [ ! "$__mac" -a "$__jail" ]; then + # + # After vnet.interface takes the eiface, it is gone + # from the host ifconfig; netgraph node remains. + # + __mac=$( jexec "$__jail" ifconfig "$__jiface" ether \ + 2> /dev/null | awk '/ether/ { print $2; exit }' ) fi + eval $__var_to_set=\"\$__mac\" + [ "$__mac" ] +} + +jng_pin_jiface() +{ + local jiface="$1" jail="$2" + local mac peer peerhook pbridge phook + + jng_jiface_mac "$jiface" "$jail" mac || return $FAILURE + + # ether bridge + set -- $( ngctl show "$jiface:" 2> /dev/null | awk ' + $3 == "bridge" { print $2, $5; exit } + ' ) + peer="$1" peerhook="$2" + [ "$peer" -a "$peerhook" ] || return $FAILURE + + jng_pin_mac "$peer" "$mac" "$peerhook" || return + if jng_bridge_has_uplink "$peer"; then + jng_bridge_persist_hosts "$peer" || : persist optional + return + fi + + # + # Secondary bridge: also pin on the parent that holds uplink + # (restrictive unknown-unicast lives there). + # + set -- $( ngctl show "$peer:" 2> /dev/null | awk ' + $3 == "bridge" { print $2, $5; exit } + ' ) + pbridge="$1" phook="$2" + [ "$pbridge" -a "$phook" ] || return $SUCCESS + jng_pin_mac "$pbridge" "$mac" "$phook" || return + jng_bridge_persist_hosts "$pbridge" || : persist optional } jng_bridge_usage="bridge [-h] [-b BRIDGE_NAME] NAME [!|=]iface0 [[!|=]iface1 ...]" @@ -326,7 +412,7 @@ jng_bridge() mustberoot_to_continue local iface parent jiface jiface_devid - local new clone_mac no_derive num quad i=0 + local new clone_mac no_derive num quad mtu i=0 for iface in $*; do clone_mac= @@ -351,77 +437,49 @@ jng_bridge() ngctl msg $iface: setautosrc 0 || return # Make sure the interface has been bridged + # NB: You must connect uplinkX before linkX + # NB: see ng_bridge(4) for policy on first connected hook if ! quietly ngctl info ${iface}bridge:; then - ngctl mkpeer $iface: bridge lower link0 || return - ngctl connect $iface: $iface:lower upper link1 || + ngctl mkpeer $iface: bridge lower uplink1 || return + ngctl connect $iface: $iface:lower upper link0 || return ngctl name $iface:lower ${iface}bridge || return + jng_bridge_persist_hosts ${iface}bridge || + : persist optional fi - mtu=$(ifconfig ${iface} | sed -n '1s/^.*mtu //p;') || return + mtu=$( ifconfig $iface | sed -n '1s/^.*mtu //p' ) || return # Optionally create a secondary bridge + # NB: This time, you want to only connect linkX (no uplinkX) if [ "$bridge" != "bridge" ] && ! quietly ngctl info "$iface$bridge:" then - num=2 + num=1 while quietly ngctl msg ${iface}bridge: getstats $num do num=$(( $num + 1 )) done - ngctl mkpeer $iface:lower bridge link$num link1 || + ngctl mkpeer $iface:lower bridge link$num link0 || return ngctl name ${iface}bridge:link$num "$iface$bridge" || return fi # Create a new interface to the bridge - num=2 + num=1 while quietly ngctl msg "$iface$bridge:" getstats $num; do num=$(( $num + 1 )) done - local hook peerhook - case "$NG_TYPE" in - eiface) - # Hook the eiface directly to the bridge - hook=link$num peerhook=ether - ngctl mkpeer "$iface$bridge:" \ - $NG_TYPE $hook $peerhook || return - ;; - iface) - # Hook tcpmss<->iface to bridge - hook=link$num peerhook=bridge - ngctl mkpeer "$iface$bridge:" \ - tcpmss $hook $peerhook || return - hook=iface peerhook=inet - ngctl mkpeer "$iface$bridge:link$num" \ - $NG_TYPE $hook $peerhook || return - ;; - *) return $FAILURE - esac + ngctl mkpeer "$iface$bridge:" eiface link$num ether || return # Rename the new interface while [ ${#jiface} -gt 15 ]; do # OS limitation jiface=${jiface%?} done - case "$NG_TYPE" in - eiface) - new=$( ngctl show -n "$iface$bridge:link$num" ) || - return - new=$( set -- $new; echo $2 ) - ngctl name "$iface$bridge:link$num" $jiface || return - ;; - iface) - ngctl name "$iface$bridge:link$num" $jiface-mss || - return - new=$( ngctl show -n "$jiface-mss:$hook" ) || return - new=$( set -- $new; echo $2 ) - ngctl name $jiface-mss:$hook $jiface || return - ngctl msg $jiface: broadcast || return - ngctl msg $jiface-mss: config "$NG_TCPMSS_CONFIG" || - return - ;; - esac + new=$( ngctl show -n "$iface$bridge:link$num" ) || return + new=$( set -- $new; echo $2 ) + ngctl name "$iface$bridge:link$num" $jiface || return ifconfig $new name $jiface || return ifconfig $jiface mtu $mtu || return ifconfig $jiface up || return @@ -439,13 +497,66 @@ jng_bridge() fi [ "$jiface_devid" ] && quietly ifconfig $jiface ether $jiface_devid + jng_pin_jiface "$jiface" "$name" || : pin optional i=$(( $i + 1 )) done # for iface } +jng_pin_usage="pin [-h] {-a | NAME ...}" +jng_pin_descr="Pin eiface MACs into ng_bridge forwarding database (FDB)" +jng_pin() +{ + local OPTIND=1 OPTARG flag + local show_all= err=$SUCCESS + local name iface jiface + + while getopts ah flag; do + case "$flag" in + a) show_all=1 ;; + *) action_usage pin # NOTREACHED + esac + done + shift $(( $OPTIND - 1 )) + if [ "$show_all" ]; then + [ $# -eq 0 ] || + action_usage pin "too many arguments" # NOTREACHED + for iface in $( ifconfig -l ); do + quietly ngctl info ${iface}bridge: || continue + jng_bridge_persist_hosts ${iface}bridge || + : persist optional + done + set -- $( jls -q name 2> /dev/null ) + [ $# -gt 0 ] || + action_usage pin "no jails" # NOTREACHED + else + [ $# -gt 0 ] || + action_usage pin "too few arguments" # NOTREACHED + fi + + mustberoot_to_continue + + for name in "$@"; do + [ "${name:-x}" = "${name#*[!0-9a-zA-Z_]}" ] || + action_usage pin "invalid name: %s" "$name" + # NOTREACHED + for jiface in $( jexec "$name" ifconfig -l 2> /dev/null ) + do + case "$jiface" in + ng[0-9]*) + jng_pin_jiface "$jiface" "$name" || { + echo "$pgm: pin $jiface: failed" >&2 + err=$FAILURE + } + ;; + esac + done + done + return $err +} + jng_graph_usage="graph [-fh] [-T type] [-o output]" -jng_graph_descr="Generate network graph (default output is \`jng.svg')" +jng_graph_descr="Generate network graph (default output is 'jng.svg')" jng_graph() { local OPTIND=1 OPTARG flag @@ -465,7 +576,7 @@ jng_graph() mustberoot_to_continue if [ -e "$output" -a ! "$force" ]; then - echo "$output: Already exists (use \`-f' to overwrite)" >&2 + echo "$output: Already exists (use '-f' to overwrite)" >&2 return $FAILURE fi if [ ! "$output_type" ]; then @@ -481,7 +592,7 @@ jng_graph() } jng_show_usage="show [-h]" -jng_show_descr="List possible NAME values for \`show NAME'" +jng_show_descr="List possible NAME values for 'show NAME'" jng_show1_usage="show [-h] NAME ..." jng_show1_descr="Lists ng0_NAME [ng1_NAME ...]" jng_show2_usage="show [NAME ...]" @@ -508,11 +619,9 @@ jng_show() fi for name in "$@"; do ngctl ls | awk -v name="$name" ' - BEGIN { N = length(name) + 1 } - !match(ng = $2, /^ng[[:digit:]]+_/) { next } - { _name = substr(ng, S = RSTART + RLENGTH) } - _name != name && substr(_name, 1, N) != name "-" { next } - (type = $4) ~ /^(e?iface|tcpmss)$/, $0 = ng + match($2, /^ng[[:digit:]]+_/) && + substr($2, RSTART + RLENGTH) == name && + $4 == "eiface", $0 = $2 ' | sort done } @@ -588,13 +697,13 @@ jng_stats() if ifconfig -l | xargs -n1 2> /dev/null | fgrep -qw "$name" then [ "$STATS_FMT" != "text" ] || - echo "${name}bridge:link0 [lower]" - ngctl msg ${name}bridge: getstats 0 | + echo "${name}bridge:uplink1 [lower]" + ngctl msg ${name}bridge: getstats -1 | fmt_stats -n "${name}.lower" -t "$now" [ "$STATS_FMT" != "text" ] || - echo "${name}bridge:link1 [upper]" - ngctl msg ${name}bridge: getstats 1 | + echo "${name}bridge:link0 [upper]" + ngctl msg ${name}bridge: getstats 0 | fmt_stats -n "${name}.upper" -t "$now" fi local jiface @@ -672,17 +781,25 @@ action="$1" # # Validate action argument # +case "$action" in +-h) usage ;; # NOTREACHED +-v) VERSION="${VERSION#*: }" + echo "${VERSION% $}" + exit $SUCCESS ;; +-*) usage "unknown option: %s" "$action" ;; # NOTREACHED +*[!a-zA-Z0-9_-]*) usage 'invalid action "%s"' "$action" ;; # NOTREACHED +esac if [ "$BASH_VERSION" ]; then - type="$( type -t "jng_$action" )" || usage # NOTREACHED + type="$( type -t "jng_$action" )" else - type="$( type "jng_$action" 2> /dev/null )" || usage # NOTREACHED -fi + type="$( type "jng_$action" 2> /dev/null )" +fi || usage 'unknown action "%s"' "$action" # NOTREACHED case "$type" in *function) shift 1 # action eval "jng_$action" \"\$@\" ;; -*) usage # NOTREACHED +*) usage 'unknown action "%s"' "$action" # NOTREACHED esac ################################################################################