Home | History | Annotate | Download | only in route
      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 (at) 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 
     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 
     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 
     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 
    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 
    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 
    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 
    225 static void rule_dump_stats(struct nl_object *obj, struct nl_dump_params *p)
    226 {
    227 	rule_dump_details(obj, p);
    228 }
    229 
    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 
    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 
    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 
    331 struct rtnl_rule *rtnl_rule_alloc(void)
    332 {
    333 	return (struct rtnl_rule *) nl_object_alloc(&rule_obj_ops);
    334 }
    335 
    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  */
    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 
    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  */
    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  */
    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  */
    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  */
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    787 static void __init rule_init(void)
    788 {
    789 	nl_cache_mngt_register(&rtnl_rule_ops);
    790 }
    791 
    792 static void __exit rule_exit(void)
    793 {
    794 	nl_cache_mngt_unregister(&rtnl_rule_ops);
    795 }
    796 
    797 /** @} */
    798