]> git.ipfire.org Git - thirdparty/iproute2.git/log
thirdparty/iproute2.git
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 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 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>
2 years agotc/mqprio: add support for preemptible traffic classes
Vladimir Oltean [Tue, 18 Apr 2023 11:39:52 +0000 (14:39 +0300)] 
tc/mqprio: add support for preemptible traffic classes

Add support for the "fp" argument in tc-mqprio, which takes an array
of letters "E" (for express) or "P" (for preemptible), one per traffic
class, and transforms them into TCA_MQPRIO_TC_ENTRY_FP u32 attributes of
the TCA_MQPRIO_TC_ENTRY nest. We also dump these new netlink attributes
when they come from the kernel.

Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
Signed-off-by: David Ahern <dsahern@kernel.org>
2 years agoutils: add max() definition
Vladimir Oltean [Tue, 18 Apr 2023 11:39:51 +0000 (14:39 +0300)] 
utils: add max() definition

There is already a min() definition, add this below it.

Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
Signed-off-by: David Ahern <dsahern@kernel.org>
2 years agoMerge remote-tracking branch 'main/main' into next
David Ahern [Tue, 25 Apr 2023 01:41:19 +0000 (19:41 -0600)] 
Merge remote-tracking branch 'main/main' into next

Signed-off-by: David Ahern <dsahern@kernel.org>
2 years agotc/taprio: break up help text into multiple lines
Vladimir Oltean [Tue, 18 Apr 2023 11:39:49 +0000 (14:39 +0300)] 
tc/taprio: break up help text into multiple lines

Currently, the output of "tc qdisc add dev lo taprio help" looks
absolutely horrible, it looks better in the source code. Put new lines
in the output everywhere where the text switches to a new line in the
source code.

Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
2 years agotc/mqprio: break up synopsis into multiple lines
Vladimir Oltean [Tue, 18 Apr 2023 11:39:48 +0000 (14:39 +0300)] 
tc/mqprio: break up synopsis into multiple lines

tc-taprio(8) has a synopsis which is much easier to follow, because it
breaks up the command line arguments on multiple lines. Do this in
tc-mqprio(8) too.

Also, the highlighting (bold) of the keywords is all wrong. Take the
opportunity to fix that.

Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
2 years agotc/mqprio: use words in man page to express min_rate/max_rate dependency on bw_rlimit
Vladimir Oltean [Tue, 18 Apr 2023 11:39:47 +0000 (14:39 +0300)] 
tc/mqprio: use words in man page to express min_rate/max_rate dependency on bw_rlimit

It is confusing and easy to get lost in the soup of brackets when trying
to explain that min_rate and max_rate are only accepted as optional
arguments when "shaper" takes the value "bw_rlimit".

Before (synopsis):

[ shaper dcb| [ bw_rlimit min_rate min_rate1 min_rate2 ...  max_rate max_rate1 max_rate2 ...  ]]

After (synopsis):

[ shaper dcb|bw_rlimit ] [ min_rate min_rate1 min_rate2 ... ] [ max_rate max_rate1 max_rate2 ...  ]

Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
2 years agotc/mqprio: fix stray ] in man page synopsis
Vladimir Oltean [Tue, 18 Apr 2023 11:39:46 +0000 (14:39 +0300)] 
tc/mqprio: fix stray ] in man page synopsis

The closing ] bracket doesn't close anything, it is extraneous.
Remove it.

Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
2 years agotc/taprio: add a size table to the examples from the man page
Vladimir Oltean [Tue, 18 Apr 2023 11:39:45 +0000 (14:39 +0300)] 
tc/taprio: add a size table to the examples from the man page

