Apache Mesos
internal.hpp
Go to the documentation of this file.
1 // Licensed to the Apache Software Foundation (ASF) under one
2 // or more contributor license agreements. See the NOTICE file
3 // distributed with this work for additional information
4 // regarding copyright ownership. The ASF licenses this file
5 // to you under the Apache License, Version 2.0 (the
6 // "License"); you may not use this file except in compliance
7 // with the License. You may obtain a copy of the License at
8 //
9 // http://www.apache.org/licenses/LICENSE-2.0
10 //
11 // Unless required by applicable law or agreed to in writing, software
12 // distributed under the License is distributed on an "AS IS" BASIS,
13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 // See the License for the specific language governing permissions and
15 // limitations under the License.
16 
17 #ifndef __LINUX_ROUTING_QUEUEING_INTERNAL_HPP__
18 #define __LINUX_ROUTING_QUEUEING_INTERNAL_HPP__
19 
20 #include <netlink/cache.h>
21 #include <netlink/errno.h>
22 #include <netlink/object.h>
23 #include <netlink/socket.h>
24 
25 #include <netlink/route/link.h>
26 #include <netlink/route/qdisc.h>
27 #include <netlink/route/tc.h>
28 
29 #include <string>
30 #include <vector>
31 
32 #include <stout/error.hpp>
33 #include <stout/foreach.hpp>
34 #include <stout/none.hpp>
35 #include <stout/nothing.hpp>
36 #include <stout/result.hpp>
37 #include <stout/try.hpp>
38 
39 #include "linux/routing/handle.hpp"
41 
43 
46 
47 namespace routing {
48 
49 template <>
50 inline void cleanup(struct rtnl_qdisc* qdisc)
51 {
52  rtnl_qdisc_put(qdisc);
53 }
54 
55 namespace queueing {
56 namespace internal {
57 
59 // Helpers for {en}decoding.
61 
62 // Forward declaration. Each type of queueing discipline needs to
63 // implement this function to encode its type specific configurations
64 // into the libnl queueing discipline (rtnl_qdisc).
65 template <typename Config>
67  const Netlink<struct rtnl_qdisc>& qdisc,
68  const Config& config);
69 
70 
71 // Forward declaration. Each type of queueing discipline needs to
72 // implement this function to decode its type specific configurations
73 // from the libnl queueing discipline (rtnl_qdisc). Returns None if
74 // the libnl queueing discipline does not match the specified queueing
75 // discipline type.
76 template <typename Config>
78 
79 
80 // Encodes a queueing discipline (in our representation) to a libnl
81 // queueing discipline (rtnl_qdisc). We use template here so that it
82 // works for any type of queueing discipline.
83 template <typename Config>
85  const Netlink<struct rtnl_link>& link,
86  const Discipline<Config>& discipline)
87 {
88  struct rtnl_qdisc* q = rtnl_qdisc_alloc();
89  if (q == nullptr) {
90  return Error("Failed to allocate a libnl qdisc");
91  }
92 
94 
95  rtnl_tc_set_link(TC_CAST(qdisc.get()), link.get());
96  rtnl_tc_set_parent(TC_CAST(qdisc.get()), discipline.parent.get());
97 
98  if (discipline.handle.isSome()) {
99  rtnl_tc_set_handle(TC_CAST(qdisc.get()), discipline.handle.get().get());
100  }
101 
102  int error = rtnl_tc_set_kind(TC_CAST(qdisc.get()), discipline.kind.c_str());
103  if (error != 0) {
104  return Error(
105  "Failed to set the kind of the queueing discipline: " +
106  std::string(nl_geterror(error)));
107  }
108 
109  // Perform queue discipline specific encoding.
110  Try<Nothing> encoding = encode(qdisc, discipline.config);
111  if (encoding.isError()) {
112  return Error(
113  "Failed to encode the queueing discipline: " +
114  encoding.error());
115  }
116 
117  return qdisc;
118 }
119 
121 // Helpers for internal APIs.
123 
124 // Returns all the libnl queue discipline (rtnl_qdisc) on the link.
126  const Netlink<struct rtnl_link>& link)
127 {
129  if (socket.isError()) {
130  return Error(socket.error());
131  }
132 
133  // Dump all the queueing discipline from kernel.
134  struct nl_cache* c = nullptr;
135  int error = rtnl_qdisc_alloc_cache(socket.get().get(), &c);
136  if (error != 0) {
137  return Error(
138  "Failed to get queueing discipline info from kernel: " +
139  std::string(nl_geterror(error)));
140  }
141 
142  Netlink<struct nl_cache> cache(c);
143 
144  std::vector<Netlink<struct rtnl_qdisc>> results;
145 
146  for (struct nl_object* o = nl_cache_get_first(cache.get());
147  o != nullptr; o = nl_cache_get_next(o)) {
148  if (rtnl_tc_get_ifindex(TC_CAST(o)) == rtnl_link_get_ifindex(link.get())) {
149  // NOTE: We increment the reference counter here because 'cache'
150  // will be freed when this function finishes and we want this
151  // object's life to be longer than this function.
152  nl_object_get(o);
153 
154  results.push_back(Netlink<struct rtnl_qdisc>((struct rtnl_qdisc*) o));
155  }
156  }
157 
158  return results;
159 }
160 
161 
162 // Returns the libnl queueing discipline (rtnl_qdisc) attached to the
163 // given parent that matches the specified queueing discipline kind on
164 // the link. Return None if no match has been found.
166  const Netlink<struct rtnl_link>& link,
167  const Handle& parent,
168  const std::string& kind)
169 {
171  if (qdiscs.isError()) {
172  return Error(qdiscs.error());
173  }
174 
175  foreach (const Netlink<struct rtnl_qdisc>& qdisc, qdiscs.get()) {
176  if (rtnl_tc_get_parent(TC_CAST(qdisc.get())) == parent.get() &&
177  rtnl_tc_get_kind(TC_CAST(qdisc.get())) == kind) {
178  return qdisc;
179  }
180  }
181 
182  return None();
183 }
184 
186 // Internal queueing APIs.
188 
189 // Returns true if there exists a queueing discipline attached to the
190 // given parent that matches the specified queueing discipline kind on
191 // the link.
193  const std::string& _link,
194  const Handle& parent,
195  const std::string& kind)
196 {
198  if (link.isError()) {
199  return Error(link.error());
200  } else if (link.isNone()) {
201  return false;
202  }
203 
204  Result<Netlink<struct rtnl_qdisc>> qdisc = getQdisc(link.get(), parent, kind);
205  if (qdisc.isError()) {
206  return Error(qdisc.error());
207  }
208 
209  return qdisc.isSome();
210 }
211 
212 
213 // Creates a new queueing discipline on the link. Returns false if a
214 // queueing discipline attached to the same parent with the same
215 // configuration already exists on the link. We use template here so
216 // that it works for any type of queueing discipline.
217 template <typename Config>
219  const std::string& _link,
220  const Discipline<Config>& discipline)
221 {
223  if (link.isError()) {
224  return Error(link.error());
225  } else if (link.isNone()) {
226  return Error("Link '" + _link + "' is not found");
227  }
228 
230  encodeDiscipline(link.get(), discipline);
231 
232  if (qdisc.isError()) {
233  return Error("Failed to encode the queueing discipline: " + qdisc.error());
234  }
235 
237  if (socket.isError()) {
238  return Error(socket.error());
239  }
240 
241  // The flag NLM_F_EXCL tells libnl that if the qdisc already exists,
242  // this function should return error.
243  int error = rtnl_qdisc_add(
244  socket.get().get(),
245  qdisc.get().get(),
246  NLM_F_CREATE | NLM_F_EXCL);
247 
248  if (error != 0) {
249  if (error == -NLE_EXIST) {
250  return false;
251  }
252  return Error(
253  "Failed to add a queueing discipline to the link: " +
254  std::string(nl_geterror(error)));
255  }
256 
257  return true;
258 }
259 
260 
261 // Removes the specified discipline attached to the given parent that
262 // matches the specified queueing discipline kind on the link. Return
263 // false if such a queueing discipline is not found.
264 inline Try<bool> remove(
265  const std::string& _link,
266  const Handle& parent,
267  const std::string& kind)
268 {
270  if (link.isError()) {
271  return Error(link.error());
272  } else if (link.isNone()) {
273  return false;
274  }
275 
276  Result<Netlink<struct rtnl_qdisc>> qdisc = getQdisc(link.get(), parent, kind);
277  if (qdisc.isError()) {
278  return Error(qdisc.error());
279  } else if (qdisc.isNone()) {
280  return false;
281  }
282 
284  if (socket.isError()) {
285  return Error(socket.error());
286  }
287 
288  int error = rtnl_qdisc_delete(socket.get().get(), qdisc.get().get());
289  if (error != 0) {
290  // TODO(jieyu): Interpret the error code and return false if it
291  // indicates that the queueing discipline is not found.
292  return Error(std::string(nl_geterror(error)));
293  }
294 
295  return true;
296 }
297 
298 
299 // Returns the set of common Traffic Control statistics for the
300 // queueing discipline on the link, None() if the link or qdisc does
301 // not exist or an error if we cannot cannot determine the result.
303  const std::string& _link,
304  const Handle& parent,
305  const std::string& kind)
306 {
308  if (link.isError()) {
309  return Error(link.error());
310  } else if (link.isNone()) {
311  return None();
312  }
313 
314  Result<Netlink<struct rtnl_qdisc>> qdisc = getQdisc(link.get(), parent, kind);
315  if (qdisc.isError()) {
316  return Error(qdisc.error());
317  } else if (qdisc.isNone()) {
318  return None();
319  }
320 
322  char name[32];
323 
324  // NOTE: We use '<=' here because RTNL_TC_STATS_MAX is set to be the
325  // value of the last enum entry.
326  for (size_t i = 0; i <= static_cast<size_t>(RTNL_TC_STATS_MAX); i++) {
327  if (rtnl_tc_stat2str(static_cast<rtnl_tc_stat>(i), name, sizeof(name))) {
328  results[name] = rtnl_tc_get_stat(
329  TC_CAST(qdisc.get().get()),
330  static_cast<rtnl_tc_stat>(i));
331  }
332  }
333  return results;
334 }
335 
336 } // namespace internal {
337 } // namespace queueing {
338 } // namespace routing {
339 
340 #endif // __LINUX_ROUTING_QUEUEING_INTERNAL_HPP__
std::string kind
Definition: discipline.hpp:42
bool isNone() const
Definition: result.hpp:112
Definition: errorbase.hpp:35
Result< hashmap< std::string, uint64_t > > statistics(const std::string &_link, const Handle &parent, const std::string &kind)
Definition: internal.hpp:302
Definition: try.hpp:34
static Result< T > error(const std::string &message)
Definition: result.hpp:53
Definition: handle.hpp:38
Try< Netlink< struct rtnl_qdisc > > encodeDiscipline(const Netlink< struct rtnl_link > &link, const Discipline< Config > &discipline)
Definition: internal.hpp:84
Result< Netlink< struct rtnl_qdisc > > getQdisc(const Netlink< struct rtnl_link > &link, const Handle &parent, const std::string &kind)
Definition: internal.hpp:165
Try< Nothing > encode(const Netlink< struct rtnl_qdisc > &qdisc, const Config &config)
Definition: result.hpp:40
Definition: hashmap.hpp:38
const char * kind()
Try< std::vector< Netlink< struct rtnl_qdisc > > > getQdiscs(const Netlink< struct rtnl_link > &link)
Definition: internal.hpp:125
Try< bool > exists(const std::string &_link, const Handle &parent, const std::string &kind)
Definition: internal.hpp:192
const T & get() const
Definition: result.hpp:115
static Try error(const E &e)
Definition: try.hpp:42
Definition: none.hpp:27
bool isError() const
Definition: try.hpp:71
Try< bool > create(const std::string &_link, const Discipline< Config > &discipline)
Definition: internal.hpp:218
std::string error(const std::string &msg, uint32_t code)
Option< Handle > handle
Definition: discipline.hpp:44
Config config
Definition: discipline.hpp:47
bool isSome() const
Definition: result.hpp:111
bool isError() const
Definition: result.hpp:113
Definition: discipline.hpp:30
void cleanup(struct rtnl_cls *cls)
Definition: internal.hpp:64
Try< Netlink< struct nl_sock > > socket(int protocol=NETLINK_ROUTE)
Definition: internal.hpp:91
const T & get() const
Definition: try.hpp:73
constexpr const char * name
Definition: shell.hpp:41
constexpr uint32_t get() const
Definition: handle.hpp:66
Result< Config > decode(const Netlink< struct rtnl_qdisc > &qdisc)
Handle parent
Definition: discipline.hpp:43