-
-
Save sassyn/9d1ef5811d7672e9138ebdd8fb46d428 to your computer and use it in GitHub Desktop.
Script to enable IP multicast without using Ethernet broadcast. It uses tc mirred and pedit actions to copy and edit an IP multicast packet to send over multiple Ethernet unicast frames. It requires two network interfaces to work. One is the interface to grab original multicast packets from and the other is to send out modified packets. This is …
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/sh | |
[[ -n "$1" && -n "$2" ]] || { echo "Usage: $0 <interface to grab multicast packets from> <interface to send modified packets to> [target MAC address 1] [target MAC address 2] ..."; exit 0 ; } | |
IIF=$1 | |
OIF=$2 | |
shift | |
shift | |
SRC_MACADDR=`ip link show $OIF | awk '/ether/ {print $2}' | tr -d :` | |
HANDLE=10 | |
TC=tc | |
BASE_PRIO=100 | |
# File which stores the priority of the tc filter that is to be registered | |
PRIO_FILE=/var/run/ec2_broadcastd_tc_prio | |
# Load the priority that the previous filter is registered with | |
if [ -r $PRIO_FILE ]; then | |
BASE_PRIO=`cat $PRIO_FILE` | |
fi | |
# Determine the priority that the new filter will be registered with | |
# (Any number which is different from the previous one is fine unless | |
# other filters exist.) | |
if [ `expr $BASE_PRIO % 2` -eq 1 ]; then | |
PRIO=`expr $BASE_PRIO + 1` | |
else | |
PRIO=`expr $BASE_PRIO - 1` | |
fi | |
# Create queue discipline for the origin network interface | |
$TC qdisc add dev $IIF root handle ${HANDLE}: prio >& /dev/null | |
# Calculate bit mask for modifying packet ID. (We will send duplicate IP packets. | |
# In order not to break underlying packet fragmentation and reconstruction, | |
# each IP packet needs to have different ID) | |
RETAIN_MASK=0xfff0 | |
# Create the list of actions to apply to outgoing multicast packets | |
i=0 | |
for DST_MACADDR in $* | |
do | |
DST_MACADDR=`echo $DST_MACADDR | tr -d :` | |
if [ "${actions}X" != "X" ]; then | |
# Action to mirror the filtered packet to the outgoing interface | |
actions="$actions action mirred egress mirror dev $OIF " | |
fi | |
# Actions to modify Ethernet header | |
# Offset 0 is the beginning of the IP header | |
# Offset has to be factor of 4 | |
# Last a few bits of the packet ID are modified to make each packet unique | |
actions="$actions action pedit | |
munge offset -16 u32 set 0x0000`echo $DST_MACADDR | cut -c 1-4` | |
munge offset -12 u32 set 0x`echo $DST_MACADDR | cut -c 5-12` | |
munge offset -8 u32 set 0x`echo $SRC_MACADDR | cut -c 1-8` | |
munge offset 4 u16 set 0x`printf "%04x" $i` retain $RETAIN_MASK pipe " | |
# Recalculate IP header checksum because we have modified the packet ID field | |
actions="$actions action csum ip4h pipe " | |
i=`expr $i + 1` | |
done | |
# Action to redirect the filtered packet to the outgoing interface | |
# (Note that this suppresses to send out the original frame with | |
# the broadcast address.) | |
actions="$actions action mirred egress redirect dev $OIF" | |
# Register the filter that matches ethernet broadcast frames which | |
# carry IP packets addressed to class D (IP multicast) | |
$TC filter add dev $IIF parent ${HANDLE}: protocol ip prio $PRIO u32 \ | |
match u8 0x01 0x01 at 0 match u8 0xe0 0xe0 at 16 $actions | |
# Delete the old filter if exists | |
if [ -r $PRIO_FILE ]; then | |
$TC filter del dev $IIF parent ${HANDLE}: prio $BASE_PRIO | |
fi | |
# Store the priority used for the filter for future reference | |
echo $PRIO > $PRIO_FILE |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment