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
41 static struct nl_cache_ops rtnl_rule_ops;
42 static struct nl_object_ops rule_obj_ops;
43 /** @endcond */
44
rule_free_data(struct nl_object * c)45 static 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
rule_clone(struct nl_object * _dst,struct nl_object * _src)56 static 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
72 static 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
rule_msg_parser(struct nl_cache_ops * ops,struct sockaddr_nl * who,struct nlmsghdr * n,struct nl_parser_param * pp)80 static 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);
158 errout:
159 rtnl_rule_put(rule);
160 return err;
161
162 errout_enomem:
163 err = -NLE_NOMEM;
164 goto errout;
165 }
166
rule_request_update(struct nl_cache * c,struct nl_sock * h)167 static 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
rule_dump_line(struct nl_object * o,struct nl_dump_params * p)172 static 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
rule_dump_details(struct nl_object * obj,struct nl_dump_params * p)213 static 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
rule_dump_stats(struct nl_object * obj,struct nl_dump_params * p)225 static void rule_dump_stats(struct nl_object *obj, struct nl_dump_params *p)
226 {
227 rule_dump_details(obj, p);
228 }
229
rule_dump_env(struct nl_object * obj,struct nl_dump_params * p)230 static void rule_dump_env(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_PRIORITY=%u\n", rule->r_prio);
236 nl_dump_line(p, "RULE_FAMILY=%s\n",
237 nl_af2str(rule->r_family, buf, sizeof(buf)));
238
239 if (rule->ce_mask & RULE_ATTR_DST)
240 nl_dump_line(p, "RULE_DST=%s\n",
241 nl_addr2str(rule->r_dst, buf, sizeof(buf)));
242
243 if (rule->ce_mask & RULE_ATTR_DST_LEN)
244 nl_dump_line(p, "RULE_DSTLEN=%u\n", rule->r_dst_len);
245
246 if (rule->ce_mask & RULE_ATTR_SRC)
247 nl_dump_line(p, "RULE_SRC=%s\n",
248 nl_addr2str(rule->r_src, buf, sizeof(buf)));
249
250 if (rule->ce_mask & RULE_ATTR_SRC_LEN)
251 nl_dump_line(p, "RULE_SRCLEN=%u\n", rule->r_src_len);
252
253 if (rule->ce_mask & RULE_ATTR_IIF)
254 nl_dump_line(p, "RULE_IIF=%s\n", rule->r_iif);
255
256 if (rule->ce_mask & RULE_ATTR_TABLE)
257 nl_dump_line(p, "RULE_TABLE=%u\n", rule->r_table);
258
259 if (rule->ce_mask & RULE_ATTR_REALMS)
260 nl_dump_line(p, "RULE_REALM=%u\n", rule->r_realms);
261
262 if (rule->ce_mask & RULE_ATTR_MARK)
263 nl_dump_line(p, "RULE_MARK=0x%" PRIx64 "\n", rule->r_mark);
264
265 if (rule->ce_mask & RULE_ATTR_DSFIELD)
266 nl_dump_line(p, "RULE_DSFIELD=%u\n", rule->r_dsfield);
267
268 if (rule->ce_mask & RULE_ATTR_TYPE)
269 nl_dump_line(p, "RULE_TYPE=%s\n",
270 nl_rtntype2str(rule->r_type, buf, sizeof(buf)));
271
272 if (rule->ce_mask & RULE_ATTR_SRCMAP)
273 nl_dump_line(p, "RULE_SRCMAP=%s\n",
274 nl_addr2str(rule->r_srcmap, buf, sizeof(buf)));
275 }
276
rule_compare(struct nl_object * _a,struct nl_object * _b,uint32_t attrs,int flags)277 static int rule_compare(struct nl_object *_a, struct nl_object *_b,
278 uint32_t attrs, int flags)
279 {
280 struct rtnl_rule *a = (struct rtnl_rule *) _a;
281 struct rtnl_rule *b = (struct rtnl_rule *) _b;
282 int diff = 0;
283
284 #define RULE_DIFF(ATTR, EXPR) ATTR_DIFF(attrs, RULE_ATTR_##ATTR, a, b, EXPR)
285
286 diff |= RULE_DIFF(FAMILY, a->r_family != b->r_family);
287 diff |= RULE_DIFF(TABLE, a->r_table != b->r_table);
288 diff |= RULE_DIFF(REALMS, a->r_realms != b->r_realms);
289 diff |= RULE_DIFF(DSFIELD, a->r_dsfield != b->r_dsfield);
290 diff |= RULE_DIFF(TYPE, a->r_type != b->r_type);
291 diff |= RULE_DIFF(PRIO, a->r_prio != b->r_prio);
292 diff |= RULE_DIFF(MARK, a->r_mark != b->r_mark);
293 diff |= RULE_DIFF(SRC_LEN, a->r_src_len != b->r_src_len);
294 diff |= RULE_DIFF(DST_LEN, a->r_dst_len != b->r_dst_len);
295 diff |= RULE_DIFF(SRC, nl_addr_cmp(a->r_src, b->r_src));
296 diff |= RULE_DIFF(DST, nl_addr_cmp(a->r_dst, b->r_dst));
297 diff |= RULE_DIFF(IIF, strcmp(a->r_iif, b->r_iif));
298
299 #undef RULE_DIFF
300
301 return diff;
302 }
303
304 static struct trans_tbl rule_attrs[] = {
305 __ADD(RULE_ATTR_FAMILY, family)
306 __ADD(RULE_ATTR_PRIO, prio)
307 __ADD(RULE_ATTR_MARK, mark)
308 __ADD(RULE_ATTR_IIF, iif)
309 __ADD(RULE_ATTR_REALMS, realms)
310 __ADD(RULE_ATTR_SRC, src)
311 __ADD(RULE_ATTR_DST, dst)
312 __ADD(RULE_ATTR_DSFIELD, dsfield)
313 __ADD(RULE_ATTR_TABLE, table)
314 __ADD(RULE_ATTR_TYPE, type)
315 __ADD(RULE_ATTR_SRC_LEN, src_len)
316 __ADD(RULE_ATTR_DST_LEN, dst_len)
317 __ADD(RULE_ATTR_SRCMAP, srcmap)
318 };
319
rule_attrs2str(int attrs,char * buf,size_t len)320 static char *rule_attrs2str(int attrs, char *buf, size_t len)
321 {
322 return __flags2str(attrs, buf, len, rule_attrs,
323 ARRAY_SIZE(rule_attrs));
324 }
325
326 /**
327 * @name Allocation/Freeing
328 * @{
329 */
330
rtnl_rule_alloc(void)331 struct rtnl_rule *rtnl_rule_alloc(void)
332 {
333 return (struct rtnl_rule *) nl_object_alloc(&rule_obj_ops);
334 }
335
rtnl_rule_put(struct rtnl_rule * rule)336 void rtnl_rule_put(struct rtnl_rule *rule)
337 {
338 nl_object_put((struct nl_object *) rule);
339 }
340
341 /** @} */
342
343 /**
344 * @name Cache Management
345 * @{
346 */
347
348 /**
349 * Build a rule cache including all rules currently configured in the kernel.
350 * @arg sk Netlink socket.
351 * @arg family Address family or AF_UNSPEC.
352 * @arg result Pointer to store resulting cache.
353 *
354 * Allocates a new rule cache, initializes it properly and updates it
355 * to include all rules currently configured in the kernel.
356 *
357 * @return 0 on success or a negative error code.
358 */
rtnl_rule_alloc_cache(struct nl_sock * sock,int family,struct nl_cache ** result)359 int rtnl_rule_alloc_cache(struct nl_sock *sock, int family,
360 struct nl_cache **result)
361 {
362 struct nl_cache * cache;
363 int err;
364
365 if (!(cache = nl_cache_alloc(&rtnl_rule_ops)))
366 return -NLE_NOMEM;
367
368 cache->c_iarg1 = family;
369
370 if (sock && (err = nl_cache_refill(sock, cache)) < 0) {
371 free(cache);
372 return err;
373 }
374
375 *result = cache;
376 return 0;
377 }
378
379 /** @} */
380
381 /**
382 * @name Rule Addition
383 * @{
384 */
385
build_rule_msg(struct rtnl_rule * tmpl,int cmd,int flags,struct nl_msg ** result)386 static int build_rule_msg(struct rtnl_rule *tmpl, int cmd, int flags,
387 struct nl_msg **result)
388 {
389 struct nl_msg *msg;
390 struct rtmsg rtm = {
391 .rtm_type = RTN_UNSPEC
392 };
393
394 if (cmd == RTM_NEWRULE)
395 rtm.rtm_type = RTN_UNICAST;
396
397 if (tmpl->ce_mask & RULE_ATTR_FAMILY)
398 rtm.rtm_family = tmpl->r_family;
399
400 if (tmpl->ce_mask & RULE_ATTR_TABLE)
401 rtm.rtm_table = tmpl->r_table;
402
403 if (tmpl->ce_mask & RULE_ATTR_DSFIELD)
404 rtm.rtm_tos = tmpl->r_dsfield;
405
406 if (tmpl->ce_mask & RULE_ATTR_TYPE)
407 rtm.rtm_type = tmpl->r_type;
408
409 if (tmpl->ce_mask & RULE_ATTR_SRC_LEN)
410 rtm.rtm_src_len = tmpl->r_src_len;
411
412 if (tmpl->ce_mask & RULE_ATTR_DST_LEN)
413 rtm.rtm_dst_len = tmpl->r_dst_len;
414
415 msg = nlmsg_alloc_simple(cmd, flags);
416 if (!msg)
417 return -NLE_NOMEM;
418
419 if (nlmsg_append(msg, &rtm, sizeof(rtm), NLMSG_ALIGNTO) < 0)
420 goto nla_put_failure;
421
422 if (tmpl->ce_mask & RULE_ATTR_SRC)
423 NLA_PUT_ADDR(msg, RTA_SRC, tmpl->r_src);
424
425 if (tmpl->ce_mask & RULE_ATTR_DST)
426 NLA_PUT_ADDR(msg, RTA_DST, tmpl->r_dst);
427
428 if (tmpl->ce_mask & RULE_ATTR_PRIO)
429 NLA_PUT_U32(msg, RTA_PRIORITY, tmpl->r_prio);
430
431 if (tmpl->ce_mask & RULE_ATTR_MARK)
432 NLA_PUT_U32(msg, RTA_PROTOINFO, tmpl->r_mark);
433
434 if (tmpl->ce_mask & RULE_ATTR_REALMS)
435 NLA_PUT_U32(msg, RTA_FLOW, tmpl->r_realms);
436
437 if (tmpl->ce_mask & RULE_ATTR_IIF)
438 NLA_PUT_STRING(msg, RTA_IIF, tmpl->r_iif);
439
440 *result = msg;
441 return 0;
442
443 nla_put_failure:
444 nlmsg_free(msg);
445 return -NLE_MSGSIZE;
446 }
447
448 /**
449 * Build netlink request message to add a new rule
450 * @arg tmpl template with data of new rule
451 * @arg flags additional netlink message flags
452 *
453 * Builds a new netlink message requesting a addition of a new
454 * rule. The netlink message header isn't fully equipped with
455 * all relevant fields and must thus be sent out via nl_send_auto_complete()
456 * or supplemented as needed. \a tmpl must contain the attributes of the new
457 * address set via \c rtnl_rule_set_* functions.
458 *
459 * @return The netlink message
460 */
rtnl_rule_build_add_request(struct rtnl_rule * tmpl,int flags,struct nl_msg ** result)461 int rtnl_rule_build_add_request(struct rtnl_rule *tmpl, int flags,
462 struct nl_msg **result)
463 {
464 return build_rule_msg(tmpl, RTM_NEWRULE, NLM_F_CREATE | flags,
465 result);
466 }
467
468 /**
469 * Add a new rule
470 * @arg sk Netlink socket.
471 * @arg tmpl template with requested changes
472 * @arg flags additional netlink message flags
473 *
474 * Builds a netlink message by calling rtnl_rule_build_add_request(),
475 * sends the request to the kernel and waits for the next ACK to be
476 * received and thus blocks until the request has been fullfilled.
477 *
478 * @return 0 on sucess or a negative error if an error occured.
479 */
rtnl_rule_add(struct nl_sock * sk,struct rtnl_rule * tmpl,int flags)480 int rtnl_rule_add(struct nl_sock *sk, struct rtnl_rule *tmpl, int flags)
481 {
482 struct nl_msg *msg;
483 int err;
484
485 if ((err = rtnl_rule_build_add_request(tmpl, flags, &msg)) < 0)
486 return err;
487
488 err = nl_send_auto_complete(sk, msg);
489 nlmsg_free(msg);
490 if (err < 0)
491 return err;
492
493 return wait_for_ack(sk);
494 }
495
496 /** @} */
497
498 /**
499 * @name Rule Deletion
500 * @{
501 */
502
503 /**
504 * Build a netlink request message to delete a rule
505 * @arg rule rule to delete
506 * @arg flags additional netlink message flags
507 *
508 * Builds a new netlink message requesting a deletion of a rule.
509 * The netlink message header isn't fully equipped with all relevant
510 * fields and must thus be sent out via nl_send_auto_complete()
511 * or supplemented as needed. \a rule must point to an existing
512 * address.
513 *
514 * @return The netlink message
515 */
rtnl_rule_build_delete_request(struct rtnl_rule * rule,int flags,struct nl_msg ** result)516 int rtnl_rule_build_delete_request(struct rtnl_rule *rule, int flags,
517 struct nl_msg **result)
518 {
519 return build_rule_msg(rule, RTM_DELRULE, flags, result);
520 }
521
522 /**
523 * Delete a rule
524 * @arg sk Netlink socket.
525 * @arg rule rule to delete
526 * @arg flags additional netlink message flags
527 *
528 * Builds a netlink message by calling rtnl_rule_build_delete_request(),
529 * sends the request to the kernel and waits for the next ACK to be
530 * received and thus blocks until the request has been fullfilled.
531 *
532 * @return 0 on sucess or a negative error if an error occured.
533 */
rtnl_rule_delete(struct nl_sock * sk,struct rtnl_rule * rule,int flags)534 int rtnl_rule_delete(struct nl_sock *sk, struct rtnl_rule *rule, int flags)
535 {
536 struct nl_msg *msg;
537 int err;
538
539 if ((err = rtnl_rule_build_delete_request(rule, flags, &msg)) < 0)
540 return err;
541
542 err = nl_send_auto_complete(sk, msg);
543 nlmsg_free(msg);
544 if (err < 0)
545 return err;
546
547 return wait_for_ack(sk);
548 }
549
550 /** @} */
551
552 /**
553 * @name Attribute Modification
554 * @{
555 */
556
rtnl_rule_set_family(struct rtnl_rule * rule,int family)557 void rtnl_rule_set_family(struct rtnl_rule *rule, int family)
558 {
559 rule->r_family = family;
560 rule->ce_mask |= RULE_ATTR_FAMILY;
561 }
562
rtnl_rule_get_family(struct rtnl_rule * rule)563 int rtnl_rule_get_family(struct rtnl_rule *rule)
564 {
565 if (rule->ce_mask & RULE_ATTR_FAMILY)
566 return rule->r_family;
567 else
568 return AF_UNSPEC;
569 }
570
rtnl_rule_set_prio(struct rtnl_rule * rule,int prio)571 void rtnl_rule_set_prio(struct rtnl_rule *rule, int prio)
572 {
573 rule->r_prio = prio;
574 rule->ce_mask |= RULE_ATTR_PRIO;
575 }
576
rtnl_rule_get_prio(struct rtnl_rule * rule)577 int rtnl_rule_get_prio(struct rtnl_rule *rule)
578 {
579 if (rule->ce_mask & RULE_ATTR_PRIO)
580 return rule->r_prio;
581 else
582 return -1;
583 }
584
rtnl_rule_set_mark(struct rtnl_rule * rule,uint64_t mark)585 void rtnl_rule_set_mark(struct rtnl_rule *rule, uint64_t mark)
586 {
587 rule->r_mark = mark;
588 rule->ce_mask |= RULE_ATTR_MARK;
589 }
590
rtnl_rule_get_mark(struct rtnl_rule * rule)591 uint64_t rtnl_rule_get_mark(struct rtnl_rule *rule)
592 {
593 if (rule->ce_mask & RULE_ATTR_MARK)
594 return rule->r_mark;
595 else
596 return UINT_LEAST64_MAX;
597 }
598
rtnl_rule_set_table(struct rtnl_rule * rule,int table)599 void rtnl_rule_set_table(struct rtnl_rule *rule, int table)
600 {
601 rule->r_table = table;
602 rule->ce_mask |= RULE_ATTR_TABLE;
603 }
604
rtnl_rule_get_table(struct rtnl_rule * rule)605 int rtnl_rule_get_table(struct rtnl_rule *rule)
606 {
607 if (rule->ce_mask & RULE_ATTR_TABLE)
608 return rule->r_table;
609 else
610 return -1;
611 }
612
rtnl_rule_set_dsfield(struct rtnl_rule * rule,int dsfield)613 void rtnl_rule_set_dsfield(struct rtnl_rule *rule, int dsfield)
614 {
615 rule->r_dsfield = dsfield;
616 rule->ce_mask |= RULE_ATTR_DSFIELD;
617 }
618
rtnl_rule_get_dsfield(struct rtnl_rule * rule)619 int rtnl_rule_get_dsfield(struct rtnl_rule *rule)
620 {
621 if (rule->ce_mask & RULE_ATTR_DSFIELD)
622 return rule->r_dsfield;
623 else
624 return -1;
625 }
626
rtnl_rule_set_src_len(struct rtnl_rule * rule,int len)627 void rtnl_rule_set_src_len(struct rtnl_rule *rule, int len)
628 {
629 rule->r_src_len = len;
630 if (rule->ce_mask & RULE_ATTR_SRC)
631 nl_addr_set_prefixlen(rule->r_src, len);
632 rule->ce_mask |= RULE_ATTR_SRC_LEN;
633 }
634
rtnl_rule_get_src_len(struct rtnl_rule * rule)635 int rtnl_rule_get_src_len(struct rtnl_rule *rule)
636 {
637 if (rule->ce_mask & RULE_ATTR_SRC_LEN)
638 return rule->r_src_len;
639 else
640 return -1;
641 }
642
rtnl_rule_set_dst_len(struct rtnl_rule * rule,int len)643 void rtnl_rule_set_dst_len(struct rtnl_rule *rule, int len)
644 {
645 rule->r_dst_len = len;
646 if (rule->ce_mask & RULE_ATTR_DST)
647 nl_addr_set_prefixlen(rule->r_dst, len);
648 rule->ce_mask |= RULE_ATTR_DST_LEN;
649 }
650
rtnl_rule_get_dst_len(struct rtnl_rule * rule)651 int rtnl_rule_get_dst_len(struct rtnl_rule *rule)
652 {
653 if (rule->ce_mask & RULE_ATTR_DST_LEN)
654 return rule->r_dst_len;
655 else
656 return -1;
657 }
658
__assign_addr(struct rtnl_rule * rule,struct nl_addr ** pos,struct nl_addr * new,uint8_t * len,int flag)659 static inline int __assign_addr(struct rtnl_rule *rule, struct nl_addr **pos,
660 struct nl_addr *new, uint8_t *len, int flag)
661 {
662 if (rule->ce_mask & RULE_ATTR_FAMILY) {
663 if (new->a_family != rule->r_family)
664 return -NLE_AF_MISMATCH;
665 } else
666 rule->r_family = new->a_family;
667
668 if (*pos)
669 nl_addr_put(*pos);
670
671 nl_addr_get(new);
672 *pos = new;
673 *len = nl_addr_get_prefixlen(new);
674
675 rule->ce_mask |= (flag | RULE_ATTR_FAMILY);
676
677 return 0;
678 }
679
rtnl_rule_set_src(struct rtnl_rule * rule,struct nl_addr * src)680 int rtnl_rule_set_src(struct rtnl_rule *rule, struct nl_addr *src)
681 {
682 return __assign_addr(rule, &rule->r_src, src, &rule->r_src_len,
683 RULE_ATTR_SRC | RULE_ATTR_SRC_LEN);
684 }
685
rtnl_rule_get_src(struct rtnl_rule * rule)686 struct nl_addr *rtnl_rule_get_src(struct rtnl_rule *rule)
687 {
688 if (rule->ce_mask & RULE_ATTR_SRC)
689 return rule->r_src;
690 else
691 return NULL;
692 }
693
rtnl_rule_set_dst(struct rtnl_rule * rule,struct nl_addr * dst)694 int rtnl_rule_set_dst(struct rtnl_rule *rule, struct nl_addr *dst)
695 {
696 return __assign_addr(rule, &rule->r_dst, dst, &rule->r_dst_len,
697 RULE_ATTR_DST | RULE_ATTR_DST_LEN);
698 }
699
rtnl_rule_get_dst(struct rtnl_rule * rule)700 struct nl_addr *rtnl_rule_get_dst(struct rtnl_rule *rule)
701 {
702 if (rule->ce_mask & RULE_ATTR_DST)
703 return rule->r_dst;
704 else
705 return NULL;
706 }
707
rtnl_rule_set_iif(struct rtnl_rule * rule,const char * dev)708 int rtnl_rule_set_iif(struct rtnl_rule *rule, const char *dev)
709 {
710 if (strlen(dev) > IFNAMSIZ-1)
711 return -NLE_RANGE;
712
713 strcpy(rule->r_iif, dev);
714 rule->ce_mask |= RULE_ATTR_IIF;
715 return 0;
716 }
717
rtnl_rule_get_iif(struct rtnl_rule * rule)718 char *rtnl_rule_get_iif(struct rtnl_rule *rule)
719 {
720 if (rule->ce_mask & RULE_ATTR_IIF)
721 return rule->r_iif;
722 else
723 return NULL;
724 }
725
rtnl_rule_set_action(struct rtnl_rule * rule,int type)726 void rtnl_rule_set_action(struct rtnl_rule *rule, int type)
727 {
728 rule->r_type = type;
729 rule->ce_mask |= RULE_ATTR_TYPE;
730 }
731
rtnl_rule_get_action(struct rtnl_rule * rule)732 int rtnl_rule_get_action(struct rtnl_rule *rule)
733 {
734 if (rule->ce_mask & RULE_ATTR_TYPE)
735 return rule->r_type;
736 else
737 return -NLE_NOATTR;
738 }
739
rtnl_rule_set_realms(struct rtnl_rule * rule,uint32_t realms)740 void rtnl_rule_set_realms(struct rtnl_rule *rule, uint32_t realms)
741 {
742 rule->r_realms = realms;
743 rule->ce_mask |= RULE_ATTR_REALMS;
744 }
745
rtnl_rule_get_realms(struct rtnl_rule * rule)746 uint32_t rtnl_rule_get_realms(struct rtnl_rule *rule)
747 {
748 if (rule->ce_mask & RULE_ATTR_REALMS)
749 return rule->r_realms;
750 else
751 return 0;
752 }
753
754 /** @} */
755
756 static struct nl_object_ops rule_obj_ops = {
757 .oo_name = "route/rule",
758 .oo_size = sizeof(struct rtnl_rule),
759 .oo_free_data = rule_free_data,
760 .oo_clone = rule_clone,
761 .oo_dump = {
762 [NL_DUMP_LINE] = rule_dump_line,
763 [NL_DUMP_DETAILS] = rule_dump_details,
764 [NL_DUMP_STATS] = rule_dump_stats,
765 [NL_DUMP_ENV] = rule_dump_env,
766 },
767 .oo_compare = rule_compare,
768 .oo_attrs2str = rule_attrs2str,
769 .oo_id_attrs = ~0,
770 };
771
772 static struct nl_cache_ops rtnl_rule_ops = {
773 .co_name = "route/rule",
774 .co_hdrsize = sizeof(struct rtmsg),
775 .co_msgtypes = {
776 { RTM_NEWRULE, NL_ACT_NEW, "new" },
777 { RTM_DELRULE, NL_ACT_DEL, "del" },
778 { RTM_GETRULE, NL_ACT_GET, "get" },
779 END_OF_MSGTYPES_LIST,
780 },
781 .co_protocol = NETLINK_ROUTE,
782 .co_request_update = rule_request_update,
783 .co_msg_parser = rule_msg_parser,
784 .co_obj_ops = &rule_obj_ops,
785 };
786
rule_init(void)787 static void __init rule_init(void)
788 {
789 nl_cache_mngt_register(&rtnl_rule_ops);
790 }
791
rule_exit(void)792 static void __exit rule_exit(void)
793 {
794 nl_cache_mngt_unregister(&rtnl_rule_ops);
795 }
796
797 /** @} */
798