Skip to content

Instantly share code, notes, and snippets.

@hellt
Last active November 10, 2024 13:06
Show Gist options
  • Save hellt/3626a753a74e3e5a950c71e6b294543f to your computer and use it in GitHub Desktop.
Save hellt/3626a753a74e3e5a950c71e6b294543f to your computer and use it in GitHub Desktop.
Virsh interface move
#!/bin/bash
# usage ~/vifmove.sh <virsh_domain_name/id> <interface_name> <new_bridge_name>
tmpxml=$(mktemp /tmp/ifcfg.XXX)
macaddr="$(virsh domiflist $1 | awk "/$2\s/ {print \$NF}")"
cat > "$tmpxml" <<EOF
<interface type='bridge'>
<mac address='$macaddr'/>
<source bridge='$3'/>
<model type='virtio'/>
</interface>
EOF
virsh update-device "$1" "$tmpxml" --live --persistent
rm "$tmpxml"
@Znuff
Copy link

Znuff commented Dec 19, 2021

#!/bin/bash
# usage ~/vifmove.sh <virsh_domain_name/id> <interface_name> <new_bridge_name>
function update_bridge() {
  tmpxml=$(mktemp /tmp/ifcfg.XXX)
  macaddr="$(virsh domiflist $1 | awk "/$2\s/ {print \$NF}")"
  model="$(virsh domiflist $1 | awk "/$2\s/ {print \$4F}")"

  cat > "$tmpxml" <<EOF
<interface type='bridge'>
<mac address='$macaddr'/>
<source bridge='$3'/>
<model type='$model'/>
</interface>
EOF
  virsh update-device "$1" "$tmpxml" --live
  rm "$tmpxml"
}

for domain in $(virsh list --uuid); do
  update_bridge $domain $1 $2
done

I've added some bits to do all VMs in a batch.

@jacob-wm
Copy link

jacob-wm commented Apr 1, 2022

Added this to the end, for interfaces that have DHCP, it will bring it down and back up to refresh network. Note this only works for one interface, assumes you have DHCP in the guest, but the original script only assumes one interface per bridge anyway.

#!/bin/bash
# usage ~/vifmove.sh <virsh_domain_name/id> <interface_name> <new_bridge_name>
tmpxml=$(mktemp /tmp/ifcfg.XXX)
macaddr="$(virsh domiflist $1 | awk "/$2\s/ {print \$NF}")"
cat > "$tmpxml" <<EOF
<interface type='bridge'>
<mac address='$macaddr'/>
<source bridge='$3'/>
<model type='virtio'/>
</interface>
EOF
virsh update-device "$1" "$tmpxml" --live --persistent
rm "$tmpxml"
netintface=`virsh domiflist $1 | grep $3 | awk '{print $1}'`
echo $netintface
virsh domif-setlink "$1" $netintface down
sleep 2
virsh domif-setlink "$1" $netintface up

@tonusoo
Copy link

tonusoo commented Nov 10, 2024

A version which finds the <virsh_domain_name/id> automatically:

#!/usr/bin/env bash

# usage ~/vifmove.sh <interface_name> <new_bridge_name>

# Script expects that VMs are installed under system libvirtd instance(qemu:///system URI) and not under
# session libvirtd instance(qemu:///session URI).

error_and_exit() {
    echo "ERROR: $1" >&2
    exit 1
}


(( $# != 2 )) && error_and_exit "Usage: sudo ${0##*/} <interface_name> <new_bridge_name>"
(( EUID != 0 )) && error_and_exit "Script needs to be executed as a root user."


# Check if the <new_bridge_name> exists.
[[ ! -d /sys/class/net/$2/bridge ]] && error_and_exit "Linux bridge $2 does not exist"


while read -r vm_id vm_name vm_state; do

    # VMs which are not running have the "-" on Id field.
    [[ "$vm_id" == - ]] || [[ "$vm_id" =~ ^[0-9]+$ ]] || continue

    while read -r int_name int_type int_source int_model int_mac_addr; do

        [[ "$int_type" != "bridge" ]] && continue
        [[ "$int_name" == "$1" ]] && break 2

    done < <(virsh domiflist "$vm_name")

done < <(virsh list --all)

[[ -z "$int_name" ]] && error_and_exit "None of the VMs have the 'bridge' type $1 interface associated"

if [[ "$2" == "$int_source" ]]; then
    echo "$1 is already connected to $2"
    exit
fi

tmp_xml=$(mktemp "/tmp/${0##*/}.XXXXXXXX")

cat << EOF > "$tmp_xml"
<interface type='bridge'>
  <mac address='$int_mac_addr'/>
  <source bridge='$2'/>
  <target dev='$1'/>
  <model type='$int_model'/>
</interface>
EOF


# Temporary XML file for "virsh update-device" is removed only if the
# "virsh update-device" succeeds. This is for troubleshooting purposes.
if [[ "$vm_state" == "running" ]] || [[ "$vm_state" == "paused" ]]; then

    if virsh update-device "$vm_name" "$tmp_xml" --config --live; then
        echo "Connected $int_name from bridge $int_source to bridge $2 and updated $vm_name XML"
        rm -f "$tmp_xml"
    fi

else

    if virsh update-device "$vm_name" "$tmp_xml" --config; then
        echo "Updated $vm_name XML with $int_name connected to $2 bridge"
        rm -f "$tmp_xml"
    fi

fi

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment