Back to home page

OSCL-LXR

 
 

    


0001 #!/bin/bash
0002 #
0003 # SPDX-License-Identifier: GPL-2.0
0004 # Copyright (c) 2018 Jesper Dangaard Brouer, Red Hat Inc.
0005 #
0006 # Bash-shell example on using iproute2 tools 'tc' and 'ip' to load
0007 # eBPF programs, both for XDP and clsbpf.  Shell script function
0008 # wrappers and even long options parsing is illustrated, for ease of
0009 # use.
0010 #
0011 # Related to sample/bpf/xdp2skb_meta_kern.c, which contains BPF-progs
0012 # that need to collaborate between XDP and TC hooks.  Thus, it is
0013 # convenient that the same tool load both programs that need to work
0014 # together.
0015 #
0016 BPF_FILE=xdp2skb_meta_kern.o
0017 DIR=$(dirname $0)
0018 
0019 [ -z "$TC" ] && TC=tc
0020 [ -z "$IP" ] && IP=ip
0021 
0022 function usage() {
0023     echo ""
0024     echo "Usage: $0 [-vfh] --dev ethX"
0025     echo "  -d | --dev     :             Network device (required)"
0026     echo "  --flush        :             Cleanup flush TC and XDP progs"
0027     echo "  --list         : (\$LIST)     List TC and XDP progs"
0028     echo "  -v | --verbose : (\$VERBOSE)  Verbose"
0029     echo "  --dry-run      : (\$DRYRUN)   Dry-run only (echo commands)"
0030     echo ""
0031 }
0032 
0033 ## -- General shell logging cmds --
0034 function err() {
0035     local exitcode=$1
0036     shift
0037     echo "ERROR: $@" >&2
0038     exit $exitcode
0039 }
0040 
0041 function info() {
0042     if [[ -n "$VERBOSE" ]]; then
0043         echo "# $@"
0044     fi
0045 }
0046 
0047 ## -- Helper function calls --
0048 
0049 # Wrapper call for TC and IP
0050 # - Will display the offending command on failure
0051 function _call_cmd() {
0052     local cmd="$1"
0053     local allow_fail="$2"
0054     shift 2
0055     if [[ -n "$VERBOSE" ]]; then
0056         echo "$cmd $@"
0057     fi
0058     if [[ -n "$DRYRUN" ]]; then
0059         return
0060     fi
0061     $cmd "$@"
0062     local status=$?
0063     if (( $status != 0 )); then
0064         if [[ "$allow_fail" == "" ]]; then
0065             err 2 "Exec error($status) occurred cmd: \"$cmd $@\""
0066         fi
0067     fi
0068 }
0069 function call_tc() {
0070     _call_cmd "$TC" "" "$@"
0071 }
0072 function call_tc_allow_fail() {
0073     _call_cmd "$TC" "allow_fail" "$@"
0074 }
0075 function call_ip() {
0076     _call_cmd "$IP" "" "$@"
0077 }
0078 
0079 ##  --- Parse command line arguments / parameters ---
0080 # Using external program "getopt" to get --long-options
0081 OPTIONS=$(getopt -o vfhd: \
0082     --long verbose,flush,help,list,dev:,dry-run -- "$@")
0083 if (( $? != 0 )); then
0084     err 4 "Error calling getopt"
0085 fi
0086 eval set -- "$OPTIONS"
0087 
0088 unset DEV
0089 unset FLUSH
0090 while true; do
0091     case "$1" in
0092         -d | --dev ) # device
0093             DEV=$2
0094             info "Device set to: DEV=$DEV" >&2
0095             shift 2
0096             ;;
0097         -v | --verbose)
0098             VERBOSE=yes
0099             # info "Verbose mode: VERBOSE=$VERBOSE" >&2
0100             shift
0101             ;;
0102         --dry-run )
0103             DRYRUN=yes
0104             VERBOSE=yes
0105             info "Dry-run mode: enable VERBOSE and don't call TC+IP" >&2
0106             shift
0107             ;;
0108         -f | --flush )
0109             FLUSH=yes
0110             shift
0111             ;;
0112         --list )
0113             LIST=yes
0114             shift
0115             ;;
0116         -- )
0117             shift
0118             break
0119             ;;
0120         -h | --help )
0121             usage;
0122             exit 0
0123             ;;
0124         * )
0125             shift
0126             break
0127             ;;
0128     esac
0129 done
0130 
0131 FILE="$DIR/$BPF_FILE"
0132 if [[ ! -e $FILE ]]; then
0133     err 3 "Missing BPF object file ($FILE)"
0134 fi
0135 
0136 if [[ -z $DEV ]]; then
0137     usage
0138     err 2 "Please specify network device -- required option --dev"
0139 fi
0140 
0141 ## -- Function calls --
0142 
0143 function list_tc()
0144 {
0145     local device="$1"
0146     shift
0147     info "Listing current TC ingress rules"
0148     call_tc filter show dev $device ingress
0149 }
0150 
0151 function list_xdp()
0152 {
0153     local device="$1"
0154     shift
0155     info "Listing current XDP device($device) setting"
0156     call_ip link show dev $device | grep --color=auto xdp
0157 }
0158 
0159 function flush_tc()
0160 {
0161     local device="$1"
0162     shift
0163     info "Flush TC on device: $device"
0164     call_tc_allow_fail filter del dev $device ingress
0165     call_tc_allow_fail qdisc del dev $device clsact
0166 }
0167 
0168 function flush_xdp()
0169 {
0170     local device="$1"
0171     shift
0172     info "Flush XDP on device: $device"
0173     call_ip link set dev $device xdp off
0174 }
0175 
0176 function attach_tc_mark()
0177 {
0178     local device="$1"
0179     local file="$2"
0180     local prog="tc_mark"
0181     shift 2
0182 
0183     # Re-attach clsact to clear/flush existing role
0184     call_tc_allow_fail qdisc del dev $device clsact 2> /dev/null
0185     call_tc            qdisc add dev $device clsact
0186 
0187     # Attach BPF prog
0188     call_tc filter add dev $device ingress \
0189             prio 1 handle 1 bpf da obj $file sec $prog
0190 }
0191 
0192 function attach_xdp_mark()
0193 {
0194     local device="$1"
0195     local file="$2"
0196     local prog="xdp_mark"
0197     shift 2
0198 
0199     # Remove XDP prog in-case it's already loaded
0200     # TODO: Need ip-link option to override/replace existing XDP prog
0201     flush_xdp $device
0202 
0203     # Attach XDP/BPF prog
0204     call_ip link set dev $device xdp obj $file sec $prog
0205 }
0206 
0207 if [[ -n $FLUSH ]]; then
0208     flush_tc  $DEV
0209     flush_xdp $DEV
0210     exit 0
0211 fi
0212 
0213 if [[ -n $LIST ]]; then
0214     list_tc  $DEV
0215     list_xdp $DEV
0216     exit 0
0217 fi
0218 
0219 attach_tc_mark  $DEV $FILE
0220 attach_xdp_mark $DEV $FILE