Jesper Dangaard Brouer | 36e04a2 | 2018-01-10 18:21:44 +0100 | [diff] [blame] | 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 | |
Taeung Song | b9626f4 | 2018-07-10 02:51:21 +0900 | [diff] [blame] | 19 | [ -z "$TC" ] && TC=tc |
| 20 | [ -z "$IP" ] && IP=ip |
Jesper Dangaard Brouer | 36e04a2 | 2018-01-10 18:21:44 +0100 | [diff] [blame] | 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 |
Taeung Song | b9626f4 | 2018-07-10 02:51:21 +0900 | [diff] [blame] | 56 | echo "$cmd $@" |
Jesper Dangaard Brouer | 36e04a2 | 2018-01-10 18:21:44 +0100 | [diff] [blame] | 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 |