rule.c

00001 /*
00002  * lib/route/rule.c          Routing Rules
00003  *
00004  *      This library is free software; you can redistribute it and/or
00005  *      modify it under the terms of the GNU Lesser General Public
00006  *      License as published by the Free Software Foundation version 2.1
00007  *      of the License.
00008  *
00009  * Copyright (c) 2003-2010 Thomas Graf <tgraf@suug.ch>
00010  */
00011 
00012 /**
00013  * @ingroup rtnl
00014  * @defgroup rule Routing Rules
00015  * @brief
00016  * @{
00017  */
00018 
00019 #include <netlink-local.h>
00020 #include <netlink/netlink.h>
00021 #include <netlink/utils.h>
00022 #include <netlink/route/rtnl.h>
00023 #include <netlink/route/rule.h>
00024 #include <inttypes.h>
00025 
00026 /** @cond SKIP */
00027 #define RULE_ATTR_FAMILY        0x0001
00028 #define RULE_ATTR_TABLE         0x0002
00029 #define RULE_ATTR_ACTION        0x0004
00030 #define RULE_ATTR_FLAGS         0x0008
00031 #define RULE_ATTR_IIFNAME       0x0010
00032 #define RULE_ATTR_OIFNAME       0x0020
00033 #define RULE_ATTR_PRIO          0x0040
00034 #define RULE_ATTR_MARK          0x0080
00035 #define RULE_ATTR_MASK          0x0100
00036 #define RULE_ATTR_GOTO          0x0200
00037 #define RULE_ATTR_SRC           0x0400
00038 #define RULE_ATTR_DST           0x0800
00039 #define RULE_ATTR_DSFIELD       0x1000
00040 #define RULE_ATTR_FLOW          0x2000
00041 
00042 static struct nl_cache_ops rtnl_rule_ops;
00043 static struct nl_object_ops rule_obj_ops;
00044 /** @endcond */
00045 
00046 static void rule_free_data(struct nl_object *c)
00047 {
00048         struct rtnl_rule *rule = nl_object_priv(c);
00049 
00050         if (!rule)
00051                 return;
00052 
00053         nl_addr_put(rule->r_src);
00054         nl_addr_put(rule->r_dst);
00055 }
00056 
00057 static int rule_clone(struct nl_object *_dst, struct nl_object *_src)
00058 {
00059         struct rtnl_rule *dst = nl_object_priv(_dst);
00060         struct rtnl_rule *src = nl_object_priv(_src);
00061 
00062         if (src->r_src)
00063                 if (!(dst->r_src = nl_addr_clone(src->r_src)))
00064                         return -NLE_NOMEM;
00065 
00066         if (src->r_dst)
00067                 if (!(dst->r_dst = nl_addr_clone(src->r_dst)))
00068                         return -NLE_NOMEM;
00069 
00070         return 0;
00071 }
00072 
00073 static struct nla_policy rule_policy[FRA_MAX+1] = {
00074         [FRA_TABLE]     = { .type = NLA_U32 },
00075         [FRA_IIFNAME]   = { .type = NLA_STRING, .maxlen = IFNAMSIZ },
00076         [FRA_OIFNAME]   = { .type = NLA_STRING, .maxlen = IFNAMSIZ },
00077         [FRA_PRIORITY]  = { .type = NLA_U32 },
00078         [FRA_FWMARK]    = { .type = NLA_U32 },
00079         [FRA_FWMASK]    = { .type = NLA_U32 },
00080         [FRA_GOTO]      = { .type = NLA_U32 },
00081         [FRA_FLOW]      = { .type = NLA_U32 },
00082 };
00083 
00084 static int rule_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
00085                            struct nlmsghdr *n, struct nl_parser_param *pp)
00086 {
00087         struct rtnl_rule *rule;
00088         struct fib_rule_hdr *frh;
00089         struct nlattr *tb[FRA_MAX+1];
00090         int err = 1, family;
00091 
00092         rule = rtnl_rule_alloc();
00093         if (!rule) {
00094                 err = -NLE_NOMEM;
00095                 goto errout;
00096         }
00097 
00098         rule->ce_msgtype = n->nlmsg_type;
00099         frh = nlmsg_data(n);
00100 
00101         err = nlmsg_parse(n, sizeof(*frh), tb, FRA_MAX, rule_policy);
00102         if (err < 0)
00103                 goto errout;
00104 
00105         rule->r_family = family = frh->family;
00106         rule->r_table = frh->table;
00107         rule->r_action = frh->action;
00108         rule->r_flags = frh->flags;
00109 
00110         rule->ce_mask = (RULE_ATTR_FAMILY | RULE_ATTR_TABLE | RULE_ATTR_ACTION |
00111                          RULE_ATTR_FLAGS);
00112 
00113         /* ipv4 only */
00114         if (frh->tos) {
00115                 rule->r_dsfield = frh->tos;
00116                 rule->ce_mask |= RULE_ATTR_DSFIELD;
00117         }
00118 
00119         if (tb[FRA_TABLE]) {
00120                 rule->r_table = nla_get_u32(tb[FRA_TABLE]);
00121                 rule->ce_mask |= RULE_ATTR_TABLE;
00122         }
00123 
00124         if (tb[FRA_IIFNAME]) {
00125                 nla_strlcpy(rule->r_iifname, tb[FRA_IIFNAME], IFNAMSIZ);
00126                 rule->ce_mask |= RULE_ATTR_IIFNAME;
00127         }
00128 
00129         if (tb[FRA_OIFNAME]) {
00130                 nla_strlcpy(rule->r_oifname, tb[FRA_OIFNAME], IFNAMSIZ);
00131                 rule->ce_mask |= RULE_ATTR_OIFNAME;
00132         }
00133 
00134         if (tb[FRA_PRIORITY]) {
00135                 rule->r_prio = nla_get_u32(tb[FRA_PRIORITY]);
00136                 rule->ce_mask |= RULE_ATTR_PRIO;
00137         }
00138 
00139         if (tb[FRA_FWMARK]) {
00140                 rule->r_mark = nla_get_u32(tb[FRA_FWMARK]);
00141                 rule->ce_mask |= RULE_ATTR_MARK;
00142         }
00143 
00144         if (tb[FRA_FWMASK]) {
00145                 rule->r_mask = nla_get_u32(tb[FRA_FWMASK]);
00146                 rule->ce_mask |= RULE_ATTR_MASK;
00147         }
00148 
00149         if (tb[FRA_GOTO]) {
00150                 rule->r_goto = nla_get_u32(tb[FRA_GOTO]);
00151                 rule->ce_mask |= RULE_ATTR_GOTO;
00152         }
00153 
00154         if (tb[FRA_SRC]) {
00155                 if (!(rule->r_src = nl_addr_alloc_attr(tb[FRA_SRC], family)))
00156                         goto errout_enomem;
00157 
00158                 nl_addr_set_prefixlen(rule->r_src, frh->src_len);
00159                 rule->ce_mask |= RULE_ATTR_SRC;
00160         }
00161 
00162         if (tb[FRA_DST]) {
00163                 if (!(rule->r_dst = nl_addr_alloc_attr(tb[FRA_DST], family)))
00164                         goto errout_enomem;
00165                 nl_addr_set_prefixlen(rule->r_dst, frh->dst_len);
00166                 rule->ce_mask |= RULE_ATTR_DST;
00167         }
00168 
00169         /* ipv4 only */
00170         if (tb[FRA_FLOW]) {
00171                 rule->r_flow = nla_get_u32(tb[FRA_FLOW]);
00172                 rule->ce_mask |= RULE_ATTR_FLOW;
00173         }
00174 
00175         err = pp->pp_cb((struct nl_object *) rule, pp);
00176 errout:
00177         rtnl_rule_put(rule);
00178         return err;
00179 
00180 errout_enomem:
00181         err = -NLE_NOMEM;
00182         goto errout;
00183 }
00184 
00185 static int rule_request_update(struct nl_cache *c, struct nl_sock *h)
00186 {
00187         return nl_rtgen_request(h, RTM_GETRULE, AF_UNSPEC, NLM_F_DUMP);
00188 }
00189 
00190 static void rule_dump_line(struct nl_object *o, struct nl_dump_params *p)
00191 {
00192         struct rtnl_rule *r = (struct rtnl_rule *) o;
00193         char buf[128];
00194 
00195         nl_dump_line(p, "%8d ", (r->ce_mask & RULE_ATTR_PRIO) ? r->r_prio : 0);
00196         nl_dump(p, "%s ", nl_af2str(r->r_family, buf, sizeof(buf)));
00197 
00198         if (r->ce_mask & RULE_ATTR_SRC)
00199                 nl_dump(p, "from %s ",
00200                         nl_addr2str(r->r_src, buf, sizeof(buf)));
00201 
00202         if (r->ce_mask & RULE_ATTR_DST)
00203                 nl_dump(p, "to %s ",
00204                         nl_addr2str(r->r_dst, buf, sizeof(buf)));
00205 
00206         if (r->ce_mask & RULE_ATTR_DSFIELD)
00207                 nl_dump(p, "tos %u ", r->r_dsfield);
00208 
00209         if (r->ce_mask & (RULE_ATTR_MARK | RULE_ATTR_MASK))
00210                 nl_dump(p, "mark %#x/%#x", r->r_mark, r->r_mask);
00211 
00212         if (r->ce_mask & RULE_ATTR_IIFNAME)
00213                 nl_dump(p, "iif %s ", r->r_iifname);
00214 
00215         if (r->ce_mask & RULE_ATTR_OIFNAME)
00216                 nl_dump(p, "oif %s ", r->r_oifname);
00217 
00218         if (r->ce_mask & RULE_ATTR_TABLE)
00219                 nl_dump(p, "lookup %s ",
00220                         rtnl_route_table2str(r->r_table, buf, sizeof(buf)));
00221 
00222         if (r->ce_mask & RULE_ATTR_FLOW)
00223                 nl_dump(p, "flow %s ",
00224                         rtnl_realms2str(r->r_flow, buf, sizeof(buf)));
00225 
00226         if (r->ce_mask & RULE_ATTR_GOTO)
00227                 nl_dump(p, "goto %u ", r->r_goto);
00228 
00229         if (r->ce_mask & RULE_ATTR_ACTION)
00230                 nl_dump(p, "action %s",
00231                         nl_rtntype2str(r->r_action, buf, sizeof(buf)));
00232 
00233         nl_dump(p, "\n");
00234 }
00235 
00236 static void rule_dump_details(struct nl_object *obj, struct nl_dump_params *p)
00237 {
00238         rule_dump_line(obj, p);
00239 }
00240 
00241 static void rule_dump_stats(struct nl_object *obj, struct nl_dump_params *p)
00242 {
00243         rule_dump_details(obj, p);
00244 }
00245 
00246 #define RULE_ATTR_FLAGS         0x0008
00247 
00248 static int rule_compare(struct nl_object *_a, struct nl_object *_b,
00249                         uint32_t attrs, int flags)
00250 {
00251         struct rtnl_rule *a = (struct rtnl_rule *) _a;
00252         struct rtnl_rule *b = (struct rtnl_rule *) _b;
00253         int diff = 0;
00254 
00255 #define RULE_DIFF(ATTR, EXPR) ATTR_DIFF(attrs, RULE_ATTR_##ATTR, a, b, EXPR)
00256 
00257         diff |= RULE_DIFF(FAMILY,       a->r_family != b->r_family);
00258         diff |= RULE_DIFF(TABLE,        a->r_table != b->r_table);
00259         diff |= RULE_DIFF(ACTION,       a->r_action != b->r_action);
00260         diff |= RULE_DIFF(IIFNAME,      strcmp(a->r_iifname, b->r_iifname));
00261         diff |= RULE_DIFF(OIFNAME,      strcmp(a->r_oifname, b->r_oifname));
00262         diff |= RULE_DIFF(PRIO,         a->r_prio != b->r_prio);
00263         diff |= RULE_DIFF(MARK,         a->r_mark != b->r_mark);
00264         diff |= RULE_DIFF(MASK,         a->r_mask != b->r_mask);
00265         diff |= RULE_DIFF(GOTO,         a->r_goto != b->r_goto);
00266         diff |= RULE_DIFF(SRC,          nl_addr_cmp(a->r_src, b->r_src));
00267         diff |= RULE_DIFF(DST,          nl_addr_cmp(a->r_dst, b->r_dst));
00268         diff |= RULE_DIFF(DSFIELD,      a->r_dsfield != b->r_dsfield);
00269         diff |= RULE_DIFF(FLOW,         a->r_flow != b->r_flow);
00270         
00271 #undef RULE_DIFF
00272 
00273         return diff;
00274 }
00275 
00276 static const struct trans_tbl rule_attrs[] = {
00277         __ADD(RULE_ATTR_FAMILY, family)
00278         __ADD(RULE_ATTR_TABLE, table)
00279         __ADD(RULE_ATTR_ACTION, action)
00280         __ADD(RULE_ATTR_IIFNAME, iifname)
00281         __ADD(RULE_ATTR_OIFNAME, oifname)
00282         __ADD(RULE_ATTR_PRIO, prio)
00283         __ADD(RULE_ATTR_MARK, mark)
00284         __ADD(RULE_ATTR_MASK, mask)
00285         __ADD(RULE_ATTR_GOTO, goto)
00286         __ADD(RULE_ATTR_SRC, src)
00287         __ADD(RULE_ATTR_DST, dst)
00288         __ADD(RULE_ATTR_DSFIELD, dsfield)
00289         __ADD(RULE_ATTR_FLOW, flow)
00290 };
00291 
00292 static char *rule_attrs2str(int attrs, char *buf, size_t len)
00293 {
00294         return __flags2str(attrs, buf, len, rule_attrs,
00295                            ARRAY_SIZE(rule_attrs));
00296 }
00297 
00298 /**
00299  * @name Allocation/Freeing
00300  * @{
00301  */
00302 
00303 struct rtnl_rule *rtnl_rule_alloc(void)
00304 {
00305         return (struct rtnl_rule *) nl_object_alloc(&rule_obj_ops);
00306 }
00307 
00308 void rtnl_rule_put(struct rtnl_rule *rule)
00309 {
00310         nl_object_put((struct nl_object *) rule);
00311 }
00312 
00313 /** @} */
00314 
00315 /**
00316  * @name Cache Management
00317  * @{
00318  */
00319 
00320 /**
00321  * Build a rule cache including all rules currently configured in the kernel.
00322  * @arg sk              Netlink socket.
00323  * @arg family          Address family or AF_UNSPEC.
00324  * @arg result          Pointer to store resulting cache.
00325  *
00326  * Allocates a new rule cache, initializes it properly and updates it
00327  * to include all rules currently configured in the kernel.
00328  *
00329  * @return 0 on success or a negative error code.
00330  */
00331 int rtnl_rule_alloc_cache(struct nl_sock *sock, int family,
00332                           struct nl_cache **result)
00333 {
00334         struct nl_cache * cache;
00335         int err;
00336 
00337         if (!(cache = nl_cache_alloc(&rtnl_rule_ops)))
00338                 return -NLE_NOMEM;
00339 
00340         cache->c_iarg1 = family;
00341 
00342         if (sock && (err = nl_cache_refill(sock, cache)) < 0) {
00343                 free(cache);
00344                 return err;
00345         }
00346 
00347         *result = cache;
00348         return 0;
00349 }
00350 
00351 /** @} */
00352 
00353 /**
00354  * @name Rule Addition
00355  * @{
00356  */
00357 
00358 static int build_rule_msg(struct rtnl_rule *tmpl, int cmd, int flags,
00359                           struct nl_msg **result)
00360 {
00361         struct nl_msg *msg;
00362         struct fib_rule_hdr frh = {
00363                 .family = tmpl->r_family,
00364                 .table = tmpl->r_table,
00365                 .action = tmpl->r_action,
00366                 .flags = tmpl->r_flags,
00367                 .tos = tmpl->r_dsfield,
00368         };
00369 
00370         if (!(tmpl->ce_mask & RULE_ATTR_FAMILY))
00371                 return -NLE_MISSING_ATTR;
00372 
00373         msg = nlmsg_alloc_simple(cmd, flags);
00374         if (!msg)
00375                 return -NLE_NOMEM;
00376 
00377         if (nlmsg_append(msg, &frh, sizeof(frh), NLMSG_ALIGNTO) < 0)
00378                 goto nla_put_failure;
00379 
00380         if (tmpl->ce_mask & RULE_ATTR_SRC) {
00381                 frh.src_len = nl_addr_get_prefixlen(tmpl->r_src);
00382                 NLA_PUT_ADDR(msg, FRA_SRC, tmpl->r_src);
00383         }
00384 
00385         if (tmpl->ce_mask & RULE_ATTR_DST) {
00386                 frh.dst_len = nl_addr_get_prefixlen(tmpl->r_dst);
00387                 NLA_PUT_ADDR(msg, FRA_DST, tmpl->r_dst);
00388         }
00389 
00390         if (tmpl->ce_mask & RULE_ATTR_IIFNAME)
00391                 NLA_PUT_STRING(msg, FRA_IIFNAME, tmpl->r_iifname);
00392 
00393         if (tmpl->ce_mask & RULE_ATTR_OIFNAME)
00394                 NLA_PUT_STRING(msg, FRA_OIFNAME, tmpl->r_oifname);
00395 
00396         if (tmpl->ce_mask & RULE_ATTR_PRIO)
00397                 NLA_PUT_U32(msg, FRA_PRIORITY, tmpl->r_prio);
00398 
00399         if (tmpl->ce_mask & RULE_ATTR_MARK)
00400                 NLA_PUT_U32(msg, FRA_FWMARK, tmpl->r_mark);
00401 
00402         if (tmpl->ce_mask & RULE_ATTR_MASK)
00403                 NLA_PUT_U32(msg, FRA_FWMASK, tmpl->r_mask);
00404 
00405         if (tmpl->ce_mask & RULE_ATTR_GOTO)
00406                 NLA_PUT_U32(msg, FRA_GOTO, tmpl->r_goto);
00407 
00408         if (tmpl->ce_mask & RULE_ATTR_FLOW)
00409                 NLA_PUT_U32(msg, FRA_FLOW, tmpl->r_flow);
00410 
00411 
00412         *result = msg;
00413         return 0;
00414 
00415 nla_put_failure:
00416         nlmsg_free(msg);
00417         return -NLE_MSGSIZE;
00418 }
00419 
00420 /**
00421  * Build netlink request message to add a new rule
00422  * @arg tmpl            template with data of new rule
00423  * @arg flags           additional netlink message flags
00424  *
00425  * Builds a new netlink message requesting a addition of a new
00426  * rule. The netlink message header isn't fully equipped with
00427  * all relevant fields and must thus be sent out via nl_send_auto_complete()
00428  * or supplemented as needed. \a tmpl must contain the attributes of the new
00429  * address set via \c rtnl_rule_set_* functions.
00430  * 
00431  * @return The netlink message
00432  */
00433 int rtnl_rule_build_add_request(struct rtnl_rule *tmpl, int flags,
00434                                 struct nl_msg **result)
00435 {
00436         return build_rule_msg(tmpl, RTM_NEWRULE, NLM_F_CREATE | flags,
00437                               result);
00438 }
00439 
00440 /**
00441  * Add a new rule
00442  * @arg sk              Netlink socket.
00443  * @arg tmpl            template with requested changes
00444  * @arg flags           additional netlink message flags
00445  *
00446  * Builds a netlink message by calling rtnl_rule_build_add_request(),
00447  * sends the request to the kernel and waits for the next ACK to be
00448  * received and thus blocks until the request has been fullfilled.
00449  *
00450  * @return 0 on sucess or a negative error if an error occured.
00451  */
00452 int rtnl_rule_add(struct nl_sock *sk, struct rtnl_rule *tmpl, int flags)
00453 {
00454         struct nl_msg *msg;
00455         int err;
00456         
00457         if ((err = rtnl_rule_build_add_request(tmpl, flags, &msg)) < 0)
00458                 return err;
00459 
00460         err = nl_send_auto_complete(sk, msg);
00461         nlmsg_free(msg);
00462         if (err < 0)
00463                 return err;
00464 
00465         return wait_for_ack(sk);
00466 }
00467 
00468 /** @} */
00469 
00470 /**
00471  * @name Rule Deletion
00472  * @{
00473  */
00474 
00475 /**
00476  * Build a netlink request message to delete a rule
00477  * @arg rule            rule to delete
00478  * @arg flags           additional netlink message flags
00479  *
00480  * Builds a new netlink message requesting a deletion of a rule.
00481  * The netlink message header isn't fully equipped with all relevant
00482  * fields and must thus be sent out via nl_send_auto_complete()
00483  * or supplemented as needed. \a rule must point to an existing
00484  * address.
00485  *
00486  * @return The netlink message
00487  */
00488 int rtnl_rule_build_delete_request(struct rtnl_rule *rule, int flags,
00489                                    struct nl_msg **result)
00490 {
00491         return build_rule_msg(rule, RTM_DELRULE, flags, result);
00492 }
00493 
00494 /**
00495  * Delete a rule
00496  * @arg sk              Netlink socket.
00497  * @arg rule            rule to delete
00498  * @arg flags           additional netlink message flags
00499  *
00500  * Builds a netlink message by calling rtnl_rule_build_delete_request(),
00501  * sends the request to the kernel and waits for the next ACK to be
00502  * received and thus blocks until the request has been fullfilled.
00503  *
00504  * @return 0 on sucess or a negative error if an error occured.
00505  */
00506 int rtnl_rule_delete(struct nl_sock *sk, struct rtnl_rule *rule, int flags)
00507 {
00508         struct nl_msg *msg;
00509         int err;
00510         
00511         if ((err = rtnl_rule_build_delete_request(rule, flags, &msg)) < 0)
00512                 return err;
00513 
00514         err = nl_send_auto_complete(sk, msg);
00515         nlmsg_free(msg);
00516         if (err < 0)
00517                 return err;
00518 
00519         return wait_for_ack(sk);
00520 }
00521 
00522 /** @} */
00523 
00524 /**
00525  * @name Attribute Modification
00526  * @{
00527  */
00528 
00529 void rtnl_rule_set_family(struct rtnl_rule *rule, int family)
00530 {
00531         rule->r_family = family;
00532         rule->ce_mask |= RULE_ATTR_FAMILY;
00533 }
00534 
00535 int rtnl_rule_get_family(struct rtnl_rule *rule)
00536 {
00537         if (rule->ce_mask & RULE_ATTR_FAMILY)
00538                 return rule->r_family;
00539         else
00540                 return AF_UNSPEC;
00541 }
00542 
00543 void rtnl_rule_set_prio(struct rtnl_rule *rule, uint32_t prio)
00544 {
00545         rule->r_prio = prio;
00546         rule->ce_mask |= RULE_ATTR_PRIO;
00547 }
00548 
00549 uint32_t rtnl_rule_get_prio(struct rtnl_rule *rule)
00550 {
00551         return rule->r_prio;
00552 }
00553 
00554 void rtnl_rule_set_mark(struct rtnl_rule *rule, uint32_t mark)
00555 {
00556         rule->r_mark = mark;
00557         rule->ce_mask |= RULE_ATTR_MARK;
00558 }
00559 
00560 uint32_t rtnl_rule_get_mark(struct rtnl_rule *rule)
00561 {
00562         return rule->r_mark;
00563 }
00564 
00565 void rtnl_rule_set_mask(struct rtnl_rule *rule, uint32_t mask)
00566 {
00567         rule->r_mask = mask;
00568         rule->ce_mask |= RULE_ATTR_MASK;
00569 }
00570 
00571 uint32_t rtnl_rule_get_mask(struct rtnl_rule *rule)
00572 {
00573         return rule->r_mask;
00574 }
00575 
00576 void rtnl_rule_set_table(struct rtnl_rule *rule, uint32_t table)
00577 {
00578         rule->r_table = table;
00579         rule->ce_mask |= RULE_ATTR_TABLE;
00580 }
00581 
00582 uint32_t rtnl_rule_get_table(struct rtnl_rule *rule)
00583 {
00584         return rule->r_table;
00585 }
00586 
00587 void rtnl_rule_set_dsfield(struct rtnl_rule *rule, uint8_t dsfield)
00588 {
00589         rule->r_dsfield = dsfield;
00590         rule->ce_mask |= RULE_ATTR_DSFIELD;
00591 }
00592 
00593 uint8_t rtnl_rule_get_dsfield(struct rtnl_rule *rule)
00594 {
00595         return rule->r_dsfield;
00596 }
00597 
00598 static inline int __assign_addr(struct rtnl_rule *rule, struct nl_addr **pos,
00599                                 struct nl_addr *new, int flag)
00600 {
00601         if (rule->ce_mask & RULE_ATTR_FAMILY) {
00602                 if (new->a_family != rule->r_family)
00603                         return -NLE_AF_MISMATCH;
00604         } else
00605                 rule->r_family = new->a_family;
00606 
00607         if (*pos)
00608                 nl_addr_put(*pos);
00609 
00610         nl_addr_get(new);
00611         *pos = new;
00612 
00613         rule->ce_mask |= (flag | RULE_ATTR_FAMILY);
00614 
00615         return 0;
00616 }
00617 
00618 int rtnl_rule_set_src(struct rtnl_rule *rule, struct nl_addr *src)
00619 {
00620         return __assign_addr(rule, &rule->r_src, src, RULE_ATTR_SRC);
00621 }
00622 
00623 struct nl_addr *rtnl_rule_get_src(struct rtnl_rule *rule)
00624 {
00625         return rule->r_src;
00626 }
00627 
00628 int rtnl_rule_set_dst(struct rtnl_rule *rule, struct nl_addr *dst)
00629 {
00630         return __assign_addr(rule, &rule->r_dst, dst, RULE_ATTR_DST);
00631 }
00632 
00633 struct nl_addr *rtnl_rule_get_dst(struct rtnl_rule *rule)
00634 {
00635         return rule->r_dst;
00636 }
00637 
00638 int rtnl_rule_set_iif(struct rtnl_rule *rule, const char *dev)
00639 {
00640         if (strlen(dev) > IFNAMSIZ-1)
00641                 return -NLE_RANGE;
00642 
00643         strcpy(rule->r_iifname, dev);
00644         rule->ce_mask |= RULE_ATTR_IIFNAME;
00645         return 0;
00646 }
00647 
00648 char *rtnl_rule_get_iif(struct rtnl_rule *rule)
00649 {
00650         if (rule->ce_mask & RULE_ATTR_IIFNAME)
00651                 return rule->r_iifname;
00652         else
00653                 return NULL;
00654 }
00655 
00656 int rtnl_rule_set_oif(struct rtnl_rule *rule, const char *dev)
00657 {
00658         if (strlen(dev) > IFNAMSIZ-1)
00659                 return -NLE_RANGE;
00660 
00661         strcpy(rule->r_oifname, dev);
00662         rule->ce_mask |= RULE_ATTR_OIFNAME;
00663         return 0;
00664 }
00665 
00666 char *rtnl_rule_get_oif(struct rtnl_rule *rule)
00667 {
00668         if (rule->ce_mask & RULE_ATTR_OIFNAME)
00669                 return rule->r_oifname;
00670         else
00671                 return NULL;
00672 }
00673 
00674 void rtnl_rule_set_action(struct rtnl_rule *rule, uint8_t action)
00675 {
00676         rule->r_action = action;
00677         rule->ce_mask |= RULE_ATTR_ACTION;
00678 }
00679 
00680 uint8_t rtnl_rule_get_action(struct rtnl_rule *rule)
00681 {
00682         return rule->r_action;
00683 }
00684 
00685 void rtnl_rule_set_realms(struct rtnl_rule *rule, uint32_t realms)
00686 {
00687         rule->r_flow = realms;
00688         rule->ce_mask |= RULE_ATTR_FLOW;
00689 }
00690 
00691 uint32_t rtnl_rule_get_realms(struct rtnl_rule *rule)
00692 {
00693         return rule->r_flow;
00694 }
00695 
00696 void rtnl_rule_set_goto(struct rtnl_rule *rule, uint32_t ref)
00697 {
00698         rule->r_goto = ref;
00699         rule->ce_mask |= RULE_ATTR_GOTO;
00700 }
00701 
00702 uint32_t rtnl_rule_get_goto(struct rtnl_rule *rule)
00703 {
00704         return rule->r_goto;
00705 }
00706 
00707 /** @} */
00708 
00709 static struct nl_object_ops rule_obj_ops = {
00710         .oo_name                = "route/rule",
00711         .oo_size                = sizeof(struct rtnl_rule),
00712         .oo_free_data           = rule_free_data,
00713         .oo_clone               = rule_clone,
00714         .oo_dump = {
00715             [NL_DUMP_LINE]      = rule_dump_line,
00716             [NL_DUMP_DETAILS]   = rule_dump_details,
00717             [NL_DUMP_STATS]     = rule_dump_stats,
00718         },
00719         .oo_compare             = rule_compare,
00720         .oo_attrs2str           = rule_attrs2str,
00721         .oo_id_attrs            = ~0,
00722 };
00723 
00724 static struct nl_cache_ops rtnl_rule_ops = {
00725         .co_name                = "route/rule",
00726         .co_hdrsize             = sizeof(struct fib_rule_hdr),
00727         .co_msgtypes            = {
00728                                         { RTM_NEWRULE, NL_ACT_NEW, "new" },
00729                                         { RTM_DELRULE, NL_ACT_DEL, "del" },
00730                                         { RTM_GETRULE, NL_ACT_GET, "get" },
00731                                         END_OF_MSGTYPES_LIST,
00732                                   },
00733         .co_protocol            = NETLINK_ROUTE,
00734         .co_request_update      = rule_request_update,
00735         .co_msg_parser          = rule_msg_parser,
00736         .co_obj_ops             = &rule_obj_ops,
00737 };
00738 
00739 static void __init rule_init(void)
00740 {
00741         nl_cache_mngt_register(&rtnl_rule_ops);
00742 }
00743 
00744 static void __exit rule_exit(void)
00745 {
00746         nl_cache_mngt_unregister(&rtnl_rule_ops);
00747 }
00748 
00749 /** @} */