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