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

Linux/Unix编程

开发平台:

Unix_Linux

  1. /*
  2.  * net/sched/cls_u32.c Ugly (or Universal) 32bit key Packet Classifier.
  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.  * The filters are packed to hash tables of key nodes
  12.  * with a set of 32bit key/mask pairs at every node.
  13.  * Nodes reference next level hash tables etc.
  14.  *
  15.  * This scheme is the best universal classifier I managed to
  16.  * invent; it is not super-fast, but it is not slow (provided you
  17.  * program it correctly), and general enough.  And its relative
  18.  * speed grows as the number of rules becomes larger.
  19.  *
  20.  * It seems that it represents the best middle point between
  21.  * speed and manageability both by human and by machine.
  22.  *
  23.  * It is especially useful for link sharing combined with QoS;
  24.  * pure RSVP doesn't need such a general approach and can use
  25.  * much simpler (and faster) schemes, sort of cls_rsvp.c.
  26.  */
  27. #include <asm/uaccess.h>
  28. #include <asm/system.h>
  29. #include <asm/bitops.h>
  30. #include <linux/config.h>
  31. #include <linux/module.h>
  32. #include <linux/types.h>
  33. #include <linux/kernel.h>
  34. #include <linux/sched.h>
  35. #include <linux/string.h>
  36. #include <linux/mm.h>
  37. #include <linux/socket.h>
  38. #include <linux/sockios.h>
  39. #include <linux/in.h>
  40. #include <linux/errno.h>
  41. #include <linux/interrupt.h>
  42. #include <linux/if_ether.h>
  43. #include <linux/inet.h>
  44. #include <linux/netdevice.h>
  45. #include <linux/etherdevice.h>
  46. #include <linux/notifier.h>
  47. #include <linux/rtnetlink.h>
  48. #include <net/ip.h>
  49. #include <net/route.h>
  50. #include <linux/skbuff.h>
  51. #include <net/sock.h>
  52. #include <net/pkt_sched.h>
  53. struct tc_u_knode
  54. {
  55. struct tc_u_knode *next;
  56. u32 handle;
  57. struct tc_u_hnode *ht_up;
  58. #ifdef CONFIG_NET_CLS_POLICE
  59. struct tcf_police *police;
  60. #endif
  61. struct tcf_result res;
  62. struct tc_u_hnode *ht_down;
  63. struct tc_u32_sel sel;
  64. };
  65. struct tc_u_hnode
  66. {
  67. struct tc_u_hnode *next;
  68. u32 handle;
  69. struct tc_u_common *tp_c;
  70. int refcnt;
  71. unsigned divisor;
  72. u32 hgenerator;
  73. struct tc_u_knode *ht[1];
  74. };
  75. struct tc_u_common
  76. {
  77. struct tc_u_common *next;
  78. struct tc_u_hnode *hlist;
  79. struct Qdisc *q;
  80. int refcnt;
  81. u32 hgenerator;
  82. };
  83. static struct tc_u_common *u32_list;
  84. static __inline__ unsigned u32_hash_fold(u32 key, struct tc_u32_sel *sel)
  85. {
  86. unsigned h = key & sel->hmask;
  87. h ^= h>>16;
  88. h ^= h>>8;
  89. return h;
  90. }
  91. static int u32_classify(struct sk_buff *skb, struct tcf_proto *tp, struct tcf_result *res)
  92. {
  93. struct {
  94. struct tc_u_knode *knode;
  95. u8   *ptr;
  96. } stack[TC_U32_MAXDEPTH];
  97. struct tc_u_hnode *ht = (struct tc_u_hnode*)tp->root;
  98. u8 *ptr = skb->nh.raw;
  99. struct tc_u_knode *n;
  100. int sdepth = 0;
  101. int off2 = 0;
  102. int sel = 0;
  103. int i;
  104. #if !defined(__i386__) && !defined(__mc68000__)
  105. if ((unsigned long)ptr & 3)
  106. return -1;
  107. #endif
  108. next_ht:
  109. n = ht->ht[sel];
  110. next_knode:
  111. if (n) {
  112. struct tc_u32_key *key = n->sel.keys;
  113. for (i = n->sel.nkeys; i>0; i--, key++) {
  114. if ((*(u32*)(ptr+key->off+(off2&key->offmask))^key->val)&key->mask) {
  115. n = n->next;
  116. goto next_knode;
  117. }
  118. }
  119. if (n->ht_down == NULL) {
  120. check_terminal:
  121. if (n->sel.flags&TC_U32_TERMINAL) {
  122. *res = n->res;
  123. #ifdef CONFIG_NET_CLS_POLICE
  124. if (n->police) {
  125. int pol_res = tcf_police(skb, n->police);
  126. if (pol_res >= 0)
  127. return pol_res;
  128. } else
  129. #endif
  130. return 0;
  131. }
  132. n = n->next;
  133. goto next_knode;
  134. }
  135. /* PUSH */
  136. if (sdepth >= TC_U32_MAXDEPTH)
  137. goto deadloop;
  138. stack[sdepth].knode = n;
  139. stack[sdepth].ptr = ptr;
  140. sdepth++;
  141. ht = n->ht_down;
  142. sel = 0;
  143. if (ht->divisor)
  144. sel = ht->divisor&u32_hash_fold(*(u32*)(ptr+n->sel.hoff), &n->sel);
  145. if (!(n->sel.flags&(TC_U32_VAROFFSET|TC_U32_OFFSET|TC_U32_EAT)))
  146. goto next_ht;
  147. if (n->sel.flags&(TC_U32_OFFSET|TC_U32_VAROFFSET)) {
  148. off2 = n->sel.off + 3;
  149. if (n->sel.flags&TC_U32_VAROFFSET)
  150. off2 += ntohs(n->sel.offmask & *(u16*)(ptr+n->sel.offoff)) >>n->sel.offshift;
  151. off2 &= ~3;
  152. }
  153. if (n->sel.flags&TC_U32_EAT) {
  154. ptr += off2;
  155. off2 = 0;
  156. }
  157. if (ptr < skb->tail)
  158. goto next_ht;
  159. }
  160. /* POP */
  161. if (sdepth--) {
  162. n = stack[sdepth].knode;
  163. ht = n->ht_up;
  164. ptr = stack[sdepth].ptr;
  165. goto check_terminal;
  166. }
  167. return -1;
  168. deadloop:
  169. if (net_ratelimit())
  170. printk("cls_u32: dead loopn");
  171. return -1;
  172. }
  173. static __inline__ struct tc_u_hnode *
  174. u32_lookup_ht(struct tc_u_common *tp_c, u32 handle)
  175. {
  176. struct tc_u_hnode *ht;
  177. for (ht = tp_c->hlist; ht; ht = ht->next)
  178. if (ht->handle == handle)
  179. break;
  180. return ht;
  181. }
  182. static __inline__ struct tc_u_knode *
  183. u32_lookup_key(struct tc_u_hnode *ht, u32 handle)
  184. {
  185. unsigned sel;
  186. struct tc_u_knode *n;
  187. sel = TC_U32_HASH(handle);
  188. if (sel > ht->divisor)
  189. return 0;
  190. for (n = ht->ht[sel]; n; n = n->next)
  191. if (n->handle == handle)
  192. return n;
  193. return NULL;
  194. }
  195. static unsigned long u32_get(struct tcf_proto *tp, u32 handle)
  196. {
  197. struct tc_u_hnode *ht;
  198. struct tc_u_common *tp_c = tp->data;
  199. if (TC_U32_HTID(handle) == TC_U32_ROOT)
  200. ht = tp->root;
  201. else
  202. ht = u32_lookup_ht(tp_c, TC_U32_HTID(handle));
  203. if (!ht)
  204. return 0;
  205. if (TC_U32_KEY(handle) == 0)
  206. return (unsigned long)ht;
  207. return (unsigned long)u32_lookup_key(ht, handle);
  208. }
  209. static void u32_put(struct tcf_proto *tp, unsigned long f)
  210. {
  211. }
  212. static u32 gen_new_htid(struct tc_u_common *tp_c)
  213. {
  214. int i = 0x800;
  215. do {
  216. if (++tp_c->hgenerator == 0x7FF)
  217. tp_c->hgenerator = 1;
  218. } while (--i>0 && u32_lookup_ht(tp_c, (tp_c->hgenerator|0x800)<<20));
  219. return i > 0 ? (tp_c->hgenerator|0x800)<<20 : 0;
  220. }
  221. static int u32_init(struct tcf_proto *tp)
  222. {
  223. struct tc_u_hnode *root_ht;
  224. struct tc_u_common *tp_c;
  225. MOD_INC_USE_COUNT;
  226. for (tp_c = u32_list; tp_c; tp_c = tp_c->next)
  227. if (tp_c->q == tp->q)
  228. break;
  229. root_ht = kmalloc(sizeof(*root_ht), GFP_KERNEL);
  230. if (root_ht == NULL) {
  231. MOD_DEC_USE_COUNT;
  232. return -ENOBUFS;
  233. }
  234. memset(root_ht, 0, sizeof(*root_ht));
  235. root_ht->divisor = 0;
  236. root_ht->refcnt++;
  237. root_ht->handle = tp_c ? gen_new_htid(tp_c) : 0x80000000;
  238. if (tp_c == NULL) {
  239. tp_c = kmalloc(sizeof(*tp_c), GFP_KERNEL);
  240. if (tp_c == NULL) {
  241. kfree(root_ht);
  242. MOD_DEC_USE_COUNT;
  243. return -ENOBUFS;
  244. }
  245. memset(tp_c, 0, sizeof(*tp_c));
  246. tp_c->q = tp->q;
  247. tp_c->next = u32_list;
  248. u32_list = tp_c;
  249. }
  250. tp_c->refcnt++;
  251. root_ht->next = tp_c->hlist;
  252. tp_c->hlist = root_ht;
  253. root_ht->tp_c = tp_c;
  254. tp->root = root_ht;
  255. tp->data = tp_c;
  256. return 0;
  257. }
  258. static int u32_destroy_key(struct tcf_proto *tp, struct tc_u_knode *n)
  259. {
  260. unsigned long cl;
  261. if ((cl = __cls_set_class(&n->res.class, 0)) != 0)
  262. tp->q->ops->cl_ops->unbind_tcf(tp->q, cl);
  263. #ifdef CONFIG_NET_CLS_POLICE
  264. tcf_police_release(n->police);
  265. #endif
  266. if (n->ht_down)
  267. n->ht_down->refcnt--;
  268. kfree(n);
  269. return 0;
  270. }
  271. static int u32_delete_key(struct tcf_proto *tp, struct tc_u_knode* key)
  272. {
  273. struct tc_u_knode **kp;
  274. struct tc_u_hnode *ht = key->ht_up;
  275. if (ht) {
  276. for (kp = &ht->ht[TC_U32_HASH(key->handle)]; *kp; kp = &(*kp)->next) {
  277. if (*kp == key) {
  278. tcf_tree_lock(tp);
  279. *kp = key->next;
  280. tcf_tree_unlock(tp);
  281. u32_destroy_key(tp, key);
  282. return 0;
  283. }
  284. }
  285. }
  286. BUG_TRAP(0);
  287. return 0;
  288. }
  289. static void u32_clear_hnode(struct tcf_proto *tp, struct tc_u_hnode *ht)
  290. {
  291. struct tc_u_knode *n;
  292. unsigned h;
  293. for (h=0; h<=ht->divisor; h++) {
  294. while ((n = ht->ht[h]) != NULL) {
  295. ht->ht[h] = n->next;
  296. u32_destroy_key(tp, n);
  297. }
  298. }
  299. }
  300. static int u32_destroy_hnode(struct tcf_proto *tp, struct tc_u_hnode *ht)
  301. {
  302. struct tc_u_common *tp_c = tp->data;
  303. struct tc_u_hnode **hn;
  304. BUG_TRAP(!ht->refcnt);
  305. u32_clear_hnode(tp, ht);
  306. for (hn = &tp_c->hlist; *hn; hn = &(*hn)->next) {
  307. if (*hn == ht) {
  308. *hn = ht->next;
  309. kfree(ht);
  310. return 0;
  311. }
  312. }
  313. BUG_TRAP(0);
  314. return -ENOENT;
  315. }
  316. static void u32_destroy(struct tcf_proto *tp)
  317. {
  318. struct tc_u_common *tp_c = tp->data;
  319. struct tc_u_hnode *root_ht = xchg(&tp->root, NULL);
  320. BUG_TRAP(root_ht != NULL);
  321. if (root_ht && --root_ht->refcnt == 0)
  322. u32_destroy_hnode(tp, root_ht);
  323. if (--tp_c->refcnt == 0) {
  324. struct tc_u_hnode *ht;
  325. struct tc_u_common **tp_cp;
  326. for (tp_cp = &u32_list; *tp_cp; tp_cp = &(*tp_cp)->next) {
  327. if (*tp_cp == tp_c) {
  328. *tp_cp = tp_c->next;
  329. break;
  330. }
  331. }
  332. for (ht=tp_c->hlist; ht; ht = ht->next)
  333. u32_clear_hnode(tp, ht);
  334. while ((ht = tp_c->hlist) != NULL) {
  335. tp_c->hlist = ht->next;
  336. BUG_TRAP(ht->refcnt == 0);
  337. kfree(ht);
  338. };
  339. kfree(tp_c);
  340. }
  341. MOD_DEC_USE_COUNT;
  342. tp->data = NULL;
  343. }
  344. static int u32_delete(struct tcf_proto *tp, unsigned long arg)
  345. {
  346. struct tc_u_hnode *ht = (struct tc_u_hnode*)arg;
  347. if (ht == NULL)
  348. return 0;
  349. if (TC_U32_KEY(ht->handle))
  350. return u32_delete_key(tp, (struct tc_u_knode*)ht);
  351. if (tp->root == ht)
  352. return -EINVAL;
  353. if (--ht->refcnt == 0)
  354. u32_destroy_hnode(tp, ht);
  355. return 0;
  356. }
  357. static u32 gen_new_kid(struct tc_u_hnode *ht, u32 handle)
  358. {
  359. struct tc_u_knode *n;
  360. unsigned i = 0x7FF;
  361. for (n=ht->ht[TC_U32_HASH(handle)]; n; n = n->next)
  362. if (i < TC_U32_NODE(n->handle))
  363. i = TC_U32_NODE(n->handle);
  364. i++;
  365. return handle|(i>0xFFF ? 0xFFF : i);
  366. }
  367. static int u32_set_parms(struct Qdisc *q, unsigned long base,
  368.  struct tc_u_hnode *ht,
  369.  struct tc_u_knode *n, struct rtattr **tb,
  370.  struct rtattr *est)
  371. {
  372. if (tb[TCA_U32_LINK-1]) {
  373. u32 handle = *(u32*)RTA_DATA(tb[TCA_U32_LINK-1]);
  374. struct tc_u_hnode *ht_down = NULL;
  375. if (TC_U32_KEY(handle))
  376. return -EINVAL;
  377. if (handle) {
  378. ht_down = u32_lookup_ht(ht->tp_c, handle);
  379. if (ht_down == NULL)
  380. return -EINVAL;
  381. ht_down->refcnt++;
  382. }
  383. sch_tree_lock(q);
  384. ht_down = xchg(&n->ht_down, ht_down);
  385. sch_tree_unlock(q);
  386. if (ht_down)
  387. ht_down->refcnt--;
  388. }
  389. if (tb[TCA_U32_CLASSID-1]) {
  390. unsigned long cl;
  391. n->res.classid = *(u32*)RTA_DATA(tb[TCA_U32_CLASSID-1]);
  392. sch_tree_lock(q);
  393. cl = __cls_set_class(&n->res.class, q->ops->cl_ops->bind_tcf(q, base, n->res.classid));
  394. sch_tree_unlock(q);
  395. if (cl)
  396. q->ops->cl_ops->unbind_tcf(q, cl);
  397. }
  398. #ifdef CONFIG_NET_CLS_POLICE
  399. if (tb[TCA_U32_POLICE-1]) {
  400. struct tcf_police *police = tcf_police_locate(tb[TCA_U32_POLICE-1], est);
  401. sch_tree_lock(q);
  402. police = xchg(&n->police, police);
  403. sch_tree_unlock(q);
  404. tcf_police_release(police);
  405. }
  406. #endif
  407. return 0;
  408. }
  409. static int u32_change(struct tcf_proto *tp, unsigned long base, u32 handle,
  410.       struct rtattr **tca,
  411.       unsigned long *arg)
  412. {
  413. struct tc_u_common *tp_c = tp->data;
  414. struct tc_u_hnode *ht;
  415. struct tc_u_knode *n;
  416. struct tc_u32_sel *s;
  417. struct rtattr *opt = tca[TCA_OPTIONS-1];
  418. struct rtattr *tb[TCA_U32_MAX];
  419. u32 htid;
  420. int err;
  421. if (opt == NULL)
  422. return handle ? -EINVAL : 0;
  423. if (rtattr_parse(tb, TCA_U32_MAX, RTA_DATA(opt), RTA_PAYLOAD(opt)) < 0)
  424. return -EINVAL;
  425. if ((n = (struct tc_u_knode*)*arg) != NULL) {
  426. if (TC_U32_KEY(n->handle) == 0)
  427. return -EINVAL;
  428. return u32_set_parms(tp->q, base, n->ht_up, n, tb, tca[TCA_RATE-1]);
  429. }
  430. if (tb[TCA_U32_DIVISOR-1]) {
  431. unsigned divisor = *(unsigned*)RTA_DATA(tb[TCA_U32_DIVISOR-1]);
  432. if (--divisor > 0x100)
  433. return -EINVAL;
  434. if (TC_U32_KEY(handle))
  435. return -EINVAL;
  436. if (handle == 0) {
  437. handle = gen_new_htid(tp->data);
  438. if (handle == 0)
  439. return -ENOMEM;
  440. }
  441. ht = kmalloc(sizeof(*ht) + divisor*sizeof(void*), GFP_KERNEL);
  442. if (ht == NULL)
  443. return -ENOBUFS;
  444. memset(ht, 0, sizeof(*ht) + divisor*sizeof(void*));
  445. ht->tp_c = tp_c;
  446. ht->refcnt = 0;
  447. ht->divisor = divisor;
  448. ht->handle = handle;
  449. ht->next = tp_c->hlist;
  450. tp_c->hlist = ht;
  451. *arg = (unsigned long)ht;
  452. return 0;
  453. }
  454. if (tb[TCA_U32_HASH-1]) {
  455. htid = *(unsigned*)RTA_DATA(tb[TCA_U32_HASH-1]);
  456. if (TC_U32_HTID(htid) == TC_U32_ROOT) {
  457. ht = tp->root;
  458. htid = ht->handle;
  459. } else {
  460. ht = u32_lookup_ht(tp->data, TC_U32_HTID(htid));
  461. if (ht == NULL)
  462. return -EINVAL;
  463. }
  464. } else {
  465. ht = tp->root;
  466. htid = ht->handle;
  467. }
  468. if (ht->divisor < TC_U32_HASH(htid))
  469. return -EINVAL;
  470. if (handle) {
  471. if (TC_U32_HTID(handle) && TC_U32_HTID(handle^htid))
  472. return -EINVAL;
  473. handle = htid | TC_U32_NODE(handle);
  474. } else
  475. handle = gen_new_kid(ht, htid);
  476. if (tb[TCA_U32_SEL-1] == 0 ||
  477.     RTA_PAYLOAD(tb[TCA_U32_SEL-1]) < sizeof(struct tc_u32_sel))
  478. return -EINVAL;
  479. s = RTA_DATA(tb[TCA_U32_SEL-1]);
  480. n = kmalloc(sizeof(*n) + s->nkeys*sizeof(struct tc_u32_key), GFP_KERNEL);
  481. if (n == NULL)
  482. return -ENOBUFS;
  483. memset(n, 0, sizeof(*n) + s->nkeys*sizeof(struct tc_u32_key));
  484. memcpy(&n->sel, s, sizeof(*s) + s->nkeys*sizeof(struct tc_u32_key));
  485. n->ht_up = ht;
  486. n->handle = handle;
  487. err = u32_set_parms(tp->q, base, ht, n, tb, tca[TCA_RATE-1]);
  488. if (err == 0) {
  489. struct tc_u_knode **ins;
  490. for (ins = &ht->ht[TC_U32_HASH(handle)]; *ins; ins = &(*ins)->next)
  491. if (TC_U32_NODE(handle) < TC_U32_NODE((*ins)->handle))
  492. break;
  493. n->next = *ins;
  494. wmb();
  495. *ins = n;
  496. *arg = (unsigned long)n;
  497. return 0;
  498. }
  499. kfree(n);
  500. return err;
  501. }
  502. static void u32_walk(struct tcf_proto *tp, struct tcf_walker *arg)
  503. {
  504. struct tc_u_common *tp_c = tp->data;
  505. struct tc_u_hnode *ht;
  506. struct tc_u_knode *n;
  507. unsigned h;
  508. if (arg->stop)
  509. return;
  510. for (ht = tp_c->hlist; ht; ht = ht->next) {
  511. if (arg->count >= arg->skip) {
  512. if (arg->fn(tp, (unsigned long)ht, arg) < 0) {
  513. arg->stop = 1;
  514. return;
  515. }
  516. }
  517. arg->count++;
  518. for (h = 0; h <= ht->divisor; h++) {
  519. for (n = ht->ht[h]; n; n = n->next) {
  520. if (arg->count < arg->skip) {
  521. arg->count++;
  522. continue;
  523. }
  524. if (arg->fn(tp, (unsigned long)n, arg) < 0) {
  525. arg->stop = 1;
  526. return;
  527. }
  528. arg->count++;
  529. }
  530. }
  531. }
  532. }
  533. static int u32_dump(struct tcf_proto *tp, unsigned long fh,
  534.      struct sk_buff *skb, struct tcmsg *t)
  535. {
  536. struct tc_u_knode *n = (struct tc_u_knode*)fh;
  537. unsigned char  *b = skb->tail;
  538. struct rtattr *rta;
  539. if (n == NULL)
  540. return skb->len;
  541. t->tcm_handle = n->handle;
  542. rta = (struct rtattr*)b;
  543. RTA_PUT(skb, TCA_OPTIONS, 0, NULL);
  544. if (TC_U32_KEY(n->handle) == 0) {
  545. struct tc_u_hnode *ht = (struct tc_u_hnode*)fh;
  546. u32 divisor = ht->divisor+1;
  547. RTA_PUT(skb, TCA_U32_DIVISOR, 4, &divisor);
  548. } else {
  549. RTA_PUT(skb, TCA_U32_SEL,
  550. sizeof(n->sel) + n->sel.nkeys*sizeof(struct tc_u32_key),
  551. &n->sel);
  552. if (n->ht_up) {
  553. u32 htid = n->handle & 0xFFFFF000;
  554. RTA_PUT(skb, TCA_U32_HASH, 4, &htid);
  555. }
  556. if (n->res.classid)
  557. RTA_PUT(skb, TCA_U32_CLASSID, 4, &n->res.classid);
  558. if (n->ht_down)
  559. RTA_PUT(skb, TCA_U32_LINK, 4, &n->ht_down->handle);
  560. #ifdef CONFIG_NET_CLS_POLICE
  561. if (n->police) {
  562. struct rtattr * p_rta = (struct rtattr*)skb->tail;
  563. RTA_PUT(skb, TCA_U32_POLICE, 0, NULL);
  564. if (tcf_police_dump(skb, n->police) < 0)
  565. goto rtattr_failure;
  566. p_rta->rta_len = skb->tail - (u8*)p_rta;
  567. }
  568. #endif
  569. }
  570. rta->rta_len = skb->tail - b;
  571. #ifdef CONFIG_NET_CLS_POLICE
  572. if (TC_U32_KEY(n->handle) && n->police) {
  573. if (qdisc_copy_stats(skb, &n->police->stats))
  574. goto rtattr_failure;
  575. }
  576. #endif
  577. return skb->len;
  578. rtattr_failure:
  579. skb_trim(skb, b - skb->data);
  580. return -1;
  581. }
  582. struct tcf_proto_ops cls_u32_ops = {
  583. NULL,
  584. "u32",
  585. u32_classify,
  586. u32_init,
  587. u32_destroy,
  588. u32_get,
  589. u32_put,
  590. u32_change,
  591. u32_delete,
  592. u32_walk,
  593. u32_dump
  594. };
  595. #ifdef MODULE
  596. int init_module(void)
  597. {
  598. return register_tcf_proto_ops(&cls_u32_ops);
  599. }
  600. void cleanup_module(void) 
  601. {
  602. unregister_tcf_proto_ops(&cls_u32_ops);
  603. }
  604. #endif
  605. MODULE_LICENSE("GPL");