.I DIRECTION ACTION
.RB "[ " index
.IR INDEX " ] "
-.BI dev " DEVICENAME"
+.I TARGET
.ti -8
.IR DIRECTION " := { "
.BR ingress " | " egress " }"
+.ti -8
+.IR TARGET " := { " DEV " | " BLOCK " }"
+
+.ti -8
+.IR DEV " := "
+.BI dev " DEVICENAME"
+
+.ti -8
+.IR BLOCK " := "
+.BI blockid " BLOCKID"
+
.ti -8
.IR ACTION " := { "
.BR mirror " | " redirect " }"
action allows packet mirroring (copying) or redirecting (stealing) the packet it
receives. Mirroring is what is sometimes referred to as Switch Port Analyzer
(SPAN) and is commonly used to analyze and/or debug flows.
+When mirroring to a tc block, the packet will be mirrored to all the ports in
+the block with exception of the port where the packet ingressed, if that port is
+part of the tc block. Redirecting is simillar to mirroring except that the
+behaviour is to mirror to the first N - 1 ports in the block and redirect to the
+last one (note that the port in which the packet arrived is not going to be
+mirrored or redirected to).
.SH OPTIONS
.TP
.B ingress
.RB ( mirror )
or moved
.RB ( redirect )
-to the destination interface.
+to the destination interface or block.
.TP
.BI index " INDEX"
Assign a unique ID to this action instead of letting the kernel choose one
.TP
.BI dev " DEVICENAME"
Specify the network interface to redirect or mirror to.
+.TP
+.BI blockid " BLOCKID"
+Specify the tc block to redirect or mirror to.
.SH EXAMPLES
Limit ingress bandwidth on eth0 to 1mbit/s, redirect exceeding traffic to lo for
debugging purposes:
explain(void)
{
fprintf(stderr,
- "Usage: mirred <DIRECTION> <ACTION> [index INDEX] <dev DEVICENAME>\n"
+ "Usage: mirred <DIRECTION> <ACTION> [index INDEX] <TARGET>\n"
"where:\n"
"\tDIRECTION := <ingress | egress>\n"
"\tACTION := <mirror | redirect>\n"
"\tINDEX is the specific policy instance id\n"
- "\tDEVICENAME is the devicename\n");
+ "\tTARGET := <BLOCK | DEVICE>\n"
+ "\tDEVICE := dev DEVICENAME\n"
+ "\tDEVICENAME is the devicename\n"
+ "\tBLOCK := blockid BLOCKID\n"
+ "\tBLOCKID := 32-bit unsigned block ID\n");
}
static void
struct tc_mirred p = {};
struct rtattr *tail;
char d[IFNAMSIZ] = {};
+ __u32 blockid = 0;
while (argc > 0) {
TCA_INGRESS_REDIR;
p.action = TC_ACT_STOLEN;
ok++;
- } else if ((redir || mirror) &&
- matches(*argv, "dev") == 0) {
- NEXT_ARG();
- if (strlen(d))
- duparg("dev", *argv);
-
- strncpy(d, *argv, sizeof(d)-1);
- argc--;
- argv++;
+ } else if ((redir || mirror)) {
+ if (strcmp(*argv, "blockid") == 0) {
+ if (strlen(d)) {
+ fprintf(stderr,
+ "blockid and device are mutually exclusive.\n");
+ return -1;
+ }
+ NEXT_ARG();
+ if (get_u32(&blockid, *argv, 0) ||
+ !blockid) {
+ fprintf(stderr,
+ "invalid block ID");
+ return -1;
+ }
+ argc--;
+ argv++;
+ }
+ if (argc && matches(*argv, "dev") == 0) {
+ if (blockid) {
+ fprintf(stderr,
+ "blockid and device are mutually exclusive.\n");
+ return -1;
+ }
+ NEXT_ARG();
+ if (strlen(d))
+ duparg("dev", *argv);
+
+ strncpy(d, *argv, sizeof(d)-1);
+ argc--;
+ argv++;
+ }
break;
tail = addattr_nest(n, MAX_MSG, tca_id);
addattr_l(n, MAX_MSG, TCA_MIRRED_PARMS, &p, sizeof(p));
+ if (blockid)
+ addattr32(n, MAX_MSG, TCA_MIRRED_BLOCKID, blockid);
addattr_nest_end(n, tail);
*argc_p = argc;
mirred_action(p->eaction));
print_string(PRINT_JSON, "direction", NULL,
mirred_direction(p->eaction));
- print_string(PRINT_ANY, "to_dev", " to device %s)", dev);
+ if (tb[TCA_MIRRED_BLOCKID]) {
+ const __u32 *blockid = RTA_DATA(tb[TCA_MIRRED_BLOCKID]);
+
+ print_uint(PRINT_ANY, "to_blockid", " to blockid %u)",
+ *blockid);
+ } else {
+ print_string(PRINT_ANY, "to_dev", " to device %s)", dev);
+ }
+
print_action_control(f, " ", p->action, "");
print_nl();