updated: 27th of November 2021
published: 26th of November 2021
In a previous post I showed you how to configure a port-mirror in Proxmox. In that post, I used a bit of a dirty hack (bash scripts and crontab) to ensure the port-mirror is activated if the host or the VM reboots.
Luckily for me, I have some really smart colleagues who mentioned that in libvirt, there is a hook mechanism that can be used to trigger scripts based on VM state. A quick duck hunt revealed that Proxmox has implemented this feature as well 🥳
In this post I will show you how to use Hook Scripts with Proxmox to enable/disable a port-mirror depending on the VMs execution phase .
As an added bonus, I will also show you how to duplicate a port-mirror source, to multiple destinations within Proxmox.
The following software was used in this post.
The following diagram show the lab setup outlined in this post. The goal, is to have traffic port-mirrored from the Juniper switch to both the eda01 and eta01 VMs. Both the eda01 and eta01 VMs need a dedicated feed therefore, port-mirror traffic will be duplicated on vmbr1
The following points summarise the diagram.
As previously mentioned, hook scripts allow you to run a script based on a VMs execution phase .
This feature is not extensively documented (that I could find). From what I can gather the supported phases are:
An example hook script can be found in the onboard docs at the following location:
/usr/share/pve-docs/examples/guest-example-hookscript.pl
For all you Perl loving heathons, that should be right up your alley. For everyone else, it looks like you can run a script in any language that has a runtime installed.
For my purposes, I will be using the bash script from the previous post with a couple of alterations to make it more portable and useable for multiple guests.
Hook scripts need to be stored in a snippets/ directory on a storage pool that Proxmox knows about. I will place my scripts in the /var/lib/vz/ directory that maps to the local storage pool.
Create a file named extrahop-port-mirror.sh in the /var/lib/vz/snippets/ directory with the following contents.
#! /usr/bin/env bash
# /var/lib/vz/snippets/extrahop-port-mirror.sh
VM_ID=$1;
EXECUTION_PHASE=$2
SOURCE_PORT="enp1s0";
VM_BRIDGE="vmbr1";
LOGGING=/root/scripts/extrahop-port-mirror.log;
function create_mirror {
/usr/bin/date >> $LOGGING;
/usr/bin/echo "Creating mirror on $VM_BRIDGE for $VM_ID"... >> $LOGGING;
/usr/bin/ovs-vsctl \
-- --id=@"$SOURCE_PORT" get Port "$SOURCE_PORT" \
-- --id=@tap"$VM_ID"i1 get Port tap"$VM_ID"i1 \
-- --id=@"$VM_ID"m create \
Mirror name="$VM_ID"-mirror \
select-dst-port=@"$SOURCE_PORT" \
select-src-port=@"$SOURCE_PORT" \
output-port=@tap"$VM_ID"i1 \
-- add Bridge "$VM_BRIDGE" mirrors @"$VM_ID"m; >> $LOGGING;
/usr/bin/echo "####################" >> $LOGGING;
}
function clear_mirror {
/usr/bin/date >> $LOGGING;
/usr/bin/echo "Clearing mirror on $VM_BRIDGE for $VM_ID..." >> $LOGGING;
/usr/bin/ovs-vsctl \
-- --id=@"$VM_ID"m get Mirror "$VM_ID"-mirror \
-- remove Bridge "$VM_BRIDGE" mirrors @"$VM_ID"m; >> $LOGGGING;
/usr/bin/echo "####################" >> $LOGGING;
}
function show_mirrors {
/usr/bin/date >> $LOGGING;
/usr/bin/echo "Show existing mirrors..." >> $LOGGING;
/usr/bin/ovs-vsctl list Mirror >> $LOGGING;
/usr/bin/echo "####################" >> $LOGGING;
}
if [[ "$EXECUTION_PHASE" == "post-start" ]]; then
clear_mirror;
create_mirror;
show_mirrors;
elif [[ "$EXECUTION_PHASE" == "pre-stop" ]]; then
clear_mirror;
show_mirrors;
fi
When Proxmox executes this script, it does so with 2 arguments.
These arguments can be mapped to variables in the script. In my case I am mapping them as follows.
The other variables: SOURCE_PORT , VM_BRIDGE and LOGGING should be confirgured to match your setup.
This script allows you to add and remove multiple port-mirror destinations by using the add and remove commands rather than the set and clear commands from the previous post.
The other thing that is required, is to make the script executable.
chmod +x /var/lib/vz/snippets/extrahop-port-mirror.sh
Now that the hook script is created, we need to connect it to a VM. Connect the hookscript to both the eda01 and eta01 VMs with the following command.
qm set 201 --hookscript local:snippets/extrahop-port-mirror.sh
qm set 204 --hookscript local:snippets/extrahop-port-mirror.sh
# Output
update VM 201: -hookscript local:snippets/extrahop-port-mirror.sh
update VM 204: -hookscript local:snippets/extrahop-port-mirror.sh
That's it! Now when the VM or host shuts down or restarts, the port mirror will be automagically activated/deactivated. Additionally, vmbr1 is sending a duplicate data feed to both the eda01 and eta01.
If for some reason you want to disconnect a hook script from a VM, use the following command.
qm set 201 --delete hookscript
# Output
update VM 201: -delete hookscript
Below is an example of the log file that is generated.
####################
Sat Nov 27 06:24:50 AEST 2021
Clearing mirror on vmbr1 for 204...
####################
Sat Nov 27 06:24:50 AEST 2021
Show existing mirrors...
_uuid : 89c4a723-130d-4871-a84d-d143e165ec7d
external_ids : {}
name : "201-mirror"
output_port : a9e16d6a-2010-484e-a924-cb4f1a46195f
output_vlan : []
select_all : false
select_dst_port : [dbd6b1f0-2cf0-453c-881e-a888f655e83a]
select_src_port : [dbd6b1f0-2cf0-453c-881e-a888f655e83a]
select_vlan : []
snaplen : []
statistics : {tx_bytes=82504527671, tx_packets=82870736}
####################
Sat Nov 27 06:25:03 AEST 2021
Clearing mirror on vmbr1 for 204...
####################
Sat Nov 27 06:25:03 AEST 2021
Creating mirror on vmbr1 for 204...
####################
Sat Nov 27 06:25:03 AEST 2021
Show existing mirrors...
_uuid : 7c33f30a-2bdf-44d2-8ce2-8d7d92d5cc7f
external_ids : {}
name : "204-mirror"
output_port : e36be586-eda1-44e1-b6d0-45b802b16ecf
output_vlan : []
select_all : false
select_dst_port : [dbd6b1f0-2cf0-453c-881e-a888f655e83a]
select_src_port : [dbd6b1f0-2cf0-453c-881e-a888f655e83a]
select_vlan : []
snaplen : []
statistics : {}
_uuid : 89c4a723-130d-4871-a84d-d143e165ec7d
external_ids : {}
name : "201-mirror"
output_port : a9e16d6a-2010-484e-a924-cb4f1a46195f
output_vlan : []
select_all : false
select_dst_port : [dbd6b1f0-2cf0-453c-881e-a888f655e83a]
select_src_port : [dbd6b1f0-2cf0-453c-881e-a888f655e83a]
select_vlan : []
snaplen : []
statistics : {tx_bytes=82511889277, tx_packets=82881722}
####################
In this post, I showed you how use a Proxmox hook script to automagically start/stop a port-mirror destined for multiple VMs connected to the same virtual bridge. I believe this method is a nice improvement over my previous attempt and I hope you find it useful.
https://pve.proxmox.com/pve-docs/pve-admin-guide.html#_hookscripts
https://github.com/ayufan/pve-helpers
https://forum.proxmox.com/threads/change-remove-hookscript-from-lxc-container.97567/