Skip to content

Commit 071c0fc

Browse files
jmberg-intelkuba-moo
authored andcommitted
net: extend drop reasons for multiple subsystems
Extend drop reasons to make them usable by subsystems other than core by reserving the high 16 bits for a new subsystem ID, of which 0 of course is used for the existing reasons immediately. To still be able to have string reasons, restructure that code a bit to make the loopup under RCU, the only user of this (right now) is drop_monitor. Link: https://lore.kernel.org/netdev/00659771ed54353f92027702c5bbb84702da62ce.camel@sipsolutions.net Signed-off-by: Johannes Berg <johannes.berg@intel.com> Signed-off-by: Jakub Kicinski <kuba@kernel.org>
1 parent 5b8285c commit 071c0fc

4 files changed

Lines changed: 121 additions & 16 deletions

File tree

include/net/dropreason-core.h

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -340,12 +340,20 @@ enum skb_drop_reason {
340340
*/
341341
SKB_DROP_REASON_IPV6_NDISC_NS_OTHERHOST,
342342
/**
343-
* @SKB_DROP_REASON_MAX: the maximum of drop reason, which shouldn't be
344-
* used as a real 'reason'
343+
* @SKB_DROP_REASON_MAX: the maximum of core drop reasons, which
344+
* shouldn't be used as a real 'reason' - only for tracing code gen
345345
*/
346346
SKB_DROP_REASON_MAX,
347+
348+
/**
349+
* @SKB_DROP_REASON_SUBSYS_MASK: subsystem mask in drop reasons,
350+
* see &enum skb_drop_reason_subsys
351+
*/
352+
SKB_DROP_REASON_SUBSYS_MASK = 0xffff0000,
347353
};
348354

355+
#define SKB_DROP_REASON_SUBSYS_SHIFT 16
356+
349357
#define SKB_DR_INIT(name, reason) \
350358
enum skb_drop_reason name = SKB_DROP_REASON_##reason
351359
#define SKB_DR(name) \
@@ -359,6 +367,4 @@ enum skb_drop_reason {
359367
SKB_DR_SET(name, reason); \
360368
} while (0)
361369

362-
extern const char * const drop_reasons[];
363-
364370
#endif

include/net/dropreason.h

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
/* SPDX-License-Identifier: GPL-2.0-or-later */
2+
3+
#ifndef _LINUX_DROPREASON_H
4+
#define _LINUX_DROPREASON_H
5+
#include <net/dropreason-core.h>
6+
7+
/**
8+
* enum skb_drop_reason_subsys - subsystem tag for (extended) drop reasons
9+
*/
10+
enum skb_drop_reason_subsys {
11+
/** @SKB_DROP_REASON_SUBSYS_CORE: core drop reasons defined above */
12+
SKB_DROP_REASON_SUBSYS_CORE,
13+
14+
/** @SKB_DROP_REASON_SUBSYS_NUM: number of subsystems defined */
15+
SKB_DROP_REASON_SUBSYS_NUM
16+
};
17+
18+
struct drop_reason_list {
19+
const char * const *reasons;
20+
size_t n_reasons;
21+
};
22+
23+
/* Note: due to dynamic registrations, access must be under RCU */
24+
extern const struct drop_reason_list __rcu *
25+
drop_reasons_by_subsys[SKB_DROP_REASON_SUBSYS_NUM];
26+
27+
void drop_reasons_register_subsys(enum skb_drop_reason_subsys subsys,
28+
const struct drop_reason_list *list);
29+
void drop_reasons_unregister_subsys(enum skb_drop_reason_subsys subsys);
30+
31+
#endif

net/core/drop_monitor.c

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include <linux/workqueue.h>
2222
#include <linux/netlink.h>
2323
#include <linux/net_dropmon.h>
24+
#include <linux/bitfield.h>
2425
#include <linux/percpu.h>
2526
#include <linux/timer.h>
2627
#include <linux/bitops.h>
@@ -29,6 +30,7 @@
2930
#include <net/genetlink.h>
3031
#include <net/netevent.h>
3132
#include <net/flow_offload.h>
33+
#include <net/dropreason.h>
3234
#include <net/devlink.h>
3335

