blob: 32db5ed5b107b1ffec2812eaf3a638d36356fdb0 [file] [log] [blame]
Jiri Pirko8b1c0212014-11-21 12:31:30 +01001/*
2 * m_vlan.c vlan manipulation module
3 *
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.
8 *
9 * Authors: Jiri Pirko <jiri@resnulli.us>
10 */
11
12#include <stdio.h>
13#include <stdlib.h>
14#include <unistd.h>
15#include <string.h>
16#include <linux/if_ether.h>
17#include "utils.h"
18#include "rt_names.h"
19#include "tc_util.h"
20#include <linux/tc_act/tc_vlan.h>
21
22static void explain(void)
23{
24 fprintf(stderr, "Usage: vlan pop\n");
25 fprintf(stderr, " vlan push [ protocol VLANPROTO ] id VLANID\n");
26 fprintf(stderr, " VLANPROTO is one of 802.1Q or 802.1AD\n");
27 fprintf(stderr, " with default: 802.1Q\n");
28}
29
30static void usage(void)
31{
32 explain();
33 exit(-1);
34}
35
36static int parse_vlan(struct action_util *a, int *argc_p, char ***argv_p,
37 int tca_id, struct nlmsghdr *n)
38{
39 int argc = *argc_p;
40 char **argv = *argv_p;
41 struct rtattr *tail;
42 int action = 0;
43 __u16 id;
44 int id_set = 0;
45 __u16 proto;
46 int proto_set = 0;
47 struct tc_vlan parm = { 0 };
48
49 if (matches(*argv, "vlan") != 0)
50 return -1;
51
52 NEXT_ARG();
53
54 while (argc > 0) {
55 if (matches(*argv, "pop") == 0) {
56 if (action) {
57 fprintf(stderr, "unexpected \"%s\" - action already specified\n",
58 *argv);
59 explain();
60 return -1;
61 }
62 action = TCA_VLAN_ACT_POP;
63 } else if (matches(*argv, "push") == 0) {
64 if (action) {
65 fprintf(stderr, "unexpected \"%s\" - action already specified\n",
66 *argv);
67 explain();
68 return -1;
69 }
70 action = TCA_VLAN_ACT_PUSH;
71 } else if (matches(*argv, "id") == 0) {
72 if (action != TCA_VLAN_ACT_PUSH) {
73 fprintf(stderr, "\"%s\" is only valid for push\n",
74 *argv);
75 explain();
76 return -1;
77 }
78 NEXT_ARG();
79 if (get_u16(&id, *argv, 0))
80 invarg("id is invalid", *argv);
81 id_set = 1;
82 } else if (matches(*argv, "protocol") == 0) {
83 if (action != TCA_VLAN_ACT_PUSH) {
84 fprintf(stderr, "\"%s\" is only valid for push\n",
85 *argv);
86 explain();
87 return -1;
88 }
89 NEXT_ARG();
90 if (ll_proto_a2n(&proto, *argv))
91 invarg("protocol is invalid", *argv);
92 proto_set = 1;
93 } else if (matches(*argv, "help") == 0) {
94 usage();
95 } else {
96 break;
97 }
98 argc--;
99 argv++;
100 }
101
102 parm.action = TC_ACT_PIPE;
103 if (argc) {
104 if (matches(*argv, "reclassify") == 0) {
105 parm.action = TC_ACT_RECLASSIFY;
Jamal Hadi Salim564663b2015-01-11 09:31:30 -0500106 argc--;
107 argv++;
Jiri Pirko8b1c0212014-11-21 12:31:30 +0100108 } else if (matches(*argv, "pipe") == 0) {
109 parm.action = TC_ACT_PIPE;
Jamal Hadi Salim564663b2015-01-11 09:31:30 -0500110 argc--;
111 argv++;
Jiri Pirko8b1c0212014-11-21 12:31:30 +0100112 } else if (matches(*argv, "drop") == 0 ||
113 matches(*argv, "shot") == 0) {
114 parm.action = TC_ACT_SHOT;
Jamal Hadi Salim564663b2015-01-11 09:31:30 -0500115 argc--;
116 argv++;
Jiri Pirko8b1c0212014-11-21 12:31:30 +0100117 } else if (matches(*argv, "continue") == 0) {
118 parm.action = TC_ACT_UNSPEC;
Jamal Hadi Salim564663b2015-01-11 09:31:30 -0500119 argc--;
120 argv++;
Jiri Pirko8b1c0212014-11-21 12:31:30 +0100121 } else if (matches(*argv, "pass") == 0) {
122 parm.action = TC_ACT_OK;
Jamal Hadi Salim564663b2015-01-11 09:31:30 -0500123 argc--;
124 argv++;
Jiri Pirko8b1c0212014-11-21 12:31:30 +0100125 }
126 }
127
128 if (argc) {
129 if (matches(*argv, "index") == 0) {
130 NEXT_ARG();
131 if (get_u32(&parm.index, *argv, 10)) {
132 fprintf(stderr, "vlan: Illegal \"index\"\n");
133 return -1;
134 }
135 argc--;
136 argv++;
137 }
138 }
139
140 if (action == TCA_VLAN_ACT_PUSH && !id_set) {
141 fprintf(stderr, "id needs to be set for push\n");
142 explain();
143 return -1;
144 }
145
146 parm.v_action = action;
147 tail = NLMSG_TAIL(n);
148 addattr_l(n, MAX_MSG, tca_id, NULL, 0);
149 addattr_l(n, MAX_MSG, TCA_VLAN_PARMS, &parm, sizeof(parm));
150 if (id_set)
151 addattr_l(n, MAX_MSG, TCA_VLAN_PUSH_VLAN_ID, &id, 2);
152 if (proto_set) {
153 if (proto != htons(ETH_P_8021Q) &&
154 proto != htons(ETH_P_8021AD)) {
155 fprintf(stderr, "protocol not supported\n");
156 explain();
157 return -1;
158 }
159
160 addattr_l(n, MAX_MSG, TCA_VLAN_PUSH_VLAN_PROTOCOL, &proto, 2);
161 }
162 tail->rta_len = (char *)NLMSG_TAIL(n) - (char *)tail;
163
164 *argc_p = argc;
165 *argv_p = argv;
166 return 0;
167}
168
169static int print_vlan(struct action_util *au, FILE *f, struct rtattr *arg)
170{
171 SPRINT_BUF(b1);
172 struct rtattr *tb[TCA_VLAN_MAX + 1];
173 __u16 val;
174 struct tc_vlan *parm;
175
176 if (arg == NULL)
177 return -1;
178
179 parse_rtattr_nested(tb, TCA_VLAN_MAX, arg);
180
181 if (!tb[TCA_VLAN_PARMS]) {
182 fprintf(f, "[NULL vlan parameters]");
183 return -1;
184 }
185 parm = RTA_DATA(tb[TCA_VLAN_PARMS]);
186
187 fprintf(f, " vlan");
188
189 switch(parm->v_action) {
190 case TCA_VLAN_ACT_POP:
191 fprintf(f, " pop");
192 break;
193 case TCA_VLAN_ACT_PUSH:
194 fprintf(f, " push");
195 if (tb[TCA_VLAN_PUSH_VLAN_ID]) {
196 val = rta_getattr_u16(tb[TCA_VLAN_PUSH_VLAN_ID]);
197 fprintf(f, " id %u", val);
198 }
199 if (tb[TCA_VLAN_PUSH_VLAN_PROTOCOL]) {
200 fprintf(f, " protocol %s",
201 ll_proto_n2a(rta_getattr_u16(tb[TCA_VLAN_PUSH_VLAN_PROTOCOL]),
202 b1, sizeof(b1)));
203 }
204 break;
205 }
Jamal Hadi Salim564663b2015-01-11 09:31:30 -0500206 fprintf(f, " %s", action_n2a(parm->action, b1, sizeof (b1)));
Jiri Pirko8b1c0212014-11-21 12:31:30 +0100207
208 fprintf(f, "\n\t index %d ref %d bind %d", parm->index, parm->refcnt,
209 parm->bindcnt);
210
211 if (show_stats) {
212 if (tb[TCA_VLAN_TM]) {
213 struct tcf_t *tm = RTA_DATA(tb[TCA_VLAN_TM]);
214 print_tm(f, tm);
215 }
216 }
217
218 fprintf(f, "\n ");
219
220 return 0;
221}
222
223struct action_util vlan_action_util = {
224 .id = "vlan",
225 .parse_aopt = parse_vlan,
226 .print_aopt = print_vlan,
227};