mirror of
https://dev.iopsys.eu/feed/iopsys.git
synced 2025-12-10 07:44:50 +01:00
517 lines
14 KiB
Bash
Executable file
517 lines
14 KiB
Bash
Executable file
#!/bin/sh
|
|
# Install ebtables rules
|
|
|
|
BR_RULE=""
|
|
BR6_RULE=""
|
|
BR_RULE_DSCP2PBIT=""
|
|
DSCP2PBIT_MAPPING=""
|
|
|
|
init_broute_rule() {
|
|
BR_RULE=""
|
|
BR6_RULE=""
|
|
}
|
|
|
|
init_broute_dscp2pbit_rule() {
|
|
BR_RULE_DSCP2PBIT=""
|
|
DSCP2PBIT_MAPPING=""
|
|
}
|
|
|
|
broute_filter_on_l3_if() {
|
|
BR_RULE="$BR_RULE --logical-in $1"
|
|
}
|
|
|
|
broute_filter_on_src_if() {
|
|
BR_RULE="$BR_RULE --in-if $1"
|
|
}
|
|
|
|
broute_filter_on_src_mac() {
|
|
BR_RULE="$BR_RULE --src $1"
|
|
}
|
|
|
|
broute_filter_on_dst_mac() {
|
|
BR_RULE="$BR_RULE --dst $1"
|
|
}
|
|
|
|
broute_filter_on_pcp() {
|
|
# 5.04 onwards the vlan extension in ebtables is used for classification
|
|
# on the basis of vlan params which needs proto to be defined as 802_1Q in
|
|
# order to add a rule, now, proto can also be defined by specifying proto uci
|
|
# option as well as the rule may have a vlan id as well in which case the
|
|
# proto will already be present, hence, this check to not add --proto more
|
|
# than once
|
|
case "$BR_RULE" in
|
|
*proto*)
|
|
BR_RULE="$BR_RULE --vlan-prio $1"
|
|
;;
|
|
*)
|
|
BR_RULE="$BR_RULE --proto 802_1Q --vlan-prio $1"
|
|
;;
|
|
esac
|
|
}
|
|
|
|
broute_filter_on_ether_type() {
|
|
BR_RULE="$BR_RULE --proto $1"
|
|
}
|
|
|
|
broute_filter_on_ether_type6() {
|
|
BR6_RULE="$BR6_RULE --proto IPv6"
|
|
}
|
|
|
|
ebt_match_src_ip() {
|
|
BR_RULE="$BR_RULE --ip-src $1"
|
|
}
|
|
|
|
ebt_match_dst_ip() {
|
|
BR_RULE="$BR_RULE --ip-dst $1"
|
|
}
|
|
|
|
ebt_match_ipv6_src_ip() {
|
|
BR_RULE="$BR_RULE --ip6-src $1"
|
|
}
|
|
|
|
ebt_match_ipv6_dst_ip() {
|
|
BR_RULE="$BR_RULE --ip6-dst $1"
|
|
}
|
|
|
|
ebt_match_ip_src_port() {
|
|
BR_RULE="$BR_RULE --ip-source-port $1"
|
|
}
|
|
|
|
ebt_match_ip_dst_port() {
|
|
BR_RULE="$BR_RULE --ip-destination-port $1"
|
|
}
|
|
|
|
ebt_match_ipv6_src_port() {
|
|
#when ethertype is not configured by user then both proto rules of ipv4
|
|
#and ipv6 to be installed so update BR6_RULE string as well otherwise
|
|
#update BR_RULE only for installation of ipv6 proto rule only.
|
|
if [ -n "$BR6_RULE" ]; then
|
|
BR6_RULE="$BR6_RULE --ip6-source-port $1"
|
|
else
|
|
BR_RULE="$BR_RULE --ip6-source-port $1"
|
|
fi
|
|
}
|
|
|
|
ebt_match_ipv6_dst_port() {
|
|
#when ethertype is not configured by user then both proto rules of ipv4
|
|
#and ipv6 to be installed so update BR6_RULE string as well otherwise
|
|
#update BR_RULE only for installation of ipv6 proto rule only.
|
|
if [ -n "$BR6_RULE" ]; then
|
|
BR6_RULE="$BR6_RULE --ip6-destination-port $1"
|
|
else
|
|
BR_RULE="$BR_RULE --ip6-destination-port $1"
|
|
fi
|
|
}
|
|
|
|
ebt_match_ip_protocol() {
|
|
BR_RULE="$BR_RULE --ip-proto $1"
|
|
}
|
|
|
|
ebt_match_ip_icmp_type() {
|
|
BR_RULE="$BR_RULE --ip-icmp-type $1"
|
|
}
|
|
|
|
ebt_match_ipv6_protocol() {
|
|
#when ethertype is not configured by user then both proto rules of ipv4
|
|
#and ipv6 to be installed so update BR6_RULE string as well otherwise
|
|
#update BR_RULE only for installation of ipv6 proto rule only.
|
|
if [ -n "$BR6_RULE" ]; then
|
|
BR6_RULE="$BR6_RULE --ip6-proto $1"
|
|
else
|
|
BR_RULE="$BR_RULE --ip6-proto $1"
|
|
fi
|
|
}
|
|
|
|
ebt_match_ipv6_icmp_type() {
|
|
#when ethertype is not configured by user then both proto rules of ipv4
|
|
#and ipv6 to be installed so update BR6_RULE string as well otherwise
|
|
#update BR_RULE only for installation of ipv6 proto rule only.
|
|
if [ -n "$BR6_RULE" ]; then
|
|
BR6_RULE="$BR6_RULE --ip6-icmp-type $1"
|
|
else
|
|
BR_RULE="$BR_RULE --ip6-icmp-type $1"
|
|
fi
|
|
}
|
|
|
|
broute_filter_on_vid() {
|
|
|
|
if [ -z "$1" ] || [ "$1" -lt 0 ]; then
|
|
return
|
|
fi
|
|
|
|
case "$BR_RULE" in
|
|
*proto*)
|
|
BR_RULE="$BR_RULE --vlan-id $1"
|
|
;;
|
|
*)
|
|
BR_RULE="$BR_RULE --proto 802_1Q --vlan-id $1"
|
|
;;
|
|
esac
|
|
}
|
|
|
|
broute_append_rule() {
|
|
# if src_if is loopback, then add the rule to OUTPUT(qos_output) chain of nat table
|
|
if [ "$src_if" = "lo" ]; then
|
|
echo "ebtables --concurrent -t nat -A qos_output $BR_RULE" >> /tmp/qos/classify.ebtables
|
|
if [ -n "$BR6_RULE" ]; then
|
|
echo "ebtables --concurrent -t nat -A qos_output $BR6_RULE" >> /tmp/qos/classify.ebtables
|
|
fi
|
|
return
|
|
fi
|
|
|
|
local broute_chain="$1"
|
|
#when ethertype is not configured by user then both proto rules of ipv4
|
|
#and ipv6 to be installed otherwise install ipv6 proto rule only.
|
|
echo "ebtables --concurrent -t broute -A $broute_chain $BR_RULE" >> /tmp/qos/classify.ebtables
|
|
if [ -n "$BR6_RULE" ]; then
|
|
echo "ebtables --concurrent -t broute -A $broute_chain $BR6_RULE" >> /tmp/qos/classify.ebtables
|
|
fi
|
|
}
|
|
|
|
broute_apply_dscp2pbit_rule() {
|
|
# Write dscp2pbit broute rule to classify.ebtables file
|
|
echo "ebtables --concurrent -t broute -A dscp2pbits -p 0x8100 $BR_RULE_DSCP2PBIT" >> /tmp/qos/classify.ebtables
|
|
}
|
|
|
|
broute_rule_set_xlate_vid_pbit() {
|
|
local vid_mark="$1"
|
|
local pcp_mark="$2"
|
|
|
|
BR_RULE="$BR_RULE -j vlantranslation"
|
|
[ -n "$vid_mark" ] && BR_RULE="$BR_RULE --vlanxlate-vid-set $vid_mark"
|
|
[ -n "$pcp_mark" ] && BR_RULE="$BR_RULE --vlanxlate-prio-set $pcp_mark"
|
|
BR_RULE="$BR_RULE --vlanxlate-target CONTINUE"
|
|
}
|
|
|
|
set_ip_addr()
|
|
{
|
|
local cid="$1"
|
|
local match_src_ip_func="$2"
|
|
local match_dst_ip_func="$3"
|
|
|
|
config_get src_ip "$cid" "src_ip"
|
|
config_get dst_ip "$cid" "dest_ip"
|
|
|
|
if [ -n "$src_ip" ]; then
|
|
$match_src_ip_func "$src_ip"
|
|
fi
|
|
|
|
if [ -n "$dst_ip" ]; then
|
|
$match_dst_ip_func "$dst_ip"
|
|
fi
|
|
}
|
|
|
|
set_ports()
|
|
{
|
|
local cid="$1"
|
|
local match_src_port_func="$2"
|
|
local match_dst_port_func="$3"
|
|
local src_port=""
|
|
local dst_port=""
|
|
local src_port_range=""
|
|
local dst_port_range=""
|
|
|
|
config_get src_port "$cid" "src_port"
|
|
config_get dst_port "$cid" "dest_port"
|
|
config_get src_port_range "$cid" "src_port_range"
|
|
config_get dst_port_range "$cid" "dest_port_range"
|
|
|
|
if [ -n "$src_port" ] && [ -n "$src_port_range" ] ; then
|
|
$match_src_port_func "$src_port:$src_port_range"
|
|
elif [ -n "$src_port" ] ; then
|
|
$match_src_port_func "$src_port"
|
|
fi
|
|
|
|
if [ -n "$dst_port" ] && [ -n "$dst_port_range" ] ; then
|
|
$match_dst_port_func "$dst_port:$dst_port_range"
|
|
elif [ -n "$dst_port" ] ; then
|
|
$match_dst_port_func "$dst_port"
|
|
fi
|
|
}
|
|
|
|
protocol_string_to_num()
|
|
{
|
|
local value="-1"
|
|
|
|
case "$1" in
|
|
TCP|tcp)
|
|
value=6
|
|
;;
|
|
UDP|udp)
|
|
value=17
|
|
;;
|
|
ICMP|icmp)
|
|
value=1
|
|
;;
|
|
ICMPv6|icmpv6)
|
|
value=58
|
|
;;
|
|
IGMP|igmp)
|
|
value=2
|
|
;;
|
|
SCTP|sctp)
|
|
value=132
|
|
;;
|
|
*[0-9]*)
|
|
value="$1"
|
|
;;
|
|
*)
|
|
value=-1
|
|
;;
|
|
esac
|
|
echo $value
|
|
}
|
|
|
|
handle_ebtables_rules() {
|
|
local sid="$1"
|
|
local is_l2_rule=0
|
|
local src_dhcp_options=""
|
|
local dst_dhcp_options=""
|
|
local protocol=""
|
|
local ip_version=""
|
|
|
|
config_get pcp_mark "$sid" "pcp_mark"
|
|
config_get dscp_filter "$sid" "dscp_filter"
|
|
# return if its a classfy section for DSCP to p-bit mapping
|
|
if [ -n "$pcp_mark" ] && [ -n "$dscp_filter" ]; then
|
|
return
|
|
fi
|
|
|
|
init_broute_rule
|
|
|
|
config_get src_if "$sid" "ifname"
|
|
config_get src_mac "$sid" "src_mac"
|
|
config_get dst_mac "$sid" "dst_mac"
|
|
config_get pcp_check "$sid" "pcp_check"
|
|
config_get eth_type "$sid" "ethertype"
|
|
config_get vid "$sid" "vid_check"
|
|
config_get dhcp_type "$sid" "dhcp_type" # dhcpv4 or v6
|
|
config_get src_vcid "$sid" "src_vendor_class_id" # dhcp option 60
|
|
config_get dst_vcid "$sid" "dst_vendor_class_id" # dhcp option 60
|
|
config_get src_clid "$sid" "src_client_id" # dhcp option 61
|
|
config_get dst_clid "$sid" "dst_client_id" # dhcp option 61
|
|
config_get src_ucid "$sid" "src_user_class_id" # dhcp option 77
|
|
config_get dst_ucid "$sid" "dst_user_class_id" # dhcp option 77
|
|
config_get traffic_class "$sid" "traffic_class"
|
|
config_get protocol "$sid" "proto"
|
|
config_get all_interfaces "$sid" "all_interfaces"
|
|
config_get l3_ifname "$sid" "l3_ifname"
|
|
config_get vid_mark "$sid" "vid_mark"
|
|
|
|
if [ -n "$l3_ifname" ]; then
|
|
broute_filter_on_l3_if "$l3_ifname"
|
|
is_l2_rule=1
|
|
fi
|
|
|
|
if [ "$all_interfaces" == "1" ]; then
|
|
is_l2_rule=1
|
|
elif [ -n "$src_if" ]; then
|
|
for interf in $(jsonfilter -i /etc/board.json -e @.network.lan.ports[*] -e @.network.lan.device -e @.network.wan.device | xargs); do
|
|
if [ "$src_if" == "$interf" ]; then
|
|
src_if="$src_if+"
|
|
broute_filter_on_src_if "$src_if"
|
|
is_l2_rule=1
|
|
fi
|
|
done
|
|
fi
|
|
|
|
if [ -n "$src_mac" ]; then
|
|
broute_filter_on_src_mac "$src_mac"
|
|
is_l2_rule=1
|
|
fi
|
|
|
|
if [ -n "$dst_mac" ]; then
|
|
broute_filter_on_dst_mac "$dst_mac"
|
|
is_l2_rule=1
|
|
fi
|
|
|
|
if [ -n "$pcp_check" ]; then
|
|
broute_filter_on_pcp "$pcp_check"
|
|
is_l2_rule=1
|
|
fi
|
|
|
|
if [ -n "$eth_type" ]; then
|
|
broute_filter_on_ether_type "$eth_type"
|
|
is_l2_rule=1
|
|
fi
|
|
|
|
if [ -n "$vid" ]; then
|
|
broute_filter_on_vid "$vid"
|
|
is_l2_rule=1
|
|
fi
|
|
|
|
case $(echo "$eth_type" | tr 'a-z' 'A-Z') in
|
|
IPV4|0800|800|0X0800)
|
|
ip_version=4
|
|
;;
|
|
IPV6|86DD|0X86DD)
|
|
ip_version=6
|
|
;;
|
|
*)
|
|
if [ -z "$eth_type" ]; then
|
|
case "$src_ip$dst_ip" in
|
|
*.*)
|
|
ip_version=4
|
|
broute_filter_on_ether_type "IPv4"
|
|
;;
|
|
*:*)
|
|
ip_version=6
|
|
broute_filter_on_ether_type "IPv6"
|
|
;;
|
|
*)
|
|
if [ -n "$protocol" ] || [ -n "$dscp_filter" ]; then
|
|
# Neither ether_type nor ip address used,
|
|
# ethertype is not configured by user, so install
|
|
# both proto IPv4 and IPv6 rule (version 1)
|
|
ip_version=1
|
|
BR6_RULE="$BR_RULE"
|
|
broute_filter_on_ether_type "IPv4"
|
|
broute_filter_on_ether_type6 "IPv6"
|
|
fi
|
|
esac
|
|
fi
|
|
esac
|
|
|
|
if [ "$ip_version" == "4" ] || [ "$ip_version" == "1" ]; then
|
|
broute_ipv4_rule_options "$sid"
|
|
is_l2_rule=1
|
|
fi
|
|
|
|
if [ "$ip_version" == "6" ] || [ "$ip_version" == "1" ]; then
|
|
broute_ipv6_rule_options "$sid"
|
|
is_l2_rule=1
|
|
fi
|
|
|
|
# first process options that will help figure our source mac address
|
|
# dhcp option for "vendor class id"
|
|
if [ -n "$src_vcid" ]; then
|
|
src_dhcp_options="$src_dhcp_options vcid=$src_vcid"
|
|
is_l2_rule=1
|
|
fi
|
|
|
|
# dhcp option for "client id"
|
|
if [ -n "$src_clid" ]; then
|
|
src_dhcp_options="$src_dhcp_options clid=$src_clid"
|
|
is_l2_rule=1
|
|
fi
|
|
|
|
# dhcp option for "user class id"
|
|
if [ -n "$src_ucid" ]; then
|
|
src_dhcp_options="$src_dhcp_options ucid=$src_ucid"
|
|
is_l2_rule=1
|
|
fi
|
|
|
|
# if src mac is already a classification criteria, then it
|
|
# does not really make sense to add it as a criteria to
|
|
# filter packets again based on source mac
|
|
if [ -n "$src_dhcp_options" ] && [ -z "$src_mac" ]; then
|
|
comp="$(grep -i "$src_dhcp_options" /tmp/dhcp.client.options)"
|
|
if [ -n "$comp" ]; then
|
|
s_mac_add="$(echo $comp | head -n1 | awk '{print $1;}')"
|
|
if [ -n "$s_mac_add" ]; then
|
|
broute_filter_on_src_mac "$s_mac_add"
|
|
fi
|
|
fi
|
|
fi
|
|
|
|
# Now process options that will help figure our destination mac address
|
|
# dhcp option for "vendor class id"
|
|
if [ -n "$dst_vcid" ]; then
|
|
dst_dhcp_options="$dst_dhcp_options vcid=$dst_vcid"
|
|
is_l2_rule=1
|
|
fi
|
|
|
|
# dhcp option for "client id"
|
|
if [ -n "$dst_clid" ]; then
|
|
dst_dhcp_options="$dst_dhcp_options clid=$dst_clid"
|
|
is_l2_rule=1
|
|
fi
|
|
|
|
# dhcp option for "user class id"
|
|
if [ -n "$dst_ucid" ]; then
|
|
dst_dhcp_options="$dst_dhcp_options ucid=$dst_ucid"
|
|
is_l2_rule=1
|
|
fi
|
|
|
|
# if dst mac is already a classification criteria, then it
|
|
# does not really make sense to add it as a criteria to
|
|
# filter packets again based on destination mac
|
|
if [ -n "$dst_dhcp_options" ] && [ -z "$dst_mac" ] ; then
|
|
comp="$(grep -i "$dst_dhcp_options" /tmp/dhcp.client.options)"
|
|
if [ -n "$comp" ]; then
|
|
d_mac_add="$(echo $comp | head -n1 | awk '{print $1;}')"
|
|
if [ -n "$d_mac_add" ]; then
|
|
broute_filter_on_dst_mac "$d_mac_add"
|
|
fi
|
|
fi
|
|
fi
|
|
|
|
if [ $is_l2_rule -eq 0 ]; then
|
|
return
|
|
fi
|
|
|
|
[ -n "$traffic_class" ] && broute_rule_set_traffic_class "$traffic_class"
|
|
|
|
if [ -n "$vid_mark" ] || [ -n "$pcp_mark" ]; then
|
|
broute_rule_set_xlate_vid_pbit "$vid_mark" "$pcp_mark"
|
|
fi
|
|
|
|
if [ -n "$BR_RULE" ]; then
|
|
if [ -n "$vid_mark" ] || [ -n "$pcp_mark" ]; then
|
|
broute_append_rule "prevlanxlate" "$src_if"
|
|
else
|
|
broute_append_rule "qos" "$src_if"
|
|
fi
|
|
fi
|
|
}
|
|
|
|
handle_ebtables_dscp2pbit() {
|
|
local in_if=$1
|
|
local dscp_filter=""
|
|
local pcp_mark=""
|
|
local ifname=""
|
|
local dscp2pbit_mapping_list=""
|
|
local corder_file="/tmp/qos/classify.order"
|
|
|
|
if [ -z "$in_if" ]; then
|
|
return
|
|
fi
|
|
|
|
init_broute_dscp2pbit_rule
|
|
while read -r line; do
|
|
line_cid=${line#*_}
|
|
config_get dscp_filter "$line_cid" "dscp_filter"
|
|
config_get pcp_mark "$line_cid" "pcp_mark"
|
|
|
|
# return if not a dscp to p-bit rule
|
|
if [ -z "$dscp_filter" ] || [ -z "$pcp_mark" ]; then
|
|
continue
|
|
fi
|
|
|
|
config_get ifname "$line_cid" "ifname"
|
|
|
|
# return if this config is not for the currently processing interface (in_if)
|
|
if [ -n "$ifname" ] && [ "$ifname" != "$in_if" ]; then
|
|
continue
|
|
fi
|
|
|
|
dscp2pbit_mapping_list="$dscp2pbit_mapping_list,$dscp_filter=$pcp_mark"
|
|
done < "$corder_file"
|
|
|
|
# if not dscp2pbit config found for our interface, return
|
|
[ -z "$dscp2pbit_mapping_list" ] && return
|
|
|
|
# remove first character(comma) from the dscp2pbit_mapping_list, not required.
|
|
dscp2pbit_mapping_list="${dscp2pbit_mapping_list:1}"
|
|
|
|
# construct ebtables rule:
|
|
BR_RULE_DSCP2PBIT=" -i $in_if -j dscp2pbit --dscp2pbit-mapping $dscp2pbit_mapping_list --dscp2pbit-target CONTINUE"
|
|
}
|
|
|
|
flush_ebtables_chains() {
|
|
echo "ebtables --concurrent -t nat -F qos_output" > /tmp/qos/classify.ebtables
|
|
echo "ebtables --concurrent -t broute -F qos" > /tmp/qos/classify.ebtables
|
|
echo "ebtables --concurrent -t broute -F dscp2pbits" >> /tmp/qos/classify.ebtables
|
|
echo "ebtables --concurrent -t broute -F prevlanxlate" >> /tmp/qos/classify.ebtables
|
|
}
|
|
|