cls_fw.c
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:8k
源码类别:

嵌入式Linux

开发平台:

Unix_Linux

  1. /*
  2.  * net/sched/cls_fw.c Classifier mapping ipchains' fwmark to traffic class.
  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.  * Changes:
  12.  * Karlis Peisenieks <karlis@mt.lv> : 990415 : fw_walk off by one
  13.  * Karlis Peisenieks <karlis@mt.lv> : 990415 : fw_delete killed all the filter (and kernel).
  14.  */
  15. #include <linux/config.h>
  16. #include <linux/module.h>
  17. #include <asm/uaccess.h>
  18. #include <asm/system.h>
  19. #include <asm/bitops.h>
  20. #include <linux/types.h>
  21. #include <linux/kernel.h>
  22. #include <linux/sched.h>
  23. #include <linux/string.h>
  24. #include <linux/mm.h>
  25. #include <linux/socket.h>
  26. #include <linux/sockios.h>
  27. #include <linux/in.h>
  28. #include <linux/errno.h>
  29. #include <linux/interrupt.h>
  30. #include <linux/if_ether.h>
  31. #include <linux/inet.h>
  32. #include <linux/netdevice.h>
  33. #include <linux/etherdevice.h>
  34. #include <linux/notifier.h>
  35. #include <linux/netfilter.h>
  36. #include <net/ip.h>
  37. #include <net/route.h>
  38. #include <linux/skbuff.h>
  39. #include <net/sock.h>
  40. #include <net/pkt_sched.h>
  41. struct fw_head
  42. {
  43. struct fw_filter *ht[256];
  44. };
  45. struct fw_filter
  46. {
  47. struct fw_filter *next;
  48. u32 id;
  49. struct tcf_result res;
  50. #ifdef CONFIG_NET_CLS_POLICE
  51. struct tcf_police *police;
  52. #endif
  53. };
  54. static __inline__ int fw_hash(u32 handle)
  55. {
  56. return handle&0xFF;
  57. }
  58. static int fw_classify(struct sk_buff *skb, struct tcf_proto *tp,
  59.   struct tcf_result *res)
  60. {
  61. struct fw_head *head = (struct fw_head*)tp->root;
  62. struct fw_filter *f;
  63. #ifdef CONFIG_NETFILTER
  64. u32 id = skb->nfmark;
  65. #else
  66. u32 id = 0;
  67. #endif
  68. if (head == NULL)
  69. goto old_method;
  70. for (f=head->ht[fw_hash(id)]; f; f=f->next) {
  71. if (f->id == id) {
  72. *res = f->res;
  73. #ifdef CONFIG_NET_CLS_POLICE
  74. if (f->police)
  75. return tcf_police(skb, f->police);
  76. #endif
  77. return 0;
  78. }
  79. }
  80. return -1;
  81. old_method:
  82. if (id && (TC_H_MAJ(id) == 0 ||
  83.      !(TC_H_MAJ(id^tp->q->handle)))) {
  84. res->classid = id;
  85. res->class = 0;
  86. return 0;
  87. }
  88. return -1;
  89. }
  90. static unsigned long fw_get(struct tcf_proto *tp, u32 handle)
  91. {
  92. struct fw_head *head = (struct fw_head*)tp->root;
  93. struct fw_filter *f;
  94. if (head == NULL)
  95. return 0;
  96. for (f=head->ht[fw_hash(handle)]; f; f=f->next) {
  97. if (f->id == handle)
  98. return (unsigned long)f;
  99. }
  100. return 0;
  101. }
  102. static void fw_put(struct tcf_proto *tp, unsigned long f)
  103. {
  104. }
  105. static int fw_init(struct tcf_proto *tp)
  106. {
  107. MOD_INC_USE_COUNT;
  108. return 0;
  109. }
  110. static void fw_destroy(struct tcf_proto *tp)
  111. {
  112. struct fw_head *head = (struct fw_head*)xchg(&tp->root, NULL);
  113. struct fw_filter *f;
  114. int h;
  115. if (head == NULL) {
  116. MOD_DEC_USE_COUNT;
  117. return;
  118. }
  119. for (h=0; h<256; h++) {
  120. while ((f=head->ht[h]) != NULL) {
  121. unsigned long cl;
  122. head->ht[h] = f->next;
  123. if ((cl = __cls_set_class(&f->res.class, 0)) != 0)
  124. tp->q->ops->cl_ops->unbind_tcf(tp->q, cl);
  125. #ifdef CONFIG_NET_CLS_POLICE
  126. tcf_police_release(f->police);
  127. #endif
  128. kfree(f);
  129. }
  130. }
  131. kfree(head);
  132. MOD_DEC_USE_COUNT;
  133. }
  134. static int fw_delete(struct tcf_proto *tp, unsigned long arg)
  135. {
  136. struct fw_head *head = (struct fw_head*)tp->root;
  137. struct fw_filter *f = (struct fw_filter*)arg;
  138. struct fw_filter **fp;
  139. if (head == NULL || f == NULL)
  140. return -EINVAL;
  141. for (fp=&head->ht[fw_hash(f->id)]; *fp; fp = &(*fp)->next) {
  142. if (*fp == f) {
  143. unsigned long cl;
  144. tcf_tree_lock(tp);
  145. *fp = f->next;
  146. tcf_tree_unlock(tp);
  147. if ((cl = cls_set_class(tp, &f->res.class, 0)) != 0)
  148. tp->q->ops->cl_ops->unbind_tcf(tp->q, cl);
  149. #ifdef CONFIG_NET_CLS_POLICE
  150. tcf_police_release(f->police);
  151. #endif
  152. kfree(f);
  153. return 0;
  154. }
  155. }
  156. return -EINVAL;
  157. }
  158. static int fw_change(struct tcf_proto *tp, unsigned long base,
  159.      u32 handle,
  160.      struct rtattr **tca,
  161.      unsigned long *arg)
  162. {
  163. struct fw_head *head = (struct fw_head*)tp->root;
  164. struct fw_filter *f;
  165. struct rtattr *opt = tca[TCA_OPTIONS-1];
  166. struct rtattr *tb[TCA_FW_MAX];
  167. int err;
  168. if (!opt)
  169. return handle ? -EINVAL : 0;
  170. if (rtattr_parse(tb, TCA_FW_MAX, RTA_DATA(opt), RTA_PAYLOAD(opt)) < 0)
  171. return -EINVAL;
  172. if ((f = (struct fw_filter*)*arg) != NULL) {
  173. /* Node exists: adjust only classid */
  174. if (f->id != handle && handle)
  175. return -EINVAL;
  176. if (tb[TCA_FW_CLASSID-1]) {
  177. unsigned long cl;
  178. f->res.classid = *(u32*)RTA_DATA(tb[TCA_FW_CLASSID-1]);
  179. cl = tp->q->ops->cl_ops->bind_tcf(tp->q, base, f->res.classid);
  180. cl = cls_set_class(tp, &f->res.class, cl);
  181. if (cl)
  182. tp->q->ops->cl_ops->unbind_tcf(tp->q, cl);
  183. }
  184. #ifdef CONFIG_NET_CLS_POLICE
  185. if (tb[TCA_FW_POLICE-1]) {
  186. struct tcf_police *police = tcf_police_locate(tb[TCA_FW_POLICE-1], tca[TCA_RATE-1]);
  187. tcf_tree_lock(tp);
  188. police = xchg(&f->police, police);
  189. tcf_tree_unlock(tp);
  190. tcf_police_release(police);
  191. }
  192. #endif
  193. return 0;
  194. }
  195. if (!handle)
  196. return -EINVAL;
  197. if (head == NULL) {
  198. head = kmalloc(sizeof(struct fw_head), GFP_KERNEL);
  199. if (head == NULL)
  200. return -ENOBUFS;
  201. memset(head, 0, sizeof(*head));
  202. tcf_tree_lock(tp);
  203. tp->root = head;
  204. tcf_tree_unlock(tp);
  205. }
  206. f = kmalloc(sizeof(struct fw_filter), GFP_KERNEL);
  207. if (f == NULL)
  208. return -ENOBUFS;
  209. memset(f, 0, sizeof(*f));
  210. f->id = handle;
  211. if (tb[TCA_FW_CLASSID-1]) {
  212. err = -EINVAL;
  213. if (RTA_PAYLOAD(tb[TCA_FW_CLASSID-1]) != 4)
  214. goto errout;
  215. f->res.classid = *(u32*)RTA_DATA(tb[TCA_FW_CLASSID-1]);
  216. cls_set_class(tp, &f->res.class, tp->q->ops->cl_ops->bind_tcf(tp->q, base, f->res.classid));
  217. }
  218. #ifdef CONFIG_NET_CLS_POLICE
  219. if (tb[TCA_FW_POLICE-1])
  220. f->police = tcf_police_locate(tb[TCA_FW_POLICE-1], tca[TCA_RATE-1]);
  221. #endif
  222. f->next = head->ht[fw_hash(handle)];
  223. tcf_tree_lock(tp);
  224. head->ht[fw_hash(handle)] = f;
  225. tcf_tree_unlock(tp);
  226. *arg = (unsigned long)f;
  227. return 0;
  228. errout:
  229. if (f)
  230. kfree(f);
  231. return err;
  232. }
  233. static void fw_walk(struct tcf_proto *tp, struct tcf_walker *arg)
  234. {
  235. struct fw_head *head = (struct fw_head*)tp->root;
  236. int h;
  237. if (head == NULL)
  238. arg->stop = 1;
  239. if (arg->stop)
  240. return;
  241. for (h = 0; h < 256; h++) {
  242. struct fw_filter *f;
  243. for (f = head->ht[h]; f; f = f->next) {
  244. if (arg->count < arg->skip) {
  245. arg->count++;
  246. continue;
  247. }
  248. if (arg->fn(tp, (unsigned long)f, arg) < 0) {
  249. arg->stop = 1;
  250. break;
  251. }
  252. arg->count++;
  253. }
  254. }
  255. }
  256. static int fw_dump(struct tcf_proto *tp, unsigned long fh,
  257.    struct sk_buff *skb, struct tcmsg *t)
  258. {
  259. struct fw_filter *f = (struct fw_filter*)fh;
  260. unsigned char  *b = skb->tail;
  261. struct rtattr *rta;
  262. if (f == NULL)
  263. return skb->len;
  264. t->tcm_handle = f->id;
  265.        if (!f->res.classid
  266. #ifdef CONFIG_NET_CLS_POLICE
  267.            && !f->police
  268. #endif
  269.            )
  270. return skb->len;
  271. rta = (struct rtattr*)b;
  272. RTA_PUT(skb, TCA_OPTIONS, 0, NULL);
  273. if (f->res.classid)
  274. RTA_PUT(skb, TCA_FW_CLASSID, 4, &f->res.classid);
  275. #ifdef CONFIG_NET_CLS_POLICE
  276. if (f->police) {
  277. struct rtattr * p_rta = (struct rtattr*)skb->tail;
  278. RTA_PUT(skb, TCA_FW_POLICE, 0, NULL);
  279. if (tcf_police_dump(skb, f->police) < 0)
  280. goto rtattr_failure;
  281. p_rta->rta_len = skb->tail - (u8*)p_rta;
  282. }
  283. #endif
  284. rta->rta_len = skb->tail - b;
  285. #ifdef CONFIG_NET_CLS_POLICE
  286. if (f->police) {
  287. if (qdisc_copy_stats(skb, &f->police->stats))
  288. goto rtattr_failure;
  289. }
  290. #endif
  291. return skb->len;
  292. rtattr_failure:
  293. skb_trim(skb, b - skb->data);
  294. return -1;
  295. }
  296. struct tcf_proto_ops cls_fw_ops = {
  297. NULL,
  298. "fw",
  299. fw_classify,
  300. fw_init,
  301. fw_destroy,
  302. fw_get,
  303. fw_put,
  304. fw_change,
  305. fw_delete,
  306. fw_walk,
  307. fw_dump
  308. };
  309. #ifdef MODULE
  310. int init_module(void)
  311. {
  312. return register_tcf_proto_ops(&cls_fw_ops);
  313. }
  314. void cleanup_module(void) 
  315. {
  316. unregister_tcf_proto_ops(&cls_fw_ops);
  317. }
  318. #endif
  319. MODULE_LICENSE("GPL");