libnl  3.2.14
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 void rtnl_route_nh_dump(struct rtnl_nexthop *nh, struct nl_dump_params *dp)
170 {
171  switch (dp->dp_type) {
172  case NL_DUMP_LINE:
173  nh_dump_line(nh, dp);
174  break;
175 
176  case NL_DUMP_DETAILS:
177  case NL_DUMP_STATS:
178  if (dp->dp_ivar == NH_DUMP_FROM_DETAILS)
179  nh_dump_details(nh, dp);
180  break;
181 
182  default:
183  break;
184  }
185 }
186 
187 /**
188  * @name Attributes
189  * @{
190  */
191 
192 void rtnl_route_nh_set_weight(struct rtnl_nexthop *nh, uint8_t weight)
193 {
194  nh->rtnh_weight = weight;
195  nh->ce_mask |= NH_ATTR_WEIGHT;
196 }
197 
198 uint8_t rtnl_route_nh_get_weight(struct rtnl_nexthop *nh)
199 {
200  return nh->rtnh_weight;
201 }
202 
203 void rtnl_route_nh_set_ifindex(struct rtnl_nexthop *nh, int ifindex)
204 {
205  nh->rtnh_ifindex = ifindex;
206  nh->ce_mask |= NH_ATTR_IFINDEX;
207 }
208 
209 int rtnl_route_nh_get_ifindex(struct rtnl_nexthop *nh)
210 {
211  return nh->rtnh_ifindex;
212 }
213 
214 /* FIXME: Convert to return an int */
215 void rtnl_route_nh_set_gateway(struct rtnl_nexthop *nh, struct nl_addr *addr)
216 {
217  struct nl_addr *old = nh->rtnh_gateway;
218 
219  if (addr) {
220  nh->rtnh_gateway = nl_addr_get(addr);
221  nh->ce_mask |= NH_ATTR_GATEWAY;
222  } else {
223  nh->ce_mask &= ~NH_ATTR_GATEWAY;
224  nh->rtnh_gateway = NULL;
225  }
226 
227  if (old)
228  nl_addr_put(old);
229 }
230 
231 struct nl_addr *rtnl_route_nh_get_gateway(struct rtnl_nexthop *nh)
232 {
233  return nh->rtnh_gateway;
234 }
235 
236 void rtnl_route_nh_set_flags(struct rtnl_nexthop *nh, unsigned int flags)
237 {
238  nh->rtnh_flag_mask |= flags;
239  nh->rtnh_flags |= flags;
240  nh->ce_mask |= NH_ATTR_FLAGS;
241 }
242 
243 void rtnl_route_nh_unset_flags(struct rtnl_nexthop *nh, unsigned int flags)
244 {
245  nh->rtnh_flag_mask |= flags;
246  nh->rtnh_flags &= ~flags;
247  nh->ce_mask |= NH_ATTR_FLAGS;
248 }
249 
250 unsigned int rtnl_route_nh_get_flags(struct rtnl_nexthop *nh)
251 {
252  return nh->rtnh_flags;
253 }
254 
255 void rtnl_route_nh_set_realms(struct rtnl_nexthop *nh, uint32_t realms)
256 {
257  nh->rtnh_realms = realms;
258  nh->ce_mask |= NH_ATTR_REALMS;
259 }
260 
261 uint32_t rtnl_route_nh_get_realms(struct rtnl_nexthop *nh)
262 {
263  return nh->rtnh_realms;
264 }
265 
266 /** @} */
267 
268 /**
269  * @name Nexthop Flags Translations
270  * @{
271  */
272 
273 static const struct trans_tbl nh_flags[] = {
274  __ADD(RTNH_F_DEAD, dead)
275  __ADD(RTNH_F_PERVASIVE, pervasive)
276  __ADD(RTNH_F_ONLINK, onlink)
277 };
278 
279 char *rtnl_route_nh_flags2str(int flags, char *buf, size_t len)
280 {
281  return __flags2str(flags, buf, len, nh_flags, ARRAY_SIZE(nh_flags));
282 }
283 
284 int rtnl_route_nh_str2flags(const char *name)
285 {
286  return __str2flags(name, nh_flags, ARRAY_SIZE(nh_flags));
287 }
288 
289 /** @} */
290 
291 /** @} */