route_obj.c revision 464988628802b76d5b3e50af99158413ac28bd18
144d362409d5469aed47d19e7908d19bd194493aThomas Graf/*
244d362409d5469aed47d19e7908d19bd194493aThomas Graf * lib/route/route_obj.c	Route Object
344d362409d5469aed47d19e7908d19bd194493aThomas Graf *
444d362409d5469aed47d19e7908d19bd194493aThomas Graf *	This library is free software; you can redistribute it and/or
544d362409d5469aed47d19e7908d19bd194493aThomas Graf *	modify it under the terms of the GNU Lesser General Public
644d362409d5469aed47d19e7908d19bd194493aThomas Graf *	License as published by the Free Software Foundation version 2.1
744d362409d5469aed47d19e7908d19bd194493aThomas Graf *	of the License.
844d362409d5469aed47d19e7908d19bd194493aThomas Graf *
944d362409d5469aed47d19e7908d19bd194493aThomas Graf * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch>
1044d362409d5469aed47d19e7908d19bd194493aThomas Graf */
1144d362409d5469aed47d19e7908d19bd194493aThomas Graf
1244d362409d5469aed47d19e7908d19bd194493aThomas Graf/**
1344d362409d5469aed47d19e7908d19bd194493aThomas Graf * @ingroup route
1444d362409d5469aed47d19e7908d19bd194493aThomas Graf * @defgroup route_obj Route Object
1544d362409d5469aed47d19e7908d19bd194493aThomas Graf *
1644d362409d5469aed47d19e7908d19bd194493aThomas Graf * @par Attributes
1744d362409d5469aed47d19e7908d19bd194493aThomas Graf * @code
1844d362409d5469aed47d19e7908d19bd194493aThomas Graf * Name                                           Default
1944d362409d5469aed47d19e7908d19bd194493aThomas Graf * -------------------------------------------------------------
2044d362409d5469aed47d19e7908d19bd194493aThomas Graf * routing table                                  RT_TABLE_MAIN
2144d362409d5469aed47d19e7908d19bd194493aThomas Graf * scope                                          RT_SCOPE_NOWHERE
2244d362409d5469aed47d19e7908d19bd194493aThomas Graf * tos                                            0
2344d362409d5469aed47d19e7908d19bd194493aThomas Graf * realms                                         0
2444d362409d5469aed47d19e7908d19bd194493aThomas Graf * protocol                                       RTPROT_STATIC
2544d362409d5469aed47d19e7908d19bd194493aThomas Graf * prio                                           0
2644d362409d5469aed47d19e7908d19bd194493aThomas Graf * family                                         AF_UNSPEC
2744d362409d5469aed47d19e7908d19bd194493aThomas Graf * type                                           RTN_UNICAST
2844d362409d5469aed47d19e7908d19bd194493aThomas Graf * oif                                            RTNL_LINK_NOT_FOUND
2944d362409d5469aed47d19e7908d19bd194493aThomas Graf * iif                                            NULL
3044d362409d5469aed47d19e7908d19bd194493aThomas Graf * mpalgo                                         IP_MP_ALG_NONE
3144d362409d5469aed47d19e7908d19bd194493aThomas Graf * @endcode
3244d362409d5469aed47d19e7908d19bd194493aThomas Graf *
3344d362409d5469aed47d19e7908d19bd194493aThomas Graf * @{
3444d362409d5469aed47d19e7908d19bd194493aThomas Graf */
3544d362409d5469aed47d19e7908d19bd194493aThomas Graf
3644d362409d5469aed47d19e7908d19bd194493aThomas Graf#include <netlink-local.h>
3744d362409d5469aed47d19e7908d19bd194493aThomas Graf#include <netlink/netlink.h>
3844d362409d5469aed47d19e7908d19bd194493aThomas Graf#include <netlink/cache.h>
3944d362409d5469aed47d19e7908d19bd194493aThomas Graf#include <netlink/utils.h>
4044d362409d5469aed47d19e7908d19bd194493aThomas Graf#include <netlink/data.h>
4144d362409d5469aed47d19e7908d19bd194493aThomas Graf#include <netlink/route/rtnl.h>
4244d362409d5469aed47d19e7908d19bd194493aThomas Graf#include <netlink/route/route.h>
4344d362409d5469aed47d19e7908d19bd194493aThomas Graf#include <netlink/route/link.h>
4444d362409d5469aed47d19e7908d19bd194493aThomas Graf
4544d362409d5469aed47d19e7908d19bd194493aThomas Graf/** @cond SKIP */
4644d362409d5469aed47d19e7908d19bd194493aThomas Graf#define ROUTE_ATTR_FAMILY    0x000001
4744d362409d5469aed47d19e7908d19bd194493aThomas Graf#define ROUTE_ATTR_TOS       0x000002
4844d362409d5469aed47d19e7908d19bd194493aThomas Graf#define ROUTE_ATTR_TABLE     0x000004
4944d362409d5469aed47d19e7908d19bd194493aThomas Graf#define ROUTE_ATTR_PROTOCOL  0x000008
5044d362409d5469aed47d19e7908d19bd194493aThomas Graf#define ROUTE_ATTR_SCOPE     0x000010
5144d362409d5469aed47d19e7908d19bd194493aThomas Graf#define ROUTE_ATTR_TYPE      0x000020
5244d362409d5469aed47d19e7908d19bd194493aThomas Graf#define ROUTE_ATTR_FLAGS     0x000040
5344d362409d5469aed47d19e7908d19bd194493aThomas Graf#define ROUTE_ATTR_DST       0x000080
5444d362409d5469aed47d19e7908d19bd194493aThomas Graf#define ROUTE_ATTR_SRC       0x000100
5544d362409d5469aed47d19e7908d19bd194493aThomas Graf#define ROUTE_ATTR_IIF       0x000200
5644d362409d5469aed47d19e7908d19bd194493aThomas Graf#define ROUTE_ATTR_OIF       0x000400
5744d362409d5469aed47d19e7908d19bd194493aThomas Graf#define ROUTE_ATTR_GATEWAY   0x000800
5844d362409d5469aed47d19e7908d19bd194493aThomas Graf#define ROUTE_ATTR_PRIO      0x001000
5944d362409d5469aed47d19e7908d19bd194493aThomas Graf#define ROUTE_ATTR_PREF_SRC  0x002000
6044d362409d5469aed47d19e7908d19bd194493aThomas Graf#define ROUTE_ATTR_METRICS   0x004000
6144d362409d5469aed47d19e7908d19bd194493aThomas Graf#define ROUTE_ATTR_MULTIPATH 0x008000
6244d362409d5469aed47d19e7908d19bd194493aThomas Graf#define ROUTE_ATTR_REALMS    0x010000
6344d362409d5469aed47d19e7908d19bd194493aThomas Graf#define ROUTE_ATTR_CACHEINFO 0x020000
6444d362409d5469aed47d19e7908d19bd194493aThomas Graf#define ROUTE_ATTR_MP_ALGO   0x040000
6544d362409d5469aed47d19e7908d19bd194493aThomas Graf/** @endcond */
6644d362409d5469aed47d19e7908d19bd194493aThomas Graf
6744d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic int route_dump_brief(struct nl_object *a, struct nl_dump_params *p);
6844d362409d5469aed47d19e7908d19bd194493aThomas Graf
6944d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic void route_constructor(struct nl_object *c)
7044d362409d5469aed47d19e7908d19bd194493aThomas Graf{
7144d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct rtnl_route *r = (struct rtnl_route *) c;
7244d362409d5469aed47d19e7908d19bd194493aThomas Graf
7344d362409d5469aed47d19e7908d19bd194493aThomas Graf	nl_init_list_head(&r->rt_nexthops);
7444d362409d5469aed47d19e7908d19bd194493aThomas Graf}
7544d362409d5469aed47d19e7908d19bd194493aThomas Graf
7644d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic void route_free_data(struct nl_object *c)
7744d362409d5469aed47d19e7908d19bd194493aThomas Graf{
7844d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct rtnl_route *r = (struct rtnl_route *) c;
7944d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct rtnl_nexthop *nh, *tmp;
8044d362409d5469aed47d19e7908d19bd194493aThomas Graf
8144d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (r == NULL)
8244d362409d5469aed47d19e7908d19bd194493aThomas Graf		return;
8344d362409d5469aed47d19e7908d19bd194493aThomas Graf
8444d362409d5469aed47d19e7908d19bd194493aThomas Graf	nl_addr_put(r->rt_dst);
8544d362409d5469aed47d19e7908d19bd194493aThomas Graf	nl_addr_put(r->rt_src);
8644d362409d5469aed47d19e7908d19bd194493aThomas Graf	nl_addr_put(r->rt_gateway);
8744d362409d5469aed47d19e7908d19bd194493aThomas Graf	nl_addr_put(r->rt_pref_src);
8844d362409d5469aed47d19e7908d19bd194493aThomas Graf
8944d362409d5469aed47d19e7908d19bd194493aThomas Graf	nl_list_for_each_entry_safe(nh, tmp, &r->rt_nexthops, rtnh_list) {
9044d362409d5469aed47d19e7908d19bd194493aThomas Graf		rtnl_route_remove_nexthop(nh);
9144d362409d5469aed47d19e7908d19bd194493aThomas Graf		rtnl_route_nh_free(nh);
9244d362409d5469aed47d19e7908d19bd194493aThomas Graf	}
9344d362409d5469aed47d19e7908d19bd194493aThomas Graf}
9444d362409d5469aed47d19e7908d19bd194493aThomas Graf
9544d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic int route_clone(struct nl_object *_dst, struct nl_object *_src)
9644d362409d5469aed47d19e7908d19bd194493aThomas Graf{
9744d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct rtnl_route *dst = (struct rtnl_route *) _dst;
9844d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct rtnl_route *src = (struct rtnl_route *) _src;
9944d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct rtnl_nexthop *nh, *new;
10044d362409d5469aed47d19e7908d19bd194493aThomas Graf
10144d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (src->rt_dst)
10244d362409d5469aed47d19e7908d19bd194493aThomas Graf		if (!(dst->rt_dst = nl_addr_clone(src->rt_dst)))
10344d362409d5469aed47d19e7908d19bd194493aThomas Graf			goto errout;
10444d362409d5469aed47d19e7908d19bd194493aThomas Graf
10544d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (src->rt_src)
10644d362409d5469aed47d19e7908d19bd194493aThomas Graf		if (!(dst->rt_src = nl_addr_clone(src->rt_src)))
10744d362409d5469aed47d19e7908d19bd194493aThomas Graf			goto errout;
10844d362409d5469aed47d19e7908d19bd194493aThomas Graf
10944d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (src->rt_gateway)
11044d362409d5469aed47d19e7908d19bd194493aThomas Graf		if (!(dst->rt_gateway = nl_addr_clone(src->rt_gateway)))
11144d362409d5469aed47d19e7908d19bd194493aThomas Graf			goto errout;
11244d362409d5469aed47d19e7908d19bd194493aThomas Graf
11344d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (src->rt_pref_src)
11444d362409d5469aed47d19e7908d19bd194493aThomas Graf		if (!(dst->rt_pref_src = nl_addr_clone(src->rt_pref_src)))
11544d362409d5469aed47d19e7908d19bd194493aThomas Graf			goto errout;
11644d362409d5469aed47d19e7908d19bd194493aThomas Graf
11744d362409d5469aed47d19e7908d19bd194493aThomas Graf	nl_init_list_head(&dst->rt_nexthops);
11844d362409d5469aed47d19e7908d19bd194493aThomas Graf	nl_list_for_each_entry(nh, &src->rt_nexthops, rtnh_list) {
11944d362409d5469aed47d19e7908d19bd194493aThomas Graf		new = rtnl_route_nh_clone(nh);
12044d362409d5469aed47d19e7908d19bd194493aThomas Graf		if (!new)
12144d362409d5469aed47d19e7908d19bd194493aThomas Graf			goto errout;
12244d362409d5469aed47d19e7908d19bd194493aThomas Graf
12344d362409d5469aed47d19e7908d19bd194493aThomas Graf		rtnl_route_add_nexthop(dst, new);
12444d362409d5469aed47d19e7908d19bd194493aThomas Graf	}
12544d362409d5469aed47d19e7908d19bd194493aThomas Graf
12644d362409d5469aed47d19e7908d19bd194493aThomas Graf	return 0;
12744d362409d5469aed47d19e7908d19bd194493aThomas Graferrout:
12844d362409d5469aed47d19e7908d19bd194493aThomas Graf	return nl_get_errno();
12944d362409d5469aed47d19e7908d19bd194493aThomas Graf}
13044d362409d5469aed47d19e7908d19bd194493aThomas Graf
13144d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic int route_dump_brief(struct nl_object *a, struct nl_dump_params *p)
13244d362409d5469aed47d19e7908d19bd194493aThomas Graf{
13344d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct rtnl_route *r = (struct rtnl_route *) a;
13444d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct nl_cache *link_cache;
13544d362409d5469aed47d19e7908d19bd194493aThomas Graf	char buf[64];
13644d362409d5469aed47d19e7908d19bd194493aThomas Graf
13744d362409d5469aed47d19e7908d19bd194493aThomas Graf	link_cache = nl_cache_mngt_require("route/link");
13844d362409d5469aed47d19e7908d19bd194493aThomas Graf
139464988628802b76d5b3e50af99158413ac28bd18Thomas Graf	if (!(r->ce_mask & ROUTE_ATTR_DST) ||
140464988628802b76d5b3e50af99158413ac28bd18Thomas Graf	    nl_addr_get_len(r->rt_dst) == 0)
14144d362409d5469aed47d19e7908d19bd194493aThomas Graf		dp_dump(p, "default ");
142464988628802b76d5b3e50af99158413ac28bd18Thomas Graf	else
143464988628802b76d5b3e50af99158413ac28bd18Thomas Graf		dp_dump(p, "%s ", nl_addr2str(r->rt_dst, buf, sizeof(buf)));
14444d362409d5469aed47d19e7908d19bd194493aThomas Graf
14544d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (r->ce_mask & ROUTE_ATTR_OIF) {
14644d362409d5469aed47d19e7908d19bd194493aThomas Graf		if (link_cache)
14744d362409d5469aed47d19e7908d19bd194493aThomas Graf			dp_dump(p, "dev %s ",
14844d362409d5469aed47d19e7908d19bd194493aThomas Graf				rtnl_link_i2name(link_cache, r->rt_oif,
14944d362409d5469aed47d19e7908d19bd194493aThomas Graf						 buf, sizeof(buf)));
15044d362409d5469aed47d19e7908d19bd194493aThomas Graf		else
15144d362409d5469aed47d19e7908d19bd194493aThomas Graf			dp_dump(p, "dev %d ", r->rt_oif);
15244d362409d5469aed47d19e7908d19bd194493aThomas Graf	}
15344d362409d5469aed47d19e7908d19bd194493aThomas Graf
15444d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (r->ce_mask & ROUTE_ATTR_GATEWAY)
15544d362409d5469aed47d19e7908d19bd194493aThomas Graf		dp_dump(p, "via %s ", nl_addr2str(r->rt_gateway, buf,
15644d362409d5469aed47d19e7908d19bd194493aThomas Graf						  sizeof(buf)));
15744d362409d5469aed47d19e7908d19bd194493aThomas Graf	else if (r->ce_mask & ROUTE_ATTR_MULTIPATH)
15844d362409d5469aed47d19e7908d19bd194493aThomas Graf		dp_dump(p, "via nexthops ");
15944d362409d5469aed47d19e7908d19bd194493aThomas Graf
16044d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (r->ce_mask & ROUTE_ATTR_SCOPE)
16144d362409d5469aed47d19e7908d19bd194493aThomas Graf		dp_dump(p, "scope %s ",
16244d362409d5469aed47d19e7908d19bd194493aThomas Graf			rtnl_scope2str(r->rt_scope, buf, sizeof(buf)));
16344d362409d5469aed47d19e7908d19bd194493aThomas Graf
16444d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (r->ce_mask & ROUTE_ATTR_FLAGS && r->rt_flags) {
16544d362409d5469aed47d19e7908d19bd194493aThomas Graf		int flags = r->rt_flags;
16644d362409d5469aed47d19e7908d19bd194493aThomas Graf
16744d362409d5469aed47d19e7908d19bd194493aThomas Graf		dp_dump(p, "<");
16844d362409d5469aed47d19e7908d19bd194493aThomas Graf
16944d362409d5469aed47d19e7908d19bd194493aThomas Graf#define PRINT_FLAG(f) if (flags & RTNH_F_##f) { \
17044d362409d5469aed47d19e7908d19bd194493aThomas Graf		flags &= ~RTNH_F_##f; dp_dump(p, #f "%s", flags ? "," : ""); }
17144d362409d5469aed47d19e7908d19bd194493aThomas Graf		PRINT_FLAG(DEAD);
17244d362409d5469aed47d19e7908d19bd194493aThomas Graf		PRINT_FLAG(ONLINK);
17344d362409d5469aed47d19e7908d19bd194493aThomas Graf		PRINT_FLAG(PERVASIVE);
17444d362409d5469aed47d19e7908d19bd194493aThomas Graf#undef PRINT_FLAG
17544d362409d5469aed47d19e7908d19bd194493aThomas Graf
17644d362409d5469aed47d19e7908d19bd194493aThomas Graf#define PRINT_FLAG(f) if (flags & RTM_F_##f) { \
17744d362409d5469aed47d19e7908d19bd194493aThomas Graf		flags &= ~RTM_F_##f; dp_dump(p, #f "%s", flags ? "," : ""); }
17844d362409d5469aed47d19e7908d19bd194493aThomas Graf		PRINT_FLAG(NOTIFY);
17944d362409d5469aed47d19e7908d19bd194493aThomas Graf		PRINT_FLAG(CLONED);
18044d362409d5469aed47d19e7908d19bd194493aThomas Graf		PRINT_FLAG(EQUALIZE);
18144d362409d5469aed47d19e7908d19bd194493aThomas Graf		PRINT_FLAG(PREFIX);
18244d362409d5469aed47d19e7908d19bd194493aThomas Graf#undef PRINT_FLAG
18344d362409d5469aed47d19e7908d19bd194493aThomas Graf
18444d362409d5469aed47d19e7908d19bd194493aThomas Graf		dp_dump(p, ">");
18544d362409d5469aed47d19e7908d19bd194493aThomas Graf	}
18644d362409d5469aed47d19e7908d19bd194493aThomas Graf
18744d362409d5469aed47d19e7908d19bd194493aThomas Graf	dp_dump(p, "\n");
18844d362409d5469aed47d19e7908d19bd194493aThomas Graf
18944d362409d5469aed47d19e7908d19bd194493aThomas Graf	return 1;
19044d362409d5469aed47d19e7908d19bd194493aThomas Graf}
19144d362409d5469aed47d19e7908d19bd194493aThomas Graf
19244d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic int route_dump_full(struct nl_object *a, struct nl_dump_params *p)
19344d362409d5469aed47d19e7908d19bd194493aThomas Graf{
19444d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct rtnl_route *r = (struct rtnl_route *) a;
19544d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct nl_cache *link_cache;
19644d362409d5469aed47d19e7908d19bd194493aThomas Graf	char buf[128];
19744d362409d5469aed47d19e7908d19bd194493aThomas Graf	int i, line;
19844d362409d5469aed47d19e7908d19bd194493aThomas Graf
19944d362409d5469aed47d19e7908d19bd194493aThomas Graf	link_cache = nl_cache_mngt_require("route/link");
20044d362409d5469aed47d19e7908d19bd194493aThomas Graf	line = route_dump_brief(a, p);
20144d362409d5469aed47d19e7908d19bd194493aThomas Graf
20244d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (r->ce_mask & ROUTE_ATTR_MULTIPATH) {
20344d362409d5469aed47d19e7908d19bd194493aThomas Graf		struct rtnl_nexthop *nh;
20444d362409d5469aed47d19e7908d19bd194493aThomas Graf
20544d362409d5469aed47d19e7908d19bd194493aThomas Graf		nl_list_for_each_entry(nh, &r->rt_nexthops, rtnh_list) {
20644d362409d5469aed47d19e7908d19bd194493aThomas Graf			dp_dump_line(p, line++, "  via ");
20744d362409d5469aed47d19e7908d19bd194493aThomas Graf
20844d362409d5469aed47d19e7908d19bd194493aThomas Graf			if (nh->rtnh_mask & NEXTHOP_HAS_GATEWAY)
20944d362409d5469aed47d19e7908d19bd194493aThomas Graf				dp_dump(p, "%s ",
21044d362409d5469aed47d19e7908d19bd194493aThomas Graf					nl_addr2str(nh->rtnh_gateway,
21144d362409d5469aed47d19e7908d19bd194493aThomas Graf						    buf, sizeof(buf)));
21244d362409d5469aed47d19e7908d19bd194493aThomas Graf			if (link_cache) {
21344d362409d5469aed47d19e7908d19bd194493aThomas Graf				dp_dump(p, "dev %s ",
21444d362409d5469aed47d19e7908d19bd194493aThomas Graf					rtnl_link_i2name(link_cache,
21544d362409d5469aed47d19e7908d19bd194493aThomas Graf							 nh->rtnh_ifindex,
21644d362409d5469aed47d19e7908d19bd194493aThomas Graf							 buf, sizeof(buf)));
21744d362409d5469aed47d19e7908d19bd194493aThomas Graf			} else
21844d362409d5469aed47d19e7908d19bd194493aThomas Graf				dp_dump(p, "dev %d ", nh->rtnh_ifindex);
21944d362409d5469aed47d19e7908d19bd194493aThomas Graf
22044d362409d5469aed47d19e7908d19bd194493aThomas Graf			dp_dump(p, "weight %u <%s>\n", nh->rtnh_weight,
22144d362409d5469aed47d19e7908d19bd194493aThomas Graf				rtnl_route_nh_flags2str(nh->rtnh_flags,
22244d362409d5469aed47d19e7908d19bd194493aThomas Graf							buf, sizeof(buf)));
22344d362409d5469aed47d19e7908d19bd194493aThomas Graf		}
22444d362409d5469aed47d19e7908d19bd194493aThomas Graf	}
22544d362409d5469aed47d19e7908d19bd194493aThomas Graf
22644d362409d5469aed47d19e7908d19bd194493aThomas Graf	dp_dump_line(p, line++, "  ");
22744d362409d5469aed47d19e7908d19bd194493aThomas Graf
22844d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (r->ce_mask & ROUTE_ATTR_PREF_SRC)
22944d362409d5469aed47d19e7908d19bd194493aThomas Graf		dp_dump(p, "preferred-src %s ",
23044d362409d5469aed47d19e7908d19bd194493aThomas Graf			nl_addr2str(r->rt_pref_src, buf, sizeof(buf)));
23144d362409d5469aed47d19e7908d19bd194493aThomas Graf
23244d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (r->ce_mask & ROUTE_ATTR_TABLE)
23344d362409d5469aed47d19e7908d19bd194493aThomas Graf		dp_dump(p, "table %s ",
23444d362409d5469aed47d19e7908d19bd194493aThomas Graf			rtnl_route_table2str(r->rt_table, buf, sizeof(buf)));
23544d362409d5469aed47d19e7908d19bd194493aThomas Graf
23644d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (r->ce_mask & ROUTE_ATTR_TYPE)
23744d362409d5469aed47d19e7908d19bd194493aThomas Graf		dp_dump(p, "type %s ",
23844d362409d5469aed47d19e7908d19bd194493aThomas Graf			nl_rtntype2str(r->rt_type, buf, sizeof(buf)));
23944d362409d5469aed47d19e7908d19bd194493aThomas Graf
24044d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (r->ce_mask & ROUTE_ATTR_PRIO)
24144d362409d5469aed47d19e7908d19bd194493aThomas Graf		dp_dump(p, "metric %#x ", r->rt_prio);
24244d362409d5469aed47d19e7908d19bd194493aThomas Graf
24344d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (r->ce_mask & ROUTE_ATTR_FAMILY)
24444d362409d5469aed47d19e7908d19bd194493aThomas Graf		dp_dump(p, "family %s ",
24544d362409d5469aed47d19e7908d19bd194493aThomas Graf			nl_af2str(r->rt_family, buf, sizeof(buf)));
24644d362409d5469aed47d19e7908d19bd194493aThomas Graf
24744d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (r->ce_mask & ROUTE_ATTR_PROTOCOL)
24844d362409d5469aed47d19e7908d19bd194493aThomas Graf		dp_dump(p, "protocol %s ",
24944d362409d5469aed47d19e7908d19bd194493aThomas Graf			rtnl_route_proto2str(r->rt_protocol, buf, sizeof(buf)));
25044d362409d5469aed47d19e7908d19bd194493aThomas Graf
25144d362409d5469aed47d19e7908d19bd194493aThomas Graf	dp_dump(p, "\n");
25244d362409d5469aed47d19e7908d19bd194493aThomas Graf
25344d362409d5469aed47d19e7908d19bd194493aThomas Graf	if ((r->ce_mask & (ROUTE_ATTR_IIF | ROUTE_ATTR_SRC | ROUTE_ATTR_TOS |
25444d362409d5469aed47d19e7908d19bd194493aThomas Graf			   ROUTE_ATTR_REALMS)) ||
25544d362409d5469aed47d19e7908d19bd194493aThomas Graf	    ((r->ce_mask & ROUTE_ATTR_CACHEINFO) &&
25644d362409d5469aed47d19e7908d19bd194493aThomas Graf	     r->rt_cacheinfo.rtci_error)) {
25744d362409d5469aed47d19e7908d19bd194493aThomas Graf		dp_dump_line(p, line++, "  ");
25844d362409d5469aed47d19e7908d19bd194493aThomas Graf
25944d362409d5469aed47d19e7908d19bd194493aThomas Graf		if (r->ce_mask & ROUTE_ATTR_IIF)
26044d362409d5469aed47d19e7908d19bd194493aThomas Graf			dp_dump(p, "iif %s ", r->rt_iif);
26144d362409d5469aed47d19e7908d19bd194493aThomas Graf
26244d362409d5469aed47d19e7908d19bd194493aThomas Graf		if (r->ce_mask & ROUTE_ATTR_SRC)
26344d362409d5469aed47d19e7908d19bd194493aThomas Graf			dp_dump(p, "src %s ",
26444d362409d5469aed47d19e7908d19bd194493aThomas Graf				nl_addr2str(r->rt_src, buf, sizeof(buf)));
26544d362409d5469aed47d19e7908d19bd194493aThomas Graf
26644d362409d5469aed47d19e7908d19bd194493aThomas Graf		if (r->ce_mask & ROUTE_ATTR_TOS)
26744d362409d5469aed47d19e7908d19bd194493aThomas Graf			dp_dump(p, "tos %#x ", r->rt_tos);
26844d362409d5469aed47d19e7908d19bd194493aThomas Graf
26944d362409d5469aed47d19e7908d19bd194493aThomas Graf		if (r->ce_mask & ROUTE_ATTR_REALMS)
27044d362409d5469aed47d19e7908d19bd194493aThomas Graf			dp_dump(p, "realm %04x:%04x ",
27144d362409d5469aed47d19e7908d19bd194493aThomas Graf				RTNL_REALM_FROM(r->rt_realms),
27244d362409d5469aed47d19e7908d19bd194493aThomas Graf				RTNL_REALM_TO(r->rt_realms));
27344d362409d5469aed47d19e7908d19bd194493aThomas Graf
27444d362409d5469aed47d19e7908d19bd194493aThomas Graf		if ((r->ce_mask & ROUTE_ATTR_CACHEINFO) &&
27544d362409d5469aed47d19e7908d19bd194493aThomas Graf		    r->rt_cacheinfo.rtci_error)
27644d362409d5469aed47d19e7908d19bd194493aThomas Graf			dp_dump(p, "error %d (%s) ", r->rt_cacheinfo.rtci_error,
27744d362409d5469aed47d19e7908d19bd194493aThomas Graf				strerror(-r->rt_cacheinfo.rtci_error));
27844d362409d5469aed47d19e7908d19bd194493aThomas Graf
27944d362409d5469aed47d19e7908d19bd194493aThomas Graf		dp_dump(p, "\n");
28044d362409d5469aed47d19e7908d19bd194493aThomas Graf	}
28144d362409d5469aed47d19e7908d19bd194493aThomas Graf
28244d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (r->ce_mask & ROUTE_ATTR_METRICS) {
28344d362409d5469aed47d19e7908d19bd194493aThomas Graf		dp_dump_line(p, line++, "  ");
28444d362409d5469aed47d19e7908d19bd194493aThomas Graf		for (i = 0; i < RTAX_MAX; i++)
28544d362409d5469aed47d19e7908d19bd194493aThomas Graf			if (r->rt_metrics_mask & (1 << i))
28644d362409d5469aed47d19e7908d19bd194493aThomas Graf				dp_dump(p, "%s %u ",
28744d362409d5469aed47d19e7908d19bd194493aThomas Graf					rtnl_route_metric2str(i+1,
28844d362409d5469aed47d19e7908d19bd194493aThomas Graf							      buf, sizeof(buf)),
28944d362409d5469aed47d19e7908d19bd194493aThomas Graf					r->rt_metrics[i]);
29044d362409d5469aed47d19e7908d19bd194493aThomas Graf		dp_dump(p, "\n");
29144d362409d5469aed47d19e7908d19bd194493aThomas Graf	}
29244d362409d5469aed47d19e7908d19bd194493aThomas Graf
29344d362409d5469aed47d19e7908d19bd194493aThomas Graf	return line;
29444d362409d5469aed47d19e7908d19bd194493aThomas Graf}
29544d362409d5469aed47d19e7908d19bd194493aThomas Graf
29644d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic int route_dump_stats(struct nl_object *obj, struct nl_dump_params *p)
29744d362409d5469aed47d19e7908d19bd194493aThomas Graf{
29844d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct rtnl_route *route = (struct rtnl_route *) obj;
29944d362409d5469aed47d19e7908d19bd194493aThomas Graf	int line;
30044d362409d5469aed47d19e7908d19bd194493aThomas Graf
30144d362409d5469aed47d19e7908d19bd194493aThomas Graf	line = route_dump_full(obj, p);
30244d362409d5469aed47d19e7908d19bd194493aThomas Graf
30344d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (route->ce_mask & ROUTE_ATTR_CACHEINFO) {
30444d362409d5469aed47d19e7908d19bd194493aThomas Graf		struct rtnl_rtcacheinfo *ci = &route->rt_cacheinfo;
30544d362409d5469aed47d19e7908d19bd194493aThomas Graf		dp_dump_line(p, line++, "  used %u refcnt %u ",
30644d362409d5469aed47d19e7908d19bd194493aThomas Graf			     ci->rtci_used, ci->rtci_clntref);
30744d362409d5469aed47d19e7908d19bd194493aThomas Graf		dp_dump_line(p, line++, "last-use %us expires %us\n",
30844d362409d5469aed47d19e7908d19bd194493aThomas Graf			     ci->rtci_last_use / nl_get_hz(),
30944d362409d5469aed47d19e7908d19bd194493aThomas Graf			     ci->rtci_expires / nl_get_hz());
31044d362409d5469aed47d19e7908d19bd194493aThomas Graf	}
31144d362409d5469aed47d19e7908d19bd194493aThomas Graf
31244d362409d5469aed47d19e7908d19bd194493aThomas Graf	return line;
31344d362409d5469aed47d19e7908d19bd194493aThomas Graf}
31444d362409d5469aed47d19e7908d19bd194493aThomas Graf
31544d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic int route_dump_xml(struct nl_object *obj, struct nl_dump_params *p)
31644d362409d5469aed47d19e7908d19bd194493aThomas Graf{
31744d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct rtnl_route *route = (struct rtnl_route *) obj;
31844d362409d5469aed47d19e7908d19bd194493aThomas Graf	char buf[128];
31944d362409d5469aed47d19e7908d19bd194493aThomas Graf	int line = 0;
32044d362409d5469aed47d19e7908d19bd194493aThomas Graf
32144d362409d5469aed47d19e7908d19bd194493aThomas Graf	dp_dump_line(p, line++, "<route>\n");
32244d362409d5469aed47d19e7908d19bd194493aThomas Graf	dp_dump_line(p, line++, "  <family>%s</family>\n",
32344d362409d5469aed47d19e7908d19bd194493aThomas Graf		     nl_af2str(route->rt_family, buf, sizeof(buf)));
32444d362409d5469aed47d19e7908d19bd194493aThomas Graf
32544d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (route->ce_mask & ROUTE_ATTR_DST)
32644d362409d5469aed47d19e7908d19bd194493aThomas Graf		dp_dump_line(p, line++, "  <dst>%s</dst>\n",
32744d362409d5469aed47d19e7908d19bd194493aThomas Graf			     nl_addr2str(route->rt_dst, buf, sizeof(buf)));
32844d362409d5469aed47d19e7908d19bd194493aThomas Graf
32944d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (route->ce_mask & ROUTE_ATTR_SRC)
33044d362409d5469aed47d19e7908d19bd194493aThomas Graf		dp_dump_line(p, line++, "  <src>%s</src>\n",
33144d362409d5469aed47d19e7908d19bd194493aThomas Graf			     nl_addr2str(route->rt_src, buf, sizeof(buf)));
33244d362409d5469aed47d19e7908d19bd194493aThomas Graf
33344d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (route->ce_mask & ROUTE_ATTR_GATEWAY)
33444d362409d5469aed47d19e7908d19bd194493aThomas Graf		dp_dump_line(p, line++, "  <gateway>%s</gateway>\n",
33544d362409d5469aed47d19e7908d19bd194493aThomas Graf			     nl_addr2str(route->rt_gateway, buf, sizeof(buf)));
33644d362409d5469aed47d19e7908d19bd194493aThomas Graf
33744d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (route->ce_mask & ROUTE_ATTR_PREF_SRC)
33844d362409d5469aed47d19e7908d19bd194493aThomas Graf		dp_dump_line(p, line++, "  <prefsrc>%s</prefsrc>\n",
33944d362409d5469aed47d19e7908d19bd194493aThomas Graf			     nl_addr2str(route->rt_pref_src, buf, sizeof(buf)));
34044d362409d5469aed47d19e7908d19bd194493aThomas Graf
34144d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (route->ce_mask & ROUTE_ATTR_IIF)
34244d362409d5469aed47d19e7908d19bd194493aThomas Graf		dp_dump_line(p, line++, "  <iif>%s</iif>\n", route->rt_iif);
34344d362409d5469aed47d19e7908d19bd194493aThomas Graf
34444d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (route->ce_mask & ROUTE_ATTR_REALMS)
34544d362409d5469aed47d19e7908d19bd194493aThomas Graf		dp_dump_line(p, line++, "  <realms>%u</realms>\n",
34644d362409d5469aed47d19e7908d19bd194493aThomas Graf			     route->rt_realms);
34744d362409d5469aed47d19e7908d19bd194493aThomas Graf
34844d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (route->ce_mask & ROUTE_ATTR_TOS)
34944d362409d5469aed47d19e7908d19bd194493aThomas Graf		dp_dump_line(p, line++, "  <tos>%u</tos>\n", route->rt_tos);
35044d362409d5469aed47d19e7908d19bd194493aThomas Graf
35144d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (route->ce_mask & ROUTE_ATTR_TABLE)
35244d362409d5469aed47d19e7908d19bd194493aThomas Graf		dp_dump_line(p, line++, "  <table>%u</table>\n",
35344d362409d5469aed47d19e7908d19bd194493aThomas Graf			     route->rt_table);
35444d362409d5469aed47d19e7908d19bd194493aThomas Graf
35544d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (route->ce_mask & ROUTE_ATTR_SCOPE)
35644d362409d5469aed47d19e7908d19bd194493aThomas Graf		dp_dump_line(p, line++, "  <scope>%s</scope>\n",
35744d362409d5469aed47d19e7908d19bd194493aThomas Graf			     rtnl_scope2str(route->rt_scope, buf, sizeof(buf)));
35844d362409d5469aed47d19e7908d19bd194493aThomas Graf
35944d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (route->ce_mask & ROUTE_ATTR_PRIO)
36044d362409d5469aed47d19e7908d19bd194493aThomas Graf		dp_dump_line(p, line++, "  <metric>%u</metric>\n",
36144d362409d5469aed47d19e7908d19bd194493aThomas Graf			     route->rt_prio);
36244d362409d5469aed47d19e7908d19bd194493aThomas Graf
36344d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (route->ce_mask & ROUTE_ATTR_OIF) {
36444d362409d5469aed47d19e7908d19bd194493aThomas Graf		struct nl_cache *link_cache;
36544d362409d5469aed47d19e7908d19bd194493aThomas Graf
36644d362409d5469aed47d19e7908d19bd194493aThomas Graf		link_cache = nl_cache_mngt_require("route/link");
36744d362409d5469aed47d19e7908d19bd194493aThomas Graf		if (link_cache)
36844d362409d5469aed47d19e7908d19bd194493aThomas Graf			dp_dump_line(p, line++, "  <oif>%s</oif>\n",
36944d362409d5469aed47d19e7908d19bd194493aThomas Graf				     rtnl_link_i2name(link_cache,
37044d362409d5469aed47d19e7908d19bd194493aThomas Graf						      route->rt_oif,
37144d362409d5469aed47d19e7908d19bd194493aThomas Graf						      buf, sizeof(buf)));
37244d362409d5469aed47d19e7908d19bd194493aThomas Graf		else
37344d362409d5469aed47d19e7908d19bd194493aThomas Graf			dp_dump_line(p, line++, "  <oif>%u</oif>\n",
37444d362409d5469aed47d19e7908d19bd194493aThomas Graf				     route->rt_oif);
37544d362409d5469aed47d19e7908d19bd194493aThomas Graf	}
37644d362409d5469aed47d19e7908d19bd194493aThomas Graf
37744d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (route->ce_mask & ROUTE_ATTR_TYPE)
37844d362409d5469aed47d19e7908d19bd194493aThomas Graf		dp_dump_line(p, line++, "  <type>%s</type>\n",
37944d362409d5469aed47d19e7908d19bd194493aThomas Graf			     nl_rtntype2str(route->rt_type, buf, sizeof(buf)));
38044d362409d5469aed47d19e7908d19bd194493aThomas Graf
38144d362409d5469aed47d19e7908d19bd194493aThomas Graf	dp_dump_line(p, line++, "</route>\n");
38244d362409d5469aed47d19e7908d19bd194493aThomas Graf
38344d362409d5469aed47d19e7908d19bd194493aThomas Graf#if 0
38444d362409d5469aed47d19e7908d19bd194493aThomas Graf	uint8_t			rt_protocol;
38544d362409d5469aed47d19e7908d19bd194493aThomas Graf	uint32_t		rt_flags;
38644d362409d5469aed47d19e7908d19bd194493aThomas Graf	uint32_t		rt_metrics[RTAX_MAX];
38744d362409d5469aed47d19e7908d19bd194493aThomas Graf	uint32_t		rt_metrics_mask;
38844d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct rtnl_nexthop *	rt_nexthops;
38944d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct rtnl_rtcacheinfo	rt_cacheinfo;
39044d362409d5469aed47d19e7908d19bd194493aThomas Graf	uint32_t		rt_mp_algo;
39144d362409d5469aed47d19e7908d19bd194493aThomas Graf
39244d362409d5469aed47d19e7908d19bd194493aThomas Graf#endif
39344d362409d5469aed47d19e7908d19bd194493aThomas Graf
39444d362409d5469aed47d19e7908d19bd194493aThomas Graf	return line;
39544d362409d5469aed47d19e7908d19bd194493aThomas Graf}
39644d362409d5469aed47d19e7908d19bd194493aThomas Graf
39744d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic int route_dump_env(struct nl_object *obj, struct nl_dump_params *p)
39844d362409d5469aed47d19e7908d19bd194493aThomas Graf{
39944d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct rtnl_route *route = (struct rtnl_route *) obj;
40044d362409d5469aed47d19e7908d19bd194493aThomas Graf	char buf[128];
40144d362409d5469aed47d19e7908d19bd194493aThomas Graf	int line = 0;
40244d362409d5469aed47d19e7908d19bd194493aThomas Graf
40344d362409d5469aed47d19e7908d19bd194493aThomas Graf	dp_dump_line(p, line++, "ROUTE_FAMILY=%s\n",
40444d362409d5469aed47d19e7908d19bd194493aThomas Graf		     nl_af2str(route->rt_family, buf, sizeof(buf)));
40544d362409d5469aed47d19e7908d19bd194493aThomas Graf
40644d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (route->ce_mask & ROUTE_ATTR_DST)
40744d362409d5469aed47d19e7908d19bd194493aThomas Graf		dp_dump_line(p, line++, "ROUTE_DST=%s\n",
40844d362409d5469aed47d19e7908d19bd194493aThomas Graf			     nl_addr2str(route->rt_dst, buf, sizeof(buf)));
40944d362409d5469aed47d19e7908d19bd194493aThomas Graf
41044d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (route->ce_mask & ROUTE_ATTR_SRC)
41144d362409d5469aed47d19e7908d19bd194493aThomas Graf		dp_dump_line(p, line++, "ROUTE_SRC=%s\n",
41244d362409d5469aed47d19e7908d19bd194493aThomas Graf			     nl_addr2str(route->rt_src, buf, sizeof(buf)));
41344d362409d5469aed47d19e7908d19bd194493aThomas Graf
41444d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (route->ce_mask & ROUTE_ATTR_GATEWAY)
41544d362409d5469aed47d19e7908d19bd194493aThomas Graf		dp_dump_line(p, line++, "ROUTE_GATEWAY=%s\n",
41644d362409d5469aed47d19e7908d19bd194493aThomas Graf			     nl_addr2str(route->rt_gateway, buf, sizeof(buf)));
41744d362409d5469aed47d19e7908d19bd194493aThomas Graf
41844d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (route->ce_mask & ROUTE_ATTR_PREF_SRC)
41944d362409d5469aed47d19e7908d19bd194493aThomas Graf		dp_dump_line(p, line++, "ROUTE_PREFSRC=%s\n",
42044d362409d5469aed47d19e7908d19bd194493aThomas Graf			     nl_addr2str(route->rt_pref_src, buf, sizeof(buf)));
42144d362409d5469aed47d19e7908d19bd194493aThomas Graf
42244d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (route->ce_mask & ROUTE_ATTR_IIF)
42344d362409d5469aed47d19e7908d19bd194493aThomas Graf		dp_dump_line(p, line++, "ROUTE_IIF=%s\n", route->rt_iif);
42444d362409d5469aed47d19e7908d19bd194493aThomas Graf
42544d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (route->ce_mask & ROUTE_ATTR_REALMS)
42644d362409d5469aed47d19e7908d19bd194493aThomas Graf		dp_dump_line(p, line++, "ROUTE_REALM=%u\n",
42744d362409d5469aed47d19e7908d19bd194493aThomas Graf			     route->rt_realms);
42844d362409d5469aed47d19e7908d19bd194493aThomas Graf
42944d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (route->ce_mask & ROUTE_ATTR_TOS)
43044d362409d5469aed47d19e7908d19bd194493aThomas Graf		dp_dump_line(p, line++, "ROUTE_TOS=%u\n", route->rt_tos);
43144d362409d5469aed47d19e7908d19bd194493aThomas Graf
43244d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (route->ce_mask & ROUTE_ATTR_TABLE)
43344d362409d5469aed47d19e7908d19bd194493aThomas Graf		dp_dump_line(p, line++, "ROUTE_TABLE=%u\n",
43444d362409d5469aed47d19e7908d19bd194493aThomas Graf			     route->rt_table);
43544d362409d5469aed47d19e7908d19bd194493aThomas Graf
43644d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (route->ce_mask & ROUTE_ATTR_SCOPE)
43744d362409d5469aed47d19e7908d19bd194493aThomas Graf		dp_dump_line(p, line++, "ROUTE_SCOPE=%s\n",
43844d362409d5469aed47d19e7908d19bd194493aThomas Graf			     rtnl_scope2str(route->rt_scope, buf, sizeof(buf)));
43944d362409d5469aed47d19e7908d19bd194493aThomas Graf
44044d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (route->ce_mask & ROUTE_ATTR_PRIO)
44144d362409d5469aed47d19e7908d19bd194493aThomas Graf		dp_dump_line(p, line++, "ROUTE_METRIC=%u\n",
44244d362409d5469aed47d19e7908d19bd194493aThomas Graf			     route->rt_prio);
44344d362409d5469aed47d19e7908d19bd194493aThomas Graf
44444d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (route->ce_mask & ROUTE_ATTR_OIF) {
44544d362409d5469aed47d19e7908d19bd194493aThomas Graf		struct nl_cache *link_cache;
44644d362409d5469aed47d19e7908d19bd194493aThomas Graf
44744d362409d5469aed47d19e7908d19bd194493aThomas Graf		dp_dump_line(p, line++, "ROUTE_OIF_IFINDEX=%u\n",
44844d362409d5469aed47d19e7908d19bd194493aThomas Graf			     route->rt_oif);
44944d362409d5469aed47d19e7908d19bd194493aThomas Graf
45044d362409d5469aed47d19e7908d19bd194493aThomas Graf		link_cache = nl_cache_mngt_require("route/link");
45144d362409d5469aed47d19e7908d19bd194493aThomas Graf		if (link_cache)
45244d362409d5469aed47d19e7908d19bd194493aThomas Graf			dp_dump_line(p, line++, "ROUTE_OIF_IFNAME=%s\n",
45344d362409d5469aed47d19e7908d19bd194493aThomas Graf				     rtnl_link_i2name(link_cache,
45444d362409d5469aed47d19e7908d19bd194493aThomas Graf						      route->rt_oif,
45544d362409d5469aed47d19e7908d19bd194493aThomas Graf						      buf, sizeof(buf)));
45644d362409d5469aed47d19e7908d19bd194493aThomas Graf	}
45744d362409d5469aed47d19e7908d19bd194493aThomas Graf
45844d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (route->ce_mask & ROUTE_ATTR_TYPE)
45944d362409d5469aed47d19e7908d19bd194493aThomas Graf		dp_dump_line(p, line++, "ROUTE_TYPE=%s\n",
46044d362409d5469aed47d19e7908d19bd194493aThomas Graf			     nl_rtntype2str(route->rt_type, buf, sizeof(buf)));
46144d362409d5469aed47d19e7908d19bd194493aThomas Graf
46244d362409d5469aed47d19e7908d19bd194493aThomas Graf	return line;
46344d362409d5469aed47d19e7908d19bd194493aThomas Graf}
46444d362409d5469aed47d19e7908d19bd194493aThomas Graf
46544d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic int route_compare(struct nl_object *_a, struct nl_object *_b,
46644d362409d5469aed47d19e7908d19bd194493aThomas Graf			uint32_t attrs, int flags)
46744d362409d5469aed47d19e7908d19bd194493aThomas Graf{
46844d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct rtnl_route *a = (struct rtnl_route *) _a;
46944d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct rtnl_route *b = (struct rtnl_route *) _b;
47044d362409d5469aed47d19e7908d19bd194493aThomas Graf	int diff = 0;
47144d362409d5469aed47d19e7908d19bd194493aThomas Graf
47244d362409d5469aed47d19e7908d19bd194493aThomas Graf#define ROUTE_DIFF(ATTR, EXPR) ATTR_DIFF(attrs, ROUTE_ATTR_##ATTR, a, b, EXPR)
47344d362409d5469aed47d19e7908d19bd194493aThomas Graf
47444d362409d5469aed47d19e7908d19bd194493aThomas Graf	diff |= ROUTE_DIFF(FAMILY,	a->rt_family != b->rt_family);
47544d362409d5469aed47d19e7908d19bd194493aThomas Graf	diff |= ROUTE_DIFF(TOS,		a->rt_tos != b->rt_tos);
47644d362409d5469aed47d19e7908d19bd194493aThomas Graf	diff |= ROUTE_DIFF(TABLE,	a->rt_table != b->rt_table);
47744d362409d5469aed47d19e7908d19bd194493aThomas Graf	diff |= ROUTE_DIFF(PROTOCOL,	a->rt_protocol != b->rt_protocol);
47844d362409d5469aed47d19e7908d19bd194493aThomas Graf	diff |= ROUTE_DIFF(SCOPE,	a->rt_scope != b->rt_scope);
47944d362409d5469aed47d19e7908d19bd194493aThomas Graf	diff |= ROUTE_DIFF(TYPE,	a->rt_type != b->rt_type);
48044d362409d5469aed47d19e7908d19bd194493aThomas Graf	diff |= ROUTE_DIFF(OIF,		a->rt_oif != b->rt_oif);
48144d362409d5469aed47d19e7908d19bd194493aThomas Graf	diff |= ROUTE_DIFF(PRIO,	a->rt_prio != b->rt_prio);
48244d362409d5469aed47d19e7908d19bd194493aThomas Graf	diff |= ROUTE_DIFF(REALMS,	a->rt_realms != b->rt_realms);
48344d362409d5469aed47d19e7908d19bd194493aThomas Graf	diff |= ROUTE_DIFF(MP_ALGO,	a->rt_mp_algo != b->rt_mp_algo);
48444d362409d5469aed47d19e7908d19bd194493aThomas Graf	diff |= ROUTE_DIFF(DST,		nl_addr_cmp(a->rt_dst, b->rt_dst));
48544d362409d5469aed47d19e7908d19bd194493aThomas Graf	diff |= ROUTE_DIFF(SRC,		nl_addr_cmp(a->rt_src, b->rt_src));
48644d362409d5469aed47d19e7908d19bd194493aThomas Graf	diff |= ROUTE_DIFF(IIF,		strcmp(a->rt_iif, b->rt_iif));
48744d362409d5469aed47d19e7908d19bd194493aThomas Graf	diff |= ROUTE_DIFF(PREF_SRC,	nl_addr_cmp(a->rt_pref_src,
48844d362409d5469aed47d19e7908d19bd194493aThomas Graf						    b->rt_pref_src));
48944d362409d5469aed47d19e7908d19bd194493aThomas Graf	diff |= ROUTE_DIFF(GATEWAY,	nl_addr_cmp(a->rt_gateway,
49044d362409d5469aed47d19e7908d19bd194493aThomas Graf						    b->rt_gateway));
49144d362409d5469aed47d19e7908d19bd194493aThomas Graf
49244d362409d5469aed47d19e7908d19bd194493aThomas Graf	/* FIXME: Compare metrics, multipath config */
49344d362409d5469aed47d19e7908d19bd194493aThomas Graf
49444d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (flags & LOOSE_FLAG_COMPARISON)
49544d362409d5469aed47d19e7908d19bd194493aThomas Graf		diff |= ROUTE_DIFF(FLAGS,
49644d362409d5469aed47d19e7908d19bd194493aThomas Graf			  (a->rt_flags ^ b->rt_flags) & b->rt_flag_mask);
49744d362409d5469aed47d19e7908d19bd194493aThomas Graf	else
49844d362409d5469aed47d19e7908d19bd194493aThomas Graf		diff |= ROUTE_DIFF(FLAGS, a->rt_flags != b->rt_flags);
49944d362409d5469aed47d19e7908d19bd194493aThomas Graf
50044d362409d5469aed47d19e7908d19bd194493aThomas Graf#undef ROUTE_DIFF
50144d362409d5469aed47d19e7908d19bd194493aThomas Graf
50244d362409d5469aed47d19e7908d19bd194493aThomas Graf	return diff;
50344d362409d5469aed47d19e7908d19bd194493aThomas Graf}
50444d362409d5469aed47d19e7908d19bd194493aThomas Graf
50544d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic struct trans_tbl route_attrs[] = {
50644d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(ROUTE_ATTR_FAMILY, family)
50744d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(ROUTE_ATTR_TOS, tos)
50844d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(ROUTE_ATTR_TABLE, table)
50944d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(ROUTE_ATTR_PROTOCOL, protocol)
51044d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(ROUTE_ATTR_SCOPE, scope)
51144d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(ROUTE_ATTR_TYPE, type)
51244d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(ROUTE_ATTR_FLAGS, flags)
51344d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(ROUTE_ATTR_DST, dst)
51444d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(ROUTE_ATTR_SRC, src)
51544d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(ROUTE_ATTR_IIF, iif)
51644d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(ROUTE_ATTR_OIF, oif)
51744d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(ROUTE_ATTR_GATEWAY, gateway)
51844d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(ROUTE_ATTR_PRIO, prio)
51944d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(ROUTE_ATTR_PREF_SRC, pref_src)
52044d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(ROUTE_ATTR_METRICS, metrics)
52144d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(ROUTE_ATTR_MULTIPATH, multipath)
52244d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(ROUTE_ATTR_REALMS, realms)
52344d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(ROUTE_ATTR_CACHEINFO, cacheinfo)
52444d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(ROUTE_ATTR_MP_ALGO, mp_algo)
52544d362409d5469aed47d19e7908d19bd194493aThomas Graf};
52644d362409d5469aed47d19e7908d19bd194493aThomas Graf
52744d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic char *route_attrs2str(int attrs, char *buf, size_t len)
52844d362409d5469aed47d19e7908d19bd194493aThomas Graf{
52944d362409d5469aed47d19e7908d19bd194493aThomas Graf	return __flags2str(attrs, buf, len, route_attrs,
53044d362409d5469aed47d19e7908d19bd194493aThomas Graf			   ARRAY_SIZE(route_attrs));
53144d362409d5469aed47d19e7908d19bd194493aThomas Graf}
53244d362409d5469aed47d19e7908d19bd194493aThomas Graf
53344d362409d5469aed47d19e7908d19bd194493aThomas Graf/**
53444d362409d5469aed47d19e7908d19bd194493aThomas Graf * @name Allocation/Freeing
53544d362409d5469aed47d19e7908d19bd194493aThomas Graf * @{
53644d362409d5469aed47d19e7908d19bd194493aThomas Graf */
53744d362409d5469aed47d19e7908d19bd194493aThomas Graf
53844d362409d5469aed47d19e7908d19bd194493aThomas Grafstruct rtnl_route *rtnl_route_alloc(void)
53944d362409d5469aed47d19e7908d19bd194493aThomas Graf{
54044d362409d5469aed47d19e7908d19bd194493aThomas Graf	return (struct rtnl_route *) nl_object_alloc(&route_obj_ops);
54144d362409d5469aed47d19e7908d19bd194493aThomas Graf}
54244d362409d5469aed47d19e7908d19bd194493aThomas Graf
54344d362409d5469aed47d19e7908d19bd194493aThomas Grafvoid rtnl_route_get(struct rtnl_route *route)
54444d362409d5469aed47d19e7908d19bd194493aThomas Graf{
54544d362409d5469aed47d19e7908d19bd194493aThomas Graf	nl_object_get((struct nl_object *) route);
54644d362409d5469aed47d19e7908d19bd194493aThomas Graf}
54744d362409d5469aed47d19e7908d19bd194493aThomas Graf
54844d362409d5469aed47d19e7908d19bd194493aThomas Grafvoid rtnl_route_put(struct rtnl_route *route)
54944d362409d5469aed47d19e7908d19bd194493aThomas Graf{
55044d362409d5469aed47d19e7908d19bd194493aThomas Graf	nl_object_put((struct nl_object *) route);
55144d362409d5469aed47d19e7908d19bd194493aThomas Graf}
55244d362409d5469aed47d19e7908d19bd194493aThomas Graf
55344d362409d5469aed47d19e7908d19bd194493aThomas Graf/** @} */
55444d362409d5469aed47d19e7908d19bd194493aThomas Graf
55544d362409d5469aed47d19e7908d19bd194493aThomas Graf/**
55644d362409d5469aed47d19e7908d19bd194493aThomas Graf * @name Attributes
55744d362409d5469aed47d19e7908d19bd194493aThomas Graf * @{
55844d362409d5469aed47d19e7908d19bd194493aThomas Graf */
55944d362409d5469aed47d19e7908d19bd194493aThomas Graf
56044d362409d5469aed47d19e7908d19bd194493aThomas Grafvoid rtnl_route_set_table(struct rtnl_route *route, int table)
56144d362409d5469aed47d19e7908d19bd194493aThomas Graf{
56244d362409d5469aed47d19e7908d19bd194493aThomas Graf	route->rt_table = table;
56344d362409d5469aed47d19e7908d19bd194493aThomas Graf	route->ce_mask |= ROUTE_ATTR_TABLE;
56444d362409d5469aed47d19e7908d19bd194493aThomas Graf}
56544d362409d5469aed47d19e7908d19bd194493aThomas Graf
56644d362409d5469aed47d19e7908d19bd194493aThomas Grafint rtnl_route_get_table(struct rtnl_route *route)
56744d362409d5469aed47d19e7908d19bd194493aThomas Graf{
56844d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (route->ce_mask & ROUTE_ATTR_TABLE)
56944d362409d5469aed47d19e7908d19bd194493aThomas Graf		return route->rt_table;
57044d362409d5469aed47d19e7908d19bd194493aThomas Graf	else
57144d362409d5469aed47d19e7908d19bd194493aThomas Graf		return RT_TABLE_MAIN;
57244d362409d5469aed47d19e7908d19bd194493aThomas Graf}
57344d362409d5469aed47d19e7908d19bd194493aThomas Graf
57444d362409d5469aed47d19e7908d19bd194493aThomas Grafvoid rtnl_route_set_scope(struct rtnl_route *route, int scope)
57544d362409d5469aed47d19e7908d19bd194493aThomas Graf{
57644d362409d5469aed47d19e7908d19bd194493aThomas Graf	route->rt_scope = scope;
57744d362409d5469aed47d19e7908d19bd194493aThomas Graf	route->ce_mask |= ROUTE_ATTR_SCOPE;
57844d362409d5469aed47d19e7908d19bd194493aThomas Graf}
57944d362409d5469aed47d19e7908d19bd194493aThomas Graf
58044d362409d5469aed47d19e7908d19bd194493aThomas Grafint rtnl_route_get_scope(struct rtnl_route *route)
58144d362409d5469aed47d19e7908d19bd194493aThomas Graf{
58244d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (route->ce_mask & ROUTE_ATTR_SCOPE)
58344d362409d5469aed47d19e7908d19bd194493aThomas Graf		return route->rt_scope;
58444d362409d5469aed47d19e7908d19bd194493aThomas Graf	else
58544d362409d5469aed47d19e7908d19bd194493aThomas Graf		return RT_SCOPE_NOWHERE;
58644d362409d5469aed47d19e7908d19bd194493aThomas Graf}
58744d362409d5469aed47d19e7908d19bd194493aThomas Graf
58844d362409d5469aed47d19e7908d19bd194493aThomas Grafvoid rtnl_route_set_tos(struct rtnl_route *route, int tos)
58944d362409d5469aed47d19e7908d19bd194493aThomas Graf{
59044d362409d5469aed47d19e7908d19bd194493aThomas Graf	route->rt_tos = tos;
59144d362409d5469aed47d19e7908d19bd194493aThomas Graf	route->ce_mask |= ROUTE_ATTR_TOS;
59244d362409d5469aed47d19e7908d19bd194493aThomas Graf}
59344d362409d5469aed47d19e7908d19bd194493aThomas Graf
59444d362409d5469aed47d19e7908d19bd194493aThomas Grafint rtnl_route_get_tos(struct rtnl_route *route)
59544d362409d5469aed47d19e7908d19bd194493aThomas Graf{
59644d362409d5469aed47d19e7908d19bd194493aThomas Graf	return route->rt_tos;
59744d362409d5469aed47d19e7908d19bd194493aThomas Graf}
59844d362409d5469aed47d19e7908d19bd194493aThomas Graf
59944d362409d5469aed47d19e7908d19bd194493aThomas Grafvoid rtnl_route_set_realms(struct rtnl_route *route, realm_t realms)
60044d362409d5469aed47d19e7908d19bd194493aThomas Graf{
60144d362409d5469aed47d19e7908d19bd194493aThomas Graf	route->rt_realms = realms;
60244d362409d5469aed47d19e7908d19bd194493aThomas Graf	route->ce_mask |= ROUTE_ATTR_REALMS;
60344d362409d5469aed47d19e7908d19bd194493aThomas Graf}
60444d362409d5469aed47d19e7908d19bd194493aThomas Graf
60544d362409d5469aed47d19e7908d19bd194493aThomas Grafrealm_t rtnl_route_get_realms(struct rtnl_route *route)
60644d362409d5469aed47d19e7908d19bd194493aThomas Graf{
60744d362409d5469aed47d19e7908d19bd194493aThomas Graf	return route->rt_realms;
60844d362409d5469aed47d19e7908d19bd194493aThomas Graf}
60944d362409d5469aed47d19e7908d19bd194493aThomas Graf
61044d362409d5469aed47d19e7908d19bd194493aThomas Grafvoid rtnl_route_set_protocol(struct rtnl_route *route, int proto)
61144d362409d5469aed47d19e7908d19bd194493aThomas Graf{
61244d362409d5469aed47d19e7908d19bd194493aThomas Graf	route->rt_protocol = proto;
61344d362409d5469aed47d19e7908d19bd194493aThomas Graf	route->ce_mask |= ROUTE_ATTR_PROTOCOL;
61444d362409d5469aed47d19e7908d19bd194493aThomas Graf}
61544d362409d5469aed47d19e7908d19bd194493aThomas Graf
61644d362409d5469aed47d19e7908d19bd194493aThomas Grafint rtnl_route_get_protocol(struct rtnl_route *route)
61744d362409d5469aed47d19e7908d19bd194493aThomas Graf{
61844d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (route->ce_mask & ROUTE_ATTR_PROTOCOL)
61944d362409d5469aed47d19e7908d19bd194493aThomas Graf		return route->rt_protocol;
62044d362409d5469aed47d19e7908d19bd194493aThomas Graf	else
62144d362409d5469aed47d19e7908d19bd194493aThomas Graf		return RTPROT_STATIC;
62244d362409d5469aed47d19e7908d19bd194493aThomas Graf}
62344d362409d5469aed47d19e7908d19bd194493aThomas Graf
62444d362409d5469aed47d19e7908d19bd194493aThomas Grafvoid rtnl_route_set_prio(struct rtnl_route *route, int prio)
62544d362409d5469aed47d19e7908d19bd194493aThomas Graf{
62644d362409d5469aed47d19e7908d19bd194493aThomas Graf	route->rt_prio = prio;
62744d362409d5469aed47d19e7908d19bd194493aThomas Graf	route->ce_mask |= ROUTE_ATTR_PRIO;
62844d362409d5469aed47d19e7908d19bd194493aThomas Graf}
62944d362409d5469aed47d19e7908d19bd194493aThomas Graf
63044d362409d5469aed47d19e7908d19bd194493aThomas Grafint rtnl_route_get_prio(struct rtnl_route *route)
63144d362409d5469aed47d19e7908d19bd194493aThomas Graf{
63244d362409d5469aed47d19e7908d19bd194493aThomas Graf	return route->rt_prio;
63344d362409d5469aed47d19e7908d19bd194493aThomas Graf}
63444d362409d5469aed47d19e7908d19bd194493aThomas Graf
63544d362409d5469aed47d19e7908d19bd194493aThomas Grafvoid rtnl_route_set_family(struct rtnl_route *route, int family)
63644d362409d5469aed47d19e7908d19bd194493aThomas Graf{
63744d362409d5469aed47d19e7908d19bd194493aThomas Graf	route->rt_family = family;
63844d362409d5469aed47d19e7908d19bd194493aThomas Graf	route->ce_mask |= ROUTE_ATTR_FAMILY;
63944d362409d5469aed47d19e7908d19bd194493aThomas Graf}
64044d362409d5469aed47d19e7908d19bd194493aThomas Graf
64144d362409d5469aed47d19e7908d19bd194493aThomas Grafint rtnl_route_get_family(struct rtnl_route *route)
64244d362409d5469aed47d19e7908d19bd194493aThomas Graf{
64344d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (route->ce_mask & ROUTE_ATTR_FAMILY)
64444d362409d5469aed47d19e7908d19bd194493aThomas Graf		return route->rt_family;
64544d362409d5469aed47d19e7908d19bd194493aThomas Graf	else
64644d362409d5469aed47d19e7908d19bd194493aThomas Graf		return AF_UNSPEC;
64744d362409d5469aed47d19e7908d19bd194493aThomas Graf}
64844d362409d5469aed47d19e7908d19bd194493aThomas Graf
64944d362409d5469aed47d19e7908d19bd194493aThomas Grafint rtnl_route_set_dst(struct rtnl_route *route, struct nl_addr *addr)
65044d362409d5469aed47d19e7908d19bd194493aThomas Graf{
65144d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (route->ce_mask & ROUTE_ATTR_FAMILY) {
65244d362409d5469aed47d19e7908d19bd194493aThomas Graf		if (addr->a_family != route->rt_family)
65344d362409d5469aed47d19e7908d19bd194493aThomas Graf			return nl_error(EINVAL, "Address family mismatch");
65444d362409d5469aed47d19e7908d19bd194493aThomas Graf	} else
65544d362409d5469aed47d19e7908d19bd194493aThomas Graf		route->rt_family = addr->a_family;
65644d362409d5469aed47d19e7908d19bd194493aThomas Graf
65744d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (route->rt_dst)
65844d362409d5469aed47d19e7908d19bd194493aThomas Graf		nl_addr_put(route->rt_dst);
65944d362409d5469aed47d19e7908d19bd194493aThomas Graf
66044d362409d5469aed47d19e7908d19bd194493aThomas Graf	nl_addr_get(addr);
66144d362409d5469aed47d19e7908d19bd194493aThomas Graf	route->rt_dst = addr;
66244d362409d5469aed47d19e7908d19bd194493aThomas Graf
66344d362409d5469aed47d19e7908d19bd194493aThomas Graf	route->ce_mask |= (ROUTE_ATTR_DST | ROUTE_ATTR_FAMILY);
66444d362409d5469aed47d19e7908d19bd194493aThomas Graf
66544d362409d5469aed47d19e7908d19bd194493aThomas Graf	return 0;
66644d362409d5469aed47d19e7908d19bd194493aThomas Graf}
66744d362409d5469aed47d19e7908d19bd194493aThomas Graf
66844d362409d5469aed47d19e7908d19bd194493aThomas Grafstruct nl_addr *rtnl_route_get_dst(struct rtnl_route *route)
66944d362409d5469aed47d19e7908d19bd194493aThomas Graf{
67044d362409d5469aed47d19e7908d19bd194493aThomas Graf	return route->rt_dst;
67144d362409d5469aed47d19e7908d19bd194493aThomas Graf}
67244d362409d5469aed47d19e7908d19bd194493aThomas Graf
67344d362409d5469aed47d19e7908d19bd194493aThomas Grafint rtnl_route_get_dst_len(struct rtnl_route *route)
67444d362409d5469aed47d19e7908d19bd194493aThomas Graf{
67544d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (route->ce_mask & ROUTE_ATTR_DST)
67644d362409d5469aed47d19e7908d19bd194493aThomas Graf		return nl_addr_get_prefixlen(route->rt_dst);
67744d362409d5469aed47d19e7908d19bd194493aThomas Graf	else
67844d362409d5469aed47d19e7908d19bd194493aThomas Graf		return 0;
67944d362409d5469aed47d19e7908d19bd194493aThomas Graf}
68044d362409d5469aed47d19e7908d19bd194493aThomas Graf
68144d362409d5469aed47d19e7908d19bd194493aThomas Grafint rtnl_route_set_src(struct rtnl_route *route, struct nl_addr *addr)
68244d362409d5469aed47d19e7908d19bd194493aThomas Graf{
68344d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (route->ce_mask & ROUTE_ATTR_FAMILY) {
68444d362409d5469aed47d19e7908d19bd194493aThomas Graf		if (addr->a_family != route->rt_family)
68544d362409d5469aed47d19e7908d19bd194493aThomas Graf			return nl_error(EINVAL, "Address family mismatch");
68644d362409d5469aed47d19e7908d19bd194493aThomas Graf	} else
68744d362409d5469aed47d19e7908d19bd194493aThomas Graf		route->rt_family = addr->a_family;
68844d362409d5469aed47d19e7908d19bd194493aThomas Graf
68944d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (route->rt_src)
69044d362409d5469aed47d19e7908d19bd194493aThomas Graf		nl_addr_put(route->rt_src);
69144d362409d5469aed47d19e7908d19bd194493aThomas Graf
69244d362409d5469aed47d19e7908d19bd194493aThomas Graf	nl_addr_get(addr);
69344d362409d5469aed47d19e7908d19bd194493aThomas Graf	route->rt_src = addr;
69444d362409d5469aed47d19e7908d19bd194493aThomas Graf	route->ce_mask |= (ROUTE_ATTR_SRC | ROUTE_ATTR_FAMILY);
69544d362409d5469aed47d19e7908d19bd194493aThomas Graf
69644d362409d5469aed47d19e7908d19bd194493aThomas Graf	return 0;
69744d362409d5469aed47d19e7908d19bd194493aThomas Graf}
69844d362409d5469aed47d19e7908d19bd194493aThomas Graf
69944d362409d5469aed47d19e7908d19bd194493aThomas Grafstruct nl_addr *rtnl_route_get_src(struct rtnl_route *route)
70044d362409d5469aed47d19e7908d19bd194493aThomas Graf{
70144d362409d5469aed47d19e7908d19bd194493aThomas Graf	return route->rt_src;
70244d362409d5469aed47d19e7908d19bd194493aThomas Graf}
70344d362409d5469aed47d19e7908d19bd194493aThomas Graf
70444d362409d5469aed47d19e7908d19bd194493aThomas Grafint rtnl_route_get_src_len(struct rtnl_route *route)
70544d362409d5469aed47d19e7908d19bd194493aThomas Graf{
70644d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (route->ce_mask & ROUTE_ATTR_SRC)
70744d362409d5469aed47d19e7908d19bd194493aThomas Graf		return nl_addr_get_prefixlen(route->rt_src);
70844d362409d5469aed47d19e7908d19bd194493aThomas Graf	else
70944d362409d5469aed47d19e7908d19bd194493aThomas Graf		return 0;
71044d362409d5469aed47d19e7908d19bd194493aThomas Graf}
71144d362409d5469aed47d19e7908d19bd194493aThomas Graf
71244d362409d5469aed47d19e7908d19bd194493aThomas Grafint rtnl_route_set_gateway(struct rtnl_route *route, struct nl_addr *addr)
71344d362409d5469aed47d19e7908d19bd194493aThomas Graf{
71444d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (route->ce_mask & ROUTE_ATTR_FAMILY) {
71544d362409d5469aed47d19e7908d19bd194493aThomas Graf		if (addr->a_family != route->rt_family)
71644d362409d5469aed47d19e7908d19bd194493aThomas Graf			return nl_error(EINVAL, "Address family mismatch");
71744d362409d5469aed47d19e7908d19bd194493aThomas Graf	} else
71844d362409d5469aed47d19e7908d19bd194493aThomas Graf		route->rt_family = addr->a_family;
71944d362409d5469aed47d19e7908d19bd194493aThomas Graf
72044d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (route->rt_gateway)
72144d362409d5469aed47d19e7908d19bd194493aThomas Graf		nl_addr_put(route->rt_gateway);
72244d362409d5469aed47d19e7908d19bd194493aThomas Graf
72344d362409d5469aed47d19e7908d19bd194493aThomas Graf	nl_addr_get(addr);
72444d362409d5469aed47d19e7908d19bd194493aThomas Graf	route->rt_gateway = addr;
72544d362409d5469aed47d19e7908d19bd194493aThomas Graf	route->ce_mask |= (ROUTE_ATTR_GATEWAY | ROUTE_ATTR_FAMILY);
72644d362409d5469aed47d19e7908d19bd194493aThomas Graf
72744d362409d5469aed47d19e7908d19bd194493aThomas Graf	return 0;
72844d362409d5469aed47d19e7908d19bd194493aThomas Graf}
72944d362409d5469aed47d19e7908d19bd194493aThomas Graf
73044d362409d5469aed47d19e7908d19bd194493aThomas Grafstruct nl_addr *rtnl_route_get_gateway(struct rtnl_route *route)
73144d362409d5469aed47d19e7908d19bd194493aThomas Graf{
73244d362409d5469aed47d19e7908d19bd194493aThomas Graf	return route->rt_gateway;
73344d362409d5469aed47d19e7908d19bd194493aThomas Graf}
73444d362409d5469aed47d19e7908d19bd194493aThomas Graf
73544d362409d5469aed47d19e7908d19bd194493aThomas Grafvoid rtnl_route_set_type(struct rtnl_route *route, int type)
73644d362409d5469aed47d19e7908d19bd194493aThomas Graf{
73744d362409d5469aed47d19e7908d19bd194493aThomas Graf	route->rt_type = type;
73844d362409d5469aed47d19e7908d19bd194493aThomas Graf	route->ce_mask |= ROUTE_ATTR_TYPE;
73944d362409d5469aed47d19e7908d19bd194493aThomas Graf}
74044d362409d5469aed47d19e7908d19bd194493aThomas Graf
74144d362409d5469aed47d19e7908d19bd194493aThomas Grafint rtnl_route_get_type(struct rtnl_route *route)
74244d362409d5469aed47d19e7908d19bd194493aThomas Graf{
74344d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (route->ce_mask & ROUTE_ATTR_TYPE)
74444d362409d5469aed47d19e7908d19bd194493aThomas Graf		return route->rt_type;
74544d362409d5469aed47d19e7908d19bd194493aThomas Graf	else
74644d362409d5469aed47d19e7908d19bd194493aThomas Graf		return RTN_UNICAST;
74744d362409d5469aed47d19e7908d19bd194493aThomas Graf}
74844d362409d5469aed47d19e7908d19bd194493aThomas Graf
74944d362409d5469aed47d19e7908d19bd194493aThomas Grafvoid rtnl_route_set_flags(struct rtnl_route *route, unsigned int flags)
75044d362409d5469aed47d19e7908d19bd194493aThomas Graf{
75144d362409d5469aed47d19e7908d19bd194493aThomas Graf	route->rt_flag_mask |= flags;
75244d362409d5469aed47d19e7908d19bd194493aThomas Graf	route->rt_flags |= flags;
75344d362409d5469aed47d19e7908d19bd194493aThomas Graf	route->ce_mask |= ROUTE_ATTR_FLAGS;
75444d362409d5469aed47d19e7908d19bd194493aThomas Graf}
75544d362409d5469aed47d19e7908d19bd194493aThomas Graf
75644d362409d5469aed47d19e7908d19bd194493aThomas Grafvoid rtnl_route_unset_flags(struct rtnl_route *route, unsigned int flags)
75744d362409d5469aed47d19e7908d19bd194493aThomas Graf{
75844d362409d5469aed47d19e7908d19bd194493aThomas Graf	route->rt_flag_mask |= flags;
75944d362409d5469aed47d19e7908d19bd194493aThomas Graf	route->rt_flags &= ~flags;
76044d362409d5469aed47d19e7908d19bd194493aThomas Graf	route->ce_mask |= ROUTE_ATTR_FLAGS;
76144d362409d5469aed47d19e7908d19bd194493aThomas Graf}
76244d362409d5469aed47d19e7908d19bd194493aThomas Graf
76344d362409d5469aed47d19e7908d19bd194493aThomas Grafunsigned int rtnl_route_get_flags(struct rtnl_route *route)
76444d362409d5469aed47d19e7908d19bd194493aThomas Graf{
76544d362409d5469aed47d19e7908d19bd194493aThomas Graf	return route->rt_flags;
76644d362409d5469aed47d19e7908d19bd194493aThomas Graf}
76744d362409d5469aed47d19e7908d19bd194493aThomas Graf
76844d362409d5469aed47d19e7908d19bd194493aThomas Grafint rtnl_route_set_metric(struct rtnl_route *route, int metric, uint32_t value)
76944d362409d5469aed47d19e7908d19bd194493aThomas Graf{
77044d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (metric > RTAX_MAX || metric < 1)
77144d362409d5469aed47d19e7908d19bd194493aThomas Graf		return nl_error(EINVAL, "Metric out of range (1..%d)",
77244d362409d5469aed47d19e7908d19bd194493aThomas Graf		    RTAX_MAX);
77344d362409d5469aed47d19e7908d19bd194493aThomas Graf
77444d362409d5469aed47d19e7908d19bd194493aThomas Graf	route->rt_metrics[metric - 1] = value;
77544d362409d5469aed47d19e7908d19bd194493aThomas Graf	route->rt_metrics_mask |= (1 << (metric - 1));
77644d362409d5469aed47d19e7908d19bd194493aThomas Graf
77744d362409d5469aed47d19e7908d19bd194493aThomas Graf	return 0;
77844d362409d5469aed47d19e7908d19bd194493aThomas Graf}
77944d362409d5469aed47d19e7908d19bd194493aThomas Graf
78044d362409d5469aed47d19e7908d19bd194493aThomas Grafint rtnl_route_unset_metric(struct rtnl_route *route, int metric)
78144d362409d5469aed47d19e7908d19bd194493aThomas Graf{
78244d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (metric > RTAX_MAX || metric < 1)
78344d362409d5469aed47d19e7908d19bd194493aThomas Graf		return nl_error(EINVAL, "Metric out of range (1..%d)",
78444d362409d5469aed47d19e7908d19bd194493aThomas Graf		    RTAX_MAX);
78544d362409d5469aed47d19e7908d19bd194493aThomas Graf
78644d362409d5469aed47d19e7908d19bd194493aThomas Graf	route->rt_metrics_mask &= ~(1 << (metric - 1));
78744d362409d5469aed47d19e7908d19bd194493aThomas Graf
78844d362409d5469aed47d19e7908d19bd194493aThomas Graf	return 0;
78944d362409d5469aed47d19e7908d19bd194493aThomas Graf}
79044d362409d5469aed47d19e7908d19bd194493aThomas Graf
79144d362409d5469aed47d19e7908d19bd194493aThomas Grafunsigned int rtnl_route_get_metric(struct rtnl_route *route, int metric)
79244d362409d5469aed47d19e7908d19bd194493aThomas Graf{
79344d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (metric > RTAX_MAX || metric < 1)
79444d362409d5469aed47d19e7908d19bd194493aThomas Graf		return UINT_MAX;
79544d362409d5469aed47d19e7908d19bd194493aThomas Graf
79644d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (!(route->rt_metrics_mask & (1 << (metric - 1))))
79744d362409d5469aed47d19e7908d19bd194493aThomas Graf		return UINT_MAX;
79844d362409d5469aed47d19e7908d19bd194493aThomas Graf
79944d362409d5469aed47d19e7908d19bd194493aThomas Graf	return route->rt_metrics[metric - 1];
80044d362409d5469aed47d19e7908d19bd194493aThomas Graf}
80144d362409d5469aed47d19e7908d19bd194493aThomas Graf
80244d362409d5469aed47d19e7908d19bd194493aThomas Grafint rtnl_route_set_pref_src(struct rtnl_route *route, struct nl_addr *addr)
80344d362409d5469aed47d19e7908d19bd194493aThomas Graf{
80444d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (route->ce_mask & ROUTE_ATTR_FAMILY) {
80544d362409d5469aed47d19e7908d19bd194493aThomas Graf		if (addr->a_family != route->rt_family)
80644d362409d5469aed47d19e7908d19bd194493aThomas Graf			return nl_error(EINVAL, "Address family mismatch");
80744d362409d5469aed47d19e7908d19bd194493aThomas Graf	} else
80844d362409d5469aed47d19e7908d19bd194493aThomas Graf		route->rt_family = addr->a_family;
80944d362409d5469aed47d19e7908d19bd194493aThomas Graf
81044d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (route->rt_pref_src)
81144d362409d5469aed47d19e7908d19bd194493aThomas Graf		nl_addr_put(route->rt_pref_src);
81244d362409d5469aed47d19e7908d19bd194493aThomas Graf
81344d362409d5469aed47d19e7908d19bd194493aThomas Graf	nl_addr_get(addr);
81444d362409d5469aed47d19e7908d19bd194493aThomas Graf	route->rt_pref_src = addr;
81544d362409d5469aed47d19e7908d19bd194493aThomas Graf	route->ce_mask |= (ROUTE_ATTR_PREF_SRC | ROUTE_ATTR_FAMILY);
81644d362409d5469aed47d19e7908d19bd194493aThomas Graf
81744d362409d5469aed47d19e7908d19bd194493aThomas Graf	return 0;
81844d362409d5469aed47d19e7908d19bd194493aThomas Graf}
81944d362409d5469aed47d19e7908d19bd194493aThomas Graf
82044d362409d5469aed47d19e7908d19bd194493aThomas Grafstruct nl_addr *rtnl_route_get_pref_src(struct rtnl_route *route)
82144d362409d5469aed47d19e7908d19bd194493aThomas Graf{
82244d362409d5469aed47d19e7908d19bd194493aThomas Graf	return route->rt_pref_src;
82344d362409d5469aed47d19e7908d19bd194493aThomas Graf}
82444d362409d5469aed47d19e7908d19bd194493aThomas Graf
82544d362409d5469aed47d19e7908d19bd194493aThomas Grafvoid rtnl_route_set_oif(struct rtnl_route *route, int ifindex)
82644d362409d5469aed47d19e7908d19bd194493aThomas Graf{
82744d362409d5469aed47d19e7908d19bd194493aThomas Graf	route->rt_oif = ifindex;
82844d362409d5469aed47d19e7908d19bd194493aThomas Graf	route->ce_mask |= ROUTE_ATTR_OIF;
82944d362409d5469aed47d19e7908d19bd194493aThomas Graf}
83044d362409d5469aed47d19e7908d19bd194493aThomas Graf
83144d362409d5469aed47d19e7908d19bd194493aThomas Grafint rtnl_route_get_oif(struct rtnl_route *route)
83244d362409d5469aed47d19e7908d19bd194493aThomas Graf{
83344d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (route->ce_mask & ROUTE_ATTR_OIF)
83444d362409d5469aed47d19e7908d19bd194493aThomas Graf		return route->rt_oif;
83544d362409d5469aed47d19e7908d19bd194493aThomas Graf	else
83644d362409d5469aed47d19e7908d19bd194493aThomas Graf		return RTNL_LINK_NOT_FOUND;
83744d362409d5469aed47d19e7908d19bd194493aThomas Graf}
83844d362409d5469aed47d19e7908d19bd194493aThomas Graf
83944d362409d5469aed47d19e7908d19bd194493aThomas Grafvoid rtnl_route_set_iif(struct rtnl_route *route, const char *name)
84044d362409d5469aed47d19e7908d19bd194493aThomas Graf{
84144d362409d5469aed47d19e7908d19bd194493aThomas Graf	strncpy(route->rt_iif, name, sizeof(route->rt_iif) - 1);
84244d362409d5469aed47d19e7908d19bd194493aThomas Graf	route->ce_mask |= ROUTE_ATTR_IIF;
84344d362409d5469aed47d19e7908d19bd194493aThomas Graf}
84444d362409d5469aed47d19e7908d19bd194493aThomas Graf
84544d362409d5469aed47d19e7908d19bd194493aThomas Grafchar *rtnl_route_get_iif(struct rtnl_route *route)
84644d362409d5469aed47d19e7908d19bd194493aThomas Graf{
84744d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (route->ce_mask & ROUTE_ATTR_IIF)
84844d362409d5469aed47d19e7908d19bd194493aThomas Graf		return route->rt_iif;
84944d362409d5469aed47d19e7908d19bd194493aThomas Graf	else
85044d362409d5469aed47d19e7908d19bd194493aThomas Graf		return NULL;
85144d362409d5469aed47d19e7908d19bd194493aThomas Graf}
85244d362409d5469aed47d19e7908d19bd194493aThomas Graf
85344d362409d5469aed47d19e7908d19bd194493aThomas Grafvoid rtnl_route_add_nexthop(struct rtnl_route *route, struct rtnl_nexthop *nh)
85444d362409d5469aed47d19e7908d19bd194493aThomas Graf{
85544d362409d5469aed47d19e7908d19bd194493aThomas Graf	nl_list_add_tail(&nh->rtnh_list, &route->rt_nexthops);
85644d362409d5469aed47d19e7908d19bd194493aThomas Graf	route->ce_mask |= ROUTE_ATTR_MULTIPATH;
85744d362409d5469aed47d19e7908d19bd194493aThomas Graf}
85844d362409d5469aed47d19e7908d19bd194493aThomas Graf
85944d362409d5469aed47d19e7908d19bd194493aThomas Grafvoid rtnl_route_remove_nexthop(struct rtnl_nexthop *nh)
86044d362409d5469aed47d19e7908d19bd194493aThomas Graf{
86144d362409d5469aed47d19e7908d19bd194493aThomas Graf	nl_list_del(&nh->rtnh_list);
86244d362409d5469aed47d19e7908d19bd194493aThomas Graf}
86344d362409d5469aed47d19e7908d19bd194493aThomas Graf
86444d362409d5469aed47d19e7908d19bd194493aThomas Grafstruct nl_list_head *rtnl_route_get_nexthops(struct rtnl_route *route)
86544d362409d5469aed47d19e7908d19bd194493aThomas Graf{
86644d362409d5469aed47d19e7908d19bd194493aThomas Graf	return &route->rt_nexthops;
86744d362409d5469aed47d19e7908d19bd194493aThomas Graf}
86844d362409d5469aed47d19e7908d19bd194493aThomas Graf
86944d362409d5469aed47d19e7908d19bd194493aThomas Grafvoid rtnl_route_set_cacheinfo(struct rtnl_route *route,
87044d362409d5469aed47d19e7908d19bd194493aThomas Graf			      struct rtnl_rtcacheinfo *ci)
87144d362409d5469aed47d19e7908d19bd194493aThomas Graf{
87244d362409d5469aed47d19e7908d19bd194493aThomas Graf	memcpy(&route->rt_cacheinfo, ci, sizeof(*ci));
87344d362409d5469aed47d19e7908d19bd194493aThomas Graf	route->ce_mask |= ROUTE_ATTR_CACHEINFO;
87444d362409d5469aed47d19e7908d19bd194493aThomas Graf}
87544d362409d5469aed47d19e7908d19bd194493aThomas Graf
87644d362409d5469aed47d19e7908d19bd194493aThomas Grafuint32_t rtnl_route_get_mp_algo(struct rtnl_route *route)
87744d362409d5469aed47d19e7908d19bd194493aThomas Graf{
87844d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (route->ce_mask & ROUTE_ATTR_MP_ALGO)
87944d362409d5469aed47d19e7908d19bd194493aThomas Graf		return route->rt_mp_algo;
88044d362409d5469aed47d19e7908d19bd194493aThomas Graf	else
88144d362409d5469aed47d19e7908d19bd194493aThomas Graf		return IP_MP_ALG_NONE;
88244d362409d5469aed47d19e7908d19bd194493aThomas Graf}
88344d362409d5469aed47d19e7908d19bd194493aThomas Graf
88444d362409d5469aed47d19e7908d19bd194493aThomas Grafvoid rtnl_route_set_mp_algo(struct rtnl_route *route, uint32_t algo)
88544d362409d5469aed47d19e7908d19bd194493aThomas Graf{
88644d362409d5469aed47d19e7908d19bd194493aThomas Graf	route->rt_mp_algo = algo;
88744d362409d5469aed47d19e7908d19bd194493aThomas Graf	route->ce_mask |= ROUTE_ATTR_MP_ALGO;
88844d362409d5469aed47d19e7908d19bd194493aThomas Graf}
88944d362409d5469aed47d19e7908d19bd194493aThomas Graf
89044d362409d5469aed47d19e7908d19bd194493aThomas Graf/** @} */
89144d362409d5469aed47d19e7908d19bd194493aThomas Graf
89244d362409d5469aed47d19e7908d19bd194493aThomas Grafstruct nl_object_ops route_obj_ops = {
89344d362409d5469aed47d19e7908d19bd194493aThomas Graf	.oo_name		= "route/route",
89444d362409d5469aed47d19e7908d19bd194493aThomas Graf	.oo_size		= sizeof(struct rtnl_route),
89544d362409d5469aed47d19e7908d19bd194493aThomas Graf	.oo_constructor		= route_constructor,
89644d362409d5469aed47d19e7908d19bd194493aThomas Graf	.oo_free_data		= route_free_data,
89744d362409d5469aed47d19e7908d19bd194493aThomas Graf	.oo_clone		= route_clone,
89844d362409d5469aed47d19e7908d19bd194493aThomas Graf	.oo_dump[NL_DUMP_BRIEF]	= route_dump_brief,
89944d362409d5469aed47d19e7908d19bd194493aThomas Graf	.oo_dump[NL_DUMP_FULL]	= route_dump_full,
90044d362409d5469aed47d19e7908d19bd194493aThomas Graf	.oo_dump[NL_DUMP_STATS]	= route_dump_stats,
90144d362409d5469aed47d19e7908d19bd194493aThomas Graf	.oo_dump[NL_DUMP_XML]	= route_dump_xml,
90244d362409d5469aed47d19e7908d19bd194493aThomas Graf	.oo_dump[NL_DUMP_ENV]	= route_dump_env,
90344d362409d5469aed47d19e7908d19bd194493aThomas Graf	.oo_compare		= route_compare,
90444d362409d5469aed47d19e7908d19bd194493aThomas Graf	.oo_attrs2str		= route_attrs2str,
90544d362409d5469aed47d19e7908d19bd194493aThomas Graf	.oo_id_attrs		= (ROUTE_ATTR_FAMILY | ROUTE_ATTR_TOS |
90644d362409d5469aed47d19e7908d19bd194493aThomas Graf				   ROUTE_ATTR_TABLE | ROUTE_ATTR_DST),
90744d362409d5469aed47d19e7908d19bd194493aThomas Graf};
90844d362409d5469aed47d19e7908d19bd194493aThomas Graf
90944d362409d5469aed47d19e7908d19bd194493aThomas Graf/** @} */
910