]> git.ipfire.org Git - thirdparty/iproute2.git/log
thirdparty/iproute2.git
23 months agoAdd get_long utility and adapt get_integer accordingly
Mathieu Schroeter [Tue, 8 Aug 2023 21:42:55 +0000 (23:42 +0200)] 
Add get_long utility and adapt get_integer accordingly

Signed-off-by: Mathieu Schroeter <mathieu@schroetersa.ch>
Signed-off-by: David Ahern <dsahern@kernel.org>
23 months agodevlink: accept "name" command line option instead of "trap"/"group"
Jiri Pirko [Thu, 10 Aug 2023 14:01:02 +0000 (16:01 +0200)] 
devlink: accept "name" command line option instead of "trap"/"group"

It is common for all iproute2 apps to have command line option
names matching with show command outputs. However, that is not true
in case of trap and trap group devlink objects.

Correct would be to have "trap" and "group" in the outputs, but that is
not possible to change now. Instead of that, accept "name" instead of
"trap" and "group" options.

Examples:

$ devlink trap show netdevsim/netdevsim1
netdevsim/netdevsim1:
  name source_mac_is_multicast type drop generic true action drop group l2_drops
  name vlan_tag_mismatch type drop generic true action drop group l2_drops
  name ingress_vlan_filter type drop generic true action drop group l2_drops
  name ingress_spanning_tree_filter type drop generic true action drop group l2_drops
  name port_list_is_empty type drop generic true action drop group l2_drops
  name port_loopback_filter type drop generic true action drop group l2_drops
  name fid_miss type exception generic false action trap group l2_drops
  name blackhole_route type drop generic true action drop group l3_drops
  name ttl_value_is_too_small type exception generic true action trap group l3_exceptions
  name tail_drop type drop generic true action drop group buffer_drops
  name ingress_flow_action_drop type drop generic true action drop group acl_drops
  name egress_flow_action_drop type drop generic true action drop group acl_drops
  name igmp_query type control generic true action mirror group mc_snooping
  name igmp_v1_report type control generic true action trap group mc_snooping
$ devlink trap show netdevsim/netdevsim1 trap source_mac_is_multicast
netdevsim/netdevsim1:
  name source_mac_is_multicast type drop generic true action drop group l2_drops
$ devlink trap show netdevsim/netdevsim1 name source_mac_is_multicast
netdevsim/netdevsim1:
  name source_mac_is_multicast type drop generic true action drop group l2_drops

$ devlink trap group
netdevsim/netdevsim1:
  name l2_drops generic true
  name l3_drops generic true policer 1
  name l3_exceptions generic true policer 1
  name buffer_drops generic true policer 2
  name acl_drops generic true policer 3
  name mc_snooping generic true policer 3
$ devlink trap group show netdevsim/netdevsim1 group l2_drops
netdevsim/netdevsim1:
  name l2_drops generic true
$ devlink trap group show netdevsim/netdevsim1 name l2_drops
  name l2_drops generic true

Signed-off-by: Jiri Pirko <jiri@nvidia.com>
Signed-off-by: David Ahern <dsahern@kernel.org>
2 years agotc: Classifier support for SPI field
Ratheesh Kannoth [Wed, 2 Aug 2023 15:49:41 +0000 (21:19 +0530)] 
tc: Classifier support for SPI field

tc flower support for SPI field in ESP and AH packets.

Signed-off-by: Ratheesh Kannoth <rkannoth@marvell.com>
Signed-off-by: David Ahern <dsahern@kernel.org>
2 years agobridge: Add backup nexthop ID support
Ido Schimmel [Wed, 2 Aug 2023 16:41:15 +0000 (19:41 +0300)] 
bridge: Add backup nexthop ID support

Extend the bridge and ip utilities to set and show the backup nexthop ID
bridge port attribute. A value of 0 (default) disables the feature, in
which case the attribute is not printed since it is not emitted by the
kernel.

Example:

 # bridge -d link show dev swp1 | grep -o "backup_nhid [0-9]*"
 # bridge -d -j -p link show dev swp1 | jq '.[]["backup_nhid"]'
 null

 # bridge link set dev swp1 backup_nhid 10
 # bridge -d link show dev swp1 | grep -o "backup_nhid [0-9]*"
 backup_nhid 10
 # bridge -d -j -p link show dev swp1 | jq '.[]["backup_nhid"]'
 10

 # bridge link set dev swp1 backup_nhid 0
 # bridge -d link show dev swp1 | grep -o "backup_nhid [0-9]*"
 # bridge -d -j -p link show dev swp1 | jq '.[]["backup_nhid"]'
 null

 # ip -d link show dev swp1 | grep -o "backup_nhid [0-9]*"
 # ip -d -j -p lin show dev swp1 | jq '.[]["linkinfo"]["info_slave_data"]["backup_nhid"]'
 null

 # ip link set dev swp1 type bridge_slave backup_nhid 10
 # ip -d link show dev swp1 | grep -o "backup_nhid [0-9]*"
 backup_nhid 10
 # ip -d -j -p lin show dev swp1 | jq '.[]["linkinfo"]["info_slave_data"]["backup_nhid"]'
 10

 # ip link set dev swp1 type bridge_slave backup_nhid 0
 # ip -d link show dev swp1 | grep -o "backup_nhid [0-9]*"
 # ip -d -j -p lin show dev swp1 | jq '.[]["linkinfo"]["info_slave_data"]["backup_nhid"]'
 null

Signed-off-by: Ido Schimmel <idosch@nvidia.com>
Reviewed-by: Petr Machata <petrm@nvidia.com>
Signed-off-by: David Ahern <dsahern@kernel.org>
2 years agoMerge remote-tracking branch 'main/main' into next
David Ahern [Wed, 2 Aug 2023 15:28:53 +0000 (09:28 -0600)] 
Merge remote-tracking branch 'main/main' into next

Signed-off-by: David Ahern <dsahern@kernel.org>
2 years agoUpdate kernel headers
David Ahern [Wed, 2 Aug 2023 15:27:51 +0000 (09:27 -0600)] 
Update kernel headers

Update kernel headers to commit:
    34093c9fa05d ("net: Remove duplicated include in mac.c")

Signed-off-by: David Ahern <dsahern@kernel.org>
2 years agoip: error out if iplink does not consume all options
Jakub Kicinski [Mon, 31 Jul 2023 16:19:20 +0000 (09:19 -0700)] 
ip: error out if iplink does not consume all options

dummy does not define .parse_opt, which make ip ignore all
trailing arguments, for example:

 # ip link add type dummy a b c d e f name cheese

