Skip to content

Commit f3ef8e3

Browse files
committed
issue: 1557652 Add tc_add_filter_dev2tap() operation
This function creates rule that redirect traffic from device to tap device. Signed-off-by: Igor Ivanov <[email protected]>
1 parent 13a5798 commit f3ef8e3

File tree

3 files changed

+298
-36
lines changed

3 files changed

+298
-36
lines changed

tools/daemon/flow.c

Lines changed: 9 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -134,15 +134,12 @@ int add_flow(struct store_pid *pid_value, struct store_flow *value)
134134
struct flow_element *cur_element = NULL;
135135
struct list_head *cur_entry = NULL;
136136
char if_name[IF_NAMESIZE];
137-
char tap_name[IF_NAMESIZE];
138-
char *out_buf = NULL;
139137
uint32_t ip = value->flow.dst_ip;
140138
int ht = HANDLE_HT(value->handle);
141139
int bkt = HANDLE_BKT(value->handle);
142140
int id = HANDLE_ID(value->handle);
143141
int ht_internal = KERNEL_HT;
144142
struct flow_ctx *ctx = NULL;
145-
char str_tmp[100];
146143

147144
/* Egress rules should be created for new tap device
148145
*/
@@ -158,13 +155,6 @@ int add_flow(struct store_pid *pid_value, struct store_flow *value)
158155
goto err;
159156
}
160157

161-
if (NULL == if_indextoname(value->tap_id, tap_name)) {
162-
log_error("[%d] tap interface is not found by index %d errno %d (%s)\n",
163-
pid, value->tap_id, errno, strerror(errno));
164-
rc = -errno;
165-
goto err;
166-
}
167-
168158
/* interface list processing
169159
* use interface index as unique identifier
170160
* every network interface has qdisc
@@ -334,36 +324,22 @@ int add_flow(struct store_pid *pid_value, struct store_flow *value)
334324
switch (value->type) {
335325
case VMA_MSG_FLOW_TCP_3T:
336326
case VMA_MSG_FLOW_UDP_3T:
337-
out_buf = sys_exec("tc filter add dev %s parent ffff: protocol ip "
338-
"prio %d handle ::%x u32 ht %x:%x: "
339-
"match ip protocol %d 0xff "
340-
"match ip nofrag "
341-
"match ip dst %s/32 match ip dport %d 0xffff "
342-
"action mirred egress redirect dev %s > /dev/null 2>&1 || echo $?",
343-
if_name, get_prio(value), id, ht, bkt, get_protocol(value),
344-
sys_ip2str(value->flow.dst_ip), ntohs(value->flow.dst_port), tap_name);
327+
rc = tc_add_filter_dev2tap_3t(tc, value->if_id,
328+
get_prio(value), ht, bkt, id,
329+
get_protocol(value), value->flow.dst_ip, value->flow.dst_port, value->tap_id);
345330
break;
346331
case VMA_MSG_FLOW_TCP_5T:
347332
case VMA_MSG_FLOW_UDP_5T:
348-
strncpy(str_tmp, sys_ip2str(value->flow.t5.src_ip), sizeof(str_tmp));
349-
str_tmp[sizeof(str_tmp) - 1] = '\0';
350-
out_buf = sys_exec("tc filter add dev %s parent ffff: protocol ip "
351-
"prio %d handle ::%x u32 ht %x:%x: "
352-
"match ip protocol %d 0xff "
353-
"match ip nofrag "
354-
"match ip src %s/32 match ip sport %d 0xffff "
355-
"match ip dst %s/32 match ip dport %d 0xffff "
356-
"action mirred egress redirect dev %s > /dev/null 2>&1 || echo $?",
357-
if_name, get_prio(value), id, ht, bkt, get_protocol(value),
358-
str_tmp, ntohs(value->flow.t5.src_port),
359-
sys_ip2str(value->flow.dst_ip), ntohs(value->flow.dst_port), tap_name);
333+
rc = tc_add_filter_dev2tap_5t(tc, value->if_id,
334+
get_prio(value), ht, bkt, id,
335+
get_protocol(value), value->flow.dst_ip, value->flow.dst_port,
336+
value->flow.t5.src_ip, value->flow.t5.src_port, value->tap_id);
360337
break;
361338
default:
362339
break;
363340
}
364-
if (NULL == out_buf || (out_buf[0] != '\0' && out_buf[0] != '0')) {
365-
log_error("[%d] failed add filter dev %s prio %d handle %x:%x:%x output: %s\n",
366-
pid, if_name, get_prio(value), ht, bkt, id, (out_buf ? out_buf : "n/a"));
341+
if (rc < 0) {
342+
log_error("[%d] failed tc operation errno = %d\n", pid, errno);
367343
free(cur_element);
368344
rc = -EFAULT;
369345
goto err;

tools/daemon/tc.c

Lines changed: 285 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,9 @@ struct tc_object {
6060

6161
#if defined(USE_NETLINK) && (USE_NETLINK == 1)
6262
static int pack_key(struct tc_u32_sel *sel, uint32_t key, uint32_t mask, int off, int offmask);
63+
static int pack_key8(struct tc_u32_sel *sel, uint32_t key, uint32_t mask, int off, int offmask);
64+
static int pack_key16(struct tc_u32_sel *sel, uint32_t key, uint32_t mask, int off, int offmask);
65+
static int pack_key32(struct tc_u32_sel *sel, uint32_t key, uint32_t mask, int off, int offmask);
6366
#endif /* USE_NETLINK */
6467

