xref: /aosp_15_r20/external/libnl/lib/route/nh.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) 2022 Stanislav Zaikin <[email protected]>
4*4dc78e53SAndroid Build Coastguard Worker  */
5*4dc78e53SAndroid Build Coastguard Worker 
6*4dc78e53SAndroid Build Coastguard Worker #include "nl-default.h"
7*4dc78e53SAndroid Build Coastguard Worker 
8*4dc78e53SAndroid Build Coastguard Worker #include <linux/nexthop.h>
9*4dc78e53SAndroid Build Coastguard Worker 
10*4dc78e53SAndroid Build Coastguard Worker #include <netlink/route/nh.h>
11*4dc78e53SAndroid Build Coastguard Worker #include <netlink/hashtable.h>
12*4dc78e53SAndroid Build Coastguard Worker #include <netlink/route/nexthop.h>
13*4dc78e53SAndroid Build Coastguard Worker 
14*4dc78e53SAndroid Build Coastguard Worker #include "nl-aux-route/nl-route.h"
15*4dc78e53SAndroid Build Coastguard Worker #include "nl-route.h"
16*4dc78e53SAndroid Build Coastguard Worker #include "nl-priv-dynamic-core/nl-core.h"
17*4dc78e53SAndroid Build Coastguard Worker #include "nl-priv-dynamic-core/cache-api.h"
18*4dc78e53SAndroid Build Coastguard Worker 
19*4dc78e53SAndroid Build Coastguard Worker /** @cond SKIP */
20*4dc78e53SAndroid Build Coastguard Worker struct rtnl_nh {
21*4dc78e53SAndroid Build Coastguard Worker 	NLHDR_COMMON
22*4dc78e53SAndroid Build Coastguard Worker 
23*4dc78e53SAndroid Build Coastguard Worker 	uint8_t nh_family;
24*4dc78e53SAndroid Build Coastguard Worker 	uint32_t nh_flags;
25*4dc78e53SAndroid Build Coastguard Worker 
26*4dc78e53SAndroid Build Coastguard Worker 	uint32_t nh_id;
27*4dc78e53SAndroid Build Coastguard Worker 	uint32_t nh_group_type;
28*4dc78e53SAndroid Build Coastguard Worker 	nl_nh_group_t *nh_group;
29*4dc78e53SAndroid Build Coastguard Worker 	uint32_t nh_oif;
30*4dc78e53SAndroid Build Coastguard Worker 	struct nl_addr *nh_gateway;
31*4dc78e53SAndroid Build Coastguard Worker };
32*4dc78e53SAndroid Build Coastguard Worker 
33*4dc78e53SAndroid Build Coastguard Worker #define NH_ATTR_FLAGS (1 << 0)
34*4dc78e53SAndroid Build Coastguard Worker #define NH_ATTR_ID (1 << 1)
35*4dc78e53SAndroid Build Coastguard Worker #define NH_ATTR_GROUP (1 << 2)
36*4dc78e53SAndroid Build Coastguard Worker #define NH_ATTR_FLAG_BLACKHOLE (1 << 3)
37*4dc78e53SAndroid Build Coastguard Worker #define NH_ATTR_OIF (1 << 4)
38*4dc78e53SAndroid Build Coastguard Worker #define NH_ATTR_GATEWAY (1 << 5)
39*4dc78e53SAndroid Build Coastguard Worker #define NH_ATTR_FLAG_GROUPS (1 << 6)
40*4dc78e53SAndroid Build Coastguard Worker #define NH_ATTR_FLAG_FDB (1 << 8)
41*4dc78e53SAndroid Build Coastguard Worker /** @endcond */
42*4dc78e53SAndroid Build Coastguard Worker 
43*4dc78e53SAndroid Build Coastguard Worker struct nla_policy rtnl_nh_policy[NHA_MAX + 1] = {
44*4dc78e53SAndroid Build Coastguard Worker 	[NHA_UNSPEC] = { .type = NLA_UNSPEC },
45*4dc78e53SAndroid Build Coastguard Worker 	[NHA_ID] = { .type = NLA_U32 },
46*4dc78e53SAndroid Build Coastguard Worker 	[NHA_GROUP] = { .type = NLA_NESTED },
47*4dc78e53SAndroid Build Coastguard Worker 	[NHA_GROUP_TYPE] = { .type = NLA_U16 },
48*4dc78e53SAndroid Build Coastguard Worker 	[NHA_BLACKHOLE] = { .type = NLA_UNSPEC },
49*4dc78e53SAndroid Build Coastguard Worker 	[NHA_OIF] = { .type = NLA_U32 },
50*4dc78e53SAndroid Build Coastguard Worker };
51*4dc78e53SAndroid Build Coastguard Worker 
52*4dc78e53SAndroid Build Coastguard Worker static struct nl_cache_ops rtnl_nh_ops;
53*4dc78e53SAndroid Build Coastguard Worker static struct nl_object_ops nh_obj_ops;
54*4dc78e53SAndroid Build Coastguard Worker 
rtnl_nh_grp_alloc(unsigned size)55*4dc78e53SAndroid Build Coastguard Worker static nl_nh_group_t *rtnl_nh_grp_alloc(unsigned size)
56*4dc78e53SAndroid Build Coastguard Worker {
57*4dc78e53SAndroid Build Coastguard Worker 	nl_nh_group_t *nhg;
58*4dc78e53SAndroid Build Coastguard Worker 
59*4dc78e53SAndroid Build Coastguard Worker 	_nl_assert(size <= (unsigned)INT_MAX);
60*4dc78e53SAndroid Build Coastguard Worker 
61*4dc78e53SAndroid Build Coastguard Worker 	if (!(nhg = calloc(1, sizeof(*nhg))))
62*4dc78e53SAndroid Build Coastguard Worker 		return NULL;
63*4dc78e53SAndroid Build Coastguard Worker 
64*4dc78e53SAndroid Build Coastguard Worker 	nhg->size = size;
65*4dc78e53SAndroid Build Coastguard Worker 
66*4dc78e53SAndroid Build Coastguard Worker 	if (!(nhg->entries = calloc(size, sizeof(*nhg->entries)))) {
67*4dc78e53SAndroid Build Coastguard Worker 		free(nhg);
68*4dc78e53SAndroid Build Coastguard Worker 		return NULL;
69*4dc78e53SAndroid Build Coastguard Worker 	}
70*4dc78e53SAndroid Build Coastguard Worker 
71*4dc78e53SAndroid Build Coastguard Worker 	nhg->ce_refcnt = 1;
72*4dc78e53SAndroid Build Coastguard Worker 
73*4dc78e53SAndroid Build Coastguard Worker 	return nhg;
74*4dc78e53SAndroid Build Coastguard Worker }
75*4dc78e53SAndroid Build Coastguard Worker 
rtnl_nh_grp_put(nl_nh_group_t * nhg)76*4dc78e53SAndroid Build Coastguard Worker static void rtnl_nh_grp_put(nl_nh_group_t *nhg)
77*4dc78e53SAndroid Build Coastguard Worker {
78*4dc78e53SAndroid Build Coastguard Worker 	if (!nhg)
79*4dc78e53SAndroid Build Coastguard Worker 		return;
80*4dc78e53SAndroid Build Coastguard Worker 
81*4dc78e53SAndroid Build Coastguard Worker 	_nl_assert(nhg->ce_refcnt > 0);
82*4dc78e53SAndroid Build Coastguard Worker 
83*4dc78e53SAndroid Build Coastguard Worker 	nhg->ce_refcnt--;
84*4dc78e53SAndroid Build Coastguard Worker 
85*4dc78e53SAndroid Build Coastguard Worker 	if (nhg->ce_refcnt > 0)
86*4dc78e53SAndroid Build Coastguard Worker 		return;
87*4dc78e53SAndroid Build Coastguard Worker 
88*4dc78e53SAndroid Build Coastguard Worker 	free(nhg);
89*4dc78e53SAndroid Build Coastguard Worker }
90*4dc78e53SAndroid Build Coastguard Worker 
rtnh_nh_grp_cmp(const nl_nh_group_t * a,const nl_nh_group_t * b)91*4dc78e53SAndroid Build Coastguard Worker static int rtnh_nh_grp_cmp(const nl_nh_group_t *a, const nl_nh_group_t *b)
92*4dc78e53SAndroid Build Coastguard Worker {
93*4dc78e53SAndroid Build Coastguard Worker 	unsigned i;
94*4dc78e53SAndroid Build Coastguard Worker 
95*4dc78e53SAndroid Build Coastguard Worker 	_NL_CMP_SELF(a, b);
96*4dc78e53SAndroid Build Coastguard Worker 	_NL_CMP_DIRECT(a->size, b->size);
97*4dc78e53SAndroid Build Coastguard Worker 	for (i = 0; i < a->size; i++) {
98*4dc78e53SAndroid Build Coastguard Worker 		_NL_CMP_DIRECT(a->entries[i].nh_id, b->entries[i].nh_id);
99*4dc78e53SAndroid Build Coastguard Worker 		_NL_CMP_DIRECT(a->entries[i].weight, b->entries[i].weight);
100*4dc78e53SAndroid Build Coastguard Worker 	}
101*4dc78e53SAndroid Build Coastguard Worker 	return 0;
102*4dc78e53SAndroid Build Coastguard Worker }
103*4dc78e53SAndroid Build Coastguard Worker 
rtnh_nh_grp_clone(nl_nh_group_t * src,nl_nh_group_t ** dst)104*4dc78e53SAndroid Build Coastguard Worker static int rtnh_nh_grp_clone(nl_nh_group_t *src, nl_nh_group_t **dst)
105*4dc78e53SAndroid Build Coastguard Worker {
106*4dc78e53SAndroid Build Coastguard Worker 	nl_nh_group_t *ret;
107*4dc78e53SAndroid Build Coastguard Worker 	unsigned i;
108*4dc78e53SAndroid Build Coastguard Worker 
109*4dc78e53SAndroid Build Coastguard Worker 	ret = rtnl_nh_grp_alloc(src->size);
110*4dc78e53SAndroid Build Coastguard Worker 
111*4dc78e53SAndroid Build Coastguard Worker 	if (!ret)
112*4dc78e53SAndroid Build Coastguard Worker 		return -NLE_NOMEM;
113*4dc78e53SAndroid Build Coastguard Worker 
114*4dc78e53SAndroid Build Coastguard Worker 	for (i = 0; i < src->size; i++) {
115*4dc78e53SAndroid Build Coastguard Worker 		ret->entries[i].nh_id = src->entries[i].nh_id;
116*4dc78e53SAndroid Build Coastguard Worker 		ret->entries[i].weight = src->entries[i].weight;
117*4dc78e53SAndroid Build Coastguard Worker 	}
118*4dc78e53SAndroid Build Coastguard Worker 
119*4dc78e53SAndroid Build Coastguard Worker 	*dst = ret;
120*4dc78e53SAndroid Build Coastguard Worker 
121*4dc78e53SAndroid Build Coastguard Worker 	return NLE_SUCCESS;
122*4dc78e53SAndroid Build Coastguard Worker }
123*4dc78e53SAndroid Build Coastguard Worker 
rtnl_nh_alloc(void)124*4dc78e53SAndroid Build Coastguard Worker struct rtnl_nh *rtnl_nh_alloc(void)
125*4dc78e53SAndroid Build Coastguard Worker {
126*4dc78e53SAndroid Build Coastguard Worker 	return (struct rtnl_nh *)nl_object_alloc(&nh_obj_ops);
127*4dc78e53SAndroid Build Coastguard Worker }
128*4dc78e53SAndroid Build Coastguard Worker 
nh_clone(struct nl_object * _src,struct nl_object * _dst)129*4dc78e53SAndroid Build Coastguard Worker static int nh_clone(struct nl_object *_src, struct nl_object *_dst)
130*4dc78e53SAndroid Build Coastguard Worker {
131*4dc78e53SAndroid Build Coastguard Worker 	struct rtnl_nh *dst = nl_object_priv(_dst);
132*4dc78e53SAndroid Build Coastguard Worker 	struct rtnl_nh *src = nl_object_priv(_src);
133*4dc78e53SAndroid Build Coastguard Worker 
134*4dc78e53SAndroid Build Coastguard Worker 	dst->nh_flags = src->nh_flags;
135*4dc78e53SAndroid Build Coastguard Worker 	dst->nh_family = src->nh_family;
136*4dc78e53SAndroid Build Coastguard Worker 	dst->nh_id = src->nh_id;
137*4dc78e53SAndroid Build Coastguard Worker 	dst->nh_oif = src->nh_oif;
138*4dc78e53SAndroid Build Coastguard Worker 	dst->ce_mask = src->ce_mask;
139*4dc78e53SAndroid Build Coastguard Worker 
140*4dc78e53SAndroid Build Coastguard Worker 	if (src->nh_gateway) {
141*4dc78e53SAndroid Build Coastguard Worker 		dst->nh_gateway = nl_addr_clone(src->nh_gateway);
142*4dc78e53SAndroid Build Coastguard Worker 		if (!dst->nh_gateway) {
143*4dc78e53SAndroid Build Coastguard Worker 			return -NLE_NOMEM;
144*4dc78e53SAndroid Build Coastguard Worker 		}
145*4dc78e53SAndroid Build Coastguard Worker 	}
146*4dc78e53SAndroid Build Coastguard Worker 
147*4dc78e53SAndroid Build Coastguard Worker 	if (src->nh_group) {
148*4dc78e53SAndroid Build Coastguard Worker 		if (rtnh_nh_grp_clone(src->nh_group, &dst->nh_group) < 0) {
149*4dc78e53SAndroid Build Coastguard Worker 			return -NLE_NOMEM;
150*4dc78e53SAndroid Build Coastguard Worker 		}
151*4dc78e53SAndroid Build Coastguard Worker 	}
152*4dc78e53SAndroid Build Coastguard Worker 
153*4dc78e53SAndroid Build Coastguard Worker 	return 0;
154*4dc78e53SAndroid Build Coastguard Worker }
155*4dc78e53SAndroid Build Coastguard Worker 
nh_free(struct nl_object * obj)156*4dc78e53SAndroid Build Coastguard Worker static void nh_free(struct nl_object *obj)
157*4dc78e53SAndroid Build Coastguard Worker {
158*4dc78e53SAndroid Build Coastguard Worker 	struct rtnl_nh *nh = nl_object_priv(obj);
159*4dc78e53SAndroid Build Coastguard Worker 	nl_addr_put(nh->nh_gateway);
160*4dc78e53SAndroid Build Coastguard Worker 
161*4dc78e53SAndroid Build Coastguard Worker 	if (nh->nh_group)
162*4dc78e53SAndroid Build Coastguard Worker 		rtnl_nh_grp_put(nh->nh_group);
163*4dc78e53SAndroid Build Coastguard Worker }
164*4dc78e53SAndroid Build Coastguard Worker 
rtnl_nh_put(struct rtnl_nh * nh)165*4dc78e53SAndroid Build Coastguard Worker void rtnl_nh_put(struct rtnl_nh *nh)
166*4dc78e53SAndroid Build Coastguard Worker {
167*4dc78e53SAndroid Build Coastguard Worker 	struct nl_object *obj = (struct nl_object *)nh;
168*4dc78e53SAndroid Build Coastguard Worker 
169*4dc78e53SAndroid Build Coastguard Worker 	nl_object_put(obj);
170*4dc78e53SAndroid Build Coastguard Worker }
171*4dc78e53SAndroid Build Coastguard Worker 
nexthop_keygen(struct nl_object * obj,uint32_t * hashkey,uint32_t table_sz)172*4dc78e53SAndroid Build Coastguard Worker static void nexthop_keygen(struct nl_object *obj, uint32_t *hashkey,
173*4dc78e53SAndroid Build Coastguard Worker 			   uint32_t table_sz)
174*4dc78e53SAndroid Build Coastguard Worker {
175*4dc78e53SAndroid Build Coastguard Worker 	struct rtnl_nh *nexthop = nl_object_priv(obj);
176*4dc78e53SAndroid Build Coastguard Worker 	unsigned int lkey_sz;
177*4dc78e53SAndroid Build Coastguard Worker 	struct nexthop_hash_key {
178*4dc78e53SAndroid Build Coastguard Worker 		uint32_t nh_id;
179*4dc78e53SAndroid Build Coastguard Worker 	} _nl_packed lkey;
180*4dc78e53SAndroid Build Coastguard Worker 
181*4dc78e53SAndroid Build Coastguard Worker 	lkey_sz = sizeof(lkey);
182*4dc78e53SAndroid Build Coastguard Worker 	lkey.nh_id = nexthop->nh_id;
183*4dc78e53SAndroid Build Coastguard Worker 
184*4dc78e53SAndroid Build Coastguard Worker 	*hashkey = nl_hash(&lkey, lkey_sz, 0) % table_sz;
185*4dc78e53SAndroid Build Coastguard Worker 
186*4dc78e53SAndroid Build Coastguard Worker 	return;
187*4dc78e53SAndroid Build Coastguard Worker }
188*4dc78e53SAndroid Build Coastguard Worker 
rtnl_nh_set_gateway(struct rtnl_nh * nexthop,struct nl_addr * addr)189*4dc78e53SAndroid Build Coastguard Worker int rtnl_nh_set_gateway(struct rtnl_nh *nexthop, struct nl_addr *addr)
190*4dc78e53SAndroid Build Coastguard Worker {
191*4dc78e53SAndroid Build Coastguard Worker 	if (nexthop->ce_mask & NH_ATTR_GATEWAY) {
192*4dc78e53SAndroid Build Coastguard Worker 		nl_addr_put(nexthop->nh_gateway);
193*4dc78e53SAndroid Build Coastguard Worker 	}
194*4dc78e53SAndroid Build Coastguard Worker 
195*4dc78e53SAndroid Build Coastguard Worker 	nexthop->nh_gateway = nl_addr_clone(addr);
196*4dc78e53SAndroid Build Coastguard Worker 	nexthop->ce_mask |= NH_ATTR_GATEWAY;
197*4dc78e53SAndroid Build Coastguard Worker 
198*4dc78e53SAndroid Build Coastguard Worker 	return 0;
199*4dc78e53SAndroid Build Coastguard Worker }
200*4dc78e53SAndroid Build Coastguard Worker 
rtnl_nh_get_gateway(struct rtnl_nh * nexthop)201*4dc78e53SAndroid Build Coastguard Worker struct nl_addr *rtnl_nh_get_gateway(struct rtnl_nh *nexthop)
202*4dc78e53SAndroid Build Coastguard Worker {
203*4dc78e53SAndroid Build Coastguard Worker 	return nexthop->nh_gateway;
204*4dc78e53SAndroid Build Coastguard Worker }
205*4dc78e53SAndroid Build Coastguard Worker 
rtnl_nh_set_fdb(struct rtnl_nh * nexthop,int value)206*4dc78e53SAndroid Build Coastguard Worker int rtnl_nh_set_fdb(struct rtnl_nh *nexthop, int value)
207*4dc78e53SAndroid Build Coastguard Worker {
208*4dc78e53SAndroid Build Coastguard Worker 	if (value)
209*4dc78e53SAndroid Build Coastguard Worker 		nexthop->ce_mask |= NH_ATTR_FLAG_FDB;
210*4dc78e53SAndroid Build Coastguard Worker 	else
211*4dc78e53SAndroid Build Coastguard Worker 		nexthop->ce_mask &= ~NH_ATTR_FLAG_FDB;
212*4dc78e53SAndroid Build Coastguard Worker 
213*4dc78e53SAndroid Build Coastguard Worker 	return 0;
214*4dc78e53SAndroid Build Coastguard Worker }
215*4dc78e53SAndroid Build Coastguard Worker 
rtnl_nh_get_oif(struct rtnl_nh * nexthop)216*4dc78e53SAndroid Build Coastguard Worker int rtnl_nh_get_oif(struct rtnl_nh *nexthop)
217*4dc78e53SAndroid Build Coastguard Worker {
218*4dc78e53SAndroid Build Coastguard Worker 	if (nexthop->ce_mask & NH_ATTR_OIF)
219*4dc78e53SAndroid Build Coastguard Worker 		return nexthop->nh_oif;
220*4dc78e53SAndroid Build Coastguard Worker 
221*4dc78e53SAndroid Build Coastguard Worker 	return 0;
222*4dc78e53SAndroid Build Coastguard Worker }
223*4dc78e53SAndroid Build Coastguard Worker 
rtnl_nh_get_fdb(struct rtnl_nh * nexthop)224*4dc78e53SAndroid Build Coastguard Worker int rtnl_nh_get_fdb(struct rtnl_nh *nexthop)
225*4dc78e53SAndroid Build Coastguard Worker {
226*4dc78e53SAndroid Build Coastguard Worker 	return nexthop->ce_mask & NH_ATTR_FLAG_FDB;
227*4dc78e53SAndroid Build Coastguard Worker }
228*4dc78e53SAndroid Build Coastguard Worker 
rtnl_nh_get_group_entry(struct rtnl_nh * nexthop,int n)229*4dc78e53SAndroid Build Coastguard Worker int rtnl_nh_get_group_entry(struct rtnl_nh *nexthop, int n)
230*4dc78e53SAndroid Build Coastguard Worker {
231*4dc78e53SAndroid Build Coastguard Worker 	if (!(nexthop->ce_mask & NH_ATTR_GROUP) || !nexthop->nh_group)
232*4dc78e53SAndroid Build Coastguard Worker 		return -NLE_MISSING_ATTR;
233*4dc78e53SAndroid Build Coastguard Worker 
234*4dc78e53SAndroid Build Coastguard Worker 	if (n < 0 || ((unsigned)n) >= nexthop->nh_group->size)
235*4dc78e53SAndroid Build Coastguard Worker 		return -NLE_INVAL;
236*4dc78e53SAndroid Build Coastguard Worker 
237*4dc78e53SAndroid Build Coastguard Worker 	return nexthop->nh_group->entries[n].nh_id;
238*4dc78e53SAndroid Build Coastguard Worker }
239*4dc78e53SAndroid Build Coastguard Worker 
rtnl_nh_get_group_size(struct rtnl_nh * nexthop)240*4dc78e53SAndroid Build Coastguard Worker int rtnl_nh_get_group_size(struct rtnl_nh *nexthop)
241*4dc78e53SAndroid Build Coastguard Worker {
242*4dc78e53SAndroid Build Coastguard Worker 	if (!(nexthop->ce_mask & NH_ATTR_GROUP) || !nexthop->nh_group)
243*4dc78e53SAndroid Build Coastguard Worker 		return -NLE_MISSING_ATTR;
244*4dc78e53SAndroid Build Coastguard Worker 
245*4dc78e53SAndroid Build Coastguard Worker 	_nl_assert(nexthop->nh_group->size <= INT_MAX);
246*4dc78e53SAndroid Build Coastguard Worker 
247*4dc78e53SAndroid Build Coastguard Worker 	return (int)nexthop->nh_group->size;
248*4dc78e53SAndroid Build Coastguard Worker }
249*4dc78e53SAndroid Build Coastguard Worker 
rtnl_nh_grp_info(unsigned size,const struct nexthop_grp * vi,nl_nh_group_t ** nvi)250*4dc78e53SAndroid Build Coastguard Worker static int rtnl_nh_grp_info(unsigned size, const struct nexthop_grp *vi,
251*4dc78e53SAndroid Build Coastguard Worker 			    nl_nh_group_t **nvi)
252*4dc78e53SAndroid Build Coastguard Worker {
253*4dc78e53SAndroid Build Coastguard Worker 	nl_nh_group_t *ret;
254*4dc78e53SAndroid Build Coastguard Worker 	unsigned i;
255*4dc78e53SAndroid Build Coastguard Worker 
256*4dc78e53SAndroid Build Coastguard Worker 	if (!(ret = rtnl_nh_grp_alloc(size)))
257*4dc78e53SAndroid Build Coastguard Worker 		return -NLE_NOMEM;
258*4dc78e53SAndroid Build Coastguard Worker 
259*4dc78e53SAndroid Build Coastguard Worker 	for (i = 0; i < size; i++) {
260*4dc78e53SAndroid Build Coastguard Worker 		ret->entries[i].nh_id = vi[i].id;
261*4dc78e53SAndroid Build Coastguard Worker 		ret->entries[i].weight = vi[i].weight;
262*4dc78e53SAndroid Build Coastguard Worker 	}
263*4dc78e53SAndroid Build Coastguard Worker 
264*4dc78e53SAndroid Build Coastguard Worker 	*nvi = ret;
265*4dc78e53SAndroid Build Coastguard Worker 	return NLE_SUCCESS;
266*4dc78e53SAndroid Build Coastguard Worker }
267*4dc78e53SAndroid Build Coastguard Worker 
rtnl_nh_get_id(struct rtnl_nh * nh)268*4dc78e53SAndroid Build Coastguard Worker int rtnl_nh_get_id(struct rtnl_nh *nh)
269*4dc78e53SAndroid Build Coastguard Worker {
270*4dc78e53SAndroid Build Coastguard Worker 	if (nh->ce_mask & NH_ATTR_ID)
271*4dc78e53SAndroid Build Coastguard Worker 		return nh->nh_id;
272*4dc78e53SAndroid Build Coastguard Worker 
273*4dc78e53SAndroid Build Coastguard Worker 	return -NLE_INVAL;
274*4dc78e53SAndroid Build Coastguard Worker }
275*4dc78e53SAndroid Build Coastguard Worker 
nexthop_msg_parser(struct nl_cache_ops * ops,struct sockaddr_nl * who,struct nlmsghdr * n,struct nl_parser_param * pp)276*4dc78e53SAndroid Build Coastguard Worker static int nexthop_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who,
277*4dc78e53SAndroid Build Coastguard Worker 			      struct nlmsghdr *n, struct nl_parser_param *pp)
278*4dc78e53SAndroid Build Coastguard Worker {
279*4dc78e53SAndroid Build Coastguard Worker 	_nl_auto_rtnl_nh struct rtnl_nh *nexthop = NULL;
280*4dc78e53SAndroid Build Coastguard Worker 	struct nhmsg *ifi;
281*4dc78e53SAndroid Build Coastguard Worker 	struct nlattr *tb[NHA_MAX + 1];
282*4dc78e53SAndroid Build Coastguard Worker 	int err;
283*4dc78e53SAndroid Build Coastguard Worker 	int family;
284*4dc78e53SAndroid Build Coastguard Worker 
285*4dc78e53SAndroid Build Coastguard Worker 	nexthop = rtnl_nh_alloc();
286*4dc78e53SAndroid Build Coastguard Worker 	if (nexthop == NULL)
287*4dc78e53SAndroid Build Coastguard Worker 		return -NLE_NOMEM;
288*4dc78e53SAndroid Build Coastguard Worker 
289*4dc78e53SAndroid Build Coastguard Worker 	nexthop->ce_msgtype = n->nlmsg_type;
290*4dc78e53SAndroid Build Coastguard Worker 
291*4dc78e53SAndroid Build Coastguard Worker 	if (!nlmsg_valid_hdr(n, sizeof(*ifi)))
292*4dc78e53SAndroid Build Coastguard Worker 		return -NLE_MSG_TOOSHORT;
293*4dc78e53SAndroid Build Coastguard Worker 
294*4dc78e53SAndroid Build Coastguard Worker 	ifi = nlmsg_data(n);
295*4dc78e53SAndroid Build Coastguard Worker 	family = ifi->nh_family;
296*4dc78e53SAndroid Build Coastguard Worker 	nexthop->nh_family = family;
297*4dc78e53SAndroid Build Coastguard Worker 	nexthop->nh_flags = ifi->nh_flags;
298*4dc78e53SAndroid Build Coastguard Worker 	nexthop->ce_mask = (NH_ATTR_FLAGS);
299*4dc78e53SAndroid Build Coastguard Worker 
300*4dc78e53SAndroid Build Coastguard Worker 	err = nlmsg_parse(n, sizeof(*ifi), tb, NHA_MAX, rtnl_nh_policy);
301*4dc78e53SAndroid Build Coastguard Worker 	if (err < 0)
302*4dc78e53SAndroid Build Coastguard Worker 		return err;
303*4dc78e53SAndroid Build Coastguard Worker 
304*4dc78e53SAndroid Build Coastguard Worker 	if (tb[NHA_ID]) {
305*4dc78e53SAndroid Build Coastguard Worker 		nexthop->nh_id = nla_get_u32(tb[NHA_ID]);
306*4dc78e53SAndroid Build Coastguard Worker 		nexthop->ce_mask |= NH_ATTR_ID;
307*4dc78e53SAndroid Build Coastguard Worker 	}
308*4dc78e53SAndroid Build Coastguard Worker 
309*4dc78e53SAndroid Build Coastguard Worker 	if (tb[NHA_OIF]) {
310*4dc78e53SAndroid Build Coastguard Worker 		nexthop->nh_oif = nla_get_u32(tb[NHA_OIF]);
311*4dc78e53SAndroid Build Coastguard Worker 		nexthop->ce_mask |= NH_ATTR_OIF;
312*4dc78e53SAndroid Build Coastguard Worker 	}
313*4dc78e53SAndroid Build Coastguard Worker 
314*4dc78e53SAndroid Build Coastguard Worker 	if (tb[NHA_GATEWAY]) {
315*4dc78e53SAndroid Build Coastguard Worker 		nexthop->nh_gateway =
316*4dc78e53SAndroid Build Coastguard Worker 			nl_addr_alloc_attr(tb[NHA_GATEWAY], family);
317*4dc78e53SAndroid Build Coastguard Worker 		nexthop->ce_mask |= NH_ATTR_GATEWAY;
318*4dc78e53SAndroid Build Coastguard Worker 	}
319*4dc78e53SAndroid Build Coastguard Worker 
320*4dc78e53SAndroid Build Coastguard Worker 	if (tb[NHA_BLACKHOLE]) {
321*4dc78e53SAndroid Build Coastguard Worker 		nexthop->ce_mask |= NH_ATTR_FLAG_BLACKHOLE;
322*4dc78e53SAndroid Build Coastguard Worker 	}
323*4dc78e53SAndroid Build Coastguard Worker 
324*4dc78e53SAndroid Build Coastguard Worker 	if (tb[NHA_GROUPS]) {
325*4dc78e53SAndroid Build Coastguard Worker 		nexthop->ce_mask |= NH_ATTR_FLAG_GROUPS;
326*4dc78e53SAndroid Build Coastguard Worker 	}
327*4dc78e53SAndroid Build Coastguard Worker 
328*4dc78e53SAndroid Build Coastguard Worker 	if (tb[NHA_FDB]) {
329*4dc78e53SAndroid Build Coastguard Worker 		nexthop->ce_mask |= NH_ATTR_FLAG_FDB;
330*4dc78e53SAndroid Build Coastguard Worker 	}
331*4dc78e53SAndroid Build Coastguard Worker 
332*4dc78e53SAndroid Build Coastguard Worker 	if (tb[NHA_GROUP]) {
333*4dc78e53SAndroid Build Coastguard Worker 		nl_nh_group_t *nh_group = NULL;
334*4dc78e53SAndroid Build Coastguard Worker 		const void *data;
335*4dc78e53SAndroid Build Coastguard Worker 		unsigned size;
336*4dc78e53SAndroid Build Coastguard Worker 		unsigned len;
337*4dc78e53SAndroid Build Coastguard Worker 
338*4dc78e53SAndroid Build Coastguard Worker 		data = nla_data(tb[NHA_GROUP]);
339*4dc78e53SAndroid Build Coastguard Worker 		len = _nla_len(tb[NHA_GROUP]);
340*4dc78e53SAndroid Build Coastguard Worker 		size = len / sizeof(struct nexthop_grp);
341*4dc78e53SAndroid Build Coastguard Worker 
342*4dc78e53SAndroid Build Coastguard Worker 		err = rtnl_nh_grp_info(size, (const struct nexthop_grp *)data,
343*4dc78e53SAndroid Build Coastguard Worker 				       &nh_group);
344*4dc78e53SAndroid Build Coastguard Worker 		if (err < 0) {
345*4dc78e53SAndroid Build Coastguard Worker 			return err;
346*4dc78e53SAndroid Build Coastguard Worker 		}
347*4dc78e53SAndroid Build Coastguard Worker 
348*4dc78e53SAndroid Build Coastguard Worker 		nexthop->nh_group = nh_group;
349*4dc78e53SAndroid Build Coastguard Worker 		nexthop->ce_mask |= NH_ATTR_GROUP;
350*4dc78e53SAndroid Build Coastguard Worker 	}
351*4dc78e53SAndroid Build Coastguard Worker 
352*4dc78e53SAndroid Build Coastguard Worker 	return pp->pp_cb((struct nl_object *)nexthop, pp);
353*4dc78e53SAndroid Build Coastguard Worker }
354*4dc78e53SAndroid Build Coastguard Worker 
nexthop_request_update(struct nl_cache * cache,struct nl_sock * sk)355*4dc78e53SAndroid Build Coastguard Worker static int nexthop_request_update(struct nl_cache *cache, struct nl_sock *sk)
356*4dc78e53SAndroid Build Coastguard Worker {
357*4dc78e53SAndroid Build Coastguard Worker 	_nl_auto_nl_msg struct nl_msg *msg = NULL;
358*4dc78e53SAndroid Build Coastguard Worker 	int family = cache->c_iarg1;
359*4dc78e53SAndroid Build Coastguard Worker 	struct nhmsg hdr = { .nh_family = family };
360*4dc78e53SAndroid Build Coastguard Worker 	int err;
361*4dc78e53SAndroid Build Coastguard Worker 
362*4dc78e53SAndroid Build Coastguard Worker 	msg = nlmsg_alloc_simple(RTM_GETNEXTHOP, NLM_F_DUMP);
363*4dc78e53SAndroid Build Coastguard Worker 	if (!msg)
364*4dc78e53SAndroid Build Coastguard Worker 		return -NLE_NOMEM;
365*4dc78e53SAndroid Build Coastguard Worker 
366*4dc78e53SAndroid Build Coastguard Worker 	if (nlmsg_append(msg, &hdr, sizeof(hdr), NLMSG_ALIGNTO) < 0)
367*4dc78e53SAndroid Build Coastguard Worker 		return -NLE_MSGSIZE;
368*4dc78e53SAndroid Build Coastguard Worker 
369*4dc78e53SAndroid Build Coastguard Worker 	err = nl_send_auto(sk, msg);
370*4dc78e53SAndroid Build Coastguard Worker 	if (err < 0)
371*4dc78e53SAndroid Build Coastguard Worker 		return err;
372*4dc78e53SAndroid Build Coastguard Worker 
373*4dc78e53SAndroid Build Coastguard Worker 	return NLE_SUCCESS;
374*4dc78e53SAndroid Build Coastguard Worker }
375*4dc78e53SAndroid Build Coastguard Worker 
dump_nh_group(nl_nh_group_t * group,struct nl_dump_params * dp)376*4dc78e53SAndroid Build Coastguard Worker static void dump_nh_group(nl_nh_group_t *group, struct nl_dump_params *dp)
377*4dc78e53SAndroid Build Coastguard Worker {
378*4dc78e53SAndroid Build Coastguard Worker 	unsigned i;
379*4dc78e53SAndroid Build Coastguard Worker 
380*4dc78e53SAndroid Build Coastguard Worker 	nl_dump(dp, " nh_grp:");
381*4dc78e53SAndroid Build Coastguard Worker 	for (i = 0; i < group->size; i++) {
382*4dc78e53SAndroid Build Coastguard Worker 		nl_dump(dp, " %u", group->entries[i].nh_id);
383*4dc78e53SAndroid Build Coastguard Worker 	}
384*4dc78e53SAndroid Build Coastguard Worker }
385*4dc78e53SAndroid Build Coastguard Worker 
nh_dump_line(struct nl_object * obj,struct nl_dump_params * dp)386*4dc78e53SAndroid Build Coastguard Worker static void nh_dump_line(struct nl_object *obj, struct nl_dump_params *dp)
387*4dc78e53SAndroid Build Coastguard Worker {
388*4dc78e53SAndroid Build Coastguard Worker 	struct nl_cache *cache;
389*4dc78e53SAndroid Build Coastguard Worker 	char buf[128];
390*4dc78e53SAndroid Build Coastguard Worker 	struct rtnl_nh *nh = nl_object_priv(obj);
391*4dc78e53SAndroid Build Coastguard Worker 
392*4dc78e53SAndroid Build Coastguard Worker 	cache = nl_cache_mngt_require_safe("route/nh");
393*4dc78e53SAndroid Build Coastguard Worker 
394*4dc78e53SAndroid Build Coastguard Worker 	if (nh->ce_mask & NH_ATTR_ID)
395*4dc78e53SAndroid Build Coastguard Worker 		nl_dump(dp, "nhid %u", nh->nh_id);
396*4dc78e53SAndroid Build Coastguard Worker 
397*4dc78e53SAndroid Build Coastguard Worker 	if (nh->ce_mask & NH_ATTR_OIF)
398*4dc78e53SAndroid Build Coastguard Worker 		nl_dump(dp, " oif %d", nh->nh_oif);
399*4dc78e53SAndroid Build Coastguard Worker 
400*4dc78e53SAndroid Build Coastguard Worker 	if (nh->ce_mask & NH_ATTR_GATEWAY)
401*4dc78e53SAndroid Build Coastguard Worker 		nl_dump(dp, " via %s",
402*4dc78e53SAndroid Build Coastguard Worker 			nl_addr2str(nh->nh_gateway, buf, sizeof(buf)));
403*4dc78e53SAndroid Build Coastguard Worker 
404*4dc78e53SAndroid Build Coastguard Worker 	if (nh->ce_mask & NH_ATTR_FLAG_BLACKHOLE)
405*4dc78e53SAndroid Build Coastguard Worker 		nl_dump(dp, " blackhole");
406*4dc78e53SAndroid Build Coastguard Worker 
407*4dc78e53SAndroid Build Coastguard Worker 	if (nh->ce_mask & NH_ATTR_FLAG_GROUPS)
408*4dc78e53SAndroid Build Coastguard Worker 		nl_dump(dp, " groups");
409*4dc78e53SAndroid Build Coastguard Worker 
410*4dc78e53SAndroid Build Coastguard Worker 	if (nh->ce_mask & NH_ATTR_GROUP)
411*4dc78e53SAndroid Build Coastguard Worker 		dump_nh_group(nh->nh_group, dp);
412*4dc78e53SAndroid Build Coastguard Worker 
413*4dc78e53SAndroid Build Coastguard Worker 	if (nh->ce_mask & NH_ATTR_FLAG_FDB)
414*4dc78e53SAndroid Build Coastguard Worker 		nl_dump(dp, " fdb");
415*4dc78e53SAndroid Build Coastguard Worker 
416*4dc78e53SAndroid Build Coastguard Worker 	nl_dump(dp, "\n");
417*4dc78e53SAndroid Build Coastguard Worker 
418*4dc78e53SAndroid Build Coastguard Worker 	if (cache)
419*4dc78e53SAndroid Build Coastguard Worker 		nl_cache_put(cache);
420*4dc78e53SAndroid Build Coastguard Worker }
421*4dc78e53SAndroid Build Coastguard Worker 
nh_dump_details(struct nl_object * nh,struct nl_dump_params * dp)422*4dc78e53SAndroid Build Coastguard Worker static void nh_dump_details(struct nl_object *nh, struct nl_dump_params *dp)
423*4dc78e53SAndroid Build Coastguard Worker {
424*4dc78e53SAndroid Build Coastguard Worker 	nh_dump_line(nh, dp);
425*4dc78e53SAndroid Build Coastguard Worker }
426*4dc78e53SAndroid Build Coastguard Worker 
nh_compare(struct nl_object * a,struct nl_object * b,uint64_t attrs,int loose)427*4dc78e53SAndroid Build Coastguard Worker static uint64_t nh_compare(struct nl_object *a, struct nl_object *b,
428*4dc78e53SAndroid Build Coastguard Worker 			   uint64_t attrs, int loose)
429*4dc78e53SAndroid Build Coastguard Worker {
430*4dc78e53SAndroid Build Coastguard Worker 	int diff = 0;
431*4dc78e53SAndroid Build Coastguard Worker 	struct rtnl_nh *src = nl_object_priv(a);
432*4dc78e53SAndroid Build Coastguard Worker 	struct rtnl_nh *dst = nl_object_priv(b);
433*4dc78e53SAndroid Build Coastguard Worker 
434*4dc78e53SAndroid Build Coastguard Worker #define _DIFF(ATTR, EXPR) ATTR_DIFF(attrs, ATTR, a, b, EXPR)
435*4dc78e53SAndroid Build Coastguard Worker 	diff |= _DIFF(NH_ATTR_ID, src->nh_id != dst->nh_id);
436*4dc78e53SAndroid Build Coastguard Worker 	diff |= _DIFF(NH_ATTR_GATEWAY,
437*4dc78e53SAndroid Build Coastguard Worker 		      nl_addr_cmp(src->nh_gateway, dst->nh_gateway));
438*4dc78e53SAndroid Build Coastguard Worker 	diff |= _DIFF(NH_ATTR_OIF, src->nh_oif != dst->nh_oif);
439*4dc78e53SAndroid Build Coastguard Worker 	diff |= _DIFF(NH_ATTR_GROUP,
440*4dc78e53SAndroid Build Coastguard Worker 		      rtnh_nh_grp_cmp(src->nh_group, dst->nh_group));
441*4dc78e53SAndroid Build Coastguard Worker 	diff |= _DIFF(NH_ATTR_FLAG_FDB, false);
442*4dc78e53SAndroid Build Coastguard Worker 	diff |= _DIFF(NH_ATTR_FLAG_GROUPS, false);
443*4dc78e53SAndroid Build Coastguard Worker 	diff |= _DIFF(NH_ATTR_FLAG_BLACKHOLE, false);
444*4dc78e53SAndroid Build Coastguard Worker #undef _DIFF
445*4dc78e53SAndroid Build Coastguard Worker 
446*4dc78e53SAndroid Build Coastguard Worker 	return diff;
447*4dc78e53SAndroid Build Coastguard Worker }
448*4dc78e53SAndroid Build Coastguard Worker 
rtnl_nh_get(struct nl_cache * cache,int nhid)449*4dc78e53SAndroid Build Coastguard Worker struct rtnl_nh *rtnl_nh_get(struct nl_cache *cache, int nhid)
450*4dc78e53SAndroid Build Coastguard Worker {
451*4dc78e53SAndroid Build Coastguard Worker 	struct rtnl_nh *nh;
452*4dc78e53SAndroid Build Coastguard Worker 
453*4dc78e53SAndroid Build Coastguard Worker 	if (cache->c_ops != &rtnl_nh_ops)
454*4dc78e53SAndroid Build Coastguard Worker 		return NULL;
455*4dc78e53SAndroid Build Coastguard Worker 
456*4dc78e53SAndroid Build Coastguard Worker 	nl_list_for_each_entry(nh, &cache->c_items, ce_list) {
457*4dc78e53SAndroid Build Coastguard Worker 		if (nh->nh_id == ((unsigned)nhid)) {
458*4dc78e53SAndroid Build Coastguard Worker 			nl_object_get((struct nl_object *)nh);
459*4dc78e53SAndroid Build Coastguard Worker 			return nh;
460*4dc78e53SAndroid Build Coastguard Worker 		}
461*4dc78e53SAndroid Build Coastguard Worker 	}
462*4dc78e53SAndroid Build Coastguard Worker 
463*4dc78e53SAndroid Build Coastguard Worker 	return NULL;
464*4dc78e53SAndroid Build Coastguard Worker }
465*4dc78e53SAndroid Build Coastguard Worker 
466*4dc78e53SAndroid Build Coastguard Worker /**
467*4dc78e53SAndroid Build Coastguard Worker  * Allocate nexthop cache and fill in all configured nexthops.
468*4dc78e53SAndroid Build Coastguard Worker  * @arg sk		Netnexthop socket.
469*4dc78e53SAndroid Build Coastguard Worker  * @arg family		nexthop address family or AF_UNSPEC
470*4dc78e53SAndroid Build Coastguard Worker  * @arg result		Pointer to store resulting cache.
471*4dc78e53SAndroid Build Coastguard Worker  * @arg flags		Flags to set in nexthop cache before filling
472*4dc78e53SAndroid Build Coastguard Worker  *
473*4dc78e53SAndroid Build Coastguard Worker  * Allocates and initializes a new nexthop cache. If \c sk is valid, a netnexthop
474*4dc78e53SAndroid Build Coastguard Worker  * message is sent to the kernel requesting a full dump of all configured
475*4dc78e53SAndroid Build Coastguard Worker  * nexthops. The returned messages are parsed and filled into the cache. If
476*4dc78e53SAndroid Build Coastguard Worker  * the operation succeeds, the resulting cache will contain a nexthop object for
477*4dc78e53SAndroid Build Coastguard Worker  * each nexthop configured in the kernel. If \c sk is NULL, returns 0 but the
478*4dc78e53SAndroid Build Coastguard Worker  * cache is still empty.
479*4dc78e53SAndroid Build Coastguard Worker  *
480*4dc78e53SAndroid Build Coastguard Worker  * If \c family is set to an address family other than \c AF_UNSPEC the
481*4dc78e53SAndroid Build Coastguard Worker  * contents of the cache can be limited to a specific address family.
482*4dc78e53SAndroid Build Coastguard Worker  * Currently the following address families are supported:
483*4dc78e53SAndroid Build Coastguard Worker  * - AF_BRIDGE
484*4dc78e53SAndroid Build Coastguard Worker  * - AF_INET6
485*4dc78e53SAndroid Build Coastguard Worker  *
486*4dc78e53SAndroid Build Coastguard Worker  * @route_doc{nexthop_list, Get List of nexthops}
487*4dc78e53SAndroid Build Coastguard Worker  * @see rtnl_nh_get()
488*4dc78e53SAndroid Build Coastguard Worker  * @see rtnl_nh_get_by_name()
489*4dc78e53SAndroid Build Coastguard Worker  * @return 0 on success or a negative error code.
490*4dc78e53SAndroid Build Coastguard Worker  */
rtnl_nh_alloc_cache_flags(struct nl_sock * sk,int family,struct nl_cache ** result,unsigned int flags)491*4dc78e53SAndroid Build Coastguard Worker static int rtnl_nh_alloc_cache_flags(struct nl_sock *sk, int family,
492*4dc78e53SAndroid Build Coastguard Worker 				     struct nl_cache **result,
493*4dc78e53SAndroid Build Coastguard Worker 				     unsigned int flags)
494*4dc78e53SAndroid Build Coastguard Worker {
495*4dc78e53SAndroid Build Coastguard Worker 	struct nl_cache *cache;
496*4dc78e53SAndroid Build Coastguard Worker 	int err;
497*4dc78e53SAndroid Build Coastguard Worker 
498*4dc78e53SAndroid Build Coastguard Worker 	cache = nl_cache_alloc(&rtnl_nh_ops);
499*4dc78e53SAndroid Build Coastguard Worker 	if (!cache)
500*4dc78e53SAndroid Build Coastguard Worker 		return -NLE_NOMEM;
501*4dc78e53SAndroid Build Coastguard Worker 
502*4dc78e53SAndroid Build Coastguard Worker 	cache->c_iarg1 = family;
503*4dc78e53SAndroid Build Coastguard Worker 
504*4dc78e53SAndroid Build Coastguard Worker 	if (flags)
505*4dc78e53SAndroid Build Coastguard Worker 		nl_cache_set_flags(cache, flags);
506*4dc78e53SAndroid Build Coastguard Worker 
507*4dc78e53SAndroid Build Coastguard Worker 	if (sk && (err = nl_cache_refill(sk, cache)) < 0) {
508*4dc78e53SAndroid Build Coastguard Worker 		nl_cache_free(cache);
509*4dc78e53SAndroid Build Coastguard Worker 		return err;
510*4dc78e53SAndroid Build Coastguard Worker 	}
511*4dc78e53SAndroid Build Coastguard Worker 
512*4dc78e53SAndroid Build Coastguard Worker 	*result = cache;
513*4dc78e53SAndroid Build Coastguard Worker 	return 0;
514*4dc78e53SAndroid Build Coastguard Worker }
515*4dc78e53SAndroid Build Coastguard Worker 
516*4dc78e53SAndroid Build Coastguard Worker /**
517*4dc78e53SAndroid Build Coastguard Worker  * Allocate nexthop cache and fill in all configured nexthops.
518*4dc78e53SAndroid Build Coastguard Worker  * @arg sk		Netnexthop socket.
519*4dc78e53SAndroid Build Coastguard Worker  * @arg family		nexthop address family or AF_UNSPEC
520*4dc78e53SAndroid Build Coastguard Worker  * @arg result		Pointer to store resulting cache.
521*4dc78e53SAndroid Build Coastguard Worker  *
522*4dc78e53SAndroid Build Coastguard Worker  * Allocates and initializes a new nexthop cache. If \c sk is valid, a netnexthop
523*4dc78e53SAndroid Build Coastguard Worker  * message is sent to the kernel requesting a full dump of all configured
524*4dc78e53SAndroid Build Coastguard Worker  * nexthops. The returned messages are parsed and filled into the cache. If
525*4dc78e53SAndroid Build Coastguard Worker  * the operation succeeds, the resulting cache will contain a nexthop object for
526*4dc78e53SAndroid Build Coastguard Worker  * each nexthop configured in the kernel. If \c sk is NULL, returns 0 but the
527*4dc78e53SAndroid Build Coastguard Worker  * cache is still empty.
528*4dc78e53SAndroid Build Coastguard Worker  *
529*4dc78e53SAndroid Build Coastguard Worker  * If \c family is set to an address family other than \c AF_UNSPEC the
530*4dc78e53SAndroid Build Coastguard Worker  * contents of the cache can be limited to a specific address family.
531*4dc78e53SAndroid Build Coastguard Worker  * Currently the following address families are supported:
532*4dc78e53SAndroid Build Coastguard Worker  * - AF_BRIDGE
533*4dc78e53SAndroid Build Coastguard Worker  * - AF_INET6
534*4dc78e53SAndroid Build Coastguard Worker  *
535*4dc78e53SAndroid Build Coastguard Worker  * @route_doc{nexthop_list, Get List of nexthops}
536*4dc78e53SAndroid Build Coastguard Worker  * @see rtnl_nh_get()
537*4dc78e53SAndroid Build Coastguard Worker  * @see rtnl_nh_get_by_name()
538*4dc78e53SAndroid Build Coastguard Worker  * @return 0 on success or a negative error code.
539*4dc78e53SAndroid Build Coastguard Worker  */
rtnl_nh_alloc_cache(struct nl_sock * sk,int family,struct nl_cache ** result)540*4dc78e53SAndroid Build Coastguard Worker int rtnl_nh_alloc_cache(struct nl_sock *sk, int family,
541*4dc78e53SAndroid Build Coastguard Worker 			struct nl_cache **result)
542*4dc78e53SAndroid Build Coastguard Worker {
543*4dc78e53SAndroid Build Coastguard Worker 	return rtnl_nh_alloc_cache_flags(sk, family, result, 0);
544*4dc78e53SAndroid Build Coastguard Worker }
545*4dc78e53SAndroid Build Coastguard Worker 
546*4dc78e53SAndroid Build Coastguard Worker static struct nl_object_ops nh_obj_ops = {
547*4dc78e53SAndroid Build Coastguard Worker   .oo_name		= "route/nh",
548*4dc78e53SAndroid Build Coastguard Worker   .oo_size		= sizeof(struct rtnl_nh),
549*4dc78e53SAndroid Build Coastguard Worker   .oo_free_data		= nh_free,
550*4dc78e53SAndroid Build Coastguard Worker   .oo_clone		= nh_clone,
551*4dc78e53SAndroid Build Coastguard Worker   .oo_dump = {
552*4dc78e53SAndroid Build Coastguard Worker       [NL_DUMP_LINE]	= nh_dump_line,
553*4dc78e53SAndroid Build Coastguard Worker       [NL_DUMP_DETAILS]	= nh_dump_details,
554*4dc78e53SAndroid Build Coastguard Worker   },
555*4dc78e53SAndroid Build Coastguard Worker   .oo_compare		= nh_compare,
556*4dc78e53SAndroid Build Coastguard Worker   .oo_keygen		= nexthop_keygen,
557*4dc78e53SAndroid Build Coastguard Worker   .oo_attrs2str		= rtnl_route_nh_flags2str,
558*4dc78e53SAndroid Build Coastguard Worker   .oo_id_attrs		= NH_ATTR_ID,
559*4dc78e53SAndroid Build Coastguard Worker };
560*4dc78e53SAndroid Build Coastguard Worker 
561*4dc78e53SAndroid Build Coastguard Worker static struct nl_af_group nh_groups[] = {
562*4dc78e53SAndroid Build Coastguard Worker 	{ AF_UNSPEC, RTNLGRP_NEXTHOP },
563*4dc78e53SAndroid Build Coastguard Worker 	{ END_OF_GROUP_LIST },
564*4dc78e53SAndroid Build Coastguard Worker };
565*4dc78e53SAndroid Build Coastguard Worker 
566*4dc78e53SAndroid Build Coastguard Worker static struct nl_cache_ops rtnl_nh_ops = {
567*4dc78e53SAndroid Build Coastguard Worker   .co_name		= "route/nh",
568*4dc78e53SAndroid Build Coastguard Worker   .co_hdrsize		= sizeof(struct nhmsg),
569*4dc78e53SAndroid Build Coastguard Worker   .co_msgtypes		= {
570*4dc78e53SAndroid Build Coastguard Worker           { RTM_NEWNEXTHOP, NL_ACT_NEW, "new" },
571*4dc78e53SAndroid Build Coastguard Worker           { RTM_DELNEXTHOP, NL_ACT_DEL, "del" },
572*4dc78e53SAndroid Build Coastguard Worker           { RTM_GETNEXTHOP, NL_ACT_GET, "get" },
573*4dc78e53SAndroid Build Coastguard Worker           END_OF_MSGTYPES_LIST,
574*4dc78e53SAndroid Build Coastguard Worker           },
575*4dc78e53SAndroid Build Coastguard Worker   .co_protocol  = NETLINK_ROUTE,
576*4dc78e53SAndroid Build Coastguard Worker   .co_groups		= nh_groups,
577*4dc78e53SAndroid Build Coastguard Worker   .co_request_update	= nexthop_request_update,
578*4dc78e53SAndroid Build Coastguard Worker   .co_msg_parser		= nexthop_msg_parser,
579*4dc78e53SAndroid Build Coastguard Worker   .co_obj_ops		= &nh_obj_ops,
580*4dc78e53SAndroid Build Coastguard Worker };
581*4dc78e53SAndroid Build Coastguard Worker 
nexthop_init(void)582*4dc78e53SAndroid Build Coastguard Worker static void _nl_init nexthop_init(void)
583*4dc78e53SAndroid Build Coastguard Worker {
584*4dc78e53SAndroid Build Coastguard Worker 	nl_cache_mngt_register(&rtnl_nh_ops);
585*4dc78e53SAndroid Build Coastguard Worker }
586*4dc78e53SAndroid Build Coastguard Worker 
nexthop_exit(void)587*4dc78e53SAndroid Build Coastguard Worker static void _nl_exit nexthop_exit(void)
588*4dc78e53SAndroid Build Coastguard Worker {
589*4dc78e53SAndroid Build Coastguard Worker 	nl_cache_mngt_unregister(&rtnl_nh_ops);
590*4dc78e53SAndroid Build Coastguard Worker }
591