linux/net/dccp/qpolicy.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 *  net/dccp/qpolicy.c
   4 *
   5 *  Policy-based packet dequeueing interface for DCCP.
   6 *
   7 *  Copyright (c) 2008 Tomasz Grobelny <tomasz@grobelny.oswiecenia.net>
   8 */
   9#include "dccp.h"
  10
  11/*
  12 *      Simple Dequeueing Policy:
  13 *      If tx_qlen is different from 0, enqueue up to tx_qlen elements.
  14 */
  15static void qpolicy_simple_push(struct sock *sk, struct sk_buff *skb)
  16{
  17        skb_queue_tail(&sk->sk_write_queue, skb);
  18}
  19
  20static bool qpolicy_simple_full(struct sock *sk)
  21{
  22        return dccp_sk(sk)->dccps_tx_qlen &&
  23               sk->sk_write_queue.qlen >= dccp_sk(sk)->dccps_tx_qlen;
  24}
  25
  26static struct sk_buff *qpolicy_simple_top(struct sock *sk)
  27{
  28        return skb_peek(&sk->sk_write_queue);
  29}
  30
  31/*
  32 *      Priority-based Dequeueing Policy:
  33 *      If tx_qlen is different from 0 and the queue has reached its upper bound
  34 *      of tx_qlen elements, replace older packets lowest-priority-first.
  35 */
  36static struct sk_buff *qpolicy_prio_best_skb(struct sock *sk)
  37{
  38        struct sk_buff *skb, *best = NULL;
  39
  40        skb_queue_walk(&sk->sk_write_queue, skb)
  41                if (best == NULL || skb->priority > best->priority)
  42                        best = skb;
  43        return best;
  44}
  45
  46static struct sk_buff *qpolicy_prio_worst_skb(struct sock *sk)
  47{
  48        struct sk_buff *skb, *worst = NULL;
  49
  50        skb_queue_walk(&sk->sk_write_queue, skb)
  51                if (worst == NULL || skb->priority < worst->priority)
  52                        worst = skb;
  53        return worst;
  54}
  55
  56static bool qpolicy_prio_full(struct sock *sk)
  57{
  58        if (qpolicy_simple_full(sk))
  59                dccp_qpolicy_drop(sk, qpolicy_prio_worst_skb(sk));
  60        return false;
  61}
  62
  63/**
  64 * struct dccp_qpolicy_operations  -  TX Packet Dequeueing Interface
  65 * @push: add a new @skb to the write queue
  66 * @full: indicates that no more packets will be admitted
  67 * @top:  peeks at whatever the queueing policy defines as its `top'
  68 * @params: parameter passed to policy operation
  69 */
  70struct dccp_qpolicy_operations {
  71        void            (*push) (struct sock *sk, struct sk_buff *skb);
  72        bool            (*full) (struct sock *sk);
  73        struct sk_buff* (*top)  (struct sock *sk);
  74        __be32          params;
  75};
  76
  77static struct dccp_qpolicy_operations qpol_table[DCCPQ_POLICY_MAX] = {
  78        [DCCPQ_POLICY_SIMPLE] = {
  79                .push   = qpolicy_simple_push,
  80                .full   = qpolicy_simple_full,
  81                .top    = qpolicy_simple_top,
  82                .params = 0,
  83        },
  84        [DCCPQ_POLICY_PRIO] = {
  85                .push   = qpolicy_simple_push,
  86                .full   = qpolicy_prio_full,
  87                .top    = qpolicy_prio_best_skb,
  88                .params = DCCP_SCM_PRIORITY,
  89        },
  90};
  91
  92/*
  93 *      Externally visible interface
  94 */
  95void dccp_qpolicy_push(struct sock *sk, struct sk_buff *skb)
  96{
  97        qpol_table[dccp_sk(sk)->dccps_qpolicy].push(sk, skb);
  98}
  99
 100bool dccp_qpolicy_full(struct sock *sk)
 101{
 102        return qpol_table[dccp_sk(sk)->dccps_qpolicy].full(sk);
 103}
 104
 105void dccp_qpolicy_drop(struct sock *sk, struct sk_buff *skb)
 106{
 107        if (skb != NULL) {
 108                skb_unlink(skb, &sk->sk_write_queue);
 109                kfree_skb(skb);
 110        }
 111}
 112
 113struct sk_buff *dccp_qpolicy_top(struct sock *sk)
 114{
 115        return qpol_table[dccp_sk(sk)->dccps_qpolicy].top(sk);
 116}
 117
 118struct sk_buff *dccp_qpolicy_pop(struct sock *sk)
 119{
 120        struct sk_buff *skb = dccp_qpolicy_top(sk);
 121
 122        if (skb != NULL) {
 123                /* Clear any skb fields that we used internally */
 124                skb->priority = 0;
 125                skb_unlink(skb, &sk->sk_write_queue);
 126        }
 127        return skb;
 128}
 129
 130bool dccp_qpolicy_param_ok(struct sock *sk, __be32 param)
 131{
 132        /* check if exactly one bit is set */
 133        if (!param || (param & (param - 1)))
 134                return false;
 135        return (qpol_table[dccp_sk(sk)->dccps_qpolicy].params & param) == param;
 136}
 137