upload tizen1.0 source
[external/libnl2.git] / lib / route / nexthop.c
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
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
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
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
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
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
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
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 }
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
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
238 uint8_t rtnl_route_nh_get_weight(struct rtnl_nexthop *nh)
239 {
240         return nh->rtnh_weight;
241 }
242
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
249 int rtnl_route_nh_get_ifindex(struct rtnl_nexthop *nh)
250 {
251         return nh->rtnh_ifindex;
252 }       
253
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
270 struct nl_addr *rtnl_route_nh_get_gateway(struct rtnl_nexthop *nh)
271 {
272         return nh->rtnh_gateway;
273 }
274
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
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
289 unsigned int rtnl_route_nh_get_flags(struct rtnl_nexthop *nh)
290 {
291         return nh->rtnh_flags;
292 }
293
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
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
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
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 /** @} */