Since kernel commit a3d91b2c6f6b ("net/sched: taprio: warn about missing
size table"), the kernel emits a warning netlink extack if the user
doesn't specify a stab. We want the user be aware of the fact that the
L1 overhead is determined by taprio exactly based on the overhead of the
stab, so we want to encourage users to add a size table to the Qdisc.
Teach them how.

Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
2 years agotc/taprio: add max-sdu to the man page SYNOPSIS section
Vladimir Oltean [Tue, 18 Apr 2023 11:39:44 +0000 (14:39 +0300)] 
tc/taprio: add max-sdu to the man page SYNOPSIS section

Although the max-sdu argument is documented in the PARAMETERS section,
it is absent from the SYNOPSIS. Add it there too.

Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
2 years agoMerge branch 'main' into next
David Ahern [Sat, 22 Apr 2023 16:08:08 +0000 (10:08 -0600)] 
Merge branch 'main' into next

Signed-off-by: David Ahern <dsahern@kernel.org>
2 years agoUpdate kernel headers
David Ahern [Sat, 22 Apr 2023 16:03:31 +0000 (10:03 -0600)] 
Update kernel headers

Update kernel headers to commit:
    fbc1449d385d ("Merge tag 'mlx5-updates-2023-04-20' of git://git.kernel.org/pub/scm/linux/kernel/git/saeed/linux")

Signed-off-by: David Ahern <dsahern@kernel.org>
2 years agoiplink: fix help of 'netns' arg
Nicolas Dichtel [Fri, 21 Apr 2023 07:47:20 +0000 (09:47 +0200)] 
iplink: fix help of 'netns' arg

'ip link set foo netns /proc/1/ns/net' is a valid command.
Let's update the doc accordingly.

Fixes: 0dc34c7713bb ("iproute2: Add processless network namespace support")
Signed-off-by: Nicolas Dichtel <nicolas.dichtel@6wind.com>
Reviewed-by: Simon Horman <simon.horman@corigine.com>
Reviewed-by: David Marchand <david.marchand@redhat.com>
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
2 years agoiplink: use the same token NETNSNAME everywhere
Nicolas Dichtel [Fri, 21 Apr 2023 07:47:19 +0000 (09:47 +0200)] 
iplink: use the same token NETNSNAME everywhere

Use NETNSNAME everywhere to ensure consistency between man pages and help
of the 'ip' command.

Signed-off-by: Nicolas Dichtel <nicolas.dichtel@6wind.com>
Reviewed-by: Simon Horman <simon.horman@corigine.com>
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
2 years agoip: bridge_slave: Fix help message indentation
Ido Schimmel [Wed, 19 Apr 2023 15:43:59 +0000 (18:43 +0300)] 
ip: bridge_slave: Fix help message indentation

Use tabs instead of spaces to be consistent with the rest of the
options.

Before:

$ ip link help bridge_slave
Usage: ... bridge_slave [ fdb_flush ]
[...]
                        [ vlan_tunnel {on | off} ]
                        [ isolated {on | off} ]
                        [ locked {on | off} ]
                       [ mab {on | off} ]
                        [ backup_port DEVICE ] [ nobackup_port ]

After:

$ ip link help bridge_slave
Usage: ... bridge_slave [ fdb_flush ]
[...]
                        [ vlan_tunnel {on | off} ]
                        [ isolated {on | off} ]
                        [ locked {on | off} ]
                        [ mab {on | off} ]
                        [ backup_port DEVICE ] [ nobackup_port ]

Fixes: 05f1164fe811 ("bridge: link: Add MAC Authentication Bypass (MAB) support")
Signed-off-by: Ido Schimmel <idosch@nvidia.com>
Reviewed-by: Simon Horman <simon.horman@corigine.com>
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
2 years agowhitespace cleanup
Stephen Hemminger [Sat, 22 Apr 2023 03:09:04 +0000 (20:09 -0700)] 
whitespace cleanup

Remove trailing blanks.

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
2 years agolwtunnel: use sizeof() on segbuf
Stephen Hemminger [Fri, 21 Apr 2023 17:05:49 +0000 (10:05 -0700)] 
lwtunnel: use sizeof() on segbuf

Avoid assuming that segbuf is 1024 bytes. Use sizeof() in
places where it is being updated.

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
2 years agolwtunnel: fix warning from strncpy
Stephen Hemminger [Fri, 21 Apr 2023 17:01:51 +0000 (10:01 -0700)] 
lwtunnel: fix warning from strncpy

The code for parsing segments in lwtunnel would trigger a warning
about strncpy if address sanitizer was enabled. Simpler to just
use strlcpy() like elsewhere.

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
2 years agoiproute_lwtunnel: fix JSON output
Stephen Hemminger [Fri, 14 Apr 2023 19:42:48 +0000 (12:42 -0700)] 
iproute_lwtunnel: fix JSON output

The same tag "dst" was being used for both the route destination
and the encap destination. This made it hard for JSON parsers.
Change to put the per-encap information under a nested JSON
object (similar to ip link type info).

Original output
[ {
        "dst": "192.168.11.0/24",
        "encap": "ip6",
        "id": 0,
        "src": "::",
        "dst": "fd00::c0a8:2dd",
        "hoplimit": 0,
        "tc": 0,
        "protocol": "5",
        "scope": "link",
        "flags": [ ]
    } ]

Revised output
[ {
        "dst": "192.168.11.0/24",
        "encap": {
            "encap_type": "ip6",
            "id": 0,
            "src": "::",
            "dst": "fd00::c0a8:2dd",
            "hoplimit": 0,
            "tc": 0
        },
        "protocol": "5",
        "scope": "link",
        "flags": [ ]
    } ]

Reported-by: Lars Ekman <uablrek@gmail.com>
Fixes: 663c3cb23103 ("iproute: implement JSON and color output")
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
2 years agoiproute_tunnel: use uint16 for tunnel encap type
Stephen Hemminger [Fri, 14 Apr 2023 19:40:56 +0000 (12:40 -0700)] 
iproute_tunnel: use uint16 for tunnel encap type

The tunnel encap type is passed as unsigned 16 bit value
in/out of kernel. Keep it unsigned in the encode/decode
logic.

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
2 years agoiptunnel: detect protocol mismatch on tunnel change
Stephen Hemminger [Mon, 10 Apr 2023 23:22:51 +0000 (16:22 -0700)] 
iptunnel: detect protocol mismatch on tunnel change

If attempt is made to change an IPv6 tunnel by using IPv4
parameters, a stack overflow would happen and garbage request
would be passed to kernel.

Example:
ip tunnel add gre1 mode ip6gre local 2001:db8::1 remote 2001:db8::2 ttl 255
ip tunnel change gre1 mode gre local 192.168.0.0 remote 192.168.0.1 ttl 255

The second command should fail because it attempting set IPv4 addresses
on a GRE tunnel that is IPv6.

Do best effort detection of this mismatch by giving a bigger buffer to get
tunnel request, and checking that the IP header is IPv4. It is still possible
but unlikely that byte would match in IPv6 tunnel paramater, but good enough
to catch the obvious cases.

Bug-Debian: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1032642
Tested-by: Luca Boccassi <bluca@debian.org>
Reported-by: Robin <imer@imer.cc>
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
2 years agotc: m_tunnel_key: support code for "nofrag" tunnels
Davide Caratti [Fri, 31 Mar 2023 16:49:03 +0000 (18:49 +0200)] 
tc: m_tunnel_key: support code for "nofrag" tunnels

add control plane for setting TCA_TUNNEL_KEY_NO_FRAG flag on
act_tunnel_key actions.

Signed-off-by: Davide Caratti <dcaratti@redhat.com>
Reviewed-by: Simon Horman <simon.horman@corigine.com>
Signed-off-by: David Ahern <dsahern@kernel.org>
2 years agoUpdate kernel headers
David Ahern [Fri, 7 Apr 2023 15:34:12 +0000 (09:34 -0600)] 
Update kernel headers

Update kernel headers to commit:
    e28531143b25 ("net: ethernet: mtk_eth_soc: mtk_ppe: prefer newly added l2 flows")

Signed-off-by: David Ahern <dsahern@kernel.org>
2 years agoip-xfrm: accept "allow" as action in ip xfrm policy setdefault
Sabrina Dubroca [Fri, 31 Mar 2023 13:18:25 +0000 (15:18 +0200)] 
ip-xfrm: accept "allow" as action in ip xfrm policy setdefault

The help text claims that setdefault takes ACTION values, ie block |
allow. In reality, xfrm_str_to_policy takes block | accept.

We could also fix that by changing the help text/manpage, but then
it'd be frustrating to have multiple ACTION with similar values used
in different subcommands.

I'm not changing the output in xfrm_policy_to_str because some
userspace somewhere probably depends on the "accept" value.

Fixes: 76b30805f9f6 ("xfrm: enable to manage default policies")
Signed-off-by: Sabrina Dubroca <sd@queasysnail.net>
Acked-by: Nicolas Dichtel <nicolas.dichtel@6wind.com>
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
2 years agoMerge branch 'ip-addr-proto' into next
David Ahern [Thu, 30 Mar 2023 15:57:02 +0000 (09:57 -0600)] 
Merge branch 'ip-addr-proto' into next

Petr Machata  says:

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

IPv4 and IPv6 addresses can be assigned a protocol value that indicates the
provenance of the IP address. The attribute is modeled after ip route
protocols, and essentially allows the administrator or userspace stack to
tag addresses in some way that makes sense to the actor in question.
Support for this feature was merged with commit 47f0bd503210 ("net: Add new
protocol attribute to IP addresses"), for kernel 5.18.

In this patchset, add support for setting the protocol attribute at IP
address addition, replacement, and listing requests.

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

Signed-off-by: David Ahern <dsahern@kernel.org>
2 years agoman: man8: Add man page coverage for "ip address add ... proto"
Petr Machata [Mon, 27 Mar 2023 16:12:06 +0000 (18:12 +0200)] 
man: man8: Add man page coverage for "ip address add ... proto"

Signed-off-by: Petr Machata <petrm@nvidia.com>
Signed-off-by: David Ahern <dsahern@kernel.org>
2 years agoip: Support IP address protocol
Petr Machata [Mon, 27 Mar 2023 16:12:05 +0000 (18:12 +0200)] 
ip: Support IP address protocol

IPv4 and IPv6 addresses can be assigned a protocol value that indicates the
provenance of the IP address. The attribute is modeled after ip route
protocols, and essentially allows the administrator or userspace stack to
tag addresses in some way that makes sense to the actor in question.
Support for this feature was merged with commit 47f0bd503210 ("net: Add new
protocol attribute to IP addresses"), for kernel 5.18.

In this patch, add support for setting the protocol attribute at IP address
addition, replacement, and listing requests.

An example session with the feature in action:

# ip address add dev d 192.0.2.1/28 proto 0xab
# ip address show dev d
26: d: <BROADCAST,NOARP> mtu 1500 qdisc noop state DOWN group default qlen 1000
    link/ether 06:29:74:fd:1f:eb brd ff:ff:ff:ff:ff:ff
    inet 192.0.2.1/28 scope global proto 0xab d
       valid_lft forever preferred_lft forever

# ip address replace dev d 192.0.2.1/28 proto 0x11
# ip address show dev d
26: d: <BROADCAST,NOARP> mtu 1500 qdisc noop state DOWN group default qlen 1000
    link/ether 06:29:74:fd:1f:eb brd ff:ff:ff:ff:ff:ff
    inet 192.0.2.1/28 scope global proto 0x11 d
       valid_lft forever preferred_lft forever

A JSON dump. The protocol value is always provided as a string, even in
numeric mode, to provide a consistent interface.

# ip -j address show dev d | jq
[
  {
    "ifindex": 26,
    "ifname": "d",
    "flags": [
      "BROADCAST",
      "NOARP"
    ],
    "mtu": 1500,
    "qdisc": "noop",
    "operstate": "DOWN",
    "group": "default",
    "txqlen": 1000,
    "link_type": "ether",
    "address": "06:29:74:fd:1f:eb",
    "broadcast": "ff:ff:ff:ff:ff:ff",
    "addr_info": [
      {
        "family": "inet",
        "local": "192.0.2.1",
        "prefixlen": 28,
        "scope": "global",
        "protocol": "0x11",
        "label": "d",
        "valid_life_time": 4294967295,
        "preferred_life_time": 4294967295
      }
    ]
  }
]

Signed-off-by: Petr Machata <petrm@nvidia.com>
Signed-off-by: David Ahern <dsahern@kernel.org>
2 years agomacvlan: Add bclim parameter
Herbert Xu [Thu, 30 Mar 2023 03:07:25 +0000 (11:07 +0800)] 
macvlan: Add bclim parameter

This patch adds support for setting the broadcast queueing threshold
on macvlan devices.  This controls which multicast packets will be
processed in a workqueue instead of inline.

Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
 ip/iplink_macvlan.c          |   26 ++++++++++++++++++++++++--
 man/man8/ip-link.8.in        |   18 ++++++++++++++++++
 3 files changed, 43 insertions(+), 2 deletions(-)

Signed-off-by: David Ahern <dsahern@kernel.org>
2 years agoUpdate kernel headers
David Ahern [Thu, 30 Mar 2023 15:43:49 +0000 (09:43 -0600)] 
Update kernel headers

Update kernel headers to commit:
    da617cd8d906 ("smsc911x: remove superfluous variable init")

Signed-off-by: David Ahern <dsahern@kernel.org>
2 years agoMerge branch 'bridge-mdb-vxlan-attr' into next
David Ahern [Sat, 25 Mar 2023 00:30:40 +0000 (18:30 -0600)] 
Merge branch 'bridge-mdb-vxlan-attr' into next

Ido Schimmel  says:

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

Add support for new VXLAN MDB attributes.

See kernel merge commit abf36703d704 ("Merge branch
'vxlan-MDB-support'") for background and motivation.

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

Signed-off-by: David Ahern <dsahern@kernel.org>
2 years agobridge: mdb: Document the catchall MDB entries
Ido Schimmel [Tue, 21 Mar 2023 13:01:27 +0000 (15:01 +0200)] 
bridge: mdb: Document the catchall MDB entries

Document the catchall MDB entries used to transmit IPv4 and IPv6
unregistered multicast packets.

In deployments where inter-subnet multicast forwarding is used, not all
the VTEPs in a tenant domain are members in all the broadcast domains.
It is therefore advantageous to transmit BULL (broadcast, unknown
unicast and link-local multicast) and unregistered IP multicast traffic
on different tunnels. If the same tunnel was used, a VTEP only
interested in IP multicast traffic would also pull all the BULL traffic
and drop it as it is not a member in the originating broadcast domain
[1].

[1] https://datatracker.ietf.org/doc/html/draft-ietf-bess-evpn-irb-mcast#section-2.6

Signed-off-by: Ido Schimmel <idosch@nvidia.com>
Reviewed-by: Nikolay Aleksandrov <razor@blackwall.org>
2 years agobridge: mdb: Add outgoing interface support
Ido Schimmel [Tue, 21 Mar 2023 13:01:26 +0000 (15:01 +0200)] 
bridge: mdb: Add outgoing interface support

In a similar fashion to VXLAN FDB entries, allow user space to program
and view the outgoing interface of VXLAN MDB entries. Specifically, add
support for the 'MDBE_ATTR_IFINDEX' and 'MDBA_MDB_EATTR_IFINDEX'
attributes in request and response messages, respectively.

The outgoing interface will be forced during the underlay route lookup
and is required when the underlay destination IP is multicast, as the
multicast routing tables are not consulted.

Example:

 # bridge mdb add dev vxlan0 port vxlan0 grp 239.1.1.1 permanent dst 198.51.100.1 via dummy10

 $ bridge -d -s mdb show
 dev vxlan0 port vxlan0 grp 239.1.1.1 permanent filter_mode exclude proto static dst 198.51.100.1 via dummy10    0.00

 $ bridge -d -s -j -p mdb show
 [ {
         "mdb": [ {
                 "index": 10,
                 "dev": "vxlan0",
                 "port": "vxlan0",
                 "grp": "239.1.1.1",
                 "state": "permanent",
                 "filter_mode": "exclude",
                 "protocol": "static",
                 "flags": [ ],
                 "dst": "198.51.100.1",
                 "via": "dummy10",
                 "timer": "   0.00"
             } ],
         "router": {}
     } ]

Signed-off-by: Ido Schimmel <idosch@nvidia.com>
Reviewed-by: Nikolay Aleksandrov <razor@blackwall.org>
2 years agobridge: mdb: Add source VNI support
Ido Schimmel [Tue, 21 Mar 2023 13:01:25 +0000 (15:01 +0200)] 
bridge: mdb: Add source VNI support

In a similar fashion to VXLAN FDB entries, allow user space to program
and view the source VNI of VXLAN MDB entries. Specifically, add support
for the 'MDBE_ATTR_SRC_VNI' and 'MDBA_MDB_EATTR_SRC_VNI' attributes in
request and response messages, respectively.

The source VNI is only relevant when the VXLAN device is in external
mode, where multiple VNIs can be multiplexed over a single VXLAN device.

Example:

 # bridge mdb add dev vxlan0 port vxlan0 grp 239.1.1.1 permanent dst 198.51.100.1 src_vni 2222

 $ bridge -d -s mdb show
 dev vxlan0 port vxlan0 grp 239.1.1.1 permanent filter_mode exclude proto static dst 198.51.100.1 src_vni 2222    0.00

 $ bridge -d -s -j -p mdb show
 [ {
         "mdb": [ {
                 "index": 16,
                 "dev": "vxlan0",
                 "port": "vxlan0",
                 "grp": "239.1.1.1",
                 "state": "permanent",
                 "filter_mode": "exclude",
                 "protocol": "static",
                 "flags": [ ],
                 "dst": "198.51.100.1",
                 "src_vni": 2222,
                 "timer": "   0.00"
             } ],
         "router": {}
     } ]

Signed-off-by: Ido Schimmel <idosch@nvidia.com>
Reviewed-by: Nikolay Aleksandrov <razor@blackwall.org>
2 years agobridge: mdb: Add destination VNI support
Ido Schimmel [Tue, 21 Mar 2023 13:01:24 +0000 (15:01 +0200)] 
bridge: mdb: Add destination VNI support

In a similar fashion to VXLAN FDB entries, allow user space to program
and view the destination VNI of VXLAN MDB entries. Specifically, add
support for the 'MDBE_ATTR_VNI' and 'MDBA_MDB_EATTR_VNI' attributes in
request and response messages, respectively.

This is useful when ingress replication (IR) is used and the destination
VXLAN tunnel endpoint (VTEP) is not a member of the source broadcast
domain (BD). In this case, the ingress VTEP should transmit the packet
using the VNI of the Supplementary Broadcast Domain (SBD) in which all
the VTEPs are member of [1].

Example:

 # bridge mdb add dev vxlan0 port vxlan0 grp 239.1.1.1 permanent dst 198.51.100.1 vni 1111

 $ bridge -d -s mdb show
 dev vxlan0 port vxlan0 grp 239.1.1.1 permanent filter_mode exclude proto static dst 198.51.100.1 vni 1111    0.00

 $ bridge -d -s -j -p mdb show
 [ {
         "mdb": [ {
                 "index": 15,
                 "dev": "vxlan0",
                 "port": "vxlan0",
                 "grp": "239.1.1.1",
                 "state": "permanent",
                 "filter_mode": "exclude",
                 "protocol": "static",
                 "flags": [ ],
                 "dst": "198.51.100.1",
                 "vni": 1111,
                 "timer": "   0.00"
             } ],
         "router": {}
     } ]

[1] https://datatracker.ietf.org/doc/html/draft-ietf-bess-evpn-irb-mcast#section-3.2.2

Signed-off-by: Ido Schimmel <idosch@nvidia.com>
Reviewed-by: Nikolay Aleksandrov <razor@blackwall.org>
2 years agobridge: mdb: Add UDP destination port support
Ido Schimmel [Tue, 21 Mar 2023 13:01:23 +0000 (15:01 +0200)] 
bridge: mdb: Add UDP destination port support

In a similar fashion to VXLAN FDB entries, allow user space to program
and view the UDP destination port of VXLAN MDB entries. Specifically,
add support for the 'MDBE_ATTR_DST_PORT' and 'MDBA_MDB_EATTR_DST_PORT'
attributes in request and response messages, respectively.

Use the keyword "dst_port" instead of "port" as the latter is already
used to specify the net device associated with the MDB entry.

Example:

 # bridge mdb add dev vxlan0 port vxlan0 grp 239.1.1.1 permanent dst 198.51.100.1 dst_port 1234

 $ bridge -d -s mdb show
 dev vxlan0 port vxlan0 grp 239.1.1.1 permanent filter_mode exclude proto static dst 198.51.100.1 dst_port 1234    0.00

 $ bridge -d -s -j -p mdb show
 [ {
         "mdb": [ {
                 "index": 15,
                 "dev": "vxlan0",
                 "port": "vxlan0",
                 "grp": "239.1.1.1",
                 "state": "permanent",
                 "filter_mode": "exclude",
                 "protocol": "static",
                 "flags": [ ],
                 "dst": "198.51.100.1",
                 "dst_port": 1234,
                 "timer": "   0.00"
             } ],
         "router": {}
     } ]

Signed-off-by: Ido Schimmel <idosch@nvidia.com>
Reviewed-by: Nikolay Aleksandrov <razor@blackwall.org>
2 years agobridge: mdb: Add underlay destination IP support
Ido Schimmel [Tue, 21 Mar 2023 13:01:22 +0000 (15:01 +0200)] 
bridge: mdb: Add underlay destination IP support

Allow user space to program and view VXLAN MDB entries. Specifically,
add support for the 'MDBE_ATTR_DST' and 'MDBA_MDB_EATTR_DST' attributes
in request and response messages, respectively.

The attributes encode the IP address of the destination VXLAN tunnel
endpoint where multicast receivers for the specified multicast flow
reside.

Multiple destinations can be added for each flow.

Example:

 # bridge mdb add dev vxlan0 port vxlan0 grp 239.1.1.1 permanent dst 198.51.100.1
 # bridge mdb add dev vxlan0 port vxlan0 grp 239.1.1.1 permanent dst 192.0.2.1

 $ bridge -d -s mdb show
 dev vxlan0 port vxlan0 grp 239.1.1.1 permanent filter_mode exclude proto static dst 192.0.2.1    0.00
 dev vxlan0 port vxlan0 grp 239.1.1.1 permanent filter_mode exclude proto static dst 198.51.100.1    0.00

 $ bridge -d -s -j -p mdb show
 [ {
         "mdb": [ {
                 "index": 15,
                 "dev": "vxlan0",
                 "port": "vxlan0",
                 "grp": "239.1.1.1",
                 "state": "permanent",
                 "filter_mode": "exclude",
                 "protocol": "static",
                 "flags": [ ],
                 "dst": "192.0.2.1",
                 "timer": "   0.00"
             },{
                 "index": 15,
                 "dev": "vxlan0",
                 "port": "vxlan0",
                 "grp": "239.1.1.1",
                 "state": "permanent",
                 "filter_mode": "exclude",
                 "protocol": "static",
                 "flags": [ ],
                 "dst": "198.51.100.1",
                 "timer": "   0.00"
             } ],
         "router": {}
     } ]

Signed-off-by: Ido Schimmel <idosch@nvidia.com>
Reviewed-by: Nikolay Aleksandrov <razor@blackwall.org>
2 years agoUpdate kernel headers
David Ahern [Thu, 23 Mar 2023 15:45:31 +0000 (09:45 -0600)] 
Update kernel headers

Update kernel headers to commit:
    fcb3a4653bc5 ("net/sched: act_api: use the correct TCA_ACT attributes in dump")

Signed-off-by: David Ahern <dsahern@kernel.org>
2 years agotc: m_action: fix parsing of TCA_EXT_WARN_MSG by using different enum
Hangbin Liu [Thu, 16 Mar 2023 03:52:42 +0000 (11:52 +0800)] 
tc: m_action: fix parsing of TCA_EXT_WARN_MSG by using different enum

We can't use TCA_EXT_WARN_MSG directly in tc action as it's using different
enum with filter. Let's use a new TCA_ROOT_EXT_WARN_MSG for tc action
specifically.

Fixes: 6035995665b7 ("tc: add new attr TCA_EXT_WARN_MSG")
Reviewed-by: Andrea Claudi <aclaudi@redhat.com>
Reported-and-tested-by: Davide Caratti <dcaratti@redhat.com>
Signed-off-by: Hangbin Liu <liuhangbin@gmail.com>
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
2 years agoRevert "tc: m_action: fix parsing of TCA_EXT_WARN_MSG"
Hangbin Liu [Thu, 16 Mar 2023 03:52:41 +0000 (11:52 +0800)] 
Revert "tc: m_action: fix parsing of TCA_EXT_WARN_MSG"

This reverts commit 70b9ebae63ce7e6f9911bdfbcf47a6d18f24159a.

The TCA_EXT_WARN_MSG is not sit within the TCA_ACT_TAB hierarchy. It's
belong to the TCA_MAX namespace. I will fix the issue in another patch.

Reviewed-by: Andrea Claudi <aclaudi@redhat.com>
Signed-off-by: Hangbin Liu <liuhangbin@gmail.com>
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
2 years agouapi: update headers from 6.3-rc2
Stephen Hemminger [Sun, 19 Mar 2023 02:16:31 +0000 (19:16 -0700)] 
uapi: update headers from 6.3-rc2

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
2 years agouapi: update license of fou.h
Stephen Hemminger [Mon, 13 Mar 2023 02:47:48 +0000 (19:47 -0700)] 
uapi: update license of fou.h

Upstream 6.2-rc2

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
2 years agoman/netem: rework man page
Stephen Hemminger [Wed, 8 Mar 2023 18:44:59 +0000 (10:44 -0800)] 
man/netem: rework man page

Cleanup and rewrite netem man page.
Incorporate the examples from the old LF netem wiki
so that it can be removed/deprecated.

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
2 years agotc: m_nat: parse index argument correctly
Pedro Tammela [Mon, 27 Feb 2023 18:45:10 +0000 (15:45 -0300)] 
tc: m_nat: parse index argument correctly

'action nat index 1' is a valid cli according to TC's
architecture. Fix the grammar parsing to accept it.

tdc tests:
1..28
ok 1 7565 - Add nat action on ingress with default control action
ok 2 fd79 - Add nat action on ingress with pipe control action
ok 3 eab9 - Add nat action on ingress with continue control action
ok 4 c53a - Add nat action on ingress with reclassify control action
ok 5 76c9 - Add nat action on ingress with jump control action
ok 6 24c6 - Add nat action on ingress with drop control action
ok 7 2120 - Add nat action on ingress with maximum index value
ok 8 3e9d - Add nat action on ingress with invalid index value
ok 9 f6c9 - Add nat action on ingress with invalid IP address
ok 10 be25 - Add nat action on ingress with invalid argument
ok 11 a7bd - Add nat action on ingress with DEFAULT IP address
ok 12 ee1e - Add nat action on ingress with ANY IP address
ok 13 1de8 - Add nat action on ingress with ALL IP address
ok 14 8dba - Add nat action on egress with default control action
ok 15 19a7 - Add nat action on egress with pipe control action
ok 16 f1d9 - Add nat action on egress with continue control action
ok 17 6d4a - Add nat action on egress with reclassify control action
ok 18 b313 - Add nat action on egress with jump control action
ok 19 d9fc - Add nat action on egress with drop control action
ok 20 a895 - Add nat action on egress with DEFAULT IP address
ok 21 2572 - Add nat action on egress with ANY IP address
ok 22 37f3 - Add nat action on egress with ALL IP address
ok 23 6054 - Add nat action on egress with cookie
ok 24 79d6 - Add nat action on ingress with cookie
ok 25 4b12 - Replace nat action with invalid goto chain control
ok 26 b811 - Delete nat action with valid index
ok 27 a521 - Delete nat action with invalid index
ok 28 2c81 - Reference nat action object in filter

Fixes: fc2d02069b52 ("Add NAT action")
Reviewed-by: Jamal Hadi Salim <jhs@mojatatu.com>
Signed-off-by: Pedro Tammela <pctammela@mojatatu.com>
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
2 years agotc: m_mpls: parse index argument correctly
Pedro Tammela [Mon, 27 Feb 2023 18:45:09 +0000 (15:45 -0300)] 
tc: m_mpls: parse index argument correctly

'action mpls index 1' is a valid cli according to TC's
architecture. Fix the grammar parsing to accept it.

tdc tests:
1..54
ok 1 a933 - Add MPLS dec_ttl action with pipe opcode
ok 2 08d1 - Add mpls dec_ttl action with pass opcode
ok 3 d786 - Add mpls dec_ttl action with drop opcode
ok 4 f334 - Add mpls dec_ttl action with reclassify opcode
ok 5 29bd - Add mpls dec_ttl action with continue opcode
ok 6 48df - Add mpls dec_ttl action with jump opcode
ok 7 62eb - Add mpls dec_ttl action with trap opcode
ok 8 09d2 - Add mpls dec_ttl action with opcode and cookie
ok 9 c170 - Add mpls dec_ttl action with opcode and cookie of max length
ok 10 9118 - Add mpls dec_ttl action with invalid opcode
ok 11 6ce1 - Add mpls dec_ttl action with label (invalid)
ok 12 352f - Add mpls dec_ttl action with tc (invalid)
ok 13 fa1c - Add mpls dec_ttl action with ttl (invalid)
ok 14 6b79 - Add mpls dec_ttl action with bos (invalid)
ok 15 d4c4 - Add mpls pop action with ip proto
ok 16 91fb - Add mpls pop action with ip proto and cookie
ok 17 92fe - Add mpls pop action with mpls proto
ok 18 7e23 - Add mpls pop action with no protocol (invalid)
ok 19 6182 - Add mpls pop action with label (invalid)
ok 20 6475 - Add mpls pop action with tc (invalid)
ok 21 067b - Add mpls pop action with ttl (invalid)
ok 22 7316 - Add mpls pop action with bos (invalid)
ok 23 38cc - Add mpls push action with label
ok 24 c281 - Add mpls push action with mpls_mc protocol
ok 25 5db4 - Add mpls push action with label, tc and ttl
ok 26 7c34 - Add mpls push action with label, tc ttl and cookie of max length
ok 27 16eb - Add mpls push action with label and bos
ok 28 d69d - Add mpls push action with no label (invalid)
ok 29 e8e4 - Add mpls push action with ipv4 protocol (invalid)
ok 30 ecd0 - Add mpls push action with out of range label (invalid)
ok 31 d303 - Add mpls push action with out of range tc (invalid)
ok 32 fd6e - Add mpls push action with ttl of 0 (invalid)
ok 33 19e9 - Add mpls mod action with mpls label
ok 34 1fde - Add mpls mod action with max mpls label
ok 35 0c50 - Add mpls mod action with mpls label exceeding max (invalid)
ok 36 10b6 - Add mpls mod action with mpls label of MPLS_LABEL_IMPLNULL (invalid)
ok 37 57c9 - Add mpls mod action with mpls min tc
ok 38 6872 - Add mpls mod action with mpls max tc
ok 39 a70a - Add mpls mod action with mpls tc exceeding max (invalid)
ok 40 6ed5 - Add mpls mod action with mpls ttl
ok 41 77c1 - Add mpls mod action with mpls ttl and cookie
ok 42 b80f - Add mpls mod action with mpls max ttl
ok 43 8864 - Add mpls mod action with mpls min ttl
ok 44 6c06 - Add mpls mod action with mpls ttl of 0 (invalid)
ok 45 b5d8 - Add mpls mod action with mpls ttl exceeding max (invalid)
ok 46 451f - Add mpls mod action with mpls max bos
ok 47 a1ed - Add mpls mod action with mpls min bos
ok 48 3dcf - Add mpls mod action with mpls bos exceeding max (invalid)
ok 49 db7c - Add mpls mod action with protocol (invalid)
ok 50 b070 - Replace existing mpls push action with new ID
ok 51 95a9 - Replace existing mpls push action with new label, tc, ttl and cookie
ok 52 6cce - Delete mpls pop action
ok 53 d138 - Flush mpls actions
ok 54 7a70 - Reference mpls action object in filter

Fixes: fb57b0920f06 ("tc: add mpls actions")
Reviewed-by: Jamal Hadi Salim <jhs@mojatatu.com>
Signed-off-by: Pedro Tammela <pctammela@mojatatu.com>
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
2 years agotc: m_csum: parse index argument correctly
Pedro Tammela [Mon, 27 Feb 2023 18:45:08 +0000 (15:45 -0300)] 
tc: m_csum: parse index argument correctly

'action csum index 1' is a valid cli according to TC's
architecture. Fix the grammar parsing to accept it.

tdc tests:
1..24
ok 1 6d84 - Add csum iph action
ok 2 1862 - Add csum ip4h action
ok 3 15c6 - Add csum ipv4h action
ok 4 bf47 - Add csum icmp action
ok 5 cc1d - Add csum igmp action
ok 6 bccc - Add csum foobar action
ok 7 3bb4 - Add csum tcp action
ok 8 759c - Add csum udp action
ok 9 bdb6 - Add csum udp xor iph action
ok 10 c220 - Add csum udplite action
ok 11 8993 - Add csum sctp action
ok 12 b138 - Add csum ip & icmp action
ok 13 eeda - Add csum ip & sctp action
ok 14 0017 - Add csum udp or tcp action
ok 15 b10b - Add all 7 csum actions
ok 16 ce92 - Add csum udp action with cookie
ok 17 912f - Add csum icmp action with large cookie
ok 18 879b - Add batch of 32 csum tcp actions
ok 19 b4e9 - Delete batch of 32 csum actions
ok 20 0015 - Add batch of 32 csum tcp actions with large cookies
ok 21 989e - Delete batch of 32 csum actions with large cookies
ok 22 d128 - Replace csum action with invalid goto chain control
ok 23 eaf0 - Add csum iph action with no_percpu flag
ok 24 c619 - Reference csum action object in filter

Fixes: 3822cc986cc3 ("tc: add ACT_CSUM action support (csum)")
Reviewed-by: Jamal Hadi Salim <jhs@mojatatu.com>
Signed-off-by: Pedro Tammela <pctammela@mojatatu.com>
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
2 years agotc: f_u32: fix json object leak
Hangbin Liu [Tue, 28 Feb 2023 07:31:46 +0000 (15:31 +0800)] 
tc: f_u32: fix json object leak

Previously, the code returned directly within the switch statement in
the functions print_{ipv4, ipv6}. While this approach was functional,
after the commit 721435dc, we can no longer return directly because we
need to close the match object. To resolve this issue, replace the return
statement with break.

Fixes: 721435dcfd92 ("tc: u32: add json support in `print_raw`, `print_ipv4`, `print_ipv6`")
Signed-off-by: Hangbin Liu <liuhangbin@gmail.com>
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
2 years agou32: fix TC_U32_TERMINAL printing
Hangbin Liu [Wed, 1 Mar 2023 14:21:00 +0000 (22:21 +0800)] 
u32: fix TC_U32_TERMINAL printing

We previously printed an asterisk if there was no 'sel' or
'TC_U32_TERMINAL' flag. However,
 commit 1ff227545ce1 ("u32: fix json formatting of flowid")
changed the logic to print an asterisk only if there is a
'TC_U32_TERMINAL' flag. Therefore, we need to fix this
regression.

Before the fix, the tdc u32 test failed:

1..11
not ok 1 afa9 - Add u32 with source match
        Could not match regex pattern. Verify command output:
filter protocol ip pref 1 u32 chain 0
filter protocol ip pref 1 u32 chain 0 fh 800: ht divisor 1
filter protocol ip pref 1 u32 chain 0 fh 800::800 order 2048 key ht 800 bkt 0 *flowid 1:1 not_in_hw
  match 7f000001/ffffffff at 12
        action order 1: gact action pass
         random type none pass val 0
         index 1 ref 1 bind 1

After fix, the test passed:
1..11
ok 1 afa9 - Add u32 with source match

Fixes: 1ff227545ce1 ("u32: fix json formatting of flowid")
Signed-off-by: Hangbin Liu <liuhangbin@gmail.com>
Reviewed-by: Victor Nogueira <victor@mojatatu.com>
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
2 years agogenl: print caps for all families
Jakub Kicinski [Sat, 25 Feb 2023 00:37:54 +0000 (16:37 -0800)] 
genl: print caps for all families

Back in 2006 kernel commit 334c29a64507 ("[GENETLINK]: Move
command capabilities to flags.") removed some attributes and
moved the capabilities to flags. Corresponding iproute2
commit 26328fc3933f ("Add controller support for new features
exposed") added the ability to print those caps.

Printing is gated on version of the family, but we're checking
the version of each individual family rather than the control
family. The format of attributes in the control family
is dictated by the version of the control family alone.

In fact the entire version check is not strictly necessary.
The code is not using the old attributes, so on older kernels
it will simply print nothing either way.

Families can't use flags for random things, because kernel core
has a fixed interpretation.

Thanks to this change caps will be shown for all families
(assuming kernel newer than 2.6.19), not just those which
by coincidence have their local version >= 2.

For instance devlink, before:

  $ genl ctrl get name devlink
  Name: devlink
ID: 0x15  Version: 0x1  header size: 0  max attribs: 179
commands supported:
#1:  ID-0x1
#2:  ID-0x5
#3:  ID-0x6
...

after:

  $ genl ctrl get name devlink
  Name: devlink
ID: 0x15  Version: 0x1  header size: 0  max attribs: 179
commands supported:
#1:  ID-0x1
Capabilities (0xe):
    can doit; can dumpit; has policy

#2:  ID-0x5
Capabilities (0xe):
    can doit; can dumpit; has policy

#3:  ID-0x6
Capabilities (0xb):
    requires admin permission; can doit; has policy

Fixes: 26328fc3933f ("Add controller support for new features exposed")
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Reviewed-by: Jamal Hadi Salim <jhs@mojatatu.com>
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>