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 ...
随机推荐
- Servlet学习:(三)Servlet3.0 上传文件
转: Servlet学习:(三)Servlet3.0 上传文件 2018年08月03日 11:57:58 iDark_CSDN 阅读数:362 一.注意事项 客户端(浏览器) 表单的提交方法必须是 ...
- (next_permutation) 排列2 hdu 1716
排列2 Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Total Submis ...
- STM32 --- 什么时候打开复用IO的时钟(比如RCC_APB2Periph_AFIO)
需要用到外设的重映射功能时才需要使能AFIO的时钟,包括外部中断. 外部中断(EXTI)中与AFIO有关的寄存器是AFIO-EXTICR1.2.3,它们是用来选择EXTIx外部中断的输入脚之用. 举例 ...
- MUI 窗体切换(setting设置)即窗口从右往左切换,返回从左往右切换。
1)引入mui.min.css 2)引入mui.min.js 引入mui.view.js 1.HTML: //这是页面的主体结构 <div id="app" class=& ...
- django分页功能
采用django自带的Paginator功能 from django.core.paginator import Paginator food = foodInfo.objects.filter(fo ...
- mac 本上对 rar 压缩包解压
以前从晚上各种找软件对 xxx.rar 压缩包文件进行解压,也确实找到过那么几个,要不是不好用就是解压完有乱码,很是头疼. 这次又遇到这样的问题,于是下定决心将这个问题彻底解决好,经过验证,总结一下最 ...
- Nginx 入门指南
Nginx 入门指南 简介: Nginx 是一款轻量级的 Web 服务器/反向代理服务器及电子邮件(IMAP/POP3)代理服务器,其特点是占有内存少,并发能力强.本教程根据淘宝核心系统服务器平台组的 ...
- 设计模式---对象创建模式之构建器模式(Builder)
一:概念 Builder模式也叫建造者模式或者生成器模式,是由GoF提出的23种设计模式中的一种.Builder模式是一种对象创建型模式之一,用来隐藏复合对象的创建过程,它把复合对象的创建过程加以抽象 ...
- Java 编程下使用 Class.forName() 加载类【转】
在一些应用中,无法事先知道使用者将加载什么类,而必须让使用者指定类名称以加载类,可以使用 Class 的静态 forName() 方法实现动态加载类.下面的范例让你可以指定类名称来获得类的相关信息. ...
- Java的参数传递是「按值传递」还是「按引用传递」?
JAVA传递的只有值,.传递的都是栈里的的值,只是有些栈里面的是值.有的是内存地址.(原文传递的都是栈里的的值有误,局部变量在栈中,成员变量在堆中,类变量(静态变量和常量)在方法区中,可以看做本文的变 ...