The push_header() callback of a tunnel netdev class returns void, so a
tunnel implementation has no way to drop a packet it cannot
encapsulate.  Encrypting tunnels need this: for example, an IPsec ESP
tunnel must drop packets once its sequence number space is exhausted
instead of reusing a nonce.

Make push_header() return an errno value.  netdev_push_header() drops
packets for which it fails and counts them in the existing
'netdev_push_header_drops' coverage counter.  All existing
implementations always succeed.

Assisted-by: claude-opus-5-5, Claude Code
Signed-off-by: Thilak Raj Surendra Babu <[email protected]>
---
 lib/netdev-native-tnl.c | 20 +++++++++++++++-----
 lib/netdev-native-tnl.h | 10 +++++-----
 lib/netdev-provider.h   | 13 ++++++++-----
 lib/netdev.c            | 18 ++++++++++++------
 4 files changed, 40 insertions(+), 21 deletions(-)

diff --git a/lib/netdev-native-tnl.c b/lib/netdev-native-tnl.c
index f27b8b692..cf3989d1e 100644
--- a/lib/netdev-native-tnl.c
+++ b/lib/netdev-native-tnl.c
@@ -300,7 +300,7 @@ tnl_ol_pop(struct dp_packet *packet, int off)
     dp_packet_reset_packet(packet, off);
 }
 
-void
+int
 netdev_tnl_push_udp_header(const struct netdev *netdev OVS_UNUSED,
                            const struct netdev *ingress_netdev,
                            struct dp_packet *packet,
@@ -339,6 +339,8 @@ netdev_tnl_push_udp_header(const struct netdev *netdev 
OVS_UNUSED,
     if (l4_ofs != UINT16_MAX) {
         packet->inner_l4_ofs = l4_ofs + data->header_len;
     }
+
+    return 0;
 }
 
 static void *
@@ -535,7 +537,7 @@ err:
     return NULL;
 }
 
-void
+int
 netdev_gre_push_header(const struct netdev *netdev,
                        const struct netdev *ingress_netdev OVS_UNUSED,
                        struct dp_packet *packet,
@@ -577,6 +579,8 @@ netdev_gre_push_header(const struct netdev *netdev,
     if (l4_ofs != UINT16_MAX) {
         packet->inner_l4_ofs = l4_ofs + data->header_len;
     }
+
+    return 0;
 }
 
 int
@@ -699,7 +703,7 @@ err:
     return NULL;
 }
 
-void
+int
 netdev_erspan_push_header(const struct netdev *netdev,
                           const struct netdev *ingress_netdev OVS_UNUSED,
                           struct dp_packet *packet,
@@ -724,6 +728,8 @@ netdev_erspan_push_header(const struct netdev *netdev,
         md2 = ALIGNED_CAST(struct erspan_md2 *, ersh + 1);
         put_16aligned_be32(&md2->timestamp, get_erspan_ts(ERSPAN_100US));
     }
+
+    return 0;
 }
 
 int
@@ -873,7 +879,7 @@ err:
     return NULL;
 }
 
-void
+int
 netdev_gtpu_push_header(const struct netdev *netdev,
                         const struct netdev *ingress_netdev OVS_UNUSED,
                         struct dp_packet *packet,
@@ -907,6 +913,8 @@ netdev_gtpu_push_header(const struct netdev *netdev,
         payload_len += sizeof(struct gtpuhdr_opt);
     }
     gtpuh->len = htons(payload_len);
+
+    return 0;
 }
 
 int
@@ -1007,7 +1015,7 @@ netdev_srv6_build_header(const struct netdev *netdev,
     return 0;
 }
 
