cls_tcindex.c
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:12k
源码类别:

Linux/Unix编程

开发平台:

Unix_Linux

  1. /*
  2.  * net/sched/cls_tcindex.c Packet classifier for skb->tc_index
  3.  *
  4.  * Written 1998,1999 by Werner Almesberger, EPFL ICA
  5.  */
  6. #include <linux/config.h>
  7. #include <linux/module.h>
  8. #include <linux/types.h>
  9. #include <linux/kernel.h>
  10. #include <linux/skbuff.h>
  11. #include <linux/errno.h>
  12. #include <linux/netdevice.h>
  13. #include <net/ip.h>
  14. #include <net/pkt_sched.h>
  15. #include <net/route.h>
  16. /*
  17.  * Not quite sure if we need all the xchgs Alexey uses when accessing things.
  18.  * Can always add them later ... :)
  19.  */
  20. /*
  21.  * Passing parameters to the root seems to be done more awkwardly than really
  22.  * necessary. At least, u32 doesn't seem to use such dirty hacks. To be
  23.  * verified. FIXME.
  24.  */
  25. #define PERFECT_HASH_THRESHOLD 64 /* use perfect hash if not bigger */
  26. #define DEFAULT_HASH_SIZE 64 /* optimized for diffserv */
  27. #if 1 /* control */
  28. #define DPRINTK(format,args...) printk(KERN_DEBUG format,##args)
  29. #else
  30. #define DPRINTK(format,args...)
  31. #endif
  32. #if 0 /* data */
  33. #define D2PRINTK(format,args...) printk(KERN_DEBUG format,##args)
  34. #else
  35. #define D2PRINTK(format,args...)
  36. #endif
  37. #define PRIV(tp) ((struct tcindex_data *) (tp)->root)
  38. struct tcindex_filter_result {
  39. struct tcf_police *police;
  40. struct tcf_result res;
  41. };
  42. struct tcindex_filter {
  43. __u16 key;
  44. struct tcindex_filter_result result;
  45. struct tcindex_filter *next;
  46. };
  47. struct tcindex_data {
  48. struct tcindex_filter_result *perfect; /* perfect hash; NULL if none */
  49. struct tcindex_filter **h; /* imperfect hash; only used if !perfect;
  50.       NULL if unused */
  51. __u16 mask; /* AND key with mask */
  52. int shift; /* shift ANDed key to the right */
  53. int hash; /* hash table size; 0 if undefined */
  54. int alloc_hash; /* allocated size */
  55. int fall_through; /* 0: only classify if explicit match */
  56. };
  57. static struct tcindex_filter_result *lookup(struct tcindex_data *p,__u16 key)
  58. {
  59. struct tcindex_filter *f;
  60. if (p->perfect)
  61. return p->perfect[key].res.class ? p->perfect+key : NULL;
  62. if (!p->h)
  63. return NULL;
  64. for (f = p->h[key % p->hash]; f; f = f->next) {
  65. if (f->key == key)
  66. return &f->result;
  67. }
  68. return NULL;
  69. }
  70. static int tcindex_classify(struct sk_buff *skb, struct tcf_proto *tp,
  71.   struct tcf_result *res)
  72. {
  73. struct tcindex_data *p = PRIV(tp);
  74. struct tcindex_filter_result *f;
  75. D2PRINTK("tcindex_classify(skb %p,tp %p,res %p),p %pn",skb,tp,res,p);
  76. f = lookup(p,(skb->tc_index & p->mask) >> p->shift);
  77. if (!f) {
  78. if (!p->fall_through)
  79. return -1;
  80. res->classid = TC_H_MAKE(TC_H_MAJ(tp->q->handle),
  81.     (skb->tc_index& p->mask) >> p->shift);
  82. res->class = 0;
  83. D2PRINTK("alg 0x%xn",res->classid);
  84. return 0;
  85. }
  86. *res = f->res;
  87. D2PRINTK("map 0x%xn",res->classid);
  88. #ifdef CONFIG_NET_CLS_POLICE
  89. if (f->police) {
  90. int result;
  91. result = tcf_police(skb,f->police);
  92. D2PRINTK("police %dn",res);
  93. return result;
  94. }
  95. #endif
  96. return 0;
  97. }
  98. static unsigned long tcindex_get(struct tcf_proto *tp, u32 handle)
  99. {
  100. struct tcindex_data *p = PRIV(tp);
  101. struct tcindex_filter_result *r;
  102. DPRINTK("tcindex_get(tp %p,handle 0x%08x)n",tp,handle);
  103. if (p->perfect && handle >= p->alloc_hash)
  104. return 0;
  105. r = lookup(PRIV(tp),handle);
  106. return r && r->res.class ? (unsigned long) r : 0;
  107. }
  108. static void tcindex_put(struct tcf_proto *tp, unsigned long f)
  109. {
  110. DPRINTK("tcindex_put(tp %p,f 0x%lx)n",tp,f);
  111. }
  112. static int tcindex_init(struct tcf_proto *tp)
  113. {
  114. struct tcindex_data *p;
  115. DPRINTK("tcindex_init(tp %p)n",tp);
  116. MOD_INC_USE_COUNT;
  117. p = kmalloc(sizeof(struct tcindex_data),GFP_KERNEL);
  118. if (!p) {
  119. MOD_DEC_USE_COUNT;
  120. return -ENOMEM;
  121. }
  122. tp->root = p;
  123. p->perfect = NULL;
  124. p->h = NULL;
  125. p->hash = 0;
  126. p->mask = 0xffff;
  127. p->shift = 0;
  128. p->fall_through = 1;
  129. return 0;
  130. }
  131. static int tcindex_delete(struct tcf_proto *tp, unsigned long arg)
  132. {
  133. struct tcindex_data *p = PRIV(tp);
  134. struct tcindex_filter_result *r = (struct tcindex_filter_result *) arg;
  135. struct tcindex_filter *f = NULL;
  136. unsigned long cl;
  137. DPRINTK("tcindex_delete(tp %p,arg 0x%lx),p %p,f %pn",tp,arg,p,f);
  138. if (p->perfect) {
  139. if (!r->res.class)
  140. return -ENOENT;
  141. } else {
  142. int i;
  143. struct tcindex_filter **walk = NULL;
  144. for (i = 0; i < p->hash; i++)
  145. for (walk = p->h+i; *walk; walk = &(*walk)->next)
  146. if (&(*walk)->result == r)
  147. goto found;
  148. return -ENOENT;
  149. found:
  150. f = *walk;
  151. tcf_tree_lock(tp); 
  152. *walk = f->next;
  153. tcf_tree_unlock(tp);
  154. }
  155. cl = __cls_set_class(&r->res.class,0);
  156. if (cl)
  157. tp->q->ops->cl_ops->unbind_tcf(tp->q,cl);
  158. #ifdef CONFIG_NET_CLS_POLICE
  159. tcf_police_release(r->police);
  160. #endif
  161. if (f)
  162. kfree(f);
  163. return 0;
  164. }
  165. /*
  166.  * There are no parameters for tcindex_init, so we overload tcindex_change
  167.  */
  168. static int tcindex_change(struct tcf_proto *tp,unsigned long base,u32 handle,
  169.     struct rtattr **tca,unsigned long *arg)
  170. {
  171. struct tcindex_filter_result new_filter_result = {
  172. NULL, /* no policing */
  173. { 0,0 }, /* no classification */
  174. };
  175. struct rtattr *opt = tca[TCA_OPTIONS-1];
  176. struct rtattr *tb[TCA_TCINDEX_MAX];
  177. struct tcindex_data *p = PRIV(tp);
  178. struct tcindex_filter *f;
  179. struct tcindex_filter_result *r = (struct tcindex_filter_result *) *arg;
  180. struct tcindex_filter **walk;
  181. int hash,shift;
  182. __u16 mask;
  183. DPRINTK("tcindex_change(tp %p,handle 0x%08x,tca %p,arg %p),opt %p,"
  184.     "p %p,r %pn",tp,handle,tca,arg,opt,p,r);
  185. if (arg)
  186. DPRINTK("*arg = 0x%lxn",*arg);
  187. if (!opt)
  188. return 0;
  189. if (rtattr_parse(tb,TCA_TCINDEX_MAX,RTA_DATA(opt),RTA_PAYLOAD(opt)) < 0)
  190. return -EINVAL;
  191. if (!tb[TCA_TCINDEX_HASH-1]) {
  192. hash = p->hash;
  193. } else {
  194. if (RTA_PAYLOAD(tb[TCA_TCINDEX_HASH-1]) < sizeof(int))
  195. return -EINVAL;
  196. hash = *(int *) RTA_DATA(tb[TCA_TCINDEX_HASH-1]);
  197. }
  198. if (!tb[TCA_TCINDEX_MASK-1]) {
  199. mask = p->mask;
  200. } else {
  201. if (RTA_PAYLOAD(tb[TCA_TCINDEX_MASK-1]) < sizeof(__u16))
  202. return -EINVAL;
  203. mask = *(__u16 *) RTA_DATA(tb[TCA_TCINDEX_MASK-1]);
  204. }
  205. if (!tb[TCA_TCINDEX_SHIFT-1])
  206. shift = p->shift;
  207. else {
  208. if (RTA_PAYLOAD(tb[TCA_TCINDEX_SHIFT-1]) < sizeof(__u16))
  209. return -EINVAL;
  210. shift = *(int *) RTA_DATA(tb[TCA_TCINDEX_SHIFT-1]);
  211. }
  212. if (p->perfect && hash <= (mask >> shift))
  213. return -EBUSY;
  214. if (p->perfect && hash > p->alloc_hash)
  215. return -EBUSY;
  216. if (p->h && hash != p->alloc_hash)
  217. return -EBUSY;
  218. p->hash = hash;
  219. p->mask = mask;
  220. p->shift = shift;
  221. if (tb[TCA_TCINDEX_FALL_THROUGH-1]) {
  222. if (RTA_PAYLOAD(tb[TCA_TCINDEX_FALL_THROUGH-1]) < sizeof(int))
  223. return -EINVAL;
  224. p->fall_through =
  225.     *(int *) RTA_DATA(tb[TCA_TCINDEX_FALL_THROUGH-1]);
  226. }
  227. DPRINTK("classid/police %p/%pn",tb[TCA_TCINDEX_CLASSID-1],
  228.     tb[TCA_TCINDEX_POLICE-1]);
  229. if (!tb[TCA_TCINDEX_CLASSID-1] && !tb[TCA_TCINDEX_POLICE-1])
  230. return 0;
  231. if (!hash) {
  232. if ((mask >> shift) < PERFECT_HASH_THRESHOLD) {
  233. p->hash = (mask >> shift)+1;
  234. } else {
  235. p->hash = DEFAULT_HASH_SIZE;
  236. }
  237. }
  238. if (!p->perfect && !p->h) {
  239. p->alloc_hash = p->hash;
  240. DPRINTK("hash %d mask %dn",p->hash,p->mask);
  241. if (p->hash > (mask >> shift)) {
  242. p->perfect = kmalloc(p->hash*
  243.     sizeof(struct tcindex_filter_result),GFP_KERNEL);
  244. if (!p->perfect)
  245. return -ENOMEM;
  246. memset(p->perfect, 0,
  247.        p->hash * sizeof(struct tcindex_filter_result));
  248. } else {
  249. p->h = kmalloc(p->hash*sizeof(struct tcindex_filter *),
  250.     GFP_KERNEL);
  251. if (!p->h)
  252. return -ENOMEM;
  253. memset(p->h, 0, p->hash*sizeof(struct tcindex_filter *));
  254. }
  255. }
  256. /*
  257.  * Note: this could be as restrictive as
  258.  * if (handle & ~(mask >> shift))
  259.  * but then, we'd fail handles that may become valid after some
  260.  * future mask change. While this is extremely unlikely to ever
  261.  * matter, the check below is safer (and also more
  262.  * backwards-compatible).
  263.  */
  264. if (p->perfect && handle >= p->alloc_hash)
  265. return -EINVAL;
  266. if (p->perfect) {
  267. r = p->perfect+handle;
  268. } else {
  269. r = lookup(p,handle);
  270. DPRINTK("r=%pn",r);
  271. if (!r)
  272. r = &new_filter_result;
  273. }
  274. DPRINTK("r=%pn",r);
  275. if (tb[TCA_TCINDEX_CLASSID-1]) {
  276. unsigned long cl = cls_set_class(tp,&r->res.class,0);
  277. if (cl)
  278. tp->q->ops->cl_ops->unbind_tcf(tp->q,cl);
  279. r->res.classid = *(__u32 *) RTA_DATA(tb[TCA_TCINDEX_CLASSID-1]);
  280. r->res.class = tp->q->ops->cl_ops->bind_tcf(tp->q,base,
  281.     r->res.classid);
  282. if (!r->res.class) {
  283. r->res.classid = 0;
  284. return -ENOENT;
  285. }
  286.         }
  287. #ifdef CONFIG_NET_CLS_POLICE
  288. {
  289. struct tcf_police *police;
  290. police = tb[TCA_TCINDEX_POLICE-1] ?
  291.     tcf_police_locate(tb[TCA_TCINDEX_POLICE-1],NULL) : NULL;
  292. tcf_tree_lock(tp);
  293. police = xchg(&r->police,police);
  294. tcf_tree_unlock(tp);
  295. tcf_police_release(police);
  296. }
  297. #endif
  298. if (r != &new_filter_result)
  299. return 0;
  300. f = kmalloc(sizeof(struct tcindex_filter),GFP_KERNEL);
  301. if (!f)
  302. return -ENOMEM;
  303. f->key = handle;
  304. f->result = new_filter_result;
  305. f->next = NULL;
  306. for (walk = p->h+(handle % p->hash); *walk; walk = &(*walk)->next)
  307. /* nothing */;
  308. wmb();
  309. *walk = f;
  310. return 0;
  311. }
  312. static void tcindex_walk(struct tcf_proto *tp, struct tcf_walker *walker)
  313. {
  314. struct tcindex_data *p = PRIV(tp);
  315. struct tcindex_filter *f,*next;
  316. int i;
  317. DPRINTK("tcindex_walk(tp %p,walker %p),p %pn",tp,walker,p);
  318. if (p->perfect) {
  319. for (i = 0; i < p->hash; i++) {
  320. if (!p->perfect[i].res.class)
  321. continue;
  322. if (walker->count >= walker->skip) {
  323. if (walker->fn(tp,
  324.     (unsigned long) (p->perfect+i), walker)
  325.      < 0) {
  326. walker->stop = 1;
  327. return;
  328. }
  329. }
  330. walker->count++;
  331. }
  332. }
  333. if (!p->h)
  334. return;
  335. for (i = 0; i < p->hash; i++) {
  336. for (f = p->h[i]; f; f = next) {
  337. next = f->next;
  338. if (walker->count >= walker->skip) {
  339. if (walker->fn(tp,(unsigned long) &f->result,
  340.     walker) < 0) {
  341. walker->stop = 1;
  342. return;
  343. }
  344. }
  345. walker->count++;
  346. }
  347. }
  348. }
  349. static int tcindex_destroy_element(struct tcf_proto *tp,
  350.     unsigned long arg, struct tcf_walker *walker)
  351. {
  352. return tcindex_delete(tp,arg);
  353. }
  354. static void tcindex_destroy(struct tcf_proto *tp)
  355. {
  356. struct tcindex_data *p = PRIV(tp);
  357. struct tcf_walker walker;
  358. DPRINTK("tcindex_destroy(tp %p),p %pn",tp,p);
  359. walker.count = 0;
  360. walker.skip = 0;
  361. walker.fn = &tcindex_destroy_element;
  362. tcindex_walk(tp,&walker);
  363. if (p->perfect)
  364. kfree(p->perfect);
  365. if (p->h)
  366. kfree(p->h);
  367. kfree(p);
  368. tp->root = NULL;
  369. MOD_DEC_USE_COUNT;
  370. }
  371. static int tcindex_dump(struct tcf_proto *tp, unsigned long fh,
  372.     struct sk_buff *skb, struct tcmsg *t)
  373. {
  374. struct tcindex_data *p = PRIV(tp);
  375. struct tcindex_filter_result *r = (struct tcindex_filter_result *) fh;
  376. unsigned char *b = skb->tail;
  377. struct rtattr *rta;
  378. DPRINTK("tcindex_dump(tp %p,fh 0x%lx,skb %p,t %p),p %p,r %p,b %pn",
  379.     tp,fh,skb,t,p,r,b);
  380. DPRINTK("p->perfect %p p->h %pn",p->perfect,p->h);
  381. rta = (struct rtattr *) b;
  382. RTA_PUT(skb,TCA_OPTIONS,0,NULL);
  383. if (!fh) {
  384. t->tcm_handle = ~0; /* whatever ... */
  385. RTA_PUT(skb,TCA_TCINDEX_HASH,sizeof(p->hash),&p->hash);
  386. RTA_PUT(skb,TCA_TCINDEX_MASK,sizeof(p->mask),&p->mask);
  387. RTA_PUT(skb,TCA_TCINDEX_SHIFT,sizeof(p->shift),&p->shift);
  388. RTA_PUT(skb,TCA_TCINDEX_FALL_THROUGH,sizeof(p->fall_through),
  389.     &p->fall_through);
  390. } else {
  391. if (p->perfect) {
  392. t->tcm_handle = r-p->perfect;
  393. } else {
  394. struct tcindex_filter *f;
  395. int i;
  396. t->tcm_handle = 0;
  397. for (i = 0; !t->tcm_handle && i < p->hash; i++) {
  398. for (f = p->h[i]; !t->tcm_handle && f;
  399.      f = f->next) {
  400. if (&f->result == r)
  401. t->tcm_handle = f->key;
  402. }
  403. }
  404. }
  405. DPRINTK("handle = %dn",t->tcm_handle);
  406. if (r->res.class)
  407. RTA_PUT(skb, TCA_TCINDEX_CLASSID, 4, &r->res.classid);
  408. #ifdef CONFIG_NET_CLS_POLICE
  409. if (r->police) {
  410. struct rtattr *p_rta = (struct rtattr *) skb->tail;
  411. RTA_PUT(skb,TCA_TCINDEX_POLICE,0,NULL);
  412. if (tcf_police_dump(skb,r->police) < 0)
  413. goto rtattr_failure;
  414. p_rta->rta_len = skb->tail-(u8 *) p_rta;
  415. }
  416. #endif
  417. }
  418. rta->rta_len = skb->tail-b;
  419. return skb->len;
  420. rtattr_failure:
  421. skb_trim(skb, b - skb->data);
  422. return -1;
  423. }
  424. struct tcf_proto_ops cls_tcindex_ops = {
  425. NULL,
  426. "tcindex",
  427. tcindex_classify,
  428. tcindex_init,
  429. tcindex_destroy,
  430. tcindex_get,
  431. tcindex_put,
  432. tcindex_change,
  433. tcindex_delete,
  434. tcindex_walk,
  435. tcindex_dump
  436. };
  437. #ifdef MODULE
  438. int init_module(void)
  439. {
  440. return register_tcf_proto_ops(&cls_tcindex_ops);
  441. }
  442. void cleanup_module(void) 
  443. {
  444. unregister_tcf_proto_ops(&cls_tcindex_ops);
  445. }
  446. #endif
  447. MODULE_LICENSE("GPL");