6568

@@ -286,7 +289,7 @@ int tc_add_filter_link(tc_t tc, int ifindex, int prio, int ht, int id, uint32_t
286289
* dst: 16
287290
* addr/mask: ip/0xffffffff
288291
*/
289-
pack_key(&opt_sel.sel, ip, 0xffffffff, 16, 0);
292+
pack_key32(&opt_sel.sel, ntohl(ip), 0xffffffff, 16, 0);
290293
nl_attr_add(&tc->req.hdr, TCA_U32_SEL, &opt_sel, sizeof(opt_sel.sel) + opt_sel.sel.nkeys * sizeof(opt_sel.sel.keys[0]));
291294
nl_attr_nest_end(&tc->req.hdr, opts);
292295

@@ -385,9 +388,9 @@ int tc_add_filter_tap2dev(tc_t tc, int ifindex, int prio, int id, uint32_t ip, i
385388
* addr/mask: ip/0xffffffff
386389
*/
387390
if (ip) {
388-
pack_key(&opt_sel.sel, ip, 0xffffffff, 16, 0);
391+
pack_key32(&opt_sel.sel, ntohl(ip), 0xffffffff, 16, 0);
389392
} else {
390-
pack_key(&opt_sel.sel, ip, 0, 0, 0);
393+
pack_key32(&opt_sel.sel, ntohl(ip), 0, 0, 0);
391394
}
392395
opt_sel.sel.flags |= TC_U32_TERMINAL;
393396
nl_attr_add(&tc->req.hdr, TCA_U32_SEL, &opt_sel, sizeof(opt_sel.sel) + opt_sel.sel.nkeys * sizeof(opt_sel.sel.keys[0]));
@@ -442,6 +445,245 @@ int tc_add_filter_tap2dev(tc_t tc, int ifindex, int prio, int id, uint32_t ip, i
442445
return rc;
443446
}
444447

448+
int tc_add_filter_dev2tap_3t(tc_t tc, int ifindex, int prio, int ht, int bkt, int id,
449+
int proto, uint32_t dst_ip, uint16_t dst_port, int ifindex_to)
450+
{
451+
int rc = 0;
452+
453+
#if defined(USE_NETLINK) && (USE_NETLINK == 1)
454+
struct tc_qdisc qdisc = {HANDLE_SET(0, 0, id), 0xffff0000, prio};
455+
char opt_kind[] = "u32";
456+
uint32_t opt_ht = HANDLE_SET(ht, bkt, 0);
457+
struct rtattr *opts = NULL;
458+
struct {
459+
struct tc_u32_sel sel;
460+
struct tc_u32_key keys[10];
461+
} opt_sel;
462+
463+
tc_req(tc, ifindex, RTM_NEWTFILTER,
464+
(NLM_F_REQUEST | NLM_F_ACK | NLM_F_EXCL | NLM_F_CREATE),
465+
qdisc);
466+
467+
nl_attr_add(&tc->req.hdr, TCA_KIND, opt_kind, sizeof(opt_kind));
468+
469+
/* [filter] options filling */
470+
opts = nl_attr_nest_start(&tc->req.hdr, TCA_OPTIONS);
471+
{
472+
struct rtattr *opts_action = NULL;
473+
474+
/* [action] options filling */
475+
opts_action = nl_attr_nest_start(&tc->req.hdr, TCA_U32_ACT);
476+
{
477+
int prio = 0;
478+
char opt_act_kind[] = "mirred";
479+
struct rtattr *opts_action_prio = NULL;
480+
481+
/* [mirred] options filling */
482+
opts_action_prio = nl_attr_nest_start(&tc->req.hdr, ++prio);
483+
nl_attr_add(&tc->req.hdr, TCA_ACT_KIND, opt_act_kind, sizeof(opt_act_kind));
484+
{
485+
struct rtattr *opts_action_prio_mirred = NULL;
486+
struct tc_mirred opt_mirred;
487+
488+
opts_action_prio_mirred = nl_attr_nest_start(&tc->req.hdr, TCA_ACT_OPTIONS);
489+
memset(&opt_mirred, 0, sizeof(opt_mirred));
490+
opt_mirred.eaction = TCA_EGRESS_REDIR;
491+
opt_mirred.action = TC_ACT_STOLEN;
492+
opt_mirred.ifindex = ifindex_to;
493+
nl_attr_add(&tc->req.hdr, TCA_MIRRED_PARMS, &opt_mirred, sizeof(opt_mirred));
494+
495+
nl_attr_nest_end(&tc->req.hdr, opts_action_prio_mirred);
496+
}
497+
498+
nl_attr_nest_end(&tc->req.hdr, opts_action_prio);
499+
}
500+
501+
nl_attr_nest_end(&tc->req.hdr, opts_action);
502+
}
503+
504+
nl_attr_add(&tc->req.hdr, TCA_U32_HASH, &opt_ht, sizeof(opt_ht));
505+
memset(&opt_sel, 0, sizeof(opt_sel));
506+
/* [match] protocol option */
507+
pack_key8(&opt_sel.sel, proto, 0xff, 9, 0);
508+
/* [match] nofrag option */
509+
pack_key16(&opt_sel.sel, 0, 0x3fff, 6, 0);
510+
/* [match] dst option */
511+
pack_key32(&opt_sel.sel, ntohl(dst_ip), 0xffffffff, 16, 0);
512+
/* [match] dport option */
513+
pack_key16(&opt_sel.sel, ntohs(dst_port), 0xffff, 22, 0);
514+
opt_sel.sel.flags |= TC_U32_TERMINAL;
515+
nl_attr_add(&tc->req.hdr, TCA_U32_SEL, &opt_sel, sizeof(opt_sel.sel) + opt_sel.sel.nkeys * sizeof(opt_sel.sel.keys[0]));
516+
517+
nl_attr_nest_end(&tc->req.hdr, opts);
518+
519+
if (nl_send(tc->nl, &tc->req.hdr) < 0) {
520+
rc = -1;
521+
goto err;
522+
}
523+
if (nl_recv(tc->nl, NULL, NULL) < 0) {
524+
rc = -1;
525+
goto err;
526+
}
527+
#else
528+
char *out_buf = NULL;
529+
char if_name[IF_NAMESIZE];
530+
char tap_name[IF_NAMESIZE];
531+
532+
UNREFERENCED_PARAMETER(tc);
533+
534+
if (NULL == if_indextoname(ifindex, if_name)) {
535+
rc = -errno;
536+
goto err;
537+
}
538+
539+
if (NULL == if_indextoname(ifindex_to, tap_name)) {
540+
rc = -errno;
541+
goto err;
542+
}
543+
544+
out_buf = sys_exec("tc filter add dev %s parent ffff: protocol ip "
545+
"prio %d handle ::%x u32 ht %x:%x: "
546+
"match ip protocol %d 0xff "
547+
"match ip nofrag "
548+
"match ip dst %s/32 match ip dport %d 0xffff "
549+
"action mirred egress redirect dev %s "
550+
"> /dev/null 2>&1 || echo $?",
551+
if_name, prio, id, ht, bkt, proto,
552+
sys_ip2str(dst_ip), ntohs(dst_port), tap_name);
553+
if (NULL == out_buf || (out_buf[0] != '\0' && out_buf[0] != '0')) {
554+
rc = -1;
555+
goto err;
556+
}
557+
#endif /* USE_NETLINK */
558+
559+
err:
560+
return rc;
561+
}
562+
563+
int tc_add_filter_dev2tap_5t(tc_t tc, int ifindex, int prio, int ht, int bkt, int id,
564+
int proto, uint32_t dst_ip, uint16_t dst_port, uint32_t src_ip, uint16_t src_port, int ifindex_to)
565+
{
566+
int rc = 0;
567+
568+
#if defined(USE_NETLINK) && (USE_NETLINK == 1)
569+
struct tc_qdisc qdisc = {HANDLE_SET(0, 0, id), 0xffff0000, prio};
570+
char opt_kind[] = "u32";
571+
uint32_t opt_ht = HANDLE_SET(ht, bkt, 0);
572+
struct rtattr *opts = NULL;
573+
struct {
574+
struct tc_u32_sel sel;
575+
struct tc_u32_key keys[10];
576+
} opt_sel;
577+
578+
tc_req(tc, ifindex, RTM_NEWTFILTER,
579+
(NLM_F_REQUEST | NLM_F_ACK | NLM_F_EXCL | NLM_F_CREATE),
580+
qdisc);
581+
582+
nl_attr_add(&tc->req.hdr, TCA_KIND, opt_kind, sizeof(opt_kind));
583+
584+
/* [filter] options filling */
585+
opts = nl_attr_nest_start(&tc->req.hdr, TCA_OPTIONS);
586+
{
587+
struct rtattr *opts_action = NULL;
588+
589+
/* [action] options filling */
590+
opts_action = nl_attr_nest_start(&tc->req.hdr, TCA_U32_ACT);
591+
{
592+
int prio = 0;
593+
char opt_act_kind[] = "mirred";
594+
struct rtattr *opts_action_prio = NULL;
595+
596+
/* [mirred] options filling */
597+
opts_action_prio = nl_attr_nest_start(&tc->req.hdr, ++prio);
598+
nl_attr_add(&tc->req.hdr, TCA_ACT_KIND, opt_act_kind, sizeof(opt_act_kind));
599+
{
600+
struct rtattr *opts_action_prio_mirred = NULL;
601+
struct tc_mirred opt_mirred;
602+
603+
opts_action_prio_mirred = nl_attr_nest_start(&tc->req.hdr, TCA_ACT_OPTIONS);
604+
memset(&opt_mirred, 0, sizeof(opt_mirred));
605+
opt_mirred.eaction = TCA_EGRESS_REDIR;
606+
opt_mirred.action = TC_ACT_STOLEN;
607+
opt_mirred.ifindex = ifindex_to;
608+
nl_attr_add(&tc->req.hdr, TCA_MIRRED_PARMS, &opt_mirred, sizeof(opt_mirred));
609+
610+
nl_attr_nest_end(&tc->req.hdr, opts_action_prio_mirred);
611+
}
612+
613+
nl_attr_nest_end(&tc->req.hdr, opts_action_prio);
614+
}
615+
616+
nl_attr_nest_end(&tc->req.hdr, opts_action);
617+
}
618+
619+
nl_attr_add(&tc->req.hdr, TCA_U32_HASH, &opt_ht, sizeof(opt_ht));
620+
memset(&opt_sel, 0, sizeof(opt_sel));
621+
/* [match] protocol option */
622+
pack_key8(&opt_sel.sel, proto, 0xff, 9, 0);
623+
/* [match] nofrag option */
624+
pack_key16(&opt_sel.sel, 0, 0x3fff, 6, 0);
625+
/* [match] src option */
626+
pack_key32(&opt_sel.sel, ntohl(src_ip), 0xffffffff, 12, 0);
627+
/* [match] sport option */
628+
pack_key16(&opt_sel.sel, ntohs(src_port), 0xffff, 20, 0);
629+
/* [match] dst option */
630+
pack_key32(&opt_sel.sel, ntohl(dst_ip), 0xffffffff, 16, 0);
631+
/* [match] dport option */
632+
pack_key16(&opt_sel.sel, ntohs(dst_port), 0xffff, 22, 0);
633+
opt_sel.sel.flags |= TC_U32_TERMINAL;
634+
nl_attr_add(&tc->req.hdr, TCA_U32_SEL, &opt_sel, sizeof(opt_sel.sel) + opt_sel.sel.nkeys * sizeof(opt_sel.sel.keys[0]));
635+
636+
nl_attr_nest_end(&tc->req.hdr, opts);
637+
638+
if (nl_send(tc->nl, &tc->req.hdr) < 0) {
639+
rc = -1;
640+
goto err;
641+
}
642+
if (nl_recv(tc->nl, NULL, NULL) < 0) {
643+
rc = -1;
644+
goto err;
645+
}
646+
#else
647+
char *out_buf = NULL;
648+
char if_name[IF_NAMESIZE];
649+
char tap_name[IF_NAMESIZE];
650+
char str_tmp[100];
651+
652+
UNREFERENCED_PARAMETER(tc);
653+
654+
if (NULL == if_indextoname(ifindex, if_name)) {
655+
rc = -errno;
656+
goto err;
657+
}
658+
659+
if (NULL == if_indextoname(ifindex_to, tap_name)) {
660+
rc = -errno;
661+
goto err;
662+
}
663+
664+
strncpy(str_tmp, sys_ip2str(src_ip), sizeof(str_tmp));
665+
str_tmp[sizeof(str_tmp) - 1] = '\0';
666+
out_buf = sys_exec("tc filter add dev %s parent ffff: protocol ip "
667+
"prio %d handle ::%x u32 ht %x:%x: "
668+
"match ip protocol %d 0xff "
669+
"match ip nofrag "
670+
"match ip src %s/32 match ip sport %d 0xffff "
671+
"match ip dst %s/32 match ip dport %d 0xffff "
672+
"action mirred egress redirect dev %s "
673+
"> /dev/null 2>&1 || echo $?",
674+
if_name, prio, id, ht, bkt, proto,
675+
str_tmp, src_port,
676+
sys_ip2str(dst_ip), ntohs(dst_port), tap_name);
677+
if (NULL == out_buf || (out_buf[0] != '\0' && out_buf[0] != '0')) {
678+
rc = -1;
679+
goto err;
680+
}
681+
#endif /* USE_NETLINK */
682+
683+
err:
684+
return rc;
685+
}
686+
445687
int tc_del_filter(tc_t tc, int ifindex, int prio, int ht, int bkt, int id)
446688
{
447689
int rc = 0;
@@ -519,4 +761,44 @@ static int pack_key(struct tc_u32_sel *sel, uint32_t key, uint32_t mask, int of
519761

520762
return 0;
521763
}
764+
765+
static int pack_key8(struct tc_u32_sel *sel, uint32_t key, uint32_t mask, int off, int offmask)
766+
{
767+
if ((off & 3) == 0) {
768+
key <<= 24;
769+
mask <<= 24;
770+
} else if ((off & 3) == 1) {
771+
key <<= 16;
772+
mask <<= 16;
773+
} else if ((off & 3) == 2) {
774+
key <<= 8;
775+
mask <<= 8;
776+
}
777+
off &= ~3;
778+
key = htonl(key);
779+
mask = htonl(mask);
780+
781+
return pack_key(sel, key, mask, off, offmask);
782+
}
783+
784+
static int pack_key16(struct tc_u32_sel *sel, uint32_t key, uint32_t mask, int off, int offmask)
785+
{
786+
if ((off & 3) == 0) {
787+
key <<= 16;
788+
mask <<= 16;
789+
}
790+
off &= ~3;
791+
key = htonl(key);
792+
mask = htonl(mask);
793+
794+
return pack_key(sel, key, mask, off, offmask);
795+
}
796+
797+
static int pack_key32(struct tc_u32_sel *sel, uint32_t key, uint32_t mask, int off, int offmask)
798+
{
799+
key = htonl(key);
800+
mask = htonl(mask);
801+
802+
return pack_key(sel, key, mask, off, offmask);
803+
}
522804
#endif /* USE_NETLINK */

0 commit comments

Comments
 (0)