From patchwork Fri Mar 6 17:04:09 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Michal Kubecek X-Patchwork-Id: 222926 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.8 required=3.0 tests=HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SIGNED_OFF_BY, SPF_HELO_NONE, SPF_PASS autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 24A2AC10DCE for ; Fri, 6 Mar 2020 17:04:14 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 04E9C2146E for ; Fri, 6 Mar 2020 17:04:14 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726992AbgCFREN (ORCPT ); Fri, 6 Mar 2020 12:04:13 -0500 Received: from mx2.suse.de ([195.135.220.15]:42930 "EHLO mx2.suse.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726237AbgCFREM (ORCPT ); Fri, 6 Mar 2020 12:04:12 -0500 X-Virus-Scanned: by amavisd-new at test-mx.suse.de Received: from relay2.suse.de (unknown [195.135.220.254]) by mx2.suse.de (Postfix) with ESMTP id 11892B08C; Fri, 6 Mar 2020 17:04:10 +0000 (UTC) Received: by unicorn.suse.cz (Postfix, from userid 1000) id BBDD8E00E7; Fri, 6 Mar 2020 18:04:09 +0100 (CET) Message-Id: <6a7d5aae7a4ddd3d2254b7d08b8a0b8587c784e7.1583513281.git.mkubecek@suse.cz> In-Reply-To: References: From: Michal Kubecek Subject: [PATCH ethtool v3 02/25] update UAPI header copies To: John Linville , netdev@vger.kernel.org Cc: Andrew Lunn , Florian Fainelli Date: Fri, 6 Mar 2020 18:04:09 +0100 (CET) Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org Update to v5.6-rc1. Signed-off-by: Michal Kubecek --- uapi/linux/ethtool.h | 17 +++++++++++++++++ uapi/linux/net_tstamp.h | 27 +++++++++++++++++++++++++++ 2 files changed, 44 insertions(+) diff --git a/uapi/linux/ethtool.h b/uapi/linux/ethtool.h index 9afd2e6c5eea..16198061d723 100644 --- a/uapi/linux/ethtool.h +++ b/uapi/linux/ethtool.h @@ -591,6 +591,9 @@ struct ethtool_pauseparam { * @ETH_SS_RSS_HASH_FUNCS: RSS hush function names * @ETH_SS_PHY_STATS: Statistic names, for use with %ETHTOOL_GPHYSTATS * @ETH_SS_PHY_TUNABLES: PHY tunable names + * @ETH_SS_LINK_MODES: link mode names + * @ETH_SS_MSG_CLASSES: debug message class names + * @ETH_SS_WOL_MODES: wake-on-lan modes */ enum ethtool_stringset { ETH_SS_TEST = 0, @@ -602,6 +605,12 @@ enum ethtool_stringset { ETH_SS_TUNABLES, ETH_SS_PHY_STATS, ETH_SS_PHY_TUNABLES, + ETH_SS_LINK_MODES, + ETH_SS_MSG_CLASSES, + ETH_SS_WOL_MODES, + + /* add new constants above here */ + ETH_SS_COUNT }; /** @@ -1505,6 +1514,11 @@ enum ethtool_link_mode_bit_indices { ETHTOOL_LINK_MODE_200000baseCR4_Full_BIT = 66, ETHTOOL_LINK_MODE_100baseT1_Full_BIT = 67, ETHTOOL_LINK_MODE_1000baseT1_Full_BIT = 68, + ETHTOOL_LINK_MODE_400000baseKR8_Full_BIT = 69, + ETHTOOL_LINK_MODE_400000baseSR8_Full_BIT = 70, + ETHTOOL_LINK_MODE_400000baseLR8_ER8_FR8_Full_BIT = 71, + ETHTOOL_LINK_MODE_400000baseDR8_Full_BIT = 72, + ETHTOOL_LINK_MODE_400000baseCR8_Full_BIT = 73, /* must be last entry */ __ETHTOOL_LINK_MODE_MASK_NBITS @@ -1616,6 +1630,7 @@ enum ethtool_link_mode_bit_indices { #define SPEED_56000 56000 #define SPEED_100000 100000 #define SPEED_200000 200000 +#define SPEED_400000 400000 #define SPEED_UNKNOWN -1 @@ -1680,6 +1695,8 @@ static __inline__ int ethtool_validate_duplex(__u8 duplex) #define WAKE_MAGICSECURE (1 << 6) /* only meaningful if WAKE_MAGIC */ #define WAKE_FILTER (1 << 7) +#define WOL_MODE_COUNT 8 + /* L2-L4 network traffic flow types */ #define TCP_V4_FLOW 0x01 /* hash or spec (tcp_ip4_spec) */ #define UDP_V4_FLOW 0x02 /* hash or spec (udp_ip4_spec) */ diff --git a/uapi/linux/net_tstamp.h b/uapi/linux/net_tstamp.h index 3d421d912193..f96e650d0af9 100644 --- a/uapi/linux/net_tstamp.h +++ b/uapi/linux/net_tstamp.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ /* * Userspace API for hardware time stamping of network packets * @@ -89,6 +90,14 @@ enum hwtstamp_tx_types { * queue. */ HWTSTAMP_TX_ONESTEP_SYNC, + + /* + * Same as HWTSTAMP_TX_ONESTEP_SYNC, but also enables time + * stamp insertion directly into PDelay_Resp packets. In this + * case, neither transmitted Sync nor PDelay_Resp packets will + * receive a time stamp via the socket error queue. + */ + HWTSTAMP_TX_ONESTEP_P2P, }; /* possible values for hwtstamp_config->rx_filter */ @@ -140,4 +149,22 @@ struct scm_ts_pktinfo { __u32 reserved[2]; }; +/* + * SO_TXTIME gets a struct sock_txtime with flags being an integer bit + * field comprised of these values. + */ +enum txtime_flags { + SOF_TXTIME_DEADLINE_MODE = (1 << 0), + SOF_TXTIME_REPORT_ERRORS = (1 << 1), + + SOF_TXTIME_FLAGS_LAST = SOF_TXTIME_REPORT_ERRORS, + SOF_TXTIME_FLAGS_MASK = (SOF_TXTIME_FLAGS_LAST - 1) | + SOF_TXTIME_FLAGS_LAST +}; + +struct sock_txtime { + __kernel_clockid_t clockid;/* reference clockid */ + __u32 flags; /* as defined by enum txtime_flags */ +}; + #endif /* _NET_TIMESTAMPING_H */ From patchwork Fri Mar 6 17:04:19 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Michal Kubecek X-Patchwork-Id: 222925 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.8 required=3.0 tests=HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SIGNED_OFF_BY, SPF_HELO_NONE, SPF_PASS autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 110DDC10DCE for ; Fri, 6 Mar 2020 17:04:25 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id C5A2B206E2 for ; Fri, 6 Mar 2020 17:04:24 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727026AbgCFREY (ORCPT ); Fri, 6 Mar 2020 12:04:24 -0500 Received: from mx2.suse.de ([195.135.220.15]:43022 "EHLO mx2.suse.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726083AbgCFREX (ORCPT ); Fri, 6 Mar 2020 12:04:23 -0500 X-Virus-Scanned: by amavisd-new at test-mx.suse.de Received: from relay2.suse.de (unknown [195.135.220.254]) by mx2.suse.de (Postfix) with ESMTP id 2B5D9B152; Fri, 6 Mar 2020 17:04:20 +0000 (UTC) Received: by unicorn.suse.cz (Postfix, from userid 1000) id C9675E00E7; Fri, 6 Mar 2020 18:04:19 +0100 (CET) Message-Id: <5ac30be11d2b1fd4dacb23b1abbd286a4a3dc0d3.1583513281.git.mkubecek@suse.cz> In-Reply-To: References: From: Michal Kubecek Subject: [PATCH ethtool v3 04/25] use named initializers in command line option list To: John Linville , netdev@vger.kernel.org Cc: Andrew Lunn , Florian Fainelli Date: Fri, 6 Mar 2020 18:04:19 +0100 (CET) Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org The command line option list initialization does not look very nice and adding another struct member would not make it look any better. Reformat it to use named initializers. Also replace want_device with (bool) no_dev as only two options have want_device = 0 so that using an opposite would allow omitting the initializer for almost all options. Signed-off-by: Michal Kubecek --- ethtool.c | 559 ++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 358 insertions(+), 201 deletions(-) diff --git a/ethtool.c b/ethtool.c index dd0242b27a2f..3186a72644fd 100644 --- a/ethtool.c +++ b/ethtool.c @@ -5288,200 +5288,357 @@ int send_ioctl(struct cmd_context *ctx, void *cmd) static int show_usage(struct cmd_context *ctx); -static const struct option { - const char *opts; - int want_device; - int (*func)(struct cmd_context *); - char *help; - char *opthelp; -} args[] = { - { "-s|--change", 1, do_sset, "Change generic options", - " [ speed %d ]\n" - " [ duplex half|full ]\n" - " [ port tp|aui|bnc|mii|fibre ]\n" - " [ mdix auto|on|off ]\n" - " [ autoneg on|off ]\n" - " [ advertise %x ]\n" - " [ phyad %d ]\n" - " [ xcvr internal|external ]\n" - " [ wol p|u|m|b|a|g|s|f|d... ]\n" - " [ sopass %x:%x:%x:%x:%x:%x ]\n" - " [ msglvl %d | msglvl type on|off ... ]\n" }, - { "-a|--show-pause", 1, do_gpause, "Show pause options" }, - { "-A|--pause", 1, do_spause, "Set pause options", - " [ autoneg on|off ]\n" - " [ rx on|off ]\n" - " [ tx on|off ]\n" }, - { "-c|--show-coalesce", 1, do_gcoalesce, "Show coalesce options" }, - { "-C|--coalesce", 1, do_scoalesce, "Set coalesce options", - " [adaptive-rx on|off]\n" - " [adaptive-tx on|off]\n" - " [rx-usecs N]\n" - " [rx-frames N]\n" - " [rx-usecs-irq N]\n" - " [rx-frames-irq N]\n" - " [tx-usecs N]\n" - " [tx-frames N]\n" - " [tx-usecs-irq N]\n" - " [tx-frames-irq N]\n" - " [stats-block-usecs N]\n" - " [pkt-rate-low N]\n" - " [rx-usecs-low N]\n" - " [rx-frames-low N]\n" - " [tx-usecs-low N]\n" - " [tx-frames-low N]\n" - " [pkt-rate-high N]\n" - " [rx-usecs-high N]\n" - " [rx-frames-high N]\n" - " [tx-usecs-high N]\n" - " [tx-frames-high N]\n" - " [sample-interval N]\n" }, - { "-g|--show-ring", 1, do_gring, "Query RX/TX ring parameters" }, - { "-G|--set-ring", 1, do_sring, "Set RX/TX ring parameters", - " [ rx N ]\n" - " [ rx-mini N ]\n" - " [ rx-jumbo N ]\n" - " [ tx N ]\n" }, - { "-k|--show-features|--show-offload", 1, do_gfeatures, - "Get state of protocol offload and other features" }, - { "-K|--features|--offload", 1, do_sfeatures, - "Set protocol offload and other features", - " FEATURE on|off ...\n" }, - { "-i|--driver", 1, do_gdrv, "Show driver information" }, - { "-d|--register-dump", 1, do_gregs, "Do a register dump", - " [ raw on|off ]\n" - " [ file FILENAME ]\n" }, - { "-e|--eeprom-dump", 1, do_geeprom, "Do a EEPROM dump", - " [ raw on|off ]\n" - " [ offset N ]\n" - " [ length N ]\n" }, - { "-E|--change-eeprom", 1, do_seeprom, - "Change bytes in device EEPROM", - " [ magic N ]\n" - " [ offset N ]\n" - " [ length N ]\n" - " [ value N ]\n" }, - { "-r|--negotiate", 1, do_nway_rst, "Restart N-WAY negotiation" }, - { "-p|--identify", 1, do_phys_id, - "Show visible port identification (e.g. blinking)", - " [ TIME-IN-SECONDS ]\n" }, - { "-t|--test", 1, do_test, "Execute adapter self test", - " [ online | offline | external_lb ]\n" }, - { "-S|--statistics", 1, do_gnicstats, "Show adapter statistics" }, - { "--phy-statistics", 1, do_gphystats, - "Show phy statistics" }, - { "-n|-u|--show-nfc|--show-ntuple", 1, do_grxclass, - "Show Rx network flow classification options or rules", - " [ rx-flow-hash tcp4|udp4|ah4|esp4|sctp4|" - "tcp6|udp6|ah6|esp6|sctp6 [context %d] |\n" - " rule %d ]\n" }, - { "-N|-U|--config-nfc|--config-ntuple", 1, do_srxclass, - "Configure Rx network flow classification options or rules", - " rx-flow-hash tcp4|udp4|ah4|esp4|sctp4|" - "tcp6|udp6|ah6|esp6|sctp6 m|v|t|s|d|f|n|r... [context %d] |\n" - " flow-type ether|ip4|tcp4|udp4|sctp4|ah4|esp4|" - "ip6|tcp6|udp6|ah6|esp6|sctp6\n" - " [ src %x:%x:%x:%x:%x:%x [m %x:%x:%x:%x:%x:%x] ]\n" - " [ dst %x:%x:%x:%x:%x:%x [m %x:%x:%x:%x:%x:%x] ]\n" - " [ proto %d [m %x] ]\n" - " [ src-ip IP-ADDRESS [m IP-ADDRESS] ]\n" - " [ dst-ip IP-ADDRESS [m IP-ADDRESS] ]\n" - " [ tos %d [m %x] ]\n" - " [ tclass %d [m %x] ]\n" - " [ l4proto %d [m %x] ]\n" - " [ src-port %d [m %x] ]\n" - " [ dst-port %d [m %x] ]\n" - " [ spi %d [m %x] ]\n" - " [ vlan-etype %x [m %x] ]\n" - " [ vlan %x [m %x] ]\n" - " [ user-def %x [m %x] ]\n" - " [ dst-mac %x:%x:%x:%x:%x:%x [m %x:%x:%x:%x:%x:%x] ]\n" - " [ action %d ] | [ vf %d queue %d ]\n" - " [ context %d ]\n" - " [ loc %d]] |\n" - " delete %d\n" }, - { "-T|--show-time-stamping", 1, do_tsinfo, - "Show time stamping capabilities" }, - { "-x|--show-rxfh-indir|--show-rxfh", 1, do_grxfh, - "Show Rx flow hash indirection table and/or RSS hash key", - " [ context %d ]\n" }, - { "-X|--set-rxfh-indir|--rxfh", 1, do_srxfh, - "Set Rx flow hash indirection table and/or RSS hash key", - " [ context %d|new ]\n" - " [ equal N | weight W0 W1 ... | default ]\n" - " [ hkey %x:%x:%x:%x:%x:.... ]\n" - " [ hfunc FUNC ]\n" - " [ delete ]\n" }, - { "-f|--flash", 1, do_flash, - "Flash firmware image from the specified file to a region on the device", - " FILENAME [ REGION-NUMBER-TO-FLASH ]\n" }, - { "-P|--show-permaddr", 1, do_permaddr, - "Show permanent hardware address" }, - { "-w|--get-dump", 1, do_getfwdump, - "Get dump flag, data", - " [ data FILENAME ]\n" }, - { "-W|--set-dump", 1, do_setfwdump, - "Set dump flag of the device", - " N\n"}, - { "-l|--show-channels", 1, do_gchannels, "Query Channels" }, - { "-L|--set-channels", 1, do_schannels, "Set Channels", - " [ rx N ]\n" - " [ tx N ]\n" - " [ other N ]\n" - " [ combined N ]\n" }, - { "--show-priv-flags", 1, do_gprivflags, "Query private flags" }, - { "--set-priv-flags", 1, do_sprivflags, "Set private flags", - " FLAG on|off ...\n" }, - { "-m|--dump-module-eeprom|--module-info", 1, do_getmodule, - "Query/Decode Module EEPROM information and optical diagnostics if available", - " [ raw on|off ]\n" - " [ hex on|off ]\n" - " [ offset N ]\n" - " [ length N ]\n" }, - { "--show-eee", 1, do_geee, "Show EEE settings"}, - { "--set-eee", 1, do_seee, "Set EEE settings", - " [ eee on|off ]\n" - " [ advertise %x ]\n" - " [ tx-lpi on|off ]\n" - " [ tx-timer %d ]\n"}, - { "--set-phy-tunable", 1, do_set_phy_tunable, "Set PHY tunable", - " [ downshift on|off [count N] ]\n" - " [ fast-link-down on|off [msecs N] ]\n" - " [ energy-detect-power-down on|off [msecs N] ]\n"}, - { "--get-phy-tunable", 1, do_get_phy_tunable, "Get PHY tunable", - " [ downshift ]\n" - " [ fast-link-down ]\n" - " [ energy-detect-power-down ]\n"}, - { "--reset", 1, do_reset, "Reset components", - " [ flags %x ]\n" - " [ mgmt ]\n" - " [ mgmt-shared ]\n" - " [ irq ]\n" - " [ irq-shared ]\n" - " [ dma ]\n" - " [ dma-shared ]\n" - " [ filter ]\n" - " [ filter-shared ]\n" - " [ offload ]\n" - " [ offload-shared ]\n" - " [ mac ]\n" - " [ mac-shared ]\n" - " [ phy ]\n" - " [ phy-shared ]\n" - " [ ram ]\n" - " [ ram-shared ]\n" - " [ ap ]\n" - " [ ap-shared ]\n" - " [ dedicated ]\n" - " [ all ]\n"}, - { "--show-fec", 1, do_gfec, "Show FEC settings"}, - { "--set-fec", 1, do_sfec, "Set FEC settings", - " [ encoding auto|off|rs|baser [...]]\n"}, - { "-Q|--per-queue", 1, do_perqueue, "Apply per-queue command." - "The supported sub commands include --show-coalesce, --coalesce", - " [queue_mask %x] SUB_COMMAND\n"}, - { "-h|--help", 0, show_usage, "Show this help" }, - { "--version", 0, do_version, "Show version number" }, +struct option { + const char *opts; + bool no_dev; + int (*func)(struct cmd_context *); + const char *help; + const char *xhelp; +}; + +static const struct option args[] = { + { + .opts = "-s|--change", + .func = do_sset, + .help = "Change generic options", + .xhelp = " [ speed %d ]\n" + " [ duplex half|full ]\n" + " [ port tp|aui|bnc|mii|fibre ]\n" + " [ mdix auto|on|off ]\n" + " [ autoneg on|off ]\n" + " [ advertise %x ]\n" + " [ phyad %d ]\n" + " [ xcvr internal|external ]\n" + " [ wol p|u|m|b|a|g|s|f|d... ]\n" + " [ sopass %x:%x:%x:%x:%x:%x ]\n" + " [ msglvl %d | msglvl type on|off ... ]\n" + }, + { + .opts = "-a|--show-pause", + .func = do_gpause, + .help = "Show pause options" + }, + { + .opts = "-A|--pause", + .func = do_spause, + .help = "Set pause options", + .xhelp = " [ autoneg on|off ]\n" + " [ rx on|off ]\n" + " [ tx on|off ]\n" + }, + { + .opts = "-c|--show-coalesce", + .func = do_gcoalesce, + .help = "Show coalesce options" + }, + { + .opts = "-C|--coalesce", + .func = do_scoalesce, + .help = "Set coalesce options", + .xhelp = " [adaptive-rx on|off]\n" + " [adaptive-tx on|off]\n" + " [rx-usecs N]\n" + " [rx-frames N]\n" + " [rx-usecs-irq N]\n" + " [rx-frames-irq N]\n" + " [tx-usecs N]\n" + " [tx-frames N]\n" + " [tx-usecs-irq N]\n" + " [tx-frames-irq N]\n" + " [stats-block-usecs N]\n" + " [pkt-rate-low N]\n" + " [rx-usecs-low N]\n" + " [rx-frames-low N]\n" + " [tx-usecs-low N]\n" + " [tx-frames-low N]\n" + " [pkt-rate-high N]\n" + " [rx-usecs-high N]\n" + " [rx-frames-high N]\n" + " [tx-usecs-high N]\n" + " [tx-frames-high N]\n" + " [sample-interval N]\n" + }, + { + .opts = "-g|--show-ring", + .func = do_gring, + .help = "Query RX/TX ring parameters" + }, + { + .opts = "-G|--set-ring", + .func = do_sring, + .help = "Set RX/TX ring parameters", + .xhelp = " [ rx N ]\n" + " [ rx-mini N ]\n" + " [ rx-jumbo N ]\n" + " [ tx N ]\n" + }, + { + .opts = "-k|--show-features|--show-offload", + .func = do_gfeatures, + .help = "Get state of protocol offload and other features" + }, + { + .opts = "-K|--features|--offload", + .func = do_sfeatures, + .help = "Set protocol offload and other features", + .xhelp = " FEATURE on|off ...\n" + }, + { + .opts = "-i|--driver", + .func = do_gdrv, + .help = "Show driver information" + }, + { + .opts = "-d|--register-dump", + .func = do_gregs, + .help = "Do a register dump", + .xhelp = " [ raw on|off ]\n" + " [ file FILENAME ]\n" + }, + { + .opts = "-e|--eeprom-dump", + .func = do_geeprom, + .help = "Do a EEPROM dump", + .xhelp = " [ raw on|off ]\n" + " [ offset N ]\n" + " [ length N ]\n" + }, + { + .opts = "-E|--change-eeprom", + .func = do_seeprom, + .help = "Change bytes in device EEPROM", + .xhelp = " [ magic N ]\n" + " [ offset N ]\n" + " [ length N ]\n" + " [ value N ]\n" + }, + { + .opts = "-r|--negotiate", + .func = do_nway_rst, + .help = "Restart N-WAY negotiation" + }, + { + .opts = "-p|--identify", + .func = do_phys_id, + .help = "Show visible port identification (e.g. blinking)", + .xhelp = " [ TIME-IN-SECONDS ]\n" + }, + { + .opts = "-t|--test", + .func = do_test, + .help = "Execute adapter self test", + .xhelp = " [ online | offline | external_lb ]\n" + }, + { + .opts = "-S|--statistics", + .func = do_gnicstats, + .help = "Show adapter statistics" + }, + { + .opts = "--phy-statistics", + .func = do_gphystats, + .help = "Show phy statistics" + }, + { + .opts = "-n|-u|--show-nfc|--show-ntuple", + .func = do_grxclass, + .help = "Show Rx network flow classification options or rules", + .xhelp = " [ rx-flow-hash tcp4|udp4|ah4|esp4|sctp4|" + "tcp6|udp6|ah6|esp6|sctp6 [context %d] |\n" + " rule %d ]\n" + }, + { + .opts = "-N|-U|--config-nfc|--config-ntuple", + .func = do_srxclass, + .help = "Configure Rx network flow classification options or rules", + .xhelp = " rx-flow-hash tcp4|udp4|ah4|esp4|sctp4|" + "tcp6|udp6|ah6|esp6|sctp6 m|v|t|s|d|f|n|r... [context %d] |\n" + " flow-type ether|ip4|tcp4|udp4|sctp4|ah4|esp4|" + "ip6|tcp6|udp6|ah6|esp6|sctp6\n" + " [ src %x:%x:%x:%x:%x:%x [m %x:%x:%x:%x:%x:%x] ]\n" + " [ dst %x:%x:%x:%x:%x:%x [m %x:%x:%x:%x:%x:%x] ]\n" + " [ proto %d [m %x] ]\n" + " [ src-ip IP-ADDRESS [m IP-ADDRESS] ]\n" + " [ dst-ip IP-ADDRESS [m IP-ADDRESS] ]\n" + " [ tos %d [m %x] ]\n" + " [ tclass %d [m %x] ]\n" + " [ l4proto %d [m %x] ]\n" + " [ src-port %d [m %x] ]\n" + " [ dst-port %d [m %x] ]\n" + " [ spi %d [m %x] ]\n" + " [ vlan-etype %x [m %x] ]\n" + " [ vlan %x [m %x] ]\n" + " [ user-def %x [m %x] ]\n" + " [ dst-mac %x:%x:%x:%x:%x:%x [m %x:%x:%x:%x:%x:%x] ]\n" + " [ action %d ] | [ vf %d queue %d ]\n" + " [ context %d ]\n" + " [ loc %d]] |\n" + " delete %d\n" + }, + { + .opts = "-T|--show-time-stamping", + .func = do_tsinfo, + .help = "Show time stamping capabilities" + }, + { + .opts = "-x|--show-rxfh-indir|--show-rxfh", + .func = do_grxfh, + .help = "Show Rx flow hash indirection table and/or RSS hash key", + .xhelp = " [ context %d ]\n" + }, + { + .opts = "-X|--set-rxfh-indir|--rxfh", + .func = do_srxfh, + .help = "Set Rx flow hash indirection table and/or RSS hash key", + .xhelp = " [ context %d|new ]\n" + " [ equal N | weight W0 W1 ... | default ]\n" + " [ hkey %x:%x:%x:%x:%x:.... ]\n" + " [ hfunc FUNC ]\n" + " [ delete ]\n" + }, + { + .opts = "-f|--flash", + .func = do_flash, + .help = "Flash firmware image from the specified file to a region on the device", + .xhelp = " FILENAME [ REGION-NUMBER-TO-FLASH ]\n" + }, + { + .opts = "-P|--show-permaddr", + .func = do_permaddr, + .help = "Show permanent hardware address" + }, + { + .opts = "-w|--get-dump", + .func = do_getfwdump, + .help = "Get dump flag, data", + .xhelp = " [ data FILENAME ]\n" + }, + { + .opts = "-W|--set-dump", + .func = do_setfwdump, + .help = "Set dump flag of the device", + .xhelp = " N\n" + }, + { + .opts = "-l|--show-channels", + .func = do_gchannels, + .help = "Query Channels" + }, + { + .opts = "-L|--set-channels", + .func = do_schannels, + .help = "Set Channels", + .xhelp = " [ rx N ]\n" + " [ tx N ]\n" + " [ other N ]\n" + " [ combined N ]\n" + }, + { + .opts = "--show-priv-flags", + .func = do_gprivflags, + .help = "Query private flags" + }, + { + .opts = "--set-priv-flags", + .func = do_sprivflags, + .help = "Set private flags", + .xhelp = " FLAG on|off ...\n" + }, + { + .opts = "-m|--dump-module-eeprom|--module-info", + .func = do_getmodule, + .help = "Query/Decode Module EEPROM information and optical diagnostics if available", + .xhelp = " [ raw on|off ]\n" + " [ hex on|off ]\n" + " [ offset N ]\n" + " [ length N ]\n" + }, + { + .opts = "--show-eee", + .func = do_geee, + .help = "Show EEE settings", + }, + { + .opts = "--set-eee", + .func = do_seee, + .help = "Set EEE settings", + .xhelp = " [ eee on|off ]\n" + " [ advertise %x ]\n" + " [ tx-lpi on|off ]\n" + " [ tx-timer %d ]\n" + }, + { + .opts = "--set-phy-tunable", + .func = do_set_phy_tunable, + .help = "Set PHY tunable", + .xhelp = " [ downshift on|off [count N] ]\n" + " [ fast-link-down on|off [msecs N] ]\n" + " [ energy-detect-power-down on|off [msecs N] ]\n" + }, + { + .opts = "--get-phy-tunable", + .func = do_get_phy_tunable, + .help = "Get PHY tunable", + .xhelp = " [ downshift ]\n" + " [ fast-link-down ]\n" + " [ energy-detect-power-down ]\n" + }, + { + .opts = "--reset", + .func = do_reset, + .help = "Reset components", + .xhelp = " [ flags %x ]\n" + " [ mgmt ]\n" + " [ mgmt-shared ]\n" + " [ irq ]\n" + " [ irq-shared ]\n" + " [ dma ]\n" + " [ dma-shared ]\n" + " [ filter ]\n" + " [ filter-shared ]\n" + " [ offload ]\n" + " [ offload-shared ]\n" + " [ mac ]\n" + " [ mac-shared ]\n" + " [ phy ]\n" + " [ phy-shared ]\n" + " [ ram ]\n" + " [ ram-shared ]\n" + " [ ap ]\n" + " [ ap-shared ]\n" + " [ dedicated ]\n" + " [ all ]\n" + }, + { + .opts = "--show-fec", + .func = do_gfec, + .help = "Show FEC settings", + }, + { + .opts = "--set-fec", + .func = do_sfec, + .help = "Set FEC settings", + .xhelp = " [ encoding auto|off|rs|baser [...]]\n" + }, + { + .opts = "-Q|--per-queue", + .func = do_perqueue, + .help = "Apply per-queue command. ", + .xhelp = "The supported sub commands include --show-coalesce, --coalesce" + " [queue_mask %x] SUB_COMMAND\n", + }, + { + .opts = "-h|--help", + .no_dev = true, + .func = show_usage, + .help = "Show this help" + }, + { + .opts = "--version", + .no_dev = true, + .func = do_version, + .help = "Show version number" + }, {} }; @@ -5499,10 +5656,10 @@ static int show_usage(struct cmd_context *ctx maybe_unused) fputs(" ethtool [ --debug MASK ] ", stdout); fprintf(stdout, "%s %s\t%s\n", args[i].opts, - args[i].want_device ? "DEVNAME" : "\t", + args[i].no_dev ? "\t" : "DEVNAME", args[i].help); - if (args[i].opthelp) - fputs(args[i].opthelp, stdout); + if (args[i].xhelp) + fputs(args[i].xhelp, stdout); } return 0; @@ -5702,8 +5859,8 @@ static int do_perqueue(struct cmd_context *ctx) int main(int argc, char **argp) { int (*func)(struct cmd_context *); - int want_device; struct cmd_context ctx; + bool no_dev; int k; init_global_link_mode_masks(); @@ -5738,16 +5895,16 @@ int main(int argc, char **argp) argp++; argc--; func = args[k].func; - want_device = args[k].want_device; + no_dev = args[k].no_dev; goto opt_found; } if ((*argp)[0] == '-') exit_bad_args(); func = do_gset; - want_device = 1; + no_dev = false; opt_found: - if (want_device) { + if (!no_dev) { ctx.devname = *argp++; argc--; From patchwork Fri Mar 6 17:04:24 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Michal Kubecek X-Patchwork-Id: 222924 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.0 required=3.0 tests=HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SIGNED_OFF_BY, SPF_HELO_NONE, SPF_PASS, UPPERCASE_50_75 autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id E86E9C10F00 for ; Fri, 6 Mar 2020 17:04:34 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 9B3A1206E2 for ; Fri, 6 Mar 2020 17:04:34 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727076AbgCFREe (ORCPT ); Fri, 6 Mar 2020 12:04:34 -0500 Received: from mx2.suse.de ([195.135.220.15]:43118 "EHLO mx2.suse.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727030AbgCFREd (ORCPT ); Fri, 6 Mar 2020 12:04:33 -0500 X-Virus-Scanned: by amavisd-new at test-mx.suse.de Received: from relay2.suse.de (unknown [195.135.220.254]) by mx2.suse.de (Postfix) with ESMTP id 3E5DEB20F; Fri, 6 Mar 2020 17:04:25 +0000 (UTC) Received: by unicorn.suse.cz (Postfix, from userid 1000) id CD022E00E7; Fri, 6 Mar 2020 18:04:24 +0100 (CET) Message-Id: In-Reply-To: References: From: Michal Kubecek Subject: [PATCH ethtool v3 05/25] netlink: add netlink related UAPI header files To: John Linville , netdev@vger.kernel.org Cc: Andrew Lunn , Florian Fainelli Date: Fri, 6 Mar 2020 18:04:24 +0100 (CET) Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org Add copies of kernel UAPI header files needed for netlink interface: The (sanitized) copies are taken from v5.6-rc1. v2: - add linux/rtnetlink.h and linux/if_link.h Signed-off-by: Michal Kubecek --- uapi/linux/ethtool_netlink.h | 237 ++++++++ uapi/linux/genetlink.h | 89 +++ uapi/linux/if_link.h | 1051 ++++++++++++++++++++++++++++++++++ uapi/linux/netlink.h | 248 ++++++++ uapi/linux/rtnetlink.h | 777 +++++++++++++++++++++++++ 5 files changed, 2402 insertions(+) create mode 100644 uapi/linux/ethtool_netlink.h create mode 100644 uapi/linux/genetlink.h create mode 100644 uapi/linux/if_link.h create mode 100644 uapi/linux/netlink.h create mode 100644 uapi/linux/rtnetlink.h diff --git a/uapi/linux/ethtool_netlink.h b/uapi/linux/ethtool_netlink.h new file mode 100644 index 000000000000..ad6d3a00019d --- /dev/null +++ b/uapi/linux/ethtool_netlink.h @@ -0,0 +1,237 @@ +/* SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note */ +/* + * include/uapi/linux/ethtool_netlink.h - netlink interface for ethtool + * + * See Documentation/networking/ethtool-netlink.txt in kernel source tree for + * doucumentation of the interface. + */ + +#ifndef _LINUX_ETHTOOL_NETLINK_H_ +#define _LINUX_ETHTOOL_NETLINK_H_ + +#include + +/* message types - userspace to kernel */ +enum { + ETHTOOL_MSG_USER_NONE, + ETHTOOL_MSG_STRSET_GET, + ETHTOOL_MSG_LINKINFO_GET, + ETHTOOL_MSG_LINKINFO_SET, + ETHTOOL_MSG_LINKMODES_GET, + ETHTOOL_MSG_LINKMODES_SET, + ETHTOOL_MSG_LINKSTATE_GET, + ETHTOOL_MSG_DEBUG_GET, + ETHTOOL_MSG_DEBUG_SET, + ETHTOOL_MSG_WOL_GET, + ETHTOOL_MSG_WOL_SET, + + /* add new constants above here */ + __ETHTOOL_MSG_USER_CNT, + ETHTOOL_MSG_USER_MAX = __ETHTOOL_MSG_USER_CNT - 1 +}; + +/* message types - kernel to userspace */ +enum { + ETHTOOL_MSG_KERNEL_NONE, + ETHTOOL_MSG_STRSET_GET_REPLY, + ETHTOOL_MSG_LINKINFO_GET_REPLY, + ETHTOOL_MSG_LINKINFO_NTF, + ETHTOOL_MSG_LINKMODES_GET_REPLY, + ETHTOOL_MSG_LINKMODES_NTF, + ETHTOOL_MSG_LINKSTATE_GET_REPLY, + ETHTOOL_MSG_DEBUG_GET_REPLY, + ETHTOOL_MSG_DEBUG_NTF, + ETHTOOL_MSG_WOL_GET_REPLY, + ETHTOOL_MSG_WOL_NTF, + + /* add new constants above here */ + __ETHTOOL_MSG_KERNEL_CNT, + ETHTOOL_MSG_KERNEL_MAX = __ETHTOOL_MSG_KERNEL_CNT - 1 +}; + +/* request header */ + +/* use compact bitsets in reply */ +#define ETHTOOL_FLAG_COMPACT_BITSETS (1 << 0) +/* provide optional reply for SET or ACT requests */ +#define ETHTOOL_FLAG_OMIT_REPLY (1 << 1) + +#define ETHTOOL_FLAG_ALL (ETHTOOL_FLAG_COMPACT_BITSETS | \ + ETHTOOL_FLAG_OMIT_REPLY) + +enum { + ETHTOOL_A_HEADER_UNSPEC, + ETHTOOL_A_HEADER_DEV_INDEX, /* u32 */ + ETHTOOL_A_HEADER_DEV_NAME, /* string */ + ETHTOOL_A_HEADER_FLAGS, /* u32 - ETHTOOL_FLAG_* */ + + /* add new constants above here */ + __ETHTOOL_A_HEADER_CNT, + ETHTOOL_A_HEADER_MAX = __ETHTOOL_A_HEADER_CNT - 1 +}; + +/* bit sets */ + +enum { + ETHTOOL_A_BITSET_BIT_UNSPEC, + ETHTOOL_A_BITSET_BIT_INDEX, /* u32 */ + ETHTOOL_A_BITSET_BIT_NAME, /* string */ + ETHTOOL_A_BITSET_BIT_VALUE, /* flag */ + + /* add new constants above here */ + __ETHTOOL_A_BITSET_BIT_CNT, + ETHTOOL_A_BITSET_BIT_MAX = __ETHTOOL_A_BITSET_BIT_CNT - 1 +}; + +enum { + ETHTOOL_A_BITSET_BITS_UNSPEC, + ETHTOOL_A_BITSET_BITS_BIT, /* nest - _A_BITSET_BIT_* */ + + /* add new constants above here */ + __ETHTOOL_A_BITSET_BITS_CNT, + ETHTOOL_A_BITSET_BITS_MAX = __ETHTOOL_A_BITSET_BITS_CNT - 1 +}; + +enum { + ETHTOOL_A_BITSET_UNSPEC, + ETHTOOL_A_BITSET_NOMASK, /* flag */ + ETHTOOL_A_BITSET_SIZE, /* u32 */ + ETHTOOL_A_BITSET_BITS, /* nest - _A_BITSET_BITS_* */ + ETHTOOL_A_BITSET_VALUE, /* binary */ + ETHTOOL_A_BITSET_MASK, /* binary */ + + /* add new constants above here */ + __ETHTOOL_A_BITSET_CNT, + ETHTOOL_A_BITSET_MAX = __ETHTOOL_A_BITSET_CNT - 1 +}; + +/* string sets */ + +enum { + ETHTOOL_A_STRING_UNSPEC, + ETHTOOL_A_STRING_INDEX, /* u32 */ + ETHTOOL_A_STRING_VALUE, /* string */ + + /* add new constants above here */ + __ETHTOOL_A_STRING_CNT, + ETHTOOL_A_STRING_MAX = __ETHTOOL_A_STRING_CNT - 1 +}; + +enum { + ETHTOOL_A_STRINGS_UNSPEC, + ETHTOOL_A_STRINGS_STRING, /* nest - _A_STRINGS_* */ + + /* add new constants above here */ + __ETHTOOL_A_STRINGS_CNT, + ETHTOOL_A_STRINGS_MAX = __ETHTOOL_A_STRINGS_CNT - 1 +}; + +enum { + ETHTOOL_A_STRINGSET_UNSPEC, + ETHTOOL_A_STRINGSET_ID, /* u32 */ + ETHTOOL_A_STRINGSET_COUNT, /* u32 */ + ETHTOOL_A_STRINGSET_STRINGS, /* nest - _A_STRINGS_* */ + + /* add new constants above here */ + __ETHTOOL_A_STRINGSET_CNT, + ETHTOOL_A_STRINGSET_MAX = __ETHTOOL_A_STRINGSET_CNT - 1 +}; + +enum { + ETHTOOL_A_STRINGSETS_UNSPEC, + ETHTOOL_A_STRINGSETS_STRINGSET, /* nest - _A_STRINGSET_* */ + + /* add new constants above here */ + __ETHTOOL_A_STRINGSETS_CNT, + ETHTOOL_A_STRINGSETS_MAX = __ETHTOOL_A_STRINGSETS_CNT - 1 +}; + +/* STRSET */ + +enum { + ETHTOOL_A_STRSET_UNSPEC, + ETHTOOL_A_STRSET_HEADER, /* nest - _A_HEADER_* */ + ETHTOOL_A_STRSET_STRINGSETS, /* nest - _A_STRINGSETS_* */ + ETHTOOL_A_STRSET_COUNTS_ONLY, /* flag */ + + /* add new constants above here */ + __ETHTOOL_A_STRSET_CNT, + ETHTOOL_A_STRSET_MAX = __ETHTOOL_A_STRSET_CNT - 1 +}; + +/* LINKINFO */ + +enum { + ETHTOOL_A_LINKINFO_UNSPEC, + ETHTOOL_A_LINKINFO_HEADER, /* nest - _A_HEADER_* */ + ETHTOOL_A_LINKINFO_PORT, /* u8 */ + ETHTOOL_A_LINKINFO_PHYADDR, /* u8 */ + ETHTOOL_A_LINKINFO_TP_MDIX, /* u8 */ + ETHTOOL_A_LINKINFO_TP_MDIX_CTRL, /* u8 */ + ETHTOOL_A_LINKINFO_TRANSCEIVER, /* u8 */ + + /* add new constants above here */ + __ETHTOOL_A_LINKINFO_CNT, + ETHTOOL_A_LINKINFO_MAX = __ETHTOOL_A_LINKINFO_CNT - 1 +}; + +/* LINKMODES */ + +enum { + ETHTOOL_A_LINKMODES_UNSPEC, + ETHTOOL_A_LINKMODES_HEADER, /* nest - _A_HEADER_* */ + ETHTOOL_A_LINKMODES_AUTONEG, /* u8 */ + ETHTOOL_A_LINKMODES_OURS, /* bitset */ + ETHTOOL_A_LINKMODES_PEER, /* bitset */ + ETHTOOL_A_LINKMODES_SPEED, /* u32 */ + ETHTOOL_A_LINKMODES_DUPLEX, /* u8 */ + + /* add new constants above here */ + __ETHTOOL_A_LINKMODES_CNT, + ETHTOOL_A_LINKMODES_MAX = __ETHTOOL_A_LINKMODES_CNT - 1 +}; + +/* LINKSTATE */ + +enum { + ETHTOOL_A_LINKSTATE_UNSPEC, + ETHTOOL_A_LINKSTATE_HEADER, /* nest - _A_HEADER_* */ + ETHTOOL_A_LINKSTATE_LINK, /* u8 */ + + /* add new constants above here */ + __ETHTOOL_A_LINKSTATE_CNT, + ETHTOOL_A_LINKSTATE_MAX = __ETHTOOL_A_LINKSTATE_CNT - 1 +}; + +/* DEBUG */ + +enum { + ETHTOOL_A_DEBUG_UNSPEC, + ETHTOOL_A_DEBUG_HEADER, /* nest - _A_HEADER_* */ + ETHTOOL_A_DEBUG_MSGMASK, /* bitset */ + + /* add new constants above here */ + __ETHTOOL_A_DEBUG_CNT, + ETHTOOL_A_DEBUG_MAX = __ETHTOOL_A_DEBUG_CNT - 1 +}; + +/* WOL */ + +enum { + ETHTOOL_A_WOL_UNSPEC, + ETHTOOL_A_WOL_HEADER, /* nest - _A_HEADER_* */ + ETHTOOL_A_WOL_MODES, /* bitset */ + ETHTOOL_A_WOL_SOPASS, /* binary */ + + /* add new constants above here */ + __ETHTOOL_A_WOL_CNT, + ETHTOOL_A_WOL_MAX = __ETHTOOL_A_WOL_CNT - 1 +}; + +/* generic netlink info */ +#define ETHTOOL_GENL_NAME "ethtool" +#define ETHTOOL_GENL_VERSION 1 + +#define ETHTOOL_MCGRP_MONITOR_NAME "monitor" + +#endif /* _LINUX_ETHTOOL_NETLINK_H_ */ diff --git a/uapi/linux/genetlink.h b/uapi/linux/genetlink.h new file mode 100644 index 000000000000..1317119cbff8 --- /dev/null +++ b/uapi/linux/genetlink.h @@ -0,0 +1,89 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +#ifndef __LINUX_GENERIC_NETLINK_H +#define __LINUX_GENERIC_NETLINK_H + +#include +#include + +#define GENL_NAMSIZ 16 /* length of family name */ + +#define GENL_MIN_ID NLMSG_MIN_TYPE +#define GENL_MAX_ID 1023 + +struct genlmsghdr { + __u8 cmd; + __u8 version; + __u16 reserved; +}; + +#define GENL_HDRLEN NLMSG_ALIGN(sizeof(struct genlmsghdr)) + +#define GENL_ADMIN_PERM 0x01 +#define GENL_CMD_CAP_DO 0x02 +#define GENL_CMD_CAP_DUMP 0x04 +#define GENL_CMD_CAP_HASPOL 0x08 +#define GENL_UNS_ADMIN_PERM 0x10 + +/* + * List of reserved static generic netlink identifiers: + */ +#define GENL_ID_CTRL NLMSG_MIN_TYPE +#define GENL_ID_VFS_DQUOT (NLMSG_MIN_TYPE + 1) +#define GENL_ID_PMCRAID (NLMSG_MIN_TYPE + 2) +/* must be last reserved + 1 */ +#define GENL_START_ALLOC (NLMSG_MIN_TYPE + 3) + +/************************************************************************** + * Controller + **************************************************************************/ + +enum { + CTRL_CMD_UNSPEC, + CTRL_CMD_NEWFAMILY, + CTRL_CMD_DELFAMILY, + CTRL_CMD_GETFAMILY, + CTRL_CMD_NEWOPS, + CTRL_CMD_DELOPS, + CTRL_CMD_GETOPS, + CTRL_CMD_NEWMCAST_GRP, + CTRL_CMD_DELMCAST_GRP, + CTRL_CMD_GETMCAST_GRP, /* unused */ + __CTRL_CMD_MAX, +}; + +#define CTRL_CMD_MAX (__CTRL_CMD_MAX - 1) + +enum { + CTRL_ATTR_UNSPEC, + CTRL_ATTR_FAMILY_ID, + CTRL_ATTR_FAMILY_NAME, + CTRL_ATTR_VERSION, + CTRL_ATTR_HDRSIZE, + CTRL_ATTR_MAXATTR, + CTRL_ATTR_OPS, + CTRL_ATTR_MCAST_GROUPS, + __CTRL_ATTR_MAX, +}; + +#define CTRL_ATTR_MAX (__CTRL_ATTR_MAX - 1) + +enum { + CTRL_ATTR_OP_UNSPEC, + CTRL_ATTR_OP_ID, + CTRL_ATTR_OP_FLAGS, + __CTRL_ATTR_OP_MAX, +}; + +#define CTRL_ATTR_OP_MAX (__CTRL_ATTR_OP_MAX - 1) + +enum { + CTRL_ATTR_MCAST_GRP_UNSPEC, + CTRL_ATTR_MCAST_GRP_NAME, + CTRL_ATTR_MCAST_GRP_ID, + __CTRL_ATTR_MCAST_GRP_MAX, +}; + +#define CTRL_ATTR_MCAST_GRP_MAX (__CTRL_ATTR_MCAST_GRP_MAX - 1) + + +#endif /* __LINUX_GENERIC_NETLINK_H */ diff --git a/uapi/linux/if_link.h b/uapi/linux/if_link.h new file mode 100644 index 000000000000..cb88bcb47287 --- /dev/null +++ b/uapi/linux/if_link.h @@ -0,0 +1,1051 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +#ifndef _LINUX_IF_LINK_H +#define _LINUX_IF_LINK_H + +#include +#include + +/* This struct should be in sync with struct rtnl_link_stats64 */ +struct rtnl_link_stats { + __u32 rx_packets; /* total packets received */ + __u32 tx_packets; /* total packets transmitted */ + __u32 rx_bytes; /* total bytes received */ + __u32 tx_bytes; /* total bytes transmitted */ + __u32 rx_errors; /* bad packets received */ + __u32 tx_errors; /* packet transmit problems */ + __u32 rx_dropped; /* no space in linux buffers */ + __u32 tx_dropped; /* no space available in linux */ + __u32 multicast; /* multicast packets received */ + __u32 collisions; + + /* detailed rx_errors: */ + __u32 rx_length_errors; + __u32 rx_over_errors; /* receiver ring buff overflow */ + __u32 rx_crc_errors; /* recved pkt with crc error */ + __u32 rx_frame_errors; /* recv'd frame alignment error */ + __u32 rx_fifo_errors; /* recv'r fifo overrun */ + __u32 rx_missed_errors; /* receiver missed packet */ + + /* detailed tx_errors */ + __u32 tx_aborted_errors; + __u32 tx_carrier_errors; + __u32 tx_fifo_errors; + __u32 tx_heartbeat_errors; + __u32 tx_window_errors; + + /* for cslip etc */ + __u32 rx_compressed; + __u32 tx_compressed; + + __u32 rx_nohandler; /* dropped, no handler found */ +}; + +/* The main device statistics structure */ +struct rtnl_link_stats64 { + __u64 rx_packets; /* total packets received */ + __u64 tx_packets; /* total packets transmitted */ + __u64 rx_bytes; /* total bytes received */ + __u64 tx_bytes; /* total bytes transmitted */ + __u64 rx_errors; /* bad packets received */ + __u64 tx_errors; /* packet transmit problems */ + __u64 rx_dropped; /* no space in linux buffers */ + __u64 tx_dropped; /* no space available in linux */ + __u64 multicast; /* multicast packets received */ + __u64 collisions; + + /* detailed rx_errors: */ + __u64 rx_length_errors; + __u64 rx_over_errors; /* receiver ring buff overflow */ + __u64 rx_crc_errors; /* recved pkt with crc error */ + __u64 rx_frame_errors; /* recv'd frame alignment error */ + __u64 rx_fifo_errors; /* recv'r fifo overrun */ + __u64 rx_missed_errors; /* receiver missed packet */ + + /* detailed tx_errors */ + __u64 tx_aborted_errors; + __u64 tx_carrier_errors; + __u64 tx_fifo_errors; + __u64 tx_heartbeat_errors; + __u64 tx_window_errors; + + /* for cslip etc */ + __u64 rx_compressed; + __u64 tx_compressed; + + __u64 rx_nohandler; /* dropped, no handler found */ +}; + +/* The struct should be in sync with struct ifmap */ +struct rtnl_link_ifmap { + __u64 mem_start; + __u64 mem_end; + __u64 base_addr; + __u16 irq; + __u8 dma; + __u8 port; +}; + +/* + * IFLA_AF_SPEC + * Contains nested attributes for address family specific attributes. + * Each address family may create a attribute with the address family + * number as type and create its own attribute structure in it. + * + * Example: + * [IFLA_AF_SPEC] = { + * [AF_INET] = { + * [IFLA_INET_CONF] = ..., + * }, + * [AF_INET6] = { + * [IFLA_INET6_FLAGS] = ..., + * [IFLA_INET6_CONF] = ..., + * } + * } + */ + +enum { + IFLA_UNSPEC, + IFLA_ADDRESS, + IFLA_BROADCAST, + IFLA_IFNAME, + IFLA_MTU, + IFLA_LINK, + IFLA_QDISC, + IFLA_STATS, + IFLA_COST, +#define IFLA_COST IFLA_COST + IFLA_PRIORITY, +#define IFLA_PRIORITY IFLA_PRIORITY + IFLA_MASTER, +#define IFLA_MASTER IFLA_MASTER + IFLA_WIRELESS, /* Wireless Extension event - see wireless.h */ +#define IFLA_WIRELESS IFLA_WIRELESS + IFLA_PROTINFO, /* Protocol specific information for a link */ +#define IFLA_PROTINFO IFLA_PROTINFO + IFLA_TXQLEN, +#define IFLA_TXQLEN IFLA_TXQLEN + IFLA_MAP, +#define IFLA_MAP IFLA_MAP + IFLA_WEIGHT, +#define IFLA_WEIGHT IFLA_WEIGHT + IFLA_OPERSTATE, + IFLA_LINKMODE, + IFLA_LINKINFO, +#define IFLA_LINKINFO IFLA_LINKINFO + IFLA_NET_NS_PID, + IFLA_IFALIAS, + IFLA_NUM_VF, /* Number of VFs if device is SR-IOV PF */ + IFLA_VFINFO_LIST, + IFLA_STATS64, + IFLA_VF_PORTS, + IFLA_PORT_SELF, + IFLA_AF_SPEC, + IFLA_GROUP, /* Group the device belongs to */ + IFLA_NET_NS_FD, + IFLA_EXT_MASK, /* Extended info mask, VFs, etc */ + IFLA_PROMISCUITY, /* Promiscuity count: > 0 means acts PROMISC */ +#define IFLA_PROMISCUITY IFLA_PROMISCUITY + IFLA_NUM_TX_QUEUES, + IFLA_NUM_RX_QUEUES, + IFLA_CARRIER, + IFLA_PHYS_PORT_ID, + IFLA_CARRIER_CHANGES, + IFLA_PHYS_SWITCH_ID, + IFLA_LINK_NETNSID, + IFLA_PHYS_PORT_NAME, + IFLA_PROTO_DOWN, + IFLA_GSO_MAX_SEGS, + IFLA_GSO_MAX_SIZE, + IFLA_PAD, + IFLA_XDP, + IFLA_EVENT, + IFLA_NEW_NETNSID, + IFLA_IF_NETNSID, + IFLA_TARGET_NETNSID = IFLA_IF_NETNSID, /* new alias */ + IFLA_CARRIER_UP_COUNT, + IFLA_CARRIER_DOWN_COUNT, + IFLA_NEW_IFINDEX, + IFLA_MIN_MTU, + IFLA_MAX_MTU, + IFLA_PROP_LIST, + IFLA_ALT_IFNAME, /* Alternative ifname */ + IFLA_PERM_ADDRESS, + __IFLA_MAX +}; + + +#define IFLA_MAX (__IFLA_MAX - 1) + +/* backwards compatibility for userspace */ +#define IFLA_RTA(r) ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ifinfomsg)))) +#define IFLA_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct ifinfomsg)) + +enum { + IFLA_INET_UNSPEC, + IFLA_INET_CONF, + __IFLA_INET_MAX, +}; + +#define IFLA_INET_MAX (__IFLA_INET_MAX - 1) + +/* ifi_flags. + + IFF_* flags. + + The only change is: + IFF_LOOPBACK, IFF_BROADCAST and IFF_POINTOPOINT are + more not changeable by user. They describe link media + characteristics and set by device driver. + + Comments: + - Combination IFF_BROADCAST|IFF_POINTOPOINT is invalid + - If neither of these three flags are set; + the interface is NBMA. + + - IFF_MULTICAST does not mean anything special: + multicasts can be used on all not-NBMA links. + IFF_MULTICAST means that this media uses special encapsulation + for multicast frames. Apparently, all IFF_POINTOPOINT and + IFF_BROADCAST devices are able to use multicasts too. + */ + +/* IFLA_LINK. + For usual devices it is equal ifi_index. + If it is a "virtual interface" (f.e. tunnel), ifi_link + can point to real physical interface (f.e. for bandwidth calculations), + or maybe 0, what means, that real media is unknown (usual + for IPIP tunnels, when route to endpoint is allowed to change) + */ + +/* Subtype attributes for IFLA_PROTINFO */ +enum { + IFLA_INET6_UNSPEC, + IFLA_INET6_FLAGS, /* link flags */ + IFLA_INET6_CONF, /* sysctl parameters */ + IFLA_INET6_STATS, /* statistics */ + IFLA_INET6_MCAST, /* MC things. What of them? */ + IFLA_INET6_CACHEINFO, /* time values and max reasm size */ + IFLA_INET6_ICMP6STATS, /* statistics (icmpv6) */ + IFLA_INET6_TOKEN, /* device token */ + IFLA_INET6_ADDR_GEN_MODE, /* implicit address generator mode */ + __IFLA_INET6_MAX +}; + +#define IFLA_INET6_MAX (__IFLA_INET6_MAX - 1) + +enum in6_addr_gen_mode { + IN6_ADDR_GEN_MODE_EUI64, + IN6_ADDR_GEN_MODE_NONE, + IN6_ADDR_GEN_MODE_STABLE_PRIVACY, + IN6_ADDR_GEN_MODE_RANDOM, +}; + +/* Bridge section */ + +enum { + IFLA_BR_UNSPEC, + IFLA_BR_FORWARD_DELAY, + IFLA_BR_HELLO_TIME, + IFLA_BR_MAX_AGE, + IFLA_BR_AGEING_TIME, + IFLA_BR_STP_STATE, + IFLA_BR_PRIORITY, + IFLA_BR_VLAN_FILTERING, + IFLA_BR_VLAN_PROTOCOL, + IFLA_BR_GROUP_FWD_MASK, + IFLA_BR_ROOT_ID, + IFLA_BR_BRIDGE_ID, + IFLA_BR_ROOT_PORT, + IFLA_BR_ROOT_PATH_COST, + IFLA_BR_TOPOLOGY_CHANGE, + IFLA_BR_TOPOLOGY_CHANGE_DETECTED, + IFLA_BR_HELLO_TIMER, + IFLA_BR_TCN_TIMER, + IFLA_BR_TOPOLOGY_CHANGE_TIMER, + IFLA_BR_GC_TIMER, + IFLA_BR_GROUP_ADDR, + IFLA_BR_FDB_FLUSH, + IFLA_BR_MCAST_ROUTER, + IFLA_BR_MCAST_SNOOPING, + IFLA_BR_MCAST_QUERY_USE_IFADDR, + IFLA_BR_MCAST_QUERIER, + IFLA_BR_MCAST_HASH_ELASTICITY, + IFLA_BR_MCAST_HASH_MAX, + IFLA_BR_MCAST_LAST_MEMBER_CNT, + IFLA_BR_MCAST_STARTUP_QUERY_CNT, + IFLA_BR_MCAST_LAST_MEMBER_INTVL, + IFLA_BR_MCAST_MEMBERSHIP_INTVL, + IFLA_BR_MCAST_QUERIER_INTVL, + IFLA_BR_MCAST_QUERY_INTVL, + IFLA_BR_MCAST_QUERY_RESPONSE_INTVL, + IFLA_BR_MCAST_STARTUP_QUERY_INTVL, + IFLA_BR_NF_CALL_IPTABLES, + IFLA_BR_NF_CALL_IP6TABLES, + IFLA_BR_NF_CALL_ARPTABLES, + IFLA_BR_VLAN_DEFAULT_PVID, + IFLA_BR_PAD, + IFLA_BR_VLAN_STATS_ENABLED, + IFLA_BR_MCAST_STATS_ENABLED, + IFLA_BR_MCAST_IGMP_VERSION, + IFLA_BR_MCAST_MLD_VERSION, + IFLA_BR_VLAN_STATS_PER_PORT, + IFLA_BR_MULTI_BOOLOPT, + __IFLA_BR_MAX, +}; + +#define IFLA_BR_MAX (__IFLA_BR_MAX - 1) + +struct ifla_bridge_id { + __u8 prio[2]; + __u8 addr[6]; /* ETH_ALEN */ +}; + +enum { + BRIDGE_MODE_UNSPEC, + BRIDGE_MODE_HAIRPIN, +}; + +enum { + IFLA_BRPORT_UNSPEC, + IFLA_BRPORT_STATE, /* Spanning tree state */ + IFLA_BRPORT_PRIORITY, /* " priority */ + IFLA_BRPORT_COST, /* " cost */ + IFLA_BRPORT_MODE, /* mode (hairpin) */ + IFLA_BRPORT_GUARD, /* bpdu guard */ + IFLA_BRPORT_PROTECT, /* root port protection */ + IFLA_BRPORT_FAST_LEAVE, /* multicast fast leave */ + IFLA_BRPORT_LEARNING, /* mac learning */ + IFLA_BRPORT_UNICAST_FLOOD, /* flood unicast traffic */ + IFLA_BRPORT_PROXYARP, /* proxy ARP */ + IFLA_BRPORT_LEARNING_SYNC, /* mac learning sync from device */ + IFLA_BRPORT_PROXYARP_WIFI, /* proxy ARP for Wi-Fi */ + IFLA_BRPORT_ROOT_ID, /* designated root */ + IFLA_BRPORT_BRIDGE_ID, /* designated bridge */ + IFLA_BRPORT_DESIGNATED_PORT, + IFLA_BRPORT_DESIGNATED_COST, + IFLA_BRPORT_ID, + IFLA_BRPORT_NO, + IFLA_BRPORT_TOPOLOGY_CHANGE_ACK, + IFLA_BRPORT_CONFIG_PENDING, + IFLA_BRPORT_MESSAGE_AGE_TIMER, + IFLA_BRPORT_FORWARD_DELAY_TIMER, + IFLA_BRPORT_HOLD_TIMER, + IFLA_BRPORT_FLUSH, + IFLA_BRPORT_MULTICAST_ROUTER, + IFLA_BRPORT_PAD, + IFLA_BRPORT_MCAST_FLOOD, + IFLA_BRPORT_MCAST_TO_UCAST, + IFLA_BRPORT_VLAN_TUNNEL, + IFLA_BRPORT_BCAST_FLOOD, + IFLA_BRPORT_GROUP_FWD_MASK, + IFLA_BRPORT_NEIGH_SUPPRESS, + IFLA_BRPORT_ISOLATED, + IFLA_BRPORT_BACKUP_PORT, + __IFLA_BRPORT_MAX +}; +#define IFLA_BRPORT_MAX (__IFLA_BRPORT_MAX - 1) + +struct ifla_cacheinfo { + __u32 max_reasm_len; + __u32 tstamp; /* ipv6InterfaceTable updated timestamp */ + __u32 reachable_time; + __u32 retrans_time; +}; + +enum { + IFLA_INFO_UNSPEC, + IFLA_INFO_KIND, + IFLA_INFO_DATA, + IFLA_INFO_XSTATS, + IFLA_INFO_SLAVE_KIND, + IFLA_INFO_SLAVE_DATA, + __IFLA_INFO_MAX, +}; + +#define IFLA_INFO_MAX (__IFLA_INFO_MAX - 1) + +/* VLAN section */ + +enum { + IFLA_VLAN_UNSPEC, + IFLA_VLAN_ID, + IFLA_VLAN_FLAGS, + IFLA_VLAN_EGRESS_QOS, + IFLA_VLAN_INGRESS_QOS, + IFLA_VLAN_PROTOCOL, + __IFLA_VLAN_MAX, +}; + +#define IFLA_VLAN_MAX (__IFLA_VLAN_MAX - 1) + +struct ifla_vlan_flags { + __u32 flags; + __u32 mask; +}; + +enum { + IFLA_VLAN_QOS_UNSPEC, + IFLA_VLAN_QOS_MAPPING, + __IFLA_VLAN_QOS_MAX +}; + +#define IFLA_VLAN_QOS_MAX (__IFLA_VLAN_QOS_MAX - 1) + +struct ifla_vlan_qos_mapping { + __u32 from; + __u32 to; +}; + +/* MACVLAN section */ +enum { + IFLA_MACVLAN_UNSPEC, + IFLA_MACVLAN_MODE, + IFLA_MACVLAN_FLAGS, + IFLA_MACVLAN_MACADDR_MODE, + IFLA_MACVLAN_MACADDR, + IFLA_MACVLAN_MACADDR_DATA, + IFLA_MACVLAN_MACADDR_COUNT, + __IFLA_MACVLAN_MAX, +}; + +#define IFLA_MACVLAN_MAX (__IFLA_MACVLAN_MAX - 1) + +enum macvlan_mode { + MACVLAN_MODE_PRIVATE = 1, /* don't talk to other macvlans */ + MACVLAN_MODE_VEPA = 2, /* talk to other ports through ext bridge */ + MACVLAN_MODE_BRIDGE = 4, /* talk to bridge ports directly */ + MACVLAN_MODE_PASSTHRU = 8,/* take over the underlying device */ + MACVLAN_MODE_SOURCE = 16,/* use source MAC address list to assign */ +}; + +enum macvlan_macaddr_mode { + MACVLAN_MACADDR_ADD, + MACVLAN_MACADDR_DEL, + MACVLAN_MACADDR_FLUSH, + MACVLAN_MACADDR_SET, +}; + +#define MACVLAN_FLAG_NOPROMISC 1 + +/* VRF section */ +enum { + IFLA_VRF_UNSPEC, + IFLA_VRF_TABLE, + __IFLA_VRF_MAX +}; + +#define IFLA_VRF_MAX (__IFLA_VRF_MAX - 1) + +enum { + IFLA_VRF_PORT_UNSPEC, + IFLA_VRF_PORT_TABLE, + __IFLA_VRF_PORT_MAX +}; + +#define IFLA_VRF_PORT_MAX (__IFLA_VRF_PORT_MAX - 1) + +/* MACSEC section */ +enum { + IFLA_MACSEC_UNSPEC, + IFLA_MACSEC_SCI, + IFLA_MACSEC_PORT, + IFLA_MACSEC_ICV_LEN, + IFLA_MACSEC_CIPHER_SUITE, + IFLA_MACSEC_WINDOW, + IFLA_MACSEC_ENCODING_SA, + IFLA_MACSEC_ENCRYPT, + IFLA_MACSEC_PROTECT, + IFLA_MACSEC_INC_SCI, + IFLA_MACSEC_ES, + IFLA_MACSEC_SCB, + IFLA_MACSEC_REPLAY_PROTECT, + IFLA_MACSEC_VALIDATION, + IFLA_MACSEC_PAD, + __IFLA_MACSEC_MAX, +}; + +#define IFLA_MACSEC_MAX (__IFLA_MACSEC_MAX - 1) + +/* XFRM section */ +enum { + IFLA_XFRM_UNSPEC, + IFLA_XFRM_LINK, + IFLA_XFRM_IF_ID, + __IFLA_XFRM_MAX +}; + +#define IFLA_XFRM_MAX (__IFLA_XFRM_MAX - 1) + +enum macsec_validation_type { + MACSEC_VALIDATE_DISABLED = 0, + MACSEC_VALIDATE_CHECK = 1, + MACSEC_VALIDATE_STRICT = 2, + __MACSEC_VALIDATE_END, + 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, + IFLA_IPVLAN_MODE, + IFLA_IPVLAN_FLAGS, + __IFLA_IPVLAN_MAX +}; + +#define IFLA_IPVLAN_MAX (__IFLA_IPVLAN_MAX - 1) + +enum ipvlan_mode { + IPVLAN_MODE_L2 = 0, + IPVLAN_MODE_L3, + IPVLAN_MODE_L3S, + IPVLAN_MODE_MAX +}; + +#define IPVLAN_F_PRIVATE 0x01 +#define IPVLAN_F_VEPA 0x02 + +/* VXLAN section */ +enum { + IFLA_VXLAN_UNSPEC, + IFLA_VXLAN_ID, + IFLA_VXLAN_GROUP, /* group or remote address */ + IFLA_VXLAN_LINK, + IFLA_VXLAN_LOCAL, + IFLA_VXLAN_TTL, + IFLA_VXLAN_TOS, + IFLA_VXLAN_LEARNING, + IFLA_VXLAN_AGEING, + IFLA_VXLAN_LIMIT, + IFLA_VXLAN_PORT_RANGE, /* source port */ + IFLA_VXLAN_PROXY, + IFLA_VXLAN_RSC, + IFLA_VXLAN_L2MISS, + IFLA_VXLAN_L3MISS, + IFLA_VXLAN_PORT, /* destination port */ + IFLA_VXLAN_GROUP6, + IFLA_VXLAN_LOCAL6, + IFLA_VXLAN_UDP_CSUM, + IFLA_VXLAN_UDP_ZERO_CSUM6_TX, + IFLA_VXLAN_UDP_ZERO_CSUM6_RX, + IFLA_VXLAN_REMCSUM_TX, + IFLA_VXLAN_REMCSUM_RX, + IFLA_VXLAN_GBP, + IFLA_VXLAN_REMCSUM_NOPARTIAL, + IFLA_VXLAN_COLLECT_METADATA, + IFLA_VXLAN_LABEL, + IFLA_VXLAN_GPE, + IFLA_VXLAN_TTL_INHERIT, + IFLA_VXLAN_DF, + __IFLA_VXLAN_MAX +}; +#define IFLA_VXLAN_MAX (__IFLA_VXLAN_MAX - 1) + +struct ifla_vxlan_port_range { + __be16 low; + __be16 high; +}; + +enum ifla_vxlan_df { + VXLAN_DF_UNSET = 0, + VXLAN_DF_SET, + VXLAN_DF_INHERIT, + __VXLAN_DF_END, + VXLAN_DF_MAX = __VXLAN_DF_END - 1, +}; + +/* GENEVE section */ +enum { + IFLA_GENEVE_UNSPEC, + IFLA_GENEVE_ID, + IFLA_GENEVE_REMOTE, + IFLA_GENEVE_TTL, + IFLA_GENEVE_TOS, + IFLA_GENEVE_PORT, /* destination port */ + IFLA_GENEVE_COLLECT_METADATA, + IFLA_GENEVE_REMOTE6, + IFLA_GENEVE_UDP_CSUM, + IFLA_GENEVE_UDP_ZERO_CSUM6_TX, + IFLA_GENEVE_UDP_ZERO_CSUM6_RX, + IFLA_GENEVE_LABEL, + IFLA_GENEVE_TTL_INHERIT, + IFLA_GENEVE_DF, + __IFLA_GENEVE_MAX +}; +#define IFLA_GENEVE_MAX (__IFLA_GENEVE_MAX - 1) + +enum ifla_geneve_df { + GENEVE_DF_UNSET = 0, + GENEVE_DF_SET, + GENEVE_DF_INHERIT, + __GENEVE_DF_END, + GENEVE_DF_MAX = __GENEVE_DF_END - 1, +}; + +/* Bareudp section */ +enum { + IFLA_BAREUDP_UNSPEC, + IFLA_BAREUDP_PORT, + IFLA_BAREUDP_ETHERTYPE, + IFLA_BAREUDP_SRCPORT_MIN, + IFLA_BAREUDP_MULTIPROTO_MODE, + __IFLA_BAREUDP_MAX +}; + +#define IFLA_BAREUDP_MAX (__IFLA_BAREUDP_MAX - 1) + +/* PPP section */ +enum { + IFLA_PPP_UNSPEC, + IFLA_PPP_DEV_FD, + __IFLA_PPP_MAX +}; +#define IFLA_PPP_MAX (__IFLA_PPP_MAX - 1) + +/* GTP section */ + +enum ifla_gtp_role { + GTP_ROLE_GGSN = 0, + GTP_ROLE_SGSN, +}; + +enum { + IFLA_GTP_UNSPEC, + IFLA_GTP_FD0, + IFLA_GTP_FD1, + IFLA_GTP_PDP_HASHSIZE, + IFLA_GTP_ROLE, + __IFLA_GTP_MAX, +}; +#define IFLA_GTP_MAX (__IFLA_GTP_MAX - 1) + +/* Bonding section */ + +enum { + IFLA_BOND_UNSPEC, + IFLA_BOND_MODE, + IFLA_BOND_ACTIVE_SLAVE, + IFLA_BOND_MIIMON, + IFLA_BOND_UPDELAY, + IFLA_BOND_DOWNDELAY, + IFLA_BOND_USE_CARRIER, + IFLA_BOND_ARP_INTERVAL, + IFLA_BOND_ARP_IP_TARGET, + IFLA_BOND_ARP_VALIDATE, + IFLA_BOND_ARP_ALL_TARGETS, + IFLA_BOND_PRIMARY, + IFLA_BOND_PRIMARY_RESELECT, + IFLA_BOND_FAIL_OVER_MAC, + IFLA_BOND_XMIT_HASH_POLICY, + IFLA_BOND_RESEND_IGMP, + IFLA_BOND_NUM_PEER_NOTIF, + IFLA_BOND_ALL_SLAVES_ACTIVE, + IFLA_BOND_MIN_LINKS, + IFLA_BOND_LP_INTERVAL, + IFLA_BOND_PACKETS_PER_SLAVE, + IFLA_BOND_AD_LACP_RATE, + IFLA_BOND_AD_SELECT, + IFLA_BOND_AD_INFO, + IFLA_BOND_AD_ACTOR_SYS_PRIO, + IFLA_BOND_AD_USER_PORT_KEY, + IFLA_BOND_AD_ACTOR_SYSTEM, + IFLA_BOND_TLB_DYNAMIC_LB, + IFLA_BOND_PEER_NOTIF_DELAY, + __IFLA_BOND_MAX, +}; + +#define IFLA_BOND_MAX (__IFLA_BOND_MAX - 1) + +enum { + IFLA_BOND_AD_INFO_UNSPEC, + IFLA_BOND_AD_INFO_AGGREGATOR, + IFLA_BOND_AD_INFO_NUM_PORTS, + IFLA_BOND_AD_INFO_ACTOR_KEY, + IFLA_BOND_AD_INFO_PARTNER_KEY, + IFLA_BOND_AD_INFO_PARTNER_MAC, + __IFLA_BOND_AD_INFO_MAX, +}; + +#define IFLA_BOND_AD_INFO_MAX (__IFLA_BOND_AD_INFO_MAX - 1) + +enum { + IFLA_BOND_SLAVE_UNSPEC, + IFLA_BOND_SLAVE_STATE, + IFLA_BOND_SLAVE_MII_STATUS, + IFLA_BOND_SLAVE_LINK_FAILURE_COUNT, + IFLA_BOND_SLAVE_PERM_HWADDR, + IFLA_BOND_SLAVE_QUEUE_ID, + IFLA_BOND_SLAVE_AD_AGGREGATOR_ID, + IFLA_BOND_SLAVE_AD_ACTOR_OPER_PORT_STATE, + IFLA_BOND_SLAVE_AD_PARTNER_OPER_PORT_STATE, + __IFLA_BOND_SLAVE_MAX, +}; + +#define IFLA_BOND_SLAVE_MAX (__IFLA_BOND_SLAVE_MAX - 1) + +/* SR-IOV virtual function management section */ + +enum { + IFLA_VF_INFO_UNSPEC, + IFLA_VF_INFO, + __IFLA_VF_INFO_MAX, +}; + +#define IFLA_VF_INFO_MAX (__IFLA_VF_INFO_MAX - 1) + +enum { + IFLA_VF_UNSPEC, + IFLA_VF_MAC, /* Hardware queue specific attributes */ + IFLA_VF_VLAN, /* VLAN ID and QoS */ + IFLA_VF_TX_RATE, /* Max TX Bandwidth Allocation */ + IFLA_VF_SPOOFCHK, /* Spoof Checking on/off switch */ + IFLA_VF_LINK_STATE, /* link state enable/disable/auto switch */ + IFLA_VF_RATE, /* Min and Max TX Bandwidth Allocation */ + IFLA_VF_RSS_QUERY_EN, /* RSS Redirection Table and Hash Key query + * on/off switch + */ + IFLA_VF_STATS, /* network device statistics */ + IFLA_VF_TRUST, /* Trust VF */ + IFLA_VF_IB_NODE_GUID, /* VF Infiniband node GUID */ + IFLA_VF_IB_PORT_GUID, /* VF Infiniband port GUID */ + IFLA_VF_VLAN_LIST, /* nested list of vlans, option for QinQ */ + IFLA_VF_BROADCAST, /* VF broadcast */ + __IFLA_VF_MAX, +}; + +#define IFLA_VF_MAX (__IFLA_VF_MAX - 1) + +struct ifla_vf_mac { + __u32 vf; + __u8 mac[32]; /* MAX_ADDR_LEN */ +}; + +struct ifla_vf_broadcast { + __u8 broadcast[32]; +}; + +struct ifla_vf_vlan { + __u32 vf; + __u32 vlan; /* 0 - 4095, 0 disables VLAN filter */ + __u32 qos; +}; + +enum { + IFLA_VF_VLAN_INFO_UNSPEC, + IFLA_VF_VLAN_INFO, /* VLAN ID, QoS and VLAN protocol */ + __IFLA_VF_VLAN_INFO_MAX, +}; + +#define IFLA_VF_VLAN_INFO_MAX (__IFLA_VF_VLAN_INFO_MAX - 1) +#define MAX_VLAN_LIST_LEN 1 + +struct ifla_vf_vlan_info { + __u32 vf; + __u32 vlan; /* 0 - 4095, 0 disables VLAN filter */ + __u32 qos; + __be16 vlan_proto; /* VLAN protocol either 802.1Q or 802.1ad */ +}; + +struct ifla_vf_tx_rate { + __u32 vf; + __u32 rate; /* Max TX bandwidth in Mbps, 0 disables throttling */ +}; + +struct ifla_vf_rate { + __u32 vf; + __u32 min_tx_rate; /* Min Bandwidth in Mbps */ + __u32 max_tx_rate; /* Max Bandwidth in Mbps */ +}; + +struct ifla_vf_spoofchk { + __u32 vf; + __u32 setting; +}; + +struct ifla_vf_guid { + __u32 vf; + __u64 guid; +}; + +enum { + IFLA_VF_LINK_STATE_AUTO, /* link state of the uplink */ + IFLA_VF_LINK_STATE_ENABLE, /* link always up */ + IFLA_VF_LINK_STATE_DISABLE, /* link always down */ + __IFLA_VF_LINK_STATE_MAX, +}; + +struct ifla_vf_link_state { + __u32 vf; + __u32 link_state; +}; + +struct ifla_vf_rss_query_en { + __u32 vf; + __u32 setting; +}; + +enum { + IFLA_VF_STATS_RX_PACKETS, + IFLA_VF_STATS_TX_PACKETS, + IFLA_VF_STATS_RX_BYTES, + IFLA_VF_STATS_TX_BYTES, + IFLA_VF_STATS_BROADCAST, + IFLA_VF_STATS_MULTICAST, + IFLA_VF_STATS_PAD, + IFLA_VF_STATS_RX_DROPPED, + IFLA_VF_STATS_TX_DROPPED, + __IFLA_VF_STATS_MAX, +}; + +#define IFLA_VF_STATS_MAX (__IFLA_VF_STATS_MAX - 1) + +struct ifla_vf_trust { + __u32 vf; + __u32 setting; +}; + +/* VF ports management section + * + * Nested layout of set/get msg is: + * + * [IFLA_NUM_VF] + * [IFLA_VF_PORTS] + * [IFLA_VF_PORT] + * [IFLA_PORT_*], ... + * [IFLA_VF_PORT] + * [IFLA_PORT_*], ... + * ... + * [IFLA_PORT_SELF] + * [IFLA_PORT_*], ... + */ + +enum { + IFLA_VF_PORT_UNSPEC, + IFLA_VF_PORT, /* nest */ + __IFLA_VF_PORT_MAX, +}; + +#define IFLA_VF_PORT_MAX (__IFLA_VF_PORT_MAX - 1) + +enum { + IFLA_PORT_UNSPEC, + IFLA_PORT_VF, /* __u32 */ + IFLA_PORT_PROFILE, /* string */ + IFLA_PORT_VSI_TYPE, /* 802.1Qbg (pre-)standard VDP */ + IFLA_PORT_INSTANCE_UUID, /* binary UUID */ + IFLA_PORT_HOST_UUID, /* binary UUID */ + IFLA_PORT_REQUEST, /* __u8 */ + IFLA_PORT_RESPONSE, /* __u16, output only */ + __IFLA_PORT_MAX, +}; + +#define IFLA_PORT_MAX (__IFLA_PORT_MAX - 1) + +#define PORT_PROFILE_MAX 40 +#define PORT_UUID_MAX 16 +#define PORT_SELF_VF -1 + +enum { + PORT_REQUEST_PREASSOCIATE = 0, + PORT_REQUEST_PREASSOCIATE_RR, + PORT_REQUEST_ASSOCIATE, + PORT_REQUEST_DISASSOCIATE, +}; + +enum { + PORT_VDP_RESPONSE_SUCCESS = 0, + PORT_VDP_RESPONSE_INVALID_FORMAT, + PORT_VDP_RESPONSE_INSUFFICIENT_RESOURCES, + PORT_VDP_RESPONSE_UNUSED_VTID, + PORT_VDP_RESPONSE_VTID_VIOLATION, + PORT_VDP_RESPONSE_VTID_VERSION_VIOALTION, + PORT_VDP_RESPONSE_OUT_OF_SYNC, + /* 0x08-0xFF reserved for future VDP use */ + PORT_PROFILE_RESPONSE_SUCCESS = 0x100, + PORT_PROFILE_RESPONSE_INPROGRESS, + PORT_PROFILE_RESPONSE_INVALID, + PORT_PROFILE_RESPONSE_BADSTATE, + PORT_PROFILE_RESPONSE_INSUFFICIENT_RESOURCES, + PORT_PROFILE_RESPONSE_ERROR, +}; + +struct ifla_port_vsi { + __u8 vsi_mgr_id; + __u8 vsi_type_id[3]; + __u8 vsi_type_version; + __u8 pad[3]; +}; + + +/* IPoIB section */ + +enum { + IFLA_IPOIB_UNSPEC, + IFLA_IPOIB_PKEY, + IFLA_IPOIB_MODE, + IFLA_IPOIB_UMCAST, + __IFLA_IPOIB_MAX +}; + +enum { + IPOIB_MODE_DATAGRAM = 0, /* using unreliable datagram QPs */ + IPOIB_MODE_CONNECTED = 1, /* using connected QPs */ +}; + +#define IFLA_IPOIB_MAX (__IFLA_IPOIB_MAX - 1) + + +/* HSR section */ + +enum { + IFLA_HSR_UNSPEC, + IFLA_HSR_SLAVE1, + IFLA_HSR_SLAVE2, + IFLA_HSR_MULTICAST_SPEC, /* Last byte of supervision addr */ + IFLA_HSR_SUPERVISION_ADDR, /* Supervision frame multicast addr */ + IFLA_HSR_SEQ_NR, + IFLA_HSR_VERSION, /* HSR version */ + __IFLA_HSR_MAX, +}; + +#define IFLA_HSR_MAX (__IFLA_HSR_MAX - 1) + +/* STATS section */ + +struct if_stats_msg { + __u8 family; + __u8 pad1; + __u16 pad2; + __u32 ifindex; + __u32 filter_mask; +}; + +/* A stats attribute can be netdev specific or a global stat. + * For netdev stats, lets use the prefix IFLA_STATS_LINK_* + */ +enum { + IFLA_STATS_UNSPEC, /* also used as 64bit pad attribute */ + IFLA_STATS_LINK_64, + IFLA_STATS_LINK_XSTATS, + IFLA_STATS_LINK_XSTATS_SLAVE, + IFLA_STATS_LINK_OFFLOAD_XSTATS, + IFLA_STATS_AF_SPEC, + __IFLA_STATS_MAX, +}; + +#define IFLA_STATS_MAX (__IFLA_STATS_MAX - 1) + +#define IFLA_STATS_FILTER_BIT(ATTR) (1 << (ATTR - 1)) + +/* These are embedded into IFLA_STATS_LINK_XSTATS: + * [IFLA_STATS_LINK_XSTATS] + * -> [LINK_XSTATS_TYPE_xxx] + * -> [rtnl link type specific attributes] + */ +enum { + LINK_XSTATS_TYPE_UNSPEC, + LINK_XSTATS_TYPE_BRIDGE, + LINK_XSTATS_TYPE_BOND, + __LINK_XSTATS_TYPE_MAX +}; +#define LINK_XSTATS_TYPE_MAX (__LINK_XSTATS_TYPE_MAX - 1) + +/* These are stats embedded into IFLA_STATS_LINK_OFFLOAD_XSTATS */ +enum { + IFLA_OFFLOAD_XSTATS_UNSPEC, + IFLA_OFFLOAD_XSTATS_CPU_HIT, /* struct rtnl_link_stats64 */ + __IFLA_OFFLOAD_XSTATS_MAX +}; +#define IFLA_OFFLOAD_XSTATS_MAX (__IFLA_OFFLOAD_XSTATS_MAX - 1) + +/* XDP section */ + +#define XDP_FLAGS_UPDATE_IF_NOEXIST (1U << 0) +#define XDP_FLAGS_SKB_MODE (1U << 1) +#define XDP_FLAGS_DRV_MODE (1U << 2) +#define XDP_FLAGS_HW_MODE (1U << 3) +#define XDP_FLAGS_MODES (XDP_FLAGS_SKB_MODE | \ + XDP_FLAGS_DRV_MODE | \ + XDP_FLAGS_HW_MODE) +#define XDP_FLAGS_MASK (XDP_FLAGS_UPDATE_IF_NOEXIST | \ + XDP_FLAGS_MODES) + +/* These are stored into IFLA_XDP_ATTACHED on dump. */ +enum { + XDP_ATTACHED_NONE = 0, + XDP_ATTACHED_DRV, + XDP_ATTACHED_SKB, + XDP_ATTACHED_HW, + XDP_ATTACHED_MULTI, +}; + +enum { + IFLA_XDP_UNSPEC, + IFLA_XDP_FD, + IFLA_XDP_ATTACHED, + IFLA_XDP_FLAGS, + IFLA_XDP_PROG_ID, + IFLA_XDP_DRV_PROG_ID, + IFLA_XDP_SKB_PROG_ID, + IFLA_XDP_HW_PROG_ID, + __IFLA_XDP_MAX, +}; + +#define IFLA_XDP_MAX (__IFLA_XDP_MAX - 1) + +enum { + IFLA_EVENT_NONE, + IFLA_EVENT_REBOOT, /* internal reset / reboot */ + IFLA_EVENT_FEATURES, /* change in offload features */ + IFLA_EVENT_BONDING_FAILOVER, /* change in active slave */ + IFLA_EVENT_NOTIFY_PEERS, /* re-sent grat. arp/ndisc */ + IFLA_EVENT_IGMP_RESEND, /* re-sent IGMP JOIN */ + IFLA_EVENT_BONDING_OPTIONS, /* change in bonding options */ +}; + +/* tun section */ + +enum { + IFLA_TUN_UNSPEC, + IFLA_TUN_OWNER, + IFLA_TUN_GROUP, + IFLA_TUN_TYPE, + IFLA_TUN_PI, + IFLA_TUN_VNET_HDR, + IFLA_TUN_PERSIST, + IFLA_TUN_MULTI_QUEUE, + IFLA_TUN_NUM_QUEUES, + IFLA_TUN_NUM_DISABLED_QUEUES, + __IFLA_TUN_MAX, +}; + +#define IFLA_TUN_MAX (__IFLA_TUN_MAX - 1) + +/* rmnet section */ + +#define RMNET_FLAGS_INGRESS_DEAGGREGATION (1U << 0) +#define RMNET_FLAGS_INGRESS_MAP_COMMANDS (1U << 1) +#define RMNET_FLAGS_INGRESS_MAP_CKSUMV4 (1U << 2) +#define RMNET_FLAGS_EGRESS_MAP_CKSUMV4 (1U << 3) + +enum { + IFLA_RMNET_UNSPEC, + IFLA_RMNET_MUX_ID, + IFLA_RMNET_FLAGS, + __IFLA_RMNET_MAX, +}; + +#define IFLA_RMNET_MAX (__IFLA_RMNET_MAX - 1) + +struct ifla_rmnet_flags { + __u32 flags; + __u32 mask; +}; + +#endif /* _LINUX_IF_LINK_H */ diff --git a/uapi/linux/netlink.h b/uapi/linux/netlink.h new file mode 100644 index 000000000000..2c28d329e595 --- /dev/null +++ b/uapi/linux/netlink.h @@ -0,0 +1,248 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +#ifndef __LINUX_NETLINK_H +#define __LINUX_NETLINK_H + +#include +#include /* for __kernel_sa_family_t */ +#include + +#define NETLINK_ROUTE 0 /* Routing/device hook */ +#define NETLINK_UNUSED 1 /* Unused number */ +#define NETLINK_USERSOCK 2 /* Reserved for user mode socket protocols */ +#define NETLINK_FIREWALL 3 /* Unused number, formerly ip_queue */ +#define NETLINK_SOCK_DIAG 4 /* socket monitoring */ +#define NETLINK_NFLOG 5 /* netfilter/iptables ULOG */ +#define NETLINK_XFRM 6 /* ipsec */ +#define NETLINK_SELINUX 7 /* SELinux event notifications */ +#define NETLINK_ISCSI 8 /* Open-iSCSI */ +#define NETLINK_AUDIT 9 /* auditing */ +#define NETLINK_FIB_LOOKUP 10 +#define NETLINK_CONNECTOR 11 +#define NETLINK_NETFILTER 12 /* netfilter subsystem */ +#define NETLINK_IP6_FW 13 +#define NETLINK_DNRTMSG 14 /* DECnet routing messages */ +#define NETLINK_KOBJECT_UEVENT 15 /* Kernel messages to userspace */ +#define NETLINK_GENERIC 16 +/* leave room for NETLINK_DM (DM Events) */ +#define NETLINK_SCSITRANSPORT 18 /* SCSI Transports */ +#define NETLINK_ECRYPTFS 19 +#define NETLINK_RDMA 20 +#define NETLINK_CRYPTO 21 /* Crypto layer */ +#define NETLINK_SMC 22 /* SMC monitoring */ + +#define NETLINK_INET_DIAG NETLINK_SOCK_DIAG + +#define MAX_LINKS 32 + +struct sockaddr_nl { + __kernel_sa_family_t nl_family; /* AF_NETLINK */ + unsigned short nl_pad; /* zero */ + __u32 nl_pid; /* port ID */ + __u32 nl_groups; /* multicast groups mask */ +}; + +struct nlmsghdr { + __u32 nlmsg_len; /* Length of message including header */ + __u16 nlmsg_type; /* Message content */ + __u16 nlmsg_flags; /* Additional flags */ + __u32 nlmsg_seq; /* Sequence number */ + __u32 nlmsg_pid; /* Sending process port ID */ +}; + +/* Flags values */ + +#define NLM_F_REQUEST 0x01 /* It is request message. */ +#define NLM_F_MULTI 0x02 /* Multipart message, terminated by NLMSG_DONE */ +#define NLM_F_ACK 0x04 /* Reply with ack, with zero or error code */ +#define NLM_F_ECHO 0x08 /* Echo this request */ +#define NLM_F_DUMP_INTR 0x10 /* Dump was inconsistent due to sequence change */ +#define NLM_F_DUMP_FILTERED 0x20 /* Dump was filtered as requested */ + +/* Modifiers to GET request */ +#define NLM_F_ROOT 0x100 /* specify tree root */ +#define NLM_F_MATCH 0x200 /* return all matching */ +#define NLM_F_ATOMIC 0x400 /* atomic GET */ +#define NLM_F_DUMP (NLM_F_ROOT|NLM_F_MATCH) + +/* Modifiers to NEW request */ +#define NLM_F_REPLACE 0x100 /* Override existing */ +#define NLM_F_EXCL 0x200 /* Do not touch, if it exists */ +#define NLM_F_CREATE 0x400 /* Create, if it does not exist */ +#define NLM_F_APPEND 0x800 /* Add to end of list */ + +/* Modifiers to DELETE request */ +#define NLM_F_NONREC 0x100 /* Do not delete recursively */ + +/* Flags for ACK message */ +#define NLM_F_CAPPED 0x100 /* request was capped */ +#define NLM_F_ACK_TLVS 0x200 /* extended ACK TVLs were included */ + +/* + 4.4BSD ADD NLM_F_CREATE|NLM_F_EXCL + 4.4BSD CHANGE NLM_F_REPLACE + + True CHANGE NLM_F_CREATE|NLM_F_REPLACE + Append NLM_F_CREATE + Check NLM_F_EXCL + */ + +#define NLMSG_ALIGNTO 4U +#define NLMSG_ALIGN(len) ( ((len)+NLMSG_ALIGNTO-1) & ~(NLMSG_ALIGNTO-1) ) +#define NLMSG_HDRLEN ((int) NLMSG_ALIGN(sizeof(struct nlmsghdr))) +#define NLMSG_LENGTH(len) ((len) + NLMSG_HDRLEN) +#define NLMSG_SPACE(len) NLMSG_ALIGN(NLMSG_LENGTH(len)) +#define NLMSG_DATA(nlh) ((void*)(((char*)nlh) + NLMSG_LENGTH(0))) +#define NLMSG_NEXT(nlh,len) ((len) -= NLMSG_ALIGN((nlh)->nlmsg_len), \ + (struct nlmsghdr*)(((char*)(nlh)) + NLMSG_ALIGN((nlh)->nlmsg_len))) +#define NLMSG_OK(nlh,len) ((len) >= (int)sizeof(struct nlmsghdr) && \ + (nlh)->nlmsg_len >= sizeof(struct nlmsghdr) && \ + (nlh)->nlmsg_len <= (len)) +#define NLMSG_PAYLOAD(nlh,len) ((nlh)->nlmsg_len - NLMSG_SPACE((len))) + +#define NLMSG_NOOP 0x1 /* Nothing. */ +#define NLMSG_ERROR 0x2 /* Error */ +#define NLMSG_DONE 0x3 /* End of a dump */ +#define NLMSG_OVERRUN 0x4 /* Data lost */ + +#define NLMSG_MIN_TYPE 0x10 /* < 0x10: reserved control messages */ + +struct nlmsgerr { + int error; + struct nlmsghdr msg; + /* + * followed by the message contents unless NETLINK_CAP_ACK was set + * or the ACK indicates success (error == 0) + * message length is aligned with NLMSG_ALIGN() + */ + /* + * followed by TLVs defined in enum nlmsgerr_attrs + * if NETLINK_EXT_ACK was set + */ +}; + +/** + * enum nlmsgerr_attrs - nlmsgerr attributes + * @NLMSGERR_ATTR_UNUSED: unused + * @NLMSGERR_ATTR_MSG: error message string (string) + * @NLMSGERR_ATTR_OFFS: offset of the invalid attribute in the original + * message, counting from the beginning of the header (u32) + * @NLMSGERR_ATTR_COOKIE: arbitrary subsystem specific cookie to + * be used - in the success case - to identify a created + * object or operation or similar (binary) + * @__NLMSGERR_ATTR_MAX: number of attributes + * @NLMSGERR_ATTR_MAX: highest attribute number + */ +enum nlmsgerr_attrs { + NLMSGERR_ATTR_UNUSED, + NLMSGERR_ATTR_MSG, + NLMSGERR_ATTR_OFFS, + NLMSGERR_ATTR_COOKIE, + + __NLMSGERR_ATTR_MAX, + NLMSGERR_ATTR_MAX = __NLMSGERR_ATTR_MAX - 1 +}; + +#define NETLINK_ADD_MEMBERSHIP 1 +#define NETLINK_DROP_MEMBERSHIP 2 +#define NETLINK_PKTINFO 3 +#define NETLINK_BROADCAST_ERROR 4 +#define NETLINK_NO_ENOBUFS 5 +#define NETLINK_RX_RING 6 +#define NETLINK_TX_RING 7 +#define NETLINK_LISTEN_ALL_NSID 8 +#define NETLINK_LIST_MEMBERSHIPS 9 +#define NETLINK_CAP_ACK 10 +#define NETLINK_EXT_ACK 11 +#define NETLINK_GET_STRICT_CHK 12 + +struct nl_pktinfo { + __u32 group; +}; + +struct nl_mmap_req { + unsigned int nm_block_size; + unsigned int nm_block_nr; + unsigned int nm_frame_size; + unsigned int nm_frame_nr; +}; + +struct nl_mmap_hdr { + unsigned int nm_status; + unsigned int nm_len; + __u32 nm_group; + /* credentials */ + __u32 nm_pid; + __u32 nm_uid; + __u32 nm_gid; +}; + +enum nl_mmap_status { + NL_MMAP_STATUS_UNUSED, + NL_MMAP_STATUS_RESERVED, + NL_MMAP_STATUS_VALID, + NL_MMAP_STATUS_COPY, + NL_MMAP_STATUS_SKIP, +}; + +#define NL_MMAP_MSG_ALIGNMENT NLMSG_ALIGNTO +#define NL_MMAP_MSG_ALIGN(sz) __ALIGN_KERNEL(sz, NL_MMAP_MSG_ALIGNMENT) +#define NL_MMAP_HDRLEN NL_MMAP_MSG_ALIGN(sizeof(struct nl_mmap_hdr)) + +#define NET_MAJOR 36 /* Major 36 is reserved for networking */ + +enum { + NETLINK_UNCONNECTED = 0, + NETLINK_CONNECTED, +}; + +/* + * <------- NLA_HDRLEN ------> <-- NLA_ALIGN(payload)--> + * +---------------------+- - -+- - - - - - - - - -+- - -+ + * | Header | Pad | Payload | Pad | + * | (struct nlattr) | ing | | ing | + * +---------------------+- - -+- - - - - - - - - -+- - -+ + * <-------------- nlattr->nla_len --------------> + */ + +struct nlattr { + __u16 nla_len; + __u16 nla_type; +}; + +/* + * nla_type (16 bits) + * +---+---+-------------------------------+ + * | N | O | Attribute Type | + * +---+---+-------------------------------+ + * N := Carries nested attributes + * O := Payload stored in network byte order + * + * Note: The N and O flag are mutually exclusive. + */ +#define NLA_F_NESTED (1 << 15) +#define NLA_F_NET_BYTEORDER (1 << 14) +#define NLA_TYPE_MASK ~(NLA_F_NESTED | NLA_F_NET_BYTEORDER) + +#define NLA_ALIGNTO 4 +#define NLA_ALIGN(len) (((len) + NLA_ALIGNTO - 1) & ~(NLA_ALIGNTO - 1)) +#define NLA_HDRLEN ((int) NLA_ALIGN(sizeof(struct nlattr))) + +/* Generic 32 bitflags attribute content sent to the kernel. + * + * The value is a bitmap that defines the values being set + * The selector is a bitmask that defines which value is legit + * + * Examples: + * value = 0x0, and selector = 0x1 + * implies we are selecting bit 1 and we want to set its value to 0. + * + * value = 0x2, and selector = 0x2 + * implies we are selecting bit 2 and we want to set its value to 1. + * + */ +struct nla_bitfield32 { + __u32 value; + __u32 selector; +}; + +#endif /* __LINUX_NETLINK_H */ diff --git a/uapi/linux/rtnetlink.h b/uapi/linux/rtnetlink.h new file mode 100644 index 000000000000..9d802cd7f695 --- /dev/null +++ b/uapi/linux/rtnetlink.h @@ -0,0 +1,777 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +#ifndef __LINUX_RTNETLINK_H +#define __LINUX_RTNETLINK_H + +#include +#include +#include +#include +#include + +/* rtnetlink families. Values up to 127 are reserved for real address + * families, values above 128 may be used arbitrarily. + */ +#define RTNL_FAMILY_IPMR 128 +#define RTNL_FAMILY_IP6MR 129 +#define RTNL_FAMILY_MAX 129 + +/**** + * Routing/neighbour discovery messages. + ****/ + +/* Types of messages */ + +enum { + RTM_BASE = 16, +#define RTM_BASE RTM_BASE + + RTM_NEWLINK = 16, +#define RTM_NEWLINK RTM_NEWLINK + RTM_DELLINK, +#define RTM_DELLINK RTM_DELLINK + RTM_GETLINK, +#define RTM_GETLINK RTM_GETLINK + RTM_SETLINK, +#define RTM_SETLINK RTM_SETLINK + + RTM_NEWADDR = 20, +#define RTM_NEWADDR RTM_NEWADDR + RTM_DELADDR, +#define RTM_DELADDR RTM_DELADDR + RTM_GETADDR, +#define RTM_GETADDR RTM_GETADDR + + RTM_NEWROUTE = 24, +#define RTM_NEWROUTE RTM_NEWROUTE + RTM_DELROUTE, +#define RTM_DELROUTE RTM_DELROUTE + RTM_GETROUTE, +#define RTM_GETROUTE RTM_GETROUTE + + RTM_NEWNEIGH = 28, +#define RTM_NEWNEIGH RTM_NEWNEIGH + RTM_DELNEIGH, +#define RTM_DELNEIGH RTM_DELNEIGH + RTM_GETNEIGH, +#define RTM_GETNEIGH RTM_GETNEIGH + + RTM_NEWRULE = 32, +#define RTM_NEWRULE RTM_NEWRULE + RTM_DELRULE, +#define RTM_DELRULE RTM_DELRULE + RTM_GETRULE, +#define RTM_GETRULE RTM_GETRULE + + RTM_NEWQDISC = 36, +#define RTM_NEWQDISC RTM_NEWQDISC + RTM_DELQDISC, +#define RTM_DELQDISC RTM_DELQDISC + RTM_GETQDISC, +#define RTM_GETQDISC RTM_GETQDISC + + RTM_NEWTCLASS = 40, +#define RTM_NEWTCLASS RTM_NEWTCLASS + RTM_DELTCLASS, +#define RTM_DELTCLASS RTM_DELTCLASS + RTM_GETTCLASS, +#define RTM_GETTCLASS RTM_GETTCLASS + + RTM_NEWTFILTER = 44, +#define RTM_NEWTFILTER RTM_NEWTFILTER + RTM_DELTFILTER, +#define RTM_DELTFILTER RTM_DELTFILTER + RTM_GETTFILTER, +#define RTM_GETTFILTER RTM_GETTFILTER + + RTM_NEWACTION = 48, +#define RTM_NEWACTION RTM_NEWACTION + RTM_DELACTION, +#define RTM_DELACTION RTM_DELACTION + RTM_GETACTION, +#define RTM_GETACTION RTM_GETACTION + + RTM_NEWPREFIX = 52, +#define RTM_NEWPREFIX RTM_NEWPREFIX + + RTM_GETMULTICAST = 58, +#define RTM_GETMULTICAST RTM_GETMULTICAST + + RTM_GETANYCAST = 62, +#define RTM_GETANYCAST RTM_GETANYCAST + + RTM_NEWNEIGHTBL = 64, +#define RTM_NEWNEIGHTBL RTM_NEWNEIGHTBL + RTM_GETNEIGHTBL = 66, +#define RTM_GETNEIGHTBL RTM_GETNEIGHTBL + RTM_SETNEIGHTBL, +#define RTM_SETNEIGHTBL RTM_SETNEIGHTBL + + RTM_NEWNDUSEROPT = 68, +#define RTM_NEWNDUSEROPT RTM_NEWNDUSEROPT + + RTM_NEWADDRLABEL = 72, +#define RTM_NEWADDRLABEL RTM_NEWADDRLABEL + RTM_DELADDRLABEL, +#define RTM_DELADDRLABEL RTM_DELADDRLABEL + RTM_GETADDRLABEL, +#define RTM_GETADDRLABEL RTM_GETADDRLABEL + + RTM_GETDCB = 78, +#define RTM_GETDCB RTM_GETDCB + RTM_SETDCB, +#define RTM_SETDCB RTM_SETDCB + + RTM_NEWNETCONF = 80, +#define RTM_NEWNETCONF RTM_NEWNETCONF + RTM_DELNETCONF, +#define RTM_DELNETCONF RTM_DELNETCONF + RTM_GETNETCONF = 82, +#define RTM_GETNETCONF RTM_GETNETCONF + + RTM_NEWMDB = 84, +#define RTM_NEWMDB RTM_NEWMDB + RTM_DELMDB = 85, +#define RTM_DELMDB RTM_DELMDB + RTM_GETMDB = 86, +#define RTM_GETMDB RTM_GETMDB + + RTM_NEWNSID = 88, +#define RTM_NEWNSID RTM_NEWNSID + RTM_DELNSID = 89, +#define RTM_DELNSID RTM_DELNSID + RTM_GETNSID = 90, +#define RTM_GETNSID RTM_GETNSID + + RTM_NEWSTATS = 92, +#define RTM_NEWSTATS RTM_NEWSTATS + RTM_GETSTATS = 94, +#define RTM_GETSTATS RTM_GETSTATS + + RTM_NEWCACHEREPORT = 96, +#define RTM_NEWCACHEREPORT RTM_NEWCACHEREPORT + + RTM_NEWCHAIN = 100, +#define RTM_NEWCHAIN RTM_NEWCHAIN + RTM_DELCHAIN, +#define RTM_DELCHAIN RTM_DELCHAIN + RTM_GETCHAIN, +#define RTM_GETCHAIN RTM_GETCHAIN + + RTM_NEWNEXTHOP = 104, +#define RTM_NEWNEXTHOP RTM_NEWNEXTHOP + RTM_DELNEXTHOP, +#define RTM_DELNEXTHOP RTM_DELNEXTHOP + RTM_GETNEXTHOP, +#define RTM_GETNEXTHOP RTM_GETNEXTHOP + + RTM_NEWLINKPROP = 108, +#define RTM_NEWLINKPROP RTM_NEWLINKPROP + RTM_DELLINKPROP, +#define RTM_DELLINKPROP RTM_DELLINKPROP + 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) +}; + +#define RTM_NR_MSGTYPES (RTM_MAX + 1 - RTM_BASE) +#define RTM_NR_FAMILIES (RTM_NR_MSGTYPES >> 2) +#define RTM_FAM(cmd) (((cmd) - RTM_BASE) >> 2) + +/* + Generic structure for encapsulation of optional route information. + It is reminiscent of sockaddr, but with sa_family replaced + with attribute type. + */ + +struct rtattr { + unsigned short rta_len; + unsigned short rta_type; +}; + +/* Macros to handle rtattributes */ + +#define RTA_ALIGNTO 4U +#define RTA_ALIGN(len) ( ((len)+RTA_ALIGNTO-1) & ~(RTA_ALIGNTO-1) ) +#define RTA_OK(rta,len) ((len) >= (int)sizeof(struct rtattr) && \ + (rta)->rta_len >= sizeof(struct rtattr) && \ + (rta)->rta_len <= (len)) +#define RTA_NEXT(rta,attrlen) ((attrlen) -= RTA_ALIGN((rta)->rta_len), \ + (struct rtattr*)(((char*)(rta)) + RTA_ALIGN((rta)->rta_len))) +#define RTA_LENGTH(len) (RTA_ALIGN(sizeof(struct rtattr)) + (len)) +#define RTA_SPACE(len) RTA_ALIGN(RTA_LENGTH(len)) +#define RTA_DATA(rta) ((void*)(((char*)(rta)) + RTA_LENGTH(0))) +#define RTA_PAYLOAD(rta) ((int)((rta)->rta_len) - RTA_LENGTH(0)) + + + + +/****************************************************************************** + * Definitions used in routing table administration. + ****/ + +struct rtmsg { + unsigned char rtm_family; + unsigned char rtm_dst_len; + unsigned char rtm_src_len; + unsigned char rtm_tos; + + unsigned char rtm_table; /* Routing table id */ + unsigned char rtm_protocol; /* Routing protocol; see below */ + unsigned char rtm_scope; /* See below */ + unsigned char rtm_type; /* See below */ + + unsigned rtm_flags; +}; + +/* rtm_type */ + +enum { + RTN_UNSPEC, + RTN_UNICAST, /* Gateway or direct route */ + RTN_LOCAL, /* Accept locally */ + RTN_BROADCAST, /* Accept locally as broadcast, + send as broadcast */ + RTN_ANYCAST, /* Accept locally as broadcast, + but send as unicast */ + RTN_MULTICAST, /* Multicast route */ + RTN_BLACKHOLE, /* Drop */ + RTN_UNREACHABLE, /* Destination is unreachable */ + RTN_PROHIBIT, /* Administratively prohibited */ + RTN_THROW, /* Not in this table */ + RTN_NAT, /* Translate this address */ + RTN_XRESOLVE, /* Use external resolver */ + __RTN_MAX +}; + +#define RTN_MAX (__RTN_MAX - 1) + + +/* rtm_protocol */ + +#define RTPROT_UNSPEC 0 +#define RTPROT_REDIRECT 1 /* Route installed by ICMP redirects; + not used by current IPv4 */ +#define RTPROT_KERNEL 2 /* Route installed by kernel */ +#define RTPROT_BOOT 3 /* Route installed during boot */ +#define RTPROT_STATIC 4 /* Route installed by administrator */ + +/* Values of protocol >= RTPROT_STATIC are not interpreted by kernel; + they are just passed from user and back as is. + It will be used by hypothetical multiple routing daemons. + Note that protocol values should be standardized in order to + avoid conflicts. + */ + +#define RTPROT_GATED 8 /* Apparently, GateD */ +#define RTPROT_RA 9 /* RDISC/ND router advertisements */ +#define RTPROT_MRT 10 /* Merit MRT */ +#define RTPROT_ZEBRA 11 /* Zebra */ +#define RTPROT_BIRD 12 /* BIRD */ +#define RTPROT_DNROUTED 13 /* DECnet routing daemon */ +#define RTPROT_XORP 14 /* XORP */ +#define RTPROT_NTK 15 /* Netsukuku */ +#define RTPROT_DHCP 16 /* DHCP client */ +#define RTPROT_MROUTED 17 /* Multicast daemon */ +#define RTPROT_BABEL 42 /* Babel daemon */ +#define RTPROT_BGP 186 /* BGP Routes */ +#define RTPROT_ISIS 187 /* ISIS Routes */ +#define RTPROT_OSPF 188 /* OSPF Routes */ +#define RTPROT_RIP 189 /* RIP Routes */ +#define RTPROT_EIGRP 192 /* EIGRP Routes */ + +/* rtm_scope + + Really it is not scope, but sort of distance to the destination. + NOWHERE are reserved for not existing destinations, HOST is our + local addresses, LINK are destinations, located on directly attached + link and UNIVERSE is everywhere in the Universe. + + Intermediate values are also possible f.e. interior routes + could be assigned a value between UNIVERSE and LINK. +*/ + +enum rt_scope_t { + RT_SCOPE_UNIVERSE=0, +/* User defined values */ + RT_SCOPE_SITE=200, + RT_SCOPE_LINK=253, + RT_SCOPE_HOST=254, + RT_SCOPE_NOWHERE=255 +}; + +/* rtm_flags */ + +#define RTM_F_NOTIFY 0x100 /* Notify user of route change */ +#define RTM_F_CLONED 0x200 /* This route is cloned */ +#define RTM_F_EQUALIZE 0x400 /* Multipath equalizer: NI */ +#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 */ + +enum rt_class_t { + RT_TABLE_UNSPEC=0, +/* User defined values */ + RT_TABLE_COMPAT=252, + RT_TABLE_DEFAULT=253, + RT_TABLE_MAIN=254, + RT_TABLE_LOCAL=255, + RT_TABLE_MAX=0xFFFFFFFF +}; + + +/* Routing message attributes */ + +enum rtattr_type_t { + RTA_UNSPEC, + RTA_DST, + RTA_SRC, + RTA_IIF, + RTA_OIF, + RTA_GATEWAY, + RTA_PRIORITY, + RTA_PREFSRC, + RTA_METRICS, + RTA_MULTIPATH, + RTA_PROTOINFO, /* no longer used */ + RTA_FLOW, + RTA_CACHEINFO, + RTA_SESSION, /* no longer used */ + RTA_MP_ALGO, /* no longer used */ + RTA_TABLE, + RTA_MARK, + RTA_MFC_STATS, + RTA_VIA, + RTA_NEWDST, + RTA_PREF, + RTA_ENCAP_TYPE, + RTA_ENCAP, + RTA_EXPIRES, + RTA_PAD, + RTA_UID, + RTA_TTL_PROPAGATE, + RTA_IP_PROTO, + RTA_SPORT, + RTA_DPORT, + RTA_NH_ID, + __RTA_MAX +}; + +#define RTA_MAX (__RTA_MAX - 1) + +#define RTM_RTA(r) ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct rtmsg)))) +#define RTM_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct rtmsg)) + +/* RTM_MULTIPATH --- array of struct rtnexthop. + * + * "struct rtnexthop" describes all necessary nexthop information, + * i.e. parameters of path to a destination via this nexthop. + * + * At the moment it is impossible to set different prefsrc, mtu, window + * and rtt for different paths from multipath. + */ + +struct rtnexthop { + unsigned short rtnh_len; + unsigned char rtnh_flags; + unsigned char rtnh_hops; + int rtnh_ifindex; +}; + +/* rtnh_flags */ + +#define RTNH_F_DEAD 1 /* Nexthop is dead (used by multipath) */ +#define RTNH_F_PERVASIVE 2 /* Do recursive gateway lookup */ +#define RTNH_F_ONLINK 4 /* Gateway is forced on link */ +#define RTNH_F_OFFLOAD 8 /* offloaded route */ +#define RTNH_F_LINKDOWN 16 /* carrier-down on nexthop */ +#define RTNH_F_UNRESOLVED 32 /* The entry is unresolved (ipmr) */ + +#define RTNH_COMPARE_MASK (RTNH_F_DEAD | RTNH_F_LINKDOWN | RTNH_F_OFFLOAD) + +/* Macros to handle hexthops */ + +#define RTNH_ALIGNTO 4 +#define RTNH_ALIGN(len) ( ((len)+RTNH_ALIGNTO-1) & ~(RTNH_ALIGNTO-1) ) +#define RTNH_OK(rtnh,len) ((rtnh)->rtnh_len >= sizeof(struct rtnexthop) && \ + ((int)(rtnh)->rtnh_len) <= (len)) +#define RTNH_NEXT(rtnh) ((struct rtnexthop*)(((char*)(rtnh)) + RTNH_ALIGN((rtnh)->rtnh_len))) +#define RTNH_LENGTH(len) (RTNH_ALIGN(sizeof(struct rtnexthop)) + (len)) +#define RTNH_SPACE(len) RTNH_ALIGN(RTNH_LENGTH(len)) +#define RTNH_DATA(rtnh) ((struct rtattr*)(((char*)(rtnh)) + RTNH_LENGTH(0))) + +/* RTA_VIA */ +struct rtvia { + __kernel_sa_family_t rtvia_family; + __u8 rtvia_addr[0]; +}; + +/* RTM_CACHEINFO */ + +struct rta_cacheinfo { + __u32 rta_clntref; + __u32 rta_lastuse; + __s32 rta_expires; + __u32 rta_error; + __u32 rta_used; + +#define RTNETLINK_HAVE_PEERINFO 1 + __u32 rta_id; + __u32 rta_ts; + __u32 rta_tsage; +}; + +/* RTM_METRICS --- array of struct rtattr with types of RTAX_* */ + +enum { + RTAX_UNSPEC, +#define RTAX_UNSPEC RTAX_UNSPEC + RTAX_LOCK, +#define RTAX_LOCK RTAX_LOCK + RTAX_MTU, +#define RTAX_MTU RTAX_MTU + RTAX_WINDOW, +#define RTAX_WINDOW RTAX_WINDOW + RTAX_RTT, +#define RTAX_RTT RTAX_RTT + RTAX_RTTVAR, +#define RTAX_RTTVAR RTAX_RTTVAR + RTAX_SSTHRESH, +#define RTAX_SSTHRESH RTAX_SSTHRESH + RTAX_CWND, +#define RTAX_CWND RTAX_CWND + RTAX_ADVMSS, +#define RTAX_ADVMSS RTAX_ADVMSS + RTAX_REORDERING, +#define RTAX_REORDERING RTAX_REORDERING + RTAX_HOPLIMIT, +#define RTAX_HOPLIMIT RTAX_HOPLIMIT + RTAX_INITCWND, +#define RTAX_INITCWND RTAX_INITCWND + RTAX_FEATURES, +#define RTAX_FEATURES RTAX_FEATURES + RTAX_RTO_MIN, +#define RTAX_RTO_MIN RTAX_RTO_MIN + RTAX_INITRWND, +#define RTAX_INITRWND RTAX_INITRWND + RTAX_QUICKACK, +#define RTAX_QUICKACK RTAX_QUICKACK + RTAX_CC_ALGO, +#define RTAX_CC_ALGO RTAX_CC_ALGO + RTAX_FASTOPEN_NO_COOKIE, +#define RTAX_FASTOPEN_NO_COOKIE RTAX_FASTOPEN_NO_COOKIE + __RTAX_MAX +}; + +#define RTAX_MAX (__RTAX_MAX - 1) + +#define RTAX_FEATURE_ECN (1 << 0) +#define RTAX_FEATURE_SACK (1 << 1) +#define RTAX_FEATURE_TIMESTAMP (1 << 2) +#define RTAX_FEATURE_ALLFRAG (1 << 3) + +#define RTAX_FEATURE_MASK (RTAX_FEATURE_ECN | RTAX_FEATURE_SACK | \ + RTAX_FEATURE_TIMESTAMP | RTAX_FEATURE_ALLFRAG) + +struct rta_session { + __u8 proto; + __u8 pad1; + __u16 pad2; + + union { + struct { + __u16 sport; + __u16 dport; + } ports; + + struct { + __u8 type; + __u8 code; + __u16 ident; + } icmpt; + + __u32 spi; + } u; +}; + +struct rta_mfc_stats { + __u64 mfcs_packets; + __u64 mfcs_bytes; + __u64 mfcs_wrong_if; +}; + +/**** + * General form of address family dependent message. + ****/ + +struct rtgenmsg { + unsigned char rtgen_family; +}; + +/***************************************************************** + * Link layer specific messages. + ****/ + +/* struct ifinfomsg + * passes link level specific information, not dependent + * on network protocol. + */ + +struct ifinfomsg { + unsigned char ifi_family; + unsigned char __ifi_pad; + unsigned short ifi_type; /* ARPHRD_* */ + int ifi_index; /* Link index */ + unsigned ifi_flags; /* IFF_* flags */ + unsigned ifi_change; /* IFF_* change mask */ +}; + +/******************************************************************** + * prefix information + ****/ + +struct prefixmsg { + unsigned char prefix_family; + unsigned char prefix_pad1; + unsigned short prefix_pad2; + int prefix_ifindex; + unsigned char prefix_type; + unsigned char prefix_len; + unsigned char prefix_flags; + unsigned char prefix_pad3; +}; + +enum +{ + PREFIX_UNSPEC, + PREFIX_ADDRESS, + PREFIX_CACHEINFO, + __PREFIX_MAX +}; + +#define PREFIX_MAX (__PREFIX_MAX - 1) + +struct prefix_cacheinfo { + __u32 preferred_time; + __u32 valid_time; +}; + + +/***************************************************************** + * Traffic control messages. + ****/ + +struct tcmsg { + unsigned char tcm_family; + unsigned char tcm__pad1; + unsigned short tcm__pad2; + int tcm_ifindex; + __u32 tcm_handle; + __u32 tcm_parent; +/* tcm_block_index is used instead of tcm_parent + * in case tcm_ifindex == TCM_IFINDEX_MAGIC_BLOCK + */ +#define tcm_block_index tcm_parent + __u32 tcm_info; +}; + +/* For manipulation of filters in shared block, tcm_ifindex is set to + * TCM_IFINDEX_MAGIC_BLOCK, and tcm_parent is aliased to tcm_block_index + * which is the block index. + */ +#define TCM_IFINDEX_MAGIC_BLOCK (0xFFFFFFFFU) + +enum { + TCA_UNSPEC, + TCA_KIND, + TCA_OPTIONS, + TCA_STATS, + TCA_XSTATS, + TCA_RATE, + TCA_FCNT, + TCA_STATS2, + TCA_STAB, + TCA_PAD, + TCA_DUMP_INVISIBLE, + TCA_CHAIN, + TCA_HW_OFFLOAD, + TCA_INGRESS_BLOCK, + TCA_EGRESS_BLOCK, + __TCA_MAX +}; + +#define TCA_MAX (__TCA_MAX - 1) + +#define TCA_RTA(r) ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct tcmsg)))) +#define TCA_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct tcmsg)) + +/******************************************************************** + * Neighbor Discovery userland options + ****/ + +struct nduseroptmsg { + unsigned char nduseropt_family; + unsigned char nduseropt_pad1; + unsigned short nduseropt_opts_len; /* Total length of options */ + int nduseropt_ifindex; + __u8 nduseropt_icmp_type; + __u8 nduseropt_icmp_code; + unsigned short nduseropt_pad2; + unsigned int nduseropt_pad3; + /* Followed by one or more ND options */ +}; + +enum { + NDUSEROPT_UNSPEC, + NDUSEROPT_SRCADDR, + __NDUSEROPT_MAX +}; + +#define NDUSEROPT_MAX (__NDUSEROPT_MAX - 1) + +/* RTnetlink multicast groups - backwards compatibility for userspace */ +#define RTMGRP_LINK 1 +#define RTMGRP_NOTIFY 2 +#define RTMGRP_NEIGH 4 +#define RTMGRP_TC 8 + +#define RTMGRP_IPV4_IFADDR 0x10 +#define RTMGRP_IPV4_MROUTE 0x20 +#define RTMGRP_IPV4_ROUTE 0x40 +#define RTMGRP_IPV4_RULE 0x80 + +#define RTMGRP_IPV6_IFADDR 0x100 +#define RTMGRP_IPV6_MROUTE 0x200 +#define RTMGRP_IPV6_ROUTE 0x400 +#define RTMGRP_IPV6_IFINFO 0x800 + +#define RTMGRP_DECnet_IFADDR 0x1000 +#define RTMGRP_DECnet_ROUTE 0x4000 + +#define RTMGRP_IPV6_PREFIX 0x20000 + +/* RTnetlink multicast groups */ +enum rtnetlink_groups { + RTNLGRP_NONE, +#define RTNLGRP_NONE RTNLGRP_NONE + RTNLGRP_LINK, +#define RTNLGRP_LINK RTNLGRP_LINK + RTNLGRP_NOTIFY, +#define RTNLGRP_NOTIFY RTNLGRP_NOTIFY + RTNLGRP_NEIGH, +#define RTNLGRP_NEIGH RTNLGRP_NEIGH + RTNLGRP_TC, +#define RTNLGRP_TC RTNLGRP_TC + RTNLGRP_IPV4_IFADDR, +#define RTNLGRP_IPV4_IFADDR RTNLGRP_IPV4_IFADDR + RTNLGRP_IPV4_MROUTE, +#define RTNLGRP_IPV4_MROUTE RTNLGRP_IPV4_MROUTE + RTNLGRP_IPV4_ROUTE, +#define RTNLGRP_IPV4_ROUTE RTNLGRP_IPV4_ROUTE + RTNLGRP_IPV4_RULE, +#define RTNLGRP_IPV4_RULE RTNLGRP_IPV4_RULE + RTNLGRP_IPV6_IFADDR, +#define RTNLGRP_IPV6_IFADDR RTNLGRP_IPV6_IFADDR + RTNLGRP_IPV6_MROUTE, +#define RTNLGRP_IPV6_MROUTE RTNLGRP_IPV6_MROUTE + RTNLGRP_IPV6_ROUTE, +#define RTNLGRP_IPV6_ROUTE RTNLGRP_IPV6_ROUTE + RTNLGRP_IPV6_IFINFO, +#define RTNLGRP_IPV6_IFINFO RTNLGRP_IPV6_IFINFO + RTNLGRP_DECnet_IFADDR, +#define RTNLGRP_DECnet_IFADDR RTNLGRP_DECnet_IFADDR + RTNLGRP_NOP2, + RTNLGRP_DECnet_ROUTE, +#define RTNLGRP_DECnet_ROUTE RTNLGRP_DECnet_ROUTE + RTNLGRP_DECnet_RULE, +#define RTNLGRP_DECnet_RULE RTNLGRP_DECnet_RULE + RTNLGRP_NOP4, + RTNLGRP_IPV6_PREFIX, +#define RTNLGRP_IPV6_PREFIX RTNLGRP_IPV6_PREFIX + RTNLGRP_IPV6_RULE, +#define RTNLGRP_IPV6_RULE RTNLGRP_IPV6_RULE + RTNLGRP_ND_USEROPT, +#define RTNLGRP_ND_USEROPT RTNLGRP_ND_USEROPT + RTNLGRP_PHONET_IFADDR, +#define RTNLGRP_PHONET_IFADDR RTNLGRP_PHONET_IFADDR + RTNLGRP_PHONET_ROUTE, +#define RTNLGRP_PHONET_ROUTE RTNLGRP_PHONET_ROUTE + RTNLGRP_DCB, +#define RTNLGRP_DCB RTNLGRP_DCB + RTNLGRP_IPV4_NETCONF, +#define RTNLGRP_IPV4_NETCONF RTNLGRP_IPV4_NETCONF + RTNLGRP_IPV6_NETCONF, +#define RTNLGRP_IPV6_NETCONF RTNLGRP_IPV6_NETCONF + RTNLGRP_MDB, +#define RTNLGRP_MDB RTNLGRP_MDB + RTNLGRP_MPLS_ROUTE, +#define RTNLGRP_MPLS_ROUTE RTNLGRP_MPLS_ROUTE + RTNLGRP_NSID, +#define RTNLGRP_NSID RTNLGRP_NSID + RTNLGRP_MPLS_NETCONF, +#define RTNLGRP_MPLS_NETCONF RTNLGRP_MPLS_NETCONF + RTNLGRP_IPV4_MROUTE_R, +#define RTNLGRP_IPV4_MROUTE_R RTNLGRP_IPV4_MROUTE_R + RTNLGRP_IPV6_MROUTE_R, +#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) + +/* TC action piece */ +struct tcamsg { + unsigned char tca_family; + unsigned char tca__pad1; + unsigned short tca__pad2; +}; + +enum { + TCA_ROOT_UNSPEC, + TCA_ROOT_TAB, +#define TCA_ACT_TAB TCA_ROOT_TAB +#define TCAA_MAX TCA_ROOT_TAB + TCA_ROOT_FLAGS, + TCA_ROOT_COUNT, + TCA_ROOT_TIME_DELTA, /* in msecs */ + __TCA_ROOT_MAX, +#define TCA_ROOT_MAX (__TCA_ROOT_MAX - 1) +}; + +#define TA_RTA(r) ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct tcamsg)))) +#define TA_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct tcamsg)) +/* tcamsg flags stored in attribute TCA_ROOT_FLAGS + * + * TCA_FLAG_LARGE_DUMP_ON user->kernel to request for larger than TCA_ACT_MAX_PRIO + * actions in a dump. All dump responses will contain the number of actions + * being dumped stored in for user app's consumption in TCA_ROOT_COUNT + * + */ +#define TCA_FLAG_LARGE_DUMP_ON (1 << 0) + +/* New extended info filters for IFLA_EXT_MASK */ +#define RTEXT_FILTER_VF (1 << 0) +#define RTEXT_FILTER_BRVLAN (1 << 1) +#define RTEXT_FILTER_BRVLAN_COMPRESSED (1 << 2) +#define RTEXT_FILTER_SKIP_STATS (1 << 3) + +/* End of information exported to user level */ + + + +#endif /* __LINUX_RTNETLINK_H */ From patchwork Fri Mar 6 17:04:39 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Michal Kubecek X-Patchwork-Id: 222923 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.8 required=3.0 tests=HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SIGNED_OFF_BY, SPF_HELO_NONE, SPF_PASS autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 8911EC10DCE for ; Fri, 6 Mar 2020 17:04:47 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 54D94206E2 for ; Fri, 6 Mar 2020 17:04:47 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727097AbgCFREq (ORCPT ); Fri, 6 Mar 2020 12:04:46 -0500 Received: from mx2.suse.de ([195.135.220.15]:43368 "EHLO mx2.suse.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727083AbgCFREq (ORCPT ); Fri, 6 Mar 2020 12:04:46 -0500 X-Virus-Scanned: by amavisd-new at test-mx.suse.de Received: from relay2.suse.de (unknown [195.135.220.254]) by mx2.suse.de (Postfix) with ESMTP id 3B5E7B2D8; Fri, 6 Mar 2020 17:04:40 +0000 (UTC) Received: by unicorn.suse.cz (Postfix, from userid 1000) id E04CCE00E7; Fri, 6 Mar 2020 18:04:39 +0100 (CET) Message-Id: In-Reply-To: References: From: Michal Kubecek Subject: [PATCH ethtool v3 08/25] netlink: netlink socket wrapper and helpers To: John Linville , netdev@vger.kernel.org Cc: Andrew Lunn , Florian Fainelli Date: Fri, 6 Mar 2020 18:04:39 +0100 (CET) Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org Add data structure for netlink socket and few helpers to work with it. The nl_socket structure is a wrapper for struct mnl_socket from libmnl, a message buffer and some additional data. Helpers for sending netlink (and genetlink), processing replies are provided as well as debugging helpers. v2: - reworked debugging output for incoming/outgoing messages - drop tables of message type names (replaced in patch 22) - nl_context::suppress_nlerr allows two levels (EOPNOTSUPP / all codes) - drop nlsock_init(), rename __nlsock_init() to nlsock_init() - add kerneldoc style comments Signed-off-by: Michal Kubecek --- Makefile.am | 3 +- internal.h | 8 + netlink/netlink.c | 28 ++++ netlink/netlink.h | 11 ++ netlink/nlsock.c | 364 ++++++++++++++++++++++++++++++++++++++++++++++ netlink/nlsock.h | 45 ++++++ 6 files changed, 458 insertions(+), 1 deletion(-) create mode 100644 netlink/nlsock.c create mode 100644 netlink/nlsock.h diff --git a/Makefile.am b/Makefile.am index 2f4b8334cfe6..c51193ac92fd 100644 --- a/Makefile.am +++ b/Makefile.am @@ -26,7 +26,8 @@ endif if ETHTOOL_ENABLE_NETLINK ethtool_SOURCES += \ netlink/netlink.c netlink/netlink.h netlink/extapi.h \ - netlink/msgbuff.c netlink/msgbuff.h \ + netlink/msgbuff.c netlink/msgbuff.h netlink/nlsock.c \ + netlink/nlsock.h \ uapi/linux/ethtool_netlink.h \ uapi/linux/netlink.h uapi/linux/genetlink.h \ uapi/linux/rtnetlink.h uapi/linux/if_link.h diff --git a/internal.h b/internal.h index 72a04e638a13..a518bfa99380 100644 --- a/internal.h +++ b/internal.h @@ -119,8 +119,16 @@ static inline int test_bit(unsigned int nr, const unsigned long *addr) /* debugging flags */ enum { DEBUG_PARSE, + DEBUG_NL_MSGS, /* incoming/outgoing netlink messages */ + DEBUG_NL_DUMP_SND, /* dump outgoing netlink messages */ + DEBUG_NL_DUMP_RCV, /* dump incoming netlink messages */ }; +static inline bool debug_on(unsigned long debug, unsigned int bit) +{ + return (debug & (1 << bit)); +} + /* Internal values for old-style offload flags. Values and names * must not clash with the flags defined for ETHTOOL_{G,S}FLAGS. */ diff --git a/netlink/netlink.c b/netlink/netlink.c index 84e188119989..7d5eca666c84 100644 --- a/netlink/netlink.c +++ b/netlink/netlink.c @@ -10,6 +10,34 @@ #include "netlink.h" #include "extapi.h" +/* Used as reply callback for requests where no reply is expected (e.g. most + * "set" type commands) + */ +int nomsg_reply_cb(const struct nlmsghdr *nlhdr, void *data) +{ + const struct genlmsghdr *ghdr = (const struct genlmsghdr *)(nlhdr + 1); + + fprintf(stderr, "received unexpected message: len=%u type=%u cmd=%u\n", + nlhdr->nlmsg_len, nlhdr->nlmsg_type, ghdr->cmd); + return MNL_CB_OK; +} + +/* standard attribute parser callback; it fills provided array with pointers + * to attributes like kernel nla_parse(). We must expect to run on top of + * a newer kernel which may send attributes that we do not know (yet). Rather + * than treating them as an error, just ignore them. + */ +int attr_cb(const struct nlattr *attr, void *data) +{ + const struct attr_tb_info *tb_info = data; + int type = mnl_attr_get_type(attr); + + if (type >= 0 && type <= tb_info->max_type) + tb_info->tb[type] = attr; + + return MNL_CB_OK; +} + /* initialization */ int netlink_init(struct cmd_context *ctx) diff --git a/netlink/netlink.h b/netlink/netlink.h index 1eaeec30b7d2..fbcea0b62240 100644 --- a/netlink/netlink.h +++ b/netlink/netlink.h @@ -24,4 +24,15 @@ struct nl_context { uint16_t ethnl_fam; }; +struct attr_tb_info { + const struct nlattr **tb; + unsigned int max_type; +}; + +#define DECLARE_ATTR_TB_INFO(tbl) \ + struct attr_tb_info tbl ## _info = { (tbl), (MNL_ARRAY_SIZE(tbl) - 1) } + +int nomsg_reply_cb(const struct nlmsghdr *nlhdr, void *data); +int attr_cb(const struct nlattr *attr, void *data); + #endif /* ETHTOOL_NETLINK_INT_H__ */ diff --git a/netlink/nlsock.c b/netlink/nlsock.c new file mode 100644 index 000000000000..d5fa668f508d --- /dev/null +++ b/netlink/nlsock.c @@ -0,0 +1,364 @@ +/* + * nlsock.c - netlink socket + * + * Data structure and code for netlink socket abstraction. + */ + +#include +#include + +#include "../internal.h" +#include "nlsock.h" +#include "netlink.h" + +#define NLSOCK_RECV_BUFFSIZE 65536 + +static void ctrl_msg_summary(const struct nlmsghdr *nlhdr) +{ + const struct nlmsgerr *nlerr; + + switch (nlhdr->nlmsg_type) { + case NLMSG_NOOP: + printf(" noop\n"); + break; + case NLMSG_ERROR: + printf(" error"); + if (nlhdr->nlmsg_len < NLMSG_HDRLEN + sizeof(*nlerr)) { + printf(" malformed\n"); + break; + } + nlerr = mnl_nlmsg_get_payload(nlhdr); + printf(" errno=%d\n", nlerr->error); + break; + case NLMSG_DONE: + printf(" done\n"); + break; + case NLMSG_OVERRUN: + printf(" overrun\n"); + break; + default: + printf(" type %u\n", nlhdr->nlmsg_type); + break; + } +} + +static void genl_msg_summary(const struct nlmsghdr *nlhdr, int ethnl_fam, + bool outgoing) +{ + if (nlhdr->nlmsg_type == ethnl_fam) { + const struct genlmsghdr *ghdr; + + printf(" ethool"); + if (nlhdr->nlmsg_len < NLMSG_HDRLEN + GENL_HDRLEN) { + printf(" malformed\n"); + return; + } + ghdr = mnl_nlmsg_get_payload(nlhdr); + + printf(" cmd %u", ghdr->cmd); + fputc('\n', stdout); + + return; + } + + if (nlhdr->nlmsg_type == GENL_ID_CTRL) + printf(" genl-ctrl\n"); + else + fputc('\n', stdout); +} + +static void rtnl_msg_summary(const struct nlmsghdr *nlhdr) +{ + unsigned int type = nlhdr->nlmsg_type; + + printf(" type %u\n", type); +} + +static void debug_msg_summary(const struct nlmsghdr *nlhdr, int ethnl_fam, + int nl_fam, bool outgoing) +{ + printf(" msg length %u", nlhdr->nlmsg_len); + + if (nlhdr->nlmsg_type < NLMSG_MIN_TYPE) { + ctrl_msg_summary(nlhdr); + return; + } + + switch(nl_fam) { + case NETLINK_GENERIC: + genl_msg_summary(nlhdr, ethnl_fam, outgoing); + break; + case NETLINK_ROUTE: + rtnl_msg_summary(nlhdr); + break; + default: + fputc('\n', stdout); + break; + } +} + +static void debug_msg(struct nl_socket *nlsk, const void *msg, unsigned int len, + bool outgoing) +{ + const char *dirlabel = outgoing ? "sending" : "received"; + uint32_t debug = nlsk->nlctx->ctx->debug; + const struct nlmsghdr *nlhdr = msg; + bool summary, dump; + const char *nl_fam_label; + int left = len; + + summary = debug_on(debug, DEBUG_NL_MSGS); + dump = debug_on(debug, + outgoing ? DEBUG_NL_DUMP_SND : DEBUG_NL_DUMP_RCV); + if (!summary && !dump) + return; + switch(nlsk->nl_fam) { + case NETLINK_GENERIC: + nl_fam_label = "genetlink"; + break; + case NETLINK_ROUTE: + nl_fam_label = "rtnetlink"; + break; + default: + nl_fam_label = "netlink"; + break; + } + printf("%s %s packet (%u bytes):\n", dirlabel, nl_fam_label, len); + + while (nlhdr && left > 0 && mnl_nlmsg_ok(nlhdr, left)) { + if (summary) + debug_msg_summary(nlhdr, nlsk->nlctx->ethnl_fam, + nlsk->nl_fam, outgoing); + if (dump) + mnl_nlmsg_fprintf(stdout, nlhdr, nlhdr->nlmsg_len, + GENL_HDRLEN); + + nlhdr = mnl_nlmsg_next(nlhdr, &left); + } +} + +/** + * nlsock_process_ack() - process NLMSG_ERROR message from kernel + * @nlhdr: pointer to netlink header + * @len: length of received data (from nlhdr to end of buffer) + * @suppress_nlerr: 0 show all errors, 1 silence -EOPNOTSUPP, 2 silence all + * + * Return: error code extracted from the message + */ +static int nlsock_process_ack(struct nlmsghdr *nlhdr, ssize_t len, + unsigned int suppress_nlerr) +{ + const struct nlattr *tb[NLMSGERR_ATTR_MAX + 1] = {}; + DECLARE_ATTR_TB_INFO(tb); + unsigned int tlv_offset; + struct nlmsgerr *nlerr; + bool silent; + + if (len < NLMSG_HDRLEN + sizeof(*nlerr)) + return -EFAULT; + nlerr = mnl_nlmsg_get_payload(nlhdr); + silent = (!(nlhdr->nlmsg_flags & NLM_F_ACK_TLVS) || + suppress_nlerr >= 2 || + (suppress_nlerr && nlerr->error == -EOPNOTSUPP)); + if (silent) + goto out; + + tlv_offset = sizeof(*nlerr); + if (!(nlhdr->nlmsg_flags & NLM_F_CAPPED)) + tlv_offset += MNL_ALIGN(mnl_nlmsg_get_payload_len(&nlerr->msg)); + + if (mnl_attr_parse(nlhdr, tlv_offset, attr_cb, &tb_info) < 0) + goto out; + if (tb[NLMSGERR_ATTR_MSG]) { + const char *msg = mnl_attr_get_str(tb[NLMSGERR_ATTR_MSG]); + + fprintf(stderr, "netlink %s: %s", + nlerr->error ? "error" : "warning", msg); + if (tb[NLMSGERR_ATTR_OFFS]) + fprintf(stderr, " (offset %u)", + mnl_attr_get_u32(tb[NLMSGERR_ATTR_OFFS])); + fputc('\n', stderr); + } + +out: + if (nlerr->error) { + errno = -nlerr->error; + if (!silent) + perror("netlink error"); + } + return nlerr->error; +} + +/** + * nlsock_process_reply() - process reply packet(s) from kernel + * @nlsk: netlink socket to read from + * @reply_cb: callback to process each message + * @data: pointer passed as argument to @reply_cb callback + * + * Read packets from kernel and pass reply messages to @reply_cb callback + * until an error is encountered or NLMSG_ERR message is received. In the + * latter case, return value is the error code extracted from it. + * + * Return: 0 on success or negative error code + */ +int nlsock_process_reply(struct nl_socket *nlsk, mnl_cb_t reply_cb, void *data) +{ + struct nl_msg_buff *msgbuff = &nlsk->msgbuff; + struct nlmsghdr *nlhdr; + ssize_t len; + char *buff; + int ret; + + ret = msgbuff_realloc(msgbuff, NLSOCK_RECV_BUFFSIZE); + if (ret < 0) + return ret; + buff = msgbuff->buff; + + do { + len = mnl_socket_recvfrom(nlsk->sk, buff, msgbuff->size); + if (len <= 0) + return (len ? -EFAULT : 0); + debug_msg(nlsk, buff, len, false); + if (len < NLMSG_HDRLEN) + return -EFAULT; + + nlhdr = (struct nlmsghdr *)buff; + if (nlhdr->nlmsg_type == NLMSG_ERROR) + return nlsock_process_ack(nlhdr, len, + nlsk->nlctx->suppress_nlerr); + + msgbuff->nlhdr = nlhdr; + msgbuff->genlhdr = mnl_nlmsg_get_payload(nlhdr); + msgbuff->payload = + mnl_nlmsg_get_payload_offset(nlhdr, GENL_HDRLEN); + ret = mnl_cb_run(buff, len, nlsk->seq, nlsk->port, reply_cb, + data); + } while (ret > 0); + + return ret; +} + +int nlsock_prep_get_request(struct nl_socket *nlsk, unsigned int nlcmd, + uint16_t hdr_attrtype, u32 flags) +{ + unsigned int nlm_flags = NLM_F_REQUEST | NLM_F_ACK; + struct nl_context *nlctx = nlsk->nlctx; + const char *devname = nlctx->ctx->devname; + int ret; + + if (devname && !strcmp(devname, WILDCARD_DEVNAME)) { + devname = NULL; + nlm_flags |= NLM_F_DUMP; + } + nlctx->is_dump = !devname; + + ret = msg_init(nlctx, &nlsk->msgbuff, nlcmd, nlm_flags); + if (ret < 0) + return ret; + if (ethnla_fill_header(&nlsk->msgbuff, hdr_attrtype, devname, flags)) + return -EMSGSIZE; + + return 0; +} + +/** + * nlsock_sendmsg() - send a netlink message to kernel + * @nlsk: netlink socket + * @altbuff: alternative message buffer; if null, use buffer embedded in @nlsk + * + * Return: sent size or negative error code + */ +ssize_t nlsock_sendmsg(struct nl_socket *nlsk, struct nl_msg_buff *altbuff) +{ + struct nl_msg_buff *msgbuff = altbuff ?: &nlsk->msgbuff; + struct nlmsghdr *nlhdr = msgbuff->nlhdr; + + nlhdr->nlmsg_seq = ++nlsk->seq; + debug_msg(nlsk, msgbuff->buff, nlhdr->nlmsg_len, true); + return mnl_socket_sendto(nlsk->sk, nlhdr, nlhdr->nlmsg_len); +} + +/** + * nlsock_send_get_request() - send request and process reply + * @nlsk: netlink socket + * @cb: callback to process reply message(s) + * + * This simple helper only handles the most common case when the embedded + * message buffer is sent and @cb takes netlink context (struct nl_context) + * as last argument. + */ +int nlsock_send_get_request(struct nl_socket *nlsk, mnl_cb_t cb) +{ + int ret; + + ret = nlsock_sendmsg(nlsk, NULL); + if (ret < 0) + goto err; + ret = nlsock_process_reply(nlsk, cb, nlsk->nlctx); + if (ret == 0) + return 0; +err: + return nlsk->nlctx->exit_code ?: 1; +} + +/** + * nlsock_init() - allocate and initialize netlink socket + * @nlctx: netlink context + * @__nlsk: store pointer to the allocated socket here + * @nl_fam: netlink family (e.g. NETLINK_GENERIC or NETLINK_ROUTE) + * + * Allocate and initialize netlink socket and its embedded message buffer. + * Cleans up on error, caller is responsible for destroying the socket with + * nlsock_done() on success. + * + * Return: 0 on success or negative error code + */ +int nlsock_init(struct nl_context *nlctx, struct nl_socket **__nlsk, int nl_fam) +{ + struct nl_socket *nlsk; + int val; + int ret; + + nlsk = calloc(1, sizeof(*nlsk)); + if (!nlsk) + return -ENOMEM; + nlsk->nlctx = nlctx; + msgbuff_init(&nlsk->msgbuff); + + ret = -ECONNREFUSED; + nlsk->sk = mnl_socket_open(nl_fam); + if (!nlsk->sk) + goto out_msgbuff; + val = 1; + mnl_socket_setsockopt(nlsk->sk, NETLINK_EXT_ACK, &val, sizeof(val)); + ret = mnl_socket_bind(nlsk->sk, 0, MNL_SOCKET_AUTOPID); + if (ret < 0) + goto out_close; + nlsk->port = mnl_socket_get_portid(nlsk->sk); + nlsk->nl_fam = nl_fam; + + *__nlsk = nlsk; + return 0; + +out_close: + if (nlsk->sk) + mnl_socket_close(nlsk->sk); +out_msgbuff: + msgbuff_done(&nlsk->msgbuff); + free(nlsk); + return ret; +} + +/** + * nlsock_done() - destroy a netlink socket + * @nlsk: netlink socket + * + * Close the socket and free the structure and related data. + */ +void nlsock_done(struct nl_socket *nlsk) +{ + if (nlsk->sk) + mnl_socket_close(nlsk->sk); + msgbuff_done(&nlsk->msgbuff); + memset(nlsk, '\0', sizeof(*nlsk)); +} diff --git a/netlink/nlsock.h b/netlink/nlsock.h new file mode 100644 index 000000000000..b015f8642704 --- /dev/null +++ b/netlink/nlsock.h @@ -0,0 +1,45 @@ +/* + * nlsock.h - netlink socket + * + * Declarations of netlink socket structure and related functions. + */ + +#ifndef ETHTOOL_NETLINK_NLSOCK_H__ +#define ETHTOOL_NETLINK_NLSOCK_H__ + +#include +#include +#include +#include +#include "msgbuff.h" + +struct nl_context; + +/** + * struct nl_socket - netlink socket abstraction + * @nlctx: netlink context + * @sk: libmnl socket handle + * @msgbuff: embedded message buffer used by default + * @port: port number for netlink header + * @seq: autoincremented sequence number for netlink header + * @nl_fam: netlink family (e.g. NETLINK_GENERIC or NETLINK_ROUTE) + */ +struct nl_socket { + struct nl_context *nlctx; + struct mnl_socket *sk; + struct nl_msg_buff msgbuff; + unsigned int port; + unsigned int seq; + int nl_fam; +}; + +int nlsock_init(struct nl_context *nlctx, struct nl_socket **__nlsk, + int nl_fam); +void nlsock_done(struct nl_socket *nlsk); +int nlsock_prep_get_request(struct nl_socket *nlsk, unsigned int nlcmd, + uint16_t hdr_attrtype, u32 flags); +ssize_t nlsock_sendmsg(struct nl_socket *nlsk, struct nl_msg_buff *__msgbuff); +int nlsock_send_get_request(struct nl_socket *nlsk, mnl_cb_t cb); +int nlsock_process_reply(struct nl_socket *nlsk, mnl_cb_t reply_cb, void *data); + +#endif /* ETHTOOL_NETLINK_NLSOCK_H__ */ From patchwork Fri Mar 6 17:04:49 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Michal Kubecek X-Patchwork-Id: 222922 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.8 required=3.0 tests=HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SIGNED_OFF_BY, SPF_HELO_NONE, SPF_PASS autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 06386C10DCE for ; Fri, 6 Mar 2020 17:04:56 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id D0573208C3 for ; Fri, 6 Mar 2020 17:04:55 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727126AbgCFREz (ORCPT ); Fri, 6 Mar 2020 12:04:55 -0500 Received: from mx2.suse.de ([195.135.220.15]:43518 "EHLO mx2.suse.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726738AbgCFREy (ORCPT ); Fri, 6 Mar 2020 12:04:54 -0500 X-Virus-Scanned: by amavisd-new at test-mx.suse.de Received: from relay2.suse.de (unknown [195.135.220.254]) by mx2.suse.de (Postfix) with ESMTP id 49658B324; Fri, 6 Mar 2020 17:04:50 +0000 (UTC) Received: by unicorn.suse.cz (Postfix, from userid 1000) id ED3EBE00E7; Fri, 6 Mar 2020 18:04:49 +0100 (CET) Message-Id: <0967c9bf176b0f4e14f941a0e9c9ef32d54d899f.1583513281.git.mkubecek@suse.cz> In-Reply-To: References: From: Michal Kubecek Subject: [PATCH ethtool v3 10/25] netlink: add support for string sets To: John Linville , netdev@vger.kernel.org Cc: Andrew Lunn , Florian Fainelli Date: Fri, 6 Mar 2020 18:04:49 +0100 (CET) Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org Add infrastructure for querying kernel for string sets (analog to ioctl commands ETHTOOL_GSSET_INFO and ETHTOOL_GSTRINGS), caching the results and making them available to netlink code. There are two types of string sets: global (not related to a device) and per device (each device has its set of string sets). Per device string sets are stored in a linked list (one entry for each device) for now. String sets can be either preloaded completely on start using preload_global_strings() and preload_perdev_strings() or requested by one when there is a need for them. In the latter case (preferred, in particular for one shot operation mode), second netlink socket is used to request the string set contents. Signed-off-by: Michal Kubecek --- Makefile.am | 2 +- netlink/netlink.c | 53 +++++++++ netlink/netlink.h | 9 ++ netlink/strset.c | 295 ++++++++++++++++++++++++++++++++++++++++++++++ netlink/strset.h | 25 ++++ 5 files changed, 383 insertions(+), 1 deletion(-) create mode 100644 netlink/strset.c create mode 100644 netlink/strset.h diff --git a/Makefile.am b/Makefile.am index c51193ac92fd..70ded2ec8bc3 100644 --- a/Makefile.am +++ b/Makefile.am @@ -27,7 +27,7 @@ if ETHTOOL_ENABLE_NETLINK ethtool_SOURCES += \ netlink/netlink.c netlink/netlink.h netlink/extapi.h \ netlink/msgbuff.c netlink/msgbuff.h netlink/nlsock.c \ - netlink/nlsock.h \ + netlink/nlsock.h netlink/strset.c netlink/strset.h \ uapi/linux/ethtool_netlink.h \ uapi/linux/netlink.h uapi/linux/genetlink.h \ uapi/linux/rtnetlink.h uapi/linux/if_link.h diff --git a/netlink/netlink.c b/netlink/netlink.c index 7cd7bef6eac9..60f7912181df 100644 --- a/netlink/netlink.c +++ b/netlink/netlink.c @@ -11,6 +11,7 @@ #include "extapi.h" #include "msgbuff.h" #include "nlsock.h" +#include "strset.h" /* Used as reply callback for requests where no reply is expected (e.g. most * "set" type commands) @@ -40,6 +41,57 @@ int attr_cb(const struct nlattr *attr, void *data) return MNL_CB_OK; } +/* misc helpers */ + +const char *get_dev_name(const struct nlattr *nest) +{ + const struct nlattr *tb[ETHTOOL_A_HEADER_MAX + 1] = {}; + DECLARE_ATTR_TB_INFO(tb); + int ret; + + if (!nest) + return NULL; + ret = mnl_attr_parse_nested(nest, attr_cb, &tb_info); + if (ret < 0 || !tb[ETHTOOL_A_HEADER_DEV_NAME]) + return "(none)"; + return mnl_attr_get_str(tb[ETHTOOL_A_HEADER_DEV_NAME]); +} + +int get_dev_info(const struct nlattr *nest, int *ifindex, char *ifname) +{ + const struct nlattr *tb[ETHTOOL_A_HEADER_MAX + 1] = {}; + const struct nlattr *index_attr; + const struct nlattr *name_attr; + DECLARE_ATTR_TB_INFO(tb); + int ret; + + if (ifindex) + *ifindex = 0; + if (ifname) + memset(ifname, '\0', ALTIFNAMSIZ); + + if (!nest) + return -EFAULT; + ret = mnl_attr_parse_nested(nest, attr_cb, &tb_info); + index_attr = tb[ETHTOOL_A_HEADER_DEV_INDEX]; + name_attr = tb[ETHTOOL_A_HEADER_DEV_NAME]; + if (ret < 0 || (ifindex && !index_attr) || (ifname && !name_attr)) + return -EFAULT; + + if (ifindex) + *ifindex = mnl_attr_get_u32(index_attr); + if (ifname) { + strncpy(ifname, mnl_attr_get_str(name_attr), ALTIFNAMSIZ); + if (ifname[ALTIFNAMSIZ - 1]) { + ifname[ALTIFNAMSIZ - 1] = '\0'; + fprintf(stderr, "kernel device name too long: '%s'\n", + mnl_attr_get_str(name_attr)); + return -EFAULT; + } + } + return 0; +} + /* initialization */ struct fam_info { @@ -153,4 +205,5 @@ void netlink_done(struct cmd_context *ctx) free(ctx->nlctx); ctx->nlctx = NULL; + cleanup_all_strings(); } diff --git a/netlink/netlink.h b/netlink/netlink.h index 9ba03b05163f..04ad7bcd347c 100644 --- a/netlink/netlink.h +++ b/netlink/netlink.h @@ -39,6 +39,15 @@ struct attr_tb_info { int nomsg_reply_cb(const struct nlmsghdr *nlhdr, void *data); int attr_cb(const struct nlattr *attr, void *data); +const char *get_dev_name(const struct nlattr *nest); +int get_dev_info(const struct nlattr *nest, int *ifindex, char *ifname); + +static inline void copy_devname(char *dst, const char *src) +{ + strncpy(dst, src, ALTIFNAMSIZ); + dst[ALTIFNAMSIZ - 1] = '\0'; +} + static inline int netlink_init_ethnl2_socket(struct nl_context *nlctx) { if (nlctx->ethnl2_socket) diff --git a/netlink/strset.c b/netlink/strset.c new file mode 100644 index 000000000000..bc468ae5a88e --- /dev/null +++ b/netlink/strset.c @@ -0,0 +1,295 @@ +/* + * strset.c - string set handling + * + * Implementation of local cache of ethtool string sets. + */ + +#include +#include + +#include "../internal.h" +#include "netlink.h" +#include "nlsock.h" +#include "msgbuff.h" + +struct stringset { + const char **strings; + void *raw_data; + unsigned int count; + bool loaded; +}; + +struct perdev_strings { + int ifindex; + char devname[ALTIFNAMSIZ]; + struct stringset strings[ETH_SS_COUNT]; + struct perdev_strings *next; +}; + +/* universal string sets */ +static struct stringset global_strings[ETH_SS_COUNT]; +/* linked list of string sets related to network devices */ +static struct perdev_strings *device_strings; + +static void drop_stringset(struct stringset *set) +{ + if (!set) + return; + + free(set->strings); + free(set->raw_data); + memset(set, 0, sizeof(*set)); +} + +static int import_stringset(struct stringset *dest, const struct nlattr *nest) +{ + const struct nlattr *tb_stringset[ETHTOOL_A_STRINGSET_MAX + 1] = {}; + DECLARE_ATTR_TB_INFO(tb_stringset); + const struct nlattr *string; + unsigned int size; + unsigned int count; + unsigned int idx; + int ret; + + ret = mnl_attr_parse_nested(nest, attr_cb, &tb_stringset_info); + if (ret < 0) + return ret; + if (!tb_stringset[ETHTOOL_A_STRINGSET_ID] || + !tb_stringset[ETHTOOL_A_STRINGSET_COUNT] || + !tb_stringset[ETHTOOL_A_STRINGSET_STRINGS]) + return -EFAULT; + idx = mnl_attr_get_u32(tb_stringset[ETHTOOL_A_STRINGSET_ID]); + if (idx >= ETH_SS_COUNT) + return 0; + if (dest[idx].loaded) + drop_stringset(&dest[idx]); + dest[idx].loaded = true; + count = mnl_attr_get_u32(tb_stringset[ETHTOOL_A_STRINGSET_COUNT]); + if (count == 0) + return 0; + + size = mnl_attr_get_len(tb_stringset[ETHTOOL_A_STRINGSET_STRINGS]); + ret = -ENOMEM; + dest[idx].raw_data = malloc(size); + if (!dest[idx].raw_data) + goto err; + memcpy(dest[idx].raw_data, tb_stringset[ETHTOOL_A_STRINGSET_STRINGS], + size); + dest[idx].strings = calloc(count, sizeof(dest[idx].strings[0])); + if (!dest[idx].strings) + goto err; + dest[idx].count = count; + + nest = dest[idx].raw_data; + mnl_attr_for_each_nested(string, nest) { + const struct nlattr *tb[ETHTOOL_A_STRING_MAX + 1] = {}; + DECLARE_ATTR_TB_INFO(tb); + unsigned int i; + + if (mnl_attr_get_type(string) != ETHTOOL_A_STRINGS_STRING) + continue; + ret = mnl_attr_parse_nested(string, attr_cb, &tb_info); + if (ret < 0) + goto err; + ret = -EFAULT; + if (!tb[ETHTOOL_A_STRING_INDEX] || !tb[ETHTOOL_A_STRING_VALUE]) + goto err; + + i = mnl_attr_get_u32(tb[ETHTOOL_A_STRING_INDEX]); + if (i >= count) + goto err; + dest[idx].strings[i] = + mnl_attr_get_payload(tb[ETHTOOL_A_STRING_VALUE]); + } + + return 0; +err: + drop_stringset(&dest[idx]); + return ret; +} + +static struct perdev_strings *get_perdev_by_ifindex(int ifindex) +{ + struct perdev_strings *perdev = device_strings; + + while (perdev && perdev->ifindex != ifindex) + perdev = perdev->next; + if (perdev) + return perdev; + + /* not found, allocate and insert into list */ + perdev = calloc(sizeof(*perdev), 1); + if (!perdev) + return NULL; + perdev->ifindex = ifindex; + perdev->next = device_strings; + device_strings = perdev; + + return perdev; +} + +static int strset_reply_cb(const struct nlmsghdr *nlhdr, void *data) +{ + const struct nlattr *tb[ETHTOOL_A_STRSET_MAX + 1] = {}; + DECLARE_ATTR_TB_INFO(tb); + struct nl_context *nlctx = data; + char devname[ALTIFNAMSIZ] = ""; + struct stringset *dest; + struct nlattr *attr; + int ifindex = 0; + int ret; + + ret = mnl_attr_parse(nlhdr, GENL_HDRLEN, attr_cb, &tb_info); + if (ret < 0) + return ret; + if (tb[ETHTOOL_A_STRSET_HEADER]) { + ret = get_dev_info(tb[ETHTOOL_A_STRSET_HEADER], &ifindex, + devname); + if (ret < 0) + return MNL_CB_OK; + nlctx->devname = devname; + } + + if (ifindex) { + struct perdev_strings *perdev; + + perdev = get_perdev_by_ifindex(ifindex); + if (!perdev) + return MNL_CB_OK; + copy_devname(perdev->devname, devname); + dest = perdev->strings; + } else { + dest = global_strings; + } + + if (!tb[ETHTOOL_A_STRSET_STRINGSETS]) + return MNL_CB_OK; + mnl_attr_for_each_nested(attr, tb[ETHTOOL_A_STRSET_STRINGSETS]) { + if (mnl_attr_get_type(attr) == + ETHTOOL_A_STRINGSETS_STRINGSET) + import_stringset(dest, attr); + } + + return MNL_CB_OK; +} + +static int fill_stringset_id(struct nl_msg_buff *msgbuff, unsigned int type) +{ + struct nlattr *nest_sets; + struct nlattr *nest_set; + + nest_sets = ethnla_nest_start(msgbuff, ETHTOOL_A_STRSET_STRINGSETS); + if (!nest_sets) + return -EMSGSIZE; + nest_set = ethnla_nest_start(msgbuff, ETHTOOL_A_STRINGSETS_STRINGSET); + if (!nest_set) + goto err; + if (ethnla_put_u32(msgbuff, ETHTOOL_A_STRINGSET_ID, type)) + goto err; + ethnla_nest_end(msgbuff, nest_set); + ethnla_nest_end(msgbuff, nest_sets); + return 0; + +err: + ethnla_nest_cancel(msgbuff, nest_sets); + return -EMSGSIZE; +} + +static int stringset_load_request(struct nl_socket *nlsk, const char *devname, + int type, bool is_dump) +{ + struct nl_msg_buff *msgbuff = &nlsk->msgbuff; + int ret; + + ret = msg_init(nlsk->nlctx, msgbuff, ETHTOOL_MSG_STRSET_GET, + NLM_F_REQUEST | NLM_F_ACK | (is_dump ? NLM_F_DUMP : 0)); + if (ret < 0) + return ret; + if (ethnla_fill_header(msgbuff, ETHTOOL_A_STRSET_HEADER, devname, 0)) + return -EMSGSIZE; + if (type >= 0) { + ret = fill_stringset_id(msgbuff, type); + if (ret < 0) + return ret; + } + + ret = nlsock_send_get_request(nlsk, strset_reply_cb); + return ret; +} + +/* interface */ + +const struct stringset *global_stringset(unsigned int type, + struct nl_socket *nlsk) +{ + int ret; + + if (type >= ETH_SS_COUNT) + return NULL; + if (global_strings[type].loaded) + return &global_strings[type]; + ret = stringset_load_request(nlsk, NULL, type, false); + return ret < 0 ? NULL : &global_strings[type]; +} + +const struct stringset *perdev_stringset(const char *devname, unsigned int type, + struct nl_socket *nlsk) +{ + const struct perdev_strings *p; + int ret; + + if (type >= ETH_SS_COUNT) + return NULL; + for (p = device_strings; p; p = p->next) + if (!strcmp(p->devname, devname)) + return &p->strings[type]; + + ret = stringset_load_request(nlsk, devname, type, false); + if (ret < 0) + return NULL; + for (p = device_strings; p; p = p->next) + if (!strcmp(p->devname, devname)) + return &p->strings[type]; + + return NULL; +} + +unsigned int get_count(const struct stringset *set) +{ + return set->count; +} + +const char *get_string(const struct stringset *set, unsigned int idx) +{ + if (!set || idx >= set->count) + return NULL; + return set->strings[idx]; +} + +int preload_global_strings(struct nl_socket *nlsk) +{ + return stringset_load_request(nlsk, NULL, -1, false); +} + +int preload_perdev_strings(struct nl_socket *nlsk, const char *dev) +{ + return stringset_load_request(nlsk, dev, -1, !dev); +} + +void cleanup_all_strings(void) +{ + struct perdev_strings *perdev; + unsigned int i; + + for (i = 0; i < ETH_SS_COUNT; i++) + drop_stringset(&global_strings[i]); + + perdev = device_strings; + while (perdev) { + device_strings = perdev->next; + for (i = 0; i < ETH_SS_COUNT; i++) + drop_stringset(&perdev->strings[i]); + free(perdev); + perdev = device_strings; + } +} diff --git a/netlink/strset.h b/netlink/strset.h new file mode 100644 index 000000000000..72a4a3929244 --- /dev/null +++ b/netlink/strset.h @@ -0,0 +1,25 @@ +/* + * strset.h - string set handling + * + * Interface for local cache of ethtool string sets. + */ + +#ifndef ETHTOOL_NETLINK_STRSET_H__ +#define ETHTOOL_NETLINK_STRSET_H__ + +struct nl_socket; +struct stringset; + +const struct stringset *global_stringset(unsigned int type, + struct nl_socket *nlsk); +const struct stringset *perdev_stringset(const char *dev, unsigned int type, + struct nl_socket *nlsk); + +unsigned int get_count(const struct stringset *set); +const char *get_string(const struct stringset *set, unsigned int idx); + +int preload_global_strings(struct nl_socket *nlsk); +int preload_perdev_strings(struct nl_socket *nlsk, const char *dev); +void cleanup_all_strings(void); + +#endif /* ETHTOOL_NETLINK_STRSET_H__ */ From patchwork Fri Mar 6 17:05:00 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Michal Kubecek X-Patchwork-Id: 222921 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.8 required=3.0 tests=HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SIGNED_OFF_BY, SPF_HELO_NONE, SPF_PASS autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 80C40C10DCE for ; Fri, 6 Mar 2020 17:05:05 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 5438D206E2 for ; Fri, 6 Mar 2020 17:05:05 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727152AbgCFRFE (ORCPT ); Fri, 6 Mar 2020 12:05:04 -0500 Received: from mx2.suse.de ([195.135.220.15]:43624 "EHLO mx2.suse.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726300AbgCFRFE (ORCPT ); Fri, 6 Mar 2020 12:05:04 -0500 X-Virus-Scanned: by amavisd-new at test-mx.suse.de Received: from relay2.suse.de (unknown [195.135.220.254]) by mx2.suse.de (Postfix) with ESMTP id 55EA4B35E; Fri, 6 Mar 2020 17:05:00 +0000 (UTC) Received: by unicorn.suse.cz (Postfix, from userid 1000) id 05DC5E00E7; Fri, 6 Mar 2020 18:05:00 +0100 (CET) Message-Id: In-Reply-To: References: From: Michal Kubecek Subject: [PATCH ethtool v3 12/25] move shared code into a common file To: John Linville , netdev@vger.kernel.org Cc: Andrew Lunn , Florian Fainelli Date: Fri, 6 Mar 2020 18:05:00 +0100 (CET) Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org Move code which is going to be shared between ioctl and netlink implementation into a common file common.c and declarations into header file common.h. Signed-off-by: Michal Kubecek --- Makefile.am | 2 +- common.c | 145 +++++++++++++++++++++++++++++++++++++++++++++++++ common.h | 26 +++++++++ ethtool.c | 151 +++------------------------------------------------- 4 files changed, 179 insertions(+), 145 deletions(-) create mode 100644 common.c create mode 100644 common.h diff --git a/Makefile.am b/Makefile.am index 2985ce533ed3..e6abd3f79cd7 100644 --- a/Makefile.am +++ b/Makefile.am @@ -7,7 +7,7 @@ EXTRA_DIST = LICENSE ethtool.8 ethtool.spec.in aclocal.m4 ChangeLog autogen.sh sbin_PROGRAMS = ethtool ethtool_SOURCES = ethtool.c uapi/linux/ethtool.h internal.h \ - uapi/linux/net_tstamp.h rxclass.c + uapi/linux/net_tstamp.h rxclass.c common.c common.h if ETHTOOL_ENABLE_PRETTY_DUMP ethtool_SOURCES += \ amd8111e.c de2104x.c dsa.c e100.c e1000.c et131x.c igb.c \ diff --git a/common.c b/common.c new file mode 100644 index 000000000000..f9c41a32d3a3 --- /dev/null +++ b/common.c @@ -0,0 +1,145 @@ +/* + * common.h - common code header + * + * Data and functions shared by ioctl and netlink implementation. + */ + +#include "internal.h" +#include "common.h" + +#ifndef HAVE_NETIF_MSG +enum { + NETIF_MSG_DRV = 0x0001, + NETIF_MSG_PROBE = 0x0002, + NETIF_MSG_LINK = 0x0004, + NETIF_MSG_TIMER = 0x0008, + NETIF_MSG_IFDOWN = 0x0010, + NETIF_MSG_IFUP = 0x0020, + NETIF_MSG_RX_ERR = 0x0040, + NETIF_MSG_TX_ERR = 0x0080, + NETIF_MSG_TX_QUEUED = 0x0100, + NETIF_MSG_INTR = 0x0200, + NETIF_MSG_TX_DONE = 0x0400, + NETIF_MSG_RX_STATUS = 0x0800, + NETIF_MSG_PKTDATA = 0x1000, + NETIF_MSG_HW = 0x2000, + NETIF_MSG_WOL = 0x4000, +}; +#endif + +const struct flag_info flags_msglvl[] = { + { "drv", NETIF_MSG_DRV }, + { "probe", NETIF_MSG_PROBE }, + { "link", NETIF_MSG_LINK }, + { "timer", NETIF_MSG_TIMER }, + { "ifdown", NETIF_MSG_IFDOWN }, + { "ifup", NETIF_MSG_IFUP }, + { "rx_err", NETIF_MSG_RX_ERR }, + { "tx_err", NETIF_MSG_TX_ERR }, + { "tx_queued", NETIF_MSG_TX_QUEUED }, + { "intr", NETIF_MSG_INTR }, + { "tx_done", NETIF_MSG_TX_DONE }, + { "rx_status", NETIF_MSG_RX_STATUS }, + { "pktdata", NETIF_MSG_PKTDATA }, + { "hw", NETIF_MSG_HW }, + { "wol", NETIF_MSG_WOL }, + {} +}; +const unsigned int n_flags_msglvl = ARRAY_SIZE(flags_msglvl) - 1; + +void print_flags(const struct flag_info *info, unsigned int n_info, u32 value) +{ + const char *sep = ""; + + while (n_info) { + if (value & info->value) { + printf("%s%s", sep, info->name); + sep = " "; + value &= ~info->value; + } + ++info; + --n_info; + } + + /* Print any unrecognised flags in hex */ + if (value) + printf("%s%#x", sep, value); +} + +static char *unparse_wolopts(int wolopts) +{ + static char buf[16]; + char *p = buf; + + memset(buf, 0, sizeof(buf)); + + if (wolopts) { + if (wolopts & WAKE_PHY) + *p++ = 'p'; + if (wolopts & WAKE_UCAST) + *p++ = 'u'; + if (wolopts & WAKE_MCAST) + *p++ = 'm'; + if (wolopts & WAKE_BCAST) + *p++ = 'b'; + if (wolopts & WAKE_ARP) + *p++ = 'a'; + if (wolopts & WAKE_MAGIC) + *p++ = 'g'; + if (wolopts & WAKE_MAGICSECURE) + *p++ = 's'; + if (wolopts & WAKE_FILTER) + *p++ = 'f'; + } else { + *p = 'd'; + } + + return buf; +} + +int dump_wol(struct ethtool_wolinfo *wol) +{ + fprintf(stdout, " Supports Wake-on: %s\n", + unparse_wolopts(wol->supported)); + fprintf(stdout, " Wake-on: %s\n", + unparse_wolopts(wol->wolopts)); + if (wol->supported & WAKE_MAGICSECURE) { + int i; + int delim = 0; + + fprintf(stdout, " SecureOn password: "); + for (i = 0; i < SOPASS_MAX; i++) { + fprintf(stdout, "%s%02x", delim ? ":" : "", + wol->sopass[i]); + delim = 1; + } + fprintf(stdout, "\n"); + } + + return 0; +} + +void dump_mdix(u8 mdix, u8 mdix_ctrl) +{ + fprintf(stdout, " MDI-X: "); + if (mdix_ctrl == ETH_TP_MDI) { + fprintf(stdout, "off (forced)\n"); + } else if (mdix_ctrl == ETH_TP_MDI_X) { + fprintf(stdout, "on (forced)\n"); + } else { + switch (mdix) { + case ETH_TP_MDI: + fprintf(stdout, "off"); + break; + case ETH_TP_MDI_X: + fprintf(stdout, "on"); + break; + default: + fprintf(stdout, "Unknown"); + break; + } + if (mdix_ctrl == ETH_TP_MDI_AUTO) + fprintf(stdout, " (auto)"); + fprintf(stdout, "\n"); + } +} diff --git a/common.h b/common.h new file mode 100644 index 000000000000..3a680114a7c2 --- /dev/null +++ b/common.h @@ -0,0 +1,26 @@ +/* + * common.h - common code header + * + * Declarations for data and functions shared by ioctl and netlink code. + */ + +#ifndef ETHTOOL_COMMON_H__ +#define ETHTOOL_COMMON_H__ + +#include "internal.h" + +#define KERNEL_VERSION(a, b, c) (((a) << 16) + ((b) << 8) + (c)) + +struct flag_info { + const char *name; + u32 value; +}; + +extern const struct flag_info flags_msglvl[]; +extern const unsigned int n_flags_msglvl; + +void print_flags(const struct flag_info *info, unsigned int n_info, u32 value); +int dump_wol(struct ethtool_wolinfo *wol); +void dump_mdix(u8 mdix, u8 mdix_ctrl); + +#endif /* ETHTOOL_COMMON_H__ */ diff --git a/ethtool.c b/ethtool.c index 97eaa58a3090..c2b7cc8c0502 100644 --- a/ethtool.c +++ b/ethtool.c @@ -48,32 +48,13 @@ #include #include +#include "common.h" #include "netlink/extapi.h" #ifndef MAX_ADDR_LEN #define MAX_ADDR_LEN 32 #endif -#ifndef HAVE_NETIF_MSG -enum { - NETIF_MSG_DRV = 0x0001, - NETIF_MSG_PROBE = 0x0002, - NETIF_MSG_LINK = 0x0004, - NETIF_MSG_TIMER = 0x0008, - NETIF_MSG_IFDOWN = 0x0010, - NETIF_MSG_IFUP = 0x0020, - NETIF_MSG_RX_ERR = 0x0040, - NETIF_MSG_TX_ERR = 0x0080, - NETIF_MSG_TX_QUEUED = 0x0100, - NETIF_MSG_INTR = 0x0200, - NETIF_MSG_TX_DONE = 0x0400, - NETIF_MSG_RX_STATUS = 0x0800, - NETIF_MSG_PKTDATA = 0x1000, - NETIF_MSG_HW = 0x2000, - NETIF_MSG_WOL = 0x4000, -}; -#endif - #ifndef NETLINK_GENERIC #define NETLINK_GENERIC 16 #endif @@ -121,29 +102,6 @@ struct cmdline_info { void *seen_val; }; -struct flag_info { - const char *name; - u32 value; -}; - -static const struct flag_info flags_msglvl[] = { - { "drv", NETIF_MSG_DRV }, - { "probe", NETIF_MSG_PROBE }, - { "link", NETIF_MSG_LINK }, - { "timer", NETIF_MSG_TIMER }, - { "ifdown", NETIF_MSG_IFDOWN }, - { "ifup", NETIF_MSG_IFUP }, - { "rx_err", NETIF_MSG_RX_ERR }, - { "tx_err", NETIF_MSG_TX_ERR }, - { "tx_queued", NETIF_MSG_TX_QUEUED }, - { "intr", NETIF_MSG_INTR }, - { "tx_done", NETIF_MSG_TX_DONE }, - { "rx_status", NETIF_MSG_RX_STATUS }, - { "pktdata", NETIF_MSG_PKTDATA }, - { "hw", NETIF_MSG_HW }, - { "wol", NETIF_MSG_WOL }, -}; - struct off_flag_def { const char *short_name; const char *long_name; @@ -426,26 +384,6 @@ static void flag_to_cmdline_info(const char *name, u32 value, cli->seen_val = mask; } -static void -print_flags(const struct flag_info *info, unsigned int n_info, u32 value) -{ - const char *sep = ""; - - while (n_info) { - if (value & info->value) { - printf("%s%s", sep, info->name); - sep = " "; - value &= ~info->value; - } - ++info; - --n_info; - } - - /* Print any unrecognised flags in hex */ - if (value) - printf("%s%#x", sep, value); -} - static int rxflow_str_to_type(const char *str) { int flow_type = 0; @@ -904,31 +842,9 @@ dump_link_usettings(const struct ethtool_link_usettings *link_usettings) (link_usettings->base.autoneg == AUTONEG_DISABLE) ? "off" : "on"); - if (link_usettings->base.port == PORT_TP) { - fprintf(stdout, " MDI-X: "); - if (link_usettings->base.eth_tp_mdix_ctrl == ETH_TP_MDI) { - fprintf(stdout, "off (forced)\n"); - } else if (link_usettings->base.eth_tp_mdix_ctrl - == ETH_TP_MDI_X) { - fprintf(stdout, "on (forced)\n"); - } else { - switch (link_usettings->base.eth_tp_mdix) { - case ETH_TP_MDI: - fprintf(stdout, "off"); - break; - case ETH_TP_MDI_X: - fprintf(stdout, "on"); - break; - default: - fprintf(stdout, "Unknown"); - break; - } - if (link_usettings->base.eth_tp_mdix_ctrl - == ETH_TP_MDI_AUTO) - fprintf(stdout, " (auto)"); - fprintf(stdout, "\n"); - } - } + if (link_usettings->base.port == PORT_TP) + dump_mdix(link_usettings->base.eth_tp_mdix, + link_usettings->base.eth_tp_mdix_ctrl); return 0; } @@ -1000,58 +916,6 @@ static int parse_wolopts(char *optstr, u32 *data) return 0; } -static char *unparse_wolopts(int wolopts) -{ - static char buf[16]; - char *p = buf; - - memset(buf, 0, sizeof(buf)); - - if (wolopts) { - if (wolopts & WAKE_PHY) - *p++ = 'p'; - if (wolopts & WAKE_UCAST) - *p++ = 'u'; - if (wolopts & WAKE_MCAST) - *p++ = 'm'; - if (wolopts & WAKE_BCAST) - *p++ = 'b'; - if (wolopts & WAKE_ARP) - *p++ = 'a'; - if (wolopts & WAKE_MAGIC) - *p++ = 'g'; - if (wolopts & WAKE_MAGICSECURE) - *p++ = 's'; - if (wolopts & WAKE_FILTER) - *p++ = 'f'; - } else { - *p = 'd'; - } - - return buf; -} - -static int dump_wol(struct ethtool_wolinfo *wol) -{ - fprintf(stdout, " Supports Wake-on: %s\n", - unparse_wolopts(wol->supported)); - fprintf(stdout, " Wake-on: %s\n", - unparse_wolopts(wol->wolopts)); - if (wol->supported & WAKE_MAGICSECURE) { - int i; - int delim = 0; - - fprintf(stdout, " SecureOn password: "); - for (i = 0; i < SOPASS_MAX; i++) { - fprintf(stdout, "%s%02x", delim?":":"", wol->sopass[i]); - delim = 1; - } - fprintf(stdout, "\n"); - } - - return 0; -} - static int parse_rxfhashopts(char *optstr, u32 *data) { *data = 0; @@ -2839,8 +2703,7 @@ static int do_gset(struct cmd_context *ctx) fprintf(stdout, " Current message level: 0x%08x (%d)\n" " ", edata.data, edata.data); - print_flags(flags_msglvl, ARRAY_SIZE(flags_msglvl), - edata.data); + print_flags(flags_msglvl, n_flags_msglvl, edata.data); fprintf(stdout, "\n"); allfail = 0; } else if (errno != EOPNOTSUPP) { @@ -2886,13 +2749,13 @@ static int do_sset(struct cmd_context *ctx) int msglvl_changed = 0; u32 msglvl_wanted = 0; u32 msglvl_mask = 0; - struct cmdline_info cmdline_msglvl[ARRAY_SIZE(flags_msglvl)]; + struct cmdline_info cmdline_msglvl[n_flags_msglvl]; int argc = ctx->argc; char **argp = ctx->argp; int i; int err = 0; - for (i = 0; i < ARRAY_SIZE(flags_msglvl); i++) + for (i = 0; i < n_flags_msglvl; i++) flag_to_cmdline_info(flags_msglvl[i].name, flags_msglvl[i].value, &msglvl_wanted, &msglvl_mask, From patchwork Fri Mar 6 17:05:10 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Michal Kubecek X-Patchwork-Id: 222920 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.8 required=3.0 tests=HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SIGNED_OFF_BY, SPF_HELO_NONE, SPF_PASS autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id CC1C2C10DCE for ; Fri, 6 Mar 2020 17:05:17 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 9997D206E2 for ; Fri, 6 Mar 2020 17:05:17 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727180AbgCFRFR (ORCPT ); Fri, 6 Mar 2020 12:05:17 -0500 Received: from mx2.suse.de ([195.135.220.15]:43684 "EHLO mx2.suse.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726299AbgCFRFQ (ORCPT ); Fri, 6 Mar 2020 12:05:16 -0500 X-Virus-Scanned: by amavisd-new at test-mx.suse.de Received: from relay2.suse.de (unknown [195.135.220.254]) by mx2.suse.de (Postfix) with ESMTP id 69616B216; Fri, 6 Mar 2020 17:05:10 +0000 (UTC) Received: by unicorn.suse.cz (Postfix, from userid 1000) id 136C6E00E7; Fri, 6 Mar 2020 18:05:10 +0100 (CET) Message-Id: <5cdb94b000c60287e8dfffa20926329f18199128.1583513281.git.mkubecek@suse.cz> In-Reply-To: References: From: Michal Kubecek Subject: [PATCH ethtool v3 14/25] netlink: partial netlink handler for gset (no option) To: John Linville , netdev@vger.kernel.org Cc: Andrew Lunn , Florian Fainelli Date: Fri, 6 Mar 2020 18:05:10 +0100 (CET) Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org Partially implement "ethtool " subcommand. This commit retrieves and displays information provided by ETHTOOL_MSG_LINKINFO_GET, ETHTOOL_MSG_LINKMODES_GET and ETHTOOL_MSG_LINKSTATE_GET netlink requests, i.e. everything except wake-on-lan and debugging (msglevel). Also register the callbacks in monitor so that corresponding notifications can be displayed with "ethtool --monitor". v2: - print banner only once unless monitor or wildcard (dump request) - suppress error messages for -EOPNOTSUPP responses - only show "No data available" if there is no reply at all - more readable nl_gset() v3: - fix gcc9 compiler warning Signed-off-by: Michal Kubecek --- Makefile.am | 1 + ethtool.c | 1 + netlink/extapi.h | 3 + netlink/monitor.c | 16 ++ netlink/netlink.h | 4 + netlink/settings.c | 647 +++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 672 insertions(+) create mode 100644 netlink/settings.c diff --git a/Makefile.am b/Makefile.am index 616c45007fbd..eeb36a279045 100644 --- a/Makefile.am +++ b/Makefile.am @@ -29,6 +29,7 @@ ethtool_SOURCES += \ netlink/msgbuff.c netlink/msgbuff.h netlink/nlsock.c \ netlink/nlsock.h netlink/strset.c netlink/strset.h \ netlink/monitor.c netlink/bitset.c netlink/bitset.h \ + netlink/settings.c \ uapi/linux/ethtool_netlink.h \ uapi/linux/netlink.h uapi/linux/genetlink.h \ uapi/linux/rtnetlink.h uapi/linux/if_link.h diff --git a/ethtool.c b/ethtool.c index c2b7cc8c0502..a69233bd73fc 100644 --- a/ethtool.c +++ b/ethtool.c @@ -5805,6 +5805,7 @@ int main(int argc, char **argp) } if ((*argp)[0] == '-') exit_bad_args(); + nlfunc = nl_gset; func = do_gset; no_dev = false; diff --git a/netlink/extapi.h b/netlink/extapi.h index 1d5b68226af4..8608ea7f51f5 100644 --- a/netlink/extapi.h +++ b/netlink/extapi.h @@ -15,6 +15,7 @@ struct nl_context; int netlink_init(struct cmd_context *ctx); void netlink_done(struct cmd_context *ctx); +int nl_gset(struct cmd_context *ctx); int nl_monitor(struct cmd_context *ctx); void nl_monitor_usage(void); @@ -34,6 +35,8 @@ static inline void nl_monitor_usage(void) { } +#define nl_gset NULL + #endif /* ETHTOOL_ENABLE_NETLINK */ #endif /* ETHTOOL_EXTAPI_H__ */ diff --git a/netlink/monitor.c b/netlink/monitor.c index 300fd5bc2e51..e8fdcd2b93ef 100644 --- a/netlink/monitor.c +++ b/netlink/monitor.c @@ -15,6 +15,14 @@ static struct { uint8_t cmd; mnl_cb_t cb; } monitor_callbacks[] = { + { + .cmd = ETHTOOL_MSG_LINKMODES_NTF, + .cb = linkmodes_reply_cb, + }, + { + .cmd = ETHTOOL_MSG_LINKINFO_NTF, + .cb = linkinfo_reply_cb, + }, }; static void clear_filter(struct nl_context *nlctx) @@ -70,6 +78,14 @@ static struct monitor_option monitor_opts[] = { .pattern = "|--all", .cmd = 0, }, + { + .pattern = "-s|--change", + .cmd = ETHTOOL_MSG_LINKINFO_NTF, + }, + { + .pattern = "-s|--change", + .cmd = ETHTOOL_MSG_LINKMODES_NTF, + }, }; static bool pattern_match(const char *s, const char *pattern) diff --git a/netlink/netlink.h b/netlink/netlink.h index be44f9c16f19..16754899976d 100644 --- a/netlink/netlink.h +++ b/netlink/netlink.h @@ -30,6 +30,7 @@ struct nl_context { bool is_monitor; uint32_t filter_cmds[CMDMASK_WORDS]; const char *filter_devname; + bool no_banner; }; struct attr_tb_info { @@ -46,6 +47,9 @@ int attr_cb(const struct nlattr *attr, void *data); const char *get_dev_name(const struct nlattr *nest); int get_dev_info(const struct nlattr *nest, int *ifindex, char *ifname); +int linkmodes_reply_cb(const struct nlmsghdr *nlhdr, void *data); +int linkinfo_reply_cb(const struct nlmsghdr *nlhdr, void *data); + static inline void copy_devname(char *dst, const char *src) { strncpy(dst, src, ALTIFNAMSIZ); diff --git a/netlink/settings.c b/netlink/settings.c new file mode 100644 index 000000000000..25d0f02210b5 --- /dev/null +++ b/netlink/settings.c @@ -0,0 +1,647 @@ +/* + * settings.c - netlink implementation of settings commands + * + * Implementation of "ethtool " and "ethtool -s ...". + */ + +#include +#include +#include + +#include "../internal.h" +#include "../common.h" +#include "netlink.h" +#include "strset.h" +#include "bitset.h" + +/* GET_SETTINGS */ + +enum link_mode_class { + LM_CLASS_UNKNOWN, + LM_CLASS_REAL, + LM_CLASS_AUTONEG, + LM_CLASS_PORT, + LM_CLASS_PAUSE, + LM_CLASS_FEC, +}; + +struct link_mode_info { + enum link_mode_class class; + u32 speed; + u8 duplex; +}; + +static const char *const names_duplex[] = { + [DUPLEX_HALF] = "Half", + [DUPLEX_FULL] = "Full", +}; + +static const char *const names_port[] = { + [PORT_TP] = "Twisted Pair", + [PORT_AUI] = "AUI", + [PORT_BNC] = "BNC", + [PORT_MII] = "MII", + [PORT_FIBRE] = "FIBRE", + [PORT_DA] = "Direct Attach Copper", + [PORT_NONE] = "None", + [PORT_OTHER] = "Other", +}; + +static const char *const names_transceiver[] = { + [XCVR_INTERNAL] = "internal", + [XCVR_EXTERNAL] = "external", +}; + +/* the practice of putting completely unrelated flags into link mode bitmaps + * is rather unfortunate but as even ethtool_link_ksettings preserved that, + * there is little chance of getting them separated any time soon so let's + * sort them out ourselves + */ +static const struct link_mode_info link_modes[] = { + [ETHTOOL_LINK_MODE_10baseT_Half_BIT] = + { LM_CLASS_REAL, 10, DUPLEX_HALF }, + [ETHTOOL_LINK_MODE_10baseT_Full_BIT] = + { LM_CLASS_REAL, 10, DUPLEX_FULL }, + [ETHTOOL_LINK_MODE_100baseT_Half_BIT] = + { LM_CLASS_REAL, 100, DUPLEX_HALF }, + [ETHTOOL_LINK_MODE_100baseT_Full_BIT] = + { LM_CLASS_REAL, 100, DUPLEX_FULL }, + [ETHTOOL_LINK_MODE_1000baseT_Half_BIT] = + { LM_CLASS_REAL, 1000, DUPLEX_HALF }, + [ETHTOOL_LINK_MODE_1000baseT_Full_BIT] = + { LM_CLASS_REAL, 1000, DUPLEX_FULL }, + [ETHTOOL_LINK_MODE_Autoneg_BIT] = + { LM_CLASS_AUTONEG }, + [ETHTOOL_LINK_MODE_TP_BIT] = + { LM_CLASS_PORT }, + [ETHTOOL_LINK_MODE_AUI_BIT] = + { LM_CLASS_PORT }, + [ETHTOOL_LINK_MODE_MII_BIT] = + { LM_CLASS_PORT }, + [ETHTOOL_LINK_MODE_FIBRE_BIT] = + { LM_CLASS_PORT }, + [ETHTOOL_LINK_MODE_BNC_BIT] = + { LM_CLASS_PORT }, + [ETHTOOL_LINK_MODE_10000baseT_Full_BIT] = + { LM_CLASS_REAL, 10000, DUPLEX_FULL }, + [ETHTOOL_LINK_MODE_Pause_BIT] = + { LM_CLASS_PAUSE }, + [ETHTOOL_LINK_MODE_Asym_Pause_BIT] = + { LM_CLASS_PAUSE }, + [ETHTOOL_LINK_MODE_2500baseX_Full_BIT] = + { LM_CLASS_REAL, 2500, DUPLEX_FULL }, + [ETHTOOL_LINK_MODE_Backplane_BIT] = + { LM_CLASS_PORT }, + [ETHTOOL_LINK_MODE_1000baseKX_Full_BIT] = + { LM_CLASS_REAL, 1000, DUPLEX_FULL }, + [ETHTOOL_LINK_MODE_10000baseKX4_Full_BIT] = + { LM_CLASS_REAL, 10000, DUPLEX_FULL }, + [ETHTOOL_LINK_MODE_10000baseKR_Full_BIT] = + { LM_CLASS_REAL, 10000, DUPLEX_FULL }, + [ETHTOOL_LINK_MODE_10000baseR_FEC_BIT] = + { LM_CLASS_REAL, 10000, DUPLEX_FULL }, + [ETHTOOL_LINK_MODE_20000baseMLD2_Full_BIT] = + { LM_CLASS_REAL, 20000, DUPLEX_FULL }, + [ETHTOOL_LINK_MODE_20000baseKR2_Full_BIT] = + { LM_CLASS_REAL, 20000, DUPLEX_FULL }, + [ETHTOOL_LINK_MODE_40000baseKR4_Full_BIT] = + { LM_CLASS_REAL, 40000, DUPLEX_FULL }, + [ETHTOOL_LINK_MODE_40000baseCR4_Full_BIT] = + { LM_CLASS_REAL, 40000, DUPLEX_FULL }, + [ETHTOOL_LINK_MODE_40000baseSR4_Full_BIT] = + { LM_CLASS_REAL, 40000, DUPLEX_FULL }, + [ETHTOOL_LINK_MODE_40000baseLR4_Full_BIT] = + { LM_CLASS_REAL, 40000, DUPLEX_FULL }, + [ETHTOOL_LINK_MODE_56000baseKR4_Full_BIT] = + { LM_CLASS_REAL, 56000, DUPLEX_FULL }, + [ETHTOOL_LINK_MODE_56000baseCR4_Full_BIT] = + { LM_CLASS_REAL, 56000, DUPLEX_FULL }, + [ETHTOOL_LINK_MODE_56000baseSR4_Full_BIT] = + { LM_CLASS_REAL, 56000, DUPLEX_FULL }, + [ETHTOOL_LINK_MODE_56000baseLR4_Full_BIT] = + { LM_CLASS_REAL, 56000, DUPLEX_FULL }, + [ETHTOOL_LINK_MODE_25000baseCR_Full_BIT] = + { LM_CLASS_REAL, 25000, DUPLEX_FULL }, + [ETHTOOL_LINK_MODE_25000baseKR_Full_BIT] = + { LM_CLASS_REAL, 25000, DUPLEX_FULL }, + [ETHTOOL_LINK_MODE_25000baseSR_Full_BIT] = + { LM_CLASS_REAL, 25000, DUPLEX_FULL }, + [ETHTOOL_LINK_MODE_50000baseCR2_Full_BIT] = + { LM_CLASS_REAL, 50000, DUPLEX_FULL }, + [ETHTOOL_LINK_MODE_50000baseKR2_Full_BIT] = + { LM_CLASS_REAL, 50000, DUPLEX_FULL }, + [ETHTOOL_LINK_MODE_100000baseKR4_Full_BIT] = + { LM_CLASS_REAL, 100000, DUPLEX_FULL }, + [ETHTOOL_LINK_MODE_100000baseSR4_Full_BIT] = + { LM_CLASS_REAL, 100000, DUPLEX_FULL }, + [ETHTOOL_LINK_MODE_100000baseCR4_Full_BIT] = + { LM_CLASS_REAL, 100000, DUPLEX_FULL }, + [ETHTOOL_LINK_MODE_100000baseLR4_ER4_Full_BIT] = + { LM_CLASS_REAL, 100000, DUPLEX_FULL }, + [ETHTOOL_LINK_MODE_50000baseSR2_Full_BIT] = + { LM_CLASS_REAL, 50000, DUPLEX_FULL }, + [ETHTOOL_LINK_MODE_1000baseX_Full_BIT] = + { LM_CLASS_REAL, 1000, DUPLEX_FULL }, + [ETHTOOL_LINK_MODE_10000baseCR_Full_BIT] = + { LM_CLASS_REAL, 10000, DUPLEX_FULL }, + [ETHTOOL_LINK_MODE_10000baseSR_Full_BIT] = + { LM_CLASS_REAL, 10000, DUPLEX_FULL }, + [ETHTOOL_LINK_MODE_10000baseLR_Full_BIT] = + { LM_CLASS_REAL, 10000, DUPLEX_FULL }, + [ETHTOOL_LINK_MODE_10000baseLRM_Full_BIT] = + { LM_CLASS_REAL, 10000, DUPLEX_FULL }, + [ETHTOOL_LINK_MODE_10000baseER_Full_BIT] = + { LM_CLASS_REAL, 10000, DUPLEX_FULL }, + [ETHTOOL_LINK_MODE_2500baseT_Full_BIT] = + { LM_CLASS_REAL, 2500, DUPLEX_FULL }, + [ETHTOOL_LINK_MODE_5000baseT_Full_BIT] = + { LM_CLASS_REAL, 5000, DUPLEX_FULL }, + [ETHTOOL_LINK_MODE_FEC_NONE_BIT] = + { LM_CLASS_FEC }, + [ETHTOOL_LINK_MODE_FEC_RS_BIT] = + { LM_CLASS_FEC }, + [ETHTOOL_LINK_MODE_FEC_BASER_BIT] = + { LM_CLASS_FEC }, + [ETHTOOL_LINK_MODE_50000baseKR_Full_BIT] = + { LM_CLASS_REAL, 50000, DUPLEX_FULL }, + [ETHTOOL_LINK_MODE_50000baseSR_Full_BIT] = + { LM_CLASS_REAL, 50000, DUPLEX_FULL }, + [ETHTOOL_LINK_MODE_50000baseCR_Full_BIT] = + { LM_CLASS_REAL, 50000, DUPLEX_FULL }, + [ETHTOOL_LINK_MODE_50000baseLR_ER_FR_Full_BIT] = + { LM_CLASS_REAL, 50000, DUPLEX_FULL }, + [ETHTOOL_LINK_MODE_50000baseDR_Full_BIT] = + { LM_CLASS_REAL, 50000, DUPLEX_FULL }, + [ETHTOOL_LINK_MODE_100000baseKR2_Full_BIT] = + { LM_CLASS_REAL, 100000, DUPLEX_FULL }, + [ETHTOOL_LINK_MODE_100000baseSR2_Full_BIT] = + { LM_CLASS_REAL, 100000, DUPLEX_FULL }, + [ETHTOOL_LINK_MODE_100000baseCR2_Full_BIT] = + { LM_CLASS_REAL, 100000, DUPLEX_FULL }, + [ETHTOOL_LINK_MODE_100000baseLR2_ER2_FR2_Full_BIT] = + { LM_CLASS_REAL, 100000, DUPLEX_FULL }, + [ETHTOOL_LINK_MODE_100000baseDR2_Full_BIT] = + { LM_CLASS_REAL, 100000, DUPLEX_FULL }, + [ETHTOOL_LINK_MODE_200000baseKR4_Full_BIT] = + { LM_CLASS_REAL, 200000, DUPLEX_FULL }, + [ETHTOOL_LINK_MODE_200000baseSR4_Full_BIT] = + { LM_CLASS_REAL, 200000, DUPLEX_FULL }, + [ETHTOOL_LINK_MODE_200000baseLR4_ER4_FR4_Full_BIT] = + { LM_CLASS_REAL, 200000, DUPLEX_FULL }, + [ETHTOOL_LINK_MODE_200000baseDR4_Full_BIT] = + { LM_CLASS_REAL, 200000, DUPLEX_FULL }, + [ETHTOOL_LINK_MODE_200000baseCR4_Full_BIT] = + { LM_CLASS_REAL, 200000, DUPLEX_FULL }, + [ETHTOOL_LINK_MODE_100baseT1_Full_BIT] = + { LM_CLASS_REAL, 100, DUPLEX_FULL }, + [ETHTOOL_LINK_MODE_1000baseT1_Full_BIT] = + { LM_CLASS_REAL, 1000, DUPLEX_FULL }, + [ETHTOOL_LINK_MODE_400000baseKR8_Full_BIT] = + { LM_CLASS_REAL, 400000, DUPLEX_FULL }, + [ETHTOOL_LINK_MODE_400000baseSR8_Full_BIT] = + { LM_CLASS_REAL, 400000, DUPLEX_FULL }, + [ETHTOOL_LINK_MODE_400000baseLR8_ER8_FR8_Full_BIT] = + { LM_CLASS_REAL, 400000, DUPLEX_FULL }, + [ETHTOOL_LINK_MODE_400000baseDR8_Full_BIT] = + { LM_CLASS_REAL, 400000, DUPLEX_FULL }, + [ETHTOOL_LINK_MODE_400000baseCR8_Full_BIT] = + { LM_CLASS_REAL, 400000, DUPLEX_FULL }, +}; +const unsigned int link_modes_count = ARRAY_SIZE(link_modes); + +static bool lm_class_match(unsigned int mode, enum link_mode_class class) +{ + unsigned int mode_class = (mode < link_modes_count) ? + link_modes[mode].class : LM_CLASS_UNKNOWN; + + return mode_class == class || + (class == LM_CLASS_REAL && mode_class == LM_CLASS_UNKNOWN); +} + +static void print_enum(const char *const *info, unsigned int n_info, + unsigned int val, const char *label) +{ + if (val >= n_info || !info[val]) + printf("\t%s: Unknown! (%d)\n", label, val); + else + printf("\t%s: %s\n", label, info[val]); +} + +static int dump_pause(const struct nlattr *attr, bool mask, const char *label) +{ + bool pause, asym; + int ret = 0; + + pause = bitset_get_bit(attr, mask, ETHTOOL_LINK_MODE_Pause_BIT, &ret); + if (ret < 0) + goto err; + asym = bitset_get_bit(attr, mask, ETHTOOL_LINK_MODE_Asym_Pause_BIT, + &ret); + if (ret < 0) + goto err; + + printf("\t%s", label); + if (pause) + printf("%s\n", asym ? "Symmetric Receive-only" : "Symmetric"); + else + printf("%s\n", asym ? "Transmit-only" : "No"); + + return 0; +err: + fprintf(stderr, "malformed netlink message (pause modes)\n"); + return ret; +} + +static void print_banner(struct nl_context *nlctx) +{ + if (nlctx->no_banner) + return; + printf("Settings for %s:\n", nlctx->devname); + nlctx->no_banner = true; +} + +static int dump_link_modes(struct nl_context *nlctx, + const struct nlattr *bitset, bool mask, + unsigned int class, const char *before, + const char *between, const char *after, + const char *if_none) +{ + const struct nlattr *bitset_tb[ETHTOOL_A_BITSET_MAX + 1] = {}; + DECLARE_ATTR_TB_INFO(bitset_tb); + const unsigned int before_len = strlen(before); + const struct nlattr *bits; + const struct nlattr *bit; + bool first = true; + int prev = -2; + int ret; + + ret = mnl_attr_parse_nested(bitset, attr_cb, &bitset_tb_info); + bits = bitset_tb[ETHTOOL_A_BITSET_BITS]; + if (ret < 0) + goto err_nonl; + if (!bits) { + const struct stringset *lm_strings; + unsigned int count; + unsigned int idx; + const char *name; + + ret = netlink_init_ethnl2_socket(nlctx); + if (ret < 0) + goto err_nonl; + lm_strings = global_stringset(ETH_SS_LINK_MODES, + nlctx->ethnl2_socket); + bits = mask ? bitset_tb[ETHTOOL_A_BITSET_MASK] : + bitset_tb[ETHTOOL_A_BITSET_VALUE]; + ret = -EFAULT; + if (!bits || !bitset_tb[ETHTOOL_A_BITSET_SIZE]) + goto err_nonl; + count = mnl_attr_get_u32(bitset_tb[ETHTOOL_A_BITSET_SIZE]); + if (mnl_attr_get_payload_len(bits) / 4 < (count + 31) / 32) + goto err_nonl; + + printf("\t%s", before); + for (idx = 0; idx < count; idx++) { + const uint32_t *raw_data = mnl_attr_get_payload(bits); + char buff[14]; + + if (!(raw_data[idx / 32] & (1U << (idx % 32)))) + continue; + if (!lm_class_match(idx, class)) + continue; + name = get_string(lm_strings, idx); + if (!name) { + snprintf(buff, sizeof(buff), "BIT%u", idx); + name = buff; + } + if (first) + first = false; + /* ugly hack to preserve old output format */ + if (class == LM_CLASS_REAL && (prev == idx - 1) && + prev < link_modes_count && + link_modes[prev].class == LM_CLASS_REAL && + link_modes[prev].duplex == DUPLEX_HALF) + putchar(' '); + else if (between) + printf("\t%s", between); + else + printf("\n\t%*s", before_len, ""); + printf("%s", name); + prev = idx; + } + goto after; + } + + printf("\t%s", before); + mnl_attr_for_each_nested(bit, bits) { + const struct nlattr *tb[ETHTOOL_A_BITSET_BIT_MAX + 1] = {}; + DECLARE_ATTR_TB_INFO(tb); + unsigned int idx; + const char *name; + + if (mnl_attr_get_type(bit) != ETHTOOL_A_BITSET_BITS_BIT) + continue; + ret = mnl_attr_parse_nested(bit, attr_cb, &tb_info); + if (ret < 0) + goto err; + ret = -EFAULT; + if (!tb[ETHTOOL_A_BITSET_BIT_INDEX] || + !tb[ETHTOOL_A_BITSET_BIT_NAME]) + goto err; + if (!mask && !tb[ETHTOOL_A_BITSET_BIT_VALUE]) + continue; + + idx = mnl_attr_get_u32(tb[ETHTOOL_A_BITSET_BIT_INDEX]); + name = mnl_attr_get_str(tb[ETHTOOL_A_BITSET_BIT_NAME]); + if (!lm_class_match(idx, class)) + continue; + if (first) { + first = false; + } else { + /* ugly hack to preserve old output format */ + if ((class == LM_CLASS_REAL) && (prev == idx - 1) && + (prev < link_modes_count) && + (link_modes[prev].class == LM_CLASS_REAL) && + (link_modes[prev].duplex == DUPLEX_HALF)) + putchar(' '); + else if (between) + printf("\t%s", between); + else + printf("\n\t%*s", before_len, ""); + } + printf("%s", name); + prev = idx; + } +after: + if (first && if_none) + printf("%s", if_none); + printf(after); + + return 0; +err: + putchar('\n'); +err_nonl: + fflush(stdout); + fprintf(stderr, "malformed netlink message (link_modes)\n"); + return ret; +} + +static int dump_our_modes(struct nl_context *nlctx, const struct nlattr *attr) +{ + bool autoneg; + int ret; + + print_banner(nlctx); + ret = dump_link_modes(nlctx, attr, true, LM_CLASS_PORT, + "Supported ports: [ ", " ", " ]\n", NULL); + if (ret < 0) + return ret; + + ret = dump_link_modes(nlctx, attr, true, LM_CLASS_REAL, + "Supported link modes: ", NULL, "\n", + "Not reported"); + if (ret < 0) + return ret; + ret = dump_pause(attr, true, "Supported pause frame use: "); + if (ret < 0) + return ret; + + autoneg = bitset_get_bit(attr, true, ETHTOOL_LINK_MODE_Autoneg_BIT, + &ret); + if (ret < 0) + return ret; + printf("\tSupports auto-negotiation: %s\n", autoneg ? "Yes" : "No"); + + ret = dump_link_modes(nlctx, attr, true, LM_CLASS_FEC, + "Supported FEC modes: ", " ", "\n", + "Not reported"); + if (ret < 0) + return ret; + + ret = dump_link_modes(nlctx, attr, false, LM_CLASS_REAL, + "Advertised link modes: ", NULL, "\n", + "Not reported"); + if (ret < 0) + return ret; + + ret = dump_pause(attr, false, "Advertised pause frame use: "); + if (ret < 0) + return ret; + autoneg = bitset_get_bit(attr, false, ETHTOOL_LINK_MODE_Autoneg_BIT, + &ret); + if (ret < 0) + return ret; + printf("\tAdvertised auto-negotiation: %s\n", autoneg ? "Yes" : "No"); + + ret = dump_link_modes(nlctx, attr, true, LM_CLASS_FEC, + "Advertised FEC modes: ", " ", "\n", + "Not reported"); + return ret; +} + +static int dump_peer_modes(struct nl_context *nlctx, const struct nlattr *attr) +{ + bool autoneg; + int ret; + + print_banner(nlctx); + ret = dump_link_modes(nlctx, attr, false, LM_CLASS_REAL, + "Link partner advertised link modes: ", + NULL, "\n", "Not reported"); + if (ret < 0) + return ret; + + ret = dump_pause(attr, false, + "Link partner advertised pause frame use: "); + if (ret < 0) + return ret; + + autoneg = bitset_get_bit(attr, false, + ETHTOOL_LINK_MODE_Autoneg_BIT, &ret); + if (ret < 0) + return ret; + printf("\tLink partner advertised auto-negotiation: %s\n", + autoneg ? "Yes" : "No"); + + ret = dump_link_modes(nlctx, attr, true, LM_CLASS_FEC, + "Link partner advertised FEC modes: ", + " ", "\n", "No"); + return ret; +} + +int linkmodes_reply_cb(const struct nlmsghdr *nlhdr, void *data) +{ + const struct nlattr *tb[ETHTOOL_A_LINKMODES_MAX + 1] = {}; + DECLARE_ATTR_TB_INFO(tb); + struct nl_context *nlctx = data; + int ret; + + if (nlctx->is_dump || nlctx->is_monitor) + nlctx->no_banner = false; + ret = mnl_attr_parse(nlhdr, GENL_HDRLEN, attr_cb, &tb_info); + if (ret < 0) + return ret; + nlctx->devname = get_dev_name(tb[ETHTOOL_A_LINKMODES_HEADER]); + if (!dev_ok(nlctx)) + return MNL_CB_OK; + + if (tb[ETHTOOL_A_LINKMODES_OURS]) { + ret = dump_our_modes(nlctx, tb[ETHTOOL_A_LINKMODES_OURS]); + if (ret < 0) + goto err; + } + if (tb[ETHTOOL_A_LINKMODES_PEER]) { + ret = dump_peer_modes(nlctx, tb[ETHTOOL_A_LINKMODES_PEER]); + if (ret < 0) + goto err; + } + if (tb[ETHTOOL_A_LINKMODES_SPEED]) { + uint32_t val = mnl_attr_get_u32(tb[ETHTOOL_A_LINKMODES_SPEED]); + + print_banner(nlctx); + if (val == 0 || val == (uint16_t)(-1) || val == (uint32_t)(-1)) + printf("\tSpeed: Unknown!\n"); + else + printf("\tSpeed: %uMb/s\n", val); + } + if (tb[ETHTOOL_A_LINKMODES_DUPLEX]) { + uint8_t val = mnl_attr_get_u8(tb[ETHTOOL_A_LINKMODES_DUPLEX]); + + print_banner(nlctx); + print_enum(names_duplex, ARRAY_SIZE(names_duplex), val, + "Duplex"); + } + if (tb[ETHTOOL_A_LINKMODES_AUTONEG]) { + int autoneg = mnl_attr_get_u8(tb[ETHTOOL_A_LINKMODES_AUTONEG]); + + print_banner(nlctx); + printf("\tAuto-negotiation: %s\n", + (autoneg == AUTONEG_DISABLE) ? "off" : "on"); + } + + return MNL_CB_OK; +err: + if (nlctx->is_monitor || nlctx->is_dump) + return MNL_CB_OK; + fputs("No data available\n", stdout); + nlctx->exit_code = 75; + return MNL_CB_ERROR; +} + +int linkinfo_reply_cb(const struct nlmsghdr *nlhdr, void *data) +{ + const struct nlattr *tb[ETHTOOL_A_LINKINFO_MAX + 1] = {}; + DECLARE_ATTR_TB_INFO(tb); + struct nl_context *nlctx = data; + int port = -1; + int ret; + + if (nlctx->is_dump || nlctx->is_monitor) + nlctx->no_banner = false; + ret = mnl_attr_parse(nlhdr, GENL_HDRLEN, attr_cb, &tb_info); + if (ret < 0) + return ret; + nlctx->devname = get_dev_name(tb[ETHTOOL_A_LINKINFO_HEADER]); + if (!dev_ok(nlctx)) + return MNL_CB_OK; + + if (tb[ETHTOOL_A_LINKINFO_PORT]) { + uint8_t val = mnl_attr_get_u8(tb[ETHTOOL_A_LINKINFO_PORT]); + + print_banner(nlctx); + print_enum(names_port, ARRAY_SIZE(names_port), val, "Port"); + port = val; + } + if (tb[ETHTOOL_A_LINKINFO_PHYADDR]) { + uint8_t val = mnl_attr_get_u8(tb[ETHTOOL_A_LINKINFO_PHYADDR]); + + print_banner(nlctx); + printf("\tPHYAD: %u\n", val); + } + if (tb[ETHTOOL_A_LINKINFO_TRANSCEIVER]) { + uint8_t val; + + val = mnl_attr_get_u8(tb[ETHTOOL_A_LINKINFO_TRANSCEIVER]); + print_banner(nlctx); + print_enum(names_transceiver, ARRAY_SIZE(names_transceiver), + val, "Transceiver"); + } + if (tb[ETHTOOL_A_LINKINFO_TP_MDIX] && tb[ETHTOOL_A_LINKINFO_TP_MDIX] && + port == PORT_TP) { + uint8_t mdix = mnl_attr_get_u8(tb[ETHTOOL_A_LINKINFO_TP_MDIX]); + uint8_t mdix_ctrl = + mnl_attr_get_u8(tb[ETHTOOL_A_LINKINFO_TP_MDIX_CTRL]); + + print_banner(nlctx); + dump_mdix(mdix, mdix_ctrl); + } + + return MNL_CB_OK; +} + +int linkstate_reply_cb(const struct nlmsghdr *nlhdr, void *data) +{ + const struct nlattr *tb[ETHTOOL_A_LINKSTATE_MAX + 1] = {}; + DECLARE_ATTR_TB_INFO(tb); + struct nl_context *nlctx = data; + int ret; + + if (nlctx->is_dump || nlctx->is_monitor) + nlctx->no_banner = false; + ret = mnl_attr_parse(nlhdr, GENL_HDRLEN, attr_cb, &tb_info); + if (ret < 0) + return ret; + nlctx->devname = get_dev_name(tb[ETHTOOL_A_LINKSTATE_HEADER]); + if (!dev_ok(nlctx)) + return MNL_CB_OK; + + if (tb[ETHTOOL_A_LINKSTATE_LINK]) { + uint8_t val = mnl_attr_get_u8(tb[ETHTOOL_A_LINKSTATE_LINK]); + + print_banner(nlctx); + printf("\tLink detected: %s\n", val ? "yes" : "no"); + } + + return MNL_CB_OK; +} + +static int gset_request(struct nl_socket *nlsk, uint8_t msg_type, + uint16_t hdr_attr, mnl_cb_t cb) +{ + int ret; + + ret = nlsock_prep_get_request(nlsk, msg_type, hdr_attr, 0); + if (ret < 0) + return ret; + return nlsock_send_get_request(nlsk, cb); +} + +int nl_gset(struct cmd_context *ctx) +{ + struct nl_context *nlctx = ctx->nlctx; + struct nl_socket *nlsk = nlctx->ethnl_socket; + int ret; + + nlctx->suppress_nlerr = 1; + + ret = gset_request(nlsk, ETHTOOL_MSG_LINKMODES_GET, + ETHTOOL_A_LINKMODES_HEADER, linkmodes_reply_cb); + if (ret == -ENODEV) + return ret; + + ret = gset_request(nlsk, ETHTOOL_MSG_LINKINFO_GET, + ETHTOOL_A_LINKINFO_HEADER, linkinfo_reply_cb); + if (ret == -ENODEV) + return ret; + + ret = gset_request(nlsk, ETHTOOL_MSG_LINKSTATE_GET, + ETHTOOL_A_LINKSTATE_HEADER, linkstate_reply_cb); + if (ret == -ENODEV) + return ret; + + if (!nlctx->no_banner) { + printf("No data available\n"); + return 75; + } + + return 0; +} From patchwork Fri Mar 6 17:05:20 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Michal Kubecek X-Patchwork-Id: 222919 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.8 required=3.0 tests=HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SIGNED_OFF_BY, SPF_HELO_NONE, SPF_PASS autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 2A132C10DCE for ; Fri, 6 Mar 2020 17:05:26 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id EB82B208C3 for ; Fri, 6 Mar 2020 17:05:25 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727196AbgCFRFZ (ORCPT ); Fri, 6 Mar 2020 12:05:25 -0500 Received: from mx2.suse.de ([195.135.220.15]:43760 "EHLO mx2.suse.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727066AbgCFRFY (ORCPT ); Fri, 6 Mar 2020 12:05:24 -0500 X-Virus-Scanned: by amavisd-new at test-mx.suse.de Received: from relay2.suse.de (unknown [195.135.220.254]) by mx2.suse.de (Postfix) with ESMTP id 7B974AEF8; Fri, 6 Mar 2020 17:05:20 +0000 (UTC) Received: by unicorn.suse.cz (Postfix, from userid 1000) id 20754E00E7; Fri, 6 Mar 2020 18:05:20 +0100 (CET) Message-Id: <7ec07fe56010053a402c3507edf224679d32bbc6.1583513281.git.mkubecek@suse.cz> In-Reply-To: References: From: Michal Kubecek Subject: [PATCH ethtool v3 16/25] netlink: add basic command line parsing helpers To: John Linville , netdev@vger.kernel.org Cc: Andrew Lunn , Florian Fainelli Date: Fri, 6 Mar 2020 18:05:20 +0100 (CET) Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org Existing command line parser functions from the ioctl interface are often too closely tied to the ioctl data structures and would not be easily adapted to generating netlink messages. Introduce a new parser framework which assigns parser handlers to parameters and provide basic handlers for most common parameter types: - flag represented by presence of a parameter - u8 bool represented by name followed by "on" or "off" - string represented by string argument - u32 represented by numeric argument - u8 represented by numeric argument - u32 represented by symbolic name (lookup table) - u8 represented by symbolic name (lookup table) - binary blob represented by MAC-like syntax Main parser entry point is nl_parse() function; it gets an array of with entries assigning parser handlers and optional data to command line parameters and generates corresponding netlink attributes or fills raw data. Optionally, attributes can be divided into multiple netlink messages or multiple nested attributes. Signed-off-by: Michal Kubecek --- Makefile.am | 2 +- netlink/netlink.h | 4 + netlink/parser.c | 615 ++++++++++++++++++++++++++++++++++++++++++++++ netlink/parser.h | 123 ++++++++++ 4 files changed, 743 insertions(+), 1 deletion(-) create mode 100644 netlink/parser.c create mode 100644 netlink/parser.h diff --git a/Makefile.am b/Makefile.am index eeb36a279045..30cda5b1fc6f 100644 --- a/Makefile.am +++ b/Makefile.am @@ -29,7 +29,7 @@ ethtool_SOURCES += \ netlink/msgbuff.c netlink/msgbuff.h netlink/nlsock.c \ netlink/nlsock.h netlink/strset.c netlink/strset.h \ netlink/monitor.c netlink/bitset.c netlink/bitset.h \ - netlink/settings.c \ + netlink/settings.c netlink/parser.c netlink/parser.h \ uapi/linux/ethtool_netlink.h \ uapi/linux/netlink.h uapi/linux/genetlink.h \ uapi/linux/rtnetlink.h uapi/linux/if_link.h diff --git a/netlink/netlink.h b/netlink/netlink.h index 730f8e1b3fe9..3ab5f2329e2f 100644 --- a/netlink/netlink.h +++ b/netlink/netlink.h @@ -31,6 +31,10 @@ struct nl_context { uint32_t filter_cmds[CMDMASK_WORDS]; const char *filter_devname; bool no_banner; + const char *cmd; + const char *param; + char **argp; + int argc; }; struct attr_tb_info { diff --git a/netlink/parser.c b/netlink/parser.c new file mode 100644 index 000000000000..0e2190eed0b4 --- /dev/null +++ b/netlink/parser.c @@ -0,0 +1,615 @@ +/* + * parser.c - netlink command line parser + * + * Implementation of command line parser used by netlink code. + */ + +#include +#include +#include +#include + +#include "../internal.h" +#include "../common.h" +#include "netlink.h" +#include "parser.h" + +static void parser_err_unknown_param(struct nl_context *nlctx) +{ + fprintf(stderr, "ethtool (%s): unknown parameter '%s'\n", nlctx->cmd, + nlctx->param); +} + +static void parser_err_dup_param(struct nl_context *nlctx) +{ + fprintf(stderr, "ethtool (%s): duplicate parameter '%s'\n", nlctx->cmd, + nlctx->param); +} + +static void parser_err_min_argc(struct nl_context *nlctx, unsigned int min_argc) +{ + if (min_argc == 1) + fprintf(stderr, "ethtool (%s): no value for parameter '%s'\n", + nlctx->cmd, nlctx->param); + else + fprintf(stderr, + "ethtool (%s): parameter '%s' requires %u words\n", + nlctx->cmd, nlctx->param, min_argc); +} + +static void parser_err_invalid_value(struct nl_context *nlctx, const char *val) +{ + fprintf(stderr, "ethtool (%s): invalid value '%s' for parameter '%s'\n", + nlctx->cmd, val, nlctx->param); +} + +static bool __prefix_0x(const char *p) +{ + return p[0] == '0' && (p[1] == 'x' || p[1] == 'X'); +} + +static int __parse_u32(const char *arg, uint32_t *result, uint32_t min, + uint32_t max, int base) +{ + unsigned long long val; + char *endptr; + + if (!arg || !arg[0]) + return -EINVAL; + val = strtoul(arg, &endptr, base); + if (*endptr || val < min || val > max) + return -EINVAL; + + *result = (uint32_t)val; + return 0; +} + +static int parse_u32d(const char *arg, uint32_t *result) +{ + return __parse_u32(arg, result, 0, 0xffffffff, 10); +} + +static int parse_x32(const char *arg, uint32_t *result) +{ + return __parse_u32(arg, result, 0, 0xffffffff, 16); +} + +int parse_u32(const char *arg, uint32_t *result) +{ + if (!arg) + return -EINVAL; + if (__prefix_0x(arg)) + return parse_x32(arg + 2, result); + else + return parse_u32d(arg, result); +} + +static int parse_u8(const char *arg, uint8_t *result) +{ + uint32_t val; + int ret = parse_u32(arg, &val); + + if (ret < 0) + return ret; + if (val > UINT8_MAX) + return -EINVAL; + + *result = (uint8_t)val; + return 0; +} + +static int lookup_u32(const char *arg, uint32_t *result, + const struct lookup_entry_u32 *tbl) +{ + if (!arg) + return -EINVAL; + while (tbl->arg) { + if (!strcmp(tbl->arg, arg)) { + *result = tbl->val; + return 0; + } + tbl++; + } + + return -EINVAL; +} + +static int lookup_u8(const char *arg, uint8_t *result, + const struct lookup_entry_u8 *tbl) +{ + if (!arg) + return -EINVAL; + while (tbl->arg) { + if (!strcmp(tbl->arg, arg)) { + *result = tbl->val; + return 0; + } + tbl++; + } + + return -EINVAL; +} + +/* Parser handler for a flag. Expects a name (with no additional argument), + * generates NLA_FLAG or sets a bool (if the name was present). + */ +int nl_parse_flag(struct nl_context *nlctx, uint16_t type, const void *data, + struct nl_msg_buff *msgbuff, void *dest) +{ + if (dest) + *(bool *)dest = true; + return (type && ethnla_put_flag(msgbuff, type, true)) ? -EMSGSIZE : 0; +} + +/* Parser handler for null terminated string. Expects a string argument, + * generates NLA_NUL_STRING or fills const char * + */ +int nl_parse_string(struct nl_context *nlctx, uint16_t type, const void *data, + struct nl_msg_buff *msgbuff, void *dest) +{ + const char *arg = *nlctx->argp; + + nlctx->argp++; + nlctx->argc--; + + if (dest) + *(const char **)dest = arg; + return (type && ethnla_put_strz(msgbuff, type, arg)) ? -EMSGSIZE : 0; +} + +/* Parser handler for unsigned 32-bit integer. Expects a numeric argument + * (may use 0x prefix), generates NLA_U32 or fills an uint32_t. + */ +int nl_parse_direct_u32(struct nl_context *nlctx, uint16_t type, + const void *data, struct nl_msg_buff *msgbuff, + void *dest) +{ + const char *arg = *nlctx->argp; + uint32_t val; + int ret; + + nlctx->argp++; + nlctx->argc--; + ret = parse_u32(arg, &val); + if (ret < 0) { + parser_err_invalid_value(nlctx, arg); + return ret; + } + + if (dest) + *(uint32_t *)dest = val; + return (type && ethnla_put_u32(msgbuff, type, val)) ? -EMSGSIZE : 0; +} + +/* Parser handler for unsigned 32-bit integer. Expects a numeric argument + * (may use 0x prefix), generates NLA_U32 or fills an uint32_t. + */ +int nl_parse_direct_u8(struct nl_context *nlctx, uint16_t type, + const void *data, struct nl_msg_buff *msgbuff, + void *dest) +{ + const char *arg = *nlctx->argp; + uint8_t val; + int ret; + + nlctx->argp++; + nlctx->argc--; + ret = parse_u8(arg, &val); + if (ret < 0) { + parser_err_invalid_value(nlctx, arg); + return ret; + } + + if (dest) + *(uint8_t *)dest = val; + return (type && ethnla_put_u8(msgbuff, type, val)) ? -EMSGSIZE : 0; +} + +/* Parser handler for (tri-state) bool. Expects "name on|off", generates + * NLA_U8 which is 1 for "on" and 0 for "off". + */ +int nl_parse_u8bool(struct nl_context *nlctx, uint16_t type, const void *data, + struct nl_msg_buff *msgbuff, void *dest) +{ + const char *arg = *nlctx->argp; + int ret; + + nlctx->argp++; + nlctx->argc--; + if (!strcmp(arg, "on")) { + if (dest) + *(uint8_t *)dest = 1; + ret = type ? ethnla_put_u8(msgbuff, type, 1) : 0; + } else if (!strcmp(arg, "off")) { + if (dest) + *(uint8_t *)dest = 0; + ret = type ? ethnla_put_u8(msgbuff, type, 0) : 0; + } else { + parser_err_invalid_value(nlctx, arg); + return -EINVAL; + } + + return ret ? -EMSGSIZE : 0; +} + +/* Parser handler for 32-bit lookup value. Expects a string argument, looks it + * up in a table, generates NLA_U32 or fills uint32_t variable. The @data + * parameter is a null terminated array of struct lookup_entry_u32. + */ +int nl_parse_lookup_u32(struct nl_context *nlctx, uint16_t type, + const void *data, struct nl_msg_buff *msgbuff, + void *dest) +{ + const char *arg = *nlctx->argp; + uint32_t val; + int ret; + + nlctx->argp++; + nlctx->argc--; + ret = lookup_u32(arg, &val, data); + if (ret < 0) { + parser_err_invalid_value(nlctx, arg); + return ret; + } + + if (dest) + *(uint32_t *)dest = val; + return (type && ethnla_put_u32(msgbuff, type, val)) ? -EMSGSIZE : 0; +} + +/* Parser handler for 8-bit lookup value. Expects a string argument, looks it + * up in a table, generates NLA_U8 or fills uint8_t variable. The @data + * parameter is a null terminated array of struct lookup_entry_u8. + */ +int nl_parse_lookup_u8(struct nl_context *nlctx, uint16_t type, + const void *data, struct nl_msg_buff *msgbuff, + void *dest) +{ + const char *arg = *nlctx->argp; + uint8_t val; + int ret; + + nlctx->argp++; + nlctx->argc--; + ret = lookup_u8(arg, &val, data); + if (ret < 0) { + parser_err_invalid_value(nlctx, arg); + return ret; + } + + if (dest) + *(uint8_t *)dest = val; + return (type && ethnla_put_u8(msgbuff, type, val)) ? -EMSGSIZE : 0; +} + +static bool __is_hex(char c) +{ + if (isdigit(c)) + return true; + else + return (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'); +} + +static unsigned int __hex_val(char c) +{ + if (c >= '0' && c <= '9') + return c - '0'; + if (c >= 'a' && c <= 'f') + return c - 'a' + 0xa; + if (c >= 'A' && c <= 'F') + return c - 'A' + 0xa; + return 0; +} + +static bool __bytestr_delim(const char *p, char delim) +{ + return !*p || (delim ? (*p == delim) : !__is_hex(*p)); +} + +/* Parser handler for generic byte string in MAC-like format. Expects string + * argument in the "[[:xdigit:]]{2}(:[[:xdigit:]]{2})*" format, generates + * NLA_BINARY or fills a struct byte_str_value (if @dest is not null and the + * handler succeeds, caller is responsible for freeing the value). The @data + * parameter points to struct byte_str_parser_data. + */ +int nl_parse_byte_str(struct nl_context *nlctx, uint16_t type, const void *data, + struct nl_msg_buff *msgbuff, void *dest) +{ + const struct byte_str_parser_data *pdata = data; + struct byte_str_value *dest_value = dest; + const char *arg = *nlctx->argp; + uint8_t *val = NULL; + unsigned int len, i; + const char *p; + int ret; + + nlctx->argp++; + nlctx->argc--; + + len = 0; + p = arg; + if (!*p) + goto err; + while (true) { + len++; + if (!__bytestr_delim(p, pdata->delim)) + p++; + if (!__bytestr_delim(p, pdata->delim)) + p++; + if (!__bytestr_delim(p, pdata->delim)) + goto err; + if (!*p) + break; + p++; + if (*p && __bytestr_delim(p, pdata->delim)) + goto err; + } + if (len < pdata->min_len || (pdata->max_len && len > pdata->max_len)) + goto err; + val = malloc(len); + if (!val) + return -ENOMEM; + + p = arg; + for (i = 0; i < len; i++) { + uint8_t byte = 0; + + if (!__is_hex(*p)) + goto err; + while (__is_hex(*p)) + byte = 16 * byte + __hex_val(*p++); + if (!__bytestr_delim(p, pdata->delim)) + goto err; + val[i] = byte; + if (*p) + p++; + } + ret = type ? ethnla_put(msgbuff, type, len, val) : 0; + if (dest) { + dest_value->len = len; + dest_value->data = val; + } else { + free(val); + } + return ret; + +err: + free(val); + fprintf(stderr, "ethtool (%s): invalid value '%s' of parameter '%s'\n", + nlctx->cmd, arg, nlctx->param); + return -EINVAL; +} + +/* Parser handler for parameters recognized for backward compatibility but + * supposed to fail without passing to kernel. Does not generate any netlink + * attributes of fill any variable. The @data parameter points to struct + * error_parser_params (error message, return value and number of extra + * arguments to skip). + */ +int nl_parse_error(struct nl_context *nlctx, uint16_t type, const void *data, + struct nl_msg_buff *msgbuff, void *dest) +{ + const struct error_parser_data *parser_data = data; + unsigned int skip = parser_data->extra_args; + + fprintf(stderr, "ethtool (%s): ", nlctx->cmd); + fprintf(stderr, parser_data->err_msg, nlctx->param); + if (nlctx->argc < skip) { + fprintf(stderr, "ethtool (%s): too few arguments for parameter '%s' (expected %u)\n", + nlctx->cmd, nlctx->param, skip); + } else { + nlctx->argp += skip; + nlctx->argc -= skip; + } + + return parser_data->ret_val; +} + +/* parser implementation */ + +static const struct param_parser *find_parser(const struct param_parser *params, + const char *arg) +{ + const struct param_parser *parser; + + for (parser = params; parser->arg; parser++) + if (!strcmp(arg, parser->arg)) + return parser; + return NULL; +} + +static bool __parser_bit(const uint64_t *map, unsigned int idx) +{ + return map[idx / 64] & (1 << (idx % 64)); +} + +static void __parser_set(uint64_t *map, unsigned int idx) +{ + map[idx / 64] |= (1 << (idx % 64)); +} + +struct tmp_buff { + struct nl_msg_buff msgbuff; + unsigned int id; + unsigned int orig_len; + struct tmp_buff *next; +}; + +static struct tmp_buff *tmp_buff_find(struct tmp_buff *head, unsigned int id) +{ + struct tmp_buff *buff; + + for (buff = head; buff; buff = buff->next) + if (buff->id == id) + break; + + return buff; +} + +static struct tmp_buff *tmp_buff_find_or_create(struct tmp_buff **phead, + unsigned int id) +{ + struct tmp_buff **pbuff; + struct tmp_buff *new_buff; + + for (pbuff = phead; *pbuff; pbuff = &(*pbuff)->next) + if ((*pbuff)->id == id) + return *pbuff; + + new_buff = malloc(sizeof(*new_buff)); + if (!new_buff) + return NULL; + new_buff->id = id; + msgbuff_init(&new_buff->msgbuff); + new_buff->next = NULL; + *pbuff = new_buff; + + return new_buff; +} + +static void tmp_buff_destroy(struct tmp_buff *head) +{ + struct tmp_buff *buff = head; + struct tmp_buff *next; + + while (buff) { + next = buff->next; + msgbuff_done(&buff->msgbuff); + free(buff); + buff = next; + } +} + +/* Main entry point of parser implementation. + * @nlctx: netlink context + * @params: array of struct param_parser describing expected arguments + * and their handlers; the array must be terminated by null + * element {} + * @dest: optional destination to copy parsed data to (at + * param_parser::offset) + * @group_style: defines if identifiers in .group represent separate messages, + * nested attributes or are not allowed + */ +int nl_parser(struct nl_context *nlctx, const struct param_parser *params, + void *dest, enum parser_group_style group_style) +{ + struct nl_socket *nlsk = nlctx->ethnl_socket; + const struct param_parser *parser; + struct tmp_buff *buffs = NULL; + struct tmp_buff *buff; + unsigned int n_params; + uint64_t *params_seen; + int ret; + + n_params = 0; + for (parser = params; parser->arg; parser++) { + struct nl_msg_buff *msgbuff; + struct nlattr *nest; + + n_params++; + if (group_style == PARSER_GROUP_NONE || !parser->group) + continue; + ret = -ENOMEM; + buff = tmp_buff_find_or_create(&buffs, parser->group); + if (!buff) + goto out_free_buffs; + msgbuff = &buff->msgbuff; + + switch (group_style) { + case PARSER_GROUP_NEST: + ret = -EMSGSIZE; + nest = ethnla_nest_start(&buff->msgbuff, parser->group); + if (!nest) + goto out_free_buffs; + break; + case PARSER_GROUP_MSG: + ret = msg_init(nlctx, msgbuff, parser->group, + NLM_F_REQUEST | NLM_F_ACK); + if (ret < 0) + goto out_free_buffs; + if (ethnla_fill_header(msgbuff, + ETHTOOL_A_LINKINFO_HEADER, + nlctx->devname, 0)) + goto out_free_buffs; + break; + default: + break; + } + + buff->orig_len = msgbuff_len(msgbuff); + } + ret = -ENOMEM; + params_seen = calloc(DIV_ROUND_UP(n_params, 64), sizeof(uint64_t)); + if (!params_seen) + goto out_free_buffs; + + while (nlctx->argc > 0) { + struct nl_msg_buff *msgbuff; + void *param_dest; + + nlctx->param = *nlctx->argp; + ret = -EINVAL; + parser = find_parser(params, nlctx->param); + if (!parser) { + parser_err_unknown_param(nlctx); + goto out_free; + } + + /* check duplicates and minimum number of arguments */ + if (__parser_bit(params_seen, parser - params)) { + parser_err_dup_param(nlctx); + goto out_free; + } + nlctx->argc--; + nlctx->argp++; + if (nlctx->argc < parser->min_argc) { + parser_err_min_argc(nlctx, parser->min_argc); + goto out_free; + } + __parser_set(params_seen, parser - params); + + buff = NULL; + if (parser->group) + buff = tmp_buff_find(buffs, parser->group); + msgbuff = buff ? &buff->msgbuff : &nlsk->msgbuff; + + param_dest = dest ? (dest + parser->dest_offset) : NULL; + ret = parser->handler(nlctx, parser->type, parser->handler_data, + msgbuff, param_dest); + if (ret < 0) + goto out_free; + } + + for (buff = buffs; buff; buff = buff->next) { + struct nl_msg_buff *msgbuff = &buff->msgbuff; + + if (group_style == PARSER_GROUP_NONE || + msgbuff_len(msgbuff) == buff->orig_len) + continue; + switch (group_style) { + case PARSER_GROUP_NEST: + ethnla_nest_end(msgbuff, msgbuff->payload); + ret = msgbuff_append(&nlsk->msgbuff, msgbuff); + if (ret < 0) + goto out_free; + break; + case PARSER_GROUP_MSG: + ret = nlsock_sendmsg(nlsk, msgbuff); + if (ret < 0) + goto out_free; + ret = nlsock_process_reply(nlsk, nomsg_reply_cb, NULL); + if (ret < 0) + goto out_free; + break; + default: + break; + } + } + + ret = 0; +out_free: + free(params_seen); +out_free_buffs: + tmp_buff_destroy(buffs); + return ret; +} diff --git a/netlink/parser.h b/netlink/parser.h new file mode 100644 index 000000000000..b5e8cd418b50 --- /dev/null +++ b/netlink/parser.h @@ -0,0 +1,123 @@ +/* + * parser.h - netlink command line parser + * + * Interface for command line parser used by netlink code. + */ + +#ifndef ETHTOOL_NETLINK_PARSER_H__ +#define ETHTOOL_NETLINK_PARSER_H__ + +#include + +#include "netlink.h" + +/* Some commands need to generate multiple netlink messages or multiple nested + * attributes from one set of command line parameters. Argument @group_style + * of nl_parser() takes one of three values: + * + * PARSER_GROUP_NONE - no grouping, flat series of attributes (default) + * PARSER_GROUP_NEST - one nest for each @group value (@group is nest type) + * PARSER_GROUP_MSG - one message for each @group value (@group is command) + */ +enum parser_group_style { + PARSER_GROUP_NONE = 0, + PARSER_GROUP_NEST, + PARSER_GROUP_MSG, +}; + +typedef int (*param_parser_cb_t)(struct nl_context *, uint16_t, const void *, + struct nl_msg_buff *, void *); + +struct param_parser { + /* command line parameter handled by this entry */ + const char *arg; + /* group id (see enum parser_group_style above) */ + unsigned int group; + /* netlink attribute type */ + uint16_t type; /* netlink attribute type */ + /* function called to parse parameter and its value */ + param_parser_cb_t handler; + /* pointer passed as @data argument of the handler */ + const void *handler_data; + /* minimum number of extra arguments after this parameter */ + unsigned int min_argc; + /* if @dest is passed to nl_parser(), offset to store value */ + unsigned int dest_offset; +}; + +/* data structures used for handler data */ + +/* used by nl_parse_lookup_u32() */ +struct lookup_entry_u32 { + const char *arg; + uint32_t val; +}; + +/* used by nl_parse_lookup_u8() */ +struct lookup_entry_u8 { + const char *arg; + uint8_t val; +}; + +/* used by nl_parse_byte_str() */ +struct byte_str_parser_data { + unsigned int min_len; + unsigned int max_len; + char delim; +}; + +/* used for value stored by nl_parse_byte_str() */ +struct byte_str_value { + unsigned int len; + u8 *data; +}; + +/* used by nl_parse_error() */ +struct error_parser_data { + const char *err_msg; + int ret_val; + unsigned int extra_args; +}; + +int parse_u32(const char *arg, uint32_t *result); + +/* parser handlers to use as param_parser::handler */ + +/* NLA_FLAG represented by on | off */ +int nl_parse_flag(struct nl_context *nlctx, uint16_t type, const void *data, + struct nl_msg_buff *msgbuff, void *dest); +/* NLA_NUL_STRING represented by a string argument */ +int nl_parse_string(struct nl_context *nlctx, uint16_t type, const void *data, + struct nl_msg_buff *msgbuff, void *dest); +/* NLA_U32 represented as numeric argument */ +int nl_parse_direct_u32(struct nl_context *nlctx, uint16_t type, + const void *data, struct nl_msg_buff *msgbuff, + void *dest); +/* NLA_U8 represented as numeric argument */ +int nl_parse_direct_u8(struct nl_context *nlctx, uint16_t type, + const void *data, struct nl_msg_buff *msgbuff, + void *dest); +/* NLA_U8 represented as on | off */ +int nl_parse_u8bool(struct nl_context *nlctx, uint16_t type, const void *data, + struct nl_msg_buff *msgbuff, void *dest); +/* NLA_U32 represented by a string argument (lookup table) */ +int nl_parse_lookup_u32(struct nl_context *nlctx, uint16_t type, + const void *data, struct nl_msg_buff *msgbuff, + void *dest); +/* NLA_U8 represented by a string argument (lookup table) */ +int nl_parse_lookup_u8(struct nl_context *nlctx, uint16_t type, + const void *data, struct nl_msg_buff *msgbuff, + void *dest); +/* always fail (for deprecated parameters) */ +int nl_parse_error(struct nl_context *nlctx, uint16_t type, const void *data, + struct nl_msg_buff *msgbuff, void *dest); +/* NLA_BINARY represented by %x:%x:...%x (e.g. a MAC address) */ +int nl_parse_byte_str(struct nl_context *nlctx, uint16_t type, + const void *data, struct nl_msg_buff *msgbuff, + void *dest); + +/* main entry point called to parse the command line */ +int nl_parser(struct nl_context *nlctx, const struct param_parser *params, + void *dest, enum parser_group_style group_style); + +#endif /* ETHTOOL_NETLINK_PARSER_H__ */ From patchwork Fri Mar 6 17:05:30 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Michal Kubecek X-Patchwork-Id: 222918 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.8 required=3.0 tests=HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SIGNED_OFF_BY, SPF_HELO_NONE, SPF_PASS autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id ACD71C10DCE for ; Fri, 6 Mar 2020 17:05:34 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 854E8206E2 for ; Fri, 6 Mar 2020 17:05:34 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727217AbgCFRFd (ORCPT ); Fri, 6 Mar 2020 12:05:33 -0500 Received: from mx2.suse.de ([195.135.220.15]:43810 "EHLO mx2.suse.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726397AbgCFRFd (ORCPT ); Fri, 6 Mar 2020 12:05:33 -0500 X-Virus-Scanned: by amavisd-new at test-mx.suse.de Received: from relay2.suse.de (unknown [195.135.220.254]) by mx2.suse.de (Postfix) with ESMTP id 7C5E9B15D; Fri, 6 Mar 2020 17:05:30 +0000 (UTC) Received: by unicorn.suse.cz (Postfix, from userid 1000) id 2D886E00E7; Fri, 6 Mar 2020 18:05:30 +0100 (CET) Message-Id: <148c6fb218b83db9d0e973fb5684b4e3408a5f0a.1583513281.git.mkubecek@suse.cz> In-Reply-To: References: From: Michal Kubecek Subject: [PATCH ethtool v3 18/25] netlink: add netlink handler for sset (-s) To: John Linville , netdev@vger.kernel.org Cc: Andrew Lunn , Florian Fainelli Date: Fri, 6 Mar 2020 18:05:30 +0100 (CET) Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org Implement "ethtool -s " subcommand using netlink interface request ETHTOOL_MSG_LINKINFO_SET, ETHTOOL_MSG_LINKMODES_SET, ETHTOOL_MSG_WOL_SET and ETHTOOL_MSG_DEBUG_SET. Parser grouping with PARSER_GROUP_MSG group style is used to create multiple request messages from one set of attributes which can be in arbitrary order. Signed-off-by: Michal Kubecek --- ethtool.8.in | 15 ++-- ethtool.c | 9 ++- netlink/extapi.h | 2 + netlink/settings.c | 193 +++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 210 insertions(+), 9 deletions(-) diff --git a/ethtool.8.in b/ethtool.8.in index 28e4f75eee8d..ba85cfe4f413 100644 --- a/ethtool.8.in +++ b/ethtool.8.in @@ -242,16 +242,21 @@ ethtool \- query or control network driver and hardware settings .I devname .BN speed .B2 duplex half full -.B4 port tp aui bnc mii fibre +.B4 port tp aui bnc mii fibre da .B3 mdix auto on off .B2 autoneg on off -.BN advertise +.RB [ advertise \ \fIN\fP[\fB/\fP\fIM\fP] +| +.BI advertise \ mode +.A1 on off +.RB ...] .BN phyad .B2 xcvr internal external -.RB [ wol \ \*(WO] +.RB [ wol \ \fIN\fP[\fB/\fP\fIM\fP] +.RB | \ wol \ \*(WO] .RB [ sopass \ \*(MA] .RB [ msglvl -.IR N \ | +.IR N\fP[/\fIM\fP] \ | .BI msglvl \ type .A1 on off .RB ...] @@ -638,7 +643,7 @@ with just the device name as an argument will show you the supported device spee .A2 duplex half full Sets full or half duplex mode. .TP -.A4 port tp aui bnc mii fibre +.A4 port tp aui bnc mii fibre da Selects device port. .TP .A3 mdix auto on off diff --git a/ethtool.c b/ethtool.c index a69233bd73fc..baa6458bb486 100644 --- a/ethtool.c +++ b/ethtool.c @@ -5166,18 +5166,19 @@ static const struct option args[] = { { .opts = "-s|--change", .func = do_sset, + .nlfunc = nl_sset, .help = "Change generic options", .xhelp = " [ speed %d ]\n" " [ duplex half|full ]\n" - " [ port tp|aui|bnc|mii|fibre ]\n" + " [ port tp|aui|bnc|mii|fibre|da ]\n" " [ mdix auto|on|off ]\n" " [ autoneg on|off ]\n" - " [ advertise %x ]\n" + " [ advertise %x[/%x] | mode on|off ... [--] ]\n" " [ phyad %d ]\n" " [ xcvr internal|external ]\n" - " [ wol p|u|m|b|a|g|s|f|d... ]\n" + " [ wol %d[/%d] | p|u|m|b|a|g|s|f|d... ]\n" " [ sopass %x:%x:%x:%x:%x:%x ]\n" - " [ msglvl %d | msglvl type on|off ... ]\n" + " [ msglvl %d[/%d] | type on|off ... [--] ]\n" }, { .opts = "-a|--show-pause", diff --git a/netlink/extapi.h b/netlink/extapi.h index 8608ea7f51f5..612002e8228b 100644 --- a/netlink/extapi.h +++ b/netlink/extapi.h @@ -16,6 +16,7 @@ int netlink_init(struct cmd_context *ctx); void netlink_done(struct cmd_context *ctx); int nl_gset(struct cmd_context *ctx); +int nl_sset(struct cmd_context *ctx); int nl_monitor(struct cmd_context *ctx); void nl_monitor_usage(void); @@ -36,6 +37,7 @@ static inline void nl_monitor_usage(void) } #define nl_gset NULL +#define nl_sset NULL #endif /* ETHTOOL_ENABLE_NETLINK */ diff --git a/netlink/settings.c b/netlink/settings.c index 1e43d742245c..c8a911d718b9 100644 --- a/netlink/settings.c +++ b/netlink/settings.c @@ -13,6 +13,7 @@ #include "netlink.h" #include "strset.h" #include "bitset.h" +#include "parser.h" /* GET_SETTINGS */ @@ -760,3 +761,195 @@ int nl_gset(struct cmd_context *ctx) return 0; } + +/* SET_SETTINGS */ + +enum { + WAKE_PHY_BIT = 0, + WAKE_UCAST_BIT = 1, + WAKE_MCAST_BIT = 2, + WAKE_BCAST_BIT = 3, + WAKE_ARP_BIT = 4, + WAKE_MAGIC_BIT = 5, + WAKE_MAGICSECURE_BIT = 6, + WAKE_FILTER_BIT = 7, +}; + +#define WAKE_ALL (WAKE_PHY | WAKE_UCAST | WAKE_MCAST | WAKE_BCAST | WAKE_ARP | \ + WAKE_MAGIC | WAKE_MAGICSECURE) + +static const struct lookup_entry_u8 port_values[] = { + { .arg = "tp", .val = PORT_TP }, + { .arg = "aui", .val = PORT_AUI }, + { .arg = "mii", .val = PORT_MII }, + { .arg = "fibre", .val = PORT_FIBRE }, + { .arg = "bnc", .val = PORT_BNC }, + { .arg = "da", .val = PORT_DA }, + {} +}; + +static const struct lookup_entry_u8 mdix_values[] = { + { .arg = "auto", .val = ETH_TP_MDI_AUTO }, + { .arg = "on", .val = ETH_TP_MDI_X }, + { .arg = "off", .val = ETH_TP_MDI }, + {} +}; + +static const struct error_parser_data xcvr_parser_data = { + .err_msg = "deprecated parameter '%s' not supported by kernel\n", + .ret_val = -EINVAL, + .extra_args = 1, +}; + +static const struct lookup_entry_u8 autoneg_values[] = { + { .arg = "off", .val = AUTONEG_DISABLE }, + { .arg = "on", .val = AUTONEG_ENABLE }, + {} +}; + +static const struct bitset_parser_data advertise_parser_data = { + .no_mask = false, + .force_hex = true, +}; + +static const struct lookup_entry_u32 duplex_values[] = { + { .arg = "half", .val = DUPLEX_HALF }, + { .arg = "full", .val = DUPLEX_FULL }, + {} +}; + +char wol_bit_chars[WOL_MODE_COUNT] = { + [WAKE_PHY_BIT] = 'p', + [WAKE_UCAST_BIT] = 'u', + [WAKE_MCAST_BIT] = 'm', + [WAKE_BCAST_BIT] = 'b', + [WAKE_ARP_BIT] = 'a', + [WAKE_MAGIC_BIT] = 'g', + [WAKE_MAGICSECURE_BIT] = 's', + [WAKE_FILTER_BIT] = 'f', +}; + +const struct char_bitset_parser_data wol_parser_data = { + .bit_chars = wol_bit_chars, + .nbits = WOL_MODE_COUNT, + .reset_char = 'd', +}; + +const struct byte_str_parser_data sopass_parser_data = { + .min_len = 6, + .max_len = 6, + .delim = ':', +}; + +static const struct bitset_parser_data msglvl_parser_data = { + .no_mask = false, + .force_hex = false, +}; + +static const struct param_parser sset_params[] = { + { + .arg = "port", + .group = ETHTOOL_MSG_LINKINFO_SET, + .type = ETHTOOL_A_LINKINFO_PORT, + .handler = nl_parse_lookup_u8, + .handler_data = port_values, + .min_argc = 1, + }, + { + .arg = "mdix", + .group = ETHTOOL_MSG_LINKINFO_SET, + .type = ETHTOOL_A_LINKINFO_TP_MDIX_CTRL, + .handler = nl_parse_lookup_u8, + .handler_data = mdix_values, + .min_argc = 1, + }, + { + .arg = "phyad", + .group = ETHTOOL_MSG_LINKINFO_SET, + .type = ETHTOOL_A_LINKINFO_PHYADDR, + .handler = nl_parse_direct_u8, + .min_argc = 1, + }, + { + .arg = "xcvr", + .group = ETHTOOL_MSG_LINKINFO_SET, + .handler = nl_parse_error, + .handler_data = &xcvr_parser_data, + .min_argc = 1, + }, + { + .arg = "autoneg", + .group = ETHTOOL_MSG_LINKMODES_SET, + .type = ETHTOOL_A_LINKMODES_AUTONEG, + .handler = nl_parse_lookup_u8, + .handler_data = autoneg_values, + .min_argc = 1, + }, + { + .arg = "advertise", + .group = ETHTOOL_MSG_LINKMODES_SET, + .type = ETHTOOL_A_LINKMODES_OURS, + .handler = nl_parse_bitset, + .handler_data = &advertise_parser_data, + .min_argc = 1, + }, + { + .arg = "speed", + .group = ETHTOOL_MSG_LINKMODES_SET, + .type = ETHTOOL_A_LINKMODES_SPEED, + .handler = nl_parse_direct_u32, + .min_argc = 1, + }, + { + .arg = "duplex", + .group = ETHTOOL_MSG_LINKMODES_SET, + .type = ETHTOOL_A_LINKMODES_DUPLEX, + .handler = nl_parse_lookup_u8, + .handler_data = duplex_values, + .min_argc = 1, + }, + { + .arg = "wol", + .group = ETHTOOL_MSG_WOL_SET, + .type = ETHTOOL_A_WOL_MODES, + .handler = nl_parse_char_bitset, + .handler_data = &wol_parser_data, + .min_argc = 1, + }, + { + .arg = "sopass", + .group = ETHTOOL_MSG_WOL_SET, + .type = ETHTOOL_A_WOL_SOPASS, + .handler = nl_parse_byte_str, + .handler_data = &sopass_parser_data, + .min_argc = 1, + }, + { + .arg = "msglvl", + .group = ETHTOOL_MSG_DEBUG_SET, + .type = ETHTOOL_A_DEBUG_MSGMASK, + .handler = nl_parse_bitset, + .handler_data = &msglvl_parser_data, + .min_argc = 1, + }, + {} +}; + +int nl_sset(struct cmd_context *ctx) +{ + struct nl_context *nlctx = ctx->nlctx; + int ret; + + nlctx->cmd = "-s"; + nlctx->argp = ctx->argp; + nlctx->argc = ctx->argc; + nlctx->devname = ctx->devname; + + ret = nl_parser(nlctx, sset_params, NULL, PARSER_GROUP_MSG); + if (ret < 0) + return 1; + + if (ret == 0) + return 0; + return nlctx->exit_code ?: 75; +} From patchwork Fri Mar 6 17:05:40 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Michal Kubecek X-Patchwork-Id: 222917 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.8 required=3.0 tests=HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SIGNED_OFF_BY, SPF_HELO_NONE, SPF_PASS autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 8537DC10DCE for ; Fri, 6 Mar 2020 17:05:44 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 65B31206E2 for ; Fri, 6 Mar 2020 17:05:44 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726704AbgCFRFn (ORCPT ); Fri, 6 Mar 2020 12:05:43 -0500 Received: from mx2.suse.de ([195.135.220.15]:43850 "EHLO mx2.suse.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726397AbgCFRFn (ORCPT ); Fri, 6 Mar 2020 12:05:43 -0500 X-Virus-Scanned: by amavisd-new at test-mx.suse.de Received: from relay2.suse.de (unknown [195.135.220.254]) by mx2.suse.de (Postfix) with ESMTP id 8F858B152; Fri, 6 Mar 2020 17:05:40 +0000 (UTC) Received: by unicorn.suse.cz (Postfix, from userid 1000) id 3A5BEE00E7; Fri, 6 Mar 2020 18:05:40 +0100 (CET) Message-Id: In-Reply-To: References: From: Michal Kubecek Subject: [PATCH ethtool v3 20/25] netlink: add handler for permaddr (-P) To: John Linville , netdev@vger.kernel.org Cc: Andrew Lunn , Florian Fainelli Date: Fri, 6 Mar 2020 18:05:40 +0100 (CET) Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org Implement "ethtool -P " subcommand. This retrieves and displays information traditionally provided by ETHTOOL_GPERMADDR ioctl request. Permanent hardware address is provided by rtnetlink RTM_GETLINK request so that basic support for rtnetlink (which is not based on genetlink) requests is also added. The IFLA_PERM_ADDRESS attribute in RTM_NEWLINK message is not set if the device driver did not set its permanent hardware address which is hard to distinguish from ethtool running on top of an older kernel not supporting the attribute. As IFLA_PERM_ADDRESS attribute was added to kernel shortly before the initial portion of ethtool netlink interface, we let ethtool initialize ethtool netlink even if it is not needed so that we can fall back to ioctl on older kernels and assume that absence of IFLA_PERM_ADDRESS means the permanent address is not set. This would be only wrong on some distribution kernel which would backport ethtool netlink interface but not IFLA_PERM_ADDRESS which is unlikely. Permanent address is immutable (or not mutable using standard interfaces) so that there is no related notification message. Signed-off-by: Michal Kubecek --- Makefile.am | 1 + ethtool.c | 1 + netlink/extapi.h | 2 + netlink/netlink.h | 8 ++++ netlink/permaddr.c | 114 +++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 126 insertions(+) create mode 100644 netlink/permaddr.c diff --git a/Makefile.am b/Makefile.am index 30cda5b1fc6f..11acdab1a65e 100644 --- a/Makefile.am +++ b/Makefile.am @@ -30,6 +30,7 @@ ethtool_SOURCES += \ netlink/nlsock.h netlink/strset.c netlink/strset.h \ netlink/monitor.c netlink/bitset.c netlink/bitset.h \ netlink/settings.c netlink/parser.c netlink/parser.h \ + netlink/permaddr.c \ uapi/linux/ethtool_netlink.h \ uapi/linux/netlink.h uapi/linux/genetlink.h \ uapi/linux/rtnetlink.h uapi/linux/if_link.h diff --git a/ethtool.c b/ethtool.c index baa6458bb486..1b4e08b6e60f 100644 --- a/ethtool.c +++ b/ethtool.c @@ -5372,6 +5372,7 @@ static const struct option args[] = { { .opts = "-P|--show-permaddr", .func = do_permaddr, + .nlfunc = nl_permaddr, .help = "Show permanent hardware address" }, { diff --git a/netlink/extapi.h b/netlink/extapi.h index 612002e8228b..d5b3cd92d4ab 100644 --- a/netlink/extapi.h +++ b/netlink/extapi.h @@ -17,6 +17,7 @@ void netlink_done(struct cmd_context *ctx); int nl_gset(struct cmd_context *ctx); int nl_sset(struct cmd_context *ctx); +int nl_permaddr(struct cmd_context *ctx); int nl_monitor(struct cmd_context *ctx); void nl_monitor_usage(void); @@ -38,6 +39,7 @@ static inline void nl_monitor_usage(void) #define nl_gset NULL #define nl_sset NULL +#define nl_permaddr NULL #endif /* ETHTOOL_ENABLE_NETLINK */ diff --git a/netlink/netlink.h b/netlink/netlink.h index 3ab5f2329e2f..db078d28fabb 100644 --- a/netlink/netlink.h +++ b/netlink/netlink.h @@ -27,6 +27,7 @@ struct nl_context { uint32_t ethnl_mongrp; struct nl_socket *ethnl_socket; struct nl_socket *ethnl2_socket; + struct nl_socket *rtnl_socket; bool is_monitor; uint32_t filter_cmds[CMDMASK_WORDS]; const char *filter_devname; @@ -76,4 +77,11 @@ static inline int netlink_init_ethnl2_socket(struct nl_context *nlctx) return nlsock_init(nlctx, &nlctx->ethnl2_socket, NETLINK_GENERIC); } +static inline int netlink_init_rtnl_socket(struct nl_context *nlctx) +{ + if (nlctx->rtnl_socket) + return 0; + return nlsock_init(nlctx, &nlctx->rtnl_socket, NETLINK_ROUTE); +} + #endif /* ETHTOOL_NETLINK_INT_H__ */ diff --git a/netlink/permaddr.c b/netlink/permaddr.c new file mode 100644 index 000000000000..006eac6c0094 --- /dev/null +++ b/netlink/permaddr.c @@ -0,0 +1,114 @@ +/* + * permaddr.c - netlink implementation of permanent address request + * + * Implementation of "ethtool -P " + */ + +#include +#include +#include +#include +#include + +#include "../internal.h" +#include "../common.h" +#include "netlink.h" + +/* PERMADDR_GET */ + +static int permaddr_prep_request(struct nl_socket *nlsk) +{ + unsigned int nlm_flags = NLM_F_REQUEST | NLM_F_ACK; + struct nl_context *nlctx = nlsk->nlctx; + const char *devname = nlctx->ctx->devname; + struct nl_msg_buff *msgbuff = &nlsk->msgbuff; + struct ifinfomsg *ifinfo; + struct nlmsghdr *nlhdr; + int ret; + + if (devname && !strcmp(devname, WILDCARD_DEVNAME)) { + devname = NULL; + nlm_flags |= NLM_F_DUMP; + } + nlctx->is_dump = !devname; + + ret = msgbuff_realloc(msgbuff, MNL_SOCKET_BUFFER_SIZE); + if (ret < 0) + return ret; + memset(msgbuff->buff, '\0', NLMSG_HDRLEN + sizeof(*ifinfo)); + + nlhdr = mnl_nlmsg_put_header(msgbuff->buff); + nlhdr->nlmsg_type = RTM_GETLINK; + nlhdr->nlmsg_flags = nlm_flags; + msgbuff->nlhdr = nlhdr; + ifinfo = mnl_nlmsg_put_extra_header(nlhdr, sizeof(*ifinfo)); + + if (devname) { + uint16_t type = IFLA_IFNAME; + + if (strlen(devname) >= IFNAMSIZ) + type = IFLA_ALT_IFNAME; + if (ethnla_put_strz(msgbuff, type, devname)) + return -EMSGSIZE; + } + if (ethnla_put_u32(msgbuff, IFLA_EXT_MASK, RTEXT_FILTER_SKIP_STATS)) + return -EMSGSIZE; + + return 0; +} + +int permaddr_reply_cb(const struct nlmsghdr *nlhdr, void *data) +{ + const struct nlattr *tb[__IFLA_MAX] = {}; + DECLARE_ATTR_TB_INFO(tb); + struct nl_context *nlctx = data; + const uint8_t *permaddr; + unsigned int i; + int ret; + + if (nlhdr->nlmsg_type != RTM_NEWLINK) + goto err; + ret = mnl_attr_parse(nlhdr, sizeof(struct ifinfomsg), attr_cb, + &tb_info); + if (ret < 0 || !tb[IFLA_IFNAME]) + goto err; + nlctx->devname = mnl_attr_get_str(tb[IFLA_IFNAME]); + if (!dev_ok(nlctx)) + goto err; + + if (!tb[IFLA_PERM_ADDRESS]) { + if (!nlctx->is_dump) + printf("Permanent address: not set\n"); + return MNL_CB_OK; + } + + if (nlctx->is_dump) + printf("Permanent address of %s:", nlctx->devname); + else + printf("Permanent address:"); + permaddr = mnl_attr_get_payload(tb[IFLA_PERM_ADDRESS]); + for (i = 0; i < mnl_attr_get_payload_len(tb[IFLA_PERM_ADDRESS]); i++) + printf("%c%02x", i ? ':' : ' ', permaddr[i]); + putchar('\n'); + return MNL_CB_OK; + +err: + if (nlctx->is_dump || nlctx->is_monitor) + return MNL_CB_OK; + nlctx->exit_code = 2; + return MNL_CB_ERROR; +} + +int nl_permaddr(struct cmd_context *ctx) +{ + struct nl_context *nlctx = ctx->nlctx; + int ret; + + ret = netlink_init_rtnl_socket(nlctx); + if (ret < 0) + return ret; + ret = permaddr_prep_request(nlctx->rtnl_socket); + if (ret < 0) + return ret; + return nlsock_send_get_request(nlctx->rtnl_socket, permaddr_reply_cb); +} From patchwork Fri Mar 6 17:05:50 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Michal Kubecek X-Patchwork-Id: 222916 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.0 required=3.0 tests=HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SIGNED_OFF_BY, SPF_HELO_NONE, SPF_PASS, UPPERCASE_50_75 autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id E1BD1C10DCE for ; Fri, 6 Mar 2020 17:05:54 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id B84A620709 for ; Fri, 6 Mar 2020 17:05:54 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727252AbgCFRFy (ORCPT ); Fri, 6 Mar 2020 12:05:54 -0500 Received: from mx2.suse.de ([195.135.220.15]:43910 "EHLO mx2.suse.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726397AbgCFRFx (ORCPT ); Fri, 6 Mar 2020 12:05:53 -0500 X-Virus-Scanned: by amavisd-new at test-mx.suse.de Received: from relay2.suse.de (unknown [195.135.220.254]) by mx2.suse.de (Postfix) with ESMTP id 546A1B374; Fri, 6 Mar 2020 17:05:51 +0000 (UTC) Received: by unicorn.suse.cz (Postfix, from userid 1000) id 47149E00E7; Fri, 6 Mar 2020 18:05:50 +0100 (CET) Message-Id: <0d2a147aa6373af3d586eed4eb54a56a4b2aa8f5.1583513281.git.mkubecek@suse.cz> In-Reply-To: References: From: Michal Kubecek Subject: [PATCH ethtool v3 22/25] netlink: message format description for ethtool netlink To: John Linville , netdev@vger.kernel.org Cc: Andrew Lunn , Florian Fainelli Date: Fri, 6 Mar 2020 18:05:50 +0100 (CET) Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org Add description of ethtool netlink message formats to be used for pretty printing infrastructure. These arrays map (numeric) attribute types to their symbolic names and format of their payload so that attributes can be displayed in human friendly form. Signed-off-by: Michal Kubecek --- Makefile.am | 1 + netlink/desc-ethtool.c | 139 +++++++++++++++++++++++++++++++++++++++++ netlink/prettymsg.h | 7 +++ 3 files changed, 147 insertions(+) create mode 100644 netlink/desc-ethtool.c diff --git a/Makefile.am b/Makefile.am index d745471e53b1..5654b273a0a0 100644 --- a/Makefile.am +++ b/Makefile.am @@ -31,6 +31,7 @@ ethtool_SOURCES += \ netlink/monitor.c netlink/bitset.c netlink/bitset.h \ netlink/settings.c netlink/parser.c netlink/parser.h \ netlink/permaddr.c netlink/prettymsg.c netlink/prettymsg.h \ + netlink/desc-ethtool.c \ uapi/linux/ethtool_netlink.h \ uapi/linux/netlink.h uapi/linux/genetlink.h \ uapi/linux/rtnetlink.h uapi/linux/if_link.h diff --git a/netlink/desc-ethtool.c b/netlink/desc-ethtool.c new file mode 100644 index 000000000000..76c6f13e4648 --- /dev/null +++ b/netlink/desc-ethtool.c @@ -0,0 +1,139 @@ +/* + * desc-ethtool.c - ethtool netlink format descriptions + * + * Descriptions of ethtool netlink messages and attributes for pretty print. + */ + +#include + +#include "../internal.h" +#include "prettymsg.h" + +static const struct pretty_nla_desc __header_desc[] = { + NLATTR_DESC_INVALID(ETHTOOL_A_HEADER_UNSPEC), + NLATTR_DESC_U32(ETHTOOL_A_HEADER_DEV_INDEX), + NLATTR_DESC_STRING(ETHTOOL_A_HEADER_DEV_NAME), + NLATTR_DESC_X32(ETHTOOL_A_HEADER_FLAGS), +}; + +static const struct pretty_nla_desc __bitset_bit_desc[] = { + NLATTR_DESC_INVALID(ETHTOOL_A_BITSET_BIT_UNSPEC), + NLATTR_DESC_U32(ETHTOOL_A_BITSET_BIT_INDEX), + NLATTR_DESC_STRING(ETHTOOL_A_BITSET_BIT_NAME), + NLATTR_DESC_FLAG(ETHTOOL_A_BITSET_BIT_VALUE), +}; + +static const struct pretty_nla_desc __bitset_bits_desc[] = { + NLATTR_DESC_INVALID(ETHTOOL_A_BITSET_BITS_UNSPEC), + NLATTR_DESC_NESTED(ETHTOOL_A_BITSET_BITS_BIT, bitset_bit), +}; + +static const struct pretty_nla_desc __bitset_desc[] = { + NLATTR_DESC_INVALID(ETHTOOL_A_BITSET_UNSPEC), + NLATTR_DESC_FLAG(ETHTOOL_A_BITSET_NOMASK), + NLATTR_DESC_U32(ETHTOOL_A_BITSET_SIZE), + NLATTR_DESC_NESTED(ETHTOOL_A_BITSET_BITS, bitset_bits), + NLATTR_DESC_BINARY(ETHTOOL_A_BITSET_VALUE), + NLATTR_DESC_BINARY(ETHTOOL_A_BITSET_MASK), +}; + +static const struct pretty_nla_desc __string_desc[] = { + NLATTR_DESC_INVALID(ETHTOOL_A_STRING_UNSPEC), + NLATTR_DESC_U32(ETHTOOL_A_STRING_INDEX), + NLATTR_DESC_STRING(ETHTOOL_A_STRING_VALUE), +}; + +static const struct pretty_nla_desc __strings_desc[] = { + NLATTR_DESC_INVALID(ETHTOOL_A_STRINGS_UNSPEC), + NLATTR_DESC_NESTED(ETHTOOL_A_STRINGS_STRING, string), +}; + +static const struct pretty_nla_desc __stringset_desc[] = { + NLATTR_DESC_INVALID(ETHTOOL_A_STRINGSET_UNSPEC), + NLATTR_DESC_U32(ETHTOOL_A_STRINGSET_ID), + NLATTR_DESC_U32(ETHTOOL_A_STRINGSET_COUNT), + NLATTR_DESC_NESTED(ETHTOOL_A_STRINGSET_STRINGS, strings), +}; + +static const struct pretty_nla_desc __stringsets_desc[] = { + NLATTR_DESC_INVALID(ETHTOOL_A_STRINGSETS_UNSPEC), + NLATTR_DESC_NESTED(ETHTOOL_A_STRINGSETS_STRINGSET, stringset), +}; + +static const struct pretty_nla_desc __strset_desc[] = { + NLATTR_DESC_INVALID(ETHTOOL_A_STRSET_UNSPEC), + NLATTR_DESC_NESTED(ETHTOOL_A_STRSET_HEADER, header), + NLATTR_DESC_NESTED(ETHTOOL_A_STRSET_STRINGSETS, stringsets), + NLATTR_DESC_FLAG(ETHTOOL_A_STRSET_COUNTS_ONLY), +}; + +static const struct pretty_nla_desc __linkinfo_desc[] = { + NLATTR_DESC_INVALID(ETHTOOL_A_LINKINFO_UNSPEC), + NLATTR_DESC_NESTED(ETHTOOL_A_LINKINFO_HEADER, header), + NLATTR_DESC_U8(ETHTOOL_A_LINKINFO_PORT), + NLATTR_DESC_U8(ETHTOOL_A_LINKINFO_PHYADDR), + NLATTR_DESC_U8(ETHTOOL_A_LINKINFO_TP_MDIX), + NLATTR_DESC_U8(ETHTOOL_A_LINKINFO_TP_MDIX_CTRL), + NLATTR_DESC_U8(ETHTOOL_A_LINKINFO_TRANSCEIVER), +}; + +static const struct pretty_nla_desc __linkmodes_desc[] = { + NLATTR_DESC_INVALID(ETHTOOL_A_LINKMODES_UNSPEC), + NLATTR_DESC_NESTED(ETHTOOL_A_LINKMODES_HEADER, header), + NLATTR_DESC_BOOL(ETHTOOL_A_LINKMODES_AUTONEG), + NLATTR_DESC_NESTED(ETHTOOL_A_LINKMODES_OURS, bitset), + NLATTR_DESC_NESTED(ETHTOOL_A_LINKMODES_PEER, bitset), + NLATTR_DESC_U32(ETHTOOL_A_LINKMODES_SPEED), + NLATTR_DESC_U8(ETHTOOL_A_LINKMODES_DUPLEX), +}; + +static const struct pretty_nla_desc __linkstate_desc[] = { + NLATTR_DESC_INVALID(ETHTOOL_A_LINKSTATE_UNSPEC), + NLATTR_DESC_NESTED(ETHTOOL_A_LINKSTATE_HEADER, header), + NLATTR_DESC_BOOL(ETHTOOL_A_LINKSTATE_LINK), +}; + +static const struct pretty_nla_desc __debug_desc[] = { + NLATTR_DESC_INVALID(ETHTOOL_A_DEBUG_UNSPEC), + NLATTR_DESC_NESTED(ETHTOOL_A_DEBUG_HEADER, header), + NLATTR_DESC_NESTED(ETHTOOL_A_DEBUG_MSGMASK, bitset), +}; + +static const struct pretty_nla_desc __wol_desc[] = { + NLATTR_DESC_INVALID(ETHTOOL_A_WOL_UNSPEC), + NLATTR_DESC_NESTED(ETHTOOL_A_WOL_HEADER, header), + NLATTR_DESC_NESTED(ETHTOOL_A_WOL_MODES, bitset), + NLATTR_DESC_BINARY(ETHTOOL_A_WOL_SOPASS), +}; + +const struct pretty_nlmsg_desc ethnl_umsg_desc[] = { + NLMSG_DESC_INVALID(ETHTOOL_MSG_USER_NONE), + NLMSG_DESC(ETHTOOL_MSG_STRSET_GET, strset), + NLMSG_DESC(ETHTOOL_MSG_LINKINFO_GET, linkinfo), + NLMSG_DESC(ETHTOOL_MSG_LINKINFO_SET, linkinfo), + NLMSG_DESC(ETHTOOL_MSG_LINKMODES_GET, linkmodes), + NLMSG_DESC(ETHTOOL_MSG_LINKMODES_SET, linkmodes), + NLMSG_DESC(ETHTOOL_MSG_LINKSTATE_GET, linkstate), + NLMSG_DESC(ETHTOOL_MSG_DEBUG_GET, debug), + NLMSG_DESC(ETHTOOL_MSG_DEBUG_SET, debug), + NLMSG_DESC(ETHTOOL_MSG_WOL_GET, wol), + NLMSG_DESC(ETHTOOL_MSG_WOL_SET, wol), +}; + +const unsigned int ethnl_umsg_n_desc = ARRAY_SIZE(ethnl_umsg_desc); + +const struct pretty_nlmsg_desc ethnl_kmsg_desc[] = { + NLMSG_DESC_INVALID(ETHTOOL_MSG_KERNEL_NONE), + NLMSG_DESC(ETHTOOL_MSG_STRSET_GET_REPLY, strset), + NLMSG_DESC(ETHTOOL_MSG_LINKINFO_GET_REPLY, linkinfo), + NLMSG_DESC(ETHTOOL_MSG_LINKINFO_NTF, linkinfo), + NLMSG_DESC(ETHTOOL_MSG_LINKMODES_GET_REPLY, linkmodes), + NLMSG_DESC(ETHTOOL_MSG_LINKMODES_NTF, linkmodes), + NLMSG_DESC(ETHTOOL_MSG_LINKSTATE_GET_REPLY, linkstate), + NLMSG_DESC(ETHTOOL_MSG_DEBUG_GET_REPLY, debug), + NLMSG_DESC(ETHTOOL_MSG_DEBUG_NTF, debug), + NLMSG_DESC(ETHTOOL_MSG_WOL_GET_REPLY, wol), + NLMSG_DESC(ETHTOOL_MSG_WOL_NTF, wol), +}; + +const unsigned int ethnl_kmsg_n_desc = ARRAY_SIZE(ethnl_kmsg_desc); diff --git a/netlink/prettymsg.h b/netlink/prettymsg.h index 68ec275a22f6..9d8ca77fd42c 100644 --- a/netlink/prettymsg.h +++ b/netlink/prettymsg.h @@ -99,4 +99,11 @@ int pretty_print_genlmsg(const struct nlmsghdr *nlhdr, const struct pretty_nlmsg_desc *desc, unsigned int ndesc, unsigned int err_offset); +/* message descriptions */ + +extern const struct pretty_nlmsg_desc ethnl_umsg_desc[]; +extern const unsigned int ethnl_umsg_n_desc; +extern const struct pretty_nlmsg_desc ethnl_kmsg_desc[]; +extern const unsigned int ethnl_kmsg_n_desc; + #endif /* ETHTOOL_NETLINK_PRETTYMSG_H__ */ From patchwork Fri Mar 6 17:06:00 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Michal Kubecek X-Patchwork-Id: 222915 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.8 required=3.0 tests=HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SIGNED_OFF_BY, SPF_HELO_NONE, SPF_PASS autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id CC250C10F25 for ; Fri, 6 Mar 2020 17:06:57 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id A708F20717 for ; Fri, 6 Mar 2020 17:06:57 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726905AbgCFRG5 (ORCPT ); Fri, 6 Mar 2020 12:06:57 -0500 Received: from mx2.suse.de ([195.135.220.15]:44368 "EHLO mx2.suse.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726368AbgCFRG4 (ORCPT ); Fri, 6 Mar 2020 12:06:56 -0500 X-Virus-Scanned: by amavisd-new at test-mx.suse.de Received: from relay2.suse.de (unknown [195.135.220.254]) by mx2.suse.de (Postfix) with ESMTP id A4ED5B381; Fri, 6 Mar 2020 17:06:00 +0000 (UTC) Received: by unicorn.suse.cz (Postfix, from userid 1000) id 53AF2E00E7; Fri, 6 Mar 2020 18:06:00 +0100 (CET) Message-Id: <5142c96fa91a5c08bfcb46edae99dd6835db24b5.1583513281.git.mkubecek@suse.cz> In-Reply-To: References: From: Michal Kubecek Subject: [PATCH ethtool v3 24/25] netlink: message format descriptions for rtnetlink To: John Linville , netdev@vger.kernel.org Cc: Andrew Lunn , Florian Fainelli Date: Fri, 6 Mar 2020 18:06:00 +0100 (CET) Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org Add description of rtnetlink message formats to be used for pretty printing infrastructure and helper function to pretty print rtnetlink messages. As rtnetlink is quite complex and only RTM_GETLINK and RTM_NEWLINK messages are interesting for ethtool at the moment, this commit provides only names of a limited subset of rtnetlink messages and names and formats of top level attributes used in RTM_{NEW,DEL,GET,SET}LINK messages. Signed-off-by: Michal Kubecek --- Makefile.am | 1 + netlink/desc-rtnl.c | 96 +++++++++++++++++++++++++++++++++++++++++++++ netlink/prettymsg.c | 44 +++++++++++++++++++++ netlink/prettymsg.h | 6 +++ 4 files changed, 147 insertions(+) create mode 100644 netlink/desc-rtnl.c diff --git a/Makefile.am b/Makefile.am index 8d99315c4b0d..0f8465f7ada9 100644 --- a/Makefile.am +++ b/Makefile.am @@ -32,6 +32,7 @@ ethtool_SOURCES += \ netlink/settings.c netlink/parser.c netlink/parser.h \ netlink/permaddr.c netlink/prettymsg.c netlink/prettymsg.h \ netlink/desc-ethtool.c netlink/desc-genlctrl.c \ + netlink/desc-rtnl.c \ uapi/linux/ethtool_netlink.h \ uapi/linux/netlink.h uapi/linux/genetlink.h \ uapi/linux/rtnetlink.h uapi/linux/if_link.h diff --git a/netlink/desc-rtnl.c b/netlink/desc-rtnl.c new file mode 100644 index 000000000000..e15e6f0f0d2e --- /dev/null +++ b/netlink/desc-rtnl.c @@ -0,0 +1,96 @@ +/* + * desc-rtnl.c - rtnetlink message descriptions + * + * Descriptions of rtnetlink messages and attributes for pretty print. + */ + +#include + +#include "../internal.h" +#include "prettymsg.h" + +static const struct pretty_nla_desc __link_desc[] = { + NLATTR_DESC_INVALID(IFLA_UNSPEC), + NLATTR_DESC_BINARY(IFLA_ADDRESS), + NLATTR_DESC_BINARY(IFLA_BROADCAST), + NLATTR_DESC_STRING(IFLA_IFNAME), + NLATTR_DESC_U32(IFLA_MTU), + NLATTR_DESC_U32(IFLA_LINK), + NLATTR_DESC_STRING(IFLA_QDISC), + NLATTR_DESC_BINARY(IFLA_STATS), + NLATTR_DESC_INVALID(IFLA_COST), + NLATTR_DESC_INVALID(IFLA_PRIORITY), + NLATTR_DESC_U32(IFLA_MASTER), + NLATTR_DESC_BINARY(IFLA_WIRELESS), + NLATTR_DESC_NESTED_NODESC(IFLA_PROTINFO), + NLATTR_DESC_U32(IFLA_TXQLEN), + NLATTR_DESC_BINARY(IFLA_MAP), + NLATTR_DESC_U32(IFLA_WEIGHT), + NLATTR_DESC_U8(IFLA_OPERSTATE), + NLATTR_DESC_U8(IFLA_LINKMODE), + NLATTR_DESC_NESTED_NODESC(IFLA_LINKINFO), + NLATTR_DESC_U32(IFLA_NET_NS_PID), + NLATTR_DESC_STRING(IFLA_IFALIAS), + NLATTR_DESC_U32(IFLA_NUM_VF), + NLATTR_DESC_NESTED_NODESC(IFLA_VFINFO_LIST), + NLATTR_DESC_BINARY(IFLA_STATS64), + NLATTR_DESC_NESTED_NODESC(IFLA_VF_PORTS), + NLATTR_DESC_NESTED_NODESC(IFLA_PORT_SELF), + NLATTR_DESC_NESTED_NODESC(IFLA_AF_SPEC), + NLATTR_DESC_U32(IFLA_GROUP), + NLATTR_DESC_U32(IFLA_NET_NS_FD), + NLATTR_DESC_U32(IFLA_EXT_MASK), + NLATTR_DESC_U32(IFLA_PROMISCUITY), + NLATTR_DESC_U32(IFLA_NUM_TX_QUEUES), + NLATTR_DESC_U32(IFLA_NUM_RX_QUEUES), + NLATTR_DESC_U8(IFLA_CARRIER), + NLATTR_DESC_BINARY(IFLA_PHYS_PORT_ID), + NLATTR_DESC_U32(IFLA_CARRIER_CHANGES), + NLATTR_DESC_BINARY(IFLA_PHYS_SWITCH_ID), + NLATTR_DESC_S32(IFLA_LINK_NETNSID), + NLATTR_DESC_STRING(IFLA_PHYS_PORT_NAME), + NLATTR_DESC_U8(IFLA_PROTO_DOWN), + NLATTR_DESC_U32(IFLA_GSO_MAX_SEGS), + NLATTR_DESC_U32(IFLA_GSO_MAX_SIZE), + NLATTR_DESC_BINARY(IFLA_PAD), + NLATTR_DESC_U32(IFLA_XDP), + NLATTR_DESC_U32(IFLA_EVENT), + NLATTR_DESC_S32(IFLA_NEW_NETNSID), + NLATTR_DESC_S32(IFLA_IF_NETNSID), + NLATTR_DESC_U32(IFLA_CARRIER_UP_COUNT), + NLATTR_DESC_U32(IFLA_CARRIER_DOWN_COUNT), + NLATTR_DESC_S32(IFLA_NEW_IFINDEX), + NLATTR_DESC_U32(IFLA_MIN_MTU), + NLATTR_DESC_U32(IFLA_MAX_MTU), + NLATTR_DESC_NESTED_NODESC(IFLA_PROP_LIST), + NLATTR_DESC_STRING(IFLA_ALT_IFNAME), + NLATTR_DESC_BINARY(IFLA_PERM_ADDRESS), +}; + +const struct pretty_nlmsg_desc rtnl_msg_desc[] = { + NLMSG_DESC(RTM_NEWLINK, link), + NLMSG_DESC(RTM_DELLINK, link), + NLMSG_DESC(RTM_GETLINK, link), + NLMSG_DESC(RTM_SETLINK, link), +}; + +const unsigned int rtnl_msg_n_desc = ARRAY_SIZE(rtnl_msg_desc); + +#define RTNL_MSGHDR_LEN(_name, _struct) \ + [((RTM_ ## _name) - RTM_BASE) / 4] = sizeof(struct _struct) +#define RTNL_MSGHDR_NOLEN(_name) \ + [((RTM_ ## _name) - RTM_BASE) / 4] = USHRT_MAX + +const unsigned short rtnl_msghdr_lengths[] = { + RTNL_MSGHDR_LEN(NEWLINK, ifinfomsg), + RTNL_MSGHDR_LEN(NEWADDR, ifaddrmsg), + RTNL_MSGHDR_LEN(NEWROUTE, rtmsg), + RTNL_MSGHDR_LEN(NEWNEIGH, ndmsg), + RTNL_MSGHDR_LEN(NEWRULE, rtmsg), + RTNL_MSGHDR_LEN(NEWQDISC, tcmsg), + RTNL_MSGHDR_LEN(NEWTCLASS, tcmsg), + RTNL_MSGHDR_LEN(NEWTFILTER, tcmsg), + RTNL_MSGHDR_LEN(NEWACTION, tcamsg), +}; + +const unsigned int rtnl_msghdr_n_len = ARRAY_SIZE(rtnl_msghdr_lengths); diff --git a/netlink/prettymsg.c b/netlink/prettymsg.c index 74fe6f2db7ed..9e62bebe615e 100644 --- a/netlink/prettymsg.c +++ b/netlink/prettymsg.c @@ -191,3 +191,47 @@ int pretty_print_genlmsg(const struct nlmsghdr *nlhdr, msg_desc ? msg_desc->attrs : NULL, msg_desc ? msg_desc->n_attrs : 0, err_offset); } + +static void rtm_link_summary(const struct ifinfomsg *ifinfo) +{ + if (ifinfo->ifi_family) + printf(" family=%u", ifinfo->ifi_family); + if (ifinfo->ifi_type) + printf(" type=0x%04x", ifinfo->ifi_type); + if (ifinfo->ifi_index) + printf(" ifindex=%d", ifinfo->ifi_index); + if (ifinfo->ifi_flags) + printf(" flags=0x%x", ifinfo->ifi_flags); + if (ifinfo->ifi_flags) + printf(" change=0x%x", ifinfo->ifi_change); +} + +int pretty_print_rtnlmsg(const struct nlmsghdr *nlhdr, unsigned int err_offset) +{ + const unsigned int idx = (nlhdr->nlmsg_type - RTM_BASE) / 4; + const struct pretty_nlmsg_desc *msg_desc = NULL; + unsigned int hdrlen = USHRT_MAX; + + if (nlhdr->nlmsg_type < rtnl_msg_n_desc) + msg_desc = &rtnl_msg_desc[nlhdr->nlmsg_type]; + if (idx < rtnl_msghdr_n_len) + hdrlen = rtnl_msghdr_lengths[idx]; + if (hdrlen < USHRT_MAX && mnl_nlmsg_get_payload_len(nlhdr) < hdrlen) { + fprintf(stderr, "ethtool: message too short (%u bytes)\n", + nlhdr->nlmsg_len); + return -EINVAL; + } + if (msg_desc && msg_desc->name) + printf(" %s", msg_desc->name); + else + printf(" [%u]", nlhdr->nlmsg_type); + if (idx == (RTM_NEWLINK - RTM_BASE) / 4) + rtm_link_summary(mnl_nlmsg_get_payload(nlhdr)); + putchar('\n'); + if (hdrlen == USHRT_MAX) + return 0; + + return pretty_print_nlmsg(nlhdr, hdrlen, + msg_desc ? msg_desc->attrs : NULL, + msg_desc ? msg_desc->n_attrs : 0, err_offset); +} diff --git a/netlink/prettymsg.h b/netlink/prettymsg.h index 50d0bbf43665..b5e5f735ac8a 100644 --- a/netlink/prettymsg.h +++ b/netlink/prettymsg.h @@ -98,6 +98,7 @@ struct pretty_nlmsg_desc { int pretty_print_genlmsg(const struct nlmsghdr *nlhdr, const struct pretty_nlmsg_desc *desc, unsigned int ndesc, unsigned int err_offset); +int pretty_print_rtnlmsg(const struct nlmsghdr *nlhdr, unsigned int err_offset); /* message descriptions */ @@ -109,4 +110,9 @@ extern const unsigned int ethnl_kmsg_n_desc; extern const struct pretty_nlmsg_desc genlctrl_msg_desc[]; extern const unsigned int genlctrl_msg_n_desc; +extern const struct pretty_nlmsg_desc rtnl_msg_desc[]; +extern const unsigned int rtnl_msg_n_desc; +extern const unsigned short rtnl_msghdr_lengths[]; +extern const unsigned int rtnl_msghdr_n_len; + #endif /* ETHTOOL_NETLINK_PRETTYMSG_H__ */