The branch main has been updated by dteske:

URL: 
https://cgit.FreeBSD.org/src/commit/?id=19b0b1f648d8f114f77e82495618587b1729c4cc

commit 19b0b1f648d8f114f77e82495618587b1729c4cc
Author:     Devin Teske <[email protected]>
AuthorDate: 2026-09-03 06:17:52 +0000
Commit:     Devin Teske <[email protected]>
CommitDate: 2026-09-03 06:17:52 +0000

    examples/jails: Encode ifnames used as derive_mac counters
    
    derive_mac keeps a per-parent branch index in a global named from the
    parent interface so the N nibble can increment when the same PHY is
    presented more than once. That name must be a POSIX identifier; a
    vlan-style parent (em0.20) is not.
    
    Encode the ifname first (alnum unchanged, every other byte as _HH) so
    the lookup stays a symbol-table hit and em0.20 does not collide with
    em0_20. Same change in jib (9.2) and jng (9.4).
    
    In jng, also address netgraph by node name. ngctl(8) treats `.' and
    `:' as control characters, so ng_ether(4) names its node after the
    sanitized ifname (vtnet0.20 becomes vtnet0_20). Sanitize the parent
    ifname where it enters and use that for every ngctl call; ifconfig(8)
    and derive_mac keep the real name. Previously jng failed outright on
    such parents where jib did not.
    
    PR:             291143
    Reported by:    Victor <[email protected]>
    MFC after:      1 week
    Reviewed by:    jlduran
    Differential Revision:  https://reviews.freebsd.org/D59326
---
 share/examples/jails/jib | 32 +++++++++++++---
 share/examples/jails/jng | 99 +++++++++++++++++++++++++++++++++---------------
 2 files changed, 96 insertions(+), 35 deletions(-)

diff --git a/share/examples/jails/jib b/share/examples/jails/jib
index 44d53c44bf11..b18c60da15ec 100755
--- a/share/examples/jails/jib
+++ b/share/examples/jails/jib
@@ -7,7 +7,7 @@
 ############################################################ IDENT(1)
 #
 # $Title: if_bridge(4) management script for vnet jails $
-# $Version: 9.1 $
+# $Version: 9.2 $
 #
 ############################################################ INFORMATION
 #
@@ -111,7 +111,7 @@
 #
 ############################################################ GLOBALS
 
-VERSION='$Version: 9.1 $'
+VERSION='$Version: 9.2 $'
 
 pgm="${0##*/}" # Program basename
 
@@ -157,6 +157,25 @@ action_usage()
        exit $FAILURE
 }
 
+iface_encode()
+{
+       LC_ALL=C iface="$1" awk 'BEGIN {
+               for (n = 0; n < 256; n++)
+                       pack[sprintf("%c", n)] = sprintf("_%02x", n)
+               numbers = "0123456789"
+               uppercase = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+               lowercase = "abcdefghijklmnopqrstuvwxyz"
+               valid = "[" numbers uppercase lowercase "]"
+               iface = ENVIRON["iface"]
+               len = length(iface)
+               for (n = 1; n <= len; n++) {
+                       let = substr(iface, n, 1)
+                       _iface = _iface (let ~ valid ? let : pack[let])
+               }
+               print _iface
+       }'
+}
+
 derive_mac()
 {
        local OPTIND=1 OPTARG __flag
@@ -169,13 +188,16 @@ derive_mac()
        done
        shift $(( $OPTIND - 1 ))
 
+       local __iface="$1"
        if [ ! "$__mac_num" ]; then
-               eval __mac_num=\${_${iface}_num:--1}
+               local __iface_encoded
+               __iface_encoded=$( iface_encode "$__iface" )
+               eval __mac_num=\${_${__iface_encoded}_num:--1}
                __mac_num=$(( $__mac_num + 1 ))
-               eval _${iface}_num=\$__mac_num
+               eval _${__iface_encoded}_num=\$__mac_num
        fi
 
-       local __iface="$1" __name="$2" __var_to_set="$3" __var_to_set_b="$4"
+       local __name="$2" __var_to_set="$3" __var_to_set_b="$4"
        local __iface_devid __new_devid __num __new_devid_b
        #
        # Calculate MAC address derived from given iface.
diff --git a/share/examples/jails/jng b/share/examples/jails/jng
index 48dc3eb67967..db7f16334884 100755
--- a/share/examples/jails/jng
+++ b/share/examples/jails/jng
@@ -7,7 +7,7 @@
 ############################################################ IDENT(1)
 #
 # $Title: netgraph(4) management script for vnet jails $
-# $Version: 9.3 $
+# $Version: 9.4 $
 #
 ############################################################ INFORMATION
 #
@@ -138,7 +138,7 @@ NG_BRIDGE_MAX_STALENESS=4294967295
 
 ############################################################ GLOBALS
 
-VERSION='$Version: 9.3 $'
+VERSION='$Version: 9.4 $'
 
 pgm="${0##*/}" # Program basename
 
@@ -214,6 +214,25 @@ action_usage()
        die
 }
 
