Commit bee9705c authored by David S. Miller's avatar David S. Miller

Merge branch 'net-sched-tc-drop-reason'

Victor Nogueira says:

====================
net: sched: Make tc-related drop reason more flexible for remaining qdiscs

This patch builds on Daniel's patch[1] to add initial support of tc drop
reason. The main goal is to distinguish between policy and error drops for
the remainder of the egress qdiscs (other than clsact).
The drop reason is set by cls_api and act_api in the tc skb cb in case
any error occurred in the data path.

Also add new skb drop reasons that are idiosyncratic to TC.

[1] https://lore.kernel.org/all/20231009092655.22025-1-daniel@iogearbox.net

Changes in V5:
- Drop "EXT_" from cookie error's drop reason name in doc

Changes in V4:
- Condense all the cookie drop reasons into one

Changes in V3:
- Removed duplicate assignment
- Rename function tc_skb_cb_drop_reason to tcf_get_drop_reason
- Move zone field upwards in struct tc_skb_cb to move hole to the end of
  the struct

Changes in V2:
- Dropped RFC tag
- Removed check for drop reason being overwritten by filter in cls_api.c
- Simplified logic and removed function tcf_init_drop_reason
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 18764b88 4cf24dc8
......@@ -85,8 +85,10 @@
FN(IPV6_NDISC_BAD_OPTIONS) \
FN(IPV6_NDISC_NS_OTHERHOST) \
FN(QUEUE_PURGE) \
FN(TC_ERROR) \
FN(TC_COOKIE_ERROR) \
FN(PACKET_SOCK_ERROR) \
FN(TC_CHAIN_NOTFOUND) \
FN(TC_RECLASSIFY_LOOP) \
FNe(MAX)
/**
......@@ -377,13 +379,23 @@ enum skb_drop_reason {
SKB_DROP_REASON_IPV6_NDISC_NS_OTHERHOST,
/** @SKB_DROP_REASON_QUEUE_PURGE: bulk free. */
SKB_DROP_REASON_QUEUE_PURGE,
/** @SKB_DROP_REASON_TC_ERROR: generic internal tc error. */
SKB_DROP_REASON_TC_ERROR,
/**
* @SKB_DROP_REASON_TC_COOKIE_ERROR: An error occurred whilst
* processing a tc ext cookie.
*/
SKB_DROP_REASON_TC_COOKIE_ERROR,
/**
* @SKB_DROP_REASON_PACKET_SOCK_ERROR: generic packet socket errors
* after its filter matches an incoming packet.
*/
SKB_DROP_REASON_PACKET_SOCK_ERROR,
/** @SKB_DROP_REASON_TC_CHAIN_NOTFOUND: tc chain lookup failed. */
SKB_DROP_REASON_TC_CHAIN_NOTFOUND,
/**
* @SKB_DROP_REASON_TC_RECLASSIFY_LOOP: tc exceeded max reclassify loop
* iterations.
*/
SKB_DROP_REASON_TC_RECLASSIFY_LOOP,
/**
* @SKB_DROP_REASON_MAX: the maximum of core drop reasons, which
* shouldn't be used as a real 'reason' - only for tracing code gen
......
......@@ -154,12 +154,6 @@ __cls_set_class(unsigned long *clp, unsigned long cl)
return xchg(clp, cl);
}
static inline void tcf_set_drop_reason(struct tcf_result *res,
enum skb_drop_reason reason)
{
res->drop_reason = reason;
}
static inline void
__tcf_bind_filter(struct Qdisc *q, struct tcf_result *r, unsigned long base)
{
......
......@@ -275,24 +275,6 @@ static inline void skb_txtime_consumed(struct sk_buff *skb)
skb->tstamp = ktime_set(0, 0);
}
struct tc_skb_cb {
struct qdisc_skb_cb qdisc_cb;
u16 mru;
u8 post_ct:1;
u8 post_ct_snat:1;
u8 post_ct_dnat:1;
u16 zone; /* Only valid if post_ct = true */
};
static inline struct tc_skb_cb *tc_skb_cb(const struct sk_buff *skb)
{
struct tc_skb_cb *cb = (struct tc_skb_cb *)skb->cb;
BUILD_BUG_ON(sizeof(*cb) > sizeof_field(struct sk_buff, cb));
return cb;
}
static inline bool tc_qdisc_stats_dump(struct Qdisc *sch,
unsigned long cl,
struct qdisc_walker *arg)
......
......@@ -332,7 +332,6 @@ struct tcf_result {
};
const struct tcf_proto *goto_tp;
};
enum skb_drop_reason drop_reason;
};
struct tcf_chain;
......@@ -1037,6 +1036,37 @@ static inline struct sk_buff *qdisc_dequeue_head(struct Qdisc *sch)
return skb;
}
struct tc_skb_cb {
struct qdisc_skb_cb qdisc_cb;
u32 drop_reason;
u16 zone; /* Only valid if post_ct = true */
u16 mru;
u8 post_ct:1;
u8 post_ct_snat:1;
u8 post_ct_dnat:1;
};
static inline struct tc_skb_cb *tc_skb_cb(const struct sk_buff *skb)
{
struct tc_skb_cb *cb = (struct tc_skb_cb *)skb->cb;
BUILD_BUG_ON(sizeof(*cb) > sizeof_field(struct sk_buff, cb));
return cb;
}
static inline enum skb_drop_reason
tcf_get_drop_reason(const struct sk_buff *skb)
{
return tc_skb_cb(skb)->drop_reason;
}
static inline void tcf_set_drop_reason(const struct sk_buff *skb,
enum skb_drop_reason reason)
{
tc_skb_cb(skb)->drop_reason = reason;
}
/* Instead of calling kfree_skb() while root qdisc lock is held,
* queue the skb for future freeing at end of __dev_xmit_skb()
*/
......
......@@ -3753,6 +3753,8 @@ static inline int __dev_xmit_skb(struct sk_buff *skb, struct Qdisc *q,
qdisc_calculate_pkt_len(skb, q);
tcf_set_drop_reason(skb, SKB_DROP_REASON_QDISC_DROP);
if (q->flags & TCQ_F_NOLOCK) {
if (q->flags & TCQ_F_CAN_BYPASS && nolock_qdisc_is_empty(q) &&
qdisc_run_begin(q)) {
......@@ -3782,7 +3784,7 @@ static inline int __dev_xmit_skb(struct sk_buff *skb, struct Qdisc *q,
no_lock_out:
if (unlikely(to_free))
kfree_skb_list_reason(to_free,
SKB_DROP_REASON_QDISC_DROP);
tcf_get_drop_reason(to_free));
return rc;
}
......@@ -3837,7 +3839,8 @@ static inline int __dev_xmit_skb(struct sk_buff *skb, struct Qdisc *q,
}
spin_unlock(root_lock);
if (unlikely(to_free))
kfree_skb_list_reason(to_free, SKB_DROP_REASON_QDISC_DROP);
kfree_skb_list_reason(to_free,
tcf_get_drop_reason(to_free));
if (unlikely(contended))
spin_unlock(&q->busylock);
return rc;
......@@ -3923,14 +3926,14 @@ static int tc_run(struct tcx_entry *entry, struct sk_buff *skb,
tc_skb_cb(skb)->mru = 0;
tc_skb_cb(skb)->post_ct = false;
res.drop_reason = *drop_reason;
tcf_set_drop_reason(skb, *drop_reason);
mini_qdisc_bstats_cpu_update(miniq, skb);
ret = tcf_classify(skb, miniq->block, miniq->filter_list, &res, false);
/* Only tcf related quirks below. */
switch (ret) {
case TC_ACT_SHOT:
*drop_reason = res.drop_reason;
*drop_reason = tcf_get_drop_reason(skb);
mini_qdisc_qstats_cpu_drop(miniq);
break;
case TC_ACT_OK:
......
......@@ -1119,7 +1119,8 @@ int tcf_action_exec(struct sk_buff *skb, struct tc_action **actions,
}
} else if (TC_ACT_EXT_CMP(ret, TC_ACT_GOTO_CHAIN)) {
if (unlikely(!rcu_access_pointer(a->goto_chain))) {
tcf_set_drop_reason(res, SKB_DROP_REASON_TC_ERROR);
tcf_set_drop_reason(skb,
SKB_DROP_REASON_TC_CHAIN_NOTFOUND);
return TC_ACT_SHOT;
}
tcf_action_goto_chain_exec(a, res);
......
......@@ -1657,7 +1657,6 @@ static inline int __tcf_classify(struct sk_buff *skb,
int act_index,
u32 *last_executed_chain)
{
u32 orig_reason = res->drop_reason;
#ifdef CONFIG_NET_CLS_ACT
const int max_reclassify_loop = 16;
const struct tcf_proto *first_tp;
......@@ -1682,13 +1681,15 @@ static inline int __tcf_classify(struct sk_buff *skb,
*/
if (unlikely(n->tp != tp || n->tp->chain != n->chain ||
!tp->ops->get_exts)) {
tcf_set_drop_reason(res, SKB_DROP_REASON_TC_ERROR);
tcf_set_drop_reason(skb,
SKB_DROP_REASON_TC_COOKIE_ERROR);
return TC_ACT_SHOT;
}
exts = tp->ops->get_exts(tp, n->handle);
if (unlikely(!exts || n->exts != exts)) {
tcf_set_drop_reason(res, SKB_DROP_REASON_TC_ERROR);
tcf_set_drop_reason(skb,
SKB_DROP_REASON_TC_COOKIE_ERROR);
return TC_ACT_SHOT;
}
......@@ -1712,18 +1713,13 @@ static inline int __tcf_classify(struct sk_buff *skb,
goto reset;
}
#endif
if (err >= 0) {
/* Policy drop or drop reason is over-written by
* classifiers with a bogus value(0) */
if (err == TC_ACT_SHOT &&
res->drop_reason == SKB_NOT_DROPPED_YET)
tcf_set_drop_reason(res, orig_reason);
if (err >= 0)
return err;
}
}
if (unlikely(n)) {
tcf_set_drop_reason(res, SKB_DROP_REASON_TC_ERROR);
tcf_set_drop_reason(skb,
SKB_DROP_REASON_TC_COOKIE_ERROR);
return TC_ACT_SHOT;
}
......@@ -1735,7 +1731,8 @@ static inline int __tcf_classify(struct sk_buff *skb,
tp->chain->block->index,
tp->prio & 0xffff,
ntohs(tp->protocol));
tcf_set_drop_reason(res, SKB_DROP_REASON_TC_ERROR);
tcf_set_drop_reason(skb,
SKB_DROP_REASON_TC_RECLASSIFY_LOOP);
return TC_ACT_SHOT;
}
......@@ -1773,7 +1770,8 @@ int tcf_classify(struct sk_buff *skb,
n = tcf_exts_miss_cookie_lookup(ext->act_miss_cookie,
&act_index);
if (!n) {
tcf_set_drop_reason(res, SKB_DROP_REASON_TC_ERROR);
tcf_set_drop_reason(skb,
SKB_DROP_REASON_TC_COOKIE_ERROR);
return TC_ACT_SHOT;
}
......@@ -1784,7 +1782,9 @@ int tcf_classify(struct sk_buff *skb,
fchain = tcf_chain_lookup_rcu(block, chain);
if (!fchain) {
tcf_set_drop_reason(res, SKB_DROP_REASON_TC_ERROR);
tcf_set_drop_reason(skb,
SKB_DROP_REASON_TC_CHAIN_NOTFOUND);
return TC_ACT_SHOT;
}
......@@ -1806,10 +1806,9 @@ int tcf_classify(struct sk_buff *skb,
ext = tc_skb_ext_alloc(skb);
if (WARN_ON_ONCE(!ext)) {
tcf_set_drop_reason(res, SKB_DROP_REASON_TC_ERROR);
tcf_set_drop_reason(skb, SKB_DROP_REASON_NOMEM);
return TC_ACT_SHOT;
}
ext->chain = last_executed_chain;
ext->mru = cb->mru;
ext->post_ct = cb->post_ct;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment