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