]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
net: bridge: add skb drop reasons to the most common drop points
authorRadu Rendec <rrendec@redhat.com>
Thu, 19 Dec 2024 16:36:06 +0000 (11:36 -0500)
committerJakub Kicinski <kuba@kernel.org>
Mon, 23 Dec 2024 18:11:04 +0000 (10:11 -0800)
The bridge input code may drop frames for various reasons and at various
points in the ingress handling logic. Currently kfree_skb() is used
everywhere, and therefore no drop reason is specified. Add drop reasons
to the most common drop points.

Drop reasons are not added exhaustively to the entire bridge code. The
intention is to incrementally add drop reasons to the rest of the bridge
code in follow up patches.

Signed-off-by: Radu Rendec <rrendec@redhat.com>
Reviewed-by: Ido Schimmel <idosch@nvidia.com>
Acked-by: Nikolay Aleksandrov <razor@blackwall.org>
Link: https://patch.msgid.link/20241219163606.717758-3-rrendec@redhat.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
include/net/dropreason-core.h
net/bridge/br_forward.c
net/bridge/br_input.c

index 6e32106d722949042a4b4d6e561f58ed91332df9..3a6602f379783078388eaaad3a9237b11baad534 100644 (file)
        FN(TUNNEL_TXINFO)               \
        FN(LOCAL_MAC)                   \
        FN(ARP_PVLAN_DISABLE)           \
+       FN(MAC_IEEE_MAC_CONTROL)        \
+       FN(BRIDGE_INGRESS_STP_STATE)    \
        FNe(MAX)
 
 /**
@@ -520,6 +522,16 @@ enum skb_drop_reason {
         * enabled.
         */
        SKB_DROP_REASON_ARP_PVLAN_DISABLE,
