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-2010 Thomas Graf <tgraf@suug.ch>
10 */
11
12 /**
13 * @ingroup rtnl
14 * @defgroup rule Routing Rules
15 * @brief
16 * @{
17 */
18
19 #include <netlink-private/netlink.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_TABLE 0x0002
29 #define RULE_ATTR_ACTION 0x0004
30 #define RULE_ATTR_FLAGS 0x0008
31 #define RULE_ATTR_IIFNAME 0x0010
32 #define RULE_ATTR_OIFNAME 0x0020
33 #define RULE_ATTR_PRIO 0x0040
34 #define RULE_ATTR_MARK 0x0080
35 #define RULE_ATTR_MASK 0x0100
36 #define RULE_ATTR_GOTO 0x0200
37 #define RULE_ATTR_SRC 0x0400
38 #define RULE_ATTR_DST 0x0800
39 #define RULE_ATTR_DSFIELD 0x1000
40 #define RULE_ATTR_FLOW 0x2000
41
42 static struct nl_cache_ops rtnl_rule_ops;
43 static struct nl_object_ops rule_obj_ops;
44 /** @endcond */
45
rule_free_data(struct nl_object * c)46 static void rule_free_data(struct nl_object *c)
47 {
48 struct rtnl_rule *rule = nl_object_priv(c);
49
50 if (!rule)
51 return;
52
53 nl_addr_put(rule->r_src);
54 nl_addr_put(rule->r_dst);
55 }
56
rule_clone(struct nl_object * _dst,struct nl_object * _src)57 static int rule_clone(struct nl_object *_dst, struct nl_object *_src)
58 {
59 struct rtnl_rule *dst = nl_object_priv(_dst);
60 struct rtnl_rule *src = nl_object_priv(_src);
61
62 if (src->r_src)
63 if (!(dst->r_src = nl_addr_clone(src->r_src)))
64 return -NLE_NOMEM;
65
66 if (src->r_dst)
67 if (!(dst->r_dst = nl_addr_clone(src->r_dst)))
68 return -NLE_NOMEM;
69
70 return 0;
71 }
72
73 static struct nla_policy rule_policy[FRA_MAX+1] = {
74 [FRA_TABLE] = { .type = NLA_U32 },
75 [FRA_IIFNAME] = { .type = NLA_STRING, .maxlen = IFNAMSIZ },
76 [FRA_OIFNAME] = { .type = NLA_STRING, .maxlen = IFNAMSIZ },
77 [FRA_PRIORITY] = { .type = NLA_U32 },
78 [FRA_FWMARK] = { .type = NLA_U32 },
79 [FRA_FWMASK] = { .type = NLA_U32 },
80 [FRA_GOTO] = { .type = NLA_U32 },
81 [FRA_FLOW] = { .type = NLA_U32 },
82 };
83
rule_msg_parser(struct nl_cache_ops * ops,struct sockaddr_nl * who,struct nlmsghdr * n,struct nl_parser_param * pp)84 static int rule_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
85 struct nlmsghdr *n, struct nl_parser_param *pp)
86 {
87 struct rtnl_rule *rule;
88 struct fib_rule_hdr *frh;
89 struct nlattr *tb[FRA_MAX+1];
90 int err = 1, family;
91
92 rule = rtnl_rule_alloc();
93 if (!rule) {
94 err = -NLE_NOMEM;
95 goto errout;
96 }
97
98 rule->ce_msgtype = n->nlmsg_type;
99 frh = nlmsg_data(n);
100
101 err = nlmsg_parse(n, sizeof(*frh), tb, FRA_MAX, rule_policy);
102 if (err < 0)
103 goto errout;
104
105 rule->r_family = family = frh->family;
106 rule->r_table = frh->table;
107 rule->r_action = frh->action;
108 rule->r_flags = frh->flags;
109
110 rule->ce_mask = (RULE_ATTR_FAMILY | RULE_ATTR_TABLE | RULE_ATTR_ACTION |
111 RULE_ATTR_FLAGS);
112
113 /* ipv4 only */
114 if (frh->tos) {
115 rule->r_dsfield = frh->tos;
116 rule->ce_mask |= RULE_ATTR_DSFIELD;
117 }
118
119 if (tb[FRA_TABLE]) {
120 rule->r_table = nla_get_u32(tb[FRA_TABLE]);
121 rule->ce_mask |= RULE_ATTR_TABLE;
122 }
123
124 if (tb[FRA_IIFNAME]) {
125 nla_strlcpy(rule->r_iifname, tb[FRA_IIFNAME], IFNAMSIZ);
126 rule->ce_mask |= RULE_ATTR_IIFNAME;
127 }
128
129 if (tb[FRA_OIFNAME]) {
130 nla_strlcpy(rule->r_oifname, tb[FRA_OIFNAME], IFNAMSIZ);
131 rule->ce_mask |= RULE_ATTR_OIFNAME;
132 }
133
134 if (tb[FRA_PRIORITY]) {
135 rule->r_prio = nla_get_u32(tb[FRA_PRIORITY]);
136 rule->ce_mask |= RULE_ATTR_PRIO;
137 }
138
139 if (tb[FRA_FWMARK]) {
140 rule->r_mark = nla_get_u32(tb[FRA_FWMARK]);
141 rule->ce_mask |= RULE_ATTR_MARK;
142 }
143
144 if (tb[FRA_FWMASK]) {
145 rule->r_mask = nla_get_u32(tb[FRA_FWMASK]);
146 rule->ce_mask |= RULE_ATTR_MASK;
147 }
148
149 if (tb[FRA_GOTO]) {
150 rule->r_goto = nla_get_u32(tb[FRA_GOTO]);
151 rule->ce_mask |= RULE_ATTR_GOTO;
152 }
153
154 if (tb[FRA_SRC]) {
155 if (!(rule->r_src = nl_addr_alloc_attr(tb[FRA_SRC], family)))
156 goto errout_enomem;
157
158 nl_addr_set_prefixlen(rule->r_src, frh->src_len);
159 rule->ce_mask |= RULE_ATTR_SRC;
160 }
161
162 if (tb[FRA_DST]) {
163 if (!(rule->r_dst = nl_addr_alloc_attr(tb[FRA_DST], family)))
164 goto errout_enomem;
165 nl_addr_set_prefixlen(rule->r_dst, frh->dst_len);
166 rule->ce_mask |= RULE_ATTR_DST;
167 }
168
169 /* ipv4 only */
170 if (tb[FRA_FLOW]) {
171 rule->r_flow = nla_get_u32(tb[FRA_FLOW]);
172 rule->ce_mask |= RULE_ATTR_FLOW;
173 }
174
175 err = pp->pp_cb((struct nl_object *) rule, pp);
176 errout:
177 rtnl_rule_put(rule);
178 return err;
179
180 errout_enomem:
181 err = -NLE_NOMEM;
182 goto errout;
183 }
184
rule_request_update(struct nl_cache * c,struct nl_sock * h)185 static int rule_request_update(struct nl_cache *c, struct nl_sock *h)
186 {
187 return nl_rtgen_request(h, RTM_GETRULE, AF_UNSPEC, NLM_F_DUMP);
188 }
189
rule_dump_line(struct nl_object * o,struct nl_dump_params * p)190 static void rule_dump_line(struct nl_object *o, struct nl_dump_params *p)
191 {
192 struct rtnl_rule *r = (struct rtnl_rule *) o;
193 char buf[128];
194
195 nl_dump_line(p, "%8d ", (r->ce_mask & RULE_ATTR_PRIO) ? r->r_prio : 0);
196 nl_dump(p, "%s ", nl_af2str(r->r_family, buf, sizeof(buf)));
197
198 if (r->ce_mask & RULE_ATTR_SRC)
199 nl_dump(p, "from %s ",
200 nl_addr2str(r->r_src, buf, sizeof(buf)));
201
202 if (r->ce_mask & RULE_ATTR_DST)
203 nl_dump(p, "to %s ",
204 nl_addr2str(r->r_dst, buf, sizeof(buf)));
205
206 if (r->ce_mask & RULE_ATTR_DSFIELD)
207 nl_dump(p, "tos %u ", r->r_dsfield);
208
209 if (r->ce_mask & (RULE_ATTR_MARK | RULE_ATTR_MASK))
210 nl_dump(p, "mark %#x/%#x", r->r_mark, r->r_mask);
211
212 if (r->ce_mask & RULE_ATTR_IIFNAME)
213 nl_dump(p, "iif %s ", r->r_iifname);
214
215 if (r->ce_mask & RULE_ATTR_OIFNAME)
216 nl_dump(p, "oif %s ", r->r_oifname);
217
218 if (r->ce_mask & RULE_ATTR_TABLE)
219 nl_dump(p, "lookup %s ",
220 rtnl_route_table2str(r->r_table, buf, sizeof(buf)));
221
222 if (r->ce_mask & RULE_ATTR_FLOW)
223 nl_dump(p, "flow %s ",
224 rtnl_realms2str(r->r_flow, buf, sizeof(buf)));
225
226 if (r->ce_mask & RULE_ATTR_GOTO)
227 nl_dump(p, "goto %u ", r->r_goto);
228
229 if (r->ce_mask & RULE_ATTR_ACTION)
230 nl_dump(p, "action %s",
231 nl_rtntype2str(r->r_action, buf, sizeof(buf)));
232
233 nl_dump(p, "\n");
234 }
235
rule_dump_details(struct nl_object * obj,struct nl_dump_params * p)236 static void rule_dump_details(struct nl_object *obj, struct nl_dump_params *p)
237 {
238 rule_dump_line(obj, p);
239 }
240
rule_dump_stats(struct nl_object * obj,struct nl_dump_params * p)241 static void rule_dump_stats(struct nl_object *obj, struct nl_dump_params *p)
242 {
243 rule_dump_details(obj, p);
244 }
245
246 #define RULE_ATTR_FLAGS 0x0008
247
rule_compare(struct nl_object * _a,struct nl_object * _b,uint32_t attrs,int flags)248 static int rule_compare(struct nl_object *_a, struct nl_object *_b,
249 uint32_t attrs, int flags)
250 {
251 struct rtnl_rule *a = (struct rtnl_rule *) _a;
252 struct rtnl_rule *b = (struct rtnl_rule *) _b;
253 int diff = 0;
254
255 #define RULE_DIFF(ATTR, EXPR) ATTR_DIFF(attrs, RULE_ATTR_##ATTR, a, b, EXPR)
256
257 diff |= RULE_DIFF(FAMILY, a->r_family != b->r_family);
258 diff |= RULE_DIFF(TABLE, a->r_table != b->r_table);
259 diff |= RULE_DIFF(ACTION, a->r_action != b->r_action);
260 diff |= RULE_DIFF(IIFNAME, strcmp(a->r_iifname, b->r_iifname));
261 diff |= RULE_DIFF(OIFNAME, strcmp(a->r_oifname, b->r_oifname));
262 diff |= RULE_DIFF(PRIO, a->r_prio != b->r_prio);
263 diff |= RULE_DIFF(MARK, a->r_mark != b->r_mark);
264 diff |= RULE_DIFF(MASK, a->r_mask != b->r_mask);
265 diff |= RULE_DIFF(GOTO, a->r_goto != b->r_goto);
266 diff |= RULE_DIFF(SRC, nl_addr_cmp(a->r_src, b->r_src));
267 diff |= RULE_DIFF(DST, nl_addr_cmp(a->r_dst, b->r_dst));
268 diff |= RULE_DIFF(DSFIELD, a->r_dsfield != b->r_dsfield);
269 diff |= RULE_DIFF(FLOW, a->r_flow != b->r_flow);
270
271 #undef RULE_DIFF
272
273 return diff;
274 }
275
276 static const struct trans_tbl rule_attrs[] = {
277 __ADD(RULE_ATTR_FAMILY, family)
278 __ADD(RULE_ATTR_TABLE, table)
279 __ADD(RULE_ATTR_ACTION, action)
280 __ADD(RULE_ATTR_IIFNAME, iifname)
281 __ADD(RULE_ATTR_OIFNAME, oifname)
282 __ADD(RULE_ATTR_PRIO, prio)
283 __ADD(RULE_ATTR_MARK, mark)
284 __ADD(RULE_ATTR_MASK, mask)
285 __ADD(RULE_ATTR_GOTO, goto)
286 __ADD(RULE_ATTR_SRC, src)
287 __ADD(RULE_ATTR_DST, dst)
288 __ADD(RULE_ATTR_DSFIELD, dsfield)
289 __ADD(RULE_ATTR_FLOW, flow)
290 };
291
rule_attrs2str(int attrs,char * buf,size_t len)292 static char *rule_attrs2str(int attrs, char *buf, size_t len)
293 {
294 return __flags2str(attrs, buf, len, rule_attrs,
295 ARRAY_SIZE(rule_attrs));
296 }
297
298 /**
299 * @name Allocation/Freeing
300 * @{
301 */
302
rtnl_rule_alloc(void)303 struct rtnl_rule *rtnl_rule_alloc(void)
304 {
305 return (struct rtnl_rule *) nl_object_alloc(&rule_obj_ops);
306 }
307
rtnl_rule_put(struct rtnl_rule * rule)308 void rtnl_rule_put(struct rtnl_rule *rule)
309 {
310 nl_object_put((struct nl_object *) rule);
311 }
312
313 /** @} */
314
315 /**
316 * @name Cache Management
317 * @{
318 */
319
320 /**
321 * Build a rule cache including all rules currently configured in the kernel.
322 * @arg sock Netlink socket.
323 * @arg family Address family or AF_UNSPEC.
324 * @arg result Pointer to store resulting cache.
325 *
326 * Allocates a new rule cache, initializes it properly and updates it
327 * to include all rules currently configured in the kernel.
328 *
329 * @return 0 on success or a negative error code.
330 */
rtnl_rule_alloc_cache(struct nl_sock * sock,int family,struct nl_cache ** result)331 int rtnl_rule_alloc_cache(struct nl_sock *sock, int family,
332 struct nl_cache **result)
333 {
334 struct nl_cache * cache;
335 int err;
336
337 if (!(cache = nl_cache_alloc(&rtnl_rule_ops)))
338 return -NLE_NOMEM;
339
340 cache->c_iarg1 = family;
341
342 if (sock && (err = nl_cache_refill(sock, cache)) < 0) {
343 free(cache);
344 return err;
345 }
346
347 *result = cache;
348 return 0;
349 }
350
351 /** @} */
352
353 /**
354 * @name Rule Addition
355 * @{
356 */
357
build_rule_msg(struct rtnl_rule * tmpl,int cmd,int flags,struct nl_msg ** result)358 static int build_rule_msg(struct rtnl_rule *tmpl, int cmd, int flags,
359 struct nl_msg **result)
360 {
361 struct nl_msg *msg;
362 struct fib_rule_hdr frh = {
363 .family = tmpl->r_family,
364 .table = tmpl->r_table,
365 .action = tmpl->r_action,
366 .flags = tmpl->r_flags,
367 .tos = tmpl->r_dsfield,
368 };
369
370 if (!(tmpl->ce_mask & RULE_ATTR_FAMILY))
371 return -NLE_MISSING_ATTR;
372
373 msg = nlmsg_alloc_simple(cmd, flags);
374 if (!msg)
375 return -NLE_NOMEM;
376
377 if (tmpl->ce_mask & RULE_ATTR_SRC)
378 frh.src_len = nl_addr_get_prefixlen(tmpl->r_src);
379
380 if (tmpl->ce_mask & RULE_ATTR_DST)
381 frh.dst_len = nl_addr_get_prefixlen(tmpl->r_dst);
382
383 if (nlmsg_append(msg, &frh, sizeof(frh), NLMSG_ALIGNTO) < 0)
384 goto nla_put_failure;
385
386 /* Additional table attribute replacing the 8bit in the header, was
387 * required to allow more than 256 tables. */
388 NLA_PUT_U32(msg, FRA_TABLE, tmpl->r_table);
389
390 if (tmpl->ce_mask & RULE_ATTR_SRC)
391 NLA_PUT_ADDR(msg, FRA_SRC, tmpl->r_src);
392
393 if (tmpl->ce_mask & RULE_ATTR_DST)
394 NLA_PUT_ADDR(msg, FRA_DST, tmpl->r_dst);
395
396 if (tmpl->ce_mask & RULE_ATTR_IIFNAME)
397 NLA_PUT_STRING(msg, FRA_IIFNAME, tmpl->r_iifname);
398
399 if (tmpl->ce_mask & RULE_ATTR_OIFNAME)
400 NLA_PUT_STRING(msg, FRA_OIFNAME, tmpl->r_oifname);
401
402 if (tmpl->ce_mask & RULE_ATTR_PRIO)
403 NLA_PUT_U32(msg, FRA_PRIORITY, tmpl->r_prio);
404
405 if (tmpl->ce_mask & RULE_ATTR_MARK)
406 NLA_PUT_U32(msg, FRA_FWMARK, tmpl->r_mark);
407
408 if (tmpl->ce_mask & RULE_ATTR_MASK)
409 NLA_PUT_U32(msg, FRA_FWMASK, tmpl->r_mask);
410
411 if (tmpl->ce_mask & RULE_ATTR_GOTO)
412 NLA_PUT_U32(msg, FRA_GOTO, tmpl->r_goto);
413
414 if (tmpl->ce_mask & RULE_ATTR_FLOW)
415 NLA_PUT_U32(msg, FRA_FLOW, tmpl->r_flow);
416
417
418 *result = msg;
419 return 0;
420
421 nla_put_failure:
422 nlmsg_free(msg);
423 return -NLE_MSGSIZE;
424 }
425
426 /**
427 * Build netlink request message to add a new rule
428 * @arg tmpl template with data of new rule
429 * @arg flags additional netlink message flags
430 * @arg result Result pointer
431 *
432 * Builds a new netlink message requesting a addition of a new
433 * rule. The netlink message header isn't fully equipped with
434 * all relevant fields and must thus be sent out via nl_send_auto_complete()
435 * or supplemented as needed. \a tmpl must contain the attributes of the new
436 * address set via \c rtnl_rule_set_* functions.
437 *
438 * @return 0 on success or a negative error code.
439 */
rtnl_rule_build_add_request(struct rtnl_rule * tmpl,int flags,struct nl_msg ** result)440 int rtnl_rule_build_add_request(struct rtnl_rule *tmpl, int flags,
441 struct nl_msg **result)
442 {
443 return build_rule_msg(tmpl, RTM_NEWRULE, NLM_F_CREATE | flags,
444 result);
445 }
446
447 /**
448 * Add a new rule
449 * @arg sk Netlink socket.
450 * @arg tmpl template with requested changes
451 * @arg flags additional netlink message flags
452 *
453 * Builds a netlink message by calling rtnl_rule_build_add_request(),
454 * sends the request to the kernel and waits for the next ACK to be
455 * received and thus blocks until the request has been fullfilled.
456 *
457 * @return 0 on sucess or a negative error if an error occured.
458 */
rtnl_rule_add(struct nl_sock * sk,struct rtnl_rule * tmpl,int flags)459 int rtnl_rule_add(struct nl_sock *sk, struct rtnl_rule *tmpl, int flags)
460 {
461 struct nl_msg *msg;
462 int err;
463
464 if ((err = rtnl_rule_build_add_request(tmpl, flags, &msg)) < 0)
465 return err;
466
467 err = nl_send_auto_complete(sk, msg);
468 nlmsg_free(msg);
469 if (err < 0)
470 return err;
471
472 return wait_for_ack(sk);
473 }
474
475 /** @} */
476
477 /**
478 * @name Rule Deletion
479 * @{
480 */
481
482 /**
483 * Build a netlink request message to delete a rule
484 * @arg rule rule to delete
485 * @arg flags additional netlink message flags
486 * @arg result Result pointer
487 *
488 * Builds a new netlink message requesting a deletion of a rule.
489 * The netlink message header isn't fully equipped with all relevant
490 * fields and must thus be sent out via nl_send_auto_complete()
491 * or supplemented as needed. \a rule must point to an existing
492 * address.
493 *
494 * @return 0 on success or a negative error code.
495 */
rtnl_rule_build_delete_request(struct rtnl_rule * rule,int flags,struct nl_msg ** result)496 int rtnl_rule_build_delete_request(struct rtnl_rule *rule, int flags,
497 struct nl_msg **result)
498 {
499 return build_rule_msg(rule, RTM_DELRULE, flags, result);
500 }
501
502 /**
503 * Delete a rule
504 * @arg sk Netlink socket.
505 * @arg rule rule to delete
506 * @arg flags additional netlink message flags
507 *
508 * Builds a netlink message by calling rtnl_rule_build_delete_request(),
509 * sends the request to the kernel and waits for the next ACK to be
510 * received and thus blocks until the request has been fullfilled.
511 *
512 * @return 0 on sucess or a negative error if an error occured.
513 */
rtnl_rule_delete(struct nl_sock * sk,struct rtnl_rule * rule,int flags)514 int rtnl_rule_delete(struct nl_sock *sk, struct rtnl_rule *rule, int flags)
515 {
516 struct nl_msg *msg;
517 int err;
518
519 if ((err = rtnl_rule_build_delete_request(rule, flags, &msg)) < 0)
520 return err;
521
522 err = nl_send_auto_complete(sk, msg);
523 nlmsg_free(msg);
524 if (err < 0)
525 return err;
526
527 return wait_for_ack(sk);
528 }
529
530 /** @} */
531
532 /**
533 * @name Attribute Modification
534 * @{
535 */
536
rtnl_rule_set_family(struct rtnl_rule * rule,int family)537 void rtnl_rule_set_family(struct rtnl_rule *rule, int family)
538 {
539 rule->r_family = family;
540 rule->ce_mask |= RULE_ATTR_FAMILY;
541 }
542
rtnl_rule_get_family(struct rtnl_rule * rule)543 int rtnl_rule_get_family(struct rtnl_rule *rule)
544 {
545 if (rule->ce_mask & RULE_ATTR_FAMILY)
546 return rule->r_family;
547 else
548 return AF_UNSPEC;
549 }
550
rtnl_rule_set_prio(struct rtnl_rule * rule,uint32_t prio)551 void rtnl_rule_set_prio(struct rtnl_rule *rule, uint32_t prio)
552 {
553 rule->r_prio = prio;
554 rule->ce_mask |= RULE_ATTR_PRIO;
555 }
556
rtnl_rule_get_prio(struct rtnl_rule * rule)557 uint32_t rtnl_rule_get_prio(struct rtnl_rule *rule)
558 {
559 return rule->r_prio;
560 }
561
rtnl_rule_set_mark(struct rtnl_rule * rule,uint32_t mark)562 void rtnl_rule_set_mark(struct rtnl_rule *rule, uint32_t mark)
563 {
564 rule->r_mark = mark;
565 rule->ce_mask |= RULE_ATTR_MARK;
566 }
567
rtnl_rule_get_mark(struct rtnl_rule * rule)568 uint32_t rtnl_rule_get_mark(struct rtnl_rule *rule)
569 {
570 return rule->r_mark;
571 }
572
rtnl_rule_set_mask(struct rtnl_rule * rule,uint32_t mask)573 void rtnl_rule_set_mask(struct rtnl_rule *rule, uint32_t mask)
574 {
575 rule->r_mask = mask;
576 rule->ce_mask |= RULE_ATTR_MASK;
577 }
578
rtnl_rule_get_mask(struct rtnl_rule * rule)579 uint32_t rtnl_rule_get_mask(struct rtnl_rule *rule)
580 {
581 return rule->r_mask;
582 }
583
rtnl_rule_set_table(struct rtnl_rule * rule,uint32_t table)584 void rtnl_rule_set_table(struct rtnl_rule *rule, uint32_t table)
585 {
586 rule->r_table = table;
587 rule->ce_mask |= RULE_ATTR_TABLE;
588 }
589
rtnl_rule_get_table(struct rtnl_rule * rule)590 uint32_t rtnl_rule_get_table(struct rtnl_rule *rule)
591 {
592 return rule->r_table;
593 }
594
rtnl_rule_set_dsfield(struct rtnl_rule * rule,uint8_t dsfield)595 void rtnl_rule_set_dsfield(struct rtnl_rule *rule, uint8_t dsfield)
596 {
597 rule->r_dsfield = dsfield;
598 rule->ce_mask |= RULE_ATTR_DSFIELD;
599 }
600
rtnl_rule_get_dsfield(struct rtnl_rule * rule)601 uint8_t rtnl_rule_get_dsfield(struct rtnl_rule *rule)
602 {
603 return rule->r_dsfield;
604 }
605
__assign_addr(struct rtnl_rule * rule,struct nl_addr ** pos,struct nl_addr * new,int flag)606 static inline int __assign_addr(struct rtnl_rule *rule, struct nl_addr **pos,
607 struct nl_addr *new, int flag)
608 {
609 if (rule->ce_mask & RULE_ATTR_FAMILY) {
610 if (new->a_family != rule->r_family)
611 return -NLE_AF_MISMATCH;
612 } else
613 rule->r_family = new->a_family;
614
615 if (*pos)
616 nl_addr_put(*pos);
617
618 nl_addr_get(new);
619 *pos = new;
620
621 rule->ce_mask |= (flag | RULE_ATTR_FAMILY);
622
623 return 0;
624 }
625
rtnl_rule_set_src(struct rtnl_rule * rule,struct nl_addr * src)626 int rtnl_rule_set_src(struct rtnl_rule *rule, struct nl_addr *src)
627 {
628 return __assign_addr(rule, &rule->r_src, src, RULE_ATTR_SRC);
629 }
630
rtnl_rule_get_src(struct rtnl_rule * rule)631 struct nl_addr *rtnl_rule_get_src(struct rtnl_rule *rule)
632 {
633 return rule->r_src;
634 }
635
rtnl_rule_set_dst(struct rtnl_rule * rule,struct nl_addr * dst)636 int rtnl_rule_set_dst(struct rtnl_rule *rule, struct nl_addr *dst)
637 {
638 return __assign_addr(rule, &rule->r_dst, dst, RULE_ATTR_DST);
639 }
640
rtnl_rule_get_dst(struct rtnl_rule * rule)641 struct nl_addr *rtnl_rule_get_dst(struct rtnl_rule *rule)
642 {
643 return rule->r_dst;
644 }
645
rtnl_rule_set_iif(struct rtnl_rule * rule,const char * dev)646 int rtnl_rule_set_iif(struct rtnl_rule *rule, const char *dev)
647 {
648 if (strlen(dev) > IFNAMSIZ-1)
649 return -NLE_RANGE;
650
651 strcpy(rule->r_iifname, dev);
652 rule->ce_mask |= RULE_ATTR_IIFNAME;
653 return 0;
654 }
655
rtnl_rule_get_iif(struct rtnl_rule * rule)656 char *rtnl_rule_get_iif(struct rtnl_rule *rule)
657 {
658 if (rule->ce_mask & RULE_ATTR_IIFNAME)
659 return rule->r_iifname;
660 else
661 return NULL;
662 }
663
rtnl_rule_set_oif(struct rtnl_rule * rule,const char * dev)664 int rtnl_rule_set_oif(struct rtnl_rule *rule, const char *dev)
665 {
666 if (strlen(dev) > IFNAMSIZ-1)
667 return -NLE_RANGE;
668
669 strcpy(rule->r_oifname, dev);
670 rule->ce_mask |= RULE_ATTR_OIFNAME;
671 return 0;
672 }
673
rtnl_rule_get_oif(struct rtnl_rule * rule)674 char *rtnl_rule_get_oif(struct rtnl_rule *rule)
675 {
676 if (rule->ce_mask & RULE_ATTR_OIFNAME)
677 return rule->r_oifname;
678 else
679 return NULL;
680 }
681
rtnl_rule_set_action(struct rtnl_rule * rule,uint8_t action)682 void rtnl_rule_set_action(struct rtnl_rule *rule, uint8_t action)
683 {
684 rule->r_action = action;
685 rule->ce_mask |= RULE_ATTR_ACTION;
686 }
687
rtnl_rule_get_action(struct rtnl_rule * rule)688 uint8_t rtnl_rule_get_action(struct rtnl_rule *rule)
689 {
690 return rule->r_action;
691 }
692
rtnl_rule_set_realms(struct rtnl_rule * rule,uint32_t realms)693 void rtnl_rule_set_realms(struct rtnl_rule *rule, uint32_t realms)
694 {
695 rule->r_flow = realms;
696 rule->ce_mask |= RULE_ATTR_FLOW;
697 }
698
rtnl_rule_get_realms(struct rtnl_rule * rule)699 uint32_t rtnl_rule_get_realms(struct rtnl_rule *rule)
700 {
701 return rule->r_flow;
702 }
703
rtnl_rule_set_goto(struct rtnl_rule * rule,uint32_t ref)704 void rtnl_rule_set_goto(struct rtnl_rule *rule, uint32_t ref)
705 {
706 rule->r_goto = ref;
707 rule->ce_mask |= RULE_ATTR_GOTO;
708 }
709
rtnl_rule_get_goto(struct rtnl_rule * rule)710 uint32_t rtnl_rule_get_goto(struct rtnl_rule *rule)
711 {
712 return rule->r_goto;
713 }
714
715 /** @} */
716
717 static struct nl_object_ops rule_obj_ops = {
718 .oo_name = "route/rule",
719 .oo_size = sizeof(struct rtnl_rule),
720 .oo_free_data = rule_free_data,
721 .oo_clone = rule_clone,
722 .oo_dump = {
723 [NL_DUMP_LINE] = rule_dump_line,
724 [NL_DUMP_DETAILS] = rule_dump_details,
725 [NL_DUMP_STATS] = rule_dump_stats,
726 },
727 .oo_compare = rule_compare,
728 .oo_attrs2str = rule_attrs2str,
729 .oo_id_attrs = ~0,
730 };
731
732 static struct nl_cache_ops rtnl_rule_ops = {
733 .co_name = "route/rule",
734 .co_hdrsize = sizeof(struct fib_rule_hdr),
735 .co_msgtypes = {
736 { RTM_NEWRULE, NL_ACT_NEW, "new" },
737 { RTM_DELRULE, NL_ACT_DEL, "del" },
738 { RTM_GETRULE, NL_ACT_GET, "get" },
739 END_OF_MSGTYPES_LIST,
740 },
741 .co_protocol = NETLINK_ROUTE,
742 .co_request_update = rule_request_update,
743 .co_msg_parser = rule_msg_parser,
744 .co_obj_ops = &rule_obj_ops,
745 };
746
rule_init(void)747 static void __init rule_init(void)
748 {
749 nl_cache_mngt_register(&rtnl_rule_ops);
750 }
751
rule_exit(void)752 static void __exit rule_exit(void)
753 {
754 nl_cache_mngt_unregister(&rtnl_rule_ops);
755 }
756
757 /** @} */
758