1 #!/bin/bash 2 # 3 # SPDX-License-Identifier: GPL-2.0 4 # Copyright (c) 2018 Jesper Dangaard Brouer, Red Hat Inc. 5 # 6 # Bash-shell example on using iproute2 tools 'tc' and 'ip' to load 7 # eBPF programs, both for XDP and clsbpf. Shell script function 8 # wrappers and even long options parsing is illustrated, for ease of 9 # use. 10 # 11 # Related to sample/bpf/xdp2skb_meta_kern.c, which contains BPF-progs 12 # that need to collaborate between XDP and TC hooks. Thus, it is 13 # convenient that the same tool load both programs that need to work 14 # together. 15 # 16 BPF_FILE=xdp2skb_meta_kern.o 17 DIR=$(dirname $0) 18 19 [ -z "$TC" ] && TC=tc 20 [ -z "$IP" ] && IP=ip 21 22 function usage() { 23 echo "" 24 echo "Usage: $0 [-vfh] --dev ethX" 25 echo " -d | --dev : Network device (required)" 26 echo " --flush : Cleanup flush TC and XDP progs" 27 echo " --list : (\$LIST) List TC and XDP progs" 28 echo " -v | --verbose : (\$VERBOSE) Verbose" 29 echo " --dry-run : (\$DRYRUN) Dry-run only (echo commands)" 30 echo "" 31 } 32 33 ## -- General shell logging cmds -- 34 function err() { 35 local exitcode=$1 36 shift 37 echo "ERROR: $@" >&2 38 exit $exitcode 39 } 40 41 function info() { 42 if [[ -n "$VERBOSE" ]]; then 43 echo "# $@" 44 fi 45 } 46 47 ## -- Helper function calls -- 48 49 # Wrapper call for TC and IP 50 # - Will display the offending command on failure 51 function _call_cmd() { 52 local cmd="$1" 53 local allow_fail="$2" 54 shift 2 55 if [[ -n "$VERBOSE" ]]; then 56 echo "$cmd $@" 57 fi 58 if [[ -n "$DRYRUN" ]]; then 59 return 60 fi 61 $cmd "$@" 62 local status=$? 63 if (( $status != 0 )); then 64 if [[ "$allow_fail" == "" ]]; then 65 err 2 "Exec error($status) occurred cmd: \"$cmd $@\"" 66 fi 67 fi 68 } 69 function call_tc() { 70 _call_cmd "$TC" "" "$@" 71 } 72 function call_tc_allow_fail() { 73 _call_cmd "$TC" "allow_fail" "$@" 74 } 75 function call_ip() { 76 _call_cmd "$IP" "" "$@" 77 } 78 79 ## --- Parse command line arguments / parameters --- 80 # Using external program "getopt" to get --long-options 81 OPTIONS=$(getopt -o vfhd: \ 82 --long verbose,flush,help,list,dev:,dry-run -- "$@") 83 if (( $? != 0 )); then 84 err 4 "Error calling getopt" 85 fi 86 eval set -- "$OPTIONS" 87 88 unset DEV 89 unset FLUSH 90 while true; do 91 case "$1" in 92 -d | --dev ) # device 93 DEV=$2 94 info "Device set to: DEV=$DEV" >&2 95 shift 2 96 ;; 97 -v | --verbose) 98 VERBOSE=yes 99 # info "Verbose mode: VERBOSE=$VERBOSE" >&2 100 shift 101 ;; 102 --dry-run ) 103 DRYRUN=yes 104 VERBOSE=yes 105 info "Dry-run mode: enable VERBOSE and don't call TC+IP" >&2 106 shift 107 ;; 108 -f | --flush ) 109 FLUSH=yes 110 shift 111 ;; 112 --list ) 113 LIST=yes 114 shift 115 ;; 116 -- ) 117 shift 118 break 119 ;; 120 -h | --help ) 121 usage; 122 exit 0 123 ;; 124 * ) 125 shift 126 break 127 ;; 128 esac 129 done 130 131 FILE="$DIR/$BPF_FILE" 132 if [[ ! -e $FILE ]]; then 133 err 3 "Missing BPF object file ($FILE)" 134 fi 135 136 if [[ -z $DEV ]]; then 137 usage 138 err 2 "Please specify network device -- required option --dev" 139 fi 140 141 ## -- Function calls -- 142 143 function list_tc() 144 { 145 local device="$1" 146 shift 147 info "Listing current TC ingress rules" 148 call_tc filter show dev $device ingress 149 } 150 151 function list_xdp() 152 { 153 local device="$1" 154 shift 155 info "Listing current XDP device($device) setting" 156 call_ip link show dev $device | grep --color=auto xdp 157 } 158 159 function flush_tc() 160 { 161 local device="$1" 162 shift 163 info "Flush TC on device: $device" 164 call_tc_allow_fail filter del dev $device ingress 165 call_tc_allow_fail qdisc del dev $device clsact 166 } 167 168 function flush_xdp() 169 { 170 local device="$1" 171 shift 172 info "Flush XDP on device: $device" 173 call_ip link set dev $device xdp off 174 } 175 176 function attach_tc_mark() 177 { 178 local device="$1" 179 local file="$2" 180 local prog="tc_mark" 181 shift 2 182 183 # Re-attach clsact to clear/flush existing role 184 call_tc_allow_fail qdisc del dev $device clsact 2> /dev/null 185 call_tc qdisc add dev $device clsact 186 187 # Attach BPF prog 188 call_tc filter add dev $device ingress \ 189 prio 1 handle 1 bpf da obj $file sec $prog 190 } 191 192 function attach_xdp_mark() 193 { 194 local device="$1" 195 local file="$2" 196 local prog="xdp_mark" 197 shift 2 198 199 # Remove XDP prog in-case it's already loaded 200 # TODO: Need ip-link option to override/replace existing XDP prog 201 flush_xdp $device 202 203 # Attach XDP/BPF prog 204 call_ip link set dev $device xdp obj $file sec $prog 205 } 206 207 if [[ -n $FLUSH ]]; then 208 flush_tc $DEV 209 flush_xdp $DEV 210 exit 0 211 fi 212 213 if [[ -n $LIST ]]; then 214 list_tc $DEV 215 list_xdp $DEV 216 exit 0 217 fi 218 219 attach_tc_mark $DEV $FILE 220 attach_xdp_mark $DEV $FILE
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.