diff --git a/devlink/devlink.c b/devlink/devlink.c index e22ee0a0..f9bc16c3 100644 --- a/devlink/devlink.c +++ b/devlink/devlink.c @@ -176,6 +176,7 @@ static void ifname_map_free(struct ifname_map *ifname_map) #define DL_OPT_ESWITCH_INLINE_MODE BIT(12) #define DL_OPT_DPIPE_TABLE_NAME BIT(13) #define DL_OPT_DPIPE_TABLE_COUNTERS BIT(14) +#define DL_OPT_ESWITCH_ENCAP_MODE BIT(15) struct dl_opts { uint32_t present; /* flags of present items */ @@ -195,6 +196,7 @@ struct dl_opts { enum devlink_eswitch_inline_mode eswitch_inline_mode; const char *dpipe_table_name; bool dpipe_counters_enable; + bool eswitch_encap_mode; }; struct dl { @@ -299,6 +301,7 @@ static const enum mnl_attr_data_type devlink_policy[DEVLINK_ATTR_MAX + 1] = { [DEVLINK_ATTR_SB_OCC_MAX] = MNL_TYPE_U32, [DEVLINK_ATTR_ESWITCH_MODE] = MNL_TYPE_U16, [DEVLINK_ATTR_ESWITCH_INLINE_MODE] = MNL_TYPE_U8, + [DEVLINK_ATTR_ESWITCH_ENCAP_MODE] = MNL_TYPE_U8, [DEVLINK_ATTR_DPIPE_TABLES] = MNL_TYPE_NESTED, [DEVLINK_ATTR_DPIPE_TABLE] = MNL_TYPE_NESTED, [DEVLINK_ATTR_DPIPE_TABLE_NAME] = MNL_TYPE_STRING, @@ -754,6 +757,19 @@ static int dpipe_counters_enable_get(const char *typestr, return 0; } +static int eswitch_encap_mode_get(const char *typestr, bool *p_mode) +{ + if (strcmp(typestr, "enable") == 0) { + *p_mode = true; + } else if (strcmp(typestr, "disable") == 0) { + *p_mode = false; + } else { + pr_err("Unknown eswitch encap mode \"%s\"\n", typestr); + return -EINVAL; + } + return 0; +} + static int dl_argv_parse(struct dl *dl, uint32_t o_required, uint32_t o_optional) { @@ -908,7 +924,19 @@ static int dl_argv_parse(struct dl *dl, uint32_t o_required, if (err) return err; o_found |= DL_OPT_DPIPE_TABLE_COUNTERS; + } else if (dl_argv_match(dl, "encap") && + (o_all & DL_OPT_ESWITCH_ENCAP_MODE)) { + const char *typestr; + dl_arg_inc(dl); + err = dl_argv_str(dl, &typestr); + if (err) + return err; + err = eswitch_encap_mode_get(typestr, + &opts->eswitch_encap_mode); + if (err) + return err; + o_found |= DL_OPT_ESWITCH_ENCAP_MODE; } else { pr_err("Unknown option \"%s\"\n", dl_argv(dl)); return -EINVAL; @@ -986,6 +1014,13 @@ static int dl_argv_parse(struct dl *dl, uint32_t o_required, pr_err("Dpipe table counter state expected\n"); return -EINVAL; } + + if ((o_required & DL_OPT_ESWITCH_ENCAP_MODE) && + !(o_found & DL_OPT_ESWITCH_ENCAP_MODE)) { + pr_err("E-Switch encapsulation option expected.\n"); + return -EINVAL; + } + return 0; } @@ -1041,6 +1076,9 @@ static void dl_opts_put(struct nlmsghdr *nlh, struct dl *dl) if (opts->present & DL_OPT_DPIPE_TABLE_COUNTERS) mnl_attr_put_u8(nlh, DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED, opts->dpipe_counters_enable); + if (opts->present & DL_OPT_ESWITCH_ENCAP_MODE) + mnl_attr_put_u8(nlh, DEVLINK_ATTR_ESWITCH_ENCAP_MODE, + opts->eswitch_encap_mode); } static int dl_argv_parse_put(struct nlmsghdr *nlh, struct dl *dl, @@ -1097,6 +1135,7 @@ static void cmd_dev_help(void) pr_err("Usage: devlink dev show [ DEV ]\n"); pr_err(" devlink dev eswitch set DEV [ mode { legacy | switchdev } ]\n"); pr_err(" [ inline-mode { none | link | network | transport } ]\n"); + pr_err(" [ encap { disable | enable } ]\n"); pr_err(" devlink dev eswitch show DEV\n"); } @@ -1421,6 +1460,12 @@ static void pr_out_eswitch(struct dl *dl, struct nlattr **tb) eswitch_inline_mode_name(mnl_attr_get_u8( tb[DEVLINK_ATTR_ESWITCH_INLINE_MODE]))); + if (tb[DEVLINK_ATTR_ESWITCH_ENCAP_MODE]) { + bool encap_mode = !!mnl_attr_get_u8(tb[DEVLINK_ATTR_ESWITCH_ENCAP_MODE]); + + pr_out_str(dl, "encap", encap_mode ? "enable" : "disable"); + } + pr_out_handle_end(dl); } @@ -1465,7 +1510,8 @@ static int cmd_dev_eswitch_set(struct dl *dl) err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE, DL_OPT_ESWITCH_MODE | - DL_OPT_ESWITCH_INLINE_MODE); + DL_OPT_ESWITCH_INLINE_MODE | + DL_OPT_ESWITCH_ENCAP_MODE); if (err) return err; diff --git a/ip/iplink_bridge.c b/ip/iplink_bridge.c index 818b43c8..cccdec1c 100644 --- a/ip/iplink_bridge.c +++ b/ip/iplink_bridge.c @@ -13,9 +13,9 @@ #include #include #include +#include #include #include -#include #include #include "rt_names.h" diff --git a/ip/iplink_can.c b/ip/iplink_can.c index 20d4d37d..5df56b2b 100644 --- a/ip/iplink_can.c +++ b/ip/iplink_can.c @@ -41,6 +41,8 @@ static void print_usage(FILE *f) "\t[ restart-ms TIME-MS ]\n" "\t[ restart ]\n" "\n" + "\t[ termination { 0..65535 } ]\n" + "\n" "\tWhere: BITRATE := { 1..1000000 }\n" "\t SAMPLE-POINT := { 0.000..0.999 }\n" "\t TQ := { NUMBER }\n" @@ -220,6 +222,14 @@ static int can_parse_opt(struct link_util *lu, int argc, char **argv, if (get_u32(&val, *argv, 0)) invarg("invalid \"restart-ms\" value\n", *argv); addattr32(n, 1024, IFLA_CAN_RESTART_MS, val); + } else if (matches(*argv, "termination") == 0) { + __u16 val; + + NEXT_ARG(); + if (get_u16(&val, *argv, 0)) + invarg("invalid \"termination\" value\n", + *argv); + addattr16(n, 1024, IFLA_CAN_TERMINATION, val); } else if (matches(*argv, "help") == 0) { usage(); return -1; @@ -282,7 +292,8 @@ static void can_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[]) fprintf(f, "restart-ms %d ", *restart_ms); } - if (tb[IFLA_CAN_BITTIMING]) { + /* bittiming is irrelevant if fixed bitrate is defined */ + if (tb[IFLA_CAN_BITTIMING] && !tb[IFLA_CAN_BITRATE_CONST]) { struct can_bittiming *bt = RTA_DATA(tb[IFLA_CAN_BITTIMING]); fprintf(f, "\n bitrate %d sample-point %.3f ", @@ -292,7 +303,8 @@ static void can_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[]) bt->sjw); } - if (tb[IFLA_CAN_BITTIMING_CONST]) { + /* bittiming const is irrelevant if fixed bitrate is defined */ + if (tb[IFLA_CAN_BITTIMING_CONST] && !tb[IFLA_CAN_BITRATE_CONST]) { struct can_bittiming_const *btc = RTA_DATA(tb[IFLA_CAN_BITTIMING_CONST]); @@ -303,7 +315,37 @@ static void can_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[]) btc->brp_min, btc->brp_max, btc->brp_inc); } - if (tb[IFLA_CAN_DATA_BITTIMING]) { + if (tb[IFLA_CAN_BITRATE_CONST]) { + __u32 *bitrate_const = RTA_DATA(tb[IFLA_CAN_BITRATE_CONST]); + int bitrate_cnt = RTA_PAYLOAD(tb[IFLA_CAN_BITRATE_CONST]) / + sizeof(*bitrate_const); + int i; + __u32 bitrate = 0; + + if (tb[IFLA_CAN_BITTIMING]) { + struct can_bittiming *bt = + RTA_DATA(tb[IFLA_CAN_BITTIMING]); + bitrate = bt->bitrate; + } + + fprintf(f, "\n bitrate %u", bitrate); + fprintf(f, "\n ["); + + for (i = 0; i < bitrate_cnt - 1; ++i) { + /* This will keep lines below 80 signs */ + if (!(i % 6) && i) + fprintf(f, "\n "); + + fprintf(f, "%8u, ", bitrate_const[i]); + } + + if (!(i % 6) && i) + fprintf(f, "\n "); + fprintf(f, "%8u ]", bitrate_const[i]); + } + + /* data bittiming is irrelevant if fixed bitrate is defined */ + if (tb[IFLA_CAN_DATA_BITTIMING] && !tb[IFLA_CAN_DATA_BITRATE_CONST]) { struct can_bittiming *dbt = RTA_DATA(tb[IFLA_CAN_DATA_BITTIMING]); @@ -315,7 +357,9 @@ static void can_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[]) dbt->phase_seg2, dbt->sjw); } - if (tb[IFLA_CAN_DATA_BITTIMING_CONST]) { + /* data bittiming const is irrelevant if fixed bitrate is defined */ + if (tb[IFLA_CAN_DATA_BITTIMING_CONST] && + !tb[IFLA_CAN_DATA_BITRATE_CONST]) { struct can_bittiming_const *dbtc = RTA_DATA(tb[IFLA_CAN_DATA_BITTIMING_CONST]); @@ -326,6 +370,52 @@ static void can_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[]) dbtc->brp_min, dbtc->brp_max, dbtc->brp_inc); } + if (tb[IFLA_CAN_DATA_BITRATE_CONST]) { + __u32 *dbitrate_const = + RTA_DATA(tb[IFLA_CAN_DATA_BITRATE_CONST]); + int dbitrate_cnt = + RTA_PAYLOAD(tb[IFLA_CAN_DATA_BITRATE_CONST]) / + sizeof(*dbitrate_const); + int i; + __u32 dbitrate = 0; + + if (tb[IFLA_CAN_DATA_BITTIMING]) { + struct can_bittiming *dbt = + RTA_DATA(tb[IFLA_CAN_DATA_BITTIMING]); + dbitrate = dbt->bitrate; + } + + fprintf(f, "\n dbitrate %u", dbitrate); + fprintf(f, "\n ["); + + for (i = 0; i < dbitrate_cnt - 1; ++i) { + /* This will keep lines below 80 signs */ + if (!(i % 6) && i) + fprintf(f, "\n "); + + fprintf(f, "%8u, ", dbitrate_const[i]); + } + + if (!(i % 6) && i) + fprintf(f, "\n "); + fprintf(f, "%8u ]", dbitrate_const[i]); + } + + if (tb[IFLA_CAN_TERMINATION_CONST] && tb[IFLA_CAN_TERMINATION]) { + __u16 *trm = RTA_DATA(tb[IFLA_CAN_TERMINATION]); + __u16 *trm_const = RTA_DATA(tb[IFLA_CAN_TERMINATION_CONST]); + int trm_cnt = RTA_PAYLOAD(tb[IFLA_CAN_TERMINATION_CONST]) / + sizeof(*trm_const); + int i; + + fprintf(f, "\n termination %hu [ ", *trm); + + for (i = 0; i < trm_cnt - 1; ++i) + fprintf(f, "%hu, ", trm_const[i]); + + fprintf(f, "%hu ]", trm_const[i]); + } + if (tb[IFLA_CAN_CLOCK]) { struct can_clock *clock = RTA_DATA(tb[IFLA_CAN_CLOCK]); diff --git a/lib/libnetlink.c b/lib/libnetlink.c index 5b75b2db..d4b831f6 100644 --- a/lib/libnetlink.c +++ b/lib/libnetlink.c @@ -266,21 +266,27 @@ static int rtnl_dump_done(const struct rtnl_handle *rth, { int len = *(int *)NLMSG_DATA(h); - if (rth->proto == NETLINK_SOCK_DIAG) { - if (h->nlmsg_len < NLMSG_LENGTH(sizeof(int))) { - fprintf(stderr, "DONE truncated\n"); - return -1; - } - - - if (len < 0) { - errno = -len; - if (errno == ENOENT || errno == EOPNOTSUPP) - return -1; - perror("RTNETLINK answers"); - return len; - } + if (h->nlmsg_len < NLMSG_LENGTH(sizeof(int))) { + fprintf(stderr, "DONE truncated\n"); + return -1; } + + if (len < 0) { + errno = -len; + switch (errno) { + case ENOENT: + case EOPNOTSUPP: + return -1; + case EMSGSIZE: + fprintf(stderr, + "Error: Buffer too small for object.\n"); + break; + default: + perror("RTNETLINK answers"); + } + return len; + } + return 0; } diff --git a/man/man8/devlink-dev.8 b/man/man8/devlink-dev.8 index 6bfe66f8..b074d57a 100644 --- a/man/man8/devlink-dev.8 +++ b/man/man8/devlink-dev.8 @@ -34,6 +34,9 @@ devlink-dev \- devlink device configuration .RI "[ " .BR inline-mode " { " none " | " link " | " network " | " transport " } " .RI "]" +.RI "[ " +.BR encap " { " disable " | " enable " } " +.RI "]" .ti -8 .BR "devlink dev eswitch show" @@ -81,6 +84,16 @@ Some HWs need the VF driver to put part of the packet headers on the TX descript .I transport - L4 mode +.TP +.BR encap " { " disable " | " enable " } " +Set eswitch encapsulation support + +.I disable +- Disable encapsulation support + +.I enable +- Enable encapsulation support + .SH "EXAMPLES" .PP devlink dev show diff --git a/tc/Makefile b/tc/Makefile index 9a6bb1dd..678b3029 100644 --- a/tc/Makefile +++ b/tc/Makefile @@ -45,6 +45,7 @@ TCMODULES += m_nat.o TCMODULES += m_pedit.o TCMODULES += m_ife.o TCMODULES += m_skbedit.o +TCMODULES += m_skbmod.o TCMODULES += m_csum.o TCMODULES += m_simple.o TCMODULES += m_vlan.o diff --git a/tc/m_xt.c b/tc/m_xt.c index e59df8e1..ad52d239 100644 --- a/tc/m_xt.c +++ b/tc/m_xt.c @@ -146,6 +146,9 @@ static int parse_ipt(struct action_util *a, int *argc_p, char ***argv_p, int tca_id, struct nlmsghdr *n) { struct xtables_target *m = NULL; +#if XTABLES_VERSION_CODE >= 6 + struct ipt_entry fw = {}; +#endif struct rtattr *tail; int c; @@ -206,7 +209,7 @@ static int parse_ipt(struct action_util *a, int *argc_p, default: #if XTABLES_VERSION_CODE >= 6 if (m != NULL && m->x6_parse != NULL) { - xtables_option_tpcall(c, argv, 0, m, NULL); + xtables_option_tpcall(c, argv, 0, m, &fw); #else if (m != NULL && m->parse != NULL) { m->parse(c - m->option_offset, argv, 0,