diff mbox series

[v4,1/2] tools/hotplug/Linux: Add bridge VLAN support

Message ID 20240517140506.8460-2-leigh@solinno.co.uk (mailing list archive)
State New
Headers show
Series Finalise bridge VLAN support | expand

Commit Message

Leigh Brown May 17, 2024, 2:05 p.m. UTC
Update add_to_bridge shell function to read the vlan parameter from
xenstore and set the bridge VLAN configuration for the VID.

Add additional helper functions to parse the vlan specification,
which consists of one or more of the following:

a) single VLAN (e.g. 10).
b) contiguous range of VLANs (e.g. 10-15).
c) discontiguous range with base, increment and count
   (e.g. 100+10x9 which gives VLAN IDs 100, 110, ... 190).

A single VLAN can be suffixed with "p" to indicate the PVID, or
"u" to indicate untagged. A range of VLANs can be suffixed with
"u" to indicate untagged.  A complex example would be:

   vlan=1p/10-15/20-25u

This capability requires the iproute2 bridge command to be
installed.  An error will be generated if the vlan parameter is
set and the bridge command is not available.

Signed-off-by: Leigh Brown <leigh@solinno.co.uk>
---
 tools/hotplug/Linux/xen-network-common.sh | 109 ++++++++++++++++++++++
 1 file changed, 109 insertions(+)

Comments

Jason Andryuk May 18, 2024, 12:03 p.m. UTC | #1
On Fri, May 17, 2024 at 10:05 AM Leigh Brown <leigh@solinno.co.uk> wrote:
>
> Update add_to_bridge shell function to read the vlan parameter from
> xenstore and set the bridge VLAN configuration for the VID.
>
> Add additional helper functions to parse the vlan specification,
> which consists of one or more of the following:
>
> a) single VLAN (e.g. 10).
> b) contiguous range of VLANs (e.g. 10-15).
> c) discontiguous range with base, increment and count
>    (e.g. 100+10x9 which gives VLAN IDs 100, 110, ... 190).
>
> A single VLAN can be suffixed with "p" to indicate the PVID, or
> "u" to indicate untagged. A range of VLANs can be suffixed with
> "u" to indicate untagged.  A complex example would be:
>
>    vlan=1p/10-15/20-25u
>
> This capability requires the iproute2 bridge command to be
> installed.  An error will be generated if the vlan parameter is
> set and the bridge command is not available.
>
> Signed-off-by: Leigh Brown <leigh@solinno.co.uk>

Reviewed-by: Jason Andryuk <jason.andryuk@amd.com>

Thanks,
Jason
diff mbox series

Patch

diff --git a/tools/hotplug/Linux/xen-network-common.sh b/tools/hotplug/Linux/xen-network-common.sh
index 42fa704e8d..31d359b83c 100644
--- a/tools/hotplug/Linux/xen-network-common.sh
+++ b/tools/hotplug/Linux/xen-network-common.sh
@@ -121,10 +121,111 @@  create_bridge () {
     fi
 }
 
+_vif_vlan_add() {
+    # References vlans and pvid variables from the calling function
+    local -i vid=$1
+    local flag=${2:-}
+
+    if (( vid < 1 || vid > 4094 )) ;then
+        fatal "vlan id $vid not between 1 and 4094"
+    fi
+    if [[ -n "${vlans[$vid]}" ]] ;then
+        fatal "vlan id $vid specified more than once"
+    fi
+    case $flag in
+     p) if (( pvid != 0 )) ;then
+            fatal "more than one pvid specified ($vid and $pvid)"
+        fi
+        pvid=$vid
+        vlans[$vid]=p ;;
+     u) vlans[$vid]=u ;;
+     *) vlans[$vid]=t ;;
+    esac
+}
+
+_vif_vlan_parse_term() {
+    local vid incr last term=${1:-}
+
+    if [[ $term =~ ^([0-9]+)([pu])?$ ]] ;then
+        _vif_vlan_add ${BASH_REMATCH[1]} ${BASH_REMATCH[2]}
+    elif [[ $term =~ ^([0-9]+)-([0-9]+)(u)?$ ]] ;then
+        vid=${BASH_REMATCH[1]}
+        last=${BASH_REMATCH[2]}
+        if (( last >= vid )) ;then
+            for (( ; vid<=last; vid++ )) ;do
+                _vif_vlan_add $vid ${BASH_REMATCH[3]}
+            done
+        else
+            fatal "invalid vlan id range: $term"
+        fi
+    elif [[ $term =~ ^([0-9]+)\+([0-9]+)x([0-9]+)(u)?$ ]] ;then
+        vid=${BASH_REMATCH[1]}
+        incr=${BASH_REMATCH[2]}
+        for (( j=${BASH_REMATCH[3]}; j>0; --j, vid+=incr ))
+        do
+            _vif_vlan_add $vid ${BASH_REMATCH[4]}
+        done
+    else
+        fatal "invalid vlan specification: $term"
+    fi
+}
+
+_vif_vlan_validate_pvid() {
+    # References vlans and pvid variables from the calling function
+    if (( pvid == 0 )) ;then
+        if (( ${#vlans[@]} == 1 )) ;then
+            vlans[${!vlans[*]}]=p
+        else
+            fatal "pvid required when using multiple vlan ids"
+        fi
+    fi
+}
+
+_vif_vlan_setup() {
+    # References vlans and dev variable from the calling function
+    local -i vid
+    local -a args
+
+    # Remove the default vlan id automatically added to the vif
+    bridge vlan del dev $dev vid 1
+
+    # Add the required vlans
+    for vid in ${!vlans[@]} ;do
+        case ${vlans[$vid]} in
+             p) args=(pvid untagged) ;;
+             u) args=(untagged) ;;
+             t) args=() ;;
+        esac
+        bridge vlan add dev $dev vid $vid ${args[@]}
+    done
+}
+
+_vif_vlan_membership() {
+    # The vlans, pvid and dev variables are used by sub-functions
+    local -A vlans=()
+    local -a terms=()
+    local -i i pvid=0
+    local dev=$1 term
+
+    # Split the vlan specification string into its terms, removing the newline
+    # that readarray adds to the last element
+    readarray -d / -t terms <<<$2
+    terms[-1]=${terms[-1]%%[[:space:]]}
+
+    for term in ${terms[@]} ;do
+        _vif_vlan_parse_term $term
+    done
+
+    _vif_vlan_validate_pvid
+    _vif_vlan_setup
+    return 0
+}
+
 # Usage: add_to_bridge bridge dev
 add_to_bridge () {
     local bridge=$1
     local dev=$2
+    local vlan=$(xenstore_read_default "$XENBUS_PATH/vlan" "")
 
     # Don't add $dev to $bridge if it's already on the bridge.
     if [ ! -e "/sys/class/net/${bridge}/brif/${dev}" ]; then
@@ -134,6 +235,14 @@  add_to_bridge () {
         else
             ip link set ${dev} master ${bridge}
         fi
+        if [ -n "${vlan}" ] ;then
+            log debug "configuring vlans for ${dev} on ${bridge}"
+            if which bridge >&/dev/null; then
+                _vif_vlan_membership "${dev}" "${vlan}"
+            else
+                fatal "vlan configuration failed: bridge command not found"
+            fi
+        fi
     else
         log debug "$dev already on bridge $bridge"
     fi