libnl 2.0

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