]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
Fixes for 5.15
authorSasha Levin <sashal@kernel.org>
Sat, 1 Mar 2025 14:19:54 +0000 (09:19 -0500)
committerSasha Levin <sashal@kernel.org>
Sat, 1 Mar 2025 14:19:54 +0000 (09:19 -0500)
Signed-off-by: Sasha Levin <sashal@kernel.org>
20 files changed:
queue-5.15/afs-fix-the-server_list-to-unuse-a-displaced-server-.patch [new file with mode: 0644]
queue-5.15/afs-make-it-possible-to-find-the-volumes-that-are-us.patch [new file with mode: 0644]
queue-5.15/afs-remove-variable-nr_servers.patch [new file with mode: 0644]
queue-5.15/alsa-usb-audio-avoid-dropping-midi-events-at-closing.patch [new file with mode: 0644]
queue-5.15/asoc-es8328-fix-route-from-dac-to-output.patch [new file with mode: 0644]
queue-5.15/bluetooth-l2cap-fix-l2cap_ecred_conn_rsp-response.patch [new file with mode: 0644]
queue-5.15/include-net-add-static-inline-dst_dev_overhead-to-ds.patch [new file with mode: 0644]
queue-5.15/ipvs-always-clear-ipvs_property-flag-in-skb_scrub_pa.patch [new file with mode: 0644]
queue-5.15/net-cadence-macb-synchronize-stats-calculations.patch [new file with mode: 0644]
queue-5.15/net-ipv6-fix-dst-ref-loop-on-input-in-rpl-lwt.patch [new file with mode: 0644]
queue-5.15/net-ipv6-fix-dst-ref-loop-on-input-in-seg6-lwt.patch [new file with mode: 0644]
queue-5.15/net-ipv6-rpl_iptunnel-mitigate-2-realloc-issue.patch [new file with mode: 0644]
queue-5.15/net-ipv6-seg6_iptunnel-mitigate-2-realloc-issue.patch [new file with mode: 0644]
queue-5.15/net-loopback-avoid-sending-ip-packets-without-an-eth.patch [new file with mode: 0644]
queue-5.15/net-mlx5-irq-fix-null-string-in-debug-print.patch [new file with mode: 0644]
queue-5.15/net-mvpp2-cls-fixed-non-ip-flow-with-vlan-tag-flow-d.patch [new file with mode: 0644]
queue-5.15/seg6-add-support-for-srv6-h.encaps.red-behavior.patch [new file with mode: 0644]
queue-5.15/seg6-add-support-for-srv6-h.l2encaps.red-behavior.patch [new file with mode: 0644]
queue-5.15/series
queue-5.15/tcp-defer-ts_recent-changes-until-req-is-owned.patch [new file with mode: 0644]

