@@ -16,6 +16,7 @@
#define TCA_VLAN_ACT_POP 1
#define TCA_VLAN_ACT_PUSH 2
+#define TCA_VLAN_ACT_MODIFY 3
struct tc_vlan {
tc_gen;
@@ -6,7 +6,7 @@ vlan - vlan manipulation module
.in +8
.ti -8
.BR tc " ... " "action vlan" " { " pop " |"
-.IR PUSH " } [ " CONTROL " ]"
+.IR PUSH " | " MODIFY " } [ " CONTROL " ]"
.ti -8
.IR PUSH " := "
@@ -17,22 +17,30 @@ vlan - vlan manipulation module
.BI id " VLANID"
.ti -8
+.IR MODIFY " := "
+.BR modify " [ " protocol
+.IR VLANPROTO " ]"
+.BR " [ " priority
+.IR VLANPRIO " ] "
+.BI id " VLANID"
+
+.ti -8
.IR CONTROL " := { "
.BR reclassify " | " pipe " | " drop " | " continue " | " pass " }"
.SH DESCRIPTION
The
.B vlan
action allows to perform 802.1Q en- or decapsulation on a packet, reflected by
-the two operation modes
-.IR POP " and " PUSH .
+the operation modes
+.IR POP ", " PUSH " and " MODIFY .
The
.I POP
mode is simple, as no further information is required to just drop the
outer-most VLAN encapsulation. The
-.I PUSH
-mode on the other hand requires at least a
+.IR PUSH " and " MODIFY
+modes require at least a
.I VLANID
-and allows to optionally choose the
+and allow to optionally choose the
.I VLANPROTO
to use.
.SH OPTIONS
@@ -45,6 +53,11 @@ Encapsulation mode. Requires at least
.B id
option.
.TP
+.B modify
+Replace mode. Existing 802.1Q tag is replaced. Requires at least
+.B id
+option.
+.TP
.BI id " VLANID"
Specify the VLAN ID to encapsulate into.
.I VLANID
@@ -19,10 +19,17 @@
#include "tc_util.h"
#include <linux/tc_act/tc_vlan.h>
+static const char * const action_names[] = {
+ [TCA_VLAN_ACT_POP] = "pop",
+ [TCA_VLAN_ACT_PUSH] = "push",
+ [TCA_VLAN_ACT_MODIFY] = "modify",
+};
+
static void explain(void)
{
fprintf(stderr, "Usage: vlan pop\n");
fprintf(stderr, " vlan push [ protocol VLANPROTO ] id VLANID [ priority VLANPRIO ] [CONTROL]\n");
+ fprintf(stderr, " vlan modify [ protocol VLANPROTO ] id VLANID [ priority VLANPRIO ] [CONTROL]\n");
fprintf(stderr, " VLANPROTO is one of 802.1Q or 802.1AD\n");
fprintf(stderr, " with default: 802.1Q\n");
fprintf(stderr, " CONTROL := reclassify | pipe | drop | continue | pass\n");
@@ -34,6 +41,11 @@ static void usage(void)
exit(-1);
}
+static bool has_push_attribs(int action)
+{
+ return action == TCA_VLAN_ACT_PUSH || action == TCA_VLAN_ACT_MODIFY;
+}
+
static int parse_vlan(struct action_util *a, int *argc_p, char ***argv_p,
int tca_id, struct nlmsghdr *n)
{
@@ -71,9 +83,17 @@ static int parse_vlan(struct action_util *a, int *argc_p, char ***argv_p,
return -1;
}
action = TCA_VLAN_ACT_PUSH;
+ } else if (matches(*argv, "modify") == 0) {
+ if (action) {
+ fprintf(stderr, "unexpected \"%s\" - action already specified\n",
+ *argv);
+ explain();
+ return -1;
+ }
+ action = TCA_VLAN_ACT_MODIFY;
} else if (matches(*argv, "id") == 0) {
- if (action != TCA_VLAN_ACT_PUSH) {
- fprintf(stderr, "\"%s\" is only valid for push\n",
+ if (!has_push_attribs(action)) {
+ fprintf(stderr, "\"%s\" is only valid for push/modify\n",
*argv);
explain();
return -1;
@@ -83,8 +103,8 @@ static int parse_vlan(struct action_util *a, int *argc_p, char ***argv_p,
invarg("id is invalid", *argv);
id_set = 1;
} else if (matches(*argv, "protocol") == 0) {
- if (action != TCA_VLAN_ACT_PUSH) {
- fprintf(stderr, "\"%s\" is only valid for push\n",
+ if (!has_push_attribs(action)) {
+ fprintf(stderr, "\"%s\" is only valid for push/modify\n",
*argv);
explain();
return -1;
@@ -94,8 +114,8 @@ static int parse_vlan(struct action_util *a, int *argc_p, char ***argv_p,
invarg("protocol is invalid", *argv);
proto_set = 1;
} else if (matches(*argv, "priority") == 0) {
- if (action != TCA_VLAN_ACT_PUSH) {
- fprintf(stderr, "\"%s\" is only valid for push\n",
+ if (!has_push_attribs(action)) {
+ fprintf(stderr, "\"%s\" is only valid for push/modify\n",
*argv);
explain();
return -1;
@@ -129,8 +149,9 @@ static int parse_vlan(struct action_util *a, int *argc_p, char ***argv_p,
}
}
- if (action == TCA_VLAN_ACT_PUSH && !id_set) {
- fprintf(stderr, "id needs to be set for push\n");
+ if (has_push_attribs(action) && !id_set) {
+ fprintf(stderr, "id needs to be set for %s\n",
+ action_names[action]);
explain();
return -1;
}
@@ -186,7 +207,8 @@ static int print_vlan(struct action_util *au, FILE *f, struct rtattr *arg)
fprintf(f, " pop");
break;
case TCA_VLAN_ACT_PUSH:
- fprintf(f, " push");
+ case TCA_VLAN_ACT_MODIFY:
+ fprintf(f, " %s", action_names[parm->v_action]);
if (tb[TCA_VLAN_PUSH_VLAN_ID]) {
val = rta_getattr_u16(tb[TCA_VLAN_PUSH_VLAN_ID]);
fprintf(f, " id %u", val);
The 'vlan modify' action allows to replace an existing 802.1q tag according to user provided settings. It accepts same arguments as the 'vlan push' action. For example, this replaces vid 6 with vid 5: # tc filter add dev veth0 parent ffff: pref 1 protocol 802.1q \ basic match 'meta(vlan mask 0xfff eq 6)' \ action vlan modify id 5 continue Signed-off-by: Shmulik Ladkani <shmulik.ladkani@gmail.com> --- v2: Coding. No need to encapsule action_names[] access into a function include/linux/tc_act/tc_vlan.h | 1 + man/man8/tc-vlan.8 | 25 +++++++++++++++++++------ tc/m_vlan.c | 40 +++++++++++++++++++++++++++++++--------- 3 files changed, 51 insertions(+), 15 deletions(-)