]> git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/blobdiff - include/net/sch_generic.h
net: sched: sch: add extack for block callback
[mirror_ubuntu-jammy-kernel.git] / include / net / sch_generic.h
index 83a3e47d5845b99fa61799a15b29e7247d478c72..f65dd2837142210c56775e00be3503830c54059b 100644 (file)
@@ -71,6 +71,7 @@ struct Qdisc {
                                      * qdisc_tree_decrease_qlen() should stop.
                                      */
 #define TCQ_F_INVISIBLE                0x80 /* invisible by default in dump */
+#define TCQ_F_NOLOCK           0x100 /* qdisc does not require locking */
 #define TCQ_F_OFFLOADED                0x200 /* qdisc is offloaded to HW */
        u32                     limit;
        const struct Qdisc_ops  *ops;
@@ -88,14 +89,14 @@ struct Qdisc {
        /*
         * For performance sake on SMP, we put highly modified fields at the end
         */
-       struct sk_buff          *gso_skb ____cacheline_aligned_in_smp;
+       struct sk_buff_head     gso_skb ____cacheline_aligned_in_smp;
        struct qdisc_skb_head   q;
        struct gnet_stats_basic_packed bstats;
        seqcount_t              running;
        struct gnet_stats_queue qstats;
        unsigned long           state;
        struct Qdisc            *next_sched;
-       struct sk_buff          *skb_bad_txq;
+       struct sk_buff_head     skb_bad_txq;
        int                     padded;
        refcount_t              refcnt;
 
@@ -157,12 +158,15 @@ struct Qdisc_class_ops {
        /* Class manipulation routines */
        unsigned long           (*find)(struct Qdisc *, u32 classid);
        int                     (*change)(struct Qdisc *, u32, u32,
-                                       struct nlattr **, unsigned long *);
+                                       struct nlattr **, unsigned long *,
+                                       struct netlink_ext_ack *);
        int                     (*delete)(struct Qdisc *, unsigned long);
        void                    (*walk)(struct Qdisc *, struct qdisc_walker * arg);
 
        /* Filter manipulation */
-       struct tcf_block *      (*tcf_block)(struct Qdisc *, unsigned long);
+       struct tcf_block *      (*tcf_block)(struct Qdisc *sch,
+                                            unsigned long arg,
+                                            struct netlink_ext_ack *extack);
        unsigned long           (*bind_tcf)(struct Qdisc *, unsigned long,
                                        u32 classid);
        void                    (*unbind_tcf)(struct Qdisc *, unsigned long);
@@ -179,6 +183,7 @@ struct Qdisc_ops {
        const struct Qdisc_class_ops    *cl_ops;
        char                    id[IFNAMSIZ];
        int                     priv_size;
+       unsigned int            static_flags;
 
        int                     (*enqueue)(struct sk_buff *skb,
                                           struct Qdisc *sch,
@@ -186,11 +191,14 @@ struct Qdisc_ops {
        struct sk_buff *        (*dequeue)(struct Qdisc *);
        struct sk_buff *        (*peek)(struct Qdisc *);
 
-       int                     (*init)(struct Qdisc *, struct nlattr *arg);
+       int                     (*init)(struct Qdisc *sch, struct nlattr *arg,
+                                       struct netlink_ext_ack *extack);
        void                    (*reset)(struct Qdisc *);
        void                    (*destroy)(struct Qdisc *);
-       int                     (*change)(struct Qdisc *, struct nlattr *arg);
-       void                    (*attach)(struct Qdisc *);
+       int                     (*change)(struct Qdisc *sch,
+                                         struct nlattr *arg,
+                                         struct netlink_ext_ack *extack);
+       void                    (*attach)(struct Qdisc *sch);
 
        int                     (*dump)(struct Qdisc *, struct sk_buff *);
        int                     (*dump_stats)(struct Qdisc *, struct gnet_dump *);
@@ -279,7 +287,6 @@ struct tcf_block {
        struct net *net;
        struct Qdisc *q;
        struct list_head cb_list;
-       struct work_struct work;
 };
 
 static inline void qdisc_cb_private_validate(const struct sk_buff *skb, int sz)
@@ -290,11 +297,31 @@ static inline void qdisc_cb_private_validate(const struct sk_buff *skb, int sz)
        BUILD_BUG_ON(sizeof(qcb->data) < sz);
 }
 
+static inline int qdisc_qlen_cpu(const struct Qdisc *q)
+{
+       return this_cpu_ptr(q->cpu_qstats)->qlen;
+}
+
 static inline int qdisc_qlen(const struct Qdisc *q)
 {
        return q->q.qlen;
 }
 
+static inline int qdisc_qlen_sum(const struct Qdisc *q)
+{
+       __u32 qlen = 0;
+       int i;
+
+       if (q->flags & TCQ_F_NOLOCK) {
+               for_each_possible_cpu(i)
+                       qlen += per_cpu_ptr(q->cpu_qstats, i)->qlen;
+       } else {
+               qlen = q->q.qlen;
+       }
+
+       return qlen;
+}
+
 static inline struct qdisc_skb_cb *qdisc_skb_cb(const struct sk_buff *skb)
 {
        return (struct qdisc_skb_cb *)skb->cb;
@@ -631,12 +658,39 @@ static inline void qdisc_qstats_backlog_dec(struct Qdisc *sch,
        sch->qstats.backlog -= qdisc_pkt_len(skb);
 }
 
+static inline void qdisc_qstats_cpu_backlog_dec(struct Qdisc *sch,
+                                               const struct sk_buff *skb)
+{
+       this_cpu_sub(sch->cpu_qstats->backlog, qdisc_pkt_len(skb));
+}
+
 static inline void qdisc_qstats_backlog_inc(struct Qdisc *sch,
                                            const struct sk_buff *skb)
 {
        sch->qstats.backlog += qdisc_pkt_len(skb);
 }
 
+static inline void qdisc_qstats_cpu_backlog_inc(struct Qdisc *sch,
+                                               const struct sk_buff *skb)
+{
+       this_cpu_add(sch->cpu_qstats->backlog, qdisc_pkt_len(skb));
+}
+
+static inline void qdisc_qstats_cpu_qlen_inc(struct Qdisc *sch)
+{
+       this_cpu_inc(sch->cpu_qstats->qlen);
+}
+
+static inline void qdisc_qstats_cpu_qlen_dec(struct Qdisc *sch)
+{
+       this_cpu_dec(sch->cpu_qstats->qlen);
+}
+
+static inline void qdisc_qstats_cpu_requeues_inc(struct Qdisc *sch)
+{
+       this_cpu_inc(sch->cpu_qstats->requeues);
+}
+
 static inline void __qdisc_qstats_drop(struct Qdisc *sch, int count)
 {
        sch->qstats.drops += count;
@@ -767,26 +821,30 @@ static inline struct sk_buff *qdisc_peek_head(struct Qdisc *sch)
 /* generic pseudo peek method for non-work-conserving qdisc */
 static inline struct sk_buff *qdisc_peek_dequeued(struct Qdisc *sch)
 {
+       struct sk_buff *skb = skb_peek(&sch->gso_skb);
+
        /* we can reuse ->gso_skb because peek isn't called for root qdiscs */
-       if (!sch->gso_skb) {
-               sch->gso_skb = sch->dequeue(sch);
-               if (sch->gso_skb) {
+       if (!skb) {
+               skb = sch->dequeue(sch);
+
+               if (skb) {
+                       __skb_queue_head(&sch->gso_skb, skb);
                        /* it's still part of the queue */
-                       qdisc_qstats_backlog_inc(sch, sch->gso_skb);
+                       qdisc_qstats_backlog_inc(sch, skb);
                        sch->q.qlen++;
                }
        }
 
-       return sch->gso_skb;
+       return skb;
 }
 
 /* use instead of qdisc->dequeue() for all qdiscs queried with ->peek() */
 static inline struct sk_buff *qdisc_dequeue_peeked(struct Qdisc *sch)
 {
-       struct sk_buff *skb = sch->gso_skb;
+       struct sk_buff *skb = skb_peek(&sch->gso_skb);
 
        if (skb) {
-               sch->gso_skb = NULL;
+               skb = __skb_dequeue(&sch->gso_skb);
                qdisc_qstats_backlog_dec(sch, skb);
                sch->q.qlen--;
        } else {
@@ -844,6 +902,14 @@ static inline void rtnl_qdisc_drop(struct sk_buff *skb, struct Qdisc *sch)
        qdisc_qstats_drop(sch);
 }
 
+static inline int qdisc_drop_cpu(struct sk_buff *skb, struct Qdisc *sch,
+                                struct sk_buff **to_free)
+{
+       __qdisc_drop(skb, to_free);
+       qdisc_qstats_cpu_drop(sch);
+
+       return NET_XMIT_DROP;
+}
 
 static inline int qdisc_drop(struct sk_buff *skb, struct Qdisc *sch,
                             struct sk_buff **to_free)