+iface_encode()
+{
+       LC_ALL=C iface="$1" awk 'BEGIN {
+               for (n = 0; n < 256; n++)
+                       pack[sprintf("%c", n)] = sprintf("_%02x", n)
+               numbers = "0123456789"
+               uppercase = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+               lowercase = "abcdefghijklmnopqrstuvwxyz"
+               valid = "[" numbers uppercase lowercase "]"
+               iface = ENVIRON["iface"]
+               len = length(iface)
+               for (n = 1; n <= len; n++) {
+                       let = substr(iface, n, 1)
+                       _iface = _iface (let ~ valid ? let : pack[let])
+               }
+               print _iface
+       }'
+}
+
 derive_mac()
 {
        local OPTIND=1 OPTARG __flag
@@ -226,13 +245,16 @@ derive_mac()
        done
        shift $(( $OPTIND - 1 ))
 
+       local __iface="$1"
        if [ ! "$__mac_num" ]; then
-               eval __mac_num=\${_${iface}_num:--1}
+               local __iface_encoded
+               __iface_encoded=$( iface_encode "$__iface" )
+               eval __mac_num=\${_${__iface_encoded}_num:--1}
                __mac_num=$(( $__mac_num + 1 ))
-               eval _${iface}_num=\$__mac_num
+               eval _${__iface_encoded}_num=\$__mac_num
        fi
 
-       local __iface="$1" __name="$2" __var_to_set="$3" __var_to_set_b="$4"
+       local __name="$2" __var_to_set="$3" __var_to_set_b="$4"
        local __iface_devid __new_devid __num __new_devid_b
        #
        # Calculate MAC address derived from given iface.
@@ -391,6 +413,16 @@ jng_pin_jiface()
        jng_bridge_persist_hosts "$pbridge" || : persist optional
 }
 
+ng_ether_sanitize_ifname()
+{
+       # NB: Emulates function of same name in sys/netgraph/ng_ether.c
+       ifname="$1" awk 'BEGIN {
+               _ifname = ENVIRON["ifname"]
+               gsub(/[.:]/, "_", _ifname)
+               print _ifname
+       }'
+}
+
 jng_bridge_usage="bridge [-h] [-b BRIDGE_NAME] NAME [!|=]iface0 [[!|=]iface1 
...]"
 jng_bridge_descr="Create ng0_NAME [ng1_NAME ...]"
 jng_bridge()
@@ -417,7 +449,7 @@ jng_bridge()
 
        mustberoot_to_continue
 
-       local iface parent jiface jiface_devid
+       local iface node parent jiface jiface_devid
        local new clone_mac no_derive num quad mtu i=0
        for iface in $*; do
 
