Docker Libnetwork Bridge插件实现代码分析----创建网络部分
2017-03-09 17:16
671 查看
// 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数据结构如下所示
// 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数据结构如下所示:
bridgeSetup数据结构如下所示:
// 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的数据结构如下所示:
// 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数据结构如下所示:
// 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插件实现代码分析----初始化部分
- CNI bridge 插件实现代码分析
- 以Network Dataset(网络数据集)方式实现的最短路径分析
- 基于visual c++之windows核心编程代码分析(47)实现交换网络的QQ号嗅探
- 16 - Docker network第二讲-容器默认网络bridge(Docker系列)
- 从零实现一个高性能网络爬虫(一)网络请求分析及代码实现
- Docker实现跨主机容器实例网络通信(1)——利用LinuxBridge构建多主机Docker网络
- 浅谈SQL Server所实现创建分页功能的存储过程的分析及代码
- 实例分析之用ASP编程实现网络内容快速查找的代码
- 【Network】OVS、VXLAN/GRE、OVN等 实现 Docker/Kubernetes 网络的多租户隔离
- Docker 1.9 Overlay Network实现跨主机网络互通
- 基于visual c++之windows核心编程代码分析(59)实现网络简单代理编程
- 今天看了ACE 中Proactor实现部分的一些代码,做一些总结和分析
- HTTP代理实现请求报文的拦截与篡改10--大结局 篡改部分的代码分析
- Android通用网络请求解析框架.3(代码实现,公共部分)
- [深度学习]Python/Theano实现逻辑回归网络的代码分析
- 3d(三维)验证码实现(部分代码来自网络),旋转未完成,有待改进(二)
- jQuery创建插件的代码分析
- adb 通信协议分析以及实现 (三) (Adb 网络通信部分解析)
- HTTP代理实现请求报文的拦截与篡改10--大结局 篡改部分的代码分析