will work just fine (and won't call the device "cheese").
Error out in this case with a clear error message:

 # ip link add type dummy a b c d e f name cheese
 Garbage instead of arguments "a ...". Try "ip link help".

Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
2 years agobridge: link: allow filtering on bridge name
Nicolas Escande [Wed, 26 Jul 2023 07:25:07 +0000 (09:25 +0200)] 
bridge: link: allow filtering on bridge name

When using 'brige link show' we can either dump all links enslaved to any bridge
(called without arg ) or display a single link (called with dev arg).
However there is no way to dummp all links of a single bridge.

To do so, this adds new optional 'master XXX' arg to 'bridge link show' command.
usage: bridge link show master br0

Signed-off-by: Nicolas Escande <nico.escande@gmail.com>
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
2 years agoRead configuration files from /etc and /usr
Gioele Barabucci [Wed, 26 Jul 2023 06:14:09 +0000 (08:14 +0200)] 
Read configuration files from /etc and /usr

Add support for the so called "stateless" configuration pattern (read
from /etc, fall back to /usr), giving system administrators a way to
define local configuration without changing any distro-provided files.

In practice this means that each configuration file FOO is loaded
from /usr/lib/iproute2/FOO unless /etc/iproute2/FOO exists.

Signed-off-by: Gioele Barabucci <gioele@svario.it>
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
2 years agoman: (ss) fix wrong margin
Masatake YAMATO [Sun, 23 Jul 2023 16:42:57 +0000 (01:42 +0900)] 
man: (ss) fix wrong margin

Signed-off-by: Masatake YAMATO <yamato@redhat.com>
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
2 years agotc: fix a wrong file name in comment
Masatake YAMATO [Sun, 23 Jul 2023 16:42:56 +0000 (01:42 +0900)] 
tc: fix a wrong file name in comment

Signed-off-by: Masatake YAMATO <yamato@redhat.com>
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
2 years agobridge/mdb.c: include limits.h
Trevor Gamblin [Thu, 20 Jul 2023 20:37:26 +0000 (16:37 -0400)] 
bridge/mdb.c: include limits.h

While building iproute2 6.4.0 with musl using Yocto Project, errors such
as the following were encountered:

| mdb.c: In function 'mdb_parse_vni':
| mdb.c:666:47: error: 'ULONG_MAX' undeclared (first use in this function)
|   666 |         if ((endptr && *endptr) || vni_num == ULONG_MAX)
|       |                                               ^~~~~~~~~
| mdb.c:666:47: note: 'ULONG_MAX' is defined in header '<limits.h>'; did you forget to '#include <limits.h>'?

Include limits.h in bridge/mdb.c to fix this issue. This change is based
on one in Alpine Linux, but the author there had no plans to submit:
https://git.alpinelinux.org/aports/commit/main/iproute2/include.patch?id=bd46efb8a8da54948639cebcfa5b37bd608f1069

Signed-off-by: Trevor Gamblin <tgamblin@baylibre.com>
Reviewed-by: Ido Schimmel <idosch@nvidia.com>
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
2 years agomisc/ifstat: fix incorrect output data in json mode
Chander Govindarajan [Tue, 25 Jul 2023 01:23:48 +0000 (18:23 -0700)] 
misc/ifstat: fix incorrect output data in json mode

Due to this bug, in json mode (with the -j flag), the output was
always in absolute mode (as if passing in the -a flag) and not in
relative mode.

Signed-off-by: Chander Govindarajan <mail@chandergovind.org>
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
2 years agoAdd missing SPDX headers
Stephen Hemminger [Sat, 22 Jul 2023 02:41:37 +0000 (19:41 -0700)] 
Add missing SPDX headers

All headers and source in iproute2 should be using SPDX license info.
Add a couple that were missed, and take off boilerplate.

Acked-by: Daniel Borkmann <daniel@iogearbox.net>
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
2 years agoinclude: dual license the bpf helper includes
Stephen Hemminger [Sat, 22 Jul 2023 02:38:52 +0000 (19:38 -0700)] 
include: dual license the bpf helper includes

The files bpf_api.h and bpf_elf.h are useful for TC BPF programs
to use. And there is no requirement that those be GPL only;
we intend to allow BSD licensed BPF helpers as well.

This makes the file license same as libbpf.

Acked-by: Daniel Borkmann <daniel@iogearbox.net>
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
2 years agomisc/ifstat: fix incorrect output data in json mode
Chander Govindarajan [Mon, 17 Jul 2023 09:32:46 +0000 (15:02 +0530)] 
misc/ifstat: fix incorrect output data in json mode

Due to this bug, in json mode (with the -j flag), the output was
always in absolute mode (as if passing in the -a flag) and not in
relative mode.

Signed-off-by: Chander Govindarajan <mail@chandergovind.org>
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
2 years agof_flower: Treat port 0 as valid
Ido Schimmel [Tue, 11 Jul 2023 06:59:03 +0000 (09:59 +0300)] 
f_flower: Treat port 0 as valid

It is not currently possible to add a filter matching on port 0 despite
it being a valid port number. This is caused by cited commit which
treats a value of 0 as an indication that the port was not specified.

Instead of inferring that a port range was specified by checking that both
the minimum and the maximum ports are non-zero, simply add a boolean
argument to parse_range() and set it after parsing a port range.

Before:

 # tc filter add dev swp1 ingress pref 1 proto ip flower ip_proto udp src_port 0 action pass
 Illegal "src_port"

 # tc filter add dev swp1 ingress pref 2 proto ip flower ip_proto udp dst_port 0 action pass
 Illegal "dst_port"

 # tc filter add dev swp1 ingress pref 3 proto ip flower ip_proto udp src_port 0-100 action pass
 Illegal "src_port"

 # tc filter add dev swp1 ingress pref 4 proto ip flower ip_proto udp dst_port 0-100 action pass
 Illegal "dst_port"

After:

 # tc filter add dev swp1 ingress pref 1 proto ip flower ip_proto udp src_port 0 action pass

 # tc filter add dev swp1 ingress pref 2 proto ip flower ip_proto udp dst_port 0 action pass

 # tc filter add dev swp1 ingress pref 3 proto ip flower ip_proto udp src_port 0-100 action pass

 # tc filter add dev swp1 ingress pref 4 proto ip flower ip_proto udp dst_port 0-100 action pass

 # tc filter show dev swp1 ingress | grep _port
   src_port 0
   dst_port 0
   src_port 0-100
   dst_port 0-100

Fixes: 767b6fd620dd ("tc: flower: fix port value truncation")
Signed-off-by: Ido Schimmel <idosch@nvidia.com>
Reviewed-by: Petr Machata <petrm@nvidia.com>
Reviewed-by: Simon Horman <simon.horman@corigine.com>
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
2 years agouapi: update headers to 6.5-rc1
Stephen Hemminger [Mon, 10 Jul 2023 17:00:07 +0000 (10:00 -0700)] 
uapi: update headers to 6.5-rc1

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
2 years agotc/taprio: fix parsing of "fp" option when it doesn't appear last
Vladimir Oltean [Wed, 5 Jul 2023 10:51:55 +0000 (13:51 +0300)] 
tc/taprio: fix parsing of "fp" option when it doesn't appear last

When installing a Qdisc this way:

tc qdisc replace dev $ifname handle 8001: parent root stab overhead 24 taprio \
num_tc 8 \
map 0 1 2 3 4 5 6 7 \
queues 1@0 1@1 1@2 1@3 1@4 1@5 1@6 1@7 \
base-time 0 \
sched-entry S 01 1216 \
sched-entry S fe 12368 \
fp P E E E E E E E \
flags 0x2

the parser will error out when it tries to parse the "fp" array and it
finds "flags" as one of the elements, expecting it to be one of "P" or
"E".

The way this is handled in the parsing of other array arguments of
variable size (max-sdu, map, queues etc) is to not fail, call PREV_ARG()
and attempt re-parsing the argument as something else. Do that for "fp"
as well.

Apparently mqprio handles this case correctly, so I must have forgotten
to apply the same treatment for taprio as well, during development.

Fixes: 5fbca3b469ec ("tc/taprio: add support for preemptible traffic classes")
Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
2 years agof_flower: simplify cfm dump function
Zahari Doychev [Thu, 29 Jun 2023 19:57:36 +0000 (21:57 +0200)] 
f_flower: simplify cfm dump function

The standard print function can be used to print the cfm attributes in
both standard and json use cases. In this way no string buffer is needed
which simplifies the code.

Signed-off-by: Zahari Doychev <zdoychev@maxlinear.com>
Reviewed-by: Petr Machata <me@pmachata.org>
Reviewed-by: Ido Schimmel <idosch@nvidia.com>
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
2 years agoMerge remote-tracking branch 'main/main' into next
David Ahern [Fri, 30 Jun 2023 01:38:39 +0000 (19:38 -0600)] 
Merge remote-tracking branch 'main/main' into next

Signed-off-by: David Ahern <dsahern@kernel.org>
2 years agoifstat: fix warning about conditional
Stephen Hemminger [Wed, 28 Jun 2023 23:35:25 +0000 (16:35 -0700)] 
ifstat: fix warning about conditional

Gcc with warnings enabled complains because the conditional.
  if ((long)(a - b) < 0)
could be construed as never true.  Change to simple comparison.

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
2 years agoct: check for invalid proto
Stephen Hemminger [Wed, 28 Jun 2023 23:34:01 +0000 (16:34 -0700)] 
ct: check for invalid proto

Previously since proto was __u8 an invalid proto would
be allowed.  Gcc warns about never true conditional
since __u8 can never be negative.

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
2 years agoss: fix warning about empty if()
Stephen Hemminger [Wed, 28 Jun 2023 23:33:10 +0000 (16:33 -0700)] 
ss: fix warning about empty if()

With all warnings enabled gcc wants brackets around the
empty if() clause. "Yes I really want an empty clause"

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
2 years agofix fallthrough warnings
Stephen Hemminger [Wed, 28 Jun 2023 23:32:22 +0000 (16:32 -0700)] 
fix fallthrough warnings

In lib/utils.c comment for fallthrough was in wrong place
and one was missing in xfrm_state.

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
2 years agodcb: fully initialize flag table
Stephen Hemminger [Wed, 28 Jun 2023 23:31:33 +0000 (16:31 -0700)] 
dcb: fully initialize flag table

And make the flag table const since only used for lookup.

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
2 years agoMerge git://git.kernel.org/pub/scm/network/iproute2/iproute2-next
Stephen Hemminger [Wed, 28 Jun 2023 15:20:57 +0000 (08:20 -0700)] 
Merge git://git.kernel.org/pub/scm/network/iproute2/iproute2-next

2 years agov6.4.0 v6.4.0
Stephen Hemminger [Mon, 26 Jun 2023 16:12:23 +0000 (09:12 -0700)] 
v6.4.0

2 years agoman: fix typos found by Lintian
Luca Boccassi [Thu, 15 Jun 2023 01:06:59 +0000 (02:06 +0100)] 
man: fix typos found by Lintian

Signed-off-by: Luca Boccassi <bluca@debian.org>
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
2 years agof_flower: add cfm support
Zahari Doychev [Wed, 21 Jun 2023 20:55:45 +0000 (22:55 +0200)] 
f_flower: add cfm support

Add support for matching on CFM Maintenance Domain level and opcode.

  # tc filter add dev ens6 ingress pref 1 proto cfm \
       flower cfm op 1 mdl 5 action ok

  # tc filter show dev ens6 ingress
    filter protocol cfm pref 1 flower chain 0
    filter protocol cfm pref 1 flower chain 0 handle 0x1
      eth_type 8902
      cfm mdl 5 op 1
      not_in_hw
            action order 1: gact action pass
             random type none pass val 0
             index 1 ref 1 bind 1

  # tc -j -p filter show dev ens6 ingress
    [ {
            "protocol": "cfm",
            "pref": 1,
            "kind": "flower",
            "chain": 0
        },{
            "protocol": "cfm",
            "pref": 1,
            "kind": "flower",
            "chain": 0,
            "options": {
                "handle": 1,
                "keys": {
                    "eth_type": "8902",
                    "cfm": {
                        "mdl": 5,
                        "op": 1
                    }
                },
                "not_in_hw": true,
                "actions": [ {
                        "order": 1,
                        "kind": "gact",
                        "control_action": {
                            "type": "pass"
                        },
                        "prob": {
                            "random_type": "none",
                            "control_action": {
                                "type": "pass"
                            },
                            "val": 0
                        },
                        "index": 1,
                        "ref": 1,
                        "bind": 1
                    } ]
            }
        } ]

Signed-off-by: Zahari Doychev <zdoychev@maxlinear.com>
Reviewed-by: Ido Schimmel <idosch@nvidia.com>
Signed-off-by: David Ahern <dsahern@kernel.org>
2 years agoiplink: filter stats using RTEXT_FILTER_SKIP_STATS
Edwin Peer [Sun, 11 Jun 2023 10:57:38 +0000 (13:57 +0300)] 
iplink: filter stats using RTEXT_FILTER_SKIP_STATS

Don't request statistics we do not intend to render. This avoids the
possibility of a truncated IFLA_VFINFO_LIST when statistics are not
requested as well as the fetching of unnecessary data.

Signed-off-by: Edwin Peer <edwin.peer@broadcom.com>
Cc: Edwin Peer <espeer@gmail.com>
Signed-off-by: Gal Pressman <gal@nvidia.com>
Signed-off-by: David Ahern <dsahern@kernel.org>
2 years agoUpdate kernel headers
David Ahern [Wed, 21 Jun 2023 16:13:05 +0000 (09:13 -0700)] 
Update kernel headers

Update kernel headers to commit:
    cc7554954848 ("net: micrel: Change to receive timestamp in the frame for lan8841")

Signed-off-by: David Ahern <dsahern@kernel.org>
2 years agotc/taprio: print the offload xstats
Vladimir Oltean [Wed, 7 Jun 2023 15:45:04 +0000 (18:45 +0300)] 
tc/taprio: print the offload xstats

When the kernel reports offload counters through TCA_STATS2 ->
TCA_STATS_APP for the taprio qdisc, decode and print them.

Usage:

 # Global stats
 $ tc -s qdisc show dev eth0 root
 # Per-tc stats
 $ tc -s class show dev eth0

Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
Signed-off-by: David Ahern <dsahern@kernel.org>
2 years agof_flower: Add l2_miss support
Ido Schimmel [Wed, 7 Jun 2023 15:35:50 +0000 (18:35 +0300)] 
f_flower: Add l2_miss support

Add the ability to match on packets that encountered a layer 2 miss in
bridge driver's FDB / MDB. Example:

 # tc filter add dev swp2 egress pref 1 proto all flower indev swp1 l2_miss 1 action drop
 # tc filter add dev swp2 egress pref 1 proto all flower indev swp1 l2_miss 0 action drop

 # tc filter show dev swp2 egress
 filter protocol all pref 1 flower chain 0
 filter protocol all pref 1 flower chain 0 handle 0x1
   indev swp1
   l2_miss 1
   not_in_hw
         action order 1: gact action drop
          random type none pass val 0
          index 1 ref 1 bind 1

 filter protocol all pref 1 flower chain 0 handle 0x2
   indev swp1
   l2_miss 0
   not_in_hw
         action order 1: gact action drop
          random type none pass val 0
          index 2 ref 1 bind 1

 # tc -j -p filter show dev swp2 egress
 [ {
         "protocol": "all",
         "pref": 1,
         "kind": "flower",
         "chain": 0
     },{
         "protocol": "all",
         "pref": 1,
         "kind": "flower",
         "chain": 0,
         "options": {
             "handle": 1,
             "indev": "swp1",
             "keys": {
                 "l2_miss": 1
             },
             "not_in_hw": true,
             "actions": [ {
 [...]
                 } ]
         }
     },{
         "protocol": "all",
         "pref": 1,
         "kind": "flower",
         "chain": 0,
         "options": {
             "handle": 2,
             "indev": "swp1",
             "keys": {
                 "l2_miss": 0
             },
             "not_in_hw": true,
             "actions": [ {
 [...]
                 } ]
         }
     } ]

Signed-off-by: Ido Schimmel <idosch@nvidia.com>
Signed-off-by: David Ahern <dsahern@kernel.org>
2 years agoMerge branch 'dcb-rewr-subcmd' into next
David Ahern [Fri, 9 Jun 2023 21:46:04 +0000 (15:46 -0600)] 
Merge branch 'dcb-rewr-subcmd' into next

Daniel Machon  says:

====================

========================================================================
Introduction:
========================================================================

This series introduces a new DCB subcommand: rewr, which is used to
configure the in-kernel DCB rewrite table [1].

Rewrite support is added as a separate DCB subcommand, rather than an
APP opt-in flag or similar. This goes in line with what we did to dcbnl,
where rewrite is a separate object.  Obviously this requires a bit more
code to implement the new command, but much of the existing dcb-app code
(especially the bookkeeping code) can be reused. In some cases a little
adaptation is needed.

========================================================================
dcb-rewr parameters:
========================================================================

Initially, I have only made support for the prio-pcp and prio-dscp
parameters, as DSCP and PCP  are the only selectors that currently have
a user [2] and to be honest, I am not even sure it makes sense to add
dgram, stream, ethtype rewrite support - At least the rewriter of Sparx5
does not support this. Any input here is much appreciated!

Examples:

Rewrite DSCP to 63 for packets with priority 1
$ dcb rewr add dev eth0 prio-dscp 1:63

Rewrite PCP 7 and DEI to 1 for packets with priority 1
$ dcb rewr add dev eth0 prio-pcp 1:7de

A new manpage has been added, to cover the new dcb-rewr subcommand, and
its parameters. Also I took the liberty to clean up a few things in the
dcb-app manpage.

========================================================================
Patch overview:
========================================================================

Patch  #1 Adds a new field 'attr' to the dcb_app_table struct, which is
          used to distinguish app and rewrite tables.

Patch  #2 Replaces uses of %d with %u for unsigned int.

Patch  #3 Moves colon out of callback functions.

Patch  #4 Renames protocl print functions from _key to _pid

Patch  #5 Modifies the _print_filtered() function for dcb-rewr reuse, by
          introducing new callbacks.

Patch  #6 Modifies existing dcb-app function dcb_app_table_remove_replaced
          for reuse by dcb-rewr

Patch  #7 Expose dcb-app functions required by dcb-rewr.

Patch  #8 Adds the new dcb-rewr subcommand with initial support for
          prio-pcp and prio-dscp rewrite.

Patch  #9 Introduces symbol for max DSCP value and updates accordingly.

Patch #10 Adds the dcb-rewr.8 manpage
Patch #11 Adds references to dcb-apptrust and dcb-rewr in the dcb.8
          manpage.

Patch #12 Cleans up the dcb-app.8 manpage.

[1] https://elixir.bootlin.com/linux/v6.4-rc1/source/net/dcb/dcbnl.c#L181
[2] https://elixir.bootlin.com/linux/v6.4-rc1/source/drivers/net/ethernet/microchip/sparx5/sparx5_dcb.c#L380

====================

Signed-off-by: David Ahern <dsahern@kernel.org>
2 years agoman: dcb-app: clean up a few mistakes
Daniel Machon [Tue, 6 Jun 2023 07:19:47 +0000 (09:19 +0200)] 
man: dcb-app: clean up a few mistakes

While referencing the dcb-app manpage, I spotted a few mistakes. Lets
fix them.

Reviewed-by: Petr Machata <me@pmachata.org>
Signed-off-by: Daniel Machon <daniel.machon@microchip.com>
Signed-off-by: David Ahern <dsahern@kernel.org>
2 years agoman: dcb: add additional references under 'SEE ALSO'
Daniel Machon [Tue, 6 Jun 2023 07:19:46 +0000 (09:19 +0200)] 
man: dcb: add additional references under 'SEE ALSO'

Add dcb-apptrust and dcb-rewr to the 'SEE ALSO' section of the dcb
manpage.

Reviewed-by: Petr Machata <me@pmachata.org>
Signed-off-by: Daniel Machon <daniel.machon@microchip.com>
Signed-off-by: David Ahern <dsahern@kernel.org>
2 years agoman: dcb-rewr: add new manpage for dcb-rewr
Daniel Machon [Tue, 6 Jun 2023 07:19:45 +0000 (09:19 +0200)] 
man: dcb-rewr: add new manpage for dcb-rewr

Add a new manpage for dcb-rewr. Most of the content is copied over from
dcb-app, as the same set of commands and parameters (in reverse) applies
to dcb-rewr.

Reviewed-by: Petr Machata <me@pmachata.org>
Signed-off-by: Daniel Machon <daniel.machon@microchip.com>
Signed-off-by: David Ahern <dsahern@kernel.org>
2 years agodcb: rewr: add symbol for max DSCP value
Daniel Machon [Tue, 6 Jun 2023 07:19:44 +0000 (09:19 +0200)] 
dcb: rewr: add symbol for max DSCP value

A symbol, DCB_APP_PCP_MAX, for maximum PCP value, already exists. Lets
add a symbol DCB_APP_DSCP_MAX and update accordingly.

Signed-off-by: Daniel Machon <daniel.machon@microchip.com>
Reviewed-by: Petr Machata <me@pmachata.org>
Signed-off-by: David Ahern <dsahern@kernel.org>
2 years agodcb: rewr: add new dcb-rewr subcommand
Daniel Machon [Tue, 6 Jun 2023 07:19:43 +0000 (09:19 +0200)] 
dcb: rewr: add new dcb-rewr subcommand

Add a new subcommand 'rewr' for configuring the in-kernel DCB rewrite
table. The rewrite table of the kernel is similar to the APP table,
therefore, much of the existing bookkeeping code from dcb-app, can be
reused in the dcb-rewr implementation.

Initially, only support for configuring PCP and DSCP-based rewrite has
been added.

Signed-off-by: Daniel Machon <daniel.machon@microchip.com>
Reviewed-by: Petr Machata <me@pmachata.org>
Signed-off-by: David Ahern <dsahern@kernel.org>
2 years agodcb: app: expose functions required by dcb-rewr
Daniel Machon [Tue, 6 Jun 2023 07:19:42 +0000 (09:19 +0200)] 
dcb: app: expose functions required by dcb-rewr

In preparation for the dcb-rewr implementation, expose required
functions, and structs.

Signed-off-by: Daniel Machon <daniel.machon@microchip.com>
Reviewed-by: Petr Machata <me@pmachata.org>
Signed-off-by: David Ahern <dsahern@kernel.org>
2 years agodcb: app: modify dcb_app_table_remove_replaced() for dcb-rewr reuse
Daniel Machon [Tue, 6 Jun 2023 07:19:41 +0000 (09:19 +0200)] 
dcb: app: modify dcb_app_table_remove_replaced() for dcb-rewr reuse

When doing a replace command, entries are checked against selector and
protocol. Rewrite requires the check to be against selector and
priority.

Adapt the existing dcb_app_table_remove_replace function for this, by
using callback functions for selector, pid and prio checks.

Signed-off-by: Daniel Machon <daniel.machon@microchip.com>
Reviewed-by: Petr Machata <me@pmachata.org>
Signed-off-by: David Ahern <dsahern@kernel.org>
2 years agodcb: app: modify dcb_app_print_filtered() for dcb-rewr reuse
Daniel Machon [Tue, 6 Jun 2023 07:19:40 +0000 (09:19 +0200)] 
dcb: app: modify dcb_app_print_filtered() for dcb-rewr reuse

Where dcb-app requires protocol to be the printed key, dcb-rewr requires
it to be the priority. Adapt existing dcb-app print functions for this.

dcb_app_print_filtered() has been modified, to take two callbacks; one
for printing the entire string (pid and prio), and one for the pid type
(dec, hex, dscp, pcp). This saves us for making one dedicated function
for each pid type for both app and rewr.

Also, printing the colon is now expected to be handled by the
print_pid_prio() callback.

Signed-off-by: Daniel Machon <daniel.machon@microchip.com>
Reviewed-by: Petr Machata <me@pmachata.org>
Signed-off-by: David Ahern <dsahern@kernel.org>
2 years agodcb: app: rename dcb_app_print_key_*() functions
Daniel Machon [Tue, 6 Jun 2023 07:19:39 +0000 (09:19 +0200)] 
dcb: app: rename dcb_app_print_key_*() functions

In preparation for changing the prototype of dcb_app_print_filtered(),
rename the _print_key_*() functions to _print_pid_*(), as the protocol
can both be key and value with the introduction of dcb-rewr.

Signed-off-by: Daniel Machon <daniel.machon@microchip.com>
Reviewed-by: Petr Machata <me@pmachata.org>
Signed-off-by: David Ahern <dsahern@kernel.org>
2 years agodcb: app: move colon printing out of callbacks
Daniel Machon [Tue, 6 Jun 2023 07:19:38 +0000 (09:19 +0200)] 
dcb: app: move colon printing out of callbacks

In preparation for changing the prototype of dcb_app_print_filtered(),
move the colon printing out of the callbacks, and into
dcb_app_print_filtered().

Signed-off-by: Daniel Machon <daniel.machon@microchip.com>
Reviewed-by: Petr Machata <me@pmachata.org>
Signed-off-by: David Ahern <dsahern@kernel.org>
2 years agodcb: app: replace occurrences of %d with %u for printing unsigned int
Daniel Machon [Tue, 6 Jun 2023 07:19:37 +0000 (09:19 +0200)] 
dcb: app: replace occurrences of %d with %u for printing unsigned int

In preparation for changing the prototype of dcb_app_print_filtered(),
replace occurrences of %d for printing unsigned integer, with %u as it
ought to be.

Signed-off-by: Daniel Machon <daniel.machon@microchip.com>
Reviewed-by: Petr Machata <me@pmachata.org>
Signed-off-by: David Ahern <dsahern@kernel.org>
2 years agodcb: app: add new dcbnl attribute field
Daniel Machon [Tue, 6 Jun 2023 07:19:36 +0000 (09:19 +0200)] 
dcb: app: add new dcbnl attribute field

Add a new field 'attr' to the dcb_app_table struct, in order to inject
different dcbnl get/set attributes for APP and rewrite.

Signed-off-by: Daniel Machon <daniel.machon@microchip.com>
Reviewed-by: Petr Machata <me@pmachata.org>
Signed-off-by: David Ahern <dsahern@kernel.org>
2 years agouapi: update to bpf.h
Stephen Hemminger [Fri, 9 Jun 2023 16:23:40 +0000 (09:23 -0700)] 
uapi: update to bpf.h

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
2 years agort_names: check for malloc() failure
Stephen Hemminger [Thu, 8 Jun 2023 01:33:49 +0000 (18:33 -0700)] 
rt_names: check for malloc() failure

Fixes issue reported by Gcc 13 analayzer.

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
2 years agoip-link: add support for nolocalbypass in vxlan
Vladimir Nikishkin [Tue, 6 Jun 2023 02:32:02 +0000 (10:32 +0800)] 
ip-link: add support for nolocalbypass in vxlan

Add userspace support for the [no]localbypass vxlan netlink
attribute. With localbypass on (default), the vxlan driver processes
the packets destined to the local machine by itself, bypassing the
userspace nework stack. With nolocalbypass the packets are always
forwarded to the userspace network stack, so userspace programs,
such as tcpdump have a chance to process them.

Signed-off-by: Vladimir Nikishkin <vladimir@nikishkin.pw>
Reviewed-by: Ido Schimmel <idosch@nvidia.com>
Reviewed-by: Andrea Claudi <aclaudi@redhat.com>
Reviewed-by: Nikolay Aleksandrov <razor@blackwall.org>
Signed-off-by: David Ahern <dsahern@kernel.org>
2 years agoUpdate kernel headers
David Ahern [Tue, 6 Jun 2023 14:30:22 +0000 (08:30 -0600)] 
Update kernel headers

Update kernel headers to commit:
    ae91f7e436f8 ("net/pppoe: fix a typo for the PPPOE_HASH_BITS_1 definition")

Signed-off-by: David Ahern <dsahern@kernel.org>
2 years agowhitespace cleanups
Stephen Hemminger [Tue, 6 Jun 2023 01:43:58 +0000 (18:43 -0700)] 
whitespace cleanups

Remove trailing whitespace.
Make sure there is space after keywords.

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
2 years agotreewide: fix indentation
Andrea Claudi [Wed, 31 May 2023 10:35:56 +0000 (12:35 +0200)] 
treewide: fix indentation

Replace multiple whitespaces with tab where appropriate.
While at it, fix tc flower help message and remove some double
whitespaces.

Signed-off-by: Andrea Claudi <aclaudi@redhat.com>
Reviewed-by: Ido Schimmel <idosch@nvidia.com>
Tested-by: Ido Schimmel <idosch@nvidia.com>
Signed-off-by: David Ahern <dsahern@kernel.org>
2 years agoMerge branch 'main' into next
David Ahern [Mon, 5 Jun 2023 15:18:09 +0000 (09:18 -0600)] 
Merge branch 'main' into next

Signed-off-by: David Ahern <dsahern@kernel.org>
2 years agordma: make rd_attr_check static
Stephen Hemminger [Thu, 1 Jun 2023 17:14:11 +0000 (10:14 -0700)] 
rdma: make rd_attr_check static

Function defined and used in only one file.

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
2 years agoxfrm: make xfrm_stat_print_nokeys static
Stephen Hemminger [Thu, 1 Jun 2023 17:13:23 +0000 (10:13 -0700)] 
xfrm: make xfrm_stat_print_nokeys static

This function is only used in one file.

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
2 years agoip: make print_rta_gateway static
Stephen Hemminger [Thu, 1 Jun 2023 17:12:32 +0000 (10:12 -0700)] 
ip: make print_rta_gateway static

Function only used in one file.

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
2 years agobridge: make print_vlan_info static
Stephen Hemminger [Thu, 1 Jun 2023 17:10:31 +0000 (10:10 -0700)] 
bridge: make print_vlan_info static

Function defined and used in only one file.

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
2 years agolibnetlink: drop unused rtnl_talk_iov
Stephen Hemminger [Thu, 1 Jun 2023 17:09:47 +0000 (10:09 -0700)] 
libnetlink: drop unused rtnl_talk_iov

Function was defined but not used in current iproute2 code.

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
2 years agoutils: make local cmdline functions static
Stephen Hemminger [Thu, 1 Jun 2023 17:08:09 +0000 (10:08 -0700)] 
utils: make local cmdline functions static

No need to expose these parts of command line parsing.

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
2 years agoipaddress: accept symbolic names
Stephen Hemminger [Fri, 2 Jun 2023 15:51:53 +0000 (08:51 -0700)] 
ipaddress: accept symbolic names

The function rtnl_addproto_a2n() was defined but never used.
Use it to allow for symbolic names, and fix the function signatures
so protocol value is consistently __u8.

Fixes: bdb8d8549ed9 ("ip: Support IP address protocol")
Cc: petrm@nvidia.com
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
2 years agouapi: update headers to 6.4-rc4
Stephen Hemminger [Tue, 30 May 2023 21:54:10 +0000 (14:54 -0700)] 
uapi: update headers to 6.4-rc4

Minor addition to in.h

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
2 years agovxlan: make option printing more consistent
Stephen Hemminger [Tue, 23 May 2023 16:57:15 +0000 (09:57 -0700)] 
vxlan: make option printing more consistent

Add new helper function print_bool_opt() which prints
with no prefix and use it for vxlan options.

If the option matches the expected default value,
it is not printed if in non JSON mode unless the details
setting is repeated.

Use a table for the vxlan options. This will change
the order of the printing of options.

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
2 years agovxlan: use print_nll for gbp and gpe
Stephen Hemminger [Tue, 23 May 2023 16:56:05 +0000 (09:56 -0700)] 
vxlan: use print_nll for gbp and gpe

The Gbp and Gpe are presence, not booleans so use print_null()
for them

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
2 years agoiproute_lwtunnel: fix array boundary check
Andrea Claudi [Mon, 29 May 2023 21:42:16 +0000 (23:42 +0200)] 
iproute_lwtunnel: fix array boundary check

seg6_mode_types is made up of 5 elements, so ARRAY_SIZE(seg6_mode_types)
evaluates to 5. Thus, when mode = 5, this function returns
seg6_mode_types[5], resulting in an out-of-bound access.

Fix this bailing out when mode is equal to or greater than 5.

Fixes: cf87da417bb4 ("iproute: add support for seg6 l2encap mode")
Signed-off-by: Andrea Claudi <aclaudi@redhat.com>
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
2 years agovdpa: propagate error from cmd_dev_vstats_show()
Andrea Claudi [Mon, 29 May 2023 21:41:41 +0000 (23:41 +0200)] 
vdpa: propagate error from cmd_dev_vstats_show()

Error potentially returned from mnlu_gen_socket_sndrcv() are propagated
for each and every invocation in vdpa. Let's do the same here.

Fixes: 6f97e9c9337b ("vdpa: Add support for reading vdpa device statistics")
Signed-off-by: Andrea Claudi <aclaudi@redhat.com>
Reviewed-by: Parav Pandit <parav@nvidia.com>
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
2 years agoipstats: fix message reporting error
Andrea Claudi [Mon, 29 May 2023 16:59:15 +0000 (18:59 +0200)] 
ipstats: fix message reporting error

strerror() accepts any integer as arguments, but returns meaningful
error descriptions only for positive integers.

ipstats code uses strerror on a code path where either err is 0 or
-ENOMEM, thus resulting in a useless error message.

Fix this using errno and moving the error printing closer to the only
function populating it in this code path.

Fixes: df0b2c6d0098 ("ipstats: Add a shell of "show" command")
Signed-off-by: Andrea Claudi <aclaudi@redhat.com>
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
2 years agobridge: vni: remove useless checks on vni
Andrea Claudi [Fri, 26 May 2023 17:27:20 +0000 (19:27 +0200)] 
bridge: vni: remove useless checks on vni

After the (d == NULL || vni == NULL) check, vni cannot be NULL anymore.

This remove two useless conditional checks on vni value:
- the first check cannot be true, so remove the whole conditional block
- the second check is always true, so remove the check

Signed-off-by: Andrea Claudi <aclaudi@redhat.com>
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
2 years agoip: remove double space before 'allmulti' flag
Andrea Claudi [Fri, 26 May 2023 17:36:54 +0000 (19:36 +0200)] 
ip: remove double space before 'allmulti' flag

Current output:
$ ip -d link show vxlan0
79: vxlan0: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/ether b6:f6:12:c3:2d:52 brd ff:ff:ff:ff:ff:ff promiscuity 0  allmulti 0 minmtu 68 maxmtu 65535

Resulting output:
$ ip -d link show vxlan0
79: vxlan0: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/ether b6:f6:12:c3:2d:52 brd ff:ff:ff:ff:ff:ff promiscuity 0 allmulti 0 minmtu 68 maxmtu 65535

Fixes: e98683accc28 ("link: display 'allmulti' counter")
Signed-off-by: Andrea Claudi <aclaudi@redhat.com>
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
2 years agoll_type_n2a: use ARRAY_SIZE
Stephen Hemminger [Fri, 26 May 2023 18:55:58 +0000 (11:55 -0700)] 
ll_type_n2a: use ARRAY_SIZE

Replace open coded version of array size computation.
And fix whitespace.

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
2 years agomptcp: add support for implicit flag
Andrea Claudi [Tue, 16 May 2023 09:48:04 +0000 (11:48 +0200)] 
mptcp: add support for implicit flag

Kernel supports implicit flag since commit d045b9eb95a9 ("mptcp:
introduce implicit endpoints"), included in v5.18.

Let's add support for displaying it to iproute2.

Before this change:
$ ip mptcp endpoint show
10.0.2.2 id 1 rawflags 10

After this change:
$ ip mptcp endpoint show
10.0.2.2 id 1 implicit

Signed-off-by: Andrea Claudi <aclaudi@redhat.com>
Signed-off-by: David Ahern <dsahern@kernel.org>
2 years agoCREDITS: add file
Stephen Hemminger [Fri, 12 May 2023 03:47:54 +0000 (20:47 -0700)] 
CREDITS: add file

Record some of the historical contributors to iproute2.
Take Alexey out of README.

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
2 years agotc/prio: handle possible truncated kernel response
Stephen Hemminger [Tue, 9 May 2023 03:17:50 +0000 (20:17 -0700)] 
tc/prio: handle possible truncated kernel response

Reported by -fanalyzer. If kernel did not send full qdisc
info, then uninitialized or null data could be referenced.

q_prio.c: In function ‘prio_print_opt’:
q_prio.c:105:57: warning: dereference of NULL ‘0’ [CWE-476] [-Wanalyzer-null-dereference]
  105 |         print_uint(PRINT_ANY, "bands", "bands %u ", qopt->bands);
      |                                                     ~~~~^~~~~~~
  ‘prio_print_opt’: event 1
    |
    |   98 |         if (opt == NULL)
    |      |            ^
    |      |            |
    |      |            (1) following ‘false’ branch (when ‘opt’ is non-NULL)...
    |
  ‘prio_print_opt’: event 2
    |
    |../include/uapi/linux/rtnetlink.h:228:38:
    |  228 | #define RTA_PAYLOAD(rta) ((int)((rta)->rta_len) - RTA_LENGTH(0))
    |      |                                ~~~~~~^~~~~~~~~~
    |      |                                      |
    |      |                                      (2) ...to here
../include/libnetlink.h:236:19: note: in expansion of macro ‘RTA_PAYLOAD’
    |  236 |         ({ data = RTA_PAYLOAD(rta) >= len ? RTA_DATA(rta) : NULL;       \
    |      |                   ^~~~~~~~~~~
q_prio.c:101:13: note: in expansion of macro ‘parse_rtattr_nested_compat’
    |  101 |         if (parse_rtattr_nested_compat(tb, TCA_PRIO_MAX, opt, qopt,
    |      |             ^~~~~~~~~~~~~~~~~~~~~~~~~~
    |
  ‘prio_print_opt’: event 3
    |
    |../include/libnetlink.h:236:59:
    |  236 |         ({ data = RTA_PAYLOAD(rta) >= len ? RTA_DATA(rta) : NULL;       \
q_prio.c:101:13: note: in expansion of macro ‘parse_rtattr_nested_compat’
    |  101 |         if (parse_rtattr_nested_compat(tb, TCA_PRIO_MAX, opt, qopt,
    |      |             ^~~~~~~~~~~~~~~~~~~~~~~~~~
    |
  ‘prio_print_opt’: events 4-5
    |
    |  105 |         print_uint(PRINT_ANY, "bands", "bands %u ", qopt->bands);
    |      |                                                     ~~~~^~~~~~~
    |      |                                                         |
    |      |                                                         (4) ...to here
    |      |                                                         (5) dereference of NULL ‘<unknown>’
    |

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
2 years agordma/utils: fix some analyzer warnings
Stephen Hemminger [Tue, 9 May 2023 03:15:52 +0000 (20:15 -0700)] 
rdma/utils: fix some analyzer warnings

Add error checks for cases where analyzer thinks it is possible
to us a possibly NULL value.

utils.c: In function ‘get_port_from_argv’:
utils.c:76:17: warning: use of NULL where non-null expected [CWE-476] [-Wanalyzer-null-argument]
   76 |         slash = strchr(rd_argv(rd), '/');
      |                 ^~~~~~~~~~~~~~~~~~~~~~~~
  ‘get_port_from_argv’: events 1-2
    |
    |   68 | static int get_port_from_argv(struct rd *rd, uint32_t *port,
    |      |            ^~~~~~~~~~~~~~~~~~
    |      |            |
    |      |            (1) entry to ‘get_port_from_argv’
    |......
    |   76 |         slash = strchr(rd_argv(rd), '/');
    |      |                        ~
    |      |                        |
    |      |                        (2) inlined call to ‘rd_argv’ from ‘get_port_from_argv’
    |
    +--> ‘rd_argv’: event 3
           |
           |   18 |         if (!rd_argc(rd))
           |      |            ^
           |      |            |
           |      |            (3) following ‘true’ branch...
           |
    <------+
    |
  ‘get_port_from_argv’: events 4-5
    |
    |   76 |         slash = strchr(rd_argv(rd), '/');
    |      |                 ^~~~~~~~~~~~~~~~~~~~~~~~
    |      |                 |
    |      |                 (4) ...to here
    |      |                 (5) argument 1 (‘<unknown>’) NULL where non-null expected
    |
In file included from rdma.h:10,
                 from utils.c:7:
/usr/include/string.h:246:14: note: argument 1 of ‘strchr’ must be non-null
  246 | extern char *strchr (const char *__s, int __c)
      |              ^~~~~~

Fixes: 40df8263a0f0 ("rdma: Add dev object")
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
2 years agonstat: fix potential NULL deref
Stephen Hemminger [Tue, 9 May 2023 02:42:03 +0000 (19:42 -0700)] 
nstat: fix potential NULL deref

Reported as:
    CC       nstat
nstat.c: In function ‘load_ugly_table’:
nstat.c:205:24: warning: dereference of NULL ‘p’ [CWE-476] [-Wanalyzer-null-dereference]
  205 |                 while (*p) {
      |                        ^~
  ‘main’: events 1-14
    |
    |  575 | int main(int argc, char *argv[])
    |      |     ^~~~
    |      |     |
    |      |     (1) entry to ‘main’
    |......
    |  635 |         if (scan_interval > 0) {
    |      |            ~
    |      |            |
    |      |            (2) following ‘true’ branch...
    |  636 |                 if (time_constant == 0)
    |      |                     ~~~~~~~~~~~~~~~~~~
    |      |                                   |
    |      |                                   (3) ...to here
    |......
    |  640 |                 if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
    |      |                    ~      ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    |      |                    |      |
    |      |                    |      (4) when ‘socket’ succeeds
    |      |                    (5) following ‘false’ branch (when ‘fd >= 0’)...
    |......
    |  644 |                 if (bind(fd, (struct sockaddr *)&sun, 2+1+strlen(sun.sun_path+1)) < 0) {
    |      |                    ~                                      ~~~~~~~~~~~~~~~~~~~~~~
    |      |                    |                                      |
    |      |                    (7) following ‘false’ branch...        (6) ...to here
    |......
    |  648 |                 if (listen(fd, 5) < 0) {
    |      |                    ~~~~~~~~~~~~~~
    |      |                    ||
    |      |                    |(8) ...to here
    |      |                    |(9) when ‘listen’ succeeds
    |      |                    (10) following ‘false’ branch...
    |......
    |  652 |                 if (daemon(0, 0)) {
    |      |                    ~~~~~~~~~~~~~
    |      |                    ||
    |      |                    |(11) ...to here
    |      |                    (12) following ‘false’ branch...
    |......
    |  656 |                 signal(SIGPIPE, SIG_IGN);
    |      |                 ~~~~~~~~~~~~~~~~~~~~~~~~
    |      |                 |
    |      |                 (13) ...to here
    |  657 |                 signal(SIGCHLD, sigchild);
    |  658 |                 server_loop(fd);
    |      |                 ~~~~~~~~~~~~~~~
    |      |                 |
    |      |                 (14) calling ‘server_loop’ from ‘main’
    |
    +--> ‘server_loop’: events 15-16
           |
           |  472 | static void server_loop(int fd)
           |      |             ^~~~~~~~~~~
           |      |             |
           |      |             (15) entry to ‘server_loop’
           |......
           |  483 |         load_netstat();
           |      |         ~~~~~~~~~~~~~~
           |      |         |
           |      |         (16) calling ‘load_netstat’ from ‘server_loop’
           |
           +--> ‘load_netstat’: events 17-20
                  |
                  |  302 | static void load_netstat(void)
                  |      |             ^~~~~~~~~~~~
                  |      |             |
                  |      |             (17) entry to ‘load_netstat’
                  |......
                  |  306 |         if (fp) {
                  |      |            ~
                  |      |            |
                  |      |            (18) following ‘true’ branch (when ‘fp’ is non-NULL)...
                  |  307 |                 load_ugly_table(fp);
                  |      |                 ~~~~~~~~~~~~~~~~~~~
                  |      |                 |
                  |      |                 (19) ...to here
                  |      |                 (20) calling ‘load_ugly_table’ from ‘load_netstat’
                  |
                  +--> ‘load_ugly_table’: events 21-26
                         |
                         |  178 | static void load_ugly_table(FILE *fp)
                         |      |             ^~~~~~~~~~~~~~~
                         |      |             |
                         |      |             (21) entry to ‘load_ugly_table’
                         |  179 | {
                         |  180 |         char *buf = NULL;
                         |      |               ~~~
                         |      |               |
                         |      |               (22) ‘buf’ is NULL
                         |......
                         |  186 |         while ((nread = getline(&buf, &buflen, fp)) != -1) {
                         |      |                ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                         |      |                                                     |
                         |      |                                                     (23) following ‘true’ branch...
                         |......
                         |  192 |                 p = strchr(buf, ':');
                         |      |                     ~~~~~~~~~~~~~~~~
                         |      |                     |
                         |      |                     (24) ...to here
                         |      |                     (25) when ‘strchr’ returns non-NULL
                         |  193 |                 if (!p) {
                         |      |                    ~
                         |      |                    |
                         |      |                    (26) following ‘false’ branch (when ‘p’ is non-NULL)...
                         |
                       ‘load_ugly_table’: event 27
                         |
                         |cc1:
                         | (27): ...to here
                         |
                       ‘load_ugly_table’: events 28-40
                         |
                         |  205 |                 while (*p) {
                         |      |                        ^~
                         |      |                        |
                         |      |                        (28) following ‘true’ branch...
                         |      |                        (40) dereference of NULL ‘p’
                         |......
                         |  208 |                         if ((next = strchr(p, ' ')) != NULL)
                         |      |                            ~        ~~~~~~~~~~~~~~
                         |      |                            |        |
                         |      |                            |        (29) ...to here
                         |      |                            |        (30) when ‘strchr’ returns NULL
                         |      |                            (31) following ‘false’ branch (when ‘next’ is NULL)...
                         |  209 |                                 *next++ = 0;
                         |  210 |                         else if ((next = strchr(p, '\n')) != NULL)
                         |      |                                 ~        ~~~~~~~~~~~~~~~
                         |      |                                 |        |
                         |      |                                 |        (32) ...to here
                         |      |                                 |        (33) when ‘strchr’ returns NULL
                         |      |                                 (34) following ‘false’ branch (when ‘next’ is NULL)...
                         |  211 |                                 *next++ = 0;
                         |  212 |                         if (off < sizeof(idbuf)) {
                         |      |                            ~~~~~~~~~~~~~~~~~~~~
                         |      |                            |    |
                         |      |                            |    (35) ...to here
                         |      |                            (36) following ‘false’ branch...
                         |......
                         |  216 |                         n = malloc(sizeof(*n));
                         |      |                             ~~~~~~~~~~~~~~~~~~
                         |      |                             |
                         |      |                             (37) ...to here
                         |  217 |                         if (!n) {
                         |      |                            ~
                         |      |                            |
                         |      |                            (38) following ‘false’ branch (when ‘n’ is non-NULL)...
                         |......
                         |  221 |                         n->id = strdup(idbuf);
                         |      |                                 ~~~~~~~~~~~~~
                         |      |                                 |
                         |      |                                 (39) ...to here
                         |
nstat.c:254:35: warning: dereference of NULL ‘n’ [CWE-476] [-Wanalyzer-null-dereference]
  254 |                                 n = n->next;
      |                                 ~~^~~~~~~~~
  ‘main’: events 1-14
    |
    |  575 | int main(int argc, char *argv[])
    |      |     ^~~~
    |      |     |
    |      |     (1) entry to ‘main’
    |......
    |  635 |         if (scan_interval > 0) {
    |      |            ~
    |      |            |
    |      |            (2) following ‘true’ branch...
    |  636 |                 if (time_constant == 0)
    |      |                     ~~~~~~~~~~~~~~~~~~
    |      |                                   |
    |      |                                   (3) ...to here
    |......
    |  640 |                 if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
    |      |                    ~      ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    |      |                    |      |
    |      |                    |      (4) when ‘socket’ succeeds
    |      |                    (5) following ‘false’ branch (when ‘fd >= 0’)...
    |......
    |  644 |                 if (bind(fd, (struct sockaddr *)&sun, 2+1+strlen(sun.sun_path+1)) < 0) {
    |      |                    ~                                      ~~~~~~~~~~~~~~~~~~~~~~
    |      |                    |                                      |
    |      |                    (7) following ‘false’ branch...        (6) ...to here
    |......
    |  648 |                 if (listen(fd, 5) < 0) {
    |      |                    ~~~~~~~~~~~~~~
    |      |                    ||
    |      |                    |(8) ...to here
    |      |                    |(9) when ‘listen’ succeeds
    |      |                    (10) following ‘false’ branch...
    |......
    |  652 |                 if (daemon(0, 0)) {
    |      |                    ~~~~~~~~~~~~~
    |      |                    ||
    |      |                    |(11) ...to here
    |      |                    (12) following ‘false’ branch...
    |......
    |  656 |                 signal(SIGPIPE, SIG_IGN);
    |      |                 ~~~~~~~~~~~~~~~~~~~~~~~~
    |      |                 |
    |      |                 (13) ...to here
    |  657 |                 signal(SIGCHLD, sigchild);
    |  658 |                 server_loop(fd);
    |      |                 ~~~~~~~~~~~~~~~
    |      |                 |
    |      |                 (14) calling ‘server_loop’ from ‘main’
    |
    +--> ‘server_loop’: events 15-16
           |
           |  472 | static void server_loop(int fd)
           |      |             ^~~~~~~~~~~
           |      |             |
           |      |             (15) entry to ‘server_loop’
           |......
           |  483 |         load_netstat();
           |      |         ~~~~~~~~~~~~~~
           |      |         |
           |      |         (16) calling ‘load_netstat’ from ‘server_loop’
           |
           +--> ‘load_netstat’: events 17-20
                  |
                  |  302 | static void load_netstat(void)
                  |      |             ^~~~~~~~~~~~
                  |      |             |
                  |      |             (17) entry to ‘load_netstat’
                  |......
                  |  306 |         if (fp) {
                  |      |            ~
                  |      |            |
                  |      |            (18) following ‘true’ branch (when ‘fp’ is non-NULL)...
                  |  307 |                 load_ugly_table(fp);
                  |      |                 ~~~~~~~~~~~~~~~~~~~
                  |      |                 |
                  |      |                 (19) ...to here
                  |      |                 (20) calling ‘load_ugly_table’ from ‘load_netstat’
                  |
                  +--> ‘load_ugly_table’: events 21-25
                         |
                         |  178 | static void load_ugly_table(FILE *fp)
                         |      |             ^~~~~~~~~~~~~~~
                         |      |             |
                         |      |             (21) entry to ‘load_ugly_table’
                         |......
                         |  186 |         while ((nread = getline(&buf, &buflen, fp)) != -1) {
                         |      |                ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                         |      |                                                     |
                         |      |                                                     (22) following ‘true’ branch...
                         |......
                         |  192 |                 p = strchr(buf, ':');
                         |      |                     ~~~~~~~~~~~~~~~~
                         |      |                     |
                         |      |                     (23) ...to here
                         |      |                     (24) when ‘strchr’ returns non-NULL
                         |  193 |                 if (!p) {
                         |      |                    ~
                         |      |                    |
                         |      |                    (25) following ‘false’ branch (when ‘p’ is non-NULL)...
                         |
                       ‘load_ugly_table’: event 26
                         |
                         |cc1:
                         | (26): ...to here
                         |
                       ‘load_ugly_table’: events 27-28
                         |
                         |  205 |                 while (*p) {
                         |      |                        ^
                         |      |                        |
                         |      |                        (27) following ‘false’ branch...
                         |......
                         |  228 |                 nread = getline(&buf, &buflen, fp);
                         |      |                         ~
                         |      |                         |
                         |      |                         (28) inlined call to ‘getline’ from ‘load_ugly_table’
                         |
                         +--> ‘getline’: event 29
                                |
                                |/usr/include/bits/stdio.h:120:10:
                                |  120 |   return __getdelim (__lineptr, __n, '\n', __stream);
                                |      |          ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                                |      |          |
                                |      |          (29) ...to here
                                |
                         <------+
                         |
                       ‘load_ugly_table’: events 30-36
                         |
                         |nstat.c:229:20:
                         |  229 |                 if (nread == -1) {
                         |      |                    ^
                         |      |                    |
                         |      |                    (30) following ‘false’ branch...
                         |......
                         |  234 |                 count2 = count_spaces(buf);
                         |      |                          ~~~~~~~~~~~~~~~~~
                         |      |                          |
                         |      |                          (31) ...to here
                         |......
                         |  239 |                         if (!p) {
                         |      |                            ~
                         |      |                            |
                         |      |                            (32) following ‘false’ branch (when ‘p’ is non-NULL)...
                         |......
                         |  244 |                         *p = 0;
                         |      |                         ~~~~~~
                         |      |                            |
                         |      |                            (33) ...to here
                         |  245 |                         if (sscanf(p+1, "%llu", &n->val) != 1) {
                         |      |                            ~
                         |      |                            |
                         |      |                            (34) following ‘false’ branch...
                         |......
                         |  251 |                         if (skip)
                         |      |                            ~
                         |      |                            |
                         |      |                            (35) ...to here
                         |......
                         |  254 |                                 n = n->next;
                         |      |                                 ~~~~~~~~~~~
                         |      |                                   |
                         |      |                                   (36) dereference of NULL ‘n’
                         |

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
2 years agonetem: fix NULL deref on allocation failure
Stephen Hemminger [Tue, 9 May 2023 02:36:14 +0000 (19:36 -0700)] 
netem: fix NULL deref on allocation failure

q_netem.c: In function ‘get_distribution’:
q_netem.c:159:35: warning: dereference of possibly-NULL ‘data’ [CWE-690] [-Wanalyzer-possible-null-dereference]
  159 |                         data[n++] = x;
      |                         ~~~~~~~~~~^~~
  ‘netem_parse_opt’: events 1-24
    |
    |  192 | static int netem_parse_opt(struct qdisc_util *qu, int argc, char **argv,
    |      |            ^~~~~~~~~~~~~~~
    |      |            |
    |      |            (1) entry to ‘netem_parse_opt’
    |......
    |  212 |         for ( ; argc > 0; --argc, ++argv) {
    |      |                 ~~~~~~~~
    |      |                      |
    |      |                      (2) following ‘true’ branch (when ‘argc > 0’)...
    |  213 |                 if (matches(*argv, "limit") == 0) {
    |      |                    ~~~~~~~~~~~~~~~~~~~~~~~~
    |      |                    ||
    |      |                    |(3) ...to here
    |      |                    (4) following ‘true’ branch...
    |......
    |  219 |                 } else if (matches(*argv, "latency") == 0 ||
    |      |                           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    |      |                           ||                              |
    |      |                           |(5) ...to here                 (8) following ‘true’ branch...
    |      |                           (6) following ‘true’ branch...
    |  220 |                            matches(*argv, "delay") == 0) {
    |      |                            ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    |      |                            |
    |      |                            (7) ...to here
    |......
    |  243 |                 } else if (matches(*argv, "loss") == 0 ||
    |      |                           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    |      |                           ||                           |
    |      |                           |(9) ...to here              (12) following ‘true’ branch...
    |      |                           (10) following ‘true’ branch...
    |  244 |                            matches(*argv, "drop") == 0) {
    |      |                            ~~~~~~~~~~~~~~~~~~~~~~~~~~~
    |      |                            |
    |      |                            (11) ...to here
    |......
    |  366 |                 } else if (matches(*argv, "ecn") == 0) {
    |      |                           ~~~~~~~~~~~~~~~~~~~~~~
    |      |                           ||
    |      |                           |(13) ...to here
    |      |                           (14) following ‘true’ branch...
    |  367 |                         present[TCA_NETEM_ECN] = 1;
    |  368 |                 } else if (matches(*argv, "reorder") == 0) {
    |      |                           ~~~~~~~~~~~~~~~~~~~~~~~~~~
    |      |                           ||
    |      |                           |(15) ...to here
    |      |                           (16) following ‘true’ branch...
    |......
    |  383 |                 } else if (matches(*argv, "corrupt") == 0) {
    |      |                           ~~~~~~~~~~~~~~~~~~~~~~~~~~
    |      |                           ||
    |      |                           |(17) ...to here
    |      |                           (18) following ‘true’ branch...
    |......
    |  398 |                 } else if (matches(*argv, "gap") == 0) {
    |      |                           ~~~~~~~~~~~~~~~~~~~~~~
    |      |                           ||
    |      |                           |(19) ...to here
    |      |                           (20) following ‘true’ branch...
    |......
    |  404 |                 } else if (matches(*argv, "duplicate") == 0) {
    |      |                           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    |      |                           ||
    |      |                           |(21) ...to here
    |      |                           (22) following ‘true’ branch...
    |......
    |  417 |                 } else if (matches(*argv, "distribution") == 0) {
    |      |                           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    |      |                           ||
    |      |                           |(23) ...to here
    |      |                           (24) following ‘false’ branch...
    |
  ‘netem_parse_opt’: event 25
    |
    |../include/utils.h:50:29:
    |   50 | #define NEXT_ARG() do { argv++; if (--argc <= 0) incomplete_command(); } while(0)
    |      |                         ~~~~^~
    |      |                             |
    |      |                             (25) ...to here
q_netem.c:418:25: note: in expansion of macro ‘NEXT_ARG’
    |  418 |                         NEXT_ARG();
    |      |                         ^~~~~~~~
    |
  ‘netem_parse_opt’: event 26
    |
    |../include/utils.h:50:36:
    |   50 | #define NEXT_ARG() do { argv++; if (--argc <= 0) incomplete_command(); } while(0)
    |      |                                    ^
    |      |                                    |
    |      |                                    (26) following ‘false’ branch (when ‘argc != 0’)...
q_netem.c:418:25: note: in expansion of macro ‘NEXT_ARG’
    |  418 |                         NEXT_ARG();
    |      |                         ^~~~~~~~
    |
  ‘netem_parse_opt’: events 27-29
    |
    |  419 |                         dist_data = calloc(sizeof(dist_data[0]), MAX_DIST);
    |      |                                     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    |      |                                     |
    |      |                                     (27) ...to here
    |      |                                     (28) this call could return NULL
    |  420 |                         dist_size = get_distribution(*argv, dist_data, MAX_DIST);
    |      |                                     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    |      |                                     |
    |      |                                     (29) calling ‘get_distribution’ from ‘netem_parse_opt’
    |
    +--> ‘get_distribution’: events 30-31
           |
           |  124 | static int get_distribution(const char *type, __s16 *data, int maxdata)
           |      |            ^~~~~~~~~~~~~~~~
           |      |            |
           |      |            (30) entry to ‘get_distribution’
           |......
           |  135 |         if (f == NULL) {
           |      |            ~
           |      |            |
           |      |            (31) following ‘false’ branch (when ‘f’ is non-NULL)...
           |
         ‘get_distribution’: event 32
           |
           |cc1:
           | (32): ...to here
           |
         ‘get_distribution’: events 33-35
           |
           |  142 |         while (getline(&line, &len, f) != -1) {
           |      |                ~~~~~~~~~~~~~~~~~~~~~~~~^~~~~
           |      |                                        |
           |      |                                        (33) following ‘true’ branch...
           |......
           |  145 |                 if (*line == '\n' || *line == '#')
           |      |                    ~~~~~~
           |      |                    ||
           |      |                    |(34) ...to here
           |      |                    (35) following ‘false’ branch...
           |
         ‘get_distribution’: event 36
           |
           |cc1:
           | (36): ...to here
           |
         ‘get_distribution’: events 37-41
           |
           |  150 |                         if (endp == p)
           |      |                            ^
           |      |                            |
           |      |                            (37) following ‘false’ branch...
           |......
           |  153 |                         if (n >= maxdata) {
           |      |                            ~
           |      |                            |
           |      |                            (38) ...to here
           |      |                            (39) following ‘false’ branch (when ‘n < maxdata’)...
           |......
           |  159 |                         data[n++] = x;
           |      |                         ~~~~~~~~~~~~~
           |      |                               |   |
           |      |                               |   (41) ‘data + (long unsigned int)n * 2’ could be NULL: unchecked value from (28)
           |      |                               (40) ...to here
           |

Fixes: c1b81cb5fe92 ("netem potential dist table overflow")
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
2 years agom_action: fix warning of overwrite of const string
Stephen Hemminger [Tue, 9 May 2023 02:25:33 +0000 (19:25 -0700)] 
m_action: fix warning of overwrite of const string

The function get_action_kind() searches first for the given
action, then rescans on failure for "gact". In the process,
it would overwrite the argument.  Avoid the warning
by using a const argument and not copying.

The problem dates back to pre-git history.

m_action.c: In function ‘get_action_kind’:
m_action.c:126:17: warning: write to string literal [-Wanalyzer-write-to-string-literal]
  126 |                 strcpy(str, "gact");
      |                 ^~~~~~~~~~~~~~~~~~~
  ‘do_action’: events 1-6
    |
    |  853 | int do_action(int argc, char **argv)
    |      |     ^~~~~~~~~
    |      |     |
    |      |     (1) entry to ‘do_action’
    |......
    |  858 |         while (argc > 0) {
    |      |                ~~~~~~~~
    |      |                     |
    |      |                     (2) following ‘true’ branch...
    |  859 |
    |  860 |                 if (matches(*argv, "add") == 0) {
    |      |                    ~~~~~~~~~~~~~~~~~~~~~~
    |      |                    ||
    |      |                    |(3) ...to here
    |      |                    (4) following ‘false’ branch...
    |  861 |                         ret =  tc_action_modify(RTM_NEWACTION,
    |      |                                ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    |      |                                |
    |      |                                (5) ...to here
    |      |                                (6) calling ‘tc_action_modify’ from ‘do_action’
    |  862 |                                                 NLM_F_EXCL | NLM_F_CREATE,
    |      |                                                 ~~~~~~~~~~~~~~~~~~~~~~~~~~
    |  863 |                                                 &argc, &argv);
    |      |                                                 ~~~~~~~~~~~~~
    |
    +--> ‘tc_action_modify’: events 7-8
           |
           |  715 | static int tc_action_modify(int cmd, unsigned int flags,
           |      |            ^~~~~~~~~~~~~~~~
           |      |            |
           |      |            (7) entry to ‘tc_action_modify’
           |......
           |  735 |         if (parse_action(&argc, &argv, TCA_ACT_TAB, &req.n)) {
           |      |             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
           |      |             |
           |      |             (8) calling ‘parse_action’ from ‘tc_action_modify’
           |
           +--> ‘parse_action’: events 9-18
                  |
                  |  203 | int parse_action(int *argc_p, char ***argv_p, int tca_id, struct nlmsghdr *n)
                  |      |     ^~~~~~~~~~~~
                  |      |     |
                  |      |     (9) entry to ‘parse_action’
                  |......
                  |  217 |         if (argc <= 0)
                  |      |            ~
                  |      |            |
                  |      |            (10) following ‘false’ branch...
                  |......
                  |  220 |         tail2 = addattr_nest(n, MAX_MSG, tca_id);
                  |      |                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                  |      |                 |
                  |      |                 (11) ...to here
                  |  221 |
                  |  222 |         while (argc > 0) {
                  |      |                ~~~~~~~~
                  |      |                     |
                  |      |                     (12) following ‘true’ branch...
                  |  223 |
                  |  224 |                 memset(k, 0, sizeof(k));
                  |      |                 ~~~~~~~~~~~~~~~~~~~~~~~
                  |      |                 |
                  |      |                 (13) ...to here
                  |  225 |
                  |  226 |                 if (strcmp(*argv, "action") == 0) {
                  |      |                    ~
                  |      |                    |
                  |      |                    (14) following ‘true’ branch (when the strings are equal)...
                  |  227 |                         argc--;
                  |      |                         ~~~~~~
                  |      |                             |
                  |      |                             (15) ...to here
                  |......
                  |  231 |                         if (!gact_ld)
                  |      |                            ~
                  |      |                            |
                  |      |                            (16) following ‘true’ branch...
                  |  232 |                                 get_action_kind("gact");
                  |      |                                 ~~~~~~~~~~~~~~~~~~~~~~~
                  |      |                                 |
                  |      |                                 (17) ...to here
                  |      |                                 (18) calling ‘get_action_kind’ from ‘parse_action’
                  |
                  +--> ‘get_action_kind’: events 19-24
                         |
                         |   86 | static struct action_util *get_action_kind(char *str)
                         |      |                            ^~~~~~~~~~~~~~~
                         |      |                            |
                         |      |                            (19) entry to ‘get_action_kind’
                         |......
                         |  114 |         if (a == NULL)
                         |      |            ~
                         |      |            |
                         |      |            (20) following ‘true’ branch (when ‘a’ is NULL)...
                         |  115 |                 goto noexist;
                         |      |                 ~~~~
                         |      |                 |
                         |      |                 (21) ...to here
                         |......
                         |  124 |         if (!looked4gact) {
                         |      |            ~
                         |      |            |
                         |      |            (22) following ‘true’ branch (when ‘looked4gact == 0’)...
                         |  125 |                 looked4gact = 1;
                         |  126 |                 strcpy(str, "gact");
                         |      |                 ~~~~~~~~~~~~~~~~~~~
                         |      |                 |
                         |      |                 (23) ...to here
                         |      |                 (24) write to string literal here
                         |

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
2 years agotc_exec: don't dereference NULL on calloc failure
Stephen Hemminger [Tue, 9 May 2023 02:21:27 +0000 (19:21 -0700)] 
tc_exec: don't dereference NULL on calloc failure

Reported as:
tc_exec.c: In function ‘do_exec’:
tc_exec.c:103:18: warning: dereference of NULL ‘eu’ [CWE-476] [-Wanalyzer-null-dereference]
  103 |         return eu->parse_eopt(eu, argc, argv);
      |                ~~^~~~~~~~~~~~
  ‘do_exec’: events 1-6
    |
    |   81 | int do_exec(int argc, char **argv)
    |      |     ^~~~~~~
    |      |     |
    |      |     (1) entry to ‘do_exec’
    |......
    |   86 |         if (argc < 1) {
    |      |            ~
    |      |            |
    |      |            (2) following ‘false’ branch (when ‘argc > 0’)...
    |......
    |   91 |         if (matches(*argv, "help") == 0) {
    |      |            ~~~~~~~~~~~~~~~~~~~~~~~
    |      |            ||
    |      |            |(3) ...to here
    |      |            (4) following ‘true’ branch...
    |......
    |   96 |         strncpy(kind, *argv, sizeof(kind) - 1);
    |      |         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    |      |         |
    |      |         (5) ...to here
    |   97 |
    |   98 |         eu = get_exec_kind(kind);
    |      |              ~~~~~~~~~~~~~~~~~~~
    |      |              |
    |      |              (6) calling ‘get_exec_kind’ from ‘do_exec’
    |
    +--> ‘get_exec_kind’: events 7-10
           |
           |   40 | static struct exec_util *get_exec_kind(const char *name)
           |      |                          ^~~~~~~~~~~~~
           |      |                          |
           |      |                          (7) entry to ‘get_exec_kind’
           |......
           |   63 |         if (eu == NULL)
           |      |            ~
           |      |            |
           |      |            (8) following ‘true’ branch (when ‘eu’ is NULL)...
           |   64 |                 goto noexist;
           |      |                 ~~~~
           |      |                 |
           |      |                 (9) ...to here
           |......
           |   72 |         if (eu) {
           |      |            ~
           |      |            |
           |      |            (10) following ‘false’ branch (when ‘eu’ is NULL)...
           |
         ‘get_exec_kind’: event 11
           |
           |cc1:
           | (11): ...to here
           |
    <------+
    |
  ‘do_exec’: events 12-13
    |
    |   98 |         eu = get_exec_kind(kind);
    |      |              ^~~~~~~~~~~~~~~~~~~
    |      |              |
    |      |              (12) return of NULL to ‘do_exec’ from ‘get_exec_kind’
    |......
    |  103 |         return eu->parse_eopt(eu, argc, argv);
    |      |                ~~~~~~~~~~~~~~
    |      |                  |
    |      |                  (13) dereference of NULL ‘eu’
    |

Fixes: 4bd624467bc6 ("tc: built-in eBPF exec proxy")
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
2 years agotc_util fix unitialized warning
Stephen Hemminger [Tue, 9 May 2023 02:15:43 +0000 (19:15 -0700)] 
tc_util fix unitialized warning

tc_util.c: In function ‘parse_action_control_slash_spaces’:
tc_util.c:488:28: warning: use of uninitialized value ‘result2’ [CWE-457] [-Wanalyzer-use-of-uninitialized-value]
  488 |                 *result2_p = result2;
      |                 ~~~~~~~~~~~^~~~~~~~~
  ‘parse_action_control_slash_spaces’: events 1-5
    |
    |  455 | static int parse_action_control_slash_spaces(int *argc_p, char ***argv_p,
    |      |            ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    |      |            |
    |      |            (1) entry to ‘parse_action_control_slash_spaces’
    |......
    |  461 |         int result1 = -1, result2;
    |      |                           ~~~~~~~
    |      |                           |
    |      |                           (2) region created on stack here
    |      |                           (3) capacity: 4 bytes
    |......
    |  467 |                 switch (ok) {
    |      |                 ~~~~~~
    |      |                 |
    |      |                 (4) following ‘case 0:’ branch...
    |......
    |  475 |                         ret = parse_action_control(&argc, &argv,
    |      |                               ~
    |      |                               |
    |      |                               (5) inlined call to ‘parse_action_control’ from ‘parse_action_control_slash_spaces’
    |
    +--> ‘parse_action_control’: events 6-7
           |
           |  432 |         return __parse_action_control(argc_p, argv_p, result_p,
           |      |                ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
           |      |                |
           |      |                (6) ...to here
           |      |                (7) calling ‘__parse_action_control’ from ‘parse_action_control_slash_spaces’
           |  433 |                                       allow_num, false);
           |      |                                       ~~~~~~~~~~~~~~~~~
           |
         ‘__parse_action_control’: events 8-11
           |
           |  371 | static int __parse_action_control(int *argc_p, char ***argv_p, int *result_p,
           |      |            ^~~~~~~~~~~~~~~~~~~~~~
           |      |            |
           |      |            (8) entry to ‘__parse_action_control’
           |......
           |  378 |         if (!argc)
           |      |            ~
           |      |            |
           |      |            (9) following ‘false’ branch (when ‘argc != 0’)...
           |  379 |                 return -1;
           |  380 |         if (action_a2n(*argv, &result, allow_num) == -1) {
           |      |             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
           |      |             |
           |      |             (10) ...to here
           |      |             (11) calling ‘action_a2n’ from ‘__parse_action_control’
           |
           +--> ‘action_a2n’: events 12-16
                  |
                  |  335 | int action_a2n(char *arg, int *result, bool allow_num)
                  |      |     ^~~~~~~~~~
                  |      |     |
                  |      |     (12) entry to ‘action_a2n’
                  |......
                  |  356 |         for (iter = a2n; iter->a; iter++) {
                  |      |                          ~~~~
                  |      |                          |
                  |      |                          (13) following ‘true’ branch...
                  |  357 |                 if (matches(arg, iter->a) != 0)
                  |      |                     ~~~~~~~~~~~~~~~~~~~~~
                  |      |                     |
                  |      |                     (14) ...to here
                  |......
                  |  366 |         if (result)
                  |      |            ~
                  |      |            |
                  |      |            (15) following ‘true’ branch (when ‘result’ is non-NULL)...
                  |  367 |                 *result = n;
                  |      |                 ~~~~~~~~~~~
                  |      |                         |
                  |      |                         (16) ...to here
                  |
           <------+
           |
         ‘__parse_action_control’: event 17
           |
           |  380 |         if (action_a2n(*argv, &result, allow_num) == -1) {
           |      |             ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
           |      |             |
           |      |             (17) returning to ‘__parse_action_control’ from ‘action_a2n’
           |
    <------+
    |
  ‘parse_action_control_slash_spaces’: event 18
    |
    |  475 |                         ret = parse_action_control(&argc, &argv,
    |      |                               ^
    |      |                               |
    |      |                               (18) inlined call to ‘parse_action_control’ from ‘parse_action_control_slash_spaces’
    |
    +--> ‘parse_action_control’: event 19
           |
           |  432 |         return __parse_action_control(argc_p, argv_p, result_p,
           |      |                ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
           |      |                |
           |      |                (19) returning to ‘parse_action_control_slash_spaces’ from ‘__parse_action_control’
           |  433 |                                       allow_num, false);
           |      |                                       ~~~~~~~~~~~~~~~~~
           |
    <------+
    |
  ‘parse_action_control_slash_spaces’: events 20-24
    |
    |  477 |                         if (ret)
    |      |                            ^
    |      |                            |
    |      |                            (20) following ‘false’ branch...
    |  478 |                                 return ret;
    |  479 |                         ok++;
    |      |                         ~~~~
    |      |                           |
    |      |                           (21) ...to here
    |......
    |  487 |         if (ok == 2)
    |      |            ~
    |      |            |
    |      |            (22) following ‘true’ branch (when ‘ok == 2’)...
    |  488 |                 *result2_p = result2;
    |      |                 ~~~~~~~~~~~~~~~~~~~~
    |      |                            |
    |      |                            (23) ...to here
    |      |                            (24) use of uninitialized value ‘result2’ here
    |
tc_util.c:488:28: warning: use of uninitialized value ‘result2’ [CWE-457] [-Wanalyzer-use-of-uninitialized-value]
  488 |                 *result2_p = result2;
      |                 ~~~~~~~~~~~^~~~~~~~~
  ‘parse_action_control_slash’: events 1-5
    |
    |  505 | int parse_action_control_slash(int *argc_p, char ***argv_p,
    |      |     ^~~~~~~~~~~~~~~~~~~~~~~~~~
    |      |     |
    |      |     (1) entry to ‘parse_action_control_slash’
    |......
    |  510 |         char *p = strchr(*argv, '/');
    |      |                   ~~~~~~~~~~~~~~~~~~
    |      |                   |
    |      |                   (2) when ‘strchr’ returns NULL
    |  511 |
    |  512 |         if (!p)
    |      |            ~
    |      |            |
    |      |            (3) following ‘true’ branch (when ‘p’ is NULL)...
    |  513 |                 return parse_action_control_slash_spaces(argc_p, argv_p,
    |      |                        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    |      |                        |
    |      |                        (4) ...to here
    |      |                        (5) calling ‘parse_action_control_slash_spaces’ from ‘parse_action_control_slash’
    |  514 |                                                          result1_p, result2_p,
    |      |                                                          ~~~~~~~~~~~~~~~~~~~~~
    |  515 |                                                          allow_num);
    |      |                                                          ~~~~~~~~~~
    |
    +--> ‘parse_action_control_slash_spaces’: events 6-10
           |
           |  455 | static int parse_action_control_slash_spaces(int *argc_p, char ***argv_p,
           |      |            ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
           |      |            |
           |      |            (6) entry to ‘parse_action_control_slash_spaces’
           |......
           |  461 |         int result1 = -1, result2;
           |      |                           ~~~~~~~
           |      |                           |
           |      |                           (7) region created on stack here
           |      |                           (8) capacity: 4 bytes
           |......
           |  467 |                 switch (ok) {
           |      |                 ~~~~~~
           |      |                 |
           |      |                 (9) following ‘case 0:’ branch...
           |......
           |  475 |                         ret = parse_action_control(&argc, &argv,
           |      |                               ~
           |      |                               |
           |      |                               (10) inlined call to ‘parse_action_control’ from ‘parse_action_control_slash_spaces’
           |
           +--> ‘parse_action_control’: events 11-12
                  |
                  |  432 |         return __parse_action_control(argc_p, argv_p, result_p,
                  |      |                ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                  |      |                |
                  |      |                (11) ...to here
                  |      |                (12) calling ‘__parse_action_control’ from ‘parse_action_control_slash_spaces’
                  |  433 |                                       allow_num, false);
                  |      |                                       ~~~~~~~~~~~~~~~~~
                  |
                ‘__parse_action_control’: events 13-16
                  |
                  |  371 | static int __parse_action_control(int *argc_p, char ***argv_p, int *result_p,
                  |      |            ^~~~~~~~~~~~~~~~~~~~~~
                  |      |            |
                  |      |            (13) entry to ‘__parse_action_control’
                  |......
                  |  378 |         if (!argc)
                  |      |            ~
                  |      |            |
                  |      |            (14) following ‘false’ branch (when ‘argc != 0’)...
                  |  379 |                 return -1;
                  |  380 |         if (action_a2n(*argv, &result, allow_num) == -1) {
                  |      |             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                  |      |             |
                  |      |             (15) ...to here
                  |      |             (16) calling ‘action_a2n’ from ‘__parse_action_control’
                  |
                  +--> ‘action_a2n’: events 17-21
                         |
                         |  335 | int action_a2n(char *arg, int *result, bool allow_num)
                         |      |     ^~~~~~~~~~
                         |      |     |
                         |      |     (17) entry to ‘action_a2n’
                         |......
                         |  356 |         for (iter = a2n; iter->a; iter++) {
                         |      |                          ~~~~
                         |      |                          |
                         |      |                          (18) following ‘true’ branch...
                         |  357 |                 if (matches(arg, iter->a) != 0)
                         |      |                     ~~~~~~~~~~~~~~~~~~~~~
                         |      |                     |
                         |      |                     (19) ...to here
                         |......
                         |  366 |         if (result)
                         |      |            ~
                         |      |            |
                         |      |            (20) following ‘true’ branch (when ‘result’ is non-NULL)...
                         |  367 |                 *result = n;
                         |      |                 ~~~~~~~~~~~
                         |      |                         |
                         |      |                         (21) ...to here
                         |
                  <------+
                  |
                ‘__parse_action_control’: event 22
                  |
                  |  380 |         if (action_a2n(*argv, &result, allow_num) == -1) {
                  |      |             ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                  |      |             |
                  |      |             (22) returning to ‘__parse_action_control’ from ‘action_a2n’
                  |
           <------+
           |
         ‘parse_action_control_slash_spaces’: event 23
           |
           |  475 |                         ret = parse_action_control(&argc, &argv,
           |      |                               ^
           |      |                               |
           |      |                               (23) inlined call to ‘parse_action_control’ from ‘parse_action_control_slash_spaces’
           |
           +--> ‘parse_action_control’: event 24
                  |
                  |  432 |         return __parse_action_control(argc_p, argv_p, result_p,
                  |      |                ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                  |      |                |
                  |      |                (24) returning to ‘parse_action_control_slash_spaces’ from ‘__parse_action_control’
                  |  433 |                                       allow_num, false);
                  |      |                                       ~~~~~~~~~~~~~~~~~
                  |
           <------+
           |
         ‘parse_action_control_slash_spaces’: events 25-29
           |
           |  477 |                         if (ret)
           |      |                            ^
           |      |                            |
           |      |                            (25) following ‘false’ branch...
           |  478 |                                 return ret;
           |  479 |                         ok++;
           |      |                         ~~~~
           |      |                           |
           |      |                           (26) ...to here
           |......
           |  487 |         if (ok == 2)
           |      |            ~
           |      |            |
           |      |            (27) following ‘true’ branch (when ‘ok == 2’)...
           |  488 |                 *result2_p = result2;
           |      |                 ~~~~~~~~~~~~~~~~~~~~
           |      |                            |
           |      |                            (28) ...to here
           |      |                            (29) use of uninitialized value ‘result2’ here
           |

Fixes: e67aba559581 ("tc: actions: add helpers to parse and print control actions")
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
2 years agotc_filter: fix unitialized warning
Stephen Hemminger [Tue, 9 May 2023 02:12:23 +0000 (19:12 -0700)] 
tc_filter: fix unitialized warning

When run with -fanalyzer.

tc_filter.c: In function ‘tc_filter_list’:
tc_filter.c:718:17: warning: use of uninitialized value ‘chain_index’ [CWE-457] [-Wanalyzer-use-of-uninitialized-value]
  718 |                 addattr32(&req.n, sizeof(req), TCA_CHAIN, chain_index);
      |                 ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  ‘do_chain’: events 1-4
    |
    |  772 | int do_chain(int argc, char **argv)
    |      |     ^~~~~~~~
    |      |     |
    |      |     (1) entry to ‘do_chain’
    |  773 | {
    |  774 |         if (argc < 1)
    |      |            ~
    |      |            |
    |      |            (2) following ‘true’ branch (when ‘argc <= 0’)...
    |  775 |                 return tc_filter_list(RTM_GETCHAIN, 0, NULL);
    |      |                        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    |      |                        |
    |      |                        (3) ...to here
    |      |                        (4) calling ‘tc_filter_list’ from ‘do_chain’
    |
    +--> ‘tc_filter_list’: events 5-8
           |
           |  582 | static int tc_filter_list(int cmd, int argc, char **argv)
           |      |            ^~~~~~~~~~~~~~
           |      |            |
           |      |            (5) entry to ‘tc_filter_list’
           |......
           |  597 |         __u32 chain_index;
           |      |               ~~~~~~~~~~~
           |      |               |
           |      |               (6) region created on stack here
           |      |               (7) capacity: 4 bytes
           |......
           |  601 |         while (argc > 0) {
           |      |                ~~~~~~~~
           |      |                     |
           |      |                     (8) following ‘false’ branch (when ‘argc <= 0’)...
           |
         ‘tc_filter_list’: event 9
           |
           |../include/uapi/linux/pkt_sched.h:72:35:
           |   72 | #define TC_H_MAKE(maj,min) (((maj)&TC_H_MAJ_MASK)|((min)&TC_H_MIN_MASK))
           |      |                             ~~~~~~^~~~~~~~~~~~~~~
           |      |                                   |
           |      |                                   (9) ...to here
tc_filter.c:698:26: note: in expansion of macro ‘TC_H_MAKE’
           |  698 |         req.t.tcm_info = TC_H_MAKE(prio<<16, protocol);
           |      |                          ^~~~~~~~~
           |
         ‘tc_filter_list’: events 10-16
           |
           |  702 |         if (d[0]) {
           |      |            ^
           |      |            |
           |      |            (10) following ‘false’ branch...
           |......
           |  707 |         } else if (block_index) {
           |      |                   ~~~~~~~~~~~~
           |      |                   ||
           |      |                   |(11) ...to here
           |      |                   (12) following ‘false’ branch...
           |......
           |  717 |         if (filter_chain_index_set)
           |      |            ~~~~~~~~~~~~~~~~~~~~~~~
           |      |            ||
           |      |            |(13) ...to here
           |      |            (14) following ‘true’ branch...
           |  718 |                 addattr32(&req.n, sizeof(req), TCA_CHAIN, chain_index);
           |      |                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
           |      |                 |
           |      |                 (15) ...to here
           |      |                 (16) use of uninitialized value ‘chain_index’ here
           |
tc_filter.c:718:17: warning: use of uninitialized value ‘chain_index’ [CWE-457] [-Wanalyzer-use-of-uninitialized-value]
  718 |                 addattr32(&req.n, sizeof(req), TCA_CHAIN, chain_index);
      |                 ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  ‘do_filter’: events 1-4
    |
    |  744 | int do_filter(int argc, char **argv)
    |      |     ^~~~~~~~~
    |      |     |
    |      |     (1) entry to ‘do_filter’
    |  745 | {
    |  746 |         if (argc < 1)
    |      |            ~
    |      |            |
    |      |            (2) following ‘true’ branch (when ‘argc <= 0’)...
    |  747 |                 return tc_filter_list(RTM_GETTFILTER, 0, NULL);
    |      |                        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    |      |                        |
    |      |                        (3) ...to here
    |      |                        (4) calling ‘tc_filter_list’ from ‘do_filter’
    |
    +--> ‘tc_filter_list’: events 5-8
           |
           |  582 | static int tc_filter_list(int cmd, int argc, char **argv)
           |      |            ^~~~~~~~~~~~~~
           |      |            |
           |      |            (5) entry to ‘tc_filter_list’
           |......
           |  597 |         __u32 chain_index;
           |      |               ~~~~~~~~~~~
           |      |               |
           |      |               (6) region created on stack here
           |      |               (7) capacity: 4 bytes
           |......
           |  601 |         while (argc > 0) {
           |      |                ~~~~~~~~
           |      |                     |
           |      |                     (8) following ‘false’ branch (when ‘argc <= 0’)...
           |
         ‘tc_filter_list’: event 9
           |
           |../include/uapi/linux/pkt_sched.h:72:35:
           |   72 | #define TC_H_MAKE(maj,min) (((maj)&TC_H_MAJ_MASK)|((min)&TC_H_MIN_MASK))
           |      |                             ~~~~~~^~~~~~~~~~~~~~~
           |      |                                   |
           |      |                                   (9) ...to here
tc_filter.c:698:26: note: in expansion of macro ‘TC_H_MAKE’
           |  698 |         req.t.tcm_info = TC_H_MAKE(prio<<16, protocol);
           |      |                          ^~~~~~~~~
           |
         ‘tc_filter_list’: events 10-16
           |
           |  702 |         if (d[0]) {
           |      |            ^
           |      |            |
           |      |            (10) following ‘false’ branch...
           |......
           |  707 |         } else if (block_index) {
           |      |                   ~~~~~~~~~~~~
           |      |                   ||
           |      |                   |(11) ...to here
           |      |                   (12) following ‘false’ branch...
           |......
           |  717 |         if (filter_chain_index_set)
           |      |            ~~~~~~~~~~~~~~~~~~~~~~~
           |      |            ||
           |      |            |(13) ...to here
           |      |            (14) following ‘true’ branch...
           |  718 |                 addattr32(&req.n, sizeof(req), TCA_CHAIN, chain_index);
           |      |                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
           |      |                 |
           |      |                 (15) ...to here
           |      |                 (16) use of uninitialized value ‘chain_index’ here
           |

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
2 years agoiproute_lwtunnel: fix possible use of NULL when malloc() fails
Stephen Hemminger [Tue, 9 May 2023 02:05:38 +0000 (19:05 -0700)] 
iproute_lwtunnel: fix possible use of NULL when malloc() fails

iproute_lwtunnel.c: In function ‘parse_srh’:
iproute_lwtunnel.c:903:9: warning: use of possibly-NULL ‘srh’ where non-null expected [CWE-690] [-Wanalyzer-possible-null-argument]
  903 |         memset(srh, 0, srhlen);
      |         ^~~~~~~~~~~~~~~~~~~~~~
  ‘parse_srh’: events 1-2
    |
    |  902 |         srh = malloc(srhlen);
    |      |               ^~~~~~~~~~~~~~
    |      |               |
    |      |               (1) this call could return NULL
    |  903 |         memset(srh, 0, srhlen);
    |      |         ~~~~~~~~~~~~~~~~~~~~~~
    |      |         |
    |      |         (2) argument 1 (‘srh’) from (1) could be NULL where non-null expected
    |
In file included from iproute_lwtunnel.c:13:
/usr/include/string.h:61:14: note: argument 1 of ‘memset’ must be non-null
   61 | extern void *memset (void *__s, int __c, size_t __n) __THROW __nonnull ((1));
      |              ^~~~~~
iproute_lwtunnel.c: In function ‘parse_encap_seg6’:
iproute_lwtunnel.c:980:9: warning: use of possibly-NULL ‘tuninfo’ where non-null expected [CWE-690] [-Wanalyzer-possible-null-argument]
  980 |         memset(tuninfo, 0, sizeof(*tuninfo) + srhlen);
      |         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  ‘parse_encap_seg6’: events 1-2
    |
    |  934 | static int parse_encap_seg6(struct rtattr *rta, size_t len, int *argcp,
    |      |            ^~~~~~~~~~~~~~~~
    |      |            |
    |      |            (1) entry to ‘parse_encap_seg6’
    |......
    |  976 |         srh = parse_srh(segbuf, hmac, encap);
    |      |               ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    |      |               |
    |      |               (2) calling ‘parse_srh’ from ‘parse_encap_seg6’
    |
    +--> ‘parse_srh’: events 3-5
           |
           |  882 | static struct ipv6_sr_hdr *parse_srh(char *segbuf, int hmac, bool encap)
           |      |                            ^~~~~~~~~
           |      |                            |
           |      |                            (3) entry to ‘parse_srh’
           |......
           |  922 |         if (hmac) {
           |      |            ~
           |      |            |
           |      |            (4) following ‘false’ branch (when ‘hmac == 0’)...
           |......
           |  931 |         return srh;
           |      |                ~~~
           |      |                |
           |      |                (5) ...to here
           |
    <------+
    |
  ‘parse_encap_seg6’: events 6-8
    |
    |  976 |         srh = parse_srh(segbuf, hmac, encap);
    |      |               ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    |      |               |
    |      |               (6) returning to ‘parse_encap_seg6’ from ‘parse_srh’
    |......
    |  979 |         tuninfo = malloc(sizeof(*tuninfo) + srhlen);
    |      |                   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    |      |                   |
    |      |                   (7) this call could return NULL
    |  980 |         memset(tuninfo, 0, sizeof(*tuninfo) + srhlen);
    |      |         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    |      |         |
    |      |         (8) argument 1 (‘tuninfo’) from (7) could be NULL where non-null expected
    |
/usr/include/string.h:61:14: note: argument 1 of ‘memset’ must be non-null
   61 | extern void *memset (void *__s, int __c, size_t __n) __THROW __nonnull ((1));
      |              ^~~~~~
iproute_lwtunnel.c: In function ‘parse_rpl_srh’:
iproute_lwtunnel.c:1018:21: warning: dereference of possibly-NULL ‘srh’ [CWE-690] [-Wanalyzer-possible-null-dereference]
 1018 |         srh->hdrlen = (srhlen >> 3) - 1;
      |         ~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~
  ‘parse_rpl_srh’: events 1-2
    |
    | 1016 |         srh = calloc(1, srhlen);
    |      |               ^~~~~~~~~~~~~~~~~
    |      |               |
    |      |               (1) this call could return NULL
    | 1017 |
    | 1018 |         srh->hdrlen = (srhlen >> 3) - 1;
    |      |         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    |      |                     |
    |      |                     (2) ‘srh’ could be NULL: unchecked value from (1)
    |

Fixes: 00e76d4da37f ("iproute: add helper functions for SRH processing")
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
2 years agoipmaddr: fix dereference of NULL on malloc() failure
Stephen Hemminger [Tue, 9 May 2023 02:02:20 +0000 (19:02 -0700)] 
ipmaddr: fix dereference of NULL on malloc() failure

Found by -fanalyzer. This is a bug since beginning of initial
versions of ip multicast support (pre git).

ipmaddr.c: In function ‘read_dev_mcast’:
ipmaddr.c:105:25: warning: dereference of possibly-NULL ‘ma’ [CWE-690] [-Wanalyzer-possible-null-dereference]
  105 |                         memcpy(ma, &m, sizeof(m));
      |                         ^~~~~~~~~~~~~~~~~~~~~~~~~
  ‘do_multiaddr’: events 1-4
    |
    |  354 | int do_multiaddr(int argc, char **argv)
    |      |     ^~~~~~~~~~~~
    |      |     |
    |      |     (1) entry to ‘do_multiaddr’
    |  355 | {
    |  356 |         if (argc < 1)
    |      |            ~
    |      |            |
    |      |            (2) following ‘true’ branch (when ‘argc <= 0’)...
    |  357 |                 return multiaddr_list(0, NULL);
    |      |                        ~~~~~~~~~~~~~~~~~~~~~~~
    |      |                        |
    |      |                        (3) ...to here
    |      |                        (4) calling ‘multiaddr_list’ from ‘do_multiaddr’
    |
    +--> ‘multiaddr_list’: events 5-10
           |
           |  255 | static int multiaddr_list(int argc, char **argv)
           |      |            ^~~~~~~~~~~~~~
           |      |            |
           |      |            (5) entry to ‘multiaddr_list’
           |......
           |  262 |         while (argc > 0) {
           |      |                ~~~~~~~~
           |      |                     |
           |      |                     (6) following ‘false’ branch (when ‘argc <= 0’)...
           |......
           |  275 |         if (!filter.family || filter.family == AF_PACKET)
           |      |            ~ ~~~~~~~~~~~~~
           |      |            |       |
           |      |            |       (7) ...to here
           |      |            (8) following ‘true’ branch...
           |  276 |                 read_dev_mcast(&list);
           |      |                 ~~~~~~~~~~~~~~~~~~~~~
           |      |                 |
           |      |                 (9) ...to here
           |      |                 (10) calling ‘read_dev_mcast’ from ‘multiaddr_list’
           |
           +--> ‘read_dev_mcast’: events 11-12
                  |
                  |   82 | static void read_dev_mcast(struct ma_info **result_p)
                  |      |             ^~~~~~~~~~~~~~
                  |      |             |
                  |      |             (11) entry to ‘read_dev_mcast’
                  |......
                  |   87 |         if (!fp)
                  |      |            ~
                  |      |            |
                  |      |            (12) following ‘false’ branch (when ‘fp’ is non-NULL)...
                  |
                ‘read_dev_mcast’: event 13
                  |
                  |cc1:
                  | (13): ...to here
                  |
                ‘read_dev_mcast’: events 14-17
                  |
                  |   90 |         while (fgets(buf, sizeof(buf), fp)) {
                  |      |                ^~~~~
                  |      |                |
                  |      |                (14) following ‘true’ branch...
                  |   91 |                 char hexa[256];
                  |   92 |                 struct ma_info m = { .addr.family = AF_PACKET };
                  |      |                                ~
                  |      |                                |
                  |      |                                (15) ...to here
                  |......
                  |  103 |                         struct ma_info *ma = malloc(sizeof(m));
                  |      |                                              ~~~~~~~~~~~~~~~~~
                  |      |                                              |
                  |      |                                              (16) this call could return NULL
                  |  104 |
                  |  105 |                         memcpy(ma, &m, sizeof(m));
                  |      |                         ~~~~~~~~~~~~~~~~~~~~~~~~~
                  |      |                         |
                  |      |                         (17) ‘ma’ could be NULL: unchecked value from (16)
                  |
ipmaddr.c: In function ‘read_igmp’:
ipmaddr.c:152:17: warning: dereference of possibly-NULL ‘ma’ [CWE-690] [-Wanalyzer-possible-null-dereference]
  152 |                 memcpy(ma, &m, sizeof(m));
      |                 ^~~~~~~~~~~~~~~~~~~~~~~~~
  ‘do_multiaddr’: events 1-4
    |
    |  354 | int do_multiaddr(int argc, char **argv)
    |      |     ^~~~~~~~~~~~
    |      |     |
    |      |     (1) entry to ‘do_multiaddr’
    |  355 | {
    |  356 |         if (argc < 1)
    |      |            ~
    |      |            |
    |      |            (2) following ‘true’ branch (when ‘argc <= 0’)...
    |  357 |                 return multiaddr_list(0, NULL);
    |      |                        ~~~~~~~~~~~~~~~~~~~~~~~
    |      |                        |
    |      |                        (3) ...to here
    |      |                        (4) calling ‘multiaddr_list’ from ‘do_multiaddr’
    |
    +--> ‘multiaddr_list’: events 5-10
           |
           |  255 | static int multiaddr_list(int argc, char **argv)
           |      |            ^~~~~~~~~~~~~~
           |      |            |
           |      |            (5) entry to ‘multiaddr_list’
           |......
           |  262 |         while (argc > 0) {
           |      |                ~~~~~~~~
           |      |                     |
           |      |                     (6) following ‘false’ branch (when ‘argc <= 0’)...
           |......
           |  275 |         if (!filter.family || filter.family == AF_PACKET)
           |      |              ~~~~~~~~~~~~~
           |      |                    |
           |      |                    (7) ...to here
           |  276 |                 read_dev_mcast(&list);
           |  277 |         if (!filter.family || filter.family == AF_INET)
           |      |            ~
           |      |            |
           |      |            (8) following ‘true’ branch...
           |  278 |                 read_igmp(&list);
           |      |                 ~~~~~~~~~~~~~~~~
           |      |                 |
           |      |                 (9) ...to here
           |      |                 (10) calling ‘read_igmp’ from ‘multiaddr_list’
           |
           +--> ‘read_igmp’: events 11-14
                  |
                  |  116 | static void read_igmp(struct ma_info **result_p)
                  |      |             ^~~~~~~~~
                  |      |             |
                  |      |             (11) entry to ‘read_igmp’
                  |......
                  |  126 |         if (!fp)
                  |      |            ~
                  |      |            |
                  |      |            (12) following ‘false’ branch (when ‘fp’ is non-NULL)...
                  |  127 |                 return;
                  |  128 |         if (!fgets(buf, sizeof(buf), fp)) {
                  |      |            ~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~
                  |      |            | |
                  |      |            | (13) ...to here
                  |      |            (14) following ‘false’ branch...
                  |
                ‘read_igmp’: event 15
                  |
                  |cc1:
                  | (15): ...to here
                  |
                ‘read_igmp’: events 16-19
                  |
                  |  133 |         while (fgets(buf, sizeof(buf), fp)) {
                  |      |                ^~~~~
                  |      |                |
                  |      |                (16) following ‘true’ branch...
                  |......
                  |  136 |                 if (buf[0] != '\t') {
                  |      |                     ~~~~~~
                  |      |                        |
                  |      |                        (17) ...to here
                  |......
                  |  151 |                 ma = malloc(sizeof(m));
                  |      |                      ~~~~~~~~~~~~~~~~~
                  |      |                      |
                  |      |                      (18) this call could return NULL
                  |  152 |                 memcpy(ma, &m, sizeof(m));
                  |      |                 ~~~~~~~~~~~~~~~~~~~~~~~~~
                  |      |                 |
                  |      |                 (19) ‘ma’ could be NULL: unchecked value from (18)
                  |
ipmaddr.c: In function ‘read_igmp6’:
ipmaddr.c:181:25: warning: dereference of possibly-NULL ‘ma’ [CWE-690] [-Wanalyzer-possible-null-dereference]
  181 |                         memcpy(ma, &m, sizeof(m));
      |                         ^~~~~~~~~~~~~~~~~~~~~~~~~
  ‘do_multiaddr’: events 1-4
    |
    |  354 | int do_multiaddr(int argc, char **argv)
    |      |     ^~~~~~~~~~~~
    |      |     |
    |      |     (1) entry to ‘do_multiaddr’
    |  355 | {
    |  356 |         if (argc < 1)
    |      |            ~
    |      |            |
    |      |            (2) following ‘true’ branch (when ‘argc <= 0’)...
    |  357 |                 return multiaddr_list(0, NULL);
    |      |                        ~~~~~~~~~~~~~~~~~~~~~~~
    |      |                        |
    |      |                        (3) ...to here
    |      |                        (4) calling ‘multiaddr_list’ from ‘do_multiaddr’
    |
    +--> ‘multiaddr_list’: events 5-10
           |
           |  255 | static int multiaddr_list(int argc, char **argv)
           |      |            ^~~~~~~~~~~~~~
           |      |            |
           |      |            (5) entry to ‘multiaddr_list’
           |......
           |  262 |         while (argc > 0) {
           |      |                ~~~~~~~~
           |      |                     |
           |      |                     (6) following ‘false’ branch (when ‘argc <= 0’)...
           |......
           |  275 |         if (!filter.family || filter.family == AF_PACKET)
           |      |              ~~~~~~~~~~~~~
           |      |                    |
           |      |                    (7) ...to here
           |......
           |  279 |         if (!filter.family || filter.family == AF_INET6)
           |      |            ~
           |      |            |
           |      |            (8) following ‘true’ branch...
           |  280 |                 read_igmp6(&list);
           |      |                 ~~~~~~~~~~~~~~~~~
           |      |                 |
           |      |                 (9) ...to here
           |      |                 (10) calling ‘read_igmp6’ from ‘multiaddr_list’
           |
           +--> ‘read_igmp6’: events 11-12
                  |
                  |  159 | static void read_igmp6(struct ma_info **result_p)
                  |      |             ^~~~~~~~~~
                  |      |             |
                  |      |             (11) entry to ‘read_igmp6’
                  |......
                  |  164 |         if (!fp)
                  |      |            ~
                  |      |            |
                  |      |            (12) following ‘false’ branch (when ‘fp’ is non-NULL)...
                  |
                ‘read_igmp6’: event 13
                  |
                  |cc1:
                  | (13): ...to here
                  |
                ‘read_igmp6’: events 14-17
                  |
                  |  167 |         while (fgets(buf, sizeof(buf), fp)) {
                  |      |                ^~~~~
                  |      |                |
                  |      |                (14) following ‘true’ branch...
                  |  168 |                 char hexa[256];
                  |  169 |                 struct ma_info m = { .addr.family = AF_INET6 };
                  |      |                                ~
                  |      |                                |
                  |      |                                (15) ...to here
                  |......
                  |  179 |                         struct ma_info *ma = malloc(sizeof(m));
                  |      |                                              ~~~~~~~~~~~~~~~~~
                  |      |                                              |
                  |      |                                              (16) this call could return NULL
                  |  180 |
                  |  181 |                         memcpy(ma, &m, sizeof(m));
                  |      |                         ~~~~~~~~~~~~~~~~~~~~~~~~~
                  |      |                         |
                  |      |                         (17) ‘ma’ could be NULL: unchecked value from (16)
                  |

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
2 years agolib/fs: fix file leak in task_get_name
Stephen Hemminger [Tue, 9 May 2023 01:38:10 +0000 (18:38 -0700)] 
lib/fs: fix file leak in task_get_name

Fixes the problem identified -fanalyzer.
Why did rdma choose to reimplement the same function as
exiting glibc pthread_getname().

fs.c: In function ‘get_task_name’:
fs.c:355:12: warning: leak of FILE ‘f’ [CWE-775] [-Wanalyzer-file-leak]
  355 |         if (!fgets(name, len, f))
      |            ^
  ‘get_task_name’: events 1-9
    |
    |  345 |         if (!pid)
    |      |            ^
    |      |            |
    |      |            (1) following ‘false’ branch (when ‘pid != 0’)...
    |......
    |  348 |         if (snprintf(path, sizeof(path), "/proc/%d/comm", pid) >= sizeof(path))
    |      |            ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    |      |            ||
    |      |            |(2) ...to here
    |      |            (3) following ‘false’ branch...
    |......
    |  351 |         f = fopen(path, "r");
    |      |             ~~~~~~~~~~~~~~~~
    |      |             |
    |      |             (4) ...to here
    |      |             (5) opened here
    |  352 |         if (!f)
    |      |            ~
    |      |            |
    |      |            (6) assuming ‘f’ is non-NULL
    |      |            (7) following ‘false’ branch (when ‘f’ is non-NULL)...
    |......
    |  355 |         if (!fgets(name, len, f))
    |      |            ~ ~~~~~~~~~~~~~~~~~~~
    |      |            | |
    |      |            | (8) ...to here
    |      |            (9) following ‘true’ branch...
    |
  ‘get_task_name’: event 10
    |
    |cc1:
    | (10): ...to here
    |
  ‘get_task_name’: event 11
    |
    |  355 |         if (!fgets(name, len, f))
    |      |            ^
    |      |            |
    |      |            (11) ‘f’ leaks here; was opened at (5)
    |
fs.c:355:12: warning: leak of ‘f’ [CWE-401] [-Wanalyzer-malloc-leak]
  ‘get_task_name’: events 1-9
    |
    |  345 |         if (!pid)
    |      |            ^
    |      |            |
    |      |            (1) following ‘false’ branch (when ‘pid != 0’)...
    |......
    |  348 |         if (snprintf(path, sizeof(path), "/proc/%d/comm", pid) >= sizeof(path))
    |      |            ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    |      |            ||
    |      |            |(2) ...to here
    |      |            (3) following ‘false’ branch...
    |......
    |  351 |         f = fopen(path, "r");
    |      |             ~~~~~~~~~~~~~~~~
    |      |             |
    |      |             (4) ...to here
    |      |             (5) allocated here
    |  352 |         if (!f)
    |      |            ~
    |      |            |
    |      |            (6) assuming ‘f’ is non-NULL
    |      |            (7) following ‘false’ branch (when ‘f’ is non-NULL)...
    |......
    |  355 |         if (!fgets(name, len, f))
    |      |            ~ ~~~~~~~~~~~~~~~~~~~
    |      |            | |
    |      |            | (8) ...to here
    |      |            (9) following ‘true’ branch...
    |
  ‘get_task_name’: event 10
    |
    |cc1:
    | (10): ...to here
    |
  ‘get_task_name’: event 11
    |
    |  355 |         if (!fgets(name, len, f))
    |      |            ^
    |      |            |
    |      |            (11) ‘f’ leaks here; was allocated at (5)

Fixes: 81bfd01a4c9e ("lib: move get_task_name() from rdma")
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
2 years agoAdd MAINTAINERS file
Stephen Hemminger [Wed, 10 May 2023 15:36:16 +0000 (08:36 -0700)] 
Add MAINTAINERS file

Record the maintainers of subsections of iproute2.
The subtree maintainers are based off of most recent current
patches and maintainer of kernel portion of that subsystem.

Acked-by: Nikolay Aleksandrov <razor@blackwall.org>
Acked-by: Petr Machata <me@pmachata.org> # For DCB
Acked-by: Parav Pandit <parav@nvidia.com>
Acked-by: Jiri Pirko <jiri@nvidia.com>
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
2 years agoiproute2: optimize code and fix some mem-leak risk
zhaoshuang [Thu, 11 May 2023 00:37:26 +0000 (08:37 +0800)] 
iproute2: optimize code and fix some mem-leak risk

Signed-off-by: zhaoshuang <izhaoshuang@163.com>
Reviewed-by: Pawel Chmielewski <pawel.chmielewski@intel.com>
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
2 years agoipnetns: fix fd leak with 'ip netns set'
Nicolas Dichtel [Thu, 11 May 2023 14:42:24 +0000 (16:42 +0200)] 
ipnetns: fix fd leak with 'ip netns set'

There is no reason to open this netns file. set_netnsid_from_name() uses
netns_get_fd() for this purpose and uses the returned fd.

Reported-by: Stephen Hemminger <stephen@networkplumber.org>
Fixes: d182ee1307c7 ("ipnetns: allow to get and set netns ids")
Signed-off-by: Nicolas Dichtel <nicolas.dichtel@6wind.com>
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
2 years agoip-rule: more manual page grammer fixes
Stephen Hemminger [Thu, 11 May 2023 21:10:26 +0000 (14:10 -0700)] 
ip-rule: more manual page grammer fixes

Add missing articles and replace use of passive voice.

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
2 years agordma: Report device protocol
Kamal Heib [Thu, 4 May 2023 12:09:18 +0000 (08:09 -0400)] 
rdma: Report device protocol

Add support for reporting the device protocol.

11: mlx5_0: node_type ca protocol roce fw 12.28.2006
    node_guid 248a:0703:004b:f094 sys_image_guid 248a:0703:004b:f094
12: mlx5_1: node_type ca protocol ib fw 12.28.2006
    node_guid 248a:0703:0049:d4f0 sys_image_guid 248a:0703:0049:d4f0
13: mlx5_2: node_type ca protocol ib fw 12.28.2006
    node_guid 248a:0703:0049:d4f1 sys_image_guid 248a:0703:0049:d4f0
19: siw0: node_type rnic protocol iw node_guid 0200:00ff:fe00:0000
    sys_image_guid 0200:00ff:fe00:0000

Signed-off-by: Kamal Heib <kheib@redhat.com>
Acked-by: Leon Romanovsky <leonro@nvidia.com>
Signed-off-by: David Ahern <dsahern@kernel.org>
2 years agoMerge branch 'main' into next
David Ahern [Wed, 10 May 2023 20:00:29 +0000 (14:00 -0600)] 
Merge branch 'main' into next

Signed-off-by: David Ahern <dsahern@kernel.org>
2 years agoremove unnecessary checks for NULL before calling free()
Stephen Hemminger [Wed, 10 May 2023 15:16:40 +0000 (08:16 -0700)] 
remove unnecessary checks for NULL before calling free()

The function free() handles the case wher argument is NULL
by doing nothing. So the extra checks are not needed.

Found by modified version of kernel coccinelle script.

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
2 years agouapi: add capability.h
Stephen Hemminger [Tue, 9 May 2023 21:22:20 +0000 (14:22 -0700)] 
uapi: add capability.h

All kernel header files should come from local copy of sanitized
headers, rather than relying on what Linux distribution ships.

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
2 years agouapi: update kernel headers 6.4-rc1
Stephen Hemminger [Mon, 8 May 2023 20:41:31 +0000 (13:41 -0700)] 
uapi: update kernel headers 6.4-rc1

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
2 years agofixed the grammar in ip-rule(8) man page
Bilal Khan [Tue, 2 May 2023 09:44:32 +0000 (14:44 +0500)] 
fixed the grammar in ip-rule(8) man page

a small grammatical error has been idenfied in the ip-rule(8) man page

Signed-off-by: Bilal Khan <bilalkhanrecovered@gmail.com>
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
2 years agoMerge git://git.kernel.org/pub/scm/network/iproute2/iproute2-next
Stephen Hemminger [Sat, 29 Apr 2023 19:10:38 +0000 (12:10 -0700)] 
Merge git://git.kernel.org/pub/scm/network/iproute2/iproute2-next

2 years agov6.3.0 v6.3.0
Stephen Hemminger [Thu, 27 Apr 2023 15:55:24 +0000 (08:55 -0700)] 
v6.3.0

2 years agodevlink: Fix dumps where interface map is used
Ido Schimmel [Thu, 27 Apr 2023 05:25:21 +0000 (08:25 +0300)] 
devlink: Fix dumps where interface map is used

The devlink utility stores an interface map that can be used to map an
interface name to a devlink port and vice versa. The map is populated by
issuing a devlink port dump via 'DEVLINK_CMD_PORT_GET' command.

Cited commits started to populate the map only when it is actually
needed. One such case is when a dump (e.g., shared buffer dump) only
returns devlink port handles. When pretty printing is required, the
utility will consult the map to translate the devlink port handles to
the corresponding interface names.

The above is problematic as it means that the port dump response(s) will
be queued to the same receive buffer as the response(s) of the dump that
triggered the port dump, resulting in a failed dump [1].

Fix by using a different netlink socket for the population of the
interface map.

[1]
$ devlink sb tc bind show
kernel answers: Device or resource busy
Failed to create index map
//0:
  sb 0 tc 4 type egress pool 4 threshold 9
kernel answers: Device or resource busy
[...]
$ echo $?
1

Fixes: 5cddbb274eab ("devlink: load port-ifname map on demand")
Fixes: 63d84b1fc98d ("devlink: load ifname map on demand from ifname_map_rev_lookup() as well")
Signed-off-by: Ido Schimmel <idosch@nvidia.com>
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
2 years agobridge: link: Add support for neigh_vlan_suppress option
Ido Schimmel [Mon, 24 Apr 2023 16:09:51 +0000 (19:09 +0300)] 
bridge: link: Add support for neigh_vlan_suppress option

Add support for the per-port neigh_vlan_suppress option. Example:

 # bridge link set dev swp1 neigh_vlan_suppress on
 # bridge -d -j -p link show dev swp1
 [ {
         "ifindex": 62,
         "ifname": "swp1",
         "flags": [ "BROADCAST","NOARP","UP","LOWER_UP" ],
         "mtu": 1500,
         "master": "br0",
         "state": "forwarding",
         "priority": 32,
         "cost": 100,
         "hairpin": false,
         "guard": false,
         "root_block": false,
         "fastleave": false,
         "learning": true,
         "flood": true,
         "mcast_flood": true,
         "bcast_flood": true,
         "mcast_router": 1,
         "mcast_to_unicast": false,
         "neigh_suppress": false,
         "neigh_vlan_suppress": true,
         "vlan_tunnel": false,
         "isolated": false,
         "locked": false,
         "mab": false,
         "mcast_n_groups": 0,
         "mcast_max_groups": 0
     } ]
 # bridge -d link show dev swp1
 62: swp1: <BROADCAST,NOARP,UP,LOWER_UP> mtu 1500 master br0 state forwarding priority 32 cost 100
     hairpin off guard off root_block off fastleave off learning on flood on mcast_flood on bcast_flood on mcast_router 1 mcast_to_unicast off neigh_suppress off neigh_vlan_suppress on vlan_tunnel off isolated off locked off mab off mcast_n_groups 0 mcast_max_groups 0

 # bridge link set dev swp1 neigh_vlan_suppress off
 # bridge -d -j -p link show dev swp1
 [ {
         "ifindex": 62,
         "ifname": "swp1",
         "flags": [ "BROADCAST","NOARP","UP","LOWER_UP" ],
         "mtu": 1500,
         "master": "br0",
         "state": "forwarding",
         "priority": 32,
         "cost": 100,
         "hairpin": false,
         "guard": false,
         "root_block": false,
         "fastleave": false,
         "learning": true,
         "flood": true,
         "mcast_flood": true,
         "bcast_flood": true,
         "mcast_router": 1,
         "mcast_to_unicast": false,
         "neigh_suppress": false,
         "neigh_vlan_suppress": false,
         "vlan_tunnel": false,
         "isolated": false,
         "locked": false,
         "mab": false,
         "mcast_n_groups": 0,
         "mcast_max_groups": 0
     } ]
 # bridge -d link show dev swp1
 62: swp1: <BROADCAST,NOARP,UP,LOWER_UP> mtu 1500 master br0 state forwarding priority 32 cost 100
     hairpin off guard off root_block off fastleave off learning on flood on mcast_flood on bcast_flood on mcast_router 1 mcast_to_unicast off neigh_suppress off neigh_vlan_suppress off vlan_tunnel off isolated off locked off mab off mcast_n_groups 0 mcast_max_groups 0

Signed-off-by: Ido Schimmel <idosch@nvidia.com>
Reviewed-by: Nikolay Aleksandrov <razor@blackwall.org>
Signed-off-by: David Ahern <dsahern@kernel.org>
2 years agobridge: vlan: Add support for neigh_suppress option
Ido Schimmel [Mon, 24 Apr 2023 16:09:50 +0000 (19:09 +0300)] 
bridge: vlan: Add support for neigh_suppress option

Add support for the per-VLAN neigh_suppress option. Example:

 # bridge vlan set vid 10 dev swp1 neigh_suppress on
 # bridge -d -j -p vlan show dev swp1 vid 10
 [ {
         "ifname": "swp1",
         "vlans": [ {
                 "vlan": 10,
                 "state": "forwarding",
                 "mcast_router": 1,
                 "neigh_suppress": true
             } ]
     } ]
 # bridge -d vlan show dev swp1 vid 10
 port              vlan-id
 swp1              10
                     state forwarding mcast_router 1 neigh_suppress on

 # bridge vlan set vid 10 dev swp1 neigh_suppress off
 # bridge -d -j -p vlan show dev swp1 vid 10
 [ {
         "ifname": "swp1",
         "vlans": [ {
                 "vlan": 10,
                 "state": "forwarding",
                 "mcast_router": 1,
                 "neigh_suppress": false
             } ]
     } ]
 # bridge -d vlan show dev swp1 vid 10
 port              vlan-id
 swp1              10
                     state forwarding mcast_router 1 neigh_suppress off

Signed-off-by: Ido Schimmel <idosch@nvidia.com>
Reviewed-by: Nikolay Aleksandrov <razor@blackwall.org>
Signed-off-by: David Ahern <dsahern@kernel.org>
2 years agoMerge branch 'preemptible-traffic-classes' into next
David Ahern [Tue, 25 Apr 2023 01:44:47 +0000 (19:44 -0600)] 
Merge branch 'preemptible-traffic-classes' into next

Vladimir Oltean  says:

====================

This is the iproute2 support for the tc program to make use of the
kernel features added in commit f7d29571ab0a ("Merge branch
'add-kernel-tc-mqprio-and-tc-taprio-support-for-preemptible-traffic-classes'").

====================

Signed-off-by: David Ahern <dsahern@kernel.org>
2 years agotc/taprio: add support for preemptible traffic classes
Vladimir Oltean [Tue, 18 Apr 2023 11:39:53 +0000 (14:39 +0300)] 
tc/taprio: add support for preemptible traffic classes

Add support for the same kind of "fp" array argument as in mqprio,
except here we already have some handling for per-tc entries (max-sdu).
We just need to expand that logic such that we also add (and parse) the
FP adminStatus property of each traffic class.

Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
Signed-off-by: David Ahern <dsahern@kernel.org>