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

Linux/Unix编程

开发平台:

Unix_Linux

  1. /* net/sched/sch_ingress.c - Ingress qdisc 
  2.  *              This program is free software; you can redistribute it and/or
  3.  *              modify it under the terms of the GNU General Public License
  4.  *              as published by the Free Software Foundation; either version
  5.  *              2 of the License, or (at your option) any later version.
  6.  *
  7.  * Authors:     Jamal Hadi Salim 1999
  8.  */
  9. #include <linux/config.h>
  10. #include <linux/module.h>
  11. #include <linux/types.h>
  12. #include <linux/skbuff.h>
  13. #include <linux/netdevice.h>
  14. #include <linux/rtnetlink.h>
  15. #include <linux/netfilter_ipv4.h>
  16. #include <linux/netfilter.h>
  17. #include <net/pkt_sched.h>
  18. #include <asm/byteorder.h>
  19. #include <asm/uaccess.h>
  20. #include <asm/smp.h>
  21. #include <linux/kmod.h>
  22. #include <linux/stat.h>
  23. #include <linux/interrupt.h>
  24. #include <linux/list.h>
  25. #undef DEBUG_INGRESS
  26. #ifdef DEBUG_INGRESS  /* control */
  27. #define DPRINTK(format,args...) printk(KERN_DEBUG format,##args)
  28. #else
  29. #define DPRINTK(format,args...)
  30. #endif
  31. #if 0  /* data */
  32. #define D2PRINTK(format,args...) printk(KERN_DEBUG format,##args)
  33. #else
  34. #define D2PRINTK(format,args...)
  35. #endif
  36. #define PRIV(sch) ((struct ingress_qdisc_data *) (sch)->data)
  37. /* Thanks to Doron Oz for this hack
  38. */
  39. static int nf_registered = 0; 
  40. struct ingress_qdisc_data {
  41. struct Qdisc *q;
  42. struct tcf_proto *filter_list;
  43. };
  44. /* ------------------------- Class/flow operations ------------------------- */
  45. static int ingress_graft(struct Qdisc *sch,unsigned long arg,
  46.     struct Qdisc *new,struct Qdisc **old)
  47. {
  48. #ifdef DEBUG_INGRESS
  49. struct ingress_qdisc_data *p = PRIV(sch);
  50. #endif
  51. DPRINTK("ingress_graft(sch %p,[qdisc %p],new %p,old %p)n",
  52. sch, p, new, old);
  53. DPRINTK("n ingress_graft: You cannot add qdiscs to classes");
  54.         return 1;
  55. }
  56. static struct Qdisc *ingress_leaf(struct Qdisc *sch, unsigned long arg)
  57. {
  58. return NULL;
  59. }
  60. static unsigned long ingress_get(struct Qdisc *sch,u32 classid)
  61. {
  62. #ifdef DEBUG_INGRESS
  63. struct ingress_qdisc_data *p = PRIV(sch);
  64. #endif
  65. DPRINTK("ingress_get(sch %p,[qdisc %p],classid %x)n", sch, p, classid);
  66. return TC_H_MIN(classid) + 1;
  67. }
  68. static unsigned long ingress_bind_filter(struct Qdisc *sch,
  69.     unsigned long parent, u32 classid)
  70. {
  71. return ingress_get(sch, classid);
  72. }
  73. static void ingress_put(struct Qdisc *sch, unsigned long cl)
  74. {
  75. }
  76. static int ingress_change(struct Qdisc *sch, u32 classid, u32 parent,
  77.     struct rtattr **tca, unsigned long *arg)
  78. {
  79. #ifdef DEBUG_INGRESS
  80. struct ingress_qdisc_data *p = PRIV(sch);
  81. #endif
  82. DPRINTK("ingress_change(sch %p,[qdisc %p],classid %x,parent %x),"
  83. "arg 0x%lxn", sch, p, classid, parent, *arg);
  84. DPRINTK("No effect. sch_ingress doesn't maintain classes at the moment");
  85. return 0;
  86. }
  87. static void ingress_walk(struct Qdisc *sch,struct qdisc_walker *walker)
  88. {
  89. #ifdef DEBUG_INGRESS
  90. struct ingress_qdisc_data *p = PRIV(sch);
  91. #endif
  92. DPRINTK("ingress_walk(sch %p,[qdisc %p],walker %p)n", sch, p, walker);
  93. DPRINTK("No effect. sch_ingress doesn't maintain classes at the moment");
  94. }
  95. static struct tcf_proto **ingress_find_tcf(struct Qdisc *sch,unsigned long cl)
  96. {
  97. struct ingress_qdisc_data *p = PRIV(sch);
  98. return &p->filter_list;
  99. }
  100. /* --------------------------- Qdisc operations ---------------------------- */
  101. static int ingress_enqueue(struct sk_buff *skb,struct Qdisc *sch)
  102. {
  103. struct ingress_qdisc_data *p = PRIV(sch);
  104. struct tcf_result res;
  105. int result;
  106. D2PRINTK("ingress_enqueue(skb %p,sch %p,[qdisc %p])n", skb, sch, p);
  107. result = tc_classify(skb, p->filter_list, &res);
  108. D2PRINTK("result %d class 0x%04xn", result, res.classid);
  109. /*
  110.  * Unlike normal "enqueue" functions, ingress_enqueue returns a
  111.  * firewall FW_* code.
  112.  */
  113. #ifdef CONFIG_NET_CLS_POLICE
  114. switch (result) {
  115. case TC_POLICE_SHOT:
  116. result = NF_DROP;
  117. sch->stats.drops++;
  118. break;
  119. case TC_POLICE_RECLASSIFY: /* DSCP remarking here ? */
  120. case TC_POLICE_OK:
  121. case TC_POLICE_UNSPEC:
  122. default:
  123. sch->stats.packets++;
  124. sch->stats.bytes += skb->len;
  125. result = NF_ACCEPT;
  126. break;
  127. };
  128. #else
  129. sch->stats.packets++;
  130. sch->stats.bytes += skb->len;
  131. #endif
  132. skb->tc_index = TC_H_MIN(res.classid);
  133. return result;
  134. }
  135. static struct sk_buff *ingress_dequeue(struct Qdisc *sch)
  136. {
  137. /*
  138. struct ingress_qdisc_data *p = PRIV(sch);
  139. D2PRINTK("ingress_dequeue(sch %p,[qdisc %p])n",sch,PRIV(p));
  140. */
  141. return NULL;
  142. }
  143. static int ingress_requeue(struct sk_buff *skb,struct Qdisc *sch)
  144. {
  145. /*
  146. struct ingress_qdisc_data *p = PRIV(sch);
  147. D2PRINTK("ingress_requeue(skb %p,sch %p,[qdisc %p])n",skb,sch,PRIV(p));
  148. */
  149. return 0;
  150. }
  151. static int ingress_drop(struct Qdisc *sch)
  152. {
  153. #ifdef DEBUG_INGRESS
  154. struct ingress_qdisc_data *p = PRIV(sch);
  155. #endif
  156. DPRINTK("ingress_drop(sch %p,[qdisc %p])n", sch, p);
  157. return 0;
  158. }
  159. static unsigned int
  160. ing_hook(unsigned int hook, struct sk_buff **pskb,
  161.                              const struct net_device *indev,
  162.                              const struct net_device *outdev,
  163.                      int (*okfn)(struct sk_buff *))
  164. {
  165. struct Qdisc *q;
  166. struct sk_buff *skb = *pskb;
  167.         struct net_device *dev = skb->dev;
  168. int fwres=NF_ACCEPT;
  169. DPRINTK("ing_hook: skb %s dev=%s len=%un",
  170. skb->sk ? "(owned)" : "(unowned)",
  171. skb->dev ? (*pskb)->dev->name : "(no dev)",
  172. skb->len);
  173. /* 
  174. revisit later: Use a private since lock dev->queue_lock is also
  175. used on the egress (might slow things for an iota)
  176. */
  177. if (dev->qdisc_ingress) {
  178. spin_lock(&dev->queue_lock);
  179. if ((q = dev->qdisc_ingress) != NULL)
  180. fwres = q->enqueue(skb, q);
  181. spin_unlock(&dev->queue_lock);
  182.         }
  183. return fwres;
  184. }
  185. /* after ipt_filter */
  186. static struct nf_hook_ops ing_ops =
  187. {
  188. { NULL, NULL},
  189. ing_hook,
  190. PF_INET,
  191. NF_IP_PRE_ROUTING,
  192. NF_IP_PRI_FILTER + 1
  193. };
  194. int ingress_init(struct Qdisc *sch,struct rtattr *opt)
  195. {
  196. struct ingress_qdisc_data *p = PRIV(sch);
  197. if (!nf_registered) {
  198. if (nf_register_hook(&ing_ops) < 0) {
  199. printk("ingress qdisc registration error n");
  200. goto error;
  201. }
  202. nf_registered++;
  203. }
  204. DPRINTK("ingress_init(sch %p,[qdisc %p],opt %p)n",sch,p,opt);
  205. memset(p, 0, sizeof(*p));
  206. p->filter_list = NULL;
  207. p->q = &noop_qdisc;
  208. MOD_INC_USE_COUNT;
  209. return 0;
  210. error:
  211. return -EINVAL;
  212. }
  213. static void ingress_reset(struct Qdisc *sch)
  214. {
  215. struct ingress_qdisc_data *p = PRIV(sch);
  216. DPRINTK("ingress_reset(sch %p,[qdisc %p])n", sch, p);
  217. /*
  218. #if 0
  219. */
  220. /* for future use */
  221. qdisc_reset(p->q);
  222. /*
  223. #endif
  224. */
  225. }
  226. /* ------------------------------------------------------------- */
  227. /* ------------------------------------------------------------- */
  228. static void ingress_destroy(struct Qdisc *sch)
  229. {
  230. struct ingress_qdisc_data *p = PRIV(sch);
  231. struct tcf_proto *tp;
  232. DPRINTK("ingress_destroy(sch %p,[qdisc %p])n", sch, p);
  233. while (p->filter_list) {
  234. tp = p->filter_list;
  235. p->filter_list = tp->next;
  236. tp->ops->destroy(tp);
  237. }
  238. memset(p, 0, sizeof(*p));
  239. p->filter_list = NULL;
  240. #if 0
  241. /* for future use */
  242. qdisc_destroy(p->q);
  243. #endif
  244.  
  245. MOD_DEC_USE_COUNT;
  246. }
  247. static int ingress_dump(struct Qdisc *sch, struct sk_buff *skb)
  248. {
  249. unsigned char *b = skb->tail;
  250. struct rtattr *rta;
  251. rta = (struct rtattr *) b;
  252. RTA_PUT(skb, TCA_OPTIONS, 0, NULL);
  253. rta->rta_len = skb->tail - b;
  254. return skb->len;
  255. rtattr_failure:
  256. skb_trim(skb, b - skb->data);
  257. return -1;
  258. }
  259. static struct Qdisc_class_ops ingress_class_ops =
  260. {
  261. ingress_graft, /* graft */
  262. ingress_leaf, /* leaf */
  263. ingress_get, /* get */
  264. ingress_put, /* put */
  265. ingress_change, /* change */
  266. NULL, /* delete */
  267. ingress_walk, /* walk */
  268. ingress_find_tcf, /* tcf_chain */
  269. ingress_bind_filter, /* bind_tcf */
  270. ingress_put, /* unbind_tcf */
  271. NULL, /* dump */
  272. };
  273. struct Qdisc_ops ingress_qdisc_ops =
  274. {
  275. NULL, /* next */
  276. &ingress_class_ops, /* cl_ops */
  277. "ingress",
  278. sizeof(struct ingress_qdisc_data),
  279. ingress_enqueue, /* enqueue */
  280. ingress_dequeue, /* dequeue */
  281. ingress_requeue, /* requeue */
  282. ingress_drop, /* drop */
  283. ingress_init, /* init */
  284. ingress_reset, /* reset */
  285. ingress_destroy, /* destroy */
  286. NULL, /* change */
  287. ingress_dump, /* dump */
  288. };
  289. #ifdef MODULE
  290. int init_module(void)
  291. {
  292. int ret = 0;
  293. if ((ret = register_qdisc(&ingress_qdisc_ops)) < 0) {
  294. printk("Unable to register Ingress qdiscn");
  295. return ret;
  296. }
  297. return ret;
  298. }
  299. void cleanup_module(void) 
  300. {
  301. unregister_qdisc(&ingress_qdisc_ops);
  302. if (nf_registered)
  303. nf_unregister_hook(&ing_ops);
  304. }
  305. #endif
  306. MODULE_LICENSE("GPL");