2 * m_vlan.c vlan manipulation module
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version
7 * 2 of the License, or (at your option) any later version.
9 * Authors: Jiri Pirko <jiri@resnulli.us>
16 #include <linux/if_ether.h>
20 #include <linux/tc_act/tc_vlan.h>
22 static const char * const action_names
[] = {
23 [TCA_VLAN_ACT_POP
] = "pop",
24 [TCA_VLAN_ACT_PUSH
] = "push",
25 [TCA_VLAN_ACT_MODIFY
] = "modify",
26 [TCA_VLAN_ACT_POP_ETH
] = "pop_eth",
27 [TCA_VLAN_ACT_PUSH_ETH
] = "push_eth",
30 static void explain(void)
33 "Usage: vlan pop [CONTROL]\n"
34 " vlan push [ protocol VLANPROTO ] id VLANID [ priority VLANPRIO ] [CONTROL]\n"
35 " vlan modify [ protocol VLANPROTO ] id VLANID [ priority VLANPRIO ] [CONTROL]\n"
36 " vlan pop_eth [CONTROL]\n"
37 " vlan push_eth dst_mac LLADDR src_mac LLADDR [CONTROL]\n"
38 " VLANPROTO is one of 802.1Q or 802.1AD\n"
39 " with default: 802.1Q\n"
40 " CONTROL := reclassify | pipe | drop | continue | pass |\n"
41 " goto chain <CHAIN_INDEX>\n");
44 static void usage(void)
50 static bool has_push_attribs(int action
)
52 return action
== TCA_VLAN_ACT_PUSH
|| action
== TCA_VLAN_ACT_MODIFY
;
55 static void unexpected(const char *arg
)
58 "unexpected \"%s\" - action already specified\n",
63 static int parse_vlan(struct action_util
*a
, int *argc_p
, char ***argv_p
,
64 int tca_id
, struct nlmsghdr
*n
)
67 char **argv
= *argv_p
;
70 char dst_mac
[ETH_ALEN
] = {};
72 char src_mac
[ETH_ALEN
] = {};
80 struct tc_vlan parm
= {};
82 if (matches(*argv
, "vlan") != 0)
88 if (matches(*argv
, "pop") == 0) {
93 action
= TCA_VLAN_ACT_POP
;
94 } else if (matches(*argv
, "push") == 0) {
99 action
= TCA_VLAN_ACT_PUSH
;
100 } else if (matches(*argv
, "modify") == 0) {
105 action
= TCA_VLAN_ACT_MODIFY
;
106 } else if (matches(*argv
, "pop_eth") == 0) {
111 action
= TCA_VLAN_ACT_POP_ETH
;
112 } else if (matches(*argv
, "push_eth") == 0) {
117 action
= TCA_VLAN_ACT_PUSH_ETH
;
118 } else if (matches(*argv
, "id") == 0) {
119 if (!has_push_attribs(action
))
120 invarg("only valid for push/modify", *argv
);
123 if (get_u16(&id
, *argv
, 0))
124 invarg("id is invalid", *argv
);
126 } else if (matches(*argv
, "protocol") == 0) {
127 if (!has_push_attribs(action
))
128 invarg("only valid for push/modify", *argv
);
131 if (ll_proto_a2n(&proto
, *argv
))
132 invarg("protocol is invalid", *argv
);
134 } else if (matches(*argv
, "priority") == 0) {
135 if (!has_push_attribs(action
))
136 invarg("only valid for push/modify", *argv
);
139 if (get_u8(&prio
, *argv
, 0) || (prio
& ~0x7))
140 invarg("prio is invalid", *argv
);
142 } else if (matches(*argv
, "dst_mac") == 0) {
143 if (action
!= TCA_VLAN_ACT_PUSH_ETH
)
144 invarg("only valid for push_eth", *argv
);
147 if (ll_addr_a2n(dst_mac
, sizeof(dst_mac
), *argv
) < 0)
148 invarg("dst_mac is invalid", *argv
);
150 } else if (matches(*argv
, "src_mac") == 0) {
151 if (action
!= TCA_VLAN_ACT_PUSH_ETH
)
152 invarg("only valid for push_eth", *argv
);
155 if (ll_addr_a2n(src_mac
, sizeof(src_mac
), *argv
) < 0)
156 invarg("src_mac is invalid", *argv
);
158 } else if (matches(*argv
, "help") == 0) {
167 parse_action_control_dflt(&argc
, &argv
, &parm
.action
,
171 if (matches(*argv
, "index") == 0) {
173 if (get_u32(&parm
.index
, *argv
, 10)) {
174 fprintf(stderr
, "vlan: Illegal \"index\"\n");
182 if (has_push_attribs(action
) && !id_set
) {
183 fprintf(stderr
, "id needs to be set for %s\n",
184 action_names
[action
]);
189 if (action
== TCA_VLAN_ACT_PUSH_ETH
) {
191 fprintf(stderr
, "dst_mac needs to be set for %s\n",
192 action_names
[action
]);
195 } else if (!src_mac_set
) {
196 fprintf(stderr
, "src_mac needs to be set for %s\n",
197 action_names
[action
]);
203 parm
.v_action
= action
;
204 tail
= addattr_nest(n
, MAX_MSG
, tca_id
);
205 addattr_l(n
, MAX_MSG
, TCA_VLAN_PARMS
, &parm
, sizeof(parm
));
207 addattr_l(n
, MAX_MSG
, TCA_VLAN_PUSH_VLAN_ID
, &id
, 2);
209 if (proto
!= htons(ETH_P_8021Q
) &&
210 proto
!= htons(ETH_P_8021AD
)) {
211 fprintf(stderr
, "protocol not supported\n");
216 addattr_l(n
, MAX_MSG
, TCA_VLAN_PUSH_VLAN_PROTOCOL
, &proto
, 2);
219 addattr8(n
, MAX_MSG
, TCA_VLAN_PUSH_VLAN_PRIORITY
, prio
);
221 addattr_l(n
, MAX_MSG
, TCA_VLAN_PUSH_ETH_DST
, dst_mac
,
224 addattr_l(n
, MAX_MSG
, TCA_VLAN_PUSH_ETH_SRC
, src_mac
,
227 addattr_nest_end(n
, tail
);
234 static int print_vlan(struct action_util
*au
, FILE *f
, struct rtattr
*arg
)
237 struct rtattr
*tb
[TCA_VLAN_MAX
+ 1];
239 struct tc_vlan
*parm
;
241 print_string(PRINT_ANY
, "kind", "%s ", "vlan");
245 parse_rtattr_nested(tb
, TCA_VLAN_MAX
, arg
);
247 if (!tb
[TCA_VLAN_PARMS
]) {
248 fprintf(stderr
, "Missing vlan parameters\n");
251 parm
= RTA_DATA(tb
[TCA_VLAN_PARMS
]);
253 print_string(PRINT_ANY
, "vlan_action", " %s",
254 action_names
[parm
->v_action
]);
256 switch (parm
->v_action
) {
257 case TCA_VLAN_ACT_PUSH
:
258 case TCA_VLAN_ACT_MODIFY
:
259 if (tb
[TCA_VLAN_PUSH_VLAN_ID
]) {
260 val
= rta_getattr_u16(tb
[TCA_VLAN_PUSH_VLAN_ID
]);
261 print_uint(PRINT_ANY
, "id", " id %u", val
);
263 if (tb
[TCA_VLAN_PUSH_VLAN_PROTOCOL
]) {
266 proto
= rta_getattr_u16(tb
[TCA_VLAN_PUSH_VLAN_PROTOCOL
]);
267 print_string(PRINT_ANY
, "protocol", " protocol %s",
268 ll_proto_n2a(proto
, b1
, sizeof(b1
)));
270 if (tb
[TCA_VLAN_PUSH_VLAN_PRIORITY
]) {
271 val
= rta_getattr_u8(tb
[TCA_VLAN_PUSH_VLAN_PRIORITY
]);
272 print_uint(PRINT_ANY
, "priority", " priority %u", val
);
275 case TCA_VLAN_ACT_PUSH_ETH
:
276 if (tb
[TCA_VLAN_PUSH_ETH_DST
] &&
277 RTA_PAYLOAD(tb
[TCA_VLAN_PUSH_ETH_DST
]) == ETH_ALEN
) {
278 ll_addr_n2a(RTA_DATA(tb
[TCA_VLAN_PUSH_ETH_DST
]),
279 ETH_ALEN
, 0, b1
, sizeof(b1
));
280 print_string(PRINT_ANY
, "dst_mac", " dst_mac %s", b1
);
282 if (tb
[TCA_VLAN_PUSH_ETH_SRC
&&
283 RTA_PAYLOAD(tb
[TCA_VLAN_PUSH_ETH_SRC
]) == ETH_ALEN
]) {
284 ll_addr_n2a(RTA_DATA(tb
[TCA_VLAN_PUSH_ETH_SRC
]),
285 ETH_ALEN
, 0, b1
, sizeof(b1
));
286 print_string(PRINT_ANY
, "src_mac", " src_mac %s", b1
);
289 print_action_control(f
, " ", parm
->action
, "");
292 print_uint(PRINT_ANY
, "index", "\t index %u", parm
->index
);
293 print_int(PRINT_ANY
, "ref", " ref %d", parm
->refcnt
);
294 print_int(PRINT_ANY
, "bind", " bind %d", parm
->bindcnt
);
297 if (tb
[TCA_VLAN_TM
]) {
298 struct tcf_t
*tm
= RTA_DATA(tb
[TCA_VLAN_TM
]);
309 struct action_util vlan_action_util
= {
311 .parse_aopt
= parse_vlan
,
312 .print_aopt
= print_vlan
,