Blame view

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