Commit a37c7472 authored by Stephen Hemminger's avatar Stephen Hemminger

Merge branch 'net-next-for-3.13'

parents 514cdfb4 8c452755
......@@ -18,6 +18,9 @@ struct ifaddrmsg {
* It makes no difference for normally configured broadcast interfaces,
* but for point-to-point IFA_ADDRESS is DESTINATION address,
* local address is supplied in IFA_LOCAL attribute.
*
* IFA_FLAGS is a u32 attribute that extends the u8 field ifa_flags.
* If present, the value from struct ifaddrmsg will be ignored.
*/
enum {
IFA_UNSPEC,
......@@ -28,6 +31,7 @@ enum {
IFA_ANYCAST,
IFA_CACHEINFO,
IFA_MULTICAST,
IFA_FLAGS,
__IFA_MAX,
};
......@@ -44,6 +48,8 @@ enum {
#define IFA_F_DEPRECATED 0x20
#define IFA_F_TENTATIVE 0x40
#define IFA_F_PERMANENT 0x80
#define IFA_F_MANAGETEMPADDR 0x100
#define IFA_F_NOPREFIXROUTE 0x200
struct ifa_cacheinfo {
__u32 ifa_prefered;
......
......@@ -94,6 +94,7 @@
#define ARPHRD_CAIF 822 /* CAIF media type */
#define ARPHRD_IP6GRE 823 /* GRE over IPv6 */
#define ARPHRD_NETLINK 824 /* Netlink header */
#define ARPHRD_6LOWPAN 825 /* IPv6 over LoWPAN */
#define ARPHRD_VOID 0xFFFF /* Void type, nothing is known */
#define ARPHRD_NONE 0xFFFE /* zero header length */
......
......@@ -144,6 +144,7 @@ enum {
IFLA_NUM_RX_QUEUES,
IFLA_CARRIER,
IFLA_PHYS_PORT_ID,
IFLA_SLAVE,
__IFLA_MAX
};
......@@ -329,11 +330,55 @@ enum {
IFLA_BOND_UNSPEC,
IFLA_BOND_MODE,
IFLA_BOND_ACTIVE_SLAVE,
IFLA_BOND_MIIMON,
IFLA_BOND_UPDELAY,
IFLA_BOND_DOWNDELAY,
IFLA_BOND_USE_CARRIER,
IFLA_BOND_ARP_INTERVAL,
IFLA_BOND_ARP_IP_TARGET,
IFLA_BOND_ARP_VALIDATE,
IFLA_BOND_ARP_ALL_TARGETS,
IFLA_BOND_PRIMARY,
IFLA_BOND_PRIMARY_RESELECT,
IFLA_BOND_FAIL_OVER_MAC,
IFLA_BOND_XMIT_HASH_POLICY,
IFLA_BOND_RESEND_IGMP,
IFLA_BOND_NUM_PEER_NOTIF,
IFLA_BOND_ALL_SLAVES_ACTIVE,
IFLA_BOND_MIN_LINKS,
IFLA_BOND_LP_INTERVAL,
IFLA_BOND_PACKETS_PER_SLAVE,
IFLA_BOND_AD_LACP_RATE,
IFLA_BOND_AD_SELECT,
IFLA_BOND_AD_INFO,
__IFLA_BOND_MAX,
};
#define IFLA_BOND_MAX (__IFLA_BOND_MAX - 1)
enum {
IFLA_BOND_AD_INFO_AGGREGATOR,
IFLA_BOND_AD_INFO_NUM_PORTS,
IFLA_BOND_AD_INFO_ACTOR_KEY,
IFLA_BOND_AD_INFO_PARTNER_KEY,
IFLA_BOND_AD_INFO_PARTNER_MAC,
__IFLA_BOND_AD_INFO_MAX,
};
#define IFLA_BOND_AD_INFO_MAX (__IFLA_BOND_AD_INFO_MAX - 1)
enum {
IFLA_SLAVE_STATE,
IFLA_SLAVE_MII_STATUS,
IFLA_SLAVE_LINK_FAILURE_COUNT,
IFLA_SLAVE_PERM_HWADDR,
IFLA_SLAVE_QUEUE_ID,
IFLA_SLAVE_AD_AGGREGATOR_ID,
__IFLA_SLAVE_MAX,
};
#define IFLA_SLAVE_MAX (__IFLA_SLAVE_MAX - 1)
/* SR-IOV virtual function management section */
enum {
......
......@@ -14,6 +14,7 @@ enum {
NETCONFA_FORWARDING,
NETCONFA_RP_FILTER,
NETCONFA_MC_FORWARDING,
NETCONFA_PROXY_NEIGH,
__NETCONFA_MAX
};
#define NETCONFA_MAX (__NETCONFA_MAX - 1)
......
......@@ -51,6 +51,7 @@ enum nf_inet_hooks {
enum {
NFPROTO_UNSPEC = 0,
NFPROTO_INET = 1,
NFPROTO_IPV4 = 2,
NFPROTO_ARP = 3,
NFPROTO_BRIDGE = 7,
......
......@@ -173,6 +173,8 @@ enum {
TCA_TBF_PTAB,
TCA_TBF_RATE64,
TCA_TBF_PRATE64,
TCA_TBF_BURST,
TCA_TBF_PBURST,
__TCA_TBF_MAX,
};
......@@ -523,6 +525,7 @@ enum {
TCA_NETEM_LOSS,
TCA_NETEM_RATE,
TCA_NETEM_ECN,
TCA_NETEM_RATE64,
__TCA_NETEM_MAX,
};
......@@ -790,4 +793,54 @@ struct tc_fq_qd_stats {
__u32 throttled_flows;
__u32 pad;
};
/* Heavy-Hitter Filter */
enum {
TCA_HHF_UNSPEC,
TCA_HHF_BACKLOG_LIMIT,
TCA_HHF_QUANTUM,
TCA_HHF_HH_FLOWS_LIMIT,
TCA_HHF_RESET_TIMEOUT,
TCA_HHF_ADMIT_BYTES,
TCA_HHF_EVICT_TIMEOUT,
TCA_HHF_NON_HH_WEIGHT,
__TCA_HHF_MAX
};
#define TCA_HHF_MAX (__TCA_HHF_MAX - 1)
struct tc_hhf_xstats {
__u32 drop_overlimit; /* number of times max qdisc packet limit
* was hit
*/
__u32 hh_overlimit; /* number of times max heavy-hitters was hit */
__u32 hh_tot_count; /* number of captured heavy-hitters so far */
__u32 hh_cur_count; /* number of current heavy-hitters */
};
/* PIE */
enum {
TCA_PIE_UNSPEC,
TCA_PIE_TARGET,
TCA_PIE_LIMIT,
TCA_PIE_TUPDATE,
TCA_PIE_ALPHA,
TCA_PIE_BETA,
TCA_PIE_ECN,
TCA_PIE_BYTEMODE,
__TCA_PIE_MAX
};
#define TCA_PIE_MAX (__TCA_PIE_MAX - 1)
struct tc_pie_xstats {
__u32 prob; /* current probability */
__u32 delay; /* current delay in ms */
__u32 avg_dq_rate; /* current average dq_rate in bits/pie_time */
__u32 packets_in; /* total number of packets enqueued */
__u32 dropped; /* packets dropped due to pie_action */
__u32 overlimit; /* dropped due to lack of space in queue */
__u32 maxq; /* maximum queue size */
__u32 ecn_mark; /* packets marked with ecn*/
};
#endif
......@@ -4,6 +4,7 @@
#include <linux/pkt_cls.h>
#define TCA_ACT_IPT 6
#define TCA_ACT_XT 10
enum {
TCA_IPT_UNSPEC,
......
......@@ -35,6 +35,8 @@ enum {
TCP_METRICS_ATTR_FOPEN_SYN_DROPS, /* u16, count of drops */
TCP_METRICS_ATTR_FOPEN_SYN_DROP_TS, /* msecs age */
TCP_METRICS_ATTR_FOPEN_COOKIE, /* binary */
TCP_METRICS_ATTR_SADDR_IPV4, /* u32 */
TCP_METRICS_ATTR_SADDR_IPV6, /* binary */
__TCP_METRICS_ATTR_MAX,
};
......
......@@ -82,7 +82,7 @@ static void usage(void)
fprintf(stderr, " tentative | deprecated | dadfailed | temporary |\n");
fprintf(stderr, " CONFFLAG-LIST ]\n");
fprintf(stderr, "CONFFLAG-LIST := [ CONFFLAG-LIST ] CONFFLAG\n");
fprintf(stderr, "CONFFLAG := [ home | nodad ]\n");
fprintf(stderr, "CONFFLAG := [ home | nodad | mngtmpaddr | noprefixroute ]\n");
fprintf(stderr, "LIFETIME := [ valid_lft LFT ] [ preferred_lft LFT ]\n");
fprintf(stderr, "LFT := forever | SECONDS\n");
......@@ -541,6 +541,13 @@ static int set_lifetime(unsigned int *lifetime, char *argv)
return 0;
}
static unsigned int get_ifa_flags(struct ifaddrmsg *ifa,
struct rtattr *ifa_flags_attr)
{
return ifa_flags_attr ? rta_getattr_u32(ifa_flags_attr) :
ifa->ifa_flags;
}
int print_addrinfo(const struct sockaddr_nl *who, struct nlmsghdr *n,
void *arg)
{
......@@ -567,6 +574,8 @@ int print_addrinfo(const struct sockaddr_nl *who, struct nlmsghdr *n,
parse_rtattr(rta_tb, IFA_MAX, IFA_RTA(ifa), n->nlmsg_len - NLMSG_LENGTH(sizeof(*ifa)));
ifa_flags = get_ifa_flags(ifa, rta_tb[IFA_FLAGS]);
if (!rta_tb[IFA_LOCAL])
rta_tb[IFA_LOCAL] = rta_tb[IFA_ADDRESS];
if (!rta_tb[IFA_ADDRESS])
......@@ -576,7 +585,7 @@ int print_addrinfo(const struct sockaddr_nl *who, struct nlmsghdr *n,
return 0;
if ((filter.scope^ifa->ifa_scope)&filter.scopemask)
return 0;
if ((filter.flags^ifa->ifa_flags)&filter.flagmask)
if ((filter.flags ^ ifa_flags) & filter.flagmask)
return 0;
if (filter.label) {
SPRINT_BUF(b1);
......@@ -670,36 +679,43 @@ int print_addrinfo(const struct sockaddr_nl *who, struct nlmsghdr *n,
abuf, sizeof(abuf)));
}
fprintf(fp, "scope %s ", rtnl_rtscope_n2a(ifa->ifa_scope, b1, sizeof(b1)));
ifa_flags = ifa->ifa_flags;
if (ifa->ifa_flags&IFA_F_SECONDARY) {
if (ifa_flags & IFA_F_SECONDARY) {
ifa_flags &= ~IFA_F_SECONDARY;
if (ifa->ifa_family == AF_INET6)
fprintf(fp, "temporary ");
else
fprintf(fp, "secondary ");
}
if (ifa->ifa_flags&IFA_F_TENTATIVE) {
if (ifa_flags & IFA_F_TENTATIVE) {
ifa_flags &= ~IFA_F_TENTATIVE;
fprintf(fp, "tentative ");
}
if (ifa->ifa_flags&IFA_F_DEPRECATED) {
if (ifa_flags & IFA_F_DEPRECATED) {
ifa_flags &= ~IFA_F_DEPRECATED;
deprecated = 1;
fprintf(fp, "deprecated ");
}
if (ifa->ifa_flags&IFA_F_HOMEADDRESS) {
if (ifa_flags & IFA_F_HOMEADDRESS) {
ifa_flags &= ~IFA_F_HOMEADDRESS;
fprintf(fp, "home ");
}
if (ifa->ifa_flags&IFA_F_NODAD) {
if (ifa_flags & IFA_F_NODAD) {
ifa_flags &= ~IFA_F_NODAD;
fprintf(fp, "nodad ");
}
if (!(ifa->ifa_flags&IFA_F_PERMANENT)) {
if (ifa_flags & IFA_F_MANAGETEMPADDR) {
ifa_flags &= ~IFA_F_MANAGETEMPADDR;
fprintf(fp, "mngtmpaddr ");
}
if (ifa_flags & IFA_F_NOPREFIXROUTE) {
ifa_flags &= ~IFA_F_NOPREFIXROUTE;
fprintf(fp, "noprefixroute ");
}
if (!(ifa_flags & IFA_F_PERMANENT)) {
fprintf(fp, "dynamic ");
} else
ifa_flags &= ~IFA_F_PERMANENT;
if (ifa->ifa_flags&IFA_F_DADFAILED) {
if (ifa_flags & IFA_F_DADFAILED) {
ifa_flags &= ~IFA_F_DADFAILED;
fprintf(fp, "dadfailed ");
}
......@@ -926,6 +942,8 @@ static void ipaddr_filter(struct nlmsg_chain *linfo, struct nlmsg_chain *ainfo)
for (a = ainfo->head; a; a = a->next) {
struct nlmsghdr *n = &a->h;
struct ifaddrmsg *ifa = NLMSG_DATA(n);
struct rtattr *tb[IFA_MAX + 1];
unsigned int ifa_flags;
if (ifa->ifa_index != ifi->ifi_index)
continue;
......@@ -934,11 +952,13 @@ static void ipaddr_filter(struct nlmsg_chain *linfo, struct nlmsg_chain *ainfo)
continue;
if ((filter.scope^ifa->ifa_scope)&filter.scopemask)
continue;
if ((filter.flags^ifa->ifa_flags)&filter.flagmask)
parse_rtattr(tb, IFA_MAX, IFA_RTA(ifa), IFA_PAYLOAD(n));
ifa_flags = get_ifa_flags(ifa, tb[IFA_FLAGS]);
if ((filter.flags ^ ifa_flags) & filter.flagmask)
continue;
if (filter.pfx.family || filter.label) {
struct rtattr *tb[IFA_MAX+1];
parse_rtattr(tb, IFA_MAX, IFA_RTA(ifa), IFA_PAYLOAD(n));
if (!tb[IFA_LOCAL])
tb[IFA_LOCAL] = tb[IFA_ADDRESS];
......@@ -1114,6 +1134,12 @@ static int ipaddr_list_flush_or_save(int argc, char **argv, int action)
} else if (strcmp(*argv, "nodad") == 0) {
filter.flags |= IFA_F_NODAD;
filter.flagmask |= IFA_F_NODAD;
} else if (strcmp(*argv, "mngtmpaddr") == 0) {
filter.flags |= IFA_F_MANAGETEMPADDR;
filter.flagmask |= IFA_F_MANAGETEMPADDR;
} else if (strcmp(*argv, "noprefixroute") == 0) {
filter.flags |= IFA_F_NOPREFIXROUTE;
filter.flagmask |= IFA_F_NOPREFIXROUTE;
} else if (strcmp(*argv, "dadfailed") == 0) {
filter.flags |= IFA_F_DADFAILED;
filter.flagmask |= IFA_F_DADFAILED;
......@@ -1252,6 +1278,7 @@ static int ipaddr_modify(int cmd, int flags, int argc, char **argv)
__u32 preferred_lft = INFINITY_LIFE_TIME;
__u32 valid_lft = INFINITY_LIFE_TIME;
struct ifa_cacheinfo cinfo;
unsigned int ifa_flags = 0;
memset(&req, 0, sizeof(req));
......@@ -1329,9 +1356,13 @@ static int ipaddr_modify(int cmd, int flags, int argc, char **argv)
if (set_lifetime(&preferred_lft, *argv))
invarg("preferred_lft value", *argv);
} else if (strcmp(*argv, "home") == 0) {
req.ifa.ifa_flags |= IFA_F_HOMEADDRESS;
ifa_flags |= IFA_F_HOMEADDRESS;
} else if (strcmp(*argv, "nodad") == 0) {
req.ifa.ifa_flags |= IFA_F_NODAD;
ifa_flags |= IFA_F_NODAD;
} else if (strcmp(*argv, "mngtmpaddr") == 0) {
ifa_flags |= IFA_F_MANAGETEMPADDR;
} else if (strcmp(*argv, "noprefixroute") == 0) {
ifa_flags |= IFA_F_NOPREFIXROUTE;
} else {
if (strcmp(*argv, "local") == 0) {
NEXT_ARG();
......@@ -1349,6 +1380,9 @@ static int ipaddr_modify(int cmd, int flags, int argc, char **argv)
}
argc--; argv++;
}
req.ifa.ifa_flags = ifa_flags;
addattr32(&req.n, sizeof(req), IFA_FLAGS, ifa_flags);
if (d == NULL) {
fprintf(stderr, "Not enough information: \"dev\" argument is required.\n");
return -1;
......
This diff is collapsed.
......@@ -114,6 +114,10 @@ int print_netconf(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
fprintf(fp, "mc_forwarding %d ",
*(int *)RTA_DATA(tb[NETCONFA_MC_FORWARDING]));
if (tb[NETCONFA_PROXY_NEIGH])
fprintf(fp, "proxy_neigh %s ",
*(int *)RTA_DATA(tb[NETCONFA_PROXY_NEIGH])?"on":"off");
fprintf(fp, "\n");
fflush(fp);
return 0;
......
......@@ -2,7 +2,7 @@ TARGETS = ip-address.8 ip-link.8 ip-route.8
MAN8PAGES = $(TARGETS) ip.8 arpd.8 lnstat.8 routel.8 rtacct.8 rtmon.8 ss.8 \
tc.8 tc-bfifo.8 tc-cbq.8 tc-cbq-details.8 tc-choke.8 tc-codel.8 \
tc-drr.8 tc-ematch.8 tc-fq_codel.8 tc-hfsc.8 tc-htb.8 \
tc-drr.8 tc-ematch.8 tc-fq_codel.8 tc-hfsc.8 tc-htb.8 tc-pie.8 \
tc-netem.8 tc-pfifo.8 tc-pfifo_fast.8 tc-prio.8 tc-red.8 \
tc-sfb.8 tc-sfq.8 tc-stab.8 tc-tbf.8 \
bridge.8 rtstat.8 ctstat.8 nstat.8 routef.8 \
......
.TH PIE 8 "16 January 2014" "iproute2" "Linux"
.SH NAME
PIE \- Proportional Integral controller-Enhanced AQM algorithm
.SH SYNOPSIS
.B tc qdisc ... pie
[
.B limit
PACKETS ] [
.B target
TIME ] [
.B tupdate
TIME ] [
.B alpha
int ] [
.B beta
int ] [
.B ecn
|
.B noecn
] [
.B bytemode
|
.B nobytemode
]
.SH DESCRIPTION
Proportional Integral controller-Enhanced (PIE) is a control theoretic active
queue management scheme. It is based on the proportional integral controller but
aims to control delay. The main design goals are
o Low latency control
o High link utilization
o Simple implementation
o Guaranteed stability and fast responsiveness
.SH ALGORITHM
PIE is designed to control delay effectively. First, an average dequeue rate is
estimated based on the standing queue. The rate is used to calculate the current
delay. Then, on a periodic basis, the delay is used to calculate the dropping
probabilty. Finally, on arrival, a packet is dropped (or marked) based on this
probability.
PIE makes adjustments to the probability based on the trend of the delay i.e.
whether it is going up or down.The delay converges quickly to the target value
specified.
alpha and beta are statically chosen parameters chosen to control the drop probability
growth and are determined through control theoretic approaches. alpha determines how
the deviation between the current and target latency changes probability. beta exerts
additional adjustments depending on the latency trend.
The drop probabilty is used to mark packets in ecn mode. However, as in RED,
beyond 10% packets are dropped based on this probability. The bytemode is used
to drop packets proportional to the packet size.
Additional details can be found in the paper cited below.
.SH PARAMETERS
.SS limit
limit on the queue size in packets. Incoming packets are dropped when this limit
is reached. Default is 1000 packets.
.SS target
is the expected queue delay. The default target delay is 20ms.
.SS tupdate
is the frequency at which the system drop probability is calculated. The default is 30ms.
.SS alpha
.SS beta
alpha and beta are parameters chosen to control the drop probability. These
should be in the range between 0 and 32.
.SS ecn | noecn
is used to mark packets instead of dropping
.B ecn
to turn on ecn mode,
.B noecn
to turn off ecn mode. By default,
.B ecn
is turned off.
.SS bytemode | nobytemode
is used to scale drop probability proportional to packet size
.B bytemode
to turn on bytemode,
.B nobytemode
to turn off bytemode. By default,
.B bytemode
is turned off.
.SH EXAMPLES
# tc qdisc add dev eth0 root pie
# tc -s qdisc show
qdisc pie 8034: dev eth0 root refcnt 2 limit 200p target 19000us tupdate 29000us alpha 2 beta 20
Sent 7443524 bytes 7204 pkt (dropped 900, overlimits 0 requeues 0)
backlog 38998b 37p requeues 0
prob 0.123384 delay 25000us avg_dq_rate 1464840
pkts_in 7241 overlimit 900 dropped 0 maxq 186 ecn_mark 0
# tc qdisc add dev eth0 root pie limit 100 target 20ms tupdate 30ms ecn
# tc -s qdisc show
qdisc pie 8036: dev eth0 root refcnt 2 limit 200p target 19000 tupdate 29000 alpha 2 beta 20 ecn
Sent 2491922 bytes 2507 pkt (dropped 214, overlimits 0 requeues 0)
backlog 33728b 32p requeues 0
prob 0.102262 delay 24000us avg_dq_rate 1464840
pkts_in 2468 overlimit 214 dropped 0 maxq 192 ecn_mark 71
# tc qdisc add dev eth0 root pie limit 100 target 50ms tupdate 30ms bytemode
# tc -s qdisc show
qdisc pie 8036: dev eth0 root refcnt 2 limit 200p target 19000 tupdate 29000 alpha 2 beta 20 ecn
Sent 2491922 bytes 2507 pkt (dropped 214, overlimits 0 requeues 0)
backlog 33728b 32p requeues 0
prob 0.102262 delay 24000us avg_dq_rate 1464840
pkts_in 2468 overlimit 214 dropped 0 maxq 192 ecn_mark 71
.SH SEE ALSO
.BR tc (8),
.BR tc-codel (8)
.BR tc-red (8)
.SH SOURCES
o IETF draft submission is at http://tools.ietf.org/html/draft-pan-tsvwg-pie-00
o IEEE Conference on High Performance Switching and Routing 2013 : "PIE: A
Lightweight Control Scheme to Address the Bufferbloat Problem"
.SH AUTHORS
PIE was implemented by Vijay Subramanian and Mythili Prabhu, also the authors of
this man page. Please report bugs and corrections to the Linux networking
development mailing list at <netdev@vger.kernel.org>.
......@@ -53,6 +53,7 @@ TCMODULES += q_mqprio.o
TCMODULES += q_codel.o
TCMODULES += q_fq_codel.o
TCMODULES += q_fq.o
TCMODULES += q_pie.o
ifeq ($(TC_CONFIG_IPSET), y)
ifeq ($(TC_CONFIG_XT), y)
......
......@@ -113,6 +113,7 @@ static int htb_parse_class_opt(struct qdisc_util *qu, int argc, char **argv, str
unsigned int direct_qlen = ~0U;
unsigned int linklayer = LINKLAYER_ETHERNET; /* Assume ethernet */
struct rtattr *tail;
__u64 ceil64 = 0, rate64 = 0;
memset(&opt, 0, sizeof(opt)); mtu = 1600; /* eth packet len */
......@@ -173,22 +174,22 @@ static int htb_parse_class_opt(struct qdisc_util *qu, int argc, char **argv, str
ok++;
} else if (strcmp(*argv, "ceil") == 0) {
NEXT_ARG();
if (opt.ceil.rate) {
if (ceil64) {
fprintf(stderr, "Double \"ceil\" spec\n");
return -1;
}
if (get_rate(&opt.ceil.rate, *argv)) {
if (get_rate64(&ceil64, *argv)) {
explain1("ceil");
return -1;
}
ok++;
} else if (strcmp(*argv, "rate") == 0) {
NEXT_ARG();
if (opt.rate.rate) {
if (rate64) {
fprintf(stderr, "Double \"rate\" spec\n");
return -1;
}
if (get_rate(&opt.rate.rate, *argv)) {
if (get_rate64(&rate64, *argv)) {
explain1("rate");
return -1;
}
......@@ -207,17 +208,23 @@ static int htb_parse_class_opt(struct qdisc_util *qu, int argc, char **argv, str
/* if (!ok)
return 0;*/
if (opt.rate.rate == 0) {
if (!rate64) {
fprintf(stderr, "\"rate\" is required.\n");
return -1;
}
/* if ceil params are missing, use the same as rate */
if (!opt.ceil.rate) opt.ceil = opt.rate;
if (!ceil64)
ceil64 = rate64;
opt.rate.rate = (rate64 >= (1ULL << 32)) ? ~0U : rate64;
opt.ceil.rate = (ceil64 >= (1ULL << 32)) ? ~0U : ceil64;
/* compute minimal allowed burst from rate; mtu is added here to make
sute that buffer is larger than mtu and to have some safeguard space */
if (!buffer) buffer = opt.rate.rate / get_hz() + mtu;
if (!cbuffer) cbuffer = opt.ceil.rate / get_hz() + mtu;
if (!buffer)
buffer = rate64 / get_hz() + mtu;
if (!cbuffer)
cbuffer = ceil64 / get_hz() + mtu;
opt.ceil.overhead = overhead;
opt.rate.overhead = overhead;
......@@ -229,19 +236,26 @@ static int htb_parse_class_opt(struct qdisc_util *qu, int argc, char **argv, str
fprintf(stderr, "htb: failed to calculate rate table.\n");
return -1;
}
opt.buffer = tc_calc_xmittime(opt.rate.rate, buffer);
opt.buffer = tc_calc_xmittime(rate64, buffer);
if (tc_calc_rtable(&opt.ceil, ctab, ccell_log, mtu, linklayer) < 0) {
fprintf(stderr, "htb: failed to calculate ceil rate table.\n");
return -1;
}
opt.cbuffer = tc_calc_xmittime(opt.ceil.rate, cbuffer);
opt.cbuffer = tc_calc_xmittime(ceil64, 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);
if (rate64 >= (1ULL << 32))
addattr_l(n, 1124, TCA_HTB_RATE64, &rate64, sizeof(rate64));
if (ceil64 >= (1ULL << 32))
addattr_l(n, 1224, TCA_HTB_CEIL64, &ceil64, sizeof(ceil64));
addattr_l(n, 2024, TCA_HTB_PARMS, &opt, sizeof(opt));
addattr_l(n, 3024, TCA_HTB_RTAB, rtab, 1024);
addattr_l(n, 4024, TCA_HTB_CTAB, ctab, 1024);
......@@ -256,6 +270,7 @@ static int htb_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt)
struct tc_htb_glob *gopt;
double buffer,cbuffer;
unsigned int linklayer;
__u64 rate64, ceil64;
SPRINT_BUF(b1);
SPRINT_BUF(b2);
SPRINT_BUF(b3);
......@@ -275,12 +290,25 @@ static int htb_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt)
if (show_details)
fprintf(f, "quantum %d ", (int)hopt->quantum);
}
fprintf(f, "rate %s ", sprint_rate(hopt->rate.rate, b1));
rate64 = hopt->rate.rate;
if (tb[TCA_HTB_RATE64] &&
RTA_PAYLOAD(tb[TCA_HTB_RATE64]) >= sizeof(rate64)) {
rate64 = rta_getattr_u64(tb[TCA_HTB_RATE64]);
}
ceil64 = hopt->ceil.rate;
if (tb[TCA_HTB_CEIL64] &&
RTA_PAYLOAD(tb[TCA_HTB_CEIL64]) >= sizeof(ceil64))
ceil64 = rta_getattr_u64(tb[TCA_HTB_CEIL64]);
fprintf(f, "rate %s ", sprint_rate(rate64, b1));
if (hopt->rate.overhead)
fprintf(f, "overhead %u ", hopt->rate.overhead);
buffer = tc_calc_xmitsize(hopt->rate.rate, hopt->buffer);
fprintf(f, "ceil %s ", sprint_rate(hopt->ceil.rate, b1));
cbuffer = tc_calc_xmitsize(hopt->ceil.rate, hopt->cbuffer);
buffer = tc_calc_xmitsize(rate64, hopt->buffer);
fprintf(f, "ceil %s ", sprint_rate(ceil64, b1));
cbuffer = tc_calc_xmitsize(ceil64, hopt->cbuffer);
linklayer = (hopt->rate.linklayer & TC_LINKLAYER_MASK);
if (linklayer > TC_LINKLAYER_ETHERNET || show_details)
fprintf(f, "linklayer %s ", sprint_linklayer(linklayer, b4));
......
......@@ -183,6 +183,7 @@ static int netem_parse_opt(struct qdisc_util *qu, int argc, char **argv,
__s16 *dist_data = NULL;
__u16 loss_type = NETEM_LOSS_UNSPEC;
int present[__TCA_NETEM_MAX];
__u64 rate64 = 0;
memset(&cor, 0, sizeof(cor));
memset(&reorder, 0, sizeof(reorder));
......@@ -391,7 +392,7 @@ static int netem_parse_opt(struct qdisc_util *qu, int argc, char **argv,
} else if (matches(*argv, "rate") == 0) {
++present[TCA_NETEM_RATE];
NEXT_ARG();
if (get_rate(&rate.rate, *argv)) {
if (get_rate64(&rate64, *argv)) {
explain1("rate");
return -1;
}
......@@ -496,9 +497,18 @@ static int netem_parse_opt(struct qdisc_util *qu, int argc, char **argv,
addattr_nest_end(n, start);
}
if (present[TCA_NETEM_RATE] &&
addattr_l(n, 1024, TCA_NETEM_RATE, &rate, sizeof(rate)) < 0)
return -1;
if (present[TCA_NETEM_RATE]) {
if (rate64 >= (1ULL << 32)) {
if (addattr_l(n, 1024,
TCA_NETEM_RATE64, &rate64, sizeof(rate64)) < 0)
return -1;
rate.rate = ~0U;
} else {
rate.rate = rate64;
}
if (addattr_l(n, 1024, TCA_NETEM_RATE, &rate, sizeof(rate)) < 0)
return -1;
}
if (dist_data) {
if (addattr_l(n, MAX_DIST * sizeof(dist_data[0]),
......@@ -522,6 +532,7 @@ static int netem_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt)
struct tc_netem_qopt qopt;
const struct tc_netem_rate *rate = NULL;
int len = RTA_PAYLOAD(opt) - sizeof(qopt);
__u64 rate64 = 0;
SPRINT_BUF(b1);
if (opt == NULL)
......@@ -572,6 +583,11 @@ static int netem_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt)
return -1;
ecn = RTA_DATA(tb[TCA_NETEM_ECN]);
}
if (tb[TCA_NETEM_RATE64]) {
if (RTA_PAYLOAD(tb[TCA_NETEM_RATE64]) < sizeof(rate64))
return -1;
rate64 = rta_getattr_u64(tb[TCA_NETEM_RATE64]);
}
}
fprintf(f, "limit %d", qopt.limit);
......@@ -632,7 +648,10 @@ static int netem_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt)
}
if (rate && rate->rate) {
fprintf(f, " rate %s", sprint_rate(rate->rate, b1));
if (rate64)
fprintf(f, " rate %s", sprint_rate(rate64, b1));
else
fprintf(f, " rate %s", sprint_rate(rate->rate, b1));
if (rate->packet_overhead)
fprintf(f, " packetoverhead %d", rate->packet_overhead);
if (rate->cell_size)
......
/* Copyright (C) 2013 Cisco Systems, Inc, 2013.
*
* 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.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* Author: Vijay Subramanian <vijaynsu@cisco.com>
* Author: Mythili Prabhu <mysuryan@cisco.com>
*
*/
#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 <math.h>
#include "utils.h"
#include "tc_util.h"
static void explain(void)
{
fprintf(stderr, "Usage: ... pie [ limit PACKETS ][ target TIME us]\n");
fprintf(stderr, " [ tupdate TIME us][ alpha ALPHA ]");
fprintf(stderr, "[beta BETA ][bytemode | nobytemode][ecn | noecn ]\n");
}
#define ALPHA_MAX 32
#define ALPHA_MIN 0
#define BETA_MAX 32
#define BETA_MIN 0
static int pie_parse_opt(struct qdisc_util *qu, int argc, char **argv,
struct nlmsghdr *n)
{
unsigned int limit = 0;
unsigned int target = 0;
unsigned int tupdate = 0;
unsigned int alpha = 0;
unsigned int beta = 0;
int ecn = -1;
int bytemode = -1;
struct rtattr *tail;
while (argc > 0) {
if (strcmp(*argv, "limit") == 0) {
NEXT_ARG();
if (get_unsigned(&limit, *argv, 0)) {
fprintf(stderr, "Illegal \"limit\"\n");
return -1;
}
} else if (strcmp(*argv, "target") == 0) {
NEXT_ARG();
if (get_time(&target, *argv)) {
fprintf(stderr, "Illegal \"target\"\n");
return -1;
}
} else if (strcmp(*argv, "tupdate") == 0) {
NEXT_ARG();
if (get_time(&tupdate, *argv)) {
fprintf(stderr, "Illegal \"tupdate\"\n");
return -1;
}
} else if (strcmp(*argv, "alpha") == 0) {
NEXT_ARG();
if (get_unsigned(&alpha, *argv, 0) ||
(alpha > ALPHA_MAX) || (alpha < ALPHA_MIN)) {
fprintf(stderr, "Illegal \"alpha\"\n");
return -1;
}
} else if (strcmp(*argv, "beta") == 0) {
NEXT_ARG();
if (get_unsigned(&beta, *argv, 0) ||
(beta > BETA_MAX) || (beta < BETA_MIN)) {
fprintf(stderr, "Illegal \"beta\"\n");
return -1;
}
} else if (strcmp(*argv, "ecn") == 0) {
ecn = 1;
} else if (strcmp(*argv, "noecn") == 0) {
ecn = 0;
} else if (strcmp(*argv, "bytemode") == 0) {
bytemode = 1;
} else if (strcmp(*argv, "nobytemode") == 0) {
bytemode = 0;
} else if (strcmp(*argv, "help") == 0) {
explain();
return -1;
} else {
fprintf(stderr, "What is \"%s\"?\n", *argv);
explain();
return -1;
}
argc--;
argv++;
}
tail = NLMSG_TAIL(n);
addattr_l(n, 1024, TCA_OPTIONS, NULL, 0);
if (limit)
addattr_l(n, 1024, TCA_PIE_LIMIT, &limit, sizeof(limit));
if (tupdate)
addattr_l(n, 1024, TCA_PIE_TUPDATE, &tupdate, sizeof(tupdate));
if (target)
addattr_l(n, 1024, TCA_PIE_TARGET, &target, sizeof(target));
if (alpha)
addattr_l(n, 1024, TCA_PIE_ALPHA, &alpha, sizeof(alpha));
if (beta)
addattr_l(n, 1024, TCA_PIE_BETA, &beta, sizeof(beta));
if (ecn != -1)
addattr_l(n, 1024, TCA_PIE_ECN, &ecn, sizeof(ecn));
if (bytemode != -1)
addattr_l(n, 1024, TCA_PIE_BYTEMODE, &bytemode,
sizeof(bytemode));
tail->rta_len = (void *)NLMSG_TAIL(n) - (void *)tail;
return 0;
}
static int pie_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt)
{
struct rtattr *tb[TCA_PIE_MAX + 1];
unsigned int limit;
unsigned int tupdate;
unsigned int target;
unsigned int alpha;
unsigned int beta;
unsigned ecn;
unsigned bytemode;
SPRINT_BUF(b1);
if (opt == NULL)
return 0;
parse_rtattr_nested(tb, TCA_PIE_MAX, opt);
if (tb[TCA_PIE_LIMIT] &&
RTA_PAYLOAD(tb[TCA_PIE_LIMIT]) >= sizeof(__u32)) {
limit = rta_getattr_u32(tb[TCA_PIE_LIMIT]);
fprintf(f, "limit %up ", limit);
}
if (tb[TCA_PIE_TARGET] &&
RTA_PAYLOAD(tb[TCA_PIE_TARGET]) >= sizeof(__u32)) {
target = rta_getattr_u32(tb[TCA_PIE_TARGET]);
fprintf(f, "target %s ", sprint_time(target, b1));
}
if (tb[TCA_PIE_TUPDATE] &&
RTA_PAYLOAD(tb[TCA_PIE_TUPDATE]) >= sizeof(__u32)) {
tupdate = rta_getattr_u32(tb[TCA_PIE_TUPDATE]);
fprintf(f, "tupdate %s ", sprint_time(tupdate, b1));
}
if (tb[TCA_PIE_ALPHA] &&
RTA_PAYLOAD(tb[TCA_PIE_ALPHA]) >= sizeof(__u32)) {
alpha = rta_getattr_u32(tb[TCA_PIE_ALPHA]);
fprintf(f, "alpha %u ", alpha);
}
if (tb[TCA_PIE_BETA] &&
RTA_PAYLOAD(tb[TCA_PIE_BETA]) >= sizeof(__u32)) {
beta = rta_getattr_u32(tb[TCA_PIE_BETA]);
fprintf(f, "beta %u ", beta);
}
if (tb[TCA_PIE_ECN] && RTA_PAYLOAD(tb[TCA_PIE_ECN]) >= sizeof(__u32)) {
ecn = rta_getattr_u32(tb[TCA_PIE_ECN]);
if (ecn)
fprintf(f, "ecn ");
}
if (tb[TCA_PIE_BYTEMODE] &&
RTA_PAYLOAD(tb[TCA_PIE_BYTEMODE]) >= sizeof(__u32)) {
bytemode = rta_getattr_u32(tb[TCA_PIE_BYTEMODE]);
if (bytemode)
fprintf(f, "bytemode ");
}
return 0;
}
static int pie_print_xstats(struct qdisc_util *qu, FILE *f,
struct rtattr *xstats)
{
struct tc_pie_xstats *st;
if (xstats == NULL)
return 0;
if (RTA_PAYLOAD(xstats) < sizeof(*st))
return -1;
st = RTA_DATA(xstats);
/*prob is returned as a fracion of maximum integer value */
fprintf(f, "prob %f delay %uus avg_dq_rate %u\n",
(double)st->prob / (double)0xffffffff, st->delay,
st->avg_dq_rate);
fprintf(f, "pkts_in %u overlimit %u dropped %u maxq %u ecn_mark %u\n",
st->packets_in, st->overlimit, st->dropped, st->maxq,
st->ecn_mark);
return 0;
}
struct qdisc_util pie_qdisc_util = {
.id = "pie",
.parse_qopt = pie_parse_opt,
.print_qopt = pie_print_opt,
.print_xstats = pie_print_xstats,
};
......@@ -47,6 +47,7 @@ static int tbf_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nl
unsigned short overhead=0;
unsigned int linklayer = LINKLAYER_ETHERNET; /* Assume ethernet */
struct rtattr *tail;
__u64 rate64 = 0, prate64 = 0;
memset(&opt, 0, sizeof(opt));
......@@ -121,22 +122,22 @@ static int tbf_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nl
ok++;
} else if (strcmp(*argv, "rate") == 0) {
NEXT_ARG();
if (opt.rate.rate) {
if (rate64) {
fprintf(stderr, "tbf: duplicate \"rate\" specification\n");
return -1;
}
if (get_rate(&opt.rate.rate, *argv)) {
if (get_rate64(&rate64, *argv)) {
explain1("rate", *argv);
return -1;
}
ok++;
} else if (matches(*argv, "peakrate") == 0) {
NEXT_ARG();
if (opt.peakrate.rate) {
if (prate64) {
fprintf(stderr, "tbf: duplicate \"peakrate\" specification\n");
return -1;
}
if (get_rate(&opt.peakrate.rate, *argv)) {
if (get_rate64(&prate64, *argv)) {
explain1("peakrate", *argv);
return -1;
}
......@@ -172,7 +173,7 @@ static int tbf_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nl
* one go rather than reveal one more problem when a
* previous one has been fixed.
*/
if (opt.rate.rate == 0) {
if (rate64 == 0) {
fprintf(stderr, "tbf: the \"rate\" parameter is mandatory.\n");
verdict = -1;
}
......@@ -180,7 +181,7 @@ static int tbf_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nl
fprintf(stderr, "tbf: the \"burst\" parameter is mandatory.\n");
verdict = -1;
}
if (opt.peakrate.rate) {
if (prate64) {
if (!mtu) {
fprintf(stderr, "tbf: when \"peakrate\" is specified, \"mtu\" must also be specified.\n");
verdict = -1;
......@@ -197,10 +198,13 @@ static int tbf_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nl
return verdict;
}
opt.rate.rate = (rate64 >= (1ULL << 32)) ? ~0U : rate64;
opt.peakrate.rate = (prate64 >= (1ULL << 32)) ? ~0U : prate64;
if (opt.limit == 0) {
double lim = opt.rate.rate*(double)latency/TIME_UNITS_PER_SEC + buffer;
if (opt.peakrate.rate) {
double lim2 = opt.peakrate.rate*(double)latency/TIME_UNITS_PER_SEC + mtu;
double lim = rate64*(double)latency/TIME_UNITS_PER_SEC + buffer;
if (prate64) {
double lim2 = prate64*(double)latency/TIME_UNITS_PER_SEC + mtu;
if (lim2 < lim)
lim = lim2;
}
......@@ -228,20 +232,28 @@ static int tbf_parse_opt(struct qdisc_util *qu, int argc, char **argv, struct nl
tail = NLMSG_TAIL(n);
addattr_l(n, 1024, TCA_OPTIONS, NULL, 0);
addattr_l(n, 2024, TCA_TBF_PARMS, &opt, sizeof(opt));
addattr_l(n, 2124, TCA_TBF_BURST, &buffer, sizeof(buffer));
if (rate64 >= (1ULL << 32))
addattr_l(n, 2124, TCA_TBF_RATE64, &rate64, sizeof(rate64));
addattr_l(n, 3024, TCA_TBF_RTAB, rtab, 1024);
if (opt.peakrate.rate)
if (opt.peakrate.rate) {
if (prate64 >= (1ULL << 32))
addattr_l(n, 3124, TCA_TBF_PRATE64, &prate64, sizeof(prate64));
addattr_l(n, 3224, TCA_TBF_PBURST, &mtu, sizeof(mtu));
addattr_l(n, 4096, TCA_TBF_PTAB, ptab, 1024);
}
tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail;
return 0;
}
static int tbf_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt)
{
struct rtattr *tb[TCA_TBF_PTAB+1];
struct rtattr *tb[TCA_TBF_MAX+1];
struct tc_tbf_qopt *qopt;
unsigned int linklayer;
double buffer, mtu;
double latency;
__u64 rate64 = 0, prate64 = 0;
SPRINT_BUF(b1);
SPRINT_BUF(b2);
SPRINT_BUF(b3);
......@@ -249,7 +261,7 @@ static int tbf_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt)
if (opt == NULL)
return 0;
parse_rtattr_nested(tb, TCA_TBF_PTAB, opt);
parse_rtattr_nested(tb, TCA_TBF_MAX, opt);
if (tb[TCA_TBF_PARMS] == NULL)
return -1;
......@@ -257,8 +269,12 @@ static int tbf_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt)
qopt = RTA_DATA(tb[TCA_TBF_PARMS]);
if (RTA_PAYLOAD(tb[TCA_TBF_PARMS]) < sizeof(*qopt))
return -1;
fprintf(f, "rate %s ", sprint_rate(qopt->rate.rate, b1));
buffer = tc_calc_xmitsize(qopt->rate.rate, qopt->buffer);
rate64 = qopt->rate.rate;
if (tb[TCA_TBF_RATE64] &&
RTA_PAYLOAD(tb[TCA_TBF_RATE64]) >= sizeof(rate64))
rate64 = rta_getattr_u64(tb[TCA_TBF_RATE64]);
fprintf(f, "rate %s ", sprint_rate(rate64, b1));
buffer = tc_calc_xmitsize(rate64, qopt->buffer);
if (show_details) {
fprintf(f, "burst %s/%u mpu %s ", sprint_size(buffer, b1),
1<<qopt->rate.cell_log, sprint_size(qopt->rate.mpu, b2));
......@@ -267,10 +283,14 @@ static int tbf_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt)
}
if (show_raw)
fprintf(f, "[%08x] ", qopt->buffer);
if (qopt->peakrate.rate) {
fprintf(f, "peakrate %s ", sprint_rate(qopt->peakrate.rate, b1));
prate64 = qopt->peakrate.rate;
if (tb[TCA_TBF_PRATE64] &&
RTA_PAYLOAD(tb[TCA_TBF_PRATE64]) >= sizeof(prate64))
prate64 = rta_getattr_u64(tb[TCA_TBF_PRATE64]);
if (prate64) {
fprintf(f, "peakrate %s ", sprint_rate(prate64, b1));
if (qopt->mtu || qopt->peakrate.mpu) {
mtu = tc_calc_xmitsize(qopt->peakrate.rate, qopt->mtu);
mtu = tc_calc_xmitsize(prate64, qopt->mtu);
if (show_details) {
fprintf(f, "mtu %s/%u mpu %s ", sprint_size(mtu, b1),
1<<qopt->peakrate.cell_log, sprint_size(qopt->peakrate.mpu, b2));
......@@ -285,9 +305,9 @@ static int tbf_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt)
if (show_raw)
fprintf(f, "limit %s ", sprint_size(qopt->limit, b1));
latency = TIME_UNITS_PER_SEC*(qopt->limit/(double)qopt->rate.rate) - tc_core_tick2time(qopt->buffer);
if (qopt->peakrate.rate) {
double lat2 = TIME_UNITS_PER_SEC*(qopt->limit/(double)qopt->peakrate.rate) - tc_core_tick2time(qopt->mtu);
latency = TIME_UNITS_PER_SEC*(qopt->limit/(double)rate64) - tc_core_tick2time(qopt->buffer);
if (prate64) {
double lat2 = TIME_UNITS_PER_SEC*(qopt->limit/(double)prate64) - tc_core_tick2time(qopt->mtu);
if (lat2 > latency)
latency = lat2;
}
......
......@@ -56,12 +56,12 @@ unsigned tc_core_ktime2time(unsigned ktime)
return ktime / clock_factor;
}
unsigned tc_calc_xmittime(unsigned rate, unsigned size)
unsigned tc_calc_xmittime(__u64 rate, unsigned size)
{
return tc_core_time2tick(TIME_UNITS_PER_SEC*((double)size/rate));
return tc_core_time2tick(TIME_UNITS_PER_SEC*((double)size/(double)rate));
}
unsigned tc_calc_xmitsize(unsigned rate, unsigned ticks)
unsigned tc_calc_xmitsize(__u64 rate, unsigned ticks)
{
return ((double)rate*tc_core_tick2time(ticks))/TIME_UNITS_PER_SEC;
}
......
......@@ -18,8 +18,8 @@ unsigned tc_core_time2tick(unsigned time);
unsigned tc_core_tick2time(unsigned tick);
unsigned tc_core_time2ktime(unsigned time);
unsigned tc_core_ktime2time(unsigned ktime);
unsigned tc_calc_xmittime(unsigned rate, unsigned size);
unsigned tc_calc_xmitsize(unsigned rate, unsigned ticks);
unsigned tc_calc_xmittime(__u64 rate, unsigned size);
unsigned tc_calc_xmitsize(__u64 rate, unsigned ticks);
int tc_calc_rtable(struct tc_ratespec *r, __u32 *rtab,
int cell_log, unsigned mtu, enum link_layer link_layer);
int tc_calc_size_table(struct tc_sizespec *s, __u16 **stab);
......
......@@ -171,6 +171,31 @@ int get_rate(unsigned *rate, const char *str)
return 0;
}
int get_rate64(__u64 *rate, const char *str)
{
char *p;
double bps = strtod(str, &p);
const struct rate_suffix *s;
if (p == str)
return -1;
for (s = suffixes; s->name; ++s) {
if (strcasecmp(s->name, p) == 0) {
bps *= s->scale;
p += strlen(p);
break;
}
}
if (*p)
return -1; /* unknown suffix */
bps /= 8; /* -> bytes per second */
*rate = bps;
return 0;
}
void print_rate(char *buf, int len, __u64 rate)
{
extern int use_iec;
......
......@@ -58,6 +58,7 @@ extern struct filter_util *get_filter_kind(const char *str);
extern int get_qdisc_handle(__u32 *h, const char *str);
extern int get_rate(unsigned *rate, const char *str);
extern int get_rate64(__u64 *rate, const char *str);
extern int get_size(unsigned *size, const char *str);
extern int get_size_and_cell(unsigned *size, int *cell_log, char *str);
extern int get_time(unsigned *time, const char *str);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment