]> git.proxmox.com Git - mirror_iproute2.git/blame - tc/m_vlan.c
tc: util: No need for action_n2a() to be reentrant
[mirror_iproute2.git] / tc / m_vlan.c
CommitLineData
8b1c0216
JP
1/*
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");
51011dac 25 fprintf(stderr, " vlan push [ protocol VLANPROTO ] id VLANID [CONTROL]\n");
8b1c0216
JP
26 fprintf(stderr, " VLANPROTO is one of 802.1Q or 802.1AD\n");
27 fprintf(stderr, " with default: 802.1Q\n");
51011dac 28 fprintf(stderr, " CONTROL := reclassify | pipe | drop | continue | pass\n");
8b1c0216
JP
29}
30
31static void usage(void)
32{
33 explain();
34 exit(-1);
35}
36
37static int parse_vlan(struct action_util *a, int *argc_p, char ***argv_p,
38 int tca_id, struct nlmsghdr *n)
39{
40 int argc = *argc_p;
41 char **argv = *argv_p;
42 struct rtattr *tail;
43 int action = 0;
44 __u16 id;
45 int id_set = 0;
46 __u16 proto;
47 int proto_set = 0;
48 struct tc_vlan parm = { 0 };
49
50 if (matches(*argv, "vlan") != 0)
51 return -1;
52
53 NEXT_ARG();
54
55 while (argc > 0) {
56 if (matches(*argv, "pop") == 0) {
57 if (action) {
58 fprintf(stderr, "unexpected \"%s\" - action already specified\n",
59 *argv);
60 explain();
61 return -1;
62 }
63 action = TCA_VLAN_ACT_POP;
64 } else if (matches(*argv, "push") == 0) {
65 if (action) {
66 fprintf(stderr, "unexpected \"%s\" - action already specified\n",
67 *argv);
68 explain();
69 return -1;
70 }
71 action = TCA_VLAN_ACT_PUSH;
72 } else if (matches(*argv, "id") == 0) {
73 if (action != TCA_VLAN_ACT_PUSH) {
74 fprintf(stderr, "\"%s\" is only valid for push\n",
75 *argv);
76 explain();
77 return -1;
78 }
79 NEXT_ARG();
80 if (get_u16(&id, *argv, 0))
81 invarg("id is invalid", *argv);
82 id_set = 1;
83 } else if (matches(*argv, "protocol") == 0) {
84 if (action != TCA_VLAN_ACT_PUSH) {
85 fprintf(stderr, "\"%s\" is only valid for push\n",
86 *argv);
87 explain();
88 return -1;
89 }
90 NEXT_ARG();
91 if (ll_proto_a2n(&proto, *argv))
92 invarg("protocol is invalid", *argv);
93 proto_set = 1;
94 } else if (matches(*argv, "help") == 0) {
95 usage();
96 } else {
97 break;
98 }
99 argc--;
100 argv++;
101 }
102
103 parm.action = TC_ACT_PIPE;
69f5aff6
PS
104 if (argc && !action_a2n(*argv, &parm.action, false))
105 NEXT_ARG_FWD();
8b1c0216
JP
106
107 if (argc) {
108 if (matches(*argv, "index") == 0) {
109 NEXT_ARG();
110 if (get_u32(&parm.index, *argv, 10)) {
111 fprintf(stderr, "vlan: Illegal \"index\"\n");
112 return -1;
113 }
114 argc--;
115 argv++;
116 }
117 }
118
119 if (action == TCA_VLAN_ACT_PUSH && !id_set) {
120 fprintf(stderr, "id needs to be set for push\n");
121 explain();
122 return -1;
123 }
124
125 parm.v_action = action;
126 tail = NLMSG_TAIL(n);
127 addattr_l(n, MAX_MSG, tca_id, NULL, 0);
128 addattr_l(n, MAX_MSG, TCA_VLAN_PARMS, &parm, sizeof(parm));
129 if (id_set)
130 addattr_l(n, MAX_MSG, TCA_VLAN_PUSH_VLAN_ID, &id, 2);
131 if (proto_set) {
132 if (proto != htons(ETH_P_8021Q) &&
133 proto != htons(ETH_P_8021AD)) {
134 fprintf(stderr, "protocol not supported\n");
135 explain();
136 return -1;
137 }
138
139 addattr_l(n, MAX_MSG, TCA_VLAN_PUSH_VLAN_PROTOCOL, &proto, 2);
140 }
141 tail->rta_len = (char *)NLMSG_TAIL(n) - (char *)tail;
142
143 *argc_p = argc;
144 *argv_p = argv;
145 return 0;
146}
147
148static int print_vlan(struct action_util *au, FILE *f, struct rtattr *arg)
149{
150 SPRINT_BUF(b1);
151 struct rtattr *tb[TCA_VLAN_MAX + 1];
152 __u16 val;
153 struct tc_vlan *parm;
154
155 if (arg == NULL)
156 return -1;
157
158 parse_rtattr_nested(tb, TCA_VLAN_MAX, arg);
159
160 if (!tb[TCA_VLAN_PARMS]) {
161 fprintf(f, "[NULL vlan parameters]");
162 return -1;
163 }
164 parm = RTA_DATA(tb[TCA_VLAN_PARMS]);
165
166 fprintf(f, " vlan");
167
32a121cb 168 switch (parm->v_action) {
8b1c0216
JP
169 case TCA_VLAN_ACT_POP:
170 fprintf(f, " pop");
171 break;
172 case TCA_VLAN_ACT_PUSH:
173 fprintf(f, " push");
174 if (tb[TCA_VLAN_PUSH_VLAN_ID]) {
175 val = rta_getattr_u16(tb[TCA_VLAN_PUSH_VLAN_ID]);
176 fprintf(f, " id %u", val);
177 }
178 if (tb[TCA_VLAN_PUSH_VLAN_PROTOCOL]) {
179 fprintf(f, " protocol %s",
180 ll_proto_n2a(rta_getattr_u16(tb[TCA_VLAN_PUSH_VLAN_PROTOCOL]),
181 b1, sizeof(b1)));
182 }
183 break;
184 }
70932006 185 fprintf(f, " %s", action_n2a(parm->action));
8b1c0216
JP
186
187 fprintf(f, "\n\t index %d ref %d bind %d", parm->index, parm->refcnt,
188 parm->bindcnt);
189
190 if (show_stats) {
191 if (tb[TCA_VLAN_TM]) {
192 struct tcf_t *tm = RTA_DATA(tb[TCA_VLAN_TM]);
32a121cb 193
8b1c0216
JP
194 print_tm(f, tm);
195 }
196 }
197
198 fprintf(f, "\n ");
199
200 return 0;
201}
202
203struct action_util vlan_action_util = {
204 .id = "vlan",
205 .parse_aopt = parse_vlan,
206 .print_aopt = print_vlan,
207};