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