client模式下对应接口加入桥接出错
client模式下,响应的接口wlan0 加入桥接时出现如下错误:
root@root:~# brctl addif br-lan wlan0
brctl: bridge br-lan: Operation not supported。
查看相应busybox代码(brctl.c),函数为 brctl_main,
strncpy_IFNAMSIZ(ifr.ifr_name, br);
if (key == ARG_addif || key == ARG_delif) { /* addif or delif */
brif = *argv;
ifr.ifr_ifindex = if_nametoindex(brif);
if (!ifr.ifr_ifindex) {
bb_perror_msg_and_die("iface %s", brif);
}
ioctl_or_perror_and_die(fd,
key == ARG_addif ? SIOCBRADDIF : SIOCBRDELIF, &ifr, "bridge %s", br);
goto done_next_argv;
}
得到addif 和 delif 相应的ioctl命令码为 SIOCBRADDIF 和 SIOCBRDELIF。
内核中对应命令字的定义:
include/linux/sockios.h:#define SIOCBRADDIF 0x89a2 /* add interface to bridge,十进制为35234
查找内核中响应的代码, 此处内核版本为3.10.14。
* Perform the SIOCxIFxxx calls, inside rtnl_lock()
*/
static int dev_ifsioc(struct net *net, struct ifreq *ifr, unsigned int cmd)
{
switch (cmd) {
/*
* Unknown or private ioctl
*/
default:
if ((cmd >= SIOCDEVPRIVATE &&
cmd <= SIOCDEVPRIVATE + 15) ||
cmd == SIOCBONDENSLAVE ||
cmd == SIOCBONDRELEASE ||
cmd == SIOCBONDSETHWADDR ||
cmd == SIOCBONDSLAVEINFOQUERY ||
cmd == SIOCBONDINFOQUERY ||
cmd == SIOCBONDCHANGEACTIVE ||
cmd == SIOCGMIIPHY ||
cmd == SIOCGMIIREG ||
cmd == SIOCSMIIREG ||
cmd == SIOCBRADDIF || // 添加桥接接口
cmd == SIOCBRDELIF || // 删除桥接接口
cmd == SIOCSHWTSTAMP ||
cmd == SIOCWANDEV) {
err = -EOPNOTSUPP;
if (ops->ndo_do_ioctl) {
if (netif_device_present(dev))
err = ops->ndo_do_ioctl(dev, ifr, cmd); // 调用回调函数
else
err = -ENODEV;
}
} else
err = -EINVAL;
}
}
对应的回调函数位于 /net/bridge/br_device.c中
static const struct net_device_ops br_netdev_ops = {
.ndo_open = br_dev_open,
.ndo_stop = br_dev_stop,
.ndo_init = br_dev_init,
.ndo_start_xmit = br_dev_xmit,
.ndo_get_stats64 = br_get_stats64,
.ndo_set_mac_address = br_set_mac_address,
.ndo_set_rx_mode = br_dev_set_multicast_list,
.ndo_change_mtu = br_change_mtu,
.ndo_do_ioctl = br_dev_ioctl, // 此处对应增加(addif)和删除(delif)的回调
#ifdef CONFIG_NET_POLL_CONTROLLER
.ndo_netpoll_setup = br_netpoll_setup,
.ndo_netpoll_cleanup = br_netpoll_cleanup,
.ndo_poll_controller = br_poll_controller,
#endif
.ndo_add_slave = br_add_slave,
.ndo_del_slave = br_del_slave,
.ndo_fix_features = br_fix_features,
.ndo_fdb_add = br_fdb_add,
.ndo_fdb_del = br_fdb_delete,
.ndo_fdb_dump = br_fdb_dump,
.ndo_bridge_getlink = br_getlink,
.ndo_bridge_setlink = br_setlink,
.ndo_bridge_dellink = br_dellink,
};
查看回调函数如下:
int br_dev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
{
struct net_bridge *br = netdev_priv(dev);
switch(cmd) {
// 旧式的处理方式
case SIOCDEVPRIVATE:
return old_dev_ioctl(dev, rq, cmd);
// 实现如下:
case SIOCBRADDIF:
case SIOCBRDELIF:
return add_del_if(br, rq->ifr_ifindex, cmd == SIOCBRADDIF);
}
br_debug(br, "Bridge does not support ioctl 0x%x\n", cmd);
return -EOPNOTSUPP;
}
位于 /net/bridge/br_ioctl.c中
static int add_del_if(struct net_bridge *br, int ifindex, int isadd)
{
struct net *net = dev_net(br->dev);
struct net_device *dev;
int ret;
if (!ns_capable(net->user_ns, CAP_NET_ADMIN))
return -EPERM;
dev = __dev_get_by_index(net, ifindex);
if (dev == NULL)
return -EINVAL;
if (isadd)
ret = br_add_if(br, dev); // 添加桥接接口
else
ret = br_del_if(br, dev); // 删除桥接接口
return ret;
}
位于 /net/bridge/br_if.c中
int br_add_if(struct net_bridge *br, struct net_device *dev)
{
struct net_bridge_port *p;
int err = 0;
bool changed_addr;
/* Don't allow bridging non-ethernet like devices */
if ((dev->flags & IFF_LOOPBACK) ||
dev->type != ARPHRD_ETHER || dev->addr_len != ETH_ALEN ||
!is_valid_ether_addr(dev->dev_addr))
return -EINVAL;
/* No bridging of bridges */
if (dev->netdev_ops->ndo_start_xmit == br_dev_xmit)
return -ELOOP;
/* Device is already being bridged */
if (br_port_exists(dev))
return -EBUSY;
/* No bridging devices that dislike that (e.g. wireless) */
if (dev->priv_flags & IFF_DONT_BRIDGE) // wlan0加入桥接时在此处遇到问题,退出
return -EOPNOTSUPP;
p = new_nbp(br, dev);
if (IS_ERR(p))
return PTR_ERR(p);
call_netdevice_notifiers(NETDEV_JOIN, dev);
err = dev_set_promiscuity(dev, 1);
if (err)
goto put_back;
err = kobject_init_and_add(&p->kobj, &brport_ktype, &(dev->dev.kobj),
SYSFS_BRIDGE_PORT_ATTR);
if (err)
goto err1;
err = br_sysfs_addif(p);
if (err)
goto err2;
if (br_netpoll_info(br) && ((err = br_netpoll_enable(p, GFP_KERNEL))))
goto err3;
err = netdev_master_upper_dev_link(dev, br->dev);
if (err)
goto err4;
err = netdev_rx_handler_register(dev, br_handle_frame, p);
if (err)
goto err5;
dev->priv_flags |= IFF_BRIDGE_PORT;
dev_disable_lro(dev);
list_add_rcu(&p->list, &br->port_list);
netdev_update_features(br->dev);
spin_lock_bh(&br->lock);
changed_addr = br_stp_recalculate_bridge_id(br);
if (netif_running(dev) && netif_oper_up(dev) &&
(br->dev->flags & IFF_UP))
br_stp_enable_port(p);
spin_unlock_bh(&br->lock);
br_ifinfo_notify(RTM_NEWLINK, p);
if (changed_addr)
call_netdevice_notifiers(NETDEV_CHANGEADDR, br->dev);
dev_set_mtu(br->dev, br_min_mtu(br));
if (br_fdb_insert(br, p, dev->dev_addr, 0))
netdev_err(dev, "failed insert local address bridge forwarding table\n");
kobject_uevent(&p->kobj, KOBJ_ADD);
return 0;
err5:
netdev_upper_dev_unlink(dev, br->dev);
err4:
br_netpoll_disable(p);
err3:
sysfs_remove_link(br->ifobj, p->dev->name);
err2:
kobject_put(&p->kobj);
p = NULL; /* kobject_put frees */
err1:
dev_set_promiscuity(dev, -1);
put_back:
dev_put(dev);
kfree(p);
return err;
}
追溯出问题的地方,查找 IFF_DONT_BRIDGE 标志置位的地方,找到如下:
static int cfg80211_netdev_notifier_call(struct notifier_block *nb,
unsigned long state, void *ndev)
{
.......
switch (state) {
case NETDEV_REGISTER: // 注册设备
if ((wdev->iftype == NL80211_IFTYPE_STATION ||
wdev->iftype == NL80211_IFTYPE_P2P_CLIENT ||
wdev->iftype == NL80211_IFTYPE_ADHOC) && !wdev->use_4addr)
dev->priv_flags |= IFF_DONT_BRIDGE;
break;
}
.........
}
从以上红色部分可以看出,当设备为client或者adhoc以及wds时,对应的无线接口是无法加入到桥接中去的。
在br_add_if 中判断标志位出错后,返回值为EOPNOTSUPP,定义如下:
#define EOPNOTSUPP 45 /* Op not supported on transport endpoint */
跟串口中配置出错时打印相符。
client模式下对应接口加入桥接出错的更多相关文章
- Apache Spark技术实战之8:Standalone部署模式下的临时文件清理
未经本人同意严禁转载,徽沪一郎. 概要 在Standalone部署模式下,Spark运行过程中会创建哪些临时性目录及文件,这些临时目录和文件又是在什么时候被清理,本文将就这些问题做深入细致的解答. 从 ...
- Java虚拟机6:内存溢出和内存泄露、并行和并发、Minor GC和Full GC、Client模式和Server模式的区别
前言 之前的文章尤其是讲解GC的时候提到了很多的概念,比如内存溢出和内存泄露.并行与并发.Client模式和Server模式.Minor GC和Full GC,本文详细讲解下这些概念的区别. 内存溢出 ...
- Apache Spark技术实战之6 --Standalone部署模式下的临时文件清理
问题导读 1.在Standalone部署模式下,Spark运行过程中会创建哪些临时性目录及文件? 2.在Standalone部署模式下分为几种模式? 3.在client模式和cluster模式下有什么 ...
- Java虚拟机10:Client模式和Server模式的区别
部分商用虚拟机中,Java程序最初是通过解释器对.class文件进行解释执行的,当虚拟机发现某个方法或代码块运行地特别频繁的时候,就会把这些代码认定为热点代码Hot Spot Code(这也是我们使用 ...
- spark on yarn模式下内存资源管理(笔记2)
1.spark 2.2内存占用计算公式 https://blog.csdn.net/lingbo229/article/details/80914283 2.spark on yarn内存分配** 本 ...
- 嵌入式以太网模块的TCP Client模式说明
嵌入式以太网模块采用TTL电平串口,支持TCP Server,TCP Client,UDP Slave,UDP Master,TCP-ZSD,UDP-ZSD多种通信协议,TCP服务器模式支持多连接,可 ...
- 虚拟机Linux桥接模式下设置静态IP
之前一直使用NAT模式,测试时android端远程访问虚拟机的mysql时发现无法连接,但是访问同学拷过来的虚拟机Linux的mysql却成功了,想了下原因是他设置的桥接模式.关于两种模式的区别,网上 ...
- 业务类接口在TCP,HTTP,BLL模式下的实例 设计模式混搭 附源码一份
业务类接口在TCP,HTTP,BLL模式下的实例 设计模式混搭 附源码一份 WinForm酒店管理软件--框架这篇随笔可以说是我写的最被大家争议的随笔,一度是支持和反对是一样的多.大家对我做的这个行业 ...
- c# 调试模式下Swaggerf附加接口参数
c# 调试模式下Swaggerf附加接口参数,如:每个接口Header中附加参数appId 1.新增过滤器: public class GlobalHttpHeaderFilter : IOperat ...
随机推荐
- Java NIO -- 管道 (Pipe)
Java NIO 管道是2个线程之间的单向数据连接. Pipe有一个source通道和一个sink通道.数据会被写到sink通道,从source通道读取. 举个例子: package com.soyo ...
- Java_io体系之RandomAccessFile简介、走进源码及示例——20
Java_io体系之RandomAccessFile简介.走进源码及示例——20 RandomAccessFile 1. 类功能简介: 文件随机访问流.关心几个特点: 1.他实现的接口不再 ...
- Codeforces 382 D Permutations
题目大意: 给出一张二分图,这张二分图完美匹配的个数是奇数,求删掉第$i(1<=i<=m)$条边后完美匹配个数的奇偶性. 设这张图的邻接矩阵为$A$,那么完美匹配的个数为$A$的积和式,即 ...
- 【HDU3085】nightmare2 双向BFS
对于搜索树分支很多且有明确起点和终点的情况时,可以采用双向搜索来减小搜索树的大小. 对于双向BFS来说,与单向最大的不同是双向BFS需要按层扩展,表示可能到达的区域.而单向BFS则是按照单个节点进行扩 ...
- Java:判断当前操作系统界面采用的主题是windows经典样式还是xp样式
想起两三年前,发现写Java界面的时候,如果将当前界面的layout设为null,由于windows的不同主题界面下,标题栏的高度不一致,导致当前界面表现也不一致. 当时就想找到一个办法先判断当前用户 ...
- Java:在不同界面样式下JPopupMenu与鼠标事件mousePressed表现的结果不同!
今天遇到一个郁闷的事儿: 在一个JFrame上放了一个JList元件,这个JList元件添加了鼠标事件: mouseReleased.mousePressed ... 其中,在mouseRelease ...
- idea svn performing vcs refresh 很长时间
go to settings - version control - background set changelists to cache initially to minimal value (1 ...
- java 中方法重载
方法的重载 * 在同一个类中,方法名相同,参数列表不同.与返回值类型无关. * 参数列表不同: * A:参数个数不同 * B:参数类型不同 * C:参数的顺序不同(不算重载 报错) ex: publi ...
- xtrabackup备份MySQL
mysql备份之xtrabackup(建议用来备份innodb) 下载地址:https://www.percona.com/downloads/XtraBackup/ 安装xtrabackup [ro ...
- Hbase记录-Hbase基础概念
HBase是什么? HBase是建立在Hadoop文件系统之上的分布式面向列的数据库.它是一个开源项目,是横向扩展的. HBase是一个数据模型,类似于谷歌的大表设计,可以提供快速随机访问海量结构化数 ...