@@ -428,6 +460,10 @@ jng_bridge()
                !*) iface=${iface#!} no_derive=1 ;;
                esac
 
+               # ngctl(8) treats `.' and `:' as control characters, so
+               # ng_ether(4) names its node after the sanitized ifname
+               node=$( ng_ether_sanitize_ifname "$iface" )
+
                # Make sure the interface doesn't exist already
                jiface=ng${i}_$name
                if quietly ngctl msg "$jiface:" getifname; then
@@ -439,18 +475,18 @@ jng_bridge()
                ifconfig $iface up || return
 
                # Set promiscuous mode and don't overwrite src addr
-               ngctl msg $iface: setpromisc 1 || return
-               ngctl msg $iface: setautosrc 0 || return
+               ngctl msg $node: setpromisc 1 || return
+               ngctl msg $node: 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 uplink1 || return
-                       ngctl connect $iface: $iface:lower upper link0 ||
+               if ! quietly ngctl info ${node}bridge:; then
+                       ngctl mkpeer $node: bridge lower uplink1 || return
+                       ngctl connect $node: $node:lower upper link0 ||
                                return
-                       ngctl name $iface:lower ${iface}bridge || return
-                       jng_bridge_persist_hosts ${iface}bridge ||
+                       ngctl name $node:lower ${node}bridge || return
+                       jng_bridge_persist_hosts ${node}bridge ||
                                : persist optional
                fi
 
@@ -459,33 +495,33 @@ jng_bridge()
                # Optionally create a secondary bridge
                # NB: This time, you want to only connect linkX (no uplinkX)
                if [ "$bridge" != "bridge" ] &&
-                  ! quietly ngctl info "$iface$bridge:"
+                  ! quietly ngctl info "$node$bridge:"
                then
                        num=1
-                       while quietly ngctl msg ${iface}bridge: getstats $num
+                       while quietly ngctl msg ${node}bridge: getstats $num
                        do
                                num=$(( $num + 1 ))
                        done
-                       ngctl mkpeer $iface:lower bridge link$num link0 ||
+                       ngctl mkpeer $node:lower bridge link$num link0 ||
                                return
-                       ngctl name ${iface}bridge:link$num "$iface$bridge" ||
+                       ngctl name ${node}bridge:link$num "$node$bridge" ||
                                return
                fi
 
                # Create a new interface to the bridge
                num=1
-               while quietly ngctl msg "$iface$bridge:" getstats $num; do
+               while quietly ngctl msg "$node$bridge:" getstats $num; do
                        num=$(( $num + 1 ))
                done
-               ngctl mkpeer "$iface$bridge:" eiface link$num ether || return
+               ngctl mkpeer "$node$bridge:" eiface link$num ether || return
 
                # Rename the new interface
                while [ ${#jiface} -gt 15 ]; do # OS limitation
                        jiface=${jiface%?}
                done
-               new=$( ngctl show -n "$iface$bridge:link$num" ) || return
+               new=$( ngctl show -n "$node$bridge:link$num" ) || return
                new=$( set -- $new; echo $2 )
-               ngctl name "$iface$bridge:link$num" $jiface || return
+               ngctl name "$node$bridge:link$num" $jiface || return
                ifconfig $new name $jiface || return
                ifconfig $jiface mtu $mtu || return
                ifconfig $jiface up || return
@@ -515,7 +551,7 @@ jng_pin()
 {
        local OPTIND=1 OPTARG flag
        local show_all= err=$SUCCESS
-       local name iface jiface
+       local name iface node jiface
 
        while getopts ah flag; do
                case "$flag" in
@@ -528,8 +564,9 @@ jng_pin()
                [ $# -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 ||
+                       node=$( ng_ether_sanitize_ifname "$iface" )
+                       quietly ngctl info ${node}bridge: || continue
+                       jng_bridge_persist_hosts ${node}bridge ||
                                : persist optional
                done
                set -- $( jls -q name 2> /dev/null )
@@ -663,7 +700,7 @@ jng_stats()
 {
        local OPTIND=1 OPTARG flag
        local show_all=
-       local name iface ether=
+       local name iface node ether=
        while getopts ahj flag; do
                case "$flag" in
                a) show_all=1 ;;
@@ -682,7 +719,8 @@ jng_stats()
 
                # Get a list of bridged ng_ether(4) devices
                for iface in $( ifconfig -l ); do
-                       quietly ngctl info ${iface}bridge: || continue
+                       node=$( ng_ether_sanitize_ifname "$iface" )
+                       quietly ngctl info ${node}bridge: || continue
                        ether="$ether $iface"
                done
                set -- $ether $( "$0" show )
@@ -702,14 +740,15 @@ jng_stats()
                        # NOTREACHED
                if ifconfig -l | xargs -n1 2> /dev/null | fgrep -qw "$name"
                then
+                       node=$( ng_ether_sanitize_ifname "$name" )
                        [ "$STATS_FMT" != "text" ] ||
-                               echo "${name}bridge:uplink1 [lower]"
-                       ngctl msg ${name}bridge: getstats -1 |
+                               echo "${node}bridge:uplink1 [lower]"
+                       ngctl msg ${node}bridge: getstats -1 |
                                fmt_stats -n "${name}.lower" -t "$now"
 
                        [ "$STATS_FMT" != "text" ] ||
-                               echo "${name}bridge:link0 [upper]"
-                       ngctl msg ${name}bridge: getstats 0 |
+                               echo "${node}bridge:link0 [upper]"
+                       ngctl msg ${node}bridge: getstats 0 |
                                fmt_stats -n "${name}.upper" -t "$now"
                fi
                local jiface

Reply via email to