From 7b0d424abef169ac259ce54de90d69237b5d2bda Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Wed, 4 Dec 2019 15:37:26 -0800 Subject: [PATCH 01/15] tc: do not output newline in oneline mode In oneline mode the line seperator should be \ but several parts of tc aren't doing it right. Signed-off-by: Stephen Hemminger Signed-off-by: David Ahern --- tc/f_flower.c | 66 +++++++++++++++++++++++++++++++---------------- tc/m_csum.c | 4 +-- tc/m_ct.c | 5 ++-- tc/m_gact.c | 8 +++--- tc/m_mirred.c | 5 ++-- tc/m_mpls.c | 3 ++- tc/m_pedit.c | 2 +- tc/m_simple.c | 2 +- tc/m_tunnel_key.c | 3 ++- tc/m_vlan.c | 5 ++-- tc/m_xt.c | 2 +- tc/q_cake.c | 4 +-- tc/q_fq_codel.c | 3 ++- tc/tc_filter.c | 4 +-- tc/tc_qdisc.c | 8 +++--- tc/tc_util.c | 2 +- 16 files changed, 78 insertions(+), 48 deletions(-) diff --git a/tc/f_flower.c b/tc/f_flower.c index a193c0ec..ce057a72 100644 --- a/tc/f_flower.c +++ b/tc/f_flower.c @@ -1624,7 +1624,8 @@ static void flower_print_eth_type(__be16 *p_eth_type, else sprintf(out, "%04x", ntohs(eth_type)); - print_string(PRINT_ANY, "eth_type", "\n eth_type %s", out); + print_nl(); + print_string(PRINT_ANY, "eth_type", " eth_type %s", out); *p_eth_type = eth_type; } @@ -1651,7 +1652,8 @@ static void flower_print_ip_proto(__u8 *p_ip_proto, else sprintf(out, "%02x", ip_proto); - print_string(PRINT_ANY, "ip_proto", "\n ip_proto %s", out); + print_nl(); + print_string(PRINT_ANY, "ip_proto", " ip_proto %s", out); *p_ip_proto = ip_proto; } @@ -1682,7 +1684,8 @@ static void flower_print_matching_flags(char *name, continue; if (mtf_mask & flags_str[i].flag) { if (++count == 1) { - print_string(PRINT_FP, NULL, "\n %s ", name); + print_nl(); + print_string(PRINT_FP, NULL, " %s ", name); open_json_object(name); } else { print_string(PRINT_FP, NULL, "/", NULL); @@ -1829,7 +1832,8 @@ static void flower_print_ct_state(struct rtattr *flags_attr, flower_ct_states[i].str); } - print_string(PRINT_ANY, "ct_state", "\n ct_state %s", out); + print_nl(); + print_string(PRINT_ANY, "ct_state", " ct_state %s", out); } static void flower_print_ct_label(struct rtattr *attr, @@ -1864,7 +1868,8 @@ static void flower_print_ct_label(struct rtattr *attr, } *p = '\0'; - print_string(PRINT_ANY, "ct_label", "\n ct_label %s", out); + print_nl(); + print_string(PRINT_ANY, "ct_label", " ct_label %s", out); } static void flower_print_ct_zone(struct rtattr *attr, @@ -1886,7 +1891,8 @@ static void flower_print_key_id(const char *name, struct rtattr *attr) if (!attr) return; - sprintf(namefrm,"\n %s %%u", name); + print_nl(); + sprintf(namefrm, " %s %%u", name); print_uint(PRINT_ANY, name, namefrm, rta_getattr_be32(attr)); } @@ -1934,7 +1940,7 @@ static void flower_print_geneve_opts(const char *name, struct rtattr *attr, static void flower_print_geneve_parts(const char *name, struct rtattr *attr, char *key, char *mask) { - char *namefrm = "\n geneve_opt %s"; + char *namefrm = " geneve_opt %s"; char *key_token, *mask_token, *out; int len; @@ -1952,6 +1958,7 @@ static void flower_print_geneve_parts(const char *name, struct rtattr *attr, } out[len - 1] = '\0'; + print_nl(); print_string(PRINT_FP, name, namefrm, out); free(out); } @@ -2015,7 +2022,8 @@ static void flower_print_masked_u8(const char *name, struct rtattr *attr, if (mask != UINT8_MAX) sprintf(out + done, "/%d", mask); - sprintf(namefrm,"\n %s %%s", name); + print_nl(); + sprintf(namefrm, " %s %%s", name); print_string(PRINT_ANY, name, namefrm, out); } @@ -2031,7 +2039,8 @@ static void flower_print_u32(const char *name, struct rtattr *attr) if (!attr) return; - sprintf(namefrm,"\n %s %%u", name); + print_nl(); + sprintf(namefrm, " %s %%u", name); print_uint(PRINT_ANY, name, namefrm, rta_getattr_u32(attr)); } @@ -2086,14 +2095,16 @@ static int flower_print_opt(struct filter_util *qu, FILE *f, if (tb[TCA_FLOWER_KEY_VLAN_ID]) { struct rtattr *attr = tb[TCA_FLOWER_KEY_VLAN_ID]; - print_uint(PRINT_ANY, "vlan_id", "\n vlan_id %u", + print_nl(); + print_uint(PRINT_ANY, "vlan_id", " vlan_id %u", rta_getattr_u16(attr)); } if (tb[TCA_FLOWER_KEY_VLAN_PRIO]) { struct rtattr *attr = tb[TCA_FLOWER_KEY_VLAN_PRIO]; - print_uint(PRINT_ANY, "vlan_prio", "\n vlan_prio %d", + print_nl(); + print_uint(PRINT_ANY, "vlan_prio", " vlan_prio %d", rta_getattr_u8(attr)); } @@ -2101,7 +2112,8 @@ static int flower_print_opt(struct filter_util *qu, FILE *f, SPRINT_BUF(buf); struct rtattr *attr = tb[TCA_FLOWER_KEY_VLAN_ETH_TYPE]; - print_string(PRINT_ANY, "vlan_ethtype", "\n vlan_ethtype %s", + print_nl(); + print_string(PRINT_ANY, "vlan_ethtype", " vlan_ethtype %s", ll_proto_n2a(rta_getattr_u16(attr), buf, sizeof(buf))); } @@ -2109,14 +2121,16 @@ static int flower_print_opt(struct filter_util *qu, FILE *f, if (tb[TCA_FLOWER_KEY_CVLAN_ID]) { struct rtattr *attr = tb[TCA_FLOWER_KEY_CVLAN_ID]; - print_uint(PRINT_ANY, "cvlan_id", "\n cvlan_id %u", + print_nl(); + print_uint(PRINT_ANY, "cvlan_id", " cvlan_id %u", rta_getattr_u16(attr)); } if (tb[TCA_FLOWER_KEY_CVLAN_PRIO]) { struct rtattr *attr = tb[TCA_FLOWER_KEY_CVLAN_PRIO]; - print_uint(PRINT_ANY, "cvlan_prio", "\n cvlan_prio %d", + print_nl(); + print_uint(PRINT_ANY, "cvlan_prio", " cvlan_prio %d", rta_getattr_u8(attr)); } @@ -2124,7 +2138,8 @@ static int flower_print_opt(struct filter_util *qu, FILE *f, SPRINT_BUF(buf); struct rtattr *attr = tb[TCA_FLOWER_KEY_CVLAN_ETH_TYPE]; - print_string(PRINT_ANY, "cvlan_ethtype", "\n cvlan_ethtype %s", + print_nl(); + print_string(PRINT_ANY, "cvlan_ethtype", " cvlan_ethtype %s", ll_proto_n2a(rta_getattr_u16(attr), buf, sizeof(buf))); } @@ -2254,13 +2269,18 @@ static int flower_print_opt(struct filter_util *qu, FILE *f, if (tb[TCA_FLOWER_FLAGS]) { __u32 flags = rta_getattr_u32(tb[TCA_FLOWER_FLAGS]); - if (flags & TCA_CLS_FLAGS_SKIP_HW) - print_bool(PRINT_ANY, "skip_hw", "\n skip_hw", true); - if (flags & TCA_CLS_FLAGS_SKIP_SW) - print_bool(PRINT_ANY, "skip_sw", "\n skip_sw", true); + if (flags & TCA_CLS_FLAGS_SKIP_HW) { + print_nl(); + print_bool(PRINT_ANY, "skip_hw", " skip_hw", true); + } + if (flags & TCA_CLS_FLAGS_SKIP_SW) { + print_nl(); + print_bool(PRINT_ANY, "skip_sw", " skip_sw", true); + } if (flags & TCA_CLS_FLAGS_IN_HW) { - print_bool(PRINT_ANY, "in_hw", "\n in_hw", true); + print_nl(); + print_bool(PRINT_ANY, "in_hw", " in_hw", true); if (tb[TCA_FLOWER_IN_HW_COUNT]) { __u32 count = rta_getattr_u32(tb[TCA_FLOWER_IN_HW_COUNT]); @@ -2269,8 +2289,10 @@ static int flower_print_opt(struct filter_util *qu, FILE *f, " in_hw_count %u", count); } } - else if (flags & TCA_CLS_FLAGS_NOT_IN_HW) - print_bool(PRINT_ANY, "not_in_hw", "\n not_in_hw", true); + else if (flags & TCA_CLS_FLAGS_NOT_IN_HW) { + print_nl(); + print_bool(PRINT_ANY, "not_in_hw", " not_in_hw", true); + } } if (tb[TCA_FLOWER_ACT]) diff --git a/tc/m_csum.c b/tc/m_csum.c index 3e3dc251..afbee9c8 100644 --- a/tc/m_csum.c +++ b/tc/m_csum.c @@ -205,7 +205,7 @@ print_csum(struct action_util *au, FILE *f, struct rtattr *arg) uflag_4, uflag_5, uflag_6, uflag_7); print_string(PRINT_ANY, "csum", "(%s) ", buf); - print_action_control(f, "action ", sel->action, "\n"); + print_action_control(f, "action ", sel->action, _SL_); print_uint(PRINT_ANY, "index", "\tindex %u", sel->index); print_int(PRINT_ANY, "ref", " ref %d", sel->refcnt); print_int(PRINT_ANY, "bind", " bind %d", sel->bindcnt); @@ -217,7 +217,7 @@ print_csum(struct action_util *au, FILE *f, struct rtattr *arg) print_tm(f, tm); } } - print_string(PRINT_FP, NULL, "%s", "\n"); + print_nl(); return 0; } diff --git a/tc/m_ct.c b/tc/m_ct.c index 45fa4a8c..70d186e8 100644 --- a/tc/m_ct.c +++ b/tc/m_ct.c @@ -473,7 +473,8 @@ static int print_ct(struct action_util *au, FILE *f, struct rtattr *arg) print_action_control(f, " ", p->action, ""); - print_uint(PRINT_ANY, "index", "\n\t index %u", p->index); + print_nl(); + print_uint(PRINT_ANY, "index", "\t index %u", p->index); print_int(PRINT_ANY, "ref", " ref %d", p->refcnt); print_int(PRINT_ANY, "bind", " bind %d", p->bindcnt); @@ -484,7 +485,7 @@ static int print_ct(struct action_util *au, FILE *f, struct rtattr *arg) print_tm(f, tm); } } - print_string(PRINT_FP, NULL, "%s", "\n "); + print_nl(); return 0; } diff --git a/tc/m_gact.c b/tc/m_gact.c index b06e8ee9..33f326f8 100644 --- a/tc/m_gact.c +++ b/tc/m_gact.c @@ -193,13 +193,15 @@ print_gact(struct action_util *au, FILE *f, struct rtattr *arg) pp = &pp_dummy; } open_json_object("prob"); - print_string(PRINT_ANY, "random_type", "\n\t random type %s", + print_nl(); + print_string(PRINT_ANY, "random_type", "\t random type %s", prob_n2a(pp->ptype)); print_action_control(f, " ", pp->paction, " "); print_int(PRINT_ANY, "val", "val %d", pp->pval); close_json_object(); #endif - print_uint(PRINT_ANY, "index", "\n\t index %u", p->index); + print_nl(); + print_uint(PRINT_ANY, "index", "\t index %u", p->index); print_int(PRINT_ANY, "ref", " ref %d", p->refcnt); print_int(PRINT_ANY, "bind", " bind %d", p->bindcnt); if (show_stats) { @@ -209,7 +211,7 @@ print_gact(struct action_util *au, FILE *f, struct rtattr *arg) print_tm(f, tm); } } - print_string(PRINT_FP, NULL, "%s", "\n"); + print_nl(); return 0; } diff --git a/tc/m_mirred.c b/tc/m_mirred.c index 13209523..d2bdf407 100644 --- a/tc/m_mirred.c +++ b/tc/m_mirred.c @@ -307,7 +307,8 @@ print_mirred(struct action_util *au, FILE *f, struct rtattr *arg) print_string(PRINT_ANY, "to_dev", " to device %s)", dev); print_action_control(f, " ", p->action, ""); - print_uint(PRINT_ANY, "index", "\n \tindex %u", p->index); + print_nl(); + print_uint(PRINT_ANY, "index", "\tindex %u", p->index); print_int(PRINT_ANY, "ref", " ref %d", p->refcnt); print_int(PRINT_ANY, "bind", " bind %d", p->bindcnt); @@ -318,7 +319,7 @@ print_mirred(struct action_util *au, FILE *f, struct rtattr *arg) print_tm(f, tm); } } - print_string(PRINT_FP, NULL, "%s", "\n "); + print_nl(); return 0; } diff --git a/tc/m_mpls.c b/tc/m_mpls.c index 4b1ec70e..6f3a39f4 100644 --- a/tc/m_mpls.c +++ b/tc/m_mpls.c @@ -252,7 +252,8 @@ static int print_mpls(struct action_util *au, FILE *f, struct rtattr *arg) } print_action_control(f, " ", parm->action, ""); - print_uint(PRINT_ANY, "index", "\n\t index %u", parm->index); + print_nl(); + print_uint(PRINT_ANY, "index", "\t index %u", parm->index); print_int(PRINT_ANY, "ref", " ref %d", parm->refcnt); print_int(PRINT_ANY, "bind", " bind %d", parm->bindcnt); diff --git a/tc/m_pedit.c b/tc/m_pedit.c index 1cd2d162..fccfd17c 100644 --- a/tc/m_pedit.c +++ b/tc/m_pedit.c @@ -820,7 +820,7 @@ static int print_pedit(struct action_util *au, FILE *f, struct rtattr *arg) sel->nkeys); } - fprintf(f, "\n "); + print_nl(); free(keys_ex); return 0; diff --git a/tc/m_simple.c b/tc/m_simple.c index 49e25047..70897d6b 100644 --- a/tc/m_simple.c +++ b/tc/m_simple.c @@ -194,7 +194,7 @@ static int print_simple(struct action_util *au, FILE *f, struct rtattr *arg) print_tm(f, tm); } } - fprintf(f, "\n"); + print_nl(); return 0; } diff --git a/tc/m_tunnel_key.c b/tc/m_tunnel_key.c index 4e65e444..8fde6891 100644 --- a/tc/m_tunnel_key.c +++ b/tc/m_tunnel_key.c @@ -420,7 +420,8 @@ static void tunnel_key_print_geneve_options(const char *name, uint8_t type; open_json_array(PRINT_JSON, name); - print_string(PRINT_FP, name, "\n\t%s ", "geneve_opt"); + print_nl(); + print_string(PRINT_FP, name, "\t%s ", "geneve_opt"); while (rem) { parse_rtattr(tb, TCA_TUNNEL_KEY_ENC_OPT_GENEVE_MAX, i, rem); diff --git a/tc/m_vlan.c b/tc/m_vlan.c index 9c8071e9..1096ba0f 100644 --- a/tc/m_vlan.c +++ b/tc/m_vlan.c @@ -219,7 +219,8 @@ static int print_vlan(struct action_util *au, FILE *f, struct rtattr *arg) } print_action_control(f, " ", parm->action, ""); - print_uint(PRINT_ANY, "index", "\n\t index %u", parm->index); + print_nl(); + print_uint(PRINT_ANY, "index", "\t index %u", parm->index); print_int(PRINT_ANY, "ref", " ref %d", parm->refcnt); print_int(PRINT_ANY, "bind", " bind %d", parm->bindcnt); @@ -231,7 +232,7 @@ static int print_vlan(struct action_util *au, FILE *f, struct rtattr *arg) } } - print_string(PRINT_FP, NULL, "%s", "\n"); + print_nl(); return 0; } diff --git a/tc/m_xt.c b/tc/m_xt.c index bf0db2be..487ba25a 100644 --- a/tc/m_xt.c +++ b/tc/m_xt.c @@ -391,7 +391,7 @@ print_ipt(struct action_util *au, FILE *f, struct rtattr *arg) print_tm(f, tm); } } - fprintf(f, "\n"); + print_nl(); xtables_free_opts(1); diff --git a/tc/q_cake.c b/tc/q_cake.c index 65ea07ef..3c78b176 100644 --- a/tc/q_cake.c +++ b/tc/q_cake.c @@ -766,7 +766,7 @@ static int cake_print_xstats(struct qdisc_util *qu, FILE *f, fprintf(f, " "); for (i = 0; i < num_tins; i++) fprintf(f, " Tin %u", i); - fprintf(f, "\n"); + fprintf(f, "%s", _SL_); }; #define GET_TSTAT(i, attr) (tstat[i][TCA_CAKE_TIN_STATS_ ## attr]) @@ -775,7 +775,7 @@ static int cake_print_xstats(struct qdisc_util *qu, FILE *f, fprintf(f, name); \ for (i = 0; i < num_tins; i++) \ fprintf(f, " %12" fmts, val); \ - fprintf(f, "\n"); \ + fprintf(f, "%s", _SL_); \ } \ } while (0) diff --git a/tc/q_fq_codel.c b/tc/q_fq_codel.c index 376ac50d..12ce3fbf 100644 --- a/tc/q_fq_codel.c +++ b/tc/q_fq_codel.c @@ -257,7 +257,8 @@ static int fq_codel_print_xstats(struct qdisc_util *qu, FILE *f, if (st->qdisc_stats.drop_overmemory) print_uint(PRINT_ANY, "drop_overmemory", " drop_overmemory %u", st->qdisc_stats.drop_overmemory); - print_uint(PRINT_ANY, "new_flows_len", "\n new_flows_len %u", + print_nl(); + print_uint(PRINT_ANY, "new_flows_len", " new_flows_len %u", st->qdisc_stats.new_flows_len); print_uint(PRINT_ANY, "old_flows_len", " old_flows_len %u", st->qdisc_stats.old_flows_len); diff --git a/tc/tc_filter.c b/tc/tc_filter.c index f7d2e4a6..dcddca77 100644 --- a/tc/tc_filter.c +++ b/tc/tc_filter.c @@ -364,11 +364,11 @@ int print_filter(struct nlmsghdr *n, void *arg) close_json_object(); } } - print_string(PRINT_FP, NULL, "\n", NULL); + print_nl(); if (show_stats && (tb[TCA_STATS] || tb[TCA_STATS2])) { print_tcstats_attr(fp, tb, " ", NULL); - print_string(PRINT_FP, NULL, "\n", NULL); + print_nl(); } close_json_object(); diff --git a/tc/tc_qdisc.c b/tc/tc_qdisc.c index 17e39983..75a14672 100644 --- a/tc/tc_qdisc.c +++ b/tc/tc_qdisc.c @@ -317,11 +317,11 @@ int print_qdisc(struct nlmsghdr *n, void *arg) } close_json_object(); - print_string(PRINT_FP, NULL, "\n", NULL); + print_nl(); if (show_details && tb[TCA_STAB]) { print_size_table(fp, " ", tb[TCA_STAB]); - print_string(PRINT_FP, NULL, "\n", NULL); + print_nl(); } if (show_stats) { @@ -329,12 +329,12 @@ int print_qdisc(struct nlmsghdr *n, void *arg) if (tb[TCA_STATS] || tb[TCA_STATS2] || tb[TCA_XSTATS]) { print_tcstats_attr(fp, tb, " ", &xstats); - print_string(PRINT_FP, NULL, "\n", NULL); + print_nl(); } if (q && xstats && q->print_xstats) { q->print_xstats(q, fp, xstats); - print_string(PRINT_FP, NULL, "\n", NULL); + print_nl(); } } close_json_object(); diff --git a/tc/tc_util.c b/tc/tc_util.c index 0e70632d..5f13d729 100644 --- a/tc/tc_util.c +++ b/tc/tc_util.c @@ -869,7 +869,7 @@ void print_tcstats2_attr(FILE *fp, struct rtattr *rta, char *prefix, struct rtat memcpy(&q, RTA_DATA(tbs[TCA_STATS_QUEUE]), MIN(RTA_PAYLOAD(tbs[TCA_STATS_QUEUE]), sizeof(q))); if (!tbs[TCA_STATS_RATE_EST]) - print_string(PRINT_FP, NULL, "\n", ""); + print_nl(); print_uint(PRINT_JSON, "backlog", NULL, q.backlog); print_string(PRINT_FP, NULL, "%s", prefix); print_string(PRINT_FP, NULL, "backlog %s", From 0486388a877aa579fb1446ec593a2b63c9ba3df6 Mon Sep 17 00:00:00 2001 From: Paolo Lungaroni Date: Fri, 6 Dec 2019 19:11:54 +0100 Subject: [PATCH 02/15] add support for table name in SRv6 End.DT* behaviors it allows to specify also the table name in addition to the table number in SRv6 End.DT* behaviors. To add an End.DT6 behavior route specifying the table by name: $ ip -6 route add 2001:db8::1 encap seg6local action End.DT6 table main dev eth0 The ip route show to print output this route: $ ip -6 route show 2001:db8::1 2001:db8::1 encap seg6local action End.DT6 table main dev eth0 metric 1024 pref medium The JSON output: $ ip -6 -j -p route show 2001:db8::1 [ { "dst": "2001:db8::1", "encap": "seg6local", "action": "End.DT6", "table": "main", "dev": "eth0", "metric": 1024, "flags": [ ], "pref": "medium" } ] Signed-off-by: Paolo Lungaroni Signed-off-by: David Ahern --- ip/iproute_lwtunnel.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/ip/iproute_lwtunnel.c b/ip/iproute_lwtunnel.c index 60f34a32..0d7d7149 100644 --- a/ip/iproute_lwtunnel.c +++ b/ip/iproute_lwtunnel.c @@ -229,6 +229,8 @@ static void print_encap_seg6local(FILE *fp, struct rtattr *encap) struct rtattr *tb[SEG6_LOCAL_MAX + 1]; int action; + SPRINT_BUF(b1); + parse_rtattr_nested(tb, SEG6_LOCAL_MAX, encap); if (!tb[SEG6_LOCAL_ACTION]) @@ -246,8 +248,9 @@ static void print_encap_seg6local(FILE *fp, struct rtattr *encap) } if (tb[SEG6_LOCAL_TABLE]) - print_uint(PRINT_ANY, "table", - "table %u ", rta_getattr_u32(tb[SEG6_LOCAL_TABLE])); + print_string(PRINT_ANY, "table", "table %s ", + rtnl_rttable_n2a(rta_getattr_u32(tb[SEG6_LOCAL_TABLE]), + b1, sizeof(b1))); if (tb[SEG6_LOCAL_NH4]) { print_string(PRINT_ANY, "nh4", @@ -654,7 +657,7 @@ static int parse_encap_seg6local(struct rtattr *rta, size_t len, int *argcp, NEXT_ARG(); if (table_ok++) duparg2("table", *argv); - get_u32(&table, *argv, 0); + rtnl_rttable_a2n(&table, *argv); ret = rta_addattr32(rta, len, SEG6_LOCAL_TABLE, table); } else if (strcmp(*argv, "nh4") == 0) { NEXT_ARG(); From 974f889c2d0f72adfbe3428afd58884e376d3750 Mon Sep 17 00:00:00 2001 From: David Ahern Date: Tue, 17 Dec 2019 16:25:26 +0000 Subject: [PATCH 03/15] Update kernel headers Update kernel headers to commit: 6f6dded1385c ("Merge branch 'WireGuard-CI-and-housekeeping'") Signed-off-by: David Ahern --- include/uapi/linux/if_bonding.h | 10 ++++++++++ include/uapi/linux/if_bridge.h | 10 ++++++++++ include/uapi/linux/if_link.h | 1 + 3 files changed, 21 insertions(+) diff --git a/include/uapi/linux/if_bonding.h b/include/uapi/linux/if_bonding.h index 790585f0..6829213a 100644 --- a/include/uapi/linux/if_bonding.h +++ b/include/uapi/linux/if_bonding.h @@ -95,6 +95,16 @@ #define BOND_XMIT_POLICY_ENCAP23 3 /* encapsulated layer 2+3 */ #define BOND_XMIT_POLICY_ENCAP34 4 /* encapsulated layer 3+4 */ +/* 802.3ad port state definitions (43.4.2.2 in the 802.3ad standard) */ +#define AD_STATE_LACP_ACTIVITY 0x1 +#define AD_STATE_LACP_TIMEOUT 0x2 +#define AD_STATE_AGGREGATION 0x4 +#define AD_STATE_SYNCHRONIZATION 0x8 +#define AD_STATE_COLLECTING 0x10 +#define AD_STATE_DISTRIBUTING 0x20 +#define AD_STATE_DEFAULTED 0x40 +#define AD_STATE_EXPIRED 0x80 + typedef struct ifbond { __s32 bond_mode; __s32 num_slaves; diff --git a/include/uapi/linux/if_bridge.h b/include/uapi/linux/if_bridge.h index 31fc51bd..9fefc7f3 100644 --- a/include/uapi/linux/if_bridge.h +++ b/include/uapi/linux/if_bridge.h @@ -156,6 +156,15 @@ struct bridge_vlan_xstats { __u32 pad2; }; +struct bridge_stp_xstats { + __u64 transition_blk; + __u64 transition_fwd; + __u64 rx_bpdu; + __u64 tx_bpdu; + __u64 rx_tcn; + __u64 tx_tcn; +}; + /* Bridge multicast database attributes * [MDBA_MDB] = { * [MDBA_MDB_ENTRY] = { @@ -262,6 +271,7 @@ enum { BRIDGE_XSTATS_VLAN, BRIDGE_XSTATS_MCAST, BRIDGE_XSTATS_PAD, + BRIDGE_XSTATS_STP, __BRIDGE_XSTATS_MAX }; #define BRIDGE_XSTATS_MAX (__BRIDGE_XSTATS_MAX - 1) diff --git a/include/uapi/linux/if_link.h b/include/uapi/linux/if_link.h index 1c49f436..29eac87e 100644 --- a/include/uapi/linux/if_link.h +++ b/include/uapi/linux/if_link.h @@ -169,6 +169,7 @@ enum { IFLA_MAX_MTU, IFLA_PROP_LIST, IFLA_ALT_IFNAME, /* Alternative ifname */ + IFLA_PERM_ADDRESS, __IFLA_MAX }; From 2b8e6995fe36b5863c394ddf6444eb4163c8c83c Mon Sep 17 00:00:00 2001 From: Michal Kubecek Date: Sun, 15 Dec 2019 22:06:10 +0100 Subject: [PATCH 04/15] ip link: show permanent hardware address Display permanent hardware address of an interface in output of "ip link show" and "ip addr show". To reduce noise, permanent address is only shown if it is different from current one. Signed-off-by: Michal Kubecek Signed-off-by: David Ahern --- ip/ipaddress.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/ip/ipaddress.c b/ip/ipaddress.c index 964f14df..9415d768 100644 --- a/ip/ipaddress.c +++ b/ip/ipaddress.c @@ -1011,6 +1011,24 @@ int print_linkinfo(struct nlmsghdr *n, void *arg) ifi->ifi_type, b1, sizeof(b1))); } + if (tb[IFLA_PERM_ADDRESS]) { + unsigned int len = RTA_PAYLOAD(tb[IFLA_PERM_ADDRESS]); + + if (!tb[IFLA_ADDRESS] || + RTA_PAYLOAD(tb[IFLA_ADDRESS]) != len || + memcmp(RTA_DATA(tb[IFLA_PERM_ADDRESS]), + RTA_DATA(tb[IFLA_ADDRESS]), len)) { + print_string(PRINT_FP, NULL, " permaddr ", NULL); + print_color_string(PRINT_ANY, + COLOR_MAC, + "permaddr", + "%s", + ll_addr_n2a(RTA_DATA(tb[IFLA_PERM_ADDRESS]), + RTA_PAYLOAD(tb[IFLA_PERM_ADDRESS]), + ifi->ifi_type, + b1, sizeof(b1))); + } + } } if (tb[IFLA_LINK_NETNSID]) { From 0dcf36db1a785f5ca274fc1ab192e34569844250 Mon Sep 17 00:00:00 2001 From: Vivien Didelot Date: Wed, 11 Dec 2019 20:07:11 -0500 Subject: [PATCH 05/15] iplink: add support for STP xstats Add support for the BRIDGE_XSTATS_STP xstats, as follow: # ip link xstats type bridge_slave dev lan4 stp lan4 STP BPDU: RX: 0 TX: 61 STP TCN: RX: 0 TX: 0 STP Transitions: Blocked: 2 Forwarding: 1 Or below as JSON: # ip -j -p link xstats type bridge_slave dev lan0 stp [ { "ifname": "lan0", "stp": { "rx_bpdu": 0, "tx_bpdu": 500, "rx_tcn": 0, "tx_tcn": 0, "transition_blk": 0, "transition_fwd": 0 } } ] Signed-off-by: Vivien Didelot Signed-off-by: David Ahern --- ip/iplink_bridge.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/ip/iplink_bridge.c b/ip/iplink_bridge.c index 06f736d4..bbd6f3a8 100644 --- a/ip/iplink_bridge.c +++ b/ip/iplink_bridge.c @@ -688,6 +688,7 @@ static void bridge_print_xstats_help(struct link_util *lu, FILE *f) static void bridge_print_stats_attr(struct rtattr *attr, int ifindex) { struct rtattr *brtb[LINK_XSTATS_TYPE_MAX+1]; + struct bridge_stp_xstats *sstats; struct br_mcast_stats *mstats; struct rtattr *i, *list; const char *ifname = ""; @@ -807,6 +808,29 @@ static void bridge_print_stats_attr(struct rtattr *attr, int ifindex) mstats->mld_parse_errors); close_json_object(); break; + case BRIDGE_XSTATS_STP: + sstats = RTA_DATA(i); + open_json_object("stp"); + print_string(PRINT_FP, NULL, + "%-16s STP BPDU: ", ""); + print_u64(PRINT_ANY, "rx_bpdu", "RX: %llu ", + sstats->rx_bpdu); + print_u64(PRINT_ANY, "tx_bpdu", "TX: %llu\n", + sstats->tx_bpdu); + print_string(PRINT_FP, NULL, + "%-16s STP TCN: ", ""); + print_u64(PRINT_ANY, "rx_tcn", "RX: %llu ", + sstats->rx_tcn); + print_u64(PRINT_ANY, "tx_tcn", "TX: %llu\n", + sstats->tx_tcn); + print_string(PRINT_FP, NULL, + "%-16s STP Transitions: ", ""); + print_u64(PRINT_ANY, "transition_blk", "Blocked: %llu ", + sstats->transition_blk); + print_u64(PRINT_ANY, "transition_fwd", "Forwarding: %llu\n", + sstats->transition_fwd); + close_json_object(); + break; } } close_json_object(); @@ -843,6 +867,8 @@ int bridge_parse_xstats(struct link_util *lu, int argc, char **argv) while (argc > 0) { if (strcmp(*argv, "igmp") == 0 || strcmp(*argv, "mcast") == 0) { xstats_print_attr = BRIDGE_XSTATS_MCAST; + } else if (strcmp(*argv, "stp") == 0) { + xstats_print_attr = BRIDGE_XSTATS_STP; } else if (strcmp(*argv, "dev") == 0) { NEXT_ARG(); filter_index = ll_name_to_index(*argv); From a6cf98c23fc692c3816bf4c0ecc221c125a6e169 Mon Sep 17 00:00:00 2001 From: David Ahern Date: Thu, 2 Jan 2020 17:26:50 +0000 Subject: [PATCH 06/15] Update kernel headers Update kernel headers to commit: fe23d63422c8 Merge branch '1GbE' of git://git.kernel.org/pub/scm/linux/kernel/git/jkirsher/next-queue Signed-off-by: David Ahern --- include/uapi/linux/bpf.h | 10 ++++++++++ include/uapi/linux/btf.h | 3 ++- include/uapi/linux/if_bonding.h | 16 ++++++++-------- include/uapi/linux/pkt_sched.h | 17 +++++++++++++++++ include/uapi/linux/tipc_netlink.h | 2 ++ 5 files changed, 39 insertions(+), 9 deletions(-) diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h index 913d6df5..3e3f6e8d 100644 --- a/include/uapi/linux/bpf.h +++ b/include/uapi/linux/bpf.h @@ -231,6 +231,11 @@ enum bpf_attach_type { * When children program makes decision (like picking TCP CA or sock bind) * parent program has a chance to override it. * + * With BPF_F_ALLOW_MULTI a new program is added to the end of the list of + * programs for a cgroup. Though it's possible to replace an old program at + * any position by also specifying BPF_F_REPLACE flag and position itself in + * replace_bpf_fd attribute. Old program at this position will be released. + * * A cgroup with MULTI or OVERRIDE flag allows any attach flags in sub-cgroups. * A cgroup with NONE doesn't allow any programs in sub-cgroups. * Ex1: @@ -249,6 +254,7 @@ enum bpf_attach_type { */ #define BPF_F_ALLOW_OVERRIDE (1U << 0) #define BPF_F_ALLOW_MULTI (1U << 1) +#define BPF_F_REPLACE (1U << 2) /* If BPF_F_STRICT_ALIGNMENT is used in BPF_PROG_LOAD command, the * verifier will perform strict alignment checking as if the kernel @@ -442,6 +448,10 @@ union bpf_attr { __u32 attach_bpf_fd; /* eBPF program to attach */ __u32 attach_type; __u32 attach_flags; + __u32 replace_bpf_fd; /* previously attached eBPF + * program to replace if + * BPF_F_REPLACE is used + */ }; struct { /* anonymous struct used by BPF_PROG_TEST_RUN command */ diff --git a/include/uapi/linux/btf.h b/include/uapi/linux/btf.h index d28dd89a..7467223d 100644 --- a/include/uapi/linux/btf.h +++ b/include/uapi/linux/btf.h @@ -142,7 +142,8 @@ struct btf_param { enum { BTF_VAR_STATIC = 0, - BTF_VAR_GLOBAL_ALLOCATED, + BTF_VAR_GLOBAL_ALLOCATED = 1, + BTF_VAR_GLOBAL_EXTERN = 2, }; /* BTF_KIND_VAR is followed by a single "struct btf_var" to describe diff --git a/include/uapi/linux/if_bonding.h b/include/uapi/linux/if_bonding.h index 6829213a..45f3750a 100644 --- a/include/uapi/linux/if_bonding.h +++ b/include/uapi/linux/if_bonding.h @@ -96,14 +96,14 @@ #define BOND_XMIT_POLICY_ENCAP34 4 /* encapsulated layer 3+4 */ /* 802.3ad port state definitions (43.4.2.2 in the 802.3ad standard) */ -#define AD_STATE_LACP_ACTIVITY 0x1 -#define AD_STATE_LACP_TIMEOUT 0x2 -#define AD_STATE_AGGREGATION 0x4 -#define AD_STATE_SYNCHRONIZATION 0x8 -#define AD_STATE_COLLECTING 0x10 -#define AD_STATE_DISTRIBUTING 0x20 -#define AD_STATE_DEFAULTED 0x40 -#define AD_STATE_EXPIRED 0x80 +#define LACP_STATE_LACP_ACTIVITY 0x1 +#define LACP_STATE_LACP_TIMEOUT 0x2 +#define LACP_STATE_AGGREGATION 0x4 +#define LACP_STATE_SYNCHRONIZATION 0x8 +#define LACP_STATE_COLLECTING 0x10 +#define LACP_STATE_DISTRIBUTING 0x20 +#define LACP_STATE_DEFAULTED 0x40 +#define LACP_STATE_EXPIRED 0x80 typedef struct ifbond { __s32 bond_mode; diff --git a/include/uapi/linux/pkt_sched.h b/include/uapi/linux/pkt_sched.h index 9f1a7287..bf5a5b1d 100644 --- a/include/uapi/linux/pkt_sched.h +++ b/include/uapi/linux/pkt_sched.h @@ -1187,4 +1187,21 @@ enum { #define TCA_TAPRIO_ATTR_MAX (__TCA_TAPRIO_ATTR_MAX - 1) +/* ETS */ + +#define TCQ_ETS_MAX_BANDS 16 + +enum { + TCA_ETS_UNSPEC, + TCA_ETS_NBANDS, /* u8 */ + TCA_ETS_NSTRICT, /* u8 */ + TCA_ETS_QUANTA, /* nested TCA_ETS_QUANTA_BAND */ + TCA_ETS_QUANTA_BAND, /* u32 */ + TCA_ETS_PRIOMAP, /* nested TCA_ETS_PRIOMAP_BAND */ + TCA_ETS_PRIOMAP_BAND, /* u8 */ + __TCA_ETS_MAX, +}; + +#define TCA_ETS_MAX (__TCA_ETS_MAX - 1) + #endif diff --git a/include/uapi/linux/tipc_netlink.h b/include/uapi/linux/tipc_netlink.h index 6c2194ab..dc0d23a5 100644 --- a/include/uapi/linux/tipc_netlink.h +++ b/include/uapi/linux/tipc_netlink.h @@ -65,6 +65,7 @@ enum { TIPC_NL_UDP_GET_REMOTEIP, TIPC_NL_KEY_SET, TIPC_NL_KEY_FLUSH, + TIPC_NL_ADDR_LEGACY_GET, __TIPC_NL_CMD_MAX, TIPC_NL_CMD_MAX = __TIPC_NL_CMD_MAX - 1 @@ -176,6 +177,7 @@ enum { TIPC_NLA_NET_ADDR, /* u32 */ TIPC_NLA_NET_NODEID, /* u64 */ TIPC_NLA_NET_NODEID_W1, /* u64 */ + TIPC_NLA_NET_ADDR_LEGACY, /* flag */ __TIPC_NLA_NET_MAX, TIPC_NLA_NET_MAX = __TIPC_NLA_NET_MAX - 1 From 39ac2d2b802b42ae460e84cc3fb971ceafb2b4d2 Mon Sep 17 00:00:00 2001 From: Andy Roulin Date: Tue, 31 Dec 2019 04:15:02 -0800 Subject: [PATCH 07/15] iplink: bond: print lacp actor/partner oper states as strings The 802.3ad/LACP actor/partner operating states are only printed as numbers, e.g, ad_actor_oper_port_state 15 Add an additional output in ip link show that prints a string describing the individual 3ad bit meanings in the following way: ad_actor_oper_port_state_str JSON output is also supported, the field becomes a json array: "ad_actor_oper_port_state_str": ["active","short_timeout","aggregating","in_sync"] Signed-off-by: Andy Roulin Signed-off-by: David Ahern --- ip/iplink_bond_slave.c | 36 ++++++++++++++++++++++++++++++++---- 1 file changed, 32 insertions(+), 4 deletions(-) diff --git a/ip/iplink_bond_slave.c b/ip/iplink_bond_slave.c index 4eaf72b8..d488aaab 100644 --- a/ip/iplink_bond_slave.c +++ b/ip/iplink_bond_slave.c @@ -68,6 +68,26 @@ static void print_slave_mii_status(FILE *f, struct rtattr *tb) slave_mii_status[status]); } +static void print_slave_oper_state(FILE *fp, const char *name, __u16 state) +{ + open_json_array(PRINT_ANY, name); + print_string(PRINT_FP, NULL, " <", NULL); +#define _PF(s, str) if (state & LACP_STATE_##s) { \ + state &= ~LACP_STATE_##s; \ + print_string(PRINT_ANY, NULL, \ + state ? "%s," : "%s", str); } + _PF(LACP_ACTIVITY, "active"); + _PF(LACP_TIMEOUT, "short_timeout"); + _PF(AGGREGATION, "aggregating"); + _PF(SYNCHRONIZATION, "in_sync"); + _PF(COLLECTING, "collecting"); + _PF(DISTRIBUTING, "distributing"); + _PF(DEFAULTED, "defaulted"); + _PF(EXPIRED, "expired"); +#undef _PF + close_json_array(PRINT_ANY, "> "); +} + static void bond_slave_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[]) { SPRINT_BUF(b1); @@ -106,17 +126,25 @@ static void bond_slave_print_opt(struct link_util *lu, FILE *f, struct rtattr *t "ad_aggregator_id %d ", rta_getattr_u16(tb[IFLA_BOND_SLAVE_AD_AGGREGATOR_ID])); - if (tb[IFLA_BOND_SLAVE_AD_ACTOR_OPER_PORT_STATE]) + if (tb[IFLA_BOND_SLAVE_AD_ACTOR_OPER_PORT_STATE]) { + __u8 state = rta_getattr_u8(tb[IFLA_BOND_SLAVE_AD_ACTOR_OPER_PORT_STATE]); + print_int(PRINT_ANY, "ad_actor_oper_port_state", "ad_actor_oper_port_state %d ", - rta_getattr_u8(tb[IFLA_BOND_SLAVE_AD_ACTOR_OPER_PORT_STATE])); + state); + print_slave_oper_state(f, "ad_actor_oper_port_state_str", state); + } + + if (tb[IFLA_BOND_SLAVE_AD_PARTNER_OPER_PORT_STATE]) { + __u16 state = rta_getattr_u8(tb[IFLA_BOND_SLAVE_AD_PARTNER_OPER_PORT_STATE]); - if (tb[IFLA_BOND_SLAVE_AD_PARTNER_OPER_PORT_STATE]) print_int(PRINT_ANY, "ad_partner_oper_port_state", "ad_partner_oper_port_state %d ", - rta_getattr_u16(tb[IFLA_BOND_SLAVE_AD_PARTNER_OPER_PORT_STATE])); + state); + print_slave_oper_state(f, "ad_partner_oper_port_state_str", state); + } } static int bond_slave_parse_opt(struct link_util *lu, int argc, char **argv, From c4f58629945898722ad9078e0f407c96f1ec7d2b Mon Sep 17 00:00:00 2001 From: Peter Junos Date: Thu, 26 Dec 2019 14:07:09 +0100 Subject: [PATCH 08/15] ss: use compact output for undetected screen width This change fixes calculation of width in case user pipes the output. SS output output works correctly when stdout is a terminal. When one pipes the output, it tries to use 80 or 160 columns. That adds a line-break if user has terminal width of 100 chars and output is of the similar width. No width is assumed here. To reproduce the issue, call ss | less and see every other line empty if your screen is between 80 and 160 columns wide. This second version of the patch fixes screen_width being set to arbitrary value. Signed-off-by: Peter Junos Signed-off-by: David Ahern --- misc/ss.c | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/misc/ss.c b/misc/ss.c index 95f1d37a..378b985c 100644 --- a/misc/ss.c +++ b/misc/ss.c @@ -1135,10 +1135,10 @@ static void buf_free_all(void) buffer.chunks = 0; } -/* Get current screen width, default to 80 columns if TIOCGWINSZ fails */ +/* Get current screen width, returns -1 if TIOCGWINSZ fails */ static int render_screen_width(void) { - int width = 80; + int width = -1; if (isatty(STDOUT_FILENO)) { struct winsize w; @@ -1159,9 +1159,15 @@ static int render_screen_width(void) */ static void render_calc_width(void) { - int screen_width = render_screen_width(); + int screen_width, first, len = 0, linecols = 0; struct column *c, *eol = columns - 1; - int first, len = 0, linecols = 0; + bool compact_output = false; + + screen_width = render_screen_width(); + if (screen_width == -1) { + screen_width = INT_MAX; + compact_output = true; + } /* First pass: set width for each column to measured content length */ for (first = 1, c = columns; c - columns < COL_MAX; c++) { @@ -1183,6 +1189,11 @@ static void render_calc_width(void) first = 0; } + if (compact_output) { + /* Compact output, skip extending columns. */ + return; + } + /* Second pass: find out newlines and distribute available spacing */ for (c = columns; c - columns < COL_MAX; c++) { int pad, spacing, rem, last; From 8b802d20e41db92a56497a4897f487aca0396718 Mon Sep 17 00:00:00 2001 From: David Ahern Date: Sat, 18 Jan 2020 21:39:15 +0000 Subject: [PATCH 09/15] Update kernel headers Update kernel headers to commit 9aaa29494030 ("Merge branch '1GbE' of git://git.kernel.org/pub/scm/linux/kernel/git/jkirsher/next-queue") Signed-off-by: David Ahern --- include/uapi/linux/if_bridge.h | 29 +++++++++++++++++++++++++++++ include/uapi/linux/if_link.h | 7 +++++++ include/uapi/linux/if_macsec.h | 11 +++++++++++ include/uapi/linux/in.h | 2 ++ include/uapi/linux/rtnetlink.h | 11 +++++++++++ include/uapi/linux/tcp.h | 5 +++-- 6 files changed, 63 insertions(+), 2 deletions(-) diff --git a/include/uapi/linux/if_bridge.h b/include/uapi/linux/if_bridge.h index 9fefc7f3..18e8f3c4 100644 --- a/include/uapi/linux/if_bridge.h +++ b/include/uapi/linux/if_bridge.h @@ -165,6 +165,35 @@ struct bridge_stp_xstats { __u64 tx_tcn; }; +/* Bridge vlan RTM header */ +struct br_vlan_msg { + __u8 family; + __u8 reserved1; + __u16 reserved2; + __u32 ifindex; +}; + +/* Bridge vlan RTM attributes + * [BRIDGE_VLANDB_ENTRY] = { + * [BRIDGE_VLANDB_ENTRY_INFO] + * ... + * } + */ +enum { + BRIDGE_VLANDB_UNSPEC, + BRIDGE_VLANDB_ENTRY, + __BRIDGE_VLANDB_MAX, +}; +#define BRIDGE_VLANDB_MAX (__BRIDGE_VLANDB_MAX - 1) + +enum { + BRIDGE_VLANDB_ENTRY_UNSPEC, + BRIDGE_VLANDB_ENTRY_INFO, + BRIDGE_VLANDB_ENTRY_RANGE, + __BRIDGE_VLANDB_ENTRY_MAX, +}; +#define BRIDGE_VLANDB_ENTRY_MAX (__BRIDGE_VLANDB_ENTRY_MAX - 1) + /* Bridge multicast database attributes * [MDBA_MDB] = { * [MDBA_MDB_ENTRY] = { diff --git a/include/uapi/linux/if_link.h b/include/uapi/linux/if_link.h index 29eac87e..533abd2c 100644 --- a/include/uapi/linux/if_link.h +++ b/include/uapi/linux/if_link.h @@ -484,6 +484,13 @@ enum macsec_validation_type { MACSEC_VALIDATE_MAX = __MACSEC_VALIDATE_END - 1, }; +enum macsec_offload { + MACSEC_OFFLOAD_OFF = 0, + MACSEC_OFFLOAD_PHY = 1, + __MACSEC_OFFLOAD_END, + MACSEC_OFFLOAD_MAX = __MACSEC_OFFLOAD_END - 1, +}; + /* IPVLAN section */ enum { IFLA_IPVLAN_UNSPEC, diff --git a/include/uapi/linux/if_macsec.h b/include/uapi/linux/if_macsec.h index 77439932..33c32051 100644 --- a/include/uapi/linux/if_macsec.h +++ b/include/uapi/linux/if_macsec.h @@ -45,6 +45,7 @@ enum macsec_attrs { MACSEC_ATTR_RXSC_LIST, /* dump, nested, macsec_rxsc_attrs for each RXSC */ MACSEC_ATTR_TXSC_STATS, /* dump, nested, macsec_txsc_stats_attr */ MACSEC_ATTR_SECY_STATS, /* dump, nested, macsec_secy_stats_attr */ + MACSEC_ATTR_OFFLOAD, /* config, nested, macsec_offload_attrs */ __MACSEC_ATTR_END, NUM_MACSEC_ATTR = __MACSEC_ATTR_END, MACSEC_ATTR_MAX = __MACSEC_ATTR_END - 1, @@ -97,6 +98,15 @@ enum macsec_sa_attrs { MACSEC_SA_ATTR_MAX = __MACSEC_SA_ATTR_END - 1, }; +enum macsec_offload_attrs { + MACSEC_OFFLOAD_ATTR_UNSPEC, + MACSEC_OFFLOAD_ATTR_TYPE, /* config/dump, u8 0..2 */ + MACSEC_OFFLOAD_ATTR_PAD, + __MACSEC_OFFLOAD_ATTR_END, + NUM_MACSEC_OFFLOAD_ATTR = __MACSEC_OFFLOAD_ATTR_END, + MACSEC_OFFLOAD_ATTR_MAX = __MACSEC_OFFLOAD_ATTR_END - 1, +}; + enum macsec_nl_commands { MACSEC_CMD_GET_TXSC, MACSEC_CMD_ADD_RXSC, @@ -108,6 +118,7 @@ enum macsec_nl_commands { MACSEC_CMD_ADD_RXSA, MACSEC_CMD_DEL_RXSA, MACSEC_CMD_UPD_RXSA, + MACSEC_CMD_UPD_OFFLOAD, }; /* u64 per-RXSC stats */ diff --git a/include/uapi/linux/in.h b/include/uapi/linux/in.h index ac079abc..83a4c187 100644 --- a/include/uapi/linux/in.h +++ b/include/uapi/linux/in.h @@ -76,6 +76,8 @@ enum { #define IPPROTO_MPLS IPPROTO_MPLS IPPROTO_RAW = 255, /* Raw IP packets */ #define IPPROTO_RAW IPPROTO_RAW + IPPROTO_MPTCP = 262, /* Multipath TCP connection */ +#define IPPROTO_MPTCP IPPROTO_MPTCP IPPROTO_MAX }; #endif diff --git a/include/uapi/linux/rtnetlink.h b/include/uapi/linux/rtnetlink.h index 4b93791c..9d802cd7 100644 --- a/include/uapi/linux/rtnetlink.h +++ b/include/uapi/linux/rtnetlink.h @@ -171,6 +171,13 @@ enum { RTM_GETLINKPROP, #define RTM_GETLINKPROP RTM_GETLINKPROP + RTM_NEWVLAN = 112, +#define RTM_NEWNVLAN RTM_NEWVLAN + RTM_DELVLAN, +#define RTM_DELVLAN RTM_DELVLAN + RTM_GETVLAN, +#define RTM_GETVLAN RTM_GETVLAN + __RTM_MAX, #define RTM_MAX (((__RTM_MAX + 3) & ~3) - 1) }; @@ -309,6 +316,8 @@ enum rt_scope_t { #define RTM_F_PREFIX 0x800 /* Prefix addresses */ #define RTM_F_LOOKUP_TABLE 0x1000 /* set rtm_table to FIB lookup result */ #define RTM_F_FIB_MATCH 0x2000 /* return full fib lookup match */ +#define RTM_F_OFFLOAD 0x4000 /* route is offloaded */ +#define RTM_F_TRAP 0x8000 /* route is trapping packets */ /* Reserved table identifiers */ @@ -719,6 +728,8 @@ enum rtnetlink_groups { #define RTNLGRP_IPV6_MROUTE_R RTNLGRP_IPV6_MROUTE_R RTNLGRP_NEXTHOP, #define RTNLGRP_NEXTHOP RTNLGRP_NEXTHOP + RTNLGRP_BRVLAN, +#define RTNLGRP_BRVLAN RTNLGRP_BRVLAN __RTNLGRP_MAX }; #define RTNLGRP_MAX (__RTNLGRP_MAX - 1) diff --git a/include/uapi/linux/tcp.h b/include/uapi/linux/tcp.h index 9415cb9f..0a2c423e 100644 --- a/include/uapi/linux/tcp.h +++ b/include/uapi/linux/tcp.h @@ -317,14 +317,15 @@ enum { #define TCP_MD5SIG_MAXKEYLEN 80 /* tcp_md5sig extension flags for TCP_MD5SIG_EXT */ -#define TCP_MD5SIG_FLAG_PREFIX 1 /* address prefix length */ +#define TCP_MD5SIG_FLAG_PREFIX 0x1 /* address prefix length */ +#define TCP_MD5SIG_FLAG_IFINDEX 0x2 /* ifindex set */ struct tcp_md5sig { struct __kernel_sockaddr_storage tcpm_addr; /* address associated */ __u8 tcpm_flags; /* extension flags */ __u8 tcpm_prefixlen; /* address prefix */ __u16 tcpm_keylen; /* key length */ - __u32 __tcpm_pad; /* zero */ + int tcpm_ifindex; /* device index for scope */ __u8 tcpm_key[TCP_MD5SIG_MAXKEYLEN]; /* key (binary) */ }; From ed81a2a040a9af811b098cbb8cf026afd698bdbe Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Thu, 16 Jan 2020 20:43:48 +0200 Subject: [PATCH 10/15] ip route: Print "rt_offload" and "rt_trap" indication The kernel now signals the offload state of a route using the 'RTM_F_OFFLOAD' and 'RTM_F_TRAP' flags. Print these to help users understand the offload state of each route. The "rt_" prefix is used in order to distinguish it from the offload state of nexthops. Signed-off-by: Ido Schimmel Signed-off-by: David Ahern --- ip/iproute.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ip/iproute.c b/ip/iproute.c index 32bb52df..93b805c9 100644 --- a/ip/iproute.c +++ b/ip/iproute.c @@ -368,6 +368,10 @@ void print_rt_flags(FILE *fp, unsigned int flags) print_string(PRINT_ANY, NULL, "%s ", "linkdown"); if (flags & RTNH_F_UNRESOLVED) print_string(PRINT_ANY, NULL, "%s ", "unresolved"); + if (flags & RTM_F_OFFLOAD) + print_string(PRINT_ANY, NULL, "%s ", "rt_offload"); + if (flags & RTM_F_TRAP) + print_string(PRINT_ANY, NULL, "%s ", "rt_trap"); close_json_array(PRINT_JSON, NULL); } From 0da4cfaa5d57a0329357a256eb9e92020e1fcd07 Mon Sep 17 00:00:00 2001 From: Petr Machata Date: Mon, 13 Jan 2020 15:16:28 +0100 Subject: [PATCH 11/15] libnetlink: parse_rtattr_nested should allow NLA_F_NESTED flag In kernel commit 8cb081746c03 ("netlink: make validation more configurable for future strictness"), Linux started implicitly flagging nests with NLA_F_NESTED, unless the nest is created with nla_nest_start_noflag(). The ETS code uses nla_nest_start() where possible, so it does not work with the current iproute2 code. Have libnetlink catch up by admitting the flag in the attribute. Signed-off-by: Petr Machata Reviewed-by: Jiri Pirko Signed-off-by: David Ahern --- include/libnetlink.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/libnetlink.h b/include/libnetlink.h index 8ebdc6d3..e27516f7 100644 --- a/include/libnetlink.h +++ b/include/libnetlink.h @@ -173,7 +173,8 @@ int rta_nest_end(struct rtattr *rta, struct rtattr *nest); RTA_ALIGN((rta)->rta_len))) #define parse_rtattr_nested(tb, max, rta) \ - (parse_rtattr((tb), (max), RTA_DATA(rta), RTA_PAYLOAD(rta))) + (parse_rtattr_flags((tb), (max), RTA_DATA(rta), RTA_PAYLOAD(rta), \ + NLA_F_NESTED)) #define parse_rtattr_one_nested(type, rta) \ (parse_rtattr_one(type, RTA_DATA(rta), RTA_PAYLOAD(rta))) From d2773f12615430f19097584a8d4b6f99d886f90d Mon Sep 17 00:00:00 2001 From: Petr Machata Date: Mon, 13 Jan 2020 15:16:29 +0100 Subject: [PATCH 12/15] tc: Add support for ETS Qdisc Add a new module to generate and parse options specific to the ETS Qdisc. Example output: bands 8 strict 3 priomap 0 1 2 3 4 5 6 7 qdisc ets 1: root refcnt 2 offloaded bands 8 strict 3 quanta 1514 1514 1514 1514 1514 priomap 0 1 2 3 4 5 6 7 7 7 7 7 7 7 7 7 [ { "kind": "ets", "handle": "1:", "root": true, "refcnt": 2, "offloaded": true, "options": { "bands": 8, "strict": 3, "quanta": [1514, 1514, 1514, 1514, 1514], "priomap": [0, 1, 2, 3, 4, 5, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7] } } ] Signed-off-by: Petr Machata Reviewed-by: Jiri Pirko Signed-off-by: David Ahern --- man/man8/tc-ets.8 | 192 ++++++++++++++++++++++++++ man/man8/tc.8 | 7 + tc/Makefile | 1 + tc/q_ets.c | 342 ++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 542 insertions(+) create mode 100644 man/man8/tc-ets.8 create mode 100644 tc/q_ets.c diff --git a/man/man8/tc-ets.8 b/man/man8/tc-ets.8 new file mode 100644 index 00000000..d3e68167 --- /dev/null +++ b/man/man8/tc-ets.8 @@ -0,0 +1,192 @@ +.TH TC 8 "December 2019" "iproute2" "Linux" +.SH NAME +ETS \- Enhanced Transmission Selection scheduler +.SH SYNOPSIS +.B tc qdisc ... ets [ bands +number +.B ] [ strict +number +.B ] [ quanta +bytes bytes bytes... +.B ] [ priomap +band band band... +.B ] + +.B tc class ... ets [ quantum +bytes +.B ] + +.SH DESCRIPTION + +The Enhanced Transmission Selection scheduler is a classful queuing +discipline that merges functionality of PRIO and DRR qdiscs in one +scheduler. ETS makes it easy to configure a set of strict and +bandwidth-sharing bands to implement the transmission selection described +in 802.1Qaz. + +On creation with 'tc qdisc add', a fixed number of bands is created. Each +band is a class, although it is not possible to directly add and remove +bands with 'tc class' commands. The number of bands to be created must +instead be specified on the command line as the qdisc is added. + +The minor number of classid to use when referring to a band is the band +number increased by one. Thus band 0 will have classid of major:1, band 1 +that of major:2, etc. + +ETS bands are of two types: some number may be in strict mode, the +remaining ones are in bandwidth-sharing mode. + +.SH ALGORITHM +When dequeuing, strict bands are tried first, if there are any. Band 0 is +tried first. If it did not deliver a packet, band 1 is tried next, and so +on until one of the bands delivers a packet, or the strict bands are +exhausted. + +If no packet has been dequeued from any of the strict bands, if there are +any bandwidth-sharing bands, the dequeuing proceeds according to the DRR +algorithm. Each bandwidth-sharing band is assigned a deficit counter, +initialized to quantum assigned by a +.B quanta +element. ETS maintains an (internal) ''active'' list of bandwidth-sharing +bands whose qdiscs are non-empty. This list is used for dequeuing. A packet +is dequeued from the band at the head of the list if the packet size is +smaller or equal to the deficit counter. If the counter is too small, it is +increased by +.B quantum +and the scheduler moves on to the next band in the active list. + +Only qdiscs that own their queue should be added below the +bandwidth-sharing bands. Attaching to them non-work-conserving qdiscs like +TBF does not make sense \-\- other qdiscs in the active list will be +skipped until the dequeue operation succeeds. This limitation does not +exist with the strict bands. + +.SH CLASSIFICATION +The ETS qdisc allows three ways to decide which band to enqueue a packet +to: + +- Packet priority can be directly set to a class handle, in which case that + is the queue where the packet will be put. For example, band number 2 of + a qdisc with handle of 11: will have classid 11:3. To mark a packet for + queuing to this band, the packet priority should be set to 0x110003. + +- A tc filter attached to the qdisc can put the packet to a band by using + the \fBflowid\fR keyword. + +- As a last resort, the ETS qdisc consults its priomap (see below), which + maps packets to bands based on packet priority. + +.SH PARAMETERS +.TP +strict +The number of bands that should be created in strict mode. If not given, +this value is 0. + +.TP +quanta +Each bandwidth-sharing band needs to know its quantum, which is the amount +of bytes a band is allowed to dequeue before the scheduler moves to the +next bandwidth-sharing band. The +.B quanta +argument lists quanta for the individual bandwidth-sharing bands. +The minimum value of each quantum is 1. If +.B quanta +is not given, the default is no bandwidth-sharing bands, but note that when +specifying a large number of +.B bands, +the extra ones are in bandwidth-sharing mode by default. + +.TP +bands +Number of bands given explicitly. This value has to be at least large +enough to cover the strict bands specified through the +.B strict +keyword and bandwidth-sharing bands specified in +.B quanta. +If a larger value is given, any extra bands are in bandwidth-sharing mode, +and their quanta are deduced from the interface MTU. If no value is given, +as many bands are created as necessary to cover all bands implied by the +.B strict +and +.B quanta +keywords. + +.TP +priomap +The priomap maps the priority of a packet to a band. The argument is a list +of numbers. The first number indicates which band the packets with priority +0 should be put to, the second is for priority 1, and so on. + +There can be up to 16 numbers in the list. If there are fewer, the default +band that traffic with one of the unmentioned priorities goes to is the +last one. + +.SH EXAMPLE & USAGE + +.P +Add a qdisc with 8 bandwidth-sharing bands, using the interface MTU as +their quanta. Since all quanta are the same, this will lead to equal +distribution of bandwidth between the bands, each will get about 12.5% of +the link. The low 8 priorities go to individual bands in a reverse 1:1 +fashion (such that the highest priority goes to the first band). + +.P +# tc qdisc add dev eth0 root handle 1: ets bands 8 priomap 7 6 5 4 3 2 1 0 +.br +# tc qdisc show dev eth0 +.br +qdisc ets 1: root refcnt 2 bands 8 quanta 1514 1514 1514 1514 1514 1514 1514 1514 priomap 7 6 5 4 3 2 1 0 7 7 7 7 7 7 7 7 + +.P +Tweak the first band of the above qdisc to give it a quantum of 2650, which +will give it about 20% of the link (and about 11.5% to the remaining +bands): + +.P +# tc class change dev eth0 classid 1:1 ets quantum 2650 +.br +# tc qdisc show dev eth0 +.br +qdisc ets 1: root refcnt 2 bands 8 quanta 2650 1514 1514 1514 1514 1514 1514 1514 priomap 7 6 5 4 3 2 1 0 7 7 7 7 7 7 7 7 + +.P +Create a purely strict Qdisc with reverse 1:1 mapping between priorities +and bands: + +.P +# tc qdisc add dev eth0 root handle 1: ets strict 8 priomap 7 6 5 4 3 2 1 0 +.br +# tc qdisc sh dev eth0 +.br +qdisc ets 1: root refcnt 2 bands 8 strict 8 priomap 7 6 5 4 3 2 1 0 7 7 7 7 7 7 7 7 + +.P +Add a Qdisc with 6 bands, 3 strict and 3 ETS with 35%-30%-25% weights: +.P +# tc qdisc add dev eth0 root handle 1: ets strict 3 quanta 3500 3000 2500 priomap 0 1 1 1 2 3 4 5 +.br +# tc qdisc sh dev eth0 +.br +qdisc ets 1: root refcnt 2 bands 6 strict 3 quanta 3500 3000 2500 priomap 0 1 1 1 2 3 4 5 5 5 5 5 5 5 5 5 + +.P +Create a Qdisc such that traffic with priorities 2, 3 and 4 are strictly +prioritized over other traffic, and the rest goes into bandwidth-sharing +classes with equal weights: +.P +# tc qdisc add dev eth0 root handle 1: ets bands 8 strict 3 priomap 3 4 0 1 2 5 6 7 +.br +# tc qdisc sh dev eth0 +.br +qdisc ets 1: root refcnt 2 bands 8 strict 3 quanta 1514 1514 1514 1514 1514 priomap 3 4 0 1 2 5 6 7 7 7 7 7 7 7 7 7 + +.SH SEE ALSO +.BR tc (8), +.BR tc-prio (8), +.BR tc-drr (8) + +.SH AUTHOR +Parts of both this manual page and the code itself are taken from PRIO and +DRR qdiscs. +.br +ETS qdisc itself was written by Petr Machata. diff --git a/man/man8/tc.8 b/man/man8/tc.8 index d25aadda..39976ad7 100644 --- a/man/man8/tc.8 +++ b/man/man8/tc.8 @@ -394,6 +394,12 @@ DSMARK Classify packets based on TOS field, change TOS field of packets based on classification. .TP +ETS +The ETS qdisc is a queuing discipline that merges functionality of PRIO and DRR +qdiscs in one scheduler. ETS makes it easy to configure a set of strict and +bandwidth-sharing bands to implement the transmission selection described in +802.1Qaz. +.TP HFSC Hierarchical Fair Service Curve guarantees precise bandwidth and delay allocation for leaf classes and allocates excess bandwidth fairly. Unlike HTB, it makes use of packet dropping to achieve low delays which interactive sessions benefit from. .TP @@ -844,6 +850,7 @@ was written by Alexey N. Kuznetsov and added in Linux 2.2. .BR tc-codel (8), .BR tc-drr (8), .BR tc-ematch (8), +.BR tc-ets (8), .BR tc-flow (8), .BR tc-flower (8), .BR tc-fq (8), diff --git a/tc/Makefile b/tc/Makefile index 14171a28..bea5550f 100644 --- a/tc/Makefile +++ b/tc/Makefile @@ -79,6 +79,7 @@ TCMODULES += q_cbs.o TCMODULES += q_etf.o TCMODULES += q_taprio.o TCMODULES += q_plug.o +TCMODULES += q_ets.o TCSO := ifeq ($(TC_CONFIG_ATM),y) diff --git a/tc/q_ets.c b/tc/q_ets.c new file mode 100644 index 00000000..e7903d50 --- /dev/null +++ b/tc/q_ets.c @@ -0,0 +1,342 @@ +// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause + +/* + * Enhanced Transmission Selection - 802.1Qaz-based Qdisc + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "utils.h" +#include "tc_util.h" + +static void explain(void) +{ + fprintf(stderr, "Usage: ... ets [bands NUMBER] [strict NUMBER] [quanta Q1 Q2...] [priomap P1 P2...]\n"); +} + +static void cexplain(void) +{ + fprintf(stderr, "Usage: ... ets [quantum Q1]\n"); +} + +static unsigned int parse_quantum(const char *arg) +{ + unsigned int quantum; + + if (get_unsigned(&quantum, arg, 10)) { + fprintf(stderr, "Illegal \"quanta\" element\n"); + return 0; + } + if (!quantum) + fprintf(stderr, "\"quanta\" must be > 0\n"); + return quantum; +} + +static int parse_nbands(const char *arg, __u8 *pnbands, const char *what) +{ + unsigned int tmp; + + if (get_unsigned(&tmp, arg, 10)) { + fprintf(stderr, "Illegal \"%s\"\n", what); + return -1; + } + if (tmp > TCQ_ETS_MAX_BANDS) { + fprintf(stderr, "The number of \"%s\" must be <= %d\n", + what, TCQ_ETS_MAX_BANDS); + return -1; + } + + *pnbands = tmp; + return 0; +} + +static int ets_parse_opt(struct qdisc_util *qu, int argc, char **argv, + struct nlmsghdr *n, const char *dev) +{ + __u8 nbands = 0; + __u8 nstrict = 0; + bool quanta_mode = false; + unsigned int nquanta = 0; + __u32 quanta[TCQ_ETS_MAX_BANDS]; + bool priomap_mode = false; + unsigned int nprio = 0; + __u8 priomap[TC_PRIO_MAX + 1]; + unsigned int tmp; + struct rtattr *tail, *nest; + + while (argc > 0) { + if (strcmp(*argv, "bands") == 0) { + if (nbands) { + fprintf(stderr, "Duplicate \"bands\"\n"); + return -1; + } + NEXT_ARG(); + if (parse_nbands(*argv, &nbands, "bands")) + return -1; + priomap_mode = quanta_mode = false; + } else if (strcmp(*argv, "strict") == 0) { + if (nstrict) { + fprintf(stderr, "Duplicate \"strict\"\n"); + return -1; + } + NEXT_ARG(); + if (parse_nbands(*argv, &nstrict, "strict")) + return -1; + priomap_mode = quanta_mode = false; + } else if (strcmp(*argv, "quanta") == 0) { + if (nquanta) { + fprintf(stderr, "Duplicate \"quanta\"\n"); + return -1; + } + NEXT_ARG(); + priomap_mode = false; + quanta_mode = true; + goto parse_quantum; + } else if (strcmp(*argv, "priomap") == 0) { + if (nprio) { + fprintf(stderr, "Duplicate \"priomap\"\n"); + return -1; + } + NEXT_ARG(); + priomap_mode = true; + quanta_mode = false; + goto parse_priomap; + } else if (strcmp(*argv, "help") == 0) { + explain(); + return -1; + } else if (quanta_mode) { + unsigned int quantum; + +parse_quantum: + quantum = parse_quantum(*argv); + if (!quantum) + return -1; + quanta[nquanta++] = quantum; + } else if (priomap_mode) { + unsigned int band; + +parse_priomap: + if (get_unsigned(&band, *argv, 10)) { + fprintf(stderr, "Illegal \"priomap\" element\n"); + return -1; + } + if (nprio > TC_PRIO_MAX) { + fprintf(stderr, "\"priomap\" index cannot be higher than %u\n", TC_PRIO_MAX); + return -1; + } + priomap[nprio++] = band; + } else { + fprintf(stderr, "What is \"%s\"?\n", *argv); + explain(); + return -1; + } + argc--; argv++; + } + + if (!nbands) + nbands = nquanta + nstrict; + if (!nbands) { + fprintf(stderr, "One of \"bands\", \"quanta\" or \"strict\" needs to be specified\n"); + explain(); + return -1; + } + if (nbands < 1) { + fprintf(stderr, "The number of \"bands\" must be >= 1\n"); + explain(); + return -1; + } + if (nstrict + nquanta > nbands) { + fprintf(stderr, "Not enough total bands to cover all the strict bands and quanta\n"); + explain(); + return -1; + } + for (tmp = 0; tmp < nprio; tmp++) { + if (priomap[tmp] >= nbands) { + fprintf(stderr, "\"priomap\" element is out of bounds\n"); + return -1; + } + } + + tail = addattr_nest(n, 1024, TCA_OPTIONS | NLA_F_NESTED); + addattr_l(n, 1024, TCA_ETS_NBANDS, &nbands, sizeof(nbands)); + if (nstrict) + addattr_l(n, 1024, TCA_ETS_NSTRICT, &nstrict, sizeof(nstrict)); + if (nquanta) { + nest = addattr_nest(n, 1024, TCA_ETS_QUANTA | NLA_F_NESTED); + for (tmp = 0; tmp < nquanta; tmp++) + addattr_l(n, 1024, TCA_ETS_QUANTA_BAND, + &quanta[tmp], sizeof(quanta[0])); + addattr_nest_end(n, nest); + } + if (nprio) { + nest = addattr_nest(n, 1024, TCA_ETS_PRIOMAP | NLA_F_NESTED); + for (tmp = 0; tmp < nprio; tmp++) + addattr_l(n, 1024, TCA_ETS_PRIOMAP_BAND, + &priomap[tmp], sizeof(priomap[0])); + addattr_nest_end(n, nest); + } + addattr_nest_end(n, tail); + + return 0; +} + +static int ets_parse_copt(struct qdisc_util *qu, int argc, char **argv, + struct nlmsghdr *n, const char *dev) +{ + unsigned int quantum = 0; + struct rtattr *tail; + + while (argc > 0) { + if (strcmp(*argv, "quantum") == 0) { + if (quantum) { + fprintf(stderr, "Duplicate \"quantum\"\n"); + return -1; + } + NEXT_ARG(); + quantum = parse_quantum(*argv); + if (!quantum) + return -1; + } else if (strcmp(*argv, "help") == 0) { + cexplain(); + return -1; + } else { + fprintf(stderr, "What is \"%s\"?\n", *argv); + cexplain(); + return -1; + } + argc--; argv++; + } + + tail = addattr_nest(n, 1024, TCA_OPTIONS | NLA_F_NESTED); + if (quantum) + addattr_l(n, 1024, TCA_ETS_QUANTA_BAND, &quantum, + sizeof(quantum)); + addattr_nest_end(n, tail); + + return 0; +} + +static int ets_print_opt_quanta(struct rtattr *opt) +{ + int len = RTA_PAYLOAD(opt); + unsigned int offset; + + open_json_array(PRINT_ANY, "quanta"); + for (offset = 0; offset < len; ) { + struct rtattr *tb[TCA_ETS_MAX + 1] = {NULL}; + struct rtattr *attr; + __u32 quantum; + + attr = RTA_DATA(opt) + offset; + parse_rtattr(tb, TCA_ETS_MAX, attr, len - offset); + offset += RTA_LENGTH(RTA_PAYLOAD(attr)); + + if (!tb[TCA_ETS_QUANTA_BAND]) { + fprintf(stderr, "No ETS band quantum\n"); + return -1; + } + + quantum = rta_getattr_u32(tb[TCA_ETS_QUANTA_BAND]); + print_uint(PRINT_ANY, NULL, " %u", quantum); + + } + close_json_array(PRINT_ANY, " "); + + return 0; +} + +static int ets_print_opt_priomap(struct rtattr *opt) +{ + int len = RTA_PAYLOAD(opt); + unsigned int offset; + + open_json_array(PRINT_ANY, "priomap"); + for (offset = 0; offset < len; ) { + struct rtattr *tb[TCA_ETS_MAX + 1] = {NULL}; + struct rtattr *attr; + __u8 band; + + attr = RTA_DATA(opt) + offset; + parse_rtattr(tb, TCA_ETS_MAX, attr, len - offset); + offset += RTA_LENGTH(RTA_PAYLOAD(attr)) + 3 /* padding */; + + if (!tb[TCA_ETS_PRIOMAP_BAND]) { + fprintf(stderr, "No ETS priomap band\n"); + return -1; + } + + band = rta_getattr_u8(tb[TCA_ETS_PRIOMAP_BAND]); + print_uint(PRINT_ANY, NULL, " %u", band); + + } + close_json_array(PRINT_ANY, " "); + + return 0; +} + +static int ets_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt) +{ + struct rtattr *tb[TCA_ETS_MAX + 1]; + __u8 nbands; + __u8 nstrict; + int err; + + if (opt == NULL) + return 0; + + parse_rtattr_nested(tb, TCA_ETS_MAX, opt); + + if (!tb[TCA_ETS_NBANDS] || !tb[TCA_ETS_PRIOMAP]) { + fprintf(stderr, "Incomplete ETS options\n"); + return -1; + } + + nbands = rta_getattr_u8(tb[TCA_ETS_NBANDS]); + print_uint(PRINT_ANY, "bands", "bands %u ", nbands); + + if (tb[TCA_ETS_NSTRICT]) { + nstrict = rta_getattr_u8(tb[TCA_ETS_NSTRICT]); + print_uint(PRINT_ANY, "strict", "strict %u ", nstrict); + } + + if (tb[TCA_ETS_QUANTA]) { + err = ets_print_opt_quanta(tb[TCA_ETS_QUANTA]); + if (err) + return err; + } + + return ets_print_opt_priomap(tb[TCA_ETS_PRIOMAP]); +} + +static int ets_print_copt(struct qdisc_util *qu, FILE *f, struct rtattr *opt) +{ + struct rtattr *tb[TCA_ETS_MAX + 1]; + __u32 quantum; + + if (opt == NULL) + return 0; + + parse_rtattr_nested(tb, TCA_ETS_MAX, opt); + + if (tb[TCA_ETS_QUANTA_BAND]) { + quantum = rta_getattr_u32(tb[TCA_ETS_QUANTA_BAND]); + print_uint(PRINT_ANY, "quantum", "quantum %u ", quantum); + } + + return 0; +} + +struct qdisc_util ets_qdisc_util = { + .id = "ets", + .parse_qopt = ets_parse_opt, + .parse_copt = ets_parse_copt, + .print_qopt = ets_print_opt, + .print_copt = ets_print_copt, +}; From 4df5ad933ca8cebf23a4868061b28ab869e9b77a Mon Sep 17 00:00:00 2001 From: David Ahern Date: Wed, 22 Jan 2020 03:40:26 +0000 Subject: [PATCH 13/15] Update kernel headers and import udp.h Update kernel headers to commit: 4f2c17e0f332 ("Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/klassert/ipsec-next") and import udp.h for the next patch. Signed-off-by: David Ahern --- include/uapi/linux/hdlc/ioctl.h | 9 +++++++ include/uapi/linux/if.h | 1 + include/uapi/linux/udp.h | 47 +++++++++++++++++++++++++++++++++ 3 files changed, 57 insertions(+) create mode 100644 include/uapi/linux/udp.h diff --git a/include/uapi/linux/hdlc/ioctl.h b/include/uapi/linux/hdlc/ioctl.h index 0fe4238e..b06341ac 100644 --- a/include/uapi/linux/hdlc/ioctl.h +++ b/include/uapi/linux/hdlc/ioctl.h @@ -79,6 +79,15 @@ typedef struct { unsigned int timeout; } cisco_proto; +typedef struct { + unsigned short dce; /* 1 for DCE (network side) operation */ + unsigned int modulo; /* modulo (8 = basic / 128 = extended) */ + unsigned int window; /* frame window size */ + unsigned int t1; /* timeout t1 */ + unsigned int t2; /* timeout t2 */ + unsigned int n2; /* frame retry counter */ +} x25_hdlc_proto; + /* PPP doesn't need any info now - supply length = 0 to ioctl */ #endif /* __ASSEMBLY__ */ diff --git a/include/uapi/linux/if.h b/include/uapi/linux/if.h index cf27ea4c..074b14e3 100644 --- a/include/uapi/linux/if.h +++ b/include/uapi/linux/if.h @@ -211,6 +211,7 @@ struct if_settings { fr_proto *fr; fr_proto_pvc *fr_pvc; fr_proto_pvc_info *fr_pvc_info; + x25_hdlc_proto *x25; /* interface settings */ sync_serial_settings *sync; diff --git a/include/uapi/linux/udp.h b/include/uapi/linux/udp.h new file mode 100644 index 00000000..d0a7223a --- /dev/null +++ b/include/uapi/linux/udp.h @@ -0,0 +1,47 @@ +/* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */ +/* + * INET An implementation of the TCP/IP protocol suite for the LINUX + * operating system. INET is implemented using the BSD Socket + * interface as the means of communication with the user level. + * + * Definitions for the UDP protocol. + * + * Version: @(#)udp.h 1.0.2 04/28/93 + * + * Author: Fred N. van Kempen, + * + * 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. + */ +#ifndef _LINUX_UDP_H +#define _LINUX_UDP_H + +#include + +struct udphdr { + __be16 source; + __be16 dest; + __be16 len; + __sum16 check; +}; + +/* UDP socket options */ +#define UDP_CORK 1 /* Never send partially complete segments */ +#define UDP_ENCAP 100 /* Set the socket to accept encapsulated packets */ +#define UDP_NO_CHECK6_TX 101 /* Disable sending checksum for UDP6X */ +#define UDP_NO_CHECK6_RX 102 /* Disable accpeting checksum for UDP6 */ +#define UDP_SEGMENT 103 /* Set GSO segmentation size */ +#define UDP_GRO 104 /* This socket can receive UDP GRO packets */ + +/* UDP encapsulation types */ +#define UDP_ENCAP_ESPINUDP_NON_IKE 1 /* draft-ietf-ipsec-nat-t-ike-00/01 */ +#define UDP_ENCAP_ESPINUDP 2 /* draft-ietf-ipsec-udp-encaps-06 */ +#define UDP_ENCAP_L2TPINUDP 3 /* rfc2661 */ +#define UDP_ENCAP_GTP0 4 /* GSM TS 09.60 */ +#define UDP_ENCAP_GTP1U 5 /* 3GPP TS 29.060 */ +#define UDP_ENCAP_RXRPC 6 +#define TCP_ENCAP_ESPINTCP 7 /* Yikes, this is really xfrm encap types. */ + +#endif /* _LINUX_UDP_H */ From 22aec42679d57b8e0aef864c4d45feadb727c3ce Mon Sep 17 00:00:00 2001 From: Sabrina Dubroca Date: Sun, 19 Jan 2020 11:32:09 +0100 Subject: [PATCH 14/15] ip: xfrm: add espintcp encapsulation While at it, convert xfrm_xfrma_print and xfrm_encap_type_parse to use the UAPI macros for encap_type as suggested by David Ahern, and add the UAPI udp.h header (sync'd from ipsec-next to get the TCP_ENCAP_ESPINTCP definition). Co-developed-by: Herbert Xu Signed-off-by: Sabrina Dubroca Signed-off-by: David Ahern --- ip/ipxfrm.c | 14 ++++++++++---- ip/xfrm_state.c | 2 +- man/man8/ip-xfrm.8 | 4 ++-- 3 files changed, 13 insertions(+), 7 deletions(-) diff --git a/ip/ipxfrm.c b/ip/ipxfrm.c index 32f56093..fec206ab 100644 --- a/ip/ipxfrm.c +++ b/ip/ipxfrm.c @@ -34,6 +34,7 @@ #include #include #include +#include #include "utils.h" #include "xfrm.h" @@ -753,12 +754,15 @@ void xfrm_xfrma_print(struct rtattr *tb[], __u16 family, fprintf(fp, "type "); switch (e->encap_type) { - case 1: + case UDP_ENCAP_ESPINUDP_NON_IKE: fprintf(fp, "espinudp-nonike "); break; - case 2: + case UDP_ENCAP_ESPINUDP: fprintf(fp, "espinudp "); break; + case TCP_ENCAP_ESPINTCP: + fprintf(fp, "espintcp "); + break; default: fprintf(fp, "%u ", e->encap_type); break; @@ -1208,9 +1212,11 @@ int xfrm_encap_type_parse(__u16 *type, int *argcp, char ***argvp) char **argv = *argvp; if (strcmp(*argv, "espinudp-nonike") == 0) - *type = 1; + *type = UDP_ENCAP_ESPINUDP_NON_IKE; else if (strcmp(*argv, "espinudp") == 0) - *type = 2; + *type = UDP_ENCAP_ESPINUDP; + else if (strcmp(*argv, "espintcp") == 0) + *type = TCP_ENCAP_ESPINTCP; else invarg("ENCAP-TYPE value is invalid", *argv); diff --git a/ip/xfrm_state.c b/ip/xfrm_state.c index b03ccc58..df2d50c3 100644 --- a/ip/xfrm_state.c +++ b/ip/xfrm_state.c @@ -130,7 +130,7 @@ static void usage(void) "LIMIT-LIST := [ LIMIT-LIST ] limit LIMIT\n" "LIMIT := { time-soft | time-hard | time-use-soft | time-use-hard } SECONDS |\n" " { byte-soft | byte-hard } SIZE | { packet-soft | packet-hard } COUNT\n" - "ENCAP := { espinudp | espinudp-nonike } SPORT DPORT OADDR\n" + "ENCAP := { espinudp | espinudp-nonike | espintcp } SPORT DPORT OADDR\n" "DIR := in | out\n"); exit(-1); diff --git a/man/man8/ip-xfrm.8 b/man/man8/ip-xfrm.8 index cfce1e40..f99f30bb 100644 --- a/man/man8/ip-xfrm.8 +++ b/man/man8/ip-xfrm.8 @@ -207,7 +207,7 @@ ip-xfrm \- transform configuration .ti -8 .IR ENCAP " :=" -.RB "{ " espinudp " | " espinudp-nonike " }" +.RB "{ " espinudp " | " espinudp-nonike " | " espintcp " }" .IR SPORT " " DPORT " " OADDR .ti -8 @@ -548,7 +548,7 @@ sets limits in seconds, bytes, or numbers of packets. .TP .I ENCAP encapsulates packets with protocol -.BR espinudp " or " espinudp-nonike "," +.BR espinudp ", " espinudp-nonike ", or " espintcp "," .RI "using source port " SPORT ", destination port " DPORT .RI ", and original address " OADDR "." From eae5f4b5c88eb60465d8b70c52efff57039d0024 Mon Sep 17 00:00:00 2001 From: Leslie Monis Date: Thu, 16 Jan 2020 21:27:01 +0530 Subject: [PATCH 15/15] tc: parse attributes with NLA_F_NESTED flag The kernel now requires all new nested attributes to set the NLA_F_NESTED flag. Enable tc {qdisc,class,filter} to parse attributes that have the NLA_F_NESTED flag set. Signed-off-by: Leslie Monis Signed-off-by: David Ahern --- tc/tc_class.c | 6 +++--- tc/tc_filter.c | 2 +- tc/tc_qdisc.c | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/tc/tc_class.c b/tc/tc_class.c index c7e3cfdf..39bea971 100644 --- a/tc/tc_class.c +++ b/tc/tc_class.c @@ -246,8 +246,8 @@ static void graph_cls_show(FILE *fp, char *buf, struct hlist_head *root_list, "+---(%s)", cls_id_str); strcat(buf, str); - parse_rtattr(tb, TCA_MAX, (struct rtattr *)cls->data, - cls->data_len); + parse_rtattr_flags(tb, TCA_MAX, (struct rtattr *)cls->data, + cls->data_len, NLA_F_NESTED); if (tb[TCA_KIND] == NULL) { strcat(buf, " [unknown qdisc kind] "); @@ -327,7 +327,7 @@ int print_class(struct nlmsghdr *n, void *arg) if (filter_classid && t->tcm_handle != filter_classid) return 0; - parse_rtattr(tb, TCA_MAX, TCA_RTA(t), len); + parse_rtattr_flags(tb, TCA_MAX, TCA_RTA(t), len, NLA_F_NESTED); if (tb[TCA_KIND] == NULL) { fprintf(stderr, "print_class: NULL kind\n"); diff --git a/tc/tc_filter.c b/tc/tc_filter.c index dcddca77..c591a19f 100644 --- a/tc/tc_filter.c +++ b/tc/tc_filter.c @@ -267,7 +267,7 @@ int print_filter(struct nlmsghdr *n, void *arg) return -1; } - parse_rtattr(tb, TCA_MAX, TCA_RTA(t), len); + parse_rtattr_flags(tb, TCA_MAX, TCA_RTA(t), len, NLA_F_NESTED); if (tb[TCA_KIND] == NULL && (n->nlmsg_type == RTM_NEWTFILTER || n->nlmsg_type == RTM_GETTFILTER || diff --git a/tc/tc_qdisc.c b/tc/tc_qdisc.c index 75a14672..181fe2f0 100644 --- a/tc/tc_qdisc.c +++ b/tc/tc_qdisc.c @@ -235,7 +235,7 @@ int print_qdisc(struct nlmsghdr *n, void *arg) if (filter_ifindex && filter_ifindex != t->tcm_ifindex) return 0; - parse_rtattr(tb, TCA_MAX, TCA_RTA(t), len); + parse_rtattr_flags(tb, TCA_MAX, TCA_RTA(t), len, NLA_F_NESTED); if (tb[TCA_KIND] == NULL) { fprintf(stderr, "print_qdisc: NULL kind\n"); @@ -461,7 +461,7 @@ static int tc_qdisc_block_exists_cb(struct nlmsghdr *n, void *arg) if (len < 0) return -1; - parse_rtattr(tb, TCA_MAX, TCA_RTA(t), len); + parse_rtattr_flags(tb, TCA_MAX, TCA_RTA(t), len, NLA_F_NESTED); if (tb[TCA_KIND] == NULL) return -1;