]> git.proxmox.com Git - mirror_iproute2.git/blame - bridge/vlan.c
bridge: code cleanup
[mirror_iproute2.git] / bridge / vlan.c
CommitLineData
9eff0e5c
VY
1#include <stdio.h>
2#include <stdlib.h>
3#include <unistd.h>
4#include <fcntl.h>
5#include <sys/socket.h>
6#include <net/if.h>
7#include <netinet/in.h>
8#include <linux/if_bridge.h>
9#include <linux/if_ether.h>
10#include <string.h>
11
12#include "libnetlink.h"
13#include "br_common.h"
14#include "utils.h"
15
9dca899b 16static unsigned int filter_index;
9eff0e5c
VY
17
18static void usage(void)
19{
20 fprintf(stderr, "Usage: bridge vlan { add | del } vid VLAN_ID dev DEV [ pvid] [ untagged ]\n");
21 fprintf(stderr, " [ self ] [ master ]\n");
22 fprintf(stderr, " bridge vlan { show } [ dev DEV ]\n");
23 exit(-1);
24}
25
26static int vlan_modify(int cmd, int argc, char **argv)
27{
28 struct {
df4b043f
SH
29 struct nlmsghdr n;
30 struct ifinfomsg ifm;
31 char buf[1024];
9eff0e5c
VY
32 } req;
33 char *d = NULL;
34 short vid = -1;
3ac0d36d 35 short vid_end = -1;
9eff0e5c
VY
36 struct rtattr *afspec;
37 struct bridge_vlan_info vinfo;
38 unsigned short flags = 0;
39
40 memset(&vinfo, 0, sizeof(vinfo));
41 memset(&req, 0, sizeof(req));
42
43 req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
44 req.n.nlmsg_flags = NLM_F_REQUEST;
45 req.n.nlmsg_type = cmd;
46 req.ifm.ifi_family = PF_BRIDGE;
47
48 while (argc > 0) {
49 if (strcmp(*argv, "dev") == 0) {
50 NEXT_ARG();
51 d = *argv;
52 } else if (strcmp(*argv, "vid") == 0) {
3ac0d36d 53 char *p;
df4b043f 54
9eff0e5c 55 NEXT_ARG();
3ac0d36d
RP
56 p = strchr(*argv, '-');
57 if (p) {
58 *p = '\0';
59 p++;
60 vid = atoi(*argv);
61 vid_end = atoi(p);
62 vinfo.flags |= BRIDGE_VLAN_INFO_RANGE_BEGIN;
63 } else {
64 vid = atoi(*argv);
65 }
9eff0e5c
VY
66 } else if (strcmp(*argv, "self") == 0) {
67 flags |= BRIDGE_FLAGS_SELF;
68 } else if (strcmp(*argv, "master") == 0) {
69 flags |= BRIDGE_FLAGS_MASTER;
70 } else if (strcmp(*argv, "pvid") == 0) {
71 vinfo.flags |= BRIDGE_VLAN_INFO_PVID;
72 } else if (strcmp(*argv, "untagged") == 0) {
73 vinfo.flags |= BRIDGE_VLAN_INFO_UNTAGGED;
74 } else {
75 if (matches(*argv, "help") == 0) {
76 NEXT_ARG();
77 }
78 }
79 argc--; argv++;
80 }
81
82 if (d == NULL || vid == -1) {
83 fprintf(stderr, "Device and VLAN ID are required arguments.\n");
42ecedd4 84 return -1;
9eff0e5c
VY
85 }
86
87 req.ifm.ifi_index = ll_name_to_index(d);
88 if (req.ifm.ifi_index == 0) {
89 fprintf(stderr, "Cannot find bridge device \"%s\"\n", d);
90 return -1;
91 }
92
93 if (vid >= 4096) {
94 fprintf(stderr, "Invalid VLAN ID \"%hu\"\n", vid);
95 return -1;
96 }
97
3ac0d36d
RP
98 if (vinfo.flags & BRIDGE_VLAN_INFO_RANGE_BEGIN) {
99 if (vid_end == -1 || vid_end >= 4096 || vid >= vid_end) {
100 fprintf(stderr, "Invalid VLAN range \"%hu-%hu\"\n",
101 vid, vid_end);
102 return -1;
103 }
104 if (vinfo.flags & BRIDGE_VLAN_INFO_PVID) {
105 fprintf(stderr,
106 "pvid cannot be configured for a vlan range\n");
107 return -1;
108 }
109 }
9eff0e5c
VY
110
111 afspec = addattr_nest(&req.n, sizeof(req), IFLA_AF_SPEC);
112
113 if (flags)
114 addattr16(&req.n, sizeof(req), IFLA_BRIDGE_FLAGS, flags);
115
3ac0d36d
RP
116 vinfo.vid = vid;
117 if (vid_end != -1) {
118 /* send vlan range start */
119 addattr_l(&req.n, sizeof(req), IFLA_BRIDGE_VLAN_INFO, &vinfo,
120 sizeof(vinfo));
121 vinfo.flags &= ~BRIDGE_VLAN_INFO_RANGE_BEGIN;
122
123 /* Now send the vlan range end */
124 vinfo.flags |= BRIDGE_VLAN_INFO_RANGE_END;
125 vinfo.vid = vid_end;
126 addattr_l(&req.n, sizeof(req), IFLA_BRIDGE_VLAN_INFO, &vinfo,
127 sizeof(vinfo));
128 } else {
129 addattr_l(&req.n, sizeof(req), IFLA_BRIDGE_VLAN_INFO, &vinfo,
130 sizeof(vinfo));
131 }
9eff0e5c
VY
132
133 addattr_nest_end(&req.n, afspec);
134
c079e121 135 if (rtnl_talk(&rth, &req.n, NULL, 0) < 0)
42ecedd4 136 return -1;
9eff0e5c
VY
137
138 return 0;
139}
140
141static int print_vlan(const struct sockaddr_nl *who,
142 struct nlmsghdr *n,
143 void *arg)
144{
145 FILE *fp = arg;
146 struct ifinfomsg *ifm = NLMSG_DATA(n);
147 int len = n->nlmsg_len;
df4b043f 148 struct rtattr *tb[IFLA_MAX+1];
9eff0e5c
VY
149
150 if (n->nlmsg_type != RTM_NEWLINK) {
151 fprintf(stderr, "Not RTM_NEWLINK: %08x %08x %08x\n",
152 n->nlmsg_len, n->nlmsg_type, n->nlmsg_flags);
153 return 0;
154 }
155
156 len -= NLMSG_LENGTH(sizeof(*ifm));
157 if (len < 0) {
158 fprintf(stderr, "BUG: wrong nlmsg len %d\n", len);
159 return -1;
160 }
161
162 if (ifm->ifi_family != AF_BRIDGE)
163 return 0;
164
165 if (filter_index && filter_index != ifm->ifi_index)
166 return 0;
167
168 parse_rtattr(tb, IFLA_MAX, IFLA_RTA(ifm), len);
169
170 /* if AF_SPEC isn't there, vlan table is not preset for this port */
171 if (!tb[IFLA_AF_SPEC]) {
172 fprintf(fp, "%s\tNone\n", ll_index_to_name(ifm->ifi_index));
173 return 0;
174 } else {
175 struct rtattr *i, *list = tb[IFLA_AF_SPEC];
176 int rem = RTA_PAYLOAD(list);
177
178 fprintf(fp, "%s", ll_index_to_name(ifm->ifi_index));
179 for (i = RTA_DATA(list); RTA_OK(i, rem); i = RTA_NEXT(i, rem)) {
180 struct bridge_vlan_info *vinfo;
181
182 if (i->rta_type != IFLA_BRIDGE_VLAN_INFO)
183 continue;
184
185 vinfo = RTA_DATA(i);
a2f7934d
RP
186 if (vinfo->flags & BRIDGE_VLAN_INFO_RANGE_END)
187 fprintf(fp, "-%hu", vinfo->vid);
188 else
189 fprintf(fp, "\t %hu", vinfo->vid);
190 if (vinfo->flags & BRIDGE_VLAN_INFO_RANGE_BEGIN)
191 continue;
9eff0e5c
VY
192 if (vinfo->flags & BRIDGE_VLAN_INFO_PVID)
193 fprintf(fp, " PVID");
194 if (vinfo->flags & BRIDGE_VLAN_INFO_UNTAGGED)
195 fprintf(fp, " Egress Untagged");
196 fprintf(fp, "\n");
197 }
198 }
199 fprintf(fp, "\n");
200 fflush(fp);
201 return 0;
202}
203
204static int vlan_show(int argc, char **argv)
205{
206 char *filter_dev = NULL;
207
208 while (argc > 0) {
209 if (strcmp(*argv, "dev") == 0) {
210 NEXT_ARG();
211 if (filter_dev)
212 duparg("dev", *argv);
213 filter_dev = *argv;
214 }
215 argc--; argv++;
216 }
217
218 if (filter_dev) {
219 if ((filter_index = if_nametoindex(filter_dev)) == 0) {
220 fprintf(stderr, "Cannot find device \"%s\"\n",
221 filter_dev);
222 return -1;
223 }
224 }
225
226 if (rtnl_wilddump_req_filter(&rth, PF_BRIDGE, RTM_GETLINK,
a2f7934d
RP
227 (compress_vlans ?
228 RTEXT_FILTER_BRVLAN_COMPRESSED :
229 RTEXT_FILTER_BRVLAN)) < 0) {
9eff0e5c
VY
230 perror("Cannont send dump request");
231 exit(1);
232 }
233
234 printf("port\tvlan ids\n");
235 if (rtnl_dump_filter(&rth, print_vlan, stdout) < 0) {
236 fprintf(stderr, "Dump ternminated\n");
237 exit(1);
238 }
239
240 return 0;
241}
242
243
244int do_vlan(int argc, char **argv)
245{
246 ll_init_map(&rth);
247
248 if (argc > 0) {
249 if (matches(*argv, "add") == 0)
250 return vlan_modify(RTM_SETLINK, argc-1, argv+1);
251 if (matches(*argv, "delete") == 0)
252 return vlan_modify(RTM_DELLINK, argc-1, argv+1);
253 if (matches(*argv, "show") == 0 ||
254 matches(*argv, "lst") == 0 ||
255 matches(*argv, "list") == 0)
256 return vlan_show(argc-1, argv+1);
257 if (matches(*argv, "help") == 0)
258 usage();
259 } else
260 return vlan_show(0, NULL);
261
262 fprintf(stderr, "Command \"%s\" is unknown, try \"bridge fdb help\".\n", *argv);
263 exit(-1);
264}