linux代码心得

(1) bridge ioctl

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);

}

pr_debug("Bridge does not support ioctl 0x%x\n", cmd);return -EOPNOTSUPP;}

static int add_del_if(struct net_bridge *br, int ifindex, int isadd)

通过这个可以看出来,在调用add_del_if的时候,使用了cmd==SIOCBRADDIF. 在函数声明里面用了 int isadd.这样当函数和调用者在不同的文件里面的时候,用这种方法,可以不需要让add_def_if()所在的文件里面包含SIOCBRADDIF的声明。

(2)设置网桥网桥工具的安装:  默认Ubuntu是没有网桥设置工具(brctl)的。你需要安装bridge-utils,这里在我的pc2上:SYSHUNTER-UBUNTU# apt-get install bridge-utils

配置网桥:  先创建一个网桥接口:  SYSHUNTER-UBUNTU# brctl addbr br0

  将两块已有的网卡添加到网桥:  SYSHUNTER-UBUNTU# brctl addif br0 eth0  SYSHUNTER-UBUNTU# brctl addif br0 eth1

  将两块网卡IP设置为0,它们已经不再需要了:  SYSHUNTER-UBUNTU# ifconfig eth0 0.0.0.0  SYSHUNTER-UBUNTU# ifconfig eth1 0.0.0.0

  给新网桥设置一个IP:  SYSHUNTER-UBUNTU# ifconfig br0 192.168.1.10

(3)用户空间工具ifconfig工具在包net-tools里面,查看其源代码,发现ifconfig使用的是ioctl来与内核空间交互的。fd=socket(…..);ret=ioctl(fd,cmd,XXX);由于用的socket文件句柄所以调用sock_ioctl();(4)bridge默认不编译到内核里面,可以设置其编译进内核。bridge相关初始化代码在net/bridge/br.cint (*br_should_route_hook) (struct sk_buff **pskb) = NULL;

static int __init br_init(void){br_fdb_init();

#ifdef CONFIG_BRIDGE_NETFILTERif (br_netfilter_init())return 1;#endifbrioctl_set(br_ioctl_deviceless_stub);br_handle_frame_hook = br_handle_frame;

#if defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE)br_fdb_get_hook = br_fdb_get;br_fdb_put_hook = br_fdb_put;#endifregister_netdevice_notifier(&br_device_notifier);

return 0;}module_init(br_init)可以看到bridge模块的初始化函数是br_init.他做了几件事情:(netfilter的部分先不管)1)初始化forwarding database.2) 设置bridge相关的ioctl3)设置收包函数4)注册bridge模块的notifier.

(5)当用户调用### brctl addbr br0建一个新的bridge.用户空间程序会调用ioctl,并最终调用到br_ioctl_deviceless_stub()这个函数从用户空间得到bridge的名字,并调用br_add_bridge( )添加该bridge.br_add_bridge()主要做几件事情:1)建一个net_bridge结构和一个net_device结构,这2个结构相对应,代表了这个bridge.net_bridge br;net_device dev;dev->priv = br;br->dev = dev;2)register_netdevice(dev);3)ret = br_sysfs_addbr(dev);4)初始化一些与stp相关的东西。

(6)当用户调用 ###brctl addif br0 eth0把eth0添加到bridge里面,成为bridge的一个端口。会调用br_dev_ioctl( )。并最终调用ret = br_add_if(br, dev);来添加这个端口。会做下面几件事:1)生成一个net_bridge_port结构,表示这个端口。2)由于该端口本身就是一个实际的设备,如一块网卡,所以他本身有一个net_device结构。net_bridge_port port;net_devicedev;net_bridgebr;port->dev = dev;port->br = br;dev->br_port = port;add_list(br->portlist,port);3)设置stp相关的部分。(7)收包。当网卡被加入到bridge里面以后,其net_device结构中多了一项 dev->br_port = port; (该dev对应bridge port)包进网卡还是按照正常流程走。到了netif_receive_skb()里面会调用if (handle_bridge(&skb, &pt_prev, &ret))goto out;进行bridge相关的包处理。static __inline__ int handle_bridge(struct sk_buff **pskb,struct packet_type **pt_prev, int *ret){struct net_bridge_port *port;

if ((*pskb)->pkt_type == PACKET_LOOPBACK ||(port = rcu_dereference((*pskb)->dev->br_port)) == NULL)return 0;

if (*pt_prev) {*ret = deliver_skb(*pskb, *pt_prev);*pt_prev = NULL;}return br_handle_frame_hook(port, pskb);}可以看到如果该包是loopback的直接返回。如果收该包的dev不是一个bridge port则返回。所以当一个dev被加成一个bridge port的时候,从这个dev收来的包就会调用 br_handle_frame_hook()进行处理。(8)bridge相关的包处理进行以下步骤:对包进行判断,drop错包|V进行源地址学习|V目的地址判断———BPDU包—->进行|V查找fdb做转发判断+flooding<—–+—–>forward to other bridge port|Vhand packet to upper layer当需要把这个skb送到upper layer的时候,会把skb中的dev域替换成bridge的dev.

也只有懂的接受自己的失败,才能更好的去发挥自身优势,也才能够更好的去实现自我;

linux代码心得

相关文章:

你感兴趣的文章:

标签云: