]> git.proxmox.com Git - mirror_iproute2.git/blob - ip/iplink_vlan.c
ip: allow to specify mode for sit tunnels
[mirror_iproute2.git] / ip / iplink_vlan.c
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
21 static void explain(void)
22 {
23 fprintf(stderr,
24 "Usage: ... vlan [ protocol VLANPROTO ] id VLANID"
25 " [ FLAG-LIST ]\n"
26 " [ ingress-qos-map QOS-MAP ] [ egress-qos-map QOS-MAP ]\n"
27 "\n"
28 "VLANPROTO: [ 802.1Q / 802.1ad ]\n"
29 "VLANID := 0-4095\n"
30 "FLAG-LIST := [ FLAG-LIST ] FLAG\n"
31 "FLAG := [ reorder_hdr { on | off } ] [ gvrp { on | off } ] [ mvrp { on | off } ]\n"
32 " [ loose_binding { on | off } ]\n"
33 "QOS-MAP := [ QOS-MAP ] QOS-MAPPING\n"
34 "QOS-MAPPING := FROM:TO\n"
35 );
36 }
37
38 static int on_off(const char *msg, const char *arg)
39 {
40 fprintf(stderr, "Error: argument of \"%s\" must be \"on\" or \"off\", not \"%s\"\n", msg, arg);
41 return -1;
42 }
43
44 static int vlan_parse_qos_map(int *argcp, char ***argvp, struct nlmsghdr *n,
45 int attrtype)
46 {
47 int argc = *argcp;
48 char **argv = *argvp;
49 struct ifla_vlan_qos_mapping m;
50 struct rtattr *tail;
51
52 tail = NLMSG_TAIL(n);
53 addattr_l(n, 1024, attrtype, NULL, 0);
54
55 while (argc > 0) {
56 char *colon = strchr(*argv, ':');
57
58 if (!colon)
59 break;
60 *colon = '\0';
61
62 if (get_u32(&m.from, *argv, 0))
63 return 1;
64 if (get_u32(&m.to, colon + 1, 0))
65 return 1;
66 argc--, argv++;
67
68 addattr_l(n, 1024, IFLA_VLAN_QOS_MAPPING, &m, sizeof(m));
69 }
70
71 tail->rta_len = (void *) NLMSG_TAIL(n) - (void *)tail;
72
73 *argcp = argc;
74 *argvp = argv;
75 return 0;
76 }
77
78 static int vlan_parse_opt(struct link_util *lu, int argc, char **argv,
79 struct nlmsghdr *n)
80 {
81 struct ifla_vlan_flags flags = { 0 };
82 __u16 id, proto;
83
84 while (argc > 0) {
85 if (matches(*argv, "protocol") == 0) {
86 NEXT_ARG();
87 if (ll_proto_a2n(&proto, *argv))
88 invarg("protocol is invalid", *argv);
89 addattr_l(n, 1024, IFLA_VLAN_PROTOCOL, &proto, 2);
90 } else if (matches(*argv, "id") == 0) {
91 NEXT_ARG();
92 if (get_u16(&id, *argv, 0))
93 invarg("id is invalid", *argv);
94 addattr_l(n, 1024, IFLA_VLAN_ID, &id, 2);
95 } else if (matches(*argv, "reorder_hdr") == 0) {
96 NEXT_ARG();
97 flags.mask |= VLAN_FLAG_REORDER_HDR;
98 if (strcmp(*argv, "on") == 0)
99 flags.flags |= VLAN_FLAG_REORDER_HDR;
100 else if (strcmp(*argv, "off") == 0)
101 flags.flags &= ~VLAN_FLAG_REORDER_HDR;
102 else
103 return on_off("reorder_hdr", *argv);
104 } else if (matches(*argv, "gvrp") == 0) {
105 NEXT_ARG();
106 flags.mask |= VLAN_FLAG_GVRP;
107 if (strcmp(*argv, "on") == 0)
108 flags.flags |= VLAN_FLAG_GVRP;
109 else if (strcmp(*argv, "off") == 0)
110 flags.flags &= ~VLAN_FLAG_GVRP;
111 else
112 return on_off("gvrp", *argv);
113 } else if (matches(*argv, "mvrp") == 0) {
114 NEXT_ARG();
115 flags.mask |= VLAN_FLAG_MVRP;
116 if (strcmp(*argv, "on") == 0)
117 flags.flags |= VLAN_FLAG_MVRP;
118 else if (strcmp(*argv, "off") == 0)
119 flags.flags &= ~VLAN_FLAG_MVRP;
120 else
121 return on_off("mvrp", *argv);
122 } else if (matches(*argv, "loose_binding") == 0) {
123 NEXT_ARG();
124 flags.mask |= VLAN_FLAG_LOOSE_BINDING;
125 if (strcmp(*argv, "on") == 0)
126 flags.flags |= VLAN_FLAG_LOOSE_BINDING;
127 else if (strcmp(*argv, "off") == 0)
128 flags.flags &= ~VLAN_FLAG_LOOSE_BINDING;
129 else
130 return on_off("loose_binding", *argv);
131 } else if (matches(*argv, "ingress-qos-map") == 0) {
132 NEXT_ARG();
133 if (vlan_parse_qos_map(&argc, &argv, n,
134 IFLA_VLAN_INGRESS_QOS))
135 invarg("invalid ingress-qos-map", *argv);
136 continue;
137 } else if (matches(*argv, "egress-qos-map") == 0) {
138 NEXT_ARG();
139 if (vlan_parse_qos_map(&argc, &argv, n,
140 IFLA_VLAN_EGRESS_QOS))
141 invarg("invalid egress-qos-map", *argv);
142 continue;
143 } else if (matches(*argv, "help") == 0) {
144 explain();
145 return -1;
146 } else {
147 fprintf(stderr, "vlan: unknown command \"%s\"?\n", *argv);
148 explain();
149 return -1;
150 }
151 argc--, argv++;
152 }
153
154 if (flags.mask)
155 addattr_l(n, 1024, IFLA_VLAN_FLAGS, &flags, sizeof(flags));
156
157 return 0;
158 }
159
160 static void vlan_print_map(FILE *f, char *name, struct rtattr *attr)
161 {
162 struct ifla_vlan_qos_mapping *m;
163 struct rtattr *i;
164 int rem;
165
166 fprintf(f, "\n %s { ", name);
167
168 rem = RTA_PAYLOAD(attr);
169 for (i = RTA_DATA(attr); RTA_OK(i, rem); i = RTA_NEXT(i, rem)) {
170 m = RTA_DATA(i);
171 fprintf(f, "%u:%u ", m->from, m->to);
172 }
173 fprintf(f, "} ");
174 }
175
176 static void vlan_print_flags(FILE *fp, __u32 flags)
177 {
178 fprintf(fp, "<");
179 #define _PF(f) if (flags & VLAN_FLAG_##f) { \
180 flags &= ~ VLAN_FLAG_##f; \
181 fprintf(fp, #f "%s", flags ? "," : ""); \
182 }
183 _PF(REORDER_HDR);
184 _PF(GVRP);
185 _PF(MVRP);
186 _PF(LOOSE_BINDING);
187 #undef _PF
188 if (flags)
189 fprintf(fp, "%x", flags);
190 fprintf(fp, "> ");
191 }
192
193 static void vlan_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
194 {
195 struct ifla_vlan_flags *flags;
196 SPRINT_BUF(b1);
197
198 if (!tb)
199 return;
200
201 if (tb[IFLA_VLAN_PROTOCOL] &&
202 RTA_PAYLOAD(tb[IFLA_VLAN_PROTOCOL]) < sizeof(__u16))
203 return;
204 if (!tb[IFLA_VLAN_ID] ||
205 RTA_PAYLOAD(tb[IFLA_VLAN_ID]) < sizeof(__u16))
206 return;
207
208 if (tb[IFLA_VLAN_PROTOCOL])
209 fprintf(f, "protocol %s ",
210 ll_proto_n2a(rta_getattr_u16(tb[IFLA_VLAN_PROTOCOL]),
211 b1, sizeof(b1)));
212 else
213 fprintf(f, "protocol 802.1q ");
214
215 fprintf(f, "id %u ", rta_getattr_u16(tb[IFLA_VLAN_ID]));
216
217 if (tb[IFLA_VLAN_FLAGS]) {
218 if (RTA_PAYLOAD(tb[IFLA_VLAN_FLAGS]) < sizeof(*flags))
219 return;
220 flags = RTA_DATA(tb[IFLA_VLAN_FLAGS]);
221 vlan_print_flags(f, flags->flags);
222 }
223 if (tb[IFLA_VLAN_INGRESS_QOS])
224 vlan_print_map(f, "ingress-qos-map", tb[IFLA_VLAN_INGRESS_QOS]);
225 if (tb[IFLA_VLAN_EGRESS_QOS])
226 vlan_print_map(f, "egress-qos-map", tb[IFLA_VLAN_EGRESS_QOS]);
227 }
228
229 struct link_util vlan_link_util = {
230 .id = "vlan",
231 .maxattr = IFLA_VLAN_MAX,
232 .parse_opt = vlan_parse_opt,
233 .print_opt = vlan_print_opt,
234 };