libnl 2.0
|
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 /** @} */