+       /**
+        * @SKB_DROP_REASON_MAC_IEEE_MAC_CONTROL: the destination MAC address
+        * is an IEEE MAC Control address.
+        */
+       SKB_DROP_REASON_MAC_IEEE_MAC_CONTROL,
+       /**
+        * @SKB_DROP_REASON_BRIDGE_INGRESS_STP_STATE: the STP state of the
+        * ingress bridge port does not allow frames to be forwarded.
+        */
+       SKB_DROP_REASON_BRIDGE_INGRESS_STP_STATE,
        /**
         * @SKB_DROP_REASON_MAX: the maximum of core drop reasons, which
         * shouldn't be used as a real 'reason' - only for tracing code gen
index e19b583ff2c6d077ec2b2b6439a5ef6f68ef0956..29097e984b4f7501a17d99da258a331dada1fbae 100644 (file)
@@ -201,6 +201,7 @@ void br_flood(struct net_bridge *br, struct sk_buff *skb,
              enum br_pkt_type pkt_type, bool local_rcv, bool local_orig,
              u16 vid)
 {
+       enum skb_drop_reason reason = SKB_DROP_REASON_NO_TX_TARGET;
        struct net_bridge_port *prev = NULL;
        struct net_bridge_port *p;
 
@@ -234,8 +235,11 @@ void br_flood(struct net_bridge *br, struct sk_buff *skb,
                        continue;
 
                prev = maybe_deliver(prev, p, skb, local_orig);
-               if (IS_ERR(prev))
+               if (IS_ERR(prev)) {
+                       reason = PTR_ERR(prev) == -ENOMEM ? SKB_DROP_REASON_NOMEM :
+                                SKB_DROP_REASON_NOT_SPECIFIED;
                        goto out;
+               }
        }
 
        if (!prev)
@@ -249,7 +253,7 @@ void br_flood(struct net_bridge *br, struct sk_buff *skb,
 
 out:
        if (!local_rcv)
-               kfree_skb(skb);
+               kfree_skb_reason(skb, reason);
 }
 
 #ifdef CONFIG_BRIDGE_IGMP_SNOOPING
@@ -289,6 +293,7 @@ void br_multicast_flood(struct net_bridge_mdb_entry *mdst,
                        struct net_bridge_mcast *brmctx,
                        bool local_rcv, bool local_orig)
 {
+       enum skb_drop_reason reason = SKB_DROP_REASON_NO_TX_TARGET;
        struct net_bridge_port *prev = NULL;
        struct net_bridge_port_group *p;
        bool allow_mode_include = true;
@@ -329,8 +334,11 @@ void br_multicast_flood(struct net_bridge_mdb_entry *mdst,
                }
 
                prev = maybe_deliver(prev, port, skb, local_orig);
-               if (IS_ERR(prev))
+               if (IS_ERR(prev)) {
+                       reason = PTR_ERR(prev) == -ENOMEM ? SKB_DROP_REASON_NOMEM :
+                                SKB_DROP_REASON_NOT_SPECIFIED;
                        goto out;
+               }
 delivered:
                if ((unsigned long)lport >= (unsigned long)port)
                        p = rcu_dereference(p->next);
@@ -349,6 +357,6 @@ delivered:
 
 out:
        if (!local_rcv)
-               kfree_skb(skb);
+               kfree_skb_reason(skb, reason);
 }
 #endif
index ceaa5a89b947fc574ee2a05003db3de7cc9797b1..232133a0fd21c61ac92d00bc8792bbc8802bb391 100644 (file)
@@ -75,6 +75,7 @@ static int br_pass_frame_up(struct sk_buff *skb, bool promisc)
 /* note: already called with rcu_read_lock */
 int br_handle_frame_finish(struct net *net, struct sock *sk, struct sk_buff *skb)
 {
+       enum skb_drop_reason reason = SKB_DROP_REASON_NOT_SPECIFIED;
        struct net_bridge_port *p = br_port_get_rcu(skb->dev);
        enum br_pkt_type pkt_type = BR_PKT_UNICAST;
        struct net_bridge_fdb_entry *dst = NULL;
@@ -96,8 +97,10 @@ int br_handle_frame_finish(struct net *net, struct sock *sk, struct sk_buff *skb
        if (br_mst_is_enabled(br)) {
                state = BR_STATE_FORWARDING;
        } else {
-               if (p->state == BR_STATE_DISABLED)
+               if (p->state == BR_STATE_DISABLED) {
+                       reason = SKB_DROP_REASON_BRIDGE_INGRESS_STP_STATE;
                        goto drop;
+               }
 
                state = p->state;
        }
@@ -155,8 +158,10 @@ int br_handle_frame_finish(struct net *net, struct sock *sk, struct sk_buff *skb
                }
        }
 
-       if (state == BR_STATE_LEARNING)
+       if (state == BR_STATE_LEARNING) {
+               reason = SKB_DROP_REASON_BRIDGE_INGRESS_STP_STATE;
                goto drop;
+       }
 
        BR_INPUT_SKB_CB(skb)->brdev = br->dev;
        BR_INPUT_SKB_CB(skb)->src_port_isolated = !!(p->flags & BR_ISOLATED);
@@ -223,7 +228,7 @@ int br_handle_frame_finish(struct net *net, struct sock *sk, struct sk_buff *skb
 out:
        return 0;
 drop:
-       kfree_skb(skb);
+       kfree_skb_reason(skb, reason);
        goto out;
 }
 EXPORT_SYMBOL_GPL(br_handle_frame_finish);
@@ -324,6 +329,7 @@ static int br_process_frame_type(struct net_bridge_port *p,
  */
 static rx_handler_result_t br_handle_frame(struct sk_buff **pskb)
 {
+       enum skb_drop_reason reason = SKB_DROP_REASON_NOT_SPECIFIED;
        struct net_bridge_port *p;
        struct sk_buff *skb = *pskb;
        const unsigned char *dest = eth_hdr(skb)->h_dest;
@@ -331,8 +337,10 @@ static rx_handler_result_t br_handle_frame(struct sk_buff **pskb)
        if (unlikely(skb->pkt_type == PACKET_LOOPBACK))
                return RX_HANDLER_PASS;
 
-       if (!is_valid_ether_addr(eth_hdr(skb)->h_source))
+       if (!is_valid_ether_addr(eth_hdr(skb)->h_source)) {
+               reason = SKB_DROP_REASON_MAC_INVALID_SOURCE;
                goto drop;
+       }
 
        skb = skb_share_check(skb, GFP_ATOMIC);
        if (!skb)
@@ -374,6 +382,7 @@ static rx_handler_result_t br_handle_frame(struct sk_buff **pskb)
                        return RX_HANDLER_PASS;
 
                case 0x01:      /* IEEE MAC (Pause) */
+                       reason = SKB_DROP_REASON_MAC_IEEE_MAC_CONTROL;
                        goto drop;
 
                case 0x0E:      /* 802.1AB LLDP */
@@ -423,8 +432,9 @@ defer_stp_filtering:
 
                return nf_hook_bridge_pre(skb, pskb);
        default:
+               reason = SKB_DROP_REASON_BRIDGE_INGRESS_STP_STATE;
 drop:
-               kfree_skb(skb);
+               kfree_skb_reason(skb, reason);
        }
        return RX_HANDLER_CONSUMED;
 }