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
f1f1aeb2
Commit
f1f1aeb2
authored
Oct 30, 2013
by
Stephen Hemminger
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'master' into net-next-3.11
Conflicts: tc/q_fq.c
parents
6d64ec02
9bea14ff
Changes
29
Hide whitespace changes
Inline
Side-by-side
Showing
29 changed files
with
1368 additions
and
178 deletions
+1368
-178
bridge/monitor.c
bridge/monitor.c
+4
-1
include/linux/tc_act/tc_defact.h
include/linux/tc_act/tc_defact.h
+19
-0
include/utils.h
include/utils.h
+1
-0
ip/Makefile
ip/Makefile
+1
-2
ip/ip6tunnel.c
ip/ip6tunnel.c
+114
-17
ip/iplink.c
ip/iplink.c
+4
-5
ip/iplink_vxlan.c
ip/iplink_vxlan.c
+49
-10
ip/link_gre6.c
ip/link_gre6.c
+398
-0
ip/xfrm_policy.c
ip/xfrm_policy.c
+1
-1
ip/xfrm_state.c
ip/xfrm_state.c
+2
-2
lib/ll_types.c
lib/ll_types.c
+1
-0
lib/utils.c
lib/utils.c
+8
-0
man/man8/bridge.8
man/man8/bridge.8
+85
-3
man/man8/ip-link.8.in
man/man8/ip-link.8.in
+123
-1
man/man8/ip-tunnel.8
man/man8/ip-tunnel.8
+2
-2
man/man8/lnstat.8
man/man8/lnstat.8
+3
-0
man/man8/rtacct.8
man/man8/rtacct.8
+12
-10
misc/ifstat.c
misc/ifstat.c
+112
-19
misc/lnstat.c
misc/lnstat.c
+104
-67
misc/nstat.c
misc/nstat.c
+68
-9
tc/Makefile
tc/Makefile
+1
-0
tc/m_nat.c
tc/m_nat.c
+1
-1
tc/m_simple.c
tc/m_simple.c
+202
-0
tc/q_fq.c
tc/q_fq.c
+1
-1
tc/q_htb.c
tc/q_htb.c
+19
-12
tc/tc_class.c
tc/tc_class.c
+3
-0
tc/tc_qdisc.c
tc/tc_qdisc.c
+8
-7
tc/tc_util.c
tc/tc_util.c
+20
-6
tc/tc_util.h
tc/tc_util.h
+2
-2
No files found.
bridge/monitor.c
View file @
f1f1aeb2
...
...
@@ -132,12 +132,15 @@ int do_monitor(int argc, char **argv)
if
(
file
)
{
FILE
*
fp
;
int
err
;
fp
=
fopen
(
file
,
"r"
);
if
(
fp
==
NULL
)
{
perror
(
"Cannot fopen"
);
exit
(
-
1
);
}
return
rtnl_from_file
(
fp
,
accept_msg
,
stdout
);
err
=
rtnl_from_file
(
fp
,
accept_msg
,
stdout
);
fclose
(
fp
);
return
err
;
}
if
(
rtnl_open
(
&
rth
,
groups
)
<
0
)
...
...
include/linux/tc_act/tc_defact.h
0 → 100644
View file @
f1f1aeb2
#ifndef __LINUX_TC_DEF_H
#define __LINUX_TC_DEF_H
#include <linux/pkt_cls.h>
struct
tc_defact
{
tc_gen
;
};
enum
{
TCA_DEF_UNSPEC
,
TCA_DEF_TM
,
TCA_DEF_PARMS
,
TCA_DEF_DATA
,
__TCA_DEF_MAX
};
#define TCA_DEF_MAX (__TCA_DEF_MAX - 1)
#endif
include/utils.h
View file @
f1f1aeb2
...
...
@@ -151,6 +151,7 @@ int print_timestamp(FILE *fp);
extern
int
cmdlineno
;
extern
ssize_t
getcmdline
(
char
**
line
,
size_t
*
len
,
FILE
*
in
);
extern
int
makeargs
(
char
*
line
,
char
*
argv
[],
int
maxargs
);
extern
int
inet_get_addr
(
const
char
*
src
,
__u32
*
dst
,
struct
in6_addr
*
dst6
);
struct
iplink_req
;
int
iplink_parse
(
int
argc
,
char
**
argv
,
struct
iplink_req
*
req
,
...
...
ip/Makefile
View file @
f1f1aeb2
...
...
@@ -5,7 +5,7 @@ IPOBJ=ip.o ipaddress.o ipaddrlabel.o iproute.o iprule.o ipnetns.o \
iplink_vlan.o link_veth.o link_gre.o iplink_can.o
\
iplink_macvlan.o iplink_macvtap.o ipl2tp.o link_vti.o
\
iplink_vxlan.o tcp_metrics.o iplink_ipoib.o ipnetconf.o link_ip6tnl.o
\
link_iptnl.o
link_iptnl.o
link_gre6.o
RTMONOBJ
=
rtmon.o
...
...
@@ -23,7 +23,6 @@ all: $(TARGETS) $(SCRIPTS)
ip
:
$(IPOBJ) $(LIBNETLINK)
rtmon
:
$(RTMONOBJ)
install
:
all
...
...
ip/ip6tunnel.c
View file @
f1f1aeb2
...
...
@@ -48,11 +48,12 @@ static void usage(void) __attribute__((noreturn));
static
void
usage
(
void
)
{
fprintf
(
stderr
,
"Usage: ip -f inet6 tunnel { add | change | del | show } [ NAME ]
\n
"
);
fprintf
(
stderr
,
" [ mode { ip6ip6 | ipip6 | any } ]
\n
"
);
fprintf
(
stderr
,
" [ mode { ip6ip6 | ipip6 |
ip6gre |
any } ]
\n
"
);
fprintf
(
stderr
,
" [ remote ADDR local ADDR ] [ dev PHYS_DEV ]
\n
"
);
fprintf
(
stderr
,
" [ encaplimit ELIM ]
\n
"
);
fprintf
(
stderr
,
" [ hoplimit TTL ] [ tclass TCLASS ] [ flowlabel FLOWLABEL ]
\n
"
);
fprintf
(
stderr
,
" [ dscp inherit ]
\n
"
);
fprintf
(
stderr
,
" [ [i|o]seq ] [ [i|o]key KEY ] [ [i|o]csum ]
\n
"
);
fprintf
(
stderr
,
"
\n
"
);
fprintf
(
stderr
,
"Where: NAME := STRING
\n
"
);
fprintf
(
stderr
,
" ADDR := IPV6_ADDRESS
\n
"
);
...
...
@@ -62,10 +63,11 @@ static void usage(void)
DEFAULT_TNL_HOP_LIMIT
);
fprintf
(
stderr
,
" TCLASS := { 0x0..0xff | inherit }
\n
"
);
fprintf
(
stderr
,
" FLOWLABEL := { 0x0..0xfffff | inherit }
\n
"
);
fprintf
(
stderr
,
" KEY := { DOTTED_QUAD | NUMBER }
\n
"
);
exit
(
-
1
);
}
static
void
print_tunnel
(
struct
ip6_tnl_parm
*
p
)
static
void
print_tunnel
(
struct
ip6_tnl_parm
2
*
p
)
{
char
remote
[
64
];
char
local
[
64
];
...
...
@@ -104,9 +106,29 @@ static void print_tunnel(struct ip6_tnl_parm *p)
if
(
p
->
flags
&
IP6_TNL_F_RCV_DSCP_COPY
)
printf
(
" dscp inherit"
);
if
(
p
->
proto
==
IPPROTO_GRE
)
{
if
((
p
->
i_flags
&
GRE_KEY
)
&&
(
p
->
o_flags
&
GRE_KEY
)
&&
p
->
o_key
==
p
->
i_key
)
printf
(
" key %u"
,
ntohl
(
p
->
i_key
));
else
if
((
p
->
i_flags
|
p
->
o_flags
)
&
GRE_KEY
)
{
if
(
p
->
i_flags
&
GRE_KEY
)
printf
(
" ikey %u "
,
ntohl
(
p
->
i_key
));
if
(
p
->
o_flags
&
GRE_KEY
)
printf
(
" okey %u "
,
ntohl
(
p
->
o_key
));
}
if
(
p
->
i_flags
&
GRE_SEQ
)
printf
(
"%s Drop packets out of sequence.
\n
"
,
_SL_
);
if
(
p
->
i_flags
&
GRE_CSUM
)
printf
(
"%s Checksum in received packet is required."
,
_SL_
);
if
(
p
->
o_flags
&
GRE_SEQ
)
printf
(
"%s Sequence packets on output."
,
_SL_
);
if
(
p
->
o_flags
&
GRE_CSUM
)
printf
(
"%s Checksum output packets."
,
_SL_
);
}
}
static
int
parse_args
(
int
argc
,
char
**
argv
,
int
cmd
,
struct
ip6_tnl_parm
*
p
)
static
int
parse_args
(
int
argc
,
char
**
argv
,
int
cmd
,
struct
ip6_tnl_parm
2
*
p
)
{
int
count
=
0
;
char
medium
[
IFNAMSIZ
];
...
...
@@ -124,6 +146,9 @@ static int parse_args(int argc, char **argv, int cmd, struct ip6_tnl_parm *p)
strcmp
(
*
argv
,
"ipip6"
)
==
0
||
strcmp
(
*
argv
,
"ip4ip6"
)
==
0
)
p
->
proto
=
IPPROTO_IPIP
;
else
if
(
strcmp
(
*
argv
,
"ip6gre"
)
==
0
||
strcmp
(
*
argv
,
"gre/ipv6"
)
==
0
)
p
->
proto
=
IPPROTO_GRE
;
else
if
(
strcmp
(
*
argv
,
"any/ipv6"
)
==
0
||
strcmp
(
*
argv
,
"any"
)
==
0
)
p
->
proto
=
0
;
...
...
@@ -202,6 +227,60 @@ static int parse_args(int argc, char **argv, int cmd, struct ip6_tnl_parm *p)
if
(
strcmp
(
*
argv
,
"inherit"
)
!=
0
)
invarg
(
"not inherit"
,
*
argv
);
p
->
flags
|=
IP6_TNL_F_RCV_DSCP_COPY
;
}
else
if
(
strcmp
(
*
argv
,
"key"
)
==
0
)
{
unsigned
uval
;
NEXT_ARG
();
p
->
i_flags
|=
GRE_KEY
;
p
->
o_flags
|=
GRE_KEY
;
if
(
strchr
(
*
argv
,
'.'
))
p
->
i_key
=
p
->
o_key
=
get_addr32
(
*
argv
);
else
{
if
(
get_unsigned
(
&
uval
,
*
argv
,
0
)
<
0
)
{
fprintf
(
stderr
,
"invalid value of
\"
key
\"\n
"
);
exit
(
-
1
);
}
p
->
i_key
=
p
->
o_key
=
htonl
(
uval
);
}
}
else
if
(
strcmp
(
*
argv
,
"ikey"
)
==
0
)
{
unsigned
uval
;
NEXT_ARG
();
p
->
i_flags
|=
GRE_KEY
;
if
(
strchr
(
*
argv
,
'.'
))
p
->
i_key
=
get_addr32
(
*
argv
);
else
{
if
(
get_unsigned
(
&
uval
,
*
argv
,
0
)
<
0
)
{
fprintf
(
stderr
,
"invalid value of
\"
ikey
\"\n
"
);
exit
(
-
1
);
}
p
->
i_key
=
htonl
(
uval
);
}
}
else
if
(
strcmp
(
*
argv
,
"okey"
)
==
0
)
{
unsigned
uval
;
NEXT_ARG
();
p
->
o_flags
|=
GRE_KEY
;
if
(
strchr
(
*
argv
,
'.'
))
p
->
o_key
=
get_addr32
(
*
argv
);
else
{
if
(
get_unsigned
(
&
uval
,
*
argv
,
0
)
<
0
)
{
fprintf
(
stderr
,
"invalid value of
\"
okey
\"\n
"
);
exit
(
-
1
);
}
p
->
o_key
=
htonl
(
uval
);
}
}
else
if
(
strcmp
(
*
argv
,
"seq"
)
==
0
)
{
p
->
i_flags
|=
GRE_SEQ
;
p
->
o_flags
|=
GRE_SEQ
;
}
else
if
(
strcmp
(
*
argv
,
"iseq"
)
==
0
)
{
p
->
i_flags
|=
GRE_SEQ
;
}
else
if
(
strcmp
(
*
argv
,
"oseq"
)
==
0
)
{
p
->
o_flags
|=
GRE_SEQ
;
}
else
if
(
strcmp
(
*
argv
,
"csum"
)
==
0
)
{
p
->
i_flags
|=
GRE_CSUM
;
p
->
o_flags
|=
GRE_CSUM
;
}
else
if
(
strcmp
(
*
argv
,
"icsum"
)
==
0
)
{
p
->
i_flags
|=
GRE_CSUM
;
}
else
if
(
strcmp
(
*
argv
,
"ocsum"
)
==
0
)
{
p
->
o_flags
|=
GRE_CSUM
;
}
else
{
if
(
strcmp
(
*
argv
,
"name"
)
==
0
)
{
NEXT_ARG
();
...
...
@@ -212,7 +291,7 @@ static int parse_args(int argc, char **argv, int cmd, struct ip6_tnl_parm *p)
duparg2
(
"name"
,
*
argv
);
strncpy
(
p
->
name
,
*
argv
,
IFNAMSIZ
-
1
);
if
(
cmd
==
SIOCCHGTUNNEL
&&
count
==
0
)
{
struct
ip6_tnl_parm
old_p
;
struct
ip6_tnl_parm
2
old_p
;
memset
(
&
old_p
,
0
,
sizeof
(
old_p
));
if
(
tnl_get_ioctl
(
*
argv
,
&
old_p
))
return
-
1
;
...
...
@@ -230,7 +309,7 @@ static int parse_args(int argc, char **argv, int cmd, struct ip6_tnl_parm *p)
return
0
;
}
static
void
ip6_tnl_parm_init
(
struct
ip6_tnl_parm
*
p
,
int
apply_default
)
static
void
ip6_tnl_parm_init
(
struct
ip6_tnl_parm
2
*
p
,
int
apply_default
)
{
memset
(
p
,
0
,
sizeof
(
*
p
));
p
->
proto
=
IPPROTO_IPV6
;
...
...
@@ -244,8 +323,8 @@ static void ip6_tnl_parm_init(struct ip6_tnl_parm *p, int apply_default)
* @p1: user specified parameter
* @p2: database entry
*/
static
int
ip6_tnl_parm_match
(
const
struct
ip6_tnl_parm
*
p1
,
const
struct
ip6_tnl_parm
*
p2
)
static
int
ip6_tnl_parm_match
(
const
struct
ip6_tnl_parm
2
*
p1
,
const
struct
ip6_tnl_parm
2
*
p2
)
{
return
((
!
p1
->
link
||
p1
->
link
==
p2
->
link
)
&&
(
!
p1
->
name
[
0
]
||
strcmp
(
p1
->
name
,
p2
->
name
)
==
0
)
&&
...
...
@@ -263,7 +342,7 @@ static int ip6_tnl_parm_match(const struct ip6_tnl_parm *p1,
(
!
p1
->
flags
||
(
p1
->
flags
&
p2
->
flags
)));
}
static
int
do_tunnels_list
(
struct
ip6_tnl_parm
*
p
)
static
int
do_tunnels_list
(
struct
ip6_tnl_parm
2
*
p
)
{
char
buf
[
512
];
int
err
=
-
1
;
...
...
@@ -287,7 +366,7 @@ static int do_tunnels_list(struct ip6_tnl_parm *p)
rx_fifo
,
rx_frame
,
tx_bytes
,
tx_packets
,
tx_errs
,
tx_drops
,
tx_fifo
,
tx_colls
,
tx_carrier
,
rx_multi
;
struct
ip6_tnl_parm
p1
;
struct
ip6_tnl_parm
2
p1
;
char
*
ptr
;
buf
[
sizeof
(
buf
)
-
1
]
=
'\0'
;
...
...
@@ -312,10 +391,12 @@ static int do_tunnels_list(struct ip6_tnl_parm *p)
fprintf
(
stderr
,
"Failed to get type of
\"
%s
\"\n
"
,
name
);
continue
;
}
if
(
type
!=
ARPHRD_TUNNEL6
)
if
(
type
!=
ARPHRD_TUNNEL6
&&
type
!=
ARPHRD_IP6GRE
)
continue
;
memset
(
&
p1
,
0
,
sizeof
(
p1
));
ip6_tnl_parm_init
(
&
p1
,
0
);
if
(
type
==
ARPHRD_IP6GRE
)
p1
.
proto
=
IPPROTO_GRE
;
strcpy
(
p1
.
name
,
name
);
p1
.
link
=
ll_name_to_index
(
p1
.
name
);
if
(
p1
.
link
==
0
)
...
...
@@ -346,7 +427,7 @@ static int do_tunnels_list(struct ip6_tnl_parm *p)
static
int
do_show
(
int
argc
,
char
**
argv
)
{
struct
ip6_tnl_parm
p
;
struct
ip6_tnl_parm
2
p
;
ll_init_map
(
&
rth
);
ip6_tnl_parm_init
(
&
p
,
0
);
...
...
@@ -369,28 +450,44 @@ static int do_show(int argc, char **argv)
static
int
do_add
(
int
cmd
,
int
argc
,
char
**
argv
)
{
struct
ip6_tnl_parm
p
;
struct
ip6_tnl_parm
2
p
;
ip6_tnl_parm_init
(
&
p
,
1
);
if
(
parse_args
(
argc
,
argv
,
cmd
,
&
p
)
<
0
)
return
-
1
;
return
tnl_add_ioctl
(
cmd
,
cmd
==
SIOCCHGTUNNEL
&&
p
.
name
[
0
]
?
p
.
name
:
"ip6tnl0"
,
p
.
name
,
&
p
);
switch
(
p
.
proto
)
{
case
IPPROTO_IPIP
:
case
IPPROTO_IPV6
:
return
tnl_add_ioctl
(
cmd
,
"ip6tnl0"
,
p
.
name
,
&
p
);
case
IPPROTO_GRE
:
return
tnl_add_ioctl
(
cmd
,
"ip6gre0"
,
p
.
name
,
&
p
);
default:
fprintf
(
stderr
,
"cannot determine tunnel mode (ip6ip6, ipip6 or gre)
\n
"
);
}
return
-
1
;
}
static
int
do_del
(
int
argc
,
char
**
argv
)
{
struct
ip6_tnl_parm
p
;
struct
ip6_tnl_parm
2
p
;
ip6_tnl_parm_init
(
&
p
,
1
);
if
(
parse_args
(
argc
,
argv
,
SIOCDELTUNNEL
,
&
p
)
<
0
)
return
-
1
;
return
tnl_del_ioctl
(
p
.
name
[
0
]
?
p
.
name
:
"ip6tnl0"
,
p
.
name
,
&
p
);
switch
(
p
.
proto
)
{
case
IPPROTO_IPIP
:
case
IPPROTO_IPV6
:
return
tnl_del_ioctl
(
"ip6tnl0"
,
p
.
name
,
&
p
);
case
IPPROTO_GRE
:
return
tnl_del_ioctl
(
"ip6gre0"
,
p
.
name
,
&
p
);
default:
return
tnl_del_ioctl
(
p
.
name
,
p
.
name
,
&
p
);
}
return
-
1
;
}
int
do_ip6tunnel
(
int
argc
,
char
**
argv
)
...
...
ip/iplink.c
View file @
f1f1aeb2
...
...
@@ -84,8 +84,9 @@ void iplink_usage(void)
if
(
iplink_have_newlink
())
{
fprintf
(
stderr
,
"
\n
"
);
fprintf
(
stderr
,
"TYPE := { vlan | veth | vcan | dummy | ifb | macvlan | can |
\n
"
);
fprintf
(
stderr
,
" bridge | ipoib | ip6tnl | ipip | sit | vxlan }
\n
"
);
fprintf
(
stderr
,
"TYPE := { vlan | veth | vcan | dummy | ifb | macvlan | macvtap |
\n
"
);
fprintf
(
stderr
,
" can | bridge | ipoib | ip6tnl | ipip | sit | vxlan |
\n
"
);
fprintf
(
stderr
,
" gre | gretap | ip6gre | ip6gretap | vti }
\n
"
);
}
exit
(
-
1
);
}
...
...
@@ -243,7 +244,7 @@ static int iplink_parse_vf(int vf, int *argcp, char ***argvp,
}
ivt
.
vf
=
vf
;
addattr_l
(
&
req
->
n
,
sizeof
(
*
req
),
IFLA_VF_TX_RATE
,
&
ivt
,
sizeof
(
ivt
));
}
else
if
(
matches
(
*
argv
,
"spoofchk"
)
==
0
)
{
struct
ifla_vf_spoofchk
ivs
;
NEXT_ARG
();
...
...
@@ -286,7 +287,6 @@ static int iplink_parse_vf(int vf, int *argcp, char ***argvp,
return
0
;
}
int
iplink_parse
(
int
argc
,
char
**
argv
,
struct
iplink_req
*
req
,
char
**
name
,
char
**
type
,
char
**
link
,
char
**
dev
,
int
*
group
)
{
...
...
@@ -811,7 +811,6 @@ static int set_address(struct ifreq *ifr, int brd)
return
0
;
}
static
int
do_set
(
int
argc
,
char
**
argv
)
{
char
*
dev
=
NULL
;
...
...
ip/iplink_vxlan.c
View file @
f1f1aeb2
...
...
@@ -43,6 +43,9 @@ static int vxlan_parse_opt(struct link_util *lu, int argc, char **argv,
__u32
saddr
=
0
;
__u32
gaddr
=
0
;
__u32
daddr
=
0
;
struct
in6_addr
saddr6
=
IN6ADDR_ANY_INIT
;
struct
in6_addr
gaddr6
=
IN6ADDR_ANY_INIT
;
struct
in6_addr
daddr6
=
IN6ADDR_ANY_INIT
;
unsigned
link
=
0
;
__u8
tos
=
0
;
__u8
ttl
=
0
;
...
...
@@ -66,21 +69,30 @@ static int vxlan_parse_opt(struct link_util *lu, int argc, char **argv,
vni_set
=
1
;
}
else
if
(
!
matches
(
*
argv
,
"group"
))
{
NEXT_ARG
();
gaddr
=
get_addr32
(
*
argv
);
if
(
!
IN_MULTICAST
(
ntohl
(
gaddr
)))
if
(
!
inet_get_addr
(
*
argv
,
&
gaddr
,
&
gaddr6
))
{
fprintf
(
stderr
,
"Invalid address
\"
%s
\"\n
"
,
*
argv
);
return
-
1
;
}
if
(
!
IN6_IS_ADDR_MULTICAST
(
&
gaddr6
)
&&
!
IN_MULTICAST
(
ntohl
(
gaddr
)))
invarg
(
"invalid group address"
,
*
argv
);
}
else
if
(
!
matches
(
*
argv
,
"remote"
))
{
NEXT_ARG
();
daddr
=
get_addr32
(
*
argv
);
if
(
IN_MULTICAST
(
ntohl
(
daddr
)))
if
(
!
inet_get_addr
(
*
argv
,
&
daddr
,
&
daddr6
))
{
fprintf
(
stderr
,
"Invalid address
\"
%s
\"\n
"
,
*
argv
);
return
-
1
;
}
if
(
IN6_IS_ADDR_MULTICAST
(
&
daddr6
)
||
IN_MULTICAST
(
ntohl
(
daddr
)))
invarg
(
"invalid remote address"
,
*
argv
);
}
else
if
(
!
matches
(
*
argv
,
"local"
))
{
NEXT_ARG
();
if
(
strcmp
(
*
argv
,
"any"
))
saddr
=
get_addr32
(
*
argv
);
if
(
IN_MULTICAST
(
ntohl
(
saddr
)))
if
(
strcmp
(
*
argv
,
"any"
))
{
if
(
!
inet_get_addr
(
*
argv
,
&
saddr
,
&
saddr6
))
{
fprintf
(
stderr
,
"Invalid address
\"
%s
\"\n
"
,
*
argv
);
return
-
1
;
}
}
if
(
IN_MULTICAST
(
ntohl
(
saddr
))
||
IN6_IS_ADDR_MULTICAST
(
&
saddr6
))
invarg
(
"invalid local address"
,
*
argv
);
}
else
if
(
!
matches
(
*
argv
,
"dev"
))
{
NEXT_ARG
();
...
...
@@ -167,7 +179,9 @@ static int vxlan_parse_opt(struct link_util *lu, int argc, char **argv,
fprintf
(
stderr
,
"vxlan: missing virtual network identifier
\n
"
);
return
-
1
;
}
if
(
gaddr
&&
daddr
)
{
if
((
gaddr
&&
daddr
)
||
(
memcmp
(
&
gaddr6
,
&
in6addr_any
,
sizeof
(
gaddr6
))
&&
memcmp
(
&
daddr6
,
&
in6addr_any
,
sizeof
(
daddr6
))))
{
fprintf
(
stderr
,
"vxlan: both group and remote cannot be specified
\n
"
);
return
-
1
;
}
...
...
@@ -176,8 +190,16 @@ static int vxlan_parse_opt(struct link_util *lu, int argc, char **argv,
addattr_l
(
n
,
1024
,
IFLA_VXLAN_GROUP
,
&
gaddr
,
4
);
else
if
(
daddr
)
addattr_l
(
n
,
1024
,
IFLA_VXLAN_GROUP
,
&
daddr
,
4
);
if
(
memcmp
(
&
gaddr6
,
&
in6addr_any
,
sizeof
(
gaddr6
))
!=
0
)
addattr_l
(
n
,
1024
,
IFLA_VXLAN_GROUP6
,
&
gaddr6
,
sizeof
(
struct
in6_addr
));
else
if
(
memcmp
(
&
daddr6
,
&
in6addr_any
,
sizeof
(
daddr6
))
!=
0
)
addattr_l
(
n
,
1024
,
IFLA_VXLAN_GROUP6
,
&
daddr6
,
sizeof
(
struct
in6_addr
));
if
(
saddr
)
addattr_l
(
n
,
1024
,
IFLA_VXLAN_LOCAL
,
&
saddr
,
4
);
else
if
(
memcmp
(
&
saddr6
,
&
in6addr_any
,
sizeof
(
saddr6
))
!=
0
)
addattr_l
(
n
,
1024
,
IFLA_VXLAN_LOCAL6
,
&
saddr6
,
sizeof
(
struct
in6_addr
));
if
(
link
)
addattr32
(
n
,
1024
,
IFLA_VXLAN_LINK
,
link
);
addattr8
(
n
,
1024
,
IFLA_VXLAN_TTL
,
ttl
);
...
...
@@ -229,6 +251,17 @@ static void vxlan_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
fprintf
(
f
,
"remote %s "
,
format_host
(
AF_INET
,
4
,
&
addr
,
s1
,
sizeof
(
s1
)));
}
}
else
if
(
tb
[
IFLA_VXLAN_GROUP6
])
{
struct
in6_addr
addr
;
memcpy
(
&
addr
,
RTA_DATA
(
tb
[
IFLA_VXLAN_GROUP6
]),
sizeof
(
struct
in6_addr
));
if
(
memcmp
(
&
addr
,
&
in6addr_any
,
sizeof
(
addr
))
!=
0
)
{
if
(
IN6_IS_ADDR_MULTICAST
(
&
addr
))
fprintf
(
f
,
"group %s "
,
format_host
(
AF_INET6
,
sizeof
(
struct
in6_addr
),
&
addr
,
s1
,
sizeof
(
s1
)));
else
fprintf
(
f
,
"remote %s "
,
format_host
(
AF_INET6
,
sizeof
(
struct
in6_addr
),
&
addr
,
s1
,
sizeof
(
s1
)));
}
}
if
(
tb
[
IFLA_VXLAN_LOCAL
])
{
...
...
@@ -236,6 +269,12 @@ static void vxlan_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
if
(
addr
)
fprintf
(
f
,
"local %s "
,
format_host
(
AF_INET
,
4
,
&
addr
,
s1
,
sizeof
(
s1
)));
}
else
if
(
tb
[
IFLA_VXLAN_LOCAL6
])
{
struct
in6_addr
addr
;
memcpy
(
&
addr
,
RTA_DATA
(
tb
[
IFLA_VXLAN_LOCAL6
]),
sizeof
(
struct
in6_addr
));
if
(
memcmp
(
&
addr
,
&
in6addr_any
,
sizeof
(
addr
))
!=
0
)
fprintf
(
f
,
"local %s "
,
format_host
(
AF_INET6
,
sizeof
(
struct
in6_addr
),
&
addr
,
s1
,
sizeof
(
s1
)));
}
if
(
tb
[
IFLA_VXLAN_LINK
]
&&
...
...
ip/link_gre6.c
0 → 100644
View file @
f1f1aeb2
/*
* link_gre6.c gre driver module
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
* Authors: Dmitry Kozlov <xeb@mail.ru>
*
*/
#include <string.h>
#include <net/if.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <linux/ip.h>
#include <linux/if_tunnel.h>
#include <linux/ip6_tunnel.h>
#include "rt_names.h"
#include "utils.h"
#include "ip_common.h"
#include "tunnel.h"
#define IP6_FLOWINFO_TCLASS htonl(0x0FF00000)
#define IP6_FLOWINFO_FLOWLABEL htonl(0x000FFFFF)
#define DEFAULT_TNL_HOP_LIMIT (64)
static
void
usage
(
void
)
__attribute__
((
noreturn
));
static
void
usage
(
void
)
{
fprintf
(
stderr
,
"Usage: ip link { add | set | change | replace | del } NAME
\n
"
);
fprintf
(
stderr
,
" type { ip6gre | ip6gretap } [ remote ADDR ] [ local ADDR ]
\n
"
);
fprintf
(
stderr
,
" [ [i|o]seq ] [ [i|o]key KEY ] [ [i|o]csum ]
\n
"
);
fprintf
(
stderr
,
" [ hoplimit TTL ] [ encaplimit ELIM ]
\n
"
);
fprintf
(
stderr
,
" [ tclass TCLASS ] [ flowlabel FLOWLABEL ]
\n
"
);
fprintf
(
stderr
,
" [ dscp inherit ] [ dev PHYS_DEV ]
\n
"
);
fprintf
(
stderr
,
"
\n
"
);
fprintf
(
stderr
,
"Where: NAME := STRING
\n
"
);
fprintf
(
stderr
,
" ADDR := IPV6_ADDRESS
\n
"
);
fprintf
(
stderr
,
" TTL := { 0..255 } (default=%d)
\n
"
,
DEFAULT_TNL_HOP_LIMIT
);
fprintf
(
stderr
,
" KEY := { DOTTED_QUAD | NUMBER }
\n
"
);
fprintf
(
stderr
,
" ELIM := { none | 0..255 }(default=%d)
\n
"
,
IPV6_DEFAULT_TNL_ENCAP_LIMIT
);
fprintf
(
stderr
,
" TCLASS := { 0x0..0xff | inherit }
\n
"
);
fprintf
(
stderr
,
" FLOWLABEL := { 0x0..0xfffff | inherit }
\n
"
);
exit
(
-
1
);
}
static
int
gre_parse_opt
(
struct
link_util
*
lu
,
int
argc
,
char
**
argv
,
struct
nlmsghdr
*
n
)
{
struct
{
struct
nlmsghdr
n
;
struct
ifinfomsg
i
;
char
buf
[
1024
];
}
req
;
struct
ifinfomsg
*
ifi
=
(
struct
ifinfomsg
*
)(
n
+
1
);
struct
rtattr
*
tb
[
IFLA_MAX
+
1
];
struct
rtattr
*
linkinfo
[
IFLA_INFO_MAX
+
1
];
struct
rtattr
*
greinfo
[
IFLA_GRE_MAX
+
1
];
__u16
iflags
=
0
;
__u16
oflags
=
0
;
unsigned
ikey
=
0
;
unsigned
okey
=
0
;
struct
in6_addr
raddr
=
IN6ADDR_ANY_INIT
;
struct
in6_addr
laddr
=
IN6ADDR_ANY_INIT
;
unsigned
link
=
0
;
unsigned
flowinfo
=
0
;
unsigned
flags
=
0
;
__u8
hop_limit
=
DEFAULT_TNL_HOP_LIMIT
;
__u8
encap_limit
=
IPV6_DEFAULT_TNL_ENCAP_LIMIT
;
int
len
;
if
(
!
(
n
->
nlmsg_flags
&
NLM_F_CREATE
))
{
memset
(
&
req
,
0
,
sizeof
(
req
));
req
.
n
.
nlmsg_len
=
NLMSG_LENGTH
(
sizeof
(
*
ifi
));
req
.
n
.
nlmsg_flags
=
NLM_F_REQUEST
;
req
.
n
.
nlmsg_type
=
RTM_GETLINK
;
req
.
i
.
ifi_family
=
preferred_family
;
req
.
i
.
ifi_index
=
ifi
->
ifi_index
;
if
(
rtnl_talk
(
&
rth
,
&
req
.
n
,
0
,
0
,
&
req
.
n
)
<
0
)
{
get_failed:
fprintf
(
stderr
,
"Failed to get existing tunnel info.
\n
"
);
return
-
1
;
}
len
=
req
.
n
.
nlmsg_len
;
len
-=
NLMSG_LENGTH
(
sizeof
(
*
ifi
));
if
(
len
<
0
)
goto
get_failed
;
parse_rtattr
(
tb
,
IFLA_MAX
,
IFLA_RTA
(
&
req
.
i
),
len
);
if
(
!
tb
[
IFLA_LINKINFO
])
goto
get_failed
;
parse_rtattr_nested
(
linkinfo
,
IFLA_INFO_MAX
,
tb
[
IFLA_LINKINFO
]);
if
(
!
linkinfo
[
IFLA_INFO_DATA
])
goto
get_failed
;
parse_rtattr_nested
(
greinfo
,
IFLA_GRE_MAX
,
linkinfo
[
IFLA_INFO_DATA
]);
if
(
greinfo
[
IFLA_GRE_IKEY
])
ikey
=
rta_getattr_u32
(
greinfo
[
IFLA_GRE_IKEY
]);
if
(
greinfo
[
IFLA_GRE_OKEY
])
okey
=
rta_getattr_u32
(
greinfo
[
IFLA_GRE_OKEY
]);
if
(
greinfo
[
IFLA_GRE_IFLAGS
])
iflags
=
rta_getattr_u16
(
greinfo
[
IFLA_GRE_IFLAGS
]);
if
(
greinfo
[
IFLA_GRE_OFLAGS
])
oflags
=
rta_getattr_u16
(
greinfo
[
IFLA_GRE_OFLAGS
]);
if
(
greinfo
[
IFLA_GRE_LOCAL
])
memcpy
(
&
laddr
,
RTA_DATA
(
greinfo
[
IFLA_GRE_LOCAL
]),
sizeof
(
laddr
));
if
(
greinfo
[
IFLA_GRE_REMOTE
])
memcpy
(
&
raddr
,
RTA_DATA
(
greinfo
[
IFLA_GRE_REMOTE
]),
sizeof
(
raddr
));
if
(
greinfo
[
IFLA_GRE_TTL
])
hop_limit
=
rta_getattr_u8
(
greinfo
[
IFLA_GRE_TTL
]);
if
(
greinfo
[
IFLA_GRE_LINK
])
link
=
rta_getattr_u32
(
greinfo
[
IFLA_GRE_LINK
]);
if
(
greinfo
[
IFLA_GRE_ENCAP_LIMIT
])
encap_limit
=
rta_getattr_u8
(
greinfo
[
IFLA_GRE_ENCAP_LIMIT
]);
if
(
greinfo
[
IFLA_GRE_FLOWINFO
])
flowinfo
=
rta_getattr_u32
(
greinfo
[
IFLA_GRE_FLOWINFO
]);
if
(
greinfo
[
IFLA_GRE_FLAGS
])
flags
=
rta_getattr_u32
(
greinfo
[
IFLA_GRE_FLAGS
]);
}
while
(
argc
>
0
)
{
if
(
!
matches
(
*
argv
,
"key"
))
{
unsigned
uval
;
NEXT_ARG
();
iflags
|=
GRE_KEY
;
oflags
|=
GRE_KEY
;
if
(
strchr
(
*
argv
,
'.'
))
uval
=
get_addr32
(
*
argv
);
else
{
if
(
get_unsigned
(
&
uval
,
*
argv
,
0
)
<
0
)
{
fprintf
(
stderr
,
"Invalid value for
\"
key
\"\n
"
);
exit
(
-
1
);
}
uval
=
htonl
(
uval
);
}
ikey
=
okey
=
uval
;
}
else
if
(
!
matches
(
*
argv
,
"ikey"
))
{
unsigned
uval
;
NEXT_ARG
();
iflags
|=
GRE_KEY
;
if
(
strchr
(
*
argv
,
'.'
))
uval
=
get_addr32
(
*
argv
);
else
{
if
(
get_unsigned
(
&
uval
,
*
argv
,
0
)
<
0
)
{
fprintf
(
stderr
,
"invalid value of
\"
ikey
\"\n
"
);
exit
(
-
1
);
}
uval
=
htonl
(
uval
);
}
ikey
=
uval
;
}
else
if
(
!
matches
(
*
argv
,
"okey"
))
{
unsigned
uval
;
NEXT_ARG
();
oflags
|=
GRE_KEY
;
if
(
strchr
(
*
argv
,
'.'
))
uval
=
get_addr32
(
*
argv
);
else
{
if
(
get_unsigned
(
&
uval
,
*
argv
,
0
)
<
0
)
{
fprintf
(
stderr
,
"invalid value of
\"
okey
\"\n
"
);
exit
(
-
1
);
}
uval
=
htonl
(
uval
);
}
okey
=
uval
;
}
else
if
(
!
matches
(
*
argv
,
"seq"
))
{
iflags
|=
GRE_SEQ
;
oflags
|=
GRE_SEQ
;
}
else
if
(
!
matches
(
*
argv
,
"iseq"
))
{
iflags
|=
GRE_SEQ
;
}
else
if
(
!
matches
(
*
argv
,
"oseq"
))
{
oflags
|=
GRE_SEQ
;
}
else
if
(
!
matches
(
*
argv
,
"csum"
))
{
iflags
|=
GRE_CSUM
;
oflags
|=
GRE_CSUM
;
}
else
if
(
!
matches
(
*
argv
,
"icsum"
))
{
iflags
|=
GRE_CSUM
;
}
else
if
(
!
matches
(
*
argv
,
"ocsum"
))
{
oflags
|=
GRE_CSUM
;
}
else
if
(
!
matches
(
*
argv
,
"remote"
))
{
inet_prefix
addr
;
NEXT_ARG
();
get_prefix
(
&
addr
,
*
argv
,
preferred_family
);
if
(
addr
.
family
==
AF_UNSPEC
)
invarg
(
"
\"
remote
\"
address family is AF_UNSPEC"
,
*
argv
);
memcpy
(
&
raddr
,
&
addr
.
data
,
sizeof
(
raddr
));
}
else
if
(
!
matches
(
*
argv
,
"local"
))
{
inet_prefix
addr
;
NEXT_ARG
();
get_prefix
(
&
addr
,
*
argv
,
preferred_family
);
if
(
addr
.
family
==
AF_UNSPEC
)
invarg
(
"
\"
local
\"
address family is AF_UNSPEC"
,
*
argv
);
memcpy
(
&
laddr
,
&
addr
.
data
,
sizeof
(
laddr
));
}
else
if
(
!
matches
(
*
argv
,
"dev"
))
{
NEXT_ARG
();
link
=
if_nametoindex
(
*
argv
);
if
(
link
==
0
)
exit
(
-
1
);
}
else
if
(
!
matches
(
*
argv
,
"ttl"
)
||
!
matches
(
*
argv
,
"hoplimit"
))
{
__u8
uval
;
NEXT_ARG
();
if
(
get_u8
(
&
uval
,
*
argv
,
0
))
invarg
(
"invalid TTL"
,
*
argv
);
hop_limit
=
uval
;
}
else
if
(
!
matches
(
*
argv
,
"tos"
)
||
!
matches
(
*
argv
,
"tclass"
)
||
!
matches
(
*
argv
,
"dsfield"
))
{
__u8
uval
;
NEXT_ARG
();
if
(
strcmp
(
*
argv
,
"inherit"
)
==
0
)
flags
|=
IP6_TNL_F_USE_ORIG_TCLASS
;
else
{
if
(
get_u8
(
&
uval
,
*
argv
,
16
))
invarg
(
"invalid TClass"
,
*
argv
);
flowinfo
|=
htonl
((
__u32
)
uval
<<
20
)
&
IP6_FLOWINFO_TCLASS
;
flags
&=
~
IP6_TNL_F_USE_ORIG_TCLASS
;
}
}
else
if
(
strcmp
(
*
argv
,
"flowlabel"
)
==
0
||
strcmp
(
*
argv
,
"fl"
)
==
0
)
{
__u32
uval
;
NEXT_ARG
();
if
(
strcmp
(
*
argv
,
"inherit"
)
==
0
)
flags
|=
IP6_TNL_F_USE_ORIG_FLOWLABEL
;
else
{
if
(
get_u32
(
&
uval
,
*
argv
,
16
))
invarg
(
"invalid Flowlabel"
,
*
argv
);
if
(
uval
>
0xFFFFF
)
invarg
(
"invalid Flowlabel"
,
*
argv
);
flowinfo
|=
htonl
(
uval
)
&
IP6_FLOWINFO_FLOWLABEL
;
flags
&=
~
IP6_TNL_F_USE_ORIG_FLOWLABEL
;
}
}
else
if
(
strcmp
(
*
argv
,
"dscp"
)
==
0
)
{
NEXT_ARG
();
if
(
strcmp
(
*
argv
,
"inherit"
)
!=
0
)
invarg
(
"not inherit"
,
*
argv
);
flags
|=
IP6_TNL_F_RCV_DSCP_COPY
;
}
else
usage
();
argc
--
;
argv
++
;
}
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
,
&
laddr
,
sizeof
(
laddr
));
addattr_l
(
n
,
1024
,
IFLA_GRE_REMOTE
,
&
raddr
,
sizeof
(
raddr
));
if
(
link
)
addattr32
(
n
,
1024
,
IFLA_GRE_LINK
,
link
);
addattr_l
(
n
,
1024
,
IFLA_GRE_TTL
,
&
hop_limit
,
1
);
addattr_l
(
n
,
1024
,
IFLA_GRE_ENCAP_LIMIT
,
&
encap_limit
,
1
);
addattr_l
(
n
,
1024
,
IFLA_GRE_FLOWINFO
,
&
flowinfo
,
4
);
addattr_l
(
n
,
1024
,
IFLA_GRE_FLAGS
,
&
flowinfo
,
4
);
return
0
;
}
static
void
gre_print_opt
(
struct
link_util
*
lu
,
FILE
*
f
,
struct
rtattr
*
tb
[])
{
char
s1
[
1024
];
char
s2
[
64
];
const
char
*
local
=
"any"
;
const
char
*
remote
=
"any"
;
unsigned
iflags
=
0
;
unsigned
oflags
=
0
;
unsigned
flags
=
0
;
unsigned
flowinfo
=
0
;
struct
in6_addr
in6_addr_any
=
IN6ADDR_ANY_INIT
;
if
(
!
tb
)
return
;
if
(
tb
[
IFLA_GRE_FLAGS
])
flags
=
rta_getattr_u32
(
tb
[
IFLA_GRE_FLAGS
]);
if
(
tb
[
IFLA_GRE_FLOWINFO
])
flags
=
rta_getattr_u32
(
tb
[
IFLA_GRE_FLOWINFO
]);
if
(
tb
[
IFLA_GRE_REMOTE
])
{
struct
in6_addr
addr
;
memcpy
(
&
addr
,
RTA_DATA
(
tb
[
IFLA_GRE_REMOTE
]),
sizeof
(
addr
));
if
(
memcmp
(
&
addr
,
&
in6_addr_any
,
sizeof
(
addr
)))
remote
=
format_host
(
AF_INET6
,
sizeof
(
addr
),
&
addr
,
s1
,
sizeof
(
s1
));
}
fprintf
(
f
,
"remote %s "
,
remote
);
if
(
tb
[
IFLA_GRE_LOCAL
])
{
struct
in6_addr
addr
;
memcpy
(
&
addr
,
RTA_DATA
(
tb
[
IFLA_GRE_LOCAL
]),
sizeof
(
addr
));
if
(
memcmp
(
&
addr
,
&
in6_addr_any
,
sizeof
(
addr
)))
local
=
format_host
(
AF_INET6
,
sizeof
(
addr
),
&
addr
,
s1
,
sizeof
(
s1
));
}
fprintf
(
f
,
"local %s "
,
local
);
if
(
tb
[
IFLA_GRE_LINK
]
&&
rta_getattr_u32
(
tb
[
IFLA_GRE_LINK
]))
{
unsigned
link
=
rta_getattr_u32
(
tb
[
IFLA_GRE_LINK
]);
const
char
*
n
=
if_indextoname
(
link
,
s2
);
if
(
n
)
fprintf
(
f
,
"dev %s "
,
n
);
else
fprintf
(
f
,
"dev %u "
,
link
);
}
if
(
tb
[
IFLA_GRE_TTL
]
&&
rta_getattr_u8
(
tb
[
IFLA_GRE_TTL
]))
fprintf
(
f
,
"hoplimit %d "
,
rta_getattr_u8
(
tb
[
IFLA_GRE_TTL
]));
if
(
flags
&
IP6_TNL_F_IGN_ENCAP_LIMIT
)
fprintf
(
f
,
"encaplimit none "
);
else
if
(
tb
[
IFLA_GRE_ENCAP_LIMIT
])
{
int
encap_limit
=
rta_getattr_u8
(
tb
[
IFLA_GRE_ENCAP_LIMIT
]);
fprintf
(
f
,
"encaplimit %d "
,
encap_limit
);
}
if
(
flags
&
IP6_TNL_F_USE_ORIG_FLOWLABEL
)
fprintf
(
f
,
"flowlabel inherit "
);
else
fprintf
(
f
,
"flowlabel 0x%05x "
,
ntohl
(
flowinfo
&
IP6_FLOWINFO_FLOWLABEL
));
if
(
flags
&
IP6_TNL_F_RCV_DSCP_COPY
)
fprintf
(
f
,
"dscp inherit "
);
if
(
tb
[
IFLA_GRE_IFLAGS
])
iflags
=
rta_getattr_u16
(
tb
[
IFLA_GRE_IFLAGS
]);
if
(
tb
[
IFLA_GRE_OFLAGS
])
oflags
=
rta_getattr_u16
(
tb
[
IFLA_GRE_OFLAGS
]);
if
((
iflags
&
GRE_KEY
)
&&
tb
[
IFLA_GRE_IKEY
])
{
inet_ntop
(
AF_INET
,
RTA_DATA
(
tb
[
IFLA_GRE_IKEY
]),
s2
,
sizeof
(
s2
));
fprintf
(
f
,
"ikey %s "
,
s2
);
}
if
((
oflags
&
GRE_KEY
)
&&
tb
[
IFLA_GRE_OKEY
])
{
inet_ntop
(
AF_INET
,
RTA_DATA
(
tb
[
IFLA_GRE_OKEY
]),
s2
,
sizeof
(
s2
));
fprintf
(
f
,
"okey %s "
,
s2
);
}
if
(
iflags
&
GRE_SEQ
)
fputs
(
"iseq "
,
f
);
if
(
oflags
&
GRE_SEQ
)
fputs
(
"oseq "
,
f
);
if
(
iflags
&
GRE_CSUM
)
fputs
(
"icsum "
,
f
);
if
(
oflags
&
GRE_CSUM
)
fputs
(
"ocsum "
,
f
);
}
struct
link_util
ip6gre_link_util
=
{
.
id
=
"ip6gre"
,
.
maxattr
=
IFLA_GRE_MAX
,
.
parse_opt
=
gre_parse_opt
,
.
print_opt
=
gre_print_opt
,
};
struct
link_util
ip6gretap_link_util
=
{
.
id
=
"ip6gretap"
,
.
maxattr
=
IFLA_GRE_MAX
,
.
parse_opt
=
gre_parse_opt
,
.
print_opt
=
gre_print_opt
,
};
ip/xfrm_policy.c
View file @
f1f1aeb2
...
...
@@ -373,7 +373,7 @@ static int xfrm_policy_modify(int cmd, unsigned flags, int argc, char **argv)
(
void
*
)
tmpls_buf
,
tmpls_len
);
}
if
(
mark
.
m
&
mark
.
v
)
{
if
(
mark
.
m
)
{
int
r
=
addattr_l
(
&
req
.
n
,
sizeof
(
req
.
buf
),
XFRMA_MARK
,
(
void
*
)
&
mark
,
sizeof
(
mark
));
if
(
r
<
0
)
{
...
...
ip/xfrm_state.c
View file @
f1f1aeb2
...
...
@@ -162,7 +162,7 @@ static int xfrm_algo_parse(struct xfrm_algo *alg, enum xfrm_attr_type_t type,
if
(
len
>
max
)
invarg
(
"ALGO-KEYMAT value makes buffer overflow
\n
"
,
key
);
strn
cpy
(
buf
,
key
,
len
);
mem
cpy
(
buf
,
key
,
len
);
}
}
...
...
@@ -528,7 +528,7 @@ static int xfrm_state_modify(int cmd, unsigned flags, int argc, char **argv)
exit
(
1
);
}
if
(
mark
.
m
&
mark
.
v
)
{
if
(
mark
.
m
)
{
int
r
=
addattr_l
(
&
req
.
n
,
sizeof
(
req
.
buf
),
XFRMA_MARK
,
(
void
*
)
&
mark
,
sizeof
(
mark
));
if
(
r
<
0
)
{
...
...
lib/ll_types.c
View file @
f1f1aeb2
...
...
@@ -103,6 +103,7 @@ __PF(IEEE802154, ieee802.15.4)
__PF
(
PHONET
,
phonet
)
__PF
(
PHONET_PIPE
,
phonet_pipe
)
__PF
(
CAIF
,
caif
)
__PF
(
IP6GRE
,
gre6
)
__PF
(
NONE
,
none
)
__PF
(
VOID
,
void
)
...
...
lib/utils.c
View file @
f1f1aeb2
...
...
@@ -868,3 +868,11 @@ int makeargs(char *line, char *argv[], int maxargs)
return
argc
;
}
int
inet_get_addr
(
const
char
*
src
,
__u32
*
dst
,
struct
in6_addr
*
dst6
)
{
if
(
strchr
(
src
,
':'
))
return
inet_pton
(
AF_INET6
,
src
,
dst6
);
else
return
inet_pton
(
AF_INET
,
src
,
dst
);
}
man/man8/bridge.8
View file @
f1f1aeb2
...
...
@@ -13,7 +13,7 @@ bridge \- show / manipulate bridge addresses and devices
.ti -8
.IR OBJECT " := { "
.BR link " | " fdb " | " vlan " | " monitor " }"
.BR link " | " fdb " | "
mdb " | "
vlan " | " monitor " }"
.sp
.ti -8
...
...
@@ -64,6 +64,21 @@ bridge \- show / manipulate bridge addresses and devices
.B dev
.IR DEV " ]"
.ti -8
.BR "bridge mdb" " { " add " | " del " } "
.B dev
.IR DEV
.B port
.IR PORT
.B grp
.IR GROUP " [ "
.BR permanent " | " temp " ]"
.ti -8
.BR "bridge mdb show " [ "
.B dev
.IR DEV " ]"
.ti -8
.BR "bridge vlan" " { " add " | " del " } "
.B dev
...
...
@@ -79,7 +94,7 @@ bridge \- show / manipulate bridge addresses and devices
.IR DEV " ]"
.ti -8
.BR "bridge monitor" " [ " all " | " neigh " | " link " ]"
.BR "bridge monitor" " [ " all " | " neigh " | " link "
| " mdb "
]"
.SH OPTIONS
...
...
@@ -109,6 +124,10 @@ As a rule, the information is statistics or some time values.
.B fdb
- Forwarding Database entry.
.TP
.B mdb
- Multicast group database entry.
.TP
.B vlan
- VLAN filter list.
...
...
@@ -326,6 +345,69 @@ With the
option, the command becomes verbose. It prints out the last updated
and last used time for each entry.
.SH bridge mdb - multicast group database management
.B mdb
objects contain known IP multicast group addresses on a link.
.P
The corresponding commands display mdb entries, add new entries,
and delete old ones.
.SS bridge mdb add - add a new multicast group database entry
This command creates a new mdb entry.
.TP
.BI dev " DEV"
the interface where this group address is associated.
.TP
.BI port " PORT"
the port whose link is known to have members of this multicast group.
.TP
.BI grp " GROUP"
the IP multicast group address whose members reside on the link connected to
the port.
.B permanent
- the mdb entry is permanent
.sp
.B temp
- the mdb entry is temporary (default)
.sp
.in -8
.SS bridge mdb delete - delete a multicast group database entry
This command removes an existing mdb entry.
.PP
The arguments are the same as with
.BR "bridge mdb add" .
.SS bridge mdb show - list multicast group database entries
This command displays the current multicast group membership table. The table
is populated by IGMP and MLD snooping in the bridge driver automatically. It
can be altered by
.B bridge mdb add
and
.B bridge mdb del
commands manually too.
.TP
.BI dev " DEV"
the interface only whose entries should be listed. Default is to list all
bridge interfaces.
.PP
With the
.B -details
option, the command becomes verbose. It prints out the ports known to have
a connected router.
.SH bridge vlan - VLAN filter list
.B vlan
...
...
@@ -395,7 +477,7 @@ command is the first in the command line and then the object list follows:
.I OBJECT-LIST
is the list of object types that we want to monitor.
It may contain
.BR link ",
and " f
db "."
.BR link ",
" fdb ", and " m
db "."
If no
.B file
argument is given,
...
...
man/man8/ip-link.8.in
View file @
f1f1aeb2
...
...
@@ -62,7 +62,11 @@ ip-link \- network device configuration
.BR vxlan " |"
.BR ip6tnl " |"
.BR ipip " |"
.BR sit " ]"
.BR sit " |"
.BR gre " |"
.BR gretap " |"
.BR ip6gre " |"
.BR ip6gretap " ]"
.ti -8
.BI "ip link delete " DEVICE
...
...
@@ -186,6 +190,18 @@ Link types:
.sp
.BR sit
- Virtual tunnel interface IPv6 over IPv4
.sp
.BR gre
- Virtual tunnel interface GRE over IPv4
.sp
.BR gretap
- Virtual L2 tuunel interface GRE over IPv4
.sp
.BR ip6gre
- Virtual tuunel interface GRE over IPv6
.sp
.BR ip6gretap
- Virtual L2 tuunel interface GRE over IPv6
.in -8
.TP
...
...
@@ -292,6 +308,112 @@ are entered into the VXLAN device forwarding database.
.in -8
.TP
IP6GRE/IP6GRETAP Type Support
For a link of type
.I IP6GRE/IP6GRETAP
the following additional arguments are supported:
.BI "ip link add " DEVICE
.BI type " { ip6gre | ip6gretap } " remote " ADDR " local " ADDR
.R " [ "
.I "[i|o]seq]"
.R " ] [ "
.I "[i|o]key" KEY
.R " ] [ "
.I " [i|o]csum "
.R " ] [ "
.BI hoplimit " TTL "
.R " ] [ "
.BI encaplimit " ELIM "
.R " ] [ "
.BI tclass " TCLASS "
.R " ] [ "
.BI flowlabel " FLOWLABEL "
.R " ] [ "
.BI "dscp inherit"
.R " ] [ "
.BI dev " PHYS_DEV "
.R " ]"
.in +8
.sp
.BI remote " ADDR "
- specifies the remote IPv6 address of the tunnel.
.sp
.BI local " ADDR "
- specifies the fixed local IPv6 address for tunneled packets.
It must be and address on another interface on this host.
.sp
.BI [i|o]seq
- serialize packets.
The
.B oseq
flag enables sequencing of outgoing packets.
The
.B iseq
flag requires that all input packets are serialized.
.sp
.BI [i|o]key " KEY"
- use keyed GRE with key
.IR KEY ". "KEY
is either a number or an IPv4 address-like dotted quad.
The
.B key
parameter specifies the same key to use in both directions.
The
.BR ikey " and " okey
parameters specify different keys for input and output.
.sp
.BI [i|o]csum
- generate/require checksums for tunneled packets.
The
.B ocsum
flag calculates checksums for outgoing packets.
The
.B icsum
flag requires that all input packets have the correct
checksum. The
.B csum
flag is equivalent to the combination
.BR "icsum ocsum" .
.sp
.BI hoplimit " TTL"
- specifies Hop Limit value to use in outgoing packets.
.sp
.BI encaplimit " ELIM"
- specifies a fixed encapsulation limit. Default is 4.
.sp
.BI flowlabel " FLOWLABEL"
- specifies a fixed flowlabel.
.sp
.BI tclass " TCLASS"
- specifies the traffic class field on
tunneled packets, which can be specified as either a two-digit
hex value (e.g. c0) or a predefined string (e.g. internet).
The value
.B inherit
causes the field to be copied from the original IP header. The
values
.BI "inherit/" STRING
or
.BI "inherit/" 00 ".." ff
will set the field to
.I STRING
or
.IR 00 ".." ff
when tunneling non-IP packets. The default value is 00.
.in -8
.SS ip link delete - delete virtual link
.I DEVICE
specifies the virtual device to act operate on.
...
...
man/man8/ip-tunnel.8
View file @
f1f1aeb2
...
...
@@ -50,7 +50,7 @@ ip-tunnel - tunnel configuration
.ti -8
.IR MODE " := "
.RB " { " ipip " | " gre " | " sit " | " isatap " | " ip6ip6 " | " ipip6 " | " any " }"
.RB " { " ipip " | " gre " | " sit " | " isatap " | " ip6ip6 " | " ipip6 " | "
ip6gre " | "
any " }"
.ti -8
.IR ADDR " := { " IP_ADDRESS " |"
...
...
@@ -110,7 +110,7 @@ Modes for IPv4 encapsulation available:
.BR ipip ", " sit ", " isatap " and " gre "."
.br
Modes for IPv6 encapsulation available:
.BR ip6ip6 ", " ipip6 " and " any "."
.BR ip6ip6 ", " ipip6 "
, " ip6gre ",
and " any "."
.TP
.BI remote " ADDRESS"
...
...
man/man8/lnstat.8
View file @
f1f1aeb2
...
...
@@ -33,6 +33,9 @@ Statistics file to use.
.B \-i, \-\-interval <intv>
Set interval to 'intv' seconds.
.TP
.B \-j, \-\-json
Display results in JSON format
.TP
.B \-k, \-\-keys k,k,k,...
Display only keys specified.
.TP
...
...
man/man8/rtacct.8
View file @
f1f1aeb2
...
...
@@ -15,33 +15,35 @@ and
are simple tools to monitor kernel snmp counters and network interface statistics.
.SH OPTIONS
.TP
-h -?
.B \-h, \-\-help
Print help
.TP
-v -V
.B \-V, \-\-version
Print version
.TP
-z
.B \-z, \-\-zero
Dump zero counters too. By default they are not shown.
.TP
-r
.B \-r, \-\-reset
Reset history.
.TP
-n
.B \-n, \-\-nooutput
Do not display anything, only update history.
.TP
-a
.B \-a, \-\-ignore
Dump absolute values of counters. The default is to calculate increments since the previous use.
.TP
-s
.B \-s, \-\-noupdate
Do not update history, so that the next time you will see counters including values accumulated to the moment of this measurement too.
.B \-j, \-\-json
Display results in JSON format.
.TP
-d
<INTERVAL>
.B \-d, \-\-interval
<INTERVAL>
Run in daemon mode collecting statistics. <INTERVAL> is interval between measurements in seconds.
.TP
-t <INTERVAL>
Time interval to average rates. Default value is 60 seconds.
.TP
.SH SEE ALSO
lnstat(8)
...
...
misc/ifstat.c
View file @
f1f1aeb2
...
...
@@ -38,6 +38,7 @@ int dump_zeros = 0;
int
reset_history
=
0
;
int
ignore_history
=
0
;
int
no_output
=
0
;
int
json_output
=
0
;
int
no_update
=
0
;
int
scan_interval
=
0
;
int
time_constant
=
0
;
...
...
@@ -61,6 +62,32 @@ struct ifstat_ent
__u32
ival
[
MAXS
];
};
static
const
char
*
stats
[
MAXS
]
=
{
"rx_packets"
,
"tx_packets"
,
"rx_bytes"
,
"tx_bytes"
,
"rx_errors"
,
"tx_errors"
,
"rx_dropped"
,
"tx_dropped"
,
"multicast"
,
"collisions"
,
"rx_length_errors"
,
"rx_over_errors"
,
"rx_crc_errors"
,
"rx_frame_errors"
,
"rx_fifo_errors"
,
"rx_missed_errors"
,
"tx_aborted_errors"
,
"tx_carrier_errors"
,
"tx_fifo_errors"
,
"tx_heartbeat_errors"
,
"tx_window_errors"
,
"rx_compressed"
,
"tx_compressed"
};
struct
ifstat_ent
*
kern_db
;
struct
ifstat_ent
*
hist_db
;
...
...
@@ -212,8 +239,13 @@ static void load_raw_table(FILE *fp)
static
void
dump_raw_db
(
FILE
*
fp
,
int
to_hist
)
{
struct
ifstat_ent
*
n
,
*
h
;
const
char
*
eol
=
"
\n
"
;
h
=
hist_db
;
fprintf
(
fp
,
"#%s
\n
"
,
info_source
);
if
(
json_output
)
fprintf
(
fp
,
"{
\"
%s
\"
:{"
,
info_source
);
else
fprintf
(
fp
,
"#%s
\n
"
,
info_source
);
for
(
n
=
kern_db
;
n
;
n
=
n
->
next
)
{
int
i
;
...
...
@@ -232,10 +264,22 @@ static void dump_raw_db(FILE *fp, int to_hist)
}
}
}
fprintf
(
fp
,
"%d %s "
,
n
->
ifindex
,
n
->
name
);
for
(
i
=
0
;
i
<
MAXS
;
i
++
)
fprintf
(
fp
,
"%llu %u "
,
vals
[
i
],
(
unsigned
)
rates
[
i
]);
fprintf
(
fp
,
"
\n
"
);
if
(
json_output
)
{
fprintf
(
fp
,
"%s
\"
%s
\"
:{"
,
eol
,
n
->
name
);
eol
=
",
\n
"
;
for
(
i
=
0
;
i
<
MAXS
&&
stats
[
i
];
i
++
)
fprintf
(
fp
,
"
\"
%s
\"
:%llu"
,
stats
[
i
],
vals
[
i
]);
fprintf
(
fp
,
"}"
);
}
else
{
fprintf
(
fp
,
"%d %s "
,
n
->
ifindex
,
n
->
name
);
for
(
i
=
0
;
i
<
MAXS
;
i
++
)
fprintf
(
fp
,
"%llu %u "
,
vals
[
i
],
(
unsigned
)
rates
[
i
]);
fprintf
(
fp
,
"
\n
"
);
}
}
}
...
...
@@ -244,10 +288,11 @@ static const unsigned long long giga = 1000000000ull;
static
const
unsigned
long
long
mega
=
1000000
;
static
const
unsigned
long
long
kilo
=
1000
;
static
void
format_rate
(
FILE
*
fp
,
unsigned
long
long
*
vals
,
double
*
rates
,
int
i
)
static
void
format_rate
(
FILE
*
fp
,
const
unsigned
long
long
*
vals
,
const
double
*
rates
,
int
i
)
{
char
temp
[
64
];
if
(
vals
[
i
]
>
giga
)
fprintf
(
fp
,
"%7lluM "
,
vals
[
i
]
/
mega
);
else
if
(
vals
[
i
]
>
mega
)
...
...
@@ -265,7 +310,7 @@ static void format_rate(FILE *fp, unsigned long long *vals,
fprintf
(
fp
,
"%-6u "
,
(
unsigned
)
rates
[
i
]);
}
static
void
format_pair
(
FILE
*
fp
,
unsigned
long
long
*
vals
,
int
i
,
int
k
)
static
void
format_pair
(
FILE
*
fp
,
const
unsigned
long
long
*
vals
,
int
i
,
int
k
)
{
char
temp
[
64
];
if
(
vals
[
i
]
>
giga
)
...
...
@@ -328,10 +373,27 @@ static void print_head(FILE *fp)
}
}
static
void
print_one_if
(
FILE
*
fp
,
struct
ifstat_ent
*
n
,
unsigned
long
long
*
vals
)
static
void
print_one_json
(
FILE
*
fp
,
const
struct
ifstat_ent
*
n
,
const
unsigned
long
long
*
vals
)
{
int
i
,
m
;
const
char
*
sep
=
" "
;
m
=
show_errors
?
20
:
10
;
fprintf
(
fp
,
"
\"
%s
\"
:{"
,
n
->
name
);
for
(
i
=
0
;
i
<
m
&&
stats
[
i
];
i
++
)
{
fprintf
(
fp
,
"%s
\"
%s
\"
:%llu"
,
sep
,
stats
[
i
],
vals
[
i
]);
sep
=
", "
;
}
fprintf
(
fp
,
" }"
);
}
static
void
print_one_if
(
FILE
*
fp
,
const
struct
ifstat_ent
*
n
,
const
unsigned
long
long
*
vals
)
{
int
i
;
fprintf
(
fp
,
"%-15s "
,
n
->
name
);
for
(
i
=
0
;
i
<
4
;
i
++
)
format_rate
(
fp
,
vals
,
n
->
rate
,
i
);
...
...
@@ -375,27 +437,42 @@ static void print_one_if(FILE *fp, struct ifstat_ent *n,
}
}
static
void
dump_kern_db
(
FILE
*
fp
)
{
struct
ifstat_ent
*
n
;
const
char
*
eol
=
"
\n
"
;
print_head
(
fp
);
if
(
json_output
)
fprintf
(
fp
,
"{
\"
%s
\"
: {"
,
info_source
);
else
print_head
(
fp
);
for
(
n
=
kern_db
;
n
;
n
=
n
->
next
)
{
if
(
!
match
(
n
->
name
))
continue
;
print_one_if
(
fp
,
n
,
n
->
val
);
if
(
json_output
)
{
fprintf
(
fp
,
"%s"
,
eol
);
eol
=
",
\n
"
;
print_one_json
(
fp
,
n
,
n
->
val
);
}
else
print_one_if
(
fp
,
n
,
n
->
val
);
}
if
(
json_output
)
fprintf
(
fp
,
"
\n
} }
\n
"
);
}
static
void
dump_incr_db
(
FILE
*
fp
)
{
struct
ifstat_ent
*
n
,
*
h
;
h
=
hist_db
;
const
char
*
eol
=
"
\n
"
;
print_head
(
fp
);
h
=
hist_db
;
if
(
json_output
)
fprintf
(
fp
,
"{
\"
%s
\"
:{"
,
info_source
);
else
print_head
(
fp
);
for
(
n
=
kern_db
;
n
;
n
=
n
->
next
)
{
int
i
;
...
...
@@ -414,8 +491,16 @@ static void dump_incr_db(FILE *fp)
}
if
(
!
match
(
n
->
name
))
continue
;
print_one_if
(
fp
,
n
,
vals
);
if
(
json_output
)
{
fprintf
(
fp
,
"%s"
,
eol
);
eol
=
",
\n
"
;
print_one_json
(
fp
,
n
,
n
->
val
);
}
else
print_one_if
(
fp
,
n
,
vals
);
}
if
(
json_output
)
fprintf
(
fp
,
"
\n
} }
\n
"
);
}
...
...
@@ -559,9 +644,10 @@ static void usage(void)
" -a, --ignore ignore history
\n
"
" -d, --scan=SECS sample every statistics every SECS
\n
"
" -e, --errors show errors
\n
"
" -j, --json format output in JSON
\n
"
" -n, --nooutput do history only
\n
"
" -r, --reset reset history
\n
"
" -s, --noupdate don
;
t update history
\n
"
" -s, --noupdate don
\'
t update history
\n
"
" -t, --interval=SECS report average over the last SECS
\n
"
" -V, --version output version information
\n
"
" -z, --zeros show entries with zero activity
\n
"
);
...
...
@@ -575,6 +661,7 @@ static const struct option longopts[] = {
{
"scan"
,
1
,
0
,
'd'
},
{
"errors"
,
0
,
0
,
'e'
},
{
"nooutput"
,
0
,
0
,
'n'
},
{
"json"
,
0
,
0
,
'j'
},
{
"reset"
,
0
,
0
,
'r'
},
{
"noupdate"
,
0
,
0
,
's'
},
{
"interval"
,
1
,
0
,
't'
},
...
...
@@ -591,7 +678,7 @@ int main(int argc, char *argv[])
int
ch
;
int
fd
;
while
((
ch
=
getopt_long
(
argc
,
argv
,
"h
vVzrnasd:t:eK
"
,
while
((
ch
=
getopt_long
(
argc
,
argv
,
"h
jvVzrnasd:t:e
"
,
longopts
,
NULL
))
!=
EOF
)
{
switch
(
ch
)
{
case
'z'
:
...
...
@@ -612,6 +699,9 @@ int main(int argc, char *argv[])
case
'e'
:
show_errors
=
1
;
break
;
case
'j'
:
json_output
=
1
;
break
;
case
'd'
:
scan_interval
=
atoi
(
optarg
)
*
1000
;
if
(
scan_interval
<=
0
)
{
...
...
@@ -759,11 +849,14 @@ int main(int argc, char *argv[])
else
dump_incr_db
(
stdout
);
}
if
(
!
no_update
)
{
ftruncate
(
fileno
(
hist_fp
),
0
);
rewind
(
hist_fp
);
json_output
=
0
;
dump_raw_db
(
hist_fp
,
1
);
f
flush
(
hist_fp
);
f
close
(
hist_fp
);
}
exit
(
0
);
}
misc/lnstat.c
View file @
f1f1aeb2
...
...
@@ -41,7 +41,8 @@
static
struct
option
opts
[]
=
{
{
"version"
,
0
,
NULL
,
'V'
},
{
"count"
,
1
,
NULL
,
'c'
},
{
"dump"
,
1
,
NULL
,
'd'
},
{
"dump"
,
0
,
NULL
,
'd'
},
{
"json"
,
0
,
NULL
,
'j'
},
{
"file"
,
1
,
NULL
,
'f'
},
{
"help"
,
0
,
NULL
,
'h'
},
{
"interval"
,
1
,
NULL
,
'i'
},
...
...
@@ -63,6 +64,8 @@ static int usage(char *name, int exit_code)
"Print <count> number of intervals
\n
"
);
fprintf
(
stderr
,
"
\t
-d --dump
\t\t
"
"Dump list of available files/keys
\n
"
);
fprintf
(
stderr
,
"
\t
-j --json
\t\t
"
"Display in JSON format
\n
"
);
fprintf
(
stderr
,
"
\t
-f --file <file>
\t
Statistics file to use
\n
"
);
fprintf
(
stderr
,
"
\t
-h --help
\t\t
This help message
\n
"
);
fprintf
(
stderr
,
"
\t
-i --interval <intv>
\t
"
...
...
@@ -94,7 +97,7 @@ static void print_line(FILE *of, const struct lnstat_file *lnstat_files,
int
i
;
for
(
i
=
0
;
i
<
fp
->
num
;
i
++
)
{
struct
lnstat_field
*
lf
=
fp
->
params
[
i
].
lf
;
const
struct
lnstat_field
*
lf
=
fp
->
params
[
i
].
lf
;
char
formatbuf
[
255
];
snprintf
(
formatbuf
,
sizeof
(
formatbuf
)
-
1
,
"%%%ulu|"
,
...
...
@@ -104,6 +107,30 @@ static void print_line(FILE *of, const struct lnstat_file *lnstat_files,
fputc
(
'\n'
,
of
);
}
static
void
print_json
(
FILE
*
of
,
const
struct
lnstat_file
*
lnstat_files
,
const
struct
field_params
*
fp
)
{
int
i
;
const
char
*
sep
;
const
char
*
base
=
NULL
;
fputs
(
"{
\n
"
,
of
);
for
(
i
=
0
;
i
<
fp
->
num
;
i
++
)
{
const
struct
lnstat_field
*
lf
=
fp
->
params
[
i
].
lf
;
if
(
!
base
||
lf
->
file
->
basename
!=
base
)
{
if
(
base
)
fputs
(
"},
\n
"
,
of
);
base
=
lf
->
file
->
basename
;
sep
=
"
\n\t
"
;
fprintf
(
of
,
"
\"
%s
\"
:{"
,
base
);
}
fprintf
(
of
,
"%s
\"
%s
\"
:%lu"
,
sep
,
lf
->
name
,
lf
->
result
);
sep
=
",
\n\t
"
;
}
fputs
(
"}
\n
}
\n
"
,
of
);
}
/* find lnstat_field according to user specification */
static
int
map_field_params
(
struct
lnstat_file
*
lnstat_files
,
struct
field_params
*
fps
,
int
interval
)
...
...
@@ -218,15 +245,16 @@ int main(int argc, char **argv)
{
struct
lnstat_file
*
lnstat_files
;
const
char
*
basename
;
int
c
;
int
i
,
c
;
int
interval
=
DEFAULT_INTERVAL
;
int
hdr
=
2
;
enum
{
MODE_DUMP
,
MODE_JSON
,
MODE_NORMAL
,
}
mode
=
MODE_NORMAL
;
unsigned
long
count
=
1
;
struct
table_hdr
*
header
;
static
struct
field_params
fp
;
int
num_req_files
=
0
;
char
*
req_files
[
LNSTAT_MAX_FILES
];
...
...
@@ -248,70 +276,73 @@ int main(int argc, char **argv)
num_req_files
=
1
;
}
while
((
c
=
getopt_long
(
argc
,
argv
,
"Vc:df:h?i:k:s:w:"
,
while
((
c
=
getopt_long
(
argc
,
argv
,
"Vc:d
j
f:h?i:k:s:w:"
,
opts
,
NULL
))
!=
-
1
)
{
int
i
,
len
=
0
;
int
len
=
0
;
char
*
tmp
,
*
tok
;
switch
(
c
)
{
case
'c'
:
count
=
strtoul
(
optarg
,
NULL
,
0
);
break
;
case
'd'
:
mode
=
MODE_DUMP
;
break
;
case
'f'
:
req_files
[
num_req_files
++
]
=
strdup
(
optarg
);
case
'c'
:
count
=
strtoul
(
optarg
,
NULL
,
0
);
break
;
case
'd'
:
mode
=
MODE_DUMP
;
break
;
case
'j'
:
mode
=
MODE_JSON
;
break
;
case
'f'
:
req_files
[
num_req_files
++
]
=
strdup
(
optarg
);
break
;
case
'?'
:
case
'h'
:
usage
(
argv
[
0
],
0
);
break
;
case
'i'
:
sscanf
(
optarg
,
"%u"
,
&
interval
);
break
;
case
'k'
:
tmp
=
strdup
(
optarg
);
if
(
!
tmp
)
break
;
case
'?'
:
case
'h'
:
usage
(
argv
[
0
],
0
);
break
;
case
'i'
:
sscanf
(
optarg
,
"%u"
,
&
interval
);
break
;
case
'k'
:
tmp
=
strdup
(
optarg
);
if
(
!
tmp
)
for
(
tok
=
strtok
(
tmp
,
","
);
tok
;
tok
=
strtok
(
NULL
,
","
))
{
if
(
fp
.
num
>=
MAX_FIELDS
)
{
fprintf
(
stderr
,
"WARN: too many keys"
" requested: (%d max)
\n
"
,
MAX_FIELDS
);
break
;
for
(
tok
=
strtok
(
tmp
,
","
);
tok
;
tok
=
strtok
(
NULL
,
","
))
{
if
(
fp
.
num
>=
MAX_FIELDS
)
{
fprintf
(
stderr
,
"WARN: too many keys"
" requested: (%d max)
\n
"
,
MAX_FIELDS
);
break
;
}
fp
.
params
[
fp
.
num
++
].
name
=
tok
;
}
fp
.
params
[
fp
.
num
++
].
name
=
tok
;
}
break
;
case
's'
:
sscanf
(
optarg
,
"%u"
,
&
hdr
);
break
;
case
'w'
:
tmp
=
strdup
(
optarg
);
if
(
!
tmp
)
break
;
case
's'
:
sscanf
(
optarg
,
"%u"
,
&
hdr
);
break
;
case
'w'
:
tmp
=
strdup
(
optarg
);
if
(
!
tmp
)
break
;
i
=
0
;
for
(
tok
=
strtok
(
tmp
,
","
);
tok
;
tok
=
strtok
(
NULL
,
","
))
{
len
=
strtoul
(
tok
,
NULL
,
0
);
if
(
len
>
FIELD_WIDTH_MAX
)
len
=
FIELD_WIDTH_MAX
;
i
=
0
;
for
(
tok
=
strtok
(
tmp
,
","
);
tok
;
tok
=
strtok
(
NULL
,
","
))
{
len
=
strtoul
(
tok
,
NULL
,
0
);
if
(
len
>
FIELD_WIDTH_MAX
)
len
=
FIELD_WIDTH_MAX
;
fp
.
params
[
i
].
print
.
width
=
len
;
i
++
;
}
if
(
i
==
1
)
{
for
(
i
=
0
;
i
<
MAX_FIELDS
;
i
++
)
fp
.
params
[
i
].
print
.
width
=
len
;
i
++
;
}
if
(
i
==
1
)
{
for
(
i
=
0
;
i
<
MAX_FIELDS
;
i
++
)
fp
.
params
[
i
].
print
.
width
=
len
;
}
break
;
default:
usage
(
argv
[
0
],
1
);
break
;
}
break
;
default:
usage
(
argv
[
0
],
1
);
break
;
}
}
...
...
@@ -319,13 +350,12 @@ int main(int argc, char **argv)
(
const
char
**
)
req_files
);
switch
(
mode
)
{
int
i
;
struct
table_hdr
*
header
;
case
MODE_DUMP
:
lnstat_dump
(
stderr
,
lnstat_files
);
break
;
case
MODE_NORMAL
:
case
MODE_NORMAL
:
case
MODE_JSON
:
if
(
!
map_field_params
(
lnstat_files
,
&
fp
,
interval
))
exit
(
1
);
...
...
@@ -334,16 +364,23 @@ int main(int argc, char **argv)
exit
(
1
);
if
(
interval
<
1
)
interval
=
1
;
interval
=
1
;
for
(
i
=
0
;
i
<
count
;
i
++
)
{
if
((
hdr
>
1
&&
(
!
(
i
%
20
)))
||
(
hdr
==
1
&&
i
==
0
))
print_hdr
(
stdout
,
header
);
lnstat_update
(
lnstat_files
);
print_line
(
stdout
,
lnstat_files
,
&
fp
);
if
(
mode
==
MODE_JSON
)
print_json
(
stdout
,
lnstat_files
,
&
fp
);
else
{
if
((
hdr
>
1
&&
(
!
(
i
%
20
)))
||
(
hdr
==
1
&&
i
==
0
))
print_hdr
(
stdout
,
header
);
print_line
(
stdout
,
lnstat_files
,
&
fp
);
}
fflush
(
stdout
);
sleep
(
interval
);
if
(
i
<
count
-
1
)
sleep
(
interval
);
}
break
;
}
return
1
;
...
...
misc/nstat.c
View file @
f1f1aeb2
...
...
@@ -26,6 +26,7 @@
#include <sys/stat.h>
#include <signal.h>
#include <math.h>
#include <getopt.h>
#include <SNAPSHOT.h>
...
...
@@ -33,6 +34,7 @@ int dump_zeros = 0;
int
reset_history
=
0
;
int
ignore_history
=
0
;
int
no_output
=
0
;
int
json_output
=
0
;
int
no_update
=
0
;
int
scan_interval
=
0
;
int
time_constant
=
0
;
...
...
@@ -255,11 +257,18 @@ static void load_netstat(void)
}
}
static
void
dump_kern_db
(
FILE
*
fp
,
int
to_hist
)
{
struct
nstat_ent
*
n
,
*
h
;
const
char
*
eol
=
"
\n
"
;
h
=
hist_db
;
fprintf
(
fp
,
"#%s
\n
"
,
info_source
);
if
(
json_output
)
fprintf
(
fp
,
"{
\"
%s
\"
:{"
,
info_source
);
else
fprintf
(
fp
,
"#%s
\n
"
,
info_source
);
for
(
n
=
kern_db
;
n
;
n
=
n
->
next
)
{
unsigned
long
long
val
=
n
->
val
;
if
(
!
dump_zeros
&&
!
val
&&
!
n
->
rate
)
...
...
@@ -276,15 +285,29 @@ static void dump_kern_db(FILE *fp, int to_hist)
}
}
}
fprintf
(
fp
,
"%-32s%-16llu%6.1f
\n
"
,
n
->
id
,
val
,
n
->
rate
);
if
(
json_output
)
{
fprintf
(
fp
,
"%s
\"
%s
\"
:%llu"
,
eol
,
n
->
id
,
val
);
eol
=
",
\n
"
;
}
else
fprintf
(
fp
,
"%-32s%-16llu%6.1f
\n
"
,
n
->
id
,
val
,
n
->
rate
);
}
if
(
json_output
)
fprintf
(
fp
,
"
\n
} }
\n
"
);
}
static
void
dump_incr_db
(
FILE
*
fp
)
{
struct
nstat_ent
*
n
,
*
h
;
const
char
*
eol
=
"
\n
"
;
h
=
hist_db
;
fprintf
(
fp
,
"#%s
\n
"
,
info_source
);
if
(
json_output
)
fprintf
(
fp
,
"{
\"
%s
\"
:{"
,
info_source
);
else
fprintf
(
fp
,
"#%s
\n
"
,
info_source
);
for
(
n
=
kern_db
;
n
;
n
=
n
->
next
)
{
int
ovfl
=
0
;
unsigned
long
long
val
=
n
->
val
;
...
...
@@ -304,9 +327,17 @@ static void dump_incr_db(FILE *fp)
continue
;
if
(
!
match
(
n
->
id
))
continue
;
fprintf
(
fp
,
"%-32s%-16llu%6.1f%s
\n
"
,
n
->
id
,
val
,
n
->
rate
,
ovfl
?
" (overflow)"
:
""
);
if
(
json_output
)
{
fprintf
(
fp
,
"%s
\"
%s
\"
:%llu"
,
eol
,
n
->
id
,
val
);
eol
=
",
\n
"
;
}
else
fprintf
(
fp
,
"%-32s%-16llu%6.1f%s
\n
"
,
n
->
id
,
val
,
n
->
rate
,
ovfl
?
" (overflow)"
:
""
);
}
if
(
json_output
)
fprintf
(
fp
,
"
\n
} }
\n
"
);
}
static
int
children
;
...
...
@@ -437,11 +468,33 @@ static void usage(void) __attribute__((noreturn));
static
void
usage
(
void
)
{
fprintf
(
stderr
,
"Usage: nstat [ -h?vVzrnasd:t: ] [ PATTERN [ PATTERN ] ]
\n
"
);
"Usage: nstat [OPTION] [ PATTERN [ PATTERN ] ]
\n
"
" -h, --help this message
\n
"
" -a, --ignore ignore history
\n
"
" -d, --scan=SECS sample every statistics every SECS
\n
"
" -j, --json format output in JSON
\n
"
" -n, --nooutput do history only
\n
"
" -r, --reset reset history
\n
"
" -s, --noupdate don
\'
t update history
\n
"
" -t, --interval=SECS report average over the last SECS
\n
"
" -V, --version output version information
\n
"
" -z, --zeros show entries with zero activity
\n
"
);
exit
(
-
1
);
}
static
const
struct
option
longopts
[]
=
{
{
"help"
,
0
,
0
,
'h'
},
{
"ignore"
,
0
,
0
,
'a'
},
{
"scan"
,
1
,
0
,
'd'
},
{
"nooutput"
,
0
,
0
,
'n'
},
{
"json"
,
0
,
0
,
'j'
},
{
"reset"
,
0
,
0
,
'r'
},
{
"noupdate"
,
0
,
0
,
's'
},
{
"interval"
,
1
,
0
,
't'
},
{
"version"
,
0
,
0
,
'V'
},
{
"zeros"
,
0
,
0
,
'z'
},
{
0
}
};
int
main
(
int
argc
,
char
*
argv
[])
{
...
...
@@ -451,7 +504,8 @@ int main(int argc, char *argv[])
int
ch
;
int
fd
;
while
((
ch
=
getopt
(
argc
,
argv
,
"h?vVzrnasd:t:"
))
!=
EOF
)
{
while
((
ch
=
getopt_long
(
argc
,
argv
,
"h?vVzrnasd:t:j"
,
longopts
,
NULL
))
!=
EOF
)
{
switch
(
ch
)
{
case
'z'
:
dump_zeros
=
1
;
...
...
@@ -478,6 +532,9 @@ int main(int argc, char *argv[])
exit
(
-
1
);
}
break
;
case
'j'
:
json_output
=
1
;
break
;
case
'v'
:
case
'V'
:
printf
(
"nstat utility, iproute2-ss%s
\n
"
,
SNAPSHOT
);
...
...
@@ -614,8 +671,10 @@ int main(int argc, char *argv[])
if
(
!
no_update
)
{
ftruncate
(
fileno
(
hist_fp
),
0
);
rewind
(
hist_fp
);
json_output
=
0
;
dump_kern_db
(
hist_fp
,
1
);
f
flush
(
hist_fp
);
f
close
(
hist_fp
);
}
exit
(
0
);
}
tc/Makefile
View file @
f1f1aeb2
...
...
@@ -38,6 +38,7 @@ TCMODULES += m_nat.o
TCMODULES
+=
m_pedit.o
TCMODULES
+=
m_skbedit.o
TCMODULES
+=
m_csum.o
TCMODULES
+=
m_simple.o
TCMODULES
+=
p_ip.o
TCMODULES
+=
p_icmp.o
TCMODULES
+=
p_tcp.o
...
...
tc/m_nat.c
View file @
f1f1aeb2
...
...
@@ -146,7 +146,7 @@ parse_nat(struct action_util *a, int *argc_p, char ***argv_p, int tca_id, struct
if
(
matches
(
*
argv
,
"index"
)
==
0
)
{
NEXT_ARG
();
if
(
get_u32
(
&
sel
.
index
,
*
argv
,
10
))
{
fprintf
(
stderr
,
"
Pedi
t: Illegal
\"
index
\"\n
"
);
fprintf
(
stderr
,
"
Na
t: Illegal
\"
index
\"\n
"
);
return
-
1
;
}
argc
--
;
...
...
tc/m_simple.c
0 → 100644
View file @
f1f1aeb2
/*
* m_simple.c simple action
*
* This program is free software; you can distribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
* Authors: J Hadi Salim <jhs@mojatatu.com>
*
* Pedagogical example. Adds a string that will be printed everytime
* the simple instance is hit.
* Use this as a skeleton action and keep modifying it to meet your needs.
* Look at linux/tc_act/tc_defact.h for the different components ids and
* definitions used in this actions
*
* example use, yell "Incoming ICMP!" every time you see an incoming ICMP on
* eth0. Steps are:
* 1) Add an ingress qdisc point to eth0
* 2) Start a chain on ingress of eth0 that first matches ICMP then invokes
* the simple action to shout.
* 3) display stats and show that no packet has been seen by the action
* 4) Send one ping packet to google (expect to receive a response back)
* 5) grep the logs to see the logged message
* 6) display stats again and observe increment by 1
*
hadi@noma1:$ tc qdisc add dev eth0 ingress
hadi@noma1:$tc filter add dev eth0 parent ffff: protocol ip prio 5 \
u32 match ip protocol 1 0xff flowid 1:1 action simple "Incoming ICMP"
hadi@noma1:$ sudo tc -s filter ls dev eth0 parent ffff:
filter protocol ip pref 5 u32
filter protocol ip pref 5 u32 fh 800: ht divisor 1
filter protocol ip pref 5 u32 fh 800::800 order 2048 key ht 800 bkt 0 flowid 1:1
match 00010000/00ff0000 at 8
action order 1: Simple <Incoming ICMP>
index 4 ref 1 bind 1 installed 29 sec used 29 sec
Action statistics:
Sent 0 bytes 0 pkt (dropped 0, overlimits 0 requeues 0)
backlog 0b 0p requeues 0
hadi@noma1$ ping -c 1 www.google.ca
PING www.google.ca (74.125.225.120) 56(84) bytes of data.
64 bytes from ord08s08-in-f24.1e100.net (74.125.225.120): icmp_req=1 ttl=53 time=31.3 ms
--- www.google.ca ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 31.316/31.316/31.316/0.000 ms
hadi@noma1$ dmesg | grep simple
[135354.473951] simple: Incoming ICMP_1
hadi@noma1$ sudo tc/tc -s filter ls dev eth0 parent ffff:
filter protocol ip pref 5 u32
filter protocol ip pref 5 u32 fh 800: ht divisor 1
filter protocol ip pref 5 u32 fh 800::800 order 2048 key ht 800 bkt 0 flowid 1:1
match 00010000/00ff0000 at 8
action order 1: Simple <Incoming ICMP>
index 4 ref 1 bind 1 installed 206 sec used 67 sec
Action statistics:
Sent 84 bytes 1 pkt (dropped 0, overlimits 0 requeues 0)
backlog 0b 0p requeues 0
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <syslog.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include "utils.h"
#include "tc_util.h"
#include <linux/tc_act/tc_defact.h>
#ifndef SIMP_MAX_DATA
#define SIMP_MAX_DATA 32
#endif
static
void
explain
(
void
)
{
fprintf
(
stderr
,
"Usage: ... simple STRING
\n
"
"STRING being an arbitrary string
\n
"
"example:
\"
simple blah
\"\n
"
);
}
static
void
usage
(
void
)
{
explain
();
exit
(
-
1
);
}
static
int
parse_simple
(
struct
action_util
*
a
,
int
*
argc_p
,
char
***
argv_p
,
int
tca_id
,
struct
nlmsghdr
*
n
)
{
struct
tc_defact
sel
=
{};
int
argc
=
*
argc_p
;
char
**
argv
=
*
argv_p
;
int
ok
=
0
;
struct
rtattr
*
tail
;
char
*
simpdata
=
NULL
;
while
(
argc
>
0
)
{
if
(
matches
(
*
argv
,
"simple"
)
==
0
)
{
NEXT_ARG
();
simpdata
=
*
argv
;
ok
=
1
;
argc
--
;
argv
++
;
break
;
}
else
if
(
matches
(
*
argv
,
"help"
)
==
0
)
{
usage
();
}
else
{
break
;
}
}
if
(
!
ok
)
{
explain
();
return
-
1
;
}
if
(
argc
)
{
if
(
matches
(
*
argv
,
"index"
)
==
0
)
{
NEXT_ARG
();
if
(
get_u32
(
&
sel
.
index
,
*
argv
,
10
))
{
fprintf
(
stderr
,
"simple: Illegal
\"
index
\"\n
"
);
return
-
1
;
}
argc
--
;
argv
++
;
}
}
if
(
strlen
(
simpdata
)
>
(
SIMP_MAX_DATA
-
1
))
{
fprintf
(
stderr
,
"simple: Illegal string len %ld <%s>
\n
"
,
strlen
(
simpdata
),
simpdata
);
return
-
1
;
}
sel
.
action
=
TC_ACT_PIPE
;
tail
=
NLMSG_TAIL
(
n
);
addattr_l
(
n
,
MAX_MSG
,
tca_id
,
NULL
,
0
);
addattr_l
(
n
,
MAX_MSG
,
TCA_DEF_PARMS
,
&
sel
,
sizeof
(
sel
));
addattr_l
(
n
,
MAX_MSG
,
TCA_DEF_DATA
,
simpdata
,
SIMP_MAX_DATA
);
tail
->
rta_len
=
(
char
*
)
NLMSG_TAIL
(
n
)
-
(
char
*
)
tail
;
*
argc_p
=
argc
;
*
argv_p
=
argv
;
return
0
;
}
static
int
print_simple
(
struct
action_util
*
au
,
FILE
*
f
,
struct
rtattr
*
arg
)
{
struct
tc_defact
*
sel
;
struct
rtattr
*
tb
[
TCA_DEF_MAX
+
1
];
char
*
simpdata
;
if
(
arg
==
NULL
)
return
-
1
;
parse_rtattr_nested
(
tb
,
TCA_DEF_MAX
,
arg
);
if
(
tb
[
TCA_DEF_PARMS
]
==
NULL
)
{
fprintf
(
f
,
"[NULL simple parameters]"
);
return
-
1
;
}
sel
=
RTA_DATA
(
tb
[
TCA_DEF_PARMS
]);
if
(
tb
[
TCA_DEF_DATA
]
==
NULL
)
{
fprintf
(
f
,
"[missing simple string]"
);
return
-
1
;
}
simpdata
=
RTA_DATA
(
tb
[
TCA_DEF_DATA
]);
fprintf
(
f
,
"Simple <%s>
\n
"
,
simpdata
);
fprintf
(
f
,
"
\t
index %d ref %d bind %d"
,
sel
->
index
,
sel
->
refcnt
,
sel
->
bindcnt
);
if
(
show_stats
)
{
if
(
tb
[
TCA_DEF_TM
])
{
struct
tcf_t
*
tm
=
RTA_DATA
(
tb
[
TCA_DEF_TM
]);
print_tm
(
f
,
tm
);
fprintf
(
f
,
"
\n
"
);
}
}
return
0
;
}
struct
action_util
simple_action_util
=
{
.
id
=
"simple"
,
.
parse_aopt
=
parse_simple
,
.
print_aopt
=
print_simple
,
};
tc/q_fq.c
View file @
f1f1aeb2
...
...
@@ -53,7 +53,7 @@ static void explain(void)
fprintf
(
stderr
,
"Usage: ... fq [ limit PACKETS ] [ flow_limit PACKETS ]
\n
"
);
fprintf
(
stderr
,
" [ quantum BYTES ] [ initial_quantum BYTES ]
\n
"
);
fprintf
(
stderr
,
" [ maxrate RATE ] [ buckets NUMBER ]
\n
"
);
fprintf
(
stderr
,
" [ [no]pacing ]
\n
"
);
fprintf
(
stderr
,
" [ [no]pacing ]
\n
"
);
}
static
unsigned
int
ilog2
(
unsigned
int
val
)
...
...
tc/q_htb.c
View file @
f1f1aeb2
...
...
@@ -31,9 +31,11 @@
static
void
explain
(
void
)
{
fprintf
(
stderr
,
"Usage: ... qdisc add ... htb [default N] [r2q N]
\n
"
" [direct_qlen P]
\n
"
" default minor id of class to which unclassified packets are sent {0}
\n
"
" r2q DRR quantums are computed as rate in Bps/r2q {10}
\n
"
" debug string of 16 numbers each 0-3 {0}
\n\n
"
" direct_qlen Limit of the direct queue {in packets}
\n
"
"... class add ... htb rate R1 [burst B1] [mpu B] [overhead O]
\n
"
" [prio P] [slot S] [pslot PS]
\n
"
" [ceil R2] [cburst B2] [mtu MTU] [quantum Q]
\n
"
...
...
@@ -108,6 +110,7 @@ static int htb_parse_class_opt(struct qdisc_util *qu, int argc, char **argv, str
unsigned
mtu
;
unsigned
short
mpu
=
0
;
unsigned
short
overhead
=
0
;
unsigned
int
direct_qlen
=
~
0U
;
unsigned
int
linklayer
=
LINKLAYER_ETHERNET
;
/* Assume ethernet */
struct
rtattr
*
tail
;
...
...
@@ -125,6 +128,11 @@ static int htb_parse_class_opt(struct qdisc_util *qu, int argc, char **argv, str
if
(
get_u32
(
&
mtu
,
*
argv
,
10
))
{
explain1
(
"mtu"
);
return
-
1
;
}
}
else
if
(
matches
(
*
argv
,
"direct_qlen"
)
==
0
)
{
NEXT_ARG
();
if
(
get_u32
(
&
direct_qlen
,
*
argv
,
10
))
{
explain1
(
"direct_qlen"
);
return
-
1
;
}
}
else
if
(
matches
(
*
argv
,
"mpu"
)
==
0
)
{
NEXT_ARG
();
if
(
get_u16
(
&
mpu
,
*
argv
,
10
))
{
...
...
@@ -230,6 +238,9 @@ static int htb_parse_class_opt(struct qdisc_util *qu, int argc, char **argv, str
opt
.
cbuffer
=
tc_calc_xmittime
(
opt
.
ceil
.
rate
,
cbuffer
);
tail
=
NLMSG_TAIL
(
n
);
if
(
direct_qlen
!=
~
0U
)
addattr_l
(
n
,
1024
,
TCA_HTB_DIRECT_QLEN
,
&
direct_qlen
,
sizeof
(
direct_qlen
));
addattr_l
(
n
,
1024
,
TCA_OPTIONS
,
NULL
,
0
);
addattr_l
(
n
,
2024
,
TCA_HTB_PARMS
,
&
opt
,
sizeof
(
opt
));
addattr_l
(
n
,
3024
,
TCA_HTB_RTAB
,
rtab
,
1024
);
...
...
@@ -240,7 +251,7 @@ static int htb_parse_class_opt(struct qdisc_util *qu, int argc, char **argv, str
static
int
htb_print_opt
(
struct
qdisc_util
*
qu
,
FILE
*
f
,
struct
rtattr
*
opt
)
{
struct
rtattr
*
tb
[
TCA_HTB_
RTAB
+
1
];
struct
rtattr
*
tb
[
TCA_HTB_
MAX
+
1
];
struct
tc_htb_opt
*
hopt
;
struct
tc_htb_glob
*
gopt
;
double
buffer
,
cbuffer
;
...
...
@@ -253,7 +264,7 @@ static int htb_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt)
if
(
opt
==
NULL
)
return
0
;
parse_rtattr_nested
(
tb
,
TCA_HTB_
RTAB
,
opt
);
parse_rtattr_nested
(
tb
,
TCA_HTB_
MAX
,
opt
);
if
(
tb
[
TCA_HTB_PARMS
])
{
hopt
=
RTA_DATA
(
tb
[
TCA_HTB_PARMS
]);
...
...
@@ -302,6 +313,12 @@ static int htb_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt)
if
(
show_details
)
fprintf
(
f
,
" ver %d.%d"
,
gopt
->
version
>>
16
,
gopt
->
version
&
0xffff
);
}
if
(
tb
[
TCA_HTB_DIRECT_QLEN
]
&&
RTA_PAYLOAD
(
tb
[
TCA_HTB_DIRECT_QLEN
])
>=
sizeof
(
__u32
))
{
__u32
direct_qlen
=
rta_getattr_u32
(
tb
[
TCA_HTB_DIRECT_QLEN
]);
fprintf
(
f
,
" direct_qlen %u"
,
direct_qlen
);
}
return
0
;
}
...
...
@@ -329,13 +346,3 @@ struct qdisc_util htb_qdisc_util = {
.
parse_copt
=
htb_parse_class_opt
,
.
print_copt
=
htb_print_opt
,
};
/* for testing of old one */
struct
qdisc_util
htb2_qdisc_util
=
{
.
id
=
"htb2"
,
.
parse_qopt
=
htb_parse_opt
,
.
print_qopt
=
htb_print_opt
,
.
print_xstats
=
htb_print_xstats
,
.
parse_copt
=
htb_parse_class_opt
,
.
print_copt
=
htb_print_opt
,
};
tc/tc_class.c
View file @
f1f1aeb2
...
...
@@ -241,6 +241,9 @@ static int tc_class_list(int argc, char **argv)
t
.
tcm_family
=
AF_UNSPEC
;
memset
(
d
,
0
,
sizeof
(
d
));
filter_qdisc
=
0
;
filter_classid
=
0
;
while
(
argc
>
0
)
{
if
(
strcmp
(
*
argv
,
"dev"
)
==
0
)
{
NEXT_ARG
();
...
...
tc/tc_qdisc.c
View file @
f1f1aeb2
...
...
@@ -137,15 +137,16 @@ static int tc_qdisc_modify(int cmd, unsigned flags, int argc, char **argv)
if
(
est
.
ewma_log
)
addattr_l
(
&
req
.
n
,
sizeof
(
req
),
TCA_RATE
,
&
est
,
sizeof
(
est
));
if
(
argc
)
{
if
(
q
)
{
if
(
!
q
->
parse_qopt
)
{
fprintf
(
stderr
,
"qdisc '%s' does not support option parsing
\n
"
,
k
);
return
-
1
;
}
if
(
q
)
{
if
(
q
->
parse_qopt
)
{
if
(
q
->
parse_qopt
(
q
,
argc
,
argv
,
&
req
.
n
))
return
1
;
}
else
{
}
else
if
(
argc
)
{
fprintf
(
stderr
,
"qdisc '%s' does not support option parsing
\n
"
,
k
);
return
-
1
;
}
}
else
{
if
(
argc
)
{
if
(
matches
(
*
argv
,
"help"
)
==
0
)
usage
();
...
...
tc/tc_util.c
View file @
f1f1aeb2
...
...
@@ -171,20 +171,24 @@ int get_rate(unsigned *rate, const char *str)
return
0
;
}
void
print_rate
(
char
*
buf
,
int
len
,
__u
32
rate
)
void
print_rate
(
char
*
buf
,
int
len
,
__u
64
rate
)
{
double
tmp
=
(
double
)
rate
*
8
;
extern
int
use_iec
;
if
(
use_iec
)
{
if
(
tmp
>=
1000
.
0
*
1024
.
0
*
1024
.
0
)
if
(
tmp
>=
1000
.
0
*
1024
.
0
*
1024
.
0
*
1024
.
0
)
snprintf
(
buf
,
len
,
"%.0fGibit"
,
tmp
/
(
1024
.
0
*
1024
.
0
*
1024
.
0
));
else
if
(
tmp
>=
1000
.
0
*
1024
.
0
*
1024
.
0
)
snprintf
(
buf
,
len
,
"%.0fMibit"
,
tmp
/
(
1024
.
0
*
1024
.
0
));
else
if
(
tmp
>=
1000
.
0
*
1024
)
snprintf
(
buf
,
len
,
"%.0fKibit"
,
tmp
/
1024
);
else
snprintf
(
buf
,
len
,
"%.0fbit"
,
tmp
);
}
else
{
if
(
tmp
>=
1000
.
0
*
1000000
.
0
)
if
(
tmp
>=
1000
.
0
*
1000000000
.
0
)
snprintf
(
buf
,
len
,
"%.0fGbit"
,
tmp
/
1000000000
.
0
);
else
if
(
tmp
>=
1000
.
0
*
1000000
.
0
)
snprintf
(
buf
,
len
,
"%.0fMbit"
,
tmp
/
1000000
.
0
);
else
if
(
tmp
>=
1000
.
0
*
1000
.
0
)
snprintf
(
buf
,
len
,
"%.0fKbit"
,
tmp
/
1000
.
0
);
...
...
@@ -193,7 +197,7 @@ void print_rate(char *buf, int len, __u32 rate)
}
}
char
*
sprint_rate
(
__u
32
rate
,
char
*
buf
)
char
*
sprint_rate
(
__u
64
rate
,
char
*
buf
)
{
print_rate
(
buf
,
SPRINT_BSIZE
-
1
,
rate
);
return
buf
;
...
...
@@ -460,9 +464,19 @@ void print_tcstats2_attr(FILE *fp, struct rtattr *rta, char *prefix, struct rtat
q
.
drops
,
q
.
overlimits
,
q
.
requeues
);
}
if
(
tbs
[
TCA_STATS_RATE_EST
])
{
if
(
tbs
[
TCA_STATS_RATE_EST64
])
{
struct
gnet_stats_rate_est64
re
=
{
0
};
memcpy
(
&
re
,
RTA_DATA
(
tbs
[
TCA_STATS_RATE_EST64
]),
MIN
(
RTA_PAYLOAD
(
tbs
[
TCA_STATS_RATE_EST64
]),
sizeof
(
re
)));
fprintf
(
fp
,
"
\n
%srate %s %llupps "
,
prefix
,
sprint_rate
(
re
.
bps
,
b1
),
re
.
pps
);
}
else
if
(
tbs
[
TCA_STATS_RATE_EST
])
{
struct
gnet_stats_rate_est
re
=
{
0
};
memcpy
(
&
re
,
RTA_DATA
(
tbs
[
TCA_STATS_RATE_EST
]),
MIN
(
RTA_PAYLOAD
(
tbs
[
TCA_STATS_RATE_EST
]),
sizeof
(
re
)));
memcpy
(
&
re
,
RTA_DATA
(
tbs
[
TCA_STATS_RATE_EST
]),
MIN
(
RTA_PAYLOAD
(
tbs
[
TCA_STATS_RATE_EST
]),
sizeof
(
re
)));
fprintf
(
fp
,
"
\n
%srate %s %upps "
,
prefix
,
sprint_rate
(
re
.
bps
,
b1
),
re
.
pps
);
}
...
...
tc/tc_util.h
View file @
f1f1aeb2
...
...
@@ -63,12 +63,12 @@ extern int get_size_and_cell(unsigned *size, int *cell_log, char *str);
extern
int
get_time
(
unsigned
*
time
,
const
char
*
str
);
extern
int
get_linklayer
(
unsigned
*
val
,
const
char
*
arg
);
extern
void
print_rate
(
char
*
buf
,
int
len
,
__u
32
rate
);
extern
void
print_rate
(
char
*
buf
,
int
len
,
__u
64
rate
);
extern
void
print_size
(
char
*
buf
,
int
len
,
__u32
size
);
extern
void
print_qdisc_handle
(
char
*
buf
,
int
len
,
__u32
h
);
extern
void
print_time
(
char
*
buf
,
int
len
,
__u32
time
);
extern
void
print_linklayer
(
char
*
buf
,
int
len
,
unsigned
linklayer
);
extern
char
*
sprint_rate
(
__u
32
rate
,
char
*
buf
);
extern
char
*
sprint_rate
(
__u
64
rate
,
char
*
buf
);
extern
char
*
sprint_size
(
__u32
size
,
char
*
buf
);
extern
char
*
sprint_qdisc_handle
(
__u32
h
,
char
*
buf
);
extern
char
*
sprint_tc_classid
(
__u32
h
,
char
*
buf
);
...
...
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