• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * lib/route/nexthop.c	Routing Nexthop
3  *
4  *	This library is free software; you can redistribute it and/or
5  *	modify it under the terms of the GNU Lesser General Public
6  *	License as published by the Free Software Foundation version 2.1
7  *	of the License.
8  *
9  * Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch>
10  */
11 
12 /**
13  * @ingroup route_obj
14  * @defgroup nexthop Nexthop
15  * @{
16  */
17 
18 #include <netlink-local.h>
19 #include <netlink/netlink.h>
20 #include <netlink/utils.h>
21 #include <netlink/route/rtnl.h>
22 #include <netlink/route/route.h>
23 
24 /** @cond SKIP */
25 #define NH_ATTR_FLAGS   0x000001
26 #define NH_ATTR_WEIGHT  0x000002
27 #define NH_ATTR_IFINDEX 0x000004
28 #define NH_ATTR_GATEWAY 0x000008
29 #define NH_ATTR_REALMS  0x000010
30 /** @endcond */
31 
32 /**
33  * @name Allocation/Freeing
34  * @{
35  */
36 
rtnl_route_nh_alloc(void)37 struct rtnl_nexthop *rtnl_route_nh_alloc(void)
38 {
39 	struct rtnl_nexthop *nh;
40 
41 	nh = calloc(1, sizeof(*nh));
42 	if (!nh)
43 		return NULL;
44 
45 	nl_init_list_head(&nh->rtnh_list);
46 
47 	return nh;
48 }
49 
rtnl_route_nh_clone(struct rtnl_nexthop * src)50 struct rtnl_nexthop *rtnl_route_nh_clone(struct rtnl_nexthop *src)
51 {
52 	struct rtnl_nexthop *nh;
53 
54 	nh = rtnl_route_nh_alloc();
55 	if (!nh)
56 		return NULL;
57 
58 	nh->rtnh_flags = src->rtnh_flags;
59 	nh->rtnh_flag_mask = src->rtnh_flag_mask;
60 	nh->rtnh_weight = src->rtnh_weight;
61 	nh->rtnh_ifindex = src->rtnh_ifindex;
62 	nh->ce_mask = src->ce_mask;
63 
64 	if (src->rtnh_gateway) {
65 		nh->rtnh_gateway = nl_addr_clone(src->rtnh_gateway);
66 		if (!nh->rtnh_gateway) {
67 			free(nh);
68 			return NULL;
69 		}
70 	}
71 
72 	return nh;
73 }
74 
rtnl_route_nh_free(struct rtnl_nexthop * nh)75 void rtnl_route_nh_free(struct rtnl_nexthop *nh)
76 {
77 	nl_addr_put(nh->rtnh_gateway);
78 	free(nh);
79 }
80 
81 /** @} */
82 
rtnl_route_nh_compare(struct rtnl_nexthop * a,struct rtnl_nexthop * b,uint32_t attrs,int loose)83 int rtnl_route_nh_compare(struct rtnl_nexthop *a, struct rtnl_nexthop *b,
84 			  uint32_t attrs, int loose)
85 {
86 	int diff = 0;
87 
88 #define NH_DIFF(ATTR, EXPR) ATTR_DIFF(attrs, NH_ATTR_##ATTR, a, b, EXPR)
89 
90 	diff |= NH_DIFF(IFINDEX,	a->rtnh_ifindex != b->rtnh_ifindex);
91 	diff |= NH_DIFF(WEIGHT,		a->rtnh_weight != b->rtnh_weight);
92 	diff |= NH_DIFF(REALMS,		a->rtnh_realms != b->rtnh_realms);
93 	diff |= NH_DIFF(GATEWAY,	nl_addr_cmp(a->rtnh_gateway,
94 						    b->rtnh_gateway));
95 
96 	if (loose)
97 		diff |= NH_DIFF(FLAGS,
98 			  (a->rtnh_flags ^ b->rtnh_flags) & b->rtnh_flag_mask);
99 	else
100 		diff |= NH_DIFF(FLAGS, a->rtnh_flags != b->rtnh_flags);
101 
102 #undef NH_DIFF
103 
104 	return diff;
105 }
106 
nh_dump_line(struct rtnl_nexthop * nh,struct nl_dump_params * dp)107 static void nh_dump_line(struct rtnl_nexthop *nh, struct nl_dump_params *dp)
108 {
109 	struct nl_cache *link_cache;
110 	char buf[128];
111 
112 	link_cache = nl_cache_mngt_require("route/link");
113 
114 	nl_dump(dp, "via");
115 
116 	if (nh->ce_mask & NH_ATTR_GATEWAY)
117 		nl_dump(dp, " %s", nl_addr2str(nh->rtnh_gateway,
118 						   buf, sizeof(buf)));
119 
120 	if(nh->ce_mask & NH_ATTR_IFINDEX) {
121 		if (link_cache) {
122 			nl_dump(dp, " dev %s",
123 				rtnl_link_i2name(link_cache,
124 						 nh->rtnh_ifindex,
125 						 buf, sizeof(buf)));
126 		} else
127 			nl_dump(dp, " dev %d", nh->rtnh_ifindex);
128 	}
129 
130 	nl_dump(dp, " ");
131 }
132 
nh_dump_details(struct rtnl_nexthop * nh,struct nl_dump_params * dp)133 static void nh_dump_details(struct rtnl_nexthop *nh, struct nl_dump_params *dp)
134 {
135 	struct nl_cache *link_cache;
136 	char buf[128];
137 
138 	link_cache = nl_cache_mngt_require("route/link");
139 
140 	nl_dump(dp, "nexthop");
141 
142 	if (nh->ce_mask & NH_ATTR_GATEWAY)
143 		nl_dump(dp, " via %s", nl_addr2str(nh->rtnh_gateway,
144 						   buf, sizeof(buf)));
145 
146 	if(nh->ce_mask & NH_ATTR_IFINDEX) {
147 		if (link_cache) {
148 			nl_dump(dp, " dev %s",
149 				rtnl_link_i2name(link_cache,
150 						 nh->rtnh_ifindex,
151 						 buf, sizeof(buf)));
152 		} else
153 			nl_dump(dp, " dev %d", nh->rtnh_ifindex);
154 	}
155 
156 	if (nh->ce_mask & NH_ATTR_WEIGHT)
157 		nl_dump(dp, " weight %u", nh->rtnh_weight);
158 
159 	if (nh->ce_mask & NH_ATTR_REALMS)
160 		nl_dump(dp, " realm %04x:%04x",
161 			RTNL_REALM_FROM(nh->rtnh_realms),
162 			RTNL_REALM_TO(nh->rtnh_realms));
163 
164 	if (nh->ce_mask & NH_ATTR_FLAGS)
165 		nl_dump(dp, " <%s>", rtnl_route_nh_flags2str(nh->rtnh_flags,
166 							buf, sizeof(buf)));
167 }
168 
nh_dump_env(struct rtnl_nexthop * nh,struct nl_dump_params * dp)169 static void nh_dump_env(struct rtnl_nexthop *nh, struct nl_dump_params *dp)
170 {
171 	struct nl_cache *link_cache;
172 	char buf[128];
173 
174 	link_cache = nl_cache_mngt_require("route/link");
175 
176 	if (nh->ce_mask & NH_ATTR_GATEWAY)
177 		nl_dump_line(dp, "ROUTE_NH%d_VIA=%s\n", dp->dp_ivar,
178 			nl_addr2str(nh->rtnh_gateway, buf, sizeof(buf)));
179 
180 	if(nh->ce_mask & NH_ATTR_IFINDEX) {
181 		if (link_cache) {
182 			nl_dump_line(dp, "ROUTE_NH%d_DEV=%s\n", dp->dp_ivar,
183 					rtnl_link_i2name(link_cache,
184 						 nh->rtnh_ifindex,
185 						 buf, sizeof(buf)));
186 		} else
187 			nl_dump_line(dp, "ROUTE_NH%d_DEV=%d\n", dp->dp_ivar,
188 					nh->rtnh_ifindex);
189 	}
190 
191 	if (nh->ce_mask & NH_ATTR_WEIGHT)
192 		nl_dump_line(dp, "ROUTE_NH%d_WEIGHT=%u\n", dp->dp_ivar,
193 				nh->rtnh_weight);
194 
195 	if (nh->ce_mask & NH_ATTR_REALMS)
196 		nl_dump_line(dp, "ROUTE_NH%d_REALM=%04x:%04x\n", dp->dp_ivar,
197 			RTNL_REALM_FROM(nh->rtnh_realms),
198 			RTNL_REALM_TO(nh->rtnh_realms));
199 
200 	if (nh->ce_mask & NH_ATTR_FLAGS)
201 		nl_dump_line(dp, "ROUTE_NH%d_FLAGS=<%s>\n", dp->dp_ivar,
202 			rtnl_route_nh_flags2str(nh->rtnh_flags,
203 							buf, sizeof(buf)));
204 }
rtnl_route_nh_dump(struct rtnl_nexthop * nh,struct nl_dump_params * dp)205 void rtnl_route_nh_dump(struct rtnl_nexthop *nh, struct nl_dump_params *dp)
206 {
207 	switch (dp->dp_type) {
208 	case NL_DUMP_LINE:
209 		nh_dump_line(nh, dp);
210 		break;
211 
212 	case NL_DUMP_DETAILS:
213 	case NL_DUMP_STATS:
214 		if (dp->dp_ivar == NH_DUMP_FROM_DETAILS)
215 			nh_dump_details(nh, dp);
216 		break;
217 
218 	case NL_DUMP_ENV:
219 		nh_dump_env(nh, dp);
220 		break;
221 
222 	default:
223 		break;
224 	}
225 }
226 
227 /**
228  * @name Attributes
229  * @{
230  */
231 
rtnl_route_nh_set_weight(struct rtnl_nexthop * nh,uint8_t weight)232 void rtnl_route_nh_set_weight(struct rtnl_nexthop *nh, uint8_t weight)
233 {
234 	nh->rtnh_weight = weight;
235 	nh->ce_mask |= NH_ATTR_WEIGHT;
236 }
237 
rtnl_route_nh_get_weight(struct rtnl_nexthop * nh)238 uint8_t rtnl_route_nh_get_weight(struct rtnl_nexthop *nh)
239 {
240 	return nh->rtnh_weight;
241 }
242 
rtnl_route_nh_set_ifindex(struct rtnl_nexthop * nh,int ifindex)243 void rtnl_route_nh_set_ifindex(struct rtnl_nexthop *nh, int ifindex)
244 {
245 	nh->rtnh_ifindex = ifindex;
246 	nh->ce_mask |= NH_ATTR_IFINDEX;
247 }
248 
rtnl_route_nh_get_ifindex(struct rtnl_nexthop * nh)249 int rtnl_route_nh_get_ifindex(struct rtnl_nexthop *nh)
250 {
251 	return nh->rtnh_ifindex;
252 }
253 
rtnl_route_nh_set_gateway(struct rtnl_nexthop * nh,struct nl_addr * addr)254 void rtnl_route_nh_set_gateway(struct rtnl_nexthop *nh, struct nl_addr *addr)
255 {
256 	struct nl_addr *old = nh->rtnh_gateway;
257 
258 	if (addr) {
259 		nh->rtnh_gateway = nl_addr_get(addr);
260 		nh->ce_mask |= NH_ATTR_GATEWAY;
261 	} else {
262 		nh->ce_mask &= ~NH_ATTR_GATEWAY;
263 		nh->rtnh_gateway = NULL;
264 	}
265 
266 	if (old)
267 		nl_addr_put(old);
268 }
269 
rtnl_route_nh_get_gateway(struct rtnl_nexthop * nh)270 struct nl_addr *rtnl_route_nh_get_gateway(struct rtnl_nexthop *nh)
271 {
272 	return nh->rtnh_gateway;
273 }
274 
rtnl_route_nh_set_flags(struct rtnl_nexthop * nh,unsigned int flags)275 void rtnl_route_nh_set_flags(struct rtnl_nexthop *nh, unsigned int flags)
276 {
277 	nh->rtnh_flag_mask |= flags;
278 	nh->rtnh_flags |= flags;
279 	nh->ce_mask |= NH_ATTR_FLAGS;
280 }
281 
rtnl_route_nh_unset_flags(struct rtnl_nexthop * nh,unsigned int flags)282 void rtnl_route_nh_unset_flags(struct rtnl_nexthop *nh, unsigned int flags)
283 {
284 	nh->rtnh_flag_mask |= flags;
285 	nh->rtnh_flags &= ~flags;
286 	nh->ce_mask |= NH_ATTR_FLAGS;
287 }
288 
rtnl_route_nh_get_flags(struct rtnl_nexthop * nh)289 unsigned int rtnl_route_nh_get_flags(struct rtnl_nexthop *nh)
290 {
291 	return nh->rtnh_flags;
292 }
293 
rtnl_route_nh_set_realms(struct rtnl_nexthop * nh,uint32_t realms)294 void rtnl_route_nh_set_realms(struct rtnl_nexthop *nh, uint32_t realms)
295 {
296 	nh->rtnh_realms = realms;
297 	nh->ce_mask |= NH_ATTR_REALMS;
298 }
299 
rtnl_route_nh_get_realms(struct rtnl_nexthop * nh)300 uint32_t rtnl_route_nh_get_realms(struct rtnl_nexthop *nh)
301 {
302 	return nh->rtnh_realms;
303 }
304 
305 /** @} */
306 
307 /**
308  * @name Nexthop Flags Translations
309  * @{
310  */
311 
312 static struct trans_tbl nh_flags[] = {
313 	__ADD(RTNH_F_DEAD, dead)
314 	__ADD(RTNH_F_PERVASIVE, pervasive)
315 	__ADD(RTNH_F_ONLINK, onlink)
316 };
317 
rtnl_route_nh_flags2str(int flags,char * buf,size_t len)318 char *rtnl_route_nh_flags2str(int flags, char *buf, size_t len)
319 {
320 	return __flags2str(flags, buf, len, nh_flags, ARRAY_SIZE(nh_flags));
321 }
322 
rtnl_route_nh_str2flags(const char * name)323 int rtnl_route_nh_str2flags(const char *name)
324 {
325 	return __str2flags(name, nh_flags, ARRAY_SIZE(nh_flags));
326 }
327 
328 /** @} */
329 
330 /** @} */
331