2 * lib/route/rule.c Routing Rules
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation version 2.1
9 * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch>
14 * @defgroup rule Routing Rules
19 #include <netlink-local.h>
20 #include <netlink/netlink.h>
21 #include <netlink/utils.h>
22 #include <netlink/route/rtnl.h>
23 #include <netlink/route/rule.h>
27 #define RULE_ATTR_FAMILY 0x0001
28 #define RULE_ATTR_PRIO 0x0002
29 #define RULE_ATTR_MARK 0x0004
30 #define RULE_ATTR_IIF 0x0008
31 #define RULE_ATTR_REALMS 0x0010
32 #define RULE_ATTR_SRC 0x0020
33 #define RULE_ATTR_DST 0x0040
34 #define RULE_ATTR_DSFIELD 0x0080
35 #define RULE_ATTR_TABLE 0x0100
36 #define RULE_ATTR_TYPE 0x0200
37 #define RULE_ATTR_SRC_LEN 0x0400
38 #define RULE_ATTR_DST_LEN 0x0800
39 #define RULE_ATTR_SRCMAP 0x1000
41 static struct nl_cache_ops rtnl_rule_ops;
42 static struct nl_object_ops rule_obj_ops;
45 static void rule_free_data(struct nl_object *c)
47 struct rtnl_rule *rule = nl_object_priv(c);
52 nl_addr_put(rule->r_src);
53 nl_addr_put(rule->r_dst);
56 static int rule_clone(struct nl_object *_dst, struct nl_object *_src)
58 struct rtnl_rule *dst = nl_object_priv(_dst);
59 struct rtnl_rule *src = nl_object_priv(_src);
62 if (!(dst->r_src = nl_addr_clone(src->r_src)))
66 if (!(dst->r_dst = nl_addr_clone(src->r_dst)))
72 static struct nla_policy rule_policy[RTA_MAX+1] = {
73 [RTA_PRIORITY] = { .type = NLA_U32 },
74 [RTA_FLOW] = { .type = NLA_U32 },
75 [RTA_PROTOINFO] = { .type = NLA_U32 },
76 [RTA_IIF] = { .type = NLA_STRING,
77 .maxlen = IFNAMSIZ, },
80 static int rule_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
81 struct nlmsghdr *n, struct nl_parser_param *pp)
83 struct rtnl_rule *rule;
85 struct nlattr *tb[RTA_MAX+1];
88 rule = rtnl_rule_alloc();
94 rule->ce_msgtype = n->nlmsg_type;
97 err = nlmsg_parse(n, sizeof(*r), tb, RTA_MAX, rule_policy);
101 rule->r_family = family = r->rtm_family;
102 rule->r_type = r->rtm_type;
103 rule->r_dsfield = r->rtm_tos;
104 rule->r_src_len = r->rtm_src_len;
105 rule->r_dst_len = r->rtm_dst_len;
106 rule->r_table = r->rtm_table;
107 rule->ce_mask = (RULE_ATTR_FAMILY | RULE_ATTR_TYPE | RULE_ATTR_DSFIELD |
108 RULE_ATTR_SRC_LEN | RULE_ATTR_DST_LEN |RULE_ATTR_TYPE |
111 if (tb[RTA_PRIORITY]) {
112 rule->r_prio = nla_get_u32(tb[RTA_PRIORITY]);
113 rule->ce_mask |= RULE_ATTR_PRIO;
117 if (!(rule->r_src = nl_addr_alloc_attr(tb[RTA_SRC], family)))
119 nl_addr_set_prefixlen(rule->r_src, r->rtm_src_len);
120 rule->ce_mask |= RULE_ATTR_SRC;
124 if (!(rule->r_dst = nl_addr_alloc_attr(tb[RTA_DST], family)))
126 nl_addr_set_prefixlen(rule->r_dst, r->rtm_dst_len);
127 rule->ce_mask |= RULE_ATTR_DST;
130 if (tb[RTA_PROTOINFO]) {
131 rule->r_mark = nla_get_u32(tb[RTA_PROTOINFO]);
132 rule->ce_mask |= RULE_ATTR_MARK;
136 nla_strlcpy(rule->r_iif, tb[RTA_IIF], IFNAMSIZ);
137 rule->ce_mask |= RULE_ATTR_IIF;
141 rule->r_realms = nla_get_u32(tb[RTA_FLOW]);
142 rule->ce_mask |= RULE_ATTR_REALMS;
145 if (tb[RTA_GATEWAY]) {
146 rule->r_srcmap = nl_addr_alloc_attr(tb[RTA_GATEWAY], family);
149 rule->ce_mask |= RULE_ATTR_SRCMAP;
153 rule->r_table = nla_get_u32(tb[RTA_TABLE]);
154 rule->ce_mask |= RULE_ATTR_TABLE;
157 err = pp->pp_cb((struct nl_object *) rule, pp);
167 static int rule_request_update(struct nl_cache *c, struct nl_sock *h)
169 return nl_rtgen_request(h, RTM_GETRULE, AF_UNSPEC, NLM_F_DUMP);
172 static void rule_dump_line(struct nl_object *o, struct nl_dump_params *p)
174 struct rtnl_rule *r = (struct rtnl_rule *) o;
177 nl_dump_line(p, "%8d ", (r->ce_mask & RULE_ATTR_PRIO) ? r->r_prio : 0);
178 nl_dump(p, "%s ", nl_af2str(r->r_family, buf, sizeof(buf)));
180 if (r->ce_mask & RULE_ATTR_SRC)
181 nl_dump(p, "from %s ",
182 nl_addr2str(r->r_src, buf, sizeof(buf)));
183 else if (r->ce_mask & RULE_ATTR_SRC_LEN && r->r_src_len)
184 nl_dump(p, "from 0/%d ", r->r_src_len);
186 if (r->ce_mask & RULE_ATTR_DST)
188 nl_addr2str(r->r_dst, buf, sizeof(buf)));
189 else if (r->ce_mask & RULE_ATTR_DST_LEN && r->r_dst_len)
190 nl_dump(p, "to 0/%d ", r->r_dst_len);
192 if (r->ce_mask & RULE_ATTR_DSFIELD && r->r_dsfield)
193 nl_dump(p, "tos %d ", r->r_dsfield);
195 if (r->ce_mask & RULE_ATTR_MARK)
196 nl_dump(p, "mark %" PRIx64 , r->r_mark);
198 if (r->ce_mask & RULE_ATTR_IIF)
199 nl_dump(p, "iif %s ", r->r_iif);
201 if (r->ce_mask & RULE_ATTR_TABLE)
202 nl_dump(p, "lookup %s ",
203 rtnl_route_table2str(r->r_table, buf, sizeof(buf)));
205 if (r->ce_mask & RULE_ATTR_REALMS)
206 nl_dump(p, "realms %s ",
207 rtnl_realms2str(r->r_realms, buf, sizeof(buf)));
209 nl_dump(p, "action %s\n",
210 nl_rtntype2str(r->r_type, buf, sizeof(buf)));
213 static void rule_dump_details(struct nl_object *obj, struct nl_dump_params *p)
215 struct rtnl_rule *rule = (struct rtnl_rule *) obj;
218 rule_dump_line(obj, p);
220 if (rule->ce_mask & RULE_ATTR_SRCMAP)
221 nl_dump_line(p, " srcmap %s\n",
222 nl_addr2str(rule->r_srcmap, buf, sizeof(buf)));
225 static void rule_dump_stats(struct nl_object *obj, struct nl_dump_params *p)
227 rule_dump_details(obj, p);
230 static void rule_dump_env(struct nl_object *obj, struct nl_dump_params *p)
232 struct rtnl_rule *rule = (struct rtnl_rule *) obj;
235 nl_dump_line(p, "RULE_PRIORITY=%u\n", rule->r_prio);
236 nl_dump_line(p, "RULE_FAMILY=%s\n",
237 nl_af2str(rule->r_family, buf, sizeof(buf)));
239 if (rule->ce_mask & RULE_ATTR_DST)
240 nl_dump_line(p, "RULE_DST=%s\n",
241 nl_addr2str(rule->r_dst, buf, sizeof(buf)));
243 if (rule->ce_mask & RULE_ATTR_DST_LEN)
244 nl_dump_line(p, "RULE_DSTLEN=%u\n", rule->r_dst_len);
246 if (rule->ce_mask & RULE_ATTR_SRC)
247 nl_dump_line(p, "RULE_SRC=%s\n",
248 nl_addr2str(rule->r_src, buf, sizeof(buf)));
250 if (rule->ce_mask & RULE_ATTR_SRC_LEN)
251 nl_dump_line(p, "RULE_SRCLEN=%u\n", rule->r_src_len);
253 if (rule->ce_mask & RULE_ATTR_IIF)
254 nl_dump_line(p, "RULE_IIF=%s\n", rule->r_iif);
256 if (rule->ce_mask & RULE_ATTR_TABLE)
257 nl_dump_line(p, "RULE_TABLE=%u\n", rule->r_table);
259 if (rule->ce_mask & RULE_ATTR_REALMS)
260 nl_dump_line(p, "RULE_REALM=%u\n", rule->r_realms);
262 if (rule->ce_mask & RULE_ATTR_MARK)
263 nl_dump_line(p, "RULE_MARK=0x%" PRIx64 "\n", rule->r_mark);
265 if (rule->ce_mask & RULE_ATTR_DSFIELD)
266 nl_dump_line(p, "RULE_DSFIELD=%u\n", rule->r_dsfield);
268 if (rule->ce_mask & RULE_ATTR_TYPE)
269 nl_dump_line(p, "RULE_TYPE=%s\n",
270 nl_rtntype2str(rule->r_type, buf, sizeof(buf)));
272 if (rule->ce_mask & RULE_ATTR_SRCMAP)
273 nl_dump_line(p, "RULE_SRCMAP=%s\n",
274 nl_addr2str(rule->r_srcmap, buf, sizeof(buf)));
277 static int rule_compare(struct nl_object *_a, struct nl_object *_b,
278 uint32_t attrs, int flags)
280 struct rtnl_rule *a = (struct rtnl_rule *) _a;
281 struct rtnl_rule *b = (struct rtnl_rule *) _b;
284 #define RULE_DIFF(ATTR, EXPR) ATTR_DIFF(attrs, RULE_ATTR_##ATTR, a, b, EXPR)
286 diff |= RULE_DIFF(FAMILY, a->r_family != b->r_family);
287 diff |= RULE_DIFF(TABLE, a->r_table != b->r_table);
288 diff |= RULE_DIFF(REALMS, a->r_realms != b->r_realms);
289 diff |= RULE_DIFF(DSFIELD, a->r_dsfield != b->r_dsfield);
290 diff |= RULE_DIFF(TYPE, a->r_type != b->r_type);
291 diff |= RULE_DIFF(PRIO, a->r_prio != b->r_prio);
292 diff |= RULE_DIFF(MARK, a->r_mark != b->r_mark);
293 diff |= RULE_DIFF(SRC_LEN, a->r_src_len != b->r_src_len);
294 diff |= RULE_DIFF(DST_LEN, a->r_dst_len != b->r_dst_len);
295 diff |= RULE_DIFF(SRC, nl_addr_cmp(a->r_src, b->r_src));
296 diff |= RULE_DIFF(DST, nl_addr_cmp(a->r_dst, b->r_dst));
297 diff |= RULE_DIFF(IIF, strcmp(a->r_iif, b->r_iif));
304 static struct trans_tbl rule_attrs[] = {
305 __ADD(RULE_ATTR_FAMILY, family)
306 __ADD(RULE_ATTR_PRIO, prio)
307 __ADD(RULE_ATTR_MARK, mark)
308 __ADD(RULE_ATTR_IIF, iif)
309 __ADD(RULE_ATTR_REALMS, realms)
310 __ADD(RULE_ATTR_SRC, src)
311 __ADD(RULE_ATTR_DST, dst)
312 __ADD(RULE_ATTR_DSFIELD, dsfield)
313 __ADD(RULE_ATTR_TABLE, table)
314 __ADD(RULE_ATTR_TYPE, type)
315 __ADD(RULE_ATTR_SRC_LEN, src_len)
316 __ADD(RULE_ATTR_DST_LEN, dst_len)
317 __ADD(RULE_ATTR_SRCMAP, srcmap)
320 static char *rule_attrs2str(int attrs, char *buf, size_t len)
322 return __flags2str(attrs, buf, len, rule_attrs,
323 ARRAY_SIZE(rule_attrs));
327 * @name Allocation/Freeing
331 struct rtnl_rule *rtnl_rule_alloc(void)
333 return (struct rtnl_rule *) nl_object_alloc(&rule_obj_ops);
336 void rtnl_rule_put(struct rtnl_rule *rule)
338 nl_object_put((struct nl_object *) rule);
344 * @name Cache Management
349 * Build a rule cache including all rules currently configured in the kernel.
350 * @arg sk Netlink socket.
351 * @arg family Address family or AF_UNSPEC.
352 * @arg result Pointer to store resulting cache.
354 * Allocates a new rule cache, initializes it properly and updates it
355 * to include all rules currently configured in the kernel.
357 * @return 0 on success or a negative error code.
359 int rtnl_rule_alloc_cache(struct nl_sock *sock, int family,
360 struct nl_cache **result)
362 struct nl_cache * cache;
365 if (!(cache = nl_cache_alloc(&rtnl_rule_ops)))
368 cache->c_iarg1 = family;
370 if (sock && (err = nl_cache_refill(sock, cache)) < 0) {
382 * @name Rule Addition
386 static int build_rule_msg(struct rtnl_rule *tmpl, int cmd, int flags,
387 struct nl_msg **result)
391 .rtm_type = RTN_UNSPEC
394 if (cmd == RTM_NEWRULE)
395 rtm.rtm_type = RTN_UNICAST;
397 if (tmpl->ce_mask & RULE_ATTR_FAMILY)
398 rtm.rtm_family = tmpl->r_family;
400 if (tmpl->ce_mask & RULE_ATTR_TABLE)
401 rtm.rtm_table = tmpl->r_table;
403 if (tmpl->ce_mask & RULE_ATTR_DSFIELD)
404 rtm.rtm_tos = tmpl->r_dsfield;
406 if (tmpl->ce_mask & RULE_ATTR_TYPE)
407 rtm.rtm_type = tmpl->r_type;
409 if (tmpl->ce_mask & RULE_ATTR_SRC_LEN)
410 rtm.rtm_src_len = tmpl->r_src_len;
412 if (tmpl->ce_mask & RULE_ATTR_DST_LEN)
413 rtm.rtm_dst_len = tmpl->r_dst_len;
415 msg = nlmsg_alloc_simple(cmd, flags);
419 if (nlmsg_append(msg, &rtm, sizeof(rtm), NLMSG_ALIGNTO) < 0)
420 goto nla_put_failure;
422 if (tmpl->ce_mask & RULE_ATTR_SRC)
423 NLA_PUT_ADDR(msg, RTA_SRC, tmpl->r_src);
425 if (tmpl->ce_mask & RULE_ATTR_DST)
426 NLA_PUT_ADDR(msg, RTA_DST, tmpl->r_dst);
428 if (tmpl->ce_mask & RULE_ATTR_PRIO)
429 NLA_PUT_U32(msg, RTA_PRIORITY, tmpl->r_prio);
431 if (tmpl->ce_mask & RULE_ATTR_MARK)
432 NLA_PUT_U32(msg, RTA_PROTOINFO, tmpl->r_mark);
434 if (tmpl->ce_mask & RULE_ATTR_REALMS)
435 NLA_PUT_U32(msg, RTA_FLOW, tmpl->r_realms);
437 if (tmpl->ce_mask & RULE_ATTR_IIF)
438 NLA_PUT_STRING(msg, RTA_IIF, tmpl->r_iif);
449 * Build netlink request message to add a new rule
450 * @arg tmpl template with data of new rule
451 * @arg flags additional netlink message flags
453 * Builds a new netlink message requesting a addition of a new
454 * rule. The netlink message header isn't fully equipped with
455 * all relevant fields and must thus be sent out via nl_send_auto_complete()
456 * or supplemented as needed. \a tmpl must contain the attributes of the new
457 * address set via \c rtnl_rule_set_* functions.
459 * @return The netlink message
461 int rtnl_rule_build_add_request(struct rtnl_rule *tmpl, int flags,
462 struct nl_msg **result)
464 return build_rule_msg(tmpl, RTM_NEWRULE, NLM_F_CREATE | flags,
470 * @arg sk Netlink socket.
471 * @arg tmpl template with requested changes
472 * @arg flags additional netlink message flags
474 * Builds a netlink message by calling rtnl_rule_build_add_request(),
475 * sends the request to the kernel and waits for the next ACK to be
476 * received and thus blocks until the request has been fullfilled.
478 * @return 0 on sucess or a negative error if an error occured.
480 int rtnl_rule_add(struct nl_sock *sk, struct rtnl_rule *tmpl, int flags)
485 if ((err = rtnl_rule_build_add_request(tmpl, flags, &msg)) < 0)
488 err = nl_send_auto_complete(sk, msg);
493 return wait_for_ack(sk);
499 * @name Rule Deletion
504 * Build a netlink request message to delete a rule
505 * @arg rule rule to delete
506 * @arg flags additional netlink message flags
508 * Builds a new netlink message requesting a deletion of a rule.
509 * The netlink message header isn't fully equipped with all relevant
510 * fields and must thus be sent out via nl_send_auto_complete()
511 * or supplemented as needed. \a rule must point to an existing
514 * @return The netlink message
516 int rtnl_rule_build_delete_request(struct rtnl_rule *rule, int flags,
517 struct nl_msg **result)
519 return build_rule_msg(rule, RTM_DELRULE, flags, result);
524 * @arg sk Netlink socket.
525 * @arg rule rule to delete
526 * @arg flags additional netlink message flags
528 * Builds a netlink message by calling rtnl_rule_build_delete_request(),
529 * sends the request to the kernel and waits for the next ACK to be
530 * received and thus blocks until the request has been fullfilled.
532 * @return 0 on sucess or a negative error if an error occured.
534 int rtnl_rule_delete(struct nl_sock *sk, struct rtnl_rule *rule, int flags)
539 if ((err = rtnl_rule_build_delete_request(rule, flags, &msg)) < 0)
542 err = nl_send_auto_complete(sk, msg);
547 return wait_for_ack(sk);
553 * @name Attribute Modification
557 void rtnl_rule_set_family(struct rtnl_rule *rule, int family)
559 rule->r_family = family;
560 rule->ce_mask |= RULE_ATTR_FAMILY;
563 int rtnl_rule_get_family(struct rtnl_rule *rule)
565 if (rule->ce_mask & RULE_ATTR_FAMILY)
566 return rule->r_family;
571 void rtnl_rule_set_prio(struct rtnl_rule *rule, int prio)
574 rule->ce_mask |= RULE_ATTR_PRIO;
577 int rtnl_rule_get_prio(struct rtnl_rule *rule)
579 if (rule->ce_mask & RULE_ATTR_PRIO)
585 void rtnl_rule_set_mark(struct rtnl_rule *rule, uint64_t mark)
588 rule->ce_mask |= RULE_ATTR_MARK;
591 uint64_t rtnl_rule_get_mark(struct rtnl_rule *rule)
593 if (rule->ce_mask & RULE_ATTR_MARK)
596 return UINT_LEAST64_MAX;
599 void rtnl_rule_set_table(struct rtnl_rule *rule, int table)
601 rule->r_table = table;
602 rule->ce_mask |= RULE_ATTR_TABLE;
605 int rtnl_rule_get_table(struct rtnl_rule *rule)
607 if (rule->ce_mask & RULE_ATTR_TABLE)
608 return rule->r_table;
613 void rtnl_rule_set_dsfield(struct rtnl_rule *rule, int dsfield)
615 rule->r_dsfield = dsfield;
616 rule->ce_mask |= RULE_ATTR_DSFIELD;
619 int rtnl_rule_get_dsfield(struct rtnl_rule *rule)
621 if (rule->ce_mask & RULE_ATTR_DSFIELD)
622 return rule->r_dsfield;
627 void rtnl_rule_set_src_len(struct rtnl_rule *rule, int len)
629 rule->r_src_len = len;
630 if (rule->ce_mask & RULE_ATTR_SRC)
631 nl_addr_set_prefixlen(rule->r_src, len);
632 rule->ce_mask |= RULE_ATTR_SRC_LEN;
635 int rtnl_rule_get_src_len(struct rtnl_rule *rule)
637 if (rule->ce_mask & RULE_ATTR_SRC_LEN)
638 return rule->r_src_len;
643 void rtnl_rule_set_dst_len(struct rtnl_rule *rule, int len)
645 rule->r_dst_len = len;
646 if (rule->ce_mask & RULE_ATTR_DST)
647 nl_addr_set_prefixlen(rule->r_dst, len);
648 rule->ce_mask |= RULE_ATTR_DST_LEN;
651 int rtnl_rule_get_dst_len(struct rtnl_rule *rule)
653 if (rule->ce_mask & RULE_ATTR_DST_LEN)
654 return rule->r_dst_len;
659 static inline int __assign_addr(struct rtnl_rule *rule, struct nl_addr **pos,
660 struct nl_addr *new, uint8_t *len, int flag)
662 if (rule->ce_mask & RULE_ATTR_FAMILY) {
663 if (new->a_family != rule->r_family)
664 return -NLE_AF_MISMATCH;
666 rule->r_family = new->a_family;
673 *len = nl_addr_get_prefixlen(new);
675 rule->ce_mask |= (flag | RULE_ATTR_FAMILY);
680 int rtnl_rule_set_src(struct rtnl_rule *rule, struct nl_addr *src)
682 return __assign_addr(rule, &rule->r_src, src, &rule->r_src_len,
683 RULE_ATTR_SRC | RULE_ATTR_SRC_LEN);
686 struct nl_addr *rtnl_rule_get_src(struct rtnl_rule *rule)
688 if (rule->ce_mask & RULE_ATTR_SRC)
694 int rtnl_rule_set_dst(struct rtnl_rule *rule, struct nl_addr *dst)
696 return __assign_addr(rule, &rule->r_dst, dst, &rule->r_dst_len,
697 RULE_ATTR_DST | RULE_ATTR_DST_LEN);
700 struct nl_addr *rtnl_rule_get_dst(struct rtnl_rule *rule)
702 if (rule->ce_mask & RULE_ATTR_DST)
708 int rtnl_rule_set_iif(struct rtnl_rule *rule, const char *dev)
710 if (strlen(dev) > IFNAMSIZ-1)
713 strcpy(rule->r_iif, dev);
714 rule->ce_mask |= RULE_ATTR_IIF;
718 char *rtnl_rule_get_iif(struct rtnl_rule *rule)
720 if (rule->ce_mask & RULE_ATTR_IIF)
726 void rtnl_rule_set_action(struct rtnl_rule *rule, int type)
729 rule->ce_mask |= RULE_ATTR_TYPE;
732 int rtnl_rule_get_action(struct rtnl_rule *rule)
734 if (rule->ce_mask & RULE_ATTR_TYPE)
740 void rtnl_rule_set_realms(struct rtnl_rule *rule, uint32_t realms)
742 rule->r_realms = realms;
743 rule->ce_mask |= RULE_ATTR_REALMS;
746 uint32_t rtnl_rule_get_realms(struct rtnl_rule *rule)
748 if (rule->ce_mask & RULE_ATTR_REALMS)
749 return rule->r_realms;
756 static struct nl_object_ops rule_obj_ops = {
757 .oo_name = "route/rule",
758 .oo_size = sizeof(struct rtnl_rule),
759 .oo_free_data = rule_free_data,
760 .oo_clone = rule_clone,
762 [NL_DUMP_LINE] = rule_dump_line,
763 [NL_DUMP_DETAILS] = rule_dump_details,
764 [NL_DUMP_STATS] = rule_dump_stats,
765 [NL_DUMP_ENV] = rule_dump_env,
767 .oo_compare = rule_compare,
768 .oo_attrs2str = rule_attrs2str,
772 static struct nl_cache_ops rtnl_rule_ops = {
773 .co_name = "route/rule",
774 .co_hdrsize = sizeof(struct rtmsg),
776 { RTM_NEWRULE, NL_ACT_NEW, "new" },
777 { RTM_DELRULE, NL_ACT_DEL, "del" },
778 { RTM_GETRULE, NL_ACT_GET, "get" },
779 END_OF_MSGTYPES_LIST,
781 .co_protocol = NETLINK_ROUTE,
782 .co_request_update = rule_request_update,
783 .co_msg_parser = rule_msg_parser,
784 .co_obj_ops = &rule_obj_ops,
787 static void __init rule_init(void)
789 nl_cache_mngt_register(&rtnl_rule_ops);
792 static void __exit rule_exit(void)
794 nl_cache_mngt_unregister(&rtnl_rule_ops);