Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F156938485
D43516.id133055.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
13 KB
Referenced Files
None
Subscribers
None
D43516.id133055.diff
View Options
diff --git a/share/examples/jails/jng.orig b/share/examples/jails/jng
--- a/share/examples/jails/jng.orig
+++ b/share/examples/jails/jng
@@ -1,6 +1,6 @@
#!/bin/sh
#-
-# Copyright (c) 2016 Devin Teske
+# Copyright (c) 2016-2023 Devin Teske <dteske@FreeBSD.org>
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
@@ -24,10 +24,12 @@
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.
#
+# $FreeBSD$
#
############################################################ IDENT(1)
#
# $Title: netgraph(4) management script for vnet jails $
+# $Version: 2.0 $
#
############################################################ INFORMATION
#
@@ -129,6 +131,26 @@
# 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.
#
+############################################################ 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
+#
+NG_TCPMSS_CONFIG='{ inHook="bridge" outHook="'$NG_TYPE'" maxMSS=1280 }'
+
############################################################ GLOBALS
pgm="${0##*/}" # Program basename
@@ -139,13 +161,27 @@
SUCCESS=0
FAILURE=1
+#
+# Command-line options
+#
+STATS_FMT=text # -j for JSON
+
############################################################ FUNCTIONS
+quietly(){ "$@" > /dev/null 2>&1; }
+
usage()
{
+ local fmt="$1"
local action usage descr
exec >&2
- echo "Usage: $pgm action [arguments]"
+ 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:"
for action in \
bridge \
@@ -165,7 +201,12 @@
action_usage()
{
- local usage descr action="$1"
+ local usage descr action="$1" fmt="$2"
+ shift 1 # action
+ if [ "$fmt" ]; then
+ shift 1 # fmt
+ printf "%s: %s: $fmt\n" "$pgm" "$action" "$@" >&2
+ fi
eval usage=\"\$jng_${action}_usage\"
echo "Usage: $pgm $usage" >&2
eval descr=\"\$jng_${action}_descr\"
@@ -260,28 +301,33 @@
fi
}
-jng_bridge_usage="bridge [-b BRIDGE_NAME] NAME [!|=]iface0 [[!|=]iface1 ...]"
+jng_bridge_usage="bridge [-h] [-b BRIDGE_NAME] NAME [!|=]iface0 [[!|=]iface1 ...]"
jng_bridge_descr="Create ng0_NAME [ng1_NAME ...]"
jng_bridge()
{
local OPTIND=1 OPTARG flag bridge=bridge
- while getopts b: flag; do
+ while getopts b:h flag; do
case "$flag" in
b) bridge="$OPTARG"
- [ "$bridge" ] || action_usage bridge ;; # NOTREACHED
+ [ "$bridge" ] ||
+ action_usage bridge "-b argument cannot be empty"
+ ;; # NOTREACHED
*) action_usage bridge # NOTREACHED
esac
done
shift $(( $OPTIND - 1 ))
+ [ $# -gt 0 ] || action_usage bridge "too few arguments" # NOTREACHED
+
local name="$1"
- [ "${name:-x}" = "${name#*[!0-9a-zA-Z_]}" -a $# -gt 1 ] ||
- action_usage bridge # NOTREACHED
+ [ "${name:-x}" = "${name#*[!0-9a-zA-Z_]}" ] ||
+ action_usage bridge "invalid bridge name: %s" "$name"
+ # NOTREACHED
shift 1 # name
mustberoot_to_continue
- local iface parent eiface eiface_devid
+ local iface parent jiface jiface_devid
local new clone_mac no_derive num quad i=0
for iface in $*; do
@@ -293,8 +339,8 @@
esac
# Make sure the interface doesn't exist already
- eiface=ng${i}_$name
- if ngctl msg "$eiface:" getifname > /dev/null 2>&1; then
+ jiface=ng${i}_$name
+ if quietly ngctl msg "$jiface:" getifname; then
i=$(( $i + 1 ))
continue
fi
@@ -307,7 +353,7 @@
ngctl msg $iface: setautosrc 0 || return
# Make sure the interface has been bridged
- if ! ngctl info ${iface}bridge: > /dev/null 2>&1; then
+ if ! quietly ngctl info ${iface}bridge:; then
ngctl mkpeer $iface: bridge lower link0 || return
ngctl connect $iface: $iface:lower upper link1 ||
return
@@ -316,11 +362,10 @@
# Optionally create a secondary bridge
if [ "$bridge" != "bridge" ] &&
- ! ngctl info "$iface$bridge:" > /dev/null 2>&1
+ ! quietly ngctl info "$iface$bridge:"
then
num=2
- while ngctl msg ${iface}bridge: getstats $num \
- > /dev/null 2>&1
+ while quietly ngctl msg ${iface}bridge: getstats $num
do
num=$(( $num + 1 ))
done
@@ -332,47 +377,79 @@
# Create a new interface to the bridge
num=2
- while ngctl msg "$iface$bridge:" getstats $num > /dev/null 2>&1
- do
+ while quietly ngctl msg "$iface$bridge:" getstats $num; do
num=$(( $num + 1 ))
done
- ngctl mkpeer "$iface$bridge:" eiface link$num ether || return
+ 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
# Rename the new interface
- while [ ${#eiface} -gt 15 ]; do # OS limitation
- eiface=${eiface%?}
+ while [ ${#jiface} -gt 15 ]; do # OS limitation
+ jiface=${jiface%?}
done
- new=$( set -- `ngctl show -n "$iface$bridge:link$num"` &&
- echo $2 ) || return
- ngctl name "$iface$bridge:link$num" $eiface || return
- ifconfig $new name $eiface || return
- ifconfig $eiface up || return
+ 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
+ ifconfig $new name $jiface || return
+ ifconfig $jiface up || return
#
# Set the MAC address of the new interface using a sensible
# algorithm to prevent conflicts on the network.
#
- eiface_devid=
+ jiface_devid=
if [ "$clone_mac" ]; then
- eiface_devid=$( ifconfig $iface ether |
+ jiface_devid=$( ifconfig $iface ether |
awk '/ether/,$0=$2' )
elif [ ! "$no_derive" ]; then
- derive_mac $iface "$name" eiface_devid
+ derive_mac $iface "$name" jiface_devid
fi
- [ "$eiface_devid" ] &&
- ifconfig $eiface ether $eiface_devid > /dev/null 2>&1
+ [ "$jiface_devid" ] &&
+ quietly ifconfig $jiface ether $jiface_devid
i=$(( $i + 1 ))
done # for iface
}
-jng_graph_usage="graph [-f] [-T type] [-o output]"
+jng_graph_usage="graph [-fh] [-T type] [-o output]"
jng_graph_descr="Generate network graph (default output is \`jng.svg')"
jng_graph()
{
local OPTIND=1 OPTARG flag
local output=jng.svg output_type= force=
- while getopts fo:T: flag; do
+ while getopts fho:T: flag; do
case "$flag" in
f) force=1 ;;
o) output="$OPTARG" ;;
@@ -381,8 +458,11 @@
esac
done
shift $(( $OPTIND - 1 ))
- [ $# -eq 0 -a "$output" ] || action_usage graph # NOTREACHED
+
+ [ $# -eq 0 ] || action_usage graph "too many arguments" # NOTREACHED
+
mustberoot_to_continue
+
if [ -e "$output" -a ! "$force" ]; then
echo "$output: Already exists (use \`-f' to overwrite)" >&2
return $FAILURE
@@ -399,21 +479,25 @@
ngctl dot | dot ${output_type:+-T "$output_type"} -o "$output"
}
-jng_show_usage="show"
+jng_show_usage="show [-h]"
jng_show_descr="List possible NAME values for \`show NAME'"
-jng_show1_usage="show NAME"
+jng_show1_usage="show [-h] NAME ..."
jng_show1_descr="Lists ng0_NAME [ng1_NAME ...]"
-jng_show2_usage="show [NAME]"
+jng_show2_usage="show [NAME ...]"
+jng_show2_descr="List NAME values or show interfaces associated with NAME."
jng_show()
{
local OPTIND=1 OPTARG flag
- while getopts "" flag; do
+ local name
+ while getopts h flag; do
case "$flag" in
*) action_usage show2 # NOTREACHED
esac
done
shift $(( $OPTIND - 1 ))
+
mustberoot_to_continue
+
if [ $# -eq 0 ]; then
ngctl ls | awk '$4=="bridge",$0=$2' |
xargs -rn1 -Ibridge ngctl show bridge: |
@@ -421,69 +505,165 @@
sort -u
return
fi
- ngctl ls | awk -v name="$1" '
- match($2, /^ng[[:digit:]]+_/) &&
- substr($2, RSTART + RLENGTH) == name &&
- $4 == "eiface", $0 = $2
- ' | sort
+ 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
+ ' | sort
+ done
}
-jng_shutdown_usage="shutdown NAME"
+jng_shutdown_usage="shutdown [-h] NAME ..."
jng_shutdown_descr="Shutdown ng0_NAME [ng1_NAME ...]"
jng_shutdown()
{
local OPTIND=1 OPTARG flag
- while getopts "" flag; do
+ while getopts h flag; do
case "$flag" in
*) action_usage shutdown # NOTREACHED
esac
done
shift $(( $OPTIND -1 ))
- local name="$1"
- [ "${name:-x}" = "${name#*[!0-9a-zA-Z_]}" -a $# -eq 1 ] ||
- action_usage shutdown # NOTREACHED
+
+ [ $# -gt 0 ] || action_usage shutdown "too few arguments" # NOTREACHED
+
mustberoot_to_continue
- jng_show "$name" | xargs -rn1 -I eiface ngctl shutdown eiface:
+
+ local name
+ for name in "$@"; do
+ [ "${name:-x}" = "${name#*[!0-9a-zA-Z_]}" ] ||
+ action_usage shutdown "invalid name: %s" "$name"
+ # NOTREACHED
+ jng_show "$name" | xargs -rn1 -I jiface ngctl shutdown jiface:
+ done
}
-jng_stats_usage="stats NAME"
+jng_stats_usage="stats [-h] {-a | NAME ...}"
jng_stats_descr="Show ng_bridge link statistics for NAME interfaces"
jng_stats()
{
local OPTIND=1 OPTARG flag
- while getopts "" flag; do
+ local show_all=
+ local name iface ether=
+ while getopts ahj flag; do
case "$flag" in
+ a) show_all=1 ;;
+ j) STATS_FMT=json
+ export pgm
+ : "${HOSTNAME:=$( hostname )}"
+ export HOSTNAME
+ ;;
*) action_usage stats # NOTREACHED
esac
done
shift $(( $OPTIND -1 ))
- local name="$1"
- [ "${name:-x}" = "${name#*[!0-9a-zA-Z_]}" -a $# -eq 1 ] ||
- action_usage stats # NOTREACHED
+ if [ "$show_all" ]; then
+ [ $# -eq 0 ] ||
+ action_usage stats "too many arguments" # NOTREACHED
+
+ # Get a list of bridged ng_ether(4) devices
+ for iface in $( ifconfig -l ); do
+ quietly ngctl info ${iface}bridge: || continue
+ ether="$ether $iface"
+ done
+ set -- $ether $( "$0" show )
+ [ $# -gt 0 ] ||
+ action_usage stats "no bridged interfaces" # NOTREACHED
+ else
+ [ $# -gt 0 ] ||
+ action_usage stats "too few arguments" # NOTREACHED
+ fi
+
mustberoot_to_continue
- for eiface in $( jng_show "$name" ); do
- echo "$eiface:"
- ngctl show $eiface: | awk '
- $3 == "bridge" && $5 ~ /^link/ {
- bridge = $2
- link = substr($5, 5)
- system(sprintf("ngctl msg %s: getstats %u",
- bridge, link))
- }' | fmt 2 | awk '
- /=/ && fl = index($0, "=") {
- printf "%20s = %s\n",
- substr($0, 0, fl-1),
- substr($0, 0, fl+1)
- }
- ' # END-QUOTE
+
+ local now="$( date +%s )"
+ for name in "$@"; do
+ [ "${name:-x}" = "${name#*[!0-9a-zA-Z_]}" ] ||
+ action_usage stats "invalid name: %s" "$name"
+ # NOTREACHED
+ 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 |
+ fmt_stats -n "${name}.lower" -t "$now"
+
+ [ "$STATS_FMT" != "text" ] ||
+ echo "${name}bridge:link0 [lower]"
+ ngctl msg ${name}bridge: getstats 1 |
+ fmt_stats -n "${name}.upper" -t "$now"
+ fi
+ local jiface
+ for jiface in $( jng_show "$name" ); do
+ [ "$STATS_FMT" != "text" ] || echo "$jiface:"
+ ngctl show $jiface: | awk '
+ $3 == "bridge" && $5 ~ /^link/ {
+ bridge = $2
+ link = substr($5, 5)
+ system(sprintf("ngctl msg %s: getstats %u",
+ bridge, link))
+ }' | fmt_stats -n "$jiface" -t "$now"
+ done
done
}
+fmt_stats()
+{
+ local OPTIND=1 OPTARG flag
+ while getopts n:t: flag; do
+ case "$flag" in
+ n) name="$OPTARG" ;;
+ t) time="$OPTARG" ;;
+ *) break
+ esac
+ done
+ shift $(( OPTIND - 1 ))
+ fmt 2 | awk -v fmt="$STATS_FMT" -v name="$name" -v tm="$time" '
+ function json_add_str(pre, k, s)
+ {
+ return sprintf("%s,\"%s\":\"%s\"", pre, k, s)
+ }
+ function json_add_int(pre, k, i)
+ {
+ return sprintf("%s,\"%s\":%d", pre, k, i)
+ }
+ BEGIN {
+ if (fmt == "json") {
+ if (time == "") srand() # Time-seed
+ js = json_add_int(js, "epoch",
+ time != "" ? time : srand())
+ js = json_add_str(js, "hostname",
+ ENVIRON["HOSTNAME"])
+ js = json_add_str(js, "program",
+ ENVIRON["pgm"])
+ js = json_add_str(js, "name", name)
+ }
+ }
+ /=/ && fl = index($0, "=") {
+ key = substr($0, 0, fl-1)
+ val = substr($0, fl+1)
+ if (fmt == "json") {
+ js = json_add_int(js, key, val)
+ } else { # Multi-line text
+ printf "%20s = %s\n", key, val
+ }
+ }
+ END {
+ if (fmt == "json") {
+ print "{" substr(js, 2) "}"
+ }
+ }
+ ' # END-QUOTE
+}
############################################################ MAIN
#
# Command-line arguments
#
+[ $# -gt 0 ] || usage "too few arguments" # NOTREACHED
action="$1"
[ "$action" ] || usage # NOTREACHED
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Mon, May 18, 12:16 PM (1 h, 5 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
33247928
Default Alt Text
D43516.id133055.diff (13 KB)
Attached To
Mode
D43516: New version of jng (2.0)
Attached
Detach File
Event Timeline
Log In to Comment