xref: /aosp_15_r20/external/libnl/lib/route/route_obj.c (revision 4dc78e53d49367fa8e61b07018507c90983a077d)
1*4dc78e53SAndroid Build Coastguard Worker /* SPDX-License-Identifier: LGPL-2.1-only */
2*4dc78e53SAndroid Build Coastguard Worker /*
3*4dc78e53SAndroid Build Coastguard Worker  * Copyright (c) 2003-2008 Thomas Graf <[email protected]>
4*4dc78e53SAndroid Build Coastguard Worker  */
5*4dc78e53SAndroid Build Coastguard Worker 
6*4dc78e53SAndroid Build Coastguard Worker /**
7*4dc78e53SAndroid Build Coastguard Worker  * @ingroup route
8*4dc78e53SAndroid Build Coastguard Worker  * @defgroup route_obj Route Object
9*4dc78e53SAndroid Build Coastguard Worker  *
10*4dc78e53SAndroid Build Coastguard Worker  * @par Attributes
11*4dc78e53SAndroid Build Coastguard Worker  * @code
12*4dc78e53SAndroid Build Coastguard Worker  * Name                                           Default
13*4dc78e53SAndroid Build Coastguard Worker  * -------------------------------------------------------------
14*4dc78e53SAndroid Build Coastguard Worker  * routing table                                  RT_TABLE_MAIN
15*4dc78e53SAndroid Build Coastguard Worker  * scope                                          RT_SCOPE_NOWHERE
16*4dc78e53SAndroid Build Coastguard Worker  * tos                                            0
17*4dc78e53SAndroid Build Coastguard Worker  * protocol                                       RTPROT_STATIC
18*4dc78e53SAndroid Build Coastguard Worker  * prio                                           0
19*4dc78e53SAndroid Build Coastguard Worker  * family                                         AF_UNSPEC
20*4dc78e53SAndroid Build Coastguard Worker  * type                                           RTN_UNICAST
21*4dc78e53SAndroid Build Coastguard Worker  * iif                                            NULL
22*4dc78e53SAndroid Build Coastguard Worker  * @endcode
23*4dc78e53SAndroid Build Coastguard Worker  *
24*4dc78e53SAndroid Build Coastguard Worker  * @{
25*4dc78e53SAndroid Build Coastguard Worker  */
26*4dc78e53SAndroid Build Coastguard Worker 
27*4dc78e53SAndroid Build Coastguard Worker #include "nl-default.h"
28*4dc78e53SAndroid Build Coastguard Worker 
29*4dc78e53SAndroid Build Coastguard Worker #include <linux/in_route.h>
30*4dc78e53SAndroid Build Coastguard Worker 
31*4dc78e53SAndroid Build Coastguard Worker #include <netlink/netlink.h>
32*4dc78e53SAndroid Build Coastguard Worker #include <netlink/cache.h>
33*4dc78e53SAndroid Build Coastguard Worker #include <netlink/utils.h>
34*4dc78e53SAndroid Build Coastguard Worker #include <netlink/data.h>
35*4dc78e53SAndroid Build Coastguard Worker #include <netlink/hashtable.h>
36*4dc78e53SAndroid Build Coastguard Worker #include <netlink/route/rtnl.h>
37*4dc78e53SAndroid Build Coastguard Worker #include <netlink/route/route.h>
38*4dc78e53SAndroid Build Coastguard Worker #include <netlink/route/link.h>
39*4dc78e53SAndroid Build Coastguard Worker #include <netlink/route/nexthop.h>
40*4dc78e53SAndroid Build Coastguard Worker 
41*4dc78e53SAndroid Build Coastguard Worker #include "nl-route.h"
42*4dc78e53SAndroid Build Coastguard Worker #include "nl-aux-route/nl-route.h"
43*4dc78e53SAndroid Build Coastguard Worker #include "nl-priv-dynamic-core/nl-core.h"
44*4dc78e53SAndroid Build Coastguard Worker #include "nexthop-encap.h"
45*4dc78e53SAndroid Build Coastguard Worker 
46*4dc78e53SAndroid Build Coastguard Worker /** @cond SKIP */
47*4dc78e53SAndroid Build Coastguard Worker struct rtnl_route {
48*4dc78e53SAndroid Build Coastguard Worker 	NLHDR_COMMON
49*4dc78e53SAndroid Build Coastguard Worker 
50*4dc78e53SAndroid Build Coastguard Worker 	uint8_t rt_family;
51*4dc78e53SAndroid Build Coastguard Worker 	uint8_t rt_tos;
52*4dc78e53SAndroid Build Coastguard Worker 	uint8_t rt_protocol;
53*4dc78e53SAndroid Build Coastguard Worker 	uint8_t rt_scope;
54*4dc78e53SAndroid Build Coastguard Worker 	uint8_t rt_type;
55*4dc78e53SAndroid Build Coastguard Worker 	uint8_t rt_nmetrics;
56*4dc78e53SAndroid Build Coastguard Worker 	uint8_t rt_ttl_propagate;
57*4dc78e53SAndroid Build Coastguard Worker 	uint32_t rt_flags;
58*4dc78e53SAndroid Build Coastguard Worker 	struct nl_addr *rt_dst;
59*4dc78e53SAndroid Build Coastguard Worker 	struct nl_addr *rt_src;
60*4dc78e53SAndroid Build Coastguard Worker 	uint32_t rt_table;
61*4dc78e53SAndroid Build Coastguard Worker 	uint32_t rt_iif;
62*4dc78e53SAndroid Build Coastguard Worker 	uint32_t rt_prio;
63*4dc78e53SAndroid Build Coastguard Worker 	uint32_t rt_metrics[RTAX_MAX];
64*4dc78e53SAndroid Build Coastguard Worker 	uint32_t rt_metrics_mask;
65*4dc78e53SAndroid Build Coastguard Worker 	uint32_t rt_nr_nh;
66*4dc78e53SAndroid Build Coastguard Worker 	uint32_t rt_nhid;
67*4dc78e53SAndroid Build Coastguard Worker 	struct nl_addr *rt_pref_src;
68*4dc78e53SAndroid Build Coastguard Worker 	struct nl_list_head rt_nexthops;
69*4dc78e53SAndroid Build Coastguard Worker 	struct rtnl_rtcacheinfo rt_cacheinfo;
70*4dc78e53SAndroid Build Coastguard Worker 	uint32_t rt_flag_mask;
71*4dc78e53SAndroid Build Coastguard Worker };
72*4dc78e53SAndroid Build Coastguard Worker 
73*4dc78e53SAndroid Build Coastguard Worker #define ROUTE_ATTR_FAMILY    0x000001
74*4dc78e53SAndroid Build Coastguard Worker #define ROUTE_ATTR_TOS       0x000002
75*4dc78e53SAndroid Build Coastguard Worker #define ROUTE_ATTR_TABLE     0x000004
76*4dc78e53SAndroid Build Coastguard Worker #define ROUTE_ATTR_PROTOCOL  0x000008
77*4dc78e53SAndroid Build Coastguard Worker #define ROUTE_ATTR_SCOPE     0x000010
78*4dc78e53SAndroid Build Coastguard Worker #define ROUTE_ATTR_TYPE      0x000020
79*4dc78e53SAndroid Build Coastguard Worker #define ROUTE_ATTR_FLAGS     0x000040
80*4dc78e53SAndroid Build Coastguard Worker #define ROUTE_ATTR_DST       0x000080
81*4dc78e53SAndroid Build Coastguard Worker #define ROUTE_ATTR_SRC       0x000100
82*4dc78e53SAndroid Build Coastguard Worker #define ROUTE_ATTR_IIF       0x000200
83*4dc78e53SAndroid Build Coastguard Worker #define ROUTE_ATTR_OIF       0x000400
84*4dc78e53SAndroid Build Coastguard Worker #define ROUTE_ATTR_GATEWAY   0x000800
85*4dc78e53SAndroid Build Coastguard Worker #define ROUTE_ATTR_PRIO      0x001000
86*4dc78e53SAndroid Build Coastguard Worker #define ROUTE_ATTR_PREF_SRC  0x002000
87*4dc78e53SAndroid Build Coastguard Worker #define ROUTE_ATTR_METRICS   0x004000
88*4dc78e53SAndroid Build Coastguard Worker #define ROUTE_ATTR_MULTIPATH 0x008000
89*4dc78e53SAndroid Build Coastguard Worker #define ROUTE_ATTR_REALMS    0x010000
90*4dc78e53SAndroid Build Coastguard Worker #define ROUTE_ATTR_CACHEINFO 0x020000
91*4dc78e53SAndroid Build Coastguard Worker #define ROUTE_ATTR_TTL_PROPAGATE 0x040000
92*4dc78e53SAndroid Build Coastguard Worker #define ROUTE_ATTR_NHID      0x080000
93*4dc78e53SAndroid Build Coastguard Worker /** @endcond */
94*4dc78e53SAndroid Build Coastguard Worker 
route_constructor(struct nl_object * c)95*4dc78e53SAndroid Build Coastguard Worker static void route_constructor(struct nl_object *c)
96*4dc78e53SAndroid Build Coastguard Worker {
97*4dc78e53SAndroid Build Coastguard Worker 	struct rtnl_route *r = (struct rtnl_route *) c;
98*4dc78e53SAndroid Build Coastguard Worker 
99*4dc78e53SAndroid Build Coastguard Worker 	r->rt_family = AF_UNSPEC;
100*4dc78e53SAndroid Build Coastguard Worker 	r->rt_scope = RT_SCOPE_NOWHERE;
101*4dc78e53SAndroid Build Coastguard Worker 	r->rt_table = RT_TABLE_MAIN;
102*4dc78e53SAndroid Build Coastguard Worker 	r->rt_protocol = RTPROT_STATIC;
103*4dc78e53SAndroid Build Coastguard Worker 	r->rt_type = RTN_UNICAST;
104*4dc78e53SAndroid Build Coastguard Worker 	r->rt_prio = 0;
105*4dc78e53SAndroid Build Coastguard Worker 
106*4dc78e53SAndroid Build Coastguard Worker 	nl_init_list_head(&r->rt_nexthops);
107*4dc78e53SAndroid Build Coastguard Worker }
108*4dc78e53SAndroid Build Coastguard Worker 
route_free_data(struct nl_object * c)109*4dc78e53SAndroid Build Coastguard Worker static void route_free_data(struct nl_object *c)
110*4dc78e53SAndroid Build Coastguard Worker {
111*4dc78e53SAndroid Build Coastguard Worker 	struct rtnl_route *r = (struct rtnl_route *) c;
112*4dc78e53SAndroid Build Coastguard Worker 	struct rtnl_nexthop *nh, *tmp;
113*4dc78e53SAndroid Build Coastguard Worker 
114*4dc78e53SAndroid Build Coastguard Worker 	if (r == NULL)
115*4dc78e53SAndroid Build Coastguard Worker 		return;
116*4dc78e53SAndroid Build Coastguard Worker 
117*4dc78e53SAndroid Build Coastguard Worker 	nl_addr_put(r->rt_dst);
118*4dc78e53SAndroid Build Coastguard Worker 	nl_addr_put(r->rt_src);
119*4dc78e53SAndroid Build Coastguard Worker 	nl_addr_put(r->rt_pref_src);
120*4dc78e53SAndroid Build Coastguard Worker 
121*4dc78e53SAndroid Build Coastguard Worker 	nl_list_for_each_entry_safe(nh, tmp, &r->rt_nexthops, rtnh_list) {
122*4dc78e53SAndroid Build Coastguard Worker 		rtnl_route_remove_nexthop(r, nh);
123*4dc78e53SAndroid Build Coastguard Worker 		rtnl_route_nh_free(nh);
124*4dc78e53SAndroid Build Coastguard Worker 	}
125*4dc78e53SAndroid Build Coastguard Worker }
126*4dc78e53SAndroid Build Coastguard Worker 
route_clone(struct nl_object * _dst,struct nl_object * _src)127*4dc78e53SAndroid Build Coastguard Worker static int route_clone(struct nl_object *_dst, struct nl_object *_src)
128*4dc78e53SAndroid Build Coastguard Worker {
129*4dc78e53SAndroid Build Coastguard Worker 	struct rtnl_route *dst = (struct rtnl_route *) _dst;
130*4dc78e53SAndroid Build Coastguard Worker 	struct rtnl_route *src = (struct rtnl_route *) _src;
131*4dc78e53SAndroid Build Coastguard Worker 	struct rtnl_nexthop *nh, *new;
132*4dc78e53SAndroid Build Coastguard Worker 
133*4dc78e53SAndroid Build Coastguard Worker 	dst->rt_dst = NULL;
134*4dc78e53SAndroid Build Coastguard Worker 	dst->rt_src = NULL;
135*4dc78e53SAndroid Build Coastguard Worker 	dst->rt_pref_src = NULL;
136*4dc78e53SAndroid Build Coastguard Worker 	nl_init_list_head(&dst->rt_nexthops);
137*4dc78e53SAndroid Build Coastguard Worker 	dst->rt_nr_nh = 0;
138*4dc78e53SAndroid Build Coastguard Worker 
139*4dc78e53SAndroid Build Coastguard Worker 	if (src->rt_dst) {
140*4dc78e53SAndroid Build Coastguard Worker 		if (!(dst->rt_dst = nl_addr_clone(src->rt_dst)))
141*4dc78e53SAndroid Build Coastguard Worker 			return -NLE_NOMEM;
142*4dc78e53SAndroid Build Coastguard Worker 	}
143*4dc78e53SAndroid Build Coastguard Worker 
144*4dc78e53SAndroid Build Coastguard Worker 	if (src->rt_src) {
145*4dc78e53SAndroid Build Coastguard Worker 		if (!(dst->rt_src = nl_addr_clone(src->rt_src)))
146*4dc78e53SAndroid Build Coastguard Worker 			return -NLE_NOMEM;
147*4dc78e53SAndroid Build Coastguard Worker 	}
148*4dc78e53SAndroid Build Coastguard Worker 
149*4dc78e53SAndroid Build Coastguard Worker 	if (src->rt_pref_src) {
150*4dc78e53SAndroid Build Coastguard Worker 		if (!(dst->rt_pref_src = nl_addr_clone(src->rt_pref_src)))
151*4dc78e53SAndroid Build Coastguard Worker 			return -NLE_NOMEM;
152*4dc78e53SAndroid Build Coastguard Worker 	}
153*4dc78e53SAndroid Build Coastguard Worker 
154*4dc78e53SAndroid Build Coastguard Worker 	nl_list_for_each_entry(nh, &src->rt_nexthops, rtnh_list) {
155*4dc78e53SAndroid Build Coastguard Worker 		new = rtnl_route_nh_clone(nh);
156*4dc78e53SAndroid Build Coastguard Worker 		if (!new)
157*4dc78e53SAndroid Build Coastguard Worker 			return -NLE_NOMEM;
158*4dc78e53SAndroid Build Coastguard Worker 
159*4dc78e53SAndroid Build Coastguard Worker 		rtnl_route_add_nexthop(dst, new);
160*4dc78e53SAndroid Build Coastguard Worker 	}
161*4dc78e53SAndroid Build Coastguard Worker 
162*4dc78e53SAndroid Build Coastguard Worker 	return 0;
163*4dc78e53SAndroid Build Coastguard Worker }
164*4dc78e53SAndroid Build Coastguard Worker 
route_dump_line(struct nl_object * a,struct nl_dump_params * p)165*4dc78e53SAndroid Build Coastguard Worker static void route_dump_line(struct nl_object *a, struct nl_dump_params *p)
166*4dc78e53SAndroid Build Coastguard Worker {
167*4dc78e53SAndroid Build Coastguard Worker 	struct rtnl_route *r = (struct rtnl_route *) a;
168*4dc78e53SAndroid Build Coastguard Worker 	int cache = 0, flags;
169*4dc78e53SAndroid Build Coastguard Worker 	char buf[64];
170*4dc78e53SAndroid Build Coastguard Worker 
171*4dc78e53SAndroid Build Coastguard Worker 	if (r->rt_flags & RTM_F_CLONED)
172*4dc78e53SAndroid Build Coastguard Worker 		cache = 1;
173*4dc78e53SAndroid Build Coastguard Worker 
174*4dc78e53SAndroid Build Coastguard Worker 	nl_dump_line(p, "%s ", nl_af2str(r->rt_family, buf, sizeof(buf)));
175*4dc78e53SAndroid Build Coastguard Worker 
176*4dc78e53SAndroid Build Coastguard Worker 	if (cache)
177*4dc78e53SAndroid Build Coastguard Worker 		nl_dump(p, "cache ");
178*4dc78e53SAndroid Build Coastguard Worker 
179*4dc78e53SAndroid Build Coastguard Worker 	if (!(r->ce_mask & ROUTE_ATTR_DST) ||
180*4dc78e53SAndroid Build Coastguard Worker 	    (nl_addr_get_prefixlen(r->rt_dst) == 0 &&
181*4dc78e53SAndroid Build Coastguard Worker 	     nl_addr_get_len(r->rt_dst) > 0 && nl_addr_iszero(r->rt_dst)))
182*4dc78e53SAndroid Build Coastguard Worker 		nl_dump(p, "default ");
183*4dc78e53SAndroid Build Coastguard Worker 	else
184*4dc78e53SAndroid Build Coastguard Worker 		nl_dump(p, "%s ", nl_addr2str(r->rt_dst, buf, sizeof(buf)));
185*4dc78e53SAndroid Build Coastguard Worker 
186*4dc78e53SAndroid Build Coastguard Worker 	if (r->ce_mask & ROUTE_ATTR_TABLE && !cache)
187*4dc78e53SAndroid Build Coastguard Worker 		nl_dump(p, "table %s ",
188*4dc78e53SAndroid Build Coastguard Worker 			rtnl_route_table2str(r->rt_table, buf, sizeof(buf)));
189*4dc78e53SAndroid Build Coastguard Worker 
190*4dc78e53SAndroid Build Coastguard Worker 	if (r->ce_mask & ROUTE_ATTR_TYPE)
191*4dc78e53SAndroid Build Coastguard Worker 		nl_dump(p, "type %s ",
192*4dc78e53SAndroid Build Coastguard Worker 			nl_rtntype2str(r->rt_type, buf, sizeof(buf)));
193*4dc78e53SAndroid Build Coastguard Worker 
194*4dc78e53SAndroid Build Coastguard Worker 	if (r->ce_mask & ROUTE_ATTR_TOS && r->rt_tos != 0)
195*4dc78e53SAndroid Build Coastguard Worker 		nl_dump(p, "tos %#x ", r->rt_tos);
196*4dc78e53SAndroid Build Coastguard Worker 
197*4dc78e53SAndroid Build Coastguard Worker 	if (r->ce_mask & ROUTE_ATTR_NHID)
198*4dc78e53SAndroid Build Coastguard Worker 		nl_dump(p, "nhid %u ", r->rt_nhid);
199*4dc78e53SAndroid Build Coastguard Worker 
200*4dc78e53SAndroid Build Coastguard Worker 	if (r->ce_mask & ROUTE_ATTR_MULTIPATH) {
201*4dc78e53SAndroid Build Coastguard Worker 		struct rtnl_nexthop *nh;
202*4dc78e53SAndroid Build Coastguard Worker 
203*4dc78e53SAndroid Build Coastguard Worker 		nl_list_for_each_entry(nh, &r->rt_nexthops, rtnh_list) {
204*4dc78e53SAndroid Build Coastguard Worker 			p->dp_ivar = NH_DUMP_FROM_ONELINE;
205*4dc78e53SAndroid Build Coastguard Worker 			rtnl_route_nh_dump(nh, p);
206*4dc78e53SAndroid Build Coastguard Worker 		}
207*4dc78e53SAndroid Build Coastguard Worker 	}
208*4dc78e53SAndroid Build Coastguard Worker 
209*4dc78e53SAndroid Build Coastguard Worker 	flags = r->rt_flags & ~(RTM_F_CLONED);
210*4dc78e53SAndroid Build Coastguard Worker 	if (r->ce_mask & ROUTE_ATTR_FLAGS && flags) {
211*4dc78e53SAndroid Build Coastguard Worker 
212*4dc78e53SAndroid Build Coastguard Worker 		nl_dump(p, "<");
213*4dc78e53SAndroid Build Coastguard Worker 
214*4dc78e53SAndroid Build Coastguard Worker #define PRINT_FLAG(f) if (flags & RTNH_F_##f) { \
215*4dc78e53SAndroid Build Coastguard Worker 		flags &= ~RTNH_F_##f; nl_dump(p, #f "%s", flags ? "," : ""); }
216*4dc78e53SAndroid Build Coastguard Worker 		PRINT_FLAG(DEAD);
217*4dc78e53SAndroid Build Coastguard Worker 		PRINT_FLAG(ONLINK);
218*4dc78e53SAndroid Build Coastguard Worker 		PRINT_FLAG(PERVASIVE);
219*4dc78e53SAndroid Build Coastguard Worker #undef PRINT_FLAG
220*4dc78e53SAndroid Build Coastguard Worker 
221*4dc78e53SAndroid Build Coastguard Worker #define PRINT_FLAG(f) if (flags & RTM_F_##f) { \
222*4dc78e53SAndroid Build Coastguard Worker 		flags &= ~RTM_F_##f; nl_dump(p, #f "%s", flags ? "," : ""); }
223*4dc78e53SAndroid Build Coastguard Worker 		PRINT_FLAG(NOTIFY);
224*4dc78e53SAndroid Build Coastguard Worker 		PRINT_FLAG(EQUALIZE);
225*4dc78e53SAndroid Build Coastguard Worker 		PRINT_FLAG(PREFIX);
226*4dc78e53SAndroid Build Coastguard Worker #undef PRINT_FLAG
227*4dc78e53SAndroid Build Coastguard Worker 
228*4dc78e53SAndroid Build Coastguard Worker #define PRINT_FLAG(f) if (flags & RTCF_##f) { \
229*4dc78e53SAndroid Build Coastguard Worker 		flags &= ~RTCF_##f; nl_dump(p, #f "%s", flags ? "," : ""); }
230*4dc78e53SAndroid Build Coastguard Worker 		PRINT_FLAG(NOTIFY);
231*4dc78e53SAndroid Build Coastguard Worker 		PRINT_FLAG(REDIRECTED);
232*4dc78e53SAndroid Build Coastguard Worker 		PRINT_FLAG(DOREDIRECT);
233*4dc78e53SAndroid Build Coastguard Worker 		PRINT_FLAG(DIRECTSRC);
234*4dc78e53SAndroid Build Coastguard Worker 		PRINT_FLAG(DNAT);
235*4dc78e53SAndroid Build Coastguard Worker 		PRINT_FLAG(BROADCAST);
236*4dc78e53SAndroid Build Coastguard Worker 		PRINT_FLAG(MULTICAST);
237*4dc78e53SAndroid Build Coastguard Worker 		PRINT_FLAG(LOCAL);
238*4dc78e53SAndroid Build Coastguard Worker #undef PRINT_FLAG
239*4dc78e53SAndroid Build Coastguard Worker 
240*4dc78e53SAndroid Build Coastguard Worker 		nl_dump(p, ">");
241*4dc78e53SAndroid Build Coastguard Worker 	}
242*4dc78e53SAndroid Build Coastguard Worker 
243*4dc78e53SAndroid Build Coastguard Worker 	nl_dump(p, "\n");
244*4dc78e53SAndroid Build Coastguard Worker }
245*4dc78e53SAndroid Build Coastguard Worker 
route_dump_details(struct nl_object * a,struct nl_dump_params * p)246*4dc78e53SAndroid Build Coastguard Worker static void route_dump_details(struct nl_object *a, struct nl_dump_params *p)
247*4dc78e53SAndroid Build Coastguard Worker {
248*4dc78e53SAndroid Build Coastguard Worker 	_nl_auto_nl_cache struct nl_cache *link_cache = NULL;
249*4dc78e53SAndroid Build Coastguard Worker 	struct rtnl_route *r = (struct rtnl_route *) a;
250*4dc78e53SAndroid Build Coastguard Worker 	char buf[256];
251*4dc78e53SAndroid Build Coastguard Worker 	int i;
252*4dc78e53SAndroid Build Coastguard Worker 
253*4dc78e53SAndroid Build Coastguard Worker 	link_cache = nl_cache_mngt_require_safe("route/link");
254*4dc78e53SAndroid Build Coastguard Worker 
255*4dc78e53SAndroid Build Coastguard Worker 	route_dump_line(a, p);
256*4dc78e53SAndroid Build Coastguard Worker 	nl_dump_line(p, "    ");
257*4dc78e53SAndroid Build Coastguard Worker 
258*4dc78e53SAndroid Build Coastguard Worker 	if (r->ce_mask & ROUTE_ATTR_PREF_SRC)
259*4dc78e53SAndroid Build Coastguard Worker 		nl_dump(p, "preferred-src %s ",
260*4dc78e53SAndroid Build Coastguard Worker 			nl_addr2str(r->rt_pref_src, buf, sizeof(buf)));
261*4dc78e53SAndroid Build Coastguard Worker 
262*4dc78e53SAndroid Build Coastguard Worker 	if (r->ce_mask & ROUTE_ATTR_SCOPE && r->rt_scope != RT_SCOPE_NOWHERE)
263*4dc78e53SAndroid Build Coastguard Worker 		nl_dump(p, "scope %s ",
264*4dc78e53SAndroid Build Coastguard Worker 			rtnl_scope2str(r->rt_scope, buf, sizeof(buf)));
265*4dc78e53SAndroid Build Coastguard Worker 
266*4dc78e53SAndroid Build Coastguard Worker 	if (r->ce_mask & ROUTE_ATTR_PRIO)
267*4dc78e53SAndroid Build Coastguard Worker 		nl_dump(p, "priority %#x ", r->rt_prio);
268*4dc78e53SAndroid Build Coastguard Worker 
269*4dc78e53SAndroid Build Coastguard Worker 	if (r->ce_mask & ROUTE_ATTR_PROTOCOL)
270*4dc78e53SAndroid Build Coastguard Worker 		nl_dump(p, "protocol %s ",
271*4dc78e53SAndroid Build Coastguard Worker 			rtnl_route_proto2str(r->rt_protocol, buf, sizeof(buf)));
272*4dc78e53SAndroid Build Coastguard Worker 
273*4dc78e53SAndroid Build Coastguard Worker 	if (r->ce_mask & ROUTE_ATTR_IIF) {
274*4dc78e53SAndroid Build Coastguard Worker 		if (link_cache) {
275*4dc78e53SAndroid Build Coastguard Worker 			nl_dump(p, "iif %s ",
276*4dc78e53SAndroid Build Coastguard Worker 				rtnl_link_i2name(link_cache, r->rt_iif,
277*4dc78e53SAndroid Build Coastguard Worker 						 buf, sizeof(buf)));
278*4dc78e53SAndroid Build Coastguard Worker 		} else
279*4dc78e53SAndroid Build Coastguard Worker 			nl_dump(p, "iif %d ", r->rt_iif);
280*4dc78e53SAndroid Build Coastguard Worker 	}
281*4dc78e53SAndroid Build Coastguard Worker 
282*4dc78e53SAndroid Build Coastguard Worker 	if (r->ce_mask & ROUTE_ATTR_SRC)
283*4dc78e53SAndroid Build Coastguard Worker 		nl_dump(p, "src %s ", nl_addr2str(r->rt_src, buf, sizeof(buf)));
284*4dc78e53SAndroid Build Coastguard Worker 
285*4dc78e53SAndroid Build Coastguard Worker 	if (r->ce_mask & ROUTE_ATTR_TTL_PROPAGATE) {
286*4dc78e53SAndroid Build Coastguard Worker 		nl_dump(p, " ttl-propagate %s",
287*4dc78e53SAndroid Build Coastguard Worker 			r->rt_ttl_propagate ? "enabled" : "disabled");
288*4dc78e53SAndroid Build Coastguard Worker 	}
289*4dc78e53SAndroid Build Coastguard Worker 
290*4dc78e53SAndroid Build Coastguard Worker 	if (r->ce_mask & ROUTE_ATTR_NHID)
291*4dc78e53SAndroid Build Coastguard Worker 		nl_dump(p, "nhid %u ", r->rt_nhid);
292*4dc78e53SAndroid Build Coastguard Worker 
293*4dc78e53SAndroid Build Coastguard Worker 	nl_dump(p, "\n");
294*4dc78e53SAndroid Build Coastguard Worker 
295*4dc78e53SAndroid Build Coastguard Worker 	if (r->ce_mask & ROUTE_ATTR_MULTIPATH) {
296*4dc78e53SAndroid Build Coastguard Worker 		struct rtnl_nexthop *nh;
297*4dc78e53SAndroid Build Coastguard Worker 
298*4dc78e53SAndroid Build Coastguard Worker 		nl_list_for_each_entry(nh, &r->rt_nexthops, rtnh_list) {
299*4dc78e53SAndroid Build Coastguard Worker 			nl_dump_line(p, "    ");
300*4dc78e53SAndroid Build Coastguard Worker 			p->dp_ivar = NH_DUMP_FROM_DETAILS;
301*4dc78e53SAndroid Build Coastguard Worker 			rtnl_route_nh_dump(nh, p);
302*4dc78e53SAndroid Build Coastguard Worker 			nl_dump(p, "\n");
303*4dc78e53SAndroid Build Coastguard Worker 		}
304*4dc78e53SAndroid Build Coastguard Worker 	}
305*4dc78e53SAndroid Build Coastguard Worker 
306*4dc78e53SAndroid Build Coastguard Worker 	if ((r->ce_mask & ROUTE_ATTR_CACHEINFO) && r->rt_cacheinfo.rtci_error) {
307*4dc78e53SAndroid Build Coastguard Worker 		nl_dump_line(p, "    cacheinfo error %d (%s)\n",
308*4dc78e53SAndroid Build Coastguard Worker 			r->rt_cacheinfo.rtci_error,
309*4dc78e53SAndroid Build Coastguard Worker 			nl_strerror_l(-r->rt_cacheinfo.rtci_error));
310*4dc78e53SAndroid Build Coastguard Worker 	}
311*4dc78e53SAndroid Build Coastguard Worker 
312*4dc78e53SAndroid Build Coastguard Worker 	if (r->ce_mask & ROUTE_ATTR_METRICS) {
313*4dc78e53SAndroid Build Coastguard Worker 		nl_dump_line(p, "    metrics [");
314*4dc78e53SAndroid Build Coastguard Worker 		for (i = 0; i < RTAX_MAX; i++)
315*4dc78e53SAndroid Build Coastguard Worker 			if (r->rt_metrics_mask & (1 << i))
316*4dc78e53SAndroid Build Coastguard Worker 				nl_dump(p, "%s %u ",
317*4dc78e53SAndroid Build Coastguard Worker 					rtnl_route_metric2str(i+1,
318*4dc78e53SAndroid Build Coastguard Worker 							      buf, sizeof(buf)),
319*4dc78e53SAndroid Build Coastguard Worker 					r->rt_metrics[i]);
320*4dc78e53SAndroid Build Coastguard Worker 		nl_dump(p, "]\n");
321*4dc78e53SAndroid Build Coastguard Worker 	}
322*4dc78e53SAndroid Build Coastguard Worker }
323*4dc78e53SAndroid Build Coastguard Worker 
route_dump_stats(struct nl_object * obj,struct nl_dump_params * p)324*4dc78e53SAndroid Build Coastguard Worker static void route_dump_stats(struct nl_object *obj, struct nl_dump_params *p)
325*4dc78e53SAndroid Build Coastguard Worker {
326*4dc78e53SAndroid Build Coastguard Worker 	struct rtnl_route *route = (struct rtnl_route *) obj;
327*4dc78e53SAndroid Build Coastguard Worker 
328*4dc78e53SAndroid Build Coastguard Worker 	route_dump_details(obj, p);
329*4dc78e53SAndroid Build Coastguard Worker 
330*4dc78e53SAndroid Build Coastguard Worker 	if (route->ce_mask & ROUTE_ATTR_CACHEINFO) {
331*4dc78e53SAndroid Build Coastguard Worker 		struct rtnl_rtcacheinfo *ci = &route->rt_cacheinfo;
332*4dc78e53SAndroid Build Coastguard Worker 
333*4dc78e53SAndroid Build Coastguard Worker 		nl_dump_line(p, "    used %u refcnt %u last-use %us "
334*4dc78e53SAndroid Build Coastguard Worker 				"expires %us\n",
335*4dc78e53SAndroid Build Coastguard Worker 			     ci->rtci_used, ci->rtci_clntref,
336*4dc78e53SAndroid Build Coastguard Worker 			     ci->rtci_last_use / nl_get_user_hz(),
337*4dc78e53SAndroid Build Coastguard Worker 			     ci->rtci_expires / nl_get_user_hz());
338*4dc78e53SAndroid Build Coastguard Worker 	}
339*4dc78e53SAndroid Build Coastguard Worker }
340*4dc78e53SAndroid Build Coastguard Worker 
route_keygen(struct nl_object * obj,uint32_t * hashkey,uint32_t table_sz)341*4dc78e53SAndroid Build Coastguard Worker static void route_keygen(struct nl_object *obj, uint32_t *hashkey,
342*4dc78e53SAndroid Build Coastguard Worker 			  uint32_t table_sz)
343*4dc78e53SAndroid Build Coastguard Worker {
344*4dc78e53SAndroid Build Coastguard Worker 	struct rtnl_route *route = (struct rtnl_route *) obj;
345*4dc78e53SAndroid Build Coastguard Worker 	unsigned int rkey_sz;
346*4dc78e53SAndroid Build Coastguard Worker 	struct nl_addr *addr = NULL;
347*4dc78e53SAndroid Build Coastguard Worker 	_nl_auto_free struct route_hash_key {
348*4dc78e53SAndroid Build Coastguard Worker 		uint8_t		rt_family;
349*4dc78e53SAndroid Build Coastguard Worker 		uint8_t		rt_tos;
350*4dc78e53SAndroid Build Coastguard Worker 		uint32_t	rt_table;
351*4dc78e53SAndroid Build Coastguard Worker 		uint32_t	rt_prio;
352*4dc78e53SAndroid Build Coastguard Worker 		char 		rt_addr[0];
353*4dc78e53SAndroid Build Coastguard Worker 	} _nl_packed *rkey = NULL;
354*4dc78e53SAndroid Build Coastguard Worker 	char buf[INET6_ADDRSTRLEN+5];
355*4dc78e53SAndroid Build Coastguard Worker 
356*4dc78e53SAndroid Build Coastguard Worker 	if (route->rt_dst)
357*4dc78e53SAndroid Build Coastguard Worker 		addr = route->rt_dst;
358*4dc78e53SAndroid Build Coastguard Worker 
359*4dc78e53SAndroid Build Coastguard Worker 	rkey_sz = sizeof(*rkey);
360*4dc78e53SAndroid Build Coastguard Worker 	if (addr)
361*4dc78e53SAndroid Build Coastguard Worker 		rkey_sz += nl_addr_get_len(addr);
362*4dc78e53SAndroid Build Coastguard Worker 	rkey = calloc(1, rkey_sz);
363*4dc78e53SAndroid Build Coastguard Worker 	if (!rkey) {
364*4dc78e53SAndroid Build Coastguard Worker 		NL_DBG(2, "Warning: calloc failed for %d bytes...\n", rkey_sz);
365*4dc78e53SAndroid Build Coastguard Worker 		*hashkey = 0;
366*4dc78e53SAndroid Build Coastguard Worker 		return;
367*4dc78e53SAndroid Build Coastguard Worker 	}
368*4dc78e53SAndroid Build Coastguard Worker 	rkey->rt_family = route->rt_family;
369*4dc78e53SAndroid Build Coastguard Worker 	rkey->rt_tos = route->rt_tos;
370*4dc78e53SAndroid Build Coastguard Worker 	rkey->rt_table = route->rt_table;
371*4dc78e53SAndroid Build Coastguard Worker 	rkey->rt_prio = route->rt_prio;
372*4dc78e53SAndroid Build Coastguard Worker 	if (addr)
373*4dc78e53SAndroid Build Coastguard Worker 		memcpy(rkey->rt_addr, nl_addr_get_binary_addr(addr),
374*4dc78e53SAndroid Build Coastguard Worker 			nl_addr_get_len(addr));
375*4dc78e53SAndroid Build Coastguard Worker 
376*4dc78e53SAndroid Build Coastguard Worker 	*hashkey = nl_hash(rkey, rkey_sz, 0) % table_sz;
377*4dc78e53SAndroid Build Coastguard Worker 
378*4dc78e53SAndroid Build Coastguard Worker 	NL_DBG(5,
379*4dc78e53SAndroid Build Coastguard Worker 	       "route %p key (fam %d tos %d table %d prio %d addr %s) keysz %d hash 0x%x\n",
380*4dc78e53SAndroid Build Coastguard Worker 	       route, rkey->rt_family, rkey->rt_tos, rkey->rt_table,
381*4dc78e53SAndroid Build Coastguard Worker 	       rkey->rt_prio, nl_addr2str(addr, buf, sizeof(buf)), rkey_sz,
382*4dc78e53SAndroid Build Coastguard Worker 	       *hashkey);
383*4dc78e53SAndroid Build Coastguard Worker 
384*4dc78e53SAndroid Build Coastguard Worker 	return;
385*4dc78e53SAndroid Build Coastguard Worker }
386*4dc78e53SAndroid Build Coastguard Worker 
route_id_attrs_get(struct nl_object * obj)387*4dc78e53SAndroid Build Coastguard Worker static uint32_t route_id_attrs_get(struct nl_object *obj)
388*4dc78e53SAndroid Build Coastguard Worker {
389*4dc78e53SAndroid Build Coastguard Worker 	struct rtnl_route *route = (struct rtnl_route *)obj;
390*4dc78e53SAndroid Build Coastguard Worker 	struct nl_object_ops *ops = obj->ce_ops;
391*4dc78e53SAndroid Build Coastguard Worker 	uint32_t rv = ops->oo_id_attrs;
392*4dc78e53SAndroid Build Coastguard Worker 
393*4dc78e53SAndroid Build Coastguard Worker 	/* MPLS address family does not allow RTA_PRIORITY to be set */
394*4dc78e53SAndroid Build Coastguard Worker 	if (route->rt_family == AF_MPLS)
395*4dc78e53SAndroid Build Coastguard Worker 		rv &= ~ROUTE_ATTR_PRIO;
396*4dc78e53SAndroid Build Coastguard Worker 
397*4dc78e53SAndroid Build Coastguard Worker 	return rv;
398*4dc78e53SAndroid Build Coastguard Worker }
399*4dc78e53SAndroid Build Coastguard Worker 
route_compare(struct nl_object * _a,struct nl_object * _b,uint64_t attrs,int flags)400*4dc78e53SAndroid Build Coastguard Worker static uint64_t route_compare(struct nl_object *_a, struct nl_object *_b,
401*4dc78e53SAndroid Build Coastguard Worker 			      uint64_t attrs, int flags)
402*4dc78e53SAndroid Build Coastguard Worker {
403*4dc78e53SAndroid Build Coastguard Worker 	struct rtnl_route *a = (struct rtnl_route *) _a;
404*4dc78e53SAndroid Build Coastguard Worker 	struct rtnl_route *b = (struct rtnl_route *) _b;
405*4dc78e53SAndroid Build Coastguard Worker 	struct rtnl_nexthop *nh_a, *nh_b;
406*4dc78e53SAndroid Build Coastguard Worker 	int i, found;
407*4dc78e53SAndroid Build Coastguard Worker 	uint64_t diff = 0;
408*4dc78e53SAndroid Build Coastguard Worker 
409*4dc78e53SAndroid Build Coastguard Worker #define _DIFF(ATTR, EXPR) ATTR_DIFF(attrs, ATTR, a, b, EXPR)
410*4dc78e53SAndroid Build Coastguard Worker 	diff |= _DIFF(ROUTE_ATTR_FAMILY, a->rt_family != b->rt_family);
411*4dc78e53SAndroid Build Coastguard Worker 	diff |= _DIFF(ROUTE_ATTR_TOS, a->rt_tos != b->rt_tos);
412*4dc78e53SAndroid Build Coastguard Worker 	diff |= _DIFF(ROUTE_ATTR_TABLE, a->rt_table != b->rt_table);
413*4dc78e53SAndroid Build Coastguard Worker 	diff |= _DIFF(ROUTE_ATTR_PROTOCOL, a->rt_protocol != b->rt_protocol);
414*4dc78e53SAndroid Build Coastguard Worker 	diff |= _DIFF(ROUTE_ATTR_SCOPE, a->rt_scope != b->rt_scope);
415*4dc78e53SAndroid Build Coastguard Worker 	diff |= _DIFF(ROUTE_ATTR_TYPE, a->rt_type != b->rt_type);
416*4dc78e53SAndroid Build Coastguard Worker 	diff |= _DIFF(ROUTE_ATTR_PRIO, a->rt_prio != b->rt_prio);
417*4dc78e53SAndroid Build Coastguard Worker 	diff |= _DIFF(ROUTE_ATTR_DST, nl_addr_cmp(a->rt_dst, b->rt_dst));
418*4dc78e53SAndroid Build Coastguard Worker 	diff |= _DIFF(ROUTE_ATTR_SRC, nl_addr_cmp(a->rt_src, b->rt_src));
419*4dc78e53SAndroid Build Coastguard Worker 	diff |= _DIFF(ROUTE_ATTR_IIF, a->rt_iif != b->rt_iif);
420*4dc78e53SAndroid Build Coastguard Worker 	diff |= _DIFF(ROUTE_ATTR_PREF_SRC,
421*4dc78e53SAndroid Build Coastguard Worker 		      nl_addr_cmp(a->rt_pref_src, b->rt_pref_src));
422*4dc78e53SAndroid Build Coastguard Worker 	diff |= _DIFF(ROUTE_ATTR_TTL_PROPAGATE,
423*4dc78e53SAndroid Build Coastguard Worker 		      a->rt_ttl_propagate != b->rt_ttl_propagate);
424*4dc78e53SAndroid Build Coastguard Worker 	diff |= _DIFF(ROUTE_ATTR_NHID, a->rt_nhid != b->rt_nhid);
425*4dc78e53SAndroid Build Coastguard Worker 
426*4dc78e53SAndroid Build Coastguard Worker 	if (flags & LOOSE_COMPARISON) {
427*4dc78e53SAndroid Build Coastguard Worker 		nl_list_for_each_entry(nh_b, &b->rt_nexthops, rtnh_list) {
428*4dc78e53SAndroid Build Coastguard Worker 			found = 0;
429*4dc78e53SAndroid Build Coastguard Worker 			nl_list_for_each_entry(nh_a, &a->rt_nexthops,
430*4dc78e53SAndroid Build Coastguard Worker 					       rtnh_list) {
431*4dc78e53SAndroid Build Coastguard Worker 				if (!rtnl_route_nh_compare(nh_a, nh_b,
432*4dc78e53SAndroid Build Coastguard Worker 							nh_b->ce_mask, 1)) {
433*4dc78e53SAndroid Build Coastguard Worker 					found = 1;
434*4dc78e53SAndroid Build Coastguard Worker 					break;
435*4dc78e53SAndroid Build Coastguard Worker 				}
436*4dc78e53SAndroid Build Coastguard Worker 			}
437*4dc78e53SAndroid Build Coastguard Worker 
438*4dc78e53SAndroid Build Coastguard Worker 			if (!found)
439*4dc78e53SAndroid Build Coastguard Worker 				goto nh_mismatch;
440*4dc78e53SAndroid Build Coastguard Worker 		}
441*4dc78e53SAndroid Build Coastguard Worker 
442*4dc78e53SAndroid Build Coastguard Worker 		for (i = 0; i < RTAX_MAX - 1; i++) {
443*4dc78e53SAndroid Build Coastguard Worker 			if (a->rt_metrics_mask & (1 << i) &&
444*4dc78e53SAndroid Build Coastguard Worker 			    (!(b->rt_metrics_mask & (1 << i)) ||
445*4dc78e53SAndroid Build Coastguard Worker 			     a->rt_metrics[i] != b->rt_metrics[i]))
446*4dc78e53SAndroid Build Coastguard Worker 				diff |= _DIFF(ROUTE_ATTR_METRICS, 1);
447*4dc78e53SAndroid Build Coastguard Worker 		}
448*4dc78e53SAndroid Build Coastguard Worker 
449*4dc78e53SAndroid Build Coastguard Worker 		diff |= _DIFF(ROUTE_ATTR_FLAGS,
450*4dc78e53SAndroid Build Coastguard Worker 			  (a->rt_flags ^ b->rt_flags) & b->rt_flag_mask);
451*4dc78e53SAndroid Build Coastguard Worker 	} else {
452*4dc78e53SAndroid Build Coastguard Worker 		if (a->rt_nr_nh != b->rt_nr_nh)
453*4dc78e53SAndroid Build Coastguard Worker 			goto nh_mismatch;
454*4dc78e53SAndroid Build Coastguard Worker 
455*4dc78e53SAndroid Build Coastguard Worker 		/* search for a dup in each nh of a */
456*4dc78e53SAndroid Build Coastguard Worker 		nl_list_for_each_entry(nh_a, &a->rt_nexthops, rtnh_list) {
457*4dc78e53SAndroid Build Coastguard Worker 			found = 0;
458*4dc78e53SAndroid Build Coastguard Worker 			nl_list_for_each_entry(nh_b, &b->rt_nexthops,
459*4dc78e53SAndroid Build Coastguard Worker 					       rtnh_list) {
460*4dc78e53SAndroid Build Coastguard Worker 				if (rtnl_route_nh_identical(nh_a, nh_b)) {
461*4dc78e53SAndroid Build Coastguard Worker 					found = 1;
462*4dc78e53SAndroid Build Coastguard Worker 					break;
463*4dc78e53SAndroid Build Coastguard Worker 				}
464*4dc78e53SAndroid Build Coastguard Worker 			}
465*4dc78e53SAndroid Build Coastguard Worker 			if (!found)
466*4dc78e53SAndroid Build Coastguard Worker 				goto nh_mismatch;
467*4dc78e53SAndroid Build Coastguard Worker 		}
468*4dc78e53SAndroid Build Coastguard Worker 
469*4dc78e53SAndroid Build Coastguard Worker 		/* search for a dup in each nh of b, covers case where a has
470*4dc78e53SAndroid Build Coastguard Worker 		 * dupes itself */
471*4dc78e53SAndroid Build Coastguard Worker 		nl_list_for_each_entry(nh_b, &b->rt_nexthops, rtnh_list) {
472*4dc78e53SAndroid Build Coastguard Worker 			found = 0;
473*4dc78e53SAndroid Build Coastguard Worker 			nl_list_for_each_entry(nh_a, &a->rt_nexthops,
474*4dc78e53SAndroid Build Coastguard Worker 					       rtnh_list) {
475*4dc78e53SAndroid Build Coastguard Worker 				if (rtnl_route_nh_identical(nh_a, nh_b)) {
476*4dc78e53SAndroid Build Coastguard Worker 					found = 1;
477*4dc78e53SAndroid Build Coastguard Worker 					break;
478*4dc78e53SAndroid Build Coastguard Worker 				}
479*4dc78e53SAndroid Build Coastguard Worker 			}
480*4dc78e53SAndroid Build Coastguard Worker 			if (!found)
481*4dc78e53SAndroid Build Coastguard Worker 				goto nh_mismatch;
482*4dc78e53SAndroid Build Coastguard Worker 		}
483*4dc78e53SAndroid Build Coastguard Worker 
484*4dc78e53SAndroid Build Coastguard Worker 		for (i = 0; i < RTAX_MAX - 1; i++) {
485*4dc78e53SAndroid Build Coastguard Worker 			if ((a->rt_metrics_mask & (1 << i)) ^
486*4dc78e53SAndroid Build Coastguard Worker 			    (b->rt_metrics_mask & (1 << i)))
487*4dc78e53SAndroid Build Coastguard Worker 				diff |= _DIFF(ROUTE_ATTR_METRICS, 1);
488*4dc78e53SAndroid Build Coastguard Worker 			else
489*4dc78e53SAndroid Build Coastguard Worker 				diff |= _DIFF(ROUTE_ATTR_METRICS,
490*4dc78e53SAndroid Build Coastguard Worker 					a->rt_metrics[i] != b->rt_metrics[i]);
491*4dc78e53SAndroid Build Coastguard Worker 		}
492*4dc78e53SAndroid Build Coastguard Worker 
493*4dc78e53SAndroid Build Coastguard Worker 		diff |= _DIFF(ROUTE_ATTR_FLAGS, a->rt_flags != b->rt_flags);
494*4dc78e53SAndroid Build Coastguard Worker 	}
495*4dc78e53SAndroid Build Coastguard Worker 
496*4dc78e53SAndroid Build Coastguard Worker out:
497*4dc78e53SAndroid Build Coastguard Worker 	return diff;
498*4dc78e53SAndroid Build Coastguard Worker 
499*4dc78e53SAndroid Build Coastguard Worker nh_mismatch:
500*4dc78e53SAndroid Build Coastguard Worker 	diff |= _DIFF(ROUTE_ATTR_MULTIPATH, 1);
501*4dc78e53SAndroid Build Coastguard Worker 	goto out;
502*4dc78e53SAndroid Build Coastguard Worker #undef _DIFF
503*4dc78e53SAndroid Build Coastguard Worker }
504*4dc78e53SAndroid Build Coastguard Worker 
route_update(struct nl_object * old_obj,struct nl_object * new_obj)505*4dc78e53SAndroid Build Coastguard Worker static int route_update(struct nl_object *old_obj, struct nl_object *new_obj)
506*4dc78e53SAndroid Build Coastguard Worker {
507*4dc78e53SAndroid Build Coastguard Worker 	struct rtnl_route *new_route = (struct rtnl_route *) new_obj;
508*4dc78e53SAndroid Build Coastguard Worker 	struct rtnl_route *old_route = (struct rtnl_route *) old_obj;
509*4dc78e53SAndroid Build Coastguard Worker 	struct rtnl_nexthop *new_nh;
510*4dc78e53SAndroid Build Coastguard Worker 	int action = new_obj->ce_msgtype;
511*4dc78e53SAndroid Build Coastguard Worker 	char buf[INET6_ADDRSTRLEN+5];
512*4dc78e53SAndroid Build Coastguard Worker 
513*4dc78e53SAndroid Build Coastguard Worker 	/*
514*4dc78e53SAndroid Build Coastguard Worker 	 * ipv6 ECMP route notifications from the kernel come as
515*4dc78e53SAndroid Build Coastguard Worker 	 * separate notifications, one for every nexthop. This update
516*4dc78e53SAndroid Build Coastguard Worker 	 * function collapses such route msgs into a single
517*4dc78e53SAndroid Build Coastguard Worker 	 * route with multiple nexthops. The resulting object looks
518*4dc78e53SAndroid Build Coastguard Worker 	 * similar to a ipv4 ECMP route
519*4dc78e53SAndroid Build Coastguard Worker 	 */
520*4dc78e53SAndroid Build Coastguard Worker 	if (new_route->rt_family != AF_INET6 ||
521*4dc78e53SAndroid Build Coastguard Worker 	    new_route->rt_table == RT_TABLE_LOCAL)
522*4dc78e53SAndroid Build Coastguard Worker 		return -NLE_OPNOTSUPP;
523*4dc78e53SAndroid Build Coastguard Worker 
524*4dc78e53SAndroid Build Coastguard Worker 	/*
525*4dc78e53SAndroid Build Coastguard Worker 	 * For routes that are already multipath,
526*4dc78e53SAndroid Build Coastguard Worker 	 * or dont have a nexthop dont do anything
527*4dc78e53SAndroid Build Coastguard Worker 	 */
528*4dc78e53SAndroid Build Coastguard Worker 	if (rtnl_route_get_nnexthops(new_route) != 1)
529*4dc78e53SAndroid Build Coastguard Worker 		return -NLE_OPNOTSUPP;
530*4dc78e53SAndroid Build Coastguard Worker 
531*4dc78e53SAndroid Build Coastguard Worker 	/*
532*4dc78e53SAndroid Build Coastguard Worker 	 * Get the only nexthop entry from the new route. For
533*4dc78e53SAndroid Build Coastguard Worker 	 * IPv6 we always get a route with a 0th NH
534*4dc78e53SAndroid Build Coastguard Worker 	 * filled or nothing at all
535*4dc78e53SAndroid Build Coastguard Worker 	 */
536*4dc78e53SAndroid Build Coastguard Worker 	new_nh = rtnl_route_nexthop_n(new_route, 0);
537*4dc78e53SAndroid Build Coastguard Worker 	if (!new_nh || !rtnl_route_nh_get_gateway(new_nh))
538*4dc78e53SAndroid Build Coastguard Worker 		return -NLE_OPNOTSUPP;
539*4dc78e53SAndroid Build Coastguard Worker 
540*4dc78e53SAndroid Build Coastguard Worker 	switch(action) {
541*4dc78e53SAndroid Build Coastguard Worker 	case RTM_NEWROUTE : {
542*4dc78e53SAndroid Build Coastguard Worker 		struct rtnl_nexthop *cloned_nh;
543*4dc78e53SAndroid Build Coastguard Worker 		struct rtnl_nexthop *old_nh;
544*4dc78e53SAndroid Build Coastguard Worker 
545*4dc78e53SAndroid Build Coastguard Worker 		/*
546*4dc78e53SAndroid Build Coastguard Worker 		 * Do not add the nexthop to old route if it was already added before
547*4dc78e53SAndroid Build Coastguard Worker 		 */
548*4dc78e53SAndroid Build Coastguard Worker 		nl_list_for_each_entry(old_nh, &old_route->rt_nexthops, rtnh_list) {
549*4dc78e53SAndroid Build Coastguard Worker 			if (rtnl_route_nh_identical(old_nh, new_nh)) {
550*4dc78e53SAndroid Build Coastguard Worker 				return 0;
551*4dc78e53SAndroid Build Coastguard Worker 			}
552*4dc78e53SAndroid Build Coastguard Worker 		}
553*4dc78e53SAndroid Build Coastguard Worker 
554*4dc78e53SAndroid Build Coastguard Worker 		/*
555*4dc78e53SAndroid Build Coastguard Worker 		 * Add the nexthop to old route
556*4dc78e53SAndroid Build Coastguard Worker 		 */
557*4dc78e53SAndroid Build Coastguard Worker 		cloned_nh = rtnl_route_nh_clone(new_nh);
558*4dc78e53SAndroid Build Coastguard Worker 		if (!cloned_nh)
559*4dc78e53SAndroid Build Coastguard Worker 			return -NLE_NOMEM;
560*4dc78e53SAndroid Build Coastguard Worker 		rtnl_route_add_nexthop(old_route, cloned_nh);
561*4dc78e53SAndroid Build Coastguard Worker 
562*4dc78e53SAndroid Build Coastguard Worker 		NL_DBG(2, "Route obj %p updated. Added "
563*4dc78e53SAndroid Build Coastguard Worker 			"nexthop %p via %s\n", old_route, cloned_nh,
564*4dc78e53SAndroid Build Coastguard Worker 			nl_addr2str(cloned_nh->rtnh_gateway, buf,
565*4dc78e53SAndroid Build Coastguard Worker 					sizeof(buf)));
566*4dc78e53SAndroid Build Coastguard Worker 	}
567*4dc78e53SAndroid Build Coastguard Worker 		break;
568*4dc78e53SAndroid Build Coastguard Worker 	case RTM_DELROUTE : {
569*4dc78e53SAndroid Build Coastguard Worker 		struct rtnl_nexthop *old_nh;
570*4dc78e53SAndroid Build Coastguard Worker 
571*4dc78e53SAndroid Build Coastguard Worker 		/*
572*4dc78e53SAndroid Build Coastguard Worker 		 * Only take care of nexthop deletes and not
573*4dc78e53SAndroid Build Coastguard Worker 		 * route deletes. So, if there is only one nexthop
574*4dc78e53SAndroid Build Coastguard Worker 		 * quite likely we did not update it. So dont do
575*4dc78e53SAndroid Build Coastguard Worker 		 * anything and return
576*4dc78e53SAndroid Build Coastguard Worker 		 */
577*4dc78e53SAndroid Build Coastguard Worker 		if (rtnl_route_get_nnexthops(old_route) <= 1)
578*4dc78e53SAndroid Build Coastguard Worker 			return -NLE_OPNOTSUPP;
579*4dc78e53SAndroid Build Coastguard Worker 
580*4dc78e53SAndroid Build Coastguard Worker 		/*
581*4dc78e53SAndroid Build Coastguard Worker 		 * Find the next hop in old route and delete it
582*4dc78e53SAndroid Build Coastguard Worker 		 */
583*4dc78e53SAndroid Build Coastguard Worker 		nl_list_for_each_entry(old_nh, &old_route->rt_nexthops,
584*4dc78e53SAndroid Build Coastguard Worker 			rtnh_list) {
585*4dc78e53SAndroid Build Coastguard Worker 			if (rtnl_route_nh_identical(old_nh, new_nh)) {
586*4dc78e53SAndroid Build Coastguard Worker 
587*4dc78e53SAndroid Build Coastguard Worker 				rtnl_route_remove_nexthop(old_route, old_nh);
588*4dc78e53SAndroid Build Coastguard Worker 
589*4dc78e53SAndroid Build Coastguard Worker 				NL_DBG(2, "Route obj %p updated. Removed "
590*4dc78e53SAndroid Build Coastguard Worker 					"nexthop %p via %s\n", old_route,
591*4dc78e53SAndroid Build Coastguard Worker 					old_nh,
592*4dc78e53SAndroid Build Coastguard Worker 					nl_addr2str(old_nh->rtnh_gateway, buf,
593*4dc78e53SAndroid Build Coastguard Worker 					sizeof(buf)));
594*4dc78e53SAndroid Build Coastguard Worker 
595*4dc78e53SAndroid Build Coastguard Worker 				rtnl_route_nh_free(old_nh);
596*4dc78e53SAndroid Build Coastguard Worker 				break;
597*4dc78e53SAndroid Build Coastguard Worker 			}
598*4dc78e53SAndroid Build Coastguard Worker 		}
599*4dc78e53SAndroid Build Coastguard Worker 	}
600*4dc78e53SAndroid Build Coastguard Worker 		break;
601*4dc78e53SAndroid Build Coastguard Worker 	default:
602*4dc78e53SAndroid Build Coastguard Worker 		NL_DBG(2, "Unknown action associated "
603*4dc78e53SAndroid Build Coastguard Worker 			"to object %p during route update\n", new_obj);
604*4dc78e53SAndroid Build Coastguard Worker 		return -NLE_OPNOTSUPP;
605*4dc78e53SAndroid Build Coastguard Worker 	}
606*4dc78e53SAndroid Build Coastguard Worker 
607*4dc78e53SAndroid Build Coastguard Worker 	return NLE_SUCCESS;
608*4dc78e53SAndroid Build Coastguard Worker }
609*4dc78e53SAndroid Build Coastguard Worker 
610*4dc78e53SAndroid Build Coastguard Worker static const struct trans_tbl route_attrs[] = {
611*4dc78e53SAndroid Build Coastguard Worker 	__ADD(ROUTE_ATTR_FAMILY, family),
612*4dc78e53SAndroid Build Coastguard Worker 	__ADD(ROUTE_ATTR_TOS, tos),
613*4dc78e53SAndroid Build Coastguard Worker 	__ADD(ROUTE_ATTR_TABLE, table),
614*4dc78e53SAndroid Build Coastguard Worker 	__ADD(ROUTE_ATTR_PROTOCOL, protocol),
615*4dc78e53SAndroid Build Coastguard Worker 	__ADD(ROUTE_ATTR_SCOPE, scope),
616*4dc78e53SAndroid Build Coastguard Worker 	__ADD(ROUTE_ATTR_TYPE, type),
617*4dc78e53SAndroid Build Coastguard Worker 	__ADD(ROUTE_ATTR_FLAGS, flags),
618*4dc78e53SAndroid Build Coastguard Worker 	__ADD(ROUTE_ATTR_DST, dst),
619*4dc78e53SAndroid Build Coastguard Worker 	__ADD(ROUTE_ATTR_SRC, src),
620*4dc78e53SAndroid Build Coastguard Worker 	__ADD(ROUTE_ATTR_IIF, iif),
621*4dc78e53SAndroid Build Coastguard Worker 	__ADD(ROUTE_ATTR_OIF, oif),
622*4dc78e53SAndroid Build Coastguard Worker 	__ADD(ROUTE_ATTR_GATEWAY, gateway),
623*4dc78e53SAndroid Build Coastguard Worker 	__ADD(ROUTE_ATTR_PRIO, prio),
624*4dc78e53SAndroid Build Coastguard Worker 	__ADD(ROUTE_ATTR_PREF_SRC, pref_src),
625*4dc78e53SAndroid Build Coastguard Worker 	__ADD(ROUTE_ATTR_METRICS, metrics),
626*4dc78e53SAndroid Build Coastguard Worker 	__ADD(ROUTE_ATTR_MULTIPATH, multipath),
627*4dc78e53SAndroid Build Coastguard Worker 	__ADD(ROUTE_ATTR_REALMS, realms),
628*4dc78e53SAndroid Build Coastguard Worker 	__ADD(ROUTE_ATTR_CACHEINFO, cacheinfo),
629*4dc78e53SAndroid Build Coastguard Worker 	__ADD(ROUTE_ATTR_TTL_PROPAGATE, ttl_propagate),
630*4dc78e53SAndroid Build Coastguard Worker 	__ADD(ROUTE_ATTR_NHID, nhid),
631*4dc78e53SAndroid Build Coastguard Worker };
632*4dc78e53SAndroid Build Coastguard Worker 
route_attrs2str(int attrs,char * buf,size_t len)633*4dc78e53SAndroid Build Coastguard Worker static char *route_attrs2str(int attrs, char *buf, size_t len)
634*4dc78e53SAndroid Build Coastguard Worker {
635*4dc78e53SAndroid Build Coastguard Worker 	return __flags2str(attrs, buf, len, route_attrs,
636*4dc78e53SAndroid Build Coastguard Worker 			   ARRAY_SIZE(route_attrs));
637*4dc78e53SAndroid Build Coastguard Worker }
638*4dc78e53SAndroid Build Coastguard Worker 
639*4dc78e53SAndroid Build Coastguard Worker /**
640*4dc78e53SAndroid Build Coastguard Worker  * @name Allocation/Freeing
641*4dc78e53SAndroid Build Coastguard Worker  * @{
642*4dc78e53SAndroid Build Coastguard Worker  */
643*4dc78e53SAndroid Build Coastguard Worker 
rtnl_route_alloc(void)644*4dc78e53SAndroid Build Coastguard Worker struct rtnl_route *rtnl_route_alloc(void)
645*4dc78e53SAndroid Build Coastguard Worker {
646*4dc78e53SAndroid Build Coastguard Worker 	return (struct rtnl_route *) nl_object_alloc(&route_obj_ops);
647*4dc78e53SAndroid Build Coastguard Worker }
648*4dc78e53SAndroid Build Coastguard Worker 
rtnl_route_get(struct rtnl_route * route)649*4dc78e53SAndroid Build Coastguard Worker void rtnl_route_get(struct rtnl_route *route)
650*4dc78e53SAndroid Build Coastguard Worker {
651*4dc78e53SAndroid Build Coastguard Worker 	nl_object_get((struct nl_object *) route);
652*4dc78e53SAndroid Build Coastguard Worker }
653*4dc78e53SAndroid Build Coastguard Worker 
rtnl_route_put(struct rtnl_route * route)654*4dc78e53SAndroid Build Coastguard Worker void rtnl_route_put(struct rtnl_route *route)
655*4dc78e53SAndroid Build Coastguard Worker {
656*4dc78e53SAndroid Build Coastguard Worker 	nl_object_put((struct nl_object *) route);
657*4dc78e53SAndroid Build Coastguard Worker }
658*4dc78e53SAndroid Build Coastguard Worker 
659*4dc78e53SAndroid Build Coastguard Worker /** @} */
660*4dc78e53SAndroid Build Coastguard Worker 
661*4dc78e53SAndroid Build Coastguard Worker /**
662*4dc78e53SAndroid Build Coastguard Worker  * @name Attributes
663*4dc78e53SAndroid Build Coastguard Worker  * @{
664*4dc78e53SAndroid Build Coastguard Worker  */
665*4dc78e53SAndroid Build Coastguard Worker 
rtnl_route_set_table(struct rtnl_route * route,uint32_t table)666*4dc78e53SAndroid Build Coastguard Worker void rtnl_route_set_table(struct rtnl_route *route, uint32_t table)
667*4dc78e53SAndroid Build Coastguard Worker {
668*4dc78e53SAndroid Build Coastguard Worker 	route->rt_table = table;
669*4dc78e53SAndroid Build Coastguard Worker 	route->ce_mask |= ROUTE_ATTR_TABLE;
670*4dc78e53SAndroid Build Coastguard Worker }
671*4dc78e53SAndroid Build Coastguard Worker 
rtnl_route_get_table(struct rtnl_route * route)672*4dc78e53SAndroid Build Coastguard Worker uint32_t rtnl_route_get_table(struct rtnl_route *route)
673*4dc78e53SAndroid Build Coastguard Worker {
674*4dc78e53SAndroid Build Coastguard Worker 	return route->rt_table;
675*4dc78e53SAndroid Build Coastguard Worker }
676*4dc78e53SAndroid Build Coastguard Worker 
rtnl_route_set_scope(struct rtnl_route * route,uint8_t scope)677*4dc78e53SAndroid Build Coastguard Worker void rtnl_route_set_scope(struct rtnl_route *route, uint8_t scope)
678*4dc78e53SAndroid Build Coastguard Worker {
679*4dc78e53SAndroid Build Coastguard Worker 	route->rt_scope = scope;
680*4dc78e53SAndroid Build Coastguard Worker 	route->ce_mask |= ROUTE_ATTR_SCOPE;
681*4dc78e53SAndroid Build Coastguard Worker }
682*4dc78e53SAndroid Build Coastguard Worker 
rtnl_route_get_scope(struct rtnl_route * route)683*4dc78e53SAndroid Build Coastguard Worker uint8_t rtnl_route_get_scope(struct rtnl_route *route)
684*4dc78e53SAndroid Build Coastguard Worker {
685*4dc78e53SAndroid Build Coastguard Worker 	return route->rt_scope;
686*4dc78e53SAndroid Build Coastguard Worker }
687*4dc78e53SAndroid Build Coastguard Worker 
rtnl_route_set_tos(struct rtnl_route * route,uint8_t tos)688*4dc78e53SAndroid Build Coastguard Worker void rtnl_route_set_tos(struct rtnl_route *route, uint8_t tos)
689*4dc78e53SAndroid Build Coastguard Worker {
690*4dc78e53SAndroid Build Coastguard Worker 	route->rt_tos = tos;
691*4dc78e53SAndroid Build Coastguard Worker 	route->ce_mask |= ROUTE_ATTR_TOS;
692*4dc78e53SAndroid Build Coastguard Worker }
693*4dc78e53SAndroid Build Coastguard Worker 
rtnl_route_get_tos(struct rtnl_route * route)694*4dc78e53SAndroid Build Coastguard Worker uint8_t rtnl_route_get_tos(struct rtnl_route *route)
695*4dc78e53SAndroid Build Coastguard Worker {
696*4dc78e53SAndroid Build Coastguard Worker 	return route->rt_tos;
697*4dc78e53SAndroid Build Coastguard Worker }
698*4dc78e53SAndroid Build Coastguard Worker 
rtnl_route_set_protocol(struct rtnl_route * route,uint8_t protocol)699*4dc78e53SAndroid Build Coastguard Worker void rtnl_route_set_protocol(struct rtnl_route *route, uint8_t protocol)
700*4dc78e53SAndroid Build Coastguard Worker {
701*4dc78e53SAndroid Build Coastguard Worker 	route->rt_protocol = protocol;
702*4dc78e53SAndroid Build Coastguard Worker 	route->ce_mask |= ROUTE_ATTR_PROTOCOL;
703*4dc78e53SAndroid Build Coastguard Worker }
704*4dc78e53SAndroid Build Coastguard Worker 
rtnl_route_get_protocol(struct rtnl_route * route)705*4dc78e53SAndroid Build Coastguard Worker uint8_t rtnl_route_get_protocol(struct rtnl_route *route)
706*4dc78e53SAndroid Build Coastguard Worker {
707*4dc78e53SAndroid Build Coastguard Worker 	return route->rt_protocol;
708*4dc78e53SAndroid Build Coastguard Worker }
709*4dc78e53SAndroid Build Coastguard Worker 
rtnl_route_set_priority(struct rtnl_route * route,uint32_t prio)710*4dc78e53SAndroid Build Coastguard Worker void rtnl_route_set_priority(struct rtnl_route *route, uint32_t prio)
711*4dc78e53SAndroid Build Coastguard Worker {
712*4dc78e53SAndroid Build Coastguard Worker 	route->rt_prio = prio;
713*4dc78e53SAndroid Build Coastguard Worker 	route->ce_mask |= ROUTE_ATTR_PRIO;
714*4dc78e53SAndroid Build Coastguard Worker }
715*4dc78e53SAndroid Build Coastguard Worker 
rtnl_route_get_priority(struct rtnl_route * route)716*4dc78e53SAndroid Build Coastguard Worker uint32_t rtnl_route_get_priority(struct rtnl_route *route)
717*4dc78e53SAndroid Build Coastguard Worker {
718*4dc78e53SAndroid Build Coastguard Worker 	return route->rt_prio;
719*4dc78e53SAndroid Build Coastguard Worker }
720*4dc78e53SAndroid Build Coastguard Worker 
rtnl_route_set_family(struct rtnl_route * route,uint8_t family)721*4dc78e53SAndroid Build Coastguard Worker int rtnl_route_set_family(struct rtnl_route *route, uint8_t family)
722*4dc78e53SAndroid Build Coastguard Worker {
723*4dc78e53SAndroid Build Coastguard Worker 	switch(family) {
724*4dc78e53SAndroid Build Coastguard Worker 	case AF_INET:
725*4dc78e53SAndroid Build Coastguard Worker 	case AF_INET6:
726*4dc78e53SAndroid Build Coastguard Worker 	case AF_DECnet:
727*4dc78e53SAndroid Build Coastguard Worker 	case AF_MPLS:
728*4dc78e53SAndroid Build Coastguard Worker 		route->rt_family = family;
729*4dc78e53SAndroid Build Coastguard Worker 		route->ce_mask |= ROUTE_ATTR_FAMILY;
730*4dc78e53SAndroid Build Coastguard Worker 		return 0;
731*4dc78e53SAndroid Build Coastguard Worker 	}
732*4dc78e53SAndroid Build Coastguard Worker 
733*4dc78e53SAndroid Build Coastguard Worker 	return -NLE_AF_NOSUPPORT;
734*4dc78e53SAndroid Build Coastguard Worker }
735*4dc78e53SAndroid Build Coastguard Worker 
rtnl_route_get_family(struct rtnl_route * route)736*4dc78e53SAndroid Build Coastguard Worker uint8_t rtnl_route_get_family(struct rtnl_route *route)
737*4dc78e53SAndroid Build Coastguard Worker {
738*4dc78e53SAndroid Build Coastguard Worker 	return route->rt_family;
739*4dc78e53SAndroid Build Coastguard Worker }
740*4dc78e53SAndroid Build Coastguard Worker 
rtnl_route_set_dst(struct rtnl_route * route,struct nl_addr * addr)741*4dc78e53SAndroid Build Coastguard Worker int rtnl_route_set_dst(struct rtnl_route *route, struct nl_addr *addr)
742*4dc78e53SAndroid Build Coastguard Worker {
743*4dc78e53SAndroid Build Coastguard Worker 	if (route->ce_mask & ROUTE_ATTR_FAMILY) {
744*4dc78e53SAndroid Build Coastguard Worker 		if (addr->a_family != route->rt_family)
745*4dc78e53SAndroid Build Coastguard Worker 			return -NLE_AF_MISMATCH;
746*4dc78e53SAndroid Build Coastguard Worker 	} else
747*4dc78e53SAndroid Build Coastguard Worker 		route->rt_family = addr->a_family;
748*4dc78e53SAndroid Build Coastguard Worker 
749*4dc78e53SAndroid Build Coastguard Worker 	if (route->rt_dst)
750*4dc78e53SAndroid Build Coastguard Worker 		nl_addr_put(route->rt_dst);
751*4dc78e53SAndroid Build Coastguard Worker 
752*4dc78e53SAndroid Build Coastguard Worker 	nl_addr_get(addr);
753*4dc78e53SAndroid Build Coastguard Worker 	route->rt_dst = addr;
754*4dc78e53SAndroid Build Coastguard Worker 
755*4dc78e53SAndroid Build Coastguard Worker 	route->ce_mask |= (ROUTE_ATTR_DST | ROUTE_ATTR_FAMILY);
756*4dc78e53SAndroid Build Coastguard Worker 
757*4dc78e53SAndroid Build Coastguard Worker 	return 0;
758*4dc78e53SAndroid Build Coastguard Worker }
759*4dc78e53SAndroid Build Coastguard Worker 
rtnl_route_get_dst(struct rtnl_route * route)760*4dc78e53SAndroid Build Coastguard Worker struct nl_addr *rtnl_route_get_dst(struct rtnl_route *route)
761*4dc78e53SAndroid Build Coastguard Worker {
762*4dc78e53SAndroid Build Coastguard Worker 	return route->rt_dst;
763*4dc78e53SAndroid Build Coastguard Worker }
764*4dc78e53SAndroid Build Coastguard Worker 
rtnl_route_set_src(struct rtnl_route * route,struct nl_addr * addr)765*4dc78e53SAndroid Build Coastguard Worker int rtnl_route_set_src(struct rtnl_route *route, struct nl_addr *addr)
766*4dc78e53SAndroid Build Coastguard Worker {
767*4dc78e53SAndroid Build Coastguard Worker 	if (addr->a_family == AF_INET)
768*4dc78e53SAndroid Build Coastguard Worker 		return -NLE_SRCRT_NOSUPPORT;
769*4dc78e53SAndroid Build Coastguard Worker 
770*4dc78e53SAndroid Build Coastguard Worker 	if (route->ce_mask & ROUTE_ATTR_FAMILY) {
771*4dc78e53SAndroid Build Coastguard Worker 		if (addr->a_family != route->rt_family)
772*4dc78e53SAndroid Build Coastguard Worker 			return -NLE_AF_MISMATCH;
773*4dc78e53SAndroid Build Coastguard Worker 	} else
774*4dc78e53SAndroid Build Coastguard Worker 		route->rt_family = addr->a_family;
775*4dc78e53SAndroid Build Coastguard Worker 
776*4dc78e53SAndroid Build Coastguard Worker 	if (route->rt_src)
777*4dc78e53SAndroid Build Coastguard Worker 		nl_addr_put(route->rt_src);
778*4dc78e53SAndroid Build Coastguard Worker 
779*4dc78e53SAndroid Build Coastguard Worker 	nl_addr_get(addr);
780*4dc78e53SAndroid Build Coastguard Worker 	route->rt_src = addr;
781*4dc78e53SAndroid Build Coastguard Worker 	route->ce_mask |= (ROUTE_ATTR_SRC | ROUTE_ATTR_FAMILY);
782*4dc78e53SAndroid Build Coastguard Worker 
783*4dc78e53SAndroid Build Coastguard Worker 	return 0;
784*4dc78e53SAndroid Build Coastguard Worker }
785*4dc78e53SAndroid Build Coastguard Worker 
rtnl_route_get_src(struct rtnl_route * route)786*4dc78e53SAndroid Build Coastguard Worker struct nl_addr *rtnl_route_get_src(struct rtnl_route *route)
787*4dc78e53SAndroid Build Coastguard Worker {
788*4dc78e53SAndroid Build Coastguard Worker 	return route->rt_src;
789*4dc78e53SAndroid Build Coastguard Worker }
790*4dc78e53SAndroid Build Coastguard Worker 
rtnl_route_set_type(struct rtnl_route * route,uint8_t type)791*4dc78e53SAndroid Build Coastguard Worker int rtnl_route_set_type(struct rtnl_route *route, uint8_t type)
792*4dc78e53SAndroid Build Coastguard Worker {
793*4dc78e53SAndroid Build Coastguard Worker 	if (type > RTN_MAX)
794*4dc78e53SAndroid Build Coastguard Worker 		return -NLE_RANGE;
795*4dc78e53SAndroid Build Coastguard Worker 
796*4dc78e53SAndroid Build Coastguard Worker 	route->rt_type = type;
797*4dc78e53SAndroid Build Coastguard Worker 	route->ce_mask |= ROUTE_ATTR_TYPE;
798*4dc78e53SAndroid Build Coastguard Worker 
799*4dc78e53SAndroid Build Coastguard Worker 	return 0;
800*4dc78e53SAndroid Build Coastguard Worker }
801*4dc78e53SAndroid Build Coastguard Worker 
rtnl_route_get_type(struct rtnl_route * route)802*4dc78e53SAndroid Build Coastguard Worker uint8_t rtnl_route_get_type(struct rtnl_route *route)
803*4dc78e53SAndroid Build Coastguard Worker {
804*4dc78e53SAndroid Build Coastguard Worker 	return route->rt_type;
805*4dc78e53SAndroid Build Coastguard Worker }
806*4dc78e53SAndroid Build Coastguard Worker 
rtnl_route_set_flags(struct rtnl_route * route,uint32_t flags)807*4dc78e53SAndroid Build Coastguard Worker void rtnl_route_set_flags(struct rtnl_route *route, uint32_t flags)
808*4dc78e53SAndroid Build Coastguard Worker {
809*4dc78e53SAndroid Build Coastguard Worker 	route->rt_flag_mask |= flags;
810*4dc78e53SAndroid Build Coastguard Worker 	route->rt_flags |= flags;
811*4dc78e53SAndroid Build Coastguard Worker 	route->ce_mask |= ROUTE_ATTR_FLAGS;
812*4dc78e53SAndroid Build Coastguard Worker }
813*4dc78e53SAndroid Build Coastguard Worker 
rtnl_route_unset_flags(struct rtnl_route * route,uint32_t flags)814*4dc78e53SAndroid Build Coastguard Worker void rtnl_route_unset_flags(struct rtnl_route *route, uint32_t flags)
815*4dc78e53SAndroid Build Coastguard Worker {
816*4dc78e53SAndroid Build Coastguard Worker 	route->rt_flag_mask |= flags;
817*4dc78e53SAndroid Build Coastguard Worker 	route->rt_flags &= ~flags;
818*4dc78e53SAndroid Build Coastguard Worker 	route->ce_mask |= ROUTE_ATTR_FLAGS;
819*4dc78e53SAndroid Build Coastguard Worker }
820*4dc78e53SAndroid Build Coastguard Worker 
rtnl_route_get_flags(struct rtnl_route * route)821*4dc78e53SAndroid Build Coastguard Worker uint32_t rtnl_route_get_flags(struct rtnl_route *route)
822*4dc78e53SAndroid Build Coastguard Worker {
823*4dc78e53SAndroid Build Coastguard Worker 	return route->rt_flags;
824*4dc78e53SAndroid Build Coastguard Worker }
825*4dc78e53SAndroid Build Coastguard Worker 
rtnl_route_set_metric(struct rtnl_route * route,int metric,uint32_t value)826*4dc78e53SAndroid Build Coastguard Worker int rtnl_route_set_metric(struct rtnl_route *route, int metric, uint32_t value)
827*4dc78e53SAndroid Build Coastguard Worker {
828*4dc78e53SAndroid Build Coastguard Worker 	if (metric > RTAX_MAX || metric < 1)
829*4dc78e53SAndroid Build Coastguard Worker 		return -NLE_RANGE;
830*4dc78e53SAndroid Build Coastguard Worker 
831*4dc78e53SAndroid Build Coastguard Worker 	route->rt_metrics[metric - 1] = value;
832*4dc78e53SAndroid Build Coastguard Worker 
833*4dc78e53SAndroid Build Coastguard Worker 	if (!(route->rt_metrics_mask & (1 << (metric - 1)))) {
834*4dc78e53SAndroid Build Coastguard Worker 		route->rt_nmetrics++;
835*4dc78e53SAndroid Build Coastguard Worker 		route->rt_metrics_mask |= (1 << (metric - 1));
836*4dc78e53SAndroid Build Coastguard Worker 	}
837*4dc78e53SAndroid Build Coastguard Worker 
838*4dc78e53SAndroid Build Coastguard Worker 	route->ce_mask |= ROUTE_ATTR_METRICS;
839*4dc78e53SAndroid Build Coastguard Worker 
840*4dc78e53SAndroid Build Coastguard Worker 	return 0;
841*4dc78e53SAndroid Build Coastguard Worker }
842*4dc78e53SAndroid Build Coastguard Worker 
rtnl_route_unset_metric(struct rtnl_route * route,int metric)843*4dc78e53SAndroid Build Coastguard Worker int rtnl_route_unset_metric(struct rtnl_route *route, int metric)
844*4dc78e53SAndroid Build Coastguard Worker {
845*4dc78e53SAndroid Build Coastguard Worker 	if (metric > RTAX_MAX || metric < 1)
846*4dc78e53SAndroid Build Coastguard Worker 		return -NLE_RANGE;
847*4dc78e53SAndroid Build Coastguard Worker 
848*4dc78e53SAndroid Build Coastguard Worker 	if (route->rt_metrics_mask & (1 << (metric - 1))) {
849*4dc78e53SAndroid Build Coastguard Worker 		route->rt_nmetrics--;
850*4dc78e53SAndroid Build Coastguard Worker 		route->rt_metrics_mask &= ~(1 << (metric - 1));
851*4dc78e53SAndroid Build Coastguard Worker 	}
852*4dc78e53SAndroid Build Coastguard Worker 
853*4dc78e53SAndroid Build Coastguard Worker 	return 0;
854*4dc78e53SAndroid Build Coastguard Worker }
855*4dc78e53SAndroid Build Coastguard Worker 
rtnl_route_get_metric(struct rtnl_route * route,int metric,uint32_t * value)856*4dc78e53SAndroid Build Coastguard Worker int rtnl_route_get_metric(struct rtnl_route *route, int metric, uint32_t *value)
857*4dc78e53SAndroid Build Coastguard Worker {
858*4dc78e53SAndroid Build Coastguard Worker 	if (metric > RTAX_MAX || metric < 1)
859*4dc78e53SAndroid Build Coastguard Worker 		return -NLE_RANGE;
860*4dc78e53SAndroid Build Coastguard Worker 
861*4dc78e53SAndroid Build Coastguard Worker 	if (!(route->rt_metrics_mask & (1 << (metric - 1))))
862*4dc78e53SAndroid Build Coastguard Worker 		return -NLE_OBJ_NOTFOUND;
863*4dc78e53SAndroid Build Coastguard Worker 
864*4dc78e53SAndroid Build Coastguard Worker 	if (value)
865*4dc78e53SAndroid Build Coastguard Worker 		*value = route->rt_metrics[metric - 1];
866*4dc78e53SAndroid Build Coastguard Worker 
867*4dc78e53SAndroid Build Coastguard Worker 	return 0;
868*4dc78e53SAndroid Build Coastguard Worker }
869*4dc78e53SAndroid Build Coastguard Worker 
rtnl_route_set_pref_src(struct rtnl_route * route,struct nl_addr * addr)870*4dc78e53SAndroid Build Coastguard Worker int rtnl_route_set_pref_src(struct rtnl_route *route, struct nl_addr *addr)
871*4dc78e53SAndroid Build Coastguard Worker {
872*4dc78e53SAndroid Build Coastguard Worker 	if (route->ce_mask & ROUTE_ATTR_FAMILY) {
873*4dc78e53SAndroid Build Coastguard Worker 		if (addr->a_family != route->rt_family)
874*4dc78e53SAndroid Build Coastguard Worker 			return -NLE_AF_MISMATCH;
875*4dc78e53SAndroid Build Coastguard Worker 	} else
876*4dc78e53SAndroid Build Coastguard Worker 		route->rt_family = addr->a_family;
877*4dc78e53SAndroid Build Coastguard Worker 
878*4dc78e53SAndroid Build Coastguard Worker 	if (route->rt_pref_src)
879*4dc78e53SAndroid Build Coastguard Worker 		nl_addr_put(route->rt_pref_src);
880*4dc78e53SAndroid Build Coastguard Worker 
881*4dc78e53SAndroid Build Coastguard Worker 	nl_addr_get(addr);
882*4dc78e53SAndroid Build Coastguard Worker 	route->rt_pref_src = addr;
883*4dc78e53SAndroid Build Coastguard Worker 	route->ce_mask |= (ROUTE_ATTR_PREF_SRC | ROUTE_ATTR_FAMILY);
884*4dc78e53SAndroid Build Coastguard Worker 
885*4dc78e53SAndroid Build Coastguard Worker 	return 0;
886*4dc78e53SAndroid Build Coastguard Worker }
887*4dc78e53SAndroid Build Coastguard Worker 
rtnl_route_get_pref_src(struct rtnl_route * route)888*4dc78e53SAndroid Build Coastguard Worker struct nl_addr *rtnl_route_get_pref_src(struct rtnl_route *route)
889*4dc78e53SAndroid Build Coastguard Worker {
890*4dc78e53SAndroid Build Coastguard Worker 	return route->rt_pref_src;
891*4dc78e53SAndroid Build Coastguard Worker }
892*4dc78e53SAndroid Build Coastguard Worker 
rtnl_route_set_iif(struct rtnl_route * route,int ifindex)893*4dc78e53SAndroid Build Coastguard Worker void rtnl_route_set_iif(struct rtnl_route *route, int ifindex)
894*4dc78e53SAndroid Build Coastguard Worker {
895*4dc78e53SAndroid Build Coastguard Worker 	route->rt_iif = ifindex;
896*4dc78e53SAndroid Build Coastguard Worker 	route->ce_mask |= ROUTE_ATTR_IIF;
897*4dc78e53SAndroid Build Coastguard Worker }
898*4dc78e53SAndroid Build Coastguard Worker 
rtnl_route_get_iif(struct rtnl_route * route)899*4dc78e53SAndroid Build Coastguard Worker int rtnl_route_get_iif(struct rtnl_route *route)
900*4dc78e53SAndroid Build Coastguard Worker {
901*4dc78e53SAndroid Build Coastguard Worker 	return route->rt_iif;
902*4dc78e53SAndroid Build Coastguard Worker }
903*4dc78e53SAndroid Build Coastguard Worker 
rtnl_route_add_nexthop(struct rtnl_route * route,struct rtnl_nexthop * nh)904*4dc78e53SAndroid Build Coastguard Worker void rtnl_route_add_nexthop(struct rtnl_route *route, struct rtnl_nexthop *nh)
905*4dc78e53SAndroid Build Coastguard Worker {
906*4dc78e53SAndroid Build Coastguard Worker 	nl_list_add_tail(&nh->rtnh_list, &route->rt_nexthops);
907*4dc78e53SAndroid Build Coastguard Worker 	route->rt_nr_nh++;
908*4dc78e53SAndroid Build Coastguard Worker 	route->ce_mask |= ROUTE_ATTR_MULTIPATH;
909*4dc78e53SAndroid Build Coastguard Worker }
910*4dc78e53SAndroid Build Coastguard Worker 
rtnl_route_remove_nexthop(struct rtnl_route * route,struct rtnl_nexthop * nh)911*4dc78e53SAndroid Build Coastguard Worker void rtnl_route_remove_nexthop(struct rtnl_route *route, struct rtnl_nexthop *nh)
912*4dc78e53SAndroid Build Coastguard Worker {
913*4dc78e53SAndroid Build Coastguard Worker 	if (route->ce_mask & ROUTE_ATTR_MULTIPATH) {
914*4dc78e53SAndroid Build Coastguard Worker 		route->rt_nr_nh--;
915*4dc78e53SAndroid Build Coastguard Worker 		nl_list_del(&nh->rtnh_list);
916*4dc78e53SAndroid Build Coastguard Worker 	}
917*4dc78e53SAndroid Build Coastguard Worker }
918*4dc78e53SAndroid Build Coastguard Worker 
rtnl_route_get_nexthops(struct rtnl_route * route)919*4dc78e53SAndroid Build Coastguard Worker struct nl_list_head *rtnl_route_get_nexthops(struct rtnl_route *route)
920*4dc78e53SAndroid Build Coastguard Worker {
921*4dc78e53SAndroid Build Coastguard Worker 	if (route->ce_mask & ROUTE_ATTR_MULTIPATH)
922*4dc78e53SAndroid Build Coastguard Worker 		return &route->rt_nexthops;
923*4dc78e53SAndroid Build Coastguard Worker 
924*4dc78e53SAndroid Build Coastguard Worker 	return NULL;
925*4dc78e53SAndroid Build Coastguard Worker }
926*4dc78e53SAndroid Build Coastguard Worker 
rtnl_route_get_nnexthops(struct rtnl_route * route)927*4dc78e53SAndroid Build Coastguard Worker int rtnl_route_get_nnexthops(struct rtnl_route *route)
928*4dc78e53SAndroid Build Coastguard Worker {
929*4dc78e53SAndroid Build Coastguard Worker 	if (route->ce_mask & ROUTE_ATTR_MULTIPATH)
930*4dc78e53SAndroid Build Coastguard Worker 		return route->rt_nr_nh;
931*4dc78e53SAndroid Build Coastguard Worker 
932*4dc78e53SAndroid Build Coastguard Worker 	return 0;
933*4dc78e53SAndroid Build Coastguard Worker }
934*4dc78e53SAndroid Build Coastguard Worker 
rtnl_route_foreach_nexthop(struct rtnl_route * r,void (* cb)(struct rtnl_nexthop *,void *),void * arg)935*4dc78e53SAndroid Build Coastguard Worker void rtnl_route_foreach_nexthop(struct rtnl_route *r,
936*4dc78e53SAndroid Build Coastguard Worker                                 void (*cb)(struct rtnl_nexthop *, void *),
937*4dc78e53SAndroid Build Coastguard Worker                                 void *arg)
938*4dc78e53SAndroid Build Coastguard Worker {
939*4dc78e53SAndroid Build Coastguard Worker 	struct rtnl_nexthop *nh;
940*4dc78e53SAndroid Build Coastguard Worker 
941*4dc78e53SAndroid Build Coastguard Worker 	if (r->ce_mask & ROUTE_ATTR_MULTIPATH) {
942*4dc78e53SAndroid Build Coastguard Worker 		nl_list_for_each_entry(nh, &r->rt_nexthops, rtnh_list) {
943*4dc78e53SAndroid Build Coastguard Worker 			cb(nh, arg);
944*4dc78e53SAndroid Build Coastguard Worker 		}
945*4dc78e53SAndroid Build Coastguard Worker 	}
946*4dc78e53SAndroid Build Coastguard Worker }
947*4dc78e53SAndroid Build Coastguard Worker 
rtnl_route_nexthop_n(struct rtnl_route * r,int n)948*4dc78e53SAndroid Build Coastguard Worker struct rtnl_nexthop *rtnl_route_nexthop_n(struct rtnl_route *r, int n)
949*4dc78e53SAndroid Build Coastguard Worker {
950*4dc78e53SAndroid Build Coastguard Worker 	struct rtnl_nexthop *nh;
951*4dc78e53SAndroid Build Coastguard Worker 
952*4dc78e53SAndroid Build Coastguard Worker 	if (r->ce_mask & ROUTE_ATTR_MULTIPATH && n >= 0 &&
953*4dc78e53SAndroid Build Coastguard Worker 	    ((unsigned)n) < r->rt_nr_nh) {
954*4dc78e53SAndroid Build Coastguard Worker 		int i;
955*4dc78e53SAndroid Build Coastguard Worker 
956*4dc78e53SAndroid Build Coastguard Worker 		i = 0;
957*4dc78e53SAndroid Build Coastguard Worker 		nl_list_for_each_entry(nh, &r->rt_nexthops, rtnh_list) {
958*4dc78e53SAndroid Build Coastguard Worker 			if (i == n) return nh;
959*4dc78e53SAndroid Build Coastguard Worker 			i++;
960*4dc78e53SAndroid Build Coastguard Worker 		}
961*4dc78e53SAndroid Build Coastguard Worker 	}
962*4dc78e53SAndroid Build Coastguard Worker 	return NULL;
963*4dc78e53SAndroid Build Coastguard Worker }
964*4dc78e53SAndroid Build Coastguard Worker 
rtnl_route_set_ttl_propagate(struct rtnl_route * route,uint8_t ttl_prop)965*4dc78e53SAndroid Build Coastguard Worker void rtnl_route_set_ttl_propagate(struct rtnl_route *route, uint8_t ttl_prop)
966*4dc78e53SAndroid Build Coastguard Worker {
967*4dc78e53SAndroid Build Coastguard Worker 	route->rt_ttl_propagate = ttl_prop;
968*4dc78e53SAndroid Build Coastguard Worker 	route->ce_mask |= ROUTE_ATTR_TTL_PROPAGATE;
969*4dc78e53SAndroid Build Coastguard Worker }
970*4dc78e53SAndroid Build Coastguard Worker 
rtnl_route_get_ttl_propagate(struct rtnl_route * route)971*4dc78e53SAndroid Build Coastguard Worker int rtnl_route_get_ttl_propagate(struct rtnl_route *route)
972*4dc78e53SAndroid Build Coastguard Worker {
973*4dc78e53SAndroid Build Coastguard Worker 	if (!route)
974*4dc78e53SAndroid Build Coastguard Worker 		return -NLE_INVAL;
975*4dc78e53SAndroid Build Coastguard Worker 	if (!(route->ce_mask & ROUTE_ATTR_TTL_PROPAGATE))
976*4dc78e53SAndroid Build Coastguard Worker 		return -NLE_MISSING_ATTR;
977*4dc78e53SAndroid Build Coastguard Worker 	return route->rt_ttl_propagate;
978*4dc78e53SAndroid Build Coastguard Worker }
979*4dc78e53SAndroid Build Coastguard Worker 
rtnl_route_set_nhid(struct rtnl_route * route,uint32_t nhid)980*4dc78e53SAndroid Build Coastguard Worker void rtnl_route_set_nhid(struct rtnl_route *route, uint32_t nhid)
981*4dc78e53SAndroid Build Coastguard Worker {
982*4dc78e53SAndroid Build Coastguard Worker 	route->rt_nhid = nhid;
983*4dc78e53SAndroid Build Coastguard Worker 
984*4dc78e53SAndroid Build Coastguard Worker 	if (nhid > 0)
985*4dc78e53SAndroid Build Coastguard Worker 		route->ce_mask |= ROUTE_ATTR_NHID;
986*4dc78e53SAndroid Build Coastguard Worker 	else
987*4dc78e53SAndroid Build Coastguard Worker 		route->ce_mask &= ~ROUTE_ATTR_NHID;
988*4dc78e53SAndroid Build Coastguard Worker }
989*4dc78e53SAndroid Build Coastguard Worker 
rtnl_route_get_nhid(struct rtnl_route * route)990*4dc78e53SAndroid Build Coastguard Worker uint32_t rtnl_route_get_nhid(struct rtnl_route *route)
991*4dc78e53SAndroid Build Coastguard Worker {
992*4dc78e53SAndroid Build Coastguard Worker 	return route->rt_nhid;
993*4dc78e53SAndroid Build Coastguard Worker }
994*4dc78e53SAndroid Build Coastguard Worker 
995*4dc78e53SAndroid Build Coastguard Worker /** @} */
996*4dc78e53SAndroid Build Coastguard Worker 
997*4dc78e53SAndroid Build Coastguard Worker /**
998*4dc78e53SAndroid Build Coastguard Worker  * @name Utilities
999*4dc78e53SAndroid Build Coastguard Worker  * @{
1000*4dc78e53SAndroid Build Coastguard Worker  */
1001*4dc78e53SAndroid Build Coastguard Worker 
1002*4dc78e53SAndroid Build Coastguard Worker /**
1003*4dc78e53SAndroid Build Coastguard Worker  * Guess scope of a route object.
1004*4dc78e53SAndroid Build Coastguard Worker  * @arg route		Route object.
1005*4dc78e53SAndroid Build Coastguard Worker  *
1006*4dc78e53SAndroid Build Coastguard Worker  * Guesses the scope of a route object, based on the following rules:
1007*4dc78e53SAndroid Build Coastguard Worker  * @code
1008*4dc78e53SAndroid Build Coastguard Worker  *   1) Local route -> local scope
1009*4dc78e53SAndroid Build Coastguard Worker  *   2) At least one nexthop not directly connected -> universe scope
1010*4dc78e53SAndroid Build Coastguard Worker  *   3) All others -> link scope
1011*4dc78e53SAndroid Build Coastguard Worker  * @endcode
1012*4dc78e53SAndroid Build Coastguard Worker  *
1013*4dc78e53SAndroid Build Coastguard Worker  * @return Scope value.
1014*4dc78e53SAndroid Build Coastguard Worker  */
rtnl_route_guess_scope(struct rtnl_route * route)1015*4dc78e53SAndroid Build Coastguard Worker int rtnl_route_guess_scope(struct rtnl_route *route)
1016*4dc78e53SAndroid Build Coastguard Worker {
1017*4dc78e53SAndroid Build Coastguard Worker 	if (route->rt_type == RTN_LOCAL)
1018*4dc78e53SAndroid Build Coastguard Worker 		return RT_SCOPE_HOST;
1019*4dc78e53SAndroid Build Coastguard Worker 
1020*4dc78e53SAndroid Build Coastguard Worker 	if (route->rt_family == AF_MPLS)
1021*4dc78e53SAndroid Build Coastguard Worker 		return RT_SCOPE_UNIVERSE;
1022*4dc78e53SAndroid Build Coastguard Worker 
1023*4dc78e53SAndroid Build Coastguard Worker 	if (!nl_list_empty(&route->rt_nexthops)) {
1024*4dc78e53SAndroid Build Coastguard Worker 		struct rtnl_nexthop *nh;
1025*4dc78e53SAndroid Build Coastguard Worker 
1026*4dc78e53SAndroid Build Coastguard Worker 		/*
1027*4dc78e53SAndroid Build Coastguard Worker 		 * Use scope uiniverse if there is at least one nexthop which
1028*4dc78e53SAndroid Build Coastguard Worker 		 * is not directly connected
1029*4dc78e53SAndroid Build Coastguard Worker 		 */
1030*4dc78e53SAndroid Build Coastguard Worker 		nl_list_for_each_entry(nh, &route->rt_nexthops, rtnh_list) {
1031*4dc78e53SAndroid Build Coastguard Worker 			if (nh->rtnh_gateway || nh->rtnh_via)
1032*4dc78e53SAndroid Build Coastguard Worker 				return RT_SCOPE_UNIVERSE;
1033*4dc78e53SAndroid Build Coastguard Worker 		}
1034*4dc78e53SAndroid Build Coastguard Worker 	}
1035*4dc78e53SAndroid Build Coastguard Worker 
1036*4dc78e53SAndroid Build Coastguard Worker 	return RT_SCOPE_LINK;
1037*4dc78e53SAndroid Build Coastguard Worker }
1038*4dc78e53SAndroid Build Coastguard Worker 
1039*4dc78e53SAndroid Build Coastguard Worker /** @} */
1040*4dc78e53SAndroid Build Coastguard Worker 
rtnl_route_parse_via(struct nlattr * nla)1041*4dc78e53SAndroid Build Coastguard Worker static struct nl_addr *rtnl_route_parse_via(struct nlattr *nla)
1042*4dc78e53SAndroid Build Coastguard Worker {
1043*4dc78e53SAndroid Build Coastguard Worker 	int alen = nla_len(nla) - offsetof(struct rtvia, rtvia_addr);
1044*4dc78e53SAndroid Build Coastguard Worker 	struct rtvia *via = nla_data(nla);
1045*4dc78e53SAndroid Build Coastguard Worker 
1046*4dc78e53SAndroid Build Coastguard Worker 	return nl_addr_build(via->rtvia_family, via->rtvia_addr, alen);
1047*4dc78e53SAndroid Build Coastguard Worker }
1048*4dc78e53SAndroid Build Coastguard Worker 
rtnl_route_put_via(struct nl_msg * msg,struct nl_addr * addr)1049*4dc78e53SAndroid Build Coastguard Worker static int rtnl_route_put_via(struct nl_msg *msg, struct nl_addr *addr)
1050*4dc78e53SAndroid Build Coastguard Worker {
1051*4dc78e53SAndroid Build Coastguard Worker 	unsigned int alen = nl_addr_get_len(addr);
1052*4dc78e53SAndroid Build Coastguard Worker 	struct nlattr *nla;
1053*4dc78e53SAndroid Build Coastguard Worker 	struct rtvia *via;
1054*4dc78e53SAndroid Build Coastguard Worker 
1055*4dc78e53SAndroid Build Coastguard Worker 	nla = nla_reserve(msg, RTA_VIA, alen + sizeof(*via));
1056*4dc78e53SAndroid Build Coastguard Worker 	if (!nla)
1057*4dc78e53SAndroid Build Coastguard Worker 		return -EMSGSIZE;
1058*4dc78e53SAndroid Build Coastguard Worker 
1059*4dc78e53SAndroid Build Coastguard Worker 	via = nla_data(nla);
1060*4dc78e53SAndroid Build Coastguard Worker 	via->rtvia_family = nl_addr_get_family(addr);
1061*4dc78e53SAndroid Build Coastguard Worker 	memcpy(via->rtvia_addr, nl_addr_get_binary_addr(addr), alen);
1062*4dc78e53SAndroid Build Coastguard Worker 
1063*4dc78e53SAndroid Build Coastguard Worker 	return 0;
1064*4dc78e53SAndroid Build Coastguard Worker }
1065*4dc78e53SAndroid Build Coastguard Worker 
1066*4dc78e53SAndroid Build Coastguard Worker static struct nla_policy route_policy[RTA_MAX+1] = {
1067*4dc78e53SAndroid Build Coastguard Worker 	[RTA_IIF]	= { .type = NLA_U32 },
1068*4dc78e53SAndroid Build Coastguard Worker 	[RTA_OIF]	= { .type = NLA_U32 },
1069*4dc78e53SAndroid Build Coastguard Worker 	[RTA_PRIORITY]	= { .type = NLA_U32 },
1070*4dc78e53SAndroid Build Coastguard Worker 	[RTA_FLOW]	= { .type = NLA_U32 },
1071*4dc78e53SAndroid Build Coastguard Worker 	[RTA_CACHEINFO]	= { .minlen = sizeof(struct rta_cacheinfo) },
1072*4dc78e53SAndroid Build Coastguard Worker 	[RTA_METRICS]	= { .type = NLA_NESTED },
1073*4dc78e53SAndroid Build Coastguard Worker 	[RTA_MULTIPATH]	= { .type = NLA_NESTED },
1074*4dc78e53SAndroid Build Coastguard Worker 	[RTA_TTL_PROPAGATE] = { .type = NLA_U8 },
1075*4dc78e53SAndroid Build Coastguard Worker 	[RTA_ENCAP]	= { .type = NLA_NESTED },
1076*4dc78e53SAndroid Build Coastguard Worker 	[RTA_ENCAP_TYPE] = { .type = NLA_U16 },
1077*4dc78e53SAndroid Build Coastguard Worker 	[RTA_NH_ID]	= { .type = NLA_U32 },
1078*4dc78e53SAndroid Build Coastguard Worker };
1079*4dc78e53SAndroid Build Coastguard Worker 
parse_multipath(struct rtnl_route * route,struct nlattr * attr)1080*4dc78e53SAndroid Build Coastguard Worker static int parse_multipath(struct rtnl_route *route, struct nlattr *attr)
1081*4dc78e53SAndroid Build Coastguard Worker {
1082*4dc78e53SAndroid Build Coastguard Worker 	struct rtnexthop *rtnh = nla_data(attr);
1083*4dc78e53SAndroid Build Coastguard Worker 	size_t tlen = nla_len(attr);
1084*4dc78e53SAndroid Build Coastguard Worker 	int err;
1085*4dc78e53SAndroid Build Coastguard Worker 
1086*4dc78e53SAndroid Build Coastguard Worker 	while (tlen >= sizeof(*rtnh) && tlen >= rtnh->rtnh_len) {
1087*4dc78e53SAndroid Build Coastguard Worker 		_nl_auto_rtnl_nexthop struct rtnl_nexthop *nh = NULL;
1088*4dc78e53SAndroid Build Coastguard Worker 
1089*4dc78e53SAndroid Build Coastguard Worker 		nh = rtnl_route_nh_alloc();
1090*4dc78e53SAndroid Build Coastguard Worker 		if (!nh)
1091*4dc78e53SAndroid Build Coastguard Worker 			return -NLE_NOMEM;
1092*4dc78e53SAndroid Build Coastguard Worker 
1093*4dc78e53SAndroid Build Coastguard Worker 		rtnl_route_nh_set_weight(nh, rtnh->rtnh_hops);
1094*4dc78e53SAndroid Build Coastguard Worker 		rtnl_route_nh_set_ifindex(nh, rtnh->rtnh_ifindex);
1095*4dc78e53SAndroid Build Coastguard Worker 		rtnl_route_nh_set_flags(nh, rtnh->rtnh_flags);
1096*4dc78e53SAndroid Build Coastguard Worker 
1097*4dc78e53SAndroid Build Coastguard Worker 		if (rtnh->rtnh_len > sizeof(*rtnh)) {
1098*4dc78e53SAndroid Build Coastguard Worker 			struct nlattr *ntb[RTA_MAX + 1];
1099*4dc78e53SAndroid Build Coastguard Worker 
1100*4dc78e53SAndroid Build Coastguard Worker 			err = nla_parse(ntb, RTA_MAX, (struct nlattr *)
1101*4dc78e53SAndroid Build Coastguard Worker 					RTNH_DATA(rtnh),
1102*4dc78e53SAndroid Build Coastguard Worker 					rtnh->rtnh_len - sizeof(*rtnh),
1103*4dc78e53SAndroid Build Coastguard Worker 					route_policy);
1104*4dc78e53SAndroid Build Coastguard Worker 			if (err < 0)
1105*4dc78e53SAndroid Build Coastguard Worker 				return err;
1106*4dc78e53SAndroid Build Coastguard Worker 
1107*4dc78e53SAndroid Build Coastguard Worker 			if (ntb[RTA_GATEWAY]) {
1108*4dc78e53SAndroid Build Coastguard Worker 				_nl_auto_nl_addr struct nl_addr *addr = NULL;
1109*4dc78e53SAndroid Build Coastguard Worker 
1110*4dc78e53SAndroid Build Coastguard Worker 				addr = nl_addr_alloc_attr(ntb[RTA_GATEWAY],
1111*4dc78e53SAndroid Build Coastguard Worker 							  route->rt_family);
1112*4dc78e53SAndroid Build Coastguard Worker 				if (!addr)
1113*4dc78e53SAndroid Build Coastguard Worker 					return -NLE_NOMEM;
1114*4dc78e53SAndroid Build Coastguard Worker 
1115*4dc78e53SAndroid Build Coastguard Worker 				rtnl_route_nh_set_gateway(nh, addr);
1116*4dc78e53SAndroid Build Coastguard Worker 			}
1117*4dc78e53SAndroid Build Coastguard Worker 
1118*4dc78e53SAndroid Build Coastguard Worker 			if (ntb[RTA_FLOW]) {
1119*4dc78e53SAndroid Build Coastguard Worker 				uint32_t realms;
1120*4dc78e53SAndroid Build Coastguard Worker 
1121*4dc78e53SAndroid Build Coastguard Worker 				realms = nla_get_u32(ntb[RTA_FLOW]);
1122*4dc78e53SAndroid Build Coastguard Worker 				rtnl_route_nh_set_realms(nh, realms);
1123*4dc78e53SAndroid Build Coastguard Worker 			}
1124*4dc78e53SAndroid Build Coastguard Worker 
1125*4dc78e53SAndroid Build Coastguard Worker 			if (ntb[RTA_NEWDST]) {
1126*4dc78e53SAndroid Build Coastguard Worker 				_nl_auto_nl_addr struct nl_addr *addr = NULL;
1127*4dc78e53SAndroid Build Coastguard Worker 
1128*4dc78e53SAndroid Build Coastguard Worker 				addr = nl_addr_alloc_attr(ntb[RTA_NEWDST],
1129*4dc78e53SAndroid Build Coastguard Worker 							  route->rt_family);
1130*4dc78e53SAndroid Build Coastguard Worker 				if (!addr)
1131*4dc78e53SAndroid Build Coastguard Worker 					return -NLE_NOMEM;
1132*4dc78e53SAndroid Build Coastguard Worker 
1133*4dc78e53SAndroid Build Coastguard Worker 				err = rtnl_route_nh_set_newdst(nh, addr);
1134*4dc78e53SAndroid Build Coastguard Worker 				if (err < 0)
1135*4dc78e53SAndroid Build Coastguard Worker 					return err;
1136*4dc78e53SAndroid Build Coastguard Worker 			}
1137*4dc78e53SAndroid Build Coastguard Worker 
1138*4dc78e53SAndroid Build Coastguard Worker 			if (ntb[RTA_VIA]) {
1139*4dc78e53SAndroid Build Coastguard Worker 				_nl_auto_nl_addr struct nl_addr *addr = NULL;
1140*4dc78e53SAndroid Build Coastguard Worker 
1141*4dc78e53SAndroid Build Coastguard Worker 				addr = rtnl_route_parse_via(ntb[RTA_VIA]);
1142*4dc78e53SAndroid Build Coastguard Worker 				if (!addr)
1143*4dc78e53SAndroid Build Coastguard Worker 					return -NLE_NOMEM;
1144*4dc78e53SAndroid Build Coastguard Worker 
1145*4dc78e53SAndroid Build Coastguard Worker 				err = rtnl_route_nh_set_via(nh, addr);
1146*4dc78e53SAndroid Build Coastguard Worker 				if (err < 0)
1147*4dc78e53SAndroid Build Coastguard Worker 					return err;
1148*4dc78e53SAndroid Build Coastguard Worker 			}
1149*4dc78e53SAndroid Build Coastguard Worker 
1150*4dc78e53SAndroid Build Coastguard Worker 			if (ntb[RTA_ENCAP] && ntb[RTA_ENCAP_TYPE]) {
1151*4dc78e53SAndroid Build Coastguard Worker 				err = nh_encap_parse_msg(ntb[RTA_ENCAP],
1152*4dc78e53SAndroid Build Coastguard Worker 							 ntb[RTA_ENCAP_TYPE],
1153*4dc78e53SAndroid Build Coastguard Worker 							 nh);
1154*4dc78e53SAndroid Build Coastguard Worker 				if (err < 0)
1155*4dc78e53SAndroid Build Coastguard Worker 					return err;
1156*4dc78e53SAndroid Build Coastguard Worker 			}
1157*4dc78e53SAndroid Build Coastguard Worker 		}
1158*4dc78e53SAndroid Build Coastguard Worker 
1159*4dc78e53SAndroid Build Coastguard Worker 		rtnl_route_add_nexthop(route, _nl_steal_pointer(&nh));
1160*4dc78e53SAndroid Build Coastguard Worker 		tlen -= RTNH_ALIGN(rtnh->rtnh_len);
1161*4dc78e53SAndroid Build Coastguard Worker 		rtnh = RTNH_NEXT(rtnh);
1162*4dc78e53SAndroid Build Coastguard Worker 	}
1163*4dc78e53SAndroid Build Coastguard Worker 
1164*4dc78e53SAndroid Build Coastguard Worker 	return 0;
1165*4dc78e53SAndroid Build Coastguard Worker }
1166*4dc78e53SAndroid Build Coastguard Worker 
rtnl_route_parse(struct nlmsghdr * nlh,struct rtnl_route ** result)1167*4dc78e53SAndroid Build Coastguard Worker int rtnl_route_parse(struct nlmsghdr *nlh, struct rtnl_route **result)
1168*4dc78e53SAndroid Build Coastguard Worker {
1169*4dc78e53SAndroid Build Coastguard Worker 	_nl_auto_rtnl_route struct rtnl_route *route = NULL;
1170*4dc78e53SAndroid Build Coastguard Worker 	_nl_auto_rtnl_nexthop struct rtnl_nexthop *old_nh = NULL;
1171*4dc78e53SAndroid Build Coastguard Worker 	_nl_auto_nl_addr struct nl_addr *src = NULL;
1172*4dc78e53SAndroid Build Coastguard Worker 	_nl_auto_nl_addr struct nl_addr *dst = NULL;
1173*4dc78e53SAndroid Build Coastguard Worker 	struct nlattr *tb[RTA_MAX + 1];
1174*4dc78e53SAndroid Build Coastguard Worker 	struct rtmsg *rtm;
1175*4dc78e53SAndroid Build Coastguard Worker 	int family;
1176*4dc78e53SAndroid Build Coastguard Worker 	int err;
1177*4dc78e53SAndroid Build Coastguard Worker 
1178*4dc78e53SAndroid Build Coastguard Worker 	route = rtnl_route_alloc();
1179*4dc78e53SAndroid Build Coastguard Worker 	if (!route)
1180*4dc78e53SAndroid Build Coastguard Worker 		return -NLE_NOMEM;
1181*4dc78e53SAndroid Build Coastguard Worker 
1182*4dc78e53SAndroid Build Coastguard Worker 	route->ce_msgtype = nlh->nlmsg_type;
1183*4dc78e53SAndroid Build Coastguard Worker 
1184*4dc78e53SAndroid Build Coastguard Worker 	err = nlmsg_parse(nlh, sizeof(struct rtmsg), tb, RTA_MAX, route_policy);
1185*4dc78e53SAndroid Build Coastguard Worker 	if (err < 0)
1186*4dc78e53SAndroid Build Coastguard Worker 		return err;
1187*4dc78e53SAndroid Build Coastguard Worker 
1188*4dc78e53SAndroid Build Coastguard Worker 	rtm = nlmsg_data(nlh);
1189*4dc78e53SAndroid Build Coastguard Worker 	route->rt_family = family = rtm->rtm_family;
1190*4dc78e53SAndroid Build Coastguard Worker 	route->rt_tos = rtm->rtm_tos;
1191*4dc78e53SAndroid Build Coastguard Worker 	route->rt_table = rtm->rtm_table;
1192*4dc78e53SAndroid Build Coastguard Worker 	route->rt_type = rtm->rtm_type;
1193*4dc78e53SAndroid Build Coastguard Worker 	route->rt_scope = rtm->rtm_scope;
1194*4dc78e53SAndroid Build Coastguard Worker 	route->rt_protocol = rtm->rtm_protocol;
1195*4dc78e53SAndroid Build Coastguard Worker 	route->rt_flags = rtm->rtm_flags;
1196*4dc78e53SAndroid Build Coastguard Worker 	route->rt_prio = 0;
1197*4dc78e53SAndroid Build Coastguard Worker 
1198*4dc78e53SAndroid Build Coastguard Worker 	route->ce_mask |= ROUTE_ATTR_FAMILY | ROUTE_ATTR_TOS |
1199*4dc78e53SAndroid Build Coastguard Worker 			  ROUTE_ATTR_TABLE | ROUTE_ATTR_TYPE |
1200*4dc78e53SAndroid Build Coastguard Worker 			  ROUTE_ATTR_SCOPE | ROUTE_ATTR_PROTOCOL |
1201*4dc78e53SAndroid Build Coastguard Worker 			  ROUTE_ATTR_FLAGS;
1202*4dc78e53SAndroid Build Coastguard Worker 
1203*4dc78e53SAndroid Build Coastguard Worker 	/* right now MPLS does not allow rt_prio to be set, so don't
1204*4dc78e53SAndroid Build Coastguard Worker 	 * assume it is unless it comes from an attribute
1205*4dc78e53SAndroid Build Coastguard Worker 	 */
1206*4dc78e53SAndroid Build Coastguard Worker 	if (family != AF_MPLS)
1207*4dc78e53SAndroid Build Coastguard Worker 		route->ce_mask |= ROUTE_ATTR_PRIO;
1208*4dc78e53SAndroid Build Coastguard Worker 
1209*4dc78e53SAndroid Build Coastguard Worker 	if (tb[RTA_DST]) {
1210*4dc78e53SAndroid Build Coastguard Worker 		if (!(dst = nl_addr_alloc_attr(tb[RTA_DST], family)))
1211*4dc78e53SAndroid Build Coastguard Worker 			return -NLE_NOMEM;
1212*4dc78e53SAndroid Build Coastguard Worker 	} else {
1213*4dc78e53SAndroid Build Coastguard Worker 		int len;
1214*4dc78e53SAndroid Build Coastguard Worker 
1215*4dc78e53SAndroid Build Coastguard Worker 		switch (family) {
1216*4dc78e53SAndroid Build Coastguard Worker 			case AF_INET:
1217*4dc78e53SAndroid Build Coastguard Worker 				len = 4;
1218*4dc78e53SAndroid Build Coastguard Worker 				break;
1219*4dc78e53SAndroid Build Coastguard Worker 
1220*4dc78e53SAndroid Build Coastguard Worker 			case AF_INET6:
1221*4dc78e53SAndroid Build Coastguard Worker 				len = 16;
1222*4dc78e53SAndroid Build Coastguard Worker 				break;
1223*4dc78e53SAndroid Build Coastguard Worker 			default:
1224*4dc78e53SAndroid Build Coastguard Worker 				len = 0;
1225*4dc78e53SAndroid Build Coastguard Worker 				break;
1226*4dc78e53SAndroid Build Coastguard Worker 		}
1227*4dc78e53SAndroid Build Coastguard Worker 
1228*4dc78e53SAndroid Build Coastguard Worker 		if (!(dst = nl_addr_build(family, NULL, len)))
1229*4dc78e53SAndroid Build Coastguard Worker 			return -NLE_NOMEM;
1230*4dc78e53SAndroid Build Coastguard Worker 	}
1231*4dc78e53SAndroid Build Coastguard Worker 
1232*4dc78e53SAndroid Build Coastguard Worker 	nl_addr_set_prefixlen(dst, rtm->rtm_dst_len);
1233*4dc78e53SAndroid Build Coastguard Worker 	err = rtnl_route_set_dst(route, dst);
1234*4dc78e53SAndroid Build Coastguard Worker 	if (err < 0)
1235*4dc78e53SAndroid Build Coastguard Worker 		return err;
1236*4dc78e53SAndroid Build Coastguard Worker 
1237*4dc78e53SAndroid Build Coastguard Worker 	if (tb[RTA_SRC]) {
1238*4dc78e53SAndroid Build Coastguard Worker 		if (!(src = nl_addr_alloc_attr(tb[RTA_SRC], family)))
1239*4dc78e53SAndroid Build Coastguard Worker 			return -NLE_NOMEM;
1240*4dc78e53SAndroid Build Coastguard Worker 	} else if (rtm->rtm_src_len)
1241*4dc78e53SAndroid Build Coastguard Worker 		if (!(src = nl_addr_alloc(0)))
1242*4dc78e53SAndroid Build Coastguard Worker 			return -NLE_NOMEM;
1243*4dc78e53SAndroid Build Coastguard Worker 
1244*4dc78e53SAndroid Build Coastguard Worker 	if (src) {
1245*4dc78e53SAndroid Build Coastguard Worker 		nl_addr_set_prefixlen(src, rtm->rtm_src_len);
1246*4dc78e53SAndroid Build Coastguard Worker 		rtnl_route_set_src(route, src);
1247*4dc78e53SAndroid Build Coastguard Worker 	}
1248*4dc78e53SAndroid Build Coastguard Worker 
1249*4dc78e53SAndroid Build Coastguard Worker 	if (tb[RTA_TABLE])
1250*4dc78e53SAndroid Build Coastguard Worker 		rtnl_route_set_table(route, nla_get_u32(tb[RTA_TABLE]));
1251*4dc78e53SAndroid Build Coastguard Worker 
1252*4dc78e53SAndroid Build Coastguard Worker 	if (tb[RTA_IIF])
1253*4dc78e53SAndroid Build Coastguard Worker 		rtnl_route_set_iif(route, nla_get_u32(tb[RTA_IIF]));
1254*4dc78e53SAndroid Build Coastguard Worker 
1255*4dc78e53SAndroid Build Coastguard Worker 	if (tb[RTA_PRIORITY])
1256*4dc78e53SAndroid Build Coastguard Worker 		rtnl_route_set_priority(route, nla_get_u32(tb[RTA_PRIORITY]));
1257*4dc78e53SAndroid Build Coastguard Worker 
1258*4dc78e53SAndroid Build Coastguard Worker 	if (tb[RTA_PREFSRC]) {
1259*4dc78e53SAndroid Build Coastguard Worker 		_nl_auto_nl_addr struct nl_addr *addr = NULL;
1260*4dc78e53SAndroid Build Coastguard Worker 
1261*4dc78e53SAndroid Build Coastguard Worker 		if (!(addr = nl_addr_alloc_attr(tb[RTA_PREFSRC], family)))
1262*4dc78e53SAndroid Build Coastguard Worker 			return -NLE_NOMEM;
1263*4dc78e53SAndroid Build Coastguard Worker 		rtnl_route_set_pref_src(route, addr);
1264*4dc78e53SAndroid Build Coastguard Worker 	}
1265*4dc78e53SAndroid Build Coastguard Worker 
1266*4dc78e53SAndroid Build Coastguard Worker 	if (tb[RTA_METRICS]) {
1267*4dc78e53SAndroid Build Coastguard Worker 		struct nlattr *mtb[RTAX_MAX + 1];
1268*4dc78e53SAndroid Build Coastguard Worker 		int i;
1269*4dc78e53SAndroid Build Coastguard Worker 
1270*4dc78e53SAndroid Build Coastguard Worker 		err = nla_parse_nested(mtb, RTAX_MAX, tb[RTA_METRICS], NULL);
1271*4dc78e53SAndroid Build Coastguard Worker 		if (err < 0)
1272*4dc78e53SAndroid Build Coastguard Worker 			return err;
1273*4dc78e53SAndroid Build Coastguard Worker 
1274*4dc78e53SAndroid Build Coastguard Worker 		for (i = 1; i <= RTAX_MAX; i++) {
1275*4dc78e53SAndroid Build Coastguard Worker 			if (mtb[i] && _nla_len(mtb[i]) >= sizeof(uint32_t)) {
1276*4dc78e53SAndroid Build Coastguard Worker 				uint32_t m = nla_get_u32(mtb[i]);
1277*4dc78e53SAndroid Build Coastguard Worker 
1278*4dc78e53SAndroid Build Coastguard Worker 				err = rtnl_route_set_metric(route, i, m);
1279*4dc78e53SAndroid Build Coastguard Worker 				if (err < 0)
1280*4dc78e53SAndroid Build Coastguard Worker 					return err;
1281*4dc78e53SAndroid Build Coastguard Worker 			}
1282*4dc78e53SAndroid Build Coastguard Worker 		}
1283*4dc78e53SAndroid Build Coastguard Worker 	}
1284*4dc78e53SAndroid Build Coastguard Worker 
1285*4dc78e53SAndroid Build Coastguard Worker 	if (tb[RTA_MULTIPATH]) {
1286*4dc78e53SAndroid Build Coastguard Worker 		if ((err = parse_multipath(route, tb[RTA_MULTIPATH])) < 0)
1287*4dc78e53SAndroid Build Coastguard Worker 			return err;
1288*4dc78e53SAndroid Build Coastguard Worker 	}
1289*4dc78e53SAndroid Build Coastguard Worker 
1290*4dc78e53SAndroid Build Coastguard Worker 	if (tb[RTA_CACHEINFO]) {
1291*4dc78e53SAndroid Build Coastguard Worker 		nla_memcpy(&route->rt_cacheinfo, tb[RTA_CACHEINFO],
1292*4dc78e53SAndroid Build Coastguard Worker 			   sizeof(route->rt_cacheinfo));
1293*4dc78e53SAndroid Build Coastguard Worker 		route->ce_mask |= ROUTE_ATTR_CACHEINFO;
1294*4dc78e53SAndroid Build Coastguard Worker 	}
1295*4dc78e53SAndroid Build Coastguard Worker 
1296*4dc78e53SAndroid Build Coastguard Worker 	if (tb[RTA_OIF]) {
1297*4dc78e53SAndroid Build Coastguard Worker 		if (!old_nh && !(old_nh = rtnl_route_nh_alloc()))
1298*4dc78e53SAndroid Build Coastguard Worker 			return -NLE_NOMEM;
1299*4dc78e53SAndroid Build Coastguard Worker 
1300*4dc78e53SAndroid Build Coastguard Worker 		rtnl_route_nh_set_ifindex(old_nh, nla_get_u32(tb[RTA_OIF]));
1301*4dc78e53SAndroid Build Coastguard Worker 	}
1302*4dc78e53SAndroid Build Coastguard Worker 
1303*4dc78e53SAndroid Build Coastguard Worker 	if (tb[RTA_GATEWAY]) {
1304*4dc78e53SAndroid Build Coastguard Worker 		_nl_auto_nl_addr struct nl_addr *addr = NULL;
1305*4dc78e53SAndroid Build Coastguard Worker 
1306*4dc78e53SAndroid Build Coastguard Worker 		if (!old_nh && !(old_nh = rtnl_route_nh_alloc()))
1307*4dc78e53SAndroid Build Coastguard Worker 			return -NLE_NOMEM;
1308*4dc78e53SAndroid Build Coastguard Worker 
1309*4dc78e53SAndroid Build Coastguard Worker 		if (!(addr = nl_addr_alloc_attr(tb[RTA_GATEWAY], family)))
1310*4dc78e53SAndroid Build Coastguard Worker 			return -NLE_NOMEM;
1311*4dc78e53SAndroid Build Coastguard Worker 
1312*4dc78e53SAndroid Build Coastguard Worker 		rtnl_route_nh_set_gateway(old_nh, addr);
1313*4dc78e53SAndroid Build Coastguard Worker 	}
1314*4dc78e53SAndroid Build Coastguard Worker 
1315*4dc78e53SAndroid Build Coastguard Worker 	if (tb[RTA_FLOW]) {
1316*4dc78e53SAndroid Build Coastguard Worker 		if (!old_nh && !(old_nh = rtnl_route_nh_alloc()))
1317*4dc78e53SAndroid Build Coastguard Worker 			return -NLE_NOMEM;
1318*4dc78e53SAndroid Build Coastguard Worker 
1319*4dc78e53SAndroid Build Coastguard Worker 		rtnl_route_nh_set_realms(old_nh, nla_get_u32(tb[RTA_FLOW]));
1320*4dc78e53SAndroid Build Coastguard Worker 	}
1321*4dc78e53SAndroid Build Coastguard Worker 
1322*4dc78e53SAndroid Build Coastguard Worker 	if (tb[RTA_NEWDST]) {
1323*4dc78e53SAndroid Build Coastguard Worker 		_nl_auto_nl_addr struct nl_addr *addr = NULL;
1324*4dc78e53SAndroid Build Coastguard Worker 
1325*4dc78e53SAndroid Build Coastguard Worker 		if (!old_nh && !(old_nh = rtnl_route_nh_alloc()))
1326*4dc78e53SAndroid Build Coastguard Worker 			return -NLE_NOMEM;
1327*4dc78e53SAndroid Build Coastguard Worker 
1328*4dc78e53SAndroid Build Coastguard Worker 		addr = nl_addr_alloc_attr(tb[RTA_NEWDST], route->rt_family);
1329*4dc78e53SAndroid Build Coastguard Worker 		if (!addr)
1330*4dc78e53SAndroid Build Coastguard Worker 			return -NLE_NOMEM;
1331*4dc78e53SAndroid Build Coastguard Worker 
1332*4dc78e53SAndroid Build Coastguard Worker 		err = rtnl_route_nh_set_newdst(old_nh, addr);
1333*4dc78e53SAndroid Build Coastguard Worker 		if (err < 0)
1334*4dc78e53SAndroid Build Coastguard Worker 			return err;
1335*4dc78e53SAndroid Build Coastguard Worker 	}
1336*4dc78e53SAndroid Build Coastguard Worker 
1337*4dc78e53SAndroid Build Coastguard Worker 	if (tb[RTA_VIA]) {
1338*4dc78e53SAndroid Build Coastguard Worker 		int alen = nla_len(tb[RTA_VIA]) - offsetof(struct rtvia, rtvia_addr);
1339*4dc78e53SAndroid Build Coastguard Worker 		_nl_auto_nl_addr struct nl_addr *addr = NULL;
1340*4dc78e53SAndroid Build Coastguard Worker 		struct rtvia *via = nla_data(tb[RTA_VIA]);
1341*4dc78e53SAndroid Build Coastguard Worker 
1342*4dc78e53SAndroid Build Coastguard Worker 		if (!old_nh && !(old_nh = rtnl_route_nh_alloc()))
1343*4dc78e53SAndroid Build Coastguard Worker 			return -NLE_NOMEM;
1344*4dc78e53SAndroid Build Coastguard Worker 
1345*4dc78e53SAndroid Build Coastguard Worker 		addr = nl_addr_build(via->rtvia_family, via->rtvia_addr, alen);
1346*4dc78e53SAndroid Build Coastguard Worker 		if (!addr)
1347*4dc78e53SAndroid Build Coastguard Worker 			return -NLE_NOMEM;
1348*4dc78e53SAndroid Build Coastguard Worker 
1349*4dc78e53SAndroid Build Coastguard Worker 		err = rtnl_route_nh_set_via(old_nh, addr);
1350*4dc78e53SAndroid Build Coastguard Worker 		if (err < 0)
1351*4dc78e53SAndroid Build Coastguard Worker 			return err;
1352*4dc78e53SAndroid Build Coastguard Worker 	}
1353*4dc78e53SAndroid Build Coastguard Worker 
1354*4dc78e53SAndroid Build Coastguard Worker 	if (tb[RTA_TTL_PROPAGATE]) {
1355*4dc78e53SAndroid Build Coastguard Worker 		rtnl_route_set_ttl_propagate(route,
1356*4dc78e53SAndroid Build Coastguard Worker 					     nla_get_u8(tb[RTA_TTL_PROPAGATE]));
1357*4dc78e53SAndroid Build Coastguard Worker 	}
1358*4dc78e53SAndroid Build Coastguard Worker 
1359*4dc78e53SAndroid Build Coastguard Worker 	if (tb[RTA_ENCAP] && tb[RTA_ENCAP_TYPE]) {
1360*4dc78e53SAndroid Build Coastguard Worker 		if (!old_nh && !(old_nh = rtnl_route_nh_alloc()))
1361*4dc78e53SAndroid Build Coastguard Worker 			return -NLE_NOMEM;
1362*4dc78e53SAndroid Build Coastguard Worker 
1363*4dc78e53SAndroid Build Coastguard Worker 		err = nh_encap_parse_msg(tb[RTA_ENCAP],
1364*4dc78e53SAndroid Build Coastguard Worker 					 tb[RTA_ENCAP_TYPE], old_nh);
1365*4dc78e53SAndroid Build Coastguard Worker 		if (err < 0)
1366*4dc78e53SAndroid Build Coastguard Worker 			return err;
1367*4dc78e53SAndroid Build Coastguard Worker 	}
1368*4dc78e53SAndroid Build Coastguard Worker 
1369*4dc78e53SAndroid Build Coastguard Worker 	if (tb[RTA_NH_ID]) {
1370*4dc78e53SAndroid Build Coastguard Worker 		rtnl_route_set_nhid(route, nla_get_u32(tb[RTA_NH_ID]));
1371*4dc78e53SAndroid Build Coastguard Worker 	}
1372*4dc78e53SAndroid Build Coastguard Worker 
1373*4dc78e53SAndroid Build Coastguard Worker 	if (old_nh) {
1374*4dc78e53SAndroid Build Coastguard Worker 		rtnl_route_nh_set_flags(old_nh, rtm->rtm_flags & 0xff);
1375*4dc78e53SAndroid Build Coastguard Worker 		if (route->rt_nr_nh == 0) {
1376*4dc78e53SAndroid Build Coastguard Worker 			/* If no nexthops have been provided via RTA_MULTIPATH
1377*4dc78e53SAndroid Build Coastguard Worker 			 * we add it as regular nexthop to maintain backwards
1378*4dc78e53SAndroid Build Coastguard Worker 			 * compatibility */
1379*4dc78e53SAndroid Build Coastguard Worker 			rtnl_route_add_nexthop(route, _nl_steal_pointer(&old_nh));
1380*4dc78e53SAndroid Build Coastguard Worker 		} else {
1381*4dc78e53SAndroid Build Coastguard Worker 			/* Kernel supports new style nexthop configuration,
1382*4dc78e53SAndroid Build Coastguard Worker 			 * verify that it is a duplicate and discard nexthop. */
1383*4dc78e53SAndroid Build Coastguard Worker 			struct rtnl_nexthop *first;
1384*4dc78e53SAndroid Build Coastguard Worker 
1385*4dc78e53SAndroid Build Coastguard Worker 			first = nl_list_first_entry(&route->rt_nexthops,
1386*4dc78e53SAndroid Build Coastguard Worker 						    struct rtnl_nexthop,
1387*4dc78e53SAndroid Build Coastguard Worker 						    rtnh_list);
1388*4dc78e53SAndroid Build Coastguard Worker 			if (!first)
1389*4dc78e53SAndroid Build Coastguard Worker 				BUG();
1390*4dc78e53SAndroid Build Coastguard Worker 
1391*4dc78e53SAndroid Build Coastguard Worker 			if (rtnl_route_nh_compare(old_nh, first,
1392*4dc78e53SAndroid Build Coastguard Worker 						  old_nh->ce_mask, 0)) {
1393*4dc78e53SAndroid Build Coastguard Worker 				return -NLE_INVAL;
1394*4dc78e53SAndroid Build Coastguard Worker 			}
1395*4dc78e53SAndroid Build Coastguard Worker 		}
1396*4dc78e53SAndroid Build Coastguard Worker 	}
1397*4dc78e53SAndroid Build Coastguard Worker 
1398*4dc78e53SAndroid Build Coastguard Worker 	*result = _nl_steal_pointer(&route);
1399*4dc78e53SAndroid Build Coastguard Worker 	return 0;
1400*4dc78e53SAndroid Build Coastguard Worker }
1401*4dc78e53SAndroid Build Coastguard Worker 
rtnl_route_build_msg(struct nl_msg * msg,struct rtnl_route * route)1402*4dc78e53SAndroid Build Coastguard Worker int rtnl_route_build_msg(struct nl_msg *msg, struct rtnl_route *route)
1403*4dc78e53SAndroid Build Coastguard Worker {
1404*4dc78e53SAndroid Build Coastguard Worker 	int i;
1405*4dc78e53SAndroid Build Coastguard Worker 	struct nlattr *metrics;
1406*4dc78e53SAndroid Build Coastguard Worker 	struct rtmsg rtmsg = {
1407*4dc78e53SAndroid Build Coastguard Worker 		.rtm_family = route->rt_family,
1408*4dc78e53SAndroid Build Coastguard Worker 		.rtm_tos = route->rt_tos,
1409*4dc78e53SAndroid Build Coastguard Worker 		.rtm_table = route->rt_table,
1410*4dc78e53SAndroid Build Coastguard Worker 		.rtm_protocol = route->rt_protocol,
1411*4dc78e53SAndroid Build Coastguard Worker 		.rtm_scope = route->rt_scope,
1412*4dc78e53SAndroid Build Coastguard Worker 		.rtm_type = route->rt_type,
1413*4dc78e53SAndroid Build Coastguard Worker 		.rtm_flags = route->rt_flags,
1414*4dc78e53SAndroid Build Coastguard Worker 	};
1415*4dc78e53SAndroid Build Coastguard Worker 
1416*4dc78e53SAndroid Build Coastguard Worker 	if (route->rt_dst == NULL)
1417*4dc78e53SAndroid Build Coastguard Worker 		return -NLE_MISSING_ATTR;
1418*4dc78e53SAndroid Build Coastguard Worker 
1419*4dc78e53SAndroid Build Coastguard Worker 	rtmsg.rtm_dst_len = nl_addr_get_prefixlen(route->rt_dst);
1420*4dc78e53SAndroid Build Coastguard Worker 	if (route->rt_src)
1421*4dc78e53SAndroid Build Coastguard Worker 		rtmsg.rtm_src_len = nl_addr_get_prefixlen(route->rt_src);
1422*4dc78e53SAndroid Build Coastguard Worker 
1423*4dc78e53SAndroid Build Coastguard Worker 	if (!(route->ce_mask & ROUTE_ATTR_SCOPE))
1424*4dc78e53SAndroid Build Coastguard Worker 		rtmsg.rtm_scope = rtnl_route_guess_scope(route);
1425*4dc78e53SAndroid Build Coastguard Worker 
1426*4dc78e53SAndroid Build Coastguard Worker 	if (rtnl_route_get_nnexthops(route) == 1) {
1427*4dc78e53SAndroid Build Coastguard Worker 		struct rtnl_nexthop *nh;
1428*4dc78e53SAndroid Build Coastguard Worker 		nh = rtnl_route_nexthop_n(route, 0);
1429*4dc78e53SAndroid Build Coastguard Worker 		rtmsg.rtm_flags |= nh->rtnh_flags;
1430*4dc78e53SAndroid Build Coastguard Worker 	}
1431*4dc78e53SAndroid Build Coastguard Worker 
1432*4dc78e53SAndroid Build Coastguard Worker 	if (nlmsg_append(msg, &rtmsg, sizeof(rtmsg), NLMSG_ALIGNTO) < 0)
1433*4dc78e53SAndroid Build Coastguard Worker 		goto nla_put_failure;
1434*4dc78e53SAndroid Build Coastguard Worker 
1435*4dc78e53SAndroid Build Coastguard Worker 	/* Additional table attribute replacing the 8bit in the header, was
1436*4dc78e53SAndroid Build Coastguard Worker 	 * required to allow more than 256 tables. MPLS does not allow the
1437*4dc78e53SAndroid Build Coastguard Worker 	 * table attribute to be set
1438*4dc78e53SAndroid Build Coastguard Worker 	 */
1439*4dc78e53SAndroid Build Coastguard Worker 	if (route->rt_family != AF_MPLS)
1440*4dc78e53SAndroid Build Coastguard Worker 		NLA_PUT_U32(msg, RTA_TABLE, route->rt_table);
1441*4dc78e53SAndroid Build Coastguard Worker 
1442*4dc78e53SAndroid Build Coastguard Worker 	if (nl_addr_get_len(route->rt_dst))
1443*4dc78e53SAndroid Build Coastguard Worker 		NLA_PUT_ADDR(msg, RTA_DST, route->rt_dst);
1444*4dc78e53SAndroid Build Coastguard Worker 
1445*4dc78e53SAndroid Build Coastguard Worker 	if (route->ce_mask & ROUTE_ATTR_PRIO)
1446*4dc78e53SAndroid Build Coastguard Worker 		NLA_PUT_U32(msg, RTA_PRIORITY, route->rt_prio);
1447*4dc78e53SAndroid Build Coastguard Worker 
1448*4dc78e53SAndroid Build Coastguard Worker 	if (route->ce_mask & ROUTE_ATTR_SRC)
1449*4dc78e53SAndroid Build Coastguard Worker 		NLA_PUT_ADDR(msg, RTA_SRC, route->rt_src);
1450*4dc78e53SAndroid Build Coastguard Worker 
1451*4dc78e53SAndroid Build Coastguard Worker 	if (route->ce_mask & ROUTE_ATTR_PREF_SRC)
1452*4dc78e53SAndroid Build Coastguard Worker 		NLA_PUT_ADDR(msg, RTA_PREFSRC, route->rt_pref_src);
1453*4dc78e53SAndroid Build Coastguard Worker 
1454*4dc78e53SAndroid Build Coastguard Worker 	if (route->ce_mask & ROUTE_ATTR_IIF)
1455*4dc78e53SAndroid Build Coastguard Worker 		NLA_PUT_U32(msg, RTA_IIF, route->rt_iif);
1456*4dc78e53SAndroid Build Coastguard Worker 
1457*4dc78e53SAndroid Build Coastguard Worker 	if (route->ce_mask & ROUTE_ATTR_TTL_PROPAGATE)
1458*4dc78e53SAndroid Build Coastguard Worker 		NLA_PUT_U8(msg, RTA_TTL_PROPAGATE, route->rt_ttl_propagate);
1459*4dc78e53SAndroid Build Coastguard Worker 
1460*4dc78e53SAndroid Build Coastguard Worker 	if (route->rt_nmetrics > 0) {
1461*4dc78e53SAndroid Build Coastguard Worker 		uint32_t val;
1462*4dc78e53SAndroid Build Coastguard Worker 
1463*4dc78e53SAndroid Build Coastguard Worker 		metrics = nla_nest_start(msg, RTA_METRICS);
1464*4dc78e53SAndroid Build Coastguard Worker 		if (metrics == NULL)
1465*4dc78e53SAndroid Build Coastguard Worker 			goto nla_put_failure;
1466*4dc78e53SAndroid Build Coastguard Worker 
1467*4dc78e53SAndroid Build Coastguard Worker 		for (i = 1; i <= RTAX_MAX; i++) {
1468*4dc78e53SAndroid Build Coastguard Worker 			if (!rtnl_route_get_metric(route, i, &val))
1469*4dc78e53SAndroid Build Coastguard Worker 				NLA_PUT_U32(msg, i, val);
1470*4dc78e53SAndroid Build Coastguard Worker 		}
1471*4dc78e53SAndroid Build Coastguard Worker 
1472*4dc78e53SAndroid Build Coastguard Worker 		nla_nest_end(msg, metrics);
1473*4dc78e53SAndroid Build Coastguard Worker 	}
1474*4dc78e53SAndroid Build Coastguard Worker 
1475*4dc78e53SAndroid Build Coastguard Worker 	/* Nexthop specification and nexthop id are mutually exclusive */
1476*4dc78e53SAndroid Build Coastguard Worker 	if (route->ce_mask & ROUTE_ATTR_NHID) {
1477*4dc78e53SAndroid Build Coastguard Worker 		NLA_PUT_U32(msg, RTA_NH_ID, route->rt_nhid);
1478*4dc78e53SAndroid Build Coastguard Worker 	} else if (rtnl_route_get_nnexthops(route) == 1) {
1479*4dc78e53SAndroid Build Coastguard Worker 		struct rtnl_nexthop *nh;
1480*4dc78e53SAndroid Build Coastguard Worker 
1481*4dc78e53SAndroid Build Coastguard Worker 		nh = rtnl_route_nexthop_n(route, 0);
1482*4dc78e53SAndroid Build Coastguard Worker 		if (nh->rtnh_gateway)
1483*4dc78e53SAndroid Build Coastguard Worker 			NLA_PUT_ADDR(msg, RTA_GATEWAY, nh->rtnh_gateway);
1484*4dc78e53SAndroid Build Coastguard Worker 		if (nh->rtnh_ifindex)
1485*4dc78e53SAndroid Build Coastguard Worker 			NLA_PUT_U32(msg, RTA_OIF, nh->rtnh_ifindex);
1486*4dc78e53SAndroid Build Coastguard Worker 		if (nh->rtnh_realms)
1487*4dc78e53SAndroid Build Coastguard Worker 			NLA_PUT_U32(msg, RTA_FLOW, nh->rtnh_realms);
1488*4dc78e53SAndroid Build Coastguard Worker 		if (nh->rtnh_newdst)
1489*4dc78e53SAndroid Build Coastguard Worker 			NLA_PUT_ADDR(msg, RTA_NEWDST, nh->rtnh_newdst);
1490*4dc78e53SAndroid Build Coastguard Worker 		if (nh->rtnh_via && rtnl_route_put_via(msg, nh->rtnh_via) < 0)
1491*4dc78e53SAndroid Build Coastguard Worker 			goto nla_put_failure;
1492*4dc78e53SAndroid Build Coastguard Worker 		if (nh->rtnh_encap &&
1493*4dc78e53SAndroid Build Coastguard Worker 		    nh_encap_build_msg(msg, nh->rtnh_encap) < 0)
1494*4dc78e53SAndroid Build Coastguard Worker 			goto nla_put_failure;
1495*4dc78e53SAndroid Build Coastguard Worker 	} else if (rtnl_route_get_nnexthops(route) > 1) {
1496*4dc78e53SAndroid Build Coastguard Worker 		struct nlattr *multipath;
1497*4dc78e53SAndroid Build Coastguard Worker 		struct rtnl_nexthop *nh;
1498*4dc78e53SAndroid Build Coastguard Worker 
1499*4dc78e53SAndroid Build Coastguard Worker 		if (!(multipath = nla_nest_start(msg, RTA_MULTIPATH)))
1500*4dc78e53SAndroid Build Coastguard Worker 			goto nla_put_failure;
1501*4dc78e53SAndroid Build Coastguard Worker 
1502*4dc78e53SAndroid Build Coastguard Worker 		nl_list_for_each_entry(nh, &route->rt_nexthops, rtnh_list) {
1503*4dc78e53SAndroid Build Coastguard Worker 			struct rtnexthop *rtnh;
1504*4dc78e53SAndroid Build Coastguard Worker 
1505*4dc78e53SAndroid Build Coastguard Worker 			rtnh = nlmsg_reserve(msg, sizeof(*rtnh), NLMSG_ALIGNTO);
1506*4dc78e53SAndroid Build Coastguard Worker 			if (!rtnh)
1507*4dc78e53SAndroid Build Coastguard Worker 				goto nla_put_failure;
1508*4dc78e53SAndroid Build Coastguard Worker 
1509*4dc78e53SAndroid Build Coastguard Worker 			rtnh->rtnh_flags = nh->rtnh_flags;
1510*4dc78e53SAndroid Build Coastguard Worker 			rtnh->rtnh_hops = nh->rtnh_weight;
1511*4dc78e53SAndroid Build Coastguard Worker 			rtnh->rtnh_ifindex = nh->rtnh_ifindex;
1512*4dc78e53SAndroid Build Coastguard Worker 
1513*4dc78e53SAndroid Build Coastguard Worker 			if (nh->rtnh_gateway)
1514*4dc78e53SAndroid Build Coastguard Worker 				NLA_PUT_ADDR(msg, RTA_GATEWAY,
1515*4dc78e53SAndroid Build Coastguard Worker 					     nh->rtnh_gateway);
1516*4dc78e53SAndroid Build Coastguard Worker 
1517*4dc78e53SAndroid Build Coastguard Worker 			if (nh->rtnh_newdst)
1518*4dc78e53SAndroid Build Coastguard Worker 				NLA_PUT_ADDR(msg, RTA_NEWDST, nh->rtnh_newdst);
1519*4dc78e53SAndroid Build Coastguard Worker 
1520*4dc78e53SAndroid Build Coastguard Worker 			if (nh->rtnh_via &&
1521*4dc78e53SAndroid Build Coastguard Worker 			    rtnl_route_put_via(msg, nh->rtnh_via) < 0)
1522*4dc78e53SAndroid Build Coastguard Worker 				goto nla_put_failure;
1523*4dc78e53SAndroid Build Coastguard Worker 
1524*4dc78e53SAndroid Build Coastguard Worker 			if (nh->rtnh_realms)
1525*4dc78e53SAndroid Build Coastguard Worker 				NLA_PUT_U32(msg, RTA_FLOW, nh->rtnh_realms);
1526*4dc78e53SAndroid Build Coastguard Worker 
1527*4dc78e53SAndroid Build Coastguard Worker 			if (nh->rtnh_encap &&
1528*4dc78e53SAndroid Build Coastguard Worker 			    nh_encap_build_msg(msg, nh->rtnh_encap) < 0)
1529*4dc78e53SAndroid Build Coastguard Worker 				goto nla_put_failure;
1530*4dc78e53SAndroid Build Coastguard Worker 
1531*4dc78e53SAndroid Build Coastguard Worker 			rtnh->rtnh_len = (char *) nlmsg_tail(msg->nm_nlh) -
1532*4dc78e53SAndroid Build Coastguard Worker 						(char *) rtnh;
1533*4dc78e53SAndroid Build Coastguard Worker 		}
1534*4dc78e53SAndroid Build Coastguard Worker 
1535*4dc78e53SAndroid Build Coastguard Worker 		nla_nest_end(msg, multipath);
1536*4dc78e53SAndroid Build Coastguard Worker 	}
1537*4dc78e53SAndroid Build Coastguard Worker 
1538*4dc78e53SAndroid Build Coastguard Worker 	return 0;
1539*4dc78e53SAndroid Build Coastguard Worker 
1540*4dc78e53SAndroid Build Coastguard Worker nla_put_failure:
1541*4dc78e53SAndroid Build Coastguard Worker 	return -NLE_MSGSIZE;
1542*4dc78e53SAndroid Build Coastguard Worker }
1543*4dc78e53SAndroid Build Coastguard Worker 
1544*4dc78e53SAndroid Build Coastguard Worker /** @cond SKIP */
1545*4dc78e53SAndroid Build Coastguard Worker struct nl_object_ops route_obj_ops = {
1546*4dc78e53SAndroid Build Coastguard Worker 	.oo_name		= "route/route",
1547*4dc78e53SAndroid Build Coastguard Worker 	.oo_size		= sizeof(struct rtnl_route),
1548*4dc78e53SAndroid Build Coastguard Worker 	.oo_constructor		= route_constructor,
1549*4dc78e53SAndroid Build Coastguard Worker 	.oo_free_data		= route_free_data,
1550*4dc78e53SAndroid Build Coastguard Worker 	.oo_clone		= route_clone,
1551*4dc78e53SAndroid Build Coastguard Worker 	.oo_dump = {
1552*4dc78e53SAndroid Build Coastguard Worker 	    [NL_DUMP_LINE]	= route_dump_line,
1553*4dc78e53SAndroid Build Coastguard Worker 	    [NL_DUMP_DETAILS]	= route_dump_details,
1554*4dc78e53SAndroid Build Coastguard Worker 	    [NL_DUMP_STATS]	= route_dump_stats,
1555*4dc78e53SAndroid Build Coastguard Worker 	},
1556*4dc78e53SAndroid Build Coastguard Worker 	.oo_compare		= route_compare,
1557*4dc78e53SAndroid Build Coastguard Worker 	.oo_keygen		= route_keygen,
1558*4dc78e53SAndroid Build Coastguard Worker 	.oo_update		= route_update,
1559*4dc78e53SAndroid Build Coastguard Worker 	.oo_attrs2str		= route_attrs2str,
1560*4dc78e53SAndroid Build Coastguard Worker 	.oo_id_attrs		= (ROUTE_ATTR_FAMILY | ROUTE_ATTR_TOS |
1561*4dc78e53SAndroid Build Coastguard Worker 				   ROUTE_ATTR_TABLE | ROUTE_ATTR_DST |
1562*4dc78e53SAndroid Build Coastguard Worker 				   ROUTE_ATTR_PRIO),
1563*4dc78e53SAndroid Build Coastguard Worker 	.oo_id_attrs_get	= route_id_attrs_get,
1564*4dc78e53SAndroid Build Coastguard Worker };
1565*4dc78e53SAndroid Build Coastguard Worker /** @endcond */
1566*4dc78e53SAndroid Build Coastguard Worker 
1567*4dc78e53SAndroid Build Coastguard Worker /** @} */
1568