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_FILTER_INTERNAL_HPP__
18 #define __LINUX_ROUTING_FILTER_INTERNAL_HPP__
19 
20 #include <stdint.h>
21 
22 #include <netlink/cache.h>
23 #include <netlink/errno.h>
24 #include <netlink/object.h>
25 #include <netlink/socket.h>
26 
27 #include <netlink/route/classifier.h>
28 #include <netlink/route/link.h>
29 #include <netlink/route/tc.h>
30 
31 #include <netlink/route/act/mirred.h>
32 
33 #include <netlink/route/cls/basic.h>
34 #include <netlink/route/cls/u32.h>
35 
36 #include <string>
37 #include <vector>
38 
39 #include <process/shared.hpp>
40 
41 #include <stout/error.hpp>
42 #include <stout/foreach.hpp>
43 #include <stout/hashmap.hpp>
44 #include <stout/hashset.hpp>
45 #include <stout/none.hpp>
46 #include <stout/nothing.hpp>
47 #include <stout/option.hpp>
48 #include <stout/result.hpp>
49 #include <stout/try.hpp>
50 
51 #include "linux/routing/handle.hpp"
53 
58 
60 
61 namespace routing {
62 
63 template <>
64 inline void cleanup(struct rtnl_cls* cls)
65 {
66  rtnl_cls_put(cls);
67 }
68 
69 
70 template <>
71 inline void cleanup(struct rtnl_act* act)
72 {
73  rtnl_act_put(act);
74 }
75 
76 namespace filter {
77 namespace internal {
78 
80 // Helpers for {en}decoding.
82 
83 // Forward declaration. Each type of classifier needs to implement
84 // this function to encode itself into the libnl filter (rtnl_cls).
85 template <typename Classifier>
87  const Netlink<struct rtnl_cls>& cls,
88  const Classifier& classifier);
89 
90 
91 // Forward declaration. Each type of classifier needs to implement
92 // this function to decode itself from the libnl filter (rtnl_cls).
93 // Returns None if the libnl filter does not match the type of the
94 // classifier.
95 template <typename Classifier>
97 
98 
99 // Attaches a redirect action to the libnl filter (rtnl_cls).
101  const Netlink<struct rtnl_cls>& cls,
102  const action::Redirect& redirect)
103 {
105  link::internal::get(redirect.link);
106 
107  if (link.isError()) {
108  return Error(link.error());
109  } else if (link.isNone()) {
110  return Error("Link '" + redirect.link + "' is not found");
111  }
112 
113  Netlink<struct rtnl_act> act(rtnl_act_alloc());
114  if (act.get() == nullptr) {
115  return Error("Failed to allocate a libnl action (rtnl_act)");
116  }
117 
118  // Set the kind of the action to 'mirred'. The kind 'mirred' stands
119  // for mirror or redirect actions.
120  int error = rtnl_tc_set_kind(TC_CAST(act.get()), "mirred");
121  if (error != 0) {
122  return Error(
123  "Failed to set the kind of the action: " +
124  std::string(nl_geterror(error)));
125  }
126 
127  rtnl_mirred_set_ifindex(act.get(), rtnl_link_get_ifindex(link->get()));
128  rtnl_mirred_set_action(act.get(), TCA_EGRESS_REDIR);
129  rtnl_mirred_set_policy(act.get(), TC_ACT_STOLEN);
130 
131  const std::string kind = rtnl_tc_get_kind(TC_CAST(cls.get()));
132  if (kind == "basic") {
133  error = rtnl_basic_add_action(cls.get(), act.get());
134  if (error != 0) {
135  return Error(std::string(nl_geterror(error)));
136  }
137  } else if (kind == "u32") {
138  error = rtnl_u32_add_action(cls.get(), act.get());
139  if (error != 0) {
140  return Error(std::string(nl_geterror(error)));
141  }
142 
143  // Automatically set the 'terminal' flag for u32 filters if a
144  // redirect action is attached.
145  error = rtnl_u32_set_cls_terminal(cls.get());
146  if (error != 0) {
147  return Error(
148  "Failed to set the terminal flag: " +
149  std::string(nl_geterror(error)));
150  }
151  } else {
152  return Error("Unsupported classifier kind: " + kind);
153  }
154 
155  return Nothing();
156 }
157 
158 
159 // Attaches a mirror action to the libnl filter (rtnl_cls).
161  const Netlink<struct rtnl_cls>& cls,
162  const action::Mirror& mirror)
163 {
164  const std::string kind = rtnl_tc_get_kind(TC_CAST(cls.get()));
165 
166  foreach (const std::string& _link, mirror.links) {
168  if (link.isError()) {
169  return Error(link.error());
170  } else if (link.isNone()) {
171  return Error("Link '" + _link + "' is not found");
172  }
173 
174  Netlink<struct rtnl_act> act(rtnl_act_alloc());
175  if (act.get() == nullptr) {
176  return Error("Failed to allocate a libnl action (rtnl_act)");
177  }
178 
179  int error = rtnl_tc_set_kind(TC_CAST(act.get()), "mirred");
180  if (error != 0) {
181  return Error(
182  "Failed to set the kind of the action: " +
183  std::string(nl_geterror(error)));
184  }
185 
186  rtnl_mirred_set_ifindex(act.get(), rtnl_link_get_ifindex(link->get()));
187  rtnl_mirred_set_action(act.get(), TCA_EGRESS_MIRROR);
188  rtnl_mirred_set_policy(act.get(), TC_ACT_PIPE);
189 
190  if (kind == "basic") {
191  error = rtnl_basic_add_action(cls.get(), act.get());
192  if (error != 0) {
193  return Error(std::string(nl_geterror(error)));
194  }
195  } else if (kind == "u32") {
196  error = rtnl_u32_add_action(cls.get(), act.get());
197  if (error != 0) {
198  return Error(std::string(nl_geterror(error)));
199  }
200  } else {
201  return Error("Unsupported classifier kind: " + kind);
202  }
203  }
204 
205  // Automatically set the 'terminal' flag for u32 filters if a mirror
206  // action is attached.
207  if (kind == "u32") {
208  int error = rtnl_u32_set_cls_terminal(cls.get());
209  if (error != 0) {
210  return Error(
211  "Failed to set the terminal flag: " +
212  std::string(nl_geterror(error)));
213  }
214  }
215 
216  return Nothing();
217 }
218 
219 
220 // Attaches a terminal action to the libnl filter (rtnl_cls). It will
221 // stop the packet from being passed to the next filter if a match is
222 // found. This is only applied to u32 filters (which can match any
223 // 32-bit value in a packet). This function will return error if the
224 // user tries to attach a terminal action to a non-u32 filter.
226  const Netlink<struct rtnl_cls>& cls,
227  const action::Terminal& terminal)
228 {
229  const std::string kind = rtnl_tc_get_kind(TC_CAST(cls.get()));
230  if (kind != "u32") {
231  return Error("Cannot attach terminal action to a non-u32 filter.");
232  }
233 
234  int error = rtnl_u32_set_cls_terminal(cls.get());
235  if (error != 0) {
236  return Error(
237  "Failed to set the terminal flag: " +
238  std::string(nl_geterror(error)));
239  }
240 
241  return Nothing();
242 }
243 
244 
245 // Attaches an action to the libnl filter (rtnl_cls). This function
246 // essentially delegates the call to the corresponding attach function
247 // depending on the type of the action.
249  const Netlink<struct rtnl_cls>& cls,
250  const process::Shared<action::Action>& action)
251 {
252  const action::Redirect* redirect =
253  dynamic_cast<const action::Redirect*>(action.get());
254  if (redirect != nullptr) {
255  return attach(cls, *redirect);
256  }
257 
258  const action::Mirror* mirror =
259  dynamic_cast<const action::Mirror*>(action.get());
260  if (mirror != nullptr) {
261  return attach(cls, *mirror);
262  }
263 
264  const action::Terminal* terminal =
265  dynamic_cast<const action::Terminal*>(action.get());
266  if (terminal != nullptr) {
267  return attach(cls, *terminal);
268  }
269 
270  return Error("Unsupported action type");
271 }
272 
273 
274 // Generates the handle for the given filter on the link. Returns none
275 // if we decide to let the kernel choose the handle.
276 template <typename Classifier>
278  const Netlink<struct rtnl_link>& link,
279  const Filter<Classifier>& filter)
280 {
281  // If the user does not specify a priority, we have no choice but
282  // let the kernel choose the handle because we do not know the
283  // 'htid' that is associated with that priority.
284  if (filter.priority.isNone()) {
285  return None();
286  }
287 
288  // Scan all the filters attached to the given parent on the link.
290  if (socket.isError()) {
291  return Error(socket.error());
292  }
293 
294  // Dump all the libnl filters (i.e., rtnl_cls) attached to the given
295  // parent on the link.
296  struct nl_cache* c = nullptr;
297  int error = rtnl_cls_alloc_cache(
298  socket->get(),
299  rtnl_link_get_ifindex(link.get()),
300  filter.parent.get(),
301  &c);
302 
303  if (error != 0) {
304  return Error(
305  "Failed to get filter info from kernel: " +
306  std::string(nl_geterror(error)));
307  }
308 
309  Netlink<struct nl_cache> cache(c);
310 
311  // A map from priority to the corresponding 'htid'.
313 
314  // A map from 'htid' to a set of already used nodes.
316 
317  for (struct nl_object* o = nl_cache_get_first(cache.get());
318  o != nullptr; o = nl_cache_get_next(o)) {
319  struct rtnl_cls* cls = (struct rtnl_cls*) o;
320 
321  // Only look at u32 filters. For other type of filters, their
322  // handles are generated by the kernel correctly.
323  if (rtnl_tc_get_kind(TC_CAST(cls)) == std::string("u32")) {
324  U32Handle handle(rtnl_tc_get_handle(TC_CAST(cls)));
325 
326  htids[rtnl_cls_get_prio(cls)] = handle.htid();
327  nodes[handle.htid()].insert(handle.node());
328  }
329  }
330 
331  // If this filter has a new priority, we need to let the kernel
332  // decide the handle because we don't know which 'htid' this
333  // priority will be associated with.
334  if (!htids.contains(filter.priority->get())) {
335  return None();
336  }
337 
338  // NOTE: By default, kernel will choose to use divisor 1, which
339  // means all filters will be in hash bucket 0. Also, kernel assigns
340  // node id starting from 0x800 by default. Here, we keep the same
341  // semantics as kernel.
342  uint32_t htid = htids[filter.priority->get()];
343  for (uint32_t node = 0x800; node <= 0xfff; node++) {
344  if (!nodes[htid].contains(node)) {
345  return U32Handle(htid, 0x0, node);
346  }
347  }
348 
349  return Error("No available handle exists");
350 }
351 
352 
353 // Encodes a filter (in our representation) to a libnl filter
354 // (rtnl_cls). We use template here so that it works for any type of
355 // classifier.
356 template <typename Classifier>
358  const Netlink<struct rtnl_link>& link,
359  const Filter<Classifier>& filter)
360 {
361  struct rtnl_cls* c = rtnl_cls_alloc();
362  if (c == nullptr) {
363  return Error("Failed to allocate a libnl filter (rtnl_cls)");
364  }
365 
367 
368  rtnl_tc_set_link(TC_CAST(cls.get()), link.get());
369  rtnl_tc_set_parent(TC_CAST(cls.get()), filter.parent.get());
370 
371  // Encode the priority.
372  if (filter.priority.isSome()) {
373  rtnl_cls_set_prio(cls.get(), filter.priority->get());
374  }
375 
376  // Encode the classifier using the classifier specific function.
377  Try<Nothing> encoding = encode(cls, filter.classifier);
378  if (encoding.isError()) {
379  return Error("Failed to encode the classifier " + encoding.error());
380  }
381 
382  // Attach actions to the libnl filter.
383  foreach (const process::Shared<action::Action>& action, filter.actions) {
384  Try<Nothing> attaching = attach(cls, action);
385  if (attaching.isError()) {
386  return Error("Failed to attach an action " + attaching.error());
387  }
388  }
389 
390  // Encode the handle.
391  if (filter.handle.isSome()) {
392  rtnl_tc_set_handle(TC_CAST(cls.get()), filter.handle->get());
393  } else {
394  // NOTE: This is a workaround for MESOS-1617. Normally, if the
395  // user does not specify the handle for a filter, the kernel will
396  // generate one automatically. However, for u32 filters, the
397  // existing kernel is buggy in the sense that it will generate a
398  // handle that is already used by some other u32 filter (see the
399  // ticket for details). To address that, we explicitly set the
400  // handle of the filter by picking an unused handle.
401  // TODO(jieyu): Revisit this once the kernel bug is fixed.
402  if (rtnl_tc_get_kind(TC_CAST(cls.get())) == std::string("u32")) {
403  Result<U32Handle> handle = generateU32Handle(link, filter);
404  if (handle.isError()) {
405  return Error("Failed to find an unused u32 handle: " + handle.error());
406  }
407 
408  // If 'handle' is none, let the kernel choose the handle.
409  if (handle.isSome()) {
410  rtnl_tc_set_handle(TC_CAST(cls.get()), handle->get());
411  }
412  }
413  }
414 
415  // Set the classid if needed.
416  if (filter.classid.isSome()) {
417  if (rtnl_tc_get_kind(TC_CAST(cls.get())) == std::string("u32")) {
418  rtnl_u32_set_classid(cls.get(), filter.classid->get());
419  } else if (rtnl_tc_get_kind(TC_CAST(cls.get())) == std::string("basic")) {
420  rtnl_basic_set_target(cls.get(), filter.classid->get());
421  }
422  }
423 
424  return cls;
425 }
426 
427 
428 // Decodes a libnl filter (rtnl_cls) to our filter representation.
429 // Returns None if the libnl filter does not match the specified
430 // classifier type. We use template here so that it works for any type
431 // of classifier.
432 template <typename Classifier>
434 {
435  // If the handle of the libnl filer is 0, it means that it is an
436  // internal filter, therefore is definitely not created by us.
437  if (rtnl_tc_get_handle(TC_CAST(cls.get())) == 0) {
438  return None();
439  }
440 
441  // Decode the parent.
442  Handle parent(rtnl_tc_get_parent(TC_CAST(cls.get())));
443 
444  // Decode the priority. If the priority is not specified by the
445  // user, kernel will assign a priority to the filter. So we should
446  // always have a valid priority here.
447  Priority priority(rtnl_cls_get_prio(cls.get()));
448 
449  // Decode the handle. If the handle is not specified by the user,
450  // kernel will assign a handle to the filter. So we should always
451  // have a valid handle here.
452  Handle handle(rtnl_tc_get_handle(TC_CAST(cls.get())));
453 
454  // Decode the classifier using a classifier specific function.
455  Result<Classifier> classifier = decode<Classifier>(cls);
456  if (classifier.isError()) {
457  return Error("Failed to decode the classifier: " + classifier.error());
458  } else if (classifier.isNone()) {
459  return None();
460  }
461 
463  if (rtnl_tc_get_kind(TC_CAST(cls.get())) == std::string("u32")) {
464  uint32_t _classid;
465  if (rtnl_u32_get_classid(cls.get(), &_classid) == 0) {
466  classid = _classid;
467  }
468  } else if (rtnl_tc_get_kind(TC_CAST(cls.get())) == std::string("basic")) {
469  classid = rtnl_basic_get_target(cls.get());
470  }
471 
472  // TODO(jieyu): Decode all the actions attached to the filter.
473  // Currently, libnl does not support that (but will support that in
474  // the future).
475  return Filter<Classifier>(parent,
476  classifier.get(),
477  priority,
478  handle,
479  classid);
480 }
481 
483 // Helpers for internal APIs.
485 
486 // Returns all the libnl filters (rtnl_cls) attached to the given
487 // parent on the link.
489  const Netlink<struct rtnl_link>& link,
490  const Handle& parent)
491 {
493  if (socket.isError()) {
494  return Error(socket.error());
495  }
496 
497  // Dump all the libnl filters (i.e., rtnl_cls) attached to the given
498  // parent on the link.
499  struct nl_cache* c = nullptr;
500  int error = rtnl_cls_alloc_cache(
501  socket->get(),
502  rtnl_link_get_ifindex(link.get()),
503  parent.get(),
504  &c);
505 
506  if (error != 0) {
507  return Error(
508  "Failed to get filter info from kernel: " +
509  std::string(nl_geterror(error)));
510  }
511 
512  Netlink<struct nl_cache> cache(c);
513 
514  std::vector<Netlink<struct rtnl_cls>> results;
515 
516  for (struct nl_object* o = nl_cache_get_first(cache.get());
517  o != nullptr; o = nl_cache_get_next(o)) {
518  // NOTE: We increment the reference counter here because 'cache'
519  // will be freed when this function finishes and we want this
520  // object's life to be longer than this function.
521  nl_object_get(o);
522 
523  results.push_back(Netlink<struct rtnl_cls>((struct rtnl_cls*) o));
524  }
525 
526  return results;
527 }
528 
529 
530 // Returns the libnl filter (rtnl_cls) attached to the given parent
531 // that matches the specified classifier on the link. Returns None if
532 // no match has been found. We use template here so that it works for
533 // any type of classifier.
534 template <typename Classifier>
536  const Netlink<struct rtnl_link>& link,
537  const Handle& parent,
538  const Classifier& classifier)
539 {
540  Try<std::vector<Netlink<struct rtnl_cls>>> clses = getClses(link, parent);
541  if (clses.isError()) {
542  return Error(clses.error());
543  }
544 
545  foreach (const Netlink<struct rtnl_cls>& cls, clses.get()) {
546  // The decode function will return None if 'cls' does not match
547  // the classifier type. In that case, we just move on to the next
548  // libnl filter.
549  Result<Filter<Classifier>> filter = decodeFilter<Classifier>(cls);
550  if (filter.isError()) {
551  return Error("Failed to decode: " + filter.error());
552  } else if (filter.isSome() && filter->classifier == classifier) {
553  return cls;
554  }
555  }
556 
557  return None();
558 }
559 
561 // Internal filter APIs.
563 
564 // Returns true if there exists a filter attached to the given parent
565 // that matches the specified classifier on the link. We use template
566 // here so that it works for any type of classifier.
567 template <typename Classifier>
569  const std::string& _link,
570  const Handle& parent,
571  const Classifier& classifier)
572 {
574  if (link.isError()) {
575  return Error(link.error());
576  } else if (link.isNone()) {
577  return false;
578  }
579 
581  getCls(link.get(), parent, classifier);
582 
583  if (cls.isError()) {
584  return Error(cls.error());
585  }
586  return cls.isSome();
587 }
588 
589 
590 // Creates a new filter on the link. Returns false if a filter
591 // attached to the same parent with the same classifier already
592 // exists. We use template here so that it works for any type of
593 // classifier.
594 template <typename Classifier>
595 Try<bool> create(const std::string& _link, const Filter<Classifier>& filter)
596 {
597  // TODO(jieyu): Currently, we're not able to guarantee the atomicity
598  // between the existence check and the following add operation. So
599  // if two threads try to create the same filter, both of them may
600  // succeed and end up with two filters in the kernel.
601  Try<bool> _exists = exists(_link, filter.parent, filter.classifier);
602  if (_exists.isError()) {
603  return Error("Check filter existence failed: " + _exists.error());
604  } else if (_exists.get()) {
605  // The filter already exists.
606  return false;
607  }
608 
610  if (link.isError()) {
611  return Error(link.error());
612  } else if (link.isNone()) {
613  return Error("Link '" + _link + "' is not found");
614  }
615 
617  if (cls.isError()) {
618  return Error("Failed to encode the filter: " + cls.error());
619  }
620 
622  if (socket.isError()) {
623  return Error(socket.error());
624  }
625 
626  int error = rtnl_cls_add(
627  socket->get(),
628  cls->get(),
629  NLM_F_CREATE | NLM_F_EXCL);
630 
631  if (error != 0) {
632  if (error == -NLE_EXIST) {
633  return false;
634  } else {
635  return Error(std::string(nl_geterror(error)));
636  }
637  }
638 
639  return true;
640 }
641 
642 
643 // Removes the filter attached to the given parent that matches the
644 // specified classifier from the link. Returns false if such a filter
645 // is not found. We use template here so that it works for any type of
646 // classifier.
647 template <typename Classifier>
648 Try<bool> remove(
649  const std::string& _link,
650  const Handle& parent,
651  const Classifier& classifier)
652 {
654  if (link.isError()) {
655  return Error(link.error());
656  } else if (link.isNone()) {
657  return false;
658  }
659 
661  getCls(link.get(), parent, classifier);
662 
663  if (cls.isError()) {
664  return Error(cls.error());
665  } else if (cls.isNone()) {
666  return false;
667  }
668 
670  if (socket.isError()) {
671  return Error(socket.error());
672  }
673 
674  int error = rtnl_cls_delete(socket->get(), cls.get().get(), 0);
675  if (error != 0) {
676  // TODO(jieyu): Interpret the error code and return false if it
677  // indicates that the filter is not found.
678  return Error(std::string(nl_geterror(error)));
679  }
680 
681  return true;
682 }
683 
684 
685 // Updates the action of the filter attached to the given parent that
686 // matches the specified classifier on the link. Returns false if such
687 // a filter is not found. We use template here so that it works for
688 // any type of classifier.
689 template <typename Classifier>
690 Try<bool> update(const std::string& _link, const Filter<Classifier>& filter)
691 {
693  if (link.isError()) {
694  return Error(link.error());
695  } else if (link.isNone()) {
696  return false;
697  }
698 
699  // Get the old libnl classifier (to-be-updated) from kernel.
701  getCls(link.get(), filter.parent, filter.classifier);
702 
703  if (oldCls.isError()) {
704  return Error(oldCls.error());
705  } else if (oldCls.isNone()) {
706  return false;
707  }
708 
709  // The kernel does not allow us to update the priority. So if the
710  // user specifies a priority, we will check to make sure they match.
711  if (filter.priority.isSome() &&
712  filter.priority->get() != rtnl_cls_get_prio(oldCls.get().get())) {
713  return Error(
714  "The priorities do not match. The old priority is " +
715  stringify(rtnl_cls_get_prio(oldCls->get())) +
716  " and the new priority is " +
717  stringify(filter.priority->get()));
718  }
719 
720  // The kernel does not allow us to update the handle. So if the user
721  // specifies a handle, we will check to make sure they match.
722  if (filter.handle.isSome() &&
723  filter.handle->get() !=
724  rtnl_tc_get_handle(TC_CAST(oldCls->get()))) {
725  return Error(
726  "The handles do not match. The old handle is " +
727  stringify(rtnl_tc_get_handle(TC_CAST(oldCls->get()))) +
728  " and the new handle is " +
729  stringify(filter.handle->get()));
730  }
731 
733  if (newCls.isError()) {
734  return Error("Failed to encode the new filter: " + newCls.error());
735  }
736 
737  // Set the handle of the new filter to match that of the old one.
738  rtnl_tc_set_handle(
739  TC_CAST(newCls->get()),
740  rtnl_tc_get_handle(TC_CAST(oldCls->get())));
741 
742  // Set the priority of the new filter to match that of the old one.
743  rtnl_cls_set_prio(
744  newCls->get(),
745  rtnl_cls_get_prio(oldCls->get()));
746 
748  if (socket.isError()) {
749  return Error(socket.error());
750  }
751 
752  int error = rtnl_cls_change(socket->get(), newCls.get().get(), 0);
753  if (error != 0) {
754  if (error == -NLE_OBJ_NOTFOUND) {
755  return false;
756  } else {
757  return Error(std::string(nl_geterror(error)));
758  }
759  }
760 
761  return true;
762 }
763 
764 
765 // Returns all the filters attached to the given parent on the link.
766 // Returns None if the link or the parent is not found. We use
767 // template here so that it works for any type of classifier.
768 template <typename Classifier>
770  const std::string& _link,
771  const Handle& parent)
772 {
774  if (link.isError()) {
775  return Error(link.error());
776  } else if (link.isNone()) {
777  return None();
778  }
779 
781  getClses(link.get(), parent);
782 
783  if (clses.isError()) {
784  return Error(clses.error());
785  }
786 
787  std::vector<Filter<Classifier>> results;
788 
789  foreach (const Netlink<struct rtnl_cls>& cls, clses.get()) {
790  // The decode function will return None if 'cls' does not match
791  // the classifier type. In that case, we just move on to the next
792  // libnl filter.
793  Result<Filter<Classifier>> filter = decodeFilter<Classifier>(cls);
794  if (filter.isError()) {
795  return Error(filter.error());
796  } else if (filter.isSome()) {
797  results.push_back(filter.get());
798  }
799  }
800 
801  return results;
802 }
803 
804 
805 // Returns all the classifiers attached to the given parent on the
806 // link. Returns None if the link or the parent is not found. We use
807 // template here so that it works for any type of classifier.
808 template <typename Classifier>
810  const std::string& link,
811  const Handle& parent)
812 {
814  filters<Classifier>(link, parent);
815 
816  if (_filters.isError()) {
817  return Error(_filters.error());
818  } else if (_filters.isNone()) {
819  return None();
820  }
821 
822  std::vector<Classifier> results;
823 
824  foreach (const Filter<Classifier>& filter, _filters.get()) {
825  results.push_back(filter.classifier);
826  }
827 
828  return results;
829 }
830 
831 } // namespace internal {
832 } // namespace filter {
833 } // namespace routing {
834 
835 #endif // __LINUX_ROUTING_FILTER_INTERNAL_HPP__
Result< std::vector< Classifier > > classifiers(const std::string &link, const Handle &parent)
Definition: internal.hpp:809
bool isNone() const
Definition: result.hpp:112
Definition: nothing.hpp:16
Definition: errorbase.hpp:36
Definition: option.hpp:28
Result< U32Handle > generateU32Handle(const Netlink< struct rtnl_link > &link, const Filter< Classifier > &filter)
Definition: internal.hpp:277
Result< Filter< Classifier > > decodeFilter(const Netlink< struct rtnl_cls > &cls)
Definition: internal.hpp:433
Classifier classifier
Definition: filter.hpp:90
T & get()&
Definition: try.hpp:73
Result< Classifier > decode(const Netlink< struct rtnl_cls > &cls)
Definition: check.hpp:33
Option< Handle > classid
Definition: filter.hpp:111
static Result< T > error(const std::string &message)
Definition: result.hpp:53
Result< Netlink< struct rtnl_cls > > getCls(const Netlink< struct rtnl_link > &link, const Handle &parent, const Classifier &classifier)
Definition: internal.hpp:535
Definition: handle.hpp:38
Definition: priority.hpp:39
std::set< std::string > links
Definition: action.hpp:60
Future< Nothing > redirect(int_fd from, Option< int_fd > to, size_t chunk=4096, const std::vector< lambda::function< void(const std::string &)>> &hooks={})
Redirect output from the &#39;from&#39; file descriptor to the &#39;to&#39; file descriptor (or /dev/null if &#39;to&#39; is ...
Definition: check.hpp:30
Definition: action.hpp:66
Definition: action.hpp:41
Definition: hashmap.hpp:38
const char * kind()
Try< Nothing > encode(const Netlink< struct rtnl_cls > &cls, const Classifier &classifier)
bool contains(const std::string &s, const std::string &substr)
Definition: strings.hpp:423
Definition: filter.hpp:46
Option< Handle > handle
Definition: filter.hpp:96
Definition: owned.hpp:26
Result< std::vector< Filter< Classifier > > > filters(const std::string &_link, const Handle &parent)
Definition: internal.hpp:769
Option< Priority > priority
Definition: filter.hpp:93
Try< bool > update(const std::string &_link, const Filter< Classifier > &filter)
Definition: internal.hpp:690
const T & get() const
Definition: result.hpp:115
uint32_t node() const
Definition: handle.hpp:56
Try< Netlink< struct rtnl_cls > > encodeFilter(const Netlink< struct rtnl_link > &link, const Filter< Classifier > &filter)
Definition: internal.hpp:357
Try< std::vector< Netlink< struct rtnl_cls > > > getClses(const Netlink< struct rtnl_link > &link, const Handle &parent)
Definition: internal.hpp:488
static Try error(const E &e)
Definition: try.hpp:42
Definition: handle.hpp:38
Try< Nothing > attach(const Netlink< struct rtnl_cls > &cls, const action::Redirect &redirect)
Definition: internal.hpp:100
Definition: none.hpp:27
Definition: attributes.hpp:24
bool isError() const
Definition: try.hpp:71
std::vector< process::Shared< action::Action > > actions
Definition: filter.hpp:115
std::string error(const std::string &msg, uint32_t code)
Definition: diagnosis.hpp:30
Try< uint32_t > classid(const std::string &hierarchy, const std::string &cgroup)
bool isSome() const
Definition: result.hpp:111
bool isError() const
Definition: result.hpp:113
uint32_t htid() const
Definition: handle.hpp:54
void cleanup(struct rtnl_cls *cls)
Definition: internal.hpp:64
Definition: action.hpp:54
Try< Netlink< struct nl_sock > > socket(int protocol=NETLINK_ROUTE)
Definition: internal.hpp:91
std::string stringify(int flags)
std::string link
Definition: action.hpp:47
const T * get() const
Definition: shared.hpp:118
bool contains(const Key &key) const
Definition: hashmap.hpp:86
Handle parent
Definition: filter.hpp:87
Try< bool > exists(const std::string &_link, const Handle &parent, const Classifier &classifier)
Definition: internal.hpp:568
constexpr uint32_t get() const
Definition: handle.hpp:66
Try< bool > create(const std::string &_link, const Filter< Classifier > &filter)
Definition: internal.hpp:595
void filter(Filter *filter)