xdp2skb_meta.sh 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220
  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. [ -z "$TC" ] && TC=tc
  19. [ -z "$IP" ] && IP=ip
  20. function usage() {
  21. echo ""
  22. echo "Usage: $0 [-vfh] --dev ethX"
  23. echo " -d | --dev : Network device (required)"
  24. echo " --flush : Cleanup flush TC and XDP progs"
  25. echo " --list : (\$LIST) List TC and XDP progs"
  26. echo " -v | --verbose : (\$VERBOSE) Verbose"
  27. echo " --dry-run : (\$DRYRUN) Dry-run only (echo commands)"
  28. echo ""
  29. }
  30. ## -- General shell logging cmds --
  31. function err() {
  32. local exitcode=$1
  33. shift
  34. echo "ERROR: $@" >&2
  35. exit $exitcode
  36. }
  37. function info() {
  38. if [[ -n "$VERBOSE" ]]; then
  39. echo "# $@"
  40. fi
  41. }
  42. ## -- Helper function calls --
  43. # Wrapper call for TC and IP
  44. # - Will display the offending command on failure
  45. function _call_cmd() {
  46. local cmd="$1"
  47. local allow_fail="$2"
  48. shift 2
  49. if [[ -n "$VERBOSE" ]]; then
  50. echo "$cmd $@"
  51. fi
  52. if [[ -n "$DRYRUN" ]]; then
  53. return
  54. fi
  55. $cmd "$@"
  56. local status=$?
  57. if (( $status != 0 )); then
  58. if [[ "$allow_fail" == "" ]]; then
  59. err 2 "Exec error($status) occurred cmd: \"$cmd $@\""
  60. fi
  61. fi
  62. }
  63. function call_tc() {
  64. _call_cmd "$TC" "" "$@"
  65. }
  66. function call_tc_allow_fail() {
  67. _call_cmd "$TC" "allow_fail" "$@"
  68. }
  69. function call_ip() {
  70. _call_cmd "$IP" "" "$@"
  71. }
  72. ## --- Parse command line arguments / parameters ---
  73. # Using external program "getopt" to get --long-options
  74. OPTIONS=$(getopt -o vfhd: \
  75. --long verbose,flush,help,list,dev:,dry-run -- "$@")
  76. if (( $? != 0 )); then
  77. err 4 "Error calling getopt"
  78. fi
  79. eval set -- "$OPTIONS"
  80. unset DEV
  81. unset FLUSH
  82. while true; do
  83. case "$1" in
  84. -d | --dev ) # device
  85. DEV=$2
  86. info "Device set to: DEV=$DEV" >&2
  87. shift 2
  88. ;;
  89. -v | --verbose)
  90. VERBOSE=yes
  91. # info "Verbose mode: VERBOSE=$VERBOSE" >&2
  92. shift
  93. ;;
  94. --dry-run )
  95. DRYRUN=yes
  96. VERBOSE=yes
  97. info "Dry-run mode: enable VERBOSE and don't call TC+IP" >&2
  98. shift
  99. ;;
  100. -f | --flush )
  101. FLUSH=yes
  102. shift
  103. ;;
  104. --list )
  105. LIST=yes
  106. shift
  107. ;;
  108. -- )
  109. shift
  110. break
  111. ;;
  112. -h | --help )
  113. usage;
  114. exit 0
  115. ;;
  116. * )
  117. shift
  118. break
  119. ;;
  120. esac
  121. done
  122. FILE="$DIR/$BPF_FILE"
  123. if [[ ! -e $FILE ]]; then
  124. err 3 "Missing BPF object file ($FILE)"
  125. fi
  126. if [[ -z $DEV ]]; then
  127. usage
  128. err 2 "Please specify network device -- required option --dev"
  129. fi
  130. ## -- Function calls --
  131. function list_tc()
  132. {
  133. local device="$1"
  134. shift
  135. info "Listing current TC ingress rules"
  136. call_tc filter show dev $device ingress
  137. }
  138. function list_xdp()
  139. {
  140. local device="$1"
  141. shift
  142. info "Listing current XDP device($device) setting"
  143. call_ip link show dev $device | grep --color=auto xdp
  144. }
  145. function flush_tc()
  146. {
  147. local device="$1"
  148. shift
  149. info "Flush TC on device: $device"
  150. call_tc_allow_fail filter del dev $device ingress
  151. call_tc_allow_fail qdisc del dev $device clsact
  152. }
  153. function flush_xdp()
  154. {
  155. local device="$1"
  156. shift
  157. info "Flush XDP on device: $device"
  158. call_ip link set dev $device xdp off
  159. }
  160. function attach_tc_mark()
  161. {
  162. local device="$1"
  163. local file="$2"
  164. local prog="tc_mark"
  165. shift 2
  166. # Re-attach clsact to clear/flush existing role
  167. call_tc_allow_fail qdisc del dev $device clsact 2> /dev/null
  168. call_tc qdisc add dev $device clsact
  169. # Attach BPF prog
  170. call_tc filter add dev $device ingress \
  171. prio 1 handle 1 bpf da obj $file sec $prog
  172. }
  173. function attach_xdp_mark()
  174. {
  175. local device="$1"
  176. local file="$2"
  177. local prog="xdp_mark"
  178. shift 2
  179. # Remove XDP prog in-case it's already loaded
  180. # TODO: Need ip-link option to override/replace existing XDP prog
  181. flush_xdp $device
  182. # Attach XDP/BPF prog
  183. call_ip link set dev $device xdp obj $file sec $prog
  184. }
  185. if [[ -n $FLUSH ]]; then
  186. flush_tc $DEV
  187. flush_xdp $DEV
  188. exit 0
  189. fi
  190. if [[ -n $LIST ]]; then
  191. list_tc $DEV
  192. list_xdp $DEV
  193. exit 0
  194. fi
  195. attach_tc_mark $DEV $FILE
  196. attach_xdp_mark $DEV $FILE