From 27d44f3a8a4708bcc99995a4d9b6fe6f81e3e15b Mon Sep 17 00:00:00 2001 From: Quentin Monnet Date: Tue, 3 May 2016 09:39:08 +0200 Subject: [PATCH 1/8] tc: add bash-completion function Add function for command completion for tc in bash, and update Makefile to install it under /usr/share/bash-completion/completions/. Inside iproute2 repository, the completion code is in a new `bash-completion` toplevel directory. v2: Remove `if` statement in Makefile: do not try to install in /etc/bash_completion.d/ if /usr/share/bash-completion/completions/ is not found; instead, the user can override the installation path with the specific environment variable. Signed-off-by: Quentin Monnet --- Makefile | 3 + bash-completion/tc | 723 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 726 insertions(+) create mode 100644 bash-completion/tc diff --git a/Makefile b/Makefile index 0190aa00..eb571a5a 100644 --- a/Makefile +++ b/Makefile @@ -7,6 +7,7 @@ DOCDIR?=$(DATADIR)/doc/iproute2 MANDIR?=$(DATADIR)/man ARPDDIR?=/var/lib/arpd KERNEL_INCLUDE?=/usr/include +BASH_COMPDIR?=$(DATADIR)/bash-completion/completions # Path to db_185.h include DBM_INCLUDE:=$(DESTDIR)/usr/include @@ -66,6 +67,8 @@ install: all $(DESTDIR)$(DOCDIR)/examples/diffserv @for i in $(SUBDIRS) doc; do $(MAKE) -C $$i install; done install -m 0644 $(shell find etc/iproute2 -maxdepth 1 -type f) $(DESTDIR)$(CONFDIR) + install -m 0755 -d $(DESTDIR)$(BASH_COMPDIR) + install -m 0644 bash-completion/tc $(DESTDIR)$(BASH_COMPDIR) snapshot: echo "static const char SNAPSHOT[] = \""`date +%y%m%d`"\";" \ diff --git a/bash-completion/tc b/bash-completion/tc new file mode 100644 index 00000000..79dd5fcc --- /dev/null +++ b/bash-completion/tc @@ -0,0 +1,723 @@ +# tc(8) completion -*- shell-script -*- +# Copyright 2016 6WIND S.A. +# Copyright 2016 Quentin Monnet + +# Takes a list of words in argument; each one of them is added to COMPREPLY if +# it is not already present on the command line. Returns no value. +_tc_once_attr() +{ + local w subcword found + for w in $*; do + found=0 + for (( subcword=3; subcword < ${#words[@]}-1; subcword++ )); do + if [[ $w == ${words[subcword]} ]]; then + found=1 + break + fi + done + [[ $found -eq 0 ]] && \ + COMPREPLY+=( $( compgen -W "$w" -- "$cur" ) ) + done +} + +# Takes a list of words in argument; adds them all to COMPREPLY if none of them +# is already present on the command line. Returns no value. +_tc_one_of_list() +{ + local w subcword + for w in $*; do + for (( subcword=3; subcword < ${#words[@]}-1; subcword++ )); do + [[ $w == ${words[subcword]} ]] && return 1 + done + done + COMPREPLY+=( $( compgen -W "$*" -- "$cur" ) ) +} + +# Returns "$cur ${cur}arg1 ${cur}arg2 ..." +_tc_expand_units() +{ + [[ $cur =~ ^[0-9]+ ]] || return 1 + local value=${cur%%[^0-9]*} + [[ $cur == $value ]] && echo $cur + echo ${@/#/$value} +} + +# Complete based on given word, usually $prev (or possibly the word before), +# for when an argument or an option name has but a few possible arguments (so +# tc does not take particular commands into account here). +# Returns 0 is completion should stop after running this function, 1 otherwise. +_tc_direct_complete() +{ + case $1 in + # Command options + dev) + _available_interfaces + return 0 + ;; + classid) + return 0 + ;; + estimator) + local list=$( _tc_expand_units 'secs' 'msecs' 'usecs' ) + COMPREPLY+=( $( compgen -W "$list" -- "$cur" ) ) + return 0 + ;; + handle) + return 0 + ;; + parent|flowid) + local i iface ids cmd + for (( i=3; i < ${#words[@]}-2; i++ )); do + [[ ${words[i]} == dev ]] && iface=${words[i+1]} + break + done + for cmd in qdisc class; do + if [[ -n $iface ]]; then + ids+=$( tc $cmd show dev $iface 2>/dev/null | \ + cut -d\ -f 3 )" " + else + ids+=$( tc $cmd show 2>/dev/null | cut -d\ -f 3 ) + fi + done + [[ $ids != " " ]] && \ + COMPREPLY+=( $( compgen -W "$ids" -- "$cur" ) ) + return 0 + ;; + protocol) # list comes from lib/ll_proto.c + COMPREPLY+=( $( compgen -W ' 802.1Q 802.1ad 802_2 802_3 LLDP aarp \ + all aoe arp atalk atmfate atmmpoa ax25 bpq can control cust \ + ddcmp dec diag dna_dl dna_rc dna_rt econet ieeepup ieeepupat \ + ip ipv4 ipv6 ipx irda lat localtalk loop mobitex ppp_disc \ + ppp_mp ppp_ses ppptalk pup pupat rarp sca snap tipc tr_802_2 \ + wan_ppp x25' -- "$cur" ) ) + return 0 + ;; + prio) + return 0 + ;; + stab) + COMPREPLY+=( $( compgen -W 'mtu tsize mpu overhead + linklayer' -- "$cur" ) ) + ;; + + # Qdiscs and classes options + alpha|bands|beta|buckets|corrupt|debug|decrement|default|\ + default_index|depth|direct_qlen|divisor|duplicate|ewma|flow_limit|\ + flows|hh_limit|increment|indices|linklayer|non_hh_weight|num_tc|\ + penalty_burst|penalty_rate|prio|priomap|probability|queues|r2q|\ + reorder|vq|vqs) + return 0 + ;; + setup) + COMPREPLY+=( $( compgen -W 'vqs' -- "$cur" ) ) + return 0 + ;; + hw) + COMPREPLY+=( $( compgen -W '1 0' -- "$cur" ) ) + return 0 + ;; + distribution) + COMPREPLY+=( $( compgen -W 'uniform normal pareto + paretonormal' -- "$cur" ) ) + return 0 + ;; + loss) + COMPREPLY+=( $( compgen -W 'random state gmodel' -- "$cur" ) ) + return 0 + ;; + + # Qdiscs and classes options options + gap|gmodel|state) + return 0 + ;; + + # Filters options + map) + COMPREPLY+=( $( compgen -W 'key' -- "$cur" ) ) + return 0 + ;; + hash) + COMPREPLY+=( $( compgen -W 'keys' -- "$cur" ) ) + return 0 + ;; + indev) + _available_interfaces + return 0 + ;; + eth_type) + COMPREPLY+=( $( compgen -W 'ipv4 ipv6' -- "$cur" ) ) + return 0 + ;; + ip_proto) + COMPREPLY+=( $( compgen -W 'tcp udp' -- "$cur" ) ) + return 0 + ;; + + # Filters options options + key|keys) + [[ ${words[@]} =~ graft ]] && return 1 + COMPREPLY+=( $( compgen -W 'src dst proto proto-src proto-dst iif \ + priority mark nfct nfct-src nfct-dst nfct-proto-src \ + nfct-proto-dst rt-classid sk-uid sk-gid vlan-tag rxhash' -- \ + "$cur" ) ) + return 0 + ;; + + # BPF options - used for filters, actions, and exec + export|bytecode|bytecode-file|object-file) + _filedir + return 0 + ;; + object-pinned|graft) # Pinned object is probably under /sys/fs/bpf/ + [[ -n "$cur" ]] && _filedir && return 0 + COMPREPLY=( $( compgen -G "/sys/fs/bpf/*" -- "$cur" ) ) || _filedir + compopt -o nospace + return 0 + ;; + section) + if (type objdump > /dev/null 2>&1) ; then + local fword objfile section_list + for (( fword=3; fword < ${#words[@]}-3; fword++ )); do + if [[ ${words[fword]} == object-file ]]; then + objfile=${words[fword+1]} + break + fi + done + section_list=$( objdump -h $objfile 2>/dev/null | \ + sed -n 's/^ *[0-9]\+ \([^ ]*\) *.*/\1/p' ) + COMPREPLY+=( $( compgen -W "$section_list" -- "$cur" ) ) + fi + return 0 + ;; + import|run) + _filedir + return 0 + ;; + type) + COMPREPLY+=( $( compgen -W 'cls act' -- "$cur" ) ) + return 0 + ;; + + # Actions options + random) + _tc_one_of_list 'netrand determ' + return 0 + ;; + + # Units for option arguments + bandwidth|maxrate|peakrate|rate) + local list=$( _tc_expand_units 'bit' \ + 'kbit' 'kibit' 'kbps' 'kibps' \ + 'mbit' 'mibit' 'mbps' 'mibps' \ + 'gbit' 'gibit' 'gbps' 'gibps' \ + 'tbit' 'tibit' 'tbps' 'tibps' ) + COMPREPLY+=( $( compgen -W "$list" -- "$cur" ) ) + ;; + admit_bytes|avpkt|burst|cell|initial_quantum|limit|max|min|mtu|mpu|\ + overhead|quantum|redflowlist) + local list=$( _tc_expand_units \ + 'b' 'kbit' 'k' 'mbit' 'm' 'gbit' 'g' ) + COMPREPLY+=( $( compgen -W "$list" -- "$cur" ) ) + ;; + db|delay|evict_timeout|interval|latency|perturb|rehash|reset_timeout|\ + target|tupdate) + local list=$( _tc_expand_units 'secs' 'msecs' 'usecs' ) + COMPREPLY+=( $( compgen -W "$list" -- "$cur" ) ) + ;; + esac + return 1 +} + +# Complete with options names for qdiscs. Each qdisc has its own set of options +# and it seems we cannot really parse it from anywhere, so we add it manually +# in this function. +# Returns 0 is completion should stop after running this function, 1 otherwise. +_tc_qdisc_options() +{ + case $1 in + choke) + _tc_once_attr 'limit bandwidth ecn min max burst' + return 0 + ;; + codel) + _tc_once_attr 'limit target interval' + _tc_one_of_list 'ecn noecn' + return 0 + ;; + bfifo|pfifo|pfifo_head_drop) + _tc_once_attr 'limit' + return 0 + ;; + fq) + _tc_once_attr 'limit flow_limit quantum initial_quantum maxrate \ + buckets' + _tc_one_of_list 'pacing nopacing' + return 0 + ;; + fq_codel) + _tc_once_attr 'limit flows target interval quantum' + _tc_one_of_list 'ecn noecn' + return 0 + ;; + gred) + _tc_once_attr 'setup vqs default grio vq prio limit min max avpkt \ + burst probability bandwidth' + return 0 + ;; + hhf) + _tc_once_attr 'limit quantum hh_limit reset_timeout admit_bytes \ + evict_timeout non_hh_weight' + return 0 + ;; + mqprio) + _tc_once_attr 'num_tc map queues hw' + return 0 + ;; + netem) + _tc_once_attr 'delay distribution corrupt duplicate loss ecn \ + reorder rate' + return 0 + ;; + pie) + _tc_once_attr 'limit target tupdate alpha beta' + _tc_one_of_list 'bytemode nobytemode' + _tc_one_of_list 'ecn noecn' + return 0 + ;; + red) + _tc_once_attr 'limit min max avpkt burst adaptive probability \ + bandwidth ecn harddrop' + return 0 + ;; + rr|prio) + _tc_once_attr 'bands priomap multiqueue' + return 0 + ;; + sfb) + _tc_once_attr 'rehash db limit max target increment decrement \ + penalty_rate penalty_burst' + return 0 + ;; + sfq) + _tc_once_attr 'limit perturb quantum divisor flows depth headdrop \ + redflowlimit min max avpkt burst probability ecn harddrop' + return 0 + ;; + tbf) + _tc_once_attr 'limit burst rate mtu peakrate latency overhead \ + linklayer' + return 0 + ;; + cbq) + _tc_once_attr 'bandwidth avpkt mpu cell ewma' + return 0 + ;; + dsmark) + _tc_once_attr 'indices default_index set_tc_index' + return 0 + ;; + hfsc) + _tc_once_attr 'default' + return 0 + ;; + htb) + _tc_once_attr 'default r2q direct_qlen debug' + return 0 + ;; + multiq|pfifo_fast|atm|drr|qfq) + return 0 + ;; + esac + return 1 +} + +# Complete with options names for BPF filters or actions. +# Returns 0 is completion should stop after running this function, 1 otherwise. +_tc_bpf_options() +{ + [[ ${words[${#words[@]}-3]} == object-file ]] && \ + _tc_once_attr 'section export' + [[ ${words[${#words[@]}-5]} == object-file ]] && \ + [[ ${words[${#words[@]}-3]} =~ (section|export) ]] && \ + _tc_once_attr 'section export' + _tc_one_of_list 'bytecode bytecode-file object-file object-pinned' + _tc_once_attr 'verbose index direct-action action classid' + return 0 +} + +# Complete with options names for filters. +# Returns 0 is completion should stop after running this function, 1 otherwise. +_tc_filter_options() +{ + case $1 in + basic) + _tc_once_attr 'match action classid' + return 0 + ;; + bpf) + _tc_bpf_options + return 0 + ;; + cgroup) + _tc_once_attr 'match action' + return 0 + ;; + flow) + local i + for (( i=5; i < ${#words[@]}-1; i++ )); do + if [[ ${words[i]} =~ ^keys?$ ]]; then + _tc_direct_complete 'key' + COMPREPLY+=( $( compgen -W 'or and xor rshift addend' -- \ + "$cur" ) ) + break + fi + done + _tc_once_attr 'map hash divisor baseclass match action' + return 0 + ;; + flower) + _tc_once_attr 'action classid indev dst_mac src_mac eth_type \ + ip_proto dst_ip src_ip dst_port src_port' + return 0 + ;; + fw) + _tc_once_attr 'action classid' + return 0 + ;; + route) + _tc_one_of_list 'from fromif' + _tc_once_attr 'to classid action' + return 0 + ;; + rsvp) + _tc_once_attr 'ipproto session sender classid action tunnelid \ + tunnel flowlabel spi/ah spi/esp u8 u16 u32' + [[ ${words[${#words[@]}-3]} == tunnel ]] && \ + COMPREPLY+=( $( compgen -W 'skip' -- "$cur" ) ) + [[ ${words[${#words[@]}-3]} =~ u(8|16|32) ]] && \ + COMPREPLY+=( $( compgen -W 'mask' -- "$cur" ) ) + [[ ${words[${#words[@]}-3]} == mask ]] && \ + COMPREPLY+=( $( compgen -W 'at' -- "$cur" ) ) + return 0 + ;; + tcindex) + _tc_once_attr 'hash mask shift classid action' + _tc_one_of_list 'pass_on fall_through' + return 0 + ;; + u32) + _tc_once_attr 'match link classid action offset ht hashkey sample' + COMPREPLY+=( $( compgen -W 'ip ip6 udp tcp icmp u8 u16 u32 mark \ + divisor' -- "$cur" ) ) + return 0 + ;; + esac + return 1 +} + +# Complete with options names for actions. +# Returns 0 is completion should stop after running this function, 1 otherwise. +_tc_action_options() +{ + case $1 in + bpf) + _tc_bpf_options + return 0 + ;; + mirred) + _tc_one_of_list 'ingress egress' + _tc_one_of_list 'mirror redirect' + _tc_once_attr 'index dev' + return 0 + ;; + gact) + _tc_one_of_list 'reclassify drop continue pass' + _tc_once_attr 'random' + return 0 + ;; + esac + return 1 +} + +# Complete with options names for exec. +# Returns 0 is completion should stop after running this function, 1 otherwise. +_tc_exec_options() +{ + case $1 in + import) + [[ ${words[${#words[@]}-3]} == import ]] && \ + _tc_once_attr 'run' + return 0 + ;; + graft) + COMPREPLY+=( $( compgen -W 'key type' -- "$cur" ) ) + [[ ${words[${#words[@]}-3]} == object-file ]] && \ + _tc_once_attr 'type' + _tc_bpf_options + return 0 + ;; + esac + return 1 +} + +# Main completion function +# Logic is as follows: +# 1. Check if previous word is a global option; if so, propose arguments. +# 2. Check if current word is a global option; if so, propose completion. +# 3. Check for the presence of a main command (qdisc|class|filter|...). If +# there is one, first call _tc_direct_complete to see if previous word is +# waiting for a particular completion. If so, propose completion and exit. +# 4. Extract main command and -- if available -- its subcommand +# (add|delete|show|...). +# 5. Propose completion based on main and sub- command in use. Additional +# functions may be called for qdiscs, classes or filter options. +_tc() +{ + local cur prev words cword + _init_completion || return + + case $prev in + -V|-Version) + return 0 + ;; + -b|-batch|-cf|-conf) + _filedir + return 0 + ;; + -force) + COMPREPLY=( $( compgen -W '-batch' -- "$cur" ) ) + return 0 + ;; + -nm|name) + [[ -r /etc/iproute2/tc_cls ]] || \ + COMPREPLY=( $( compgen -W '-conf' -- "$cur" ) ) + return 0 + ;; + -n|-net|-netns) + local nslist=$( ip netns list 2>/dev/null ) + COMPREPLY+=( $( compgen -W "$nslist" -- "$cur" ) ) + return 0 + ;; + -tshort) + _tc_once_attr '-statistics' + COMPREPLY+=( $( compgen -W 'monitor' -- "$cur" ) ) + return 0 + ;; + -timestamp) + _tc_once_attr '-statistics -tshort' + COMPREPLY+=( $( compgen -W 'monitor' -- "$cur" ) ) + return 0 + ;; + esac + + # Search for main commands + local subcword cmd subcmd + for (( subcword=1; subcword < ${#words[@]}-1; subcword++ )); do + [[ ${words[subcword]} == -b?(atch) ]] && return 0 + [[ -n $cmd ]] && subcmd=${words[subcword]} && break + [[ ${words[subcword]} != -* && \ + ${words[subcword-1]} != -@(n?(et?(ns))|c?(on)f) ]] && \ + cmd=${words[subcword]} + done + + if [[ -z $cmd ]]; then + case $cur in + -*) + local c='-Version -statistics -details -raw -pretty \ + -iec -graphe -batch -name -netns -timestamp' + [[ $cword -eq 1 ]] && c+=' -force' + COMPREPLY=( $( compgen -W "$c" -- "$cur" ) ) + return 0 + ;; + *) + COMPREPLY=( $( compgen -W "help $( tc help 2>&1 | \ + command sed \ + -e '/OBJECT := /!d' \ + -e 's/.*{//' \ + -e 's/}.*//' \ + -e \ 's/|//g' )" -- "$cur" ) ) + return 0 + ;; + esac + fi + + [[ $subcmd == help ]] && return 0 + + # For this set of commands we may create COMPREPLY just by analysing the + # previous word, if it expects for a specific list of options or values. + if [[ $cmd =~ (qdisc|class|filter|action|exec) ]]; then + _tc_direct_complete $prev && return 0 + if [[ ${words[${#words[@]}-3]} == estimator ]]; then + local list=$( _tc_expand_units 'secs' 'msecs' 'usecs' ) + COMPREPLY+=( $( compgen -W "$list" -- "$cur" ) ) && return 0 + fi + fi + + # Completion depends on main command and subcommand in use. + case $cmd in + qdisc) + case $subcmd in + add|change|replace|link|del|delete) + if [[ $(($cword-$subcword)) -eq 1 ]]; then + COMPREPLY=( $( compgen -W 'dev' -- "$cur" ) ) + return 0 + fi + local qdisc qdwd QDISC_KIND=' choke codel bfifo pfifo \ + pfifo_head_drop fq fq_codel gred hhf mqprio multiq \ + netem pfifo_fast pie red rr sfb sfq tbf atm cbq drr \ + dsmark hfsc htb prio qfq ' + for ((qdwd=$subcword; qdwd < ${#words[@]}-1; qdwd++)); do + if [[ $QDISC_KIND =~ ' '${words[qdwd]}' ' ]]; then + qdisc=${words[qdwd]} + _tc_qdisc_options $qdisc && return 0 + fi + done + _tc_one_of_list $QDISC_KIND + _tc_one_of_list 'root ingress parent clsact' + _tc_once_attr 'handle estimator stab' + ;; + show) + _tc_once_attr 'dev' + _tc_one_of_list 'ingress clsact' + _tc_once_attr '-statistics -details -raw -pretty -iec \ + -graph -name' + ;; + help) + return 0 + ;; + *) + [[ $cword -eq $subcword ]] && \ + COMPREPLY=( $( compgen -W 'help add delete change \ + replace link show' -- "$cur" ) ) + ;; + esac + ;; + + class) + case $subcmd in + add|change|replace|del|delete) + if [[ $(($cword-$subcword)) -eq 1 ]]; then + COMPREPLY=( $( compgen -W 'dev' -- "$cur" ) ) + return 0 + fi + local qdisc qdwd QDISC_KIND=' choke codel bfifo pfifo \ + pfifo_head_drop fq fq_codel gred hhf mqprio multiq \ + netem pfifo_fast pie red rr sfb sfq tbf atm cbq drr \ + dsmark hfsc htb prio qfq ' + for ((qdwd=$subcword; qdwd < ${#words[@]}-1; qdwd++)); do + if [[ $QDISC_KIND =~ ' '${words[qdwd]}' ' ]]; then + qdisc=${words[qdwd]} + _tc_qdisc_options $qdisc && return 0 + fi + done + _tc_one_of_list $QDISC_KIND + _tc_one_of_list 'root parent' + _tc_once_attr 'classid' + ;; + show) + _tc_once_attr 'dev' + _tc_one_of_list 'root parent' + _tc_once_attr '-statistics -details -raw -pretty -iec \ + -graph -name' + ;; + help) + return 0 + ;; + *) + [[ $cword -eq $subcword ]] && \ + COMPREPLY=( $( compgen -W 'help add delete change \ + replace show' -- "$cur" ) ) + ;; + esac + ;; + + filter) + case $subcmd in + add|change|replace|del|delete) + if [[ $(($cword-$subcword)) -eq 1 ]]; then + COMPREPLY=( $( compgen -W 'dev' -- "$cur" ) ) + return 0 + fi + local filter fltwd FILTER_KIND=' basic bpf cgroup flow \ + flower fw route rsvp tcindex u32 ' + for ((fltwd=$subcword; fltwd < ${#words[@]}-1; fltwd++)); + do + if [[ $FILTER_KIND =~ ' '${words[fltwd]}' ' ]]; then + filter=${words[fltwd]} + _tc_filter_options $filter && return 0 + fi + done + _tc_one_of_list $FILTER_KIND + _tc_one_of_list 'root ingress egress parent' + _tc_once_attr 'handle estimator pref protocol' + ;; + show) + _tc_once_attr 'dev' + _tc_one_of_list 'root ingress egress parent' + _tc_once_attr '-statistics -details -raw -pretty -iec \ + -graph -name' + ;; + help) + return 0 + ;; + *) + [[ $cword -eq $subcword ]] && \ + COMPREPLY=( $( compgen -W 'help add delete change \ + replace show' -- "$cur" ) ) + ;; + esac + ;; + + action) + case $subcmd in + add|change|replace) + local action acwd ACTION_KIND=' gact mirred bpf ' + for ((acwd=$subcword; acwd < ${#words[@]}-1; acwd++)); do + if [[ $ACTION_KIND =~ ' '${words[acwd]}' ' ]]; then + action=${words[acwd]} + _tc_action_options $action && return 0 + fi + done + _tc_one_of_list $ACTION_KIND + ;; + get|del|delete) + _tc_once_attr 'index' + ;; + lst|list|flush|show) + _tc_one_of_list $ACTION_KIND + ;; + *) + [[ $cword -eq $subcword ]] && \ + COMPREPLY=( $( compgen -W 'help add delete change \ + replace show list flush action' -- "$cur" ) ) + ;; + esac + ;; + + monitor) + COMPREPLY=( $( compgen -W 'help' -- "$cur" ) ) + ;; + + exec) + case $subcmd in + bpf) + local excmd exwd EXEC_KIND=' import debug graft ' + for ((exwd=$subcword; exwd < ${#words[@]}-1; exwd++)); do + if [[ $EXEC_KIND =~ ' '${words[exwd]}' ' ]]; then + excmd=${words[exwd]} + _tc_exec_options $excmd && return 0 + fi + done + _tc_one_of_list $EXEC_KIND + ;; + *) + [[ $cword -eq $subcword ]] && \ + COMPREPLY=( $( compgen -W 'bpf' -- "$cur" ) ) + ;; + esac + ;; + esac +} && +complete -F _tc tc + +# ex: ts=4 sw=4 et filetype=sh From df217d5d5ccc25e564acf94935ab5d74443fe69b Mon Sep 17 00:00:00 2001 From: Jiri Benc Date: Wed, 27 Apr 2016 16:11:13 +0200 Subject: [PATCH 2/8] ip link gre: create interfaces in external mode correctly For GRE interfaces in 'external' mode, the kernel ignores all manual settings like remote IP address or TTL. However, for some of those attributes, kernel checks their value and does not allow them to be zero (even though they're ignored later). Currently, 'ip link' always includes all attributes in the netlink message. This leads to problem with creating interfaces in 'external' mode. For example, this command does not work: ip link add gre1 type gretap external and needs a bogus remote IP address to be specified, as the kernel enforces remote IP address to be either not present, or not null. Ignore the parameters that do not make sense in 'external' mode. Unfortunately, we cannot error out, as there may be existing deployments that workarounded the bug by specifying bogus values. Fixes: 926b39e1feffd ("gre: add support for collect metadata flag") Signed-off-by: Jiri Benc --- ip/link_gre.c | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/ip/link_gre.c b/ip/link_gre.c index bcf003aa..36ce1252 100644 --- a/ip/link_gre.c +++ b/ip/link_gre.c @@ -315,24 +315,26 @@ get_failed: return -1; } - addattr32(n, 1024, IFLA_GRE_IKEY, ikey); - addattr32(n, 1024, IFLA_GRE_OKEY, okey); - addattr_l(n, 1024, IFLA_GRE_IFLAGS, &iflags, 2); - addattr_l(n, 1024, IFLA_GRE_OFLAGS, &oflags, 2); - addattr_l(n, 1024, IFLA_GRE_LOCAL, &saddr, 4); - addattr_l(n, 1024, IFLA_GRE_REMOTE, &daddr, 4); - addattr_l(n, 1024, IFLA_GRE_PMTUDISC, &pmtudisc, 1); - if (link) - addattr32(n, 1024, IFLA_GRE_LINK, link); - addattr_l(n, 1024, IFLA_GRE_TTL, &ttl, 1); - addattr_l(n, 1024, IFLA_GRE_TOS, &tos, 1); + if (!metadata) { + addattr32(n, 1024, IFLA_GRE_IKEY, ikey); + addattr32(n, 1024, IFLA_GRE_OKEY, okey); + addattr_l(n, 1024, IFLA_GRE_IFLAGS, &iflags, 2); + addattr_l(n, 1024, IFLA_GRE_OFLAGS, &oflags, 2); + addattr_l(n, 1024, IFLA_GRE_LOCAL, &saddr, 4); + addattr_l(n, 1024, IFLA_GRE_REMOTE, &daddr, 4); + addattr_l(n, 1024, IFLA_GRE_PMTUDISC, &pmtudisc, 1); + if (link) + addattr32(n, 1024, IFLA_GRE_LINK, link); + addattr_l(n, 1024, IFLA_GRE_TTL, &ttl, 1); + addattr_l(n, 1024, IFLA_GRE_TOS, &tos, 1); + } else { + addattr_l(n, 1024, IFLA_GRE_COLLECT_METADATA, NULL, 0); + } addattr16(n, 1024, IFLA_GRE_ENCAP_TYPE, encaptype); addattr16(n, 1024, IFLA_GRE_ENCAP_FLAGS, encapflags); addattr16(n, 1024, IFLA_GRE_ENCAP_SPORT, htons(encapsport)); addattr16(n, 1024, IFLA_GRE_ENCAP_DPORT, htons(encapdport)); - if (metadata) - addattr_l(n, 1024, IFLA_GRE_COLLECT_METADATA, NULL, 0); return 0; } From 7c337e2c20cac3ec85fb011617d4d281fde912b3 Mon Sep 17 00:00:00 2001 From: Jiri Benc Date: Wed, 27 Apr 2016 16:11:14 +0200 Subject: [PATCH 3/8] ip link gre: print only relevant info in external mode Display only attributes that are relevant when a GRE interface is in 'external' mode instead of the default values (which are ignored by the kernel even if passed back). Fixes: 926b39e1feffd ("gre: add support for collect metadata flag") Signed-off-by: Jiri Benc --- ip/link_gre.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/ip/link_gre.c b/ip/link_gre.c index 36ce1252..492c2205 100644 --- a/ip/link_gre.c +++ b/ip/link_gre.c @@ -339,7 +339,7 @@ get_failed: return 0; } -static void gre_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[]) +static void gre_print_direct_opt(FILE *f, struct rtattr *tb[]) { char s2[64]; const char *local = "any"; @@ -347,9 +347,6 @@ static void gre_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[]) unsigned int iflags = 0; unsigned int oflags = 0; - if (!tb) - return; - if (tb[IFLA_GRE_REMOTE]) { unsigned int addr = rta_getattr_u32(tb[IFLA_GRE_REMOTE]); @@ -421,8 +418,16 @@ static void gre_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[]) fputs("icsum ", f); if (oflags & GRE_CSUM) fputs("ocsum ", f); +} - if (tb[IFLA_GRE_COLLECT_METADATA]) +static void gre_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[]) +{ + if (!tb) + return; + + if (!tb[IFLA_GRE_COLLECT_METADATA]) + gre_print_direct_opt(f, tb); + else fputs("external ", f); if (tb[IFLA_GRE_ENCAP_TYPE] && From 2642b6b03e546b04e163a7cb2585ece791324a05 Mon Sep 17 00:00:00 2001 From: Edward Cree Date: Fri, 6 May 2016 15:28:25 +0100 Subject: [PATCH 4/8] geneve: fix IPv6 remote address reporting Since we can only configure unicast, we probably want to be able to display unicast, rather than multicast. Fixes: 906ac5437ab8 ("geneve: add support for IPv6 link partners") Signed-off-by: Edward Cree --- ip/iplink_geneve.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ip/iplink_geneve.c b/ip/iplink_geneve.c index 84d948fc..65af6b35 100644 --- a/ip/iplink_geneve.c +++ b/ip/iplink_geneve.c @@ -204,7 +204,7 @@ static void geneve_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[]) memcpy(&addr, RTA_DATA(tb[IFLA_GENEVE_REMOTE6]), sizeof(struct in6_addr)); if (memcmp(&addr, &in6addr_any, sizeof(addr)) != 0) { - if (IN6_IS_ADDR_MULTICAST(&addr)) + if (!IN6_IS_ADDR_MULTICAST(&addr)) fprintf(f, "remote %s ", format_host(AF_INET6, sizeof(struct in6_addr), &addr)); } From c3d25ec3924ad4a90d04112f8da8846201f0b138 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Fri, 13 May 2016 14:38:38 -0700 Subject: [PATCH 5/8] Revert "devlink: implement shared buffer occupancy control" This reverts commit a60ebcb6f34f4c43cba092f52b1150d7fb1deec5. --- devlink/devlink.c | 349 ---------------------------------------- include/linux/devlink.h | 6 - 2 files changed, 355 deletions(-) diff --git a/devlink/devlink.c b/devlink/devlink.c index ffefa86d..228807f8 100644 --- a/devlink/devlink.c +++ b/devlink/devlink.c @@ -27,12 +27,6 @@ #define pr_err(args...) fprintf(stderr, ##args) #define pr_out(args...) fprintf(stdout, ##args) -#define pr_out_sp(num, args...) \ - do { \ - int ret = fprintf(stdout, ##args); \ - if (ret < num) \ - fprintf(stdout, "%*s", num - ret, ""); \ - } while (0) static int _mnlg_socket_recv_run(struct mnlg_socket *nlg, mnl_cb_t data_cb, void *data) @@ -281,12 +275,6 @@ static int attr_cb(const struct nlattr *attr, void *data) if (type == DEVLINK_ATTR_SB_TC_INDEX && mnl_attr_validate(attr, MNL_TYPE_U16) < 0) return MNL_CB_ERROR; - if (type == DEVLINK_ATTR_SB_OCC_CUR && - mnl_attr_validate(attr, MNL_TYPE_U32) < 0) - return MNL_CB_ERROR; - if (type == DEVLINK_ATTR_SB_OCC_MAX && - mnl_attr_validate(attr, MNL_TYPE_U32) < 0) - return MNL_CB_ERROR; tb[type] = attr; return MNL_CB_OK; } @@ -876,7 +864,6 @@ static bool dl_dump_filter(struct dl *dl, struct nlattr **tb) struct nlattr *attr_bus_name = tb[DEVLINK_ATTR_BUS_NAME]; struct nlattr *attr_dev_name = tb[DEVLINK_ATTR_DEV_NAME]; struct nlattr *attr_port_index = tb[DEVLINK_ATTR_PORT_INDEX]; - struct nlattr *attr_sb_index = tb[DEVLINK_ATTR_SB_INDEX]; if (opts->present & DL_OPT_HANDLE && attr_bus_name && attr_dev_name) { @@ -898,12 +885,6 @@ static bool dl_dump_filter(struct dl *dl, struct nlattr **tb) port_index != opts->port_index) return false; } - if (opts->present & DL_OPT_SB && attr_sb_index) { - uint32_t sb_index = mnl_attr_get_u32(attr_sb_index); - - if (sb_index != opts->sb_index) - return false; - } return true; } @@ -1187,9 +1168,6 @@ static void cmd_sb_help(void) pr_out(" devlink sb tc bind set DEV/PORT_INDEX [ sb SB_INDEX ] tc TC_INDEX\n"); pr_out(" type { ingress | egress } pool POOL_INDEX\n"); pr_out(" th THRESHOLD\n"); - pr_out(" devlink sb occupancy show { DEV | DEV/PORT_INDEX } [ sb SB_INDEX ]\n"); - pr_out(" devlink sb occupancy snapshot DEV [ sb SB_INDEX ]\n"); - pr_out(" devlink sb occupancy clearmax DEV [ sb SB_INDEX ]\n"); } static void pr_out_sb(struct nlattr **tb) @@ -1526,330 +1504,6 @@ static int cmd_sb_tc(struct dl *dl) return -ENOENT; } -struct occ_item { - struct list_head list; - uint32_t index; - uint32_t cur; - uint32_t max; - uint32_t bound_pool_index; -}; - -struct occ_port { - struct list_head list; - char *bus_name; - char *dev_name; - uint32_t port_index; - uint32_t sb_index; - struct list_head pool_list; - struct list_head ing_tc_list; - struct list_head eg_tc_list; -}; - -struct occ_show { - struct dl *dl; - int err; - struct list_head port_list; -}; - -static struct occ_item *occ_item_alloc(void) -{ - return calloc(1, sizeof(struct occ_item)); -} - -static void occ_item_free(struct occ_item *occ_item) -{ - free(occ_item); -} - -static struct occ_port *occ_port_alloc(uint32_t port_index) -{ - struct occ_port *occ_port; - - occ_port = calloc(1, sizeof(*occ_port)); - if (!occ_port) - return NULL; - occ_port->port_index = port_index; - INIT_LIST_HEAD(&occ_port->pool_list); - INIT_LIST_HEAD(&occ_port->ing_tc_list); - INIT_LIST_HEAD(&occ_port->eg_tc_list); - return occ_port; -} - -static void occ_port_free(struct occ_port *occ_port) -{ - struct occ_item *occ_item, *tmp; - - list_for_each_entry_safe(occ_item, tmp, &occ_port->pool_list, list) - occ_item_free(occ_item); - list_for_each_entry_safe(occ_item, tmp, &occ_port->ing_tc_list, list) - occ_item_free(occ_item); - list_for_each_entry_safe(occ_item, tmp, &occ_port->eg_tc_list, list) - occ_item_free(occ_item); -} - -static struct occ_show *occ_show_alloc(struct dl *dl) -{ - struct occ_show *occ_show; - - occ_show = calloc(1, sizeof(*occ_show)); - if (!occ_show) - return NULL; - occ_show->dl = dl; - INIT_LIST_HEAD(&occ_show->port_list); - return occ_show; -} - -static void occ_show_free(struct occ_show *occ_show) -{ - struct occ_port *occ_port, *tmp; - - list_for_each_entry_safe(occ_port, tmp, &occ_show->port_list, list) - occ_port_free(occ_port); -} - -static struct occ_port *occ_port_get(struct occ_show *occ_show, - struct nlattr **tb) -{ - struct occ_port *occ_port; - uint32_t port_index; - - port_index = mnl_attr_get_u32(tb[DEVLINK_ATTR_PORT_INDEX]); - - list_for_each_entry_reverse(occ_port, &occ_show->port_list, list) { - if (occ_port->port_index == port_index) - return occ_port; - } - occ_port = occ_port_alloc(port_index); - if (!occ_port) - return NULL; - list_add_tail(&occ_port->list, &occ_show->port_list); - return occ_port; -} - -static void pr_out_occ_show_item_list(const char *label, struct list_head *list, - bool bound_pool) -{ - struct occ_item *occ_item; - int i = 1; - - pr_out_sp(7, " %s:", label); - list_for_each_entry(occ_item, list, list) { - if ((i - 1) % 4 == 0 && i != 1) - pr_out_sp(7, " "); - if (bound_pool) - pr_out_sp(7, "%2u(%u):", occ_item->index, - occ_item->bound_pool_index); - else - pr_out_sp(7, "%2u:", occ_item->index); - pr_out_sp(15, "%7u/%u", occ_item->cur, occ_item->max); - if (i++ % 4 == 0) - pr_out("\n"); - } - if ((i - 1) % 4 != 0) - pr_out("\n"); -} - -static void pr_out_occ_show_port(struct occ_port *occ_port) -{ - pr_out_occ_show_item_list("pool", &occ_port->pool_list, false); - pr_out_occ_show_item_list("itc", &occ_port->ing_tc_list, true); - pr_out_occ_show_item_list("etc", &occ_port->eg_tc_list, true); -} - -static void pr_out_occ_show(struct occ_show *occ_show) -{ - struct dl *dl = occ_show->dl; - struct dl_opts *opts = &dl->opts; - struct occ_port *occ_port; - - list_for_each_entry(occ_port, &occ_show->port_list, list) { - __pr_out_port_handle_nice(dl, opts->bus_name, opts->dev_name, - occ_port->port_index); - pr_out(":\n"); - pr_out_occ_show_port(occ_port); - } -} - -static void cmd_sb_occ_port_pool_process(struct occ_show *occ_show, - struct nlattr **tb) -{ - struct occ_port *occ_port; - struct occ_item *occ_item; - - if (occ_show->err || !dl_dump_filter(occ_show->dl, tb)) - return; - - occ_port = occ_port_get(occ_show, tb); - if (!occ_port) { - occ_show->err = -ENOMEM; - return; - } - - occ_item = occ_item_alloc(); - if (!occ_item) { - occ_show->err = -ENOMEM; - return; - } - occ_item->index = mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_POOL_INDEX]); - occ_item->cur = mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_OCC_CUR]); - occ_item->max = mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_OCC_MAX]); - list_add_tail(&occ_item->list, &occ_port->pool_list); -} - -static int cmd_sb_occ_port_pool_process_cb(const struct nlmsghdr *nlh, void *data) -{ - struct occ_show *occ_show = data; - struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {}; - struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh); - - mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb); - if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] || - !tb[DEVLINK_ATTR_PORT_INDEX] || !tb[DEVLINK_ATTR_SB_INDEX] || - !tb[DEVLINK_ATTR_SB_POOL_INDEX] || - !tb[DEVLINK_ATTR_SB_OCC_CUR] || !tb[DEVLINK_ATTR_SB_OCC_MAX]) - return MNL_CB_ERROR; - cmd_sb_occ_port_pool_process(occ_show, tb); - return MNL_CB_OK; -} - -static void cmd_sb_occ_tc_pool_process(struct occ_show *occ_show, - struct nlattr **tb) -{ - struct occ_port *occ_port; - struct occ_item *occ_item; - uint8_t pool_type; - - if (occ_show->err || !dl_dump_filter(occ_show->dl, tb)) - return; - - occ_port = occ_port_get(occ_show, tb); - if (!occ_port) { - occ_show->err = -ENOMEM; - return; - } - - occ_item = occ_item_alloc(); - if (!occ_item) { - occ_show->err = -ENOMEM; - return; - } - occ_item->index = mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_TC_INDEX]); - occ_item->cur = mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_OCC_CUR]); - occ_item->max = mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_OCC_MAX]); - occ_item->bound_pool_index = - mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_POOL_INDEX]); - pool_type = mnl_attr_get_u8(tb[DEVLINK_ATTR_SB_POOL_TYPE]); - if (pool_type == DEVLINK_SB_POOL_TYPE_INGRESS) - list_add_tail(&occ_item->list, &occ_port->ing_tc_list); - else if (pool_type == DEVLINK_SB_POOL_TYPE_EGRESS) - list_add_tail(&occ_item->list, &occ_port->eg_tc_list); - else - occ_item_free(occ_item); -} - -static int cmd_sb_occ_tc_pool_process_cb(const struct nlmsghdr *nlh, void *data) -{ - struct occ_show *occ_show = data; - struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {}; - struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh); - - mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb); - if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] || - !tb[DEVLINK_ATTR_PORT_INDEX] || !tb[DEVLINK_ATTR_SB_INDEX] || - !tb[DEVLINK_ATTR_SB_TC_INDEX] || !tb[DEVLINK_ATTR_SB_POOL_TYPE] || - !tb[DEVLINK_ATTR_SB_POOL_INDEX] || - !tb[DEVLINK_ATTR_SB_OCC_CUR] || !tb[DEVLINK_ATTR_SB_OCC_MAX]) - return MNL_CB_ERROR; - cmd_sb_occ_tc_pool_process(occ_show, tb); - return MNL_CB_OK; -} - -static int cmd_sb_occ_show(struct dl *dl) -{ - struct nlmsghdr *nlh; - struct occ_show *occ_show; - uint16_t flags = NLM_F_REQUEST | NLM_F_ACK | NLM_F_DUMP; - int err; - - err = dl_argv_parse(dl, DL_OPT_HANDLE | DL_OPT_HANDLEP, DL_OPT_SB); - if (err) - return err; - - occ_show = occ_show_alloc(dl); - if (!occ_show) - return -ENOMEM; - - nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_PORT_POOL_GET, flags); - - err = _mnlg_socket_sndrcv(dl->nlg, nlh, - cmd_sb_occ_port_pool_process_cb, occ_show); - if (err) - goto out; - - nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_TC_POOL_BIND_GET, flags); - - err = _mnlg_socket_sndrcv(dl->nlg, nlh, - cmd_sb_occ_tc_pool_process_cb, occ_show); - if (err) - goto out; - - pr_out_occ_show(occ_show); - -out: - occ_show_free(occ_show); - return err; -} - -static int cmd_sb_occ_snapshot(struct dl *dl) -{ - struct nlmsghdr *nlh; - int err; - - nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_OCC_SNAPSHOT, - NLM_F_REQUEST | NLM_F_ACK); - - err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE, DL_OPT_SB); - if (err) - return err; - - return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL); -} - -static int cmd_sb_occ_clearmax(struct dl *dl) -{ - struct nlmsghdr *nlh; - int err; - - nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_OCC_MAX_CLEAR, - NLM_F_REQUEST | NLM_F_ACK); - - err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE, DL_OPT_SB); - if (err) - return err; - - return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL); -} - -static int cmd_sb_occ(struct dl *dl) -{ - if (dl_argv_match(dl, "help") || dl_no_arg(dl)) { - cmd_sb_help(); - return 0; - } else if (dl_argv_match(dl, "show") || - dl_argv_match(dl, "list")) { - dl_arg_inc(dl); - return cmd_sb_occ_show(dl); - } else if (dl_argv_match(dl, "snapshot")) { - dl_arg_inc(dl); - return cmd_sb_occ_snapshot(dl); - } else if (dl_argv_match(dl, "clearmax")) { - dl_arg_inc(dl); - return cmd_sb_occ_clearmax(dl); - } - pr_err("Command \"%s\" not found\n", dl_argv(dl)); - return -ENOENT; -} - static int cmd_sb(struct dl *dl) { if (dl_argv_match(dl, "help")) { @@ -1868,9 +1522,6 @@ static int cmd_sb(struct dl *dl) } else if (dl_argv_match(dl, "tc")) { dl_arg_inc(dl); return cmd_sb_tc(dl); - } else if (dl_argv_match(dl, "occupancy")) { - dl_arg_inc(dl); - return cmd_sb_occ(dl); } pr_err("Command \"%s\" not found\n", dl_argv(dl)); return -ENOENT; diff --git a/include/linux/devlink.h b/include/linux/devlink.h index ba0073b2..9c1aa578 100644 --- a/include/linux/devlink.h +++ b/include/linux/devlink.h @@ -53,10 +53,6 @@ enum devlink_command { DEVLINK_CMD_SB_TC_POOL_BIND_NEW, DEVLINK_CMD_SB_TC_POOL_BIND_DEL, - /* Shared buffer occupancy monitoring commands */ - DEVLINK_CMD_SB_OCC_SNAPSHOT, - DEVLINK_CMD_SB_OCC_MAX_CLEAR, - /* add new commands above here */ __DEVLINK_CMD_MAX, @@ -123,8 +119,6 @@ enum devlink_attr { DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE, /* u8 */ DEVLINK_ATTR_SB_THRESHOLD, /* u32 */ DEVLINK_ATTR_SB_TC_INDEX, /* u16 */ - DEVLINK_ATTR_SB_OCC_CUR, /* u32 */ - DEVLINK_ATTR_SB_OCC_MAX, /* u32 */ /* add new attributes above here, update the policy in devlink.c */ From 7aca60c0eb73b8d577c2a36be830a82d4cb8f861 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Fri, 13 May 2016 14:38:47 -0700 Subject: [PATCH 6/8] Revert "devlink: implement shared buffer support" This reverts commit b56700bf8add4ebb2fe451c85f50602b58a886a2. --- devlink/devlink.c | 603 +--------------------------------------- include/linux/devlink.h | 57 ---- 2 files changed, 1 insertion(+), 659 deletions(-) diff --git a/devlink/devlink.c b/devlink/devlink.c index 228807f8..e2e04136 100644 --- a/devlink/devlink.c +++ b/devlink/devlink.c @@ -114,13 +114,6 @@ static void ifname_map_free(struct ifname_map *ifname_map) #define DL_OPT_HANDLEP BIT(1) #define DL_OPT_PORT_TYPE BIT(2) #define DL_OPT_PORT_COUNT BIT(3) -#define DL_OPT_SB BIT(4) -#define DL_OPT_SB_POOL BIT(5) -#define DL_OPT_SB_SIZE BIT(6) -#define DL_OPT_SB_TYPE BIT(7) -#define DL_OPT_SB_THTYPE BIT(8) -#define DL_OPT_SB_TH BIT(9) -#define DL_OPT_SB_TC BIT(10) struct dl_opts { uint32_t present; /* flags of present items */ @@ -129,13 +122,6 @@ struct dl_opts { uint32_t port_index; enum devlink_port_type port_type; uint32_t port_count; - uint32_t sb_index; - uint16_t sb_pool_index; - uint32_t sb_pool_size; - enum devlink_sb_pool_type sb_pool_type; - enum devlink_sb_threshold_type sb_pool_thtype; - uint32_t sb_threshold; - uint16_t sb_tc_index; }; struct dl { @@ -239,42 +225,6 @@ static int attr_cb(const struct nlattr *attr, void *data) if (type == DEVLINK_ATTR_PORT_IBDEV_NAME && mnl_attr_validate(attr, MNL_TYPE_NUL_STRING) < 0) return MNL_CB_ERROR; - if (type == DEVLINK_ATTR_SB_INDEX && - mnl_attr_validate(attr, MNL_TYPE_U32) < 0) - return MNL_CB_ERROR; - if (type == DEVLINK_ATTR_SB_SIZE && - mnl_attr_validate(attr, MNL_TYPE_U32) < 0) - return MNL_CB_ERROR; - if (type == DEVLINK_ATTR_SB_INGRESS_POOL_COUNT && - mnl_attr_validate(attr, MNL_TYPE_U16) < 0) - return MNL_CB_ERROR; - if (type == DEVLINK_ATTR_SB_EGRESS_POOL_COUNT && - mnl_attr_validate(attr, MNL_TYPE_U16) < 0) - return MNL_CB_ERROR; - if (type == DEVLINK_ATTR_SB_INGRESS_TC_COUNT && - mnl_attr_validate(attr, MNL_TYPE_U16) < 0) - return MNL_CB_ERROR; - if (type == DEVLINK_ATTR_SB_EGRESS_TC_COUNT && - mnl_attr_validate(attr, MNL_TYPE_U16) < 0) - return MNL_CB_ERROR; - if (type == DEVLINK_ATTR_SB_POOL_INDEX && - mnl_attr_validate(attr, MNL_TYPE_U16) < 0) - return MNL_CB_ERROR; - if (type == DEVLINK_ATTR_SB_POOL_TYPE && - mnl_attr_validate(attr, MNL_TYPE_U8) < 0) - return MNL_CB_ERROR; - if (type == DEVLINK_ATTR_SB_POOL_SIZE && - mnl_attr_validate(attr, MNL_TYPE_U32) < 0) - return MNL_CB_ERROR; - if (type == DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE && - mnl_attr_validate(attr, MNL_TYPE_U8) < 0) - return MNL_CB_ERROR; - if (type == DEVLINK_ATTR_SB_THRESHOLD && - mnl_attr_validate(attr, MNL_TYPE_U32) < 0) - return MNL_CB_ERROR; - if (type == DEVLINK_ATTR_SB_TC_INDEX && - mnl_attr_validate(attr, MNL_TYPE_U16) < 0) - return MNL_CB_ERROR; tb[type] = attr; return MNL_CB_OK; } @@ -413,20 +363,6 @@ static int strtouint32_t(const char *str, uint32_t *p_val) return 0; } -static int strtouint16_t(const char *str, uint16_t *p_val) -{ - char *endptr; - unsigned long int val; - - val = strtoul(str, &endptr, 10); - if (endptr == str || *endptr != '\0') - return -EINVAL; - if (val > USHRT_MAX) - return -ERANGE; - *p_val = val; - return 0; -} - static int __dl_argv_handle(char *str, char **p_bus_name, char **p_dev_name) { strslashrsplit(str, p_bus_name, p_dev_name); @@ -567,24 +503,6 @@ static int dl_argv_uint32_t(struct dl *dl, uint32_t *p_val) return 0; } -static int dl_argv_uint16_t(struct dl *dl, uint16_t *p_val) -{ - char *str = dl_argv_next(dl); - int err; - - if (!str) { - pr_err("Unsigned number argument expected\n"); - return -EINVAL; - } - - err = strtouint16_t(str, p_val); - if (err) { - pr_err("\"%s\" is not a number or not within range\n", str); - return err; - } - return 0; -} - static int dl_argv_str(struct dl *dl, const char **p_str) { const char *str = dl_argv_next(dl); @@ -612,33 +530,6 @@ static int port_type_get(const char *typestr, enum devlink_port_type *p_type) return 0; } -static int pool_type_get(const char *typestr, enum devlink_sb_pool_type *p_type) -{ - if (strcmp(typestr, "ingress") == 0) { - *p_type = DEVLINK_SB_POOL_TYPE_INGRESS; - } else if (strcmp(typestr, "egress") == 0) { - *p_type = DEVLINK_SB_POOL_TYPE_EGRESS; - } else { - pr_err("Unknown pool type \"%s\"\n", typestr); - return -EINVAL; - } - return 0; -} - -static int threshold_type_get(const char *typestr, - enum devlink_sb_threshold_type *p_type) -{ - if (strcmp(typestr, "static") == 0) { - *p_type = DEVLINK_SB_THRESHOLD_TYPE_STATIC; - } else if (strcmp(typestr, "dynamic") == 0) { - *p_type = DEVLINK_SB_THRESHOLD_TYPE_DYNAMIC; - } else { - pr_err("Unknown threshold type \"%s\"\n", typestr); - return -EINVAL; - } - return 0; -} - static int dl_argv_parse(struct dl *dl, uint32_t o_required, uint32_t o_optional) { @@ -688,66 +579,6 @@ static int dl_argv_parse(struct dl *dl, uint32_t o_required, if (err) return err; o_found |= DL_OPT_PORT_COUNT; - } else if (dl_argv_match(dl, "sb") && - (o_all & DL_OPT_SB)) { - dl_arg_inc(dl); - err = dl_argv_uint32_t(dl, &opts->sb_index); - if (err) - return err; - o_found |= DL_OPT_SB; - } else if (dl_argv_match(dl, "pool") && - (o_all & DL_OPT_SB_POOL)) { - dl_arg_inc(dl); - err = dl_argv_uint16_t(dl, &opts->sb_pool_index); - if (err) - return err; - o_found |= DL_OPT_SB_POOL; - } else if (dl_argv_match(dl, "size") && - (o_all & DL_OPT_SB_SIZE)) { - dl_arg_inc(dl); - err = dl_argv_uint32_t(dl, &opts->sb_pool_size); - if (err) - return err; - o_found |= DL_OPT_SB_SIZE; - } else if (dl_argv_match(dl, "type") && - (o_all & DL_OPT_SB_TYPE)) { - const char *typestr; - - dl_arg_inc(dl); - err = dl_argv_str(dl, &typestr); - if (err) - return err; - err = pool_type_get(typestr, &opts->sb_pool_type); - if (err) - return err; - o_found |= DL_OPT_SB_TYPE; - } else if (dl_argv_match(dl, "thtype") && - (o_all & DL_OPT_SB_THTYPE)) { - const char *typestr; - - dl_arg_inc(dl); - err = dl_argv_str(dl, &typestr); - if (err) - return err; - err = threshold_type_get(typestr, - &opts->sb_pool_thtype); - if (err) - return err; - o_found |= DL_OPT_SB_THTYPE; - } else if (dl_argv_match(dl, "th") && - (o_all & DL_OPT_SB_TH)) { - dl_arg_inc(dl); - err = dl_argv_uint32_t(dl, &opts->sb_threshold); - if (err) - return err; - o_found |= DL_OPT_SB_TH; - } else if (dl_argv_match(dl, "tc") && - (o_all & DL_OPT_SB_TC)) { - dl_arg_inc(dl); - err = dl_argv_uint16_t(dl, &opts->sb_tc_index); - if (err) - return err; - o_found |= DL_OPT_SB_TC; } else { pr_err("Unknown option \"%s\"\n", dl_argv(dl)); return -EINVAL; @@ -756,11 +587,6 @@ static int dl_argv_parse(struct dl *dl, uint32_t o_required, opts->present = o_found; - if ((o_optional & DL_OPT_SB) && !(o_found & DL_OPT_SB)) { - opts->sb_index = 0; - opts->present |= DL_OPT_SB; - } - if ((o_required & DL_OPT_PORT_TYPE) && !(o_found & DL_OPT_PORT_TYPE)) { pr_err("Port type option expected.\n"); return -EINVAL; @@ -772,35 +598,6 @@ static int dl_argv_parse(struct dl *dl, uint32_t o_required, return -EINVAL; } - if ((o_required & DL_OPT_SB_POOL) && !(o_found & DL_OPT_SB_POOL)) { - pr_err("Pool index option expected.\n"); - return -EINVAL; - } - - if ((o_required & DL_OPT_SB_SIZE) && !(o_found & DL_OPT_SB_SIZE)) { - pr_err("Pool size option expected.\n"); - return -EINVAL; - } - - if ((o_required & DL_OPT_SB_TYPE) && !(o_found & DL_OPT_SB_TYPE)) { - pr_err("Pool type option expected.\n"); - return -EINVAL; - } - - if ((o_required & DL_OPT_SB_THTYPE) && !(o_found & DL_OPT_SB_THTYPE)) { - pr_err("Pool threshold type option expected.\n"); - return -EINVAL; - } - - if ((o_required & DL_OPT_SB_TH) && !(o_found & DL_OPT_SB_TH)) { - pr_err("Threshold option expected.\n"); - return -EINVAL; - } - - if ((o_required & DL_OPT_SB_TC) && !(o_found & DL_OPT_SB_TC)) { - pr_err("TC index option expected.\n"); - return -EINVAL; - } return 0; } @@ -823,27 +620,6 @@ static void dl_opts_put(struct nlmsghdr *nlh, struct dl *dl) if (opts->present & DL_OPT_PORT_COUNT) mnl_attr_put_u32(nlh, DEVLINK_ATTR_PORT_SPLIT_COUNT, opts->port_count); - if (opts->present & DL_OPT_SB) - mnl_attr_put_u32(nlh, DEVLINK_ATTR_SB_INDEX, - opts->sb_index); - if (opts->present & DL_OPT_SB_POOL) - mnl_attr_put_u16(nlh, DEVLINK_ATTR_SB_POOL_INDEX, - opts->sb_pool_index); - if (opts->present & DL_OPT_SB_SIZE) - mnl_attr_put_u32(nlh, DEVLINK_ATTR_SB_POOL_SIZE, - opts->sb_pool_size); - if (opts->present & DL_OPT_SB_TYPE) - mnl_attr_put_u8(nlh, DEVLINK_ATTR_SB_POOL_TYPE, - opts->sb_pool_type); - if (opts->present & DL_OPT_SB_THTYPE) - mnl_attr_put_u8(nlh, DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE, - opts->sb_pool_thtype); - if (opts->present & DL_OPT_SB_TH) - mnl_attr_put_u32(nlh, DEVLINK_ATTR_SB_THRESHOLD, - opts->sb_threshold); - if (opts->present & DL_OPT_SB_TC) - mnl_attr_put_u16(nlh, DEVLINK_ATTR_SB_TC_INDEX, - opts->sb_tc_index); } static int dl_argv_parse_put(struct nlmsghdr *nlh, struct dl *dl, @@ -1153,380 +929,6 @@ static int cmd_port(struct dl *dl) return -ENOENT; } -static void cmd_sb_help(void) -{ - pr_out("Usage: devlink sb show [ DEV [ sb SB_INDEX ] ]\n"); - pr_out(" devlink sb pool show [ DEV [ sb SB_INDEX ] pool POOL_INDEX ]\n"); - pr_out(" devlink sb pool set DEV [ sb SB_INDEX ] pool POOL_INDEX\n"); - pr_out(" size POOL_SIZE thtype { static | dynamic }\n"); - pr_out(" devlink sb port pool show [ DEV/PORT_INDEX [ sb SB_INDEX ]\n"); - pr_out(" pool POOL_INDEX ]\n"); - pr_out(" devlink sb port pool set DEV/PORT_INDEX [ sb SB_INDEX ]\n"); - pr_out(" pool POOL_INDEX th THRESHOLD\n"); - pr_out(" devlink sb tc bind show [ DEV/PORT_INDEX [ sb SB_INDEX ] tc TC_INDEX\n"); - pr_out(" type { ingress | egress } ]\n"); - pr_out(" devlink sb tc bind set DEV/PORT_INDEX [ sb SB_INDEX ] tc TC_INDEX\n"); - pr_out(" type { ingress | egress } pool POOL_INDEX\n"); - pr_out(" th THRESHOLD\n"); -} - -static void pr_out_sb(struct nlattr **tb) -{ - pr_out_handle(tb); - pr_out(": sb %u size %u ing_pools %u eg_pools %u ing_tcs %u eg_tcs %u\n", - mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_INDEX]), - mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_SIZE]), - mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_INGRESS_POOL_COUNT]), - mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_EGRESS_POOL_COUNT]), - mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_INGRESS_TC_COUNT]), - mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_EGRESS_TC_COUNT])); -} - -static int cmd_sb_show_cb(const struct nlmsghdr *nlh, void *data) -{ - struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {}; - struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh); - - mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb); - if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] || - !tb[DEVLINK_ATTR_SB_INDEX] || !tb[DEVLINK_ATTR_SB_SIZE] || - !tb[DEVLINK_ATTR_SB_INGRESS_POOL_COUNT] || - !tb[DEVLINK_ATTR_SB_EGRESS_POOL_COUNT] || - !tb[DEVLINK_ATTR_SB_INGRESS_TC_COUNT] || - !tb[DEVLINK_ATTR_SB_EGRESS_TC_COUNT]) - return MNL_CB_ERROR; - pr_out_sb(tb); - return MNL_CB_OK; -} - -static int cmd_sb_show(struct dl *dl) -{ - struct nlmsghdr *nlh; - uint16_t flags = NLM_F_REQUEST | NLM_F_ACK; - int err; - - if (dl_argc(dl) == 0) - flags |= NLM_F_DUMP; - - nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_GET, flags); - - if (dl_argc(dl) > 0) { - err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE, DL_OPT_SB); - if (err) - return err; - } - - return _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_sb_show_cb, NULL); -} - -static const char *pool_type_name(uint8_t type) -{ - switch (type) { - case DEVLINK_SB_POOL_TYPE_INGRESS: return "ingress"; - case DEVLINK_SB_POOL_TYPE_EGRESS: return "egress"; - default: return ""; - } -} - -static const char *threshold_type_name(uint8_t type) -{ - switch (type) { - case DEVLINK_SB_THRESHOLD_TYPE_STATIC: return "static"; - case DEVLINK_SB_THRESHOLD_TYPE_DYNAMIC: return "dynamic"; - default: return ""; - } -} - -static void pr_out_sb_pool(struct nlattr **tb) -{ - pr_out_handle(tb); - pr_out(": sb %u pool %u type %s size %u thtype %s\n", - mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_INDEX]), - mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_POOL_INDEX]), - pool_type_name(mnl_attr_get_u8(tb[DEVLINK_ATTR_SB_POOL_TYPE])), - mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_POOL_SIZE]), - threshold_type_name(mnl_attr_get_u8(tb[DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE]))); -} - -static int cmd_sb_pool_show_cb(const struct nlmsghdr *nlh, void *data) -{ - struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {}; - struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh); - - mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb); - if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] || - !tb[DEVLINK_ATTR_SB_INDEX] || !tb[DEVLINK_ATTR_SB_POOL_INDEX] || - !tb[DEVLINK_ATTR_SB_POOL_TYPE] || !tb[DEVLINK_ATTR_SB_POOL_SIZE] || - !tb[DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE]) - return MNL_CB_ERROR; - pr_out_sb_pool(tb); - return MNL_CB_OK; -} - -static int cmd_sb_pool_show(struct dl *dl) -{ - struct nlmsghdr *nlh; - uint16_t flags = NLM_F_REQUEST | NLM_F_ACK; - int err; - - if (dl_argc(dl) == 0) - flags |= NLM_F_DUMP; - - nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_POOL_GET, flags); - - if (dl_argc(dl) > 0) { - err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE | DL_OPT_SB_POOL, - DL_OPT_SB); - if (err) - return err; - } - - return _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_sb_pool_show_cb, NULL); -} - -static int cmd_sb_pool_set(struct dl *dl) -{ - struct nlmsghdr *nlh; - int err; - - nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_POOL_SET, - NLM_F_REQUEST | NLM_F_ACK); - - err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE | DL_OPT_SB_POOL | - DL_OPT_SB_SIZE | DL_OPT_SB_THTYPE, DL_OPT_SB); - if (err) - return err; - - return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL); -} - -static int cmd_sb_pool(struct dl *dl) -{ - if (dl_argv_match(dl, "help")) { - cmd_sb_help(); - return 0; - } else if (dl_argv_match(dl, "show") || - dl_argv_match(dl, "list") || dl_no_arg(dl)) { - dl_arg_inc(dl); - return cmd_sb_pool_show(dl); - } else if (dl_argv_match(dl, "set")) { - dl_arg_inc(dl); - return cmd_sb_pool_set(dl); - } - pr_err("Command \"%s\" not found\n", dl_argv(dl)); - return -ENOENT; -} - -static void pr_out_sb_port_pool(struct dl *dl, struct nlattr **tb) -{ - pr_out_port_handle_nice(dl, tb); - pr_out(": sb %u pool %u threshold %u\n", - mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_INDEX]), - mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_POOL_INDEX]), - mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_THRESHOLD])); -} - -static int cmd_sb_port_pool_show_cb(const struct nlmsghdr *nlh, void *data) -{ - struct dl *dl = data; - struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {}; - struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh); - - mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb); - if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] || - !tb[DEVLINK_ATTR_PORT_INDEX] || !tb[DEVLINK_ATTR_SB_INDEX] || - !tb[DEVLINK_ATTR_SB_POOL_INDEX] || !tb[DEVLINK_ATTR_SB_THRESHOLD]) - return MNL_CB_ERROR; - pr_out_sb_port_pool(dl, tb); - return MNL_CB_OK; -} - -static int cmd_sb_port_pool_show(struct dl *dl) -{ - struct nlmsghdr *nlh; - uint16_t flags = NLM_F_REQUEST | NLM_F_ACK; - int err; - - if (dl_argc(dl) == 0) - flags |= NLM_F_DUMP; - - nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_PORT_POOL_GET, flags); - - if (dl_argc(dl) > 0) { - err = dl_argv_parse_put(nlh, dl, - DL_OPT_HANDLEP | DL_OPT_SB_POOL, - DL_OPT_SB); - if (err) - return err; - } - - return _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_sb_port_pool_show_cb, dl); -} - -static int cmd_sb_port_pool_set(struct dl *dl) -{ - struct nlmsghdr *nlh; - int err; - - nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_PORT_POOL_SET, - NLM_F_REQUEST | NLM_F_ACK); - - err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLEP | DL_OPT_SB_POOL | - DL_OPT_SB_TH, DL_OPT_SB); - if (err) - return err; - - return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL); -} - -static int cmd_sb_port_pool(struct dl *dl) -{ - if (dl_argv_match(dl, "help")) { - cmd_sb_help(); - return 0; - } else if (dl_argv_match(dl, "show") || - dl_argv_match(dl, "list") || dl_no_arg(dl)) { - dl_arg_inc(dl); - return cmd_sb_port_pool_show(dl); - } else if (dl_argv_match(dl, "set")) { - dl_arg_inc(dl); - return cmd_sb_port_pool_set(dl); - } - pr_err("Command \"%s\" not found\n", dl_argv(dl)); - return -ENOENT; -} - -static int cmd_sb_port(struct dl *dl) -{ - if (dl_argv_match(dl, "help") || dl_no_arg(dl)) { - cmd_sb_help(); - return 0; - } else if (dl_argv_match(dl, "pool")) { - dl_arg_inc(dl); - return cmd_sb_port_pool(dl); - } - pr_err("Command \"%s\" not found\n", dl_argv(dl)); - return -ENOENT; -} - -static void pr_out_sb_tc_bind(struct dl *dl, struct nlattr **tb) -{ - pr_out_port_handle_nice(dl, tb); - pr_out(": sb %u tc %u type %s pool %u threshold %u\n", - mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_INDEX]), - mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_TC_INDEX]), - pool_type_name(mnl_attr_get_u8(tb[DEVLINK_ATTR_SB_POOL_TYPE])), - mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_POOL_INDEX]), - mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_THRESHOLD])); -} - -static int cmd_sb_tc_bind_show_cb(const struct nlmsghdr *nlh, void *data) -{ - struct dl *dl = data; - struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {}; - struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh); - - mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb); - if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] || - !tb[DEVLINK_ATTR_PORT_INDEX] || !tb[DEVLINK_ATTR_SB_INDEX] || - !tb[DEVLINK_ATTR_SB_TC_INDEX] || !tb[DEVLINK_ATTR_SB_POOL_TYPE] || - !tb[DEVLINK_ATTR_SB_POOL_INDEX] || !tb[DEVLINK_ATTR_SB_THRESHOLD]) - return MNL_CB_ERROR; - pr_out_sb_tc_bind(dl, tb); - return MNL_CB_OK; -} - -static int cmd_sb_tc_bind_show(struct dl *dl) -{ - struct nlmsghdr *nlh; - uint16_t flags = NLM_F_REQUEST | NLM_F_ACK; - int err; - - if (dl_argc(dl) == 0) - flags |= NLM_F_DUMP; - - nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_TC_POOL_BIND_GET, flags); - - if (dl_argc(dl) > 0) { - err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLEP | DL_OPT_SB_TC | - DL_OPT_SB_TYPE, DL_OPT_SB); - if (err) - return err; - } - - return _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_sb_tc_bind_show_cb, dl); -} - -static int cmd_sb_tc_bind_set(struct dl *dl) -{ - struct nlmsghdr *nlh; - int err; - - nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_TC_POOL_BIND_SET, - NLM_F_REQUEST | NLM_F_ACK); - - err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLEP | DL_OPT_SB_TC | - DL_OPT_SB_TYPE | DL_OPT_SB_POOL | DL_OPT_SB_TH, - DL_OPT_SB); - if (err) - return err; - - return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL); -} - -static int cmd_sb_tc_bind(struct dl *dl) -{ - if (dl_argv_match(dl, "help")) { - cmd_sb_help(); - return 0; - } else if (dl_argv_match(dl, "show") || - dl_argv_match(dl, "list") || dl_no_arg(dl)) { - dl_arg_inc(dl); - return cmd_sb_tc_bind_show(dl); - } else if (dl_argv_match(dl, "set")) { - dl_arg_inc(dl); - return cmd_sb_tc_bind_set(dl); - } - pr_err("Command \"%s\" not found\n", dl_argv(dl)); - return -ENOENT; -} - -static int cmd_sb_tc(struct dl *dl) -{ - if (dl_argv_match(dl, "help") || dl_no_arg(dl)) { - cmd_sb_help(); - return 0; - } else if (dl_argv_match(dl, "bind")) { - dl_arg_inc(dl); - return cmd_sb_tc_bind(dl); - } - pr_err("Command \"%s\" not found\n", dl_argv(dl)); - return -ENOENT; -} - -static int cmd_sb(struct dl *dl) -{ - if (dl_argv_match(dl, "help")) { - cmd_sb_help(); - return 0; - } else if (dl_argv_match(dl, "show") || - dl_argv_match(dl, "list") || dl_no_arg(dl)) { - dl_arg_inc(dl); - return cmd_sb_show(dl); - } else if (dl_argv_match(dl, "pool")) { - dl_arg_inc(dl); - return cmd_sb_pool(dl); - } else if (dl_argv_match(dl, "port")) { - dl_arg_inc(dl); - return cmd_sb_port(dl); - } else if (dl_argv_match(dl, "tc")) { - dl_arg_inc(dl); - return cmd_sb_tc(dl); - } - pr_err("Command \"%s\" not found\n", dl_argv(dl)); - return -ENOENT; -} - static const char *cmd_name(uint8_t cmd) { switch (cmd) { @@ -1662,7 +1064,7 @@ static int cmd_mon(struct dl *dl) static void help(void) { pr_out("Usage: devlink [ OPTIONS ] OBJECT { COMMAND | help }\n" - "where OBJECT := { dev | port | sb | monitor }\n" + "where OBJECT := { dev | port | monitor }\n" " OPTIONS := { -V[ersion] | -n[no-nice-names] }\n"); } @@ -1677,9 +1079,6 @@ static int dl_cmd(struct dl *dl) } else if (dl_argv_match(dl, "port")) { dl_arg_inc(dl); return cmd_port(dl); - } else if (dl_argv_match(dl, "sb")) { - dl_arg_inc(dl); - return cmd_sb(dl); } else if (dl_argv_match(dl, "monitor")) { dl_arg_inc(dl); return cmd_mon(dl); diff --git a/include/linux/devlink.h b/include/linux/devlink.h index 9c1aa578..c9fee578 100644 --- a/include/linux/devlink.h +++ b/include/linux/devlink.h @@ -33,26 +33,6 @@ enum devlink_command { DEVLINK_CMD_PORT_SPLIT, DEVLINK_CMD_PORT_UNSPLIT, - DEVLINK_CMD_SB_GET, /* can dump */ - DEVLINK_CMD_SB_SET, - DEVLINK_CMD_SB_NEW, - DEVLINK_CMD_SB_DEL, - - DEVLINK_CMD_SB_POOL_GET, /* can dump */ - DEVLINK_CMD_SB_POOL_SET, - DEVLINK_CMD_SB_POOL_NEW, - DEVLINK_CMD_SB_POOL_DEL, - - DEVLINK_CMD_SB_PORT_POOL_GET, /* can dump */ - DEVLINK_CMD_SB_PORT_POOL_SET, - DEVLINK_CMD_SB_PORT_POOL_NEW, - DEVLINK_CMD_SB_PORT_POOL_DEL, - - DEVLINK_CMD_SB_TC_POOL_BIND_GET, /* can dump */ - DEVLINK_CMD_SB_TC_POOL_BIND_SET, - DEVLINK_CMD_SB_TC_POOL_BIND_NEW, - DEVLINK_CMD_SB_TC_POOL_BIND_DEL, - /* add new commands above here */ __DEVLINK_CMD_MAX, @@ -66,31 +46,6 @@ enum devlink_port_type { DEVLINK_PORT_TYPE_IB, }; -enum devlink_sb_pool_type { - DEVLINK_SB_POOL_TYPE_INGRESS, - DEVLINK_SB_POOL_TYPE_EGRESS, -}; - -/* static threshold - limiting the maximum number of bytes. - * dynamic threshold - limiting the maximum number of bytes - * based on the currently available free space in the shared buffer pool. - * In this mode, the maximum quota is calculated based - * on the following formula: - * max_quota = alpha / (1 + alpha) * Free_Buffer - * While Free_Buffer is the amount of none-occupied buffer associated to - * the relevant pool. - * The value range which can be passed is 0-20 and serves - * for computation of alpha by following formula: - * alpha = 2 ^ (passed_value - 10) - */ - -enum devlink_sb_threshold_type { - DEVLINK_SB_THRESHOLD_TYPE_STATIC, - DEVLINK_SB_THRESHOLD_TYPE_DYNAMIC, -}; - -#define DEVLINK_SB_THRESHOLD_TO_ALPHA_MAX 20 - enum devlink_attr { /* don't change the order or add anything between, this is ABI! */ DEVLINK_ATTR_UNSPEC, @@ -107,18 +62,6 @@ enum devlink_attr { DEVLINK_ATTR_PORT_IBDEV_NAME, /* string */ DEVLINK_ATTR_PORT_SPLIT_COUNT, /* u32 */ DEVLINK_ATTR_PORT_SPLIT_GROUP, /* u32 */ - DEVLINK_ATTR_SB_INDEX, /* u32 */ - DEVLINK_ATTR_SB_SIZE, /* u32 */ - DEVLINK_ATTR_SB_INGRESS_POOL_COUNT, /* u16 */ - DEVLINK_ATTR_SB_EGRESS_POOL_COUNT, /* u16 */ - DEVLINK_ATTR_SB_INGRESS_TC_COUNT, /* u16 */ - DEVLINK_ATTR_SB_EGRESS_TC_COUNT, /* u16 */ - DEVLINK_ATTR_SB_POOL_INDEX, /* u16 */ - DEVLINK_ATTR_SB_POOL_TYPE, /* u8 */ - DEVLINK_ATTR_SB_POOL_SIZE, /* u32 */ - DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE, /* u8 */ - DEVLINK_ATTR_SB_THRESHOLD, /* u32 */ - DEVLINK_ATTR_SB_TC_INDEX, /* u16 */ /* add new attributes above here, update the policy in devlink.c */ From 8a781d7e2580e14f097b23a7c4731bafc800a824 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Fri, 13 May 2016 14:41:45 -0700 Subject: [PATCH 7/8] update kernel headers to 4.6-rc6 Close to final upstream headers --- include/linux/devlink.h | 6 ++-- include/linux/if.h | 28 +++++++++++++++ include/linux/libc-compat.h | 44 ++++++++++++++++++++++++ include/linux/netfilter_ipv4/ip_tables.h | 1 + 4 files changed, 76 insertions(+), 3 deletions(-) diff --git a/include/linux/devlink.h b/include/linux/devlink.h index c9fee578..a96e1a0e 100644 --- a/include/linux/devlink.h +++ b/include/linux/devlink.h @@ -9,8 +9,8 @@ * (at your option) any later version. */ -#ifndef _UAPI_LINUX_DEVLINK_H_ -#define _UAPI_LINUX_DEVLINK_H_ +#ifndef _LINUX_DEVLINK_H_ +#define _LINUX_DEVLINK_H_ #define DEVLINK_GENL_NAME "devlink" #define DEVLINK_GENL_VERSION 0x1 @@ -69,4 +69,4 @@ enum devlink_attr { DEVLINK_ATTR_MAX = __DEVLINK_ATTR_MAX - 1 }; -#endif /* _UAPI_LINUX_DEVLINK_H_ */ +#endif /* _LINUX_DEVLINK_H_ */ diff --git a/include/linux/if.h b/include/linux/if.h index 86fffb05..5b849482 100644 --- a/include/linux/if.h +++ b/include/linux/if.h @@ -19,14 +19,20 @@ #ifndef _LINUX_IF_H #define _LINUX_IF_H +#include /* for compatibility with glibc */ #include /* for "__kernel_caddr_t" et al */ #include /* for "struct sockaddr" et al */ /* for "__user" et al */ +#if __UAPI_DEF_IF_IFNAMSIZ #define IFNAMSIZ 16 +#endif /* __UAPI_DEF_IF_IFNAMSIZ */ #define IFALIASZ 256 #include +/* For glibc compatibility. An empty enum does not compile. */ +#if __UAPI_DEF_IF_NET_DEVICE_FLAGS_LOWER_UP_DORMANT_ECHO != 0 && \ + __UAPI_DEF_IF_NET_DEVICE_FLAGS != 0 /** * enum net_device_flags - &struct net_device flags * @@ -68,6 +74,8 @@ * @IFF_ECHO: echo sent packets. Volatile. */ enum net_device_flags { +/* for compatibility with glibc net/if.h */ +#if __UAPI_DEF_IF_NET_DEVICE_FLAGS IFF_UP = 1<<0, /* sysfs */ IFF_BROADCAST = 1<<1, /* __volatile__ */ IFF_DEBUG = 1<<2, /* sysfs */ @@ -84,11 +92,17 @@ enum net_device_flags { IFF_PORTSEL = 1<<13, /* sysfs */ IFF_AUTOMEDIA = 1<<14, /* sysfs */ IFF_DYNAMIC = 1<<15, /* sysfs */ +#endif /* __UAPI_DEF_IF_NET_DEVICE_FLAGS */ +#if __UAPI_DEF_IF_NET_DEVICE_FLAGS_LOWER_UP_DORMANT_ECHO IFF_LOWER_UP = 1<<16, /* __volatile__ */ IFF_DORMANT = 1<<17, /* __volatile__ */ IFF_ECHO = 1<<18, /* __volatile__ */ +#endif /* __UAPI_DEF_IF_NET_DEVICE_FLAGS_LOWER_UP_DORMANT_ECHO */ }; +#endif /* __UAPI_DEF_IF_NET_DEVICE_FLAGS_LOWER_UP_DORMANT_ECHO != 0 && __UAPI_DEF_IF_NET_DEVICE_FLAGS != 0 */ +/* for compatibility with glibc net/if.h */ +#if __UAPI_DEF_IF_NET_DEVICE_FLAGS #define IFF_UP IFF_UP #define IFF_BROADCAST IFF_BROADCAST #define IFF_DEBUG IFF_DEBUG @@ -105,9 +119,13 @@ enum net_device_flags { #define IFF_PORTSEL IFF_PORTSEL #define IFF_AUTOMEDIA IFF_AUTOMEDIA #define IFF_DYNAMIC IFF_DYNAMIC +#endif /* __UAPI_DEF_IF_NET_DEVICE_FLAGS */ + +#if __UAPI_DEF_IF_NET_DEVICE_FLAGS_LOWER_UP_DORMANT_ECHO #define IFF_LOWER_UP IFF_LOWER_UP #define IFF_DORMANT IFF_DORMANT #define IFF_ECHO IFF_ECHO +#endif /* __UAPI_DEF_IF_NET_DEVICE_FLAGS_LOWER_UP_DORMANT_ECHO */ #define IFF_VOLATILE (IFF_LOOPBACK|IFF_POINTOPOINT|IFF_BROADCAST|IFF_ECHO|\ IFF_MASTER|IFF_SLAVE|IFF_RUNNING|IFF_LOWER_UP|IFF_DORMANT) @@ -166,6 +184,8 @@ enum { * being very small might be worth keeping for clean configuration. */ +/* for compatibility with glibc net/if.h */ +#if __UAPI_DEF_IF_IFMAP struct ifmap { unsigned long mem_start; unsigned long mem_end; @@ -175,6 +195,7 @@ struct ifmap { unsigned char port; /* 3 bytes spare */ }; +#endif /* __UAPI_DEF_IF_IFMAP */ struct if_settings { unsigned int type; /* Type of physical device or protocol */ @@ -200,6 +221,8 @@ struct if_settings { * remainder may be interface specific. */ +/* for compatibility with glibc net/if.h */ +#if __UAPI_DEF_IF_IFREQ struct ifreq { #define IFHWADDRLEN 6 union @@ -223,6 +246,7 @@ struct ifreq { struct if_settings ifru_settings; } ifr_ifru; }; +#endif /* __UAPI_DEF_IF_IFREQ */ #define ifr_name ifr_ifrn.ifrn_name /* interface name */ #define ifr_hwaddr ifr_ifru.ifru_hwaddr /* MAC address */ @@ -249,6 +273,8 @@ struct ifreq { * must know all networks accessible). */ +/* for compatibility with glibc net/if.h */ +#if __UAPI_DEF_IF_IFCONF struct ifconf { int ifc_len; /* size of buffer */ union { @@ -256,6 +282,8 @@ struct ifconf { struct ifreq *ifcu_req; } ifc_ifcu; }; +#endif /* __UAPI_DEF_IF_IFCONF */ + #define ifc_buf ifc_ifcu.ifcu_buf /* buffer address */ #define ifc_req ifc_ifcu.ifcu_req /* array of structures */ diff --git a/include/linux/libc-compat.h b/include/linux/libc-compat.h index 9bed5b6a..b3c20851 100644 --- a/include/linux/libc-compat.h +++ b/include/linux/libc-compat.h @@ -51,6 +51,40 @@ /* We have included glibc headers... */ #if defined(__GLIBC__) +/* Coordinate with glibc net/if.h header. */ +#if defined(_NET_IF_H) + +/* GLIBC headers included first so don't define anything + * that would already be defined. */ + +#define __UAPI_DEF_IF_IFCONF 0 +#define __UAPI_DEF_IF_IFMAP 0 +#define __UAPI_DEF_IF_IFNAMSIZ 0 +#define __UAPI_DEF_IF_IFREQ 0 +/* Everything up to IFF_DYNAMIC, matches net/if.h until glibc 2.23 */ +#define __UAPI_DEF_IF_NET_DEVICE_FLAGS 0 +/* For the future if glibc adds IFF_LOWER_UP, IFF_DORMANT and IFF_ECHO */ +#ifndef __UAPI_DEF_IF_NET_DEVICE_FLAGS_LOWER_UP_DORMANT_ECHO +#define __UAPI_DEF_IF_NET_DEVICE_FLAGS_LOWER_UP_DORMANT_ECHO 1 +#endif /* __UAPI_DEF_IF_NET_DEVICE_FLAGS_LOWER_UP_DORMANT_ECHO */ + +#else /* _NET_IF_H */ + +/* Linux headers included first, and we must define everything + * we need. The expectation is that glibc will check the + * __UAPI_DEF_* defines and adjust appropriately. */ + +#define __UAPI_DEF_IF_IFCONF 1 +#define __UAPI_DEF_IF_IFMAP 1 +#define __UAPI_DEF_IF_IFNAMSIZ 1 +#define __UAPI_DEF_IF_IFREQ 1 +/* Everything up to IFF_DYNAMIC, matches net/if.h until glibc 2.23 */ +#define __UAPI_DEF_IF_NET_DEVICE_FLAGS 1 +/* For the future if glibc adds IFF_LOWER_UP, IFF_DORMANT and IFF_ECHO */ +#define __UAPI_DEF_IF_NET_DEVICE_FLAGS_LOWER_UP_DORMANT_ECHO 1 + +#endif /* _NET_IF_H */ + /* Coordinate with glibc netinet/in.h header. */ #if defined(_NETINET_IN_H) @@ -117,6 +151,16 @@ * that we need. */ #else /* !defined(__GLIBC__) */ +/* Definitions for if.h */ +#define __UAPI_DEF_IF_IFCONF 1 +#define __UAPI_DEF_IF_IFMAP 1 +#define __UAPI_DEF_IF_IFNAMSIZ 1 +#define __UAPI_DEF_IF_IFREQ 1 +/* Everything up to IFF_DYNAMIC, matches net/if.h until glibc 2.23 */ +#define __UAPI_DEF_IF_NET_DEVICE_FLAGS 1 +/* For the future if glibc adds IFF_LOWER_UP, IFF_DORMANT and IFF_ECHO */ +#define __UAPI_DEF_IF_NET_DEVICE_FLAGS_LOWER_UP_DORMANT_ECHO 1 + /* Definitions for in.h */ #define __UAPI_DEF_IN_ADDR 1 #define __UAPI_DEF_IN_IPPROTO 1 diff --git a/include/linux/netfilter_ipv4/ip_tables.h b/include/linux/netfilter_ipv4/ip_tables.h index 38542b4f..456fb863 100644 --- a/include/linux/netfilter_ipv4/ip_tables.h +++ b/include/linux/netfilter_ipv4/ip_tables.h @@ -17,6 +17,7 @@ #include +#include #include #include From 719c443bb8c4c49da78e7b19d88b30cd2399c6d1 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Fri, 13 May 2016 14:42:06 -0700 Subject: [PATCH 8/8] devlink: remove unused code Unused code causes warnings, removed. --- devlink/devlink.c | 42 ------------------------------------------ 1 file changed, 42 deletions(-) diff --git a/devlink/devlink.c b/devlink/devlink.c index e2e04136..68bdf397 100644 --- a/devlink/devlink.c +++ b/devlink/devlink.c @@ -634,35 +634,6 @@ static int dl_argv_parse_put(struct nlmsghdr *nlh, struct dl *dl, return 0; } -static bool dl_dump_filter(struct dl *dl, struct nlattr **tb) -{ - struct dl_opts *opts = &dl->opts; - struct nlattr *attr_bus_name = tb[DEVLINK_ATTR_BUS_NAME]; - struct nlattr *attr_dev_name = tb[DEVLINK_ATTR_DEV_NAME]; - struct nlattr *attr_port_index = tb[DEVLINK_ATTR_PORT_INDEX]; - - if (opts->present & DL_OPT_HANDLE && - attr_bus_name && attr_dev_name) { - const char *bus_name = mnl_attr_get_str(attr_bus_name); - const char *dev_name = mnl_attr_get_str(attr_dev_name); - - if (strcmp(bus_name, opts->bus_name) != 0 || - strcmp(dev_name, opts->dev_name) != 0) - return false; - } - if (opts->present & DL_OPT_HANDLEP && - attr_bus_name && attr_dev_name && attr_port_index) { - const char *bus_name = mnl_attr_get_str(attr_bus_name); - const char *dev_name = mnl_attr_get_str(attr_dev_name); - uint32_t port_index = mnl_attr_get_u32(attr_port_index); - - if (strcmp(bus_name, opts->bus_name) != 0 || - strcmp(dev_name, opts->dev_name) != 0 || - port_index != opts->port_index) - return false; - } - return true; -} static void cmd_dev_help(void) { @@ -714,19 +685,6 @@ no_nice_names: __pr_out_port_handle(bus_name, dev_name, port_index); } -static void pr_out_port_handle_nice(struct dl *dl, struct nlattr **tb) -{ - const char *bus_name; - const char *dev_name; - uint32_t port_index; - - bus_name = mnl_attr_get_str(tb[DEVLINK_ATTR_BUS_NAME]); - dev_name = mnl_attr_get_str(tb[DEVLINK_ATTR_DEV_NAME]); - port_index = mnl_attr_get_u32(tb[DEVLINK_ATTR_PORT_INDEX]); - - __pr_out_port_handle_nice(dl, bus_name, dev_name, port_index); -} - static void pr_out_dev(struct nlattr **tb) { pr_out_handle(tb);