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 *
9535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf * Copyright (c) 2003-2008 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 * protocol                                       RTPROT_STATIC
2444d362409d5469aed47d19e7908d19bd194493aThomas Graf * prio                                           0
2544d362409d5469aed47d19e7908d19bd194493aThomas Graf * family                                         AF_UNSPEC
2644d362409d5469aed47d19e7908d19bd194493aThomas Graf * type                                           RTN_UNICAST
2744d362409d5469aed47d19e7908d19bd194493aThomas Graf * iif                                            NULL
2844d362409d5469aed47d19e7908d19bd194493aThomas Graf * @endcode
2944d362409d5469aed47d19e7908d19bd194493aThomas Graf *
3044d362409d5469aed47d19e7908d19bd194493aThomas Graf * @{
3144d362409d5469aed47d19e7908d19bd194493aThomas Graf */
3244d362409d5469aed47d19e7908d19bd194493aThomas Graf
3344d362409d5469aed47d19e7908d19bd194493aThomas Graf#include <netlink-local.h>
3444d362409d5469aed47d19e7908d19bd194493aThomas Graf#include <netlink/netlink.h>
3544d362409d5469aed47d19e7908d19bd194493aThomas Graf#include <netlink/cache.h>
3644d362409d5469aed47d19e7908d19bd194493aThomas Graf#include <netlink/utils.h>
3744d362409d5469aed47d19e7908d19bd194493aThomas Graf#include <netlink/data.h>
3844d362409d5469aed47d19e7908d19bd194493aThomas Graf#include <netlink/route/rtnl.h>
3944d362409d5469aed47d19e7908d19bd194493aThomas Graf#include <netlink/route/route.h>
4044d362409d5469aed47d19e7908d19bd194493aThomas Graf#include <netlink/route/link.h>
41535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf#include <netlink/route/nexthop.h>
4244d362409d5469aed47d19e7908d19bd194493aThomas Graf
4344d362409d5469aed47d19e7908d19bd194493aThomas Graf/** @cond SKIP */
4444d362409d5469aed47d19e7908d19bd194493aThomas Graf#define ROUTE_ATTR_FAMILY    0x000001
4544d362409d5469aed47d19e7908d19bd194493aThomas Graf#define ROUTE_ATTR_TOS       0x000002
4644d362409d5469aed47d19e7908d19bd194493aThomas Graf#define ROUTE_ATTR_TABLE     0x000004
4744d362409d5469aed47d19e7908d19bd194493aThomas Graf#define ROUTE_ATTR_PROTOCOL  0x000008
4844d362409d5469aed47d19e7908d19bd194493aThomas Graf#define ROUTE_ATTR_SCOPE     0x000010
4944d362409d5469aed47d19e7908d19bd194493aThomas Graf#define ROUTE_ATTR_TYPE      0x000020
5044d362409d5469aed47d19e7908d19bd194493aThomas Graf#define ROUTE_ATTR_FLAGS     0x000040
5144d362409d5469aed47d19e7908d19bd194493aThomas Graf#define ROUTE_ATTR_DST       0x000080
5244d362409d5469aed47d19e7908d19bd194493aThomas Graf#define ROUTE_ATTR_SRC       0x000100
5344d362409d5469aed47d19e7908d19bd194493aThomas Graf#define ROUTE_ATTR_IIF       0x000200
5444d362409d5469aed47d19e7908d19bd194493aThomas Graf#define ROUTE_ATTR_OIF       0x000400
5544d362409d5469aed47d19e7908d19bd194493aThomas Graf#define ROUTE_ATTR_GATEWAY   0x000800
5644d362409d5469aed47d19e7908d19bd194493aThomas Graf#define ROUTE_ATTR_PRIO      0x001000
5744d362409d5469aed47d19e7908d19bd194493aThomas Graf#define ROUTE_ATTR_PREF_SRC  0x002000
5844d362409d5469aed47d19e7908d19bd194493aThomas Graf#define ROUTE_ATTR_METRICS   0x004000
5944d362409d5469aed47d19e7908d19bd194493aThomas Graf#define ROUTE_ATTR_MULTIPATH 0x008000
6044d362409d5469aed47d19e7908d19bd194493aThomas Graf#define ROUTE_ATTR_REALMS    0x010000
6144d362409d5469aed47d19e7908d19bd194493aThomas Graf#define ROUTE_ATTR_CACHEINFO 0x020000
6244d362409d5469aed47d19e7908d19bd194493aThomas Graf/** @endcond */
6344d362409d5469aed47d19e7908d19bd194493aThomas Graf
6444d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic void route_constructor(struct nl_object *c)
6544d362409d5469aed47d19e7908d19bd194493aThomas Graf{
6644d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct rtnl_route *r = (struct rtnl_route *) c;
6744d362409d5469aed47d19e7908d19bd194493aThomas Graf
68535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf	r->rt_family = AF_UNSPEC;
69535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf	r->rt_scope = RT_SCOPE_NOWHERE;
70535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf	r->rt_table = RT_TABLE_MAIN;
71535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf	r->rt_protocol = RTPROT_STATIC;
72535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf	r->rt_type = RTN_UNICAST;
73535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf
7444d362409d5469aed47d19e7908d19bd194493aThomas Graf	nl_init_list_head(&r->rt_nexthops);
7544d362409d5469aed47d19e7908d19bd194493aThomas Graf}
7644d362409d5469aed47d19e7908d19bd194493aThomas Graf
7744d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic void route_free_data(struct nl_object *c)
7844d362409d5469aed47d19e7908d19bd194493aThomas Graf{
7944d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct rtnl_route *r = (struct rtnl_route *) c;
8044d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct rtnl_nexthop *nh, *tmp;
8144d362409d5469aed47d19e7908d19bd194493aThomas Graf
8244d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (r == NULL)
8344d362409d5469aed47d19e7908d19bd194493aThomas Graf		return;
8444d362409d5469aed47d19e7908d19bd194493aThomas Graf
8544d362409d5469aed47d19e7908d19bd194493aThomas Graf	nl_addr_put(r->rt_dst);
8644d362409d5469aed47d19e7908d19bd194493aThomas Graf	nl_addr_put(r->rt_src);
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) {
90535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf		rtnl_route_remove_nexthop(r, 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)))
1038a3efffa5b3fde252675239914118664d36a2c24Thomas Graf			return -NLE_NOMEM;
10444d362409d5469aed47d19e7908d19bd194493aThomas Graf
10544d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (src->rt_src)
10644d362409d5469aed47d19e7908d19bd194493aThomas Graf		if (!(dst->rt_src = nl_addr_clone(src->rt_src)))
1078a3efffa5b3fde252675239914118664d36a2c24Thomas Graf			return -NLE_NOMEM;
10844d362409d5469aed47d19e7908d19bd194493aThomas Graf
10944d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (src->rt_pref_src)
11044d362409d5469aed47d19e7908d19bd194493aThomas Graf		if (!(dst->rt_pref_src = nl_addr_clone(src->rt_pref_src)))
1118a3efffa5b3fde252675239914118664d36a2c24Thomas Graf			return -NLE_NOMEM;
11244d362409d5469aed47d19e7908d19bd194493aThomas Graf
11344d362409d5469aed47d19e7908d19bd194493aThomas Graf	nl_init_list_head(&dst->rt_nexthops);
11444d362409d5469aed47d19e7908d19bd194493aThomas Graf	nl_list_for_each_entry(nh, &src->rt_nexthops, rtnh_list) {
11544d362409d5469aed47d19e7908d19bd194493aThomas Graf		new = rtnl_route_nh_clone(nh);
11644d362409d5469aed47d19e7908d19bd194493aThomas Graf		if (!new)
1178a3efffa5b3fde252675239914118664d36a2c24Thomas Graf			return -NLE_NOMEM;
11844d362409d5469aed47d19e7908d19bd194493aThomas Graf
11944d362409d5469aed47d19e7908d19bd194493aThomas Graf		rtnl_route_add_nexthop(dst, new);
12044d362409d5469aed47d19e7908d19bd194493aThomas Graf	}
12144d362409d5469aed47d19e7908d19bd194493aThomas Graf
12244d362409d5469aed47d19e7908d19bd194493aThomas Graf	return 0;
12344d362409d5469aed47d19e7908d19bd194493aThomas Graf}
12444d362409d5469aed47d19e7908d19bd194493aThomas Graf
125d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Grafstatic void route_dump_line(struct nl_object *a, struct nl_dump_params *p)
12644d362409d5469aed47d19e7908d19bd194493aThomas Graf{
12744d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct rtnl_route *r = (struct rtnl_route *) a;
12844d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct nl_cache *link_cache;
1297072675b40b611279466756ef800cc5dbee92c54Thomas Graf	int cache = 0, flags;
13044d362409d5469aed47d19e7908d19bd194493aThomas Graf	char buf[64];
13144d362409d5469aed47d19e7908d19bd194493aThomas Graf
13244d362409d5469aed47d19e7908d19bd194493aThomas Graf	link_cache = nl_cache_mngt_require("route/link");
13344d362409d5469aed47d19e7908d19bd194493aThomas Graf
1347072675b40b611279466756ef800cc5dbee92c54Thomas Graf	if (r->rt_flags & RTM_F_CLONED)
1357072675b40b611279466756ef800cc5dbee92c54Thomas Graf		cache = 1;
1367072675b40b611279466756ef800cc5dbee92c54Thomas Graf
137d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Graf	nl_dump_line(p, "%s ", nl_af2str(r->rt_family, buf, sizeof(buf)));
138535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf
1397072675b40b611279466756ef800cc5dbee92c54Thomas Graf	if (cache)
1407072675b40b611279466756ef800cc5dbee92c54Thomas Graf		nl_dump(p, "cache ");
1417072675b40b611279466756ef800cc5dbee92c54Thomas Graf
142464988628802b76d5b3e50af99158413ac28bd18Thomas Graf	if (!(r->ce_mask & ROUTE_ATTR_DST) ||
143464988628802b76d5b3e50af99158413ac28bd18Thomas Graf	    nl_addr_get_len(r->rt_dst) == 0)
144535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf		nl_dump(p, "default ");
145464988628802b76d5b3e50af99158413ac28bd18Thomas Graf	else
146535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf		nl_dump(p, "%s ", nl_addr2str(r->rt_dst, buf, sizeof(buf)));
14744d362409d5469aed47d19e7908d19bd194493aThomas Graf
1487072675b40b611279466756ef800cc5dbee92c54Thomas Graf	if (r->ce_mask & ROUTE_ATTR_TABLE && !cache)
149535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf		nl_dump(p, "table %s ",
150535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf			rtnl_route_table2str(r->rt_table, buf, sizeof(buf)));
15144d362409d5469aed47d19e7908d19bd194493aThomas Graf
152535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf	if (r->ce_mask & ROUTE_ATTR_TYPE)
153535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf		nl_dump(p, "type %s ",
154535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf			nl_rtntype2str(r->rt_type, buf, sizeof(buf)));
155535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf
156535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf	if (r->ce_mask & ROUTE_ATTR_TOS && r->rt_tos != 0)
157535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf		nl_dump(p, "tos %#x ", r->rt_tos);
158535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf
159535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf	if (r->ce_mask & ROUTE_ATTR_MULTIPATH) {
160535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf		struct rtnl_nexthop *nh;
161535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf
162535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf		nl_list_for_each_entry(nh, &r->rt_nexthops, rtnh_list) {
163535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf			p->dp_ivar = NH_DUMP_FROM_ONELINE;
164535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf			rtnl_route_nh_dump(nh, p);
165535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf		}
166535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf	}
16744d362409d5469aed47d19e7908d19bd194493aThomas Graf
1687072675b40b611279466756ef800cc5dbee92c54Thomas Graf	flags = r->rt_flags & ~(RTM_F_CLONED);
1697072675b40b611279466756ef800cc5dbee92c54Thomas Graf	if (r->ce_mask & ROUTE_ATTR_FLAGS && flags) {
17044d362409d5469aed47d19e7908d19bd194493aThomas Graf
171535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf		nl_dump(p, "<");
1727072675b40b611279466756ef800cc5dbee92c54Thomas Graf
17344d362409d5469aed47d19e7908d19bd194493aThomas Graf#define PRINT_FLAG(f) if (flags & RTNH_F_##f) { \
174535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf		flags &= ~RTNH_F_##f; nl_dump(p, #f "%s", flags ? "," : ""); }
17544d362409d5469aed47d19e7908d19bd194493aThomas Graf		PRINT_FLAG(DEAD);
17644d362409d5469aed47d19e7908d19bd194493aThomas Graf		PRINT_FLAG(ONLINK);
17744d362409d5469aed47d19e7908d19bd194493aThomas Graf		PRINT_FLAG(PERVASIVE);
17844d362409d5469aed47d19e7908d19bd194493aThomas Graf#undef PRINT_FLAG
17944d362409d5469aed47d19e7908d19bd194493aThomas Graf
18044d362409d5469aed47d19e7908d19bd194493aThomas Graf#define PRINT_FLAG(f) if (flags & RTM_F_##f) { \
181535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf		flags &= ~RTM_F_##f; nl_dump(p, #f "%s", flags ? "," : ""); }
18244d362409d5469aed47d19e7908d19bd194493aThomas Graf		PRINT_FLAG(NOTIFY);
18344d362409d5469aed47d19e7908d19bd194493aThomas Graf		PRINT_FLAG(EQUALIZE);
18444d362409d5469aed47d19e7908d19bd194493aThomas Graf		PRINT_FLAG(PREFIX);
18544d362409d5469aed47d19e7908d19bd194493aThomas Graf#undef PRINT_FLAG
18644d362409d5469aed47d19e7908d19bd194493aThomas Graf
1877072675b40b611279466756ef800cc5dbee92c54Thomas Graf#define PRINT_FLAG(f) if (flags & RTCF_##f) { \
1887072675b40b611279466756ef800cc5dbee92c54Thomas Graf		flags &= ~RTCF_##f; nl_dump(p, #f "%s", flags ? "," : ""); }
1897072675b40b611279466756ef800cc5dbee92c54Thomas Graf		PRINT_FLAG(NOTIFY);
1907072675b40b611279466756ef800cc5dbee92c54Thomas Graf		PRINT_FLAG(REDIRECTED);
1917072675b40b611279466756ef800cc5dbee92c54Thomas Graf		PRINT_FLAG(DOREDIRECT);
1927072675b40b611279466756ef800cc5dbee92c54Thomas Graf		PRINT_FLAG(DIRECTSRC);
1937072675b40b611279466756ef800cc5dbee92c54Thomas Graf		PRINT_FLAG(DNAT);
1947072675b40b611279466756ef800cc5dbee92c54Thomas Graf		PRINT_FLAG(BROADCAST);
1957072675b40b611279466756ef800cc5dbee92c54Thomas Graf		PRINT_FLAG(MULTICAST);
1967072675b40b611279466756ef800cc5dbee92c54Thomas Graf		PRINT_FLAG(LOCAL);
1977072675b40b611279466756ef800cc5dbee92c54Thomas Graf#undef PRINT_FLAG
1987072675b40b611279466756ef800cc5dbee92c54Thomas Graf
199535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf		nl_dump(p, ">");
20044d362409d5469aed47d19e7908d19bd194493aThomas Graf	}
20144d362409d5469aed47d19e7908d19bd194493aThomas Graf
202535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf	nl_dump(p, "\n");
20344d362409d5469aed47d19e7908d19bd194493aThomas Graf}
20444d362409d5469aed47d19e7908d19bd194493aThomas Graf
205d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Grafstatic void route_dump_details(struct nl_object *a, struct nl_dump_params *p)
20644d362409d5469aed47d19e7908d19bd194493aThomas Graf{
20744d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct rtnl_route *r = (struct rtnl_route *) a;
20844d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct nl_cache *link_cache;
20944d362409d5469aed47d19e7908d19bd194493aThomas Graf	char buf[128];
210535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf	int i;
21144d362409d5469aed47d19e7908d19bd194493aThomas Graf
21244d362409d5469aed47d19e7908d19bd194493aThomas Graf	link_cache = nl_cache_mngt_require("route/link");
21344d362409d5469aed47d19e7908d19bd194493aThomas Graf
214d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Graf	route_dump_line(a, p);
215535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf	nl_dump_line(p, "    ");
21644d362409d5469aed47d19e7908d19bd194493aThomas Graf
21744d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (r->ce_mask & ROUTE_ATTR_PREF_SRC)
218535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf		nl_dump(p, "preferred-src %s ",
21944d362409d5469aed47d19e7908d19bd194493aThomas Graf			nl_addr2str(r->rt_pref_src, buf, sizeof(buf)));
22044d362409d5469aed47d19e7908d19bd194493aThomas Graf
221535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf	if (r->ce_mask & ROUTE_ATTR_SCOPE && r->rt_scope != RT_SCOPE_NOWHERE)
222535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf		nl_dump(p, "scope %s ",
223535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf			rtnl_scope2str(r->rt_scope, buf, sizeof(buf)));
22444d362409d5469aed47d19e7908d19bd194493aThomas Graf
22544d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (r->ce_mask & ROUTE_ATTR_PRIO)
226535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf		nl_dump(p, "priority %#x ", r->rt_prio);
22744d362409d5469aed47d19e7908d19bd194493aThomas Graf
22844d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (r->ce_mask & ROUTE_ATTR_PROTOCOL)
229535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf		nl_dump(p, "protocol %s ",
23044d362409d5469aed47d19e7908d19bd194493aThomas Graf			rtnl_route_proto2str(r->rt_protocol, buf, sizeof(buf)));
23144d362409d5469aed47d19e7908d19bd194493aThomas Graf
232d6cd72555d1e0334567d213eb84547758aef6255Thomas Graf	if (r->ce_mask & ROUTE_ATTR_IIF) {
233d6cd72555d1e0334567d213eb84547758aef6255Thomas Graf		if (link_cache) {
234d6cd72555d1e0334567d213eb84547758aef6255Thomas Graf			nl_dump(p, "iif %s ",
235d6cd72555d1e0334567d213eb84547758aef6255Thomas Graf				rtnl_link_i2name(link_cache, r->rt_iif,
236d6cd72555d1e0334567d213eb84547758aef6255Thomas Graf						 buf, sizeof(buf)));
237d6cd72555d1e0334567d213eb84547758aef6255Thomas Graf		} else
238d6cd72555d1e0334567d213eb84547758aef6255Thomas Graf			nl_dump(p, "iif %d ", r->rt_iif);
239d6cd72555d1e0334567d213eb84547758aef6255Thomas Graf	}
24044d362409d5469aed47d19e7908d19bd194493aThomas Graf
241535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf	if (r->ce_mask & ROUTE_ATTR_SRC)
242535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf		nl_dump(p, "src %s ", nl_addr2str(r->rt_src, buf, sizeof(buf)));
24344d362409d5469aed47d19e7908d19bd194493aThomas Graf
244535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf	nl_dump(p, "\n");
24544d362409d5469aed47d19e7908d19bd194493aThomas Graf
246535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf	if (r->ce_mask & ROUTE_ATTR_MULTIPATH) {
247535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf		struct rtnl_nexthop *nh;
24844d362409d5469aed47d19e7908d19bd194493aThomas Graf
249535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf		nl_list_for_each_entry(nh, &r->rt_nexthops, rtnh_list) {
250535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf			nl_dump_line(p, "    ");
251535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf			p->dp_ivar = NH_DUMP_FROM_DETAILS;
252535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf			rtnl_route_nh_dump(nh, p);
253535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf			nl_dump(p, "\n");
254535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf		}
255535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf	}
25644d362409d5469aed47d19e7908d19bd194493aThomas Graf
257535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf	if ((r->ce_mask & ROUTE_ATTR_CACHEINFO) && r->rt_cacheinfo.rtci_error) {
258535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf		nl_dump_line(p, "    cacheinfo error %d (%s)\n",
259535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf			r->rt_cacheinfo.rtci_error,
260535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf			strerror(-r->rt_cacheinfo.rtci_error));
26144d362409d5469aed47d19e7908d19bd194493aThomas Graf	}
26244d362409d5469aed47d19e7908d19bd194493aThomas Graf
26344d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (r->ce_mask & ROUTE_ATTR_METRICS) {
264535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf		nl_dump_line(p, "    metrics [");
26544d362409d5469aed47d19e7908d19bd194493aThomas Graf		for (i = 0; i < RTAX_MAX; i++)
26644d362409d5469aed47d19e7908d19bd194493aThomas Graf			if (r->rt_metrics_mask & (1 << i))
267535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf				nl_dump(p, "%s %u ",
26844d362409d5469aed47d19e7908d19bd194493aThomas Graf					rtnl_route_metric2str(i+1,
26944d362409d5469aed47d19e7908d19bd194493aThomas Graf							      buf, sizeof(buf)),
27044d362409d5469aed47d19e7908d19bd194493aThomas Graf					r->rt_metrics[i]);
271535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf		nl_dump(p, "]\n");
27244d362409d5469aed47d19e7908d19bd194493aThomas Graf	}
27344d362409d5469aed47d19e7908d19bd194493aThomas Graf}
27444d362409d5469aed47d19e7908d19bd194493aThomas Graf
275d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Grafstatic void route_dump_stats(struct nl_object *obj, struct nl_dump_params *p)
27644d362409d5469aed47d19e7908d19bd194493aThomas Graf{
27744d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct rtnl_route *route = (struct rtnl_route *) obj;
27844d362409d5469aed47d19e7908d19bd194493aThomas Graf
279535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf	route_dump_details(obj, p);
28044d362409d5469aed47d19e7908d19bd194493aThomas Graf
28144d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (route->ce_mask & ROUTE_ATTR_CACHEINFO) {
28244d362409d5469aed47d19e7908d19bd194493aThomas Graf		struct rtnl_rtcacheinfo *ci = &route->rt_cacheinfo;
283535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf
284535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf		nl_dump_line(p, "    used %u refcnt %u last-use %us "
285535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf				"expires %us\n",
286535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf			     ci->rtci_used, ci->rtci_clntref,
28744d362409d5469aed47d19e7908d19bd194493aThomas Graf			     ci->rtci_last_use / nl_get_hz(),
28844d362409d5469aed47d19e7908d19bd194493aThomas Graf			     ci->rtci_expires / nl_get_hz());
28944d362409d5469aed47d19e7908d19bd194493aThomas Graf	}
29044d362409d5469aed47d19e7908d19bd194493aThomas Graf}
29144d362409d5469aed47d19e7908d19bd194493aThomas Graf
292d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Grafstatic void route_dump_env(struct nl_object *obj, struct nl_dump_params *p)
29344d362409d5469aed47d19e7908d19bd194493aThomas Graf{
29444d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct rtnl_route *route = (struct rtnl_route *) obj;
295d6cd72555d1e0334567d213eb84547758aef6255Thomas Graf	struct nl_cache *link_cache;
29644d362409d5469aed47d19e7908d19bd194493aThomas Graf	char buf[128];
297535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf
298d6cd72555d1e0334567d213eb84547758aef6255Thomas Graf	link_cache = nl_cache_mngt_require("route/link");
299d6cd72555d1e0334567d213eb84547758aef6255Thomas Graf
300d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Graf	nl_dump_line(p, "ROUTE_FAMILY=%s\n",
30144d362409d5469aed47d19e7908d19bd194493aThomas Graf		     nl_af2str(route->rt_family, buf, sizeof(buf)));
30244d362409d5469aed47d19e7908d19bd194493aThomas Graf
30344d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (route->ce_mask & ROUTE_ATTR_DST)
304535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf		nl_dump_line(p, "ROUTE_DST=%s\n",
30544d362409d5469aed47d19e7908d19bd194493aThomas Graf			     nl_addr2str(route->rt_dst, buf, sizeof(buf)));
30644d362409d5469aed47d19e7908d19bd194493aThomas Graf
30744d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (route->ce_mask & ROUTE_ATTR_SRC)
308535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf		nl_dump_line(p, "ROUTE_SRC=%s\n",
30944d362409d5469aed47d19e7908d19bd194493aThomas Graf			     nl_addr2str(route->rt_src, buf, sizeof(buf)));
31044d362409d5469aed47d19e7908d19bd194493aThomas Graf
31144d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (route->ce_mask & ROUTE_ATTR_PREF_SRC)
312535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf		nl_dump_line(p, "ROUTE_PREFSRC=%s\n",
31344d362409d5469aed47d19e7908d19bd194493aThomas Graf			     nl_addr2str(route->rt_pref_src, buf, sizeof(buf)));
31444d362409d5469aed47d19e7908d19bd194493aThomas Graf
315d6cd72555d1e0334567d213eb84547758aef6255Thomas Graf	if (route->ce_mask & ROUTE_ATTR_IIF) {
316d6cd72555d1e0334567d213eb84547758aef6255Thomas Graf		if (link_cache) {
317d6cd72555d1e0334567d213eb84547758aef6255Thomas Graf			nl_dump_line(p, "ROUTE_IIF=%s",
318d6cd72555d1e0334567d213eb84547758aef6255Thomas Graf				rtnl_link_i2name(link_cache, route->rt_iif,
319d6cd72555d1e0334567d213eb84547758aef6255Thomas Graf						 buf, sizeof(buf)));
320d6cd72555d1e0334567d213eb84547758aef6255Thomas Graf		} else
321d6cd72555d1e0334567d213eb84547758aef6255Thomas Graf			nl_dump_line(p, "ROUTE_IIF=%d", route->rt_iif);
322d6cd72555d1e0334567d213eb84547758aef6255Thomas Graf	}
32344d362409d5469aed47d19e7908d19bd194493aThomas Graf
32444d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (route->ce_mask & ROUTE_ATTR_TOS)
325535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf		nl_dump_line(p, "ROUTE_TOS=%u\n", route->rt_tos);
32644d362409d5469aed47d19e7908d19bd194493aThomas Graf
32744d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (route->ce_mask & ROUTE_ATTR_TABLE)
328535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf		nl_dump_line(p, "ROUTE_TABLE=%u\n",
32944d362409d5469aed47d19e7908d19bd194493aThomas Graf			     route->rt_table);
33044d362409d5469aed47d19e7908d19bd194493aThomas Graf
33144d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (route->ce_mask & ROUTE_ATTR_SCOPE)
332535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf		nl_dump_line(p, "ROUTE_SCOPE=%s\n",
33344d362409d5469aed47d19e7908d19bd194493aThomas Graf			     rtnl_scope2str(route->rt_scope, buf, sizeof(buf)));
33444d362409d5469aed47d19e7908d19bd194493aThomas Graf
33544d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (route->ce_mask & ROUTE_ATTR_PRIO)
336535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf		nl_dump_line(p, "ROUTE_PRIORITY=%u\n",
33744d362409d5469aed47d19e7908d19bd194493aThomas Graf			     route->rt_prio);
33844d362409d5469aed47d19e7908d19bd194493aThomas Graf
33944d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (route->ce_mask & ROUTE_ATTR_TYPE)
340535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf		nl_dump_line(p, "ROUTE_TYPE=%s\n",
34144d362409d5469aed47d19e7908d19bd194493aThomas Graf			     nl_rtntype2str(route->rt_type, buf, sizeof(buf)));
34244d362409d5469aed47d19e7908d19bd194493aThomas Graf
343535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf	if (route->ce_mask & ROUTE_ATTR_MULTIPATH) {
344535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf		struct rtnl_nexthop *nh;
345535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf		int index = 1;
34644d362409d5469aed47d19e7908d19bd194493aThomas Graf
347535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf		if (route->rt_nr_nh > 0)
348535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf			nl_dump_line(p, "ROUTE_NR_NH=%u\n", route->rt_nr_nh);
34944d362409d5469aed47d19e7908d19bd194493aThomas Graf
350535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf		nl_list_for_each_entry(nh, &route->rt_nexthops, rtnh_list) {
351535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf			p->dp_ivar = index++;
352535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf			rtnl_route_nh_dump(nh, p);
353535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf		}
35444d362409d5469aed47d19e7908d19bd194493aThomas Graf	}
35544d362409d5469aed47d19e7908d19bd194493aThomas Graf}
35644d362409d5469aed47d19e7908d19bd194493aThomas Graf
35744d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic int route_compare(struct nl_object *_a, struct nl_object *_b,
35844d362409d5469aed47d19e7908d19bd194493aThomas Graf			uint32_t attrs, int flags)
35944d362409d5469aed47d19e7908d19bd194493aThomas Graf{
36044d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct rtnl_route *a = (struct rtnl_route *) _a;
36144d362409d5469aed47d19e7908d19bd194493aThomas Graf	struct rtnl_route *b = (struct rtnl_route *) _b;
362535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf	struct rtnl_nexthop *nh_a, *nh_b;
363535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf	int i, diff = 0, found;
36444d362409d5469aed47d19e7908d19bd194493aThomas Graf
36544d362409d5469aed47d19e7908d19bd194493aThomas Graf#define ROUTE_DIFF(ATTR, EXPR) ATTR_DIFF(attrs, ROUTE_ATTR_##ATTR, a, b, EXPR)
36644d362409d5469aed47d19e7908d19bd194493aThomas Graf
36744d362409d5469aed47d19e7908d19bd194493aThomas Graf	diff |= ROUTE_DIFF(FAMILY,	a->rt_family != b->rt_family);
36844d362409d5469aed47d19e7908d19bd194493aThomas Graf	diff |= ROUTE_DIFF(TOS,		a->rt_tos != b->rt_tos);
36944d362409d5469aed47d19e7908d19bd194493aThomas Graf	diff |= ROUTE_DIFF(TABLE,	a->rt_table != b->rt_table);
37044d362409d5469aed47d19e7908d19bd194493aThomas Graf	diff |= ROUTE_DIFF(PROTOCOL,	a->rt_protocol != b->rt_protocol);
37144d362409d5469aed47d19e7908d19bd194493aThomas Graf	diff |= ROUTE_DIFF(SCOPE,	a->rt_scope != b->rt_scope);
37244d362409d5469aed47d19e7908d19bd194493aThomas Graf	diff |= ROUTE_DIFF(TYPE,	a->rt_type != b->rt_type);
37344d362409d5469aed47d19e7908d19bd194493aThomas Graf	diff |= ROUTE_DIFF(PRIO,	a->rt_prio != b->rt_prio);
37444d362409d5469aed47d19e7908d19bd194493aThomas Graf	diff |= ROUTE_DIFF(DST,		nl_addr_cmp(a->rt_dst, b->rt_dst));
37544d362409d5469aed47d19e7908d19bd194493aThomas Graf	diff |= ROUTE_DIFF(SRC,		nl_addr_cmp(a->rt_src, b->rt_src));
376535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf	diff |= ROUTE_DIFF(IIF,		a->rt_iif != b->rt_iif);
37744d362409d5469aed47d19e7908d19bd194493aThomas Graf	diff |= ROUTE_DIFF(PREF_SRC,	nl_addr_cmp(a->rt_pref_src,
37844d362409d5469aed47d19e7908d19bd194493aThomas Graf						    b->rt_pref_src));
37944d362409d5469aed47d19e7908d19bd194493aThomas Graf
380535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf	if (flags & LOOSE_COMPARISON) {
381535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf		nl_list_for_each_entry(nh_b, &b->rt_nexthops, rtnh_list) {
382535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf			found = 0;
383535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf			nl_list_for_each_entry(nh_a, &a->rt_nexthops,
384535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf					       rtnh_list) {
385535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf				if (!rtnl_route_nh_compare(nh_a, nh_b,
386535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf							nh_b->ce_mask, 1)) {
387535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf					found = 1;
388535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf					break;
389535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf				}
390535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf			}
391535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf
392535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf			if (!found)
393535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf				goto nh_mismatch;
394535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf		}
395535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf
39648e1e5c4720094f60494ee55c2a22230ac986ad3Thomas Graf		for (i = 0; i < RTAX_MAX - 1; i++) {
39748e1e5c4720094f60494ee55c2a22230ac986ad3Thomas Graf			if (a->rt_metrics_mask & (1 << i) &&
39848e1e5c4720094f60494ee55c2a22230ac986ad3Thomas Graf			    (!(b->rt_metrics_mask & (1 << i)) ||
39948e1e5c4720094f60494ee55c2a22230ac986ad3Thomas Graf			     a->rt_metrics[i] != b->rt_metrics[i]))
40048e1e5c4720094f60494ee55c2a22230ac986ad3Thomas Graf				ROUTE_DIFF(METRICS, 1);
401535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf		}
40244d362409d5469aed47d19e7908d19bd194493aThomas Graf
40344d362409d5469aed47d19e7908d19bd194493aThomas Graf		diff |= ROUTE_DIFF(FLAGS,
40444d362409d5469aed47d19e7908d19bd194493aThomas Graf			  (a->rt_flags ^ b->rt_flags) & b->rt_flag_mask);
405535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf	} else {
406535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf		if (a->rt_nr_nh != a->rt_nr_nh)
407535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf			goto nh_mismatch;
408535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf
409535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf		/* search for a dup in each nh of a */
410535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf		nl_list_for_each_entry(nh_a, &a->rt_nexthops, rtnh_list) {
411535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf			found = 0;
412535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf			nl_list_for_each_entry(nh_b, &b->rt_nexthops,
413535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf					       rtnh_list) {
414535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf				if (!rtnl_route_nh_compare(nh_a, nh_b, ~0, 0))
415535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf					found = 1;
416535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf					break;
417535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf			}
418535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf			if (!found)
419535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf				goto nh_mismatch;
420535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf		}
421535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf
422535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf		/* search for a dup in each nh of b, covers case where a has
423535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf		 * dupes itself */
424535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf		nl_list_for_each_entry(nh_b, &b->rt_nexthops, rtnh_list) {
425535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf			found = 0;
426535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf			nl_list_for_each_entry(nh_a, &a->rt_nexthops,
427535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf					       rtnh_list) {
428535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf				if (!rtnl_route_nh_compare(nh_a, nh_b, ~0, 0))
429535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf					found = 1;
430535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf					break;
431535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf			}
432535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf			if (!found)
433535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf				goto nh_mismatch;
434535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf		}
435535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf
43648e1e5c4720094f60494ee55c2a22230ac986ad3Thomas Graf		for (i = 0; i < RTAX_MAX - 1; i++) {
43748e1e5c4720094f60494ee55c2a22230ac986ad3Thomas Graf			if ((a->rt_metrics_mask & (1 << i)) ^
43848e1e5c4720094f60494ee55c2a22230ac986ad3Thomas Graf			    (b->rt_metrics_mask & (1 << i)))
439535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf				diff |= ROUTE_DIFF(METRICS, 1);
440535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf			else
44148e1e5c4720094f60494ee55c2a22230ac986ad3Thomas Graf				diff |= ROUTE_DIFF(METRICS,
44248e1e5c4720094f60494ee55c2a22230ac986ad3Thomas Graf					a->rt_metrics[i] != b->rt_metrics[i]);
443535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf		}
444535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf
44544d362409d5469aed47d19e7908d19bd194493aThomas Graf		diff |= ROUTE_DIFF(FLAGS, a->rt_flags != b->rt_flags);
446535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf	}
44744d362409d5469aed47d19e7908d19bd194493aThomas Graf
448535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Grafout:
44944d362409d5469aed47d19e7908d19bd194493aThomas Graf	return diff;
450535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf
451535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Grafnh_mismatch:
452535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf	diff |= ROUTE_DIFF(MULTIPATH, 1);
453535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf	goto out;
454535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf
455535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf#undef ROUTE_DIFF
45644d362409d5469aed47d19e7908d19bd194493aThomas Graf}
45744d362409d5469aed47d19e7908d19bd194493aThomas Graf
45844d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic struct trans_tbl route_attrs[] = {
45944d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(ROUTE_ATTR_FAMILY, family)
46044d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(ROUTE_ATTR_TOS, tos)
46144d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(ROUTE_ATTR_TABLE, table)
46244d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(ROUTE_ATTR_PROTOCOL, protocol)
46344d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(ROUTE_ATTR_SCOPE, scope)
46444d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(ROUTE_ATTR_TYPE, type)
46544d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(ROUTE_ATTR_FLAGS, flags)
46644d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(ROUTE_ATTR_DST, dst)
46744d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(ROUTE_ATTR_SRC, src)
46844d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(ROUTE_ATTR_IIF, iif)
46944d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(ROUTE_ATTR_OIF, oif)
47044d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(ROUTE_ATTR_GATEWAY, gateway)
47144d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(ROUTE_ATTR_PRIO, prio)
47244d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(ROUTE_ATTR_PREF_SRC, pref_src)
47344d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(ROUTE_ATTR_METRICS, metrics)
47444d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(ROUTE_ATTR_MULTIPATH, multipath)
47544d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(ROUTE_ATTR_REALMS, realms)
47644d362409d5469aed47d19e7908d19bd194493aThomas Graf	__ADD(ROUTE_ATTR_CACHEINFO, cacheinfo)
47744d362409d5469aed47d19e7908d19bd194493aThomas Graf};
47844d362409d5469aed47d19e7908d19bd194493aThomas Graf
47944d362409d5469aed47d19e7908d19bd194493aThomas Grafstatic char *route_attrs2str(int attrs, char *buf, size_t len)
48044d362409d5469aed47d19e7908d19bd194493aThomas Graf{
48144d362409d5469aed47d19e7908d19bd194493aThomas Graf	return __flags2str(attrs, buf, len, route_attrs,
48244d362409d5469aed47d19e7908d19bd194493aThomas Graf			   ARRAY_SIZE(route_attrs));
48344d362409d5469aed47d19e7908d19bd194493aThomas Graf}
48444d362409d5469aed47d19e7908d19bd194493aThomas Graf
48544d362409d5469aed47d19e7908d19bd194493aThomas Graf/**
48644d362409d5469aed47d19e7908d19bd194493aThomas Graf * @name Allocation/Freeing
48744d362409d5469aed47d19e7908d19bd194493aThomas Graf * @{
48844d362409d5469aed47d19e7908d19bd194493aThomas Graf */
48944d362409d5469aed47d19e7908d19bd194493aThomas Graf
49044d362409d5469aed47d19e7908d19bd194493aThomas Grafstruct rtnl_route *rtnl_route_alloc(void)
49144d362409d5469aed47d19e7908d19bd194493aThomas Graf{
49244d362409d5469aed47d19e7908d19bd194493aThomas Graf	return (struct rtnl_route *) nl_object_alloc(&route_obj_ops);
49344d362409d5469aed47d19e7908d19bd194493aThomas Graf}
49444d362409d5469aed47d19e7908d19bd194493aThomas Graf
49544d362409d5469aed47d19e7908d19bd194493aThomas Grafvoid rtnl_route_get(struct rtnl_route *route)
49644d362409d5469aed47d19e7908d19bd194493aThomas Graf{
49744d362409d5469aed47d19e7908d19bd194493aThomas Graf	nl_object_get((struct nl_object *) route);
49844d362409d5469aed47d19e7908d19bd194493aThomas Graf}
49944d362409d5469aed47d19e7908d19bd194493aThomas Graf
50044d362409d5469aed47d19e7908d19bd194493aThomas Grafvoid rtnl_route_put(struct rtnl_route *route)
50144d362409d5469aed47d19e7908d19bd194493aThomas Graf{
50244d362409d5469aed47d19e7908d19bd194493aThomas Graf	nl_object_put((struct nl_object *) route);
50344d362409d5469aed47d19e7908d19bd194493aThomas Graf}
50444d362409d5469aed47d19e7908d19bd194493aThomas Graf
50544d362409d5469aed47d19e7908d19bd194493aThomas Graf/** @} */
50644d362409d5469aed47d19e7908d19bd194493aThomas Graf
50744d362409d5469aed47d19e7908d19bd194493aThomas Graf/**
50844d362409d5469aed47d19e7908d19bd194493aThomas Graf * @name Attributes
50944d362409d5469aed47d19e7908d19bd194493aThomas Graf * @{
51044d362409d5469aed47d19e7908d19bd194493aThomas Graf */
51144d362409d5469aed47d19e7908d19bd194493aThomas Graf
512535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Grafvoid rtnl_route_set_table(struct rtnl_route *route, uint32_t table)
51344d362409d5469aed47d19e7908d19bd194493aThomas Graf{
51444d362409d5469aed47d19e7908d19bd194493aThomas Graf	route->rt_table = table;
51544d362409d5469aed47d19e7908d19bd194493aThomas Graf	route->ce_mask |= ROUTE_ATTR_TABLE;
51644d362409d5469aed47d19e7908d19bd194493aThomas Graf}
51744d362409d5469aed47d19e7908d19bd194493aThomas Graf
518535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Grafuint32_t rtnl_route_get_table(struct rtnl_route *route)
51944d362409d5469aed47d19e7908d19bd194493aThomas Graf{
520535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf	return route->rt_table;
52144d362409d5469aed47d19e7908d19bd194493aThomas Graf}
52244d362409d5469aed47d19e7908d19bd194493aThomas Graf
523535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Grafvoid rtnl_route_set_scope(struct rtnl_route *route, uint8_t scope)
52444d362409d5469aed47d19e7908d19bd194493aThomas Graf{
52544d362409d5469aed47d19e7908d19bd194493aThomas Graf	route->rt_scope = scope;
52644d362409d5469aed47d19e7908d19bd194493aThomas Graf	route->ce_mask |= ROUTE_ATTR_SCOPE;
52744d362409d5469aed47d19e7908d19bd194493aThomas Graf}
52844d362409d5469aed47d19e7908d19bd194493aThomas Graf
529535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Grafuint8_t rtnl_route_get_scope(struct rtnl_route *route)
53044d362409d5469aed47d19e7908d19bd194493aThomas Graf{
531535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf	return route->rt_scope;
53244d362409d5469aed47d19e7908d19bd194493aThomas Graf}
53344d362409d5469aed47d19e7908d19bd194493aThomas Graf
534535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Grafvoid rtnl_route_set_tos(struct rtnl_route *route, uint8_t tos)
53544d362409d5469aed47d19e7908d19bd194493aThomas Graf{
53644d362409d5469aed47d19e7908d19bd194493aThomas Graf	route->rt_tos = tos;
53744d362409d5469aed47d19e7908d19bd194493aThomas Graf	route->ce_mask |= ROUTE_ATTR_TOS;
53844d362409d5469aed47d19e7908d19bd194493aThomas Graf}
53944d362409d5469aed47d19e7908d19bd194493aThomas Graf
540535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Grafuint8_t rtnl_route_get_tos(struct rtnl_route *route)
54144d362409d5469aed47d19e7908d19bd194493aThomas Graf{
54244d362409d5469aed47d19e7908d19bd194493aThomas Graf	return route->rt_tos;
54344d362409d5469aed47d19e7908d19bd194493aThomas Graf}
54444d362409d5469aed47d19e7908d19bd194493aThomas Graf
545535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Grafvoid rtnl_route_set_protocol(struct rtnl_route *route, uint8_t protocol)
54644d362409d5469aed47d19e7908d19bd194493aThomas Graf{
547535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf	route->rt_protocol = protocol;
54844d362409d5469aed47d19e7908d19bd194493aThomas Graf	route->ce_mask |= ROUTE_ATTR_PROTOCOL;
54944d362409d5469aed47d19e7908d19bd194493aThomas Graf}
55044d362409d5469aed47d19e7908d19bd194493aThomas Graf
551535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Grafuint8_t rtnl_route_get_protocol(struct rtnl_route *route)
55244d362409d5469aed47d19e7908d19bd194493aThomas Graf{
553535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf	return route->rt_protocol;
55444d362409d5469aed47d19e7908d19bd194493aThomas Graf}
55544d362409d5469aed47d19e7908d19bd194493aThomas Graf
556535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Grafvoid rtnl_route_set_priority(struct rtnl_route *route, uint32_t prio)
55744d362409d5469aed47d19e7908d19bd194493aThomas Graf{
55844d362409d5469aed47d19e7908d19bd194493aThomas Graf	route->rt_prio = prio;
55944d362409d5469aed47d19e7908d19bd194493aThomas Graf	route->ce_mask |= ROUTE_ATTR_PRIO;
56044d362409d5469aed47d19e7908d19bd194493aThomas Graf}
56144d362409d5469aed47d19e7908d19bd194493aThomas Graf
562535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Grafuint32_t rtnl_route_get_priority(struct rtnl_route *route)
56344d362409d5469aed47d19e7908d19bd194493aThomas Graf{
56444d362409d5469aed47d19e7908d19bd194493aThomas Graf	return route->rt_prio;
56544d362409d5469aed47d19e7908d19bd194493aThomas Graf}
56644d362409d5469aed47d19e7908d19bd194493aThomas Graf
567535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Grafint rtnl_route_set_family(struct rtnl_route *route, uint8_t family)
56844d362409d5469aed47d19e7908d19bd194493aThomas Graf{
569535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf	if (family != AF_INET && family != AF_INET6 && family != AF_DECnet)
5708a3efffa5b3fde252675239914118664d36a2c24Thomas Graf		return -NLE_AF_NOSUPPORT;
571535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf
57244d362409d5469aed47d19e7908d19bd194493aThomas Graf	route->rt_family = family;
57344d362409d5469aed47d19e7908d19bd194493aThomas Graf	route->ce_mask |= ROUTE_ATTR_FAMILY;
574535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf
575535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf	return 0;
57644d362409d5469aed47d19e7908d19bd194493aThomas Graf}
57744d362409d5469aed47d19e7908d19bd194493aThomas Graf
578535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Grafuint8_t rtnl_route_get_family(struct rtnl_route *route)
57944d362409d5469aed47d19e7908d19bd194493aThomas Graf{
580535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf	return route->rt_family;
58144d362409d5469aed47d19e7908d19bd194493aThomas Graf}
58244d362409d5469aed47d19e7908d19bd194493aThomas Graf
58344d362409d5469aed47d19e7908d19bd194493aThomas Grafint rtnl_route_set_dst(struct rtnl_route *route, struct nl_addr *addr)
58444d362409d5469aed47d19e7908d19bd194493aThomas Graf{
58544d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (route->ce_mask & ROUTE_ATTR_FAMILY) {
58644d362409d5469aed47d19e7908d19bd194493aThomas Graf		if (addr->a_family != route->rt_family)
5878a3efffa5b3fde252675239914118664d36a2c24Thomas Graf			return -NLE_AF_MISMATCH;
58844d362409d5469aed47d19e7908d19bd194493aThomas Graf	} else
58944d362409d5469aed47d19e7908d19bd194493aThomas Graf		route->rt_family = addr->a_family;
59044d362409d5469aed47d19e7908d19bd194493aThomas Graf
59144d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (route->rt_dst)
59244d362409d5469aed47d19e7908d19bd194493aThomas Graf		nl_addr_put(route->rt_dst);
59344d362409d5469aed47d19e7908d19bd194493aThomas Graf
59444d362409d5469aed47d19e7908d19bd194493aThomas Graf	nl_addr_get(addr);
59544d362409d5469aed47d19e7908d19bd194493aThomas Graf	route->rt_dst = addr;
59644d362409d5469aed47d19e7908d19bd194493aThomas Graf
59744d362409d5469aed47d19e7908d19bd194493aThomas Graf	route->ce_mask |= (ROUTE_ATTR_DST | ROUTE_ATTR_FAMILY);
59844d362409d5469aed47d19e7908d19bd194493aThomas Graf
59944d362409d5469aed47d19e7908d19bd194493aThomas Graf	return 0;
60044d362409d5469aed47d19e7908d19bd194493aThomas Graf}
60144d362409d5469aed47d19e7908d19bd194493aThomas Graf
60244d362409d5469aed47d19e7908d19bd194493aThomas Grafstruct nl_addr *rtnl_route_get_dst(struct rtnl_route *route)
60344d362409d5469aed47d19e7908d19bd194493aThomas Graf{
60444d362409d5469aed47d19e7908d19bd194493aThomas Graf	return route->rt_dst;
60544d362409d5469aed47d19e7908d19bd194493aThomas Graf}
60644d362409d5469aed47d19e7908d19bd194493aThomas Graf
60744d362409d5469aed47d19e7908d19bd194493aThomas Grafint rtnl_route_set_src(struct rtnl_route *route, struct nl_addr *addr)
60844d362409d5469aed47d19e7908d19bd194493aThomas Graf{
609535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf	if (addr->a_family == AF_INET)
6108a3efffa5b3fde252675239914118664d36a2c24Thomas Graf		return -NLE_SRCRT_NOSUPPORT;
611535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf
61244d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (route->ce_mask & ROUTE_ATTR_FAMILY) {
61344d362409d5469aed47d19e7908d19bd194493aThomas Graf		if (addr->a_family != route->rt_family)
6148a3efffa5b3fde252675239914118664d36a2c24Thomas Graf			return -NLE_AF_MISMATCH;
61544d362409d5469aed47d19e7908d19bd194493aThomas Graf	} else
61644d362409d5469aed47d19e7908d19bd194493aThomas Graf		route->rt_family = addr->a_family;
61744d362409d5469aed47d19e7908d19bd194493aThomas Graf
61844d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (route->rt_src)
61944d362409d5469aed47d19e7908d19bd194493aThomas Graf		nl_addr_put(route->rt_src);
62044d362409d5469aed47d19e7908d19bd194493aThomas Graf
62144d362409d5469aed47d19e7908d19bd194493aThomas Graf	nl_addr_get(addr);
62244d362409d5469aed47d19e7908d19bd194493aThomas Graf	route->rt_src = addr;
62344d362409d5469aed47d19e7908d19bd194493aThomas Graf	route->ce_mask |= (ROUTE_ATTR_SRC | ROUTE_ATTR_FAMILY);
62444d362409d5469aed47d19e7908d19bd194493aThomas Graf
62544d362409d5469aed47d19e7908d19bd194493aThomas Graf	return 0;
62644d362409d5469aed47d19e7908d19bd194493aThomas Graf}
62744d362409d5469aed47d19e7908d19bd194493aThomas Graf
62844d362409d5469aed47d19e7908d19bd194493aThomas Grafstruct nl_addr *rtnl_route_get_src(struct rtnl_route *route)
62944d362409d5469aed47d19e7908d19bd194493aThomas Graf{
63044d362409d5469aed47d19e7908d19bd194493aThomas Graf	return route->rt_src;
63144d362409d5469aed47d19e7908d19bd194493aThomas Graf}
63244d362409d5469aed47d19e7908d19bd194493aThomas Graf
633535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Grafint rtnl_route_set_type(struct rtnl_route *route, uint8_t type)
63444d362409d5469aed47d19e7908d19bd194493aThomas Graf{
635535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf	if (type > RTN_MAX)
6368a3efffa5b3fde252675239914118664d36a2c24Thomas Graf		return -NLE_RANGE;
6378a3efffa5b3fde252675239914118664d36a2c24Thomas Graf
63844d362409d5469aed47d19e7908d19bd194493aThomas Graf	route->rt_type = type;
63944d362409d5469aed47d19e7908d19bd194493aThomas Graf	route->ce_mask |= ROUTE_ATTR_TYPE;
640535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf
641535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf	return 0;
64244d362409d5469aed47d19e7908d19bd194493aThomas Graf}
64344d362409d5469aed47d19e7908d19bd194493aThomas Graf
644535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Grafuint8_t rtnl_route_get_type(struct rtnl_route *route)
64544d362409d5469aed47d19e7908d19bd194493aThomas Graf{
646535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf	return route->rt_type;
64744d362409d5469aed47d19e7908d19bd194493aThomas Graf}
64844d362409d5469aed47d19e7908d19bd194493aThomas Graf
649535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Grafvoid rtnl_route_set_flags(struct rtnl_route *route, uint32_t flags)
65044d362409d5469aed47d19e7908d19bd194493aThomas Graf{
65144d362409d5469aed47d19e7908d19bd194493aThomas Graf	route->rt_flag_mask |= flags;
65244d362409d5469aed47d19e7908d19bd194493aThomas Graf	route->rt_flags |= flags;
65344d362409d5469aed47d19e7908d19bd194493aThomas Graf	route->ce_mask |= ROUTE_ATTR_FLAGS;
65444d362409d5469aed47d19e7908d19bd194493aThomas Graf}
65544d362409d5469aed47d19e7908d19bd194493aThomas Graf
656535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Grafvoid rtnl_route_unset_flags(struct rtnl_route *route, uint32_t flags)
65744d362409d5469aed47d19e7908d19bd194493aThomas Graf{
65844d362409d5469aed47d19e7908d19bd194493aThomas Graf	route->rt_flag_mask |= flags;
65944d362409d5469aed47d19e7908d19bd194493aThomas Graf	route->rt_flags &= ~flags;
66044d362409d5469aed47d19e7908d19bd194493aThomas Graf	route->ce_mask |= ROUTE_ATTR_FLAGS;
66144d362409d5469aed47d19e7908d19bd194493aThomas Graf}
66244d362409d5469aed47d19e7908d19bd194493aThomas Graf
663535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Grafuint32_t rtnl_route_get_flags(struct rtnl_route *route)
66444d362409d5469aed47d19e7908d19bd194493aThomas Graf{
66544d362409d5469aed47d19e7908d19bd194493aThomas Graf	return route->rt_flags;
66644d362409d5469aed47d19e7908d19bd194493aThomas Graf}
66744d362409d5469aed47d19e7908d19bd194493aThomas Graf
66844d362409d5469aed47d19e7908d19bd194493aThomas Grafint rtnl_route_set_metric(struct rtnl_route *route, int metric, uint32_t value)
66944d362409d5469aed47d19e7908d19bd194493aThomas Graf{
67044d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (metric > RTAX_MAX || metric < 1)
6718a3efffa5b3fde252675239914118664d36a2c24Thomas Graf		return -NLE_RANGE;
67244d362409d5469aed47d19e7908d19bd194493aThomas Graf
67344d362409d5469aed47d19e7908d19bd194493aThomas Graf	route->rt_metrics[metric - 1] = value;
674535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf
675535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf	if (!(route->rt_metrics_mask & (1 << (metric - 1)))) {
676535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf		route->rt_nmetrics++;
677535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf		route->rt_metrics_mask |= (1 << (metric - 1));
678535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf	}
679535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf
680535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf	route->ce_mask |= ROUTE_ATTR_METRICS;
68144d362409d5469aed47d19e7908d19bd194493aThomas Graf
68244d362409d5469aed47d19e7908d19bd194493aThomas Graf	return 0;
68344d362409d5469aed47d19e7908d19bd194493aThomas Graf}
68444d362409d5469aed47d19e7908d19bd194493aThomas Graf
68544d362409d5469aed47d19e7908d19bd194493aThomas Grafint rtnl_route_unset_metric(struct rtnl_route *route, int metric)
68644d362409d5469aed47d19e7908d19bd194493aThomas Graf{
68744d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (metric > RTAX_MAX || metric < 1)
6888a3efffa5b3fde252675239914118664d36a2c24Thomas Graf		return -NLE_RANGE;
68944d362409d5469aed47d19e7908d19bd194493aThomas Graf
690535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf	if (route->rt_metrics_mask & (1 << (metric - 1))) {
691535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf		route->rt_nmetrics--;
692535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf		route->rt_metrics_mask &= ~(1 << (metric - 1));
693535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf	}
69444d362409d5469aed47d19e7908d19bd194493aThomas Graf
69544d362409d5469aed47d19e7908d19bd194493aThomas Graf	return 0;
69644d362409d5469aed47d19e7908d19bd194493aThomas Graf}
69744d362409d5469aed47d19e7908d19bd194493aThomas Graf
698535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Grafint rtnl_route_get_metric(struct rtnl_route *route, int metric, uint32_t *value)
69944d362409d5469aed47d19e7908d19bd194493aThomas Graf{
70044d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (metric > RTAX_MAX || metric < 1)
7018a3efffa5b3fde252675239914118664d36a2c24Thomas Graf		return -NLE_RANGE;
70244d362409d5469aed47d19e7908d19bd194493aThomas Graf
70344d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (!(route->rt_metrics_mask & (1 << (metric - 1))))
7048a3efffa5b3fde252675239914118664d36a2c24Thomas Graf		return -NLE_OBJ_NOTFOUND;
705535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf
706535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf	if (value)
707535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf		*value = route->rt_metrics[metric - 1];
70844d362409d5469aed47d19e7908d19bd194493aThomas Graf
709535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf	return 0;
71044d362409d5469aed47d19e7908d19bd194493aThomas Graf}
71144d362409d5469aed47d19e7908d19bd194493aThomas Graf
71244d362409d5469aed47d19e7908d19bd194493aThomas Grafint rtnl_route_set_pref_src(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)
7168a3efffa5b3fde252675239914118664d36a2c24Thomas Graf			return -NLE_AF_MISMATCH;
71744d362409d5469aed47d19e7908d19bd194493aThomas Graf	} else
71844d362409d5469aed47d19e7908d19bd194493aThomas Graf		route->rt_family = addr->a_family;
71944d362409d5469aed47d19e7908d19bd194493aThomas Graf
72044d362409d5469aed47d19e7908d19bd194493aThomas Graf	if (route->rt_pref_src)
72144d362409d5469aed47d19e7908d19bd194493aThomas Graf		nl_addr_put(route->rt_pref_src);
72244d362409d5469aed47d19e7908d19bd194493aThomas Graf
72344d362409d5469aed47d19e7908d19bd194493aThomas Graf	nl_addr_get(addr);
72444d362409d5469aed47d19e7908d19bd194493aThomas Graf	route->rt_pref_src = addr;
72544d362409d5469aed47d19e7908d19bd194493aThomas Graf	route->ce_mask |= (ROUTE_ATTR_PREF_SRC | ROUTE_ATTR_FAMILY);
72644d362409d5469aed47d19e7908d19bd194493aThomas Graf
72744d362409d5469aed47d19e7908d19bd194493aThomas Graf	return 0;
72844d362409d5469aed47d19e7908d19bd194493aThomas Graf}
72944d362409d5469aed47d19e7908d19bd194493aThomas Graf
73044d362409d5469aed47d19e7908d19bd194493aThomas Grafstruct nl_addr *rtnl_route_get_pref_src(struct rtnl_route *route)
73144d362409d5469aed47d19e7908d19bd194493aThomas Graf{
73244d362409d5469aed47d19e7908d19bd194493aThomas Graf	return route->rt_pref_src;
73344d362409d5469aed47d19e7908d19bd194493aThomas Graf}
73444d362409d5469aed47d19e7908d19bd194493aThomas Graf
735535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Grafvoid rtnl_route_set_iif(struct rtnl_route *route, int ifindex)
73644d362409d5469aed47d19e7908d19bd194493aThomas Graf{
737535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf	route->rt_iif = ifindex;
73844d362409d5469aed47d19e7908d19bd194493aThomas Graf	route->ce_mask |= ROUTE_ATTR_IIF;
73944d362409d5469aed47d19e7908d19bd194493aThomas Graf}
74044d362409d5469aed47d19e7908d19bd194493aThomas Graf
741535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Grafint rtnl_route_get_iif(struct rtnl_route *route)
74244d362409d5469aed47d19e7908d19bd194493aThomas Graf{
743535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf	return route->rt_iif;
74444d362409d5469aed47d19e7908d19bd194493aThomas Graf}
74544d362409d5469aed47d19e7908d19bd194493aThomas Graf
74644d362409d5469aed47d19e7908d19bd194493aThomas Grafvoid rtnl_route_add_nexthop(struct rtnl_route *route, struct rtnl_nexthop *nh)
74744d362409d5469aed47d19e7908d19bd194493aThomas Graf{
74844d362409d5469aed47d19e7908d19bd194493aThomas Graf	nl_list_add_tail(&nh->rtnh_list, &route->rt_nexthops);
749535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf	route->rt_nr_nh++;
75044d362409d5469aed47d19e7908d19bd194493aThomas Graf	route->ce_mask |= ROUTE_ATTR_MULTIPATH;
75144d362409d5469aed47d19e7908d19bd194493aThomas Graf}
75244d362409d5469aed47d19e7908d19bd194493aThomas Graf
753535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Grafvoid rtnl_route_remove_nexthop(struct rtnl_route *route, struct rtnl_nexthop *nh)
75444d362409d5469aed47d19e7908d19bd194493aThomas Graf{
755535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf	route->rt_nr_nh--;
75644d362409d5469aed47d19e7908d19bd194493aThomas Graf	nl_list_del(&nh->rtnh_list);
75744d362409d5469aed47d19e7908d19bd194493aThomas Graf}
75844d362409d5469aed47d19e7908d19bd194493aThomas Graf
75944d362409d5469aed47d19e7908d19bd194493aThomas Grafstruct nl_list_head *rtnl_route_get_nexthops(struct rtnl_route *route)
76044d362409d5469aed47d19e7908d19bd194493aThomas Graf{
76144d362409d5469aed47d19e7908d19bd194493aThomas Graf	return &route->rt_nexthops;
76244d362409d5469aed47d19e7908d19bd194493aThomas Graf}
76344d362409d5469aed47d19e7908d19bd194493aThomas Graf
764535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Grafint rtnl_route_get_nnexthops(struct rtnl_route *route)
76544d362409d5469aed47d19e7908d19bd194493aThomas Graf{
766535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf	return route->rt_nr_nh;
76744d362409d5469aed47d19e7908d19bd194493aThomas Graf}
76844d362409d5469aed47d19e7908d19bd194493aThomas Graf
769cc9c6d63848400b77906a4a9df0be826dfc21b72Ben Gamsavoid rtnl_route_foreach_nexthop(struct rtnl_route *r,
770cc9c6d63848400b77906a4a9df0be826dfc21b72Ben Gamsa                                void (*cb)(struct rtnl_nexthop *, void *),
771cc9c6d63848400b77906a4a9df0be826dfc21b72Ben Gamsa                                void *arg)
772cc9c6d63848400b77906a4a9df0be826dfc21b72Ben Gamsa{
773cc9c6d63848400b77906a4a9df0be826dfc21b72Ben Gamsa	struct rtnl_nexthop *nh;
774cc9c6d63848400b77906a4a9df0be826dfc21b72Ben Gamsa
775cc9c6d63848400b77906a4a9df0be826dfc21b72Ben Gamsa	if (r->ce_mask & ROUTE_ATTR_MULTIPATH) {
776cc9c6d63848400b77906a4a9df0be826dfc21b72Ben Gamsa		nl_list_for_each_entry(nh, &r->rt_nexthops, rtnh_list) {
777cc9c6d63848400b77906a4a9df0be826dfc21b72Ben Gamsa                        cb(nh, arg);
778cc9c6d63848400b77906a4a9df0be826dfc21b72Ben Gamsa		}
779cc9c6d63848400b77906a4a9df0be826dfc21b72Ben Gamsa	}
780cc9c6d63848400b77906a4a9df0be826dfc21b72Ben Gamsa}
781cc9c6d63848400b77906a4a9df0be826dfc21b72Ben Gamsa
782cc9c6d63848400b77906a4a9df0be826dfc21b72Ben Gamsastruct rtnl_nexthop *rtnl_route_nexthop_n(struct rtnl_route *r, int n)
783cc9c6d63848400b77906a4a9df0be826dfc21b72Ben Gamsa{
784cc9c6d63848400b77906a4a9df0be826dfc21b72Ben Gamsa	struct rtnl_nexthop *nh;
785cc9c6d63848400b77906a4a9df0be826dfc21b72Ben Gamsa	int i;
786cc9c6d63848400b77906a4a9df0be826dfc21b72Ben Gamsa
787cc9c6d63848400b77906a4a9df0be826dfc21b72Ben Gamsa	if (r->ce_mask & ROUTE_ATTR_MULTIPATH && r->rt_nr_nh > n) {
788cc9c6d63848400b77906a4a9df0be826dfc21b72Ben Gamsa		i = 0;
789cc9c6d63848400b77906a4a9df0be826dfc21b72Ben Gamsa		nl_list_for_each_entry(nh, &r->rt_nexthops, rtnh_list) {
790cc9c6d63848400b77906a4a9df0be826dfc21b72Ben Gamsa                        if (i == n) return nh;
791cc9c6d63848400b77906a4a9df0be826dfc21b72Ben Gamsa			i++;
792cc9c6d63848400b77906a4a9df0be826dfc21b72Ben Gamsa		}
793cc9c6d63848400b77906a4a9df0be826dfc21b72Ben Gamsa	}
794cc9c6d63848400b77906a4a9df0be826dfc21b72Ben Gamsa        return NULL;
795cc9c6d63848400b77906a4a9df0be826dfc21b72Ben Gamsa}
796cc9c6d63848400b77906a4a9df0be826dfc21b72Ben Gamsa
797535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf/** @} */
798535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf
799535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf/**
800535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf * @name Utilities
801535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf * @{
802535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf */
803535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf
804535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf/**
805535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf * Guess scope of a route object.
806535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf * @arg route		Route object.
807535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf *
808535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf * Guesses the scope of a route object, based on the following rules:
809535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf * @code
810535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf *   1) Local route -> local scope
811535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf *   2) At least one nexthop not directly connected -> universe scope
812535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf *   3) All others -> link scope
813535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf * @endcode
814535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf *
815535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf * @return Scope value.
816535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf */
817535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Grafint rtnl_route_guess_scope(struct rtnl_route *route)
81844d362409d5469aed47d19e7908d19bd194493aThomas Graf{
819535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf	if (route->rt_type == RTN_LOCAL)
820535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf		return RT_SCOPE_HOST;
821535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf
822535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf	if (!nl_list_empty(&route->rt_nexthops)) {
823535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf		struct rtnl_nexthop *nh;
824535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf
825535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf		/*
826535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf		 * Use scope uiniverse if there is at least one nexthop which
827535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf		 * is not directly connected
828535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf		 */
829535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf		nl_list_for_each_entry(nh, &route->rt_nexthops, rtnh_list) {
830535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf			if (nh->rtnh_gateway)
831535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf				return RT_SCOPE_UNIVERSE;
832535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf		}
833535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf	}
834535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf
835535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf	return RT_SCOPE_LINK;
83644d362409d5469aed47d19e7908d19bd194493aThomas Graf}
83744d362409d5469aed47d19e7908d19bd194493aThomas Graf
838535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf/** @} */
839535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf
840535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Grafstatic struct nla_policy route_policy[RTA_MAX+1] = {
841535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf	[RTA_IIF]	= { .type = NLA_U32 },
842535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf	[RTA_OIF]	= { .type = NLA_U32 },
843535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf	[RTA_PRIORITY]	= { .type = NLA_U32 },
844535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf	[RTA_FLOW]	= { .type = NLA_U32 },
845535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf	[RTA_CACHEINFO]	= { .minlen = sizeof(struct rta_cacheinfo) },
846535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf	[RTA_METRICS]	= { .type = NLA_NESTED },
847535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf	[RTA_MULTIPATH]	= { .type = NLA_NESTED },
848535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf};
849535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf
850eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Grafstatic int parse_multipath(struct rtnl_route *route, struct nlattr *attr)
851eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf{
852eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf	struct rtnl_nexthop *nh = NULL;
853eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf	struct rtnexthop *rtnh = nla_data(attr);
854eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf	size_t tlen = nla_len(attr);
855eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf	int err;
856eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf
857eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf	while (tlen >= sizeof(*rtnh) && tlen >= rtnh->rtnh_len) {
858eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf		nh = rtnl_route_nh_alloc();
859eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf		if (!nh)
860eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf			return -NLE_NOMEM;
861eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf
862eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf		rtnl_route_nh_set_weight(nh, rtnh->rtnh_hops);
863eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf		rtnl_route_nh_set_ifindex(nh, rtnh->rtnh_ifindex);
864eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf		rtnl_route_nh_set_flags(nh, rtnh->rtnh_flags);
865eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf
866eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf		if (rtnh->rtnh_len > sizeof(*rtnh)) {
867eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf			struct nlattr *ntb[RTA_MAX + 1];
868eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf
869eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf			err = nla_parse(ntb, RTA_MAX, (struct nlattr *)
870eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf					RTNH_DATA(rtnh),
871eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf					rtnh->rtnh_len - sizeof(*rtnh),
872eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf					route_policy);
873eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf			if (err < 0)
874eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf				goto errout;
875eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf
876eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf			if (ntb[RTA_GATEWAY]) {
877eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf				struct nl_addr *addr;
878eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf
879eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf				addr = nl_addr_alloc_attr(ntb[RTA_GATEWAY],
880eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf							  route->rt_family);
881eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf				if (!addr) {
882eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf					err = -NLE_NOMEM;
883eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf					goto errout;
884eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf				}
885eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf
886eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf				rtnl_route_nh_set_gateway(nh, addr);
887eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf				nl_addr_put(addr);
888eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf			}
889eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf
890eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf			if (ntb[RTA_FLOW]) {
891eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf				uint32_t realms;
892eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf
893eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf				realms = nla_get_u32(ntb[RTA_FLOW]);
894eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf				rtnl_route_nh_set_realms(nh, realms);
895eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf			}
896eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf		}
897eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf
898eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf		rtnl_route_add_nexthop(route, nh);
899eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf		tlen -= RTNH_ALIGN(rtnh->rtnh_len);
900eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf		rtnh = RTNH_NEXT(rtnh);
901eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf	}
902eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf
903eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf	err = 0;
904eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graferrout:
905eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf	if (err && nh)
906eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf		rtnl_route_nh_free(nh);
907eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf
908eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf	return err;
909eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf}
910eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf
9118a3efffa5b3fde252675239914118664d36a2c24Thomas Grafint rtnl_route_parse(struct nlmsghdr *nlh, struct rtnl_route **result)
91244d362409d5469aed47d19e7908d19bd194493aThomas Graf{
913535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf	struct rtmsg *rtm;
914535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf	struct rtnl_route *route;
915535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf	struct nlattr *tb[RTA_MAX + 1];
916535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf	struct nl_addr *src = NULL, *dst = NULL, *addr;
917535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf	struct rtnl_nexthop *old_nh = NULL;
918eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf	int err, family;
919535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf
920535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf	route = rtnl_route_alloc();
921535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf	if (!route) {
9228a3efffa5b3fde252675239914118664d36a2c24Thomas Graf		err = -NLE_NOMEM;
923535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf		goto errout;
924535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf	}
925535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf
926535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf	route->ce_msgtype = nlh->nlmsg_type;
927535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf
928535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf	err = nlmsg_parse(nlh, sizeof(struct rtmsg), tb, RTA_MAX, route_policy);
929535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf	if (err < 0)
930535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf		goto errout;
931535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf
932535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf	rtm = nlmsg_data(nlh);
933eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf	route->rt_family = family = rtm->rtm_family;
934535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf	route->rt_tos = rtm->rtm_tos;
935535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf	route->rt_table = rtm->rtm_table;
936535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf	route->rt_type = rtm->rtm_type;
937535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf	route->rt_scope = rtm->rtm_scope;
938535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf	route->rt_protocol = rtm->rtm_protocol;
939535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf	route->rt_flags = rtm->rtm_flags;
940535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf
941535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf	route->ce_mask |= ROUTE_ATTR_FAMILY | ROUTE_ATTR_TOS |
942535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf			  ROUTE_ATTR_TABLE | ROUTE_ATTR_TYPE |
943535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf			  ROUTE_ATTR_SCOPE | ROUTE_ATTR_PROTOCOL |
944535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf			  ROUTE_ATTR_FLAGS;
945535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf
946535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf	if (tb[RTA_DST]) {
947eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf		if (!(dst = nl_addr_alloc_attr(tb[RTA_DST], family)))
948eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf			goto errout_nomem;
949535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf	} else {
950eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf		if (!(dst = nl_addr_alloc(0)))
951eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf			goto errout_nomem;
952535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf		nl_addr_set_family(dst, rtm->rtm_family);
953535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf	}
954535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf
955535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf	nl_addr_set_prefixlen(dst, rtm->rtm_dst_len);
956535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf	err = rtnl_route_set_dst(route, dst);
957535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf	if (err < 0)
958535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf		goto errout;
959535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf
960535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf	nl_addr_put(dst);
961535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf
962535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf	if (tb[RTA_SRC]) {
963eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf		if (!(src = nl_addr_alloc_attr(tb[RTA_SRC], family)))
964eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf			goto errout_nomem;
965535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf	} else if (rtm->rtm_src_len)
966eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf		if (!(src = nl_addr_alloc(0)))
967eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf			goto errout_nomem;
968535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf
969535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf	if (src) {
970535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf		nl_addr_set_prefixlen(src, rtm->rtm_src_len);
971535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf		rtnl_route_set_src(route, src);
972535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf		nl_addr_put(src);
973535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf	}
974535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf
975535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf	if (tb[RTA_IIF])
976535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf		rtnl_route_set_iif(route, nla_get_u32(tb[RTA_IIF]));
977535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf
978535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf	if (tb[RTA_PRIORITY])
979535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf		rtnl_route_set_priority(route, nla_get_u32(tb[RTA_PRIORITY]));
980535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf
981535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf	if (tb[RTA_PREFSRC]) {
982eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf		if (!(addr = nl_addr_alloc_attr(tb[RTA_PREFSRC], family)))
983eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf			goto errout_nomem;
984535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf		rtnl_route_set_pref_src(route, addr);
985535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf		nl_addr_put(addr);
986535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf	}
987535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf
988535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf	if (tb[RTA_METRICS]) {
989535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf		struct nlattr *mtb[RTAX_MAX + 1];
990535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf		int i;
991535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf
992535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf		err = nla_parse_nested(mtb, RTAX_MAX, tb[RTA_METRICS], NULL);
993535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf		if (err < 0)
994535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf			goto errout;
995535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf
996535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf		for (i = 1; i <= RTAX_MAX; i++) {
997535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf			if (mtb[i] && nla_len(mtb[i]) >= sizeof(uint32_t)) {
998535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf				uint32_t m = nla_get_u32(mtb[i]);
999535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf				if (rtnl_route_set_metric(route, i, m) < 0)
1000535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf					goto errout;
1001535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf			}
1002535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf		}
1003535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf	}
1004535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf
1005eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf	if (tb[RTA_MULTIPATH])
1006eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf		if ((err = parse_multipath(route, tb[RTA_MULTIPATH])) < 0)
1007eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf			goto errout;
1008535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf
1009535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf	if (tb[RTA_CACHEINFO]) {
1010535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf		nla_memcpy(&route->rt_cacheinfo, tb[RTA_CACHEINFO],
1011535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf			   sizeof(route->rt_cacheinfo));
1012535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf		route->ce_mask |= ROUTE_ATTR_CACHEINFO;
1013535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf	}
1014535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf
1015535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf	if (tb[RTA_OIF]) {
1016535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf		if (!old_nh && !(old_nh = rtnl_route_nh_alloc()))
1017535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf			goto errout;
1018535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf
1019535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf		rtnl_route_nh_set_ifindex(old_nh, nla_get_u32(tb[RTA_OIF]));
1020535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf	}
1021535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf
1022535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf	if (tb[RTA_GATEWAY]) {
1023535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf		if (!old_nh && !(old_nh = rtnl_route_nh_alloc()))
1024535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf			goto errout;
1025535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf
1026eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf		if (!(addr = nl_addr_alloc_attr(tb[RTA_GATEWAY], family)))
1027eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf			goto errout_nomem;
1028535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf
1029535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf		rtnl_route_nh_set_gateway(old_nh, addr);
1030535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf		nl_addr_put(addr);
1031535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf	}
1032535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf
1033535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf	if (tb[RTA_FLOW]) {
1034535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf		if (!old_nh && !(old_nh = rtnl_route_nh_alloc()))
1035535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf			goto errout;
1036535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf
1037535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf		rtnl_route_nh_set_realms(old_nh, nla_get_u32(tb[RTA_FLOW]));
1038535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf	}
1039535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf
1040535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf	if (old_nh) {
1041535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf		if (route->rt_nr_nh == 0) {
1042535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf			/* If no nexthops have been provided via RTA_MULTIPATH
1043535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf			 * we add it as regular nexthop to maintain backwards
1044535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf			 * compatibility */
1045535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf			rtnl_route_add_nexthop(route, old_nh);
1046535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf		} else {
1047535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf			/* Kernel supports new style nexthop configuration,
1048535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf			 * verify that it is a duplicate and discard nexthop. */
1049535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf			struct rtnl_nexthop *first;
1050535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf
1051535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf			first = nl_list_first_entry(&route->rt_nexthops,
1052535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf						    struct rtnl_nexthop,
1053535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf						    rtnh_list);
1054535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf			if (!first)
1055535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf				BUG();
1056535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf
1057535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf			if (rtnl_route_nh_compare(old_nh, first,
1058535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf						  old_nh->ce_mask, 0)) {
10598a3efffa5b3fde252675239914118664d36a2c24Thomas Graf				err = -NLE_INVAL;
1060535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf				goto errout;
1061535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf			}
1062535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf
1063535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf			rtnl_route_nh_free(old_nh);
1064535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf		}
1065535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf	}
1066535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf
10678a3efffa5b3fde252675239914118664d36a2c24Thomas Graf	*result = route;
10688a3efffa5b3fde252675239914118664d36a2c24Thomas Graf	return 0;
1069535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf
1070535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graferrout:
1071535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf	rtnl_route_put(route);
10728a3efffa5b3fde252675239914118664d36a2c24Thomas Graf	return err;
1073eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf
1074eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graferrout_nomem:
1075eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf	err = -NLE_NOMEM;
1076eed2afaab7aa72fae393a395a8879b91a922ff5eThomas Graf	goto errout;
107744d362409d5469aed47d19e7908d19bd194493aThomas Graf}
107844d362409d5469aed47d19e7908d19bd194493aThomas Graf
1079535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Grafint rtnl_route_build_msg(struct nl_msg *msg, struct rtnl_route *route)
1080535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf{
1081535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf	int i;
1082535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf	struct nlattr *metrics;
1083535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf	struct rtmsg rtmsg = {
1084535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf		.rtm_family = route->rt_family,
1085535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf		.rtm_tos = route->rt_tos,
1086535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf		.rtm_table = route->rt_table,
1087535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf		.rtm_protocol = route->rt_protocol,
1088535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf		.rtm_scope = route->rt_scope,
1089535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf		.rtm_type = route->rt_type,
1090535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf		.rtm_flags = route->rt_flags,
1091535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf	};
1092535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf
1093535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf	if (route->rt_dst == NULL)
10948a3efffa5b3fde252675239914118664d36a2c24Thomas Graf		return -NLE_MISSING_ATTR;
1095535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf
1096535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf	rtmsg.rtm_dst_len = nl_addr_get_prefixlen(route->rt_dst);
1097535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf	if (route->rt_src)
1098535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf		rtmsg.rtm_src_len = nl_addr_get_prefixlen(route->rt_src);
109944d362409d5469aed47d19e7908d19bd194493aThomas Graf
1100535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf
1101535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf	if (rtmsg.rtm_scope == RT_SCOPE_NOWHERE)
1102535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf		rtmsg.rtm_scope = rtnl_route_guess_scope(route);
1103535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf
1104535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf	if (nlmsg_append(msg, &rtmsg, sizeof(rtmsg), NLMSG_ALIGNTO) < 0)
1105535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf		goto nla_put_failure;
1106535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf
1107535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf	/* Additional table attribute replacing the 8bit in the header, was
1108535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf	 * required to allow more than 256 tables. */
1109535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf	NLA_PUT_U32(msg, RTA_TABLE, route->rt_table);
1110535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf
11112b3fabab9ef2445ab1c48de0fed82514e4eb32dcDavid Lamparter	if (nl_addr_get_len(route->rt_dst))
11122b3fabab9ef2445ab1c48de0fed82514e4eb32dcDavid Lamparter		NLA_PUT_ADDR(msg, RTA_DST, route->rt_dst);
1113535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf	NLA_PUT_U32(msg, RTA_PRIORITY, route->rt_prio);
1114535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf
1115535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf	if (route->ce_mask & ROUTE_ATTR_SRC)
1116535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf		NLA_PUT_ADDR(msg, RTA_SRC, route->rt_src);
1117535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf
1118535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf	if (route->ce_mask & ROUTE_ATTR_PREF_SRC)
1119535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf		NLA_PUT_ADDR(msg, RTA_PREFSRC, route->rt_pref_src);
1120535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf
1121535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf	if (route->ce_mask & ROUTE_ATTR_IIF)
1122535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf		NLA_PUT_U32(msg, RTA_IIF, route->rt_iif);
1123535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf
1124535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf	if (route->rt_nmetrics > 0) {
1125535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf		uint32_t val;
1126535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf
1127535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf		metrics = nla_nest_start(msg, RTA_METRICS);
1128535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf		if (metrics == NULL)
1129535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf			goto nla_put_failure;
1130535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf
1131535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf		for (i = 1; i <= RTAX_MAX; i++) {
1132535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf			if (!rtnl_route_get_metric(route, i, &val))
1133535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf				NLA_PUT_U32(msg, i, val);
1134535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf		}
1135535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf
1136535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf		nla_nest_end(msg, metrics);
1137535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf	}
1138535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf
1139535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf	if (rtnl_route_get_nnexthops(route) > 0) {
1140535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf		struct nlattr *multipath;
1141535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf		struct rtnl_nexthop *nh;
1142535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf
1143535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf		if (!(multipath = nla_nest_start(msg, RTA_MULTIPATH)))
1144535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf			goto nla_put_failure;
1145535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf
1146535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf		nl_list_for_each_entry(nh, &route->rt_nexthops, rtnh_list) {
1147535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf			struct rtnexthop *rtnh;
1148535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf
1149535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf			rtnh = nlmsg_reserve(msg, sizeof(*rtnh), NLMSG_ALIGNTO);
1150535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf			if (!rtnh)
1151535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf				goto nla_put_failure;
1152535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf
1153535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf			rtnh->rtnh_flags = nh->rtnh_flags;
1154535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf			rtnh->rtnh_hops = nh->rtnh_weight;
1155535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf			rtnh->rtnh_ifindex = nh->rtnh_ifindex;
1156535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf
1157535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf			if (nh->rtnh_gateway)
1158535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf				NLA_PUT_ADDR(msg, RTA_GATEWAY,
1159535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf					     nh->rtnh_gateway);
1160535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf
1161535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf			if (nh->rtnh_realms)
1162535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf				NLA_PUT_U32(msg, RTA_FLOW, nh->rtnh_realms);
1163535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf
1164535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf			rtnh->rtnh_len = nlmsg_tail(msg->nm_nlh) -
1165535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf						(void *) rtnh;
1166535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf		}
1167535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf
1168535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf		nla_nest_end(msg, multipath);
1169535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf	}
1170535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf
1171535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf	return 0;
1172535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf
1173535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Grafnla_put_failure:
11748a3efffa5b3fde252675239914118664d36a2c24Thomas Graf	return -NLE_MSGSIZE;
1175535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf}
1176535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf
1177535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf/** @cond SKIP */
117844d362409d5469aed47d19e7908d19bd194493aThomas Grafstruct nl_object_ops route_obj_ops = {
117944d362409d5469aed47d19e7908d19bd194493aThomas Graf	.oo_name		= "route/route",
118044d362409d5469aed47d19e7908d19bd194493aThomas Graf	.oo_size		= sizeof(struct rtnl_route),
118144d362409d5469aed47d19e7908d19bd194493aThomas Graf	.oo_constructor		= route_constructor,
118244d362409d5469aed47d19e7908d19bd194493aThomas Graf	.oo_free_data		= route_free_data,
118344d362409d5469aed47d19e7908d19bd194493aThomas Graf	.oo_clone		= route_clone,
1184d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Graf	.oo_dump = {
1185d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Graf	    [NL_DUMP_LINE]	= route_dump_line,
1186d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Graf	    [NL_DUMP_DETAILS]	= route_dump_details,
1187d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Graf	    [NL_DUMP_STATS]	= route_dump_stats,
1188d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Graf	    [NL_DUMP_ENV]	= route_dump_env,
1189d84430702496f617c01c5e2d27d0e82e02390bb7Thomas Graf	},
119044d362409d5469aed47d19e7908d19bd194493aThomas Graf	.oo_compare		= route_compare,
119144d362409d5469aed47d19e7908d19bd194493aThomas Graf	.oo_attrs2str		= route_attrs2str,
119244d362409d5469aed47d19e7908d19bd194493aThomas Graf	.oo_id_attrs		= (ROUTE_ATTR_FAMILY | ROUTE_ATTR_TOS |
119344d362409d5469aed47d19e7908d19bd194493aThomas Graf				   ROUTE_ATTR_TABLE | ROUTE_ATTR_DST),
119444d362409d5469aed47d19e7908d19bd194493aThomas Graf};
1195535e83162249ed6274ba46bc72d8cc683ba20e17Thomas Graf/** @endcond */
119644d362409d5469aed47d19e7908d19bd194493aThomas Graf
119744d362409d5469aed47d19e7908d19bd194493aThomas Graf/** @} */
1198