5 #include <sys/socket.h>
7 #include <netinet/in.h>
8 #include <linux/if_bridge.h>
9 #include <linux/if_ether.h>
12 #include "libnetlink.h"
13 #include "br_common.h"
16 static unsigned int filter_index
, filter_vlan
;
18 static void usage(void)
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 ] [ vid VLAN_ID ]\n");
26 static int vlan_modify(int cmd
, int argc
, char **argv
)
36 struct rtattr
*afspec
;
37 struct bridge_vlan_info vinfo
;
38 unsigned short flags
= 0;
40 memset(&vinfo
, 0, sizeof(vinfo
));
41 memset(&req
, 0, sizeof(req
));
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
;
49 if (strcmp(*argv
, "dev") == 0) {
52 } else if (strcmp(*argv
, "vid") == 0) {
56 p
= strchr(*argv
, '-');
62 vinfo
.flags
|= BRIDGE_VLAN_INFO_RANGE_BEGIN
;
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
;
75 if (matches(*argv
, "help") == 0) {
82 if (d
== NULL
|| vid
== -1) {
83 fprintf(stderr
, "Device and VLAN ID are required arguments.\n");
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
);
94 fprintf(stderr
, "Invalid VLAN ID \"%hu\"\n", vid
);
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",
104 if (vinfo
.flags
& BRIDGE_VLAN_INFO_PVID
) {
106 "pvid cannot be configured for a vlan range\n");
111 afspec
= addattr_nest(&req
.n
, sizeof(req
), IFLA_AF_SPEC
);
114 addattr16(&req
.n
, sizeof(req
), IFLA_BRIDGE_FLAGS
, flags
);
118 /* send vlan range start */
119 addattr_l(&req
.n
, sizeof(req
), IFLA_BRIDGE_VLAN_INFO
, &vinfo
,
121 vinfo
.flags
&= ~BRIDGE_VLAN_INFO_RANGE_BEGIN
;
123 /* Now send the vlan range end */
124 vinfo
.flags
|= BRIDGE_VLAN_INFO_RANGE_END
;
126 addattr_l(&req
.n
, sizeof(req
), IFLA_BRIDGE_VLAN_INFO
, &vinfo
,
129 addattr_l(&req
.n
, sizeof(req
), IFLA_BRIDGE_VLAN_INFO
, &vinfo
,
133 addattr_nest_end(&req
.n
, afspec
);
135 if (rtnl_talk(&rth
, &req
.n
, NULL
, 0) < 0)
141 /* In order to use this function for both filtering and non-filtering cases
142 * we need to make it a tristate:
143 * return -1 - if filtering we've gone over so don't continue
144 * return 0 - skip entry and continue (applies to range start or to entries
145 * which are less than filter_vlan)
146 * return 1 - print the entry and continue
148 static int filter_vlan_check(struct bridge_vlan_info
*vinfo
)
150 /* if we're filtering we should stop on the first greater entry */
151 if (filter_vlan
&& vinfo
->vid
> filter_vlan
&&
152 !(vinfo
->flags
& BRIDGE_VLAN_INFO_RANGE_END
))
154 if ((vinfo
->flags
& BRIDGE_VLAN_INFO_RANGE_BEGIN
) ||
155 vinfo
->vid
< filter_vlan
)
161 static int print_vlan(const struct sockaddr_nl
*who
,
166 struct ifinfomsg
*ifm
= NLMSG_DATA(n
);
167 int len
= n
->nlmsg_len
;
168 struct rtattr
*tb
[IFLA_MAX
+1];
170 if (n
->nlmsg_type
!= RTM_NEWLINK
) {
171 fprintf(stderr
, "Not RTM_NEWLINK: %08x %08x %08x\n",
172 n
->nlmsg_len
, n
->nlmsg_type
, n
->nlmsg_flags
);
176 len
-= NLMSG_LENGTH(sizeof(*ifm
));
178 fprintf(stderr
, "BUG: wrong nlmsg len %d\n", len
);
182 if (ifm
->ifi_family
!= AF_BRIDGE
)
185 if (filter_index
&& filter_index
!= ifm
->ifi_index
)
188 parse_rtattr(tb
, IFLA_MAX
, IFLA_RTA(ifm
), len
);
190 /* if AF_SPEC isn't there, vlan table is not preset for this port */
191 if (!tb
[IFLA_AF_SPEC
]) {
193 fprintf(fp
, "%s\tNone\n",
194 ll_index_to_name(ifm
->ifi_index
));
197 struct rtattr
*i
, *list
= tb
[IFLA_AF_SPEC
];
198 int rem
= RTA_PAYLOAD(list
);
199 __u16 last_vid_start
= 0;
202 fprintf(fp
, "%s", ll_index_to_name(ifm
->ifi_index
));
203 for (i
= RTA_DATA(list
); RTA_OK(i
, rem
); i
= RTA_NEXT(i
, rem
)) {
204 struct bridge_vlan_info
*vinfo
;
207 if (i
->rta_type
!= IFLA_BRIDGE_VLAN_INFO
)
212 if (!(vinfo
->flags
& BRIDGE_VLAN_INFO_RANGE_END
))
213 last_vid_start
= vinfo
->vid
;
214 vcheck_ret
= filter_vlan_check(vinfo
);
215 if (vcheck_ret
== -1)
217 else if (vcheck_ret
== 0)
222 ll_index_to_name(ifm
->ifi_index
));
223 fprintf(fp
, "\t %hu", last_vid_start
);
224 if (last_vid_start
!= vinfo
->vid
)
225 fprintf(fp
, "-%hu", vinfo
->vid
);
226 if (vinfo
->flags
& BRIDGE_VLAN_INFO_PVID
)
227 fprintf(fp
, " PVID");
228 if (vinfo
->flags
& BRIDGE_VLAN_INFO_UNTAGGED
)
229 fprintf(fp
, " Egress Untagged");
239 static int vlan_show(int argc
, char **argv
)
241 char *filter_dev
= NULL
;
244 if (strcmp(*argv
, "dev") == 0) {
247 duparg("dev", *argv
);
249 } else if (strcmp(*argv
, "vid") == 0) {
252 duparg("vid", *argv
);
253 filter_vlan
= atoi(*argv
);
259 if ((filter_index
= if_nametoindex(filter_dev
)) == 0) {
260 fprintf(stderr
, "Cannot find device \"%s\"\n",
266 if (rtnl_wilddump_req_filter(&rth
, PF_BRIDGE
, RTM_GETLINK
,
268 RTEXT_FILTER_BRVLAN_COMPRESSED
:
269 RTEXT_FILTER_BRVLAN
)) < 0) {
270 perror("Cannont send dump request");
274 printf("port\tvlan ids\n");
275 if (rtnl_dump_filter(&rth
, print_vlan
, stdout
) < 0) {
276 fprintf(stderr
, "Dump ternminated\n");
284 int do_vlan(int argc
, char **argv
)
289 if (matches(*argv
, "add") == 0)
290 return vlan_modify(RTM_SETLINK
, argc
-1, argv
+1);
291 if (matches(*argv
, "delete") == 0)
292 return vlan_modify(RTM_DELLINK
, argc
-1, argv
+1);
293 if (matches(*argv
, "show") == 0 ||
294 matches(*argv
, "lst") == 0 ||
295 matches(*argv
, "list") == 0)
296 return vlan_show(argc
-1, argv
+1);
297 if (matches(*argv
, "help") == 0)
300 return vlan_show(0, NULL
);
302 fprintf(stderr
, "Command \"%s\" is unknown, try \"bridge vlan help\".\n", *argv
);