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