00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
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
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
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
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
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
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
00317
00318
00319
00320
00321
00322
00323
00324
00325
00326
00327
00328
00329
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
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 (tmpl->ce_mask & RULE_ATTR_SRC)
00378 frh.src_len = nl_addr_get_prefixlen(tmpl->r_src);
00379
00380 if (tmpl->ce_mask & RULE_ATTR_DST)
00381 frh.dst_len = nl_addr_get_prefixlen(tmpl->r_dst);
00382
00383 if (nlmsg_append(msg, &frh, sizeof(frh), NLMSG_ALIGNTO) < 0)
00384 goto nla_put_failure;
00385
00386 if (tmpl->ce_mask & RULE_ATTR_SRC)
00387 NLA_PUT_ADDR(msg, FRA_SRC, tmpl->r_src);
00388
00389 if (tmpl->ce_mask & RULE_ATTR_DST)
00390 NLA_PUT_ADDR(msg, FRA_DST, tmpl->r_dst);
00391
00392 if (tmpl->ce_mask & RULE_ATTR_IIFNAME)
00393 NLA_PUT_STRING(msg, FRA_IIFNAME, tmpl->r_iifname);
00394
00395 if (tmpl->ce_mask & RULE_ATTR_OIFNAME)
00396 NLA_PUT_STRING(msg, FRA_OIFNAME, tmpl->r_oifname);
00397
00398 if (tmpl->ce_mask & RULE_ATTR_PRIO)
00399 NLA_PUT_U32(msg, FRA_PRIORITY, tmpl->r_prio);
00400
00401 if (tmpl->ce_mask & RULE_ATTR_MARK)
00402 NLA_PUT_U32(msg, FRA_FWMARK, tmpl->r_mark);
00403
00404 if (tmpl->ce_mask & RULE_ATTR_MASK)
00405 NLA_PUT_U32(msg, FRA_FWMASK, tmpl->r_mask);
00406
00407 if (tmpl->ce_mask & RULE_ATTR_GOTO)
00408 NLA_PUT_U32(msg, FRA_GOTO, tmpl->r_goto);
00409
00410 if (tmpl->ce_mask & RULE_ATTR_FLOW)
00411 NLA_PUT_U32(msg, FRA_FLOW, tmpl->r_flow);
00412
00413
00414 *result = msg;
00415 return 0;
00416
00417 nla_put_failure:
00418 nlmsg_free(msg);
00419 return -NLE_MSGSIZE;
00420 }
00421
00422
00423
00424
00425
00426
00427
00428
00429
00430
00431
00432
00433
00434
00435
00436 int rtnl_rule_build_add_request(struct rtnl_rule *tmpl, int flags,
00437 struct nl_msg **result)
00438 {
00439 return build_rule_msg(tmpl, RTM_NEWRULE, NLM_F_CREATE | flags,
00440 result);
00441 }
00442
00443
00444
00445
00446
00447
00448
00449
00450
00451
00452
00453
00454
00455 int rtnl_rule_add(struct nl_sock *sk, struct rtnl_rule *tmpl, int flags)
00456 {
00457 struct nl_msg *msg;
00458 int err;
00459
00460 if ((err = rtnl_rule_build_add_request(tmpl, flags, &msg)) < 0)
00461 return err;
00462
00463 err = nl_send_auto_complete(sk, msg);
00464 nlmsg_free(msg);
00465 if (err < 0)
00466 return err;
00467
00468 return wait_for_ack(sk);
00469 }
00470
00471
00472
00473
00474
00475
00476
00477
00478
00479
00480
00481
00482
00483
00484
00485
00486
00487
00488
00489
00490
00491
00492 int rtnl_rule_build_delete_request(struct rtnl_rule *rule, int flags,
00493 struct nl_msg **result)
00494 {
00495 return build_rule_msg(rule, RTM_DELRULE, flags, result);
00496 }
00497
00498
00499
00500
00501
00502
00503
00504
00505
00506
00507
00508
00509
00510 int rtnl_rule_delete(struct nl_sock *sk, struct rtnl_rule *rule, int flags)
00511 {
00512 struct nl_msg *msg;
00513 int err;
00514
00515 if ((err = rtnl_rule_build_delete_request(rule, flags, &msg)) < 0)
00516 return err;
00517
00518 err = nl_send_auto_complete(sk, msg);
00519 nlmsg_free(msg);
00520 if (err < 0)
00521 return err;
00522
00523 return wait_for_ack(sk);
00524 }
00525
00526
00527
00528
00529
00530
00531
00532
00533 void rtnl_rule_set_family(struct rtnl_rule *rule, int family)
00534 {
00535 rule->r_family = family;
00536 rule->ce_mask |= RULE_ATTR_FAMILY;
00537 }
00538
00539 int rtnl_rule_get_family(struct rtnl_rule *rule)
00540 {
00541 if (rule->ce_mask & RULE_ATTR_FAMILY)
00542 return rule->r_family;
00543 else
00544 return AF_UNSPEC;
00545 }
00546
00547 void rtnl_rule_set_prio(struct rtnl_rule *rule, uint32_t prio)
00548 {
00549 rule->r_prio = prio;
00550 rule->ce_mask |= RULE_ATTR_PRIO;
00551 }
00552
00553 uint32_t rtnl_rule_get_prio(struct rtnl_rule *rule)
00554 {
00555 return rule->r_prio;
00556 }
00557
00558 void rtnl_rule_set_mark(struct rtnl_rule *rule, uint32_t mark)
00559 {
00560 rule->r_mark = mark;
00561 rule->ce_mask |= RULE_ATTR_MARK;
00562 }
00563
00564 uint32_t rtnl_rule_get_mark(struct rtnl_rule *rule)
00565 {
00566 return rule->r_mark;
00567 }
00568
00569 void rtnl_rule_set_mask(struct rtnl_rule *rule, uint32_t mask)
00570 {
00571 rule->r_mask = mask;
00572 rule->ce_mask |= RULE_ATTR_MASK;
00573 }
00574
00575 uint32_t rtnl_rule_get_mask(struct rtnl_rule *rule)
00576 {
00577 return rule->r_mask;
00578 }
00579
00580 void rtnl_rule_set_table(struct rtnl_rule *rule, uint32_t table)
00581 {
00582 rule->r_table = table;
00583 rule->ce_mask |= RULE_ATTR_TABLE;
00584 }
00585
00586 uint32_t rtnl_rule_get_table(struct rtnl_rule *rule)
00587 {
00588 return rule->r_table;
00589 }
00590
00591 void rtnl_rule_set_dsfield(struct rtnl_rule *rule, uint8_t dsfield)
00592 {
00593 rule->r_dsfield = dsfield;
00594 rule->ce_mask |= RULE_ATTR_DSFIELD;
00595 }
00596
00597 uint8_t rtnl_rule_get_dsfield(struct rtnl_rule *rule)
00598 {
00599 return rule->r_dsfield;
00600 }
00601
00602 static inline int __assign_addr(struct rtnl_rule *rule, struct nl_addr **pos,
00603 struct nl_addr *new, int flag)
00604 {
00605 if (rule->ce_mask & RULE_ATTR_FAMILY) {
00606 if (new->a_family != rule->r_family)
00607 return -NLE_AF_MISMATCH;
00608 } else
00609 rule->r_family = new->a_family;
00610
00611 if (*pos)
00612 nl_addr_put(*pos);
00613
00614 nl_addr_get(new);
00615 *pos = new;
00616
00617 rule->ce_mask |= (flag | RULE_ATTR_FAMILY);
00618
00619 return 0;
00620 }
00621
00622 int rtnl_rule_set_src(struct rtnl_rule *rule, struct nl_addr *src)
00623 {
00624 return __assign_addr(rule, &rule->r_src, src, RULE_ATTR_SRC);
00625 }
00626
00627 struct nl_addr *rtnl_rule_get_src(struct rtnl_rule *rule)
00628 {
00629 return rule->r_src;
00630 }
00631
00632 int rtnl_rule_set_dst(struct rtnl_rule *rule, struct nl_addr *dst)
00633 {
00634 return __assign_addr(rule, &rule->r_dst, dst, RULE_ATTR_DST);
00635 }
00636
00637 struct nl_addr *rtnl_rule_get_dst(struct rtnl_rule *rule)
00638 {
00639 return rule->r_dst;
00640 }
00641
00642 int rtnl_rule_set_iif(struct rtnl_rule *rule, const char *dev)
00643 {
00644 if (strlen(dev) > IFNAMSIZ-1)
00645 return -NLE_RANGE;
00646
00647 strcpy(rule->r_iifname, dev);
00648 rule->ce_mask |= RULE_ATTR_IIFNAME;
00649 return 0;
00650 }
00651
00652 char *rtnl_rule_get_iif(struct rtnl_rule *rule)
00653 {
00654 if (rule->ce_mask & RULE_ATTR_IIFNAME)
00655 return rule->r_iifname;
00656 else
00657 return NULL;
00658 }
00659
00660 int rtnl_rule_set_oif(struct rtnl_rule *rule, const char *dev)
00661 {
00662 if (strlen(dev) > IFNAMSIZ-1)
00663 return -NLE_RANGE;
00664
00665 strcpy(rule->r_oifname, dev);
00666 rule->ce_mask |= RULE_ATTR_OIFNAME;
00667 return 0;
00668 }
00669
00670 char *rtnl_rule_get_oif(struct rtnl_rule *rule)
00671 {
00672 if (rule->ce_mask & RULE_ATTR_OIFNAME)
00673 return rule->r_oifname;
00674 else
00675 return NULL;
00676 }
00677
00678 void rtnl_rule_set_action(struct rtnl_rule *rule, uint8_t action)
00679 {
00680 rule->r_action = action;
00681 rule->ce_mask |= RULE_ATTR_ACTION;
00682 }
00683
00684 uint8_t rtnl_rule_get_action(struct rtnl_rule *rule)
00685 {
00686 return rule->r_action;
00687 }
00688
00689 void rtnl_rule_set_realms(struct rtnl_rule *rule, uint32_t realms)
00690 {
00691 rule->r_flow = realms;
00692 rule->ce_mask |= RULE_ATTR_FLOW;
00693 }
00694
00695 uint32_t rtnl_rule_get_realms(struct rtnl_rule *rule)
00696 {
00697 return rule->r_flow;
00698 }
00699
00700 void rtnl_rule_set_goto(struct rtnl_rule *rule, uint32_t ref)
00701 {
00702 rule->r_goto = ref;
00703 rule->ce_mask |= RULE_ATTR_GOTO;
00704 }
00705
00706 uint32_t rtnl_rule_get_goto(struct rtnl_rule *rule)
00707 {
00708 return rule->r_goto;
00709 }
00710
00711
00712
00713 static struct nl_object_ops rule_obj_ops = {
00714 .oo_name = "route/rule",
00715 .oo_size = sizeof(struct rtnl_rule),
00716 .oo_free_data = rule_free_data,
00717 .oo_clone = rule_clone,
00718 .oo_dump = {
00719 [NL_DUMP_LINE] = rule_dump_line,
00720 [NL_DUMP_DETAILS] = rule_dump_details,
00721 [NL_DUMP_STATS] = rule_dump_stats,
00722 },
00723 .oo_compare = rule_compare,
00724 .oo_attrs2str = rule_attrs2str,
00725 .oo_id_attrs = ~0,
00726 };
00727
00728 static struct nl_cache_ops rtnl_rule_ops = {
00729 .co_name = "route/rule",
00730 .co_hdrsize = sizeof(struct fib_rule_hdr),
00731 .co_msgtypes = {
00732 { RTM_NEWRULE, NL_ACT_NEW, "new" },
00733 { RTM_DELRULE, NL_ACT_DEL, "del" },
00734 { RTM_GETRULE, NL_ACT_GET, "get" },
00735 END_OF_MSGTYPES_LIST,
00736 },
00737 .co_protocol = NETLINK_ROUTE,
00738 .co_request_update = rule_request_update,
00739 .co_msg_parser = rule_msg_parser,
00740 .co_obj_ops = &rule_obj_ops,
00741 };
00742
00743 static void __init rule_init(void)
00744 {
00745 nl_cache_mngt_register(&rtnl_rule_ops);
00746 }
00747
00748 static void __exit rule_exit(void)
00749 {
00750 nl_cache_mngt_unregister(&rtnl_rule_ops);
00751 }
00752
00753