17 #ifndef __LINUX_ROUTING_FILTER_INTERNAL_HPP__
18 #define __LINUX_ROUTING_FILTER_INTERNAL_HPP__
22 #include <netlink/cache.h>
23 #include <netlink/errno.h>
24 #include <netlink/object.h>
25 #include <netlink/socket.h>
27 #include <netlink/route/classifier.h>
28 #include <netlink/route/link.h>
29 #include <netlink/route/tc.h>
31 #include <netlink/route/act/mirred.h>
33 #include <netlink/route/cls/basic.h>
34 #include <netlink/route/cls/u32.h>
78 template <
typename Classifier>
81 const Classifier& classifier);
88 template <
typename Classifier>
102 }
else if (link.
isNone()) {
103 return Error(
"Link '" + redirect.
link +
"' is not found");
109 struct rtnl_act* act = rtnl_act_alloc();
110 if (act ==
nullptr) {
111 return Error(
"Failed to allocate a libnl action (rtnl_act)");
116 int error = rtnl_tc_set_kind(TC_CAST(act),
"mirred");
120 "Failed to set the kind of the action: " +
121 std::string(nl_geterror(error)));
124 rtnl_mirred_set_ifindex(act, rtnl_link_get_ifindex(link.
get().get()));
125 rtnl_mirred_set_action(act, TCA_EGRESS_REDIR);
126 rtnl_mirred_set_policy(act, TC_ACT_STOLEN);
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);
133 return Error(std::string(nl_geterror(error)));
135 }
else if (kind ==
"u32") {
136 error = rtnl_u32_add_action(cls.
get(), act);
139 return Error(std::string(nl_geterror(error)));
144 error = rtnl_u32_set_cls_terminal(cls.
get());
147 "Failed to set the terminal flag: " +
148 std::string(nl_geterror(error)));
152 return Error(
"Unsupported classifier kind: " + kind);
164 const std::string
kind = rtnl_tc_get_kind(TC_CAST(cls.
get()));
166 foreach (
const std::string& _link, mirror.
links) {
170 }
else if (link.
isNone()) {
171 return Error(
"Link '" + _link +
"' is not found");
177 struct rtnl_act* act = rtnl_act_alloc();
178 if (act ==
nullptr) {
179 return Error(
"Failed to allocate a libnl action (rtnl_act)");
182 int error = rtnl_tc_set_kind(TC_CAST(act),
"mirred");
186 "Failed to set the kind of the action: " +
187 std::string(nl_geterror(error)));
190 rtnl_mirred_set_ifindex(act, rtnl_link_get_ifindex(link.
get().get()));
191 rtnl_mirred_set_action(act, TCA_EGRESS_MIRROR);
192 rtnl_mirred_set_policy(act, TC_ACT_PIPE);
194 if (kind ==
"basic") {
195 error = rtnl_basic_add_action(cls.
get(), act);
198 return Error(std::string(nl_geterror(error)));
200 }
else if (kind ==
"u32") {
201 error = rtnl_u32_add_action(cls.
get(), act);
204 return Error(std::string(nl_geterror(error)));
208 return Error(
"Unsupported classifier kind: " + kind);
215 int error = rtnl_u32_set_cls_terminal(cls.
get());
218 "Failed to set the terminal flag: " +
219 std::string(nl_geterror(error)));
236 const std::string
kind = rtnl_tc_get_kind(TC_CAST(cls.
get()));
238 return Error(
"Cannot attach terminal action to a non-u32 filter.");
241 int error = rtnl_u32_set_cls_terminal(cls.
get());
244 "Failed to set the terminal flag: " +
245 std::string(nl_geterror(error)));
261 if (redirect !=
nullptr) {
262 return attach(cls, *redirect);
267 if (mirror !=
nullptr) {
268 return attach(cls, *mirror);
273 if (terminal !=
nullptr) {
274 return attach(cls, *terminal);
277 return Error(
"Unsupported action type");
283 template <
typename Classifier>
303 struct nl_cache* c =
nullptr;
304 int error = rtnl_cls_alloc_cache(
306 rtnl_link_get_ifindex(link.
get()),
312 "Failed to get filter info from kernel: " +
313 std::string(nl_geterror(error)));
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;
330 if (rtnl_tc_get_kind(TC_CAST(cls)) == std::string(
"u32")) {
331 U32Handle handle(rtnl_tc_get_handle(TC_CAST(cls)));
333 htids[rtnl_cls_get_prio(cls)] = handle.
htid();
334 nodes[handle.
htid()].insert(handle.
node());
349 uint32_t htid = htids[filter.
priority.get().get()];
350 for (uint32_t node = 0x800; node <= 0xfff; node++) {
356 return Error(
"No available handle exists");
363 template <
typename Classifier>
368 struct rtnl_cls* c = rtnl_cls_alloc();
370 return Error(
"Failed to allocate a libnl filter (rtnl_cls)");
375 rtnl_tc_set_link(TC_CAST(cls.
get()), link.
get());
376 rtnl_tc_set_parent(TC_CAST(cls.
get()), filter.
parent.get());
380 rtnl_cls_set_prio(cls.
get(), filter.
priority.get().get());
386 return Error(
"Failed to encode the classifier " + encoding.
error());
393 return Error(
"Failed to attach an action " + attaching.
error());
398 if (filter.
handle.isSome()) {
399 rtnl_tc_set_handle(TC_CAST(cls.
get()), filter.
handle.get().get());
409 if (rtnl_tc_get_kind(TC_CAST(cls.
get())) == std::string(
"u32")) {
412 return Error(
"Failed to find an unused u32 handle: " + handle.
error());
417 rtnl_tc_set_handle(TC_CAST(cls.
get()), handle.
get().get());
424 if (rtnl_tc_get_kind(TC_CAST(cls.
get())) == std::string(
"u32")) {
425 rtnl_u32_set_classid(cls.
get(), filter.
classid.get().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().get());
439 template <
typename Classifier>
444 if (rtnl_tc_get_handle(TC_CAST(cls.
get())) == 0) {
449 Handle parent(rtnl_tc_get_parent(TC_CAST(cls.
get())));
459 Handle handle(rtnl_tc_get_handle(TC_CAST(cls.
get())));
463 if (classifier.isError()) {
464 return Error(
"Failed to decode the classifier: " + classifier.error());
465 }
else if (classifier.isNone()) {
470 if (rtnl_tc_get_kind(TC_CAST(cls.
get())) == std::string(
"u32")) {
472 if (rtnl_u32_get_classid(cls.
get(), &_classid) == 0) {
475 }
else if (rtnl_tc_get_kind(TC_CAST(cls.
get())) == std::string(
"basic")) {
476 classid = rtnl_basic_get_target(cls.
get());
506 struct nl_cache* c =
nullptr;
507 int error = rtnl_cls_alloc_cache(
509 rtnl_link_get_ifindex(link.
get()),
515 "Failed to get filter info from kernel: " +
516 std::string(nl_geterror(error)));
521 std::vector<Netlink<struct rtnl_cls>> results;
523 for (
struct nl_object* o = nl_cache_get_first(cache.
get());
524 o !=
nullptr; o = nl_cache_get_next(o)) {
541 template <
typename Classifier>
545 const Classifier& classifier)
558 return Error(
"Failed to decode: " + filter.
error());
559 }
else if (filter.
isSome() && filter.
get().classifier == classifier) {
574 template <
typename Classifier>
576 const std::string& _link,
578 const Classifier& classifier)
583 }
else if (link.
isNone()) {
601 template <
typename Classifier>
610 return Error(
"Check filter existence failed: " + _exists.
error());
611 }
else if (_exists.
get()) {
619 }
else if (link.
isNone()) {
620 return Error(
"Link '" + _link +
"' is not found");
625 return Error(
"Failed to encode the filter: " + cls.
error());
633 int error = rtnl_cls_add(
636 NLM_F_CREATE | NLM_F_EXCL);
639 if (error == -NLE_EXIST) {
642 return Error(std::string(nl_geterror(error)));
654 template <
typename Classifier>
656 const std::string& _link,
658 const Classifier& classifier)
663 }
else if (link.
isNone()) {
672 }
else if (cls.
isNone()) {
681 int error = rtnl_cls_delete(socket.
get().get(), cls.
get().get(), 0);
685 return Error(std::string(nl_geterror(error)));
696 template <
typename Classifier>
702 }
else if (link.
isNone()) {
712 }
else if (oldCls.
isNone()) {
719 filter.
priority.get().get() != rtnl_cls_get_prio(oldCls.
get().get())) {
721 "The priorities do not match. The old priority is " +
723 " and the new priority is " +
729 if (filter.
handle.isSome() &&
730 filter.
handle.get().get() !=
731 rtnl_tc_get_handle(TC_CAST(oldCls.
get().get()))) {
733 "The handles do not match. The old handle is " +
734 stringify(rtnl_tc_get_handle(TC_CAST(oldCls.
get().get()))) +
735 " and the new handle is " +
741 return Error(
"Failed to encode the new filter: " + newCls.
error());
746 TC_CAST(newCls.
get().get()),
747 rtnl_tc_get_handle(TC_CAST(oldCls.
get().get())));
752 rtnl_cls_get_prio(oldCls.
get().get()));
759 int error = rtnl_cls_change(socket.
get().get(), newCls.
get().get(), 0);
761 if (error == -NLE_OBJ_NOTFOUND) {
764 return Error(std::string(nl_geterror(error)));
775 template <
typename Classifier>
777 const std::string& _link,
783 }
else if (link.
isNone()) {
794 std::vector<Filter<Classifier>> results;
803 }
else if (filter.
isSome()) {
804 results.push_back(filter.
get());
815 template <
typename Classifier>
817 const std::string& link,
821 filters<Classifier>(link, parent);
825 }
else if (_filters.
isNone()) {
829 std::vector<Classifier> results;
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:35
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
Result< Classifier > decode(const Netlink< struct rtnl_cls > &cls)
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
Result< Netlink< struct rtnl_link > > get(const std::string &link)
Definition: internal.hpp:57
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 'from' file descriptor to the 'to' file descriptor (or /dev/null if 'to' is ...
Definition: result.hpp:40
Definition: action.hpp:66
Definition: action.hpp:41
Definition: hashmap.hpp:38
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:406
Definition: filter.hpp:46
Option< Handle > handle
Definition: filter.hpp:96
Result< std::vector< Filter< Classifier > > > filters(const std::string &_link, const Handle &parent)
Definition: internal.hpp:776
Option< Priority > priority
Definition: filter.hpp:93
T * get() const
Definition: internal.hpp:65
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
Definition: internal.hpp:60
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
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)
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:116
bool contains(const Key &key) const
Definition: hashmap.hpp:86
Handle parent
Definition: filter.hpp:87
const T & get() const
Definition: try.hpp:73
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)