3436
#include <trace/events/skb.h>
@@ -504,8 +506,6 @@ static void net_dm_packet_trace_kfree_skb_hit(void *ignore,
504506
if (!nskb)
505507
return;
506508

507-
if (unlikely(reason >= SKB_DROP_REASON_MAX || reason <= 0))
508-
reason = SKB_DROP_REASON_NOT_SPECIFIED;
509509
cb = NET_DM_SKB_CB(nskb);
510510
cb->reason = reason;
511511
cb->pc = location;
@@ -552,9 +552,9 @@ static size_t net_dm_in_port_size(void)
552552
}
553553

554554
#define NET_DM_MAX_SYMBOL_LEN 40
555+
#define NET_DM_MAX_REASON_LEN 50
555556

556-
static size_t net_dm_packet_report_size(size_t payload_len,
557-
enum skb_drop_reason reason)
557+
static size_t net_dm_packet_report_size(size_t payload_len)
558558
{
559559
size_t size;
560560

@@ -576,7 +576,7 @@ static size_t net_dm_packet_report_size(size_t payload_len,
576576
/* NET_DM_ATTR_PROTO */
577577
nla_total_size(sizeof(u16)) +
578578
/* NET_DM_ATTR_REASON */
579-
nla_total_size(strlen(drop_reasons[reason]) + 1) +
579+
nla_total_size(NET_DM_MAX_REASON_LEN + 1) +
580580
/* NET_DM_ATTR_PAYLOAD */
581581
nla_total_size(payload_len);
582582
}
@@ -610,6 +610,8 @@ static int net_dm_packet_report_fill(struct sk_buff *msg, struct sk_buff *skb,
610610
size_t payload_len)
611611
{
612612
struct net_dm_skb_cb *cb = NET_DM_SKB_CB(skb);
613+
const struct drop_reason_list *list = NULL;
614+
unsigned int subsys, subsys_reason;
613615
char buf[NET_DM_MAX_SYMBOL_LEN];
614616
struct nlattr *attr;
615617
void *hdr;
@@ -627,9 +629,24 @@ static int net_dm_packet_report_fill(struct sk_buff *msg, struct sk_buff *skb,
627629
NET_DM_ATTR_PAD))
628630
goto nla_put_failure;
629631

632+
rcu_read_lock();
633+
subsys = u32_get_bits(cb->reason, SKB_DROP_REASON_SUBSYS_MASK);
634+
if (subsys < SKB_DROP_REASON_SUBSYS_NUM)
635+
list = rcu_dereference(drop_reasons_by_subsys[subsys]);
636+
subsys_reason = cb->reason & ~SKB_DROP_REASON_SUBSYS_MASK;
637+
if (!list ||
638+
subsys_reason >= list->n_reasons ||
639+
!list->reasons[subsys_reason] ||
640+
strlen(list->reasons[subsys_reason]) > NET_DM_MAX_REASON_LEN) {
641+
list = rcu_dereference(drop_reasons_by_subsys[SKB_DROP_REASON_SUBSYS_CORE]);
642+
subsys_reason = SKB_DROP_REASON_NOT_SPECIFIED;
643+
}
630644
if (nla_put_string(msg, NET_DM_ATTR_REASON,
631-
drop_reasons[cb->reason]))
645+
list->reasons[subsys_reason])) {
646+
rcu_read_unlock();
632647
goto nla_put_failure;
648+
}
649+
rcu_read_unlock();
633650

634651
snprintf(buf, sizeof(buf), "%pS", cb->pc);
635652
if (nla_put_string(msg, NET_DM_ATTR_SYMBOL, buf))
@@ -687,9 +704,7 @@ static void net_dm_packet_report(struct sk_buff *skb)
687704
if (net_dm_trunc_len)
688705
payload_len = min_t(size_t, net_dm_trunc_len, payload_len);
689706

690-
msg = nlmsg_new(net_dm_packet_report_size(payload_len,
691-
NET_DM_SKB_CB(skb)->reason),
692-
GFP_KERNEL);
707+
msg = nlmsg_new(net_dm_packet_report_size(payload_len), GFP_KERNEL);
693708
if (!msg)
694709
goto out;
695710

net/core/skbuff.c

