rule.c revision d84430702496f617c01c5e2d27d0e82e02390bb7
1/* 2 * lib/route/rule.c Routing Rules 3 * 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 7 * of the License. 8 * 9 * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch> 10 */ 11 12/** 13 * @ingroup rtnl 14 * @defgroup rule Routing Rules 15 * @brief 16 * @{ 17 */ 18 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> 24#include <inttypes.h> 25 26/** @cond SKIP */ 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 40 41static struct nl_cache_ops rtnl_rule_ops; 42static struct nl_object_ops rule_obj_ops; 43/** @endcond */ 44 45static void rule_free_data(struct nl_object *c) 46{ 47 struct rtnl_rule *rule = nl_object_priv(c); 48 49 if (!rule) 50 return; 51 52 nl_addr_put(rule->r_src); 53 nl_addr_put(rule->r_dst); 54} 55 56static int rule_clone(struct nl_object *_dst, struct nl_object *_src) 57{ 58 struct rtnl_rule *dst = nl_object_priv(_dst); 59 struct rtnl_rule *src = nl_object_priv(_src); 60 61 if (src->r_src) 62 if (!(dst->r_src = nl_addr_clone(src->r_src))) 63 return -NLE_NOMEM; 64 65 if (src->r_dst) 66 if (!(dst->r_dst = nl_addr_clone(src->r_dst))) 67 return -NLE_NOMEM; 68 69 return 0; 70} 71 72static 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, }, 78}; 79 80static int rule_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who, 81 struct nlmsghdr *n, struct nl_parser_param *pp) 82{ 83 struct rtnl_rule *rule; 84 struct rtmsg *r; 85 struct nlattr *tb[RTA_MAX+1]; 86 int err = 1, family; 87 88 rule = rtnl_rule_alloc(); 89 if (!rule) { 90 err = -NLE_NOMEM; 91 goto errout; 92 } 93 94 rule->ce_msgtype = n->nlmsg_type; 95 r = nlmsg_data(n); 96 97 err = nlmsg_parse(n, sizeof(*r), tb, RTA_MAX, rule_policy); 98 if (err < 0) 99 goto errout; 100 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 | 109 RULE_ATTR_TABLE); 110 111 if (tb[RTA_PRIORITY]) { 112 rule->r_prio = nla_get_u32(tb[RTA_PRIORITY]); 113 rule->ce_mask |= RULE_ATTR_PRIO; 114 } 115 116 if (tb[RTA_SRC]) { 117 if (!(rule->r_src = nl_addr_alloc_attr(tb[RTA_SRC], family))) 118 goto errout_enomem; 119 nl_addr_set_prefixlen(rule->r_src, r->rtm_src_len); 120 rule->ce_mask |= RULE_ATTR_SRC; 121 } 122 123 if (tb[RTA_DST]) { 124 if (!(rule->r_dst = nl_addr_alloc_attr(tb[RTA_DST], family))) 125 goto errout_enomem; 126 nl_addr_set_prefixlen(rule->r_dst, r->rtm_dst_len); 127 rule->ce_mask |= RULE_ATTR_DST; 128 } 129 130 if (tb[RTA_PROTOINFO]) { 131 rule->r_mark = nla_get_u32(tb[RTA_PROTOINFO]); 132 rule->ce_mask |= RULE_ATTR_MARK; 133 } 134 135 if (tb[RTA_IIF]) { 136 nla_strlcpy(rule->r_iif, tb[RTA_IIF], IFNAMSIZ); 137 rule->ce_mask |= RULE_ATTR_IIF; 138 } 139 140 if (tb[RTA_FLOW]) { 141 rule->r_realms = nla_get_u32(tb[RTA_FLOW]); 142 rule->ce_mask |= RULE_ATTR_REALMS; 143 } 144 145 if (tb[RTA_GATEWAY]) { 146 rule->r_srcmap = nl_addr_alloc_attr(tb[RTA_GATEWAY], family); 147 if (!rule->r_srcmap) 148 goto errout_enomem; 149 rule->ce_mask |= RULE_ATTR_SRCMAP; 150 } 151 152 if (tb[RTA_TABLE]) { 153 rule->r_table = nla_get_u32(tb[RTA_TABLE]); 154 rule->ce_mask |= RULE_ATTR_TABLE; 155 } 156 157 err = pp->pp_cb((struct nl_object *) rule, pp); 158errout: 159 rtnl_rule_put(rule); 160 return err; 161 162errout_enomem: 163 err = -NLE_NOMEM; 164 goto errout; 165} 166 167static int rule_request_update(struct nl_cache *c, struct nl_sock *h) 168{ 169 return nl_rtgen_request(h, RTM_GETRULE, AF_UNSPEC, NLM_F_DUMP); 170} 171 172static void rule_dump_line(struct nl_object *o, struct nl_dump_params *p) 173{ 174 struct rtnl_rule *r = (struct rtnl_rule *) o; 175 char buf[128]; 176 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))); 179 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); 185 186 if (r->ce_mask & RULE_ATTR_DST) 187 nl_dump(p, "to %s ", 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); 191 192 if (r->ce_mask & RULE_ATTR_DSFIELD && r->r_dsfield) 193 nl_dump(p, "tos %d ", r->r_dsfield); 194 195 if (r->ce_mask & RULE_ATTR_MARK) 196 nl_dump(p, "mark %" PRIx64 , r->r_mark); 197 198 if (r->ce_mask & RULE_ATTR_IIF) 199 nl_dump(p, "iif %s ", r->r_iif); 200 201 if (r->ce_mask & RULE_ATTR_TABLE) 202 nl_dump(p, "lookup %s ", 203 rtnl_route_table2str(r->r_table, buf, sizeof(buf))); 204 205 if (r->ce_mask & RULE_ATTR_REALMS) 206 nl_dump(p, "realms %s ", 207 rtnl_realms2str(r->r_realms, buf, sizeof(buf))); 208 209 nl_dump(p, "action %s\n", 210 nl_rtntype2str(r->r_type, buf, sizeof(buf))); 211} 212 213static void rule_dump_details(struct nl_object *obj, struct nl_dump_params *p) 214{ 215 struct rtnl_rule *rule = (struct rtnl_rule *) obj; 216 char buf[128]; 217 218 rule_dump_line(obj, p); 219 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))); 223} 224 225static void rule_dump_stats(struct nl_object *obj, struct nl_dump_params *p) 226{ 227 rule_dump_details(obj, p); 228} 229 230static void rule_dump_xml(struct nl_object *obj, struct nl_dump_params *p) 231{ 232 struct rtnl_rule *rule = (struct rtnl_rule *) obj; 233 char buf[128]; 234 235 nl_dump_line(p, "<rule>\n"); 236 237 nl_dump_line(p, " <priority>%u</priority>\n", rule->r_prio); 238 nl_dump_line(p, " <family>%s</family>\n", 239 nl_af2str(rule->r_family, buf, sizeof(buf))); 240 241 if (rule->ce_mask & RULE_ATTR_DST) 242 nl_dump_line(p, " <dst>%s</dst>\n", 243 nl_addr2str(rule->r_dst, buf, sizeof(buf))); 244 245 if (rule->ce_mask & RULE_ATTR_DST_LEN) 246 nl_dump_line(p, " <dstlen>%u</dstlen>\n", rule->r_dst_len); 247 248 if (rule->ce_mask & RULE_ATTR_SRC) 249 nl_dump_line(p, " <src>%s</src>\n", 250 nl_addr2str(rule->r_src, buf, sizeof(buf))); 251 252 if (rule->ce_mask & RULE_ATTR_SRC_LEN) 253 nl_dump_line(p, " <srclen>%u</srclen>\n", rule->r_src_len); 254 255 if (rule->ce_mask & RULE_ATTR_IIF) 256 nl_dump_line(p, " <iif>%s</iif>\n", rule->r_iif); 257 258 if (rule->ce_mask & RULE_ATTR_TABLE) 259 nl_dump_line(p, " <table>%u</table>\n", rule->r_table); 260 261 if (rule->ce_mask & RULE_ATTR_REALMS) 262 nl_dump_line(p, " <realms>%u</realms>\n", rule->r_realms); 263 264 if (rule->ce_mask & RULE_ATTR_MARK) 265 nl_dump_line(p, " <mark>%" PRIx64 "</mark>\n", rule->r_mark); 266 267 if (rule->ce_mask & RULE_ATTR_DSFIELD) 268 nl_dump_line(p, " <dsfield>%u</dsfield>\n", rule->r_dsfield); 269 270 if (rule->ce_mask & RULE_ATTR_TYPE) 271 nl_dump_line(p, "<type>%s</type>\n", 272 nl_rtntype2str(rule->r_type, buf, sizeof(buf))); 273 274 if (rule->ce_mask & RULE_ATTR_SRCMAP) 275 nl_dump_line(p, "<srcmap>%s</srcmap>\n", 276 nl_addr2str(rule->r_srcmap, buf, sizeof(buf))); 277 278 nl_dump_line(p, "</rule>\n"); 279} 280 281static void rule_dump_env(struct nl_object *obj, struct nl_dump_params *p) 282{ 283 struct rtnl_rule *rule = (struct rtnl_rule *) obj; 284 char buf[128]; 285 286 nl_dump_line(p, "RULE_PRIORITY=%u\n", rule->r_prio); 287 nl_dump_line(p, "RULE_FAMILY=%s\n", 288 nl_af2str(rule->r_family, buf, sizeof(buf))); 289 290 if (rule->ce_mask & RULE_ATTR_DST) 291 nl_dump_line(p, "RULE_DST=%s\n", 292 nl_addr2str(rule->r_dst, buf, sizeof(buf))); 293 294 if (rule->ce_mask & RULE_ATTR_DST_LEN) 295 nl_dump_line(p, "RULE_DSTLEN=%u\n", rule->r_dst_len); 296 297 if (rule->ce_mask & RULE_ATTR_SRC) 298 nl_dump_line(p, "RULE_SRC=%s\n", 299 nl_addr2str(rule->r_src, buf, sizeof(buf))); 300 301 if (rule->ce_mask & RULE_ATTR_SRC_LEN) 302 nl_dump_line(p, "RULE_SRCLEN=%u\n", rule->r_src_len); 303 304 if (rule->ce_mask & RULE_ATTR_IIF) 305 nl_dump_line(p, "RULE_IIF=%s\n", rule->r_iif); 306 307 if (rule->ce_mask & RULE_ATTR_TABLE) 308 nl_dump_line(p, "RULE_TABLE=%u\n", rule->r_table); 309 310 if (rule->ce_mask & RULE_ATTR_REALMS) 311 nl_dump_line(p, "RULE_REALM=%u\n", rule->r_realms); 312 313 if (rule->ce_mask & RULE_ATTR_MARK) 314 nl_dump_line(p, "RULE_MARK=0x%" PRIx64 "\n", rule->r_mark); 315 316 if (rule->ce_mask & RULE_ATTR_DSFIELD) 317 nl_dump_line(p, "RULE_DSFIELD=%u\n", rule->r_dsfield); 318 319 if (rule->ce_mask & RULE_ATTR_TYPE) 320 nl_dump_line(p, "RULE_TYPE=%s\n", 321 nl_rtntype2str(rule->r_type, buf, sizeof(buf))); 322 323 if (rule->ce_mask & RULE_ATTR_SRCMAP) 324 nl_dump_line(p, "RULE_SRCMAP=%s\n", 325 nl_addr2str(rule->r_srcmap, buf, sizeof(buf))); 326} 327 328static int rule_compare(struct nl_object *_a, struct nl_object *_b, 329 uint32_t attrs, int flags) 330{ 331 struct rtnl_rule *a = (struct rtnl_rule *) _a; 332 struct rtnl_rule *b = (struct rtnl_rule *) _b; 333 int diff = 0; 334 335#define RULE_DIFF(ATTR, EXPR) ATTR_DIFF(attrs, RULE_ATTR_##ATTR, a, b, EXPR) 336 337 diff |= RULE_DIFF(FAMILY, a->r_family != b->r_family); 338 diff |= RULE_DIFF(TABLE, a->r_table != b->r_table); 339 diff |= RULE_DIFF(REALMS, a->r_realms != b->r_realms); 340 diff |= RULE_DIFF(DSFIELD, a->r_dsfield != b->r_dsfield); 341 diff |= RULE_DIFF(TYPE, a->r_type != b->r_type); 342 diff |= RULE_DIFF(PRIO, a->r_prio != b->r_prio); 343 diff |= RULE_DIFF(MARK, a->r_mark != b->r_mark); 344 diff |= RULE_DIFF(SRC_LEN, a->r_src_len != b->r_src_len); 345 diff |= RULE_DIFF(DST_LEN, a->r_dst_len != b->r_dst_len); 346 diff |= RULE_DIFF(SRC, nl_addr_cmp(a->r_src, b->r_src)); 347 diff |= RULE_DIFF(DST, nl_addr_cmp(a->r_dst, b->r_dst)); 348 diff |= RULE_DIFF(IIF, strcmp(a->r_iif, b->r_iif)); 349 350#undef RULE_DIFF 351 352 return diff; 353} 354 355static struct trans_tbl rule_attrs[] = { 356 __ADD(RULE_ATTR_FAMILY, family) 357 __ADD(RULE_ATTR_PRIO, prio) 358 __ADD(RULE_ATTR_MARK, mark) 359 __ADD(RULE_ATTR_IIF, iif) 360 __ADD(RULE_ATTR_REALMS, realms) 361 __ADD(RULE_ATTR_SRC, src) 362 __ADD(RULE_ATTR_DST, dst) 363 __ADD(RULE_ATTR_DSFIELD, dsfield) 364 __ADD(RULE_ATTR_TABLE, table) 365 __ADD(RULE_ATTR_TYPE, type) 366 __ADD(RULE_ATTR_SRC_LEN, src_len) 367 __ADD(RULE_ATTR_DST_LEN, dst_len) 368 __ADD(RULE_ATTR_SRCMAP, srcmap) 369}; 370 371static char *rule_attrs2str(int attrs, char *buf, size_t len) 372{ 373 return __flags2str(attrs, buf, len, rule_attrs, 374 ARRAY_SIZE(rule_attrs)); 375} 376 377/** 378 * @name Allocation/Freeing 379 * @{ 380 */ 381 382struct rtnl_rule *rtnl_rule_alloc(void) 383{ 384 return (struct rtnl_rule *) nl_object_alloc(&rule_obj_ops); 385} 386 387void rtnl_rule_put(struct rtnl_rule *rule) 388{ 389 nl_object_put((struct nl_object *) rule); 390} 391 392/** @} */ 393 394/** 395 * @name Cache Management 396 * @{ 397 */ 398 399/** 400 * Build a rule cache including all rules currently configured in the kernel. 401 * @arg sk Netlink socket. 402 * @arg family Address family or AF_UNSPEC. 403 * @arg result Pointer to store resulting cache. 404 * 405 * Allocates a new rule cache, initializes it properly and updates it 406 * to include all rules currently configured in the kernel. 407 * 408 * @return 0 on success or a negative error code. 409 */ 410int rtnl_rule_alloc_cache(struct nl_sock *sock, int family, 411 struct nl_cache **result) 412{ 413 struct nl_cache * cache; 414 int err; 415 416 if (!(cache = nl_cache_alloc(&rtnl_rule_ops))) 417 return -NLE_NOMEM; 418 419 cache->c_iarg1 = family; 420 421 if (sock && (err = nl_cache_refill(sock, cache)) < 0) { 422 free(cache); 423 return err; 424 } 425 426 *result = cache; 427 return 0; 428} 429 430/** @} */ 431 432/** 433 * @name Rule Addition 434 * @{ 435 */ 436 437static int build_rule_msg(struct rtnl_rule *tmpl, int cmd, int flags, 438 struct nl_msg **result) 439{ 440 struct nl_msg *msg; 441 struct rtmsg rtm = { 442 .rtm_type = RTN_UNSPEC 443 }; 444 445 if (cmd == RTM_NEWRULE) 446 rtm.rtm_type = RTN_UNICAST; 447 448 if (tmpl->ce_mask & RULE_ATTR_FAMILY) 449 rtm.rtm_family = tmpl->r_family; 450 451 if (tmpl->ce_mask & RULE_ATTR_TABLE) 452 rtm.rtm_table = tmpl->r_table; 453 454 if (tmpl->ce_mask & RULE_ATTR_DSFIELD) 455 rtm.rtm_tos = tmpl->r_dsfield; 456 457 if (tmpl->ce_mask & RULE_ATTR_TYPE) 458 rtm.rtm_type = tmpl->r_type; 459 460 if (tmpl->ce_mask & RULE_ATTR_SRC_LEN) 461 rtm.rtm_src_len = tmpl->r_src_len; 462 463 if (tmpl->ce_mask & RULE_ATTR_DST_LEN) 464 rtm.rtm_dst_len = tmpl->r_dst_len; 465 466 msg = nlmsg_alloc_simple(cmd, flags); 467 if (!msg) 468 return -NLE_NOMEM; 469 470 if (nlmsg_append(msg, &rtm, sizeof(rtm), NLMSG_ALIGNTO) < 0) 471 goto nla_put_failure; 472 473 if (tmpl->ce_mask & RULE_ATTR_SRC) 474 NLA_PUT_ADDR(msg, RTA_SRC, tmpl->r_src); 475 476 if (tmpl->ce_mask & RULE_ATTR_DST) 477 NLA_PUT_ADDR(msg, RTA_DST, tmpl->r_dst); 478 479 if (tmpl->ce_mask & RULE_ATTR_PRIO) 480 NLA_PUT_U32(msg, RTA_PRIORITY, tmpl->r_prio); 481 482 if (tmpl->ce_mask & RULE_ATTR_MARK) 483 NLA_PUT_U32(msg, RTA_PROTOINFO, tmpl->r_mark); 484 485 if (tmpl->ce_mask & RULE_ATTR_REALMS) 486 NLA_PUT_U32(msg, RTA_FLOW, tmpl->r_realms); 487 488 if (tmpl->ce_mask & RULE_ATTR_IIF) 489 NLA_PUT_STRING(msg, RTA_IIF, tmpl->r_iif); 490 491 *result = msg; 492 return 0; 493 494nla_put_failure: 495 nlmsg_free(msg); 496 return -NLE_MSGSIZE; 497} 498 499/** 500 * Build netlink request message to add a new rule 501 * @arg tmpl template with data of new rule 502 * @arg flags additional netlink message flags 503 * 504 * Builds a new netlink message requesting a addition of a new 505 * rule. The netlink message header isn't fully equipped with 506 * all relevant fields and must thus be sent out via nl_send_auto_complete() 507 * or supplemented as needed. \a tmpl must contain the attributes of the new 508 * address set via \c rtnl_rule_set_* functions. 509 * 510 * @return The netlink message 511 */ 512int rtnl_rule_build_add_request(struct rtnl_rule *tmpl, int flags, 513 struct nl_msg **result) 514{ 515 return build_rule_msg(tmpl, RTM_NEWRULE, NLM_F_CREATE | flags, 516 result); 517} 518 519/** 520 * Add a new rule 521 * @arg sk Netlink socket. 522 * @arg tmpl template with requested changes 523 * @arg flags additional netlink message flags 524 * 525 * Builds a netlink message by calling rtnl_rule_build_add_request(), 526 * sends the request to the kernel and waits for the next ACK to be 527 * received and thus blocks until the request has been fullfilled. 528 * 529 * @return 0 on sucess or a negative error if an error occured. 530 */ 531int rtnl_rule_add(struct nl_sock *sk, struct rtnl_rule *tmpl, int flags) 532{ 533 struct nl_msg *msg; 534 int err; 535 536 if ((err = rtnl_rule_build_add_request(tmpl, flags, &msg)) < 0) 537 return err; 538 539 err = nl_send_auto_complete(sk, msg); 540 nlmsg_free(msg); 541 if (err < 0) 542 return err; 543 544 return nl_wait_for_ack(sk); 545} 546 547/** @} */ 548 549/** 550 * @name Rule Deletion 551 * @{ 552 */ 553 554/** 555 * Build a netlink request message to delete a rule 556 * @arg rule rule to delete 557 * @arg flags additional netlink message flags 558 * 559 * Builds a new netlink message requesting a deletion of a rule. 560 * The netlink message header isn't fully equipped with all relevant 561 * fields and must thus be sent out via nl_send_auto_complete() 562 * or supplemented as needed. \a rule must point to an existing 563 * address. 564 * 565 * @return The netlink message 566 */ 567int rtnl_rule_build_delete_request(struct rtnl_rule *rule, int flags, 568 struct nl_msg **result) 569{ 570 return build_rule_msg(rule, RTM_DELRULE, flags, result); 571} 572 573/** 574 * Delete a rule 575 * @arg sk Netlink socket. 576 * @arg rule rule to delete 577 * @arg flags additional netlink message flags 578 * 579 * Builds a netlink message by calling rtnl_rule_build_delete_request(), 580 * sends the request to the kernel and waits for the next ACK to be 581 * received and thus blocks until the request has been fullfilled. 582 * 583 * @return 0 on sucess or a negative error if an error occured. 584 */ 585int rtnl_rule_delete(struct nl_sock *sk, struct rtnl_rule *rule, int flags) 586{ 587 struct nl_msg *msg; 588 int err; 589 590 if ((err = rtnl_rule_build_delete_request(rule, flags, &msg)) < 0) 591 return err; 592 593 err = nl_send_auto_complete(sk, msg); 594 nlmsg_free(msg); 595 if (err < 0) 596 return err; 597 598 return nl_wait_for_ack(sk); 599} 600 601/** @} */ 602 603/** 604 * @name Attribute Modification 605 * @{ 606 */ 607 608void rtnl_rule_set_family(struct rtnl_rule *rule, int family) 609{ 610 rule->r_family = family; 611 rule->ce_mask |= RULE_ATTR_FAMILY; 612} 613 614int rtnl_rule_get_family(struct rtnl_rule *rule) 615{ 616 if (rule->ce_mask & RULE_ATTR_FAMILY) 617 return rule->r_family; 618 else 619 return AF_UNSPEC; 620} 621 622void rtnl_rule_set_prio(struct rtnl_rule *rule, int prio) 623{ 624 rule->r_prio = prio; 625 rule->ce_mask |= RULE_ATTR_PRIO; 626} 627 628int rtnl_rule_get_prio(struct rtnl_rule *rule) 629{ 630 if (rule->ce_mask & RULE_ATTR_PRIO) 631 return rule->r_prio; 632 else 633 return -1; 634} 635 636void rtnl_rule_set_mark(struct rtnl_rule *rule, uint64_t mark) 637{ 638 rule->r_mark = mark; 639 rule->ce_mask |= RULE_ATTR_MARK; 640} 641 642uint64_t rtnl_rule_get_mark(struct rtnl_rule *rule) 643{ 644 if (rule->ce_mask & RULE_ATTR_MARK) 645 return rule->r_mark; 646 else 647 return UINT_LEAST64_MAX; 648} 649 650void rtnl_rule_set_table(struct rtnl_rule *rule, int table) 651{ 652 rule->r_table = table; 653 rule->ce_mask |= RULE_ATTR_TABLE; 654} 655 656int rtnl_rule_get_table(struct rtnl_rule *rule) 657{ 658 if (rule->ce_mask & RULE_ATTR_TABLE) 659 return rule->r_table; 660 else 661 return -1; 662} 663 664void rtnl_rule_set_dsfield(struct rtnl_rule *rule, int dsfield) 665{ 666 rule->r_dsfield = dsfield; 667 rule->ce_mask |= RULE_ATTR_DSFIELD; 668} 669 670int rtnl_rule_get_dsfield(struct rtnl_rule *rule) 671{ 672 if (rule->ce_mask & RULE_ATTR_DSFIELD) 673 return rule->r_dsfield; 674 else 675 return -1; 676} 677 678void rtnl_rule_set_src_len(struct rtnl_rule *rule, int len) 679{ 680 rule->r_src_len = len; 681 if (rule->ce_mask & RULE_ATTR_SRC) 682 nl_addr_set_prefixlen(rule->r_src, len); 683 rule->ce_mask |= RULE_ATTR_SRC_LEN; 684} 685 686int rtnl_rule_get_src_len(struct rtnl_rule *rule) 687{ 688 if (rule->ce_mask & RULE_ATTR_SRC_LEN) 689 return rule->r_src_len; 690 else 691 return -1; 692} 693 694void rtnl_rule_set_dst_len(struct rtnl_rule *rule, int len) 695{ 696 rule->r_dst_len = len; 697 if (rule->ce_mask & RULE_ATTR_DST) 698 nl_addr_set_prefixlen(rule->r_dst, len); 699 rule->ce_mask |= RULE_ATTR_DST_LEN; 700} 701 702int rtnl_rule_get_dst_len(struct rtnl_rule *rule) 703{ 704 if (rule->ce_mask & RULE_ATTR_DST_LEN) 705 return rule->r_dst_len; 706 else 707 return -1; 708} 709 710static inline int __assign_addr(struct rtnl_rule *rule, struct nl_addr **pos, 711 struct nl_addr *new, uint8_t *len, int flag) 712{ 713 if (rule->ce_mask & RULE_ATTR_FAMILY) { 714 if (new->a_family != rule->r_family) 715 return -NLE_AF_MISMATCH; 716 } else 717 rule->r_family = new->a_family; 718 719 if (*pos) 720 nl_addr_put(*pos); 721 722 nl_addr_get(new); 723 *pos = new; 724 *len = nl_addr_get_prefixlen(new); 725 726 rule->ce_mask |= (flag | RULE_ATTR_FAMILY); 727 728 return 0; 729} 730 731int rtnl_rule_set_src(struct rtnl_rule *rule, struct nl_addr *src) 732{ 733 return __assign_addr(rule, &rule->r_src, src, &rule->r_src_len, 734 RULE_ATTR_SRC | RULE_ATTR_SRC_LEN); 735} 736 737struct nl_addr *rtnl_rule_get_src(struct rtnl_rule *rule) 738{ 739 if (rule->ce_mask & RULE_ATTR_SRC) 740 return rule->r_src; 741 else 742 return NULL; 743} 744 745int rtnl_rule_set_dst(struct rtnl_rule *rule, struct nl_addr *dst) 746{ 747 return __assign_addr(rule, &rule->r_dst, dst, &rule->r_dst_len, 748 RULE_ATTR_DST | RULE_ATTR_DST_LEN); 749} 750 751struct nl_addr *rtnl_rule_get_dst(struct rtnl_rule *rule) 752{ 753 if (rule->ce_mask & RULE_ATTR_DST) 754 return rule->r_dst; 755 else 756 return NULL; 757} 758 759int rtnl_rule_set_iif(struct rtnl_rule *rule, const char *dev) 760{ 761 if (strlen(dev) > IFNAMSIZ-1) 762 return -NLE_RANGE; 763 764 strcpy(rule->r_iif, dev); 765 rule->ce_mask |= RULE_ATTR_IIF; 766 return 0; 767} 768 769char *rtnl_rule_get_iif(struct rtnl_rule *rule) 770{ 771 if (rule->ce_mask & RULE_ATTR_IIF) 772 return rule->r_iif; 773 else 774 return NULL; 775} 776 777void rtnl_rule_set_action(struct rtnl_rule *rule, int type) 778{ 779 rule->r_type = type; 780 rule->ce_mask |= RULE_ATTR_TYPE; 781} 782 783int rtnl_rule_get_action(struct rtnl_rule *rule) 784{ 785 if (rule->ce_mask & RULE_ATTR_TYPE) 786 return rule->r_type; 787 else 788 return -NLE_NOATTR; 789} 790 791void rtnl_rule_set_realms(struct rtnl_rule *rule, uint32_t realms) 792{ 793 rule->r_realms = realms; 794 rule->ce_mask |= RULE_ATTR_REALMS; 795} 796 797uint32_t rtnl_rule_get_realms(struct rtnl_rule *rule) 798{ 799 if (rule->ce_mask & RULE_ATTR_REALMS) 800 return rule->r_realms; 801 else 802 return 0; 803} 804 805/** @} */ 806 807static struct nl_object_ops rule_obj_ops = { 808 .oo_name = "route/rule", 809 .oo_size = sizeof(struct rtnl_rule), 810 .oo_free_data = rule_free_data, 811 .oo_clone = rule_clone, 812 .oo_dump = { 813 [NL_DUMP_LINE] = rule_dump_line, 814 [NL_DUMP_DETAILS] = rule_dump_details, 815 [NL_DUMP_STATS] = rule_dump_stats, 816 [NL_DUMP_XML] = rule_dump_xml, 817 [NL_DUMP_ENV] = rule_dump_env, 818 }, 819 .oo_compare = rule_compare, 820 .oo_attrs2str = rule_attrs2str, 821 .oo_id_attrs = ~0, 822}; 823 824static struct nl_cache_ops rtnl_rule_ops = { 825 .co_name = "route/rule", 826 .co_hdrsize = sizeof(struct rtmsg), 827 .co_msgtypes = { 828 { RTM_NEWRULE, NL_ACT_NEW, "new" }, 829 { RTM_DELRULE, NL_ACT_DEL, "del" }, 830 { RTM_GETRULE, NL_ACT_GET, "get" }, 831 END_OF_MSGTYPES_LIST, 832 }, 833 .co_protocol = NETLINK_ROUTE, 834 .co_request_update = rule_request_update, 835 .co_msg_parser = rule_msg_parser, 836 .co_obj_ops = &rule_obj_ops, 837}; 838 839static void __init rule_init(void) 840{ 841 nl_cache_mngt_register(&rtnl_rule_ops); 842} 843 844static void __exit rule_exit(void) 845{ 846 nl_cache_mngt_unregister(&rtnl_rule_ops); 847} 848 849/** @} */ 850