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> 85 template <
typename Classifier>
88 const Classifier& classifier);
95 template <
typename Classifier>
109 }
else if (link.
isNone()) {
110 return Error(
"Link '" + redirect.
link +
"' is not found");
114 if (act.
get() ==
nullptr) {
115 return Error(
"Failed to allocate a libnl action (rtnl_act)");
120 int error = rtnl_tc_set_kind(TC_CAST(act.
get()),
"mirred");
123 "Failed to set the kind of the action: " +
124 std::string(nl_geterror(error)));
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);
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());
135 return Error(std::string(nl_geterror(error)));
137 }
else if (kind ==
"u32") {
138 error = rtnl_u32_add_action(cls.
get(), act.
get());
140 return Error(std::string(nl_geterror(error)));
145 error = rtnl_u32_set_cls_terminal(cls.
get());
148 "Failed to set the terminal flag: " +
149 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");
175 if (act.
get() ==
nullptr) {
176 return Error(
"Failed to allocate a libnl action (rtnl_act)");
179 int error = rtnl_tc_set_kind(TC_CAST(act.
get()),
"mirred");
182 "Failed to set the kind of the action: " +
183 std::string(nl_geterror(error)));
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);
190 if (kind ==
"basic") {
191 error = rtnl_basic_add_action(cls.
get(), act.
get());
193 return Error(std::string(nl_geterror(error)));
195 }
else if (kind ==
"u32") {
196 error = rtnl_u32_add_action(cls.
get(), act.
get());
198 return Error(std::string(nl_geterror(error)));
201 return Error(
"Unsupported classifier kind: " + kind);
208 int error = rtnl_u32_set_cls_terminal(cls.
get());
211 "Failed to set the terminal flag: " +
212 std::string(nl_geterror(error)));
229 const std::string
kind = rtnl_tc_get_kind(TC_CAST(cls.
get()));
231 return Error(
"Cannot attach terminal action to a non-u32 filter.");
234 int error = rtnl_u32_set_cls_terminal(cls.
get());
237 "Failed to set the terminal flag: " +
238 std::string(nl_geterror(error)));
254 if (redirect !=
nullptr) {
255 return attach(cls, *redirect);
260 if (mirror !=
nullptr) {
261 return attach(cls, *mirror);
266 if (terminal !=
nullptr) {
267 return attach(cls, *terminal);
270 return Error(
"Unsupported action type");
276 template <
typename Classifier>
296 struct nl_cache* c =
nullptr;
297 int error = rtnl_cls_alloc_cache(
299 rtnl_link_get_ifindex(link.
get()),
305 "Failed to get filter info from kernel: " +
306 std::string(nl_geterror(error)));
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;
323 if (rtnl_tc_get_kind(TC_CAST(cls)) == std::string(
"u32")) {
324 U32Handle handle(rtnl_tc_get_handle(TC_CAST(cls)));
326 htids[rtnl_cls_get_prio(cls)] = handle.
htid();
327 nodes[handle.
htid()].insert(handle.
node());
342 uint32_t htid = htids[filter.
priority->get()];
343 for (uint32_t node = 0x800; node <= 0xfff; node++) {
349 return Error(
"No available handle exists");
356 template <
typename Classifier>
361 struct rtnl_cls* c = rtnl_cls_alloc();
363 return Error(
"Failed to allocate a libnl filter (rtnl_cls)");
368 rtnl_tc_set_link(TC_CAST(cls.
get()), link.
get());
369 rtnl_tc_set_parent(TC_CAST(cls.
get()), filter.
parent.get());
373 rtnl_cls_set_prio(cls.
get(), filter.
priority->get());
378 if (encoding.isError()) {
379 return Error(
"Failed to encode the classifier " + encoding.error());
386 return Error(
"Failed to attach an action " + attaching.
error());
391 if (filter.
handle.isSome()) {
392 rtnl_tc_set_handle(TC_CAST(cls.
get()), filter.
handle->get());
402 if (rtnl_tc_get_kind(TC_CAST(cls.
get())) == std::string(
"u32")) {
405 return Error(
"Failed to find an unused u32 handle: " + handle.
error());
410 rtnl_tc_set_handle(TC_CAST(cls.
get()), handle->
get());
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());
432 template <
typename Classifier>
437 if (rtnl_tc_get_handle(TC_CAST(cls.
get())) == 0) {
442 Handle parent(rtnl_tc_get_parent(TC_CAST(cls.
get())));
452 Handle handle(rtnl_tc_get_handle(TC_CAST(cls.
get())));
456 if (classifier.isError()) {
457 return Error(
"Failed to decode the classifier: " + classifier.error());
458 }
else if (classifier.isNone()) {
463 if (rtnl_tc_get_kind(TC_CAST(cls.
get())) == std::string(
"u32")) {
465 if (rtnl_u32_get_classid(cls.
get(), &_classid) == 0) {
468 }
else if (rtnl_tc_get_kind(TC_CAST(cls.
get())) == std::string(
"basic")) {
469 classid = rtnl_basic_get_target(cls.
get());
499 struct nl_cache* c =
nullptr;
500 int error = rtnl_cls_alloc_cache(
502 rtnl_link_get_ifindex(link.
get()),
508 "Failed to get filter info from kernel: " +
509 std::string(nl_geterror(error)));
514 std::vector<Netlink<struct rtnl_cls>> results;
516 for (
struct nl_object* o = nl_cache_get_first(cache.
get());
517 o !=
nullptr; o = nl_cache_get_next(o)) {
534 template <
typename Classifier>
538 const Classifier& classifier)
551 return Error(
"Failed to decode: " + filter.
error());
552 }
else if (filter.
isSome() && filter->classifier == classifier) {
567 template <
typename Classifier>
569 const std::string& _link,
571 const Classifier& classifier)
576 }
else if (link.
isNone()) {
594 template <
typename Classifier>
603 return Error(
"Check filter existence failed: " + _exists.
error());
604 }
else if (_exists.
get()) {
612 }
else if (link.
isNone()) {
613 return Error(
"Link '" + _link +
"' is not found");
618 return Error(
"Failed to encode the filter: " + cls.
error());
622 if (socket.isError()) {
623 return Error(socket.error());
626 int error = rtnl_cls_add(
629 NLM_F_CREATE | NLM_F_EXCL);
632 if (error == -NLE_EXIST) {
635 return Error(std::string(nl_geterror(error)));
647 template <
typename Classifier>
649 const std::string& _link,
651 const Classifier& classifier)
656 }
else if (link.
isNone()) {
665 }
else if (cls.
isNone()) {
674 int error = rtnl_cls_delete(socket->
get(), cls.
get().get(), 0);
678 return Error(std::string(nl_geterror(error)));
689 template <
typename Classifier>
695 }
else if (link.
isNone()) {
705 }
else if (oldCls.
isNone()) {
712 filter.
priority->get() != rtnl_cls_get_prio(oldCls.
get().get())) {
714 "The priorities do not match. The old priority is " +
716 " and the new priority is " +
722 if (filter.
handle.isSome() &&
724 rtnl_tc_get_handle(TC_CAST(oldCls->
get()))) {
726 "The handles do not match. The old handle is " +
728 " and the new handle is " +
734 return Error(
"Failed to encode the new filter: " + newCls.
error());
739 TC_CAST(newCls->
get()),
740 rtnl_tc_get_handle(TC_CAST(oldCls->
get())));
745 rtnl_cls_get_prio(oldCls->
get()));
752 int error = rtnl_cls_change(socket->
get(), newCls.
get().get(), 0);
754 if (error == -NLE_OBJ_NOTFOUND) {
757 return Error(std::string(nl_geterror(error)));
768 template <
typename Classifier>
770 const std::string& _link,
776 }
else if (link.
isNone()) {
787 std::vector<Filter<Classifier>> results;
796 }
else if (filter.
isSome()) {
797 results.push_back(filter.
get());
808 template <
typename Classifier>
810 const std::string& link,
814 filters<Classifier>(link, parent);
818 }
else if (_filters.
isNone()) {
822 std::vector<Classifier> results;
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:113
Definition: nothing.hpp:16
Definition: errorbase.hpp:36
Definition: option.hpp:29
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:80
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:54
Result< Netlink< struct rtnl_cls > > getCls(const Netlink< struct rtnl_link > &link, const Handle &parent, const Classifier &classifier)
Definition: internal.hpp:535
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: action.hpp:66
Definition: action.hpp:41
Definition: hashmap.hpp:38
Try< Nothing > encode(const Netlink< struct rtnl_cls > &cls, const Classifier &classifier)
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:769
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:690
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: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:43
Definition: handle.hpp:38
Try< Nothing > attach(const Netlink< struct rtnl_cls > &cls, const action::Redirect &redirect)
Definition: internal.hpp:100
Definition: attributes.hpp:24
bool isError() const
Definition: try.hpp:78
std::vector< process::Shared< action::Action > > actions
Definition: filter.hpp:115
std::string error(const std::string &msg, uint32_t code)
T & get()&
Definition: result.hpp:116
Definition: diagnosis.hpp:30
Try< uint32_t > classid(const std::string &hierarchy, const std::string &cgroup)
bool isSome() const
Definition: result.hpp:112
bool isError() const
Definition: result.hpp:114
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
bool contains(const Resource &left, const Resource &right)
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)