Docker Libnetwork Bridge插件实现代码分析----创建网络部分
// drivers/bridge/bridge.go
// Create a new network using bridge plugin
1、func (d *driver) CreateNetwork(id string, option map[string]interface{}, nInfo driverapi.NetworkInfo, ipV4Data, ipV6Data []driverapi.IPAMData) error
- 首先确定len(ipV4Data)不为0且ipV4Data[0].Pool.String()不为"0.0.0.0/0",否则返回"ipv4 pool is empty"
- 调用config, err := parseNetworkOptions(id, option)确认配置不和当前的networks的配置矛盾
- 调用err = config.processIPAM(id, ipV4Data, ipV6Data)
- 调用err = d.createNetwork(config)进行具体的网络创建
- 最后调用return d.storeUpdate(config)
// driver/bridge/bridge.go
2、func parseNetworkOptions(id string, option options.Generic) (*networkConfiguration, error)
- 首先如果option[netlabel.GenericData]不为空,则调用config, err = parseNetworkGenericOptions(genData)先解析generic label
- 再对well-known labels进行处理,例如config.EnableIPv6和config.Internal
- 若config.BridgeName为"",并且config.DefaultBridge为false,则默认创建config.BridgeName = "br-" + id[:12]
- 之后再调用exists, err := bridgeInterfaceExists(config.BridgeName),若不存在则config.BridgeIfaceCreator = ifaceCreatedByLibnetwork,否则为ifaceCreatedByUser
networkConfiguraion数据结构如下所示
// networkConfiguraion for network specific configuraion
type networkConfiguraion struct {
ID string
BridgeName string
EnableIPv6 bool
EnableIPMasquerade bool
EnableICC bool
Mtu int
DefaultBindingIP net.IP
DefaultBridge bool
// Internal fields set after ipam data parsing
AddressIPv4 *net.IPNet
AddressIPv6 *net.IPNet
DefaultGatewayIPv4 net.IP
DefaultGatewayIPv6 net.IP
dbIndex uint64
dbExists bool
Internal bool
BridgeIfaceCreator ifaceCreator // ifaceCreator represents how the bridge interface was created
}
// driver/bridge/bridge.go
3、func (c *networkConfiguraion) processIPAM(id string, ipamV4Data, ipamV6Data []driverapi.IPAMData) error
- 若ipamV4Data[0].Gateway不为nil,则调用c.AddressIPv4 = types.GetIPNetCopy(ipamV4Data[0].Gateway)
- gw, ok := ipamV4Data[0].AuxAddresses[DefaultGatewayV4AuxKey],若ok为true,则c.DefaultGatewayIPv4为gw.IP
- 若len(ipamV6Data)大于0,则操作方式和ipamV4Data相同
// driver/bridge/bridge.go
4、func (d *driver) createNetwork(config *networkConfiguraion) error
- 首先调用networkList := d.getNetworks(),然后再调用for i, nw := range networkList进行遍历
- 调用nwConfig := nw.config,如果nwConfig.Conflicts(config)返回错误,如果config.DefaultBridge为真,则将nwConfig删除。
- 创建并且设置一个network handler,network := &bridgeNetwork{},并且将其添加到d.networks[config.ID] = network
- 如果d.nlh为nil,则调用d.nlh = ns.NlHandle()
- 调用bridgeIface, err := newInterface(d.nlh, config)创建并且返回the bridge L3 interface,并且将network.bridge = bridgeIface
- 调用config.conflictsWithNetworks(config.ID, networkList)判断该network configuration 和之前已经安装的networks是否冲突
- 调用setupNetworkIsolationRules := func(config *networkConfiguration, i *bridgeInterface) error{}
- 调用bridgeSetup := newBridgeSetup(config, bridgeIface),准备bridge创建的配置,仅仅只是返回一个&bridgeSetup{config: c, bridge: i}的数据结构
- 调用bridgeAlreadyExists := bridgeIface.exists()判断bridge是否存在,如果不存在则调用bridgeSetup.queueStep(setupDevice)创建设备,即使bridge已经存在了,也调用bridgeSetup.queueStep(setupBridgeIPv4)来设置ip
- 再利用一个for循环,针对不同的条件,例如config.EnableIPv6,bridgeAlreadyExists等等,调用相应的bridgeSetup.queueStep(step.Fn)
- 最后调用bridgeSetup.queueStep(setupDeviceUp)和bridgeSetup.apply()
bridgeNetwork数据结构如下所示:
type bridgeNetwork struct {
id string
bridge *bridgeInterface // The bridge's L3 interface
config *networkConfiguraion
endpoints map[string]*bridgeEndpoint // key: endpoint id
portMapper *portmapper.PortMapper
driver *driver
iptCleanFuncs iptablesCleanFuncs
sync.Mutex
}
bridgeSetup数据结构如下所示:
type bridgeSetup struct {
config *networkConfiguraion
bridge *bridgeInterface
steps []setupStep
// setupStep是一个函数类型,type setupStep func(*networkConfiguraion, *bridgeInterface) error
//可以调用queueStep函数往其中添加step,最后调用apply函数遍历执行
}
// driver/bridge/interface.go
// newInterface creates a new bridge interface structure. It attempts to find an already existing device
// identified by the configuration BridgeName field, or the default bridge name when unspecified, but
// doesn't attempt to create one when missing
5、func newInterface(nlh *netlink.Handle, config *networkConfiguraion) (*bridgeInterface, error)
- 首先创建i := &bridgeInterface{nlh: nlh}
- 若config.BridgeName为"",则将其设置为DefaultBridgeName,即"docker0"
- 最后调用i.Link, err = nlh.LinkByName(config.BridgeName)查找是否已经存在以该名字命名的网桥
bridgeInterface的数据结构如下所示:
// Interface models the bridge network device
type bridgeInterface struct {
Link netlink.Link
bridgeIPv4 *net.IPNet
bridgeIPv6 *net.IPNet
gatewayIPv4 net.IP
gatewayIPv6 net.IP
nlh *netlink.Handle
}
// driver/bridge/setup_device.go
// SetupDevice create a new bridge interface
6、func setupDevice(config *networkConfiguraion, i *bridgeInterface) error
- 在config.BridgeName != DefaultBridgeName && config.DefaultBridge时退出,两者不兼容
- 创建i.Link = &netlink.Bridge{LinkAttrs: netlink.LinkAttrs{Name: config.BridgeName,},}
- 调用kv, err := kernel.GetKernelVersion()获取内核版本,只有在版本大于3.3时,才设置bridge的Mac地址
- 调用err = i.nlh.LinkAdd(i.Link)创建bridge,若失败,则调用return ioctlCreateBridge(config.BridgeName, setMac)再次创建
- 若setMac为真,则调用hwAddr := netutils.GenerateRandomMAC()和i.nlh.LinkSetHardwareAddr(i.Link, hwAddr)设置bridge的Mac地址
// driver/bridge/setup_ipv4.go
7、func setupBridgeIPv4(config *networkConfiguraion, i *bridgeInterface) error
- 调用addrv4List, _, err := i.address()[直接调用i.nlh.AddrList(i.Link, netlink.FAMILY_V4)]和addrv4, _ := selectIPv4Address(addrv4List, config.AddressIPv4)
- 调用types.CompareIPNet(addrv4.IPNet, config.AddressIPv4),若两者不相等,当addrv4.IPNet不为nil时,调用i.nlh.AddrDel(i.Link, &addrv4)删除该地址,并且调用i.nlh.AddrAdd(i.Link, &netlink.Addr{IPNet: config.AddressIPv4})添加地址
- 设置i.bridgeIPv4 = config.AddressIPv4,i.gatewayIPv4 = config.AddressIPv4.IP
// driver/bridge/setup_device.go
// SetupDeviceUp ups the given bridge interface
8、func setupDeviceUp(config *networkConfiguraion, i *bridgeInterface) error
- 该函数仅仅调用err := i.nlh.LinkSetup(i.Link)启动bridge
- 再调用lnk, err := i.nlh.LinkByName(config.BridgeName)重新获取link,并且将其赋值给i.Link
--------------------------------------------------------- 创建endpoint ----------------------------------------
// drivers/bridge/bridge.go
1、func (d *driver) CreateEndpoint(nid, eid string, ifInfo driverapi.InterfaceInfo, epOptions map[string]interface{}) error
- 首先调用n, ok := d.networks[nid], dconfig := d.config获取配置信息
- 调用epConfig, err := parseEndpointOptions(epOptions)将options转换为endpoint configuraion
- 调用endpoint := &bridgeEndpoint{id: eid, nid: nid, config: epConfig}和n.endpoints[eid] = endpoint将endpoint加入网络中
- 创建veth := &netlink.Veth{...}和d.nlh.LinkAdd(veth)添加veth pair
- 调用addToBridge(d.nlh, hostIfName, config.BridgeName)将host端的veth加入bridge中
- 将containerIfName,ifInfo.MacAddress(),ifInfo.Address(),info.AddressIPv6信息存储到endpoint中
- 最后调用d.storeUpdate(endpoint)将endpoint的信息保存起来
bridgeEndpoint数据结构如下所示:
type bridgeEndpoint struct {
id string
nid string
srcName string
addr *net.IPNet
addrv6 *net.IPNet
macAddress net.HardwareAddr
config *endpointConfiguration // User specified parameters
containerConfig *containerConfiguration
extConnConfig *connectivityConfiguraion
portMapping []types.PortBinding // Operation port bindings
dxIndex uint64
dbExists bool
}
Docker Libnetwork Bridge插件实现代码分析----创建网络部分的更多相关文章
- Docker Libnetwork Bridge插件实现代码分析----初始化部分
Bridge driver数据结构如下所示: type driver struct { config *configuration network *bridgeNetwork natChain *i ...
- CNI bridge 插件实现代码分析
对于每个CNI 插件在执行函数cmdAdd之前的操作是完全一样的,即从环境变量和标准输入内读取配置.这在http://www.cnblogs.com/YaoDD/p/6410725.html这篇博文里 ...
- jQuery File Upload 插件 php代码分析
jquery file upload php代码分析首先进入构造方法 __construct() 再进入 initialize()因为我是post方式传的数据 在进入initialize()中的po ...
- 使用 Gradle 插件进行代码分析(转)
代码分析在大多数项目中通常是作为最后一个步骤(如果做了的话)完成的.其通常难以配置及与现有代码整合. 本文旨在勾勒出使用 Gradle 整合 PMD 与 FindBugs 的步骤,并将其与一个现有的 ...
- Eclipse插件(导出UML图,打开文件资源管理器插件,静态代码分析工具PMD,在eclipse上安装插件)
目录 能够导出UML图的Eclipse插件 打开文件资源管理器插件 Java静态代码分析工具PMD 如何在eclipse上安装插件 JProfiler性能分析工具 从更新站点安装EclEmma 能够导 ...
- vs中插件影响代码自动创建后台事件问题
CSS Tools 启用之后会影响代码自动创建后台事件,禁用之后解决.禁用之后鼠标悬浮不能看图片,颜色也不能展示
- docker——libnetwork插件网络功能
从1.7.0版本开始,Docker正是把网络和存储这两部分的功能都以插件化形式剥离出来,允许用户通过指令来选择不同的后端实现.剥离出来的独立容器网络项目叫libnetwork,从名字就能看出,它希望将 ...
- 虚拟机创建流程中neutron代码分析(二)
前言: 当nova服务发送了创建port的restful调用信息之后,在neutron服务中有相应的处理函数来处理调用.根据restful的工作原理,是按照 paste.ini文件中配置好的流程去处理 ...
- Hyperledger Fabric(v1.2.0)代码分析1——channel创建
Hyperledger Fabric(v1.2.0)代码分析1--channel创建 0. e2e_cli Hyperledger Fabric提供了一个e2e的例子,该例中创建了一个基础的区块链网络 ...
随机推荐
- 新标准C++程序设计读书笔记_类和对象
面向对象的程序设计方法 抽象:将某类客观事物共同特点(属性)归纳出来,形成一个数据结构(可以用多个变量描述事物的属性):将这类事物所能进行的行为也归纳出来,形成一个个函数,这些函数可以用来操作数据结构 ...
- python-hanoi
#!/usr/bin/env python #-*- coding:utf-8 -*- ############################ #File Name: hanoi.py #Autho ...
- poj 2846 Repository
题目大意:给你n个字符串,然后给你m个子串,看这个子串在上面的多少个串中,出现过: 题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2846 本题可以在字 ...
- PL/SQL Developer导入、导出表结构和表数据
在表的所有者不能改变的情况下,可以使用导入导出表结构和表数据的方法,将表移动到你想要的所有者下(注:特别是建立表的时候如果以sysdba的身份登录的话,所有表的所有者都为sys,此时会对你用c#访问数 ...
- Java监听模式
说明 生活中,监听无处不在.比如说,手机播放音乐功能,也是一种监听:你不点击播放按钮,手机就不放歌,当你点击时,手机就播放音乐.即触发某种行为,便执行相应的动作. 组成 Java监听模式右三个部分组成 ...
- jqgrid删除多行数据,删不全的解决方案
功能实现: 删除选中的多条数据 bug: 总是删不干净,比如选中5条执行删除操作,后台全删掉了,可是前台仍然有剩余的几条,再次刷新会不见 错误代码: var ids = $("#grid-t ...
- 今天升级netbean出错
出现:无法初始化 UI netbean 由于ubuntun装的是open jdk 直接删除open jdk就可以 sudo apt-get autoremove open-jdk*
- Python中集合类型(set)学习小结
set 是一个无序的元素集合,支持并.交.差及对称差等数学运算, 但由于 set 不记录元素位置,因此不支持索引.分片等类序列的操作. 初始化 复制代码代码如下: s0 = set()d0 = {}s ...
- 理解Java中字符流与字节流
1. 什么是流 Java中的流是对字节序列的抽象,我们可以想象有一个水管,只不过现在流动在水管中的不再是水,而是字节序列.和水流一样,Java中的流也具有一个"流动的方向",通常可 ...
- Cross compile perl
Alex Suykov had do some work for this purpose, and my compile script is based on her patch. Steps St ...