mirror of
https://git.proxmox.com/git/mirror_iproute2
synced 2025-10-11 09:59:43 +00:00

Michael Tautschnig wrote: During a rebuild [...]. Please note that we use our research compiler tool-chain (using tools from the cbmc package), which permits extended reporting on type inconsistencies at link time. [...] gcc bridge.o fdb.o monitor.o link.o mdb.o vlan.o ../lib/libnetlink.a ../lib/libutil.a ../lib/libnetlink.a ../lib/libutil.a -o bridge file link.c line 18: error: conflicting types for variable "filter_index" old definition in module fdb file fdb.c line 29 signed int new definition in module link file link.c line 18 unsigned int <builtin>: recipe for target 'bridge' failed make[3]: *** [bridge] Error 64 make[3]: Leaving directory '/srv/jenkins-slave/workspace/sid-goto-cc-iproute2/iproute2-3.14.0/bridge' Makefile:45: recipe for target 'all' failed While practical constraints may limit the value of filter_index to remain within the bounds of a positive signed int, there is certainly no such guarantee here. Also, a plain majority vote suggests that this really just a wrong declaration in link.c as several declarations of filter_index as signed int exist. [...] My followup on this was: I think the majority is wrong. filter_index is assigned exclusively from if_nametoindex or ll_name_to_index which both return unsigned int. Changing it to unsigned everywhere seems better. This has been minimally tested by using the bridge tool to add vids and showing available vids on different devices. Reported-by: Michael Tautschnig <mt@debian.org> Signed-off-by: Andreas Henriksson <andreas@fatal.se>
221 lines
5.0 KiB
C
221 lines
5.0 KiB
C
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <unistd.h>
|
|
#include <fcntl.h>
|
|
#include <sys/socket.h>
|
|
#include <net/if.h>
|
|
#include <netinet/in.h>
|
|
#include <linux/if_bridge.h>
|
|
#include <linux/if_ether.h>
|
|
#include <string.h>
|
|
|
|
#include "libnetlink.h"
|
|
#include "br_common.h"
|
|
#include "utils.h"
|
|
|
|
static unsigned int filter_index;
|
|
|
|
static void usage(void)
|
|
{
|
|
fprintf(stderr, "Usage: bridge vlan { add | del } vid VLAN_ID dev DEV [ pvid] [ untagged ]\n");
|
|
fprintf(stderr, " [ self ] [ master ]\n");
|
|
fprintf(stderr, " bridge vlan { show } [ dev DEV ]\n");
|
|
exit(-1);
|
|
}
|
|
|
|
static int vlan_modify(int cmd, int argc, char **argv)
|
|
{
|
|
struct {
|
|
struct nlmsghdr n;
|
|
struct ifinfomsg ifm;
|
|
char buf[1024];
|
|
} req;
|
|
char *d = NULL;
|
|
short vid = -1;
|
|
struct rtattr *afspec;
|
|
struct bridge_vlan_info vinfo;
|
|
unsigned short flags = 0;
|
|
|
|
memset(&vinfo, 0, sizeof(vinfo));
|
|
memset(&req, 0, sizeof(req));
|
|
|
|
req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
|
|
req.n.nlmsg_flags = NLM_F_REQUEST;
|
|
req.n.nlmsg_type = cmd;
|
|
req.ifm.ifi_family = PF_BRIDGE;
|
|
|
|
while (argc > 0) {
|
|
if (strcmp(*argv, "dev") == 0) {
|
|
NEXT_ARG();
|
|
d = *argv;
|
|
} else if (strcmp(*argv, "vid") == 0) {
|
|
NEXT_ARG();
|
|
vid = atoi(*argv);
|
|
} else if (strcmp(*argv, "self") == 0) {
|
|
flags |= BRIDGE_FLAGS_SELF;
|
|
} else if (strcmp(*argv, "master") == 0) {
|
|
flags |= BRIDGE_FLAGS_MASTER;
|
|
} else if (strcmp(*argv, "pvid") == 0) {
|
|
vinfo.flags |= BRIDGE_VLAN_INFO_PVID;
|
|
} else if (strcmp(*argv, "untagged") == 0) {
|
|
vinfo.flags |= BRIDGE_VLAN_INFO_UNTAGGED;
|
|
} else {
|
|
if (matches(*argv, "help") == 0) {
|
|
NEXT_ARG();
|
|
}
|
|
}
|
|
argc--; argv++;
|
|
}
|
|
|
|
if (d == NULL || vid == -1) {
|
|
fprintf(stderr, "Device and VLAN ID are required arguments.\n");
|
|
exit(-1);
|
|
}
|
|
|
|
req.ifm.ifi_index = ll_name_to_index(d);
|
|
if (req.ifm.ifi_index == 0) {
|
|
fprintf(stderr, "Cannot find bridge device \"%s\"\n", d);
|
|
return -1;
|
|
}
|
|
|
|
if (vid >= 4096) {
|
|
fprintf(stderr, "Invalid VLAN ID \"%hu\"\n", vid);
|
|
return -1;
|
|
}
|
|
|
|
vinfo.vid = vid;
|
|
|
|
afspec = addattr_nest(&req.n, sizeof(req), IFLA_AF_SPEC);
|
|
|
|
if (flags)
|
|
addattr16(&req.n, sizeof(req), IFLA_BRIDGE_FLAGS, flags);
|
|
|
|
addattr_l(&req.n, sizeof(req), IFLA_BRIDGE_VLAN_INFO, &vinfo,
|
|
sizeof(vinfo));
|
|
|
|
addattr_nest_end(&req.n, afspec);
|
|
|
|
if (rtnl_talk(&rth, &req.n, 0, 0, NULL) < 0)
|
|
exit(2);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int print_vlan(const struct sockaddr_nl *who,
|
|
struct nlmsghdr *n,
|
|
void *arg)
|
|
{
|
|
FILE *fp = arg;
|
|
struct ifinfomsg *ifm = NLMSG_DATA(n);
|
|
int len = n->nlmsg_len;
|
|
struct rtattr * tb[IFLA_MAX+1];
|
|
|
|
if (n->nlmsg_type != RTM_NEWLINK) {
|
|
fprintf(stderr, "Not RTM_NEWLINK: %08x %08x %08x\n",
|
|
n->nlmsg_len, n->nlmsg_type, n->nlmsg_flags);
|
|
return 0;
|
|
}
|
|
|
|
len -= NLMSG_LENGTH(sizeof(*ifm));
|
|
if (len < 0) {
|
|
fprintf(stderr, "BUG: wrong nlmsg len %d\n", len);
|
|
return -1;
|
|
}
|
|
|
|
if (ifm->ifi_family != AF_BRIDGE)
|
|
return 0;
|
|
|
|
if (filter_index && filter_index != ifm->ifi_index)
|
|
return 0;
|
|
|
|
parse_rtattr(tb, IFLA_MAX, IFLA_RTA(ifm), len);
|
|
|
|
/* if AF_SPEC isn't there, vlan table is not preset for this port */
|
|
if (!tb[IFLA_AF_SPEC]) {
|
|
fprintf(fp, "%s\tNone\n", ll_index_to_name(ifm->ifi_index));
|
|
return 0;
|
|
} else {
|
|
struct rtattr *i, *list = tb[IFLA_AF_SPEC];
|
|
int rem = RTA_PAYLOAD(list);
|
|
|
|
fprintf(fp, "%s", ll_index_to_name(ifm->ifi_index));
|
|
for (i = RTA_DATA(list); RTA_OK(i, rem); i = RTA_NEXT(i, rem)) {
|
|
struct bridge_vlan_info *vinfo;
|
|
|
|
if (i->rta_type != IFLA_BRIDGE_VLAN_INFO)
|
|
continue;
|
|
|
|
vinfo = RTA_DATA(i);
|
|
fprintf(fp, "\t %hu", vinfo->vid);
|
|
if (vinfo->flags & BRIDGE_VLAN_INFO_PVID)
|
|
fprintf(fp, " PVID");
|
|
if (vinfo->flags & BRIDGE_VLAN_INFO_UNTAGGED)
|
|
fprintf(fp, " Egress Untagged");
|
|
fprintf(fp, "\n");
|
|
}
|
|
}
|
|
fprintf(fp, "\n");
|
|
fflush(fp);
|
|
return 0;
|
|
}
|
|
|
|
static int vlan_show(int argc, char **argv)
|
|
{
|
|
char *filter_dev = NULL;
|
|
|
|
while (argc > 0) {
|
|
if (strcmp(*argv, "dev") == 0) {
|
|
NEXT_ARG();
|
|
if (filter_dev)
|
|
duparg("dev", *argv);
|
|
filter_dev = *argv;
|
|
}
|
|
argc--; argv++;
|
|
}
|
|
|
|
if (filter_dev) {
|
|
if ((filter_index = if_nametoindex(filter_dev)) == 0) {
|
|
fprintf(stderr, "Cannot find device \"%s\"\n",
|
|
filter_dev);
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
if (rtnl_wilddump_req_filter(&rth, PF_BRIDGE, RTM_GETLINK,
|
|
RTEXT_FILTER_BRVLAN) < 0) {
|
|
perror("Cannont send dump request");
|
|
exit(1);
|
|
}
|
|
|
|
printf("port\tvlan ids\n");
|
|
if (rtnl_dump_filter(&rth, print_vlan, stdout) < 0) {
|
|
fprintf(stderr, "Dump ternminated\n");
|
|
exit(1);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
int do_vlan(int argc, char **argv)
|
|
{
|
|
ll_init_map(&rth);
|
|
|
|
if (argc > 0) {
|
|
if (matches(*argv, "add") == 0)
|
|
return vlan_modify(RTM_SETLINK, argc-1, argv+1);
|
|
if (matches(*argv, "delete") == 0)
|
|
return vlan_modify(RTM_DELLINK, argc-1, argv+1);
|
|
if (matches(*argv, "show") == 0 ||
|
|
matches(*argv, "lst") == 0 ||
|
|
matches(*argv, "list") == 0)
|
|
return vlan_show(argc-1, argv+1);
|
|
if (matches(*argv, "help") == 0)
|
|
usage();
|
|
} else
|
|
return vlan_show(0, NULL);
|
|
|
|
fprintf(stderr, "Command \"%s\" is unknown, try \"bridge fdb help\".\n", *argv);
|
|
exit(-1);
|
|
}
|