]> git.proxmox.com Git - mirror_iproute2.git/blame - ip/iplink_vlan.c
man: dcb-ets: Remove an unnecessary empty line
[mirror_iproute2.git] / ip / iplink_vlan.c
CommitLineData
5c302d51
PM
1/*
2 * iplink_vlan.c VLAN device support
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: Patrick McHardy <kaber@trash.net>
10 */
11
12#include <stdio.h>
13#include <stdlib.h>
14#include <string.h>
15#include <linux/if_vlan.h>
16
17#include "rt_names.h"
18#include "utils.h"
19#include "ip_common.h"
20
561e650e 21static void print_explain(FILE *f)
5c302d51 22{
561e650e 23 fprintf(f,
8b471354 24 "Usage: ... vlan id VLANID\n"
8589eb4e
MC
25 " [ protocol VLANPROTO ]\n"
26 " [ reorder_hdr { on | off } ]\n"
27 " [ gvrp { on | off } ]\n"
28 " [ mvrp { on | off } ]\n"
29 " [ loose_binding { on | off } ]\n"
30 " [ bridge_binding { on | off } ]\n"
31 " [ ingress-qos-map QOS-MAP ]\n"
32 " [ egress-qos-map QOS-MAP ]\n"
5c302d51
PM
33 "\n"
34 "VLANID := 0-4095\n"
6754e1d9 35 "VLANPROTO: [ 802.1Q | 802.1ad ]\n"
5c302d51
PM
36 "QOS-MAP := [ QOS-MAP ] QOS-MAPPING\n"
37 "QOS-MAPPING := FROM:TO\n"
38 );
39}
40
561e650e 41static void explain(void)
42{
43 print_explain(stderr);
44}
45
14645ec2 46static int on_off(const char *msg, const char *arg)
5c302d51 47{
14645ec2 48 fprintf(stderr, "Error: argument of \"%s\" must be \"on\" or \"off\", not \"%s\"\n", msg, arg);
5c302d51
PM
49 return -1;
50}
51
28e663ee
PM
52static int parse_qos_mapping(__u32 key, char *value, void *data)
53{
54 struct nlmsghdr *n = data;
55 struct ifla_vlan_qos_mapping m = {
56 .from = key,
57 };
58
59 if (get_u32(&m.to, value, 0))
60 return 1;
61
62 return addattr_l(n, 1024, IFLA_VLAN_QOS_MAPPING, &m, sizeof(m));
63}
64
5c302d51
PM
65static int vlan_parse_qos_map(int *argcp, char ***argvp, struct nlmsghdr *n,
66 int attrtype)
67{
5c302d51
PM
68 struct rtattr *tail;
69
c14f9d92 70 tail = addattr_nest(n, 1024, attrtype);
5c302d51 71
66a2d714 72 if (parse_mapping(argcp, argvp, false, &parse_qos_mapping, n))
28e663ee 73 return 1;
5c302d51 74
c14f9d92 75 addattr_nest_end(n, tail);
5c302d51
PM
76 return 0;
77}
78
79static int vlan_parse_opt(struct link_util *lu, int argc, char **argv,
80 struct nlmsghdr *n)
81{
82 struct ifla_vlan_flags flags = { 0 };
8fd8f6ed 83 __u16 id, proto;
5c302d51
PM
84
85 while (argc > 0) {
8fd8f6ed
PM
86 if (matches(*argv, "protocol") == 0) {
87 NEXT_ARG();
88 if (ll_proto_a2n(&proto, *argv))
89 invarg("protocol is invalid", *argv);
90 addattr_l(n, 1024, IFLA_VLAN_PROTOCOL, &proto, 2);
91 } else if (matches(*argv, "id") == 0) {
5c302d51
PM
92 NEXT_ARG();
93 if (get_u16(&id, *argv, 0))
94 invarg("id is invalid", *argv);
95 addattr_l(n, 1024, IFLA_VLAN_ID, &id, 2);
96 } else if (matches(*argv, "reorder_hdr") == 0) {
97 NEXT_ARG();
98 flags.mask |= VLAN_FLAG_REORDER_HDR;
99 if (strcmp(*argv, "on") == 0)
100 flags.flags |= VLAN_FLAG_REORDER_HDR;
101 else if (strcmp(*argv, "off") == 0)
102 flags.flags &= ~VLAN_FLAG_REORDER_HDR;
103 else
14645ec2 104 return on_off("reorder_hdr", *argv);
47420640
PM
105 } else if (matches(*argv, "gvrp") == 0) {
106 NEXT_ARG();
107 flags.mask |= VLAN_FLAG_GVRP;
108 if (strcmp(*argv, "on") == 0)
109 flags.flags |= VLAN_FLAG_GVRP;
110 else if (strcmp(*argv, "off") == 0)
111 flags.flags &= ~VLAN_FLAG_GVRP;
112 else
14645ec2 113 return on_off("gvrp", *argv);
4e9a6860
DW
114 } else if (matches(*argv, "mvrp") == 0) {
115 NEXT_ARG();
116 flags.mask |= VLAN_FLAG_MVRP;
117 if (strcmp(*argv, "on") == 0)
118 flags.flags |= VLAN_FLAG_MVRP;
119 else if (strcmp(*argv, "off") == 0)
120 flags.flags &= ~VLAN_FLAG_MVRP;
121 else
122 return on_off("mvrp", *argv);
2180b6b5
PM
123 } else if (matches(*argv, "loose_binding") == 0) {
124 NEXT_ARG();
125 flags.mask |= VLAN_FLAG_LOOSE_BINDING;
126 if (strcmp(*argv, "on") == 0)
127 flags.flags |= VLAN_FLAG_LOOSE_BINDING;
128 else if (strcmp(*argv, "off") == 0)
129 flags.flags &= ~VLAN_FLAG_LOOSE_BINDING;
130 else
14645ec2 131 return on_off("loose_binding", *argv);
3f2e457a
MM
132 } else if (matches(*argv, "bridge_binding") == 0) {
133 NEXT_ARG();
134 flags.mask |= VLAN_FLAG_BRIDGE_BINDING;
135 if (strcmp(*argv, "on") == 0)
136 flags.flags |= VLAN_FLAG_BRIDGE_BINDING;
137 else if (strcmp(*argv, "off") == 0)
138 flags.flags &= ~VLAN_FLAG_BRIDGE_BINDING;
139 else
140 return on_off("bridge_binding", *argv);
5c302d51
PM
141 } else if (matches(*argv, "ingress-qos-map") == 0) {
142 NEXT_ARG();
143 if (vlan_parse_qos_map(&argc, &argv, n,
144 IFLA_VLAN_INGRESS_QOS))
145 invarg("invalid ingress-qos-map", *argv);
146 continue;
147 } else if (matches(*argv, "egress-qos-map") == 0) {
148 NEXT_ARG();
149 if (vlan_parse_qos_map(&argc, &argv, n,
150 IFLA_VLAN_EGRESS_QOS))
151 invarg("invalid egress-qos-map", *argv);
152 continue;
153 } else if (matches(*argv, "help") == 0) {
154 explain();
155 return -1;
156 } else {
14645ec2 157 fprintf(stderr, "vlan: unknown command \"%s\"?\n", *argv);
5c302d51
PM
158 explain();
159 return -1;
160 }
161 argc--, argv++;
162 }
163
164 if (flags.mask)
165 addattr_l(n, 1024, IFLA_VLAN_FLAGS, &flags, sizeof(flags));
166
167 return 0;
168}
169
43bc20ae
JF
170static void vlan_print_map(FILE *f,
171 const char *name_json,
172 const char *name_fp,
173 struct rtattr *attr)
5c302d51
PM
174{
175 struct ifla_vlan_qos_mapping *m;
176 struct rtattr *i;
177 int rem;
178
43bc20ae 179 open_json_array(PRINT_JSON, name_json);
970db267
VD
180 print_nl();
181 print_string(PRINT_FP, NULL, " %s { ", name_fp);
5c302d51
PM
182
183 rem = RTA_PAYLOAD(attr);
184 for (i = RTA_DATA(attr); RTA_OK(i, rem); i = RTA_NEXT(i, rem)) {
185 m = RTA_DATA(i);
43bc20ae
JF
186
187 if (is_json_context()) {
188 open_json_object(NULL);
189 print_uint(PRINT_JSON, "from", NULL, m->from);
190 print_uint(PRINT_JSON, "to", NULL, m->to);
191 close_json_object();
192 } else {
193 fprintf(f, "%u:%u ", m->from, m->to);
194 }
5c302d51 195 }
43bc20ae
JF
196
197 close_json_array(PRINT_JSON, NULL);
198 print_string(PRINT_FP, NULL, "%s ", "}");
5c302d51
PM
199}
200
201static void vlan_print_flags(FILE *fp, __u32 flags)
202{
43bc20ae
JF
203 open_json_array(PRINT_ANY, is_json_context() ? "flags" : "<");
204#define _PF(f) if (flags & VLAN_FLAG_##f) { \
205 flags &= ~VLAN_FLAG_##f; \
206 print_string(PRINT_ANY, NULL, flags ? "%s," : "%s", #f); \
207 }
5c302d51 208 _PF(REORDER_HDR);
47420640 209 _PF(GVRP);
4e9a6860 210 _PF(MVRP);
2180b6b5 211 _PF(LOOSE_BINDING);
3f2e457a 212 _PF(BRIDGE_BINDING);
5c302d51
PM
213#undef _PF
214 if (flags)
43bc20ae
JF
215 print_hex(PRINT_ANY, NULL, "%x", flags);
216 close_json_array(PRINT_ANY, "> ");
5c302d51
PM
217}
218
219static void vlan_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
220{
221 struct ifla_vlan_flags *flags;
56f5daac 222
8fd8f6ed
PM
223 SPRINT_BUF(b1);
224
5c302d51
PM
225 if (!tb)
226 return;
227
8fd8f6ed
PM
228 if (tb[IFLA_VLAN_PROTOCOL] &&
229 RTA_PAYLOAD(tb[IFLA_VLAN_PROTOCOL]) < sizeof(__u16))
230 return;
5c302d51
PM
231 if (!tb[IFLA_VLAN_ID] ||
232 RTA_PAYLOAD(tb[IFLA_VLAN_ID]) < sizeof(__u16))
233 return;
234
8fd8f6ed 235 if (tb[IFLA_VLAN_PROTOCOL])
43bc20ae
JF
236 print_string(PRINT_ANY,
237 "protocol",
238 "protocol %s ",
239 ll_proto_n2a(
240 rta_getattr_u16(tb[IFLA_VLAN_PROTOCOL]),
8fd8f6ed
PM
241 b1, sizeof(b1)));
242 else
43bc20ae 243 print_string(PRINT_ANY, "protocol", "protocol %s ", "802.1q");
8fd8f6ed 244
43bc20ae
JF
245 print_uint(PRINT_ANY,
246 "id",
247 "id %u ",
248 rta_getattr_u16(tb[IFLA_VLAN_ID]));
5c302d51
PM
249
250 if (tb[IFLA_VLAN_FLAGS]) {
251 if (RTA_PAYLOAD(tb[IFLA_VLAN_FLAGS]) < sizeof(*flags))
252 return;
253 flags = RTA_DATA(tb[IFLA_VLAN_FLAGS]);
254 vlan_print_flags(f, flags->flags);
255 }
256 if (tb[IFLA_VLAN_INGRESS_QOS])
43bc20ae
JF
257 vlan_print_map(f,
258 "ingress_qos",
259 "ingress-qos-map",
260 tb[IFLA_VLAN_INGRESS_QOS]);
5c302d51 261 if (tb[IFLA_VLAN_EGRESS_QOS])
43bc20ae
JF
262 vlan_print_map(f,
263 "egress_qos",
264 "egress-qos-map",
265 tb[IFLA_VLAN_EGRESS_QOS]);
5c302d51
PM
266}
267
561e650e 268static void vlan_print_help(struct link_util *lu, int argc, char **argv,
43bc20ae 269 FILE *f)
561e650e 270{
271 print_explain(f);
272}
273
5c302d51
PM
274struct link_util vlan_link_util = {
275 .id = "vlan",
276 .maxattr = IFLA_VLAN_MAX,
277 .parse_opt = vlan_parse_opt,
278 .print_opt = vlan_print_opt,
561e650e 279 .print_help = vlan_print_help,
5c302d51 280};