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>
This commit is contained in:
parent
5b8285cca6
commit
071c0fc6fb
|
@ -340,12 +340,20 @@ enum skb_drop_reason {
|
|||
*/
|
||||
SKB_DROP_REASON_IPV6_NDISC_NS_OTHERHOST,
|
||||
/**
|
||||
* @SKB_DROP_REASON_MAX: the maximum of drop reason, which shouldn't be
|
||||
* used as a real 'reason'
|
||||
* @SKB_DROP_REASON_MAX: the maximum of core drop reasons, which
|
||||
* shouldn't be used as a real 'reason' - only for tracing code gen
|
||||
*/
|
||||
SKB_DROP_REASON_MAX,
|
||||
|
||||
/**
|
||||
* @SKB_DROP_REASON_SUBSYS_MASK: subsystem mask in drop reasons,
|
||||
* see &enum skb_drop_reason_subsys
|
||||
*/
|
||||
SKB_DROP_REASON_SUBSYS_MASK = 0xffff0000,
|
||||
};
|
||||
|
||||
#define SKB_DROP_REASON_SUBSYS_SHIFT 16
|
||||
|
||||
#define SKB_DR_INIT(name, reason) \
|
||||
enum skb_drop_reason name = SKB_DROP_REASON_##reason
|
||||
#define SKB_DR(name) \
|
||||
|
@ -359,6 +367,4 @@ enum skb_drop_reason {
|
|||
SKB_DR_SET(name, reason); \
|
||||
} while (0)
|
||||
|
||||
extern const char * const drop_reasons[];
|
||||
|
||||
#endif
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#ifndef _LINUX_DROPREASON_H
|
||||
#define _LINUX_DROPREASON_H
|
||||
#include <net/dropreason-core.h>
|
||||
|
||||
/**
|
||||
* enum skb_drop_reason_subsys - subsystem tag for (extended) drop reasons
|
||||
*/
|
||||
enum skb_drop_reason_subsys {
|
||||
/** @SKB_DROP_REASON_SUBSYS_CORE: core drop reasons defined above */
|
||||
SKB_DROP_REASON_SUBSYS_CORE,
|
||||
|
||||
/** @SKB_DROP_REASON_SUBSYS_NUM: number of subsystems defined */
|
||||
SKB_DROP_REASON_SUBSYS_NUM
|
||||
};
|
||||
|
||||
struct drop_reason_list {
|
||||
const char * const *reasons;
|
||||
size_t n_reasons;
|
||||
};
|
||||
|
||||
/* Note: due to dynamic registrations, access must be under RCU */
|
||||
extern const struct drop_reason_list __rcu *
|
||||
drop_reasons_by_subsys[SKB_DROP_REASON_SUBSYS_NUM];
|
||||
|
||||
void drop_reasons_register_subsys(enum skb_drop_reason_subsys subsys,
|
||||
const struct drop_reason_list *list);
|
||||
void drop_reasons_unregister_subsys(enum skb_drop_reason_subsys subsys);
|
||||
|
||||
#endif
|
|
@ -21,6 +21,7 @@
|
|||
#include <linux/workqueue.h>
|
||||
#include <linux/netlink.h>
|
||||
#include <linux/net_dropmon.h>
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/percpu.h>
|
||||
#include <linux/timer.h>
|
||||
#include <linux/bitops.h>
|
||||
|
@ -29,6 +30,7 @@
|
|||
#include <net/genetlink.h>
|
||||
#include <net/netevent.h>
|
||||
#include <net/flow_offload.h>
|
||||
#include <net/dropreason.h>
|
||||
#include <net/devlink.h>
|
||||
|
||||
#include <trace/events/skb.h>
|
||||
|
@ -504,8 +506,6 @@ static void net_dm_packet_trace_kfree_skb_hit(void *ignore,
|
|||
if (!nskb)
|
||||
return;
|
||||
|
||||
if (unlikely(reason >= SKB_DROP_REASON_MAX || reason <= 0))
|
||||
reason = SKB_DROP_REASON_NOT_SPECIFIED;
|
||||
cb = NET_DM_SKB_CB(nskb);
|
||||
cb->reason = reason;
|
||||
cb->pc = location;
|
||||
|
@ -552,9 +552,9 @@ static size_t net_dm_in_port_size(void)
|
|||
}
|
||||
|
||||
#define NET_DM_MAX_SYMBOL_LEN 40
|
||||
#define NET_DM_MAX_REASON_LEN 50
|
||||
|
||||
static size_t net_dm_packet_report_size(size_t payload_len,
|
||||
enum skb_drop_reason reason)
|
||||
static size_t net_dm_packet_report_size(size_t payload_len)
|
||||
{
|
||||
size_t size;
|
||||
|
||||
|
@ -576,7 +576,7 @@ static size_t net_dm_packet_report_size(size_t payload_len,
|
|||
/* NET_DM_ATTR_PROTO */
|
||||
nla_total_size(sizeof(u16)) +
|
||||
/* NET_DM_ATTR_REASON */
|
||||
nla_total_size(strlen(drop_reasons[reason]) + 1) +
|
||||
nla_total_size(NET_DM_MAX_REASON_LEN + 1) +
|
||||
/* NET_DM_ATTR_PAYLOAD */
|
||||
nla_total_size(payload_len);
|
||||
}
|
||||
|
@ -610,6 +610,8 @@ static int net_dm_packet_report_fill(struct sk_buff *msg, struct sk_buff *skb,
|
|||
size_t payload_len)
|
||||
{
|
||||
struct net_dm_skb_cb *cb = NET_DM_SKB_CB(skb);
|
||||
const struct drop_reason_list *list = NULL;
|
||||
unsigned int subsys, subsys_reason;
|
||||
char buf[NET_DM_MAX_SYMBOL_LEN];
|
||||
struct nlattr *attr;
|
||||
void *hdr;
|
||||
|
@ -627,9 +629,24 @@ static int net_dm_packet_report_fill(struct sk_buff *msg, struct sk_buff *skb,
|
|||
NET_DM_ATTR_PAD))
|
||||
goto nla_put_failure;
|
||||
|
||||
rcu_read_lock();
|
||||
subsys = u32_get_bits(cb->reason, SKB_DROP_REASON_SUBSYS_MASK);
|
||||
if (subsys < SKB_DROP_REASON_SUBSYS_NUM)
|
||||
list = rcu_dereference(drop_reasons_by_subsys[subsys]);
|
||||
subsys_reason = cb->reason & ~SKB_DROP_REASON_SUBSYS_MASK;
|
||||
if (!list ||
|
||||
subsys_reason >= list->n_reasons ||
|
||||
!list->reasons[subsys_reason] ||
|
||||
strlen(list->reasons[subsys_reason]) > NET_DM_MAX_REASON_LEN) {
|
||||
list = rcu_dereference(drop_reasons_by_subsys[SKB_DROP_REASON_SUBSYS_CORE]);
|
||||
subsys_reason = SKB_DROP_REASON_NOT_SPECIFIED;
|
||||
}
|
||||
if (nla_put_string(msg, NET_DM_ATTR_REASON,
|
||||
drop_reasons[cb->reason]))
|
||||
list->reasons[subsys_reason])) {
|
||||
rcu_read_unlock();
|
||||
goto nla_put_failure;
|
||||
}
|
||||
rcu_read_unlock();
|
||||
|
||||
snprintf(buf, sizeof(buf), "%pS", cb->pc);
|
||||
if (nla_put_string(msg, NET_DM_ATTR_SYMBOL, buf))
|
||||
|
@ -687,9 +704,7 @@ static void net_dm_packet_report(struct sk_buff *skb)
|
|||
if (net_dm_trunc_len)
|
||||
payload_len = min_t(size_t, net_dm_trunc_len, payload_len);
|
||||
|
||||
msg = nlmsg_new(net_dm_packet_report_size(payload_len,
|
||||
NET_DM_SKB_CB(skb)->reason),
|
||||
GFP_KERNEL);
|
||||
msg = nlmsg_new(net_dm_packet_report_size(payload_len), GFP_KERNEL);
|
||||
if (!msg)
|
||||
goto out;
|
||||
|
||||
|
|
|
@ -58,6 +58,7 @@
|
|||
#include <linux/scatterlist.h>
|
||||
#include <linux/errqueue.h>
|
||||
#include <linux/prefetch.h>
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/if_vlan.h>
|
||||
#include <linux/mpls.h>
|
||||
#include <linux/kcov.h>
|
||||
|
@ -72,6 +73,7 @@
|
|||
#include <net/mptcp.h>
|
||||
#include <net/mctp.h>
|
||||
#include <net/page_pool.h>
|
||||
#include <net/dropreason.h>
|
||||
|
||||
#include <linux/uaccess.h>
|
||||
#include <trace/events/skb.h>
|
||||
|
@ -122,11 +124,59 @@ EXPORT_SYMBOL(sysctl_max_skb_frags);
|
|||
|
||||
#undef FN
|
||||
#define FN(reason) [SKB_DROP_REASON_##reason] = #reason,
|
||||
const char * const drop_reasons[] = {
|
||||
static const char * const drop_reasons[] = {
|
||||
[SKB_CONSUMED] = "CONSUMED",
|
||||
DEFINE_DROP_REASON(FN, FN)
|
||||
};
|
||||
EXPORT_SYMBOL(drop_reasons);
|
||||
|
||||
static const struct drop_reason_list drop_reasons_core = {
|
||||
.reasons = drop_reasons,
|
||||
.n_reasons = ARRAY_SIZE(drop_reasons),
|
||||
};
|
||||
|
||||
const struct drop_reason_list __rcu *
|
||||
drop_reasons_by_subsys[SKB_DROP_REASON_SUBSYS_NUM] = {
|
||||
[SKB_DROP_REASON_SUBSYS_CORE] = RCU_INITIALIZER(&drop_reasons_core),
|
||||
};
|
||||
EXPORT_SYMBOL(drop_reasons_by_subsys);
|
||||
|
||||
/**
|
||||
* drop_reasons_register_subsys - register another drop reason subsystem
|
||||
* @subsys: the subsystem to register, must not be the core
|
||||
* @list: the list of drop reasons within the subsystem, must point to
|
||||
* a statically initialized list
|
||||
*/
|
||||
void drop_reasons_register_subsys(enum skb_drop_reason_subsys subsys,
|
||||
const struct drop_reason_list *list)
|
||||
{
|
||||
if (WARN(subsys <= SKB_DROP_REASON_SUBSYS_CORE ||
|
||||
subsys >= ARRAY_SIZE(drop_reasons_by_subsys),
|
||||
"invalid subsystem %d\n", subsys))
|
||||
return;
|
||||
|
||||
/* must point to statically allocated memory, so INIT is OK */
|
||||
RCU_INIT_POINTER(drop_reasons_by_subsys[subsys], list);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(drop_reasons_register_subsys);
|
||||
|
||||
/**
|
||||
* drop_reasons_unregister_subsys - unregister a drop reason subsystem
|
||||
* @subsys: the subsystem to remove, must not be the core
|
||||
*
|
||||
* Note: This will synchronize_rcu() to ensure no users when it returns.
|
||||
*/
|
||||
void drop_reasons_unregister_subsys(enum skb_drop_reason_subsys subsys)
|
||||
{
|
||||
if (WARN(subsys <= SKB_DROP_REASON_SUBSYS_CORE ||
|
||||
subsys >= ARRAY_SIZE(drop_reasons_by_subsys),
|
||||
"invalid subsystem %d\n", subsys))
|
||||
return;
|
||||
|
||||
RCU_INIT_POINTER(drop_reasons_by_subsys[subsys], NULL);
|
||||
|
||||
synchronize_rcu();
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(drop_reasons_unregister_subsys);
|
||||
|
||||
/**
|
||||
* 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)
|
|||
if (unlikely(!skb_unref(skb)))
|
||||
return false;
|
||||
|
||||
DEBUG_NET_WARN_ON_ONCE(reason <= 0 || reason >= SKB_DROP_REASON_MAX);
|
||||
DEBUG_NET_WARN_ON_ONCE(reason == SKB_NOT_DROPPED_YET ||
|
||||
u32_get_bits(reason,
|
||||
SKB_DROP_REASON_SUBSYS_MASK) >=
|
||||
SKB_DROP_REASON_SUBSYS_NUM);
|
||||
|
||||
if (reason == SKB_CONSUMED)
|
||||
trace_consume_skb(skb, __builtin_return_address(0));
|
||||
|
|
Loading…
Reference in New Issue