diff --git a/queue-5.15/afs-fix-the-server_list-to-unuse-a-displaced-server-.patch b/queue-5.15/afs-fix-the-server_list-to-unuse-a-displaced-server-.patch
new file mode 100644 (file)
index 0000000..d1918c1
--- /dev/null
@@ -0,0 +1,59 @@
+From 42818f1709e47e92a07145178c35a7b9e81e5e1e Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 18 Feb 2025 19:22:47 +0000
+Subject: afs: Fix the server_list to unuse a displaced server rather than
+ putting it
+
+From: David Howells <dhowells@redhat.com>
+
+[ Upstream commit add117e48df4788a86a21bd0515833c0a6db1ad1 ]
+
+When allocating and building an afs_server_list struct object from a VLDB
+record, we look up each server address to get the server record for it -
+but a server may have more than one entry in the record and we discard the
+duplicate pointers.  Currently, however, when we discard, we only put a
+server record, not unuse it - but the lookup got as an active-user count.
+
+The active-user count on an afs_server_list object determines its lifetime
+whereas the refcount keeps the memory backing it around.  Failing to reduce
+the active-user counter prevents the record from being cleaned up and can
+lead to multiple copied being seen - and pointing to deleted afs_cell
+objects and other such things.
+
+Fix this by switching the incorrect 'put' to an 'unuse' instead.
+
+Without this, occasionally, a dead server record can be seen in
+/proc/net/afs/servers and list corruption may be observed:
+
+    list_del corruption. prev->next should be ffff888102423e40, but was 0000000000000000. (prev=ffff88810140cd38)
+
+Fixes: 977e5f8ed0ab ("afs: Split the usage count on struct afs_server")
+Signed-off-by: David Howells <dhowells@redhat.com>
+cc: Marc Dionne <marc.dionne@auristor.com>
+cc: Simon Horman <horms@kernel.org>
+cc: linux-afs@lists.infradead.org
+Link: https://patch.msgid.link/20250218192250.296870-5-dhowells@redhat.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/afs/server_list.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/fs/afs/server_list.c b/fs/afs/server_list.c
+index 4d6369477f54e..89c75d934f79e 100644
+--- a/fs/afs/server_list.c
++++ b/fs/afs/server_list.c
+@@ -67,8 +67,8 @@ struct afs_server_list *afs_alloc_server_list(struct afs_volume *volume,
+                               break;
+               if (j < slist->nr_servers) {
+                       if (slist->servers[j].server == server) {
+-                              afs_put_server(volume->cell->net, server,
+-                                             afs_server_trace_put_slist_isort);
++                              afs_unuse_server(volume->cell->net, server,
++                                               afs_server_trace_put_slist_isort);
+                               continue;
+                       }
+-- 
+2.39.5
+
diff --git a/queue-5.15/afs-make-it-possible-to-find-the-volumes-that-are-us.patch b/queue-5.15/afs-make-it-possible-to-find-the-volumes-that-are-us.patch
new file mode 100644 (file)
index 0000000..a6fd359
--- /dev/null
@@ -0,0 +1,417 @@
+From 5f8c6204fbe4f3c481396d5db4d52c3385aa6d39 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 2 Nov 2023 16:08:43 +0000
+Subject: afs: Make it possible to find the volumes that are using a server
+
+From: David Howells <dhowells@redhat.com>
+
+[ Upstream commit ca0e79a46097d54e4af46c67c852479d97af35bb ]
+
+Make it possible to find the afs_volume structs that are using an
+afs_server struct to aid in breaking volume callbacks.
+
+The way this is done is that each afs_volume already has an array of
+afs_server_entry records that point to the servers where that volume might
+be found.  An afs_volume backpointer and a list node is added to each entry
+and each entry is then added to an RCU-traversable list on the afs_server
+to which it points.
+
+Signed-off-by: David Howells <dhowells@redhat.com>
+cc: Marc Dionne <marc.dionne@auristor.com>
+cc: linux-afs@lists.infradead.org
+Stable-dep-of: add117e48df4 ("afs: Fix the server_list to unuse a displaced server rather than putting it")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/afs/cell.c        |   1 +
+ fs/afs/internal.h    |  23 +++++----
+ fs/afs/server.c      |   1 +
+ fs/afs/server_list.c | 112 +++++++++++++++++++++++++++++++++++++++----
+ fs/afs/vl_alias.c    |   2 +-
+ fs/afs/volume.c      |  36 ++++++++------
+ 6 files changed, 143 insertions(+), 32 deletions(-)
+
+diff --git a/fs/afs/cell.c b/fs/afs/cell.c
+index 77571372888d9..c04c7b5ec780d 100644
+--- a/fs/afs/cell.c
++++ b/fs/afs/cell.c
+@@ -161,6 +161,7 @@ static struct afs_cell *afs_alloc_cell(struct afs_net *net,
+       refcount_set(&cell->ref, 1);
+       atomic_set(&cell->active, 0);
+       INIT_WORK(&cell->manager, afs_manage_cell_work);
++      spin_lock_init(&cell->vs_lock);
+       cell->volumes = RB_ROOT;
+       INIT_HLIST_HEAD(&cell->proc_volumes);
+       seqlock_init(&cell->volume_lock);
+diff --git a/fs/afs/internal.h b/fs/afs/internal.h
+index 0c03877cdaf7e..3918dfbd72a49 100644
+--- a/fs/afs/internal.h
++++ b/fs/afs/internal.h
+@@ -382,6 +382,7 @@ struct afs_cell {
+       unsigned int            debug_id;
+       /* The volumes belonging to this cell */
++      spinlock_t              vs_lock;        /* Lock for server->volumes */
+       struct rb_root          volumes;        /* Tree of volumes on this server */
+       struct hlist_head       proc_volumes;   /* procfs volume list */
+       seqlock_t               volume_lock;    /* For volumes */
+@@ -505,6 +506,7 @@ struct afs_server {
+       struct hlist_node       addr4_link;     /* Link in net->fs_addresses4 */
+       struct hlist_node       addr6_link;     /* Link in net->fs_addresses6 */
+       struct hlist_node       proc_link;      /* Link in net->fs_proc */
++      struct list_head        volumes;        /* RCU list of afs_server_entry objects */
+       struct work_struct      initcb_work;    /* Work for CB.InitCallBackState* */
+       struct afs_server       *gc_next;       /* Next server in manager's list */
+       time64_t                unuse_time;     /* Time at which last unused */
+@@ -553,12 +555,14 @@ struct afs_server {
+  */
+ struct afs_server_entry {
+       struct afs_server       *server;
++      struct afs_volume       *volume;
++      struct list_head        slink;          /* Link in server->volumes */
+ };
+ struct afs_server_list {
+       struct rcu_head         rcu;
+-      afs_volid_t             vids[AFS_MAXTYPES]; /* Volume IDs */
+       refcount_t              usage;
++      bool                    attached;       /* T if attached to servers */
+       unsigned char           nr_servers;
+       unsigned char           preferred;      /* Preferred server */
+       unsigned short          vnovol_mask;    /* Servers to be skipped due to VNOVOL */
+@@ -571,10 +575,9 @@ struct afs_server_list {
+  * Live AFS volume management.
+  */
+ struct afs_volume {
+-      union {
+-              struct rcu_head rcu;
+-              afs_volid_t     vid;            /* volume ID */
+-      };
++      struct rcu_head rcu;
++      afs_volid_t             vid;            /* The volume ID of this volume */
++      afs_volid_t             vids[AFS_MAXTYPES]; /* All associated volume IDs */
+       refcount_t              ref;
+       time64_t                update_at;      /* Time at which to next update */
+       struct afs_cell         *cell;          /* Cell to which belongs (pins ref) */
+@@ -1436,10 +1439,14 @@ static inline struct afs_server_list *afs_get_serverlist(struct afs_server_list
+ }
+ extern void afs_put_serverlist(struct afs_net *, struct afs_server_list *);
+-extern struct afs_server_list *afs_alloc_server_list(struct afs_cell *, struct key *,
+-                                                   struct afs_vldb_entry *,
+-                                                   u8);
++struct afs_server_list *afs_alloc_server_list(struct afs_volume *volume,
++                                            struct key *key,
++                                            struct afs_vldb_entry *vldb);
+ extern bool afs_annotate_server_list(struct afs_server_list *, struct afs_server_list *);
++void afs_attach_volume_to_servers(struct afs_volume *volume, struct afs_server_list *slist);
++void afs_reattach_volume_to_servers(struct afs_volume *volume, struct afs_server_list *slist,
++                                  struct afs_server_list *old);
++void afs_detach_volume_from_servers(struct afs_volume *volume, struct afs_server_list *slist);
+ /*
+  * super.c
+diff --git a/fs/afs/server.c b/fs/afs/server.c
+index 34b47218129e9..5ee8a7518c5ec 100644
+--- a/fs/afs/server.c
++++ b/fs/afs/server.c
+@@ -236,6 +236,7 @@ static struct afs_server *afs_alloc_server(struct afs_cell *cell,
+       server->addr_version = alist->version;
+       server->uuid = *uuid;
+       rwlock_init(&server->fs_lock);
++      INIT_LIST_HEAD(&server->volumes);
+       INIT_WORK(&server->initcb_work, afs_server_init_callback_work);
+       init_waitqueue_head(&server->probe_wq);
+       INIT_LIST_HEAD(&server->probe_link);
+diff --git a/fs/afs/server_list.c b/fs/afs/server_list.c
+index b59896b1de0af..4d6369477f54e 100644
+--- a/fs/afs/server_list.c
++++ b/fs/afs/server_list.c
+@@ -24,13 +24,13 @@ void afs_put_serverlist(struct afs_net *net, struct afs_server_list *slist)
+ /*
+  * Build a server list from a VLDB record.
+  */
+-struct afs_server_list *afs_alloc_server_list(struct afs_cell *cell,
++struct afs_server_list *afs_alloc_server_list(struct afs_volume *volume,
+                                             struct key *key,
+-                                            struct afs_vldb_entry *vldb,
+-                                            u8 type_mask)
++                                            struct afs_vldb_entry *vldb)
+ {
+       struct afs_server_list *slist;
+       struct afs_server *server;
++      unsigned int type_mask = 1 << volume->type;
+       int ret = -ENOMEM, nr_servers = 0, i, j;
+       for (i = 0; i < vldb->nr_servers; i++)
+@@ -44,15 +44,12 @@ struct afs_server_list *afs_alloc_server_list(struct afs_cell *cell,
+       refcount_set(&slist->usage, 1);
+       rwlock_init(&slist->lock);
+-      for (i = 0; i < AFS_MAXTYPES; i++)
+-              slist->vids[i] = vldb->vid[i];
+-
+       /* Make sure a records exists for each server in the list. */
+       for (i = 0; i < vldb->nr_servers; i++) {
+               if (!(vldb->fs_mask[i] & type_mask))
+                       continue;
+-              server = afs_lookup_server(cell, key, &vldb->fs_server[i],
++              server = afs_lookup_server(volume->cell, key, &vldb->fs_server[i],
+                                          vldb->addr_version[i]);
+               if (IS_ERR(server)) {
+                       ret = PTR_ERR(server);
+@@ -70,7 +67,7 @@ struct afs_server_list *afs_alloc_server_list(struct afs_cell *cell,
+                               break;
+               if (j < slist->nr_servers) {
+                       if (slist->servers[j].server == server) {
+-                              afs_put_server(cell->net, server,
++                              afs_put_server(volume->cell->net, server,
+                                              afs_server_trace_put_slist_isort);
+                               continue;
+                       }
+@@ -81,6 +78,7 @@ struct afs_server_list *afs_alloc_server_list(struct afs_cell *cell,
+               }
+               slist->servers[j].server = server;
++              slist->servers[j].volume = volume;
+               slist->nr_servers++;
+       }
+@@ -92,7 +90,7 @@ struct afs_server_list *afs_alloc_server_list(struct afs_cell *cell,
+       return slist;
+ error_2:
+-      afs_put_serverlist(cell->net, slist);
++      afs_put_serverlist(volume->cell->net, slist);
+ error:
+       return ERR_PTR(ret);
+ }
+@@ -127,3 +125,99 @@ bool afs_annotate_server_list(struct afs_server_list *new,
+       return true;
+ }
++
++/*
++ * Attach a volume to the servers it is going to use.
++ */
++void afs_attach_volume_to_servers(struct afs_volume *volume, struct afs_server_list *slist)
++{
++      struct afs_server_entry *se, *pe;
++      struct afs_server *server;
++      struct list_head *p;
++      unsigned int i;
++
++      spin_lock(&volume->cell->vs_lock);
++
++      for (i = 0; i < slist->nr_servers; i++) {
++              se = &slist->servers[i];
++              server = se->server;
++
++              list_for_each(p, &server->volumes) {
++                      pe = list_entry(p, struct afs_server_entry, slink);
++                      if (volume->vid <= pe->volume->vid)
++                              break;
++              }
++              list_add_tail_rcu(&se->slink, p);
++      }
++
++      slist->attached = true;
++      spin_unlock(&volume->cell->vs_lock);
++}
++
++/*
++ * Reattach a volume to the servers it is going to use when server list is
++ * replaced.  We try to switch the attachment points to avoid rewalking the
++ * lists.
++ */
++void afs_reattach_volume_to_servers(struct afs_volume *volume, struct afs_server_list *new,
++                                  struct afs_server_list *old)
++{
++      unsigned int n = 0, o = 0;
++
++      spin_lock(&volume->cell->vs_lock);
++
++      while (n < new->nr_servers || o < old->nr_servers) {
++              struct afs_server_entry *pn = n < new->nr_servers ? &new->servers[n] : NULL;
++              struct afs_server_entry *po = o < old->nr_servers ? &old->servers[o] : NULL;
++              struct afs_server_entry *s;
++              struct list_head *p;
++              int diff;
++
++              if (pn && po && pn->server == po->server) {
++                      list_replace_rcu(&po->slink, &pn->slink);
++                      n++;
++                      o++;
++                      continue;
++              }
++
++              if (pn && po)
++                      diff = memcmp(&pn->server->uuid, &po->server->uuid,
++                                    sizeof(pn->server->uuid));
++              else
++                      diff = pn ? -1 : 1;
++
++              if (diff < 0) {
++                      list_for_each(p, &pn->server->volumes) {
++                              s = list_entry(p, struct afs_server_entry, slink);
++                              if (volume->vid <= s->volume->vid)
++                                      break;
++                      }
++                      list_add_tail_rcu(&pn->slink, p);
++                      n++;
++              } else {
++                      list_del_rcu(&po->slink);
++                      o++;
++              }
++      }
++
++      spin_unlock(&volume->cell->vs_lock);
++}
++
++/*
++ * Detach a volume from the servers it has been using.
++ */
++void afs_detach_volume_from_servers(struct afs_volume *volume, struct afs_server_list *slist)
++{
++      unsigned int i;
++
++      if (!slist->attached)
++              return;
++
++      spin_lock(&volume->cell->vs_lock);
++
++      for (i = 0; i < slist->nr_servers; i++)
++              list_del_rcu(&slist->servers[i].slink);
++
++      slist->attached = false;
++      spin_unlock(&volume->cell->vs_lock);
++}
+diff --git a/fs/afs/vl_alias.c b/fs/afs/vl_alias.c
+index 83cf1bfbe343a..b2cc10df95308 100644
+--- a/fs/afs/vl_alias.c
++++ b/fs/afs/vl_alias.c
+@@ -126,7 +126,7 @@ static int afs_compare_volume_slists(const struct afs_volume *vol_a,
+       lb = rcu_dereference(vol_b->servers);
+       for (i = 0; i < AFS_MAXTYPES; i++)
+-              if (la->vids[i] != lb->vids[i])
++              if (vol_a->vids[i] != vol_b->vids[i])
+                       return 0;
+       while (a < la->nr_servers && b < lb->nr_servers) {
+diff --git a/fs/afs/volume.c b/fs/afs/volume.c
+index f904ef5ea7141..a0c440324baba 100644
+--- a/fs/afs/volume.c
++++ b/fs/afs/volume.c
+@@ -73,11 +73,11 @@ static void afs_remove_volume_from_cell(struct afs_volume *volume)
+  */
+ static struct afs_volume *afs_alloc_volume(struct afs_fs_context *params,
+                                          struct afs_vldb_entry *vldb,
+-                                         unsigned long type_mask)
++                                         struct afs_server_list **_slist)
+ {
+       struct afs_server_list *slist;
+       struct afs_volume *volume;
+-      int ret = -ENOMEM;
++      int ret = -ENOMEM, i;
+       volume = kzalloc(sizeof(struct afs_volume), GFP_KERNEL);
+       if (!volume)
+@@ -96,13 +96,16 @@ static struct afs_volume *afs_alloc_volume(struct afs_fs_context *params,
+       rwlock_init(&volume->cb_v_break_lock);
+       memcpy(volume->name, vldb->name, vldb->name_len + 1);
+-      slist = afs_alloc_server_list(params->cell, params->key, vldb, type_mask);
++      for (i = 0; i < AFS_MAXTYPES; i++)
++              volume->vids[i] = vldb->vid[i];
++
++      slist = afs_alloc_server_list(volume, params->key, vldb);
+       if (IS_ERR(slist)) {
+               ret = PTR_ERR(slist);
+               goto error_1;
+       }
+-      refcount_set(&slist->usage, 1);
++      *_slist = slist;
+       rcu_assign_pointer(volume->servers, slist);
+       trace_afs_volume(volume->vid, 1, afs_volume_trace_alloc);
+       return volume;
+@@ -118,17 +121,19 @@ static struct afs_volume *afs_alloc_volume(struct afs_fs_context *params,
+  * Look up or allocate a volume record.
+  */
+ static struct afs_volume *afs_lookup_volume(struct afs_fs_context *params,
+-                                          struct afs_vldb_entry *vldb,
+-                                          unsigned long type_mask)
++                                          struct afs_vldb_entry *vldb)
+ {
++      struct afs_server_list *slist;
+       struct afs_volume *candidate, *volume;
+-      candidate = afs_alloc_volume(params, vldb, type_mask);
++      candidate = afs_alloc_volume(params, vldb, &slist);
+       if (IS_ERR(candidate))
+               return candidate;
+       volume = afs_insert_volume_into_cell(params->cell, candidate);
+-      if (volume != candidate)
++      if (volume == candidate)
++              afs_attach_volume_to_servers(volume, slist);
++      else
+               afs_put_volume(params->net, candidate, afs_volume_trace_put_cell_dup);
+       return volume;
+ }
+@@ -209,8 +214,7 @@ struct afs_volume *afs_create_volume(struct afs_fs_context *params)
+               goto error;
+       }
+-      type_mask = 1UL << params->type;
+-      volume = afs_lookup_volume(params, vldb, type_mask);
++      volume = afs_lookup_volume(params, vldb);
+ error:
+       kfree(vldb);
+@@ -222,14 +226,17 @@ struct afs_volume *afs_create_volume(struct afs_fs_context *params)
+  */
+ static void afs_destroy_volume(struct afs_net *net, struct afs_volume *volume)
+ {
++      struct afs_server_list *slist = rcu_access_pointer(volume->servers);
++
+       _enter("%p", volume);
+ #ifdef CONFIG_AFS_FSCACHE
+       ASSERTCMP(volume->cache, ==, NULL);
+ #endif
++      afs_detach_volume_from_servers(volume, slist);
+       afs_remove_volume_from_cell(volume);
+-      afs_put_serverlist(net, rcu_access_pointer(volume->servers));
++      afs_put_serverlist(net, slist);
+       afs_put_cell(volume->cell, afs_cell_trace_put_vol);
+       trace_afs_volume(volume->vid, refcount_read(&volume->ref),
+                        afs_volume_trace_free);
+@@ -348,8 +355,7 @@ static int afs_update_volume_status(struct afs_volume *volume, struct key *key)
+       }
+       /* See if the volume's server list got updated. */
+-      new = afs_alloc_server_list(volume->cell, key,
+-                                  vldb, (1 << volume->type));
++      new = afs_alloc_server_list(volume, key, vldb);
+       if (IS_ERR(new)) {
+               ret = PTR_ERR(new);
+               goto error_vldb;
+@@ -370,9 +376,11 @@ static int afs_update_volume_status(struct afs_volume *volume, struct key *key)
+       volume->update_at = ktime_get_real_seconds() + afs_volume_record_life;
+       write_unlock(&volume->servers_lock);
+-      ret = 0;
++      if (discard == old)
++              afs_reattach_volume_to_servers(volume, new, old);
+       afs_put_serverlist(volume->cell->net, discard);
++      ret = 0;
+ error_vldb:
+       kfree(vldb);
+ error:
+-- 
+2.39.5
+
diff --git a/queue-5.15/afs-remove-variable-nr_servers.patch b/queue-5.15/afs-remove-variable-nr_servers.patch
new file mode 100644 (file)
index 0000000..646c771
--- /dev/null
@@ -0,0 +1,44 @@
+From 8b5658ec52b5499839ee761a0c24eb5eedd75e4b Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 20 Oct 2022 18:39:23 +0100
+Subject: afs: remove variable nr_servers
+
+From: Colin Ian King <colin.i.king@gmail.com>
+
+[ Upstream commit 318b83b71242998814a570c3420c042ee6165fca ]
+
+Variable nr_servers is no longer being used, the last reference
+to it was removed in commit 45df8462730d ("afs: Fix server list handling")
+so clean up the code by removing it.
+
+Signed-off-by: Colin Ian King <colin.i.king@gmail.com>
+Signed-off-by: David Howells <dhowells@redhat.com>
+cc: Marc Dionne <marc.dionne@auristor.com>
+cc: linux-afs@lists.infradead.org
+Link: https://lore.kernel.org/r/20221020173923.21342-1-colin.i.king@gmail.com/
+Stable-dep-of: add117e48df4 ("afs: Fix the server_list to unuse a displaced server rather than putting it")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ fs/afs/volume.c | 6 +-----
+ 1 file changed, 1 insertion(+), 5 deletions(-)
+
+diff --git a/fs/afs/volume.c b/fs/afs/volume.c
+index 3d39ce5a23f22..f904ef5ea7141 100644
+--- a/fs/afs/volume.c
++++ b/fs/afs/volume.c
+@@ -77,11 +77,7 @@ static struct afs_volume *afs_alloc_volume(struct afs_fs_context *params,
+ {
+       struct afs_server_list *slist;
+       struct afs_volume *volume;
+-      int ret = -ENOMEM, nr_servers = 0, i;
+-
+-      for (i = 0; i < vldb->nr_servers; i++)
+-              if (vldb->fs_mask[i] & type_mask)
+-                      nr_servers++;
++      int ret = -ENOMEM;
+       volume = kzalloc(sizeof(struct afs_volume), GFP_KERNEL);
+       if (!volume)
+-- 
+2.39.5
+
diff --git a/queue-5.15/alsa-usb-audio-avoid-dropping-midi-events-at-closing.patch b/queue-5.15/alsa-usb-audio-avoid-dropping-midi-events-at-closing.patch
new file mode 100644 (file)
index 0000000..d05e1c2
--- /dev/null
@@ -0,0 +1,47 @@
+From 17ae2db9ddc87e5933169d11a45bc965e3d47cbb Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 18 Feb 2025 12:40:24 +0100
+Subject: ALSA: usb-audio: Avoid dropping MIDI events at closing multiple ports
+
+From: Takashi Iwai <tiwai@suse.de>
+
+[ Upstream commit a3bdd8f5c2217e1cb35db02c2eed36ea20fb50f5 ]
+
+We fixed the UAF issue in USB MIDI code by canceling the pending work
+at closing each MIDI output device in the commit below.  However, this
+assumed that it's the only one that is tied with the endpoint, and it
+resulted in unexpected data truncations when multiple devices are
+assigned to a single endpoint and opened simultaneously.
+
+For addressing the unexpected MIDI message drops, simply replace
+cancel_work_sync() with flush_work().  The drain callback should have
+been already invoked before the close callback, hence the port->active
+flag must be already cleared.  So this just assures that the pending
+work is finished before freeing the resources.
+
+Fixes: 0125de38122f ("ALSA: usb-audio: Cancel pending work at closing a MIDI substream")
+Reported-and-tested-by: John Keeping <jkeeping@inmusicbrands.com>
+Closes: https://lore.kernel.org/20250217111647.3368132-1-jkeeping@inmusicbrands.com
+Link: https://patch.msgid.link/20250218114024.23125-1-tiwai@suse.de
+Signed-off-by: Takashi Iwai <tiwai@suse.de>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ sound/usb/midi.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/sound/usb/midi.c b/sound/usb/midi.c
+index 9a361b202a09d..a56c1a69b422a 100644
+--- a/sound/usb/midi.c
++++ b/sound/usb/midi.c
+@@ -1145,7 +1145,7 @@ static int snd_usbmidi_output_close(struct snd_rawmidi_substream *substream)
+ {
+       struct usbmidi_out_port *port = substream->runtime->private_data;
+-      cancel_work_sync(&port->ep->work);
++      flush_work(&port->ep->work);
+       return substream_open(substream, 0, 0);
+ }
+-- 
+2.39.5
+
diff --git a/queue-5.15/asoc-es8328-fix-route-from-dac-to-output.patch b/queue-5.15/asoc-es8328-fix-route-from-dac-to-output.patch
new file mode 100644 (file)
index 0000000..0568a2b
--- /dev/null
@@ -0,0 +1,110 @@
+From c90068e14ca9cc16a08949ada9ccafea01bc35b2 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 22 Feb 2025 20:39:57 +0100
+Subject: ASoC: es8328: fix route from DAC to output
+
+From: Nicolas Frattaroli <nicolas.frattaroli@collabora.com>
+
+[ Upstream commit 5b0c02f9b8acf2a791e531bbc09acae2d51f4f9b ]
+
+The ES8328 codec driver, which is also used for the ES8388 chip that
+appears to have an identical register map, claims that the output can
+either take the route from DAC->Mixer->Output or through DAC->Output
+directly. To the best of what I could find, this is not true, and
+creates problems.
+
+Without DACCONTROL17 bit index 7 set for the left channel, as well as
+DACCONTROL20 bit index 7 set for the right channel, I cannot get any
+analog audio out on Left Out 2 and Right Out 2 respectively, despite the
+DAPM routes claiming that this should be possible. Furthermore, the same
+is the case for Left Out 1 and Right Out 1, showing that those two don't
+have a direct route from DAC to output bypassing the mixer either.
+
+Those control bits toggle whether the DACs are fed (stale bread?) into
+their respective mixers. If one "unmutes" the mixer controls in
+alsamixer, then sure, the audio output works, but if it doesn't work
+without the mixer being fed the DAC input then evidently it's not a
+direct output from the DAC.
+
+ES8328/ES8388 are seemingly not alone in this. ES8323, which uses a
+separate driver for what appears to be a very similar register map,
+simply flips those two bits on in its probe function, and then pretends
+there is no power management whatsoever for the individual controls.
+Fair enough.
+
+My theory as to why nobody has noticed this up to this point is that
+everyone just assumes it's their fault when they had to unmute an
+additional control in ALSA.
+
+Fix this in the es8328 driver by removing the erroneous direct route,
+then get rid of the playback switch controls and have those bits tied to
+the mixer's widget instead, which until now had no register to play
+with.
+
+Fixes: 567e4f98922c ("ASoC: add es8328 codec driver")
+Signed-off-by: Nicolas Frattaroli <nicolas.frattaroli@collabora.com>
+Link: https://patch.msgid.link/20250222-es8328-route-bludgeoning-v1-1-99bfb7fb22d9@collabora.com
+Signed-off-by: Mark Brown <broonie@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ sound/soc/codecs/es8328.c | 15 ++++-----------
+ 1 file changed, 4 insertions(+), 11 deletions(-)
+
+diff --git a/sound/soc/codecs/es8328.c b/sound/soc/codecs/es8328.c
+index ca3b1c00fa787..fe4763805df94 100644
+--- a/sound/soc/codecs/es8328.c
++++ b/sound/soc/codecs/es8328.c
+@@ -234,7 +234,6 @@ static const struct snd_kcontrol_new es8328_right_line_controls =
+ /* Left Mixer */
+ static const struct snd_kcontrol_new es8328_left_mixer_controls[] = {
+-      SOC_DAPM_SINGLE("Playback Switch", ES8328_DACCONTROL17, 7, 1, 0),
+       SOC_DAPM_SINGLE("Left Bypass Switch", ES8328_DACCONTROL17, 6, 1, 0),
+       SOC_DAPM_SINGLE("Right Playback Switch", ES8328_DACCONTROL18, 7, 1, 0),
+       SOC_DAPM_SINGLE("Right Bypass Switch", ES8328_DACCONTROL18, 6, 1, 0),
+@@ -244,7 +243,6 @@ static const struct snd_kcontrol_new es8328_left_mixer_controls[] = {
+ static const struct snd_kcontrol_new es8328_right_mixer_controls[] = {
+       SOC_DAPM_SINGLE("Left Playback Switch", ES8328_DACCONTROL19, 7, 1, 0),
+       SOC_DAPM_SINGLE("Left Bypass Switch", ES8328_DACCONTROL19, 6, 1, 0),
+-      SOC_DAPM_SINGLE("Playback Switch", ES8328_DACCONTROL20, 7, 1, 0),
+       SOC_DAPM_SINGLE("Right Bypass Switch", ES8328_DACCONTROL20, 6, 1, 0),
+ };
+@@ -337,10 +335,10 @@ static const struct snd_soc_dapm_widget es8328_dapm_widgets[] = {
+       SND_SOC_DAPM_DAC("Left DAC", "Left Playback", ES8328_DACPOWER,
+                       ES8328_DACPOWER_LDAC_OFF, 1),
+-      SND_SOC_DAPM_MIXER("Left Mixer", SND_SOC_NOPM, 0, 0,
++      SND_SOC_DAPM_MIXER("Left Mixer", ES8328_DACCONTROL17, 7, 0,
+               &es8328_left_mixer_controls[0],
+               ARRAY_SIZE(es8328_left_mixer_controls)),
+-      SND_SOC_DAPM_MIXER("Right Mixer", SND_SOC_NOPM, 0, 0,
++      SND_SOC_DAPM_MIXER("Right Mixer", ES8328_DACCONTROL20, 7, 0,
+               &es8328_right_mixer_controls[0],
+               ARRAY_SIZE(es8328_right_mixer_controls)),
+@@ -419,19 +417,14 @@ static const struct snd_soc_dapm_route es8328_dapm_routes[] = {
+       { "Right Line Mux", "PGA", "Right PGA Mux" },
+       { "Right Line Mux", "Differential", "Differential Mux" },
+-      { "Left Out 1", NULL, "Left DAC" },
+-      { "Right Out 1", NULL, "Right DAC" },
+-      { "Left Out 2", NULL, "Left DAC" },
+-      { "Right Out 2", NULL, "Right DAC" },
+-
+-      { "Left Mixer", "Playback Switch", "Left DAC" },
++      { "Left Mixer", NULL, "Left DAC" },
+       { "Left Mixer", "Left Bypass Switch", "Left Line Mux" },
+       { "Left Mixer", "Right Playback Switch", "Right DAC" },
+       { "Left Mixer", "Right Bypass Switch", "Right Line Mux" },
+       { "Right Mixer", "Left Playback Switch", "Left DAC" },
+       { "Right Mixer", "Left Bypass Switch", "Left Line Mux" },
+-      { "Right Mixer", "Playback Switch", "Right DAC" },
++      { "Right Mixer", NULL, "Right DAC" },
+       { "Right Mixer", "Right Bypass Switch", "Right Line Mux" },
+       { "DAC DIG", NULL, "DAC STM" },
+-- 
+2.39.5
+
diff --git a/queue-5.15/bluetooth-l2cap-fix-l2cap_ecred_conn_rsp-response.patch b/queue-5.15/bluetooth-l2cap-fix-l2cap_ecred_conn_rsp-response.patch
new file mode 100644 (file)
index 0000000..68a6373
--- /dev/null
@@ -0,0 +1,99 @@
+From 4ae5026aebfaf5a2b0304e9f9831fb843f5f637b Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 14 Feb 2025 10:30:25 -0500
+Subject: Bluetooth: L2CAP: Fix L2CAP_ECRED_CONN_RSP response
+
+From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
+
+[ Upstream commit b25120e1d5f2ebb3db00af557709041f47f7f3d0 ]
+
+L2CAP_ECRED_CONN_RSP needs to respond DCID in the same order received as
+SCID but the order is reversed due to use of list_add which actually
+prepend channels to the list so the response is reversed:
+
+> ACL Data RX: Handle 16 flags 0x02 dlen 26
+      LE L2CAP: Enhanced Credit Connection Request (0x17) ident 2 len 18
+        PSM: 39 (0x0027)
+        MTU: 256
+        MPS: 251
+        Credits: 65535
+        Source CID: 116
+        Source CID: 117
+        Source CID: 118
+        Source CID: 119
+        Source CID: 120
+< ACL Data TX: Handle 16 flags 0x00 dlen 26
+      LE L2CAP: Enhanced Credit Connection Response (0x18) ident 2 len 18
+        MTU: 517
+        MPS: 247
+        Credits: 3
+        Result: Connection successful (0x0000)
+        Destination CID: 68
+        Destination CID: 67
+        Destination CID: 66
+        Destination CID: 65
+        Destination CID: 64
+
+Also make sure the response don't include channels that are not on
+BT_CONNECT2 since the chan->ident can be set to the same value as in the
+following trace:
+
+< ACL Data TX: Handle 16 flags 0x00 dlen 12
+      LE L2CAP: LE Flow Control Credit (0x16) ident 6 len 4
+        Source CID: 64
+        Credits: 1
+...
+> ACL Data RX: Handle 16 flags 0x02 dlen 18
+      LE L2CAP: Enhanced Credit Connection Request (0x17) ident 6 len 10
+        PSM: 39 (0x0027)
+        MTU: 517
+        MPS: 251
+        Credits: 255
+        Source CID: 70
+< ACL Data TX: Handle 16 flags 0x00 dlen 20
+      LE L2CAP: Enhanced Credit Connection Response (0x18) ident 6 len 12
+        MTU: 517
+        MPS: 247
+        Credits: 3
+        Result: Connection successful (0x0000)
+        Destination CID: 64
+        Destination CID: 68
+
+Closes: https://github.com/bluez/bluez/issues/1094
+Fixes: 9aa9d9473f15 ("Bluetooth: L2CAP: Fix responding with wrong PDU type")
+Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/bluetooth/l2cap_core.c | 9 +++++++--
+ 1 file changed, 7 insertions(+), 2 deletions(-)
+
+diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
+index 496634c359eb7..2d451009a6477 100644
+--- a/net/bluetooth/l2cap_core.c
++++ b/net/bluetooth/l2cap_core.c
+@@ -632,7 +632,8 @@ void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
+           test_bit(FLAG_HOLD_HCI_CONN, &chan->flags))
+               hci_conn_hold(conn->hcon);
+-      list_add(&chan->list, &conn->chan_l);
++      /* Append to the list since the order matters for ECRED */
++      list_add_tail(&chan->list, &conn->chan_l);
+ }
+ void l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
+@@ -3971,7 +3972,11 @@ static void l2cap_ecred_rsp_defer(struct l2cap_chan *chan, void *data)
+ {
+       struct l2cap_ecred_rsp_data *rsp = data;
+-      if (test_bit(FLAG_ECRED_CONN_REQ_SENT, &chan->flags))
++      /* Check if channel for outgoing connection or if it wasn't deferred
++       * since in those cases it must be skipped.
++       */
++      if (test_bit(FLAG_ECRED_CONN_REQ_SENT, &chan->flags) ||
++          !test_and_clear_bit(FLAG_DEFER_SETUP, &chan->flags))
+               return;
+       /* Reset ident so only one response is sent */
+-- 
+2.39.5
+
diff --git a/queue-5.15/include-net-add-static-inline-dst_dev_overhead-to-ds.patch b/queue-5.15/include-net-add-static-inline-dst_dev_overhead-to-ds.patch
new file mode 100644 (file)
index 0000000..d96dbd6
--- /dev/null
@@ -0,0 +1,49 @@
+From d66f6c6aaf7fc532f8e9628bf88fdfcbca2cc1c1 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 3 Dec 2024 13:49:42 +0100
+Subject: include: net: add static inline dst_dev_overhead() to dst.h
+
+From: Justin Iurman <justin.iurman@uliege.be>
+
+[ Upstream commit 0600cf40e9b36fe17f9c9f04d4f9cef249eaa5e7 ]
+
+Add static inline dst_dev_overhead() function to include/net/dst.h. This
+helper function is used by ioam6_iptunnel, rpl_iptunnel and
+seg6_iptunnel to get the dev's overhead based on a cache entry
+(dst_entry). If the cache is empty, the default and generic value
+skb->mac_len is returned. Otherwise, LL_RESERVED_SPACE() over dst's dev
+is returned.
+
+Signed-off-by: Justin Iurman <justin.iurman@uliege.be>
+Cc: Alexander Lobakin <aleksander.lobakin@intel.com>
+Cc: Vadim Fedorenko <vadim.fedorenko@linux.dev>
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+Stable-dep-of: c64a0727f9b1 ("net: ipv6: fix dst ref loop on input in seg6 lwt")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ include/net/dst.h | 9 +++++++++
+ 1 file changed, 9 insertions(+)
+
+diff --git a/include/net/dst.h b/include/net/dst.h
+index 827f99d577331..bf0a9b0cc269c 100644
+--- a/include/net/dst.h
++++ b/include/net/dst.h
+@@ -433,6 +433,15 @@ static inline void dst_set_expires(struct dst_entry *dst, int timeout)
+               dst->expires = expires;
+ }
++static inline unsigned int dst_dev_overhead(struct dst_entry *dst,
++                                          struct sk_buff *skb)
++{
++      if (likely(dst))
++              return LL_RESERVED_SPACE(dst->dev);
++
++      return skb->mac_len;
++}
++
+ INDIRECT_CALLABLE_DECLARE(int ip6_output(struct net *, struct sock *,
+                                        struct sk_buff *));
+ INDIRECT_CALLABLE_DECLARE(int ip_output(struct net *, struct sock *,
+-- 
+2.39.5
+
diff --git a/queue-5.15/ipvs-always-clear-ipvs_property-flag-in-skb_scrub_pa.patch b/queue-5.15/ipvs-always-clear-ipvs_property-flag-in-skb_scrub_pa.patch
new file mode 100644 (file)
index 0000000..4d0fc18
--- /dev/null
@@ -0,0 +1,51 @@
+From 7ab1a8e436b5a73b04d445c0c46b1eb1593c727b Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Sat, 22 Feb 2025 11:35:18 +0800
+Subject: ipvs: Always clear ipvs_property flag in skb_scrub_packet()
+
+From: Philo Lu <lulie@linux.alibaba.com>
+
+[ Upstream commit de2c211868b9424f9aa9b3432c4430825bafb41b ]
+
+We found an issue when using bpf_redirect with ipvs NAT mode after
+commit ff70202b2d1a ("dev_forward_skb: do not scrub skb mark within
+the same name space"). Particularly, we use bpf_redirect to return
+the skb directly back to the netif it comes from, i.e., xnet is
+false in skb_scrub_packet(), and then ipvs_property is preserved
+and SNAT is skipped in the rx path.
+
+ipvs_property has been already cleared when netns is changed in
+commit 2b5ec1a5f973 ("netfilter/ipvs: clear ipvs_property flag when
+SKB net namespace changed"). This patch just clears it in spite of
+netns.
+
+Fixes: 2b5ec1a5f973 ("netfilter/ipvs: clear ipvs_property flag when SKB net namespace changed")
+Signed-off-by: Philo Lu <lulie@linux.alibaba.com>
+Acked-by: Julian Anastasov <ja@ssi.bg>
+Link: https://patch.msgid.link/20250222033518.126087-1-lulie@linux.alibaba.com
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/core/skbuff.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/net/core/skbuff.c b/net/core/skbuff.c
+index 17073429cc365..d4c821d97b545 100644
+--- a/net/core/skbuff.c
++++ b/net/core/skbuff.c
+@@ -5558,11 +5558,11 @@ void skb_scrub_packet(struct sk_buff *skb, bool xnet)
+       skb->offload_fwd_mark = 0;
+       skb->offload_l3_fwd_mark = 0;
+ #endif
++      ipvs_reset(skb);
+       if (!xnet)
+               return;
+-      ipvs_reset(skb);
+       skb->mark = 0;
+       skb->tstamp = 0;
+ }
+-- 
+2.39.5
+
diff --git a/queue-5.15/net-cadence-macb-synchronize-stats-calculations.patch b/queue-5.15/net-cadence-macb-synchronize-stats-calculations.patch
new file mode 100644 (file)
index 0000000..7075ff8
--- /dev/null
@@ -0,0 +1,115 @@
+From 4d2c99eaefc8e9847a8a7b1598c7599acfdec2df Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 20 Feb 2025 11:29:50 -0500
+Subject: net: cadence: macb: Synchronize stats calculations
+
+From: Sean Anderson <sean.anderson@linux.dev>
+
+[ Upstream commit fa52f15c745ce55261b92873676f64f7348cfe82 ]
+
+Stats calculations involve a RMW to add the stat update to the existing
+value. This is currently not protected by any synchronization mechanism,
+so data races are possible. Add a spinlock to protect the update. The
+reader side could be protected using u64_stats, but we would still need
+a spinlock for the update side anyway. And we always do an update
+immediately before reading the stats anyway.
+
+Fixes: 89e5785fc8a6 ("[PATCH] Atmel MACB ethernet driver")
+Signed-off-by: Sean Anderson <sean.anderson@linux.dev>
+Link: https://patch.msgid.link/20250220162950.95941-1-sean.anderson@linux.dev
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/cadence/macb.h      |  2 ++
+ drivers/net/ethernet/cadence/macb_main.c | 12 ++++++++++--
+ 2 files changed, 12 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/net/ethernet/cadence/macb.h b/drivers/net/ethernet/cadence/macb.h
+index d8d87213697cd..d3d1b9237d594 100644
+--- a/drivers/net/ethernet/cadence/macb.h
++++ b/drivers/net/ethernet/cadence/macb.h
+@@ -1258,6 +1258,8 @@ struct macb {
+       struct clk              *rx_clk;
+       struct clk              *tsu_clk;
+       struct net_device       *dev;
++      /* Protects hw_stats and ethtool_stats */
++      spinlock_t              stats_lock;
+       union {
+               struct macb_stats       macb;
+               struct gem_stats        gem;
+diff --git a/drivers/net/ethernet/cadence/macb_main.c b/drivers/net/ethernet/cadence/macb_main.c
+index 4e7359657941d..275baaaea0e12 100644
+--- a/drivers/net/ethernet/cadence/macb_main.c
++++ b/drivers/net/ethernet/cadence/macb_main.c
+@@ -1892,10 +1892,12 @@ static irqreturn_t macb_interrupt(int irq, void *dev_id)
+               if (status & MACB_BIT(ISR_ROVR)) {
+                       /* We missed at least one packet */
++                      spin_lock(&bp->stats_lock);
+                       if (macb_is_gem(bp))
+                               bp->hw_stats.gem.rx_overruns++;
+                       else
+                               bp->hw_stats.macb.rx_overruns++;
++                      spin_unlock(&bp->stats_lock);
+                       if (bp->caps & MACB_CAPS_ISR_CLEAR_ON_WRITE)
+                               queue_writel(queue, ISR, MACB_BIT(ISR_ROVR));
+@@ -2939,6 +2941,7 @@ static struct net_device_stats *gem_get_stats(struct macb *bp)
+       if (!netif_running(bp->dev))
+               return nstat;
++      spin_lock_irq(&bp->stats_lock);
+       gem_update_stats(bp);
+       nstat->rx_errors = (hwstat->rx_frame_check_sequence_errors +
+@@ -2968,6 +2971,7 @@ static struct net_device_stats *gem_get_stats(struct macb *bp)
+       nstat->tx_aborted_errors = hwstat->tx_excessive_collisions;
+       nstat->tx_carrier_errors = hwstat->tx_carrier_sense_errors;
+       nstat->tx_fifo_errors = hwstat->tx_underrun;
++      spin_unlock_irq(&bp->stats_lock);
+       return nstat;
+ }
+@@ -2975,12 +2979,13 @@ static struct net_device_stats *gem_get_stats(struct macb *bp)
+ static void gem_get_ethtool_stats(struct net_device *dev,
+                                 struct ethtool_stats *stats, u64 *data)
+ {
+-      struct macb *bp;
++      struct macb *bp = netdev_priv(dev);
+-      bp = netdev_priv(dev);
++      spin_lock_irq(&bp->stats_lock);
+       gem_update_stats(bp);
+       memcpy(data, &bp->ethtool_stats, sizeof(u64)
+                       * (GEM_STATS_LEN + QUEUE_STATS_LEN * MACB_MAX_QUEUES));
++      spin_unlock_irq(&bp->stats_lock);
+ }
+ static int gem_get_sset_count(struct net_device *dev, int sset)
+@@ -3030,6 +3035,7 @@ static struct net_device_stats *macb_get_stats(struct net_device *dev)
+               return gem_get_stats(bp);
+       /* read stats from hardware */
++      spin_lock_irq(&bp->stats_lock);
+       macb_update_stats(bp);
+       /* Convert HW stats into netdevice stats */
+@@ -3063,6 +3069,7 @@ static struct net_device_stats *macb_get_stats(struct net_device *dev)
+       nstat->tx_carrier_errors = hwstat->tx_carrier_errors;
+       nstat->tx_fifo_errors = hwstat->tx_underruns;
+       /* Don't know about heartbeat or window errors... */
++      spin_unlock_irq(&bp->stats_lock);
+       return nstat;
+ }
+@@ -4802,6 +4809,7 @@ static int macb_probe(struct platform_device *pdev)
+       bp->usrio = macb_config->usrio;
+       spin_lock_init(&bp->lock);
++      spin_lock_init(&bp->stats_lock);
+       /* setup capabilities */
+       macb_configure_caps(bp, macb_config);
+-- 
+2.39.5
+
diff --git a/queue-5.15/net-ipv6-fix-dst-ref-loop-on-input-in-rpl-lwt.patch b/queue-5.15/net-ipv6-fix-dst-ref-loop-on-input-in-rpl-lwt.patch
new file mode 100644 (file)
index 0000000..919d2fb
--- /dev/null
@@ -0,0 +1,60 @@
+From 196d882db70031c42a137b1814e2e6957647c748 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 25 Feb 2025 18:51:39 +0100
+Subject: net: ipv6: fix dst ref loop on input in rpl lwt
+
+From: Justin Iurman <justin.iurman@uliege.be>
+
+[ Upstream commit 13e55fbaec176119cff68a7e1693b251c8883c5f ]
+
+Prevent a dst ref loop on input in rpl_iptunnel.
+
+Fixes: a7a29f9c361f ("net: ipv6: add rpl sr tunnel")
+Cc: Alexander Aring <alex.aring@gmail.com>
+Cc: Ido Schimmel <idosch@nvidia.com>
+Reviewed-by: Ido Schimmel <idosch@nvidia.com>
+Signed-off-by: Justin Iurman <justin.iurman@uliege.be>
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/ipv6/rpl_iptunnel.c | 14 ++++++++++++--
+ 1 file changed, 12 insertions(+), 2 deletions(-)
+
+diff --git a/net/ipv6/rpl_iptunnel.c b/net/ipv6/rpl_iptunnel.c
+index 69b9bd90140dd..862ac1e2e191c 100644
+--- a/net/ipv6/rpl_iptunnel.c
++++ b/net/ipv6/rpl_iptunnel.c
+@@ -259,10 +259,18 @@ static int rpl_input(struct sk_buff *skb)
+ {
+       struct dst_entry *orig_dst = skb_dst(skb);
+       struct dst_entry *dst = NULL;
++      struct lwtunnel_state *lwtst;
+       struct rpl_lwt *rlwt;
+       int err;
+-      rlwt = rpl_lwt_lwtunnel(orig_dst->lwtstate);
++      /* We cannot dereference "orig_dst" once ip6_route_input() or
++       * skb_dst_drop() is called. However, in order to detect a dst loop, we
++       * need the address of its lwtstate. So, save the address of lwtstate
++       * now and use it later as a comparison.
++       */
++      lwtst = orig_dst->lwtstate;
++
++      rlwt = rpl_lwt_lwtunnel(lwtst);
+       local_bh_disable();
+       dst = dst_cache_get(&rlwt->cache);
+@@ -277,7 +285,9 @@ static int rpl_input(struct sk_buff *skb)
+       if (!dst) {
+               ip6_route_input(skb);
+               dst = skb_dst(skb);
+-              if (!dst->error) {
++
++              /* cache only if we don't create a dst reference loop */
++              if (!dst->error && lwtst != dst->lwtstate) {
+                       local_bh_disable();
+                       dst_cache_set_ip6(&rlwt->cache, dst,
+                                         &ipv6_hdr(skb)->saddr);
+-- 
+2.39.5
+
diff --git a/queue-5.15/net-ipv6-fix-dst-ref-loop-on-input-in-seg6-lwt.patch b/queue-5.15/net-ipv6-fix-dst-ref-loop-on-input-in-seg6-lwt.patch
new file mode 100644 (file)
index 0000000..d16ac15
--- /dev/null
@@ -0,0 +1,60 @@
+From 1f8341e3f1f9cbf03429d67179b92f1a468d7a7e Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 25 Feb 2025 18:51:38 +0100
+Subject: net: ipv6: fix dst ref loop on input in seg6 lwt
+
+From: Justin Iurman <justin.iurman@uliege.be>
+
+[ Upstream commit c64a0727f9b1cbc63a5538c8c0014e9a175ad864 ]
+
+Prevent a dst ref loop on input in seg6_iptunnel.
+
+Fixes: af4a2209b134 ("ipv6: sr: use dst_cache in seg6_input")
+Cc: David Lebrun <dlebrun@google.com>
+Cc: Ido Schimmel <idosch@nvidia.com>
+Reviewed-by: Ido Schimmel <idosch@nvidia.com>
+Signed-off-by: Justin Iurman <justin.iurman@uliege.be>
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/ipv6/seg6_iptunnel.c | 14 ++++++++++++--
+ 1 file changed, 12 insertions(+), 2 deletions(-)
+
+diff --git a/net/ipv6/seg6_iptunnel.c b/net/ipv6/seg6_iptunnel.c
+index c161298c8b335..b186d85ec5b3f 100644
+--- a/net/ipv6/seg6_iptunnel.c
++++ b/net/ipv6/seg6_iptunnel.c
+@@ -472,10 +472,18 @@ static int seg6_input_core(struct net *net, struct sock *sk,
+ {
+       struct dst_entry *orig_dst = skb_dst(skb);
+       struct dst_entry *dst = NULL;
++      struct lwtunnel_state *lwtst;
+       struct seg6_lwt *slwt;
+       int err;
+-      slwt = seg6_lwt_lwtunnel(orig_dst->lwtstate);
++      /* We cannot dereference "orig_dst" once ip6_route_input() or
++       * skb_dst_drop() is called. However, in order to detect a dst loop, we
++       * need the address of its lwtstate. So, save the address of lwtstate
++       * now and use it later as a comparison.
++       */
++      lwtst = orig_dst->lwtstate;
++
++      slwt = seg6_lwt_lwtunnel(lwtst);
+       local_bh_disable();
+       dst = dst_cache_get(&slwt->cache);
+@@ -490,7 +498,9 @@ static int seg6_input_core(struct net *net, struct sock *sk,
+       if (!dst) {
+               ip6_route_input(skb);
+               dst = skb_dst(skb);
+-              if (!dst->error) {
++
++              /* cache only if we don't create a dst reference loop */
++              if (!dst->error && lwtst != dst->lwtstate) {
+                       local_bh_disable();
+                       dst_cache_set_ip6(&slwt->cache, dst,
+                                         &ipv6_hdr(skb)->saddr);
+-- 
+2.39.5
+
diff --git a/queue-5.15/net-ipv6-rpl_iptunnel-mitigate-2-realloc-issue.patch b/queue-5.15/net-ipv6-rpl_iptunnel-mitigate-2-realloc-issue.patch
new file mode 100644 (file)
index 0000000..82c4774
--- /dev/null
@@ -0,0 +1,155 @@
+From 6b31b93f7088f7b9333a79ea991ef1313000767d Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 3 Dec 2024 13:49:45 +0100
+Subject: net: ipv6: rpl_iptunnel: mitigate 2-realloc issue
+
+From: Justin Iurman <justin.iurman@uliege.be>
+
+[ Upstream commit 985ec6f5e6235242191370628acb73d7a9f0c0ea ]
+
+This patch mitigates the two-reallocations issue with rpl_iptunnel by
+providing the dst_entry (in the cache) to the first call to
+skb_cow_head(). As a result, the very first iteration would still
+trigger two reallocations (i.e., empty cache), while next iterations
+would only trigger a single reallocation.
+
+Performance tests before/after applying this patch, which clearly shows
+there is no impact (it even shows improvement):
+- before: https://ibb.co/nQJhqwc
+- after: https://ibb.co/4ZvW6wV
+
+Signed-off-by: Justin Iurman <justin.iurman@uliege.be>
+Cc: Alexander Aring <aahringo@redhat.com>
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+Stable-dep-of: 13e55fbaec17 ("net: ipv6: fix dst ref loop on input in rpl lwt")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/ipv6/rpl_iptunnel.c | 46 ++++++++++++++++++++++-------------------
+ 1 file changed, 25 insertions(+), 21 deletions(-)
+
+diff --git a/net/ipv6/rpl_iptunnel.c b/net/ipv6/rpl_iptunnel.c
+index c1d0f947a7c87..69b9bd90140dd 100644
+--- a/net/ipv6/rpl_iptunnel.c
++++ b/net/ipv6/rpl_iptunnel.c
+@@ -125,7 +125,8 @@ static void rpl_destroy_state(struct lwtunnel_state *lwt)
+ }
+ static int rpl_do_srh_inline(struct sk_buff *skb, const struct rpl_lwt *rlwt,
+-                           const struct ipv6_rpl_sr_hdr *srh)
++                           const struct ipv6_rpl_sr_hdr *srh,
++                           struct dst_entry *cache_dst)
+ {
+       struct ipv6_rpl_sr_hdr *isrh, *csrh;
+       const struct ipv6hdr *oldhdr;
+@@ -153,7 +154,7 @@ static int rpl_do_srh_inline(struct sk_buff *skb, const struct rpl_lwt *rlwt,
+       hdrlen = ((csrh->hdrlen + 1) << 3);
+-      err = skb_cow_head(skb, hdrlen + skb->mac_len);
++      err = skb_cow_head(skb, hdrlen + dst_dev_overhead(cache_dst, skb));
+       if (unlikely(err)) {
+               kfree(buf);
+               return err;
+@@ -186,7 +187,8 @@ static int rpl_do_srh_inline(struct sk_buff *skb, const struct rpl_lwt *rlwt,
+       return 0;
+ }
+-static int rpl_do_srh(struct sk_buff *skb, const struct rpl_lwt *rlwt)
++static int rpl_do_srh(struct sk_buff *skb, const struct rpl_lwt *rlwt,
++                    struct dst_entry *cache_dst)
+ {
+       struct dst_entry *dst = skb_dst(skb);
+       struct rpl_iptunnel_encap *tinfo;
+@@ -196,7 +198,7 @@ static int rpl_do_srh(struct sk_buff *skb, const struct rpl_lwt *rlwt)
+       tinfo = rpl_encap_lwtunnel(dst->lwtstate);
+-      return rpl_do_srh_inline(skb, rlwt, tinfo->srh);
++      return rpl_do_srh_inline(skb, rlwt, tinfo->srh, cache_dst);
+ }
+ static int rpl_output(struct net *net, struct sock *sk, struct sk_buff *skb)
+@@ -208,14 +210,14 @@ static int rpl_output(struct net *net, struct sock *sk, struct sk_buff *skb)
+       rlwt = rpl_lwt_lwtunnel(orig_dst->lwtstate);
+-      err = rpl_do_srh(skb, rlwt);
+-      if (unlikely(err))
+-              goto drop;
+-
+       local_bh_disable();
+       dst = dst_cache_get(&rlwt->cache);
+       local_bh_enable();
++      err = rpl_do_srh(skb, rlwt, dst);
++      if (unlikely(err))
++              goto drop;
++
+       if (unlikely(!dst)) {
+               struct ipv6hdr *hdr = ipv6_hdr(skb);
+               struct flowi6 fl6;
+@@ -237,15 +239,15 @@ static int rpl_output(struct net *net, struct sock *sk, struct sk_buff *skb)
+               local_bh_disable();
+               dst_cache_set_ip6(&rlwt->cache, dst, &fl6.saddr);
+               local_bh_enable();
++
++              err = skb_cow_head(skb, LL_RESERVED_SPACE(dst->dev));
++              if (unlikely(err))
++                      goto drop;
+       }
+       skb_dst_drop(skb);
+       skb_dst_set(skb, dst);
+-      err = skb_cow_head(skb, LL_RESERVED_SPACE(dst->dev));
+-      if (unlikely(err))
+-              goto drop;
+-
+       return dst_output(net, sk, skb);
+ drop:
+@@ -262,12 +264,13 @@ static int rpl_input(struct sk_buff *skb)
+       rlwt = rpl_lwt_lwtunnel(orig_dst->lwtstate);
+-      err = rpl_do_srh(skb, rlwt);
+-      if (unlikely(err))
+-              goto drop;
+-
+       local_bh_disable();
+       dst = dst_cache_get(&rlwt->cache);
++      local_bh_enable();
++
++      err = rpl_do_srh(skb, rlwt, dst);
++      if (unlikely(err))
++              goto drop;
+       skb_dst_drop(skb);
+@@ -275,17 +278,18 @@ static int rpl_input(struct sk_buff *skb)
+               ip6_route_input(skb);
+               dst = skb_dst(skb);
+               if (!dst->error) {
++                      local_bh_disable();
+                       dst_cache_set_ip6(&rlwt->cache, dst,
+                                         &ipv6_hdr(skb)->saddr);
++                      local_bh_enable();
+               }
++
++              err = skb_cow_head(skb, LL_RESERVED_SPACE(dst->dev));
++              if (unlikely(err))
++                      goto drop;
+       } else {
+               skb_dst_set(skb, dst);
+       }
+-      local_bh_enable();
+-
+-      err = skb_cow_head(skb, LL_RESERVED_SPACE(dst->dev));
+-      if (unlikely(err))
+-              goto drop;
+       return dst_input(skb);
+-- 
+2.39.5
+
diff --git a/queue-5.15/net-ipv6-seg6_iptunnel-mitigate-2-realloc-issue.patch b/queue-5.15/net-ipv6-seg6_iptunnel-mitigate-2-realloc-issue.patch
new file mode 100644 (file)
index 0000000..5cf0187
--- /dev/null
@@ -0,0 +1,255 @@
+From c783d7414bfd1cafd4f5537a97844f428b356989 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 3 Dec 2024 13:49:44 +0100
+Subject: net: ipv6: seg6_iptunnel: mitigate 2-realloc issue
+
+From: Justin Iurman <justin.iurman@uliege.be>
+
+[ Upstream commit 40475b63761abb6f8fdef960d03228a08662c9c4 ]
+
+This patch mitigates the two-reallocations issue with seg6_iptunnel by
+providing the dst_entry (in the cache) to the first call to
+skb_cow_head(). As a result, the very first iteration would still
+trigger two reallocations (i.e., empty cache), while next iterations
+would only trigger a single reallocation.
+
+Performance tests before/after applying this patch, which clearly shows
+the improvement:
+- before: https://ibb.co/3Cg4sNH
+- after: https://ibb.co/8rQ350r
+
+Signed-off-by: Justin Iurman <justin.iurman@uliege.be>
+Cc: David Lebrun <dlebrun@google.com>
+Signed-off-by: Paolo Abeni <pabeni@redhat.com>
+Stable-dep-of: c64a0727f9b1 ("net: ipv6: fix dst ref loop on input in seg6 lwt")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/ipv6/seg6_iptunnel.c | 85 ++++++++++++++++++++++++----------------
+ 1 file changed, 52 insertions(+), 33 deletions(-)
+
+diff --git a/net/ipv6/seg6_iptunnel.c b/net/ipv6/seg6_iptunnel.c
+index ae5299c277bcf..c161298c8b335 100644
+--- a/net/ipv6/seg6_iptunnel.c
++++ b/net/ipv6/seg6_iptunnel.c
+@@ -124,8 +124,8 @@ static __be32 seg6_make_flowlabel(struct net *net, struct sk_buff *skb,
+       return flowlabel;
+ }
+-/* encapsulate an IPv6 packet within an outer IPv6 header with a given SRH */
+-int seg6_do_srh_encap(struct sk_buff *skb, struct ipv6_sr_hdr *osrh, int proto)
++static int __seg6_do_srh_encap(struct sk_buff *skb, struct ipv6_sr_hdr *osrh,
++                             int proto, struct dst_entry *cache_dst)
+ {
+       struct dst_entry *dst = skb_dst(skb);
+       struct net *net = dev_net(dst->dev);
+@@ -137,7 +137,7 @@ int seg6_do_srh_encap(struct sk_buff *skb, struct ipv6_sr_hdr *osrh, int proto)
+       hdrlen = (osrh->hdrlen + 1) << 3;
+       tot_len = hdrlen + sizeof(*hdr);
+-      err = skb_cow_head(skb, tot_len + skb->mac_len);
++      err = skb_cow_head(skb, tot_len + dst_dev_overhead(cache_dst, skb));
+       if (unlikely(err))
+               return err;
+@@ -197,11 +197,18 @@ int seg6_do_srh_encap(struct sk_buff *skb, struct ipv6_sr_hdr *osrh, int proto)
+       return 0;
+ }
++
++/* encapsulate an IPv6 packet within an outer IPv6 header with a given SRH */
++int seg6_do_srh_encap(struct sk_buff *skb, struct ipv6_sr_hdr *osrh, int proto)
++{
++      return __seg6_do_srh_encap(skb, osrh, proto, NULL);
++}
+ EXPORT_SYMBOL_GPL(seg6_do_srh_encap);
+ /* encapsulate an IPv6 packet within an outer IPv6 header with reduced SRH */
+ static int seg6_do_srh_encap_red(struct sk_buff *skb,
+-                               struct ipv6_sr_hdr *osrh, int proto)
++                               struct ipv6_sr_hdr *osrh, int proto,
++                               struct dst_entry *cache_dst)
+ {
+       __u8 first_seg = osrh->first_segment;
+       struct dst_entry *dst = skb_dst(skb);
+@@ -230,7 +237,7 @@ static int seg6_do_srh_encap_red(struct sk_buff *skb,
+       tot_len = red_hdrlen + sizeof(struct ipv6hdr);
+-      err = skb_cow_head(skb, tot_len + skb->mac_len);
++      err = skb_cow_head(skb, tot_len + dst_dev_overhead(cache_dst, skb));
+       if (unlikely(err))
+               return err;
+@@ -317,8 +324,8 @@ static int seg6_do_srh_encap_red(struct sk_buff *skb,
+       return 0;
+ }
+-/* insert an SRH within an IPv6 packet, just after the IPv6 header */
+-int seg6_do_srh_inline(struct sk_buff *skb, struct ipv6_sr_hdr *osrh)
++static int __seg6_do_srh_inline(struct sk_buff *skb, struct ipv6_sr_hdr *osrh,
++                              struct dst_entry *cache_dst)
+ {
+       struct ipv6hdr *hdr, *oldhdr;
+       struct ipv6_sr_hdr *isrh;
+@@ -326,7 +333,7 @@ int seg6_do_srh_inline(struct sk_buff *skb, struct ipv6_sr_hdr *osrh)
+       hdrlen = (osrh->hdrlen + 1) << 3;
+-      err = skb_cow_head(skb, hdrlen + skb->mac_len);
++      err = skb_cow_head(skb, hdrlen + dst_dev_overhead(cache_dst, skb));
+       if (unlikely(err))
+               return err;
+@@ -369,9 +376,8 @@ int seg6_do_srh_inline(struct sk_buff *skb, struct ipv6_sr_hdr *osrh)
+       return 0;
+ }
+-EXPORT_SYMBOL_GPL(seg6_do_srh_inline);
+-static int seg6_do_srh(struct sk_buff *skb)
++static int seg6_do_srh(struct sk_buff *skb, struct dst_entry *cache_dst)
+ {
+       struct dst_entry *dst = skb_dst(skb);
+       struct seg6_iptunnel_encap *tinfo;
+@@ -384,7 +390,7 @@ static int seg6_do_srh(struct sk_buff *skb)
+               if (skb->protocol != htons(ETH_P_IPV6))
+                       return -EINVAL;
+-              err = seg6_do_srh_inline(skb, tinfo->srh);
++              err = __seg6_do_srh_inline(skb, tinfo->srh, cache_dst);
+               if (err)
+                       return err;
+               break;
+@@ -402,9 +408,11 @@ static int seg6_do_srh(struct sk_buff *skb)
+                       return -EINVAL;
+               if (tinfo->mode == SEG6_IPTUN_MODE_ENCAP)
+-                      err = seg6_do_srh_encap(skb, tinfo->srh, proto);
++                      err = __seg6_do_srh_encap(skb, tinfo->srh,
++                                                proto, cache_dst);
+               else
+-                      err = seg6_do_srh_encap_red(skb, tinfo->srh, proto);
++                      err = seg6_do_srh_encap_red(skb, tinfo->srh,
++                                                  proto, cache_dst);
+               if (err)
+                       return err;
+@@ -425,11 +433,13 @@ static int seg6_do_srh(struct sk_buff *skb)
+               skb_push(skb, skb->mac_len);
+               if (tinfo->mode == SEG6_IPTUN_MODE_L2ENCAP)
+-                      err = seg6_do_srh_encap(skb, tinfo->srh,
+-                                              IPPROTO_ETHERNET);
++                      err = __seg6_do_srh_encap(skb, tinfo->srh,
++                                                IPPROTO_ETHERNET,
++                                                cache_dst);
+               else
+                       err = seg6_do_srh_encap_red(skb, tinfo->srh,
+-                                                  IPPROTO_ETHERNET);
++                                                  IPPROTO_ETHERNET,
++                                                  cache_dst);
+               if (err)
+                       return err;
+@@ -444,6 +454,13 @@ static int seg6_do_srh(struct sk_buff *skb)
+       return 0;
+ }
++/* insert an SRH within an IPv6 packet, just after the IPv6 header */
++int seg6_do_srh_inline(struct sk_buff *skb, struct ipv6_sr_hdr *osrh)
++{
++      return __seg6_do_srh_inline(skb, osrh, NULL);
++}
++EXPORT_SYMBOL_GPL(seg6_do_srh_inline);
++
+ static int seg6_input_finish(struct net *net, struct sock *sk,
+                            struct sk_buff *skb)
+ {
+@@ -458,14 +475,15 @@ static int seg6_input_core(struct net *net, struct sock *sk,
+       struct seg6_lwt *slwt;
+       int err;
+-      err = seg6_do_srh(skb);
+-      if (unlikely(err))
+-              goto drop;
+-
+       slwt = seg6_lwt_lwtunnel(orig_dst->lwtstate);
+       local_bh_disable();
+       dst = dst_cache_get(&slwt->cache);
++      local_bh_enable();
++
++      err = seg6_do_srh(skb, dst);
++      if (unlikely(err))
++              goto drop;
+       skb_dst_drop(skb);
+@@ -473,17 +491,18 @@ static int seg6_input_core(struct net *net, struct sock *sk,
+               ip6_route_input(skb);
+               dst = skb_dst(skb);
+               if (!dst->error) {
++                      local_bh_disable();
+                       dst_cache_set_ip6(&slwt->cache, dst,
+                                         &ipv6_hdr(skb)->saddr);
++                      local_bh_enable();
+               }
++
++              err = skb_cow_head(skb, LL_RESERVED_SPACE(dst->dev));
++              if (unlikely(err))
++                      goto drop;
+       } else {
+               skb_dst_set(skb, dst);
+       }
+-      local_bh_enable();
+-
+-      err = skb_cow_head(skb, LL_RESERVED_SPACE(dst->dev));
+-      if (unlikely(err))
+-              goto drop;
+       if (static_branch_unlikely(&nf_hooks_lwtunnel_enabled))
+               return NF_HOOK(NFPROTO_IPV6, NF_INET_LOCAL_OUT,
+@@ -529,16 +548,16 @@ static int seg6_output_core(struct net *net, struct sock *sk,
+       struct seg6_lwt *slwt;
+       int err;
+-      err = seg6_do_srh(skb);
+-      if (unlikely(err))
+-              goto drop;
+-
+       slwt = seg6_lwt_lwtunnel(orig_dst->lwtstate);
+       local_bh_disable();
+       dst = dst_cache_get(&slwt->cache);
+       local_bh_enable();
++      err = seg6_do_srh(skb, dst);
++      if (unlikely(err))
++              goto drop;
++
+       if (unlikely(!dst)) {
+               struct ipv6hdr *hdr = ipv6_hdr(skb);
+               struct flowi6 fl6;
+@@ -560,15 +579,15 @@ static int seg6_output_core(struct net *net, struct sock *sk,
+               local_bh_disable();
+               dst_cache_set_ip6(&slwt->cache, dst, &fl6.saddr);
+               local_bh_enable();
++
++              err = skb_cow_head(skb, LL_RESERVED_SPACE(dst->dev));
++              if (unlikely(err))
++                      goto drop;
+       }
+       skb_dst_drop(skb);
+       skb_dst_set(skb, dst);
+-      err = skb_cow_head(skb, LL_RESERVED_SPACE(dst->dev));
+-      if (unlikely(err))
+-              goto drop;
+-
+       if (static_branch_unlikely(&nf_hooks_lwtunnel_enabled))
+               return NF_HOOK(NFPROTO_IPV6, NF_INET_LOCAL_OUT, net, sk, skb,
+                              NULL, skb_dst(skb)->dev, dst_output);
+-- 
+2.39.5
+
diff --git a/queue-5.15/net-loopback-avoid-sending-ip-packets-without-an-eth.patch b/queue-5.15/net-loopback-avoid-sending-ip-packets-without-an-eth.patch
new file mode 100644 (file)
index 0000000..aa7cd37
--- /dev/null
@@ -0,0 +1,94 @@
+From d3469638c4191258653e20fbdc73473fc26e5ea1 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Thu, 20 Feb 2025 09:25:59 +0200
+Subject: net: loopback: Avoid sending IP packets without an Ethernet header
+
+From: Ido Schimmel <idosch@nvidia.com>
+
+[ Upstream commit 0e4427f8f587c4b603475468bb3aee9418574893 ]
+
+After commit 22600596b675 ("ipv4: give an IPv4 dev to blackhole_netdev")
+IPv4 neighbors can be constructed on the blackhole net device, but they
+are constructed with an output function (neigh_direct_output()) that
+simply calls dev_queue_xmit(). The latter will transmit packets via
+'skb->dev' which might not be the blackhole net device if dst_dev_put()
+switched 'dst->dev' to the blackhole net device while another CPU was
+using the dst entry in ip_output(), but after it already initialized
+'skb->dev' from 'dst->dev'.
+
+Specifically, the following can happen:
+
+    CPU1                                      CPU2
+
+udp_sendmsg(sk1)                          udp_sendmsg(sk2)
+udp_send_skb()                            [...]
+ip_output()
+    skb->dev = skb_dst(skb)->dev
+                                          dst_dev_put()
+                                              dst->dev = blackhole_netdev
+ip_finish_output2()
+    resolves neigh on dst->dev
+neigh_output()
+neigh_direct_output()
+dev_queue_xmit()
+
+This will result in IPv4 packets being sent without an Ethernet header
+via a valid net device:
+
+tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
+listening on enp9s0, link-type EN10MB (Ethernet), snapshot length 262144 bytes
+22:07:02.329668 20:00:40:11:18:fb > 45:00:00:44:f4:94, ethertype Unknown
+(0x58c6), length 68:
+        0x0000:  8dda 74ca f1ae ca6c ca6c 0098 969c 0400  ..t....l.l......
+        0x0010:  0000 4730 3f18 6800 0000 0000 0000 9971  ..G0?.h........q
+        0x0020:  c4c9 9055 a157 0a70 9ead bf83 38ca ab38  ...U.W.p....8..8
+        0x0030:  8add ab96 e052                           .....R
+
+Fix by making sure that neighbors are constructed on top of the
+blackhole net device with an output function that simply consumes the
+packets, in a similar fashion to dst_discard_out() and
+blackhole_netdev_xmit().
+
+Fixes: 8d7017fd621d ("blackhole_netdev: use blackhole_netdev to invalidate dst entries")
+Fixes: 22600596b675 ("ipv4: give an IPv4 dev to blackhole_netdev")
+Reported-by: Florian Meister <fmei@sfs.com>
+Closes: https://lore.kernel.org/netdev/20250210084931.23a5c2e4@hermes.local/
+Signed-off-by: Ido Schimmel <idosch@nvidia.com>
+Reviewed-by: Eric Dumazet <edumazet@google.com>
+Link: https://patch.msgid.link/20250220072559.782296-1-idosch@nvidia.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/loopback.c | 14 ++++++++++++++
+ 1 file changed, 14 insertions(+)
+
+diff --git a/drivers/net/loopback.c b/drivers/net/loopback.c
+index 498e5c8013efb..0160a4f57ce92 100644
+--- a/drivers/net/loopback.c
++++ b/drivers/net/loopback.c
+@@ -243,8 +243,22 @@ static netdev_tx_t blackhole_netdev_xmit(struct sk_buff *skb,
+       return NETDEV_TX_OK;
+ }
++static int blackhole_neigh_output(struct neighbour *n, struct sk_buff *skb)
++{
++      kfree_skb(skb);
++      return 0;
++}
++
++static int blackhole_neigh_construct(struct net_device *dev,
++                                   struct neighbour *n)
++{
++      n->output = blackhole_neigh_output;
++      return 0;
++}
++
+ static const struct net_device_ops blackhole_netdev_ops = {
+       .ndo_start_xmit = blackhole_netdev_xmit,
++      .ndo_neigh_construct = blackhole_neigh_construct,
+ };
+ /* This is a dst-dummy device used specifically for invalidated
+-- 
+2.39.5
+
diff --git a/queue-5.15/net-mlx5-irq-fix-null-string-in-debug-print.patch b/queue-5.15/net-mlx5-irq-fix-null-string-in-debug-print.patch
new file mode 100644 (file)
index 0000000..f97c64d
--- /dev/null
@@ -0,0 +1,42 @@
+From 063419f3c06a90a4d4a63010fef6aca231923a8d Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Tue, 25 Feb 2025 09:26:08 +0200
+Subject: net/mlx5: IRQ, Fix null string in debug print
+
+From: Shay Drory <shayd@nvidia.com>
+
+[ Upstream commit 2f5a6014eb168a97b24153adccfa663d3b282767 ]
+
+irq_pool_alloc() debug print can print a null string.
+Fix it by providing a default string to print.
+
+Fixes: 71e084e26414 ("net/mlx5: Allocating a pool of MSI-X vectors for SFs")
+Signed-off-by: Shay Drory <shayd@nvidia.com>
+Reported-by: kernel test robot <lkp@intel.com>
+Closes: https://lore.kernel.org/oe-kbuild-all/202501141055.SwfIphN0-lkp@intel.com/
+Reviewed-by: Moshe Shemesh <moshe@nvidia.com>
+Signed-off-by: Tariq Toukan <tariqt@nvidia.com>
+Reviewed-by: Kalesh AP <kalesh-anakkur.purayil@broadcom.com>
+Link: https://patch.msgid.link/20250225072608.526866-4-tariqt@nvidia.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/mellanox/mlx5/core/pci_irq.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/net/ethernet/mellanox/mlx5/core/pci_irq.c b/drivers/net/ethernet/mellanox/mlx5/core/pci_irq.c
+index 2fa84556bc20e..4c78821f5edb3 100644
+--- a/drivers/net/ethernet/mellanox/mlx5/core/pci_irq.c
++++ b/drivers/net/ethernet/mellanox/mlx5/core/pci_irq.c
+@@ -474,7 +474,7 @@ irq_pool_alloc(struct mlx5_core_dev *dev, int start, int size, char *name,
+       pool->min_threshold = min_threshold * MLX5_EQ_REFS_PER_IRQ;
+       pool->max_threshold = max_threshold * MLX5_EQ_REFS_PER_IRQ;
+       mlx5_core_dbg(dev, "pool->name = %s, pool->size = %d, pool->start = %d",
+-                    name, size, start);
++                    name ? name : "mlx5_pcif_pool", size, start);
+       return pool;
+ }
+-- 
+2.39.5
+
diff --git a/queue-5.15/net-mvpp2-cls-fixed-non-ip-flow-with-vlan-tag-flow-d.patch b/queue-5.15/net-mvpp2-cls-fixed-non-ip-flow-with-vlan-tag-flow-d.patch
new file mode 100644 (file)
index 0000000..c523dfe
--- /dev/null
@@ -0,0 +1,40 @@
+From 5b71ef41ecd684a3e57325c3d4a1ef002fcdce33 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 24 Feb 2025 20:20:58 -0800
+Subject: net: mvpp2: cls: Fixed Non IP flow, with vlan tag flow defination.
+
+From: Harshal Chaudhari <hchaudhari@marvell.com>
+
+[ Upstream commit 2d253726ff7106b39a44483b6864398bba8a2f74 ]
+
+Non IP flow, with vlan tag not working as expected while
+running below command for vlan-priority. fixed that.
+
+ethtool -N eth1 flow-type ether vlan 0x8000 vlan-mask 0x1fff action 0 loc 0
+
+Fixes: 1274daede3ef ("net: mvpp2: cls: Add steering based on vlan Id and priority.")
+Signed-off-by: Harshal Chaudhari <hchaudhari@marvell.com>
+Reviewed-by: Maxime Chevallier <maxime.chevallier@bootlin.com>
+Link: https://patch.msgid.link/20250225042058.2643838-1-hchaudhari@marvell.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ drivers/net/ethernet/marvell/mvpp2/mvpp2_cls.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/net/ethernet/marvell/mvpp2/mvpp2_cls.c b/drivers/net/ethernet/marvell/mvpp2/mvpp2_cls.c
+index 40aeaa7bd739f..d2757cc116139 100644
+--- a/drivers/net/ethernet/marvell/mvpp2/mvpp2_cls.c
++++ b/drivers/net/ethernet/marvell/mvpp2/mvpp2_cls.c
+@@ -324,7 +324,7 @@ static const struct mvpp2_cls_flow cls_flows[MVPP2_N_PRS_FLOWS] = {
+                      MVPP2_PRS_RI_VLAN_MASK),
+       /* Non IP flow, with vlan tag */
+       MVPP2_DEF_FLOW(MVPP22_FLOW_ETHERNET, MVPP2_FL_NON_IP_TAG,
+-                     MVPP22_CLS_HEK_OPT_VLAN,
++                     MVPP22_CLS_HEK_TAGGED,
+                      0, 0),
+ };
+-- 
+2.39.5
+
diff --git a/queue-5.15/seg6-add-support-for-srv6-h.encaps.red-behavior.patch b/queue-5.15/seg6-add-support-for-srv6-h.encaps.red-behavior.patch
new file mode 100644 (file)
index 0000000..64e2202
--- /dev/null
@@ -0,0 +1,214 @@
+From 92b53ccdf21e19a30ec9707d97d1ae92f7e19b3a Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 27 Jul 2022 20:54:05 +0200
+Subject: seg6: add support for SRv6 H.Encaps.Red behavior
+
+From: Andrea Mayer <andrea.mayer@uniroma2.it>
+
+[ Upstream commit b07c8cdbe918aa17da864da9a89b22afaed0393e ]
+
+The SRv6 H.Encaps.Red behavior described in [1] is an optimization of
+the SRv6 H.Encaps behavior [2].
+
+H.Encaps.Red reduces the length of the SRH by excluding the first
+segment (SID) in the SRH of the pushed IPv6 header. The first SID is
+only placed in the IPv6 Destination Address field of the pushed IPv6
+header.
+When the SRv6 Policy only contains one SID the SRH is omitted, unless
+there is an HMAC TLV to be carried.
+
+[1] - https://datatracker.ietf.org/doc/html/rfc8986#section-5.2
+[2] - https://datatracker.ietf.org/doc/html/rfc8986#section-5.1
+
+Signed-off-by: Andrea Mayer <andrea.mayer@uniroma2.it>
+Signed-off-by: Anton Makarov <anton.makarov11235@gmail.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Stable-dep-of: c64a0727f9b1 ("net: ipv6: fix dst ref loop on input in seg6 lwt")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ include/uapi/linux/seg6_iptunnel.h |   1 +
+ net/ipv6/seg6_iptunnel.c           | 128 ++++++++++++++++++++++++++++-
+ 2 files changed, 128 insertions(+), 1 deletion(-)
+
+diff --git a/include/uapi/linux/seg6_iptunnel.h b/include/uapi/linux/seg6_iptunnel.h
+index eb815e0d0ac3e..538152a7b2c3f 100644
+--- a/include/uapi/linux/seg6_iptunnel.h
++++ b/include/uapi/linux/seg6_iptunnel.h
+@@ -35,6 +35,7 @@ enum {
+       SEG6_IPTUN_MODE_INLINE,
+       SEG6_IPTUN_MODE_ENCAP,
+       SEG6_IPTUN_MODE_L2ENCAP,
++      SEG6_IPTUN_MODE_ENCAP_RED,
+ };
+ #endif
+diff --git a/net/ipv6/seg6_iptunnel.c b/net/ipv6/seg6_iptunnel.c
+index 135712649d25f..0e4b11d190be3 100644
+--- a/net/ipv6/seg6_iptunnel.c
++++ b/net/ipv6/seg6_iptunnel.c
+@@ -36,6 +36,7 @@ static size_t seg6_lwt_headroom(struct seg6_iptunnel_encap *tuninfo)
+       case SEG6_IPTUN_MODE_INLINE:
+               break;
+       case SEG6_IPTUN_MODE_ENCAP:
++      case SEG6_IPTUN_MODE_ENCAP_RED:
+               head = sizeof(struct ipv6hdr);
+               break;
+       case SEG6_IPTUN_MODE_L2ENCAP:
+@@ -197,6 +198,124 @@ int seg6_do_srh_encap(struct sk_buff *skb, struct ipv6_sr_hdr *osrh, int proto)
+ }
+ EXPORT_SYMBOL_GPL(seg6_do_srh_encap);
++/* encapsulate an IPv6 packet within an outer IPv6 header with reduced SRH */
++static int seg6_do_srh_encap_red(struct sk_buff *skb,
++                               struct ipv6_sr_hdr *osrh, int proto)
++{
++      __u8 first_seg = osrh->first_segment;
++      struct dst_entry *dst = skb_dst(skb);
++      struct net *net = dev_net(dst->dev);
++      struct ipv6hdr *hdr, *inner_hdr;
++      int hdrlen = ipv6_optlen(osrh);
++      int red_tlv_offset, tlv_offset;
++      struct ipv6_sr_hdr *isrh;
++      bool skip_srh = false;
++      __be32 flowlabel;
++      int tot_len, err;
++      int red_hdrlen;
++      int tlvs_len;
++
++      if (first_seg > 0) {
++              red_hdrlen = hdrlen - sizeof(struct in6_addr);
++      } else {
++              /* NOTE: if tag/flags and/or other TLVs are introduced in the
++               * seg6_iptunnel infrastructure, they should be considered when
++               * deciding to skip the SRH.
++               */
++              skip_srh = !sr_has_hmac(osrh);
++
++              red_hdrlen = skip_srh ? 0 : hdrlen;
++      }
++
++      tot_len = red_hdrlen + sizeof(struct ipv6hdr);
++
++      err = skb_cow_head(skb, tot_len + skb->mac_len);
++      if (unlikely(err))
++              return err;
++
++      inner_hdr = ipv6_hdr(skb);
++      flowlabel = seg6_make_flowlabel(net, skb, inner_hdr);
++
++      skb_push(skb, tot_len);
++      skb_reset_network_header(skb);
++      skb_mac_header_rebuild(skb);
++      hdr = ipv6_hdr(skb);
++
++      /* based on seg6_do_srh_encap() */
++      if (skb->protocol == htons(ETH_P_IPV6)) {
++              ip6_flow_hdr(hdr, ip6_tclass(ip6_flowinfo(inner_hdr)),
++                           flowlabel);
++              hdr->hop_limit = inner_hdr->hop_limit;
++      } else {
++              ip6_flow_hdr(hdr, 0, flowlabel);
++              hdr->hop_limit = ip6_dst_hoplimit(skb_dst(skb));
++
++              memset(IP6CB(skb), 0, sizeof(*IP6CB(skb)));
++              IP6CB(skb)->iif = skb->skb_iif;
++      }
++
++      /* no matter if we have to skip the SRH or not, the first segment
++       * always comes in the pushed IPv6 header.
++       */
++      hdr->daddr = osrh->segments[first_seg];
++
++      if (skip_srh) {
++              hdr->nexthdr = proto;
++
++              set_tun_src(net, dst->dev, &hdr->daddr, &hdr->saddr);
++              goto out;
++      }
++
++      /* we cannot skip the SRH, slow path */
++
++      hdr->nexthdr = NEXTHDR_ROUTING;
++      isrh = (void *)hdr + sizeof(struct ipv6hdr);
++
++      if (unlikely(!first_seg)) {
++              /* this is a very rare case; we have only one SID but
++               * we cannot skip the SRH since we are carrying some
++               * other info.
++               */
++              memcpy(isrh, osrh, hdrlen);
++              goto srcaddr;
++      }
++
++      tlv_offset = sizeof(*osrh) + (first_seg + 1) * sizeof(struct in6_addr);
++      red_tlv_offset = tlv_offset - sizeof(struct in6_addr);
++
++      memcpy(isrh, osrh, red_tlv_offset);
++
++      tlvs_len = hdrlen - tlv_offset;
++      if (unlikely(tlvs_len > 0)) {
++              const void *s = (const void *)osrh + tlv_offset;
++              void *d = (void *)isrh + red_tlv_offset;
++
++              memcpy(d, s, tlvs_len);
++      }
++
++      --isrh->first_segment;
++      isrh->hdrlen -= 2;
++
++srcaddr:
++      isrh->nexthdr = proto;
++      set_tun_src(net, dst->dev, &hdr->daddr, &hdr->saddr);
++
++#ifdef CONFIG_IPV6_SEG6_HMAC
++      if (unlikely(!skip_srh && sr_has_hmac(isrh))) {
++              err = seg6_push_hmac(net, &hdr->saddr, isrh);
++              if (unlikely(err))
++                      return err;
++      }
++#endif
++
++out:
++      hdr->payload_len = htons(skb->len - sizeof(struct ipv6hdr));
++
++      skb_postpush_rcsum(skb, hdr, tot_len);
++
++      return 0;
++}
++
+ /* insert an SRH within an IPv6 packet, just after the IPv6 header */
+ int seg6_do_srh_inline(struct sk_buff *skb, struct ipv6_sr_hdr *osrh)
+ {
+@@ -269,6 +388,7 @@ static int seg6_do_srh(struct sk_buff *skb)
+                       return err;
+               break;
+       case SEG6_IPTUN_MODE_ENCAP:
++      case SEG6_IPTUN_MODE_ENCAP_RED:
+               err = iptunnel_handle_offloads(skb, SKB_GSO_IPXIP6);
+               if (err)
+                       return err;
+@@ -280,7 +400,11 @@ static int seg6_do_srh(struct sk_buff *skb)
+               else
+                       return -EINVAL;
+-              err = seg6_do_srh_encap(skb, tinfo->srh, proto);
++              if (tinfo->mode == SEG6_IPTUN_MODE_ENCAP)
++                      err = seg6_do_srh_encap(skb, tinfo->srh, proto);
++              else
++                      err = seg6_do_srh_encap_red(skb, tinfo->srh, proto);
++
+               if (err)
+                       return err;
+@@ -516,6 +640,8 @@ static int seg6_build_state(struct net *net, struct nlattr *nla,
+               break;
+       case SEG6_IPTUN_MODE_L2ENCAP:
+               break;
++      case SEG6_IPTUN_MODE_ENCAP_RED:
++              break;
+       default:
+               return -EINVAL;
+       }
+-- 
+2.39.5
+
diff --git a/queue-5.15/seg6-add-support-for-srv6-h.l2encaps.red-behavior.patch b/queue-5.15/seg6-add-support-for-srv6-h.l2encaps.red-behavior.patch
new file mode 100644 (file)
index 0000000..2af92f6
--- /dev/null
@@ -0,0 +1,91 @@
+From f3ff5cd2f12d6acb4bf7274c35dcb5da1a35a3d5 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 27 Jul 2022 20:54:06 +0200
+Subject: seg6: add support for SRv6 H.L2Encaps.Red behavior
+
+From: Andrea Mayer <andrea.mayer@uniroma2.it>
+
+[ Upstream commit 13f0296be8ece1189cbc4383a45ba97cafaecc09 ]
+
+The SRv6 H.L2Encaps.Red behavior described in [1] is an optimization of
+the SRv6 H.L2Encaps behavior [2].
+
+H.L2Encaps.Red reduces the length of the SRH by excluding the first
+segment (SID) in the SRH of the pushed IPv6 header. The first SID is
+only placed in the IPv6 Destination Address field of the pushed IPv6
+header.
+When the SRv6 Policy only contains one SID the SRH is omitted, unless
+there is an HMAC TLV to be carried.
+
+[1] - https://datatracker.ietf.org/doc/html/rfc8986#section-5.4
+[2] - https://datatracker.ietf.org/doc/html/rfc8986#section-5.3
+
+Signed-off-by: Andrea Mayer <andrea.mayer@uniroma2.it>
+Signed-off-by: Anton Makarov <anton.makarov11235@gmail.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Stable-dep-of: c64a0727f9b1 ("net: ipv6: fix dst ref loop on input in seg6 lwt")
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ include/uapi/linux/seg6_iptunnel.h |  1 +
+ net/ipv6/seg6_iptunnel.c           | 12 +++++++++++-
+ 2 files changed, 12 insertions(+), 1 deletion(-)
+
+diff --git a/include/uapi/linux/seg6_iptunnel.h b/include/uapi/linux/seg6_iptunnel.h
+index 538152a7b2c3f..a9fa777f16de4 100644
+--- a/include/uapi/linux/seg6_iptunnel.h
++++ b/include/uapi/linux/seg6_iptunnel.h
+@@ -36,6 +36,7 @@ enum {
+       SEG6_IPTUN_MODE_ENCAP,
+       SEG6_IPTUN_MODE_L2ENCAP,
+       SEG6_IPTUN_MODE_ENCAP_RED,
++      SEG6_IPTUN_MODE_L2ENCAP_RED,
+ };
+ #endif
+diff --git a/net/ipv6/seg6_iptunnel.c b/net/ipv6/seg6_iptunnel.c
+index 0e4b11d190be3..ae5299c277bcf 100644
+--- a/net/ipv6/seg6_iptunnel.c
++++ b/net/ipv6/seg6_iptunnel.c
+@@ -40,6 +40,7 @@ static size_t seg6_lwt_headroom(struct seg6_iptunnel_encap *tuninfo)
+               head = sizeof(struct ipv6hdr);
+               break;
+       case SEG6_IPTUN_MODE_L2ENCAP:
++      case SEG6_IPTUN_MODE_L2ENCAP_RED:
+               return 0;
+       }
+@@ -413,6 +414,7 @@ static int seg6_do_srh(struct sk_buff *skb)
+               skb->protocol = htons(ETH_P_IPV6);
+               break;
+       case SEG6_IPTUN_MODE_L2ENCAP:
++      case SEG6_IPTUN_MODE_L2ENCAP_RED:
+               if (!skb_mac_header_was_set(skb))
+                       return -EINVAL;
+@@ -422,7 +424,13 @@ static int seg6_do_srh(struct sk_buff *skb)
+               skb_mac_header_rebuild(skb);
+               skb_push(skb, skb->mac_len);
+-              err = seg6_do_srh_encap(skb, tinfo->srh, IPPROTO_ETHERNET);
++              if (tinfo->mode == SEG6_IPTUN_MODE_L2ENCAP)
++                      err = seg6_do_srh_encap(skb, tinfo->srh,
++                                              IPPROTO_ETHERNET);
++              else
++                      err = seg6_do_srh_encap_red(skb, tinfo->srh,
++                                                  IPPROTO_ETHERNET);
++
+               if (err)
+                       return err;
+@@ -642,6 +650,8 @@ static int seg6_build_state(struct net *net, struct nlattr *nla,
+               break;
+       case SEG6_IPTUN_MODE_ENCAP_RED:
+               break;
++      case SEG6_IPTUN_MODE_L2ENCAP_RED:
++              break;
+       default:
+               return -EINVAL;
+       }
+-- 
+2.39.5
+
index a2e0b1b2b4f853a5627755eb95a57c9c1910f147..810f84ba2c788673295703df2efa4b31b22c1810 100644 (file)
@@ -495,3 +495,22 @@ scsi-core-don-t-memset-the-entire-scsi_cmnd-in-scsi_.patch
 scsi-core-clear-driver-private-data-when-retrying-re.patch
 rdma-mlx5-fix-bind-qp-error-cleanup-flow.patch
 sunrpc-suppress-warnings-for-unused-procfs-functions.patch
+alsa-usb-audio-avoid-dropping-midi-events-at-closing.patch
+bluetooth-l2cap-fix-l2cap_ecred_conn_rsp-response.patch
+afs-remove-variable-nr_servers.patch
+afs-make-it-possible-to-find-the-volumes-that-are-us.patch
+afs-fix-the-server_list-to-unuse-a-displaced-server-.patch
+net-loopback-avoid-sending-ip-packets-without-an-eth.patch
+net-cadence-macb-synchronize-stats-calculations.patch
+asoc-es8328-fix-route-from-dac-to-output.patch
+ipvs-always-clear-ipvs_property-flag-in-skb_scrub_pa.patch
+tcp-defer-ts_recent-changes-until-req-is-owned.patch
+net-mvpp2-cls-fixed-non-ip-flow-with-vlan-tag-flow-d.patch
+net-mlx5-irq-fix-null-string-in-debug-print.patch
+seg6-add-support-for-srv6-h.encaps.red-behavior.patch
+seg6-add-support-for-srv6-h.l2encaps.red-behavior.patch
+include-net-add-static-inline-dst_dev_overhead-to-ds.patch
+net-ipv6-seg6_iptunnel-mitigate-2-realloc-issue.patch
+net-ipv6-fix-dst-ref-loop-on-input-in-seg6-lwt.patch
+net-ipv6-rpl_iptunnel-mitigate-2-realloc-issue.patch
+net-ipv6-fix-dst-ref-loop-on-input-in-rpl-lwt.patch
diff --git a/queue-5.15/tcp-defer-ts_recent-changes-until-req-is-owned.patch b/queue-5.15/tcp-defer-ts_recent-changes-until-req-is-owned.patch
new file mode 100644 (file)
index 0000000..146781a
--- /dev/null
@@ -0,0 +1,92 @@
+From 5c9f97761ebcddbf3088873543afbbe054ad2199 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Mon, 24 Feb 2025 17:00:47 +0800
+Subject: tcp: Defer ts_recent changes until req is owned
+
+From: Wang Hai <wanghai38@huawei.com>
+
+[ Upstream commit 8d52da23b6c68a0f6bad83959ebb61a2cf623c4e ]
+
+Recently a bug was discovered where the server had entered TCP_ESTABLISHED
+state, but the upper layers were not notified.
+
+The same 5-tuple packet may be processed by different CPUSs, so two
+CPUs may receive different ack packets at the same time when the
+state is TCP_NEW_SYN_RECV.
+
+In that case, req->ts_recent in tcp_check_req may be changed concurrently,
+which will probably cause the newsk's ts_recent to be incorrectly large.
+So that tcp_validate_incoming will fail. At this point, newsk will not be
+able to enter the TCP_ESTABLISHED.
+
+cpu1                                    cpu2
+tcp_check_req
+                                        tcp_check_req
+ req->ts_recent = rcv_tsval = t1
+                                         req->ts_recent = rcv_tsval = t2
+
+ syn_recv_sock
+  tcp_sk(child)->rx_opt.ts_recent = req->ts_recent = t2 // t1 < t2
+tcp_child_process
+ tcp_rcv_state_process
+  tcp_validate_incoming
+   tcp_paws_check
+    if ((s32)(rx_opt->ts_recent - rx_opt->rcv_tsval) <= paws_win)
+        // t2 - t1 > paws_win, failed
+                                        tcp_v4_do_rcv
+                                         tcp_rcv_state_process
+                                         // TCP_ESTABLISHED
+
+The cpu2's skb or a newly received skb will call tcp_v4_do_rcv to get
+the newsk into the TCP_ESTABLISHED state, but at this point it is no
+longer possible to notify the upper layer application. A notification
+mechanism could be added here, but the fix is more complex, so the
+current fix is used.
+
+In tcp_check_req, req->ts_recent is used to assign a value to
+tcp_sk(child)->rx_opt.ts_recent, so removing the change in req->ts_recent
+and changing tcp_sk(child)->rx_opt.ts_recent directly after owning the
+req fixes this bug.
+
+Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
+Signed-off-by: Wang Hai <wanghai38@huawei.com>
+Reviewed-by: Jason Xing <kerneljasonxing@gmail.com>
+Reviewed-by: Eric Dumazet <edumazet@google.com>
+Reviewed-by: Kuniyuki Iwashima <kuniyu@amazon.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/ipv4/tcp_minisocks.c | 10 ++++------
+ 1 file changed, 4 insertions(+), 6 deletions(-)
+
+diff --git a/net/ipv4/tcp_minisocks.c b/net/ipv4/tcp_minisocks.c
+index d84b71f70766b..061225d645e6b 100644
+--- a/net/ipv4/tcp_minisocks.c
++++ b/net/ipv4/tcp_minisocks.c
+@@ -725,12 +725,6 @@ struct sock *tcp_check_req(struct sock *sk, struct sk_buff *skb,
+       /* In sequence, PAWS is OK. */
+-      /* TODO: We probably should defer ts_recent change once
+-       * we take ownership of @req.
+-       */
+-      if (tmp_opt.saw_tstamp && !after(TCP_SKB_CB(skb)->seq, tcp_rsk(req)->rcv_nxt))
+-              WRITE_ONCE(req->ts_recent, tmp_opt.rcv_tsval);
+-
+       if (TCP_SKB_CB(skb)->seq == tcp_rsk(req)->rcv_isn) {
+               /* Truncate SYN, it is out of window starting
+                  at tcp_rsk(req)->rcv_isn + 1. */
+@@ -779,6 +773,10 @@ struct sock *tcp_check_req(struct sock *sk, struct sk_buff *skb,
+       if (!child)
+               goto listen_overflow;
++      if (own_req && tmp_opt.saw_tstamp &&
++          !after(TCP_SKB_CB(skb)->seq, tcp_rsk(req)->rcv_nxt))
++              tcp_sk(child)->rx_opt.ts_recent = tmp_opt.rcv_tsval;
++
+       if (own_req && rsk_drop_req(req)) {
+               reqsk_queue_removed(&inet_csk(req->rsk_listener)->icsk_accept_queue, req);
+               inet_csk_reqsk_queue_drop_and_put(req->rsk_listener, req);
+-- 
+2.39.5
+