-void
+int
 netdev_srv6_push_header(const struct netdev *netdev OVS_UNUSED,
                         const struct netdev *ingress_netdev OVS_UNUSED,
                         struct dp_packet *packet,
@@ -1041,6 +1049,8 @@ netdev_srv6_push_header(const struct netdev *netdev 
OVS_UNUSED,
 
     netdev_tnl_push_ip_header(packet, data->header,
                               data->header_len, &ip_tot_size, ipv6_label);
+
+    return 0;
 }
 
 struct dp_packet *
diff --git a/lib/netdev-native-tnl.h b/lib/netdev-native-tnl.h
index ec1531d55..75430c765 100644
--- a/lib/netdev-native-tnl.h
+++ b/lib/netdev-native-tnl.h
@@ -33,7 +33,7 @@ netdev_gre_build_header(const struct netdev *netdev,
                         struct ovs_action_push_tnl *data,
                         const struct netdev_tnl_build_header_params *params);
 
-void
+int
 netdev_gre_push_header(const struct netdev *netdev,
                        const struct netdev *ingress_netdev,
                        struct dp_packet *packet,
@@ -46,7 +46,7 @@ netdev_erspan_build_header(const struct netdev *netdev,
                            struct ovs_action_push_tnl *data,
                            const struct netdev_tnl_build_header_params *p);
 
-void
+int
 netdev_erspan_push_header(const struct netdev *netdev,
                           const struct netdev *ingress_netdev,
                           struct dp_packet *packet,
@@ -57,7 +57,7 @@ netdev_erspan_pop_header(struct dp_packet *packet);
 struct dp_packet *
 netdev_gtpu_pop_header(struct dp_packet *packet);
 
-void
+int
 netdev_gtpu_push_header(const struct netdev *netdev,
                         const struct netdev *ingress_netdev,
                         struct dp_packet *packet,
@@ -70,7 +70,7 @@ netdev_gtpu_build_header(const struct netdev *netdev,
 
 struct dp_packet *netdev_srv6_pop_header(struct dp_packet *);
 
-void netdev_srv6_push_header(const struct netdev *,
+int netdev_srv6_push_header(const struct netdev *,
                              const struct netdev *ingress_netdev,
                              struct dp_packet *,
                              const struct ovs_action_push_tnl *);
@@ -79,7 +79,7 @@ int netdev_srv6_build_header(const struct netdev *,
                              struct ovs_action_push_tnl *,
                              const struct netdev_tnl_build_header_params *);
 
-void
+int
 netdev_tnl_push_udp_header(const struct netdev *netdev,
                            const struct netdev *ingress_netdev,
                            struct dp_packet *packet,
diff --git a/lib/netdev-provider.h b/lib/netdev-provider.h
index 8646f467d..4a2423a55 100644
--- a/lib/netdev-provider.h
+++ b/lib/netdev-provider.h
@@ -340,11 +340,14 @@ struct netdev_class {
      *
      * The 'ingress_netdev' points to the original ingress netdev for the
      * 'packet'.  This variable is valid only if hardware offload is enabled;
-     * otherwise, it will be NULL. */
-    void (*push_header)(const struct netdev *netdev,
-                        const struct netdev *ingress_netdev,
-                        struct dp_packet *packet,
-                        const struct ovs_action_push_tnl *data);
+     * otherwise, it will be NULL.
+     *
+     * Returns 0 if successful, otherwise a positive errno value.  On failure
+     * the caller drops 'packet'. */
+    int (*push_header)(const struct netdev *netdev,
+                       const struct netdev *ingress_netdev,
+                       struct dp_packet *packet,
+                       const struct ovs_action_push_tnl *data);
 
     /* Pop tunnel header from packet, build tunnel metadata and resize packet
      * for further processing.
diff --git a/lib/netdev.c b/lib/netdev.c
index 533c1eadf..ba7505122 100644
--- a/lib/netdev.c
+++ b/lib/netdev.c
@@ -916,12 +916,11 @@ netdev_push_header(const struct netdev *netdev,
                               || (data->tnl_type == OVS_VPORT_TYPE_VXLAN)
                               || (data->tnl_type == OVS_VPORT_TYPE_GRE)
                               || (data->tnl_type == OVS_VPORT_TYPE_IP6GRE);
+    size_t i, size = dp_packet_batch_size(batch);
     struct dp_packet *packet;
 
     if (userspace_tso_enabled()) {
         if (OVS_UNLIKELY(!supported_offloads)) {
-            size_t i, size = dp_packet_batch_size(batch);
-
             DP_PACKET_BATCH_REFILL_FOR_EACH (i, size, packet, batch) {
                 if (OVS_UNLIKELY(dp_packet_get_tso_segsz(packet))) {
                     COVERAGE_INC(netdev_push_header_drops);
@@ -935,7 +934,7 @@ netdev_push_header(const struct netdev *netdev,
                 dp_packet_batch_add(batch, packet);
             }
         } else {
-            DP_PACKET_BATCH_FOR_EACH (i, packet, batch) {
+            DP_PACKET_BATCH_FOR_EACH (j, packet, batch) {
                 if (dp_packet_tunnel(packet)
                     && dp_packet_get_tso_segsz(packet)) {
                     dp_packet_gso_batch(batch);
@@ -945,13 +944,20 @@ netdev_push_header(const struct netdev *netdev,
         }
     }
 
-    DP_PACKET_BATCH_FOR_EACH (i, packet, batch) {
+    size = dp_packet_batch_size(batch);
+    DP_PACKET_BATCH_REFILL_FOR_EACH (i, size, packet, batch) {
         if (!supported_offloads || dp_packet_tunnel(packet)) {
             dp_packet_ol_send_prepare(packet, 0);
         }
-        netdev->netdev_class->push_header(netdev, ingress_netdev, packet,
-                                          data);
+        if (OVS_UNLIKELY(netdev->netdev_class->push_header(netdev,
+                                                           ingress_netdev,
+                                                           packet, data))) {
+            COVERAGE_INC(netdev_push_header_drops);
+            dp_packet_delete(packet);
+            continue;
+        }
         pkt_metadata_init(&packet->md, data->out_port);
+        dp_packet_batch_add(batch, packet);
     }
 
     return 0;
-- 
2.43.0

_______________________________________________
dev mailing list
[email protected]
https://mail.openvswitch.org/mailman/listinfo/ovs-dev

Reply via email to