From: David Ahern Date: Tue, 9 Jul 2019 21:26:44 +0000 (-0700) Subject: Merge branch 'master' into next X-Git-Tag: v5.4.0~94 X-Git-Url: https://git.proxmox.com/?a=commitdiff_plain;h=830ac9abe62d00304ce4dbd2194ec6ad2d217de1;hp=-c;p=mirror_iproute2.git Merge branch 'master' into next Signed-off-by: David Ahern --- 830ac9abe62d00304ce4dbd2194ec6ad2d217de1 diff --combined ip/ipaddress.c index 3d8caf0e,733f7d9d..bc8f5ba1 --- a/ip/ipaddress.c +++ b/ip/ipaddress.c @@@ -26,7 -26,6 +26,7 @@@ #include #include +#include #include #include @@@ -53,33 -52,32 +53,33 @@@ static void usage(void if (do_link) iplink_usage(); - fprintf(stderr, "Usage: ip address {add|change|replace} IFADDR dev IFNAME [ LIFETIME ]\n"); - fprintf(stderr, " [ CONFFLAG-LIST ]\n"); - fprintf(stderr, " ip address del IFADDR dev IFNAME [mngtmpaddr]\n"); - fprintf(stderr, " ip address {save|flush} [ dev IFNAME ] [ scope SCOPE-ID ]\n"); - fprintf(stderr, " [ to PREFIX ] [ FLAG-LIST ] [ label LABEL ] [up]\n"); - fprintf(stderr, " ip address [ show [ dev IFNAME ] [ scope SCOPE-ID ] [ master DEVICE ]\n"); - fprintf(stderr, " [ type TYPE ] [ to PREFIX ] [ FLAG-LIST ]\n"); - fprintf(stderr, " [ label LABEL ] [up] [ vrf NAME ] ]\n"); - fprintf(stderr, " ip address {showdump|restore}\n"); - fprintf(stderr, "IFADDR := PREFIX | ADDR peer PREFIX\n"); - fprintf(stderr, " [ broadcast ADDR ] [ anycast ADDR ]\n"); - fprintf(stderr, " [ label IFNAME ] [ scope SCOPE-ID ] [ metric METRIC ]\n"); - fprintf(stderr, "SCOPE-ID := [ host | link | global | NUMBER ]\n"); - fprintf(stderr, "FLAG-LIST := [ FLAG-LIST ] FLAG\n"); - fprintf(stderr, "FLAG := [ permanent | dynamic | secondary | primary |\n"); - 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 | mngtmpaddr | noprefixroute | autojoin ]\n"); - fprintf(stderr, "LIFETIME := [ valid_lft LFT ] [ preferred_lft LFT ]\n"); - fprintf(stderr, "LFT := forever | SECONDS\n"); - fprintf(stderr, "TYPE := { vlan | veth | vcan | vxcan | dummy | ifb | macvlan | macvtap |\n"); - fprintf(stderr, " bridge | bond | ipoib | ip6tnl | ipip | sit | vxlan | lowpan |\n"); - fprintf(stderr, " gre | gretap | erspan | ip6gre | ip6gretap | ip6erspan | vti |\n"); - fprintf(stderr, " nlmon | can | bond_slave | ipvlan | geneve | bridge_slave |\n"); - fprintf(stderr, " hsr | macsec | netdevsim }\n"); + fprintf(stderr, + "Usage: ip address {add|change|replace} IFADDR dev IFNAME [ LIFETIME ]\n" + " [ CONFFLAG-LIST ]\n" + " ip address del IFADDR dev IFNAME [mngtmpaddr]\n" + " ip address {save|flush} [ dev IFNAME ] [ scope SCOPE-ID ]\n" + " [ to PREFIX ] [ FLAG-LIST ] [ label LABEL ] [up]\n" + " ip address [ show [ dev IFNAME ] [ scope SCOPE-ID ] [ master DEVICE ]\n" + " [ type TYPE ] [ to PREFIX ] [ FLAG-LIST ]\n" + " [ label LABEL ] [up] [ vrf NAME ] ]\n" + " ip address {showdump|restore}\n" + "IFADDR := PREFIX | ADDR peer PREFIX\n" + " [ broadcast ADDR ] [ anycast ADDR ]\n" + " [ label IFNAME ] [ scope SCOPE-ID ] [ metric METRIC ]\n" + "SCOPE-ID := [ host | link | global | NUMBER ]\n" + "FLAG-LIST := [ FLAG-LIST ] FLAG\n" + "FLAG := [ permanent | dynamic | secondary | primary |\n" + " [-]tentative | [-]deprecated | [-]dadfailed | temporary |\n" + " CONFFLAG-LIST ]\n" + "CONFFLAG-LIST := [ CONFFLAG-LIST ] CONFFLAG\n" + "CONFFLAG := [ home | nodad | mngtmpaddr | noprefixroute | autojoin ]\n" + "LIFETIME := [ valid_lft LFT ] [ preferred_lft LFT ]\n" + "LFT := forever | SECONDS\n" + "TYPE := { vlan | veth | vcan | vxcan | dummy | ifb | macvlan | macvtap |\n" + " bridge | bond | ipoib | ip6tnl | ipip | sit | vxlan | lowpan |\n" + " gre | gretap | erspan | ip6gre | ip6gretap | ip6erspan | vti |\n" + " nlmon | can | bond_slave | ipvlan | geneve | bridge_slave |\n" + " hsr | macsec | netdevsim }\n"); exit(-1); } @@@ -351,10 -349,9 +351,10 @@@ static void print_af_spec(FILE *fp, str static void print_vf_stats64(FILE *fp, struct rtattr *vfstats); -static void print_vfinfo(FILE *fp, struct rtattr *vfinfo) +static void print_vfinfo(FILE *fp, struct ifinfomsg *ifi, struct rtattr *vfinfo) { struct ifla_vf_mac *vf_mac; + struct ifla_vf_broadcast *vf_broadcast; struct ifla_vf_tx_rate *vf_tx_rate; struct rtattr *vf[IFLA_VF_MAX + 1] = {}; @@@ -368,41 -365,13 +368,41 @@@ parse_rtattr_nested(vf, IFLA_VF_MAX, vfinfo); vf_mac = RTA_DATA(vf[IFLA_VF_MAC]); + vf_broadcast = RTA_DATA(vf[IFLA_VF_BROADCAST]); vf_tx_rate = RTA_DATA(vf[IFLA_VF_TX_RATE]); print_string(PRINT_FP, NULL, "%s ", _SL_); print_int(PRINT_ANY, "vf", "vf %d ", vf_mac->vf); - print_string(PRINT_ANY, "mac", "MAC %s", - ll_addr_n2a((unsigned char *) &vf_mac->mac, - ETH_ALEN, 0, b1, sizeof(b1))); + + print_string(PRINT_ANY, + "link_type", + " link/%s ", + ll_type_n2a(ifi->ifi_type, b1, sizeof(b1))); + + print_color_string(PRINT_ANY, COLOR_MAC, + "address", "%s", + ll_addr_n2a((unsigned char *) &vf_mac->mac, + ifi->ifi_type == ARPHRD_ETHER ? + ETH_ALEN : INFINIBAND_ALEN, + ifi->ifi_type, + b1, sizeof(b1))); + + if (vf[IFLA_VF_BROADCAST]) { + if (ifi->ifi_flags&IFF_POINTOPOINT) { + print_string(PRINT_FP, NULL, " peer ", NULL); + print_bool(PRINT_JSON, + "link_pointtopoint", NULL, true); + } else + print_string(PRINT_FP, NULL, " brd ", NULL); + + print_color_string(PRINT_ANY, COLOR_MAC, + "broadcast", "%s", + ll_addr_n2a((unsigned char *) &vf_broadcast->broadcast, + ifi->ifi_type == ARPHRD_ETHER ? + ETH_ALEN : INFINIBAND_ALEN, + ifi->ifi_type, + b1, sizeof(b1))); + } if (vf[IFLA_VF_VLAN_LIST]) { struct rtattr *i, *vfvlanlist = vf[IFLA_VF_VLAN_LIST]; @@@ -1133,7 -1102,7 +1133,7 @@@ int print_linkinfo(struct nlmsghdr *n, open_json_array(PRINT_JSON, "vfinfo_list"); for (i = RTA_DATA(vflist); RTA_OK(i, rem); i = RTA_NEXT(i, rem)) { open_json_object(NULL); - print_vfinfo(fp, i); + print_vfinfo(fp, ifi, i); close_json_object(); } close_json_array(PRINT_JSON, NULL); @@@ -2278,11 -2247,20 +2278,20 @@@ static int ipaddr_modify(int cmd, int f if (set_lifetime(&preferred_lft, *argv)) invarg("preferred_lft value", *argv); } else if (strcmp(*argv, "home") == 0) { - ifa_flags |= IFA_F_HOMEADDRESS; + if (req.ifa.ifa_family == AF_INET6) + ifa_flags |= IFA_F_HOMEADDRESS; + else + fprintf(stderr, "Warning: home option can be set only for IPv6 addresses\n"); } else if (strcmp(*argv, "nodad") == 0) { - ifa_flags |= IFA_F_NODAD; + if (req.ifa.ifa_family == AF_INET6) + ifa_flags |= IFA_F_NODAD; + else + fprintf(stderr, "Warning: nodad option can be set only for IPv6 addresses\n"); } else if (strcmp(*argv, "mngtmpaddr") == 0) { - ifa_flags |= IFA_F_MANAGETEMPADDR; + if (req.ifa.ifa_family == AF_INET6) + ifa_flags |= IFA_F_MANAGETEMPADDR; + else + fprintf(stderr, "Warning: mngtmpaddr option can be set only for IPv6 addresses\n"); } else if (strcmp(*argv, "noprefixroute") == 0) { ifa_flags |= IFA_F_NOPREFIXROUTE; } else if (strcmp(*argv, "autojoin") == 0) { diff --combined ip/iproute.c index 6b814225,1669e013..83e99fa2 --- a/ip/iproute.c +++ b/ip/iproute.c @@@ -80,7 -80,7 +80,7 @@@ static void usage(void " [ table TABLE_ID ] [ proto RTPROTO ]\n" " [ scope SCOPE ] [ metric METRIC ]\n" " [ ttl-propagate { enabled | disabled } ]\n" - "INFO_SPEC := NH OPTIONS FLAGS [ nexthop NH ]...\n" + "INFO_SPEC := { NH | nhid ID } OPTIONS FLAGS [ nexthop NH ]...\n" "NH := [ encap ENCAPTYPE ENCAPHDR ] [ via [ FAMILY ] ADDRESS ]\n" " [ dev STRING ] [ weight NUMBER ] NHFLAGS\n" "FAMILY := [ inet | inet6 | mpls | bridge | link ]\n" @@@ -349,7 -349,7 +349,7 @@@ static void print_rtax_features(FILE *f "features", "%#llx ", of); } -static void print_rt_flags(FILE *fp, unsigned int flags) +void print_rt_flags(FILE *fp, unsigned int flags) { open_json_array(PRINT_JSON, is_json_context() ? "flags" : ""); @@@ -394,7 -394,8 +394,7 @@@ static void print_rt_pref(FILE *fp, uns } } -static void print_rta_if(FILE *fp, const struct rtattr *rta, - const char *prefix) +void print_rta_if(FILE *fp, const struct rtattr *rta, const char *prefix) { const char *ifname = ll_index_to_name(rta_getattr_u32(rta)); @@@ -531,16 -532,17 +531,16 @@@ static void print_rta_newdst(FILE *fp, } } -static void print_rta_gateway(FILE *fp, const struct rtmsg *r, - const struct rtattr *rta) +void print_rta_gateway(FILE *fp, unsigned char family, const struct rtattr *rta) { - const char *gateway = format_host_rta(r->rtm_family, rta); + const char *gateway = format_host_rta(family, rta); if (is_json_context()) print_string(PRINT_JSON, "gateway", NULL, gateway); else { fprintf(fp, "via "); print_color_string(PRINT_FP, - ifa_family_color(r->rtm_family), + ifa_family_color(family), NULL, "%s ", gateway); } } @@@ -677,8 -679,7 +677,8 @@@ static void print_rta_multipath(FILE *f if (tb[RTA_NEWDST]) print_rta_newdst(fp, r, tb[RTA_NEWDST]); if (tb[RTA_GATEWAY]) - print_rta_gateway(fp, r, tb[RTA_GATEWAY]); + print_rta_gateway(fp, r->rtm_family, + tb[RTA_GATEWAY]); if (tb[RTA_VIA]) print_rta_via(fp, tb[RTA_VIA]); if (tb[RTA_FLOW]) @@@ -809,10 -810,6 +809,10 @@@ int print_route(struct nlmsghdr *n, voi print_string(PRINT_ANY, "src", "from %s ", b1); } + if (tb[RTA_NH_ID]) + print_uint(PRINT_ANY, "nhid", "nhid %u ", + rta_getattr_u32(tb[RTA_NH_ID])); + if (tb[RTA_NEWDST]) print_rta_newdst(fp, r, tb[RTA_NEWDST]); @@@ -825,7 -822,7 +825,7 @@@ } if (tb[RTA_GATEWAY] && filter.rvia.bitlen != host_len) - print_rta_gateway(fp, r, tb[RTA_GATEWAY]); + print_rta_gateway(fp, r->rtm_family, tb[RTA_GATEWAY]); if (tb[RTA_VIA]) print_rta_via(fp, tb[RTA_VIA]); @@@ -1000,8 -997,7 +1000,8 @@@ static int parse_one_nh(struct nlmsghd } else if (strcmp(*argv, "encap") == 0) { int old_len = rta->rta_len; - if (lwt_parse_encap(rta, len, &argc, &argv)) + if (lwt_parse_encap(rta, len, &argc, &argv, + RTA_ENCAP, RTA_ENCAP_TYPE)) return -1; rtnh->rtnh_len += rta->rta_len - old_len; } else if (strcmp(*argv, "as") == 0) { @@@ -1084,7 -1080,6 +1084,7 @@@ static int iproute_modify(int cmd, unsi int table_ok = 0; int raw = 0; int type_ok = 0; + __u32 nhid = 0; if (cmd != RTM_DELROUTE) { req.r.rtm_protocol = RTPROT_BOOT; @@@ -1363,11 -1358,6 +1363,11 @@@ } else if (strcmp(*argv, "nexthop") == 0) { nhs_ok = 1; break; + } else if (!strcmp(*argv, "nhid")) { + NEXT_ARG(); + if (get_u32(&nhid, *argv, 0)) + invarg("\"id\" value is invalid\n", *argv); + addattr32(&req.n, sizeof(req), RTA_NH_ID, nhid); } else if (matches(*argv, "protocol") == 0) { __u32 prot; @@@ -1426,8 -1416,7 +1426,8 @@@ rta->rta_type = RTA_ENCAP; rta->rta_len = RTA_LENGTH(0); - lwt_parse_encap(rta, sizeof(buf), &argc, &argv); + lwt_parse_encap(rta, sizeof(buf), &argc, &argv, + RTA_ENCAP, RTA_ENCAP_TYPE); if (rta->rta_len > RTA_LENGTH(0)) addraw_l(&req.n, 1024 @@@ -1530,7 -1519,7 +1530,7 @@@ req.r.rtm_type == RTN_UNSPEC) { if (cmd == RTM_DELROUTE) req.r.rtm_scope = RT_SCOPE_NOWHERE; - else if (!gw_ok && !nhs_ok) + else if (!gw_ok && !nhs_ok && !nhid) req.r.rtm_scope = RT_SCOPE_LINK; } } @@@ -1613,6 -1602,30 +1613,30 @@@ static int save_route_prep(void return 0; } + static int iproute_dump_filter(struct nlmsghdr *nlh, int reqlen) + { + struct rtmsg *rtm = NLMSG_DATA(nlh); + int err; + + rtm->rtm_protocol = filter.protocol; + if (filter.cloned) + rtm->rtm_flags |= RTM_F_CLONED; + + if (filter.tb) { + err = addattr32(nlh, reqlen, RTA_TABLE, filter.tb); + if (err) + return err; + } + + if (filter.oif) { + err = addattr32(nlh, reqlen, RTA_OIF, filter.oif); + if (err) + return err; + } + + return 0; + } + static int iproute_flush(int family, rtnl_filter_t filter_fn) { time_t start = time(0); @@@ -1635,7 -1648,7 +1659,7 @@@ filter.flushe = sizeof(flushb); for (;;) { - if (rtnl_routedump_req(&rth, family, NULL) < 0) { + if (rtnl_routedump_req(&rth, family, iproute_dump_filter) < 0) { perror("Cannot send dump request"); return -2; } @@@ -1675,30 -1688,6 +1699,6 @@@ } } - static int iproute_dump_filter(struct nlmsghdr *nlh, int reqlen) - { - struct rtmsg *rtm = NLMSG_DATA(nlh); - int err; - - rtm->rtm_protocol = filter.protocol; - if (filter.cloned) - rtm->rtm_flags |= RTM_F_CLONED; - - if (filter.tb) { - err = addattr32(nlh, reqlen, RTA_TABLE, filter.tb); - if (err) - return err; - } - - if (filter.oif) { - err = addattr32(nlh, reqlen, RTA_OIF, filter.oif); - if (err) - return err; - } - - return 0; - } - static int iproute_list_flush_or_save(int argc, char **argv, int action) { int dump_family = preferred_family; diff --combined misc/ss.c index e01ebf4d,3d9d1d8f..e1c665a5 --- a/misc/ss.c +++ b/misc/ss.c @@@ -106,6 -106,7 +106,6 @@@ static int security_get_initial_context } #endif -static int resolve_services = 1; int preferred_family = AF_UNSPEC; static int show_options; int show_details; @@@ -120,7 -121,6 +120,7 @@@ static int follow_events static int sctp_ino; static int show_tipcinfo; static int show_tos; +int numeric; int oneline; enum col_id { @@@ -1553,7 -1553,7 +1553,7 @@@ static const char *resolve_service(int return buf; } - if (!resolve_services) + if (numeric) goto do_numeric; if (dg_proto == RAW_PROTO) @@@ -2361,7 -2361,9 +2361,9 @@@ static int proc_inet_split_line(char *l static char *sprint_bw(char *buf, double bw) { - if (bw > 1000000.) + if (!resolve_services) + sprintf(buf, "%.0f", bw); + else if (bw > 1000000.) sprintf(buf, "%.1fM", bw / 1000000.); else if (bw > 1000.) sprintf(buf, "%.1fK", bw / 1000.); @@@ -4296,11 -4298,14 +4298,11 @@@ static int netlink_show_one(struct filt sock_state_print(&st); - if (resolve_services) - prot_name = nl_proto_n2a(prot, prot_buf, sizeof(prot_buf)); - else - prot_name = int_to_str(prot, prot_buf); + prot_name = nl_proto_n2a(prot, prot_buf, sizeof(prot_buf)); if (pid == -1) { procname[0] = '*'; - } else if (resolve_services) { + } else if (!numeric) { int done = 0; if (!pid) { @@@ -5047,7 -5052,7 +5049,7 @@@ int main(int argc, char *argv[] long_opts, NULL)) != EOF) { switch (ch) { case 'n': - resolve_services = 0; + numeric = 1; break; case 'r': resolve_hosts = 1; @@@ -5265,7 -5270,7 +5267,7 @@@ filter_states_set(¤t_filter, state_filter); filter_merge_defaults(¤t_filter); - if (resolve_services && resolve_hosts && + if (!numeric && resolve_hosts && (current_filter.dbs & (UNIX_DBM|INET_L4_DBM))) init_service_resolver(); diff --combined tc/q_netem.c index b85938f4,d1cd17f8..6d748f68 --- a/tc/q_netem.c +++ b/tc/q_netem.c @@@ -30,22 -30,22 +30,22 @@@ static void explain(void) { fprintf(stderr, -"Usage: ... netem [ limit PACKETS ]\n" \ -" [ delay TIME [ JITTER [CORRELATION]]]\n" \ -" [ distribution {uniform|normal|pareto|paretonormal} ]\n" \ -" [ corrupt PERCENT [CORRELATION]]\n" \ -" [ duplicate PERCENT [CORRELATION]]\n" \ -" [ loss random PERCENT [CORRELATION]]\n" \ -" [ loss state P13 [P31 [P32 [P23 P14]]]\n" \ -" [ loss gemodel PERCENT [R [1-H [1-K]]]\n" \ -" [ ecn ]\n" \ -" [ reorder PRECENT [CORRELATION] [ gap DISTANCE ]]\n" \ -" [ rate RATE [PACKETOVERHEAD] [CELLSIZE] [CELLOVERHEAD]]\n" \ -" [ slot MIN_DELAY [MAX_DELAY] [packets MAX_PACKETS]" \ -" [bytes MAX_BYTES]]\n" \ -" [ slot distribution" \ -" {uniform|normal|pareto|paretonormal|custom} DELAY JITTER" \ -" [packets MAX_PACKETS] [bytes MAX_BYTES]]\n"); + "Usage: ... netem [ limit PACKETS ]\n" \ + " [ delay TIME [ JITTER [CORRELATION]]]\n" \ + " [ distribution {uniform|normal|pareto|paretonormal} ]\n" \ + " [ corrupt PERCENT [CORRELATION]]\n" \ + " [ duplicate PERCENT [CORRELATION]]\n" \ + " [ loss random PERCENT [CORRELATION]]\n" \ + " [ loss state P13 [P31 [P32 [P23 P14]]]\n" \ + " [ loss gemodel PERCENT [R [1-H [1-K]]]\n" \ + " [ ecn ]\n" \ + " [ reorder PRECENT [CORRELATION] [ gap DISTANCE ]]\n" \ + " [ rate RATE [PACKETOVERHEAD] [CELLSIZE] [CELLOVERHEAD]]\n" \ + " [ slot MIN_DELAY [MAX_DELAY] [packets MAX_PACKETS]" \ + " [bytes MAX_BYTES]]\n" \ + " [ slot distribution" \ + " {uniform|normal|pareto|paretonormal|custom} DELAY JITTER" \ + " [packets MAX_PACKETS] [bytes MAX_BYTES]]\n"); } static void explain1(const char *arg) @@@ -58,43 -58,6 +58,43 @@@ */ #define MAX_DIST (16*1024) +/* Print values only if they are non-zero */ +static void __print_int_opt(const char *label_json, const char *label_fp, + int val) +{ + print_int(PRINT_ANY, label_json, val ? label_fp : "", val); +} +#define PRINT_INT_OPT(label, val) \ + __print_int_opt(label, " " label " %d", (val)) + +/* Time print prints normally with varying units, but for JSON prints + * in seconds (1ms vs 0.001). + */ +static void __print_time64(const char *label_json, const char *label_fp, + __u64 val) +{ + SPRINT_BUF(b1); + + print_string(PRINT_FP, NULL, label_fp, sprint_time64(val, b1)); + print_float(PRINT_JSON, label_json, NULL, val / 1000000000.); +} +#define __PRINT_TIME64(label_json, label_fp, val) \ + __print_time64(label_json, label_fp " %s", (val)) +#define PRINT_TIME64(label, val) __PRINT_TIME64(label, " " label, (val)) + +/* Percent print prints normally in percentage points, but for JSON prints + * an absolute value (1% vs 0.01). + */ +static void __print_percent(const char *label_json, const char *label_fp, + __u32 per) +{ + print_float(PRINT_FP, NULL, label_fp, (100. * per) / UINT32_MAX); + print_float(PRINT_JSON, label_json, NULL, (1. * per) / UINT32_MAX); +} +#define __PRINT_PERCENT(label_json, label_fp, per) \ + __print_percent(label_json, label_fp " %g%%", (per)) +#define PRINT_PERCENT(label, per) __PRINT_PERCENT(label, " " label, (per)) + /* scaled value used to percent of maximum. */ static void set_percent(__u32 *percent, double per) { @@@ -112,14 -75,15 +112,14 @@@ static int get_percent(__u32 *percent, return 0; } -static void print_percent(char *buf, int len, __u32 per) -{ - snprintf(buf, len, "%g%%", (100. * per) / UINT32_MAX); -} - -static char *sprint_percent(__u32 per, char *buf) +static void print_corr(bool present, __u32 value) { - print_percent(buf, SPRINT_BSIZE-1, per); - return buf; + if (!is_json_context()) { + if (present) + __PRINT_PERCENT("", "", value); + } else { + PRINT_PERCENT("correlation", value); + } } /* @@@ -320,14 -284,17 +320,17 @@@ static int netem_parse_opt(struct qdisc } } else if (!strcmp(*argv, "gemodel")) { + double p; + NEXT_ARG(); - if (get_percent(&gemodel.p, *argv)) { + if (parse_percent(&p, *argv)) { explain1("loss gemodel p"); return -1; } + set_percent(&gemodel.p, p); /* set defaults */ - set_percent(&gemodel.r, 1.); + set_percent(&gemodel.r, 1. - p); set_percent(&gemodel.h, 0); set_percent(&gemodel.k1, 0); loss_type = NETEM_LOSS_GE; @@@ -723,109 -690,97 +726,109 @@@ static int netem_print_opt(struct qdisc } } - fprintf(f, "limit %d", qopt.limit); + print_uint(PRINT_ANY, "limit", "limit %d", qopt.limit); if (qopt.latency) { - fprintf(f, " delay %s", sprint_ticks(qopt.latency, b1)); - - if (qopt.jitter) { - fprintf(f, " %s", sprint_ticks(qopt.jitter, b1)); - if (cor && cor->delay_corr) - fprintf(f, " %s", sprint_percent(cor->delay_corr, b1)); + open_json_object("delay"); + if (!is_json_context()) { + print_string(PRINT_FP, NULL, " delay %s", + sprint_ticks(qopt.latency, b1)); + + if (qopt.jitter) + print_string(PRINT_FP, NULL, " %s", + sprint_ticks(qopt.jitter, b1)); + } else { + print_float(PRINT_JSON, "delay", NULL, + tc_core_tick2time(qopt.latency) / + 1000000.); + print_float(PRINT_JSON, "jitter", NULL, + tc_core_tick2time(qopt.jitter) / + 1000000.); } + print_corr(qopt.jitter && cor && cor->delay_corr, + cor ? cor->delay_corr : 0); + close_json_object(); } if (qopt.loss) { - fprintf(f, " loss %s", sprint_percent(qopt.loss, b1)); - if (cor && cor->loss_corr) - fprintf(f, " %s", sprint_percent(cor->loss_corr, b1)); + open_json_object("loss-random"); + PRINT_PERCENT("loss", qopt.loss); + print_corr(cor && cor->loss_corr, cor ? cor->loss_corr : 0); + close_json_object(); } if (gimodel) { - fprintf(f, " loss state p13 %s", sprint_percent(gimodel->p13, b1)); - fprintf(f, " p31 %s", sprint_percent(gimodel->p31, b1)); - fprintf(f, " p32 %s", sprint_percent(gimodel->p32, b1)); - fprintf(f, " p23 %s", sprint_percent(gimodel->p23, b1)); - fprintf(f, " p14 %s", sprint_percent(gimodel->p14, b1)); + open_json_object("loss-state"); + __PRINT_PERCENT("p13", " loss state p13", gimodel->p13); + PRINT_PERCENT("p31", gimodel->p31); + PRINT_PERCENT("p32", gimodel->p32); + PRINT_PERCENT("p23", gimodel->p23); + PRINT_PERCENT("p14", gimodel->p14); + close_json_object(); } if (gemodel) { - fprintf(f, " loss gemodel p %s", - sprint_percent(gemodel->p, b1)); - fprintf(f, " r %s", sprint_percent(gemodel->r, b1)); - fprintf(f, " 1-h %s", sprint_percent(UINT32_MAX - - gemodel->h, b1)); - fprintf(f, " 1-k %s", sprint_percent(gemodel->k1, b1)); + open_json_object("loss-gemodel"); + __PRINT_PERCENT("p", " loss gemodel p", gemodel->p); + PRINT_PERCENT("r", gemodel->r); + PRINT_PERCENT("1-h", UINT32_MAX - gemodel->h); + PRINT_PERCENT("1-k", gemodel->k1); + close_json_object(); } if (qopt.duplicate) { - fprintf(f, " duplicate %s", - sprint_percent(qopt.duplicate, b1)); - if (cor && cor->dup_corr) - fprintf(f, " %s", sprint_percent(cor->dup_corr, b1)); + open_json_object("duplicate"); + PRINT_PERCENT("duplicate", qopt.duplicate); + print_corr(cor && cor->dup_corr, cor ? cor->dup_corr : 0); + close_json_object(); } if (reorder && reorder->probability) { - fprintf(f, " reorder %s", - sprint_percent(reorder->probability, b1)); - if (reorder->correlation) - fprintf(f, " %s", - sprint_percent(reorder->correlation, b1)); + open_json_object("reorder"); + PRINT_PERCENT("reorder", reorder->probability); + print_corr(reorder->correlation, reorder->correlation); + close_json_object(); } if (corrupt && corrupt->probability) { - fprintf(f, " corrupt %s", - sprint_percent(corrupt->probability, b1)); - if (corrupt->correlation) - fprintf(f, " %s", - sprint_percent(corrupt->correlation, b1)); + open_json_object("corrupt"); + PRINT_PERCENT("corrupt", corrupt->probability); + print_corr(corrupt->correlation, corrupt->correlation); + close_json_object(); } if (rate && rate->rate) { - 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) - fprintf(f, " cellsize %u", rate->cell_size); - if (rate->cell_overhead) - fprintf(f, " celloverhead %d", rate->cell_overhead); + open_json_object("rate"); + rate64 = rate64 ? : rate->rate; + print_string(PRINT_FP, NULL, " rate %s", + sprint_rate(rate64, b1)); + print_lluint(PRINT_JSON, "rate", NULL, rate64); + PRINT_INT_OPT("packetoverhead", rate->packet_overhead); + print_uint(PRINT_ANY, "cellsize", + rate->cell_size ? " cellsize %u" : "", + rate->cell_size); + PRINT_INT_OPT("celloverhead", rate->cell_overhead); + close_json_object(); } if (slot) { + open_json_object("slot"); if (slot->dist_jitter > 0) { - fprintf(f, " slot distribution %s", sprint_time64(slot->dist_delay, b1)); - fprintf(f, " %s", sprint_time64(slot->dist_jitter, b1)); + __PRINT_TIME64("distribution", " slot distribution", + slot->dist_delay); + __PRINT_TIME64("jitter", "", slot->dist_jitter); } else { - fprintf(f, " slot %s", sprint_time64(slot->min_delay, b1)); - fprintf(f, " %s", sprint_time64(slot->max_delay, b1)); + __PRINT_TIME64("min-delay", " slot", slot->min_delay); + __PRINT_TIME64("max-delay", "", slot->max_delay); } - if (slot->max_packets) - fprintf(f, " packets %d", slot->max_packets); - if (slot->max_bytes) - fprintf(f, " bytes %d", slot->max_bytes); + PRINT_INT_OPT("packets", slot->max_packets); + PRINT_INT_OPT("bytes", slot->max_bytes); + close_json_object(); } - if (ecn) - fprintf(f, " ecn "); - - if (qopt.gap) - fprintf(f, " gap %lu", (unsigned long)qopt.gap); - + print_bool(PRINT_ANY, "ecn", ecn ? " ecn " : "", ecn); + print_luint(PRINT_ANY, "gap", qopt.gap ? " gap %lu" : "", + (unsigned long)qopt.gap); return 0; }