Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
I
iproute2
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
iproute2
Commits
7fd86a96
Commit
7fd86a96
authored
May 13, 2016
by
Stephen Hemminger
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'master' into net-next
parents
b76b93dd
719c443b
Changes
9
Hide whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
921 additions
and
1170 deletions
+921
-1170
Makefile
Makefile
+3
-0
bash-completion/tc
bash-completion/tc
+723
-0
devlink/devlink.c
devlink/devlink.c
+96
-1088
include/linux/devlink.h
include/linux/devlink.h
+0
-63
include/linux/if.h
include/linux/if.h
+28
-0
include/linux/libc-compat.h
include/linux/libc-compat.h
+44
-0
include/linux/netfilter_ipv4/ip_tables.h
include/linux/netfilter_ipv4/ip_tables.h
+1
-0
ip/iplink_geneve.c
ip/iplink_geneve.c
+1
-1
ip/link_gre.c
ip/link_gre.c
+25
-18
No files found.
Makefile
View file @
7fd86a96
...
...
@@ -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
`
"
\"
;"
\
...
...
bash-completion/tc
0 → 100644
View file @
7fd86a96
# tc(8) completion -*- shell-script -*-
# Copyright 2016 6WIND S.A.
# Copyright 2016 Quentin Monnet <quentin.monnet@6wind.com>
# 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
devlink/devlink.c
View file @
7fd86a96
...
...
@@ -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
)
...
...
@@ -120,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 */
...
...
@@ -135,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
{
...
...
@@ -245,48 +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
;
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
;
}
...
...
@@ -425,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
);
...
...
@@ -579,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
);
...
...
@@ -624,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
)
{
...
...
@@ -700,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
;
...
...
@@ -768,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
;
...
...
@@ -784,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
;
}
...
...
@@ -835,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
,
...
...
@@ -870,42 +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
];
struct
nlattr
*
attr_sb_index
=
tb
[
DEVLINK_ATTR_SB_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
;
}
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
;
}
static
void
cmd_dev_help
(
void
)
{
...
...
@@ -957,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
);
...
...
@@ -1172,830 +887,126 @@ static int cmd_port(struct dl *dl)
return
-
ENOENT
;
}
static
void
cmd_sb_help
(
voi
d
)
static
const
char
*
cmd_name
(
uint8_t
cm
d
)
{
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
"
);
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
"
);
switch
(
cmd
)
{
case
DEVLINK_CMD_UNSPEC
:
return
"unspec"
;
case
DEVLINK_CMD_GET
:
return
"get"
;
case
DEVLINK_CMD_SET
:
return
"set"
;
case
DEVLINK_CMD_NEW
:
return
"new"
;
case
DEVLINK_CMD_DEL
:
return
"del"
;
case
DEVLINK_CMD_PORT_GET
:
return
"get"
;
case
DEVLINK_CMD_PORT_SET
:
return
"set"
;
case
DEVLINK_CMD_PORT_NEW
:
return
"net"
;
case
DEVLINK_CMD_PORT_DEL
:
return
"del"
;
default:
return
"<unknown cmd>"
;
}
}
static
void
pr_out_sb
(
struct
nlattr
**
tb
)
static
const
char
*
cmd_obj
(
uint8_t
cmd
)
{
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
]));
switch
(
cmd
)
{
case
DEVLINK_CMD_UNSPEC
:
return
"unspec"
;
case
DEVLINK_CMD_GET
:
case
DEVLINK_CMD_SET
:
case
DEVLINK_CMD_NEW
:
case
DEVLINK_CMD_DEL
:
return
"dev"
;
case
DEVLINK_CMD_PORT_GET
:
case
DEVLINK_CMD_PORT_SET
:
case
DEVLINK_CMD_PORT_NEW
:
case
DEVLINK_CMD_PORT_DEL
:
return
"port"
;
default:
return
"<unknown obj>"
;
}
}
static
int
cmd_sb_show_cb
(
const
struct
nlmsghdr
*
nlh
,
void
*
data
)
static
void
pr_out_mon_header
(
uint8_t
cmd
)
{
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
;
pr_out
(
"[%s,%s] "
,
cmd_obj
(
cmd
),
cmd_name
(
cmd
));
}
static
int
cmd_sb_show
(
struct
dl
*
dl
)
static
bool
cmd_filter_check
(
struct
dl
*
dl
,
uint8_t
cmd
)
{
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
);
const
char
*
obj
=
cmd_obj
(
cmd
);
unsigned
int
index
=
0
;
const
char
*
cur_obj
;
if
(
dl_argc
(
dl
)
>
0
)
{
err
=
dl_argv_parse_put
(
nlh
,
dl
,
DL_OPT_HANDLE
,
DL_OPT_SB
);
if
(
err
)
return
err
;
if
(
dl_no_arg
(
dl
))
return
true
;
while
((
cur_obj
=
dl_argv_index
(
dl
,
index
++
)))
{
if
(
strcmp
(
cur_obj
,
obj
)
==
0
||
strcmp
(
cur_obj
,
"all"
)
==
0
)
return
true
;
}
return
_mnlg_socket_sndrcv
(
dl
->
nlg
,
nlh
,
cmd_sb_show_cb
,
NULL
);
return
false
;
}
static
const
char
*
pool_type_name
(
uint8_t
type
)
static
int
cmd_mon_show_cb
(
const
struct
nlmsghdr
*
nlh
,
void
*
data
)
{
switch
(
type
)
{
case
DEVLINK_SB_POOL_TYPE_INGRESS
:
return
"ingress"
;
case
DEVLINK_SB_POOL_TYPE_EGRESS
:
return
"egress"
;
default:
return
"<unknown type>"
;
struct
dl
*
dl
=
data
;
struct
nlattr
*
tb
[
DEVLINK_ATTR_MAX
+
1
]
=
{};
struct
genlmsghdr
*
genl
=
mnl_nlmsg_get_payload
(
nlh
);
uint8_t
cmd
=
genl
->
cmd
;
if
(
!
cmd_filter_check
(
dl
,
cmd
))
return
MNL_CB_OK
;
switch
(
cmd
)
{
case
DEVLINK_CMD_GET
:
/* fall through */
case
DEVLINK_CMD_SET
:
/* fall through */
case
DEVLINK_CMD_NEW
:
/* fall through */
case
DEVLINK_CMD_DEL
:
mnl_attr_parse
(
nlh
,
sizeof
(
*
genl
),
attr_cb
,
tb
);
if
(
!
tb
[
DEVLINK_ATTR_BUS_NAME
]
||
!
tb
[
DEVLINK_ATTR_DEV_NAME
])
return
MNL_CB_ERROR
;
pr_out_mon_header
(
genl
->
cmd
);
pr_out_dev
(
tb
);
break
;
case
DEVLINK_CMD_PORT_GET
:
/* fall through */
case
DEVLINK_CMD_PORT_SET
:
/* fall through */
case
DEVLINK_CMD_PORT_NEW
:
/* fall through */
case
DEVLINK_CMD_PORT_DEL
:
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
])
return
MNL_CB_ERROR
;
pr_out_mon_header
(
genl
->
cmd
);
pr_out_port
(
tb
);
break
;
}
return
MNL_CB_OK
;
}
static
const
char
*
threshold_type_name
(
uint8_t
type
)
static
int
cmd_mon_show
(
struct
dl
*
dl
)
{
switch
(
type
)
{
case
DEVLINK_SB_THRESHOLD_TYPE_STATIC
:
return
"static"
;
case
DEVLINK_SB_THRESHOLD_TYPE_DYNAMIC
:
return
"dynamic"
;
default:
return
"<unknown type>"
;
int
err
;
unsigned
int
index
=
0
;
const
char
*
cur_obj
;
while
((
cur_obj
=
dl_argv_index
(
dl
,
index
++
)))
{
if
(
strcmp
(
cur_obj
,
"all"
)
!=
0
&&
strcmp
(
cur_obj
,
"dev"
)
!=
0
&&
strcmp
(
cur_obj
,
"port"
)
!=
0
)
{
pr_err
(
"Unknown object
\"
%s
\"\n
"
,
cur_obj
);
return
-
EINVAL
;
}
}
err
=
_mnlg_socket_group_add
(
dl
->
nlg
,
DEVLINK_GENL_MCGRP_CONFIG_NAME
);
if
(
err
)
return
err
;
err
=
_mnlg_socket_recv_run
(
dl
->
nlg
,
cmd_mon_show_cb
,
dl
);
if
(
err
)
return
err
;
return
0
;
}
static
void
pr_out_sb_pool
(
struct
nlattr
**
tb
)
static
void
cmd_mon_help
(
void
)
{
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
])));
pr_out
(
"Usage: devlink monitor [ all | OBJECT-LIST ]
\n
"
"where OBJECT-LIST := { dev | port }
\n
"
);
}
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
;
}
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"
))
{
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
);
}
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
;
}
static
const
char
*
cmd_name
(
uint8_t
cmd
)
{
switch
(
cmd
)
{
case
DEVLINK_CMD_UNSPEC
:
return
"unspec"
;
case
DEVLINK_CMD_GET
:
return
"get"
;
case
DEVLINK_CMD_SET
:
return
"set"
;
case
DEVLINK_CMD_NEW
:
return
"new"
;
case
DEVLINK_CMD_DEL
:
return
"del"
;
case
DEVLINK_CMD_PORT_GET
:
return
"get"
;
case
DEVLINK_CMD_PORT_SET
:
return
"set"
;
case
DEVLINK_CMD_PORT_NEW
:
return
"net"
;
case
DEVLINK_CMD_PORT_DEL
:
return
"del"
;
default:
return
"<unknown cmd>"
;
}
}
static
const
char
*
cmd_obj
(
uint8_t
cmd
)
{
switch
(
cmd
)
{
case
DEVLINK_CMD_UNSPEC
:
return
"unspec"
;
case
DEVLINK_CMD_GET
:
case
DEVLINK_CMD_SET
:
case
DEVLINK_CMD_NEW
:
case
DEVLINK_CMD_DEL
:
return
"dev"
;
case
DEVLINK_CMD_PORT_GET
:
case
DEVLINK_CMD_PORT_SET
:
case
DEVLINK_CMD_PORT_NEW
:
case
DEVLINK_CMD_PORT_DEL
:
return
"port"
;
default:
return
"<unknown obj>"
;
}
}
static
void
pr_out_mon_header
(
uint8_t
cmd
)
{
pr_out
(
"[%s,%s] "
,
cmd_obj
(
cmd
),
cmd_name
(
cmd
));
}
static
bool
cmd_filter_check
(
struct
dl
*
dl
,
uint8_t
cmd
)
{
const
char
*
obj
=
cmd_obj
(
cmd
);
unsigned
int
index
=
0
;
const
char
*
cur_obj
;
if
(
dl_no_arg
(
dl
))
return
true
;
while
((
cur_obj
=
dl_argv_index
(
dl
,
index
++
)))
{
if
(
strcmp
(
cur_obj
,
obj
)
==
0
||
strcmp
(
cur_obj
,
"all"
)
==
0
)
return
true
;
}
return
false
;
}
static
int
cmd_mon_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
);
uint8_t
cmd
=
genl
->
cmd
;
if
(
!
cmd_filter_check
(
dl
,
cmd
))
return
MNL_CB_OK
;
switch
(
cmd
)
{
case
DEVLINK_CMD_GET
:
/* fall through */
case
DEVLINK_CMD_SET
:
/* fall through */
case
DEVLINK_CMD_NEW
:
/* fall through */
case
DEVLINK_CMD_DEL
:
mnl_attr_parse
(
nlh
,
sizeof
(
*
genl
),
attr_cb
,
tb
);
if
(
!
tb
[
DEVLINK_ATTR_BUS_NAME
]
||
!
tb
[
DEVLINK_ATTR_DEV_NAME
])
return
MNL_CB_ERROR
;
pr_out_mon_header
(
genl
->
cmd
);
pr_out_dev
(
tb
);
break
;
case
DEVLINK_CMD_PORT_GET
:
/* fall through */
case
DEVLINK_CMD_PORT_SET
:
/* fall through */
case
DEVLINK_CMD_PORT_NEW
:
/* fall through */
case
DEVLINK_CMD_PORT_DEL
:
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
])
return
MNL_CB_ERROR
;
pr_out_mon_header
(
genl
->
cmd
);
pr_out_port
(
tb
);
break
;
}
return
MNL_CB_OK
;
}
static
int
cmd_mon_show
(
struct
dl
*
dl
)
{
int
err
;
unsigned
int
index
=
0
;
const
char
*
cur_obj
;
while
((
cur_obj
=
dl_argv_index
(
dl
,
index
++
)))
{
if
(
strcmp
(
cur_obj
,
"all"
)
!=
0
&&
strcmp
(
cur_obj
,
"dev"
)
!=
0
&&
strcmp
(
cur_obj
,
"port"
)
!=
0
)
{
pr_err
(
"Unknown object
\"
%s
\"\n
"
,
cur_obj
);
return
-
EINVAL
;
}
}
err
=
_mnlg_socket_group_add
(
dl
->
nlg
,
DEVLINK_GENL_MCGRP_CONFIG_NAME
);
if
(
err
)
return
err
;
err
=
_mnlg_socket_recv_run
(
dl
->
nlg
,
cmd_mon_show_cb
,
dl
);
if
(
err
)
return
err
;
return
0
;
}
static
void
cmd_mon_help
(
void
)
{
pr_out
(
"Usage: devlink monitor [ all | OBJECT-LIST ]
\n
"
"where OBJECT-LIST := { dev | port }
\n
"
);
}
static
int
cmd_mon
(
struct
dl
*
dl
)
static
int
cmd_mon
(
struct
dl
*
dl
)
{
if
(
dl_argv_match
(
dl
,
"help"
))
{
cmd_mon_help
();
...
...
@@ -2011,7 +1022,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
"
);
}
...
...
@@ -2026,9 +1037,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
);
...
...
include/linux/devlink.h
View file @
7fd86a96
...
...
@@ -33,30 +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
,
/* Shared buffer occupancy monitoring commands */
DEVLINK_CMD_SB_OCC_SNAPSHOT
,
DEVLINK_CMD_SB_OCC_MAX_CLEAR
,
/* add new commands above here */
__DEVLINK_CMD_MAX
,
...
...
@@ -70,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
,
...
...
@@ -111,20 +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 */
DEVLINK_ATTR_SB_OCC_CUR
,
/* u32 */
DEVLINK_ATTR_SB_OCC_MAX
,
/* u32 */
/* add new attributes above here, update the policy in devlink.c */
...
...
include/linux/if.h
View file @
7fd86a96
...
...
@@ -19,14 +19,20 @@
#ifndef _LINUX_IF_H
#define _LINUX_IF_H
#include <linux/libc-compat.h>
/* for compatibility with glibc */
#include <linux/types.h>
/* for "__kernel_caddr_t" et al */
#include <linux/socket.h>
/* 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 <linux/hdlc/ioctl.h>
/* 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 */
...
...
include/linux/libc-compat.h
View file @
7fd86a96
...
...
@@ -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
...
...
include/linux/netfilter_ipv4/ip_tables.h
View file @
7fd86a96
...
...
@@ -17,6 +17,7 @@
#include <linux/types.h>
#include <linux/if.h>
#include <linux/netfilter_ipv4.h>
#include <linux/netfilter/x_tables.h>
...
...
ip/iplink_geneve.c
View file @
7fd86a96
...
...
@@ -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
));
}
...
...
ip/link_gre.c
View file @
7fd86a96
...
...
@@ -315,29 +315,31 @@ 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
;
}
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"
;
...
...
@@ -345,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
]);
...
...
@@ -419,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
]
&&
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment