1 /* 2 * net/sched/police.c Input police filter. 3 * 4 * This program is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU General Public License 6 * as published by the Free Software Foundation; either version 7 * 2 of the License, or (at your option) any later version. 8 * 9 * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> 10 */ 11 12 #include <asm/uaccess.h> 13 #include <asm/system.h> 14 #include <asm/bitops.h> 15 #include <linux/config.h> 16 #include <linux/module.h> 17 #include <linux/types.h> 18 #include <linux/kernel.h> 19 #include <linux/sched.h> 20 #include <linux/string.h> 21 #include <linux/mm.h> 22 #include <linux/socket.h> 23 #include <linux/sockios.h> 24 #include <linux/in.h> 25 #include <linux/errno.h> 26 #include <linux/interrupt.h> 27 #include <linux/netdevice.h> 28 #include <linux/skbuff.h> 29 #include <linux/rtnetlink.h> 30 #include <linux/init.h> 31 #include <net/sock.h> 32 #include <net/pkt_sched.h> 33 34 #define L2T(p,L) ((p)->R_tab->data[(L)>>(p)->R_tab->rate.cell_log]) 35 #define L2T_P(p,L) ((p)->P_tab->data[(L)>>(p)->P_tab->rate.cell_log]) 36 37 static u32 idx_gen; 38 static struct tcf_police *tcf_police_ht[16]; 39 /* Policer hash table lock */ 40 static rwlock_t police_lock = RW_LOCK_UNLOCKED; 41 42 /* Each policer is serialized by its individual spinlock */ 43 44 static __inline__ unsigned tcf_police_hash(u32 index) 45 { 46 return index&0xF; 47 } 48 49 static __inline__ struct tcf_police * tcf_police_lookup(u32 index) 50 { 51 struct tcf_police *p; 52 53 read_lock(&police_lock); 54 for (p = tcf_police_ht[tcf_police_hash(index)]; p; p = p->next) { 55 if (p->index == index) 56 break; 57 } 58 read_unlock(&police_lock); 59 return p; 60 } 61 62 static __inline__ u32 tcf_police_new_index(void) 63 { 64 do { 65 if (++idx_gen == 0) 66 idx_gen = 1; 67 } while (tcf_police_lookup(idx_gen)); 68 69 return idx_gen; 70 } 71 72 73 void tcf_police_destroy(struct tcf_police *p) 74 { 75 unsigned h = tcf_police_hash(p->index); 76 struct tcf_police **p1p; 77 78 for (p1p = &tcf_police_ht[h]; *p1p; p1p = &(*p1p)->next) { 79 if (*p1p == p) { 80 write_lock_bh(&police_lock); 81 *p1p = p->next; 82 write_unlock_bh(&police_lock); 83 #ifdef CONFIG_NET_ESTIMATOR 84 qdisc_kill_estimator(&p->stats); 85 #endif 86 if (p->R_tab) 87 qdisc_put_rtab(p->R_tab); 88 if (p->P_tab) 89 qdisc_put_rtab(p->P_tab); 90 kfree(p); 91 return; 92 } 93 } 94 BUG_TRAP(0); 95 } 96 97 struct tcf_police * tcf_police_locate(struct rtattr *rta, struct rtattr *est) 98 { 99 unsigned h; 100 struct tcf_police *p; 101 struct rtattr *tb[TCA_POLICE_MAX]; 102 struct tc_police *parm; 103 104 if (rtattr_parse(tb, TCA_POLICE_MAX, RTA_DATA(rta), RTA_PAYLOAD(rta)) < 0) 105 return NULL; 106 107 if (tb[TCA_POLICE_TBF-1] == NULL) 108 return NULL; 109 110 parm = RTA_DATA(tb[TCA_POLICE_TBF-1]); 111 112 if (parm->index && (p = tcf_police_lookup(parm->index)) != NULL) { 113 p->refcnt++; 114 return p; 115 } 116 117 p = kmalloc(sizeof(*p), GFP_KERNEL); 118 if (p == NULL) 119 return NULL; 120 121 memset(p, 0, sizeof(*p)); 122 p->refcnt = 1; 123 spin_lock_init(&p->lock); 124 p->stats.lock = &p->lock; 125 if (parm->rate.rate) { 126 if ((p->R_tab = qdisc_get_rtab(&parm->rate, tb[TCA_POLICE_RATE-1])) == NULL) 127 goto failure; 128 if (parm->peakrate.rate && 129 (p->P_tab = qdisc_get_rtab(&parm->peakrate, tb[TCA_POLICE_PEAKRATE-1])) == NULL) 130 goto failure; 131 } 132 if (tb[TCA_POLICE_RESULT-1]) 133 p->result = *(int*)RTA_DATA(tb[TCA_POLICE_RESULT-1]); 134 #ifdef CONFIG_NET_ESTIMATOR 135 if (tb[TCA_POLICE_AVRATE-1]) 136 p->ewma_rate = *(u32*)RTA_DATA(tb[TCA_POLICE_AVRATE-1]); 137 #endif 138 p->toks = p->burst = parm->burst; 139 p->mtu = parm->mtu; 140 if (p->mtu == 0) { 141 p->mtu = ~0; 142 if (p->R_tab) 143 p->mtu = 255<<p->R_tab->rate.cell_log; 144 } 145 if (p->P_tab) 146 p->ptoks = L2T_P(p, p->mtu); 147 PSCHED_GET_TIME(p->t_c); 148 p->index = parm->index ? : tcf_police_new_index(); 149 p->action = parm->action; 150 #ifdef CONFIG_NET_ESTIMATOR 151 if (est) 152 qdisc_new_estimator(&p->stats, est); 153 #endif 154 h = tcf_police_hash(p->index); 155 write_lock_bh(&police_lock); 156 p->next = tcf_police_ht[h]; 157 tcf_police_ht[h] = p; 158 write_unlock_bh(&police_lock); 159 return p; 160 161 failure: 162 if (p->R_tab) 163 qdisc_put_rtab(p->R_tab); 164 kfree(p); 165 return NULL; 166 } 167 168 int tcf_police(struct sk_buff *skb, struct tcf_police *p) 169 { 170 psched_time_t now; 171 long toks; 172 long ptoks = 0; 173 174 spin_lock(&p->lock); 175 176 p->stats.bytes += skb->len; 177 p->stats.packets++; 178 179 #ifdef CONFIG_NET_ESTIMATOR 180 if (p->ewma_rate && p->stats.bps >= p->ewma_rate) { 181 p->stats.overlimits++; 182 spin_unlock(&p->lock); 183 return p->action; 184 } 185 #endif 186 187 if (skb->len <= p->mtu) { 188 if (p->R_tab == NULL) { 189 spin_unlock(&p->lock); 190 return p->result; 191 } 192 193 PSCHED_GET_TIME(now); 194 195 toks = PSCHED_TDIFF_SAFE(now, p->t_c, p->burst, 0); 196 197 if (p->P_tab) { 198 ptoks = toks + p->ptoks; 199 if (ptoks > (long)L2T_P(p, p->mtu)) 200 ptoks = (long)L2T_P(p, p->mtu); 201 ptoks -= L2T_P(p, skb->len); 202 } 203 toks += p->toks; 204 if (toks > (long)p->burst) 205 toks = p->burst; 206 toks -= L2T(p, skb->len); 207 208 if ((toks|ptoks) >= 0) { 209 p->t_c = now; 210 p->toks = toks; 211 p->ptoks = ptoks; 212 spin_unlock(&p->lock); 213 return p->result; 214 } 215 } 216 217 p->stats.overlimits++; 218 spin_unlock(&p->lock); 219 return p->action; 220 } 221 222 int tcf_police_dump(struct sk_buff *skb, struct tcf_police *p) 223 { 224 unsigned char *b = skb->tail; 225 struct tc_police opt; 226 227 opt.index = p->index; 228 opt.action = p->action; 229 opt.mtu = p->mtu; 230 opt.burst = p->burst; 231 if (p->R_tab) 232 opt.rate = p->R_tab->rate; 233 else 234 memset(&opt.rate, 0, sizeof(opt.rate)); 235 if (p->P_tab) 236 opt.peakrate = p->P_tab->rate; 237 else 238 memset(&opt.peakrate, 0, sizeof(opt.peakrate)); 239 RTA_PUT(skb, TCA_POLICE_TBF, sizeof(opt), &opt); 240 if (p->result) 241 RTA_PUT(skb, TCA_POLICE_RESULT, sizeof(int), &p->result); 242 #ifdef CONFIG_NET_ESTIMATOR 243 if (p->ewma_rate) 244 RTA_PUT(skb, TCA_POLICE_AVRATE, 4, &p->ewma_rate); 245 #endif 246 return skb->len; 247 248 rtattr_failure: 249 skb_trim(skb, b - skb->data); 250 return -1; 251 } 252 253 EXPORT_SYMBOL(tcf_police); 254 EXPORT_SYMBOL(tcf_police_destroy); 255 EXPORT_SYMBOL(tcf_police_dump); 256 EXPORT_SYMBOL(tcf_police_hash); 257 EXPORT_SYMBOL(tcf_police_ht); 258 EXPORT_SYMBOL(tcf_police_locate); 259 EXPORT_SYMBOL(tcf_police_lookup); 260 EXPORT_SYMBOL(tcf_police_new_index); 261
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.