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-private/netlink.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_safe("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 if (link_cache)
133 nl_cache_put(link_cache);
134 }
135
nh_dump_details(struct rtnl_nexthop * nh,struct nl_dump_params * dp)136 static void nh_dump_details(struct rtnl_nexthop *nh, struct nl_dump_params *dp)
137 {
138 struct nl_cache *link_cache;
139 char buf[128];
140
141 link_cache = nl_cache_mngt_require_safe("route/link");
142
143 nl_dump(dp, "nexthop");
144
145 if (nh->ce_mask & NH_ATTR_GATEWAY)
146 nl_dump(dp, " via %s", nl_addr2str(nh->rtnh_gateway,
147 buf, sizeof(buf)));
148
149 if(nh->ce_mask & NH_ATTR_IFINDEX) {
150 if (link_cache) {
151 nl_dump(dp, " dev %s",
152 rtnl_link_i2name(link_cache,
153 nh->rtnh_ifindex,
154 buf, sizeof(buf)));
155 } else
156 nl_dump(dp, " dev %d", nh->rtnh_ifindex);
157 }
158
159 if (nh->ce_mask & NH_ATTR_WEIGHT)
160 nl_dump(dp, " weight %u", nh->rtnh_weight);
161
162 if (nh->ce_mask & NH_ATTR_REALMS)
163 nl_dump(dp, " realm %04x:%04x",
164 RTNL_REALM_FROM(nh->rtnh_realms),
165 RTNL_REALM_TO(nh->rtnh_realms));
166
167 if (nh->ce_mask & NH_ATTR_FLAGS)
168 nl_dump(dp, " <%s>", rtnl_route_nh_flags2str(nh->rtnh_flags,
169 buf, sizeof(buf)));
170
171 if (link_cache)
172 nl_cache_put(link_cache);
173 }
174
rtnl_route_nh_dump(struct rtnl_nexthop * nh,struct nl_dump_params * dp)175 void rtnl_route_nh_dump(struct rtnl_nexthop *nh, struct nl_dump_params *dp)
176 {
177 switch (dp->dp_type) {
178 case NL_DUMP_LINE:
179 nh_dump_line(nh, dp);
180 break;
181
182 case NL_DUMP_DETAILS:
183 case NL_DUMP_STATS:
184 if (dp->dp_ivar == NH_DUMP_FROM_DETAILS)
185 nh_dump_details(nh, dp);
186 break;
187
188 default:
189 break;
190 }
191 }
192
193 /**
194 * @name Attributes
195 * @{
196 */
197
rtnl_route_nh_set_weight(struct rtnl_nexthop * nh,uint8_t weight)198 void rtnl_route_nh_set_weight(struct rtnl_nexthop *nh, uint8_t weight)
199 {
200 nh->rtnh_weight = weight;
201 nh->ce_mask |= NH_ATTR_WEIGHT;
202 }
203
rtnl_route_nh_get_weight(struct rtnl_nexthop * nh)204 uint8_t rtnl_route_nh_get_weight(struct rtnl_nexthop *nh)
205 {
206 return nh->rtnh_weight;
207 }
208
rtnl_route_nh_set_ifindex(struct rtnl_nexthop * nh,int ifindex)209 void rtnl_route_nh_set_ifindex(struct rtnl_nexthop *nh, int ifindex)
210 {
211 nh->rtnh_ifindex = ifindex;
212 nh->ce_mask |= NH_ATTR_IFINDEX;
213 }
214
rtnl_route_nh_get_ifindex(struct rtnl_nexthop * nh)215 int rtnl_route_nh_get_ifindex(struct rtnl_nexthop *nh)
216 {
217 return nh->rtnh_ifindex;
218 }
219
220 /* FIXME: Convert to return an int */
rtnl_route_nh_set_gateway(struct rtnl_nexthop * nh,struct nl_addr * addr)221 void rtnl_route_nh_set_gateway(struct rtnl_nexthop *nh, struct nl_addr *addr)
222 {
223 struct nl_addr *old = nh->rtnh_gateway;
224
225 if (addr) {
226 nh->rtnh_gateway = nl_addr_get(addr);
227 nh->ce_mask |= NH_ATTR_GATEWAY;
228 } else {
229 nh->ce_mask &= ~NH_ATTR_GATEWAY;
230 nh->rtnh_gateway = NULL;
231 }
232
233 if (old)
234 nl_addr_put(old);
235 }
236
rtnl_route_nh_get_gateway(struct rtnl_nexthop * nh)237 struct nl_addr *rtnl_route_nh_get_gateway(struct rtnl_nexthop *nh)
238 {
239 return nh->rtnh_gateway;
240 }
241
rtnl_route_nh_set_flags(struct rtnl_nexthop * nh,unsigned int flags)242 void rtnl_route_nh_set_flags(struct rtnl_nexthop *nh, unsigned int flags)
243 {
244 nh->rtnh_flag_mask |= flags;
245 nh->rtnh_flags |= flags;
246 nh->ce_mask |= NH_ATTR_FLAGS;
247 }
248
rtnl_route_nh_unset_flags(struct rtnl_nexthop * nh,unsigned int flags)249 void rtnl_route_nh_unset_flags(struct rtnl_nexthop *nh, unsigned int flags)
250 {
251 nh->rtnh_flag_mask |= flags;
252 nh->rtnh_flags &= ~flags;
253 nh->ce_mask |= NH_ATTR_FLAGS;
254 }
255
rtnl_route_nh_get_flags(struct rtnl_nexthop * nh)256 unsigned int rtnl_route_nh_get_flags(struct rtnl_nexthop *nh)
257 {
258 return nh->rtnh_flags;
259 }
260
rtnl_route_nh_set_realms(struct rtnl_nexthop * nh,uint32_t realms)261 void rtnl_route_nh_set_realms(struct rtnl_nexthop *nh, uint32_t realms)
262 {
263 nh->rtnh_realms = realms;
264 nh->ce_mask |= NH_ATTR_REALMS;
265 }
266
rtnl_route_nh_get_realms(struct rtnl_nexthop * nh)267 uint32_t rtnl_route_nh_get_realms(struct rtnl_nexthop *nh)
268 {
269 return nh->rtnh_realms;
270 }
271
272 /** @} */
273
274 /**
275 * @name Nexthop Flags Translations
276 * @{
277 */
278
279 static const struct trans_tbl nh_flags[] = {
280 __ADD(RTNH_F_DEAD, dead)
281 __ADD(RTNH_F_PERVASIVE, pervasive)
282 __ADD(RTNH_F_ONLINK, onlink)
283 };
284
rtnl_route_nh_flags2str(int flags,char * buf,size_t len)285 char *rtnl_route_nh_flags2str(int flags, char *buf, size_t len)
286 {
287 return __flags2str(flags, buf, len, nh_flags, ARRAY_SIZE(nh_flags));
288 }
289
rtnl_route_nh_str2flags(const char * name)290 int rtnl_route_nh_str2flags(const char *name)
291 {
292 return __str2flags(name, nh_flags, ARRAY_SIZE(nh_flags));
293 }
294
295 /** @} */
296
297 /** @} */
298