Lines changed: 56 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@
5858
#include <linux/scatterlist.h>
5959
#include <linux/errqueue.h>
6060
#include <linux/prefetch.h>
61+
#include <linux/bitfield.h>
6162
#include <linux/if_vlan.h>
6263
#include <linux/mpls.h>
6364
#include <linux/kcov.h>
@@ -72,6 +73,7 @@
7273
#include <net/mptcp.h>
7374
#include <net/mctp.h>
7475
#include <net/page_pool.h>
76+
#include <net/dropreason.h>
7577

7678
#include <linux/uaccess.h>
7779
#include <trace/events/skb.h>
@@ -122,11 +124,59 @@ EXPORT_SYMBOL(sysctl_max_skb_frags);
122124

123125
#undef FN
124126
#define FN(reason) [SKB_DROP_REASON_##reason] = #reason,
125-
const char * const drop_reasons[] = {
127+
static const char * const drop_reasons[] = {
126128
[SKB_CONSUMED] = "CONSUMED",
127129
DEFINE_DROP_REASON(FN, FN)
128130
};
129-
EXPORT_SYMBOL(drop_reasons);
131+
132+
static const struct drop_reason_list drop_reasons_core = {
133+
.reasons = drop_reasons,
134+
.n_reasons = ARRAY_SIZE(drop_reasons),
135+
};
136+
137+
const struct drop_reason_list __rcu *
138+
drop_reasons_by_subsys[SKB_DROP_REASON_SUBSYS_NUM] = {
139+
[SKB_DROP_REASON_SUBSYS_CORE] = RCU_INITIALIZER(&drop_reasons_core),
140+
};
141+
EXPORT_SYMBOL(drop_reasons_by_subsys);
142+
143+
/**
144+
* drop_reasons_register_subsys - register another drop reason subsystem
145+
* @subsys: the subsystem to register, must not be the core
146+
* @list: the list of drop reasons within the subsystem, must point to
147+
* a statically initialized list
148+
*/
149+
void drop_reasons_register_subsys(enum skb_drop_reason_subsys subsys,
150+
const struct drop_reason_list *list)
151+
{
152+
if (WARN(subsys <= SKB_DROP_REASON_SUBSYS_CORE ||
153+
subsys >= ARRAY_SIZE(drop_reasons_by_subsys),
154+
"invalid subsystem %d\n", subsys))
155+
return;
156+
157+
/* must point to statically allocated memory, so INIT is OK */
158+
RCU_INIT_POINTER(drop_reasons_by_subsys[subsys], list);
159+
}
160+
EXPORT_SYMBOL_GPL(drop_reasons_register_subsys);
161+
162+
/**
163+
* drop_reasons_unregister_subsys - unregister a drop reason subsystem
164+
* @subsys: the subsystem to remove, must not be the core
165+
*
166+
* Note: This will synchronize_rcu() to ensure no users when it returns.
167+
*/
168+
void drop_reasons_unregister_subsys(enum skb_drop_reason_subsys subsys)
169+
{
170+
if (WARN(subsys <= SKB_DROP_REASON_SUBSYS_CORE ||
171+
subsys >= ARRAY_SIZE(drop_reasons_by_subsys),
172+
"invalid subsystem %d\n", subsys))
173+
return;
174+
175+
RCU_INIT_POINTER(drop_reasons_by_subsys[subsys], NULL);
176+
177+
synchronize_rcu();
178+
}
179+
EXPORT_SYMBOL_GPL(drop_reasons_unregister_subsys);
130180

131181
/**
132182
* skb_panic - private function for out-of-line support
@@ -986,7 +1036,10 @@ bool __kfree_skb_reason(struct sk_buff *skb, enum skb_drop_reason reason)
9861036
if (unlikely(!skb_unref(skb)))
9871037
return false;
9881038

989-
DEBUG_NET_WARN_ON_ONCE(reason <= 0 || reason >= SKB_DROP_REASON_MAX);
1039+
DEBUG_NET_WARN_ON_ONCE(reason == SKB_NOT_DROPPED_YET ||
1040+
u32_get_bits(reason,
1041+
SKB_DROP_REASON_SUBSYS_MASK) >=
1042+
SKB_DROP_REASON_SUBSYS_NUM);
9901043

9911044
if (reason == SKB_CONSUMED)
9921045
trace_consume_skb(skb, __builtin_return_address(0));

0 commit comments

Comments
 (0)