// 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插件实现代码分析----创建网络部分的更多相关文章

  1. Docker Libnetwork Bridge插件实现代码分析----初始化部分

    Bridge driver数据结构如下所示: type driver struct { config *configuration network *bridgeNetwork natChain *i ...

  2. CNI bridge 插件实现代码分析

    对于每个CNI 插件在执行函数cmdAdd之前的操作是完全一样的,即从环境变量和标准输入内读取配置.这在http://www.cnblogs.com/YaoDD/p/6410725.html这篇博文里 ...

  3. jQuery File Upload 插件 php代码分析

    jquery file upload php代码分析首先进入构造方法 __construct() 再进入 initialize()因为我是post方式传的数据  在进入initialize()中的po ...

  4. 使用 Gradle 插件进行代码分析(转)

    代码分析在大多数项目中通常是作为最后一个步骤(如果做了的话)完成的.其通常难以配置及与现有代码整合. 本文旨在勾勒出使用 Gradle 整合 PMD 与 FindBugs 的步骤,并将其与一个现有的 ...

  5. Eclipse插件(导出UML图,打开文件资源管理器插件,静态代码分析工具PMD,在eclipse上安装插件)

    目录 能够导出UML图的Eclipse插件 打开文件资源管理器插件 Java静态代码分析工具PMD 如何在eclipse上安装插件 JProfiler性能分析工具 从更新站点安装EclEmma 能够导 ...

  6. vs中插件影响代码自动创建后台事件问题

    CSS Tools 启用之后会影响代码自动创建后台事件,禁用之后解决.禁用之后鼠标悬浮不能看图片,颜色也不能展示

  7. docker——libnetwork插件网络功能

    从1.7.0版本开始,Docker正是把网络和存储这两部分的功能都以插件化形式剥离出来,允许用户通过指令来选择不同的后端实现.剥离出来的独立容器网络项目叫libnetwork,从名字就能看出,它希望将 ...

  8. 虚拟机创建流程中neutron代码分析(二)

    前言: 当nova服务发送了创建port的restful调用信息之后,在neutron服务中有相应的处理函数来处理调用.根据restful的工作原理,是按照 paste.ini文件中配置好的流程去处理 ...

  9. Hyperledger Fabric(v1.2.0)代码分析1——channel创建

    Hyperledger Fabric(v1.2.0)代码分析1--channel创建 0. e2e_cli Hyperledger Fabric提供了一个e2e的例子,该例中创建了一个基础的区块链网络 ...

随机推荐

  1. makefile之origin函数

    origin 函数的作用是告诉你变量是哪里来的,其出生状况如何,他并不改变变量. 函数语法: $(origin ) 为变量的名字,而不是引用,所以一般没有"$"字符在前. orig ...

  2. Jquery学习笔记(10)--ajax删除用户,使用了js原生ajax

    主要复习了php的pdo数据库操作,和js的ajax,真麻烦,希望jquery的ajax简单点. index.php: <!DOCTYPE html> <html lang=&quo ...

  3. 初识layer遮罩层

    背景:楼主做了一个先删除数据再插入的功能,但是狂点菜单的时候会有重复数据插入进来,设置字段unique之后,再狂点,控制台也会报错. 为了防止这种问题出现,我采取了制止”狂点“这种行为出现的做法,所以 ...

  4. shell30题之第一题

    1.1.1 Shell面试题1:批量生成随机字符文件名案例 使用for循环在/oldboy目录下批量创建10个html文件,其中每个文件需要包含10个随机小写字母加固定字符串oldboy,名称示例如下 ...

  5. Installing scipy on redhat with error “no lapack/blas resources found”

    这是更新scipy出现的结果,需要新版本的scipy,而机器上只装了0.7的版本,更新的时候报错,找到了一个解决方法: wget http://mirror.centos.org/centos/6/o ...

  6. 12 jsp page 指令

    jsp 指令影响由 jsp 页面生成的 servlet 整体结构. jsp page 用来设置整个页面属性, 例如 import 就是引用这些类, 还可以设置 session 等等. <%@ p ...

  7. 响应式网页设计:rem、em设置网页字体大小自适应

    「rem」是指根元素(root element,html)的字体大小,好开心的是,从遥远的 IE6 到版本帝 Chrome 他们都约好了,根元素默认的 font-size 都是 16px.这样一个新的 ...

  8. [Buzz Today]2013.08.18

    # Go 语言实现memcached:groupcache memcached作者Brad Fitzpatrick用Go语言重新实现了memcached. groupcache继承了memcached ...

  9. 利用多态,实现一般处理程序(ashx)中的AOP(切面编程)

    本文是对工作中的项目进行代码优化(完善登陆验证的AOP切面编程)时,所遇到的各种解决方案思考过程. 项目背景:由ashx+nvelocity构建的简单B/S问卷系统,现需要优化登录验证环节(时隔若干个 ...

  10. python urllib2导出elasticsearch数据时 返回 "urllib2.HTTPError: HTTP Error 500: Internal Server Error"

    0.业务场景 将ES中某个index的某个字段的所有数据,导出到文件中 1.ES数据导出方法简述 ES数据导出方法,我主要找到了以下几个方面,欢迎大家补充: ES官方API:snapshot and ...